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 001/715] 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 002/715] 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 003/715] 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 004/715] 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 005/715] 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 006/715] 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 007/715] 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 008/715] 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 009/715] 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 010/715] 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 011/715] 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 012/715] 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 013/715] 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 014/715] 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 015/715] 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 016/715] 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 017/715] 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 018/715] 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 019/715] 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 020/715] 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 021/715] 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 022/715] 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 023/715] 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 024/715] 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 025/715] [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 026/715] 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 027/715] 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 028/715] 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 029/715] 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 030/715] 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 031/715] 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 032/715] =?UTF-8?q?[Enhancement]=20Convert=20fast-unstake?= =?UTF-8?q?=20to=20use=20StakingInterface,=20decouplin=E2=80=A6=20(#12424)?= 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 033/715] 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 034/715] 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 035/715] 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 036/715] 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 037/715] 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 038/715] 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 039/715] 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 040/715] 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 041/715] 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 042/715] 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 043/715] [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 044/715] 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 045/715] 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 046/715] 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 047/715] 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 048/715] 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 049/715] 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 050/715] 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 051/715] 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 052/715] 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 053/715] 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 054/715] 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 055/715] 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 056/715] 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 057/715] 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 058/715] 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 059/715] 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 060/715] 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 061/715] 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 062/715] `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 063/715] 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 064/715] `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 065/715] 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 066/715] 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 067/715] 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 068/715] [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 069/715] 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 070/715] 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 071/715] 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 072/715] 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 073/715] 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 074/715] 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 075/715] 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 076/715] 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 077/715] 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 078/715] 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 079/715] 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 080/715] `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 081/715] 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 082/715] 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 083/715] 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 084/715] 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 085/715] 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 086/715] 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 087/715] 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 088/715] 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 089/715] 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 090/715] 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 091/715] [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 092/715] 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 093/715] [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 094/715] 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 095/715] 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 096/715] `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 097/715] 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 098/715] 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 099/715] 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 100/715] 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 101/715] [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 102/715] 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 103/715] [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 104/715] [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 105/715] 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 106/715] 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 107/715] 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 108/715] 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 109/715] 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 110/715] 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 111/715] [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 112/715] 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 113/715] 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 114/715] 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 115/715] 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 116/715] 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 117/715] 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 118/715] 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 119/715] 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 120/715] 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 121/715] 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 122/715] 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 123/715] 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 124/715] 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 125/715] 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 126/715] 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 127/715] 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 128/715] 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 129/715] 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 130/715] 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 131/715] 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 132/715] 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 133/715] 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 134/715] 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 135/715] 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 136/715] 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 137/715] 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 138/715] 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 139/715] 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 140/715] 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 141/715] 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 142/715] 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 143/715] 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 144/715] 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 145/715] 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 146/715] 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 147/715] 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 148/715] 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 149/715] 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 150/715] [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 151/715] 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 152/715] 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 153/715] 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 154/715] 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 155/715] 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 156/715] 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 157/715] 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 158/715] 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 159/715] 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 160/715] 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 161/715] 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 162/715] 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 163/715] [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 164/715] 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 165/715] 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 166/715] 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 167/715] 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 168/715] 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 169/715] 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 170/715] 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 171/715] 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 172/715] 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 173/715] 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 174/715] 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 175/715] 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 176/715] 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 177/715] 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 178/715] `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 179/715] 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 180/715] 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 181/715] 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 182/715] 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 183/715] 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 184/715] 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 185/715] [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) From 89498c0d756c649d71e82340bee44fcc7cfe8037 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 13 Dec 2022 22:47:51 +0100 Subject: [PATCH 186/715] Fixup some wrong dependencies (#12899) * Fixup some wrong dependencies Dev dependencies should not appear in the feature list. If features are required, they should be directly enabled for the `dev-dependency`. * More fixups * Fix fix * Remove deprecated feature * Make all work properly and nice!! * FMT * Fix formatting --- Cargo.lock | 2 +- frame/assets/Cargo.toml | 3 +- frame/assets/src/lib.rs | 2 + frame/bags-list/src/lib.rs | 58 ++++++++++--------- frame/election-provider-support/Cargo.toml | 3 +- frame/election-provider-support/src/lib.rs | 3 + frame/fast-unstake/Cargo.toml | 6 -- frame/nomination-pools/Cargo.toml | 2 +- .../nomination-pools/benchmarking/Cargo.toml | 2 - frame/staking/Cargo.toml | 8 +-- frame/staking/src/pallet/impls.rs | 41 +++++++------ .../asset-tx-payment/Cargo.toml | 4 -- .../asset-tx-payment/src/tests.rs | 5 +- primitives/core/src/lib.rs | 46 +++++++++++++++ primitives/staking/Cargo.toml | 2 + primitives/staking/src/lib.rs | 2 + utils/wasm-builder/src/wasm_project.rs | 9 +-- 17 files changed, 120 insertions(+), 78 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2f2b4aa7cf35d..ea34146f16f9b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5176,7 +5176,6 @@ dependencies = [ "frame-support", "frame-system", "log", - "pallet-assets", "pallet-balances", "pallet-staking", "pallet-staking-reward-curve", @@ -9475,6 +9474,7 @@ version = "4.0.0-dev" dependencies = [ "parity-scale-codec", "scale-info", + "sp-core", "sp-runtime", "sp-std", ] diff --git a/frame/assets/Cargo.toml b/frame/assets/Cargo.toml index 715149b20c042..84bfd9535a461 100644 --- a/frame/assets/Cargo.toml +++ b/frame/assets/Cargo.toml @@ -23,9 +23,9 @@ frame-support = { version = "4.0.0-dev", default-features = false, path = "../su # `system` module provides us with all sorts of useful stuff and macros depend on it being around. 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 = "7.0.0", default-features = false, path = "../../primitives/core" } [dev-dependencies] -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" } @@ -35,6 +35,7 @@ default = ["std"] std = [ "codec/std", "scale-info/std", + "sp-core/std", "sp-std/std", "sp-runtime/std", "frame-support/std", diff --git a/frame/assets/src/lib.rs b/frame/assets/src/lib.rs index 629a0243cfc80..ab589c0eef0f4 100644 --- a/frame/assets/src/lib.rs +++ b/frame/assets/src/lib.rs @@ -1487,3 +1487,5 @@ pub mod pallet { } } } + +sp_core::generate_feature_enabled_macro!(runtime_benchmarks_enabled, feature = "runtime-benchmarks", $); diff --git a/frame/bags-list/src/lib.rs b/frame/bags-list/src/lib.rs index 1ffdf29345513..14f8a613eb798 100644 --- a/frame/bags-list/src/lib.rs +++ b/frame/bags-list/src/lib.rs @@ -359,25 +359,26 @@ impl, I: 'static> SortedListProvider for Pallet List::::unsafe_clear() } - #[cfg(feature = "runtime-benchmarks")] - 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 current_bag_idx = thresholds - .iter() - .chain(sp_std::iter::once(&T::Score::max_value())) - .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] + frame_election_provider_support::runtime_benchmarks_enabled! { + 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 current_bag_idx = thresholds + .iter() + .chain(sp_std::iter::once(&T::Score::max_value())) + .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] + } } } } @@ -389,14 +390,15 @@ impl, I: 'static> ScoreProvider for Pallet { Node::::get(id).map(|node| node.score()).unwrap_or_default() } - #[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() { - node.set_score(new_score) - } else { - panic!("trying to mutate {:?} which does not exists", id); - } - }) + frame_election_provider_support::runtime_benchmarks_or_fuzz_enabled! { + 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.score = new_score; + } else { + panic!("trying to mutate {:?} which does not exists", id); + } + }) + } } } diff --git a/frame/election-provider-support/Cargo.toml b/frame/election-provider-support/Cargo.toml index b9584c899e1b1..33a6f25ed0822 100644 --- a/frame/election-provider-support/Cargo.toml +++ b/frame/election-provider-support/Cargo.toml @@ -21,10 +21,10 @@ sp-arithmetic = { version = "6.0.0", default-features = false, path = "../../pri sp-npos-elections = { version = "4.0.0-dev", default-features = false, path = "../../primitives/npos-elections" } 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" } [dev-dependencies] rand = "0.7.3" -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" } @@ -38,6 +38,7 @@ std = [ "scale-info/std", "sp-arithmetic/std", "sp-npos-elections/std", + "sp-core/std", "sp-runtime/std", "sp-std/std", ] diff --git a/frame/election-provider-support/src/lib.rs b/frame/election-provider-support/src/lib.rs index 8b26148844c39..9d5d6c018e5e1 100644 --- a/frame/election-provider-support/src/lib.rs +++ b/frame/election-provider-support/src/lib.rs @@ -671,3 +671,6 @@ pub type BoundedSupportsOf = BoundedSupports< ::AccountId, ::MaxWinners, >; + +sp_core::generate_feature_enabled_macro!(runtime_benchmarks_enabled, feature = "runtime-benchmarks", $); +sp_core::generate_feature_enabled_macro!(runtime_benchmarks_or_fuzz_enabled, any(feature = "runtime-benchmarks", feature = "fuzzing"), $); diff --git a/frame/fast-unstake/Cargo.toml b/frame/fast-unstake/Cargo.toml index 61bc823cc11e5..b61060e775a9f 100644 --- a/frame/fast-unstake/Cargo.toml +++ b/frame/fast-unstake/Cargo.toml @@ -25,10 +25,7 @@ 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" } @@ -38,8 +35,6 @@ 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] default = ["std"] @@ -64,6 +59,5 @@ runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", "frame-system/runtime-benchmarks", "sp-staking/runtime-benchmarks", - "pallet-staking/runtime-benchmarks" ] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/nomination-pools/Cargo.toml b/frame/nomination-pools/Cargo.toml index 4894e3d97f19a..3eb2d4bc5fd9b 100644 --- a/frame/nomination-pools/Cargo.toml +++ b/frame/nomination-pools/Cargo.toml @@ -26,7 +26,7 @@ sp-core = { version = "7.0.0", default-features = false, path = "../../primitive 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 +# Optional: use for testing and/or fuzzing pallet-balances = { version = "4.0.0-dev", path = "../balances", optional = true } sp-tracing = { version = "6.0.0", path = "../../primitives/tracing", optional = true } diff --git a/frame/nomination-pools/benchmarking/Cargo.toml b/frame/nomination-pools/benchmarking/Cargo.toml index be52d9777ac86..74b71a353fe7f 100644 --- a/frame/nomination-pools/benchmarking/Cargo.toml +++ b/frame/nomination-pools/benchmarking/Cargo.toml @@ -31,7 +31,6 @@ 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" } @@ -53,7 +52,6 @@ std = [ "pallet-nomination-pools/std", "sp-runtime/std", "sp-runtime-interface/std", - "sp-io/std", "sp-staking/std", "sp-std/std", ] diff --git a/frame/staking/Cargo.toml b/frame/staking/Cargo.toml index 3ad63ad94a08a..a7fca045cc4ba 100644 --- a/frame/staking/Cargo.toml +++ b/frame/staking/Cargo.toml @@ -32,10 +32,9 @@ 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 dependencies for cargo features +# Optional imports for benchmarking 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" } @@ -75,10 +74,5 @@ 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 = [ - "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 6729a2ca32ecc..1a4086ad2ab11 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -1329,7 +1329,7 @@ impl ScoreProvider for Pallet { Self::weight_of(who) } - #[cfg(any(feature = "runtime-benchmarks", feature = "fuzz"))] + #[cfg(feature = "runtime-benchmarks")] 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. @@ -1594,28 +1594,27 @@ impl StakingInterface for Pallet { 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()) - } + sp_staking::runtime_benchmarks_enabled! { + 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) - } + 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 }; + >::insert(¤t_era, &stash, &exposure); + } - #[cfg(feature = "runtime-benchmarks")] - fn set_current_era(era: EraIndex) { - CurrentEra::::put(era); + fn set_current_era(era: EraIndex) { + CurrentEra::::put(era); + } } } diff --git a/frame/transaction-payment/asset-tx-payment/Cargo.toml b/frame/transaction-payment/asset-tx-payment/Cargo.toml index b192c4e9cd96e..8e4645a2677f9 100644 --- a/frame/transaction-payment/asset-tx-payment/Cargo.toml +++ b/frame/transaction-payment/asset-tx-payment/Cargo.toml @@ -19,12 +19,10 @@ 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"] } @@ -40,7 +38,6 @@ 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 = [ @@ -60,6 +57,5 @@ 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 02e15654f3eed..b70a88d02c6e1 100644 --- a/frame/transaction-payment/asset-tx-payment/src/tests.rs +++ b/frame/transaction-payment/asset-tx-payment/src/tests.rs @@ -173,8 +173,9 @@ impl pallet_assets::Config for Runtime { type Extra = (); type WeightInfo = (); type RemoveItemsLimit = ConstU32<1000>; - #[cfg(feature = "runtime-benchmarks")] - type BenchmarkHelper = (); + pallet_assets::runtime_benchmarks_enabled! { + type BenchmarkHelper = (); + } } pub struct HardcodedAuthor; diff --git a/primitives/core/src/lib.rs b/primitives/core/src/lib.rs index fda7604d5337f..30d0cc199b74d 100644 --- a/primitives/core/src/lib.rs +++ b/primitives/core/src/lib.rs @@ -622,3 +622,49 @@ macro_rules! bounded_btree_map { } }; } + +/// Generates a macro for checking if a certain feature is enabled. +/// +/// These feature checking macros can be used to conditionally enable/disable code in a dependent +/// crate based on a feature in the crate where the macro is called. +#[macro_export] +// We need to skip formatting this macro because of this bug: +// https://github.com/rust-lang/rustfmt/issues/5283 +#[rustfmt::skip] +macro_rules! generate_feature_enabled_macro { + ( $macro_name:ident, $feature_name:meta, $d:tt ) => { + /// Enable/disable the given code depending on + #[doc = concat!("`", stringify!($feature_name), "`")] + /// being enabled for the crate or not. + /// + /// # Example + /// + /// ```nocompile + /// // Will add the code depending on the feature being enabled or not. + #[doc = concat!(stringify!($macro_name), "!( println!(\"Hello\") )")] + /// ``` + #[cfg($feature_name)] + #[macro_export] + macro_rules! $macro_name { + ( $d ( $d input:tt )* ) => { + $d ( $d input )* + } + } + + /// Enable/disable the given code depending on + #[doc = concat!("`", stringify!($feature_name), "`")] + /// being enabled for the crate or not. + /// + /// # Example + /// + /// ```nocompile + /// // Will add the code depending on the feature being enabled or not. + #[doc = concat!(stringify!($macro_name), "!( println!(\"Hello\") )")] + /// ``` + #[cfg(not($feature_name))] + #[macro_export] + macro_rules! $macro_name { + ( $d ( $d input:tt )* ) => {}; + } + }; +} diff --git a/primitives/staking/Cargo.toml b/primitives/staking/Cargo.toml index 550c1485e992c..35feae43ebb8c 100644 --- a/primitives/staking/Cargo.toml +++ b/primitives/staking/Cargo.toml @@ -15,6 +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.1.1", default-features = false, features = ["derive"] } +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" } @@ -23,6 +24,7 @@ default = ["std"] std = [ "codec/std", "scale-info/std", + "sp-core/std", "sp-runtime/std", "sp-std/std", ] diff --git a/primitives/staking/src/lib.rs b/primitives/staking/src/lib.rs index 703f0abe80458..9eb4a4890cdf8 100644 --- a/primitives/staking/src/lib.rs +++ b/primitives/staking/src/lib.rs @@ -190,3 +190,5 @@ pub trait StakingInterface { #[cfg(feature = "runtime-benchmarks")] fn set_current_era(era: EraIndex); } + +sp_core::generate_feature_enabled_macro!(runtime_benchmarks_enabled, feature = "runtime-benchmarks", $); diff --git a/utils/wasm-builder/src/wasm_project.rs b/utils/wasm-builder/src/wasm_project.rs index 7688069dd7cca..d17997360deef 100644 --- a/utils/wasm-builder/src/wasm_project.rs +++ b/utils/wasm-builder/src/wasm_project.rs @@ -379,14 +379,15 @@ fn find_package_by_manifest_path<'a>( 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() .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() { + + if let Some(pkg) = pkgs_by_name.first() { + if pkgs_by_name.len() > 1 { panic!( "Found multiple packages matching the name {pkg_name} ({manifest_path:?}): {:?}", pkgs_by_name @@ -395,7 +396,7 @@ fn find_package_by_manifest_path<'a>( return pkg } } else { - panic!("Failed to find entry for package {pkg_name} ({manifest_path:?})"); + panic!("Failed to find entry for package {pkg_name} ({manifest_path:?})."); } } From b65c9f044804b6f401197b2567e1ab10b4776159 Mon Sep 17 00:00:00 2001 From: Alexander Popiak Date: Wed, 14 Dec 2022 10:59:04 +0100 Subject: [PATCH 187/715] add numerator and denominator to Rational128 Debug impl and increase precision of float representation (#12914) --- primitives/arithmetic/src/rational.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/primitives/arithmetic/src/rational.rs b/primitives/arithmetic/src/rational.rs index 54cabfc6214e8..447b37551bb1f 100644 --- a/primitives/arithmetic/src/rational.rs +++ b/primitives/arithmetic/src/rational.rs @@ -94,14 +94,14 @@ pub struct Rational128(u128, u128); #[cfg(feature = "std")] impl sp_std::fmt::Debug for Rational128 { fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { - write!(f, "Rational128({:.4})", self.0 as f32 / self.1 as f32) + write!(f, "Rational128({} / {} ≈ {:.8})", self.0, self.1, self.0 as f64 / self.1 as f64) } } #[cfg(not(feature = "std"))] impl sp_std::fmt::Debug for Rational128 { fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { - write!(f, "Rational128(..)") + write!(f, "Rational128({} / {})", self.0, self.1) } } From 59b590300c368f285e885a5304d231dd994b6020 Mon Sep 17 00:00:00 2001 From: Arkadiy Paronyan Date: Wed, 14 Dec 2022 12:03:16 +0100 Subject: [PATCH 188/715] Fix state-db pinning (#12927) * Pin all canonicalized blocks * Added a test * Docs --- client/db/src/lib.rs | 1 + client/state-db/src/lib.rs | 10 +++++ client/state-db/src/noncanonical.rs | 65 +++++++++++++++++++++-------- 3 files changed, 58 insertions(+), 18 deletions(-) diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index 426876f5cba8c..4452d5dcb3f29 100644 --- a/client/db/src/lib.rs +++ b/client/db/src/lib.rs @@ -2002,6 +2002,7 @@ impl sc_client_api::backend::Backend for Backend { .map_err(sp_blockchain::Error::from_state_db)?; Err(e) } else { + self.storage.state_db.sync(); Ok(()) } } diff --git a/client/state-db/src/lib.rs b/client/state-db/src/lib.rs index 94d41787701b3..5e01a0e063ac1 100644 --- a/client/state-db/src/lib.rs +++ b/client/state-db/src/lib.rs @@ -470,6 +470,10 @@ impl StateDbSync { } } + fn sync(&mut self) { + self.non_canonical.sync(); + } + pub fn get( &self, key: &Q, @@ -573,6 +577,12 @@ impl StateDb { self.db.write().unpin(hash) } + /// Confirm that all changes made to commit sets are on disk. Allows for temporarily pinned + /// blocks to be released. + pub fn sync(&self) { + self.db.write().sync() + } + /// Get a value from non-canonical/pruning overlay or the backing DB. pub fn get( &self, diff --git a/client/state-db/src/noncanonical.rs b/client/state-db/src/noncanonical.rs index 7cb3017966b0f..84ba94c052909 100644 --- a/client/state-db/src/noncanonical.rs +++ b/client/state-db/src/noncanonical.rs @@ -38,7 +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, + pinned_canonincalized: Vec, } #[cfg_attr(test, derive(PartialEq, Debug))] @@ -226,7 +226,7 @@ impl NonCanonicalOverlay { pinned: Default::default(), pinned_insertions: Default::default(), values, - last_canon_pinned: None, + pinned_canonincalized: Default::default(), }) } @@ -350,6 +350,18 @@ impl NonCanonicalOverlay { self.last_canonicalized.as_ref().map(|&(_, n)| n) } + /// Confirm that all changes made to commit sets are on disk. Allows for temporarily pinned + /// blocks to be released. + pub fn sync(&mut self) { + let mut pinned = std::mem::take(&mut self.pinned_canonincalized); + for hash in pinned.iter() { + self.unpin(hash) + } + pinned.clear(); + // Reuse the same memory buffer + self.pinned_canonincalized = pinned; + } + /// Select a top-level root and canonicalized it. Discards all sibling subtrees and the root. /// Add a set of changes of the canonicalized block to `CommitSet` /// Return the block number of the canonicalized block @@ -371,13 +383,9 @@ impl NonCanonicalOverlay { // 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()); + self.pinned_canonincalized.push(hash.clone()); let mut discarded_journals = Vec::new(); let mut discarded_blocks = Vec::new(); @@ -720,16 +728,17 @@ mod tests { let mut commit = CommitSet::default(); overlay.canonicalize(&h1, &mut commit).unwrap(); db.commit(&commit); - assert!(contains(&overlay, 5)); + overlay.sync(); + assert!(!contains(&overlay, 5)); assert!(contains(&overlay, 7)); assert_eq!(overlay.levels.len(), 1); - assert_eq!(overlay.parents.len(), 2); + assert_eq!(overlay.parents.len(), 1); let mut commit = CommitSet::default(); overlay.canonicalize(&h2, &mut commit).unwrap(); - assert!(!contains(&overlay, 5)); db.commit(&commit); + overlay.sync(); assert_eq!(overlay.levels.len(), 0); - assert_eq!(overlay.parents.len(), 1); + assert_eq!(overlay.parents.len(), 0); assert!(db.data_eq(&make_db(&[1, 4, 6, 7, 8]))); } @@ -746,8 +755,7 @@ 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); + overlay.sync(); assert!(!contains(&overlay, 1)); } @@ -834,9 +842,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); + overlay.sync(); assert_eq!(overlay.levels.len(), 2); assert_eq!(overlay.parents.len(), 6); assert!(!contains(&overlay, 1)); @@ -856,8 +863,8 @@ 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); + overlay.sync(); assert_eq!(overlay.levels.len(), 1); assert_eq!(overlay.parents.len(), 3); assert!(!contains(&overlay, 11)); @@ -873,8 +880,8 @@ 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); + overlay.sync(); assert_eq!(overlay.levels.len(), 0); assert_eq!(overlay.parents.len(), 0); assert!(db.data_eq(&make_db(&[1, 12, 122]))); @@ -958,6 +965,28 @@ mod tests { assert!(!contains(&overlay, 1)); } + #[test] + fn pins_canonicalized() { + let mut db = make_db(&[]); + + let (h_1, c_1) = (H256::random(), make_changeset(&[1], &[])); + 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, 2, &h_1, c_2).unwrap()); + + let mut commit = CommitSet::default(); + overlay.canonicalize(&h_1, &mut commit).unwrap(); + overlay.canonicalize(&h_2, &mut commit).unwrap(); + assert!(contains(&overlay, 1)); + assert!(contains(&overlay, 2)); + db.commit(&commit); + overlay.sync(); + assert!(!contains(&overlay, 1)); + assert!(!contains(&overlay, 2)); + } + #[test] fn pin_keeps_parent() { let mut db = make_db(&[]); @@ -1019,8 +1048,8 @@ 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); + overlay.sync(); assert!(!contains(&overlay, 21)); } From 2e21c35f879e904101d8305eef7a203d95dd6cd6 Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Wed, 14 Dec 2022 12:36:33 +0100 Subject: [PATCH 189/715] [ci] add job switcher (#12922) --- .gitlab-ci.yml | 9 ++++++++- scripts/ci/gitlab/pipeline/build.yml | 3 +++ scripts/ci/gitlab/pipeline/publish.yml | 1 + scripts/ci/gitlab/pipeline/test.yml | 2 ++ 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 25d61cf349615..dcc0cbb7c9693 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -81,8 +81,14 @@ default: paths: - artifacts/ +.job-switcher: + before_script: + - if echo "$CI_DISABLED_JOBS" | grep -xF "$CI_JOB_NAME"; then echo "The job has been cancelled in CI settings"; exit 0; fi + .kubernetes-env: image: "${CI_IMAGE}" + before_script: + - !reference [.job-switcher, before_script] tags: - kubernetes-parity-build @@ -95,6 +101,7 @@ default: .pipeline-stopper-vars: script: + - !reference [.job-switcher, before_script] - echo "Collecting env variables for the cancel-pipeline job" - echo "FAILED_JOB_URL=${CI_JOB_URL}" > pipeline-stopper.env - echo "FAILED_JOB_NAME=${CI_JOB_NAME}" >> pipeline-stopper.env @@ -110,6 +117,7 @@ default: 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 [.job-switcher, before_script] - !reference [.rust-info-script, script] - !reference [.rusty-cachier, before_script] - !reference [.pipeline-stopper-vars, script] @@ -300,7 +308,6 @@ rusty-cachier-notify: PR_NUM: "${PR_NUM}" trigger: project: "parity/infrastructure/ci_cd/pipeline-stopper" - branch: "as-improve" remove-cancel-pipeline-message: stage: .post diff --git a/scripts/ci/gitlab/pipeline/build.yml b/scripts/ci/gitlab/pipeline/build.yml index 2f8cff7b3ffa6..ba529569d0fc1 100644 --- a/scripts/ci/gitlab/pipeline/build.yml +++ b/scripts/ci/gitlab/pipeline/build.yml @@ -62,6 +62,7 @@ build-linux-substrate: - job: test-linux-stable artifacts: false before_script: + - !reference [.job-switcher, before_script] - mkdir -p ./artifacts/substrate/ - !reference [.rusty-cachier, before_script] # tldr: we need to checkout the branch HEAD explicitly because of our dynamic versioning approach while building the substrate binary @@ -94,6 +95,7 @@ build-linux-substrate: # this variable gets overriden by "rusty-cachier environment inject", use the value as default CARGO_TARGET_DIR: "$CI_PROJECT_DIR/target" before_script: + - !reference [.job-switcher, before_script] - mkdir -p ./artifacts/subkey - !reference [.rusty-cachier, before_script] script: @@ -118,6 +120,7 @@ build-subkey-macos: # duplicating before_script & script sections from .build-subkey hidden job # to overwrite rusty-cachier integration as it doesn't work on macos before_script: + - !reference [.job-switcher, before_script] - mkdir -p ./artifacts/subkey script: - cd ./bin/utils/subkey diff --git a/scripts/ci/gitlab/pipeline/publish.yml b/scripts/ci/gitlab/pipeline/publish.yml index 381a1bc420ef3..6a0d6d6341304 100644 --- a/scripts/ci/gitlab/pipeline/publish.yml +++ b/scripts/ci/gitlab/pipeline/publish.yml @@ -12,6 +12,7 @@ DOCKERFILE: $PRODUCT.Dockerfile IMAGE_NAME: docker.io/$IMAGE_PATH before_script: + - !reference [.job-switcher, before_script] - cd ./artifacts/$PRODUCT/ - VERSION="$(cat ./VERSION)" - echo "${PRODUCT} version = ${VERSION}" diff --git a/scripts/ci/gitlab/pipeline/test.yml b/scripts/ci/gitlab/pipeline/test.yml index ea1240af8bd57..a468a7b04caeb 100644 --- a/scripts/ci/gitlab/pipeline/test.yml +++ b/scripts/ci/gitlab/pipeline/test.yml @@ -65,6 +65,7 @@ cargo-check-benches: before_script: # perform rusty-cachier operations before any further modifications to the git repo to make cargo feel cheated not so much - !reference [.rust-info-script, script] + - !reference [.job-switcher, before_script] - !reference [.rusty-cachier, before_script] - !reference [.pipeline-stopper-vars, script] # merges in the master branch on PRs @@ -414,6 +415,7 @@ cargo-check-each-crate-macos: - .collect-artifacts - .pipeline-stopper-artifacts before_script: + - !reference [.job-switcher, before_script] - !reference [.rust-info-script, script] - !reference [.pipeline-stopper-vars, script] variables: From 2f6105bbc6a230210d022e48c568404acd501a81 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Wed, 14 Dec 2022 14:56:17 +0100 Subject: [PATCH 190/715] Use LOG_TARGET in consensus related crates (#12875) * Use shared LOG_TARGET in consensus related crates * Rename target from "afg" to "grandpa" --- client/consensus/aura/src/import_queue.rs | 7 +- client/consensus/aura/src/lib.rs | 8 +- client/consensus/babe/src/aux_schema.rs | 4 +- client/consensus/babe/src/lib.rs | 86 +++++++++++-------- client/consensus/babe/src/tests.rs | 10 +-- client/consensus/babe/src/verification.rs | 15 ++-- client/consensus/common/src/import_queue.rs | 37 +++++--- .../common/src/import_queue/basic_queue.rs | 25 +++--- .../manual-seal/src/consensus/babe.rs | 6 +- client/consensus/manual-seal/src/lib.rs | 2 + client/consensus/pow/src/lib.rs | 20 +++-- client/consensus/pow/src/worker.rs | 34 ++------ client/consensus/slots/src/lib.rs | 16 ++-- client/consensus/slots/src/slots.rs | 4 +- client/finality-grandpa/src/authorities.rs | 20 +++-- client/finality-grandpa/src/aux_schema.rs | 13 +-- .../src/communication/gossip.rs | 47 ++++++---- .../finality-grandpa/src/communication/mod.rs | 39 ++++++--- .../src/communication/periodic.rs | 8 +- client/finality-grandpa/src/environment.rs | 80 ++++++++++++----- client/finality-grandpa/src/finality_proof.rs | 10 +-- client/finality-grandpa/src/import.rs | 17 ++-- client/finality-grandpa/src/lib.rs | 25 ++++-- client/finality-grandpa/src/observer.rs | 6 +- client/finality-grandpa/src/until_imported.rs | 6 +- frame/aura/src/lib.rs | 4 +- frame/babe/src/equivocation.rs | 16 ++-- frame/babe/src/lib.rs | 2 + frame/grandpa/src/equivocation.rs | 16 ++-- frame/grandpa/src/lib.rs | 2 + frame/grandpa/src/migrations/v4.rs | 5 +- 31 files changed, 343 insertions(+), 247 deletions(-) diff --git a/client/consensus/aura/src/import_queue.rs b/client/consensus/aura/src/import_queue.rs index 07f982542c95b..d5cf40f33359e 100644 --- a/client/consensus/aura/src/import_queue.rs +++ b/client/consensus/aura/src/import_queue.rs @@ -20,6 +20,7 @@ use crate::{ aura_err, authorities, find_pre_digest, slot_author, AuthorityId, CompatibilityMode, Error, + LOG_TARGET, }; use codec::{Codec, Decode, Encode}; use log::{debug, info, trace}; @@ -88,7 +89,7 @@ where .map_err(Error::Client)? { info!( - target: "aura", + target: LOG_TARGET, "Slot author is equivocating at slot {} with headers {:?} and {:?}", slot, equivocation_proof.first_header.hash(), @@ -256,7 +257,7 @@ where block.body = Some(inner_body); } - trace!(target: "aura", "Checked {:?}; importing.", pre_header); + trace!(target: LOG_TARGET, "Checked {:?}; importing.", pre_header); telemetry!( self.telemetry; CONSENSUS_TRACE; @@ -272,7 +273,7 @@ where Ok((block, None)) }, CheckedHeader::Deferred(a, b) => { - debug!(target: "aura", "Checking {:?} failed; {:?}, {:?}.", hash, a, b); + debug!(target: LOG_TARGET, "Checking {:?} failed; {:?}, {:?}.", hash, a, b); telemetry!( self.telemetry; CONSENSUS_DEBUG; diff --git a/client/consensus/aura/src/lib.rs b/client/consensus/aura/src/lib.rs index 46b9124f9077f..a8ed80d7c0432 100644 --- a/client/consensus/aura/src/lib.rs +++ b/client/consensus/aura/src/lib.rs @@ -72,6 +72,8 @@ pub use sp_consensus_aura::{ AuraApi, ConsensusLog, SlotDuration, AURA_ENGINE_ID, }; +const LOG_TARGET: &str = "aura"; + type AuthorityId

=

::Public; /// Run `AURA` in a compatibility mode. @@ -530,7 +532,7 @@ where } fn aura_err(error: Error) -> Error { - debug!(target: "aura", "{}", error); + debug!(target: LOG_TARGET, "{}", error); error } @@ -580,10 +582,10 @@ pub fn find_pre_digest(header: &B::Header) -> Resul let mut pre_digest: Option = None; for log in header.digest().logs() { - trace!(target: "aura", "Checking log {:?}", log); + trace!(target: LOG_TARGET, "Checking log {:?}", log); match (CompatibleDigestItem::::as_aura_pre_digest(log), pre_digest.is_some()) { (Some(_), true) => return Err(aura_err(Error::MultipleHeaders)), - (None, _) => trace!(target: "aura", "Ignoring digest not meant for us"), + (None, _) => trace!(target: LOG_TARGET, "Ignoring digest not meant for us"), (s, false) => pre_digest = s, } } diff --git a/client/consensus/babe/src/aux_schema.rs b/client/consensus/babe/src/aux_schema.rs index fef84bda86974..2a09aa738f4ec 100644 --- a/client/consensus/babe/src/aux_schema.rs +++ b/client/consensus/babe/src/aux_schema.rs @@ -21,7 +21,7 @@ use codec::{Decode, Encode}; use log::info; -use crate::{migration::EpochV0, Epoch}; +use crate::{migration::EpochV0, Epoch, LOG_TARGET}; use sc_client_api::backend::AuxStore; use sc_consensus_epochs::{ migration::{EpochChangesV0For, EpochChangesV1For}, @@ -82,7 +82,7 @@ pub fn load_epoch_changes( let epoch_changes = SharedEpochChanges::::new(maybe_epoch_changes.unwrap_or_else(|| { info!( - target: "babe", + target: LOG_TARGET, "👶 Creating empty BABE epoch changes on what appears to be first startup.", ); EpochChangesFor::::default() diff --git a/client/consensus/babe/src/lib.rs b/client/consensus/babe/src/lib.rs index 84b6893648f49..b50874ae3401d 100644 --- a/client/consensus/babe/src/lib.rs +++ b/client/consensus/babe/src/lib.rs @@ -149,6 +149,8 @@ pub mod aux_schema; #[cfg(test)] mod tests; +const LOG_TARGET: &str = "babe"; + /// BABE epoch information #[derive(Decode, Encode, PartialEq, Eq, Clone, Debug)] pub struct Epoch { @@ -323,7 +325,7 @@ impl From> for String { } fn babe_err(error: Error) -> Error { - debug!(target: "babe", "{}", error); + debug!(target: LOG_TARGET, "{}", error); error } @@ -345,7 +347,7 @@ where 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"); + debug!(target: LOG_TARGET, "No finalized state is available. Reading config from genesis"); BlockId::Hash(client.usage_info().chain.genesis_hash) }; @@ -486,7 +488,7 @@ where telemetry, }; - info!(target: "babe", "👶 Starting BABE Authorship worker"); + info!(target: LOG_TARGET, "👶 Starting BABE Authorship worker"); let slot_worker = sc_consensus_slots::start_slot_worker( babe_link.config.slot_duration(), @@ -523,12 +525,8 @@ fn aux_storage_cleanup + HeaderBackend, Block: B Ok(meta) => { hashes.insert(meta.parent); }, - Err(err) => warn!( - target: "babe", - "Failed to lookup metadata for block `{:?}`: {}", - first, - err, - ), + Err(err) => + warn!(target: LOG_TARGET, "Failed to lookup metadata for block `{:?}`: {}", first, err,), } // Cleans data for finalized block's ancestors @@ -716,7 +714,7 @@ where type AuxData = ViableEpochDescriptor, Epoch>; fn logging_target(&self) -> &'static str { - "babe" + LOG_TARGET } fn block_import(&mut self) -> &mut Self::BlockImport { @@ -749,7 +747,7 @@ where slot: Slot, epoch_descriptor: &ViableEpochDescriptor, Epoch>, ) -> Option { - debug!(target: "babe", "Attempting to claim slot {}", slot); + debug!(target: LOG_TARGET, "Attempting to claim slot {}", slot); let s = authorship::claim_slot( slot, self.epoch_changes @@ -760,7 +758,7 @@ where ); if s.is_some() { - debug!(target: "babe", "Claimed slot {}", slot); + debug!(target: LOG_TARGET, "Claimed slot {}", slot); } s @@ -777,7 +775,7 @@ where Ok(()) => true, Err(e) => if e.is_full() { - warn!(target: "babe", "Trying to notify a slot but the channel is full"); + warn!(target: LOG_TARGET, "Trying to notify a slot but the channel is full"); true } else { false @@ -904,10 +902,10 @@ pub fn find_pre_digest(header: &B::Header) -> Result = None; for log in header.digest().logs() { - trace!(target: "babe", "Checking log {:?}, looking for pre runtime digest", log); + trace!(target: LOG_TARGET, "Checking log {:?}, looking for pre runtime digest", log); match (log.as_babe_pre_digest(), pre_digest.is_some()) { (Some(_), true) => return Err(babe_err(Error::MultiplePreRuntimeDigests)), - (None, _) => trace!(target: "babe", "Ignoring digest not meant for us"), + (None, _) => trace!(target: LOG_TARGET, "Ignoring digest not meant for us"), (s, false) => pre_digest = s, } } @@ -920,13 +918,13 @@ fn find_next_epoch_digest( ) -> 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); + trace!(target: LOG_TARGET, "Checking log {:?}, looking for epoch change digest.", log); let log = log.try_to::(OpaqueDigestItemId::Consensus(&BABE_ENGINE_ID)); match (log, epoch_digest.is_some()) { (Some(ConsensusLog::NextEpochData(_)), true) => return Err(babe_err(Error::MultipleEpochChangeDigests)), (Some(ConsensusLog::NextEpochData(epoch)), false) => epoch_digest = Some(epoch), - _ => trace!(target: "babe", "Ignoring digest not meant for us"), + _ => trace!(target: LOG_TARGET, "Ignoring digest not meant for us"), } } @@ -939,13 +937,13 @@ fn find_next_config_digest( ) -> 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); + trace!(target: LOG_TARGET, "Checking log {:?}, looking for epoch change digest.", log); let log = log.try_to::(OpaqueDigestItemId::Consensus(&BABE_ENGINE_ID)); match (log, config_digest.is_some()) { (Some(ConsensusLog::NextConfigData(_)), true) => return Err(babe_err(Error::MultipleConfigChangeDigests)), (Some(ConsensusLog::NextConfigData(config)), false) => config_digest = Some(config), - _ => trace!(target: "babe", "Ignoring digest not meant for us"), + _ => trace!(target: LOG_TARGET, "Ignoring digest not meant for us"), } } @@ -1075,7 +1073,10 @@ where None => match generate_key_owner_proof(&best_id)? { Some(proof) => proof, None => { - debug!(target: "babe", "Equivocation offender is not part of the authority set."); + debug!( + target: LOG_TARGET, + "Equivocation offender is not part of the authority set." + ); return Ok(()) }, }, @@ -1091,7 +1092,7 @@ where ) .map_err(Error::RuntimeApi)?; - info!(target: "babe", "Submitted equivocation report for author {:?}", author); + info!(target: LOG_TARGET, "Submitted equivocation report for author {:?}", author); Ok(()) } @@ -1121,7 +1122,7 @@ where mut block: BlockImportParams, ) -> BlockVerificationResult { trace!( - target: "babe", + target: LOG_TARGET, "Verifying origin: {:?} header: {:?} justification(s): {:?} body: {:?}", block.origin, block.header, @@ -1140,7 +1141,11 @@ where return Ok((block, Default::default())) } - debug!(target: "babe", "We have {:?} logs in this header", block.header.digest().logs().len()); + debug!( + target: LOG_TARGET, + "We have {:?} logs in this header", + block.header.digest().logs().len() + ); let create_inherent_data_providers = self .create_inherent_data_providers @@ -1204,7 +1209,10 @@ where ) .await { - warn!(target: "babe", "Error checking/reporting BABE equivocation: {}", err); + warn!( + target: LOG_TARGET, + "Error checking/reporting BABE equivocation: {}", err + ); } if let Some(inner_body) = block.body { @@ -1233,7 +1241,7 @@ where block.body = Some(inner_body); } - trace!(target: "babe", "Checked {:?}; importing.", pre_header); + trace!(target: LOG_TARGET, "Checked {:?}; importing.", pre_header); telemetry!( self.telemetry; CONSENSUS_TRACE; @@ -1252,7 +1260,7 @@ where Ok((block, Default::default())) }, CheckedHeader::Deferred(a, b) => { - debug!(target: "babe", "Checking {:?} failed; {:?}, {:?}.", hash, a, b); + debug!(target: LOG_TARGET, "Checking {:?} failed; {:?}, {:?}.", hash, a, b); telemetry!( self.telemetry; CONSENSUS_DEBUG; @@ -1520,21 +1528,23 @@ where log::Level::Info }; - log!(target: "babe", - log_level, - "👶 New epoch {} launching at block {} (block slot {} >= start slot {}).", - viable_epoch.as_ref().epoch_index, - hash, - slot, - viable_epoch.as_ref().start_slot, + log!( + target: LOG_TARGET, + log_level, + "👶 New epoch {} launching at block {} (block slot {} >= start slot {}).", + viable_epoch.as_ref().epoch_index, + hash, + slot, + viable_epoch.as_ref().start_slot, ); let next_epoch = viable_epoch.increment((next_epoch_descriptor, epoch_config)); - log!(target: "babe", - log_level, - "👶 Next epoch starts at slot {}", - next_epoch.as_ref().start_slot, + log!( + target: LOG_TARGET, + log_level, + "👶 Next epoch starts at slot {}", + next_epoch.as_ref().start_slot, ); // prune the tree of epochs not part of the finalized chain or @@ -1565,7 +1575,7 @@ where }; if let Err(e) = prune_and_import() { - debug!(target: "babe", "Failed to launch next epoch: {}", e); + debug!(target: LOG_TARGET, "Failed to launch next epoch: {}", e); *epoch_changes = old_epoch_changes.expect("set `Some` above and not taken; qed"); return Err(e) diff --git a/client/consensus/babe/src/tests.rs b/client/consensus/babe/src/tests.rs index 7f51eb2c51977..d7691235a550d 100644 --- a/client/consensus/babe/src/tests.rs +++ b/client/consensus/babe/src/tests.rs @@ -323,7 +323,7 @@ impl TestNetFactory for BabeTestNet { use substrate_test_runtime_client::DefaultTestClientBuilderExt; let client = client.as_client(); - trace!(target: "babe", "Creating a verifier"); + trace!(target: LOG_TARGET, "Creating a verifier"); // ensure block import and verifier are linked correctly. let data = maybe_link @@ -352,12 +352,12 @@ impl TestNetFactory for BabeTestNet { } fn peer(&mut self, i: usize) -> &mut BabePeer { - trace!(target: "babe", "Retrieving a peer"); + trace!(target: LOG_TARGET, "Retrieving a peer"); &mut self.peers[i] } fn peers(&self) -> &Vec { - trace!(target: "babe", "Retrieving peers"); + trace!(target: LOG_TARGET, "Retrieving peers"); &self.peers } @@ -583,7 +583,7 @@ fn can_author_block() { // with secondary slots enabled it should never be empty match claim_slot(i.into(), &epoch, &keystore) { None => i += 1, - Some(s) => debug!(target: "babe", "Authored block {:?}", s.0), + Some(s) => debug!(target: LOG_TARGET, "Authored block {:?}", s.0), } // otherwise with only vrf-based primary slots we might need to try a couple @@ -593,7 +593,7 @@ fn can_author_block() { match claim_slot(i.into(), &epoch, &keystore) { None => i += 1, Some(s) => { - debug!(target: "babe", "Authored block {:?}", s.0); + debug!(target: LOG_TARGET, "Authored block {:?}", s.0); break }, } diff --git a/client/consensus/babe/src/verification.rs b/client/consensus/babe/src/verification.rs index 53ec3002e6a85..e77a70c8e465a 100644 --- a/client/consensus/babe/src/verification.rs +++ b/client/consensus/babe/src/verification.rs @@ -17,9 +17,9 @@ // along with this program. If not, see . //! Verification for BABE headers. -use super::{ +use crate::{ authorship::{calculate_primary_threshold, check_primary_threshold, secondary_slot_author}, - babe_err, find_pre_digest, BlockT, Epoch, Error, + babe_err, find_pre_digest, BlockT, Epoch, Error, LOG_TARGET, }; use log::{debug, trace}; use sc_consensus_slots::CheckedHeader; @@ -67,7 +67,7 @@ pub(super) fn check_header( let authorities = &epoch.authorities; let pre_digest = pre_digest.map(Ok).unwrap_or_else(|| find_pre_digest::(&header))?; - trace!(target: "babe", "Checking header"); + trace!(target: LOG_TARGET, "Checking header"); let seal = header .digest_mut() .pop() @@ -93,7 +93,8 @@ pub(super) fn check_header( match &pre_digest { PreDigest::Primary(primary) => { - debug!(target: "babe", + debug!( + target: LOG_TARGET, "Verifying primary block #{} at slot: {}", header.number(), primary.slot, @@ -104,7 +105,8 @@ pub(super) fn check_header( PreDigest::SecondaryPlain(secondary) if epoch.config.allowed_slots.is_secondary_plain_slots_allowed() => { - debug!(target: "babe", + debug!( + target: LOG_TARGET, "Verifying secondary plain block #{} at slot: {}", header.number(), secondary.slot, @@ -115,7 +117,8 @@ pub(super) fn check_header( PreDigest::SecondaryVRF(secondary) if epoch.config.allowed_slots.is_secondary_vrf_slots_allowed() => { - debug!(target: "babe", + debug!( + target: LOG_TARGET, "Verifying secondary VRF block #{} at slot: {}", header.number(), secondary.slot, diff --git a/client/consensus/common/src/import_queue.rs b/client/consensus/common/src/import_queue.rs index d49b240ef3489..02309cc6a365e 100644 --- a/client/consensus/common/src/import_queue.rs +++ b/client/consensus/common/src/import_queue.rs @@ -45,6 +45,8 @@ use crate::{ pub use basic_queue::BasicQueue; use sp_consensus::{error::Error as ConsensusError, BlockOrigin, CacheKeyId}; +const LOG_TARGET: &str = "sync::import-queue"; + /// A commonly-used Import Queue type. /// /// This defines the transaction type of the `BasicQueue` to be the transaction type for a client. @@ -247,15 +249,15 @@ pub(crate) async fn import_single_block_metered< (Some(header), justifications) => (header, justifications), (None, _) => { if let Some(ref peer) = peer { - debug!(target: "sync", "Header {} was not provided by {} ", block.hash, peer); + debug!(target: LOG_TARGET, "Header {} was not provided by {} ", block.hash, peer); } else { - debug!(target: "sync", "Header {} was not provided ", block.hash); + debug!(target: LOG_TARGET, "Header {} was not provided ", block.hash); } return Err(BlockImportError::IncompleteHeader(peer)) }, }; - trace!(target: "sync", "Header {} has {:?} logs", block.hash, header.digest().logs().len()); + trace!(target: LOG_TARGET, "Header {} has {:?} logs", block.hash, header.digest().logs().len()); let number = *header.number(); let hash = block.hash; @@ -263,27 +265,31 @@ pub(crate) async fn import_single_block_metered< let import_handler = |import| match import { Ok(ImportResult::AlreadyInChain) => { - trace!(target: "sync", "Block already in chain {}: {:?}", number, hash); + trace!(target: LOG_TARGET, "Block already in chain {}: {:?}", number, hash); Ok(BlockImportStatus::ImportedKnown(number, peer)) }, Ok(ImportResult::Imported(aux)) => Ok(BlockImportStatus::ImportedUnknown(number, aux, peer)), Ok(ImportResult::MissingState) => { - debug!(target: "sync", "Parent state is missing for {}: {:?}, parent: {:?}", - number, hash, parent_hash); + debug!( + target: LOG_TARGET, + "Parent state is missing for {}: {:?}, parent: {:?}", number, hash, parent_hash + ); Err(BlockImportError::MissingState) }, Ok(ImportResult::UnknownParent) => { - debug!(target: "sync", "Block with unknown parent {}: {:?}, parent: {:?}", - number, hash, parent_hash); + debug!( + target: LOG_TARGET, + "Block with unknown parent {}: {:?}, parent: {:?}", number, hash, parent_hash + ); Err(BlockImportError::UnknownParent) }, Ok(ImportResult::KnownBad) => { - debug!(target: "sync", "Peer gave us a bad block {}: {:?}", number, hash); + debug!(target: LOG_TARGET, "Peer gave us a bad block {}: {:?}", number, hash); Err(BlockImportError::BadBlock(peer)) }, Err(e) => { - debug!(target: "sync", "Error importing block {}: {:?}: {}", number, hash, e); + debug!(target: LOG_TARGET, "Error importing block {}: {:?}: {}", number, hash, e); Err(BlockImportError::Other(e)) }, }; @@ -324,9 +330,16 @@ pub(crate) async fn import_single_block_metered< let (import_block, maybe_keys) = verifier.verify(import_block).await.map_err(|msg| { if let Some(ref peer) = peer { - trace!(target: "sync", "Verifying {}({}) from {} failed: {}", number, hash, peer, msg); + trace!( + target: LOG_TARGET, + "Verifying {}({}) from {} failed: {}", + number, + hash, + peer, + msg + ); } else { - trace!(target: "sync", "Verifying {}({}) failed: {}", number, hash, msg); + trace!(target: LOG_TARGET, "Verifying {}({}) failed: {}", number, hash, msg); } if let Some(metrics) = metrics.as_ref() { metrics.report_verification(false, started.elapsed()); diff --git a/client/consensus/common/src/import_queue/basic_queue.rs b/client/consensus/common/src/import_queue/basic_queue.rs index 20e8d262cacda..b63bc192b2e77 100644 --- a/client/consensus/common/src/import_queue/basic_queue.rs +++ b/client/consensus/common/src/import_queue/basic_queue.rs @@ -35,7 +35,7 @@ use crate::{ buffered_link::{self, BufferedLinkReceiver, BufferedLinkSender}, import_single_block_metered, BlockImportError, BlockImportStatus, BoxBlockImport, BoxJustificationImport, ImportQueue, ImportQueueService, IncomingBlock, Link, - RuntimeOrigin, Verifier, + RuntimeOrigin, Verifier, LOG_TARGET, }, metrics::Metrics, }; @@ -129,14 +129,14 @@ impl ImportQueueService for BasicQueueHandle { return } - trace!(target: "sync", "Scheduling {} blocks for import", blocks.len()); + trace!(target: LOG_TARGET, "Scheduling {} blocks for import", blocks.len()); let res = self .block_import_sender .unbounded_send(worker_messages::ImportBlocks(origin, blocks)); if res.is_err() { log::error!( - target: "sync", + target: LOG_TARGET, "import_blocks: Background import task is no longer alive" ); } @@ -156,7 +156,7 @@ impl ImportQueueService for BasicQueueHandle { if res.is_err() { log::error!( - target: "sync", + target: LOG_TARGET, "import_justification: Background import task is no longer alive" ); } @@ -179,7 +179,10 @@ impl ImportQueue for BasicQueue /// 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"); + log::error!( + target: LOG_TARGET, + "poll_actions: Background import task is no longer alive" + ); } } @@ -231,7 +234,7 @@ async fn block_import_process( Some(blocks) => blocks, None => { log::debug!( - target: "block-import", + target: LOG_TARGET, "Stopping block import because the import channel was closed!", ); return @@ -305,7 +308,7 @@ impl BlockImportWorker { // down and we should end this future. if worker.result_sender.is_closed() { log::debug!( - target: "block-import", + target: LOG_TARGET, "Stopping block import because result channel was closed!", ); return @@ -318,7 +321,7 @@ impl BlockImportWorker { worker.import_justification(who, hash, number, justification).await, None => { log::debug!( - target: "block-import", + target: LOG_TARGET, "Stopping block import because justification channel was closed!", ); return @@ -353,7 +356,7 @@ impl BlockImportWorker { .await .map_err(|e| { debug!( - target: "sync", + target: LOG_TARGET, "Justification import failed for hash = {:?} with number = {:?} coming from node = {:?} with error: {}", hash, number, @@ -407,7 +410,7 @@ async fn import_many_blocks, Transaction: Send + 'stat _ => Default::default(), }; - trace!(target: "sync", "Starting import of {} blocks {}", count, blocks_range); + trace!(target: LOG_TARGET, "Starting import of {} blocks {}", count, blocks_range); let mut imported = 0; let mut results = vec![]; @@ -447,7 +450,7 @@ async fn import_many_blocks, Transaction: Send + 'stat if import_result.is_ok() { trace!( - target: "sync", + target: LOG_TARGET, "Block imported successfully {:?} ({})", block_number, block_hash, diff --git a/client/consensus/manual-seal/src/consensus/babe.rs b/client/consensus/manual-seal/src/consensus/babe.rs index 206f5163a13cd..d2bea3a3a3656 100644 --- a/client/consensus/manual-seal/src/consensus/babe.rs +++ b/client/consensus/manual-seal/src/consensus/babe.rs @@ -20,7 +20,7 @@ //! that expect babe-specific digests. use super::ConsensusDataProvider; -use crate::Error; +use crate::{Error, LOG_TARGET}; use codec::Encode; use sc_client_api::{AuxStore, UsageProvider}; use sc_consensus_babe::{ @@ -179,7 +179,7 @@ where let epoch = epoch_changes .viable_epoch(&epoch_descriptor, |slot| Epoch::genesis(&self.config, slot)) .ok_or_else(|| { - log::info!(target: "babe", "create_digest: no viable_epoch :("); + log::info!(target: LOG_TARGET, "create_digest: no viable_epoch :("); sp_consensus::Error::InvalidAuthoritiesSet })?; @@ -290,7 +290,7 @@ where let has_authority = epoch.authorities.iter().any(|(id, _)| *id == *authority); if !has_authority { - log::info!(target: "manual-seal", "authority not found"); + log::info!(target: LOG_TARGET, "authority not found"); let timestamp = inherents .timestamp_inherent_data()? .ok_or_else(|| Error::StringError("No timestamp inherent data".into()))?; diff --git a/client/consensus/manual-seal/src/lib.rs b/client/consensus/manual-seal/src/lib.rs index 09ab139b91c73..700b94cf1d704 100644 --- a/client/consensus/manual-seal/src/lib.rs +++ b/client/consensus/manual-seal/src/lib.rs @@ -49,6 +49,8 @@ pub use self::{ use sc_transaction_pool_api::TransactionPool; use sp_api::{ProvideRuntimeApi, TransactionFor}; +const LOG_TARGET: &str = "manual-seal"; + /// The `ConsensusEngineId` of Manual Seal. pub const MANUAL_SEAL_ENGINE_ID: ConsensusEngineId = [b'm', b'a', b'n', b'l']; diff --git a/client/consensus/pow/src/lib.rs b/client/consensus/pow/src/lib.rs index ac7ce3b411333..ace00a34459af 100644 --- a/client/consensus/pow/src/lib.rs +++ b/client/consensus/pow/src/lib.rs @@ -67,6 +67,8 @@ use sp_runtime::{ }; use std::{cmp::Ordering, collections::HashMap, marker::PhantomData, sync::Arc, time::Duration}; +const LOG_TARGET: &str = "pow"; + #[derive(Debug, thiserror::Error)] pub enum Error { #[error("Header uses the wrong engine {0:?}")] @@ -531,7 +533,7 @@ where } if sync_oracle.is_major_syncing() { - debug!(target: "pow", "Skipping proposal due to sync."); + debug!(target: LOG_TARGET, "Skipping proposal due to sync."); worker.on_major_syncing(); continue } @@ -540,7 +542,7 @@ where Ok(x) => x, Err(err) => { warn!( - target: "pow", + target: LOG_TARGET, "Unable to pull new block for authoring. \ Select best chain error: {}", err @@ -561,7 +563,7 @@ where Ok(x) => x, Err(err) => { warn!( - target: "pow", + target: LOG_TARGET, "Unable to propose new block for authoring. \ Fetch difficulty failed: {}", err, @@ -577,7 +579,7 @@ where Ok(x) => x, Err(err) => { warn!( - target: "pow", + target: LOG_TARGET, "Unable to propose new block for authoring. \ Creating inherent data providers failed: {}", err, @@ -590,7 +592,7 @@ where Ok(r) => r, Err(e) => { warn!( - target: "pow", + target: LOG_TARGET, "Unable to propose new block for authoring. \ Creating inherent data failed: {}", e, @@ -610,7 +612,7 @@ where Ok(x) => x, Err(err) => { warn!( - target: "pow", + target: LOG_TARGET, "Unable to propose new block for authoring. \ Creating proposer failed: {:?}", err, @@ -624,7 +626,7 @@ where Ok(x) => x, Err(err) => { warn!( - target: "pow", + target: LOG_TARGET, "Unable to propose new block for authoring. \ Creating proposal failed: {}", err, @@ -654,14 +656,14 @@ where fn find_pre_digest(header: &B::Header) -> Result>, Error> { let mut pre_digest: Option<_> = None; for log in header.digest().logs() { - trace!(target: "pow", "Checking log {:?}, looking for pre runtime digest", log); + trace!(target: LOG_TARGET, "Checking log {:?}, looking for pre runtime digest", log); match (log, pre_digest.is_some()) { (DigestItem::PreRuntime(POW_ENGINE_ID, _), true) => return Err(Error::MultiplePreRuntimeDigests), (DigestItem::PreRuntime(POW_ENGINE_ID, v), false) => { pre_digest = Some(v.clone()); }, - (_, _) => trace!(target: "pow", "Ignoring digest not meant for us"), + (_, _) => trace!(target: LOG_TARGET, "Ignoring digest not meant for us"), } } diff --git a/client/consensus/pow/src/worker.rs b/client/consensus/pow/src/worker.rs index a00da6e7022fb..b53227bb3ca50 100644 --- a/client/consensus/pow/src/worker.rs +++ b/client/consensus/pow/src/worker.rs @@ -41,7 +41,7 @@ use std::{ time::Duration, }; -use crate::{PowAlgorithm, PowIntermediate, Seal, INTERMEDIATE_KEY, POW_ENGINE_ID}; +use crate::{PowAlgorithm, PowIntermediate, Seal, INTERMEDIATE_KEY, LOG_TARGET, POW_ENGINE_ID}; /// Mining metadata. This is the information needed to start an actual mining loop. #[derive(Clone, Eq, PartialEq)] @@ -159,26 +159,16 @@ where ) { Ok(true) => (), Ok(false) => { - warn!( - target: "pow", - "Unable to import mined block: seal is invalid", - ); + warn!(target: LOG_TARGET, "Unable to import mined block: seal is invalid",); return false }, Err(err) => { - warn!( - target: "pow", - "Unable to import mined block: {}", - err, - ); + warn!(target: LOG_TARGET, "Unable to import mined block: {}", err,); return false }, } } else { - warn!( - target: "pow", - "Unable to import mined block: metadata does not exist", - ); + warn!(target: LOG_TARGET, "Unable to import mined block: metadata does not exist",); return false } @@ -192,10 +182,7 @@ where } { build } else { - warn!( - target: "pow", - "Unable to import mined block: build does not exist", - ); + warn!(target: LOG_TARGET, "Unable to import mined block: build does not exist",); return false }; @@ -225,18 +212,13 @@ where ); info!( - target: "pow", - "✅ Successfully mined block on top of: {}", - build.metadata.best_hash + target: LOG_TARGET, + "✅ Successfully mined block on top of: {}", build.metadata.best_hash ); true }, Err(err) => { - warn!( - target: "pow", - "Unable to import mined block: {}", - err, - ); + warn!(target: LOG_TARGET, "Unable to import mined block: {}", err,); false }, } diff --git a/client/consensus/slots/src/lib.rs b/client/consensus/slots/src/lib.rs index bc68797dc734e..6126647e6190d 100644 --- a/client/consensus/slots/src/lib.rs +++ b/client/consensus/slots/src/lib.rs @@ -48,6 +48,8 @@ use std::{ time::{Duration, Instant}, }; +const LOG_TARGET: &str = "slots"; + /// The changes that need to applied to the storage to create the state for a block. /// /// See [`sp_state_machine::StorageChanges`] for more information. @@ -198,9 +200,9 @@ pub trait SimpleSlotWorker { > { let slot = slot_info.slot; let telemetry = self.telemetry(); - let logging_target = self.logging_target(); + let log_target = self.logging_target(); - let inherent_data = Self::create_inherent_data(&slot_info, &logging_target).await?; + let inherent_data = Self::create_inherent_data(&slot_info, &log_target).await?; let proposing_remaining_duration = self.proposing_remaining_duration(&slot_info); let logs = self.pre_digest_data(slot, claim); @@ -220,19 +222,19 @@ pub trait SimpleSlotWorker { 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: log_target, "Proposing failed: {}", err); return None }, Either::Right(_) => { info!( - target: logging_target, + target: log_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, + target: log_target, "👉 Recompile your node in `--release` mode to mitigate this problem.", ); telemetry!( @@ -525,13 +527,13 @@ 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: LOG_TARGET, "Error while polling for next slot: {}", e); return }, }; if sync_oracle.is_major_syncing() { - debug!(target: "slots", "Skipping proposal slot due to sync."); + debug!(target: LOG_TARGET, "Skipping proposal slot due to sync."); continue } diff --git a/client/consensus/slots/src/slots.rs b/client/consensus/slots/src/slots.rs index f8f366d89c82c..9bb5650b313d5 100644 --- a/client/consensus/slots/src/slots.rs +++ b/client/consensus/slots/src/slots.rs @@ -20,7 +20,7 @@ //! //! This is used instead of `futures_timer::Interval` because it was unreliable. -use super::{InherentDataProviderExt, Slot}; +use super::{InherentDataProviderExt, Slot, LOG_TARGET}; use sp_consensus::{Error, SelectChain}; use sp_inherents::{CreateInherentDataProviders, InherentDataProvider}; use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; @@ -146,7 +146,7 @@ where Ok(x) => x, Err(e) => { log::warn!( - target: "slots", + target: LOG_TARGET, "Unable to author block in slot. No best block header: {}", e, ); diff --git a/client/finality-grandpa/src/authorities.rs b/client/finality-grandpa/src/authorities.rs index 0803e6b3c2931..a61c66979bb5c 100644 --- a/client/finality-grandpa/src/authorities.rs +++ b/client/finality-grandpa/src/authorities.rs @@ -29,7 +29,7 @@ use sc_consensus::shared_data::{SharedData, SharedDataLocked}; use sc_telemetry::{telemetry, TelemetryHandle, CONSENSUS_INFO}; use sp_finality_grandpa::{AuthorityId, AuthorityList}; -use crate::SetId; +use crate::{SetId, LOG_TARGET}; /// Error type returned on operations on the `AuthoritySet`. #[derive(Debug, thiserror::Error)] @@ -314,7 +314,7 @@ where let number = pending.canon_height.clone(); debug!( - target: "afg", + target: LOG_TARGET, "Inserting potential standard set change signaled at block {:?} (delayed by {:?} blocks).", (&number, &hash), pending.delay, @@ -323,7 +323,7 @@ where self.pending_standard_changes.import(hash, number, pending, is_descendent_of)?; debug!( - target: "afg", + target: LOG_TARGET, "There are now {} alternatives for the next pending standard change (roots), and a \ total of {} pending standard changes (across all forks).", self.pending_standard_changes.roots().count(), @@ -362,7 +362,7 @@ where .unwrap_or_else(|i| i); debug!( - target: "afg", + target: LOG_TARGET, "Inserting potential forced set change at block {:?} (delayed by {:?} blocks).", (&pending.canon_height, &pending.canon_hash), pending.delay, @@ -370,7 +370,11 @@ where self.pending_forced_changes.insert(idx, pending); - debug!(target: "afg", "There are now {} pending forced changes.", self.pending_forced_changes.len()); + debug!( + target: LOG_TARGET, + "There are now {} pending forced changes.", + self.pending_forced_changes.len() + ); Ok(()) } @@ -475,7 +479,7 @@ where if standard_change.effective_number() <= median_last_finalized && is_descendent_of(&standard_change.canon_hash, &change.canon_hash)? { - log::info!(target: "afg", + log::info!(target: LOG_TARGET, "Not applying authority set change forced at block #{:?}, due to pending standard change at block #{:?}", change.canon_height, standard_change.effective_number(), @@ -488,7 +492,7 @@ where } // apply this change: make the set canonical - afg_log!( + grandpa_log!( initial_sync, "👴 Applying authority set change forced at block #{:?}", change.canon_height, @@ -570,7 +574,7 @@ where } if let Some(change) = change { - afg_log!( + grandpa_log!( initial_sync, "👴 Applying authority set change scheduled at block #{:?}", change.canon_height, diff --git a/client/finality-grandpa/src/aux_schema.rs b/client/finality-grandpa/src/aux_schema.rs index 235453ea35df1..a7357a7fa5e40 100644 --- a/client/finality-grandpa/src/aux_schema.rs +++ b/client/finality-grandpa/src/aux_schema.rs @@ -38,7 +38,7 @@ use crate::{ CompletedRound, CompletedRounds, CurrentRounds, HasVoted, SharedVoterSetState, VoterSetState, }, - GrandpaJustification, NewAuthoritySet, + GrandpaJustification, NewAuthoritySet, LOG_TARGET, }; const VERSION_KEY: &[u8] = b"grandpa_schema_version"; @@ -100,8 +100,8 @@ 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", "Node is in a potentially inconsistent state."); + warn!(target: LOG_TARGET, "Error migrating pending authority set change: {}", err); + warn!(target: LOG_TARGET, "Node is in a potentially inconsistent state."); } } @@ -384,8 +384,11 @@ where } // genesis. - info!(target: "afg", "👴 Loading GRANDPA authority set \ - from genesis on what appears to be first startup."); + info!( + target: LOG_TARGET, + "👴 Loading GRANDPA authority set \ + from genesis on what appears to be first startup." + ); let genesis_authorities = genesis_authorities()?; let genesis_set = AuthoritySet::genesis(genesis_authorities) diff --git a/client/finality-grandpa/src/communication/gossip.rs b/client/finality-grandpa/src/communication/gossip.rs index 218b4b668c10f..408cbda745e56 100644 --- a/client/finality-grandpa/src/communication/gossip.rs +++ b/client/finality-grandpa/src/communication/gossip.rs @@ -99,7 +99,7 @@ use sp_finality_grandpa::AuthorityId; use sp_runtime::traits::{Block as BlockT, NumberFor, Zero}; use super::{benefit, cost, Round, SetId, NEIGHBOR_REBROADCAST_PERIOD}; -use crate::{environment, CatchUp, CompactCommit, SignedMessage}; +use crate::{environment, CatchUp, CompactCommit, SignedMessage, LOG_TARGET}; use std::{ collections::{HashSet, VecDeque}, @@ -578,8 +578,13 @@ impl Peers { last_update: Some(now), }; - trace!(target: "afg", "Peer {} updated view. Now at {:?}, {:?}", - who, peer.view.round, peer.view.set_id); + trace!( + target: LOG_TARGET, + "Peer {} updated view. Now at {:?}, {:?}", + who, + peer.view.round, + peer.view.set_id + ); Ok(Some(&peer.view)) } @@ -801,8 +806,12 @@ impl Inner { let set_id = local_view.set_id; - debug!(target: "afg", "Voter {} noting beginning of round {:?} to network.", - self.config.name(), (round, set_id)); + debug!( + target: LOG_TARGET, + "Voter {} noting beginning of round {:?} to network.", + self.config.name(), + (round, set_id) + ); local_view.update_round(round); @@ -824,7 +833,7 @@ impl Inner { authorities.iter().collect::>(); if diff_authorities { - debug!(target: "afg", + debug!(target: LOG_TARGET, "Gossip validator noted set {:?} twice with different authorities. \ Was the authority set hard forked?", set_id, @@ -912,7 +921,7 @@ impl Inner { // ensure authority is part of the set. if !self.authorities.contains(&full.message.id) { - debug!(target: "afg", "Message from unknown voter: {}", full.message.id); + debug!(target: LOG_TARGET, "Message from unknown voter: {}", full.message.id); telemetry!( self.config.telemetry; CONSENSUS_DEBUG; @@ -929,7 +938,7 @@ impl Inner { full.round.0, full.set_id.0, ) { - debug!(target: "afg", "Bad message signature {}", full.message.id); + debug!(target: LOG_TARGET, "Bad message signature {}", full.message.id); telemetry!( self.config.telemetry; CONSENSUS_DEBUG; @@ -964,7 +973,7 @@ impl Inner { if full.message.precommits.len() != full.message.auth_data.len() || full.message.precommits.is_empty() { - debug!(target: "afg", "Malformed compact commit"); + debug!(target: LOG_TARGET, "Malformed compact commit"); telemetry!( self.config.telemetry; CONSENSUS_DEBUG; @@ -1023,9 +1032,9 @@ impl Inner { PendingCatchUp::Processing { .. } => { self.pending_catch_up = PendingCatchUp::None; }, - state => debug!(target: "afg", - "Noted processed catch up message when state was: {:?}", - state, + state => debug!( + target: LOG_TARGET, + "Noted processed catch up message when state was: {:?}", state, ), } } @@ -1067,7 +1076,9 @@ impl Inner { return (None, Action::Discard(Misbehavior::OutOfScopeMessage.cost())) } - trace!(target: "afg", "Replying to catch-up request for round {} from {} with round {}", + trace!( + target: LOG_TARGET, + "Replying to catch-up request for round {} from {} with round {}", request.round.0, who, last_completed_round.number, @@ -1141,9 +1152,9 @@ impl Inner { let (catch_up_allowed, catch_up_report) = self.note_catch_up_request(who, &request); if catch_up_allowed { - debug!(target: "afg", "Sending catch-up request for round {} to {}", - round, - who, + debug!( + target: LOG_TARGET, + "Sending catch-up request for round {} to {}", round, who, ); catch_up = Some(GossipMessage::::CatchUpRequest(request)); @@ -1347,7 +1358,7 @@ impl GossipValidator { let metrics = match prometheus_registry.map(Metrics::register) { Some(Ok(metrics)) => Some(metrics), Some(Err(e)) => { - debug!(target: "afg", "Failed to register metrics: {:?}", e); + debug!(target: LOG_TARGET, "Failed to register metrics: {:?}", e); None }, None => None, @@ -1466,7 +1477,7 @@ impl GossipValidator { }, Err(e) => { message_name = None; - debug!(target: "afg", "Error decoding message: {}", e); + debug!(target: LOG_TARGET, "Error decoding message: {}", e); telemetry!( self.telemetry; CONSENSUS_DEBUG; diff --git a/client/finality-grandpa/src/communication/mod.rs b/client/finality-grandpa/src/communication/mod.rs index 75a7697812c6c..e7e3c12989c96 100644 --- a/client/finality-grandpa/src/communication/mod.rs +++ b/client/finality-grandpa/src/communication/mod.rs @@ -54,7 +54,7 @@ use sp_runtime::traits::{Block as BlockT, Hash as HashT, Header as HeaderT, Numb use crate::{ environment::HasVoted, CatchUp, Commit, CommunicationIn, CommunicationOutH, CompactCommit, - Error, Message, SignedMessage, + Error, Message, SignedMessage, LOG_TARGET, }; use gossip::{ FullCatchUpMessage, FullCommitMessage, GossipMessage, GossipValidator, PeerReport, VoteMessage, @@ -274,7 +274,8 @@ impl> NetworkBridge { gossip_engine.lock().register_gossip_message(topic, message.encode()); } - trace!(target: "afg", + trace!( + target: LOG_TARGET, "Registered {} messages for topic {:?} (round: {}, set_id: {})", round.votes.len(), topic, @@ -340,13 +341,19 @@ impl> NetworkBridge { match decoded { Err(ref e) => { - debug!(target: "afg", "Skipping malformed message {:?}: {}", notification, e); + debug!( + target: LOG_TARGET, + "Skipping malformed message {:?}: {}", notification, e + ); future::ready(None) }, Ok(GossipMessage::Vote(msg)) => { // check signature. if !voters.contains(&msg.message.id) { - debug!(target: "afg", "Skipping message from unknown voter {}", msg.message.id); + debug!( + target: LOG_TARGET, + "Skipping message from unknown voter {}", msg.message.id + ); return future::ready(None) } @@ -388,7 +395,7 @@ impl> NetworkBridge { future::ready(Some(msg.message)) }, _ => { - debug!(target: "afg", "Skipping unknown message type"); + debug!(target: LOG_TARGET, "Skipping unknown message type"); future::ready(None) }, } @@ -631,7 +638,12 @@ fn incoming_global( // this could be optimized by decoding piecewise. let decoded = GossipMessage::::decode(&mut ¬ification.message[..]); if let Err(ref e) = decoded { - trace!(target: "afg", "Skipping malformed commit message {:?}: {}", notification, e); + trace!( + target: LOG_TARGET, + "Skipping malformed commit message {:?}: {}", + notification, + e + ); } future::ready(decoded.map(move |d| (notification, d)).ok()) }) @@ -642,7 +654,7 @@ fn incoming_global( GossipMessage::CatchUp(msg) => process_catch_up(msg, notification, &gossip_engine, &gossip_validator, &voters), _ => { - debug!(target: "afg", "Skipping unknown message type"); + debug!(target: LOG_TARGET, "Skipping unknown message type"); None }, }) @@ -748,7 +760,7 @@ impl Sink> for OutgoingMessages { }); debug!( - target: "afg", + target: LOG_TARGET, "Announcing block {} to peers which we voted on in round {} in set {}", target_hash, self.round, @@ -813,7 +825,7 @@ fn check_compact_commit( return Err(cost::MALFORMED_COMMIT) } } else { - debug!(target: "afg", "Skipping commit containing unknown voter {}", id); + debug!(target: LOG_TARGET, "Skipping commit containing unknown voter {}", id); return Err(cost::MALFORMED_COMMIT) } } @@ -838,7 +850,7 @@ fn check_compact_commit( set_id.0, &mut buf, ) { - debug!(target: "afg", "Bad commit message signature {}", id); + debug!(target: LOG_TARGET, "Bad commit message signature {}", id); telemetry!( telemetry; CONSENSUS_DEBUG; @@ -886,7 +898,10 @@ fn check_catch_up( return Err(cost::MALFORMED_CATCH_UP) } } else { - debug!(target: "afg", "Skipping catch up message containing unknown voter {}", id); + debug!( + target: LOG_TARGET, + "Skipping catch up message containing unknown voter {}", id + ); return Err(cost::MALFORMED_CATCH_UP) } } @@ -922,7 +937,7 @@ fn check_catch_up( if !sp_finality_grandpa::check_message_signature_with_buffer( &msg, id, sig, round, set_id, buf, ) { - debug!(target: "afg", "Bad catch up message signature {}", id); + debug!(target: LOG_TARGET, "Bad catch up message signature {}", id); telemetry!( telemetry; CONSENSUS_DEBUG; diff --git a/client/finality-grandpa/src/communication/periodic.rs b/client/finality-grandpa/src/communication/periodic.rs index c001796b5ca5d..7e50abb96e441 100644 --- a/client/finality-grandpa/src/communication/periodic.rs +++ b/client/finality-grandpa/src/communication/periodic.rs @@ -21,17 +21,19 @@ use futures::{future::FutureExt as _, prelude::*, ready, stream::Stream}; use futures_timer::Delay; use log::debug; -use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; use std::{ pin::Pin, task::{Context, Poll}, time::Duration, }; -use super::gossip::{GossipMessage, NeighborPacket}; use sc_network::PeerId; +use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; use sp_runtime::traits::{Block as BlockT, NumberFor}; +use super::gossip::{GossipMessage, NeighborPacket}; +use crate::LOG_TARGET; + /// A sender used to send neighbor packets to a background job. #[derive(Clone)] pub(super) struct NeighborPacketSender( @@ -46,7 +48,7 @@ impl NeighborPacketSender { neighbor_packet: NeighborPacket>, ) { if let Err(err) = self.0.unbounded_send((who, neighbor_packet)) { - debug!(target: "afg", "Failed to send neighbor packet: {:?}", err); + debug!(target: LOG_TARGET, "Failed to send neighbor packet: {:?}", err); } } } diff --git a/client/finality-grandpa/src/environment.rs b/client/finality-grandpa/src/environment.rs index f235c3a86c04e..110d0eb2c927e 100644 --- a/client/finality-grandpa/src/environment.rs +++ b/client/finality-grandpa/src/environment.rs @@ -60,7 +60,7 @@ use crate::{ until_imported::UntilVoteTargetImported, voting_rule::VotingRule as VotingRuleT, ClientForGrandpa, CommandOrError, Commit, Config, Error, NewAuthoritySet, Precommit, Prevote, - PrimaryPropose, SignedMessage, VoterCommand, + PrimaryPropose, SignedMessage, VoterCommand, LOG_TARGET, }; type HistoricalVotes = finality_grandpa::HistoricalVotes< @@ -551,7 +551,10 @@ where { Some(proof) => proof, None => { - debug!(target: "afg", "Equivocation offender is not part of the authority set."); + debug!( + target: LOG_TARGET, + "Equivocation offender is not part of the authority set." + ); return Ok(()) }, }; @@ -609,8 +612,13 @@ 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 {:?}: {}", - block, base, e); + debug!( + target: LOG_TARGET, + "Encountered error computing ancestry between block {:?} and base {:?}: {}", + block, + base, + e + ); return Err(GrandpaError::NotDescendent) }, @@ -955,7 +963,8 @@ where historical_votes: &HistoricalVotes, ) -> Result<(), Self::Error> { debug!( - target: "afg", "Voter {} completed round {} in set {}. Estimate = {:?}, Finalized in round = {:?}", + target: LOG_TARGET, + "Voter {} completed round {} in set {}. Estimate = {:?}, Finalized in round = {:?}", self.config.name(), round, self.set_id, @@ -1016,7 +1025,8 @@ where historical_votes: &HistoricalVotes, ) -> Result<(), Self::Error> { debug!( - target: "afg", "Voter {} concluded round {} in set {}. Estimate = {:?}, Finalized in round = {:?}", + target: LOG_TARGET, + "Voter {} concluded round {} in set {}. Estimate = {:?}, Finalized in round = {:?}", self.config.name(), round, self.set_id, @@ -1102,9 +1112,12 @@ where Self::Signature, >, ) { - warn!(target: "afg", "Detected prevote equivocation in the finality worker: {:?}", equivocation); + warn!( + target: LOG_TARGET, + "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: LOG_TARGET, "Error reporting prevote equivocation: {}", err); } } @@ -1117,9 +1130,12 @@ where Self::Signature, >, ) { - warn!(target: "afg", "Detected precommit equivocation in the finality worker: {:?}", equivocation); + warn!( + target: LOG_TARGET, + "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: LOG_TARGET, "Error reporting precommit equivocation: {}", err); } } } @@ -1158,7 +1174,8 @@ where let base_header = match client.header(BlockId::Hash(block))? { Some(h) => h, None => { - debug!(target: "afg", + debug!( + target: LOG_TARGET, "Encountered error finding best chain containing {:?}: couldn't find base block", block, ); @@ -1172,7 +1189,10 @@ where // proceed onwards. most of the time there will be no pending transition. the limit, if any, is // guaranteed to be higher than or equal to the given base number. let limit = authority_set.current_limit(*base_header.number()); - debug!(target: "afg", "Finding best chain containing block {:?} with number limit {:?}", block, limit); + debug!( + target: LOG_TARGET, + "Finding best chain containing block {:?} with number limit {:?}", block, limit + ); let result = match select_chain.finality_target(block, None).await { Ok(best_hash) => { @@ -1234,7 +1254,10 @@ 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: LOG_TARGET, + "Encountered error finding best chain containing {:?}: {}", block, e + ); None }, }; @@ -1273,7 +1296,7 @@ where // This can happen after a forced change (triggered manually from the runtime when // finality is stalled), since the voter will be restarted at the median last finalized // block, which can be lower than the local best finalized block. - warn!(target: "afg", "Re-finalized block #{:?} ({:?}) in the canonical chain, current best finalized is #{:?}", + warn!(target: LOG_TARGET, "Re-finalized block #{:?} ({:?}) in the canonical chain, current best finalized is #{:?}", hash, number, status.finalized_number, @@ -1303,7 +1326,10 @@ 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: LOG_TARGET, + "Error creating justification for subscriber: {}", err + ); } } } @@ -1354,11 +1380,16 @@ where client .apply_finality(import_op, hash, persisted_justification, true) .map_err(|e| { - warn!(target: "afg", "Error applying finality to block {:?}: {}", (hash, number), e); + warn!( + target: LOG_TARGET, + "Error applying finality to block {:?}: {}", + (hash, number), + e + ); e })?; - debug!(target: "afg", "Finalizing blocks up to ({:?}, {})", number, hash); + debug!(target: LOG_TARGET, "Finalizing blocks up to ({:?}, {})", number, hash); telemetry!( telemetry; @@ -1376,13 +1407,17 @@ where let (new_id, set_ref) = authority_set.current(); if set_ref.len() > 16 { - afg_log!( + grandpa_log!( initial_sync, "👴 Applying GRANDPA set change to new set with {} authorities", set_ref.len(), ); } else { - afg_log!(initial_sync, "👴 Applying GRANDPA set change to new set {:?}", set_ref); + grandpa_log!( + initial_sync, + "👴 Applying GRANDPA set change to new set {:?}", + set_ref + ); } telemetry!( @@ -1411,8 +1446,11 @@ where ); if let Err(e) = write_result { - warn!(target: "afg", "Failed to write updated authority set to disk. Bailing."); - warn!(target: "afg", "Node is in a potentially inconsistent state."); + warn!( + target: LOG_TARGET, + "Failed to write updated authority set to disk. Bailing." + ); + warn!(target: LOG_TARGET, "Node is in a potentially inconsistent state."); return Err(e.into()) } diff --git a/client/finality-grandpa/src/finality_proof.rs b/client/finality-grandpa/src/finality_proof.rs index 453b41bc63468..43ed0ed31993e 100644 --- a/client/finality-grandpa/src/finality_proof.rs +++ b/client/finality-grandpa/src/finality_proof.rs @@ -52,7 +52,7 @@ use crate::{ authorities::{AuthoritySetChangeId, AuthoritySetChanges}, best_justification, justification::GrandpaJustification, - SharedAuthoritySet, + SharedAuthoritySet, LOG_TARGET, }; const MAX_UNKNOWN_HEADERS: usize = 100_000; @@ -163,7 +163,7 @@ where "Requested finality proof for descendant of #{} while we only have finalized #{}.", block, info.finalized_number, ); - trace!(target: "afg", "{}", &err); + trace!(target: LOG_TARGET, "{}", &err); return Err(FinalityProofError::BlockNotYetFinalized) } @@ -175,7 +175,7 @@ where justification } else { trace!( - target: "afg", + target: LOG_TARGET, "No justification found for the latest finalized block. \ Returning empty proof.", ); @@ -194,7 +194,7 @@ where grandpa_justification } else { trace!( - target: "afg", + target: LOG_TARGET, "No justification found when making finality proof for {}. \ Returning empty proof.", block, @@ -205,7 +205,7 @@ where }, AuthoritySetChangeId::Unknown => { warn!( - target: "afg", + target: LOG_TARGET, "AuthoritySetChanges does not cover the requested block #{} due to missing data. \ You need to resync to populate AuthoritySetChanges properly.", block, diff --git a/client/finality-grandpa/src/import.rs b/client/finality-grandpa/src/import.rs index 3715287eea31f..e061c105eeea5 100644 --- a/client/finality-grandpa/src/import.rs +++ b/client/finality-grandpa/src/import.rs @@ -45,6 +45,7 @@ use crate::{ justification::GrandpaJustification, notification::GrandpaJustificationSender, AuthoritySetChanges, ClientForGrandpa, CommandOrError, Error, NewAuthoritySet, VoterCommand, + LOG_TARGET, }; /// A block-import handler for GRANDPA. @@ -589,18 +590,16 @@ where Ok(ImportResult::Imported(aux)) => aux, Ok(r) => { debug!( - target: "afg", - "Restoring old authority set after block import result: {:?}", - r, + target: LOG_TARGET, + "Restoring old authority set after block import result: {:?}", r, ); pending_changes.revert(); return Ok(r) }, Err(e) => { debug!( - target: "afg", - "Restoring old authority set after block import error: {}", - e, + target: LOG_TARGET, + "Restoring old authority set after block import error: {}", e, ); pending_changes.revert(); return Err(ConsensusError::ClientImport(e.to_string())) @@ -665,7 +664,7 @@ where import_res.unwrap_or_else(|err| { if needs_justification { debug!( - target: "afg", + target: LOG_TARGET, "Requesting justification from peers due to imported block #{} that enacts authority set change with invalid justification: {}", number, err @@ -678,7 +677,7 @@ where None => if needs_justification { debug!( - target: "afg", + target: LOG_TARGET, "Imported unjustified block #{} that enacts authority set change, waiting for finality for enactment.", number, ); @@ -803,7 +802,7 @@ where match result { Err(CommandOrError::VoterCommand(command)) => { - afg_log!( + grandpa_log!( initial_sync, "👴 Imported justification for block #{} that triggers \ command {}, signaling voter.", diff --git a/client/finality-grandpa/src/lib.rs b/client/finality-grandpa/src/lib.rs index c1b4962d04a12..efc46d8f93a6d 100644 --- a/client/finality-grandpa/src/lib.rs +++ b/client/finality-grandpa/src/lib.rs @@ -93,10 +93,12 @@ use std::{ time::Duration, }; +const LOG_TARGET: &str = "grandpa"; + // utility logging macro that takes as first argument a conditional to // decide whether to log under debug or info level (useful to restrict // logging under initial sync). -macro_rules! afg_log { +macro_rules! grandpa_log { ($condition:expr, $($msg: expr),+ $(,)?) => { { let log_level = if $condition { @@ -105,7 +107,7 @@ macro_rules! afg_log { log::Level::Info }; - log::log!(target: "afg", log_level, $($msg),+); + log::log!(target: LOG_TARGET, log_level, $($msg),+); } }; } @@ -803,10 +805,11 @@ where ); let voter_work = voter_work.map(|res| match res { - Ok(()) => error!(target: "afg", + Ok(()) => error!( + target: LOG_TARGET, "GRANDPA voter future has concluded naturally, this should be unreachable." ), - Err(e) => error!(target: "afg", "GRANDPA voter error: {}", e), + Err(e) => error!(target: LOG_TARGET, "GRANDPA voter error: {}", e), }); // Make sure that `telemetry_task` doesn't accidentally finish and kill grandpa. @@ -871,7 +874,7 @@ where let metrics = match prometheus_registry.as_ref().map(Metrics::register) { Some(Ok(metrics)) => Some(metrics), Some(Err(e)) => { - debug!(target: "afg", "Failed to register metrics: {:?}", e); + debug!(target: LOG_TARGET, "Failed to register metrics: {:?}", e); None }, None => None, @@ -913,7 +916,12 @@ where /// state. This method should be called when we know that the authority set /// has changed (e.g. as signalled by a voter command). fn rebuild_voter(&mut self) { - debug!(target: "afg", "{}: Starting new voter with set ID {}", self.env.config.name(), self.env.set_id); + debug!( + target: LOG_TARGET, + "{}: Starting new voter with set ID {}", + self.env.config.name(), + self.env.set_id + ); let maybe_authority_id = local_authority_id(&self.env.voters, self.env.config.keystore.as_ref()); @@ -974,7 +982,8 @@ where // Repoint shared_voter_state so that the RPC endpoint can query the state if self.shared_voter_state.reset(voter.voter_state()).is_none() { - info!(target: "afg", + info!( + target: LOG_TARGET, "Timed out trying to update shared GRANDPA voter state. \ RPC endpoints may return stale data." ); @@ -1043,7 +1052,7 @@ where Ok(()) }, VoterCommand::Pause(reason) => { - info!(target: "afg", "Pausing old validator set: {}", reason); + info!(target: LOG_TARGET, "Pausing old validator set: {}", reason); // not racing because old voter is shut down. self.env.update_voter_set_state(|voter_set_state| { diff --git a/client/finality-grandpa/src/observer.rs b/client/finality-grandpa/src/observer.rs index 9bcb03c0555c2..1efb71e5903ec 100644 --- a/client/finality-grandpa/src/observer.rs +++ b/client/finality-grandpa/src/observer.rs @@ -43,7 +43,7 @@ use crate::{ environment, global_communication, notification::GrandpaJustificationSender, ClientForGrandpa, CommandOrError, CommunicationIn, Config, Error, LinkHalf, VoterCommand, - VoterSetState, + VoterSetState, LOG_TARGET, }; struct ObserverChain<'a, Block: BlockT, Client> { @@ -145,7 +145,7 @@ where // proceed processing with new finalized block number future::ok(finalized_number) } else { - debug!(target: "afg", "Received invalid commit: ({:?}, {:?})", round, commit); + debug!(target: LOG_TARGET, "Received invalid commit: ({:?}, {:?})", round, commit); finality_grandpa::process_commit_validation_result(validation_result, callback); @@ -317,7 +317,7 @@ where // update it on-disk in case we restart as validator in the future. self.persistent_data.set_state = match command { VoterCommand::Pause(reason) => { - info!(target: "afg", "Pausing old validator set: {}", reason); + info!(target: LOG_TARGET, "Pausing old validator set: {}", reason); let completed_rounds = self.persistent_data.set_state.read().completed_rounds(); let set_state = VoterSetState::Paused { completed_rounds }; diff --git a/client/finality-grandpa/src/until_imported.rs b/client/finality-grandpa/src/until_imported.rs index df0b63348e94b..95b658e92298a 100644 --- a/client/finality-grandpa/src/until_imported.rs +++ b/client/finality-grandpa/src/until_imported.rs @@ -24,7 +24,7 @@ use super::{ BlockStatus as BlockStatusT, BlockSyncRequester as BlockSyncRequesterT, CommunicationIn, Error, - SignedMessage, + SignedMessage, LOG_TARGET, }; use finality_grandpa::voter; @@ -296,7 +296,7 @@ where let next_log = *last_log + LOG_PENDING_INTERVAL; if Instant::now() >= next_log { debug!( - target: "afg", + target: LOG_TARGET, "Waiting to import block {} before {} {} messages can be imported. \ Requesting network sync service to retrieve block from. \ Possible fork?", @@ -346,7 +346,7 @@ where fn warn_authority_wrong_target(hash: H, id: AuthorityId) { warn!( - target: "afg", + target: LOG_TARGET, "Authority {:?} signed GRANDPA message with \ wrong block number for hash {}", id, diff --git a/frame/aura/src/lib.rs b/frame/aura/src/lib.rs index ff2c5df04a453..635e22c5d58aa 100644 --- a/frame/aura/src/lib.rs +++ b/frame/aura/src/lib.rs @@ -58,6 +58,8 @@ mod tests; pub use pallet::*; +const LOG_TARGET: &str = "runtime::aura"; + #[frame_support::pallet] pub mod pallet { use super::*; @@ -222,7 +224,7 @@ impl OneSessionHandler for Pallet { if last_authorities != next_authorities { if next_authorities.len() as u32 > T::MaxAuthorities::get() { log::warn!( - target: "runtime::aura", + target: LOG_TARGET, "next authorities list larger than {}, truncating", T::MaxAuthorities::get(), ); diff --git a/frame/babe/src/equivocation.rs b/frame/babe/src/equivocation.rs index f55bda751887d..70f087fd461f9 100644 --- a/frame/babe/src/equivocation.rs +++ b/frame/babe/src/equivocation.rs @@ -48,7 +48,7 @@ use sp_staking::{ }; use sp_std::prelude::*; -use crate::{Call, Config, Pallet}; +use crate::{Call, Config, Pallet, LOG_TARGET}; /// A trait with utility methods for handling equivocation reports in BABE. /// The trait provides methods for reporting an offence triggered by a valid @@ -161,15 +161,9 @@ where }; match SubmitTransaction::>::submit_unsigned_transaction(call.into()) { - Ok(()) => log::info!( - target: "runtime::babe", - "Submitted BABE equivocation report.", - ), - Err(e) => log::error!( - target: "runtime::babe", - "Error submitting equivocation report: {:?}", - e, - ), + Ok(()) => log::info!(target: LOG_TARGET, "Submitted BABE equivocation report.",), + Err(e) => + log::error!(target: LOG_TARGET, "Error submitting equivocation report: {:?}", e,), } Ok(()) @@ -192,7 +186,7 @@ impl Pallet { TransactionSource::Local | TransactionSource::InBlock => { /* allowed */ }, _ => { log::warn!( - target: "runtime::babe", + target: LOG_TARGET, "rejecting unsigned report equivocation transaction because it is not local/in-block.", ); diff --git a/frame/babe/src/lib.rs b/frame/babe/src/lib.rs index 1a9b3200087ae..16b2b2119793a 100644 --- a/frame/babe/src/lib.rs +++ b/frame/babe/src/lib.rs @@ -50,6 +50,8 @@ use sp_consensus_vrf::schnorrkel; pub use sp_consensus_babe::{AuthorityId, PUBLIC_KEY_LENGTH, RANDOMNESS_LENGTH, VRF_OUTPUT_LENGTH}; +const LOG_TARGET: &str = "runtime::babe"; + mod default_weights; mod equivocation; mod randomness; diff --git a/frame/grandpa/src/equivocation.rs b/frame/grandpa/src/equivocation.rs index 181d22fba545c..23801a4982a82 100644 --- a/frame/grandpa/src/equivocation.rs +++ b/frame/grandpa/src/equivocation.rs @@ -52,7 +52,7 @@ use sp_staking::{ SessionIndex, }; -use super::{Call, Config, Pallet}; +use super::{Call, Config, Pallet, LOG_TARGET}; /// A trait with utility methods for handling equivocation reports in GRANDPA. /// The offence type is generic, and the trait provides , reporting an offence @@ -170,15 +170,9 @@ where }; match SubmitTransaction::>::submit_unsigned_transaction(call.into()) { - Ok(()) => log::info!( - target: "runtime::afg", - "Submitted GRANDPA equivocation report.", - ), - Err(e) => log::error!( - target: "runtime::afg", - "Error submitting equivocation report: {:?}", - e, - ), + Ok(()) => log::info!(target: LOG_TARGET, "Submitted GRANDPA equivocation report.",), + Err(e) => + log::error!(target: LOG_TARGET, "Error submitting equivocation report: {:?}", e,), } Ok(()) @@ -211,7 +205,7 @@ impl Pallet { TransactionSource::Local | TransactionSource::InBlock => { /* allowed */ }, _ => { log::warn!( - target: "runtime::afg", + target: LOG_TARGET, "rejecting unsigned report equivocation transaction because it is not local/in-block." ); diff --git a/frame/grandpa/src/lib.rs b/frame/grandpa/src/lib.rs index c6b7fd251661f..716cf54865773 100644 --- a/frame/grandpa/src/lib.rs +++ b/frame/grandpa/src/lib.rs @@ -70,6 +70,8 @@ pub use equivocation::{ pub use pallet::*; +const LOG_TARGET: &str = "runtime::grandpa"; + #[frame_support::pallet] pub mod pallet { use super::*; diff --git a/frame/grandpa/src/migrations/v4.rs b/frame/grandpa/src/migrations/v4.rs index 81dbd3bab4b67..33e200b728336 100644 --- a/frame/grandpa/src/migrations/v4.rs +++ b/frame/grandpa/src/migrations/v4.rs @@ -15,6 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +use crate::LOG_TARGET; use frame_support::{ traits::{Get, StorageVersion}, weights::Weight, @@ -34,14 +35,14 @@ pub const OLD_PREFIX: &[u8] = b"GrandpaFinality"; pub fn migrate>(new_pallet_name: N) -> Weight { if new_pallet_name.as_ref().as_bytes() == OLD_PREFIX { log::info!( - target: "runtime::afg", + target: LOG_TARGET, "New pallet name is equal to the old prefix. No migration needs to be done.", ); return Weight::zero() } let storage_version = StorageVersion::get::>(); log::info!( - target: "runtime::afg", + target: LOG_TARGET, "Running migration to v3.1 for grandpa with storage version {:?}", storage_version, ); From bb94ac73b65a4b21186efaf5a870b5550aa056aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Wed, 14 Dec 2022 22:55:24 +0000 Subject: [PATCH 191/715] Staking: store last `min-active-bond` on-chain (#12889) * Staking: store last min-active-bond on-chain Storing the `min-active-bond` onchain helps the UIs with minimal on-chain costs. Closes https://github.com/paritytech/substrate/issues/12746 * Avoid relying on sorting to set the * Addresses PR comments --- frame/staking/src/pallet/impls.rs | 14 +++++++++++++- frame/staking/src/pallet/mod.rs | 4 ++++ frame/staking/src/tests.rs | 26 ++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 1a4086ad2ab11..830b33ceb69a2 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -704,6 +704,9 @@ impl Pallet { /// /// `maybe_max_len` can imposes a cap on the number of voters returned; /// + /// Sets `MinimumActiveStake` to the minimum active nominator stake in the returned set of + /// nominators. + /// /// This function is self-weighing as [`DispatchClass::Mandatory`]. pub fn get_npos_voters(maybe_max_len: Option) -> Vec> { let max_allowed_len = { @@ -719,6 +722,7 @@ impl Pallet { let mut voters_seen = 0u32; let mut validators_taken = 0u32; let mut nominators_taken = 0u32; + let mut min_active_stake = u64::MAX; let mut sorted_voters = T::VoterList::iter(); while all_voters.len() < max_allowed_len && @@ -733,12 +737,15 @@ impl Pallet { }; if let Some(Nominations { targets, .. }) = >::get(&voter) { + let voter_weight = weight_of(&voter); if !targets.is_empty() { - all_voters.push((voter.clone(), weight_of(&voter), targets)); + all_voters.push((voter.clone(), voter_weight, targets)); nominators_taken.saturating_inc(); } else { // Technically should never happen, but not much we can do about it. } + min_active_stake = + if voter_weight < min_active_stake { voter_weight } else { min_active_stake }; } else if Validators::::contains_key(&voter) { // if this voter is a validator: let self_vote = ( @@ -769,6 +776,11 @@ impl Pallet { Self::register_weight(T::WeightInfo::get_npos_voters(validators_taken, nominators_taken)); + let min_active_stake: T::CurrencyBalance = + if all_voters.len() == 0 { 0u64.into() } else { min_active_stake.into() }; + + MinimumActiveStake::::put(min_active_stake); + log!( info, "generated {} npos voters, {} from validators and {} nominators", diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index fda455ca3c166..2daa992f4ef6e 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -295,6 +295,10 @@ pub mod pallet { #[pallet::storage] pub type MinValidatorBond = StorageValue<_, BalanceOf, ValueQuery>; + /// The minimum active nominator stake of the last successful election. + #[pallet::storage] + pub type MinimumActiveStake = StorageValue<_, BalanceOf, ValueQuery>; + /// The minimum amount of commission that validators can set. /// /// If set to `0`, no limit exists. diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 3e0a62f53d886..74d8dc8a8105c 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -4463,6 +4463,32 @@ mod election_data_provider { ); } + #[test] + fn set_minimum_active_stake_is_correct() { + ExtBuilder::default() + .nominate(false) + .add_staker(61, 60, 2_000, StakerStatus::::Nominator(vec![21])) + .add_staker(71, 70, 10, StakerStatus::::Nominator(vec![21])) + .add_staker(81, 80, 50, StakerStatus::::Nominator(vec![21])) + .build_and_execute(|| { + assert_ok!(::electing_voters(None)); + assert_eq!(MinimumActiveStake::::get(), 10); + + // remove staker with lower bond by limiting the number of voters and check + // `MinimumActiveStake` again after electing voters. + assert_ok!(::electing_voters(Some(5))); + assert_eq!(MinimumActiveStake::::get(), 50); + }); + } + + #[test] + fn set_minimum_active_stake_zero_correct() { + ExtBuilder::default().has_stakers(false).build_and_execute(|| { + assert_ok!(::electing_voters(None)); + assert_eq!(MinimumActiveStake::::get(), 0); + }); + } + #[test] fn voters_include_self_vote() { ExtBuilder::default().nominate(false).build_and_execute(|| { From cd2fdcf85eb96c53ce2a5d418d4338eb92f5d4f5 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Wed, 14 Dec 2022 23:59:01 +0000 Subject: [PATCH 192/715] Try-runtime Revamp and Facelift (#12537) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix online/offline confusion * unified cache file * multi-threaded babyyy * checkpoint for niklas * compiles * all tests pass with --test-threads 1 * child-tree scrape is also multi-threaded now. * better thread splitting * some suggestions (#12532) * some suggestions * tokio multithread * move unused dependencies * snapshot command * fix rem * a bit of cleanup * support optional checks * fix * OCW command migrated to wasm-only, as an example * state-version management fully in remote-ext * almost everything move to wasm executor, some CLI flags reduced * follow-chain works as well * Master.into() * everything builds now * concurrent insertion and download for remote builds * minor fix * fix a bug * checkpoint * some updates * fmt * review comments * fmt * fix * fmt * update * fmt * rename * fix the damn UI tests * fmt * remoe the thread abstraction for the time being * cleanup * fix CI * fmt * fix * fix a few more things * tweak log levels * better error handling * address grumbles: use futures::mpsc * review comments * fmt * Apply suggestions from code review Co-authored-by: Bastian Köcher * Update utils/frame/try-runtime/cli/src/lib.rs Co-authored-by: Bastian Köcher * better api version stuff * some doc update * a whole lot of docs * fmt * fix all docs * fmt * rpc rebase: Try-runtime Revamp and Facelift (#12921) * 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 <> * Checkout to the branch HEAD explicitly in `build-linux-substrate` (#12876) * cli: Improve pruning documentation (#12819) * 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 * Revert "Move LockableCurrency trait to fungibles::Lockable and deprecate LockableCurrency (#12798)" (#12882) This reverts commit ea3ca3f757ff9d9559665719a77da81f4cf0f0ce. * 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: * 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 * 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 * Move import queue out of `sc-network` (#12764) * 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 * Trace response payload in default `jsonrpsee` middleware (#12886) * Trace result in default `jsonrpsee` middleware * `rpc_metrics::extra` Co-authored-by: Bastian Köcher Co-authored-by: Bastian Köcher * 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 <> * Safe desired targets call (#12826) * checked call for desired targets * fix compile * fmt * fix tests * cleaner with and_then * Fix typo (#12900) * ValidateUnsigned: Improve docs. (#12870) * ValidateUnsigned: Improve docs. * Review comments * 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 * `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 * 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 * Pin canonincalized block (#12902) * 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 <> * bounties calls docs fix (#12909) Co-authored-by: parity-processbot <> * pallet-contracts migration pre-upgrade fix for v8 (#12905) * Only run pre-v8 migration check for versions older than 8 * Logix fix * use custom environment for publishing crates (#12912) * [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 * frame/remote-externalities: Fix clippy Signed-off-by: Alexandru Vasile * frame/rpc: Add previous export Signed-off-by: Alexandru Vasile * Fixup some wrong dependencies (#12899) * Fixup some wrong dependencies Dev dependencies should not appear in the feature list. If features are required, they should be directly enabled for the `dev-dependency`. * More fixups * Fix fix * Remove deprecated feature * Make all work properly and nice!! * FMT * Fix formatting * add numerator and denominator to Rational128 Debug impl and increase precision of float representation (#12914) * Fix state-db pinning (#12927) * Pin all canonicalized blocks * Added a test * Docs * [ci] add job switcher (#12922) Signed-off-by: Alexandru Vasile Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Keith Yeung Co-authored-by: Vlad Co-authored-by: Bastian Köcher Co-authored-by: Anthony Alaribe Co-authored-by: Gavin Wood Co-authored-by: Oliver Tale-Yazdi Co-authored-by: Robert Klotzner Co-authored-by: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Co-authored-by: Aaro Altonen <48052676+altonen@users.noreply.github.com> Co-authored-by: tgmichel Co-authored-by: Ankan <10196091+Ank4n@users.noreply.github.com> Co-authored-by: Luke Schoen Co-authored-by: Niklas Adolfsson Co-authored-by: Arkadiy Paronyan Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: Andronik Co-authored-by: Ankan Co-authored-by: Muharem Ismailov Co-authored-by: Dino Pačandi <3002868+Dinonard@users.noreply.github.com> Co-authored-by: João Paulo Silva de Souza <77391175+joao-paulo-parity@users.noreply.github.com> Co-authored-by: Sasha Gryaznov Co-authored-by: Alexander Popiak Co-authored-by: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> * Revert "rpc rebase: Try-runtime Revamp and Facelift (#12921)" This reverts commit 4ce770a9cb8daf1401529bda7d974b8c703f6b3e. * Lexnv/kiz revamp try runtime stuff (#12932) * 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 <> * Checkout to the branch HEAD explicitly in `build-linux-substrate` (#12876) * cli: Improve pruning documentation (#12819) * 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 * Revert "Move LockableCurrency trait to fungibles::Lockable and deprecate LockableCurrency (#12798)" (#12882) This reverts commit ea3ca3f757ff9d9559665719a77da81f4cf0f0ce. * 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: * 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 * 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 * Move import queue out of `sc-network` (#12764) * 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 * Trace response payload in default `jsonrpsee` middleware (#12886) * Trace result in default `jsonrpsee` middleware * `rpc_metrics::extra` Co-authored-by: Bastian Köcher Co-authored-by: Bastian Köcher * 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 <> * Safe desired targets call (#12826) * checked call for desired targets * fix compile * fmt * fix tests * cleaner with and_then * Fix typo (#12900) * ValidateUnsigned: Improve docs. (#12870) * ValidateUnsigned: Improve docs. * Review comments * 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 * `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 * 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 * Pin canonincalized block (#12902) * 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 <> * bounties calls docs fix (#12909) Co-authored-by: parity-processbot <> * pallet-contracts migration pre-upgrade fix for v8 (#12905) * Only run pre-v8 migration check for versions older than 8 * Logix fix * use custom environment for publishing crates (#12912) * [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 * frame/remote-externalities: Fix clippy Signed-off-by: Alexandru Vasile * frame/rpc: Add previous export Signed-off-by: Alexandru Vasile * Fixup some wrong dependencies (#12899) * Fixup some wrong dependencies Dev dependencies should not appear in the feature list. If features are required, they should be directly enabled for the `dev-dependency`. * More fixups * Fix fix * Remove deprecated feature * Make all work properly and nice!! * FMT * Fix formatting * add numerator and denominator to Rational128 Debug impl and increase precision of float representation (#12914) * Fix state-db pinning (#12927) * Pin all canonicalized blocks * Added a test * Docs * [ci] add job switcher (#12922) * Use LOG_TARGET in consensus related crates (#12875) * Use shared LOG_TARGET in consensus related crates * Rename target from "afg" to "grandpa" Signed-off-by: Alexandru Vasile Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Keith Yeung Co-authored-by: Vlad Co-authored-by: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Co-authored-by: Bastian Köcher Co-authored-by: Anthony Alaribe Co-authored-by: Gavin Wood Co-authored-by: Oliver Tale-Yazdi Co-authored-by: Robert Klotzner Co-authored-by: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Co-authored-by: Aaro Altonen <48052676+altonen@users.noreply.github.com> Co-authored-by: tgmichel Co-authored-by: Ankan <10196091+Ank4n@users.noreply.github.com> Co-authored-by: Luke Schoen Co-authored-by: Niklas Adolfsson Co-authored-by: Arkadiy Paronyan Co-authored-by: Andronik Co-authored-by: Ankan Co-authored-by: Muharem Ismailov Co-authored-by: Dino Pačandi <3002868+Dinonard@users.noreply.github.com> Co-authored-by: João Paulo Silva de Souza <77391175+joao-paulo-parity@users.noreply.github.com> Co-authored-by: Sasha Gryaznov Co-authored-by: Alexandru Vasile Co-authored-by: Alexander Popiak Co-authored-by: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Co-authored-by: Davide Galassi * Revert "Lexnv/kiz revamp try runtime stuff (#12932)" This reverts commit 378cfb26d984bcde467781f07ef8ddb6998212cb. * fmt * update * fix publish Signed-off-by: Alexandru Vasile Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Niklas Adolfsson Co-authored-by: Bastian Köcher Co-authored-by: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Co-authored-by: Keith Yeung Co-authored-by: Vlad Co-authored-by: Anthony Alaribe Co-authored-by: Gavin Wood Co-authored-by: Oliver Tale-Yazdi Co-authored-by: Robert Klotzner Co-authored-by: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Co-authored-by: Aaro Altonen <48052676+altonen@users.noreply.github.com> Co-authored-by: tgmichel Co-authored-by: Ankan <10196091+Ank4n@users.noreply.github.com> Co-authored-by: Luke Schoen Co-authored-by: Arkadiy Paronyan Co-authored-by: Andronik Co-authored-by: Ankan Co-authored-by: Muharem Ismailov Co-authored-by: Dino Pačandi <3002868+Dinonard@users.noreply.github.com> Co-authored-by: João Paulo Silva de Souza <77391175+joao-paulo-parity@users.noreply.github.com> Co-authored-by: Sasha Gryaznov Co-authored-by: Alexander Popiak Co-authored-by: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Co-authored-by: Alexandru Vasile Co-authored-by: Davide Galassi --- Cargo.lock | 79 +- bin/node-template/node/Cargo.toml | 1 + bin/node-template/node/src/command.rs | 10 +- bin/node-template/runtime/src/lib.rs | 7 +- bin/node/cli/Cargo.toml | 1 + bin/node/cli/src/command.rs | 9 +- bin/node/runtime/src/lib.rs | 14 +- frame/bags-list/remote-tests/src/migration.rs | 2 +- frame/bags-list/remote-tests/src/snapshot.rs | 18 +- frame/bags-list/remote-tests/src/try_state.rs | 8 +- frame/executive/Cargo.toml | 2 +- frame/executive/src/lib.rs | 94 +- frame/staking/Cargo.toml | 1 - frame/staking/src/pallet/impls.rs | 11 +- frame/state-trie-migration/src/lib.rs | 9 +- .../procedural/src/pallet/expand/hooks.rs | 2 +- frame/support/src/dispatch.rs | 2 +- frame/support/src/traits/hooks.rs | 177 +-- frame/support/src/traits/try_runtime.rs | 2 + ...age_ensure_span_are_ok_on_wrong_gen.stderr | 4 +- ...re_span_are_ok_on_wrong_gen_unnamed.stderr | 4 +- frame/try-runtime/src/lib.rs | 19 +- primitives/runtime/Cargo.toml | 1 + .../src/generic/unchecked_extrinsic.rs | 16 + primitives/runtime/src/testing.rs | 8 + primitives/runtime/src/traits.rs | 22 + primitives/storage/src/lib.rs | 1 + utils/frame/remote-externalities/Cargo.toml | 4 +- utils/frame/remote-externalities/src/lib.rs | 1194 ++++++++++------- .../remote-externalities/test_data/proxy_test | Bin 0 -> 70206 bytes .../test_data/proxy_test.top | Bin 39 -> 0 bytes utils/frame/rpc/client/src/lib.rs | 1 + utils/frame/try-runtime/cli/Cargo.toml | 16 +- .../cli/src/commands/create_snapshot.rs | 78 ++ .../cli/src/commands/execute_block.rs | 197 +-- .../cli/src/commands/follow_chain.rs | 128 +- .../frame/try-runtime/cli/src/commands/mod.rs | 9 +- .../cli/src/commands/offchain_worker.rs | 112 +- .../cli/src/commands/on_runtime_upgrade.rs | 56 +- utils/frame/try-runtime/cli/src/lib.rs | 923 +++++++------ 40 files changed, 1779 insertions(+), 1463 deletions(-) create mode 100644 utils/frame/remote-externalities/test_data/proxy_test delete mode 100644 utils/frame/remote-externalities/test_data/proxy_test.top create mode 100644 utils/frame/try-runtime/cli/src/commands/create_snapshot.rs diff --git a/Cargo.lock b/Cargo.lock index ea34146f16f9b..b840cadce3e5c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -269,9 +269,9 @@ checksum = "e91831deabf0d6d7ec49552e489aed63b7456a7a3c46cff62adad428110b0af0" [[package]] name = "async-trait" -version = "0.1.58" +version = "0.1.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e805d94e6b5001b651426cf4cd446b1ab5f319d27bab5c644f61de0a804360c" +checksum = "31e6e93155431f3931513b243d371981bb2770112b370c82745a1d19d2f99364" dependencies = [ "proc-macro2", "quote", @@ -2031,6 +2031,7 @@ version = "0.10.0-dev" dependencies = [ "env_logger", "frame-support", + "futures", "log", "pallet-elections-phragmen", "parity-scale-codec", @@ -2042,6 +2043,7 @@ dependencies = [ "sp-version", "substrate-rpc-client", "tokio", + "tracing-subscriber 0.3.16", ] [[package]] @@ -2874,9 +2876,9 @@ checksum = "879d54834c8c76457ef4293a689b2a8c59b076067ad77b15efafbb05f92a592b" [[package]] name = "itertools" -version = "0.10.3" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" dependencies = [ "either", ] @@ -3788,6 +3790,15 @@ dependencies = [ "regex-automata", ] +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata", +] + [[package]] name = "matches" version = "0.1.8" @@ -4271,6 +4282,7 @@ dependencies = [ "sp-core", "sp-finality-grandpa", "sp-inherents", + "sp-io", "sp-keyring", "sp-keystore", "sp-runtime", @@ -4427,6 +4439,7 @@ dependencies = [ "sp-core", "sp-finality-grandpa", "sp-inherents", + "sp-io", "sp-keyring", "sp-runtime", "sp-timestamp", @@ -4529,6 +4542,16 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + [[package]] name = "num-bigint" version = "0.4.3" @@ -4667,6 +4690,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + [[package]] name = "pallet-alliance" version = "4.0.0-dev" @@ -7585,7 +7614,7 @@ dependencies = [ "substrate-test-runtime", "tempfile", "tracing", - "tracing-subscriber", + "tracing-subscriber 0.2.25", "wasmi 0.13.0", "wat", ] @@ -8337,7 +8366,7 @@ dependencies = [ "thiserror", "tracing", "tracing-log", - "tracing-subscriber", + "tracing-subscriber 0.2.25", ] [[package]] @@ -8705,9 +8734,9 @@ dependencies = [ [[package]] name = "sharded-slab" -version = "0.1.1" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79c719719ee05df97490f80a45acfc99e5a30ce98a1e4fb67aee422745ae14e3" +checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" dependencies = [ "lazy_static", ] @@ -8763,9 +8792,9 @@ checksum = "03b634d87b960ab1a38c4fe143b508576f075e7c978bfad18217645ebfdfa2ec" [[package]] name = "smallvec" -version = "1.8.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" [[package]] name = "snap" @@ -9555,7 +9584,7 @@ dependencies = [ "sp-std", "tracing", "tracing-core", - "tracing-subscriber", + "tracing-subscriber 0.2.25", ] [[package]] @@ -10431,9 +10460,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.28" +version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b7358be39f2f274f322d2aaed611acc57f382e8eb1e5b48cb9ae30933495ce7" +checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" dependencies = [ "once_cell", "valuable", @@ -10479,7 +10508,7 @@ dependencies = [ "ansi_term", "chrono", "lazy_static", - "matchers", + "matchers 0.0.1", "parking_lot 0.11.2", "regex", "serde", @@ -10493,6 +10522,24 @@ dependencies = [ "tracing-serde", ] +[[package]] +name = "tracing-subscriber" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70" +dependencies = [ + "matchers 0.1.0", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + [[package]] name = "treeline" version = "0.1.0" @@ -10605,6 +10652,7 @@ dependencies = [ "clap 4.0.11", "frame-remote-externalities", "frame-try-runtime", + "hex", "log", "parity-scale-codec", "sc-chain-spec", @@ -10612,10 +10660,13 @@ dependencies = [ "sc-executor", "sc-service", "serde", + "sp-api", "sp-core", + "sp-debug-derive", "sp-externalities", "sp-io", "sp-keystore", + "sp-rpc", "sp-runtime", "sp-state-machine", "sp-version", diff --git a/bin/node-template/node/Cargo.toml b/bin/node-template/node/Cargo.toml index 2ea841093d0e2..364cfa25d3c6b 100644 --- a/bin/node-template/node/Cargo.toml +++ b/bin/node-template/node/Cargo.toml @@ -36,6 +36,7 @@ sc-finality-grandpa = { version = "0.10.0-dev", path = "../../../client/finality 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 = "7.0.0", path = "../../../primitives/runtime" } +sp-io = { version = "7.0.0", path = "../../../primitives/io" } sp-timestamp = { version = "4.0.0-dev", path = "../../../primitives/timestamp" } sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } sp-keyring = { version = "7.0.0", path = "../../../primitives/keyring" } diff --git a/bin/node-template/node/src/command.rs b/bin/node-template/node/src/command.rs index 6d293b7b85fcc..15cd69b34b5b2 100644 --- a/bin/node-template/node/src/command.rs +++ b/bin/node-template/node/src/command.rs @@ -174,6 +174,8 @@ pub fn run() -> sc_cli::Result<()> { }, #[cfg(feature = "try-runtime")] Some(Subcommand::TryRuntime(cmd)) => { + use crate::service::ExecutorDispatch; + use sc_executor::{sp_wasm_interface::ExtendedHostFunctions, NativeExecutionDispatch}; 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 @@ -182,7 +184,13 @@ pub fn run() -> sc_cli::Result<()> { 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)) + Ok(( + cmd.run::::ExtendHostFunctions, + >>(), + task_manager, + )) }) }, #[cfg(not(feature = "try-runtime"))] diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs index 938282c662b5c..f76b2c449ee4a 100644 --- a/bin/node-template/runtime/src/lib.rs +++ b/bin/node-template/runtime/src/lib.rs @@ -539,22 +539,23 @@ impl_runtime_apis! { #[cfg(feature = "try-runtime")] impl frame_try_runtime::TryRuntime for Runtime { - fn on_runtime_upgrade() -> (Weight, Weight) { + fn on_runtime_upgrade(checks: bool) -> (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(); + let weight = Executive::try_runtime_upgrade(checks).unwrap(); (weight, BlockWeights::get().max_block) } fn execute_block( block: Block, state_root_check: bool, + signature_check: bool, select: frame_try_runtime::TryStateSelect ) -> Weight { // NOTE: intentional unwrap: we don't want to propagate the error backwards, and want to // have a backtrace here. - Executive::try_execute_block(block, state_root_check, select).expect("execute-block failed") + Executive::try_execute_block(block, state_root_check, signature_check, select).expect("execute-block failed") } } } diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index 4ee4bcd033921..6b50115fd9a00 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -59,6 +59,7 @@ 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" } +sp-io = { path = "../../../primitives/io" } # client dependencies sc-client-api = { version = "4.0.0-dev", path = "../../../client/api" } diff --git a/bin/node/cli/src/command.rs b/bin/node/cli/src/command.rs index 108d7743843b6..fd464bbc914a5 100644 --- a/bin/node/cli/src/command.rs +++ b/bin/node/cli/src/command.rs @@ -227,6 +227,7 @@ pub fn run() -> Result<()> { }, #[cfg(feature = "try-runtime")] Some(Subcommand::TryRuntime(cmd)) => { + use sc_executor::{sp_wasm_interface::ExtendedHostFunctions, NativeExecutionDispatch}; 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 @@ -236,7 +237,13 @@ pub fn run() -> Result<()> { 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)) + Ok(( + cmd.run::::ExtendHostFunctions, + >>(), + task_manager, + )) }) }, #[cfg(not(feature = "try-runtime"))] diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 00d2a54d1e774..0e3bee8821fc2 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -2158,29 +2158,23 @@ impl_runtime_apis! { #[cfg(feature = "try-runtime")] impl frame_try_runtime::TryRuntime for Runtime { - fn on_runtime_upgrade() -> (Weight, Weight) { + fn on_runtime_upgrade(checks: bool) -> (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(); + let weight = Executive::try_runtime_upgrade(checks).unwrap(); (weight, RuntimeBlockWeights::get().max_block) } fn execute_block( block: Block, state_root_check: bool, + signature_check: bool, select: frame_try_runtime::TryStateSelect ) -> Weight { - 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() + Executive::try_execute_block(block, state_root_check, signature_check, select).unwrap() } } diff --git a/frame/bags-list/remote-tests/src/migration.rs b/frame/bags-list/remote-tests/src/migration.rs index b013472b4c90e..759906a4ef479 100644 --- a/frame/bags-list/remote-tests/src/migration.rs +++ b/frame/bags-list/remote-tests/src/migration.rs @@ -30,7 +30,7 @@ pub async fn execute( ws_url: String, ) where Runtime: RuntimeT, - Block: BlockT, + Block: BlockT + DeserializeOwned, Block::Header: DeserializeOwned, { let mut ext = Builder::::new() diff --git a/frame/bags-list/remote-tests/src/snapshot.rs b/frame/bags-list/remote-tests/src/snapshot.rs index cfe065924bd92..0163ca200a15d 100644 --- a/frame/bags-list/remote-tests/src/snapshot.rs +++ b/frame/bags-list/remote-tests/src/snapshot.rs @@ -25,7 +25,7 @@ use sp_runtime::{traits::Block as BlockT, DeserializeOwned}; pub async fn execute(voter_limit: Option, currency_unit: u64, ws_url: String) where Runtime: crate::RuntimeT, - Block: BlockT, + Block: BlockT + DeserializeOwned, Block::Header: DeserializeOwned, { use frame_support::storage::generator::StorageMap; @@ -38,14 +38,18 @@ where pallets: vec![pallet_bags_list::Pallet::::name() .to_string()], at: None, + hashed_prefixes: vec![ + >::prefix_hash(), + >::prefix_hash(), + >::map_storage_final_prefix(), + >::map_storage_final_prefix(), + ], + hashed_keys: vec![ + >::counter_storage_final_key().to_vec(), + >::counter_storage_final_key().to_vec(), + ], ..Default::default() })) - .inject_hashed_prefix(&>::prefix_hash()) - .inject_hashed_prefix(&>::prefix_hash()) - .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/bags-list/remote-tests/src/try_state.rs b/frame/bags-list/remote-tests/src/try_state.rs index d3fb63f045a64..514c80d72ab67 100644 --- a/frame/bags-list/remote-tests/src/try_state.rs +++ b/frame/bags-list/remote-tests/src/try_state.rs @@ -31,7 +31,7 @@ pub async fn execute( ws_url: String, ) where Runtime: crate::RuntimeT, - Block: BlockT, + Block: BlockT + DeserializeOwned, Block::Header: DeserializeOwned, { let mut ext = Builder::::new() @@ -39,10 +39,12 @@ pub async fn execute( transport: ws_url.to_string().into(), pallets: vec![pallet_bags_list::Pallet::::name() .to_string()], + hashed_prefixes: vec![ + >::prefix_hash(), + >::prefix_hash(), + ], ..Default::default() })) - .inject_hashed_prefix(&>::prefix_hash()) - .inject_hashed_prefix(&>::prefix_hash()) .build() .await .unwrap(); diff --git a/frame/executive/Cargo.toml b/frame/executive/Cargo.toml index b3e4247445710..a6d16e9b0793f 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" ] +try-runtime = ["frame-support/try-runtime", "frame-try-runtime/try-runtime", "sp-runtime/try-runtime"] diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index 6f59ac72eb2fd..1f20e93f43c30 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -227,27 +227,71 @@ where { /// Execute given block, but don't as strict is the normal block execution. /// - /// 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`. + /// Some checks can be disabled via: + /// + /// - `state_root_check` + /// - `signature_check` /// /// Should only be used for testing ONLY. pub fn try_execute_block( block: Block, - try_state_root: bool, + state_root_check: bool, + signature_check: bool, select: frame_try_runtime::TryStateSelect, - ) -> Result { - use frame_support::traits::TryState; + ) -> Result { + frame_support::log::info!( + target: "frame::executive", + "try-runtime: executing block #{:?} / state root check: {:?} / signature check: {:?} / try-state-select: {:?}", + block.header().number(), + state_root_check, + signature_check, + select, + ); Self::initialize_block(block.header()); Self::initial_checks(&block); let (header, extrinsics) = block.deconstruct(); - Self::execute_extrinsics_with_book_keeping(extrinsics, *header.number()); + let try_apply_extrinsic = |uxt: Block::Extrinsic| -> ApplyExtrinsicResult { + sp_io::init_tracing(); + let encoded = uxt.encode(); + let encoded_len = encoded.len(); + + // skip signature verification. + let xt = if signature_check { + uxt.check(&Default::default()) + } else { + uxt.unchecked_into_checked_i_know_what_i_am_doing(&Default::default()) + }?; + >::note_extrinsic(encoded); + + let dispatch_info = xt.get_dispatch_info(); + let r = Applyable::apply::(xt, &dispatch_info, encoded_len)?; - // run the try-state checks of all pallets. - >::try_state( + >::note_applied_extrinsic(&r, dispatch_info); + + Ok(r.map(|_| ()).map_err(|e| e.error)) + }; + + for e in extrinsics { + if let Err(err) = try_apply_extrinsic(e.clone()) { + frame_support::log::error!( + target: "runtime::executive", "executing transaction {:?} failed due to {:?}. Aborting the rest of the block execution.", + e, + err, + ); + break + } + } + + // post-extrinsics book-keeping + >::note_finished_extrinsics(); + Self::idle_and_finalize_hook(*header.number()); + + // run the try-state checks of all pallets, ensuring they don't alter any state. + let _guard = frame_support::StorageNoopGuard::default(); + >::try_state( *header.number(), select, ) @@ -255,6 +299,7 @@ where frame_support::log::error!(target: "runtime::executive", "failure: {:?}", e); e })?; + drop(_guard); // do some of the checks that would normally happen in `final_checks`, but perhaps skip // the state root check. @@ -266,7 +311,7 @@ where assert!(header_item == computed_item, "Digest item must match that calculated."); } - if try_state_root { + if state_root_check { let storage_root = new_header.state_root(); header.state_root().check_equal(storage_root); assert!( @@ -286,9 +331,30 @@ where /// Execute all `OnRuntimeUpgrade` of this runtime, including the pre and post migration checks. /// - /// This should only be used for testing. - pub fn try_runtime_upgrade() -> Result { - let weight = Self::execute_on_runtime_upgrade(); + /// Runs the try-state code both before and after the migration function if `checks` is set to + /// `true`. Also, if set to `true`, it runs the `pre_upgrade` and `post_upgrade` hooks. + pub fn try_runtime_upgrade(checks: bool) -> Result { + if checks { + let _guard = frame_support::StorageNoopGuard::default(); + >::try_state( + frame_system::Pallet::::block_number(), + frame_try_runtime::TryStateSelect::All, + )?; + } + + let weight = + <(COnRuntimeUpgrade, AllPalletsWithSystem) as OnRuntimeUpgrade>::try_on_runtime_upgrade( + checks, + )?; + + if checks { + let _guard = frame_support::StorageNoopGuard::default(); + >::try_state( + frame_system::Pallet::::block_number(), + frame_try_runtime::TryStateSelect::All, + )?; + } + Ok(weight) } } @@ -314,7 +380,7 @@ where UnsignedValidator: ValidateUnsigned>, { /// Execute all `OnRuntimeUpgrade` of this runtime, and return the aggregate weight. - pub fn execute_on_runtime_upgrade() -> frame_support::weights::Weight { + pub fn execute_on_runtime_upgrade() -> Weight { <(COnRuntimeUpgrade, AllPalletsWithSystem) as OnRuntimeUpgrade>::on_runtime_upgrade() } diff --git a/frame/staking/Cargo.toml b/frame/staking/Cargo.toml index a7fca045cc4ba..f6b3b95d0beb9 100644 --- a/frame/staking/Cargo.toml +++ b/frame/staking/Cargo.toml @@ -62,7 +62,6 @@ std = [ "sp-runtime/std", "sp-staking/std", "pallet-session/std", - "pallet-bags-list/std", "frame-system/std", "pallet-authorship/std", "sp-application-crypto/std", diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 830b33ceb69a2..d3b9b6a2b1e83 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -1636,9 +1636,9 @@ impl Pallet { ensure!( T::VoterList::iter() .all(|x| >::contains_key(&x) || >::contains_key(&x)), - "VoterList contains non-nominators" + "VoterList contains non-staker" ); - T::VoterList::try_state()?; + Self::check_nominators()?; Self::check_exposures()?; Self::check_ledgers()?; @@ -1651,7 +1651,10 @@ impl Pallet { Nominators::::count() + Validators::::count(), "wrong external count" ); - + ensure!( + ::TargetList::count() == Validators::::count(), + "wrong external count" + ); ensure!( ValidatorCount::::get() <= ::MaxWinners::get(), @@ -1692,7 +1695,7 @@ impl Pallet { >::iter() .filter_map( |(nominator, nomination)| { - if nomination.submitted_in > era { + if nomination.submitted_in < era { Some(nominator) } else { None diff --git a/frame/state-trie-migration/src/lib.rs b/frame/state-trie-migration/src/lib.rs index 823ea08a0b573..23f73bb56b173 100644 --- a/frame/state-trie-migration/src/lib.rs +++ b/frame/state-trie-migration/src/lib.rs @@ -1619,7 +1619,10 @@ 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, Zero}; + use sp_runtime::{ + traits::{Block as BlockT, HashFor, Header as _, One, Zero}, + DeserializeOwned, + }; use thousands::Separable; #[allow(dead_code)] @@ -1648,12 +1651,12 @@ pub(crate) mod remote_tests { pub(crate) async fn run_with_limits(limits: MigrationLimits, mode: Mode) where Runtime: crate::Config, - Block: BlockT, + Block: BlockT + DeserializeOwned, Block::Header: serde::de::DeserializeOwned, { let mut ext = remote_externalities::Builder::::new() .mode(mode) - .state_version(sp_core::storage::StateVersion::V0) + .overwrite_state_version(sp_core::storage::StateVersion::V0) .build() .await .unwrap(); diff --git a/frame/support/procedural/src/pallet/expand/hooks.rs b/frame/support/procedural/src/pallet/expand/hooks.rs index d8d009cf3c940..0aa7c1e7aaf06 100644 --- a/frame/support/procedural/src/pallet/expand/hooks.rs +++ b/frame/support/procedural/src/pallet/expand/hooks.rs @@ -50,7 +50,7 @@ pub fn expand_hooks(def: &mut Def) -> proc_macro2::TokenStream { } else { // default. quote::quote! { - #frame_support::log::info!( + #frame_support::log::debug!( target: #frame_support::LOG_TARGET, "✅ no migration for {}", pallet_name, diff --git a/frame/support/src/dispatch.rs b/frame/support/src/dispatch.rs index 1696e9a63915e..93cf08c131641 100644 --- a/frame/support/src/dispatch.rs +++ b/frame/support/src/dispatch.rs @@ -2188,7 +2188,7 @@ macro_rules! decl_module { $system::Config >::PalletInfo as $crate::traits::PalletInfo>::name::().unwrap_or(""); - $crate::log::info!( + $crate::log::debug!( target: $crate::LOG_TARGET, "✅ no migration for {}", pallet_name, diff --git a/frame/support/src/traits/hooks.rs b/frame/support/src/traits/hooks.rs index 3415682c0b382..3f7db1fa046bd 100644 --- a/frame/support/src/traits/hooks.rs +++ b/frame/support/src/traits/hooks.rs @@ -22,9 +22,6 @@ use impl_trait_for_tuples::impl_for_tuples; use sp_runtime::traits::AtLeast32BitUnsigned; use sp_std::prelude::*; -#[cfg(all(feature = "try-runtime", test))] -use codec::{Decode, Encode}; - /// The block initialization trait. /// /// Implementing this lets you express what should happen for your pallet when the block is @@ -136,6 +133,29 @@ pub trait OnRuntimeUpgrade { Weight::zero() } + /// Same as `on_runtime_upgrade`, but perform the optional `pre_upgrade` and `post_upgrade` as + /// well. + #[cfg(feature = "try-runtime")] + fn try_on_runtime_upgrade(checks: bool) -> Result { + let maybe_state = if checks { + let _guard = frame_support::StorageNoopGuard::default(); + let state = Self::pre_upgrade()?; + Some(state) + } else { + None + }; + + let weight = Self::on_runtime_upgrade(); + + if let Some(state) = maybe_state { + let _guard = frame_support::StorageNoopGuard::default(); + // we want to panic if any checks fail right here right now. + Self::post_upgrade(state)? + } + + Ok(weight) + } + /// Execute some pre-checks prior to a runtime upgrade. /// /// Return a `Vec` that can contain arbitrary encoded data (usually some pre-upgrade state), @@ -143,6 +163,9 @@ pub trait OnRuntimeUpgrade { /// 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. + /// + /// This hook must not write to any state, as it would make the main `on_runtime_upgrade` path + /// inaccurate. #[cfg(feature = "try-runtime")] fn pre_upgrade() -> Result, &'static str> { Ok(Vec::new()) @@ -155,6 +178,9 @@ pub trait OnRuntimeUpgrade { /// 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. + /// + /// This hook must not write to any state, as it would make the main `on_runtime_upgrade` path + /// inaccurate. #[cfg(feature = "try-runtime")] fn post_upgrade(_state: Vec) -> Result<(), &'static str> { Ok(()) @@ -165,7 +191,6 @@ 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()); )* ); @@ -176,40 +201,10 @@ impl OnRuntimeUpgrade for Tuple { /// 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; - + fn try_on_runtime_upgrade(checks: bool) -> Result { 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> { - Ok(Vec::new()) - } - - #[cfg(feature = "try-runtime")] - /// noop - fn post_upgrade(_state: Vec) -> Result<(), &'static str> { - Ok(()) + for_tuples!( #( weight = weight.saturating_add(Tuple::try_on_runtime_upgrade(checks)?); )* ); + Ok(weight) } } @@ -274,6 +269,8 @@ pub trait Hooks { /// /// 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. + /// + /// This hook should not alter any storage. #[cfg(feature = "try-runtime")] fn try_state(_n: BlockNumber) -> Result<(), &'static str> { Ok(()) @@ -440,110 +437,4 @@ mod tests { ON_IDLE_INVOCATION_ORDER.clear(); } } - - #[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(()) - } - } - - 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); - }); - } } diff --git a/frame/support/src/traits/try_runtime.rs b/frame/support/src/traits/try_runtime.rs index 640bb566a65af..f741ca56a56fc 100644 --- a/frame/support/src/traits/try_runtime.rs +++ b/frame/support/src/traits/try_runtime.rs @@ -85,6 +85,8 @@ impl sp_std::str::FromStr for Select { /// /// Usually, these checks should check all of the invariants that are expected to be held on all of /// the storage items of your pallet. +/// +/// This hook should not alter any storage. pub trait TryState { /// Execute the state checks. fn try_state(_: BlockNumber, _: Select) -> Result<(), &'static str>; 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 999d8585c221a..a3af9897be5c7 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 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` @@ -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 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 e2870ffb9e86f..9e87f87825b2a 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 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` @@ -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 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/try-runtime/src/lib.rs b/frame/try-runtime/src/lib.rs index ed1247bd8e6f2..99c68d4dc65b8 100644 --- a/frame/try-runtime/src/lib.rs +++ b/frame/try-runtime/src/lib.rs @@ -33,12 +33,21 @@ 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() -> (Weight, Weight); + /// + /// If `checks` is `true`, `pre_migrate` and `post_migrate` of each migration and + /// `try_state` of all pallets will be executed. Else, no. If checks are executed, the PoV + /// tracking is likely inaccurate. + fn on_runtime_upgrade(checks: bool) -> (Weight, Weight); - /// Execute the given block, but don't check that its state root matches that of yours. + /// Execute the given block, but optionally disable state-root and signature checks. /// - /// 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(block: Block, state_root_check: bool, try_state: TryStateSelect) -> Weight; + /// Optionally, a number of `try_state` hooks can also be executed after the block + /// execution. + fn execute_block( + block: Block, + state_root_check: bool, + signature_check: bool, + try_state: TryStateSelect, + ) -> Weight; } } diff --git a/primitives/runtime/Cargo.toml b/primitives/runtime/Cargo.toml index 8ea6ed3eb3b19..4202110cd60c2 100644 --- a/primitives/runtime/Cargo.toml +++ b/primitives/runtime/Cargo.toml @@ -41,6 +41,7 @@ substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/ru [features] runtime-benchmarks = [] +try-runtime = [] default = ["std"] std = [ "codec/std", diff --git a/primitives/runtime/src/generic/unchecked_extrinsic.rs b/primitives/runtime/src/generic/unchecked_extrinsic.rs index 5d378410e4756..bab4411167a7f 100644 --- a/primitives/runtime/src/generic/unchecked_extrinsic.rs +++ b/primitives/runtime/src/generic/unchecked_extrinsic.rs @@ -149,6 +149,22 @@ where None => CheckedExtrinsic { signed: None, function: self.function }, }) } + + #[cfg(feature = "try-runtime")] + fn unchecked_into_checked_i_know_what_i_am_doing( + self, + lookup: &Lookup, + ) -> Result { + Ok(match self.signature { + Some((signed, _, extra)) => { + let signed = lookup.lookup(signed)?; + let raw_payload = SignedPayload::new(self.function, extra)?; + let (function, extra, _) = raw_payload.deconstruct(); + CheckedExtrinsic { signed: Some((signed, extra)), function } + }, + None => CheckedExtrinsic { signed: None, function: self.function }, + }) + } } impl ExtrinsicMetadata diff --git a/primitives/runtime/src/testing.rs b/primitives/runtime/src/testing.rs index 0cd78ba6267dd..81762b3fc4f9f 100644 --- a/primitives/runtime/src/testing.rs +++ b/primitives/runtime/src/testing.rs @@ -326,6 +326,14 @@ impl Checkable for TestXt Result { Ok(self) } + + #[cfg(feature = "try-runtime")] + fn unchecked_into_checked_i_know_what_i_am_doing( + self, + _: &Context, + ) -> Result { + unreachable!() + } } impl traits::Extrinsic for TestXt { diff --git a/primitives/runtime/src/traits.rs b/primitives/runtime/src/traits.rs index c69f8616b4be5..375475141b818 100644 --- a/primitives/runtime/src/traits.rs +++ b/primitives/runtime/src/traits.rs @@ -990,6 +990,20 @@ pub trait Checkable: Sized { /// Check self, given an instance of Context. fn check(self, c: &Context) -> Result; + + /// Blindly check self. + /// + /// ## WARNING + /// + /// DO NOT USE IN PRODUCTION. This is only meant to be used in testing environments. A runtime + /// compiled with `try-runtime` should never be in production. Moreover, the name of this + /// function is deliberately chosen to prevent developers from ever calling it in consensus + /// code-paths. + #[cfg(feature = "try-runtime")] + fn unchecked_into_checked_i_know_what_i_am_doing( + self, + c: &Context, + ) -> Result; } /// A "checkable" piece of information, used by the standard Substrate Executive in order to @@ -1011,6 +1025,14 @@ impl Checkable for T { fn check(self, _c: &Context) -> Result { BlindCheckable::check(self) } + + #[cfg(feature = "try-runtime")] + fn unchecked_into_checked_i_know_what_i_am_doing( + self, + _: &Context, + ) -> Result { + unreachable!(); + } } /// A lazy call (module function and argument values) that can be executed via its `dispatch` diff --git a/primitives/storage/src/lib.rs b/primitives/storage/src/lib.rs index 79c1012196bde..237787710a7e7 100644 --- a/primitives/storage/src/lib.rs +++ b/primitives/storage/src/lib.rs @@ -407,6 +407,7 @@ impl ChildTrieParentKeyId { /// 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)] +#[cfg_attr(feature = "std", derive(Encode, Decode))] pub enum StateVersion { /// Old state version, no value nodes. V0 = 0, diff --git a/utils/frame/remote-externalities/Cargo.toml b/utils/frame/remote-externalities/Cargo.toml index 4cb847867f374..ad8230fe29dcf 100644 --- a/utils/frame/remote-externalities/Cargo.toml +++ b/utils/frame/remote-externalities/Cargo.toml @@ -22,12 +22,14 @@ 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" } +tokio = { version = "1.22.0", features = ["macros", "rt-multi-thread"] } substrate-rpc-client = { path = "../rpc/client" } +futures = "0.3" [dev-dependencies] -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" } +tracing-subscriber = { version = "0.3.16", features = ["env-filter"] } [features] remote-test = ["frame-support"] diff --git a/utils/frame/remote-externalities/src/lib.rs b/utils/frame/remote-externalities/src/lib.rs index db062e246ceef..fb63b4275172d 100644 --- a/utils/frame/remote-externalities/src/lib.rs +++ b/utils/frame/remote-externalities/src/lib.rs @@ -21,7 +21,7 @@ //! based chain, or a local state snapshot file. use codec::{Decode, Encode}; - +use futures::{channel::mpsc, stream::StreamExt}; use log::*; use serde::de::DeserializeOwned; use sp_core::{ @@ -36,8 +36,11 @@ pub use sp_io::TestExternalities; use sp_runtime::{traits::Block as BlockT, StateVersion}; use std::{ fs, + num::NonZeroUsize, + ops::{Deref, DerefMut}, path::{Path, PathBuf}, sync::Arc, + thread, }; use substrate_rpc_client::{ rpc_params, ws_client, BatchRequestBuilder, ChainApi, ClientT, StateApi, WsClient, @@ -48,18 +51,49 @@ type TopKeyValues = Vec; 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 = 1000; +const DEFAULT_WS_ENDPOINT: &str = "wss://rpc.polkadot.io:443"; +const DEFAULT_VALUE_DOWNLOAD_BATCH: usize = 4096; +// NOTE: increasing this value does not seem to impact speed all that much. +const DEFAULT_KEY_DOWNLOAD_PAGE: u32 = 1000; +/// The snapshot that we store on disk. +#[derive(Decode, Encode)] +struct Snapshot { + state_version: StateVersion, + block_hash: B::Hash, + top: TopKeyValues, + child: ChildKeyValues, +} + +/// An externalities that acts exactly the same as [`sp_io::TestExternalities`] but has a few extra +/// bits and pieces to it, and can be loaded remotely. +pub struct RemoteExternalities { + /// The inner externalities. + pub inner_ext: TestExternalities, + /// The block hash it which we created this externality env. + pub block_hash: B::Hash, +} + +impl Deref for RemoteExternalities { + type Target = TestExternalities; + fn deref(&self) -> &Self::Target { + &self.inner_ext + } +} + +impl DerefMut for RemoteExternalities { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.inner_ext + } +} /// The execution mode. #[derive(Clone)] pub enum Mode { - /// Online. Potentially writes to a cache file. + /// Online. Potentially writes to a snapshot 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. + /// Prefer using a snapshot file if it exists, else use a remote server. OfflineOrElseOnline(OfflineConfig, OnlineConfig), } @@ -95,6 +129,13 @@ impl Transport { } } + fn as_client_cloned(&self) -> Option> { + match self { + Self::RemoteClient(client) => Some(client.clone()), + _ => 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 { @@ -134,38 +175,56 @@ 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 pallets to scrape. If empty, entire chain state will be scraped. + /// The pallets to scrape. These values are hashed and added to `hashed_prefix`. 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, + pub child_trie: bool, + /// Storage entry key prefixes to be injected into the externalities. The *hashed* prefix must + /// be given. + pub hashed_prefixes: Vec>, + /// Storage entry keys to be injected into the externalities. The *hashed* key must be given. + pub hashed_keys: Vec>, } impl OnlineConfig { - /// Return rpc (ws) client. + /// Return rpc (ws) client reference. fn rpc_client(&self) -> &WsClient { self.transport .as_client() .expect("ws client must have been initialized by now; qed.") } + + /// Return a cloned rpc (ws) client, suitable for being moved to threads. + fn rpc_client_cloned(&self) -> Arc { + self.transport + .as_client_cloned() + .expect("ws client must have been initialized by now; qed.") + } + + fn at_expected(&self) -> B::Hash { + self.at.expect("block at must be initialized; qed") + } } impl Default for OnlineConfig { fn default() -> Self { Self { - transport: Transport::Uri(DEFAULT_TARGET.to_owned()), + transport: Transport::from(DEFAULT_WS_ENDPOINT.to_owned()), + child_trie: true, at: None, state_snapshot: None, - pallets: vec![], - scrape_children: true, + pallets: Default::default(), + hashed_keys: Default::default(), + hashed_prefixes: Default::default(), } } } impl From for OnlineConfig { - fn from(s: String) -> Self { - Self { transport: s.into(), ..Default::default() } + fn from(t: String) -> Self { + Self { transport: t.into(), ..Default::default() } } } @@ -196,20 +255,18 @@ impl Default for SnapshotConfig { /// Builder for remote-externalities. pub struct Builder { - /// Custom key-pairs to be injected into the externalities. The *hashed* keys and values must - /// be given. + /// Custom key-pairs to be injected into the final 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. + /// Connectivity mode, online or offline. mode: Mode, - /// The state version being used. - state_version: StateVersion, + /// If provided, overwrite the state version with this. Otherwise, the state_version of the + /// remote node is used. All cache files also store their state version. + /// + /// Overwrite only with care. + overwrite_state_version: Option, } // NOTE: ideally we would use `DefaultNoBound` here, but not worth bringing in frame-support for @@ -219,10 +276,8 @@ impl Default for Builder { Self { mode: Default::default(), hashed_key_values: Default::default(), - hashed_prefixes: Default::default(), - hashed_keys: Default::default(), hashed_blacklist: Default::default(), - state_version: StateVersion::V1, + overwrite_state_version: None, } } } @@ -252,20 +307,22 @@ where B::Hash: DeserializeOwned, B::Header: DeserializeOwned, { + /// Get the number of threads to use. + fn threads() -> NonZeroUsize { + thread::available_parallelism() + .unwrap_or(NonZeroUsize::new(4usize).expect("4 is non-zero; qed")) + } + async fn rpc_get_storage( &self, key: StorageKey, maybe_at: Option, - ) -> Result { + ) -> Result, &'static str> { trace!(target: LOG_TARGET, "rpc: get_storage"); - 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.") - }, - } + self.as_online().rpc_client().storage(key, maybe_at).await.map_err(|e| { + error!(target: LOG_TARGET, "Error = {:?}", e); + "rpc get_storage failed." + }) } /// Get the latest finalized head. @@ -293,7 +350,12 @@ where let page = self .as_online() .rpc_client() - .storage_keys_paged(Some(prefix.clone()), PAGE, last_key.clone(), Some(at)) + .storage_keys_paged( + Some(prefix.clone()), + DEFAULT_KEY_DOWNLOAD_PAGE, + last_key.clone(), + Some(at), + ) .await .map_err(|e| { error!(target: LOG_TARGET, "Error = {:?}", e); @@ -303,7 +365,7 @@ where all_keys.extend(page); - if page_len < PAGE as usize { + if page_len < DEFAULT_KEY_DOWNLOAD_PAGE as usize { log::debug!(target: LOG_TARGET, "last page received: {}", page_len); break all_keys } else { @@ -322,7 +384,7 @@ where Ok(keys) } - /// Synonym of `rpc_get_pairs_unsafe` that uses paged queries to first get the keys, and then + /// Synonym of `getPairs` that uses paged queries to first get the keys, and then /// map them to values one by one. /// /// This can work with public nodes. But, expect it to be darn slow. @@ -330,79 +392,169 @@ where &self, prefix: StorageKey, at: B::Hash, + pending_ext: &mut TestExternalities, ) -> 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 keys = self.rpc_get_keys_paged(prefix.clone(), at).await?; + if keys.is_empty() { + return Ok(Default::default()) + } - let mut key_values: Vec = vec![]; - let mut batch_success = true; + let client = self.as_online().rpc_client_cloned(); + let threads = Self::threads().get(); + let thread_chunk_size = (keys.len() + threads - 1) / threads; - let client = self.as_online().rpc_client(); - for chunk_keys in keys.chunks(BATCH_SIZE) { - let mut batch = BatchRequestBuilder::new(); + log::info!( + target: LOG_TARGET, + "Querying a total of {} keys from prefix {:?}, splitting among {} threads, {} keys per thread", + keys.len(), + HexDisplay::from(&prefix), + threads, + thread_chunk_size, + ); - for key in chunk_keys.iter() { - batch - .insert("state_getStorage", rpc_params![key, at]) - .map_err(|_| "Invalid batch params")?; - } + let mut handles = Vec::new(); + let keys_chunked: Vec> = + keys.chunks(thread_chunk_size).map(|s| s.into()).collect::>(); + + enum Message { + /// This thread completed the assigned work. + Terminated, + /// The thread produced the following batch response. + Batch(Vec<(Vec, Vec)>), + /// A request from the batch failed. + BatchFailed(String), + } - 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." - })?; + let (tx, mut rx) = mpsc::unbounded::(); + + for thread_keys in keys_chunked { + let thread_client = client.clone(); + let thread_sender = tx.clone(); + let handle = std::thread::spawn(move || { + let rt = tokio::runtime::Runtime::new().unwrap(); + let mut thread_key_values = Vec::with_capacity(thread_keys.len()); + + for chunk_keys in thread_keys.chunks(DEFAULT_VALUE_DOWNLOAD_BATCH) { + let mut batch = BatchRequestBuilder::new(); + + for key in chunk_keys.iter() { + batch + .insert("state_getStorage", rpc_params![key, at]) + .map_err(|_| "Invalid batch params") + .unwrap(); + } + + let batch_response = rt + .block_on(thread_client.batch_request::>(batch)) + .map_err(|e| { + log::error!( + target: LOG_TARGET, + "failed to execute batch: {:?}. Error: {:?}", + chunk_keys.iter().map(HexDisplay::from).collect::>(), + e + ); + "batch failed." + }) + .unwrap(); + + // Check if we got responses for all submitted requests. + assert_eq!(chunk_keys.len(), batch_response.len()); + + let mut batch_kv = Vec::with_capacity(chunk_keys.len()); + for (key, maybe_value) in chunk_keys.into_iter().zip(batch_response) { + match maybe_value { + Ok(Some(data)) => { + thread_key_values.push((key.clone(), data.clone())); + batch_kv.push((key.clone().0, data.0)); + }, + Ok(None) => { + log::warn!( + target: LOG_TARGET, + "key {:?} had none corresponding value.", + &key + ); + let data = StorageData(vec![]); + thread_key_values.push((key.clone(), data.clone())); + batch_kv.push((key.clone().0, data.0)); + }, + Err(e) => { + let reason = format!("key {:?} failed: {:?}", &key, e); + log::error!(target: LOG_TARGET, "Reason: {}", reason); + // Signal failures to the main thread, stop aggregating (key, value) + // pairs and return immediately an error. + thread_sender.unbounded_send(Message::BatchFailed(reason)).unwrap(); + return Default::default() + }, + }; + + if thread_key_values.len() % (thread_keys.len() / 10).max(1) == 0 { + let ratio: f64 = + thread_key_values.len() as f64 / thread_keys.len() as f64; + log::debug!( + target: LOG_TARGET, + "[thread = {:?}] progress = {:.2} [{} / {}]", + std::thread::current().id(), + ratio, + thread_key_values.len(), + thread_keys.len(), + ); + } + } + + // Send this batch to the main thread to start inserting. + thread_sender.unbounded_send(Message::Batch(batch_kv)).unwrap(); + } - assert_eq!(chunk_keys.len(), batch_response.len()); + thread_sender.unbounded_send(Message::Terminated).unwrap(); + thread_key_values + }); - 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; - }, - }; + handles.push(handle); + } - if key_values.len() % (10 * BATCH_SIZE) == 0 { - let ratio: f64 = key_values.len() as f64 / keys_count as f64; - log::debug!( - target: LOG_TARGET, - "progress = {:.2} [{} / {}]", - ratio, - key_values.len(), - keys_count, - ); - } + // first, wait until all threads send a `Terminated` message, in the meantime populate + // `pending_ext`. + let mut terminated = 0usize; + let mut batch_failed = false; + loop { + match rx.next().await.unwrap() { + Message::Batch(kv) => { + for (k, v) in kv { + // skip writing the child root data. + if is_default_child_storage_key(k.as_ref()) { + continue + } + pending_ext.insert(k, v); + } + }, + Message::BatchFailed(error) => { + log::error!(target: LOG_TARGET, "Batch processing failed: {:?}", error); + batch_failed = true; + break + }, + Message::Terminated => { + terminated += 1; + if terminated == handles.len() { + break + } + }, } } - if batch_success { - Ok(key_values) - } else { - Err("batch failed.") + // Ensure all threads finished execution before returning. + let keys_and_values = + handles.into_iter().flat_map(|h| h.join().unwrap()).collect::>(); + + if batch_failed { + return Err("Batch failed.") } + + Ok(keys_and_values) } /// Get the values corresponding to `child_keys` at the given `prefixed_top_key`. pub(crate) async fn rpc_child_get_storage_paged( - &self, + client: &WsClient, prefixed_top_key: &StorageKey, child_keys: Vec, at: B::Hash, @@ -410,7 +562,7 @@ where let mut child_kv_inner = vec![]; let mut batch_success = true; - for batch_child_key in child_keys.chunks(BATCH_SIZE) { + for batch_child_key in child_keys.chunks(DEFAULT_VALUE_DOWNLOAD_BATCH) { let mut batch_request = BatchRequestBuilder::new(); for key in batch_child_key { @@ -426,12 +578,8 @@ where .map_err(|_| "Invalid batch params")?; } - let batch_response = self - .as_online() - .rpc_client() - .batch_request::>(batch_request) - .await - .map_err(|e| { + let batch_response = + client.batch_request::>(batch_request).await.map_err(|e| { log::error!( target: LOG_TARGET, "failed to execute batch: {:?}. Error: {:?}", @@ -472,7 +620,7 @@ where } pub(crate) async fn rpc_child_get_keys( - &self, + client: &WsClient, prefixed_top_key: &StorageKey, child_prefix: StorageKey, at: B::Hash, @@ -480,7 +628,7 @@ where // 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(), + client, PrefixedStorageKey::new(prefixed_top_key.as_ref().to_vec()), child_prefix, Some(at), @@ -493,7 +641,8 @@ where debug!( target: LOG_TARGET, - "scraped {} child-keys of the child-bearing top key: {}", + "[thread = {:?}] scraped {} child-keys of the child-bearing top key: {}", + std::thread::current().id(), child_keys.len(), HexDisplay::from(prefixed_top_key) ); @@ -502,214 +651,341 @@ where } } -// 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(); - 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(()) - } - - /// 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(|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( + /// `top_kv` need not be only child-bearing top keys. It should be all of the top keys that are + /// included thus far. + /// + /// This function concurrently populates `pending_ext`. the return value is only for writing to + /// cache, we can also optimize further. + async fn load_child_remote( &self, top_kv: &[KeyValue], + pending_ext: &mut TestExternalities, ) -> 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)) + .into_iter() + .filter_map(|(k, _)| is_default_child_storage_key(k.as_ref()).then(|| k.clone())) .collect::>(); + if child_roots.is_empty() { + return Ok(Default::default()) + } + + // div-ceil simulation. + let threads = Self::threads().get(); + let child_roots_per_thread = (child_roots.len() + threads - 1) / threads; + info!( target: LOG_TARGET, - "👩‍👦 scraping child-tree data from {} top keys", - child_roots.len() + "👩‍👦 scraping child-tree data from {} top keys, split among {} threads, {} top keys per thread", + child_roots.len(), + threads, + child_roots_per_thread, ); - 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") - }, - }; + // NOTE: the threading done here is the simpler, yet slightly un-elegant because we are + // splitting child root among threads, and it is very common for these root to have vastly + // different child tries underneath them, causing some threads to finish way faster than + // others. Certainly still better than single thread though. + let mut handles = vec![]; + let client = self.as_online().rpc_client_cloned(); + let at = self.as_online().at_expected(); + + enum Message { + Terminated, + Batch((ChildInfo, Vec<(Vec, Vec)>)), + } + let (tx, mut rx) = mpsc::unbounded::(); + + for thread_child_roots in child_roots + .chunks(child_roots_per_thread) + .map(|x| x.into()) + .collect::>>() + { + let thread_client = client.clone(); + let thread_sender = tx.clone(); + let handle = thread::spawn(move || { + let rt = tokio::runtime::Runtime::new().unwrap(); + let mut thread_child_kv = vec![]; + for prefixed_top_key in thread_child_roots { + let child_keys = rt.block_on(Self::rpc_child_get_keys( + &thread_client, + &prefixed_top_key, + StorageKey(vec![]), + at, + ))?; + let child_kv_inner = rt.block_on(Self::rpc_child_get_storage_paged( + &thread_client, + &prefixed_top_key, + child_keys, + at, + ))?; + + 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") + }, + }; + + thread_sender + .unbounded_send(Message::Batch(( + ChildInfo::new_default(un_prefixed), + child_kv_inner + .iter() + .cloned() + .map(|(k, v)| (k.0, v.0)) + .collect::>(), + ))) + .unwrap(); + thread_child_kv.push((ChildInfo::new_default(un_prefixed), child_kv_inner)); + } + + thread_sender.unbounded_send(Message::Terminated).unwrap(); + Ok(thread_child_kv) + }); + handles.push(handle); + } - child_kv.push((ChildInfo::new_default(un_prefixed), child_kv_inner)); + // first, wait until all threads send a `Terminated` message, in the meantime populate + // `pending_ext`. + let mut terminated = 0usize; + loop { + match rx.next().await.unwrap() { + Message::Batch((info, kvs)) => + for (k, v) in kvs { + pending_ext.insert_child(info.clone(), k, v); + }, + Message::Terminated => { + terminated += 1; + if terminated == handles.len() { + break + } + }, + } } + let child_kv = handles + .into_iter() + .flat_map(|h| h.join().unwrap()) + .flatten() + .collect::>(); Ok(child_kv) } /// Build `Self` from a network node denoted by `uri`. - async fn load_top_remote(&self) -> Result { + /// + /// This function concurrently populates `pending_ext`. the return value is only for writing to + /// cache, we can also optimize further. + async fn load_top_remote( + &self, + pending_ext: &mut TestExternalities, + ) -> Result { let config = self.as_online(); let at = self .as_online() .at .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 { - let mut filtered_kv = vec![]; - 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: {}).", - p, - pallet_kv.len(), - HexDisplay::from(&hashed_prefix), - ); - filtered_kv.extend(pallet_kv); - } - filtered_kv - } else { - log::info!(target: LOG_TARGET, "downloading data for all pallets."); - self.rpc_get_pairs_paged(StorageKey(vec![]), at).await? - }; + log::info!(target: LOG_TARGET, "scraping key-pairs from remote at block height {:?}", at); - for prefix in &self.hashed_prefixes { + let mut keys_and_values = Vec::new(); + for prefix in &config.hashed_prefixes { + let now = std::time::Instant::now(); + let additional_key_values = + self.rpc_get_pairs_paged(StorageKey(prefix.to_vec()), at, pending_ext).await?; + let elapsed = now.elapsed(); log::info!( target: LOG_TARGET, - "adding data for hashed prefix: {:?}", - HexDisplay::from(prefix) + "adding data for hashed prefix: {:?}, took {:?}s", + HexDisplay::from(prefix), + elapsed.as_secs() ); - let additional_key_values = - self.rpc_get_pairs_paged(StorageKey(prefix.to_vec()), at).await?; keys_and_values.extend(additional_key_values); } - for key in &self.hashed_keys { + for key in &config.hashed_keys { let key = StorageKey(key.to_vec()); 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)); + match self.rpc_get_storage(key.clone(), Some(at)).await? { + Some(value) => { + pending_ext.insert(key.clone().0, value.clone().0); + keys_and_values.push((key, value)); + }, + None => { + log::warn!( + target: LOG_TARGET, + "no data found for hashed key: {:?}", + HexDisplay::from(&key) + ); + }, + } } Ok(keys_and_values) } - pub(crate) async fn init_remote_client(&mut self) -> Result<(), &'static str> { + /// The entry point of execution, if `mode` is online. + /// + /// initializes the remote client in `transport`, and sets the `at` field, if not specified. + async fn init_remote_client(&mut self) -> Result<(), &'static str> { // First, initialize the 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() { let at = self.rpc_get_head().await?; + log::info!( + target: LOG_TARGET, + "since no at is provided, setting it to latest finalized head, {:?}", + at + ); self.as_online_mut().at = Some(at); } + // Then, a few transformation that we want to perform in the online config: + let online_config = self.as_online_mut(); + online_config + .pallets + .iter() + .for_each(|p| online_config.hashed_prefixes.push(twox_128(p.as_bytes()).to_vec())); + + if online_config.child_trie { + online_config.hashed_prefixes.push(DEFAULT_CHILD_STORAGE_KEY_PREFIX.to_vec()); + } + + // Finally, if by now, we have put any limitations on prefixes that we are interested in, we + // download everything. + if online_config + .hashed_prefixes + .iter() + .filter(|p| *p != DEFAULT_CHILD_STORAGE_KEY_PREFIX) + .count() == 0 + { + log::info!( + target: LOG_TARGET, + "since no prefix is filtered, the data for all pallets will be downloaded" + ); + online_config.hashed_prefixes.push(vec![]); + } + Ok(()) } - 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?; - self.load_top_remote_and_maybe_save().await? - }, + /// Load the data from a remote server. The main code path is calling into `load_top_remote` and + /// `load_child_remote`. + /// + /// Must be called after `init_remote_client`. + async fn load_remote_and_maybe_save(&mut self) -> Result { + let state_version = + StateApi::::runtime_version(self.as_online().rpc_client(), None) + .await + .map_err(|e| { + error!(target: LOG_TARGET, "Error = {:?}", e); + "rpc runtime_version failed." + }) + .map(|v| v.state_version())?; + let mut pending_ext = TestExternalities::new_with_code_and_state( + Default::default(), + Default::default(), + self.overwrite_state_version.unwrap_or(state_version), + ); + let top_kv = self.load_top_remote(&mut pending_ext).await?; + let child_kv = self.load_child_remote(&top_kv, &mut pending_ext).await?; + + if let Some(path) = self.as_online().state_snapshot.clone().map(|c| c.path) { + let snapshot = Snapshot:: { + state_version, + top: top_kv, + child: child_kv, + block_hash: self + .as_online() + .at + .expect("set to `Some` in `init_remote_client`; must be called before; qed"), + }; + let encoded = snapshot.encode(); + log::info!( + target: LOG_TARGET, + "writing snapshot of {} bytes to {:?}", + encoded.len(), + path + ); + std::fs::write(path, encoded).map_err(|_| "fs::write failed")?; + } + + Ok(pending_ext) + } + + fn load_snapshot(&mut self, path: PathBuf) -> Result, &'static str> { + info!(target: LOG_TARGET, "loading data from snapshot {:?}", path); + let bytes = fs::read(path).map_err(|_| "fs::read failed.")?; + Decode::decode(&mut &*bytes).map_err(|_| "decode failed") + } + + async fn do_load_remote(&mut self) -> Result, &'static str> { + self.init_remote_client().await?; + let block_hash = self.as_online().at_expected(); + let inner_ext = self.load_remote_and_maybe_save().await?; + Ok(RemoteExternalities { block_hash, inner_ext }) + } + + fn do_load_offline( + &mut self, + config: OfflineConfig, + ) -> Result, &'static str> { + let Snapshot { block_hash, top, child, state_version } = + self.load_snapshot(config.state_snapshot.path.clone())?; + + let mut inner_ext = TestExternalities::new_with_code_and_state( + Default::default(), + Default::default(), + self.overwrite_state_version.unwrap_or(state_version), + ); + + info!(target: LOG_TARGET, "injecting a total of {} top keys", top.len()); + for (k, v) in top { + // skip writing the child root data. + if is_default_child_storage_key(k.as_ref()) { + continue + } + inner_ext.insert(k.0, v.0); + } + + info!( + target: LOG_TARGET, + "injecting a total of {} child keys", + child.iter().flat_map(|(_, kv)| kv).count() + ); + + for (info, key_values) in child { + for (k, v) in key_values { + inner_ext.insert_child(info.clone(), k.0, v.0); + } + } + + Ok(RemoteExternalities { inner_ext, block_hash }) + } + + pub(crate) async fn pre_build(mut self) -> Result, &'static str> { + let mut ext = match self.mode.clone() { + Mode::Offline(config) => self.do_load_offline(config)?, + Mode::Online(_) => self.do_load_remote().await?, Mode::OfflineOrElseOnline(offline_config, _) => { - if let Ok(kv) = self.load_top_snapshot(&offline_config.state_snapshot.path) { - kv - } else { - self.init_remote_client().await?; - self.load_top_remote_and_maybe_save().await? + match self.do_load_offline(offline_config) { + Ok(x) => x, + Err(_) => self.do_load_remote().await?, } }, }; @@ -721,7 +997,9 @@ where "extending externalities with {} manually injected key-values", self.hashed_key_values.len() ); - top_kv.extend(self.hashed_key_values.clone()); + for (k, v) in self.hashed_key_values { + ext.insert(k.0, v.0); + } } // exclude manual key values. @@ -731,87 +1009,34 @@ where "excluding externalities from {} keys", self.hashed_blacklist.len() ); - top_kv.retain(|(k, _)| !self.hashed_blacklist.contains(&k.0)) + for k in self.hashed_blacklist { + ext.execute_with(|| sp_io::storage::clear(&k)); + } } - 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)) + Ok(ext) } } // Public methods -impl Builder { +impl Builder +where + B::Hash: DeserializeOwned, + B::Header: DeserializeOwned, +{ /// Create a new builder. pub fn new() -> Self { Default::default() } /// Inject a manual list of key and values to the storage. - pub fn inject_hashed_key_value(mut self, injections: &[KeyValue]) -> Self { + pub fn inject_hashed_key_value(mut self, injections: Vec) -> 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. - /// - /// 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()); - self - } - - /// 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. - /// - /// 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 - /// [`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) - } - - /// 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()); - 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 { @@ -826,64 +1051,20 @@ impl Builder { } /// 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`] - 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); - } + pub fn overwrite_state_version(mut self, version: StateVersion) -> Self { + self.overwrite_state_version = Some(version); 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; - let (top_kv, child_kv) = self.pre_build().await?; - 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 { - // 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().flat_map(|(_, kv)| kv).count() - ); - - for (info, key_values) in child_kv { - for (k, v) in key_values { - ext.insert_child(info.clone(), k.0, v.0); - } - } + pub async fn build(self) -> Result, &'static str> { + let mut ext = self.pre_build().await?; ext.commit_all().unwrap(); + info!( target: LOG_TARGET, - "initialized state externalities with storage root {:?}", - ext.as_backend().root() + "initialized state externalities with storage root {:?} and state_version {:?}", + ext.as_backend().root(), + ext.state_version ); Ok(ext) @@ -892,16 +1073,16 @@ where #[cfg(test)] mod test_prelude { + use tracing_subscriber::EnvFilter; + pub(crate) use super::*; pub(crate) use sp_runtime::testing::{Block as RawBlock, ExtrinsicWrapper, H256 as Hash}; - pub(crate) type Block = RawBlock>; pub(crate) fn init_logger() { - let _ = env_logger::Builder::from_default_env() - .format_module_path(true) - .format_level(true) - .filter_module(LOG_TARGET, log::LevelFilter::Debug) + let _ = tracing_subscriber::fmt() + .with_env_filter(EnvFilter::from_default_env()) + .with_level(true) .try_init(); } } @@ -910,7 +1091,7 @@ mod test_prelude { mod tests { use super::test_prelude::*; - #[tokio::test] + #[tokio::test(flavor = "multi_thread")] async fn can_load_state_snapshot() { init_logger(); Builder::::new() @@ -919,15 +1100,15 @@ mod tests { })) .build() .await - .expect("Can't read state snapshot file") + .unwrap() .execute_with(|| {}); } - #[tokio::test] - async fn can_exclude_from_cache() { + #[tokio::test(flavor = "multi_thread")] + async fn can_exclude_from_snapshot() { init_logger(); - // get the first key from the cache file. + // get the first key from the snapshot file. let some_key = Builder::::new() .mode(Mode::Offline(OfflineConfig { state_snapshot: SnapshotConfig::new("test_data/proxy_test"), @@ -957,19 +1138,88 @@ mod tests { #[cfg(all(test, feature = "remote-test"))] mod remote_tests { use super::test_prelude::*; + use std::os::unix::fs::MetadataExt; + + #[tokio::test(flavor = "multi_thread")] + async fn state_version_is_kept_and_can_be_altered() { + const CACHE: &'static str = "state_version_is_kept_and_can_be_altered"; + init_logger(); + + // first, build a snapshot. + let ext = Builder::::new() + .mode(Mode::Online(OnlineConfig { + pallets: vec!["Proxy".to_owned()], + child_trie: false, + state_snapshot: Some(SnapshotConfig::new(CACHE)), + ..Default::default() + })) + .build() + .await + .unwrap(); + + // now re-create the same snapshot. + let cached_ext = Builder::::new() + .mode(Mode::Offline(OfflineConfig { state_snapshot: SnapshotConfig::new(CACHE) })) + .build() + .await + .unwrap(); + + assert_eq!(ext.state_version, cached_ext.state_version); + + // now overwrite it + let other = match ext.state_version { + StateVersion::V0 => StateVersion::V1, + StateVersion::V1 => StateVersion::V0, + }; + let cached_ext = Builder::::new() + .mode(Mode::Offline(OfflineConfig { state_snapshot: SnapshotConfig::new(CACHE) })) + .overwrite_state_version(other) + .build() + .await + .unwrap(); + + assert_eq!(cached_ext.state_version, other); + } + + #[tokio::test(flavor = "multi_thread")] + async fn snapshot_block_hash_works() { + const CACHE: &'static str = "snapshot_block_hash_works"; + init_logger(); + + // first, build a snapshot. + let ext = Builder::::new() + .mode(Mode::Online(OnlineConfig { + pallets: vec!["Proxy".to_owned()], + child_trie: false, + state_snapshot: Some(SnapshotConfig::new(CACHE)), + ..Default::default() + })) + .build() + .await + .unwrap(); - #[tokio::test] + // now re-create the same snapshot. + let cached_ext = Builder::::new() + .mode(Mode::Offline(OfflineConfig { state_snapshot: SnapshotConfig::new(CACHE) })) + .build() + .await + .unwrap(); + + assert_eq!(ext.block_hash, cached_ext.block_hash); + } + + #[tokio::test(flavor = "multi_thread")] async fn offline_else_online_works() { + const CACHE: &'static str = "offline_else_online_works_data"; init_logger(); - // this shows that in the second run, we use the remote and create a cache. + // this shows that in the second run, we use the remote and create a snapshot. Builder::::new() .mode(Mode::OfflineOrElseOnline( - OfflineConfig { - state_snapshot: SnapshotConfig::new("offline_else_online_works_data"), - }, + OfflineConfig { state_snapshot: SnapshotConfig::new(CACHE) }, OnlineConfig { pallets: vec!["Proxy".to_owned()], - state_snapshot: Some(SnapshotConfig::new("offline_else_online_works_data")), + child_trie: false, + state_snapshot: Some(SnapshotConfig::new(CACHE)), ..Default::default() }, )) @@ -981,12 +1231,8 @@ mod remote_tests { // this shows that in the second run, we are not using the remote Builder::::new() .mode(Mode::OfflineOrElseOnline( - OfflineConfig { - state_snapshot: SnapshotConfig::new("offline_else_online_works_data"), - }, + OfflineConfig { state_snapshot: SnapshotConfig::new(CACHE) }, OnlineConfig { - pallets: vec!["Proxy".to_owned()], - state_snapshot: Some(SnapshotConfig::new("offline_else_online_works_data")), transport: "ws://non-existent:666".to_owned().into(), ..Default::default() }, @@ -1000,51 +1246,20 @@ mod remote_tests { .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" - }) + .filter(|p| p.path().file_name().unwrap_or_default() == CACHE) .collect::>(); - assert!(to_delete.len() > 0); - for d in to_delete { - std::fs::remove_file(d.path()).unwrap(); - } - } - #[tokio::test] - #[ignore = "too slow"] - async fn can_build_one_big_pallet() { - init_logger(); - Builder::::new() - .mode(Mode::Online(OnlineConfig { - pallets: vec!["System".to_owned()], - ..Default::default() - })) - .build() - .await - .unwrap() - .execute_with(|| {}); + assert!(to_delete.len() == 1); + std::fs::remove_file(to_delete[0].path()).unwrap(); } - #[tokio::test] + #[tokio::test(flavor = "multi_thread")] 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 - .unwrap() - .execute_with(|| {}); - - Builder::::new() - .mode(Mode::Online(OnlineConfig { - transport: "wss://rpc.polkadot.io:443".to_owned().into(), - pallets: vec!["Council".to_owned()], + pallets: vec!["Proxy".to_owned()], + child_trie: false, ..Default::default() })) .build() @@ -1053,24 +1268,13 @@ mod remote_tests { .execute_with(|| {}); } - #[tokio::test] + #[tokio::test(flavor = "multi_thread")] async fn can_build_few_pallet() { 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 - .unwrap() - .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()], + child_trie: false, ..Default::default() })) .build() @@ -1079,13 +1283,16 @@ mod remote_tests { .execute_with(|| {}); } - #[tokio::test] - async fn can_create_top_snapshot() { + #[tokio::test(flavor = "multi_thread")] + async fn can_create_snapshot() { + const CACHE: &'static str = "can_create_snapshot"; init_logger(); + Builder::::new() .mode(Mode::Online(OnlineConfig { - state_snapshot: Some(SnapshotConfig::new("can_create_top_snapshot_data")), + state_snapshot: Some(SnapshotConfig::new(CACHE)), pallets: vec!["Proxy".to_owned()], + child_trie: false, ..Default::default() })) .build() @@ -1097,38 +1304,29 @@ mod remote_tests { .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" - }) + .filter(|p| p.path().file_name().unwrap_or_default() == CACHE) .collect::>(); - assert!(to_delete.len() > 0); + let snap: Snapshot = Builder::::new().load_snapshot(CACHE.into()).unwrap(); + assert!(matches!(snap, Snapshot { top, child, .. } if top.len() > 0 && child.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(); - } + assert!(to_delete.len() == 1); + let to_delete = to_delete.first().unwrap(); + assert!(std::fs::metadata(to_delete.path()).unwrap().size() > 1); + std::fs::remove_file(to_delete.path()).unwrap(); } - #[tokio::test] + #[tokio::test(flavor = "multi_thread")] async fn can_create_child_snapshot() { + const CACHE: &'static str = "can_create_child_snapshot"; init_logger(); Builder::::new() .mode(Mode::Online(OnlineConfig { - state_snapshot: Some(SnapshotConfig::new("can_create_child_snapshot_data")), + state_snapshot: Some(SnapshotConfig::new(CACHE)), pallets: vec!["Crowdloan".to_owned()], + child_trie: true, ..Default::default() })) - .inject_default_child_tree_prefix() .build() .await .unwrap() @@ -1138,72 +1336,46 @@ mod remote_tests { .unwrap() .into_iter() .map(|d| d.unwrap()) - .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" - }) + .filter(|p| p.path().file_name().unwrap_or_default() == CACHE) .collect::>(); - assert!(to_delete.len() > 0); + let snap: Snapshot = Builder::::new().load_snapshot(CACHE.into()).unwrap(); + assert!(matches!(snap, Snapshot { top, child, .. } if top.len() > 0 && child.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(); - } + assert!(to_delete.len() == 1); + let to_delete = to_delete.first().unwrap(); + assert!(std::fs::metadata(to_delete.path()).unwrap().size() > 1); + std::fs::remove_file(to_delete.path()).unwrap(); } - #[tokio::test] - async fn can_fetch_all() { + #[tokio::test(flavor = "multi_thread")] + async fn can_build_big_pallet() { + if std::option_env!("TEST_WS").is_none() { + return + } init_logger(); Builder::::new() .mode(Mode::Online(OnlineConfig { - state_snapshot: Some(SnapshotConfig::new("can_fetch_all_data")), + transport: std::option_env!("TEST_WS").unwrap().to_owned().into(), + pallets: vec!["Staking".to_owned()], + child_trie: false, ..Default::default() })) .build() .await .unwrap() .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(); - } } - #[tokio::test] - async fn can_build_child_tree() { + #[tokio::test(flavor = "multi_thread")] + async fn can_fetch_all() { + if std::option_env!("TEST_WS").is_none() { + return + } init_logger(); Builder::::new() .mode(Mode::Online(OnlineConfig { - transport: "wss://rpc.polkadot.io:443".to_owned().into(), - pallets: vec!["Crowdloan".to_owned()], + transport: std::option_env!("TEST_WS").unwrap().to_owned().into(), ..Default::default() })) .build() diff --git a/utils/frame/remote-externalities/test_data/proxy_test b/utils/frame/remote-externalities/test_data/proxy_test new file mode 100644 index 0000000000000000000000000000000000000000..6673bd6765ad8df2a9e74f210d8795acfeb54a30 GIT binary patch literal 70206 zcmcG1Wmwf)^ER;wrMtVkyHk)xx3Ip8tLxtE&(aYO-h4=q;$Od!T0JZ-}ChdG6;SH7=o|Lw>LiF~`c`ij=~ULE^qz z2$pvCM*bazk|R)^PeBx}KUwE-7IF^Ur8lHQ41oyD(zGO5wdiRp)gM0#8TaO@AHHQG zavLuR#fb=nHpb${Tce*I9)*NL97i7rUpspJBc?=r2S0Md(8Y-x!)soyLhzP@ktZXd z2I7DJ);LG(qE_o>TRs!LS-lF5>%aNUP=;|_E2_l6=T9Z)3-!N6Ki`CiUJjd;Gvy-K zcnq;~8y?fHzt)J7=}*ny>Ucvp`m!jnxnYX=f2;rR-@o{lSV4ukT#aj*rJ4AE6P4qc z?o10+v4<8rI%_MG{>4|hc$!)*Y~xozKpa;+lt8Xwjz7aff@pJQ*;jsPr`#C2$~v1f zv?FCRDail*&AQW{(XhKk!j@uC#<6c0_D z%%bpV6e?x?N`7a=!=zRFYk>Q?BhD7%OQatVK>cQDVH9uYqB%Xkzr$NFx2;INAk4FL zn1!mg9jQFc=f&w@c;Krn|Af$cSkCVvuXuc^@F4dlv5|skoHTLyn)e3E{bpk`iX{>D zOn`tj0N$+_+`!6Z%Y#=i~t%iJpdJm*IpUX!Q`+UC6_4y z^R!&{u`!04!PP#ylsf-FTR8wDG01V4dj<%Q##-C%`IXNWreXVo?+a}x^zG+%L#ejq zd5R2kE&FH=Xz(xq^)td4{|GlhmGtZ#rMU<}P1`&fJ*Rwt!l7uHy@*V@#A^ z@!}H=a19WNt!yL+AZePjbIK~U9Q*F|+rPP%Fa83jbxx{E)%pl{janZTdA_V@V`Cfsvt z&!jJ@$RYgg4bresp*_1Mr6C#Ry#l~sqFWb%VZnZYMQsNghawx6cG)u-lN9Z0R;#ECZ0eG_-LDQ{vt{*x~H^Rc&s6;ubKO=oe0p*mN3U?9i zIf^$#%NXK`HG3kLT8>}dZQX1cI34(mGzx%8X_!(!$FP+2*rhf%(qtRQ46DjPpLgv- z4cUcH`$?`pBT`W}KX{pQxBPd2zKV&%fi9sA_mu>kvx{!o9E_Ntv$}L?VbHR)6{6WN zy5nNAgnGCG0p1M;o18$wo=fk#dW&)E3C|jNZZ$(l+?!rYi6EghMKC=8%S^XZbo+>7 zY$~0`SZedGR1(5y80)TW8+P~ACX>VtpS9*Qdfw9t5Mck^{JYr`osiMBO;n9Veq3!) zu&5hUNti%yWK}Yd&IC+K!ye!h0}%1kFuGhO5}MJcUa`%l!eMmF?Wc&VZ|vavFAz^3 z@SJk30s)qQBynC_JR%fSzR9@mXO4DL3_8ZGE$9P;Z8qnndU-Gl8=S4>r|p3N9apJM zyx)f|B$G()GihH(9wb$`Q+SXXM=a?J=(qsBz*;I6n&)wI@8y_t^B$ zHvs`?ak!$+gnIVfIVOFi+vii6>D~(XpWTM^uk15?lwi%kG~g8+^4Ym1mn|&9kJ&D< z9b`hz!FNJ7Bv_BIsW8~djX=-bV-_YtcU~Z1a=Zn^!Ct-!T5i^1*yCJSCeuA<|*zs_{~X~hkYjJ62o z(krTE+LZGDp~ZZFPGlrswBw|XKd%JJmk?-?(Se&}!6!v=uhTtVDFjr&S8AI!k58%D zmz)n-mc7)K$oOpD-hu!H6XD{u`mAO@YcFM$FS^@_sPjPYDjgV)7pVSyzI;u&Utm7v ze)(}M#T3?Y+ci%#$s2*M#^*@FB<1Z%X++{HsMpsnRU7}DuE6z^8J9+@6w5oNRK<$E z1AzHA0?wTV!p_1I(yO+`cB{CUIXn@7sO?{}$qq-mKH=%|my5BWx7 zKmb(n6EIMj4SwM*!}}&GbUy3?EiRYU0s?cGX%~TVau+aru-A9&9~1J$r^iBX-rkc8 zQk^ngDyZdaWCa9c`mbKImMsehDI0|8fDAa|EmWO(SW@j&`}m8O$~kx~LDU%zwR~P#|33IJqa(Q%MFQM%d4^|Gx%zyyb5jk;e=hu06 z0~^BWWEm5i4jA23p}T;w-)E}LK@d1#h5$KTP*}@4E;fjqP1h}USA)8F>U#M1lv^Z) zA^8uDZ`a(Y@z&w0$PXZG;cahsWUSA|t}NEjg+z3fXQmY-USRTWn9{%<%k6$>*NX*~ zR2LU8^pnc(2G(M-y<~f9b}r|!^kpKq1RAR6IrD5^7Onr}J>smV5yQltU{SpZJxHo< z%2S@RbClg)XMfOU%U-<;5O7D$DS}nU;NNPfBx1{p1E)gL{D6gc3ix@-yM7n`h6+qLp}zhqxYq`(IM#J z!669I(O!UY>}E00bcz*B1JH>^3Skm9F}6gcNSl-78=v+)A|+{s4qwUi3ED`IYSj_% zD<;4j3IPEz)_44Z=A1Dm1Gsz(+%&I$8_&8+btrST422>e!>qG`Yrs<2r^*IahV82y zrXQ4XJcs#47@i)Dr!>@$&Psl2PWhkwE>jd42tmaMOBQAYrzJHo2Tp#|GJ2cecPA0! z;Wgb@Da?>2|BN4)24FyQ53DH{DS8gVIAd8JH3sZ@H1sK2KzQx&xi z6#xO|sD)7S^!oKvq#CoF3h2mRyJ*=U7Vs^wP7~a){guE?DHyoT8zE9&o51J}u2x9r z2iLO$$_euh<$lxdUu6t_pFJ3n=2wcVSb>1HXReK2rNKkrg~NhN{Lf1CD)=9zyq`@~ zREa5@Ze}&XWHbgpTFMvYxgV5<@k2t*anZS-f>>}ZUzggK23KdUpOL8K$ORSn7bXA! z18>M9rSAx<5%Jl(IaDvnYA`W?Dfh|_f9?F(w@p}`OOb-2+Z)zIF%>=f(GzQ3YbTx~y*2|~e`o{}2-tQx zgk}A%vl5G3J4Q^mdm6T-%>LB$ORrNY zCyW*)m&Km$w;groE-eqOl2xXd7_`fn$d><^!iHtA^hRYzkc!-peUxg61mED>D8^!7 z5QV+l)_m%Ux6%!wpS@aNJ_Zm#d~lf!yVp`T>Zdj?3CS(t{&AUHp5@7Y<@-4uZEMvl zFfoA5WNcW*^7!Q3tpRJVRBof4c)@*aen2$T(ah=zzmm%CSJ(_>Fhcmx3M&pmq}^k% z@XTTPw|@FEA^)rQ;R~=_Nkev<9FW4*lh^u9_Q39yL`NW?!T!jLOHa93iRclBB|46* z!2UL@gK+)Seu#P!mc&>R%?7|XPx=2)?Rwc3hNs6982{!=~ zJ->Kp%n$$sY(`;i{NQ16w^?9aiK05(WH1}l(<)p~$_|}7h`(Nz1=oPZPh5E+7xPe- zkli7O=GSy$@0;l|-#T$=y>g!PmCRs z-3s5Q4FkfOl;{+w6%TF z3`C&4Q*eDieo9?H402P`3co!Q8Uq?lZX{u<%xD zKtjo%;29L%{jhj#i%eY-vQggr<|>~_SRvyCjcs2aSi9z4Yqc()!jZjL;0diWUl2kZGb&;@O^>0R!oLUiT#qd8b89xPT7n%>p=U*l7w6=e}Kun$OzR;ZO*?+be|3cJmC!PQMi^7L*7N4=-l5$A=XN)2s)fa`J zL}8%!KB|&W=lwm&7M6bd6u&MHYu#t(d2Jd9@Fa1!I%cqj2;b8$CVlLo z{ScpP-4Uh2A@#LEcE1Wv8O*d!P<+|*YtD}&a~Cvynfg)TVyTTp3 zXRZ7`i+l!nsFT~}IXFxKz)HXWL1B0Rm-Zox2Aab|NdUB|sTly&Aym+=0q0FN5B63E z>B7f#$miBxQ6*^c=@00GS$&B7RuQPz=BLO-D>u2lR%wdq^x0?p9Np-d@BN$KR0HN) zd?fcB5syHDTKciIEvZ+ID5_BkK{mp5^K`=)N&Ewo!$ivQr*UJF$cqJ6BDl3S2x5I9&p*|t| zJ1oPHg^%?&?Y-xlAhE0oVsgF1Ju||Y4aSWvA(z7j#xm6jT`a1f2>b{h<^J#X!ed0^~t&)Yqer*MvdF^Phi%?m+Z`TMwOs#>tn6yVUA-b?~cveL8^He#A=-yxopv;5dNPed^f_V%5lXc+Im`~}=gn`gYa4oQbW)Qbg#f-<{1P3{ z00J1uaxXBO87gZFaWVuSoK#dhAKAnk^`XY=)*>>f!m#`$t5Rb-Bs2t7Nq8@y72Bzbu=vlf|BjM>TK_xKB>y4O@MH$V#;?xrPcj3^u53-U#gU zr-5X=DoFvzl*^97?9u-OH6T`0gLC01J*JZN5wqk-C4DiR8E6FomgO0XQ5NshD8V#< z4(DO(Dc90wqE)WMZ0OQ>gdzGdgN$1di7Ks5X|<*_TcDu~Q-6vIo2O%RCi}Qsi-)dsa9Kd-QfMzdoQslncwxCoV!kC}$77&DCW!JY?i!+> zH(a2lmCNTSgx~`xrx9wXc(0wMnw;-&61>T4LQP{d)zcgKNYk8~TRvFG`e$NGvb>Mq z5oxdj`P26`$>AfH=!Q_w-o>b?l7m#6I=hyG7pU%*SlEs0uV=02(GO=eIvB;6Z*e=d zIE}2H>{V435WoI|=fBQrbUz>_QMYy8&1+X%L`O9SKZ{|Iq~2+pKxYJ}mv4=BZ7?X6 zSozG5fSM^sG=zlTrT4D9Y|zJa9aIBJ8~};1P6LASQaWx$v9D$?7W~tq7vBGUGewVb zv#1uqmzv{d)4ub)==IUAysMuczh%(lRxMrCs*O0g5ZzX6eKio^FRJ72C192m(`Rh% zNGK!mZZQvcp7QJo|C@;erV)oWn7s_W&PD&*TI8c)){Bzwfu0QAQ;7>>kOYzf@w~4d zZMr_=ipI9{4knWW0Z|o}!}^i7Wd=8GULFdV__7nF>WIQu6k{JAfXlYO<-s(7frTYw zxM+oyl@ynOR>680rk0lqs@Ule6ETog7(MFgE{)y<`?Uux5Wr8AGeAwioTM7SrsWkD zu(qz?bz8D^PI!5|wC7$ZDh+1pWfG)vJFRSZ$P{*1@^tLzdoF(7*_b zYpj-K^g=y71)=_(ib`?1RW$!0dc$uxV)5(Nl{vkgnw=k`b4trV5) zW@Rp~4(m^J1U@0(x{=xor-fp%TP&$j4ZQeim$~R`tMR5UlANfjfvvi(1lFkR`*#?h zdEiOOcVx5vl>5J*Q)G@_An9b5OqTduor~IMK|7?spR{vp9UWkDS0O|`0h&}IKVW3g>tG;ZK_z~R2tY(4>c$d<1~`=i^wsj z4G!(0x^E?PxW3CF^yAfkHz>)%OcI6_liMLJMMvMYTO3S z;xLajUX?Krz;0}l5*#1h8|1D=8t?C-w3sWMh{kh5Tji=94%sL@wvs`LkApZCd zx+B#}b0`vrJyep6^~k@Vuqp1x#}(st0zkX4TChcMT!G?f)^@SX&sbG^bX&ZyP%pGU z7{AjxOY<)xpeI$j!IJiq!Z?-7;n@!htoh~Y+;ZsuCz^j<$5^3h{9IMKzgmb4y-CM_ zQ{zzSqRGM`FKJ~HLgiE(mG0da2xTr{qXYtIMT0alNH}eEVENIj9w5T_`IonjfLdrD zTZ?4|grWW@cz=H?z=p@)XLz>B89L}K6N@dW)6)yvo!KFl!Rt!!+z>2&_Qg{6mrEKY z!GA_5ww|b2DE&I<&t*3eJ|Ezq^_!%>vTP7|Tw#Vqa#CiGt|$IX)nyk29n7HOUKdYJ z6kPe z*MK#(xumst2YP>Ex#+WRrx)>F_i0?A29I7Nm_R?HjTyYbmM1RFYajqN)j903cB&}1 zegL-}1x4QccsIq4uDQL^DYkqklMDk)La`qi=1nW{Oj*V^9K&s)X8?TOjvg2EyrQro z-)h?-vm3idZzmkfp8@T*KPg(FF<^cBDG?M2(8AtCQE~KI6q}_W*C#@4Fqc&U(*O?a z)*>r0l?kXm6X^?t=`Lz-CPusn=GZdir$EN&pNkAZ{Cah%qE4W0&O1U|9l%)s6e_}H zx>t`J&${Jf7pJ>Hhoxep)O z6deAj5`W*#ao8E(BF*;5Cr}07O)76=(f9;D_cv~^pq9_EqFtE`wp&@aYT!_a{xes= ztbUwOO?ZZ6K~uFK8by}%8G)!XE@Z=m-aP4{v%dnEC%6C1Lo*4rZV@d0}eDXcDm`E0%(L2Hy9DuFS%BoEd!` zh7&~)y;pdVvD zb=d_CIfsIoASbfJJh>-*KfUATUHp?)kI|p)$zKa-TpuaT83WWm7tB`(C%T}EE_SRZ zSPrB`OcoHEq%lQM_EDfVYRip*+HPw7@|&oRv0uq3j1U#Zj=A(!Qas;!;durH@W0du z(sF~DQ@GAM>ru(rI%#hXi#n?&ZfyDmQG9a79z4w7xEDbSvVC=OP}t1PQ!PSO6DS4j9B>71_t60iyVQQQ@Bk8(2t?LRUf+KrUZ`t7Ajqol-K)$ z7pq^RXF2V~6rl%_-G2LB4Fd!e>>mtVW~+Scjc`zXwH@?$LzIYtPT)6aiusf~>}jq9 zCRDlYKZ!|+WNB&n;EkEA6RzOq%4ROn)ZBAWDV~ zGCi;wne}U``Dj0oSvCG=Cm!5`O$O3ah!C*ULfBWHmK3F_A!8c3T>1kGn(eTwMFLH< zSPOyCil9!hE9#-U&7#K}C2g%a3997T>-3Hwdgn|dh0RK*)X?BPm>}eNL+CftC{oXP zr-*tkA!cPSJx`FzLX&1?6bW%WH$$F!FqNOjbP zOi91TZ~b6==)e%I24)C&Bd96yt4_Q*R}}1R-AKI%ej=5G>7eL={54$7+kkqaNW`#Y5+LB8R)ASC1U=80^9jnoGFMKMF3i<+ zpQYRq&-j%#xxf#^YG$bueHY^+XdOI9WR28HrmX?D=SU|Qq-#hbfv~1 zQtq8n0;%}uFXJd2L>9-lBR z{Uik@3xtcq_A_3`&mzhm-uU?o0vZ-<*zqv z!Zo_p$al8}=WQ(0Z^h83KE-zsY#(0`uN*1Sz^2bi%@iF$b>rhHfxe{%JJ&;}`0*a4 z&>^!@Y_L0!bag-!5)i}bb@6;I0{2Hr|EEQ8|Fg5k8@nLOsW3HJ^>+&HHvR$@*?b(j zUb%H>hIPGuVC)T;-y#Cv+|Z+D%CvN{2Gdbu|FbKTQY=~I2%u9HrZQkubz;LLh9(zL z1-fm+JXBBrSif~3!p@X6QOq#n-u zUu-;HT<}jDkC#P%-_MGwoT4$Gy>h6b_)fQ&^X+roRLb(q=x09})|sM(^}95;XPSt` zMHkQ>`9EqWC203JOhr4Lqo`8EXF3s3lgHtG@SbSuLjcAnnaVtyZ$8>v{q&Ix12xo- z@XaS*%U8Z`W`t?&?dCZ6bQ{)A3Y#@yYti!%c z%A7dqQBiX}?fQ|Ud_bJ&8kVM892BU38cTSIL2V{_ZRDKP;RVuejRjj0Dl&O7-&A6zP47nF-EuC)5d9ZeLFm`5rl-3 z1cgeo+Bl0Lu+^H9#q|oMSy_=7u6R1ld<=+yb>KlJXo~&9X_;NsY^ZYvuz6rwJvH6WUJQT%jgzFkxFJ79y@8}bZgJ5@!ypUxTKz) zCW0mfn$Ke`I&VUmY;#5}6UjB_%@)ncS{t(CBIyJR$Q z&?+t#11Z(~Tt*V(*$l89*Jbj>f{y2<3!p$(t71NAFTc9JSQ;j46)UQ~9+FvLhPiwQ zauw@!4T7(oa(My$-%E&ZvGmotp<7|e=v-7*r9-q_MJ{2rWl{4{yIONQ7vBn&U|2Th z%?*)(xcS*_716>$mO@pHsFkBJ>IlZiQC~#c)%@%0(`?;QLdcg6r!UVll|=F!in=ba zvMYT^LNlf^JE-T2-a$TR4(ulegO^2rpG4ovlrwJ*Jm-JUj=mVL{k#mP?FF6gFuRCO z7p&1v2a+MVKvS*1Ii!F9ASE?FLr#5`L|yK^Hld}fU?HGy!d8&J)LyHJ`U@Ktn1Om* zJ&%fR+EtUAR)g^=OgOsrJz#;k6xnDR4WNA1-Aj7s6R*A_LIni14geR%fdqcIC*X5N z{Z4InPC3jE5#^BnpIEK%TU7GMilE!t_eHwo)a!! zw{%#)nE7S64K?qd=@=iT|H(`Rg`FPMYNMOhX6u z%!O5cOdEAa?bdcXl~|lqmfea|%PGiR5LQK~g?qmS)YglUhqJ~<^-f~%Al=yHsuct; z_;;~=Xq#+tuU7i`Yy&3k;X(pp!s&zd)j|^r}OOPmkZ_4%z3rK&t?mKz* z6j_0|{(Kwy_+-PX=)CnUzAtT)B_1b!ryUQ>04Zu=gqhssvr#lkLZRP$Md%Dc54U>z zOi$r*{H+%IN~`0s>g*h|V;oc&{?%;q5yW6EZ+w)K-tAUDPmbbMUJl0A`BohOF1`Jc zD{ckrPZRUkk2xrXxE}+vc!w!8fxk@1EPLgn1WDvV#Ub z|0A7B>5NMa8!LL!S22XuC#RjRCUx@?X2|6t!+jy32L0Gj&-lS|z=!WG@#*BN%iG+<^^xd;sOPTbDA83X{eZTWRXTkJ#0n0m$dX@b^|?nXx)6L*B1Fl|e{>jX8Hc|8hfR z!J%Ak64mPQVQU0K*&U_|Re>ZX9OEN4G%Gy>1cR1W8RqNf#4-3b%;e3EXtar(nQ2Pz zLYxp22YZe`^A`|*&nQ(B>bTr*vyuzcGHMSRQd4G}1aY5z7Q3)ae|#W?6D}8(xP)SU zFB}U5+?-O%B_%R=TZ}%>5d9=x(Yxo*%M~$BJENIU8PpVq+lU{K41n)wVI=2lWNa7*Ql6Pud%_K4*JS8w%sPTl5&A%Hk0ot;0xKt$BPw^ zoc2#w8Nu|xJIJ6qh*&KQ>R?kyZ^1#Q%R?3|Pz&*^X6fPlzY zg!iVq=<-HnA5Kw?gB#vt@cHT;#Glgojz(H1zGem2fN^VYS3*&^z<>xTU+Pglf^qVgdS!PABRFAm9NqMa32+*=G4B@#@`VjWT1+q!iM!g-Z8&K0@}@ zcXV(Kxa=e9baVLn2}$j3#19_pTi2R_t$E(lz zn7I1F+i$vr9KU8wX*_c?v+lgG)WUjZ`! zM!W*rX+1cBR&vy#GZ-By37*xki*y#;JJo8BaapzQ^|43^d8!J^L>1q{ffl52DQvfm zti0=0t0yfVKHXOr9!vrO$isNb(}IoFQ`eV~3|${hn>WzO?x9>F0(^BU?-QNgg6RQu zgW8ShgVHg6neO3b6F99C>F)>)uwLP1Y>huv%t!I6)jx_yFsnlY0Z%nYlEbU94|0>2LH4OOhrgTgi8JW!nfQfHUADhNgX*U8pbVg+#&oX zb2YIaV#_AAOhRv5Ep$QeX}E65v4$>tFF|BO<}0%lMlYw*Hl_w>qG@>l#Bq=owg(d_ znv6sf22viPtmViSA-m@%5+h+57&<>xs`6+iMR^+dqPL50d?8nxL4G1^9&cNre@3NL zz&@nl%V2=MEU9w}3UnJ$#AbTSb)|rw;QsaQq<+bJ>(JerF=o%H~ z=$d^4@e7{*zOrie#4Y+p5lno7)gE)}G&170!$&NK7kZp;>bpVWaUzcE9><^Qhyxu| z0rz1E*LAP1WdPzuOs~+%Xrg*?*$FZPE<*1QUfIHfJD#mIlSQQU;FA(YsUzIi?IuI% zRY9}c*foy^30>F0_jT+HDoSuNof948Cwm$}28@~a>HEIjm)VTi($H_!H^M&(Puk9m z!sigO8N48Rv?{OX+4ME-YS8O?x?5`V+ThY7VkD27`cWrcx`1qSF#V*nHAVe-hQYM~ zO9_4aB%CAWM~PnNyqxg>Dz3khmlKTl3Hx~Uk7g(k@r}&*%;b{g5GGt?>!Pbn^)LbT zPf$M-YNzBh0zo(Gz{Ha-E1_#exuQS%SR)5-1yZ5YjFp=Vr$ggu6Hmow^qcZ-I}EMJ zJq>oyTSj=N{0};PEGh8C`vpxyXq@*k31i8=p0y)8ETYy7T!P`=SnI zf*;CZn?H|aW9AyC2<(*^p=(4E$`VN(C1)*&BTSZo6u*Cx9>7d}`V~62J&{M9T0|OW z9W^fBT)VukGBSG@g;)yoZ6KYsnH{z=dTUHT*T^**!&6q5#|4cXva5v8c=x?pbIb(y zgCV@XeCMoI#rcy`{@w!yF=!w1noHL@5T`Id`A>a2e>aTBe;9c&SlS73UKmRcP#HiJ zg+guzsm%ZX1muMBatbI@=$KMxetZLSq|-X+XUlG6sD7KX4>=2`-BT~1uZU+*q_)r- zkd>Ro9~eoX@t~a_N5ArLc}HZlu)GDE{<7%rRc3?Yh+qAj*^)gA7E7A4v1E1PDVwty zp_9rzdUMoBcRu$k&EK0wctIzaqzWb|m*d{ufqaKeHt2p5On580o_dkt28JFzA_rfE zzzn&e7;RoGK~zxAfNr7O|JiUwfwK8JHxy% z#pHNJwv9)wD%?S{bgs~@i;eqsO}p6!Rtyzqb%;p5-JJXMS)YDM z(qynu{Xu!@O9p7O30;hXE~j_6DWH0iscrq%0@A4~|J|<^U|V0)xmPF-xY69&f6I&_ z@nO3*E`Nhc=`D;tvYw`F!3F=8rxE(QcM-_pkeD{tlb|W~6}TR>?t*TZ{T+&|llOKC zcVBWN8S>97efjM--z(R%f~gxBLC|>>)@NXA8IR~L23}12Y#x$3N`mEn7kKM1WlN*Sd(2Q;iVhEM_pO2OaKxx|hEH zrSF@eI#d*P8 z!xz^5eWo=@?PPd+@W!do>S}w^<~V8e{uFY9U9Bz*l^k)g4!#$~Nv+pI^i?*9_vp-z z2T-edrHwYEf$96GpIS0?LKAlJ{1AsHWuc4rv0up2u6}yDlp~hBDrS7me(xRMl$Rap zM|CM&hpNKBd?Nm5&gmGj2ACT_nJt{LKXS{j5eCl_TH3cAyD;FUsv|G)N#qah{+jnD z1&DODkBo_R02m_mzG1{4_DCGkpA{2GMgkB*3&so@)x17DywL}}|MHs5vnGz$4w+gi z)Y1}@zeD$G1pi#Ml@T;ICk}B*2LO}zCg<88ilPot80pm;H%NCmh@G8H~T~b=^e`t2&4b)$c$@nqQZxKFAU|0f@N>Nt%)2-j7QU)oW{Gr%uMU z(Es=V?%<#quH$hbQMEGPh2*<5k=Pcs;NKRRDGDs(Wl|6ip>Jdd3oZ?WOO-$edjIqW zFPQ1ctkiw%>LkNRgM*To0ad2b>Xzgv)(?okD|Fo#iVan#;4`O>Fnxpk|Fyp;uFH<- z^*mC;u(OOQLMm&eGIufb$#iauZSWh~mV#(|VekY8+^zj1a&3da^CpFu1XOWdE^#a0 zN7c1OOd8re2jiDTf8Sr2ov?pz#FrkCFAX~EO@X1%Mu6OyO0yYA#ySf!uCQaYk7hMJ za9zX&0!*xitkTP)M!JP)zP83Wbp8^Ra535;`i(EksuV%`>;z__GsjufduN#9_ZvoI z3zD_DPegH$l!F$>B<+1&QI;;$+v>jTy{@Y`UC@wPVRs^gO~4$=1AW``od2n<#W@av zata)L!W}-Iege2%y?IriV=Y>EneMBsVeKodux{K>E-4MzJc5fCm6s)^4~^c83W#}0 zQ$WDJsI5AwJxk#(Oa)UP7OdrlJH*V;T!*t_Kkix8NC>#MFwDDS@`?*8uehBht|7Qu ze~`E_zdk-Kct1Qa7@o5bkqC2XXOjH}nG*<*+@LuAi5J}O`c{Yih@pTUpRq1TenD6K zQmc1gAvR1MOwgOpd|s~HbX7=+PyNaEm0Sxa(#R8unGrgKR4jbonc=5EJCS3+k}jyL zS5=aXct32ElatX2_yLWM;s5TF*P8c}MMV%vzGlS<1(+DHV0R0m_h1=qlhA4*Dtyx> zeUq{>EI2>%mi`&efNJ`dNgUx7@`NVnrsRJ#a401aUtnIZSSwH~(YrsK<^` zQ{jRNQGad-Xzefiq3oNUk?b9iLs0G5;vZU`XSAYMkQ*f_3w{?om^exh9(RisI z=AHf9V+@cCvs#ACYb7&ei}rC3Ivz=(`+E;}M>*aw?6n(bOm82!9hbGC!q~;?qCUIh z=H3Dy>KO1gI?DgiDnZGIhgW791$vD<)c{)@-xmn5x%l94&Rkr;QrOCn=(!S>}EtgWMz+I5h*CJ)!ADMA=a+zKYp=ZHT zy$71Lo4DlS_+h^uN0m|`K@4|UdbL+>cbVuq`CbQY-`k*u0n9eZmMEf|z2FOd=wajg zEA@_bm@jirEQF+7p)A%8YUxHEx<4~E)8KnOK-HJH1OaIcnbbFC(7VU5YlvH!u@1Xk zoLf9T+3P75PV~=HN&j@S{DrLlN-FuMVUL&p>F=wrt?GA76u#V*s9g*N-`{U?l_64y zJ$|C~TPlSWueiwx2qO1eP9gY!etYC!9TNY2mv3vig@ZaH=OKB7JoPq5GJN6eu*)|YCVFk(wvgo9 zvCHiRYR#htczTqD7>3|~#(rd(5lvVb;YNjw0<7vH=5J zA=S^5>Jaf}Gtw_JzUY!bKpx%K(0zp%-S`(pW$4{Ix=DvxKG*J zOOoUi$Y;F`g6)15|8VU|4S|dgU(bx8AvbSw8svQcu7!p8(4KkmKP!v9DJfb!zx$Q7 zb!$@U(G@YU;dXW!qzqE={ZxKDDsm+@893Gkv2tMvt|NX!WG83M2eoz0Ziz|5yGY_yc zp*|>VHcs{QV8)5HAXW7{<<*PAf{4MPZj0zHF>|N=dE^FPw+JtX+-H3k>J*tfnT6|& z5=@1~@jhStyYKJu^$=yN!t9*YYjPMefue;Dfyn_0?CRu??PP{QhCOH^K!6hi;if%i z)o-%wwTZLZ+0DPAr`_b?8O1c2Wh0lA>Wwz4)T(NG z?b~fcO7Khc4aD-Bc)HQ0P>{gEyWm%c1{FcfhP7qf4mt9i&2gxCL!7sg%xsjPH0J-O z+${)wCTZ3~;GMUkZ9V@Od>wqCH+GDjpJexEcdnMCjM#J(+qVy_DdG2UWX`b}#2trMMX1!re% zP*g(D{p6`HEGhrz-UZD5)unVmkI96~PJe?2yIcUjh}}MH6fSw{jsjP&QeUFjVd;PY zF8A~|5R{&-;VHL9>>@rnSoorhzRn!TiDheA-?(4}R*aB-qjUnZdvmEKMMeM!a;*_E zl57V9SyxV;(|3NI_sdyK*en(?tsv8fr23xci2rAk0j@E6*0RVu>N|M**mM)c>>3z2 z*sU|Ba<5HbY-SzV)iflzdwW6IdY2Du-=ws3H zDheZ*&68WGw?=dsPDtDF`3@2fJ3udza+ZDu+b2ztEe!6mO1`}Lgp9?2*9i2`mPg5@ zy;01u`XL@t*1M1BD8H^`i7@K5Tbti^5R8rJfr$aPvSY{@{$~_x8rvvsBfE|etc&(F zhHlm*>%BzF%-=oG3p+{QkA9i{XAf<;i^EB(OiP;At@~`x16kDUM~IAG{UXzC=I+v! zFxj>Dk+%QJ^u|O96oT}?VCrYmk@YSIC9C8Q;;frNDW0DW#T1Cg#*rCA{)lXU-%Yv4 z7Uqr`i-hTxnQ9M;FU6f5N6o|=FRVKzQH!w7>`v@tV9mu$`V)ahlvIaBR@iI(gXOG8 z6F-fGi2b%ruY6{ASYeD~doL`)31$d9Nb6LO-ue038Kkxly5}C6VNp4hNkTPt=1qln zO6R?=Lyr}mHf)av7F;hA7Yk#i%z5St5 z;N$G|&U}tMWQ&eGGuXbk{R!hsS8R?WqEhI?pI^F~2$IdTMc1@|aT;;?(8EfEht5=t z{V^#gNxFGQfOh%qpKtl=oaV8)s--EiJ>s@dYVnO%-yzfw3k8m5@mq=3kUkz2YlC=d zj%~){K_=)|>2x*Kt~`c{V4U`qFi%+Jns)t@9r#SD_Ifg9v>pVp;%?WNg!{Wla{SChJ^56?9({sqaqQq_-EEUn_*; z^uPcAs)la-P;f+X7@5&Df0)qoN4tviSHmIAB~5{t-n00W$K>@=BG1d?^2B9c%PrVi zrS;>+m;_H_WEh}X(})`5cC9_dA^z!|{`yXjxA)Ig59XjHKD$@Tya;EMD`XT~2O+aY z&Tg#pr z2pDcT3NB!n+I>rAdZ&6!ZgZC9K(gkpVR;}o1fu=t^`6I`gJr!>GkWkQBPjzR(Qjfm zC>f0VGz=OoB~r}61ieo<+Aa&VgT1zNBL~E9?0v7bT$8R(>!ZQ+sF4M5+S52x`El5a z0e=6FxUY<=a_icrr9)6qKP?(XjH?(XjH-gHVxcf+?2e*e#5kH_); zbc}n*+-qGk){JWcD+eUq@amT zv`eudNVkm1`g%80=EsgeL)08JioAe%L>M2TzunhKQ6Saz{pOW>h(cj^I`f zQwGMDf%8uvWKMsNKq>v1M18pcF1d{@CRX@AR7M#6GkY}bWURr@PYh0F`cs*ON ziHu`EpKu<(gSS4hVZ6=^hd{b+=r2h5BK-{+sTf`D3RrB#qFs$2YqxVOuM6H$kaHed zjmG04vosrBhFd~Y7Y(HV(bBrCtRUDE+z7d(py{-{ht(^MQwr^Q6wy2$H9LPi;6K&P z2{^B9BKiP;f}ObR)Nca-_F^sxzjzMXN>s19v&wSXTLr)R$go8XY6`&B$(5%oa4CEJ zy5xAg3D4pSnE(>c`Y`bi&GV7AZ#_7HER!_-jVojaPtxDGBu_4D@sx>d?Z22Frbz-#YcC zqEW?MAJQjl=Eh_4AJNAnJJGbSl!~u@dXGIIB?E9m24oRT5{l8r1>Smcv z`=)JMV;`0VOPRqM8D;9=i!@rLb2(RO!#3htC_-7}(awN5F_169_jR>Zjo%L?{Uhu_ z)y-z;Bk>#fH-M{6Xy(th8XMc0s@Z7 z4Cl3_)Ul$!RF#V0h5%4-!=sy&wE`TPNDMvOKhG$!YMj zW5dMeJFupCl#1-NRDclAoJf&WusVVS@%c455>!FBhOb^sc|e2x#qAPfe}RheCtvfB zM(GnOFC*$>uan(c(XTpU)3^y?5Cw4m!9pK-#-GD~t6dSdLz{}{yqrlIhImL)EpKfi zCdbV(?E96=aTEsV{Se`sNf`p6)z+DFlZ^vX+6$dor+Q9np77>$T@wx^?VhpvZ)u9> zk3zgZ%ta7{5*Qu^X-jRr(qILHfnVc^TcwLaPs_s*`1uF*FZO=!k6gKP>tE_ezC&u> zdo|9yLc)rNWM3c<4i^LDJ~3VI1h;HsAu#>Z5A=or=`Fpf(+SDg78C_~UuqL~_xEv( zidVy`3uCi*>27XrMC?f@{A1S>X5bRI*2! zdTMCCWg3fcdEWTzdGUd3)XucU&$_56Y#Z#zT0Cu+dfUt;DqXOq@|8 zK>XDrCQ)QWe5L^8-dVU~qw1`Zi8NMBVH8N=_o%0mouA1BqQ1p`cgg+k4aUkMCgXI- z2vt?fjr*{1A)jrjqk0w=r~^lyz_n!xV}@_t0Ga3X7NU94n^lR$qq*dqcN1@Be#wrv z{Une4fbJA$j`*4qY zsV9WfezBEaEaL!6*M3x#t7kZ!dA&Nq9F(656nii8hD|925v>p{P7{-TYU1^D=d8)e z^G7eQ$$Dj;s2}*wCAm;V(>DET45+WsNyS33XZ(@ndFh&NT!6ZHTifhP0|$UgpuA4% z1Yb6QAUWArbLURG@(gE9sU*cZAU%LR9tFb(5p!M@W>9_HlH3{Du#rrTe$+LD;35M* z)fTzPjJ3!hlZZnFNX(jK@CgA>uY=+CPtq?o-xaBAdGFc!dk9ESwe3PUIk6%}5Lr5c zn)dN(ZG+^A2pT{RXIkW*ek(dYdos@*oOm1=92N4IYe{ZJl#w|8IT{$5{@WKIMy6hq z?quMNt#8UL)RBH+tgg5PzFWA@Ft7km$-Y_NGirlYcf|#-Itc*QhAPujN|BHEp=cA zDO-dCnE!f8R3DI=7?p6~?nc~^tNVfyr6U$;g=}sxjJ3xoJMzaCX5R#;?0MdVbfJ${ z%ccMJC2vIFSzL2qXov9iIjLgvP5iaU)Z2Zs-sqG7m7sR9r!UD7 z%LoCHA_)>s(DM5QFMSqOIY3*f+Hd+AnEZ@lDUjGw^N`R%vt!`!bpbmmOpX{tTULWf zD8LDGsK)?N4SmW3vT{j+EKIPi39acwG22ydI<~X;jM*>Hp(Xq;dmBlHUFbG>x&Eu+ z`?srn))nszs*o_d5Bp&QGchdo;*$MGM7U}kmo}fY3A(6D-T&CMa&xgFL$jY(QG)E> z!PKpxnzLs<%u8w!onFct6G<(!gJ}4Cws4U3&elr%Fmfg&X>BTL(hX*0n%ZT+_FKJ| za%i{5TxExOsPuq6?=fA@Z~23jUHPQmaq#Wk*gd>L`l1X_dA)*1ayR3!V*#St`|1Xw zeu0Jlc|+u#ltV+j#PLbWZ2T_JU{P%&ZOU+2Z~}`aw_}{G9{^=Rgu?Y&Xk*ih{LR;E z%V@sbj<4q_HT1mSVpB^Rs^vEbW<=tOjIfa+gqAcBUO#Z#dIWr zF#b9n(v6P(3B&}8Z;fOS7QyD#rkG7EV-=oE3RGOjojayy(ZQV-Y+%2aIiUO3sOWSH zFvR4jf1lu~O-L-KiJ#Sr&1mz*g+@;!$BHikkLQb8#J%A&p8iuy!^=ZV--#>H(!Bcc zILWsnRPm$57%XTX7~cB;oKcGKI4%WQul+VP>^bDofk*zOsMcnp|INE$eQ*@F#Y4wO z8?sIhO);N9>F6o#jLuUNqczuIX|L|xjy>gB!^F6y!uu>Tu6Uu+rw+!Ll)wn z4YF-~ht&rOBE?;g-#H_wqi!}Tz#0u^)3s;d5%Y?ALqz^qj2B1sewpRf(oC82uhV@7 z7c$+71!hf}Me!zn_@dzntR@X6*=)5zl@&n%him>Vo$&lqUT(Dgk%g-udzG`@pg&${ zR3yViZ@@uvN$KYQZVG!xduZDLV}S`9NPo>i!=r{uAukk2qMh0;m|B?D9~WvAX) z0_oJx+;D^JR>L~L51SS9Wpj6tIX zOSc#OWMfk1soSSmyUX|hZq2dnQG;8&%#K`Y%D?tb4>?)Uib z?@L8TzRsIOMNTkDvnd2>z*^yL*Aoy?B@Kegza4~^XHUrW74@(P-l0IQJ#&%U73wan zUQ=+XZBSkuV`{)Ot5pKhR_ed{&Hu#lSE!>x*M*^48i{ho;RJU0oA7;N1=11~dM6jA!6hS6bBHsK;5`F>Q67HMynN;F3bjZ2q6My-GA&8D9hjlBR zYpCB|#q%tzX?_JI;ok9{m47F4{p!OaI)(*JTi|ZPH878g*}PZr#qe^45#DT+EuzEB zEN6SXOJ!FI5iH62RMrT@D-U8%8Xg-IlMl3kxO7g|HYC?OtBy-$ww1loxXYr``kcm`&Uao3L))t$kAEZU5s$w zR#2cbO^V6RTa)hVf%r%bS)y9YFQi!BStp@+tITNc&|3=KkV}z(CFK3;bOyp_ZFak z7OaH134AMmjZT@j@ynIt73&i+-SbEP7SKKamj8s_mt!upt@cyhYHSDB16EgactrYx zOU!RH4>b-~Il|aUo>+2|InT<@hhIQ~^PlPbE=>b+!vnppkw@3@M(p^K5H`+b%W%b9 z7xs^EE*YdQ5f8S?2&iVX=y4Hztsa6Xyzo$k^PaZp|NcGz zQGjr^8peh}4(xGg+a+ffadHWogja?v?0w!xb>&?~^CnXGyi=Eoh#!Gh&c4L>O3{<^ zqFdLDcU8=5w=#v=TPil4eM^Q6Eu3$-`G0(yhGmW%Pqcj_p@Jdbs01HQz6lRw!UwaN zz5)}tFxpGOd;W7Tzw&U&Q+U>@BY&43r>$wZPe`lR9d}}E465hxW|27v&A#D=B6oN_ z^1i?yjKbI%&7?X|?_d6eAyU+2AL_lG@A7&HPMXnl)YXgW&qA~R9egV%9IH#i=C+)B zxpwS-*M}5(ou7jb@zM%ARyej8qj!S(gKPVY#@lXC6}35yP+66K;n;7;YK}H}zL{h6 ztS3W(A6CF#w9d!S1-2q!kv`__evoE`a*2$?VAV~oG~d#C$dY!LZI#Pvo8$%2szewU z?6sPj?CIX4#ge7|Bx>X=46vQaPnDYlH-J77$TQ;A2R8=Dj{G~uK@6uNyl)BmybFjz z$XC88N-lN8XB6Pf5AJimU)3IkW$trP6RO9%Qew9SKtV{VQ};TkpW|Jjveruu1xVh{ zDZq}HLG0z{Ym`^oyaM$E^6PvBwHG1v^iJfM57$_hobZj~C3A`xqxLMA!**BoAHuX( zHNb$L#cx8vaApa7(nGYP;LcQ3IGQk#G8PAbGld~58LlJnXOq;+3*jU9l_v*fD_kB#8EcN(MS&QYO4E-I|CSud@)0@CmmCgZ)0Raa z5la1w$9raWw24R+uzwc6yj+0DaRw;JP(|bJJFR4-_`UO07tD&}sr}!wkVRtyqTYJW z6g3|zpf}@ zOO2uEVRT9M{!imMmvo+P^fC+h0mEUKOg3-q}7i- z7F3Rq3v93OLoS4wp0$Oj;56B8XOF8c$S~&Tk6vzQqrYx5Iwk9l-g-wy&U;SCY_X38 z{igeR4t;3v7?1m!2_&ZG2@Wg#EZnFDPYDbB&U$u7L=m0w^y_J8X)KH}b=MJhY zjJ^X=?W1)*iwp1NDcxE)XRC2FUTJOyNFSlU@)hiitITCol-}ygtG@d}Yz%-JE3TZ4 z)G$4tHysOt%y!Q*t>=_g*zD)bUz~maK<8SE%5uG_Y?$JRc zp_j2v&!DUFZ9L}t@wy7^O@d?f>C{Khfsw_!LJIuQEdnG-Et)@@eYetJGvjjzDiUYe zm*I^K>2l;|9n{Cz9xldCm1--Cum9-Jiy!6DHeB&}Z}EGH>Q93^X(W`l(kOMqKI@32 zju|I>`-DN6+<;$%hI=Ou+*PQlk=dSvabsAC?FyIAs9IXT^Ct%1igYBv}; zo+Dyw3+f{yFvX+*sFYv)3_NREDp)ERS%bEY;k{R{lGgn$5O8iSxu3AN+ z)ZtELWBXpn?DLo1v!_&i{lIX;Sk%;p_2oT$1%bu*3 zY3B@^H6}LI@mTS;>Xv*liJ8bWc{3nsgLd@SB8k{_bLxtfD7i3ik9=rhGOIRqz>jDI z$3{p-dazEtL-P~6 z5==hZ`}Wou3ILQ?o+(7o+0la}vwmq~rW#@R>5|!N-bNQCE=l%Xx)7c}mhiy#f2kYyKt&VQ2l_rbck<75@%G5HS!RhUWEyGQyVS z9a&PvmexXhx0N+art?+SBw9h=X_8S(pgC0ZueZR$CSn^Ouh&l+(yr7xm45D5fJXQg z3Rt4z{A1kuR-0M~O%N?%{6eP-hJvRnn0`p#X=C_tIJQn*+V3HUiR#x9Te#|xge^fo zdHO1$fs4@)1?#XvBC!;~^GtR2VM;lR#+_X-DOa}c~bPu`9ylNsQ(&QYn z87~k67Qg6=bnqT8Ykfl~EkA#iWGktW^`mXyO%_v8DHzcQ^#p2&TB{xL=;j2$lj;$=q5>rV5i z41+7pv3ybxL7328GuTh}S$rA%+}G2k#9FD&(c1)5x(Wa2?h=eIHwoZWEe?;?2yF4^ z+k}RX@sUkLkCZzySd}}VZ>H(Lknt%L2@q)0rz1cF5rm09HoLr%;AIyTlKeJQGn5sL zXWou&d@MqK$OO1o<0)ifGyCKDG~xjHM!sjulGgjEeUD{e+ZLlf=?0eJ!)+q z7~S#nVdL03VuxOuXSn7ZI|yKqmU10Au^Vmb5=ciyBf---v_>TqofIb0>q-%-YJ z+mv}BDHqckhrXG7^vOP=eLknV{X;hnl1+KD?h>eGD7B*9(=z@rFJDaVi<1)>T~}EU zqq`*e$}w%Gig_ne`IC>U(_57tn36@~k1P|GfpYsQ zcRZkgrsh=(iLcW=0+a%2v7IP*XadwSgE2Z9yaY*&Z5e`HTKH!vklFQEcVQV&|^yVqx_$6S)A`gJZ~-TFUmFaNiXp8eR%>(=Sa^Bv(n zgnb!NV*9N`shZ9^(D8hy^SU^apJ^~xF|#p5?N2%U7jyroS&f}Mm&4&yOHK`3MnRF1$Lbz*>-8URp9F{QX~%hl1a+z+J;VnSZ4O&7Bd05p zIx%W7l)jb$(?7)kMaVDVN6kgv8&Ts3C{d~gV0?kuvQk(S(N$bxz!<=|DsPS!kCg8* zChuJ6dgAFS0csOVdg6!W9cMMNB0UPYV%(i{Zf_GW!J5qYycK=K@$(5Og6n$&*s}6} z*uhz2ZF?}e`Pjt#w$hLwf=Mm&1uKUYe&F{^+L}`lHvFj*452^}%$5hgO%gv++V5*X zs}WuhGVw)O_hx}PNPaQ|mCZSQtM^-2=9?t=8hBZAtM=OIr0m;lzLPI*^jb zl zuht1I=*Q^CXWdjYb4&Y<`+ah7TW!$+43&Gw*I7q_;Kcnse+M6Fa%u z`u$3%EFD3)cRTEa0A_j44FEFj_vJ9%f$J450->ANjSMdlu%NRQ()YgH|FC`=jtPF# zMZn@Uph4L~#dXVZe8(bYoeD(Xk{MHBu<)Bp=2mOsiVn8wzT!Lxdwn%5SeD?>ool*` z$N5@AeMr^}IBxTonAS7z=ZKg>_w8>x(k>SYiMox6LC+b zjk^GK^Z#<%B`YnBvX^~4{NIY#04Qd+#8;2W?>sH__spXD(R-w@sjV4j3R&6T%E-Xi zvUWYg>E%&K_Q4f z={AM?e%1}aTBomG8T?@cdVHs}b=%nJ`#Gl(kzw%t7#;;$A2MY|F>ytgrks7c$n*d7 z@{leEx4WX7+is7I^}hM%YqlyCvs>wUt8cWUA3B2&KJtXiRp=C@tL0w+pn5tNrb6R+ zSPK%ZBGB}%wfQ=uW$uLKSZk!i84D%VB|$vQ90STnNZkarQ&Fcy*{_r$)XN>h+9j1( zBtLOf&6vYueOm_w)pcgA08nP9l30yi9qFQ%JvpIn9yEg1%5Rn{MoExG?8m03PX0gb z_KOowxzzqULGQrxz%+ANKEY6K+}*|ETV*$SXIu_JN)LJ!B zeJW1As|*@Lrmpi<9)EP;K|oyvb2bxs2p5PigxoM}jqO1>DH?f+wfpe6NsTF$zNf(B zj6Sp9SqA}gm9%wZZ?|HKfpydofttz)HeSXkE*N@{=f$wcY!2Dx+ z|5K~0eM0@^+1p@K)j86)*VwPEeyHPl8Zvz$U0Y<2J%}hYc~;h!$FBw40;}O}v_Ano z4ocpMWc*^UPtxqxW0Qk$8;PLW)-<=(aiTU7@wERMA6`KdJoFM9>Ze=0Z`z^XRWjIY zYDx8C+bUhSBUF7J-*XB}E_9 z7PN*JN8khKTu#(dBYa|S;TC%-sNQ85v`^BeE8m102f9hV1?nb%kjP!X$KSAOI-Esg zwFbSiH{_gssftm0yFV1XFG2^ztsX^QPTdK0i#8=wc3+r{G!#ktd8w`yue(-v?{a6k zO{FoN%m|Vma*zQ~Hq)mg-J623;^OSrY6)NCYmY_9na$>CT~7cX8pp}Bo)7%x-nQsc ztT+=OKp=pdhM9CafB8N=MEN)(x2jT>5sW8U8mXrwF;!=fR}cV|^m8nth3W0qeTwJr zS{Nm|=3uU9b>Wi=ZAOy-8g_MfNU4n<^sa<@+R|So6A+$`gFP4taq-pjuqo_L4uKB7;`!F zQcpgxZ}~3;hNThB3B)7^ur{Tk{j~172pZAScv2NcxmvKjE3G-e4gm9Au@dV0Lx7{&(k>{h4t)2#o4~EnN z`;yVtrgdRh(BLuSWcjv)Iy1(Ld!vDB5AQ8*0b3X0c&h=o8^^hA;Q-DVClJE=k6ABK!5OmN%K+xXVIf~P3JB% zKa&t&$|DnbcG#=Jl~{UAP?VCWJ+ z8xHG0?mM-A71zgi>_&N;Ag*V6xS{N5HQM4b#|L8UR5j#t*S1?__R!G^)dS~1&NkFY zeK;bnL3nXH9?)TPsT!E&7rIC!0f0g+aGQj`$qSi^COv`WAbO8_vydu66h-F*j@#Lv z^j;gp=&@?#Os7S=jTefHpSJqVcX#rRS&axd52i0}72z!RXiHk0=qY<@JHVW*o8m{m z)DqRk`Zay1gedXOM<^jE`NJVGW%=U<(4UkljU6~xKfR#8Rc z?&UOKTjx5%%5rCQX!Z2ovH_qjg$@GxlFZfgQOcac(z?5ipETy#u;c9swD@!TBSS!) z{jU}mz<1&pBA9!s^J6o?1uOIUCNHck%}%dv(RB4{3@zC>A#KkfG9w%*_f=V_Bq>_d{}{%x&3KfbVoPlhoo|NVW~0a z_ije4F?MVEEGddWz8ty&nPS7b@L(#TU5q$Gtah}PRb~%u#HQ3*?$ymMbPz#U>!Amc zV=$KY7_Oy50f$<8sLMN>CH|>n7#*2Xsi0Way-7<`PE+D7aInQH#vbZxNaEtEdJTST zFP)%1=h1T2_i$=7r$_^dRb>!8RP8j8^eX+Y$uJ)h-&e!{Tb4CpJ&z&ht5$|%ZqI|D zngyObIvD5J&%pI>hr|S7wY9|_G|6bvY7OdJUz^ta&Y-d%G!SoAXeRnWG(@$hVz+V9 z&>vGUJs5g92>ogKlATM!EbQb3zI4m4Xt*B8iH&bcDcAkAp8LA6=6JW5>DJ1)fbXXS z!bGu{%{~ydMO-L7+(HSvPa(+=6xmQS*k1uq$72>h(q7H*BzzV+wHn^07G$^Ber!+s z4c|;~^n0H4|5vA8{E)A!U2xMy#TlcRE!X~}64Y;|qbu7@sy~dv2WW%}7k&*0g7*(U zM+N3=x!fMPKECtxF2V`G_#k>N9pk>Y9E$X zPf)etNIW{vpO@;O&NCG7IEJ?boL#B)D8~W!Gz4Jk^+)Y9y|NVWJmJ=qojXbDyvLDH z5hnT2+=h|1jSZp})WaD^Syb~D9jgFNZr=3ac=&}A#W$GWtaZ=|hEda0wxo+1cs3aU zGYL_84eqyoo*!!{2(HT@>!zZq?VZ09s+uQSw!G34ZIJ*`3+m%8i_oM-KDZy7;$&aJ zNru+41?9GvTGE5PsZb+W6Ig1|Xty3F83bm=z*6GA=UqX#?sN0`uMJ6h zFc3g(Z*O>W-?wz2Ew*lnB@37x1*DR3mhfB@xr}cY@gH519APR$r~!k}sbKrQgu21yq@@i8 zPQIR`B7q0%Y~9!lj>PG)8*(_vXFUBUBGQ*9B^ovgyBCL?b3=?Yh&P(Rt2RTkZ57KR z^bgnihoeclx-JOEgW)8+RR77H{Fij>f6BDJT+AkDI#mNlvG-#pWSFek)!UsUv;9)y zZIsn5Hf2j&^7fp8oA%d<*pYTU3JMz(MODw7lTU>2 zxJBIlZqjZenF@e94CpJCMK4eZ$kbX7DE+pFnlm^Q^f3@QV>z2aF2$7}MDx^?DUP!v zE`UPx_(d8qCu`56J9eBV|5t>9C_neIzo|p^><#&-@0t^ku7>)76 z8RYP%+%qHgyOX96=U}1k4$YNUe$lVr#}(GM^vCq?W}J(JSG4 zm&QKqb^1m8>gF^2R{;2tZD@$gg$H=^>;~6c*HXSTT>c2pL4F`qS$9@^)%!3=9ZMiZ zI#_-QjpUalS_f4+ZXyL#NPSAie@^FcLi9mgefzar_`yb7M{RTOwLemwLynLiIU5u* zV6=|<`JUnE4&#Rd5h<-ql3@j$=ZJ^jHIYm{DVoc*Lu^B~ zR<~&Ce-?lJC#LAW%h)@n&OAx7-2&AEQ=zMRqJA<$71Rt7L++Nvk=#GU$Cp=FT6esd z)lgc9vP7Yo(K+ZofVsODUJbcgo2@5jVFEU(F1YQ?Y4Mv&fKy5uS6sf_UXr3<8ZcZ( zp2Aci=^8T3ALTqTTG4Mjtq?$r4BOz;zvT!ZuUIW4ph0DR4CMbXqBhXD@e6i>c8%rd zB$@S-u5ey3y5B#!1jC){iR<#hvqt?f!k@$Zg3_Fk3xRkk5BDicM4dit&k|H+LJXAO zLHT##fUTt-hXW%s^PgNSRQ-gFOcMy91=;fem8+e*Q3znUF)P~57bn2Jb%+q=8 zdeE^rFl0k2`q3dpUP>qqXT^PFyc+=jZ&DM-W|$Id8oAn0fwm^ZJx zTrjKhJ8a7WX*pcv0k7VG#eYaMv$frCuu&i0WEoGdY?QV>mfB34 z5$7?2f|c*l7tbH9R`}j|?;pVT3nBZHxC%6|#CG`|eWu=$Q75zP+*yJ8bLTG(UfL6M z-)TJwE>inST(F~Qzv4Jo(z1!yYl6qQ3~ls9N01A5PIzBzSq^}@-Hnr*v96gL$b}}s zVoWP66Th=7X);$e0{OS%(7z>q>k=){zmgexdGn5Y)T&DkpI9Rajl z{3TCOZ>ijBRDe&?juFu!>C_dDX&G4|uL;66$+Pu7u5gA5RbyOU_@8Iai$x`@!h=Cc#4_7t}hwXdDUgKJmCWX4gPQz_JDI*WD%FrRmGuDGB}P zd99*obEzYgWd1!r*E~F%raD16+tzk-7sZaZ#UB< zPq%}Vya?Nm91~$-&_S=~#)x zE6eHkg0F@q1d(UsVVVwyzuo=haT9z%4X(3iPt*H94q$t<42E?@5{PpBtGl#GB_wHJ zQ=8n))K!r*QvoK%^sUBr? z`(7!r#}P#DjPNza_Z6k$GKd+eUp0n8%*XFddf_W1sjg){%cEra9sadEa&I^-JlVCn zgiE=bBidP;uy3kcfh%sCALg$FXexFI__~lPjDe#as6NDKC{re{yvirP-<}KuZc(rW=jSC&)r^H9pC) z9HE`~$$lVI#gJ>4J`<$!u!Anqm z049g={v>TB!fJMi3fGJ}XIH@;`sO%7s^@&L`FZ0My9)XI0NnyG->#~jnBIu<1(IL+ z6rGq~<4Zf_b}EPN4|#hdn#`bPRZ>s|uw<~32Or>NzD|yMo6o*~i{P1S3~4{wx(KMY z_z}|ia8~QT9z9_K92Il8uI{%U`Vz)Ss%_h1ci$UcO<&cIoZn$LFLK~vYz3mO3^?RQ z9wMKwCNRr}q_Q^JU`uLcu2-vyMNSawzq75!d^N9H75mnD7ywl?9o8>yNg4NQP+^C! zQWdv!A$b_i+XZ*AI#v)R%v}q_;AS9^w`r3C9p7iMdBoaW*lk4a1M{W9l(R#N{H}~q z(T6pZcm;0E5;mZ+k|jJem8RooNRKZmu9Oan?%2KAN-czaz}{C5K-x0reOA_g8>f2y z=;g{f&~7LPXMZ(!n0N2eGsw~Q!ME5|!+4ZE!{)MJJeIU&nFf7D;mukhuu-l#$@l(^ z$kN-zppa1c=&f{emWwAoMp*-Ny|X|{u2~R6pn>+RrUYLwE^B*1dPDheB!O`Ihy0R- zPlbe;i>aP;#kTkR+~Qb6kih9?KiVtHRu=DM2kXr9Qo1AhKue$DtHzb`(86&^k~K;Y z1sLL#Jodxp)_U(!+Y*+8oY__NZG|=z5aD+uaN*8pJQvg{hVZR18kq9f67LskhyQ53 z<$21oO(8HdgUzvcMf(tB86pyLZ}#RJh)^9ey9O%~<_XYKp81qY|Esl;zZ{NJn{Kg4 zD&#C@=F1OE4XSD;-(DpEl-&i)ssX+umyioFdwej4MGM84-vttqb3*bX!r)gm4iKR_ zR7-g8H%v$aBLbO)d~Qgc{|+9PRITwda1~fiLO@sl5tbPh&Z1|l&8i03q7M*)Q~MYb0T@w1 z#rTO|(+`K>G`+V;9k>p z^trlgqbQZjIAVyGi9@vN>CWMC>H`{3$?-1Ii~i6!9H(?-TeV$Sy4wq8PSg4B z3TiaW>&Ar$8bk&LS&4F){Bemder}IVP9Ggq#LF#@nukSrxNAeRAiwS=iR#-(rMo6( zXu+!7pyA@zXoUqp{o5BH9_F~d1V?ATwt|zH`Ft4#COJ(KEq592>r8*uGdAX?sF?&?eLs!8Y_?k zR!i!2&*tg20FhOZw_2}Gv?=ROji-F1^v%Cod-CJTS%G*06O;Z(N+jl4#9%}14Bp5b zZ?>~2!aBnn^h~cTT&xmTSqDGjj+N*h0HCylOa^JZR1!NrSmO;{kGu)SP&mrmNK0ee|%+UZWY@txl=G7n|e|C1Ih>08opH zb~PJzUFU`d{(|6`Qc@ACA1ex}f(t&LRj+d*#l8hGE}MK!^;_GJUk=vPz(~$@3p|lR zp>48PLHurj_0aWa5O-W1#giCM2e1bIZ}a0Ip1`Ego>##;Rks|^a`@14Yen8c6#OtB zx!r7!dgrKVd!Yzr=lBdpqCvn| zgbHfso^I854bawx#i&hQN?+D-jK?mUx5&3(-WQUH;o*Bvm$v4$ zZL-2>kuufAc4A-DQKk#1d|wx$|0}22$T1OOIW=-* zwk8vwSEyvMNp)}bisyei+p|Vy^)Qsid8CHVW1(9TYJ`KZXM;|z1P)mF0-L{{_v!gC z?_fTzc4k(F*gIXXSbeE*6V^bAd@Nxi9-APAH5YK{{&V6l-kdkp9VaCD-M|aCiiznH zZ6 z5$PtkAFbLgzAr)~@xNwZ{7(xs{%u>wpQGEWLHLu<{PRzIa4fi4Paz8j+0t zLR>$M(F)rW?^D1Qg(f+o_q65Fqb72#R$L>;`YPLusq)81t3iPn{~{|s@7FahkgN*J z8rF3ZK-ac9pg&~k?2L(&>Ig^Vn$#qVL8X(^R0YUxJWVl~cL9}berB&lVP9AnZiltU zLB28cA|iXS!=z~~K7Yi4#gfj~Q#6OlEe7@gI6@x7xb%TUtYJ+bO0v`9R0bR_bt9j6 zjke7Q-d|znZWSCvvo(|yip@>ZcNvK%OwQ)vWq6UHRU0qtHb)V1i8 zYq||hpk4jHYy_BX!jBlyCe0lg$5fe9VJLkOEk-T5AY>8UN*U2+}om~pD)T&E1& z!S2J=cU@i3d>m~)+&}gdTeX0%|H{TH5G%C}PoS2}21KL)7~8=!O3vOt-nhzf$i|gc znwy!>qSRn;B#5PJYAHt$;4hYz|28ZJMq$lcmVT=W3Z|6=uPeoj<$c%wF-Xm{*w}BjgT_+<+KVC~C>75OVph zvaiPV?Asiaw0TbIK5w^Pp=Q~Aaoc9|HX8(!5mI2_1M|^Mg42Ee=;hDNMPWrx$qcj( z2x?Me_m3uwAMrCv-r8i*7knlFKw&fs{@4=VP7~)n&hCL=`2CccXx4=Oi6D!F zCZPIi#u~(nS|&U3H*p5+gnr(d5<3!nq?5vih!yR%wtv_L4!PNs5d;CcaIBa?< z_G?y)uq6q?B>mRnbv)<0Q=k0v1SuEzHzs(iI%?u(ORrnNviWVZoukAZ2U&n+1yb2<)rqF z!S)ACO1w5>n!j9m``&1bqn_hmD|)OfUgqI`L0&aHH6-5`Mwy@3`W$QZ-f!hK|8ES( zJ0Z4uhcE6wVxWP|^CPx_+{u|7$yue`r(}Rz0r{czleVMSoc>s#zf{1|)amEF3Xg?c;k2>q_4K_xW#YnIH zq!t=nm6H;yYM5|^t+Ic|GpKO#-Mr|tSicRT%$Q1*hD@5whSoa~-<@&>x08gI9a35% z*4RX-V+RsW0hS7oS&c+`OwhcxA;Xa*TF2X1nhM|b!CYB0g|v5Qf-1m>PncP|z|-6j zq>y)p>KVGLek(r!94ic)0jgBilhdAU6z0M6@*VItxg2)U?C#gdQ+@ad8>|v@0@?@d zU01y9AXTC>80);KpKr>L`0NatVpLkLYdIvb+D$kC0xNCp!rA&7OcbKIa}*WcG$RcZzb+-tcpP{R{w36+_E{k3f!zbrd=j~K9F z1E9;ef{g22i@bLyb4ZVETA;f(LL0+B`pF=#ty|Rs1^5~$E+-X%$2V}O9fXNU`*UE2 zP>ae`YMO1Wd!7R!vk}DG{N;L&M4e0}t4Fc44-+ia(|LuP0yV&=Ru7^2M9a)gymI5v z6K?+MAGV|a%PF*9Ny6%Ag()o*fRDztUh6X&L^}lT zL-V>iDqDT*IUSQx{X~Q+zy~`ofiFH_*Ps8^S&%Q()Bwa_YU?6|e&De}Sa`#sFu8!sgRe<^;6ZhL|MOKtsr1%_}6!&dfU7JUoyA)3j}*Go`DFG6THGn%%`PN(5c{qFB;eCG5)6GfM2!_8QEymM&SK@$l^t z4~aGXPON*O_j+JHNm=Y!*LM$OLOr4xtqio0nMM0%+;AGjV!(HF0u*&KPMD)nJ@zzR zLzP)+H7tcWb)E{&)#XU#yS9wz_I%SS*pN&Ld3uhPuO2_hjdLM{W=?w-=_~pkn__L~ z>{_u`fctc&yKYi&%5JfpiM33zJ<+rvHPn zV}9B>e7L#|)d~L9IVZwpDjafI0k`#qcDE7)TBRwq@uu{;L_N6w34^(aLn&RAkFYWf z&|>e+izbmJR-N&)5?b7>eWk-h_o_jl{WGs-#pb251&T3c4RabhsBlR2oEz=9i@wk*n-VlK7?U-Vjnc;Wjv^^OMOKg{AptpAKN0M{p z=6+x+7X6}(#}m#{d=cid(wXw;fkCd&xGwO}-QZreR+n3)wLGW%a+^_E|q=e7{&8E1FcM$81b{Ge?_#Cro8H z(E9%cP_N9(E1RQg^SEzSz-}!gqKHeluTbbji70_ zWr&>q=(eesV43ZRXW|q?wQsx0TEBAPS3Bru#2&u)gTPTVyfZ^qdyknm|LJ&!vy>A@ z^YI%gdO5wd>Jzh^?C{Qt`2ndE%U?)fP;h-2)X-CHPE=^!tBu`eZX1Xv17{j~0h=V@0^0 z5^IAWYVJfRWf~~XarJP;H&vG5n0B~cPHym7S=_4vu=F6&MmMXo^p#zJ$pfi z4DifWsdUE}MLliJ3Y||vI?vqWZ6*jVc~ccSMi4lb6Tzf9A)Tyfp7Es(@#afop-5lp z9Pl)7BJg1Aw2OiX-I6=y=m=_d~aG zvYflT)7eqf!1mAN^F2-n*G&iTS#SB3j<`w2$kWRC(LVc7_39DdG&ufeK#Sv@nLl;} z+xw#*CPl<=NLrea*wiG};_9DgvwU4-W{RQ1sDZvef5RtDd?MQV{ErE+BisL21++uM zu6QW2VbfBp?}ty6LS7d+TiZrVWH7prCT=LCp}v(VD`ELF$*A~;lXSjUWE zF`q;^Ko$3*3qOxDTB=jrZ=EpdhbwXfN@hIQ-{yPg$0Q04(9{iiFO5Ns<8CssPoM56 zB6ln2NwaK+npfP${-Id;fFmz)Ev$mOf&tN>C26~e=7 zL#?@y9(Ft%jfLygBID#|`Kd&K-*f`=huU>rP)yViDts>!=!trsX<30*b-ouRxk+0* zA|lb5o;+Rc=G`ZJA7-$-v~Yz?RsT>NKqR?**N%sIW+rj)maB%}1YfR?e_(M*oFRAHjz@}vj;_WWUlMJnO}J1~IZpaG^M1y0i8QG<*y zx3PSx>7f6eJqf`6?!jhd;wU?ccjj)mR1Nno;8YmAf)mEb+MZ$QG$249YuFZbPCNl) zljCDaNT(Kj8x8|hHDh5-K$ajU$uis()vfaGtf{g;xOu3bHsJCMpS=a5sDa%9;@Jb) z$7Z;nST@*~`2-7YOj<9G-Oc8$WD$`v#NuAt-zR)68c>fcy{apu!xx1Q)xAivtYaX_ zq7Zl1C2VL9Bw~Bpcw3DDMI+q9_nH}0`(e!I6*U zYVTXiFfr$|>%aSbOxVv)={)rbHQF4E6TK4{InVin6uU1LEr!H` zG}_b{ol2Qg8pBjHSdk_1L#>?VG{|KTQM(uD6)T!l`mMUMc|$Af>CA+)+V!rqihy zYkI0UATqlXABl(F%>(O=`d~q&fTC~iM`-j2g4ofPsi}$F{7#770)%2`T8b(5fl>An zfNA?s?l!*wM>TaM*%Ut}Ls4$n%h9z^BC?!juThVk+`{*TL;414?dbjuq$v94K~1*7 z62}+D1iC%a_@z5HQkdAqEG4mum_i-*MfQt{0phg2&xbmtV1S~|c|#sDA0bRr6%1*_ z^OTZ9z0?+`U{BdX#EOd24ys*=LrRIY9=LR%W`?Dw7->dw^OAmx8M%1kqX3Mjq6W1B z*iA4CVa5hSt&32BJyt z-aF$)VqZq|_t+K7u{RK$l`Yq8l@nF2QC?6CO ziHjLvTDS_`uQ>DD@3X@gwodZnz+ybD;n}&HSwa;YFGW`qr3EY}ic@Q7Q9RAV&Ruv8Gih)v^>Z$I z$vZqa6zf#c2DJ%*a= z-=>ug((oFJ${Zs4-0>uUMf(OpUd0i`J!HP|XGV*Tc|Xda18dTYWyM_w0)G1E=c30u z@`Tv(Pdrc2P4peSi9NO+;<(HX12}rwO0rR=QJZ*EsmrHdR&yJdS#)5|0sT&m++nZ$ zQC;nGd|v_(8DqZ{J4vG>!;ZtxV5cDCc?+OOrAyAN|t1qi&zkA!3SX~%<@Z4WC({#yt+1h!qrD6BZPQZWfs5=4?A?y^vb4X<`bJdwEc!i@#*NHMP*ja_!szF`>5{WIu$MV8x=|o zwtQv_tX!O#4i2LrgV)jqg%OWIVu(ZU8NAQ%PC!8iNkc#gf=pk&*9i#3_(xKL~(sNV(P4>Uk#7ZTHq@KH$2B zm!DNnI3$mXOccJWC8<&cc`N&^=*)rH5O!4dqpPy1I@gBr`}xLcGSjEv^zrgI-YQ%0 zY*;*VU-&oY9P=-8iw`BDpRQ7RE2{e54fI4(ZX>+99bV=`BwdIFM*1YoZ%ahtO~D_q z=|=IOux?7!nw-ia3pUV2(QyQiRKMU`HJg^j`Y52xbi z%=96aclKb*Jkc+78H{O3Oqw+j>PTvGvc0J!0-wU@&3Q!AJwc8?_G~?m@koO0Pkwo{ z)%HUVvn8=Z;zMrYkVfW1@KKYGt4NfUr8QTVH-;BdPcdWU)^A$i%;OScv2xo}{eYEf ztb30&u?P9dnrmSx%Gcqk@5uOFWL^(p>edIHSm2J)?ya|Pade!UMTQTREALPLA}#v; z7dHasjU{>+b1b-iwr;6DK<@F$Y5Wgv`e55cJP}?1o-1 zbsOcf=8>Qloxuk@C!!H1J#&;wjO(QskU9#-G+M0zWx+Wi2Z_l=6a~2Y81845o3zq@ z+t8IHJ`T5f&>NOmTT;YUS|ir$p9{;+qlZIS0ZmAjo39}u^8(R$2Be^mCs8E_bR_MJ z)cm?x6%PY*-0SB5|3_5t{|4-82PBZ;x+?Z;NL9ZIaxdma?uh@tsNO<63qe=fvba4S zRhUb6JH7k*N|(Uog5cjR@p^rO=I=IvmDf1=z7Dm?Yba^TWqKx(L95om^HohE?n;e2 z?GV1BjGLr^_IKX^fF=aiv~?sO$ro6MG}c$?_w~dPUya^x^aaKe^j@-MeEiS9K}fFo zw{lEQXC3A0kIt+!MW~pKWJ1gaw4W2WfgbeLM2Pq;>IiWC8{Y^CpGY%+EoL|~!$YBr z59C3&E2`nD;d{o8E@`PjYDQsrPJb(hu=s>5#*4>a$W`jB@Al40?CB!z+I_Tue9*)& V3ArEafJTFa^6EoE{wI_h?O!-)7>WP@ literal 0 HcmV?d00001 diff --git a/utils/frame/remote-externalities/test_data/proxy_test.top b/utils/frame/remote-externalities/test_data/proxy_test.top deleted file mode 100644 index 548ce9cdba4f157e3ff0018d314f3fecfbed9f8f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 39 vcmZQ+kl?)D>{e98_qB(Af%W>u%I&?*zKN<^Se*X}{?*hKULwHEz`y_iDLxHx diff --git a/utils/frame/rpc/client/src/lib.rs b/utils/frame/rpc/client/src/lib.rs index a211fc6c6983e..a6f73ba6784b2 100644 --- a/utils/frame/rpc/client/src/lib.rs +++ b/utils/frame/rpc/client/src/lib.rs @@ -46,6 +46,7 @@ pub use jsonrpsee::{ core::{ client::{ClientT, Subscription, SubscriptionClientT}, params::BatchRequestBuilder, + Error, RpcResult, }, rpc_params, ws_client::{WsClient, WsClientBuilder}, diff --git a/utils/frame/try-runtime/cli/Cargo.toml b/utils/frame/try-runtime/cli/Cargo.toml index 2b095fc9419b9..d6f211392c6cf 100644 --- a/utils/frame/try-runtime/cli/Cargo.toml +++ b/utils/frame/try-runtime/cli/Cargo.toml @@ -12,11 +12,6 @@ description = "Cli command runtime testing and dry-running" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -clap = { version = "4.0.9", features = ["derive"] } -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", 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" } @@ -27,16 +22,27 @@ sp-externalities = { version = "0.13.0", path = "../../../../primitives/external 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-rpc = { version = "6.0.0", path = "../../../../primitives/rpc" } sp-state-machine = { version = "0.13.0", path = "../../../../primitives/state-machine" } sp-version = { version = "5.0.0", path = "../../../../primitives/version" } +sp-debug-derive = { path = "../../../../primitives/debug-derive" } +sp-api = { path = "../../../../primitives/api" } sp-weights = { version = "4.0.0", path = "../../../../primitives/weights" } frame-try-runtime = { optional = true, path = "../../../../frame/try-runtime" } substrate-rpc-client = { path = "../../rpc/client" } +parity-scale-codec = "3.0.0" +hex = "0.4.3" +clap = { version = "4.0.9", features = ["derive"] } +log = "0.4.17" +serde = "1.0.136" +zstd = { version = "0.11.2", default-features = false } + [dev-dependencies] tokio = "1.22.0" [features] try-runtime = [ + "sp-debug-derive/force-debug", "frame-try-runtime/try-runtime", ] diff --git a/utils/frame/try-runtime/cli/src/commands/create_snapshot.rs b/utils/frame/try-runtime/cli/src/commands/create_snapshot.rs new file mode 100644 index 0000000000000..ef39c3d9846ce --- /dev/null +++ b/utils/frame/try-runtime/cli/src/commands/create_snapshot.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. + +use crate::{build_executor, LiveState, SharedParams, State, LOG_TARGET}; +use sc_executor::sp_wasm_interface::HostFunctions; +use sp_runtime::traits::{Block as BlockT, NumberFor}; +use std::{fmt::Debug, str::FromStr}; +use substrate_rpc_client::{ws_client, StateApi}; + +/// Configurations of the [`crate::Command::CreateSnapshot`]. +#[derive(Debug, Clone, clap::Parser)] +pub struct CreateSnapshotCmd { + /// The source of the snapshot. Must be a remote node. + #[clap(flatten)] + pub from: LiveState, + + /// The snapshot path to write to. + /// + /// If not provided `-@.snap` will be used. + pub snapshot_path: Option, +} + +/// inner command for `Command::CreateSnapshot`. +pub(crate) async fn create_snapshot( + shared: SharedParams, + command: CreateSnapshotCmd, +) -> sc_cli::Result<()> +where + Block: BlockT + serde::de::DeserializeOwned, + Block::Hash: FromStr + serde::de::DeserializeOwned, + Block::Header: serde::de::DeserializeOwned, + ::Err: Debug, + NumberFor: FromStr, + as FromStr>::Err: Debug, + HostFns: HostFunctions, +{ + let snapshot_path = command.snapshot_path; + if !matches!(shared.runtime, crate::Runtime::Existing) { + return Err("creating a snapshot is only possible with --runtime existing.".into()) + } + + let path = match snapshot_path { + Some(path) => path, + None => { + let rpc = ws_client(&command.from.uri).await.unwrap(); + let remote_spec = StateApi::::runtime_version(&rpc, None).await.unwrap(); + let path_str = format!( + "{}-{}@{}.snap", + remote_spec.spec_name.to_lowercase(), + remote_spec.spec_version, + command.from.at.clone().unwrap_or("latest".to_owned()) + ); + log::info!(target: LOG_TARGET, "snapshot path not provided (-s), using '{}'", path_str); + path_str.into() + }, + }; + + let executor = build_executor::(&shared); + let _ = State::Live(command.from) + .into_ext::(&shared, &executor, Some(path.into())) + .await?; + + Ok(()) +} 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 56d88b9cb8919..80d34002fa771 100644 --- a/utils/frame/try-runtime/cli/src/commands/execute_block.rs +++ b/utils/frame/try-runtime/cli/src/commands/execute_block.rs @@ -16,30 +16,25 @@ // limitations under the License. use crate::{ - build_executor, ensure_matching_spec, extract_code, full_extensions, hash_of, local_spec, - state_machine_call_with_proof, SharedParams, State, LOG_TARGET, + build_executor, full_extensions, rpc_err_handler, state_machine_call_with_proof, LiveState, + SharedParams, State, LOG_TARGET, }; use parity_scale_codec::Encode; -use sc_service::{Configuration, NativeExecutionDispatch}; -use sp_core::storage::well_known_keys; -use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor}; +use sc_executor::sp_wasm_interface::HostFunctions; +use sp_rpc::{list::ListOrValue, number::NumberOrHex}; +use sp_runtime::{ + generic::SignedBlock, + 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`]. +/// Configurations of the [`crate::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. - #[arg(long)] - overwrite_wasm_code: bool, - - /// If set the state root check is disabled. - #[arg(long)] - no_state_root_check: bool, - /// Which try-state targets to execute when running this command. /// /// Expected values: @@ -49,69 +44,28 @@ 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. - #[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. - #[arg( - long, - value_parser = crate::parse::hash - )] - block_at: Option, + #[arg(long, default_value = "all")] + pub try_state: frame_try_runtime::TryStateSelect, /// 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. + /// This will always fetch the next block of whatever `state` is referring to, because this is + /// the only sensible combination. In other words, if you have the state of block `n`, you + /// should execute block `n+1` on top of it. + /// + /// If `state` is `Live`, this can be ignored and the same uri is used for both. #[arg( long, value_parser = crate::parse::url )] - block_ws_uri: Option, + pub 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. #[command(subcommand)] - state: State, + pub state: State, } impl ExecuteBlockCmd { - async fn block_at(&self, ws_uri: String) -> sc_cli::Result - where - Block::Hash: FromStr + serde::de::DeserializeOwned, - ::Err: Debug, - Block::Header: serde::de::DeserializeOwned, - { - let rpc = ws_client(&ws_uri).await?; - - 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: None, .. }) => { - log::warn!( - target: LOG_TARGET, - "No --block-at or --at provided, using the latest finalized block instead" - ); - 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), - _ => { - 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, @@ -123,7 +77,7 @@ impl ExecuteBlockCmd { 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::Live(LiveState { uri, .. })) => uri.clone(), (None, State::Snap { .. }) => { panic!("either `--block-uri` must be provided, or state must be `live`"); }, @@ -131,10 +85,9 @@ impl ExecuteBlockCmd { } } -pub(crate) async fn execute_block( +pub(crate) async fn execute_block( shared: SharedParams, command: ExecuteBlockCmd, - config: Configuration, ) -> sc_cli::Result<()> where Block: BlockT + serde::de::DeserializeOwned, @@ -142,79 +95,77 @@ where ::Err: Debug, Block::Hash: serde::de::DeserializeOwned, Block::Header: serde::de::DeserializeOwned, - NumberFor: FromStr, - as FromStr>::Err: Debug, - ExecDispatch: NativeExecutionDispatch + 'static, + as TryInto>::Error: Debug, + HostFns: HostFunctions, { - let executor = build_executor::(&shared, &config); - let execution = shared.execution; + let executor = build_executor::(&shared); + let ext = command.state.into_ext::(&shared, &executor, None).await?; + // get the block number associated with this block. let block_ws_uri = command.block_ws_uri::(); - let block_at = command.block_at::(block_ws_uri.clone()).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, - "fetched block #{:?} from {:?}, parent_hash to fetch the state {:?}", - block.header().number(), - 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()) - .state_version(shared.state_version); - - 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 { - builder.inject_hashed_key(well_known_keys::CODE) - }; - - builder.build().await? - }; + let next_hash = next_hash_of::(&rpc, ext.block_hash).await?; + + log::info!(target: LOG_TARGET, "fetching next block: {:?} ", next_hash); + + let block = ChainApi::<(), Block::Hash, Block::Header, SignedBlock>::block( + &rpc, + Some(next_hash), + ) + .await + .map_err(rpc_err_handler)? + .expect("header exists, block should also exist; qed") + .block; // 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 payload = (block.clone(), !command.no_state_root_check, command.try_state).encode(); - - 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_check_panic, - ) - .await; - let _ = state_machine_call_with_proof::( + // for now, hardcoded for the sake of simplicity. We might customize them one day. + let state_root_check = false; + let signature_check = false; + let payload = (block.clone(), state_root_check, signature_check, command.try_state).encode(); + + let _ = state_machine_call_with_proof::( &ext, &executor, - execution, "TryRuntime_execute_block", &payload, full_extensions(), )?; - log::info!(target: LOG_TARGET, "Core_execute_block executed without errors."); - Ok(()) } + +pub(crate) async fn next_hash_of( + rpc: &substrate_rpc_client::WsClient, + hash: Block::Hash, +) -> sc_cli::Result +where + Block: BlockT + serde::de::DeserializeOwned, + Block::Header: serde::de::DeserializeOwned, +{ + let number = ChainApi::<(), Block::Hash, Block::Header, ()>::header(rpc, Some(hash)) + .await + .map_err(rpc_err_handler) + .and_then(|maybe_header| maybe_header.ok_or("header_not_found").map(|h| *h.number()))?; + + let next = number + sp_runtime::traits::One::one(); + + let next_hash = match ChainApi::<(), Block::Hash, Block::Header, ()>::block_hash( + rpc, + Some(ListOrValue::Value(NumberOrHex::Number( + next.try_into().map_err(|_| "failed to convert number to block number")?, + ))), + ) + .await + .map_err(rpc_err_handler)? + { + ListOrValue::Value(t) => t.expect("value passed in; value comes out; qed"), + _ => unreachable!(), + }; + + Ok(next_hash) +} 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 1cc371c8f22fd..4eb3b3a8f35a9 100644 --- a/utils/frame/try-runtime/cli/src/commands/follow_chain.rs +++ b/utils/frame/try-runtime/cli/src/commands/follow_chain.rs @@ -16,32 +16,33 @@ // limitations under the License. use crate::{ - build_executor, ensure_matching_spec, extract_code, full_extensions, local_spec, parse, - state_machine_call_with_proof, SharedParams, LOG_TARGET, + build_executor, full_extensions, parse, rpc_err_handler, state_machine_call_with_proof, + LiveState, SharedParams, State, LOG_TARGET, }; use parity_scale_codec::{Decode, Encode}; -use remote_externalities::{Builder, Mode, OnlineConfig}; -use sc_executor::NativeExecutionDispatch; -use sc_service::Configuration; +use sc_executor::sp_wasm_interface::HostFunctions; use serde::{de::DeserializeOwned, Serialize}; use sp_core::H256; -use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor}; +use sp_runtime::{ + generic::SignedBlock, + traits::{Block as BlockT, Header as HeaderT, NumberFor}, +}; 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"; -/// Configurations of the [`Command::FollowChain`]. +/// Configurations of the [`crate::Command::FollowChain`]. #[derive(Debug, Clone, clap::Parser)] pub struct FollowChainCmd { /// The url to connect to. #[arg(short, long, value_parser = parse::url)] - uri: String, + pub uri: String, /// If set, then the state root check is enabled. #[arg(long)] - state_root_check: bool, + pub state_root_check: bool, /// Which try-state targets to execute when running this command. /// @@ -52,12 +53,12 @@ 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. - #[arg(long, default_value = "none")] - try_state: frame_try_runtime::TryStateSelect, + #[arg(long, default_value = "all")] + pub try_state: frame_try_runtime::TryStateSelect, /// If present, a single connection to a node will be kept and reused for fetching blocks. #[arg(long)] - keep_connection: bool, + pub keep_connection: bool, } /// Start listening for with `SUB` at `url`. @@ -77,10 +78,9 @@ async fn start_subscribing( +pub(crate) async fn follow_chain( shared: SharedParams, command: FollowChainCmd, - config: Configuration, ) -> sc_cli::Result<()> where Block: BlockT + DeserializeOwned, @@ -89,26 +89,35 @@ where ::Err: Debug, NumberFor: FromStr, as FromStr>::Err: Debug, - ExecDispatch: NativeExecutionDispatch + 'static, + HostFns: HostFunctions, { - let mut maybe_state_ext = None; 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 mut finalized_headers: FinalizedHeaders = FinalizedHeaders::new(&rpc, subscription); + let mut maybe_state_ext = None; + let executor = build_executor::(&shared); + while let Some(header) = finalized_headers.next().await { let hash = header.hash(); let number = header.number(); - let block: Block = ChainApi::<(), Block::Hash, Block::Header, _>::block(&rpc, Some(hash)) - .await - .unwrap() - .unwrap(); + let block = + ChainApi::<(), Block::Hash, Block::Header, SignedBlock>::block(&rpc, Some(hash)) + .await + .or_else(|e| { + if matches!(e, substrate_rpc_client::Error::ParseError(_)) { + log::error!( + "failed to parse the block format of remote against the local \ + codebase. The block format has changed, and follow-chain cannot run in \ + this case. Try running this command in a branch of your codebase that has \ + the same block format as the remote chain. For now, we replace the block with an empty one" + ); + } + Err(rpc_err_handler(e)) + })? + .expect("if header exists, block should also exist.") + .block; log::debug!( target: LOG_TARGET, @@ -120,49 +129,40 @@ 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() - })) - .state_version(shared.state_version); - - 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 {:?}", - number, - new_ext.as_backend().root() - ); - - let (expected_spec_name, expected_spec_version, spec_state_version) = - local_spec::(&new_ext, &executor); - ensure_matching_spec::( - command.uri.clone(), - expected_spec_name, - expected_spec_version, - shared.no_spec_check_panic, - ) - .await; - - maybe_state_ext = Some((new_ext, spec_state_version)); + let state = State::Live(LiveState { + uri: command.uri.clone(), + // a bit dodgy, we have to un-parse the has to a string again and re-parse it + // inside. + at: Some(hex::encode(header.parent_hash().encode())), + pallet: vec![], + child_tree: true, + }); + let ext = state.into_ext::(&shared, &executor, None).await?; + maybe_state_ext = Some(ext); } - let (state_ext, spec_state_version) = + 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_with_proof::( + let result = state_machine_call_with_proof::( state_ext, &executor, - execution, "TryRuntime_execute_block", (block, command.state_root_check, command.try_state.clone()).encode().as_ref(), full_extensions(), - )?; + ); + + if let Err(why) = result { + log::error!( + target: LOG_TARGET, + "failed to execute block {:?} due to {:?}", + number, + why + ); + continue + } + + let (mut changes, encoded_result) = result.expect("checked to be Ok; qed"); let consumed_weight = ::decode(&mut &*encoded_result) .map_err(|e| format!("failed to decode weight: {:?}", e))?; @@ -171,13 +171,13 @@ where .drain_storage_changes( &state_ext.backend, &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, + // 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. + state_ext.state_version, ) .unwrap(); + state_ext.backend.apply_transaction( storage_changes.transaction_storage_root, storage_changes.transaction, diff --git a/utils/frame/try-runtime/cli/src/commands/mod.rs b/utils/frame/try-runtime/cli/src/commands/mod.rs index 4861d94f077ce..ab0a066585f6a 100644 --- a/utils/frame/try-runtime/cli/src/commands/mod.rs +++ b/utils/frame/try-runtime/cli/src/commands/mod.rs @@ -15,7 +15,8 @@ // 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; +pub mod create_snapshot; +pub mod execute_block; +pub mod follow_chain; +pub mod offchain_worker; +pub 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 index 8d2585372b4a8..c55de7da64817 100644 --- a/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs +++ b/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs @@ -16,34 +16,18 @@ // 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, + build_executor, commands::execute_block::next_hash_of, full_extensions, parse, rpc_err_handler, + state_machine_call, LiveState, SharedParams, State, LOG_TARGET, }; use parity_scale_codec::Encode; -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 sc_executor::sp_wasm_interface::HostFunctions; +use sp_runtime::traits::{Block as BlockT, NumberFor}; use std::{fmt::Debug, str::FromStr}; use substrate_rpc_client::{ws_client, ChainApi}; -/// Configurations of the [`Command::OffchainWorker`]. +/// Configurations of the [`crate::Command::OffchainWorker`]. #[derive(Debug, Clone, clap::Parser)] pub struct OffchainWorkerCmd { - /// Overwrite the wasm code in state or not. - #[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. - #[arg( - long, - value_parser = 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 @@ -52,7 +36,7 @@ pub struct OffchainWorkerCmd { long, value_parser = parse::url )] - header_ws_uri: Option, + pub header_ws_uri: Option, /// The state type to use. #[command(subcommand)] @@ -60,24 +44,6 @@ pub struct OffchainWorkerCmd { } 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, @@ -89,7 +55,7 @@ impl OffchainWorkerCmd { 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::Live(LiveState { uri, .. })) => uri.clone(), (None, State::Snap { .. }) => { panic!("either `--header-uri` must be provided, or state must be `live`"); }, @@ -97,76 +63,42 @@ impl OffchainWorkerCmd { } } -pub(crate) async fn offchain_worker( +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, + Block::Hash: FromStr, ::Err: Debug, NumberFor: FromStr, as FromStr>::Err: Debug, - ExecDispatch: NativeExecutionDispatch + 'static, + HostFns: HostFunctions, { - let executor = build_executor(&shared, &config); - let execution = shared.execution; + let executor = build_executor(&shared); + // we first build the externalities with the remote code. + let ext = command.state.into_ext::(&shared, &executor, None).await?; - let header_at = command.header_at::()?; let header_ws_uri = command.header_ws_uri::(); 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: {:?}", - header_ws_uri, - header.number() - ); - - let ext = { - let builder = command.state.builder::()?.state_version(shared.state_version); - - 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 { - builder.inject_hashed_key(well_known_keys::CODE) - }; + let next_hash = next_hash_of::(&rpc, ext.block_hash).await?; + log::info!(target: LOG_TARGET, "fetching next header: {:?} ", next_hash); - 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_check_panic, - ) - .await; + let header = ChainApi::<(), Block::Hash, Block::Header, ()>::header(&rpc, Some(next_hash)) + .await + .map_err(rpc_err_handler) + .map(|maybe_header| maybe_header.ok_or("Header does not exist"))??; + let payload = header.encode(); - let _ = state_machine_call::( + let _ = state_machine_call::( &ext, &executor, - execution, "OffchainWorkerApi_offchain_worker", - header.encode().as_ref(), + &payload, 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 index fba34ddfb5060..80fb5d31f71a9 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 @@ -15,31 +15,31 @@ // 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 crate::{build_executor, state_machine_call_with_proof, SharedParams, State, LOG_TARGET}; +use parity_scale_codec::{Decode, Encode}; +use sc_executor::sp_wasm_interface::HostFunctions; use sp_runtime::traits::{Block as BlockT, NumberFor}; use sp_weights::Weight; +use std::{fmt::Debug, str::FromStr}; -use crate::{ - build_executor, ensure_matching_spec, extract_code, local_spec, state_machine_call_with_proof, - SharedParams, State, LOG_TARGET, -}; - -/// Configurations of the [`Command::OnRuntimeUpgrade`]. +/// Configurations of the [`crate::Command::OnRuntimeUpgrade`]. #[derive(Debug, Clone, clap::Parser)] pub struct OnRuntimeUpgradeCmd { /// The state type to use. #[command(subcommand)] pub state: State, + + /// Execute `try_state`, `pre_upgrade` and `post_upgrade` checks as well. + /// + /// This will perform more checks, but it will also makes the reported PoV/Weight be + /// inaccurate. + #[clap(long)] + pub checks: bool, } -pub(crate) async fn on_runtime_upgrade( +pub(crate) async fn on_runtime_upgrade( shared: SharedParams, command: OnRuntimeUpgradeCmd, - config: Configuration, ) -> sc_cli::Result<()> where Block: BlockT + serde::de::DeserializeOwned, @@ -48,40 +48,22 @@ where Block::Header: serde::de::DeserializeOwned, NumberFor: FromStr, as FromStr>::Err: Debug, - ExecDispatch: NativeExecutionDispatch + 'static, + HostFns: HostFunctions, { - let executor = build_executor(&shared, &config); - let execution = shared.execution; - - let ext = { - 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? - }; + let executor = build_executor(&shared); + let ext = command.state.into_ext::(&shared, &executor, None).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_check_panic, - ) - .await; - } - - let (_, encoded_result) = state_machine_call_with_proof::( + let (_, encoded_result) = state_machine_call_with_proof::( &ext, &executor, - execution, "TryRuntime_on_runtime_upgrade", - &[], + command.checks.encode().as_ref(), Default::default(), // we don't really need any extensions here. )?; 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 = ({} ps, {} byte), total weight = ({} ps, {} byte) ({:.2} %, {:.2} %).", diff --git a/utils/frame/try-runtime/cli/src/lib.rs b/utils/frame/try-runtime/cli/src/lib.rs index f54354342bf28..47a9dfa3f6544 100644 --- a/utils/frame/try-runtime/cli/src/lib.rs +++ b/utils/frame/try-runtime/cli/src/lib.rs @@ -22,7 +22,7 @@ //! > 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 +//! to deeply understand how the wasm/client/runtime interactions, and the runtime apis work in the //! substrate runtime, before commencing to working with `try-runtime`. //! //! #### Resources @@ -35,101 +35,102 @@ //! //! --- //! -//! ## Overview +//! ## Background Knowledge //! //! 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*. //! +//! Alternatively, the state could come from a snapshot file. +//! //! 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. +//! related to some pallets/prefixes). Moreover, some keys are especial 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. +//! runtime-api. Everything in this crate assumes wasm execution, which means the runtime that +//! you use is the one stored onchain, namely under the `:CODE:` key. +//! +//! To recap, a typical try-runtime command does the following: +//! +//! 1. Download the state of a live chain, and write to an `externalities`. +//! 2. Overwrite the `:CODE:` with a given wasm blob +//! 3. Test some functionality via calling a runtime-api. +//! +//! ## Usage +//! +//! To use any of the provided commands, [`SharedParams`] must be provided. The most important of +//! which being [`SharedParams::runtime`], which specifies which runtime to use. Furthermore, +//! [`SharedParams::overwrite_state_version`] can be used to alter the state-version (see +//! for more info). +//! +//! Then, the specific command has to be specified. See [`Command`] for more information about each +//! command's specific customization flags, and assumptions regarding the runtime being used. +//! +//! Said briefly, this CLI is capable of executing: +//! +//! * [`Command::OnRuntimeUpgrade`]: execute all the `on_runtime_upgrade` hooks. +//! * [`Command::ExecuteBlock`]: re-execute the given block. +//! * [`Command::OffchainWorker`]: re-execute the given block's offchain worker code path. +//! * [`Command::FollowChain`]: continuously execute the blocks of a remote chain on top of a given +//! runtime. +//! * [`Command::CreateSnapshot`]: Create a snapshot file from a remote node. //! //! 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`. +//! call. Moreover, `remote-ext`, `try-runtime` and `runtime` logs targets will also be useful. //! //! ## 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. +//! anything by default. This will check the, if any alterations are being made to the `:CODE:`, +//! then the spec names match. The spec versions are warned, but are not mandated to match. //! -//! Should you need to disable this on certain occasions, a top level flag of `--no-spec-name-check` -//! can be used. +//! > If anything, in most cases, we expect spec-versions to NOT match, because try-runtime is all +//! > about testing unreleased runtimes. //! -//! 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` +//! ## Note on nodes that respond to `try-runtime` requests. //! //! 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 `--ws-max-out-buffer-capacity 1000` to ensure the websocket connection can handle large -//! RPC queries. +//! - set `--rpc-max-response-size 1000` and +//! - `--rpc-max-request-size 1000` to ensure connections are not dropped in case the state is +//! large. //! - set `--rpc-cors all` to ensure ws connections can come through. //! //! Note that *none* of the try-runtime operations need unsafe RPCs. //! -//! ## Migration Best Practices +//! ## Note on signature and state-root checks +//! +//! All of the commands calling into `TryRuntime_execute_block` ([`Command::ExecuteBlock`] and +//! [`Command::FollowChain`]) disable both state root and signature checks. This is because in 99% +//! of the cases, the runtime that is being tested is different from the one that is stored in the +//! canonical chain state. This implies: +//! +//! 1. the state root will NEVER match, because `:CODE:` is different between the two. +//! 2. replaying all transactions will fail, because the spec-version is part of the transaction +//! signature. +//! +//! ## 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. +//! Try-runtime is all about battle-testing unreleased runtime. The following list of suggestions +//! help developers maximize the testing coverage and make base use of `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: +//! `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 //! @@ -147,6 +148,19 @@ //! encoded data (usually some pre-upgrade state) which will be passed to `post_upgrade` after //! upgrading and used for post checking. //! +//! ## State Consistency +//! +//! Similarly, each pallet can expose a function in `#[pallet::hooks]` section as follows: +//! +//! ``` +//! #[cfg(feature = try-runtime)] +//! fn try_state(_) -> Result<(), &'static str> {} +//! ``` +//! +//! which is called on numerous code paths in the try-runtime tool. These checks should ensure that +//! the state of the pallet is consistent and correct. See `frame_support::try_runtime::TryState` +//! for more info. +//! //! #### Logging //! //! It is super helpful to make sure your migration code uses logging (always with a `runtime` log @@ -161,216 +175,260 @@ //! //! ## 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 +//! For the following examples, we assume the existence of the following: //! -//! ```sh -//! 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. +//! 1. a substrate node compiled without `--feature try-runtime`, called `substrate`. This will be +//! the running node that you connect to. then, after some changes to this node, you compile it with +//! `--features try-runtime`. This gives you: +//! 2. a substrate binary that has the try-runtime sub-command enabled. +//! 3. a wasm blob that has try-runtime functionality. +//! +//! ```bash +//! # this is like your running deployed node. +//! cargo build --release && cp target/release/substrate . +//! +//! # this is like your WIP branch. +//! cargo build --release --features try-runtime +//! cp target/release/substrate substrate-try-runtime +//! cp ./target/release/wbuild/kitchensink-runtime/kitchensink_runtime.wasm runtime-try-runtime.wasm //! ``` //! -//! 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. +//! > The above example is with `substrate`'s `kitchensink-runtime`, but is applicable to any +//! > substrate-based chain that has implemented `try-runtime-cli`. +//! +//! * If you run `try-runtime` subcommand against `substrate` binary listed above, you get the +//! following error. +//! +//! ```bash +//! [substrate] ./substrate try-runtime +//! Error: Input("TryRuntime wasn't enabled when building the node. You can enable it with `--features try-runtime`.") +//! ``` //! -//! ```sh -//! 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! +//! * If you run the same against `substrate-try-runtime`, it will work. +//! +//! ```bash +//! [substrate] ./substrate-try-runtime try-runtime +//! Try some command against runtime state +//! +//! Usage: substrate-try-runtime try-runtime [OPTIONS] --runtime +//! +//! Commands: +//! on-runtime-upgrade Execute the migrations of the "local runtime" +//! execute-block Executes the given block against some state +//! offchain-worker Executes *the offchain worker hooks* of a given block against some state +//! follow-chain Follow the given chain's finalized blocks and apply all of its extrinsics +//! create-snapshot Create a new snapshot file +//! help Print this message or the help of the given subcommand(s) +//! +//! Options: +//! --chain +//! Specify the chain specification +//! --dev +//! Specify the development chain +//! -d, --base-path +//! Specify custom base path +//! -l, --log ... +//! Sets a custom logging filter. Syntax is `=`, e.g. -lsync=debug +//! --detailed-log-output +//! Enable detailed log output +//! --disable-log-color +//! Disable log color output +//! --enable-log-reloading +//! Enable feature to dynamically update and reload the log filter +//! --tracing-targets +//! Sets a custom profiling filter. Syntax is the same as for logging: `=` +//! --tracing-receiver +//! Receiver to process tracing messages [default: log] [possible values: log] +//! --runtime +//! The runtime to use +//! --wasm-execution +//! Type of wasm execution used [default: compiled] [possible values: interpreted-i-know-what-i-do, compiled] +//! --wasm-instantiation-strategy +//! The WASM instantiation method to use [default: pooling-copy-on-write] [possible values: pooling-copy-on-write, recreate-instance-copy-on-write, pooling, recreate-instance, legacy-instance-reuse] +//! --heap-pages +//! The number of 64KB pages to allocate for Wasm execution. Defaults to [`sc_service::Configuration.default_heap_pages`] +//! --overwrite-state-version +//! Overwrite the `state_version` +//! -h, --help +//! Print help information (use `--help` for more detail) +//! -V, --version +//! Print version information +//! ``` +//! +//! * Run the migrations of a given runtime on top of a live state. +//! +//! ```bash +//! # assuming there's `./substrate --dev --tmp --ws-port 9999` or similar running. +//! ./substrate-try-runtime \ +//! try-runtime \ +//! --runtime kitchensink_runtime.wasm \ +//! -lruntime=debug \ //! on-runtime-upgrade \ -//! live \ -//! --uri wss://rpc.polkadot.io +//! live --uri ws://localhost:9999 //! ``` //! -//! Same as the previous one, but run it at specific block number's state. This means that this +//! * 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`. //! -//! ```sh -//! 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 \ +//! ```bash +//! ./substrate-try-runtime \ +//! try-runtime \ +//! --runtime kitchensink_runtime.wasm \ +//! -lruntime=debug \ //! on-runtime-upgrade \ -//! live \ -//! --uri wss://rpc.polkadot.io \ -//! --at +//! live --uri ws://localhost:9999 \ +//! # replace with your desired block hash! +//! --at 0xa1b16c1efd889a9f17375ec4dd5c1b4351a2be17fa069564fced10d23b9b3836 //! ``` //! -//! 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. -//! -//! ```sh -//! 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 +//! * Executing the same command with the [`Runtime::Existing`] will fail because the existing +//! runtime, stored onchain in `substrate` binary that we compiled earlier does not have +//! `try-runtime` feature! +//! +//! ```bash +//! ./substrate-try-runtime try-runtime --runtime existing -lruntime=debug on-runtime-upgrade live --uri ws://localhost:9999 +//! ... +//! Error: Input("given runtime is NOT compiled with try-runtime feature!") //! ``` //! -//! 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: +//! * Now, let's use a snapshot file. First, we create the snapshot: //! -//! ```text -//! Request for native execution succeeded (native: polkadot-9900 (parity-polkadot-0.tx7.au0), chain: polkadot-9900 (parity-polkadot-0.tx7.au0)) +//! ```bash +//! ./substrate-try-runtime try-runtime --runtime existing -lruntime=debug create-snapshot --uri ws://localhost:9999 +//! 2022-12-13 10:28:17.516 INFO main try-runtime::cli: snapshot path not provided (-s), using 'node-268@latest.snap' +//! 2022-12-13 10:28:17.516 INFO main remote-ext: since no at is provided, setting it to latest finalized head, 0xe7d0b614dfe89af65b33577aae46a6f958c974bf52f8a5e865a0f4faeb578d22 +//! 2022-12-13 10:28:17.516 INFO main remote-ext: since no prefix is filtered, the data for all pallets will be downloaded +//! 2022-12-13 10:28:17.550 INFO main remote-ext: writing snapshot of 1611464 bytes to "node-268@latest.snap" +//! 2022-12-13 10:28:17.551 INFO main remote-ext: initialized state externalities with storage root 0x925e4e95de4c08474fb7f976c4472fa9b8a1091619cd7820a793bf796ee6d932 and state_version V1 //! ``` //! -//! 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: -//! -//! ```sh -//! 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 +//! > Note that the snapshot contains the `existing` runtime, which does not have the correct +//! > `try-runtime` feature. In the following commands, we still need to overwrite the runtime. +//! +//! Then, we can use it to have the same command as before, `on-runtime-upgrade` +//! +//! ```bash +//! try-runtime \ +//! --runtime runtime-try-runtime.wasm \ +//! -lruntime=debug \ +//! on-runtime-upgrade \ +//! snap -s node-268@latest.snap //! ``` //! -//! 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: -//! -//! ```sh -//! 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 \ +//! * Execute the latest finalized block with the given runtime. +//! +//! ```bash +//! ./substrate-try-runtime try-runtime \ +//! --runtime runtime-try-runtime.wasm \ +//! -lruntime=debug \ +//! execute-block live \ +//! --uri ws://localhost:999 +//! ``` +//! +//! This can still be customized at a given block with `--at`. If you want to use a snapshot, you +//! can still use `--block-ws-uri` to provide a node form which the block data can be fetched. +//! +//! Moreover, this runs the `frame_support::try_runtime::TryState` hooks as well. The hooks to run +//! can be customized with the `--try-state`. For example: +//! +//! ```bash +//! ./substrate-try-runtime try-runtime \ +//! --runtime runtime-try-runtime.wasm \ +//! -lruntime=debug \ +//! execute-block live \ +//! --try-state System,Staking \ +//! --uri ws://localhost:999 +//! ``` +//! +//! Will only run the `try-state` of the two given pallets. See +//! [`frame_try_runtime::TryStateSelect`] for more information. +//! +//! * Follow our live chain's blocks using `follow-chain`, whilst running the try-state of 3 pallets +//! in a round robin fashion +//! +//! ```bash +//! ./substrate-try-runtime \ +//! try-runtime \ +//! --runtime runtime-try-runtime.wasm \ +//! -lruntime=debug \ +//! follow-chain \ +//! --uri ws://localhost:9999 \ +//! --try-state rr-3 //! ``` #![cfg(feature = "try-runtime")] use parity_scale_codec::Decode; use remote_externalities::{ - Builder, Mode, OfflineConfig, OnlineConfig, SnapshotConfig, TestExternalities, + Builder, Mode, OfflineConfig, OnlineConfig, RemoteExternalities, SnapshotConfig, + TestExternalities, }; -use sc_chain_spec::ChainSpec; use sc_cli::{ - execution_method_from_cli, CliConfiguration, ExecutionStrategy, WasmExecutionMethod, - WasmtimeInstantiationStrategy, DEFAULT_WASMTIME_INSTANTIATION_STRATEGY, - DEFAULT_WASM_EXECUTION_METHOD, + CliConfiguration, RuntimeVersion, WasmExecutionMethod, WasmtimeInstantiationStrategy, + DEFAULT_WASMTIME_INSTANTIATION_STRATEGY, DEFAULT_WASM_EXECUTION_METHOD, }; -use sc_executor::NativeElseWasmExecutor; -use sc_service::{Configuration, NativeExecutionDispatch}; +use sc_executor::{sp_wasm_interface::HostFunctions, WasmExecutor}; +use sp_api::HashT; use sp_core::{ + hexdisplay::HexDisplay, offchain::{ testing::{TestOffchainExt, TestTransactionPoolExt}, OffchainDbExt, OffchainWorkerExt, TransactionPoolExt, }, - storage::{well_known_keys, StorageData, StorageKey}, + storage::well_known_keys, testing::TaskExecutor, - traits::TaskExecutorExt, + traits::{ReadRuntimeVersion, TaskExecutorExt}, twox_128, H256, }; use sp_externalities::Extensions; use sp_keystore::{testing::KeyStore, KeystoreExt}; use sp_runtime::{ - traits::{Block as BlockT, NumberFor}, + traits::{BlakeTwo256, Block as BlockT, NumberFor}, DeserializeOwned, }; -use sp_state_machine::{OverlayedChanges, StateMachine, TrieBackendBuilder}; +use sp_state_machine::{CompactProof, 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 mod commands; pub(crate) mod parse; pub(crate) const LOG_TARGET: &str = "try-runtime::cli"; /// Possible commands of `try-runtime`. #[derive(Debug, Clone, clap::Subcommand)] pub enum Command { - /// Execute the migrations of the "local runtime". + /// Execute the migrations of the given runtime /// - /// This uses a custom runtime api call, namely "TryRuntime_on_runtime_upgrade". + /// This uses a custom runtime api call, namely "TryRuntime_on_runtime_upgrade". The code path + /// only triggers all of the `on_runtime_upgrade` hooks in the runtime, and optionally + /// `try_state`. /// - /// 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. + /// See [`frame_try_runtime::TryRuntime`] and + /// [`commands::on_runtime_upgrade::OnRuntimeUpgradeCmd`] for more information. 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`. + /// This uses a custom runtime api call, namely "TryRuntime_execute_block". Some checks, such + /// as state-root and signature checks are always disabled, and additional checks like + /// `try-state` can be enabled. /// - /// 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 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. + /// See [`frame_try_runtime::TryRuntime`] and [`commands::execute_block::ExecuteBlockCmd`] for + /// more information. 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`. + /// + /// See [`frame_try_runtime::TryRuntime`] and [`commands::offchain_worker::OffchainWorkerCmd`] + /// for more information. 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 is essentially repeated calls to [`Command::ExecuteBlock`]. /// /// This allows the behavior of a new runtime to be inspected over a long period of time, with /// realistic transactions coming as input. @@ -382,7 +440,38 @@ pub enum Command { /// 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. + /// + /// This can only work if the block format between the remote chain and the new runtime being + /// tested has remained the same, otherwise block decoding might fail. FollowChain(commands::follow_chain::FollowChainCmd), + + /// Create a new snapshot file. + CreateSnapshot(commands::create_snapshot::CreateSnapshotCmd), +} + +#[derive(Debug, Clone)] +pub enum Runtime { + /// Use the given path to the wasm binary file. + /// + /// It must have been compiled with `try-runtime`. + Path(PathBuf), + + /// Use the code of the remote node, or the snapshot. + /// + /// In almost all cases, this is not what you want, because the code in the remote node does + /// not have any of the try-runtime custom runtime APIs. + Existing, +} + +impl FromStr for Runtime { + type Err = String; + + fn from_str(s: &str) -> Result { + Ok(match s.to_lowercase().as_ref() { + "existing" => Runtime::Existing, + x @ _ => Runtime::Path(x.into()), + }) + } } /// Shared parameters of the `try-runtime` commands @@ -390,13 +479,23 @@ pub enum Command { #[group(skip)] pub struct SharedParams { /// Shared parameters of substrate cli. + /// + /// TODO: this is only needed because try-runtime is embedded in the substrate CLI. It should + /// go away. #[allow(missing_docs)] #[clap(flatten)] pub shared_params: sc_cli::SharedParams, - /// The execution strategy that should be used. - #[arg(long, value_name = "STRATEGY", value_enum, ignore_case = true, default_value_t = ExecutionStrategy::Wasm)] - pub execution: ExecutionStrategy, + /// The runtime to use. + /// + /// Must be a path to a wasm blob, compiled with `try-runtime` feature flag. + /// + /// Or, `existing`, indicating that you don't want to overwrite the runtime. This will use + /// whatever comes from the remote node, or the snapshot file. This will most likely not work + /// against a remote node, as no (sane) blockchain should compile its onchain wasm with + /// `try-runtime` feature. + #[arg(long)] + pub runtime: Runtime, /// Type of wasm execution used. #[arg( @@ -424,13 +523,11 @@ pub struct SharedParams { #[arg(long)] pub heap_pages: Option, - /// When enabled, the spec check will not panic, and instead only show a warning. - #[arg(long)] - pub no_spec_check_panic: bool, - - /// State version that is used by the chain. - #[arg(long, default_value_t = StateVersion::V1, value_parser = parse::state_version)] - pub state_version: StateVersion, + /// Overwrite the `state_version`. + /// + /// Otherwise `remote-externalities` will automatically set the correct state version. + #[arg(long, value_parser = parse::state_version)] + pub overwrite_state_version: Option, } /// Our `try-runtime` command. @@ -445,6 +542,41 @@ pub struct TryRuntimeCmd { pub command: Command, } +/// A `Live` variant [`State`] +#[derive(Debug, Clone, clap::Args)] +pub struct LiveState { + /// The url to connect to. + #[arg( + short, + long, + value_parser = parse::url, + )] + uri: String, + + /// The block hash at which to fetch the state. + /// + /// If non provided, then the latest finalized head is used. + #[arg( + short, + long, + value_parser = parse::hash, + )] + at: Option, + + /// A pallet to scrape. Can be provided multiple times. If empty, entire chain state will + /// be scraped. + #[arg(short, long, num_args = 1..)] + pallet: Vec, + + /// 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. + #[arg(long)] + child_tree: bool, +} + /// The source of runtime *state* to use. #[derive(Debug, Clone, clap::Subcommand)] pub enum State { @@ -457,128 +589,167 @@ pub enum State { }, /// Use a live chain as the source of runtime state. - Live { - /// The url to connect to. - #[arg( - short, - long, - value_parser = 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`]. - #[arg( - short, - long, - value_parser = parse::hash, - )] - at: Option, - - /// An optional state snapshot file to WRITE to. Not written if set to `None`. - #[arg(short, long)] - snapshot_path: Option, - - /// A pallet to scrape. Can be provided multiple times. If empty, entire chain state will - /// be scraped. - #[arg(short, long, num_args = 1..)] - pallet: Vec, - - /// 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. - #[arg(long)] - child_tree: bool, - }, + Live(LiveState), } impl State { - /// Create the [`remote_externalities::Builder`] from self. - pub(crate) fn builder(&self) -> sc_cli::Result> + /// Create the [`remote_externalities::RemoteExternalities`] using [`remote-externalities`] from + /// self. + /// + /// This will override the code as it sees fit based on [`SharedParams::Runtime`]. It will also + /// check the spec-version and name. + pub(crate) async fn into_ext( + &self, + shared: &SharedParams, + executor: &WasmExecutor, + state_snapshot: Option, + ) -> sc_cli::Result> where Block::Hash: FromStr, + Block::Header: DeserializeOwned, + Block::Hash: DeserializeOwned, ::Err: Debug, { - Ok(match self { + let builder = match self { State::Snap { snapshot_path } => Builder::::new().mode(Mode::Offline(OfflineConfig { state_snapshot: SnapshotConfig::new(snapshot_path), })), - State::Live { snapshot_path, pallet, uri, at, child_tree } => { + State::Live(LiveState { pallet, uri, at, child_tree }) => { let at = match at { Some(at_str) => Some(hash_of::(at_str)?), None => None, }; - let mut builder = Builder::::new() - .mode(Mode::Online(OnlineConfig { - transport: uri.to_owned().into(), - state_snapshot: snapshot_path.as_ref().map(SnapshotConfig::new), - pallets: pallet.clone(), - scrape_children: true, - at, - })) - .inject_hashed_key( - &[twox_128(b"System"), twox_128(b"LastRuntimeUpgrade")].concat(), - ); - if *child_tree { - builder = builder.inject_default_child_tree_prefix(); - } - builder + Builder::::new().mode(Mode::Online(OnlineConfig { + at, + transport: uri.to_owned().into(), + state_snapshot, + pallets: pallet.clone(), + child_trie: *child_tree, + hashed_keys: vec![ + // we always download the code, but we almost always won't use it, based on + // `Runtime`. + well_known_keys::CODE.to_vec(), + // we will always download this key, since it helps detect if we should do + // runtime migration or not. + [twox_128(b"System"), twox_128(b"LastRuntimeUpgrade")].concat(), + [twox_128(b"System"), twox_128(b"Number")].concat(), + ], + hashed_prefixes: vec![], + })) }, - }) - } + }; + + // possibly overwrite the state version, should hardly be needed. + let builder = if let Some(state_version) = shared.overwrite_state_version { + log::warn!( + target: LOG_TARGET, + "overwriting state version to {:?}, you better know what you are doing.", + state_version + ); + builder.overwrite_state_version(state_version) + } else { + builder + }; + + // then, we prepare to replace the code based on what the CLI wishes. + let maybe_code_to_overwrite = match shared.runtime { + Runtime::Path(ref path) => Some(std::fs::read(path).map_err(|e| { + format!("error while reading runtime file from {:?}: {:?}", path, e) + })?), + Runtime::Existing => None, + }; + + // build the main ext. + let mut ext = builder.build().await?; + + // actually replace the code if needed. + if let Some(new_code) = maybe_code_to_overwrite { + let original_code = ext + .execute_with(|| sp_io::storage::get(well_known_keys::CODE)) + .expect("':CODE:' is always downloaded in try-runtime-cli; qed"); + + // NOTE: see the impl notes of `read_runtime_version`, the ext is almost not used here, + // only as a backup. + ext.insert(well_known_keys::CODE.to_vec(), new_code.clone()); + let old_version = ::decode( + &mut &*executor.read_runtime_version(&original_code, &mut ext.ext()).unwrap(), + ) + .unwrap(); + log::info!( + target: LOG_TARGET, + "original spec: {:?}-{:?}, code hash: {:?}", + old_version.spec_name, + old_version.spec_version, + HexDisplay::from(BlakeTwo256::hash(&original_code).as_fixed_bytes()), + ); + let new_version = ::decode( + &mut &*executor.read_runtime_version(&new_code, &mut ext.ext()).unwrap(), + ) + .unwrap(); + log::info!( + target: LOG_TARGET, + "new spec: {:?}-{:?}, code hash: {:?}", + new_version.spec_name, + new_version.spec_version, + HexDisplay::from(BlakeTwo256::hash(&new_code).as_fixed_bytes()) + ); - /// Get the uri, if self is `Live`. - pub(crate) fn live_uri(&self) -> Option { - match self { - State::Live { uri, .. } => Some(uri.clone()), - _ => None, + if new_version.spec_name != old_version.spec_name { + return Err("Spec names must match.".into()) + } + } + + // whatever runtime we have in store now must have been compiled with try-runtime feature. + if !ensure_try_runtime::(&executor, &mut ext) { + return Err("given runtime is NOT compiled with try-runtime feature!".into()) } + + Ok(ext) } } impl TryRuntimeCmd { - pub async fn run(&self, config: Configuration) -> sc_cli::Result<()> + pub async fn run(&self) -> sc_cli::Result<()> where Block: BlockT + DeserializeOwned, Block::Header: DeserializeOwned, Block::Hash: FromStr, ::Err: Debug, - NumberFor: FromStr, as FromStr>::Err: Debug, - ExecDispatch: NativeExecutionDispatch + 'static, + as TryInto>::Error: Debug, + NumberFor: FromStr, + HostFns: HostFunctions, { match &self.command { Command::OnRuntimeUpgrade(ref cmd) => - commands::on_runtime_upgrade::on_runtime_upgrade::( + commands::on_runtime_upgrade::on_runtime_upgrade::( self.shared.clone(), cmd.clone(), - config, ) .await, Command::OffchainWorker(cmd) => - commands::offchain_worker::offchain_worker::( + commands::offchain_worker::offchain_worker::( self.shared.clone(), cmd.clone(), - config, ) .await, Command::ExecuteBlock(cmd) => - commands::execute_block::execute_block::( + commands::execute_block::execute_block::( self.shared.clone(), cmd.clone(), - config, ) .await, Command::FollowChain(cmd) => - commands::follow_chain::follow_chain::( + commands::follow_chain::follow_chain::( + self.shared.clone(), + cmd.clone(), + ) + .await, + Command::CreateSnapshot(cmd) => + commands::create_snapshot::create_snapshot::( self.shared.clone(), cmd.clone(), - config, ) .await, } @@ -598,22 +769,6 @@ impl CliConfiguration for TryRuntimeCmd { } } -/// Extract `:code` from the given chain spec and return as `StorageData` along with the -/// corresponding `StorageKey`. -pub(crate) fn extract_code(spec: &Box) -> sc_cli::Result<(StorageKey, StorageData)> { - let genesis_storage = spec.build_storage()?; - let code = StorageData( - genesis_storage - .top - .get(well_known_keys::CODE) - .expect("code key must exist in genesis storage; qed") - .to_vec(), - ); - let code_key = StorageKey(well_known_keys::CODE.to_vec()); - - 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 @@ -625,67 +780,6 @@ where .map_err(|e| format!("Could not parse block hash: {:?}", e).into()) } -/// Check the spec_name of an `ext` -/// -/// 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 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)) - { - Ok((name, version)) => { - // first, deal with spec name - if expected_spec_name.to_lowercase() == 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 { - let msg = format!( - "spec version mismatch (local {} != remote {}). This could cause some issues.", - expected_spec_version, version - ); - if relaxed { - log::warn!(target: LOG_TARGET, "{}", msg); - } else { - panic!("{}", msg); - } - } - }, - Err(why) => { - let msg = format!( - "failed to fetch runtime version from {}: {:?}. Skipping the check", - uri, why - ); - if relaxed { - log::error!(target: LOG_TARGET, "{}", msg); - } else { - panic!("{}", msg); - } - }, - } -} - /// Build all extensions that we typically use. pub(crate) fn full_extensions() -> Extensions { let mut extensions = Extensions::default(); @@ -700,29 +794,43 @@ pub(crate) fn full_extensions() -> Extensions { extensions } -/// Build a default execution that we typically use. -pub(crate) fn build_executor( - shared: &SharedParams, - config: &sc_service::Configuration, -) -> NativeElseWasmExecutor { - 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( - execution_method_from_cli(shared.wasm_method, shared.wasmtime_instantiation_strategy), +pub(crate) fn build_executor(shared: &SharedParams) -> WasmExecutor { + let heap_pages = shared.heap_pages.or(Some(2048)); + let max_runtime_instances = 8; + let runtime_cache_size = 2; + + WasmExecutor::new( + sc_executor::WasmExecutionMethod::Interpreted, heap_pages, max_runtime_instances, + None, runtime_cache_size, ) } +/// Ensure that the given `ext` is compiled with `try-runtime` +fn ensure_try_runtime( + executor: &WasmExecutor, + ext: &mut TestExternalities, +) -> bool { + use sp_api::RuntimeApiInfo; + let final_code = ext + .execute_with(|| sp_io::storage::get(well_known_keys::CODE)) + .expect("':CODE:' is always downloaded in try-runtime-cli; qed"); + let final_version = ::decode( + &mut &*executor.read_runtime_version(&final_code, &mut ext.ext()).unwrap(), + ) + .unwrap(); + final_version + .api_version(&>::ID) + .is_some() +} + /// Execute the given `method` and `data` on top of `ext`, returning the results (encoded) and the /// state `changes`. -pub(crate) fn state_machine_call( +pub(crate) fn state_machine_call( ext: &TestExternalities, - executor: &NativeElseWasmExecutor, - execution: sc_cli::ExecutionStrategy, + executor: &WasmExecutor, method: &'static str, data: &[u8], extensions: Extensions, @@ -738,7 +846,7 @@ pub(crate) fn state_machine_call(Into::into)?; @@ -749,28 +857,23 @@ pub(crate) fn state_machine_call( +pub(crate) fn state_machine_call_with_proof( ext: &TestExternalities, - executor: &NativeElseWasmExecutor, - execution: sc_cli::ExecutionStrategy, + executor: &WasmExecutor, 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 runtime_code_backend = sp_state_machine::backend::BackendRuntimeCode::new(&backend); - let proving_backend = TrieBackendBuilder::wrap(&backend).with_recorder(Default::default()).build(); - let runtime_code = runtime_code_backend.runtime_code()?; let pre_root = *backend.root(); - let encoded_results = StateMachine::new( &proving_backend, &mut changes, @@ -781,7 +884,7 @@ pub(crate) fn state_machine_call_with_proof(Into::into)?; @@ -792,11 +895,24 @@ pub(crate) fn state_machine_call_with_proof(pre_root) - .map_err(|e| format!("failed to generate compact proof {}: {:?}", method, e))?; + .map_err(|e| { + log::error!(target: LOG_TARGET, "failed to generate compact proof {}: {:?}", method, e); + e + }) + .unwrap_or(CompactProof { encoded_nodes: Default::default() }); 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))?; + .map_err(|e| { + log::error!( + target: LOG_TARGET, + "failed to generate compressed proof {}: {:?}", + method, + e + ); + e + }) + .unwrap_or_default(); let proof_nodes = proof.into_nodes(); @@ -814,8 +930,8 @@ pub(crate) fn state_machine_call_with_proof>()), + "proof: 0x{}... / {} nodes", + HexDisplay::from(&proof_nodes.iter().flatten().cloned().take(10).collect::>()), proof_nodes.len() ); log::debug!(target: LOG_TARGET, "proof size: {}", humanize(proof_size)); @@ -825,28 +941,13 @@ pub(crate) fn state_machine_call_with_proof( - ext: &TestExternalities, - executor: &NativeElseWasmExecutor, -) -> (String, u32, sp_core::storage::StateVersion) { - 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| { - let state_version = v.state_version(); - (v.spec_name.into(), v.spec_version, state_version) - }) - .expect("all runtimes should have version; qed") +pub(crate) fn rpc_err_handler(error: impl Debug) -> &'static str { + log::error!(target: LOG_TARGET, "rpc error: {:?}", error); + "rpc error." } From f763ff622700d2c880122b291a1e13291b6a388a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 15 Dec 2022 08:57:19 +0000 Subject: [PATCH 193/715] Automatic `withdraw_unbonded` upon `unbond` (#12582) * Prevents max unbonding chunk slots from being filled when unbonding in the staking pallet * hardcode num_slashing to unlock chunks automatically * refactor withdraw logic to do_withdraw; idiomatic rust improvements * a * callable unbond() to return a DispatchWithPostInfo to dynamically update the consumed weight * refunds overpaid fees when unbond with withdraw * fetches real slashing spans before withdrawal call * nits * addresses PR comments * Adds more testing * fixes doc comments * Fixes weight refunding logic for fn unbond * generalizes to return used weight or dispatch error * Update frame/staking/src/pallet/mod.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update frame/staking/src/pallet/mod.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Addresses PR comments * Add comment to speculative num spans * adds missing add_slashing_spans in withdraw_unbonded_kill benchmarks * ".git/.scripts/bench-bot.sh" pallet dev pallet_staking * fix publish Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: command-bot <> --- frame/nomination-pools/src/lib.rs | 9 +- frame/staking/src/benchmarking.rs | 1 + frame/staking/src/pallet/impls.rs | 41 ++++ frame/staking/src/pallet/mod.rs | 80 ++++--- frame/staking/src/tests.rs | 58 +++-- frame/staking/src/weights.rs | 370 +++++++++++++++--------------- 6 files changed, 321 insertions(+), 238 deletions(-) diff --git a/frame/nomination-pools/src/lib.rs b/frame/nomination-pools/src/lib.rs index fd533ee3762b4..5e5385b62acd3 100644 --- a/frame/nomination-pools/src/lib.rs +++ b/frame/nomination-pools/src/lib.rs @@ -1644,9 +1644,12 @@ pub mod pallet { /// # 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. + /// [`Call::pool_withdraw_unbonded`] can be called to try and minimize unlocking chunks. + /// The [`StakingInterface::unbond`] will implicitly call [`Call::pool_withdraw_unbonded`] + /// to try to free chunks if necessary (ie. if unbound was called and no unlocking chunks + /// are available). However, it may not be possible to release the current unlocking chunks, + /// in which case, 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( diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index 8409b5413f992..81fa0f9d81dbf 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -316,6 +316,7 @@ benchmarks! { let scenario = ListScenario::::new(origin_weight, true)?; let controller = scenario.origin_controller1.clone(); let stash = scenario.origin_stash1; + add_slashing_spans::(&stash, s); assert!(T::VoterList::contains(&stash)); let ed = T::Currency::minimum_balance(); diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index d3b9b6a2b1e83..a7190d70c7061 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -92,6 +92,45 @@ impl Pallet { Self::slashable_balance_of_vote_weight(who, issuance) } + pub(super) fn do_withdraw_unbonded( + controller: &T::AccountId, + num_slashing_spans: u32, + ) -> Result { + let mut ledger = Self::ledger(&controller).ok_or(Error::::NotController)?; + let (stash, old_total) = (ledger.stash.clone(), ledger.total); + if let Some(current_era) = Self::current_era() { + ledger = ledger.consolidate_unlocked(current_era) + } + + let used_weight = + if ledger.unlocking.is_empty() && ledger.active < T::Currency::minimum_balance() { + // This account must have called `unbond()` with some value that caused the active + // portion to fall below existential deposit + will have no more unlocking chunks + // left. We can now safely remove all staking-related information. + Self::kill_stash(&stash, num_slashing_spans)?; + // Remove the lock. + T::Currency::remove_lock(STAKING_ID, &stash); + + T::WeightInfo::withdraw_unbonded_kill(num_slashing_spans) + } else { + // This was the consequence of a partial unbond. just update the ledger and move on. + Self::update_ledger(&controller, &ledger); + + // This is only an update, so we use less overall weight. + T::WeightInfo::withdraw_unbonded_update(num_slashing_spans) + }; + + // `old_total` should never be less than the new total because + // `consolidate_unlocked` strictly subtracts balance. + 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, amount: value }); + } + + Ok(used_weight) + } + pub(super) fn do_payout_stakers( validator_stash: T::AccountId, era: EraIndex, @@ -1568,6 +1607,8 @@ impl StakingInterface for Pallet { 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) + .map_err(|with_post| with_post.error) + .map(|_| ()) } fn chill(who: &Self::AccountId) -> DispatchResult { diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 2daa992f4ef6e..1d5babe7ffa8f 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -51,6 +51,10 @@ use crate::{ }; const STAKING_ID: LockIdentifier = *b"staking "; +// The speculative number of spans are used as an input of the weight annotation of +// [`Call::unbond`], as the post dipatch weight may depend on the number of slashing span on the +// account which is not provided as an input. The value set should be conservative but sensible. +pub(crate) const SPECULATIVE_NUM_SPANS: u32 = 32; #[frame_support::pallet] pub mod pallet { @@ -115,7 +119,6 @@ pub mod pallet { // we only accept an election provider that has staking as data provider. DataProvider = Pallet, >; - /// Something that provides the election functionality at genesis. type GenesisElectionProvider: ElectionProvider< AccountId = Self::AccountId, @@ -953,8 +956,8 @@ pub mod pallet { /// the funds out of management ready for transfer. /// /// 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). + /// can co-exists at the same time. If there are no unlocking chunks slots available + /// [`Call::withdraw_unbonded`] is called to remove some of the chunks (if possible). /// /// If a user encounters the `InsufficientBond` error when calling this extrinsic, /// they should call `chill` first in order to free up their bonded funds. @@ -963,20 +966,39 @@ pub mod pallet { /// /// See also [`Call::withdraw_unbonded`]. #[pallet::call_index(2)] - #[pallet::weight(T::WeightInfo::unbond())] + #[pallet::weight( + T::WeightInfo::withdraw_unbonded_kill(SPECULATIVE_NUM_SPANS).saturating_add(T::WeightInfo::unbond())) + ] pub fn unbond( origin: OriginFor, #[pallet::compact] value: BalanceOf, - ) -> DispatchResult { + ) -> DispatchResultWithPostInfo { let controller = ensure_signed(origin)?; + let unlocking = Self::ledger(&controller) + .map(|l| l.unlocking.len()) + .ok_or(Error::::NotController)?; + + // if there are no unlocking chunks available, try to withdraw chunks older than + // `BondingDuration` to proceed with the unbonding. + let maybe_withdraw_weight = { + if unlocking == T::MaxUnlockingChunks::get() as usize { + let real_num_slashing_spans = Self::slashing_spans(&controller).iter().count(); + Some(Self::do_withdraw_unbonded(&controller, real_num_slashing_spans as u32)?) + } else { + None + } + }; + + // we need to fetch the ledger again because it may have been mutated in the call + // to `Self::do_withdraw_unbonded` above. let mut ledger = Self::ledger(&controller).ok_or(Error::::NotController)?; + let mut value = value.min(ledger.active); + ensure!( ledger.unlocking.len() < T::MaxUnlockingChunks::get() as usize, Error::::NoMoreChunks, ); - let mut value = value.min(ledger.active); - if !value.is_zero() { ledger.active -= value; @@ -1024,7 +1046,14 @@ pub mod pallet { Self::deposit_event(Event::::Unbonded { stash: ledger.stash, amount: value }); } - Ok(()) + + let actual_weight = if let Some(withdraw_weight) = maybe_withdraw_weight { + Some(T::WeightInfo::unbond().saturating_add(withdraw_weight)) + } else { + Some(T::WeightInfo::unbond()) + }; + + Ok(actual_weight.into()) } /// Remove any unlocked chunks from the `unlocking` queue from our management. @@ -1049,40 +1078,9 @@ pub mod pallet { num_slashing_spans: u32, ) -> DispatchResultWithPostInfo { let controller = ensure_signed(origin)?; - let mut ledger = Self::ledger(&controller).ok_or(Error::::NotController)?; - let (stash, old_total) = (ledger.stash.clone(), ledger.total); - if let Some(current_era) = Self::current_era() { - ledger = ledger.consolidate_unlocked(current_era) - } - - let post_info_weight = if ledger.unlocking.is_empty() && - ledger.active < T::Currency::minimum_balance() - { - // This account must have called `unbond()` with some value that caused the active - // portion to fall below existential deposit + will have no more unlocking chunks - // left. We can now safely remove all staking-related information. - Self::kill_stash(&stash, num_slashing_spans)?; - // Remove the lock. - T::Currency::remove_lock(STAKING_ID, &stash); - // This is worst case scenario, so we use the full weight and return None - None - } else { - // This was the consequence of a partial unbond. just update the ledger and move on. - Self::update_ledger(&controller, &ledger); - - // This is only an update, so we use less overall weight. - Some(T::WeightInfo::withdraw_unbonded_update(num_slashing_spans)) - }; - - // `old_total` should never be less than the new total because - // `consolidate_unlocked` strictly subtracts balance. - 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, amount: value }); - } - Ok(post_info_weight.into()) + let actual_weight = Self::do_withdraw_unbonded(&controller, num_slashing_spans)?; + Ok(Some(actual_weight).into()) } /// Declare the desire to validate for the origin controller. diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 74d8dc8a8105c..fc6fc68e66d5d 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -1350,12 +1350,14 @@ fn bond_extra_and_withdraw_unbonded_works() { } #[test] -fn too_many_unbond_calls_should_not_work() { +fn many_unbond_calls_should_work() { ExtBuilder::default().build_and_execute(|| { let mut current_era = 0; // locked at era MaxUnlockingChunks - 1 until 3 - for i in 0..<::MaxUnlockingChunks as Get>::get() - 1 { + let max_unlocking_chunks = <::MaxUnlockingChunks as Get>::get(); + + for i in 0..max_unlocking_chunks - 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); @@ -1365,27 +1367,57 @@ fn too_many_unbond_calls_should_not_work() { current_era += 1; mock::start_active_era(current_era); - // This chunk is locked at `current_era` through `current_era + 2` (because BondingDuration - // == 3). + // This chunk is locked at `current_era` through `current_era + 2` (because + // `BondingDuration` == 3). assert_ok!(Staking::unbond(RuntimeOrigin::signed(10), 1)); assert_eq!( - Staking::ledger(&10).unwrap().unlocking.len(), + Staking::ledger(&10).map(|l| l.unlocking.len()).unwrap(), <::MaxUnlockingChunks as Get>::get() as usize ); - // can't do more. - assert_noop!(Staking::unbond(RuntimeOrigin::signed(10), 1), Error::::NoMoreChunks); - current_era += 2; + // even though the number of unlocked chunks is the same as `MaxUnlockingChunks`, + // unbonding works as expected. + for i in current_era..(current_era + max_unlocking_chunks) - 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(RuntimeOrigin::signed(10), 1)); + } + + // only slots within last `BondingDuration` are filled. + assert_eq!( + Staking::ledger(&10).map(|l| l.unlocking.len()).unwrap(), + <::BondingDuration>::get() as usize + ); + }) +} + +#[test] +fn auto_withdraw_may_not_unlock_all_chunks() { + ExtBuilder::default().build_and_execute(|| { + // set `MaxUnlockingChunks` to a low number to test case when the unbonding period + // is larger than the number of unlocking chunks available, which may result on a + // `Error::NoMoreChunks`, even when the auto-withdraw tries to release locked chunks. + MaxUnlockingChunks::set(1); + + let mut current_era = 0; + + // fills the chunking slots for account + mock::start_active_era(current_era); + assert_ok!(Staking::unbond(RuntimeOrigin::signed(10), 1)); + + current_era += 1; mock::start_active_era(current_era); + // unbonding will fail because i) there are no remaining chunks and ii) no filled chunks + // can be released because current chunk hasn't stay in the queue for at least + // `BondingDuration` assert_noop!(Staking::unbond(RuntimeOrigin::signed(10), 1), Error::::NoMoreChunks); - // free up everything except the most recently added chunk. - assert_ok!(Staking::withdraw_unbonded(RuntimeOrigin::signed(10), 0)); - assert_eq!(Staking::ledger(&10).unwrap().unlocking.len(), 1); - // Can add again. + // fast-forward a few eras for unbond to be successful with implicit withdraw + current_era += 10; + mock::start_active_era(current_era); assert_ok!(Staking::unbond(RuntimeOrigin::signed(10), 1)); - assert_eq!(Staking::ledger(&10).unwrap().unlocking.len(), 2); }) } diff --git a/frame/staking/src/weights.rs b/frame/staking/src/weights.rs index 21fc3d6f077bc..aebb8eeb9b06e 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-12-12, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-12-14, 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 @@ -88,8 +88,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn bond() -> Weight { - // Minimum execution time: 56_034 nanoseconds. - Weight::from_ref_time(56_646_000) + // Minimum execution time: 54_402 nanoseconds. + Weight::from_ref_time(55_096_000) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -99,8 +99,8 @@ 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: 94_354 nanoseconds. - Weight::from_ref_time(95_318_000) + // Minimum execution time: 94_407 nanoseconds. + Weight::from_ref_time(95_209_000) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(7)) } @@ -114,8 +114,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Bonded (r:1 w:0) // Storage: VoterList ListBags (r:2 w:2) fn unbond() -> Weight { - // Minimum execution time: 99_960 nanoseconds. - Weight::from_ref_time(101_022_000) + // Minimum execution time: 101_046 nanoseconds. + Weight::from_ref_time(101_504_000) .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(8)) } @@ -125,10 +125,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 { - // 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())) + // Minimum execution time: 45_452 nanoseconds. + Weight::from_ref_time(47_031_537) + // Standard Error: 491 + .saturating_add(Weight::from_ref_time(67_148).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -145,12 +145,16 @@ 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) + // Storage: Staking SpanSlash (r:0 w:2) /// The range of component `s` is `[0, 100]`. - fn withdraw_unbonded_kill(_s: u32, ) -> Weight { - // Minimum execution time: 86_035 nanoseconds. - Weight::from_ref_time(89_561_735) + fn withdraw_unbonded_kill(s: u32, ) -> Weight { + // Minimum execution time: 88_067 nanoseconds. + Weight::from_ref_time(93_309_587) + // Standard Error: 4_762 + .saturating_add(Weight::from_ref_time(1_114_938).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(13)) - .saturating_add(T::DbWeight::get().writes(11)) + .saturating_add(T::DbWeight::get().writes(12)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking MinValidatorBond (r:1 w:0) @@ -164,8 +168,8 @@ impl WeightInfo for SubstrateWeight { // Storage: VoterList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForValidators (r:1 w:1) fn validate() -> Weight { - // Minimum execution time: 68_748 nanoseconds. - Weight::from_ref_time(69_285_000) + // Minimum execution time: 67_308 nanoseconds. + Weight::from_ref_time(68_266_000) .saturating_add(T::DbWeight::get().reads(11)) .saturating_add(T::DbWeight::get().writes(5)) } @@ -173,10 +177,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Nominators (r:1 w:1) /// The range of component `k` is `[1, 128]`. fn kick(k: u32, ) -> Weight { - // 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())) + // Minimum execution time: 40_913 nanoseconds. + Weight::from_ref_time(48_140_584) + // Standard Error: 13_396 + .saturating_add(Weight::from_ref_time(6_862_893).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()))) @@ -194,10 +198,10 @@ 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: 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())) + // Minimum execution time: 73_490 nanoseconds. + Weight::from_ref_time(72_520_864) + // Standard Error: 7_090 + .saturating_add(Weight::from_ref_time(2_800_566).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)) @@ -210,58 +214,58 @@ impl WeightInfo for SubstrateWeight { // Storage: VoterList ListBags (r:1 w:1) // Storage: VoterList CounterForListNodes (r:1 w:1) fn chill() -> Weight { - // Minimum execution time: 67_307 nanoseconds. - Weight::from_ref_time(67_838_000) + // Minimum execution time: 66_293 nanoseconds. + Weight::from_ref_time(66_946_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_831 nanoseconds. - Weight::from_ref_time(19_047_000) + // Minimum execution time: 18_134 nanoseconds. + Weight::from_ref_time(18_497_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: 27_534 nanoseconds. - Weight::from_ref_time(27_806_000) + // Minimum execution time: 26_728 nanoseconds. + Weight::from_ref_time(27_154_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_211 nanoseconds. - Weight::from_ref_time(5_372_000) + // Minimum execution time: 4_877 nanoseconds. + Weight::from_ref_time(5_028_000) .saturating_add(T::DbWeight::get().writes(1)) } // Storage: Staking ForceEra (r:0 w:1) fn force_no_eras() -> Weight { - // Minimum execution time: 5_382 nanoseconds. - Weight::from_ref_time(5_654_000) + // Minimum execution time: 5_000 nanoseconds. + Weight::from_ref_time(5_290_000) .saturating_add(T::DbWeight::get().writes(1)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era() -> Weight { - // Minimum execution time: 5_618 nanoseconds. - Weight::from_ref_time(5_714_000) + // Minimum execution time: 5_093 nanoseconds. + Weight::from_ref_time(5_378_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_589 nanoseconds. - Weight::from_ref_time(5_776_000) + // Minimum execution time: 5_144 nanoseconds. + Weight::from_ref_time(5_454_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_541 nanoseconds. - Weight::from_ref_time(6_479_253) - // Standard Error: 49 - .saturating_add(Weight::from_ref_time(10_125).saturating_mul(v.into())) + // Minimum execution time: 5_190 nanoseconds. + Weight::from_ref_time(5_960_962) + // Standard Error: 41 + .saturating_add(Weight::from_ref_time(10_329).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().writes(1)) } // Storage: Staking Bonded (r:1 w:1) @@ -279,10 +283,10 @@ 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: 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())) + // Minimum execution time: 80_516 nanoseconds. + Weight::from_ref_time(86_317_884) + // Standard Error: 2_212 + .saturating_add(Weight::from_ref_time(1_103_962).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()))) @@ -290,10 +294,10 @@ impl WeightInfo for SubstrateWeight { // 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_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())) + // Minimum execution time: 91_795 nanoseconds. + Weight::from_ref_time(904_524_900) + // Standard Error: 59_193 + .saturating_add(Weight::from_ref_time(4_944_680).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -308,10 +312,10 @@ 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: 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())) + // Minimum execution time: 127_774 nanoseconds. + Weight::from_ref_time(178_857_156) + // Standard Error: 15_229 + .saturating_add(Weight::from_ref_time(22_112_174).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)) @@ -329,10 +333,10 @@ 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: 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())) + // Minimum execution time: 161_910 nanoseconds. + Weight::from_ref_time(217_635_072) + // Standard Error: 30_726 + .saturating_add(Weight::from_ref_time(31_244_329).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)) @@ -346,10 +350,10 @@ 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: 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())) + // Minimum execution time: 92_986 nanoseconds. + Weight::from_ref_time(94_880_481) + // Standard Error: 2_007 + .saturating_add(Weight::from_ref_time(31_421).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(8)) } @@ -368,10 +372,10 @@ 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: 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())) + // Minimum execution time: 92_750 nanoseconds. + Weight::from_ref_time(95_115_568) + // Standard Error: 2_037 + .saturating_add(Weight::from_ref_time(1_086_488).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()))) @@ -395,12 +399,12 @@ 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: 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())) + // Minimum execution time: 506_543 nanoseconds. + Weight::from_ref_time(507_261_000) + // Standard Error: 1_766_631 + .saturating_add(Weight::from_ref_time(59_139_153).saturating_mul(v.into())) + // Standard Error: 176_035 + .saturating_add(Weight::from_ref_time(13_512_781).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()))) @@ -417,12 +421,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `v` is `[500, 1000]`. /// The range of component `n` is `[500, 1000]`. fn get_npos_voters(v: u32, n: u32, ) -> Weight { - // 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())) + // Minimum execution time: 24_155_382 nanoseconds. + Weight::from_ref_time(24_252_568_000) + // Standard Error: 319_250 + .saturating_add(Weight::from_ref_time(3_596_056).saturating_mul(v.into())) + // Standard Error: 319_250 + .saturating_add(Weight::from_ref_time(2_852_023).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()))) @@ -431,10 +435,10 @@ impl WeightInfo for SubstrateWeight { // 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_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())) + // Minimum execution time: 4_741_111 nanoseconds. + Weight::from_ref_time(113_360_179) + // Standard Error: 25_375 + .saturating_add(Weight::from_ref_time(9_494_142).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) } @@ -445,8 +449,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 { - // Minimum execution time: 10_816 nanoseconds. - Weight::from_ref_time(11_242_000) + // Minimum execution time: 11_074 nanoseconds. + Weight::from_ref_time(11_312_000) .saturating_add(T::DbWeight::get().writes(6)) } // Storage: Staking MinCommission (r:0 w:1) @@ -456,8 +460,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 { - // Minimum execution time: 9_581 nanoseconds. - Weight::from_ref_time(10_383_000) + // Minimum execution time: 9_795 nanoseconds. + Weight::from_ref_time(10_116_000) .saturating_add(T::DbWeight::get().writes(6)) } // Storage: Staking Ledger (r:1 w:0) @@ -471,16 +475,16 @@ 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: 83_669 nanoseconds. - Weight::from_ref_time(84_772_000) + // Minimum execution time: 82_914 nanoseconds. + Weight::from_ref_time(83_848_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: 20_553 nanoseconds. - Weight::from_ref_time(20_933_000) + // Minimum execution time: 20_317 nanoseconds. + Weight::from_ref_time(20_639_000) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -494,8 +498,8 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn bond() -> Weight { - // Minimum execution time: 56_034 nanoseconds. - Weight::from_ref_time(56_646_000) + // Minimum execution time: 54_402 nanoseconds. + Weight::from_ref_time(55_096_000) .saturating_add(RocksDbWeight::get().reads(4)) .saturating_add(RocksDbWeight::get().writes(4)) } @@ -505,8 +509,8 @@ impl WeightInfo for () { // Storage: VoterList ListNodes (r:3 w:3) // Storage: VoterList ListBags (r:2 w:2) fn bond_extra() -> Weight { - // Minimum execution time: 94_354 nanoseconds. - Weight::from_ref_time(95_318_000) + // Minimum execution time: 94_407 nanoseconds. + Weight::from_ref_time(95_209_000) .saturating_add(RocksDbWeight::get().reads(8)) .saturating_add(RocksDbWeight::get().writes(7)) } @@ -520,8 +524,8 @@ impl WeightInfo for () { // Storage: Staking Bonded (r:1 w:0) // Storage: VoterList ListBags (r:2 w:2) fn unbond() -> Weight { - // Minimum execution time: 99_960 nanoseconds. - Weight::from_ref_time(101_022_000) + // Minimum execution time: 101_046 nanoseconds. + Weight::from_ref_time(101_504_000) .saturating_add(RocksDbWeight::get().reads(12)) .saturating_add(RocksDbWeight::get().writes(8)) } @@ -531,10 +535,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 { - // 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())) + // Minimum execution time: 45_452 nanoseconds. + Weight::from_ref_time(47_031_537) + // Standard Error: 491 + .saturating_add(Weight::from_ref_time(67_148).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(4)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -551,12 +555,16 @@ impl WeightInfo for () { // 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) /// The range of component `s` is `[0, 100]`. - fn withdraw_unbonded_kill(_s: u32, ) -> Weight { - // Minimum execution time: 86_035 nanoseconds. - Weight::from_ref_time(89_561_735) + fn withdraw_unbonded_kill(s: u32, ) -> Weight { + // Minimum execution time: 88_067 nanoseconds. + Weight::from_ref_time(93_309_587) + // Standard Error: 4_762 + .saturating_add(Weight::from_ref_time(1_114_938).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(13)) - .saturating_add(RocksDbWeight::get().writes(11)) + .saturating_add(RocksDbWeight::get().writes(12)) + .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking MinValidatorBond (r:1 w:0) @@ -570,8 +578,8 @@ impl WeightInfo for () { // Storage: VoterList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForValidators (r:1 w:1) fn validate() -> Weight { - // Minimum execution time: 68_748 nanoseconds. - Weight::from_ref_time(69_285_000) + // Minimum execution time: 67_308 nanoseconds. + Weight::from_ref_time(68_266_000) .saturating_add(RocksDbWeight::get().reads(11)) .saturating_add(RocksDbWeight::get().writes(5)) } @@ -579,10 +587,10 @@ impl WeightInfo for () { // Storage: Staking Nominators (r:1 w:1) /// The range of component `k` is `[1, 128]`. fn kick(k: u32, ) -> Weight { - // 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())) + // Minimum execution time: 40_913 nanoseconds. + Weight::from_ref_time(48_140_584) + // Standard Error: 13_396 + .saturating_add(Weight::from_ref_time(6_862_893).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()))) @@ -600,10 +608,10 @@ 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: 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())) + // Minimum execution time: 73_490 nanoseconds. + Weight::from_ref_time(72_520_864) + // Standard Error: 7_090 + .saturating_add(Weight::from_ref_time(2_800_566).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)) @@ -616,58 +624,58 @@ impl WeightInfo for () { // Storage: VoterList ListBags (r:1 w:1) // Storage: VoterList CounterForListNodes (r:1 w:1) fn chill() -> Weight { - // Minimum execution time: 67_307 nanoseconds. - Weight::from_ref_time(67_838_000) + // Minimum execution time: 66_293 nanoseconds. + Weight::from_ref_time(66_946_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_831 nanoseconds. - Weight::from_ref_time(19_047_000) + // Minimum execution time: 18_134 nanoseconds. + Weight::from_ref_time(18_497_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: 27_534 nanoseconds. - Weight::from_ref_time(27_806_000) + // Minimum execution time: 26_728 nanoseconds. + Weight::from_ref_time(27_154_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_211 nanoseconds. - Weight::from_ref_time(5_372_000) + // Minimum execution time: 4_877 nanoseconds. + Weight::from_ref_time(5_028_000) .saturating_add(RocksDbWeight::get().writes(1)) } // Storage: Staking ForceEra (r:0 w:1) fn force_no_eras() -> Weight { - // Minimum execution time: 5_382 nanoseconds. - Weight::from_ref_time(5_654_000) + // Minimum execution time: 5_000 nanoseconds. + Weight::from_ref_time(5_290_000) .saturating_add(RocksDbWeight::get().writes(1)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era() -> Weight { - // Minimum execution time: 5_618 nanoseconds. - Weight::from_ref_time(5_714_000) + // Minimum execution time: 5_093 nanoseconds. + Weight::from_ref_time(5_378_000) .saturating_add(RocksDbWeight::get().writes(1)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era_always() -> Weight { - // Minimum execution time: 5_589 nanoseconds. - Weight::from_ref_time(5_776_000) + // Minimum execution time: 5_144 nanoseconds. + Weight::from_ref_time(5_454_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_541 nanoseconds. - Weight::from_ref_time(6_479_253) - // Standard Error: 49 - .saturating_add(Weight::from_ref_time(10_125).saturating_mul(v.into())) + // Minimum execution time: 5_190 nanoseconds. + Weight::from_ref_time(5_960_962) + // Standard Error: 41 + .saturating_add(Weight::from_ref_time(10_329).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().writes(1)) } // Storage: Staking Bonded (r:1 w:1) @@ -685,10 +693,10 @@ 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: 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())) + // Minimum execution time: 80_516 nanoseconds. + Weight::from_ref_time(86_317_884) + // Standard Error: 2_212 + .saturating_add(Weight::from_ref_time(1_103_962).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()))) @@ -696,10 +704,10 @@ impl WeightInfo for () { // 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_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())) + // Minimum execution time: 91_795 nanoseconds. + Weight::from_ref_time(904_524_900) + // Standard Error: 59_193 + .saturating_add(Weight::from_ref_time(4_944_680).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1)) .saturating_add(RocksDbWeight::get().writes(1)) } @@ -714,10 +722,10 @@ 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: 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())) + // Minimum execution time: 127_774 nanoseconds. + Weight::from_ref_time(178_857_156) + // Standard Error: 15_229 + .saturating_add(Weight::from_ref_time(22_112_174).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)) @@ -735,10 +743,10 @@ 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: 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())) + // Minimum execution time: 161_910 nanoseconds. + Weight::from_ref_time(217_635_072) + // Standard Error: 30_726 + .saturating_add(Weight::from_ref_time(31_244_329).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)) @@ -752,10 +760,10 @@ 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: 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())) + // Minimum execution time: 92_986 nanoseconds. + Weight::from_ref_time(94_880_481) + // Standard Error: 2_007 + .saturating_add(Weight::from_ref_time(31_421).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(9)) .saturating_add(RocksDbWeight::get().writes(8)) } @@ -774,10 +782,10 @@ 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: 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())) + // Minimum execution time: 92_750 nanoseconds. + Weight::from_ref_time(95_115_568) + // Standard Error: 2_037 + .saturating_add(Weight::from_ref_time(1_086_488).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()))) @@ -801,12 +809,12 @@ 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: 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())) + // Minimum execution time: 506_543 nanoseconds. + Weight::from_ref_time(507_261_000) + // Standard Error: 1_766_631 + .saturating_add(Weight::from_ref_time(59_139_153).saturating_mul(v.into())) + // Standard Error: 176_035 + .saturating_add(Weight::from_ref_time(13_512_781).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()))) @@ -823,12 +831,12 @@ impl WeightInfo for () { /// The range of component `v` is `[500, 1000]`. /// The range of component `n` is `[500, 1000]`. fn get_npos_voters(v: u32, n: u32, ) -> Weight { - // 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())) + // Minimum execution time: 24_155_382 nanoseconds. + Weight::from_ref_time(24_252_568_000) + // Standard Error: 319_250 + .saturating_add(Weight::from_ref_time(3_596_056).saturating_mul(v.into())) + // Standard Error: 319_250 + .saturating_add(Weight::from_ref_time(2_852_023).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()))) @@ -837,10 +845,10 @@ impl WeightInfo for () { // 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_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())) + // Minimum execution time: 4_741_111 nanoseconds. + Weight::from_ref_time(113_360_179) + // Standard Error: 25_375 + .saturating_add(Weight::from_ref_time(9_494_142).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().reads(2)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(v.into()))) } @@ -851,8 +859,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 { - // Minimum execution time: 10_816 nanoseconds. - Weight::from_ref_time(11_242_000) + // Minimum execution time: 11_074 nanoseconds. + Weight::from_ref_time(11_312_000) .saturating_add(RocksDbWeight::get().writes(6)) } // Storage: Staking MinCommission (r:0 w:1) @@ -862,8 +870,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 { - // Minimum execution time: 9_581 nanoseconds. - Weight::from_ref_time(10_383_000) + // Minimum execution time: 9_795 nanoseconds. + Weight::from_ref_time(10_116_000) .saturating_add(RocksDbWeight::get().writes(6)) } // Storage: Staking Ledger (r:1 w:0) @@ -877,16 +885,16 @@ impl WeightInfo for () { // Storage: VoterList ListBags (r:1 w:1) // Storage: VoterList CounterForListNodes (r:1 w:1) fn chill_other() -> Weight { - // Minimum execution time: 83_669 nanoseconds. - Weight::from_ref_time(84_772_000) + // Minimum execution time: 82_914 nanoseconds. + Weight::from_ref_time(83_848_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: 20_553 nanoseconds. - Weight::from_ref_time(20_933_000) + // Minimum execution time: 20_317 nanoseconds. + Weight::from_ref_time(20_639_000) .saturating_add(RocksDbWeight::get().reads(2)) .saturating_add(RocksDbWeight::get().writes(1)) } From d29967dc93b3c3bbfa7e1c8d785df3339993415a Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Thu, 15 Dec 2022 12:12:36 +0200 Subject: [PATCH 194/715] documentation: add BEEFY 'spec' (#12920) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * beefy: add BEEFY 'spec' * Apply suggestions from code review Signed-off-by: Adrian Catangiu Co-authored-by: Tomasz Drwięga Co-authored-by: André Silva Co-authored-by: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Co-authored-by: parity-processbot <> --- client/beefy/README.md | 373 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 373 insertions(+) create mode 100644 client/beefy/README.md diff --git a/client/beefy/README.md b/client/beefy/README.md new file mode 100644 index 0000000000000..d9099dc7c661d --- /dev/null +++ b/client/beefy/README.md @@ -0,0 +1,373 @@ +# BEEFY +**BEEFY** (**B**ridge **E**fficiency **E**nabling **F**inality **Y**ielder) is a secondary +protocol running along GRANDPA Finality to support efficient bridging with non-Substrate +blockchains, currently mainly ETH mainnet. + +It can be thought of as an (optional) Bridge-specific Gadget to the GRANDPA Finality protocol. +The Protocol piggybacks on many assumptions provided by GRANDPA, and is required to be built +on top of it to work correctly. + +BEEFY is a consensus protocol designed with efficient trustless bridging in mind. It means +that building a light client of BEEFY protocol should be optimized for restricted environments +like Ethereum Smart Contracts or On-Chain State Transition Function (e.g. Substrate Runtime). +Note that BEEFY is not a standalone protocol, it is meant to be running alongside GRANDPA, a +finality gadget created for Substrate/Polkadot ecosystem. More details about GRANDPA can be found +in the [whitepaper](https://github.com/w3f/consensus/blob/master/pdf/grandpa.pdf). + +# Context + +## Bridges + +We want to be able to "bridge" different blockchains. We do so by safely sharing and verifying +information about each chain’s state, i.e. blockchain `A` should be able to verify that blockchain +`B` is at block #X. + +## Finality + +Finality in blockchains is a concept that means that after a given block #X has been finalized, +it will never be reverted (e.g. due to a re-org). As such, we can be assured that any transaction +that exists in this block will never be reverted. + +## GRANDPA + +GRANDPA is our finality gadget. It allows a set of nodes to come to BFT agreement on what is the +canonical chain. It requires that 2/3 of the validator set agrees on a prefix of the canonical +chain, which then becomes finalized. + +![img](https://miro.medium.com/max/955/1*NTg26i4xbO3JncF_Usu9MA.png) + +### Difficulties of GRANDPA finality proofs + +```rust +struct Justification { + round: u64, + commit: Commit, + votes_ancestries: Vec, +} + +struct Commit { + target_hash: Hash, + target_number: Number, + precommits: Vec>, +} + +struct SignedPrecommit { + precommit: Precommit, + signature: Signature, + id: Id, +} + +struct Precommit { + target_hash: Hash, + target_number: Number, +} +``` + +The main difficulty of verifying GRANDPA finality proofs comes from the fact that voters are +voting on different things. In GRANDPA each voter will vote for the block they think is the +latest one, and the protocol will come to agreement on what is the common ancestor which has > +2/3 support. + +This creates two sets of inefficiencies: + +- We may need to have each validator's vote data because they're all potentially different (i.e. + just the signature isn't enough). +- We may need to attach a couple of headers to the finality proof in order to be able to verify + all of the votes' ancestries. + +Additionally, since our interim goal is to bridge to Ethereum there is also a difficulty related +to "incompatible" crypto schemes. We use \`ed25519\` signatures in GRANDPA which we can't +efficiently verify in the EVM. + +Hence, + +### Goals of BEEFY + +1. Allow customisation of crypto to adapt for different targets. Support thresholds signatures as + well eventually. +1. Minimize the size of the "signed payload" and the finality proof. +1. Unify data types and use backward-compatible versioning so that the protocol can be extended + (additional payload, different crypto) without breaking existing light clients. + +And since BEEFY is required to be running on top of GRANDPA. This allows us to take couple of +shortcuts: +1. BEEFY validator set is **the same** as GRANDPA's (i.e. the same bonded actors), they might be + identified by different session keys though. +1. BEEFY runs on **finalized** canonical chain, i.e. no forks (note Misbehavior + section though). +1. From a single validator perspective, BEEFY has at most one active voting round. Since GRANDPA + validators are reaching finality, we assume they are on-line and well-connected and have + similar view of the state of the blockchain. + +# The BEEFY Protocol + +## Mental Model + +BEEFY should be considered as an extra voting round done by GRANDPA validators for the current +best finalized block. Similarily to how GRANDPA is lagging behind best produced (non-finalized) +block, BEEFY is going to lag behind best GRANDPA (finalized) block. + +``` + ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ + │ │ │ │ │ │ │ │ │ │ + │ B1 │ │ B2 │ │ B3 │ │ B4 │ │ B5 │ + │ │ │ │ │ │ │ │ │ │ + └──────┘ └───▲──┘ └──────┘ └───▲──┘ └───▲──┘ + │ │ │ + Best BEEFY block───────────────┘ │ │ + │ │ + Best GRANDPA block───────────────────────────────┘ │ + │ + Best produced block───────────────────────────────────────┘ + +``` + +A pseudo-algorithm of behaviour for a fully-synced BEEFY validator is: + +``` +loop { + let (best_beefy, best_grandpa) = wait_for_best_blocks(); + + let block_to_vote_on = choose_next_beefy_block( + best_beefy, + best_grandpa + ); + + let payload_to_vote_on = retrieve_payload(block_to_vote_on); + + let commitment = (block_to_vote_on, payload_to_vote_on); + + let signature = sign_with_current_session_key(commitment); + + broadcast_vote(commitment, signature); +} +``` + +## Details + +Before we jump into describing how BEEFY works in details, let's agree on the terms we are going +to use and actors in the system. All nodes in the network need to participate in the BEEFY +networking protocol, but we can identify two distinct actors though: **regular nodes** and +**BEEFY validators**. +Validators are expected to actively participate in the protocol, by producing and broadcasting +**votes**. Votes are simply their signatures over a **Commitment**. A Commitment consists of a +**payload** (an opaque blob of bytes extracted from a block or state at that block, expected to +be some form of crypto accumulator (like Merkle Tree Hash or Merkle Mountain Range Root Hash)) +and **block number** from which this payload originates. Additionally, Commitment contains BEEFY +**validator set id** at that particular block. Note the block is finalized, so there is no +ambiguity despite using block number instead of a hash. A collection of **votes**, or rather +a Commitment and a collection of signatures is going to be called **Signed Commitment**. A valid +(see later for the rules) Signed Commitment is also called a **BEEFY Justification** or +**BEEFY Finality Proof**. For more details on the actual data structures please see +[BEEFY primitives definitions](https://github.com/paritytech/substrate/tree/master/primitives/beefy/src). + +A **round** is an attempt by BEEFY validators to produce a BEEFY Justification. **Round number** +is simply defined as a block number the validators are voting for, or to be more precise, the +Commitment for that block number. Round ends when the next round is started, which may happen +when one of the events occur: +1. Either the node collects `2/3rd + 1` valid votes for that round. +2. Or the node receives a BEEFY Justification for a block greater than the current best BEEFY block. + +In both cases the node proceeds to determining the new round number using "Round Selection" +procedure. + +Regular nodes are expected to: +1. Receive & validate votes for the current round and broadcast them to their peers. +1. Receive & validate BEEFY Justifications and broadcast them to their peers. +1. Return BEEFY Justifications for **Mandatory Blocks** on demand. +1. Optionally return BEEFY Justifications for non-mandatory blocks on demand. + +Validators are expected to additionally: +1. Produce & broadcast vote for the current round. + +Both kinds of actors are expected to fully participate in the protocol ONLY IF they believe they +are up-to-date with the rest of the network, i.e. they are fully synced. Before this happens, +the node should continue processing imported BEEFY Justifications and votes without actively +voting themselves. + +### Round Selection + +Every node (both regular nodes and validators) need to determine locally what they believe +current round number is. The choice is based on their knowledge of: + +1. Best GRANDPA finalized block number (`best_grandpa`). +1. Best BEEFY finalized block number (`best_beefy`). +1. Starting block of current session (`session_start`). + +**Session** means a period of time (or rather number of blocks) where validator set (keys) do not change. +See `pallet_session` for implementation details in `FRAME` context. Since we piggy-back on +GRANDPA, session boundaries for BEEFY are exactly the same as the ones for GRANDPA. + +We define two kinds of blocks from the perspective of BEEFY protocol: +1. **Mandatory Blocks** +2. **Non-mandatory Blocks** + +Mandatory blocks are the ones that MUST have BEEFY justification. That means that the validators +will always start and conclude a round at mandatory blocks. For non-mandatory blocks, there may +or may not be a justification and validators may never choose these blocks to start a round. + +Every **first block in** each **session** is considered a **mandatory block**. All other blocks +in the session are non-mandatory, however validators are encouraged to finalize as many blocks as +possible to enable lower latency for light clients and hence end users. Since GRANDPA is +considering session boundary blocks as mandatory as well, `session_start` block will always have +both GRANDPA and BEEFY Justification. + +Therefore, to determine current round number nodes use a formula: + +``` +round_number = + (1 - M) * session_start + + M * (best_beefy + NEXT_POWER_OF_TWO((best_grandpa - best_beefy + 1) / 2)) +``` + +where: + +- `M` is `1` if mandatory block in current session is already finalized and `0` otherwise. +- `NEXT_POWER_OF_TWO(x)` returns the smallest number greater or equal to `x` that is a power of two. + +In other words, the next round number should be the oldest mandatory block without a justification, +or the highest GRANDPA-finalized block, whose block number difference with `best_beefy` block is +a power of two. The mental model for round selection is to first finalize the mandatory block and +then to attempt to pick a block taking into account how fast BEEFY catches up with GRANDPA. +In case GRANDPA makes progress, but BEEFY seems to be lagging behind, validators are changing +rounds less often to increase the chance of concluding them. + +As mentioned earlier, every time the node picks a new `round_number` (and validator casts a vote) +it ends the previous one, no matter if finality was reached (i.e. the round concluded) or not. +Votes for an inactive round should not be propagated. + +Note that since BEEFY only votes for GRANDPA-finalized blocks, `session_start` here actually means: +"the latest session for which the start of is GRANDPA-finalized", i.e. block production might +have already progressed, but BEEFY needs to first finalize the mandatory block of the older +session. + +In good networking conditions BEEFY may end up finalizing each and every block (if GRANDPA does +the same). Practically, with short block times, it's going to be rare and might be excessive, so +it's suggested for implementations to introduce a `min_delta` parameter which will limit the +frequency with which new rounds are started. The affected component of the formula would be: +`best_beefy + MAX(min_delta, NEXT_POWER_OF_TWO(...))`, so we start a new round only if the +power-of-two component is greater than the min delta. Note that if `round_number > best_grandpa` +the validators are not expected to start any round. + +### Catch up + +Every session is guaranteed to have at least one BEEFY-finalized block. However it also means +that the round at mandatory block must be concluded even though, a new session has already started +(i.e. the on-chain component has selected a new validator set and GRANDPA might have already +finalized the transition). In such case BEEFY must "catch up" the previous sessions and make sure to +conclude rounds for mandatory blocks. Note that older sessions must obviously be finalized by the +validator set at that point in time, not the latest/current one. + +### Initial Sync + +It's all rainbows and unicorns when the node is fully synced with the network. However during cold +startup it will have hard time determining the current round number. Because of that nodes that +are not fully synced should not participate in BEEFY protocol at all. + +During the sync we should make sure to also fetch BEEFY justifications for all mandatory blocks. +This can happen asynchronously, but validators, before starting to vote, need to be certain +about the last session that contains a concluded round on mandatory block in order to initiate the +catch up procedure. + +### Gossip + +Nodes participating in BEEFY protocol are expected to gossip messages around. +The protocol defines following messages: + +1. Votes for the current round, +2. BEEFY Justifications for recently concluded rounds, +3. BEEFY Justification for the latest mandatory block, + +Each message is additionally associated with a **topic**, which can be either: +1. the round number (i.e. topic associated with a particular round), +2. or the global topic (independent from the rounds). + +Round-specific topic should only be used to gossip the votes, other messages are gossiped +periodically on the global topic. Let's now dive into description of the messages. + +- **Votes** + - Votes are sent on the round-specific topic. + - Vote is considered valid when: + - The commitment matches local commitment. + - The validator is part of the current validator set. + - The signature is correct. + +- **BEEFY Justification** + - Justifications are sent on the global topic. + - Justification is considered worthwhile to gossip when: + - It is for a recent (implementation specific) round or the latest mandatory round. + - All signatures are valid and there is at least `2/3rd + 1` of them. + - Signatorees are part of the current validator set. + - Mandatory justifications should be announced periodically. + +## Misbehavior + +Similarily to other PoS protocols, BEEFY considers casting two different votes in the same round a +misbehavior. I.e. for a particular `round_number`, the validator produces signatures for 2 different +`Commitment`s and broadcasts them. This is called **equivocation**. + +On top of this, voting on an incorrect **payload** is considered a misbehavior as well, and since +we piggy-back on GRANDPA there is no ambiguity in terms of the fork validators should be voting for. + +Misbehavior should be penalized. If more validators misbehave in the exact same `round` the +penalty should be more severe, up to the entire bonded stake in case we reach `1/3rd + 1` +validators misbehaving. + +## Ethereum + +Initial version of BEEFY was made to enable efficient bridging with Ethereum, where the light +client is a Solidity Smart Contract compiled to EVM bytecode. Hence the choice of the initial +cryptography for BEEFY: `secp256k1` and usage of `keccak256` hashing function. + +### Future: Supporting multiple crypto + +While BEEFY currently works with `secp256k1` signatures, we intend in the future to support +multiple signature schemes. +This means that multiple kinds of `SignedCommitment`s might exist and only together they form a +full `BEEFY Justification`. + +## BEEFY Key + +The current cryptographic scheme used by BEEFY is `ecdsa`. This is **different** from other +schemes like `sr25519` and `ed25519` which are commonly used in Substrate configurations for +other pallets (BABE, GRANDPA, AuRa, etc). The most noticeable difference is that an `ecdsa` +public key is `33` bytes long, instead of `32` bytes for a `sr25519` based public key. So, a +BEEFY key [sticks out](https://github.com/paritytech/polkadot/blob/25951e45b1907853f120c752aaa01631a0b3e783/node/service/src/chain_spec.rs#L738) +among the other public keys a bit. + +For other crypto (using the default Substrate configuration) the `AccountId` (32-bytes) matches +the `PublicKey`, but note that it's not the case for BEEFY. As a consequence of this, you can +**not** convert the `AccountId` raw bytes into a BEEFY `PublicKey`. + +The easiest way to generate or view hex-encoded or SS58-encoded BEEFY Public Key is by using the +[Subkey](https://substrate.dev/docs/en/knowledgebase/integrate/subkey) tool. Generate a BEEFY key +using the following command + +```sh +subkey generate --scheme ecdsa +``` + +The output will look something like + +```sh +Secret phrase `sunset anxiety liberty mention dwarf actress advice stove peasant olive kite rebuild` is account: + Secret seed: 0x9f844e21444683c8fcf558c4c11231a14ed9dea6f09a8cc505604368ef204a61 + Public key (hex): 0x02d69740c3bbfbdbb365886c8270c4aafd17cbffb2e04ecef581e6dced5aded2cd + Public key (SS58): KW7n1vMENCBLQpbT5FWtmYWHNvEyGjSrNL4JE32mDds3xnXTf + Account ID: 0x295509ae9a9b04ade5f1756b5f58f4161cf57037b4543eac37b3b555644f6aed + SS58 Address: 5Czu5hudL79ETnQt6GAkVJHGhDQ6Qv3VWq54zN1CPKzKzYGu + +``` + +In case your BEEFY keys are using the wrong cryptographic scheme, you will see an invalid public +key format message at node startup. Basically something like + +```sh +... +2021-05-28 12:37:51 [Relaychain] Invalid BEEFY PublicKey format! +... +``` + +# BEEFY Light Client + +TODO From cb4f2491b00af7d7817f3a54209c26b20faa1f51 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Thu, 15 Dec 2022 11:38:21 +0100 Subject: [PATCH 195/715] Warn on missing `pallet::call_index` (#12894) * Warn on missing call_index Signed-off-by: Oliver Tale-Yazdi * Suppress camel case warning Signed-off-by: Oliver Tale-Yazdi * Simplify code Signed-off-by: Oliver Tale-Yazdi * Disallow warnings in pallet-ui tests Signed-off-by: Oliver Tale-Yazdi * Add pallet UI test Signed-off-by: Oliver Tale-Yazdi * Update Pallet UI Signed-off-by: Oliver Tale-Yazdi * fmt Signed-off-by: Oliver Tale-Yazdi * Use module instead of function Signed-off-by: Oliver Tale-Yazdi * Update pallet-ui Signed-off-by: Oliver Tale-Yazdi Signed-off-by: Oliver Tale-Yazdi --- .../procedural/src/pallet/expand/call.rs | 31 +++++++++++++++++++ .../procedural/src/pallet/parse/call.rs | 4 +++ frame/support/test/tests/pallet_ui.rs | 3 ++ .../pallet_ui/call_argument_invalid_bound.rs | 3 +- .../call_argument_invalid_bound.stderr | 18 +++++------ .../call_argument_invalid_bound_2.rs | 3 +- .../call_argument_invalid_bound_2.stderr | 24 +++++++------- .../call_argument_invalid_bound_3.rs | 3 +- .../call_argument_invalid_bound_3.stderr | 6 ++-- .../tests/pallet_ui/call_missing_index.rs | 22 +++++++++++++ .../tests/pallet_ui/call_missing_index.stderr | 12 +++++++ ...ev_mode_without_arg_max_encoded_len.stderr | 13 ++++++++ 12 files changed, 115 insertions(+), 27 deletions(-) create mode 100644 frame/support/test/tests/pallet_ui/call_missing_index.rs create mode 100644 frame/support/test/tests/pallet_ui/call_missing_index.stderr diff --git a/frame/support/procedural/src/pallet/expand/call.rs b/frame/support/procedural/src/pallet/expand/call.rs index 6b166e6726d38..30ef1a8fca31d 100644 --- a/frame/support/procedural/src/pallet/expand/call.rs +++ b/frame/support/procedural/src/pallet/expand/call.rs @@ -54,6 +54,29 @@ pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream { .map(|fn_name| format!("Create a call with the variant `{}`.", fn_name)) .collect::>(); + let mut warning_structs = Vec::new(); + let mut warning_names = Vec::new(); + // Emit a warning for each call that is missing `call_index` when not in dev-mode. + for method in &methods { + if method.explicit_call_index || def.dev_mode { + continue + } + + let name = syn::Ident::new(&format!("{}", method.name), method.name.span()); + let warning: syn::ItemStruct = syn::parse_quote!( + #[deprecated(note = r" + Implicit call indices are deprecated in favour of explicit ones. + Please ensure that all calls have the `pallet::call_index` attribute or that the + `dev-mode` of the pallet is enabled. For more info see: + and + .")] + #[allow(non_camel_case_types)] + struct #name; + ); + warning_names.push(name); + warning_structs.push(warning); + } + let fn_weight = methods.iter().map(|method| &method.weight); let fn_doc = methods.iter().map(|method| &method.docs).collect::>(); @@ -178,6 +201,14 @@ pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream { .collect::>(); quote::quote_spanned!(span => + mod warnings { + #( + #warning_structs + // This triggers each deprecated warning once. + const _: Option<#warning_names> = None; + )* + } + #[doc(hidden)] pub mod __substrate_call_check { #[macro_export] diff --git a/frame/support/procedural/src/pallet/parse/call.rs b/frame/support/procedural/src/pallet/parse/call.rs index fbca9a52c767c..9620038edfd6d 100644 --- a/frame/support/procedural/src/pallet/parse/call.rs +++ b/frame/support/procedural/src/pallet/parse/call.rs @@ -59,6 +59,8 @@ pub struct CallVariantDef { pub weight: syn::Expr, /// Call index of the dispatchable. pub call_index: u8, + /// Whether an explicit call index was specified. + pub explicit_call_index: bool, /// Docs, used for metadata. pub docs: Vec, /// Attributes annotated at the top of the dispatchable function. @@ -243,6 +245,7 @@ impl CallDef { FunctionAttr::CallIndex(idx) => idx, _ => unreachable!("checked during creation of the let binding"), }); + let explicit_call_index = call_index.is_some(); let final_index = match call_index { Some(i) => i, @@ -296,6 +299,7 @@ impl CallDef { name: method.sig.ident.clone(), weight, call_index: final_index, + explicit_call_index, args, docs, attrs: method.attrs.clone(), diff --git a/frame/support/test/tests/pallet_ui.rs b/frame/support/test/tests/pallet_ui.rs index 2db1d3cb0543a..26d016c5a7796 100644 --- a/frame/support/test/tests/pallet_ui.rs +++ b/frame/support/test/tests/pallet_ui.rs @@ -27,6 +27,9 @@ fn pallet_ui() { // As trybuild is using `cargo check`, we don't need the real WASM binaries. std::env::set_var("SKIP_WASM_BUILD", "1"); + // Deny all warnings since we emit warnings as part of a Pallet's UI. + std::env::set_var("RUSTFLAGS", "--deny warnings"); + let t = trybuild::TestCases::new(); t.compile_fail("tests/pallet_ui/*.rs"); t.pass("tests/pallet_ui/pass/*.rs"); diff --git a/frame/support/test/tests/pallet_ui/call_argument_invalid_bound.rs b/frame/support/test/tests/pallet_ui/call_argument_invalid_bound.rs index ee9d692eba9b3..4f18f7281817a 100644 --- a/frame/support/test/tests/pallet_ui/call_argument_invalid_bound.rs +++ b/frame/support/test/tests/pallet_ui/call_argument_invalid_bound.rs @@ -17,7 +17,8 @@ mod pallet { #[pallet::call] impl Pallet { #[pallet::weight(0)] - pub fn foo(origin: OriginFor, bar: T::Bar) -> DispatchResultWithPostInfo { + #[pallet::call_index(0)] + pub fn foo(origin: OriginFor, _bar: T::Bar) -> DispatchResultWithPostInfo { Ok(().into()) } } 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 62d8649f8af49..aed53b07b5e63 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,21 +1,21 @@ error[E0277]: `::Bar` doesn't implement `std::fmt::Debug` - --> tests/pallet_ui/call_argument_invalid_bound.rs:20:36 + --> tests/pallet_ui/call_argument_invalid_bound.rs:21:36 | -20 | pub fn foo(origin: OriginFor, bar: T::Bar) -> DispatchResultWithPostInfo { - | ^^^ `::Bar` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` +21 | pub fn foo(origin: OriginFor, _bar: T::Bar) -> DispatchResultWithPostInfo { + | ^^^^ `::Bar` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` | = help: the trait `std::fmt::Debug` is not implemented for `::Bar` = 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 - --> tests/pallet_ui/call_argument_invalid_bound.rs:20:36 + --> tests/pallet_ui/call_argument_invalid_bound.rs:21:36 | -20 | pub fn foo(origin: OriginFor, bar: T::Bar) -> DispatchResultWithPostInfo { - | ^^^ the trait `Clone` is not implemented for `::Bar` +21 | 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 + --> tests/pallet_ui/call_argument_invalid_bound.rs:21:36 | -20 | pub fn foo(origin: OriginFor, bar: T::Bar) -> DispatchResultWithPostInfo { - | ^^^ +21 | pub fn foo(origin: OriginFor, _bar: T::Bar) -> DispatchResultWithPostInfo { + | ^^^^ diff --git a/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.rs b/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.rs index d981b55c48620..20568908e72b2 100644 --- a/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.rs +++ b/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.rs @@ -17,7 +17,8 @@ mod pallet { #[pallet::call] impl Pallet { #[pallet::weight(0)] - pub fn foo(origin: OriginFor, bar: T::Bar) -> DispatchResultWithPostInfo { + #[pallet::call_index(0)] + pub fn foo(origin: OriginFor, _bar: T::Bar) -> DispatchResultWithPostInfo { Ok(().into()) } } 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 f486c071631ea..3e2e70432a9c9 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,27 +1,27 @@ error[E0277]: `::Bar` doesn't implement `std::fmt::Debug` - --> tests/pallet_ui/call_argument_invalid_bound_2.rs:20:36 + --> tests/pallet_ui/call_argument_invalid_bound_2.rs:21:36 | -20 | pub fn foo(origin: OriginFor, bar: T::Bar) -> DispatchResultWithPostInfo { - | ^^^ `::Bar` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` +21 | pub fn foo(origin: OriginFor, _bar: T::Bar) -> DispatchResultWithPostInfo { + | ^^^^ `::Bar` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` | = help: the trait `std::fmt::Debug` is not implemented for `::Bar` = 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 - --> tests/pallet_ui/call_argument_invalid_bound_2.rs:20:36 + --> tests/pallet_ui/call_argument_invalid_bound_2.rs:21:36 | -20 | pub fn foo(origin: OriginFor, bar: T::Bar) -> DispatchResultWithPostInfo { - | ^^^ the trait `Clone` is not implemented for `::Bar` +21 | 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 + --> tests/pallet_ui/call_argument_invalid_bound_2.rs:21:36 | -20 | pub fn foo(origin: OriginFor, bar: T::Bar) -> DispatchResultWithPostInfo { - | ^^^ +21 | pub fn foo(origin: OriginFor, _bar: T::Bar) -> DispatchResultWithPostInfo { + | ^^^^ error[E0277]: the trait bound `::Bar: WrapperTypeEncode` is not satisfied - --> tests/pallet_ui/call_argument_invalid_bound_2.rs:20:36 + --> tests/pallet_ui/call_argument_invalid_bound_2.rs:21:36 | 1 | / #[frame_support::pallet] 2 | | mod pallet { @@ -32,8 +32,8 @@ error[E0277]: the trait bound `::Bar: WrapperTypeEncode` is 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` +21 | pub fn foo(origin: OriginFor, _bar: T::Bar) -> DispatchResultWithPostInfo { + | ^^^^ the trait `WrapperTypeEncode` is not implemented for `::Bar` | = note: required for `::Bar` to implement `Encode` 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 1cdfb369feadb..64b6642b0a878 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 @@ -19,7 +19,8 @@ mod pallet { #[pallet::call] impl Pallet { #[pallet::weight(0)] - pub fn foo(origin: OriginFor, bar: Bar) -> DispatchResultWithPostInfo { + #[pallet::call_index(0)] + pub fn foo(origin: OriginFor, _bar: Bar) -> DispatchResultWithPostInfo { Ok(().into()) } } 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 6e51bf2dbf862..395da09cb0d6d 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,8 +1,8 @@ error[E0277]: `Bar` doesn't implement `std::fmt::Debug` - --> tests/pallet_ui/call_argument_invalid_bound_3.rs:22:36 + --> tests/pallet_ui/call_argument_invalid_bound_3.rs:23:36 | -22 | pub fn foo(origin: OriginFor, bar: Bar) -> DispatchResultWithPostInfo { - | ^^^ `Bar` cannot be formatted using `{:?}` +23 | pub fn foo(origin: OriginFor, _bar: Bar) -> DispatchResultWithPostInfo { + | ^^^^ `Bar` cannot be formatted using `{:?}` | = 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` diff --git a/frame/support/test/tests/pallet_ui/call_missing_index.rs b/frame/support/test/tests/pallet_ui/call_missing_index.rs new file mode 100644 index 0000000000000..7e305a573d622 --- /dev/null +++ b/frame/support/test/tests/pallet_ui/call_missing_index.rs @@ -0,0 +1,22 @@ +#[frame_support::pallet] +mod pallet { + use frame_support::pallet_prelude::DispatchResult; + use frame_system::pallet_prelude::OriginFor; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::call] + impl Pallet { + #[pallet::weight(0)] + pub fn foo(_: OriginFor) -> DispatchResult { + Ok(()) + } + } +} + +fn main() { +} diff --git a/frame/support/test/tests/pallet_ui/call_missing_index.stderr b/frame/support/test/tests/pallet_ui/call_missing_index.stderr new file mode 100644 index 0000000000000..9d00204979211 --- /dev/null +++ b/frame/support/test/tests/pallet_ui/call_missing_index.stderr @@ -0,0 +1,12 @@ +error: use of deprecated struct `pallet::warnings::foo`: + Implicit call indices are deprecated in favour of explicit ones. + Please ensure that all calls have the `pallet::call_index` attribute or that the + `dev-mode` of the pallet is enabled. For more info see: + and + . + --> tests/pallet_ui/call_missing_index.rs:15:10 + | +15 | pub fn foo(_: OriginFor) -> DispatchResult { + | ^^^ + | + = note: `-D deprecated` implied by `-D warnings` 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 a5ec31a9bb4e7..170555665d877 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 @@ -1,3 +1,16 @@ +error: use of deprecated struct `pallet::warnings::my_call`: + Implicit call indices are deprecated in favour of explicit ones. + Please ensure that all calls have the `pallet::call_index` attribute or that the + `dev-mode` of the pallet is enabled. For more info see: + and + . + --> tests/pallet_ui/dev_mode_without_arg_max_encoded_len.rs:25:10 + | +25 | pub fn my_call(_origin: OriginFor) -> DispatchResult { + | ^^^^^^^ + | + = note: `-D deprecated` implied by `-D warnings` + error[E0277]: the trait bound `Vec: MaxEncodedLen` is not satisfied --> tests/pallet_ui/dev_mode_without_arg_max_encoded_len.rs:11:12 | From 47ebf8742144e1b18414ecf97f43c16de624a180 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, 15 Dec 2022 09:19:50 -0300 Subject: [PATCH 196/715] increase timeout for publishing (#12934) necessary when lots of crates need to be published, as demonstrated by https://gitlab.parity.io/parity/mirrors/substrate/-/jobs/2158667 --- scripts/ci/gitlab/pipeline/publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/ci/gitlab/pipeline/publish.yml b/scripts/ci/gitlab/pipeline/publish.yml index 6a0d6d6341304..68a10e8aa1ddd 100644 --- a/scripts/ci/gitlab/pipeline/publish.yml +++ b/scripts/ci/gitlab/pipeline/publish.yml @@ -211,7 +211,7 @@ update-node-template: # 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 + timeout: 9h # A custom publishing environment is used for us to be able to set up protected secrets # specifically for it environment: publish-crates From f050628b6763176da175ab90d641c3eef608c610 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Thu, 15 Dec 2022 14:06:58 +0100 Subject: [PATCH 197/715] Node template isn't licensed, remove left-over GPL header (#12937) --- bin/node-template/node/src/benchmarking.rs | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/bin/node-template/node/src/benchmarking.rs b/bin/node-template/node/src/benchmarking.rs index 480e547c9c73c..37e0e465969de 100644 --- a/bin/node-template/node/src/benchmarking.rs +++ b/bin/node-template/node/src/benchmarking.rs @@ -1,21 +1,3 @@ -// 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 . - //! Setup code for [`super::command`] which would otherwise bloat that module. //! //! Should only be used for benchmarking as it may break in other contexts. From 5d3624c7fb7648d6f3170007790e95e726d84f35 Mon Sep 17 00:00:00 2001 From: bernardo Date: Fri, 16 Dec 2022 05:49:36 -0300 Subject: [PATCH 198/715] improve ocw validator/collator CLI description (#12931) * improve ocw validator/collator CLI description * rename WhenValidating to WhenAuthoring * Update client/cli/src/arg_enums.rs Co-authored-by: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Co-authored-by: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> --- client/cli/src/arg_enums.rs | 5 +++-- client/cli/src/params/offchain_worker_params.rs | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/client/cli/src/arg_enums.rs b/client/cli/src/arg_enums.rs index 20f68bc7fb55e..372e8645e30cc 100644 --- a/client/cli/src/arg_enums.rs +++ b/client/cli/src/arg_enums.rs @@ -232,8 +232,9 @@ pub enum OffchainWorkerEnabled { Always, /// Never enable the offchain worker. Never, - /// Only enable the offchain worker when running as validator. - WhenValidating, + /// Only enable the offchain worker when running as a validator (or collator, if this is a + /// parachain node). + WhenAuthority, } /// Syncing mode. diff --git a/client/cli/src/params/offchain_worker_params.rs b/client/cli/src/params/offchain_worker_params.rs index a660320fde255..b18e036c06de5 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", value_enum, ignore_case = true, - default_value_t = OffchainWorkerEnabled::WhenValidating + default_value_t = OffchainWorkerEnabled::WhenAuthority )] pub enabled: OffchainWorkerEnabled, @@ -56,10 +56,10 @@ impl OffchainWorkerParams { /// Load spec to `Configuration` from `OffchainWorkerParams` and spec factory. pub fn offchain_worker(&self, role: &Role) -> error::Result { let enabled = match (&self.enabled, role) { - (OffchainWorkerEnabled::WhenValidating, Role::Authority { .. }) => true, + (OffchainWorkerEnabled::WhenAuthority, Role::Authority { .. }) => true, (OffchainWorkerEnabled::Always, _) => true, (OffchainWorkerEnabled::Never, _) => false, - (OffchainWorkerEnabled::WhenValidating, _) => false, + (OffchainWorkerEnabled::WhenAuthority, _) => false, }; let indexing_enabled = self.indexing_enabled; From 8ef806c40eb58803d64328250b9e60a7d1170504 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, 16 Dec 2022 09:29:55 -0300 Subject: [PATCH 199/715] Set WASM_BUILD_WORKSPACE_HINT before starting CI jobs (#12816) * set WASM_BUILD_WORKSPACE_HINT this enables wasm-builder to find the Cargo.lock from within generated packages * wip: try out https://github.com/paritytech/pipeline-scripts/pull/90 * wip: fixup * wip * revert ci skip * set up WASM_BUILD_WORKSPACE_HINT for .kubernetes-env as well * 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> --- .gitlab-ci.yml | 13 +++++++++++-- scripts/ci/gitlab/pipeline/publish.yml | 2 +- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index dcc0cbb7c9693..145a25c809565 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -81,6 +81,15 @@ default: paths: - artifacts/ +.prepare-env: + before_script: + # TODO: remove unset invocation when we'll be free from 'ENV RUSTC_WRAPPER=sccache' & sccache + # itself in all images + - unset RUSTC_WRAPPER + # $WASM_BUILD_WORKSPACE_HINT enables wasm-builder to find the Cargo.lock from within generated + # packages + - export WASM_BUILD_WORKSPACE_HINT="$PWD" + .job-switcher: before_script: - if echo "$CI_DISABLED_JOBS" | grep -xF "$CI_JOB_NAME"; then echo "The job has been cancelled in CI settings"; exit 0; fi @@ -89,6 +98,7 @@ default: image: "${CI_IMAGE}" before_script: - !reference [.job-switcher, before_script] + - !reference [.prepare-env, before_script] tags: - kubernetes-parity-build @@ -115,9 +125,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 [.job-switcher, before_script] + - !reference [.prepare-env, before_script] - !reference [.rust-info-script, script] - !reference [.rusty-cachier, before_script] - !reference [.pipeline-stopper-vars, script] diff --git a/scripts/ci/gitlab/pipeline/publish.yml b/scripts/ci/gitlab/pipeline/publish.yml index 68a10e8aa1ddd..f2fd64bc34d73 100644 --- a/scripts/ci/gitlab/pipeline/publish.yml +++ b/scripts/ci/gitlab/pipeline/publish.yml @@ -12,7 +12,7 @@ DOCKERFILE: $PRODUCT.Dockerfile IMAGE_NAME: docker.io/$IMAGE_PATH before_script: - - !reference [.job-switcher, before_script] + - !reference [.kubernetes-env, before_script] - cd ./artifacts/$PRODUCT/ - VERSION="$(cat ./VERSION)" - echo "${PRODUCT} version = ${VERSION}" From d57f8a9f96e66bb23f74a6ad59d009c6564fc151 Mon Sep 17 00:00:00 2001 From: Dmitry Markin Date: Fri, 16 Dec 2022 16:29:39 +0300 Subject: [PATCH 200/715] Clean up tests from `runtime.block_on()` and moving around `Runtime` and `Handle` (#12941) --- client/beefy/src/aux_schema.rs | 8 +- client/beefy/src/tests.rs | 269 ++++------ client/beefy/src/worker.rs | 44 +- client/consensus/aura/src/lib.rs | 61 +-- client/consensus/babe/src/tests.rs | 295 +++++----- client/finality-grandpa/src/tests.rs | 292 +++++----- client/network-gossip/src/bridge.rs | 2 +- .../notifications/upgrade/notifications.rs | 185 +++---- .../network/src/service/tests/chain_sync.rs | 19 +- client/network/src/service/tests/mod.rs | 33 +- client/network/src/service/tests/service.rs | 352 ++++++------ client/network/test/src/lib.rs | 63 +-- client/network/test/src/sync.rs | 503 +++++++++--------- 13 files changed, 987 insertions(+), 1139 deletions(-) diff --git a/client/beefy/src/aux_schema.rs b/client/beefy/src/aux_schema.rs index 9d6a4292f32d4..67deee19b58b0 100644 --- a/client/beefy/src/aux_schema.rs +++ b/client/beefy/src/aux_schema.rs @@ -77,7 +77,6 @@ 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 { @@ -85,10 +84,9 @@ pub(crate) mod tests { version == CURRENT_VERSION } - #[test] - fn should_load_persistent_sanity_checks() { - let runtime = Runtime::new().unwrap(); - let mut net = BeefyTestNet::new(runtime.handle().clone(), 1); + #[tokio::test] + async 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 diff --git a/client/beefy/src/tests.rs b/client/beefy/src/tests.rs index f6ab0dd1020f1..d2befc979b737 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, WithRuntime, + PeersFullClient, TestNetFactory, }; use sc_utils::notification::NotificationReceiver; use serde::{Deserialize, Serialize}; @@ -64,10 +64,7 @@ use sp_runtime::{ }; use std::{collections::HashMap, marker::PhantomData, sync::Arc, task::Poll}; use substrate_test_runtime_client::{runtime::Header, ClientExt}; -use tokio::{ - runtime::{Handle, Runtime}, - time::Duration, -}; +use tokio::time::Duration; const GENESIS_HASH: H256 = H256::zero(); fn beefy_gossip_proto_name() -> ProtocolName { @@ -106,23 +103,14 @@ 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(rt_handle: Handle, n_authority: usize) -> Self { - let mut net = BeefyTestNet::with_runtime(rt_handle); + 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); @@ -151,13 +139,12 @@ impl BeefyTestNet { }); } - pub(crate) fn generate_blocks_and_sync( + pub(crate) async fn generate_blocks_and_sync( &mut self, count: usize, 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; @@ -175,7 +162,7 @@ impl BeefyTestNet { block }); - runtime.block_on(self.wait_until_sync()); + self.run_until_sync().await; } } @@ -404,17 +391,16 @@ where tasks.for_each(|_| async move {}) } -fn block_until(future: impl Future + Unpin, net: &Arc>, runtime: &mut Runtime) { +async fn run_until(future: impl Future + Unpin, net: &Arc>) { let drive_to_completion = futures::future::poll_fn(|cx| { net.lock().poll(cx); Poll::<()>::Pending }); - runtime.block_on(future::select(future, drive_to_completion)); + let _ = future::select(future, drive_to_completion).await; } -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); +async fn run_for(duration: Duration, net: &Arc>) { + run_until(Box::pin(tokio::time::sleep(duration)), net).await; } pub(crate) fn get_beefy_streams( @@ -435,10 +421,9 @@ pub(crate) fn get_beefy_streams( (best_block_streams, versioned_finality_proof_streams) } -fn wait_for_best_beefy_blocks( +async fn wait_for_best_beefy_blocks( streams: Vec>, net: &Arc>, - runtime: &mut Runtime, expected_beefy_blocks: &[u64], ) { let mut wait_for = Vec::new(); @@ -458,13 +443,12 @@ fn wait_for_best_beefy_blocks( }))); }); let wait_for = futures::future::join_all(wait_for); - block_until(wait_for, net, runtime); + run_until(wait_for, net).await; } -fn wait_for_beefy_signed_commitments( +async fn wait_for_beefy_signed_commitments( streams: Vec>>, net: &Arc>, - runtime: &mut Runtime, expected_commitment_block_nums: &[u64], ) { let mut wait_for = Vec::new(); @@ -484,34 +468,33 @@ fn wait_for_beefy_signed_commitments( }))); }); let wait_for = futures::future::join_all(wait_for); - block_until(wait_for, net, runtime); + run_until(wait_for, net).await; } -fn streams_empty_after_timeout( +async 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); + run_for(timeout, net).await; } - streams.into_iter().for_each(|mut stream| { - runtime.block_on(future::poll_fn(move |cx| { + for mut stream in streams.into_iter() { + future::poll_fn(move |cx| { assert_eq!(stream.poll_next_unpin(cx), Poll::Pending); Poll::Ready(()) - })); - }); + }) + .await; + } } -fn finalize_block_and_wait_for_beefy( +async fn finalize_block_and_wait_for_beefy( net: &Arc>, // peer index and key peers: impl Iterator + Clone, - runtime: &mut Runtime, finalize_targets: &[u64], expected_beefy: &[u64], ) { @@ -528,33 +511,32 @@ fn finalize_block_and_wait_for_beefy( if expected_beefy.is_empty() { // 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(versioned_finality_proof, &net, runtime, None); + streams_empty_after_timeout(best_blocks, &net, timeout).await; + streams_empty_after_timeout(versioned_finality_proof, &net, None).await; } else { // run until expected beefy blocks are received - wait_for_best_beefy_blocks(best_blocks, &net, runtime, expected_beefy); - wait_for_beefy_signed_commitments(versioned_finality_proof, &net, runtime, expected_beefy); + wait_for_best_beefy_blocks(best_blocks, &net, expected_beefy).await; + wait_for_beefy_signed_commitments(versioned_finality_proof, &net, expected_beefy).await; } } -#[test] -fn beefy_finalizing_blocks() { +#[tokio::test] +async 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(runtime.handle().clone(), 2); + 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)); + tokio::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, &mut runtime); + net.generate_blocks_and_sync(42, session_len, &validator_set, true).await; let net = Arc::new(Mutex::new(net)); @@ -562,51 +544,44 @@ 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, &[1, 5], &[1, 5]); + finalize_block_and_wait_for_beefy(&net, peers.clone(), &[1, 5], &[1, 5]).await; // GRANDPA finalize #10 -> BEEFY finalize #10 (mandatory) - finalize_block_and_wait_for_beefy(&net, peers.clone(), &mut runtime, &[10], &[10]); + finalize_block_and_wait_for_beefy(&net, peers.clone(), &[10], &[10]).await; // GRANDPA finalize #18 -> BEEFY finalize #14, then #18 (diff-power-of-two rule) - finalize_block_and_wait_for_beefy(&net, peers.clone(), &mut runtime, &[18], &[14, 18]); + finalize_block_and_wait_for_beefy(&net, peers.clone(), &[18], &[14, 18]).await; // GRANDPA finalize #20 -> BEEFY finalize #20 (mandatory) - finalize_block_and_wait_for_beefy(&net, peers.clone(), &mut runtime, &[20], &[20]); + finalize_block_and_wait_for_beefy(&net, peers.clone(), &[20], &[20]).await; // GRANDPA finalize #21 -> BEEFY finalize nothing (yet) because min delta is 4 - finalize_block_and_wait_for_beefy(&net, peers, &mut runtime, &[21], &[]); + finalize_block_and_wait_for_beefy(&net, peers, &[21], &[]).await; } -#[test] -fn lagging_validators() { +#[tokio::test] +async 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 session_len = 30; let min_block_delta = 1; - let mut net = BeefyTestNet::new(runtime.handle().clone(), 2); + 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)); + tokio::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, &mut runtime); + net.generate_blocks_and_sync(62, session_len, &validator_set, true).await; 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.clone(), - &mut runtime, - &[1, 15], - &[1, 9, 13, 14, 15], - ); + finalize_block_and_wait_for_beefy(&net, peers.clone(), &[1, 15], &[1, 9, 13, 14, 15]).await; // Alice finalizes #25, Bob lags behind let finalize = net @@ -620,18 +595,18 @@ fn lagging_validators() { 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(versioned_finality_proof, &net, &mut runtime, None); + streams_empty_after_timeout(best_blocks, &net, timeout).await; + streams_empty_after_timeout(versioned_finality_proof, &net, None).await; // 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(); // 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]); + wait_for_best_beefy_blocks(best_blocks, &net, &[23, 24, 25]).await; + wait_for_beefy_signed_commitments(versioned_finality_proof, &net, &[23, 24, 25]).await; // Both finalize #30 (mandatory session) and #32 -> BEEFY finalize #30 (mandatory), #31, #32 - finalize_block_and_wait_for_beefy(&net, peers.clone(), &mut runtime, &[30, 32], &[30, 31, 32]); + finalize_block_and_wait_for_beefy(&net, peers.clone(), &[30, 32], &[30, 31, 32]).await; // 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 @@ -649,28 +624,27 @@ fn lagging_validators() { 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(versioned_finality_proof, &net, &mut runtime, None); + streams_empty_after_timeout(best_blocks, &net, timeout).await; + streams_empty_after_timeout(versioned_finality_proof, &net, None).await; // 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 #60 - wait_for_best_beefy_blocks(best_blocks, &net, &mut runtime, &[60]); - wait_for_beefy_signed_commitments(versioned_finality_proof, &net, &mut runtime, &[60]); + wait_for_best_beefy_blocks(best_blocks, &net, &[60]).await; + wait_for_beefy_signed_commitments(versioned_finality_proof, &net, &[60]).await; } -#[test] -fn correct_beefy_payload() { +#[tokio::test] +async 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(runtime.handle().clone(), 4); + let mut net = BeefyTestNet::new(4); // Alice, Bob, Charlie will vote on good payloads let good_api = Arc::new(four_validators::TestApi {}); @@ -679,20 +653,20 @@ fn correct_beefy_payload() { .enumerate() .map(|(id, key)| (id, key, good_api.clone())) .collect(); - runtime.spawn(initialize_beefy(&mut net, good_peers, min_block_delta)); + tokio::spawn(initialize_beefy(&mut net, good_peers, min_block_delta)); // Dave will vote on bad mmr roots 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)); + tokio::spawn(initialize_beefy(&mut net, bad_peers, min_block_delta)); // push 12 blocks - net.generate_blocks_and_sync(12, session_len, &validator_set, false, &mut runtime); + net.generate_blocks_and_sync(12, session_len, &validator_set, false).await; 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, &[1, 10], &[1, 9]); + finalize_block_and_wait_for_beefy(&net, peers, &[1, 10], &[1, 9]).await; let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), [(0, BeefyKeyring::Alice)].into_iter()); @@ -711,8 +685,8 @@ 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(versioned_finality_proof, &net, &mut runtime, None); + streams_empty_after_timeout(best_blocks, &net, timeout).await; + streams_empty_after_timeout(versioned_finality_proof, &net, None).await; // 3rd good validator catches up and votes as well let (best_blocks, versioned_finality_proof) = @@ -720,21 +694,19 @@ fn correct_beefy_payload() { 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]); - wait_for_beefy_signed_commitments(versioned_finality_proof, &net, &mut runtime, &[11]); + wait_for_best_beefy_blocks(best_blocks, &net, &[11]).await; + wait_for_beefy_signed_commitments(versioned_finality_proof, &net, &[11]).await; } -#[test] -fn beefy_importing_blocks() { +#[tokio::test] +async fn beefy_importing_blocks() { use futures::{future::poll_fn, task::Poll}; use sc_block_builder::BlockBuilderProvider; use sc_client_api::BlockBackend; sp_tracing::try_init_simple(); - let runtime = Runtime::new().unwrap(); - - let mut net = BeefyTestNet::new(runtime.handle().clone(), 2); + 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()); @@ -759,16 +731,15 @@ fn beefy_importing_blocks() { // Import without justifications. let mut justif_recv = justif_stream.subscribe(); assert_eq!( - runtime - .block_on(block_import.import_block(params(block.clone(), None), HashMap::new())) + block_import + .import_block(params(block.clone(), None), HashMap::new()) + .await .unwrap(), ImportResult::Imported(ImportedAux { is_new_best: true, ..Default::default() }), ); assert_eq!( - runtime - .block_on(block_import.import_block(params(block, None), HashMap::new())) - .unwrap(), - ImportResult::AlreadyInChain + block_import.import_block(params(block, None), HashMap::new()).await.unwrap(), + ImportResult::AlreadyInChain, ); // Verify no BEEFY justifications present: { @@ -781,10 +752,11 @@ fn beefy_importing_blocks() { None ); // and none sent to BEEFY worker. - runtime.block_on(poll_fn(move |cx| { + poll_fn(move |cx| { assert_eq!(justif_recv.poll_next_unpin(cx), Poll::Pending); Poll::Ready(()) - })); + }) + .await; } // Import with valid justification. @@ -802,9 +774,7 @@ fn beefy_importing_blocks() { let hashof2 = block.header.hash(); let mut justif_recv = justif_stream.subscribe(); assert_eq!( - runtime - .block_on(block_import.import_block(params(block, justif), HashMap::new())) - .unwrap(), + block_import.import_block(params(block, justif), HashMap::new()).await.unwrap(), ImportResult::Imported(ImportedAux { bad_justification: false, is_new_best: true, @@ -823,13 +793,14 @@ fn beefy_importing_blocks() { ); // but sent to BEEFY worker // (worker will append it to backend when all previous mandatory justifs are there as well). - runtime.block_on(poll_fn(move |cx| { + poll_fn(move |cx| { match justif_recv.poll_next_unpin(cx) { Poll::Ready(Some(_justification)) => (), v => panic!("unexpected value: {:?}", v), } Poll::Ready(()) - })); + }) + .await; } // Import with invalid justification (incorrect validator set). @@ -847,9 +818,7 @@ fn beefy_importing_blocks() { let hashof3 = block.header.hash(); let mut justif_recv = justif_stream.subscribe(); assert_eq!( - runtime - .block_on(block_import.import_block(params(block, justif), HashMap::new())) - .unwrap(), + block_import.import_block(params(block, justif), HashMap::new()).await.unwrap(), ImportResult::Imported(ImportedAux { // Still `false` because we don't want to fail import on bad BEEFY justifications. bad_justification: false, @@ -868,33 +837,33 @@ fn beefy_importing_blocks() { None ); // and none sent to BEEFY worker. - runtime.block_on(poll_fn(move |cx| { + poll_fn(move |cx| { assert_eq!(justif_recv.poll_next_unpin(cx), Poll::Pending); Poll::Ready(()) - })); + }) + .await; } } -#[test] -fn voter_initialization() { +#[tokio::test] +async 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(runtime.handle().clone(), 2); + 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)); + tokio::spawn(initialize_beefy(&mut net, beefy_peers, min_block_delta)); // push 26 blocks - net.generate_blocks_and_sync(26, session_len, &validator_set, false, &mut runtime); + net.generate_blocks_and_sync(26, session_len, &validator_set, false).await; let net = Arc::new(Mutex::new(net)); // Finalize multiple blocks at once to get a burst of finality notifications right from start. @@ -903,31 +872,30 @@ fn voter_initialization() { finalize_block_and_wait_for_beefy( &net, peers.into_iter().enumerate(), - &mut runtime, &[1, 6, 10, 17, 24, 26], &[1, 5, 10, 15, 20, 25], - ); + ) + .await; } -#[test] -fn on_demand_beefy_justification_sync() { +#[tokio::test] +async 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(runtime.handle().clone(), 4); + 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)); + tokio::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). @@ -937,7 +905,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, &mut runtime); + net.generate_blocks_and_sync(30, session_len, &validator_set, false).await; let fast_peers = fast_peers.into_iter().enumerate(); let net = Arc::new(Mutex::new(net)); @@ -946,15 +914,15 @@ fn on_demand_beefy_justification_sync() { finalize_block_and_wait_for_beefy( &net, fast_peers.clone(), - &mut runtime, &[1, 6, 10, 17, 24], &[1, 5, 10, 15, 20], - ); + ) + .await; // Spawn Dave, he's now way behind voting and can only catch up through on-demand justif sync. - runtime.spawn(dave_task); + tokio::spawn(dave_task); // give Dave a chance to spawn and init. - run_for(Duration::from_millis(400), &net, &mut runtime); + run_for(Duration::from_millis(400), &net).await; let (dave_best_blocks, _) = get_beefy_streams(&mut net.lock(), [(dave_index, BeefyKeyring::Dave)].into_iter()); @@ -962,41 +930,40 @@ fn on_demand_beefy_justification_sync() { 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); + run_for(Duration::from_millis(100), &net).await; // 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]); + finalize_block_and_wait_for_beefy(&net, fast_peers, &[25], &[25]).await; // Now verify Dave successfully finalized #1 (through on-demand justification request). - wait_for_best_beefy_blocks(dave_best_blocks, &net, &mut runtime, &[1]); + wait_for_best_beefy_blocks(dave_best_blocks, &net, &[1]).await; // Give Dave all tasks some cpu cycles to burn through their events queues, - run_for(Duration::from_millis(100), &net, &mut runtime); + run_for(Duration::from_millis(100), &net).await; // 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], - ); + ) + .await; 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]); + finalize_block_and_wait_for_beefy(&net, all_peers, &[30], &[30]).await; } -#[test] -fn should_initialize_voter_at_genesis() { +#[tokio::test] +async fn should_initialize_voter_at_genesis() { let keys = &[BeefyKeyring::Alice]; let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); - let mut runtime = Runtime::new().unwrap(); - let mut net = BeefyTestNet::new(runtime.handle().clone(), 1); + 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, &mut runtime); + net.generate_blocks_and_sync(15, 10, &validator_set, false).await; let mut finality = net.peer(0).client().as_client().finality_notification_stream().fuse(); @@ -1033,16 +1000,15 @@ fn should_initialize_voter_at_genesis() { assert_eq!(state, persisted_state); } -#[test] -fn should_initialize_voter_when_last_final_is_session_boundary() { +#[tokio::test] +async 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 runtime = Runtime::new().unwrap(); - let mut net = BeefyTestNet::new(runtime.handle().clone(), 1); + 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, &mut runtime); + net.generate_blocks_and_sync(15, 10, &validator_set, false).await; let mut finality = net.peer(0).client().as_client().finality_notification_stream().fuse(); @@ -1094,16 +1060,15 @@ fn should_initialize_voter_when_last_final_is_session_boundary() { assert_eq!(state, persisted_state); } -#[test] -fn should_initialize_voter_at_latest_finalized() { +#[tokio::test] +async fn should_initialize_voter_at_latest_finalized() { let keys = &[BeefyKeyring::Alice]; let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); - let mut runtime = Runtime::new().unwrap(); - let mut net = BeefyTestNet::new(runtime.handle().clone(), 1); + 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, &mut runtime); + net.generate_blocks_and_sync(15, 10, &validator_set, false).await; 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 bba3563a8f70e..df465b2dbf52c 100644 --- a/client/beefy/src/worker.rs +++ b/client/beefy/src/worker.rs @@ -983,7 +983,6 @@ pub(crate) mod tests { runtime::{Block, Digest, DigestItem, Header, H256}, Backend, }; - use tokio::runtime::Runtime; impl PersistedState { pub fn voting_oracle(&self) -> &VoterOracle { @@ -1295,12 +1294,11 @@ pub(crate) mod tests { assert_eq!(extracted, Some(validator_set)); } - #[test] - fn keystore_vs_validator_set() { + #[tokio::test] + async fn keystore_vs_validator_set() { let keys = &[Keyring::Alice]; let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); - let runtime = Runtime::new().unwrap(); - let mut net = BeefyTestNet::new(runtime.handle().clone(), 1); + let mut net = BeefyTestNet::new(1); let mut worker = create_beefy_worker(&net.peer(0), &keys[0], 1, validator_set.clone()); // keystore doesn't contain other keys than validators' @@ -1319,12 +1317,11 @@ pub(crate) mod tests { assert_eq!(worker.verify_validator_set(&1, &validator_set), expected_err); } - #[test] - fn should_finalize_correctly() { + #[tokio::test] + async fn should_finalize_correctly() { let keys = [Keyring::Alice]; let validator_set = ValidatorSet::new(make_beefy_ids(&keys), 0).unwrap(); - let runtime = Runtime::new().unwrap(); - let mut net = BeefyTestNet::new(runtime.handle().clone(), 1); + 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, validator_set.clone()); // remove default session, will manually add custom one. @@ -1347,11 +1344,12 @@ pub(crate) mod tests { // no 'best beefy block' or finality proofs assert_eq!(worker.best_beefy_block(), 0); - runtime.block_on(poll_fn(move |cx| { + 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(()) - })); + }) + .await; // unknown hash for block #1 let (mut best_block_streams, mut finality_proofs) = @@ -1368,7 +1366,7 @@ pub(crate) mod tests { worker.finalize(justif.clone()).unwrap(); // verify block finalized assert_eq!(worker.best_beefy_block(), 1); - runtime.block_on(poll_fn(move |cx| { + poll_fn(move |cx| { // unknown hash -> nothing streamed assert_eq!(best_block_stream.poll_next_unpin(cx), Poll::Pending); // commitment streamed @@ -1378,7 +1376,8 @@ pub(crate) mod tests { v => panic!("unexpected value: {:?}", v), } Poll::Ready(()) - })); + }) + .await; // generate 2 blocks, try again expect success let (mut best_block_streams, _) = get_beefy_streams(&mut net, keys); @@ -1400,7 +1399,7 @@ pub(crate) mod tests { assert_eq!(worker.active_rounds().unwrap().session_start(), 2); // verify block finalized assert_eq!(worker.best_beefy_block(), 2); - runtime.block_on(poll_fn(move |cx| { + poll_fn(move |cx| { match best_block_stream.poll_next_unpin(cx) { // expect Some(hash-of-block-2) Poll::Ready(Some(hash)) => { @@ -1410,19 +1409,19 @@ pub(crate) mod tests { v => panic!("unexpected value: {:?}", v), } Poll::Ready(()) - })); + }) + .await; // check BEEFY justifications are also appended to backend let justifs = backend.blockchain().justifications(hashof2).unwrap().unwrap(); assert!(justifs.get(BEEFY_ENGINE_ID).is_some()) } - #[test] - fn should_init_session() { + #[tokio::test] + async fn should_init_session() { let keys = &[Keyring::Alice, Keyring::Bob]; let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); - let runtime = Runtime::new().unwrap(); - let mut net = BeefyTestNet::new(runtime.handle().clone(), 1); + let mut net = BeefyTestNet::new(1); let mut worker = create_beefy_worker(&net.peer(0), &keys[0], 1, validator_set.clone()); let worker_rounds = worker.active_rounds().unwrap(); @@ -1449,12 +1448,11 @@ pub(crate) mod tests { assert_eq!(rounds.validator_set_id(), new_validator_set.id()); } - #[test] - fn should_triage_votes_and_process_later() { + #[tokio::test] + async 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 runtime = Runtime::new().unwrap(); - let mut net = BeefyTestNet::new(runtime.handle().clone(), 1); + let mut net = BeefyTestNet::new(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/consensus/aura/src/lib.rs b/client/consensus/aura/src/lib.rs index a8ed80d7c0432..212376dcd009c 100644 --- a/client/consensus/aura/src/lib.rs +++ b/client/consensus/aura/src/lib.rs @@ -660,7 +660,6 @@ mod tests { runtime::{Header, H256}, TestClient, }; - use tokio::runtime::{Handle, Runtime}; const SLOT_DURATION_MS: u64 = 1000; @@ -718,20 +717,11 @@ 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 = (); @@ -780,11 +770,10 @@ mod tests { } } - #[test] - fn authoring_blocks() { + #[tokio::test] + async fn authoring_blocks() { sp_tracing::try_init_simple(); - let runtime = Runtime::new().unwrap(); - let net = AuraTestNet::new(runtime.handle().clone(), 3); + let net = AuraTestNet::new(3); let peers = &[(0, Keyring::Alice), (1, Keyring::Bob), (2, Keyring::Charlie)]; @@ -850,13 +839,14 @@ mod tests { ); } - runtime.block_on(future::select( + future::select( future::poll_fn(move |cx| { net.lock().poll(cx); Poll::<()>::Pending }), future::select(future::join_all(aura_futures), future::join_all(import_notifications)), - )); + ) + .await; } #[test] @@ -875,10 +865,9 @@ mod tests { ); } - #[test] - fn current_node_authority_should_claim_slot() { - let runtime = Runtime::new().unwrap(); - let net = AuraTestNet::new(runtime.handle().clone(), 4); + #[tokio::test] + async fn current_node_authority_should_claim_slot() { + let net = AuraTestNet::new(4); let mut authorities = vec![ Keyring::Alice.public().into(), @@ -922,20 +911,19 @@ mod tests { Default::default(), Default::default(), ); - 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()); + assert!(worker.claim_slot(&head, 0.into(), &authorities).await.is_none()); + assert!(worker.claim_slot(&head, 1.into(), &authorities).await.is_none()); + assert!(worker.claim_slot(&head, 2.into(), &authorities).await.is_none()); + assert!(worker.claim_slot(&head, 3.into(), &authorities).await.is_some()); + assert!(worker.claim_slot(&head, 4.into(), &authorities).await.is_none()); + assert!(worker.claim_slot(&head, 5.into(), &authorities).await.is_none()); + assert!(worker.claim_slot(&head, 6.into(), &authorities).await.is_none()); + assert!(worker.claim_slot(&head, 7.into(), &authorities).await.is_some()); } - #[test] - fn on_slot_returns_correct_block() { - let runtime = Runtime::new().unwrap(); - let net = AuraTestNet::new(runtime.handle().clone(), 4); + #[tokio::test] + async fn on_slot_returns_correct_block() { + let net = AuraTestNet::new(4); let keystore_path = tempfile::tempdir().expect("Creates keystore path"); let keystore = LocalKeystore::open(keystore_path.path(), None).expect("Creates keystore."); @@ -971,15 +959,16 @@ mod tests { let head = client.header(&BlockId::Number(0)).unwrap().unwrap(); - let res = runtime - .block_on(worker.on_slot(SlotInfo { + let res = 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, - })) + }) + .await .unwrap(); // The returned block should be imported and we should be able to get its header by now. diff --git a/client/consensus/babe/src/tests.rs b/client/consensus/babe/src/tests.rs index d7691235a550d..6861379ebbeb5 100644 --- a/client/consensus/babe/src/tests.rs +++ b/client/consensus/babe/src/tests.rs @@ -49,7 +49,6 @@ use sp_runtime::{ }; use sp_timestamp::Timestamp; use std::{cell::RefCell, task::Poll, time::Duration}; -use tokio::runtime::{Handle, Runtime}; type Item = DigestItem; @@ -227,20 +226,11 @@ 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 = @@ -366,12 +356,11 @@ impl TestNetFactory for BabeTestNet { } } -#[test] +#[tokio::test] #[should_panic] -fn rejects_empty_block() { +async fn rejects_empty_block() { sp_tracing::try_init_simple(); - let runtime = Runtime::new().unwrap(); - let mut net = BabeTestNet::new(runtime.handle().clone(), 3); + let mut net = BabeTestNet::new(3); let block_builder = |builder: BlockBuilder<_, _, _>| builder.build().unwrap().block; net.mut_peers(|peer| { peer[0].generate_blocks(1, BlockOrigin::NetworkInitialSync, block_builder); @@ -385,14 +374,13 @@ fn create_keystore(authority: Sr25519Keyring) -> SyncCryptoStorePtr { keystore } -fn run_one_test(mutator: impl Fn(&mut TestHeader, Stage) + Send + Sync + 'static) { +async 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; MUTATOR.with(|m| *m.borrow_mut() = mutator.clone()); - let runtime = Runtime::new().unwrap(); - let net = BabeTestNet::new(runtime.handle().clone(), 3); + let net = BabeTestNet::new(3); let peers = [Sr25519Keyring::Alice, Sr25519Keyring::Bob, Sr25519Keyring::Charlie]; @@ -469,7 +457,7 @@ fn run_one_test(mutator: impl Fn(&mut TestHeader, Stage) + Send + Sync + 'static .expect("Starts babe"), ); } - runtime.block_on(future::select( + future::select( futures::future::poll_fn(move |cx| { let mut net = net.lock(); net.poll(cx); @@ -482,17 +470,18 @@ fn run_one_test(mutator: impl Fn(&mut TestHeader, Stage) + Send + Sync + 'static Poll::<()>::Pending }), future::select(future::join_all(import_notifications), future::join_all(babe_futures)), - )); + ) + .await; } -#[test] -fn authoring_blocks() { - run_one_test(|_, _| ()) +#[tokio::test] +async fn authoring_blocks() { + run_one_test(|_, _| ()).await; } -#[test] +#[tokio::test] #[should_panic] -fn rejects_missing_inherent_digest() { +async fn rejects_missing_inherent_digest() { run_one_test(|header: &mut TestHeader, stage| { let v = std::mem::take(&mut header.digest_mut().logs); header.digest_mut().logs = v @@ -500,11 +489,12 @@ fn rejects_missing_inherent_digest() { .filter(|v| stage == Stage::PostSeal || v.as_babe_pre_digest().is_none()) .collect() }) + .await; } -#[test] +#[tokio::test] #[should_panic] -fn rejects_missing_seals() { +async fn rejects_missing_seals() { run_one_test(|header: &mut TestHeader, stage| { let v = std::mem::take(&mut header.digest_mut().logs); header.digest_mut().logs = v @@ -512,18 +502,20 @@ fn rejects_missing_seals() { .filter(|v| stage == Stage::PreSeal || v.as_babe_seal().is_none()) .collect() }) + .await; } -#[test] +#[tokio::test] #[should_panic] -fn rejects_missing_consensus_digests() { +async fn rejects_missing_consensus_digests() { run_one_test(|header: &mut TestHeader, stage| { let v = std::mem::take(&mut header.digest_mut().logs); header.digest_mut().logs = v .into_iter() .filter(|v| stage == Stage::PostSeal || v.as_next_epoch_descriptor().is_none()) .collect() - }); + }) + .await; } #[test] @@ -601,14 +593,13 @@ fn can_author_block() { } // Propose and import a new BABE block on top of the given parent. -fn propose_and_import_block( +async fn propose_and_import_block( parent: &TestHeader, slot: Option, proposer_factory: &mut DummyFactory, block_import: &mut BoxBlockImport, - runtime: &Runtime, ) -> Hash { - let mut proposer = runtime.block_on(proposer_factory.init(parent)).unwrap(); + let mut proposer = proposer_factory.init(parent).await.unwrap(); let slot = slot.unwrap_or_else(|| { let parent_pre_digest = find_pre_digest::(parent).unwrap(); @@ -624,7 +615,7 @@ fn propose_and_import_block( let parent_hash = parent.hash(); - let mut block = runtime.block_on(proposer.propose_with(pre_digest)).unwrap().block; + let mut block = proposer.propose_with(pre_digest).await.unwrap().block; let epoch_descriptor = proposer_factory .epoch_changes @@ -660,8 +651,7 @@ fn propose_and_import_block( import .insert_intermediate(INTERMEDIATE_KEY, BabeIntermediate:: { epoch_descriptor }); import.fork_choice = Some(ForkChoiceStrategy::LongestChain); - let import_result = - runtime.block_on(block_import.import_block(import, Default::default())).unwrap(); + let import_result = block_import.import_block(import, Default::default()).await.unwrap(); match import_result { ImportResult::Imported(_) => {}, @@ -674,20 +664,19 @@ fn propose_and_import_block( // 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( +async fn propose_and_import_blocks( client: &PeersFullClient, proposer_factory: &mut DummyFactory, 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, runtime); + propose_and_import_block(&parent_header, None, proposer_factory, block_import).await; hashes.push(block_hash); parent_header = client.header(&BlockId::Hash(block_hash)).unwrap().unwrap(); } @@ -695,10 +684,9 @@ fn propose_and_import_blocks( hashes } -#[test] -fn importing_block_one_sets_genesis_epoch() { - let runtime = Runtime::new().unwrap(); - let mut net = BabeTestNet::new(runtime.handle().clone(), 1); +#[tokio::test] +async fn importing_block_one_sets_genesis_epoch() { + let mut net = BabeTestNet::new(1); let peer = net.peer(0); let data = peer.data.as_ref().expect("babe link set up during initialization"); @@ -720,8 +708,8 @@ fn importing_block_one_sets_genesis_epoch() { Some(999.into()), &mut proposer_factory, &mut block_import, - &runtime, - ); + ) + .await; let genesis_epoch = Epoch::genesis(&data.link.config, 999.into()); @@ -736,10 +724,9 @@ 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 runtime = Runtime::new().unwrap(); - let mut net = BabeTestNet::new(runtime.handle().clone(), 1); +#[tokio::test] +async 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"); @@ -756,17 +743,6 @@ fn revert_prunes_epoch_changes_and_removes_weights() { 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, - &runtime, - ) - }; - // 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). @@ -779,10 +755,38 @@ fn revert_prunes_epoch_changes_and_removes_weights() { // \ 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); + let canon = propose_and_import_blocks( + &client, + &mut proposer_factory, + &mut block_import, + BlockId::Number(0), + 21, + ) + .await; + let fork1 = propose_and_import_blocks( + &client, + &mut proposer_factory, + &mut block_import, + BlockId::Hash(canon[0]), + 10, + ) + .await; + let fork2 = propose_and_import_blocks( + &client, + &mut proposer_factory, + &mut block_import, + BlockId::Hash(canon[7]), + 10, + ) + .await; + let fork3 = propose_and_import_blocks( + &client, + &mut proposer_factory, + &mut block_import, + BlockId::Hash(canon[11]), + 8, + ) + .await; // We should be tracking a total of 9 epochs in the fork tree assert_eq!(epoch_changes.shared_data().tree().iter().count(), 8); @@ -824,10 +828,9 @@ fn revert_prunes_epoch_changes_and_removes_weights() { assert!(weight_data_check(&fork3, false)); } -#[test] -fn revert_not_allowed_for_finalized() { - let runtime = Runtime::new().unwrap(); - let mut net = BabeTestNet::new(runtime.handle().clone(), 1); +#[tokio::test] +async 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"); @@ -843,18 +846,14 @@ fn revert_not_allowed_for_finalized() { 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, - &runtime, - ) - }; - - let canon = propose_and_import_blocks_wrap(BlockId::Number(0), 3); + let canon = propose_and_import_blocks( + &client, + &mut proposer_factory, + &mut block_import, + BlockId::Number(0), + 3, + ) + .await; // Finalize best block client.finalize_block(canon[2], None, false).unwrap(); @@ -870,10 +869,9 @@ fn revert_not_allowed_for_finalized() { assert!(weight_data_check(&canon, true)); } -#[test] -fn importing_epoch_change_block_prunes_tree() { - let runtime = Runtime::new().unwrap(); - let mut net = BabeTestNet::new(runtime.handle().clone(), 1); +#[tokio::test] +async fn importing_epoch_change_block_prunes_tree() { + let mut net = BabeTestNet::new(1); let peer = net.peer(0); let data = peer.data.as_ref().expect("babe link set up during initialization"); @@ -889,17 +887,6 @@ fn importing_epoch_change_block_prunes_tree() { 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, - &runtime, - ) - }; - // This is the block tree that we're going to use in this test. Each node // represents an epoch change block, the epoch duration is 6 slots. // @@ -912,12 +899,40 @@ 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 = propose_and_import_blocks_wrap(BlockId::Number(0), 30); + let canon = propose_and_import_blocks( + &client, + &mut proposer_factory, + &mut block_import, + BlockId::Number(0), + 30, + ) + .await; // Create the forks - 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); + let fork_1 = propose_and_import_blocks( + &client, + &mut proposer_factory, + &mut block_import, + BlockId::Hash(canon[0]), + 10, + ) + .await; + let fork_2 = propose_and_import_blocks( + &client, + &mut proposer_factory, + &mut block_import, + BlockId::Hash(canon[12]), + 15, + ) + .await; + let fork_3 = propose_and_import_blocks( + &client, + &mut proposer_factory, + &mut block_import, + BlockId::Hash(canon[18]), + 10, + ) + .await; // We should be tracking a total of 9 epochs in the fork tree assert_eq!(epoch_changes.shared_data().tree().iter().count(), 9); @@ -928,7 +943,14 @@ 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[12], None, false).unwrap(); - propose_and_import_blocks_wrap(BlockId::Hash(client.chain_info().best_hash), 7); + propose_and_import_blocks( + &client, + &mut proposer_factory, + &mut block_import, + BlockId::Hash(client.chain_info().best_hash), + 7, + ) + .await; let nodes: Vec<_> = epoch_changes.shared_data().tree().iter().map(|(h, _, _)| *h).collect(); @@ -941,7 +963,14 @@ fn importing_epoch_change_block_prunes_tree() { // finalizing block #25 from the canon chain should prune out the second fork client.finalize_block(canon[24], None, false).unwrap(); - propose_and_import_blocks_wrap(BlockId::Hash(client.chain_info().best_hash), 8); + propose_and_import_blocks( + &client, + &mut proposer_factory, + &mut block_import, + BlockId::Hash(client.chain_info().best_hash), + 8, + ) + .await; let nodes: Vec<_> = epoch_changes.shared_data().tree().iter().map(|(h, _, _)| *h).collect(); @@ -954,11 +983,10 @@ fn importing_epoch_change_block_prunes_tree() { assert!(nodes.iter().any(|h| *h == canon[24])); } -#[test] +#[tokio::test] #[should_panic] -fn verify_slots_are_strictly_increasing() { - let runtime = Runtime::new().unwrap(); - let mut net = BabeTestNet::new(runtime.handle().clone(), 1); +async fn verify_slots_are_strictly_increasing() { + let mut net = BabeTestNet::new(1); let peer = net.peer(0); let data = peer.data.as_ref().expect("babe link set up during initialization"); @@ -981,20 +1009,14 @@ fn verify_slots_are_strictly_increasing() { Some(999.into()), &mut proposer_factory, &mut block_import, - &runtime, - ); + ) + .await; 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, - &runtime, - ); + propose_and_import_block(&b1, Some(999.into()), &mut proposer_factory, &mut block_import).await; } #[test] @@ -1027,10 +1049,9 @@ fn babe_transcript_generation_match() { debug_assert!(test(orig_transcript) == test(transcript_from_data(new_transcript))); } -#[test] -fn obsolete_blocks_aux_data_cleanup() { - let runtime = Runtime::new().unwrap(); - let mut net = BabeTestNet::new(runtime.handle().clone(), 1); +#[tokio::test] +async 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"); @@ -1052,17 +1073,6 @@ 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, - &runtime, - ) - }; - let aux_data_check = |hashes: &[Hash], expected: bool| { hashes.iter().all(|hash| { aux_schema::load_block_weight(&*peer.client().as_backend(), hash) @@ -1077,9 +1087,30 @@ fn obsolete_blocks_aux_data_cleanup() { // 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(0), 2); - let fork3_hashes = propose_and_import_blocks_wrap(BlockId::Number(3), 2); + let fork1_hashes = propose_and_import_blocks( + &client, + &mut proposer_factory, + &mut block_import, + BlockId::Number(0), + 4, + ) + .await; + let fork2_hashes = propose_and_import_blocks( + &client, + &mut proposer_factory, + &mut block_import, + BlockId::Number(0), + 2, + ) + .await; + let fork3_hashes = propose_and_import_blocks( + &client, + &mut proposer_factory, + &mut block_import, + BlockId::Number(3), + 2, + ) + .await; // Check that aux data is present for all but the genesis block. assert!(aux_data_check(&[client.chain_info().genesis_hash], false)); diff --git a/client/finality-grandpa/src/tests.rs b/client/finality-grandpa/src/tests.rs index 6b577fd712930..97c0c9fe7ce49 100644 --- a/client/finality-grandpa/src/tests.rs +++ b/client/finality-grandpa/src/tests.rs @@ -30,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, WithRuntime, + PeersFullClient, TestClient, TestNetFactory, }; use sp_api::{ApiRef, ProvideRuntimeApi}; use sp_blockchain::Result; @@ -52,7 +52,7 @@ use std::{ pin::Pin, }; use substrate_test_runtime_client::runtime::BlockNumber; -use tokio::runtime::{Handle, Runtime}; +use tokio::runtime::Handle; use authorities::AuthoritySet; use communication::grandpa_protocol_name; @@ -71,26 +71,16 @@ 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, 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; + 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 }; for _ in 0..n_authority { net.add_authority_peer(); @@ -228,16 +218,12 @@ fn create_keystore(authority: Ed25519Keyring) -> SyncCryptoStorePtr { keystore } -fn block_until_complete( - future: impl Future + Unpin, - net: &Arc>, - runtime: &mut Runtime, -) { +async fn run_until_complete(future: impl Future + Unpin, net: &Arc>) { let drive_to_completion = futures::future::poll_fn(|cx| { net.lock().poll(cx); Poll::<()>::Pending }); - runtime.block_on(future::select(future, drive_to_completion)); + future::select(future, drive_to_completion).await; } // Spawns grandpa voters. Returns a future to spawn on the runtime. @@ -289,8 +275,7 @@ fn initialize_grandpa( // run the voters to completion. provide a closure to be invoked after // the voters are spawned but before blocking on them. -fn run_to_completion_with( - runtime: &mut Runtime, +async fn run_to_completion_with( blocks: u64, net: Arc>, peers: &[Ed25519Keyring], @@ -303,7 +288,7 @@ where let highest_finalized = Arc::new(RwLock::new(0)); - if let Some(f) = (with)(runtime.handle().clone()) { + if let Some(f) = (with)(Handle::current()) { wait_for.push(f); }; @@ -329,18 +314,17 @@ where // wait for all finalized on each. let wait_for = ::futures::future::join_all(wait_for); - block_until_complete(wait_for, &net, runtime); + run_until_complete(wait_for, &net).await; let highest_finalized = *highest_finalized.read(); highest_finalized } -fn run_to_completion( - runtime: &mut Runtime, +async fn run_to_completion( blocks: u64, net: Arc>, peers: &[Ed25519Keyring], ) -> u64 { - run_to_completion_with(runtime, blocks, net, peers, |_| None) + run_to_completion_with(blocks, net, peers, |_| None).await } fn add_scheduled_change(block: &mut Block, change: ScheduledChange) { @@ -361,17 +345,16 @@ fn add_forced_change( )); } -#[test] -fn finalize_3_voters_no_observers() { +#[tokio::test] +async fn finalize_3_voters_no_observers() { sp_tracing::try_init_simple(); - let mut runtime = Runtime::new().unwrap(); let peers = &[Ed25519Keyring::Alice, Ed25519Keyring::Bob, Ed25519Keyring::Charlie]; let voters = make_ids(peers); - let mut net = GrandpaTestNet::new(TestApi::new(voters), 3, 0, runtime.handle().clone()); - runtime.spawn(initialize_grandpa(&mut net, peers)); + let mut net = GrandpaTestNet::new(TestApi::new(voters), 3, 0); + tokio::spawn(initialize_grandpa(&mut net, peers)); net.peer(0).push_blocks(20, false); - runtime.block_on(net.wait_until_sync()); + net.run_until_sync().await; let hashof20 = net.peer(0).client().info().best_hash; for i in 0..3 { @@ -380,7 +363,7 @@ fn finalize_3_voters_no_observers() { } let net = Arc::new(Mutex::new(net)); - run_to_completion(&mut runtime, 20, net.clone(), peers); + run_to_completion(20, net.clone(), peers).await; // normally there's no justification for finalized blocks assert!( @@ -389,17 +372,15 @@ fn finalize_3_voters_no_observers() { ); } -#[test] -fn finalize_3_voters_1_full_observer() { - let mut runtime = Runtime::new().unwrap(); - +#[tokio::test] +async 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, runtime.handle().clone()); - runtime.spawn(initialize_grandpa(&mut net, peers)); + let mut net = GrandpaTestNet::new(TestApi::new(voters), 3, 1); + tokio::spawn(initialize_grandpa(&mut net, peers)); - runtime.spawn({ + tokio::spawn({ let peer_id = 3; let net_service = net.peers[peer_id].network_service().clone(); let link = net.peers[peer_id].data.lock().take().expect("link initialized at startup; qed"); @@ -444,7 +425,7 @@ fn finalize_3_voters_1_full_observer() { // wait for all finalized on each. let wait_for = futures::future::join_all(finality_notifications).map(|_| ()); - block_until_complete(wait_for, &net, &mut runtime); + run_until_complete(wait_for, &net).await; // all peers should have stored the justification for the best finalized block #20 for peer_id in 0..4 { @@ -456,8 +437,8 @@ fn finalize_3_voters_1_full_observer() { } } -#[test] -fn transition_3_voters_twice_1_full_observer() { +#[tokio::test] +async fn transition_3_voters_twice_1_full_observer() { sp_tracing::try_init_simple(); let peers_a = &[Ed25519Keyring::Alice, Ed25519Keyring::Bob, Ed25519Keyring::Charlie]; @@ -478,8 +459,7 @@ fn transition_3_voters_twice_1_full_observer() { let genesis_voters = make_ids(peers_a); let api = TestApi::new(genesis_voters); - let mut runtime = Runtime::new().unwrap(); - let net = Arc::new(Mutex::new(GrandpaTestNet::new(api, 8, 1, runtime.handle().clone()))); + let net = Arc::new(Mutex::new(GrandpaTestNet::new(api, 8, 1))); let mut voters = Vec::new(); for (peer_id, local_key) in all_peers.clone().into_iter().enumerate() { @@ -516,7 +496,7 @@ fn transition_3_voters_twice_1_full_observer() { } net.lock().peer(0).push_blocks(1, false); - runtime.block_on(net.lock().wait_until_sync()); + net.lock().run_until_sync().await; for (i, peer) in net.lock().peers().iter().enumerate() { let full_client = peer.client().as_client(); @@ -577,13 +557,13 @@ fn transition_3_voters_twice_1_full_observer() { future::ready(()) }); - runtime.spawn(block_production); + tokio::spawn(block_production); } let mut finality_notifications = Vec::new(); for voter in voters { - runtime.spawn(voter); + tokio::spawn(voter); } for (peer_id, _) in all_peers.into_iter().enumerate() { @@ -607,24 +587,23 @@ fn transition_3_voters_twice_1_full_observer() { // wait for all finalized on each. let wait_for = ::futures::future::join_all(finality_notifications); - block_until_complete(wait_for, &net, &mut runtime); + run_until_complete(wait_for, &net).await; } -#[test] -fn justification_is_generated_periodically() { - let mut runtime = Runtime::new().unwrap(); +#[tokio::test] +async 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, runtime.handle().clone()); - runtime.spawn(initialize_grandpa(&mut net, peers)); + let mut net = GrandpaTestNet::new(TestApi::new(voters), 3, 0); + tokio::spawn(initialize_grandpa(&mut net, peers)); net.peer(0).push_blocks(32, false); - runtime.block_on(net.wait_until_sync()); + net.run_until_sync().await; 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); + run_to_completion(32, net.clone(), peers).await; // when block#32 (justification_period) is finalized, justification // is required => generated @@ -633,16 +612,15 @@ fn justification_is_generated_periodically() { } } -#[test] -fn sync_justifications_on_change_blocks() { - let mut runtime = Runtime::new().unwrap(); +#[tokio::test] +async fn sync_justifications_on_change_blocks() { let peers_a = &[Ed25519Keyring::Alice, Ed25519Keyring::Bob, Ed25519Keyring::Charlie]; let peers_b = &[Ed25519Keyring::Alice, Ed25519Keyring::Bob]; let voters = make_ids(peers_b); // 4 peers, 3 of them are authorities and participate in grandpa let api = TestApi::new(voters); - let mut net = GrandpaTestNet::new(api, 3, 1, runtime.handle().clone()); + let mut net = GrandpaTestNet::new(api, 3, 1); let voters = initialize_grandpa(&mut net, peers_a); // add 20 blocks @@ -660,15 +638,15 @@ fn sync_justifications_on_change_blocks() { // add more blocks on top of it (until we have 25) net.peer(0).push_blocks(4, false); - runtime.block_on(net.wait_until_sync()); + net.run_until_sync().await; for i in 0..4 { assert_eq!(net.peer(i).client().info().best_number, 25, "Peer #{} failed to sync", i); } let net = Arc::new(Mutex::new(net)); - runtime.spawn(voters); - run_to_completion(&mut runtime, 25, net.clone(), peers_a); + tokio::spawn(voters); + run_to_completion(25, net.clone(), peers_a).await; // the first 3 peers are grandpa voters and therefore have already finalized // block 21 and stored a justification @@ -677,20 +655,20 @@ fn sync_justifications_on_change_blocks() { } // the last peer should get the justification by syncing from other peers - futures::executor::block_on(futures::future::poll_fn(move |cx| { + futures::future::poll_fn(move |cx| { if net.lock().peer(3).client().justifications(hashof21).unwrap().is_none() { net.lock().poll(cx); Poll::Pending } else { Poll::Ready(()) } - })) + }) + .await; } -#[test] -fn finalizes_multiple_pending_changes_in_order() { +#[tokio::test] +async fn finalizes_multiple_pending_changes_in_order() { sp_tracing::try_init_simple(); - let mut runtime = Runtime::new().unwrap(); let peers_a = &[Ed25519Keyring::Alice, Ed25519Keyring::Bob, Ed25519Keyring::Charlie]; let peers_b = &[Ed25519Keyring::Dave, Ed25519Keyring::Eve, Ed25519Keyring::Ferdie]; @@ -710,8 +688,8 @@ 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, runtime.handle().clone()); - runtime.spawn(initialize_grandpa(&mut net, all_peers)); + let mut net = GrandpaTestNet::new(api, 6, 0); + tokio::spawn(initialize_grandpa(&mut net, all_peers)); // add 20 blocks net.peer(0).push_blocks(20, false); @@ -742,7 +720,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); - runtime.block_on(net.wait_until_sync()); + net.run_until_sync().await; // all peers imported both change blocks for i in 0..6 { @@ -750,13 +728,12 @@ fn finalizes_multiple_pending_changes_in_order() { } let net = Arc::new(Mutex::new(net)); - run_to_completion(&mut runtime, 30, net.clone(), all_peers); + run_to_completion(30, net.clone(), all_peers).await; } -#[test] -fn force_change_to_new_set() { +#[tokio::test] +async fn force_change_to_new_set() { sp_tracing::try_init_simple(); - let mut runtime = Runtime::new().unwrap(); // two of these guys are offline. let genesis_authorities = &[ Ed25519Keyring::Alice, @@ -769,7 +746,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, runtime.handle().clone()); + let mut net = GrandpaTestNet::new(api, 3, 0); let voters_future = initialize_grandpa(&mut net, peers_a); let net = Arc::new(Mutex::new(net)); @@ -793,7 +770,7 @@ fn force_change_to_new_set() { }); net.lock().peer(0).push_blocks(25, false); - runtime.block_on(net.lock().wait_until_sync()); + net.lock().run_until_sync().await; for (i, peer) in net.lock().peers().iter().enumerate() { assert_eq!(peer.client().info().best_number, 26, "Peer #{} failed to sync", i); @@ -809,18 +786,17 @@ fn force_change_to_new_set() { // it will only finalize if the forced transition happens. // we add_blocks after the voters are spawned because otherwise // the link-halves have the wrong AuthoritySet - runtime.spawn(voters_future); - run_to_completion(&mut runtime, 25, net, peers_a); + tokio::spawn(voters_future); + run_to_completion(25, net, peers_a).await; } -#[test] -fn allows_reimporting_change_blocks() { +#[tokio::test] +async fn allows_reimporting_change_blocks() { let peers_a = &[Ed25519Keyring::Alice, Ed25519Keyring::Bob, Ed25519Keyring::Charlie]; let peers_b = &[Ed25519Keyring::Alice, Ed25519Keyring::Bob]; let voters = make_ids(peers_a); let api = TestApi::new(voters); - let runtime = Runtime::new().unwrap(); - let mut net = GrandpaTestNet::new(api.clone(), 3, 0, runtime.handle().clone()); + let mut net = GrandpaTestNet::new(api.clone(), 3, 0); let client = net.peer(0).client().clone(); let (mut block_import, ..) = net.make_block_import(client.clone()); @@ -845,7 +821,7 @@ fn allows_reimporting_change_blocks() { }; assert_eq!( - runtime.block_on(block_import.import_block(block(), HashMap::new())).unwrap(), + block_import.import_block(block(), HashMap::new()).await.unwrap(), ImportResult::Imported(ImportedAux { needs_justification: true, clear_justification_requests: false, @@ -856,19 +832,18 @@ fn allows_reimporting_change_blocks() { ); assert_eq!( - runtime.block_on(block_import.import_block(block(), HashMap::new())).unwrap(), + block_import.import_block(block(), HashMap::new()).await.unwrap(), ImportResult::AlreadyInChain ); } -#[test] -fn test_bad_justification() { +#[tokio::test] +async fn test_bad_justification() { let peers_a = &[Ed25519Keyring::Alice, Ed25519Keyring::Bob, Ed25519Keyring::Charlie]; let peers_b = &[Ed25519Keyring::Alice, Ed25519Keyring::Bob]; let voters = make_ids(peers_a); let api = TestApi::new(voters); - let runtime = Runtime::new().unwrap(); - let mut net = GrandpaTestNet::new(api.clone(), 3, 0, runtime.handle().clone()); + let mut net = GrandpaTestNet::new(api.clone(), 3, 0); let client = net.peer(0).client().clone(); let (mut block_import, ..) = net.make_block_import(client.clone()); @@ -895,7 +870,7 @@ fn test_bad_justification() { }; assert_eq!( - runtime.block_on(block_import.import_block(block(), HashMap::new())).unwrap(), + block_import.import_block(block(), HashMap::new()).await.unwrap(), ImportResult::Imported(ImportedAux { needs_justification: true, clear_justification_requests: false, @@ -906,18 +881,17 @@ fn test_bad_justification() { ); assert_eq!( - runtime.block_on(block_import.import_block(block(), HashMap::new())).unwrap(), + block_import.import_block(block(), HashMap::new()).await.unwrap(), ImportResult::AlreadyInChain ); } -#[test] -fn voter_persists_its_votes() { +#[tokio::test] +async fn voter_persists_its_votes() { use futures::future; use std::sync::atomic::{AtomicUsize, Ordering}; sp_tracing::try_init_simple(); - let mut runtime = Runtime::new().unwrap(); // 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 @@ -925,7 +899,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, runtime.handle().clone()); + let mut net = GrandpaTestNet::new(TestApi::new(voters.clone()), 2, 0); // create the communication layer for bob, but don't start any // voter. instead we'll listen for the prevote that alice casts @@ -1042,10 +1016,10 @@ fn voter_persists_its_votes() { }) } - runtime.spawn(alice_voter1); + tokio::spawn(alice_voter1); net.peer(0).push_blocks(20, false); - runtime.block_on(net.wait_until_sync()); + net.run_until_sync().await; assert_eq!(net.peer(0).client().info().best_number, 20, "Peer #{} failed to sync", 0); @@ -1062,7 +1036,7 @@ fn voter_persists_its_votes() { HasVoted::No, ); - runtime.spawn(bob_network); + tokio::spawn(bob_network); let round_tx = Arc::new(Mutex::new(round_tx)); let exit_tx = Arc::new(Mutex::new(Some(exit_tx))); @@ -1070,15 +1044,13 @@ fn voter_persists_its_votes() { let net = net.clone(); let state = Arc::new(AtomicUsize::new(0)); - let runtime_handle = runtime.handle().clone(); - runtime.spawn(round_rx.for_each(move |signed| { + tokio::spawn(round_rx.for_each(move |signed| { let net2 = net.clone(); let net = net.clone(); let abort = abort.clone(); let round_tx = round_tx.clone(); let state = state.clone(); let exit_tx = exit_tx.clone(); - let runtime_handle = runtime_handle.clone(); async move { if state.compare_exchange(0, 1, Ordering::SeqCst, Ordering::SeqCst).unwrap() == 0 { @@ -1115,7 +1087,7 @@ fn voter_persists_its_votes() { // we restart alice's voter abort.abort(); - runtime_handle.spawn(alice_voter2(peers, net.clone())); + tokio::spawn(alice_voter2(peers, net.clone())); // and we push our own prevote for block 30 let prevote = @@ -1164,17 +1136,16 @@ fn voter_persists_its_votes() { })); } - block_until_complete(exit_rx.into_future(), &net, &mut runtime); + run_until_complete(exit_rx.into_future(), &net).await; } -#[test] -fn finalize_3_voters_1_light_observer() { +#[tokio::test] +async fn finalize_3_voters_1_light_observer() { sp_tracing::try_init_simple(); - let mut runtime = Runtime::new().unwrap(); let authorities = &[Ed25519Keyring::Alice, Ed25519Keyring::Bob, Ed25519Keyring::Charlie]; let voters = make_ids(authorities); - let mut net = GrandpaTestNet::new(TestApi::new(voters), 3, 1, runtime.handle().clone()); + let mut net = GrandpaTestNet::new(TestApi::new(voters), 3, 1); let voters = initialize_grandpa(&mut net, authorities); let observer = observer::run_grandpa_observer( Config { @@ -1192,7 +1163,7 @@ fn finalize_3_voters_1_light_observer() { ) .unwrap(); net.peer(0).push_blocks(20, false); - runtime.block_on(net.wait_until_sync()); + net.run_until_sync().await; for i in 0..4 { assert_eq!(net.peer(i).client().info().best_number, 20, "Peer #{} failed to sync", i); @@ -1200,20 +1171,19 @@ fn finalize_3_voters_1_light_observer() { let net = Arc::new(Mutex::new(net)); - runtime.spawn(voters); - runtime.spawn(observer); - run_to_completion(&mut runtime, 20, net.clone(), authorities); + tokio::spawn(voters); + tokio::spawn(observer); + run_to_completion(20, net.clone(), authorities).await; } -#[test] -fn voter_catches_up_to_latest_round_when_behind() { +#[tokio::test] +async fn voter_catches_up_to_latest_round_when_behind() { sp_tracing::try_init_simple(); - let runtime = Runtime::new().unwrap(); let peers = &[Ed25519Keyring::Alice, Ed25519Keyring::Bob]; let voters = make_ids(peers); - let net = GrandpaTestNet::new(TestApi::new(voters), 2, 0, runtime.handle().clone()); + let net = GrandpaTestNet::new(TestApi::new(voters), 2, 0); let net = Arc::new(Mutex::new(net)); let mut finality_notifications = Vec::new(); @@ -1265,11 +1235,11 @@ fn voter_catches_up_to_latest_round_when_behind() { let voter = voter(Some(keystore), peer_id, link, net.clone()); - runtime.spawn(voter); + tokio::spawn(voter); } net.lock().peer(0).push_blocks(50, false); - runtime.block_on(net.lock().wait_until_sync()); + net.lock().run_until_sync().await; // 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. @@ -1279,7 +1249,6 @@ fn voter_catches_up_to_latest_round_when_behind() { // able to catch up to the latest round let test = { let net = net.clone(); - let runtime = runtime.handle().clone(); wait_for_finality.then(move |_| { net.lock().add_authority_peer(); @@ -1290,7 +1259,7 @@ fn voter_catches_up_to_latest_round_when_behind() { link.take().expect("link initialized at startup; qed") }; let set_state = link.persistent_data.set_state.clone(); - runtime.spawn(voter(None, 2, link, net.clone())); + tokio::spawn(voter(None, 2, link, net.clone())); let start_time = std::time::Instant::now(); let timeout = Duration::from_secs(5 * 60); @@ -1315,7 +1284,7 @@ fn voter_catches_up_to_latest_round_when_behind() { net.lock().poll(cx); Poll::<()>::Pending }); - runtime.block_on(future::select(test, drive_to_completion)); + future::select(test, drive_to_completion).await; } type TestEnvironment = Environment< @@ -1370,15 +1339,14 @@ where } } -#[test] -fn grandpa_environment_respects_voting_rules() { +#[tokio::test] +async fn grandpa_environment_respects_voting_rules() { use finality_grandpa::voter::Environment; let peers = &[Ed25519Keyring::Alice]; let voters = make_ids(peers); - let runtime = Runtime::new().unwrap(); - let mut net = GrandpaTestNet::new(TestApi::new(voters), 1, 0, runtime.handle().clone()); + let mut net = GrandpaTestNet::new(TestApi::new(voters), 1, 0); let peer = net.peer(0); let network_service = peer.network_service().clone(); let link = peer.data.lock().take().unwrap(); @@ -1408,8 +1376,9 @@ fn grandpa_environment_respects_voting_rules() { // the unrestricted environment should just return the best block assert_eq!( - runtime - .block_on(unrestricted_env.best_chain_containing(peer.client().info().finalized_hash)) + unrestricted_env + .best_chain_containing(peer.client().info().finalized_hash) + .await .unwrap() .unwrap() .1, @@ -1419,8 +1388,9 @@ 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!( - runtime - .block_on(three_quarters_env.best_chain_containing(peer.client().info().finalized_hash)) + three_quarters_env + .best_chain_containing(peer.client().info().finalized_hash) + .await .unwrap() .unwrap() .1, @@ -1428,8 +1398,9 @@ fn grandpa_environment_respects_voting_rules() { ); assert_eq!( - runtime - .block_on(default_env.best_chain_containing(peer.client().info().finalized_hash)) + default_env + .best_chain_containing(peer.client().info().finalized_hash) + .await .unwrap() .unwrap() .1, @@ -1446,8 +1417,9 @@ fn grandpa_environment_respects_voting_rules() { // the 3/4 environment should propose block 21 for voting assert_eq!( - runtime - .block_on(three_quarters_env.best_chain_containing(peer.client().info().finalized_hash)) + three_quarters_env + .best_chain_containing(peer.client().info().finalized_hash) + .await .unwrap() .unwrap() .1, @@ -1457,8 +1429,9 @@ 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!( - runtime - .block_on(default_env.best_chain_containing(peer.client().info().finalized_hash)) + default_env + .best_chain_containing(peer.client().info().finalized_hash) + .await .unwrap() .unwrap() .1, @@ -1477,8 +1450,9 @@ 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!( - runtime - .block_on(default_env.best_chain_containing(peer.client().info().finalized_hash)) + default_env + .best_chain_containing(peer.client().info().finalized_hash) + .await .unwrap() .unwrap() .1, @@ -1486,15 +1460,14 @@ fn grandpa_environment_respects_voting_rules() { ); } -#[test] -fn grandpa_environment_never_overwrites_round_voter_state() { +#[tokio::test] +async fn grandpa_environment_never_overwrites_round_voter_state() { use finality_grandpa::voter::Environment; let peers = &[Ed25519Keyring::Alice]; let voters = make_ids(peers); - let runtime = Runtime::new().unwrap(); - let mut net = GrandpaTestNet::new(TestApi::new(voters), 1, 0, runtime.handle().clone()); + let mut net = GrandpaTestNet::new(TestApi::new(voters), 1, 0); let peer = net.peer(0); let network_service = peer.network_service().clone(); let link = peer.data.lock().take().unwrap(); @@ -1549,16 +1522,15 @@ fn grandpa_environment_never_overwrites_round_voter_state() { assert_matches!(get_current_round(2).unwrap(), HasVoted::Yes(_, _)); } -#[test] -fn justification_with_equivocation() { +#[tokio::test] +async 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 runtime = Runtime::new().unwrap(); - let mut net = GrandpaTestNet::new(api.clone(), 1, 0, runtime.handle().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); @@ -1617,16 +1589,15 @@ fn justification_with_equivocation() { assert!(justification.verify(set_id, &voters).is_ok()); } -#[test] -fn imports_justification_for_regular_blocks_on_import() { +#[tokio::test] +async fn imports_justification_for_regular_blocks_on_import() { // NOTE: this is a regression test since initially we would only import // justifications for authority change blocks, and would discard any // existing justification otherwise. let peers = &[Ed25519Keyring::Alice]; let voters = make_ids(peers); let api = TestApi::new(voters); - let runtime = Runtime::new().unwrap(); - let mut net = GrandpaTestNet::new(api.clone(), 1, 0, runtime.handle().clone()); + let mut net = GrandpaTestNet::new(api.clone(), 1, 0); let client = net.peer(0).client().clone(); let (mut block_import, ..) = net.make_block_import(client.clone()); @@ -1675,7 +1646,7 @@ fn imports_justification_for_regular_blocks_on_import() { import.fork_choice = Some(ForkChoiceStrategy::LongestChain); assert_eq!( - runtime.block_on(block_import.import_block(import, HashMap::new())).unwrap(), + block_import.import_block(import, HashMap::new()).await.unwrap(), ImportResult::Imported(ImportedAux { needs_justification: false, clear_justification_requests: false, @@ -1689,17 +1660,15 @@ fn imports_justification_for_regular_blocks_on_import() { assert!(client.justifications(block_hash).unwrap().is_some()); } -#[test] -fn grandpa_environment_doesnt_send_equivocation_reports_for_itself() { +#[tokio::test] +async fn grandpa_environment_doesnt_send_equivocation_reports_for_itself() { use finality_grandpa::voter::Environment; 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, runtime.handle().clone()); + let mut net = GrandpaTestNet::new(TestApi::new(voters), 1, 0); let peer = net.peer(0); let network_service = peer.network_service().clone(); let link = peer.data.lock().take().unwrap(); @@ -1737,10 +1706,9 @@ fn grandpa_environment_doesnt_send_equivocation_reports_for_itself() { assert!(environment.report_equivocation(equivocation_proof).is_ok()); } -#[test] -fn revert_prunes_authority_changes() { +#[tokio::test] +async fn revert_prunes_authority_changes() { sp_tracing::try_init_simple(); - let runtime = Runtime::new().unwrap(); let peers = &[Ed25519Keyring::Alice, Ed25519Keyring::Bob, Ed25519Keyring::Charlie]; @@ -1757,8 +1725,8 @@ fn revert_prunes_authority_changes() { let api = TestApi::new(make_ids(peers)); - let mut net = GrandpaTestNet::new(api, 3, 0, runtime.handle().clone()); - runtime.spawn(initialize_grandpa(&mut net, peers)); + let mut net = GrandpaTestNet::new(api, 3, 0); + tokio::spawn(initialize_grandpa(&mut net, peers)); let peer = net.peer(0); let client = peer.client().as_client(); diff --git a/client/network-gossip/src/bridge.rs b/client/network-gossip/src/bridge.rs index 462677f53c5fd..5d7fd96c13e57 100644 --- a/client/network-gossip/src/bridge.rs +++ b/client/network-gossip/src/bridge.rs @@ -489,7 +489,7 @@ mod tests { })) } - #[tokio::test(flavor = "multi_thread")] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn keeps_multiple_subscribers_per_topic_updated_with_both_old_and_new_messages() { let topic = H256::default(); let protocol = ProtocolName::from("/my_protocol"); diff --git a/client/network/src/protocol/notifications/upgrade/notifications.rs b/client/network/src/protocol/notifications/upgrade/notifications.rs index 5d61e10727b66..5a4ec832dbea1 100644 --- a/client/network/src/protocol/notifications/upgrade/notifications.rs +++ b/client/network/src/protocol/notifications/upgrade/notifications.rs @@ -483,20 +483,15 @@ mod tests { use super::{NotificationsIn, NotificationsInOpen, NotificationsOut, NotificationsOutOpen}; use futures::{channel::oneshot, prelude::*}; use libp2p::core::upgrade; - use tokio::{ - net::{TcpListener, TcpStream}, - runtime::Runtime, - }; + use tokio::net::{TcpListener, TcpStream}; use tokio_util::compat::TokioAsyncReadCompatExt; - #[test] - fn basic_works() { + #[tokio::test] + async fn basic_works() { const PROTO_NAME: &str = "/test/proto/1"; let (listener_addr_tx, listener_addr_rx) = oneshot::channel(); - let runtime = Runtime::new().unwrap(); - - let client = runtime.spawn(async move { + let client = tokio::spawn(async move { let socket = TcpStream::connect(listener_addr_rx.await.unwrap()).await.unwrap(); let NotificationsOutOpen { handshake, mut substream, .. } = upgrade::apply_outbound( socket.compat(), @@ -510,38 +505,34 @@ mod tests { substream.send(b"test message".to_vec()).await.unwrap(); }); - 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 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.compat(), - NotificationsIn::new(PROTO_NAME, Vec::new(), 1024 * 1024), - ) - .await - .unwrap(); + let (socket, _) = listener.accept().await.unwrap(); + let NotificationsInOpen { handshake, mut substream, .. } = upgrade::apply_inbound( + socket.compat(), + NotificationsIn::new(PROTO_NAME, Vec::new(), 1024 * 1024), + ) + .await + .unwrap(); - assert_eq!(handshake, b"initial message"); - substream.send_handshake(&b"hello world"[..]); + assert_eq!(handshake, b"initial message"); + substream.send_handshake(&b"hello world"[..]); - let msg = substream.next().await.unwrap().unwrap(); - assert_eq!(msg.as_ref(), b"test message"); - }); + let msg = substream.next().await.unwrap().unwrap(); + assert_eq!(msg.as_ref(), b"test message"); - runtime.block_on(client).unwrap(); + client.await.unwrap(); } - #[test] - fn empty_handshake() { + #[tokio::test] + async fn empty_handshake() { // Check that everything still works when the handshake messages are empty. const PROTO_NAME: &str = "/test/proto/1"; let (listener_addr_tx, listener_addr_rx) = oneshot::channel(); - let runtime = Runtime::new().unwrap(); - - let client = runtime.spawn(async move { + let client = tokio::spawn(async move { let socket = TcpStream::connect(listener_addr_rx.await.unwrap()).await.unwrap(); let NotificationsOutOpen { handshake, mut substream, .. } = upgrade::apply_outbound( socket.compat(), @@ -555,36 +546,32 @@ mod tests { substream.send(Default::default()).await.unwrap(); }); - 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 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.compat(), - NotificationsIn::new(PROTO_NAME, Vec::new(), 1024 * 1024), - ) - .await - .unwrap(); + let (socket, _) = listener.accept().await.unwrap(); + let NotificationsInOpen { handshake, mut substream, .. } = upgrade::apply_inbound( + socket.compat(), + NotificationsIn::new(PROTO_NAME, Vec::new(), 1024 * 1024), + ) + .await + .unwrap(); - assert!(handshake.is_empty()); - substream.send_handshake(vec![]); + assert!(handshake.is_empty()); + substream.send_handshake(vec![]); - let msg = substream.next().await.unwrap().unwrap(); - assert!(msg.as_ref().is_empty()); - }); + let msg = substream.next().await.unwrap().unwrap(); + assert!(msg.as_ref().is_empty()); - runtime.block_on(client).unwrap(); + client.await.unwrap(); } - #[test] - fn refused() { + #[tokio::test] + async fn refused() { const PROTO_NAME: &str = "/test/proto/1"; let (listener_addr_tx, listener_addr_rx) = oneshot::channel(); - let runtime = Runtime::new().unwrap(); - - let client = runtime.spawn(async move { + let client = tokio::spawn(async move { let socket = TcpStream::connect(listener_addr_rx.await.unwrap()).await.unwrap(); let outcome = upgrade::apply_outbound( socket.compat(), @@ -599,35 +586,31 @@ mod tests { assert!(outcome.is_err()); }); - 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 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.compat(), - NotificationsIn::new(PROTO_NAME, Vec::new(), 1024 * 1024), - ) - .await - .unwrap(); + let (socket, _) = listener.accept().await.unwrap(); + let NotificationsInOpen { handshake, substream, .. } = upgrade::apply_inbound( + socket.compat(), + NotificationsIn::new(PROTO_NAME, Vec::new(), 1024 * 1024), + ) + .await + .unwrap(); - assert_eq!(handshake, b"hello"); + assert_eq!(handshake, b"hello"); - // We successfully upgrade to the protocol, but then close the substream. - drop(substream); - }); + // We successfully upgrade to the protocol, but then close the substream. + drop(substream); - runtime.block_on(client).unwrap(); + client.await.unwrap(); } - #[test] - fn large_initial_message_refused() { + #[tokio::test] + async fn large_initial_message_refused() { const PROTO_NAME: &str = "/test/proto/1"; let (listener_addr_tx, listener_addr_rx) = oneshot::channel(); - let runtime = Runtime::new().unwrap(); - - let client = runtime.spawn(async move { + let client = tokio::spawn(async move { let socket = TcpStream::connect(listener_addr_rx.await.unwrap()).await.unwrap(); let ret = upgrade::apply_outbound( socket.compat(), @@ -644,30 +627,26 @@ mod tests { assert!(ret.is_err()); }); - 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 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.compat(), - NotificationsIn::new(PROTO_NAME, Vec::new(), 1024 * 1024), - ) - .await; - assert!(ret.is_err()); - }); + let (socket, _) = listener.accept().await.unwrap(); + let ret = upgrade::apply_inbound( + socket.compat(), + NotificationsIn::new(PROTO_NAME, Vec::new(), 1024 * 1024), + ) + .await; + assert!(ret.is_err()); - runtime.block_on(client).unwrap(); + client.await.unwrap(); } - #[test] - fn large_handshake_refused() { + #[tokio::test] + async fn large_handshake_refused() { const PROTO_NAME: &str = "/test/proto/1"; let (listener_addr_tx, listener_addr_rx) = oneshot::channel(); - let runtime = Runtime::new().unwrap(); - - let client = runtime.spawn(async move { + let client = tokio::spawn(async move { let socket = TcpStream::connect(listener_addr_rx.await.unwrap()).await.unwrap(); let ret = upgrade::apply_outbound( socket.compat(), @@ -678,24 +657,22 @@ mod tests { assert!(ret.is_err()); }); - 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 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.compat(), - NotificationsIn::new(PROTO_NAME, Vec::new(), 1024 * 1024), - ) - .await - .unwrap(); - assert_eq!(handshake, b"initial message"); + let (socket, _) = listener.accept().await.unwrap(); + let NotificationsInOpen { handshake, mut substream, .. } = upgrade::apply_inbound( + socket.compat(), + NotificationsIn::new(PROTO_NAME, Vec::new(), 1024 * 1024), + ) + .await + .unwrap(); + assert_eq!(handshake, b"initial message"); - // We check that a handshake that is too large gets refused. - substream.send_handshake((0..32768).map(|_| 0).collect::>()); - let _ = substream.next().await; - }); + // We check that a handshake that is too large gets refused. + substream.send_handshake((0..32768).map(|_| 0).collect::>()); + let _ = substream.next().await; - runtime.block_on(client).unwrap(); + client.await.unwrap(); } } diff --git a/client/network/src/service/tests/chain_sync.rs b/client/network/src/service/tests/chain_sync.rs index 0f47b64c352f2..ce4430dd87db9 100644 --- a/client/network/src/service/tests/chain_sync.rs +++ b/client/network/src/service/tests/chain_sync.rs @@ -44,7 +44,6 @@ 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, @@ -72,7 +71,7 @@ async fn normal_network_poll_no_peers() { let chain_sync_service = Box::new(MockChainSyncInterface::::new()); - let mut network = TestNetworkBuilder::new(Handle::current()) + let mut network = TestNetworkBuilder::new() .with_chain_sync((chain_sync, chain_sync_service)) .build(); @@ -104,7 +103,7 @@ async fn request_justification() { let mut chain_sync = MockChainSync::::new(); set_default_expecations_no_peers(&mut chain_sync); - let mut network = TestNetworkBuilder::new(Handle::current()) + let mut network = TestNetworkBuilder::new() .with_chain_sync((Box::new(chain_sync), chain_sync_service)) .build(); @@ -135,7 +134,7 @@ async fn clear_justification_requests() { Box::new(MockChainSync::::new()); set_default_expecations_no_peers(&mut chain_sync); - let mut network = TestNetworkBuilder::new(Handle::current()) + let mut network = TestNetworkBuilder::new() .with_chain_sync((chain_sync, chain_sync_service)) .build(); @@ -174,7 +173,7 @@ async fn set_sync_fork_request() { .once() .returning(|_, _, _| ()); - let mut network = TestNetworkBuilder::new(Handle::current()) + let mut network = TestNetworkBuilder::new() .with_chain_sync((chain_sync, Box::new(chain_sync_service))) .build(); @@ -218,7 +217,7 @@ async fn on_block_finalized() { .returning(|_, _| ()); set_default_expecations_no_peers(&mut chain_sync); - let mut network = TestNetworkBuilder::new(Handle::current()) + let mut network = TestNetworkBuilder::new() .with_client(client) .with_chain_sync((chain_sync, chain_sync_service)) .build(); @@ -316,7 +315,7 @@ 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(Handle::current()) + let (service1, mut event_stream1) = TestNetworkBuilder::new() .with_import_queue(Box::new(DummyImportQueue( justification_info.clone(), DummyImportQueueHandle {}, @@ -325,7 +324,7 @@ async fn invalid_justification_imported() { .build() .start_network(); - let (service2, mut event_stream2) = TestNetworkBuilder::new(Handle::current()) + let (service2, mut event_stream2) = TestNetworkBuilder::new() .with_set_config(SetConfig { reserved_nodes: vec![MultiaddrWithPeerId { multiaddr: listen_addr, @@ -393,7 +392,7 @@ async fn disconnect_peer_using_chain_sync_handle() { ) .unwrap(); - let (node1, mut event_stream1) = TestNetworkBuilder::new(Handle::current()) + let (node1, mut event_stream1) = TestNetworkBuilder::new() .with_listen_addresses(vec![listen_addr.clone()]) .with_chain_sync((Box::new(chain_sync), Box::new(chain_sync_service))) .with_chain_sync_network((chain_sync_network_provider, chain_sync_network_handle)) @@ -401,7 +400,7 @@ async fn disconnect_peer_using_chain_sync_handle() { .build() .start_network(); - let (node2, mut event_stream2) = TestNetworkBuilder::new(Handle::current()) + let (node2, mut event_stream2) = TestNetworkBuilder::new() .with_set_config(SetConfig { reserved_nodes: vec![MultiaddrWithPeerId { multiaddr: listen_addr, diff --git a/client/network/src/service/tests/mod.rs b/client/network/src/service/tests/mod.rs index fa1486a791213..9c97a7f73837d 100644 --- a/client/network/src/service/tests/mod.rs +++ b/client/network/src/service/tests/mod.rs @@ -44,7 +44,6 @@ 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; @@ -59,12 +58,11 @@ const PROTOCOL_NAME: &str = "/foo"; struct TestNetwork { network: TestNetworkWorker, - rt_handle: Handle, } impl TestNetwork { - pub fn new(network: TestNetworkWorker, rt_handle: Handle) -> Self { - Self { network, rt_handle } + pub fn new(network: TestNetworkWorker) -> Self { + Self { network } } pub fn service(&self) -> &Arc { @@ -82,7 +80,7 @@ impl TestNetwork { let service = worker.service().clone(); let event_stream = service.event_stream("test"); - self.rt_handle.spawn(async move { + tokio::spawn(async move { futures::pin_mut!(worker); let _ = worker.await; }); @@ -100,11 +98,10 @@ struct TestNetworkBuilder { chain_sync: Option<(Box>, Box>)>, chain_sync_network: Option<(NetworkServiceProvider, NetworkServiceHandle)>, config: Option, - rt_handle: Handle, } impl TestNetworkBuilder { - pub fn new(rt_handle: Handle) -> Self { + pub fn new() -> Self { Self { import_queue: None, link: None, @@ -114,7 +111,6 @@ impl TestNetworkBuilder { chain_sync: None, chain_sync_network: None, config: None, - rt_handle, } } @@ -229,21 +225,21 @@ impl TestNetworkBuilder { let block_request_protocol_config = { let (handler, protocol_config) = BlockRequestHandler::new(&protocol_id, None, client.clone(), 50); - self.rt_handle.spawn(handler.run().boxed()); + tokio::spawn(handler.run().boxed()); protocol_config }; let state_request_protocol_config = { let (handler, protocol_config) = StateRequestHandler::new(&protocol_id, None, client.clone(), 50); - self.rt_handle.spawn(handler.run().boxed()); + tokio::spawn(handler.run().boxed()); protocol_config }; let light_client_request_protocol_config = { let (handler, protocol_config) = LightClientRequestHandler::new(&protocol_id, None, client.clone()); - self.rt_handle.spawn(handler.run().boxed()); + tokio::spawn(handler.run().boxed()); protocol_config }; @@ -310,11 +306,6 @@ impl TestNetworkBuilder { .link .unwrap_or(Box::new(sc_network_sync::service::mock::MockChainSyncInterface::new())); - 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, @@ -322,7 +313,9 @@ impl TestNetworkBuilder { >::new(config::Params { block_announce_config, role: config::Role::Full, - executor: Box::new(executor), + executor: Box::new(|f| { + tokio::spawn(f); + }), network_config, chain: client.clone(), protocol_id, @@ -340,10 +333,10 @@ impl TestNetworkBuilder { .unwrap(); let service = worker.service().clone(); - self.rt_handle.spawn(async move { + tokio::spawn(async move { let _ = chain_sync_network_provider.run(service).await; }); - self.rt_handle.spawn(async move { + tokio::spawn(async move { loop { futures::future::poll_fn(|cx| { import_queue.poll_actions(cx, &mut *link); @@ -354,6 +347,6 @@ impl TestNetworkBuilder { } }); - TestNetwork::new(worker, self.rt_handle) + TestNetwork::new(worker) } } diff --git a/client/network/src/service/tests/service.rs b/client/network/src/service/tests/service.rs index aa74e595fff7e..bdf30096356f2 100644 --- a/client/network/src/service/tests/service.rs +++ b/client/network/src/service/tests/service.rs @@ -26,7 +26,6 @@ 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, @@ -38,9 +37,7 @@ 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( - rt_handle: &Handle, -) -> ( +fn build_nodes_one_proto() -> ( Arc, impl Stream, Arc, @@ -48,12 +45,12 @@ fn build_nodes_one_proto( ) { let listen_addr = config::build_multiaddr![Memory(rand::random::())]; - let (node1, events_stream1) = TestNetworkBuilder::new(rt_handle.clone()) + let (node1, events_stream1) = TestNetworkBuilder::new() .with_listen_addresses(vec![listen_addr.clone()]) .build() .start_network(); - let (node2, events_stream2) = TestNetworkBuilder::new(rt_handle.clone()) + let (node2, events_stream2) = TestNetworkBuilder::new() .with_set_config(SetConfig { reserved_nodes: vec![MultiaddrWithPeerId { multiaddr: listen_addr, @@ -67,15 +64,12 @@ fn build_nodes_one_proto( (node1, events_stream1, node2, events_stream2) } -#[test] -fn notifications_state_consistent() { +#[tokio::test] +async fn notifications_state_consistent() { // Runs two nodes and ensures that events are propagated out of the API in a consistent // correct order, which means no notification received on a closed substream. - let runtime = tokio::runtime::Runtime::new().unwrap(); - - let (node1, mut events_stream1, node2, mut events_stream2) = - build_nodes_one_proto(runtime.handle()); + let (node1, mut events_stream1, node2, mut events_stream2) = build_nodes_one_proto(); // Write some initial notifications that shouldn't get through. for _ in 0..(rand::random::() % 5) { @@ -93,140 +87,130 @@ fn notifications_state_consistent() { ); } - 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. - let mut node2_to_node1_open = false; - // We stop the test after a certain number of iterations. - let mut iterations = 0; - // Safe guard because we don't want the test to pass if no substream has been open. - let mut something_happened = false; + // 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. + let mut node2_to_node1_open = false; + // We stop the test after a certain number of iterations. + let mut iterations = 0; + // Safe guard because we don't want the test to pass if no substream has been open. + let mut something_happened = false; + + loop { + iterations += 1; + if iterations >= 1_000 { + assert!(something_happened); + break + } - loop { - iterations += 1; - if iterations >= 1_000 { - assert!(something_happened); - break - } + // Start by sending a notification from node1 to node2 and vice-versa. Part of the + // test consists in ensuring that notifications get ignored if the stream isn't open. + if rand::random::() % 5 >= 3 { + node1.write_notification( + node2.local_peer_id(), + PROTOCOL_NAME.into(), + b"hello world".to_vec(), + ); + } + if rand::random::() % 5 >= 3 { + node2.write_notification( + node1.local_peer_id(), + PROTOCOL_NAME.into(), + b"hello world".to_vec(), + ); + } - // Start by sending a notification from node1 to node2 and vice-versa. Part of the - // test consists in ensuring that notifications get ignored if the stream isn't open. - if rand::random::() % 5 >= 3 { - node1.write_notification( - node2.local_peer_id(), - PROTOCOL_NAME.into(), - b"hello world".to_vec(), - ); - } - if rand::random::() % 5 >= 3 { - node2.write_notification( - node1.local_peer_id(), - 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.into()); + } + if rand::random::() % 20 == 0 { + node2.disconnect_peer(node1.local_peer_id(), PROTOCOL_NAME.into()); + } - // Also randomly disconnect the two nodes from time to time. - if rand::random::() % 20 == 0 { - node1.disconnect_peer(node2.local_peer_id(), PROTOCOL_NAME.into()); + // Grab next event from either `events_stream1` or `events_stream2`. + let next_event = { + let next1 = events_stream1.next(); + let next2 = events_stream2.next(); + // We also await on a small timer, otherwise it is possible for the test to wait + // forever while nothing at all happens on the network. + let continue_test = futures_timer::Delay::new(Duration::from_millis(20)); + match future::select(future::select(next1, next2), continue_test).await { + future::Either::Left((future::Either::Left((Some(ev), _)), _)) => + future::Either::Left(ev), + future::Either::Left((future::Either::Right((Some(ev), _)), _)) => + future::Either::Right(ev), + future::Either::Right(_) => continue, + _ => break, } - if rand::random::() % 20 == 0 { - node2.disconnect_peer(node1.local_peer_id(), PROTOCOL_NAME.into()); - } - - // Grab next event from either `events_stream1` or `events_stream2`. - let next_event = { - let next1 = events_stream1.next(); - let next2 = events_stream2.next(); - // We also await on a small timer, otherwise it is possible for the test to wait - // forever while nothing at all happens on the network. - let continue_test = futures_timer::Delay::new(Duration::from_millis(20)); - match future::select(future::select(next1, next2), continue_test).await { - future::Either::Left((future::Either::Left((Some(ev), _)), _)) => - future::Either::Left(ev), - future::Either::Left((future::Either::Right((Some(ev), _)), _)) => - future::Either::Right(ev), - future::Either::Right(_) => continue, - _ => break, - } - }; - - match next_event { - future::Either::Left(Event::NotificationStreamOpened { - remote, protocol, .. - }) => - if protocol == PROTOCOL_NAME.into() { - something_happened = true; - assert!(!node1_to_node2_open); - node1_to_node2_open = true; - assert_eq!(remote, node2.local_peer_id()); - }, - future::Either::Right(Event::NotificationStreamOpened { - remote, protocol, .. - }) => - if protocol == PROTOCOL_NAME.into() { - something_happened = true; - assert!(!node2_to_node1_open); - node2_to_node1_open = true; - assert_eq!(remote, node1.local_peer_id()); - }, - future::Either::Left(Event::NotificationStreamClosed { - remote, protocol, .. - }) => - if protocol == PROTOCOL_NAME.into() { - assert!(node1_to_node2_open); - node1_to_node2_open = false; - assert_eq!(remote, node2.local_peer_id()); - }, - future::Either::Right(Event::NotificationStreamClosed { - remote, protocol, .. - }) => - if protocol == PROTOCOL_NAME.into() { - assert!(node2_to_node1_open); - node2_to_node1_open = false; - assert_eq!(remote, node1.local_peer_id()); - }, - future::Either::Left(Event::NotificationsReceived { remote, .. }) => { + }; + + match next_event { + future::Either::Left(Event::NotificationStreamOpened { remote, protocol, .. }) => + if protocol == PROTOCOL_NAME.into() { + something_happened = true; + assert!(!node1_to_node2_open); + node1_to_node2_open = true; + assert_eq!(remote, node2.local_peer_id()); + }, + future::Either::Right(Event::NotificationStreamOpened { remote, protocol, .. }) => + if protocol == PROTOCOL_NAME.into() { + something_happened = true; + assert!(!node2_to_node1_open); + node2_to_node1_open = true; + assert_eq!(remote, node1.local_peer_id()); + }, + future::Either::Left(Event::NotificationStreamClosed { remote, protocol, .. }) => + if protocol == PROTOCOL_NAME.into() { assert!(node1_to_node2_open); + node1_to_node2_open = false; assert_eq!(remote, node2.local_peer_id()); - if rand::random::() % 5 >= 4 { - node1.write_notification( - node2.local_peer_id(), - PROTOCOL_NAME.into(), - b"hello world".to_vec(), - ); - } }, - future::Either::Right(Event::NotificationsReceived { remote, .. }) => { + future::Either::Right(Event::NotificationStreamClosed { remote, protocol, .. }) => + if protocol == PROTOCOL_NAME.into() { assert!(node2_to_node1_open); + node2_to_node1_open = false; assert_eq!(remote, node1.local_peer_id()); - if rand::random::() % 5 >= 4 { - node2.write_notification( - node1.local_peer_id(), - PROTOCOL_NAME.into(), - b"hello world".to_vec(), - ); - } }, + future::Either::Left(Event::NotificationsReceived { remote, .. }) => { + assert!(node1_to_node2_open); + assert_eq!(remote, node2.local_peer_id()); + if rand::random::() % 5 >= 4 { + node1.write_notification( + node2.local_peer_id(), + PROTOCOL_NAME.into(), + b"hello world".to_vec(), + ); + } + }, + future::Either::Right(Event::NotificationsReceived { remote, .. }) => { + assert!(node2_to_node1_open); + assert_eq!(remote, node1.local_peer_id()); + if rand::random::() % 5 >= 4 { + node2.write_notification( + node1.local_peer_id(), + PROTOCOL_NAME.into(), + b"hello world".to_vec(), + ); + } + }, - // Add new events here. - future::Either::Left(Event::SyncConnected { .. }) => {}, - future::Either::Right(Event::SyncConnected { .. }) => {}, - future::Either::Left(Event::SyncDisconnected { .. }) => {}, - future::Either::Right(Event::SyncDisconnected { .. }) => {}, - future::Either::Left(Event::Dht(_)) => {}, - future::Either::Right(Event::Dht(_)) => {}, - }; - } - }); + // Add new events here. + future::Either::Left(Event::SyncConnected { .. }) => {}, + future::Either::Right(Event::SyncConnected { .. }) => {}, + future::Either::Left(Event::SyncDisconnected { .. }) => {}, + future::Either::Right(Event::SyncDisconnected { .. }) => {}, + future::Either::Left(Event::Dht(_)) => {}, + future::Either::Right(Event::Dht(_)) => {}, + }; + } } #[tokio::test] async fn lots_of_incoming_peers_works() { let listen_addr = config::build_multiaddr![Memory(rand::random::())]; - let (main_node, _) = TestNetworkBuilder::new(Handle::current()) + let (main_node, _) = TestNetworkBuilder::new() .with_listen_addresses(vec![listen_addr.clone()]) .with_set_config(SetConfig { in_peers: u32::MAX, ..Default::default() }) .build() @@ -239,7 +223,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(Handle::current()) + let (_dialing_node, event_stream) = TestNetworkBuilder::new() .with_set_config(SetConfig { reserved_nodes: vec![MultiaddrWithPeerId { multiaddr: listen_addr.clone(), @@ -286,20 +270,17 @@ async fn lots_of_incoming_peers_works() { future::join_all(background_tasks_to_wait).await; } -#[test] -fn notifications_back_pressure() { +#[tokio::test] +async fn notifications_back_pressure() { // Node 1 floods node 2 with notifications. Random sleeps are done on node 2 to simulate the // node being busy. We make sure that all notifications are received. const TOTAL_NOTIFS: usize = 10_000; - let runtime = tokio::runtime::Runtime::new().unwrap(); - - let (node1, mut events_stream1, node2, mut events_stream2) = - build_nodes_one_proto(runtime.handle()); + let (node1, mut events_stream1, node2, mut events_stream2) = build_nodes_one_proto(); let node2_id = node2.local_peer_id(); - let receiver = runtime.spawn(async move { + let receiver = tokio::spawn(async move { let mut received_notifications = 0; while received_notifications < TOTAL_NOTIFS { @@ -320,40 +301,36 @@ fn notifications_back_pressure() { } }); - runtime.block_on(async move { - // Wait for the `NotificationStreamOpened`. - loop { - match events_stream1.next().await.unwrap() { - Event::NotificationStreamOpened { .. } => break, - _ => {}, - }; - } + // Wait for the `NotificationStreamOpened`. + loop { + match events_stream1.next().await.unwrap() { + Event::NotificationStreamOpened { .. } => break, + _ => {}, + }; + } - // Sending! - for num in 0..TOTAL_NOTIFS { - let notif = node1.notification_sender(node2_id, PROTOCOL_NAME.into()).unwrap(); - notif - .ready() - .await - .unwrap() - .send(format!("hello #{}", num).into_bytes()) - .unwrap(); - } + // Sending! + for num in 0..TOTAL_NOTIFS { + let notif = node1.notification_sender(node2_id, PROTOCOL_NAME.into()).unwrap(); + notif + .ready() + .await + .unwrap() + .send(format!("hello #{}", num).into_bytes()) + .unwrap(); + } - receiver.await.unwrap(); - }); + receiver.await.unwrap(); } -#[test] -fn fallback_name_working() { +#[tokio::test] +async 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 runtime = tokio::runtime::Runtime::new().unwrap(); - let listen_addr = config::build_multiaddr![Memory(rand::random::())]; - let (node1, mut events_stream1) = TestNetworkBuilder::new(runtime.handle().clone()) + let (node1, mut events_stream1) = TestNetworkBuilder::new() .with_config(config::NetworkConfiguration { extra_sets: vec![NonDefaultSetConfig { notifications_protocol: NEW_PROTOCOL_NAME.into(), @@ -369,7 +346,7 @@ fn fallback_name_working() { .build() .start_network(); - let (_, mut events_stream2) = TestNetworkBuilder::new(runtime.handle().clone()) + let (_, mut events_stream2) = TestNetworkBuilder::new() .with_set_config(SetConfig { reserved_nodes: vec![MultiaddrWithPeerId { multiaddr: listen_addr, @@ -380,7 +357,7 @@ fn fallback_name_working() { .build() .start_network(); - let receiver = runtime.spawn(async move { + let receiver = tokio::spawn(async move { // Wait for the `NotificationStreamOpened`. loop { match events_stream2.next().await.unwrap() { @@ -394,30 +371,27 @@ fn fallback_name_working() { } }); - runtime.block_on(async move { - // Wait for the `NotificationStreamOpened`. - loop { - match events_stream1.next().await.unwrap() { - Event::NotificationStreamOpened { protocol, negotiated_fallback, .. } - if protocol == NEW_PROTOCOL_NAME.into() => - { - assert_eq!(negotiated_fallback, Some(PROTOCOL_NAME.into())); - break - }, - _ => {}, - }; - } + // Wait for the `NotificationStreamOpened`. + loop { + match events_stream1.next().await.unwrap() { + Event::NotificationStreamOpened { protocol, negotiated_fallback, .. } + if protocol == NEW_PROTOCOL_NAME.into() => + { + assert_eq!(negotiated_fallback, Some(PROTOCOL_NAME.into())); + break + }, + _ => {}, + }; + } - receiver.await.unwrap(); - }); + receiver.await.unwrap(); } // Disconnect peer by calling `Protocol::disconnect_peer()` with the supplied block announcement // protocol name and verify that `SyncDisconnected` event is emitted #[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(&Handle::current()); + 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; @@ -454,7 +428,7 @@ async fn disconnect_sync_peer_using_block_announcement_protocol_name() { 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(Handle::current()) + let _ = TestNetworkBuilder::new() .with_config(config::NetworkConfiguration { listen_addresses: vec![listen_addr.clone()], transport: TransportConfig::MemoryOnly, @@ -474,7 +448,7 @@ async fn ensure_listen_addresses_consistent_with_transport_memory() { async fn ensure_listen_addresses_consistent_with_transport_not_memory() { let listen_addr = config::build_multiaddr![Memory(rand::random::())]; - let _ = TestNetworkBuilder::new(Handle::current()) + let _ = TestNetworkBuilder::new() .with_config(config::NetworkConfiguration { listen_addresses: vec![listen_addr.clone()], ..config::NetworkConfiguration::new( @@ -497,7 +471,7 @@ async fn ensure_boot_node_addresses_consistent_with_transport_memory() { peer_id: PeerId::random(), }; - let _ = TestNetworkBuilder::new(Handle::current()) + let _ = TestNetworkBuilder::new() .with_config(config::NetworkConfiguration { listen_addresses: vec![listen_addr.clone()], transport: TransportConfig::MemoryOnly, @@ -522,7 +496,7 @@ async fn ensure_boot_node_addresses_consistent_with_transport_not_memory() { peer_id: PeerId::random(), }; - let _ = TestNetworkBuilder::new(Handle::current()) + let _ = TestNetworkBuilder::new() .with_config(config::NetworkConfiguration { listen_addresses: vec![listen_addr.clone()], boot_nodes: vec![boot_node], @@ -546,7 +520,7 @@ async fn ensure_reserved_node_addresses_consistent_with_transport_memory() { peer_id: PeerId::random(), }; - let _ = TestNetworkBuilder::new(Handle::current()) + let _ = TestNetworkBuilder::new() .with_config(config::NetworkConfiguration { listen_addresses: vec![listen_addr.clone()], transport: TransportConfig::MemoryOnly, @@ -574,7 +548,7 @@ async fn ensure_reserved_node_addresses_consistent_with_transport_not_memory() { peer_id: PeerId::random(), }; - let _ = TestNetworkBuilder::new(Handle::current()) + let _ = TestNetworkBuilder::new() .with_config(config::NetworkConfiguration { listen_addresses: vec![listen_addr.clone()], default_peers_set: SetConfig { @@ -598,7 +572,7 @@ 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(Handle::current()) + let _ = TestNetworkBuilder::new() .with_config(config::NetworkConfiguration { listen_addresses: vec![listen_addr.clone()], transport: TransportConfig::MemoryOnly, @@ -620,7 +594,7 @@ 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(Handle::current()) + let _ = TestNetworkBuilder::new() .with_config(config::NetworkConfiguration { listen_addresses: vec![listen_addr.clone()], public_addresses: vec![public_address], diff --git a/client/network/test/src/lib.rs b/client/network/test/src/lib.rs index 173ca81653b1a..c3304df629e4e 100644 --- a/client/network/test/src/lib.rs +++ b/client/network/test/src/lib.rs @@ -708,16 +708,8 @@ pub struct FullPeerConfig { pub storage_chain: bool, } -/// 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 +pub trait TestNetFactory: Default + Sized where >::Transaction: Send, { @@ -747,9 +739,9 @@ where ); /// Create new test network with this many peers. - fn new(rt_handle: tokio::runtime::Handle, n: usize) -> Self { + fn new(n: usize) -> Self { trace!(target: "test_network", "Creating test network"); - let mut net = Self::with_runtime(rt_handle); + let mut net = Self::default(); for i in 0..n { trace!(target: "test_network", "Adding peer {}", i); @@ -905,14 +897,11 @@ 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: Box::new(executor), + executor: Box::new(|f| { + tokio::spawn(f); + }), network_config, chain: client.clone(), protocol_id, @@ -934,10 +923,10 @@ where trace!(target: "test_network", "Peer identifier: {}", network.service().local_peer_id()); let service = network.service().clone(); - self.rt_handle().spawn(async move { + tokio::spawn(async move { chain_sync_network_provider.run(service).await; }); - self.rt_handle().spawn(async move { + tokio::spawn(async move { import_queue.run(Box::new(chain_sync_service)).await; }); @@ -968,7 +957,7 @@ where /// Used to spawn background tasks, e.g. the block request protocol handler. fn spawn_task(&self, f: BoxFuture<'static, ()>) { - self.rt_handle().spawn(f); + tokio::spawn(f); } /// Polls the testnet until all nodes are in sync. @@ -1027,11 +1016,11 @@ where Poll::Pending } - /// Wait until we are sync'ed. + /// Run the network until we are sync'ed. /// /// Calls `poll_until_sync` repeatedly. /// (If we've not synced within 10 mins then panic rather than hang.) - async fn wait_until_sync(&mut self) { + async fn run_until_sync(&mut self) { timeout( Duration::from_secs(10 * 60), futures::future::poll_fn::<(), _>(|cx| self.poll_until_sync(cx)), @@ -1040,17 +1029,17 @@ where .expect("sync didn't happen within 10 mins"); } - /// Wait until there are no pending packets. + /// Run the network until there are no pending packets. /// /// Calls `poll_until_idle` repeatedly with the runtime passed as parameter. - async fn wait_until_idle(&mut self) { + async fn run_until_idle(&mut self) { futures::future::poll_fn::<(), _>(|cx| self.poll_until_idle(cx)).await; } - /// Wait until all peers are connected to each other. + /// Run the network until all peers are connected to each other. /// /// Calls `poll_until_connected` repeatedly with the runtime passed as parameter. - async fn wait_until_connected(&mut self) { + async fn run_until_connected(&mut self) { futures::future::poll_fn::<(), _>(|cx| self.poll_until_connected(cx)).await; } @@ -1082,20 +1071,11 @@ 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 = (); @@ -1150,16 +1130,9 @@ impl JustificationImport for ForceFinalized { .map_err(|_| ConsensusError::InvalidJustification) } } -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() - } -} +#[derive(Default)] +pub struct JustificationTestNet(TestNet); impl TestNetFactory for JustificationTestNet { type Verifier = PassThroughVerifier; diff --git a/client/network/test/src/sync.rs b/client/network/test/src/sync.rs index efe0e0577c11e..9a9b5782dc2a7 100644 --- a/client/network/test/src/sync.rs +++ b/client/network/test/src/sync.rs @@ -21,12 +21,10 @@ 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) { +async fn test_ancestor_search_when_common_is(n: usize) { sp_tracing::try_init_simple(); - let runtime = Runtime::new().unwrap(); - let mut net = TestNet::new(runtime.handle().clone(), 3); + let mut net = TestNet::new(3); net.peer(0).push_blocks(n, false); net.peer(1).push_blocks(n, false); @@ -36,18 +34,17 @@ fn test_ancestor_search_when_common_is(n: usize) { net.peer(1).push_blocks(100, false); net.peer(2).push_blocks(100, false); - runtime.block_on(net.wait_until_sync()); + net.run_until_sync().await; let peer1 = &net.peers()[1]; assert!(net.peers()[0].blockchain_canon_equals(peer1)); } -#[test] -fn sync_peers_works() { +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn sync_peers_works() { sp_tracing::try_init_simple(); - let runtime = Runtime::new().unwrap(); - let mut net = TestNet::new(runtime.handle().clone(), 3); + let mut net = TestNet::new(3); - runtime.block_on(futures::future::poll_fn::<(), _>(|cx| { + futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); for peer in 0..3 { if net.peer(peer).num_peers() != 2 { @@ -55,14 +52,14 @@ fn sync_peers_works() { } } Poll::Ready(()) - })); + }) + .await; } -#[test] -fn sync_cycle_from_offline_to_syncing_to_offline() { +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn sync_cycle_from_offline_to_syncing_to_offline() { sp_tracing::try_init_simple(); - let runtime = Runtime::new().unwrap(); - let mut net = TestNet::new(runtime.handle().clone(), 3); + let mut net = TestNet::new(3); for peer in 0..3 { // Offline, and not major syncing. assert!(net.peer(peer).is_offline()); @@ -73,7 +70,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. - runtime.block_on(futures::future::poll_fn::<(), _>(|cx| { + futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); for peer in 0..3 { // Online @@ -88,10 +85,11 @@ fn sync_cycle_from_offline_to_syncing_to_offline() { } } Poll::Ready(()) - })); + }) + .await; // Block until all nodes are done syncing. - runtime.block_on(futures::future::poll_fn::<(), _>(|cx| { + futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); for peer in 0..3 { if net.peer(peer).is_major_syncing() { @@ -99,26 +97,27 @@ fn sync_cycle_from_offline_to_syncing_to_offline() { } } Poll::Ready(()) - })); + }) + .await; // Now drop nodes 1 and 2, and check that node 0 is offline. net.peers.remove(2); net.peers.remove(1); - runtime.block_on(futures::future::poll_fn::<(), _>(|cx| { + futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); if !net.peer(0).is_offline() { Poll::Pending } else { Poll::Ready(()) } - })); + }) + .await; } -#[test] -fn syncing_node_not_major_syncing_when_disconnected() { +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn syncing_node_not_major_syncing_when_disconnected() { sp_tracing::try_init_simple(); - let runtime = Runtime::new().unwrap(); - let mut net = TestNet::new(runtime.handle().clone(), 3); + let mut net = TestNet::new(3); // Generate blocks. net.peer(2).push_blocks(100, false); @@ -127,136 +126,132 @@ fn syncing_node_not_major_syncing_when_disconnected() { assert!(!net.peer(1).is_major_syncing()); // Check that we switch to major syncing. - runtime.block_on(futures::future::poll_fn::<(), _>(|cx| { + futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); if !net.peer(1).is_major_syncing() { Poll::Pending } else { Poll::Ready(()) } - })); + }) + .await; // Destroy two nodes, and check that we switch to non-major syncing. net.peers.remove(2); net.peers.remove(0); - runtime.block_on(futures::future::poll_fn::<(), _>(|cx| { + futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); if net.peer(0).is_major_syncing() { Poll::Pending } else { Poll::Ready(()) } - })); + }) + .await; } -#[test] -fn sync_from_two_peers_works() { +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn sync_from_two_peers_works() { sp_tracing::try_init_simple(); - let runtime = Runtime::new().unwrap(); - let mut net = TestNet::new(runtime.handle().clone(), 3); + let mut net = TestNet::new(3); net.peer(1).push_blocks(100, false); net.peer(2).push_blocks(100, false); - runtime.block_on(net.wait_until_sync()); + net.run_until_sync().await; let peer1 = &net.peers()[1]; assert!(net.peers()[0].blockchain_canon_equals(peer1)); assert!(!net.peer(0).is_major_syncing()); } -#[test] -fn sync_from_two_peers_with_ancestry_search_works() { +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn sync_from_two_peers_with_ancestry_search_works() { sp_tracing::try_init_simple(); - let runtime = Runtime::new().unwrap(); - let mut net = TestNet::new(runtime.handle().clone(), 3); + let mut net = TestNet::new(3); net.peer(0).push_blocks(10, true); net.peer(1).push_blocks(100, false); net.peer(2).push_blocks(100, false); - runtime.block_on(net.wait_until_sync()); + net.run_until_sync().await; let peer1 = &net.peers()[1]; assert!(net.peers()[0].blockchain_canon_equals(peer1)); } -#[test] -fn ancestry_search_works_when_backoff_is_one() { +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn ancestry_search_works_when_backoff_is_one() { sp_tracing::try_init_simple(); - let runtime = Runtime::new().unwrap(); - let mut net = TestNet::new(runtime.handle().clone(), 3); + let mut net = TestNet::new(3); net.peer(0).push_blocks(1, false); net.peer(1).push_blocks(2, false); net.peer(2).push_blocks(2, false); - runtime.block_on(net.wait_until_sync()); + net.run_until_sync().await; let peer1 = &net.peers()[1]; assert!(net.peers()[0].blockchain_canon_equals(peer1)); } -#[test] -fn ancestry_search_works_when_ancestor_is_genesis() { +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn ancestry_search_works_when_ancestor_is_genesis() { sp_tracing::try_init_simple(); - let runtime = Runtime::new().unwrap(); - let mut net = TestNet::new(runtime.handle().clone(), 3); + let mut net = TestNet::new(3); net.peer(0).push_blocks(13, true); net.peer(1).push_blocks(100, false); net.peer(2).push_blocks(100, false); - runtime.block_on(net.wait_until_sync()); + net.run_until_sync().await; let peer1 = &net.peers()[1]; assert!(net.peers()[0].blockchain_canon_equals(peer1)); } -#[test] -fn ancestry_search_works_when_common_is_one() { - test_ancestor_search_when_common_is(1); +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn ancestry_search_works_when_common_is_one() { + test_ancestor_search_when_common_is(1).await; } -#[test] -fn ancestry_search_works_when_common_is_two() { - test_ancestor_search_when_common_is(2); +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn ancestry_search_works_when_common_is_two() { + test_ancestor_search_when_common_is(2).await; } -#[test] -fn ancestry_search_works_when_common_is_hundred() { - test_ancestor_search_when_common_is(100); +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn ancestry_search_works_when_common_is_hundred() { + test_ancestor_search_when_common_is(100).await; } -#[test] -fn sync_long_chain_works() { +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn sync_long_chain_works() { sp_tracing::try_init_simple(); - let runtime = Runtime::new().unwrap(); - let mut net = TestNet::new(runtime.handle().clone(), 2); + let mut net = TestNet::new(2); net.peer(1).push_blocks(500, false); - runtime.block_on(net.wait_until_sync()); + net.run_until_sync().await; let peer1 = &net.peers()[1]; assert!(net.peers()[0].blockchain_canon_equals(peer1)); } -#[test] -fn sync_no_common_longer_chain_fails() { +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn sync_no_common_longer_chain_fails() { sp_tracing::try_init_simple(); - let runtime = Runtime::new().unwrap(); - let mut net = TestNet::new(runtime.handle().clone(), 3); + let mut net = TestNet::new(3); net.peer(0).push_blocks(20, true); net.peer(1).push_blocks(20, false); - runtime.block_on(futures::future::poll_fn::<(), _>(|cx| { + futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); if net.peer(0).is_major_syncing() { Poll::Pending } else { Poll::Ready(()) } - })); + }) + .await; let peer1 = &net.peers()[1]; assert!(!net.peers()[0].blockchain_canon_equals(peer1)); } -#[test] -fn sync_justifications() { +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn sync_justifications() { sp_tracing::try_init_simple(); - let runtime = Runtime::new().unwrap(); - let mut net = JustificationTestNet::new(runtime.handle().clone(), 3); + let mut net = JustificationTestNet::new(3); net.peer(0).push_blocks(20, false); - runtime.block_on(net.wait_until_sync()); + net.run_until_sync().await; let backend = net.peer(0).client().as_backend(); let hashof10 = backend.blockchain().expect_block_hash_from_id(&BlockId::Number(10)).unwrap(); @@ -282,7 +277,7 @@ fn sync_justifications() { net.peer(1).request_justification(&hashof15, 15); net.peer(1).request_justification(&hashof20, 20); - runtime.block_on(futures::future::poll_fn::<(), _>(|cx| { + futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); for hash in [hashof10, hashof15, hashof20] { @@ -299,14 +294,14 @@ fn sync_justifications() { } Poll::Ready(()) - })); + }) + .await; } -#[test] -fn sync_justifications_across_forks() { +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn sync_justifications_across_forks() { sp_tracing::try_init_simple(); - let runtime = Runtime::new().unwrap(); - let mut net = JustificationTestNet::new(runtime.handle().clone(), 3); + let mut net = JustificationTestNet::new(3); // we push 5 blocks net.peer(0).push_blocks(5, false); // and then two forks 5 and 6 blocks long @@ -315,7 +310,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. - runtime.block_on(net.wait_until_sync()); + net.run_until_sync().await; let just = (*b"FRNK", Vec::new()); net.peer(0).client().finalize_block(f1_best, Some(just), true).unwrap(); @@ -323,7 +318,7 @@ fn sync_justifications_across_forks() { net.peer(1).request_justification(&f1_best, 10); net.peer(1).request_justification(&f2_best, 11); - runtime.block_on(futures::future::poll_fn::<(), _>(|cx| { + futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); if net.peer(0).client().justifications(f1_best).unwrap() == @@ -335,14 +330,14 @@ fn sync_justifications_across_forks() { } else { Poll::Pending } - })); + }) + .await; } -#[test] -fn sync_after_fork_works() { +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn sync_after_fork_works() { sp_tracing::try_init_simple(); - let runtime = Runtime::new().unwrap(); - let mut net = TestNet::new(runtime.handle().clone(), 3); + let mut net = TestNet::new(3); net.peer(0).push_blocks(30, false); net.peer(1).push_blocks(30, false); net.peer(2).push_blocks(30, false); @@ -355,25 +350,24 @@ fn sync_after_fork_works() { net.peer(2).push_blocks(1, false); // peer 1 has the best chain - runtime.block_on(net.wait_until_sync()); + net.run_until_sync().await; let peer1 = &net.peers()[1]; assert!(net.peers()[0].blockchain_canon_equals(peer1)); (net.peers()[1].blockchain_canon_equals(peer1)); (net.peers()[2].blockchain_canon_equals(peer1)); } -#[test] -fn syncs_all_forks() { +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn syncs_all_forks() { sp_tracing::try_init_simple(); - let runtime = Runtime::new().unwrap(); - let mut net = TestNet::new(runtime.handle().clone(), 4); + let mut net = TestNet::new(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); - runtime.block_on(net.wait_until_sync()); + net.run_until_sync().await; // Check that all peers have all of the branches. assert!(net.peer(0).has_block(b1)); assert!(net.peer(0).has_block(b2)); @@ -381,16 +375,15 @@ fn syncs_all_forks() { assert!(net.peer(1).has_block(b2)); } -#[test] -fn own_blocks_are_announced() { +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn own_blocks_are_announced() { sp_tracing::try_init_simple(); - let runtime = Runtime::new().unwrap(); - let mut net = TestNet::new(runtime.handle().clone(), 3); - runtime.block_on(net.wait_until_sync()); // connect'em + let mut net = TestNet::new(3); + net.run_until_sync().await; // connect'em net.peer(0) .generate_blocks(1, BlockOrigin::Own, |builder| builder.build().unwrap().block); - runtime.block_on(net.wait_until_sync()); + net.run_until_sync().await; assert_eq!(net.peer(0).client.info().best_number, 1); assert_eq!(net.peer(1).client.info().best_number, 1); @@ -399,11 +392,10 @@ fn own_blocks_are_announced() { (net.peers()[2].blockchain_canon_equals(peer0)); } -#[test] -fn can_sync_small_non_best_forks() { +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn can_sync_small_non_best_forks() { sp_tracing::try_init_simple(); - let runtime = Runtime::new().unwrap(); - let mut net = TestNet::new(runtime.handle().clone(), 2); + let mut net = TestNet::new(2); net.peer(0).push_blocks(30, false); net.peer(1).push_blocks(30, false); @@ -421,14 +413,15 @@ 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 - runtime.block_on(futures::future::poll_fn::<(), _>(|cx| { + futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); if net.peer(0).num_peers() == 0 { Poll::Pending } else { Poll::Ready(()) } - })); + }) + .await; // synchronization: 0 synced to longer chain and 1 didn't sync to small chain. @@ -441,7 +434,7 @@ fn can_sync_small_non_best_forks() { // after announcing, peer 1 downloads the block. - runtime.block_on(futures::future::poll_fn::<(), _>(|cx| { + futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); assert!(net.peer(0).client().header(&BlockId::Hash(small_hash)).unwrap().is_some()); @@ -449,29 +442,30 @@ fn can_sync_small_non_best_forks() { return Poll::Pending } Poll::Ready(()) - })); - runtime.block_on(net.wait_until_sync()); + }) + .await; + net.run_until_sync().await; let another_fork = net.peer(0).push_blocks_at(BlockId::Number(35), 2, true); net.peer(0).announce_block(another_fork, None); - runtime.block_on(futures::future::poll_fn::<(), _>(|cx| { + futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); if net.peer(1).client().header(&BlockId::Hash(another_fork)).unwrap().is_none() { return Poll::Pending } Poll::Ready(()) - })); + }) + .await; } -#[test] -fn can_sync_forks_ahead_of_the_best_chain() { +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn can_sync_forks_ahead_of_the_best_chain() { sp_tracing::try_init_simple(); - let runtime = Runtime::new().unwrap(); - let mut net = TestNet::new(runtime.handle().clone(), 2); + let mut net = TestNet::new(2); net.peer(0).push_blocks(1, false); net.peer(1).push_blocks(1, false); - runtime.block_on(net.wait_until_connected()); + net.run_until_connected().await; // Peer 0 is on 2-block fork which is announced with is_best=false let fork_hash = net.peer(0).generate_blocks_with_fork_choice( 2, @@ -486,21 +480,21 @@ 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. - runtime.block_on(futures::future::poll_fn::<(), _>(|cx| { + 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(()) - })); + }) + .await; } -#[test] -fn can_sync_explicit_forks() { +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn can_sync_explicit_forks() { sp_tracing::try_init_simple(); - let runtime = Runtime::new().unwrap(); - let mut net = TestNet::new(runtime.handle().clone(), 2); + let mut net = TestNet::new(2); net.peer(0).push_blocks(30, false); net.peer(1).push_blocks(30, false); @@ -519,14 +513,15 @@ 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 - runtime.block_on(futures::future::poll_fn::<(), _>(|cx| { + futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); if net.peer(0).num_peers() == 0 || net.peer(1).num_peers() == 0 { Poll::Pending } else { Poll::Ready(()) } - })); + }) + .await; // synchronization: 0 synced to longer chain and 1 didn't sync to small chain. @@ -540,7 +535,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. - runtime.block_on(futures::future::poll_fn::<(), _>(|cx| { + futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); assert!(net.peer(0).client().header(&BlockId::Hash(small_hash)).unwrap().is_some()); @@ -548,14 +543,14 @@ fn can_sync_explicit_forks() { return Poll::Pending } Poll::Ready(()) - })); + }) + .await; } -#[test] -fn syncs_header_only_forks() { +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn syncs_header_only_forks() { sp_tracing::try_init_simple(); - let runtime = Runtime::new().unwrap(); - let mut net = TestNet::new(runtime.handle().clone(), 0); + let mut net = TestNet::new(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); @@ -567,19 +562,18 @@ 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) { - runtime.block_on(net.wait_until_idle()); + net.run_until_idle().await; } - runtime.block_on(net.wait_until_sync()); + net.run_until_sync().await; 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] -fn does_not_sync_announced_old_best_block() { +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn does_not_sync_announced_old_best_block() { sp_tracing::try_init_simple(); - let runtime = Runtime::new().unwrap(); - let mut net = TestNet::new(runtime.handle().clone(), 3); + let mut net = TestNet::new(3); let old_hash = net.peer(0).push_blocks(1, false); let old_hash_with_parent = net.peer(0).push_blocks(1, false); @@ -587,92 +581,93 @@ fn does_not_sync_announced_old_best_block() { net.peer(1).push_blocks(20, true); net.peer(0).announce_block(old_hash, None); - runtime.block_on(futures::future::poll_fn::<(), _>(|cx| { + futures::future::poll_fn::<(), _>(|cx| { // poll once to import announcement net.poll(cx); Poll::Ready(()) - })); + }) + .await; assert!(!net.peer(1).is_major_syncing()); net.peer(0).announce_block(old_hash_with_parent, None); - runtime.block_on(futures::future::poll_fn::<(), _>(|cx| { + futures::future::poll_fn::<(), _>(|cx| { // poll once to import announcement net.poll(cx); Poll::Ready(()) - })); + }) + .await; assert!(!net.peer(1).is_major_syncing()); } -#[test] -fn full_sync_requires_block_body() { +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn full_sync_requires_block_body() { // Check that we don't sync headers-only in full mode. sp_tracing::try_init_simple(); - let runtime = Runtime::new().unwrap(); - let mut net = TestNet::new(runtime.handle().clone(), 2); + let mut net = TestNet::new(2); net.peer(0).push_headers(1); // Wait for nodes to connect - runtime.block_on(futures::future::poll_fn::<(), _>(|cx| { + futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); if net.peer(0).num_peers() == 0 || net.peer(1).num_peers() == 0 { Poll::Pending } else { Poll::Ready(()) } - })); - runtime.block_on(net.wait_until_idle()); + }) + .await; + net.run_until_idle().await; assert_eq!(net.peer(1).client.info().best_number, 0); } -#[test] -fn imports_stale_once() { +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn imports_stale_once() { sp_tracing::try_init_simple(); - let runtime = Runtime::new().unwrap(); - fn import_with_announce(runtime: &Runtime, net: &mut TestNet, hash: H256) { + async fn import_with_announce(net: &mut TestNet, hash: H256) { // Announce twice net.peer(0).announce_block(hash, None); net.peer(0).announce_block(hash, None); - runtime.block_on(futures::future::poll_fn::<(), _>(|cx| { + 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 } - })); + }) + .await; } // given the network with 2 full nodes - let mut net = TestNet::new(runtime.handle().clone(), 2); + let mut net = TestNet::new(2); // let them connect to each other - runtime.block_on(net.wait_until_sync()); + net.run_until_sync().await; // check that NEW block is imported from announce message let new_hash = net.peer(0).push_blocks(1, false); - import_with_announce(&runtime, &mut net, new_hash); + import_with_announce(&mut net, new_hash).await; 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(&runtime, &mut net, known_stale_hash); + import_with_announce(&mut net, known_stale_hash).await; assert_eq!(net.peer(1).num_downloaded_blocks(), 2); } -#[test] -fn can_sync_to_peers_with_wrong_common_block() { +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn can_sync_to_peers_with_wrong_common_block() { sp_tracing::try_init_simple(); - let runtime = Runtime::new().unwrap(); - let mut net = TestNet::new(runtime.handle().clone(), 2); + let mut net = TestNet::new(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 - runtime.block_on(net.wait_until_connected()); + net.run_until_connected().await; // both peers re-org to the same fork without notifying each other let just = Some((*b"FRNK", Vec::new())); @@ -680,7 +675,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); - runtime.block_on(net.wait_until_sync()); + net.run_until_sync().await; assert!(net.peer(1).has_block(final_hash)); } @@ -722,11 +717,10 @@ impl BlockAnnounceValidator for FailingBlockAnnounceValidator { } } -#[test] -fn sync_blocks_when_block_announce_validator_says_it_is_new_best() { +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn sync_blocks_when_block_announce_validator_says_it_is_new_best() { sp_tracing::try_init_simple(); - let runtime = Runtime::new().unwrap(); - let mut net = TestNet::new(runtime.handle().clone(), 0); + 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 { @@ -734,7 +728,7 @@ fn sync_blocks_when_block_announce_validator_says_it_is_new_best() { ..Default::default() }); - runtime.block_on(net.wait_until_connected()); + net.run_until_connected().await; // Add blocks but don't set them as best let block_hash = net.peer(0).generate_blocks_with_fork_choice( @@ -745,7 +739,7 @@ fn sync_blocks_when_block_announce_validator_says_it_is_new_best() { ); while !net.peer(2).has_block(block_hash) { - runtime.block_on(net.wait_until_idle()); + net.run_until_idle().await; } } @@ -767,18 +761,17 @@ impl BlockAnnounceValidator for DeferredBlockAnnounceValidator { } } -#[test] -fn wait_until_deferred_block_announce_validation_is_ready() { +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn wait_until_deferred_block_announce_validation_is_ready() { sp_tracing::try_init_simple(); - let runtime = Runtime::new().unwrap(); - let mut net = TestNet::new(runtime.handle().clone(), 0); + 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)), ..Default::default() }); - runtime.block_on(net.wait_until_connected()); + net.run_until_connected().await; // Add blocks but don't set them as best let block_hash = net.peer(0).generate_blocks_with_fork_choice( @@ -789,17 +782,16 @@ fn wait_until_deferred_block_announce_validation_is_ready() { ); while !net.peer(1).has_block(block_hash) { - runtime.block_on(net.wait_until_idle()); + net.run_until_idle().await; } } /// When we don't inform the sync protocol about the best block, a node will not sync from us as the /// handshake is not does not contain our best block. -#[test] -fn sync_to_tip_requires_that_sync_protocol_is_informed_about_best_block() { +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn sync_to_tip_requires_that_sync_protocol_is_informed_about_best_block() { sp_tracing::try_init_simple(); - let runtime = Runtime::new().unwrap(); - let mut net = TestNet::new(runtime.handle().clone(), 1); + let mut net = TestNet::new(1); // Produce some blocks let block_hash = @@ -807,18 +799,16 @@ 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 - runtime.block_on(async { - net.add_full_peer_with_config(Default::default()); - net.wait_until_connected().await; - net.wait_until_idle().await; - }); + net.add_full_peer_with_config(Default::default()); + net.run_until_connected().await; + net.run_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); - runtime.block_on(net.wait_until_idle()); + net.run_until_idle().await; // Connect another node that should now sync to the tip net.add_full_peer_with_config(FullPeerConfig { @@ -826,14 +816,15 @@ fn sync_to_tip_requires_that_sync_protocol_is_informed_about_best_block() { ..Default::default() }); - runtime.block_on(futures::future::poll_fn::<(), _>(|cx| { + futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); if net.peer(2).has_block(block_hash) { Poll::Ready(()) } else { Poll::Pending } - })); + }) + .await; // However peer 1 should still not have the block. assert!(!net.peer(1).has_block(block_hash)); @@ -841,12 +832,11 @@ fn sync_to_tip_requires_that_sync_protocol_is_informed_about_best_block() { /// Ensures that if we as a syncing node sync to the tip while we are connected to another peer /// that is currently also doing a major sync. -#[test] -fn sync_to_tip_when_we_sync_together_with_multiple_peers() { +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async 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(runtime.handle().clone(), 3); + let mut net = TestNet::new(3); let block_hash = net.peer(0) @@ -855,10 +845,8 @@ 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); - runtime.block_on(async { - net.wait_until_connected().await; - net.wait_until_idle().await; - }); + net.run_until_connected().await; + net.run_until_idle().await; assert!(!net.peer(2).has_block(block_hash)); @@ -866,14 +854,14 @@ 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) { - runtime.block_on(net.wait_until_idle()); + net.run_until_idle().await; } } /// Ensures that when we receive a block announcement with some data attached, that we propagate /// this data when reannouncing the block. -#[test] -fn block_announce_data_is_propagated() { +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn block_announce_data_is_propagated() { struct TestBlockAnnounceValidator; impl BlockAnnounceValidator for TestBlockAnnounceValidator { @@ -897,8 +885,7 @@ fn block_announce_data_is_propagated() { } sp_tracing::try_init_simple(); - let runtime = Runtime::new().unwrap(); - let mut net = TestNet::new(runtime.handle().clone(), 1); + let mut net = TestNet::new(1); net.add_full_peer_with_config(FullPeerConfig { block_announce_validator: Some(Box::new(TestBlockAnnounceValidator)), @@ -912,7 +899,7 @@ fn block_announce_data_is_propagated() { }); // Wait until peer 1 is connected to both nodes. - runtime.block_on(futures::future::poll_fn::<(), _>(|cx| { + futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); if net.peer(1).num_peers() == 2 && net.peer(0).num_peers() == 1 && @@ -922,18 +909,19 @@ fn block_announce_data_is_propagated() { } else { Poll::Pending } - })); + }) + .await; 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) { - runtime.block_on(net.wait_until_idle()); + net.run_until_idle().await; } } -#[test] -fn continue_to_sync_after_some_block_announcement_verifications_failed() { +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn continue_to_sync_after_some_block_announcement_verifications_failed() { struct TestBlockAnnounceValidator; impl BlockAnnounceValidator for TestBlockAnnounceValidator { @@ -958,22 +946,19 @@ fn continue_to_sync_after_some_block_announcement_verifications_failed() { } sp_tracing::try_init_simple(); - let runtime = Runtime::new().unwrap(); - let mut net = TestNet::new(runtime.handle().clone(), 1); + let mut net = TestNet::new(1); net.add_full_peer_with_config(FullPeerConfig { block_announce_validator: Some(Box::new(TestBlockAnnounceValidator)), ..Default::default() }); - runtime.block_on(async { - net.wait_until_connected().await; - net.wait_until_idle().await; - }); + net.run_until_connected().await; + net.run_until_idle().await; let block_hash = net.peer(0).push_blocks(500, true); - runtime.block_on(net.wait_until_sync()); + net.run_until_sync().await; assert!(net.peer(1).has_block(block_hash)); } @@ -981,13 +966,12 @@ fn continue_to_sync_after_some_block_announcement_verifications_failed() { /// this peer if the request was successful. In the case of a justification request for example, /// we ask our peers multiple times until we got the requested justification. This test ensures that /// asking for the same justification multiple times doesn't ban a peer. -#[test] -fn multiple_requests_are_accepted_as_long_as_they_are_not_fulfilled() { +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn multiple_requests_are_accepted_as_long_as_they_are_not_fulfilled() { sp_tracing::try_init_simple(); - let runtime = Runtime::new().unwrap(); - let mut net = JustificationTestNet::new(runtime.handle().clone(), 2); + let mut net = JustificationTestNet::new(2); net.peer(0).push_blocks(10, false); - runtime.block_on(net.wait_until_sync()); + net.run_until_sync().await; let hashof10 = net.peer(1).client().header(&BlockId::Number(10)).unwrap().unwrap().hash(); @@ -1002,9 +986,9 @@ fn multiple_requests_are_accepted_as_long_as_they_are_not_fulfilled() { for _ in 0..5 { // We need to sleep 10 seconds as this is the time we wait between sending a new // justification request. - std::thread::sleep(std::time::Duration::from_secs(10)); + tokio::time::sleep(tokio::time::Duration::from_secs(10)).await; net.peer(0).push_blocks(1, false); - runtime.block_on(net.wait_until_sync()); + net.run_until_sync().await; assert_eq!(1, net.peer(0).num_peers()); } @@ -1021,7 +1005,7 @@ fn multiple_requests_are_accepted_as_long_as_they_are_not_fulfilled() { .finalize_block(hashof10, Some((*b"FRNK", Vec::new())), true) .unwrap(); - runtime.block_on(futures::future::poll_fn::<(), _>(|cx| { + futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); if net.peer(1).client().justifications(hashof10).unwrap() != @@ -1031,47 +1015,47 @@ fn multiple_requests_are_accepted_as_long_as_they_are_not_fulfilled() { } Poll::Ready(()) - })); + }) + .await; } -#[test] -fn syncs_all_forks_from_single_peer() { +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn syncs_all_forks_from_single_peer() { sp_tracing::try_init_simple(); - let runtime = Runtime::new().unwrap(); - let mut net = TestNet::new(runtime.handle().clone(), 2); + let mut net = TestNet::new(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 - runtime.block_on(net.wait_until_connected()); + net.run_until_connected().await; // 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 - runtime.block_on(futures::future::poll_fn::<(), _>(|cx| { + futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); if net.peer(1).network().best_seen_block() != Some(12) { return Poll::Pending } Poll::Ready(()) - })); + }) + .await; // Peer 0 produces and announces another fork let branch2 = net.peer(0).push_blocks_at(BlockId::Number(10), 2, false); - runtime.block_on(net.wait_until_sync()); + net.run_until_sync().await; // Peer 1 should have both branches, assert!(net.peer(1).client().header(&BlockId::Hash(branch1)).unwrap().is_some()); assert!(net.peer(1).client().header(&BlockId::Hash(branch2)).unwrap().is_some()); } -#[test] -fn syncs_after_missing_announcement() { +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn syncs_after_missing_announcement() { sp_tracing::try_init_simple(); - let runtime = Runtime::new().unwrap(); - let mut net = TestNet::new(runtime.handle().clone(), 0); + let mut net = TestNet::new(0); net.add_full_peer_with_config(Default::default()); // Set peer 1 to ignore announcement net.add_full_peer_with_config(FullPeerConfig { @@ -1081,23 +1065,22 @@ fn syncs_after_missing_announcement() { net.peer(0).push_blocks(10, false); net.peer(1).push_blocks(10, false); - runtime.block_on(net.wait_until_connected()); + net.run_until_connected().await; // 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); - runtime.block_on(net.wait_until_sync()); + net.run_until_sync().await; assert!(net.peer(1).client().header(&BlockId::Hash(final_block)).unwrap().is_some()); } -#[test] -fn syncs_state() { +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn syncs_state() { sp_tracing::try_init_simple(); - let runtime = Runtime::new().unwrap(); for skip_proofs in &[false, true] { - let mut net = TestNet::new(runtime.handle().clone(), 0); + let mut net = TestNet::new(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(); @@ -1138,7 +1121,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. - runtime.block_on(net.wait_until_sync()); + net.run_until_sync().await; assert!(!net.peer(1).client().has_state_at(&BlockId::Number(64))); let just = (*b"FRNK", Vec::new()); @@ -1151,33 +1134,34 @@ fn syncs_state() { .unwrap(); net.peer(1).client().finalize_block(hashof60, Some(just), true).unwrap(); // Wait for state sync. - runtime.block_on(futures::future::poll_fn::<(), _>(|cx| { + futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); if net.peer(1).client.info().finalized_state.is_some() { Poll::Ready(()) } else { Poll::Pending } - })); + }) + .await; assert!(!net.peer(1).client().has_state_at(&BlockId::Number(64))); // Wait for the rest of the states to be imported. - runtime.block_on(futures::future::poll_fn::<(), _>(|cx| { + futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); if net.peer(1).client().has_state_at(&BlockId::Number(64)) { Poll::Ready(()) } else { Poll::Pending } - })); + }) + .await; } } -#[test] -fn syncs_indexed_blocks() { +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn syncs_indexed_blocks() { use sp_runtime::traits::Hash; sp_tracing::try_init_simple(); - let runtime = Runtime::new().unwrap(); - let mut net = TestNet::new(runtime.handle().clone(), 0); + let mut net = TestNet::new(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 { @@ -1216,7 +1200,7 @@ fn syncs_indexed_blocks() { .unwrap() .is_none()); - runtime.block_on(net.wait_until_sync()); + net.run_until_sync().await; assert!(net .peer(1) .client() @@ -1226,11 +1210,10 @@ fn syncs_indexed_blocks() { .is_some()); } -#[test] -fn warp_sync() { +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn warp_sync() { sp_tracing::try_init_simple(); - let runtime = Runtime::new().unwrap(); - let mut net = TestNet::new(runtime.handle().clone(), 0); + 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()); @@ -1244,30 +1227,30 @@ fn warp_sync() { net.peer(1).push_blocks(64, false); net.peer(2).push_blocks(64, false); // Wait for peer 1 to sync state. - runtime.block_on(net.wait_until_sync()); + net.run_until_sync().await; 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 - runtime.block_on(futures::future::poll_fn::<(), _>(|cx| { + futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); if net.peer(3).has_body(gap_end) && net.peer(3).has_body(target) { Poll::Ready(()) } else { Poll::Pending } - })); + }) + .await; } -#[test] -fn syncs_huge_blocks() { +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn syncs_huge_blocks() { use sp_core::storage::well_known_keys::HEAP_PAGES; use sp_runtime::codec::Encode; use substrate_test_runtime_client::BlockBuilderExt; sp_tracing::try_init_simple(); - let runtime = Runtime::new().unwrap(); - let mut net = TestNet::new(runtime.handle().clone(), 2); + let mut net = TestNet::new(2); // Increase heap space for bigger blocks. net.peer(0).generate_blocks(1, BlockOrigin::Own, |mut builder| { @@ -1284,7 +1267,7 @@ fn syncs_huge_blocks() { builder.build().unwrap().block }); - runtime.block_on(net.wait_until_sync()); + net.run_until_sync().await; assert_eq!(net.peer(0).client.info().best_number, 33); assert_eq!(net.peer(1).client.info().best_number, 33); } From 85f660fded10af9ee80d5acb6efcc16dc59fffd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Fri, 16 Dec 2022 15:01:31 +0100 Subject: [PATCH 201/715] Fix missing block number issue on forced canonicalization (#12949) * Fix missing block number issue on forced canonicalization There is this issue about missing block numbers on forced canonicalization. I looked over the code now 10000 times and there are possible ways this can be triggered, but I don't really know how this is triggered. So, this pr is going to solve the symptom and not the cause. The block number to hash mapping is set when we import a new best block. Forced canonicalization will now stop at the best block and it will canonicalize the other blocks later when the best block moved. As the error reports indicated that this issue mainly happened on major sync, there should not be any forks, so not doing the canonicalization directly shouldn't be that harmful. All known implementations should import all blocks as best block on major sync anyway (I mean somewhere there is the bug, but I didn't yet found it). I will also do some changes to Cumulus around some potential culprit for this issue. Closes: https://github.com/paritytech/substrate/issues/12613 * Add some docs * Fix fix * Review comments * Review comments --- client/db/src/lib.rs | 187 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 158 insertions(+), 29 deletions(-) diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index 4452d5dcb3f29..7c2635f843418 100644 --- a/client/db/src/lib.rs +++ b/client/db/src/lib.rs @@ -1213,9 +1213,8 @@ impl Backend { let meta = self.blockchain.meta.read(); - if meta.best_number > best_number && - (meta.best_number - best_number).saturated_into::() > - self.canonicalization_delay + if meta.best_number.saturating_sub(best_number).saturated_into::() > + self.canonicalization_delay { return Err(sp_blockchain::Error::SetHeadTooOld) } @@ -1316,42 +1315,43 @@ impl Backend { fn force_delayed_canonicalize( &self, transaction: &mut Transaction, - hash: Block::Hash, - number: NumberFor, ) -> ClientResult<()> { - let number_u64 = number.saturated_into::(); - if number_u64 > self.canonicalization_delay { - let new_canonical = number_u64 - self.canonicalization_delay; + let best_canonical = || self.storage.state_db.best_canonical().unwrap_or(0); + let info = self.blockchain.info(); + let best_number: u64 = self.blockchain.info().best_number.saturated_into(); - if new_canonical <= self.storage.state_db.best_canonical().unwrap_or(0) { - return Ok(()) - } - let hash = if new_canonical == number_u64 { - hash - } else { - sc_client_api::blockchain::HeaderBackend::hash( - &self.blockchain, - new_canonical.saturated_into(), - )? - .ok_or_else(|| { - sp_blockchain::Error::Backend(format!( - "Can't canonicalize missing block number #{} when importing {:?} (#{})", - new_canonical, hash, number, - )) - })? - }; - if !sc_client_api::Backend::have_state_at(self, hash, new_canonical.saturated_into()) { + while best_number.saturating_sub(best_canonical()) > self.canonicalization_delay { + let to_canonicalize = best_canonical() + 1; + + let hash_to_canonicalize = sc_client_api::blockchain::HeaderBackend::hash( + &self.blockchain, + to_canonicalize.saturated_into(), + )? + .ok_or_else(|| { + let best_hash = info.best_hash; + + sp_blockchain::Error::Backend(format!( + "Can't canonicalize missing block number #{to_canonicalize} when for best block {best_hash:?} (#{best_number})", + )) + })?; + + if !sc_client_api::Backend::have_state_at( + self, + hash_to_canonicalize, + to_canonicalize.saturated_into(), + ) { return Ok(()) } - trace!(target: "db", "Canonicalize block #{} ({:?})", new_canonical, hash); - let commit = self.storage.state_db.canonicalize_block(&hash).map_err( + trace!(target: "db", "Canonicalize block #{} ({:?})", to_canonicalize, hash_to_canonicalize); + let commit = self.storage.state_db.canonicalize_block(&hash_to_canonicalize).map_err( sp_blockchain::Error::from_state_db::< sc_state_db::Error, >, )?; apply_state_commit(transaction, commit); } + Ok(()) } @@ -1559,7 +1559,7 @@ impl Backend { )?; } else { // canonicalize blocks which are old enough, regardless of finality. - self.force_delayed_canonicalize(&mut transaction, hash, *header.number())? + self.force_delayed_canonicalize(&mut transaction)? } if !existing_header { @@ -2759,6 +2759,33 @@ pub(crate) mod tests { .into(); let hash = header.hash(); + op.set_block_data(header, Some(vec![]), None, None, NewBlockState::Best) + .unwrap(); + + backend.commit_operation(op).unwrap(); + hash + }; + + let hashof4 = { + let mut op = backend.begin_operation().unwrap(); + backend.begin_state_operation(&mut op, hashof3).unwrap(); + let mut header = Header { + number: 4, + parent_hash: hashof3, + state_root: Default::default(), + digest: Default::default(), + extrinsics_root: Default::default(), + }; + + let storage: Vec<(_, _)> = vec![]; + + header.state_root = op + .old_state + .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(); @@ -2774,6 +2801,7 @@ pub(crate) mod tests { backend.finalize_block(hashof1, None).unwrap(); backend.finalize_block(hashof2, None).unwrap(); backend.finalize_block(hashof3, None).unwrap(); + backend.finalize_block(hashof4, None).unwrap(); assert!(backend .storage .db @@ -3801,4 +3829,105 @@ pub(crate) mod tests { assert_eq!(backend.blockchain().leaves().unwrap(), vec![block2]); assert_eq!(backend.blockchain().info().best_hash, block2); } + + #[test] + fn force_delayed_canonicalize_waiting_for_blocks_to_be_finalized() { + let backend = Backend::::new_test(10, 1); + + let genesis = + insert_block(&backend, 0, Default::default(), None, Default::default(), vec![], None) + .unwrap(); + + let block1 = { + let mut op = backend.begin_operation().unwrap(); + backend.begin_state_operation(&mut op, genesis).unwrap(); + let header = Header { + number: 1, + parent_hash: genesis, + 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() + }; + + assert_eq!(0, backend.storage.state_db.best_canonical().unwrap()); + + // This should not trigger any forced canonicalization as we didn't have imported any best + // block by now. + let block2 = { + let mut op = backend.begin_operation().unwrap(); + backend.begin_state_operation(&mut op, block1).unwrap(); + let header = Header { + number: 2, + parent_hash: block1, + 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() + }; + + assert_eq!(0, backend.storage.state_db.best_canonical().unwrap()); + + // This should also not trigger it yet, because we import a best block, but the best block + // from the POV of the db is still at `0`. + let block3 = { + let mut op = backend.begin_operation().unwrap(); + backend.begin_state_operation(&mut op, block2).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::Best) + .unwrap(); + + backend.commit_operation(op).unwrap(); + + header.hash() + }; + + // Now it should kick in. + let block4 = { + let mut op = backend.begin_operation().unwrap(); + backend.begin_state_operation(&mut op, block3).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::Best) + .unwrap(); + + backend.commit_operation(op).unwrap(); + + header.hash() + }; + + assert_eq!(2, backend.storage.state_db.best_canonical().unwrap()); + + assert_eq!(block1, backend.blockchain().hash(1).unwrap().unwrap()); + assert_eq!(block2, backend.blockchain().hash(2).unwrap().unwrap()); + assert_eq!(block3, backend.blockchain().hash(3).unwrap().unwrap()); + assert_eq!(block4, backend.blockchain().hash(4).unwrap().unwrap()); + } } From 0798d52690cad7db103f9d0e1eeb77f2351dfb2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Fri, 16 Dec 2022 19:52:21 +0100 Subject: [PATCH 202/715] Defensive traits: Ensure doc tests are also working without `debug_assertions` (#12952) * Defensive traits: Ensure doc tests are also working without `debug_assertions` Closes: https://github.com/paritytech/substrate/issues/12940 * Only run 'panics' tests if they will panic Signed-off-by: Oliver Tale-Yazdi Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Oliver Tale-Yazdi --- frame/support/src/traits/misc.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/frame/support/src/traits/misc.rs b/frame/support/src/traits/misc.rs index 33e48faa7ef29..734b84ebd9d85 100644 --- a/frame/support/src/traits/misc.rs +++ b/frame/support/src/traits/misc.rs @@ -445,7 +445,7 @@ pub trait DefensiveMin { /// assert_eq!(4, 4_u32.defensive_min(4_u32)); /// ``` /// - /// ```should_panic + /// ```#[cfg_attr(debug_assertions, should_panic)] /// use frame_support::traits::DefensiveMin; /// // min(4, 3) panics. /// 4_u32.defensive_min(3_u32); @@ -462,7 +462,7 @@ pub trait DefensiveMin { /// assert_eq!(3, 3_u32.defensive_strict_min(4_u32)); /// ``` /// - /// ```should_panic + /// ```#[cfg_attr(debug_assertions, should_panic)] /// use frame_support::traits::DefensiveMin; /// // min(4, 4) panics. /// 4_u32.defensive_strict_min(4_u32); @@ -509,7 +509,7 @@ pub trait DefensiveMax { /// assert_eq!(4, 4_u32.defensive_max(4_u32)); /// ``` /// - /// ```should_panic + /// ```#[cfg_attr(debug_assertions, should_panic)] /// use frame_support::traits::DefensiveMax; /// // max(4, 5) panics. /// 4_u32.defensive_max(5_u32); @@ -526,7 +526,7 @@ pub trait DefensiveMax { /// assert_eq!(4, 4_u32.defensive_strict_max(3_u32)); /// ``` /// - /// ```should_panic + /// ```#[cfg_attr(debug_assertions, should_panic)] /// use frame_support::traits::DefensiveMax; /// // max(4, 4) panics. /// 4_u32.defensive_strict_max(4_u32); @@ -1353,6 +1353,7 @@ mod test { } #[test] + #[cfg(debug_assertions)] #[should_panic(expected = "Defensive failure has been triggered!: \"DefensiveMin\"")] fn defensive_min_panics() { 10_u32.defensive_min(9_u32); @@ -1365,6 +1366,7 @@ mod test { } #[test] + #[cfg(debug_assertions)] #[should_panic(expected = "Defensive failure has been triggered!: \"DefensiveMin strict\"")] fn defensive_strict_min_panics() { 9_u32.defensive_strict_min(9_u32); @@ -1377,6 +1379,7 @@ mod test { } #[test] + #[cfg(debug_assertions)] #[should_panic(expected = "Defensive failure has been triggered!: \"DefensiveMax\"")] fn defensive_max_panics() { 9_u32.defensive_max(10_u32); @@ -1389,6 +1392,7 @@ mod test { } #[test] + #[cfg(debug_assertions)] #[should_panic(expected = "Defensive failure has been triggered!: \"DefensiveMax strict\"")] fn defensive_strict_max_panics() { 9_u32.defensive_strict_max(9_u32); From 7f4bca1ee3122335a09c7cb65104deb389c2241e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Sat, 17 Dec 2022 08:25:08 +0100 Subject: [PATCH 203/715] Authority discovery: Log when we found addresses for an authority (#12960) --- client/authority-discovery/src/worker/addr_cache.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/client/authority-discovery/src/worker/addr_cache.rs b/client/authority-discovery/src/worker/addr_cache.rs index 19bbbf0b62e7e..4859413a8cefd 100644 --- a/client/authority-discovery/src/worker/addr_cache.rs +++ b/client/authority-discovery/src/worker/addr_cache.rs @@ -69,6 +69,11 @@ impl AddrCache { ); } + log::debug!( + target: super::LOG_TARGET, + "Found addresses for authority {authority_id:?}: {addresses:?}", + ); + 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()); From a96cb5725407f8cc5ae7c9efc85a80548d071833 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Sat, 17 Dec 2022 10:07:23 +0100 Subject: [PATCH 204/715] `frame_support::storage`: Add `StorageStreamIter` (#12721) * Save * Add some test * Yep * Move to its own file * More work * More * Finish implementation * Start resolving comments and fixing bugs * Fix all review comments * Update frame/support/src/storage/stream_iter.rs Co-authored-by: Koute * Update frame/support/src/storage/stream_iter.rs Co-authored-by: Koute * Review feedback * FMT * Okay, let's initialize the values... * Fix... Co-authored-by: Koute --- frame/support/src/storage/mod.rs | 2 + frame/support/src/storage/stream_iter.rs | 666 +++++++++++++++++++++++ frame/support/src/storage/unhashed.rs | 5 +- frame/system/src/lib.rs | 9 +- 4 files changed, 676 insertions(+), 6 deletions(-) create mode 100644 frame/support/src/storage/stream_iter.rs diff --git a/frame/support/src/storage/mod.rs b/frame/support/src/storage/mod.rs index 333f4382557b1..8c0d6207c3f4d 100644 --- a/frame/support/src/storage/mod.rs +++ b/frame/support/src/storage/mod.rs @@ -30,6 +30,7 @@ use sp_runtime::generic::{Digest, DigestItem}; use sp_std::{collections::btree_set::BTreeSet, marker::PhantomData, prelude::*}; pub use self::{ + stream_iter::StorageStreamIter, transactional::{ in_storage_layer, with_storage_layer, with_transaction, with_transaction_unchecked, }, @@ -47,6 +48,7 @@ pub mod generator; pub mod hashed; pub mod migration; pub mod storage_noop_guard; +mod stream_iter; pub mod transactional; pub mod types; pub mod unhashed; diff --git a/frame/support/src/storage/stream_iter.rs b/frame/support/src/storage/stream_iter.rs new file mode 100644 index 0000000000000..4e25ca6ca1f6c --- /dev/null +++ b/frame/support/src/storage/stream_iter.rs @@ -0,0 +1,666 @@ +// 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::{BoundedBTreeMap, BoundedBTreeSet, BoundedVec, WeakBoundedVec}; +use codec::Decode; +use sp_std::vec::Vec; + +/// Provides the sealed trait `StreamIter`. +mod private { + use super::*; + + /// Used as marker trait for types that support stream iteration. + pub trait StreamIter { + /// The actual iterator implementation. + type Iterator: sp_std::iter::Iterator; + + /// Create the stream iterator for the value found at `key`. + fn stream_iter(key: Vec) -> Self::Iterator; + } + + impl StreamIter for Vec { + type Iterator = ScaleContainerStreamIter; + + fn stream_iter(key: Vec) -> Self::Iterator { + ScaleContainerStreamIter::new(key) + } + } + + impl StreamIter for sp_std::collections::btree_set::BTreeSet { + type Iterator = ScaleContainerStreamIter; + + fn stream_iter(key: Vec) -> Self::Iterator { + ScaleContainerStreamIter::new(key) + } + } + + impl StreamIter + for sp_std::collections::btree_map::BTreeMap + { + type Iterator = ScaleContainerStreamIter<(K, V)>; + + fn stream_iter(key: Vec) -> Self::Iterator { + ScaleContainerStreamIter::new(key) + } + } + + impl StreamIter for BoundedVec { + type Iterator = ScaleContainerStreamIter; + + fn stream_iter(key: Vec) -> Self::Iterator { + ScaleContainerStreamIter::new(key) + } + } + + impl StreamIter for WeakBoundedVec { + type Iterator = ScaleContainerStreamIter; + + fn stream_iter(key: Vec) -> Self::Iterator { + ScaleContainerStreamIter::new(key) + } + } + + impl StreamIter for BoundedBTreeMap { + type Iterator = ScaleContainerStreamIter<(K, V)>; + + fn stream_iter(key: Vec) -> Self::Iterator { + ScaleContainerStreamIter::new(key) + } + } + + impl StreamIter for BoundedBTreeSet { + type Iterator = ScaleContainerStreamIter; + + fn stream_iter(key: Vec) -> Self::Iterator { + ScaleContainerStreamIter::new(key) + } + } +} + +/// An iterator that streams values directly from storage. +/// +/// Requires that `T` implements the sealed trait `StreamIter`. +/// +/// Instead of loading the entire `T` into memory, the iterator only loads a certain number of bytes +/// into memory to decode the next `T::Item`. The iterator implementation is allowed to have some +/// internal buffer to reduce the number of storage reads. The iterator should have an almost +/// constant memory usage over its lifetime. If at some point there is a decoding error, the +/// iterator will return `None` to signal that the iterator is finished. +pub trait StorageStreamIter { + /// Create the streaming iterator. + fn stream_iter() -> T::Iterator; +} + +impl> + StorageStreamIter for StorageValue +{ + fn stream_iter() -> T::Iterator { + T::stream_iter(Self::hashed_key().into()) + } +} + +/// A streaming iterator implementation for SCALE container types. +/// +/// SCALE container types follow the same type of encoding `Compact(len) ++ data`. +/// This type provides an [`Iterator`](sp_std::iter::Iterator) implementation that decodes +/// one item after another with each call to [`next`](Self::next). The bytes representing +/// the container are also not read at once into memory and instead being read in chunks. As long +/// as individual items are smaller than these chunks the memory usage of this iterator should +/// be constant. On decoding errors [`next`](Self::next) will return `None` to signal that the +/// iterator is finished. +pub struct ScaleContainerStreamIter { + marker: sp_std::marker::PhantomData, + input: StorageInput, + length: u32, + read: u32, +} + +impl ScaleContainerStreamIter { + /// Creates a new instance of the stream iterator. + /// + /// - `key`: Storage key of the container in the state. + /// + /// Same as [`Self::try_new`], but logs a potential error and sets the length to `0`. + pub fn new(key: Vec) -> Self { + let mut input = StorageInput::new(key); + let length = if input.exists() { + match codec::Compact::::decode(&mut input) { + Ok(length) => length.0, + Err(e) => { + // TODO #3700: error should be handleable. + log::error!( + target: "runtime::storage", + "Corrupted state at `{:?}`: failed to decode element count: {:?}", + input.key, + e, + ); + + 0 + }, + } + } else { + 0 + }; + + Self { marker: sp_std::marker::PhantomData, input, length, read: 0 } + } + + /// Creates a new instance of the stream iterator. + /// + /// - `key`: Storage key of the container in the state. + /// + /// Returns an error if the length of the container fails to decode. + pub fn new_try(key: Vec) -> Result { + let mut input = StorageInput::new(key); + let length = if input.exists() { codec::Compact::::decode(&mut input)?.0 } else { 0 }; + + Ok(Self { marker: sp_std::marker::PhantomData, input, length, read: 0 }) + } +} + +impl sp_std::iter::Iterator for ScaleContainerStreamIter { + type Item = T; + + fn next(&mut self) -> Option { + if self.read >= self.length { + return None + } + + match codec::Decode::decode(&mut self.input) { + Ok(r) => { + self.read += 1; + Some(r) + }, + Err(e) => { + log::error!( + target: "runtime::storage", + "Corrupted state at `{:?}`: failed to decode element {} (out of {} in total): {:?}", + self.input.key, + self.read, + self.length, + e, + ); + + self.read = self.length; + None + }, + } + } + + fn size_hint(&self) -> (usize, Option) { + let left = (self.length - self.read) as usize; + + (left, Some(left)) + } +} + +/// The size of the internal buffer used by [`StorageInput`]. +/// +/// This internal buffer is used to speed up implementation as reading from the +/// state for every access is too slow. +const STORAGE_INPUT_BUFFER_CAPACITY: usize = 2 * 1024; + +/// Implementation of [`codec::Input`] using [`sp_io::storage::read`]. +/// +/// Keeps an internal buffer with a size of [`STORAGE_INPUT_BUFFER_CAPACITY`]. All read accesses +/// are tried to be served by this buffer. If the buffer doesn't hold enough bytes to fullfill the +/// current read access, the buffer is re-filled from the state. A read request that is bigger than +/// the internal buffer is directly forwarded to the state to reduce the number of reads from the +/// state. +struct StorageInput { + key: Vec, + offset: u32, + total_length: u32, + exists: bool, + buffer: Vec, + buffer_pos: usize, +} + +impl StorageInput { + /// Create a new instance of the input. + /// + /// - `key`: The storage key of the storage item that this input will read. + fn new(key: Vec) -> Self { + let mut buffer = sp_std::vec![0; STORAGE_INPUT_BUFFER_CAPACITY]; + unsafe { + buffer.set_len(buffer.capacity()); + } + + let (total_length, exists) = + if let Some(total_length) = sp_io::storage::read(&key, &mut buffer, 0) { + (total_length, true) + } else { + (0, false) + }; + + if (total_length as usize) < buffer.len() { + unsafe { + buffer.set_len(total_length as usize); + } + } + + Self { total_length, offset: buffer.len() as u32, key, exists, buffer, buffer_pos: 0 } + } + + /// Fill the internal buffer from the state. + fn fill_buffer(&mut self) -> Result<(), codec::Error> { + self.buffer.copy_within(self.buffer_pos.., 0); + let present_bytes = self.buffer.len() - self.buffer_pos; + self.buffer_pos = 0; + + unsafe { + self.buffer.set_len(self.buffer.capacity()); + } + + if let Some(length_minus_offset) = + sp_io::storage::read(&self.key, &mut self.buffer[present_bytes..], self.offset) + { + let bytes_read = + sp_std::cmp::min(length_minus_offset as usize, self.buffer.len() - present_bytes); + let buffer_len = present_bytes + bytes_read; + unsafe { + self.buffer.set_len(buffer_len); + } + + self.ensure_total_length_did_not_change(length_minus_offset)?; + + self.offset += bytes_read as u32; + + Ok(()) + } else { + // The value was deleted, let's ensure we don't read anymore. + self.stop_reading(); + + Err("Value doesn't exist in the state?".into()) + } + } + + /// Returns if the value to read exists in the state. + fn exists(&self) -> bool { + self.exists + } + + /// Reads directly into the given slice `into`. + /// + /// Should be used when `into.len() > self.buffer.capacity()` to reduce the number of reads from + /// the state. + #[inline(never)] + fn read_big_item(&mut self, into: &mut [u8]) -> Result<(), codec::Error> { + let num_cached = self.buffer.len() - self.buffer_pos; + + let (out_already_read, mut out_remaining) = into.split_at_mut(num_cached); + out_already_read.copy_from_slice(&self.buffer[self.buffer_pos..]); + + self.buffer_pos = 0; + unsafe { + self.buffer.set_len(0); + } + + if let Some(length_minus_offset) = + sp_io::storage::read(&self.key, &mut out_remaining, self.offset) + { + if (length_minus_offset as usize) < out_remaining.len() { + return Err("Not enough data to fill the buffer".into()) + } + + self.ensure_total_length_did_not_change(length_minus_offset)?; + + self.offset += out_remaining.len() as u32; + + Ok(()) + } else { + // The value was deleted, let's ensure we don't read anymore. + self.stop_reading(); + + Err("Value doesn't exist in the state?".into()) + } + } + + /// Ensures that the expected total length of the value did not change. + /// + /// On error ensures that further reading is prohibited. + fn ensure_total_length_did_not_change( + &mut self, + length_minus_offset: u32, + ) -> Result<(), codec::Error> { + if self.total_length == self.offset + length_minus_offset { + Ok(()) + } else { + // The value total length changed, let's ensure we don't read anymore. + self.stop_reading(); + + Err("Storage value changed while it is being read!".into()) + } + } + + /// Ensure that we are stop reading from this value in the state. + /// + /// Should be used when there happened an unrecoverable error while reading. + fn stop_reading(&mut self) { + self.offset = self.total_length; + + self.buffer_pos = 0; + unsafe { + self.buffer.set_len(0); + } + } +} + +impl codec::Input for StorageInput { + fn remaining_len(&mut self) -> Result, codec::Error> { + Ok(Some(self.total_length.saturating_sub( + self.offset.saturating_sub((self.buffer.len() - self.buffer_pos) as u32), + ) as usize)) + } + + fn read(&mut self, into: &mut [u8]) -> Result<(), codec::Error> { + // If there is still data left to be read from the state. + if self.offset < self.total_length { + if into.len() > self.buffer.capacity() { + return self.read_big_item(into) + } else if self.buffer_pos + into.len() > self.buffer.len() { + self.fill_buffer()?; + } + } + + // Guard against `fill_buffer` not reading enough data or just not having enough data + // anymore. + if into.len() + self.buffer_pos > self.buffer.len() { + return Err("Not enough data to fill the buffer".into()) + } + + let end = self.buffer_pos + into.len(); + into.copy_from_slice(&self.buffer[self.buffer_pos..end]); + self.buffer_pos = end; + + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use codec::{Compact, CompactLen, Encode, Input}; + + #[crate::storage_alias] + pub type TestVecU32 = StorageValue>; + + #[crate::storage_alias] + pub type TestVecVecU8 = StorageValue>>; + + #[test] + fn remaining_len_works() { + sp_io::TestExternalities::default().execute_with(|| { + let data: Vec = vec![1, 2, 3, 4, 5]; + TestVecU32::put(&data); + + let mut input = StorageInput::new(TestVecU32::hashed_key().into()); + assert_eq!( + 5 * std::mem::size_of::() + Compact::::compact_len(&5) as usize, + input.remaining_len().ok().flatten().unwrap() + ); + + assert_eq!(5, Compact::::decode(&mut input).unwrap().0); + assert_eq!( + 5 * std::mem::size_of::(), + input.remaining_len().ok().flatten().unwrap() + ); + + for i in &data { + assert_eq!(*i, u32::decode(&mut input).unwrap()); + assert_eq!( + (5 - *i as usize) * std::mem::size_of::(), + input.remaining_len().ok().flatten().unwrap() + ); + } + + let data: Vec> = vec![ + vec![0; 20], + vec![1; STORAGE_INPUT_BUFFER_CAPACITY * 2], + vec![2; STORAGE_INPUT_BUFFER_CAPACITY * 2], + vec![3; 30], + vec![4; 30], + vec![5; STORAGE_INPUT_BUFFER_CAPACITY * 2], + vec![6; 30], + ]; + TestVecVecU8::put(&data); + + let mut input = StorageInput::new(TestVecVecU8::hashed_key().into()); + let total_data_len = data + .iter() + .map(|v| v.len() + Compact::::compact_len(&(v.len() as u32)) as usize) + .sum::(); + assert_eq!( + total_data_len + Compact::::compact_len(&(data.len() as u32)) as usize, + input.remaining_len().ok().flatten().unwrap() + ); + + assert_eq!(data.len(), Compact::::decode(&mut input).unwrap().0 as usize); + assert_eq!(total_data_len, input.remaining_len().ok().flatten().unwrap()); + + let mut remaining_len = total_data_len; + for i in data { + assert_eq!(i, Vec::::decode(&mut input).unwrap()); + + remaining_len -= i.len() + Compact::::compact_len(&(i.len() as u32)) as usize; + + assert_eq!(remaining_len, input.remaining_len().ok().flatten().unwrap()); + } + }) + } + + #[test] + fn detects_value_total_length_change() { + sp_io::TestExternalities::default().execute_with(|| { + let test_data: Vec>> = vec![ + vec![vec![0; 20], vec![1; STORAGE_INPUT_BUFFER_CAPACITY * 2]], + vec![ + vec![0; STORAGE_INPUT_BUFFER_CAPACITY - 1], + vec![1; STORAGE_INPUT_BUFFER_CAPACITY - 1], + ], + ]; + + for data in test_data { + TestVecVecU8::put(&data); + + let mut input = StorageInput::new(TestVecVecU8::hashed_key().into()); + + Compact::::decode(&mut input).unwrap(); + Vec::::decode(&mut input).unwrap(); + + TestVecVecU8::append(vec![1, 2, 3]); + + assert!(Vec::::decode(&mut input) + .unwrap_err() + .to_string() + .contains("Storage value changed while it is being read")); + + // Reading a second time should now prevent reading at all. + assert!(Vec::::decode(&mut input) + .unwrap_err() + .to_string() + .contains("Not enough data to fill the buffer")); + } + }) + } + + #[test] + fn stream_read_test() { + sp_io::TestExternalities::default().execute_with(|| { + let data: Vec = vec![1, 2, 3, 4, 5]; + TestVecU32::put(&data); + + assert_eq!(data, TestVecU32::stream_iter().collect::>()); + + let data: Vec> = vec![vec![0; 3000], vec![1; 2500]]; + TestVecVecU8::put(&data); + + assert_eq!(data, TestVecVecU8::stream_iter().collect::>()); + }) + } + + #[test] + fn reading_big_intermediate_value() { + sp_io::TestExternalities::default().execute_with(|| { + let data: Vec> = + vec![vec![0; 20], vec![1; STORAGE_INPUT_BUFFER_CAPACITY * 2], vec![2; 30]]; + TestVecVecU8::put(&data); + + assert_eq!(data, TestVecVecU8::stream_iter().collect::>()); + + let data: Vec> = vec![ + vec![0; 20], + vec![1; STORAGE_INPUT_BUFFER_CAPACITY * 2], + vec![2; STORAGE_INPUT_BUFFER_CAPACITY * 2], + vec![3; 30], + vec![4; 30], + vec![5; STORAGE_INPUT_BUFFER_CAPACITY * 2], + vec![6; 30], + ]; + TestVecVecU8::put(&data); + + assert_eq!(data, TestVecVecU8::stream_iter().collect::>()); + }) + } + + #[test] + fn reading_more_data_as_in_the_state_is_detected() { + sp_io::TestExternalities::default().execute_with(|| { + let data: Vec> = vec![vec![0; 20], vec![1; STORAGE_INPUT_BUFFER_CAPACITY * 2]]; + TestVecVecU8::put(&data); + + let mut input = StorageInput::new(TestVecVecU8::hashed_key().into()); + + Compact::::decode(&mut input).unwrap(); + + Vec::::decode(&mut input).unwrap(); + + let mut buffer = vec![0; STORAGE_INPUT_BUFFER_CAPACITY * 4]; + assert!(input + .read(&mut buffer) + .unwrap_err() + .to_string() + .contains("Not enough data to fill the buffer")); + }) + } + + #[test] + fn reading_invalid_data_from_state() { + sp_io::TestExternalities::default().execute_with(|| { + let data: Vec = vec![1, 2, 3, 4, 5]; + + let mut data_encoded = data.encode(); + data_encoded.truncate(data_encoded.len() - 2); + sp_io::storage::set(&TestVecU32::hashed_key(), &data_encoded); + assert_eq!( + data.iter().copied().take(data.len() - 1).collect::>(), + TestVecU32::stream_iter().collect::>() + ); + + let data_encoded = data.encode()[2..].to_vec(); + sp_io::storage::set(&TestVecU32::hashed_key(), &data_encoded); + assert!(TestVecU32::stream_iter().collect::>().is_empty()); + + let data: Vec> = vec![vec![0; 20], vec![1; STORAGE_INPUT_BUFFER_CAPACITY * 2]]; + let mut data_encoded = data.encode(); + data_encoded.truncate(data_encoded.len() - 100); + sp_io::storage::set(&TestVecVecU8::hashed_key(), &data_encoded); + + assert_eq!( + data.iter().cloned().take(1).collect::>(), + TestVecVecU8::stream_iter().collect::>() + ); + }) + } + + #[test] + fn reading_with_fill_buffer() { + sp_io::TestExternalities::default().execute_with(|| { + const BUFFER_SIZE: usize = 300; + // Ensure that the capacity isn't dividable by `300`. + assert!(STORAGE_INPUT_BUFFER_CAPACITY % BUFFER_SIZE != 0, "Please update buffer size"); + // Create some items where the last item is partially in the inner buffer so that + // we need to fill the buffer to read the entire item. + let data: Vec> = (0..=(STORAGE_INPUT_BUFFER_CAPACITY / BUFFER_SIZE)) + .into_iter() + .map(|i| vec![i as u8; BUFFER_SIZE]) + .collect::>>(); + TestVecVecU8::put(&data); + + assert_eq!(data, TestVecVecU8::stream_iter().collect::>()); + + let mut input = StorageInput::new(TestVecVecU8::hashed_key().into()); + + Compact::::decode(&mut input).unwrap(); + + (0..data.len() - 1).into_iter().for_each(|_| { + Vec::::decode(&mut input).unwrap(); + }); + + // Try reading a more data than there should be left. + let mut result_buffer = vec![0; BUFFER_SIZE * 2]; + assert!(input + .read(&mut result_buffer) + .unwrap_err() + .to_string() + .contains("Not enough data to fill the buffer")); + }) + } + + #[test] + fn detect_value_deleted_in_state() { + sp_io::TestExternalities::default().execute_with(|| { + let data: Vec> = vec![vec![0; 20], vec![1; STORAGE_INPUT_BUFFER_CAPACITY * 2]]; + TestVecVecU8::put(&data); + + let mut input = StorageInput::new(TestVecVecU8::hashed_key().into()); + TestVecVecU8::kill(); + + Compact::::decode(&mut input).unwrap(); + Vec::::decode(&mut input).unwrap(); + + assert!(Vec::::decode(&mut input) + .unwrap_err() + .to_string() + .contains("Value doesn't exist in the state?")); + + const BUFFER_SIZE: usize = 300; + // Ensure that the capacity isn't dividable by `300`. + assert!(STORAGE_INPUT_BUFFER_CAPACITY % BUFFER_SIZE != 0, "Please update buffer size"); + // Create some items where the last item is partially in the inner buffer so that + // we need to fill the buffer to read the entire item. + let data: Vec> = (0..=(STORAGE_INPUT_BUFFER_CAPACITY / BUFFER_SIZE)) + .into_iter() + .map(|i| vec![i as u8; BUFFER_SIZE]) + .collect::>>(); + TestVecVecU8::put(&data); + + let mut input = StorageInput::new(TestVecVecU8::hashed_key().into()); + TestVecVecU8::kill(); + + Compact::::decode(&mut input).unwrap(); + (0..data.len() - 1).into_iter().for_each(|_| { + Vec::::decode(&mut input).unwrap(); + }); + + assert!(Vec::::decode(&mut input) + .unwrap_err() + .to_string() + .contains("Value doesn't exist in the state?")); + }) + } +} diff --git a/frame/support/src/storage/unhashed.rs b/frame/support/src/storage/unhashed.rs index 089230bc9bfdf..850e93e7d7fe4 100644 --- a/frame/support/src/storage/unhashed.rs +++ b/frame/support/src/storage/unhashed.rs @@ -23,12 +23,13 @@ use sp_std::prelude::*; /// Return the value of the item in storage under `key`, or `None` if there is no explicit entry. pub fn get(key: &[u8]) -> Option { sp_io::storage::get(key).and_then(|val| { - Decode::decode(&mut &val[..]).map(Some).unwrap_or_else(|_| { + Decode::decode(&mut &val[..]).map(Some).unwrap_or_else(|e| { // TODO #3700: error should be handleable. log::error!( target: "runtime::storage", - "Corrupted state at {:?}", + "Corrupted state at `{:?}: {:?}`", key, + e, ); None }) diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index b41083538a325..a77d1ca31b50f 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -88,7 +88,7 @@ use frame_support::{ extract_actual_pays_fee, extract_actual_weight, DispatchClass, DispatchInfo, DispatchResult, DispatchResultWithPostInfo, PerDispatchClass, }, - storage, + storage::{self, StorageStreamIter}, traits::{ ConstU32, Contains, EnsureOrigin, Get, HandleLifetime, OnKilledAccount, OnNewAccount, OriginTrait, PalletInfo, SortedMembers, StoredMap, TypedGet, @@ -1444,15 +1444,16 @@ impl Pallet { 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() + Self::read_events_no_consensus().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>> { - Events::::get() + pub fn read_events_no_consensus( + ) -> impl sp_std::iter::Iterator>> { + Events::::stream_iter() } /// Set the block number to something in particular. Can be used as an alternative to From 8d11cec9713a93b9f6bee1b29fde840da5ba56e0 Mon Sep 17 00:00:00 2001 From: Qinxuan Chen Date: Mon, 19 Dec 2022 14:38:51 +0800 Subject: [PATCH 205/715] *: update `rand` to v0.8.5 (#12962) * *: update rand to v0.8.5 * *: remove useless deps from Cargo.toml * fix pallet-session-benchmarking * fix pallet-election-provider-support test * remove useless rand from dev-dependencies --- Cargo.lock | 167 ++++-------------- bin/node/bench/Cargo.toml | 2 +- client/api/Cargo.toml | 2 - client/authority-discovery/Cargo.toml | 2 +- client/beefy/Cargo.toml | 3 - client/beefy/rpc/Cargo.toml | 1 - client/chain-spec/Cargo.toml | 2 - client/cli/Cargo.toml | 4 +- client/consensus/babe/Cargo.toml | 3 - client/consensus/slots/Cargo.toml | 1 - client/db/Cargo.toml | 2 +- client/finality-grandpa/Cargo.toml | 3 +- client/finality-grandpa/rpc/Cargo.toml | 1 - client/informant/Cargo.toml | 1 - client/merkle-mountain-range/Cargo.toml | 1 - client/network/Cargo.toml | 9 +- client/network/bitswap/Cargo.toml | 1 - client/network/test/Cargo.toml | 2 +- client/network/transactions/Cargo.toml | 1 - client/offchain/Cargo.toml | 2 +- client/peerset/Cargo.toml | 2 +- client/rpc-api/Cargo.toml | 4 - client/rpc-servers/Cargo.toml | 1 - client/rpc/Cargo.toml | 5 +- client/service/Cargo.toml | 7 +- client/service/test/Cargo.toml | 2 - client/state-db/Cargo.toml | 1 - client/sysinfo/Cargo.toml | 4 +- client/telemetry/Cargo.toml | 2 +- client/telemetry/src/node.rs | 2 +- .../election-provider-multi-phase/Cargo.toml | 5 +- frame/election-provider-support/Cargo.toml | 2 +- frame/election-provider-support/src/mock.rs | 6 +- frame/election-provider-support/src/tests.rs | 2 +- frame/session/benchmarking/Cargo.toml | 2 +- primitives/arithmetic/Cargo.toml | 4 +- primitives/arithmetic/benches/bench.rs | 4 +- primitives/consensus/common/Cargo.toml | 1 - primitives/consensus/slots/Cargo.toml | 4 - primitives/core/Cargo.toml | 12 +- primitives/io/Cargo.toml | 6 - primitives/npos-elections/Cargo.toml | 2 +- primitives/runtime/Cargo.toml | 4 +- primitives/state-machine/Cargo.toml | 8 +- primitives/state-machine/src/lib.rs | 2 +- primitives/timestamp/Cargo.toml | 2 - primitives/weights/Cargo.toml | 1 - utils/frame/benchmarking-cli/Cargo.toml | 5 - utils/frame/generate-bags/Cargo.toml | 3 - utils/frame/remote-externalities/Cargo.toml | 3 - .../rpc/state-trie-migration-rpc/Cargo.toml | 2 - utils/frame/rpc/support/Cargo.toml | 1 - utils/frame/rpc/system/Cargo.toml | 2 - utils/frame/try-runtime/cli/Cargo.toml | 1 - utils/prometheus/Cargo.toml | 1 - 55 files changed, 74 insertions(+), 251 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b840cadce3e5c..c62d71348fb1d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -376,15 +376,12 @@ dependencies = [ "async-trait", "fnv", "futures", - "futures-timer", "log", "parity-scale-codec", "parking_lot 0.12.1", "sc-block-builder", - "sc-chain-spec", "sc-client-api", "sc-consensus", - "sc-finality-grandpa", "sc-keystore", "sc-network", "sc-network-common", @@ -425,7 +422,6 @@ dependencies = [ "parity-scale-codec", "parking_lot 0.12.1", "sc-rpc", - "sc-utils", "serde", "serde_json", "sp-beefy", @@ -1904,16 +1900,13 @@ dependencies = [ "frame-system", "gethostname", "handlebars", - "hash-db", "itertools", - "kvdb", "lazy_static", "linked-hash-map", "log", - "memory-db", "parity-scale-codec", "rand 0.8.5", - "rand_pcg 0.3.1", + "rand_pcg", "sc-block-builder", "sc-cli", "sc-client-api", @@ -1923,7 +1916,6 @@ dependencies = [ "sc-sysinfo", "serde", "serde_json", - "serde_nanos", "sp-api", "sp-blockchain", "sp-core", @@ -1936,7 +1928,6 @@ dependencies = [ "sp-std", "sp-storage", "sp-trie", - "tempfile", "thiserror", "thousands", ] @@ -1965,7 +1956,7 @@ dependencies = [ "frame-support", "frame-system", "parity-scale-codec", - "rand 0.7.3", + "rand 0.8.5", "scale-info", "sp-arithmetic", "sp-core", @@ -2029,18 +2020,15 @@ dependencies = [ name = "frame-remote-externalities" version = "0.10.0-dev" dependencies = [ - "env_logger", "frame-support", "futures", "log", "pallet-elections-phragmen", "parity-scale-codec", "serde", - "serde_json", "sp-core", "sp-io", "sp-runtime", - "sp-version", "substrate-rpc-client", "tokio", "tracing-subscriber 0.3.16", @@ -2383,7 +2371,6 @@ dependencies = [ "git2", "num-format", "pallet-staking", - "sp-io", ] [[package]] @@ -2422,10 +2409,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" dependencies = [ "cfg-if", - "js-sys", "libc", "wasi 0.9.0+wasi-snapshot-preview1", - "wasm-bindgen", ] [[package]] @@ -3919,7 +3904,6 @@ dependencies = [ "sp-blockchain", "sp-consensus", "sp-core", - "sp-io", "sp-mmr-primitives", "sp-runtime", "sp-tracing", @@ -4196,7 +4180,7 @@ dependencies = [ "node-primitives", "node-testing", "parity-db", - "rand 0.7.3", + "rand 0.8.5", "sc-basic-authorship", "sc-client-api", "sc-transaction-pool", @@ -5029,7 +5013,7 @@ dependencies = [ "parity-scale-codec", "pretty_assertions", "rand 0.8.5", - "rand_pcg 0.3.1", + "rand_pcg", "scale-info", "serde", "smallvec", @@ -5117,7 +5101,7 @@ dependencies = [ "pallet-election-provider-support-benchmarking", "parity-scale-codec", "parking_lot 0.12.1", - "rand 0.7.3", + "rand 0.8.5", "scale-info", "sp-arithmetic", "sp-core", @@ -5126,7 +5110,6 @@ dependencies = [ "sp-runtime", "sp-std", "sp-tracing", - "static_assertions", "strum", ] @@ -5799,7 +5782,7 @@ dependencies = [ "pallet-staking-reward-curve", "pallet-timestamp", "parity-scale-codec", - "rand 0.7.3", + "rand 0.8.5", "scale-info", "sp-core", "sp-io", @@ -6238,20 +6221,20 @@ checksum = "b1de2e551fb905ac83f73f7aedf2f0cb4a0da7e35efa24a202a936269f1f18e1" [[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]] name = "pbkdf2" -version = "0.8.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d95f5254224e617595d2cc3cc73ff0a5eaf2637519e25f03388154e9378b6ffa" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" dependencies = [ - "crypto-mac 0.11.1", + "digest 0.10.3", ] [[package]] @@ -6713,7 +6696,6 @@ dependencies = [ "rand_chacha 0.2.2", "rand_core 0.5.1", "rand_hc", - "rand_pcg 0.2.1", ] [[package]] @@ -6723,7 +6705,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha 0.3.0", + "rand_chacha 0.3.1", "rand_core 0.6.2", ] @@ -6739,9 +6721,9 @@ dependencies = [ [[package]] name = "rand_chacha" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", "rand_core 0.6.2", @@ -6784,15 +6766,6 @@ dependencies = [ "rand_core 0.5.1", ] -[[package]] -name = "rand_pcg" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" -dependencies = [ - "rand_core 0.5.1", -] - [[package]] name = "rand_pcg" version = "0.3.1" @@ -7150,7 +7123,7 @@ dependencies = [ "prost", "prost-build", "quickcheck", - "rand 0.7.3", + "rand 0.8.5", "sc-client-api", "sc-network-common", "sp-api", @@ -7210,9 +7183,7 @@ dependencies = [ name = "sc-chain-spec" version = "4.0.0-dev" dependencies = [ - "impl-trait-for-tuples", "memmap2", - "parity-scale-codec", "sc-chain-spec-derive", "sc-network-common", "sc-telemetry", @@ -7246,7 +7217,7 @@ dependencies = [ "log", "names", "parity-scale-codec", - "rand 0.7.3", + "rand 0.8.5", "regex", "rpassword", "sc-client-api", @@ -7279,7 +7250,6 @@ version = "4.0.0-dev" dependencies = [ "fnv", "futures", - "hash-db", "log", "parity-scale-codec", "parking_lot 0.12.1", @@ -7297,7 +7267,6 @@ dependencies = [ "sp-state-machine", "sp-storage", "sp-test-primitives", - "sp-trie", "substrate-prometheus-endpoint", "substrate-test-runtime", "thiserror", @@ -7422,7 +7391,6 @@ dependencies = [ "sc-network-test", "sc-telemetry", "schnorrkel", - "serde", "sp-api", "sp-application-crypto", "sp-block-builder", @@ -7433,13 +7401,11 @@ dependencies = [ "sp-consensus-vrf", "sp-core", "sp-inherents", - "sp-io", "sp-keyring", "sp-keystore", "sp-runtime", "sp-timestamp", "sp-tracing", - "sp-version", "substrate-prometheus-endpoint", "substrate-test-runtime-client", "thiserror", @@ -7568,7 +7534,6 @@ dependencies = [ "sp-runtime", "sp-state-machine", "substrate-test-runtime-client", - "thiserror", ] [[package]] @@ -7686,7 +7651,6 @@ dependencies = [ "sc-chain-spec", "sc-client-api", "sc-consensus", - "sc-keystore", "sc-network", "sc-network-common", "sc-network-gossip", @@ -7726,7 +7690,6 @@ dependencies = [ "sc-finality-grandpa", "sc-rpc", "serde", - "serde_json", "sp-blockchain", "sp-core", "sp-finality-grandpa", @@ -7747,7 +7710,6 @@ dependencies = [ "log", "sc-client-api", "sc-network-common", - "sc-transaction-pool-api", "sp-blockchain", "sp-runtime", ] @@ -7775,25 +7737,19 @@ dependencies = [ "assert_matches", "async-trait", "asynchronous-codec", - "bitflags", "bytes", - "cid", "either", "fnv", - "fork-tree", "futures", "futures-timer", "ip_network", "libp2p", - "linked-hash-map", - "linked_hash_set", "log", "lru", "parity-scale-codec", "parking_lot 0.12.1", "pin-project", - "prost", - "rand 0.7.3", + "rand 0.8.5", "sc-block-builder", "sc-client-api", "sc-consensus", @@ -7846,7 +7802,6 @@ dependencies = [ "thiserror", "tokio", "unsigned-varint", - "void", ] [[package]] @@ -7961,7 +7916,7 @@ dependencies = [ "libp2p", "log", "parking_lot 0.12.1", - "rand 0.7.3", + "rand 0.8.5", "sc-block-builder", "sc-client-api", "sc-consensus", @@ -7987,7 +7942,6 @@ version = "0.10.0-dev" dependencies = [ "array-bytes", "futures", - "hex", "libp2p", "log", "parity-scale-codec", @@ -8016,7 +7970,7 @@ dependencies = [ "once_cell", "parity-scale-codec", "parking_lot 0.12.1", - "rand 0.7.3", + "rand 0.8.5", "sc-block-builder", "sc-client-api", "sc-client-db", @@ -8044,7 +7998,7 @@ dependencies = [ "futures", "libp2p", "log", - "rand 0.7.3", + "rand 0.8.5", "sc-utils", "serde_json", "wasm-timer", @@ -8065,9 +8019,7 @@ dependencies = [ "assert_matches", "env_logger", "futures", - "hash-db", "jsonrpsee", - "lazy_static", "log", "parity-scale-codec", "parking_lot 0.12.1", @@ -8101,11 +8053,8 @@ dependencies = [ name = "sc-rpc-api" version = "0.10.0-dev" dependencies = [ - "futures", "jsonrpsee", - "log", "parity-scale-codec", - "parking_lot 0.12.1", "sc-chain-spec", "sc-transaction-pool-api", "scale-info", @@ -8114,7 +8063,6 @@ dependencies = [ "sp-core", "sp-rpc", "sp-runtime", - "sp-tracing", "sp-version", "thiserror", ] @@ -8123,7 +8071,6 @@ dependencies = [ name = "sc-rpc-server" version = "4.0.0-dev" dependencies = [ - "futures", "http", "jsonrpsee", "log", @@ -8174,13 +8121,12 @@ dependencies = [ "exit-future", "futures", "futures-timer", - "hash-db", "jsonrpsee", "log", "parity-scale-codec", "parking_lot 0.12.1", "pin-project", - "rand 0.7.3", + "rand 0.8.5", "sc-block-builder", "sc-chain-spec", "sc-client-api", @@ -8208,19 +8154,15 @@ dependencies = [ "serde", "serde_json", "sp-api", - "sp-application-crypto", - "sp-block-builder", "sp-blockchain", "sp-consensus", "sp-core", "sp-externalities", - "sp-inherents", "sp-keystore", "sp-runtime", "sp-session", "sp-state-machine", "sp-storage", - "sp-tracing", "sp-transaction-pool", "sp-transaction-storage-proof", "sp-trie", @@ -8259,9 +8201,7 @@ dependencies = [ "sp-blockchain", "sp-consensus", "sp-core", - "sp-externalities", "sp-io", - "sp-panic-handler", "sp-runtime", "sp-state-machine", "sp-storage", @@ -8280,7 +8220,6 @@ dependencies = [ "log", "parity-scale-codec", "parking_lot 0.12.1", - "sc-client-api", "sp-core", ] @@ -8309,8 +8248,8 @@ dependencies = [ "futures", "libc", "log", - "rand 0.7.3", - "rand_pcg 0.2.1", + "rand 0.8.5", + "rand_pcg", "regex", "sc-telemetry", "serde", @@ -8331,7 +8270,7 @@ dependencies = [ "log", "parking_lot 0.12.1", "pin-project", - "rand 0.7.3", + "rand 0.8.5", "serde", "serde_json", "thiserror", @@ -8653,15 +8592,6 @@ 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.9.4" @@ -8929,11 +8859,10 @@ dependencies = [ "num-traits", "parity-scale-codec", "primitive-types", - "rand 0.7.3", + "rand 0.8.5", "scale-info", "serde", "sp-core", - "sp-debug-derive", "sp-std", "static_assertions", ] @@ -9023,7 +8952,6 @@ version = "0.10.0-dev" dependencies = [ "async-trait", "futures", - "futures-timer", "log", "parity-scale-codec", "sp-core", @@ -9093,8 +9021,6 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", - "sp-arithmetic", - "sp-runtime", "sp-std", "sp-timestamp", ] @@ -9119,7 +9045,6 @@ dependencies = [ "base58", "bitflags", "blake2", - "byteorder", "criterion", "dyn-clonable", "ed25519-zebra", @@ -9131,11 +9056,10 @@ dependencies = [ "libsecp256k1", "log", "merlin", - "num-traits", "parity-scale-codec", "parking_lot 0.12.1", "primitive-types", - "rand 0.7.3", + "rand 0.8.5", "regex", "scale-info", "schnorrkel", @@ -9155,7 +9079,6 @@ dependencies = [ "substrate-bip39", "thiserror", "tiny-bip39", - "wasmi 0.13.0", "zeroize", ] @@ -9247,11 +9170,9 @@ dependencies = [ "bytes", "ed25519-dalek", "futures", - "hash-db", "libsecp256k1", "log", "parity-scale-codec", - "parking_lot 0.12.1", "secp256k1", "sp-core", "sp-externalities", @@ -9261,7 +9182,6 @@ dependencies = [ "sp-std", "sp-tracing", "sp-trie", - "sp-wasm-interface", "tracing", "tracing-core", ] @@ -9325,7 +9245,7 @@ name = "sp-npos-elections" version = "4.0.0-dev" dependencies = [ "parity-scale-codec", - "rand 0.7.3", + "rand 0.8.5", "scale-info", "serde", "sp-arithmetic", @@ -9386,7 +9306,7 @@ dependencies = [ "log", "parity-scale-codec", "paste", - "rand 0.7.3", + "rand 0.8.5", "scale-info", "serde", "serde_json", @@ -9516,11 +9436,10 @@ dependencies = [ "assert_matches", "hash-db", "log", - "num-traits", "parity-scale-codec", "parking_lot 0.12.1", "pretty_assertions", - "rand 0.7.3", + "rand 0.8.5", "smallvec", "sp-core", "sp-externalities", @@ -9531,7 +9450,6 @@ dependencies = [ "thiserror", "tracing", "trie-db", - "trie-root", ] [[package]] @@ -9569,7 +9487,6 @@ dependencies = [ "futures-timer", "log", "parity-scale-codec", - "sp-api", "sp-inherents", "sp-runtime", "sp-std", @@ -9680,7 +9597,6 @@ dependencies = [ name = "sp-weights" version = "4.0.0" dependencies = [ - "impl-trait-for-tuples", "parity-scale-codec", "scale-info", "serde", @@ -9855,7 +9771,6 @@ version = "3.0.0" dependencies = [ "frame-support", "frame-system", - "futures", "jsonrpsee", "parity-scale-codec", "sc-rpc-api", @@ -9877,11 +9792,9 @@ dependencies = [ "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", @@ -9896,7 +9809,6 @@ dependencies = [ name = "substrate-prometheus-endpoint" version = "0.10.0-dev" dependencies = [ - "futures-util", "hyper", "log", "prometheus", @@ -9931,10 +9843,8 @@ dependencies = [ "serde", "serde_json", "sp-core", - "sp-io", "sp-runtime", "sp-state-machine", - "sp-std", "sp-trie", "trie-db", ] @@ -10252,17 +10162,17 @@ dependencies = [ [[package]] name = "tiny-bip39" -version = "0.8.2" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffc59cb9dfc85bb312c3a78fd6aa8a8582e310b0fa885d5bb877f6dcc601839d" +checksum = "62cc94d358b5a1e84a5cb9109f559aa3c4d634d2b1b4de3d0fa4adc7c78e2861" dependencies = [ "anyhow", - "hmac 0.8.1", + "hmac 0.12.1", "once_cell", - "pbkdf2 0.4.0", - "rand 0.7.3", + "pbkdf2 0.11.0", + "rand 0.8.5", "rustc-hash", - "sha2 0.9.8", + "sha2 0.10.2", "thiserror", "unicode-normalization", "wasm-bindgen", @@ -10655,7 +10565,6 @@ dependencies = [ "hex", "log", "parity-scale-codec", - "sc-chain-spec", "sc-cli", "sc-executor", "sc-service", @@ -10751,9 +10660,9 @@ checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" [[package]] name = "unicode-normalization" -version = "0.1.17" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07fbfce1c8a97d547e8b5334978438d9d6ec8c20e38f56d4a4374d181493eaef" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" dependencies = [ "tinyvec", ] diff --git a/bin/node/bench/Cargo.toml b/bin/node/bench/Cargo.toml index 265de731de690..9732faf6e10bd 100644 --- a/bin/node/bench/Cargo.toml +++ b/bin/node/bench/Cargo.toml @@ -36,7 +36,7 @@ sp-tracing = { version = "6.0.0", path = "../../../primitives/tracing" } hash-db = "0.15.2" tempfile = "3.1.0" fs_extra = "1" -rand = { version = "0.7.2", features = ["small_rng"] } +rand = { version = "0.8.5", features = ["small_rng"] } lazy_static = "1.4.0" parity-db = "0.4.2" sc-transaction-pool = { version = "4.0.0-dev", path = "../../../client/transaction-pool" } diff --git a/client/api/Cargo.toml b/client/api/Cargo.toml index c57a1e7221ad7..bd1f6f34b0eff 100644 --- a/client/api/Cargo.toml +++ b/client/api/Cargo.toml @@ -19,7 +19,6 @@ 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.17" parking_lot = "0.12.1" prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" } @@ -36,7 +35,6 @@ sp-keystore = { version = "0.13.0", default-features = false, path = "../../prim 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 0da79bd70ff44..5b07e4b7bbeab 100644 --- a/client/authority-discovery/Cargo.toml +++ b/client/authority-discovery/Cargo.toml @@ -24,7 +24,7 @@ ip_network = "0.4.1" libp2p = { version = "0.49.0", default-features = false, features = ["kad"] } log = "0.4.17" prost = "0.11" -rand = "0.7.2" +rand = "0.8.5" 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/beefy/Cargo.toml b/client/beefy/Cargo.toml index d0b36a9255f76..b039faa2d095d 100644 --- a/client/beefy/Cargo.toml +++ b/client/beefy/Cargo.toml @@ -14,17 +14,14 @@ 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" 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", 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" } 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" } diff --git a/client/beefy/rpc/Cargo.toml b/client/beefy/rpc/Cargo.toml index f5b5770153477..f853af8a81c74 100644 --- a/client/beefy/rpc/Cargo.toml +++ b/client/beefy/rpc/Cargo.toml @@ -19,7 +19,6 @@ thiserror = "1.0" beefy-gadget = { version = "4.0.0-dev", path = "../." } 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" } sp-runtime = { version = "7.0.0", path = "../../../primitives/runtime" } diff --git a/client/chain-spec/Cargo.toml b/client/chain-spec/Cargo.toml index 3756a7783763b..0a4e54e8d6a67 100644 --- a/client/chain-spec/Cargo.toml +++ b/client/chain-spec/Cargo.toml @@ -13,8 +13,6 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -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.85" diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index fd84ff4d4574b..a5de78da487c8 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -22,13 +22,13 @@ libp2p = "0.49.0" log = "0.4.17" names = { version = "0.13.0", default-features = false } parity-scale-codec = "3.0.0" -rand = "0.7.3" +rand = "0.8.5" regex = "1.6.0" rpassword = "7.0.0" serde = "1.0.136" serde_json = "1.0.85" thiserror = "1.0.30" -tiny-bip39 = "0.8.2" +tiny-bip39 = "1.0.0" 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" } diff --git a/client/consensus/babe/Cargo.toml b/client/consensus/babe/Cargo.toml index c39802ba237ae..312cc25dd0b59 100644 --- a/client/consensus/babe/Cargo.toml +++ b/client/consensus/babe/Cargo.toml @@ -24,7 +24,6 @@ num-rational = "0.4.1" num-traits = "0.2.8" parking_lot = "0.12.1" schnorrkel = { version = "0.9.1", features = ["preaudit_deprecated"] } -serde = { version = "1.0.136", features = ["derive"] } 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" } @@ -44,10 +43,8 @@ sp-consensus-slots = { version = "0.10.0-dev", path = "../../../primitives/conse sp-consensus-vrf = { version = "0.10.0-dev", path = "../../../primitives/consensus/vrf" } 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-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] rand_chacha = "0.2.2" diff --git a/client/consensus/slots/Cargo.toml b/client/consensus/slots/Cargo.toml index 4bb9387cf5596..6acd656d21a06 100644 --- a/client/consensus/slots/Cargo.toml +++ b/client/consensus/slots/Cargo.toml @@ -19,7 +19,6 @@ codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.21" futures-timer = "3.0.1" 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" } sc-telemetry = { version = "4.0.0-dev", path = "../../telemetry" } diff --git a/client/db/Cargo.toml b/client/db/Cargo.toml index ee879a161edfe..562a94f1900d6 100644 --- a/client/db/Cargo.toml +++ b/client/db/Cargo.toml @@ -37,7 +37,7 @@ sp-trie = { version = "7.0.0", path = "../../primitives/trie" } [dev-dependencies] criterion = "0.3.3" kvdb-rocksdb = "0.17.0" -rand = "0.8.4" +rand = "0.8.5" tempfile = "3.1.0" quickcheck = { version = "1.0.3", default-features = false } kitchensink-runtime = { path = "../../bin/node/runtime" } diff --git a/client/finality-grandpa/Cargo.toml b/client/finality-grandpa/Cargo.toml index 0d5b8eaca5bec..b47c8032482be 100644 --- a/client/finality-grandpa/Cargo.toml +++ b/client/finality-grandpa/Cargo.toml @@ -24,7 +24,7 @@ futures-timer = "3.0.1" log = "0.4.17" parity-scale-codec = { version = "3.0.0", features = ["derive"] } parking_lot = "0.12.1" -rand = "0.8.4" +rand = "0.8.5" serde_json = "1.0.85" thiserror = "1.0" fork-tree = { version = "3.0.0", path = "../../utils/fork-tree" } @@ -33,7 +33,6 @@ sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" } 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-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" } diff --git a/client/finality-grandpa/rpc/Cargo.toml b/client/finality-grandpa/rpc/Cargo.toml index 252c5e3871a64..15b9d3887ba95 100644 --- a/client/finality-grandpa/rpc/Cargo.toml +++ b/client/finality-grandpa/rpc/Cargo.toml @@ -16,7 +16,6 @@ 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"] } -serde_json = "1.0.50" thiserror = "1.0" sc-client-api = { version = "4.0.0-dev", path = "../../api" } sc-finality-grandpa = { version = "0.10.0-dev", path = "../" } diff --git a/client/informant/Cargo.toml b/client/informant/Cargo.toml index a432c2ada5c61..ca0ae03af3265 100644 --- a/client/informant/Cargo.toml +++ b/client/informant/Cargo.toml @@ -19,6 +19,5 @@ futures-timer = "3.0.1" log = "0.4.17" 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 = "7.0.0", path = "../../primitives/runtime" } diff --git a/client/merkle-mountain-range/Cargo.toml b/client/merkle-mountain-range/Cargo.toml index 4fb423cee83bc..cd7d9442492e1 100644 --- a/client/merkle-mountain-range/Cargo.toml +++ b/client/merkle-mountain-range/Cargo.toml @@ -20,7 +20,6 @@ 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" } diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index 1959e24bd680f..be9a74d2c1602 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -17,9 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] array-bytes = "4.1" async-trait = "0.1" asynchronous-codec = "0.6" -bitflags = "1.3.2" 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" @@ -27,21 +25,17 @@ futures = "0.3.21" futures-timer = "3.0.2" ip_network = "0.4.1" 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" lru = "0.8.1" parking_lot = "0.12.1" pin-project = "1.0.12" -prost = "0.11" -rand = "0.7.2" +rand = "0.8.5" serde = { version = "1.0.136", features = ["derive"] } serde_json = "1.0.85" smallvec = "1.8.0" thiserror = "1.0" unsigned-varint = { version = "0.7.1", features = ["futures", "asynchronous_codec"] } 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" } @@ -57,7 +51,6 @@ sp-runtime = { version = "7.0.0", path = "../../primitives/runtime" } [dev-dependencies] assert_matches = "1.3" -rand = "0.7.2" tempfile = "3.1.0" tokio = { version = "1.22.0", features = ["macros"] } tokio-util = { version = "0.7.4", features = ["compat"] } diff --git a/client/network/bitswap/Cargo.toml b/client/network/bitswap/Cargo.toml index 099b5cd5e88b2..c4c7850b7170b 100644 --- a/client/network/bitswap/Cargo.toml +++ b/client/network/bitswap/Cargo.toml @@ -23,7 +23,6 @@ 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" } diff --git a/client/network/test/Cargo.toml b/client/network/test/Cargo.toml index 86b5be37d256a..25e4df00e01de 100644 --- a/client/network/test/Cargo.toml +++ b/client/network/test/Cargo.toml @@ -20,7 +20,7 @@ futures-timer = "3.0.1" libp2p = { version = "0.49.0", default-features = false } log = "0.4.17" parking_lot = "0.12.1" -rand = "0.7.2" +rand = "0.8.5" 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" } diff --git a/client/network/transactions/Cargo.toml b/client/network/transactions/Cargo.toml index cb45abca02f6a..f91651d1508b5 100644 --- a/client/network/transactions/Cargo.toml +++ b/client/network/transactions/Cargo.toml @@ -16,7 +16,6 @@ targets = ["x86_64-unknown-linux-gnu"] 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.49.0" log = "0.4.17" pin-project = "1.0.12" diff --git a/client/offchain/Cargo.toml b/client/offchain/Cargo.toml index 6406d7dc475a8..baeec0b6d731a 100644 --- a/client/offchain/Cargo.toml +++ b/client/offchain/Cargo.toml @@ -25,7 +25,7 @@ libp2p = { version = "0.49.0", default-features = false } num_cpus = "1.13" once_cell = "1.8" parking_lot = "0.12.1" -rand = "0.7.2" +rand = "0.8.5" threadpool = "1.7" tracing = "0.1.29" sc-client-api = { version = "4.0.0-dev", path = "../api" } diff --git a/client/peerset/Cargo.toml b/client/peerset/Cargo.toml index ade2bc3d78d03..8625fe40c20d4 100644 --- a/client/peerset/Cargo.toml +++ b/client/peerset/Cargo.toml @@ -22,4 +22,4 @@ wasm-timer = "0.2" sc-utils = { version = "4.0.0-dev", path = "../utils" } [dev-dependencies] -rand = "0.7.2" +rand = "0.8.5" diff --git a/client/rpc-api/Cargo.toml b/client/rpc-api/Cargo.toml index c46488db2d8e1..f697f53e98283 100644 --- a/client/rpc-api/Cargo.toml +++ b/client/rpc-api/Cargo.toml @@ -14,9 +14,6 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } -futures = "0.3.21" -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.85" @@ -26,6 +23,5 @@ sc-transaction-pool-api = { version = "4.0.0-dev", path = "../transaction-pool/a sp-core = { version = "7.0.0", path = "../../primitives/core" } 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.16.2", features = ["server", "client-core", "macros"] } diff --git a/client/rpc-servers/Cargo.toml b/client/rpc-servers/Cargo.toml index b494749ffd26a..c6228d739048d 100644 --- a/client/rpc-servers/Cargo.toml +++ b/client/rpc-servers/Cargo.toml @@ -13,7 +13,6 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -futures = "0.3.21" jsonrpsee = { version = "0.16.2", features = ["server"] } log = "0.4.17" serde_json = "1.0.85" diff --git a/client/rpc/Cargo.toml b/client/rpc/Cargo.toml index a241807cc242b..d97170ddf42e6 100644 --- a/client/rpc/Cargo.toml +++ b/client/rpc/Cargo.toml @@ -15,9 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] 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.16.2", features = ["server"] } -lazy_static = { version = "1.4.0", optional = true } log = "0.4.17" parking_lot = "0.12.1" serde_json = "1.0.85" @@ -43,7 +41,6 @@ tokio = { version = "1.22.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-network-common = { version = "0.10.0-dev", path = "../network/common" } @@ -54,4 +51,4 @@ sp-io = { version = "7.0.0", path = "../../primitives/io" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } [features] -test-helpers = ["lazy_static", "tokio"] +test-helpers = ["tokio"] diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index 4d1d267d45c97..45b1c02620fb2 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -25,13 +25,12 @@ runtime-benchmarks = ["sc-client-db/runtime-benchmarks"] jsonrpsee = { version = "0.16.2", features = ["server"] } thiserror = "1.0.30" futures = "0.3.21" -rand = "0.7.3" +rand = "0.8.5" parking_lot = "0.12.1" log = "0.4.17" futures-timer = "3.0.1" exit-future = "0.2.0" pin-project = "1.0.12" -hash-db = "0.15.2" serde = "1.0.136" serde_json = "1.0.85" sc-keystore = { version = "4.0.0-dev", path = "../keystore" } @@ -45,10 +44,8 @@ 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.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 = "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" } @@ -70,13 +67,11 @@ 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" } 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 = "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 46ba1b33931ac..d3bc39aa3486c 100644 --- a/client/service/test/Cargo.toml +++ b/client/service/test/Cargo.toml @@ -33,8 +33,6 @@ 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-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" } diff --git a/client/state-db/Cargo.toml b/client/state-db/Cargo.toml index b6d40a8106322..fb70f5fc6a8ba 100644 --- a/client/state-db/Cargo.toml +++ b/client/state-db/Cargo.toml @@ -16,5 +16,4 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } log = "0.4.17" 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/sysinfo/Cargo.toml b/client/sysinfo/Cargo.toml index c59611ed1b432..73aa7b8d10422 100644 --- a/client/sysinfo/Cargo.toml +++ b/client/sysinfo/Cargo.toml @@ -17,8 +17,8 @@ targets = ["x86_64-unknown-linux-gnu"] futures = "0.3.19" libc = "0.2" log = "0.4.17" -rand = "0.7.3" -rand_pcg = "0.2.1" +rand = "0.8.5" +rand_pcg = "0.3.1" regex = "1" serde = { version = "1.0.136", features = ["derive"] } serde_json = "1.0.85" diff --git a/client/telemetry/Cargo.toml b/client/telemetry/Cargo.toml index 0a0b9284efa24..1fc89980e2de8 100644 --- a/client/telemetry/Cargo.toml +++ b/client/telemetry/Cargo.toml @@ -20,7 +20,7 @@ libp2p = { version = "0.49.0", default-features = false, features = ["dns", "tcp log = "0.4.17" parking_lot = "0.12.1" pin-project = "1.0.12" -rand = "0.7.2" +rand = "0.8.5" serde = { version = "1.0.136", features = ["derive"] } serde_json = "1.0.85" thiserror = "1.0.30" diff --git a/client/telemetry/src/node.rs b/client/telemetry/src/node.rs index 0d71a363a1b26..71eed04128c7c 100644 --- a/client/telemetry/src/node.rs +++ b/client/telemetry/src/node.rs @@ -76,7 +76,7 @@ enum NodeSocket { impl NodeSocket { fn wait_reconnect() -> NodeSocket { - let random_delay = rand::thread_rng().gen_range(10, 20); + let random_delay = rand::thread_rng().gen_range(10..20); let delay = Delay::new(Duration::from_secs(random_delay)); log::trace!(target: "telemetry", "Pausing for {} secs before reconnecting", random_delay); NodeSocket::WaitingReconnect(delay) diff --git a/frame/election-provider-multi-phase/Cargo.toml b/frame/election-provider-multi-phase/Cargo.toml index 42cd682a0ff02..a21740dd72a02 100644 --- a/frame/election-provider-multi-phase/Cargo.toml +++ b/frame/election-provider-multi-phase/Cargo.toml @@ -12,7 +12,6 @@ description = "PALLET two phase election providers" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -static_assertions = "1.1.0" codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } @@ -35,12 +34,12 @@ 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, features = ["alloc", "small_rng"], optional = true } +rand = { version = "0.8.5", default-features = false, features = ["alloc", "small_rng"], optional = true } strum = { version = "0.24.1", default-features = false, features = ["derive"], optional = true } [dev-dependencies] parking_lot = "0.12.1" -rand = { version = "0.7.3" } +rand = "0.8.5" 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" } diff --git a/frame/election-provider-support/Cargo.toml b/frame/election-provider-support/Cargo.toml index 33a6f25ed0822..108a49eb08abc 100644 --- a/frame/election-provider-support/Cargo.toml +++ b/frame/election-provider-support/Cargo.toml @@ -24,7 +24,7 @@ sp-std = { version = "5.0.0", default-features = false, path = "../../primitives sp-core = { version = "7.0.0", default-features = false, path = "../../primitives/core" } [dev-dependencies] -rand = "0.7.3" +rand = { version = "0.8.5", features = ["small_rng"] } sp-io = { version = "7.0.0", path = "../../primitives/io" } sp-npos-elections = { version = "4.0.0-dev", path = "../../primitives/npos-elections" } diff --git a/frame/election-provider-support/src/mock.rs b/frame/election-provider-support/src/mock.rs index 7c834f06f3cdf..0789ee90e6662 100644 --- a/frame/election-provider-support/src/mock.rs +++ b/frame/election-provider-support/src/mock.rs @@ -97,7 +97,7 @@ pub fn generate_random_votes( // 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)); + 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)); @@ -106,7 +106,7 @@ pub fn generate_random_votes( // 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 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); @@ -123,7 +123,7 @@ pub fn generate_random_votes( 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); + let stake = rng.gen_range(0..available_stake).min(1); stake_distribution.push(TestAccuracy::from_perthousand(stake)); available_stake -= stake; } diff --git a/frame/election-provider-support/src/tests.rs b/frame/election-provider-support/src/tests.rs index 1ccff79f3efd4..c38444f011dfe 100644 --- a/frame/election-provider-support/src/tests.rs +++ b/frame/election-provider-support/src/tests.rs @@ -92,7 +92,7 @@ mod solution_type { #[test] fn from_assignment_fail_too_many_voters() { - let rng = rand::rngs::SmallRng::seed_from_u64(0); + let rng = rand::rngs::SmallRng::seed_from_u64(1); // This will produce 24 voters.. let (voters, assignments, candidates) = generate_random_votes(10, 25, rng); diff --git a/frame/session/benchmarking/Cargo.toml b/frame/session/benchmarking/Cargo.toml index 90d6d95c07f4f..53d6ff0cd18a0 100644 --- a/frame/session/benchmarking/Cargo.toml +++ b/frame/session/benchmarking/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -rand = { version = "0.7.2", default-features = false } +rand = { version = "0.8.5", default-features = false, features = ["std_rng"] } 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/primitives/arithmetic/Cargo.toml b/primitives/arithmetic/Cargo.toml index 36c86230e96ce..2da8767fd2a7d 100644 --- a/primitives/arithmetic/Cargo.toml +++ b/primitives/arithmetic/Cargo.toml @@ -23,14 +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 = "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 = "7.0.0", features = ["full_crypto"], path = "../core" } -rand = "0.7.2" +rand = "0.8.5" [features] default = ["std"] @@ -39,7 +38,6 @@ std = [ "num-traits/std", "scale-info/std", "serde", - "sp-debug-derive/std", "sp-std/std", ] diff --git a/primitives/arithmetic/benches/bench.rs b/primitives/arithmetic/benches/bench.rs index 57556135f6431..5551d209098cf 100644 --- a/primitives/arithmetic/benches/bench.rs +++ b/primitives/arithmetic/benches/bench.rs @@ -21,7 +21,7 @@ use sp_arithmetic::biguint::{BigUint, Single}; fn random_big_uint(size: usize) -> BigUint { let mut rng = rand::thread_rng(); - let digits: Vec<_> = (0..size).map(|_| rng.gen_range(0, Single::max_value())).collect(); + let digits: Vec<_> = (0..size).map(|_| rng.gen_range(0..Single::MAX)).collect(); BigUint::from_limbs(&digits) } @@ -64,7 +64,7 @@ fn bench_division(c: &mut Criterion) { group.throughput(Throughput::Elements(*size)); group.bench_with_input(BenchmarkId::from_parameter(size), size, |bencher, &size| { let a = random_big_uint(size as usize); - let b = random_big_uint(rand::thread_rng().gen_range(2, size as usize)); + let b = random_big_uint(rand::thread_rng().gen_range(2..size as usize)); bencher.iter(|| { let _ = a.clone().div(&b, true); diff --git a/primitives/consensus/common/Cargo.toml b/primitives/consensus/common/Cargo.toml index 6df4e5c7232a8..9b4cac722adcd 100644 --- a/primitives/consensus/common/Cargo.toml +++ b/primitives/consensus/common/Cargo.toml @@ -19,7 +19,6 @@ codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive", ] } futures = { version = "0.3.21", features = ["thread-pool"] } -futures-timer = "3.0.1" log = "0.4.17" thiserror = "1.0.30" sp-core = { version = "7.0.0", path = "../../core" } diff --git a/primitives/consensus/slots/Cargo.toml b/primitives/consensus/slots/Cargo.toml index a7b941b3f498d..3360e80772084 100644 --- a/primitives/consensus/slots/Cargo.toml +++ b/primitives/consensus/slots/Cargo.toml @@ -16,8 +16,6 @@ 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 = "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" } @@ -27,8 +25,6 @@ std = [ "codec/std", "scale-info/std", "serde", - "sp-arithmetic/std", - "sp-runtime/std", "sp-std/std", "sp-timestamp/std", ] diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index bfec09a13c135..68c780c473f0a 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -20,18 +20,15 @@ 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.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.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 } base58 = { version = "0.2.0", optional = true } -rand = { version = "0.7.3", optional = true, features = ["small_rng"] } +rand = { version = "0.8.5", optional = true, features = ["small_rng"] } substrate-bip39 = { version = "0.4.4", optional = true } -tiny-bip39 = { version = "0.8.2", optional = true } +tiny-bip39 = { version = "1.0.0", 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 } lazy_static = { version = "1.4.0", default-features = false, optional = true } @@ -62,7 +59,7 @@ sp-runtime-interface = { version = "7.0.0", default-features = false, path = ".. [dev-dependencies] sp-serializer = { version = "4.0.0-dev", path = "../serializer" } -rand = "0.7.2" +rand = "0.8.5" criterion = "0.3.3" serde_json = "1.0" sp-core-hashing-proc-macro = { version = "5.0.0", path = "./hashing/proc-macro" } @@ -81,7 +78,6 @@ std = [ "full_crypto", "log/std", "thiserror", - "wasmi", "lazy_static", "parking_lot", "primitive-types/std", @@ -101,11 +97,9 @@ std = [ "base58", "substrate-bip39", "tiny-bip39", - "byteorder/std", "rand", "schnorrkel/std", "regex", - "num-traits/std", "secp256k1/std", "secp256k1/global-context", "sp-core-hashing/std", diff --git a/primitives/io/Cargo.toml b/primitives/io/Cargo.toml index cd900b8f158ef..57dc3604de73f 100644 --- a/primitives/io/Cargo.toml +++ b/primitives/io/Cargo.toml @@ -17,20 +17,17 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] 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 = "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.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 } 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} @@ -45,19 +42,16 @@ std = [ "sp-keystore", "codec/std", "sp-std/std", - "hash-db/std", "sp-trie/std", "sp-state-machine/std", "libsecp256k1", "secp256k1", "sp-runtime-interface/std", - "sp-wasm-interface/std", "sp-tracing/std", "tracing/std", "tracing-core/std", "log", "futures", - "parking_lot", "ed25519-dalek", ] diff --git a/primitives/npos-elections/Cargo.toml b/primitives/npos-elections/Cargo.toml index b99b05e0e3a09..702986da309ef 100644 --- a/primitives/npos-elections/Cargo.toml +++ b/primitives/npos-elections/Cargo.toml @@ -22,7 +22,7 @@ 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" +rand = "0.8.5" substrate-test-utils = { version = "4.0.0-dev", path = "../../test-utils" } [features] diff --git a/primitives/runtime/Cargo.toml b/primitives/runtime/Cargo.toml index 4202110cd60c2..79bbda700de29 100644 --- a/primitives/runtime/Cargo.toml +++ b/primitives/runtime/Cargo.toml @@ -20,7 +20,7 @@ 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 } paste = "1.0" -rand = { version = "0.7.2", optional = true } +rand = { version = "0.8.5", 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 = "7.0.0", default-features = false, path = "../application-crypto" } @@ -31,7 +31,7 @@ sp-std = { version = "5.0.0", default-features = false, path = "../std" } sp-weights = { version = "4.0.0", default-features = false, path = "../weights" } [dev-dependencies] -rand = "0.7.2" +rand = "0.8.5" serde_json = "1.0.85" zstd = { version = "0.11.2", default-features = false } sp-api = { version = "4.0.0-dev", path = "../api" } diff --git a/primitives/state-machine/Cargo.toml b/primitives/state-machine/Cargo.toml index 98794db60d30b..06419c5925cf8 100644 --- a/primitives/state-machine/Cargo.toml +++ b/primitives/state-machine/Cargo.toml @@ -17,13 +17,11 @@ targets = ["x86_64-unknown-linux-gnu"] 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.17", optional = true } -num-traits = { version = "0.2.8", default-features = false } parking_lot = { version = "0.12.1", optional = true } -rand = { version = "0.7.2", optional = true } +rand = { version = "0.8.5", optional = true } 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 = "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" } @@ -33,7 +31,7 @@ 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" +rand = "0.8.5" sp-runtime = { version = "7.0.0", path = "../runtime" } trie-db = "0.24.0" assert_matches = "1.5" @@ -44,7 +42,6 @@ std = [ "codec/std", "hash-db/std", "log", - "num-traits/std", "parking_lot", "rand", "sp-core/std", @@ -54,5 +51,4 @@ std = [ "sp-trie/std", "thiserror", "tracing", - "trie-root/std", ] diff --git a/primitives/state-machine/src/lib.rs b/primitives/state-machine/src/lib.rs index 225fe1582e752..188fb2f4b8d99 100644 --- a/primitives/state-machine/src/lib.rs +++ b/primitives/state-machine/src/lib.rs @@ -1845,7 +1845,7 @@ mod tests { use rand::{rngs::SmallRng, RngCore, SeedableRng}; let mut storage: HashMap, BTreeMap> = Default::default(); - let mut seed = [0; 16]; + let mut seed = [0; 32]; for i in 0..50u32 { let mut child_infos = Vec::new(); let seed_partial = &mut seed[0..4]; diff --git a/primitives/timestamp/Cargo.toml b/primitives/timestamp/Cargo.toml index 72266a48b0d6c..5d015086c4d79 100644 --- a/primitives/timestamp/Cargo.toml +++ b/primitives/timestamp/Cargo.toml @@ -18,7 +18,6 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = futures-timer = { version = "3.0.2", 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" } sp-runtime = { version = "7.0.0", default-features = false, path = "../runtime" } sp-std = { version = "5.0.0", default-features = false, path = "../std" } @@ -30,7 +29,6 @@ std = [ "codec/std", "futures-timer", "log", - "sp-api/std", "sp-inherents/std", "sp-runtime/std", "sp-std/std", diff --git a/primitives/weights/Cargo.toml b/primitives/weights/Cargo.toml index 00996458362fe..00da83069e388 100644 --- a/primitives/weights/Cargo.toml +++ b/primitives/weights/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, 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" diff --git a/utils/frame/benchmarking-cli/Cargo.toml b/utils/frame/benchmarking-cli/Cargo.toml index 5173340f7d0d9..9e231b8173fb1 100644 --- a/utils/frame/benchmarking-cli/Cargo.toml +++ b/utils/frame/benchmarking-cli/Cargo.toml @@ -19,20 +19,15 @@ 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" -hash-db = "0.15.2" Inflector = "0.11.4" itertools = "0.10.3" -kvdb = "0.13.0" lazy_static = "1.4.0" linked-hash-map = "0.5.4" log = "0.4.17" -memory-db = "0.31.0" rand = { version = "0.8.4", features = ["small_rng"] } rand_pcg = "0.3.1" serde = "1.0.136" serde_json = "1.0.85" -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" } diff --git a/utils/frame/generate-bags/Cargo.toml b/utils/frame/generate-bags/Cargo.toml index 04d598c7843c4..6006cdb5da0e5 100644 --- a/utils/frame/generate-bags/Cargo.toml +++ b/utils/frame/generate-bags/Cargo.toml @@ -15,9 +15,6 @@ frame-election-provider-support = { version = "4.0.0-dev", path = "../../../fram frame-system = { version = "4.0.0-dev", path = "../../../frame/system" } pallet-staking = { version = "4.0.0-dev", path = "../../../frame/staking" } -# primitives -sp-io = { version = "7.0.0", path = "../../../primitives/io" } - # third party chrono = { version = "0.4.19" } git2 = { version = "0.14.2", default-features = false } diff --git a/utils/frame/remote-externalities/Cargo.toml b/utils/frame/remote-externalities/Cargo.toml index ad8230fe29dcf..5a51dbc661c90 100644 --- a/utils/frame/remote-externalities/Cargo.toml +++ b/utils/frame/remote-externalities/Cargo.toml @@ -13,15 +13,12 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } -env_logger = "0.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 = "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" } tokio = { version = "1.22.0", features = ["macros", "rt-multi-thread"] } substrate-rpc-client = { path = "../rpc/client" } futures = "0.3" diff --git a/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml b/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml index 3a1b4b8b6cbf8..dd6456f714a3e 100644 --- a/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml +++ b/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml @@ -18,8 +18,6 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = serde = { version = "1", features = ["derive"] } log = { version = "0.4.17", 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" } diff --git a/utils/frame/rpc/support/Cargo.toml b/utils/frame/rpc/support/Cargo.toml index d098877e7302c..066038469292d 100644 --- a/utils/frame/rpc/support/Cargo.toml +++ b/utils/frame/rpc/support/Cargo.toml @@ -16,7 +16,6 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } -futures = "0.3.21" jsonrpsee = { version = "0.16.2", features = ["jsonrpsee-types"] } serde = "1" frame-support = { version = "4.0.0-dev", path = "../../../../frame/support" } diff --git a/utils/frame/rpc/system/Cargo.toml b/utils/frame/rpc/system/Cargo.toml index 92cf6882a10f1..55fc4b27dbf73 100644 --- a/utils/frame/rpc/system/Cargo.toml +++ b/utils/frame/rpc/system/Cargo.toml @@ -13,13 +13,11 @@ 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.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" } -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" } diff --git a/utils/frame/try-runtime/cli/Cargo.toml b/utils/frame/try-runtime/cli/Cargo.toml index d6f211392c6cf..c4cc2e757d90f 100644 --- a/utils/frame/try-runtime/cli/Cargo.toml +++ b/utils/frame/try-runtime/cli/Cargo.toml @@ -13,7 +13,6 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] 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" } sc-service = { version = "0.10.0-dev", default-features = false, path = "../../../../client/service" } diff --git a/utils/prometheus/Cargo.toml b/utils/prometheus/Cargo.toml index 1371fe6f408c0..e84a6f4b30341 100644 --- a/utils/prometheus/Cargo.toml +++ b/utils/prometheus/Cargo.toml @@ -13,7 +13,6 @@ 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.17" prometheus = { version = "0.13.0", default-features = false } From 1f0865c4f8cde8589e36f70b142db36219115f23 Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Mon, 19 Dec 2022 11:18:32 +0100 Subject: [PATCH 206/715] sc-network-test::Peer: block push methods return hashes vec (#12944) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * sc-network-test::Peer: block push methods return hashes vec This commit reworks the block generation/push methods in sc-network-test::Peer. Now methods are providing the vector of hashes that were built. This allows to get rid of redundant `block_hash_from_id` call, as all hashes are known just after being built. Similar approach was taken in BeefyTestNet::generate_blocks_and_sync method. This PR is part of BlockId::Number refactoring analysis (paritytech/substrate#11292) * fix * Apply suggestions from code review Co-authored-by: Bastian Köcher Co-authored-by: Bastian Köcher --- bin/node/bench/src/import.rs | 9 +- client/beefy/src/tests.rs | 120 +++++++++++----------- client/beefy/src/worker.rs | 8 +- client/finality-grandpa/src/tests.rs | 97 +++++++++--------- client/network/test/src/lib.rs | 32 +++--- client/network/test/src/sync.rs | 143 ++++++++++++++------------- 6 files changed, 212 insertions(+), 197 deletions(-) diff --git a/bin/node/bench/src/import.rs b/bin/node/bench/src/import.rs index 28a322834271c..7d59e94a44a09 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, HeaderBackend}; +use sc_client_api::backend::Backend; use sp_runtime::generic::BlockId; use sp_state_machine::InspectState; @@ -127,15 +127,10 @@ 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(hash) + .state_at(self.block.header.hash()) .expect("state_at failed for block#1") .inspect_state(|| { match self.block_type { diff --git a/client/beefy/src/tests.rs b/client/beefy/src/tests.rs index d2befc979b737..055c2669eb415 100644 --- a/client/beefy/src/tests.rs +++ b/client/beefy/src/tests.rs @@ -139,14 +139,26 @@ impl BeefyTestNet { }); } + /// Builds the blocks and returns the vector of built block hashes. + /// Returned vector contains the genesis hash which allows for easy indexing (block number is + /// equal to index) pub(crate) async fn generate_blocks_and_sync( &mut self, count: usize, session_length: u64, validator_set: &BeefyValidatorSet, include_mmr_digest: bool, - ) { - self.peer(0).generate_blocks(count, BlockOrigin::File, |builder| { + ) -> Vec { + let mut all_hashes = Vec::with_capacity(count + 1); + + // make sure genesis is the only block in network, so we can insert genesis at he beginning + // of hashes, otherwise indexing would be broken + assert!(self.peer(0).client().as_backend().blockchain().hash(1).unwrap().is_none()); + + // push genesis to make indexing human readable (index equals to block number) + all_hashes.push(self.peer(0).client().info().genesis_hash); + + let built_hashes = self.peer(0).generate_blocks(count, BlockOrigin::File, |builder| { let mut block = builder.build().unwrap().block; if include_mmr_digest { @@ -162,7 +174,10 @@ impl BeefyTestNet { block }); + all_hashes.extend(built_hashes); self.run_until_sync().await; + + all_hashes } } @@ -495,7 +510,7 @@ async fn finalize_block_and_wait_for_beefy( net: &Arc>, // peer index and key peers: impl Iterator + Clone, - finalize_targets: &[u64], + finalize_targets: &[H256], expected_beefy: &[u64], ) { let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), peers.clone()); @@ -503,8 +518,7 @@ async fn finalize_block_and_wait_for_beefy( for block in finalize_targets { 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(*block, None).unwrap(); }) } @@ -536,7 +550,7 @@ async fn beefy_finalizing_blocks() { tokio::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).await; + let hashes = net.generate_blocks_and_sync(42, session_len, &validator_set, true).await; let net = Arc::new(Mutex::new(net)); @@ -544,19 +558,19 @@ async 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(), &[1, 5], &[1, 5]).await; + finalize_block_and_wait_for_beefy(&net, peers.clone(), &[hashes[1], hashes[5]], &[1, 5]).await; // GRANDPA finalize #10 -> BEEFY finalize #10 (mandatory) - finalize_block_and_wait_for_beefy(&net, peers.clone(), &[10], &[10]).await; + finalize_block_and_wait_for_beefy(&net, peers.clone(), &[hashes[10]], &[10]).await; // GRANDPA finalize #18 -> BEEFY finalize #14, then #18 (diff-power-of-two rule) - finalize_block_and_wait_for_beefy(&net, peers.clone(), &[18], &[14, 18]).await; + finalize_block_and_wait_for_beefy(&net, peers.clone(), &[hashes[18]], &[14, 18]).await; // GRANDPA finalize #20 -> BEEFY finalize #20 (mandatory) - finalize_block_and_wait_for_beefy(&net, peers.clone(), &[20], &[20]).await; + finalize_block_and_wait_for_beefy(&net, peers.clone(), &[hashes[20]], &[20]).await; // GRANDPA finalize #21 -> BEEFY finalize nothing (yet) because min delta is 4 - finalize_block_and_wait_for_beefy(&net, peers, &[21], &[]).await; + finalize_block_and_wait_for_beefy(&net, peers, &[hashes[21]], &[]).await; } #[tokio::test] @@ -574,23 +588,23 @@ async fn lagging_validators() { tokio::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).await; + let hashes = net.generate_blocks_and_sync(62, session_len, &validator_set, true).await; 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.clone(), &[1, 15], &[1, 9, 13, 14, 15]).await; + finalize_block_and_wait_for_beefy( + &net, + peers.clone(), + &[hashes[1], hashes[15]], + &[1, 9, 13, 14, 15], + ) + .await; // Alice finalizes #25, Bob lags behind - let finalize = net - .lock() - .peer(0) - .client() - .as_client() - .expect_block_hash_from_id(&BlockId::number(25)) - .unwrap(); + let finalize = hashes[25]; 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 @@ -606,7 +620,13 @@ async fn lagging_validators() { wait_for_beefy_signed_commitments(versioned_finality_proof, &net, &[23, 24, 25]).await; // Both finalize #30 (mandatory session) and #32 -> BEEFY finalize #30 (mandatory), #31, #32 - finalize_block_and_wait_for_beefy(&net, peers.clone(), &[30, 32], &[30, 31, 32]).await; + finalize_block_and_wait_for_beefy( + &net, + peers.clone(), + &[hashes[30], hashes[32]], + &[30, 31, 32], + ) + .await; // 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 @@ -614,13 +634,7 @@ async 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 = net - .lock() - .peer(0) - .client() - .as_client() - .expect_block_hash_from_id(&BlockId::number(60)) - .unwrap(); + let finalize = hashes[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)); @@ -661,24 +675,18 @@ async fn correct_beefy_payload() { tokio::spawn(initialize_beefy(&mut net, bad_peers, min_block_delta)); // push 12 blocks - net.generate_blocks_and_sync(12, session_len, &validator_set, false).await; + let hashes = net.generate_blocks_and_sync(12, session_len, &validator_set, false).await; 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, &[1, 10], &[1, 9]).await; + finalize_block_and_wait_for_beefy(&net, peers, &[hashes[1], hashes[10]], &[1, 9]).await; let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), [(0, BeefyKeyring::Alice)].into_iter()); // now 2 good validators and 1 bad one are voting - let hashof11 = net - .lock() - .peer(0) - .client() - .as_client() - .expect_block_hash_from_id(&BlockId::number(11)) - .unwrap(); + let hashof11 = hashes[11]; 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(); @@ -863,7 +871,7 @@ async fn voter_initialization() { tokio::spawn(initialize_beefy(&mut net, beefy_peers, min_block_delta)); // push 26 blocks - net.generate_blocks_and_sync(26, session_len, &validator_set, false).await; + let hashes = net.generate_blocks_and_sync(26, session_len, &validator_set, false).await; let net = Arc::new(Mutex::new(net)); // Finalize multiple blocks at once to get a burst of finality notifications right from start. @@ -872,7 +880,7 @@ async fn voter_initialization() { finalize_block_and_wait_for_beefy( &net, peers.into_iter().enumerate(), - &[1, 6, 10, 17, 24, 26], + &[hashes[1], hashes[6], hashes[10], hashes[17], hashes[24], hashes[26]], &[1, 5, 10, 15, 20, 25], ) .await; @@ -905,7 +913,7 @@ async fn on_demand_beefy_justification_sync() { let dave_index = 3; // push 30 blocks - net.generate_blocks_and_sync(30, session_len, &validator_set, false).await; + let hashes = net.generate_blocks_and_sync(30, session_len, &validator_set, false).await; let fast_peers = fast_peers.into_iter().enumerate(); let net = Arc::new(Mutex::new(net)); @@ -914,7 +922,7 @@ async fn on_demand_beefy_justification_sync() { finalize_block_and_wait_for_beefy( &net, fast_peers.clone(), - &[1, 6, 10, 17, 24], + &[hashes[1], hashes[6], hashes[10], hashes[17], hashes[24]], &[1, 5, 10, 15, 20], ) .await; @@ -927,14 +935,13 @@ async fn on_demand_beefy_justification_sync() { let (dave_best_blocks, _) = 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(hashes[1], None).unwrap(); // Give Dave task some cpu cycles to process the finality notification, run_for(Duration::from_millis(100), &net).await; // 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, &[25], &[25]).await; + finalize_block_and_wait_for_beefy(&net, fast_peers, &[hashes[25]], &[25]).await; // Now verify Dave successfully finalized #1 (through on-demand justification request). wait_for_best_beefy_blocks(dave_best_blocks, &net, &[1]).await; @@ -945,14 +952,14 @@ async fn on_demand_beefy_justification_sync() { finalize_block_and_wait_for_beefy( &net, [(dave_index, BeefyKeyring::Dave)].into_iter(), - &[6, 10, 17, 24, 26], + &[hashes[6], hashes[10], hashes[17], hashes[24], hashes[26]], &[5, 10, 15, 20, 25], ) .await; 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, &[30], &[30]).await; + finalize_block_and_wait_for_beefy(&net, all_peers, &[hashes[30]], &[30]).await; } #[tokio::test] @@ -963,13 +970,12 @@ async fn should_initialize_voter_at_genesis() { 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).await; + let hashes = net.generate_blocks_and_sync(15, 10, &validator_set, false).await; 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(); + net.peer(0).client().as_client().finalize_block(hashes[13], None).unwrap(); // load persistent state - nothing in DB, should init at session boundary let persisted_state = voter_init_setup(&mut net, &mut finality).unwrap(); @@ -1008,13 +1014,12 @@ async fn should_initialize_voter_when_last_final_is_session_boundary() { 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).await; + let hashes = net.generate_blocks_and_sync(15, 10, &validator_set, false).await; 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(); + net.peer(0).client().as_client().finalize_block(hashes[13], None).unwrap(); // import/append BEEFY justification for session boundary block 10 let commitment = Commitment { @@ -1026,9 +1031,8 @@ async fn should_initialize_voter_when_last_final_is_session_boundary() { 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())) + .append_justification(hashes[10], (BEEFY_ENGINE_ID, justif.encode())) .unwrap(); // Test corner-case where session boundary == last beefy finalized, @@ -1068,13 +1072,12 @@ async fn should_initialize_voter_at_latest_finalized() { 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).await; + let hashes = net.generate_blocks_and_sync(15, 10, &validator_set, false).await; 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(); + net.peer(0).client().as_client().finalize_block(hashes[13], None).unwrap(); // import/append BEEFY justification for block 12 let commitment = Commitment { @@ -1086,9 +1089,8 @@ async fn should_initialize_voter_at_latest_finalized() { 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())) + .append_justification(hashes[12], (BEEFY_ENGINE_ID, justif.encode())) .unwrap(); // Test initialization at last BEEFY finalized. diff --git a/client/beefy/src/worker.rs b/client/beefy/src/worker.rs index df465b2dbf52c..89d231a6c2d73 100644 --- a/client/beefy/src/worker.rs +++ b/client/beefy/src/worker.rs @@ -1382,10 +1382,10 @@ 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.peer(0).push_blocks(2, false); - // 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(); + let hashes = net.peer(0).push_blocks(2, false); + // finalize 1 and 2 without justifications (hashes does not contain genesis) + let hashof1 = hashes[0]; + let hashof2 = hashes[1]; backend.finalize_block(hashof1, None).unwrap(); backend.finalize_block(hashof2, None).unwrap(); diff --git a/client/finality-grandpa/src/tests.rs b/client/finality-grandpa/src/tests.rs index 97c0c9fe7ce49..d5bc7d50c5fa8 100644 --- a/client/finality-grandpa/src/tests.rs +++ b/client/finality-grandpa/src/tests.rs @@ -627,14 +627,18 @@ async fn sync_justifications_on_change_blocks() { net.peer(0).push_blocks(20, false); // at block 21 we do add a transition which is instant - let hashof21 = net.peer(0).generate_blocks(1, BlockOrigin::File, |builder| { - let mut block = builder.build().unwrap().block; - add_scheduled_change( - &mut block, - ScheduledChange { next_authorities: make_ids(peers_b), delay: 0 }, - ); - block - }); + let hashof21 = net + .peer(0) + .generate_blocks(1, BlockOrigin::File, |builder| { + let mut block = builder.build().unwrap().block; + add_scheduled_change( + &mut block, + ScheduledChange { next_authorities: make_ids(peers_b), delay: 0 }, + ); + block + }) + .pop() + .unwrap(); // add more blocks on top of it (until we have 25) net.peer(0).push_blocks(4, false); @@ -1352,7 +1356,7 @@ async fn grandpa_environment_respects_voting_rules() { let link = peer.data.lock().take().unwrap(); // add 21 blocks - peer.push_blocks(21, false); + let hashes = peer.push_blocks(21, false); // create an environment with no voting rule restrictions let unrestricted_env = test_environment(&link, None, network_service.clone(), ()); @@ -1408,12 +1412,7 @@ async fn grandpa_environment_respects_voting_rules() { ); // we finalize block 19 with block 21 being the best block - let hashof19 = peer - .client() - .as_client() - .expect_block_hash_from_id(&BlockId::Number(19)) - .unwrap(); - peer.client().finalize_block(hashof19, None, false).unwrap(); + peer.client().finalize_block(hashes[18], None, false).unwrap(); // the 3/4 environment should propose block 21 for voting assert_eq!( @@ -1439,11 +1438,7 @@ async fn grandpa_environment_respects_voting_rules() { ); // we finalize block 21 with block 21 being the best block - let hashof21 = peer - .client() - .as_client() - .expect_block_hash_from_id(&BlockId::Number(21)) - .unwrap(); + let hashof21 = hashes[20]; peer.client().finalize_block(hashof21, None, false).unwrap(); // even though the default environment will always try to not vote on the @@ -1757,20 +1752,23 @@ async fn revert_prunes_authority_changes() { // 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, - ); + 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, + ) + .pop() + .unwrap(); // at block 27 of the fork add an authority transition peer.generate_blocks_at( BlockId::Hash(hash), @@ -1786,20 +1784,23 @@ async fn revert_prunes_authority_changes() { // 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, - ); + 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, + ) + .pop() + .unwrap(); // at block 29 of the fork add an authority transition peer.generate_blocks_at( BlockId::Hash(hash), diff --git a/client/network/test/src/lib.rs b/client/network/test/src/lib.rs index c3304df629e4e..a7b963555cae4 100644 --- a/client/network/test/src/lib.rs +++ b/client/network/test/src/lib.rs @@ -297,7 +297,12 @@ where } /// Add blocks to the peer -- edit the block before adding - pub fn generate_blocks(&mut self, count: usize, origin: BlockOrigin, edit_block: F) -> H256 + pub fn generate_blocks( + &mut self, + count: usize, + origin: BlockOrigin, + edit_block: F, + ) -> Vec where F: FnMut( BlockBuilder, @@ -323,7 +328,7 @@ where origin: BlockOrigin, edit_block: F, fork_choice: ForkChoiceStrategy, - ) -> H256 + ) -> Vec where F: FnMut( BlockBuilder, @@ -354,12 +359,13 @@ where inform_sync_about_new_best_block: bool, announce_block: bool, fork_choice: ForkChoiceStrategy, - ) -> H256 + ) -> Vec where F: FnMut( BlockBuilder, ) -> Block, { + let mut hashes = Vec::with_capacity(count); let full_client = self.client.as_client(); let mut at = full_client.header(&at).unwrap().unwrap().hash(); for _ in 0..count { @@ -391,6 +397,7 @@ where if announce_block { self.network.service().announce_block(hash, None); } + hashes.push(hash); at = hash; } @@ -400,24 +407,24 @@ where *full_client.header(&BlockId::Hash(at)).ok().flatten().unwrap().number(), ); } - at + hashes } /// Push blocks to the peer (simplified: with or without a TX) - pub fn push_blocks(&mut self, count: usize, with_tx: bool) -> H256 { + pub fn push_blocks(&mut self, count: usize, with_tx: bool) -> Vec { let best_hash = self.client.info().best_hash; self.push_blocks_at(BlockId::Hash(best_hash), count, with_tx) } /// Push blocks to the peer (simplified: with or without a TX) - pub fn push_headers(&mut self, count: usize) -> H256 { + pub fn push_headers(&mut self, count: usize) -> Vec { let best_hash = self.client.info().best_hash; self.generate_tx_blocks_at(BlockId::Hash(best_hash), count, false, true, true, true) } /// Push blocks to the peer (simplified: with or without a TX) starting from /// given hash. - pub fn push_blocks_at(&mut self, at: BlockId, count: usize, with_tx: bool) -> H256 { + pub fn push_blocks_at(&mut self, at: BlockId, count: usize, with_tx: bool) -> Vec { self.generate_tx_blocks_at(at, count, with_tx, false, true, true) } @@ -429,7 +436,7 @@ where count: usize, with_tx: bool, announce_block: bool, - ) -> H256 { + ) -> Vec { self.generate_tx_blocks_at(at, count, with_tx, false, false, announce_block) } @@ -440,7 +447,7 @@ where at: BlockId, count: usize, with_tx: bool, - ) -> H256 { + ) -> Vec { self.generate_tx_blocks_at(at, count, with_tx, false, true, false) } @@ -454,7 +461,7 @@ where headers_only: bool, inform_sync_about_new_best_block: bool, announce_block: bool, - ) -> H256 { + ) -> Vec { let mut nonce = 0; if with_tx { self.generate_blocks_at( @@ -491,7 +498,10 @@ where } } - pub fn push_authorities_change_block(&mut self, new_authorities: Vec) -> H256 { + pub fn push_authorities_change_block( + &mut self, + new_authorities: Vec, + ) -> Vec { self.generate_blocks(1, BlockOrigin::File, |mut builder| { builder.push(Extrinsic::AuthoritiesChange(new_authorities.clone())).unwrap(); builder.build().unwrap().block diff --git a/client/network/test/src/sync.rs b/client/network/test/src/sync.rs index 9a9b5782dc2a7..c7b651f457a56 100644 --- a/client/network/test/src/sync.rs +++ b/client/network/test/src/sync.rs @@ -250,13 +250,12 @@ async fn sync_no_common_longer_chain_fails() { async fn sync_justifications() { sp_tracing::try_init_simple(); let mut net = JustificationTestNet::new(3); - net.peer(0).push_blocks(20, false); + let hashes = net.peer(0).push_blocks(20, false); net.run_until_sync().await; - 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 hashof10 = hashes[9]; + let hashof15 = hashes[14]; + let hashof20 = hashes[19]; // there's currently no justification for block #10 assert_eq!(net.peer(0).client().justifications(hashof10).unwrap(), None); @@ -280,13 +279,13 @@ async fn sync_justifications() { futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); - for hash in [hashof10, hashof15, hashof20] { - if net.peer(0).client().justifications(hash).unwrap() != + for height in (10..21).step_by(5) { + if net.peer(0).client().justifications(hashes[height - 1]).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(hashes[height - 1]).unwrap() != Some(Justifications::from((*b"FRNK", Vec::new()))) { return Poll::Pending @@ -305,8 +304,8 @@ async fn sync_justifications_across_forks() { // we push 5 blocks net.peer(0).push_blocks(5, false); // and then two forks 5 and 6 blocks long - let f1_best = net.peer(0).push_blocks_at(BlockId::Number(5), 5, false); - let f2_best = net.peer(0).push_blocks_at(BlockId::Number(5), 6, false); + let f1_best = net.peer(0).push_blocks_at(BlockId::Number(5), 5, false).pop().unwrap(); + let f2_best = net.peer(0).push_blocks_at(BlockId::Number(5), 6, false).pop().unwrap(); // peer 1 will only see the longer fork. but we'll request justifications // for both and finalize the small fork instead. @@ -364,8 +363,8 @@ async fn syncs_all_forks() { 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); + let b1 = net.peer(0).push_blocks(2, true).pop().unwrap(); + let b2 = net.peer(1).push_blocks(4, false).pop().unwrap(); net.run_until_sync().await; // Check that all peers have all of the branches. @@ -446,7 +445,7 @@ async fn can_sync_small_non_best_forks() { .await; net.run_until_sync().await; - let another_fork = net.peer(0).push_blocks_at(BlockId::Number(35), 2, true); + let another_fork = net.peer(0).push_blocks_at(BlockId::Number(35), 2, true).pop().unwrap(); net.peer(0).announce_block(another_fork, None); futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); @@ -467,12 +466,16 @@ async fn can_sync_forks_ahead_of_the_best_chain() { net.run_until_connected().await; // Peer 0 is on 2-block fork which is announced with is_best=false - let fork_hash = net.peer(0).generate_blocks_with_fork_choice( - 2, - BlockOrigin::Own, - |builder| builder.build().unwrap().block, - ForkChoiceStrategy::Custom(false), - ); + let fork_hash = net + .peer(0) + .generate_blocks_with_fork_choice( + 2, + BlockOrigin::Own, + |builder| builder.build().unwrap().block, + ForkChoiceStrategy::Custom(false), + ) + .pop() + .unwrap(); // 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()); @@ -575,8 +578,8 @@ async fn does_not_sync_announced_old_best_block() { sp_tracing::try_init_simple(); let mut net = TestNet::new(3); - let old_hash = net.peer(0).push_blocks(1, false); - let old_hash_with_parent = net.peer(0).push_blocks(1, false); + let old_hash = net.peer(0).push_blocks(1, false).pop().unwrap(); + let old_hash_with_parent = net.peer(0).push_blocks(1, false).pop().unwrap(); net.peer(0).push_blocks(18, true); net.peer(1).push_blocks(20, true); @@ -647,12 +650,12 @@ async fn imports_stale_once() { net.run_until_sync().await; // check that NEW block is imported from announce message - let new_hash = net.peer(0).push_blocks(1, false); + let new_hash = net.peer(0).push_blocks(1, false).pop().unwrap(); import_with_announce(&mut net, new_hash).await; 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); + let known_stale_hash = net.peer(0).push_blocks_at(BlockId::Number(0), 1, true).pop().unwrap(); import_with_announce(&mut net, known_stale_hash).await; assert_eq!(net.peer(1).num_downloaded_blocks(), 2); } @@ -664,7 +667,7 @@ async fn can_sync_to_peers_with_wrong_common_block() { 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); + let fork_hash = net.peer(0).push_blocks_at(BlockId::Number(0), 2, false).pop().unwrap(); net.peer(1).push_blocks_at(BlockId::Number(0), 2, false); // wait for connection net.run_until_connected().await; @@ -673,7 +676,7 @@ async fn can_sync_to_peers_with_wrong_common_block() { 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(); - let final_hash = net.peer(0).push_blocks(1, false); + let final_hash = net.peer(0).push_blocks(1, false).pop().unwrap(); net.run_until_sync().await; @@ -731,12 +734,16 @@ async fn sync_blocks_when_block_announce_validator_says_it_is_new_best() { net.run_until_connected().await; // 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), - ); + let block_hash = net + .peer(0) + .generate_blocks_with_fork_choice( + 1, + BlockOrigin::Own, + |builder| builder.build().unwrap().block, + ForkChoiceStrategy::Custom(false), + ) + .pop() + .unwrap(); while !net.peer(2).has_block(block_hash) { net.run_until_idle().await; @@ -774,12 +781,16 @@ async fn wait_until_deferred_block_announce_validation_is_ready() { net.run_until_connected().await; // 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), - ); + let block_hash = net + .peer(0) + .generate_blocks_with_fork_choice( + 1, + BlockOrigin::Own, + |builder| builder.build().unwrap().block, + ForkChoiceStrategy::Custom(false), + ) + .pop() + .unwrap(); while !net.peer(1).has_block(block_hash) { net.run_until_idle().await; @@ -794,9 +805,11 @@ async 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, true); + let block_hash = net + .peer(0) + .push_blocks_at_without_informing_sync(BlockId::Number(0), 3, true, true) + .pop() + .unwrap(); // Add a node and wait until they are connected net.add_full_peer_with_config(Default::default()); @@ -838,9 +851,11 @@ async fn sync_to_tip_when_we_sync_together_with_multiple_peers() { let mut net = TestNet::new(3); - let block_hash = - net.peer(0) - .push_blocks_at_without_informing_sync(BlockId::Number(0), 10_000, false, false); + let block_hash = net + .peer(0) + .push_blocks_at_without_informing_sync(BlockId::Number(0), 10_000, false, false) + .pop() + .unwrap(); net.peer(1) .push_blocks_at_without_informing_sync(BlockId::Number(0), 5_000, false, false); @@ -912,7 +927,11 @@ async fn block_announce_data_is_propagated() { }) .await; - let block_hash = net.peer(0).push_blocks_at_without_announcing(BlockId::Number(0), 1, true); + let block_hash = net + .peer(0) + .push_blocks_at_without_announcing(BlockId::Number(0), 1, true) + .pop() + .unwrap(); 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) { @@ -956,7 +975,7 @@ async fn continue_to_sync_after_some_block_announcement_verifications_failed() { net.run_until_connected().await; net.run_until_idle().await; - let block_hash = net.peer(0).push_blocks(500, true); + let block_hash = net.peer(0).push_blocks(500, true).pop().unwrap(); net.run_until_sync().await; assert!(net.peer(1).has_block(block_hash)); @@ -970,10 +989,10 @@ async fn continue_to_sync_after_some_block_announcement_verifications_failed() { async fn multiple_requests_are_accepted_as_long_as_they_are_not_fulfilled() { sp_tracing::try_init_simple(); let mut net = JustificationTestNet::new(2); - net.peer(0).push_blocks(10, false); + let hashes = net.peer(0).push_blocks(10, false); net.run_until_sync().await; - let hashof10 = net.peer(1).client().header(&BlockId::Number(10)).unwrap().unwrap().hash(); + let hashof10 = hashes[9]; // there's currently no justification for block #10 assert_eq!(net.peer(0).client().justifications(hashof10).unwrap(), None); @@ -992,14 +1011,8 @@ async 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. + let hashof10 = hashes[9]; + // Finalize the 10th block and make the justification available. net.peer(0) .client() .finalize_block(hashof10, Some((*b"FRNK", Vec::new())), true) @@ -1030,7 +1043,7 @@ async fn syncs_all_forks_from_single_peer() { net.run_until_connected().await; // Peer 0 produces new blocks and announces. - let branch1 = net.peer(0).push_blocks_at(BlockId::Number(10), 2, true); + let branch1 = net.peer(0).push_blocks_at(BlockId::Number(10), 2, true).pop().unwrap(); // Wait till peer 1 starts downloading futures::future::poll_fn::<(), _>(|cx| { @@ -1043,7 +1056,7 @@ async fn syncs_all_forks_from_single_peer() { .await; // Peer 0 produces and announces another fork - let branch2 = net.peer(0).push_blocks_at(BlockId::Number(10), 2, false); + let branch2 = net.peer(0).push_blocks_at(BlockId::Number(10), 2, false).pop().unwrap(); net.run_until_sync().await; @@ -1070,7 +1083,7 @@ async fn syncs_after_missing_announcement() { // 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); + let final_block = net.peer(0).push_blocks_at(BlockId::Number(11), 1, false).pop().unwrap(); net.peer(1).push_blocks_at(BlockId::Number(10), 1, true); net.run_until_sync().await; assert!(net.peer(1).client().header(&BlockId::Hash(final_block)).unwrap().is_some()); @@ -1119,19 +1132,13 @@ async fn syncs_state() { 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); + let hashes = net.peer(0).push_blocks(64, false); // Wait for peer 1 to sync header chain. net.run_until_sync().await; assert!(!net.peer(1).client().has_state_at(&BlockId::Number(64))); let just = (*b"FRNK", Vec::new()); - let hashof60 = net - .peer(0) - .client() - .as_backend() - .blockchain() - .expect_block_hash_from_id(&BlockId::Number(60)) - .unwrap(); + let hashof60 = hashes[59]; net.peer(1).client().finalize_block(hashof60, Some(just), true).unwrap(); // Wait for state sync. futures::future::poll_fn::<(), _>(|cx| { @@ -1222,8 +1229,8 @@ async fn warp_sync() { sync_mode: SyncMode::Warp, ..Default::default() }); - let gap_end = net.peer(0).push_blocks(63, false); - let target = net.peer(0).push_blocks(1, false); + let gap_end = net.peer(0).push_blocks(63, false).pop().unwrap(); + let target = net.peer(0).push_blocks(1, false).pop().unwrap(); net.peer(1).push_blocks(64, false); net.peer(2).push_blocks(64, false); // Wait for peer 1 to sync state. From cad470b6b68d6d2c79371dd67d2f915b37ab8304 Mon Sep 17 00:00:00 2001 From: Liu-Cheng Xu Date: Mon, 19 Dec 2022 22:26:31 +0800 Subject: [PATCH 207/715] Support custom genesis block (#12291) * Set genesis block data using the built genesis block * Make resolve_state_version_from_wasm a separate function and some small refactorings Useful for the commit following. * Introduce trait BuildGenesisBlock Substrate users can use this trait to implement their custom genesis block when constructing the client. * Make call_executor test compile * cargo +nightly fmt --all * Fix test * Remove unnecessary clone * FMT * Apply review suggestions * Revert changes to new_full_client() and new_full_parts() signature * Remove needless `Block` type in `resolve_state_version_from_wasm` --- bin/node/testing/src/bench.rs | 30 ++++-- client/service/src/builder.rs | 59 +++++++---- client/service/src/client/call_executor.rs | 33 +++--- client/service/src/client/client.rs | 118 +++++++++++---------- client/service/src/client/genesis.rs | 67 +++++++++++- client/service/src/client/mod.rs | 2 +- client/service/src/config.rs | 17 +++ client/service/src/lib.rs | 5 +- client/service/test/src/client/mod.rs | 19 +++- test-utils/client/src/lib.rs | 24 +++-- 10 files changed, 261 insertions(+), 113 deletions(-) diff --git a/bin/node/testing/src/bench.rs b/bin/node/testing/src/bench.rs index 59f1fa94c9b20..2151a61a6ca7a 100644 --- a/bin/node/testing/src/bench.rs +++ b/bin/node/testing/src/bench.rs @@ -397,24 +397,34 @@ impl BenchDb { let task_executor = TaskExecutor::new(); let backend = sc_service::new_db_backend(db_config).expect("Should not fail"); + let executor = NativeElseWasmExecutor::new( + WasmExecutionMethod::Compiled { + instantiation_strategy: WasmtimeInstantiationStrategy::PoolingCopyOnWrite, + }, + None, + 8, + 2, + ); + let client_config = sc_service::ClientConfig::default(); + let genesis_block_builder = sc_service::GenesisBlockBuilder::new( + &keyring.generate_genesis(), + !client_config.no_genesis, + backend.clone(), + executor.clone(), + ) + .expect("Failed to create genesis block builder"); + let client = sc_service::new_client( backend.clone(), - NativeElseWasmExecutor::new( - WasmExecutionMethod::Compiled { - instantiation_strategy: WasmtimeInstantiationStrategy::PoolingCopyOnWrite, - }, - None, - 8, - 2, - ), - &keyring.generate_genesis(), + executor, + genesis_block_builder, None, None, ExecutionExtensions::new(profile.into_execution_strategies(), None, None), Box::new(task_executor.clone()), None, None, - Default::default(), + client_config, ) .expect("Should not fail"); diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index 7153672030d6a..1c8f4c7de717d 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -22,7 +22,8 @@ use crate::{ config::{Configuration, KeystoreConfig, PrometheusConfig}, error::Error, metrics::MetricsService, - start_rpc_servers, RpcHandlers, SpawnTaskHandle, TaskManager, TransactionPoolAdapter, + start_rpc_servers, BuildGenesisBlock, GenesisBlockBuilder, RpcHandlers, SpawnTaskHandle, + TaskManager, TransactionPoolAdapter, }; use futures::{channel::oneshot, future::ready, FutureExt, StreamExt}; use jsonrpsee::RpcModule; @@ -72,7 +73,6 @@ use sp_keystore::{CryptoStore, SyncCryptoStore, SyncCryptoStorePtr}; use sp_runtime::{ generic::BlockId, traits::{Block as BlockT, BlockIdTo, NumberFor, Zero}, - BuildStorage, }; use std::{str::FromStr, sync::Arc, time::SystemTime}; @@ -182,7 +182,7 @@ where new_full_parts(config, telemetry, executor).map(|parts| parts.0) } -/// Create the initial parts of a full node. +/// Create the initial parts of a full node with the default genesis block builder. pub fn new_full_parts( config: &Configuration, telemetry: Option, @@ -191,6 +191,34 @@ pub fn new_full_parts( where TBl: BlockT, TExec: CodeExecutor + RuntimeVersionOf + Clone, +{ + let backend = new_db_backend(config.db_config())?; + + let genesis_block_builder = GenesisBlockBuilder::new( + config.chain_spec.as_storage_builder(), + !config.no_genesis(), + backend.clone(), + executor.clone(), + )?; + + new_full_parts_with_genesis_builder(config, telemetry, executor, backend, genesis_block_builder) +} + +/// Create the initial parts of a full node. +pub fn new_full_parts_with_genesis_builder( + config: &Configuration, + telemetry: Option, + executor: TExec, + backend: Arc>, + genesis_block_builder: TBuildGenesisBlock, +) -> Result, Error> +where + TBl: BlockT, + TExec: CodeExecutor + RuntimeVersionOf + Clone, + TBuildGenesisBlock: BuildGenesisBlock< + TBl, + BlockImportOperation = as sc_client_api::backend::Backend>::BlockImportOperation + >, { let keystore_container = KeystoreContainer::new(&config.keystore)?; @@ -208,16 +236,7 @@ where .cloned() .unwrap_or_default(); - let (client, backend) = { - let db_config = sc_client_db::DatabaseSettings { - trie_cache_maximum_size: config.trie_cache_maximum_size, - state_pruning: config.state_pruning.clone(), - source: config.database.clone(), - blocks_pruning: config.blocks_pruning, - }; - - let backend = new_db_backend(db_config)?; - + let client = { let extensions = sc_client_api::execution_extensions::ExecutionExtensions::new( config.execution_strategies.clone(), Some(keystore_container.sync_keystore()), @@ -244,7 +263,7 @@ where let client = new_client( backend.clone(), executor, - chain_spec.as_storage_builder(), + genesis_block_builder, fork_blocks, bad_blocks, extensions, @@ -263,7 +282,7 @@ where }, )?; - (client, backend) + client }; Ok((client, backend, keystore_container, task_manager)) @@ -282,10 +301,10 @@ where } /// Create an instance of client backed by given backend. -pub fn new_client( +pub fn new_client( backend: Arc>, executor: E, - genesis_storage: &dyn BuildStorage, + genesis_block_builder: G, fork_blocks: ForkBlocks, bad_blocks: BadBlocks, execution_extensions: ExecutionExtensions, @@ -305,6 +324,10 @@ pub fn new_client( where Block: BlockT, E: CodeExecutor + RuntimeVersionOf, + G: BuildGenesisBlock< + Block, + BlockImportOperation = as sc_client_api::backend::Backend>::BlockImportOperation + >, { let executor = crate::client::LocalCallExecutor::new( backend.clone(), @@ -316,7 +339,7 @@ where crate::client::Client::new( backend, executor, - genesis_storage, + genesis_block_builder, fork_blocks, bad_blocks, prometheus_registry, diff --git a/client/service/src/client/call_executor.rs b/client/service/src/client/call_executor.rs index fcece49b5f228..bf7e8b3a6555e 100644 --- a/client/service/src/client/call_executor.rs +++ b/client/service/src/client/call_executor.rs @@ -377,24 +377,27 @@ mod tests { // LocalCallExecutor directly later on let client_config = ClientConfig::default(); - // client is used for the convenience of creating and inserting the genesis block. - let _client = substrate_test_runtime_client::client::new_with_backend::< - _, - _, - runtime::Block, - _, - runtime::RuntimeApi, - >( + let genesis_block_builder = crate::GenesisBlockBuilder::new( + &substrate_test_runtime_client::GenesisParameters::default().genesis_storage(), + !client_config.no_genesis, backend.clone(), executor.clone(), - &substrate_test_runtime_client::GenesisParameters::default().genesis_storage(), - None, - Box::new(TaskExecutor::new()), - None, - None, - Default::default(), ) - .expect("Creates a client"); + .expect("Creates genesis block builder"); + + // client is used for the convenience of creating and inserting the genesis block. + let _client = + crate::client::new_with_backend::<_, _, runtime::Block, _, runtime::RuntimeApi>( + backend.clone(), + executor.clone(), + genesis_block_builder, + None, + Box::new(TaskExecutor::new()), + None, + None, + Default::default(), + ) + .expect("Creates a client"); let call_executor = LocalCallExecutor { backend: backend.clone(), diff --git a/client/service/src/client/client.rs b/client/service/src/client/client.rs index 8ded5ec95c166..f81586d424799 100644 --- a/client/service/src/client/client.rs +++ b/client/service/src/client/client.rs @@ -20,7 +20,7 @@ use super::{ block_rules::{BlockRules, LookupResult as BlockLookupResult}, - genesis, + genesis::BuildGenesisBlock, }; use log::{info, trace, warn}; use parking_lot::{Mutex, RwLock}; @@ -70,7 +70,7 @@ use sp_runtime::{ Block as BlockT, BlockIdTo, HashFor, Header as HeaderT, NumberFor, One, SaturatedConversion, Zero, }, - BuildStorage, Digest, Justification, Justifications, StateVersion, + Digest, Justification, Justifications, StateVersion, }; use sp_state_machine::{ prove_child_read, prove_range_read_with_child_with_size, prove_read, @@ -155,9 +155,10 @@ enum PrepareStorageChangesResult, Block: BlockT> { /// Create an instance of in-memory client. #[cfg(feature = "test-helpers")] -pub fn new_in_mem( +pub fn new_in_mem( + backend: Arc>, executor: E, - genesis_storage: &S, + genesis_block_builder: G, keystore: Option, prometheus_registry: Option, telemetry: Option, @@ -168,13 +169,16 @@ pub fn new_in_mem( > where E: CodeExecutor + RuntimeVersionOf, - S: BuildStorage, Block: BlockT, + G: BuildGenesisBlock< + Block, + BlockImportOperation = as backend::Backend>::BlockImportOperation, + >, { new_with_backend( - Arc::new(in_mem::Backend::new()), + backend, executor, - genesis_storage, + genesis_block_builder, keystore, spawn_handle, prometheus_registry, @@ -214,10 +218,10 @@ impl Default for ClientConfig { /// Create a client with the explicitly provided backend. /// This is useful for testing backend implementations. #[cfg(feature = "test-helpers")] -pub fn new_with_backend( +pub fn new_with_backend( backend: Arc, executor: E, - build_genesis_storage: &S, + genesis_block_builder: G, keystore: Option, spawn_handle: Box, prometheus_registry: Option, @@ -226,7 +230,10 @@ pub fn new_with_backend( ) -> sp_blockchain::Result, Block, RA>> where E: CodeExecutor + RuntimeVersionOf, - S: BuildStorage, + G: BuildGenesisBlock< + Block, + BlockImportOperation = >::BlockImportOperation, + >, Block: BlockT, B: backend::LocalBackend + 'static, { @@ -247,7 +254,7 @@ where Client::new( backend, call_executor, - build_genesis_storage, + genesis_block_builder, Default::default(), Default::default(), prometheus_registry, @@ -347,26 +354,25 @@ where Block::Header: Clone, { /// Creates new Substrate Client with given blockchain and code executor. - pub fn new( + pub fn new( backend: Arc, executor: E, - build_genesis_storage: &dyn BuildStorage, + genesis_block_builder: G, fork_blocks: ForkBlocks, bad_blocks: BadBlocks, prometheus_registry: Option, telemetry: Option, config: ClientConfig, - ) -> sp_blockchain::Result { + ) -> sp_blockchain::Result + where + G: BuildGenesisBlock< + Block, + BlockImportOperation = >::BlockImportOperation, + >, + { let info = backend.blockchain().info(); 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, genesis_state_version)?; - let genesis_block = genesis::construct_genesis_block::(state_root); + let (genesis_block, mut op) = genesis_block_builder.build_genesis_block()?; info!( "🔨 Initializing Genesis block/state (state: {}, header-hash: {})", genesis_block.header().state_root(), @@ -379,13 +385,8 @@ where } else { NewBlockState::Normal }; - op.set_block_data( - genesis_block.deconstruct().0, - Some(vec![]), - None, - None, - block_state, - )?; + let (header, body) = genesis_block.deconstruct(); + op.set_block_data(header, Some(body), None, None, block_state)?; backend.commit_operation(op)?; } @@ -640,7 +641,7 @@ where // 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)?; + 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 @@ -1104,34 +1105,37 @@ 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(e.to_string()))?; - Ok(runtime_version.state_version()) - } else { - Err(sp_blockchain::Error::VersionInvalid( - "Runtime missing from initial storage, could not read state version.".to_string(), - )) - } +/// Return the genesis state version given the genesis storage and executor. +pub fn resolve_state_version_from_wasm( + storage: &Storage, + executor: &E, +) -> sp_blockchain::Result +where + E: RuntimeVersionOf, +{ + 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(e.to_string()))?; + Ok(runtime_version.state_version()) + } else { + Err(sp_blockchain::Error::VersionInvalid( + "Runtime missing from initial storage, could not read state version.".to_string(), + )) } } diff --git a/client/service/src/client/genesis.rs b/client/service/src/client/genesis.rs index 35fb11f04972a..54ef1182b7e7d 100644 --- a/client/service/src/client/genesis.rs +++ b/client/service/src/client/genesis.rs @@ -18,7 +18,14 @@ //! Tool for creating the genesis block. -use sp_runtime::traits::{Block as BlockT, Hash as HashT, Header as HeaderT, Zero}; +use sc_client_api::{backend::Backend, BlockImportOperation}; +use sc_executor::RuntimeVersionOf; +use sp_core::storage::Storage; +use sp_runtime::{ + traits::{Block as BlockT, Hash as HashT, Header as HeaderT, Zero}, + BuildStorage, +}; +use std::{marker::PhantomData, sync::Arc}; /// Create a genesis block, given the initial storage. pub fn construct_genesis_block(state_root: Block::Hash) -> Block { @@ -38,3 +45,61 @@ pub fn construct_genesis_block(state_root: Block::Hash) -> Block Default::default(), ) } + +/// Trait for building the genesis block. +pub trait BuildGenesisBlock { + /// The import operation used to import the genesis block into the backend. + type BlockImportOperation; + + /// Returns the built genesis block along with the block import operation + /// after setting the genesis storage. + fn build_genesis_block(self) -> sp_blockchain::Result<(Block, Self::BlockImportOperation)>; +} + +/// Default genesis block builder in Substrate. +pub struct GenesisBlockBuilder { + genesis_storage: Storage, + commit_genesis_state: bool, + backend: Arc, + executor: E, + _phantom: PhantomData, +} + +impl, E: RuntimeVersionOf> GenesisBlockBuilder { + /// Constructs a new instance of [`GenesisBlockBuilder`]. + pub fn new( + build_genesis_storage: &dyn BuildStorage, + commit_genesis_state: bool, + backend: Arc, + executor: E, + ) -> sp_blockchain::Result { + let genesis_storage = + build_genesis_storage.build_storage().map_err(sp_blockchain::Error::Storage)?; + Ok(Self { + genesis_storage, + commit_genesis_state, + backend, + executor, + _phantom: PhantomData::, + }) + } +} + +impl, E: RuntimeVersionOf> BuildGenesisBlock + for GenesisBlockBuilder +{ + type BlockImportOperation = >::BlockImportOperation; + + fn build_genesis_block(self) -> sp_blockchain::Result<(Block, Self::BlockImportOperation)> { + let Self { genesis_storage, commit_genesis_state, backend, executor, _phantom } = self; + + let genesis_state_version = + crate::resolve_state_version_from_wasm(&genesis_storage, &executor)?; + let mut op = backend.begin_operation()?; + let state_root = + op.set_genesis_state(genesis_storage, commit_genesis_state, genesis_state_version)?; + let genesis_block = construct_genesis_block::(state_root); + + Ok((genesis_block, op)) + } +} diff --git a/client/service/src/client/mod.rs b/client/service/src/client/mod.rs index eac744923d501..dafeb68831885 100644 --- a/client/service/src/client/mod.rs +++ b/client/service/src/client/mod.rs @@ -53,7 +53,7 @@ mod wasm_substitutes; pub use self::{ call_executor::LocalCallExecutor, - client::{Client, ClientConfig}, + client::{resolve_state_version_from_wasm, Client, ClientConfig}, }; #[cfg(feature = "test-helpers")] diff --git a/client/service/src/config.rs b/client/service/src/config.rs index e79ff48d6f0ff..efadb8433f63d 100644 --- a/client/service/src/config.rs +++ b/client/service/src/config.rs @@ -34,6 +34,7 @@ pub use sc_network_common::{ use prometheus_endpoint::Registry; use sc_chain_spec::ChainSpec; +use sc_network::config::SyncMode; pub use sc_telemetry::TelemetryEndpoints; pub use sc_transaction_pool::Options as TransactionPoolOptions; use sp_core::crypto::SecretString; @@ -238,6 +239,22 @@ impl Configuration { }; ProtocolId::from(protocol_id_full) } + + /// Returns true if the genesis state writting will be skipped while initializing the genesis + /// block. + pub fn no_genesis(&self) -> bool { + matches!(self.network.sync_mode, SyncMode::Fast { .. } | SyncMode::Warp { .. }) + } + + /// Returns the database config for creating the backend. + pub fn db_config(&self) -> sc_client_db::DatabaseSettings { + sc_client_db::DatabaseSettings { + trie_cache_maximum_size: self.trie_cache_maximum_size, + state_pruning: self.state_pruning.clone(), + source: self.database.clone(), + blocks_pruning: self.blocks_pruning, + } + } } /// Available RPC methods. diff --git a/client/service/src/lib.rs b/client/service/src/lib.rs index f0e3f72510c28..8b3a29ba4032a 100644 --- a/client/service/src/lib.rs +++ b/client/service/src/lib.rs @@ -57,7 +57,10 @@ pub use self::{ new_full_parts, spawn_tasks, BuildNetworkParams, KeystoreContainer, NetworkStarter, SpawnTasksParams, TFullBackend, TFullCallExecutor, TFullClient, }, - client::{ClientConfig, LocalCallExecutor}, + client::{ + genesis::{BuildGenesisBlock, GenesisBlockBuilder}, + resolve_state_version_from_wasm, ClientConfig, LocalCallExecutor, + }, error::Error, }; pub use config::{ diff --git a/client/service/test/src/client/mod.rs b/client/service/test/src/client/mod.rs index be9253d8c78e8..e0b07b39cd7e4 100644 --- a/client/service/test/src/client/mod.rs +++ b/client/service/test/src/client/mod.rs @@ -1756,17 +1756,30 @@ fn storage_keys_iter_works() { fn cleans_up_closed_notification_sinks_on_block_import() { use substrate_test_runtime_client::GenesisInit; + let backend = Arc::new(sc_client_api::in_mem::Backend::new()); + let executor = substrate_test_runtime_client::new_native_executor(); + let client_config = sc_service::ClientConfig::default(); + + let genesis_block_builder = sc_service::GenesisBlockBuilder::new( + &substrate_test_runtime_client::GenesisParameters::default().genesis_storage(), + !client_config.no_genesis, + backend.clone(), + executor.clone(), + ) + .unwrap(); + // 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::<_, Block, _, RuntimeApi>( - substrate_test_runtime_client::new_native_executor(), - &substrate_test_runtime_client::GenesisParameters::default().genesis_storage(), + backend, + executor, + genesis_block_builder, None, None, None, Box::new(TaskExecutor::new()), - Default::default(), + client_config, ) .unwrap(); diff --git a/test-utils/client/src/lib.rs b/test-utils/client/src/lib.rs index 8ee652abe2c70..5dc93da13fe74 100644 --- a/test-utils/client/src/lib.rs +++ b/test-utils/client/src/lib.rs @@ -203,7 +203,7 @@ impl ) where ExecutorDispatch: - sc_client_api::CallExecutor + sc_executor::RuntimeVersionOf + 'static, + sc_client_api::CallExecutor + sc_executor::RuntimeVersionOf + Clone + 'static, Backend: sc_client_api::backend::Backend, >::OffchainStorage: 'static, { @@ -223,19 +223,29 @@ impl storage }; + let client_config = ClientConfig { + offchain_indexing_api: self.enable_offchain_indexing_api, + no_genesis: self.no_genesis, + ..Default::default() + }; + + let genesis_block_builder = sc_service::GenesisBlockBuilder::new( + &storage, + !client_config.no_genesis, + self.backend.clone(), + executor.clone(), + ) + .expect("Creates genesis block builder"); + let client = client::Client::new( self.backend.clone(), executor, - &storage, + genesis_block_builder, self.fork_blocks, self.bad_blocks, None, None, - ClientConfig { - offchain_indexing_api: self.enable_offchain_indexing_api, - no_genesis: self.no_genesis, - ..Default::default() - }, + client_config, ) .expect("Creates new client"); From e118df551952d1aa7d85e79f04e1b8cb851b6761 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Date: Mon, 19 Dec 2022 17:38:12 +0200 Subject: [PATCH 208/715] rpc: Implement `chainHead` RPC API (#12544) * rpc/chain_head: Add event structure for serialization Signed-off-by: Alexandru Vasile * rpc/chain_head: Add tests for events Signed-off-by: Alexandru Vasile * rpc/chain_head: Add API trait for `chainHead` Signed-off-by: Alexandru Vasile * rpc/chain_head: Add RPC errors Signed-off-by: Alexandru Vasile * rpc/chain_head: Manage subscription ID tracking for pinned blocks Signed-off-by: Alexandru Vasile * rpc/chain_head: Add tests for subscription management Signed-off-by: Alexandru Vasile * rpc/chain_head: Constructor for the API Signed-off-by: Alexandru Vasile * rpc/chain_head: Placeholders for API implementation Signed-off-by: Alexandru Vasile * rpc/chain_head: Accept RPC subscription sink Signed-off-by: Alexandru Vasile * rpc/chain_head: Generate the runtime API event Signed-off-by: Alexandru Vasile * rpc/chain_head: Implement the `follow` method Signed-off-by: Alexandru Vasile * rpc/chain_head: Implement the `body` method Signed-off-by: Alexandru Vasile * rpc/chain_head: Implement the `header` method Signed-off-by: Alexandru Vasile * rpc/chain_head: Implement the `storage` method Signed-off-by: Alexandru Vasile * rpc/chain_head: Implement the `call` method Signed-off-by: Alexandru Vasile * rpc/chain_head: Implement the `unpin` method Signed-off-by: Alexandru Vasile * Update `Cargo.lock` Signed-off-by: Alexandru Vasile * rpc/chain_head: Implement `getGenesis` method Signed-off-by: Alexandru Vasile * rpc/chain_head: Fix clippy Signed-off-by: Alexandru Vasile * rpc/chain_head: Parse params from hex string Signed-off-by: Alexandru Vasile * rpc/chain_head: Constuct API with genesis hash Signed-off-by: Alexandru Vasile * rpc/chain_head: Add the finalized block to reported tree route Signed-off-by: Alexandru Vasile * rpc/chain_head: Export the API and events for better ergonomics Signed-off-by: Alexandru Vasile * chain_head/tests: Add test module with helper functions Signed-off-by: Alexandru Vasile * chain_head/tests: Test block events from the `follow` pubsub Signed-off-by: Alexandru Vasile * chain_head/tests: Test `genesisHash` getter Signed-off-by: Alexandru Vasile * chain_head/tests: Test `header` method Signed-off-by: Alexandru Vasile * chain_head/tests: Test `body` method Signed-off-by: Alexandru Vasile * chain_head/tests: Test calling into the runtime API Signed-off-by: Alexandru Vasile * chain_head/tests: Test runtime for the `follow` method Signed-off-by: Alexandru Vasile * chain_head/tests: Add runtime code changes for `follow` method Signed-off-by: Alexandru Vasile * rpc/chain_head: Remove space from rustdoc Signed-off-by: Alexandru Vasile * rpc/chain_head: Use the `child_key` for storage queries Signed-off-by: Alexandru Vasile * rpc/chain_head: Test `storage` method Signed-off-by: Alexandru Vasile * rpc/chain_head: Test child trie query for `storage` method Signed-off-by: Alexandru Vasile * rpc/chain_head: Event serialization typo Signed-off-by: Alexandru Vasile * rpc/chain_head: Remove subscription aliases Signed-off-by: Alexandru Vasile * rpc/chain_head: Add `NetworkConfig` parameter Signed-off-by: Alexandru Vasile * rpc/chain_head: Named parameters as camelCase if present Signed-off-by: Alexandru Vasile * rpc/chain_head: Implement From for RuntimeEvents Signed-off-by: Alexandru Vasile * rpc/chain_head: Handle pruning of the best block in finalization window Signed-off-by: Alexandru Vasile * rpc/chain_head: Generate initial block events Signed-off-by: Alexandru Vasile * chain_head/tests: Verify that initial in-memory blocks are reported Signed-off-by: Alexandru Vasile * chain_head/tests: Verify the finalized event with forks and pruned blocks Signed-off-by: Alexandru Vasile * rpc/chain_head: Fix clippy Signed-off-by: Alexandru Vasile * rpc/chain_head: Separate logic for generating initial events Signed-off-by: Alexandru Vasile * rpc/chain_head: Handle stopping a subscription ID Signed-off-by: Alexandru Vasile * rpc/chain_head: Submit events until the "Stop" event is triggered Signed-off-by: Alexandru Vasile * rpc/chain_head: Separate logic for handling new and finalized blocks Signed-off-by: Alexandru Vasile * rpc/chain_head: Extend subscription logic with subId handle Signed-off-by: Alexandru Vasile * rpc/chain_head: Adjust to the new subscription mngmt API Signed-off-by: Alexandru Vasile * rpc/chain_head: Refuse RuntimeAPI calls without the runtime flag Signed-off-by: Alexandru Vasile * chain_head/tests: Verify RuntimeAPI calls without runtime flag Signed-off-by: Alexandru Vasile * rpc/chain_head: Add best block per subscription Signed-off-by: Alexandru Vasile * rpc/chain_head: Check storage keys for prefixes Signed-off-by: Alexandru Vasile * chain_head/tests: Check storage queries with invalid prefixes Signed-off-by: Alexandru Vasile * rpc/chain_head: Allow maximum number of pinned blocks Signed-off-by: Alexandru Vasile * chain_head/tests: Test the maximum number of pinned blocks Signed-off-by: Alexandru Vasile * rpc/chain_head: Adjust to origin/master and apply clippy Signed-off-by: Alexandru Vasile * client/service: Enable the `chainHead` API Signed-off-by: Alexandru Vasile * rpc/chain_head: Stop subscription on client disconnect and add debug logs Signed-off-by: Alexandru Vasile * rpc/chain_head: Fix sending `Stop` on subscription exit Signed-off-by: Alexandru Vasile * rpc/chain_head: Check best block is descendent of latest finalized Signed-off-by: Alexandru Vasile * chain_head/tests: Report events before pruning the best block Signed-off-by: Alexandru Vasile * rpc/chain_head: Nonrecursive initial block generation Signed-off-by: Alexandru Vasile * rpc/chain_head: Generate initial events on subscription executor Signed-off-by: Alexandru Vasile * rpc/chain_head: Reduce dev-dependencies for tokio Signed-off-by: Alexandru Vasile * Apply suggestions from code review Co-authored-by: Sebastian Kunert * rpc/chain_head: Accept empty parameters Signed-off-by: Alexandru Vasile * rpc/chain_head: Use debug of `HexDisplay` for full format Signed-off-by: Alexandru Vasile * rpc/chain_head: Enable subscription ID Signed-off-by: Alexandru Vasile * rpc/chain_head: Use jsonrpsee 16.2 camelCase feature for paramaters Signed-off-by: Alexandru Vasile * rpc/chain_head: Use `NonZeroUsize` for `NetworkConfig` param Signed-off-by: Alexandru Vasile * rpc/chain_head: Rename `runtime_updates` to `has_runtime_updates` Signed-off-by: Alexandru Vasile Signed-off-by: Alexandru Vasile Co-authored-by: Sebastian Kunert --- Cargo.lock | 38 +- client/rpc-spec-v2/Cargo.toml | 13 + client/rpc-spec-v2/src/chain_head/api.rs | 137 +++ .../rpc-spec-v2/src/chain_head/chain_head.rs | 783 +++++++++++++ client/rpc-spec-v2/src/chain_head/error.rs | 74 ++ client/rpc-spec-v2/src/chain_head/event.rs | 480 ++++++++ client/rpc-spec-v2/src/chain_head/mod.rs | 40 + .../src/chain_head/subscription.rs | 284 +++++ client/rpc-spec-v2/src/chain_head/tests.rs | 1022 +++++++++++++++++ client/rpc-spec-v2/src/lib.rs | 1 + client/service/src/builder.rs | 22 +- 11 files changed, 2885 insertions(+), 9 deletions(-) create mode 100644 client/rpc-spec-v2/src/chain_head/api.rs create mode 100644 client/rpc-spec-v2/src/chain_head/chain_head.rs create mode 100644 client/rpc-spec-v2/src/chain_head/error.rs create mode 100644 client/rpc-spec-v2/src/chain_head/event.rs create mode 100644 client/rpc-spec-v2/src/chain_head/mod.rs create mode 100644 client/rpc-spec-v2/src/chain_head/subscription.rs create mode 100644 client/rpc-spec-v2/src/chain_head/tests.rs diff --git a/Cargo.lock b/Cargo.lock index c62d71348fb1d..046e5991ba762 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2503,7 +2503,7 @@ dependencies = [ "indexmap", "slab", "tokio", - "tokio-util", + "tokio-util 0.7.4", "tracing", ] @@ -2928,7 +2928,7 @@ dependencies = [ "thiserror", "tokio", "tokio-rustls", - "tokio-util", + "tokio-util 0.7.4", "tracing", "webpki-roots", ] @@ -2991,7 +2991,7 @@ dependencies = [ "soketto", "tokio", "tokio-stream", - "tokio-util", + "tokio-util 0.7.4", "tower", "tracing", ] @@ -4279,7 +4279,7 @@ dependencies = [ "substrate-rpc-client", "tempfile", "tokio", - "tokio-util", + "tokio-util 0.7.4", "try-runtime-cli", "wait-timeout", ] @@ -7774,7 +7774,7 @@ dependencies = [ "tempfile", "thiserror", "tokio", - "tokio-util", + "tokio-util 0.7.4", "unsigned-varint", "zeroize", ] @@ -8085,20 +8085,33 @@ dependencies = [ name = "sc-rpc-spec-v2" version = "0.10.0-dev" dependencies = [ + "array-bytes", + "assert_matches", "futures", + "futures-util", "hex", "jsonrpsee", + "log", "parity-scale-codec", + "parking_lot 0.12.1", + "sc-block-builder", "sc-chain-spec", + "sc-client-api", "sc-transaction-pool-api", "serde", "serde_json", "sp-api", "sp-blockchain", + "sp-consensus", "sp-core", + "sp-maybe-compressed-blob", "sp-runtime", + "sp-version", + "substrate-test-runtime", + "substrate-test-runtime-client", "thiserror", "tokio", + "tokio-stream", ] [[package]] @@ -10264,6 +10277,7 @@ dependencies = [ "futures-core", "pin-project-lite 0.2.9", "tokio", + "tokio-util 0.6.10", ] [[package]] @@ -10279,6 +10293,20 @@ dependencies = [ "tokio-stream", ] +[[package]] +name = "tokio-util" +version = "0.6.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36943ee01a6d67977dd3f84a5a1d2efeb4ada3a1ae771cadfaa535d9d9fc6507" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "log", + "pin-project-lite 0.2.9", + "tokio", +] + [[package]] name = "tokio-util" version = "0.7.4" diff --git a/client/rpc-spec-v2/Cargo.toml b/client/rpc-spec-v2/Cargo.toml index 930aeb4bd8956..f9598b3c1abc9 100644 --- a/client/rpc-spec-v2/Cargo.toml +++ b/client/rpc-spec-v2/Cargo.toml @@ -22,12 +22,25 @@ 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" } +sp-version = { version = "5.0.0", path = "../../primitives/version" } +sc-client-api = { version = "4.0.0-dev", path = "../api" } codec = { package = "parity-scale-codec", version = "3.0.0" } thiserror = "1.0" serde = "1.0" hex = "0.4" futures = "0.3.21" +parking_lot = "0.12.1" +tokio-stream = { version = "0.1", features = ["sync"] } +array-bytes = "4.1" +log = "0.4.17" +futures-util = { version = "0.3.19", default-features = false } [dev-dependencies] serde_json = "1.0" tokio = { version = "1.22.0", features = ["macros"] } +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-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } +sp-maybe-compressed-blob = { version = "4.1.0-dev", path = "../../primitives/maybe-compressed-blob" } +sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" } +assert_matches = "1.3.0" diff --git a/client/rpc-spec-v2/src/chain_head/api.rs b/client/rpc-spec-v2/src/chain_head/api.rs new file mode 100644 index 0000000000000..7e72d6d774b1b --- /dev/null +++ b/client/rpc-spec-v2/src/chain_head/api.rs @@ -0,0 +1,137 @@ +// 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 . + +#![allow(non_snake_case)] + +//! API trait of the chain head. +use crate::chain_head::event::{ChainHeadEvent, FollowEvent, NetworkConfig}; +use jsonrpsee::{core::RpcResult, proc_macros::rpc}; + +#[rpc(client, server)] +pub trait ChainHeadApi { + /// Track the state of the head of the chain: the finalized, non-finalized, and best blocks. + /// + /// # Unstable + /// + /// This method is unstable and subject to change in the future. + #[subscription( + name = "chainHead_unstable_follow", + unsubscribe = "chainHead_unstable_unfollow", + item = FollowEvent, + )] + fn chain_head_unstable_follow(&self, runtime_updates: bool); + + /// Retrieves the body (list of transactions) of a pinned block. + /// + /// This method should be seen as a complement to `chainHead_unstable_follow`, + /// allowing the JSON-RPC client to retrieve more information about a block + /// that has been reported. + /// + /// Use `archive_unstable_body` if instead you want to retrieve the body of an arbitrary block. + /// + /// # Unstable + /// + /// This method is unstable and subject to change in the future. + #[subscription( + name = "chainHead_unstable_body", + unsubscribe = "chainHead_unstable_stopBody", + item = ChainHeadEvent, + )] + fn chain_head_unstable_body( + &self, + follow_subscription: String, + hash: Hash, + network_config: Option, + ); + + /// Retrieves the header of a pinned block. + /// + /// This method should be seen as a complement to `chainHead_unstable_follow`, + /// allowing the JSON-RPC client to retrieve more information about a block + /// that has been reported. + /// + /// Use `archive_unstable_header` if instead you want to retrieve the header of an arbitrary + /// block. + /// + /// # Unstable + /// + /// This method is unstable and subject to change in the future. + #[method(name = "chainHead_unstable_header", blocking)] + fn chain_head_unstable_header( + &self, + follow_subscription: String, + hash: Hash, + ) -> RpcResult>; + + /// Get the chain's genesis hash. + /// + /// # Unstable + /// + /// This method is unstable and subject to change in the future. + #[method(name = "chainHead_unstable_genesisHash", blocking)] + fn chain_head_unstable_genesis_hash(&self) -> RpcResult; + + /// Return a storage entry at a specific block's state. + /// + /// # Unstable + /// + /// This method is unstable and subject to change in the future. + #[subscription( + name = "chainHead_unstable_storage", + unsubscribe = "chainHead_unstable_stopStorage", + item = ChainHeadEvent, + )] + fn chain_head_unstable_storage( + &self, + follow_subscription: String, + hash: Hash, + key: String, + child_key: Option, + network_config: Option, + ); + + /// Call into the Runtime API at a specified block's state. + /// + /// # Unstable + /// + /// This method is unstable and subject to change in the future. + #[subscription( + name = "chainHead_unstable_call", + unsubscribe = "chainHead_unstable_stopCall", + item = ChainHeadEvent, + )] + fn chain_head_unstable_call( + &self, + follow_subscription: String, + hash: Hash, + function: String, + call_parameters: String, + network_config: Option, + ); + + /// Unpin a block reported by the `follow` method. + /// + /// Ongoing operations that require the provided block + /// will continue normally. + /// + /// # Unstable + /// + /// This method is unstable and subject to change in the future. + #[method(name = "chainHead_unstable_unpin", blocking)] + fn chain_head_unstable_unpin(&self, follow_subscription: String, hash: Hash) -> RpcResult<()>; +} diff --git a/client/rpc-spec-v2/src/chain_head/chain_head.rs b/client/rpc-spec-v2/src/chain_head/chain_head.rs new file mode 100644 index 0000000000000..c55625e99cd45 --- /dev/null +++ b/client/rpc-spec-v2/src/chain_head/chain_head.rs @@ -0,0 +1,783 @@ +// 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 `chainHead`. + +use crate::{ + chain_head::{ + api::ChainHeadApiServer, + error::Error as ChainHeadRpcError, + event::{ + BestBlockChanged, ChainHeadEvent, ChainHeadResult, ErrorEvent, Finalized, FollowEvent, + Initialized, NetworkConfig, NewBlock, RuntimeEvent, RuntimeVersionEvent, + }, + subscription::{SubscriptionHandle, SubscriptionManagement, SubscriptionManagementError}, + }, + SubscriptionTaskExecutor, +}; +use codec::Encode; +use futures::{ + channel::oneshot, + future::FutureExt, + stream::{self, Stream, StreamExt}, +}; +use futures_util::future::Either; +use jsonrpsee::{ + core::{async_trait, RpcResult}, + types::{SubscriptionEmptyError, SubscriptionId, SubscriptionResult}, + SubscriptionSink, +}; +use log::{debug, error}; +use sc_client_api::{ + Backend, BlockBackend, BlockImportNotification, BlockchainEvents, CallExecutor, ChildInfo, + ExecutorProvider, FinalityNotification, StorageKey, StorageProvider, +}; +use serde::Serialize; +use sp_api::CallApiAt; +use sp_blockchain::{ + Backend as BlockChainBackend, Error as BlockChainError, HeaderBackend, HeaderMetadata, +}; +use sp_core::{hexdisplay::HexDisplay, storage::well_known_keys, Bytes}; +use sp_runtime::{ + generic::BlockId, + traits::{Block as BlockT, Header}, +}; +use std::{marker::PhantomData, sync::Arc}; + +/// An API for chain head RPC calls. +pub struct ChainHead { + /// Substrate client. + client: Arc, + /// Backend of the chain. + backend: Arc, + /// Executor to spawn subscriptions. + executor: SubscriptionTaskExecutor, + /// Keep track of the pinned blocks for each subscription. + subscriptions: Arc>, + /// The hexadecimal encoded hash of the genesis block. + genesis_hash: String, + /// The maximum number of pinned blocks allowed per connection. + max_pinned_blocks: usize, + /// Phantom member to pin the block type. + _phantom: PhantomData, +} + +impl ChainHead { + /// Create a new [`ChainHead`]. + pub fn new>( + client: Arc, + backend: Arc, + executor: SubscriptionTaskExecutor, + genesis_hash: GenesisHash, + max_pinned_blocks: usize, + ) -> Self { + let genesis_hash = format!("0x{:?}", HexDisplay::from(&genesis_hash.as_ref())); + + Self { + client, + backend, + executor, + subscriptions: Arc::new(SubscriptionManagement::new()), + genesis_hash, + max_pinned_blocks, + _phantom: PhantomData, + } + } + + /// Accept the subscription and return the subscription ID on success. + fn accept_subscription( + &self, + sink: &mut SubscriptionSink, + ) -> Result { + // The subscription must be accepted before it can provide a valid subscription ID. + sink.accept()?; + + let Some(sub_id) = sink.subscription_id() else { + // This can only happen if the subscription was not accepted. + return Err(SubscriptionEmptyError) + }; + + // Get the string representation for the subscription. + let sub_id = match sub_id { + SubscriptionId::Num(num) => num.to_string(), + SubscriptionId::Str(id) => id.into_owned().into(), + }; + + Ok(sub_id) + } +} + +/// Generate the initial events reported by the RPC `follow` method. +/// +/// This includes the "Initialized" event followed by the in-memory +/// blocks via "NewBlock" and the "BestBlockChanged". +fn generate_initial_events( + client: &Arc, + backend: &Arc, + handle: &SubscriptionHandle, + runtime_updates: bool, +) -> Result>, SubscriptionManagementError> +where + Block: BlockT + 'static, + Block::Header: Unpin, + BE: Backend + 'static, + Client: HeaderBackend + CallApiAt + 'static, +{ + // The initialized event is the first one sent. + let finalized_block_hash = client.info().finalized_hash; + handle.pin_block(finalized_block_hash)?; + + let finalized_block_runtime = generate_runtime_event( + &client, + runtime_updates, + &BlockId::Hash(finalized_block_hash), + None, + ); + + let initialized_event = FollowEvent::Initialized(Initialized { + finalized_block_hash, + finalized_block_runtime, + runtime_updates, + }); + + let initial_blocks = get_initial_blocks(&backend, finalized_block_hash); + let mut in_memory_blocks = Vec::with_capacity(initial_blocks.len() + 1); + + in_memory_blocks.push(initialized_event); + for (child, parent) in initial_blocks.into_iter() { + handle.pin_block(child)?; + + let new_runtime = generate_runtime_event( + &client, + runtime_updates, + &BlockId::Hash(child), + Some(&BlockId::Hash(parent)), + ); + + let event = FollowEvent::NewBlock(NewBlock { + block_hash: child, + parent_block_hash: parent, + new_runtime, + runtime_updates, + }); + + in_memory_blocks.push(event); + } + + // Generate a new best block event. + let best_block_hash = client.info().best_hash; + if best_block_hash != finalized_block_hash { + let best_block = FollowEvent::BestBlockChanged(BestBlockChanged { best_block_hash }); + in_memory_blocks.push(best_block); + }; + + Ok(in_memory_blocks) +} + +/// Parse hex-encoded string parameter as raw bytes. +/// +/// If the parsing fails, the subscription is rejected. +fn parse_hex_param( + sink: &mut SubscriptionSink, + param: String, +) -> Result, SubscriptionEmptyError> { + // Methods can accept empty parameters. + if param.is_empty() { + return Ok(Default::default()) + } + + match array_bytes::hex2bytes(¶m) { + Ok(bytes) => Ok(bytes), + Err(_) => { + let _ = sink.reject(ChainHeadRpcError::InvalidParam(param)); + Err(SubscriptionEmptyError) + }, + } +} + +/// Conditionally generate the runtime event of the given block. +fn generate_runtime_event( + client: &Arc, + runtime_updates: bool, + block: &BlockId, + parent: Option<&BlockId>, +) -> Option +where + Block: BlockT + 'static, + Client: CallApiAt + 'static, +{ + // No runtime versions should be reported. + if !runtime_updates { + return None + } + + let block_rt = match client.runtime_version_at(block) { + Ok(rt) => rt, + Err(err) => return Some(err.into()), + }; + + let parent = match parent { + Some(parent) => parent, + // Nothing to compare against, always report. + None => return Some(RuntimeEvent::Valid(RuntimeVersionEvent { spec: block_rt })), + }; + + let parent_rt = match client.runtime_version_at(parent) { + Ok(rt) => rt, + Err(err) => return Some(err.into()), + }; + + // Report the runtime version change. + if block_rt != parent_rt { + Some(RuntimeEvent::Valid(RuntimeVersionEvent { spec: block_rt })) + } else { + None + } +} + +/// Get the in-memory blocks of the client, starting from the provided finalized hash. +/// +/// Returns a tuple of block hash with parent hash. +fn get_initial_blocks( + backend: &Arc, + parent_hash: Block::Hash, +) -> Vec<(Block::Hash, Block::Hash)> +where + Block: BlockT + 'static, + BE: Backend + 'static, +{ + let mut result = Vec::new(); + let mut next_hash = Vec::new(); + next_hash.push(parent_hash); + + while let Some(parent_hash) = next_hash.pop() { + let Ok(blocks) = backend.blockchain().children(parent_hash) else { + continue + }; + + for child_hash in blocks { + result.push((child_hash, parent_hash)); + next_hash.push(child_hash); + } + } + + result +} + +/// Submit the events from the provided stream to the RPC client +/// for as long as the `rx_stop` event was not called. +async fn submit_events( + sink: &mut SubscriptionSink, + mut stream: EventStream, + rx_stop: oneshot::Receiver<()>, +) where + EventStream: Stream + Unpin, + T: Serialize, +{ + let mut stream_item = stream.next(); + let mut stop_event = rx_stop; + + while let Either::Left((Some(event), next_stop_event)) = + futures_util::future::select(stream_item, stop_event).await + { + match sink.send(&event) { + Ok(true) => { + stream_item = stream.next(); + stop_event = next_stop_event; + }, + // Client disconnected. + Ok(false) => return, + Err(_) => { + // Failed to submit event. + break + }, + } + } + + let _ = sink.send(&FollowEvent::::Stop); +} + +/// Generate the "NewBlock" event and potentially the "BestBlockChanged" event for +/// every notification. +fn handle_import_blocks( + client: &Arc, + handle: &SubscriptionHandle, + runtime_updates: bool, + notification: BlockImportNotification, +) -> Result<(FollowEvent, Option>), SubscriptionManagementError> +where + Block: BlockT + 'static, + Client: CallApiAt + 'static, +{ + handle.pin_block(notification.hash)?; + + let new_runtime = generate_runtime_event( + &client, + runtime_updates, + &BlockId::Hash(notification.hash), + Some(&BlockId::Hash(*notification.header.parent_hash())), + ); + + // Note: `Block::Hash` will serialize to hexadecimal encoded string. + let new_block = FollowEvent::NewBlock(NewBlock { + block_hash: notification.hash, + parent_block_hash: *notification.header.parent_hash(), + new_runtime, + runtime_updates, + }); + + if !notification.is_new_best { + return Ok((new_block, None)) + } + + // If this is the new best block, then we need to generate two events. + let best_block_event = + FollowEvent::BestBlockChanged(BestBlockChanged { best_block_hash: notification.hash }); + + let mut best_block_cache = handle.best_block_write(); + match *best_block_cache { + Some(block_cache) => { + // The RPC layer has not reported this block as best before. + // Note: This handles the race with the finalized branch. + if block_cache != notification.hash { + *best_block_cache = Some(notification.hash); + Ok((new_block, Some(best_block_event))) + } else { + Ok((new_block, None)) + } + }, + None => { + *best_block_cache = Some(notification.hash); + Ok((new_block, Some(best_block_event))) + }, + } +} + +/// Generate the "Finalized" event and potentially the "BestBlockChanged" for +/// every notification. +fn handle_finalized_blocks( + client: &Arc, + handle: &SubscriptionHandle, + notification: FinalityNotification, +) -> Result<(FollowEvent, Option>), SubscriptionManagementError> +where + Block: BlockT + 'static, + Client: HeaderBackend + HeaderMetadata + 'static, +{ + let last_finalized = notification.hash; + // We might not receive all new blocks reports, also pin the block here. + handle.pin_block(last_finalized)?; + + // The tree route contains the exclusive path from the last finalized block + // to the block reported by the notification. Ensure the finalized block is + // properly reported to that path. + let mut finalized_block_hashes = notification.tree_route.iter().cloned().collect::>(); + finalized_block_hashes.push(last_finalized); + + let pruned_block_hashes: Vec<_> = notification.stale_heads.iter().cloned().collect(); + + let finalized_event = FollowEvent::Finalized(Finalized { + finalized_block_hashes, + pruned_block_hashes: pruned_block_hashes.clone(), + }); + + let mut best_block_cache = handle.best_block_write(); + match *best_block_cache { + Some(block_cache) => { + // Check if the current best block is also reported as pruned. + let reported_pruned = pruned_block_hashes.iter().find(|&&hash| hash == block_cache); + if reported_pruned.is_none() { + return Ok((finalized_event, None)) + } + + // The best block is reported as pruned. Therefore, we need to signal a new + // best block event before submitting the finalized event. + let best_block_hash = client.info().best_hash; + if best_block_hash == block_cache { + // The client doest not have any new information about the best block. + // The information from `.info()` is updated from the DB as the last + // step of the finalization and it should be up to date. Also, the + // displaced nodes (list of nodes reported) should be reported with + // an offset of 32 blocks for substrate. + // If the info is outdated, there is nothing the RPC can do for now. + error!(target: "rpc-spec-v2", "Client does not contain different best block"); + Ok((finalized_event, None)) + } else { + let ancestor = sp_blockchain::lowest_common_ancestor( + &**client, + last_finalized, + best_block_hash, + ) + .map_err(|_| { + SubscriptionManagementError::Custom("Could not find common ancestor".into()) + })?; + + // The client's best block must be a descendent of the last finalized block. + // In other words, the lowest common ancestor must be the last finalized block. + if ancestor.hash != last_finalized { + return Err(SubscriptionManagementError::Custom( + "The finalized block is not an ancestor of the best block".into(), + )) + } + + // The RPC needs to also submit a new best block changed before the + // finalized event. + *best_block_cache = Some(best_block_hash); + let best_block_event = + FollowEvent::BestBlockChanged(BestBlockChanged { best_block_hash }); + Ok((finalized_event, Some(best_block_event))) + } + }, + None => Ok((finalized_event, None)), + } +} + +#[async_trait] +impl ChainHeadApiServer for ChainHead +where + Block: BlockT + 'static, + Block::Header: Unpin, + BE: Backend + 'static, + Client: BlockBackend + + ExecutorProvider + + HeaderBackend + + HeaderMetadata + + BlockchainEvents + + CallApiAt + + StorageProvider + + 'static, +{ + fn chain_head_unstable_follow( + &self, + mut sink: SubscriptionSink, + runtime_updates: bool, + ) -> SubscriptionResult { + let sub_id = match self.accept_subscription(&mut sink) { + Ok(sub_id) => sub_id, + Err(err) => { + sink.close(ChainHeadRpcError::InvalidSubscriptionID); + return Err(err) + }, + }; + + // Keep track of the subscription. + let Some((rx_stop, sub_handle)) = self.subscriptions.insert_subscription(sub_id.clone(), runtime_updates, self.max_pinned_blocks) else { + // Inserting the subscription can only fail if the JsonRPSee + // generated a duplicate subscription ID. + debug!(target: "rpc-spec-v2", "[follow][id={:?}] Subscription already accepted", sub_id); + let _ = sink.send(&FollowEvent::::Stop); + return Ok(()) + }; + debug!(target: "rpc-spec-v2", "[follow][id={:?}] Subscription accepted", sub_id); + + let client = self.client.clone(); + let handle = sub_handle.clone(); + let subscription_id = sub_id.clone(); + + let stream_import = self + .client + .import_notification_stream() + .map(move |notification| { + match handle_import_blocks(&client, &handle, runtime_updates, notification) { + Ok((new_block, None)) => stream::iter(vec![new_block]), + Ok((new_block, Some(best_block))) => stream::iter(vec![new_block, best_block]), + Err(_) => { + debug!(target: "rpc-spec-v2", "[follow][id={:?}] Failed to handle block import notification.", subscription_id); + handle.stop(); + stream::iter(vec![]) + }, + } + }) + .flatten(); + + let client = self.client.clone(); + let handle = sub_handle.clone(); + let subscription_id = sub_id.clone(); + + let stream_finalized = self + .client + .finality_notification_stream() + .map(move |notification| { + match handle_finalized_blocks(&client, &handle, notification) { + Ok((finalized_event, None)) => stream::iter(vec![finalized_event]), + Ok((finalized_event, Some(best_block))) => + stream::iter(vec![best_block, finalized_event]), + Err(_) => { + debug!(target: "rpc-spec-v2", "[follow][id={:?}] Failed to import finalized blocks", subscription_id); + handle.stop(); + stream::iter(vec![]) + }, + } + }) + .flatten(); + + let merged = tokio_stream::StreamExt::merge(stream_import, stream_finalized); + let subscriptions = self.subscriptions.clone(); + let client = self.client.clone(); + let backend = self.backend.clone(); + let fut = async move { + let Ok(initial_events) = generate_initial_events(&client, &backend, &sub_handle, runtime_updates) else { + // Stop the subscription if we exceeded the maximum number of blocks pinned. + debug!(target: "rpc-spec-v2", "[follow][id={:?}] Exceeded max pinned blocks from initial events", sub_id); + let _ = sink.send(&FollowEvent::::Stop); + return + }; + + let stream = stream::iter(initial_events).chain(merged); + + submit_events(&mut sink, stream.boxed(), rx_stop).await; + // The client disconnected or called the unsubscribe method. + subscriptions.remove_subscription(&sub_id); + debug!(target: "rpc-spec-v2", "[follow][id={:?}] Subscription removed", sub_id); + }; + + self.executor.spawn("substrate-rpc-subscription", Some("rpc"), fut.boxed()); + Ok(()) + } + + fn chain_head_unstable_body( + &self, + mut sink: SubscriptionSink, + follow_subscription: String, + hash: Block::Hash, + _network_config: Option, + ) -> SubscriptionResult { + let client = self.client.clone(); + let subscriptions = self.subscriptions.clone(); + + let fut = async move { + let Some(handle) = subscriptions.get_subscription(&follow_subscription) else { + // Invalid invalid subscription ID. + let _ = sink.send(&ChainHeadEvent::::Disjoint); + return + }; + + // Block is not part of the subscription. + if !handle.contains_block(&hash) { + let _ = sink.reject(ChainHeadRpcError::InvalidBlock); + return + } + + let event = match client.block(&BlockId::Hash(hash)) { + Ok(Some(signed_block)) => { + let extrinsics = signed_block.block.extrinsics(); + let result = format!("0x{:?}", HexDisplay::from(&extrinsics.encode())); + ChainHeadEvent::Done(ChainHeadResult { result }) + }, + Ok(None) => { + // The block's body was pruned. This subscription ID has become invalid. + debug!(target: "rpc-spec-v2", "[body][id={:?}] Stopping subscription because hash={:?} was pruned", follow_subscription, hash); + handle.stop(); + ChainHeadEvent::::Disjoint + }, + Err(error) => ChainHeadEvent::Error(ErrorEvent { error: error.to_string() }), + }; + let _ = sink.send(&event); + }; + + self.executor.spawn("substrate-rpc-subscription", Some("rpc"), fut.boxed()); + Ok(()) + } + + fn chain_head_unstable_header( + &self, + follow_subscription: String, + hash: Block::Hash, + ) -> RpcResult> { + let Some(handle) = self.subscriptions.get_subscription(&follow_subscription) else { + // Invalid invalid subscription ID. + return Ok(None) + }; + + // Block is not part of the subscription. + if !handle.contains_block(&hash) { + return Err(ChainHeadRpcError::InvalidBlock.into()) + } + + self.client + .header(BlockId::Hash(hash)) + .map(|opt_header| opt_header.map(|h| format!("0x{:?}", HexDisplay::from(&h.encode())))) + .map_err(ChainHeadRpcError::FetchBlockHeader) + .map_err(Into::into) + } + + fn chain_head_unstable_genesis_hash(&self) -> RpcResult { + Ok(self.genesis_hash.clone()) + } + + fn chain_head_unstable_storage( + &self, + mut sink: SubscriptionSink, + follow_subscription: String, + hash: Block::Hash, + key: String, + child_key: Option, + _network_config: Option, + ) -> SubscriptionResult { + let key = StorageKey(parse_hex_param(&mut sink, key)?); + + let child_key = child_key + .map(|child_key| parse_hex_param(&mut sink, child_key)) + .transpose()? + .map(ChildInfo::new_default_from_vec); + + let client = self.client.clone(); + let subscriptions = self.subscriptions.clone(); + + let fut = async move { + let Some(handle) = subscriptions.get_subscription(&follow_subscription) else { + // Invalid invalid subscription ID. + let _ = sink.send(&ChainHeadEvent::::Disjoint); + return + }; + + // Block is not part of the subscription. + if !handle.contains_block(&hash) { + let _ = sink.reject(ChainHeadRpcError::InvalidBlock); + return + } + + // The child key is provided, use the key to query the child trie. + if let Some(child_key) = child_key { + // The child key must not be prefixed with ":child_storage:" nor + // ":child_storage:default:". + if well_known_keys::is_default_child_storage_key(child_key.storage_key()) || + well_known_keys::is_child_storage_key(child_key.storage_key()) + { + let _ = sink + .send(&ChainHeadEvent::Done(ChainHeadResult { result: None:: })); + return + } + + let res = client + .child_storage(hash, &child_key, &key) + .map(|result| { + let result = + result.map(|storage| format!("0x{:?}", HexDisplay::from(&storage.0))); + ChainHeadEvent::Done(ChainHeadResult { result }) + }) + .unwrap_or_else(|error| { + ChainHeadEvent::Error(ErrorEvent { error: error.to_string() }) + }); + let _ = sink.send(&res); + return + } + + // The main key must not be prefixed with b":child_storage:" nor + // b":child_storage:default:". + if well_known_keys::is_default_child_storage_key(&key.0) || + well_known_keys::is_child_storage_key(&key.0) + { + let _ = + sink.send(&ChainHeadEvent::Done(ChainHeadResult { result: None:: })); + return + } + + // Main root trie storage query. + let res = client + .storage(hash, &key) + .map(|result| { + let result = + result.map(|storage| format!("0x{:?}", HexDisplay::from(&storage.0))); + ChainHeadEvent::Done(ChainHeadResult { result }) + }) + .unwrap_or_else(|error| { + ChainHeadEvent::Error(ErrorEvent { error: error.to_string() }) + }); + let _ = sink.send(&res); + }; + + self.executor.spawn("substrate-rpc-subscription", Some("rpc"), fut.boxed()); + Ok(()) + } + + fn chain_head_unstable_call( + &self, + mut sink: SubscriptionSink, + follow_subscription: String, + hash: Block::Hash, + function: String, + call_parameters: String, + _network_config: Option, + ) -> SubscriptionResult { + let call_parameters = Bytes::from(parse_hex_param(&mut sink, call_parameters)?); + + let client = self.client.clone(); + let subscriptions = self.subscriptions.clone(); + + let fut = async move { + let Some(handle) = subscriptions.get_subscription(&follow_subscription) else { + // Invalid invalid subscription ID. + let _ = sink.send(&ChainHeadEvent::::Disjoint); + return + }; + + // Block is not part of the subscription. + if !handle.contains_block(&hash) { + let _ = sink.reject(ChainHeadRpcError::InvalidBlock); + return + } + + // Reject subscription if runtime_updates is false. + if !handle.has_runtime_updates() { + let _ = sink.reject(ChainHeadRpcError::InvalidParam( + "The runtime updates flag must be set".into(), + )); + return + } + + let res = client + .executor() + .call( + &BlockId::Hash(hash), + &function, + &call_parameters, + client.execution_extensions().strategies().other, + ) + .map(|result| { + let result = format!("0x{:?}", HexDisplay::from(&result)); + ChainHeadEvent::Done(ChainHeadResult { result }) + }) + .unwrap_or_else(|error| { + ChainHeadEvent::Error(ErrorEvent { error: error.to_string() }) + }); + + let _ = sink.send(&res); + }; + + self.executor.spawn("substrate-rpc-subscription", Some("rpc"), fut.boxed()); + Ok(()) + } + + fn chain_head_unstable_unpin( + &self, + follow_subscription: String, + hash: Block::Hash, + ) -> RpcResult<()> { + let Some(handle) = self.subscriptions.get_subscription(&follow_subscription) else { + // Invalid invalid subscription ID. + return Ok(()) + }; + + if !handle.unpin_block(&hash) { + return Err(ChainHeadRpcError::InvalidBlock.into()) + } + + Ok(()) + } +} diff --git a/client/rpc-spec-v2/src/chain_head/error.rs b/client/rpc-spec-v2/src/chain_head/error.rs new file mode 100644 index 0000000000000..92f336ed4f4e3 --- /dev/null +++ b/client/rpc-spec-v2/src/chain_head/error.rs @@ -0,0 +1,74 @@ +// 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 `chainHead` RPC module. + +use jsonrpsee::{ + core::Error as RpcError, + types::error::{CallError, ErrorObject}, +}; +use sp_blockchain::Error as BlockchainError; + +/// ChainHead RPC errors. +#[derive(Debug, thiserror::Error)] +pub enum Error { + /// The provided block hash is invalid. + #[error("Invalid block hash")] + InvalidBlock, + /// Fetch block header error. + #[error("Could not fetch block header: {0}")] + FetchBlockHeader(BlockchainError), + /// Invalid parameter provided to the RPC method. + #[error("Invalid parameter: {0}")] + InvalidParam(String), + /// Invalid subscription ID provided by the RPC server. + #[error("Invalid subscription ID")] + InvalidSubscriptionID, +} + +// Base code for all `chainHead` errors. +const BASE_ERROR: i32 = 2000; +/// The provided block hash is invalid. +const INVALID_BLOCK_ERROR: i32 = BASE_ERROR + 1; +/// Fetch block header error. +const FETCH_BLOCK_HEADER_ERROR: i32 = BASE_ERROR + 2; +/// Invalid parameter error. +const INVALID_PARAM_ERROR: i32 = BASE_ERROR + 3; +/// Invalid subscription ID. +const INVALID_SUB_ID: i32 = BASE_ERROR + 4; + +impl From for ErrorObject<'static> { + fn from(e: Error) -> Self { + let msg = e.to_string(); + + match e { + Error::InvalidBlock => ErrorObject::owned(INVALID_BLOCK_ERROR, msg, None::<()>), + Error::FetchBlockHeader(_) => + ErrorObject::owned(FETCH_BLOCK_HEADER_ERROR, msg, None::<()>), + Error::InvalidParam(_) => ErrorObject::owned(INVALID_PARAM_ERROR, msg, None::<()>), + Error::InvalidSubscriptionID => ErrorObject::owned(INVALID_SUB_ID, msg, None::<()>), + } + .into() + } +} + +impl From for RpcError { + fn from(e: Error) -> Self { + CallError::Custom(e.into()).into() + } +} diff --git a/client/rpc-spec-v2/src/chain_head/event.rs b/client/rpc-spec-v2/src/chain_head/event.rs new file mode 100644 index 0000000000000..25930cb6f9950 --- /dev/null +++ b/client/rpc-spec-v2/src/chain_head/event.rs @@ -0,0 +1,480 @@ +// 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 chain head's event returned as json compatible object. + +use serde::{ser::SerializeStruct, Deserialize, Serialize, Serializer}; +use sp_api::ApiError; +use sp_version::RuntimeVersion; +use std::num::NonZeroUsize; + +/// The network config parameter is used when a function +/// needs to request the information from its peers. +/// +/// These values can be tweaked depending on the urgency of the JSON-RPC function call. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct NetworkConfig { + /// The total number of peers from which the information is requested. + total_attempts: u64, + /// The maximum number of requests to perform in parallel. + /// + /// # Note + /// + /// A zero value is illegal. + max_parallel: NonZeroUsize, + /// The time, in milliseconds, after which a single requests towards one peer + /// is considered unsuccessful. + timeout_ms: u64, +} + +/// The operation could not be processed due to an error. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ErrorEvent { + /// Reason of the error. + pub error: String, +} + +/// The runtime specification of the current block. +/// +/// This event is generated for: +/// - the first announced block by the follow subscription +/// - blocks that suffered a change in runtime compared with their parents +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct RuntimeVersionEvent { + /// The runtime version. + pub spec: RuntimeVersion, +} + +/// The runtime event generated if the `follow` subscription +/// has set the `runtime_updates` flag. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +#[serde(tag = "type")] +pub enum RuntimeEvent { + /// The runtime version of this block. + Valid(RuntimeVersionEvent), + /// The runtime could not be obtained due to an error. + Invalid(ErrorEvent), +} + +impl From for RuntimeEvent { + fn from(err: ApiError) -> Self { + RuntimeEvent::Invalid(ErrorEvent { error: format!("Api error: {}", err) }) + } +} + +/// Contain information about the latest finalized block. +/// +/// # Note +/// +/// This is the first event generated by the `follow` subscription +/// and is submitted only once. +/// +/// If the `runtime_updates` flag is set, then this event contains +/// the `RuntimeEvent`, otherwise the `RuntimeEvent` is not present. +#[derive(Debug, Clone, PartialEq, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Initialized { + /// The hash of the latest finalized block. + pub finalized_block_hash: Hash, + /// The runtime version of the finalized block. + /// + /// # Note + /// + /// This is present only if the `runtime_updates` flag is set for + /// the `follow` subscription. + pub finalized_block_runtime: Option, + /// Privately keep track if the `finalized_block_runtime` should be + /// serialized. + #[serde(default)] + pub(crate) runtime_updates: bool, +} + +impl Serialize for Initialized { + /// Custom serialize implementation to include the `RuntimeEvent` depending + /// on the internal `runtime_updates` flag. + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + if self.runtime_updates { + let mut state = serializer.serialize_struct("Initialized", 2)?; + state.serialize_field("finalizedBlockHash", &self.finalized_block_hash)?; + state.serialize_field("finalizedBlockRuntime", &self.finalized_block_runtime)?; + state.end() + } else { + let mut state = serializer.serialize_struct("Initialized", 1)?; + state.serialize_field("finalizedBlockHash", &self.finalized_block_hash)?; + state.end() + } + } +} + +/// Indicate a new non-finalized block. +#[derive(Debug, Clone, PartialEq, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct NewBlock { + /// The hash of the new block. + pub block_hash: Hash, + /// The parent hash of the new block. + pub parent_block_hash: Hash, + /// The runtime version of the new block. + /// + /// # Note + /// + /// This is present only if the `runtime_updates` flag is set for + /// the `follow` subscription. + pub new_runtime: Option, + /// Privately keep track if the `finalized_block_runtime` should be + /// serialized. + #[serde(default)] + pub(crate) runtime_updates: bool, +} + +impl Serialize for NewBlock { + /// Custom serialize implementation to include the `RuntimeEvent` depending + /// on the internal `runtime_updates` flag. + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + if self.runtime_updates { + let mut state = serializer.serialize_struct("NewBlock", 3)?; + state.serialize_field("blockHash", &self.block_hash)?; + state.serialize_field("parentBlockHash", &self.parent_block_hash)?; + state.serialize_field("newRuntime", &self.new_runtime)?; + state.end() + } else { + let mut state = serializer.serialize_struct("NewBlock", 2)?; + state.serialize_field("blockHash", &self.block_hash)?; + state.serialize_field("parentBlockHash", &self.parent_block_hash)?; + state.end() + } + } +} + +/// Indicate the block hash of the new best block. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct BestBlockChanged { + /// The block hash of the new best block. + pub best_block_hash: Hash, +} + +/// Indicate the finalized and pruned block hashes. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Finalized { + /// Block hashes that are finalized. + pub finalized_block_hashes: Vec, + /// Block hashes that are pruned (removed). + pub pruned_block_hashes: Vec, +} + +/// The event generated by the `follow` method. +/// +/// The events are generated in the following order: +/// 1. Initialized - generated only once to signal the +/// latest finalized block +/// 2. NewBlock - a new block was added. +/// 3. BestBlockChanged - indicate that the best block +/// is now the one from this event. The block was +/// announced priorly with the `NewBlock` event. +/// 4. Finalized - State the finalized and pruned blocks. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +#[serde(tag = "event")] +pub enum FollowEvent { + /// The latest finalized block. + /// + /// This event is generated only once. + Initialized(Initialized), + /// A new non-finalized block was added. + NewBlock(NewBlock), + /// The best block of the chain. + BestBlockChanged(BestBlockChanged), + /// A list of finalized and pruned blocks. + Finalized(Finalized), + /// The subscription is dropped and no further events + /// will be generated. + Stop, +} + +/// The result of a chain head method. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ChainHeadResult { + /// Result of the method. + pub result: T, +} + +/// The event generated by the body / call / storage methods. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +#[serde(tag = "event")] +pub enum ChainHeadEvent { + /// The request completed successfully. + Done(ChainHeadResult), + /// The resources requested are inaccessible. + /// + /// Resubmitting the request later might succeed. + Inaccessible(ErrorEvent), + /// An error occurred. This is definitive. + Error(ErrorEvent), + /// The provided subscription ID is stale or invalid. + Disjoint, +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn follow_initialized_event_no_updates() { + // Runtime flag is false. + let event: FollowEvent = FollowEvent::Initialized(Initialized { + finalized_block_hash: "0x1".into(), + finalized_block_runtime: None, + runtime_updates: false, + }); + + let ser = serde_json::to_string(&event).unwrap(); + let exp = r#"{"event":"initialized","finalizedBlockHash":"0x1"}"#; + assert_eq!(ser, exp); + + let event_dec: FollowEvent = serde_json::from_str(exp).unwrap(); + assert_eq!(event_dec, event); + } + + #[test] + fn follow_initialized_event_with_updates() { + // Runtime flag is true, block runtime must always be reported for this event. + let runtime = RuntimeVersion { + spec_name: "ABC".into(), + impl_name: "Impl".into(), + spec_version: 1, + ..Default::default() + }; + + let runtime_event = RuntimeEvent::Valid(RuntimeVersionEvent { spec: runtime }); + let mut initialized = Initialized { + finalized_block_hash: "0x1".into(), + finalized_block_runtime: Some(runtime_event), + runtime_updates: true, + }; + let event: FollowEvent = FollowEvent::Initialized(initialized.clone()); + + let ser = serde_json::to_string(&event).unwrap(); + let exp = concat!( + r#"{"event":"initialized","finalizedBlockHash":"0x1","#, + r#""finalizedBlockRuntime":{"type":"valid","spec":{"specName":"ABC","implName":"Impl","authoringVersion":0,"#, + r#""specVersion":1,"implVersion":0,"apis":[],"transactionVersion":0,"stateVersion":0}}}"#, + ); + assert_eq!(ser, exp); + + let event_dec: FollowEvent = serde_json::from_str(exp).unwrap(); + // The `runtime_updates` field is used for serialization purposes. + initialized.runtime_updates = false; + assert!(matches!( + event_dec, FollowEvent::Initialized(ref dec) if dec == &initialized + )); + } + + #[test] + fn follow_new_block_event_no_updates() { + // Runtime flag is false. + let event: FollowEvent = FollowEvent::NewBlock(NewBlock { + block_hash: "0x1".into(), + parent_block_hash: "0x2".into(), + new_runtime: None, + runtime_updates: false, + }); + + let ser = serde_json::to_string(&event).unwrap(); + let exp = r#"{"event":"newBlock","blockHash":"0x1","parentBlockHash":"0x2"}"#; + assert_eq!(ser, exp); + + let event_dec: FollowEvent = serde_json::from_str(exp).unwrap(); + assert_eq!(event_dec, event); + } + + #[test] + fn follow_new_block_event_with_updates() { + // Runtime flag is true, block runtime must always be reported for this event. + let runtime = RuntimeVersion { + spec_name: "ABC".into(), + impl_name: "Impl".into(), + spec_version: 1, + ..Default::default() + }; + + let runtime_event = RuntimeEvent::Valid(RuntimeVersionEvent { spec: runtime }); + let mut new_block = NewBlock { + block_hash: "0x1".into(), + parent_block_hash: "0x2".into(), + new_runtime: Some(runtime_event), + runtime_updates: true, + }; + + let event: FollowEvent = FollowEvent::NewBlock(new_block.clone()); + + let ser = serde_json::to_string(&event).unwrap(); + let exp = concat!( + r#"{"event":"newBlock","blockHash":"0x1","parentBlockHash":"0x2","#, + r#""newRuntime":{"type":"valid","spec":{"specName":"ABC","implName":"Impl","authoringVersion":0,"#, + r#""specVersion":1,"implVersion":0,"apis":[],"transactionVersion":0,"stateVersion":0}}}"#, + ); + assert_eq!(ser, exp); + + let event_dec: FollowEvent = serde_json::from_str(exp).unwrap(); + // The `runtime_updates` field is used for serialization purposes. + new_block.runtime_updates = false; + assert!(matches!( + event_dec, FollowEvent::NewBlock(ref dec) if dec == &new_block + )); + + // Runtime flag is true, runtime didn't change compared to parent. + let mut new_block = NewBlock { + block_hash: "0x1".into(), + parent_block_hash: "0x2".into(), + new_runtime: None, + runtime_updates: true, + }; + let event: FollowEvent = FollowEvent::NewBlock(new_block.clone()); + + let ser = serde_json::to_string(&event).unwrap(); + let exp = + r#"{"event":"newBlock","blockHash":"0x1","parentBlockHash":"0x2","newRuntime":null}"#; + assert_eq!(ser, exp); + new_block.runtime_updates = false; + let event_dec: FollowEvent = serde_json::from_str(exp).unwrap(); + assert!(matches!( + event_dec, FollowEvent::NewBlock(ref dec) if dec == &new_block + )); + } + + #[test] + fn follow_best_block_changed_event() { + let event: FollowEvent = + FollowEvent::BestBlockChanged(BestBlockChanged { best_block_hash: "0x1".into() }); + + let ser = serde_json::to_string(&event).unwrap(); + let exp = r#"{"event":"bestBlockChanged","bestBlockHash":"0x1"}"#; + assert_eq!(ser, exp); + + let event_dec: FollowEvent = serde_json::from_str(exp).unwrap(); + assert_eq!(event_dec, event); + } + + #[test] + fn follow_finalized_event() { + let event: FollowEvent = FollowEvent::Finalized(Finalized { + finalized_block_hashes: vec!["0x1".into()], + pruned_block_hashes: vec!["0x2".into()], + }); + + let ser = serde_json::to_string(&event).unwrap(); + let exp = + r#"{"event":"finalized","finalizedBlockHashes":["0x1"],"prunedBlockHashes":["0x2"]}"#; + assert_eq!(ser, exp); + + let event_dec: FollowEvent = serde_json::from_str(exp).unwrap(); + assert_eq!(event_dec, event); + } + + #[test] + fn follow_stop_event() { + let event: FollowEvent = FollowEvent::Stop; + + let ser = serde_json::to_string(&event).unwrap(); + let exp = r#"{"event":"stop"}"#; + assert_eq!(ser, exp); + + let event_dec: FollowEvent = serde_json::from_str(exp).unwrap(); + assert_eq!(event_dec, event); + } + + #[test] + fn chain_head_done_event() { + let event: ChainHeadEvent = + ChainHeadEvent::Done(ChainHeadResult { result: "A".into() }); + + let ser = serde_json::to_string(&event).unwrap(); + let exp = r#"{"event":"done","result":"A"}"#; + assert_eq!(ser, exp); + + let event_dec: ChainHeadEvent = serde_json::from_str(exp).unwrap(); + assert_eq!(event_dec, event); + } + + #[test] + fn chain_head_inaccessible_event() { + let event: ChainHeadEvent = + ChainHeadEvent::Inaccessible(ErrorEvent { error: "A".into() }); + + let ser = serde_json::to_string(&event).unwrap(); + let exp = r#"{"event":"inaccessible","error":"A"}"#; + assert_eq!(ser, exp); + + let event_dec: ChainHeadEvent = serde_json::from_str(exp).unwrap(); + assert_eq!(event_dec, event); + } + + #[test] + fn chain_head_error_event() { + let event: ChainHeadEvent = ChainHeadEvent::Error(ErrorEvent { error: "A".into() }); + + let ser = serde_json::to_string(&event).unwrap(); + let exp = r#"{"event":"error","error":"A"}"#; + assert_eq!(ser, exp); + + let event_dec: ChainHeadEvent = serde_json::from_str(exp).unwrap(); + assert_eq!(event_dec, event); + } + + #[test] + fn chain_head_disjoint_event() { + let event: ChainHeadEvent = ChainHeadEvent::Disjoint; + + let ser = serde_json::to_string(&event).unwrap(); + let exp = r#"{"event":"disjoint"}"#; + assert_eq!(ser, exp); + + let event_dec: ChainHeadEvent = serde_json::from_str(exp).unwrap(); + assert_eq!(event_dec, event); + } + + #[test] + fn chain_head_network_config() { + let conf = NetworkConfig { + total_attempts: 1, + max_parallel: NonZeroUsize::new(2).expect("Non zero number; qed"), + timeout_ms: 3, + }; + + let ser = serde_json::to_string(&conf).unwrap(); + let exp = r#"{"totalAttempts":1,"maxParallel":2,"timeoutMs":3}"#; + assert_eq!(ser, exp); + + let conf_dec: NetworkConfig = serde_json::from_str(exp).unwrap(); + assert_eq!(conf_dec, conf); + } +} diff --git a/client/rpc-spec-v2/src/chain_head/mod.rs b/client/rpc-spec-v2/src/chain_head/mod.rs new file mode 100644 index 0000000000000..a25933b40f07d --- /dev/null +++ b/client/rpc-spec-v2/src/chain_head/mod.rs @@ -0,0 +1,40 @@ +// 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 head API. +//! +//! # Note +//! +//! Methods are prefixed by `chainHead`. + +#[cfg(test)] +mod tests; + +pub mod api; +pub mod chain_head; +pub mod error; +pub mod event; + +mod subscription; + +pub use api::ChainHeadApiServer; +pub use chain_head::ChainHead; +pub use event::{ + BestBlockChanged, ChainHeadEvent, ChainHeadResult, ErrorEvent, Finalized, FollowEvent, + Initialized, NetworkConfig, NewBlock, RuntimeEvent, RuntimeVersionEvent, +}; diff --git a/client/rpc-spec-v2/src/chain_head/subscription.rs b/client/rpc-spec-v2/src/chain_head/subscription.rs new file mode 100644 index 0000000000000..033db45ca755c --- /dev/null +++ b/client/rpc-spec-v2/src/chain_head/subscription.rs @@ -0,0 +1,284 @@ +// 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 . + +//! Subscription management for tracking subscription IDs to pinned blocks. + +use futures::channel::oneshot; +use parking_lot::{RwLock, RwLockWriteGuard}; +use sp_runtime::traits::Block as BlockT; +use std::{ + collections::{hash_map::Entry, HashMap, HashSet}, + sync::Arc, +}; + +/// Subscription management error. +#[derive(Debug)] +pub enum SubscriptionManagementError { + /// The block cannot be pinned into memory because + /// the subscription has exceeded the maximum number + /// of blocks pinned. + ExceededLimits, + /// Custom error. + Custom(String), +} + +/// Inner subscription data structure. +struct SubscriptionInner { + /// The `runtime_updates` parameter flag of the subscription. + runtime_updates: bool, + /// Signals the "Stop" event. + tx_stop: Option>, + /// The blocks pinned. + blocks: HashSet, + /// The maximum number of pinned blocks allowed per subscription. + max_pinned_blocks: usize, +} + +/// Manage the blocks of a specific subscription ID. +#[derive(Clone)] +pub struct SubscriptionHandle { + inner: Arc>>, + /// The best reported block by this subscription. + /// Have this as a separate variable to easily share + /// the write guard with the RPC layer. + best_block: Arc>>, +} + +impl SubscriptionHandle { + /// Construct a new [`SubscriptionHandle`]. + fn new(runtime_updates: bool, tx_stop: oneshot::Sender<()>, max_pinned_blocks: usize) -> Self { + SubscriptionHandle { + inner: Arc::new(RwLock::new(SubscriptionInner { + runtime_updates, + tx_stop: Some(tx_stop), + blocks: HashSet::new(), + max_pinned_blocks, + })), + best_block: Arc::new(RwLock::new(None)), + } + } + + /// Trigger the stop event for the current subscription. + /// + /// This can happen on internal failure (ie, the pruning deleted the block from memory) + /// or if the user exceeded the amount of available pinned blocks. + pub fn stop(&self) { + let mut inner = self.inner.write(); + + if let Some(tx_stop) = inner.tx_stop.take() { + let _ = tx_stop.send(()); + } + } + + /// Pin a new block for the current subscription ID. + /// + /// Returns whether the value was newly inserted if the block can be pinned. + /// Otherwise, returns an error if the maximum number of blocks has been exceeded. + pub fn pin_block(&self, hash: Block::Hash) -> Result { + let mut inner = self.inner.write(); + + if inner.blocks.len() == inner.max_pinned_blocks { + // We have reached the limit. However, the block can be already inserted. + if inner.blocks.contains(&hash) { + return Ok(false) + } else { + return Err(SubscriptionManagementError::ExceededLimits) + } + } + + Ok(inner.blocks.insert(hash)) + } + + /// Unpin a new block for the current subscription ID. + /// + /// Returns whether the value was present in the set. + pub fn unpin_block(&self, hash: &Block::Hash) -> bool { + let mut inner = self.inner.write(); + inner.blocks.remove(hash) + } + + /// Check if the block hash is present for the provided subscription ID. + /// + /// Returns `true` if the set contains the block. + pub fn contains_block(&self, hash: &Block::Hash) -> bool { + let inner = self.inner.read(); + inner.blocks.contains(hash) + } + + /// Get the `runtime_updates` flag of this subscription. + pub fn has_runtime_updates(&self) -> bool { + let inner = self.inner.read(); + inner.runtime_updates + } + + /// Get the write guard of the best reported block. + pub fn best_block_write(&self) -> RwLockWriteGuard<'_, Option> { + self.best_block.write() + } +} + +/// Manage block pinning / unpinning for subscription IDs. +pub struct SubscriptionManagement { + /// Manage subscription by mapping the subscription ID + /// to a set of block hashes. + inner: RwLock>>, +} + +impl SubscriptionManagement { + /// Construct a new [`SubscriptionManagement`]. + pub fn new() -> Self { + SubscriptionManagement { inner: RwLock::new(HashMap::new()) } + } + + /// Insert a new subscription ID. + /// + /// If the subscription was not previously inserted, the method returns a tuple of + /// the receiver that is triggered upon the "Stop" event and the subscription + /// handle. Otherwise, when the subscription ID was already inserted returns none. + pub fn insert_subscription( + &self, + subscription_id: String, + runtime_updates: bool, + max_pinned_blocks: usize, + ) -> Option<(oneshot::Receiver<()>, SubscriptionHandle)> { + let mut subs = self.inner.write(); + + if let Entry::Vacant(entry) = subs.entry(subscription_id) { + let (tx_stop, rx_stop) = oneshot::channel(); + let handle = + SubscriptionHandle::::new(runtime_updates, tx_stop, max_pinned_blocks); + entry.insert(handle.clone()); + Some((rx_stop, handle)) + } else { + None + } + } + + /// Remove the subscription ID with associated pinned blocks. + pub fn remove_subscription(&self, subscription_id: &String) { + let mut subs = self.inner.write(); + subs.remove(subscription_id); + } + + /// Obtain the specific subscription handle. + pub fn get_subscription(&self, subscription_id: &String) -> Option> { + let subs = self.inner.write(); + subs.get(subscription_id).and_then(|handle| Some(handle.clone())) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use sp_core::H256; + use substrate_test_runtime_client::runtime::Block; + + #[test] + fn subscription_check_id() { + let subs = SubscriptionManagement::::new(); + + let id = "abc".to_string(); + let hash = H256::random(); + + let handle = subs.get_subscription(&id); + assert!(handle.is_none()); + + let (_, handle) = subs.insert_subscription(id.clone(), false, 10).unwrap(); + assert!(!handle.contains_block(&hash)); + + subs.remove_subscription(&id); + + let handle = subs.get_subscription(&id); + assert!(handle.is_none()); + } + + #[test] + fn subscription_check_block() { + let subs = SubscriptionManagement::::new(); + + let id = "abc".to_string(); + let hash = H256::random(); + + // Check with subscription. + let (_, handle) = subs.insert_subscription(id.clone(), false, 10).unwrap(); + assert!(!handle.contains_block(&hash)); + assert!(!handle.unpin_block(&hash)); + + handle.pin_block(hash).unwrap(); + assert!(handle.contains_block(&hash)); + // Unpin an invalid block. + assert!(!handle.unpin_block(&H256::random())); + + // Unpin the valid block. + assert!(handle.unpin_block(&hash)); + assert!(!handle.contains_block(&hash)); + } + + #[test] + fn subscription_check_stop_event() { + let subs = SubscriptionManagement::::new(); + + let id = "abc".to_string(); + + // Check with subscription. + let (mut rx_stop, handle) = subs.insert_subscription(id.clone(), false, 10).unwrap(); + + // Check the stop signal was not received. + let res = rx_stop.try_recv().unwrap(); + assert!(res.is_none()); + + // Inserting a second time returns None. + let res = subs.insert_subscription(id.clone(), false, 10); + assert!(res.is_none()); + + handle.stop(); + + // Check the signal was received. + let res = rx_stop.try_recv().unwrap(); + assert!(res.is_some()); + } + + #[test] + fn subscription_check_data() { + let subs = SubscriptionManagement::::new(); + + let id = "abc".to_string(); + let (_, handle) = subs.insert_subscription(id.clone(), false, 10).unwrap(); + assert!(!handle.has_runtime_updates()); + + let id2 = "abcd".to_string(); + let (_, handle) = subs.insert_subscription(id2.clone(), true, 10).unwrap(); + assert!(handle.has_runtime_updates()); + } + + #[test] + fn subscription_check_max_pinned() { + let subs = SubscriptionManagement::::new(); + + let id = "abc".to_string(); + let hash = H256::random(); + let hash_2 = H256::random(); + let (_, handle) = subs.insert_subscription(id.clone(), false, 1).unwrap(); + + handle.pin_block(hash).unwrap(); + // The same block can be pinned multiple times. + handle.pin_block(hash).unwrap(); + // Exceeded number of pinned blocks. + handle.pin_block(hash_2).unwrap_err(); + } +} diff --git a/client/rpc-spec-v2/src/chain_head/tests.rs b/client/rpc-spec-v2/src/chain_head/tests.rs new file mode 100644 index 0000000000000..4084075f0b321 --- /dev/null +++ b/client/rpc-spec-v2/src/chain_head/tests.rs @@ -0,0 +1,1022 @@ +use super::*; +use assert_matches::assert_matches; +use codec::{Decode, Encode}; +use jsonrpsee::{ + core::{error::Error, server::rpc_module::Subscription as RpcSubscription}, + types::{error::CallError, EmptyServerParams as EmptyParams}, + RpcModule, +}; +use sc_block_builder::BlockBuilderProvider; +use sc_client_api::ChildInfo; +use sp_api::BlockId; +use sp_blockchain::HeaderBackend; +use sp_consensus::BlockOrigin; +use sp_core::{ + hexdisplay::HexDisplay, + storage::well_known_keys::{self, CODE}, + testing::TaskExecutor, +}; +use sp_version::RuntimeVersion; +use std::sync::Arc; +use substrate_test_runtime::Transfer; +use substrate_test_runtime_client::{ + prelude::*, runtime, Backend, BlockBuilderExt, Client, ClientBlockImportExt, +}; + +type Header = substrate_test_runtime_client::runtime::Header; +type Block = substrate_test_runtime_client::runtime::Block; +const MAX_PINNED_BLOCKS: usize = 32; +const CHAIN_GENESIS: [u8; 32] = [0; 32]; +const INVALID_HASH: [u8; 32] = [1; 32]; +const KEY: &[u8] = b":mock"; +const VALUE: &[u8] = b"hello world"; +const CHILD_STORAGE_KEY: &[u8] = b"child"; +const CHILD_VALUE: &[u8] = b"child value"; + +async fn get_next_event(sub: &mut RpcSubscription) -> T { + let (event, _sub_id) = tokio::time::timeout(std::time::Duration::from_secs(1), sub.next()) + .await + .unwrap() + .unwrap() + .unwrap(); + event +} + +async fn setup_api() -> ( + Arc>, + RpcModule>>, + RpcSubscription, + String, + Block, +) { + let child_info = ChildInfo::new_default(CHILD_STORAGE_KEY); + let builder = TestClientBuilder::new().add_extra_child_storage( + &child_info, + KEY.to_vec(), + CHILD_VALUE.to_vec(), + ); + let backend = builder.backend(); + let mut client = Arc::new(builder.build()); + + let api = ChainHead::new( + client.clone(), + backend, + Arc::new(TaskExecutor::default()), + CHAIN_GENESIS, + MAX_PINNED_BLOCKS, + ) + .into_rpc(); + + let mut sub = api.subscribe("chainHead_unstable_follow", [true]).await.unwrap(); + let sub_id = sub.subscription_id(); + let sub_id = serde_json::to_string(&sub_id).unwrap(); + + let block = client.new_block(Default::default()).unwrap().build().unwrap().block; + client.import(BlockOrigin::Own, block.clone()).await.unwrap(); + + // Ensure the imported block is propagated and pinned for this subscription. + assert_matches!( + get_next_event::>(&mut sub).await, + FollowEvent::Initialized(_) + ); + assert_matches!( + get_next_event::>(&mut sub).await, + FollowEvent::NewBlock(_) + ); + assert_matches!( + get_next_event::>(&mut sub).await, + FollowEvent::BestBlockChanged(_) + ); + + (client, api, sub, sub_id, block) +} + +#[tokio::test] +async fn follow_subscription_produces_blocks() { + let builder = TestClientBuilder::new(); + let backend = builder.backend(); + let mut client = Arc::new(builder.build()); + + let api = ChainHead::new( + client.clone(), + backend, + Arc::new(TaskExecutor::default()), + CHAIN_GENESIS, + MAX_PINNED_BLOCKS, + ) + .into_rpc(); + + let finalized_hash = client.info().finalized_hash; + let mut sub = api.subscribe("chainHead_unstable_follow", [false]).await.unwrap(); + + // Initialized must always be reported first. + let event: FollowEvent = get_next_event(&mut sub).await; + let expected = FollowEvent::Initialized(Initialized { + finalized_block_hash: format!("{:?}", finalized_hash), + finalized_block_runtime: None, + runtime_updates: false, + }); + assert_eq!(event, expected); + + let block = client.new_block(Default::default()).unwrap().build().unwrap().block; + + let best_hash = block.header.hash(); + client.import(BlockOrigin::Own, block.clone()).await.unwrap(); + + let event: FollowEvent = get_next_event(&mut sub).await; + let expected = FollowEvent::NewBlock(NewBlock { + block_hash: format!("{:?}", best_hash), + parent_block_hash: format!("{:?}", finalized_hash), + new_runtime: None, + runtime_updates: false, + }); + assert_eq!(event, expected); + + let event: FollowEvent = get_next_event(&mut sub).await; + let expected = FollowEvent::BestBlockChanged(BestBlockChanged { + best_block_hash: format!("{:?}", best_hash), + }); + assert_eq!(event, expected); + + client.finalize_block(best_hash, None).unwrap(); + + let event: FollowEvent = get_next_event(&mut sub).await; + let expected = FollowEvent::Finalized(Finalized { + finalized_block_hashes: vec![format!("{:?}", best_hash)], + pruned_block_hashes: vec![], + }); + assert_eq!(event, expected); +} + +#[tokio::test] +async fn follow_with_runtime() { + let builder = TestClientBuilder::new(); + let backend = builder.backend(); + let mut client = Arc::new(builder.build()); + + let api = ChainHead::new( + client.clone(), + backend, + Arc::new(TaskExecutor::default()), + CHAIN_GENESIS, + MAX_PINNED_BLOCKS, + ) + .into_rpc(); + + let finalized_hash = client.info().finalized_hash; + let mut sub = api.subscribe("chainHead_unstable_follow", [true]).await.unwrap(); + + // Initialized must always be reported first. + let event: FollowEvent = get_next_event(&mut sub).await; + + let runtime_str = "{\"specName\":\"test\",\"implName\":\"parity-test\",\"authoringVersion\":1,\ + \"specVersion\":2,\"implVersion\":2,\"apis\":[[\"0xdf6acb689907609b\",4],\ + [\"0x37e397fc7c91f5e4\",1],[\"0xd2bc9897eed08f15\",3],[\"0x40fe3ad401f8959a\",6],\ + [\"0xc6e9a76309f39b09\",1],[\"0xdd718d5cc53262d4\",1],[\"0xcbca25e39f142387\",2],\ + [\"0xf78b278be53f454c\",2],[\"0xab3c0572291feb8b\",1],[\"0xbc9d89904f5b923f\",1]],\ + \"transactionVersion\":1,\"stateVersion\":1}"; + let runtime: RuntimeVersion = serde_json::from_str(runtime_str).unwrap(); + + let finalized_block_runtime = + Some(RuntimeEvent::Valid(RuntimeVersionEvent { spec: runtime.clone() })); + // Runtime must always be reported with the first event. + let expected = FollowEvent::Initialized(Initialized { + finalized_block_hash: format!("{:?}", finalized_hash), + finalized_block_runtime, + runtime_updates: false, + }); + assert_eq!(event, expected); + + // Import a new block without runtime changes. + // The runtime field must be None in this case. + let block = client.new_block(Default::default()).unwrap().build().unwrap().block; + let best_hash = block.header.hash(); + client.import(BlockOrigin::Own, block.clone()).await.unwrap(); + + let event: FollowEvent = get_next_event(&mut sub).await; + let expected = FollowEvent::NewBlock(NewBlock { + block_hash: format!("{:?}", best_hash), + parent_block_hash: format!("{:?}", finalized_hash), + new_runtime: None, + runtime_updates: false, + }); + assert_eq!(event, expected); + + let event: FollowEvent = get_next_event(&mut sub).await; + let expected = FollowEvent::BestBlockChanged(BestBlockChanged { + best_block_hash: format!("{:?}", best_hash), + }); + assert_eq!(event, expected); + + client.finalize_block(best_hash, None).unwrap(); + + let event: FollowEvent = get_next_event(&mut sub).await; + let expected = FollowEvent::Finalized(Finalized { + finalized_block_hashes: vec![format!("{:?}", best_hash)], + pruned_block_hashes: vec![], + }); + assert_eq!(event, expected); + + let finalized_hash = best_hash; + // The `RuntimeVersion` is embedded into the WASM blob at the `runtime_version` + // section. Modify the `RuntimeVersion` and commit the changes to a new block. + // The RPC must notify the runtime event change. + let wasm = sp_maybe_compressed_blob::decompress( + runtime::wasm_binary_unwrap(), + sp_maybe_compressed_blob::CODE_BLOB_BOMB_LIMIT, + ) + .unwrap(); + // Update the runtime spec version. + let mut runtime = runtime; + runtime.spec_version += 1; + let embedded = sp_version::embed::embed_runtime_version(&wasm, runtime.clone()).unwrap(); + let wasm = sp_maybe_compressed_blob::compress( + &embedded, + sp_maybe_compressed_blob::CODE_BLOB_BOMB_LIMIT, + ) + .unwrap(); + + let mut builder = client.new_block(Default::default()).unwrap(); + builder.push_storage_change(CODE.to_vec(), Some(wasm)).unwrap(); + let block = builder.build().unwrap().block; + let best_hash = block.header.hash(); + client.import(BlockOrigin::Own, block.clone()).await.unwrap(); + + let new_runtime = Some(RuntimeEvent::Valid(RuntimeVersionEvent { spec: runtime.clone() })); + let event: FollowEvent = get_next_event(&mut sub).await; + let expected = FollowEvent::NewBlock(NewBlock { + block_hash: format!("{:?}", best_hash), + parent_block_hash: format!("{:?}", finalized_hash), + new_runtime, + runtime_updates: false, + }); + assert_eq!(event, expected); +} + +#[tokio::test] +async fn get_genesis() { + let builder = TestClientBuilder::new(); + let backend = builder.backend(); + let client = Arc::new(builder.build()); + + let api = ChainHead::new( + client.clone(), + backend, + Arc::new(TaskExecutor::default()), + CHAIN_GENESIS, + MAX_PINNED_BLOCKS, + ) + .into_rpc(); + + let genesis: String = + api.call("chainHead_unstable_genesisHash", EmptyParams::new()).await.unwrap(); + assert_eq!(genesis, format!("0x{}", HexDisplay::from(&CHAIN_GENESIS))); +} + +#[tokio::test] +async fn get_header() { + let (_client, api, _sub, sub_id, block) = setup_api().await; + let block_hash = format!("{:?}", block.header.hash()); + let invalid_hash = format!("0x{:?}", HexDisplay::from(&INVALID_HASH)); + + // Invalid subscription ID must produce no results. + let res: Option = api + .call("chainHead_unstable_header", ["invalid_sub_id", &invalid_hash]) + .await + .unwrap(); + assert!(res.is_none()); + + // Valid subscription with invalid block hash will error. + let err = api + .call::<_, serde_json::Value>("chainHead_unstable_header", [&sub_id, &invalid_hash]) + .await + .unwrap_err(); + assert_matches!(err, + Error::Call(CallError::Custom(ref err)) if err.code() == 2001 && err.message() == "Invalid block hash" + ); + + // Obtain the valid header. + let res: String = api.call("chainHead_unstable_header", [&sub_id, &block_hash]).await.unwrap(); + let bytes = array_bytes::hex2bytes(&res).unwrap(); + let header: Header = Decode::decode(&mut &bytes[..]).unwrap(); + assert_eq!(header, block.header); +} + +#[tokio::test] +async fn get_body() { + let (mut client, api, mut block_sub, sub_id, block) = setup_api().await; + let block_hash = format!("{:?}", block.header.hash()); + let invalid_hash = format!("0x{:?}", HexDisplay::from(&INVALID_HASH)); + + // Subscription ID is stale the disjoint event is emitted. + let mut sub = api + .subscribe("chainHead_unstable_body", ["invalid_sub_id", &invalid_hash]) + .await + .unwrap(); + let event: ChainHeadEvent = get_next_event(&mut sub).await; + assert_eq!(event, ChainHeadEvent::::Disjoint); + + // Valid subscription ID with invalid block hash will error. + let err = api + .subscribe("chainHead_unstable_body", [&sub_id, &invalid_hash]) + .await + .unwrap_err(); + assert_matches!(err, + Error::Call(CallError::Custom(ref err)) if err.code() == 2001 && err.message() == "Invalid block hash" + ); + + // Obtain valid the body (list of extrinsics). + let mut sub = api.subscribe("chainHead_unstable_body", [&sub_id, &block_hash]).await.unwrap(); + let event: ChainHeadEvent = get_next_event(&mut sub).await; + // Block contains no extrinsics. + assert_matches!(event, + ChainHeadEvent::Done(done) if done.result == "0x00" + ); + + // Import a block with extrinsics. + let mut builder = client.new_block(Default::default()).unwrap(); + builder + .push_transfer(runtime::Transfer { + from: AccountKeyring::Alice.into(), + to: AccountKeyring::Ferdie.into(), + amount: 42, + nonce: 0, + }) + .unwrap(); + let block = builder.build().unwrap().block; + let block_hash = format!("{:?}", block.header.hash()); + client.import(BlockOrigin::Own, block.clone()).await.unwrap(); + // Ensure the imported block is propagated and pinned for this subscription. + assert_matches!( + get_next_event::>(&mut block_sub).await, + FollowEvent::NewBlock(_) + ); + assert_matches!( + get_next_event::>(&mut block_sub).await, + FollowEvent::BestBlockChanged(_) + ); + + let mut sub = api.subscribe("chainHead_unstable_body", [&sub_id, &block_hash]).await.unwrap(); + let event: ChainHeadEvent = get_next_event(&mut sub).await; + // Hex encoded scale encoded string for the vector of extrinsics. + let expected = format!("0x{:?}", HexDisplay::from(&block.extrinsics.encode())); + assert_matches!(event, + ChainHeadEvent::Done(done) if done.result == expected + ); +} + +#[tokio::test] +async fn call_runtime() { + let (_client, api, _sub, sub_id, block) = setup_api().await; + let block_hash = format!("{:?}", block.header.hash()); + let invalid_hash = format!("0x{:?}", HexDisplay::from(&INVALID_HASH)); + + // Subscription ID is stale the disjoint event is emitted. + let mut sub = api + .subscribe( + "chainHead_unstable_call", + ["invalid_sub_id", &block_hash, "BabeApi_current_epoch", "0x00"], + ) + .await + .unwrap(); + let event: ChainHeadEvent = get_next_event(&mut sub).await; + assert_eq!(event, ChainHeadEvent::::Disjoint); + + // Valid subscription ID with invalid block hash will error. + let err = api + .subscribe( + "chainHead_unstable_call", + [&sub_id, &invalid_hash, "BabeApi_current_epoch", "0x00"], + ) + .await + .unwrap_err(); + assert_matches!(err, + Error::Call(CallError::Custom(ref err)) if err.code() == 2001 && err.message() == "Invalid block hash" + ); + + // Pass an invalid parameters that cannot be decode. + let err = api + .subscribe( + "chainHead_unstable_call", + [&sub_id, &block_hash, "BabeApi_current_epoch", "0x0"], + ) + .await + .unwrap_err(); + assert_matches!(err, + Error::Call(CallError::Custom(ref err)) if err.code() == 2003 && err.message().contains("Invalid parameter") + ); + + let alice_id = AccountKeyring::Alice.to_account_id(); + // Hex encoded scale encoded bytes representing the call parameters. + let call_parameters = format!("0x{:?}", HexDisplay::from(&alice_id.encode())); + let mut sub = api + .subscribe( + "chainHead_unstable_call", + [&sub_id, &block_hash, "AccountNonceApi_account_nonce", &call_parameters], + ) + .await + .unwrap(); + + assert_matches!( + get_next_event::>(&mut sub).await, + ChainHeadEvent::Done(done) if done.result == "0x0000000000000000" + ); + + // The `current_epoch` takes no parameters and not draining the input buffer + // will cause the execution to fail. + let mut sub = api + .subscribe( + "chainHead_unstable_call", + [&sub_id, &block_hash, "BabeApi_current_epoch", "0x00"], + ) + .await + .unwrap(); + assert_matches!( + get_next_event::>(&mut sub).await, + ChainHeadEvent::Error(event) if event.error.contains("Execution failed") + ); +} + +#[tokio::test] +async fn call_runtime_without_flag() { + let builder = TestClientBuilder::new(); + let backend = builder.backend(); + let mut client = Arc::new(builder.build()); + + let api = ChainHead::new( + client.clone(), + backend, + Arc::new(TaskExecutor::default()), + CHAIN_GENESIS, + MAX_PINNED_BLOCKS, + ) + .into_rpc(); + + let mut sub = api.subscribe("chainHead_unstable_follow", [false]).await.unwrap(); + let sub_id = sub.subscription_id(); + let sub_id = serde_json::to_string(&sub_id).unwrap(); + + let block = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block_hash = format!("{:?}", block.header.hash()); + client.import(BlockOrigin::Own, block.clone()).await.unwrap(); + + // Ensure the imported block is propagated and pinned for this subscription. + assert_matches!( + get_next_event::>(&mut sub).await, + FollowEvent::Initialized(_) + ); + assert_matches!( + get_next_event::>(&mut sub).await, + FollowEvent::NewBlock(_) + ); + assert_matches!( + get_next_event::>(&mut sub).await, + FollowEvent::BestBlockChanged(_) + ); + + // Valid runtime call on a subscription started with `runtime_updates` false. + let alice_id = AccountKeyring::Alice.to_account_id(); + let call_parameters = format!("0x{:?}", HexDisplay::from(&alice_id.encode())); + let err = api + .subscribe( + "chainHead_unstable_call", + [&sub_id, &block_hash, "AccountNonceApi_account_nonce", &call_parameters], + ) + .await + .unwrap_err(); + + assert_matches!(err, + Error::Call(CallError::Custom(ref err)) if err.code() == 2003 && err.message().contains("The runtime updates flag must be set") + ); +} + +#[tokio::test] +async fn get_storage() { + let (mut client, api, mut block_sub, sub_id, block) = setup_api().await; + let block_hash = format!("{:?}", block.header.hash()); + let invalid_hash = format!("0x{:?}", HexDisplay::from(&INVALID_HASH)); + let key = format!("0x{:?}", HexDisplay::from(&KEY)); + + // Subscription ID is stale the disjoint event is emitted. + let mut sub = api + .subscribe("chainHead_unstable_storage", ["invalid_sub_id", &invalid_hash, &key]) + .await + .unwrap(); + let event: ChainHeadEvent = get_next_event(&mut sub).await; + assert_eq!(event, ChainHeadEvent::::Disjoint); + + // Valid subscription ID with invalid block hash will error. + let err = api + .subscribe("chainHead_unstable_storage", [&sub_id, &invalid_hash, &key]) + .await + .unwrap_err(); + assert_matches!(err, + Error::Call(CallError::Custom(ref err)) if err.code() == 2001 && err.message() == "Invalid block hash" + ); + + // Valid call without storage at the key. + let mut sub = api + .subscribe("chainHead_unstable_storage", [&sub_id, &block_hash, &key]) + .await + .unwrap(); + let event: ChainHeadEvent> = get_next_event(&mut sub).await; + assert_matches!(event, ChainHeadEvent::>::Done(done) if done.result.is_none()); + + // Import a new block with storage changes. + let mut builder = client.new_block(Default::default()).unwrap(); + builder.push_storage_change(KEY.to_vec(), Some(VALUE.to_vec())).unwrap(); + let block = builder.build().unwrap().block; + let block_hash = format!("{:?}", block.header.hash()); + client.import(BlockOrigin::Own, block.clone()).await.unwrap(); + + // Ensure the imported block is propagated and pinned for this subscription. + assert_matches!( + get_next_event::>(&mut block_sub).await, + FollowEvent::NewBlock(_) + ); + assert_matches!( + get_next_event::>(&mut block_sub).await, + FollowEvent::BestBlockChanged(_) + ); + + // Valid call with storage at the key. + let expected_value = Some(format!("0x{:?}", HexDisplay::from(&VALUE))); + let mut sub = api + .subscribe("chainHead_unstable_storage", [&sub_id, &block_hash, &key]) + .await + .unwrap(); + let event: ChainHeadEvent> = get_next_event(&mut sub).await; + assert_matches!(event, ChainHeadEvent::>::Done(done) if done.result == expected_value); + + // Child value set in `setup_api`. + let child_info = format!("0x{:?}", HexDisplay::from(b"child")); + let genesis_hash = format!("{:?}", client.genesis_hash()); + let expected_value = Some(format!("0x{:?}", HexDisplay::from(&CHILD_VALUE))); + let mut sub = api + .subscribe("chainHead_unstable_storage", [&sub_id, &genesis_hash, &key, &child_info]) + .await + .unwrap(); + let event: ChainHeadEvent> = get_next_event(&mut sub).await; + assert_matches!(event, ChainHeadEvent::>::Done(done) if done.result == expected_value); +} + +#[tokio::test] +async fn get_storage_wrong_key() { + let (mut _client, api, mut _block_sub, sub_id, block) = setup_api().await; + let block_hash = format!("{:?}", block.header.hash()); + let key = format!("0x{:?}", HexDisplay::from(&KEY)); + + // Key is prefixed by CHILD_STORAGE_KEY_PREFIX. + let mut prefixed_key = well_known_keys::CHILD_STORAGE_KEY_PREFIX.to_vec(); + prefixed_key.extend_from_slice(&KEY); + let prefixed_key = format!("0x{:?}", HexDisplay::from(&prefixed_key)); + let mut sub = api + .subscribe("chainHead_unstable_storage", [&sub_id, &block_hash, &prefixed_key]) + .await + .unwrap(); + let event: ChainHeadEvent> = get_next_event(&mut sub).await; + assert_matches!(event, ChainHeadEvent::>::Done(done) if done.result.is_none()); + + // Key is prefixed by DEFAULT_CHILD_STORAGE_KEY_PREFIX. + let mut prefixed_key = well_known_keys::DEFAULT_CHILD_STORAGE_KEY_PREFIX.to_vec(); + prefixed_key.extend_from_slice(&KEY); + let prefixed_key = format!("0x{:?}", HexDisplay::from(&prefixed_key)); + let mut sub = api + .subscribe("chainHead_unstable_storage", [&sub_id, &block_hash, &prefixed_key]) + .await + .unwrap(); + let event: ChainHeadEvent> = get_next_event(&mut sub).await; + assert_matches!(event, ChainHeadEvent::>::Done(done) if done.result.is_none()); + + // Child key is prefixed by CHILD_STORAGE_KEY_PREFIX. + let mut prefixed_key = well_known_keys::CHILD_STORAGE_KEY_PREFIX.to_vec(); + prefixed_key.extend_from_slice(b"child"); + let prefixed_key = format!("0x{:?}", HexDisplay::from(&prefixed_key)); + let mut sub = api + .subscribe("chainHead_unstable_storage", [&sub_id, &block_hash, &key, &prefixed_key]) + .await + .unwrap(); + let event: ChainHeadEvent> = get_next_event(&mut sub).await; + assert_matches!(event, ChainHeadEvent::>::Done(done) if done.result.is_none()); + + // Child key is prefixed by DEFAULT_CHILD_STORAGE_KEY_PREFIX. + let mut prefixed_key = well_known_keys::DEFAULT_CHILD_STORAGE_KEY_PREFIX.to_vec(); + prefixed_key.extend_from_slice(b"child"); + let prefixed_key = format!("0x{:?}", HexDisplay::from(&prefixed_key)); + let mut sub = api + .subscribe("chainHead_unstable_storage", [&sub_id, &block_hash, &key, &prefixed_key]) + .await + .unwrap(); + let event: ChainHeadEvent> = get_next_event(&mut sub).await; + assert_matches!(event, ChainHeadEvent::>::Done(done) if done.result.is_none()); +} + +#[tokio::test] +async fn follow_generates_initial_blocks() { + let builder = TestClientBuilder::new(); + let backend = builder.backend(); + let mut client = Arc::new(builder.build()); + + let api = ChainHead::new( + client.clone(), + backend, + Arc::new(TaskExecutor::default()), + CHAIN_GENESIS, + MAX_PINNED_BLOCKS, + ) + .into_rpc(); + + let finalized_hash = client.info().finalized_hash; + + // Block tree: + // finalized -> block 1 -> block 2 -> block 4 + // -> block 1 -> block 3 + let block_1 = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block_1_hash = block_1.header.hash(); + client.import(BlockOrigin::Own, block_1.clone()).await.unwrap(); + + let block_2 = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block_2_hash = block_2.header.hash(); + client.import(BlockOrigin::Own, block_2.clone()).await.unwrap(); + + let mut block_builder = client + .new_block_at(&BlockId::Hash(block_1.header.hash()), Default::default(), false) + .unwrap(); + // This push is required as otherwise block 3 has the same hash as block 2 and won't get + // imported + block_builder + .push_transfer(Transfer { + from: AccountKeyring::Alice.into(), + to: AccountKeyring::Ferdie.into(), + amount: 41, + nonce: 0, + }) + .unwrap(); + let block_3 = block_builder.build().unwrap().block; + let block_3_hash = block_3.header.hash(); + client.import(BlockOrigin::Own, block_3.clone()).await.unwrap(); + + let mut sub = api.subscribe("chainHead_unstable_follow", [false]).await.unwrap(); + + // Initialized must always be reported first. + let event: FollowEvent = get_next_event(&mut sub).await; + let expected = FollowEvent::Initialized(Initialized { + finalized_block_hash: format!("{:?}", finalized_hash), + finalized_block_runtime: None, + runtime_updates: false, + }); + assert_eq!(event, expected); + + // Check block 1. + let event: FollowEvent = get_next_event(&mut sub).await; + let expected = FollowEvent::NewBlock(NewBlock { + block_hash: format!("{:?}", block_1_hash), + parent_block_hash: format!("{:?}", finalized_hash), + new_runtime: None, + runtime_updates: false, + }); + assert_eq!(event, expected); + + // Check block 2. + let event: FollowEvent = get_next_event(&mut sub).await; + let expected = FollowEvent::NewBlock(NewBlock { + block_hash: format!("{:?}", block_2_hash), + parent_block_hash: format!("{:?}", block_1_hash), + new_runtime: None, + runtime_updates: false, + }); + assert_eq!(event, expected); + // Check block 3. + let event: FollowEvent = get_next_event(&mut sub).await; + let expected = FollowEvent::NewBlock(NewBlock { + block_hash: format!("{:?}", block_3_hash), + parent_block_hash: format!("{:?}", block_1_hash), + new_runtime: None, + runtime_updates: false, + }); + assert_eq!(event, expected); + + let event: FollowEvent = get_next_event(&mut sub).await; + let expected = FollowEvent::BestBlockChanged(BestBlockChanged { + best_block_hash: format!("{:?}", block_2_hash), + }); + assert_eq!(event, expected); + + // Import block 4. + let block_4 = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block_4_hash = block_4.header.hash(); + client.import(BlockOrigin::Own, block_4.clone()).await.unwrap(); + + let event: FollowEvent = get_next_event(&mut sub).await; + let expected = FollowEvent::NewBlock(NewBlock { + block_hash: format!("{:?}", block_4_hash), + parent_block_hash: format!("{:?}", block_2_hash), + new_runtime: None, + runtime_updates: false, + }); + assert_eq!(event, expected); + + let event: FollowEvent = get_next_event(&mut sub).await; + let expected = FollowEvent::BestBlockChanged(BestBlockChanged { + best_block_hash: format!("{:?}", block_4_hash), + }); + assert_eq!(event, expected); + + // Check the finalized event: + // - blocks 1, 2, 4 from canonical chain are finalized + // - block 3 from the fork is pruned + client.finalize_block(block_4_hash, None).unwrap(); + + let event: FollowEvent = get_next_event(&mut sub).await; + let expected = FollowEvent::Finalized(Finalized { + finalized_block_hashes: vec![ + format!("{:?}", block_1_hash), + format!("{:?}", block_2_hash), + format!("{:?}", block_4_hash), + ], + pruned_block_hashes: vec![format!("{:?}", block_3_hash)], + }); + assert_eq!(event, expected); +} + +#[tokio::test] +async fn follow_exceeding_pinned_blocks() { + let builder = TestClientBuilder::new(); + let backend = builder.backend(); + let mut client = Arc::new(builder.build()); + + let api = ChainHead::new( + client.clone(), + backend, + Arc::new(TaskExecutor::default()), + CHAIN_GENESIS, + 2, + ) + .into_rpc(); + + let mut sub = api.subscribe("chainHead_unstable_follow", [false]).await.unwrap(); + + let block = client.new_block(Default::default()).unwrap().build().unwrap().block; + client.import(BlockOrigin::Own, block.clone()).await.unwrap(); + + // Ensure the imported block is propagated and pinned for this subscription. + assert_matches!( + get_next_event::>(&mut sub).await, + FollowEvent::Initialized(_) + ); + assert_matches!( + get_next_event::>(&mut sub).await, + FollowEvent::NewBlock(_) + ); + assert_matches!( + get_next_event::>(&mut sub).await, + FollowEvent::BestBlockChanged(_) + ); + + // Block tree: + // finalized_block -> block -> block2 + // The first 2 blocks are pinned into the subscription, but the block2 will exceed the limit (2 + // blocks). + let block2 = client.new_block(Default::default()).unwrap().build().unwrap().block; + client.import(BlockOrigin::Own, block2.clone()).await.unwrap(); + + assert_matches!(get_next_event::>(&mut sub).await, FollowEvent::Stop); + + // Subscription will not produce any more event for further blocks. + let block3 = client.new_block(Default::default()).unwrap().build().unwrap().block; + client.import(BlockOrigin::Own, block3.clone()).await.unwrap(); + + assert!(sub.next::>().await.is_none()); +} + +#[tokio::test] +async fn follow_with_unpin() { + let builder = TestClientBuilder::new(); + let backend = builder.backend(); + let mut client = Arc::new(builder.build()); + + let api = ChainHead::new( + client.clone(), + backend, + Arc::new(TaskExecutor::default()), + CHAIN_GENESIS, + 2, + ) + .into_rpc(); + + let mut sub = api.subscribe("chainHead_unstable_follow", [false]).await.unwrap(); + let sub_id = sub.subscription_id(); + let sub_id = serde_json::to_string(&sub_id).unwrap(); + + let block = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block_hash = format!("{:?}", block.header.hash()); + client.import(BlockOrigin::Own, block.clone()).await.unwrap(); + + // Ensure the imported block is propagated and pinned for this subscription. + assert_matches!( + get_next_event::>(&mut sub).await, + FollowEvent::Initialized(_) + ); + assert_matches!( + get_next_event::>(&mut sub).await, + FollowEvent::NewBlock(_) + ); + assert_matches!( + get_next_event::>(&mut sub).await, + FollowEvent::BestBlockChanged(_) + ); + + // Unpin an invalid subscription ID must return Ok(()). + let invalid_hash = format!("0x{:?}", HexDisplay::from(&INVALID_HASH)); + let _res: () = api + .call("chainHead_unstable_unpin", ["invalid_sub_id", &invalid_hash]) + .await + .unwrap(); + + // Valid subscription with invalid block hash. + let invalid_hash = format!("0x{:?}", HexDisplay::from(&INVALID_HASH)); + let err = api + .call::<_, serde_json::Value>("chainHead_unstable_unpin", [&sub_id, &invalid_hash]) + .await + .unwrap_err(); + assert_matches!(err, + Error::Call(CallError::Custom(ref err)) if err.code() == 2001 && err.message() == "Invalid block hash" + ); + + // To not exceed the number of pinned blocks, we need to unpin before the next import. + let _res: () = api.call("chainHead_unstable_unpin", [&sub_id, &block_hash]).await.unwrap(); + + // Block tree: + // finalized_block -> block -> block2 + // ^ has been unpinned + let block2 = client.new_block(Default::default()).unwrap().build().unwrap().block; + client.import(BlockOrigin::Own, block2.clone()).await.unwrap(); + + assert_matches!( + get_next_event::>(&mut sub).await, + FollowEvent::NewBlock(_) + ); + + assert_matches!( + get_next_event::>(&mut sub).await, + FollowEvent::BestBlockChanged(_) + ); + + let block3 = client.new_block(Default::default()).unwrap().build().unwrap().block; + client.import(BlockOrigin::Own, block3.clone()).await.unwrap(); + + assert_matches!(get_next_event::>(&mut sub).await, FollowEvent::Stop); + assert!(sub.next::>().await.is_none()); +} + +#[tokio::test] +async fn follow_prune_best_block() { + let builder = TestClientBuilder::new(); + let backend = builder.backend(); + let mut client = Arc::new(builder.build()); + + let api = ChainHead::new( + client.clone(), + backend, + Arc::new(TaskExecutor::default()), + CHAIN_GENESIS, + MAX_PINNED_BLOCKS, + ) + .into_rpc(); + + let finalized_hash = client.info().finalized_hash; + let mut sub = api.subscribe("chainHead_unstable_follow", [false]).await.unwrap(); + + // Initialized must always be reported first. + let event: FollowEvent = get_next_event(&mut sub).await; + let expected = FollowEvent::Initialized(Initialized { + finalized_block_hash: format!("{:?}", finalized_hash), + finalized_block_runtime: None, + runtime_updates: false, + }); + assert_eq!(event, expected); + + // Block tree: + // + // finalized -> block 1 -> block 2 + // ^^^ best block reported + // + // -> block 1 -> block 3 -> block 4 + // ^^^ finalized + // + // The block 4 is needed on the longest chain because we want the + // best block 2 to be reported as pruned. Pruning is happening at + // height (N - 1), where N is the finalized block number. + + let block_1 = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block_1_hash = block_1.header.hash(); + client.import(BlockOrigin::Own, block_1.clone()).await.unwrap(); + + let block_3 = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block_3_hash = block_3.header.hash(); + client.import(BlockOrigin::Own, block_3.clone()).await.unwrap(); + + let block_4 = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block_4_hash = block_4.header.hash(); + client.import(BlockOrigin::Own, block_4.clone()).await.unwrap(); + + // Import block 2 as best on the fork. + let mut block_builder = client + .new_block_at(&BlockId::Hash(block_1.header.hash()), Default::default(), false) + .unwrap(); + // This push is required as otherwise block 3 has the same hash as block 2 and won't get + // imported + block_builder + .push_transfer(Transfer { + from: AccountKeyring::Alice.into(), + to: AccountKeyring::Ferdie.into(), + amount: 41, + nonce: 0, + }) + .unwrap(); + let block_2 = block_builder.build().unwrap().block; + let block_2_hash = block_2.header.hash(); + client.import_as_best(BlockOrigin::Own, block_2.clone()).await.unwrap(); + + // Check block 1. + let event: FollowEvent = get_next_event(&mut sub).await; + let expected = FollowEvent::NewBlock(NewBlock { + block_hash: format!("{:?}", block_1_hash), + parent_block_hash: format!("{:?}", finalized_hash), + new_runtime: None, + runtime_updates: false, + }); + assert_eq!(event, expected); + let event: FollowEvent = get_next_event(&mut sub).await; + let expected = FollowEvent::BestBlockChanged(BestBlockChanged { + best_block_hash: format!("{:?}", block_1_hash), + }); + assert_eq!(event, expected); + + // Check block 3. + let event: FollowEvent = get_next_event(&mut sub).await; + let expected = FollowEvent::NewBlock(NewBlock { + block_hash: format!("{:?}", block_3_hash), + parent_block_hash: format!("{:?}", block_1_hash), + new_runtime: None, + runtime_updates: false, + }); + assert_eq!(event, expected); + let event: FollowEvent = get_next_event(&mut sub).await; + let expected = FollowEvent::BestBlockChanged(BestBlockChanged { + best_block_hash: format!("{:?}", block_3_hash), + }); + assert_eq!(event, expected); + + // Check block 4. + let event: FollowEvent = get_next_event(&mut sub).await; + let expected = FollowEvent::NewBlock(NewBlock { + block_hash: format!("{:?}", block_4_hash), + parent_block_hash: format!("{:?}", block_3_hash), + new_runtime: None, + runtime_updates: false, + }); + assert_eq!(event, expected); + let event: FollowEvent = get_next_event(&mut sub).await; + let expected = FollowEvent::BestBlockChanged(BestBlockChanged { + best_block_hash: format!("{:?}", block_4_hash), + }); + assert_eq!(event, expected); + + // Check block 2, that we imported as custom best. + let event: FollowEvent = get_next_event(&mut sub).await; + let expected = FollowEvent::NewBlock(NewBlock { + block_hash: format!("{:?}", block_2_hash), + parent_block_hash: format!("{:?}", block_1_hash), + new_runtime: None, + runtime_updates: false, + }); + assert_eq!(event, expected); + let event: FollowEvent = get_next_event(&mut sub).await; + let expected = FollowEvent::BestBlockChanged(BestBlockChanged { + best_block_hash: format!("{:?}", block_2_hash), + }); + assert_eq!(event, expected); + + // Finalize the block 4 from the fork. + client.finalize_block(block_4_hash, None).unwrap(); + + // Expect to report the best block changed before the finalized event. + let event: FollowEvent = get_next_event(&mut sub).await; + let expected = FollowEvent::BestBlockChanged(BestBlockChanged { + best_block_hash: format!("{:?}", block_4_hash), + }); + assert_eq!(event, expected); + + // Block 2 must be reported as pruned, even if it was the previous best. + let event: FollowEvent = get_next_event(&mut sub).await; + let expected = FollowEvent::Finalized(Finalized { + finalized_block_hashes: vec![ + format!("{:?}", block_1_hash), + format!("{:?}", block_3_hash), + format!("{:?}", block_4_hash), + ], + pruned_block_hashes: vec![format!("{:?}", block_2_hash)], + }); + assert_eq!(event, expected); +} diff --git a/client/rpc-spec-v2/src/lib.rs b/client/rpc-spec-v2/src/lib.rs index f4b9d2f95bf97..5af7e3be264dc 100644 --- a/client/rpc-spec-v2/src/lib.rs +++ b/client/rpc-spec-v2/src/lib.rs @@ -23,6 +23,7 @@ #![warn(missing_docs)] #![deny(unused_crate_dependencies)] +pub mod chain_head; pub mod chain_spec; pub mod transaction; diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index 1c8f4c7de717d..64a5f70cc0812 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -59,7 +59,7 @@ use sc_rpc::{ system::SystemApiServer, DenyUnsafe, SubscriptionTaskExecutor, }; -use sc_rpc_spec_v2::transaction::TransactionApiServer; +use sc_rpc_spec_v2::{chain_head::ChainHeadApiServer, transaction::TransactionApiServer}; use sc_telemetry::{telemetry, ConnectionMessage, Telemetry, TelemetryHandle, SUBSTRATE_INFO}; use sc_transaction_pool_api::MaintainedTransactionPool; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedSender}; @@ -549,7 +549,7 @@ where keystore.clone(), system_rpc_tx.clone(), &config, - backend.offchain_storage(), + backend.clone(), &*rpc_builder, ) }; @@ -643,7 +643,7 @@ fn gen_rpc_module( keystore: SyncCryptoStorePtr, system_rpc_tx: TracingUnboundedSender>, config: &Configuration, - offchain_storage: Option<>::OffchainStorage>, + backend: Arc, rpc_builder: &(dyn Fn(DenyUnsafe, SubscriptionTaskExecutor) -> Result, Error>), ) -> Result, Error> where @@ -698,6 +698,19 @@ where ) .into_rpc(); + // Maximum pinned blocks per connection. + // This number is large enough to consider immediate blocks, + // but it will change to facilitate adequate limits for the pinning API. + const MAX_PINNED_BLOCKS: usize = 4096; + let chain_head_v2 = sc_rpc_spec_v2::chain_head::ChainHead::new( + client.clone(), + backend.clone(), + task_executor.clone(), + client.info().genesis_hash, + MAX_PINNED_BLOCKS, + ) + .into_rpc(); + let author = sc_rpc::author::Author::new( client.clone(), transaction_pool, @@ -709,7 +722,7 @@ where let system = sc_rpc::system::System::new(system_info, system_rpc_tx, deny_unsafe).into_rpc(); - if let Some(storage) = offchain_storage { + if let Some(storage) = backend.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()))?; @@ -717,6 +730,7 @@ where // Part of the RPC v2 spec. rpc_api.merge(transaction_v2).map_err(|e| Error::Application(e.into()))?; + rpc_api.merge(chain_head_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()))?; From 8a3b2f2e0d4bcf9614dbf174ad2b24da6f9b0b44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Mon, 19 Dec 2022 19:58:25 +0100 Subject: [PATCH 209/715] ed25519: Don't panic for invalid signature (#12965) * ed25519: Don't panic for invalid signature We should not panic for an invalid signature when the `UseDalekExt` is given. * Update Cargo.toml * Update primitives/io/Cargo.toml --- Cargo.lock | 5 +++-- primitives/io/Cargo.toml | 5 +++++ primitives/io/src/lib.rs | 26 ++++++++++++++++++++++---- 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 046e5991ba762..8412781c682e3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1566,9 +1566,9 @@ dependencies = [ [[package]] name = "ed25519" -version = "1.0.3" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37c66a534cbb46ab4ea03477eae19d5c22c01da8258030280b7bd9d8433fb6ef" +checksum = "1e9c280362032ea4203659fc489832d0204ef09f247a0506f170dafcac08c369" dependencies = [ "signature", ] @@ -9181,6 +9181,7 @@ name = "sp-io" version = "7.0.0" dependencies = [ "bytes", + "ed25519", "ed25519-dalek", "futures", "libsecp256k1", diff --git a/primitives/io/Cargo.toml b/primitives/io/Cargo.toml index 57dc3604de73f..d83c82c02227b 100644 --- a/primitives/io/Cargo.toml +++ b/primitives/io/Cargo.toml @@ -31,7 +31,11 @@ futures = { version = "0.3.21", features = ["thread-pool"], 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} + +# Required for backwards compatibility reason, but only used for verifying when `UseDalekExt` is set. ed25519-dalek = { version = "1.0.1", default-features = false, optional = true } +# Force the usage of ed25519, this is being used in `ed25519-dalek`. +ed25519 = { version = "1.5.2", optional = true } [features] default = ["std"] @@ -53,6 +57,7 @@ std = [ "log", "futures", "ed25519-dalek", + "ed25519", ] with-tracing = [ diff --git a/primitives/io/src/lib.rs b/primitives/io/src/lib.rs index 600d76b3b4300..bb06c00ee2c6f 100644 --- a/primitives/io/src/lib.rs +++ b/primitives/io/src/lib.rs @@ -783,13 +783,13 @@ pub trait Crypto { { use ed25519_dalek::Verifier; - let public_key = if let Ok(vk) = ed25519_dalek::PublicKey::from_bytes(&pub_key.0) { - vk - } else { + let Ok(public_key) = ed25519_dalek::PublicKey::from_bytes(&pub_key.0) else { return false }; - let sig = ed25519_dalek::Signature::from(sig.0); + let Ok(sig) = ed25519_dalek::Signature::from_bytes(&sig.0) else { + return false + }; public_key.verify(msg, &sig).is_ok() } else { @@ -1946,4 +1946,22 @@ mod tests { assert!(crypto::ed25519_verify(&zero_ed_sig(), &Vec::new(), &zero_ed_pub())); }) } + + #[test] + fn dalek_should_not_panic_on_invalid_signature() { + let mut ext = BasicExternalities::default(); + ext.register_extension(UseDalekExt::default()); + + ext.execute_with(|| { + let mut bytes = [0u8; 64]; + // Make it invalid + bytes[63] = 0b1110_0000; + + assert!(!crypto::ed25519_verify( + &ed25519::Signature::from_raw(bytes), + &Vec::new(), + &zero_ed_pub() + )); + }); + } } From 657c808eb3d22284359a802d67fdfdbe823fbd17 Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Tue, 20 Dec 2022 10:43:31 +0100 Subject: [PATCH 210/715] `BlockId` removal: refactor: `HeaderBackend::header` (#12874) * BlockId removal: refactor: HeaderBackend::header It changes the arguments of: - `HeaderBackend::header`, - `Client::header`, - `PeersClient::header` - `ChainApi::block_header` methods from: `BlockId` to: `Block::Hash` This PR is part of BlockId::Number refactoring analysis (paritytech/substrate#11292) * non-trivial usages of haeder(block_id) refactored This may required introduction of dedicated function: header_for_block_num * fmt * fix * doc fixed * ".git/.scripts/fmt.sh" * BlockId removal: refactor: HeaderBackend::expect_header It changes the arguments of `HeaderBackend::expect_header` method from: `BlockId` to: `Block::Hash` * ".git/.scripts/fmt.sh" * readme updated * ".git/.scripts/fmt.sh" * fix Co-authored-by: parity-processbot <> --- bin/node/bench/src/construct.rs | 2 +- bin/node/cli/src/service.rs | 5 +- bin/node/inspect/src/lib.rs | 7 +- client/api/src/in_mem.rs | 10 +- .../authority-discovery/src/worker/tests.rs | 2 +- client/basic-authorship/README.md | 2 +- .../basic-authorship/src/basic_authorship.rs | 40 ++++---- client/basic-authorship/src/lib.rs | 2 +- client/beefy/src/lib.rs | 2 +- client/beefy/src/tests.rs | 3 +- client/beefy/src/worker.rs | 25 +++-- client/consensus/aura/src/lib.rs | 4 +- client/consensus/babe/src/lib.rs | 4 +- client/consensus/babe/src/tests.rs | 94 +++++++------------ client/consensus/common/src/longest_chain.rs | 7 +- .../manual-seal/src/consensus/babe.rs | 4 +- .../manual-seal/src/consensus/timestamp.rs | 7 +- client/consensus/manual-seal/src/lib.rs | 22 +++-- .../consensus/manual-seal/src/seal_block.rs | 10 +- client/db/src/lib.rs | 92 +++++++++--------- client/finality-grandpa/src/environment.rs | 8 +- client/finality-grandpa/src/finality_proof.rs | 3 +- client/finality-grandpa/src/import.rs | 8 +- client/finality-grandpa/src/justification.rs | 7 +- client/finality-grandpa/src/tests.rs | 13 ++- client/finality-grandpa/src/voting_rule.rs | 28 +++--- client/finality-grandpa/src/warp_proof.rs | 11 ++- .../merkle-mountain-range/src/test_utils.rs | 4 +- client/network/src/protocol.rs | 7 +- .../network/src/service/tests/chain_sync.rs | 2 +- .../network/sync/src/block_request_handler.rs | 11 ++- client/network/sync/src/lib.rs | 2 +- client/network/test/src/block_import.rs | 3 +- client/network/test/src/lib.rs | 26 +++-- client/network/test/src/sync.rs | 47 +++++----- client/offchain/src/lib.rs | 2 +- .../rpc-spec-v2/src/chain_head/chain_head.rs | 2 +- client/rpc/src/chain/chain_full.rs | 4 +- client/rpc/src/chain/mod.rs | 10 +- client/rpc/src/dev/mod.rs | 2 +- client/service/src/builder.rs | 7 +- client/service/src/client/client.rs | 34 ++++--- client/service/test/src/client/mod.rs | 13 ++- client/sync-state-rpc/src/lib.rs | 7 +- client/tracing/src/block/mod.rs | 5 +- client/transaction-pool/benches/basics.rs | 2 +- client/transaction-pool/src/api.rs | 4 +- client/transaction-pool/src/graph/pool.rs | 2 +- client/transaction-pool/src/lib.rs | 2 +- client/transaction-pool/src/tests.rs | 2 +- primitives/blockchain/src/backend.rs | 14 +-- primitives/session/src/lib.rs | 4 +- test-utils/runtime/client/src/trait_tests.rs | 11 --- .../runtime/transaction-pool/src/lib.rs | 9 +- .../benchmarking-cli/src/storage/write.rs | 7 +- 55 files changed, 307 insertions(+), 360 deletions(-) diff --git a/bin/node/bench/src/construct.rs b/bin/node/bench/src/construct.rs index 2e20a7acb1e38..f994b29b5e843 100644 --- a/bin/node/bench/src/construct.rs +++ b/bin/node/bench/src/construct.rs @@ -143,7 +143,7 @@ impl core::Benchmark for ConstructionBenchmark { proposer_factory.init( &context .client - .header(&BlockId::number(0)) + .header(context.client.chain_info().genesis_hash) .expect("Database error querying block #0") .expect("Block #0 should exist"), ), diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs index e7b825a8e5ef1..cdee61af3f500 100644 --- a/bin/node/cli/src/service.rs +++ b/bin/node/cli/src/service.rs @@ -640,9 +640,8 @@ mod tests { Ok((node, setup_handles.unwrap())) }, |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(); - let parent_hash = parent_header.hash(); + let parent_hash = service.client().chain_info().best_hash; + let parent_header = service.client().header(parent_hash).unwrap().unwrap(); let parent_number = *parent_header.number(); futures::executor::block_on(service.transaction_pool().maintain( diff --git a/bin/node/inspect/src/lib.rs b/bin/node/inspect/src/lib.rs index 528dce14f46a5..3b9d7b2b1ff98 100644 --- a/bin/node/inspect/src/lib.rs +++ b/bin/node/inspect/src/lib.rs @@ -147,18 +147,17 @@ impl> Inspector .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()))?; + self.chain.header(hash)?.ok_or_else(|| Error::NotFound(not_found.clone()))?; TBlock::new(header, body) }, BlockAddress::Hash(hash) => { - let id = BlockId::hash(hash); - let not_found = format!("Could not find block {:?}", id); + let not_found = format!("Could not find block {:?}", BlockId::::Hash(hash)); let body = self .chain .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()))?; + self.chain.header(hash)?.ok_or_else(|| Error::NotFound(not_found.clone()))?; TBlock::new(header, body) }, }) diff --git a/client/api/src/in_mem.rs b/client/api/src/in_mem.rs index 5a3e25ab5987b..58add087074b6 100644 --- a/client/api/src/in_mem.rs +++ b/client/api/src/in_mem.rs @@ -225,7 +225,7 @@ impl Blockchain { /// Set an existing block as head. pub fn set_head(&self, hash: Block::Hash) -> sp_blockchain::Result<()> { let header = self - .header(BlockId::Hash(hash))? + .header(hash)? .ok_or_else(|| sp_blockchain::Error::UnknownBlock(format!("{}", hash)))?; self.apply_head(&header) @@ -336,11 +336,9 @@ impl Blockchain { impl HeaderBackend for Blockchain { fn header( &self, - id: BlockId, + hash: Block::Hash, ) -> sp_blockchain::Result::Header>> { - Ok(self - .id(id) - .and_then(|hash| self.storage.read().blocks.get(&hash).map(|b| b.header().clone()))) + Ok(self.storage.read().blocks.get(&hash).map(|b| b.header().clone())) } fn info(&self) -> blockchain::Info { @@ -387,7 +385,7 @@ impl HeaderMetadata for Blockchain { &self, hash: Block::Hash, ) -> Result, Self::Error> { - self.header(BlockId::hash(hash))? + self.header(hash)? .map(|header| CachedHeaderMetadata::from(&header)) .ok_or_else(|| { sp_blockchain::Error::UnknownBlock(format!("header not found: {}", hash)) diff --git a/client/authority-discovery/src/worker/tests.rs b/client/authority-discovery/src/worker/tests.rs index 8e7a221877574..ea0c16eca8063 100644 --- a/client/authority-discovery/src/worker/tests.rs +++ b/client/authority-discovery/src/worker/tests.rs @@ -58,7 +58,7 @@ impl ProvideRuntimeApi for TestApi { impl HeaderBackend for TestApi { fn header( &self, - _id: BlockId, + _hash: Block::Hash, ) -> std::result::Result, sp_blockchain::Error> { Ok(None) } diff --git a/client/basic-authorship/README.md b/client/basic-authorship/README.md index d29ce258e5134..f2f160b6e2a97 100644 --- a/client/basic-authorship/README.md +++ b/client/basic-authorship/README.md @@ -8,7 +8,7 @@ let mut proposer_factory = ProposerFactory::new(client.clone(), txpool.clone(), // From this factory, we create a `Proposer`. let proposer = proposer_factory.init( - &client.header(&BlockId::number(0)).unwrap().unwrap(), + &client.header(client.chain_info().genesis_hash).unwrap().unwrap(), ); // The proposer is created asynchronously. diff --git a/client/basic-authorship/src/basic_authorship.rs b/client/basic-authorship/src/basic_authorship.rs index b69294bf6ccb0..c39d07a14f0f1 100644 --- a/client/basic-authorship/src/basic_authorship.rs +++ b/client/basic-authorship/src/basic_authorship.rs @@ -617,8 +617,7 @@ mod tests { block_on( txpool.maintain(chain_event( client - .header(&BlockId::Number(0u64)) - .expect("header get error") + .expect_header(client.info().genesis_hash) .expect("there should be header"), )), ); @@ -628,7 +627,7 @@ mod tests { let cell = Mutex::new((false, time::Instant::now())); let proposer = proposer_factory.init_with_now( - &client.header(&BlockId::number(0)).unwrap().unwrap(), + &client.expect_header(client.info().genesis_hash).unwrap(), Box::new(move || { let mut value = cell.lock(); if !value.0 { @@ -672,7 +671,7 @@ mod tests { let cell = Mutex::new((false, time::Instant::now())); let proposer = proposer_factory.init_with_now( - &client.header(&BlockId::number(0)).unwrap().unwrap(), + &client.expect_header(client.info().genesis_hash).unwrap(), Box::new(move || { let mut value = cell.lock(); if !value.0 { @@ -705,15 +704,13 @@ mod tests { ); let genesis_hash = client.info().best_hash; - let block_id = BlockId::Hash(genesis_hash); block_on(txpool.submit_at(&BlockId::number(0), SOURCE, vec![extrinsic(0)])).unwrap(); block_on( txpool.maintain(chain_event( client - .header(&BlockId::Number(0u64)) - .expect("header get error") + .expect_header(client.info().genesis_hash) .expect("there should be header"), )), ); @@ -722,7 +719,7 @@ mod tests { ProposerFactory::new(spawner.clone(), client.clone(), txpool.clone(), None, None); let proposer = proposer_factory.init_with_now( - &client.header(&block_id).unwrap().unwrap(), + &client.header(genesis_hash).unwrap().unwrap(), Box::new(move || time::Instant::now()), ); @@ -734,7 +731,7 @@ mod tests { assert_eq!(proposal.block.extrinsics().len(), 1); let api = client.runtime_api(); - api.execute_block(&block_id, proposal.block).unwrap(); + api.execute_block(&BlockId::Hash(genesis_hash), proposal.block).unwrap(); let state = backend.state_at(genesis_hash).unwrap(); @@ -790,8 +787,9 @@ mod tests { number, expected_block_extrinsics, expected_pool_transactions| { + let hash = client.expect_block_hash_from_id(&BlockId::Number(number)).unwrap(); let proposer = proposer_factory.init_with_now( - &client.header(&BlockId::number(number)).unwrap().unwrap(), + &client.expect_header(hash).unwrap(), Box::new(move || time::Instant::now()), ); @@ -813,8 +811,7 @@ mod tests { block_on( txpool.maintain(chain_event( client - .header(&BlockId::Number(0u64)) - .expect("header get error") + .expect_header(client.info().genesis_hash) .expect("there should be header"), )), ); @@ -822,14 +819,12 @@ mod tests { // let's create one block and import it let block = propose_block(&client, 0, 2, 7); + let hashof1 = block.hash(); block_on(client.import(BlockOrigin::Own, block)).unwrap(); block_on( txpool.maintain(chain_event( - client - .header(&BlockId::Number(1)) - .expect("header get error") - .expect("there should be header"), + client.expect_header(hashof1).expect("there should be header"), )), ); assert_eq!(txpool.ready().count(), 5); @@ -851,8 +846,7 @@ mod tests { client.clone(), ); let genesis_header = client - .header(&BlockId::Number(0u64)) - .expect("header get error") + .expect_header(client.info().genesis_hash) .expect("there should be header"); let extrinsics_num = 5; @@ -966,8 +960,7 @@ mod tests { block_on( txpool.maintain(chain_event( client - .header(&BlockId::Number(0u64)) - .expect("header get error") + .expect_header(client.info().genesis_hash) .expect("there should be header"), )), ); @@ -978,7 +971,7 @@ mod tests { let cell = Mutex::new(time::Instant::now()); let proposer = proposer_factory.init_with_now( - &client.header(&BlockId::number(0)).unwrap().unwrap(), + &client.expect_header(client.info().genesis_hash).unwrap(), Box::new(move || { let mut value = cell.lock(); let old = *value; @@ -1029,8 +1022,7 @@ mod tests { block_on( txpool.maintain(chain_event( client - .header(&BlockId::Number(0u64)) - .expect("header get error") + .expect_header(client.info().genesis_hash) .expect("there should be header"), )), ); @@ -1043,7 +1035,7 @@ mod tests { let cell = Arc::new(Mutex::new((0, time::Instant::now()))); let cell2 = cell.clone(); let proposer = proposer_factory.init_with_now( - &client.header(&BlockId::number(0)).unwrap().unwrap(), + &client.expect_header(client.info().genesis_hash).unwrap(), Box::new(move || { let mut value = cell.lock(); let (called, old) = *value; diff --git a/client/basic-authorship/src/lib.rs b/client/basic-authorship/src/lib.rs index 4a26ebd9df970..e7f0d4496edeb 100644 --- a/client/basic-authorship/src/lib.rs +++ b/client/basic-authorship/src/lib.rs @@ -50,7 +50,7 @@ //! //! // From this factory, we create a `Proposer`. //! let proposer = proposer_factory.init( -//! &client.header(&BlockId::number(0)).unwrap().unwrap(), +//! &client.header(client.chain_info().genesis_hash).unwrap().unwrap(), //! ); //! //! // The proposer is created asynchronously. diff --git a/client/beefy/src/lib.rs b/client/beefy/src/lib.rs index a057a9fdc597d..35f7cac55a964 100644 --- a/client/beefy/src/lib.rs +++ b/client/beefy/src/lib.rs @@ -412,7 +412,7 @@ where })?; // Move up the chain. - header = blockchain.expect_header(BlockId::Hash(parent_hash))?; + header = blockchain.expect_header(parent_hash)?; }; aux_schema::write_current_version(backend)?; diff --git a/client/beefy/src/tests.rs b/client/beefy/src/tests.rs index 055c2669eb415..ce6f6ae3c978a 100644 --- a/client/beefy/src/tests.rs +++ b/client/beefy/src/tests.rs @@ -448,9 +448,8 @@ async fn wait_for_best_beefy_blocks( 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(); + net.lock().peer(i).client().as_client().expect_header(best_beefy_hash).unwrap(); let best_beefy = *header.number(); assert_eq!(expected, Some(best_beefy).as_ref()); diff --git a/client/beefy/src/worker.rs b/client/beefy/src/worker.rs index 89d231a6c2d73..b48dfa369eb2d 100644 --- a/client/beefy/src/worker.rs +++ b/client/beefy/src/worker.rs @@ -465,7 +465,7 @@ where .map(|hash| { backend .blockchain() - .expect_header(BlockId::hash(*hash)) + .expect_header(*hash) .expect("just finalized block should be available; qed.") }) .chain(std::iter::once(header.clone())) @@ -718,16 +718,25 @@ where let target_header = if target_number == self.best_grandpa_block() { self.persisted_state.best_grandpa_block_header.clone() } else { - self.backend + let hash = self + .backend .blockchain() - .expect_header(BlockId::Number(target_number)) + .expect_block_hash_from_id(&BlockId::Number(target_number)) .map_err(|err| { let err_msg = format!( - "Couldn't get header for block #{:?} (error: {:?}), skipping vote..", + "Couldn't get hash for block #{:?} (error: {:?}), skipping vote..", target_number, err ); Error::Backend(err_msg) - })? + })?; + + self.backend.blockchain().expect_header(hash).map_err(|err| { + let err_msg = format!( + "Couldn't get header for block #{:?} ({:?}) (error: {:?}), skipping vote..", + target_number, hash, err + ); + Error::Backend(err_msg) + })? }; let target_hash = target_header.hash(); @@ -1050,8 +1059,10 @@ pub(crate) mod tests { "/beefy/justifs/1".into(), known_peers, ); - let at = BlockId::number(Zero::zero()); - let genesis_header = backend.blockchain().expect_header(at).unwrap(); + let genesis_header = backend + .blockchain() + .expect_header(backend.blockchain().info().genesis_hash) + .unwrap(); let persisted_state = PersistedState::checked_new( genesis_header, Zero::zero(), diff --git a/client/consensus/aura/src/lib.rs b/client/consensus/aura/src/lib.rs index 212376dcd009c..6ef6bdc2ed1ff 100644 --- a/client/consensus/aura/src/lib.rs +++ b/client/consensus/aura/src/lib.rs @@ -957,7 +957,7 @@ mod tests { compatibility_mode: Default::default(), }; - let head = client.header(&BlockId::Number(0)).unwrap().unwrap(); + let head = client.expect_header(client.info().genesis_hash).unwrap(); let res = worker .on_slot(SlotInfo { @@ -972,6 +972,6 @@ mod tests { .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()); + assert!(client.header(res.block.hash()).unwrap().is_some()); } } diff --git a/client/consensus/babe/src/lib.rs b/client/consensus/babe/src/lib.rs index b50874ae3401d..9134da0b83d52 100644 --- a/client/consensus/babe/src/lib.rs +++ b/client/consensus/babe/src/lib.rs @@ -1425,7 +1425,7 @@ where let parent_hash = *block.header.parent_hash(); let parent_header = self .client - .header(BlockId::Hash(parent_hash)) + .header(parent_hash) .map_err(|e| ConsensusError::ChainLookup(e.to_string()))? .ok_or_else(|| { ConsensusError::ChainLookup( @@ -1664,7 +1664,7 @@ where let finalized_slot = { let finalized_header = client - .header(BlockId::Hash(info.finalized_hash)) + .header(info.finalized_hash) .map_err(|e| ConsensusError::ClientImport(e.to_string()))? .expect( "best finalized hash was given by client; finalized headers must exist in db; qed", diff --git a/client/consensus/babe/src/tests.rs b/client/consensus/babe/src/tests.rs index 6861379ebbeb5..84ac3d7341199 100644 --- a/client/consensus/babe/src/tests.rs +++ b/client/consensus/babe/src/tests.rs @@ -668,17 +668,17 @@ async fn propose_and_import_blocks( client: &PeersFullClient, proposer_factory: &mut DummyFactory, block_import: &mut BoxBlockImport, - parent_id: BlockId, + parent_hash: Hash, n: usize, ) -> Vec { let mut hashes = Vec::with_capacity(n); - let mut parent_header = client.header(&parent_id).unwrap().unwrap(); + let mut parent_header = client.header(parent_hash).unwrap().unwrap(); for _ in 0..n { let block_hash = propose_and_import_block(&parent_header, None, proposer_factory, block_import).await; hashes.push(block_hash); - parent_header = client.header(&BlockId::Hash(block_hash)).unwrap().unwrap(); + parent_header = client.header(block_hash).unwrap().unwrap(); } hashes @@ -701,7 +701,7 @@ async fn importing_block_one_sets_genesis_epoch() { let mut block_import = data.block_import.lock().take().expect("import set up during init"); - let genesis_header = client.header(&BlockId::Number(0)).unwrap().unwrap(); + let genesis_header = client.header(client.chain_info().genesis_hash).unwrap().unwrap(); let block_hash = propose_and_import_block( &genesis_header, @@ -759,34 +759,19 @@ async fn revert_prunes_epoch_changes_and_removes_weights() { &client, &mut proposer_factory, &mut block_import, - BlockId::Number(0), + client.chain_info().genesis_hash, 21, ) .await; - let fork1 = propose_and_import_blocks( - &client, - &mut proposer_factory, - &mut block_import, - BlockId::Hash(canon[0]), - 10, - ) - .await; - let fork2 = propose_and_import_blocks( - &client, - &mut proposer_factory, - &mut block_import, - BlockId::Hash(canon[7]), - 10, - ) - .await; - let fork3 = propose_and_import_blocks( - &client, - &mut proposer_factory, - &mut block_import, - BlockId::Hash(canon[11]), - 8, - ) - .await; + let fork1 = + propose_and_import_blocks(&client, &mut proposer_factory, &mut block_import, canon[0], 10) + .await; + let fork2 = + propose_and_import_blocks(&client, &mut proposer_factory, &mut block_import, canon[7], 10) + .await; + let fork3 = + propose_and_import_blocks(&client, &mut proposer_factory, &mut block_import, canon[11], 8) + .await; // We should be tracking a total of 9 epochs in the fork tree assert_eq!(epoch_changes.shared_data().tree().iter().count(), 8); @@ -850,7 +835,7 @@ async fn revert_not_allowed_for_finalized() { &client, &mut proposer_factory, &mut block_import, - BlockId::Number(0), + client.chain_info().genesis_hash, 3, ) .await; @@ -903,36 +888,21 @@ async fn importing_epoch_change_block_prunes_tree() { &client, &mut proposer_factory, &mut block_import, - BlockId::Number(0), + client.chain_info().genesis_hash, 30, ) .await; // Create the forks - let fork_1 = propose_and_import_blocks( - &client, - &mut proposer_factory, - &mut block_import, - BlockId::Hash(canon[0]), - 10, - ) - .await; - let fork_2 = propose_and_import_blocks( - &client, - &mut proposer_factory, - &mut block_import, - BlockId::Hash(canon[12]), - 15, - ) - .await; - let fork_3 = propose_and_import_blocks( - &client, - &mut proposer_factory, - &mut block_import, - BlockId::Hash(canon[18]), - 10, - ) - .await; + let fork_1 = + propose_and_import_blocks(&client, &mut proposer_factory, &mut block_import, canon[0], 10) + .await; + let fork_2 = + propose_and_import_blocks(&client, &mut proposer_factory, &mut block_import, canon[12], 15) + .await; + let fork_3 = + propose_and_import_blocks(&client, &mut proposer_factory, &mut block_import, canon[18], 10) + .await; // We should be tracking a total of 9 epochs in the fork tree assert_eq!(epoch_changes.shared_data().tree().iter().count(), 9); @@ -947,7 +917,7 @@ async fn importing_epoch_change_block_prunes_tree() { &client, &mut proposer_factory, &mut block_import, - BlockId::Hash(client.chain_info().best_hash), + client.chain_info().best_hash, 7, ) .await; @@ -967,7 +937,7 @@ async fn importing_epoch_change_block_prunes_tree() { &client, &mut proposer_factory, &mut block_import, - BlockId::Hash(client.chain_info().best_hash), + client.chain_info().best_hash, 8, ) .await; @@ -1001,7 +971,7 @@ async fn verify_slots_are_strictly_increasing() { mutator: Arc::new(|_, _| ()), }; - let genesis_header = client.header(&BlockId::Number(0)).unwrap().unwrap(); + let genesis_header = client.header(client.chain_info().genesis_hash).unwrap().unwrap(); // we should have no issue importing this block let b1 = propose_and_import_block( @@ -1012,7 +982,7 @@ async fn verify_slots_are_strictly_increasing() { ) .await; - let b1 = client.header(&BlockId::Hash(b1)).unwrap().unwrap(); + let b1 = client.header(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. @@ -1091,7 +1061,7 @@ async fn obsolete_blocks_aux_data_cleanup() { &client, &mut proposer_factory, &mut block_import, - BlockId::Number(0), + client.chain_info().genesis_hash, 4, ) .await; @@ -1099,7 +1069,7 @@ async fn obsolete_blocks_aux_data_cleanup() { &client, &mut proposer_factory, &mut block_import, - BlockId::Number(0), + client.chain_info().genesis_hash, 2, ) .await; @@ -1107,7 +1077,7 @@ async fn obsolete_blocks_aux_data_cleanup() { &client, &mut proposer_factory, &mut block_import, - BlockId::Number(3), + fork1_hashes[2], 2, ) .await; diff --git a/client/consensus/common/src/longest_chain.rs b/client/consensus/common/src/longest_chain.rs index 941cd4b944766..fab2c3a4c06fd 100644 --- a/client/consensus/common/src/longest_chain.rs +++ b/client/consensus/common/src/longest_chain.rs @@ -21,10 +21,7 @@ use sc_client_api::backend; use sp_blockchain::{Backend, HeaderBackend}; use sp_consensus::{Error as ConsensusError, SelectChain}; -use sp_runtime::{ - generic::BlockId, - traits::{Block as BlockT, NumberFor}, -}; +use sp_runtime::traits::{Block as BlockT, NumberFor}; use std::{marker::PhantomData, sync::Arc}; /// Implement Longest Chain Select implementation @@ -63,7 +60,7 @@ where Ok(self .backend .blockchain() - .header(BlockId::Hash(best_hash))? + .header(best_hash)? .expect("given block hash was fetched from block in db; qed")) } diff --git a/client/consensus/manual-seal/src/consensus/babe.rs b/client/consensus/manual-seal/src/consensus/babe.rs index d2bea3a3a3656..c5bb3b78fce35 100644 --- a/client/consensus/manual-seal/src/consensus/babe.rs +++ b/client/consensus/manual-seal/src/consensus/babe.rs @@ -44,7 +44,7 @@ use sp_consensus_babe::{ use sp_consensus_slots::Slot; use sp_inherents::InherentData; use sp_runtime::{ - generic::{BlockId, Digest}, + generic::Digest, traits::{Block as BlockT, Header}, DigestItem, }; @@ -108,7 +108,7 @@ where let parent_hash = import_params.header.parent_hash(); let parent = self .client - .header(BlockId::Hash(*parent_hash)) + .header(*parent_hash) .ok() .flatten() .ok_or_else(|| format!("header for block {} not found", parent_hash))?; diff --git a/client/consensus/manual-seal/src/consensus/timestamp.rs b/client/consensus/manual-seal/src/consensus/timestamp.rs index 2cb9887a81f40..b3c2d780c35d9 100644 --- a/client/consensus/manual-seal/src/consensus/timestamp.rs +++ b/client/consensus/manual-seal/src/consensus/timestamp.rs @@ -30,10 +30,7 @@ use sp_consensus_aura::{ use sp_consensus_babe::BabeApi; use sp_consensus_slots::{Slot, SlotDuration}; use sp_inherents::{InherentData, InherentDataProvider, InherentIdentifier}; -use sp_runtime::{ - generic::BlockId, - traits::{Block as BlockT, Zero}, -}; +use sp_runtime::traits::{Block as BlockT, Zero}; use sp_timestamp::{InherentType, INHERENT_IDENTIFIER}; use std::{ sync::{atomic, Arc}, @@ -109,7 +106,7 @@ impl SlotTimestampProvider { // 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))? + .header(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 diff --git a/client/consensus/manual-seal/src/lib.rs b/client/consensus/manual-seal/src/lib.rs index 700b94cf1d704..5c86382a3ab7b 100644 --- a/client/consensus/manual-seal/src/lib.rs +++ b/client/consensus/manual-seal/src/lib.rs @@ -360,7 +360,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 genesis_hash = client.info().genesis_hash; let pool = Arc::new(BasicPool::with_revalidation_type( Options::default(), true.into(), @@ -424,7 +424,8 @@ mod tests { } ); // assert that there's a new block in the db. - assert!(client.header(&BlockId::Number(1)).unwrap().is_some()) + assert!(client.header(created_block.hash).unwrap().is_some()); + assert_eq!(client.header(created_block.hash).unwrap().unwrap().number, 1) } #[tokio::test] @@ -433,7 +434,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 genesis_hash = client.info().genesis_hash; let pool = Arc::new(BasicPool::with_revalidation_type( Options::default(), true.into(), @@ -494,7 +495,7 @@ mod tests { } ); // assert that there's a new block in the db. - let header = client.header(&BlockId::Number(1)).unwrap().unwrap(); + let header = client.header(created_block.hash).unwrap().unwrap(); let (tx, rx) = futures::channel::oneshot::channel(); sink.send(EngineCommand::FinalizeBlock { sender: Some(tx), @@ -518,7 +519,7 @@ mod tests { &sp_core::testing::TaskExecutor::new(), )); let spawner = sp_core::testing::TaskExecutor::new(); - let genesis_hash = client.header(&BlockId::Number(0)).unwrap().unwrap().hash(); + let genesis_hash = client.info().genesis_hash; let pool = Arc::new(BasicPool::with_revalidation_type( Options::default(), true.into(), @@ -582,7 +583,8 @@ mod tests { 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"); + let header = client.header(created_block.hash).expect("db error").expect("imported above"); + assert_eq!(header.number, 1); pool.maintain(sc_transaction_pool_api::ChainEvent::NewBestBlock { hash: header.hash(), tree_route: None, @@ -614,7 +616,7 @@ mod tests { .is_ok()); let imported = rx2.await.unwrap().unwrap(); // assert that fork block is in the db - assert!(client.header(&BlockId::Hash(imported.hash)).unwrap().is_some()) + assert!(client.header(imported.hash).unwrap().is_some()) } #[tokio::test] @@ -623,7 +625,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 genesis_hash = client.header(client.info().genesis_hash).unwrap().unwrap().hash(); let pool = Arc::new(BasicPool::with_revalidation_type( Options::default(), true.into(), @@ -665,7 +667,7 @@ mod tests { 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); + let header = client.header(created_block.hash).unwrap().unwrap(); + assert_eq!(header.number, 1); } } diff --git a/client/consensus/manual-seal/src/seal_block.rs b/client/consensus/manual-seal/src/seal_block.rs index 25c091bf460ec..2cafdae503dce 100644 --- a/client/consensus/manual-seal/src/seal_block.rs +++ b/client/consensus/manual-seal/src/seal_block.rs @@ -26,10 +26,7 @@ use sp_api::{ProvideRuntimeApi, TransactionFor}; use sp_blockchain::HeaderBackend; use sp_consensus::{self, BlockOrigin, Environment, Proposer, SelectChain}; use sp_inherents::{CreateInherentDataProviders, InherentDataProvider}; -use sp_runtime::{ - generic::BlockId, - traits::{Block as BlockT, Header as HeaderT}, -}; +use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; use std::{collections::HashMap, sync::Arc, time::Duration}; /// max duration for creating a proposal in secs @@ -102,9 +99,8 @@ pub async fn seal_block( // use the parent_hash supplied via `EngineCommand` // or fetch the best_block. let parent = match parent_hash { - Some(hash) => client - .header(BlockId::Hash(hash))? - .ok_or_else(|| Error::BlockNotFound(format!("{}", hash)))?, + Some(hash) => + client.header(hash)?.ok_or_else(|| Error::BlockNotFound(format!("{}", hash)))?, None => select_chain.best_chain().await?, }; diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index 7c2635f843418..b1f5a6edcd52f 100644 --- a/client/db/src/lib.rs +++ b/client/db/src/lib.rs @@ -524,21 +524,19 @@ impl BlockchainDb { } impl sc_client_api::blockchain::HeaderBackend for BlockchainDb { - fn header(&self, id: BlockId) -> ClientResult> { - match &id { - BlockId::Hash(h) => { - let mut cache = self.header_cache.lock(); - if let Some(result) = cache.get_refresh(h) { - return Ok(result.clone()) - } - let header = - utils::read_header(&*self.db, columns::KEY_LOOKUP, columns::HEADER, id)?; - cache_header(&mut cache, *h, header.clone()); - Ok(header) - }, - BlockId::Number(_) => - utils::read_header(&*self.db, columns::KEY_LOOKUP, columns::HEADER, id), + fn header(&self, hash: Block::Hash) -> ClientResult> { + let mut cache = self.header_cache.lock(); + if let Some(result) = cache.get_refresh(&hash) { + return Ok(result.clone()) } + let header = utils::read_header( + &*self.db, + columns::KEY_LOOKUP, + columns::HEADER, + BlockId::::Hash(hash), + )?; + cache_header(&mut cache, hash, header.clone()); + Ok(header) } fn info(&self) -> sc_client_api::blockchain::Info { @@ -557,7 +555,7 @@ impl sc_client_api::blockchain::HeaderBackend for Blockcha fn status(&self, id: BlockId) -> ClientResult { let exists = match id { - BlockId::Hash(_) => self.header(id)?.is_some(), + BlockId::Hash(hash) => self.header(hash)?.is_some(), BlockId::Number(n) => n <= self.meta.read().best_number, }; match exists { @@ -571,8 +569,13 @@ impl sc_client_api::blockchain::HeaderBackend for Blockcha } fn hash(&self, number: NumberFor) -> ClientResult> { - self.header(BlockId::Number(number)) - .map(|maybe_header| maybe_header.map(|header| header.hash())) + Ok(utils::read_header::( + &*self.db, + columns::KEY_LOOKUP, + columns::HEADER, + BlockId::Number(number), + )? + .map(|header| header.hash())) } } @@ -736,7 +739,7 @@ impl HeaderMetadata for BlockchainDb { ) -> Result, Self::Error> { self.header_metadata_cache.header_metadata(hash).map_or_else( || { - self.header(BlockId::hash(hash))? + self.header(hash)? .map(|header| { let header_metadata = CachedHeaderMetadata::from(&header); self.header_metadata_cache @@ -1369,7 +1372,7 @@ impl Backend { }; for (block_hash, justification) in operation.finalized_blocks { - let block_header = self.blockchain.expect_header(BlockId::Hash(block_hash))?; + let block_header = self.blockchain.expect_header(block_hash)?; meta_updates.push(self.finalize_block_with_transaction( &mut transaction, block_hash, @@ -1394,8 +1397,7 @@ impl Backend { .highest_leaf() .map(|(n, _)| n) .unwrap_or(Zero::zero()); - let existing_header = - number <= highest_leaf && self.blockchain.header(BlockId::hash(hash))?.is_some(); + let existing_header = number <= highest_leaf && self.blockchain.header(hash)?.is_some(); // blocks are keyed by number + hash. let lookup_key = utils::number_and_hash_to_lookup_key(number, hash)?; @@ -1615,10 +1617,7 @@ impl Backend { ); } } else if number > best_num + One::one() && - number > One::one() && self - .blockchain - .header(BlockId::hash(parent_hash))? - .is_none() + number > One::one() && self.blockchain.header(parent_hash)?.is_none() { let gap = (best_num + One::one(), number - One::one()); transaction.set(columns::META, meta_keys::BLOCK_GAP, &gap.encode()); @@ -1640,10 +1639,9 @@ impl Backend { }; if let Some(set_head) = operation.set_head { - if let Some(header) = sc_client_api::blockchain::HeaderBackend::header( - &self.blockchain, - BlockId::Hash(set_head), - )? { + if let Some(header) = + sc_client_api::blockchain::HeaderBackend::header(&self.blockchain, set_head)? + { let number = header.number(); let hash = header.hash(); @@ -1767,10 +1765,9 @@ impl Backend { // 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)? { + match self.blockchain.header(hash)? { Some(header) => { - self.prune_block(transaction, id)?; + self.prune_block(transaction, BlockId::::hash(hash))?; number = header.number().saturating_sub(One::one()); hash = *header.parent_hash(); }, @@ -2013,7 +2010,7 @@ impl sc_client_api::backend::Backend for Backend { justification: Option, ) -> ClientResult<()> { let mut transaction = Transaction::new(); - let header = self.blockchain.expect_header(BlockId::Hash(hash))?; + let header = self.blockchain.expect_header(hash)?; let mut displaced = None; let m = self.finalize_block_with_transaction( @@ -2035,7 +2032,7 @@ impl sc_client_api::backend::Backend for Backend { justification: Justification, ) -> ClientResult<()> { let mut transaction: Transaction = Transaction::new(); - let header = self.blockchain.expect_header(BlockId::Hash(hash))?; + let header = self.blockchain.expect_header(hash)?; let number = *header.number(); // Check if the block is finalized first. @@ -2141,13 +2138,12 @@ impl sc_client_api::backend::Backend for Backend { return Ok(c.saturated_into::>()) } let mut transaction = Transaction::new(); - let removed = - self.blockchain.header(BlockId::Hash(hash_to_revert))?.ok_or_else(|| { - sp_blockchain::Error::UnknownBlock(format!( - "Error reverting to {}. Block header not found.", - hash_to_revert, - )) - })?; + let removed = self.blockchain.header(hash_to_revert)?.ok_or_else(|| { + sp_blockchain::Error::UnknownBlock(format!( + "Error reverting to {}. Block header not found.", + hash_to_revert, + )) + })?; let removed_hash = removed.hash(); let prev_number = number_to_revert.saturating_sub(One::one()); @@ -3196,7 +3192,7 @@ pub(crate) mod tests { }; { - let header = backend.blockchain().header(BlockId::Hash(hash1)).unwrap().unwrap(); + let header = backend.blockchain().header(hash1).unwrap().unwrap(); let mut op = backend.begin_operation().unwrap(); op.set_block_data(header, None, None, None, NewBlockState::Best).unwrap(); backend.commit_operation(op).unwrap(); @@ -3603,26 +3599,26 @@ pub(crate) mod tests { 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()); + assert!(backend.blockchain().header(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!(backend.blockchain().header(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()); + assert!(backend.blockchain().header(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!(backend.blockchain().header(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()); + assert!(backend.blockchain().header(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!(backend.blockchain().header(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]); } diff --git a/client/finality-grandpa/src/environment.rs b/client/finality-grandpa/src/environment.rs index 110d0eb2c927e..9e63bef78a6a9 100644 --- a/client/finality-grandpa/src/environment.rs +++ b/client/finality-grandpa/src/environment.rs @@ -525,7 +525,7 @@ where Some((_, n)) if n > best_block_number => best_block_hash, Some((h, _)) => { // this is the header at which the new set will start - let header = self.client.header(BlockId::Hash(h))?.expect( + let header = self.client.header(h)?.expect( "got block hash from registered pending change; \ pending changes are only registered on block import; qed.", ); @@ -1171,7 +1171,7 @@ where SelectChain: SelectChainT + 'static, VotingRule: VotingRuleT, { - let base_header = match client.header(BlockId::Hash(block))? { + let base_header = match client.header(block)? { Some(h) => h, None => { debug!( @@ -1197,7 +1197,7 @@ where let result = match select_chain.finality_target(block, None).await { Ok(best_hash) => { let best_header = client - .header(BlockId::Hash(best_hash))? + .header(best_hash)? .expect("Header known to exist after `finality_target` call; qed"); // check if our vote is currently being limited due to a pending change @@ -1221,7 +1221,7 @@ where } target_header = client - .header(BlockId::Hash(*target_header.parent_hash()))? + .header(*target_header.parent_hash())? .expect("Header known to exist after `finality_target` call; qed"); } diff --git a/client/finality-grandpa/src/finality_proof.rs b/client/finality-grandpa/src/finality_proof.rs index 43ed0ed31993e..416e71478ab4d 100644 --- a/client/finality-grandpa/src/finality_proof.rs +++ b/client/finality-grandpa/src/finality_proof.rs @@ -222,7 +222,8 @@ where if current > just_block || headers.len() >= MAX_UNKNOWN_HEADERS { break } - headers.push(backend.blockchain().expect_header(BlockId::Number(current))?); + let hash = backend.blockchain().expect_block_hash_from_id(&BlockId::Number(current))?; + headers.push(backend.blockchain().expect_header(hash)?); current += One::one(); } headers diff --git a/client/finality-grandpa/src/import.rs b/client/finality-grandpa/src/import.rs index e061c105eeea5..1359110132c55 100644 --- a/client/finality-grandpa/src/import.rs +++ b/client/finality-grandpa/src/import.rs @@ -122,7 +122,7 @@ where }; if let Ok(hash) = effective_block_hash { - if let Ok(Some(header)) = self.inner.header(BlockId::Hash(hash)) { + if let Ok(Some(header)) = self.inner.header(hash) { if *header.number() == pending_change.effective_number() { out.push((header.hash(), *header.number())); } @@ -364,14 +364,12 @@ where // best finalized block. let best_finalized_number = self.inner.info().finalized_number; let canon_number = best_finalized_number.min(median_last_finalized_number); - let canon_hash = - self.inner.header(BlockId::Number(canon_number)) + let canon_hash = self.inner.hash(canon_number) .map_err(|e| ConsensusError::ClientImport(e.to_string()))? .expect( "the given block number is less or equal than the current best finalized number; \ current best finalized number must exist in chain; qed." - ) - .hash(); + ); NewAuthoritySet { canon_number, diff --git a/client/finality-grandpa/src/justification.rs b/client/finality-grandpa/src/justification.rs index 56b26c964ce9b..96c31d4c0cc29 100644 --- a/client/finality-grandpa/src/justification.rs +++ b/client/finality-grandpa/src/justification.rs @@ -26,10 +26,7 @@ use finality_grandpa::{voter_set::VoterSet, Error as GrandpaError}; use parity_scale_codec::{Decode, Encode}; use sp_blockchain::{Error as ClientError, HeaderBackend}; use sp_finality_grandpa::AuthorityId; -use sp_runtime::{ - generic::BlockId, - traits::{Block as BlockT, Header as HeaderT, NumberFor}, -}; +use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor}; use crate::{AuthorityList, Commit, Error}; @@ -104,7 +101,7 @@ impl GrandpaJustification { break } - match client.header(BlockId::Hash(current_hash))? { + match client.header(current_hash)? { Some(current_header) => { // NOTE: this should never happen as we pick the lowest block // as base and only traverse backwards from the other blocks diff --git a/client/finality-grandpa/src/tests.rs b/client/finality-grandpa/src/tests.rs index d5bc7d50c5fa8..4abcb05406e5b 100644 --- a/client/finality-grandpa/src/tests.rs +++ b/client/finality-grandpa/src/tests.rs @@ -1530,10 +1530,13 @@ async fn justification_with_equivocation() { // 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 client = net.peer(0).client().as_client().clone(); + let hashof1 = client.expect_block_hash_from_id(&BlockId::Number(1)).unwrap(); + let hashof2 = client.expect_block_hash_from_id(&BlockId::Number(2)).unwrap(); + let hashof3 = client.expect_block_hash_from_id(&BlockId::Number(3)).unwrap(); + let block1 = client.expect_header(hashof1).unwrap(); + let block2 = client.expect_header(hashof2).unwrap(); + let block3 = client.expect_header(hashof3).unwrap(); let set_id = 0; let justification = { @@ -1576,7 +1579,7 @@ async fn justification_with_equivocation() { precommits, }; - GrandpaJustification::from_commit(&client.as_client(), round, commit).unwrap() + GrandpaJustification::from_commit(&client, round, commit).unwrap() }; // the justification should include the minimal necessary vote ancestry and diff --git a/client/finality-grandpa/src/voting_rule.rs b/client/finality-grandpa/src/voting_rule.rs index fb7754fc0169a..6f15a9cdd349e 100644 --- a/client/finality-grandpa/src/voting_rule.rs +++ b/client/finality-grandpa/src/voting_rule.rs @@ -27,10 +27,7 @@ use std::{future::Future, pin::Pin, sync::Arc}; use dyn_clone::DynClone; use sc_client_api::blockchain::HeaderBackend; -use sp_runtime::{ - generic::BlockId, - traits::{Block as BlockT, Header, NumberFor, One, Zero}, -}; +use sp_runtime::traits::{Block as BlockT, Header, NumberFor, One, Zero}; /// A future returned by a `VotingRule` to restrict a given vote, if any restriction is necessary. pub type VotingRuleResult = @@ -197,7 +194,7 @@ where target_hash = *target_header.parent_hash(); target_header = backend - .header(BlockId::Hash(target_hash)) + .header(target_hash) .ok()? .expect("Header known to exist due to the existence of one of its descendents; qed"); } @@ -242,7 +239,7 @@ where restricted_number >= base.number() && restricted_number < restricted_target.number() }) - .and_then(|(hash, _)| backend.header(BlockId::Hash(hash)).ok()) + .and_then(|(hash, _)| backend.header(hash).ok()) .and_then(std::convert::identity) { restricted_target = header; @@ -371,16 +368,18 @@ mod tests { let rule = VotingRulesBuilder::new().add(Subtract(50)).add(Subtract(50)).build(); let mut client = Arc::new(TestClientBuilder::new().build()); + let mut hashes = Vec::with_capacity(200); for _ in 0..200 { let block = client.new_block(Default::default()).unwrap().build().unwrap().block; + hashes.push(block.hash()); futures::executor::block_on(client.import(BlockOrigin::Own, block)).unwrap(); } - let genesis = client.header(&BlockId::Number(0u32.into())).unwrap().unwrap(); + let genesis = client.header(client.info().genesis_hash).unwrap().unwrap(); - let best = client.header(&BlockId::Hash(client.info().best_hash)).unwrap().unwrap(); + let best = client.header(client.info().best_hash).unwrap().unwrap(); let (_, number) = futures::executor::block_on(rule.restrict_vote(client.clone(), &genesis, &best, &best)) @@ -390,7 +389,7 @@ mod tests { // which means that we should be voting for block #100 assert_eq!(number, 100); - let block110 = client.header(&BlockId::Number(110u32.into())).unwrap().unwrap(); + let block110 = client.header(hashes[109]).unwrap().unwrap(); let (_, number) = futures::executor::block_on(rule.restrict_vote( client.clone(), @@ -412,17 +411,20 @@ mod tests { let mut client = Arc::new(TestClientBuilder::new().build()); - for _ in 0..5 { + let n = 5; + let mut hashes = Vec::with_capacity(n); + for _ in 0..n { let block = client.new_block(Default::default()).unwrap().build().unwrap().block; + hashes.push(block.hash()); futures::executor::block_on(client.import(BlockOrigin::Own, block)).unwrap(); } - let best = client.header(&BlockId::Hash(client.info().best_hash)).unwrap().unwrap(); + let best = client.header(client.info().best_hash).unwrap().unwrap(); let best_number = *best.number(); - for i in 0u32..5 { - let base = client.header(&BlockId::Number(i.into())).unwrap().unwrap(); + for i in 0..n { + let base = client.header(hashes[i]).unwrap().unwrap(); let (_, number) = futures::executor::block_on(rule.restrict_vote( client.clone(), &base, diff --git a/client/finality-grandpa/src/warp_proof.rs b/client/finality-grandpa/src/warp_proof.rs index c9f762fc7d593..c65a705d3e844 100644 --- a/client/finality-grandpa/src/warp_proof.rs +++ b/client/finality-grandpa/src/warp_proof.rs @@ -116,9 +116,12 @@ impl WarpSyncProof { let set_changes = set_changes.iter_from(begin_number).ok_or(Error::MissingData)?; for (_, last_block) in set_changes { - let header = blockchain.header(BlockId::Number(*last_block))?.expect( - "header number comes from previously applied set changes; must exist in db; qed.", - ); + let hash = blockchain.block_hash_from_id(&BlockId::Number(*last_block))? + .expect("header number comes from previously applied set changes; corresponding hash must exist in db; qed."); + + let header = blockchain + .header(hash)? + .expect("header hash obtained from header number exists in db; corresponding header must exist in db too; qed."); // the last block in a set is the one that triggers a change to the next set, // therefore the block must have a digest that signals the authority set change @@ -172,7 +175,7 @@ impl WarpSyncProof { }); if let Some(latest_justification) = latest_justification { - let header = blockchain.header(BlockId::Hash(latest_justification.target().1))? + let header = blockchain.header(latest_justification.target().1)? .expect("header hash corresponds to a justification in db; must exist in db as well; qed."); proofs.push(WarpSyncFragment { header, justification: latest_justification }) diff --git a/client/merkle-mountain-range/src/test_utils.rs b/client/merkle-mountain-range/src/test_utils.rs index f345fb52578ab..1bc7a9bd5bbac 100644 --- a/client/merkle-mountain-range/src/test_utils.rs +++ b/client/merkle-mountain-range/src/test_utils.rs @@ -226,8 +226,8 @@ impl HeaderMetadata for MockClient { } impl HeaderBackend for MockClient { - fn header(&self, id: BlockId) -> sc_client_api::blockchain::Result> { - self.client.lock().header(&id) + fn header(&self, hash: Hash) -> sc_client_api::blockchain::Result> { + self.client.lock().header(hash) } fn info(&self) -> Info { diff --git a/client/network/src/protocol.rs b/client/network/src/protocol.rs index 10eb31b595253..1f0ec9c0d120d 100644 --- a/client/network/src/protocol.rs +++ b/client/network/src/protocol.rs @@ -46,10 +46,7 @@ use sc_network_common::{ utils::{interval, LruHashSet}, }; use sp_arithmetic::traits::SaturatedConversion; -use sp_runtime::{ - generic::BlockId, - traits::{Block as BlockT, CheckedSub, Header as HeaderT, NumberFor, Zero}, -}; +use sp_runtime::traits::{Block as BlockT, CheckedSub, Header as HeaderT, NumberFor, Zero}; use std::{ collections::{HashMap, HashSet, VecDeque}, io, iter, @@ -627,7 +624,7 @@ where /// In chain-based consensus, we often need to make sure non-best forks are /// at least temporarily synced. pub fn announce_block(&mut self, hash: B::Hash, data: Option>) { - let header = match self.chain.header(BlockId::Hash(hash)) { + let header = match self.chain.header(hash) { Ok(Some(header)) => header, Ok(None) => { warn!("Trying to announce unknown block: {}", hash); diff --git a/client/network/src/service/tests/chain_sync.rs b/client/network/src/service/tests/chain_sync.rs index ce4430dd87db9..9d8463ff190a8 100644 --- a/client/network/src/service/tests/chain_sync.rs +++ b/client/network/src/service/tests/chain_sync.rs @@ -199,7 +199,7 @@ async fn on_block_finalized() { let mut chain_sync = Box::new(MockChainSync::::new()); - let at = client.header(&BlockId::Hash(client.info().best_hash)).unwrap().unwrap().hash(); + let at = client.header(client.info().best_hash).unwrap().unwrap().hash(); let block = client .new_block_at(&BlockId::Hash(at), Default::default(), false) .unwrap() diff --git a/client/network/sync/src/block_request_handler.rs b/client/network/sync/src/block_request_handler.rs index b5f8b6b73bce9..84755453fbea0 100644 --- a/client/network/sync/src/block_request_handler.rs +++ b/client/network/sync/src/block_request_handler.rs @@ -330,7 +330,16 @@ where let mut blocks = Vec::new(); let mut total_size: usize = 0; - while let Some(header) = self.client.header(block_id).unwrap_or_default() { + + let client_header_from_block_id = + |block_id: BlockId| -> Result, HandleRequestError> { + if let Some(hash) = self.client.block_hash_from_id(&block_id)? { + return self.client.header(hash).map_err(Into::into) + } + Ok(None) + }; + + while let Some(header) = client_header_from_block_id(block_id).unwrap_or_default() { let number = *header.number(); let hash = header.hash(); let parent_hash = *header.parent_hash(); diff --git a/client/network/sync/src/lib.rs b/client/network/sync/src/lib.rs index 75eda91219ec8..7dd818d4c12cb 100644 --- a/client/network/sync/src/lib.rs +++ b/client/network/sync/src/lib.rs @@ -1082,7 +1082,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)) { + if let Ok(Some(header)) = self.client.header(*hash) { log::debug!( target: "sync", "Starting state sync for #{} ({})", diff --git a/client/network/test/src/block_import.rs b/client/network/test/src/block_import.rs index b86f6787f30b5..250f5f5fd102c 100644 --- a/client/network/test/src/block_import.rs +++ b/client/network/test/src/block_import.rs @@ -26,7 +26,6 @@ use sc_consensus::{ IncomingBlock, }; use sp_consensus::BlockOrigin; -use sp_runtime::generic::BlockId; use substrate_test_runtime_client::{ self, prelude::*, @@ -39,7 +38,7 @@ fn prepare_good_block() -> (TestClient, Hash, u64, PeerId, IncomingBlock) block_on(client.import(BlockOrigin::File, block)).unwrap(); let (hash, number) = (client.block_hash(1).unwrap().unwrap(), 1); - let header = client.header(&BlockId::Number(1)).unwrap(); + let header = client.header(hash).unwrap(); let justifications = client.justifications(hash).unwrap(); let peer_id = PeerId::random(); ( diff --git a/client/network/test/src/lib.rs b/client/network/test/src/lib.rs index a7b963555cae4..b3653ac7c0f88 100644 --- a/client/network/test/src/lib.rs +++ b/client/network/test/src/lib.rs @@ -163,17 +163,23 @@ impl PeersClient { pub fn header( &self, - block: &BlockId, + hash: ::Hash, ) -> ClientResult::Header>> { - self.client.header(block) + self.client.header(hash) } pub fn has_state_at(&self, block: &BlockId) -> bool { - let header = match self.header(block).unwrap() { - Some(header) => header, - None => return false, + let (number, hash) = match *block { + BlockId::Hash(h) => match self.as_client().number(h) { + Ok(Some(n)) => (n, h), + _ => return false, + }, + BlockId::Number(n) => match self.as_client().hash(n) { + Ok(Some(h)) => (n, h), + _ => return false, + }, }; - self.backend.have_state_at(header.hash(), *header.number()) + self.backend.have_state_at(hash, number) } pub fn justifications( @@ -367,7 +373,7 @@ where { let mut hashes = Vec::with_capacity(count); let full_client = self.client.as_client(); - let mut at = full_client.header(&at).unwrap().unwrap().hash(); + let mut at = full_client.block_hash_from_id(&at).unwrap().unwrap(); for _ in 0..count { let builder = full_client.new_block_at(&BlockId::Hash(at), Default::default(), false).unwrap(); @@ -404,7 +410,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(), + *full_client.header(at).ok().flatten().unwrap().number(), ); } hashes @@ -549,7 +555,7 @@ where 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(hash).unwrap().is_some()) .unwrap_or(false) } @@ -673,7 +679,7 @@ impl WarpSyncProvider for TestWarpSyncProvider { _start: B::Hash, ) -> Result> { let info = self.0.info(); - let best_header = self.0.header(BlockId::hash(info.best_hash)).unwrap().unwrap(); + let best_header = self.0.header(info.best_hash).unwrap().unwrap(); Ok(EncodedProof(best_header.encode())) } fn verify( diff --git a/client/network/test/src/sync.rs b/client/network/test/src/sync.rs index c7b651f457a56..b629574fe9874 100644 --- a/client/network/test/src/sync.rs +++ b/client/network/test/src/sync.rs @@ -267,9 +267,9 @@ async fn sync_justifications() { 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(); - let hashof20 = net.peer(1).client().header(&BlockId::Number(20)).unwrap().unwrap().hash(); + let hashof10 = net.peer(1).client().as_client().hash(10).unwrap().unwrap(); + let hashof15 = net.peer(1).client().as_client().hash(15).unwrap().unwrap(); + let hashof20 = net.peer(1).client().as_client().hash(20).unwrap().unwrap(); // peer 1 should get the justifications from the network net.peer(1).request_justification(&hashof10, 10); @@ -408,8 +408,8 @@ async fn can_sync_small_non_best_forks() { net.peer(1).push_blocks(10, false); assert_eq!(net.peer(1).client().info().best_number, 40); - assert!(net.peer(0).client().header(&BlockId::Hash(small_hash)).unwrap().is_some()); - assert!(net.peer(1).client().header(&BlockId::Hash(small_hash)).unwrap().is_none()); + assert!(net.peer(0).client().header(small_hash).unwrap().is_some()); + assert!(net.peer(1).client().header(small_hash).unwrap().is_none()); // poll until the two nodes connect, otherwise announcing the block will not work futures::future::poll_fn::<(), _>(|cx| { @@ -426,8 +426,8 @@ async fn can_sync_small_non_best_forks() { assert_eq!(net.peer(0).client().info().best_number, 40); - assert!(net.peer(0).client().header(&BlockId::Hash(small_hash)).unwrap().is_some()); - assert!(!net.peer(1).client().header(&BlockId::Hash(small_hash)).unwrap().is_some()); + assert!(net.peer(0).client().header(small_hash).unwrap().is_some()); + assert!(!net.peer(1).client().header(small_hash).unwrap().is_some()); net.peer(0).announce_block(small_hash, None); @@ -436,8 +436,8 @@ async fn can_sync_small_non_best_forks() { futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); - assert!(net.peer(0).client().header(&BlockId::Hash(small_hash)).unwrap().is_some()); - if net.peer(1).client().header(&BlockId::Hash(small_hash)).unwrap().is_none() { + assert!(net.peer(0).client().header(small_hash).unwrap().is_some()); + if net.peer(1).client().header(small_hash).unwrap().is_none() { return Poll::Pending } Poll::Ready(()) @@ -449,7 +449,7 @@ async fn can_sync_small_non_best_forks() { net.peer(0).announce_block(another_fork, None); futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); - if net.peer(1).client().header(&BlockId::Hash(another_fork)).unwrap().is_none() { + if net.peer(1).client().header(another_fork).unwrap().is_none() { return Poll::Pending } Poll::Ready(()) @@ -478,7 +478,7 @@ async fn can_sync_forks_ahead_of_the_best_chain() { .unwrap(); // 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!(net.peer(0).client().header(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); @@ -486,7 +486,7 @@ async fn can_sync_forks_ahead_of_the_best_chain() { futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); - if net.peer(1).client().header(&BlockId::Hash(fork_hash)).unwrap().is_none() { + if net.peer(1).client().header(fork_hash).unwrap().is_none() { return Poll::Pending } Poll::Ready(()) @@ -512,8 +512,8 @@ async fn can_sync_explicit_forks() { net.peer(1).push_blocks(10, false); assert_eq!(net.peer(1).client().info().best_number, 40); - assert!(net.peer(0).client().header(&BlockId::Hash(small_hash)).unwrap().is_some()); - assert!(net.peer(1).client().header(&BlockId::Hash(small_hash)).unwrap().is_none()); + assert!(net.peer(0).client().header(small_hash).unwrap().is_some()); + assert!(net.peer(1).client().header(small_hash).unwrap().is_none()); // poll until the two nodes connect, otherwise announcing the block will not work futures::future::poll_fn::<(), _>(|cx| { @@ -530,8 +530,8 @@ async fn can_sync_explicit_forks() { assert_eq!(net.peer(0).client().info().best_number, 40); - assert!(net.peer(0).client().header(&BlockId::Hash(small_hash)).unwrap().is_some()); - assert!(!net.peer(1).client().header(&BlockId::Hash(small_hash)).unwrap().is_some()); + assert!(net.peer(0).client().header(small_hash).unwrap().is_some()); + assert!(!net.peer(1).client().header(small_hash).unwrap().is_some()); // request explicit sync let first_peer_id = net.peer(0).id(); @@ -541,8 +541,8 @@ async fn can_sync_explicit_forks() { futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); - assert!(net.peer(0).client().header(&BlockId::Hash(small_hash)).unwrap().is_some()); - if net.peer(1).client().header(&BlockId::Hash(small_hash)).unwrap().is_none() { + assert!(net.peer(0).client().header(small_hash).unwrap().is_some()); + if net.peer(1).client().header(small_hash).unwrap().is_none() { return Poll::Pending } Poll::Ready(()) @@ -634,7 +634,7 @@ async fn imports_stale_once() { futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); - if net.peer(1).client().header(&BlockId::Hash(hash)).unwrap().is_some() { + if net.peer(1).client().header(hash).unwrap().is_some() { Poll::Ready(()) } else { Poll::Pending @@ -992,9 +992,8 @@ async fn multiple_requests_are_accepted_as_long_as_they_are_not_fulfilled() { let hashes = net.peer(0).push_blocks(10, false); net.run_until_sync().await; - let hashof10 = hashes[9]; - // there's currently no justification for block #10 + let hashof10 = hashes[9]; assert_eq!(net.peer(0).client().justifications(hashof10).unwrap(), None); assert_eq!(net.peer(1).client().justifications(hashof10).unwrap(), None); @@ -1061,8 +1060,8 @@ async fn syncs_all_forks_from_single_peer() { net.run_until_sync().await; // Peer 1 should have both branches, - assert!(net.peer(1).client().header(&BlockId::Hash(branch1)).unwrap().is_some()); - assert!(net.peer(1).client().header(&BlockId::Hash(branch2)).unwrap().is_some()); + assert!(net.peer(1).client().header(branch1).unwrap().is_some()); + assert!(net.peer(1).client().header(branch2).unwrap().is_some()); } #[tokio::test(flavor = "multi_thread", worker_threads = 2)] @@ -1086,7 +1085,7 @@ async fn syncs_after_missing_announcement() { let final_block = net.peer(0).push_blocks_at(BlockId::Number(11), 1, false).pop().unwrap(); net.peer(1).push_blocks_at(BlockId::Number(10), 1, true); net.run_until_sync().await; - assert!(net.peer(1).client().header(&BlockId::Hash(final_block)).unwrap().is_some()); + assert!(net.peer(1).client().header(final_block).unwrap().is_some()); } #[tokio::test(flavor = "multi_thread", worker_threads = 2)] diff --git a/client/offchain/src/lib.rs b/client/offchain/src/lib.rs index 87e79833b9706..6b28d3f8a48e9 100644 --- a/client/offchain/src/lib.rs +++ b/client/offchain/src/lib.rs @@ -375,7 +375,7 @@ mod tests { client.clone(), )); let network = Arc::new(TestNetwork()); - let header = client.header(&BlockId::number(0)).unwrap().unwrap(); + let header = client.header(client.chain_info().genesis_hash).unwrap().unwrap(); // when let offchain = OffchainWorkers::new(client); diff --git a/client/rpc-spec-v2/src/chain_head/chain_head.rs b/client/rpc-spec-v2/src/chain_head/chain_head.rs index c55625e99cd45..c0ba9e165dd04 100644 --- a/client/rpc-spec-v2/src/chain_head/chain_head.rs +++ b/client/rpc-spec-v2/src/chain_head/chain_head.rs @@ -610,7 +610,7 @@ where } self.client - .header(BlockId::Hash(hash)) + .header(hash) .map(|opt_header| opt_header.map(|h| format!("0x{:?}", HexDisplay::from(&h.encode())))) .map_err(ChainHeadRpcError::FetchBlockHeader) .map_err(Into::into) diff --git a/client/rpc/src/chain/chain_full.rs b/client/rpc/src/chain/chain_full.rs index 375e724a33d69..ee7870e0629e0 100644 --- a/client/rpc/src/chain/chain_full.rs +++ b/client/rpc/src/chain/chain_full.rs @@ -62,7 +62,7 @@ where } fn header(&self, hash: Option) -> Result, Error> { - self.client.header(BlockId::Hash(self.unwrap_or_best(hash))).map_err(client_err) + self.client.header(self.unwrap_or_best(hash)).map_err(client_err) } fn block(&self, hash: Option) -> Result>, Error> { @@ -130,7 +130,7 @@ fn subscribe_headers( { // send current head right at the start. let maybe_header = client - .header(BlockId::Hash(best_block_hash())) + .header(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)) diff --git a/client/rpc/src/chain/mod.rs b/client/rpc/src/chain/mod.rs index be06b91ca747f..16e69c0f6324f 100644 --- a/client/rpc/src/chain/mod.rs +++ b/client/rpc/src/chain/mod.rs @@ -31,8 +31,8 @@ use jsonrpsee::{core::RpcResult, types::SubscriptionResult, SubscriptionSink}; use sc_client_api::BlockchainEvents; use sp_rpc::{list::ListOrValue, number::NumberOrHex}; use sp_runtime::{ - generic::{BlockId, SignedBlock}, - traits::{Block as BlockT, Header, NumberFor}, + generic::SignedBlock, + traits::{Block as BlockT, NumberFor}, }; use self::error::Error; @@ -80,11 +80,7 @@ where )) })?; let block_num = >::from(block_num); - Ok(self - .client() - .header(BlockId::number(block_num)) - .map_err(client_err)? - .map(|h| h.hash())) + self.client().hash(block_num).map_err(client_err) }, } } diff --git a/client/rpc/src/dev/mod.rs b/client/rpc/src/dev/mod.rs index 7f4b68f56f6f6..ec9e61678fd71 100644 --- a/client/rpc/src/dev/mod.rs +++ b/client/rpc/src/dev/mod.rs @@ -87,7 +87,7 @@ where let parent_hash = *block.header().parent_hash(); let parent_header = self .client - .header(BlockId::Hash(parent_hash)) + .header(parent_hash) .map_err(|e| Error::BlockQueryError(Box::new(e)))?; if let Some(header) = parent_header { header diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index 64a5f70cc0812..0a26c00485e2f 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -70,10 +70,7 @@ use sp_consensus::block_validation::{ }; use sp_core::traits::{CodeExecutor, SpawnNamed}; use sp_keystore::{CryptoStore, SyncCryptoStore, SyncCryptoStorePtr}; -use sp_runtime::{ - generic::BlockId, - traits::{Block as BlockT, BlockIdTo, NumberFor, Zero}, -}; +use sp_runtime::traits::{Block as BlockT, BlockIdTo, NumberFor, Zero}; use std::{str::FromStr, sync::Arc, time::SystemTime}; /// Full client type. @@ -479,7 +476,7 @@ where sp_session::generate_initial_session_keys( client.clone(), - &BlockId::Hash(chain_info.best_hash), + chain_info.best_hash, config.dev_key_seed.clone().map(|s| vec![s]).unwrap_or_default(), ) .map_err(|e| Error::Application(Box::new(e)))?; diff --git a/client/service/src/client/client.rs b/client/service/src/client/client.rs index f81586d424799..bf25e803f5ab4 100644 --- a/client/service/src/client/client.rs +++ b/client/service/src/client/client.rs @@ -914,7 +914,7 @@ where let header = self .backend .blockchain() - .header(BlockId::Hash(block))? + .header(block)? .expect("Block to finalize expected to be onchain; qed"); operation.notify_finalized = Some(FinalizeSummary { header, finalized, stale_heads }); @@ -1050,9 +1050,9 @@ where /// Get block header by id. pub fn header( &self, - id: &BlockId, + hash: Block::Hash, ) -> sp_blockchain::Result::Header>> { - self.backend.blockchain().header(*id) + self.backend.blockchain().header(hash) } /// Get block body by id. @@ -1069,11 +1069,11 @@ where target_hash: Block::Hash, max_generation: NumberFor, ) -> sp_blockchain::Result> { - let load_header = |id: Block::Hash| -> sp_blockchain::Result { + let load_header = |hash: Block::Hash| -> sp_blockchain::Result { self.backend .blockchain() - .header(BlockId::Hash(id))? - .ok_or_else(|| Error::UnknownBlock(format!("{:?}", id))) + .header(hash)? + .ok_or_else(|| Error::UnknownBlock(format!("{:?}", hash))) }; let genesis_hash = self.backend.blockchain().info().genesis_hash; @@ -1552,7 +1552,7 @@ where ) -> sp_blockchain::Result> { Ok(Client::uncles(self, target_hash, max_generation)? .into_iter() - .filter_map(|hash| Client::header(self, &BlockId::Hash(hash)).unwrap_or(None)) + .filter_map(|hash| Client::header(self, hash).unwrap_or(None)) .collect()) } } @@ -1564,8 +1564,8 @@ where Block: BlockT, RA: Send + Sync, { - fn header(&self, id: BlockId) -> sp_blockchain::Result> { - self.backend.blockchain().header(id) + fn header(&self, hash: Block::Hash) -> sp_blockchain::Result> { + self.backend.blockchain().header(hash) } fn info(&self) -> blockchain::Info { @@ -1616,8 +1616,8 @@ where Block: BlockT, RA: Send + Sync, { - fn header(&self, id: BlockId) -> sp_blockchain::Result> { - self.backend.blockchain().header(id) + fn header(&self, hash: Block::Hash) -> sp_blockchain::Result> { + self.backend.blockchain().header(hash) } fn info(&self) -> blockchain::Info { @@ -1948,15 +1948,13 @@ where } fn block(&self, id: &BlockId) -> sp_blockchain::Result>> { - Ok(match self.header(id)? { - Some(header) => { - let hash = header.hash(); - match (self.body(hash)?, self.justifications(hash)?) { - (Some(extrinsics), justifications) => + Ok(match self.backend.blockchain().block_hash_from_id(id)? { + Some(hash) => + match (self.header(hash)?, self.body(hash)?, self.justifications(hash)?) { + (Some(header), 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 e0b07b39cd7e4..661cf83fc49bf 100644 --- a/client/service/test/src/client/mod.rs +++ b/client/service/test/src/client/mod.rs @@ -1141,13 +1141,22 @@ fn get_block_by_bad_block_hash_returns_none() { } #[test] -fn get_header_by_block_number_doesnt_panic() { +fn expect_block_hash_by_block_number_doesnt_panic() { let client = substrate_test_runtime_client::new(); // backend uses u32 for block numbers, make sure we don't panic when // trying to convert let id = BlockId::::Number(72340207214430721); - client.header(&id).expect_err("invalid block number overflows u32"); + client.block_hash_from_id(&id).expect_err("invalid block number overflows u32"); +} + +#[test] +fn get_hash_by_block_number_doesnt_panic() { + let client = substrate_test_runtime_client::new(); + + // backend uses u32 for block numbers, make sure we don't panic when + // trying to convert + client.hash(72340207214430721).expect_err("invalid block number overflows u32"); } #[test] diff --git a/client/sync-state-rpc/src/lib.rs b/client/sync-state-rpc/src/lib.rs index 9540d94c57918..9edc2ceecb78f 100644 --- a/client/sync-state-rpc/src/lib.rs +++ b/client/sync-state-rpc/src/lib.rs @@ -48,10 +48,7 @@ use jsonrpsee::{ }; use sc_client_api::StorageData; use sp_blockchain::HeaderBackend; -use sp_runtime::{ - generic::BlockId, - traits::{Block as BlockT, NumberFor}, -}; +use sp_runtime::traits::{Block as BlockT, NumberFor}; use std::sync::Arc; type SharedAuthoritySet = @@ -164,7 +161,7 @@ where let finalized_hash = self.client.info().finalized_hash; let finalized_header = self .client - .header(BlockId::Hash(finalized_hash))? + .header(finalized_hash)? .ok_or_else(|| sp_blockchain::Error::MissingHeader(finalized_hash.to_string()))?; let finalized_block_weight = diff --git a/client/tracing/src/block/mod.rs b/client/tracing/src/block/mod.rs index 63fd1de374cba..89c0945e0eb03 100644 --- a/client/tracing/src/block/mod.rs +++ b/client/tracing/src/block/mod.rs @@ -217,10 +217,9 @@ where pub fn trace_block(&self) -> TraceBlockResult { tracing::debug!(target: "state_tracing", "Tracing block: {}", self.block); // Prepare the block - let id = BlockId::Hash(self.block); let mut header = self .client - .header(id) + .header(self.block) .map_err(Error::InvalidBlockId)? .ok_or_else(|| Error::MissingBlockComponent("Header not found".to_string()))?; let extrinsics = self @@ -298,7 +297,7 @@ where }) } else { TraceBlockResponse::BlockTrace(BlockTrace { - block_hash: block_id_as_string(id), + block_hash: block_id_as_string(BlockId::::Hash(self.block)), parent_hash: block_id_as_string(parent_id), tracing_targets: targets.to_string(), storage_keys: self.storage_keys.clone().unwrap_or_default(), diff --git a/client/transaction-pool/benches/basics.rs b/client/transaction-pool/benches/basics.rs index 602e84b47775c..97d8edddffdbc 100644 --- a/client/transaction-pool/benches/basics.rs +++ b/client/transaction-pool/benches/basics.rs @@ -117,7 +117,7 @@ impl ChainApi for TestApi { fn block_header( &self, - _: &BlockId, + _: ::Hash, ) -> Result::Header>, Self::Error> { Ok(None) } diff --git a/client/transaction-pool/src/api.rs b/client/transaction-pool/src/api.rs index c3f9b50f9482d..a2b317cfb3998 100644 --- a/client/transaction-pool/src/api.rs +++ b/client/transaction-pool/src/api.rs @@ -190,9 +190,9 @@ where fn block_header( &self, - at: &BlockId, + hash: ::Hash, ) -> Result::Header>, Self::Error> { - self.client.header(*at).map_err(Into::into) + self.client.header(hash).map_err(Into::into) } fn tree_route( diff --git a/client/transaction-pool/src/graph/pool.rs b/client/transaction-pool/src/graph/pool.rs index 9c747ade1229a..96cbeb9b80cfb 100644 --- a/client/transaction-pool/src/graph/pool.rs +++ b/client/transaction-pool/src/graph/pool.rs @@ -96,7 +96,7 @@ pub trait ChainApi: Send + Sync { /// Returns a block header given the block id. fn block_header( &self, - at: &BlockId, + at: ::Hash, ) -> Result::Header>, Self::Error>; /// Compute a tree-route between two blocks. See [`TreeRoute`] for more details. diff --git a/client/transaction-pool/src/lib.rs b/client/transaction-pool/src/lib.rs index 0124038b75949..f3797b180f14d 100644 --- a/client/transaction-pool/src/lib.rs +++ b/client/transaction-pool/src/lib.rs @@ -556,7 +556,7 @@ async fn prune_known_txs_for_block h, Ok(None) => { log::debug!(target: "txpool", "Could not find header for {:?}.", block_hash); diff --git a/client/transaction-pool/src/tests.rs b/client/transaction-pool/src/tests.rs index d8732077eba52..d399367eae818 100644 --- a/client/transaction-pool/src/tests.rs +++ b/client/transaction-pool/src/tests.rs @@ -170,7 +170,7 @@ impl ChainApi for TestApi { fn block_header( &self, - _: &BlockId, + _: ::Hash, ) -> Result::Header>, Self::Error> { Ok(None) } diff --git a/primitives/blockchain/src/backend.rs b/primitives/blockchain/src/backend.rs index 33edc56d4b6ba..6199fd25d0fca 100644 --- a/primitives/blockchain/src/backend.rs +++ b/primitives/blockchain/src/backend.rs @@ -33,7 +33,7 @@ use crate::error::{Error, Result}; /// Blockchain database header backend. Does not perform any validation. pub trait HeaderBackend: Send + Sync { /// Get block header. Returns `None` if block is not found. - fn header(&self, id: BlockId) -> Result>; + fn header(&self, hash: Block::Hash) -> Result>; /// Get blockchain info. fn info(&self) -> Info; /// Get block status. @@ -63,9 +63,9 @@ pub trait HeaderBackend: Send + Sync { } /// Get block header. Returns `UnknownBlock` error if block is not found. - fn expect_header(&self, id: BlockId) -> Result { - self.header(id)? - .ok_or_else(|| Error::UnknownBlock(format!("Expect header: {}", id))) + fn expect_header(&self, hash: Block::Hash) -> Result { + self.header(hash)? + .ok_or_else(|| Error::UnknownBlock(format!("Expect header: {}", hash))) } /// Convert an arbitrary block ID into a block number. Returns `UnknownBlock` error if block is @@ -201,7 +201,7 @@ pub trait Backend: import_lock: &RwLock<()>, ) -> Result> { let target_header = { - match self.header(BlockId::Hash(target_hash))? { + match self.header(target_hash)? { Some(x) => x, // target not in blockchain None => return Ok(None), @@ -256,7 +256,7 @@ pub trait Backend: if let Some(max_number) = maybe_max_number { loop { let current_header = self - .header(BlockId::Hash(current_hash))? + .header(current_hash)? .ok_or_else(|| Error::MissingHeader(current_hash.to_string()))?; if current_header.number() <= &max_number { @@ -276,7 +276,7 @@ pub trait Backend: } let current_header = self - .header(BlockId::Hash(current_hash))? + .header(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/session/src/lib.rs b/primitives/session/src/lib.rs index dde262738ad71..9b403409c9151 100644 --- a/primitives/session/src/lib.rs +++ b/primitives/session/src/lib.rs @@ -110,7 +110,7 @@ impl GetValidatorCount for MembershipProof { #[cfg(feature = "std")] pub fn generate_initial_session_keys( client: std::sync::Arc, - at: &BlockId, + at: Block::Hash, seeds: Vec, ) -> Result<(), sp_api::ApiError> where @@ -125,7 +125,7 @@ where let runtime_api = client.runtime_api(); for seed in seeds { - runtime_api.generate_session_keys(at, Some(seed.as_bytes().to_vec()))?; + runtime_api.generate_session_keys(&BlockId::Hash(at), Some(seed.as_bytes().to_vec()))?; } Ok(()) diff --git a/test-utils/runtime/client/src/trait_tests.rs b/test-utils/runtime/client/src/trait_tests.rs index 65aa3e65e6141..19772c8c94067 100644 --- a/test-utils/runtime/client/src/trait_tests.rs +++ b/test-utils/runtime/client/src/trait_tests.rs @@ -430,21 +430,10 @@ where let genesis_hash = client.chain_info().genesis_hash; - assert_eq!(blockchain.header(BlockId::Number(0)).unwrap().unwrap().hash(), genesis_hash); assert_eq!(blockchain.hash(0).unwrap().unwrap(), genesis_hash); - - assert_eq!(blockchain.header(BlockId::Number(1)).unwrap().unwrap().hash(), a1.hash()); assert_eq!(blockchain.hash(1).unwrap().unwrap(), a1.hash()); - - assert_eq!(blockchain.header(BlockId::Number(2)).unwrap().unwrap().hash(), a2.hash()); assert_eq!(blockchain.hash(2).unwrap().unwrap(), a2.hash()); - - assert_eq!(blockchain.header(BlockId::Number(3)).unwrap().unwrap().hash(), a3.hash()); assert_eq!(blockchain.hash(3).unwrap().unwrap(), a3.hash()); - - assert_eq!(blockchain.header(BlockId::Number(4)).unwrap().unwrap().hash(), a4.hash()); assert_eq!(blockchain.hash(4).unwrap().unwrap(), a4.hash()); - - assert_eq!(blockchain.header(BlockId::Number(5)).unwrap().unwrap().hash(), a5.hash()); assert_eq!(blockchain.hash(5).unwrap().unwrap(), a5.hash()); } diff --git a/test-utils/runtime/transaction-pool/src/lib.rs b/test-utils/runtime/transaction-pool/src/lib.rs index f8d551a6fa5bd..aadd83c00e351 100644 --- a/test-utils/runtime/transaction-pool/src/lib.rs +++ b/test-utils/runtime/transaction-pool/src/lib.rs @@ -326,14 +326,9 @@ impl sc_transaction_pool::ChainApi for TestApi { fn block_header( &self, - at: &BlockId, + hash: ::Hash, ) -> Result::Header>, Self::Error> { - Ok(match at { - BlockId::Number(num) => - self.chain.read().block_by_number.get(num).map(|b| b[0].0.header().clone()), - BlockId::Hash(hash) => - self.chain.read().block_by_hash.get(hash).map(|b| b.header().clone()), - }) + Ok(self.chain.read().block_by_hash.get(&hash).map(|b| b.header().clone())) } fn tree_route( diff --git a/utils/frame/benchmarking-cli/src/storage/write.rs b/utils/frame/benchmarking-cli/src/storage/write.rs index 55a7b60d55552..1917bc5f8fd07 100644 --- a/utils/frame/benchmarking-cli/src/storage/write.rs +++ b/utils/frame/benchmarking-cli/src/storage/write.rs @@ -21,10 +21,7 @@ use sc_client_db::{DbHash, DbState, DbStateBuilder}; 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_runtime::traits::{Block as BlockT, HashFor, Header as HeaderT}; use sp_trie::PrefixedMemoryDB; use log::{info, trace}; @@ -58,7 +55,7 @@ impl StorageCmd { let mut record = BenchRecord::default(); let best_hash = client.usage_info().chain.best_hash; - let header = client.header(BlockId::Hash(best_hash))?.ok_or("Header not found")?; + let header = client.header(best_hash)?.ok_or("Header not found")?; let original_root = *header.state_root(); let trie = DbStateBuilder::::new(storage.clone(), original_root).build(); From a8b46dacd77e7beffeb0cf91c61fde9ea0c18d2a 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, 20 Dec 2022 16:56:27 -0300 Subject: [PATCH 211/715] remove hardcoded crate versions from tests (#12950) --- frame/support/test/tests/construct_runtime.rs | 31 +++++----- frame/support/test/tests/pallet_instance.rs | 57 +++++++------------ 2 files changed, 35 insertions(+), 53 deletions(-) diff --git a/frame/support/test/tests/construct_runtime.rs b/frame/support/test/tests/construct_runtime.rs index b1ace12936241..18e4af1ac3739 100644 --- a/frame/support/test/tests/construct_runtime.rs +++ b/frame/support/test/tests/construct_runtime.rs @@ -22,10 +22,7 @@ #![recursion_limit = "128"] use codec::MaxEncodedLen; -use frame_support::{ - parameter_types, - traits::{CrateVersion, PalletInfo as _}, -}; +use frame_support::{parameter_types, traits::PalletInfo as _}; use scale_info::TypeInfo; use sp_core::{sr25519, H256}; use sp_runtime::{ @@ -733,65 +730,65 @@ 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!(PalletInfo::crate_version::().is_some()); 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!(PalletInfo::crate_version::().is_some()); 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!(PalletInfo::crate_version::().is_some()); 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!(PalletInfo::crate_version::().is_some()); 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!(PalletInfo::crate_version::().is_some()); 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!(PalletInfo::crate_version::().is_some()); 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!(PalletInfo::crate_version::().is_some()); 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!(PalletInfo::crate_version::().is_some()); 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!(PalletInfo::crate_version::().is_some()); 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!(PalletInfo::crate_version::().is_some()); 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!(PalletInfo::crate_version::().is_some()); 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!(PalletInfo::crate_version::().is_some()); 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)); + assert!(PalletInfo::crate_version::().is_some()); } diff --git a/frame/support/test/tests/pallet_instance.rs b/frame/support/test/tests/pallet_instance.rs index d8ad13ceda1dd..7fec0aa9d0e07 100644 --- a/frame/support/test/tests/pallet_instance.rs +++ b/frame/support/test/tests/pallet_instance.rs @@ -619,44 +619,29 @@ fn storage_expand() { #[test] fn pallet_metadata_expands() { - use frame_support::traits::{CrateVersion, PalletInfoData, PalletsInfoAccess}; + use frame_support::traits::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 }, - }, - ] - ); + + assert_eq!(infos[0].index, 0); + assert_eq!(infos[0].name, "System"); + assert_eq!(infos[0].module_name, "frame_system"); + + assert_eq!(infos[1].index, 1); + assert_eq!(infos[1].name, "Example"); + assert_eq!(infos[1].module_name, "pallet"); + + assert_eq!(infos[2].index, 2); + assert_eq!(infos[2].name, "Instance1Example"); + assert_eq!(infos[2].module_name, "pallet"); + + assert_eq!(infos[3].index, 3); + assert_eq!(infos[3].name, "Example2"); + assert_eq!(infos[3].module_name, "pallet2"); + + assert_eq!(infos[4].index, 4); + assert_eq!(infos[4].name, "Instance1Example2"); + assert_eq!(infos[4].module_name, "pallet2"); } #[test] From ce025f3a989d165225c0f2f7ab497cf53319dd6d Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Wed, 21 Dec 2022 11:25:16 +0100 Subject: [PATCH 212/715] BlockId removal: refactor: HeaderBackend::status (#12981) It changes the arguments of `HeaderBackend::status` method from: `BlockId` to: `Block::Hash` This PR is part of BlockId::Number refactoring analysis (paritytech/substrate#11292) Co-authored-by: parity-processbot <> --- client/api/src/in_mem.rs | 4 ++-- client/authority-discovery/src/worker/tests.rs | 2 +- client/consensus/babe/src/lib.rs | 2 +- client/db/src/lib.rs | 10 +++------- client/finality-grandpa/src/import.rs | 2 +- client/merkle-mountain-range/src/test_utils.rs | 4 ++-- client/service/src/client/client.rs | 14 +++++++------- primitives/blockchain/src/backend.rs | 2 +- 8 files changed, 18 insertions(+), 22 deletions(-) diff --git a/client/api/src/in_mem.rs b/client/api/src/in_mem.rs index 58add087074b6..144aa352f5533 100644 --- a/client/api/src/in_mem.rs +++ b/client/api/src/in_mem.rs @@ -359,8 +359,8 @@ impl HeaderBackend for Blockchain { } } - fn status(&self, id: BlockId) -> sp_blockchain::Result { - match self.id(id).map_or(false, |hash| self.storage.read().blocks.contains_key(&hash)) { + fn status(&self, hash: Block::Hash) -> sp_blockchain::Result { + match self.storage.read().blocks.contains_key(&hash) { true => Ok(BlockStatus::InChain), false => Ok(BlockStatus::Unknown), } diff --git a/client/authority-discovery/src/worker/tests.rs b/client/authority-discovery/src/worker/tests.rs index ea0c16eca8063..ce55728a1bfa6 100644 --- a/client/authority-discovery/src/worker/tests.rs +++ b/client/authority-discovery/src/worker/tests.rs @@ -78,7 +78,7 @@ impl HeaderBackend for TestApi { fn status( &self, - _id: BlockId, + _hash: Block::Hash, ) -> std::result::Result { Ok(sc_client_api::blockchain::BlockStatus::Unknown) } diff --git a/client/consensus/babe/src/lib.rs b/client/consensus/babe/src/lib.rs index 9134da0b83d52..1d5d4b5fe5413 100644 --- a/client/consensus/babe/src/lib.rs +++ b/client/consensus/babe/src/lib.rs @@ -1402,7 +1402,7 @@ where // early exit if block already in chain, otherwise the check for // epoch changes will error when trying to re-import an epoch change - match self.client.status(BlockId::Hash(hash)) { + match self.client.status(hash) { Ok(sp_blockchain::BlockStatus::InChain) => { // When re-importing existing block strip away intermediates. let _ = block.remove_intermediate::>(INTERMEDIATE_KEY); diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index b1f5a6edcd52f..3e6332732d672 100644 --- a/client/db/src/lib.rs +++ b/client/db/src/lib.rs @@ -553,12 +553,8 @@ impl sc_client_api::blockchain::HeaderBackend for Blockcha } } - fn status(&self, id: BlockId) -> ClientResult { - let exists = match id { - BlockId::Hash(hash) => self.header(hash)?.is_some(), - BlockId::Number(n) => n <= self.meta.read().best_number, - }; - match exists { + fn status(&self, hash: Block::Hash) -> ClientResult { + match self.header(hash)?.is_some() { true => Ok(sc_client_api::blockchain::BlockStatus::InChain), false => Ok(sc_client_api::blockchain::BlockStatus::Unknown), } @@ -1223,7 +1219,7 @@ impl Backend { } let parent_exists = - self.blockchain.status(BlockId::Hash(route_to))? == sp_blockchain::BlockStatus::InChain; + self.blockchain.status(route_to)? == sp_blockchain::BlockStatus::InChain; // Cannot find tree route with empty DB or when imported a detached block. if meta.best_hash != Default::default() && parent_exists { diff --git a/client/finality-grandpa/src/import.rs b/client/finality-grandpa/src/import.rs index 1359110132c55..ed6e4a0fa2e9f 100644 --- a/client/finality-grandpa/src/import.rs +++ b/client/finality-grandpa/src/import.rs @@ -534,7 +534,7 @@ where // early exit if block already in chain, otherwise the check for // authority changes will error when trying to re-import a change block - match self.inner.status(BlockId::Hash(hash)) { + match self.inner.status(hash) { Ok(BlockStatus::InChain) => { // Strip justifications when re-importing an existing block. let _justifications = block.justifications.take(); diff --git a/client/merkle-mountain-range/src/test_utils.rs b/client/merkle-mountain-range/src/test_utils.rs index 1bc7a9bd5bbac..39570e0d2384f 100644 --- a/client/merkle-mountain-range/src/test_utils.rs +++ b/client/merkle-mountain-range/src/test_utils.rs @@ -234,8 +234,8 @@ impl HeaderBackend for MockClient { self.client.lock().info() } - fn status(&self, id: BlockId) -> sc_client_api::blockchain::Result { - self.client.lock().status(id) + fn status(&self, hash: Hash) -> sc_client_api::blockchain::Result { + self.client.lock().status(hash) } fn number(&self, hash: Hash) -> sc_client_api::blockchain::Result> { diff --git a/client/service/src/client/client.rs b/client/service/src/client/client.rs index bf25e803f5ab4..493fd320b7b23 100644 --- a/client/service/src/client/client.rs +++ b/client/service/src/client/client.rs @@ -552,9 +552,9 @@ where CoreApi + ApiExt, { 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; + let status = self.backend.blockchain().status(hash)?; + let parent_exists = + self.backend.blockchain().status(parent_hash)? == blockchain::BlockStatus::InChain; match (import_existing, status) { (false, blockchain::BlockStatus::InChain) => return Ok(ImportResult::AlreadyInChain), (false, blockchain::BlockStatus::Unknown) => {}, @@ -1572,8 +1572,8 @@ where self.backend.blockchain().info() } - fn status(&self, id: BlockId) -> sp_blockchain::Result { - self.backend.blockchain().status(id) + fn status(&self, hash: Block::Hash) -> sp_blockchain::Result { + self.backend.blockchain().status(hash) } fn number( @@ -1624,8 +1624,8 @@ where self.backend.blockchain().info() } - fn status(&self, id: BlockId) -> sp_blockchain::Result { - (**self).status(id) + fn status(&self, hash: Block::Hash) -> sp_blockchain::Result { + (**self).status(hash) } fn number( diff --git a/primitives/blockchain/src/backend.rs b/primitives/blockchain/src/backend.rs index 6199fd25d0fca..ec9c8ac0d5780 100644 --- a/primitives/blockchain/src/backend.rs +++ b/primitives/blockchain/src/backend.rs @@ -37,7 +37,7 @@ pub trait HeaderBackend: Send + Sync { /// Get blockchain info. fn info(&self) -> Info; /// Get block status. - fn status(&self, id: BlockId) -> Result; + fn status(&self, hash: Block::Hash) -> Result; /// Get block number by hash. Returns `None` if the header is not in the chain. fn number( &self, From 8e76398fa1f070a1361a77b04269c2c59c08d76a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dino=20Pa=C4=8Dandi?= <3002868+Dinonard@users.noreply.github.com> Date: Wed, 21 Dec 2022 14:03:49 +0100 Subject: [PATCH 213/715] Add CallbackHandle to pallet-assets (#12307) * Add CallbackHandle to pallet-assets * Address review comments * Add use for sp_io::storage * Rebase & review comments * Fix UT Co-authored-by: Hoon Kim --- bin/node/runtime/src/lib.rs | 1 + frame/assets/src/functions.rs | 4 ++- frame/assets/src/lib.rs | 29 +++++++++++++++++- frame/assets/src/mock.rs | 19 +++++++++++- frame/assets/src/tests.rs | 30 +++++++++++++++++++ .../asset-tx-payment/src/tests.rs | 1 + 6 files changed, 81 insertions(+), 3 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 0e3bee8821fc2..e5776e3fd692c 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1478,6 +1478,7 @@ impl pallet_assets::Config for Runtime { type StringLimit = StringLimit; type Freezer = (); type Extra = (); + type CallbackHandle = (); type WeightInfo = pallet_assets::weights::SubstrateWeight; type RemoveItemsLimit = ConstU32<1000>; #[cfg(feature = "runtime-benchmarks")] diff --git a/frame/assets/src/functions.rs b/frame/assets/src/functions.rs index f7f11cafecbe2..2cdf2d7c4c8f6 100644 --- a/frame/assets/src/functions.rs +++ b/frame/assets/src/functions.rs @@ -664,7 +664,8 @@ impl, I: 'static> Pallet { status: AssetStatus::Live, }, ); - Self::deposit_event(Event::ForceCreated { asset_id: id, owner }); + Self::deposit_event(Event::ForceCreated { asset_id: id, owner: owner.clone() }); + T::CallbackHandle::created(&id, &owner); Ok(()) } @@ -754,6 +755,7 @@ impl, I: 'static> Pallet { approvals_destroyed: removed_approvals as u32, approvals_remaining: details.approvals as u32, }); + T::CallbackHandle::destroyed(&id); Ok(()) })?; Ok(removed_approvals) diff --git a/frame/assets/src/lib.rs b/frame/assets/src/lib.rs index ab589c0eef0f4..1853ef75f52be 100644 --- a/frame/assets/src/lib.rs +++ b/frame/assets/src/lib.rs @@ -116,6 +116,11 @@ //! //! Please refer to the [`Pallet`] struct for details on publicly available functions. //! +//! ### Callbacks +//! +//! Using `CallbackHandle` associated type, user can configure custom callback functions which are +//! executed when new asset is created or an existing asset is destroyed. +//! //! ## Related Modules //! //! * [`System`](../frame_system/index.html) @@ -171,6 +176,18 @@ pub use weights::WeightInfo; type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; +/// Trait with callbacks that are executed after successfull asset creation or destruction. +pub trait AssetsCallback { + /// Indicates that asset with `id` was successfully created by the `owner` + fn created(_id: &AssetId, _owner: &AccountId) {} + + /// Indicates that asset with `id` has just been destroyed + fn destroyed(_id: &AssetId) {} +} + +/// Empty implementation in case no callbacks are required. +impl AssetsCallback for () {} + #[frame_support::pallet] pub mod pallet { use super::*; @@ -283,6 +300,9 @@ pub mod pallet { /// Additional data to be stored with an account's asset balance. type Extra: Member + Parameter + Default + MaxEncodedLen; + /// Callback methods for asset state change (e.g. asset created or destroyed) + type CallbackHandle: AssetsCallback; + /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; @@ -598,7 +618,14 @@ pub mod pallet { status: AssetStatus::Live, }, ); - Self::deposit_event(Event::Created { asset_id: id, creator: owner, owner: admin }); + + Self::deposit_event(Event::Created { + asset_id: id, + creator: owner.clone(), + owner: admin, + }); + T::CallbackHandle::created(&id, &owner); + Ok(()) } diff --git a/frame/assets/src/mock.rs b/frame/assets/src/mock.rs index 06b6ccf06c57e..93a87ee6714c6 100644 --- a/frame/assets/src/mock.rs +++ b/frame/assets/src/mock.rs @@ -20,11 +20,13 @@ use super::*; use crate as pallet_assets; +use codec::Encode; use frame_support::{ construct_runtime, parameter_types, traits::{AsEnsureOriginWithArg, ConstU32, ConstU64, GenesisBuild}, }; use sp_core::H256; +use sp_io::storage; use sp_runtime::{ testing::Header, traits::{BlakeTwo256, IdentityLookup}, @@ -45,6 +47,9 @@ construct_runtime!( } ); +type AccountId = u64; +type AssetId = u32; + impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); @@ -55,7 +60,7 @@ impl frame_system::Config for Test { type BlockNumber = u64; type Hash = H256; type Hashing = BlakeTwo256; - type AccountId = u64; + type AccountId = AccountId; type Lookup = IdentityLookup; type Header = Header; type RuntimeEvent = RuntimeEvent; @@ -84,6 +89,17 @@ impl pallet_balances::Config for Test { type ReserveIdentifier = [u8; 8]; } +pub struct AssetsCallbackHandle; +impl AssetsCallback for AssetsCallbackHandle { + fn created(_id: &AssetId, _owner: &AccountId) { + storage::set(b"asset_created", &().encode()); + } + + fn destroyed(_id: &AssetId) { + storage::set(b"asset_destroyed", &().encode()); + } +} + impl Config for Test { type RuntimeEvent = RuntimeEvent; type Balance = u64; @@ -100,6 +116,7 @@ impl Config for Test { type StringLimit = ConstU32<50>; type Freezer = TestFreezer; type WeightInfo = (); + type CallbackHandle = AssetsCallbackHandle; type Extra = (); type RemoveItemsLimit = ConstU32<5>; #[cfg(feature = "runtime-benchmarks")] diff --git a/frame/assets/src/tests.rs b/frame/assets/src/tests.rs index d5fcece0e91d8..f7007ff3ccf17 100644 --- a/frame/assets/src/tests.rs +++ b/frame/assets/src/tests.rs @@ -24,6 +24,7 @@ use frame_support::{ traits::{fungibles::InspectEnumerable, Currency}, }; use pallet_balances::Error as BalancesError; +use sp_io::storage; use sp_runtime::{traits::ConvertInto, TokenError}; fn asset_ids() -> Vec { @@ -1194,3 +1195,32 @@ fn querying_roles_should_work() { assert_eq!(Assets::freezer(0), Some(4)); }); } + +#[test] +fn normal_asset_create_and_destroy_callbacks_should_work() { + new_test_ext().execute_with(|| { + assert!(storage::get(b"asset_created").is_none()); + assert!(storage::get(b"asset_destroyed").is_none()); + + Balances::make_free_balance_be(&1, 100); + assert_ok!(Assets::create(RuntimeOrigin::signed(1), 0, 1, 1)); + assert!(storage::get(b"asset_created").is_some()); + assert!(storage::get(b"asset_destroyed").is_none()); + + 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!(storage::get(b"asset_destroyed").is_some()); + }); +} + +#[test] +fn root_asset_create_should_work() { + new_test_ext().execute_with(|| { + assert!(storage::get(b"asset_created").is_none()); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert!(storage::get(b"asset_created").is_some()); + assert!(storage::get(b"asset_destroyed").is_none()); + }); +} diff --git a/frame/transaction-payment/asset-tx-payment/src/tests.rs b/frame/transaction-payment/asset-tx-payment/src/tests.rs index b70a88d02c6e1..b79b87a93c7a4 100644 --- a/frame/transaction-payment/asset-tx-payment/src/tests.rs +++ b/frame/transaction-payment/asset-tx-payment/src/tests.rs @@ -171,6 +171,7 @@ impl pallet_assets::Config for Runtime { type StringLimit = ConstU32<20>; type Freezer = (); type Extra = (); + type CallbackHandle = (); type WeightInfo = (); type RemoveItemsLimit = ConstU32<1000>; pallet_assets::runtime_benchmarks_enabled! { From 5aaf5f42a7850f00b15a14f635b67061d831ac2d Mon Sep 17 00:00:00 2001 From: Muharem Ismailov Date: Wed, 21 Dec 2022 16:25:46 +0100 Subject: [PATCH 214/715] Scheduler: remove empty agenda on cancel (#12989) * Scheduler: remove empty agenda on cancel * use iter any * fix benches * remove trailing None * Add CleanupAgendas migration Signed-off-by: Oliver Tale-Yazdi * fix ci Signed-off-by: Oliver Tale-Yazdi * Count non-empty agendas in migration Signed-off-by: Oliver Tale-Yazdi Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Oliver Tale-Yazdi --- frame/scheduler/src/benchmarking.rs | 24 ++- frame/scheduler/src/lib.rs | 20 +++ frame/scheduler/src/migration.rs | 171 ++++++++++++++++++++++ frame/scheduler/src/tests.rs | 219 ++++++++++++++++++---------- 4 files changed, 353 insertions(+), 81 deletions(-) diff --git a/frame/scheduler/src/benchmarking.rs b/frame/scheduler/src/benchmarking.rs index e621c913b2386..ca98cabc3c08b 100644 --- a/frame/scheduler/src/benchmarking.rs +++ b/frame/scheduler/src/benchmarking.rs @@ -244,13 +244,17 @@ benchmarks! { }: _>(schedule_origin, when, 0) verify { ensure!( - Lookup::::get(u32_to_name(0)).is_none(), - "didn't remove from lookup" + s == 1 || Lookup::::get(u32_to_name(0)).is_none(), + "didn't remove from lookup if more than 1 task scheduled for `when`" ); // Removed schedule is NONE ensure!( - Agenda::::get(when)[0].is_none(), - "didn't remove from schedule" + s == 1 || Agenda::::get(when)[0].is_none(), + "didn't remove from schedule if more than 1 task scheduled for `when`" + ); + ensure!( + s > 1 || Agenda::::get(when).len() == 0, + "remove from schedule if only 1 task scheduled for `when`" ); } @@ -280,13 +284,17 @@ benchmarks! { }: _(RawOrigin::Root, u32_to_name(0)) verify { ensure!( - Lookup::::get(u32_to_name(0)).is_none(), - "didn't remove from lookup" + s == 1 || Lookup::::get(u32_to_name(0)).is_none(), + "didn't remove from lookup if more than 1 task scheduled for `when`" ); // Removed schedule is NONE ensure!( - Agenda::::get(when)[0].is_none(), - "didn't remove from schedule" + s == 1 || Agenda::::get(when)[0].is_none(), + "didn't remove from schedule if more than 1 task scheduled for `when`" + ); + ensure!( + s > 1 || Agenda::::get(when).len() == 0, + "remove from schedule if only 1 task scheduled for `when`" ); } diff --git a/frame/scheduler/src/lib.rs b/frame/scheduler/src/lib.rs index d6a66c5e2cb2c..20e14206767aa 100644 --- a/frame/scheduler/src/lib.rs +++ b/frame/scheduler/src/lib.rs @@ -752,6 +752,22 @@ impl Pallet { Ok(index) } + /// Remove trailing `None` items of an agenda at `when`. If all items are `None` remove the + /// agenda record entirely. + fn cleanup_agenda(when: T::BlockNumber) { + let mut agenda = Agenda::::get(when); + match agenda.iter().rposition(|i| i.is_some()) { + Some(i) if agenda.len() > i + 1 => { + agenda.truncate(i + 1); + Agenda::::insert(when, agenda); + }, + Some(_) => {}, + None => { + Agenda::::remove(when); + }, + } + } + fn do_schedule( when: DispatchTime, maybe_periodic: Option>, @@ -802,6 +818,7 @@ impl Pallet { if let Some(id) = s.maybe_id { Lookup::::remove(id); } + Self::cleanup_agenda(when); Self::deposit_event(Event::Canceled { when, index }); Ok(()) } else { @@ -824,6 +841,7 @@ impl Pallet { ensure!(!matches!(task, Some(Scheduled { maybe_id: Some(_), .. })), Error::::Named); task.take().ok_or(Error::::NotFound) })?; + Self::cleanup_agenda(when); Self::deposit_event(Event::Canceled { when, index }); Self::place_task(new_time, task).map_err(|x| x.0) @@ -880,6 +898,7 @@ impl Pallet { } Ok(()) })?; + Self::cleanup_agenda(when); Self::deposit_event(Event::Canceled { when, index }); Ok(()) } else { @@ -905,6 +924,7 @@ impl Pallet { let task = agenda.get_mut(index as usize).ok_or(Error::::NotFound)?; task.take().ok_or(Error::::NotFound) })?; + Self::cleanup_agenda(when); Self::deposit_event(Event::Canceled { when, index }); Self::place_task(new_time, task).map_err(|x| x.0) } diff --git a/frame/scheduler/src/migration.rs b/frame/scheduler/src/migration.rs index 6769d20023196..97a5ef4c3e883 100644 --- a/frame/scheduler/src/migration.rs +++ b/frame/scheduler/src/migration.rs @@ -198,6 +198,119 @@ pub mod v3 { } } +mod v4 { + use super::*; + use frame_support::pallet_prelude::*; + + /// This migration cleans up empty agendas of the V4 scheduler. + /// + /// This should be run on a scheduler that does not have + /// since it piles up `None`-only agendas. This does not modify the pallet version. + pub struct CleanupAgendas(sp_std::marker::PhantomData); + + impl OnRuntimeUpgrade for CleanupAgendas { + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, &'static str> { + assert_eq!( + StorageVersion::get::>(), + 4, + "Can only cleanup agendas of the V4 scheduler" + ); + + let agendas = Agenda::::iter_keys().count(); + let non_empty_agendas = + Agenda::::iter_values().filter(|a| a.iter().any(|s| s.is_some())).count(); + log::info!( + target: TARGET, + "There are {} total and {} non-empty agendas", + agendas, + non_empty_agendas + ); + + Ok((agendas as u32, non_empty_agendas as u32).encode()) + } + + fn on_runtime_upgrade() -> Weight { + let version = StorageVersion::get::>(); + if version != 4 { + log::warn!(target: TARGET, "Skipping CleanupAgendas migration since it was run on the wrong version: {:?} != 4", version); + return T::DbWeight::get().reads(1) + } + + let keys = Agenda::::iter_keys().collect::>(); + let mut writes = 0; + for k in &keys { + let mut schedules = Agenda::::get(k); + let all_schedules = schedules.len(); + let suffix_none_schedules = + schedules.iter().rev().take_while(|s| s.is_none()).count(); + + match all_schedules.checked_sub(suffix_none_schedules) { + Some(0) => { + log::info!( + "Deleting None-only agenda {:?} with {} entries", + k, + all_schedules + ); + Agenda::::remove(k); + writes.saturating_inc(); + }, + Some(ne) if ne > 0 => { + log::info!( + "Removing {} schedules of {} from agenda {:?}, now {:?}", + suffix_none_schedules, + all_schedules, + ne, + k + ); + schedules.truncate(ne); + Agenda::::insert(k, schedules); + writes.saturating_inc(); + }, + Some(_) => { + frame_support::defensive!( + // Bad but let's not panic. + "Cannot have more None suffix schedules that schedules in total" + ); + }, + None => { + log::info!("Agenda {:?} does not have any None suffix schedules", k); + }, + } + } + + // We don't modify the pallet version. + + T::DbWeight::get().reads_writes(1 + keys.len().saturating_mul(2) as u64, writes) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(state: Vec) -> Result<(), &'static str> { + assert_eq!(StorageVersion::get::>(), 4, "Version must not change"); + + let (old_agendas, non_empty_agendas): (u32, u32) = + Decode::decode(&mut state.as_ref()).expect("Must decode pre_upgrade state"); + let new_agendas = Agenda::::iter_keys().count() as u32; + + match old_agendas.checked_sub(new_agendas) { + Some(0) => log::warn!( + target: TARGET, + "Did not clean up any agendas. v4::CleanupAgendas can be removed." + ), + Some(n) => + log::info!(target: TARGET, "Cleaned up {} agendas, now {}", n, new_agendas), + None => unreachable!( + "Number of agendas cannot increase, old {} new {}", + old_agendas, new_agendas + ), + } + assert_eq!(new_agendas, non_empty_agendas, "Expected to keep all non-empty agendas"); + + Ok(()) + } + } +} + #[cfg(test)] #[cfg(feature = "try-runtime")] mod test { @@ -396,6 +509,64 @@ mod test { }); } + #[test] + fn cleanup_agendas_works() { + use sp_core::bounded_vec; + new_test_ext().execute_with(|| { + StorageVersion::new(4).put::(); + + let call = RuntimeCall::System(frame_system::Call::remark { remark: vec![] }); + let bounded_call = Preimage::bound(call).unwrap(); + let some = Some(ScheduledOf:: { + maybe_id: None, + priority: 1, + call: bounded_call, + maybe_periodic: None, + origin: root(), + _phantom: Default::default(), + }); + + // Put some empty, and some non-empty agendas in there. + let test_data: Vec<( + BoundedVec>, ::MaxScheduledPerBlock>, + Option< + BoundedVec>, ::MaxScheduledPerBlock>, + >, + )> = vec![ + (bounded_vec![some.clone()], Some(bounded_vec![some.clone()])), + (bounded_vec![None, some.clone()], Some(bounded_vec![None, some.clone()])), + (bounded_vec![None, some.clone(), None], Some(bounded_vec![None, some.clone()])), + (bounded_vec![some.clone(), None, None], Some(bounded_vec![some.clone()])), + (bounded_vec![None, None], None), + (bounded_vec![None, None, None], None), + (bounded_vec![], None), + ]; + + // Insert all the agendas. + for (i, test) in test_data.iter().enumerate() { + Agenda::::insert(i as u64, test.0.clone()); + } + + // Run the migration. + let data = v4::CleanupAgendas::::pre_upgrade().unwrap(); + let _w = v4::CleanupAgendas::::on_runtime_upgrade(); + v4::CleanupAgendas::::post_upgrade(data).unwrap(); + + // Check that the post-state is correct. + for (i, test) in test_data.iter().enumerate() { + match test.1.clone() { + None => assert!( + !Agenda::::contains_key(i as u64), + "Agenda {} should be removed", + i + ), + Some(new) => + assert_eq!(Agenda::::get(i as u64), new, "Agenda wrong {}", i), + } + } + }); + } + fn signed(i: u64) -> OriginCaller { system::RawOrigin::Signed(i).into() } diff --git a/frame/scheduler/src/tests.rs b/frame/scheduler/src/tests.rs index 033d787946709..7c261fdd74bfd 100644 --- a/frame/scheduler/src/tests.rs +++ b/frame/scheduler/src/tests.rs @@ -1291,40 +1291,6 @@ fn scheduler_v3_anon_reschedule_works() { }); } -/// 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; @@ -1531,45 +1497,6 @@ fn scheduler_v3_anon_reschedule_fills_holes() { }); } -/// 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() { @@ -1767,3 +1694,149 @@ fn scheduler_v3_named_next_schedule_time_works() { ); }); } + +#[test] +fn cancel_last_task_removes_agenda() { + new_test_ext().execute_with(|| { + let when = 4; + let call = + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) }); + let address = Scheduler::do_schedule( + DispatchTime::At(when), + None, + 127, + root(), + Preimage::bound(call.clone()).unwrap(), + ) + .unwrap(); + let address2 = Scheduler::do_schedule( + DispatchTime::At(when), + None, + 127, + root(), + Preimage::bound(call).unwrap(), + ) + .unwrap(); + // two tasks at agenda. + assert!(Agenda::::get(when).len() == 2); + assert_ok!(Scheduler::do_cancel(None, address)); + // still two tasks at agenda, `None` and `Some`. + assert!(Agenda::::get(when).len() == 2); + // cancel last task from `when` agenda. + assert_ok!(Scheduler::do_cancel(None, address2)); + // if all tasks `None`, agenda fully removed. + assert!(Agenda::::get(when).len() == 0); + }); +} + +#[test] +fn cancel_named_last_task_removes_agenda() { + new_test_ext().execute_with(|| { + let when = 4; + let call = + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) }); + Scheduler::do_schedule_named( + [1u8; 32], + DispatchTime::At(when), + None, + 127, + root(), + Preimage::bound(call.clone()).unwrap(), + ) + .unwrap(); + Scheduler::do_schedule_named( + [2u8; 32], + DispatchTime::At(when), + None, + 127, + root(), + Preimage::bound(call).unwrap(), + ) + .unwrap(); + // two tasks at agenda. + assert!(Agenda::::get(when).len() == 2); + assert_ok!(Scheduler::do_cancel_named(None, [2u8; 32])); + // removes trailing `None` and leaves one task. + assert!(Agenda::::get(when).len() == 1); + // cancel last task from `when` agenda. + assert_ok!(Scheduler::do_cancel_named(None, [1u8; 32])); + // if all tasks `None`, agenda fully removed. + assert!(Agenda::::get(when).len() == 0); + }); +} + +#[test] +fn reschedule_last_task_removes_agenda() { + new_test_ext().execute_with(|| { + let when = 4; + let call = + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) }); + let address = Scheduler::do_schedule( + DispatchTime::At(when), + None, + 127, + root(), + Preimage::bound(call.clone()).unwrap(), + ) + .unwrap(); + let address2 = Scheduler::do_schedule( + DispatchTime::At(when), + None, + 127, + root(), + Preimage::bound(call).unwrap(), + ) + .unwrap(); + // two tasks at agenda. + assert!(Agenda::::get(when).len() == 2); + assert_ok!(Scheduler::do_cancel(None, address)); + // still two tasks at agenda, `None` and `Some`. + assert!(Agenda::::get(when).len() == 2); + // reschedule last task from `when` agenda. + assert_eq!( + Scheduler::do_reschedule(address2, DispatchTime::At(when + 1)).unwrap(), + (when + 1, 0) + ); + // if all tasks `None`, agenda fully removed. + assert!(Agenda::::get(when).len() == 0); + }); +} + +#[test] +fn reschedule_named_last_task_removes_agenda() { + new_test_ext().execute_with(|| { + let when = 4; + let call = + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) }); + Scheduler::do_schedule_named( + [1u8; 32], + DispatchTime::At(when), + None, + 127, + root(), + Preimage::bound(call.clone()).unwrap(), + ) + .unwrap(); + Scheduler::do_schedule_named( + [2u8; 32], + DispatchTime::At(when), + None, + 127, + root(), + Preimage::bound(call).unwrap(), + ) + .unwrap(); + // two tasks at agenda. + assert!(Agenda::::get(when).len() == 2); + assert_ok!(Scheduler::do_cancel_named(None, [1u8; 32])); + // still two tasks at agenda, `None` and `Some`. + assert!(Agenda::::get(when).len() == 2); + // reschedule last task from `when` agenda. + assert_eq!( + Scheduler::do_reschedule_named([2u8; 32], DispatchTime::At(when + 1)).unwrap(), + (when + 1, 0) + ); + // if all tasks `None`, agenda fully removed. + assert!(Agenda::::get(when).len() == 0); + }); +} From 1bcb3ce58418e72c151db797af5df87dcc20130f Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Wed, 21 Dec 2022 17:36:08 +0100 Subject: [PATCH 215/715] txpool: TestApi best_block fix (#12992) This is a minor clean up. There was a minor bug in TestApi::add_block: the best block flag for given number was not cleared when the new best block with the same number was added. The usage of is_best_block argument in add_block method in txpool tests were aligned with the BestBlock event. --- client/transaction-pool/tests/pool.rs | 25 +++++++++++-------- .../runtime/transaction-pool/src/lib.rs | 12 +++++++++ 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/client/transaction-pool/tests/pool.rs b/client/transaction-pool/tests/pool.rs index 7ba61e58b4cb5..27d62c3250abc 100644 --- a/client/transaction-pool/tests/pool.rs +++ b/client/transaction-pool/tests/pool.rs @@ -211,14 +211,18 @@ fn block_event(header: Header) -> ChainEvent { } fn block_event_with_retracted( - header: Header, + new_best_block_header: Header, retracted_start: Hash, api: &TestApi, ) -> ChainEvent { - let tree_route = - api.tree_route(retracted_start, header.parent_hash).expect("Tree route exists"); + let tree_route = api + .tree_route(retracted_start, new_best_block_header.parent_hash) + .expect("Tree route exists"); - ChainEvent::NewBestBlock { hash: header.hash(), tree_route: Some(Arc::new(tree_route)) } + ChainEvent::NewBestBlock { + hash: new_best_block_header.hash(), + tree_route: Some(Arc::new(tree_route)), + } } #[test] @@ -272,7 +276,7 @@ fn should_resubmit_from_retracted_during_maintenance() { assert_eq!(pool.status().ready, 1); let header = api.push_block(1, vec![], true); - let fork_header = api.push_block(1, vec![], false); + let fork_header = api.push_block(1, vec![], true); let event = block_event_with_retracted(header, fork_header.hash(), pool.api()); @@ -290,7 +294,7 @@ fn should_not_resubmit_from_retracted_during_maintenance_if_tx_is_also_in_enacte assert_eq!(pool.status().ready, 1); let header = api.push_block(1, vec![xt.clone()], true); - let fork_header = api.push_block(1, vec![xt], false); + let fork_header = api.push_block(1, vec![xt], true); let event = block_event_with_retracted(header, fork_header.hash(), pool.api()); @@ -309,7 +313,7 @@ fn should_not_retain_invalid_hashes_from_retracted() { assert_eq!(pool.status().ready, 1); let header = api.push_block(1, vec![], true); - let fork_header = api.push_block(1, vec![xt.clone()], false); + let fork_header = api.push_block(1, vec![xt.clone()], true); api.add_invalid(&xt); let event = block_event_with_retracted(header, fork_header.hash(), pool.api()); @@ -649,7 +653,7 @@ fn prune_and_retract_tx_at_same_time() { // Block B2 let b2 = { - let header = pool.api().push_block(2, vec![from_alice.clone()], false); + let header = pool.api().push_block(2, vec![from_alice.clone()], true); assert_eq!(pool.status().ready, 0); let event = block_event_with_retracted(header.clone(), b1, pool.api()); @@ -726,7 +730,8 @@ fn resubmit_tx_of_fork_that_is_not_part_of_retracted() { // Block D2 { - let header = pool.api().push_block(2, vec![], false); + //push new best block + let header = pool.api().push_block(2, vec![], true); let event = block_event_with_retracted(header, d0, pool.api()); block_on(pool.maintain(event)); assert_eq!(pool.status().ready, 2); @@ -1036,7 +1041,7 @@ fn finalized_only_handled_correctly() { .expect("1. Imported"); assert_eq!(pool.status().ready, 1); - let header = api.push_block(1, vec![xt], false); + let header = api.push_block(1, vec![xt], true); let event = ChainEvent::Finalized { hash: header.clone().hash(), tree_route: Arc::from(vec![]) }; diff --git a/test-utils/runtime/transaction-pool/src/lib.rs b/test-utils/runtime/transaction-pool/src/lib.rs index aadd83c00e351..8a648cd003152 100644 --- a/test-utils/runtime/transaction-pool/src/lib.rs +++ b/test-utils/runtime/transaction-pool/src/lib.rs @@ -178,6 +178,18 @@ impl TestApi { let mut chain = self.chain.write(); chain.block_by_hash.insert(hash, block.clone()); + + if is_best_block { + chain + .block_by_number + .entry(*block_number) + .or_default() + .iter_mut() + .for_each(|x| { + x.1 = IsBestBlock::No; + }); + } + chain .block_by_number .entry(*block_number) From ee316317b85b2f65fc022b27bbfefcd42b6560ae Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Wed, 21 Dec 2022 23:00:27 +0100 Subject: [PATCH 216/715] Migration should be pub (#12996) Signed-off-by: Oliver Tale-Yazdi Signed-off-by: Oliver Tale-Yazdi --- frame/scheduler/src/migration.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/scheduler/src/migration.rs b/frame/scheduler/src/migration.rs index 97a5ef4c3e883..f71b9457f5166 100644 --- a/frame/scheduler/src/migration.rs +++ b/frame/scheduler/src/migration.rs @@ -198,7 +198,7 @@ pub mod v3 { } } -mod v4 { +pub mod v4 { use super::*; use frame_support::pallet_prelude::*; From 708626fdfac84909b8de6692415fac9413f97f33 Mon Sep 17 00:00:00 2001 From: Serban Iorga Date: Thu, 22 Dec 2022 13:00:12 +0200 Subject: [PATCH 217/715] Mmr client gadget - support pallet reset (#12999) * Remove unneeded code * Moving some code * Support pallet-mmr reset * Rename update_first_mmr_block Co-authored-by: Adrian Catangiu * Renamings Co-authored-by: Adrian Catangiu --- .../merkle-mountain-range/src/aux_schema.rs | 62 +++--- client/merkle-mountain-range/src/lib.rs | 137 ++++++------ .../merkle-mountain-range/src/offchain_mmr.rs | 199 +++++++++++++----- .../merkle-mountain-range/src/test_utils.rs | 12 ++ .../merkle-mountain-range/src/mmr/storage.rs | 8 - 5 files changed, 270 insertions(+), 148 deletions(-) diff --git a/client/merkle-mountain-range/src/aux_schema.rs b/client/merkle-mountain-range/src/aux_schema.rs index 907deb0bde239..e6c53d4067988 100644 --- a/client/merkle-mountain-range/src/aux_schema.rs +++ b/client/merkle-mountain-range/src/aux_schema.rs @@ -54,8 +54,8 @@ fn load_decode(backend: &B, key: &[u8]) -> ClientResult< } } -/// Load or initialize persistent data from backend. -pub(crate) fn load_persistent(backend: &BE) -> ClientResult>> +/// Load persistent data from backend. +pub(crate) fn load_state(backend: &BE) -> ClientResult>> where B: Block, BE: AuxStore, @@ -73,15 +73,36 @@ where Ok(None) } +/// Load or initialize persistent data from backend. +pub(crate) fn load_or_init_state( + backend: &BE, + default: NumberFor, +) -> sp_blockchain::Result> +where + B: Block, + BE: AuxStore, +{ + // Initialize gadget best_canon from AUX DB or from pallet genesis. + if let Some(best) = load_state::(backend)? { + info!(target: LOG_TARGET, "Loading MMR best canonicalized state from db: {:?}.", best); + Ok(best) + } else { + info!( + target: LOG_TARGET, + "Loading MMR from pallet genesis on what appears to be the first startup: {:?}.", + default + ); + write_current_version(backend)?; + write_gadget_state::(backend, &default)?; + Ok(default) + } +} + #[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 crate::test_utils::{run_test_with_mmr_gadget_pre_post_using_client, MmrBlock, MockClient}; 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}; @@ -92,7 +113,7 @@ pub(crate) mod tests { let backend = &*client.backend; // version not available in db -> None - assert_eq!(load_persistent::(backend).unwrap(), None); + assert_eq!(load_state::(backend).unwrap(), None); // populate version in db write_current_version(backend).unwrap(); @@ -100,7 +121,7 @@ pub(crate) mod tests { 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); + assert_eq!(load_state::(backend).unwrap(), None); } #[test] @@ -113,7 +134,7 @@ pub(crate) mod tests { // 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); + assert_eq!(load_state::(&*backend).unwrap(), None); // run the gadget while importing and finalizing 3 blocks run_test_with_mmr_gadget_pre_post_using_client( client.clone(), @@ -136,7 +157,7 @@ pub(crate) mod tests { 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)); + assert_eq!(load_state::(backend).unwrap(), Some(3)); }, |client| async move { let a4 = client.import_block(&BlockId::Number(3), b"a4", Some(3)).await; @@ -148,7 +169,7 @@ pub(crate) mod tests { // 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)); + assert_eq!(load_state::(&*client.backend).unwrap(), Some(6)); }, ); } @@ -177,19 +198,8 @@ pub(crate) mod tests { 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); - } + client.undo_block_canonicalization(mmr_block) } }, ); @@ -203,7 +213,7 @@ pub(crate) mod tests { 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)); + assert_eq!(load_state::(&*client.backend).unwrap(), Some(3)); // but actually they are NOT canon (we manually reverted them earlier). client.assert_not_canonicalized(&slice); }, @@ -221,7 +231,7 @@ pub(crate) mod tests { // 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)); + assert_eq!(load_state::(&*client.backend).unwrap(), Some(6)); }, ); } diff --git a/client/merkle-mountain-range/src/lib.rs b/client/merkle-mountain-range/src/lib.rs index 401a5d5d4d56b..568c4b94c1e08 100644 --- a/client/merkle-mountain-range/src/lib.rs +++ b/client/merkle-mountain-range/src/lib.rs @@ -46,7 +46,7 @@ use crate::offchain_mmr::OffchainMmr; use beefy_primitives::MmrRootHash; use futures::StreamExt; use log::{debug, error, trace, warn}; -use sc_client_api::{Backend, BlockchainEvents, FinalityNotifications}; +use sc_client_api::{Backend, BlockchainEvents, FinalityNotification, FinalityNotifications}; use sc_offchain::OffchainDb; use sp_api::ProvideRuntimeApi; use sp_blockchain::{HeaderBackend, HeaderMetadata}; @@ -60,6 +60,62 @@ use std::{marker::PhantomData, sync::Arc}; /// Logging target for the mmr gadget. pub const LOG_TARGET: &str = "mmr"; +/// A convenience MMR client trait that defines all the type bounds a MMR client +/// has to satisfy and defines some helper methods. +pub trait MmrClient: + BlockchainEvents + HeaderBackend + HeaderMetadata + ProvideRuntimeApi +where + B: Block, + BE: Backend, + Self::Api: MmrApi>, +{ + /// Get the block number where the mmr pallet was added to the runtime. + fn first_mmr_block_num(&self, notification: &FinalityNotification) -> Option> { + let best_block = *notification.header.number(); + match self.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) => { + debug!( + target: LOG_TARGET, + "pallet-mmr detected at block {:?} with genesis at block {:?}", + best_block, + first_mmr_block + ); + Some(first_mmr_block) + }, + Err(e) => { + error!( + target: LOG_TARGET, + "Error calculating the first mmr block: {:?}", e + ); + None + }, + } + }, + _ => { + trace!( + target: LOG_TARGET, + "pallet-mmr not detected at block {:?} ... (best finalized {:?})", + best_block, + notification.header.number() + ); + None + }, + } + } +} + +impl MmrClient for T +where + B: Block, + BE: Backend, + T: BlockchainEvents + HeaderBackend + HeaderMetadata + ProvideRuntimeApi, + T::Api: MmrApi>, +{ + // empty +} + struct OffchainMmrBuilder, C> { backend: Arc, client: Arc, @@ -73,7 +129,7 @@ impl OffchainMmrBuilder where B: Block, BE: Backend, - C: ProvideRuntimeApi + HeaderBackend + HeaderMetadata, + C: MmrClient, C::Api: MmrApi>, { async fn try_build( @@ -81,66 +137,21 @@ where 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)) => { - 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) => { - 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, - 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(notification); - return Some(offchain_mmr) - }, - Err(e) => { - error!( - target: LOG_TARGET, - "Error calculating the first mmr block: {:?}", e - ); - }, - } - }, - _ => { - trace!( - target: LOG_TARGET, - "Waiting for MMR pallet to become available... (best finalized {:?})", - notification.header.number() - ); - }, + if let Some(first_mmr_block_num) = self.client.first_mmr_block_num(¬ification) { + let mut offchain_mmr = OffchainMmr::new( + self.backend, + self.client, + self.offchain_db, + self.indexing_prefix, + first_mmr_block_num, + )?; + // 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(notification); + return Some(offchain_mmr) } } @@ -165,7 +176,7 @@ where B: Block, ::Number: Into, BE: Backend, - C: BlockchainEvents + HeaderBackend + HeaderMetadata + ProvideRuntimeApi, + C: MmrClient, C::Api: MmrApi>, { async fn run(mut self, builder: OffchainMmrBuilder) { diff --git a/client/merkle-mountain-range/src/offchain_mmr.rs b/client/merkle-mountain-range/src/offchain_mmr.rs index 988b3ffef882a..bbb53cf3a9347 100644 --- a/client/merkle-mountain-range/src/offchain_mmr.rs +++ b/client/merkle-mountain-range/src/offchain_mmr.rs @@ -21,59 +21,59 @@ #![warn(missing_docs)] -use crate::{aux_schema, LOG_TARGET}; +use crate::{aux_schema, MmrClient, LOG_TARGET}; +use beefy_primitives::MmrRootHash; use log::{debug, error, info, warn}; -use sc_client_api::{AuxStore, Backend, FinalityNotification}; +use sc_client_api::{Backend, FinalityNotification}; use sc_offchain::OffchainDb; -use sp_blockchain::{CachedHeaderMetadata, ForkBackend, HeaderBackend, HeaderMetadata}; +use sp_blockchain::{CachedHeaderMetadata, ForkBackend}; use sp_core::offchain::{DbExternalities, StorageKind}; -use sp_mmr_primitives::{utils, utils::NodesUtils, NodeIndex}; +use sp_mmr_primitives::{utils, utils::NodesUtils, MmrApi, NodeIndex}; use sp_runtime::{ - traits::{Block, NumberFor, One}, + traits::{Block, Header, 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, C> { - pub backend: Arc, - pub client: Arc, - pub offchain_db: OffchainDb, - pub indexing_prefix: Vec, - pub first_mmr_block: NumberFor, - pub best_canonicalized: NumberFor, + backend: Arc, + client: Arc, + offchain_db: OffchainDb, + indexing_prefix: Vec, + first_mmr_block: NumberFor, + best_canonicalized: NumberFor, } impl OffchainMmr where - C: HeaderBackend + HeaderMetadata, BE: Backend, B: Block, + C: MmrClient, + C::Api: MmrApi>, { + pub fn new( + backend: Arc, + client: Arc, + offchain_db: OffchainDb, + indexing_prefix: Vec, + first_mmr_block: NumberFor, + ) -> Option { + let mut best_canonicalized = first_mmr_block.saturating_sub(One::one()); + best_canonicalized = aux_schema::load_or_init_state::(&*backend, best_canonicalized) + .map_err(|e| error!(target: LOG_TARGET, "Error loading state from aux db: {:?}", e)) + .ok()?; + + Some(Self { + backend, + client, + offchain_db, + indexing_prefix, + first_mmr_block, + best_canonicalized, + }) + } + fn node_temp_offchain_key(&self, pos: NodeIndex, parent_hash: B::Hash) -> Vec { NodesUtils::node_temp_offchain_key::(&self.indexing_prefix, pos, parent_hash) } @@ -82,6 +82,14 @@ where NodesUtils::node_canon_offchain_key(&self.indexing_prefix, pos) } + fn write_gadget_state_or_log(&self) { + if let Err(e) = + aux_schema::write_gadget_state::(&*self.backend, &self.best_canonicalized) + { + debug!(target: LOG_TARGET, "error saving state: {:?}", e); + } + } + fn header_metadata_or_log( &self, hash: B::Hash, @@ -231,10 +239,22 @@ where 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); + self.write_gadget_state_or_log(); + } + } + + fn handle_potential_pallet_reset(&mut self, notification: &FinalityNotification) { + if let Some(first_mmr_block_num) = self.client.first_mmr_block_num(¬ification) { + if first_mmr_block_num != self.first_mmr_block { + info!( + target: LOG_TARGET, + "pallet-mmr reset detected at block {:?} with new genesis at block {:?}", + notification.header.number(), + first_mmr_block_num + ); + self.first_mmr_block = first_mmr_block_num; + self.best_canonicalized = first_mmr_block_num.saturating_sub(One::one()); + self.write_gadget_state_or_log(); } } } @@ -243,15 +263,14 @@ where /// _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) { + // Update the first MMR block in case of a pallet reset. + self.handle_potential_pallet_reset(¬ification); + // Move offchain MMR nodes for finalized blocks to canonical keys. 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) - { - debug!(target: LOG_TARGET, "error saving state: {:?}", e); - } + self.write_gadget_state_or_log(); // Remove offchain MMR nodes for stale forks. let stale_forks = self.client.expand_forks(¬ification.stale_heads).unwrap_or_else( @@ -303,7 +322,7 @@ mod tests { // expected pruned heads because of temp key collision: b1 client.assert_pruned(&[&c1, &b1]); - client.finalize_block(d5.hash(), None); + client.finalize_block(d5.hash(), Some(5)); tokio::time::sleep(Duration::from_millis(200)).await; // expected finalized heads: d4, d5, client.assert_canonicalized(&[&d4, &d5]); @@ -312,6 +331,36 @@ mod tests { }) } + #[test] + fn canonicalize_and_prune_handles_pallet_reset() { + run_test_with_mmr_gadget(|client| async move { + // G -> A1 -> A2 -> A3 -> A4 -> A5 + // | | + // | | -> pallet reset + // | + // | -> first finality notification + + 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(0)).await; + let a4 = client.import_block(&BlockId::Hash(a3.hash()), b"a4", Some(1)).await; + let a5 = client.import_block(&BlockId::Hash(a4.hash()), b"a5", Some(2)).await; + + client.finalize_block(a1.hash(), Some(1)); + tokio::time::sleep(Duration::from_millis(200)).await; + // expected finalized heads: a1 + client.assert_canonicalized(&[&a1]); + // a2 shouldn't be either canonicalized or pruned. It should be handled as part of the + // reset process. + client.assert_not_canonicalized(&[&a2]); + + client.finalize_block(a5.hash(), Some(3)); + tokio::time::sleep(Duration::from_millis(200)).await; + //expected finalized heads: a3, a4, a5, + client.assert_canonicalized(&[&a3, &a4, &a5]); + }) + } + #[test] fn canonicalize_catchup_works_correctly() { let mmr_blocks = Arc::new(Mutex::new(vec![])); @@ -329,11 +378,9 @@ mod tests { client.finalize_block(a2.hash(), Some(2)); - { - let mut mmr_blocks = mmr_blocks_ref.lock(); - mmr_blocks.push(a1); - mmr_blocks.push(a2); - } + let mut mmr_blocks = mmr_blocks_ref.lock(); + mmr_blocks.push(a1); + mmr_blocks.push(a2); }, |client| async move { // G -> A1 -> A2 -> A3 -> A4 @@ -358,4 +405,54 @@ mod tests { }, ) } + + #[test] + fn canonicalize_catchup_works_correctly_with_pallet_reset() { + 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(0)).await; + + client.finalize_block(a2.hash(), Some(1)); + + 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 gadget start (missed notification) + // | | + pallet reset + // | + // | -> 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(1)).await; + let a4 = client.import_block(&BlockId::Hash(a3.hash()), b"a4", Some(2)).await; + + client.finalize_block(a4.hash(), Some(3)); + tokio::time::sleep(Duration::from_millis(200)).await; + // a1 shouldn't be either canonicalized or pruned. It should be handled as part of + // the reset process. Checking only that it wasn't pruned. Because of temp key + // collision with a2 we can't check that it wasn't canonicalized. + client.assert_not_pruned(&[&a1]); + // expected finalized heads: a4, a5. + client.assert_canonicalized(&[&a2, &a3, &a4]); + }, + ) + } } diff --git a/client/merkle-mountain-range/src/test_utils.rs b/client/merkle-mountain-range/src/test_utils.rs index 39570e0d2384f..e5a6673483dbb 100644 --- a/client/merkle-mountain-range/src/test_utils.rs +++ b/client/merkle-mountain-range/src/test_utils.rs @@ -162,6 +162,18 @@ impl MockClient { client.finalize_block(hash, None).unwrap(); } + pub fn undo_block_canonicalization(&self, mmr_block: &MmrBlock) { + let mut offchain_db = self.offchain_db(); + 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); + } + } + pub fn check_offchain_storage( &self, key_type: OffchainKeyType, diff --git a/frame/merkle-mountain-range/src/mmr/storage.rs b/frame/merkle-mountain-range/src/mmr/storage.rs index 1f5d01f87e273..2e3b174f3943a 100644 --- a/frame/merkle-mountain-range/src/mmr/storage.rs +++ b/frame/merkle-mountain-range/src/mmr/storage.rs @@ -60,14 +60,6 @@ impl Default for Storage { } } -impl Storage -where - T: Config, - I: 'static, - L: primitives::FullLeaf, -{ -} - impl mmr_lib::MMRStore> for Storage where T: Config, From be510f203049b3b644c5004c036c8bd2b28ef40c Mon Sep 17 00:00:00 2001 From: JP <77391175+joao-paulo-parity@users.noreply.github.com> Date: Thu, 22 Dec 2022 09:21:30 -0300 Subject: [PATCH 218/715] change crates publishing to be scheduled (#13002) --- .gitlab-ci.yml | 4 ++++ scripts/ci/gitlab/pipeline/publish.yml | 6 +++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 145a25c809565..4d17b70028810 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -213,6 +213,10 @@ 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" +.scheduled-crate-publishing-pipeline: + rules: + - if: $CI_COMMIT_REF_NAME == "master" && $CI_PIPELINE_SOURCE == "schedule" && $PIPELINE == "automatic-crate-publishing" + .crates-publishing-template: stage: test extends: .docker-env diff --git a/scripts/ci/gitlab/pipeline/publish.yml b/scripts/ci/gitlab/pipeline/publish.yml index f2fd64bc34d73..cc7451a9fbb22 100644 --- a/scripts/ci/gitlab/pipeline/publish.yml +++ b/scripts/ci/gitlab/pipeline/publish.yml @@ -225,12 +225,12 @@ update-node-template: - rusty-cachier cache upload publish-crates: - extends: .publish-crates-template + extends: + - .publish-crates-template + - .scheduled-crate-publishing-pipeline needs: - job: publish-crates-locally artifacts: false - rules: - - if: $CI_COMMIT_REF_NAME == "master" publish-crates-manual: extends: .publish-crates-template From d57777ae1658544f0f9bca98ac6d9832bd32e4f6 Mon Sep 17 00:00:00 2001 From: Sasha Gryaznov Date: Thu, 22 Dec 2022 16:48:39 +0200 Subject: [PATCH 219/715] stabilize `[seal0] take_storage` (#13007) --- frame/contracts/src/wasm/runtime.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index 50ad9996e6eb6..066c1d71ea444 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -1230,7 +1230,6 @@ pub mod env { /// # Errors /// /// `ReturnCode::KeyNotFound` - #[unstable] #[prefixed_alias] fn take_storage( ctx: _, From 96e71b531cebf63211771c721169f78eb20eae54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Thu, 22 Dec 2022 15:52:48 +0100 Subject: [PATCH 220/715] contracts: Improve contract address derivation (#12883) * Add prefix to address derivation * Extend benchmark * Fix node test * ".git/.scripts/bench-bot.sh" pallet dev pallet_contracts * Adapt to new benchmark * Update dispatchable benchmarks * ".git/.scripts/bench-bot.sh" pallet dev pallet_contracts * Use benchmark results * Apply suggestions from code review Co-authored-by: Sasha Gryaznov * Don't use T::AdressGenerator directly * Rename constructor_args to input_data Co-authored-by: command-bot <> Co-authored-by: Sasha Gryaznov --- bin/node/executor/tests/basic.rs | 3 +- frame/contracts/proc-macro/src/lib.rs | 6 +- frame/contracts/src/benchmarking/code.rs | 25 +- frame/contracts/src/benchmarking/mod.rs | 31 +- frame/contracts/src/benchmarking/sandbox.rs | 7 +- frame/contracts/src/chain_extension.rs | 27 +- frame/contracts/src/exec.rs | 18 +- frame/contracts/src/gas.rs | 6 +- frame/contracts/src/lib.rs | 61 +- frame/contracts/src/schedule.rs | 15 +- frame/contracts/src/storage.rs | 14 +- frame/contracts/src/storage/meter.rs | 10 +- frame/contracts/src/tests.rs | 852 +++++---- frame/contracts/src/wasm/code_cache.rs | 21 +- frame/contracts/src/wasm/mod.rs | 14 +- frame/contracts/src/wasm/prepare.rs | 4 - frame/contracts/src/wasm/runtime.rs | 22 +- frame/contracts/src/weights.rs | 1902 ++++++++++--------- 18 files changed, 1559 insertions(+), 1479 deletions(-) diff --git a/bin/node/executor/tests/basic.rs b/bin/node/executor/tests/basic.rs index fc4e138faafc2..c88703b929e6b 100644 --- a/bin/node/executor/tests/basic.rs +++ b/bin/node/executor/tests/basic.rs @@ -654,7 +654,8 @@ fn deploying_wasm_contract_should_work() { let transfer_code = wat::parse_str(CODE_TRANSFER).unwrap(); let transfer_ch = ::Hashing::hash(&transfer_code); - let addr = pallet_contracts::Pallet::::contract_address(&charlie(), &transfer_ch, &[]); + let addr = + pallet_contracts::Pallet::::contract_address(&charlie(), &transfer_ch, &[], &[]); let time = 42 * 1000; let b = construct_block( diff --git a/frame/contracts/proc-macro/src/lib.rs b/frame/contracts/proc-macro/src/lib.rs index a8f95bd10cff8..ded5880a2df4d 100644 --- a/frame/contracts/proc-macro/src/lib.rs +++ b/frame/contracts/proc-macro/src/lib.rs @@ -404,11 +404,7 @@ fn expand_impls(def: &mut EnvDef) -> TokenStream2 { 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]>, + impl<'a, E: Ext> crate::wasm::Environment> for Env { fn define(store: &mut ::wasmi::Store>, linker: &mut ::wasmi::Linker>, allow_unstable: bool) -> Result<(), ::wasmi::errors::LinkerError> { #impls diff --git a/frame/contracts/src/benchmarking/code.rs b/frame/contracts/src/benchmarking/code.rs index 2074e1867d506..0b09726214260 100644 --- a/frame/contracts/src/benchmarking/code.rs +++ b/frame/contracts/src/benchmarking/code.rs @@ -26,7 +26,6 @@ use crate::{Config, Determinism}; use frame_support::traits::Get; -use sp_core::crypto::UncheckedFrom; use sp_runtime::traits::Hash; use sp_std::{borrow::ToOwned, prelude::*}; use wasm_instrument::{ @@ -105,11 +104,7 @@ pub struct ImportedMemory { } impl ImportedMemory { - pub fn max() -> Self - where - T: Config, - T::AccountId: UncheckedFrom + AsRef<[u8]>, - { + pub fn max() -> Self { let pages = max_pages::(); Self { min_pages: pages, max_pages: pages } } @@ -130,11 +125,7 @@ pub struct WasmModule { pub memory: Option, } -impl From for WasmModule -where - T: Config, - T::AccountId: UncheckedFrom + AsRef<[u8]>, -{ +impl From for WasmModule { fn from(def: ModuleDefinition) -> Self { // internal functions start at that offset. let func_offset = u32::try_from(def.imported_functions.len()).unwrap(); @@ -259,11 +250,7 @@ where } } -impl WasmModule -where - T: Config, - T::AccountId: UncheckedFrom + AsRef<[u8]>, -{ +impl WasmModule { /// Uses the supplied wasm module and instruments it when requested. pub fn instrumented(code: &[u8], inject_gas: bool, inject_stack: bool) -> Self { let module = { @@ -533,11 +520,7 @@ pub mod body { } /// The maximum amount of pages any contract is allowed to have according to the current `Schedule`. -pub fn max_pages() -> u32 -where - T: Config, - T::AccountId: UncheckedFrom + AsRef<[u8]>, -{ +pub fn max_pages() -> u32 { T::Schedule::get().limits.memory_pages } diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index 6b8701ac84d96..da9b53495d077 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -63,8 +63,6 @@ struct Contract { 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. @@ -90,7 +88,7 @@ where 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); + let addr = Contracts::::contract_address(&caller, &module.hash, &data, &salt); Contracts::::store_code_raw(module.code, caller.clone())?; Contracts::::instantiate( @@ -203,8 +201,6 @@ macro_rules! load_benchmark { 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, } @@ -270,6 +266,7 @@ benchmarks! { // a code of that size into the sandbox. // // `c`: Size of the code in kilobytes. + // `i`: Size of the input in kilobytes. // `s`: Size of the salt in kilobytes. // // # Note @@ -278,15 +275,17 @@ benchmarks! { // to be larger than the maximum size **after instrumentation**. instantiate_with_code { let c in 0 .. Perbill::from_percent(49).mul_ceil(T::MaxCodeLen::get()); + let i in 0 .. code::max_pages::() * 64 * 1024; let s in 0 .. code::max_pages::() * 64 * 1024; + let input = vec![42u8; i as usize]; let salt = vec![42u8; s as usize]; 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); let origin = RawOrigin::Signed(caller.clone()); - let addr = Contracts::::contract_address(&caller, &hash, &salt); - }: _(origin, value, Weight::MAX, None, code, vec![], salt) + let addr = Contracts::::contract_address(&caller, &hash, &input, &salt); + }: _(origin, value, Weight::MAX, None, code, input, salt) verify { // the contract itself does not trigger any reserves let deposit = T::Currency::reserved_balance(&addr); @@ -303,18 +302,21 @@ benchmarks! { } // Instantiate uses a dummy contract constructor to measure the overhead of the instantiate. + // `i`: Size of the input in kilobytes. // `s`: Size of the salt in kilobytes. instantiate { + let i in 0 .. code::max_pages::() * 64 * 1024; let s in 0 .. code::max_pages::() * 64 * 1024; + let input = vec![42u8; i as usize]; let salt = vec![42u8; s as usize]; let value = Pallet::::min_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); + let addr = Contracts::::contract_address(&caller, &hash, &input, &salt); Contracts::::store_code_raw(code, caller.clone())?; - }: _(origin, value, Weight::MAX, None, hash, vec![], salt) + }: _(origin, value, Weight::MAX, None, hash, input, salt) verify { // the contract itself does not trigger any reserves let deposit = T::Currency::reserved_balance(&addr); @@ -1779,7 +1781,7 @@ benchmarks! { let addresses = hashes .iter() .map(|hash| Contracts::::contract_address( - &instance.account_id, hash, &[], + &instance.account_id, hash, &[], &[], )) .collect::>(); @@ -1796,8 +1798,9 @@ benchmarks! { } } - seal_instantiate_per_transfer_salt_kb { + seal_instantiate_per_transfer_input_salt_kb { let t in 0 .. 1; + let i in 0 .. (code::max_pages::() - 1) * 64; let s in 0 .. (code::max_pages::() - 1) * 64; let callee_code = WasmModule::::dummy(); let hash = callee_code.hash; @@ -1865,14 +1868,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 - Regular(Instruction::I32Const(0)), // input_data_ptr - Regular(Instruction::I32Const(0)), // input_data_len + Counter(salt_offset as u32, salt_len as u32), // input_data_ptr + Regular(Instruction::I32Const((i * 1024) as i32)), // 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(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::I32Const((s * 1024) as i32)), // salt_len Regular(Instruction::Call(0)), Regular(Instruction::I32Eqz), Regular(Instruction::If(BlockType::NoResult)), diff --git a/frame/contracts/src/benchmarking/sandbox.rs b/frame/contracts/src/benchmarking/sandbox.rs index a35aad3500109..5d080bad92516 100644 --- a/frame/contracts/src/benchmarking/sandbox.rs +++ b/frame/contracts/src/benchmarking/sandbox.rs @@ -20,7 +20,6 @@ /// ! 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 wasmi::{errors::LinkerError, Func, Linker, StackLimits, Store}; /// Minimal execution environment without any imported functions. @@ -36,11 +35,7 @@ impl Sandbox { } } -impl From<&WasmModule> for Sandbox -where - T: Config, - T::AccountId: UncheckedFrom + AsRef<[u8]>, -{ +impl From<&WasmModule> for Sandbox { /// 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 { diff --git a/frame/contracts/src/chain_extension.rs b/frame/contracts/src/chain_extension.rs index 3c3e9b1ef0f59..dfa9c7c2de268 100644 --- a/frame/contracts/src/chain_extension.rs +++ b/frame/contracts/src/chain_extension.rs @@ -83,7 +83,6 @@ use sp_std::{marker::PhantomData, vec::Vec}; 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; /// Result that returns a [`DispatchError`] on error. pub type Result = sp_std::result::Result; @@ -114,10 +113,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(&mut self, env: Environment) -> Result - where - E: Ext, - ::AccountId: UncheckedFrom<::Hash> + AsRef<[u8]>; + fn call>(&mut self, env: Environment) -> Result; /// Determines whether chain extensions are enabled for this chain. /// @@ -153,11 +149,7 @@ pub trait RegisteredChainExtension: ChainExtension { #[impl_trait_for_tuples::impl_for_tuples(10)] #[tuple_types_custom_trait_bound(RegisteredChainExtension)] impl ChainExtension for Tuple { - fn call(&mut self, mut env: Environment) -> Result - where - E: Ext, - ::AccountId: UncheckedFrom<::Hash> + AsRef<[u8]>, - { + fn call>(&mut self, mut env: Environment) -> Result { for_tuples!( #( if (Tuple::ID == env.ext_id()) && Tuple::enabled() { @@ -205,10 +197,7 @@ pub struct Environment<'a, 'b, E: Ext, S: State> { } /// Functions that are available in every state of this type. -impl<'a, 'b, E: Ext, S: State> Environment<'a, 'b, E, S> -where - ::AccountId: UncheckedFrom<::Hash> + AsRef<[u8]>, -{ +impl<'a, 'b, E: Ext, S: State> Environment<'a, 'b, E, S> { /// 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 @@ -326,10 +315,7 @@ impl<'a, 'b, E: Ext, S: PrimOut> Environment<'a, 'b, E, S> { } /// Functions to use the input arguments as pointer to a buffer. -impl<'a, 'b, E: Ext, S: BufIn> Environment<'a, 'b, E, S> -where - ::AccountId: UncheckedFrom<::Hash> + AsRef<[u8]>, -{ +impl<'a, 'b, E: Ext, S: BufIn> Environment<'a, 'b, E, S> { /// Reads `min(max_len, in_len)` from contract memory. /// /// This does **not** charge any weight. The caller must make sure that the an @@ -401,10 +387,7 @@ where } /// Functions to use the output arguments as pointer to a buffer. -impl<'a, 'b, E: Ext, S: BufOut> Environment<'a, 'b, E, S> -where - ::AccountId: UncheckedFrom<::Hash> + AsRef<[u8]>, -{ +impl<'a, 'b, E: Ext, S: BufOut> Environment<'a, 'b, E, S> { /// Write the supplied buffer to contract memory. /// /// If the contract supplied buffer is smaller than the passed `buffer` an `Err` is returned. diff --git a/frame/contracts/src/exec.rs b/frame/contracts/src/exec.rs index 945095dc20329..f4dc3a0ec0250 100644 --- a/frame/contracts/src/exec.rs +++ b/frame/contracts/src/exec.rs @@ -32,7 +32,7 @@ use frame_support::{ use frame_system::RawOrigin; use pallet_contracts_primitives::ExecReturnValue; use smallvec::{Array, SmallVec}; -use sp_core::{crypto::UncheckedFrom, ecdsa::Public as ECDSAPublic}; +use sp_core::ecdsa::Public as ECDSAPublic; use sp_io::{crypto::secp256k1_ecdsa_recover_compressed, hashing::blake2_256}; use sp_runtime::traits::{Convert, Hash}; use sp_std::{marker::PhantomData, mem, prelude::*}; @@ -475,6 +475,8 @@ enum FrameArgs<'a, T: Config, E> { executable: E, /// A salt used in the contract address deriviation of the new contract. salt: &'a [u8], + /// The input data is used in the contract address deriviation of the new contract. + input_data: &'a [u8], }, } @@ -596,7 +598,6 @@ impl CachedContract { impl<'a, T, E> Stack<'a, T, E> where T: Config, - T::AccountId: UncheckedFrom + AsRef<[u8]>, E: Executable, { /// Create and run a new call stack by calling into `dest`. @@ -660,6 +661,7 @@ where nonce: >::get().wrapping_add(1), executable, salt, + input_data: input_data.as_ref(), }, origin, gas_meter, @@ -742,9 +744,13 @@ where (dest, contract, executable, delegate_caller, ExportedFunction::Call, None) }, - FrameArgs::Instantiate { sender, nonce, executable, salt } => { - let account_id = - >::contract_address(&sender, executable.code_hash(), salt); + FrameArgs::Instantiate { sender, nonce, executable, salt, input_data } => { + let account_id = Contracts::::contract_address( + &sender, + executable.code_hash(), + input_data, + salt, + ); let trie_id = Storage::::generate_trie_id(&account_id, nonce); let contract = Storage::::new_contract(&account_id, trie_id, *executable.code_hash())?; @@ -1080,7 +1086,6 @@ where impl<'a, T, E> Ext for Stack<'a, T, E> where T: Config, - T::AccountId: UncheckedFrom + AsRef<[u8]>, E: Executable, { type T = T; @@ -1167,6 +1172,7 @@ where nonce, executable, salt, + input_data: input_data.as_ref(), }, value, gas_limit, diff --git a/frame/contracts/src/gas.rs b/frame/contracts/src/gas.rs index c0cc2db2aa3eb..ccbe680b2f767 100644 --- a/frame/contracts/src/gas.rs +++ b/frame/contracts/src/gas.rs @@ -23,7 +23,6 @@ use frame_support::{ weights::Weight, DefaultNoBound, }; -use sp_core::crypto::UncheckedFrom; use sp_runtime::traits::Zero; use sp_std::marker::PhantomData; @@ -86,10 +85,7 @@ pub struct GasMeter { tokens: Vec, } -impl GasMeter -where - T::AccountId: UncheckedFrom<::Hash> + AsRef<[u8]>, -{ +impl GasMeter { pub fn new(gas_limit: Weight) -> Self { GasMeter { gas_limit, diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index b76acf9d1db08..39626e43f4653 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -105,7 +105,7 @@ use crate::{ wasm::{OwnerInfo, PrefabWasmModule, TryInstantiate}, weights::WeightInfo, }; -use codec::{Codec, Encode, HasCompact}; +use codec::{Codec, Decode, Encode, HasCompact}; use frame_support::{ dispatch::{Dispatchable, GetDispatchInfo, Pays, PostDispatchInfo}, ensure, @@ -123,8 +123,7 @@ use pallet_contracts_primitives::{ StorageDeposit, }; use scale_info::TypeInfo; -use sp_core::crypto::UncheckedFrom; -use sp_runtime::traits::{Convert, Hash, Saturating, StaticLookup}; +use sp_runtime::traits::{Convert, Hash, Saturating, StaticLookup, TrailingZeroInput}; use sp_std::{fmt::Debug, marker::PhantomData, prelude::*}; pub use crate::{ @@ -155,7 +154,7 @@ const SENTINEL: u32 = u32::MAX; /// Provides the contract address generation method. /// /// See [`DefaultAddressGenerator`] for the default implementation. -pub trait AddressGenerator { +pub trait AddressGenerator { /// Generate the address of a contract based on the given instantiate parameters. /// /// # Note for implementors @@ -166,6 +165,7 @@ pub trait AddressGenerator { fn generate_address( deploying_address: &T::AccountId, code_hash: &CodeHash, + input_data: &[u8], salt: &[u8], ) -> T::AccountId; } @@ -176,28 +176,21 @@ pub trait AddressGenerator { /// 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)` +/// Formula: +/// `hash("contract_addr_v1" ++ deploying_address ++ code_hash ++ input_data ++ salt)` pub struct DefaultAddressGenerator; -impl AddressGenerator for DefaultAddressGenerator -where - T: frame_system::Config, - T::AccountId: UncheckedFrom + AsRef<[u8]>, -{ +impl AddressGenerator for DefaultAddressGenerator { fn generate_address( deploying_address: &T::AccountId, code_hash: &CodeHash, + input_data: &[u8], 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)) + let entropy = (b"contract_addr_v1", deploying_address, code_hash, input_data, salt) + .using_encoded(T::Hashing::hash); + Decode::decode(&mut TrailingZeroInput::new(entropy.as_ref())) + .expect("infinite length input; no invalid inputs for type; qed") } } @@ -352,11 +345,7 @@ pub mod pallet { } #[pallet::hooks] - impl Hooks> for Pallet - where - T::AccountId: UncheckedFrom, - T::AccountId: AsRef<[u8]>, - { + impl Hooks> for Pallet { 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()) @@ -385,8 +374,6 @@ pub mod pallet { #[pallet::call] impl Pallet where - T::AccountId: UncheckedFrom, - T::AccountId: AsRef<[u8]>, as HasCompact>::Type: Clone + Eq + PartialEq + Debug + TypeInfo + Encode, { /// Deprecated version if [`Self::call`] for use in an in-storage `Call`. @@ -415,7 +402,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) + T::WeightInfo::instantiate_with_code(code.len() as u32, data.len() as u32, salt.len() as u32) .saturating_add(>::compat_weight(*gas_limit)) )] #[allow(deprecated)] @@ -445,7 +432,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)) + T::WeightInfo::instantiate(data.len() as u32, 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`")] @@ -633,7 +620,7 @@ pub mod pallet { /// - 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) + T::WeightInfo::instantiate_with_code(code.len() as u32, data.len() as u32, salt.len() as u32) .saturating_add(*gas_limit) )] pub fn instantiate_with_code( @@ -647,6 +634,7 @@ pub mod pallet { ) -> DispatchResultWithPostInfo { let origin = ensure_signed(origin)?; let code_len = code.len() as u32; + let data_len = data.len() as u32; let salt_len = salt.len() as u32; let mut output = Self::internal_instantiate( origin, @@ -665,7 +653,7 @@ pub mod pallet { } output.gas_meter.into_dispatch_result( output.result.map(|(_address, result)| result), - T::WeightInfo::instantiate_with_code(code_len, salt_len), + T::WeightInfo::instantiate_with_code(code_len, data_len, salt_len), ) } @@ -676,7 +664,7 @@ pub mod pallet { /// must be supplied. #[pallet::call_index(8)] #[pallet::weight( - T::WeightInfo::instantiate(salt.len() as u32).saturating_add(*gas_limit) + T::WeightInfo::instantiate(data.len() as u32, salt.len() as u32).saturating_add(*gas_limit) )] pub fn instantiate( origin: OriginFor, @@ -688,6 +676,7 @@ pub mod pallet { salt: Vec, ) -> DispatchResultWithPostInfo { let origin = ensure_signed(origin)?; + let data_len = data.len() as u32; let salt_len = salt.len() as u32; let mut output = Self::internal_instantiate( origin, @@ -706,7 +695,7 @@ pub mod pallet { } output.gas_meter.into_dispatch_result( output.result.map(|(_address, output)| output), - T::WeightInfo::instantiate(salt_len), + T::WeightInfo::instantiate(data_len, salt_len), ) } } @@ -943,10 +932,7 @@ struct InternalOutput { result: Result, } -impl Pallet -where - T::AccountId: UncheckedFrom + AsRef<[u8]>, -{ +impl Pallet { /// Perform a call to a specified contract. /// /// This function is similar to [`Self::call`], but doesn't perform any address lookups @@ -1081,9 +1067,10 @@ where pub fn contract_address( deploying_address: &T::AccountId, code_hash: &CodeHash, + input_data: &[u8], salt: &[u8], ) -> T::AccountId { - T::AddressGenerator::generate_address(deploying_address, code_hash, salt) + T::AddressGenerator::generate_address(deploying_address, code_hash, input_data, salt) } /// Returns the code hash of the contract specified by `account` ID. diff --git a/frame/contracts/src/schedule.rs b/frame/contracts/src/schedule.rs index 4f2d3b61d0176..e7a6b16e23a2b 100644 --- a/frame/contracts/src/schedule.rs +++ b/frame/contracts/src/schedule.rs @@ -397,6 +397,9 @@ pub struct HostFnWeights { /// Weight surcharge that is claimed if `seal_instantiate` does a balance transfer. pub instantiate_transfer_surcharge: u64, + /// Weight per input byte supplied to `seal_instantiate`. + pub instantiate_per_input_byte: u64, + /// Weight per salt byte supplied to `seal_instantiate`. pub instantiate_per_salt_byte: u64, @@ -658,12 +661,20 @@ impl Default for HostFnWeights { call_per_cloned_byte: cost_batched_args!(seal_call_per_transfer_clone_kb, 0, 1), instantiate: cost_batched!(seal_instantiate), instantiate_transfer_surcharge: cost_byte_batched_args!( - seal_instantiate_per_transfer_salt_kb, + seal_instantiate_per_transfer_input_salt_kb, + 1, + 0, + 0 + ), + instantiate_per_input_byte: cost_byte_batched_args!( + seal_instantiate_per_transfer_input_salt_kb, + 0, 1, 0 ), instantiate_per_salt_byte: cost_byte_batched_args!( - seal_instantiate_per_transfer_salt_kb, + seal_instantiate_per_transfer_input_salt_kb, + 0, 0, 1 ), diff --git a/frame/contracts/src/storage.rs b/frame/contracts/src/storage.rs index c7644e696196f..d40cc755c315e 100644 --- a/frame/contracts/src/storage.rs +++ b/frame/contracts/src/storage.rs @@ -31,7 +31,6 @@ use frame_support::{ weights::Weight, }; use scale_info::TypeInfo; -use sp_core::crypto::UncheckedFrom; use sp_io::KillStorageResult; use sp_runtime::{ traits::{Hash, Saturating, Zero}, @@ -135,11 +134,7 @@ impl WriteOutcome { pub struct Storage(PhantomData); -impl Storage -where - T: Config, - T::AccountId: UncheckedFrom + AsRef<[u8]>, -{ +impl Storage { /// Reads a storage kv pair of a contract. /// /// The read is performed from the `trie_id` only. The `address` is not necessary. If the @@ -317,11 +312,10 @@ where Weight::from_ref_time(ref_time_weight) } - /// Generates a unique trie id by returning `hash(account_id ++ nonce)`. + /// 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() + let buf = (account_id, nonce).using_encoded(T::Hashing::hash); + buf.as_ref() .to_vec() .try_into() .expect("Runtime uses a reasonable hash size. Hence sizeof(T::Hash) <= 128; qed") diff --git a/frame/contracts/src/storage/meter.rs b/frame/contracts/src/storage/meter.rs index 0a63eb42b86cb..94bca741af661 100644 --- a/frame/contracts/src/storage/meter.rs +++ b/frame/contracts/src/storage/meter.rs @@ -29,7 +29,6 @@ use frame_support::{ DefaultNoBound, RuntimeDebugNoBound, }; use pallet_contracts_primitives::StorageDeposit as Deposit; -use sp_core::crypto::UncheckedFrom; use sp_runtime::{ traits::{Saturating, Zero}, FixedPointNumber, FixedU128, @@ -255,7 +254,6 @@ impl Default for Contribution { impl RawMeter where T: Config, - T::AccountId: UncheckedFrom + AsRef<[u8]>, E: Ext, S: State, { @@ -325,7 +323,6 @@ where impl RawMeter where T: Config, - T::AccountId: UncheckedFrom + AsRef<[u8]>, E: Ext, { /// Create new storage meter for the specified `origin` and `limit`. @@ -361,7 +358,6 @@ where 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. @@ -441,11 +437,7 @@ where } } -impl Ext for ReservingExt -where - T: Config, - T::AccountId: UncheckedFrom + AsRef<[u8]>, -{ +impl Ext for ReservingExt { fn check_limit( origin: &T::AccountId, limit: Option>, diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index 6121d880ca8c5..85fe22ab9a19b 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -19,7 +19,7 @@ use self::test_utils::hash; use crate::{ chain_extension::{ ChainExtension, Environment, Ext, InitState, RegisteredChainExtension, - Result as ExtensionResult, RetVal, ReturnFlags, SysConfig, UncheckedFrom, + Result as ExtensionResult, RetVal, ReturnFlags, SysConfig, }, exec::{FixSizedKey, Frame}, storage::Storage, @@ -174,7 +174,6 @@ impl ChainExtension for TestExtension { 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; @@ -219,7 +218,6 @@ impl ChainExtension for RevertingExtension { fn call(&mut self, _env: Environment) -> ExtensionResult where E: Ext, - ::AccountId: UncheckedFrom<::Hash> + AsRef<[u8]>, { Ok(RetVal::Diverging { flags: ReturnFlags::REVERT, data: vec![0x4B, 0x1D] }) } @@ -237,7 +235,6 @@ impl ChainExtension for DisabledExtension { fn call(&mut self, _env: Environment) -> ExtensionResult where E: Ext, - ::AccountId: UncheckedFrom<::Hash> + AsRef<[u8]>, { panic!("Disabled chain extensions are never called") } @@ -255,7 +252,6 @@ 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 { @@ -543,16 +539,19 @@ fn instantiate_and_call_and_deposit_event() { initialize_block(2); // Check at the end to get hash on error easily - assert_ok!(Contracts::instantiate( - RuntimeOrigin::signed(ALICE), + let addr = Contracts::bare_instantiate( + ALICE, value, GAS_LIMIT, None, - code_hash, + Code::Existing(code_hash), vec![], vec![], - )); - let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); + false, + ) + .result + .unwrap() + .account_id; assert!(ContractInfoOf::::contains_key(&addr)); assert_eq!( @@ -622,21 +621,24 @@ fn instantiate_and_call_and_deposit_event() { #[test] fn deposit_event_max_value_limit() { - let (wasm, code_hash) = compile_module::("event_size").unwrap(); + let (wasm, _code_hash) = compile_module::("event_size").unwrap(); ExtBuilder::default().existential_deposit(50).build().execute_with(|| { // Create let _ = Balances::deposit_creating(&ALICE, 1_000_000); - assert_ok!(Contracts::instantiate_with_code( - RuntimeOrigin::signed(ALICE), + let addr = Contracts::bare_instantiate( + ALICE, 30_000, GAS_LIMIT, None, - wasm, + Code::Upload(wasm), vec![], vec![], - )); - let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); + false, + ) + .result + .unwrap() + .account_id; // Call contract with allowed storage value. assert_ok!(Contracts::call( @@ -665,21 +667,24 @@ fn deposit_event_max_value_limit() { #[test] fn run_out_of_gas() { - let (wasm, code_hash) = compile_module::("run_out_of_gas").unwrap(); + let (wasm, _code_hash) = compile_module::("run_out_of_gas").unwrap(); 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( - RuntimeOrigin::signed(ALICE), + let addr = Contracts::bare_instantiate( + ALICE, 100 * min_balance, GAS_LIMIT, None, - wasm, + Code::Upload(wasm), vec![], vec![], - )); - let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); + false, + ) + .result + .unwrap() + .account_id; // Call the contract with a fixed gas limit. It must run out of gas because it just // loops forever. @@ -712,18 +717,21 @@ fn instantiate_unique_trie_id() { Determinism::Deterministic, ) .unwrap(); - let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); // Instantiate the contract and store its trie id for later comparison. - assert_ok!(Contracts::instantiate( - RuntimeOrigin::signed(ALICE), + let addr = Contracts::bare_instantiate( + ALICE, 0, GAS_LIMIT, None, - code_hash, + Code::Existing(code_hash), vec![], vec![], - )); + false, + ) + .result + .unwrap() + .account_id; let trie_id = get_contract(&addr).trie_id; // Try to instantiate it again without termination should yield an error. @@ -768,21 +776,24 @@ fn instantiate_unique_trie_id() { #[test] fn storage_max_value_limit() { - let (wasm, code_hash) = compile_module::("storage_size").unwrap(); + let (wasm, _code_hash) = compile_module::("storage_size").unwrap(); ExtBuilder::default().existential_deposit(50).build().execute_with(|| { // Create let _ = Balances::deposit_creating(&ALICE, 1_000_000); - assert_ok!(Contracts::instantiate_with_code( - RuntimeOrigin::signed(ALICE), + let addr = Contracts::bare_instantiate( + ALICE, 30_000, GAS_LIMIT, None, - wasm, + Code::Upload(wasm), vec![], vec![], - )); - let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); + false, + ) + .result + .unwrap() + .account_id; get_contract(&addr); // Call contract with allowed storage value. @@ -812,34 +823,46 @@ fn storage_max_value_limit() { #[test] fn deploy_and_call_other_contract() { - let (caller_wasm, caller_code_hash) = compile_module::("caller_contract").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(); // Create let _ = Balances::deposit_creating(&ALICE, 1_000_000); - assert_ok!(Contracts::instantiate_with_code( - RuntimeOrigin::signed(ALICE), + let caller_addr = Contracts::bare_instantiate( + ALICE, 100_000, GAS_LIMIT, None, - caller_wasm, + Code::Upload(caller_wasm), vec![], vec![], - )); - assert_ok!(Contracts::instantiate_with_code( - RuntimeOrigin::signed(ALICE), + false, + ) + .result + .unwrap() + .account_id; + Contracts::bare_instantiate( + ALICE, 100_000, GAS_LIMIT, None, - callee_wasm, + Code::Upload(callee_wasm), 0u32.to_le_bytes().encode(), vec![42], - )); + false, + ) + .result + .unwrap(); + + let callee_addr = Contracts::contract_address( + &caller_addr, + &callee_code_hash, + &[0, 1, 34, 51, 68, 85, 102, 119], // hard coded in wasm + &[], + ); // Drop previous events initialize_block(2); @@ -939,23 +962,26 @@ fn deploy_and_call_other_contract() { #[test] fn delegate_call() { - let (caller_wasm, caller_code_hash) = compile_module::("delegate_call").unwrap(); + 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( - RuntimeOrigin::signed(ALICE), + let caller_addr = Contracts::bare_instantiate( + ALICE, 300_000, GAS_LIMIT, None, - caller_wasm, + Code::Upload(caller_wasm), vec![], vec![], - )); + false, + ) + .result + .unwrap() + .account_id; // Only upload 'callee' code assert_ok!(Contracts::upload_code( RuntimeOrigin::signed(ALICE), @@ -977,21 +1003,24 @@ fn delegate_call() { #[test] fn cannot_self_destruct_through_draning() { - let (wasm, code_hash) = compile_module::("drain").unwrap(); + let (wasm, _code_hash) = compile_module::("drain").unwrap(); 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( - RuntimeOrigin::signed(ALICE), + let addr = Contracts::bare_instantiate( + ALICE, 1_000, GAS_LIMIT, None, - wasm, + Code::Upload(wasm), vec![], vec![], - )); - let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); + false, + ) + .result + .unwrap() + .account_id; // Check that the BOB contract has been instantiated. get_contract(&addr); @@ -1017,22 +1046,25 @@ fn cannot_self_destruct_through_draning() { #[test] fn cannot_self_destruct_through_storage_refund_after_price_change() { - let (wasm, code_hash) = compile_module::("store").unwrap(); + 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), + let addr = Contracts::bare_instantiate( + ALICE, 0, GAS_LIMIT, None, - wasm, + Code::Upload(wasm), vec![], vec![], - )); - let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); + false, + ) + .result + .unwrap() + .account_id; // Check that the BOB contract has been instantiated and has the minimum balance assert_eq!(get_contract(&addr).total_deposit(), min_balance); @@ -1073,21 +1105,24 @@ fn cannot_self_destruct_through_storage_refund_after_price_change() { #[test] fn cannot_self_destruct_by_refund_after_slash() { - let (wasm, code_hash) = compile_module::("store").unwrap(); + 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( - RuntimeOrigin::signed(ALICE), + let addr = Contracts::bare_instantiate( + ALICE, 0, GAS_LIMIT, None, - wasm, + Code::Upload(wasm), vec![], vec![], - )); - let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); + false, + ) + .result + .unwrap() + .account_id; // create 100 more reserved balance assert_ok!(Contracts::call( @@ -1156,21 +1191,24 @@ fn cannot_self_destruct_by_refund_after_slash() { #[test] fn cannot_self_destruct_while_live() { - let (wasm, code_hash) = compile_module::("self_destruct").unwrap(); + 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); // Instantiate the BOB contract. - assert_ok!(Contracts::instantiate_with_code( - RuntimeOrigin::signed(ALICE), + let addr = Contracts::bare_instantiate( + ALICE, 100_000, GAS_LIMIT, None, - wasm, + Code::Upload(wasm), vec![], vec![], - )); - let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); + false, + ) + .result + .unwrap() + .account_id; // Check that the BOB contract has been instantiated. get_contract(&addr); @@ -1202,16 +1240,19 @@ fn self_destruct_works() { let _ = Balances::deposit_creating(&DJANGO, 1_000_000); // Instantiate the BOB contract. - assert_ok!(Contracts::instantiate_with_code( - RuntimeOrigin::signed(ALICE), + let addr = Contracts::bare_instantiate( + ALICE, 100_000, GAS_LIMIT, None, - wasm, + Code::Upload(wasm), vec![], vec![], - )); - let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); + false, + ) + .result + .unwrap() + .account_id; // Check that the BOB contract has been instantiated. get_contract(&addr); @@ -1290,36 +1331,32 @@ fn self_destruct_works() { #[test] fn destroy_contract_and_transfer_funds() { let (callee_wasm, callee_code_hash) = compile_module::("self_destruct").unwrap(); - let (caller_wasm, caller_code_hash) = compile_module::("destroy_and_transfer").unwrap(); + let (caller_wasm, _caller_code_hash) = compile_module::("destroy_and_transfer").unwrap(); ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - // Create + // Create code hash for bob to instantiate let _ = Balances::deposit_creating(&ALICE, 1_000_000); - assert_ok!(Contracts::instantiate_with_code( - RuntimeOrigin::signed(ALICE), - 200_000, - GAS_LIMIT, - None, - callee_wasm, - vec![], - vec![42] - )); + Contracts::bare_upload_code(ALICE, callee_wasm, None, Determinism::Deterministic).unwrap(); // This deploys the BOB contract, which in turn deploys the CHARLIE contract during // construction. - assert_ok!(Contracts::instantiate_with_code( - RuntimeOrigin::signed(ALICE), + let addr_bob = Contracts::bare_instantiate( + ALICE, 200_000, GAS_LIMIT, None, - caller_wasm, + Code::Upload(caller_wasm), callee_code_hash.as_ref().to_vec(), vec![], - )); - let addr_bob = Contracts::contract_address(&ALICE, &caller_code_hash, &[]); - let addr_charlie = Contracts::contract_address(&addr_bob, &callee_code_hash, &[0x47, 0x11]); + false, + ) + .result + .unwrap() + .account_id; // Check that the CHARLIE contract has been instantiated. + let addr_charlie = + Contracts::contract_address(&addr_bob, &callee_code_hash, &[], &[0x47, 0x11]); get_contract(&addr_charlie); // Call BOB, which calls CHARLIE, forcing CHARLIE to self-destruct. @@ -1361,22 +1398,25 @@ fn cannot_self_destruct_in_constructor() { #[test] fn crypto_hashes() { - let (wasm, code_hash) = compile_module::("crypto_hashes").unwrap(); + let (wasm, _code_hash) = compile_module::("crypto_hashes").unwrap(); ExtBuilder::default().existential_deposit(50).build().execute_with(|| { let _ = Balances::deposit_creating(&ALICE, 1_000_000); // Instantiate the CRYPTO_HASHES contract. - assert_ok!(Contracts::instantiate_with_code( - RuntimeOrigin::signed(ALICE), + let addr = Contracts::bare_instantiate( + ALICE, 100_000, GAS_LIMIT, None, - wasm, + Code::Upload(wasm), vec![], vec![], - )); - let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); + false, + ) + .result + .unwrap() + .account_id; // Perform the call. let input = b"_DEAD_BEEF"; use sp_io::hashing::*; @@ -1419,21 +1459,24 @@ fn crypto_hashes() { #[test] fn transfer_return_code() { - let (wasm, code_hash) = compile_module::("transfer_return_code").unwrap(); + let (wasm, _code_hash) = compile_module::("transfer_return_code").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( - RuntimeOrigin::signed(ALICE), + let addr = Contracts::bare_instantiate( + ALICE, min_balance * 100, GAS_LIMIT, None, - wasm, + Code::Upload(wasm), vec![], vec![], - ),); - let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); + false, + ) + .result + .unwrap() + .account_id; // Contract has only the minimal balance so any transfer will fail. Balances::make_free_balance_be(&addr, min_balance); @@ -1474,23 +1517,26 @@ fn transfer_return_code() { #[test] 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(); + 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 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( - RuntimeOrigin::signed(ALICE), + let addr_bob = Contracts::bare_instantiate( + ALICE, min_balance * 100, GAS_LIMIT, None, - caller_code, + Code::Upload(caller_code), vec![0], vec![], - ),); - let addr_bob = Contracts::contract_address(&ALICE, &caller_hash, &[]); + false, + ) + .result + .unwrap() + .account_id; Balances::make_free_balance_be(&addr_bob, min_balance); // Contract calls into Django which is no valid contract @@ -1508,16 +1554,19 @@ fn call_return_code() { .unwrap(); assert_return_code!(result, RuntimeReturnCode::NotCallable); - assert_ok!(Contracts::instantiate_with_code( - RuntimeOrigin::signed(CHARLIE), + let addr_django = Contracts::bare_instantiate( + CHARLIE, min_balance * 100, GAS_LIMIT, None, - callee_code, + Code::Upload(callee_code), vec![0], vec![], - ),); - let addr_django = Contracts::contract_address(&CHARLIE, &callee_hash, &[]); + false, + ) + .result + .unwrap() + .account_id; Balances::make_free_balance_be(&addr_django, min_balance); // Contract has only the minimal balance so any transfer will fail. @@ -1605,7 +1654,7 @@ fn call_return_code() { #[test] fn instantiate_return_code() { - let (caller_code, caller_hash) = compile_module::("instantiate_return_code").unwrap(); + 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 min_balance = ::Currency::minimum_balance(); @@ -1621,18 +1670,21 @@ fn instantiate_return_code() { callee_code, vec![], vec![], - ),); + )); - assert_ok!(Contracts::instantiate_with_code( - RuntimeOrigin::signed(ALICE), + let addr = Contracts::bare_instantiate( + ALICE, min_balance * 100, GAS_LIMIT, None, - caller_code, + Code::Upload(caller_code), vec![], vec![], - ),); - let addr = Contracts::contract_address(&ALICE, &caller_hash, &[]); + false, + ) + .result + .unwrap() + .account_id; // Contract has only the minimal balance so any transfer will fail. Balances::make_free_balance_be(&addr, min_balance); @@ -1741,20 +1793,23 @@ fn disabled_chain_extension_wont_deploy() { #[test] fn disabled_chain_extension_errors_on_call() { - let (code, hash) = compile_module::("chain_extension").unwrap(); + let (code, _hash) = compile_module::("chain_extension").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( - RuntimeOrigin::signed(ALICE), + let addr = Contracts::bare_instantiate( + ALICE, min_balance * 100, GAS_LIMIT, None, - code, + Code::Upload(code), vec![], vec![], - ),); - let addr = Contracts::contract_address(&ALICE, &hash, &[]); + false, + ) + .result + .unwrap() + .account_id; TestExtension::disable(); assert_err_ignore_postinfo!( Contracts::call(RuntimeOrigin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, None, vec![],), @@ -1765,20 +1820,23 @@ fn disabled_chain_extension_errors_on_call() { #[test] fn chain_extension_works() { - let (code, hash) = compile_module::("chain_extension").unwrap(); + let (code, _hash) = compile_module::("chain_extension").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( - RuntimeOrigin::signed(ALICE), + let addr = Contracts::bare_instantiate( + ALICE, min_balance * 100, GAS_LIMIT, None, - code, + Code::Upload(code), vec![], vec![], - ),); - let addr = Contracts::contract_address(&ALICE, &hash, &[]); + false, + ) + .result + .unwrap() + .account_id; // 0 = read input buffer and pass it through as output let input: Vec = ExtensionInput { extension_id: 0, func_id: 0, extra: &[99] }.into(); @@ -1901,20 +1959,23 @@ fn chain_extension_works() { #[test] fn chain_extension_temp_storage_works() { - let (code, hash) = compile_module::("chain_extension_temp_storage").unwrap(); + 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( - RuntimeOrigin::signed(ALICE), + let addr = Contracts::bare_instantiate( + ALICE, min_balance * 100, GAS_LIMIT, None, - code, + Code::Upload(code), vec![], vec![], - ),); - let addr = Contracts::contract_address(&ALICE, &hash, &[]); + false, + ) + .result + .unwrap() + .account_id; // Call func 0 and func 1 back to back. let stop_recursion = 0u8; @@ -1943,22 +2004,25 @@ fn chain_extension_temp_storage_works() { #[test] fn lazy_removal_works() { - let (code, hash) = compile_module::("self_destruct").unwrap(); + 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); - assert_ok!(Contracts::instantiate_with_code( - RuntimeOrigin::signed(ALICE), + let addr = Contracts::bare_instantiate( + ALICE, min_balance * 100, GAS_LIMIT, None, - code, + Code::Upload(code), vec![], vec![], - ),); + false, + ) + .result + .unwrap() + .account_id; - let addr = Contracts::contract_address(&ALICE, &hash, &[]); let info = get_contract(&addr); let trie = &info.child_trie_info(); @@ -2010,24 +2074,27 @@ fn lazy_removal_on_full_queue_works_on_initialize() { #[test] fn lazy_batch_removal_works() { - let (code, hash) = compile_module::("self_destruct").unwrap(); + 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( - RuntimeOrigin::signed(ALICE), + let addr = Contracts::bare_instantiate( + ALICE, min_balance * 100, GAS_LIMIT, None, - code.clone(), + Code::Upload(code.clone()), vec![], vec![i], - ),); + false, + ) + .result + .unwrap() + .account_id; - let addr = Contracts::contract_address(&ALICE, &hash, &[i]); let info = get_contract(&addr); let trie = &info.child_trie_info(); @@ -2063,7 +2130,7 @@ fn lazy_batch_removal_works() { #[test] fn lazy_removal_partial_remove_works() { - let (code, hash) = compile_module::("self_destruct").unwrap(); + let (code, _hash) = compile_module::("self_destruct").unwrap(); // We create a contract with some extra keys above the weight limit let extra_keys = 7u32; @@ -2079,17 +2146,20 @@ fn lazy_removal_partial_remove_works() { let min_balance = ::Currency::minimum_balance(); let _ = Balances::deposit_creating(&ALICE, 1000 * min_balance); - assert_ok!(Contracts::instantiate_with_code( - RuntimeOrigin::signed(ALICE), + let addr = Contracts::bare_instantiate( + ALICE, min_balance * 100, GAS_LIMIT, None, - code, + Code::Upload(code), vec![], vec![], - ),); + false, + ) + .result + .unwrap() + .account_id; - let addr = Contracts::contract_address(&ALICE, &hash, &[]); let info = get_contract(&addr); // Put value into the contracts child trie @@ -2186,22 +2256,25 @@ fn lazy_removal_does_no_run_on_full_queue_and_full_block() { #[test] fn lazy_removal_does_no_run_on_low_remaining_weight() { - let (code, hash) = compile_module::("self_destruct").unwrap(); + 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); - assert_ok!(Contracts::instantiate_with_code( - RuntimeOrigin::signed(ALICE), + let addr = Contracts::bare_instantiate( + ALICE, min_balance * 100, GAS_LIMIT, None, - code, + Code::Upload(code), vec![], vec![], - ),); + false, + ) + .result + .unwrap() + .account_id; - let addr = Contracts::contract_address(&ALICE, &hash, &[]); let info = get_contract(&addr); let trie = &info.child_trie_info(); @@ -2250,7 +2323,7 @@ fn lazy_removal_does_no_run_on_low_remaining_weight() { #[test] fn lazy_removal_does_not_use_all_weight() { - let (code, hash) = compile_module::("self_destruct").unwrap(); + let (code, _hash) = compile_module::("self_destruct").unwrap(); let weight_limit = Weight::from_ref_time(5_000_000_000); let mut ext = ExtBuilder::default().existential_deposit(50).build(); @@ -2259,17 +2332,20 @@ fn lazy_removal_does_not_use_all_weight() { let min_balance = ::Currency::minimum_balance(); let _ = Balances::deposit_creating(&ALICE, 1000 * min_balance); - assert_ok!(Contracts::instantiate_with_code( - RuntimeOrigin::signed(ALICE), + let addr = Contracts::bare_instantiate( + ALICE, min_balance * 100, GAS_LIMIT, None, - code, + Code::Upload(code), vec![], vec![], - ),); + false, + ) + .result + .unwrap() + .account_id; - let addr = Contracts::contract_address(&ALICE, &hash, &[]); let info = get_contract(&addr); let (weight_per_key, max_keys) = Storage::::deletion_budget(1, weight_limit); @@ -2334,22 +2410,24 @@ fn lazy_removal_does_not_use_all_weight() { #[test] fn deletion_queue_full() { - let (code, hash) = compile_module::("self_destruct").unwrap(); + 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); - assert_ok!(Contracts::instantiate_with_code( - RuntimeOrigin::signed(ALICE), + let addr = Contracts::bare_instantiate( + ALICE, min_balance * 100, GAS_LIMIT, None, - code, + Code::Upload(code), vec![], vec![], - ),); - - let addr = Contracts::contract_address(&ALICE, &hash, &[]); + false, + ) + .result + .unwrap() + .account_id; // fill the deletion queue up until its limit Storage::::fill_queue_with_dummies(); @@ -2373,43 +2451,50 @@ fn refcounter() { 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( - RuntimeOrigin::signed(ALICE), + let addr0 = Contracts::bare_instantiate( + ALICE, min_balance * 100, GAS_LIMIT, None, - wasm.clone(), + Code::Upload(wasm.clone()), vec![], vec![0], - )); - assert_ok!(Contracts::instantiate_with_code( - RuntimeOrigin::signed(ALICE), + false, + ) + .result + .unwrap() + .account_id; + let addr1 = Contracts::bare_instantiate( + ALICE, min_balance * 100, GAS_LIMIT, None, - wasm.clone(), + Code::Upload(wasm.clone()), vec![], vec![1], - )); + false, + ) + .result + .unwrap() + .account_id; assert_refcount!(code_hash, 2); // Sharing should also work with the usual instantiate call - assert_ok!(Contracts::instantiate( - RuntimeOrigin::signed(ALICE), + let addr2 = Contracts::bare_instantiate( + ALICE, min_balance * 100, GAS_LIMIT, None, - code_hash, + Code::Existing(code_hash), vec![], vec![2], - )); + false, + ) + .result + .unwrap() + .account_id; assert_refcount!(code_hash, 3); - // addresses of all three existing contracts - let addr0 = Contracts::contract_address(&ALICE, &code_hash, &[0]); - let addr1 = Contracts::contract_address(&ALICE, &code_hash, &[1]); - let addr2 = Contracts::contract_address(&ALICE, &code_hash, &[2]); - // Terminating one contract should decrement the refcount assert_ok!(Contracts::call( RuntimeOrigin::signed(ALICE), @@ -2461,17 +2546,19 @@ fn reinstrument_does_charge() { let zero = 0u32.to_le_bytes().encode(); let code_len = wasm.len() as u32; - assert_ok!(Contracts::instantiate_with_code( - RuntimeOrigin::signed(ALICE), + let addr = Contracts::bare_instantiate( + ALICE, min_balance * 100, GAS_LIMIT, None, - wasm, + Code::Upload(wasm), zero.clone(), vec![], - )); - - let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); + false, + ) + .result + .unwrap() + .account_id; // Call the contract two times without reinstrument @@ -2531,20 +2618,23 @@ fn reinstrument_does_charge() { #[test] fn debug_message_works() { - let (wasm, code_hash) = compile_module::("debug_message_works").unwrap(); + let (wasm, _code_hash) = compile_module::("debug_message_works").unwrap(); ExtBuilder::default().existential_deposit(50).build().execute_with(|| { let _ = Balances::deposit_creating(&ALICE, 1_000_000); - assert_ok!(Contracts::instantiate_with_code( - RuntimeOrigin::signed(ALICE), + let addr = Contracts::bare_instantiate( + ALICE, 30_000, GAS_LIMIT, None, - wasm, + Code::Upload(wasm), vec![], vec![], - ),); - let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); + false, + ) + .result + .unwrap() + .account_id; let result = Contracts::bare_call( ALICE, addr, @@ -2563,20 +2653,23 @@ fn debug_message_works() { #[test] fn debug_message_logging_disabled() { - let (wasm, code_hash) = compile_module::("debug_message_logging_disabled").unwrap(); + let (wasm, _code_hash) = compile_module::("debug_message_logging_disabled").unwrap(); ExtBuilder::default().existential_deposit(50).build().execute_with(|| { let _ = Balances::deposit_creating(&ALICE, 1_000_000); - assert_ok!(Contracts::instantiate_with_code( - RuntimeOrigin::signed(ALICE), + let addr = Contracts::bare_instantiate( + ALICE, 30_000, GAS_LIMIT, None, - wasm, + Code::Upload(wasm), vec![], vec![], - ),); - let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); + false, + ) + .result + .unwrap() + .account_id; // disable logging by passing `false` let result = Contracts::bare_call( ALICE, @@ -2597,20 +2690,23 @@ fn debug_message_logging_disabled() { #[test] fn debug_message_invalid_utf8() { - let (wasm, code_hash) = compile_module::("debug_message_invalid_utf8").unwrap(); + let (wasm, _code_hash) = compile_module::("debug_message_invalid_utf8").unwrap(); ExtBuilder::default().existential_deposit(50).build().execute_with(|| { let _ = Balances::deposit_creating(&ALICE, 1_000_000); - assert_ok!(Contracts::instantiate_with_code( - RuntimeOrigin::signed(ALICE), + let addr = Contracts::bare_instantiate( + ALICE, 30_000, GAS_LIMIT, None, - wasm, + Code::Upload(wasm), vec![], vec![], - ),); - let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); + false, + ) + .result + .unwrap() + .account_id; let result = Contracts::bare_call( ALICE, addr, @@ -2627,34 +2723,40 @@ fn debug_message_invalid_utf8() { #[test] 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(); + 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 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( - RuntimeOrigin::signed(ALICE), + let addr_caller = Contracts::bare_instantiate( + ALICE, min_balance * 100, GAS_LIMIT, None, - caller_code, + Code::Upload(caller_code), vec![], vec![0], - ),); - let addr_caller = Contracts::contract_address(&ALICE, &caller_hash, &[0]); + false, + ) + .result + .unwrap() + .account_id; - assert_ok!(Contracts::instantiate_with_code( - RuntimeOrigin::signed(ALICE), + let addr_callee = Contracts::bare_instantiate( + ALICE, min_balance * 100, GAS_LIMIT, None, - callee_code, + Code::Upload(callee_code), vec![], vec![1], - ),); - let addr_callee = Contracts::contract_address(&ALICE, &callee_hash, &[1]); + false, + ) + .result + .unwrap() + .account_id; let input: Vec = AsRef::<[u8]>::as_ref(&addr_callee) .iter() @@ -2698,34 +2800,40 @@ fn gas_estimation_nested_call_fixed_limit() { #[test] 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(); + 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 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( - RuntimeOrigin::signed(ALICE), + let addr_caller = Contracts::bare_instantiate( + ALICE, min_balance * 100, GAS_LIMIT, None, - caller_code, + Code::Upload(caller_code), vec![], vec![0], - ),); - let addr_caller = Contracts::contract_address(&ALICE, &caller_hash, &[0]); + false, + ) + .result + .unwrap() + .account_id; - assert_ok!(Contracts::instantiate_with_code( - RuntimeOrigin::signed(ALICE), + let addr_callee = Contracts::bare_instantiate( + ALICE, min_balance * 100, GAS_LIMIT, None, - callee_code, + Code::Upload(callee_code), vec![], vec![1], - ),); - let addr_callee = Contracts::contract_address(&ALICE, &callee_hash, &[1]); + false, + ) + .result + .unwrap() + .account_id; // 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. @@ -2770,22 +2878,25 @@ fn gas_estimation_call_runtime() { #[test] fn ecdsa_recover() { - let (wasm, code_hash) = compile_module::("ecdsa_recover").unwrap(); + let (wasm, _code_hash) = compile_module::("ecdsa_recover").unwrap(); ExtBuilder::default().existential_deposit(50).build().execute_with(|| { let _ = Balances::deposit_creating(&ALICE, 1_000_000); // Instantiate the ecdsa_recover contract. - assert_ok!(Contracts::instantiate_with_code( - RuntimeOrigin::signed(ALICE), + let addr = Contracts::bare_instantiate( + ALICE, 100_000, GAS_LIMIT, None, - wasm, + Code::Upload(wasm), vec![], vec![], - )); - let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); + false, + ) + .result + .unwrap() + .account_id; #[rustfmt::skip] let signature: [u8; 65] = [ @@ -3072,16 +3183,19 @@ fn instantiate_with_zero_balance_works() { initialize_block(2); // Instantiate the BOB contract. - assert_ok!(Contracts::instantiate_with_code( - RuntimeOrigin::signed(ALICE), + let addr = Contracts::bare_instantiate( + ALICE, 0, GAS_LIMIT, None, - wasm, + Code::Upload(wasm), vec![], vec![], - )); - let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); + false, + ) + .result + .unwrap() + .account_id; // Check that the BOB contract has been instantiated. get_contract(&addr); @@ -3165,16 +3279,19 @@ fn instantiate_with_below_existential_deposit_works() { initialize_block(2); // Instantiate the BOB contract. - assert_ok!(Contracts::instantiate_with_code( - RuntimeOrigin::signed(ALICE), + let addr = Contracts::bare_instantiate( + ALICE, 50, GAS_LIMIT, None, - wasm, + Code::Upload(wasm), vec![], vec![], - )); - let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); + false, + ) + .result + .unwrap() + .account_id; // Check that the BOB contract has been instantiated. get_contract(&addr); @@ -3258,21 +3375,24 @@ fn instantiate_with_below_existential_deposit_works() { #[test] fn storage_deposit_works() { - let (wasm, code_hash) = compile_module::("multi_store").unwrap(); + 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( - RuntimeOrigin::signed(ALICE), + let addr = Contracts::bare_instantiate( + ALICE, 0, GAS_LIMIT, None, - wasm, + Code::Upload(wasm), vec![], vec![], - )); - let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); + false, + ) + .result + .unwrap() + .account_id; // Drop previous events initialize_block(2); @@ -3413,16 +3533,19 @@ fn set_code_extrinsic() { 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), + let addr = Contracts::bare_instantiate( + ALICE, 0, GAS_LIMIT, None, - wasm, + Code::Upload(wasm), vec![], vec![], - )); - let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); + false, + ) + .result + .unwrap() + .account_id; assert_ok!(Contracts::upload_code( RuntimeOrigin::signed(ALICE), @@ -3490,21 +3613,24 @@ fn set_code_extrinsic() { #[test] fn call_after_killed_account_needs_funding() { - let (wasm, code_hash) = compile_module::("dummy").unwrap(); + 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( - RuntimeOrigin::signed(ALICE), + let addr = Contracts::bare_instantiate( + ALICE, 700, GAS_LIMIT, None, - wasm, + Code::Upload(wasm), vec![], vec![], - )); - let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); + false, + ) + .result + .unwrap() + .account_id; // Drop previous events initialize_block(2); @@ -3791,21 +3917,23 @@ 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( - RuntimeOrigin::signed(ALICE), + let contract_addr = Contracts::bare_instantiate( + ALICE, 300_000, GAS_LIMIT, None, - wasm, + Code::Upload(wasm), vec![], vec![], - )); + false, + ) + .result + .unwrap() + .account_id; // upload new code assert_ok!(Contracts::upload_code( RuntimeOrigin::signed(ALICE), @@ -3882,22 +4010,25 @@ fn set_code_hash() { #[test] fn storage_deposit_limit_is_enforced() { - let (wasm, code_hash) = compile_module::("store").unwrap(); + 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), + let addr = Contracts::bare_instantiate( + ALICE, 0, GAS_LIMIT, None, - wasm, + Code::Upload(wasm), vec![], vec![], - )); - let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); + false, + ) + .result + .unwrap() + .account_id; // Check that the BOB contract has been instantiated and has the minimum balance assert_eq!(get_contract(&addr).total_deposit(), min_balance); @@ -3920,33 +4051,39 @@ fn storage_deposit_limit_is_enforced() { #[test] fn storage_deposit_limit_is_enforced_late() { - let (wasm_caller, code_hash_caller) = + let (wasm_caller, _code_hash_caller) = compile_module::("create_storage_and_call").unwrap(); - let (wasm_callee, code_hash_callee) = compile_module::("store").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), + let addr_caller = Contracts::bare_instantiate( + ALICE, 0, GAS_LIMIT, None, - wasm_caller, + Code::Upload(wasm_caller), vec![], vec![], - )); - let addr_caller = Contracts::contract_address(&ALICE, &code_hash_caller, &[]); - assert_ok!(Contracts::instantiate_with_code( - RuntimeOrigin::signed(ALICE), + false, + ) + .result + .unwrap() + .account_id; + let addr_callee = Contracts::bare_instantiate( + ALICE, 0, GAS_LIMIT, None, - wasm_callee, + Code::Upload(wasm_callee), vec![], vec![], - )); - let addr_callee = Contracts::contract_address(&ALICE, &code_hash_callee, &[]); + false, + ) + .result + .unwrap() + .account_id; // Create 100 bytes of storage with a price of per byte // This is 100 Balance + 2 Balance for the item @@ -4059,23 +4196,26 @@ fn storage_deposit_limit_is_enforced_late() { #[test] fn deposit_limit_honors_liquidity_restrictions() { - let (wasm, code_hash) = compile_module::("store").unwrap(); + 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), + let addr = Contracts::bare_instantiate( + ALICE, 0, GAS_LIMIT, None, - wasm, + Code::Upload(wasm), vec![], vec![], - )); - let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); + false, + ) + .result + .unwrap() + .account_id; // Check that the contract has been instantiated and has the minimum balance assert_eq!(get_contract(&addr).total_deposit(), min_balance); @@ -4100,23 +4240,26 @@ fn deposit_limit_honors_liquidity_restrictions() { #[test] fn deposit_limit_honors_existential_deposit() { - let (wasm, code_hash) = compile_module::("store").unwrap(); + 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), + let addr = Contracts::bare_instantiate( + ALICE, 0, GAS_LIMIT, None, - wasm, + Code::Upload(wasm), vec![], vec![], - )); - let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); + false, + ) + .result + .unwrap() + .account_id; // Check that the contract has been instantiated and has the minimum balance assert_eq!(get_contract(&addr).total_deposit(), min_balance); @@ -4140,23 +4283,26 @@ fn deposit_limit_honors_existential_deposit() { #[test] fn deposit_limit_honors_min_leftover() { - let (wasm, code_hash) = compile_module::("store").unwrap(); + 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), + let addr = Contracts::bare_instantiate( + ALICE, 0, GAS_LIMIT, None, - wasm, + Code::Upload(wasm), vec![], vec![], - )); - let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); + false, + ) + .result + .unwrap() + .account_id; // Check that the contract has been instantiated and has the minimum balance assert_eq!(get_contract(&addr).total_deposit(), min_balance); @@ -4420,21 +4566,24 @@ fn delegate_call_indeterministic_code() { #[test] 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, &[]); + let (wasm, _code_hash) = compile_module::("reentrance_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), + let contract_addr = Contracts::bare_instantiate( + ALICE, 300_000, GAS_LIMIT, None, - wasm, + Code::Upload(wasm), vec![], vec![], - )); + false, + ) + .result + .unwrap() + .account_id; // passing reentrant count to the input let input = 0.encode(); @@ -4457,20 +4606,23 @@ fn reentrance_count_works_with_call() { #[test] 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(|| { let _ = Balances::deposit_creating(&ALICE, 1_000_000); - assert_ok!(Contracts::instantiate_with_code( - RuntimeOrigin::signed(ALICE), + let contract_addr = Contracts::bare_instantiate( + ALICE, 300_000, GAS_LIMIT, None, - wasm, + Code::Upload(wasm), vec![], vec![], - )); + false, + ) + .result + .unwrap() + .account_id; // adding a callstack height to the input let input = (code_hash, 1).encode(); @@ -4492,36 +4644,40 @@ fn reentrance_count_works_with_delegated_call() { #[test] fn account_reentrance_count_works() { - let (wasm, code_hash) = compile_module::("account_reentrance_count_call").unwrap(); - let (wasm_reentrance_count, code_hash_reentrance_count) = + let (wasm, _code_hash) = compile_module::("account_reentrance_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); - assert_ok!(Contracts::instantiate_with_code( - RuntimeOrigin::signed(ALICE), + let contract_addr = Contracts::bare_instantiate( + ALICE, 300_000, GAS_LIMIT, None, - wasm, + Code::Upload(wasm), vec![], vec![], - )); + false, + ) + .result + .unwrap() + .account_id; - assert_ok!(Contracts::instantiate_with_code( - RuntimeOrigin::signed(ALICE), + let another_contract_addr = Contracts::bare_instantiate( + ALICE, 300_000, GAS_LIMIT, None, - wasm_reentrance_count, + Code::Upload(wasm_reentrance_count), vec![], - vec![] - )); - - let contract_addr = Contracts::contract_address(&ALICE, &code_hash, &[]); - let another_contract_addr = - Contracts::contract_address(&ALICE, &code_hash_reentrance_count, &[]); + vec![], + false, + ) + .result + .unwrap() + .account_id; 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 eb337ac682860..410d26921543d 100644 --- a/frame/contracts/src/wasm/code_cache.rs +++ b/frame/contracts/src/wasm/code_cache.rs @@ -41,7 +41,6 @@ use frame_support::{ traits::{Get, ReservableCurrency}, WeakBoundedVec, }; -use sp_core::crypto::UncheckedFrom; use sp_runtime::traits::BadOrigin; use sp_std::vec; @@ -49,10 +48,7 @@ use sp_std::vec; /// /// Increments the refcount of the in-storage `prefab_module` if it already exists in storage /// under the specified `code_hash`. -pub fn store(mut module: PrefabWasmModule, instantiated: bool) -> DispatchResult -where - T::AccountId: UncheckedFrom + AsRef<[u8]>, -{ +pub fn store(mut module: PrefabWasmModule, instantiated: bool) -> DispatchResult { let code_hash = sp_std::mem::take(&mut module.code_hash); >::mutate(&code_hash, |existing| match existing { Some(existing) => { @@ -135,10 +131,7 @@ 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 -where - T::AccountId: UncheckedFrom + AsRef<[u8]>, -{ +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); @@ -164,10 +157,7 @@ pub fn load( code_hash: CodeHash, schedule: &Schedule, gas_meter: &mut GasMeter, -) -> Result, DispatchError> -where - T::AccountId: UncheckedFrom + AsRef<[u8]>, -{ +) -> Result, DispatchError> { let max_code_len = T::MaxCodeLen::get(); let charged = gas_meter.charge(CodeToken::Load(max_code_len))?; @@ -192,10 +182,7 @@ where pub fn reinstrument( prefab_module: &mut PrefabWasmModule, schedule: &Schedule, -) -> Result -where - T::AccountId: UncheckedFrom + AsRef<[u8]>, -{ +) -> Result { let original_code = >::get(&prefab_module.code_hash).ok_or(Error::::CodeNotFound)?; let original_code_len = original_code.len(); diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index d85dac95cc712..903ca0abb5e06 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, Get}; +use sp_core::Get; use sp_runtime::RuntimeDebug; use sp_std::prelude::*; #[cfg(test)] @@ -140,10 +140,7 @@ impl ExportedFunction { } } -impl PrefabWasmModule -where - T::AccountId: UncheckedFrom + AsRef<[u8]>, -{ +impl PrefabWasmModule { /// Create the module by checking and instrumenting `original_code`. /// /// This does **not** store the module. For this one need to either call [`Self::store`] @@ -263,10 +260,7 @@ impl OwnerInfo { } } -impl Executable for PrefabWasmModule -where - T::AccountId: UncheckedFrom + AsRef<[u8]>, -{ +impl Executable for PrefabWasmModule { fn from_storage( code_hash: CodeHash, schedule: &Schedule, @@ -476,7 +470,7 @@ mod tests { salt: salt.to_vec(), }); Ok(( - Contracts::::contract_address(&ALICE, &code_hash, salt), + Contracts::::contract_address(&ALICE, &code_hash, &data, salt), ExecReturnValue { flags: ReturnFlags::empty(), data: Vec::new() }, )) } diff --git a/frame/contracts/src/wasm/prepare.rs b/frame/contracts/src/wasm/prepare.rs index c63a5b1e135d9..9bb58bb02b5ea 100644 --- a/frame/contracts/src/wasm/prepare.rs +++ b/frame/contracts/src/wasm/prepare.rs @@ -26,7 +26,6 @@ use crate::{ 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::{ @@ -396,7 +395,6 @@ fn instrument( 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 @@ -500,7 +498,6 @@ pub fn prepare( where E: Environment<()>, T: Config, - T::AccountId: UncheckedFrom + AsRef<[u8]>, { let (code, (initial, maximum)) = instrument::(original_code.as_ref(), schedule, determinism, try_instantiate)?; @@ -547,7 +544,6 @@ pub fn reinstrument( where E: Environment<()>, T: Config, - T::AccountId: UncheckedFrom + AsRef<[u8]>, { instrument::(original_code, schedule, determinism, TryInstantiate::Skip) .map_err(|(err, msg)| { diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index 066c1d71ea444..aaacb9e5f80e6 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -29,7 +29,6 @@ use codec::{Decode, DecodeLimit, Encode, MaxEncodedLen}; 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_std::{fmt, prelude::*}; @@ -270,11 +269,7 @@ pub enum RuntimeCosts { } impl RuntimeCosts { - fn token(&self, s: &HostFnWeights) -> RuntimeToken - where - T: Config, - T::AccountId: UncheckedFrom + AsRef<[u8]>, - { + fn token(&self, s: &HostFnWeights) -> RuntimeToken { use self::RuntimeCosts::*; let weight = match *self { MeteringBlock(amount) => s.gas.saturating_add(amount), @@ -324,7 +319,7 @@ impl RuntimeCosts { CallInputCloned(len) => s.call_per_cloned_byte.saturating_mul(len.into()), InstantiateBase { input_data_len, salt_len } => s .instantiate - .saturating_add(s.return_per_byte.saturating_mul(input_data_len.into())) + .saturating_add(s.instantiate_per_input_byte.saturating_mul(input_data_len.into())) .saturating_add(s.instantiate_per_salt_byte.saturating_mul(salt_len.into())), InstantiateSurchargeTransfer => s.instantiate_transfer_surcharge, HashSha256(len) => s @@ -375,11 +370,7 @@ struct RuntimeToken { weight: Weight, } -impl Token for RuntimeToken -where - T: Config, - T::AccountId: UncheckedFrom + AsRef<[u8]>, -{ +impl Token for RuntimeToken { fn weight(&self) -> Weight { self.weight } @@ -463,12 +454,7 @@ pub struct Runtime<'a, E: Ext + 'a> { chain_extension: Option::ChainExtension>>, } -impl<'a, E> Runtime<'a, E> -where - E: Ext + 'a, - ::AccountId: - UncheckedFrom<::Hash> + AsRef<[u8]>, -{ +impl<'a, E: Ext + 'a> Runtime<'a, E> { pub fn new(ext: &'a mut E, input_data: Vec) -> Self { Runtime { ext, diff --git a/frame/contracts/src/weights.rs b/frame/contracts/src/weights.rs index c3f3b50097278..69fcbd6eec983 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-12-01, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-12-09, 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,8 +53,8 @@ pub trait WeightInfo { fn on_initialize_per_queue_item(q: u32, ) -> Weight; fn reinstrument(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 instantiate_with_code(c: u32, i: u32, s: u32, ) -> Weight; + fn instantiate(i: u32, s: u32, ) -> Weight; fn call() -> Weight; fn upload_code(c: u32, ) -> Weight; fn remove_code() -> Weight; @@ -98,7 +98,7 @@ pub trait WeightInfo { fn seal_delegate_call(r: u32, ) -> Weight; fn seal_call_per_transfer_clone_kb(t: u32, c: u32, ) -> Weight; fn seal_instantiate(r: u32, ) -> Weight; - fn seal_instantiate_per_transfer_salt_kb(t: u32, s: u32, ) -> Weight; + fn seal_instantiate_per_transfer_input_salt_kb(t: u32, i: 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; @@ -172,17 +172,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_148 nanoseconds. - Weight::from_ref_time(3_326_000) + // Minimum execution time: 3_196 nanoseconds. + Weight::from_ref_time(3_293_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_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())) + // Minimum execution time: 14_857 nanoseconds. + Weight::from_ref_time(14_957_593) + // Standard Error: 1_015 + .saturating_add(Weight::from_ref_time(935_359).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()))) @@ -190,10 +190,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_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())) + // Minimum execution time: 3_231 nanoseconds. + Weight::from_ref_time(14_859_580) + // Standard Error: 3_479 + .saturating_add(Weight::from_ref_time(1_185_600).saturating_mul(q.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -201,10 +201,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: 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())) + // Minimum execution time: 34_565 nanoseconds. + Weight::from_ref_time(29_199_016) + // Standard Error: 70 + .saturating_add(Weight::from_ref_time(47_107).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -215,10 +215,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: 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())) + // Minimum execution time: 392_074 nanoseconds. + Weight::from_ref_time(404_090_909) + // Standard Error: 24 + .saturating_add(Weight::from_ref_time(30_454).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -231,14 +231,17 @@ impl WeightInfo for SubstrateWeight { // 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 `i` is `[0, 1048576]`. /// The range of component `s` is `[0, 1048576]`. - fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - // 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())) + fn instantiate_with_code(c: u32, i: u32, s: u32, ) -> Weight { + // Minimum execution time: 3_785_934 nanoseconds. + Weight::from_ref_time(683_143_843) + // Standard Error: 272 + .saturating_add(Weight::from_ref_time(87_620).saturating_mul(c.into())) + // Standard Error: 16 + .saturating_add(Weight::from_ref_time(1_363).saturating_mul(i.into())) + // Standard Error: 16 + .saturating_add(Weight::from_ref_time(1_778).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(9)) } @@ -249,12 +252,15 @@ impl WeightInfo for SubstrateWeight { // 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 `i` is `[0, 1048576]`. /// The range of component `s` is `[0, 1048576]`. - fn instantiate(s: u32, ) -> Weight { - // 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())) + fn instantiate(i: u32, s: u32, ) -> Weight { + // Minimum execution time: 1_935_310 nanoseconds. + Weight::from_ref_time(203_531_122) + // Standard Error: 8 + .saturating_add(Weight::from_ref_time(1_674).saturating_mul(i.into())) + // Standard Error: 8 + .saturating_add(Weight::from_ref_time(1_789).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(7)) } @@ -264,8 +270,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: 154_738 nanoseconds. - Weight::from_ref_time(159_212_000) + // Minimum execution time: 151_999 nanoseconds. + Weight::from_ref_time(153_527_000) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -275,10 +281,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: 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())) + // Minimum execution time: 391_165 nanoseconds. + Weight::from_ref_time(394_519_487) + // Standard Error: 75 + .saturating_add(Weight::from_ref_time(89_736).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -287,8 +293,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: 39_892 nanoseconds. - Weight::from_ref_time(40_258_000) + // Minimum execution time: 39_354 nanoseconds. + Weight::from_ref_time(39_855_000) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -296,8 +302,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_441 nanoseconds. - Weight::from_ref_time(42_011_000) + // Minimum execution time: 40_909 nanoseconds. + Weight::from_ref_time(41_275_000) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(6)) } @@ -308,10 +314,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: 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())) + // Minimum execution time: 380_150 nanoseconds. + Weight::from_ref_time(384_429_035) + // Standard Error: 34_740 + .saturating_add(Weight::from_ref_time(15_582_218).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -322,10 +328,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: 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())) + // Minimum execution time: 380_608 nanoseconds. + Weight::from_ref_time(326_544_805) + // Standard Error: 475_381 + .saturating_add(Weight::from_ref_time(190_717_772).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)) @@ -337,10 +343,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: 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())) + // Minimum execution time: 382_780 nanoseconds. + Weight::from_ref_time(333_775_113) + // Standard Error: 446_086 + .saturating_add(Weight::from_ref_time(232_531_042).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)) @@ -352,10 +358,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: 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())) + // Minimum execution time: 381_815 nanoseconds. + Weight::from_ref_time(390_931_793) + // Standard Error: 61_918 + .saturating_add(Weight::from_ref_time(18_798_438).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -366,10 +372,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: 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())) + // Minimum execution time: 379_162 nanoseconds. + Weight::from_ref_time(383_796_363) + // Standard Error: 25_555 + .saturating_add(Weight::from_ref_time(10_843_721).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -380,10 +386,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: 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())) + // Minimum execution time: 380_307 nanoseconds. + Weight::from_ref_time(390_211_779) + // Standard Error: 53_326 + .saturating_add(Weight::from_ref_time(15_311_171).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -394,10 +400,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: 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())) + // Minimum execution time: 380_230 nanoseconds. + Weight::from_ref_time(383_470_453) + // Standard Error: 45_007 + .saturating_add(Weight::from_ref_time(15_582_472).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -408,10 +414,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: 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())) + // Minimum execution time: 380_244 nanoseconds. + Weight::from_ref_time(388_092_461) + // Standard Error: 98_199 + .saturating_add(Weight::from_ref_time(97_339_528).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -422,10 +428,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: 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())) + // Minimum execution time: 380_242 nanoseconds. + Weight::from_ref_time(384_078_258) + // Standard Error: 28_510 + .saturating_add(Weight::from_ref_time(15_423_359).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -436,10 +442,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: 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())) + // Minimum execution time: 379_890 nanoseconds. + Weight::from_ref_time(383_658_430) + // Standard Error: 44_976 + .saturating_add(Weight::from_ref_time(15_451_905).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -450,10 +456,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: 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())) + // Minimum execution time: 380_269 nanoseconds. + Weight::from_ref_time(383_580_481) + // Standard Error: 31_862 + .saturating_add(Weight::from_ref_time(15_230_473).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -464,10 +470,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: 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())) + // Minimum execution time: 380_308 nanoseconds. + Weight::from_ref_time(383_732_372) + // Standard Error: 38_359 + .saturating_add(Weight::from_ref_time(15_358_775).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -479,10 +485,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: 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())) + // Minimum execution time: 380_834 nanoseconds. + Weight::from_ref_time(388_999_459) + // Standard Error: 96_447 + .saturating_add(Weight::from_ref_time(86_714_414).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -493,10 +499,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: 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())) + // Minimum execution time: 140_955 nanoseconds. + Weight::from_ref_time(144_716_423) + // Standard Error: 11_370 + .saturating_add(Weight::from_ref_time(7_858_807).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -507,10 +513,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: 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())) + // Minimum execution time: 380_210 nanoseconds. + Weight::from_ref_time(384_185_776) + // Standard Error: 49_038 + .saturating_add(Weight::from_ref_time(13_649_793).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -521,10 +527,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: 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())) + // Minimum execution time: 396_209 nanoseconds. + Weight::from_ref_time(424_522_611) + // Standard Error: 3_917 + .saturating_add(Weight::from_ref_time(9_627_216).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -535,10 +541,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: 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())) + // Minimum execution time: 378_412 nanoseconds. + Weight::from_ref_time(380_502_085) + // Standard Error: 201_552 + .saturating_add(Weight::from_ref_time(1_434_214).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -549,10 +555,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: 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())) + // Minimum execution time: 381_463 nanoseconds. + Weight::from_ref_time(383_955_553) + // Standard Error: 998 + .saturating_add(Weight::from_ref_time(230_512).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -565,10 +571,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: 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())) + // Minimum execution time: 379_877 nanoseconds. + Weight::from_ref_time(381_729_546) + // Standard Error: 214_004 + .saturating_add(Weight::from_ref_time(52_528_353).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)) @@ -582,10 +588,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: 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())) + // Minimum execution time: 380_275 nanoseconds. + Weight::from_ref_time(386_495_777) + // Standard Error: 94_674 + .saturating_add(Weight::from_ref_time(108_432_929).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -596,10 +602,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: 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())) + // Minimum execution time: 379_095 nanoseconds. + Weight::from_ref_time(393_997_924) + // Standard Error: 141_916 + .saturating_add(Weight::from_ref_time(212_937_170).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -611,12 +617,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_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())) + // Minimum execution time: 1_241_001 nanoseconds. + Weight::from_ref_time(548_526_917) + // Standard Error: 496_807 + .saturating_add(Weight::from_ref_time(177_087_769).saturating_mul(t.into())) + // Standard Error: 136_447 + .saturating_add(Weight::from_ref_time(71_558_402).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)) @@ -629,20 +635,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: 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())) + // Minimum execution time: 159_158 nanoseconds. + Weight::from_ref_time(163_427_712) + // Standard Error: 22_442 + .saturating_add(Weight::from_ref_time(12_647_838).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: 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())) + // Minimum execution time: 381_068 nanoseconds. + Weight::from_ref_time(341_041_230) + // Standard Error: 464_053 + .saturating_add(Weight::from_ref_time(402_677_314).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)) @@ -651,10 +657,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: 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())) + // Minimum execution time: 508_695 nanoseconds. + Weight::from_ref_time(663_159_695) + // Standard Error: 1_419_342 + .saturating_add(Weight::from_ref_time(96_558_570).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)) @@ -663,10 +669,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: 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())) + // Minimum execution time: 508_542 nanoseconds. + Weight::from_ref_time(634_146_978) + // Standard Error: 1_168_252 + .saturating_add(Weight::from_ref_time(64_231_947).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)) @@ -675,10 +681,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: 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())) + // Minimum execution time: 381_743 nanoseconds. + Weight::from_ref_time(337_309_674) + // Standard Error: 527_407 + .saturating_add(Weight::from_ref_time(395_767_068).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)) @@ -687,10 +693,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: 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())) + // Minimum execution time: 478_283 nanoseconds. + Weight::from_ref_time(616_673_245) + // Standard Error: 1_290_784 + .saturating_add(Weight::from_ref_time(66_534_552).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)) @@ -699,10 +705,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: 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())) + // Minimum execution time: 381_916 nanoseconds. + Weight::from_ref_time(349_150_912) + // Standard Error: 443_388 + .saturating_add(Weight::from_ref_time(316_975_558).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)) @@ -710,10 +716,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: 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())) + // Minimum execution time: 459_294 nanoseconds. + Weight::from_ref_time(579_698_524) + // Standard Error: 1_111_681 + .saturating_add(Weight::from_ref_time(159_276_087).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)) @@ -721,10 +727,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: 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())) + // Minimum execution time: 381_700 nanoseconds. + Weight::from_ref_time(352_544_675) + // Standard Error: 401_504 + .saturating_add(Weight::from_ref_time(304_380_106).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)) @@ -732,10 +738,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: 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())) + // Minimum execution time: 455_595 nanoseconds. + Weight::from_ref_time(560_428_166) + // Standard Error: 991_088 + .saturating_add(Weight::from_ref_time(61_810_610).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)) @@ -743,10 +749,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: 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())) + // Minimum execution time: 382_000 nanoseconds. + Weight::from_ref_time(336_164_219) + // Standard Error: 601_744 + .saturating_add(Weight::from_ref_time(406_198_079).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)) @@ -755,10 +761,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: 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())) + // Minimum execution time: 482_335 nanoseconds. + Weight::from_ref_time(634_245_177) + // Standard Error: 1_418_845 + .saturating_add(Weight::from_ref_time(164_352_113).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)) @@ -771,10 +777,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: 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())) + // Minimum execution time: 382_142 nanoseconds. + Weight::from_ref_time(317_581_708) + // Standard Error: 682_156 + .saturating_add(Weight::from_ref_time(1_305_289_569).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)) @@ -787,10 +793,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: 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())) + // Minimum execution time: 383_580 nanoseconds. + Weight::from_ref_time(384_176_000) + // Standard Error: 6_483_482 + .saturating_add(Weight::from_ref_time(28_047_685_517).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)) @@ -803,10 +809,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: 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())) + // Minimum execution time: 384_523 nanoseconds. + Weight::from_ref_time(385_105_000) + // Standard Error: 6_156_142 + .saturating_add(Weight::from_ref_time(27_780_652_513).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)) @@ -820,12 +826,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: 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())) + // Minimum execution time: 9_509_961 nanoseconds. + Weight::from_ref_time(8_509_991_348) + // Standard Error: 6_614_757 + .saturating_add(Weight::from_ref_time(1_244_514_376).saturating_mul(t.into())) + // Standard Error: 9_918 + .saturating_add(Weight::from_ref_time(9_856_517).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)) @@ -840,10 +846,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: 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())) + // Minimum execution time: 384_604 nanoseconds. + Weight::from_ref_time(385_278_000) + // Standard Error: 21_140_468 + .saturating_add(Weight::from_ref_time(33_100_726_150).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)) @@ -857,14 +863,15 @@ impl WeightInfo for SubstrateWeight { // 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 `i` is `[0, 960]`. /// The range of component `s` is `[0, 960]`. - fn seal_instantiate_per_transfer_salt_kb(t: u32, s: u32, ) -> Weight { - // 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())) + fn seal_instantiate_per_transfer_input_salt_kb(t: u32, i: u32, s: u32, ) -> Weight { + // Minimum execution time: 129_699_480 nanoseconds. + Weight::from_ref_time(10_187_699_005) + // Standard Error: 155_040 + .saturating_add(Weight::from_ref_time(125_284_310).saturating_mul(i.into())) + // Standard Error: 155_040 + .saturating_add(Weight::from_ref_time(125_850_564).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)) @@ -877,10 +884,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: 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())) + // Minimum execution time: 380_397 nanoseconds. + Weight::from_ref_time(382_881_855) + // Standard Error: 290_948 + .saturating_add(Weight::from_ref_time(41_017_644).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -891,10 +898,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: 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())) + // Minimum execution time: 422_439 nanoseconds. + Weight::from_ref_time(423_480_000) + // Standard Error: 56_072 + .saturating_add(Weight::from_ref_time(329_103_825).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -905,10 +912,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: 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())) + // Minimum execution time: 380_433 nanoseconds. + Weight::from_ref_time(382_325_624) + // Standard Error: 139_248 + .saturating_add(Weight::from_ref_time(53_159_175).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -919,10 +926,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: 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())) + // Minimum execution time: 434_834 nanoseconds. + Weight::from_ref_time(435_383_000) + // Standard Error: 59_824 + .saturating_add(Weight::from_ref_time(251_297_967).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -933,10 +940,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: 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())) + // Minimum execution time: 379_088 nanoseconds. + Weight::from_ref_time(381_627_077) + // Standard Error: 152_561 + .saturating_add(Weight::from_ref_time(31_696_922).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -947,10 +954,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: 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())) + // Minimum execution time: 411_630 nanoseconds. + Weight::from_ref_time(412_354_000) + // Standard Error: 50_788 + .saturating_add(Weight::from_ref_time(103_105_715).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -961,10 +968,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: 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())) + // Minimum execution time: 379_549 nanoseconds. + Weight::from_ref_time(382_406_346) + // Standard Error: 701_449 + .saturating_add(Weight::from_ref_time(31_066_353).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -975,10 +982,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: 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())) + // Minimum execution time: 412_112 nanoseconds. + Weight::from_ref_time(412_710_000) + // Standard Error: 54_875 + .saturating_add(Weight::from_ref_time(103_169_035).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -989,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_recover(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 381_994 nanoseconds. + Weight::from_ref_time(383_832_551) + // Standard Error: 676_656 + .saturating_add(Weight::from_ref_time(3_020_035_748).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -1003,10 +1010,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: 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())) + // Minimum execution time: 381_472 nanoseconds. + Weight::from_ref_time(383_590_834) + // Standard Error: 538_574 + .saturating_add(Weight::from_ref_time(2_077_926_265).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -1018,10 +1025,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: 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())) + // Minimum execution time: 381_527 nanoseconds. + Weight::from_ref_time(382_291_000) + // Standard Error: 2_760_840 + .saturating_add(Weight::from_ref_time(1_356_115_009).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)) @@ -1034,10 +1041,10 @@ 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: 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())) + // Minimum execution time: 382_722 nanoseconds. + Weight::from_ref_time(387_231_409) + // Standard Error: 28_817 + .saturating_add(Weight::from_ref_time(11_349_809).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -1048,10 +1055,10 @@ 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: 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())) + // Minimum execution time: 383_568 nanoseconds. + Weight::from_ref_time(419_835_108) + // Standard Error: 125_982 + .saturating_add(Weight::from_ref_time(25_241_800).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -1063,376 +1070,376 @@ impl WeightInfo for SubstrateWeight { // 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())) + // Minimum execution time: 382_084 nanoseconds. + Weight::from_ref_time(388_155_568) + // Standard Error: 29_161 + .saturating_add(Weight::from_ref_time(9_015_217).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. - Weight::from_ref_time(914_830) - // Standard Error: 222 - .saturating_add(Weight::from_ref_time(343_835).saturating_mul(r.into())) + // Minimum execution time: 593 nanoseconds. + Weight::from_ref_time(816_706) + // Standard Error: 173 + .saturating_add(Weight::from_ref_time(344_732).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64load(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 705 nanoseconds. + Weight::from_ref_time(1_191_205) + // Standard Error: 600 + .saturating_add(Weight::from_ref_time(986_102).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64store(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 717 nanoseconds. + Weight::from_ref_time(1_019_448) + // Standard Error: 421 + .saturating_add(Weight::from_ref_time(882_531).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_select(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 642 nanoseconds. + Weight::from_ref_time(917_880) + // Standard Error: 362 + .saturating_add(Weight::from_ref_time(957_235).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_if(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 630 nanoseconds. + Weight::from_ref_time(694_427) + // Standard Error: 1_506 + .saturating_add(Weight::from_ref_time(1_298_411).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_br(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 634 nanoseconds. + Weight::from_ref_time(1_101_754) + // Standard Error: 840 + .saturating_add(Weight::from_ref_time(526_433).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_br_if(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 651 nanoseconds. + Weight::from_ref_time(790_908) + // Standard Error: 849 + .saturating_add(Weight::from_ref_time(800_188).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_br_table(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 622 nanoseconds. + Weight::from_ref_time(416_266) + // Standard Error: 1_574 + .saturating_add(Weight::from_ref_time(1_080_225).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_177 nanoseconds. - Weight::from_ref_time(2_581_121) - // Standard Error: 67 - .saturating_add(Weight::from_ref_time(5_001).saturating_mul(e.into())) + // Minimum execution time: 2_131 nanoseconds. + Weight::from_ref_time(2_540_446) + // Standard Error: 75 + .saturating_add(Weight::from_ref_time(4_997).saturating_mul(e.into())) } /// The range of component `r` is `[0, 50]`. fn instr_call(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 650 nanoseconds. + Weight::from_ref_time(1_577_978) + // Standard Error: 2_696 + .saturating_add(Weight::from_ref_time(2_204_044).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_call_indirect(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 742 nanoseconds. + Weight::from_ref_time(1_947_575) + // Standard Error: 1_651 + .saturating_add(Weight::from_ref_time(2_799_445).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_255 nanoseconds. - Weight::from_ref_time(5_064_243) - // Standard Error: 289 - .saturating_add(Weight::from_ref_time(178_868).saturating_mul(p.into())) + // Minimum execution time: 4_230 nanoseconds. + Weight::from_ref_time(5_079_432) + // Standard Error: 315 + .saturating_add(Weight::from_ref_time(179_278).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())) + // Minimum execution time: 2_830 nanoseconds. + Weight::from_ref_time(3_601_633) + // Standard Error: 31 + .saturating_add(Weight::from_ref_time(92_499).saturating_mul(l.into())) } /// The range of component `r` is `[0, 50]`. fn instr_local_get(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 2_896 nanoseconds. + Weight::from_ref_time(3_137_247) + // Standard Error: 245 + .saturating_add(Weight::from_ref_time(364_431).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_local_set(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 2_795 nanoseconds. + Weight::from_ref_time(3_199_878) + // Standard Error: 549 + .saturating_add(Weight::from_ref_time(380_524).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_local_tee(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 2_807 nanoseconds. + Weight::from_ref_time(3_130_120) + // Standard Error: 319 + .saturating_add(Weight::from_ref_time(525_857).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_global_get(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 678 nanoseconds. + Weight::from_ref_time(1_013_348) + // Standard Error: 362 + .saturating_add(Weight::from_ref_time(810_232).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_global_set(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 624 nanoseconds. + Weight::from_ref_time(973_583) + // Standard Error: 373 + .saturating_add(Weight::from_ref_time(829_360).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_memory_current(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 698 nanoseconds. + Weight::from_ref_time(904_862) + // Standard Error: 360 + .saturating_add(Weight::from_ref_time(694_614).saturating_mul(r.into())) } /// The range of component `r` is `[0, 1]`. fn instr_memory_grow(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 642 nanoseconds. + Weight::from_ref_time(735_085) + // Standard Error: 105_815 + .saturating_add(Weight::from_ref_time(233_816_514).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64clz(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 606 nanoseconds. + Weight::from_ref_time(850_590) + // Standard Error: 262 + .saturating_add(Weight::from_ref_time(507_721).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ctz(r: u32, ) -> Weight { // 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())) + Weight::from_ref_time(853_060) + // Standard Error: 250 + .saturating_add(Weight::from_ref_time(514_225).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64popcnt(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 605 nanoseconds. + Weight::from_ref_time(849_563) + // Standard Error: 275 + .saturating_add(Weight::from_ref_time(511_494).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64eqz(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 618 nanoseconds. + Weight::from_ref_time(839_855) + // Standard Error: 228 + .saturating_add(Weight::from_ref_time(524_614).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendsi32(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 637 nanoseconds. + Weight::from_ref_time(860_326) + // Standard Error: 240 + .saturating_add(Weight::from_ref_time(504_847).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendui32(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 623 nanoseconds. + Weight::from_ref_time(844_585) + // Standard Error: 235 + .saturating_add(Weight::from_ref_time(505_821).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i32wrapi64(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 672 nanoseconds. + Weight::from_ref_time(826_784) + // Standard Error: 225 + .saturating_add(Weight::from_ref_time(504_632).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64eq(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 642 nanoseconds. + Weight::from_ref_time(867_080) + // Standard Error: 231 + .saturating_add(Weight::from_ref_time(732_430).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ne(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 639 nanoseconds. + Weight::from_ref_time(866_094) + // Standard Error: 272 + .saturating_add(Weight::from_ref_time(732_560).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64lts(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 619 nanoseconds. + Weight::from_ref_time(928_672) + // Standard Error: 484 + .saturating_add(Weight::from_ref_time(739_523).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ltu(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 612 nanoseconds. + Weight::from_ref_time(863_312) + // Standard Error: 328 + .saturating_add(Weight::from_ref_time(743_687).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64gts(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 648 nanoseconds. + Weight::from_ref_time(931_331) + // Standard Error: 612 + .saturating_add(Weight::from_ref_time(747_653).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64gtu(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 632 nanoseconds. + Weight::from_ref_time(868_901) + // Standard Error: 276 + .saturating_add(Weight::from_ref_time(744_778).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64les(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 629 nanoseconds. + Weight::from_ref_time(898_516) + // Standard Error: 288 + .saturating_add(Weight::from_ref_time(734_393).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64leu(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 603 nanoseconds. + Weight::from_ref_time(853_744) + // Standard Error: 204 + .saturating_add(Weight::from_ref_time(739_499).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ges(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 625 nanoseconds. + Weight::from_ref_time(885_174) + // Standard Error: 238 + .saturating_add(Weight::from_ref_time(734_010).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64geu(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 602 nanoseconds. + Weight::from_ref_time(915_329) + // Standard Error: 273 + .saturating_add(Weight::from_ref_time(738_209).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64add(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 585 nanoseconds. + Weight::from_ref_time(862_239) + // Standard Error: 294 + .saturating_add(Weight::from_ref_time(719_000).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64sub(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 633 nanoseconds. + Weight::from_ref_time(881_696) + // Standard Error: 195 + .saturating_add(Weight::from_ref_time(713_153).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64mul(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 629 nanoseconds. + Weight::from_ref_time(856_238) + // Standard Error: 269 + .saturating_add(Weight::from_ref_time(715_451).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64divs(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 633 nanoseconds. + Weight::from_ref_time(880_804) + // Standard Error: 725 + .saturating_add(Weight::from_ref_time(1_349_577).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64divu(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 639 nanoseconds. + Weight::from_ref_time(867_528) + // Standard Error: 1_940 + .saturating_add(Weight::from_ref_time(1_287_959).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64rems(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 595 nanoseconds. + Weight::from_ref_time(851_253) + // Standard Error: 503 + .saturating_add(Weight::from_ref_time(1_398_668).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64remu(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 604 nanoseconds. + Weight::from_ref_time(804_977) + // Standard Error: 812 + .saturating_add(Weight::from_ref_time(1_288_816).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64and(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 609 nanoseconds. + Weight::from_ref_time(890_945) + // Standard Error: 1_645 + .saturating_add(Weight::from_ref_time(719_770).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64or(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 628 nanoseconds. + Weight::from_ref_time(897_973) + // Standard Error: 1_641 + .saturating_add(Weight::from_ref_time(718_838).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64xor(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 634 nanoseconds. + Weight::from_ref_time(848_440) + // Standard Error: 249 + .saturating_add(Weight::from_ref_time(718_206).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64shl(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 625 nanoseconds. + Weight::from_ref_time(881_579) + // Standard Error: 273 + .saturating_add(Weight::from_ref_time(736_934).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64shrs(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 630 nanoseconds. + Weight::from_ref_time(897_813) + // Standard Error: 249 + .saturating_add(Weight::from_ref_time(734_657).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64shru(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 607 nanoseconds. + Weight::from_ref_time(871_660) + // Standard Error: 312 + .saturating_add(Weight::from_ref_time(735_377).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotl(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 610 nanoseconds. + Weight::from_ref_time(861_640) + // Standard Error: 293 + .saturating_add(Weight::from_ref_time(735_524).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotr(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 625 nanoseconds. + Weight::from_ref_time(880_203) + // Standard Error: 373 + .saturating_add(Weight::from_ref_time(737_354).saturating_mul(r.into())) } } @@ -1440,17 +1447,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_148 nanoseconds. - Weight::from_ref_time(3_326_000) + // Minimum execution time: 3_196 nanoseconds. + Weight::from_ref_time(3_293_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_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())) + // Minimum execution time: 14_857 nanoseconds. + Weight::from_ref_time(14_957_593) + // Standard Error: 1_015 + .saturating_add(Weight::from_ref_time(935_359).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()))) @@ -1458,10 +1465,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_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())) + // Minimum execution time: 3_231 nanoseconds. + Weight::from_ref_time(14_859_580) + // Standard Error: 3_479 + .saturating_add(Weight::from_ref_time(1_185_600).saturating_mul(q.into())) .saturating_add(RocksDbWeight::get().reads(1)) .saturating_add(RocksDbWeight::get().writes(1)) } @@ -1469,10 +1476,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: 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())) + // Minimum execution time: 34_565 nanoseconds. + Weight::from_ref_time(29_199_016) + // Standard Error: 70 + .saturating_add(Weight::from_ref_time(47_107).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(1)) .saturating_add(RocksDbWeight::get().writes(1)) } @@ -1483,10 +1490,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: 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())) + // Minimum execution time: 392_074 nanoseconds. + Weight::from_ref_time(404_090_909) + // Standard Error: 24 + .saturating_add(Weight::from_ref_time(30_454).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(4)) } @@ -1499,14 +1506,17 @@ impl WeightInfo for () { // 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 `i` is `[0, 1048576]`. /// The range of component `s` is `[0, 1048576]`. - fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - // 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())) + fn instantiate_with_code(c: u32, i: u32, s: u32, ) -> Weight { + // Minimum execution time: 3_785_934 nanoseconds. + Weight::from_ref_time(683_143_843) + // Standard Error: 272 + .saturating_add(Weight::from_ref_time(87_620).saturating_mul(c.into())) + // Standard Error: 16 + .saturating_add(Weight::from_ref_time(1_363).saturating_mul(i.into())) + // Standard Error: 16 + .saturating_add(Weight::from_ref_time(1_778).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(8)) .saturating_add(RocksDbWeight::get().writes(9)) } @@ -1517,12 +1527,15 @@ impl WeightInfo for () { // 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 `i` is `[0, 1048576]`. /// The range of component `s` is `[0, 1048576]`. - fn instantiate(s: u32, ) -> Weight { - // 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())) + fn instantiate(i: u32, s: u32, ) -> Weight { + // Minimum execution time: 1_935_310 nanoseconds. + Weight::from_ref_time(203_531_122) + // Standard Error: 8 + .saturating_add(Weight::from_ref_time(1_674).saturating_mul(i.into())) + // Standard Error: 8 + .saturating_add(Weight::from_ref_time(1_789).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(8)) .saturating_add(RocksDbWeight::get().writes(7)) } @@ -1532,8 +1545,8 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: System EventTopics (r:2 w:2) fn call() -> Weight { - // Minimum execution time: 154_738 nanoseconds. - Weight::from_ref_time(159_212_000) + // Minimum execution time: 151_999 nanoseconds. + Weight::from_ref_time(153_527_000) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(4)) } @@ -1543,10 +1556,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: 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())) + // Minimum execution time: 391_165 nanoseconds. + Weight::from_ref_time(394_519_487) + // Standard Error: 75 + .saturating_add(Weight::from_ref_time(89_736).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(2)) .saturating_add(RocksDbWeight::get().writes(4)) } @@ -1555,8 +1568,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: 39_892 nanoseconds. - Weight::from_ref_time(40_258_000) + // Minimum execution time: 39_354 nanoseconds. + Weight::from_ref_time(39_855_000) .saturating_add(RocksDbWeight::get().reads(2)) .saturating_add(RocksDbWeight::get().writes(4)) } @@ -1564,8 +1577,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_441 nanoseconds. - Weight::from_ref_time(42_011_000) + // Minimum execution time: 40_909 nanoseconds. + Weight::from_ref_time(41_275_000) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(6)) } @@ -1576,10 +1589,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: 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())) + // Minimum execution time: 380_150 nanoseconds. + Weight::from_ref_time(384_429_035) + // Standard Error: 34_740 + .saturating_add(Weight::from_ref_time(15_582_218).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -1590,10 +1603,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: 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())) + // Minimum execution time: 380_608 nanoseconds. + Weight::from_ref_time(326_544_805) + // Standard Error: 475_381 + .saturating_add(Weight::from_ref_time(190_717_772).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)) @@ -1605,10 +1618,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: 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())) + // Minimum execution time: 382_780 nanoseconds. + Weight::from_ref_time(333_775_113) + // Standard Error: 446_086 + .saturating_add(Weight::from_ref_time(232_531_042).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)) @@ -1620,10 +1633,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: 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())) + // Minimum execution time: 381_815 nanoseconds. + Weight::from_ref_time(390_931_793) + // Standard Error: 61_918 + .saturating_add(Weight::from_ref_time(18_798_438).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -1634,10 +1647,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: 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())) + // Minimum execution time: 379_162 nanoseconds. + Weight::from_ref_time(383_796_363) + // Standard Error: 25_555 + .saturating_add(Weight::from_ref_time(10_843_721).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -1648,10 +1661,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: 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())) + // Minimum execution time: 380_307 nanoseconds. + Weight::from_ref_time(390_211_779) + // Standard Error: 53_326 + .saturating_add(Weight::from_ref_time(15_311_171).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -1662,10 +1675,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: 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())) + // Minimum execution time: 380_230 nanoseconds. + Weight::from_ref_time(383_470_453) + // Standard Error: 45_007 + .saturating_add(Weight::from_ref_time(15_582_472).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -1676,10 +1689,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: 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())) + // Minimum execution time: 380_244 nanoseconds. + Weight::from_ref_time(388_092_461) + // Standard Error: 98_199 + .saturating_add(Weight::from_ref_time(97_339_528).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -1690,10 +1703,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: 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())) + // Minimum execution time: 380_242 nanoseconds. + Weight::from_ref_time(384_078_258) + // Standard Error: 28_510 + .saturating_add(Weight::from_ref_time(15_423_359).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -1704,10 +1717,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: 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())) + // Minimum execution time: 379_890 nanoseconds. + Weight::from_ref_time(383_658_430) + // Standard Error: 44_976 + .saturating_add(Weight::from_ref_time(15_451_905).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -1718,10 +1731,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: 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())) + // Minimum execution time: 380_269 nanoseconds. + Weight::from_ref_time(383_580_481) + // Standard Error: 31_862 + .saturating_add(Weight::from_ref_time(15_230_473).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -1732,10 +1745,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: 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())) + // Minimum execution time: 380_308 nanoseconds. + Weight::from_ref_time(383_732_372) + // Standard Error: 38_359 + .saturating_add(Weight::from_ref_time(15_358_775).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -1747,10 +1760,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: 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())) + // Minimum execution time: 380_834 nanoseconds. + Weight::from_ref_time(388_999_459) + // Standard Error: 96_447 + .saturating_add(Weight::from_ref_time(86_714_414).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -1761,10 +1774,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: 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())) + // Minimum execution time: 140_955 nanoseconds. + Weight::from_ref_time(144_716_423) + // Standard Error: 11_370 + .saturating_add(Weight::from_ref_time(7_858_807).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -1775,10 +1788,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: 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())) + // Minimum execution time: 380_210 nanoseconds. + Weight::from_ref_time(384_185_776) + // Standard Error: 49_038 + .saturating_add(Weight::from_ref_time(13_649_793).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -1789,10 +1802,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: 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())) + // Minimum execution time: 396_209 nanoseconds. + Weight::from_ref_time(424_522_611) + // Standard Error: 3_917 + .saturating_add(Weight::from_ref_time(9_627_216).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -1803,10 +1816,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: 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())) + // Minimum execution time: 378_412 nanoseconds. + Weight::from_ref_time(380_502_085) + // Standard Error: 201_552 + .saturating_add(Weight::from_ref_time(1_434_214).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -1817,10 +1830,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: 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())) + // Minimum execution time: 381_463 nanoseconds. + Weight::from_ref_time(383_955_553) + // Standard Error: 998 + .saturating_add(Weight::from_ref_time(230_512).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -1833,10 +1846,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: 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())) + // Minimum execution time: 379_877 nanoseconds. + Weight::from_ref_time(381_729_546) + // Standard Error: 214_004 + .saturating_add(Weight::from_ref_time(52_528_353).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)) @@ -1850,10 +1863,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: 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())) + // Minimum execution time: 380_275 nanoseconds. + Weight::from_ref_time(386_495_777) + // Standard Error: 94_674 + .saturating_add(Weight::from_ref_time(108_432_929).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -1864,10 +1877,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: 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())) + // Minimum execution time: 379_095 nanoseconds. + Weight::from_ref_time(393_997_924) + // Standard Error: 141_916 + .saturating_add(Weight::from_ref_time(212_937_170).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -1879,12 +1892,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_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())) + // Minimum execution time: 1_241_001 nanoseconds. + Weight::from_ref_time(548_526_917) + // Standard Error: 496_807 + .saturating_add(Weight::from_ref_time(177_087_769).saturating_mul(t.into())) + // Standard Error: 136_447 + .saturating_add(Weight::from_ref_time(71_558_402).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)) @@ -1897,20 +1910,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: 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())) + // Minimum execution time: 159_158 nanoseconds. + Weight::from_ref_time(163_427_712) + // Standard Error: 22_442 + .saturating_add(Weight::from_ref_time(12_647_838).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: 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())) + // Minimum execution time: 381_068 nanoseconds. + Weight::from_ref_time(341_041_230) + // Standard Error: 464_053 + .saturating_add(Weight::from_ref_time(402_677_314).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)) @@ -1919,10 +1932,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: 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())) + // Minimum execution time: 508_695 nanoseconds. + Weight::from_ref_time(663_159_695) + // Standard Error: 1_419_342 + .saturating_add(Weight::from_ref_time(96_558_570).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)) @@ -1931,10 +1944,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: 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())) + // Minimum execution time: 508_542 nanoseconds. + Weight::from_ref_time(634_146_978) + // Standard Error: 1_168_252 + .saturating_add(Weight::from_ref_time(64_231_947).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)) @@ -1943,10 +1956,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: 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())) + // Minimum execution time: 381_743 nanoseconds. + Weight::from_ref_time(337_309_674) + // Standard Error: 527_407 + .saturating_add(Weight::from_ref_time(395_767_068).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)) @@ -1955,10 +1968,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: 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())) + // Minimum execution time: 478_283 nanoseconds. + Weight::from_ref_time(616_673_245) + // Standard Error: 1_290_784 + .saturating_add(Weight::from_ref_time(66_534_552).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)) @@ -1967,10 +1980,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: 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())) + // Minimum execution time: 381_916 nanoseconds. + Weight::from_ref_time(349_150_912) + // Standard Error: 443_388 + .saturating_add(Weight::from_ref_time(316_975_558).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)) @@ -1978,10 +1991,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: 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())) + // Minimum execution time: 459_294 nanoseconds. + Weight::from_ref_time(579_698_524) + // Standard Error: 1_111_681 + .saturating_add(Weight::from_ref_time(159_276_087).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)) @@ -1989,10 +2002,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: 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())) + // Minimum execution time: 381_700 nanoseconds. + Weight::from_ref_time(352_544_675) + // Standard Error: 401_504 + .saturating_add(Weight::from_ref_time(304_380_106).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)) @@ -2000,10 +2013,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: 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())) + // Minimum execution time: 455_595 nanoseconds. + Weight::from_ref_time(560_428_166) + // Standard Error: 991_088 + .saturating_add(Weight::from_ref_time(61_810_610).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)) @@ -2011,10 +2024,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: 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())) + // Minimum execution time: 382_000 nanoseconds. + Weight::from_ref_time(336_164_219) + // Standard Error: 601_744 + .saturating_add(Weight::from_ref_time(406_198_079).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)) @@ -2023,10 +2036,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: 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())) + // Minimum execution time: 482_335 nanoseconds. + Weight::from_ref_time(634_245_177) + // Standard Error: 1_418_845 + .saturating_add(Weight::from_ref_time(164_352_113).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)) @@ -2039,10 +2052,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: 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())) + // Minimum execution time: 382_142 nanoseconds. + Weight::from_ref_time(317_581_708) + // Standard Error: 682_156 + .saturating_add(Weight::from_ref_time(1_305_289_569).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)) @@ -2055,10 +2068,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: 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())) + // Minimum execution time: 383_580 nanoseconds. + Weight::from_ref_time(384_176_000) + // Standard Error: 6_483_482 + .saturating_add(Weight::from_ref_time(28_047_685_517).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)) @@ -2071,10 +2084,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: 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())) + // Minimum execution time: 384_523 nanoseconds. + Weight::from_ref_time(385_105_000) + // Standard Error: 6_156_142 + .saturating_add(Weight::from_ref_time(27_780_652_513).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)) @@ -2088,12 +2101,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: 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())) + // Minimum execution time: 9_509_961 nanoseconds. + Weight::from_ref_time(8_509_991_348) + // Standard Error: 6_614_757 + .saturating_add(Weight::from_ref_time(1_244_514_376).saturating_mul(t.into())) + // Standard Error: 9_918 + .saturating_add(Weight::from_ref_time(9_856_517).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)) @@ -2108,10 +2121,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: 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())) + // Minimum execution time: 384_604 nanoseconds. + Weight::from_ref_time(385_278_000) + // Standard Error: 21_140_468 + .saturating_add(Weight::from_ref_time(33_100_726_150).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)) @@ -2125,14 +2138,15 @@ impl WeightInfo for () { // 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 `i` is `[0, 960]`. /// The range of component `s` is `[0, 960]`. - fn seal_instantiate_per_transfer_salt_kb(t: u32, s: u32, ) -> Weight { - // 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())) + fn seal_instantiate_per_transfer_input_salt_kb(t: u32, i: u32, s: u32, ) -> Weight { + // Minimum execution time: 129_699_480 nanoseconds. + Weight::from_ref_time(10_187_699_005) + // Standard Error: 155_040 + .saturating_add(Weight::from_ref_time(125_284_310).saturating_mul(i.into())) + // Standard Error: 155_040 + .saturating_add(Weight::from_ref_time(125_850_564).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)) @@ -2145,10 +2159,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: 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())) + // Minimum execution time: 380_397 nanoseconds. + Weight::from_ref_time(382_881_855) + // Standard Error: 290_948 + .saturating_add(Weight::from_ref_time(41_017_644).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -2159,10 +2173,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: 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())) + // Minimum execution time: 422_439 nanoseconds. + Weight::from_ref_time(423_480_000) + // Standard Error: 56_072 + .saturating_add(Weight::from_ref_time(329_103_825).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -2173,10 +2187,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: 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())) + // Minimum execution time: 380_433 nanoseconds. + Weight::from_ref_time(382_325_624) + // Standard Error: 139_248 + .saturating_add(Weight::from_ref_time(53_159_175).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -2187,10 +2201,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: 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())) + // Minimum execution time: 434_834 nanoseconds. + Weight::from_ref_time(435_383_000) + // Standard Error: 59_824 + .saturating_add(Weight::from_ref_time(251_297_967).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -2201,10 +2215,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: 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())) + // Minimum execution time: 379_088 nanoseconds. + Weight::from_ref_time(381_627_077) + // Standard Error: 152_561 + .saturating_add(Weight::from_ref_time(31_696_922).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -2215,10 +2229,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: 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())) + // Minimum execution time: 411_630 nanoseconds. + Weight::from_ref_time(412_354_000) + // Standard Error: 50_788 + .saturating_add(Weight::from_ref_time(103_105_715).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -2229,10 +2243,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: 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())) + // Minimum execution time: 379_549 nanoseconds. + Weight::from_ref_time(382_406_346) + // Standard Error: 701_449 + .saturating_add(Weight::from_ref_time(31_066_353).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -2243,10 +2257,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: 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())) + // Minimum execution time: 412_112 nanoseconds. + Weight::from_ref_time(412_710_000) + // Standard Error: 54_875 + .saturating_add(Weight::from_ref_time(103_169_035).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -2257,10 +2271,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: 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())) + // Minimum execution time: 381_994 nanoseconds. + Weight::from_ref_time(383_832_551) + // Standard Error: 676_656 + .saturating_add(Weight::from_ref_time(3_020_035_748).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -2271,10 +2285,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: 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())) + // Minimum execution time: 381_472 nanoseconds. + Weight::from_ref_time(383_590_834) + // Standard Error: 538_574 + .saturating_add(Weight::from_ref_time(2_077_926_265).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -2286,10 +2300,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: 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())) + // Minimum execution time: 381_527 nanoseconds. + Weight::from_ref_time(382_291_000) + // Standard Error: 2_760_840 + .saturating_add(Weight::from_ref_time(1_356_115_009).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)) @@ -2302,10 +2316,10 @@ 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: 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())) + // Minimum execution time: 382_722 nanoseconds. + Weight::from_ref_time(387_231_409) + // Standard Error: 28_817 + .saturating_add(Weight::from_ref_time(11_349_809).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -2316,10 +2330,10 @@ 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: 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())) + // Minimum execution time: 383_568 nanoseconds. + Weight::from_ref_time(419_835_108) + // Standard Error: 125_982 + .saturating_add(Weight::from_ref_time(25_241_800).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -2331,375 +2345,375 @@ impl WeightInfo for () { // 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())) + // Minimum execution time: 382_084 nanoseconds. + Weight::from_ref_time(388_155_568) + // Standard Error: 29_161 + .saturating_add(Weight::from_ref_time(9_015_217).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. - Weight::from_ref_time(914_830) - // Standard Error: 222 - .saturating_add(Weight::from_ref_time(343_835).saturating_mul(r.into())) + // Minimum execution time: 593 nanoseconds. + Weight::from_ref_time(816_706) + // Standard Error: 173 + .saturating_add(Weight::from_ref_time(344_732).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64load(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 705 nanoseconds. + Weight::from_ref_time(1_191_205) + // Standard Error: 600 + .saturating_add(Weight::from_ref_time(986_102).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64store(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 717 nanoseconds. + Weight::from_ref_time(1_019_448) + // Standard Error: 421 + .saturating_add(Weight::from_ref_time(882_531).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_select(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 642 nanoseconds. + Weight::from_ref_time(917_880) + // Standard Error: 362 + .saturating_add(Weight::from_ref_time(957_235).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_if(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 630 nanoseconds. + Weight::from_ref_time(694_427) + // Standard Error: 1_506 + .saturating_add(Weight::from_ref_time(1_298_411).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_br(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 634 nanoseconds. + Weight::from_ref_time(1_101_754) + // Standard Error: 840 + .saturating_add(Weight::from_ref_time(526_433).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_br_if(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 651 nanoseconds. + Weight::from_ref_time(790_908) + // Standard Error: 849 + .saturating_add(Weight::from_ref_time(800_188).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_br_table(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 622 nanoseconds. + Weight::from_ref_time(416_266) + // Standard Error: 1_574 + .saturating_add(Weight::from_ref_time(1_080_225).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_177 nanoseconds. - Weight::from_ref_time(2_581_121) - // Standard Error: 67 - .saturating_add(Weight::from_ref_time(5_001).saturating_mul(e.into())) + // Minimum execution time: 2_131 nanoseconds. + Weight::from_ref_time(2_540_446) + // Standard Error: 75 + .saturating_add(Weight::from_ref_time(4_997).saturating_mul(e.into())) } /// The range of component `r` is `[0, 50]`. fn instr_call(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 650 nanoseconds. + Weight::from_ref_time(1_577_978) + // Standard Error: 2_696 + .saturating_add(Weight::from_ref_time(2_204_044).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_call_indirect(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 742 nanoseconds. + Weight::from_ref_time(1_947_575) + // Standard Error: 1_651 + .saturating_add(Weight::from_ref_time(2_799_445).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_255 nanoseconds. - Weight::from_ref_time(5_064_243) - // Standard Error: 289 - .saturating_add(Weight::from_ref_time(178_868).saturating_mul(p.into())) + // Minimum execution time: 4_230 nanoseconds. + Weight::from_ref_time(5_079_432) + // Standard Error: 315 + .saturating_add(Weight::from_ref_time(179_278).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())) + // Minimum execution time: 2_830 nanoseconds. + Weight::from_ref_time(3_601_633) + // Standard Error: 31 + .saturating_add(Weight::from_ref_time(92_499).saturating_mul(l.into())) } /// The range of component `r` is `[0, 50]`. fn instr_local_get(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 2_896 nanoseconds. + Weight::from_ref_time(3_137_247) + // Standard Error: 245 + .saturating_add(Weight::from_ref_time(364_431).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_local_set(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 2_795 nanoseconds. + Weight::from_ref_time(3_199_878) + // Standard Error: 549 + .saturating_add(Weight::from_ref_time(380_524).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_local_tee(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 2_807 nanoseconds. + Weight::from_ref_time(3_130_120) + // Standard Error: 319 + .saturating_add(Weight::from_ref_time(525_857).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_global_get(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 678 nanoseconds. + Weight::from_ref_time(1_013_348) + // Standard Error: 362 + .saturating_add(Weight::from_ref_time(810_232).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_global_set(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 624 nanoseconds. + Weight::from_ref_time(973_583) + // Standard Error: 373 + .saturating_add(Weight::from_ref_time(829_360).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_memory_current(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 698 nanoseconds. + Weight::from_ref_time(904_862) + // Standard Error: 360 + .saturating_add(Weight::from_ref_time(694_614).saturating_mul(r.into())) } /// The range of component `r` is `[0, 1]`. fn instr_memory_grow(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 642 nanoseconds. + Weight::from_ref_time(735_085) + // Standard Error: 105_815 + .saturating_add(Weight::from_ref_time(233_816_514).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64clz(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 606 nanoseconds. + Weight::from_ref_time(850_590) + // Standard Error: 262 + .saturating_add(Weight::from_ref_time(507_721).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ctz(r: u32, ) -> Weight { // 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())) + Weight::from_ref_time(853_060) + // Standard Error: 250 + .saturating_add(Weight::from_ref_time(514_225).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64popcnt(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 605 nanoseconds. + Weight::from_ref_time(849_563) + // Standard Error: 275 + .saturating_add(Weight::from_ref_time(511_494).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64eqz(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 618 nanoseconds. + Weight::from_ref_time(839_855) + // Standard Error: 228 + .saturating_add(Weight::from_ref_time(524_614).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendsi32(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 637 nanoseconds. + Weight::from_ref_time(860_326) + // Standard Error: 240 + .saturating_add(Weight::from_ref_time(504_847).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendui32(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 623 nanoseconds. + Weight::from_ref_time(844_585) + // Standard Error: 235 + .saturating_add(Weight::from_ref_time(505_821).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i32wrapi64(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 672 nanoseconds. + Weight::from_ref_time(826_784) + // Standard Error: 225 + .saturating_add(Weight::from_ref_time(504_632).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64eq(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 642 nanoseconds. + Weight::from_ref_time(867_080) + // Standard Error: 231 + .saturating_add(Weight::from_ref_time(732_430).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ne(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 639 nanoseconds. + Weight::from_ref_time(866_094) + // Standard Error: 272 + .saturating_add(Weight::from_ref_time(732_560).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64lts(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 619 nanoseconds. + Weight::from_ref_time(928_672) + // Standard Error: 484 + .saturating_add(Weight::from_ref_time(739_523).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ltu(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 612 nanoseconds. + Weight::from_ref_time(863_312) + // Standard Error: 328 + .saturating_add(Weight::from_ref_time(743_687).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64gts(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 648 nanoseconds. + Weight::from_ref_time(931_331) + // Standard Error: 612 + .saturating_add(Weight::from_ref_time(747_653).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64gtu(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 632 nanoseconds. + Weight::from_ref_time(868_901) + // Standard Error: 276 + .saturating_add(Weight::from_ref_time(744_778).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64les(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 629 nanoseconds. + Weight::from_ref_time(898_516) + // Standard Error: 288 + .saturating_add(Weight::from_ref_time(734_393).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64leu(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 603 nanoseconds. + Weight::from_ref_time(853_744) + // Standard Error: 204 + .saturating_add(Weight::from_ref_time(739_499).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ges(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 625 nanoseconds. + Weight::from_ref_time(885_174) + // Standard Error: 238 + .saturating_add(Weight::from_ref_time(734_010).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64geu(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 602 nanoseconds. + Weight::from_ref_time(915_329) + // Standard Error: 273 + .saturating_add(Weight::from_ref_time(738_209).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64add(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 585 nanoseconds. + Weight::from_ref_time(862_239) + // Standard Error: 294 + .saturating_add(Weight::from_ref_time(719_000).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64sub(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 633 nanoseconds. + Weight::from_ref_time(881_696) + // Standard Error: 195 + .saturating_add(Weight::from_ref_time(713_153).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64mul(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 629 nanoseconds. + Weight::from_ref_time(856_238) + // Standard Error: 269 + .saturating_add(Weight::from_ref_time(715_451).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64divs(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 633 nanoseconds. + Weight::from_ref_time(880_804) + // Standard Error: 725 + .saturating_add(Weight::from_ref_time(1_349_577).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64divu(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 639 nanoseconds. + Weight::from_ref_time(867_528) + // Standard Error: 1_940 + .saturating_add(Weight::from_ref_time(1_287_959).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64rems(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 595 nanoseconds. + Weight::from_ref_time(851_253) + // Standard Error: 503 + .saturating_add(Weight::from_ref_time(1_398_668).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64remu(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 604 nanoseconds. + Weight::from_ref_time(804_977) + // Standard Error: 812 + .saturating_add(Weight::from_ref_time(1_288_816).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64and(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 609 nanoseconds. + Weight::from_ref_time(890_945) + // Standard Error: 1_645 + .saturating_add(Weight::from_ref_time(719_770).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64or(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 628 nanoseconds. + Weight::from_ref_time(897_973) + // Standard Error: 1_641 + .saturating_add(Weight::from_ref_time(718_838).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64xor(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 634 nanoseconds. + Weight::from_ref_time(848_440) + // Standard Error: 249 + .saturating_add(Weight::from_ref_time(718_206).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64shl(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 625 nanoseconds. + Weight::from_ref_time(881_579) + // Standard Error: 273 + .saturating_add(Weight::from_ref_time(736_934).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64shrs(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 630 nanoseconds. + Weight::from_ref_time(897_813) + // Standard Error: 249 + .saturating_add(Weight::from_ref_time(734_657).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64shru(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 607 nanoseconds. + Weight::from_ref_time(871_660) + // Standard Error: 312 + .saturating_add(Weight::from_ref_time(735_377).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotl(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 610 nanoseconds. + Weight::from_ref_time(861_640) + // Standard Error: 293 + .saturating_add(Weight::from_ref_time(735_524).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotr(r: u32, ) -> Weight { - // 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())) + // Minimum execution time: 625 nanoseconds. + Weight::from_ref_time(880_203) + // Standard Error: 373 + .saturating_add(Weight::from_ref_time(737_354).saturating_mul(r.into())) } } From acbb91b0c6168eed052cf68467c5532c97403bba Mon Sep 17 00:00:00 2001 From: Sasha Gryaznov Date: Thu, 22 Dec 2022 19:22:57 +0200 Subject: [PATCH 221/715] [contracts] Remove stack height limiter wasm instrumentation (#12957) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Remove stack height limiter from uploaded wasm * fix benchmarks * ".git/.scripts/bench-bot.sh" pallet dev pallet_contracts Co-authored-by: command-bot <> Co-authored-by: Alexander Theißen --- frame/contracts/src/benchmarking/code.rs | 26 ++---------------------- frame/contracts/src/benchmarking/mod.rs | 7 ++----- frame/contracts/src/schedule.rs | 18 +--------------- frame/contracts/src/tests.rs | 15 ++++++-------- frame/contracts/src/wasm/prepare.rs | 15 +------------- 5 files changed, 12 insertions(+), 69 deletions(-) diff --git a/frame/contracts/src/benchmarking/code.rs b/frame/contracts/src/benchmarking/code.rs index 0b09726214260..156b9e2f99945 100644 --- a/frame/contracts/src/benchmarking/code.rs +++ b/frame/contracts/src/benchmarking/code.rs @@ -72,11 +72,6 @@ pub struct ModuleDefinition { pub aux_body: Option, /// The amount of I64 arguments the aux function should have. pub aux_arg_num: u32, - /// If set to true the stack height limiter is injected into the the module. This is - /// needed for instruction debugging because the cost of executing the stack height - /// instrumentation should be included in the costs for the individual instructions - /// that cause more metering code (only call). - pub inject_stack_metering: bool, /// Create a table containing function pointers. pub table: Option, /// Create a section named "dummy" of the specified size. This is useful in order to @@ -238,13 +233,7 @@ impl From for WasmModule { ))); } - let mut code = contract.build(); - - if def.inject_stack_metering { - code = inject_stack_metering::(code); - } - - let code = code.into_bytes().unwrap(); + let code = contract.build().into_bytes().unwrap(); let hash = T::Hashing::hash(&code); Self { code: code.into(), hash, memory: def.memory } } @@ -252,15 +241,12 @@ impl From for WasmModule { impl WasmModule { /// Uses the supplied wasm module and instruments it when requested. - pub fn instrumented(code: &[u8], inject_gas: bool, inject_stack: bool) -> Self { + pub fn instrumented(code: &[u8], inject_gas: bool) -> Self { let module = { let mut module = Module::from_bytes(code).unwrap(); if inject_gas { module = inject_gas_metering::(module); } - if inject_stack { - module = inject_stack_metering::(module); - } module }; let limits = *module @@ -530,11 +516,3 @@ fn inject_gas_metering(module: Module) -> Module { 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 { - 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 da9b53495d077..d46da8469eb41 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -2384,7 +2384,6 @@ benchmarks! { call_body: Some(body::repeated(r * INSTR_BENCHMARK_BATCH_SIZE, &[ Instruction::Call(2), // call aux ])), - inject_stack_metering: true, .. Default::default() })); }: { @@ -2408,7 +2407,6 @@ benchmarks! { RandomI32(0, num_elements as i32), Regular(Instruction::CallIndirect(0, 0)), // we only have one sig: 0 ])), - inject_stack_metering: true, table: Some(TableSegment { num_elements, function_index: 2, // aux @@ -2441,7 +2439,6 @@ benchmarks! { RandomI32(0, num_elements as i32), Regular(Instruction::CallIndirect(p.min(1), 0)), // aux signature: 1 or 0 ])), - inject_stack_metering: true, table: Some(TableSegment { num_elements, function_index: 2, // aux @@ -2968,7 +2965,7 @@ benchmarks! { new.encode() }; let instance = Contract::::new( - WasmModule::instrumented(code, gas_metering, true), data, + WasmModule::instrumented(code, gas_metering), data, )?; let data = { let transfer: ([u8; 4], AccountIdOf, BalanceOf) = ( @@ -3015,7 +3012,7 @@ benchmarks! { new.encode() }; let instance = Contract::::with_caller( - caller, WasmModule::instrumented(code, gas_metering, true), data, + caller, WasmModule::instrumented(code, gas_metering), data, )?; balance[0] = 1; let data = { diff --git a/frame/contracts/src/schedule.rs b/frame/contracts/src/schedule.rs index e7a6b16e23a2b..912e58b048ff4 100644 --- a/frame/contracts/src/schedule.rs +++ b/frame/contracts/src/schedule.rs @@ -99,23 +99,9 @@ pub struct Limits { /// The maximum number of topics supported by an event. pub event_topics: u32, - /// Maximum allowed stack height in number of elements. - /// - /// 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. - /// - /// # 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. /// - /// Globals are not limited through the `stack_height` as locals are. Neither does - /// the linear memory limit `memory_pages` applies to them. + /// Globals are not limited through the linear memory limit `memory_pages`. pub globals: u32, /// Maximum number of locals a function can have. @@ -532,8 +518,6 @@ impl Default for Limits { fn default() -> Self { Self { event_topics: 4, - // No stack limit required because we use a runtime resident execution engine. - stack_height: None, globals: 256, locals: 1024, parameters: 128, diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index 85fe22ab9a19b..7a0736d1ed61a 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -339,9 +339,6 @@ impl pallet_utility::Config for Test { parameter_types! { 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.instruction_weights.fallback = 1; schedule }; @@ -2964,7 +2961,7 @@ fn upload_code_works() { phase: Phase::Initialization, event: RuntimeEvent::Balances(pallet_balances::Event::Reserved { who: ALICE, - amount: 241, + amount: 173, }), topics: vec![], }, @@ -3054,7 +3051,7 @@ fn remove_code_works() { phase: Phase::Initialization, event: RuntimeEvent::Balances(pallet_balances::Event::Reserved { who: ALICE, - amount: 241, + amount: 173, }), topics: vec![], }, @@ -3067,7 +3064,7 @@ fn remove_code_works() { phase: Phase::Initialization, event: RuntimeEvent::Balances(pallet_balances::Event::Unreserved { who: ALICE, - amount: 241, + amount: 173, }), topics: vec![], }, @@ -3110,7 +3107,7 @@ fn remove_code_wrong_origin() { phase: Phase::Initialization, event: RuntimeEvent::Balances(pallet_balances::Event::Reserved { who: ALICE, - amount: 241, + amount: 173, }), topics: vec![], }, @@ -3246,7 +3243,7 @@ fn instantiate_with_zero_balance_works() { phase: Phase::Initialization, event: RuntimeEvent::Balances(pallet_balances::Event::Reserved { who: ALICE, - amount: 241, + amount: 173, }), topics: vec![], }, @@ -3351,7 +3348,7 @@ fn instantiate_with_below_existential_deposit_works() { phase: Phase::Initialization, event: RuntimeEvent::Balances(pallet_balances::Event::Reserved { who: ALICE, - amount: 241, + amount: 173, }), topics: vec![], }, diff --git a/frame/contracts/src/wasm/prepare.rs b/frame/contracts/src/wasm/prepare.rs index 9bb58bb02b5ea..dfe25bc3af89f 100644 --- a/frame/contracts/src/wasm/prepare.rs +++ b/frame/contracts/src/wasm/prepare.rs @@ -216,16 +216,6 @@ impl<'a, T: Config> ContractModule<'a, T> { Ok(ContractModule { module: contract_module, schedule: self.schedule }) } - fn inject_stack_height_metering(self) -> Result { - 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 }) - } else { - Ok(ContractModule { module: self.module, schedule: self.schedule }) - } - } - /// Check that the module has required exported functions. For now /// these are just entrypoints: /// @@ -447,10 +437,7 @@ where let memory_limits = get_memory_limits(contract_module.scan_imports(&disallowed_imports)?, schedule)?; - let code = contract_module - .inject_gas_metering(determinism)? - .inject_stack_height_metering()? - .into_wasm_code()?; + let code = contract_module.inject_gas_metering(determinism)?.into_wasm_code()?; Ok((code, memory_limits)) })() From 91d91d167d37630de663ddc78e2dab38aabe573d Mon Sep 17 00:00:00 2001 From: Muharem Ismailov Date: Thu, 22 Dec 2022 21:12:01 +0100 Subject: [PATCH 222/715] Alliance: remove unused func from weight trait (#13001) * Alliance: remove unused weight func * ".git/.scripts/bench-bot.sh" pallet dev pallet_alliance Co-authored-by: command-bot <> --- frame/alliance/src/weights.rs | 569 +++++++++++++++++----------------- 1 file changed, 281 insertions(+), 288 deletions(-) diff --git a/frame/alliance/src/weights.rs b/frame/alliance/src/weights.rs index 58d28b28f2cf3..1cfc83dfc4bbd 100644 --- a/frame/alliance/src/weights.rs +++ b/frame/alliance/src/weights.rs @@ -1,22 +1,42 @@ +// 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-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `cob`, CPU: `` -//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 +//! DATE: 2022-12-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/release/substrate +// /home/benchbot/cargo_target_dir/production/substrate // benchmark // pallet -// --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet-alliance // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/alliance/src/._weights.rs +// --json-file=/var/lib/gitlab-runner/builds/zyw4fam_/0/parity/mirrors/substrate/.git/.artifacts/bench.json +// --pallet=pallet_alliance +// --chain=dev +// --header=./HEADER-APACHE2 +// --output=./frame/alliance/src/weights.rs // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -30,7 +50,6 @@ use sp_std::marker::PhantomData; pub trait WeightInfo { fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight; fn vote(m: u32, ) -> Weight; - fn veto(p: 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; @@ -62,41 +81,26 @@ impl WeightInfo for SubstrateWeight { /// 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 { - // 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)) + fn propose_proposed(_b: u32, m: u32, p: u32, ) -> Weight { + // Minimum execution time: 45_945 nanoseconds. + Weight::from_ref_time(44_195_340) + // Standard Error: 2_212 + .saturating_add(Weight::from_ref_time(73_715).saturating_mul(m.into())) + // Standard Error: 2_184 + .saturating_add(Weight::from_ref_time(172_373).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) } // Storage: Alliance Members (r:1 w:0) // Storage: AllianceMotion Voting (r:1 w:1) /// 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) - // 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 { - // 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)) + // Minimum execution time: 41_578 nanoseconds. + Weight::from_ref_time(44_299_385) + // Standard Error: 3_727 + .saturating_add(Weight::from_ref_time(138_681).saturating_mul(m.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) } // Storage: Alliance Members (r:1 w:0) // Storage: AllianceMotion Voting (r:1 w:1) @@ -106,14 +110,14 @@ 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: 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)) + // Minimum execution time: 53_033 nanoseconds. + Weight::from_ref_time(44_608_804) + // Standard Error: 2_306 + .saturating_add(Weight::from_ref_time(102_842).saturating_mul(m.into())) + // Standard Error: 2_248 + .saturating_add(Weight::from_ref_time(172_018).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: Alliance Members (r:1 w:0) // Storage: AllianceMotion Voting (r:1 w:1) @@ -124,16 +128,16 @@ 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: 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)) + // Minimum execution time: 61_157 nanoseconds. + Weight::from_ref_time(53_647_510) + // Standard Error: 235 + .saturating_add(Weight::from_ref_time(88).saturating_mul(b.into())) + // Standard Error: 2_486 + .saturating_add(Weight::from_ref_time(103_912).saturating_mul(m.into())) + // Standard Error: 2_424 + .saturating_add(Weight::from_ref_time(197_471).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: Alliance Members (r:1 w:0) // Storage: AllianceMotion Voting (r:1 w:1) @@ -144,14 +148,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `m` is `[2, 100]`. /// The range of component `p` is `[1, 100]`. 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)) + // Minimum execution time: 53_830 nanoseconds. + Weight::from_ref_time(43_926_698) + // Standard Error: 2_495 + .saturating_add(Weight::from_ref_time(112_814).saturating_mul(m.into())) + // Standard Error: 2_465 + .saturating_add(Weight::from_ref_time(186_422).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: Alliance Members (r:1 w:0) // Storage: AllianceMotion Voting (r:1 w:1) @@ -163,28 +167,28 @@ impl WeightInfo for SubstrateWeight { /// The range of component `m` is `[5, 100]`. /// The range of component `p` is `[1, 100]`. fn close_approved(_b: u32, m: u32, p: u32, ) -> Weight { - // 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)) + // Minimum execution time: 53_665 nanoseconds. + Weight::from_ref_time(44_914_913) + // Standard Error: 2_244 + .saturating_add(Weight::from_ref_time(105_848).saturating_mul(m.into())) + // Standard Error: 2_164 + .saturating_add(Weight::from_ref_time(190_830).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: Alliance Members (r:2 w:2) // Storage: AllianceMotion Members (r:1 w:1) /// The range of component `m` is `[1, 100]`. /// The range of component `z` is `[0, 100]`. 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)) + // Minimum execution time: 46_486 nanoseconds. + Weight::from_ref_time(34_596_922) + // Standard Error: 1_807 + .saturating_add(Weight::from_ref_time(143_225).saturating_mul(m.into())) + // Standard Error: 1_786 + .saturating_add(Weight::from_ref_time(125_729).saturating_mul(z.into())) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: Alliance Members (r:2 w:2) // Storage: AllianceMotion Proposals (r:1 w:0) @@ -196,68 +200,68 @@ 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: 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(4 as u64)) - .saturating_add(T::DbWeight::get().writes((2 as u64).saturating_mul(z as u64))) + // Minimum execution time: 251_640 nanoseconds. + Weight::from_ref_time(252_446_000) + // Standard Error: 20_419 + .saturating_add(Weight::from_ref_time(486_667).saturating_mul(x.into())) + // Standard Error: 20_320 + .saturating_add(Weight::from_ref_time(498_890).saturating_mul(y.into())) + // Standard Error: 40_604 + .saturating_add(Weight::from_ref_time(9_411_242).saturating_mul(z.into())) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(x.into()))) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(y.into()))) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(z.into()))) + .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(z.into()))) } // Storage: Alliance Rule (r:0 w:1) fn set_rule() -> Weight { - // Minimum execution time: 11_000 nanoseconds. - Weight::from_ref_time(12_000_000 as u64) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + // Minimum execution time: 18_867 nanoseconds. + Weight::from_ref_time(19_155_000) + .saturating_add(T::DbWeight::get().writes(1)) } // Storage: Alliance Announcements (r:1 w:1) fn announce() -> Weight { - // 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)) + // Minimum execution time: 21_942 nanoseconds. + Weight::from_ref_time(22_319_000) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) } // Storage: Alliance Announcements (r:1 w:1) fn remove_announcement() -> Weight { - // 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)) + // Minimum execution time: 23_419 nanoseconds. + Weight::from_ref_time(23_854_000) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(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: 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)) + // Minimum execution time: 53_016 nanoseconds. + Weight::from_ref_time(53_768_000) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: Alliance Members (r:3 w:1) // Storage: Alliance UnscrupulousAccounts (r:1 w:0) fn nominate_ally() -> 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(1 as u64)) + // Minimum execution time: 40_019 nanoseconds. + Weight::from_ref_time(41_087_000) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(1)) } // 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: 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)) + // Minimum execution time: 35_973 nanoseconds. + Weight::from_ref_time(36_365_000) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(4)) } // Storage: Alliance Members (r:4 w:2) // Storage: AllianceMotion Proposals (r:1 w:0) @@ -265,20 +269,20 @@ 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: 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)) + // Minimum execution time: 44_949 nanoseconds. + Weight::from_ref_time(46_284_000) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(5)) } // 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 { - // 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)) + // Minimum execution time: 45_989 nanoseconds. + Weight::from_ref_time(46_586_000) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) } // Storage: Alliance Members (r:3 w:1) // Storage: AllianceMotion Proposals (r:1 w:0) @@ -287,46 +291,48 @@ 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: 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)) + // Minimum execution time: 67_333 nanoseconds. + Weight::from_ref_time(68_302_000) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(5)) } // Storage: Alliance UnscrupulousAccounts (r:1 w:1) // Storage: Alliance UnscrupulousWebsites (r:1 w:1) /// 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: 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)) + // Minimum execution time: 16_911 nanoseconds. + Weight::from_ref_time(17_204_000) + // Standard Error: 2_688 + .saturating_add(Weight::from_ref_time(1_324_527).saturating_mul(n.into())) + // Standard Error: 1_052 + .saturating_add(Weight::from_ref_time(73_828).saturating_mul(l.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) } // Storage: Alliance UnscrupulousAccounts (r:1 w:1) // 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: 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)) + fn remove_unscrupulous_items(n: u32, l: u32, ) -> Weight { + // Minimum execution time: 17_117 nanoseconds. + Weight::from_ref_time(17_291_000) + // Standard Error: 166_132 + .saturating_add(Weight::from_ref_time(13_173_211).saturating_mul(n.into())) + // Standard Error: 65_064 + .saturating_add(Weight::from_ref_time(478_626).saturating_mul(l.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) } // Storage: Alliance Members (r:3 w:2) // 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)) + // Minimum execution time: 43_347 nanoseconds. + Weight::from_ref_time(43_986_000) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) } } @@ -340,41 +346,26 @@ impl WeightInfo for () { /// 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 { - // 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)) + fn propose_proposed(_b: u32, m: u32, p: u32, ) -> Weight { + // Minimum execution time: 45_945 nanoseconds. + Weight::from_ref_time(44_195_340) + // Standard Error: 2_212 + .saturating_add(Weight::from_ref_time(73_715).saturating_mul(m.into())) + // Standard Error: 2_184 + .saturating_add(Weight::from_ref_time(172_373).saturating_mul(p.into())) + .saturating_add(RocksDbWeight::get().reads(4)) + .saturating_add(RocksDbWeight::get().writes(4)) } // Storage: Alliance Members (r:1 w:0) // Storage: AllianceMotion Voting (r:1 w:1) /// 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) - // 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 { - // 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)) + // Minimum execution time: 41_578 nanoseconds. + Weight::from_ref_time(44_299_385) + // Standard Error: 3_727 + .saturating_add(Weight::from_ref_time(138_681).saturating_mul(m.into())) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(1)) } // Storage: Alliance Members (r:1 w:0) // Storage: AllianceMotion Voting (r:1 w:1) @@ -384,14 +375,14 @@ 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: 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)) + // Minimum execution time: 53_033 nanoseconds. + Weight::from_ref_time(44_608_804) + // Standard Error: 2_306 + .saturating_add(Weight::from_ref_time(102_842).saturating_mul(m.into())) + // Standard Error: 2_248 + .saturating_add(Weight::from_ref_time(172_018).saturating_mul(p.into())) + .saturating_add(RocksDbWeight::get().reads(4)) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: Alliance Members (r:1 w:0) // Storage: AllianceMotion Voting (r:1 w:1) @@ -402,16 +393,16 @@ 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: 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)) + // Minimum execution time: 61_157 nanoseconds. + Weight::from_ref_time(53_647_510) + // Standard Error: 235 + .saturating_add(Weight::from_ref_time(88).saturating_mul(b.into())) + // Standard Error: 2_486 + .saturating_add(Weight::from_ref_time(103_912).saturating_mul(m.into())) + // Standard Error: 2_424 + .saturating_add(Weight::from_ref_time(197_471).saturating_mul(p.into())) + .saturating_add(RocksDbWeight::get().reads(5)) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: Alliance Members (r:1 w:0) // Storage: AllianceMotion Voting (r:1 w:1) @@ -422,14 +413,14 @@ impl WeightInfo for () { /// The range of component `m` is `[2, 100]`. /// The range of component `p` is `[1, 100]`. 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)) + // Minimum execution time: 53_830 nanoseconds. + Weight::from_ref_time(43_926_698) + // Standard Error: 2_495 + .saturating_add(Weight::from_ref_time(112_814).saturating_mul(m.into())) + // Standard Error: 2_465 + .saturating_add(Weight::from_ref_time(186_422).saturating_mul(p.into())) + .saturating_add(RocksDbWeight::get().reads(5)) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: Alliance Members (r:1 w:0) // Storage: AllianceMotion Voting (r:1 w:1) @@ -441,28 +432,28 @@ impl WeightInfo for () { /// The range of component `m` is `[5, 100]`. /// The range of component `p` is `[1, 100]`. fn close_approved(_b: u32, m: u32, p: u32, ) -> Weight { - // 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)) + // Minimum execution time: 53_665 nanoseconds. + Weight::from_ref_time(44_914_913) + // Standard Error: 2_244 + .saturating_add(Weight::from_ref_time(105_848).saturating_mul(m.into())) + // Standard Error: 2_164 + .saturating_add(Weight::from_ref_time(190_830).saturating_mul(p.into())) + .saturating_add(RocksDbWeight::get().reads(5)) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: Alliance Members (r:2 w:2) // Storage: AllianceMotion Members (r:1 w:1) /// The range of component `m` is `[1, 100]`. /// The range of component `z` is `[0, 100]`. 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)) + // Minimum execution time: 46_486 nanoseconds. + Weight::from_ref_time(34_596_922) + // Standard Error: 1_807 + .saturating_add(Weight::from_ref_time(143_225).saturating_mul(m.into())) + // Standard Error: 1_786 + .saturating_add(Weight::from_ref_time(125_729).saturating_mul(z.into())) + .saturating_add(RocksDbWeight::get().reads(3)) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: Alliance Members (r:2 w:2) // Storage: AllianceMotion Proposals (r:1 w:0) @@ -474,68 +465,68 @@ 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: 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(4 as u64)) - .saturating_add(RocksDbWeight::get().writes((2 as u64).saturating_mul(z as u64))) + // Minimum execution time: 251_640 nanoseconds. + Weight::from_ref_time(252_446_000) + // Standard Error: 20_419 + .saturating_add(Weight::from_ref_time(486_667).saturating_mul(x.into())) + // Standard Error: 20_320 + .saturating_add(Weight::from_ref_time(498_890).saturating_mul(y.into())) + // Standard Error: 40_604 + .saturating_add(Weight::from_ref_time(9_411_242).saturating_mul(z.into())) + .saturating_add(RocksDbWeight::get().reads(3)) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(x.into()))) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(y.into()))) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(z.into()))) + .saturating_add(RocksDbWeight::get().writes(4)) + .saturating_add(RocksDbWeight::get().writes((2_u64).saturating_mul(z.into()))) } // Storage: Alliance Rule (r:0 w:1) fn set_rule() -> Weight { - // Minimum execution time: 11_000 nanoseconds. - Weight::from_ref_time(12_000_000 as u64) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + // Minimum execution time: 18_867 nanoseconds. + Weight::from_ref_time(19_155_000) + .saturating_add(RocksDbWeight::get().writes(1)) } // Storage: Alliance Announcements (r:1 w:1) fn announce() -> Weight { - // 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)) + // Minimum execution time: 21_942 nanoseconds. + Weight::from_ref_time(22_319_000) + .saturating_add(RocksDbWeight::get().reads(1)) + .saturating_add(RocksDbWeight::get().writes(1)) } // Storage: Alliance Announcements (r:1 w:1) fn remove_announcement() -> Weight { - // 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)) + // Minimum execution time: 23_419 nanoseconds. + Weight::from_ref_time(23_854_000) + .saturating_add(RocksDbWeight::get().reads(1)) + .saturating_add(RocksDbWeight::get().writes(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: 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)) + // Minimum execution time: 53_016 nanoseconds. + Weight::from_ref_time(53_768_000) + .saturating_add(RocksDbWeight::get().reads(5)) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: Alliance Members (r:3 w:1) // Storage: Alliance UnscrupulousAccounts (r:1 w:0) fn nominate_ally() -> 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(1 as u64)) + // Minimum execution time: 40_019 nanoseconds. + Weight::from_ref_time(41_087_000) + .saturating_add(RocksDbWeight::get().reads(4)) + .saturating_add(RocksDbWeight::get().writes(1)) } // 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: 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)) + // Minimum execution time: 35_973 nanoseconds. + Weight::from_ref_time(36_365_000) + .saturating_add(RocksDbWeight::get().reads(3)) + .saturating_add(RocksDbWeight::get().writes(4)) } // Storage: Alliance Members (r:4 w:2) // Storage: AllianceMotion Proposals (r:1 w:0) @@ -543,20 +534,20 @@ 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: 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)) + // Minimum execution time: 44_949 nanoseconds. + Weight::from_ref_time(46_284_000) + .saturating_add(RocksDbWeight::get().reads(5)) + .saturating_add(RocksDbWeight::get().writes(5)) } // 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 { - // 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)) + // Minimum execution time: 45_989 nanoseconds. + Weight::from_ref_time(46_586_000) + .saturating_add(RocksDbWeight::get().reads(4)) + .saturating_add(RocksDbWeight::get().writes(4)) } // Storage: Alliance Members (r:3 w:1) // Storage: AllianceMotion Proposals (r:1 w:0) @@ -565,45 +556,47 @@ impl WeightInfo for () { // Storage: AllianceMotion Members (r:0 w:1) // Storage: AllianceMotion Prime (r:0 w:1) fn kick_member() -> Weight { - // 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)) + // Minimum execution time: 67_333 nanoseconds. + Weight::from_ref_time(68_302_000) + .saturating_add(RocksDbWeight::get().reads(6)) + .saturating_add(RocksDbWeight::get().writes(5)) } // Storage: Alliance UnscrupulousAccounts (r:1 w:1) // Storage: Alliance UnscrupulousWebsites (r:1 w:1) /// 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: 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)) + // Minimum execution time: 16_911 nanoseconds. + Weight::from_ref_time(17_204_000) + // Standard Error: 2_688 + .saturating_add(Weight::from_ref_time(1_324_527).saturating_mul(n.into())) + // Standard Error: 1_052 + .saturating_add(Weight::from_ref_time(73_828).saturating_mul(l.into())) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(2)) } // Storage: Alliance UnscrupulousAccounts (r:1 w:1) // 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: 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)) + fn remove_unscrupulous_items(n: u32, l: u32, ) -> Weight { + // Minimum execution time: 17_117 nanoseconds. + Weight::from_ref_time(17_291_000) + // Standard Error: 166_132 + .saturating_add(Weight::from_ref_time(13_173_211).saturating_mul(n.into())) + // Standard Error: 65_064 + .saturating_add(Weight::from_ref_time(478_626).saturating_mul(l.into())) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(2)) } // 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)) + // Minimum execution time: 43_347 nanoseconds. + Weight::from_ref_time(43_986_000) + .saturating_add(RocksDbWeight::get().reads(4)) + .saturating_add(RocksDbWeight::get().writes(4)) } } From 9443052a2b7e0c05e8cdc2bb5c972a7a677ab9bc Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Thu, 22 Dec 2022 23:33:01 +0100 Subject: [PATCH 223/715] txpool: don't validate block transactions if the pool is empty (#12973) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * txpool: don't validate block transactions if the pool is empty Fix shall prevent from wasting the CPU during the major sync. Block transaction don't need to be re-validated when the txpool is empty. Fixes: #12903 * Apply suggestions from code review Co-authored-by: Bastian Köcher --- client/transaction-pool/src/graph/pool.rs | 25 +++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/client/transaction-pool/src/graph/pool.rs b/client/transaction-pool/src/graph/pool.rs index 96cbeb9b80cfb..8e3570d1dbd1f 100644 --- a/client/transaction-pool/src/graph/pool.rs +++ b/client/transaction-pool/src/graph/pool.rs @@ -271,14 +271,23 @@ impl Pool { // if it's not found in the pool query the runtime at parent block // to get validity info and tags that the extrinsic provides. None => { - let validity = self - .validated_pool - .api() - .validate_transaction(parent, TransactionSource::InBlock, extrinsic.clone()) - .await; - - if let Ok(Ok(validity)) = validity { - future_tags.extend(validity.provides); + // Avoid validating block txs if the pool is empty + if !self.validated_pool.status().is_empty() { + let validity = self + .validated_pool + .api() + .validate_transaction( + parent, + TransactionSource::InBlock, + extrinsic.clone(), + ) + .await; + + if let Ok(Ok(validity)) = validity { + future_tags.extend(validity.provides); + } + } else { + log::trace!(target: "txpool", "txpool is empty, skipping validation for block {at:?}"); } }, } From 6c65424579c04a9d366cb08579bd4f66ddd4f1ad Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Fri, 23 Dec 2022 08:04:47 +0100 Subject: [PATCH 224/715] Fix fast-unstake for accounts with slashing (#12963) * Fix fast-unstake for accounts with slashing * ".git/.scripts/fmt.sh" 1 * fmt * fix * fix weight tracking * Adds tests for withdraw_unbonded with slashing * Removes tests for withdraw_unbonded with slashing * ".git/.scripts/fmt.sh" * Adds slash spans calculation test for withdraw_unbonded Co-authored-by: command-bot <> Co-authored-by: gpestana --- frame/fast-unstake/src/lib.rs | 14 +++++---- frame/staking/src/pallet/impls.rs | 2 +- frame/staking/src/pallet/mod.rs | 3 +- frame/staking/src/tests.rs | 51 +++++++++++++++++++++++++++++++ 4 files changed, 62 insertions(+), 8 deletions(-) diff --git a/frame/fast-unstake/src/lib.rs b/frame/fast-unstake/src/lib.rs index 7f226826cbc53..f2faeebc13478 100644 --- a/frame/fast-unstake/src/lib.rs +++ b/frame/fast-unstake/src/lib.rs @@ -91,7 +91,7 @@ pub mod pallet { DispatchResult, }; use sp_staking::{EraIndex, StakingInterface}; - use sp_std::{prelude::*, vec::Vec}; + use sp_std::{collections::btree_set::BTreeSet, prelude::*, vec::Vec}; pub use weights::WeightInfo; #[derive(scale_info::TypeInfo, codec::Encode, codec::Decode, codec::MaxEncodedLen)] @@ -429,9 +429,9 @@ pub mod pallet { } }; - let check_stash = |stash, deposit, eras_checked: &mut u32| { + let check_stash = |stash, deposit, eras_checked: &mut BTreeSet| { let is_exposed = unchecked_eras_to_check.iter().any(|e| { - eras_checked.saturating_inc(); + eras_checked.insert(*e); T::Staking::is_exposed_in_era(&stash, e) }); @@ -452,7 +452,7 @@ pub mod pallet { ::WeightInfo::on_idle_unstake() } else { // eras checked so far. - let mut eras_checked = 0u32; + let mut eras_checked = BTreeSet::::new(); let pre_length = stashes.len(); let stashes: BoundedVec<(T::AccountId, BalanceOf), T::BatchSize> = stashes @@ -468,7 +468,7 @@ pub mod pallet { log!( debug, "checked {:?} eras, pre stashes: {:?}, post: {:?}", - eras_checked, + eras_checked.len(), pre_length, post_length, ); @@ -489,7 +489,9 @@ pub mod pallet { }, } - ::WeightInfo::on_idle_check(validator_count * eras_checked) + ::WeightInfo::on_idle_check( + validator_count * eras_checked.len() as u32, + ) } } } diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index a7190d70c7061..db9aeba6fb58e 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -1569,7 +1569,7 @@ impl StakingInterface for Pallet { } fn force_unstake(who: Self::AccountId) -> sp_runtime::DispatchResult { - let num_slashing_spans = Self::slashing_spans(&who).iter().count() as u32; + let num_slashing_spans = Self::slashing_spans(&who).map_or(0, |s| s.iter().count() as u32); Self::force_unstake(RawOrigin::Root.into(), who.clone(), num_slashing_spans) } diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 1d5babe7ffa8f..f04d13d05f468 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -982,7 +982,8 @@ pub mod pallet { // `BondingDuration` to proceed with the unbonding. let maybe_withdraw_weight = { if unlocking == T::MaxUnlockingChunks::get() as usize { - let real_num_slashing_spans = Self::slashing_spans(&controller).iter().count(); + let real_num_slashing_spans = + Self::slashing_spans(&controller).map_or(0, |s| s.iter().count()); Some(Self::do_withdraw_unbonded(&controller, real_num_slashing_spans as u32)?) } else { None diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index fc6fc68e66d5d..5c2766deee307 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -5725,3 +5725,54 @@ fn scale_validator_count_errors() { ); }) } + +mod staking_interface { + use frame_support::storage::with_storage_layer; + use sp_staking::StakingInterface; + + use super::*; + + #[test] + fn force_unstake_with_slash_works() { + ExtBuilder::default().build_and_execute(|| { + // without slash + let _ = with_storage_layer::<(), _, _>(|| { + // bond an account, can unstake + assert_eq!(Staking::bonded(&11), Some(10)); + assert_ok!(::force_unstake(11)); + Err(DispatchError::from("revert")) + }); + + // bond again and add a slash, still can unstake. + assert_eq!(Staking::bonded(&11), Some(10)); + add_slash(&11); + assert_ok!(::force_unstake(11)); + }); + } + + #[test] + fn do_withdraw_unbonded_with_wrong_slash_spans_works_as_expected() { + ExtBuilder::default().build_and_execute(|| { + on_offence_now( + &[OffenceDetails { + offender: (11, Staking::eras_stakers(active_era(), 11)), + reporters: vec![], + }], + &[Perbill::from_percent(100)], + ); + + assert_eq!(Staking::bonded(&11), Some(10)); + + assert_noop!( + Staking::withdraw_unbonded(RuntimeOrigin::signed(10), 0), + Error::::IncorrectSlashingSpans + ); + + let num_slashing_spans = Staking::slashing_spans(&11).map_or(0, |s| s.iter().count()); + assert_ok!(Staking::withdraw_unbonded( + RuntimeOrigin::signed(10), + num_slashing_spans as u32 + )); + }); + } +} From 40cb4318102adc806c8f7f17da20d1b6be6dce34 Mon Sep 17 00:00:00 2001 From: Dmitry Markin Date: Fri, 23 Dec 2022 16:03:08 +0300 Subject: [PATCH 225/715] Runtime diagnostics for leaked messages in unbounded channels (#12971) --- Cargo.lock | 2 + client/api/src/notifications.rs | 4 +- client/beefy/rpc/src/lib.rs | 4 +- client/beefy/src/lib.rs | 2 +- client/beefy/src/tests.rs | 10 +- .../common/src/import_queue/basic_queue.rs | 8 +- .../common/src/import_queue/buffered_link.rs | 12 +- client/finality-grandpa/rpc/src/lib.rs | 2 +- .../src/communication/gossip.rs | 2 +- .../src/communication/periodic.rs | 1 + .../src/communication/tests.rs | 4 +- client/finality-grandpa/src/lib.rs | 3 +- client/finality-grandpa/src/observer.rs | 2 +- client/finality-grandpa/src/until_imported.rs | 8 +- client/network/src/service.rs | 4 +- client/network/src/service/out_events.rs | 91 +++++++++---- client/network/sync/src/lib.rs | 2 +- client/network/sync/src/service/network.rs | 2 +- client/network/transactions/Cargo.toml | 1 + client/network/transactions/src/lib.rs | 9 +- client/offchain/src/api/http.rs | 4 +- client/peerset/src/lib.rs | 2 +- client/rpc/src/system/tests.rs | 2 +- client/service/src/builder.rs | 2 +- client/service/src/client/client.rs | 4 +- client/service/src/task_manager/mod.rs | 3 +- client/telemetry/Cargo.toml | 1 + client/telemetry/src/lib.rs | 14 +- client/transaction-pool/src/graph/watcher.rs | 2 +- client/transaction-pool/src/revalidation.rs | 2 +- client/utils/src/mpsc.rs | 121 ++++++++++++++---- client/utils/src/notification.rs | 4 +- client/utils/src/notification/tests.rs | 2 +- client/utils/src/pubsub.rs | 4 +- .../src/pubsub/tests/normal_operation.rs | 10 +- .../src/pubsub/tests/panicking_registry.rs | 37 +++--- client/utils/src/status_sinks.rs | 4 +- 37 files changed, 257 insertions(+), 134 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8412781c682e3..c4bd2532e8ede 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7948,6 +7948,7 @@ dependencies = [ "pin-project", "sc-network-common", "sc-peerset", + "sc-utils", "sp-consensus", "sp-runtime", "substrate-prometheus-endpoint", @@ -8284,6 +8285,7 @@ dependencies = [ "parking_lot 0.12.1", "pin-project", "rand 0.8.5", + "sc-utils", "serde", "serde_json", "thiserror", diff --git a/client/api/src/notifications.rs b/client/api/src/notifications.rs index 9fcc381f9697e..4dd23581d2622 100644 --- a/client/api/src/notifications.rs +++ b/client/api/src/notifications.rs @@ -144,7 +144,9 @@ impl StorageNotifications { filter_keys: Option<&[StorageKey]>, filter_child_keys: Option<&[(StorageKey, Option>)]>, ) -> StorageEventStream { - let receiver = self.0.subscribe(registry::SubscribeOp { filter_keys, filter_child_keys }); + let receiver = self + .0 + .subscribe(registry::SubscribeOp { filter_keys, filter_child_keys }, 100_000); StorageEventStream(receiver) } diff --git a/client/beefy/rpc/src/lib.rs b/client/beefy/rpc/src/lib.rs index 59a133b86214e..4fea98c6eb24e 100644 --- a/client/beefy/rpc/src/lib.rs +++ b/client/beefy/rpc/src/lib.rs @@ -120,7 +120,7 @@ where ) -> Result { let beefy_best_block = Arc::new(RwLock::new(None)); - let stream = best_block_stream.subscribe(); + let stream = best_block_stream.subscribe(100_000); let closure_clone = beefy_best_block.clone(); let future = stream.for_each(move |best_beefy| { let async_clone = closure_clone.clone(); @@ -141,7 +141,7 @@ where fn subscribe_justifications(&self, mut sink: SubscriptionSink) -> SubscriptionResult { let stream = self .finality_proof_stream - .subscribe() + .subscribe(100_000) .map(|vfp| notification::EncodedVersionedFinalityProof::new::(vfp)); let fut = async move { diff --git a/client/beefy/src/lib.rs b/client/beefy/src/lib.rs index 35f7cac55a964..5b6531822a0a1 100644 --- a/client/beefy/src/lib.rs +++ b/client/beefy/src/lib.rs @@ -265,7 +265,7 @@ where // 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(); + let block_import_justif = links.from_block_import_justif_stream.subscribe(100_000).fuse(); // Wait for BEEFY pallet to be active before starting voter. let persisted_state = diff --git a/client/beefy/src/tests.rs b/client/beefy/src/tests.rs index ce6f6ae3c978a..66d3a210d7eba 100644 --- a/client/beefy/src/tests.rs +++ b/client/beefy/src/tests.rs @@ -430,8 +430,8 @@ pub(crate) fn get_beefy_streams( 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.push(from_voter_best_beefy_stream.subscribe(100_000)); + versioned_finality_proof_streams.push(from_voter_justif_stream.subscribe(100_000)); }); (best_block_streams, versioned_finality_proof_streams) } @@ -736,7 +736,7 @@ async fn beefy_importing_blocks() { let hashof1 = block.header.hash(); // Import without justifications. - let mut justif_recv = justif_stream.subscribe(); + let mut justif_recv = justif_stream.subscribe(100_000); assert_eq!( block_import .import_block(params(block.clone(), None), HashMap::new()) @@ -779,7 +779,7 @@ async 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(); + let mut justif_recv = justif_stream.subscribe(100_000); assert_eq!( block_import.import_block(params(block, justif), HashMap::new()).await.unwrap(), ImportResult::Imported(ImportedAux { @@ -823,7 +823,7 @@ async 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(); + let mut justif_recv = justif_stream.subscribe(100_000); assert_eq!( block_import.import_block(params(block, justif), HashMap::new()).await.unwrap(), ImportResult::Imported(ImportedAux { diff --git a/client/consensus/common/src/import_queue/basic_queue.rs b/client/consensus/common/src/import_queue/basic_queue.rs index b63bc192b2e77..a96b0a47e57c7 100644 --- a/client/consensus/common/src/import_queue/basic_queue.rs +++ b/client/consensus/common/src/import_queue/basic_queue.rs @@ -69,7 +69,7 @@ impl BasicQueue { spawner: &impl sp_core::traits::SpawnEssentialNamed, prometheus_registry: Option<&Registry>, ) -> Self { - let (result_sender, result_port) = buffered_link::buffered_link(); + let (result_sender, result_port) = buffered_link::buffered_link(100_000); let metrics = prometheus_registry.and_then(|r| { Metrics::register(r) @@ -276,10 +276,10 @@ impl BlockImportWorker { use worker_messages::*; let (justification_sender, mut justification_port) = - tracing_unbounded("mpsc_import_queue_worker_justification"); + tracing_unbounded("mpsc_import_queue_worker_justification", 100_000); let (block_import_sender, block_import_port) = - tracing_unbounded("mpsc_import_queue_worker_blocks"); + tracing_unbounded("mpsc_import_queue_worker_blocks", 100_000); let mut worker = BlockImportWorker { result_sender, justification_import, metrics }; @@ -595,7 +595,7 @@ mod tests { #[test] fn prioritizes_finality_work_over_block_import() { - let (result_sender, mut result_port) = buffered_link::buffered_link(); + let (result_sender, mut result_port) = buffered_link::buffered_link(100_000); let (worker, mut finality_sender, mut block_import_sender) = BlockImportWorker::new(result_sender, (), Box::new(()), Some(Box::new(())), None); diff --git a/client/consensus/common/src/import_queue/buffered_link.rs b/client/consensus/common/src/import_queue/buffered_link.rs index e6d3b212fdbac..71adcf2dc2ea9 100644 --- a/client/consensus/common/src/import_queue/buffered_link.rs +++ b/client/consensus/common/src/import_queue/buffered_link.rs @@ -28,7 +28,7 @@ //! # use sp_test_primitives::Block; //! # struct DummyLink; impl Link for DummyLink {} //! # let mut my_link = DummyLink; -//! let (mut tx, mut rx) = buffered_link::(); +//! let (mut tx, mut rx) = buffered_link::(100_000); //! tx.blocks_processed(0, 0, vec![]); //! //! // Calls `my_link.blocks_processed(0, 0, vec![])` when polled. @@ -51,9 +51,11 @@ use super::BlockImportResult; /// Wraps around an unbounded channel from the `futures` crate. The sender implements `Link` and /// can be used to buffer commands, and the receiver can be used to poll said commands and transfer -/// them to another link. -pub fn buffered_link() -> (BufferedLinkSender, BufferedLinkReceiver) { - let (tx, rx) = tracing_unbounded("mpsc_buffered_link"); +/// them to another link. `queue_size_warning` sets the warning threshold of the channel queue size. +pub fn buffered_link( + queue_size_warning: i64, +) -> (BufferedLinkSender, BufferedLinkReceiver) { + let (tx, rx) = tracing_unbounded("mpsc_buffered_link", queue_size_warning); let tx = BufferedLinkSender { tx }; let rx = BufferedLinkReceiver { rx: rx.fuse() }; (tx, rx) @@ -175,7 +177,7 @@ mod tests { #[test] fn is_closed() { - let (tx, rx) = super::buffered_link::(); + let (tx, rx) = super::buffered_link::(1); assert!(!tx.is_closed()); drop(rx); assert!(tx.is_closed()); diff --git a/client/finality-grandpa/rpc/src/lib.rs b/client/finality-grandpa/rpc/src/lib.rs index dfdad666ba8f3..70ff7ed176869 100644 --- a/client/finality-grandpa/rpc/src/lib.rs +++ b/client/finality-grandpa/rpc/src/lib.rs @@ -104,7 +104,7 @@ where } fn subscribe_justifications(&self, mut sink: SubscriptionSink) -> SubscriptionResult { - let stream = self.justification_stream.subscribe().map( + let stream = self.justification_stream.subscribe(100_000).map( |x: sc_finality_grandpa::GrandpaJustification| { JustificationNotification::from(x) }, diff --git a/client/finality-grandpa/src/communication/gossip.rs b/client/finality-grandpa/src/communication/gossip.rs index 408cbda745e56..cbcafc727d436 100644 --- a/client/finality-grandpa/src/communication/gossip.rs +++ b/client/finality-grandpa/src/communication/gossip.rs @@ -1364,7 +1364,7 @@ impl GossipValidator { None => None, }; - let (tx, rx) = tracing_unbounded("mpsc_grandpa_gossip_validator"); + let (tx, rx) = tracing_unbounded("mpsc_grandpa_gossip_validator", 100_000); let val = GossipValidator { inner: parking_lot::RwLock::new(Inner::new(config)), set_state, diff --git a/client/finality-grandpa/src/communication/periodic.rs b/client/finality-grandpa/src/communication/periodic.rs index 7e50abb96e441..c00fed1296512 100644 --- a/client/finality-grandpa/src/communication/periodic.rs +++ b/client/finality-grandpa/src/communication/periodic.rs @@ -70,6 +70,7 @@ impl NeighborPacketWorker { pub(super) fn new(rebroadcast_period: Duration) -> (Self, NeighborPacketSender) { let (tx, rx) = tracing_unbounded::<(Vec, NeighborPacket>)>( "mpsc_grandpa_neighbor_packet_worker", + 100_000, ); let delay = Delay::new(rebroadcast_period); diff --git a/client/finality-grandpa/src/communication/tests.rs b/client/finality-grandpa/src/communication/tests.rs index eab7bb2df50cf..839b2d52be651 100644 --- a/client/finality-grandpa/src/communication/tests.rs +++ b/client/finality-grandpa/src/communication/tests.rs @@ -135,7 +135,7 @@ impl NetworkEventStream for TestNetwork { &self, _name: &'static str, ) -> Pin + Send>> { - let (tx, rx) = tracing_unbounded("test"); + let (tx, rx) = tracing_unbounded("test", 100_000); let _ = self.sender.unbounded_send(Event::EventStream(tx)); Box::pin(rx) } @@ -253,7 +253,7 @@ fn voter_set_state() -> SharedVoterSetState { // needs to run in a tokio runtime. pub(crate) fn make_test_network() -> (impl Future, TestNetwork) { - let (tx, rx) = tracing_unbounded("test"); + let (tx, rx) = tracing_unbounded("test", 100_000); let net = TestNetwork { sender: tx }; #[derive(Clone)] diff --git a/client/finality-grandpa/src/lib.rs b/client/finality-grandpa/src/lib.rs index efc46d8f93a6d..1597e60bd6061 100644 --- a/client/finality-grandpa/src/lib.rs +++ b/client/finality-grandpa/src/lib.rs @@ -566,7 +566,8 @@ where } })?; - let (voter_commands_tx, voter_commands_rx) = tracing_unbounded("mpsc_grandpa_voter_command"); + let (voter_commands_tx, voter_commands_rx) = + tracing_unbounded("mpsc_grandpa_voter_command", 100_000); let (justification_sender, justification_stream) = GrandpaJustificationStream::channel(); diff --git a/client/finality-grandpa/src/observer.rs b/client/finality-grandpa/src/observer.rs index 1efb71e5903ec..96101a8eda0ab 100644 --- a/client/finality-grandpa/src/observer.rs +++ b/client/finality-grandpa/src/observer.rs @@ -437,7 +437,7 @@ mod tests { aux_schema::load_persistent(&*backend, client.info().genesis_hash, 0, || Ok(voters)) .unwrap(); - let (_tx, voter_command_rx) = tracing_unbounded(""); + let (_tx, voter_command_rx) = tracing_unbounded("test_mpsc_voter_command", 100_000); let observer = ObserverWork::new( client, diff --git a/client/finality-grandpa/src/until_imported.rs b/client/finality-grandpa/src/until_imported.rs index 95b658e92298a..776411f8fb493 100644 --- a/client/finality-grandpa/src/until_imported.rs +++ b/client/finality-grandpa/src/until_imported.rs @@ -579,7 +579,7 @@ mod tests { impl TestChainState { fn new() -> (Self, ImportNotifications) { - let (tx, rx) = tracing_unbounded("test"); + let (tx, rx) = tracing_unbounded("test", 100_000); let state = TestChainState { sender: tx, known_blocks: Arc::new(Mutex::new(HashMap::new())) }; @@ -680,7 +680,7 @@ mod tests { // enact all dependencies before importing the message enact_dependencies(&chain_state); - let (global_tx, global_rx) = tracing_unbounded("test"); + let (global_tx, global_rx) = tracing_unbounded("test", 100_000); let until_imported = UntilGlobalMessageBlocksImported::new( import_notifications, @@ -708,7 +708,7 @@ mod tests { let (chain_state, import_notifications) = TestChainState::new(); let block_status = chain_state.block_status(); - let (global_tx, global_rx) = tracing_unbounded("test"); + let (global_tx, global_rx) = tracing_unbounded("test", 100_000); let until_imported = UntilGlobalMessageBlocksImported::new( import_notifications, @@ -896,7 +896,7 @@ mod tests { let (chain_state, import_notifications) = TestChainState::new(); let block_status = chain_state.block_status(); - let (global_tx, global_rx) = tracing_unbounded("test"); + let (global_tx, global_rx) = tracing_unbounded("test", 100_000); let block_sync_requester = TestBlockSyncRequester::default(); diff --git a/client/network/src/service.rs b/client/network/src/service.rs index 08e498299a1d3..66de263a19a3e 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -208,7 +208,7 @@ where ¶ms.network_config.transport, )?; - let (to_worker, from_service) = tracing_unbounded("mpsc_network_worker"); + let (to_worker, from_service) = tracing_unbounded("mpsc_network_worker", 100_000); if let Some(path) = ¶ms.network_config.net_config_path { fs::create_dir_all(path)?; @@ -1003,7 +1003,7 @@ where H: ExHashT, { fn event_stream(&self, name: &'static str) -> Pin + Send>> { - let (tx, rx) = out_events::channel(name); + let (tx, rx) = out_events::channel(name, 100_000); let _ = self.to_worker.unbounded_send(ServiceToWorkerMsg::EventStream(tx)); Box::pin(rx) } diff --git a/client/network/src/service/out_events.rs b/client/network/src/service/out_events.rs index 4144d7f19551e..8febdd4726b37 100644 --- a/client/network/src/service/out_events.rs +++ b/client/network/src/service/out_events.rs @@ -32,25 +32,40 @@ //! collection. use futures::{channel::mpsc, prelude::*, ready, stream::FusedStream}; +use log::error; use parking_lot::Mutex; use prometheus_endpoint::{register, CounterVec, GaugeVec, Opts, PrometheusError, Registry, U64}; use sc_network_common::protocol::event::Event; use std::{ + backtrace::{Backtrace, BacktraceStatus}, cell::RefCell, fmt, pin::Pin, - sync::Arc, + sync::{ + atomic::{AtomicI64, Ordering}, + Arc, + }, task::{Context, Poll}, }; /// Creates a new channel that can be associated to a [`OutChannels`]. /// -/// The name is used in Prometheus reports. -pub fn channel(name: &'static str) -> (Sender, Receiver) { +/// The name is used in Prometheus reports, the queue size threshold is used +/// to warn if there are too many unprocessed events in the channel. +pub fn channel(name: &'static str, queue_size_warning: i64) -> (Sender, Receiver) { let (tx, rx) = mpsc::unbounded(); let metrics = Arc::new(Mutex::new(None)); - let tx = Sender { inner: tx, name, metrics: metrics.clone() }; - let rx = Receiver { inner: rx, name, metrics }; + let queue_size = Arc::new(AtomicI64::new(0)); + let tx = Sender { + inner: tx, + name, + queue_size: queue_size.clone(), + queue_size_warning, + warning_fired: false, + creation_backtrace: Backtrace::capture(), + metrics: metrics.clone(), + }; + let rx = Receiver { inner: rx, name, queue_size, metrics }; (tx, rx) } @@ -63,7 +78,19 @@ pub fn channel(name: &'static str) -> (Sender, Receiver) { /// sync on drop. If someone adds a `#[derive(Clone)]` below, it is **wrong**. pub struct Sender { inner: mpsc::UnboundedSender, + /// Name to identify the channel (e.g., in Prometheus and logs). name: &'static str, + /// Number of events in the queue. Clone of [`Receiver::in_transit`]. + // To not bother with ordering and possible underflow errors of the unsigned counter + // we just use `i64` and `Ordering::Relaxed`, and perceive `queue_size` as approximate. + // It can turn < 0 though. + queue_size: Arc, + /// Threshold queue size to generate an error message in the logs. + queue_size_warning: i64, + /// We generate the error message only once to not spam the logs. + warning_fired: bool, + /// Backtrace of a place where the channel was created. + creation_backtrace: Backtrace, /// Clone of [`Receiver::metrics`]. metrics: Arc>>>>, } @@ -87,6 +114,7 @@ impl Drop for Sender { pub struct Receiver { inner: mpsc::UnboundedReceiver, name: &'static str, + queue_size: Arc, /// Initially contains `None`, and will be set to a value once the corresponding [`Sender`] /// is assigned to an instance of [`OutChannels`]. metrics: Arc>>>>, @@ -97,6 +125,7 @@ impl Stream for Receiver { fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll> { if let Some(ev) = ready!(Pin::new(&mut self.inner).poll_next(cx)) { + let _ = self.queue_size.fetch_sub(1, Ordering::Relaxed); let metrics = self.metrics.lock().clone(); match metrics.as_ref().map(|m| m.as_ref()) { Some(Some(metrics)) => metrics.event_out(&ev, self.name), @@ -160,12 +189,28 @@ impl OutChannels { /// Sends an event. pub fn send(&mut self, event: Event) { - self.event_streams - .retain(|sender| sender.inner.unbounded_send(event.clone()).is_ok()); + self.event_streams.retain_mut(|sender| { + let queue_size = sender.queue_size.fetch_add(1, Ordering::Relaxed); + if queue_size == sender.queue_size_warning && !sender.warning_fired { + sender.warning_fired = true; + match sender.creation_backtrace.status() { + BacktraceStatus::Captured => error!( + "The number of unprocessed events in channel `{}` reached {}.\n\ + The channel was created at:\n{}", + sender.name, sender.queue_size_warning, sender.creation_backtrace, + ), + _ => error!( + "The number of unprocessed events in channel `{}` reached {}.", + sender.name, sender.queue_size_warning, + ), + } + } + sender.inner.unbounded_send(event.clone()).is_ok() + }); if let Some(metrics) = &*self.metrics { for ev in &self.event_streams { - metrics.event_in(&event, 1, ev.name); + metrics.event_in(&event, ev.name); } } } @@ -232,45 +277,35 @@ impl Metrics { }) } - fn event_in(&self, event: &Event, num: u64, name: &str) { + fn event_in(&self, event: &Event, name: &str) { match event { Event::Dht(_) => { - self.events_total.with_label_values(&["dht", "sent", name]).inc_by(num); + self.events_total.with_label_values(&["dht", "sent", name]).inc(); }, Event::SyncConnected { .. } => { - self.events_total - .with_label_values(&["sync-connected", "sent", name]) - .inc_by(num); + self.events_total.with_label_values(&["sync-connected", "sent", name]).inc(); }, Event::SyncDisconnected { .. } => { - self.events_total - .with_label_values(&["sync-disconnected", "sent", name]) - .inc_by(num); + self.events_total.with_label_values(&["sync-disconnected", "sent", name]).inc(); }, Event::NotificationStreamOpened { protocol, .. } => { format_label("notif-open-", protocol, |protocol_label| { - self.events_total - .with_label_values(&[protocol_label, "sent", name]) - .inc_by(num); + self.events_total.with_label_values(&[protocol_label, "sent", name]).inc(); }); }, Event::NotificationStreamClosed { protocol, .. } => { format_label("notif-closed-", protocol, |protocol_label| { - self.events_total - .with_label_values(&[protocol_label, "sent", name]) - .inc_by(num); + self.events_total.with_label_values(&[protocol_label, "sent", name]).inc(); }); }, Event::NotificationsReceived { messages, .. } => for (protocol, message) in messages { format_label("notif-", protocol, |protocol_label| { - self.events_total - .with_label_values(&[protocol_label, "sent", name]) - .inc_by(num); + self.events_total.with_label_values(&[protocol_label, "sent", name]).inc(); }); - self.notifications_sizes.with_label_values(&[protocol, "sent", name]).inc_by( - num.saturating_mul(u64::try_from(message.len()).unwrap_or(u64::MAX)), - ); + self.notifications_sizes + .with_label_values(&[protocol, "sent", name]) + .inc_by(u64::try_from(message.len()).unwrap_or(u64::MAX)); }, } } diff --git a/client/network/sync/src/lib.rs b/client/network/sync/src/lib.rs index 7dd818d4c12cb..76f14a721a439 100644 --- a/client/network/sync/src/lib.rs +++ b/client/network/sync/src/lib.rs @@ -1436,7 +1436,7 @@ where state_request_protocol_name: ProtocolName, warp_sync_protocol_name: Option, ) -> Result<(Self, ChainSyncInterfaceHandle, NonDefaultSetConfig), ClientError> { - let (tx, service_rx) = tracing_unbounded("mpsc_chain_sync"); + let (tx, service_rx) = tracing_unbounded("mpsc_chain_sync", 100_000); let block_announce_config = Self::get_block_announce_proto_config( protocol_id, fork_id, diff --git a/client/network/sync/src/service/network.rs b/client/network/sync/src/service/network.rs index c44398b0f1a9e..b81a65ae731cf 100644 --- a/client/network/sync/src/service/network.rs +++ b/client/network/sync/src/service/network.rs @@ -99,7 +99,7 @@ impl NetworkServiceHandle { impl NetworkServiceProvider { /// Create new `NetworkServiceProvider` pub fn new() -> (Self, NetworkServiceHandle) { - let (tx, rx) = tracing_unbounded("mpsc_network_service_provider"); + let (tx, rx) = tracing_unbounded("mpsc_network_service_provider", 100_000); (Self { rx }, NetworkServiceHandle::new(tx)) } diff --git a/client/network/transactions/Cargo.toml b/client/network/transactions/Cargo.toml index f91651d1508b5..1255dededc3eb 100644 --- a/client/network/transactions/Cargo.toml +++ b/client/network/transactions/Cargo.toml @@ -22,5 +22,6 @@ 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" } +sc-utils = { version = "4.0.0-dev", path = "../../utils" } sp-runtime = { version = "7.0.0", path = "../../../primitives/runtime" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } diff --git a/client/network/transactions/src/lib.rs b/client/network/transactions/src/lib.rs index 4cc76507c6f16..a5adb274d29de 100644 --- a/client/network/transactions/src/lib.rs +++ b/client/network/transactions/src/lib.rs @@ -28,7 +28,7 @@ use crate::config::*; use codec::{Decode, Encode}; -use futures::{channel::mpsc, prelude::*, stream::FuturesUnordered}; +use futures::{prelude::*, stream::FuturesUnordered}; use libp2p::{multiaddr, PeerId}; use log::{debug, trace, warn}; use prometheus_endpoint::{register, Counter, PrometheusError, Registry, U64}; @@ -40,6 +40,7 @@ use sc_network_common::{ utils::{interval, LruHashSet}, ExHashT, }; +use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; use sp_runtime::traits::Block as BlockT; use std::{ collections::{hash_map::Entry, HashMap}, @@ -168,7 +169,7 @@ impl TransactionsHandlerPrototype { metrics_registry: Option<&Registry>, ) -> error::Result<(TransactionsHandler, TransactionsHandlerController)> { let event_stream = service.event_stream("transactions-handler"); - let (to_handler, from_controller) = mpsc::unbounded(); + let (to_handler, from_controller) = tracing_unbounded("mpsc_transactions_handler", 100_000); let handler = TransactionsHandler { protocol_name: self.protocol_name, @@ -197,7 +198,7 @@ impl TransactionsHandlerPrototype { /// Controls the behaviour of a [`TransactionsHandler`] it is connected to. pub struct TransactionsHandlerController { - to_handler: mpsc::UnboundedSender>, + to_handler: TracingUnboundedSender>, } impl TransactionsHandlerController { @@ -246,7 +247,7 @@ pub struct TransactionsHandler< // All connected peers peers: HashMap>, transaction_pool: Arc>, - from_controller: mpsc::UnboundedReceiver>, + from_controller: TracingUnboundedReceiver>, /// Prometheus metrics. metrics: Option, } diff --git a/client/offchain/src/api/http.rs b/client/offchain/src/api/http.rs index 4c97e5a47058d..a47adb3e8026e 100644 --- a/client/offchain/src/api/http.rs +++ b/client/offchain/src/api/http.rs @@ -66,8 +66,8 @@ impl SharedClient { /// Creates a pair of [`HttpApi`] and [`HttpWorker`]. pub fn http(shared_client: SharedClient) -> (HttpApi, HttpWorker) { - let (to_worker, from_api) = tracing_unbounded("mpsc_ocw_to_worker"); - let (to_api, from_worker) = tracing_unbounded("mpsc_ocw_to_api"); + let (to_worker, from_api) = tracing_unbounded("mpsc_ocw_to_worker", 100_000); + let (to_api, from_worker) = tracing_unbounded("mpsc_ocw_to_api", 100_000); let api = HttpApi { to_worker, diff --git a/client/peerset/src/lib.rs b/client/peerset/src/lib.rs index ec09835c4898e..9b1dc6a2d0276 100644 --- a/client/peerset/src/lib.rs +++ b/client/peerset/src/lib.rs @@ -275,7 +275,7 @@ pub struct Peerset { impl Peerset { /// Builds a new peerset from the given configuration. pub fn from_config(config: PeersetConfig) -> (Self, PeersetHandle) { - let (tx, rx) = tracing_unbounded("mpsc_peerset_messages"); + let (tx, rx) = tracing_unbounded("mpsc_peerset_messages", 10_000); let handle = PeersetHandle { tx: tx.clone() }; diff --git a/client/rpc/src/system/tests.rs b/client/rpc/src/system/tests.rs index 00ab9c46861e2..4da49cdd1a0c5 100644 --- a/client/rpc/src/system/tests.rs +++ b/client/rpc/src/system/tests.rs @@ -52,7 +52,7 @@ impl Default for Status { 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"); + let (tx, rx) = tracing_unbounded("rpc_system_tests", 10_000); thread::spawn(move || { futures::executor::block_on(rx.for_each(move |request| { match request { diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index 0a26c00485e2f..1f94f96fae89e 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -962,7 +962,7 @@ where ); 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"); + let (system_rpc_tx, system_rpc_rx) = tracing_unbounded("mpsc_system_rpc", 10_000); let future = build_network_future( config.role.clone(), diff --git a/client/service/src/client/client.rs b/client/service/src/client/client.rs index 493fd320b7b23..78f2174b89eea 100644 --- a/client/service/src/client/client.rs +++ b/client/service/src/client/client.rs @@ -1913,13 +1913,13 @@ where { /// Get block import event stream. fn import_notification_stream(&self) -> ImportNotifications { - let (sink, stream) = tracing_unbounded("mpsc_import_notification_stream"); + let (sink, stream) = tracing_unbounded("mpsc_import_notification_stream", 100_000); self.import_notification_sinks.lock().push(sink); stream } fn finality_notification_stream(&self) -> FinalityNotifications { - let (sink, stream) = tracing_unbounded("mpsc_finality_notification_stream"); + let (sink, stream) = tracing_unbounded("mpsc_finality_notification_stream", 100_000); self.finality_notification_sinks.lock().push(sink); stream } diff --git a/client/service/src/task_manager/mod.rs b/client/service/src/task_manager/mod.rs index 49189dc21ce8d..23265f9672555 100644 --- a/client/service/src/task_manager/mod.rs +++ b/client/service/src/task_manager/mod.rs @@ -310,7 +310,8 @@ impl TaskManager { let (signal, on_exit) = exit_future::signal(); // A side-channel for essential tasks to communicate shutdown. - let (essential_failed_tx, essential_failed_rx) = tracing_unbounded("mpsc_essential_tasks"); + let (essential_failed_tx, essential_failed_rx) = + tracing_unbounded("mpsc_essential_tasks", 100); let metrics = prometheus_registry.map(Metrics::register).transpose()?; diff --git a/client/telemetry/Cargo.toml b/client/telemetry/Cargo.toml index 1fc89980e2de8..6ef69d1d97afd 100644 --- a/client/telemetry/Cargo.toml +++ b/client/telemetry/Cargo.toml @@ -20,6 +20,7 @@ libp2p = { version = "0.49.0", default-features = false, features = ["dns", "tcp log = "0.4.17" parking_lot = "0.12.1" pin-project = "1.0.12" +sc-utils = { version = "4.0.0-dev", path = "../utils" } rand = "0.8.5" serde = { version = "1.0.136", features = ["derive"] } serde_json = "1.0.85" diff --git a/client/telemetry/src/lib.rs b/client/telemetry/src/lib.rs index 503a326f76c2b..aa6b841b79164 100644 --- a/client/telemetry/src/lib.rs +++ b/client/telemetry/src/lib.rs @@ -40,6 +40,7 @@ use futures::{channel::mpsc, prelude::*}; use libp2p::Multiaddr; use log::{error, warn}; use parking_lot::Mutex; +use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; use serde::Serialize; use std::{ collections::{ @@ -147,8 +148,8 @@ pub struct SysInfo { pub struct TelemetryWorker { message_receiver: mpsc::Receiver, message_sender: mpsc::Sender, - register_receiver: mpsc::UnboundedReceiver, - register_sender: mpsc::UnboundedSender, + register_receiver: TracingUnboundedReceiver, + register_sender: TracingUnboundedSender, id_counter: Arc, } @@ -163,7 +164,8 @@ impl TelemetryWorker { // 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(); + let (register_sender, register_receiver) = + tracing_unbounded("mpsc_telemetry_register", 10_000); Ok(Self { message_receiver, @@ -360,7 +362,7 @@ impl TelemetryWorker { #[derive(Debug, Clone)] pub struct TelemetryWorkerHandle { message_sender: mpsc::Sender, - register_sender: mpsc::UnboundedSender, + register_sender: TracingUnboundedSender, id_counter: Arc, } @@ -386,7 +388,7 @@ impl TelemetryWorkerHandle { #[derive(Debug)] pub struct Telemetry { message_sender: mpsc::Sender, - register_sender: mpsc::UnboundedSender, + register_sender: TracingUnboundedSender, id: Id, connection_notifier: TelemetryConnectionNotifier, endpoints: Option, @@ -460,7 +462,7 @@ impl TelemetryHandle { /// (re-)establishes. #[derive(Clone, Debug)] pub struct TelemetryConnectionNotifier { - register_sender: mpsc::UnboundedSender, + register_sender: TracingUnboundedSender, addresses: Vec, } diff --git a/client/transaction-pool/src/graph/watcher.rs b/client/transaction-pool/src/graph/watcher.rs index 0613300c8684b..df5bb94edfe6d 100644 --- a/client/transaction-pool/src/graph/watcher.rs +++ b/client/transaction-pool/src/graph/watcher.rs @@ -62,7 +62,7 @@ impl Default for Sender { impl Sender { /// Add a new watcher to this sender object. pub fn new_watcher(&mut self, hash: H) -> Watcher { - let (tx, receiver) = tracing_unbounded("mpsc_txpool_watcher"); + let (tx, receiver) = tracing_unbounded("mpsc_txpool_watcher", 100_000); self.receivers.push(tx); Watcher { receiver, hash } } diff --git a/client/transaction-pool/src/revalidation.rs b/client/transaction-pool/src/revalidation.rs index b4b4299240a32..d8c8bea625fb3 100644 --- a/client/transaction-pool/src/revalidation.rs +++ b/client/transaction-pool/src/revalidation.rs @@ -291,7 +291,7 @@ where pool: Arc>, interval: Duration, ) -> (Self, Pin + Send>>) { - let (to_worker, from_queue) = tracing_unbounded("mpsc_revalidation_queue"); + let (to_worker, from_queue) = tracing_unbounded("mpsc_revalidation_queue", 100_000); let worker = RevalidationWorker::new(api.clone(), pool.clone()); diff --git a/client/utils/src/mpsc.rs b/client/utils/src/mpsc.rs index ee3fba4a5ee67..7db5e49f5bca9 100644 --- a/client/utils/src/mpsc.rs +++ b/client/utils/src/mpsc.rs @@ -45,71 +45,136 @@ mod inner { stream::{FusedStream, Stream}, task::{Context, Poll}, }; - use std::pin::Pin; + use log::error; + use std::{ + backtrace::{Backtrace, BacktraceStatus}, + pin::Pin, + sync::{ + atomic::{AtomicBool, AtomicI64, Ordering}, + Arc, + }, + }; /// Wrapper Type around `UnboundedSender` that increases the global /// measure when a message is added #[derive(Debug)] - pub struct TracingUnboundedSender(&'static str, UnboundedSender); + pub struct TracingUnboundedSender { + inner: UnboundedSender, + name: &'static str, + // To not bother with ordering and possible underflow errors of the unsigned counter + // we just use `i64` and `Ordering::Relaxed`, and perceive `queue_size` as approximate. + // It can turn < 0 though. + queue_size: Arc, + queue_size_warning: i64, + warning_fired: Arc, + creation_backtrace: Arc, + } // Strangely, deriving `Clone` requires that `T` is also `Clone`. impl Clone for TracingUnboundedSender { fn clone(&self) -> Self { - Self(self.0, self.1.clone()) + Self { + inner: self.inner.clone(), + name: self.name, + queue_size: self.queue_size.clone(), + queue_size_warning: self.queue_size_warning, + warning_fired: self.warning_fired.clone(), + creation_backtrace: self.creation_backtrace.clone(), + } } } /// Wrapper Type around `UnboundedReceiver` that decreases the global /// measure when a message is polled #[derive(Debug)] - pub struct TracingUnboundedReceiver(&'static str, UnboundedReceiver); + pub struct TracingUnboundedReceiver { + inner: UnboundedReceiver, + name: &'static str, + queue_size: Arc, + } /// Wrapper around `mpsc::unbounded` that tracks the in- and outflow via - /// `UNBOUNDED_CHANNELS_COUNTER` + /// `UNBOUNDED_CHANNELS_COUNTER` and warns if the message queue grows + /// above the warning threshold. pub fn tracing_unbounded( - key: &'static str, + name: &'static str, + queue_size_warning: i64, ) -> (TracingUnboundedSender, TracingUnboundedReceiver) { let (s, r) = mpsc::unbounded(); - (TracingUnboundedSender(key, s), TracingUnboundedReceiver(key, r)) + let queue_size = Arc::new(AtomicI64::new(0)); + let sender = TracingUnboundedSender { + inner: s, + name, + queue_size: queue_size.clone(), + queue_size_warning, + warning_fired: Arc::new(AtomicBool::new(false)), + creation_backtrace: Arc::new(Backtrace::capture()), + }; + let receiver = TracingUnboundedReceiver { inner: r, name, queue_size }; + (sender, receiver) } impl TracingUnboundedSender { /// Proxy function to mpsc::UnboundedSender pub fn poll_ready(&self, ctx: &mut Context) -> Poll> { - self.1.poll_ready(ctx) + self.inner.poll_ready(ctx) } /// Proxy function to mpsc::UnboundedSender pub fn is_closed(&self) -> bool { - self.1.is_closed() + self.inner.is_closed() } /// Proxy function to mpsc::UnboundedSender pub fn close_channel(&self) { - self.1.close_channel() + self.inner.close_channel() } /// Proxy function to mpsc::UnboundedSender pub fn disconnect(&mut self) { - self.1.disconnect() + self.inner.disconnect() } - /// Proxy function to mpsc::UnboundedSender pub fn start_send(&mut self, msg: T) -> Result<(), SendError> { - self.1.start_send(msg) + // The underlying implementation of [`UnboundedSender::start_send`] is the same as + // [`UnboundedSender::unbounded_send`], so we just reuse the message counting and + // error reporting code from `unbounded_send`. + self.unbounded_send(msg).map_err(TrySendError::into_send_error) } /// Proxy function to mpsc::UnboundedSender pub fn unbounded_send(&self, msg: T) -> Result<(), TrySendError> { - self.1.unbounded_send(msg).map(|s| { - UNBOUNDED_CHANNELS_COUNTER.with_label_values(&[self.0, "send"]).inc(); + self.inner.unbounded_send(msg).map(|s| { + UNBOUNDED_CHANNELS_COUNTER.with_label_values(&[self.name, "send"]).inc(); + + let queue_size = self.queue_size.fetch_add(1, Ordering::Relaxed); + if queue_size == self.queue_size_warning && + !self.warning_fired.load(Ordering::Relaxed) + { + // `warning_fired` and `queue_size` are not synchronized, so it's possible + // that the warning is fired few times before the `warning_fired` is seen + // by all threads. This seems better than introducing a mutex guarding them. + self.warning_fired.store(true, Ordering::Relaxed); + match self.creation_backtrace.status() { + BacktraceStatus::Captured => error!( + "The number of unprocessed messages in channel `{}` reached {}.\n\ + The channel was created at:\n{}", + self.name, self.queue_size_warning, self.creation_backtrace, + ), + _ => error!( + "The number of unprocessed messages in channel `{}` reached {}.", + self.name, self.queue_size_warning, + ), + } + } + s }) } /// Proxy function to mpsc::UnboundedSender pub fn same_receiver(&self, other: &UnboundedSender) -> bool { - self.1.same_receiver(other) + self.inner.same_receiver(other) } } @@ -118,7 +183,7 @@ mod inner { // consume all items, make sure to reflect the updated count let mut count = 0; loop { - if self.1.is_terminated() { + if self.inner.is_terminated() { break } @@ -129,7 +194,9 @@ mod inner { } // and discount the messages if count > 0 { - UNBOUNDED_CHANNELS_COUNTER.with_label_values(&[self.0, "dropped"]).inc_by(count); + UNBOUNDED_CHANNELS_COUNTER + .with_label_values(&[self.name, "dropped"]) + .inc_by(count); } } @@ -137,15 +204,16 @@ mod inner { /// that consumes all messages first and updates the counter pub fn close(&mut self) { self.consume(); - self.1.close() + self.inner.close() } /// Proxy function to mpsc::UnboundedReceiver /// that discounts the messages taken out pub fn try_next(&mut self) -> Result, TryRecvError> { - self.1.try_next().map(|s| { + self.inner.try_next().map(|s| { if s.is_some() { - UNBOUNDED_CHANNELS_COUNTER.with_label_values(&[self.0, "received"]).inc(); + let _ = self.queue_size.fetch_sub(1, Ordering::Relaxed); + UNBOUNDED_CHANNELS_COUNTER.with_label_values(&[self.name, "received"]).inc(); } s }) @@ -165,10 +233,11 @@ mod inner { fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { let s = self.get_mut(); - match Pin::new(&mut s.1).poll_next(cx) { + match Pin::new(&mut s.inner).poll_next(cx) { Poll::Ready(msg) => { if msg.is_some() { - UNBOUNDED_CHANNELS_COUNTER.with_label_values(&[s.0, "received"]).inc(); + let _ = s.queue_size.fetch_sub(1, Ordering::Relaxed); + UNBOUNDED_CHANNELS_COUNTER.with_label_values(&[s.name, "received"]).inc(); } Poll::Ready(msg) }, @@ -179,7 +248,7 @@ mod inner { impl FusedStream for TracingUnboundedReceiver { fn is_terminated(&self) -> bool { - self.1.is_terminated() + self.inner.is_terminated() } } @@ -223,6 +292,10 @@ mod inner { } fn poll_close(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { + // The difference with `TracingUnboundedSender` is intentional. The underlying + // implementation differs for `UnboundedSender` and `&UnboundedSender`: + // the latter closes the channel completely with `close_channel()`, while the former + // only closes this specific sender with `disconnect()`. self.close_channel(); Poll::Ready(Ok(())) } diff --git a/client/utils/src/notification.rs b/client/utils/src/notification.rs index ff527c343f9f2..4917a43265df4 100644 --- a/client/utils/src/notification.rs +++ b/client/utils/src/notification.rs @@ -79,8 +79,8 @@ impl NotificationStream { } /// Subscribe to a channel through which the generic payload can be received. - pub fn subscribe(&self) -> NotificationReceiver { - let receiver = self.hub.subscribe(()); + pub fn subscribe(&self, queue_size_warning: i64) -> NotificationReceiver { + let receiver = self.hub.subscribe((), queue_size_warning); NotificationReceiver { receiver } } } diff --git a/client/utils/src/notification/tests.rs b/client/utils/src/notification/tests.rs index a001fa7e89e95..f813f37d29ddb 100644 --- a/client/utils/src/notification/tests.rs +++ b/client/utils/src/notification/tests.rs @@ -36,7 +36,7 @@ fn notification_channel_simple() { // 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 future = stream.subscribe(100_000).take(1).for_each(move |payload| { let test_payload = closure_payload.clone(); async move { assert_eq!(payload, test_payload); diff --git a/client/utils/src/pubsub.rs b/client/utils/src/pubsub.rs index ba6e9ddc6ca2a..f85f44b498841 100644 --- a/client/utils/src/pubsub.rs +++ b/client/utils/src/pubsub.rs @@ -164,7 +164,7 @@ impl Hub { /// 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 + pub fn subscribe(&self, subs_key: K, queue_size_warning: i64) -> Receiver where R: Subscribe + Unsubscribe, { @@ -178,7 +178,7 @@ impl Hub { // have the sink disposed. shared_borrowed.registry.subscribe(subs_key, subs_id); - let (tx, rx) = crate::mpsc::tracing_unbounded(self.tracing_key); + let (tx, rx) = crate::mpsc::tracing_unbounded(self.tracing_key, queue_size_warning); 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 } diff --git a/client/utils/src/pubsub/tests/normal_operation.rs b/client/utils/src/pubsub/tests/normal_operation.rs index a13c718d74a8f..830388de32e46 100644 --- a/client/utils/src/pubsub/tests/normal_operation.rs +++ b/client/utils/src/pubsub/tests/normal_operation.rs @@ -27,7 +27,7 @@ fn positive_rx_receives_relevant_messages_and_terminates_upon_hub_drop() { // No subscribers yet. That message is not supposed to get to anyone. hub.send(0); - let mut rx_01 = hub.subscribe(SubsKey::new()); + let mut rx_01 = hub.subscribe(SubsKey::new(), 100_000); assert_eq!(hub.subs_count(), 1); // That message is sent after subscription. Should be delivered into rx_01. @@ -49,9 +49,9 @@ fn positive_subs_count_is_correct_upon_drop_of_rxs() { let hub = TestHub::new(TK); assert_eq!(hub.subs_count(), 0); - let rx_01 = hub.subscribe(SubsKey::new()); + let rx_01 = hub.subscribe(SubsKey::new(), 100_000); assert_eq!(hub.subs_count(), 1); - let rx_02 = hub.subscribe(SubsKey::new()); + let rx_02 = hub.subscribe(SubsKey::new(), 100_000); assert_eq!(hub.subs_count(), 2); std::mem::drop(rx_01); @@ -69,11 +69,11 @@ fn positive_subs_count_is_correct_upon_drop_of_rxs_on_cloned_hubs() { assert_eq!(hub_01.subs_count(), 0); assert_eq!(hub_02.subs_count(), 0); - let rx_01 = hub_02.subscribe(SubsKey::new()); + let rx_01 = hub_02.subscribe(SubsKey::new(), 100_000); assert_eq!(hub_01.subs_count(), 1); assert_eq!(hub_02.subs_count(), 1); - let rx_02 = hub_02.subscribe(SubsKey::new()); + let rx_02 = hub_02.subscribe(SubsKey::new(), 100_000); assert_eq!(hub_01.subs_count(), 2); assert_eq!(hub_02.subs_count(), 2); diff --git a/client/utils/src/pubsub/tests/panicking_registry.rs b/client/utils/src/pubsub/tests/panicking_registry.rs index 26ce63bd51b01..cfe8168d80229 100644 --- a/client/utils/src/pubsub/tests/panicking_registry.rs +++ b/client/utils/src/pubsub/tests/panicking_registry.rs @@ -30,7 +30,7 @@ fn t01() { let hub = TestHub::new(TK); assert_hub_props(&hub, 0, 0); - let rx_01 = hub.subscribe(SubsKey::new()); + let rx_01 = hub.subscribe(SubsKey::new(), 100_000); assert_hub_props(&hub, 1, 1); std::mem::drop(rx_01); @@ -45,17 +45,17 @@ fn t02() { assert_hub_props(&hub, 0, 0); // Subscribe rx-01 - let rx_01 = hub.subscribe(SubsKey::new()); + let rx_01 = hub.subscribe(SubsKey::new(), 100_000); 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)); + let rx_02 = hub.subscribe(SubsKey::new().with_receiver(rx_01), 100_000); 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()); + let mut rx_03 = hub.subscribe(SubsKey::new(), 100_000); assert_hub_props(&hub, 3, 3); // drop rx-02 leads to an attempt to unsubscribe rx-01 @@ -69,7 +69,7 @@ fn t02() { // Subscribe rx-04 in order to see that it will receive messages after the unclean // unsubscription - let mut rx_04 = hub.subscribe(SubsKey::new()); + let mut rx_04 = hub.subscribe(SubsKey::new(), 100_000); assert_hub_props(&hub, 3, 3); hub.send(2); @@ -96,8 +96,8 @@ fn t02() { } 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()); + let rx_01 = hub.subscribe(SubsKey::new(), 100_000); + let rx_02 = hub.subscribe(SubsKey::new(), 100_000); hub.send(1); hub.send(2); @@ -121,9 +121,8 @@ fn t03() { 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)) - )) + assert!(catch_unwind(AssertUnwindSafe(|| hub + .subscribe(SubsKey::new().with_panic(SubsKeyPanic::OnSubscribePanicBefore), 100_000))) .is_err()); assert_hub_props(&hub, 0, 0); @@ -141,9 +140,8 @@ fn t04() { 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)) - )) + assert!(catch_unwind(AssertUnwindSafe(|| hub + .subscribe(SubsKey::new().with_panic(SubsKeyPanic::OnSubscribePanicAfter), 100_000))) .is_err()); // the registry has panicked after it has added a subs-id into its internal storage — the @@ -163,8 +161,8 @@ fn t05() { 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)); + let rx_01 = hub + .subscribe(SubsKey::new().with_panic(SubsKeyPanic::OnUnsubscribePanicBefore), 100_000); assert_hub_props(&hub, 1, 1); add_some_subscribers_see_that_messages_are_delivered_and_unsubscribe(&hub).await; @@ -189,7 +187,8 @@ fn t06() { 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)); + let rx_01 = hub + .subscribe(SubsKey::new().with_panic(SubsKeyPanic::OnUnsubscribePanicAfter), 100_000); assert_hub_props(&hub, 1, 1); add_some_subscribers_see_that_messages_are_delivered_and_unsubscribe(&hub).await; @@ -214,7 +213,8 @@ fn t07() { 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)); + let rx_01 = + hub.subscribe(SubsKey::new().with_panic(SubsKeyPanic::OnDispatchPanicBefore), 100_000); assert_hub_props(&hub, 1, 1); assert!(catch_unwind(AssertUnwindSafe(|| hub.send(1))).is_err()); assert_hub_props(&hub, 1, 1); @@ -235,7 +235,8 @@ fn t08() { 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)); + let rx_01 = + hub.subscribe(SubsKey::new().with_panic(SubsKeyPanic::OnDispatchPanicAfter), 100_000); assert_hub_props(&hub, 1, 1); assert!(catch_unwind(AssertUnwindSafe(|| hub.send(1))).is_err()); assert_hub_props(&hub, 1, 1); diff --git a/client/utils/src/status_sinks.rs b/client/utils/src/status_sinks.rs index a1d965d08085e..c536e2c18c6a1 100644 --- a/client/utils/src/status_sinks.rs +++ b/client/utils/src/status_sinks.rs @@ -58,7 +58,7 @@ impl Default for StatusSinks { impl StatusSinks { /// Builds a new empty collection. pub fn new() -> StatusSinks { - let (entries_tx, entries_rx) = tracing_unbounded("status-sinks-entries"); + let (entries_tx, entries_rx) = tracing_unbounded("status-sinks-entries", 100_000); StatusSinks { inner: Mutex::new(Inner { entries: stream::FuturesUnordered::new(), entries_rx }), @@ -196,7 +196,7 @@ mod tests { let status_sinks = StatusSinks::new(); - let (tx, rx) = tracing_unbounded("test"); + let (tx, rx) = tracing_unbounded("test", 100_000); status_sinks.push(Duration::from_millis(100), tx); let mut val_order = 5; From c7f5df2c160e8d836285127a60bbf7793b7067ba Mon Sep 17 00:00:00 2001 From: Jegor Sidorenko <5252494+jsidorenko@users.noreply.github.com> Date: Fri, 23 Dec 2022 18:07:27 +0200 Subject: [PATCH 226/715] NFTs 2.0 (#12765) * Copy Uniques into Nfts * Connect new pallet * Update weights * Nfts: Multiple approvals (#12178) * multiple approvals * clear * tests & clean up * fix in logic & fmt * fix benchmarks * deadline * test deadline * current_block + deadline * update ApprovedTransfer event * benchmark * docs * Update frame/nfts/src/lib.rs Co-authored-by: Jegor Sidorenko <5252494+jsidorenko@users.noreply.github.com> * fmt fix * Update frame/nfts/src/lib.rs Co-authored-by: Jegor Sidorenko <5252494+jsidorenko@users.noreply.github.com> * update tests * anyone can cancel * Update frame/nfts/src/tests.rs Co-authored-by: Jegor Sidorenko <5252494+jsidorenko@users.noreply.github.com> * fmt * fix logic * unnecessary line * ".git/.scripts/bench-bot.sh" pallet dev pallet_nfts * Update frame/nfts/src/lib.rs * Update lib.rs * fmt * Update frame/nfts/src/lib.rs Co-authored-by: Squirrel * Update frame/nfts/src/lib.rs Co-authored-by: Squirrel * fmt * Update frame/nfts/src/lib.rs Co-authored-by: Squirrel * suggestion * new line * ".git/.scripts/bench-bot.sh" pallet dev pallet_nfts Co-authored-by: Jegor Sidorenko <5252494+jsidorenko@users.noreply.github.com> Co-authored-by: command-bot <> Co-authored-by: Squirrel * Fixes * cargo fmt * Fixes * Fixes * Fix CI * Nfts: Fix Auto-Increment (#12223) * commit * passing benchmarks * clean up * sync * runtime implementation * fix * fmt * fix benchmark * cfg * remove try-increment-id * remove unused error * impl Incrementable for unsigned types * clean up * fix in tests * not needed anymore * Use OptionQuery Co-authored-by: Keith Yeung * Rename Origin to RuntimeOrigin * [Uniques V2] Tips (#12168) * Allow to add tips when buying an NFT * Chore * Rework tips feature * Add weights + benchmarks * Convert tuple to struct * Fix benchmark * ".git/.scripts/bench-bot.sh" pallet dev pallet_nfts * Update frame/nfts/src/benchmarking.rs Co-authored-by: Oliver Tale-Yazdi * Fix benchmarks * Revert the bounded_vec![] approach * ".git/.scripts/bench-bot.sh" pallet dev pallet_nfts Co-authored-by: command-bot <> Co-authored-by: Oliver Tale-Yazdi * [Uniques V2] Atomic NFTs swap (#12285) * Atomic NFTs swap * Fmt * Fix benchmark * Rename swap -> atomic_swap * Update target balance * Rollback * Fix * ".git/.scripts/bench-bot.sh" pallet dev pallet_nfts * Make desired item optional * Apply suggestions * Update frame/nfts/src/features/atomic_swap.rs Co-authored-by: Squirrel * Rename fields * Optimisation * Add a comment * deadline -> maybe_deadline * Add docs * Change comments * Add price direction field * ".git/.scripts/bench-bot.sh" pallet dev pallet_nfts * Wrap price and direction * Fix benchmarks * Use ensure! instead of if {} * Make duration param mandatory and limit it to MaxDeadlineDuration * Make the code safer * Fix clippy * Chore * Remove unused vars * try * try 2 * try 3 Co-authored-by: command-bot <> Co-authored-by: Squirrel * [Uniques V2] Feature flags (#12367) * Basics * WIP: change the data format * Refactor * Remove redundant new() method * Rename settings * Enable tests * Chore * Change params order * Delete the config on collection removal * Chore * Remove redundant system features * Rename force_item_status to force_collection_status * Update node runtime * Chore * Remove thaw_collection * Chore * Connect collection.is_frozen to config * Allow to lock the collection in a new way * Move free_holding into settings * Connect collection's metadata locker to feature flags * DRY * Chore * Connect pallet level feature flags * Prepare tests for the new changes * Implement Item settings * Allow to lock the metadata or attributes of an item * Common -> Settings * Extract settings related code to a separate file * Move feature flag checks inside the do_* methods * Split settings.rs into parts * Extract repeated code into macro * Extract macros into their own file * Chore * Fix traits * Fix traits * Test SystemFeatures * Fix benchmarks * Add missing benchmark * Fix node/runtime/lib.rs * ".git/.scripts/bench-bot.sh" pallet dev pallet_nfts * Keep item's config on burn if it's not empty * Fix the merge artifacts * Fmt * Add SystemFeature::NoSwaps check * Rename SystemFeatures to PalletFeatures * Rename errors * Add docs * Change error message * Rework pallet features * Move macros * Change comments * Fmt * Refactor Incrementable * Use pub(crate) for do_* functions * Update comments * Refactor freeze and lock functions * Rework Collection config and Item confg api * Chore * Make clippy happy * Chore * Update comment * RequiredDeposit => DepositRequired * Address comments Co-authored-by: command-bot <> * [Uniques V2] Refactor roles (#12437) * Basics * WIP: change the data format * Refactor * Remove redundant new() method * Rename settings * Enable tests * Chore * Change params order * Delete the config on collection removal * Chore * Remove redundant system features * Rename force_item_status to force_collection_status * Update node runtime * Chore * Remove thaw_collection * Chore * Connect collection.is_frozen to config * Allow to lock the collection in a new way * Move free_holding into settings * Connect collection's metadata locker to feature flags * DRY * Chore * Connect pallet level feature flags * Prepare tests for the new changes * Implement Item settings * Allow to lock the metadata or attributes of an item * Common -> Settings * Extract settings related code to a separate file * Move feature flag checks inside the do_* methods * Split settings.rs into parts * Extract repeated code into macro * Extract macros into their own file * Chore * Fix traits * Fix traits * Test SystemFeatures * Fix benchmarks * Add missing benchmark * Fix node/runtime/lib.rs * ".git/.scripts/bench-bot.sh" pallet dev pallet_nfts * Keep item's config on burn if it's not empty * Fix the merge artifacts * Fmt * Add SystemFeature::NoSwaps check * Refactor roles structure * Rename SystemFeatures to PalletFeatures * Rename errors * Add docs * Change error message * Rework pallet features * Move macros * Change comments * Fmt * Refactor Incrementable * Use pub(crate) for do_* functions * Update comments * Refactor freeze and lock functions * Rework Collection config and Item confg api * Chore * Make clippy happy * Chore * Fix artifacts * Address comments * Further refactoring * Add comments * Add tests for group_roles_by_account() * Update frame/nfts/src/impl_nonfungibles.rs * Add test * Replace Itertools group_by with a custom implementation * ItemsNotTransferable => ItemsNonTransferable * Update frame/nfts/src/features/roles.rs Co-authored-by: Muharem Ismailov * Address PR comments * Add missed comment Co-authored-by: command-bot <> Co-authored-by: Muharem Ismailov * Fix copy * Remove storage_prefix * Remove transactional * Update comment * [Uniques V2] Minting options (#12483) * Basics * WIP: change the data format * Refactor * Remove redundant new() method * Rename settings * Enable tests * Chore * Change params order * Delete the config on collection removal * Chore * Remove redundant system features * Rename force_item_status to force_collection_status * Update node runtime * Chore * Remove thaw_collection * Chore * Connect collection.is_frozen to config * Allow to lock the collection in a new way * Move free_holding into settings * Connect collection's metadata locker to feature flags * DRY * Chore * Connect pallet level feature flags * Prepare tests for the new changes * Implement Item settings * Allow to lock the metadata or attributes of an item * Common -> Settings * Extract settings related code to a separate file * Move feature flag checks inside the do_* methods * Split settings.rs into parts * Extract repeated code into macro * Extract macros into their own file * Chore * Fix traits * Fix traits * Test SystemFeatures * Fix benchmarks * Add missing benchmark * Fix node/runtime/lib.rs * ".git/.scripts/bench-bot.sh" pallet dev pallet_nfts * Keep item's config on burn if it's not empty * Fix the merge artifacts * Fmt * Add SystemFeature::NoSwaps check * Rename SystemFeatures to PalletFeatures * Rename errors * Add docs * Change error message * Change the format of CollectionConfig to store more data * Move max supply to the CollectionConfig and allow to change it * Remove ItemConfig from the mint() function and use the one set in mint settings * Add different mint options * Allow to change the mint settings * Add a force_mint() method * Check mint params * Some optimisations * Cover with tests * Remove merge artifacts * Chore * Use the new has_role() method * Rework item deposits * More tests * Refactoring * Address comments * Refactor lock_collection() * Update frame/nfts/src/types.rs Co-authored-by: Squirrel * Update frame/nfts/src/types.rs Co-authored-by: Squirrel * Update frame/nfts/src/lib.rs Co-authored-by: Squirrel * Update frame/nfts/src/lib.rs Co-authored-by: Squirrel * Private => Issuer * Add more tests * Fix benchmarks * Add benchmarks for new methods * [Uniques v2] Refactoring (#12570) * Move do_set_price() and do_buy_item() to buy_sell.rs * Move approvals to feature file * Move metadata to feature files * Move the rest of methods to feature files * Remove artifacts * Split force_collection_status into 2 methods * Fix benchmarks * Fix benchmarks * Update deps Co-authored-by: command-bot <> Co-authored-by: Squirrel * [Uniques V2] Smart attributes (#12702) * Basics * WIP: change the data format * Refactor * Remove redundant new() method * Rename settings * Enable tests * Chore * Change params order * Delete the config on collection removal * Chore * Remove redundant system features * Rename force_item_status to force_collection_status * Update node runtime * Chore * Remove thaw_collection * Chore * Connect collection.is_frozen to config * Allow to lock the collection in a new way * Move free_holding into settings * Connect collection's metadata locker to feature flags * DRY * Chore * Connect pallet level feature flags * Prepare tests for the new changes * Implement Item settings * Allow to lock the metadata or attributes of an item * Common -> Settings * Extract settings related code to a separate file * Move feature flag checks inside the do_* methods * Split settings.rs into parts * Extract repeated code into macro * Extract macros into their own file * Chore * Fix traits * Fix traits * Test SystemFeatures * Fix benchmarks * Add missing benchmark * Fix node/runtime/lib.rs * ".git/.scripts/bench-bot.sh" pallet dev pallet_nfts * Keep item's config on burn if it's not empty * Fix the merge artifacts * Fmt * Add SystemFeature::NoSwaps check * Rename SystemFeatures to PalletFeatures * Rename errors * Add docs * Change error message * Change the format of CollectionConfig to store more data * Move max supply to the CollectionConfig and allow to change it * Remove ItemConfig from the mint() function and use the one set in mint settings * Add different mint options * Allow to change the mint settings * Add a force_mint() method * Check mint params * Some optimisations * Cover with tests * Remove merge artifacts * Chore * Use the new has_role() method * Rework item deposits * More tests * Refactoring * Address comments * Refactor lock_collection() * Update frame/nfts/src/types.rs Co-authored-by: Squirrel * Update frame/nfts/src/types.rs Co-authored-by: Squirrel * Update frame/nfts/src/lib.rs Co-authored-by: Squirrel * Update frame/nfts/src/lib.rs Co-authored-by: Squirrel * Private => Issuer * Add more tests * Fix benchmarks * Add benchmarks for new methods * [Uniques v2] Refactoring (#12570) * Move do_set_price() and do_buy_item() to buy_sell.rs * Move approvals to feature file * Move metadata to feature files * Move the rest of methods to feature files * Remove artifacts * Smart attributes * Split force_collection_status into 2 methods * Fix benchmarks * Fix benchmarks * Update deps * Fix merge artifact * Weights + benchmarks + docs * Change params order * Chore * Update frame/nfts/src/lib.rs Co-authored-by: Squirrel * Update frame/nfts/src/lib.rs Co-authored-by: Squirrel * Update docs * Update frame/nfts/src/lib.rs Co-authored-by: Squirrel * Add PalletId * Chore * Add tests * More tests * Add doc * Update errors snapshots * Ensure we track the owner_deposit field correctly Co-authored-by: command-bot <> Co-authored-by: Squirrel * [Uniques V2] Final improvements (#12736) * Use KeyPrefixIterator instead of Box * Change create_collection() * Restrict from claiming NFTs twice * Update Readme * Remove dead code * Refactoring * Update readme * Fix clippy * Update frame/nfts/src/lib.rs Co-authored-by: Squirrel * ".git/.scripts/bench-bot.sh" pallet dev pallet_nfts * Update docs * Typo * Fix benchmarks * Add more docs * DepositRequired setting should affect only the attributes within the CollectionOwner namespace * [NFTs] Implement missed methods to set the attributes from other pallets (#12919) * Implement missed methods to set the attributes from other pallets * Revert snapshots * Update snapshot * Update snapshot * Revert snapshot changes * Update snapshots * Yet another snapshot update.. * Update frame/support/src/traits/tokens/nonfungible_v2.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Update frame/support/src/traits/tokens/nonfungible_v2.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Update frame/support/src/traits/tokens/nonfungible_v2.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Update frame/support/src/traits/tokens/nonfungibles_v2.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Update frame/nfts/src/lib.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Update frame/nfts/src/lib.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Update frame/nfts/src/lib.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Update frame/nfts/src/lib.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Update frame/nfts/src/lib.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Update frame/support/src/traits/tokens/nonfungible_v2.rs * Update frame/nfts/src/lib.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Update frame/support/src/traits/tokens/nonfungibles_v2.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Update frame/nfts/src/lib.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Update frame/nfts/src/lib.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Update frame/nfts/src/lib.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Update frame/nfts/src/lib.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Address comments * [NFTs] Add the new `owner` param to mint() method (#12997) * Add the new `owner` param to mint() method * Fmt * Address comments * ".git/.scripts/bench-bot.sh" pallet dev pallet_nfts * Update frame/nfts/src/common_functions.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Update frame/nfts/src/types.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Update frame/nfts/src/types.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Update frame/nfts/src/types.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Update frame/nfts/src/types.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Update frame/nfts/src/types.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Add call indexes * Update snapshots Co-authored-by: Sergej Sakac <73715684+Szegoo@users.noreply.github.com> Co-authored-by: Squirrel Co-authored-by: Keith Yeung Co-authored-by: Oliver Tale-Yazdi Co-authored-by: Muharem Ismailov Co-authored-by: command-bot <> Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> --- Cargo.lock | 23 +- Cargo.toml | 1 + bin/node/runtime/Cargo.toml | 4 + bin/node/runtime/src/lib.rs | 38 + frame/nfts/Cargo.toml | 49 + frame/nfts/README.md | 106 + frame/nfts/src/benchmarking.rs | 718 +++++ frame/nfts/src/common_functions.rs | 42 + frame/nfts/src/features/approvals.rs | 132 + frame/nfts/src/features/atomic_swap.rs | 184 ++ frame/nfts/src/features/attributes.rs | 323 +++ frame/nfts/src/features/buy_sell.rs | 130 + .../src/features/create_delete_collection.rs | 118 + frame/nfts/src/features/create_delete_item.rs | 126 + frame/nfts/src/features/lock.rs | 120 + frame/nfts/src/features/metadata.rs | 173 ++ frame/nfts/src/features/mod.rs | 28 + frame/nfts/src/features/roles.rs | 99 + frame/nfts/src/features/settings.rs | 103 + frame/nfts/src/features/transfer.rs | 166 ++ frame/nfts/src/impl_nonfungibles.rs | 289 ++ frame/nfts/src/lib.rs | 1769 ++++++++++++ frame/nfts/src/macros.rs | 74 + frame/nfts/src/mock.rs | 123 + frame/nfts/src/tests.rs | 2484 +++++++++++++++++ frame/nfts/src/types.rs | 465 +++ frame/nfts/src/weights.rs | 851 ++++++ frame/support/src/traits/tokens.rs | 6 +- frame/support/src/traits/tokens/misc.rs | 15 + .../src/traits/tokens/nonfungible_v2.rs | 248 ++ .../src/traits/tokens/nonfungibles_v2.rs | 257 ++ ...ev_mode_without_arg_max_encoded_len.stderr | 2 +- ...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 +- 36 files changed, 9269 insertions(+), 13 deletions(-) create mode 100644 frame/nfts/Cargo.toml create mode 100644 frame/nfts/README.md create mode 100644 frame/nfts/src/benchmarking.rs create mode 100644 frame/nfts/src/common_functions.rs create mode 100644 frame/nfts/src/features/approvals.rs create mode 100644 frame/nfts/src/features/atomic_swap.rs create mode 100644 frame/nfts/src/features/attributes.rs create mode 100644 frame/nfts/src/features/buy_sell.rs create mode 100644 frame/nfts/src/features/create_delete_collection.rs create mode 100644 frame/nfts/src/features/create_delete_item.rs create mode 100644 frame/nfts/src/features/lock.rs create mode 100644 frame/nfts/src/features/metadata.rs create mode 100644 frame/nfts/src/features/mod.rs create mode 100644 frame/nfts/src/features/roles.rs create mode 100644 frame/nfts/src/features/settings.rs create mode 100644 frame/nfts/src/features/transfer.rs create mode 100644 frame/nfts/src/impl_nonfungibles.rs create mode 100644 frame/nfts/src/lib.rs create mode 100644 frame/nfts/src/macros.rs create mode 100644 frame/nfts/src/mock.rs create mode 100644 frame/nfts/src/tests.rs create mode 100644 frame/nfts/src/types.rs create mode 100644 frame/nfts/src/weights.rs create mode 100644 frame/support/src/traits/tokens/nonfungible_v2.rs create mode 100644 frame/support/src/traits/tokens/nonfungibles_v2.rs diff --git a/Cargo.lock b/Cargo.lock index c4bd2532e8ede..19abb44e5ff9c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1640,9 +1640,9 @@ dependencies = [ [[package]] name = "enumflags2" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b3ab37dc79652c9d85f1f7b6070d77d321d2467f5fe7b00d6b7a86c57b092ae" +checksum = "e75d4cd21b95383444831539909fbb14b9dc3fdceb2a6f5d36577329a1f55ccb" dependencies = [ "enumflags2_derive", ] @@ -3093,6 +3093,7 @@ dependencies = [ "pallet-message-queue", "pallet-mmr", "pallet-multisig", + "pallet-nfts", "pallet-nis", "pallet-nomination-pools", "pallet-nomination-pools-benchmarking", @@ -5378,6 +5379,24 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-nfts" +version = "4.0.0-dev" +dependencies = [ + "enumflags2", + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "pallet-balances", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-nicks" version = "4.0.0-dev" diff --git a/Cargo.toml b/Cargo.toml index eb78d5e104486..8f55d8e527ecd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -122,6 +122,7 @@ members = [ "frame/preimage", "frame/proxy", "frame/message-queue", + "frame/nfts", "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 477545c9ac332..201e3a85f8941 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -78,6 +78,7 @@ pallet-membership = { version = "4.0.0-dev", default-features = false, path = ". 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-nfts = { version = "4.0.0-dev", default-features = false, path = "../../../frame/nfts" } 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" } @@ -197,6 +198,7 @@ std = [ "pallet-root-testing/std", "pallet-recovery/std", "pallet-uniques/std", + "pallet-nfts/std", "pallet-vesting/std", "log/std", "frame-try-runtime?/std", @@ -253,6 +255,7 @@ runtime-benchmarks = [ "pallet-treasury/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-uniques/runtime-benchmarks", + "pallet-nfts/runtime-benchmarks", "pallet-vesting/runtime-benchmarks", "pallet-whitelist/runtime-benchmarks", "frame-system-benchmarking/runtime-benchmarks", @@ -312,6 +315,7 @@ try-runtime = [ "pallet-asset-tx-payment/try-runtime", "pallet-transaction-storage/try-runtime", "pallet-uniques/try-runtime", + "pallet-nfts/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 e5776e3fd692c..3e2701b2278c8 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -56,6 +56,7 @@ use pallet_grandpa::{ fg_primitives, AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList, }; use pallet_im_online::sr25519::AuthorityId as ImOnlineId; +use pallet_nfts::PalletFeatures; use pallet_nis::WithMaximumOf; use pallet_session::historical::{self as pallet_session_historical}; pub use pallet_transaction_payment::{CurrencyAdapter, Multiplier, TargetedFeeAdjustment}; @@ -301,6 +302,7 @@ impl InstanceFilter for ProxyType { RuntimeCall::Balances(..) | RuntimeCall::Assets(..) | RuntimeCall::Uniques(..) | + RuntimeCall::Nfts(..) | RuntimeCall::Vesting(pallet_vesting::Call::vested_transfer { .. }) | RuntimeCall::Indices(pallet_indices::Call::transfer { .. }) ), @@ -1528,6 +1530,10 @@ parameter_types! { pub const ItemDeposit: Balance = 1 * DOLLARS; pub const KeyLimit: u32 = 32; pub const ValueLimit: u32 = 256; + pub const ApprovalsLimit: u32 = 20; + pub const ItemAttributesApprovalsLimit: u32 = 20; + pub const MaxTips: u32 = 10; + pub const MaxDeadlineDuration: BlockNumber = 12 * 30 * DAYS; } impl pallet_uniques::Config for Runtime { @@ -1551,6 +1557,36 @@ impl pallet_uniques::Config for Runtime { type Locker = (); } +parameter_types! { + pub Features: PalletFeatures = PalletFeatures::all_enabled(); +} + +impl pallet_nfts::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type CollectionId = u32; + type ItemId = u32; + type Currency = Balances; + type ForceOrigin = frame_system::EnsureRoot; + type CollectionDeposit = CollectionDeposit; + type ItemDeposit = ItemDeposit; + type MetadataDepositBase = MetadataDepositBase; + type AttributeDepositBase = MetadataDepositBase; + type DepositPerByte = MetadataDepositPerByte; + type StringLimit = StringLimit; + type KeyLimit = KeyLimit; + type ValueLimit = ValueLimit; + type ApprovalsLimit = ApprovalsLimit; + type ItemAttributesApprovalsLimit = ItemAttributesApprovalsLimit; + type MaxTips = MaxTips; + type MaxDeadlineDuration = MaxDeadlineDuration; + type Features = Features; + type WeightInfo = pallet_nfts::weights::SubstrateWeight; + #[cfg(feature = "runtime-benchmarks")] + type Helper = (); + type CreateOrigin = AsEnsureOriginWithArg>; + type Locker = (); +} + impl pallet_transaction_storage::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Currency = Balances; @@ -1705,6 +1741,7 @@ construct_runtime!( Lottery: pallet_lottery, Nis: pallet_nis, Uniques: pallet_uniques, + Nfts: pallet_nfts, TransactionStorage: pallet_transaction_storage, VoterList: pallet_bags_list::, StateTrieMigration: pallet_state_trie_migration, @@ -1836,6 +1873,7 @@ mod benches { [pallet_transaction_storage, TransactionStorage] [pallet_treasury, Treasury] [pallet_uniques, Uniques] + [pallet_nfts, Nfts] [pallet_utility, Utility] [pallet_vesting, Vesting] [pallet_whitelist, Whitelist] diff --git a/frame/nfts/Cargo.toml b/frame/nfts/Cargo.toml new file mode 100644 index 0000000000000..109dffdd10f50 --- /dev/null +++ b/frame/nfts/Cargo.toml @@ -0,0 +1,49 @@ +[package] +name = "pallet-nfts" +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 NFTs 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 } +enumflags2 = { version = "0.7.5" } +log = { version = "0.4.17", 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" } +frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } +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" } +sp-std = { version = "5.0.0", path = "../../primitives/std" } + +[features] +default = ["std"] +std = [ + "codec/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", + "frame-system/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", +] +try-runtime = ["frame-support/try-runtime"] diff --git a/frame/nfts/README.md b/frame/nfts/README.md new file mode 100644 index 0000000000000..7de4b9440e7f5 --- /dev/null +++ b/frame/nfts/README.md @@ -0,0 +1,106 @@ +# NFTs pallet + +A pallet for dealing with non-fungible assets. + +## Overview + +The NFTs pallet provides functionality for non-fungible tokens' management, including: + +* Collection Creation +* NFT Minting +* NFT Transfers and Atomic Swaps +* NFT Trading methods +* Attributes Management +* NFT Burning + +To use it in your runtime, you need to implement [`nfts::Config`](https://paritytech.github.io/substrate/master/pallet_nfts/pallet/trait.Config.html). + +The supported dispatchable functions are documented in the [`nfts::Call`](https://paritytech.github.io/substrate/master/pallet_nfts/pallet/enum.Call.html) enum. + +### Terminology + +* **Collection creation:** The creation of a new collection. +* **NFT minting:** The action of creating a new item within a collection. +* **NFT transfer:** The action of sending an item from one account to another. +* **Atomic swap:** The action of exchanging items between accounts without needing a 3rd party service. +* **NFT burning:** The destruction of an item. +* **Non-fungible token (NFT):** An item for which each unit has unique characteristics. There is exactly + one instance of such an item in existence and there is exactly one owning account (though that owning account could be a proxy account or multi-sig account). +* **Soul Bound NFT:** An item that is non-transferable from the account which it is minted into. + +### Goals + +The NFTs pallet in Substrate is designed to make the following possible: + +* Allow accounts to permissionlessly create nft collections. +* Allow a named (permissioned) account to mint and burn unique items within a collection. +* Move items between accounts permissionlessly. +* Allow a named (permissioned) account to freeze and unfreeze items within a + collection or the entire collection. +* Allow the owner of an item to delegate the ability to transfer the item to some + named third-party. +* Allow third-parties to store information in an NFT _without_ owning it (Eg. save game state). + +## Interface + +### Permissionless dispatchables + +* `create`: Create a new collection by placing a deposit. +* `mint`: Mint a new item within a collection (when the minting is public). +* `transfer`: Send an item to a new owner. +* `redeposit`: Update the deposit amount of an item, potentially freeing funds. +* `approve_transfer`: Name a delegate who may authorize a transfer. +* `cancel_approval`: Revert the effects of a previous `approve_transfer`. +* `approve_item_attributes`: Name a delegate who may change item's attributes within a namespace. +* `cancel_item_attributes_approval`: Revert the effects of a previous `approve_item_attributes`. +* `set_price`: Set the price for an item. +* `buy_item`: Buy an item. +* `pay_tips`: Pay tips, could be used for paying the creator royalties. +* `create_swap`: Create an offer to swap an NFT for another NFT and optionally some fungibles. +* `cancel_swap`: Cancel previously created swap offer. +* `claim_swap`: Swap items in an atomic way. + + +### Permissioned dispatchables + +* `destroy`: Destroy a collection. This destroys all the items inside the collection and refunds the deposit. +* `force_mint`: Mint a new item within a collection. +* `burn`: Destroy an item within a collection. +* `lock_item_transfer`: Prevent an individual item from being transferred. +* `unlock_item_transfer`: Revert the effects of a previous `lock_item_transfer`. +* `clear_all_transfer_approvals`: Clears all transfer approvals set by calling the `approve_transfer`. +* `lock_collection`: Prevent all items within a collection from being transferred (making them all `soul bound`). +* `lock_item_properties`: Lock item's metadata or attributes. +* `transfer_ownership`: Alter the owner of a collection, moving all associated deposits. (Ownership of individual items will not be affected.) +* `set_team`: Alter the permissioned accounts of a collection. +* `set_collection_max_supply`: Change the max supply of a collection. +* `update_mint_settings`: Update the minting settings for collection. + + +### Metadata (permissioned) dispatchables + +* `set_attribute`: Set a metadata attribute of an item or collection. +* `clear_attribute`: Remove a metadata attribute of an item or collection. +* `set_metadata`: Set general metadata of an item (E.g. an IPFS address of an image url). +* `clear_metadata`: Remove general metadata of an item. +* `set_collection_metadata`: Set general metadata of a collection. +* `clear_collection_metadata`: Remove general metadata of a collection. + + +### Force (i.e. governance) dispatchables + +* `force_create`: Create a new collection (the collection id can not be chosen). +* `force_collection_owner`: Change collection's owner. +* `force_collection_config`: Change collection's config. +* `force_set_attribute`: Set an attribute. + +Please refer to the [`Call`](https://paritytech.github.io/substrate/master/pallet_nfts/pallet/enum.Call.html) enum +and its associated variants for documentation on each function. + +## Related Modules + +* [`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_assets/) + +License: Apache-2.0 diff --git a/frame/nfts/src/benchmarking.rs b/frame/nfts/src/benchmarking.rs new file mode 100644 index 0000000000000..6517445da672d --- /dev/null +++ b/frame/nfts/src/benchmarking.rs @@ -0,0 +1,718 @@ +// 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. + +//! Nfts pallet benchmarking. + +#![cfg(feature = "runtime-benchmarks")] + +use super::*; +use enumflags2::{BitFlag, BitFlags}; +use frame_benchmarking::{ + account, benchmarks_instance_pallet, whitelist_account, whitelisted_caller, +}; +use frame_support::{ + assert_ok, + dispatch::UnfilteredDispatchable, + traits::{EnsureOrigin, Get}, + BoundedVec, +}; +use frame_system::RawOrigin as SystemOrigin; +use sp_runtime::traits::{Bounded, One}; +use sp_std::prelude::*; + +use crate::Pallet as Nfts; + +const SEED: u32 = 0; + +fn create_collection, I: 'static>( +) -> (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); + T::Currency::make_free_balance_be(&caller, DepositBalanceOf::::max_value()); + assert_ok!(Nfts::::force_create( + SystemOrigin::Root.into(), + caller_lookup.clone(), + default_collection_config::() + )); + (collection, caller, caller_lookup) +} + +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); + } + let caller_lookup = T::Lookup::unlookup(caller.clone()); + assert_ok!(Nfts::::set_collection_metadata( + SystemOrigin::Signed(caller.clone()).into(), + T::Helper::collection(0), + vec![0; T::StringLimit::get() as usize].try_into().unwrap(), + )); + (caller, caller_lookup) +} + +fn mint_item, I: 'static>( + index: u16, +) -> (T::ItemId, T::AccountId, AccountIdLookupOf) { + 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()); + let item = T::Helper::item(index); + assert_ok!(Nfts::::mint( + SystemOrigin::Signed(caller.clone()).into(), + T::Helper::collection(0), + item, + caller_lookup.clone(), + None, + )); + (item, caller, caller_lookup) +} + +fn add_item_metadata, I: 'static>( + item: T::ItemId, +) -> (T::AccountId, AccountIdLookupOf) { + 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_ok!(Nfts::::set_metadata( + SystemOrigin::Signed(caller.clone()).into(), + T::Helper::collection(0), + item, + vec![0; T::StringLimit::get() as usize].try_into().unwrap(), + )); + (caller, caller_lookup) +} + +fn add_item_attribute, I: 'static>( + item: T::ItemId, +) -> (BoundedVec, T::AccountId, AccountIdLookupOf) { + 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()); + let key: BoundedVec<_, _> = vec![0; T::KeyLimit::get() as usize].try_into().unwrap(); + assert_ok!(Nfts::::set_attribute( + SystemOrigin::Signed(caller.clone()).into(), + T::Helper::collection(0), + Some(item), + AttributeNamespace::CollectionOwner, + key.clone(), + vec![0; T::ValueLimit::get() as usize].try_into().unwrap(), + )); + (key, caller, caller_lookup) +} + +fn assert_last_event, I: 'static>(generic_event: >::RuntimeEvent) { + let events = frame_system::Pallet::::events(); + let system_event: ::RuntimeEvent = generic_event.into(); + // compare to the last event record + let frame_system::EventRecord { event, .. } = &events[events.len() - 1]; + assert_eq!(event, &system_event); +} + +fn make_collection_config, I: 'static>( + disable_settings: BitFlags, +) -> CollectionConfigFor { + CollectionConfig { + settings: CollectionSettings::from_disabled(disable_settings), + max_supply: None, + mint_settings: MintSettings::default(), + } +} + +fn default_collection_config, I: 'static>() -> CollectionConfigFor { + make_collection_config::(CollectionSetting::empty()) +} + +fn default_item_config() -> ItemConfig { + ItemConfig { settings: ItemSettings::all_enabled() } +} + +benchmarks_instance_pallet! { + create { + 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 { admin, config: default_collection_config::() }; + }: { call.dispatch_bypass_filter(origin)? } + verify { + 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, caller_lookup, default_collection_config::()) + verify { + assert_last_event::(Event::ForceCreated { collection: T::Helper::collection(0), owner: caller }.into()); + } + + destroy { + let n in 0 .. 1_000; + let m in 0 .. 1_000; + let a in 0 .. 1_000; + + let (collection, caller, _) = create_collection::(); + add_collection_metadata::(); + for i in 0..n { + mint_item::(i as u16); + } + for i in 0..m { + if !Item::::contains_key(collection, T::Helper::item(i as u16)) { + mint_item::(i as u16); + } + add_item_metadata::(T::Helper::item(i as u16)); + } + for i in 0..a { + if !Item::::contains_key(collection, T::Helper::item(i as u16)) { + mint_item::(i as u16); + } + add_item_attribute::(T::Helper::item(i as u16)); + } + let witness = Collection::::get(collection).unwrap().destroy_witness(); + }: _(SystemOrigin::Signed(caller), collection, witness) + verify { + assert_last_event::(Event::Destroyed { collection }.into()); + } + + mint { + let (collection, caller, caller_lookup) = create_collection::(); + let item = T::Helper::item(0); + }: _(SystemOrigin::Signed(caller.clone()), collection, item, caller_lookup, None) + verify { + assert_last_event::(Event::Issued { collection, item, owner: caller }.into()); + } + + force_mint { + let (collection, caller, caller_lookup) = create_collection::(); + let item = T::Helper::item(0); + }: _(SystemOrigin::Signed(caller.clone()), collection, item, caller_lookup, default_item_config()) + verify { + assert_last_event::(Event::Issued { collection, item, owner: caller }.into()); + } + + burn { + 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 { collection, item, owner: caller }.into()); + } + + transfer { + let (collection, caller, _) = create_collection::(); + let (item, ..) = mint_item::(0); + + 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()); + }: _(SystemOrigin::Signed(caller.clone()), collection, item, target_lookup) + verify { + assert_last_event::(Event::Transferred { collection, item, from: caller, to: target }.into()); + } + + redeposit { + let i in 0 .. 5_000; + let (collection, caller, _) = create_collection::(); + let items = (0..i).map(|x| mint_item::(x as u16).0).collect::>(); + Nfts::::force_collection_config( + SystemOrigin::Root.into(), + collection, + make_collection_config::(CollectionSetting::DepositRequired.into()), + )?; + }: _(SystemOrigin::Signed(caller.clone()), collection, items.clone()) + verify { + assert_last_event::(Event::Redeposited { collection, successful_items: items }.into()); + } + + lock_item_transfer { + let (collection, caller, _) = create_collection::(); + let (item, ..) = mint_item::(0); + }: _(SystemOrigin::Signed(caller.clone()), T::Helper::collection(0), T::Helper::item(0)) + verify { + assert_last_event::(Event::ItemTransferLocked { collection: T::Helper::collection(0), item: T::Helper::item(0) }.into()); + } + + unlock_item_transfer { + let (collection, caller, _) = create_collection::(); + let (item, ..) = mint_item::(0); + Nfts::::lock_item_transfer( + SystemOrigin::Signed(caller.clone()).into(), + collection, + item, + )?; + }: _(SystemOrigin::Signed(caller.clone()), collection, item) + verify { + assert_last_event::(Event::ItemTransferUnlocked { collection, item }.into()); + } + + lock_collection { + let (collection, caller, _) = create_collection::(); + let lock_settings = CollectionSettings::from_disabled( + CollectionSetting::TransferableItems | + CollectionSetting::UnlockedMetadata | + CollectionSetting::UnlockedAttributes | + CollectionSetting::UnlockedMaxSupply, + ); + }: _(SystemOrigin::Signed(caller.clone()), collection, lock_settings) + verify { + assert_last_event::(Event::CollectionLocked { collection }.into()); + } + + transfer_ownership { + 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(); + Nfts::::set_accept_ownership(origin, Some(collection))?; + }: _(SystemOrigin::Signed(caller), collection, target_lookup) + verify { + assert_last_event::(Event::OwnerChanged { collection, new_owner: target }.into()); + } + + set_team { + 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), collection, target0, target1, target2) + verify { + assert_last_event::(Event::TeamChanged{ + collection, + issuer: account("target", 0, SEED), + admin: account("target", 1, SEED), + freezer: account("target", 2, SEED), + }.into()); + } + + force_collection_owner { + let (collection, _, _) = create_collection::(); + let origin = T::ForceOrigin::successful_origin(); + 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 call = Call::::force_collection_owner { + collection, + owner: target_lookup, + }; + }: { call.dispatch_bypass_filter(origin)? } + verify { + assert_last_event::(Event::OwnerChanged { collection, new_owner: target }.into()); + } + + force_collection_config { + let (collection, caller, _) = create_collection::(); + let origin = T::ForceOrigin::successful_origin(); + let call = Call::::force_collection_config { + collection, + config: make_collection_config::(CollectionSetting::DepositRequired.into()), + }; + }: { call.dispatch_bypass_filter(origin)? } + verify { + assert_last_event::(Event::CollectionConfigChanged { collection }.into()); + } + + lock_item_properties { + let (collection, caller, _) = create_collection::(); + let (item, ..) = mint_item::(0); + let lock_metadata = true; + let lock_attributes = true; + }: _(SystemOrigin::Signed(caller), collection, item, lock_metadata, lock_attributes) + verify { + assert_last_event::(Event::ItemPropertiesLocked { collection, item, lock_metadata, lock_attributes }.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 (collection, caller, _) = create_collection::(); + let (item, ..) = mint_item::(0); + }: _(SystemOrigin::Signed(caller), collection, Some(item), AttributeNamespace::CollectionOwner, key.clone(), value.clone()) + verify { + assert_last_event::( + Event::AttributeSet { + collection, + maybe_item: Some(item), + namespace: AttributeNamespace::CollectionOwner, + key, + value, + } + .into(), + ); + } + + force_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 (collection, caller, _) = create_collection::(); + let (item, ..) = mint_item::(0); + }: _(SystemOrigin::Root, Some(caller), collection, Some(item), AttributeNamespace::CollectionOwner, key.clone(), value.clone()) + verify { + assert_last_event::( + Event::AttributeSet { + collection, + maybe_item: Some(item), + namespace: AttributeNamespace::CollectionOwner, + key, + value, + } + .into(), + ); + } + + clear_attribute { + 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), AttributeNamespace::CollectionOwner, key.clone()) + verify { + assert_last_event::( + Event::AttributeCleared { + collection, + maybe_item: Some(item), + namespace: AttributeNamespace::CollectionOwner, + key, + }.into(), + ); + } + + approve_item_attributes { + let (collection, caller, _) = 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), collection, item, target_lookup) + verify { + assert_last_event::( + Event::ItemAttributesApprovalAdded { + collection, + item, + delegate: target, + } + .into(), + ); + } + + cancel_item_attributes_approval { + let n in 0 .. 1_000; + + let (collection, caller, _) = create_collection::(); + let (item, ..) = mint_item::(0); + let target: T::AccountId = account("target", 0, SEED); + let target_lookup = T::Lookup::unlookup(target.clone()); + Nfts::::approve_item_attributes( + SystemOrigin::Signed(caller.clone()).into(), + collection, + item, + target_lookup.clone(), + )?; + T::Currency::make_free_balance_be(&target, DepositBalanceOf::::max_value()); + let value: BoundedVec<_, _> = vec![0u8; T::ValueLimit::get() as usize].try_into().unwrap(); + for i in 0..n { + let mut key = vec![0u8; T::KeyLimit::get() as usize]; + let mut s = Vec::from((i as u16).to_be_bytes()); + key.truncate(s.len()); + key.append(&mut s); + + Nfts::::set_attribute( + SystemOrigin::Signed(target.clone()).into(), + T::Helper::collection(0), + Some(item), + AttributeNamespace::Account(target.clone()), + key.try_into().unwrap(), + value.clone(), + )?; + } + let witness = CancelAttributesApprovalWitness { account_attributes: n }; + }: _(SystemOrigin::Signed(caller), collection, item, target_lookup, witness) + verify { + assert_last_event::( + Event::ItemAttributesApprovalRemoved { + collection, + item, + delegate: target, + } + .into(), + ); + } + + set_metadata { + let data: BoundedVec<_, _> = vec![0u8; T::StringLimit::get() as usize].try_into().unwrap(); + + let (collection, caller, _) = create_collection::(); + let (item, ..) = mint_item::(0); + }: _(SystemOrigin::Signed(caller), collection, item, data.clone()) + verify { + assert_last_event::(Event::ItemMetadataSet { collection, item, data }.into()); + } + + clear_metadata { + let (collection, caller, _) = create_collection::(); + let (item, ..) = mint_item::(0); + add_item_metadata::(item); + }: _(SystemOrigin::Signed(caller), collection, item) + verify { + assert_last_event::(Event::ItemMetadataCleared { collection, item }.into()); + } + + set_collection_metadata { + let data: BoundedVec<_, _> = vec![0u8; T::StringLimit::get() as usize].try_into().unwrap(); + + let (collection, caller, _) = create_collection::(); + }: _(SystemOrigin::Signed(caller), collection, data.clone()) + verify { + assert_last_event::(Event::CollectionMetadataSet { collection, data }.into()); + } + + clear_collection_metadata { + let (collection, caller, _) = create_collection::(); + add_collection_metadata::(); + }: _(SystemOrigin::Signed(caller), collection) + verify { + assert_last_event::(Event::CollectionMetadataCleared { collection }.into()); + } + + approve_transfer { + 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 deadline = T::BlockNumber::max_value(); + }: _(SystemOrigin::Signed(caller.clone()), collection, item, delegate_lookup, Some(deadline)) + verify { + assert_last_event::(Event::TransferApproved { collection, item, owner: caller, delegate, deadline: Some(deadline) }.into()); + } + + cancel_approval { + 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(); + let deadline = T::BlockNumber::max_value(); + Nfts::::approve_transfer(origin, collection, item, delegate_lookup.clone(), Some(deadline))?; + }: _(SystemOrigin::Signed(caller.clone()), collection, item, delegate_lookup) + verify { + assert_last_event::(Event::ApprovalCancelled { collection, item, owner: caller, delegate }.into()); + } + + clear_all_transfer_approvals { + 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(); + let deadline = T::BlockNumber::max_value(); + Nfts::::approve_transfer(origin, collection, item, delegate_lookup.clone(), Some(deadline))?; + }: _(SystemOrigin::Signed(caller.clone()), collection, item) + verify { + assert_last_event::(Event::AllApprovalsCancelled {collection, item, owner: caller}.into()); + } + + set_accept_ownership { + let caller: T::AccountId = whitelisted_caller(); + T::Currency::make_free_balance_be(&caller, DepositBalanceOf::::max_value()); + let collection = T::Helper::collection(0); + }: _(SystemOrigin::Signed(caller.clone()), Some(collection)) + verify { + assert_last_event::(Event::OwnershipAcceptanceChanged { + who: caller, + maybe_collection: Some(collection), + }.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()); + } + + update_mint_settings { + let (collection, caller, _) = create_collection::(); + let mint_settings = MintSettings { + mint_type: MintType::HolderOf(T::Helper::collection(0)), + start_block: Some(One::one()), + end_block: Some(One::one()), + price: Some(ItemPrice::::from(1u32)), + default_item_settings: ItemSettings::all_enabled(), + }; + }: _(SystemOrigin::Signed(caller.clone()), collection, mint_settings) + verify { + assert_last_event::(Event::CollectionMintSettingsUpdated { collection }.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(); + Nfts::::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()); + } + + pay_tips { + let n in 0 .. T::MaxTips::get() as u32; + let amount = BalanceOf::::from(100u32); + let caller: T::AccountId = whitelisted_caller(); + let collection = T::Helper::collection(0); + let item = T::Helper::item(0); + let tips: BoundedVec<_, _> = vec![ + ItemTip + { collection, item, receiver: caller.clone(), amount }; n as usize + ].try_into().unwrap(); + }: _(SystemOrigin::Signed(caller.clone()), tips) + verify { + if !n.is_zero() { + assert_last_event::(Event::TipSent { + collection, + item, + sender: caller.clone(), + receiver: caller.clone(), + amount, + }.into()); + } + } + + create_swap { + let (collection, caller, _) = create_collection::(); + let (item1, ..) = mint_item::(0); + let (item2, ..) = mint_item::(1); + let price = ItemPrice::::from(100u32); + let price_direction = PriceDirection::Receive; + let price_with_direction = PriceWithDirection { amount: price, direction: price_direction }; + let duration = T::MaxDeadlineDuration::get(); + frame_system::Pallet::::set_block_number(One::one()); + }: _(SystemOrigin::Signed(caller.clone()), collection, item1, collection, Some(item2), Some(price_with_direction.clone()), duration) + verify { + let current_block = frame_system::Pallet::::block_number(); + assert_last_event::(Event::SwapCreated { + offered_collection: collection, + offered_item: item1, + desired_collection: collection, + desired_item: Some(item2), + price: Some(price_with_direction), + deadline: current_block.saturating_add(duration), + }.into()); + } + + cancel_swap { + let (collection, caller, _) = create_collection::(); + let (item1, ..) = mint_item::(0); + let (item2, ..) = mint_item::(1); + let price = ItemPrice::::from(100u32); + let origin = SystemOrigin::Signed(caller.clone()).into(); + let duration = T::MaxDeadlineDuration::get(); + let price_direction = PriceDirection::Receive; + let price_with_direction = PriceWithDirection { amount: price, direction: price_direction }; + frame_system::Pallet::::set_block_number(One::one()); + Nfts::::create_swap(origin, collection, item1, collection, Some(item2), Some(price_with_direction.clone()), duration)?; + }: _(SystemOrigin::Signed(caller.clone()), collection, item1) + verify { + assert_last_event::(Event::SwapCancelled { + offered_collection: collection, + offered_item: item1, + desired_collection: collection, + desired_item: Some(item2), + price: Some(price_with_direction), + deadline: duration.saturating_add(One::one()), + }.into()); + } + + claim_swap { + let (collection, caller, _) = create_collection::(); + let (item1, ..) = mint_item::(0); + let (item2, ..) = mint_item::(1); + let price = ItemPrice::::from(0u32); + let price_direction = PriceDirection::Receive; + let price_with_direction = PriceWithDirection { amount: price, direction: price_direction }; + let duration = T::MaxDeadlineDuration::get(); + 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(caller.clone()); + frame_system::Pallet::::set_block_number(One::one()); + Nfts::::transfer(origin.clone().into(), collection, item2, target_lookup)?; + Nfts::::create_swap( + origin.clone().into(), + collection, + item1, + collection, + Some(item2), + Some(price_with_direction.clone()), + duration, + )?; + }: _(SystemOrigin::Signed(target.clone()), collection, item2, collection, item1, Some(price_with_direction.clone())) + verify { + let current_block = frame_system::Pallet::::block_number(); + assert_last_event::(Event::SwapClaimed { + sent_collection: collection, + sent_item: item2, + sent_item_owner: target, + received_collection: collection, + received_item: item1, + received_item_owner: caller, + price: Some(price_with_direction), + deadline: duration.saturating_add(One::one()), + }.into()); + } + + impl_benchmark_test_suite!(Nfts, crate::mock::new_test_ext(), crate::mock::Test); +} diff --git a/frame/nfts/src/common_functions.rs b/frame/nfts/src/common_functions.rs new file mode 100644 index 0000000000000..9c0faeb6b7c77 --- /dev/null +++ b/frame/nfts/src/common_functions.rs @@ -0,0 +1,42 @@ +// 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. + +//! Various pieces of common functionality. + +use super::*; + +impl, I: 'static> Pallet { + /// 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 collection, if the collection exists. + pub fn collection_owner(collection: T::CollectionId) -> Option { + Collection::::get(collection).map(|i| i.owner) + } + + #[cfg(any(test, feature = "runtime-benchmarks"))] + pub fn set_next_id(id: T::CollectionId) { + NextCollectionId::::set(Some(id)); + } + + #[cfg(test)] + pub fn get_next_id() -> T::CollectionId { + NextCollectionId::::get().unwrap_or(T::CollectionId::initial_value()) + } +} diff --git a/frame/nfts/src/features/approvals.rs b/frame/nfts/src/features/approvals.rs new file mode 100644 index 0000000000000..cb5279fd949db --- /dev/null +++ b/frame/nfts/src/features/approvals.rs @@ -0,0 +1,132 @@ +// 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::*; +use frame_support::pallet_prelude::*; + +impl, I: 'static> Pallet { + pub(crate) fn do_approve_transfer( + maybe_check_origin: Option, + collection: T::CollectionId, + item: T::ItemId, + delegate: T::AccountId, + maybe_deadline: Option<::BlockNumber>, + ) -> DispatchResult { + ensure!( + Self::is_pallet_feature_enabled(PalletFeature::Approvals), + Error::::MethodDisabled + ); + let mut details = + Item::::get(&collection, &item).ok_or(Error::::UnknownItem)?; + + let collection_config = Self::get_collection_config(&collection)?; + ensure!( + collection_config.is_setting_enabled(CollectionSetting::TransferableItems), + Error::::ItemsNonTransferable + ); + + if let Some(check_origin) = maybe_check_origin { + let is_admin = Self::has_role(&collection, &check_origin, CollectionRole::Admin); + let permitted = is_admin || check_origin == details.owner; + ensure!(permitted, Error::::NoPermission); + } + + let now = frame_system::Pallet::::block_number(); + let deadline = maybe_deadline.map(|d| d.saturating_add(now)); + + details + .approvals + .try_insert(delegate.clone(), deadline) + .map_err(|_| Error::::ReachedApprovalLimit)?; + Item::::insert(&collection, &item, &details); + + Self::deposit_event(Event::TransferApproved { + collection, + item, + owner: details.owner, + delegate, + deadline, + }); + + Ok(()) + } + + pub(crate) fn do_cancel_approval( + maybe_check_origin: Option, + collection: T::CollectionId, + item: T::ItemId, + delegate: T::AccountId, + ) -> DispatchResult { + let mut details = + Item::::get(&collection, &item).ok_or(Error::::UnknownItem)?; + + let maybe_deadline = details.approvals.get(&delegate).ok_or(Error::::NotDelegate)?; + + let is_past_deadline = if let Some(deadline) = maybe_deadline { + let now = frame_system::Pallet::::block_number(); + now > *deadline + } else { + false + }; + + if !is_past_deadline { + if let Some(check_origin) = maybe_check_origin { + let is_admin = Self::has_role(&collection, &check_origin, CollectionRole::Admin); + let permitted = is_admin || check_origin == details.owner; + ensure!(permitted, Error::::NoPermission); + } + } + + details.approvals.remove(&delegate); + Item::::insert(&collection, &item, &details); + + Self::deposit_event(Event::ApprovalCancelled { + collection, + item, + owner: details.owner, + delegate, + }); + + Ok(()) + } + + pub(crate) fn do_clear_all_transfer_approvals( + maybe_check_origin: Option, + collection: T::CollectionId, + item: T::ItemId, + ) -> DispatchResult { + let mut details = + Item::::get(&collection, &item).ok_or(Error::::UnknownCollection)?; + + if let Some(check_origin) = maybe_check_origin { + let is_admin = Self::has_role(&collection, &check_origin, CollectionRole::Admin); + let permitted = is_admin || check_origin == details.owner; + ensure!(permitted, Error::::NoPermission); + } + + details.approvals.clear(); + Item::::insert(&collection, &item, &details); + + Self::deposit_event(Event::AllApprovalsCancelled { + collection, + item, + owner: details.owner, + }); + + Ok(()) + } +} diff --git a/frame/nfts/src/features/atomic_swap.rs b/frame/nfts/src/features/atomic_swap.rs new file mode 100644 index 0000000000000..bacaccdaedcbf --- /dev/null +++ b/frame/nfts/src/features/atomic_swap.rs @@ -0,0 +1,184 @@ +// 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::*; +use frame_support::{ + pallet_prelude::*, + traits::{Currency, ExistenceRequirement::KeepAlive}, +}; + +impl, I: 'static> Pallet { + pub(crate) fn do_create_swap( + caller: T::AccountId, + offered_collection_id: T::CollectionId, + offered_item_id: T::ItemId, + desired_collection_id: T::CollectionId, + maybe_desired_item_id: Option, + maybe_price: Option>>, + duration: ::BlockNumber, + ) -> DispatchResult { + ensure!( + Self::is_pallet_feature_enabled(PalletFeature::Swaps), + Error::::MethodDisabled + ); + ensure!(duration <= T::MaxDeadlineDuration::get(), Error::::WrongDuration); + + let item = Item::::get(&offered_collection_id, &offered_item_id) + .ok_or(Error::::UnknownItem)?; + ensure!(item.owner == caller, Error::::NoPermission); + + match maybe_desired_item_id { + Some(desired_item_id) => ensure!( + Item::::contains_key(&desired_collection_id, &desired_item_id), + Error::::UnknownItem + ), + None => ensure!( + Collection::::contains_key(&desired_collection_id), + Error::::UnknownCollection + ), + }; + + let now = frame_system::Pallet::::block_number(); + let deadline = duration.saturating_add(now); + + PendingSwapOf::::insert( + &offered_collection_id, + &offered_item_id, + PendingSwap { + desired_collection: desired_collection_id, + desired_item: maybe_desired_item_id, + price: maybe_price.clone(), + deadline, + }, + ); + + Self::deposit_event(Event::SwapCreated { + offered_collection: offered_collection_id, + offered_item: offered_item_id, + desired_collection: desired_collection_id, + desired_item: maybe_desired_item_id, + price: maybe_price, + deadline, + }); + + Ok(()) + } + + pub(crate) fn do_cancel_swap( + caller: T::AccountId, + offered_collection_id: T::CollectionId, + offered_item_id: T::ItemId, + ) -> DispatchResult { + let swap = PendingSwapOf::::get(&offered_collection_id, &offered_item_id) + .ok_or(Error::::UnknownSwap)?; + + let now = frame_system::Pallet::::block_number(); + if swap.deadline > now { + let item = Item::::get(&offered_collection_id, &offered_item_id) + .ok_or(Error::::UnknownItem)?; + ensure!(item.owner == caller, Error::::NoPermission); + } + + PendingSwapOf::::remove(&offered_collection_id, &offered_item_id); + + Self::deposit_event(Event::SwapCancelled { + offered_collection: offered_collection_id, + offered_item: offered_item_id, + desired_collection: swap.desired_collection, + desired_item: swap.desired_item, + price: swap.price, + deadline: swap.deadline, + }); + + Ok(()) + } + + pub(crate) fn do_claim_swap( + caller: T::AccountId, + send_collection_id: T::CollectionId, + send_item_id: T::ItemId, + receive_collection_id: T::CollectionId, + receive_item_id: T::ItemId, + witness_price: Option>>, + ) -> DispatchResult { + ensure!( + Self::is_pallet_feature_enabled(PalletFeature::Swaps), + Error::::MethodDisabled + ); + + let send_item = Item::::get(&send_collection_id, &send_item_id) + .ok_or(Error::::UnknownItem)?; + let receive_item = Item::::get(&receive_collection_id, &receive_item_id) + .ok_or(Error::::UnknownItem)?; + let swap = PendingSwapOf::::get(&receive_collection_id, &receive_item_id) + .ok_or(Error::::UnknownSwap)?; + + ensure!(send_item.owner == caller, Error::::NoPermission); + ensure!( + swap.desired_collection == send_collection_id && swap.price == witness_price, + Error::::UnknownSwap + ); + + if let Some(desired_item) = swap.desired_item { + ensure!(desired_item == send_item_id, Error::::UnknownSwap); + } + + let now = frame_system::Pallet::::block_number(); + ensure!(now <= swap.deadline, Error::::DeadlineExpired); + + if let Some(ref price) = swap.price { + match price.direction { + PriceDirection::Send => T::Currency::transfer( + &receive_item.owner, + &send_item.owner, + price.amount, + KeepAlive, + )?, + PriceDirection::Receive => T::Currency::transfer( + &send_item.owner, + &receive_item.owner, + price.amount, + KeepAlive, + )?, + }; + } + + // This also removes the swap. + Self::do_transfer(send_collection_id, send_item_id, receive_item.owner.clone(), |_, _| { + Ok(()) + })?; + Self::do_transfer( + receive_collection_id, + receive_item_id, + send_item.owner.clone(), + |_, _| Ok(()), + )?; + + Self::deposit_event(Event::SwapClaimed { + sent_collection: send_collection_id, + sent_item: send_item_id, + sent_item_owner: send_item.owner, + received_collection: receive_collection_id, + received_item: receive_item_id, + received_item_owner: receive_item.owner, + price: swap.price, + deadline: swap.deadline, + }); + + Ok(()) + } +} diff --git a/frame/nfts/src/features/attributes.rs b/frame/nfts/src/features/attributes.rs new file mode 100644 index 0000000000000..da663d39a4ef5 --- /dev/null +++ b/frame/nfts/src/features/attributes.rs @@ -0,0 +1,323 @@ +// 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::*; +use frame_support::pallet_prelude::*; + +impl, I: 'static> Pallet { + pub(crate) fn do_set_attribute( + origin: T::AccountId, + collection: T::CollectionId, + maybe_item: Option, + namespace: AttributeNamespace, + key: BoundedVec, + value: BoundedVec, + ) -> DispatchResult { + ensure!( + Self::is_pallet_feature_enabled(PalletFeature::Attributes), + Error::::MethodDisabled + ); + + let mut collection_details = + Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; + + ensure!( + Self::is_valid_namespace( + &origin, + &namespace, + &collection, + &collection_details.owner, + &maybe_item, + )?, + Error::::NoPermission + ); + + let collection_config = Self::get_collection_config(&collection)?; + // for the `CollectionOwner` namespace we need to check if the collection/item is not locked + match namespace { + AttributeNamespace::CollectionOwner => match maybe_item { + None => { + ensure!( + collection_config.is_setting_enabled(CollectionSetting::UnlockedAttributes), + Error::::LockedCollectionAttributes + ) + }, + Some(item) => { + let maybe_is_locked = Self::get_item_config(&collection, &item) + .map(|c| c.has_disabled_setting(ItemSetting::UnlockedAttributes))?; + ensure!(!maybe_is_locked, Error::::LockedItemAttributes); + }, + }, + _ => (), + } + + let attribute = Attribute::::get((collection, maybe_item, &namespace, &key)); + if attribute.is_none() { + collection_details.attributes.saturating_inc(); + } + + let old_deposit = + attribute.map_or(AttributeDeposit { account: None, amount: Zero::zero() }, |m| m.1); + + let mut deposit = Zero::zero(); + if collection_config.is_setting_enabled(CollectionSetting::DepositRequired) || + namespace != AttributeNamespace::CollectionOwner + { + deposit = T::DepositPerByte::get() + .saturating_mul(((key.len() + value.len()) as u32).into()) + .saturating_add(T::AttributeDepositBase::get()); + } + + // NOTE: when we transfer an item, we don't move attributes in the ItemOwner namespace. + // When the new owner updates the same attribute, we will update the depositor record + // and return the deposit to the previous owner. + if old_deposit.account.is_some() && old_deposit.account != Some(origin.clone()) { + T::Currency::unreserve(&old_deposit.account.unwrap(), old_deposit.amount); + T::Currency::reserve(&origin, deposit)?; + } else if deposit > old_deposit.amount { + T::Currency::reserve(&origin, deposit - old_deposit.amount)?; + } else if deposit < old_deposit.amount { + T::Currency::unreserve(&origin, old_deposit.amount - deposit); + } + + // NOTE: we don't track the depositor in the CollectionOwner namespace as it's always a + // collection's owner. This simplifies the collection's transfer to another owner. + let deposit_owner = match namespace { + AttributeNamespace::CollectionOwner => { + collection_details.owner_deposit.saturating_accrue(deposit); + collection_details.owner_deposit.saturating_reduce(old_deposit.amount); + None + }, + _ => Some(origin), + }; + + Attribute::::insert( + (&collection, maybe_item, &namespace, &key), + (&value, AttributeDeposit { account: deposit_owner, amount: deposit }), + ); + Collection::::insert(collection, &collection_details); + Self::deposit_event(Event::AttributeSet { collection, maybe_item, key, value, namespace }); + Ok(()) + } + + pub(crate) fn do_force_set_attribute( + set_as: Option, + collection: T::CollectionId, + maybe_item: Option, + namespace: AttributeNamespace, + key: BoundedVec, + value: BoundedVec, + ) -> DispatchResult { + let mut collection_details = + Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; + + let attribute = Attribute::::get((collection, maybe_item, &namespace, &key)); + if let Some((_, deposit)) = attribute { + if deposit.account != set_as && deposit.amount != Zero::zero() { + if let Some(deposit_account) = deposit.account { + T::Currency::unreserve(&deposit_account, deposit.amount); + } + } + } else { + collection_details.attributes.saturating_inc(); + } + + Attribute::::insert( + (&collection, maybe_item, &namespace, &key), + (&value, AttributeDeposit { account: set_as, amount: Zero::zero() }), + ); + Collection::::insert(collection, &collection_details); + Self::deposit_event(Event::AttributeSet { collection, maybe_item, key, value, namespace }); + Ok(()) + } + + pub(crate) fn do_clear_attribute( + maybe_check_owner: Option, + collection: T::CollectionId, + maybe_item: Option, + namespace: AttributeNamespace, + key: BoundedVec, + ) -> DispatchResult { + if let Some((_, deposit)) = + Attribute::::take((collection, maybe_item, &namespace, &key)) + { + let mut collection_details = + Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; + + if let Some(check_owner) = &maybe_check_owner { + if deposit.account != maybe_check_owner { + ensure!( + Self::is_valid_namespace( + &check_owner, + &namespace, + &collection, + &collection_details.owner, + &maybe_item, + )?, + Error::::NoPermission + ); + } + + // can't clear `CollectionOwner` type attributes if the collection/item is locked + match namespace { + AttributeNamespace::CollectionOwner => match maybe_item { + None => { + let collection_config = Self::get_collection_config(&collection)?; + ensure!( + collection_config + .is_setting_enabled(CollectionSetting::UnlockedAttributes), + Error::::LockedCollectionAttributes + ) + }, + Some(item) => { + // NOTE: if the item was previously burned, the ItemConfigOf record + // might not exist. In that case, we allow to clear the attribute. + let maybe_is_locked = Self::get_item_config(&collection, &item) + .map_or(false, |c| { + c.has_disabled_setting(ItemSetting::UnlockedAttributes) + }); + ensure!(!maybe_is_locked, Error::::LockedItemAttributes); + }, + }, + _ => (), + }; + } + + collection_details.attributes.saturating_dec(); + match namespace { + AttributeNamespace::CollectionOwner => { + collection_details.owner_deposit.saturating_reduce(deposit.amount); + T::Currency::unreserve(&collection_details.owner, deposit.amount); + }, + _ => (), + }; + if let Some(deposit_account) = deposit.account { + T::Currency::unreserve(&deposit_account, deposit.amount); + } + Collection::::insert(collection, &collection_details); + Self::deposit_event(Event::AttributeCleared { collection, maybe_item, key, namespace }); + } + Ok(()) + } + + pub(crate) fn do_approve_item_attributes( + check_origin: T::AccountId, + collection: T::CollectionId, + item: T::ItemId, + delegate: T::AccountId, + ) -> DispatchResult { + ensure!( + Self::is_pallet_feature_enabled(PalletFeature::Attributes), + Error::::MethodDisabled + ); + + let details = Item::::get(&collection, &item).ok_or(Error::::UnknownItem)?; + ensure!(check_origin == details.owner, Error::::NoPermission); + + ItemAttributesApprovalsOf::::try_mutate(collection, item, |approvals| { + approvals + .try_insert(delegate.clone()) + .map_err(|_| Error::::ReachedApprovalLimit)?; + + Self::deposit_event(Event::ItemAttributesApprovalAdded { collection, item, delegate }); + Ok(()) + }) + } + + pub(crate) fn do_cancel_item_attributes_approval( + check_origin: T::AccountId, + collection: T::CollectionId, + item: T::ItemId, + delegate: T::AccountId, + witness: CancelAttributesApprovalWitness, + ) -> DispatchResult { + ensure!( + Self::is_pallet_feature_enabled(PalletFeature::Attributes), + Error::::MethodDisabled + ); + + let details = Item::::get(&collection, &item).ok_or(Error::::UnknownItem)?; + ensure!(check_origin == details.owner, Error::::NoPermission); + + ItemAttributesApprovalsOf::::try_mutate(collection, item, |approvals| { + approvals.remove(&delegate); + + let mut attributes: u32 = 0; + let mut deposited: DepositBalanceOf = Zero::zero(); + for (_, (_, deposit)) in Attribute::::drain_prefix(( + &collection, + Some(item), + AttributeNamespace::Account(delegate.clone()), + )) { + attributes.saturating_inc(); + deposited = deposited.saturating_add(deposit.amount); + } + ensure!(attributes <= witness.account_attributes, Error::::BadWitness); + + if !deposited.is_zero() { + T::Currency::unreserve(&delegate, deposited); + } + + Self::deposit_event(Event::ItemAttributesApprovalRemoved { + collection, + item, + delegate, + }); + Ok(()) + }) + } + + fn is_valid_namespace( + origin: &T::AccountId, + namespace: &AttributeNamespace, + collection: &T::CollectionId, + collection_owner: &T::AccountId, + maybe_item: &Option, + ) -> Result { + let mut result = false; + match namespace { + AttributeNamespace::CollectionOwner => result = origin == collection_owner, + AttributeNamespace::ItemOwner => + if let Some(item) = maybe_item { + let item_details = + Item::::get(&collection, &item).ok_or(Error::::UnknownItem)?; + result = origin == &item_details.owner + }, + AttributeNamespace::Account(account_id) => + if let Some(item) = maybe_item { + let approvals = ItemAttributesApprovalsOf::::get(&collection, &item); + result = account_id == origin && approvals.contains(&origin) + }, + _ => (), + }; + Ok(result) + } + + /// A helper method to construct attribute's key. + pub fn construct_attribute_key( + key: Vec, + ) -> Result, DispatchError> { + Ok(BoundedVec::try_from(key).map_err(|_| Error::::IncorrectData)?) + } + + /// A helper method to construct attribute's value. + pub fn construct_attribute_value( + value: Vec, + ) -> Result, DispatchError> { + Ok(BoundedVec::try_from(value).map_err(|_| Error::::IncorrectData)?) + } +} diff --git a/frame/nfts/src/features/buy_sell.rs b/frame/nfts/src/features/buy_sell.rs new file mode 100644 index 0000000000000..8ba5171f8d822 --- /dev/null +++ b/frame/nfts/src/features/buy_sell.rs @@ -0,0 +1,130 @@ +// 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::*; +use frame_support::{ + pallet_prelude::*, + traits::{Currency, ExistenceRequirement, ExistenceRequirement::KeepAlive}, +}; + +impl, I: 'static> Pallet { + pub(crate) fn do_pay_tips( + sender: T::AccountId, + tips: BoundedVec, T::MaxTips>, + ) -> DispatchResult { + for tip in tips { + let ItemTip { collection, item, receiver, amount } = tip; + T::Currency::transfer(&sender, &receiver, amount, KeepAlive)?; + Self::deposit_event(Event::TipSent { + collection, + item, + sender: sender.clone(), + receiver, + amount, + }); + } + Ok(()) + } + + pub(crate) fn do_set_price( + collection: T::CollectionId, + item: T::ItemId, + sender: T::AccountId, + price: Option>, + whitelisted_buyer: Option, + ) -> DispatchResult { + ensure!( + Self::is_pallet_feature_enabled(PalletFeature::Trading), + Error::::MethodDisabled + ); + + let details = Item::::get(&collection, &item).ok_or(Error::::UnknownItem)?; + ensure!(details.owner == sender, Error::::NoPermission); + + let collection_config = Self::get_collection_config(&collection)?; + ensure!( + collection_config.is_setting_enabled(CollectionSetting::TransferableItems), + Error::::ItemsNonTransferable + ); + + let item_config = Self::get_item_config(&collection, &item)?; + ensure!( + item_config.is_setting_enabled(ItemSetting::Transferable), + Error::::ItemLocked + ); + + if let Some(ref price) = price { + ItemPriceOf::::insert(&collection, &item, (price, whitelisted_buyer.clone())); + Self::deposit_event(Event::ItemPriceSet { + collection, + item, + price: *price, + whitelisted_buyer, + }); + } else { + ItemPriceOf::::remove(&collection, &item); + Self::deposit_event(Event::ItemPriceRemoved { collection, item }); + } + + Ok(()) + } + + pub(crate) fn do_buy_item( + collection: T::CollectionId, + item: T::ItemId, + buyer: T::AccountId, + bid_price: ItemPrice, + ) -> DispatchResult { + ensure!( + Self::is_pallet_feature_enabled(PalletFeature::Trading), + Error::::MethodDisabled + ); + + 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/nfts/src/features/create_delete_collection.rs b/frame/nfts/src/features/create_delete_collection.rs new file mode 100644 index 0000000000000..86625bf49efb2 --- /dev/null +++ b/frame/nfts/src/features/create_delete_collection.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. + +use crate::*; +use frame_support::pallet_prelude::*; + +impl, I: 'static> Pallet { + pub fn do_create_collection( + collection: T::CollectionId, + owner: T::AccountId, + admin: T::AccountId, + config: CollectionConfigFor, + deposit: DepositBalanceOf, + event: Event, + ) -> DispatchResult { + ensure!(!Collection::::contains_key(collection), Error::::CollectionIdInUse); + + T::Currency::reserve(&owner, deposit)?; + + Collection::::insert( + collection, + CollectionDetails { + owner: owner.clone(), + owner_deposit: deposit, + items: 0, + item_metadatas: 0, + attributes: 0, + }, + ); + CollectionRoleOf::::insert( + collection, + admin, + CollectionRoles( + CollectionRole::Admin | CollectionRole::Freezer | CollectionRole::Issuer, + ), + ); + + let next_id = collection.increment(); + + CollectionConfigOf::::insert(&collection, config); + CollectionAccount::::insert(&owner, &collection, ()); + NextCollectionId::::set(Some(next_id)); + + Self::deposit_event(Event::NextCollectionIdIncremented { next_id }); + Self::deposit_event(event); + Ok(()) + } + + pub fn do_destroy_collection( + collection: T::CollectionId, + witness: DestroyWitness, + maybe_check_owner: Option, + ) -> Result { + 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!(collection_details.owner == check_owner, Error::::NoPermission); + } + ensure!(collection_details.items == witness.items, Error::::BadWitness); + ensure!( + collection_details.item_metadatas == witness.item_metadatas, + Error::::BadWitness + ); + ensure!(collection_details.attributes == witness.attributes, Error::::BadWitness); + + for (item, details) in Item::::drain_prefix(&collection) { + Account::::remove((&details.owner, &collection, &item)); + T::Currency::unreserve(&details.deposit.account, details.deposit.amount); + } + #[allow(deprecated)] + ItemMetadataOf::::remove_prefix(&collection, None); + #[allow(deprecated)] + ItemPriceOf::::remove_prefix(&collection, None); + #[allow(deprecated)] + PendingSwapOf::::remove_prefix(&collection, None); + CollectionMetadataOf::::remove(&collection); + Self::clear_roles(&collection)?; + + for (_, (_, deposit)) in Attribute::::drain_prefix((&collection,)) { + if !deposit.amount.is_zero() { + if let Some(account) = deposit.account { + T::Currency::unreserve(&account, deposit.amount); + } + } + } + + CollectionAccount::::remove(&collection_details.owner, &collection); + T::Currency::unreserve(&collection_details.owner, collection_details.owner_deposit); + CollectionConfigOf::::remove(&collection); + let _ = ItemConfigOf::::clear_prefix(&collection, witness.items, None); + let _ = + ItemAttributesApprovalsOf::::clear_prefix(&collection, witness.items, None); + + Self::deposit_event(Event::Destroyed { collection }); + + Ok(DestroyWitness { + items: collection_details.items, + item_metadatas: collection_details.item_metadatas, + attributes: collection_details.attributes, + }) + }) + } +} diff --git a/frame/nfts/src/features/create_delete_item.rs b/frame/nfts/src/features/create_delete_item.rs new file mode 100644 index 0000000000000..7fd745b2bfff8 --- /dev/null +++ b/frame/nfts/src/features/create_delete_item.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 crate::*; +use frame_support::pallet_prelude::*; + +impl, I: 'static> Pallet { + pub fn do_mint( + collection: T::CollectionId, + item: T::ItemId, + depositor: T::AccountId, + mint_to: T::AccountId, + item_config: ItemConfig, + deposit_collection_owner: bool, + with_details_and_config: impl FnOnce( + &CollectionDetailsFor, + &CollectionConfigFor, + ) -> DispatchResult, + ) -> DispatchResult { + 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)?; + + let collection_config = Self::get_collection_config(&collection)?; + with_details_and_config(collection_details, &collection_config)?; + + if let Some(max_supply) = collection_config.max_supply { + ensure!(collection_details.items < max_supply, Error::::MaxSupplyReached); + } + + collection_details.items.saturating_inc(); + + let collection_config = Self::get_collection_config(&collection)?; + let deposit_amount = match collection_config + .is_setting_enabled(CollectionSetting::DepositRequired) + { + true => T::ItemDeposit::get(), + false => Zero::zero(), + }; + let deposit_account = match deposit_collection_owner { + true => collection_details.owner.clone(), + false => depositor, + }; + + let item_owner = mint_to.clone(); + Account::::insert((&item_owner, &collection, &item), ()); + + if let Ok(existing_config) = ItemConfigOf::::try_get(&collection, &item) { + ensure!(existing_config == item_config, Error::::InconsistentItemConfig); + } else { + ItemConfigOf::::insert(&collection, &item, item_config); + } + + T::Currency::reserve(&deposit_account, deposit_amount)?; + + let deposit = ItemDeposit { account: deposit_account, amount: deposit_amount }; + let details = ItemDetails { + owner: item_owner, + approvals: ApprovalsOf::::default(), + deposit, + }; + Item::::insert(&collection, &item, details); + Ok(()) + }, + )?; + + Self::deposit_event(Event::Issued { collection, item, owner: mint_to }); + Ok(()) + } + + pub fn do_burn( + collection: T::CollectionId, + item: T::ItemId, + with_details: impl FnOnce(&ItemDetailsFor) -> DispatchResult, + ) -> DispatchResult { + 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(&details)?; + + // Return the deposit. + T::Currency::unreserve(&details.deposit.account, details.deposit.amount); + collection_details.items.saturating_dec(); + Ok(details.owner) + }, + )?; + + Item::::remove(&collection, &item); + Account::::remove((&owner, &collection, &item)); + ItemPriceOf::::remove(&collection, &item); + PendingSwapOf::::remove(&collection, &item); + ItemAttributesApprovalsOf::::remove(&collection, &item); + + // NOTE: if item's settings are not empty (e.g. item's metadata is locked) + // then we keep the record and don't remove it + let config = Self::get_item_config(&collection, &item)?; + if !config.has_disabled_settings() { + ItemConfigOf::::remove(&collection, &item); + } + + Self::deposit_event(Event::Burned { collection, item, owner }); + Ok(()) + } +} diff --git a/frame/nfts/src/features/lock.rs b/frame/nfts/src/features/lock.rs new file mode 100644 index 0000000000000..e96a30dfd2c7c --- /dev/null +++ b/frame/nfts/src/features/lock.rs @@ -0,0 +1,120 @@ +// 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::*; +use frame_support::pallet_prelude::*; + +impl, I: 'static> Pallet { + pub(crate) fn do_lock_collection( + origin: T::AccountId, + collection: T::CollectionId, + lock_settings: CollectionSettings, + ) -> DispatchResult { + ensure!( + Self::has_role(&collection, &origin, CollectionRole::Freezer), + Error::::NoPermission + ); + ensure!( + !lock_settings.is_disabled(CollectionSetting::DepositRequired), + Error::::WrongSetting + ); + CollectionConfigOf::::try_mutate(collection, |maybe_config| { + let config = maybe_config.as_mut().ok_or(Error::::NoConfig)?; + + for setting in lock_settings.get_disabled() { + config.disable_setting(setting); + } + + Self::deposit_event(Event::::CollectionLocked { collection }); + Ok(()) + }) + } + + pub(crate) fn do_lock_item_transfer( + origin: T::AccountId, + collection: T::CollectionId, + item: T::ItemId, + ) -> DispatchResult { + ensure!( + Self::has_role(&collection, &origin, CollectionRole::Freezer), + Error::::NoPermission + ); + + let mut config = Self::get_item_config(&collection, &item)?; + if !config.has_disabled_setting(ItemSetting::Transferable) { + config.disable_setting(ItemSetting::Transferable); + } + ItemConfigOf::::insert(&collection, &item, config); + + Self::deposit_event(Event::::ItemTransferLocked { collection, item }); + Ok(()) + } + + pub(crate) fn do_unlock_item_transfer( + origin: T::AccountId, + collection: T::CollectionId, + item: T::ItemId, + ) -> DispatchResult { + ensure!( + Self::has_role(&collection, &origin, CollectionRole::Freezer), + Error::::NoPermission + ); + + let mut config = Self::get_item_config(&collection, &item)?; + if config.has_disabled_setting(ItemSetting::Transferable) { + config.enable_setting(ItemSetting::Transferable); + } + ItemConfigOf::::insert(&collection, &item, config); + + Self::deposit_event(Event::::ItemTransferUnlocked { collection, item }); + Ok(()) + } + + pub(crate) fn do_lock_item_properties( + maybe_check_owner: Option, + collection: T::CollectionId, + item: T::ItemId, + lock_metadata: bool, + lock_attributes: bool, + ) -> DispatchResult { + let collection_details = + Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; + + if let Some(check_owner) = &maybe_check_owner { + ensure!(check_owner == &collection_details.owner, Error::::NoPermission); + } + + ItemConfigOf::::try_mutate(collection, item, |maybe_config| { + let config = maybe_config.as_mut().ok_or(Error::::UnknownItem)?; + + if lock_metadata { + config.disable_setting(ItemSetting::UnlockedMetadata); + } + if lock_attributes { + config.disable_setting(ItemSetting::UnlockedAttributes); + } + + Self::deposit_event(Event::::ItemPropertiesLocked { + collection, + item, + lock_metadata, + lock_attributes, + }); + Ok(()) + }) + } +} diff --git a/frame/nfts/src/features/metadata.rs b/frame/nfts/src/features/metadata.rs new file mode 100644 index 0000000000000..942f377141a33 --- /dev/null +++ b/frame/nfts/src/features/metadata.rs @@ -0,0 +1,173 @@ +// 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::*; +use frame_support::pallet_prelude::*; + +impl, I: 'static> Pallet { + pub(crate) fn do_set_item_metadata( + maybe_check_owner: Option, + collection: T::CollectionId, + item: T::ItemId, + data: BoundedVec, + ) -> DispatchResult { + let mut collection_details = + Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; + + let item_config = Self::get_item_config(&collection, &item)?; + ensure!( + maybe_check_owner.is_none() || + item_config.is_setting_enabled(ItemSetting::UnlockedMetadata), + Error::::LockedItemMetadata + ); + + if let Some(check_owner) = &maybe_check_owner { + ensure!(check_owner == &collection_details.owner, Error::::NoPermission); + } + + let collection_config = Self::get_collection_config(&collection)?; + + ItemMetadataOf::::try_mutate_exists(collection, item, |metadata| { + if metadata.is_none() { + collection_details.item_metadatas.saturating_inc(); + } + let old_deposit = metadata.take().map_or(Zero::zero(), |m| m.deposit); + collection_details.owner_deposit.saturating_reduce(old_deposit); + let mut deposit = Zero::zero(); + if collection_config.is_setting_enabled(CollectionSetting::DepositRequired) && + 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(&collection_details.owner, deposit - old_deposit)?; + } else if deposit < old_deposit { + T::Currency::unreserve(&collection_details.owner, old_deposit - deposit); + } + collection_details.owner_deposit.saturating_accrue(deposit); + + *metadata = Some(ItemMetadata { deposit, data: data.clone() }); + + Collection::::insert(&collection, &collection_details); + Self::deposit_event(Event::ItemMetadataSet { collection, item, data }); + Ok(()) + }) + } + + pub(crate) fn do_clear_item_metadata( + maybe_check_owner: Option, + collection: T::CollectionId, + item: T::ItemId, + ) -> DispatchResult { + let mut collection_details = + Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; + if let Some(check_owner) = &maybe_check_owner { + ensure!(check_owner == &collection_details.owner, Error::::NoPermission); + } + + // NOTE: if the item was previously burned, the ItemConfigOf record might not exist + let is_locked = Self::get_item_config(&collection, &item) + .map_or(false, |c| c.has_disabled_setting(ItemSetting::UnlockedMetadata)); + + ensure!(maybe_check_owner.is_none() || !is_locked, Error::::LockedItemMetadata); + + ItemMetadataOf::::try_mutate_exists(collection, item, |metadata| { + if metadata.is_some() { + collection_details.item_metadatas.saturating_dec(); + } + let deposit = metadata.take().ok_or(Error::::UnknownItem)?.deposit; + T::Currency::unreserve(&collection_details.owner, deposit); + collection_details.owner_deposit.saturating_reduce(deposit); + + Collection::::insert(&collection, &collection_details); + Self::deposit_event(Event::ItemMetadataCleared { collection, item }); + Ok(()) + }) + } + + pub(crate) fn do_set_collection_metadata( + maybe_check_owner: Option, + collection: T::CollectionId, + data: BoundedVec, + ) -> DispatchResult { + let collection_config = Self::get_collection_config(&collection)?; + ensure!( + maybe_check_owner.is_none() || + collection_config.is_setting_enabled(CollectionSetting::UnlockedMetadata), + Error::::LockedCollectionMetadata + ); + + 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); + } + + CollectionMetadataOf::::try_mutate_exists(collection, |metadata| { + let old_deposit = metadata.take().map_or(Zero::zero(), |m| m.deposit); + details.owner_deposit.saturating_reduce(old_deposit); + let mut deposit = Zero::zero(); + if maybe_check_owner.is_some() && + collection_config.is_setting_enabled(CollectionSetting::DepositRequired) + { + deposit = T::DepositPerByte::get() + .saturating_mul(((data.len()) as u32).into()) + .saturating_add(T::MetadataDepositBase::get()); + } + if deposit > old_deposit { + T::Currency::reserve(&details.owner, deposit - old_deposit)?; + } else if deposit < old_deposit { + T::Currency::unreserve(&details.owner, old_deposit - deposit); + } + details.owner_deposit.saturating_accrue(deposit); + + Collection::::insert(&collection, details); + + *metadata = Some(CollectionMetadata { deposit, data: data.clone() }); + + Self::deposit_event(Event::CollectionMetadataSet { collection, data }); + Ok(()) + }) + } + + pub(crate) fn do_clear_collection_metadata( + maybe_check_owner: Option, + collection: T::CollectionId, + ) -> DispatchResult { + let details = + Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; + if let Some(check_owner) = &maybe_check_owner { + ensure!(check_owner == &details.owner, Error::::NoPermission); + } + + let collection_config = Self::get_collection_config(&collection)?; + ensure!( + maybe_check_owner.is_none() || + collection_config.is_setting_enabled(CollectionSetting::UnlockedMetadata), + Error::::LockedCollectionMetadata + ); + + CollectionMetadataOf::::try_mutate_exists(collection, |metadata| { + let deposit = metadata.take().ok_or(Error::::UnknownCollection)?.deposit; + T::Currency::unreserve(&details.owner, deposit); + Self::deposit_event(Event::CollectionMetadataCleared { collection }); + Ok(()) + }) + } +} diff --git a/frame/nfts/src/features/mod.rs b/frame/nfts/src/features/mod.rs new file mode 100644 index 0000000000000..b77ee9bf2491b --- /dev/null +++ b/frame/nfts/src/features/mod.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. + +pub mod approvals; +pub mod atomic_swap; +pub mod attributes; +pub mod buy_sell; +pub mod create_delete_collection; +pub mod create_delete_item; +pub mod lock; +pub mod metadata; +pub mod roles; +pub mod settings; +pub mod transfer; diff --git a/frame/nfts/src/features/roles.rs b/frame/nfts/src/features/roles.rs new file mode 100644 index 0000000000000..d6be9965a5e74 --- /dev/null +++ b/frame/nfts/src/features/roles.rs @@ -0,0 +1,99 @@ +// 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::*; +use frame_support::pallet_prelude::*; +use sp_std::collections::btree_map::BTreeMap; + +impl, I: 'static> Pallet { + pub(crate) fn do_set_team( + maybe_check_owner: Option, + collection: T::CollectionId, + issuer: T::AccountId, + admin: T::AccountId, + freezer: T::AccountId, + ) -> DispatchResult { + Collection::::try_mutate(collection, |maybe_details| { + let details = maybe_details.as_mut().ok_or(Error::::UnknownCollection)?; + if let Some(check_origin) = maybe_check_owner { + ensure!(check_origin == details.owner, Error::::NoPermission); + } + + // delete previous values + Self::clear_roles(&collection)?; + + let account_to_role = Self::group_roles_by_account(vec![ + (issuer.clone(), CollectionRole::Issuer), + (admin.clone(), CollectionRole::Admin), + (freezer.clone(), CollectionRole::Freezer), + ]); + for (account, roles) in account_to_role { + CollectionRoleOf::::insert(&collection, &account, roles); + } + + Self::deposit_event(Event::TeamChanged { collection, issuer, admin, freezer }); + Ok(()) + }) + } + + /// Clears all the roles in a specified collection. + /// + /// - `collection_id`: A collection to clear the roles in. + /// + /// Throws an error if some of the roles were left in storage. + /// This means the `CollectionRoles::max_roles()` needs to be adjusted. + pub(crate) fn clear_roles(collection_id: &T::CollectionId) -> Result<(), DispatchError> { + let res = CollectionRoleOf::::clear_prefix( + &collection_id, + CollectionRoles::max_roles() as u32, + None, + ); + ensure!(res.maybe_cursor.is_none(), Error::::RolesNotCleared); + Ok(()) + } + + /// Returns true if a specified account has a provided role within that collection. + /// + /// - `collection_id`: A collection to check the role in. + /// - `account_id`: An account to check the role for. + /// - `role`: A role to validate. + /// + /// Returns boolean. + pub(crate) fn has_role( + collection_id: &T::CollectionId, + account_id: &T::AccountId, + role: CollectionRole, + ) -> bool { + CollectionRoleOf::::get(&collection_id, &account_id) + .map_or(false, |roles| roles.has_role(role)) + } + + /// Groups provided roles by account, given one account could have multiple roles. + /// + /// - `input`: A vector of (Account, Role) tuples. + /// + /// Returns a grouped vector. + pub fn group_roles_by_account( + input: Vec<(T::AccountId, CollectionRole)>, + ) -> Vec<(T::AccountId, CollectionRoles)> { + let mut result = BTreeMap::new(); + for (account, role) in input.into_iter() { + result.entry(account).or_insert(CollectionRoles::none()).add_role(role); + } + result.into_iter().collect() + } +} diff --git a/frame/nfts/src/features/settings.rs b/frame/nfts/src/features/settings.rs new file mode 100644 index 0000000000000..5f408ed183c35 --- /dev/null +++ b/frame/nfts/src/features/settings.rs @@ -0,0 +1,103 @@ +// 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::*; +use frame_support::pallet_prelude::*; + +impl, I: 'static> Pallet { + pub(crate) fn do_force_collection_config( + collection: T::CollectionId, + config: CollectionConfigFor, + ) -> DispatchResult { + ensure!(Collection::::contains_key(&collection), Error::::UnknownCollection); + CollectionConfigOf::::insert(&collection, config); + Self::deposit_event(Event::CollectionConfigChanged { collection }); + Ok(()) + } + + pub(crate) fn do_set_collection_max_supply( + maybe_check_owner: Option, + collection: T::CollectionId, + max_supply: u32, + ) -> DispatchResult { + let collection_config = Self::get_collection_config(&collection)?; + ensure!( + collection_config.is_setting_enabled(CollectionSetting::UnlockedMaxSupply), + Error::::MaxSupplyLocked + ); + + 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); + + CollectionConfigOf::::try_mutate(collection, |maybe_config| { + let config = maybe_config.as_mut().ok_or(Error::::NoConfig)?; + config.max_supply = Some(max_supply); + Self::deposit_event(Event::CollectionMaxSupplySet { collection, max_supply }); + Ok(()) + }) + } + + pub(crate) fn do_update_mint_settings( + maybe_check_owner: Option, + collection: T::CollectionId, + mint_settings: MintSettings< + BalanceOf, + ::BlockNumber, + T::CollectionId, + >, + ) -> DispatchResult { + let details = + Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; + if let Some(check_owner) = &maybe_check_owner { + ensure!(check_owner == &details.owner, Error::::NoPermission); + } + + CollectionConfigOf::::try_mutate(collection, |maybe_config| { + let config = maybe_config.as_mut().ok_or(Error::::NoConfig)?; + config.mint_settings = mint_settings; + Self::deposit_event(Event::CollectionMintSettingsUpdated { collection }); + Ok(()) + }) + } + + pub(crate) fn get_collection_config( + collection_id: &T::CollectionId, + ) -> Result, DispatchError> { + let config = + CollectionConfigOf::::get(&collection_id).ok_or(Error::::NoConfig)?; + Ok(config) + } + + pub(crate) fn get_item_config( + collection_id: &T::CollectionId, + item_id: &T::ItemId, + ) -> Result { + let config = ItemConfigOf::::get(&collection_id, &item_id) + .ok_or(Error::::UnknownItem)?; + Ok(config) + } + + pub(crate) fn is_pallet_feature_enabled(feature: PalletFeature) -> bool { + let features = T::Features::get(); + return features.is_enabled(feature) + } +} diff --git a/frame/nfts/src/features/transfer.rs b/frame/nfts/src/features/transfer.rs new file mode 100644 index 0000000000000..7d6ae3553a361 --- /dev/null +++ b/frame/nfts/src/features/transfer.rs @@ -0,0 +1,166 @@ +// 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::*; +use frame_support::pallet_prelude::*; + +impl, I: 'static> Pallet { + pub fn do_transfer( + collection: T::CollectionId, + item: T::ItemId, + dest: T::AccountId, + with_details: impl FnOnce( + &CollectionDetailsFor, + &mut ItemDetailsFor, + ) -> DispatchResult, + ) -> DispatchResult { + let collection_details = + Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; + ensure!(!T::Locker::is_locked(collection, item), Error::::ItemLocked); + + let collection_config = Self::get_collection_config(&collection)?; + ensure!( + collection_config.is_setting_enabled(CollectionSetting::TransferableItems), + Error::::ItemsNonTransferable + ); + + let item_config = Self::get_item_config(&collection, &item)?; + ensure!( + item_config.is_setting_enabled(ItemSetting::Transferable), + Error::::ItemLocked + ); + + let mut details = + Item::::get(&collection, &item).ok_or(Error::::UnknownItem)?; + with_details(&collection_details, &mut details)?; + + if details.deposit.account == details.owner { + // Move the deposit to the new owner. + T::Currency::repatriate_reserved( + &details.owner, + &dest, + details.deposit.amount, + Reserved, + )?; + } + + Account::::remove((&details.owner, &collection, &item)); + Account::::insert((&dest, &collection, &item), ()); + let origin = details.owner; + details.owner = dest; + + // The approved accounts have 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.approvals.clear(); + + Item::::insert(&collection, &item, &details); + ItemPriceOf::::remove(&collection, &item); + PendingSwapOf::::remove(&collection, &item); + + Self::deposit_event(Event::Transferred { + collection, + item, + from: origin, + to: details.owner, + }); + Ok(()) + } + + pub(crate) fn do_transfer_ownership( + origin: T::AccountId, + collection: T::CollectionId, + owner: T::AccountId, + ) -> DispatchResult { + let acceptable_collection = OwnershipAcceptance::::get(&owner); + ensure!(acceptable_collection.as_ref() == Some(&collection), Error::::Unaccepted); + + 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(()) + } + + // Move the deposit to the new owner. + T::Currency::repatriate_reserved( + &details.owner, + &owner, + details.owner_deposit, + Reserved, + )?; + CollectionAccount::::remove(&details.owner, &collection); + CollectionAccount::::insert(&owner, &collection, ()); + + details.owner = owner.clone(); + OwnershipAcceptance::::remove(&owner); + + Self::deposit_event(Event::OwnerChanged { collection, new_owner: owner }); + Ok(()) + }) + } + + pub(crate) fn do_set_accept_ownership( + who: T::AccountId, + maybe_collection: Option, + ) -> DispatchResult { + let old = OwnershipAcceptance::::get(&who); + match (old.is_some(), maybe_collection.is_some()) { + (false, true) => { + frame_system::Pallet::::inc_consumers(&who)?; + }, + (true, false) => { + frame_system::Pallet::::dec_consumers(&who); + }, + _ => {}, + } + if let Some(collection) = maybe_collection.as_ref() { + OwnershipAcceptance::::insert(&who, collection); + } else { + OwnershipAcceptance::::remove(&who); + } + Self::deposit_event(Event::OwnershipAcceptanceChanged { who, maybe_collection }); + Ok(()) + } + + pub(crate) fn do_force_collection_owner( + collection: T::CollectionId, + owner: T::AccountId, + ) -> DispatchResult { + Collection::::try_mutate(collection, |maybe_details| { + let details = maybe_details.as_mut().ok_or(Error::::UnknownCollection)?; + if details.owner == owner { + return Ok(()) + } + + // Move the deposit to the new owner. + T::Currency::repatriate_reserved( + &details.owner, + &owner, + details.owner_deposit, + Reserved, + )?; + + CollectionAccount::::remove(&details.owner, &collection); + CollectionAccount::::insert(&owner, &collection, ()); + details.owner = owner.clone(); + + Self::deposit_event(Event::OwnerChanged { collection, new_owner: owner }); + Ok(()) + }) + } +} diff --git a/frame/nfts/src/impl_nonfungibles.rs b/frame/nfts/src/impl_nonfungibles.rs new file mode 100644 index 0000000000000..edfc29710b7da --- /dev/null +++ b/frame/nfts/src/impl_nonfungibles.rs @@ -0,0 +1,289 @@ +// 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. + +//! Implementations for `nonfungibles` traits. + +use super::*; +use frame_support::{ + ensure, + storage::KeyPrefixIterator, + traits::{tokens::nonfungibles_v2::*, Get}, + BoundedSlice, +}; +use sp_runtime::{DispatchError, DispatchResult}; +use sp_std::prelude::*; + +impl, I: 'static> Inspect<::AccountId> for Pallet { + type ItemId = T::ItemId; + type CollectionId = T::CollectionId; + + fn owner( + collection: &Self::CollectionId, + item: &Self::ItemId, + ) -> Option<::AccountId> { + Item::::get(collection, item).map(|a| a.owner) + } + + fn collection_owner(collection: &Self::CollectionId) -> Option<::AccountId> { + Collection::::get(collection).map(|a| a.owner) + } + + /// Returns the attribute value of `item` of `collection` corresponding to `key`. + /// + /// When `key` is empty, we return the item metadata value. + /// + /// By default this is `None`; no attributes are defined. + fn attribute( + collection: &Self::CollectionId, + item: &Self::ItemId, + namespace: &AttributeNamespace<::AccountId>, + key: &[u8], + ) -> Option> { + if key.is_empty() { + // 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((collection, Some(item), namespace, key)).map(|a| a.0.into()) + } + } + + /// Returns the attribute value of `item` of `collection` corresponding to `key`. + /// + /// When `key` is empty, we return the item metadata value. + /// + /// By default this is `None`; no attributes are defined. + fn collection_attribute(collection: &Self::CollectionId, key: &[u8]) -> Option> { + if key.is_empty() { + // 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(( + collection, + Option::::None, + AttributeNamespace::CollectionOwner, + key, + )) + .map(|a| a.0.into()) + } + } + + /// Returns `true` if the `item` of `collection` may be transferred. + /// + /// Default implementation is that all items are transferable. + fn can_transfer(collection: &Self::CollectionId, item: &Self::ItemId) -> bool { + match ( + CollectionConfigOf::::get(collection), + ItemConfigOf::::get(collection, item), + ) { + (Some(cc), Some(ic)) + if cc.is_setting_enabled(CollectionSetting::TransferableItems) && + ic.is_setting_enabled(ItemSetting::Transferable) => + true, + _ => false, + } + } +} + +impl, I: 'static> Create<::AccountId, CollectionConfigFor> + for Pallet +{ + /// Create a `collection` of nonfungible items to be owned by `who` and managed by `admin`. + fn create_collection( + who: &T::AccountId, + admin: &T::AccountId, + config: &CollectionConfigFor, + ) -> Result { + // DepositRequired can be disabled by calling the force_create() only + ensure!( + !config.has_disabled_setting(CollectionSetting::DepositRequired), + Error::::WrongSetting + ); + + let collection = + NextCollectionId::::get().unwrap_or(T::CollectionId::initial_value()); + + Self::do_create_collection( + collection, + who.clone(), + admin.clone(), + *config, + T::CollectionDeposit::get(), + Event::Created { collection, creator: who.clone(), owner: admin.clone() }, + )?; + Ok(collection) + } +} + +impl, I: 'static> Destroy<::AccountId> for Pallet { + type DestroyWitness = DestroyWitness; + + fn get_destroy_witness(collection: &Self::CollectionId) -> Option { + Collection::::get(collection).map(|a| a.destroy_witness()) + } + + fn destroy( + collection: Self::CollectionId, + witness: Self::DestroyWitness, + maybe_check_owner: Option, + ) -> Result { + Self::do_destroy_collection(collection, witness, maybe_check_owner) + } +} + +impl, I: 'static> Mutate<::AccountId, ItemConfig> for Pallet { + fn mint_into( + collection: &Self::CollectionId, + item: &Self::ItemId, + who: &T::AccountId, + item_config: &ItemConfig, + deposit_collection_owner: bool, + ) -> DispatchResult { + Self::do_mint( + *collection, + *item, + who.clone(), + who.clone(), + *item_config, + deposit_collection_owner, + |_, _| Ok(()), + ) + } + + fn burn( + collection: &Self::CollectionId, + item: &Self::ItemId, + maybe_check_owner: Option<&T::AccountId>, + ) -> DispatchResult { + Self::do_burn(*collection, *item, |d| { + if let Some(check_owner) = maybe_check_owner { + if &d.owner != check_owner { + return Err(Error::::NoPermission.into()) + } + } + Ok(()) + }) + } + + fn set_attribute( + collection: &Self::CollectionId, + item: &Self::ItemId, + key: &[u8], + value: &[u8], + ) -> DispatchResult { + Self::do_force_set_attribute( + None, + *collection, + Some(*item), + AttributeNamespace::Pallet, + Self::construct_attribute_key(key.to_vec())?, + Self::construct_attribute_value(value.to_vec())?, + ) + } + + fn set_typed_attribute( + collection: &Self::CollectionId, + item: &Self::ItemId, + key: &K, + value: &V, + ) -> DispatchResult { + key.using_encoded(|k| { + value.using_encoded(|v| { + >::set_attribute(collection, item, k, v) + }) + }) + } + + fn set_collection_attribute( + collection: &Self::CollectionId, + key: &[u8], + value: &[u8], + ) -> DispatchResult { + Self::do_force_set_attribute( + None, + *collection, + None, + AttributeNamespace::Pallet, + Self::construct_attribute_key(key.to_vec())?, + Self::construct_attribute_value(value.to_vec())?, + ) + } + + fn set_typed_collection_attribute( + collection: &Self::CollectionId, + key: &K, + value: &V, + ) -> DispatchResult { + key.using_encoded(|k| { + value.using_encoded(|v| { + >::set_collection_attribute( + collection, k, v, + ) + }) + }) + } +} + +impl, I: 'static> Transfer for Pallet { + fn transfer( + collection: &Self::CollectionId, + item: &Self::ItemId, + destination: &T::AccountId, + ) -> DispatchResult { + Self::do_transfer(*collection, *item, destination.clone(), |_, _| Ok(())) + } +} + +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() -> Self::CollectionsIterator { + Collection::::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) -> Self::ItemsIterator { + Item::::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) -> Self::OwnedIterator { + Account::::iter_key_prefix((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_collection( + collection: &Self::CollectionId, + who: &T::AccountId, + ) -> Self::OwnedInCollectionIterator { + Account::::iter_key_prefix((who, collection)) + } +} diff --git a/frame/nfts/src/lib.rs b/frame/nfts/src/lib.rs new file mode 100644 index 0000000000000..2006d78959c4d --- /dev/null +++ b/frame/nfts/src/lib.rs @@ -0,0 +1,1769 @@ +// 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. + +//! # Nfts Module +//! +//! A simple, secure module for dealing with non-fungible items. +//! +//! ## Related Modules +//! +//! * [`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)] + +#[cfg(feature = "runtime-benchmarks")] +mod benchmarking; +#[cfg(test)] +pub mod mock; +#[cfg(test)] +mod tests; + +mod common_functions; +mod features; +mod impl_nonfungibles; +mod types; + +pub mod macros; +pub mod weights; + +use codec::{Decode, Encode}; +use frame_support::traits::{ + tokens::{AttributeNamespace, Locker}, + BalanceStatus::Reserved, + Currency, EnsureOriginWithArg, ReservableCurrency, +}; +use frame_system::Config as SystemConfig; +use sp_runtime::{ + traits::{Saturating, StaticLookup, Zero}, + RuntimeDebug, +}; +use sp_std::prelude::*; + +pub use pallet::*; +pub use types::*; +pub use weights::WeightInfo; + +type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; + +#[frame_support::pallet] +pub mod pallet { + use super::*; + use frame_support::{pallet_prelude::*, traits::ExistenceRequirement}; + use frame_system::pallet_prelude::*; + + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + pub struct Pallet(_); + + #[cfg(feature = "runtime-benchmarks")] + pub trait BenchmarkHelper { + fn collection(i: u16) -> CollectionId; + fn item(i: u16) -> ItemId; + } + #[cfg(feature = "runtime-benchmarks")] + impl, ItemId: From> BenchmarkHelper for () { + fn collection(i: u16) -> CollectionId { + i.into() + } + fn item(i: u16) -> ItemId { + i.into() + } + } + + #[pallet::config] + /// The module configuration trait. + pub trait Config: frame_system::Config { + /// The overarching event type. + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; + + /// Identifier for the collection of item. + type CollectionId: Member + Parameter + MaxEncodedLen + Copy + Incrementable; + + /// 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 item or otherwise alter privileged + /// attributes. + 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::RuntimeOrigin, + Self::CollectionId, + Success = Self::AccountId, + >; + + /// Locker trait to enable Locking mechanism downstream. + type Locker: Locker; + + /// The basic amount of funds that must be reserved for collection. + #[pallet::constant] + type CollectionDeposit: Get>; + + /// The basic amount of funds that must be reserved for an item. + #[pallet::constant] + type ItemDeposit: Get>; + + /// 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 item. + #[pallet::constant] + type AttributeDepositBase: Get>; + + /// The additional funds that must be reserved for the number of bytes store in metadata, + /// either "normal" metadata or attribute metadata. + #[pallet::constant] + type DepositPerByte: Get>; + + /// The maximum length of data stored on-chain. + #[pallet::constant] + type StringLimit: Get; + + /// The maximum length of an attribute key. + #[pallet::constant] + type KeyLimit: Get; + + /// The maximum length of an attribute value. + #[pallet::constant] + type ValueLimit: Get; + + /// The maximum approvals an item could have. + #[pallet::constant] + type ApprovalsLimit: Get; + + /// The maximum attributes approvals an item could have. + #[pallet::constant] + type ItemAttributesApprovalsLimit: Get; + + /// The max number of tips a user could send. + #[pallet::constant] + type MaxTips: Get; + + /// The max duration in blocks for deadlines. + #[pallet::constant] + type MaxDeadlineDuration: Get<::BlockNumber>; + + /// Disables some of pallet's features. + #[pallet::constant] + type Features: 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; + } + + /// Details of a collection. + #[pallet::storage] + pub(super) type Collection, I: 'static = ()> = StorageMap< + _, + Blake2_128Concat, + T::CollectionId, + CollectionDetails>, + >; + + /// The collection, if any, of which an account is willing to take ownership. + #[pallet::storage] + pub(super) type OwnershipAcceptance, I: 'static = ()> = + StorageMap<_, Blake2_128Concat, T::AccountId, T::CollectionId>; + + /// The items held by any given account; set out this way so that items owned by a single + /// account can be enumerated. + #[pallet::storage] + pub(super) type Account, I: 'static = ()> = StorageNMap< + _, + ( + NMapKey, // owner + NMapKey, + NMapKey, + ), + (), + OptionQuery, + >; + + /// The collections owned by any given account; set out this way so that collections owned by + /// a single account can be enumerated. + #[pallet::storage] + pub(super) type CollectionAccount, I: 'static = ()> = StorageDoubleMap< + _, + Blake2_128Concat, + T::AccountId, + Blake2_128Concat, + T::CollectionId, + (), + OptionQuery, + >; + + /// The items in existence and their ownership details. + #[pallet::storage] + /// Stores collection roles as per account. + pub(super) type CollectionRoleOf, I: 'static = ()> = StorageDoubleMap< + _, + Blake2_128Concat, + T::CollectionId, + Blake2_128Concat, + T::AccountId, + CollectionRoles, + OptionQuery, + >; + + /// The items in existence and their ownership details. + #[pallet::storage] + pub(super) type Item, I: 'static = ()> = StorageDoubleMap< + _, + Blake2_128Concat, + T::CollectionId, + Blake2_128Concat, + T::ItemId, + ItemDetails, ApprovalsOf>, + OptionQuery, + >; + + /// Metadata of a collection. + #[pallet::storage] + pub(super) type CollectionMetadataOf, I: 'static = ()> = StorageMap< + _, + Blake2_128Concat, + T::CollectionId, + CollectionMetadata, T::StringLimit>, + OptionQuery, + >; + + /// Metadata of an item. + #[pallet::storage] + pub(super) type ItemMetadataOf, I: 'static = ()> = StorageDoubleMap< + _, + Blake2_128Concat, + T::CollectionId, + Blake2_128Concat, + T::ItemId, + ItemMetadata, T::StringLimit>, + OptionQuery, + >; + + /// Attributes of a collection. + #[pallet::storage] + pub(super) type Attribute, I: 'static = ()> = StorageNMap< + _, + ( + NMapKey, + NMapKey>, + NMapKey>, + NMapKey>, + ), + (BoundedVec, AttributeDepositOf), + OptionQuery, + >; + + /// A price of an item. + #[pallet::storage] + pub(super) type ItemPriceOf, I: 'static = ()> = StorageDoubleMap< + _, + Blake2_128Concat, + T::CollectionId, + Blake2_128Concat, + T::ItemId, + (ItemPrice, Option), + OptionQuery, + >; + + /// Item attribute approvals. + #[pallet::storage] + pub(super) type ItemAttributesApprovalsOf, I: 'static = ()> = StorageDoubleMap< + _, + Blake2_128Concat, + T::CollectionId, + Blake2_128Concat, + T::ItemId, + ItemAttributesApprovals, + ValueQuery, + >; + + /// Stores the `CollectionId` that is going to be used for the next collection. + /// This gets incremented whenever a new collection is created. + #[pallet::storage] + pub(super) type NextCollectionId, I: 'static = ()> = + StorageValue<_, T::CollectionId, OptionQuery>; + + /// Handles all the pending swaps. + #[pallet::storage] + pub(super) type PendingSwapOf, I: 'static = ()> = StorageDoubleMap< + _, + Blake2_128Concat, + T::CollectionId, + Blake2_128Concat, + T::ItemId, + PendingSwap< + T::CollectionId, + T::ItemId, + PriceWithDirection>, + ::BlockNumber, + >, + OptionQuery, + >; + + /// Config of a collection. + #[pallet::storage] + pub(super) type CollectionConfigOf, I: 'static = ()> = + StorageMap<_, Blake2_128Concat, T::CollectionId, CollectionConfigFor, OptionQuery>; + + /// Config of an item. + #[pallet::storage] + pub(super) type ItemConfigOf, I: 'static = ()> = StorageDoubleMap< + _, + Blake2_128Concat, + T::CollectionId, + Blake2_128Concat, + T::ItemId, + ItemConfig, + OptionQuery, + >; + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event, I: 'static = ()> { + /// 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 { + collection: T::CollectionId, + item: T::ItemId, + from: T::AccountId, + to: T::AccountId, + }, + /// An `item` was destroyed. + Burned { collection: T::CollectionId, item: T::ItemId, owner: T::AccountId }, + /// An `item` became non-transferable. + ItemTransferLocked { collection: T::CollectionId, item: T::ItemId }, + /// An `item` became transferable. + ItemTransferUnlocked { collection: T::CollectionId, item: T::ItemId }, + /// `item` metadata or attributes were locked. + ItemPropertiesLocked { + collection: T::CollectionId, + item: T::ItemId, + lock_metadata: bool, + lock_attributes: bool, + }, + /// Some `collection` was locked. + CollectionLocked { collection: T::CollectionId }, + /// The owner changed. + OwnerChanged { collection: T::CollectionId, new_owner: T::AccountId }, + /// The management team changed. + TeamChanged { + collection: T::CollectionId, + issuer: T::AccountId, + admin: T::AccountId, + freezer: T::AccountId, + }, + /// An `item` of a `collection` has been approved by the `owner` for transfer by + /// a `delegate`. + TransferApproved { + collection: T::CollectionId, + item: T::ItemId, + owner: T::AccountId, + delegate: T::AccountId, + deadline: Option<::BlockNumber>, + }, + /// An approval for a `delegate` account to transfer the `item` of an item + /// `collection` was cancelled by its `owner`. + ApprovalCancelled { + collection: T::CollectionId, + item: T::ItemId, + owner: T::AccountId, + delegate: T::AccountId, + }, + /// All approvals of an item got cancelled. + AllApprovalsCancelled { collection: T::CollectionId, item: T::ItemId, owner: T::AccountId }, + /// A `collection` has had its config changed by the `Force` origin. + CollectionConfigChanged { collection: T::CollectionId }, + /// New metadata has been set for a `collection`. + CollectionMetadataSet { collection: T::CollectionId, data: BoundedVec }, + /// Metadata has been cleared for a `collection`. + CollectionMetadataCleared { collection: T::CollectionId }, + /// New metadata has been set for an item. + ItemMetadataSet { + collection: T::CollectionId, + item: T::ItemId, + data: BoundedVec, + }, + /// Metadata has been cleared for an item. + ItemMetadataCleared { collection: T::CollectionId, item: T::ItemId }, + /// The deposit for a set of `item`s within a `collection` has been updated. + Redeposited { collection: T::CollectionId, successful_items: Vec }, + /// New attribute metadata has been set for a `collection` or `item`. + AttributeSet { + collection: T::CollectionId, + maybe_item: Option, + key: BoundedVec, + value: BoundedVec, + namespace: AttributeNamespace, + }, + /// Attribute metadata has been cleared for a `collection` or `item`. + AttributeCleared { + collection: T::CollectionId, + maybe_item: Option, + key: BoundedVec, + namespace: AttributeNamespace, + }, + /// A new approval to modify item attributes was added. + ItemAttributesApprovalAdded { + collection: T::CollectionId, + item: T::ItemId, + delegate: T::AccountId, + }, + /// A new approval to modify item attributes was removed. + ItemAttributesApprovalRemoved { + collection: T::CollectionId, + item: T::ItemId, + delegate: T::AccountId, + }, + /// 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 }, + /// Mint settings for a collection had changed. + CollectionMintSettingsUpdated { collection: T::CollectionId }, + /// Event gets emitted when the `NextCollectionId` gets incremented. + NextCollectionIdIncremented { next_id: T::CollectionId }, + /// The price was set for the item. + ItemPriceSet { + collection: T::CollectionId, + item: T::ItemId, + price: ItemPrice, + whitelisted_buyer: Option, + }, + /// The price for the item 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, + }, + /// A tip was sent. + TipSent { + collection: T::CollectionId, + item: T::ItemId, + sender: T::AccountId, + receiver: T::AccountId, + amount: DepositBalanceOf, + }, + /// An `item` swap intent was created. + SwapCreated { + offered_collection: T::CollectionId, + offered_item: T::ItemId, + desired_collection: T::CollectionId, + desired_item: Option, + price: Option>>, + deadline: ::BlockNumber, + }, + /// The swap was cancelled. + SwapCancelled { + offered_collection: T::CollectionId, + offered_item: T::ItemId, + desired_collection: T::CollectionId, + desired_item: Option, + price: Option>>, + deadline: ::BlockNumber, + }, + /// The swap has been claimed. + SwapClaimed { + sent_collection: T::CollectionId, + sent_item: T::ItemId, + sent_item_owner: T::AccountId, + received_collection: T::CollectionId, + received_item: T::ItemId, + received_item_owner: T::AccountId, + price: Option>>, + deadline: ::BlockNumber, + }, + } + + #[pallet::error] + pub enum Error { + /// The signing account has no permission to do the operation. + NoPermission, + /// The given item ID is unknown. + UnknownCollection, + /// The item ID has already been used for an item. + AlreadyExists, + /// The approval had a deadline that expired, so the approval isn't valid anymore. + ApprovalExpired, + /// The owner turned out to be different to what was expected. + WrongOwner, + /// The witness data given does not match the current state of the chain. + BadWitness, + /// Collection ID is already taken. + CollectionIdInUse, + /// Items within that collection are non-transferable. + ItemsNonTransferable, + /// The provided account is not a delegate. + NotDelegate, + /// The delegate turned out to be different to what was expected. + WrongDelegate, + /// No approval exists that would allow the transfer. + Unapproved, + /// The named owner has not signed ownership acceptance of the collection. + Unaccepted, + /// The item is locked (non-transferable). + ItemLocked, + /// Item's attributes are locked. + LockedItemAttributes, + /// Collection's attributes are locked. + LockedCollectionAttributes, + /// Item's metadata is locked. + LockedItemMetadata, + /// Collection's metadata is locked. + LockedCollectionMetadata, + /// All items have been minted. + MaxSupplyReached, + /// The max supply is locked and can't be changed. + MaxSupplyLocked, + /// The provided max supply is less than the number of items a collection already has. + MaxSupplyTooSmall, + /// The given item ID is unknown. + UnknownItem, + /// Swap doesn't exist. + UnknownSwap, + /// Item is not for sale. + NotForSale, + /// The provided bid is too low. + BidTooLow, + /// The item has reached its approval limit. + ReachedApprovalLimit, + /// The deadline has already expired. + DeadlineExpired, + /// The duration provided should be less than or equal to `MaxDeadlineDuration`. + WrongDuration, + /// The method is disabled by system settings. + MethodDisabled, + /// The provided setting can't be set. + WrongSetting, + /// Item's config already exists and should be equal to the provided one. + InconsistentItemConfig, + /// Config for a collection or an item can't be found. + NoConfig, + /// Some roles were not cleared. + RolesNotCleared, + /// Mint has not started yet. + MintNotStarted, + /// Mint has already ended. + MintEnded, + /// The provided Item was already used for claiming. + AlreadyClaimed, + /// The provided data is incorrect. + IncorrectData, + } + + #[pallet::call] + impl, I: 'static> Pallet { + /// Issue a new collection of non-fungible items from a public 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. + /// + /// `ItemDeposit` funds of sender are reserved. + /// + /// Parameters: + /// - `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. + /// + /// Weight: `O(1)` + #[pallet::call_index(0)] + #[pallet::weight(T::WeightInfo::create())] + pub fn create( + origin: OriginFor, + admin: AccountIdLookupOf, + config: CollectionConfigFor, + ) -> DispatchResult { + let collection = + NextCollectionId::::get().unwrap_or(T::CollectionId::initial_value()); + + let owner = T::CreateOrigin::ensure_origin(origin, &collection)?; + let admin = T::Lookup::lookup(admin)?; + + // DepositRequired can be disabled by calling the force_create() only + ensure!( + !config.has_disabled_setting(CollectionSetting::DepositRequired), + Error::::WrongSetting + ); + + Self::do_create_collection( + collection, + owner.clone(), + admin.clone(), + config, + T::CollectionDeposit::get(), + Event::Created { collection, creator: owner, owner: admin }, + ) + } + + /// Issue a new collection of non-fungible items from a privileged origin. + /// + /// This new collection has no items initially. + /// + /// The origin must conform to `ForceOrigin`. + /// + /// Unlike `create`, no funds are reserved. + /// + /// - `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. + /// + /// Weight: `O(1)` + #[pallet::call_index(1)] + #[pallet::weight(T::WeightInfo::force_create())] + pub fn force_create( + origin: OriginFor, + owner: AccountIdLookupOf, + config: CollectionConfigFor, + ) -> DispatchResult { + T::ForceOrigin::ensure_origin(origin)?; + let owner = T::Lookup::lookup(owner)?; + + let collection = + NextCollectionId::::get().unwrap_or(T::CollectionId::initial_value()); + + Self::do_create_collection( + collection, + owner.clone(), + owner.clone(), + config, + Zero::zero(), + Event::ForceCreated { collection, owner }, + ) + } + + /// 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 `collection`. + /// + /// - `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.items` + /// - `m = witness.item_metadatas` + /// - `a = witness.attributes` + #[pallet::call_index(2)] + #[pallet::weight(T::WeightInfo::destroy( + witness.items, + witness.item_metadatas, + witness.attributes, + ))] + pub fn destroy( + origin: OriginFor, + collection: T::CollectionId, + witness: DestroyWitness, + ) -> DispatchResultWithPostInfo { + let maybe_check_owner = T::ForceOrigin::try_origin(origin) + .map(|_| None) + .or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?; + let details = Self::do_destroy_collection(collection, witness, maybe_check_owner)?; + + Ok(Some(T::WeightInfo::destroy( + details.items, + details.item_metadatas, + details.attributes, + )) + .into()) + } + + /// Mint an item of a particular collection. + /// + /// The origin must be Signed and the sender must be the Issuer of the `collection`. + /// + /// - `collection`: The collection of the item to be minted. + /// - `item`: An identifier of the new item. + /// - `mint_to`: Account into which the item will be minted. + /// - `witness_data`: When the mint type is `HolderOf(collection_id)`, then the owned + /// item_id from that collection needs to be provided within the witness data object. + /// + /// Note: the deposit will be taken from the `origin` and not the `owner` of the `item`. + /// + /// Emits `Issued` event when successful. + /// + /// Weight: `O(1)` + #[pallet::call_index(3)] + #[pallet::weight(T::WeightInfo::mint())] + pub fn mint( + origin: OriginFor, + collection: T::CollectionId, + item: T::ItemId, + mint_to: AccountIdLookupOf, + witness_data: Option>, + ) -> DispatchResult { + let caller = ensure_signed(origin)?; + let mint_to = T::Lookup::lookup(mint_to)?; + + let collection_config = Self::get_collection_config(&collection)?; + let item_settings = collection_config.mint_settings.default_item_settings; + let item_config = ItemConfig { settings: item_settings }; + + Self::do_mint( + collection, + item, + caller.clone(), + mint_to.clone(), + item_config, + false, + |collection_details, collection_config| { + // Issuer can mint regardless of mint settings + if Self::has_role(&collection, &caller, CollectionRole::Issuer) { + return Ok(()) + } + + let mint_settings = collection_config.mint_settings; + let now = frame_system::Pallet::::block_number(); + + if let Some(start_block) = mint_settings.start_block { + ensure!(start_block <= now, Error::::MintNotStarted); + } + if let Some(end_block) = mint_settings.end_block { + ensure!(end_block >= now, Error::::MintEnded); + } + + match mint_settings.mint_type { + MintType::Issuer => return Err(Error::::NoPermission.into()), + MintType::HolderOf(collection_id) => { + let MintWitness { owner_of_item } = + witness_data.ok_or(Error::::BadWitness)?; + + let has_item = Account::::contains_key(( + &caller, + &collection_id, + &owner_of_item, + )); + ensure!(has_item, Error::::BadWitness); + + let attribute_key = Self::construct_attribute_key( + PalletAttributes::::UsedToClaim(collection) + .encode(), + )?; + + let key = ( + &collection_id, + Some(owner_of_item), + AttributeNamespace::Pallet, + &attribute_key, + ); + let already_claimed = Attribute::::contains_key(key.clone()); + ensure!(!already_claimed, Error::::AlreadyClaimed); + + let value = Self::construct_attribute_value(vec![0])?; + Attribute::::insert( + key, + (value, AttributeDeposit { account: None, amount: Zero::zero() }), + ); + }, + _ => {}, + } + + if let Some(price) = mint_settings.price { + T::Currency::transfer( + &caller, + &collection_details.owner, + price, + ExistenceRequirement::KeepAlive, + )?; + } + + Ok(()) + }, + ) + } + + /// Mint an item of a particular collection from a privileged origin. + /// + /// The origin must conform to `ForceOrigin` or must be `Signed` and the sender must be the + /// Issuer of the `collection`. + /// + /// - `collection`: The collection of the item to be minted. + /// - `item`: An identifier of the new item. + /// - `mint_to`: Account into which the item will be minted. + /// - `item_config`: A config of the new item. + /// + /// Emits `Issued` event when successful. + /// + /// Weight: `O(1)` + #[pallet::call_index(4)] + #[pallet::weight(T::WeightInfo::force_mint())] + pub fn force_mint( + origin: OriginFor, + collection: T::CollectionId, + item: T::ItemId, + mint_to: AccountIdLookupOf, + item_config: ItemConfig, + ) -> DispatchResult { + let maybe_check_origin = T::ForceOrigin::try_origin(origin) + .map(|_| None) + .or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?; + let mint_to = T::Lookup::lookup(mint_to)?; + + if let Some(check_origin) = maybe_check_origin { + ensure!( + Self::has_role(&collection, &check_origin, CollectionRole::Issuer), + Error::::NoPermission + ); + } + Self::do_mint(collection, item, mint_to.clone(), mint_to, item_config, true, |_, _| { + Ok(()) + }) + } + + /// Destroy a single item. + /// + /// Origin must be Signed and the sender should be the Admin of the `collection`. + /// + /// - `collection`: The collection of the item to be burned. + /// - `item`: The item to be burned. + /// - `check_owner`: If `Some` then the operation will fail with `WrongOwner` unless the + /// item is owned by this value. + /// + /// Emits `Burned` with the actual amount burned. + /// + /// Weight: `O(1)` + /// Modes: `check_owner.is_some()`. + #[pallet::call_index(5)] + #[pallet::weight(T::WeightInfo::burn())] + pub fn burn( + origin: OriginFor, + collection: T::CollectionId, + item: T::ItemId, + check_owner: Option>, + ) -> DispatchResult { + let origin = ensure_signed(origin)?; + let check_owner = check_owner.map(T::Lookup::lookup).transpose()?; + + Self::do_burn(collection, item, |details| { + let is_admin = Self::has_role(&collection, &origin, CollectionRole::Admin); + let is_permitted = is_admin || details.owner == origin; + ensure!(is_permitted, Error::::NoPermission); + ensure!( + check_owner.map_or(true, |o| o == details.owner), + Error::::WrongOwner + ); + Ok(()) + }) + } + + /// Move an item from the sender account to another. + /// + /// Origin must be Signed and the signing account must be either: + /// - the Admin of the `collection`; + /// - the Owner of the `item`; + /// - the approved delegate for the `item` (in this case, the approval is reset). + /// + /// Arguments: + /// - `collection`: The collection of the item to be transferred. + /// - `item`: The item to be transferred. + /// - `dest`: The account to receive ownership of the item. + /// + /// Emits `Transferred`. + /// + /// Weight: `O(1)` + #[pallet::call_index(6)] + #[pallet::weight(T::WeightInfo::transfer())] + pub fn transfer( + origin: OriginFor, + collection: T::CollectionId, + item: T::ItemId, + dest: AccountIdLookupOf, + ) -> DispatchResult { + let origin = ensure_signed(origin)?; + let dest = T::Lookup::lookup(dest)?; + + Self::do_transfer(collection, item, dest, |_, details| { + let is_admin = Self::has_role(&collection, &origin, CollectionRole::Admin); + if details.owner != origin && !is_admin { + let deadline = + details.approvals.get(&origin).ok_or(Error::::NoPermission)?; + if let Some(d) = deadline { + let block_number = frame_system::Pallet::::block_number(); + ensure!(block_number <= *d, Error::::ApprovalExpired); + } + } + Ok(()) + }) + } + + /// Re-evaluate the deposits on some items. + /// + /// Origin must be Signed and the sender should be the Owner of the `collection`. + /// + /// - `collection`: The collection of the items to be reevaluated. + /// - `items`: The items of the collection whose deposits will be reevaluated. + /// + /// 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 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 collection is unknown or the signer + /// is not permitted to call it. + /// + /// Weight: `O(items.len())` + #[pallet::call_index(7)] + #[pallet::weight(T::WeightInfo::redeposit(items.len() as u32))] + pub fn redeposit( + origin: OriginFor, + collection: T::CollectionId, + items: Vec, + ) -> DispatchResult { + let origin = ensure_signed(origin)?; + + let collection_details = + Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; + ensure!(collection_details.owner == origin, Error::::NoPermission); + + let config = Self::get_collection_config(&collection)?; + let deposit = match config.is_setting_enabled(CollectionSetting::DepositRequired) { + true => T::ItemDeposit::get(), + false => Zero::zero(), + }; + + 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.amount; + if old > deposit { + T::Currency::unreserve(&details.deposit.account, old - deposit); + } else if deposit > old { + if T::Currency::reserve(&details.deposit.account, 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 + } + details.deposit.amount = deposit; + Item::::insert(&collection, &item, &details); + successful.push(item); + } + + Self::deposit_event(Event::::Redeposited { + collection, + successful_items: successful, + }); + + Ok(()) + } + + /// Disallow further unprivileged transfer of an item. + /// + /// Origin must be Signed and the sender should be the Freezer of the `collection`. + /// + /// - `collection`: The collection of the item to be changed. + /// - `item`: The item to become non-transferable. + /// + /// Emits `ItemTransferLocked`. + /// + /// Weight: `O(1)` + #[pallet::call_index(8)] + #[pallet::weight(T::WeightInfo::lock_item_transfer())] + pub fn lock_item_transfer( + origin: OriginFor, + collection: T::CollectionId, + item: T::ItemId, + ) -> DispatchResult { + let origin = ensure_signed(origin)?; + Self::do_lock_item_transfer(origin, collection, item) + } + + /// Re-allow unprivileged transfer of an item. + /// + /// Origin must be Signed and the sender should be the Freezer of the `collection`. + /// + /// - `collection`: The collection of the item to be changed. + /// - `item`: The item to become transferable. + /// + /// Emits `ItemTransferUnlocked`. + /// + /// Weight: `O(1)` + #[pallet::call_index(9)] + #[pallet::weight(T::WeightInfo::unlock_item_transfer())] + pub fn unlock_item_transfer( + origin: OriginFor, + collection: T::CollectionId, + item: T::ItemId, + ) -> DispatchResult { + let origin = ensure_signed(origin)?; + Self::do_unlock_item_transfer(origin, collection, item) + } + + /// Disallows specified settings for the whole collection. + /// + /// Origin must be Signed and the sender should be the Freezer of the `collection`. + /// + /// - `collection`: The collection to be locked. + /// - `lock_settings`: The settings to be locked. + /// + /// Note: it's possible to only lock(set) the setting, but not to unset it. + /// Emits `CollectionLocked`. + /// + /// Weight: `O(1)` + #[pallet::call_index(10)] + #[pallet::weight(T::WeightInfo::lock_collection())] + pub fn lock_collection( + origin: OriginFor, + collection: T::CollectionId, + lock_settings: CollectionSettings, + ) -> DispatchResult { + let origin = ensure_signed(origin)?; + Self::do_lock_collection(origin, collection, lock_settings) + } + + /// Change the Owner of a collection. + /// + /// Origin must be Signed and the sender should be the Owner of the `collection`. + /// + /// - `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`. + /// + /// Weight: `O(1)` + #[pallet::call_index(11)] + #[pallet::weight(T::WeightInfo::transfer_ownership())] + pub fn transfer_ownership( + origin: OriginFor, + collection: T::CollectionId, + owner: AccountIdLookupOf, + ) -> DispatchResult { + let origin = ensure_signed(origin)?; + let owner = T::Lookup::lookup(owner)?; + Self::do_transfer_ownership(origin, collection, owner) + } + + /// Change the Issuer, Admin and Freezer of a collection. + /// + /// Origin must be either `ForceOrigin` or Signed and the sender should be the Owner of the + /// `collection`. + /// + /// - `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`. + /// + /// Weight: `O(1)` + #[pallet::call_index(12)] + #[pallet::weight(T::WeightInfo::set_team())] + pub fn set_team( + origin: OriginFor, + collection: T::CollectionId, + issuer: AccountIdLookupOf, + admin: AccountIdLookupOf, + freezer: AccountIdLookupOf, + ) -> DispatchResult { + let maybe_check_owner = T::ForceOrigin::try_origin(origin) + .map(|_| None) + .or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?; + let issuer = T::Lookup::lookup(issuer)?; + let admin = T::Lookup::lookup(admin)?; + let freezer = T::Lookup::lookup(freezer)?; + Self::do_set_team(maybe_check_owner, collection, issuer, admin, freezer) + } + + /// Change the Owner of a collection. + /// + /// Origin must be `ForceOrigin`. + /// + /// - `collection`: The identifier of the collection. + /// - `owner`: The new Owner of this collection. + /// + /// Emits `OwnerChanged`. + /// + /// Weight: `O(1)` + #[pallet::call_index(13)] + #[pallet::weight(T::WeightInfo::force_collection_owner())] + pub fn force_collection_owner( + origin: OriginFor, + collection: T::CollectionId, + owner: AccountIdLookupOf, + ) -> DispatchResult { + T::ForceOrigin::ensure_origin(origin)?; + let new_owner = T::Lookup::lookup(owner)?; + Self::do_force_collection_owner(collection, new_owner) + } + + /// Change the config of a collection. + /// + /// Origin must be `ForceOrigin`. + /// + /// - `collection`: The identifier of the collection. + /// - `config`: The new config of this collection. + /// + /// Emits `CollectionConfigChanged`. + /// + /// Weight: `O(1)` + #[pallet::call_index(14)] + #[pallet::weight(T::WeightInfo::force_collection_config())] + pub fn force_collection_config( + origin: OriginFor, + collection: T::CollectionId, + config: CollectionConfigFor, + ) -> DispatchResult { + T::ForceOrigin::ensure_origin(origin)?; + Self::do_force_collection_config(collection, config) + } + + /// Approve an item to be transferred by a delegated third-party account. + /// + /// Origin must be either `ForceOrigin` or Signed and the sender should be the Owner of the + /// `item`. + /// + /// - `collection`: The collection of the item to be approved for delegated transfer. + /// - `item`: The item to be approved for delegated transfer. + /// - `delegate`: The account to delegate permission to transfer the item. + /// - `maybe_deadline`: Optional deadline for the approval. Specified by providing the + /// number of blocks after which the approval will expire + /// + /// Emits `TransferApproved` on success. + /// + /// Weight: `O(1)` + #[pallet::call_index(15)] + #[pallet::weight(T::WeightInfo::approve_transfer())] + pub fn approve_transfer( + origin: OriginFor, + collection: T::CollectionId, + item: T::ItemId, + delegate: AccountIdLookupOf, + maybe_deadline: Option<::BlockNumber>, + ) -> DispatchResult { + let maybe_check_origin = T::ForceOrigin::try_origin(origin) + .map(|_| None) + .or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?; + let delegate = T::Lookup::lookup(delegate)?; + Self::do_approve_transfer( + maybe_check_origin, + collection, + item, + delegate, + maybe_deadline, + ) + } + + /// Cancel one of the transfer approvals for a specific item. + /// + /// Origin must be either: + /// - the `Force` origin; + /// - `Signed` with the signer being the Admin of the `collection`; + /// - `Signed` with the signer being the Owner of the `item`; + /// + /// Arguments: + /// - `collection`: The collection of the item of whose approval will be cancelled. + /// - `item`: The item of the collection of whose approval will be cancelled. + /// - `delegate`: The account that is going to loose their approval. + /// + /// Emits `ApprovalCancelled` on success. + /// + /// Weight: `O(1)` + #[pallet::call_index(16)] + #[pallet::weight(T::WeightInfo::cancel_approval())] + pub fn cancel_approval( + origin: OriginFor, + collection: T::CollectionId, + item: T::ItemId, + delegate: AccountIdLookupOf, + ) -> DispatchResult { + let maybe_check_origin = T::ForceOrigin::try_origin(origin) + .map(|_| None) + .or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?; + let delegate = T::Lookup::lookup(delegate)?; + Self::do_cancel_approval(maybe_check_origin, collection, item, delegate) + } + + /// Cancel all the approvals of a specific item. + /// + /// Origin must be either: + /// - the `Force` origin; + /// - `Signed` with the signer being the Admin of the `collection`; + /// - `Signed` with the signer being the Owner of the `item`; + /// + /// Arguments: + /// - `collection`: The collection of the item of whose approvals will be cleared. + /// - `item`: The item of the collection of whose approvals will be cleared. + /// + /// Emits `AllApprovalsCancelled` on success. + /// + /// Weight: `O(1)` + #[pallet::call_index(17)] + #[pallet::weight(T::WeightInfo::clear_all_transfer_approvals())] + pub fn clear_all_transfer_approvals( + origin: OriginFor, + collection: T::CollectionId, + item: T::ItemId, + ) -> DispatchResult { + let maybe_check_origin = T::ForceOrigin::try_origin(origin) + .map(|_| None) + .or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?; + Self::do_clear_all_transfer_approvals(maybe_check_origin, collection, item) + } + + /// Disallows changing the metadata or attributes of the item. + /// + /// Origin must be either `ForceOrigin` or Signed and the sender should be the Owner of the + /// `collection`. + /// + /// - `collection`: The collection if the `item`. + /// - `item`: An item to be locked. + /// - `lock_metadata`: Specifies whether the metadata should be locked. + /// - `lock_attributes`: Specifies whether the attributes in the `CollectionOwner` namespace + /// should be locked. + /// + /// Note: `lock_attributes` affects the attributes in the `CollectionOwner` namespace + /// only. When the metadata or attributes are locked, it won't be possible the unlock them. + /// + /// Emits `ItemPropertiesLocked`. + /// + /// Weight: `O(1)` + #[pallet::call_index(18)] + #[pallet::weight(T::WeightInfo::lock_item_properties())] + pub fn lock_item_properties( + origin: OriginFor, + collection: T::CollectionId, + item: T::ItemId, + lock_metadata: bool, + lock_attributes: bool, + ) -> DispatchResult { + let maybe_check_owner = T::ForceOrigin::try_origin(origin) + .map(|_| None) + .or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?; + Self::do_lock_item_properties( + maybe_check_owner, + collection, + item, + lock_metadata, + lock_attributes, + ) + } + + /// Set an attribute for a collection or item. + /// + /// Origin must be Signed and must conform to the namespace ruleset: + /// - `CollectionOwner` namespace could be modified by the `collection` owner only; + /// - `ItemOwner` namespace could be modified by the `maybe_item` owner only. `maybe_item` + /// should be set in that case; + /// - `Account(AccountId)` namespace could be modified only when the `origin` was given a + /// permission to do so; + /// + /// The funds of `origin` are reserved according to the formula: + /// `AttributeDepositBase + DepositPerByte * (key.len + value.len)` taking into + /// account any already reserved funds. + /// + /// - `collection`: The identifier of the collection whose item's metadata to set. + /// - `maybe_item`: The identifier of the item whose metadata to set. + /// - `namespace`: Attribute's namespace. + /// - `key`: The key of the attribute. + /// - `value`: The value to which to set the attribute. + /// + /// Emits `AttributeSet`. + /// + /// Weight: `O(1)` + #[pallet::call_index(19)] + #[pallet::weight(T::WeightInfo::set_attribute())] + pub fn set_attribute( + origin: OriginFor, + collection: T::CollectionId, + maybe_item: Option, + namespace: AttributeNamespace, + key: BoundedVec, + value: BoundedVec, + ) -> DispatchResult { + let origin = ensure_signed(origin)?; + Self::do_set_attribute(origin, collection, maybe_item, namespace, key, value) + } + + /// Force-set an attribute for a collection or item. + /// + /// Origin must be `ForceOrigin`. + /// + /// If the attribute already exists and it was set by another account, the deposit + /// will be returned to the previous owner. + /// + /// - `set_as`: An optional owner of the attribute. + /// - `collection`: The identifier of the collection whose item's metadata to set. + /// - `maybe_item`: The identifier of the item whose metadata to set. + /// - `namespace`: Attribute's namespace. + /// - `key`: The key of the attribute. + /// - `value`: The value to which to set the attribute. + /// + /// Emits `AttributeSet`. + /// + /// Weight: `O(1)` + #[pallet::call_index(20)] + #[pallet::weight(T::WeightInfo::force_set_attribute())] + pub fn force_set_attribute( + origin: OriginFor, + set_as: Option, + collection: T::CollectionId, + maybe_item: Option, + namespace: AttributeNamespace, + key: BoundedVec, + value: BoundedVec, + ) -> DispatchResult { + T::ForceOrigin::ensure_origin(origin)?; + Self::do_force_set_attribute(set_as, collection, maybe_item, namespace, key, value) + } + + /// Clear an attribute for a collection or item. + /// + /// Origin must be either `ForceOrigin` or Signed and the sender should be the Owner of the + /// `collection`. + /// + /// Any deposit is freed for the collection's owner. + /// + /// - `collection`: The identifier of the collection whose item's metadata to clear. + /// - `maybe_item`: The identifier of the item whose metadata to clear. + /// - `namespace`: Attribute's namespace. + /// - `key`: The key of the attribute. + /// + /// Emits `AttributeCleared`. + /// + /// Weight: `O(1)` + #[pallet::call_index(21)] + #[pallet::weight(T::WeightInfo::clear_attribute())] + pub fn clear_attribute( + origin: OriginFor, + collection: T::CollectionId, + maybe_item: Option, + namespace: AttributeNamespace, + key: BoundedVec, + ) -> DispatchResult { + let maybe_check_owner = T::ForceOrigin::try_origin(origin) + .map(|_| None) + .or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?; + Self::do_clear_attribute(maybe_check_owner, collection, maybe_item, namespace, key) + } + + /// Approve item's attributes to be changed by a delegated third-party account. + /// + /// Origin must be Signed and must be an owner of the `item`. + /// + /// - `collection`: A collection of the item. + /// - `item`: The item that holds attributes. + /// - `delegate`: The account to delegate permission to change attributes of the item. + /// + /// Emits `ItemAttributesApprovalAdded` on success. + #[pallet::call_index(22)] + #[pallet::weight(T::WeightInfo::approve_item_attributes())] + pub fn approve_item_attributes( + origin: OriginFor, + collection: T::CollectionId, + item: T::ItemId, + delegate: AccountIdLookupOf, + ) -> DispatchResult { + let origin = ensure_signed(origin)?; + let delegate = T::Lookup::lookup(delegate)?; + Self::do_approve_item_attributes(origin, collection, item, delegate) + } + + /// Cancel the previously provided approval to change item's attributes. + /// All the previously set attributes by the `delegate` will be removed. + /// + /// Origin must be Signed and must be an owner of the `item`. + /// + /// - `collection`: Collection that the item is contained within. + /// - `item`: The item that holds attributes. + /// - `delegate`: The previously approved account to remove. + /// + /// Emits `ItemAttributesApprovalRemoved` on success. + #[pallet::call_index(23)] + #[pallet::weight(T::WeightInfo::cancel_item_attributes_approval( + witness.account_attributes + ))] + pub fn cancel_item_attributes_approval( + origin: OriginFor, + collection: T::CollectionId, + item: T::ItemId, + delegate: AccountIdLookupOf, + witness: CancelAttributesApprovalWitness, + ) -> DispatchResult { + let origin = ensure_signed(origin)?; + let delegate = T::Lookup::lookup(delegate)?; + Self::do_cancel_item_attributes_approval(origin, collection, item, delegate, witness) + } + + /// Set the metadata for an item. + /// + /// Origin must be either `ForceOrigin` or Signed and the sender should be the Owner of 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. + /// + /// - `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`. + /// + /// Emits `ItemMetadataSet`. + /// + /// Weight: `O(1)` + #[pallet::call_index(24)] + #[pallet::weight(T::WeightInfo::set_metadata())] + pub fn set_metadata( + origin: OriginFor, + collection: T::CollectionId, + item: T::ItemId, + data: BoundedVec, + ) -> DispatchResult { + let maybe_check_owner = T::ForceOrigin::try_origin(origin) + .map(|_| None) + .or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?; + Self::do_set_item_metadata(maybe_check_owner, collection, item, data) + } + + /// Clear the metadata for an item. + /// + /// Origin must be either `ForceOrigin` or Signed and the sender should be the Owner of the + /// `collection`. + /// + /// Any deposit is freed for the collection's owner. + /// + /// - `collection`: The identifier of the collection whose item's metadata to clear. + /// - `item`: The identifier of the item whose metadata to clear. + /// + /// Emits `ItemMetadataCleared`. + /// + /// Weight: `O(1)` + #[pallet::call_index(25)] + #[pallet::weight(T::WeightInfo::clear_metadata())] + pub fn clear_metadata( + origin: OriginFor, + 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).map_err(DispatchError::from))?; + Self::do_clear_item_metadata(maybe_check_owner, collection, item) + } + + /// Set the metadata for a collection. + /// + /// Origin must be either `ForceOrigin` or `Signed` and the sender should be the Owner of + /// 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. + /// + /// - `collection`: The identifier of the item whose metadata to update. + /// - `data`: The general information of this item. Limited in length by `StringLimit`. + /// + /// Emits `CollectionMetadataSet`. + /// + /// Weight: `O(1)` + #[pallet::call_index(26)] + #[pallet::weight(T::WeightInfo::set_collection_metadata())] + pub fn set_collection_metadata( + origin: OriginFor, + collection: T::CollectionId, + data: BoundedVec, + ) -> DispatchResult { + let maybe_check_owner = T::ForceOrigin::try_origin(origin) + .map(|_| None) + .or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?; + Self::do_set_collection_metadata(maybe_check_owner, collection, data) + } + + /// Clear the metadata for a collection. + /// + /// Origin must be either `ForceOrigin` or `Signed` and the sender should be the Owner of + /// the `collection`. + /// + /// Any deposit is freed for the collection's owner. + /// + /// - `collection`: The identifier of the collection whose metadata to clear. + /// + /// Emits `CollectionMetadataCleared`. + /// + /// Weight: `O(1)` + #[pallet::call_index(27)] + #[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).map_err(DispatchError::from))?; + Self::do_clear_collection_metadata(maybe_check_owner, collection) + } + + /// Set (or reset) the acceptance of ownership for a particular account. + /// + /// Origin must be `Signed` and if `maybe_collection` is `Some`, then the signer must have a + /// provider reference. + /// + /// - `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::call_index(28)] + #[pallet::weight(T::WeightInfo::set_accept_ownership())] + pub fn set_accept_ownership( + origin: OriginFor, + maybe_collection: Option, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + Self::do_set_accept_ownership(who, maybe_collection) + } + + /// Set the maximum number of items a collection could have. + /// + /// Origin must be either `ForceOrigin` or `Signed` and the sender should be the Owner of + /// the `collection`. + /// + /// - `collection`: The identifier of the collection to change. + /// - `max_supply`: The maximum number of items a collection could have. + /// + /// Emits `CollectionMaxSupplySet` event when successful. + #[pallet::call_index(29)] + #[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).map_err(DispatchError::from))?; + Self::do_set_collection_max_supply(maybe_check_owner, collection, max_supply) + } + + /// Update mint settings. + /// + /// Origin must be either `ForceOrigin` or `Signed` and the sender should be the Owner of + /// the `collection`. + /// + /// - `collection`: The identifier of the collection to change. + /// - `mint_settings`: The new mint settings. + /// + /// Emits `CollectionMintSettingsUpdated` event when successful. + #[pallet::call_index(30)] + #[pallet::weight(T::WeightInfo::update_mint_settings())] + pub fn update_mint_settings( + origin: OriginFor, + collection: T::CollectionId, + mint_settings: MintSettings< + BalanceOf, + ::BlockNumber, + T::CollectionId, + >, + ) -> DispatchResult { + let maybe_check_owner = T::ForceOrigin::try_origin(origin) + .map(|_| None) + .or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?; + Self::do_update_mint_settings(maybe_check_owner, collection, mint_settings) + } + + /// 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::call_index(31)] + #[pallet::weight(T::WeightInfo::set_price())] + pub fn set_price( + origin: OriginFor, + collection: T::CollectionId, + item: T::ItemId, + price: Option>, + whitelisted_buyer: Option>, + ) -> 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::call_index(32)] + #[pallet::weight(T::WeightInfo::buy_item())] + 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) + } + + /// Allows to pay the tips. + /// + /// Origin must be Signed. + /// + /// - `tips`: Tips array. + /// + /// Emits `TipSent` on every tip transfer. + #[pallet::call_index(33)] + #[pallet::weight(T::WeightInfo::pay_tips(tips.len() as u32))] + pub fn pay_tips( + origin: OriginFor, + tips: BoundedVec, T::MaxTips>, + ) -> DispatchResult { + let origin = ensure_signed(origin)?; + Self::do_pay_tips(origin, tips) + } + + /// Register a new atomic swap, declaring an intention to send an `item` in exchange for + /// `desired_item` from origin to target on the current blockchain. + /// The target can execute the swap during the specified `duration` of blocks (if set). + /// Additionally, the price could be set for the desired `item`. + /// + /// Origin must be Signed and must be an owner of the `item`. + /// + /// - `collection`: The collection of the item. + /// - `item`: The item an owner wants to give. + /// - `desired_collection`: The collection of the desired item. + /// - `desired_item`: The desired item an owner wants to receive. + /// - `maybe_price`: The price an owner is willing to pay or receive for the desired `item`. + /// - `duration`: A deadline for the swap. Specified by providing the number of blocks + /// after which the swap will expire. + /// + /// Emits `SwapCreated` on success. + #[pallet::call_index(34)] + #[pallet::weight(T::WeightInfo::create_swap())] + pub fn create_swap( + origin: OriginFor, + offered_collection: T::CollectionId, + offered_item: T::ItemId, + desired_collection: T::CollectionId, + maybe_desired_item: Option, + maybe_price: Option>>, + duration: ::BlockNumber, + ) -> DispatchResult { + let origin = ensure_signed(origin)?; + Self::do_create_swap( + origin, + offered_collection, + offered_item, + desired_collection, + maybe_desired_item, + maybe_price, + duration, + ) + } + + /// Cancel an atomic swap. + /// + /// Origin must be Signed. + /// Origin must be an owner of the `item` if the deadline hasn't expired. + /// + /// - `collection`: The collection of the item. + /// - `item`: The item an owner wants to give. + /// + /// Emits `SwapCancelled` on success. + #[pallet::call_index(35)] + #[pallet::weight(T::WeightInfo::cancel_swap())] + pub fn cancel_swap( + origin: OriginFor, + offered_collection: T::CollectionId, + offered_item: T::ItemId, + ) -> DispatchResult { + let origin = ensure_signed(origin)?; + Self::do_cancel_swap(origin, offered_collection, offered_item) + } + + /// Claim an atomic swap. + /// This method executes a pending swap, that was created by a counterpart before. + /// + /// Origin must be Signed and must be an owner of the `item`. + /// + /// - `send_collection`: The collection of the item to be sent. + /// - `send_item`: The item to be sent. + /// - `receive_collection`: The collection of the item to be received. + /// - `receive_item`: The item to be received. + /// - `witness_price`: A price that was previously agreed on. + /// + /// Emits `SwapClaimed` on success. + #[pallet::call_index(36)] + #[pallet::weight(T::WeightInfo::claim_swap())] + pub fn claim_swap( + origin: OriginFor, + send_collection: T::CollectionId, + send_item: T::ItemId, + receive_collection: T::CollectionId, + receive_item: T::ItemId, + witness_price: Option>>, + ) -> DispatchResult { + let origin = ensure_signed(origin)?; + Self::do_claim_swap( + origin, + send_collection, + send_item, + receive_collection, + receive_item, + witness_price, + ) + } + } +} diff --git a/frame/nfts/src/macros.rs b/frame/nfts/src/macros.rs new file mode 100644 index 0000000000000..07a8f3b9f9556 --- /dev/null +++ b/frame/nfts/src/macros.rs @@ -0,0 +1,74 @@ +// 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. + +macro_rules! impl_incrementable { + ($($type:ty),+) => { + $( + impl Incrementable for $type { + fn increment(&self) -> Self { + let mut val = self.clone(); + val.saturating_inc(); + val + } + + fn initial_value() -> Self { + 0 + } + } + )+ + }; +} +pub(crate) use impl_incrementable; + +macro_rules! impl_codec_bitflags { + ($wrapper:ty, $size:ty, $bitflag_enum:ty) => { + impl MaxEncodedLen for $wrapper { + fn max_encoded_len() -> usize { + <$size>::max_encoded_len() + } + } + impl Encode for $wrapper { + fn using_encoded R>(&self, f: F) -> R { + self.0.bits().using_encoded(f) + } + } + impl EncodeLike for $wrapper {} + impl Decode for $wrapper { + fn decode( + input: &mut I, + ) -> sp_std::result::Result { + let field = <$size>::decode(input)?; + Ok(Self(BitFlags::from_bits(field as $size).map_err(|_| "invalid value")?)) + } + } + + impl TypeInfo for $wrapper { + type Identity = Self; + + fn type_info() -> Type { + Type::builder() + .path(Path::new("BitFlags", module_path!())) + .type_params(vec![TypeParameter::new("T", Some(meta_type::<$bitflag_enum>()))]) + .composite( + Fields::unnamed() + .field(|f| f.ty::<$size>().type_name(stringify!($bitflag_enum))), + ) + } + } + }; +} +pub(crate) use impl_codec_bitflags; diff --git a/frame/nfts/src/mock.rs b/frame/nfts/src/mock.rs new file mode 100644 index 0000000000000..f814b209d5f78 --- /dev/null +++ b/frame/nfts/src/mock.rs @@ -0,0 +1,123 @@ +// 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 Nfts pallet. + +use super::*; +use crate as pallet_nfts; + +use frame_support::{ + construct_runtime, parameter_types, + traits::{AsEnsureOriginWithArg, ConstU32, ConstU64}, +}; +use sp_core::H256; +use sp_runtime::{ + testing::Header, + traits::{BlakeTwo256, IdentityLookup}, +}; + +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}, + Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, + Nfts: pallet_nfts::{Pallet, Call, Storage, Event}, + } +); + +impl frame_system::Config for Test { + type BaseCallFilter = frame_support::traits::Everything; + type BlockWeights = (); + type BlockLength = (); + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type Index = u64; + type BlockNumber = u64; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup; + type Header = Header; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = ConstU64<250>; + type DbWeight = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = ConstU32<16>; +} + +impl pallet_balances::Config for Test { + type Balance = u64; + type DustRemoval = (); + type RuntimeEvent = RuntimeEvent; + type ExistentialDeposit = ConstU64<1>; + type AccountStore = System; + type WeightInfo = (); + type MaxLocks = (); + type MaxReserves = ConstU32<50>; + type ReserveIdentifier = [u8; 8]; +} + +parameter_types! { + pub storage Features: PalletFeatures = PalletFeatures::all_enabled(); +} + +impl Config for Test { + type RuntimeEvent = RuntimeEvent; + type CollectionId = u32; + type ItemId = u32; + type Currency = Balances; + type CreateOrigin = AsEnsureOriginWithArg>; + type ForceOrigin = frame_system::EnsureRoot; + type Locker = (); + type CollectionDeposit = ConstU64<2>; + type ItemDeposit = 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 ApprovalsLimit = ConstU32<10>; + type ItemAttributesApprovalsLimit = ConstU32<2>; + type MaxTips = ConstU32<10>; + type MaxDeadlineDuration = ConstU64<10000>; + type Features = Features; + type WeightInfo = (); + #[cfg(feature = "runtime-benchmarks")] + type Helper = (); +} + +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); + ext.execute_with(|| System::set_block_number(1)); + ext +} diff --git a/frame/nfts/src/tests.rs b/frame/nfts/src/tests.rs new file mode 100644 index 0000000000000..18a3fd83b4de3 --- /dev/null +++ b/frame/nfts/src/tests.rs @@ -0,0 +1,2484 @@ +// 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 Nfts pallet. + +use crate::{mock::*, Event, *}; +use enumflags2::BitFlags; +use frame_support::{ + assert_noop, assert_ok, + dispatch::Dispatchable, + traits::{ + tokens::nonfungibles_v2::{Destroy, Mutate}, + Currency, Get, + }, +}; +use pallet_balances::Error as BalancesError; +use sp_core::bounded::BoundedVec; +use sp_std::prelude::*; + +fn items() -> Vec<(u64, u32, u32)> { + let mut r: Vec<_> = Account::::iter().map(|x| x.0).collect(); + r.sort(); + let mut s: Vec<_> = Item::::iter().map(|x| (x.2.owner, x.0, x.1)).collect(); + s.sort(); + assert_eq!(r, s); + for collection in Item::::iter() + .map(|x| x.0) + .scan(None, |s, item| { + if s.map_or(false, |last| last == item) { + *s = Some(item); + Some(None) + } else { + Some(Some(item)) + } + }) + .flatten() + { + let details = Collection::::get(collection).unwrap(); + let items = Item::::iter_prefix(collection).count() as u32; + assert_eq!(details.items, items); + } + r +} + +fn collections() -> Vec<(u64, u32)> { + let mut r: Vec<_> = CollectionAccount::::iter().map(|x| (x.0, x.1)).collect(); + r.sort(); + let mut s: Vec<_> = Collection::::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() + } +} + +fn attributes(collection: u32) -> Vec<(Option, AttributeNamespace, Vec, Vec)> { + let mut s: Vec<_> = Attribute::::iter_prefix((collection,)) + .map(|(k, v)| (k.0, k.1, k.2.into(), v.0.into())) + .collect(); + s.sort_by_key(|k: &(Option, AttributeNamespace, Vec, Vec)| k.0); + s.sort_by_key(|k: &(Option, AttributeNamespace, Vec, Vec)| k.2.clone()); + s +} + +fn approvals(collection_id: u32, item_id: u32) -> Vec<(u64, Option)> { + let item = Item::::get(collection_id, item_id).unwrap(); + let s: Vec<_> = item.approvals.into_iter().collect(); + s +} + +fn item_attributes_approvals(collection_id: u32, item_id: u32) -> Vec { + let approvals = ItemAttributesApprovalsOf::::get(collection_id, item_id); + let s: Vec<_> = approvals.into_iter().collect(); + s +} + +fn events() -> Vec> { + let result = System::events() + .into_iter() + .map(|r| r.event) + .filter_map(|e| if let mock::RuntimeEvent::Nfts(inner) = e { Some(inner) } else { None }) + .collect::>(); + + System::reset_events(); + + result +} + +fn collection_config_from_disabled_settings( + settings: BitFlags, +) -> CollectionConfigFor { + CollectionConfig { + settings: CollectionSettings::from_disabled(settings), + max_supply: None, + mint_settings: MintSettings::default(), + } +} + +fn collection_config_with_all_settings_enabled() -> CollectionConfigFor { + CollectionConfig { + settings: CollectionSettings::all_enabled(), + max_supply: None, + mint_settings: MintSettings::default(), + } +} + +fn default_collection_config() -> CollectionConfigFor { + collection_config_from_disabled_settings(CollectionSetting::DepositRequired.into()) +} + +fn default_item_config() -> ItemConfig { + ItemConfig { settings: ItemSettings::all_enabled() } +} + +fn item_config_from_disabled_settings(settings: BitFlags) -> ItemConfig { + ItemConfig { settings: ItemSettings::from_disabled(settings) } +} + +#[test] +fn basic_setup_works() { + new_test_ext().execute_with(|| { + assert_eq!(items(), vec![]); + }); +} + +#[test] +fn basic_minting_should_work() { + new_test_ext().execute_with(|| { + assert_ok!(Nfts::force_create(RuntimeOrigin::root(), 1, default_collection_config())); + assert_eq!(collections(), vec![(1, 0)]); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(1), 0, 42, 1, None)); + assert_eq!(items(), vec![(1, 0, 42)]); + + assert_ok!(Nfts::force_create(RuntimeOrigin::root(), 2, default_collection_config())); + assert_eq!(collections(), vec![(1, 0), (2, 1)]); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(2), 1, 69, 1, None)); + // assert_ok!(Nfts::force_mint(RuntimeOrigin::signed(2), 1, 69, 1, default_item_config())); + assert_eq!(items(), vec![(1, 0, 42), (1, 1, 69)]); + }); +} + +#[test] +fn lifecycle_should_work() { + new_test_ext().execute_with(|| { + Balances::make_free_balance_be(&1, 100); + Balances::make_free_balance_be(&2, 100); + assert_ok!(Nfts::create( + RuntimeOrigin::signed(1), + 1, + collection_config_with_all_settings_enabled() + )); + assert_eq!(Balances::reserved_balance(&1), 2); + assert_eq!(collections(), vec![(1, 0)]); + assert_ok!(Nfts::set_collection_metadata(RuntimeOrigin::signed(1), 0, bvec![0, 0])); + assert_eq!(Balances::reserved_balance(&1), 5); + assert!(CollectionMetadataOf::::contains_key(0)); + + assert_ok!(Nfts::force_mint(RuntimeOrigin::signed(1), 0, 42, 10, default_item_config())); + assert_eq!(Balances::reserved_balance(&1), 6); + assert_ok!(Nfts::force_mint(RuntimeOrigin::signed(1), 0, 69, 20, default_item_config())); + assert_eq!(Balances::reserved_balance(&1), 7); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(1), 0, 70, 1, None)); + assert_eq!(items(), vec![(1, 0, 70), (10, 0, 42), (20, 0, 69)]); + assert_eq!(Collection::::get(0).unwrap().items, 3); + assert_eq!(Collection::::get(0).unwrap().item_metadatas, 0); + + assert_eq!(Balances::reserved_balance(&2), 0); + assert_ok!(Nfts::transfer(RuntimeOrigin::signed(1), 0, 70, 2)); + assert_eq!(Balances::reserved_balance(&2), 1); + + assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(1), 0, 42, bvec![42, 42])); + assert_eq!(Balances::reserved_balance(&1), 10); + assert!(ItemMetadataOf::::contains_key(0, 42)); + assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(1), 0, 69, bvec![69, 69])); + assert_eq!(Balances::reserved_balance(&1), 13); + assert!(ItemMetadataOf::::contains_key(0, 69)); + + let w = Nfts::get_destroy_witness(&0).unwrap(); + assert_eq!(w.items, 3); + assert_eq!(w.item_metadatas, 2); + assert_ok!(Nfts::destroy(RuntimeOrigin::signed(1), 0, w)); + assert_eq!(Balances::reserved_balance(&1), 0); + + assert!(!Collection::::contains_key(0)); + assert!(!CollectionConfigOf::::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![]); + }); +} + +#[test] +fn destroy_with_bad_witness_should_not_work() { + new_test_ext().execute_with(|| { + Balances::make_free_balance_be(&1, 100); + assert_ok!(Nfts::create( + RuntimeOrigin::signed(1), + 1, + collection_config_with_all_settings_enabled() + )); + + let w = Collection::::get(0).unwrap().destroy_witness(); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(1), 0, 42, 1, None)); + assert_noop!(Nfts::destroy(RuntimeOrigin::signed(1), 0, w), Error::::BadWitness); + }); +} + +#[test] +fn mint_should_work() { + new_test_ext().execute_with(|| { + assert_ok!(Nfts::force_create(RuntimeOrigin::root(), 1, default_collection_config())); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(1), 0, 42, 1, None)); + assert_eq!(Nfts::owner(0, 42).unwrap(), 1); + assert_eq!(collections(), vec![(1, 0)]); + assert_eq!(items(), vec![(1, 0, 42)]); + + // validate minting start and end settings + assert_ok!(Nfts::update_mint_settings( + RuntimeOrigin::signed(1), + 0, + MintSettings { + start_block: Some(2), + end_block: Some(3), + mint_type: MintType::Public, + ..Default::default() + } + )); + + System::set_block_number(1); + assert_noop!( + Nfts::mint(RuntimeOrigin::signed(2), 0, 43, 1, None), + Error::::MintNotStarted + ); + System::set_block_number(4); + assert_noop!( + Nfts::mint(RuntimeOrigin::signed(2), 0, 43, 1, None), + Error::::MintEnded + ); + + // validate price + assert_ok!(Nfts::update_mint_settings( + RuntimeOrigin::signed(1), + 0, + MintSettings { mint_type: MintType::Public, price: Some(1), ..Default::default() } + )); + Balances::make_free_balance_be(&2, 100); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(2), 0, 43, 2, None)); + assert_eq!(Balances::total_balance(&2), 99); + + // validate types + assert_ok!(Nfts::force_create(RuntimeOrigin::root(), 1, default_collection_config())); + assert_ok!(Nfts::update_mint_settings( + RuntimeOrigin::signed(1), + 1, + MintSettings { mint_type: MintType::HolderOf(0), ..Default::default() } + )); + assert_noop!( + Nfts::mint(RuntimeOrigin::signed(3), 1, 42, 3, None), + Error::::BadWitness + ); + assert_noop!( + Nfts::mint(RuntimeOrigin::signed(2), 1, 42, 2, None), + Error::::BadWitness + ); + assert_noop!( + Nfts::mint(RuntimeOrigin::signed(2), 1, 42, 2, Some(MintWitness { owner_of_item: 42 })), + Error::::BadWitness + ); + assert_ok!(Nfts::mint( + RuntimeOrigin::signed(2), + 1, + 42, + 2, + Some(MintWitness { owner_of_item: 43 }) + )); + + // can't mint twice + assert_noop!( + Nfts::mint(RuntimeOrigin::signed(2), 1, 46, 2, Some(MintWitness { owner_of_item: 43 })), + Error::::AlreadyClaimed + ); + }); +} + +#[test] +fn transfer_should_work() { + new_test_ext().execute_with(|| { + assert_ok!(Nfts::force_create(RuntimeOrigin::root(), 1, default_collection_config())); + assert_ok!(Nfts::force_mint(RuntimeOrigin::signed(1), 0, 42, 2, default_item_config())); + + assert_ok!(Nfts::transfer(RuntimeOrigin::signed(2), 0, 42, 3)); + assert_eq!(items(), vec![(3, 0, 42)]); + assert_noop!( + Nfts::transfer(RuntimeOrigin::signed(2), 0, 42, 4), + Error::::NoPermission + ); + + assert_ok!(Nfts::approve_transfer(RuntimeOrigin::signed(3), 0, 42, 2, None)); + assert_ok!(Nfts::transfer(RuntimeOrigin::signed(2), 0, 42, 4)); + + // validate we can't transfer non-transferable items + let collection_id = 1; + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + 1, + collection_config_from_disabled_settings( + CollectionSetting::TransferableItems | CollectionSetting::DepositRequired + ) + )); + + assert_ok!(Nfts::force_mint(RuntimeOrigin::signed(1), 1, 1, 42, default_item_config())); + + assert_noop!( + Nfts::transfer(RuntimeOrigin::signed(1), collection_id, 42, 3,), + Error::::ItemsNonTransferable + ); + }); +} + +#[test] +fn locking_transfer_should_work() { + new_test_ext().execute_with(|| { + assert_ok!(Nfts::force_create(RuntimeOrigin::root(), 1, default_collection_config())); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(1), 0, 42, 1, None)); + assert_ok!(Nfts::lock_item_transfer(RuntimeOrigin::signed(1), 0, 42)); + assert_noop!(Nfts::transfer(RuntimeOrigin::signed(1), 0, 42, 2), Error::::ItemLocked); + + assert_ok!(Nfts::unlock_item_transfer(RuntimeOrigin::signed(1), 0, 42)); + assert_ok!(Nfts::lock_collection( + RuntimeOrigin::signed(1), + 0, + CollectionSettings::from_disabled(CollectionSetting::TransferableItems.into()) + )); + assert_noop!( + Nfts::transfer(RuntimeOrigin::signed(1), 0, 42, 2), + Error::::ItemsNonTransferable + ); + + assert_ok!(Nfts::force_collection_config( + RuntimeOrigin::root(), + 0, + collection_config_with_all_settings_enabled(), + )); + assert_ok!(Nfts::transfer(RuntimeOrigin::signed(1), 0, 42, 2)); + }); +} + +#[test] +fn origin_guards_should_work() { + new_test_ext().execute_with(|| { + assert_ok!(Nfts::force_create(RuntimeOrigin::root(), 1, default_collection_config())); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(1), 0, 42, 1, None)); + + Balances::make_free_balance_be(&2, 100); + assert_ok!(Nfts::set_accept_ownership(RuntimeOrigin::signed(2), Some(0))); + assert_noop!( + Nfts::transfer_ownership(RuntimeOrigin::signed(2), 0, 2), + Error::::NoPermission + ); + assert_noop!( + Nfts::set_team(RuntimeOrigin::signed(2), 0, 2, 2, 2), + Error::::NoPermission + ); + assert_noop!( + Nfts::lock_item_transfer(RuntimeOrigin::signed(2), 0, 42), + Error::::NoPermission + ); + assert_noop!( + Nfts::unlock_item_transfer(RuntimeOrigin::signed(2), 0, 42), + Error::::NoPermission + ); + assert_noop!( + Nfts::mint(RuntimeOrigin::signed(2), 0, 69, 2, None), + Error::::NoPermission + ); + assert_noop!( + Nfts::burn(RuntimeOrigin::signed(2), 0, 42, None), + Error::::NoPermission + ); + let w = Nfts::get_destroy_witness(&0).unwrap(); + assert_noop!(Nfts::destroy(RuntimeOrigin::signed(2), 0, w), Error::::NoPermission); + }); +} + +#[test] +fn transfer_owner_should_work() { + new_test_ext().execute_with(|| { + Balances::make_free_balance_be(&1, 100); + Balances::make_free_balance_be(&2, 100); + Balances::make_free_balance_be(&3, 100); + assert_ok!(Nfts::create( + RuntimeOrigin::signed(1), + 1, + collection_config_with_all_settings_enabled() + )); + assert_eq!(collections(), vec![(1, 0)]); + assert_noop!( + Nfts::transfer_ownership(RuntimeOrigin::signed(1), 0, 2), + Error::::Unaccepted + ); + assert_ok!(Nfts::set_accept_ownership(RuntimeOrigin::signed(2), Some(0))); + assert_ok!(Nfts::transfer_ownership(RuntimeOrigin::signed(1), 0, 2)); + + 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); + assert_eq!(Balances::reserved_balance(&2), 2); + + assert_ok!(Nfts::set_accept_ownership(RuntimeOrigin::signed(1), Some(0))); + assert_noop!( + Nfts::transfer_ownership(RuntimeOrigin::signed(1), 0, 1), + Error::::NoPermission + ); + + // Mint and set metadata now and make sure that deposit gets transferred back. + assert_ok!(Nfts::set_collection_metadata(RuntimeOrigin::signed(2), 0, bvec![0u8; 20])); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(1), 0, 42, 1, None)); + assert_eq!(Balances::reserved_balance(&1), 1); + assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(2), 0, 42, bvec![0u8; 20])); + assert_ok!(Nfts::set_accept_ownership(RuntimeOrigin::signed(3), Some(0))); + assert_ok!(Nfts::transfer_ownership(RuntimeOrigin::signed(2), 0, 3)); + assert_eq!(collections(), vec![(3, 0)]); + assert_eq!(Balances::total_balance(&2), 58); + assert_eq!(Balances::total_balance(&3), 144); + assert_eq!(Balances::reserved_balance(&2), 0); + assert_eq!(Balances::reserved_balance(&3), 44); + + assert_ok!(Nfts::transfer(RuntimeOrigin::signed(1), 0, 42, 2)); + assert_eq!(Balances::reserved_balance(&1), 0); + assert_eq!(Balances::reserved_balance(&2), 1); + + // 2's acceptance from before is reset when it became an owner, so it cannot be transferred + // without a fresh acceptance. + assert_noop!( + Nfts::transfer_ownership(RuntimeOrigin::signed(3), 0, 2), + Error::::Unaccepted + ); + }); +} + +#[test] +fn set_team_should_work() { + new_test_ext().execute_with(|| { + assert_ok!(Nfts::force_create(RuntimeOrigin::root(), 1, default_collection_config())); + assert_ok!(Nfts::set_team(RuntimeOrigin::signed(1), 0, 2, 3, 4)); + + assert_ok!(Nfts::mint(RuntimeOrigin::signed(2), 0, 42, 2, None)); + assert_ok!(Nfts::lock_item_transfer(RuntimeOrigin::signed(4), 0, 42)); + assert_ok!(Nfts::unlock_item_transfer(RuntimeOrigin::signed(4), 0, 42)); + assert_ok!(Nfts::transfer(RuntimeOrigin::signed(3), 0, 42, 3)); + assert_ok!(Nfts::burn(RuntimeOrigin::signed(3), 0, 42, None)); + }); +} + +#[test] +fn set_collection_metadata_should_work() { + new_test_ext().execute_with(|| { + // Cannot add metadata to unknown item + assert_noop!( + Nfts::set_collection_metadata(RuntimeOrigin::signed(1), 0, bvec![0u8; 20]), + Error::::NoConfig, + ); + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + 1, + collection_config_with_all_settings_enabled() + )); + // Cannot add metadata to unowned item + assert_noop!( + Nfts::set_collection_metadata(RuntimeOrigin::signed(2), 0, bvec![0u8; 20]), + Error::::NoPermission, + ); + + // Successfully add metadata and take deposit + Balances::make_free_balance_be(&1, 30); + assert_ok!(Nfts::set_collection_metadata(RuntimeOrigin::signed(1), 0, bvec![0u8; 20])); + assert_eq!(Balances::free_balance(&1), 9); + assert!(CollectionMetadataOf::::contains_key(0)); + + // Force origin works, too. + assert_ok!(Nfts::set_collection_metadata(RuntimeOrigin::root(), 0, bvec![0u8; 18])); + + // Update deposit + assert_ok!(Nfts::set_collection_metadata(RuntimeOrigin::signed(1), 0, bvec![0u8; 15])); + assert_eq!(Balances::free_balance(&1), 14); + assert_ok!(Nfts::set_collection_metadata(RuntimeOrigin::signed(1), 0, bvec![0u8; 25])); + assert_eq!(Balances::free_balance(&1), 4); + + // Cannot over-reserve + assert_noop!( + Nfts::set_collection_metadata(RuntimeOrigin::signed(1), 0, bvec![0u8; 40]), + BalancesError::::InsufficientBalance, + ); + + // Can't set or clear metadata once frozen + assert_ok!(Nfts::set_collection_metadata(RuntimeOrigin::signed(1), 0, bvec![0u8; 15])); + assert_ok!(Nfts::lock_collection( + RuntimeOrigin::signed(1), + 0, + CollectionSettings::from_disabled(CollectionSetting::UnlockedMetadata.into()) + )); + assert_noop!( + Nfts::set_collection_metadata(RuntimeOrigin::signed(1), 0, bvec![0u8; 15]), + Error::::LockedCollectionMetadata, + ); + assert_noop!( + Nfts::clear_collection_metadata(RuntimeOrigin::signed(1), 0), + Error::::LockedCollectionMetadata + ); + + // Clear Metadata + assert_ok!(Nfts::set_collection_metadata(RuntimeOrigin::root(), 0, bvec![0u8; 15])); + assert_noop!( + Nfts::clear_collection_metadata(RuntimeOrigin::signed(2), 0), + Error::::NoPermission + ); + assert_noop!( + Nfts::clear_collection_metadata(RuntimeOrigin::signed(1), 1), + Error::::UnknownCollection + ); + assert_noop!( + Nfts::clear_collection_metadata(RuntimeOrigin::signed(1), 0), + Error::::LockedCollectionMetadata + ); + assert_ok!(Nfts::clear_collection_metadata(RuntimeOrigin::root(), 0)); + assert!(!CollectionMetadataOf::::contains_key(0)); + }); +} + +#[test] +fn set_item_metadata_should_work() { + new_test_ext().execute_with(|| { + Balances::make_free_balance_be(&1, 30); + + // Cannot add metadata to unknown item + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + 1, + collection_config_with_all_settings_enabled() + )); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(1), 0, 42, 1, None)); + // Cannot add metadata to unowned item + assert_noop!( + Nfts::set_metadata(RuntimeOrigin::signed(2), 0, 42, bvec![0u8; 20]), + Error::::NoPermission, + ); + + // Successfully add metadata and take deposit + assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(1), 0, 42, bvec![0u8; 20])); + assert_eq!(Balances::free_balance(&1), 8); + assert!(ItemMetadataOf::::contains_key(0, 42)); + + // Force origin works, too. + assert_ok!(Nfts::set_metadata(RuntimeOrigin::root(), 0, 42, bvec![0u8; 18])); + + // Update deposit + assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(1), 0, 42, bvec![0u8; 15])); + assert_eq!(Balances::free_balance(&1), 13); + assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(1), 0, 42, bvec![0u8; 25])); + assert_eq!(Balances::free_balance(&1), 3); + + // Cannot over-reserve + assert_noop!( + Nfts::set_metadata(RuntimeOrigin::signed(1), 0, 42, bvec![0u8; 40]), + BalancesError::::InsufficientBalance, + ); + + // Can't set or clear metadata once frozen + assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(1), 0, 42, bvec![0u8; 15])); + assert_ok!(Nfts::lock_item_properties(RuntimeOrigin::signed(1), 0, 42, true, false)); + assert_noop!( + Nfts::set_metadata(RuntimeOrigin::signed(1), 0, 42, bvec![0u8; 15]), + Error::::LockedItemMetadata, + ); + assert_noop!( + Nfts::clear_metadata(RuntimeOrigin::signed(1), 0, 42), + Error::::LockedItemMetadata, + ); + + // Clear Metadata + assert_ok!(Nfts::set_metadata(RuntimeOrigin::root(), 0, 42, bvec![0u8; 15])); + assert_noop!( + Nfts::clear_metadata(RuntimeOrigin::signed(2), 0, 42), + Error::::NoPermission, + ); + assert_noop!( + Nfts::clear_metadata(RuntimeOrigin::signed(1), 1, 42), + Error::::UnknownCollection, + ); + assert_ok!(Nfts::clear_metadata(RuntimeOrigin::root(), 0, 42)); + assert!(!ItemMetadataOf::::contains_key(0, 42)); + }); +} + +#[test] +fn set_collection_owner_attributes_should_work() { + new_test_ext().execute_with(|| { + Balances::make_free_balance_be(&1, 100); + + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + 1, + collection_config_with_all_settings_enabled() + )); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(1), 0, 0, 1, None)); + + assert_ok!(Nfts::set_attribute( + RuntimeOrigin::signed(1), + 0, + None, + AttributeNamespace::CollectionOwner, + bvec![0], + bvec![0], + )); + assert_ok!(Nfts::set_attribute( + RuntimeOrigin::signed(1), + 0, + Some(0), + AttributeNamespace::CollectionOwner, + bvec![0], + bvec![0], + )); + assert_ok!(Nfts::set_attribute( + RuntimeOrigin::signed(1), + 0, + Some(0), + AttributeNamespace::CollectionOwner, + bvec![1], + bvec![0], + )); + assert_eq!( + attributes(0), + vec![ + (None, AttributeNamespace::CollectionOwner, bvec![0], bvec![0]), + (Some(0), AttributeNamespace::CollectionOwner, bvec![0], bvec![0]), + (Some(0), AttributeNamespace::CollectionOwner, bvec![1], bvec![0]), + ] + ); + assert_eq!(Balances::reserved_balance(1), 10); + assert_eq!(Collection::::get(0).unwrap().owner_deposit, 9); + + assert_ok!(Nfts::set_attribute( + RuntimeOrigin::signed(1), + 0, + None, + AttributeNamespace::CollectionOwner, + bvec![0], + bvec![0; 10], + )); + assert_eq!( + attributes(0), + vec![ + (None, AttributeNamespace::CollectionOwner, bvec![0], bvec![0; 10]), + (Some(0), AttributeNamespace::CollectionOwner, bvec![0], bvec![0]), + (Some(0), AttributeNamespace::CollectionOwner, bvec![1], bvec![0]), + ] + ); + assert_eq!(Balances::reserved_balance(1), 19); + assert_eq!(Collection::::get(0).unwrap().owner_deposit, 18); + + assert_ok!(Nfts::clear_attribute( + RuntimeOrigin::signed(1), + 0, + Some(0), + AttributeNamespace::CollectionOwner, + bvec![1], + )); + assert_eq!( + attributes(0), + vec![ + (None, AttributeNamespace::CollectionOwner, bvec![0], bvec![0; 10]), + (Some(0), AttributeNamespace::CollectionOwner, bvec![0], bvec![0]), + ] + ); + assert_eq!(Balances::reserved_balance(1), 16); + + let w = Nfts::get_destroy_witness(&0).unwrap(); + assert_ok!(Nfts::destroy(RuntimeOrigin::signed(1), 0, w)); + assert_eq!(attributes(0), vec![]); + assert_eq!(Balances::reserved_balance(1), 0); + }); +} + +#[test] +fn set_item_owner_attributes_should_work() { + new_test_ext().execute_with(|| { + Balances::make_free_balance_be(&1, 100); + Balances::make_free_balance_be(&2, 100); + Balances::make_free_balance_be(&3, 100); + + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + 1, + collection_config_with_all_settings_enabled() + )); + assert_ok!(Nfts::force_mint(RuntimeOrigin::signed(1), 0, 0, 2, default_item_config())); + + // can't set for the collection + assert_noop!( + Nfts::set_attribute( + RuntimeOrigin::signed(2), + 0, + None, + AttributeNamespace::ItemOwner, + bvec![0], + bvec![0], + ), + Error::::NoPermission, + ); + // can't set for the non-owned item + assert_noop!( + Nfts::set_attribute( + RuntimeOrigin::signed(1), + 0, + Some(0), + AttributeNamespace::ItemOwner, + bvec![0], + bvec![0], + ), + Error::::NoPermission, + ); + assert_ok!(Nfts::set_attribute( + RuntimeOrigin::signed(2), + 0, + Some(0), + AttributeNamespace::ItemOwner, + bvec![0], + bvec![0], + )); + assert_ok!(Nfts::set_attribute( + RuntimeOrigin::signed(2), + 0, + Some(0), + AttributeNamespace::ItemOwner, + bvec![1], + bvec![0], + )); + assert_ok!(Nfts::set_attribute( + RuntimeOrigin::signed(2), + 0, + Some(0), + AttributeNamespace::ItemOwner, + bvec![2], + bvec![0], + )); + assert_eq!( + attributes(0), + vec![ + (Some(0), AttributeNamespace::ItemOwner, bvec![0], bvec![0]), + (Some(0), AttributeNamespace::ItemOwner, bvec![1], bvec![0]), + (Some(0), AttributeNamespace::ItemOwner, bvec![2], bvec![0]), + ] + ); + assert_eq!(Balances::reserved_balance(2), 9); + + // validate an attribute can be updated + assert_ok!(Nfts::set_attribute( + RuntimeOrigin::signed(2), + 0, + Some(0), + AttributeNamespace::ItemOwner, + bvec![0], + bvec![0; 10], + )); + assert_eq!( + attributes(0), + vec![ + (Some(0), AttributeNamespace::ItemOwner, bvec![0], bvec![0; 10]), + (Some(0), AttributeNamespace::ItemOwner, bvec![1], bvec![0]), + (Some(0), AttributeNamespace::ItemOwner, bvec![2], bvec![0]), + ] + ); + assert_eq!(Balances::reserved_balance(2), 18); + + // validate only item's owner (or the root) can remove an attribute + assert_noop!( + Nfts::clear_attribute( + RuntimeOrigin::signed(1), + 0, + Some(0), + AttributeNamespace::ItemOwner, + bvec![1], + ), + Error::::NoPermission, + ); + assert_ok!(Nfts::clear_attribute( + RuntimeOrigin::signed(2), + 0, + Some(0), + AttributeNamespace::ItemOwner, + bvec![1], + )); + assert_eq!( + attributes(0), + vec![ + (Some(0), AttributeNamespace::ItemOwner, bvec![0], bvec![0; 10]), + (Some(0), AttributeNamespace::ItemOwner, bvec![2], bvec![0]) + ] + ); + assert_eq!(Balances::reserved_balance(2), 15); + + // transfer item + assert_ok!(Nfts::transfer(RuntimeOrigin::signed(2), 0, 0, 3)); + + // validate the attribute are still here & the deposit belongs to the previous owner + assert_eq!( + attributes(0), + vec![ + (Some(0), AttributeNamespace::ItemOwner, bvec![0], bvec![0; 10]), + (Some(0), AttributeNamespace::ItemOwner, bvec![2], bvec![0]) + ] + ); + let key: BoundedVec<_, _> = bvec![0]; + let (_, deposit) = + Attribute::::get((0, Some(0), AttributeNamespace::ItemOwner, &key)).unwrap(); + assert_eq!(deposit.account, Some(2)); + assert_eq!(deposit.amount, 12); + + // on attribute update the deposit should be returned to the previous owner + assert_ok!(Nfts::set_attribute( + RuntimeOrigin::signed(3), + 0, + Some(0), + AttributeNamespace::ItemOwner, + bvec![0], + bvec![0; 11], + )); + let (_, deposit) = + Attribute::::get((0, Some(0), AttributeNamespace::ItemOwner, &key)).unwrap(); + assert_eq!(deposit.account, Some(3)); + assert_eq!(deposit.amount, 13); + assert_eq!(Balances::reserved_balance(2), 3); + assert_eq!(Balances::reserved_balance(3), 13); + + // validate attributes on item deletion + assert_ok!(Nfts::burn(RuntimeOrigin::signed(3), 0, 0, None)); + assert_eq!( + attributes(0), + vec![ + (Some(0), AttributeNamespace::ItemOwner, bvec![0], bvec![0; 11]), + (Some(0), AttributeNamespace::ItemOwner, bvec![2], bvec![0]) + ] + ); + assert_ok!(Nfts::clear_attribute( + RuntimeOrigin::signed(3), + 0, + Some(0), + AttributeNamespace::ItemOwner, + bvec![0], + )); + assert_ok!(Nfts::clear_attribute( + RuntimeOrigin::signed(2), + 0, + Some(0), + AttributeNamespace::ItemOwner, + bvec![2], + )); + assert_eq!(Balances::reserved_balance(2), 0); + assert_eq!(Balances::reserved_balance(3), 0); + }); +} + +#[test] +fn set_external_account_attributes_should_work() { + new_test_ext().execute_with(|| { + Balances::make_free_balance_be(&1, 100); + Balances::make_free_balance_be(&2, 100); + + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + 1, + collection_config_with_all_settings_enabled() + )); + assert_ok!(Nfts::force_mint(RuntimeOrigin::signed(1), 0, 0, 1, default_item_config())); + assert_ok!(Nfts::approve_item_attributes(RuntimeOrigin::signed(1), 0, 0, 2)); + + assert_noop!( + Nfts::set_attribute( + RuntimeOrigin::signed(2), + 0, + Some(0), + AttributeNamespace::Account(1), + bvec![0], + bvec![0], + ), + Error::::NoPermission, + ); + assert_ok!(Nfts::set_attribute( + RuntimeOrigin::signed(2), + 0, + Some(0), + AttributeNamespace::Account(2), + bvec![0], + bvec![0], + )); + assert_ok!(Nfts::set_attribute( + RuntimeOrigin::signed(2), + 0, + Some(0), + AttributeNamespace::Account(2), + bvec![1], + bvec![0], + )); + assert_eq!( + attributes(0), + vec![ + (Some(0), AttributeNamespace::Account(2), bvec![0], bvec![0]), + (Some(0), AttributeNamespace::Account(2), bvec![1], bvec![0]), + ] + ); + assert_eq!(Balances::reserved_balance(2), 6); + + // remove permission to set attributes + assert_ok!(Nfts::cancel_item_attributes_approval( + RuntimeOrigin::signed(1), + 0, + 0, + 2, + CancelAttributesApprovalWitness { account_attributes: 2 }, + )); + assert_eq!(attributes(0), vec![]); + assert_eq!(Balances::reserved_balance(2), 0); + assert_noop!( + Nfts::set_attribute( + RuntimeOrigin::signed(2), + 0, + Some(0), + AttributeNamespace::Account(2), + bvec![0], + bvec![0], + ), + Error::::NoPermission, + ); + }); +} + +#[test] +fn validate_deposit_required_setting() { + new_test_ext().execute_with(|| { + Balances::make_free_balance_be(&1, 100); + Balances::make_free_balance_be(&2, 100); + Balances::make_free_balance_be(&3, 100); + + // with the disabled DepositRequired setting, only the collection's owner can set the + // attributes for free. + assert_ok!(Nfts::force_create(RuntimeOrigin::root(), 1, default_collection_config())); + assert_ok!(Nfts::force_mint(RuntimeOrigin::signed(1), 0, 0, 2, default_item_config())); + assert_ok!(Nfts::approve_item_attributes(RuntimeOrigin::signed(2), 0, 0, 3)); + + assert_ok!(Nfts::set_attribute( + RuntimeOrigin::signed(1), + 0, + Some(0), + AttributeNamespace::CollectionOwner, + bvec![0], + bvec![0], + )); + assert_ok!(Nfts::set_attribute( + RuntimeOrigin::signed(2), + 0, + Some(0), + AttributeNamespace::ItemOwner, + bvec![1], + bvec![0], + )); + assert_ok!(Nfts::set_attribute( + RuntimeOrigin::signed(3), + 0, + Some(0), + AttributeNamespace::Account(3), + bvec![2], + bvec![0], + )); + assert_ok!(::AccountId, ItemConfig>>::set_attribute( + &0, + &0, + &[3], + &[0], + )); + assert_eq!( + attributes(0), + vec![ + (Some(0), AttributeNamespace::CollectionOwner, bvec![0], bvec![0]), + (Some(0), AttributeNamespace::ItemOwner, bvec![1], bvec![0]), + (Some(0), AttributeNamespace::Account(3), bvec![2], bvec![0]), + (Some(0), AttributeNamespace::Pallet, bvec![3], bvec![0]), + ] + ); + assert_eq!(Balances::reserved_balance(1), 0); + assert_eq!(Balances::reserved_balance(2), 3); + assert_eq!(Balances::reserved_balance(3), 3); + }); +} + +#[test] +fn set_attribute_should_respect_lock() { + new_test_ext().execute_with(|| { + Balances::make_free_balance_be(&1, 100); + + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + 1, + collection_config_with_all_settings_enabled(), + )); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(1), 0, 0, 1, None)); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(1), 0, 1, 1, None)); + + assert_ok!(Nfts::set_attribute( + RuntimeOrigin::signed(1), + 0, + None, + AttributeNamespace::CollectionOwner, + bvec![0], + bvec![0], + )); + assert_ok!(Nfts::set_attribute( + RuntimeOrigin::signed(1), + 0, + Some(0), + AttributeNamespace::CollectionOwner, + bvec![0], + bvec![0], + )); + assert_ok!(Nfts::set_attribute( + RuntimeOrigin::signed(1), + 0, + Some(1), + AttributeNamespace::CollectionOwner, + bvec![0], + bvec![0], + )); + assert_eq!( + attributes(0), + vec![ + (None, AttributeNamespace::CollectionOwner, bvec![0], bvec![0]), + (Some(0), AttributeNamespace::CollectionOwner, bvec![0], bvec![0]), + (Some(1), AttributeNamespace::CollectionOwner, bvec![0], bvec![0]), + ] + ); + assert_eq!(Balances::reserved_balance(1), 11); + + assert_ok!(Nfts::set_collection_metadata(RuntimeOrigin::signed(1), 0, bvec![])); + assert_ok!(Nfts::lock_collection( + RuntimeOrigin::signed(1), + 0, + CollectionSettings::from_disabled(CollectionSetting::UnlockedAttributes.into()) + )); + + let e = Error::::LockedCollectionAttributes; + assert_noop!( + Nfts::set_attribute( + RuntimeOrigin::signed(1), + 0, + None, + AttributeNamespace::CollectionOwner, + bvec![0], + bvec![0], + ), + e + ); + assert_ok!(Nfts::set_attribute( + RuntimeOrigin::signed(1), + 0, + Some(0), + AttributeNamespace::CollectionOwner, + bvec![0], + bvec![1], + )); + + assert_ok!(Nfts::lock_item_properties(RuntimeOrigin::signed(1), 0, 0, false, true)); + let e = Error::::LockedItemAttributes; + assert_noop!( + Nfts::set_attribute( + RuntimeOrigin::signed(1), + 0, + Some(0), + AttributeNamespace::CollectionOwner, + bvec![0], + bvec![1], + ), + e + ); + assert_ok!(Nfts::set_attribute( + RuntimeOrigin::signed(1), + 0, + Some(1), + AttributeNamespace::CollectionOwner, + bvec![0], + bvec![1], + )); + }); +} + +#[test] +fn preserve_config_for_frozen_items() { + new_test_ext().execute_with(|| { + Balances::make_free_balance_be(&1, 100); + + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + 1, + collection_config_with_all_settings_enabled() + )); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(1), 0, 0, 1, None)); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(1), 0, 1, 1, None)); + + // if the item is not locked/frozen then the config gets deleted on item burn + assert_ok!(Nfts::burn(RuntimeOrigin::signed(1), 0, 1, Some(1))); + assert!(!ItemConfigOf::::contains_key(0, 1)); + + // lock the item and ensure the config stays unchanged + assert_ok!(Nfts::lock_item_properties(RuntimeOrigin::signed(1), 0, 0, true, true)); + + let expect_config = item_config_from_disabled_settings( + ItemSetting::UnlockedAttributes | ItemSetting::UnlockedMetadata, + ); + let config = ItemConfigOf::::get(0, 0).unwrap(); + assert_eq!(config, expect_config); + + assert_ok!(Nfts::burn(RuntimeOrigin::signed(1), 0, 0, Some(1))); + let config = ItemConfigOf::::get(0, 0).unwrap(); + assert_eq!(config, expect_config); + + // can't mint with the different config + assert_noop!( + Nfts::force_mint(RuntimeOrigin::signed(1), 0, 0, 1, default_item_config()), + Error::::InconsistentItemConfig + ); + + assert_ok!(Nfts::update_mint_settings( + RuntimeOrigin::signed(1), + 0, + MintSettings { + default_item_settings: ItemSettings::from_disabled( + ItemSetting::UnlockedAttributes | ItemSetting::UnlockedMetadata + ), + ..Default::default() + } + )); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(1), 0, 0, 1, None)); + }); +} + +#[test] +fn force_update_collection_should_work() { + new_test_ext().execute_with(|| { + Balances::make_free_balance_be(&1, 100); + + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + 1, + collection_config_with_all_settings_enabled() + )); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(1), 0, 42, 1, None)); + assert_ok!(Nfts::force_mint(RuntimeOrigin::signed(1), 0, 69, 2, default_item_config())); + assert_ok!(Nfts::set_collection_metadata(RuntimeOrigin::signed(1), 0, bvec![0; 20])); + assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(1), 0, 42, bvec![0; 20])); + assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(1), 0, 69, bvec![0; 20])); + assert_eq!(Balances::reserved_balance(1), 65); + + // force item status to be free holding + assert_ok!(Nfts::force_collection_config( + RuntimeOrigin::root(), + 0, + collection_config_from_disabled_settings(CollectionSetting::DepositRequired.into()), + )); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(1), 0, 142, 1, None)); + assert_ok!(Nfts::force_mint(RuntimeOrigin::signed(1), 0, 169, 2, default_item_config())); + assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(1), 0, 142, bvec![0; 20])); + assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(1), 0, 169, bvec![0; 20])); + + Balances::make_free_balance_be(&5, 100); + assert_ok!(Nfts::force_collection_owner(RuntimeOrigin::root(), 0, 5)); + assert_eq!(collections(), vec![(5, 0)]); + assert_eq!(Balances::reserved_balance(1), 2); + assert_eq!(Balances::reserved_balance(5), 63); + + assert_ok!(Nfts::redeposit(RuntimeOrigin::signed(5), 0, bvec![0, 42, 50, 69, 100])); + assert_eq!(Balances::reserved_balance(1), 0); + + assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(5), 0, 42, bvec![0; 20])); + assert_eq!(Balances::reserved_balance(5), 42); + + assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(5), 0, 69, bvec![0; 20])); + assert_eq!(Balances::reserved_balance(5), 21); + + assert_ok!(Nfts::set_collection_metadata(RuntimeOrigin::signed(5), 0, bvec![0; 20])); + assert_eq!(Balances::reserved_balance(5), 0); + + // validate new roles + assert_ok!(Nfts::set_team(RuntimeOrigin::root(), 0, 2, 3, 4)); + assert_eq!( + CollectionRoleOf::::get(0, 2).unwrap(), + CollectionRoles(CollectionRole::Issuer.into()) + ); + assert_eq!( + CollectionRoleOf::::get(0, 3).unwrap(), + CollectionRoles(CollectionRole::Admin.into()) + ); + assert_eq!( + CollectionRoleOf::::get(0, 4).unwrap(), + CollectionRoles(CollectionRole::Freezer.into()) + ); + + assert_ok!(Nfts::set_team(RuntimeOrigin::root(), 0, 3, 2, 3)); + + assert_eq!( + CollectionRoleOf::::get(0, 2).unwrap(), + CollectionRoles(CollectionRole::Admin.into()) + ); + assert_eq!( + CollectionRoleOf::::get(0, 3).unwrap(), + CollectionRoles(CollectionRole::Issuer | CollectionRole::Freezer) + ); + }); +} + +#[test] +fn burn_works() { + new_test_ext().execute_with(|| { + Balances::make_free_balance_be(&1, 100); + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + 1, + collection_config_with_all_settings_enabled() + )); + assert_ok!(Nfts::set_team(RuntimeOrigin::signed(1), 0, 2, 3, 4)); + + assert_noop!( + Nfts::burn(RuntimeOrigin::signed(5), 0, 42, Some(5)), + Error::::UnknownCollection + ); + + assert_ok!(Nfts::force_mint(RuntimeOrigin::signed(2), 0, 42, 5, default_item_config())); + assert_ok!(Nfts::force_mint(RuntimeOrigin::signed(2), 0, 69, 5, default_item_config())); + assert_eq!(Balances::reserved_balance(1), 2); + + assert_noop!( + Nfts::burn(RuntimeOrigin::signed(0), 0, 42, None), + Error::::NoPermission + ); + assert_noop!( + Nfts::burn(RuntimeOrigin::signed(5), 0, 42, Some(6)), + Error::::WrongOwner + ); + + assert_ok!(Nfts::burn(RuntimeOrigin::signed(5), 0, 42, Some(5))); + assert_ok!(Nfts::burn(RuntimeOrigin::signed(3), 0, 69, Some(5))); + assert_eq!(Balances::reserved_balance(1), 0); + }); +} + +#[test] +fn approval_lifecycle_works() { + new_test_ext().execute_with(|| { + assert_ok!(Nfts::force_create(RuntimeOrigin::root(), 1, default_collection_config())); + assert_ok!(Nfts::force_mint(RuntimeOrigin::signed(1), 0, 42, 2, default_item_config())); + assert_ok!(Nfts::approve_transfer(RuntimeOrigin::signed(2), 0, 42, 3, None)); + assert_ok!(Nfts::transfer(RuntimeOrigin::signed(3), 0, 42, 4)); + assert_noop!( + Nfts::transfer(RuntimeOrigin::signed(3), 0, 42, 3), + Error::::NoPermission + ); + assert!(Item::::get(0, 42).unwrap().approvals.is_empty()); + + assert_ok!(Nfts::approve_transfer(RuntimeOrigin::signed(4), 0, 42, 2, None)); + assert_ok!(Nfts::transfer(RuntimeOrigin::signed(2), 0, 42, 2)); + + // ensure we can't buy an item when the collection has a NonTransferableItems flag + let collection_id = 1; + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + 1, + collection_config_from_disabled_settings( + CollectionSetting::TransferableItems | CollectionSetting::DepositRequired + ) + )); + + assert_ok!(Nfts::mint(RuntimeOrigin::signed(1), 1, collection_id, 1, None)); + + assert_noop!( + Nfts::approve_transfer(RuntimeOrigin::signed(1), collection_id, 1, 2, None), + Error::::ItemsNonTransferable + ); + }); +} + +#[test] +fn cancel_approval_works() { + new_test_ext().execute_with(|| { + assert_ok!(Nfts::force_create(RuntimeOrigin::root(), 1, default_collection_config())); + assert_ok!(Nfts::force_mint(RuntimeOrigin::signed(1), 0, 42, 2, default_item_config())); + + assert_ok!(Nfts::approve_transfer(RuntimeOrigin::signed(2), 0, 42, 3, None)); + assert_noop!( + Nfts::cancel_approval(RuntimeOrigin::signed(2), 1, 42, 3), + Error::::UnknownItem + ); + assert_noop!( + Nfts::cancel_approval(RuntimeOrigin::signed(2), 0, 43, 3), + Error::::UnknownItem + ); + assert_noop!( + Nfts::cancel_approval(RuntimeOrigin::signed(3), 0, 42, 3), + Error::::NoPermission + ); + assert_noop!( + Nfts::cancel_approval(RuntimeOrigin::signed(2), 0, 42, 4), + Error::::NotDelegate + ); + + assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(2), 0, 42, 3)); + assert_noop!( + Nfts::cancel_approval(RuntimeOrigin::signed(2), 0, 42, 3), + Error::::NotDelegate + ); + + let current_block = 1; + System::set_block_number(current_block); + assert_ok!(Nfts::force_mint(RuntimeOrigin::signed(1), 0, 69, 2, default_item_config())); + // approval expires after 2 blocks. + assert_ok!(Nfts::approve_transfer(RuntimeOrigin::signed(2), 0, 42, 3, Some(2))); + assert_noop!( + Nfts::cancel_approval(RuntimeOrigin::signed(5), 0, 42, 3), + Error::::NoPermission + ); + + System::set_block_number(current_block + 3); + // 5 can cancel the approval since the deadline has passed. + assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(5), 0, 42, 3)); + assert_eq!(approvals(0, 69), vec![]); + }); +} + +#[test] +fn approving_multiple_accounts_works() { + new_test_ext().execute_with(|| { + assert_ok!(Nfts::force_create(RuntimeOrigin::root(), 1, default_collection_config())); + assert_ok!(Nfts::force_mint(RuntimeOrigin::signed(1), 0, 42, 2, default_item_config())); + + let current_block = 1; + System::set_block_number(current_block); + assert_ok!(Nfts::approve_transfer(RuntimeOrigin::signed(2), 0, 42, 3, None)); + assert_ok!(Nfts::approve_transfer(RuntimeOrigin::signed(2), 0, 42, 4, None)); + assert_ok!(Nfts::approve_transfer(RuntimeOrigin::signed(2), 0, 42, 5, Some(2))); + assert_eq!(approvals(0, 42), vec![(3, None), (4, None), (5, Some(current_block + 2))]); + + assert_ok!(Nfts::transfer(RuntimeOrigin::signed(4), 0, 42, 6)); + assert_noop!( + Nfts::transfer(RuntimeOrigin::signed(3), 0, 42, 7), + Error::::NoPermission + ); + assert_noop!( + Nfts::transfer(RuntimeOrigin::signed(5), 0, 42, 8), + Error::::NoPermission + ); + }); +} + +#[test] +fn approvals_limit_works() { + new_test_ext().execute_with(|| { + assert_ok!(Nfts::force_create(RuntimeOrigin::root(), 1, default_collection_config())); + assert_ok!(Nfts::force_mint(RuntimeOrigin::signed(1), 0, 42, 2, default_item_config())); + + for i in 3..13 { + assert_ok!(Nfts::approve_transfer(RuntimeOrigin::signed(2), 0, 42, i, None)); + } + // the limit is 10 + assert_noop!( + Nfts::approve_transfer(RuntimeOrigin::signed(2), 0, 42, 14, None), + Error::::ReachedApprovalLimit + ); + }); +} + +#[test] +fn approval_deadline_works() { + new_test_ext().execute_with(|| { + System::set_block_number(0); + assert!(System::block_number().is_zero()); + + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + 1, + collection_config_from_disabled_settings(CollectionSetting::DepositRequired.into()) + )); + assert_ok!(Nfts::force_mint(RuntimeOrigin::signed(1), 0, 42, 2, default_item_config())); + + // the approval expires after the 2nd block. + assert_ok!(Nfts::approve_transfer(RuntimeOrigin::signed(2), 0, 42, 3, Some(2))); + + System::set_block_number(3); + assert_noop!( + Nfts::transfer(RuntimeOrigin::signed(3), 0, 42, 4), + Error::::ApprovalExpired + ); + System::set_block_number(1); + assert_ok!(Nfts::transfer(RuntimeOrigin::signed(3), 0, 42, 4)); + + assert_eq!(System::block_number(), 1); + // make a new approval with a deadline after 4 blocks, so it will expire after the 5th + // block. + assert_ok!(Nfts::approve_transfer(RuntimeOrigin::signed(4), 0, 42, 6, Some(4))); + // this should still work. + System::set_block_number(5); + assert_ok!(Nfts::transfer(RuntimeOrigin::signed(6), 0, 42, 5)); + }); +} + +#[test] +fn cancel_approval_works_with_admin() { + new_test_ext().execute_with(|| { + assert_ok!(Nfts::force_create(RuntimeOrigin::root(), 1, default_collection_config())); + assert_ok!(Nfts::force_mint(RuntimeOrigin::signed(1), 0, 42, 2, default_item_config())); + + assert_ok!(Nfts::approve_transfer(RuntimeOrigin::signed(2), 0, 42, 3, None)); + assert_noop!( + Nfts::cancel_approval(RuntimeOrigin::signed(1), 1, 42, 1), + Error::::UnknownItem + ); + assert_noop!( + Nfts::cancel_approval(RuntimeOrigin::signed(1), 0, 43, 1), + Error::::UnknownItem + ); + assert_noop!( + Nfts::cancel_approval(RuntimeOrigin::signed(1), 0, 42, 4), + Error::::NotDelegate + ); + + assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(1), 0, 42, 3)); + assert_noop!( + Nfts::cancel_approval(RuntimeOrigin::signed(1), 0, 42, 1), + Error::::NotDelegate + ); + }); +} + +#[test] +fn cancel_approval_works_with_force() { + new_test_ext().execute_with(|| { + assert_ok!(Nfts::force_create(RuntimeOrigin::root(), 1, default_collection_config())); + assert_ok!(Nfts::force_mint(RuntimeOrigin::signed(1), 0, 42, 2, default_item_config())); + + assert_ok!(Nfts::approve_transfer(RuntimeOrigin::signed(2), 0, 42, 3, None)); + assert_noop!( + Nfts::cancel_approval(RuntimeOrigin::root(), 1, 42, 1), + Error::::UnknownItem + ); + assert_noop!( + Nfts::cancel_approval(RuntimeOrigin::root(), 0, 43, 1), + Error::::UnknownItem + ); + assert_noop!( + Nfts::cancel_approval(RuntimeOrigin::root(), 0, 42, 4), + Error::::NotDelegate + ); + + assert_ok!(Nfts::cancel_approval(RuntimeOrigin::root(), 0, 42, 3)); + assert_noop!( + Nfts::cancel_approval(RuntimeOrigin::root(), 0, 42, 1), + Error::::NotDelegate + ); + }); +} + +#[test] +fn clear_all_transfer_approvals_works() { + new_test_ext().execute_with(|| { + assert_ok!(Nfts::force_create(RuntimeOrigin::root(), 1, default_collection_config())); + assert_ok!(Nfts::force_mint(RuntimeOrigin::signed(1), 0, 42, 2, default_item_config())); + + assert_ok!(Nfts::approve_transfer(RuntimeOrigin::signed(2), 0, 42, 3, None)); + assert_ok!(Nfts::approve_transfer(RuntimeOrigin::signed(2), 0, 42, 4, None)); + + assert_noop!( + Nfts::clear_all_transfer_approvals(RuntimeOrigin::signed(3), 0, 42), + Error::::NoPermission + ); + + assert_ok!(Nfts::clear_all_transfer_approvals(RuntimeOrigin::signed(2), 0, 42)); + + assert!(events().contains(&Event::::AllApprovalsCancelled { + collection: 0, + item: 42, + owner: 2, + })); + assert_eq!(approvals(0, 42), vec![]); + + assert_noop!( + Nfts::transfer(RuntimeOrigin::signed(3), 0, 42, 5), + Error::::NoPermission + ); + assert_noop!( + Nfts::transfer(RuntimeOrigin::signed(4), 0, 42, 5), + Error::::NoPermission + ); + }); +} + +#[test] +fn max_supply_should_work() { + new_test_ext().execute_with(|| { + let collection_id = 0; + let user_id = 1; + let max_supply = 1; + + // validate set_collection_max_supply + assert_ok!(Nfts::force_create(RuntimeOrigin::root(), user_id, default_collection_config())); + assert_eq!(CollectionConfigOf::::get(collection_id).unwrap().max_supply, None); + + assert_ok!(Nfts::set_collection_max_supply( + RuntimeOrigin::signed(user_id), + collection_id, + max_supply + )); + assert_eq!( + CollectionConfigOf::::get(collection_id).unwrap().max_supply, + Some(max_supply) + ); + + assert!(events().contains(&Event::::CollectionMaxSupplySet { + collection: collection_id, + max_supply, + })); + + assert_ok!(Nfts::set_collection_max_supply( + RuntimeOrigin::signed(user_id), + collection_id, + max_supply + 1 + )); + assert_ok!(Nfts::lock_collection( + RuntimeOrigin::signed(user_id), + collection_id, + CollectionSettings::from_disabled(CollectionSetting::UnlockedMaxSupply.into()) + )); + assert_noop!( + Nfts::set_collection_max_supply( + RuntimeOrigin::signed(user_id), + collection_id, + max_supply + 2 + ), + Error::::MaxSupplyLocked + ); + + // validate we can't mint more to max supply + assert_ok!(Nfts::mint(RuntimeOrigin::signed(user_id), collection_id, 0, user_id, None)); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(user_id), collection_id, 1, user_id, None)); + assert_noop!( + Nfts::mint(RuntimeOrigin::signed(user_id), collection_id, 2, user_id, None), + Error::::MaxSupplyReached + ); + }); +} + +#[test] +fn mint_settings_should_work() { + new_test_ext().execute_with(|| { + let collection_id = 0; + let user_id = 1; + let item_id = 0; + + assert_ok!(Nfts::force_create(RuntimeOrigin::root(), user_id, default_collection_config())); + assert_ok!(Nfts::mint( + RuntimeOrigin::signed(user_id), + collection_id, + item_id, + user_id, + None, + )); + assert_eq!( + ItemConfigOf::::get(collection_id, item_id) + .unwrap() + .settings + .get_disabled(), + ItemSettings::all_enabled().get_disabled() + ); + + let collection_id = 1; + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + user_id, + CollectionConfig { + mint_settings: MintSettings { + default_item_settings: ItemSettings::from_disabled( + ItemSetting::Transferable | ItemSetting::UnlockedMetadata + ), + ..Default::default() + }, + ..default_collection_config() + } + )); + assert_ok!(Nfts::mint( + RuntimeOrigin::signed(user_id), + collection_id, + item_id, + user_id, + None, + )); + assert_eq!( + ItemConfigOf::::get(collection_id, item_id) + .unwrap() + .settings + .get_disabled(), + ItemSettings::from_disabled(ItemSetting::Transferable | ItemSetting::UnlockedMetadata) + .get_disabled() + ); + }); +} + +#[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!(Nfts::force_create(RuntimeOrigin::root(), user_id, default_collection_config())); + + assert_ok!(Nfts::mint( + RuntimeOrigin::signed(user_id), + collection_id, + item_1, + user_id, + None, + )); + assert_ok!(Nfts::mint( + RuntimeOrigin::signed(user_id), + collection_id, + item_2, + user_id, + None, + )); + + assert_ok!(Nfts::set_price( + RuntimeOrigin::signed(user_id), + collection_id, + item_1, + Some(1), + None, + )); + + assert_ok!(Nfts::set_price( + RuntimeOrigin::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!(Nfts::set_price( + RuntimeOrigin::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)); + + // ensure we can't set price when the items are non-transferable + let collection_id = 1; + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + user_id, + collection_config_from_disabled_settings( + CollectionSetting::TransferableItems | CollectionSetting::DepositRequired + ) + )); + + assert_ok!(Nfts::mint( + RuntimeOrigin::signed(user_id), + collection_id, + item_1, + user_id, + None, + )); + + assert_noop!( + Nfts::set_price(RuntimeOrigin::signed(user_id), collection_id, item_1, Some(2), None), + Error::::ItemsNonTransferable + ); + }); +} + +#[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!(Nfts::force_create(RuntimeOrigin::root(), user_1, default_collection_config())); + + assert_ok!(Nfts::mint(RuntimeOrigin::signed(user_1), collection_id, item_1, user_1, None)); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(user_1), collection_id, item_2, user_1, None)); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(user_1), collection_id, item_3, user_1, None)); + + assert_ok!(Nfts::set_price( + RuntimeOrigin::signed(user_1), + collection_id, + item_1, + Some(price_1), + None, + )); + + assert_ok!(Nfts::set_price( + RuntimeOrigin::signed(user_1), + collection_id, + item_2, + Some(price_2), + Some(user_3), + )); + + // can't buy for less + assert_noop!( + Nfts::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!(Nfts::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(); + 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!( + Nfts::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!( + Nfts::buy_item(RuntimeOrigin::signed(user_2), collection_id, item_2, price_2), + Error::::NoPermission + ); + + // can buy when I'm a whitelisted buyer + assert_ok!(Nfts::buy_item(RuntimeOrigin::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!( + Nfts::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 are frozen + { + assert_ok!(Nfts::set_price( + RuntimeOrigin::signed(user_1), + collection_id, + item_3, + Some(price_1), + None, + )); + + // lock the collection + assert_ok!(Nfts::lock_collection( + RuntimeOrigin::signed(user_1), + collection_id, + CollectionSettings::from_disabled(CollectionSetting::TransferableItems.into()) + )); + + let buy_item_call = mock::RuntimeCall::Nfts(crate::Call::::buy_item { + collection: collection_id, + item: item_3, + bid_price: price_1, + }); + assert_noop!( + buy_item_call.dispatch(RuntimeOrigin::signed(user_2)), + Error::::ItemsNonTransferable + ); + + // unlock the collection + assert_ok!(Nfts::force_collection_config( + RuntimeOrigin::root(), + collection_id, + collection_config_with_all_settings_enabled(), + )); + + // lock the transfer + assert_ok!(Nfts::lock_item_transfer( + RuntimeOrigin::signed(user_1), + collection_id, + item_3, + )); + + let buy_item_call = mock::RuntimeCall::Nfts(crate::Call::::buy_item { + collection: collection_id, + item: item_3, + bid_price: price_1, + }); + assert_noop!( + buy_item_call.dispatch(RuntimeOrigin::signed(user_2)), + Error::::ItemLocked + ); + } + }); +} + +#[test] +fn pay_tips_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_id = 1; + let tip = 2; + 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!(Nfts::pay_tips( + RuntimeOrigin::signed(user_1), + bvec![ + ItemTip { collection: collection_id, item: item_id, receiver: user_2, amount: tip }, + ItemTip { collection: collection_id, item: item_id, receiver: user_3, amount: tip }, + ] + )); + + assert_eq!(Balances::total_balance(&user_1), initial_balance - tip * 2); + assert_eq!(Balances::total_balance(&user_2), initial_balance + tip); + assert_eq!(Balances::total_balance(&user_3), initial_balance + tip); + + let events = events(); + assert!(events.contains(&Event::::TipSent { + collection: collection_id, + item: item_id, + sender: user_1, + receiver: user_2, + amount: tip, + })); + assert!(events.contains(&Event::::TipSent { + collection: collection_id, + item: item_id, + sender: user_1, + receiver: user_3, + amount: tip, + })); + }); +} + +#[test] +fn create_cancel_swap_should_work() { + new_test_ext().execute_with(|| { + System::set_block_number(1); + let user_id = 1; + let collection_id = 0; + let item_1 = 1; + let item_2 = 2; + let price = 1; + let price_direction = PriceDirection::Receive; + let price_with_direction = PriceWithDirection { amount: price, direction: price_direction }; + let duration = 2; + let expect_deadline = 3; + + assert_ok!(Nfts::force_create(RuntimeOrigin::root(), user_id, default_collection_config())); + + assert_ok!(Nfts::mint( + RuntimeOrigin::signed(user_id), + collection_id, + item_1, + user_id, + None, + )); + assert_ok!(Nfts::mint( + RuntimeOrigin::signed(user_id), + collection_id, + item_2, + user_id, + None, + )); + + // validate desired item and the collection exists + assert_noop!( + Nfts::create_swap( + RuntimeOrigin::signed(user_id), + collection_id, + item_1, + collection_id, + Some(item_2 + 1), + Some(price_with_direction.clone()), + duration, + ), + Error::::UnknownItem + ); + assert_noop!( + Nfts::create_swap( + RuntimeOrigin::signed(user_id), + collection_id, + item_1, + collection_id + 1, + None, + Some(price_with_direction.clone()), + duration, + ), + Error::::UnknownCollection + ); + + let max_duration: u64 = ::MaxDeadlineDuration::get(); + assert_noop!( + Nfts::create_swap( + RuntimeOrigin::signed(user_id), + collection_id, + item_1, + collection_id, + Some(item_2), + Some(price_with_direction.clone()), + max_duration.saturating_add(1), + ), + Error::::WrongDuration + ); + + assert_ok!(Nfts::create_swap( + RuntimeOrigin::signed(user_id), + collection_id, + item_1, + collection_id, + Some(item_2), + Some(price_with_direction.clone()), + duration, + )); + + let swap = PendingSwapOf::::get(collection_id, item_1).unwrap(); + assert_eq!(swap.desired_collection, collection_id); + assert_eq!(swap.desired_item, Some(item_2)); + assert_eq!(swap.price, Some(price_with_direction.clone())); + assert_eq!(swap.deadline, expect_deadline); + + assert!(events().contains(&Event::::SwapCreated { + offered_collection: collection_id, + offered_item: item_1, + desired_collection: collection_id, + desired_item: Some(item_2), + price: Some(price_with_direction.clone()), + deadline: expect_deadline, + })); + + // validate we can cancel the swap + assert_ok!(Nfts::cancel_swap(RuntimeOrigin::signed(user_id), collection_id, item_1)); + assert!(events().contains(&Event::::SwapCancelled { + offered_collection: collection_id, + offered_item: item_1, + desired_collection: collection_id, + desired_item: Some(item_2), + price: Some(price_with_direction.clone()), + deadline: expect_deadline, + })); + assert!(!PendingSwapOf::::contains_key(collection_id, item_1)); + + // validate anyone can cancel the expired swap + assert_ok!(Nfts::create_swap( + RuntimeOrigin::signed(user_id), + collection_id, + item_1, + collection_id, + Some(item_2), + Some(price_with_direction.clone()), + duration, + )); + assert_noop!( + Nfts::cancel_swap(RuntimeOrigin::signed(user_id + 1), collection_id, item_1), + Error::::NoPermission + ); + System::set_block_number(expect_deadline + 1); + assert_ok!(Nfts::cancel_swap(RuntimeOrigin::signed(user_id + 1), collection_id, item_1)); + + // validate optional desired_item param + assert_ok!(Nfts::create_swap( + RuntimeOrigin::signed(user_id), + collection_id, + item_1, + collection_id, + None, + Some(price_with_direction), + duration, + )); + + let swap = PendingSwapOf::::get(collection_id, item_1).unwrap(); + assert_eq!(swap.desired_item, None); + }); +} + +#[test] +fn claim_swap_should_work() { + new_test_ext().execute_with(|| { + System::set_block_number(1); + let user_1 = 1; + let user_2 = 2; + let collection_id = 0; + let item_1 = 1; + let item_2 = 2; + let item_3 = 3; + let item_4 = 4; + let item_5 = 5; + let price = 100; + let price_direction = PriceDirection::Receive; + let price_with_direction = + PriceWithDirection { amount: price, direction: price_direction.clone() }; + let duration = 2; + let initial_balance = 1000; + let deadline = 1 + duration; + + Balances::make_free_balance_be(&user_1, initial_balance); + Balances::make_free_balance_be(&user_2, initial_balance); + + assert_ok!(Nfts::force_create(RuntimeOrigin::root(), user_1, default_collection_config())); + + assert_ok!(Nfts::mint( + RuntimeOrigin::signed(user_1), + collection_id, + item_1,user_1, + None, + )); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(user_1), + collection_id, + item_2, + user_2, + default_item_config(), + )); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(user_1), + collection_id, + item_3, + user_2, + default_item_config(), + )); + assert_ok!(Nfts::mint( + RuntimeOrigin::signed(user_1), + collection_id, + item_4, + user_1, + None, + )); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(user_1), + collection_id, + item_5, + user_2, + default_item_config(), + )); + + assert_ok!(Nfts::create_swap( + RuntimeOrigin::signed(user_1), + collection_id, + item_1, + collection_id, + Some(item_2), + Some(price_with_direction.clone()), + duration, + )); + + // validate the deadline + System::set_block_number(5); + assert_noop!( + Nfts::claim_swap( + RuntimeOrigin::signed(user_2), + collection_id, + item_2, + collection_id, + item_1, + Some(price_with_direction.clone()), + ), + Error::::DeadlineExpired + ); + System::set_block_number(1); + + // validate edge cases + assert_noop!( + Nfts::claim_swap( + RuntimeOrigin::signed(user_2), + collection_id, + item_2, + collection_id, + item_4, // no swap was created for that asset + Some(price_with_direction.clone()), + ), + Error::::UnknownSwap + ); + assert_noop!( + Nfts::claim_swap( + RuntimeOrigin::signed(user_2), + collection_id, + item_4, // not my item + collection_id, + item_1, + Some(price_with_direction.clone()), + ), + Error::::NoPermission + ); + assert_noop!( + Nfts::claim_swap( + RuntimeOrigin::signed(user_2), + collection_id, + item_5, // my item, but not the one another part wants + collection_id, + item_1, + Some(price_with_direction.clone()), + ), + Error::::UnknownSwap + ); + assert_noop!( + Nfts::claim_swap( + RuntimeOrigin::signed(user_2), + collection_id, + item_2, + collection_id, + item_1, + Some(PriceWithDirection { amount: price + 1, direction: price_direction.clone() }), // wrong price + ), + Error::::UnknownSwap + ); + assert_noop!( + Nfts::claim_swap( + RuntimeOrigin::signed(user_2), + collection_id, + item_2, + collection_id, + item_1, + Some(PriceWithDirection { amount: price, direction: PriceDirection::Send }), // wrong direction + ), + Error::::UnknownSwap + ); + + assert_ok!(Nfts::claim_swap( + RuntimeOrigin::signed(user_2), + collection_id, + item_2, + collection_id, + item_1, + Some(price_with_direction.clone()), + )); + + // validate the new owner + let item = Item::::get(collection_id, item_1).unwrap(); + assert_eq!(item.owner, user_2); + let item = Item::::get(collection_id, item_2).unwrap(); + assert_eq!(item.owner, user_1); + + // validate the balances + assert_eq!(Balances::total_balance(&user_1), initial_balance + price); + assert_eq!(Balances::total_balance(&user_2), initial_balance - price); + + // ensure we reset the swap + assert!(!PendingSwapOf::::contains_key(collection_id, item_1)); + + // validate the event + assert!(events().contains(&Event::::SwapClaimed { + sent_collection: collection_id, + sent_item: item_2, + sent_item_owner: user_2, + received_collection: collection_id, + received_item: item_1, + received_item_owner: user_1, + price: Some(price_with_direction.clone()), + deadline, + })); + + // validate the optional desired_item param and another price direction + let price_direction = PriceDirection::Send; + let price_with_direction = PriceWithDirection { amount: price, direction: price_direction }; + Balances::make_free_balance_be(&user_1, initial_balance); + Balances::make_free_balance_be(&user_2, initial_balance); + + assert_ok!(Nfts::create_swap( + RuntimeOrigin::signed(user_1), + collection_id, + item_4, + collection_id, + None, + Some(price_with_direction.clone()), + duration, + )); + assert_ok!(Nfts::claim_swap( + RuntimeOrigin::signed(user_2), + collection_id, + item_1, + collection_id, + item_4, + Some(price_with_direction), + )); + let item = Item::::get(collection_id, item_1).unwrap(); + assert_eq!(item.owner, user_1); + let item = Item::::get(collection_id, item_4).unwrap(); + assert_eq!(item.owner, user_2); + + assert_eq!(Balances::total_balance(&user_1), initial_balance - price); + assert_eq!(Balances::total_balance(&user_2), initial_balance + price); + }); +} + +#[test] +fn various_collection_settings() { + new_test_ext().execute_with(|| { + // when we set only one value it's required to call .into() on it + let config = + collection_config_from_disabled_settings(CollectionSetting::TransferableItems.into()); + assert_ok!(Nfts::force_create(RuntimeOrigin::root(), 1, config)); + + let config = CollectionConfigOf::::get(0).unwrap(); + assert!(!config.is_setting_enabled(CollectionSetting::TransferableItems)); + assert!(config.is_setting_enabled(CollectionSetting::UnlockedMetadata)); + + // no need to call .into() for multiple values + let config = collection_config_from_disabled_settings( + CollectionSetting::UnlockedMetadata | CollectionSetting::TransferableItems, + ); + assert_ok!(Nfts::force_create(RuntimeOrigin::root(), 1, config)); + + let config = CollectionConfigOf::::get(1).unwrap(); + assert!(!config.is_setting_enabled(CollectionSetting::TransferableItems)); + assert!(!config.is_setting_enabled(CollectionSetting::UnlockedMetadata)); + + assert_ok!(Nfts::force_create(RuntimeOrigin::root(), 1, default_collection_config())); + }); +} + +#[test] +fn collection_locking_should_work() { + new_test_ext().execute_with(|| { + let user_id = 1; + let collection_id = 0; + + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + user_id, + collection_config_with_all_settings_enabled() + )); + + let lock_config = + collection_config_from_disabled_settings(CollectionSetting::DepositRequired.into()); + assert_noop!( + Nfts::lock_collection( + RuntimeOrigin::signed(user_id), + collection_id, + lock_config.settings, + ), + Error::::WrongSetting + ); + + // validate partial lock + let lock_config = collection_config_from_disabled_settings( + CollectionSetting::TransferableItems | CollectionSetting::UnlockedAttributes, + ); + assert_ok!(Nfts::lock_collection( + RuntimeOrigin::signed(user_id), + collection_id, + lock_config.settings, + )); + + let stored_config = CollectionConfigOf::::get(collection_id).unwrap(); + assert_eq!(stored_config, lock_config); + + // validate full lock + assert_ok!(Nfts::lock_collection( + RuntimeOrigin::signed(user_id), + collection_id, + CollectionSettings::from_disabled(CollectionSetting::UnlockedMetadata.into()), + )); + + let stored_config = CollectionConfigOf::::get(collection_id).unwrap(); + let full_lock_config = collection_config_from_disabled_settings( + CollectionSetting::TransferableItems | + CollectionSetting::UnlockedMetadata | + CollectionSetting::UnlockedAttributes, + ); + assert_eq!(stored_config, full_lock_config); + }); +} + +#[test] +fn pallet_level_feature_flags_should_work() { + new_test_ext().execute_with(|| { + Features::set(&PalletFeatures::from_disabled( + PalletFeature::Trading | PalletFeature::Approvals | PalletFeature::Attributes, + )); + + let user_id = 1; + let collection_id = 0; + let item_id = 1; + + assert_ok!(Nfts::force_create(RuntimeOrigin::root(), user_id, default_collection_config())); + + assert_ok!(Nfts::mint( + RuntimeOrigin::signed(user_id), + collection_id, + item_id, + user_id, + None, + )); + + // PalletFeature::Trading + assert_noop!( + Nfts::set_price(RuntimeOrigin::signed(user_id), collection_id, item_id, Some(1), None), + Error::::MethodDisabled + ); + assert_noop!( + Nfts::buy_item(RuntimeOrigin::signed(user_id), collection_id, item_id, 1), + Error::::MethodDisabled + ); + + // PalletFeature::Approvals + assert_noop!( + Nfts::approve_transfer(RuntimeOrigin::signed(user_id), collection_id, item_id, 2, None), + Error::::MethodDisabled + ); + + // PalletFeature::Attributes + assert_noop!( + Nfts::set_attribute( + RuntimeOrigin::signed(user_id), + collection_id, + None, + AttributeNamespace::CollectionOwner, + bvec![0], + bvec![0], + ), + Error::::MethodDisabled + ); + }) +} + +#[test] +fn group_roles_by_account_should_work() { + new_test_ext().execute_with(|| { + assert_eq!(Nfts::group_roles_by_account(vec![]), vec![]); + + let account_to_role = Nfts::group_roles_by_account(vec![ + (3, CollectionRole::Freezer), + (1, CollectionRole::Issuer), + (2, CollectionRole::Admin), + ]); + let expect = vec![ + (1, CollectionRoles(CollectionRole::Issuer.into())), + (2, CollectionRoles(CollectionRole::Admin.into())), + (3, CollectionRoles(CollectionRole::Freezer.into())), + ]; + assert_eq!(account_to_role, expect); + + let account_to_role = Nfts::group_roles_by_account(vec![ + (3, CollectionRole::Freezer), + (2, CollectionRole::Issuer), + (2, CollectionRole::Admin), + ]); + let expect = vec![ + (2, CollectionRoles(CollectionRole::Issuer | CollectionRole::Admin)), + (3, CollectionRoles(CollectionRole::Freezer.into())), + ]; + assert_eq!(account_to_role, expect); + }) +} + +#[test] +fn add_remove_item_attributes_approval_should_work() { + new_test_ext().execute_with(|| { + let user_1 = 1; + let user_2 = 2; + let user_3 = 3; + let user_4 = 4; + let collection_id = 0; + let item_id = 0; + + assert_ok!(Nfts::force_create(RuntimeOrigin::root(), user_1, default_collection_config())); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(user_1), collection_id, item_id, user_1, None)); + assert_ok!(Nfts::approve_item_attributes( + RuntimeOrigin::signed(user_1), + collection_id, + item_id, + user_2, + )); + assert_eq!(item_attributes_approvals(collection_id, item_id), vec![user_2]); + + assert_ok!(Nfts::approve_item_attributes( + RuntimeOrigin::signed(user_1), + collection_id, + item_id, + user_3, + )); + assert_ok!(Nfts::approve_item_attributes( + RuntimeOrigin::signed(user_1), + collection_id, + item_id, + user_2, + )); + assert_eq!(item_attributes_approvals(collection_id, item_id), vec![user_2, user_3]); + + assert_noop!( + Nfts::approve_item_attributes( + RuntimeOrigin::signed(user_1), + collection_id, + item_id, + user_4, + ), + Error::::ReachedApprovalLimit + ); + + assert_ok!(Nfts::cancel_item_attributes_approval( + RuntimeOrigin::signed(user_1), + collection_id, + item_id, + user_2, + CancelAttributesApprovalWitness { account_attributes: 1 }, + )); + assert_eq!(item_attributes_approvals(collection_id, item_id), vec![user_3]); + }) +} diff --git a/frame/nfts/src/types.rs b/frame/nfts/src/types.rs new file mode 100644 index 0000000000000..58b1acaaedf42 --- /dev/null +++ b/frame/nfts/src/types.rs @@ -0,0 +1,465 @@ +// 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. + +//! Various basic types for use in the Nfts pallet. + +use super::*; +use crate::macros::*; +use codec::EncodeLike; +use enumflags2::{bitflags, BitFlags}; +use frame_support::{ + pallet_prelude::{BoundedVec, MaxEncodedLen}, + traits::Get, + BoundedBTreeMap, BoundedBTreeSet, +}; +use scale_info::{build::Fields, meta_type, Path, Type, TypeInfo, TypeParameter}; + +pub(super) type DepositBalanceOf = + <>::Currency as Currency<::AccountId>>::Balance; +pub(super) type CollectionDetailsFor = + CollectionDetails<::AccountId, DepositBalanceOf>; +pub(super) type ApprovalsOf = BoundedBTreeMap< + ::AccountId, + Option<::BlockNumber>, + >::ApprovalsLimit, +>; +pub(super) type ItemAttributesApprovals = + BoundedBTreeSet<::AccountId, >::ItemAttributesApprovalsLimit>; +pub(super) type ItemDepositOf = + ItemDeposit, ::AccountId>; +pub(super) type AttributeDepositOf = + AttributeDeposit, ::AccountId>; +pub(super) type ItemDetailsFor = + ItemDetails<::AccountId, ItemDepositOf, ApprovalsOf>; +pub(super) type BalanceOf = + <>::Currency as Currency<::AccountId>>::Balance; +pub(super) type ItemPrice = BalanceOf; +pub(super) type ItemTipOf = ItemTip< + >::CollectionId, + >::ItemId, + ::AccountId, + BalanceOf, +>; +pub(super) type CollectionConfigFor = CollectionConfig< + BalanceOf, + ::BlockNumber, + >::CollectionId, +>; + +pub trait Incrementable { + fn increment(&self) -> Self; + fn initial_value() -> Self; +} +impl_incrementable!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128); + +/// Information about a collection. +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +pub struct CollectionDetails { + /// Collection's owner. + pub(super) owner: AccountId, + /// The total balance deposited by the owner for all the storage data associated with this + /// collection. Used by `destroy`. + pub(super) owner_deposit: DepositBalance, + /// 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, +} + +/// Witness data for the destroy transactions. +#[derive(Copy, Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +pub struct DestroyWitness { + /// The total number of outstanding items of this collection. + #[codec(compact)] + pub items: u32, + /// The total number of items in this collection that have outstanding item metadata. + #[codec(compact)] + pub item_metadatas: u32, + /// The total number of attributes for this collection. + #[codec(compact)] + pub attributes: u32, +} + +impl CollectionDetails { + pub fn destroy_witness(&self) -> DestroyWitness { + DestroyWitness { + items: self.items, + item_metadatas: self.item_metadatas, + attributes: self.attributes, + } + } +} + +/// Witness data for items mint transactions. +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo)] +pub struct MintWitness { + /// Provide the id of the item in a required collection. + pub owner_of_item: ItemId, +} + +/// Information concerning the ownership of a single unique item. +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, Default, TypeInfo, MaxEncodedLen)] +pub struct ItemDetails { + /// The owner of this item. + pub(super) owner: AccountId, + /// The approved transferrer of this item, if one is set. + pub(super) approvals: Approvals, + /// The amount held in the pallet's default account for this item. Free-hold items will have + /// this as zero. + pub(super) deposit: Deposit, +} + +/// Information about the reserved item deposit. +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +pub struct ItemDeposit { + /// A depositor account. + pub(super) account: AccountId, + /// An amount that gets reserved. + pub(super) amount: DepositBalance, +} + +/// Information about the collection's metadata. +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, Default, TypeInfo, MaxEncodedLen)] +#[scale_info(skip_type_params(StringLimit))] +#[codec(mel_bound(DepositBalance: MaxEncodedLen))] +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 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, +} + +/// Information about the item's metadata. +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, Default, TypeInfo, MaxEncodedLen)] +#[scale_info(skip_type_params(StringLimit))] +#[codec(mel_bound(DepositBalance: MaxEncodedLen))] +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 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, +} + +/// Information about the tip. +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +pub struct ItemTip { + /// The collection of the item. + pub(super) collection: CollectionId, + /// An item of which the tip is sent for. + pub(super) item: ItemId, + /// A sender of the tip. + pub(super) receiver: AccountId, + /// An amount the sender is willing to tip. + pub(super) amount: Amount, +} + +/// Information about the pending swap. +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, Default, TypeInfo, MaxEncodedLen)] +pub struct PendingSwap { + /// The collection that contains the item that the user wants to receive. + pub(super) desired_collection: CollectionId, + /// The item the user wants to receive. + pub(super) desired_item: Option, + /// A price for the desired `item` with the direction. + pub(super) price: Option, + /// An optional deadline for the swap. + pub(super) deadline: Deadline, +} + +/// Information about the reserved attribute deposit. +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +pub struct AttributeDeposit { + /// A depositor account. + pub(super) account: Option, + /// An amount that gets reserved. + pub(super) amount: DepositBalance, +} + +/// Specifies whether the tokens will be sent or received. +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +pub enum PriceDirection { + /// Tokens will be sent. + Send, + /// Tokens will be received. + Receive, +} + +/// Holds the details about the price. +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +pub struct PriceWithDirection { + /// An amount. + pub(super) amount: Amount, + /// A direction (send or receive). + pub(super) direction: PriceDirection, +} + +/// Support for up to 64 user-enabled features on a collection. +#[bitflags] +#[repr(u64)] +#[derive(Copy, Clone, RuntimeDebug, PartialEq, Eq, Encode, Decode, MaxEncodedLen, TypeInfo)] +pub enum CollectionSetting { + /// Items in this collection are transferable. + TransferableItems, + /// The metadata of this collection can be modified. + UnlockedMetadata, + /// Attributes of this collection can be modified. + UnlockedAttributes, + /// The supply of this collection can be modified. + UnlockedMaxSupply, + /// When this isn't set then the deposit is required to hold the items of this collection. + DepositRequired, +} + +/// Wrapper type for `BitFlags` that implements `Codec`. +#[derive(Clone, Copy, PartialEq, Eq, Default, RuntimeDebug)] +pub struct CollectionSettings(pub BitFlags); + +impl CollectionSettings { + pub fn all_enabled() -> Self { + Self(BitFlags::EMPTY) + } + pub fn get_disabled(&self) -> BitFlags { + self.0 + } + pub fn is_disabled(&self, setting: CollectionSetting) -> bool { + self.0.contains(setting) + } + pub fn from_disabled(settings: BitFlags) -> Self { + Self(settings) + } +} + +impl_codec_bitflags!(CollectionSettings, u64, CollectionSetting); + +/// Mint type. Can the NFT be create by anyone, or only the creator of the collection, +/// or only by wallets that already hold an NFT from a certain collection? +/// The ownership of a privately minted NFT is still publicly visible. +#[derive(Clone, Copy, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +pub enum MintType { + /// Only an `Issuer` could mint items. + Issuer, + /// Anyone could mint items. + Public, + /// Only holders of items in specified collection could mint new items. + HolderOf(CollectionId), +} + +/// Holds the information about minting. +#[derive(Clone, Copy, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +pub struct MintSettings { + /// Whether anyone can mint or if minters are restricted to some subset. + pub(super) mint_type: MintType, + /// An optional price per mint. + pub(super) price: Option, + /// When the mint starts. + pub(super) start_block: Option, + /// When the mint ends. + pub(super) end_block: Option, + /// Default settings each item will get during the mint. + pub(super) default_item_settings: ItemSettings, +} + +impl Default for MintSettings { + fn default() -> Self { + Self { + mint_type: MintType::Issuer, + price: None, + start_block: None, + end_block: None, + default_item_settings: ItemSettings::all_enabled(), + } + } +} + +/// A witness data to cancel attributes approval operation. +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo)] +pub struct CancelAttributesApprovalWitness { + /// An amount of attributes previously created by account. + pub account_attributes: u32, +} + +/// A list of possible pallet-level attributes. +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +pub enum PalletAttributes { + /// Marks an item as being used in order to claim another item. + UsedToClaim(CollectionId), +} + +/// Collection's configuration. +#[derive( + Clone, Copy, Decode, Default, Encode, MaxEncodedLen, PartialEq, RuntimeDebug, TypeInfo, +)] +pub struct CollectionConfig { + /// Collection's settings. + pub(super) settings: CollectionSettings, + /// Collection's max supply. + pub(super) max_supply: Option, + /// Default settings each item will get during the mint. + pub(super) mint_settings: MintSettings, +} + +impl CollectionConfig { + pub fn is_setting_enabled(&self, setting: CollectionSetting) -> bool { + !self.settings.is_disabled(setting) + } + pub fn has_disabled_setting(&self, setting: CollectionSetting) -> bool { + self.settings.is_disabled(setting) + } + pub fn enable_setting(&mut self, setting: CollectionSetting) { + self.settings.0.remove(setting); + } + pub fn disable_setting(&mut self, setting: CollectionSetting) { + self.settings.0.insert(setting); + } +} + +/// Support for up to 64 user-enabled features on an item. +#[bitflags] +#[repr(u64)] +#[derive(Copy, Clone, RuntimeDebug, PartialEq, Eq, Encode, Decode, MaxEncodedLen, TypeInfo)] +pub enum ItemSetting { + /// This item is transferable. + Transferable, + /// The metadata of this item can be modified. + UnlockedMetadata, + /// Attributes of this item can be modified. + UnlockedAttributes, +} + +/// Wrapper type for `BitFlags` that implements `Codec`. +#[derive(Clone, Copy, PartialEq, Eq, Default, RuntimeDebug)] +pub struct ItemSettings(pub BitFlags); + +impl ItemSettings { + pub fn all_enabled() -> Self { + Self(BitFlags::EMPTY) + } + pub fn get_disabled(&self) -> BitFlags { + self.0 + } + pub fn is_disabled(&self, setting: ItemSetting) -> bool { + self.0.contains(setting) + } + pub fn from_disabled(settings: BitFlags) -> Self { + Self(settings) + } +} + +impl_codec_bitflags!(ItemSettings, u64, ItemSetting); + +/// Item's configuration. +#[derive( + Encode, Decode, Default, PartialEq, RuntimeDebug, Clone, Copy, MaxEncodedLen, TypeInfo, +)] +pub struct ItemConfig { + /// Item's settings. + pub(super) settings: ItemSettings, +} + +impl ItemConfig { + pub fn is_setting_enabled(&self, setting: ItemSetting) -> bool { + !self.settings.is_disabled(setting) + } + pub fn has_disabled_setting(&self, setting: ItemSetting) -> bool { + self.settings.is_disabled(setting) + } + pub fn has_disabled_settings(&self) -> bool { + !self.settings.get_disabled().is_empty() + } + pub fn enable_setting(&mut self, setting: ItemSetting) { + self.settings.0.remove(setting); + } + pub fn disable_setting(&mut self, setting: ItemSetting) { + self.settings.0.insert(setting); + } +} + +/// Support for up to 64 system-enabled features on a collection. +#[bitflags] +#[repr(u64)] +#[derive(Copy, Clone, RuntimeDebug, PartialEq, Eq, Encode, Decode, MaxEncodedLen, TypeInfo)] +pub enum PalletFeature { + /// Enable/disable trading operations. + Trading, + /// Allow/disallow setting attributes. + Attributes, + /// Allow/disallow transfer approvals. + Approvals, + /// Allow/disallow atomic items swap. + Swaps, +} + +/// Wrapper type for `BitFlags` that implements `Codec`. +#[derive(Default, RuntimeDebug)] +pub struct PalletFeatures(pub BitFlags); + +impl PalletFeatures { + pub fn all_enabled() -> Self { + Self(BitFlags::EMPTY) + } + pub fn from_disabled(features: BitFlags) -> Self { + Self(features) + } + pub fn is_enabled(&self, feature: PalletFeature) -> bool { + !self.0.contains(feature) + } +} +impl_codec_bitflags!(PalletFeatures, u64, PalletFeature); + +/// Support for up to 8 different roles for collections. +#[bitflags] +#[repr(u8)] +#[derive(Copy, Clone, RuntimeDebug, PartialEq, Eq, Encode, Decode, MaxEncodedLen, TypeInfo)] +pub enum CollectionRole { + /// Can mint items. + Issuer, + /// Can freeze items. + Freezer, + /// Can thaw items, force transfers and burn items from any account. + Admin, +} + +/// A wrapper type that implements `Codec`. +#[derive(Clone, Copy, PartialEq, Eq, Default, RuntimeDebug)] +pub struct CollectionRoles(pub BitFlags); + +impl CollectionRoles { + pub fn none() -> Self { + Self(BitFlags::EMPTY) + } + pub fn has_role(&self, role: CollectionRole) -> bool { + self.0.contains(role) + } + pub fn add_role(&mut self, role: CollectionRole) { + self.0.insert(role); + } + pub fn max_roles() -> u8 { + let all: BitFlags = BitFlags::all(); + all.len() as u8 + } +} +impl_codec_bitflags!(CollectionRoles, u8, CollectionRole); diff --git a/frame/nfts/src/weights.rs b/frame/nfts/src/weights.rs new file mode 100644 index 0000000000000..f05f8ca514c3e --- /dev/null +++ b/frame/nfts/src/weights.rs @@ -0,0 +1,851 @@ +// 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_nfts +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2022-12-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: +// /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_nfts +// --chain=dev +// --header=./HEADER-APACHE2 +// --output=./frame/nfts/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_nfts. +pub trait WeightInfo { + fn create() -> Weight; + fn force_create() -> Weight; + fn destroy(n: u32, m: u32, a: u32, ) -> Weight; + fn mint() -> Weight; + fn force_mint() -> Weight; + fn burn() -> Weight; + fn transfer() -> Weight; + fn redeposit(i: u32, ) -> Weight; + fn lock_item_transfer() -> Weight; + fn unlock_item_transfer() -> Weight; + fn lock_collection() -> Weight; + fn transfer_ownership() -> Weight; + fn set_team() -> Weight; + fn force_collection_owner() -> Weight; + fn force_collection_config() -> Weight; + fn lock_item_properties() -> Weight; + fn set_attribute() -> Weight; + fn force_set_attribute() -> Weight; + fn clear_attribute() -> Weight; + fn approve_item_attributes() -> Weight; + fn cancel_item_attributes_approval(n: u32, ) -> Weight; + fn set_metadata() -> Weight; + fn clear_metadata() -> Weight; + fn set_collection_metadata() -> Weight; + fn clear_collection_metadata() -> Weight; + fn approve_transfer() -> Weight; + fn cancel_approval() -> Weight; + fn clear_all_transfer_approvals() -> Weight; + fn set_accept_ownership() -> Weight; + fn set_collection_max_supply() -> Weight; + fn update_mint_settings() -> Weight; + fn set_price() -> Weight; + fn buy_item() -> Weight; + fn pay_tips(n: u32, ) -> Weight; + fn create_swap() -> Weight; + fn cancel_swap() -> Weight; + fn claim_swap() -> Weight; +} + +/// Weights for pallet_nfts using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + // Storage: Nfts NextCollectionId (r:1 w:1) + // Storage: Nfts Collection (r:1 w:1) + // Storage: Nfts CollectionRoleOf (r:0 w:1) + // Storage: Nfts CollectionConfigOf (r:0 w:1) + // Storage: Nfts CollectionAccount (r:0 w:1) + fn create() -> Weight { + // Minimum execution time: 44_312 nanoseconds. + Weight::from_ref_time(44_871_000) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(5)) + } + // Storage: Nfts NextCollectionId (r:1 w:1) + // Storage: Nfts Collection (r:1 w:1) + // Storage: Nfts CollectionRoleOf (r:0 w:1) + // Storage: Nfts CollectionConfigOf (r:0 w:1) + // Storage: Nfts CollectionAccount (r:0 w:1) + fn force_create() -> Weight { + // Minimum execution time: 31_654 nanoseconds. + Weight::from_ref_time(32_078_000) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(5)) + } + // Storage: Nfts Collection (r:1 w:1) + // Storage: Nfts Item (r:1001 w:1000) + // Storage: Nfts Attribute (r:1001 w:1000) + // Storage: Nfts ItemMetadataOf (r:0 w:1000) + // Storage: Nfts CollectionRoleOf (r:0 w:1) + // Storage: Nfts CollectionMetadataOf (r:0 w:1) + // Storage: Nfts CollectionConfigOf (r:0 w:1) + // Storage: Nfts ItemConfigOf (r:0 w:1000) + // Storage: Nfts Account (r:0 w:1000) + // Storage: Nfts CollectionAccount (r:0 w:1) + /// 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 { + // Minimum execution time: 19_183_393 nanoseconds. + Weight::from_ref_time(17_061_526_855) + // Standard Error: 16_689 + .saturating_add(Weight::from_ref_time(353_523).saturating_mul(n.into())) + // Standard Error: 16_689 + .saturating_add(Weight::from_ref_time(1_861_080).saturating_mul(m.into())) + // Standard Error: 16_689 + .saturating_add(Weight::from_ref_time(8_858_987).saturating_mul(a.into())) + .saturating_add(T::DbWeight::get().reads(1003)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(a.into()))) + .saturating_add(T::DbWeight::get().writes(3005)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(m.into()))) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(a.into()))) + } + // Storage: Nfts CollectionConfigOf (r:1 w:0) + // Storage: Nfts Item (r:1 w:1) + // Storage: Nfts Collection (r:1 w:1) + // Storage: Nfts CollectionRoleOf (r:1 w:0) + // Storage: Nfts ItemConfigOf (r:1 w:1) + // Storage: Nfts Account (r:0 w:1) + fn mint() -> Weight { + // Minimum execution time: 57_753 nanoseconds. + Weight::from_ref_time(58_313_000) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(4)) + } + // Storage: Nfts CollectionRoleOf (r:1 w:0) + // Storage: Nfts Item (r:1 w:1) + // Storage: Nfts Collection (r:1 w:1) + // Storage: Nfts CollectionConfigOf (r:1 w:0) + // Storage: Nfts ItemConfigOf (r:1 w:1) + // Storage: Nfts Account (r:0 w:1) + fn force_mint() -> Weight { + // Minimum execution time: 56_429 nanoseconds. + Weight::from_ref_time(57_202_000) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(4)) + } + // Storage: Nfts Collection (r:1 w:1) + // Storage: Nfts Item (r:1 w:1) + // Storage: Nfts CollectionRoleOf (r:1 w:0) + // Storage: Nfts ItemConfigOf (r:1 w:1) + // Storage: Nfts Account (r:0 w:1) + // Storage: Nfts ItemPriceOf (r:0 w:1) + // Storage: Nfts ItemAttributesApprovalsOf (r:0 w:1) + // Storage: Nfts PendingSwapOf (r:0 w:1) + fn burn() -> Weight { + // Minimum execution time: 59_681 nanoseconds. + Weight::from_ref_time(60_058_000) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(7)) + } + // Storage: Nfts Collection (r:1 w:0) + // Storage: Nfts CollectionConfigOf (r:1 w:0) + // Storage: Nfts ItemConfigOf (r:1 w:0) + // Storage: Nfts Item (r:1 w:1) + // Storage: Nfts CollectionRoleOf (r:1 w:0) + // Storage: System Account (r:1 w:1) + // Storage: Nfts Account (r:0 w:2) + // Storage: Nfts ItemPriceOf (r:0 w:1) + // Storage: Nfts PendingSwapOf (r:0 w:1) + fn transfer() -> Weight { + // Minimum execution time: 66_085 nanoseconds. + Weight::from_ref_time(67_065_000) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(6)) + } + // Storage: Nfts Collection (r:1 w:0) + // Storage: Nfts CollectionConfigOf (r:1 w:0) + // Storage: Nfts Item (r:102 w:102) + /// The range of component `i` is `[0, 5000]`. + fn redeposit(i: u32, ) -> Weight { + // Minimum execution time: 25_949 nanoseconds. + Weight::from_ref_time(26_106_000) + // Standard Error: 10_326 + .saturating_add(Weight::from_ref_time(11_496_776).saturating_mul(i.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(i.into()))) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) + } + // Storage: Nfts CollectionRoleOf (r:1 w:0) + // Storage: Nfts ItemConfigOf (r:1 w:1) + fn lock_item_transfer() -> Weight { + // Minimum execution time: 30_080 nanoseconds. + Weight::from_ref_time(30_825_000) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + // Storage: Nfts CollectionRoleOf (r:1 w:0) + // Storage: Nfts ItemConfigOf (r:1 w:1) + fn unlock_item_transfer() -> Weight { + // Minimum execution time: 30_612 nanoseconds. + Weight::from_ref_time(31_422_000) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + // Storage: Nfts CollectionRoleOf (r:1 w:0) + // Storage: Nfts CollectionConfigOf (r:1 w:1) + fn lock_collection() -> Weight { + // Minimum execution time: 27_470 nanoseconds. + Weight::from_ref_time(28_015_000) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + // Storage: Nfts OwnershipAcceptance (r:1 w:1) + // Storage: Nfts Collection (r:1 w:1) + // Storage: Nfts CollectionAccount (r:0 w:2) + fn transfer_ownership() -> Weight { + // Minimum execution time: 33_750 nanoseconds. + Weight::from_ref_time(34_139_000) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(4)) + } + // Storage: Nfts Collection (r:1 w:1) + // Storage: Nfts CollectionRoleOf (r:0 w:4) + fn set_team() -> Weight { + // Minimum execution time: 36_565 nanoseconds. + Weight::from_ref_time(37_464_000) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(5)) + } + // Storage: Nfts Collection (r:1 w:1) + // Storage: Nfts CollectionAccount (r:0 w:2) + fn force_collection_owner() -> Weight { + // Minimum execution time: 29_028 nanoseconds. + Weight::from_ref_time(29_479_000) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(3)) + } + // Storage: Nfts Collection (r:1 w:0) + // Storage: Nfts CollectionConfigOf (r:0 w:1) + fn force_collection_config() -> Weight { + // Minimum execution time: 24_695 nanoseconds. + Weight::from_ref_time(25_304_000) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + // Storage: Nfts Collection (r:1 w:0) + // Storage: Nfts ItemConfigOf (r:1 w:1) + fn lock_item_properties() -> Weight { + // Minimum execution time: 28_910 nanoseconds. + Weight::from_ref_time(29_186_000) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + // Storage: Nfts Collection (r:1 w:1) + // Storage: Nfts CollectionConfigOf (r:1 w:0) + // Storage: Nfts ItemConfigOf (r:1 w:0) + // Storage: Nfts Attribute (r:1 w:1) + fn set_attribute() -> Weight { + // Minimum execution time: 56_407 nanoseconds. + Weight::from_ref_time(58_176_000) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(2)) + } + // Storage: Nfts Collection (r:1 w:1) + // Storage: Nfts Attribute (r:1 w:1) + fn force_set_attribute() -> Weight { + // Minimum execution time: 36_402 nanoseconds. + Weight::from_ref_time(37_034_000) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + // Storage: Nfts Attribute (r:1 w:1) + // Storage: Nfts Collection (r:1 w:1) + // Storage: Nfts ItemConfigOf (r:1 w:0) + fn clear_attribute() -> Weight { + // Minimum execution time: 52_022 nanoseconds. + Weight::from_ref_time(54_059_000) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + // Storage: Nfts Item (r:1 w:0) + // Storage: Nfts ItemAttributesApprovalsOf (r:1 w:1) + fn approve_item_attributes() -> Weight { + // Minimum execution time: 28_475 nanoseconds. + Weight::from_ref_time(29_162_000) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + // Storage: Nfts Item (r:1 w:0) + // Storage: Nfts ItemAttributesApprovalsOf (r:1 w:1) + // Storage: Nfts Attribute (r:1 w:0) + // Storage: System Account (r:1 w:1) + /// The range of component `n` is `[0, 1000]`. + fn cancel_item_attributes_approval(n: u32, ) -> Weight { + // Minimum execution time: 37_529 nanoseconds. + Weight::from_ref_time(38_023_000) + // Standard Error: 8_136 + .saturating_add(Weight::from_ref_time(7_452_872).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes(2)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) + } + // Storage: Nfts Collection (r:1 w:1) + // Storage: Nfts ItemConfigOf (r:1 w:0) + // Storage: Nfts CollectionConfigOf (r:1 w:0) + // Storage: Nfts ItemMetadataOf (r:1 w:1) + fn set_metadata() -> Weight { + // Minimum execution time: 49_300 nanoseconds. + Weight::from_ref_time(49_790_000) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(2)) + } + // Storage: Nfts Collection (r:1 w:1) + // Storage: Nfts ItemConfigOf (r:1 w:0) + // Storage: Nfts ItemMetadataOf (r:1 w:1) + fn clear_metadata() -> Weight { + // Minimum execution time: 47_248 nanoseconds. + Weight::from_ref_time(48_094_000) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + // Storage: Nfts CollectionConfigOf (r:1 w:0) + // Storage: Nfts Collection (r:1 w:1) + // Storage: Nfts CollectionMetadataOf (r:1 w:1) + fn set_collection_metadata() -> Weight { + // Minimum execution time: 44_137 nanoseconds. + Weight::from_ref_time(44_905_000) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + // Storage: Nfts Collection (r:1 w:0) + // Storage: Nfts CollectionConfigOf (r:1 w:0) + // Storage: Nfts CollectionMetadataOf (r:1 w:1) + fn clear_collection_metadata() -> Weight { + // Minimum execution time: 43_005 nanoseconds. + Weight::from_ref_time(43_898_000) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(1)) + } + // Storage: Nfts Item (r:1 w:1) + // Storage: Nfts CollectionConfigOf (r:1 w:0) + // Storage: Nfts CollectionRoleOf (r:1 w:0) + fn approve_transfer() -> Weight { + // Minimum execution time: 36_344 nanoseconds. + Weight::from_ref_time(36_954_000) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(1)) + } + // Storage: Nfts Item (r:1 w:1) + // Storage: Nfts CollectionRoleOf (r:1 w:0) + fn cancel_approval() -> Weight { + // Minimum execution time: 32_418 nanoseconds. + Weight::from_ref_time(33_029_000) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + // Storage: Nfts Item (r:1 w:1) + // Storage: Nfts CollectionRoleOf (r:1 w:0) + fn clear_all_transfer_approvals() -> Weight { + // Minimum execution time: 31_448 nanoseconds. + Weight::from_ref_time(31_979_000) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + // Storage: Nfts OwnershipAcceptance (r:1 w:1) + fn set_accept_ownership() -> Weight { + // Minimum execution time: 27_487 nanoseconds. + Weight::from_ref_time(28_080_000) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + // Storage: Nfts CollectionConfigOf (r:1 w:1) + // Storage: Nfts Collection (r:1 w:0) + fn set_collection_max_supply() -> Weight { + // Minimum execution time: 28_235 nanoseconds. + Weight::from_ref_time(28_967_000) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + // Storage: Nfts Collection (r:1 w:0) + // Storage: Nfts CollectionConfigOf (r:1 w:1) + fn update_mint_settings() -> Weight { + // Minimum execution time: 28_172 nanoseconds. + Weight::from_ref_time(28_636_000) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + // Storage: Nfts Item (r:1 w:0) + // Storage: Nfts CollectionConfigOf (r:1 w:0) + // Storage: Nfts ItemConfigOf (r:1 w:0) + // Storage: Nfts ItemPriceOf (r:0 w:1) + fn set_price() -> Weight { + // Minimum execution time: 35_336 nanoseconds. + Weight::from_ref_time(36_026_000) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(1)) + } + // Storage: Nfts Item (r:1 w:1) + // Storage: Nfts ItemPriceOf (r:1 w:1) + // Storage: Nfts Collection (r:1 w:0) + // Storage: Nfts CollectionConfigOf (r:1 w:0) + // Storage: Nfts ItemConfigOf (r:1 w:0) + // Storage: System Account (r:1 w:1) + // Storage: Nfts Account (r:0 w:2) + // Storage: Nfts PendingSwapOf (r:0 w:1) + fn buy_item() -> Weight { + // Minimum execution time: 70_971 nanoseconds. + Weight::from_ref_time(72_036_000) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(6)) + } + /// The range of component `n` is `[0, 10]`. + fn pay_tips(n: u32, ) -> Weight { + // Minimum execution time: 5_151 nanoseconds. + Weight::from_ref_time(11_822_888) + // Standard Error: 38_439 + .saturating_add(Weight::from_ref_time(3_511_844).saturating_mul(n.into())) + } + // Storage: Nfts Item (r:2 w:0) + // Storage: Nfts PendingSwapOf (r:0 w:1) + fn create_swap() -> Weight { + // Minimum execution time: 33_027 nanoseconds. + Weight::from_ref_time(33_628_000) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + // Storage: Nfts PendingSwapOf (r:1 w:1) + // Storage: Nfts Item (r:1 w:0) + fn cancel_swap() -> Weight { + // Minimum execution time: 35_890 nanoseconds. + Weight::from_ref_time(36_508_000) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + // Storage: Nfts Item (r:2 w:2) + // Storage: Nfts PendingSwapOf (r:1 w:2) + // Storage: Nfts Collection (r:1 w:0) + // Storage: Nfts CollectionConfigOf (r:1 w:0) + // Storage: Nfts ItemConfigOf (r:2 w:0) + // Storage: System Account (r:1 w:1) + // Storage: Nfts Account (r:0 w:4) + // Storage: Nfts ItemPriceOf (r:0 w:2) + fn claim_swap() -> Weight { + // Minimum execution time: 101_076 nanoseconds. + Weight::from_ref_time(101_863_000) + .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().writes(11)) + } +} + +// For backwards compatibility and tests +impl WeightInfo for () { + // Storage: Nfts NextCollectionId (r:1 w:1) + // Storage: Nfts Collection (r:1 w:1) + // Storage: Nfts CollectionRoleOf (r:0 w:1) + // Storage: Nfts CollectionConfigOf (r:0 w:1) + // Storage: Nfts CollectionAccount (r:0 w:1) + fn create() -> Weight { + // Minimum execution time: 44_312 nanoseconds. + Weight::from_ref_time(44_871_000) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(5)) + } + // Storage: Nfts NextCollectionId (r:1 w:1) + // Storage: Nfts Collection (r:1 w:1) + // Storage: Nfts CollectionRoleOf (r:0 w:1) + // Storage: Nfts CollectionConfigOf (r:0 w:1) + // Storage: Nfts CollectionAccount (r:0 w:1) + fn force_create() -> Weight { + // Minimum execution time: 31_654 nanoseconds. + Weight::from_ref_time(32_078_000) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(5)) + } + // Storage: Nfts Collection (r:1 w:1) + // Storage: Nfts Item (r:1001 w:1000) + // Storage: Nfts Attribute (r:1001 w:1000) + // Storage: Nfts ItemMetadataOf (r:0 w:1000) + // Storage: Nfts CollectionRoleOf (r:0 w:1) + // Storage: Nfts CollectionMetadataOf (r:0 w:1) + // Storage: Nfts CollectionConfigOf (r:0 w:1) + // Storage: Nfts ItemConfigOf (r:0 w:1000) + // Storage: Nfts Account (r:0 w:1000) + // Storage: Nfts CollectionAccount (r:0 w:1) + /// 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 { + // Minimum execution time: 19_183_393 nanoseconds. + Weight::from_ref_time(17_061_526_855) + // Standard Error: 16_689 + .saturating_add(Weight::from_ref_time(353_523).saturating_mul(n.into())) + // Standard Error: 16_689 + .saturating_add(Weight::from_ref_time(1_861_080).saturating_mul(m.into())) + // Standard Error: 16_689 + .saturating_add(Weight::from_ref_time(8_858_987).saturating_mul(a.into())) + .saturating_add(RocksDbWeight::get().reads(1003)) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(a.into()))) + .saturating_add(RocksDbWeight::get().writes(3005)) + .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(m.into()))) + .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(a.into()))) + } + // Storage: Nfts CollectionConfigOf (r:1 w:0) + // Storage: Nfts Item (r:1 w:1) + // Storage: Nfts Collection (r:1 w:1) + // Storage: Nfts CollectionRoleOf (r:1 w:0) + // Storage: Nfts ItemConfigOf (r:1 w:1) + // Storage: Nfts Account (r:0 w:1) + fn mint() -> Weight { + // Minimum execution time: 57_753 nanoseconds. + Weight::from_ref_time(58_313_000) + .saturating_add(RocksDbWeight::get().reads(5)) + .saturating_add(RocksDbWeight::get().writes(4)) + } + // Storage: Nfts CollectionRoleOf (r:1 w:0) + // Storage: Nfts Item (r:1 w:1) + // Storage: Nfts Collection (r:1 w:1) + // Storage: Nfts CollectionConfigOf (r:1 w:0) + // Storage: Nfts ItemConfigOf (r:1 w:1) + // Storage: Nfts Account (r:0 w:1) + fn force_mint() -> Weight { + // Minimum execution time: 56_429 nanoseconds. + Weight::from_ref_time(57_202_000) + .saturating_add(RocksDbWeight::get().reads(5)) + .saturating_add(RocksDbWeight::get().writes(4)) + } + // Storage: Nfts Collection (r:1 w:1) + // Storage: Nfts Item (r:1 w:1) + // Storage: Nfts CollectionRoleOf (r:1 w:0) + // Storage: Nfts ItemConfigOf (r:1 w:1) + // Storage: Nfts Account (r:0 w:1) + // Storage: Nfts ItemPriceOf (r:0 w:1) + // Storage: Nfts ItemAttributesApprovalsOf (r:0 w:1) + // Storage: Nfts PendingSwapOf (r:0 w:1) + fn burn() -> Weight { + // Minimum execution time: 59_681 nanoseconds. + Weight::from_ref_time(60_058_000) + .saturating_add(RocksDbWeight::get().reads(4)) + .saturating_add(RocksDbWeight::get().writes(7)) + } + // Storage: Nfts Collection (r:1 w:0) + // Storage: Nfts CollectionConfigOf (r:1 w:0) + // Storage: Nfts ItemConfigOf (r:1 w:0) + // Storage: Nfts Item (r:1 w:1) + // Storage: Nfts CollectionRoleOf (r:1 w:0) + // Storage: System Account (r:1 w:1) + // Storage: Nfts Account (r:0 w:2) + // Storage: Nfts ItemPriceOf (r:0 w:1) + // Storage: Nfts PendingSwapOf (r:0 w:1) + fn transfer() -> Weight { + // Minimum execution time: 66_085 nanoseconds. + Weight::from_ref_time(67_065_000) + .saturating_add(RocksDbWeight::get().reads(6)) + .saturating_add(RocksDbWeight::get().writes(6)) + } + // Storage: Nfts Collection (r:1 w:0) + // Storage: Nfts CollectionConfigOf (r:1 w:0) + // Storage: Nfts Item (r:102 w:102) + /// The range of component `i` is `[0, 5000]`. + fn redeposit(i: u32, ) -> Weight { + // Minimum execution time: 25_949 nanoseconds. + Weight::from_ref_time(26_106_000) + // Standard Error: 10_326 + .saturating_add(Weight::from_ref_time(11_496_776).saturating_mul(i.into())) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(i.into()))) + .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(i.into()))) + } + // Storage: Nfts CollectionRoleOf (r:1 w:0) + // Storage: Nfts ItemConfigOf (r:1 w:1) + fn lock_item_transfer() -> Weight { + // Minimum execution time: 30_080 nanoseconds. + Weight::from_ref_time(30_825_000) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(1)) + } + // Storage: Nfts CollectionRoleOf (r:1 w:0) + // Storage: Nfts ItemConfigOf (r:1 w:1) + fn unlock_item_transfer() -> Weight { + // Minimum execution time: 30_612 nanoseconds. + Weight::from_ref_time(31_422_000) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(1)) + } + // Storage: Nfts CollectionRoleOf (r:1 w:0) + // Storage: Nfts CollectionConfigOf (r:1 w:1) + fn lock_collection() -> Weight { + // Minimum execution time: 27_470 nanoseconds. + Weight::from_ref_time(28_015_000) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(1)) + } + // Storage: Nfts OwnershipAcceptance (r:1 w:1) + // Storage: Nfts Collection (r:1 w:1) + // Storage: Nfts CollectionAccount (r:0 w:2) + fn transfer_ownership() -> Weight { + // Minimum execution time: 33_750 nanoseconds. + Weight::from_ref_time(34_139_000) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(4)) + } + // Storage: Nfts Collection (r:1 w:1) + // Storage: Nfts CollectionRoleOf (r:0 w:4) + fn set_team() -> Weight { + // Minimum execution time: 36_565 nanoseconds. + Weight::from_ref_time(37_464_000) + .saturating_add(RocksDbWeight::get().reads(1)) + .saturating_add(RocksDbWeight::get().writes(5)) + } + // Storage: Nfts Collection (r:1 w:1) + // Storage: Nfts CollectionAccount (r:0 w:2) + fn force_collection_owner() -> Weight { + // Minimum execution time: 29_028 nanoseconds. + Weight::from_ref_time(29_479_000) + .saturating_add(RocksDbWeight::get().reads(1)) + .saturating_add(RocksDbWeight::get().writes(3)) + } + // Storage: Nfts Collection (r:1 w:0) + // Storage: Nfts CollectionConfigOf (r:0 w:1) + fn force_collection_config() -> Weight { + // Minimum execution time: 24_695 nanoseconds. + Weight::from_ref_time(25_304_000) + .saturating_add(RocksDbWeight::get().reads(1)) + .saturating_add(RocksDbWeight::get().writes(1)) + } + // Storage: Nfts Collection (r:1 w:0) + // Storage: Nfts ItemConfigOf (r:1 w:1) + fn lock_item_properties() -> Weight { + // Minimum execution time: 28_910 nanoseconds. + Weight::from_ref_time(29_186_000) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(1)) + } + // Storage: Nfts Collection (r:1 w:1) + // Storage: Nfts CollectionConfigOf (r:1 w:0) + // Storage: Nfts ItemConfigOf (r:1 w:0) + // Storage: Nfts Attribute (r:1 w:1) + fn set_attribute() -> Weight { + // Minimum execution time: 56_407 nanoseconds. + Weight::from_ref_time(58_176_000) + .saturating_add(RocksDbWeight::get().reads(4)) + .saturating_add(RocksDbWeight::get().writes(2)) + } + // Storage: Nfts Collection (r:1 w:1) + // Storage: Nfts Attribute (r:1 w:1) + fn force_set_attribute() -> Weight { + // Minimum execution time: 36_402 nanoseconds. + Weight::from_ref_time(37_034_000) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(2)) + } + // Storage: Nfts Attribute (r:1 w:1) + // Storage: Nfts Collection (r:1 w:1) + // Storage: Nfts ItemConfigOf (r:1 w:0) + fn clear_attribute() -> Weight { + // Minimum execution time: 52_022 nanoseconds. + Weight::from_ref_time(54_059_000) + .saturating_add(RocksDbWeight::get().reads(3)) + .saturating_add(RocksDbWeight::get().writes(2)) + } + // Storage: Nfts Item (r:1 w:0) + // Storage: Nfts ItemAttributesApprovalsOf (r:1 w:1) + fn approve_item_attributes() -> Weight { + // Minimum execution time: 28_475 nanoseconds. + Weight::from_ref_time(29_162_000) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(1)) + } + // Storage: Nfts Item (r:1 w:0) + // Storage: Nfts ItemAttributesApprovalsOf (r:1 w:1) + // Storage: Nfts Attribute (r:1 w:0) + // Storage: System Account (r:1 w:1) + /// The range of component `n` is `[0, 1000]`. + fn cancel_item_attributes_approval(n: u32, ) -> Weight { + // Minimum execution time: 37_529 nanoseconds. + Weight::from_ref_time(38_023_000) + // Standard Error: 8_136 + .saturating_add(Weight::from_ref_time(7_452_872).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(4)) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) + .saturating_add(RocksDbWeight::get().writes(2)) + .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) + } + // Storage: Nfts Collection (r:1 w:1) + // Storage: Nfts ItemConfigOf (r:1 w:0) + // Storage: Nfts CollectionConfigOf (r:1 w:0) + // Storage: Nfts ItemMetadataOf (r:1 w:1) + fn set_metadata() -> Weight { + // Minimum execution time: 49_300 nanoseconds. + Weight::from_ref_time(49_790_000) + .saturating_add(RocksDbWeight::get().reads(4)) + .saturating_add(RocksDbWeight::get().writes(2)) + } + // Storage: Nfts Collection (r:1 w:1) + // Storage: Nfts ItemConfigOf (r:1 w:0) + // Storage: Nfts ItemMetadataOf (r:1 w:1) + fn clear_metadata() -> Weight { + // Minimum execution time: 47_248 nanoseconds. + Weight::from_ref_time(48_094_000) + .saturating_add(RocksDbWeight::get().reads(3)) + .saturating_add(RocksDbWeight::get().writes(2)) + } + // Storage: Nfts CollectionConfigOf (r:1 w:0) + // Storage: Nfts Collection (r:1 w:1) + // Storage: Nfts CollectionMetadataOf (r:1 w:1) + fn set_collection_metadata() -> Weight { + // Minimum execution time: 44_137 nanoseconds. + Weight::from_ref_time(44_905_000) + .saturating_add(RocksDbWeight::get().reads(3)) + .saturating_add(RocksDbWeight::get().writes(2)) + } + // Storage: Nfts Collection (r:1 w:0) + // Storage: Nfts CollectionConfigOf (r:1 w:0) + // Storage: Nfts CollectionMetadataOf (r:1 w:1) + fn clear_collection_metadata() -> Weight { + // Minimum execution time: 43_005 nanoseconds. + Weight::from_ref_time(43_898_000) + .saturating_add(RocksDbWeight::get().reads(3)) + .saturating_add(RocksDbWeight::get().writes(1)) + } + // Storage: Nfts Item (r:1 w:1) + // Storage: Nfts CollectionConfigOf (r:1 w:0) + // Storage: Nfts CollectionRoleOf (r:1 w:0) + fn approve_transfer() -> Weight { + // Minimum execution time: 36_344 nanoseconds. + Weight::from_ref_time(36_954_000) + .saturating_add(RocksDbWeight::get().reads(3)) + .saturating_add(RocksDbWeight::get().writes(1)) + } + // Storage: Nfts Item (r:1 w:1) + // Storage: Nfts CollectionRoleOf (r:1 w:0) + fn cancel_approval() -> Weight { + // Minimum execution time: 32_418 nanoseconds. + Weight::from_ref_time(33_029_000) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(1)) + } + // Storage: Nfts Item (r:1 w:1) + // Storage: Nfts CollectionRoleOf (r:1 w:0) + fn clear_all_transfer_approvals() -> Weight { + // Minimum execution time: 31_448 nanoseconds. + Weight::from_ref_time(31_979_000) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(1)) + } + // Storage: Nfts OwnershipAcceptance (r:1 w:1) + fn set_accept_ownership() -> Weight { + // Minimum execution time: 27_487 nanoseconds. + Weight::from_ref_time(28_080_000) + .saturating_add(RocksDbWeight::get().reads(1)) + .saturating_add(RocksDbWeight::get().writes(1)) + } + // Storage: Nfts CollectionConfigOf (r:1 w:1) + // Storage: Nfts Collection (r:1 w:0) + fn set_collection_max_supply() -> Weight { + // Minimum execution time: 28_235 nanoseconds. + Weight::from_ref_time(28_967_000) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(1)) + } + // Storage: Nfts Collection (r:1 w:0) + // Storage: Nfts CollectionConfigOf (r:1 w:1) + fn update_mint_settings() -> Weight { + // Minimum execution time: 28_172 nanoseconds. + Weight::from_ref_time(28_636_000) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(1)) + } + // Storage: Nfts Item (r:1 w:0) + // Storage: Nfts CollectionConfigOf (r:1 w:0) + // Storage: Nfts ItemConfigOf (r:1 w:0) + // Storage: Nfts ItemPriceOf (r:0 w:1) + fn set_price() -> Weight { + // Minimum execution time: 35_336 nanoseconds. + Weight::from_ref_time(36_026_000) + .saturating_add(RocksDbWeight::get().reads(3)) + .saturating_add(RocksDbWeight::get().writes(1)) + } + // Storage: Nfts Item (r:1 w:1) + // Storage: Nfts ItemPriceOf (r:1 w:1) + // Storage: Nfts Collection (r:1 w:0) + // Storage: Nfts CollectionConfigOf (r:1 w:0) + // Storage: Nfts ItemConfigOf (r:1 w:0) + // Storage: System Account (r:1 w:1) + // Storage: Nfts Account (r:0 w:2) + // Storage: Nfts PendingSwapOf (r:0 w:1) + fn buy_item() -> Weight { + // Minimum execution time: 70_971 nanoseconds. + Weight::from_ref_time(72_036_000) + .saturating_add(RocksDbWeight::get().reads(6)) + .saturating_add(RocksDbWeight::get().writes(6)) + } + /// The range of component `n` is `[0, 10]`. + fn pay_tips(n: u32, ) -> Weight { + // Minimum execution time: 5_151 nanoseconds. + Weight::from_ref_time(11_822_888) + // Standard Error: 38_439 + .saturating_add(Weight::from_ref_time(3_511_844).saturating_mul(n.into())) + } + // Storage: Nfts Item (r:2 w:0) + // Storage: Nfts PendingSwapOf (r:0 w:1) + fn create_swap() -> Weight { + // Minimum execution time: 33_027 nanoseconds. + Weight::from_ref_time(33_628_000) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(1)) + } + // Storage: Nfts PendingSwapOf (r:1 w:1) + // Storage: Nfts Item (r:1 w:0) + fn cancel_swap() -> Weight { + // Minimum execution time: 35_890 nanoseconds. + Weight::from_ref_time(36_508_000) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(1)) + } + // Storage: Nfts Item (r:2 w:2) + // Storage: Nfts PendingSwapOf (r:1 w:2) + // Storage: Nfts Collection (r:1 w:0) + // Storage: Nfts CollectionConfigOf (r:1 w:0) + // Storage: Nfts ItemConfigOf (r:2 w:0) + // Storage: System Account (r:1 w:1) + // Storage: Nfts Account (r:0 w:4) + // Storage: Nfts ItemPriceOf (r:0 w:2) + fn claim_swap() -> Weight { + // Minimum execution time: 101_076 nanoseconds. + Weight::from_ref_time(101_863_000) + .saturating_add(RocksDbWeight::get().reads(8)) + .saturating_add(RocksDbWeight::get().writes(11)) + } +} diff --git a/frame/support/src/traits/tokens.rs b/frame/support/src/traits/tokens.rs index 77eb83adfbfb0..03a24bd3ba9c8 100644 --- a/frame/support/src/traits/tokens.rs +++ b/frame/support/src/traits/tokens.rs @@ -23,9 +23,11 @@ pub mod fungibles; pub mod imbalance; mod misc; pub mod nonfungible; +pub mod nonfungible_v2; pub mod nonfungibles; +pub mod nonfungibles_v2; pub use imbalance::Imbalance; pub use misc::{ - AssetId, Balance, BalanceConversion, BalanceStatus, DepositConsequence, ExistenceRequirement, - Locker, WithdrawConsequence, WithdrawReasons, + AssetId, AttributeNamespace, Balance, BalanceConversion, BalanceStatus, DepositConsequence, + ExistenceRequirement, Locker, WithdrawConsequence, WithdrawReasons, }; diff --git a/frame/support/src/traits/tokens/misc.rs b/frame/support/src/traits/tokens/misc.rs index 294d0e89c8b9e..f9876ef477b81 100644 --- a/frame/support/src/traits/tokens/misc.rs +++ b/frame/support/src/traits/tokens/misc.rs @@ -126,6 +126,21 @@ pub enum BalanceStatus { Reserved, } +/// Attribute namespaces for non-fungible tokens. +#[derive( + Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, scale_info::TypeInfo, MaxEncodedLen, +)] +pub enum AttributeNamespace { + /// An attribute was set by the pallet. + Pallet, + /// An attribute was set by collection's owner. + CollectionOwner, + /// An attribute was set by item's owner. + ItemOwner, + /// An attribute was set by pre-approved account. + Account(AccountId), +} + bitflags::bitflags! { /// Reasons for moving funds out of an account. #[derive(Encode, Decode, MaxEncodedLen)] diff --git a/frame/support/src/traits/tokens/nonfungible_v2.rs b/frame/support/src/traits/tokens/nonfungible_v2.rs new file mode 100644 index 0000000000000..a1b75e62e4db5 --- /dev/null +++ b/frame/support/src/traits/tokens/nonfungible_v2.rs @@ -0,0 +1,248 @@ +// 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 dealing with a single non-fungible item. +//! +//! This assumes a single-level namespace identified by `Inspect::ItemId`, and could +//! reasonably be implemented by pallets that want to expose a single collection of NFT-like +//! objects. +//! +//! For an NFT API that has dual-level namespacing, the traits in `nonfungibles` are better to +//! use. + +use super::nonfungibles_v2 as nonfungibles; +use crate::{ + dispatch::DispatchResult, + traits::{tokens::misc::AttributeNamespace, Get}, +}; +use codec::{Decode, Encode}; +use sp_runtime::TokenError; +use sp_std::prelude::*; + +/// Trait for providing an interface to a read-only NFT-like item. +pub trait Inspect { + /// Type for identifying an item. + type ItemId; + + /// Returns the owner of `item`, or `None` if the item doesn't exist or has no + /// owner. + fn owner(item: &Self::ItemId) -> Option; + + /// Returns the attribute value of `item` corresponding to `key`. + /// + /// By default this is `None`; no attributes are defined. + fn attribute( + _item: &Self::ItemId, + _namespace: &AttributeNamespace, + _key: &[u8], + ) -> Option> { + None + } + + /// Returns the strongly-typed attribute value of `item` corresponding to `key`. + /// + /// By default this just attempts to use `attribute`. + fn typed_attribute( + item: &Self::ItemId, + namespace: &AttributeNamespace, + key: &K, + ) -> Option { + key.using_encoded(|d| Self::attribute(item, namespace, d)) + .and_then(|v| V::decode(&mut &v[..]).ok()) + } + + /// Returns `true` if the `item` may be transferred. + /// + /// Default implementation is that all items are transferable. + fn can_transfer(_item: &Self::ItemId) -> bool { + true + } +} + +/// 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() -> Self::ItemsIterator; + + /// Returns an iterator of the items of all collections owned by `who`. + fn owned(who: &AccountId) -> Self::OwnedIterator; +} + +/// 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 `item` to be owned by `who`. + /// + /// By default, this is not a supported operation. + fn mint_into( + _item: &Self::ItemId, + _who: &AccountId, + _config: &ItemConfig, + _deposit_collection_owner: bool, + ) -> DispatchResult { + Err(TokenError::Unsupported.into()) + } + + /// Burn some `item`. + /// + /// By default, this is not a supported operation. + fn burn(_item: &Self::ItemId, _maybe_check_owner: Option<&AccountId>) -> DispatchResult { + Err(TokenError::Unsupported.into()) + } + + /// Set attribute `value` of `item`'s `key`. + /// + /// By default, this is not a supported operation. + fn set_attribute(_item: &Self::ItemId, _key: &[u8], _value: &[u8]) -> DispatchResult { + Err(TokenError::Unsupported.into()) + } + + /// 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( + item: &Self::ItemId, + key: &K, + value: &V, + ) -> DispatchResult { + key.using_encoded(|k| value.using_encoded(|v| Self::set_attribute(item, k, v))) + } +} + +/// Trait for transferring a non-fungible item. +pub trait Transfer: Inspect { + /// Transfer `item` into `destination` account. + fn transfer(item: &Self::ItemId, destination: &AccountId) -> DispatchResult; +} + +/// Convert a `nonfungibles` trait implementation into a `nonfungible` trait implementation by +/// identifying a single item. +pub struct ItemOf< + F: nonfungibles::Inspect, + A: Get<>::CollectionId>, + AccountId, +>(sp_std::marker::PhantomData<(F, A, AccountId)>); + +impl< + F: nonfungibles::Inspect, + A: Get<>::CollectionId>, + AccountId, + > Inspect for ItemOf +{ + type ItemId = >::ItemId; + fn owner(item: &Self::ItemId) -> Option { + >::owner(&A::get(), item) + } + fn attribute( + item: &Self::ItemId, + namespace: &AttributeNamespace, + key: &[u8], + ) -> Option> { + >::attribute(&A::get(), item, namespace, key) + } + fn typed_attribute( + item: &Self::ItemId, + namespace: &AttributeNamespace, + key: &K, + ) -> Option { + >::typed_attribute(&A::get(), item, namespace, key) + } + fn can_transfer(item: &Self::ItemId) -> bool { + >::can_transfer(&A::get(), item) + } +} + +impl< + F: nonfungibles::InspectEnumerable, + A: Get<>::CollectionId>, + AccountId, + > InspectEnumerable for ItemOf +{ + type ItemsIterator = >::ItemsIterator; + type OwnedIterator = + >::OwnedInCollectionIterator; + + fn items() -> Self::ItemsIterator { + >::items(&A::get()) + } + fn owned(who: &AccountId) -> Self::OwnedIterator { + >::owned_in_collection(&A::get(), who) + } +} + +impl< + F: nonfungibles::Mutate, + A: Get<>::CollectionId>, + AccountId, + ItemConfig, + > Mutate for ItemOf +{ + fn mint_into( + item: &Self::ItemId, + who: &AccountId, + config: &ItemConfig, + deposit_collection_owner: bool, + ) -> DispatchResult { + >::mint_into( + &A::get(), + item, + who, + config, + deposit_collection_owner, + ) + } + fn burn(item: &Self::ItemId, maybe_check_owner: Option<&AccountId>) -> DispatchResult { + >::burn(&A::get(), item, maybe_check_owner) + } + fn set_attribute(item: &Self::ItemId, key: &[u8], value: &[u8]) -> DispatchResult { + >::set_attribute( + &A::get(), + item, + key, + value, + ) + } + fn set_typed_attribute( + item: &Self::ItemId, + key: &K, + value: &V, + ) -> DispatchResult { + >::set_typed_attribute( + &A::get(), + item, + key, + value, + ) + } +} + +impl< + F: nonfungibles::Transfer, + A: Get<>::CollectionId>, + AccountId, + > Transfer for ItemOf +{ + fn transfer(item: &Self::ItemId, destination: &AccountId) -> DispatchResult { + >::transfer(&A::get(), item, destination) + } +} diff --git a/frame/support/src/traits/tokens/nonfungibles_v2.rs b/frame/support/src/traits/tokens/nonfungibles_v2.rs new file mode 100644 index 0000000000000..d2f5f5529fa96 --- /dev/null +++ b/frame/support/src/traits/tokens/nonfungibles_v2.rs @@ -0,0 +1,257 @@ +// 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 dealing with multiple collections of non-fungible items. +//! +//! 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. +//! +//! For an NFT API which has single-level namespacing, the traits in `nonfungible` are better to +//! use. +//! +//! Implementations of these traits may be converted to implementations of corresponding +//! `nonfungible` traits by using the `nonfungible::ItemOf` type adapter. + +use crate::{ + dispatch::{DispatchError, DispatchResult}, + traits::tokens::misc::AttributeNamespace, +}; +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 items. +pub trait Inspect { + /// Type for identifying an item. + type ItemId; + + /// Type for identifying a collection (an identifier for an independent collection of + /// items). + type CollectionId; + + /// 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 `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 `item` of `collection` corresponding to `key`. + /// + /// By default this is `None`; no attributes are defined. + fn attribute( + _collection: &Self::CollectionId, + _item: &Self::ItemId, + _namespace: &AttributeNamespace, + _key: &[u8], + ) -> Option> { + None + } + + /// Returns the strongly-typed attribute value of `item` of `collection` corresponding to + /// `key`. + /// + /// By default this just attempts to use `attribute`. + fn typed_attribute( + collection: &Self::CollectionId, + item: &Self::ItemId, + namespace: &AttributeNamespace, + key: &K, + ) -> Option { + key.using_encoded(|d| Self::attribute(collection, item, namespace, d)) + .and_then(|v| V::decode(&mut &v[..]).ok()) + } + + /// Returns the attribute value of `collection` corresponding to `key`. + /// + /// By default this is `None`; no attributes are defined. + fn collection_attribute(_collection: &Self::CollectionId, _key: &[u8]) -> Option> { + None + } + + /// Returns the strongly-typed attribute value of `collection` corresponding to `key`. + /// + /// 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 `item` of `collection` may be transferred. + /// + /// Default implementation is that all items are transferable. + fn can_transfer(_collection: &Self::CollectionId, _item: &Self::ItemId) -> bool { + true + } +} + +/// 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() -> Self::CollectionsIterator; + + /// Returns an iterator of the items of a `collection` in existence. + fn items(collection: &Self::CollectionId) -> Self::ItemsIterator; + + /// Returns an iterator of the items of all collections owned by `who`. + 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, + ) -> Self::OwnedInCollectionIterator; +} + +/// Trait for providing the ability to create collections of nonfungible items. +pub trait Create: Inspect { + /// Create a `collection` of nonfungible items to be owned by `who` and managed by `admin`. + fn create_collection( + who: &AccountId, + admin: &AccountId, + config: &CollectionConfig, + ) -> Result; +} + +/// Trait for providing the ability to destroy collections of nonfungible items. +pub trait Destroy: Inspect { + /// The witness data needed to destroy an item. + type DestroyWitness; + + /// Provide the appropriate witness data needed to destroy an item. + fn get_destroy_witness(collection: &Self::CollectionId) -> Option; + + /// 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 `AccountId` that can be used to authorize the destroy + /// command. If not provided, we will not do any authorization checks before destroying the + /// item. + /// + /// 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( + collection: Self::CollectionId, + witness: Self::DestroyWitness, + maybe_check_owner: Option, + ) -> Result; +} + +/// 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 `item` of `collection` to be owned by `who`. + /// + /// By default, this is not a supported operation. + fn mint_into( + _collection: &Self::CollectionId, + _item: &Self::ItemId, + _who: &AccountId, + _config: &ItemConfig, + _deposit_collection_owner: bool, + ) -> DispatchResult { + Err(TokenError::Unsupported.into()) + } + + /// Burn some `item` of `collection`. + /// + /// By default, this is not a supported operation. + fn burn( + _collection: &Self::CollectionId, + _item: &Self::ItemId, + _maybe_check_owner: Option<&AccountId>, + ) -> DispatchResult { + Err(TokenError::Unsupported.into()) + } + + /// Set attribute `value` of `item` of `collection`'s `key`. + /// + /// By default, this is not a supported operation. + fn set_attribute( + _collection: &Self::CollectionId, + _item: &Self::ItemId, + _key: &[u8], + _value: &[u8], + ) -> DispatchResult { + Err(TokenError::Unsupported.into()) + } + + /// 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( + collection: &Self::CollectionId, + item: &Self::ItemId, + key: &K, + value: &V, + ) -> DispatchResult { + key.using_encoded(|k| value.using_encoded(|v| Self::set_attribute(collection, item, k, v))) + } + + /// Set attribute `value` of `collection`'s `key`. + /// + /// By default, this is not a supported operation. + 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 `collection`'s `key`. + /// + /// By default this just attempts to use `set_attribute`. + fn set_typed_collection_attribute( + collection: &Self::CollectionId, + key: &K, + value: &V, + ) -> DispatchResult { + key.using_encoded(|k| { + value.using_encoded(|v| Self::set_collection_attribute(collection, k, v)) + }) + } +} + +/// Trait for transferring non-fungible sets of items. +pub trait Transfer: Inspect { + /// Transfer `item` of `collection` into `destination` account. + fn transfer( + collection: &Self::CollectionId, + item: &Self::ItemId, + destination: &AccountId, + ) -> DispatchResult; +} 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 170555665d877..be31b39c11725 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 @@ -26,5 +26,5 @@ error[E0277]: the trait bound `Vec: 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 78 others + and 79 others = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageMyStorage, Vec>` to implement `StorageInfoTrait` 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 a3af9897be5c7..364eb5e6d5bb1 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 281 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 162 others + and 163 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 280 others + and 281 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 9e87f87825b2a..371e90323d9cb 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 281 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 162 others + and 163 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 280 others + and 281 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_info_unsatisfied.stderr b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr index cce9fa70b3da5..b5443c6f327e4 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 78 others + and 79 others = 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 877485dda2084..afc7aaa8768cf 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 78 others + and 79 others = note: required for `Key` to implement `KeyGeneratorMaxEncodedLen` = note: required for `frame_support::pallet_prelude::StorageNMap<_GeneratedPrefixForStorageFoo, Key, u32>` to implement `StorageInfoTrait` From ed31016ca2bfe24438c17e81fc98b97738af55ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Fri, 23 Dec 2022 23:28:11 +0100 Subject: [PATCH 227/715] Ignore empty authority changes (#13010) When something tries to enact an authority change with an empty authority set, we will ignore this now. --- frame/aura/src/lib.rs | 8 ++++++++ frame/babe/src/lib.rs | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/frame/aura/src/lib.rs b/frame/aura/src/lib.rs index 635e22c5d58aa..b19fbd57c5030 100644 --- a/frame/aura/src/lib.rs +++ b/frame/aura/src/lib.rs @@ -153,7 +153,15 @@ impl Pallet { /// /// The storage will be applied immediately. /// And aura consensus log will be appended to block's log. + /// + /// This is a no-op if `new` is empty. pub fn change_authorities(new: BoundedVec) { + if new.is_empty() { + log::warn!(target: LOG_TARGET, "Ignoring empty authority change."); + + return + } + >::put(&new); let log = DigestItem::Consensus( diff --git a/frame/babe/src/lib.rs b/frame/babe/src/lib.rs index 16b2b2119793a..28ae4bfdc9dad 100644 --- a/frame/babe/src/lib.rs +++ b/frame/babe/src/lib.rs @@ -572,6 +572,8 @@ impl Pallet { /// /// Typically, this is not handled directly by the user, but by higher-level validator-set /// manager logic like `pallet-session`. + /// + /// This doesn't do anything if `authorities` is empty. pub fn enact_epoch_change( authorities: WeakBoundedVec<(AuthorityId, BabeAuthorityWeight), T::MaxAuthorities>, next_authorities: WeakBoundedVec<(AuthorityId, BabeAuthorityWeight), T::MaxAuthorities>, @@ -580,6 +582,12 @@ impl Pallet { // by the session module to be called before this. debug_assert!(Self::initialized().is_some()); + if authorities.is_empty() { + log::warn!(target: LOG_TARGET, "Ignoring empty epoch change."); + + return + } + // Update epoch index let epoch_index = EpochIndex::::get() .checked_add(1) From 999b1a18b084d9d87cd0cc0f230228e00fa15be6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= <123550+andresilva@users.noreply.github.com> Date: Sat, 24 Dec 2022 00:03:31 +0000 Subject: [PATCH 228/715] babe: allow skipping over empty epochs (#11727) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * babe: allow skipping epochs in pallet * babe: detect and skip epochs on client * babe: cleaner epoch util functions * babe: add test for runtime handling of skipped epochs * babe: simpler implementation of client handling of skipped epochs * babe: test client-side handling of skipped epochs * babe: add comments on client-side skipped epochs * babe: remove emptyline * babe: make it resilient to forks * babe: typo * babe: overflow-safe math * babe: add test for skipping epochs across different forks * Fix tests * FMT Co-authored-by: Bastian Köcher --- client/consensus/babe/src/lib.rs | 49 ++++- client/consensus/babe/src/tests.rs | 261 +++++++++++++++++++++++++++ frame/babe/src/lib.rs | 49 +++-- frame/babe/src/tests.rs | 31 ++++ primitives/consensus/babe/src/lib.rs | 19 ++ 5 files changed, 386 insertions(+), 23 deletions(-) diff --git a/client/consensus/babe/src/lib.rs b/client/consensus/babe/src/lib.rs index 1d5d4b5fe5413..41c00169e5412 100644 --- a/client/consensus/babe/src/lib.rs +++ b/client/consensus/babe/src/lib.rs @@ -543,7 +543,7 @@ fn aux_storage_cleanup + HeaderBackend, Block: B let stale_forks = match client.expand_forks(¬ification.stale_heads) { Ok(stale_forks) => stale_forks, Err((stale_forks, e)) => { - warn!(target: "babe", "{:?}", e,); + warn!(target: LOG_TARGET, "{:?}", e); stale_forks }, }; @@ -1511,11 +1511,12 @@ where if let Some(next_epoch_descriptor) = next_epoch_digest { old_epoch_changes = Some((*epoch_changes).clone()); - let viable_epoch = epoch_changes + let mut viable_epoch = epoch_changes .viable_epoch(&epoch_descriptor, |slot| Epoch::genesis(&self.config, slot)) .ok_or_else(|| { ConsensusError::ClientImport(Error::::FetchEpoch(parent_hash).into()) - })?; + })? + .into_cloned(); let epoch_config = next_config_digest .map(Into::into) @@ -1528,6 +1529,48 @@ where log::Level::Info }; + if viable_epoch.as_ref().end_slot() <= slot { + // some epochs must have been skipped as our current slot + // fits outside the current epoch. we will figure out + // which epoch it belongs to and we will re-use the same + // data for that epoch + let mut epoch_data = viable_epoch.as_mut(); + let skipped_epochs = + *slot.saturating_sub(epoch_data.start_slot) / epoch_data.duration; + + // NOTE: notice that we are only updating a local copy of the `Epoch`, this + // makes it so that when we insert the next epoch into `EpochChanges` below + // (after incrementing it), it will use the correct epoch index and start slot. + // we do not update the original epoch that will be re-used because there might + // be other forks (that we haven't imported) where the epoch isn't skipped, and + // to import those forks we want to keep the original epoch data. not updating + // the original epoch works because when we search the tree for which epoch to + // use for a given slot, we will search in-depth with the predicate + // `epoch.start_slot <= slot` which will still match correctly without updating + // `start_slot` to the correct value as below. + let epoch_index = epoch_data.epoch_index.checked_add(skipped_epochs).expect( + "epoch number is u64; it should be strictly smaller than number of slots; \ + slots relate in some way to wall clock time; \ + if u64 is not enough we should crash for safety; qed.", + ); + + let start_slot = skipped_epochs + .checked_mul(epoch_data.duration) + .and_then(|skipped_slots| epoch_data.start_slot.checked_add(skipped_slots)) + .expect( + "slot number is u64; it should relate in some way to wall clock time; \ + if u64 is not enough we should crash for safety; qed.", + ); + + warn!( + target: LOG_TARGET, + "👶 Epoch(s) skipped: from {} to {}", epoch_data.epoch_index, epoch_index, + ); + + epoch_data.epoch_index = epoch_index; + epoch_data.start_slot = Slot::from(start_slot); + } + log!( target: LOG_TARGET, log_level, diff --git a/client/consensus/babe/src/tests.rs b/client/consensus/babe/src/tests.rs index 84ac3d7341199..f74864a003e2a 100644 --- a/client/consensus/babe/src/tests.rs +++ b/client/consensus/babe/src/tests.rs @@ -28,6 +28,7 @@ use rand_chacha::{ use sc_block_builder::{BlockBuilder, BlockBuilderProvider}; use sc_client_api::{backend::TransactionFor, BlockchainEvents, Finalizer}; use sc_consensus::{BoxBlockImport, BoxJustificationImport}; +use sc_consensus_epochs::{EpochIdentifier, EpochIdentifierPosition}; use sc_consensus_slots::BackoffAuthoringOnFinalizedHeadLagging; use sc_network_test::{Block as TestBlock, *}; use sp_application_crypto::key_types::BABE; @@ -1109,3 +1110,263 @@ async fn obsolete_blocks_aux_data_cleanup() { // Present C4, C5 assert!(aux_data_check(&fork3_hashes, true)); } + +#[tokio::test] +async fn allows_skipping_epochs() { + 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 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 epoch_changes = data.link.epoch_changes.clone(); + let epoch_length = data.link.config.epoch_length; + + // we create all of the blocks in epoch 0 as well as a block in epoch 1 + let blocks = propose_and_import_blocks( + &client, + &mut proposer_factory, + &mut block_import, + client.chain_info().genesis_hash, + epoch_length as usize + 1, + ) + .await; + + // the first block in epoch 0 (#1) announces both epoch 0 and 1 (this is a + // special genesis epoch) + let epoch0 = epoch_changes + .shared_data() + .epoch(&EpochIdentifier { + position: EpochIdentifierPosition::Genesis0, + hash: blocks[0], + number: 1, + }) + .unwrap() + .clone(); + + assert_eq!(epoch0.epoch_index, 0); + assert_eq!(epoch0.start_slot, Slot::from(1)); + + let epoch1 = epoch_changes + .shared_data() + .epoch(&EpochIdentifier { + position: EpochIdentifierPosition::Genesis1, + hash: blocks[0], + number: 1, + }) + .unwrap() + .clone(); + + assert_eq!(epoch1.epoch_index, 1); + assert_eq!(epoch1.start_slot, Slot::from(epoch_length + 1)); + + // the first block in epoch 1 (#7) announces epoch 2. we will be skipping + // this epoch and therefore re-using its data for epoch 3 + let epoch2 = epoch_changes + .shared_data() + .epoch(&EpochIdentifier { + position: EpochIdentifierPosition::Regular, + hash: blocks[epoch_length as usize], + number: epoch_length + 1, + }) + .unwrap() + .clone(); + + assert_eq!(epoch2.epoch_index, 2); + assert_eq!(epoch2.start_slot, Slot::from(epoch_length * 2 + 1)); + + // we now author a block that belongs to epoch 3, thereby skipping epoch 2 + let last_block = client.expect_header(*blocks.last().unwrap()).unwrap(); + let block = propose_and_import_block( + &last_block, + Some((epoch_length * 3 + 1).into()), + &mut proposer_factory, + &mut block_import, + ) + .await; + + // and the first block in epoch 3 (#8) announces epoch 4 + let epoch4 = epoch_changes + .shared_data() + .epoch(&EpochIdentifier { + position: EpochIdentifierPosition::Regular, + hash: block, + number: epoch_length + 2, + }) + .unwrap() + .clone(); + + assert_eq!(epoch4.epoch_index, 4); + assert_eq!(epoch4.start_slot, Slot::from(epoch_length * 4 + 1)); + + // if we try to get the epoch data for a slot in epoch 3 + let epoch3 = epoch_changes + .shared_data() + .epoch_data_for_child_of( + descendent_query(&*client), + &block, + epoch_length + 2, + (epoch_length * 3 + 2).into(), + |slot| Epoch::genesis(&data.link.config, slot), + ) + .unwrap() + .unwrap(); + + // we get back the data for epoch 2 + assert_eq!(epoch3, epoch2); + + // but if we try to get the epoch data for a slot in epoch 4 + let epoch4_ = epoch_changes + .shared_data() + .epoch_data_for_child_of( + descendent_query(&*client), + &block, + epoch_length + 2, + (epoch_length * 4 + 1).into(), + |slot| Epoch::genesis(&data.link.config, slot), + ) + .unwrap() + .unwrap(); + + // we get epoch 4 as expected + assert_eq!(epoch4, epoch4_); +} + +#[tokio::test] +async fn allows_skipping_epochs_on_some_forks() { + 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 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 epoch_changes = data.link.epoch_changes.clone(); + let epoch_length = data.link.config.epoch_length; + + // we create all of the blocks in epoch 0 as well as two blocks in epoch 1 + let blocks = propose_and_import_blocks( + &client, + &mut proposer_factory, + &mut block_import, + client.chain_info().genesis_hash, + epoch_length as usize + 1, + ) + .await; + + // we now author a block that belongs to epoch 2, built on top of the last + // authored block in epoch 1. + let last_block = client.expect_header(*blocks.last().unwrap()).unwrap(); + + let epoch2_block = propose_and_import_block( + &last_block, + Some((epoch_length * 2 + 1).into()), + &mut proposer_factory, + &mut block_import, + ) + .await; + + // if we try to get the epoch data for a slot in epoch 2, we get the data that + // was previously announced when epoch 1 started + let epoch2 = epoch_changes + .shared_data() + .epoch_data_for_child_of( + descendent_query(&*client), + &epoch2_block, + epoch_length + 2, + (epoch_length * 2 + 2).into(), + |slot| Epoch::genesis(&data.link.config, slot), + ) + .unwrap() + .unwrap(); + + // we now author a block that belongs to epoch 3, built on top of the last + // authored block in epoch 1. authoring this block means we're skipping epoch 2 + // entirely on this fork + let epoch3_block = propose_and_import_block( + &last_block, + Some((epoch_length * 3 + 1).into()), + &mut proposer_factory, + &mut block_import, + ) + .await; + + // if we try to get the epoch data for a slot in epoch 3 + let epoch3_ = epoch_changes + .shared_data() + .epoch_data_for_child_of( + descendent_query(&*client), + &epoch3_block, + epoch_length + 2, + (epoch_length * 3 + 2).into(), + |slot| Epoch::genesis(&data.link.config, slot), + ) + .unwrap() + .unwrap(); + + // we get back the data for epoch 2 + assert_eq!(epoch3_, epoch2); + + // if we try to get the epoch data for a slot in epoch 4 in the fork + // where we skipped epoch 2, we should get the epoch data for epoch 4 + // that was announced at the beginning of epoch 3 + let epoch_data = epoch_changes + .shared_data() + .epoch_data_for_child_of( + descendent_query(&*client), + &epoch3_block, + epoch_length + 2, + (epoch_length * 4 + 1).into(), + |slot| Epoch::genesis(&data.link.config, slot), + ) + .unwrap() + .unwrap(); + + assert!(epoch_data != epoch3_); + + // if we try to get the epoch data for a slot in epoch 4 in the fork + // where we didn't skip epoch 2, we should get back the data for epoch 3, + // that was announced when epoch 2 started in that fork + let epoch_data = epoch_changes + .shared_data() + .epoch_data_for_child_of( + descendent_query(&*client), + &epoch2_block, + epoch_length + 2, + (epoch_length * 4 + 1).into(), + |slot| Epoch::genesis(&data.link.config, slot), + ) + .unwrap() + .unwrap(); + + assert!(epoch_data != epoch3_); + + let epoch3 = epoch_changes + .shared_data() + .epoch(&EpochIdentifier { + position: EpochIdentifierPosition::Regular, + hash: epoch2_block, + number: epoch_length + 2, + }) + .unwrap() + .clone(); + + assert_eq!(epoch_data, epoch3); +} diff --git a/frame/babe/src/lib.rs b/frame/babe/src/lib.rs index 28ae4bfdc9dad..eb87d65b0549f 100644 --- a/frame/babe/src/lib.rs +++ b/frame/babe/src/lib.rs @@ -588,10 +588,19 @@ impl Pallet { return } - // Update epoch index - let epoch_index = EpochIndex::::get() - .checked_add(1) - .expect("epoch indices will never reach 2^64 before the death of the universe; qed"); + // Update epoch index. + // + // NOTE: we figure out the epoch index from the slot, which may not + // necessarily be contiguous if the chain was offline for more than + // `T::EpochDuration` slots. When skipping from epoch N to e.g. N+4, we + // will be using the randomness and authorities for that epoch that had + // been previously announced for epoch N+1, and the randomness collected + // during the current epoch (N) will be used for epoch N+5. + let epoch_index = sp_consensus_babe::epoch_index( + CurrentSlot::::get(), + GenesisSlot::::get(), + T::EpochDuration::get(), + ); EpochIndex::::put(epoch_index); Authorities::::put(authorities); @@ -638,11 +647,16 @@ impl Pallet { } } - /// Finds the start slot of the current epoch. only guaranteed to - /// give correct results after `initialize` of the first block - /// in the chain (as its result is based off of `GenesisSlot`). + /// Finds the start slot of the current epoch. + /// + /// Only guaranteed to 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()) + sp_consensus_babe::epoch_start_slot( + EpochIndex::::get(), + GenesisSlot::::get(), + T::EpochDuration::get(), + ) } /// Produces information about the current epoch. @@ -666,9 +680,15 @@ impl Pallet { if u64 is not enough we should crash for safety; qed.", ); + let start_slot = sp_consensus_babe::epoch_start_slot( + next_epoch_index, + GenesisSlot::::get(), + T::EpochDuration::get(), + ); + Epoch { epoch_index: next_epoch_index, - start_slot: Self::epoch_start(next_epoch_index), + start_slot, duration: T::EpochDuration::get(), authorities: NextAuthorities::::get().to_vec(), randomness: NextRandomness::::get(), @@ -680,17 +700,6 @@ impl Pallet { } } - fn epoch_start(epoch_index: u64) -> Slot { - // (epoch_index * epoch_duration) + genesis_slot - - const PROOF: &str = "slot number is u64; it should relate in some way to wall clock time; \ - if u64 is not enough we should crash for safety; qed."; - - let epoch_start = epoch_index.checked_mul(T::EpochDuration::get()).expect(PROOF); - - epoch_start.checked_add(*GenesisSlot::::get()).expect(PROOF).into() - } - fn deposit_consensus(new: U) { let log = DigestItem::Consensus(BABE_ENGINE_ID, new.encode()); >::deposit_log(log) diff --git a/frame/babe/src/tests.rs b/frame/babe/src/tests.rs index d4132e6378540..0b8a02547144b 100644 --- a/frame/babe/src/tests.rs +++ b/frame/babe/src/tests.rs @@ -948,3 +948,34 @@ fn generate_equivocation_report_blob() { println!("equivocation_proof.encode(): {:?}", equivocation_proof.encode()); }); } + +#[test] +fn skipping_over_epochs_works() { + let mut ext = new_test_ext(3); + + ext.execute_with(|| { + let epoch_duration: u64 = ::EpochDuration::get(); + + // this sets the genesis slot to 100; + let genesis_slot = 100; + go_to_block(1, genesis_slot); + + // we will author all blocks from epoch #0 and arrive at a point where + // we are in epoch #1. we should already have the randomness ready that + // will be used in epoch #2 + progress_to_block(epoch_duration + 1); + assert_eq!(EpochIndex::::get(), 1); + + // genesis randomness is an array of zeros + let randomness_for_epoch_2 = NextRandomness::::get(); + assert!(randomness_for_epoch_2 != [0; 32]); + + // we will now create a block for a slot that is part of epoch #4. + // we should appropriately increment the epoch index as well as re-use + // the randomness from epoch #2 on epoch #4 + go_to_block(System::block_number() + 1, genesis_slot + epoch_duration * 4); + + assert_eq!(EpochIndex::::get(), 4); + assert_eq!(Randomness::::get(), randomness_for_epoch_2); + }); +} diff --git a/primitives/consensus/babe/src/lib.rs b/primitives/consensus/babe/src/lib.rs index 621ab859b914f..cb44afcb8d4e4 100644 --- a/primitives/consensus/babe/src/lib.rs +++ b/primitives/consensus/babe/src/lib.rs @@ -360,6 +360,25 @@ pub struct Epoch { pub config: BabeEpochConfiguration, } +/// Returns the epoch index the given slot belongs to. +pub fn epoch_index(slot: Slot, genesis_slot: Slot, epoch_duration: u64) -> u64 { + *slot.saturating_sub(genesis_slot) / epoch_duration +} + +/// Returns the first slot at the given epoch index. +pub fn epoch_start_slot(epoch_index: u64, genesis_slot: Slot, epoch_duration: u64) -> Slot { + // (epoch_index * epoch_duration) + genesis_slot + + const PROOF: &str = "slot number is u64; it should relate in some way to wall clock time; \ + if u64 is not enough we should crash for safety; qed."; + + epoch_index + .checked_mul(epoch_duration) + .and_then(|slot| slot.checked_add(*genesis_slot)) + .expect(PROOF) + .into() +} + sp_api::decl_runtime_apis! { /// API necessary for block authorship with BABE. #[api_version(2)] From c16472e7e4a588d8e202c1ab3e865cf6e7b201c5 Mon Sep 17 00:00:00 2001 From: Ankan <10196091+Ank4n@users.noreply.github.com> Date: Mon, 26 Dec 2022 16:48:40 +0100 Subject: [PATCH 229/715] Allow StakingAdmin to set `min_commission` (#13018) * staking admin can set min commission * ".git/.scripts/bench-bot.sh" pallet dev pallet_staking * fmt * fix for pr comments Co-authored-by: command-bot <> --- bin/node/runtime/src/lib.rs | 2 +- frame/babe/src/mock.rs | 2 +- frame/fast-unstake/src/mock.rs | 2 +- frame/grandpa/src/mock.rs | 2 +- .../nomination-pools/benchmarking/src/mock.rs | 2 +- .../nomination-pools/test-staking/src/mock.rs | 2 +- frame/offences/benchmarking/src/mock.rs | 2 +- frame/root-offences/src/mock.rs | 2 +- frame/session/benchmarking/src/mock.rs | 2 +- frame/staking/src/benchmarking.rs | 7 + frame/staking/src/mock.rs | 14 +- frame/staking/src/pallet/mod.rs | 23 +- frame/staking/src/tests.rs | 40 ++ frame/staking/src/weights.rs | 385 +++++++++--------- 14 files changed, 286 insertions(+), 201 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 3e2701b2278c8..0c946fa180f20 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -567,7 +567,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 = EitherOfDiverse< + type AdminOrigin = EitherOfDiverse< EnsureRoot, pallet_collective::EnsureProportionAtLeast, >; diff --git a/frame/babe/src/mock.rs b/frame/babe/src/mock.rs index 204de8aae172e..dbeb588c1830e 100644 --- a/frame/babe/src/mock.rs +++ b/frame/babe/src/mock.rs @@ -195,7 +195,7 @@ impl pallet_staking::Config for Test { type SessionsPerEra = SessionsPerEra; type BondingDuration = BondingDuration; type SlashDeferDuration = SlashDeferDuration; - type SlashCancelOrigin = frame_system::EnsureRoot; + type AdminOrigin = frame_system::EnsureRoot; type SessionInterface = Self; type UnixTime = pallet_timestamp::Pallet; type EraPayout = pallet_staking::ConvertCurve; diff --git a/frame/fast-unstake/src/mock.rs b/frame/fast-unstake/src/mock.rs index b67dcf581ed97..3f974e5e1a9d6 100644 --- a/frame/fast-unstake/src/mock.rs +++ b/frame/fast-unstake/src/mock.rs @@ -140,7 +140,7 @@ impl pallet_staking::Config for Runtime { type Reward = (); type SessionsPerEra = (); type SlashDeferDuration = (); - type SlashCancelOrigin = frame_system::EnsureRoot; + type AdminOrigin = frame_system::EnsureRoot; type BondingDuration = BondingDuration; type SessionInterface = (); type EraPayout = pallet_staking::ConvertCurve; diff --git a/frame/grandpa/src/mock.rs b/frame/grandpa/src/mock.rs index 1a97b1345fe5d..131f6cafcd179 100644 --- a/frame/grandpa/src/mock.rs +++ b/frame/grandpa/src/mock.rs @@ -199,7 +199,7 @@ impl pallet_staking::Config for Test { type SessionsPerEra = SessionsPerEra; type BondingDuration = BondingDuration; type SlashDeferDuration = (); - type SlashCancelOrigin = frame_system::EnsureRoot; + type AdminOrigin = frame_system::EnsureRoot; type SessionInterface = Self; type UnixTime = pallet_timestamp::Pallet; type EraPayout = pallet_staking::ConvertCurve; diff --git a/frame/nomination-pools/benchmarking/src/mock.rs b/frame/nomination-pools/benchmarking/src/mock.rs index 6959aa9783ee5..06a66838594c7 100644 --- a/frame/nomination-pools/benchmarking/src/mock.rs +++ b/frame/nomination-pools/benchmarking/src/mock.rs @@ -102,7 +102,7 @@ impl pallet_staking::Config for Runtime { type Reward = (); type SessionsPerEra = (); type SlashDeferDuration = (); - type SlashCancelOrigin = frame_system::EnsureRoot; + type AdminOrigin = frame_system::EnsureRoot; type BondingDuration = ConstU32<3>; type SessionInterface = (); type EraPayout = pallet_staking::ConvertCurve; diff --git a/frame/nomination-pools/test-staking/src/mock.rs b/frame/nomination-pools/test-staking/src/mock.rs index 568dec7b3a340..c67aec0134b07 100644 --- a/frame/nomination-pools/test-staking/src/mock.rs +++ b/frame/nomination-pools/test-staking/src/mock.rs @@ -116,7 +116,7 @@ impl pallet_staking::Config for Runtime { type Reward = (); type SessionsPerEra = (); type SlashDeferDuration = (); - type SlashCancelOrigin = frame_system::EnsureRoot; + type AdminOrigin = frame_system::EnsureRoot; type BondingDuration = BondingDuration; type SessionInterface = (); type EraPayout = pallet_staking::ConvertCurve; diff --git a/frame/offences/benchmarking/src/mock.rs b/frame/offences/benchmarking/src/mock.rs index de3a4eca6308d..223f551a6e5c1 100644 --- a/frame/offences/benchmarking/src/mock.rs +++ b/frame/offences/benchmarking/src/mock.rs @@ -173,7 +173,7 @@ impl pallet_staking::Config for Test { type Reward = (); type SessionsPerEra = (); type SlashDeferDuration = (); - type SlashCancelOrigin = frame_system::EnsureRoot; + type AdminOrigin = frame_system::EnsureRoot; type BondingDuration = (); type SessionInterface = Self; type EraPayout = pallet_staking::ConvertCurve; diff --git a/frame/root-offences/src/mock.rs b/frame/root-offences/src/mock.rs index 65bfcad4b26fc..e1d9ee14ee2fc 100644 --- a/frame/root-offences/src/mock.rs +++ b/frame/root-offences/src/mock.rs @@ -184,7 +184,7 @@ impl pallet_staking::Config for Test { type Reward = (); type SessionsPerEra = SessionsPerEra; type SlashDeferDuration = SlashDeferDuration; - type SlashCancelOrigin = frame_system::EnsureRoot; + type AdminOrigin = frame_system::EnsureRoot; type BondingDuration = BondingDuration; type SessionInterface = Self; type EraPayout = pallet_staking::ConvertCurve; diff --git a/frame/session/benchmarking/src/mock.rs b/frame/session/benchmarking/src/mock.rs index 2db7eb385111c..0699640bc092a 100644 --- a/frame/session/benchmarking/src/mock.rs +++ b/frame/session/benchmarking/src/mock.rs @@ -167,7 +167,7 @@ impl pallet_staking::Config for Test { type Reward = (); type SessionsPerEra = (); type SlashDeferDuration = (); - type SlashCancelOrigin = frame_system::EnsureRoot; + type AdminOrigin = frame_system::EnsureRoot; type BondingDuration = (); type SessionInterface = Self; type EraPayout = pallet_staking::ConvertCurve; diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index 81fa0f9d81dbf..b3d32b26ec1f7 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -922,6 +922,13 @@ benchmarks! { ); } + set_min_commission { + let min_commission = Perbill::max_value(); + }: _(RawOrigin::Root, min_commission) + verify { + assert_eq!(MinCommission::::get(), Perbill::from_percent(100)); + } + impl_benchmark_test_suite!( Staking, crate::mock::ExtBuilder::default().has_stakers(true), diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index d3affda05277a..843e452125a6e 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -20,13 +20,14 @@ use crate::{self as pallet_staking, *}; use frame_election_provider_support::{onchain, SequentialPhragmen, VoteWeight}; use frame_support::{ - assert_ok, parameter_types, + assert_ok, ord_parameter_types, parameter_types, traits::{ - ConstU32, ConstU64, Currency, FindAuthor, GenesisBuild, Get, Hooks, Imbalance, - OnUnbalanced, OneSessionHandler, + ConstU32, ConstU64, Currency, EitherOfDiverse, FindAuthor, GenesisBuild, Get, Hooks, + Imbalance, OnUnbalanced, OneSessionHandler, }, weights::constants::RocksDbWeight, }; +use frame_system::{EnsureRoot, EnsureSignedBy}; use sp_core::H256; use sp_io; use sp_runtime::{ @@ -292,7 +293,7 @@ impl crate::pallet::pallet::Config for Test { type Reward = MockReward; type SessionsPerEra = SessionsPerEra; type SlashDeferDuration = SlashDeferDuration; - type SlashCancelOrigin = frame_system::EnsureRoot; + type AdminOrigin = EnsureOneOrRoot; type BondingDuration = BondingDuration; type SessionInterface = Self; type EraPayout = ConvertCurve; @@ -797,6 +798,11 @@ pub(crate) fn staking_events() -> Vec> { parameter_types! { static StakingEventsIndex: usize = 0; } +ord_parameter_types! { + pub const One: u64 = 1; +} + +type EnsureOneOrRoot = EitherOfDiverse, EnsureSignedBy>; pub(crate) fn staking_events_since_last_call() -> Vec> { let all: Vec<_> = System::events() diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index f04d13d05f468..8e8a8d9c7f600 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -183,8 +183,10 @@ pub mod pallet { #[pallet::constant] type SlashDeferDuration: Get; - /// The origin which can cancel a deferred slash. Root can always do this. - type SlashCancelOrigin: EnsureOrigin; + /// The origin which can manage less critical staking parameters that does not require root. + /// + /// Supported actions: (1) cancel deferred slash, (2) set minimum commission. + type AdminOrigin: EnsureOrigin; /// Interface for interacting with a session pallet. type SessionInterface: SessionInterface; @@ -1452,7 +1454,7 @@ pub mod pallet { /// Cancel enactment of a deferred slash. /// - /// Can be called by the `T::SlashCancelOrigin`. + /// Can be called by the `T::AdminOrigin`. /// /// Parameters: era and indices of the slashes for that era to kill. #[pallet::call_index(17)] @@ -1462,7 +1464,7 @@ pub mod pallet { era: EraIndex, slash_indices: Vec, ) -> DispatchResult { - T::SlashCancelOrigin::ensure_origin(origin)?; + T::AdminOrigin::ensure_origin(origin)?; ensure!(!slash_indices.is_empty(), Error::::EmptyTargets); ensure!(is_sorted_and_unique(&slash_indices), Error::::NotSortedAndUnique); @@ -1683,7 +1685,6 @@ pub mod pallet { config_op_exp!(MinCommission, min_commission); Ok(()) } - /// Declare a `controller` to stop participating as either a validator or nominator. /// /// Effects will be felt at the beginning of the next era. @@ -1792,6 +1793,18 @@ pub mod pallet { })?; Ok(()) } + + /// Sets the minimum amount of commission that each validators must maintain. + /// + /// This call has lower privilege requirements than `set_staking_config` and can be called + /// by the `T::AdminOrigin`. Root can always call this. + #[pallet::call_index(25)] + #[pallet::weight(T::WeightInfo::set_min_commission())] + pub fn set_min_commission(origin: OriginFor, new: Perbill) -> DispatchResult { + T::AdminOrigin::ensure_origin(origin)?; + MinCommission::::put(new); + Ok(()) + } } } diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 5c2766deee307..46c3c97441938 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -5726,6 +5726,46 @@ fn scale_validator_count_errors() { }) } +#[test] +fn set_min_commission_works_with_admin_origin() { + ExtBuilder::default().build_and_execute(|| { + // no minimum commission set initially + assert_eq!(MinCommission::::get(), Zero::zero()); + + // root can set min commission + assert_ok!(Staking::set_min_commission(RuntimeOrigin::root(), Perbill::from_percent(10))); + + assert_eq!(MinCommission::::get(), Perbill::from_percent(10)); + + // Non privileged origin can not set min_commission + assert_noop!( + Staking::set_min_commission(RuntimeOrigin::signed(2), Perbill::from_percent(15)), + BadOrigin + ); + + // Admin Origin can set min commission + assert_ok!(Staking::set_min_commission( + RuntimeOrigin::signed(1), + Perbill::from_percent(15), + )); + + // setting commission below min_commission fails + assert_noop!( + Staking::validate( + RuntimeOrigin::signed(10), + ValidatorPrefs { commission: Perbill::from_percent(14), blocked: false } + ), + Error::::CommissionTooLow + ); + + // setting commission >= min_commission works + assert_ok!(Staking::validate( + RuntimeOrigin::signed(10), + ValidatorPrefs { commission: Perbill::from_percent(15), blocked: false } + )); + }) +} + mod staking_interface { use frame_support::storage::with_storage_layer; use sp_staking::StakingInterface; diff --git a/frame/staking/src/weights.rs b/frame/staking/src/weights.rs index aebb8eeb9b06e..9c283f5a065e3 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-12-14, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-12-25, 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 @@ -77,6 +77,7 @@ pub trait WeightInfo { fn set_staking_configs_all_remove() -> Weight; fn chill_other() -> Weight; fn force_apply_min_commission() -> Weight; + fn set_min_commission() -> Weight; } /// Weights for pallet_staking using the Substrate node and recommended hardware. @@ -88,8 +89,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn bond() -> Weight { - // Minimum execution time: 54_402 nanoseconds. - Weight::from_ref_time(55_096_000) + // Minimum execution time: 54_884 nanoseconds. + Weight::from_ref_time(55_487_000) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -99,8 +100,8 @@ 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: 94_407 nanoseconds. - Weight::from_ref_time(95_209_000) + // Minimum execution time: 95_115 nanoseconds. + Weight::from_ref_time(96_213_000) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(7)) } @@ -114,8 +115,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Bonded (r:1 w:0) // Storage: VoterList ListBags (r:2 w:2) fn unbond() -> Weight { - // Minimum execution time: 101_046 nanoseconds. - Weight::from_ref_time(101_504_000) + // Minimum execution time: 102_031 nanoseconds. + Weight::from_ref_time(102_842_000) .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(8)) } @@ -125,10 +126,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 { - // Minimum execution time: 45_452 nanoseconds. - Weight::from_ref_time(47_031_537) - // Standard Error: 491 - .saturating_add(Weight::from_ref_time(67_148).saturating_mul(s.into())) + // Minimum execution time: 46_569 nanoseconds. + Weight::from_ref_time(48_034_493) + // Standard Error: 654 + .saturating_add(Weight::from_ref_time(63_628).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -148,10 +149,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking SpanSlash (r:0 w:2) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_kill(s: u32, ) -> Weight { - // Minimum execution time: 88_067 nanoseconds. - Weight::from_ref_time(93_309_587) - // Standard Error: 4_762 - .saturating_add(Weight::from_ref_time(1_114_938).saturating_mul(s.into())) + // Minimum execution time: 90_154 nanoseconds. + Weight::from_ref_time(95_725_631) + // Standard Error: 2_491 + .saturating_add(Weight::from_ref_time(1_110_795).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(13)) .saturating_add(T::DbWeight::get().writes(12)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -168,8 +169,8 @@ 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_308 nanoseconds. - Weight::from_ref_time(68_266_000) + // Minimum execution time: 67_978 nanoseconds. + Weight::from_ref_time(69_153_000) .saturating_add(T::DbWeight::get().reads(11)) .saturating_add(T::DbWeight::get().writes(5)) } @@ -177,10 +178,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Nominators (r:1 w:1) /// The range of component `k` is `[1, 128]`. fn kick(k: u32, ) -> Weight { - // Minimum execution time: 40_913 nanoseconds. - Weight::from_ref_time(48_140_584) - // Standard Error: 13_396 - .saturating_add(Weight::from_ref_time(6_862_893).saturating_mul(k.into())) + // Minimum execution time: 45_328 nanoseconds. + Weight::from_ref_time(47_719_103) + // Standard Error: 14_458 + .saturating_add(Weight::from_ref_time(6_999_252).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()))) @@ -198,10 +199,10 @@ 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: 73_490 nanoseconds. - Weight::from_ref_time(72_520_864) - // Standard Error: 7_090 - .saturating_add(Weight::from_ref_time(2_800_566).saturating_mul(n.into())) + // Minimum execution time: 74_650 nanoseconds. + Weight::from_ref_time(74_350_075) + // Standard Error: 10_527 + .saturating_add(Weight::from_ref_time(2_878_737).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)) @@ -214,58 +215,58 @@ 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_293 nanoseconds. - Weight::from_ref_time(66_946_000) + // Minimum execution time: 67_790 nanoseconds. + Weight::from_ref_time(68_738_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_134 nanoseconds. - Weight::from_ref_time(18_497_000) + // Minimum execution time: 19_237 nanoseconds. + Weight::from_ref_time(19_534_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_728 nanoseconds. - Weight::from_ref_time(27_154_000) + // Minimum execution time: 27_288 nanoseconds. + Weight::from_ref_time(27_667_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: 4_877 nanoseconds. - Weight::from_ref_time(5_028_000) + // Minimum execution time: 5_155 nanoseconds. + Weight::from_ref_time(5_464_000) .saturating_add(T::DbWeight::get().writes(1)) } // Storage: Staking ForceEra (r:0 w:1) fn force_no_eras() -> Weight { - // Minimum execution time: 5_000 nanoseconds. - Weight::from_ref_time(5_290_000) + // Minimum execution time: 5_405 nanoseconds. + Weight::from_ref_time(5_670_000) .saturating_add(T::DbWeight::get().writes(1)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era() -> Weight { - // Minimum execution time: 5_093 nanoseconds. - Weight::from_ref_time(5_378_000) + // Minimum execution time: 5_459 nanoseconds. + Weight::from_ref_time(5_616_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_144 nanoseconds. - Weight::from_ref_time(5_454_000) + // Minimum execution time: 5_476 nanoseconds. + Weight::from_ref_time(5_692_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_190 nanoseconds. - Weight::from_ref_time(5_960_962) - // Standard Error: 41 - .saturating_add(Weight::from_ref_time(10_329).saturating_mul(v.into())) + // Minimum execution time: 5_544 nanoseconds. + Weight::from_ref_time(6_513_190) + // Standard Error: 76 + .saturating_add(Weight::from_ref_time(9_975).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().writes(1)) } // Storage: Staking Bonded (r:1 w:1) @@ -283,10 +284,10 @@ 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_516 nanoseconds. - Weight::from_ref_time(86_317_884) - // Standard Error: 2_212 - .saturating_add(Weight::from_ref_time(1_103_962).saturating_mul(s.into())) + // Minimum execution time: 82_414 nanoseconds. + Weight::from_ref_time(88_511_246) + // Standard Error: 2_622 + .saturating_add(Weight::from_ref_time(1_131_814).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()))) @@ -294,10 +295,10 @@ impl WeightInfo for SubstrateWeight { // 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: 91_795 nanoseconds. - Weight::from_ref_time(904_524_900) - // Standard Error: 59_193 - .saturating_add(Weight::from_ref_time(4_944_680).saturating_mul(s.into())) + // Minimum execution time: 94_197 nanoseconds. + Weight::from_ref_time(903_418_326) + // Standard Error: 59_354 + .saturating_add(Weight::from_ref_time(4_948_354).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -312,10 +313,10 @@ 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_774 nanoseconds. - Weight::from_ref_time(178_857_156) - // Standard Error: 15_229 - .saturating_add(Weight::from_ref_time(22_112_174).saturating_mul(n.into())) + // Minimum execution time: 133_065 nanoseconds. + Weight::from_ref_time(197_555_906) + // Standard Error: 19_561 + .saturating_add(Weight::from_ref_time(22_683_426).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)) @@ -333,10 +334,10 @@ 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: 161_910 nanoseconds. - Weight::from_ref_time(217_635_072) - // Standard Error: 30_726 - .saturating_add(Weight::from_ref_time(31_244_329).saturating_mul(n.into())) + // Minimum execution time: 164_719 nanoseconds. + Weight::from_ref_time(226_304_276) + // Standard Error: 31_675 + .saturating_add(Weight::from_ref_time(32_622_427).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)) @@ -350,10 +351,10 @@ 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_986 nanoseconds. - Weight::from_ref_time(94_880_481) - // Standard Error: 2_007 - .saturating_add(Weight::from_ref_time(31_421).saturating_mul(l.into())) + // Minimum execution time: 95_631 nanoseconds. + Weight::from_ref_time(96_861_556) + // Standard Error: 2_114 + .saturating_add(Weight::from_ref_time(37_543).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(8)) } @@ -372,10 +373,10 @@ 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_750 nanoseconds. - Weight::from_ref_time(95_115_568) - // Standard Error: 2_037 - .saturating_add(Weight::from_ref_time(1_086_488).saturating_mul(s.into())) + // Minimum execution time: 95_251 nanoseconds. + Weight::from_ref_time(97_818_954) + // Standard Error: 2_356 + .saturating_add(Weight::from_ref_time(1_104_695).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()))) @@ -396,19 +397,20 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking ErasStakers (r:0 w:1) // Storage: Staking ErasTotalStake (r:0 w:1) // Storage: Staking ErasStartSessionIndex (r:0 w:1) + // Storage: Staking MinimumActiveStake (r:0 w:1) /// 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: 506_543 nanoseconds. - Weight::from_ref_time(507_261_000) - // Standard Error: 1_766_631 - .saturating_add(Weight::from_ref_time(59_139_153).saturating_mul(v.into())) - // Standard Error: 176_035 - .saturating_add(Weight::from_ref_time(13_512_781).saturating_mul(n.into())) + // Minimum execution time: 512_923 nanoseconds. + Weight::from_ref_time(514_740_000) + // Standard Error: 1_790_238 + .saturating_add(Weight::from_ref_time(59_320_539).saturating_mul(v.into())) + // Standard Error: 178_387 + .saturating_add(Weight::from_ref_time(13_902_705).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(4)) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(v.into()))) } // Storage: VoterList CounterForListNodes (r:1 w:0) @@ -418,27 +420,29 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Validators (r:500 w:0) // Storage: Staking Bonded (r:1500 w:0) // Storage: Staking Ledger (r:1500 w:0) + // Storage: Staking MinimumActiveStake (r:0 w:1) /// The range of component `v` is `[500, 1000]`. /// The range of component `n` is `[500, 1000]`. fn get_npos_voters(v: u32, n: u32, ) -> Weight { - // Minimum execution time: 24_155_382 nanoseconds. - Weight::from_ref_time(24_252_568_000) - // Standard Error: 319_250 - .saturating_add(Weight::from_ref_time(3_596_056).saturating_mul(v.into())) - // Standard Error: 319_250 - .saturating_add(Weight::from_ref_time(2_852_023).saturating_mul(n.into())) + // Minimum execution time: 24_913_316 nanoseconds. + Weight::from_ref_time(25_053_596_000) + // Standard Error: 324_610 + .saturating_add(Weight::from_ref_time(3_454_859).saturating_mul(v.into())) + // Standard Error: 324_610 + .saturating_add(Weight::from_ref_time(3_020_267).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()))) + .saturating_add(T::DbWeight::get().writes(1)) } // 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_741_111 nanoseconds. - Weight::from_ref_time(113_360_179) - // Standard Error: 25_375 - .saturating_add(Weight::from_ref_time(9_494_142).saturating_mul(v.into())) + // Minimum execution time: 4_916_401 nanoseconds. + Weight::from_ref_time(81_160_966) + // Standard Error: 23_829 + .saturating_add(Weight::from_ref_time(9_883_413).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) } @@ -449,8 +453,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 { - // Minimum execution time: 11_074 nanoseconds. - Weight::from_ref_time(11_312_000) + // Minimum execution time: 10_937 nanoseconds. + Weight::from_ref_time(11_324_000) .saturating_add(T::DbWeight::get().writes(6)) } // Storage: Staking MinCommission (r:0 w:1) @@ -460,8 +464,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 { - // Minimum execution time: 9_795 nanoseconds. - Weight::from_ref_time(10_116_000) + // Minimum execution time: 9_424 nanoseconds. + Weight::from_ref_time(10_021_000) .saturating_add(T::DbWeight::get().writes(6)) } // Storage: Staking Ledger (r:1 w:0) @@ -475,19 +479,25 @@ 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: 82_914 nanoseconds. - Weight::from_ref_time(83_848_000) + // Minimum execution time: 84_495 nanoseconds. + Weight::from_ref_time(85_559_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: 20_317 nanoseconds. - Weight::from_ref_time(20_639_000) + // Minimum execution time: 20_385 nanoseconds. + Weight::from_ref_time(20_824_000) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } + // Storage: Staking MinCommission (r:0 w:1) + fn set_min_commission() -> Weight { + // Minimum execution time: 6_995 nanoseconds. + Weight::from_ref_time(7_213_000) + .saturating_add(T::DbWeight::get().writes(1)) + } } // For backwards compatibility and tests @@ -498,8 +508,8 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn bond() -> Weight { - // Minimum execution time: 54_402 nanoseconds. - Weight::from_ref_time(55_096_000) + // Minimum execution time: 54_884 nanoseconds. + Weight::from_ref_time(55_487_000) .saturating_add(RocksDbWeight::get().reads(4)) .saturating_add(RocksDbWeight::get().writes(4)) } @@ -509,8 +519,8 @@ impl WeightInfo for () { // Storage: VoterList ListNodes (r:3 w:3) // Storage: VoterList ListBags (r:2 w:2) fn bond_extra() -> Weight { - // Minimum execution time: 94_407 nanoseconds. - Weight::from_ref_time(95_209_000) + // Minimum execution time: 95_115 nanoseconds. + Weight::from_ref_time(96_213_000) .saturating_add(RocksDbWeight::get().reads(8)) .saturating_add(RocksDbWeight::get().writes(7)) } @@ -524,8 +534,8 @@ impl WeightInfo for () { // Storage: Staking Bonded (r:1 w:0) // Storage: VoterList ListBags (r:2 w:2) fn unbond() -> Weight { - // Minimum execution time: 101_046 nanoseconds. - Weight::from_ref_time(101_504_000) + // Minimum execution time: 102_031 nanoseconds. + Weight::from_ref_time(102_842_000) .saturating_add(RocksDbWeight::get().reads(12)) .saturating_add(RocksDbWeight::get().writes(8)) } @@ -535,10 +545,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 { - // Minimum execution time: 45_452 nanoseconds. - Weight::from_ref_time(47_031_537) - // Standard Error: 491 - .saturating_add(Weight::from_ref_time(67_148).saturating_mul(s.into())) + // Minimum execution time: 46_569 nanoseconds. + Weight::from_ref_time(48_034_493) + // Standard Error: 654 + .saturating_add(Weight::from_ref_time(63_628).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(4)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -558,10 +568,10 @@ impl WeightInfo for () { // Storage: Staking SpanSlash (r:0 w:2) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_kill(s: u32, ) -> Weight { - // Minimum execution time: 88_067 nanoseconds. - Weight::from_ref_time(93_309_587) - // Standard Error: 4_762 - .saturating_add(Weight::from_ref_time(1_114_938).saturating_mul(s.into())) + // Minimum execution time: 90_154 nanoseconds. + Weight::from_ref_time(95_725_631) + // Standard Error: 2_491 + .saturating_add(Weight::from_ref_time(1_110_795).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(13)) .saturating_add(RocksDbWeight::get().writes(12)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -578,8 +588,8 @@ impl WeightInfo for () { // Storage: VoterList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForValidators (r:1 w:1) fn validate() -> Weight { - // Minimum execution time: 67_308 nanoseconds. - Weight::from_ref_time(68_266_000) + // Minimum execution time: 67_978 nanoseconds. + Weight::from_ref_time(69_153_000) .saturating_add(RocksDbWeight::get().reads(11)) .saturating_add(RocksDbWeight::get().writes(5)) } @@ -587,10 +597,10 @@ impl WeightInfo for () { // Storage: Staking Nominators (r:1 w:1) /// The range of component `k` is `[1, 128]`. fn kick(k: u32, ) -> Weight { - // Minimum execution time: 40_913 nanoseconds. - Weight::from_ref_time(48_140_584) - // Standard Error: 13_396 - .saturating_add(Weight::from_ref_time(6_862_893).saturating_mul(k.into())) + // Minimum execution time: 45_328 nanoseconds. + Weight::from_ref_time(47_719_103) + // Standard Error: 14_458 + .saturating_add(Weight::from_ref_time(6_999_252).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()))) @@ -608,10 +618,10 @@ 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: 73_490 nanoseconds. - Weight::from_ref_time(72_520_864) - // Standard Error: 7_090 - .saturating_add(Weight::from_ref_time(2_800_566).saturating_mul(n.into())) + // Minimum execution time: 74_650 nanoseconds. + Weight::from_ref_time(74_350_075) + // Standard Error: 10_527 + .saturating_add(Weight::from_ref_time(2_878_737).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)) @@ -624,58 +634,58 @@ impl WeightInfo for () { // Storage: VoterList ListBags (r:1 w:1) // Storage: VoterList CounterForListNodes (r:1 w:1) fn chill() -> Weight { - // Minimum execution time: 66_293 nanoseconds. - Weight::from_ref_time(66_946_000) + // Minimum execution time: 67_790 nanoseconds. + Weight::from_ref_time(68_738_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_134 nanoseconds. - Weight::from_ref_time(18_497_000) + // Minimum execution time: 19_237 nanoseconds. + Weight::from_ref_time(19_534_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_728 nanoseconds. - Weight::from_ref_time(27_154_000) + // Minimum execution time: 27_288 nanoseconds. + Weight::from_ref_time(27_667_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: 4_877 nanoseconds. - Weight::from_ref_time(5_028_000) + // Minimum execution time: 5_155 nanoseconds. + Weight::from_ref_time(5_464_000) .saturating_add(RocksDbWeight::get().writes(1)) } // Storage: Staking ForceEra (r:0 w:1) fn force_no_eras() -> Weight { - // Minimum execution time: 5_000 nanoseconds. - Weight::from_ref_time(5_290_000) + // Minimum execution time: 5_405 nanoseconds. + Weight::from_ref_time(5_670_000) .saturating_add(RocksDbWeight::get().writes(1)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era() -> Weight { - // Minimum execution time: 5_093 nanoseconds. - Weight::from_ref_time(5_378_000) + // Minimum execution time: 5_459 nanoseconds. + Weight::from_ref_time(5_616_000) .saturating_add(RocksDbWeight::get().writes(1)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era_always() -> Weight { - // Minimum execution time: 5_144 nanoseconds. - Weight::from_ref_time(5_454_000) + // Minimum execution time: 5_476 nanoseconds. + Weight::from_ref_time(5_692_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_190 nanoseconds. - Weight::from_ref_time(5_960_962) - // Standard Error: 41 - .saturating_add(Weight::from_ref_time(10_329).saturating_mul(v.into())) + // Minimum execution time: 5_544 nanoseconds. + Weight::from_ref_time(6_513_190) + // Standard Error: 76 + .saturating_add(Weight::from_ref_time(9_975).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().writes(1)) } // Storage: Staking Bonded (r:1 w:1) @@ -693,10 +703,10 @@ 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_516 nanoseconds. - Weight::from_ref_time(86_317_884) - // Standard Error: 2_212 - .saturating_add(Weight::from_ref_time(1_103_962).saturating_mul(s.into())) + // Minimum execution time: 82_414 nanoseconds. + Weight::from_ref_time(88_511_246) + // Standard Error: 2_622 + .saturating_add(Weight::from_ref_time(1_131_814).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()))) @@ -704,10 +714,10 @@ impl WeightInfo for () { // 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: 91_795 nanoseconds. - Weight::from_ref_time(904_524_900) - // Standard Error: 59_193 - .saturating_add(Weight::from_ref_time(4_944_680).saturating_mul(s.into())) + // Minimum execution time: 94_197 nanoseconds. + Weight::from_ref_time(903_418_326) + // Standard Error: 59_354 + .saturating_add(Weight::from_ref_time(4_948_354).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1)) .saturating_add(RocksDbWeight::get().writes(1)) } @@ -722,10 +732,10 @@ 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_774 nanoseconds. - Weight::from_ref_time(178_857_156) - // Standard Error: 15_229 - .saturating_add(Weight::from_ref_time(22_112_174).saturating_mul(n.into())) + // Minimum execution time: 133_065 nanoseconds. + Weight::from_ref_time(197_555_906) + // Standard Error: 19_561 + .saturating_add(Weight::from_ref_time(22_683_426).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)) @@ -743,10 +753,10 @@ 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: 161_910 nanoseconds. - Weight::from_ref_time(217_635_072) - // Standard Error: 30_726 - .saturating_add(Weight::from_ref_time(31_244_329).saturating_mul(n.into())) + // Minimum execution time: 164_719 nanoseconds. + Weight::from_ref_time(226_304_276) + // Standard Error: 31_675 + .saturating_add(Weight::from_ref_time(32_622_427).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)) @@ -760,10 +770,10 @@ 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_986 nanoseconds. - Weight::from_ref_time(94_880_481) - // Standard Error: 2_007 - .saturating_add(Weight::from_ref_time(31_421).saturating_mul(l.into())) + // Minimum execution time: 95_631 nanoseconds. + Weight::from_ref_time(96_861_556) + // Standard Error: 2_114 + .saturating_add(Weight::from_ref_time(37_543).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(9)) .saturating_add(RocksDbWeight::get().writes(8)) } @@ -782,10 +792,10 @@ 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_750 nanoseconds. - Weight::from_ref_time(95_115_568) - // Standard Error: 2_037 - .saturating_add(Weight::from_ref_time(1_086_488).saturating_mul(s.into())) + // Minimum execution time: 95_251 nanoseconds. + Weight::from_ref_time(97_818_954) + // Standard Error: 2_356 + .saturating_add(Weight::from_ref_time(1_104_695).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()))) @@ -806,19 +816,20 @@ impl WeightInfo for () { // Storage: Staking ErasStakers (r:0 w:1) // Storage: Staking ErasTotalStake (r:0 w:1) // Storage: Staking ErasStartSessionIndex (r:0 w:1) + // Storage: Staking MinimumActiveStake (r:0 w:1) /// 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: 506_543 nanoseconds. - Weight::from_ref_time(507_261_000) - // Standard Error: 1_766_631 - .saturating_add(Weight::from_ref_time(59_139_153).saturating_mul(v.into())) - // Standard Error: 176_035 - .saturating_add(Weight::from_ref_time(13_512_781).saturating_mul(n.into())) + // Minimum execution time: 512_923 nanoseconds. + Weight::from_ref_time(514_740_000) + // Standard Error: 1_790_238 + .saturating_add(Weight::from_ref_time(59_320_539).saturating_mul(v.into())) + // Standard Error: 178_387 + .saturating_add(Weight::from_ref_time(13_902_705).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(4)) .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(v.into()))) } // Storage: VoterList CounterForListNodes (r:1 w:0) @@ -828,27 +839,29 @@ impl WeightInfo for () { // Storage: Staking Validators (r:500 w:0) // Storage: Staking Bonded (r:1500 w:0) // Storage: Staking Ledger (r:1500 w:0) + // Storage: Staking MinimumActiveStake (r:0 w:1) /// The range of component `v` is `[500, 1000]`. /// The range of component `n` is `[500, 1000]`. fn get_npos_voters(v: u32, n: u32, ) -> Weight { - // Minimum execution time: 24_155_382 nanoseconds. - Weight::from_ref_time(24_252_568_000) - // Standard Error: 319_250 - .saturating_add(Weight::from_ref_time(3_596_056).saturating_mul(v.into())) - // Standard Error: 319_250 - .saturating_add(Weight::from_ref_time(2_852_023).saturating_mul(n.into())) + // Minimum execution time: 24_913_316 nanoseconds. + Weight::from_ref_time(25_053_596_000) + // Standard Error: 324_610 + .saturating_add(Weight::from_ref_time(3_454_859).saturating_mul(v.into())) + // Standard Error: 324_610 + .saturating_add(Weight::from_ref_time(3_020_267).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()))) + .saturating_add(RocksDbWeight::get().writes(1)) } // 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_741_111 nanoseconds. - Weight::from_ref_time(113_360_179) - // Standard Error: 25_375 - .saturating_add(Weight::from_ref_time(9_494_142).saturating_mul(v.into())) + // Minimum execution time: 4_916_401 nanoseconds. + Weight::from_ref_time(81_160_966) + // Standard Error: 23_829 + .saturating_add(Weight::from_ref_time(9_883_413).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().reads(2)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(v.into()))) } @@ -859,8 +872,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 { - // Minimum execution time: 11_074 nanoseconds. - Weight::from_ref_time(11_312_000) + // Minimum execution time: 10_937 nanoseconds. + Weight::from_ref_time(11_324_000) .saturating_add(RocksDbWeight::get().writes(6)) } // Storage: Staking MinCommission (r:0 w:1) @@ -870,8 +883,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 { - // Minimum execution time: 9_795 nanoseconds. - Weight::from_ref_time(10_116_000) + // Minimum execution time: 9_424 nanoseconds. + Weight::from_ref_time(10_021_000) .saturating_add(RocksDbWeight::get().writes(6)) } // Storage: Staking Ledger (r:1 w:0) @@ -885,17 +898,23 @@ impl WeightInfo for () { // Storage: VoterList ListBags (r:1 w:1) // Storage: VoterList CounterForListNodes (r:1 w:1) fn chill_other() -> Weight { - // Minimum execution time: 82_914 nanoseconds. - Weight::from_ref_time(83_848_000) + // Minimum execution time: 84_495 nanoseconds. + Weight::from_ref_time(85_559_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: 20_317 nanoseconds. - Weight::from_ref_time(20_639_000) + // Minimum execution time: 20_385 nanoseconds. + Weight::from_ref_time(20_824_000) .saturating_add(RocksDbWeight::get().reads(2)) .saturating_add(RocksDbWeight::get().writes(1)) } + // Storage: Staking MinCommission (r:0 w:1) + fn set_min_commission() -> Weight { + // Minimum execution time: 6_995 nanoseconds. + Weight::from_ref_time(7_213_000) + .saturating_add(RocksDbWeight::get().writes(1)) + } } From 27e9a1c0fdb200c3736f513f3292b8b954e3d021 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Mon, 26 Dec 2022 17:37:09 +0100 Subject: [PATCH 230/715] Make CLI state pruning optional again (#13017) * Make CLI state pruning optional again The state pruning setting is stored in the database when it is created. In later runs it is fine to drop the `--state-pruning` CLI argument as the setting is stored in the database. The state db will only return an error if the stored state pruning doesn't match the state pruning given via CLI. Recently we improved the state pruning CLI handling and accidentally made the state pruning value always present (as we set some default value for the clap). If we could find out if a user has passed a value or the default value was taken, we could keep the default value in the CLI interface, but clap isn't supporting this right now. So, we need to go back and make `state_pruning` an optional with the default written into the docs. It also adds a test to ensure that we don't break this behavior again. * More docs --- bin/node/cli/tests/common.rs | 6 ++- .../cli/tests/remember_state_pruning_works.rs | 38 +++++++++++++++++ client/cli/src/params/pruning_params.rs | 41 +++++++++++++++---- 3 files changed, 75 insertions(+), 10 deletions(-) create mode 100644 bin/node/cli/tests/remember_state_pruning_works.rs diff --git a/bin/node/cli/tests/common.rs b/bin/node/cli/tests/common.rs index 358c09779d59a..c8f9e2b3d3c82 100644 --- a/bin/node/cli/tests/common.rs +++ b/bin/node/cli/tests/common.rs @@ -161,6 +161,7 @@ pub fn find_ws_url_from_output(read: impl Read + Send) -> (String, String) { let line = line.expect("failed to obtain next line from stdout for WS address discovery"); data.push_str(&line); + data.push_str("\n"); // 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=") { @@ -170,7 +171,10 @@ pub fn find_ws_url_from_output(read: impl Read + Send) -> (String, String) { Some(format!("ws://{}", sock_addr)) }) - .expect("We should get a WebSocket address"); + .unwrap_or_else(|| { + eprintln!("Observed node output:\n{}", data); + panic!("We should get a WebSocket address") + }); (ws_url, data) } diff --git a/bin/node/cli/tests/remember_state_pruning_works.rs b/bin/node/cli/tests/remember_state_pruning_works.rs new file mode 100644 index 0000000000000..5b8e34cc7a00d --- /dev/null +++ b/bin/node/cli/tests/remember_state_pruning_works.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 . + +use tempfile::tempdir; + +pub mod common; + +#[tokio::test] +#[cfg(unix)] +async fn remember_state_pruning_works() { + let base_path = tempdir().expect("could not create a temp dir"); + + // First run with `--state-pruning=archive`. + common::run_node_for_a_while( + base_path.path(), + &["--dev", "--state-pruning=archive", "--no-hardware-benchmarks"], + ) + .await; + + // Then run again without specifying the state pruning. + // This should load state pruning settings from the db. + common::run_node_for_a_while(base_path.path(), &["--dev", "--no-hardware-benchmarks"]).await; +} diff --git a/client/cli/src/params/pruning_params.rs b/client/cli/src/params/pruning_params.rs index 7e50f53d7169a..fd01ba67bab7d 100644 --- a/client/cli/src/params/pruning_params.rs +++ b/client/cli/src/params/pruning_params.rs @@ -28,21 +28,44 @@ pub struct PruningParams { /// This mode specifies when the block's state (ie, storage) /// should be pruned (ie, removed) from the database. /// + /// This setting can only be set on the first creation of the database. Every subsequent run + /// will load the pruning mode from the database and will error if the stored mode doesn't + /// match this CLI value. It is fine to drop this CLI flag for subsequent runs. + /// /// 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, + /// + /// - 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. + /// + /// [default: 256] + #[arg(alias = "pruning", long, value_name = "PRUNING_MODE")] + pub state_pruning: Option, /// Specify the blocks pruning mode. /// /// This mode specifies when the block's body (including justifications) /// should be pruned (ie, removed) from the database. /// /// Possible values: - /// 'archive' Keep all blocks. - /// 'archive-canonical' Keep only finalized blocks. - /// number Keep the last `number` of finalized blocks. + /// - 'archive' + /// + /// Keep all blocks. + /// + /// - 'archive-canonical' + /// + /// Keep only finalized blocks. + /// + /// - number + /// + /// Keep the last `number` of finalized blocks. #[arg( alias = "keep-blocks", long, @@ -55,7 +78,7 @@ pub struct PruningParams { impl PruningParams { /// Get the pruning value from the parameters pub fn state_pruning(&self) -> error::Result> { - Ok(Some(self.state_pruning.into())) + Ok(self.state_pruning.map(|v| v.into())) } /// Get the block pruning value from the parameters From 6fe8cd4ec19f7013b0ba2e790dce880ad07020b0 Mon Sep 17 00:00:00 2001 From: Dmitry Markin Date: Tue, 27 Dec 2022 13:05:12 +0300 Subject: [PATCH 231/715] Runtime diagnostics for leaked messages in unbounded channels (part 2) (#13020) * Fix code review issues * Clarify doc * Get rid of backtrace mutex * kick CI --- Cargo.lock | 64 +++++++++++++++++------- client/network/Cargo.toml | 1 + client/network/src/service/out_events.rs | 24 ++++----- client/utils/Cargo.toml | 1 + client/utils/src/mpsc.rs | 27 +++++----- 5 files changed, 69 insertions(+), 48 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 19abb44e5ff9c..c93a0b7fdd28a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -18,7 +18,16 @@ version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" dependencies = [ - "gimli", + "gimli 0.26.1", +] + +[[package]] +name = "addr2line" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" +dependencies = [ + "gimli 0.27.0", ] [[package]] @@ -316,16 +325,16 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "backtrace" -version = "0.3.64" +version = "0.3.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e121dee8023ce33ab248d9ce1493df03c3b38a659b240096fcbd7048ff9c31f" +checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca" dependencies = [ - "addr2line", + "addr2line 0.19.0", "cc", "cfg-if", "libc", - "miniz_oxide", - "object 0.27.1", + "miniz_oxide 0.6.2", + "object 0.30.0", "rustc-demangle", ] @@ -1017,7 +1026,7 @@ dependencies = [ "cranelift-codegen-shared", "cranelift-entity", "cranelift-isle", - "gimli", + "gimli 0.26.1", "log", "regalloc2", "smallvec", @@ -1820,7 +1829,7 @@ dependencies = [ "crc32fast", "libc", "libz-sys", - "miniz_oxide", + "miniz_oxide 0.4.4", ] [[package]] @@ -2445,6 +2454,12 @@ dependencies = [ "stable_deref_trait", ] +[[package]] +name = "gimli" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dec7af912d60cdbd3677c1af9352ebae6fb8394d165568a2234df0fa00f87793" + [[package]] name = "git2" version = "0.14.2" @@ -3877,6 +3892,15 @@ dependencies = [ "autocfg", ] +[[package]] +name = "miniz_oxide" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" +dependencies = [ + "adler", +] + [[package]] name = "mio" version = "0.8.4" @@ -4611,22 +4635,22 @@ dependencies = [ [[package]] name = "object" -version = "0.27.1" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67ac1d3f9a1d3616fd9a60c8d74296f22406a238b6a72f5cc1e6f314df4ffbf9" +checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53" dependencies = [ + "crc32fast", + "hashbrown 0.12.3", + "indexmap", "memchr", ] [[package]] name = "object" -version = "0.29.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53" +checksum = "239da7f290cfa979f43f85a8efeee9a8a76d0827c356d37f9d3d7254d6b537fb" dependencies = [ - "crc32fast", - "hashbrown 0.12.3", - "indexmap", "memchr", ] @@ -7756,6 +7780,7 @@ dependencies = [ "assert_matches", "async-trait", "asynchronous-codec", + "backtrace", "bytes", "either", "fnv", @@ -8403,6 +8428,7 @@ dependencies = [ name = "sc-utils" version = "4.0.0-dev" dependencies = [ + "backtrace", "futures", "futures-timer", "lazy_static", @@ -11142,7 +11168,7 @@ dependencies = [ "cranelift-frontend", "cranelift-native", "cranelift-wasm", - "gimli", + "gimli 0.26.1", "log", "object 0.29.0", "target-lexicon", @@ -11159,7 +11185,7 @@ checksum = "5c587c62e91c5499df62012b87b88890d0eb470b2ffecc5964e9da967b70c77c" dependencies = [ "anyhow", "cranelift-entity", - "gimli", + "gimli 0.26.1", "indexmap", "log", "object 0.29.0", @@ -11176,12 +11202,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "047839b5dabeae5424a078c19b8cc897e5943a7fadc69e3d888b9c9a897666b3" dependencies = [ - "addr2line", + "addr2line 0.17.0", "anyhow", "bincode", "cfg-if", "cpp_demangle", - "gimli", + "gimli 0.26.1", "log", "object 0.29.0", "rustc-demangle", diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index be9a74d2c1602..35d4253f6b37f 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -17,6 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] array-bytes = "4.1" async-trait = "0.1" asynchronous-codec = "0.6" +backtrace = "0.3.67" bytes = "1" codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } either = "1.5.3" diff --git a/client/network/src/service/out_events.rs b/client/network/src/service/out_events.rs index 8febdd4726b37..5e0c8ac6a1a40 100644 --- a/client/network/src/service/out_events.rs +++ b/client/network/src/service/out_events.rs @@ -31,13 +31,13 @@ //! - Send events by calling [`OutChannels::send`]. Events are cloned for each sender in the //! collection. +use backtrace::Backtrace; use futures::{channel::mpsc, prelude::*, ready, stream::FusedStream}; use log::error; use parking_lot::Mutex; use prometheus_endpoint::{register, CounterVec, GaugeVec, Opts, PrometheusError, Registry, U64}; use sc_network_common::protocol::event::Event; use std::{ - backtrace::{Backtrace, BacktraceStatus}, cell::RefCell, fmt, pin::Pin, @@ -62,7 +62,7 @@ pub fn channel(name: &'static str, queue_size_warning: i64) -> (Sender, Receiver queue_size: queue_size.clone(), queue_size_warning, warning_fired: false, - creation_backtrace: Backtrace::capture(), + creation_backtrace: Backtrace::new_unresolved(), metrics: metrics.clone(), }; let rx = Receiver { inner: rx, name, queue_size, metrics }; @@ -91,7 +91,8 @@ pub struct Sender { warning_fired: bool, /// Backtrace of a place where the channel was created. creation_backtrace: Backtrace, - /// Clone of [`Receiver::metrics`]. + /// Clone of [`Receiver::metrics`]. Will be initialized when [`Sender`] is added to + /// [`OutChannels`] with `OutChannels::push()`. metrics: Arc>>>>, } @@ -193,17 +194,12 @@ impl OutChannels { let queue_size = sender.queue_size.fetch_add(1, Ordering::Relaxed); if queue_size == sender.queue_size_warning && !sender.warning_fired { sender.warning_fired = true; - match sender.creation_backtrace.status() { - BacktraceStatus::Captured => error!( - "The number of unprocessed events in channel `{}` reached {}.\n\ - The channel was created at:\n{}", - sender.name, sender.queue_size_warning, sender.creation_backtrace, - ), - _ => error!( - "The number of unprocessed events in channel `{}` reached {}.", - sender.name, sender.queue_size_warning, - ), - } + sender.creation_backtrace.resolve(); + error!( + "The number of unprocessed events in channel `{}` reached {}.\n\ + The channel was created at:\n{:?}", + sender.name, sender.queue_size_warning, sender.creation_backtrace, + ); } sender.inner.unbounded_send(event.clone()).is_ok() }); diff --git a/client/utils/Cargo.toml b/client/utils/Cargo.toml index 082ac3b55e80d..e80588453597e 100644 --- a/client/utils/Cargo.toml +++ b/client/utils/Cargo.toml @@ -10,6 +10,7 @@ description = "I/O for Substrate runtimes" readme = "README.md" [dependencies] +backtrace = "0.3.67" futures = "0.3.21" futures-timer = "3.0.2" lazy_static = "1.4.0" diff --git a/client/utils/src/mpsc.rs b/client/utils/src/mpsc.rs index 7db5e49f5bca9..d74703c4abd08 100644 --- a/client/utils/src/mpsc.rs +++ b/client/utils/src/mpsc.rs @@ -37,6 +37,7 @@ mod inner { mod inner { // tracing implementation use crate::metrics::UNBOUNDED_CHANNELS_COUNTER; + use backtrace::Backtrace; use futures::{ channel::mpsc::{ self, SendError, TryRecvError, TrySendError, UnboundedReceiver, UnboundedSender, @@ -47,7 +48,6 @@ mod inner { }; use log::error; use std::{ - backtrace::{Backtrace, BacktraceStatus}, pin::Pin, sync::{ atomic::{AtomicBool, AtomicI64, Ordering}, @@ -108,7 +108,7 @@ mod inner { queue_size: queue_size.clone(), queue_size_warning, warning_fired: Arc::new(AtomicBool::new(false)), - creation_backtrace: Arc::new(Backtrace::capture()), + creation_backtrace: Arc::new(Backtrace::new_unresolved()), }; let receiver = TracingUnboundedReceiver { inner: r, name, queue_size }; (sender, receiver) @@ -149,23 +149,20 @@ mod inner { let queue_size = self.queue_size.fetch_add(1, Ordering::Relaxed); if queue_size == self.queue_size_warning && - !self.warning_fired.load(Ordering::Relaxed) + self.warning_fired + .compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed) + .is_ok() { // `warning_fired` and `queue_size` are not synchronized, so it's possible // that the warning is fired few times before the `warning_fired` is seen // by all threads. This seems better than introducing a mutex guarding them. - self.warning_fired.store(true, Ordering::Relaxed); - match self.creation_backtrace.status() { - BacktraceStatus::Captured => error!( - "The number of unprocessed messages in channel `{}` reached {}.\n\ - The channel was created at:\n{}", - self.name, self.queue_size_warning, self.creation_backtrace, - ), - _ => error!( - "The number of unprocessed messages in channel `{}` reached {}.", - self.name, self.queue_size_warning, - ), - } + let mut backtrace = (*self.creation_backtrace).clone(); + backtrace.resolve(); + error!( + "The number of unprocessed messages in channel `{}` reached {}.\n\ + The channel was created at:\n{:?}", + self.name, self.queue_size_warning, backtrace, + ); } s From 8d20ed51e4e4b420ba7ab2f498f6e49a5b93b915 Mon Sep 17 00:00:00 2001 From: Sasha Gryaznov Date: Tue, 27 Dec 2022 15:24:49 +0200 Subject: [PATCH 232/715] [contracts] Make debug buffer work like a FIFO pipe (#12953) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * make debug buffer work like a FIFO pipe * remove unused Error type * Remove panics * Update frame/contracts/src/exec.rs Co-authored-by: Sasha Gryaznov Co-authored-by: Alexander Theißen --- frame/contracts/src/exec.rs | 84 ++++++++++++++++------------- frame/contracts/src/lib.rs | 3 -- frame/contracts/src/wasm/mod.rs | 4 +- frame/contracts/src/wasm/runtime.rs | 4 +- 4 files changed, 52 insertions(+), 43 deletions(-) diff --git a/frame/contracts/src/exec.rs b/frame/contracts/src/exec.rs index f4dc3a0ec0250..df1dd24856a8a 100644 --- a/frame/contracts/src/exec.rs +++ b/frame/contracts/src/exec.rs @@ -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) -> Result; + fn append_debug_buffer(&mut self, msg: &str) -> bool; /// Call some dispatchable and return the result. fn call_runtime(&self, call: ::RuntimeCall) -> DispatchResultWithPostInfo; @@ -1334,16 +1334,34 @@ where &mut self.top_frame_mut().nested_gas } - fn append_debug_buffer(&mut self, msg: &str) -> Result { + fn append_debug_buffer(&mut self, msg: &str) -> bool { if let Some(buffer) = &mut self.debug_message { - if !msg.is_empty() { - buffer - .try_extend(&mut msg.bytes()) - .map_err(|_| Error::::DebugBufferExhausted)?; - } - Ok(true) + let mut msg = msg.bytes(); + let num_drain = { + let capacity = DebugBufferVec::::bound().checked_sub(buffer.len()).expect( + " + `buffer` is of type `DebugBufferVec`, + `DebugBufferVec` is a `BoundedVec`, + `BoundedVec::len()` <= `BoundedVec::bound()`; + qed + ", + ); + msg.len().saturating_sub(capacity).min(buffer.len()) + }; + buffer.drain(0..num_drain); + buffer + .try_extend(&mut msg) + .map_err(|_| { + log::debug!( + target: "runtime::contracts", + "Debug message to big (size={}) for debug buffer (bound={})", + msg.len(), DebugBufferVec::::bound(), + ); + }) + .ok(); + true } else { - Ok(false) + false } } @@ -2511,12 +2529,8 @@ mod tests { #[test] fn printing_works() { let code_hash = MockLoader::insert(Call, |ctx, _| { - 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!"); + ctx.ext.append_debug_buffer("This is a test"); + ctx.ext.append_debug_buffer("More text"); exec_success() }); @@ -2549,12 +2563,8 @@ mod tests { #[test] fn printing_works_on_fail() { let code_hash = MockLoader::insert(Call, |ctx, _| { - 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!"); + ctx.ext.append_debug_buffer("This is a test"); + ctx.ext.append_debug_buffer("More text"); exec_trapped() }); @@ -2587,7 +2597,7 @@ mod tests { #[test] fn debug_buffer_is_limited() { let code_hash = MockLoader::insert(Call, move |ctx, _| { - ctx.ext.append_debug_buffer("overflowing bytes")?; + ctx.ext.append_debug_buffer("overflowing bytes"); exec_success() }); @@ -2602,20 +2612,22 @@ mod tests { 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 + MockStack::run_call( + ALICE, + BOB, + &mut gas_meter, + &mut storage_meter, + &schedule, + 0, + vec![], + Some(&mut debug_buffer), + Determinism::Deterministic, + ) + .unwrap(); + assert_eq!( + &String::from_utf8(debug_buffer[DebugBufferVec::::bound() - 17..].to_vec()) + .unwrap(), + "overflowing bytes" ); }); } diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index 39626e43f4653..778ceec961500 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -857,9 +857,6 @@ 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. diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index 903ca0abb5e06..553bae59e78b9 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -588,9 +588,9 @@ mod tests { fn gas_meter(&mut self) -> &mut GasMeter { &mut self.gas_meter } - fn append_debug_buffer(&mut self, msg: &str) -> Result { + fn append_debug_buffer(&mut self, msg: &str) -> bool { self.debug_buffer.extend(msg.as_bytes()); - Ok(true) + true } fn call_runtime( &self, diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index aaacb9e5f80e6..7d67adc3ded33 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -2380,11 +2380,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) From d2ef4b061f3802d7aa4254d6ce1f15b261a0fa61 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Tue, 27 Dec 2022 14:48:17 +0100 Subject: [PATCH 233/715] Improve inactive fund tracking (#13009) * Improve inactive fund tracking * Resetting migration * Fix * Update frame/balances/src/migration.rs --- bin/node/executor/tests/basic.rs | 11 ++++++++++- frame/balances/src/migration.rs | 26 ++++++++++++++++++++++++++ frame/treasury/src/lib.rs | 19 ++++++++++++------- 3 files changed, 48 insertions(+), 8 deletions(-) diff --git a/bin/node/executor/tests/basic.rs b/bin/node/executor/tests/basic.rs index c88703b929e6b..02b2a8787b5d5 100644 --- a/bin/node/executor/tests/basic.rs +++ b/bin/node/executor/tests/basic.rs @@ -30,7 +30,7 @@ use sp_runtime::{ use kitchensink_runtime::{ constants::{currency::*, time::SLOT_DURATION}, Balances, CheckedExtrinsic, Header, Runtime, RuntimeCall, RuntimeEvent, System, - TransactionPayment, UncheckedExtrinsic, + TransactionPayment, Treasury, UncheckedExtrinsic, }; use node_primitives::{Balance, Hash}; use node_testing::keyring::*; @@ -398,6 +398,7 @@ fn full_native_block_import_works() { }); fees = t.execute_with(|| transfer_fee(&xt())); + let pot = t.execute_with(|| Treasury::pot()); executor_call(&mut t, "Core_execute_block", &block2.0, true).0.unwrap(); @@ -408,6 +409,14 @@ fn full_native_block_import_works() { ); assert_eq!(Balances::total_balance(&bob()), 179 * DOLLARS - fees); let events = vec![ + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Treasury(pallet_treasury::Event::UpdatedInactive { + reactivated: 0, + deactivated: pot, + }), + topics: vec![], + }, EventRecord { phase: Phase::ApplyExtrinsic(0), event: RuntimeEvent::System(frame_system::Event::ExtrinsicSuccess { diff --git a/frame/balances/src/migration.rs b/frame/balances/src/migration.rs index 08e1d8c7a2c74..b660ec9fd3235 100644 --- a/frame/balances/src/migration.rs +++ b/frame/balances/src/migration.rs @@ -69,3 +69,29 @@ impl, A: Get>, I: 'static> OnRuntimeUpgrade migrate_v0_to_v1::(&A::get()) } } + +pub struct ResetInactive(PhantomData<(T, I)>); +impl, I: 'static> OnRuntimeUpgrade for ResetInactive { + fn on_runtime_upgrade() -> Weight { + let onchain_version = Pallet::::on_chain_storage_version(); + + if onchain_version == 1 { + // Remove the old `StorageVersion` type. + frame_support::storage::unhashed::kill(&frame_support::storage::storage_prefix( + Pallet::::name().as_bytes(), + "StorageVersion".as_bytes(), + )); + + InactiveIssuance::::kill(); + + // Set storage version to `0`. + StorageVersion::new(0).put::>(); + + log::info!(target: "runtime::balances", "Storage to version 0"); + T::DbWeight::get().reads_writes(1, 2) + } else { + log::info!(target: "runtime::balances", "Migration did not execute. This probably should be removed"); + T::DbWeight::get().reads(1) + } + } +} diff --git a/frame/treasury/src/lib.rs b/frame/treasury/src/lib.rs index 0ffc53d8b7978..1bde1238191a4 100644 --- a/frame/treasury/src/lib.rs +++ b/frame/treasury/src/lib.rs @@ -225,7 +225,8 @@ pub mod pallet { /// The amount which has been reported as inactive to Currency. #[pallet::storage] - pub type Inactive, I: 'static = ()> = StorageValue<_, BalanceOf, ValueQuery>; + pub type Deactivated, I: 'static = ()> = + StorageValue<_, BalanceOf, ValueQuery>; /// Proposal indices that have been approved but not yet awarded. #[pallet::storage] @@ -292,6 +293,8 @@ pub mod pallet { amount: BalanceOf, beneficiary: T::AccountId, }, + /// The inactive funds of the pallet have been updated. + UpdatedInactive { reactivated: BalanceOf, deactivated: BalanceOf }, } /// Error for the treasury pallet. @@ -321,13 +324,15 @@ pub mod pallet { /// # fn on_initialize(n: T::BlockNumber) -> Weight { let pot = Self::pot(); - let deactivated = Inactive::::get(); + let deactivated = Deactivated::::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); + T::Currency::reactivate(deactivated); + T::Currency::deactivate(pot); + Deactivated::::put(&pot); + Self::deposit_event(Event::::UpdatedInactive { + reactivated: deactivated, + deactivated: pot, + }); } // Check to see if we should spend some funds! From 891d6a5c870ab88521183facafc811a203bb6541 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 28 Dec 2022 09:16:52 +0100 Subject: [PATCH 234/715] Print "stalled" task on shutdown (#13022) * Print "stalled" task on shutdown When the node is shutting down, we give the Tokio runtime 60 seconds to shutdown. If after these 60 seconds there are still running tasks, we now print these tasks. This should help debugging nodes that have stalled tasks. This pr introduces a `TaskRegistry` that keeps track of all running tasks. Each task registers and unregisters itself in this `TaskRegistry`. * Fix rustdoc * Update client/service/src/lib.rs --- Cargo.lock | 1 + client/cli/Cargo.toml | 1 + client/cli/src/runner.rs | 117 ++++++++++++++++++++----- client/service/src/lib.rs | 2 +- client/service/src/task_manager/mod.rs | 98 ++++++++++++++++++++- 5 files changed, 193 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c93a0b7fdd28a..b2aca09fe2564 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7280,6 +7280,7 @@ dependencies = [ "sp-keystore", "sp-panic-handler", "sp-runtime", + "sp-tracing", "sp-version", "tempfile", "thiserror", diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index a5de78da487c8..ee4426b91dbb8 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -50,6 +50,7 @@ sp-version = { version = "5.0.0", path = "../../primitives/version" } [dev-dependencies] tempfile = "3.1.0" futures-timer = "3.0.1" +sp-tracing = { version = "6.0.0", path = "../../primitives/tracing" } [features] default = ["rocksdb"] diff --git a/client/cli/src/runner.rs b/client/cli/src/runner.rs index d4191feddfa90..1a532b3bbc6fb 100644 --- a/client/cli/src/runner.rs +++ b/client/cli/src/runner.rs @@ -152,10 +152,38 @@ impl Runner { // // 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); + let task_registry = task_manager.into_task_registry(); // Give all futures 60 seconds to shutdown, before tokio "leaks" them. - self.tokio_runtime.shutdown_timeout(Duration::from_secs(60)); + let shutdown_timeout = Duration::from_secs(60); + self.tokio_runtime.shutdown_timeout(shutdown_timeout); + + let running_tasks = task_registry.running_tasks(); + + if !running_tasks.is_empty() { + log::error!("Detected running(potentially stalled) tasks on shutdown:"); + running_tasks.iter().for_each(|(task, count)| { + let instances_desc = + if *count > 1 { format!("with {} instances ", count) } else { "".to_string() }; + + if task.is_default_group() { + log::error!( + "Task \"{}\" was still running {}after waiting {} seconds to finish.", + task.name, + instances_desc, + shutdown_timeout.as_secs(), + ); + } else { + log::error!( + "Task \"{}\" (Group: {}) was still running {}after waiting {} seconds to finish.", + task.name, + task.group, + instances_desc, + shutdown_timeout.as_secs(), + ); + } + }); + } res.map_err(Into::into) } @@ -388,34 +416,75 @@ mod tests { assert!((count as u128) < (Duration::from_secs(30).as_millis() / 50)); } + 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) + } + } + /// 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(); + let output = run_test_in_another_process( + "ensure_run_until_exit_is_not_blocking_indefinitely", + || { + sp_tracing::try_init_simple(); + + 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(); + }, + ); - 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(); + let Some(output) = output else { return } ; - // 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; - }); + let stderr = dbg!(String::from_utf8(output.stderr).unwrap()); - Ok::<_, sc_service::Error>(task_manager) - }) - .unwrap_err(); + assert!( + stderr.contains("Task \"test\" was still running after waiting 60 seconds to finish.") + ); + assert!(!stderr + .contains("Task \"test2\" was still running after waiting 60 seconds to finish.")); } } diff --git a/client/service/src/lib.rs b/client/service/src/lib.rs index 8b3a29ba4032a..1529b822ade32 100644 --- a/client/service/src/lib.rs +++ b/client/service/src/lib.rs @@ -83,7 +83,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, DEFAULT_GROUP_NAME}; +pub use task_manager::{SpawnTaskHandle, Task, TaskManager, TaskRegistry, 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 23265f9672555..d792122576444 100644 --- a/client/service/src/task_manager/mod.rs +++ b/client/service/src/task_manager/mod.rs @@ -24,12 +24,19 @@ use futures::{ future::{pending, select, try_join_all, BoxFuture, Either}, Future, FutureExt, StreamExt, }; +use parking_lot::Mutex; 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 std::{ + collections::{hash_map::Entry, HashMap}, + panic, + pin::Pin, + result::Result, + sync::Arc, +}; use tokio::runtime::Handle; use tracing_futures::Instrument; @@ -72,6 +79,7 @@ pub struct SpawnTaskHandle { on_exit: exit_future::Exit, tokio_handle: Handle, metrics: Option, + task_registry: TaskRegistry, } impl SpawnTaskHandle { @@ -113,6 +121,7 @@ impl SpawnTaskHandle { ) { let on_exit = self.on_exit.clone(); let metrics = self.metrics.clone(); + let registry = self.task_registry.clone(); let group = match group.into() { GroupName::Specific(var) => var, @@ -129,6 +138,10 @@ impl SpawnTaskHandle { } let future = async move { + // Register the task and keep the "token" alive until the task is ended. Then this + // "token" will unregister this task. + let _registry_token = registry.register_task(name, group); + if let Some(metrics) = metrics { // Add some wrappers around `task`. let task = { @@ -298,6 +311,8 @@ pub struct TaskManager { /// terminates and gracefully shutdown. Also ends the parent `future()` if a child's essential /// task fails. children: Vec, + /// The registry of all running tasks. + task_registry: TaskRegistry, } impl TaskManager { @@ -324,6 +339,7 @@ impl TaskManager { essential_failed_rx, keep_alive: Box::new(()), children: Vec::new(), + task_registry: Default::default(), }) } @@ -333,6 +349,7 @@ impl TaskManager { on_exit: self.on_exit.clone(), tokio_handle: self.tokio_handle.clone(), metrics: self.metrics.clone(), + task_registry: self.task_registry.clone(), } } @@ -385,6 +402,14 @@ impl TaskManager { pub fn add_child(&mut self, child: TaskManager) { self.children.push(child); } + + /// Consume `self` and return the [`TaskRegistry`]. + /// + /// This [`TaskRegistry`] can be used to check for still running tasks after this task manager + /// was dropped. + pub fn into_task_registry(self) -> TaskRegistry { + self.task_registry + } } #[derive(Clone)] @@ -434,3 +459,74 @@ impl Metrics { }) } } + +/// Ensures that a [`Task`] is unregistered when this object is dropped. +struct UnregisterOnDrop { + task: Task, + registry: TaskRegistry, +} + +impl Drop for UnregisterOnDrop { + fn drop(&mut self) { + let mut tasks = self.registry.tasks.lock(); + + if let Entry::Occupied(mut entry) = (*tasks).entry(self.task.clone()) { + *entry.get_mut() -= 1; + + if *entry.get() == 0 { + entry.remove(); + } + } + } +} + +/// Represents a running async task in the [`TaskManager`]. +/// +/// As a task is identified by a name and a group, it is totally valid that there exists multiple +/// tasks with the same name and group. +#[derive(Clone, Hash, Eq, PartialEq)] +pub struct Task { + /// The name of the task. + pub name: &'static str, + /// The group this task is associated to. + pub group: &'static str, +} + +impl Task { + /// Returns if the `group` is the [`DEFAULT_GROUP_NAME`]. + pub fn is_default_group(&self) -> bool { + self.group == DEFAULT_GROUP_NAME + } +} + +/// Keeps track of all running [`Task`]s in [`TaskManager`]. +#[derive(Clone, Default)] +pub struct TaskRegistry { + tasks: Arc>>, +} + +impl TaskRegistry { + /// Register a task with the given `name` and `group`. + /// + /// Returns [`UnregisterOnDrop`] that ensures that the task is unregistered when this value is + /// dropped. + fn register_task(&self, name: &'static str, group: &'static str) -> UnregisterOnDrop { + let task = Task { name, group }; + + { + let mut tasks = self.tasks.lock(); + + *(*tasks).entry(task.clone()).or_default() += 1; + } + + UnregisterOnDrop { task, registry: self.clone() } + } + + /// Returns the running tasks. + /// + /// As a task is only identified by its `name` and `group`, there can be duplicate tasks. The + /// number per task represents the concurrently running tasks with the same identifier. + pub fn running_tasks(&self) -> HashMap { + (*self.tasks.lock()).clone() + } +} From 043a60b0f25c7b2abfcb213fa0af6fef946198c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Enrique=20Mu=C3=B1oz=20Mart=C3=ADn?= Date: Wed, 28 Dec 2022 13:52:15 +0100 Subject: [PATCH 235/715] Add ensure-ops family methods (#12967) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add ensure-ops family methods * fix cargo doc * add EnsureOp and EnsureOpAssign meta traits * move ensure module and ArithmeticError to sp-arithmetic * fix doc examples * reexport ensure module content * ensure mod private * reexport to sp-runtime * fix doc example * remove into(). in doc examples, minor doc changes * remove return value from assign methods * Update primitives/arithmetic/src/traits.rs Co-authored-by: Bastian Köcher * Update primitives/arithmetic/src/traits.rs Co-authored-by: Bastian Köcher * Update primitives/arithmetic/src/traits.rs Co-authored-by: Bastian Köcher * Update primitives/arithmetic/src/traits.rs Co-authored-by: Bastian Köcher * Update primitives/arithmetic/src/traits.rs Co-authored-by: Bastian Köcher * Update primitives/arithmetic/src/traits.rs Co-authored-by: Bastian Köcher * Update primitives/arithmetic/src/traits.rs Co-authored-by: Bastian Köcher * Update primitives/arithmetic/src/traits.rs Co-authored-by: Bastian Köcher * Update primitives/arithmetic/src/traits.rs Co-authored-by: Bastian Köcher * Update primitives/arithmetic/src/traits.rs Co-authored-by: Bastian Köcher * Update primitives/arithmetic/src/traits.rs Co-authored-by: Bastian Köcher * Update primitives/arithmetic/src/traits.rs Co-authored-by: Bastian Köcher * Update primitives/arithmetic/src/traits.rs Co-authored-by: Bastian Köcher * Update primitives/arithmetic/src/traits.rs Co-authored-by: Bastian Köcher * Update primitives/arithmetic/src/traits.rs Co-authored-by: Bastian Köcher * Update primitives/arithmetic/src/traits.rs Co-authored-by: Bastian Köcher * Update primitives/arithmetic/src/traits.rs Co-authored-by: Bastian Köcher * Update primitives/arithmetic/src/traits.rs Co-authored-by: Bastian Köcher * Update primitives/arithmetic/src/traits.rs Co-authored-by: Bastian Köcher * Update primitives/arithmetic/src/traits.rs Co-authored-by: Bastian Köcher * Update primitives/arithmetic/src/traits.rs Co-authored-by: Bastian Köcher * Update primitives/arithmetic/src/traits.rs Co-authored-by: Bastian Köcher * Update primitives/arithmetic/src/traits.rs Co-authored-by: Bastian Köcher * Update primitives/arithmetic/src/traits.rs Co-authored-by: Bastian Köcher * Update primitives/arithmetic/src/traits.rs Co-authored-by: Bastian Köcher * Update primitives/arithmetic/src/traits.rs Co-authored-by: Bastian Köcher * Update primitives/arithmetic/src/traits.rs Co-authored-by: Bastian Köcher * Update primitives/arithmetic/src/traits.rs Co-authored-by: Bastian Köcher * Update primitives/arithmetic/src/traits.rs Co-authored-by: Bastian Köcher * cargo fmt * Apply suggestions from code review * ".git/.scripts/fmt.sh" 1 Co-authored-by: Bastian Köcher Co-authored-by: command-bot <> --- primitives/arithmetic/src/lib.rs | 28 ++ primitives/arithmetic/src/traits.rs | 529 ++++++++++++++++++++++++++++ primitives/runtime/src/lib.rs | 28 +- primitives/runtime/src/traits.rs | 6 +- 4 files changed, 564 insertions(+), 27 deletions(-) diff --git a/primitives/arithmetic/src/lib.rs b/primitives/arithmetic/src/lib.rs index d7b326164b7d3..f1f8fc8b59830 100644 --- a/primitives/arithmetic/src/lib.rs +++ b/primitives/arithmetic/src/lib.rs @@ -50,6 +50,34 @@ pub use rational::{Rational128, RationalInfinite}; use sp_std::{cmp::Ordering, fmt::Debug, prelude::*}; use traits::{BaseArithmetic, One, SaturatedConversion, Unsigned, Zero}; +use codec::{Decode, Encode}; +use scale_info::TypeInfo; + +#[cfg(feature = "std")] +use serde::{Deserialize, Serialize}; + +/// Arithmetic errors. +#[derive(Eq, PartialEq, Clone, Copy, Encode, Decode, Debug, TypeInfo)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub enum ArithmeticError { + /// Underflow. + Underflow, + /// Overflow. + Overflow, + /// Division by zero. + DivisionByZero, +} + +impl From for &'static str { + fn from(e: ArithmeticError) -> &'static str { + match e { + ArithmeticError::Underflow => "An underflow would occur", + ArithmeticError::Overflow => "An overflow would occur", + ArithmeticError::DivisionByZero => "Division by zero", + } + } +} + /// Trait for comparing two numbers with an threshold. /// /// Returns: diff --git a/primitives/arithmetic/src/traits.rs b/primitives/arithmetic/src/traits.rs index 466d5696c7136..7fa64d28669d4 100644 --- a/primitives/arithmetic/src/traits.rs +++ b/primitives/arithmetic/src/traits.rs @@ -18,6 +18,11 @@ //! Primitive traits for the runtime arithmetic. use codec::HasCompact; +pub use ensure::{ + Ensure, EnsureAdd, EnsureAddAssign, EnsureDiv, EnsureDivAssign, EnsureFixedPointNumber, + EnsureFrom, EnsureInto, EnsureMul, EnsureMulAssign, EnsureOp, EnsureOpAssign, EnsureSub, + EnsureSubAssign, +}; pub use integer_sqrt::IntegerSquareRoot; pub use num_traits::{ checked_pow, Bounded, CheckedAdd, CheckedDiv, CheckedMul, CheckedNeg, CheckedRem, CheckedShl, @@ -302,3 +307,527 @@ pub trait SaturatedConversion { } } impl SaturatedConversion for T {} + +/// Arithmetic operations with safe error handling. +/// +/// This module provide a readable way to do safe arithmetics, turning this: +/// +/// ``` +/// # use sp_arithmetic::{traits::EnsureSub, ArithmeticError}; +/// # fn foo() -> Result<(), ArithmeticError> { +/// # let mut my_value: i32 = 1; +/// # let other_value: i32 = 1; +/// my_value = my_value.checked_sub(other_value).ok_or(ArithmeticError::Overflow)?; +/// # Ok(()) +/// # } +/// ``` +/// +/// into this: +/// +/// ``` +/// # use sp_arithmetic::{traits::EnsureSubAssign, ArithmeticError}; +/// # fn foo() -> Result<(), ArithmeticError> { +/// # let mut my_value: i32 = 1; +/// # let other_value: i32 = 1; +/// my_value.ensure_sub_assign(other_value)?; +/// # Ok(()) +/// # } +/// ``` +/// +/// choosing the correct [`ArithmeticError`](crate::ArithmeticError) it should return in case of +/// fail. +/// +/// The *EnsureOps* family functions follows the same behavior as *CheckedOps* but +/// returning an [`ArithmeticError`](crate::ArithmeticError) instead of `None`. +mod ensure { + use super::{CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, Zero}; + use crate::{ArithmeticError, FixedPointNumber, FixedPointOperand}; + + /// Performs addition that returns [`ArithmeticError`] instead of wrapping around on overflow. + pub trait EnsureAdd: CheckedAdd + PartialOrd + Zero + Copy { + /// Adds two numbers, checking for overflow. + /// + /// If it fails, [`ArithmeticError`] is returned. + /// + /// Similar to [`CheckedAdd::checked_add()`] but returning an [`ArithmeticError`] error. + /// + /// ``` + /// use sp_arithmetic::{traits::EnsureAdd, ArithmeticError}; + /// + /// fn overflow() -> Result<(), ArithmeticError> { + /// u32::MAX.ensure_add(1)?; + /// Ok(()) + /// } + /// + /// fn underflow() -> Result<(), ArithmeticError> { + /// i32::MIN.ensure_add(-1)?; + /// Ok(()) + /// } + /// + /// assert_eq!(overflow(), Err(ArithmeticError::Overflow)); + /// assert_eq!(underflow(), Err(ArithmeticError::Underflow)); + /// ``` + fn ensure_add(self, v: Self) -> Result { + self.checked_add(&v).ok_or_else(|| error::equivalent(v)) + } + } + + /// Performs subtraction that returns [`ArithmeticError`] instead of wrapping around on + /// underflow. + pub trait EnsureSub: CheckedSub + PartialOrd + Zero + Copy { + /// Subtracts two numbers, checking for overflow. + /// + /// If it fails, [`ArithmeticError`] is returned. + /// + /// Similar to [`CheckedSub::checked_sub()`] but returning an [`ArithmeticError`] error. + /// + /// ``` + /// use sp_arithmetic::{traits::EnsureSub, ArithmeticError}; + /// + /// fn underflow() -> Result<(), ArithmeticError> { + /// 0u32.ensure_sub(1)?; + /// Ok(()) + /// } + /// + /// fn overflow() -> Result<(), ArithmeticError> { + /// i32::MAX.ensure_sub(-1)?; + /// Ok(()) + /// } + /// + /// assert_eq!(underflow(), Err(ArithmeticError::Underflow)); + /// assert_eq!(overflow(), Err(ArithmeticError::Overflow)); + /// ``` + fn ensure_sub(self, v: Self) -> Result { + self.checked_sub(&v).ok_or_else(|| error::inverse(v)) + } + } + + /// Performs multiplication that returns [`ArithmeticError`] instead of wrapping around on + /// overflow. + pub trait EnsureMul: CheckedMul + PartialOrd + Zero + Copy { + /// Multiplies two numbers, checking for overflow. + /// + /// If it fails, [`ArithmeticError`] is returned. + /// + /// Similar to [`CheckedMul::checked_mul()`] but returning an [`ArithmeticError`] error. + /// + /// ``` + /// use sp_arithmetic::{traits::EnsureMul, ArithmeticError}; + /// + /// fn overflow() -> Result<(), ArithmeticError> { + /// u32::MAX.ensure_mul(2)?; + /// Ok(()) + /// } + /// + /// fn underflow() -> Result<(), ArithmeticError> { + /// i32::MAX.ensure_mul(-2)?; + /// Ok(()) + /// } + /// + /// assert_eq!(overflow(), Err(ArithmeticError::Overflow)); + /// assert_eq!(underflow(), Err(ArithmeticError::Underflow)); + /// ``` + fn ensure_mul(self, v: Self) -> Result { + self.checked_mul(&v).ok_or_else(|| error::multiplication(self, v)) + } + } + + /// Performs division that returns [`ArithmeticError`] instead of wrapping around on overflow. + pub trait EnsureDiv: CheckedDiv + PartialOrd + Zero + Copy { + /// Divides two numbers, checking for overflow. + /// + /// If it fails, [`ArithmeticError`] is returned. + /// + /// Similar to [`CheckedDiv::checked_div()`] but returning an [`ArithmeticError`] error. + /// + /// ``` + /// use sp_arithmetic::{traits::EnsureDiv, ArithmeticError}; + /// + /// fn extrinsic_zero() -> Result<(), ArithmeticError> { + /// 1.ensure_div(0)?; + /// Ok(()) + /// } + /// + /// fn overflow() -> Result<(), ArithmeticError> { + /// i64::MIN.ensure_div(-1)?; + /// Ok(()) + /// } + /// + /// assert_eq!(extrinsic_zero(), Err(ArithmeticError::DivisionByZero)); + /// assert_eq!(overflow(), Err(ArithmeticError::Overflow)); + /// ``` + fn ensure_div(self, v: Self) -> Result { + self.checked_div(&v).ok_or_else(|| error::division(self, v)) + } + } + + impl EnsureAdd for T {} + impl EnsureSub for T {} + impl EnsureMul for T {} + impl EnsureDiv for T {} + + /// Meta trait that supports all immutable arithmetic `Ensure*` operations + pub trait EnsureOp: EnsureAdd + EnsureSub + EnsureMul + EnsureDiv {} + impl EnsureOp for T {} + + /// Performs self addition that returns [`ArithmeticError`] instead of wrapping around on + /// overflow. + pub trait EnsureAddAssign: EnsureAdd { + /// Adds two numbers overwriting the left hand one, checking for overflow. + /// + /// If it fails, [`ArithmeticError`] is returned. + /// + /// ``` + /// use sp_arithmetic::{traits::EnsureAddAssign, ArithmeticError}; + /// + /// fn overflow() -> Result<(), ArithmeticError> { + /// let mut max = u32::MAX; + /// max.ensure_add_assign(1)?; + /// Ok(()) + /// } + /// + /// fn underflow() -> Result<(), ArithmeticError> { + /// let mut max = i32::MIN; + /// max.ensure_add_assign(-1)?; + /// Ok(()) + /// } + /// + /// assert_eq!(overflow(), Err(ArithmeticError::Overflow)); + /// assert_eq!(underflow(), Err(ArithmeticError::Underflow)); + /// ``` + fn ensure_add_assign(&mut self, v: Self) -> Result<(), ArithmeticError> { + *self = self.ensure_add(v)?; + Ok(()) + } + } + + /// Performs self subtraction that returns [`ArithmeticError`] instead of wrapping around on + /// underflow. + pub trait EnsureSubAssign: EnsureSub { + /// Subtracts two numbers overwriting the left hand one, checking for overflow. + /// + /// If it fails, [`ArithmeticError`] is returned. + /// + /// ``` + /// use sp_arithmetic::{traits::EnsureSubAssign, ArithmeticError}; + /// + /// fn underflow() -> Result<(), ArithmeticError> { + /// let mut zero: u32 = 0; + /// zero.ensure_sub_assign(1)?; + /// Ok(()) + /// } + /// + /// fn overflow() -> Result<(), ArithmeticError> { + /// let mut zero = i32::MAX; + /// zero.ensure_sub_assign(-1)?; + /// Ok(()) + /// } + /// + /// assert_eq!(underflow(), Err(ArithmeticError::Underflow)); + /// assert_eq!(overflow(), Err(ArithmeticError::Overflow)); + /// ``` + fn ensure_sub_assign(&mut self, v: Self) -> Result<(), ArithmeticError> { + *self = self.ensure_sub(v)?; + Ok(()) + } + } + + /// Performs self multiplication that returns [`ArithmeticError`] instead of wrapping around on + /// overflow. + pub trait EnsureMulAssign: EnsureMul { + /// Multiplies two numbers overwriting the left hand one, checking for overflow. + /// + /// If it fails, [`ArithmeticError`] is returned. + /// + /// ``` + /// use sp_arithmetic::{traits::EnsureMulAssign, ArithmeticError}; + /// + /// fn overflow() -> Result<(), ArithmeticError> { + /// let mut max = u32::MAX; + /// max.ensure_mul_assign(2)?; + /// Ok(()) + /// } + /// + /// fn underflow() -> Result<(), ArithmeticError> { + /// let mut max = i32::MAX; + /// max.ensure_mul_assign(-2)?; + /// Ok(()) + /// } + /// + /// assert_eq!(overflow(), Err(ArithmeticError::Overflow)); + /// assert_eq!(underflow(), Err(ArithmeticError::Underflow)); + /// ``` + fn ensure_mul_assign(&mut self, v: Self) -> Result<(), ArithmeticError> { + *self = self.ensure_mul(v)?; + Ok(()) + } + } + + /// Performs self division that returns [`ArithmeticError`] instead of wrapping around on + /// overflow. + pub trait EnsureDivAssign: EnsureDiv { + /// Divides two numbers overwriting the left hand one, checking for overflow. + /// + /// If it fails, [`ArithmeticError`] is returned. + /// + /// ``` + /// use sp_arithmetic::{traits::EnsureDivAssign, ArithmeticError, FixedI64}; + /// + /// fn extrinsic_zero() -> Result<(), ArithmeticError> { + /// let mut one = 1; + /// one.ensure_div_assign(0)?; + /// Ok(()) + /// } + /// + /// fn overflow() -> Result<(), ArithmeticError> { + /// let mut min = FixedI64::from(i64::MIN); + /// min.ensure_div_assign(FixedI64::from(-1))?; + /// Ok(()) + /// } + /// + /// assert_eq!(extrinsic_zero(), Err(ArithmeticError::DivisionByZero)); + /// assert_eq!(overflow(), Err(ArithmeticError::Overflow)); + /// ``` + fn ensure_div_assign(&mut self, v: Self) -> Result<(), ArithmeticError> { + *self = self.ensure_div(v)?; + Ok(()) + } + } + + impl EnsureAddAssign for T {} + impl EnsureSubAssign for T {} + impl EnsureMulAssign for T {} + impl EnsureDivAssign for T {} + + /// Meta trait that supports all assigned arithmetic `Ensure*` operations + pub trait EnsureOpAssign: + EnsureAddAssign + EnsureSubAssign + EnsureMulAssign + EnsureDivAssign + { + } + impl EnsureOpAssign + for T + { + } + + /// Meta trait that supports all arithmetic operations + pub trait Ensure: EnsureOp + EnsureOpAssign {} + impl Ensure for T {} + + /// Extends [`FixedPointNumber`] with the Ensure family functions. + pub trait EnsureFixedPointNumber: FixedPointNumber { + /// Creates `self` from a rational number. Equal to `n / d`. + /// + /// Returns [`ArithmeticError`] if `d == 0` or `n / d` exceeds accuracy. + /// + /// Similar to [`FixedPointNumber::checked_from_rational()`] but returning an + /// [`ArithmeticError`] error. + /// + /// ``` + /// use sp_arithmetic::{traits::EnsureFixedPointNumber, ArithmeticError, FixedI64}; + /// + /// fn extrinsic_zero() -> Result<(), ArithmeticError> { + /// FixedI64::ensure_from_rational(1, 0)?; + /// Ok(()) + /// } + /// + /// fn underflow() -> Result<(), ArithmeticError> { + /// FixedI64::ensure_from_rational(i64::MAX, -1)?; + /// Ok(()) + /// } + /// + /// assert_eq!(extrinsic_zero(), Err(ArithmeticError::DivisionByZero)); + /// assert_eq!(underflow(), Err(ArithmeticError::Underflow)); + /// ``` + fn ensure_from_rational( + n: N, + d: D, + ) -> Result { + ::checked_from_rational(n, d) + .ok_or_else(|| error::division(n, d)) + } + + /// Ensure multiplication for integer type `N`. Equal to `self * n`. + /// + /// Returns [`ArithmeticError`] if the result does not fit in `N`. + /// + /// Similar to [`FixedPointNumber::checked_mul_int()`] but returning an [`ArithmeticError`] + /// error. + /// + /// ``` + /// use sp_arithmetic::{traits::EnsureFixedPointNumber, ArithmeticError, FixedI64}; + /// + /// fn overflow() -> Result<(), ArithmeticError> { + /// FixedI64::from(i64::MAX).ensure_mul_int(2)?; + /// Ok(()) + /// } + /// + /// fn underflow() -> Result<(), ArithmeticError> { + /// FixedI64::from(i64::MAX).ensure_mul_int(-2)?; + /// Ok(()) + /// } + /// + /// assert_eq!(overflow(), Err(ArithmeticError::Overflow)); + /// assert_eq!(underflow(), Err(ArithmeticError::Underflow)); + /// ``` + fn ensure_mul_int(self, n: N) -> Result { + self.checked_mul_int(n).ok_or_else(|| error::multiplication(self, n)) + } + + /// Ensure division for integer type `N`. Equal to `self / d`. + /// + /// Returns [`ArithmeticError`] if the result does not fit in `N` or `d == 0`. + /// + /// Similar to [`FixedPointNumber::checked_div_int()`] but returning an [`ArithmeticError`] + /// error. + /// + /// ``` + /// use sp_arithmetic::{traits::EnsureFixedPointNumber, ArithmeticError, FixedI64}; + /// + /// fn extrinsic_zero() -> Result<(), ArithmeticError> { + /// FixedI64::from(1).ensure_div_int(0)?; + /// Ok(()) + /// } + /// + /// fn overflow() -> Result<(), ArithmeticError> { + /// FixedI64::from(i64::MIN).ensure_div_int(-1)?; + /// Ok(()) + /// } + /// + /// assert_eq!(extrinsic_zero(), Err(ArithmeticError::DivisionByZero)); + /// assert_eq!(overflow(), Err(ArithmeticError::Overflow)); + /// ``` + fn ensure_div_int(self, d: D) -> Result { + self.checked_div_int(d).ok_or_else(|| error::division(self, d)) + } + } + + impl EnsureFixedPointNumber for T {} + + /// Similar to [`TryFrom`] but returning an [`ArithmeticError`] error. + pub trait EnsureFrom: + TryFrom + PartialOrd + Zero + Copy + { + /// Performs the conversion returning an [`ArithmeticError`] if fails. + /// + /// Similar to [`TryFrom::try_from()`] but returning an [`ArithmeticError`] error. + /// + /// ``` + /// use sp_arithmetic::{traits::EnsureFrom, ArithmeticError}; + /// + /// fn overflow() -> Result<(), ArithmeticError> { + /// let byte: u8 = u8::ensure_from(256u16)?; + /// Ok(()) + /// } + /// + /// fn underflow() -> Result<(), ArithmeticError> { + /// let byte: i8 = i8::ensure_from(-129i16)?; + /// Ok(()) + /// } + /// + /// assert_eq!(overflow(), Err(ArithmeticError::Overflow)); + /// assert_eq!(underflow(), Err(ArithmeticError::Underflow)); + /// ``` + fn ensure_from(other: T) -> Result { + Self::try_from(other).map_err(|_| error::equivalent(other)) + } + } + + /// Similar to [`TryInto`] but returning an [`ArithmeticError`] error. + pub trait EnsureInto: + TryInto + PartialOrd + Zero + Copy + { + /// Performs the conversion returning an [`ArithmeticError`] if fails. + /// + /// Similar to [`TryInto::try_into()`] but returning an [`ArithmeticError`] error + /// + /// ``` + /// use sp_arithmetic::{traits::EnsureInto, ArithmeticError}; + /// + /// fn overflow() -> Result<(), ArithmeticError> { + /// let byte: u8 = 256u16.ensure_into()?; + /// Ok(()) + /// } + /// + /// fn underflow() -> Result<(), ArithmeticError> { + /// let byte: i8 = (-129i16).ensure_into()?; + /// Ok(()) + /// } + /// + /// assert_eq!(overflow(), Err(ArithmeticError::Overflow)); + /// assert_eq!(underflow(), Err(ArithmeticError::Underflow)); + /// ``` + fn ensure_into(self) -> Result { + self.try_into().map_err(|_| error::equivalent(self)) + } + } + + impl + PartialOrd + Zero + Copy, S: PartialOrd + Zero + Copy> EnsureFrom for T {} + impl + PartialOrd + Zero + Copy, S: PartialOrd + Zero + Copy> EnsureInto for T {} + + mod error { + use super::{ArithmeticError, Zero}; + + #[derive(PartialEq)] + enum Signum { + Negative, + Positive, + } + + impl From for Signum { + fn from(value: T) -> Self { + if value < Zero::zero() { + Signum::Negative + } else { + Signum::Positive + } + } + } + + impl sp_std::ops::Mul for Signum { + type Output = Self; + + fn mul(self, rhs: Self) -> Self { + if self != rhs { + Signum::Negative + } else { + Signum::Positive + } + } + } + + pub fn equivalent(r: R) -> ArithmeticError { + match Signum::from(r) { + Signum::Negative => ArithmeticError::Underflow, + Signum::Positive => ArithmeticError::Overflow, + } + } + + pub fn inverse(r: R) -> ArithmeticError { + match Signum::from(r) { + Signum::Negative => ArithmeticError::Overflow, + Signum::Positive => ArithmeticError::Underflow, + } + } + + pub fn multiplication( + l: L, + r: R, + ) -> ArithmeticError { + match Signum::from(l) * Signum::from(r) { + Signum::Negative => ArithmeticError::Underflow, + Signum::Positive => ArithmeticError::Overflow, + } + } + + pub fn division( + n: N, + d: D, + ) -> ArithmeticError { + if d.is_zero() { + ArithmeticError::DivisionByZero + } else { + multiplication(n, d) + } + } + } +} diff --git a/primitives/runtime/src/lib.rs b/primitives/runtime/src/lib.rs index e94efda86aa03..96fe7d2487f48 100644 --- a/primitives/runtime/src/lib.rs +++ b/primitives/runtime/src/lib.rs @@ -93,9 +93,9 @@ pub use sp_arithmetic::biguint; pub use sp_arithmetic::helpers_128bit; /// Re-export top-level arithmetic stuff. pub use sp_arithmetic::{ - traits::SaturatedConversion, FixedI128, FixedI64, FixedPointNumber, FixedPointOperand, - FixedU128, InnerOf, PerThing, PerU16, Perbill, Percent, Permill, Perquintill, Rational128, - Rounding, UpperOf, + traits::SaturatedConversion, ArithmeticError, FixedI128, FixedI64, FixedPointNumber, + FixedPointOperand, FixedU128, InnerOf, PerThing, PerU16, Perbill, Percent, Permill, + Perquintill, Rational128, Rounding, UpperOf, }; pub use either::Either; @@ -641,28 +641,6 @@ impl From for DispatchError { } } -/// Arithmetic errors. -#[derive(Eq, PartialEq, Clone, Copy, Encode, Decode, Debug, TypeInfo)] -#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] -pub enum ArithmeticError { - /// Underflow. - Underflow, - /// Overflow. - Overflow, - /// Division by zero. - DivisionByZero, -} - -impl From for &'static str { - fn from(e: ArithmeticError) -> &'static str { - match e { - ArithmeticError::Underflow => "An underflow would occur", - ArithmeticError::Overflow => "An overflow would occur", - ArithmeticError::DivisionByZero => "Division by zero", - } - } -} - impl From for DispatchError { fn from(e: ArithmeticError) -> DispatchError { Self::Arithmetic(e) diff --git a/primitives/runtime/src/traits.rs b/primitives/runtime/src/traits.rs index 375475141b818..8978cdb11c0c6 100644 --- a/primitives/runtime/src/traits.rs +++ b/primitives/runtime/src/traits.rs @@ -33,8 +33,10 @@ use serde::{de::DeserializeOwned, Deserialize, Serialize}; use sp_application_crypto::AppKey; pub use sp_arithmetic::traits::{ AtLeast32Bit, AtLeast32BitUnsigned, Bounded, CheckedAdd, CheckedDiv, CheckedMul, CheckedShl, - CheckedShr, CheckedSub, IntegerSquareRoot, One, SaturatedConversion, Saturating, - UniqueSaturatedFrom, UniqueSaturatedInto, Zero, + CheckedShr, CheckedSub, Ensure, EnsureAdd, EnsureAddAssign, EnsureDiv, EnsureDivAssign, + EnsureFixedPointNumber, EnsureFrom, EnsureInto, EnsureMul, EnsureMulAssign, EnsureOp, + EnsureOpAssign, EnsureSub, EnsureSubAssign, IntegerSquareRoot, One, SaturatedConversion, + Saturating, UniqueSaturatedFrom, UniqueSaturatedInto, Zero, }; use sp_core::{self, storage::StateVersion, Hasher, RuntimeDebug, TypeId}; #[doc(hidden)] From 52e96b3a88c54bc62076a767b67a8bc2fe60dcec Mon Sep 17 00:00:00 2001 From: Nazar Mokrynskyi Date: Thu, 29 Dec 2022 00:10:47 +0200 Subject: [PATCH 236/715] Derive `Debug` on `SyncStatus` (#13025) --- client/network/common/src/sync.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/network/common/src/sync.rs b/client/network/common/src/sync.rs index 5e8219c550d19..802cf75fc4709 100644 --- a/client/network/common/src/sync.rs +++ b/client/network/common/src/sync.rs @@ -70,7 +70,7 @@ pub struct StateDownloadProgress { } /// Syncing status and statistics. -#[derive(Clone)] +#[derive(Debug, Clone)] pub struct SyncStatus { /// Current global sync state. pub state: SyncState>, From 3addee20bc5f726244ebfba67b77569d27d0328e Mon Sep 17 00:00:00 2001 From: Vlad Date: Thu, 29 Dec 2022 19:20:41 +0400 Subject: [PATCH 237/715] Enable `zstd` for `rusty-cachier` (#13029) --- .gitlab-ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 4d17b70028810..06890c9ed3346 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -53,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" + RUSTY_CACHIER_COMPRESSION_METHOD: zstd ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.3.22" default: From ed82c874b9cee5b7049730cf5983a02ebc9f89d5 Mon Sep 17 00:00:00 2001 From: Vlad Date: Thu, 29 Dec 2022 19:46:56 +0400 Subject: [PATCH 238/715] Unpin `ci-linux` and use the latest `production` tag as before (#13030) --- .gitlab-ci.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 06890c9ed3346..a0b1464bae23e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -48,8 +48,7 @@ variables: CARGO_INCREMENTAL: 0 DOCKER_OS: "debian:stretch" ARCH: "x86_64" - # staging image with rust 1.65 and nightly-2022-11-16 - CI_IMAGE: "paritytech/ci-linux@sha256:786869e731963b3cc0a4aa9deb83367ed9e87a6ae48b6eb029d62b0cab4d87c1" + 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" From 55c64bcc2af5a6e5fc3eb245e638379ebe18a58d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89lo=C3=AFs?= Date: Fri, 30 Dec 2022 18:54:04 +0100 Subject: [PATCH 239/715] try-runtime: add cli option --export-proof (#12539) * try-runtime: add cli option --export-proof * extract proof in raw json format * fix build * fix(try-runtime execute-block): wrong block parsing * fmt * apply suggestions * Update utils/frame/try-runtime/cli/src/lib.rs Co-authored-by: Anton * Update utils/frame/try-runtime/cli/src/lib.rs Co-authored-by: Anton * Update utils/frame/try-runtime/cli/src/lib.rs Co-authored-by: Anton * Update utils/frame/try-runtime/cli/src/lib.rs Co-authored-by: Anton * split off external dependencies * fmt * fix try-runtime compilation Co-authored-by: Anton --- Cargo.lock | 1 + utils/frame/try-runtime/cli/Cargo.toml | 5 +- .../cli/src/commands/execute_block.rs | 1 + .../cli/src/commands/follow_chain.rs | 4 ++ .../cli/src/commands/on_runtime_upgrade.rs | 1 + utils/frame/try-runtime/cli/src/lib.rs | 51 +++++++++++++++++++ 6 files changed, 61 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b2aca09fe2564..f82343e442a89 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10646,6 +10646,7 @@ dependencies = [ "sc-executor", "sc-service", "serde", + "serde_json", "sp-api", "sp-core", "sp-debug-derive", diff --git a/utils/frame/try-runtime/cli/Cargo.toml b/utils/frame/try-runtime/cli/Cargo.toml index c4cc2e757d90f..ed0f25cae7a36 100644 --- a/utils/frame/try-runtime/cli/Cargo.toml +++ b/utils/frame/try-runtime/cli/Cargo.toml @@ -30,11 +30,12 @@ sp-weights = { version = "4.0.0", path = "../../../../primitives/weights" } frame-try-runtime = { optional = true, path = "../../../../frame/try-runtime" } substrate-rpc-client = { path = "../../rpc/client" } -parity-scale-codec = "3.0.0" -hex = "0.4.3" clap = { version = "4.0.9", features = ["derive"] } +hex = { version = "0.4.3", default-features = false } log = "0.4.17" +parity-scale-codec = "3.0.0" serde = "1.0.136" +serde_json = "1.0.85" zstd = { version = "0.11.2", default-features = false } [dev-dependencies] 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 80d34002fa771..ee5e21af5d3ba 100644 --- a/utils/frame/try-runtime/cli/src/commands/execute_block.rs +++ b/utils/frame/try-runtime/cli/src/commands/execute_block.rs @@ -134,6 +134,7 @@ where "TryRuntime_execute_block", &payload, full_extensions(), + shared.export_proof, )?; 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 index 4eb3b3a8f35a9..e4f166fe7ada7 100644 --- a/utils/frame/try-runtime/cli/src/commands/follow_chain.rs +++ b/utils/frame/try-runtime/cli/src/commands/follow_chain.rs @@ -150,6 +150,10 @@ where "TryRuntime_execute_block", (block, command.state_root_check, command.try_state.clone()).encode().as_ref(), full_extensions(), + shared + .export_proof + .as_ref() + .map(|path| path.as_path().join(&format!("{}.json", number))), ); if let Err(why) = result { 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 80fb5d31f71a9..2b2800d505864 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 @@ -59,6 +59,7 @@ where "TryRuntime_on_runtime_upgrade", command.checks.encode().as_ref(), Default::default(), // we don't really need any extensions here. + shared.export_proof, )?; let (weight, total_weight) = <(Weight, Weight) as Decode>::decode(&mut &*encoded_result) diff --git a/utils/frame/try-runtime/cli/src/lib.rs b/utils/frame/try-runtime/cli/src/lib.rs index 47a9dfa3f6544..aac2ad4238431 100644 --- a/utils/frame/try-runtime/cli/src/lib.rs +++ b/utils/frame/try-runtime/cli/src/lib.rs @@ -523,6 +523,12 @@ pub struct SharedParams { #[arg(long)] pub heap_pages: Option, + /// Path to a file to export the storage proof into (as a JSON). + /// If several blocks are executed, the path is interpreted as a folder + /// where one file per block will be written (named `{block_number}-{block_hash}`). + #[clap(long)] + pub export_proof: Option, + /// Overwrite the `state_version`. /// /// Otherwise `remote-externalities` will automatically set the correct state version. @@ -863,6 +869,7 @@ pub(crate) fn state_machine_call_with_proof, ) -> sc_cli::Result<(OverlayedChanges, Vec)> { use parity_scale_codec::Encode; @@ -891,6 +898,32 @@ pub(crate) fn state_machine_call_with_proof &'static str { log::error!(target: LOG_TARGET, "rpc error: {:?}", error); "rpc error." } + +/// Converts a [`sp_state_machine::StorageProof`] into a JSON string. +fn storage_proof_to_raw_json(storage_proof: &sp_state_machine::StorageProof) -> String { + serde_json::Value::Object( + storage_proof + .to_memory_db::() + .drain() + .iter() + .map(|(key, (value, _n))| { + ( + format!("0x{}", hex::encode(key.as_bytes())), + serde_json::Value::String(format!("0x{}", hex::encode(value))), + ) + }) + .collect(), + ) + .to_string() +} From bcee526a9b73d2df9d5dea0f1a17677618d70b8e Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Mon, 2 Jan 2023 10:42:05 +0100 Subject: [PATCH 240/715] BlockId removal: refactor: BlockBackend::block|block_status (#13014) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * BlockId removal: refactor: BlockBackend::block|block_status It changes the arguments of: - `BlockBackend::block` - `BlockBackend::block_status` method from: `BlockId` to: `Block::Hash` This PR is part of BlockId::Number refactoring analysis (paritytech/substrate#11292) * non-obvious reworks * doc fix * Apply suggestions from code review Co-authored-by: Bastian Köcher Co-authored-by: Bastian Köcher Co-authored-by: parity-processbot <> --- client/api/src/client.rs | 13 +++-- client/cli/src/commands/export_blocks_cmd.rs | 4 +- client/network/sync/src/lib.rs | 11 ++--- .../rpc-spec-v2/src/chain_head/chain_head.rs | 2 +- client/rpc/src/chain/chain_full.rs | 7 +-- client/rpc/src/dev/mod.rs | 5 +- client/service/src/chain_ops/check_block.rs | 21 ++++---- client/service/src/chain_ops/export_blocks.rs | 12 +++-- client/service/src/client/client.rs | 48 +++++++++---------- client/service/test/src/client/mod.rs | 37 ++++---------- .../consensus/common/src/block_validation.rs | 12 ++--- .../frame/benchmarking-cli/src/block/bench.rs | 4 +- 12 files changed, 75 insertions(+), 101 deletions(-) diff --git a/client/api/src/client.rs b/client/api/src/client.rs index 05e3163dcc7bd..0d00257fa7b06 100644 --- a/client/api/src/client.rs +++ b/client/api/src/client.rs @@ -21,7 +21,7 @@ use sp_consensus::BlockOrigin; use sp_core::storage::StorageKey; use sp_runtime::{ - generic::{BlockId, SignedBlock}, + generic::SignedBlock, traits::{Block as BlockT, NumberFor}, Justifications, }; @@ -120,14 +120,13 @@ pub trait BlockBackend { /// that are indexed by the runtime with `storage_index_transaction`. fn block_indexed_body(&self, hash: Block::Hash) -> sp_blockchain::Result>>>; - /// Get full block by id. - fn block(&self, id: &BlockId) -> sp_blockchain::Result>>; + /// Get full block by hash. + fn block(&self, hash: Block::Hash) -> sp_blockchain::Result>>; - /// Get block status. - fn block_status(&self, id: &BlockId) - -> sp_blockchain::Result; + /// Get block status by block hash. + fn block_status(&self, hash: Block::Hash) -> sp_blockchain::Result; - /// Get block justifications for the block with the given id. + /// Get block justifications for the block with the given hash. fn justifications(&self, hash: Block::Hash) -> sp_blockchain::Result>; /// Get block hash by number. diff --git a/client/cli/src/commands/export_blocks_cmd.rs b/client/cli/src/commands/export_blocks_cmd.rs index e2f83200e511c..76fedff4d3ad7 100644 --- a/client/cli/src/commands/export_blocks_cmd.rs +++ b/client/cli/src/commands/export_blocks_cmd.rs @@ -23,7 +23,7 @@ use crate::{ }; use clap::Parser; use log::info; -use sc_client_api::{BlockBackend, UsageProvider}; +use sc_client_api::{BlockBackend, HeaderBackend, 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}; @@ -73,7 +73,7 @@ impl ExportBlocksCmd { ) -> error::Result<()> where B: BlockT, - C: BlockBackend + UsageProvider + 'static, + C: HeaderBackend + BlockBackend + UsageProvider + 'static, <::Number as FromStr>::Err: Debug, { if let Some(path) = database_config.path() { diff --git a/client/network/sync/src/lib.rs b/client/network/sync/src/lib.rs index 76f14a721a439..312fc6f5b7947 100644 --- a/client/network/sync/src/lib.rs +++ b/client/network/sync/src/lib.rs @@ -86,7 +86,6 @@ use sp_consensus::{ BlockOrigin, BlockStatus, }; use sp_runtime::{ - generic::BlockId, traits::{ Block as BlockT, CheckedSub, Hash, HashFor, Header as HeaderT, NumberFor, One, SaturatedConversion, Zero, @@ -1865,8 +1864,7 @@ where self.best_queued_number = info.best_number; if self.mode == SyncMode::Full && - self.client.block_status(&BlockId::hash(info.best_hash))? != - BlockStatus::InChainWithState + self.client.block_status(info.best_hash)? != BlockStatus::InChainWithState { self.import_existing = true; // Latest state is missing, start with the last finalized state or genesis instead. @@ -1898,7 +1896,7 @@ where if self.queue_blocks.contains(hash) { return Ok(BlockStatus::Queued) } - self.client.block_status(&BlockId::Hash(*hash)) + self.client.block_status(*hash) } /// Is the block corresponding to the given hash known? @@ -2455,9 +2453,7 @@ where if queue.contains(hash) { BlockStatus::Queued } else { - client - .block_status(&BlockId::Hash(*hash)) - .unwrap_or(BlockStatus::Unknown) + client.block_status(*hash).unwrap_or(BlockStatus::Unknown) } }, ) { @@ -3202,6 +3198,7 @@ mod test { }; use sp_blockchain::HeaderBackend; use sp_consensus::block_validation::DefaultBlockAnnounceValidator; + use sp_runtime::generic::BlockId; use substrate_test_runtime_client::{ runtime::{Block, Hash, Header}, BlockBuilderExt, ClientBlockImportExt, ClientExt, DefaultTestClientBuilderExt, TestClient, diff --git a/client/rpc-spec-v2/src/chain_head/chain_head.rs b/client/rpc-spec-v2/src/chain_head/chain_head.rs index c0ba9e165dd04..c63d373e04f16 100644 --- a/client/rpc-spec-v2/src/chain_head/chain_head.rs +++ b/client/rpc-spec-v2/src/chain_head/chain_head.rs @@ -573,7 +573,7 @@ where return } - let event = match client.block(&BlockId::Hash(hash)) { + let event = match client.block(hash) { Ok(Some(signed_block)) => { let extrinsics = signed_block.block.extrinsics(); let result = format!("0x{:?}", HexDisplay::from(&extrinsics.encode())); diff --git a/client/rpc/src/chain/chain_full.rs b/client/rpc/src/chain/chain_full.rs index ee7870e0629e0..6ff544b0deacd 100644 --- a/client/rpc/src/chain/chain_full.rs +++ b/client/rpc/src/chain/chain_full.rs @@ -29,10 +29,7 @@ use futures::{ use jsonrpsee::SubscriptionSink; use sc_client_api::{BlockBackend, BlockchainEvents}; use sp_blockchain::HeaderBackend; -use sp_runtime::{ - generic::{BlockId, SignedBlock}, - traits::Block as BlockT, -}; +use sp_runtime::{generic::SignedBlock, traits::Block as BlockT}; /// Blockchain API backend for full nodes. Reads all the data from local database. pub struct FullChain { @@ -66,7 +63,7 @@ where } fn block(&self, hash: Option) -> Result>, Error> { - self.client.block(&BlockId::Hash(self.unwrap_or_best(hash))).map_err(client_err) + self.client.block(self.unwrap_or_best(hash)).map_err(client_err) } fn subscribe_all_heads(&self, sink: SubscriptionSink) { diff --git a/client/rpc/src/dev/mod.rs b/client/rpc/src/dev/mod.rs index ec9e61678fd71..e48a8ee4e7d5c 100644 --- a/client/rpc/src/dev/mod.rs +++ b/client/rpc/src/dev/mod.rs @@ -69,10 +69,7 @@ where self.deny_unsafe.check_if_safe()?; let block = { - let block = self - .client - .block(&BlockId::Hash(hash)) - .map_err(|e| Error::BlockQueryError(Box::new(e)))?; + let block = self.client.block(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 diff --git a/client/service/src/chain_ops/check_block.rs b/client/service/src/chain_ops/check_block.rs index 41a6c73c5f473..c3380e5476ab6 100644 --- a/client/service/src/chain_ops/check_block.rs +++ b/client/service/src/chain_ops/check_block.rs @@ -18,34 +18,37 @@ use crate::error::Error; use codec::Encode; -use futures::{future, prelude::*}; use sc_client_api::{BlockBackend, HeaderBackend}; use sc_consensus::import_queue::ImportQueue; use sp_runtime::{generic::BlockId, traits::Block as BlockT}; use crate::chain_ops::import_blocks; -use std::{pin::Pin, sync::Arc}; +use std::sync::Arc; /// Re-validate known block. -pub fn check_block( +pub async fn check_block( client: Arc, import_queue: IQ, block_id: BlockId, -) -> Pin> + Send>> +) -> Result<(), Error> where C: BlockBackend + HeaderBackend + Send + Sync + 'static, B: BlockT + for<'de> serde::Deserialize<'de>, IQ: ImportQueue + 'static, { - match client.block(&block_id) { - Ok(Some(block)) => { + let maybe_block = client + .block_hash_from_id(&block_id)? + .map(|hash| client.block(hash)) + .transpose()? + .flatten(); + match maybe_block { + Some(block) => { let mut buf = Vec::new(); 1u64.encode_to(&mut buf); block.encode_to(&mut buf); let reader = std::io::Cursor::new(buf); - import_blocks(client, import_queue, reader, true, true) + import_blocks(client, import_queue, reader, true, true).await }, - Ok(None) => Box::pin(future::err("Unknown block".into())), - Err(e) => Box::pin(future::err(format!("Error reading block: {}", e).into())), + None => Err("Unknown block")?, } } diff --git a/client/service/src/chain_ops/export_blocks.rs b/client/service/src/chain_ops/export_blocks.rs index d442a11f2c39b..9638722ef6b21 100644 --- a/client/service/src/chain_ops/export_blocks.rs +++ b/client/service/src/chain_ops/export_blocks.rs @@ -25,7 +25,7 @@ use sp_runtime::{ traits::{Block as BlockT, NumberFor, One, SaturatedConversion, Zero}, }; -use sc_client_api::{BlockBackend, UsageProvider}; +use sc_client_api::{BlockBackend, HeaderBackend, UsageProvider}; use std::{io::Write, pin::Pin, sync::Arc, task::Poll}; /// Performs the blocks export. @@ -37,7 +37,7 @@ pub fn export_blocks( binary: bool, ) -> Pin>>> where - C: BlockBackend + UsageProvider + 'static, + C: HeaderBackend + BlockBackend + UsageProvider + 'static, B: BlockT, { let mut block = from; @@ -75,7 +75,12 @@ where wrote_header = true; } - match client.block(&BlockId::number(block))? { + match client + .block_hash_from_id(&BlockId::number(block))? + .map(|hash| client.block(hash)) + .transpose()? + .flatten() + { Some(block) => if binary { output.write_all(&block.encode())?; @@ -83,7 +88,6 @@ where serde_json::to_writer(&mut output, &block) .map_err(|e| format!("Error writing JSON: {}", e))?; }, - // Reached end of the chain. None => return Poll::Ready(Ok(())), } if (block % 10000u32.into()).is_zero() { diff --git a/client/service/src/client/client.rs b/client/service/src/client/client.rs index 78f2174b89eea..18012fc1931fe 100644 --- a/client/service/src/client/client.rs +++ b/client/service/src/client/client.rs @@ -784,7 +784,8 @@ where let parent_hash = import_block.header.parent_hash(); let at = BlockId::Hash(*parent_hash); let state_action = std::mem::replace(&mut import_block.state_action, StateAction::Skip); - let (enact_state, storage_changes) = match (self.block_status(&at)?, state_action) { + let (enact_state, storage_changes) = match (self.block_status(*parent_hash)?, state_action) + { (BlockStatus::KnownBad, _) => return Ok(PrepareStorageChangesResult::Discard(ImportResult::KnownBad)), ( @@ -1025,17 +1026,18 @@ where } /// Get block status. - pub fn block_status(&self, id: &BlockId) -> sp_blockchain::Result { + pub fn block_status(&self, hash: Block::Hash) -> sp_blockchain::Result { // this can probably be implemented more efficiently - if let BlockId::Hash(ref h) = id { - if self.importing_block.read().as_ref().map_or(false, |importing| h == importing) { - return Ok(BlockStatus::Queued) - } + if self + .importing_block + .read() + .as_ref() + .map_or(false, |importing| &hash == importing) + { + return Ok(BlockStatus::Queued) } - 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)), - }; + + let hash_and_number = self.backend.blockchain().number(hash)?.map(|n| (hash, n)); match hash_and_number { Some((hash, number)) => if self.backend.have_state_at(hash, number) { @@ -1779,7 +1781,7 @@ where // Own status must be checked first. If the block and ancestry is pruned // this function must return `AlreadyInChain` rather than `MissingState` match self - .block_status(&BlockId::Hash(hash)) + .block_status(hash) .map_err(|e| ConsensusError::ClientImport(e.to_string()))? { BlockStatus::InChainWithState | BlockStatus::Queued => @@ -1792,7 +1794,7 @@ where } match self - .block_status(&BlockId::Hash(parent_hash)) + .block_status(parent_hash) .map_err(|e| ConsensusError::ClientImport(e.to_string()))? { BlockStatus::InChainWithState | BlockStatus::Queued => {}, @@ -1947,20 +1949,16 @@ where self.body(hash) } - fn block(&self, id: &BlockId) -> sp_blockchain::Result>> { - Ok(match self.backend.blockchain().block_hash_from_id(id)? { - Some(hash) => - match (self.header(hash)?, self.body(hash)?, self.justifications(hash)?) { - (Some(header), Some(extrinsics), justifications) => - Some(SignedBlock { block: Block::new(header, extrinsics), justifications }), - _ => None, - }, - None => None, + fn block(&self, hash: Block::Hash) -> sp_blockchain::Result>> { + Ok(match (self.header(hash)?, self.body(hash)?, self.justifications(hash)?) { + (Some(header), Some(extrinsics), justifications) => + Some(SignedBlock { block: Block::new(header, extrinsics), justifications }), + _ => None, }) } - fn block_status(&self, id: &BlockId) -> sp_blockchain::Result { - Client::block_status(self, id) + fn block_status(&self, hash: Block::Hash) -> sp_blockchain::Result { + Client::block_status(self, hash) } fn justifications(&self, hash: Block::Hash) -> sp_blockchain::Result> { @@ -2055,9 +2053,9 @@ where { fn block_status( &self, - id: &BlockId, + hash: B::Hash, ) -> Result> { - Client::block_status(self, id).map_err(|e| Box::new(e) as Box<_>) + Client::block_status(self, hash).map_err(|e| Box::new(e) as Box<_>) } } diff --git a/client/service/test/src/client/mod.rs b/client/service/test/src/client/mod.rs index 661cf83fc49bf..97c22a1cb509e 100644 --- a/client/service/test/src/client/mod.rs +++ b/client/service/test/src/client/mod.rs @@ -1137,7 +1137,7 @@ 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()); + assert!(client.block(hash).unwrap().is_none()); } #[test] @@ -1497,10 +1497,7 @@ fn returns_status_for_pruned_blocks() { block_on(client.check_block(check_block_a1.clone())).unwrap(), ImportResult::imported(false), ); - assert_eq!( - client.block_status(&BlockId::hash(check_block_a1.hash)).unwrap(), - BlockStatus::Unknown, - ); + assert_eq!(client.block_status(check_block_a1.hash).unwrap(), BlockStatus::Unknown); block_on(client.import_as_final(BlockOrigin::Own, a1.clone())).unwrap(); @@ -1508,10 +1505,7 @@ fn returns_status_for_pruned_blocks() { block_on(client.check_block(check_block_a1.clone())).unwrap(), ImportResult::AlreadyInChain, ); - assert_eq!( - client.block_status(&BlockId::hash(check_block_a1.hash)).unwrap(), - BlockStatus::InChainWithState, - ); + assert_eq!(client.block_status(check_block_a1.hash).unwrap(), BlockStatus::InChainWithState); let a2 = client .new_block_at(&BlockId::Hash(a1.hash()), Default::default(), false) @@ -1534,18 +1528,12 @@ fn returns_status_for_pruned_blocks() { block_on(client.check_block(check_block_a1.clone())).unwrap(), ImportResult::AlreadyInChain, ); - assert_eq!( - client.block_status(&BlockId::hash(check_block_a1.hash)).unwrap(), - BlockStatus::InChainPruned, - ); + assert_eq!(client.block_status(check_block_a1.hash).unwrap(), BlockStatus::InChainPruned); assert_eq!( block_on(client.check_block(check_block_a2.clone())).unwrap(), ImportResult::AlreadyInChain, ); - assert_eq!( - client.block_status(&BlockId::hash(check_block_a2.hash)).unwrap(), - BlockStatus::InChainWithState, - ); + assert_eq!(client.block_status(check_block_a2.hash).unwrap(), BlockStatus::InChainWithState); let a3 = client .new_block_at(&BlockId::Hash(a2.hash()), Default::default(), false) @@ -1569,26 +1557,17 @@ fn returns_status_for_pruned_blocks() { block_on(client.check_block(check_block_a1.clone())).unwrap(), ImportResult::AlreadyInChain, ); - assert_eq!( - client.block_status(&BlockId::hash(check_block_a1.hash)).unwrap(), - BlockStatus::InChainPruned, - ); + assert_eq!(client.block_status(check_block_a1.hash).unwrap(), BlockStatus::InChainPruned); assert_eq!( block_on(client.check_block(check_block_a2.clone())).unwrap(), ImportResult::AlreadyInChain, ); - assert_eq!( - client.block_status(&BlockId::hash(check_block_a2.hash)).unwrap(), - BlockStatus::InChainPruned, - ); + assert_eq!(client.block_status(check_block_a2.hash).unwrap(), BlockStatus::InChainPruned); assert_eq!( block_on(client.check_block(check_block_a3.clone())).unwrap(), ImportResult::AlreadyInChain, ); - assert_eq!( - client.block_status(&BlockId::hash(check_block_a3.hash)).unwrap(), - BlockStatus::InChainWithState, - ); + assert_eq!(client.block_status(check_block_a3.hash).unwrap(), BlockStatus::InChainWithState); let mut check_block_b1 = BlockCheckParams { hash: b1.hash(), diff --git a/primitives/consensus/common/src/block_validation.rs b/primitives/consensus/common/src/block_validation.rs index 71f3a80b27a64..1dc42104913cb 100644 --- a/primitives/consensus/common/src/block_validation.rs +++ b/primitives/consensus/common/src/block_validation.rs @@ -19,18 +19,18 @@ use crate::BlockStatus; use futures::FutureExt as _; -use sp_runtime::{generic::BlockId, traits::Block}; +use sp_runtime::traits::Block; use std::{error::Error, future::Future, pin::Pin, sync::Arc}; /// A type which provides access to chain information. pub trait Chain { - /// Retrieve the status of the block denoted by the given [`BlockId`]. - fn block_status(&self, id: &BlockId) -> Result>; + /// Retrieve the status of the block denoted by the given [`Block::Hash`]. + fn block_status(&self, hash: B::Hash) -> Result>; } impl, B: Block> Chain for Arc { - fn block_status(&self, id: &BlockId) -> Result> { - (&**self).block_status(id) + fn block_status(&self, hash: B::Hash) -> Result> { + (&**self).block_status(hash) } } @@ -60,7 +60,7 @@ pub trait BlockAnnounceValidator { /// Returning [`Validation::Failure`] will lead to a decrease of the /// peers reputation as it sent us invalid data. /// - /// The returned future should only resolve to an error iff there was an internal error + /// The returned future should only resolve to an error if there was an internal error /// validating the block announcement. If the block announcement itself is invalid, this should /// *always* return [`Validation::Failure`]. fn validate( diff --git a/utils/frame/benchmarking-cli/src/block/bench.rs b/utils/frame/benchmarking-cli/src/block/bench.rs index 578158d8a2356..c69d95725eb14 100644 --- a/utils/frame/benchmarking-cli/src/block/bench.rs +++ b/utils/frame/benchmarking-cli/src/block/bench.rs @@ -94,9 +94,9 @@ where 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 hash = self.client.expect_block_hash_from_id(&block_num)?; - let block = - self.client.block(&block_num)?.ok_or(format!("Block {} not found", block_num))?; + let block = self.client.block(hash)?.ok_or(format!("Block {} not found", block_num))?; let block = self.unsealed(block.block); let took = self.measure_block(&block, &parent_num)?; From cbd8f1b56fd8ab9af0d9317432cc735264c89d70 Mon Sep 17 00:00:00 2001 From: Sergej Sakac <73715684+Szegoo@users.noreply.github.com> Date: Mon, 2 Jan 2023 11:23:33 +0100 Subject: [PATCH 241/715] Forbid stray tokens in call index (#13036) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Check for call_index * fixes * pallet ui test for weight attribute * Update frame/support/procedural/src/pallet/parse/call.rs Co-authored-by: Bastian Köcher * fix * small fix * wrong return type * ... * . * final fix * update .stderr * commit * udpate * Update frame/support/procedural/src/pallet/parse/call.rs Co-authored-by: Bastian Köcher * update .stderr Co-authored-by: Bastian Köcher --- .../procedural/src/pallet/parse/call.rs | 4 ++ .../tests/pallet_ui/call_index_has_suffix.rs | 20 +++++++++ .../pallet_ui/call_index_has_suffix.stderr | 5 +++ .../pallet_ui/weight_argument_has_suffix.rs | 21 ++++++++++ .../weight_argument_has_suffix.stderr | 41 +++++++++++++++++++ 5 files changed, 91 insertions(+) create mode 100644 frame/support/test/tests/pallet_ui/call_index_has_suffix.rs create mode 100644 frame/support/test/tests/pallet_ui/call_index_has_suffix.stderr create mode 100644 frame/support/test/tests/pallet_ui/weight_argument_has_suffix.rs create mode 100644 frame/support/test/tests/pallet_ui/weight_argument_has_suffix.stderr diff --git a/frame/support/procedural/src/pallet/parse/call.rs b/frame/support/procedural/src/pallet/parse/call.rs index 9620038edfd6d..3af3225484fae 100644 --- a/frame/support/procedural/src/pallet/parse/call.rs +++ b/frame/support/procedural/src/pallet/parse/call.rs @@ -93,6 +93,10 @@ impl syn::parse::Parse for FunctionAttr { let call_index_content; syn::parenthesized!(call_index_content in content); let index = call_index_content.parse::()?; + if !index.suffix().is_empty() { + let msg = "Number literal must not have a suffix"; + return Err(syn::Error::new(index.span(), msg)) + } Ok(FunctionAttr::CallIndex(index.base10_parse()?)) } else { Err(lookahead.error()) diff --git a/frame/support/test/tests/pallet_ui/call_index_has_suffix.rs b/frame/support/test/tests/pallet_ui/call_index_has_suffix.rs new file mode 100644 index 0000000000000..abe4dc199bf51 --- /dev/null +++ b/frame/support/test/tests/pallet_ui/call_index_has_suffix.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::call_index(0something)] + pub fn foo(origin: OriginFor) -> DispatchResultWithPostInfo {} + } +} + +fn main() { +} diff --git a/frame/support/test/tests/pallet_ui/call_index_has_suffix.stderr b/frame/support/test/tests/pallet_ui/call_index_has_suffix.stderr new file mode 100644 index 0000000000000..2f4cead6cf70c --- /dev/null +++ b/frame/support/test/tests/pallet_ui/call_index_has_suffix.stderr @@ -0,0 +1,5 @@ +error: Number literal must not have a suffix + --> tests/pallet_ui/call_index_has_suffix.rs:14:30 + | +14 | #[pallet::call_index(0something)] + | ^^^^^^^^^^ diff --git a/frame/support/test/tests/pallet_ui/weight_argument_has_suffix.rs b/frame/support/test/tests/pallet_ui/weight_argument_has_suffix.rs new file mode 100644 index 0000000000000..99195d21be62e --- /dev/null +++ b/frame/support/test/tests/pallet_ui/weight_argument_has_suffix.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::call_index(0)] + #[pallet::weight(10_000something)] + pub fn foo(origin: OriginFor) -> DispatchResultWithPostInfo { Ok(().into()) } + } +} + +fn main() { +} diff --git a/frame/support/test/tests/pallet_ui/weight_argument_has_suffix.stderr b/frame/support/test/tests/pallet_ui/weight_argument_has_suffix.stderr new file mode 100644 index 0000000000000..c9b2010f88bb3 --- /dev/null +++ b/frame/support/test/tests/pallet_ui/weight_argument_has_suffix.stderr @@ -0,0 +1,41 @@ +error: invalid suffix `something` for number literal + --> tests/pallet_ui/weight_argument_has_suffix.rs:15:26 + | +15 | #[pallet::weight(10_000something)] + | ^^^^^^^^^^^^^^^ invalid suffix `something` + | + = help: the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.) + +error[E0308]: mismatched types + --> tests/pallet_ui/weight_argument_has_suffix.rs:12:12 + | +12 | #[pallet::call] + | ^^^^ + | | + | expected trait `frame_support::dispatch::ClassifyDispatch`, found trait `frame_support::dispatch::WeighData` + | arguments to this function are incorrect + | + = note: expected reference `&dyn frame_support::dispatch::ClassifyDispatch<()>` + found reference `&dyn frame_support::dispatch::WeighData<()>` +note: associated function defined here + --> $WORKSPACE/frame/support/src/dispatch.rs + | + | fn classify_dispatch(&self, target: T) -> DispatchClass; + | ^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> tests/pallet_ui/weight_argument_has_suffix.rs:12:12 + | +12 | #[pallet::call] + | ^^^^ + | | + | expected trait `frame_support::dispatch::PaysFee`, found trait `frame_support::dispatch::WeighData` + | arguments to this function are incorrect + | + = note: expected reference `&dyn frame_support::dispatch::PaysFee<()>` + found reference `&dyn frame_support::dispatch::WeighData<()>` +note: associated function defined here + --> $WORKSPACE/frame/support/src/dispatch.rs + | + | fn pays_fee(&self, _target: T) -> Pays; + | ^^^^^^^^ From c32968aa7c02b84b10af7986fe6d82716d804bf4 Mon Sep 17 00:00:00 2001 From: Ankan <10196091+Ank4n@users.noreply.github.com> Date: Tue, 3 Jan 2023 20:45:58 +0100 Subject: [PATCH 242/715] Use #[pallet::storage_version] for pallet staking (#12728) * delete releases * use standard pallet storage version * migrate to standard storage version for staking * not compiling * keep old releases enum around for decoding * fix releases * rename old releases * retriggering ci * fix migration comments * doc update Co-authored-by: parity-processbot <> --- frame/staking/src/lib.rs | 25 ------ frame/staking/src/migrations.rs | 138 +++++++++++++++++++++++++------- frame/staking/src/pallet/mod.rs | 14 ++-- 3 files changed, 115 insertions(+), 62 deletions(-) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 0f5b8e0123ab6..3672056534b75 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -881,31 +881,6 @@ impl Default for Forcing { } } -// A value placed in storage that represents the current version of the Staking 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, TypeInfo, MaxEncodedLen)] -enum Releases { - V1_0_0Ancient, - 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. - V10_0_0, // remove `EarliestUnappliedSlash`. - V11_0_0, // Move pallet storage prefix, e.g. BagsList -> VoterBagsList - V12_0_0, // remove `HistoryDepth`. -} - -impl Default for Releases { - fn default() -> Self { - Releases::V11_0_0 - } -} - /// A `Convert` implementation that finds the stash of the given controller account, /// if any. pub struct StashOf(sp_std::marker::PhantomData); diff --git a/frame/staking/src/migrations.rs b/frame/staking/src/migrations.rs index f2ccb4f8b096f..6253c3feed17d 100644 --- a/frame/staking/src/migrations.rs +++ b/frame/staking/src/migrations.rs @@ -18,7 +18,87 @@ use super::*; use frame_election_provider_support::SortedListProvider; -use frame_support::traits::OnRuntimeUpgrade; +use frame_support::{ + dispatch::GetStorageVersion, pallet_prelude::ValueQuery, storage_alias, + traits::OnRuntimeUpgrade, +}; + +/// Used for release versioning upto v12. +/// +/// Obsolete from v13. Keeping around to make encoding/decoding of old migration code easier. +#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +enum ObsoleteReleases { + V1_0_0Ancient, + 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. + V10_0_0, // remove `EarliestUnappliedSlash`. + V11_0_0, // Move pallet storage prefix, e.g. BagsList -> VoterBagsList + V12_0_0, // remove `HistoryDepth`. +} + +impl Default for ObsoleteReleases { + fn default() -> Self { + ObsoleteReleases::V12_0_0 + } +} + +/// Alias to the old storage item used for release versioning. Obsolete since v13. +#[storage_alias] +type StorageVersion = StorageValue, ObsoleteReleases, ValueQuery>; + +pub mod v13 { + use super::*; + + pub struct MigrateToV13(sp_std::marker::PhantomData); + impl OnRuntimeUpgrade for MigrateToV13 { + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, &'static str> { + frame_support::ensure!( + StorageVersion::::get() == ObsoleteReleases::V12_0_0, + "Required v12 before upgrading to v13" + ); + + Ok(Default::default()) + } + + fn on_runtime_upgrade() -> Weight { + let current = Pallet::::current_storage_version(); + let onchain = StorageVersion::::get(); + + if current == 13 && onchain == ObsoleteReleases::V12_0_0 { + StorageVersion::::kill(); + current.put::>(); + + log!(info, "v13 applied successfully"); + T::DbWeight::get().reads_writes(1, 2) + } else { + log!(warn, "Skipping v13, should be removed"); + T::DbWeight::get().reads(1) + } + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(_state: Vec) -> Result<(), &'static str> { + frame_support::ensure!( + Pallet::::on_chain_storage_version() == 13, + "v13 not applied" + ); + + frame_support::ensure!( + !StorageVersion::::exists(), + "Storage version not migrated correctly" + ); + + Ok(()) + } + } +} pub mod v12 { use super::*; @@ -36,7 +116,7 @@ pub mod v12 { #[cfg(feature = "try-runtime")] fn pre_upgrade() -> Result, &'static str> { frame_support::ensure!( - StorageVersion::::get() == Releases::V11_0_0, + StorageVersion::::get() == ObsoleteReleases::V11_0_0, "Expected v11 before upgrading to v12" ); @@ -53,9 +133,9 @@ pub mod v12 { } fn on_runtime_upgrade() -> frame_support::weights::Weight { - if StorageVersion::::get() == Releases::V11_0_0 { + if StorageVersion::::get() == ObsoleteReleases::V11_0_0 { HistoryDepth::::kill(); - StorageVersion::::put(Releases::V12_0_0); + StorageVersion::::put(ObsoleteReleases::V12_0_0); log!(info, "v12 applied successfully"); T::DbWeight::get().reads_writes(1, 2) @@ -68,7 +148,7 @@ pub mod v12 { #[cfg(feature = "try-runtime")] fn post_upgrade(_state: Vec) -> Result<(), &'static str> { frame_support::ensure!( - StorageVersion::::get() == crate::Releases::V12_0_0, + StorageVersion::::get() == ObsoleteReleases::V12_0_0, "v12 not applied" ); Ok(()) @@ -92,7 +172,7 @@ pub mod v11 { #[cfg(feature = "try-runtime")] fn pre_upgrade() -> Result, &'static str> { frame_support::ensure!( - StorageVersion::::get() == crate::Releases::V10_0_0, + StorageVersion::::get() == ObsoleteReleases::V10_0_0, "must upgrade linearly" ); let old_pallet_prefix = twox_128(N::get().as_bytes()); @@ -117,9 +197,9 @@ pub mod v11 { let old_pallet_name = N::get(); let new_pallet_name =

::name(); - if StorageVersion::::get() == Releases::V10_0_0 { + if StorageVersion::::get() == ObsoleteReleases::V10_0_0 { // bump version anyway, even if we don't need to move the prefix - StorageVersion::::put(Releases::V11_0_0); + StorageVersion::::put(ObsoleteReleases::V11_0_0); if new_pallet_name == old_pallet_name { log!( warn, @@ -139,7 +219,7 @@ 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, + StorageVersion::::get() == ObsoleteReleases::V11_0_0, "wrong version after the upgrade" ); @@ -184,7 +264,7 @@ pub mod v10 { 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 { + if StorageVersion::::get() == ObsoleteReleases::V9_0_0 { let pending_slashes = as Store>::UnappliedSlashes::iter().take(512); for (era, slashes) in pending_slashes { for slash in slashes { @@ -196,7 +276,7 @@ pub mod v10 { } EarliestUnappliedSlash::::kill(); - StorageVersion::::put(Releases::V10_0_0); + StorageVersion::::put(ObsoleteReleases::V10_0_0); log!(info, "MigrateToV10 executed successfully"); T::DbWeight::get().reads_writes(1, 1) @@ -221,7 +301,7 @@ pub mod v9 { pub struct InjectValidatorsIntoVoterList(sp_std::marker::PhantomData); impl OnRuntimeUpgrade for InjectValidatorsIntoVoterList { fn on_runtime_upgrade() -> Weight { - if StorageVersion::::get() == Releases::V8_0_0 { + if StorageVersion::::get() == ObsoleteReleases::V8_0_0 { let prev_count = T::VoterList::count(); let weight_of_cached = Pallet::::weight_of_fn(); for (v, _) in Validators::::iter() { @@ -239,13 +319,13 @@ pub mod v9 { T::VoterList::count(), ); - StorageVersion::::put(crate::Releases::V9_0_0); + StorageVersion::::put(ObsoleteReleases::V9_0_0); T::BlockWeights::get().max_block } else { log!( warn, "InjectValidatorsIntoVoterList being executed on the wrong storage \ - version, expected Releases::V8_0_0" + version, expected ObsoleteReleases::V8_0_0" ); T::DbWeight::get().reads(1) } @@ -254,7 +334,7 @@ pub mod v9 { #[cfg(feature = "try-runtime")] fn pre_upgrade() -> Result, &'static str> { frame_support::ensure!( - StorageVersion::::get() == crate::Releases::V8_0_0, + StorageVersion::::get() == ObsoleteReleases::V8_0_0, "must upgrade linearly" ); @@ -272,7 +352,7 @@ pub mod v9 { assert!(post_count == prev_count + validators); frame_support::ensure!( - StorageVersion::::get() == crate::Releases::V9_0_0, + StorageVersion::::get() == ObsoleteReleases::V9_0_0, "must upgrade " ); Ok(()) @@ -281,14 +361,15 @@ pub mod v9 { } pub mod v8 { - use crate::{Config, Nominators, Pallet, StorageVersion, Weight}; + use super::*; + use crate::{Config, Nominators, Pallet, Weight}; use frame_election_provider_support::SortedListProvider; use frame_support::traits::Get; #[cfg(feature = "try-runtime")] pub fn pre_migrate() -> Result<(), &'static str> { frame_support::ensure!( - StorageVersion::::get() == crate::Releases::V7_0_0, + StorageVersion::::get() == ObsoleteReleases::V7_0_0, "must upgrade linearly" ); @@ -298,8 +379,8 @@ pub mod v8 { /// 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"); + if StorageVersion::::get() == ObsoleteReleases::V7_0_0 { + crate::log!(info, "migrating staking to ObsoleteReleases::V8_0_0"); let migrated = T::VoterList::unsafe_regenerate( Nominators::::iter().map(|(id, _)| id), @@ -307,10 +388,10 @@ pub mod v8 { ); debug_assert_eq!(T::VoterList::try_state(), Ok(())); - StorageVersion::::put(crate::Releases::V8_0_0); + StorageVersion::::put(ObsoleteReleases::V8_0_0); crate::log!( info, - "👜 completed staking migration to Releases::V8_0_0 with {} voters migrated", + "👜 completed staking migration to ObsoleteReleases::V8_0_0 with {} voters migrated", migrated, ); @@ -348,20 +429,20 @@ pub mod v7 { ); assert!(Validators::::count().is_zero(), "Validators already set."); assert!(Nominators::::count().is_zero(), "Nominators already set."); - assert!(StorageVersion::::get() == Releases::V6_0_0); + assert!(StorageVersion::::get() == ObsoleteReleases::V6_0_0); Ok(()) } pub fn migrate() -> Weight { - log!(info, "Migrating staking to Releases::V7_0_0"); + log!(info, "Migrating staking to ObsoleteReleases::V7_0_0"); let validator_count = Validators::::iter().count() as u32; let nominator_count = Nominators::::iter().count() as u32; CounterForValidators::::put(validator_count); CounterForNominators::::put(nominator_count); - StorageVersion::::put(Releases::V7_0_0); - log!(info, "Completed staking migration to Releases::V7_0_0"); + StorageVersion::::put(ObsoleteReleases::V7_0_0); + log!(info, "Completed staking migration to ObsoleteReleases::V7_0_0"); T::DbWeight::get().reads_writes(validator_count.saturating_add(nominator_count).into(), 2) } @@ -403,7 +484,7 @@ pub mod v6 { /// Migrate storage to v6. pub fn migrate() -> Weight { - log!(info, "Migrating staking to Releases::V6_0_0"); + log!(info, "Migrating staking to ObsoleteReleases::V6_0_0"); SnapshotValidators::::kill(); SnapshotNominators::::kill(); @@ -412,7 +493,8 @@ pub mod v6 { EraElectionStatus::::kill(); IsCurrentSessionFinal::::kill(); - StorageVersion::::put(Releases::V6_0_0); + StorageVersion::::put(ObsoleteReleases::V6_0_0); + log!(info, "Done."); T::DbWeight::get().writes(6 + 1) } diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 8e8a8d9c7f600..92502949ef1a0 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -46,7 +46,7 @@ pub use impls::*; use crate::{ slashing, weights::WeightInfo, AccountIdLookupOf, ActiveEraInfo, BalanceOf, EraPayout, EraRewardPoints, Exposure, Forcing, NegativeImbalanceOf, Nominations, PositiveImbalanceOf, - Releases, RewardDestination, SessionInterface, StakingLedger, UnappliedSlash, UnlockChunk, + RewardDestination, SessionInterface, StakingLedger, UnappliedSlash, UnlockChunk, ValidatorPrefs, }; @@ -64,8 +64,12 @@ pub mod pallet { use super::*; + /// The current storage version. + const STORAGE_VERSION: StorageVersion = StorageVersion::new(13); + #[pallet::pallet] #[pallet::generate_store(pub(crate) trait Store)] + #[pallet::storage_version(STORAGE_VERSION)] pub struct Pallet(_); /// Possible operations on the configuration values of this pallet. @@ -561,13 +565,6 @@ pub mod pallet { #[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. - /// - /// This is set to v7.0.0 for new networks. - #[pallet::storage] - pub(crate) type StorageVersion = StorageValue<_, Releases, ValueQuery>; - /// The threshold for when users can start calling `chill_other` for other validators / /// nominators. The threshold is compared to the actual number of validators / nominators /// (`CountFor*`) in the system compared to the configured max (`Max*Count`). @@ -618,7 +615,6 @@ pub mod pallet { ForceEra::::put(self.force_era); CanceledSlashPayout::::put(self.canceled_payout); SlashRewardFraction::::put(self.slash_reward_fraction); - 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 { From e22166fa0d40342d3b373aeca0a33abc782b152c Mon Sep 17 00:00:00 2001 From: Liu-Cheng Xu Date: Wed, 4 Jan 2023 06:00:10 +0800 Subject: [PATCH 243/715] Enrich TooManySiblingBlocks error info (#13052) --- client/state-db/src/lib.rs | 5 +++-- client/state-db/src/noncanonical.rs | 7 ++++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/client/state-db/src/lib.rs b/client/state-db/src/lib.rs index 5e01a0e063ac1..961f641a1a8e7 100644 --- a/client/state-db/src/lib.rs +++ b/client/state-db/src/lib.rs @@ -134,7 +134,7 @@ pub enum StateDbError { /// Invalid pruning mode specified. Contains expected mode. IncompatiblePruningModes { stored: PruningMode, requested: PruningMode }, /// Too many unfinalized sibling blocks inserted. - TooManySiblingBlocks, + TooManySiblingBlocks { number: u64 }, /// Trying to insert existing block. BlockAlreadyExists, /// Invalid metadata @@ -184,7 +184,8 @@ impl fmt::Debug for StateDbError { "Incompatible pruning modes [stored: {:?}; requested: {:?}]", stored, requested ), - Self::TooManySiblingBlocks => write!(f, "Too many sibling blocks inserted"), + Self::TooManySiblingBlocks { number } => + write!(f, "Too many sibling blocks at #{number} inserted"), Self::BlockAlreadyExists => write!(f, "Block already exists"), Self::Metadata(message) => write!(f, "Invalid metadata: {}", message), Self::BlockUnavailable => diff --git a/client/state-db/src/noncanonical.rs b/client/state-db/src/noncanonical.rs index 84ba94c052909..b7eec8ab60ee0 100644 --- a/client/state-db/src/noncanonical.rs +++ b/client/state-db/src/noncanonical.rs @@ -283,7 +283,12 @@ impl NonCanonicalOverlay { }; if level.blocks.len() >= MAX_BLOCKS_PER_LEVEL as usize { - return Err(StateDbError::TooManySiblingBlocks) + trace!( + target: "state-db", + "Too many sibling blocks at #{number}: {:?}", + level.blocks.iter().map(|b| &b.hash).collect::>() + ); + return Err(StateDbError::TooManySiblingBlocks { number }) } if level.blocks.iter().any(|b| b.hash == *hash) { return Err(StateDbError::BlockAlreadyExists) From 653eb0dd6f1eec87bc0443431df1d36700601257 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 3 Jan 2023 23:00:34 +0100 Subject: [PATCH 244/715] Do not run `forced_canonicalization` for archive nodes (#13051) We don't canonicalize on archive nodes and thus `best_canonical` always returned `None`. So, the moment such a node tried to force canonicalize, it was trapped in some endless loop. This pr solves this by renaming `best_canonical` to `last_canonicalized` and also making the return value more clear by introducing a custom enum `LastCanonicalized`. --- client/db/src/lib.rs | 270 +++++++++++++++++++++++++------------ client/state-db/src/lib.rs | 36 ++++- 2 files changed, 216 insertions(+), 90 deletions(-) diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index 3e6332732d672..c8495c4a0252b 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::{IsPruned, StateDb}; +use sc_state_db::{IsPruned, LastCanonicalized, StateDb}; use sp_arithmetic::traits::Saturating; use sp_blockchain::{ well_known_cache_keys, Backend as _, CachedHeaderMetadata, Error as ClientError, HeaderBackend, @@ -1315,19 +1315,25 @@ impl Backend { &self, transaction: &mut Transaction, ) -> ClientResult<()> { - let best_canonical = || self.storage.state_db.best_canonical().unwrap_or(0); + let best_canonical = match self.storage.state_db.last_canonicalized() { + LastCanonicalized::None => 0, + LastCanonicalized::Block(b) => b, + // Nothing needs to be done when canonicalization is not happening. + LastCanonicalized::NotCanonicalizing => return Ok(()), + }; + let info = self.blockchain.info(); let best_number: u64 = self.blockchain.info().best_number.saturated_into(); - while best_number.saturating_sub(best_canonical()) > self.canonicalization_delay { - let to_canonicalize = best_canonical() + 1; - + for to_canonicalize in + best_canonical + 1..=best_number.saturating_sub(self.canonicalization_delay) + { let hash_to_canonicalize = sc_client_api::blockchain::HeaderBackend::hash( &self.blockchain, to_canonicalize.saturated_into(), )? .ok_or_else(|| { - let best_hash = info.best_hash; + let best_hash = info.best_hash; sp_blockchain::Error::Backend(format!( "Can't canonicalize missing block number #{to_canonicalize} when for best block {best_hash:?} (#{best_number})", @@ -1697,13 +1703,13 @@ 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) && - self.storage - .state_db - .best_canonical() - .map(|c| f_num.saturated_into::() > c) - .unwrap_or(true) - { + let requires_canonicalization = match self.storage.state_db.last_canonicalized() { + LastCanonicalized::None => true, + LastCanonicalized::Block(b) => f_num.saturated_into::() > b, + LastCanonicalized::NotCanonicalizing => false, + }; + + if requires_canonicalization && sc_client_api::Backend::have_state_at(self, f_hash, f_num) { let commit = self.storage.state_db.canonicalize_block(&f_hash).map_err( sp_blockchain::Error::from_state_db::< sc_state_db::Error, @@ -3824,102 +3830,198 @@ pub(crate) mod tests { #[test] fn force_delayed_canonicalize_waiting_for_blocks_to_be_finalized() { - let backend = Backend::::new_test(10, 1); + let pruning_modes = [BlocksPruning::Some(10), BlocksPruning::KeepAll]; - let genesis = - insert_block(&backend, 0, Default::default(), None, Default::default(), vec![], None) + for pruning_mode in pruning_modes { + eprintln!("Running with pruning mode: {:?}", pruning_mode); + + let backend = Backend::::new_test_with_tx_storage(pruning_mode, 1); + + let genesis = insert_block( + &backend, + 0, + Default::default(), + None, + Default::default(), + vec![], + None, + ) + .unwrap(); + + let block1 = { + let mut op = backend.begin_operation().unwrap(); + backend.begin_state_operation(&mut op, genesis).unwrap(); + let mut header = Header { + number: 1, + parent_hash: genesis, + state_root: Default::default(), + digest: Default::default(), + extrinsics_root: Default::default(), + }; + + 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.as_slice(), v.as_ref().map(|v| &v[..]))), + StateVersion::V1, + ); + op.update_db_storage(overlay).unwrap(); + header.state_root = root.into(); + + op.update_storage(storage, Vec::new()).unwrap(); + + op.set_block_data( + header.clone(), + Some(Vec::new()), + None, + None, + NewBlockState::Normal, + ) .unwrap(); - let block1 = { - let mut op = backend.begin_operation().unwrap(); - backend.begin_state_operation(&mut op, genesis).unwrap(); - let header = Header { - number: 1, - parent_hash: genesis, - state_root: BlakeTwo256::trie_root(Vec::new(), StateVersion::V1), - digest: Default::default(), - extrinsics_root: Default::default(), + backend.commit_operation(op).unwrap(); + + header.hash() }; - op.set_block_data(header.clone(), Some(Vec::new()), None, None, NewBlockState::Normal) - .unwrap(); + if matches!(pruning_mode, BlocksPruning::Some(_)) { + assert_eq!( + LastCanonicalized::Block(0), + backend.storage.state_db.last_canonicalized() + ); + } - backend.commit_operation(op).unwrap(); + // This should not trigger any forced canonicalization as we didn't have imported any + // best block by now. + let block2 = { + let mut op = backend.begin_operation().unwrap(); + backend.begin_state_operation(&mut op, block1).unwrap(); + let mut header = Header { + number: 2, + parent_hash: block1, + state_root: Default::default(), + digest: Default::default(), + extrinsics_root: Default::default(), + }; - header.hash() - }; + let storage = vec![(vec![5, 5, 5], Some(vec![4, 5, 6, 2]))]; - assert_eq!(0, backend.storage.state_db.best_canonical().unwrap()); + let (root, overlay) = op.old_state.storage_root( + storage.iter().map(|(k, v)| (k.as_slice(), v.as_ref().map(|v| &v[..]))), + StateVersion::V1, + ); + op.update_db_storage(overlay).unwrap(); + header.state_root = root.into(); - // This should not trigger any forced canonicalization as we didn't have imported any best - // block by now. - let block2 = { - let mut op = backend.begin_operation().unwrap(); - backend.begin_state_operation(&mut op, block1).unwrap(); - let header = Header { - number: 2, - parent_hash: block1, - state_root: BlakeTwo256::trie_root(Vec::new(), StateVersion::V1), - digest: Default::default(), - extrinsics_root: Default::default(), - }; + op.update_storage(storage, Vec::new()).unwrap(); - op.set_block_data(header.clone(), Some(Vec::new()), None, None, NewBlockState::Normal) + op.set_block_data( + header.clone(), + Some(Vec::new()), + None, + None, + NewBlockState::Normal, + ) .unwrap(); - backend.commit_operation(op).unwrap(); + backend.commit_operation(op).unwrap(); - header.hash() - }; + header.hash() + }; - assert_eq!(0, backend.storage.state_db.best_canonical().unwrap()); + if matches!(pruning_mode, BlocksPruning::Some(_)) { + assert_eq!( + LastCanonicalized::Block(0), + backend.storage.state_db.last_canonicalized() + ); + } - // This should also not trigger it yet, because we import a best block, but the best block - // from the POV of the db is still at `0`. - let block3 = { - let mut op = backend.begin_operation().unwrap(); - backend.begin_state_operation(&mut op, block2).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(), - }; + // This should also not trigger it yet, because we import a best block, but the best + // block from the POV of the db is still at `0`. + let block3 = { + let mut op = backend.begin_operation().unwrap(); + backend.begin_state_operation(&mut op, block2).unwrap(); + let mut header = Header { + number: 3, + parent_hash: block2, + state_root: Default::default(), + digest: Default::default(), + extrinsics_root: Default::default(), + }; - op.set_block_data(header.clone(), Some(Vec::new()), None, None, NewBlockState::Best) - .unwrap(); + let storage = vec![(vec![5, 5, 5], Some(vec![4, 5, 6, 3]))]; - backend.commit_operation(op).unwrap(); + let (root, overlay) = op.old_state.storage_root( + storage.iter().map(|(k, v)| (k.as_slice(), v.as_ref().map(|v| &v[..]))), + StateVersion::V1, + ); + op.update_db_storage(overlay).unwrap(); + header.state_root = root.into(); - header.hash() - }; + op.update_storage(storage, Vec::new()).unwrap(); - // Now it should kick in. - let block4 = { - let mut op = backend.begin_operation().unwrap(); - backend.begin_state_operation(&mut op, block3).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::Best, + ) + .unwrap(); + + backend.commit_operation(op).unwrap(); + + header.hash() }; - op.set_block_data(header.clone(), Some(Vec::new()), None, None, NewBlockState::Best) + // Now it should kick in. + let block4 = { + let mut op = backend.begin_operation().unwrap(); + backend.begin_state_operation(&mut op, block3).unwrap(); + let mut header = Header { + number: 4, + parent_hash: block3, + state_root: Default::default(), + digest: Default::default(), + extrinsics_root: Default::default(), + }; + + let storage = vec![(vec![5, 5, 5], Some(vec![4, 5, 6, 4]))]; + + let (root, overlay) = op.old_state.storage_root( + storage.iter().map(|(k, v)| (k.as_slice(), v.as_ref().map(|v| &v[..]))), + StateVersion::V1, + ); + op.update_db_storage(overlay).unwrap(); + header.state_root = root.into(); + + op.update_storage(storage, Vec::new()).unwrap(); + + op.set_block_data( + header.clone(), + Some(Vec::new()), + None, + None, + NewBlockState::Best, + ) .unwrap(); - backend.commit_operation(op).unwrap(); + backend.commit_operation(op).unwrap(); - header.hash() - }; + header.hash() + }; - assert_eq!(2, backend.storage.state_db.best_canonical().unwrap()); + if matches!(pruning_mode, BlocksPruning::Some(_)) { + assert_eq!( + LastCanonicalized::Block(2), + backend.storage.state_db.last_canonicalized() + ); + } - assert_eq!(block1, backend.blockchain().hash(1).unwrap().unwrap()); - assert_eq!(block2, backend.blockchain().hash(2).unwrap().unwrap()); - assert_eq!(block3, backend.blockchain().hash(3).unwrap().unwrap()); - assert_eq!(block4, backend.blockchain().hash(4).unwrap().unwrap()); + assert_eq!(block1, backend.blockchain().hash(1).unwrap().unwrap()); + assert_eq!(block2, backend.blockchain().hash(2).unwrap().unwrap()); + assert_eq!(block3, backend.blockchain().hash(3).unwrap().unwrap()); + assert_eq!(block4, backend.blockchain().hash(4).unwrap().unwrap()); + } } } diff --git a/client/state-db/src/lib.rs b/client/state-db/src/lib.rs index 961f641a1a8e7..1befd6dff3bc8 100644 --- a/client/state-db/src/lib.rs +++ b/client/state-db/src/lib.rs @@ -283,6 +283,17 @@ fn to_meta_key(suffix: &[u8], data: &S) -> Vec { buffer } +/// Status information about the last canonicalized block. +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum LastCanonicalized { + /// Not yet have canonicalized any block. + None, + /// The given block number is the last canonicalized block. + Block(u64), + /// No canonicalization is happening (pruning mode is archive all). + NotCanonicalizing, +} + pub struct StateDbSync { mode: PruningMode, non_canonical: NonCanonicalOverlay, @@ -349,15 +360,28 @@ impl StateDbSync { Ok(commit) } - fn best_canonical(&self) -> Option { - self.non_canonical.last_canonicalized_block_number() + /// Returns the block number of the last canonicalized block. + fn last_canonicalized(&self) -> LastCanonicalized { + if self.mode == PruningMode::ArchiveAll { + LastCanonicalized::NotCanonicalizing + } else { + self.non_canonical + .last_canonicalized_block_number() + .map(LastCanonicalized::Block) + .unwrap_or_else(|| LastCanonicalized::None) + } } fn is_pruned(&self, hash: &BlockHash, number: u64) -> IsPruned { match self.mode { PruningMode::ArchiveAll => IsPruned::NotPruned, PruningMode::ArchiveCanonical | PruningMode::Constrained(_) => { - if self.best_canonical().map(|c| number > c).unwrap_or(true) { + if self + .non_canonical + .last_canonicalized_block_number() + .map(|c| number > c) + .unwrap_or(true) + { if self.non_canonical.have_block(hash) { IsPruned::NotPruned } else { @@ -611,9 +635,9 @@ impl StateDb { self.db.write().remove(hash) } - /// Returns last finalized block number. - pub fn best_canonical(&self) -> Option { - return self.db.read().best_canonical() + /// Returns last canonicalized block. + pub fn last_canonicalized(&self) -> LastCanonicalized { + self.db.read().last_canonicalized() } /// Check if block is pruned away. From 6e52d60931e4398b8a974a0966821f5e27481b8b Mon Sep 17 00:00:00 2001 From: cuteolaf <53915161+cuteolaf@users.noreply.github.com> Date: Tue, 3 Jan 2023 14:41:31 -0800 Subject: [PATCH 245/715] remove unused constant: MaxValueSize (#12839) --- bin/node/runtime/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 0c946fa180f20..90a52ab697dee 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1181,7 +1181,6 @@ impl pallet_tips::Config for Runtime { 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() From 18ead61a6265e6fdfccd17e5c60250432071fb53 Mon Sep 17 00:00:00 2001 From: Jegor Sidorenko <5252494+jsidorenko@users.noreply.github.com> Date: Wed, 4 Jan 2023 10:30:12 +0200 Subject: [PATCH 246/715] Fix pallet's integration (#13056) --- frame/nfts/Cargo.toml | 2 ++ frame/nfts/src/lib.rs | 2 ++ frame/nfts/src/types.rs | 16 ++++++++-------- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/frame/nfts/Cargo.toml b/frame/nfts/Cargo.toml index 109dffdd10f50..d2cdb48532fd0 100644 --- a/frame/nfts/Cargo.toml +++ b/frame/nfts/Cargo.toml @@ -20,6 +20,7 @@ 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 = "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" } @@ -38,6 +39,7 @@ std = [ "frame-system/std", "log/std", "scale-info/std", + "sp-core/std", "sp-runtime/std", "sp-std/std", ] diff --git a/frame/nfts/src/lib.rs b/frame/nfts/src/lib.rs index 2006d78959c4d..dbd2c2048155a 100644 --- a/frame/nfts/src/lib.rs +++ b/frame/nfts/src/lib.rs @@ -1767,3 +1767,5 @@ pub mod pallet { } } } + +sp_core::generate_feature_enabled_macro!(runtime_benchmarks_enabled, feature = "runtime-benchmarks", $); diff --git a/frame/nfts/src/types.rs b/frame/nfts/src/types.rs index 58b1acaaedf42..9b89fb964b316 100644 --- a/frame/nfts/src/types.rs +++ b/frame/nfts/src/types.rs @@ -272,15 +272,15 @@ pub enum MintType { #[derive(Clone, Copy, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct MintSettings { /// Whether anyone can mint or if minters are restricted to some subset. - pub(super) mint_type: MintType, + pub mint_type: MintType, /// An optional price per mint. - pub(super) price: Option, + pub price: Option, /// When the mint starts. - pub(super) start_block: Option, + pub start_block: Option, /// When the mint ends. - pub(super) end_block: Option, + pub end_block: Option, /// Default settings each item will get during the mint. - pub(super) default_item_settings: ItemSettings, + pub default_item_settings: ItemSettings, } impl Default for MintSettings { @@ -315,11 +315,11 @@ pub enum PalletAttributes { )] pub struct CollectionConfig { /// Collection's settings. - pub(super) settings: CollectionSettings, + pub settings: CollectionSettings, /// Collection's max supply. - pub(super) max_supply: Option, + pub max_supply: Option, /// Default settings each item will get during the mint. - pub(super) mint_settings: MintSettings, + pub mint_settings: MintSettings, } impl CollectionConfig { From 296772699280a07cc3512ebaf9e199cebbea651c Mon Sep 17 00:00:00 2001 From: Jegor Sidorenko <5252494+jsidorenko@users.noreply.github.com> Date: Wed, 4 Jan 2023 10:30:43 +0200 Subject: [PATCH 247/715] Disallow burning externally locked nfts (#13054) * Disallow burning externally locked nfts * Update docs --- frame/nfts/src/features/create_delete_item.rs | 1 + frame/nfts/src/lib.rs | 4 +++- frame/uniques/src/functions.rs | 1 + frame/uniques/src/lib.rs | 4 +++- 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/frame/nfts/src/features/create_delete_item.rs b/frame/nfts/src/features/create_delete_item.rs index 7fd745b2bfff8..8d6c8a280956c 100644 --- a/frame/nfts/src/features/create_delete_item.rs +++ b/frame/nfts/src/features/create_delete_item.rs @@ -91,6 +91,7 @@ impl, I: 'static> Pallet { item: T::ItemId, with_details: impl FnOnce(&ItemDetailsFor) -> DispatchResult, ) -> DispatchResult { + ensure!(!T::Locker::is_locked(collection, item), Error::::ItemLocked); let owner = Collection::::try_mutate( &collection, |maybe_collection_details| -> Result { diff --git a/frame/nfts/src/lib.rs b/frame/nfts/src/lib.rs index dbd2c2048155a..9a6242143aedb 100644 --- a/frame/nfts/src/lib.rs +++ b/frame/nfts/src/lib.rs @@ -856,7 +856,9 @@ pub mod pallet { /// Destroy a single item. /// - /// Origin must be Signed and the sender should be the Admin of the `collection`. + /// Origin must be Signed and the signing account must be either: + /// - the Admin of the `collection`; + /// - the Owner of the `item`; /// /// - `collection`: The collection of the item to be burned. /// - `item`: The item to be burned. diff --git a/frame/uniques/src/functions.rs b/frame/uniques/src/functions.rs index 4e68f1139420d..03dba16eaa12b 100644 --- a/frame/uniques/src/functions.rs +++ b/frame/uniques/src/functions.rs @@ -189,6 +189,7 @@ impl, I: 'static> Pallet { item: T::ItemId, with_details: impl FnOnce(&CollectionDetailsFor, &ItemDetailsFor) -> DispatchResult, ) -> DispatchResult { + ensure!(!T::Locker::is_locked(collection, item), Error::::Locked); let owner = Collection::::try_mutate( &collection, |maybe_collection_details| -> Result { diff --git a/frame/uniques/src/lib.rs b/frame/uniques/src/lib.rs index 8157817d4166e..6b21477be4340 100644 --- a/frame/uniques/src/lib.rs +++ b/frame/uniques/src/lib.rs @@ -577,7 +577,9 @@ pub mod pallet { /// Destroy a single item. /// - /// Origin must be Signed and the sender should be the Admin of the `collection`. + /// Origin must be Signed and the signing account must be either: + /// - the Admin of the `collection`; + /// - the Owner of the `item`; /// /// - `collection`: The collection of the item to be burned. /// - `item`: The item of the item to be burned. From d1fe09c801b3d7312f01b04f3204b1d0ec76db87 Mon Sep 17 00:00:00 2001 From: Jegor Sidorenko <5252494+jsidorenko@users.noreply.github.com> Date: Wed, 4 Jan 2023 10:31:24 +0200 Subject: [PATCH 248/715] Allow to clear attributes via traits (#13055) --- frame/nfts/src/impl_nonfungibles.rs | 43 +++++++++++++++++++ frame/nfts/src/tests.rs | 16 +++++++ .../src/traits/tokens/nonfungible_v2.rs | 24 +++++++++++ .../src/traits/tokens/nonfungibles_v2.rs | 39 +++++++++++++++++ 4 files changed, 122 insertions(+) diff --git a/frame/nfts/src/impl_nonfungibles.rs b/frame/nfts/src/impl_nonfungibles.rs index edfc29710b7da..ab4d7a16ec215 100644 --- a/frame/nfts/src/impl_nonfungibles.rs +++ b/frame/nfts/src/impl_nonfungibles.rs @@ -237,6 +237,49 @@ impl, I: 'static> Mutate<::AccountId, ItemConfig }) }) } + + fn clear_attribute( + collection: &Self::CollectionId, + item: &Self::ItemId, + key: &[u8], + ) -> DispatchResult { + Self::do_clear_attribute( + None, + *collection, + Some(*item), + AttributeNamespace::Pallet, + Self::construct_attribute_key(key.to_vec())?, + ) + } + + fn clear_typed_attribute( + collection: &Self::CollectionId, + item: &Self::ItemId, + key: &K, + ) -> DispatchResult { + key.using_encoded(|k| { + >::clear_attribute(collection, item, k) + }) + } + + fn clear_collection_attribute(collection: &Self::CollectionId, key: &[u8]) -> DispatchResult { + Self::do_clear_attribute( + None, + *collection, + None, + AttributeNamespace::Pallet, + Self::construct_attribute_key(key.to_vec())?, + ) + } + + fn clear_typed_collection_attribute( + collection: &Self::CollectionId, + key: &K, + ) -> DispatchResult { + key.using_encoded(|k| { + >::clear_collection_attribute(collection, k) + }) + } } impl, I: 'static> Transfer for Pallet { diff --git a/frame/nfts/src/tests.rs b/frame/nfts/src/tests.rs index 18a3fd83b4de3..f8187b3777ebd 100644 --- a/frame/nfts/src/tests.rs +++ b/frame/nfts/src/tests.rs @@ -1012,6 +1012,22 @@ fn validate_deposit_required_setting() { assert_eq!(Balances::reserved_balance(1), 0); assert_eq!(Balances::reserved_balance(2), 3); assert_eq!(Balances::reserved_balance(3), 3); + + assert_ok!( + ::AccountId, ItemConfig>>::clear_attribute( + &0, + &0, + &[3], + ) + ); + assert_eq!( + attributes(0), + vec![ + (Some(0), AttributeNamespace::CollectionOwner, bvec![0], bvec![0]), + (Some(0), AttributeNamespace::ItemOwner, bvec![1], bvec![0]), + (Some(0), AttributeNamespace::Account(3), bvec![2], bvec![0]), + ] + ); }); } diff --git a/frame/support/src/traits/tokens/nonfungible_v2.rs b/frame/support/src/traits/tokens/nonfungible_v2.rs index a1b75e62e4db5..e1899020bb336 100644 --- a/frame/support/src/traits/tokens/nonfungible_v2.rs +++ b/frame/support/src/traits/tokens/nonfungible_v2.rs @@ -127,6 +127,20 @@ pub trait Mutate: Inspect { ) -> DispatchResult { key.using_encoded(|k| value.using_encoded(|v| Self::set_attribute(item, k, v))) } + + /// Clear attribute of `item`'s `key`. + /// + /// By default, this is not a supported operation. + fn clear_attribute(_item: &Self::ItemId, _key: &[u8]) -> DispatchResult { + Err(TokenError::Unsupported.into()) + } + + /// Attempt to clear the strongly-typed attribute of `item`'s `key`. + /// + /// By default this just attempts to use `clear_attribute`. + fn clear_typed_attribute(item: &Self::ItemId, key: &K) -> DispatchResult { + key.using_encoded(|k| Self::clear_attribute(item, k)) + } } /// Trait for transferring a non-fungible item. @@ -234,6 +248,16 @@ impl< value, ) } + fn clear_attribute(item: &Self::ItemId, key: &[u8]) -> DispatchResult { + >::clear_attribute(&A::get(), item, key) + } + fn clear_typed_attribute(item: &Self::ItemId, key: &K) -> DispatchResult { + >::clear_typed_attribute( + &A::get(), + item, + key, + ) + } } impl< diff --git a/frame/support/src/traits/tokens/nonfungibles_v2.rs b/frame/support/src/traits/tokens/nonfungibles_v2.rs index d2f5f5529fa96..17c5d887defc0 100644 --- a/frame/support/src/traits/tokens/nonfungibles_v2.rs +++ b/frame/support/src/traits/tokens/nonfungibles_v2.rs @@ -244,6 +244,45 @@ pub trait Mutate: Inspect { value.using_encoded(|v| Self::set_collection_attribute(collection, k, v)) }) } + + /// Clear attribute of `item` of `collection`'s `key`. + /// + /// By default, this is not a supported operation. + fn clear_attribute( + _collection: &Self::CollectionId, + _item: &Self::ItemId, + _key: &[u8], + ) -> DispatchResult { + Err(TokenError::Unsupported.into()) + } + + /// Attempt to clear the strongly-typed attribute of `item` of `collection`'s `key`. + /// + /// By default this just attempts to use `clear_attribute`. + fn clear_typed_attribute( + collection: &Self::CollectionId, + item: &Self::ItemId, + key: &K, + ) -> DispatchResult { + key.using_encoded(|k| Self::clear_attribute(collection, item, k)) + } + + /// Clear attribute of `collection`'s `key`. + /// + /// By default, this is not a supported operation. + fn clear_collection_attribute(_collection: &Self::CollectionId, _key: &[u8]) -> DispatchResult { + Err(TokenError::Unsupported.into()) + } + + /// Attempt to clear the strongly-typed attribute of `collection`'s `key`. + /// + /// By default this just attempts to use `clear_attribute`. + fn clear_typed_collection_attribute( + collection: &Self::CollectionId, + key: &K, + ) -> DispatchResult { + key.using_encoded(|k| Self::clear_collection_attribute(collection, k)) + } } /// Trait for transferring non-fungible sets of items. From a052224682994e6b54c94c17572e061f690149e5 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Wed, 4 Jan 2023 13:44:41 +0100 Subject: [PATCH 249/715] Selectable on-runtime-upgrade checks (#13045) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Make try-runtime checks selectable Signed-off-by: Oliver Tale-Yazdi * Update frame/support/src/traits/try_runtime.rs Co-authored-by: Bastian Köcher * Add Clap wrapper for enum UpgradeCheckSelect Signed-off-by: Oliver Tale-Yazdi * Revert "Add Clap wrapper for enum UpgradeCheckSelect" This reverts commit e29538c1a79d1711b43addc9400d871f6aa32844. * fix pools sanity check * Set default for --checks to None Signed-off-by: Oliver Tale-Yazdi * Make --checks backwards comp Signed-off-by: Oliver Tale-Yazdi * Add clap attr comment Signed-off-by: Oliver Tale-Yazdi Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Bastian Köcher Co-authored-by: kianenigma --- bin/node-template/runtime/src/lib.rs | 2 +- bin/node/runtime/src/lib.rs | 2 +- frame/executive/src/lib.rs | 10 +++-- frame/nomination-pools/src/lib.rs | 17 +++++--- frame/support/src/traits.rs | 2 +- frame/support/src/traits/try_runtime.rs | 42 ++++++++++++++++++- frame/try-runtime/src/lib.rs | 4 +- .../cli/src/commands/on_runtime_upgrade.rs | 21 +++++++--- 8 files changed, 79 insertions(+), 21 deletions(-) diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs index f76b2c449ee4a..f4372af525da5 100644 --- a/bin/node-template/runtime/src/lib.rs +++ b/bin/node-template/runtime/src/lib.rs @@ -539,7 +539,7 @@ impl_runtime_apis! { #[cfg(feature = "try-runtime")] impl frame_try_runtime::TryRuntime for Runtime { - fn on_runtime_upgrade(checks: bool) -> (Weight, Weight) { + fn on_runtime_upgrade(checks: frame_try_runtime::UpgradeCheckSelect) -> (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. diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 90a52ab697dee..a9e93a16f0713 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -2196,7 +2196,7 @@ impl_runtime_apis! { #[cfg(feature = "try-runtime")] impl frame_try_runtime::TryRuntime for Runtime { - fn on_runtime_upgrade(checks: bool) -> (Weight, Weight) { + fn on_runtime_upgrade(checks: frame_try_runtime::UpgradeCheckSelect) -> (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. diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index 1f20e93f43c30..b454d1e276cc8 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -333,8 +333,10 @@ where /// /// Runs the try-state code both before and after the migration function if `checks` is set to /// `true`. Also, if set to `true`, it runs the `pre_upgrade` and `post_upgrade` hooks. - pub fn try_runtime_upgrade(checks: bool) -> Result { - if checks { + pub fn try_runtime_upgrade( + checks: frame_try_runtime::UpgradeCheckSelect, + ) -> Result { + if checks.try_state() { let _guard = frame_support::StorageNoopGuard::default(); >::try_state( frame_system::Pallet::::block_number(), @@ -344,10 +346,10 @@ where let weight = <(COnRuntimeUpgrade, AllPalletsWithSystem) as OnRuntimeUpgrade>::try_on_runtime_upgrade( - checks, + checks.pre_and_post(), )?; - if checks { + if checks.try_state() { let _guard = frame_support::StorageNoopGuard::default(); >::try_state( frame_system::Pallet::::block_number(), diff --git a/frame/nomination-pools/src/lib.rs b/frame/nomination-pools/src/lib.rs index 5e5385b62acd3..99bfc8b8c36a5 100644 --- a/frame/nomination-pools/src/lib.rs +++ b/frame/nomination-pools/src/lib.rs @@ -2470,12 +2470,17 @@ impl Pallet { for id in reward_pools { let account = Self::create_reward_account(id); - assert!( - T::Currency::free_balance(&account) >= T::Currency::minimum_balance(), - "reward pool of {id}: {:?} (ed = {:?})", - T::Currency::free_balance(&account), - T::Currency::minimum_balance() - ); + if T::Currency::free_balance(&account) < T::Currency::minimum_balance() { + log!( + warn, + "reward pool of {:?}: {:?} (ed = {:?}), should only happen because ED has \ + changed recently. Pool operators should be notified to top up the reward \ + account", + id, + T::Currency::free_balance(&account), + T::Currency::minimum_balance(), + ) + } } let mut pools_members = BTreeMap::::new(); diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index 63c86c1f68459..f7b57f446fee8 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -121,4 +121,4 @@ pub use messages::{ #[cfg(feature = "try-runtime")] mod try_runtime; #[cfg(feature = "try-runtime")] -pub use try_runtime::{Select as TryStateSelect, TryState}; +pub use try_runtime::{Select as TryStateSelect, TryState, UpgradeCheckSelect}; diff --git a/frame/support/src/traits/try_runtime.rs b/frame/support/src/traits/try_runtime.rs index f741ca56a56fc..273af09a145e5 100644 --- a/frame/support/src/traits/try_runtime.rs +++ b/frame/support/src/traits/try_runtime.rs @@ -21,7 +21,7 @@ use impl_trait_for_tuples::impl_for_tuples; use sp_arithmetic::traits::AtLeast32BitUnsigned; use sp_std::prelude::*; -// Which state tests to execute. +/// Which state tests to execute. #[derive(codec::Encode, codec::Decode, Clone)] pub enum Select { /// None of them. @@ -81,6 +81,46 @@ impl sp_std::str::FromStr for Select { } } +/// Select which checks should be run when trying a runtime upgrade upgrade. +#[derive(codec::Encode, codec::Decode, Clone, Debug, Copy)] +pub enum UpgradeCheckSelect { + /// Run no checks. + None, + /// Run the `try_state`, `pre_upgrade` and `post_upgrade` checks. + All, + /// Run the `pre_upgrade` and `post_upgrade` checks. + PreAndPost, + /// Run the `try_state` checks. + TryState, +} + +impl UpgradeCheckSelect { + /// Whether the pre- and post-upgrade checks are selected. + pub fn pre_and_post(&self) -> bool { + matches!(self, Self::All | Self::PreAndPost) + } + + /// Whether the try-state checks are selected. + pub fn try_state(&self) -> bool { + matches!(self, Self::All | Self::TryState) + } +} + +#[cfg(feature = "std")] +impl core::str::FromStr for UpgradeCheckSelect { + type Err = &'static str; + + fn from_str(s: &str) -> Result { + match s.to_lowercase().as_str() { + "none" => Ok(Self::None), + "all" => Ok(Self::All), + "pre-and-post" => Ok(Self::PreAndPost), + "try-state" => Ok(Self::TryState), + _ => Err("Invalid CheckSelector"), + } + } +} + /// 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 diff --git a/frame/try-runtime/src/lib.rs b/frame/try-runtime/src/lib.rs index 99c68d4dc65b8..d8b117d1ff059 100644 --- a/frame/try-runtime/src/lib.rs +++ b/frame/try-runtime/src/lib.rs @@ -20,7 +20,7 @@ #![cfg_attr(not(feature = "std"), no_std)] #![cfg(feature = "try-runtime")] -pub use frame_support::traits::TryStateSelect; +pub use frame_support::traits::{TryStateSelect, UpgradeCheckSelect}; use frame_support::weights::Weight; sp_api::decl_runtime_apis! { @@ -37,7 +37,7 @@ sp_api::decl_runtime_apis! { /// If `checks` is `true`, `pre_migrate` and `post_migrate` of each migration and /// `try_state` of all pallets will be executed. Else, no. If checks are executed, the PoV /// tracking is likely inaccurate. - fn on_runtime_upgrade(checks: bool) -> (Weight, Weight); + fn on_runtime_upgrade(checks: UpgradeCheckSelect) -> (Weight, Weight); /// Execute the given block, but optionally disable state-root and signature checks. /// 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 2b2800d505864..81f81d6a551b9 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 @@ -16,6 +16,7 @@ // limitations under the License. use crate::{build_executor, state_machine_call_with_proof, SharedParams, State, LOG_TARGET}; +use frame_try_runtime::UpgradeCheckSelect; use parity_scale_codec::{Decode, Encode}; use sc_executor::sp_wasm_interface::HostFunctions; use sp_runtime::traits::{Block as BlockT, NumberFor}; @@ -29,12 +30,22 @@ pub struct OnRuntimeUpgradeCmd { #[command(subcommand)] pub state: State, - /// Execute `try_state`, `pre_upgrade` and `post_upgrade` checks as well. + /// Select which optional checks to perform. Selects all when no value is given. /// - /// This will perform more checks, but it will also makes the reported PoV/Weight be - /// inaccurate. - #[clap(long)] - pub checks: bool, + /// - `none`: Perform no checks (default when the arg is not present). + /// - `all`: Perform all checks (default when the arg is present). + /// - `pre-and-post`: Perform pre- and post-upgrade checks. + /// - `try-state`: Perform the try-state checks. + /// + /// Performing any checks will potentially invalidate the measured PoV/Weight. + // NOTE: The clap attributes make it backwards compatible with the previous `--checks` flag. + #[clap(long, + default_value = "None", + default_missing_value = "All", + num_args = 0..=1, + require_equals = true, + verbatim_doc_comment)] + pub checks: UpgradeCheckSelect, } pub(crate) async fn on_runtime_upgrade( From da3a34ff7861d9bb504d013f2ef89e8b0ce2017c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= <123550+andresilva@users.noreply.github.com> Date: Wed, 4 Jan 2023 12:49:02 +0000 Subject: [PATCH 250/715] grandpa: pass the actual best block to voting rules (#12477) * grandpa: pass the actual best block to voting rules * grandpa: add test for checking best header is passed to voting rule --- client/finality-grandpa/src/environment.rs | 131 +++++++++--------- client/finality-grandpa/src/tests.rs | 152 +++++++++++++++++++-- 2 files changed, 207 insertions(+), 76 deletions(-) diff --git a/client/finality-grandpa/src/environment.rs b/client/finality-grandpa/src/environment.rs index 9e63bef78a6a9..40ec720c4e7fe 100644 --- a/client/finality-grandpa/src/environment.rs +++ b/client/finality-grandpa/src/environment.rs @@ -1174,7 +1174,7 @@ where let base_header = match client.header(block)? { Some(h) => h, None => { - debug!( + warn!( target: LOG_TARGET, "Encountered error finding best chain containing {:?}: couldn't find base block", block, @@ -1194,75 +1194,82 @@ where "Finding best chain containing block {:?} with number limit {:?}", block, limit ); - let result = match select_chain.finality_target(block, None).await { - Ok(best_hash) => { - let best_header = client - .header(best_hash)? - .expect("Header known to exist after `finality_target` call; qed"); - - // check if our vote is currently being limited due to a pending change - let limit = limit.filter(|limit| limit < best_header.number()); - - let (base_header, best_header, target_header) = if let Some(target_number) = limit { - let mut target_header = best_header.clone(); - - // walk backwards until we find the target block - loop { - if *target_header.number() < target_number { - unreachable!( - "we are traversing backwards from a known block; \ - blocks are stored contiguously; \ - qed" - ); - } - - if *target_header.number() == target_number { - break - } - - target_header = client - .header(*target_header.parent_hash())? - .expect("Header known to exist after `finality_target` call; qed"); - } - - (base_header, best_header, target_header) - } else { - // otherwise just use the given best as the target - (base_header, best_header.clone(), best_header) - }; + let mut target_header = match select_chain.finality_target(block, None).await { + Ok(target_hash) => client + .header(target_hash)? + .expect("Header known to exist after `finality_target` call; qed"), + Err(err) => { + warn!( + target: LOG_TARGET, + "Encountered error finding best chain containing {:?}: couldn't find target block: {}", + block, + err, + ); - // restrict vote according to the given voting rule, if the - // voting rule doesn't restrict the vote then we keep the - // previous target. - // - // note that we pass the original `best_header`, i.e. before the - // authority set limit filter, which can be considered a - // mandatory/implicit voting rule. - // - // we also make sure that the restricted vote is higher than the - // round base (i.e. last finalized), otherwise the value - // returned by the given voting rule is ignored and the original - // target is used instead. - voting_rule - .restrict_vote(client.clone(), &base_header, &best_header, &target_header) - .await - .filter(|(_, restricted_number)| { - // we can only restrict votes within the interval [base, target] - restricted_number >= base_header.number() && - restricted_number < target_header.number() - }) - .or_else(|| Some((target_header.hash(), *target_header.number()))) + return Ok(None) }, - Err(e) => { + }; + + // NOTE: this is purposefully done after `finality_target` to prevent a case + // where in-between these two requests there is a block import and + // `finality_target` returns something higher than `best_chain`. + let best_header = match select_chain.best_chain().await { + Ok(best_header) => best_header, + Err(err) => { warn!( target: LOG_TARGET, - "Encountered error finding best chain containing {:?}: {}", block, e + "Encountered error finding best chain containing {:?}: couldn't find best block: {}", + block, + err, ); - None + + return Ok(None) }, }; - Ok(result) + if target_header.number() > best_header.number() { + return Err(Error::Safety( + "SelectChain returned a finality target higher than its best block".into(), + )) + } + + // check if our vote is currently being limited due to a pending change, + // in which case we will restrict our target header to the given limit + if let Some(target_number) = limit.filter(|limit| limit < target_header.number()) { + // walk backwards until we find the target block + loop { + if *target_header.number() < target_number { + unreachable!( + "we are traversing backwards from a known block; \ + blocks are stored contiguously; \ + qed" + ); + } + + if *target_header.number() == target_number { + break + } + + target_header = client + .header(*target_header.parent_hash())? + .expect("Header known to exist after `finality_target` call; qed"); + } + } + + // restrict vote according to the given voting rule, if the voting rule + // doesn't restrict the vote then we keep the previous target. + // + // we also make sure that the restricted vote is higher than the round base + // (i.e. last finalized), otherwise the value returned by the given voting + // rule is ignored and the original target is used instead. + Ok(voting_rule + .restrict_vote(client.clone(), &base_header, &best_header, &target_header) + .await + .filter(|(_, restricted_number)| { + // we can only restrict votes within the interval [base, target] + restricted_number >= base_header.number() && restricted_number < target_header.number() + }) + .or_else(|| Some((target_header.hash(), *target_header.number())))) } /// Finalize the given block and apply any authority set changes. If an diff --git a/client/finality-grandpa/src/tests.rs b/client/finality-grandpa/src/tests.rs index 4abcb05406e5b..07ea4649148fb 100644 --- a/client/finality-grandpa/src/tests.rs +++ b/client/finality-grandpa/src/tests.rs @@ -20,6 +20,7 @@ use super::*; use assert_matches::assert_matches; +use async_trait::async_trait; use environment::HasVoted; use futures_timer::Delay; use parking_lot::{Mutex, RwLock}; @@ -33,8 +34,7 @@ use sc_network_test::{ PeersFullClient, TestClient, TestNetFactory, }; use sp_api::{ApiRef, ProvideRuntimeApi}; -use sp_blockchain::Result; -use sp_consensus::BlockOrigin; +use sp_consensus::{BlockOrigin, Error as ConsensusError, SelectChain}; use sp_core::H256; use sp_finality_grandpa::{ AuthorityList, EquivocationProof, GrandpaApi, OpaqueKeyOwnershipProof, GRANDPA_ENGINE_ID, @@ -200,11 +200,50 @@ sp_api::mock_impl_runtime_apis! { } impl GenesisAuthoritySetProvider for TestApi { - fn get(&self) -> Result { + fn get(&self) -> sp_blockchain::Result { Ok(self.genesis_authorities.clone()) } } +/// A mock `SelectChain` that allows the user to set the return values for each +/// method. After the `SelectChain` methods are called the pending value is +/// discarded and another call to set new values must be performed. +#[derive(Clone, Default)] +struct MockSelectChain { + leaves: Arc>>>, + best_chain: Arc::Header>>>, + finality_target: Arc>>, +} + +impl MockSelectChain { + fn set_best_chain(&self, best: ::Header) { + *self.best_chain.lock() = Some(best); + } + + fn set_finality_target(&self, target: Hash) { + *self.finality_target.lock() = Some(target); + } +} + +#[async_trait] +impl SelectChain for MockSelectChain { + async fn leaves(&self) -> Result, ConsensusError> { + Ok(self.leaves.lock().take().unwrap()) + } + + async fn best_chain(&self) -> Result<::Header, ConsensusError> { + Ok(self.best_chain.lock().take().unwrap()) + } + + async fn finality_target( + &self, + _target_hash: Hash, + _maybe_max_number: Option>, + ) -> Result { + Ok(self.finality_target.lock().take().unwrap()) + } +} + const TEST_GOSSIP_DURATION: Duration = Duration::from_millis(500); fn make_ids(keys: &[Ed25519Keyring]) -> AuthorityList { @@ -1291,21 +1330,16 @@ async fn voter_catches_up_to_latest_round_when_behind() { future::select(test, drive_to_completion).await; } -type TestEnvironment = Environment< - substrate_test_runtime_client::Backend, - Block, - TestClient, - N, - LongestChain, - VR, ->; +type TestEnvironment = + Environment; -fn test_environment( +fn test_environment_with_select_chain( link: &TestLinkHalf, keystore: Option, network_service: N, + select_chain: SC, voting_rule: VR, -) -> TestEnvironment +) -> TestEnvironment where N: NetworkT, VR: VotingRule, @@ -1330,7 +1364,7 @@ where authority_set: authority_set.clone(), config: config.clone(), client: link.client.clone(), - select_chain: link.select_chain.clone(), + select_chain, set_id: authority_set.set_id(), voter_set_state: set_state.clone(), voters: Arc::new(authority_set.current_authorities()), @@ -1343,6 +1377,25 @@ where } } +fn test_environment( + link: &TestLinkHalf, + keystore: Option, + network_service: N, + voting_rule: VR, +) -> TestEnvironment, VR> +where + N: NetworkT, + VR: VotingRule, +{ + test_environment_with_select_chain( + link, + keystore, + network_service, + link.select_chain.clone(), + voting_rule, + ) +} + #[tokio::test] async fn grandpa_environment_respects_voting_rules() { use finality_grandpa::voter::Environment; @@ -1455,6 +1508,77 @@ async fn grandpa_environment_respects_voting_rules() { ); } +#[tokio::test] +async fn grandpa_environment_passes_actual_best_block_to_voting_rules() { + // NOTE: this is a "regression" test since initially we were not passing the + // best block to the voting rules + use finality_grandpa::voter::Environment; + + let peers = &[Ed25519Keyring::Alice]; + let voters = make_ids(peers); + + let mut net = GrandpaTestNet::new(TestApi::new(voters), 1, 0); + let peer = net.peer(0); + let network_service = peer.network_service().clone(); + let link = peer.data.lock().take().unwrap(); + let client = peer.client().as_client().clone(); + let select_chain = MockSelectChain::default(); + + // add 42 blocks + peer.push_blocks(42, false); + + // create an environment with a voting rule that always restricts votes to + // before the best block by 5 blocks + let env = test_environment_with_select_chain( + &link, + None, + network_service.clone(), + select_chain.clone(), + voting_rule::BeforeBestBlockBy(5), + ); + + // both best block and finality target are pointing to the same latest block, + // therefore we must restrict our vote on top of the given target (#21) + let hashof21 = client.expect_block_hash_from_id(&BlockId::Number(21)).unwrap(); + select_chain.set_best_chain(client.expect_header(hashof21).unwrap()); + select_chain.set_finality_target(client.expect_header(hashof21).unwrap().hash()); + + assert_eq!( + env.best_chain_containing(peer.client().info().finalized_hash) + .await + .unwrap() + .unwrap() + .1, + 16, + ); + + // the returned finality target is already 11 blocks from the best block, + // therefore there should be no further restriction by the voting rule + let hashof10 = client.expect_block_hash_from_id(&BlockId::Number(10)).unwrap(); + select_chain.set_best_chain(client.expect_header(hashof21).unwrap()); + select_chain.set_finality_target(client.expect_header(hashof10).unwrap().hash()); + + assert_eq!( + env.best_chain_containing(peer.client().info().finalized_hash) + .await + .unwrap() + .unwrap() + .1, + 10, + ); + + // returning a finality target that's higher than the best block is an + // inconsistent state that should be handled + let hashof42 = client.expect_block_hash_from_id(&BlockId::Number(42)).unwrap(); + select_chain.set_best_chain(client.expect_header(hashof21).unwrap()); + select_chain.set_finality_target(client.expect_header(hashof42).unwrap().hash()); + + assert_matches!( + env.best_chain_containing(peer.client().info().finalized_hash).await, + Err(CommandOrError::Error(Error::Safety(_))) + ); +} + #[tokio::test] async fn grandpa_environment_never_overwrites_round_voter_state() { use finality_grandpa::voter::Environment; From 68fc275a8e9e9f84023769c033f7251318544275 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Wed, 4 Jan 2023 14:00:30 +0100 Subject: [PATCH 251/715] Remove `Copy` from `Ensure*` traits (#13043) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Remove Copy from EnsureOp and EnsureOpAssign Signed-off-by: Oliver Tale-Yazdi * Remove Copy from EnsureFrom and EnsureInto Signed-off-by: Oliver Tale-Yazdi * Fix default impl Signed-off-by: Oliver Tale-Yazdi * Reuse assignment code in Ensure trait Signed-off-by: Oliver Tale-Yazdi * Require Ensure for all BaseArithmetic types Signed-off-by: Oliver Tale-Yazdi * Fix assign impls Co-authored-by: Luis Enrique Muñoz Martín Signed-off-by: Oliver Tale-Yazdi * Add tests Signed-off-by: Oliver Tale-Yazdi * Add success doc tests Signed-off-by: Oliver Tale-Yazdi Signed-off-by: Oliver Tale-Yazdi --- primitives/arithmetic/src/traits.rs | 304 +++++++++++++++++++++++----- 1 file changed, 251 insertions(+), 53 deletions(-) diff --git a/primitives/arithmetic/src/traits.rs b/primitives/arithmetic/src/traits.rs index 7fa64d28669d4..9e9dff8e6f9ea 100644 --- a/primitives/arithmetic/src/traits.rs +++ b/primitives/arithmetic/src/traits.rs @@ -57,6 +57,7 @@ pub trait BaseArithmetic: + CheckedMul + CheckedDiv + CheckedRem + + Ensure + Saturating + PartialOrd + Ord @@ -113,6 +114,7 @@ impl< + CheckedMul + CheckedDiv + CheckedRem + + Ensure + Saturating + PartialOrd + Ord @@ -344,13 +346,24 @@ mod ensure { use crate::{ArithmeticError, FixedPointNumber, FixedPointOperand}; /// Performs addition that returns [`ArithmeticError`] instead of wrapping around on overflow. - pub trait EnsureAdd: CheckedAdd + PartialOrd + Zero + Copy { + pub trait EnsureAdd: EnsureAddAssign { /// Adds two numbers, checking for overflow. /// /// If it fails, [`ArithmeticError`] is returned. /// /// Similar to [`CheckedAdd::checked_add()`] but returning an [`ArithmeticError`] error. /// + /// # Examples + /// + /// ``` + /// use sp_arithmetic::traits::EnsureAdd; + /// + /// let a: i32 = 10; + /// let b: i32 = 20; + /// + /// assert_eq!(a.ensure_add(b), Ok(30)); + /// ``` + /// /// ``` /// use sp_arithmetic::{traits::EnsureAdd, ArithmeticError}; /// @@ -367,20 +380,32 @@ mod ensure { /// assert_eq!(overflow(), Err(ArithmeticError::Overflow)); /// assert_eq!(underflow(), Err(ArithmeticError::Underflow)); /// ``` - fn ensure_add(self, v: Self) -> Result { - self.checked_add(&v).ok_or_else(|| error::equivalent(v)) + fn ensure_add(mut self, v: Self) -> Result { + self.ensure_add_assign(v)?; + Ok(self) } } /// Performs subtraction that returns [`ArithmeticError`] instead of wrapping around on /// underflow. - pub trait EnsureSub: CheckedSub + PartialOrd + Zero + Copy { + pub trait EnsureSub: EnsureSubAssign { /// Subtracts two numbers, checking for overflow. /// /// If it fails, [`ArithmeticError`] is returned. /// /// Similar to [`CheckedSub::checked_sub()`] but returning an [`ArithmeticError`] error. /// + /// # Examples + /// + /// ``` + /// use sp_arithmetic::traits::EnsureSub; + /// + /// let a: i32 = 10; + /// let b: i32 = 20; + /// + /// assert_eq!(a.ensure_sub(b), Ok(-10)); + /// ``` + /// /// ``` /// use sp_arithmetic::{traits::EnsureSub, ArithmeticError}; /// @@ -397,20 +422,32 @@ mod ensure { /// assert_eq!(underflow(), Err(ArithmeticError::Underflow)); /// assert_eq!(overflow(), Err(ArithmeticError::Overflow)); /// ``` - fn ensure_sub(self, v: Self) -> Result { - self.checked_sub(&v).ok_or_else(|| error::inverse(v)) + fn ensure_sub(mut self, v: Self) -> Result { + self.ensure_sub_assign(v)?; + Ok(self) } } /// Performs multiplication that returns [`ArithmeticError`] instead of wrapping around on /// overflow. - pub trait EnsureMul: CheckedMul + PartialOrd + Zero + Copy { + pub trait EnsureMul: EnsureMulAssign { /// Multiplies two numbers, checking for overflow. /// /// If it fails, [`ArithmeticError`] is returned. /// /// Similar to [`CheckedMul::checked_mul()`] but returning an [`ArithmeticError`] error. /// + /// # Examples + /// + /// ``` + /// use sp_arithmetic::traits::EnsureMul; + /// + /// let a: i32 = 10; + /// let b: i32 = 20; + /// + /// assert_eq!(a.ensure_mul(b), Ok(200)); + /// ``` + /// /// ``` /// use sp_arithmetic::{traits::EnsureMul, ArithmeticError}; /// @@ -427,19 +464,31 @@ mod ensure { /// assert_eq!(overflow(), Err(ArithmeticError::Overflow)); /// assert_eq!(underflow(), Err(ArithmeticError::Underflow)); /// ``` - fn ensure_mul(self, v: Self) -> Result { - self.checked_mul(&v).ok_or_else(|| error::multiplication(self, v)) + fn ensure_mul(mut self, v: Self) -> Result { + self.ensure_mul_assign(v)?; + Ok(self) } } /// Performs division that returns [`ArithmeticError`] instead of wrapping around on overflow. - pub trait EnsureDiv: CheckedDiv + PartialOrd + Zero + Copy { + pub trait EnsureDiv: EnsureDivAssign { /// Divides two numbers, checking for overflow. /// /// If it fails, [`ArithmeticError`] is returned. /// /// Similar to [`CheckedDiv::checked_div()`] but returning an [`ArithmeticError`] error. /// + /// # Examples + /// + /// ``` + /// use sp_arithmetic::traits::EnsureDiv; + /// + /// let a: i32 = 20; + /// let b: i32 = 10; + /// + /// assert_eq!(a.ensure_div(b), Ok(2)); + /// ``` + /// /// ``` /// use sp_arithmetic::{traits::EnsureDiv, ArithmeticError}; /// @@ -456,15 +505,16 @@ mod ensure { /// assert_eq!(extrinsic_zero(), Err(ArithmeticError::DivisionByZero)); /// assert_eq!(overflow(), Err(ArithmeticError::Overflow)); /// ``` - fn ensure_div(self, v: Self) -> Result { - self.checked_div(&v).ok_or_else(|| error::division(self, v)) + fn ensure_div(mut self, v: Self) -> Result { + self.ensure_div_assign(v)?; + Ok(self) } } - impl EnsureAdd for T {} - impl EnsureSub for T {} - impl EnsureMul for T {} - impl EnsureDiv for T {} + impl EnsureAdd for T {} + impl EnsureSub for T {} + impl EnsureMul for T {} + impl EnsureDiv for T {} /// Meta trait that supports all immutable arithmetic `Ensure*` operations pub trait EnsureOp: EnsureAdd + EnsureSub + EnsureMul + EnsureDiv {} @@ -472,11 +522,23 @@ mod ensure { /// Performs self addition that returns [`ArithmeticError`] instead of wrapping around on /// overflow. - pub trait EnsureAddAssign: EnsureAdd { + pub trait EnsureAddAssign: CheckedAdd + PartialOrd + Zero { /// Adds two numbers overwriting the left hand one, checking for overflow. /// /// If it fails, [`ArithmeticError`] is returned. /// + /// # Examples + /// + /// ``` + /// use sp_arithmetic::traits::EnsureAddAssign; + /// + /// let mut a: i32 = 10; + /// let b: i32 = 20; + /// + /// a.ensure_add_assign(b).unwrap(); + /// assert_eq!(a, 30); + /// ``` + /// /// ``` /// use sp_arithmetic::{traits::EnsureAddAssign, ArithmeticError}; /// @@ -496,18 +558,30 @@ mod ensure { /// assert_eq!(underflow(), Err(ArithmeticError::Underflow)); /// ``` fn ensure_add_assign(&mut self, v: Self) -> Result<(), ArithmeticError> { - *self = self.ensure_add(v)?; + *self = self.checked_add(&v).ok_or_else(|| error::equivalent(&v))?; Ok(()) } } /// Performs self subtraction that returns [`ArithmeticError`] instead of wrapping around on /// underflow. - pub trait EnsureSubAssign: EnsureSub { + pub trait EnsureSubAssign: CheckedSub + PartialOrd + Zero { /// Subtracts two numbers overwriting the left hand one, checking for overflow. /// /// If it fails, [`ArithmeticError`] is returned. /// + /// # Examples + /// + /// ``` + /// use sp_arithmetic::traits::EnsureSubAssign; + /// + /// let mut a: i32 = 10; + /// let b: i32 = 20; + /// + /// a.ensure_sub_assign(b).unwrap(); + /// assert_eq!(a, -10); + /// ``` + /// /// ``` /// use sp_arithmetic::{traits::EnsureSubAssign, ArithmeticError}; /// @@ -527,18 +601,30 @@ mod ensure { /// assert_eq!(overflow(), Err(ArithmeticError::Overflow)); /// ``` fn ensure_sub_assign(&mut self, v: Self) -> Result<(), ArithmeticError> { - *self = self.ensure_sub(v)?; + *self = self.checked_sub(&v).ok_or_else(|| error::inverse(&v))?; Ok(()) } } /// Performs self multiplication that returns [`ArithmeticError`] instead of wrapping around on /// overflow. - pub trait EnsureMulAssign: EnsureMul { + pub trait EnsureMulAssign: CheckedMul + PartialOrd + Zero { /// Multiplies two numbers overwriting the left hand one, checking for overflow. /// /// If it fails, [`ArithmeticError`] is returned. /// + /// # Examples + /// + /// ``` + /// use sp_arithmetic::traits::EnsureMulAssign; + /// + /// let mut a: i32 = 10; + /// let b: i32 = 20; + /// + /// a.ensure_mul_assign(b).unwrap(); + /// assert_eq!(a, 200); + /// ``` + /// /// ``` /// use sp_arithmetic::{traits::EnsureMulAssign, ArithmeticError}; /// @@ -558,18 +644,30 @@ mod ensure { /// assert_eq!(underflow(), Err(ArithmeticError::Underflow)); /// ``` fn ensure_mul_assign(&mut self, v: Self) -> Result<(), ArithmeticError> { - *self = self.ensure_mul(v)?; + *self = self.checked_mul(&v).ok_or_else(|| error::multiplication(self, &v))?; Ok(()) } } /// Performs self division that returns [`ArithmeticError`] instead of wrapping around on /// overflow. - pub trait EnsureDivAssign: EnsureDiv { + pub trait EnsureDivAssign: CheckedDiv + PartialOrd + Zero { /// Divides two numbers overwriting the left hand one, checking for overflow. /// /// If it fails, [`ArithmeticError`] is returned. /// + /// # Examples + /// + /// ``` + /// use sp_arithmetic::traits::EnsureDivAssign; + /// + /// let mut a: i32 = 20; + /// let b: i32 = 10; + /// + /// a.ensure_div_assign(b).unwrap(); + /// assert_eq!(a, 2); + /// ``` + /// /// ``` /// use sp_arithmetic::{traits::EnsureDivAssign, ArithmeticError, FixedI64}; /// @@ -589,15 +687,15 @@ mod ensure { /// assert_eq!(overflow(), Err(ArithmeticError::Overflow)); /// ``` fn ensure_div_assign(&mut self, v: Self) -> Result<(), ArithmeticError> { - *self = self.ensure_div(v)?; + *self = self.checked_div(&v).ok_or_else(|| error::division(self, &v))?; Ok(()) } } - impl EnsureAddAssign for T {} - impl EnsureSubAssign for T {} - impl EnsureMulAssign for T {} - impl EnsureDivAssign for T {} + impl EnsureAddAssign for T {} + impl EnsureSubAssign for T {} + impl EnsureMulAssign for T {} + impl EnsureDivAssign for T {} /// Meta trait that supports all assigned arithmetic `Ensure*` operations pub trait EnsureOpAssign: @@ -609,7 +707,6 @@ mod ensure { { } - /// Meta trait that supports all arithmetic operations pub trait Ensure: EnsureOp + EnsureOpAssign {} impl Ensure for T {} @@ -643,7 +740,7 @@ mod ensure { d: D, ) -> Result { ::checked_from_rational(n, d) - .ok_or_else(|| error::division(n, d)) + .ok_or_else(|| error::division(&n, &d)) } /// Ensure multiplication for integer type `N`. Equal to `self * n`. @@ -670,7 +767,7 @@ mod ensure { /// assert_eq!(underflow(), Err(ArithmeticError::Underflow)); /// ``` fn ensure_mul_int(self, n: N) -> Result { - self.checked_mul_int(n).ok_or_else(|| error::multiplication(self, n)) + self.checked_mul_int(n).ok_or_else(|| error::multiplication(&self, &n)) } /// Ensure division for integer type `N`. Equal to `self / d`. @@ -697,16 +794,14 @@ mod ensure { /// assert_eq!(overflow(), Err(ArithmeticError::Overflow)); /// ``` fn ensure_div_int(self, d: D) -> Result { - self.checked_div_int(d).ok_or_else(|| error::division(self, d)) + self.checked_div_int(d).ok_or_else(|| error::division(&self, &d)) } } impl EnsureFixedPointNumber for T {} /// Similar to [`TryFrom`] but returning an [`ArithmeticError`] error. - pub trait EnsureFrom: - TryFrom + PartialOrd + Zero + Copy - { + pub trait EnsureFrom: TryFrom + PartialOrd + Zero { /// Performs the conversion returning an [`ArithmeticError`] if fails. /// /// Similar to [`TryFrom::try_from()`] but returning an [`ArithmeticError`] error. @@ -728,14 +823,13 @@ mod ensure { /// assert_eq!(underflow(), Err(ArithmeticError::Underflow)); /// ``` fn ensure_from(other: T) -> Result { - Self::try_from(other).map_err(|_| error::equivalent(other)) + let err = error::equivalent(&other); + Self::try_from(other).map_err(|_| err) } } /// Similar to [`TryInto`] but returning an [`ArithmeticError`] error. - pub trait EnsureInto: - TryInto + PartialOrd + Zero + Copy - { + pub trait EnsureInto: TryInto + PartialOrd + Zero { /// Performs the conversion returning an [`ArithmeticError`] if fails. /// /// Similar to [`TryInto::try_into()`] but returning an [`ArithmeticError`] error @@ -757,12 +851,13 @@ mod ensure { /// assert_eq!(underflow(), Err(ArithmeticError::Underflow)); /// ``` fn ensure_into(self) -> Result { - self.try_into().map_err(|_| error::equivalent(self)) + let err = error::equivalent(&self); + self.try_into().map_err(|_| err) } } - impl + PartialOrd + Zero + Copy, S: PartialOrd + Zero + Copy> EnsureFrom for T {} - impl + PartialOrd + Zero + Copy, S: PartialOrd + Zero + Copy> EnsureInto for T {} + impl + PartialOrd + Zero, S: PartialOrd + Zero> EnsureFrom for T {} + impl + PartialOrd + Zero, S: PartialOrd + Zero> EnsureInto for T {} mod error { use super::{ArithmeticError, Zero}; @@ -773,9 +868,9 @@ mod ensure { Positive, } - impl From for Signum { - fn from(value: T) -> Self { - if value < Zero::zero() { + impl From<&T> for Signum { + fn from(value: &T) -> Self { + if value < &Zero::zero() { Signum::Negative } else { Signum::Positive @@ -795,23 +890,23 @@ mod ensure { } } - pub fn equivalent(r: R) -> ArithmeticError { + pub fn equivalent(r: &R) -> ArithmeticError { match Signum::from(r) { Signum::Negative => ArithmeticError::Underflow, Signum::Positive => ArithmeticError::Overflow, } } - pub fn inverse(r: R) -> ArithmeticError { + pub fn inverse(r: &R) -> ArithmeticError { match Signum::from(r) { Signum::Negative => ArithmeticError::Overflow, Signum::Positive => ArithmeticError::Underflow, } } - pub fn multiplication( - l: L, - r: R, + pub fn multiplication( + l: &L, + r: &R, ) -> ArithmeticError { match Signum::from(l) * Signum::from(r) { Signum::Negative => ArithmeticError::Underflow, @@ -819,9 +914,9 @@ mod ensure { } } - pub fn division( - n: N, - d: D, + pub fn division( + n: &N, + d: &D, ) -> ArithmeticError { if d.is_zero() { ArithmeticError::DivisionByZero @@ -831,3 +926,106 @@ mod ensure { } } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::ArithmeticError; + use rand::{seq::SliceRandom, thread_rng, Rng}; + + #[test] + fn ensure_add_works() { + test_ensure(values(), &EnsureAdd::ensure_add, &CheckedAdd::checked_add); + } + + #[test] + fn ensure_sub_works() { + test_ensure(values(), &EnsureSub::ensure_sub, &CheckedSub::checked_sub); + } + + #[test] + fn ensure_mul_works() { + test_ensure(values(), &EnsureMul::ensure_mul, &CheckedMul::checked_mul); + } + + #[test] + fn ensure_div_works() { + test_ensure(values(), &EnsureDiv::ensure_div, &CheckedDiv::checked_div); + } + + #[test] + fn ensure_add_assign_works() { + test_ensure_assign(values(), &EnsureAddAssign::ensure_add_assign, &EnsureAdd::ensure_add); + } + + #[test] + fn ensure_sub_assign_works() { + test_ensure_assign(values(), &EnsureSubAssign::ensure_sub_assign, &EnsureSub::ensure_sub); + } + + #[test] + fn ensure_mul_assign_works() { + test_ensure_assign(values(), &EnsureMulAssign::ensure_mul_assign, &&EnsureMul::ensure_mul); + } + + #[test] + fn ensure_div_assign_works() { + test_ensure_assign(values(), &EnsureDivAssign::ensure_div_assign, &EnsureDiv::ensure_div); + } + + /// Test that the ensured function returns the expected un-ensured value. + fn test_ensure(pairs: Vec<(V, V)>, ensured: E, unensured: P) + where + V: Ensure + core::fmt::Debug + Copy, + E: Fn(V, V) -> Result, + P: Fn(&V, &V) -> Option, + { + for (a, b) in pairs.into_iter() { + match ensured(a, b) { + Ok(c) => { + assert_eq!(unensured(&a, &b), Some(c)) + }, + Err(_) => { + assert!(unensured(&a, &b).is_none()); + }, + } + } + } + + /// Test that the ensured function modifies `self` to the expected un-ensured value. + fn test_ensure_assign(pairs: Vec<(V, V)>, ensured: E, unensured: P) + where + V: Ensure + std::panic::RefUnwindSafe + std::panic::UnwindSafe + core::fmt::Debug + Copy, + E: Fn(&mut V, V) -> Result<(), ArithmeticError>, + P: Fn(V, V) -> Result + std::panic::RefUnwindSafe, + { + for (mut a, b) in pairs.into_iter() { + let old_a = a; + + match ensured(&mut a, b) { + Ok(()) => { + assert_eq!(unensured(old_a, b), Ok(a)); + }, + Err(err) => { + assert_eq!(a, old_a, "A stays unmodified in the error case"); + assert_eq!(unensured(old_a, b), Err(err)); + }, + } + } + } + + /// Generates some good values for testing integer arithmetic. + fn values() -> Vec<(i32, i32)> { + let mut rng = thread_rng(); + let mut one_dimension = || { + let mut ret = vec![0i32; 1007]; + // Some hard-coded interesting values. + ret[..7].copy_from_slice(&[-1, 0, 1, i32::MIN, i32::MAX, i32::MAX - 1, i32::MIN + 1]); + // … and some random ones. + rng.fill(&mut ret[7..]); + ret.shuffle(&mut rng); + ret + }; + one_dimension().into_iter().zip(one_dimension().into_iter()).collect() + } +} From ea387c634715793f806286abf1e64cabf9b7026f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 4 Jan 2023 14:17:18 +0100 Subject: [PATCH 252/715] Aura: Do not verify on state import (#13058) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Aura: Do not verify on state import When we import the state, we can not fetch authorities to verify the seal etc. So, we can directly skip any verification. * Skip checks as well for gap sync * Update client/consensus/aura/src/import_queue.rs Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> * Review comment Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> --- client/consensus/aura/src/import_queue.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/client/consensus/aura/src/import_queue.rs b/client/consensus/aura/src/import_queue.rs index d5cf40f33359e..0973b33d402e6 100644 --- a/client/consensus/aura/src/import_queue.rs +++ b/client/consensus/aura/src/import_queue.rs @@ -186,6 +186,19 @@ where &mut self, mut block: BlockImportParams, ) -> Result<(BlockImportParams, Option)>>), String> { + // When importing whole state we don't verify the seal as the state is not available. + if block.with_state() { + return Ok((block, Default::default())) + } + + // Skip checks that include execution, if being told so. + // + // This is done for example when gap syncing and it is expected that the block after the gap + // was checked/chosen properly, e.g. by warp syncing to this block using a finality proof. + if block.state_action.skip_execution_checks() { + return Ok((block, Default::default())) + } + let hash = block.header.hash(); let parent_hash = *block.header.parent_hash(); let authorities = authorities( From 05fe10b527dbf437aa48e530701110e2043a4816 Mon Sep 17 00:00:00 2001 From: Anton Date: Thu, 5 Jan 2023 16:03:41 +0400 Subject: [PATCH 253/715] upgrade libp2p to 0.50.0 (#12734) * upgrade libp2p to 0.50.0 * on_swarm_event and on_connection_handler_event * replace `Swarm::new` with `Swarm::with_threadpool_executor` * on_swarm_event and on_connection_handler_event part 2 * on_swarm_event and on_connection_handler_event part 3 * on_swarm_event and on_connection_handler_event part 4 * update libp2p * libp2p 0.50.0 * rename OutboundQueryCompleted to OutboundQueryProgressed refs https://github.com/libp2p/rust-libp2p/pull/2712 * remove unused var * accumulate outbound_query_records until query is finished * format code * use p_handler instead of new_handler https://github.com/paritytech/substrate/pull/12734#discussion_r1027640610 * pass ListenFailure to kademlia https://github.com/paritytech/substrate/pull/12734#discussion_r1034716664 * use tokio executor in tests https://github.com/paritytech/substrate/pull/12734#discussion_r1039291776 * use chrono Local::now instead of deprecated Local::today * remove unused vars from request_responses tests * attempt to fix pallet UI tests * restart CI * restart CI * restart CI * restart CI * restart CI * restart CI * restart CI * restart CI --- Cargo.lock | 3037 +++++++++++------ client/authority-discovery/Cargo.toml | 2 +- client/cli/Cargo.toml | 2 +- client/cli/src/runner.rs | 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 | 2 +- client/network/src/discovery.rs | 272 +- client/network/src/peer_info.rs | 295 +- client/network/src/protocol.rs | 88 +- .../src/protocol/notifications/behaviour.rs | 851 ++--- .../src/protocol/notifications/tests.rs | 101 +- client/network/src/request_responses.rs | 230 +- client/network/src/service.rs | 28 +- client/network/src/transport.rs | 10 +- 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 +- client/telemetry/src/transport.rs | 2 +- ...ev_mode_without_arg_max_encoded_len.stderr | 2 +- ...age_ensure_span_are_ok_on_wrong_gen.stderr | 10 +- ...re_span_are_ok_on_wrong_gen_unnamed.stderr | 10 +- .../pallet_ui/storage_info_unsatisfied.stderr | 2 +- .../storage_info_unsatisfied_nmap.stderr | 2 +- 31 files changed, 2970 insertions(+), 2002 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f82343e442a89..d333b79c8c403 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 0.26.2", ] [[package]] @@ -36,13 +36,34 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "aead" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fc95d1bdb8e6666b2b217308eeeb09f2d6728d104be3e31916cc74d15420331" +dependencies = [ + "generic-array 0.14.6", +] + [[package]] name = "aead" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b613b8e1e3cf911a086f53f03bf286f52fd7a7258e4fa606f0ef220d39d8877" dependencies = [ - "generic-array 0.14.4", + "generic-array 0.14.6", + "rand_core 0.6.4", +] + +[[package]] +name = "aes" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "884391ef1066acaa41e766ba8f596341b96e93ce34f9a43e7d24bf0a0eaf0561" +dependencies = [ + "aes-soft", + "aesni", + "cipher 0.2.5", ] [[package]] @@ -52,45 +73,88 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" dependencies = [ "cfg-if", - "cipher", + "cipher 0.3.0", "cpufeatures", "opaque-debug 0.3.0", ] +[[package]] +name = "aes-gcm" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5278b5fabbb9bd46e24aa69b2fdea62c99088e0a950a9be40e3e0101298f88da" +dependencies = [ + "aead 0.3.2", + "aes 0.6.0", + "cipher 0.2.5", + "ctr 0.6.0", + "ghash 0.3.1", + "subtle", +] + [[package]] name = "aes-gcm" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df5f85a83a7d8b0442b6aa7b504b8212c1733da07b98aae43d4bc21b2cb3cdf6" dependencies = [ - "aead", - "aes", - "cipher", - "ctr", - "ghash", + "aead 0.4.3", + "aes 0.7.5", + "cipher 0.3.0", + "ctr 0.8.0", + "ghash 0.4.4", "subtle", ] +[[package]] +name = "aes-soft" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be14c7498ea50828a38d0e24a765ed2effe92a705885b57d029cd67d45744072" +dependencies = [ + "cipher 0.2.5", + "opaque-debug 0.3.0", +] + +[[package]] +name = "aesni" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea2e11f5e94c2f7d386164cc2aa1f97823fed6f259e486940a71c174dd01b0ce" +dependencies = [ + "cipher 0.2.5", + "opaque-debug 0.3.0", +] + [[package]] name = "ahash" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" dependencies = [ - "getrandom 0.2.3", + "getrandom 0.2.8", "once_cell", "version_check", ] [[package]] name = "aho-corasick" -version = "0.7.18" +version = "0.7.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" dependencies = [ "memchr", ] +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "ansi_term" version = "0.12.1" @@ -102,30 +166,36 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.66" +version = "1.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6" +checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61" [[package]] name = "approx" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "072df7202e63b127ab55acfe16ce97013d5b97bf160489336d3f1840fd78e99e" +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" dependencies = [ "num-traits", ] [[package]] name = "arbitrary" -version = "1.0.0" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29d47fbf90d5149a107494b15a7dc8d69b351be2db3bb9691740e88ec17fd880" + +[[package]] +name = "arc-swap" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "698b65a961a9d730fb45b6b0327e20207810c9f61ee421b082b27ba003f49e2b" +checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6" [[package]] name = "array-bytes" -version = "4.1.0" +version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a913633b0c922e6b745072795f50d90ebea78ba31a57e2ac8c2fc7b50950949" +checksum = "f52f63c5c1316a16a4b35eaac8b76a98248961a533f061684cb2a7cb0eafb6c6" [[package]] name = "arrayref" @@ -146,114 +216,133 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" [[package]] -name = "asn1_der" -version = "0.7.4" +name = "asn1-rs" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d6e24d2cce90c53b948c46271bfb053e4bdc2db9b5d3f65e20f8cf28a1b7fc3" +checksum = "30ff05a702273012438132f449575dbc804e27b2f3cbe3069aa237d26c98fa33" +dependencies = [ + "asn1-rs-derive 0.1.0", + "asn1-rs-impl", + "displaydoc", + "nom", + "num-traits", + "rusticata-macros", + "thiserror", + "time 0.3.17", +] [[package]] -name = "assert_cmd" -version = "2.0.6" +name = "asn1-rs" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba45b8163c49ab5f972e59a8a5a03b6d2972619d486e19ec9fe744f7c2753d3c" +checksum = "cf6690c370453db30743b373a60ba498fc0d6d83b11f4abfd87a84a075db5dd4" dependencies = [ - "bstr 1.0.1", - "doc-comment", - "predicates", - "predicates-core", - "predicates-tree", - "wait-timeout", + "asn1-rs-derive 0.4.0", + "asn1-rs-impl", + "displaydoc", + "nom", + "num-traits", + "rusticata-macros", + "thiserror", + "time 0.3.17", ] [[package]] -name = "assert_matches" -version = "1.5.0" +name = "asn1-rs-derive" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" +checksum = "db8b7511298d5b7784b40b092d9e9dcd3a627a5707e4b5e507931ab0d44eeebf" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] [[package]] -name = "async-channel" -version = "1.6.1" +name = "asn1-rs-derive" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2114d64672151c0c5eaa5e131ec84a74f06e1e559830dabba01ca30605d66319" +checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c" dependencies = [ - "concurrent-queue", - "event-listener", - "futures-core", + "proc-macro2", + "quote", + "syn", + "synstructure", ] [[package]] -name = "async-executor" -version = "1.4.0" +name = "asn1-rs-impl" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb877970c7b440ead138f6321a3b5395d6061183af779340b65e20c0fede9146" +checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed" dependencies = [ - "async-task", - "concurrent-queue", - "fastrand", - "futures-lite", - "once_cell", - "vec-arena", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "async-global-executor" -version = "2.0.2" +name = "asn1_der" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e22d1f4b888c298a027c99dc9048015fac177587de20fc30232a057dfbe24a21" + +[[package]] +name = "assert_cmd" +version = "2.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9586ec52317f36de58453159d48351bc244bc24ced3effc1fce22f3d48664af6" +checksum = "fa3d466004a8b4cb1bc34044240a2fd29d17607e2e3bd613eb44fd48e8100da3" dependencies = [ - "async-channel", - "async-executor", - "async-io", - "async-mutex", - "blocking", - "futures-lite", - "num_cpus", - "once_cell", + "bstr 1.1.0", + "doc-comment", + "predicates", + "predicates-core", + "predicates-tree", + "wait-timeout", ] +[[package]] +name = "assert_matches" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" + [[package]] name = "async-io" -version = "1.6.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a811e6a479f2439f0c04038796b5cfb3d2ad56c230e0f2d3f7b04d68cfee607b" +checksum = "8c374dda1ed3e7d8f0d9ba58715f924862c63eae6849c92d3a18e7fbde9e2794" dependencies = [ + "async-lock", + "autocfg", "concurrent-queue", "futures-lite", "libc", "log", - "once_cell", "parking", "polling", "slab", "socket2", "waker-fn", - "winapi", + "windows-sys 0.42.0", ] [[package]] name = "async-lock" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e97a171d191782fba31bb902b14ad94e24a68145032b7eedf871ab0bc0d077b6" -dependencies = [ - "event-listener", -] - -[[package]] -name = "async-mutex" -version = "1.4.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479db852db25d9dbf6204e6cb6253698f175c15726470f78af0d918e99d6156e" +checksum = "c8101efe8695a6c17e02911402145357e718ac92d3ff88ae8419e84b1707b685" dependencies = [ "event-listener", + "futures-lite", ] [[package]] name = "async-stream" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "171374e7e3b2504e0e5236e3b59260560f9fe94bfe9ac39ba5e4e929c5590625" +checksum = "dad5c83079eae9969be7fadefe640a1c566901f05ff91ab221de4b6f68d9507e" dependencies = [ "async-stream-impl", "futures-core", @@ -261,26 +350,20 @@ dependencies = [ [[package]] name = "async-stream-impl" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "648ed8c8d2ce5409ccd57453d9d1b214b342a0d69376a6feda1fd6cae3299308" +checksum = "10f203db73a71dfa2fb6dd22763990fa26f3d2625a6da2da900d23b87d26be27" dependencies = [ "proc-macro2", "quote", "syn", ] -[[package]] -name = "async-task" -version = "4.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91831deabf0d6d7ec49552e489aed63b7456a7a3c46cff62adad428110b0af0" - [[package]] name = "async-trait" -version = "0.1.59" +version = "0.1.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6e93155431f3931513b243d371981bb2770112b370c82745a1d19d2f99364" +checksum = "677d1d8ab452a3936018a687b20e6f7cf5363d713b732b8884001317b0e48aa3" dependencies = [ "proc-macro2", "quote", @@ -289,9 +372,9 @@ dependencies = [ [[package]] name = "asynchronous-codec" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0de5164e5edbf51c45fb8c2d9664ae1c095cce1b265ecf7569093c0d66ef690" +checksum = "06a0daa378f5fd10634e44b0a29b2a87b890657658e072a30d6f26e57ddee182" dependencies = [ "bytes", "futures-sink", @@ -312,7 +395,7 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "hermit-abi", + "hermit-abi 0.1.19", "libc", "winapi", ] @@ -333,16 +416,16 @@ dependencies = [ "cc", "cfg-if", "libc", - "miniz_oxide 0.6.2", + "miniz_oxide", "object 0.30.0", "rustc-demangle", ] [[package]] name = "base-x" -version = "0.2.8" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4521f3e3d031370679b3b140beb36dfe4801b09ac77e30c61941f97df3ef28b" +checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270" [[package]] name = "base16ct" @@ -358,21 +441,21 @@ checksum = "6107fe1be6682a68940da878d9e9f5e90ca5745b3dec9fd1bb393c8777d4f581" [[package]] name = "base64" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64ct" -version = "1.5.1" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bdca834647821e0b13d9539a8634eb62d3501b6b6c2cec1722786ee6671b851" +checksum = "b645a089122eccb6111b4f81cbc1a49f5900ac4666bb93ac027feaecf15607bf" [[package]] name = "beef" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bed554bd50246729a1ec158d08aa3235d1b69d94ad120ebe187e28894787e736" +checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1" dependencies = [ "serde", ] @@ -489,9 +572,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitvec" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1489fcb93a5bb47da0462ca93ad252ad6af2145cce58d10d46a83931ba9f016b" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" dependencies = [ "funty", "radium", @@ -501,11 +584,11 @@ dependencies = [ [[package]] name = "blake2" -version = "0.10.4" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9cf849ee05b2ee5fba5e36f97ff8ec2533916700fc0758d40d92136a42f3388" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" dependencies = [ - "digest 0.10.3", + "digest 0.10.6", ] [[package]] @@ -516,7 +599,7 @@ checksum = "72936ee4afc7f8f736d1c38383b56480b5497b4617b4a77bdbf1d2ababc76127" dependencies = [ "arrayref", "arrayvec 0.7.2", - "constant_time_eq", + "constant_time_eq 0.1.5", ] [[package]] @@ -527,20 +610,20 @@ checksum = "db539cc2b5f6003621f1cd9ef92d7ded8ea5232c7de0f9faa2de251cd98730d4" dependencies = [ "arrayref", "arrayvec 0.7.2", - "constant_time_eq", + "constant_time_eq 0.1.5", ] [[package]] name = "blake3" -version = "1.3.1" +version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a08e53fc5a564bb15bfe6fae56bd71522205f1f91893f9c0116edad6496c183f" +checksum = "42ae2468a89544a466886840aa467a25b766499f4f04bf7d9fcd10ecee9fccef" dependencies = [ "arrayref", "arrayvec 0.7.2", "cc", "cfg-if", - "constant_time_eq", + "constant_time_eq 0.2.4", ] [[package]] @@ -549,7 +632,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" dependencies = [ - "block-padding", + "block-padding 0.1.5", "byte-tools", "byteorder", "generic-array 0.12.4", @@ -561,16 +644,26 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" dependencies = [ - "generic-array 0.14.4", + "generic-array 0.14.6", ] [[package]] name = "block-buffer" -version = "0.10.0" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" +dependencies = [ + "generic-array 0.14.6", +] + +[[package]] +name = "block-modes" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1d36a02058e76b040de25a4464ba1c80935655595b661505c8b39b664828b95" +checksum = "57a0e8073e8baa88212fb5823574c02ebccb395136ba9a164ab89379ec6072f0" dependencies = [ - "generic-array 0.14.4", + "block-padding 0.2.1", + "cipher 0.2.5", ] [[package]] @@ -583,18 +676,10 @@ dependencies = [ ] [[package]] -name = "blocking" -version = "1.0.2" +name = "block-padding" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e170dbede1f740736619b776d7251cb1b9095c435c34d8ca9f57fcd2f335e9" -dependencies = [ - "async-channel", - "async-task", - "atomic-waker", - "fastrand", - "futures-lite", - "once_cell", -] +checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" [[package]] name = "bs58" @@ -604,9 +689,9 @@ checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" [[package]] name = "bstr" -version = "0.2.15" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a40b47ad93e1a5404e6c18dec46b628214fee441c70f4ab5d6942142cc268a3d" +checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" dependencies = [ "lazy_static", "memchr", @@ -616,9 +701,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fca0852af221f458706eb0725c03e4ed6c46af9ac98e6a689d5e634215d594dd" +checksum = "b45ea9b00a7b3f2988e9a65ad3917e62123c38dba709b666506207be96d1790b" dependencies = [ "memchr", "once_cell", @@ -637,15 +722,15 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.6.1" +version = "3.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63396b8a4b9de3f4fdfb320ab6080762242f66a8ef174c49d8e19b674db4cdbe" +checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" [[package]] name = "byte-slice-cast" -version = "1.0.0" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65c1bf4a04a88c54f589125563643d773f3254b5c38571395e2b591c693bbc81" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" [[package]] name = "byte-tools" @@ -661,9 +746,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "1.1.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" +checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" [[package]] name = "bzip2-sys" @@ -676,26 +761,20 @@ dependencies = [ "pkg-config", ] -[[package]] -name = "cache-padded" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "631ae5198c9be5e753e5cc215e1bd73c2b466a3565173db433f52bb9d3e66dba" - [[package]] name = "camino" -version = "1.0.4" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4648c6d00a709aa069a236adcaae4f605a6241c72bf5bee79331a4b625921a9" +checksum = "88ad0e1e3e88dd237a156ab9f571021b8a158caa0ae44b1968a241efb5144c1e" dependencies = [ "serde", ] [[package]] name = "cargo-platform" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0226944a63d1bf35a3b5f948dd7c59e263db83695c9e8bffc4037de02e30f1d7" +checksum = "cbdb825da8a5df079a43676dbe042702f1707b1109f713a01420fbb4cc71fa27" dependencies = [ "serde", ] @@ -708,29 +787,37 @@ checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa" dependencies = [ "camino", "cargo-platform", - "semver 1.0.4", + "semver 1.0.16", "serde", "serde_json", ] [[package]] name = "cast" -version = "0.2.3" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b9434b9a5aa1450faa3f9cb14ea0e8c53bb5d2b3c1bfd1ab4fc03e9f33fbfb0" -dependencies = [ - "rustc_version 0.2.3", -] +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.0.73" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" +checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d" dependencies = [ "jobserver", ] +[[package]] +name = "ccm" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aca1a8fbc20b50ac9673ff014abfb2b5f4085ee1a850d408f14a159c5853ac7" +dependencies = [ + "aead 0.3.2", + "cipher 0.2.5", + "subtle", +] + [[package]] name = "cexpr" version = "0.6.0" @@ -768,7 +855,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c80e5460aa66fe3b91d40bcbdab953a597b60053e34d684ac6903f863b680a6" dependencies = [ "cfg-if", - "cipher", + "cipher 0.3.0", "cpufeatures", "zeroize", ] @@ -779,9 +866,9 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a18446b09be63d457bbec447509e85f662f32952b035ce892290396bc0b0cff5" dependencies = [ - "aead", + "aead 0.4.3", "chacha20", - "cipher", + "cipher 0.3.0", "poly1305", "zeroize", ] @@ -791,7 +878,7 @@ name = "chain-spec-builder" version = "2.0.0" dependencies = [ "ansi_term", - "clap 4.0.11", + "clap 4.0.32", "node-cli", "rand 0.8.5", "sc-chain-spec", @@ -802,14 +889,16 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.19" +version = "0.4.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f" dependencies = [ - "libc", + "iana-time-zone", + "js-sys", "num-integer", "num-traits", - "time", + "time 0.1.45", + "wasm-bindgen", "winapi", ] @@ -826,13 +915,22 @@ dependencies = [ "unsigned-varint", ] +[[package]] +name = "cipher" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801" +dependencies = [ + "generic-array 0.14.6", +] + [[package]] name = "cipher" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" dependencies = [ - "generic-array 0.14.4", + "generic-array 0.14.6", ] [[package]] @@ -846,9 +944,9 @@ dependencies = [ [[package]] name = "clang-sys" -version = "1.2.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "853eda514c284c2287f4bf20ae614f8781f40a81d32ecda6e91449304dfe077c" +checksum = "fa2e27ae6ab525c3d369ded447057bca5438d86dc3a68f6faafb8269ba82ebf3" dependencies = [ "glob", "libc", @@ -868,14 +966,14 @@ dependencies = [ [[package]] name = "clap" -version = "4.0.11" +version = "4.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ed45cc2c62a3eff523e718d8576ba762c83a3146151093283ac62ae11933a73" +checksum = "a7db700bc935f9e43e88d00b0850dae18a63773cfbec6d8e070fccf7fef89a39" dependencies = [ - "atty", "bitflags", "clap_derive", "clap_lex", + "is-terminal", "once_cell", "strsim", "termcolor", @@ -883,18 +981,18 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.0.5" +version = "4.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96b0fba905b035a30d25c1b585bf1171690712fbb0ad3ac47214963aa4acc36c" +checksum = "10861370d2ba66b0f5989f83ebf35db6421713fd92351790e7fdd6c36774c56b" dependencies = [ - "clap 4.0.11", + "clap 4.0.32", ] [[package]] name = "clap_derive" -version = "4.0.10" +version = "4.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db342ce9fda24fb191e2ed4e102055a4d381c1086a06630174cd8da8d5d917ce" +checksum = "0177313f9f02afc995627906bbd8967e2be069f5261954222dac78290c2b9014" dependencies = [ "heck", "proc-macro-error", @@ -924,9 +1022,9 @@ dependencies = [ [[package]] name = "comfy-table" -version = "6.0.0" +version = "6.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "121d8a5b0346092c18a4b2fd6f620d7a06f0eb7ac0a45860939a0884bc579c56" +checksum = "6e7b787b0dc42e8111badfdbe4c3059158ccb2db8780352fa1b01e8ccf45cc4d" dependencies = [ "strum", "strum_macros", @@ -935,18 +1033,18 @@ dependencies = [ [[package]] name = "concurrent-queue" -version = "1.2.2" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ed07550be01594c6026cff2a1d7fe9c8f683caa798e12b68694ac9e88286a3" +checksum = "bd7bef69dc86e3c610e4e7aed41035e2a7ed12e72dd7530f61327a6579a4390b" dependencies = [ - "cache-padded", + "crossbeam-utils", ] [[package]] name = "const-oid" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "722e23542a15cea1f65d4a1419c4cfd7a26706c70871a13a04238ca3f40f1661" +checksum = "cec318a675afcb6a1ea1d4340e2d377e56e47c266f28043ceccbf4412ddfdd3b" [[package]] name = "constant_time_eq" @@ -954,6 +1052,12 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" +[[package]] +name = "constant_time_eq" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3ad85c1f65dc7b37604eb0e89748faf0b9653065f2a8ef69f96a687ec1e9279" + [[package]] name = "core-foundation" version = "0.9.3" @@ -981,43 +1085,42 @@ dependencies = [ [[package]] name = "cpp_demangle" -version = "0.3.2" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44919ecaf6f99e8e737bc239408931c9a01e9a6c74814fee8242dd2506b65390" +checksum = "eeaa953eaad386a53111e47172c2fedba671e5684c8dd601a5f474f4f118710f" dependencies = [ "cfg-if", - "glob", ] [[package]] name = "cpufeatures" -version = "0.2.1" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469" +checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" dependencies = [ "libc", ] [[package]] name = "cpuid-bool" -version = "0.1.2" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634" +checksum = "dcb25d077389e53838a8158c8e99174c5a9d902dee4904320db714f3c653ffba" [[package]] name = "cranelift-bforest" -version = "0.88.0" +version = "0.88.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b27bbd3e6c422cf6282b047bcdd51ecd9ca9f3497a3be0132ffa08e509b824b0" +checksum = "52056f6d0584484b57fa6c1a65c1fcb15f3780d8b6a758426d9e3084169b2ddd" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-codegen" -version = "0.88.0" +version = "0.88.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "872f5d4557a411b087bd731df6347c142ae1004e6467a144a7e33662e5715a01" +checksum = "18fed94c8770dc25d01154c3ffa64ed0b3ba9d583736f305fed7beebe5d9cf74" dependencies = [ "arrayvec 0.7.2", "bumpalo", @@ -1026,7 +1129,7 @@ dependencies = [ "cranelift-codegen-shared", "cranelift-entity", "cranelift-isle", - "gimli 0.26.1", + "gimli 0.26.2", "log", "regalloc2", "smallvec", @@ -1035,33 +1138,33 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.88.0" +version = "0.88.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b49fdebb29c62c1fc4da1eeebd609e9d530ecde24a9876def546275f73a244" +checksum = "1c451b81faf237d11c7e4f3165eeb6bac61112762c5cfe7b4c0fb7241474358f" dependencies = [ "cranelift-codegen-shared", ] [[package]] name = "cranelift-codegen-shared" -version = "0.88.0" +version = "0.88.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fc0c091e2db055d4d7f6b7cec2d2ead286bcfaea3357c6a52c2a2613a8cb5ac" +checksum = "e7c940133198426d26128f08be2b40b0bd117b84771fd36798969c4d712d81fc" [[package]] name = "cranelift-entity" -version = "0.88.0" +version = "0.88.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "354a9597be87996c9b278655e68b8447f65dd907256855ad773864edee8d985c" +checksum = "87a0f1b2fdc18776956370cf8d9b009ded3f855350c480c1c52142510961f352" dependencies = [ "serde", ] [[package]] name = "cranelift-frontend" -version = "0.88.0" +version = "0.88.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cd8dd3fb8b82c772f4172e87ae1677b971676fffa7c4e3398e3047e650a266b" +checksum = "34897538b36b216cc8dd324e73263596d51b8cf610da6498322838b2546baf8a" dependencies = [ "cranelift-codegen", "log", @@ -1071,15 +1174,15 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.88.0" +version = "0.88.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b82527802b1f7d8da288adc28f1dc97ea52943f5871c041213f7b5035ac698a7" +checksum = "1b2629a569fae540f16a76b70afcc87ad7decb38dc28fa6c648ac73b51e78470" [[package]] name = "cranelift-native" -version = "0.88.0" +version = "0.88.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c30ba8b910f1be023af0c39109cb28a8809734942a6b3eecbf2de8993052ea5e" +checksum = "20937dab4e14d3e225c5adfc9c7106bafd4ac669bdb43027b911ff794c6fb318" dependencies = [ "cranelift-codegen", "libc", @@ -1088,9 +1191,9 @@ dependencies = [ [[package]] name = "cranelift-wasm" -version = "0.88.0" +version = "0.88.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "776a8916d201894aca9637a20814f1e11abc62acd5cfbe0b4eb2e63922756971" +checksum = "80fc2288957a94fd342a015811479de1837850924166d1f1856d8406e6f3609b" dependencies = [ "cranelift-codegen", "cranelift-entity", @@ -1102,20 +1205,35 @@ dependencies = [ "wasmtime-types", ] +[[package]] +name = "crc" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53757d12b596c16c78b83458d732a5d1a17ab3f53f2f7412f6fb57cc8a140ab3" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d0165d2900ae6778e36e80bbc4da3b5eefccee9ba939761f9c2882a5d9af3ff" + [[package]] name = "crc32fast" -version = "1.2.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" dependencies = [ "cfg-if", ] [[package]] name = "criterion" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1604dafd25fba2fe2d5895a9da139f8dc9b319a5fe5354ca137cbbce4e178d10" +checksum = "b01d6de93b2b6c65e17c634a26653a29d107b3c98c607c765bf38d041531cd8f" dependencies = [ "atty", "cast", @@ -1141,9 +1259,9 @@ dependencies = [ [[package]] name = "criterion-plot" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d00996de9f2f7559f7f4dc286073197f83e92256a59ed395f9aac01fe717da57" +checksum = "2673cc8207403546f45f5fd319a974b1e6983ad1a3ee7e6041650013be041876" dependencies = [ "cast", "itertools", @@ -1151,9 +1269,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.0" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dca26ee1f8d361640700bde38b2c37d8c22b3ce2d360e1fc1c74ea4b0aa7d775" +checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" dependencies = [ "cfg-if", "crossbeam-utils", @@ -1161,9 +1279,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" +checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc" dependencies = [ "cfg-if", "crossbeam-epoch", @@ -1172,25 +1290,24 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.5" +version = "0.9.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd" +checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a" dependencies = [ + "autocfg", "cfg-if", "crossbeam-utils", - "lazy_static", - "memoffset", + "memoffset 0.7.1", "scopeguard", ] [[package]] name = "crossbeam-utils" -version = "0.8.8" +version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" +checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f" dependencies = [ "cfg-if", - "lazy_static", ] [[package]] @@ -1201,23 +1318,23 @@ checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" [[package]] name = "crypto-bigint" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f2b443d17d49dad5ef0ede301c3179cc923b8822f3393b4d2c28c269dd4a122" +checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" dependencies = [ - "generic-array 0.14.4", - "rand_core 0.6.2", + "generic-array 0.14.6", + "rand_core 0.6.4", "subtle", "zeroize", ] [[package]] name = "crypto-common" -version = "0.1.3" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ - "generic-array 0.14.4", + "generic-array 0.14.6", "typenum", ] @@ -1227,27 +1344,37 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" dependencies = [ - "generic-array 0.14.4", + "generic-array 0.14.6", "subtle", ] [[package]] name = "crypto-mac" -version = "0.11.1" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" +checksum = "bff07008ec701e8028e2ceb8f83f0e4274ee62bd2dbdc4fefff2e9a91824081a" dependencies = [ - "generic-array 0.14.4", + "generic-array 0.14.6", "subtle", ] [[package]] -name = "csv" +name = "crypto-mac" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" +dependencies = [ + "generic-array 0.14.6", + "subtle", +] + +[[package]] +name = "csv" version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1" dependencies = [ - "bstr 0.2.15", + "bstr 0.2.17", "csv-core", "itoa 0.4.8", "ryu", @@ -1265,28 +1392,37 @@ dependencies = [ [[package]] name = "ctor" -version = "0.1.19" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8f45d9ad417bcef4817d614a501ab55cdd96a6fdb24f49aab89a54acfd66b19" +checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096" dependencies = [ "quote", "syn", ] +[[package]] +name = "ctr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb4a30d54f7443bf3d6191dcd486aca19e67cb3c49fa7a06a319966346707e7f" +dependencies = [ + "cipher 0.2.5", +] + [[package]] name = "ctr" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea" dependencies = [ - "cipher", + "cipher 0.3.0", ] [[package]] name = "curve25519-dalek" -version = "2.1.2" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "434e1720189a637d44fe464f4df1e6eb900b4835255b14354497c78af37d9bb8" +checksum = "4a9b85542f99a2dfa2a1b8e192662741c9859a846b296bef1c92ef9b58b5a216" dependencies = [ "byteorder", "digest 0.8.1", @@ -1297,9 +1433,9 @@ dependencies = [ [[package]] name = "curve25519-dalek" -version = "3.0.2" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f627126b946c25a4638eec0ea634fc52506dea98db118aae985118ce7c3d723f" +checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" dependencies = [ "byteorder", "digest 0.9.0", @@ -1310,22 +1446,23 @@ dependencies = [ [[package]] name = "curve25519-dalek" -version = "4.0.0-pre.1" +version = "4.0.0-pre.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4033478fbf70d6acf2655ac70da91ee65852d69daf7a67bf7a2f518fb47aafcf" +checksum = "67bc65846be335cb20f4e52d49a437b773a2c1fdb42b19fc84e79e6f6771536f" dependencies = [ - "byteorder", - "digest 0.9.0", - "rand_core 0.6.2", + "cfg-if", + "fiat-crypto", + "packed_simd_2", + "platforms 3.0.2", "subtle", "zeroize", ] [[package]] name = "cxx" -version = "1.0.80" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b7d4e43b25d3c994662706a1d4fcfc32aaa6afd287502c111b237093bb23f3a" +checksum = "5add3fc1717409d029b20c5b6903fc0c0b02fa6741d820054f4a2efa5e5816fd" dependencies = [ "cc", "cxxbridge-flags", @@ -1335,9 +1472,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.80" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84f8829ddc213e2c1368e51a2564c552b65a8cb6a28f31e576270ac81d5e5827" +checksum = "b4c87959ba14bc6fbc61df77c3fcfe180fc32b93538c4f1031dd802ccb5f2ff0" dependencies = [ "cc", "codespan-reporting", @@ -1350,32 +1487,67 @@ dependencies = [ [[package]] name = "cxxbridge-flags" -version = "1.0.80" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e72537424b474af1460806647c41d4b6d35d09ef7fe031c5c2fa5766047cc56a" +checksum = "69a3e162fde4e594ed2b07d0f83c6c67b745e7f28ce58c6df5e6b6bef99dfb59" [[package]] name = "cxxbridge-macro" -version = "1.0.80" +version = "1.0.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e7e2adeb6a0d4a282e581096b06e1791532b7d576dcde5ccd9382acf55db8e6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "darling" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0dd3cd20dc6b5a876612a6e5accfe7f3dd883db6d07acfbf14c128f61550dfa" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "309e4fb93eed90e1e14bea0da16b209f81813ba9fc7830c20ed151dd7bc0a4d7" +checksum = "a784d2ccaf7c98501746bf0be29b2022ba41fd62a2e622af997a03e9f972859f" dependencies = [ + "fnv", + "ident_case", "proc-macro2", "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7618812407e9402654622dd402b0a89dff9ba93badd6540781526117b92aab7e" +dependencies = [ + "darling_core", + "quote", "syn", ] [[package]] name = "data-encoding" -version = "2.3.2" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ee2393c4a91429dffb4bedf19f4d6abf27d8a732c8ce4980305d782e5426d57" +checksum = "23d8666cb01533c39dde32bcbab8e227b4ed6679b2c925eba05feabea39508fb" [[package]] name = "data-encoding-macro" -version = "0.1.10" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a94feec3d2ba66c0b6621bca8bc6f68415b1e5c69af3586fdd0af9fd9f29b17" +checksum = "86927b7cd2fe88fa698b87404b287ab98d1a0063a34071d92e575b72d3029aca" dependencies = [ "data-encoding", "data-encoding-macro-internal", @@ -1383,9 +1555,9 @@ dependencies = [ [[package]] name = "data-encoding-macro-internal" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f83e699727abca3c56e187945f303389590305ab2f0185ea445aa66e8d5f2a" +checksum = "a5bbed42daaa95e780b60a50546aa345b8413a1e46f9a40a12907d3598f038db" dependencies = [ "data-encoding", "syn", @@ -1393,14 +1565,74 @@ dependencies = [ [[package]] name = "der" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dd2ae565c0a381dde7fade45fce95984c568bdcb4700a4fdbe3175e0380b2f" +checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" dependencies = [ "const-oid", + "pem-rfc7468", "zeroize", ] +[[package]] +name = "der-parser" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe398ac75057914d7d07307bf67dc7f3f574a26783b4fc7805a20ffa9f506e82" +dependencies = [ + "asn1-rs 0.3.1", + "displaydoc", + "nom", + "num-bigint", + "num-traits", + "rusticata-macros", +] + +[[package]] +name = "der-parser" +version = "8.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42d4bc9b0db0a0df9ae64634ac5bdefb7afcb534e182275ca0beadbe486701c1" +dependencies = [ + "asn1-rs 0.5.1", + "displaydoc", + "nom", + "num-bigint", + "num-traits", + "rusticata-macros", +] + +[[package]] +name = "derive_builder" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d07adf7be193b71cc36b193d0f5fe60b918a3a9db4dad0449f57bcfd519704a3" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f91d4cfa921f1c05904dc3c57b4a32c38aed3340cce209f3a6fd1478babafc4" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "derive_builder_macro" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f0314b72bed045f3a68671b3c86328386762c93f82d98c65c3cb5e5f573dd68" +dependencies = [ + "derive_builder_core", + "syn", +] + [[package]] name = "derive_more" version = "0.99.17" @@ -1414,9 +1646,9 @@ dependencies = [ [[package]] name = "diff" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" [[package]] name = "difflib" @@ -1439,16 +1671,16 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" dependencies = [ - "generic-array 0.14.4", + "generic-array 0.14.6", ] [[package]] name = "digest" -version = "0.10.3" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" +checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" dependencies = [ - "block-buffer 0.10.0", + "block-buffer 0.10.3", "crypto-common", "subtle", ] @@ -1474,9 +1706,9 @@ dependencies = [ [[package]] name = "dirs-sys" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780" +checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" dependencies = [ "libc", "redox_users", @@ -1495,20 +1727,21 @@ dependencies = [ ] [[package]] -name = "dissimilar" -version = "1.0.2" +name = "displaydoc" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc4b29f4b9bb94bf267d57269fd0706d343a160937108e9619fe380645428abb" +checksum = "3bf95dc3f046b9da4f2d51833c0d3547d8564ef6910f5c1ed130306a75b92886" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] -name = "dns-parser" -version = "0.8.0" +name = "dissimilar" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4d33be9473d06f75f58220f71f7a9317aca647dc061dbd3c361b0bef505fbea" -dependencies = [ - "byteorder", - "quick-error", -] +checksum = "bd5f0c7e4bd266b8ab2550e6238d2e74977c23c15536ac7be45e9c95e2e3fbbb" [[package]] name = "doc-comment" @@ -1530,9 +1763,9 @@ checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" [[package]] name = "dtoa" -version = "1.0.2" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5caaa75cbd2b960ff1e5392d2cfb1f44717fffe12fc1f32b7b5d1267f99732a6" +checksum = "c00704156a7de8df8da0911424e30c2049957b0a714542a44e05fe693dd85313" [[package]] name = "dyn-clonable" @@ -1557,15 +1790,15 @@ dependencies = [ [[package]] name = "dyn-clone" -version = "1.0.5" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21e50f3adc76d6a43f5ed73b698a87d0760ca74617f60f7c3b879003536fdd28" +checksum = "c9b0705efd4599c15a38151f4721f7bc388306f61084d3bfd50bd07fbca5cb60" [[package]] name = "ecdsa" -version = "0.14.7" +version = "0.14.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85789ce7dfbd0f0624c07ef653a08bb2ebf43d3e16531361f46d36dd54334fed" +checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c" dependencies = [ "der", "elliptic-curve", @@ -1588,11 +1821,11 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" dependencies = [ - "curve25519-dalek 3.0.2", + "curve25519-dalek 3.2.0", "ed25519", "rand 0.7.3", "serde", - "sha2 0.9.8", + "sha2 0.9.9", "zeroize", ] @@ -1602,19 +1835,19 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c24f403d068ad0b359e577a77f92392118be3f3c927538f2bb544a5ecd828c6" dependencies = [ - "curve25519-dalek 3.0.2", - "hashbrown 0.12.3", + "curve25519-dalek 3.2.0", + "hashbrown", "hex", - "rand_core 0.6.2", - "sha2 0.9.8", + "rand_core 0.6.4", + "sha2 0.9.9", "zeroize", ] [[package]] name = "either" -version = "1.6.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" +checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" [[package]] name = "elliptic-curve" @@ -1625,11 +1858,14 @@ dependencies = [ "base16ct", "crypto-bigint", "der", - "digest 0.10.3", + "digest 0.10.6", "ff", - "generic-array 0.14.4", + "generic-array 0.14.6", "group", - "rand_core 0.6.2", + "hkdf", + "pem-rfc7468", + "pkcs8", + "rand_core 0.6.4", "sec1", "subtle", "zeroize", @@ -1669,9 +1905,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.9.0" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3" +checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" dependencies = [ "atty", "humantime", @@ -1682,9 +1918,9 @@ dependencies = [ [[package]] name = "environmental" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68b91989ae21441195d7d9b9993a2f9295c7e1a8c96255d8b729accddc124797" +checksum = "e48c92028aaa870e83d51c64e5d4e0b6981b360c522198c23959f219a4e1b15b" [[package]] name = "errno" @@ -1699,19 +1935,19 @@ dependencies = [ [[package]] name = "errno-dragonfly" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14ca354e36190500e1e1fb267c647932382b54053c50b14970856c0b00a35067" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" dependencies = [ - "gcc", + "cc", "libc", ] [[package]] name = "event-listener" -version = "2.5.1" +version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7531096570974c3a9dcf9e4b8e1cede1ec26cf5046219fb3b9d897503b9be59" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "exit-future" @@ -1736,9 +1972,9 @@ checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" [[package]] name = "fastrand" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" +checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" dependencies = [ "instant", ] @@ -1754,14 +1990,20 @@ dependencies = [ [[package]] name = "ff" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df689201f395c6b90dfe87127685f8dbfc083a5e779e613575d8bd7314300c3e" +checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160" dependencies = [ - "rand_core 0.6.2", + "rand_core 0.6.4", "subtle", ] +[[package]] +name = "fiat-crypto" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a214f5bb88731d436478f3ae1f8a277b62124089ba9fb67f4f93fb100ef73c90" + [[package]] name = "file-per-thread-logger" version = "0.1.5" @@ -1774,14 +2016,14 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.16" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0408e2626025178a6a7f7ffc05a25bc47103229f19c113755de7bf63816290c" +checksum = "4e884668cd0c7480504233e951174ddc3b382f7c2666e3b7310b5c4e7b0c37f9" dependencies = [ "cfg-if", "libc", "redox_syscall", - "winapi", + "windows-sys 0.42.0", ] [[package]] @@ -1815,21 +2057,19 @@ dependencies = [ [[package]] name = "fixedbitset" -version = "0.4.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "398ea4fabe40b9b0d885340a2a991a44c8a645624075ad966d21f88688e2b69e" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flate2" -version = "1.0.20" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd3aec53de10fe96d7d8c565eb17f2c687bb5518a2ec453b5b1252964526abe0" +checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841" dependencies = [ - "cfg-if", "crc32fast", - "libc", "libz-sys", - "miniz_oxide 0.4.4", + "miniz_oxide", ] [[package]] @@ -1856,19 +2096,18 @@ dependencies = [ [[package]] name = "form_urlencoded" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" +checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" dependencies = [ - "matches", "percent-encoding", ] [[package]] name = "fragile" -version = "1.2.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85dcb89d2b10c5f6133de2efd8c11959ce9dbb46a2f7a4cab208c4eeda6ce1ab" +checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" [[package]] name = "frame-benchmarking" @@ -1902,7 +2141,7 @@ dependencies = [ "Inflector", "array-bytes", "chrono", - "clap 4.0.11", + "clap 4.0.32", "comfy-table", "frame-benchmarking", "frame-support", @@ -1979,7 +2218,7 @@ dependencies = [ name = "frame-election-solution-type-fuzzer" version = "2.0.0-alpha.5" dependencies = [ - "clap 4.0.11", + "clap 4.0.32", "frame-election-provider-solution-type", "frame-election-provider-support", "frame-support", @@ -2234,9 +2473,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.21" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e" +checksum = "38390104763dc37a5145a53c29c63c1290b5d316d6086ec32c293f6736051bb0" dependencies = [ "futures-channel", "futures-core", @@ -2249,9 +2488,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.21" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" +checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed" dependencies = [ "futures-core", "futures-sink", @@ -2259,15 +2498,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.21" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" +checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac" [[package]] name = "futures-executor" -version = "0.3.21" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6" +checksum = "7acc85df6714c176ab5edf386123fafe217be88c0840ec11f199441134a074e2" dependencies = [ "futures-core", "futures-task", @@ -2277,15 +2516,15 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.21" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" +checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb" [[package]] name = "futures-lite" -version = "1.11.3" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4481d0cd0de1d204a4fa55e7d45f07b1d958abcb06714b3446438e2eff695fb" +checksum = "7694489acd39452c77daa48516b894c153f192c3578d5a839b62c58099fcbf48" dependencies = [ "fastrand", "futures-core", @@ -2298,9 +2537,9 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.21" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" +checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d" dependencies = [ "proc-macro2", "quote", @@ -2309,26 +2548,26 @@ dependencies = [ [[package]] name = "futures-rustls" -version = "0.22.1" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e01fe9932a224b72b45336d96040aa86386d674a31d0af27d800ea7bc8ca97fe" +checksum = "d2411eed028cdf8c8034eaf21f9915f956b6c3abec4d4c7949ee67f0721127bd" dependencies = [ "futures-io", - "rustls", - "webpki", + "rustls 0.20.7", + "webpki 0.22.0", ] [[package]] name = "futures-sink" -version = "0.3.21" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" +checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9" [[package]] name = "futures-task" -version = "0.3.21" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" +checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea" [[package]] name = "futures-timer" @@ -2338,9 +2577,9 @@ checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" [[package]] name = "futures-util" -version = "0.3.21" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" +checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6" dependencies = [ "futures-channel", "futures-core", @@ -2363,12 +2602,6 @@ dependencies = [ "byteorder", ] -[[package]] -name = "gcc" -version = "0.3.55" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" - [[package]] name = "generate-bags" version = "4.0.0-dev" @@ -2393,9 +2626,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.4" +version = "0.14.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" +checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" dependencies = [ "typenum", "version_check", @@ -2424,13 +2657,23 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.3" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" +checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" dependencies = [ "cfg-if", "libc", - "wasi 0.10.0+wasi-snapshot-preview1", + "wasi 0.11.0+wasi-snapshot-preview1", +] + +[[package]] +name = "ghash" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97304e4cd182c3846f7575ced3890c53012ce534ad9114046b0a9e00bb30a375" +dependencies = [ + "opaque-debug 0.3.0", + "polyval 0.4.5", ] [[package]] @@ -2440,14 +2683,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1583cc1656d7839fd3732b80cf4f38850336cdb9b8ded1cd399ca62958de3c99" dependencies = [ "opaque-debug 0.3.0", - "polyval", + "polyval 0.5.3", ] [[package]] name = "gimli" -version = "0.26.1" +version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" +checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d" dependencies = [ "fallible-iterator", "indexmap", @@ -2462,9 +2705,9 @@ checksum = "dec7af912d60cdbd3677c1af9352ebae6fb8394d165568a2234df0fa00f87793" [[package]] name = "git2" -version = "0.14.2" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3826a6e0e2215d7a41c2bfc7c9244123969273f3476b939a226aac0ab56e9e3c" +checksum = "d0155506aab710a86160ddb504a480d2964d7ab5b9e62419be69e0032bc5931c" dependencies = [ "bitflags", "libc", @@ -2481,12 +2724,12 @@ checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" [[package]] name = "globset" -version = "0.4.6" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c152169ef1e421390738366d2f796655fec62621dabbd0fd476f905934061e4a" +checksum = "0a1e17342619edbc21a964c2afbeb6c820c6a2560032872f397bb97ea127bd0a" dependencies = [ "aho-corasick", - "bstr 0.2.15", + "bstr 0.2.17", "fnv", "log", "regex", @@ -2494,20 +2737,20 @@ dependencies = [ [[package]] name = "group" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7391856def869c1c81063a03457c676fbcd419709c3dfb33d8d319de484b154d" +checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" dependencies = [ "ff", - "rand_core 0.6.2", + "rand_core 0.6.4", "subtle", ] [[package]] name = "h2" -version = "0.3.13" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37a82c6d637fc9515a4694bbf1cb2457b79d81ce52b3108bdeea58b07dd34a57" +checksum = "5f9f29bc9dda355256b2916cf526ab02ce0aeaaaf2bad60d65ef3f12f11dd0f4" dependencies = [ "bytes", "fnv", @@ -2518,21 +2761,21 @@ dependencies = [ "indexmap", "slab", "tokio", - "tokio-util 0.7.4", + "tokio-util", "tracing", ] [[package]] name = "half" -version = "1.7.1" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62aca2aba2d62b4a7f5b33f3712cb1b0692779a56fb510499d5c0aa594daeaf3" +checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" [[package]] name = "handlebars" -version = "4.3.5" +version = "4.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "433e4ab33f1213cdc25b5fa45c76881240cfe79284cf2b395e8b9e312a30a2fd" +checksum = "035ef95d03713f2c347a72547b7cd38cbc9af7cd51e6099fb62d586d4a6dee3a" dependencies = [ "log", "pest", @@ -2557,12 +2800,6 @@ dependencies = [ "crunchy", ] -[[package]] -name = "hashbrown" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" - [[package]] name = "hashbrown" version = "0.12.3" @@ -2580,9 +2817,18 @@ checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" [[package]] name = "hermit-abi" -version = "0.1.18" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" +checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" dependencies = [ "libc", ] @@ -2593,6 +2839,15 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hkdf" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437" +dependencies = [ + "hmac 0.12.1", +] + [[package]] name = "hmac" version = "0.8.1" @@ -2603,6 +2858,16 @@ dependencies = [ "digest 0.9.0", ] +[[package]] +name = "hmac" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1441c6b1e930e2817404b5046f1f989899143a12bf92de603b69f4e0aee1e15" +dependencies = [ + "crypto-mac 0.10.1", + "digest 0.9.0", +] + [[package]] name = "hmac" version = "0.11.0" @@ -2619,7 +2884,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest 0.10.3", + "digest 0.10.6", ] [[package]] @@ -2629,7 +2894,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" dependencies = [ "digest 0.9.0", - "generic-array 0.14.4", + "generic-array 0.14.6", "hmac 0.8.1", ] @@ -2664,7 +2929,7 @@ checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" dependencies = [ "bytes", "fnv", - "itoa 1.0.4", + "itoa 1.0.5", ] [[package]] @@ -2692,9 +2957,9 @@ checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" [[package]] name = "httpdate" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6456b8a6c8f33fee7d958fcd1b60d55b11940a79e63ae87013e6d22e26034440" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" [[package]] name = "humantime" @@ -2704,9 +2969,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.22" +version = "0.14.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abfba89e19b959ca163c7752ba59d737c1ceea53a5d31a149c805446fc958064" +checksum = "034711faac9d2166cb1baf1a2fb0b60b1f277f8492fd72176c17f3515e1abd3c" dependencies = [ "bytes", "futures-channel", @@ -2717,7 +2982,7 @@ dependencies = [ "http-body", "httparse", "httpdate", - "itoa 1.0.4", + "itoa 1.0.5", "pin-project-lite 0.2.9", "socket2", "tokio", @@ -2728,19 +2993,49 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.23.0" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d87c48c02e0dc5e3b849a2041db3029fd066650f8f717c07bf8ed78ccb895cac" +checksum = "1788965e61b367cd03a62950836d5cd41560c3577d90e40e0819373194d1661c" dependencies = [ "http", "hyper", "log", - "rustls", + "rustls 0.20.7", "rustls-native-certs", "tokio", "tokio-rustls", ] +[[package]] +name = "iana-time-zone" +version = "0.1.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "winapi", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" +dependencies = [ + "cxx", + "cxx-build", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + [[package]] name = "idna" version = "0.2.3" @@ -2752,6 +3047,16 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "idna" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "if-addrs" version = "0.7.0" @@ -2764,9 +3069,9 @@ dependencies = [ [[package]] name = "if-watch" -version = "2.0.0" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "065c008e570a43c00de6aed9714035e5ea6a498c255323db9091722af6ee67dd" +checksum = "ba7abdbb86e485125dad06c2691e1e393bf3b08c7b743b43aa162a00fd39062e" dependencies = [ "async-io", "core-foundation", @@ -2777,6 +3082,7 @@ dependencies = [ "log", "rtnetlink", "system-configuration", + "tokio", "windows", ] @@ -2811,12 +3117,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.8.0" +version = "1.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223" +checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" dependencies = [ "autocfg", - "hashbrown 0.11.2", + "hashbrown", "serde", ] @@ -2844,11 +3150,40 @@ dependencies = [ "num-traits", ] +[[package]] +name = "interceptor" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e8a11ae2da61704edada656798b61c94b35ecac2c58eb955156987d5e6be90b" +dependencies = [ + "async-trait", + "bytes", + "log", + "rand 0.8.5", + "rtcp", + "rtp", + "thiserror", + "tokio", + "waitgroup", + "webrtc-srtp", + "webrtc-util", +] + [[package]] name = "io-lifetimes" -version = "0.7.2" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24c3f4eff5495aee4c0399d7b6a0dc2b6e81be84242ffbfcf253ebacccc1d0cb" +checksum = "59ce5ef949d49ee85593fc4d3f3f95ad61657076395cbbce23e2121fc5542074" + +[[package]] +name = "io-lifetimes" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46112a93252b123d31a119a8d1a1ac19deac4fac6e0e8b0df58f0d4e5870e63c" +dependencies = [ + "libc", + "windows-sys 0.42.0", +] [[package]] name = "ip_network" @@ -2858,9 +3193,9 @@ checksum = "aa2f047c0a98b2f299aa5d6d7088443570faae494e9ae1305e48be000c9e0eb1" [[package]] name = "ipconfig" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "723519edce41262b05d4143ceb95050e4c614f483e78e9fd9e39a8275a84ad98" +checksum = "bd302af1b90f2463a98fa5ad469fc212c8e3175a41c3068601bfa2727591c5be" dependencies = [ "socket2", "widestring", @@ -2870,9 +3205,21 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.5.0" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11b0d96e660696543b251e58030cf9787df56da39dab19ad60eae7353040917e" + +[[package]] +name = "is-terminal" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879d54834c8c76457ef4293a689b2a8c59b076067ad77b15efafbb05f92a592b" +checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189" +dependencies = [ + "hermit-abi 0.2.6", + "io-lifetimes 1.0.3", + "rustix 0.36.6", + "windows-sys 0.42.0", +] [[package]] name = "itertools" @@ -2891,24 +3238,24 @@ checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" [[package]] name = "itoa" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" +checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" [[package]] name = "jobserver" -version = "0.1.21" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c71313ebb9439f74b00d9d2dcec36440beaf57a6aa0623068441dd7cd81a7f2" +checksum = "068b1ee6743e4d11fb9c6a1e6064b3693a1b600e7f5f5988047d98b3dc9fb90b" dependencies = [ "libc", ] [[package]] name = "js-sys" -version = "0.3.54" +version = "0.3.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1866b355d9c878e5e607473cbe3f63282c0b7aad2db1dbebf55076c686918254" +checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" dependencies = [ "wasm-bindgen", ] @@ -2943,7 +3290,7 @@ dependencies = [ "thiserror", "tokio", "tokio-rustls", - "tokio-util 0.7.4", + "tokio-util", "tracing", "webpki-roots", ] @@ -3006,7 +3353,7 @@ dependencies = [ "soketto", "tokio", "tokio-stream", - "tokio-util 0.7.4", + "tokio-util", "tower", "tracing", ] @@ -3039,21 +3386,24 @@ dependencies = [ [[package]] name = "k256" -version = "0.11.5" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3636d281d46c3b64182eb3a0a42b7b483191a2ecc3f05301fa67403f7c9bc949" +checksum = "72c1e0b51e7ec0a97369623508396067a486bd0cbed95a2659a4b863d28cfc8b" dependencies = [ "cfg-if", "ecdsa", "elliptic-curve", - "sha2 0.10.2", + "sha2 0.10.6", ] [[package]] name = "keccak" -version = "0.1.0" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" +checksum = "3afef3b6eff9ce9d8ff9b3601125eec7f0c8cbac7abd14f355d053fa56c98768" +dependencies = [ + "cpufeatures", +] [[package]] name = "keccak-hasher" @@ -3208,21 +3558,21 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "leb128" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3576a87f2ba00f6f106fdfcd16db1d698d648a26ad8e0573cad8537c3c362d2a" +checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "libc" -version = "0.2.126" +version = "0.2.139" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" +checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" [[package]] name = "libgit2-sys" -version = "0.13.2+1.4.2" +version = "0.13.4+1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a42de9a51a5c12e00fc0e4ca6bc2ea43582fc6418488e8f615e905d886f258b" +checksum = "d0fa6563431ede25f5cc7f6d803c6afbc1c5d3ad3d4925d12c882bf2b526f5d1" dependencies = [ "cc", "libc", @@ -3232,9 +3582,9 @@ dependencies = [ [[package]] name = "libloading" -version = "0.7.0" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f84d96438c15fcd6c3f244c8fce01d1e2b9c6b5623e9c711dc9286d8fc92d6a" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" dependencies = [ "cfg-if", "winapi", @@ -3242,22 +3592,27 @@ dependencies = [ [[package]] name = "libm" -version = "0.2.1" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7d73b3f436185384286bd8098d17ec07c9a7d2388a6599f824d8502b529702a" +checksum = "7fc7aa29613bd6a620df431842069224d8bc9011086b1db4c0e0cd47fa03ec9a" + +[[package]] +name = "libm" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb" [[package]] name = "libp2p" -version = "0.49.0" +version = "0.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec878fda12ebec479186b3914ebc48ff180fa4c51847e11a1a68bf65249e02c1" +checksum = "2e0a0d2f693675f49ded13c5d510c48b78069e23cbd9108d7ccd59f6dc568819" dependencies = [ "bytes", "futures", "futures-timer", - "getrandom 0.2.3", + "getrandom 0.2.8", "instant", - "lazy_static", "libp2p-core", "libp2p-dns", "libp2p-identify", @@ -3267,11 +3622,12 @@ dependencies = [ "libp2p-mplex", "libp2p-noise", "libp2p-ping", + "libp2p-quic", "libp2p-request-response", "libp2p-swarm", - "libp2p-swarm-derive", "libp2p-tcp", "libp2p-wasm-ext", + "libp2p-webrtc", "libp2p-websocket", "libp2p-yamux", "multiaddr", @@ -3282,9 +3638,9 @@ dependencies = [ [[package]] name = "libp2p-core" -version = "0.37.0" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "799676bb0807c788065e57551c6527d461ad572162b0519d1958946ff9e0539d" +checksum = "b6a8fcd392ff67af6cc3f03b1426c41f7f26b6b9aff2dc632c1c56dd649e571f" dependencies = [ "asn1_der", "bs58", @@ -3294,18 +3650,19 @@ dependencies = [ "futures", "futures-timer", "instant", - "lazy_static", "log", "multiaddr", "multihash", "multistream-select", + "once_cell", "parking_lot 0.12.1", "pin-project", "prost", "prost-build", "rand 0.8.5", "rw-stream-sink", - "sha2 0.10.2", + "sec1", + "sha2 0.10.6", "smallvec", "thiserror", "unsigned-varint", @@ -3315,9 +3672,9 @@ dependencies = [ [[package]] name = "libp2p-dns" -version = "0.37.0" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2322c9fb40d99101def6a01612ee30500c89abbbecb6297b3cd252903a4c1720" +checksum = "8e42a271c1b49f789b92f7fc87749fa79ce5c7bdc88cbdfacb818a4bca47fec5" dependencies = [ "futures", "libp2p-core", @@ -3329,9 +3686,9 @@ dependencies = [ [[package]] name = "libp2p-identify" -version = "0.40.0" +version = "0.41.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf9a121f699e8719bda2e6e9e9b6ddafc6cff4602471d6481c1067930ccb29b" +checksum = "c052d0026f4817b44869bfb6810f4e1112f43aec8553f2cb38881c524b563abf" dependencies = [ "asynchronous-codec", "futures", @@ -3350,9 +3707,9 @@ dependencies = [ [[package]] name = "libp2p-kad" -version = "0.41.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6721c200e2021f6c3fab8b6cf0272ead8912d871610ee194ebd628cecf428f22" +checksum = "2766dcd2be8c87d5e1f35487deb22d765f49c6ae1251b3633efe3b25698bd3d2" dependencies = [ "arrayvec 0.7.2", "asynchronous-codec", @@ -3368,7 +3725,7 @@ dependencies = [ "prost", "prost-build", "rand 0.8.5", - "sha2 0.10.2", + "sha2 0.10.6", "smallvec", "thiserror", "uint", @@ -3378,12 +3735,11 @@ dependencies = [ [[package]] name = "libp2p-mdns" -version = "0.41.0" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "761704e727f7d68d58d7bc2231eafae5fc1b9814de24290f126df09d4bd37a15" +checksum = "04f378264aade9872d6ccd315c0accc18be3a35d15fc1b9c36e5b6f983b62b5b" dependencies = [ "data-encoding", - "dns-parser", "futures", "if-watch", "libp2p-core", @@ -3393,14 +3749,15 @@ dependencies = [ "smallvec", "socket2", "tokio", + "trust-dns-proto", "void", ] [[package]] name = "libp2p-metrics" -version = "0.10.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ee31b08e78b7b8bfd1c4204a9dd8a87b4fcdf6dafc57eb51701c1c264a81cb9" +checksum = "5ad8a64f29da86005c86a4d2728b8a0719e9b192f4092b609fd8790acb9dec55" dependencies = [ "libp2p-core", "libp2p-identify", @@ -3412,9 +3769,9 @@ dependencies = [ [[package]] name = "libp2p-mplex" -version = "0.37.0" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "692664acfd98652de739a8acbb0a0d670f1d67190a49be6b4395e22c37337d89" +checksum = "03805b44107aa013e7cbbfa5627b31c36cbedfdfb00603c0311998882bc4bace" dependencies = [ "asynchronous-codec", "bytes", @@ -3430,31 +3787,32 @@ dependencies = [ [[package]] name = "libp2p-noise" -version = "0.40.0" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "048155686bd81fe6cb5efdef0c6290f25ad32a0a42e8f4f72625cf6a505a206f" +checksum = "a978cb57efe82e892ec6f348a536bfbd9fee677adbe5689d7a93ad3a9bffbf2e" dependencies = [ "bytes", - "curve25519-dalek 3.0.2", + "curve25519-dalek 3.2.0", "futures", - "lazy_static", "libp2p-core", "log", + "once_cell", "prost", "prost-build", "rand 0.8.5", - "sha2 0.10.2", + "sha2 0.10.6", "snow", "static_assertions", - "x25519-dalek", + "thiserror", + "x25519-dalek 1.1.1", "zeroize", ] [[package]] name = "libp2p-ping" -version = "0.40.1" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7228b9318d34689521349a86eb39a3c3a802c9efc99a0568062ffb80913e3f91" +checksum = "929fcace45a112536e22b3dcfd4db538723ef9c3cb79f672b98be2cc8e25f37f" dependencies = [ "futures", "futures-timer", @@ -3466,11 +3824,32 @@ dependencies = [ "void", ] +[[package]] +name = "libp2p-quic" +version = "0.7.0-alpha" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01e7c867e95c8130667b24409d236d37598270e6da69b3baf54213ba31ffca59" +dependencies = [ + "bytes", + "futures", + "futures-timer", + "if-watch", + "libp2p-core", + "libp2p-tls", + "log", + "parking_lot 0.12.1", + "quinn-proto", + "rand 0.8.5", + "rustls 0.20.7", + "thiserror", + "tokio", +] + [[package]] name = "libp2p-request-response" -version = "0.22.1" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8827af16a017b65311a410bb626205a9ad92ec0473967618425039fa5231adc1" +checksum = "3236168796727bfcf4927f766393415361e2c644b08bedb6a6b13d957c9a4884" dependencies = [ "async-trait", "bytes", @@ -3486,9 +3865,9 @@ dependencies = [ [[package]] name = "libp2p-swarm" -version = "0.40.1" +version = "0.41.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46d13df7c37807965d82930c0e4b04a659efcb6cca237373b206043db5398ecf" +checksum = "b2a35472fe3276b3855c00f1c032ea8413615e030256429ad5349cdf67c6e1a0" dependencies = [ "either", "fnv", @@ -3496,19 +3875,21 @@ dependencies = [ "futures-timer", "instant", "libp2p-core", + "libp2p-swarm-derive", "log", "pin-project", "rand 0.8.5", "smallvec", "thiserror", + "tokio", "void", ] [[package]] name = "libp2p-swarm-derive" -version = "0.30.1" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0eddc4497a8b5a506013c40e8189864f9c3a00db2b25671f428ae9007f3ba32" +checksum = "9d527d5827582abd44a6d80c07ff8b50b4ee238a8979e05998474179e79dc400" dependencies = [ "heck", "quote", @@ -3517,9 +3898,9 @@ dependencies = [ [[package]] name = "libp2p-tcp" -version = "0.37.0" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9839d96761491c6d3e238e70554b856956fca0ab60feb9de2cd08eed4473fa92" +checksum = "b4b257baf6df8f2df39678b86c578961d48cc8b68642a12f0f763f56c8e5858d" dependencies = [ "futures", "futures-timer", @@ -3531,11 +3912,29 @@ dependencies = [ "tokio", ] +[[package]] +name = "libp2p-tls" +version = "0.1.0-alpha" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7905ce0d040576634e8a3229a7587cc8beab83f79db6023800f1792895defa8" +dependencies = [ + "futures", + "futures-rustls", + "libp2p-core", + "rcgen 0.10.0", + "ring", + "rustls 0.20.7", + "thiserror", + "webpki 0.22.0", + "x509-parser 0.14.0", + "yasna", +] + [[package]] name = "libp2p-wasm-ext" -version = "0.37.0" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a17b5b8e7a73e379e47b1b77f8a82c4721e97eca01abcd18e9cd91a23ca6ce97" +checksum = "1bb1a35299860e0d4b3c02a3e74e3b293ad35ae0cee8a056363b0c862d082069" dependencies = [ "futures", "js-sys", @@ -3545,11 +3944,42 @@ dependencies = [ "wasm-bindgen-futures", ] +[[package]] +name = "libp2p-webrtc" +version = "0.4.0-alpha" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb6cd86dd68cba72308ea05de1cebf3ba0ae6e187c40548167955d4e3970f6a" +dependencies = [ + "async-trait", + "asynchronous-codec", + "bytes", + "futures", + "futures-timer", + "hex", + "if-watch", + "libp2p-core", + "libp2p-noise", + "log", + "multihash", + "prost", + "prost-build", + "prost-codec", + "rand 0.8.5", + "rcgen 0.9.3", + "serde", + "stun", + "thiserror", + "tinytemplate", + "tokio", + "tokio-util", + "webrtc", +] + [[package]] name = "libp2p-websocket" -version = "0.39.0" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3758ae6f89b2531a24b6d9f5776bda6a626b60a57600d7185d43dfa75ca5ecc4" +checksum = "1d705506030d5c0aaf2882437c70dab437605f21c5f9811978f694e6917a3b54" dependencies = [ "either", "futures", @@ -3566,9 +3996,9 @@ dependencies = [ [[package]] name = "libp2p-yamux" -version = "0.41.0" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30f079097a21ad017fc8139460630286f02488c8c13b26affb46623aa20d8845" +checksum = "4f63594a0aa818642d9d4915c791945053877253f08a3626f13416b5cd928a29" dependencies = [ "futures", "libp2p-core", @@ -3595,9 +4025,9 @@ dependencies = [ [[package]] name = "libsecp256k1" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0452aac8bab02242429380e9b2f94ea20cea2b37e2c1777a1358799bbe97f37" +checksum = "95b09eff1b35ed3b33b877ced3a691fc7a481919c7e29c53c906226fcf55e2a1" dependencies = [ "arrayref", "base64", @@ -3608,7 +4038,7 @@ dependencies = [ "libsecp256k1-gen-genmult", "rand 0.8.5", "serde", - "sha2 0.9.8", + "sha2 0.9.9", "typenum", ] @@ -3643,9 +4073,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.2" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "602113192b08db8f38796c4e85c39e960c145965140e918018bcde1952429655" +checksum = "9702761c3935f8cc2f101793272e202c72b99da8f4224a19ddcf1279a6450bbf" dependencies = [ "cc", "libc", @@ -3655,18 +4085,18 @@ dependencies = [ [[package]] name = "link-cplusplus" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9272ab7b96c9046fbc5bc56c06c117cb639fe2d509df0c421cad82d2915cf369" +checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" dependencies = [ "cc", ] [[package]] name = "linked-hash-map" -version = "0.5.4" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "linked_hash_set" @@ -3693,6 +4123,12 @@ version = "0.0.46" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4d2456c373231a208ad294c33dc5bff30051eafd954cd4caae83a712b12854d" +[[package]] +name = "linux-raw-sys" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" + [[package]] name = "lite-json" version = "0.2.0" @@ -3713,10 +4149,11 @@ dependencies = [ [[package]] name = "lock_api" -version = "0.4.6" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b" +checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" dependencies = [ + "autocfg", "scopeguard", ] @@ -3735,7 +4172,7 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6e8aaa3f231bb4bd57b84b2d5dc3ae7f350265df8aa96492e0bc394a1571909" dependencies = [ - "hashbrown 0.12.3", + "hashbrown", ] [[package]] @@ -3802,48 +4239,66 @@ dependencies = [ [[package]] name = "matches" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" [[package]] name = "matrixmultiply" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a8a15b776d9dfaecd44b03c5828c2199cddff5247215858aac14624f8d6b741" +checksum = "add85d4dd35074e6fedc608f8c8f513a3548619a9024b751949ef0e8e45a4d84" dependencies = [ "rawpointer", ] +[[package]] +name = "md-5" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6365506850d44bff6e2fbcb5176cf63650e48bd45ef2fe2665ae1570e0f4b9ca" +dependencies = [ + "digest 0.10.6", +] + [[package]] name = "memchr" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "memfd" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "480b5a5de855d11ff13195950bdc8b98b5e942ef47afc447f6615cdcc4e15d80" +checksum = "b20a59d985586e4a5aef64564ac77299f8586d8be6cf9106a5a40207e8908efb" dependencies = [ - "rustix", + "rustix 0.36.6", ] [[package]] name = "memmap2" -version = "0.5.0" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4647a11b578fead29cdbb34d4adef8dd3dc35b876c9c6d5240d83f205abfe96e" +checksum = "4b182332558b18d807c4ce1ca8ca983b34c3ee32765e47b3f0f69b90355cc1dc" dependencies = [ "libc", ] [[package]] name = "memoffset" -version = "0.6.4" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + +[[package]] +name = "memoffset" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9" +checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" dependencies = [ "autocfg", ] @@ -3855,7 +4310,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e0c7cba9ce19ac7ffd2053ac9f49843bbd3f4318feedfd74e85c19d5fb0ba66" dependencies = [ "hash-db", - "hashbrown 0.12.3", + "hashbrown", ] [[package]] @@ -3882,16 +4337,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" -[[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 = "miniz_oxide" version = "0.6.2" @@ -3903,14 +4348,14 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf" +checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" dependencies = [ "libc", "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.36.1", + "windows-sys 0.42.0", ] [[package]] @@ -3954,9 +4399,9 @@ dependencies = [ [[package]] name = "mockall" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2be9a9090bc1cac2930688fa9478092a64c6a92ddc6ae0692d46b37d9cab709" +checksum = "50e4a1c770583dac7ab5e2f6c139153b783a53a1bbee9729613f193e59828326" dependencies = [ "cfg-if", "downcast", @@ -3969,9 +4414,9 @@ dependencies = [ [[package]] name = "mockall_derive" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86d702a0530a0141cf4ed147cf5ec7be6f2c187d4e37fcbefc39cf34116bfe8f" +checksum = "832663583d5fa284ca8810bf7015e46c9fff9622d3cf34bd1eea5003fec06dd0" dependencies = [ "cfg-if", "proc-macro2", @@ -3981,14 +4426,14 @@ dependencies = [ [[package]] name = "multiaddr" -version = "0.14.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c580bfdd8803cce319b047d239559a22f809094aaea4ac13902a1fdcfcd4261" +checksum = "a4aebdb21e90f81d13ed01dc84123320838e53963c2ca94b60b305d3fa64f31e" dependencies = [ "arrayref", - "bs58", "byteorder", "data-encoding", + "multibase", "multihash", "percent-encoding", "serde", @@ -4010,17 +4455,17 @@ dependencies = [ [[package]] name = "multihash" -version = "0.16.2" +version = "0.16.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3db354f401db558759dfc1e568d010a5d4146f4d3f637be1275ec4a3cf09689" +checksum = "1c346cf9999c631f002d8f977c4eaeaa0e6386f16007202308d0b3757522c2cc" dependencies = [ "blake2b_simd", "blake2s_simd", "blake3", "core2", - "digest 0.10.3", + "digest 0.10.6", "multihash-derive", - "sha2 0.10.2", + "sha2 0.10.6", "sha3", "unsigned-varint", ] @@ -4041,15 +4486,15 @@ dependencies = [ [[package]] name = "multimap" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1255076139a83bb467426e7f8d0134968a8118844faa755985e077cf31850333" +checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" [[package]] name = "multistream-select" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bc41247ec209813e2fd414d6e16b9d94297dacf3cd613fa6ef09cd4d9755c10" +checksum = "c8552ab875c1313b97b8d20cb857b9fd63e2d1d6a0a1b53ce9821e575405f27a" dependencies = [ "bytes", "futures", @@ -4156,35 +4601,36 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92b654097027250401127914afb37cb1f311df6610a9891ff07a757e94199027" dependencies = [ - "async-io", "bytes", "futures", "libc", "log", + "tokio", ] [[package]] name = "nix" -version = "0.23.1" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f866317acbd3a240710c63f065ffb1e4fd466259045ccb504130b7f668f35c6" +checksum = "8f3790c00a0150112de0f4cd161e3d7fc4b2d8a5542ffc35f099a2562aecb35c" dependencies = [ "bitflags", "cc", "cfg-if", "libc", - "memoffset", + "memoffset 0.6.5", ] [[package]] name = "nix" -version = "0.24.2" +version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "195cdbc1741b8134346d515b3a56a1c94b0912758009cfd53f99ea0f57b065fc" +checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069" dependencies = [ "bitflags", "cfg-if", "libc", + "memoffset 0.6.5", ] [[package]] @@ -4192,7 +4638,7 @@ name = "node-bench" version = "0.9.0-dev" dependencies = [ "array-bytes", - "clap 4.0.11", + "clap 4.0.32", "derive_more", "fs_extra", "futures", @@ -4229,7 +4675,7 @@ version = "3.0.0-dev" dependencies = [ "array-bytes", "assert_cmd", - "clap 4.0.11", + "clap 4.0.32", "clap_complete", "criterion", "frame-benchmarking-cli", @@ -4239,7 +4685,7 @@ dependencies = [ "jsonrpsee", "kitchensink-runtime", "log", - "nix 0.23.1", + "nix 0.23.2", "node-executor", "node-inspect", "node-primitives", @@ -4251,7 +4697,7 @@ dependencies = [ "pallet-timestamp", "pallet-transaction-payment", "parity-scale-codec", - "platforms", + "platforms 2.0.0", "rand 0.8.5", "regex", "sc-authority-discovery", @@ -4304,7 +4750,7 @@ dependencies = [ "substrate-rpc-client", "tempfile", "tokio", - "tokio-util 0.7.4", + "tokio-util", "try-runtime-cli", "wait-timeout", ] @@ -4349,7 +4795,7 @@ dependencies = [ name = "node-inspect" version = "0.9.0-dev" dependencies = [ - "clap 4.0.11", + "clap 4.0.32", "parity-scale-codec", "sc-cli", "sc-client-api", @@ -4408,7 +4854,7 @@ dependencies = [ name = "node-runtime-generate-bags" version = "3.0.0" dependencies = [ - "clap 4.0.11", + "clap 4.0.32", "generate-bags", "kitchensink-runtime", ] @@ -4417,7 +4863,7 @@ dependencies = [ name = "node-template" version = "4.0.0-dev" dependencies = [ - "clap 4.0.11", + "clap 4.0.32", "frame-benchmarking", "frame-benchmarking-cli", "frame-system", @@ -4536,13 +4982,12 @@ checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" [[package]] name = "nom" -version = "7.1.0" +version = "7.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1d11e1ef389c76fe5b81bcaf2ea32cf88b62bc494e19f493d0b30e7a930109" +checksum = "e5507769c4919c998e69e49c839d9dc6e693ede4cc4290d6ad8b41d4f09c548c" dependencies = [ "memchr", "minimal-lexical", - "version_check", ] [[package]] @@ -4574,28 +5019,28 @@ dependencies = [ [[package]] name = "num-complex" -version = "0.4.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26873667bbbb7c5182d4a37c1add32cdf09f841af72da53318fdb81543c15085" +checksum = "7ae39348c8bc5fbd7f40c727a9925f03517afd2ab27d46702108b6a7e5414c19" dependencies = [ "num-traits", ] [[package]] name = "num-format" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54b862ff8df690cf089058c98b183676a7ed0f974cc08b426800093227cbff3b" +checksum = "a652d9771a63711fd3c3deb670acfbe5c30a4072e664d7a3bf5a9e1056ac72c3" dependencies = [ "arrayvec 0.7.2", - "itoa 1.0.4", + "itoa 1.0.5", ] [[package]] name = "num-integer" -version = "0.1.44" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" dependencies = [ "autocfg", "num-traits", @@ -4615,21 +5060,21 @@ 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", + "libm 0.2.6", ] [[package]] name = "num_cpus" -version = "1.13.1" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" dependencies = [ - "hermit-abi", + "hermit-abi 0.2.6", "libc", ] @@ -4640,7 +5085,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53" dependencies = [ "crc32fast", - "hashbrown 0.12.3", + "hashbrown", "indexmap", "memchr", ] @@ -4654,11 +5099,29 @@ dependencies = [ "memchr", ] +[[package]] +name = "oid-registry" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38e20717fa0541f39bd146692035c37bedfa532b3e5071b35761082407546b2a" +dependencies = [ + "asn1-rs 0.3.1", +] + +[[package]] +name = "oid-registry" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bedf36ffb6ba96c2eb7144ef6270557b52e54b20c0a8e1eb2ff99a6c6959bff" +dependencies = [ + "asn1-rs 0.5.1", +] + [[package]] name = "once_cell" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" +checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" [[package]] name = "oorandom" @@ -4680,21 +5143,21 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "openssl-probe" -version = "0.1.2" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "os_str_bytes" -version = "6.0.0" +version = "6.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64" +checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee" [[package]] name = "output_vt100" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53cdc5b785b7a58c5aad8216b3dfa114df64b0b06ae6e1501cef91df2fbdf8f9" +checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66" dependencies = [ "winapi", ] @@ -4705,6 +5168,38 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" +[[package]] +name = "p256" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51f44edd08f51e2ade572f141051021c5af22677e42b7dd28a88155151c33594" +dependencies = [ + "ecdsa", + "elliptic-curve", + "sha2 0.10.6", +] + +[[package]] +name = "p384" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc8c5bf642dde52bb9e87c0ecd8ca5a76faac2eeed98dedb7c717997e1080aa" +dependencies = [ + "ecdsa", + "elliptic-curve", + "sha2 0.10.6", +] + +[[package]] +name = "packed_simd_2" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1914cd452d8fccd6f9db48147b29fd4ae05bea9dc5d9ad578509f72415de282" +dependencies = [ + "cfg-if", + "libm 0.1.4", +] + [[package]] name = "pallet-alliance" version = "4.0.0-dev" @@ -4719,7 +5214,7 @@ dependencies = [ "pallet-identity", "parity-scale-codec", "scale-info", - "sha2 0.10.2", + "sha2 0.10.6", "sp-core", "sp-io", "sp-runtime", @@ -6165,9 +6660,9 @@ dependencies = [ [[package]] name = "parity-scale-codec" -version = "3.1.3" +version = "3.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04bc9583b5e01cc8c70d89acc9af14ef9b1c29ee3a0074b2a9eea8c0fa396690" +checksum = "366e44391a8af4cfd6002ef6ba072bae071a96aafca98d7d448a34c5dca38b6a" dependencies = [ "arrayvec 0.7.2", "bitvec", @@ -6216,7 +6711,7 @@ checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" dependencies = [ "instant", "lock_api", - "parking_lot_core 0.8.5", + "parking_lot_core 0.8.6", ] [[package]] @@ -6226,14 +6721,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", - "parking_lot_core 0.9.1", + "parking_lot_core 0.9.5", ] [[package]] name = "parking_lot_core" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" +checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" dependencies = [ "cfg-if", "instant", @@ -6245,22 +6740,22 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.1" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28141e0cc4143da2443301914478dc976a61ffdb3f043058310c70df2fed8954" +checksum = "7ff9f3fef3968a3ec5945535ed654cb38ff72d7495a25619e2247fb15a2ed9ba" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-sys 0.32.0", + "windows-sys 0.42.0", ] [[package]] name = "paste" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1de2e551fb905ac83f73f7aedf2f0cb4a0da7e35efa24a202a936269f1f18e1" +checksum = "d01a5bd0424d00070b0098dd17ebca6f961a959dead1dbcbbbc1d1cd8d3deeba" [[package]] name = "pbkdf2" @@ -6277,7 +6772,7 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" dependencies = [ - "digest 0.10.3", + "digest 0.10.6", ] [[package]] @@ -6286,17 +6781,35 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" +[[package]] +name = "pem" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c64931a1a212348ec4f3b4362585eca7159d0d09cbdf4a7f74f02173596fd4" +dependencies = [ + "base64", +] + +[[package]] +name = "pem-rfc7468" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d159833a9105500e0398934e205e0773f0b27529557134ecfc51c27646adac" +dependencies = [ + "base64ct", +] + [[package]] name = "percent-encoding" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" +checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" [[package]] name = "pest" -version = "2.4.0" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbc7bc69c062e492337d74d59b120c274fd3d261b6bf6d3207d499b4b379c41a" +checksum = "0f6e86fb9e7026527a0d46bc308b841d73170ef8f443e1807f6ef88526a816d4" dependencies = [ "thiserror", "ucd-trie", @@ -6304,9 +6817,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.4.0" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b75706b9642ebcb34dab3bc7750f811609a0eb1dd8b88c2d15bf628c1c65b2" +checksum = "96504449aa860c8dcde14f9fba5c58dc6658688ca1fe363589d6327b8662c603" dependencies = [ "pest", "pest_generator", @@ -6314,9 +6827,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.4.0" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f9272122f5979a6511a749af9db9bfc810393f63119970d7085fed1c4ea0db" +checksum = "798e0220d1111ae63d66cb66a5dcb3fc2d986d520b98e49e1852bfdb11d7c5e7" dependencies = [ "pest", "pest_meta", @@ -6327,9 +6840,9 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.4.0" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8717927f9b79515e565a64fe46c38b8cd0427e64c40680b14a7365ab09ac8d" +checksum = "984298b75898e30a843e278a9f2452c31e349a073a0ce6fd950a12a74464e065" dependencies = [ "once_cell", "pest", @@ -6338,9 +6851,9 @@ dependencies = [ [[package]] name = "petgraph" -version = "0.6.0" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a13a2fa9d0b63e5f22328828741e523766fff0ee9e779316902290dff3f824f" +checksum = "e6d5014253a1331579ce62aa67443b4a658c5e7dd03d4bc6d302b94474888143" dependencies = [ "fixedbitset", "indexmap", @@ -6396,9 +6909,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.19" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" +checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" [[package]] name = "platforms" @@ -6406,11 +6919,17 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8d0eef3571242013a0d5dc84861c3ae4a652e56e12adf8bdc26ff5f8cb34c94" +[[package]] +name = "platforms" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d7ddaed09e0eb771a79ab0fd64609ba0afb0a8366421957936ad14cbd13630" + [[package]] name = "plotters" -version = "0.3.1" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a3fd9ec30b9749ce28cd91f255d569591cdf937fe280c312143e3c4bad6f2a" +checksum = "2538b639e642295546c50fcd545198c9d64ee2a38620a628724a3b266d5fbf97" dependencies = [ "num-traits", "plotters-backend", @@ -6421,31 +6940,31 @@ dependencies = [ [[package]] name = "plotters-backend" -version = "0.3.0" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b07fffcddc1cb3a1de753caa4e4df03b79922ba43cf882acc1bdd7e8df9f4590" +checksum = "193228616381fecdc1224c62e96946dfbc73ff4384fba576e052ff8c1bea8142" [[package]] name = "plotters-svg" -version = "0.3.0" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b38a02e23bd9604b842a812063aec4ef702b57989c37b655254bb61c471ad211" +checksum = "f9a81d2759aae1dae668f783c308bc5c8ebd191ff4184aaa1b37f65a6ae5a56f" dependencies = [ "plotters-backend", ] [[package]] name = "polling" -version = "2.4.0" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab4609a838d88b73d8238967b60dd115cc08d38e2bbaf51ee1e4b695f89122e2" +checksum = "22122d5ec4f9fe1b3916419b76be1e80bcb93f618d071d2edf841b137b2a2bd6" dependencies = [ "autocfg", "cfg-if", "libc", "log", "wepoll-ffi", - "winapi", + "windows-sys 0.42.0", ] [[package]] @@ -6459,6 +6978,17 @@ dependencies = [ "universal-hash", ] +[[package]] +name = "polyval" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eebcc4aa140b9abd2bc40d9c3f7ccec842679cd79045ac3a7ac698c1a064b7cd" +dependencies = [ + "cpuid-bool", + "opaque-debug 0.3.0", + "universal-hash", +] + [[package]] name = "polyval" version = "0.5.3" @@ -6473,15 +7003,15 @@ dependencies = [ [[package]] name = "ppv-lite86" -version = "0.2.10" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "predicates" -version = "2.1.3" +version = "2.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed6bd09a7f7e68f3f0bf710fb7ab9c4615a488b58b5f653382a687701e458c92" +checksum = "59230a63c37f3e18569bdb90e4a89cbf5bf8b06fea0b84e65ea10cc4df47addd" dependencies = [ "difflib", "float-cmp", @@ -6493,37 +7023,47 @@ dependencies = [ [[package]] name = "predicates-core" -version = "1.0.2" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57e35a3326b75e49aa85f5dc6ec15b41108cf5aee58eabb1f274dd18b73c2451" +checksum = "72f883590242d3c6fc5bf50299011695fa6590c2c70eac95ee1bdb9a733ad1a2" [[package]] name = "predicates-tree" -version = "1.0.2" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15f553275e5721409451eb85e15fd9a860a6e5ab4496eb215987502b5f5391f2" +checksum = "54ff541861505aabf6ea722d2131ee980b8276e10a1297b94e896dd8b621850d" dependencies = [ "predicates-core", - "treeline", + "termtree", ] [[package]] name = "pretty_assertions" -version = "1.2.1" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c89f989ac94207d048d92db058e4f6ec7342b0971fc58d1271ca148b799b3563" +checksum = "a25e9bcb20aa780fd0bb16b72403a9064d6b3f22f026946029acb941a50af755" dependencies = [ - "ansi_term", "ctor", "diff", "output_vt100", + "yansi", +] + +[[package]] +name = "prettyplease" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c8992a85d8e93a28bdf76137db888d3874e3b230dee5ed8bebac4c9f7617773" +dependencies = [ + "proc-macro2", + "syn", ] [[package]] name = "primitive-types" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cfd65aea0c5fa0bfcc7c9e7ca828c921ef778f43d325325ec84bda371bfa75a" +checksum = "9f3486ccba82358b11a77516035647c34ba167dfa53312630de83b12bd4f3d66" dependencies = [ "fixed-hash", "impl-codec", @@ -6534,10 +7074,11 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "1.1.3" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e17d47ce914bf4de440332250b0edd23ce48c005f59fab39d3335866b114f11a" +checksum = "eda0fc3b0fb7c975631757e14d9049da17374063edb6ebbcbc54d880d4fe94e9" dependencies = [ + "once_cell", "thiserror", "toml", ] @@ -6568,35 +7109,35 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.46" +version = "1.0.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94e2ef8dbfc347b10c094890f778ee2e36ca9bb4262e86dc99cd217e35f3470b" +checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5" dependencies = [ "unicode-ident", ] [[package]] name = "prometheus" -version = "0.13.0" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7f64969ffd5dd8f39bd57a68ac53c163a095ed9d0fb707146da1b27025a3504" +checksum = "449811d15fbdf5ceb5c1144416066429cf82316e2ec8ce0c1f6f8a02e7bbcf8c" dependencies = [ "cfg-if", "fnv", "lazy_static", "memchr", - "parking_lot 0.11.2", + "parking_lot 0.12.1", "thiserror", ] [[package]] name = "prometheus-client" -version = "0.18.0" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c473049631c233933d6286c88bbb7be30e62ec534cf99a9ae0079211f7fa603" +checksum = "83cd1b99916654a69008fd66b4f9397fbe08e6e51dfe23d4417acf5d3b8cb87c" dependencies = [ "dtoa", - "itoa 1.0.4", + "itoa 1.0.5", "parking_lot 0.12.1", "prometheus-client-derive-text-encode", ] @@ -6614,9 +7155,9 @@ dependencies = [ [[package]] name = "prost" -version = "0.11.0" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "399c3c31cdec40583bb68f0b18403400d01ec4289c383aa047560439952c4dd7" +checksum = "c01db6702aa05baa3f57dec92b8eeeeb4cb19e894e73996b32a4093289e54592" dependencies = [ "bytes", "prost-derive", @@ -6624,9 +7165,9 @@ dependencies = [ [[package]] name = "prost-build" -version = "0.11.1" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f835c582e6bd972ba8347313300219fed5bfa52caf175298d860b61ff6069bb" +checksum = "cb5320c680de74ba083512704acb90fe00f28f79207286a848e730c45dd73ed6" dependencies = [ "bytes", "heck", @@ -6635,18 +7176,20 @@ dependencies = [ "log", "multimap", "petgraph", + "prettyplease", "prost", "prost-types", "regex", + "syn", "tempfile", "which", ] [[package]] name = "prost-codec" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "011ae9ff8359df7915f97302d591cdd9e0e27fbd5a4ddc5bd13b71079bb20987" +checksum = "0dc34979ff898b6e141106178981ce2596c387ea6e62533facfc61a37fc879c0" dependencies = [ "asynchronous-codec", "bytes", @@ -6657,9 +7200,9 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.11.0" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7345d5f0e08c0536d7ac7229952590239e77abf0a0100a1b1d890add6ea96364" +checksum = "c8842bad1a5419bca14eac663ba798f6bc19c413c2fdceb5f3ba3b0932d96720" dependencies = [ "anyhow", "itertools", @@ -6670,9 +7213,9 @@ dependencies = [ [[package]] name = "prost-types" -version = "0.11.1" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dfaa718ad76a44b3415e6c4d53b17c8f99160dcb3a99b10470fce8ad43f6e3e" +checksum = "017f79637768cde62820bc2d4fe0e45daaa027755c323ad077767c6c5f173091" dependencies = [ "bytes", "prost", @@ -6680,9 +7223,9 @@ dependencies = [ [[package]] name = "psm" -version = "0.1.12" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3abf49e5417290756acfd26501536358560c4a5cc4a0934d390939acb3e7083a" +checksum = "5787f7cda34e3033a72192c018bc5883100330f362ef279a8cbccfce8bb4e874" dependencies = [ "cc", ] @@ -6713,11 +7256,29 @@ dependencies = [ "pin-project-lite 0.1.12", ] +[[package]] +name = "quinn-proto" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72ef4ced82a24bb281af338b9e8f94429b6eca01b4e66d899f40031f074e74c9" +dependencies = [ + "bytes", + "rand 0.8.5", + "ring", + "rustc-hash", + "rustls 0.20.7", + "slab", + "thiserror", + "tinyvec", + "tracing", + "webpki 0.22.0", +] + [[package]] name = "quote" -version = "1.0.18" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" dependencies = [ "proc-macro2", ] @@ -6749,7 +7310,7 @@ checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha 0.3.1", - "rand_core 0.6.2", + "rand_core 0.6.4", ] [[package]] @@ -6769,7 +7330,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core 0.6.2", + "rand_core 0.6.4", ] [[package]] @@ -6783,11 +7344,11 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.6.2" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.3", + "getrandom 0.2.8", ] [[package]] @@ -6815,7 +7376,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59cad018caf63deb318e5a4586d99a24424a364f40f1e5778c29aca23f4fc73e" dependencies = [ - "rand_core 0.6.2", + "rand_core 0.6.4", ] [[package]] @@ -6826,62 +7387,85 @@ checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" [[package]] name = "rayon" -version = "1.5.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b0d8e0819fadc20c74ea8373106ead0600e3a67ef1fe8da56e39b9ae7275674" +checksum = "6db3a213adf02b3bcfd2d3846bb41cb22857d131789e01df434fb7e7bc0759b7" dependencies = [ - "autocfg", - "crossbeam-deque", "either", "rayon-core", ] [[package]] name = "rayon-core" -version = "1.9.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ab346ac5921dc62ffa9f89b7a773907511cdfa5490c572ae9be1be33e8afa4a" +checksum = "cac410af5d00ab6884528b4ab69d1e8e146e8d471201800fa1b4524126de6ad3" dependencies = [ "crossbeam-channel", "crossbeam-deque", "crossbeam-utils", - "lazy_static", "num_cpus", ] +[[package]] +name = "rcgen" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6413f3de1edee53342e6138e75b56d32e7bc6e332b3bd62d497b1929d4cfbcdd" +dependencies = [ + "pem", + "ring", + "time 0.3.17", + "x509-parser 0.13.2", + "yasna", +] + +[[package]] +name = "rcgen" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbe84efe2f38dea12e9bfc1f65377fdf03e53a18cb3b995faedf7934c7e785b" +dependencies = [ + "pem", + "ring", + "time 0.3.17", + "yasna", +] + [[package]] name = "redox_syscall" -version = "0.2.10" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ "bitflags", ] [[package]] name = "redox_users" -version = "0.4.0" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ - "getrandom 0.2.3", + "getrandom 0.2.8", "redox_syscall", + "thiserror", ] [[package]] name = "ref-cast" -version = "1.0.6" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "300f2a835d808734ee295d45007adacb9ebb29dd3ae2424acfa17930cae541da" +checksum = "8c78fb8c9293bcd48ef6fce7b4ca950ceaf21210de6e105a883ee280c0f7b9ed" dependencies = [ "ref-cast-impl", ] [[package]] name = "ref-cast-impl" -version = "1.0.6" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c38e3aecd2b21cb3959637b883bb3714bc7e43f0268b9a29d3743ee3e55cdd2" +checksum = "9f9c0c92af03644e4806106281fe2e068ac5bc0ae74a707266d06ea27bccee5f" dependencies = [ "proc-macro2", "quote", @@ -6902,9 +7486,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" +checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a" dependencies = [ "aho-corasick", "memchr", @@ -6913,19 +7497,18 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae1ded71d66a4a97f5e961fd0cb25a5f366a42a41570d16a763a69c092c26ae4" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" dependencies = [ - "byteorder", "regex-syntax", ] [[package]] name = "regex-syntax" -version = "0.6.27" +version = "0.6.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" +checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" [[package]] name = "remove_dir_all" @@ -6948,9 +7531,9 @@ dependencies = [ [[package]] name = "rfc6979" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88c86280f057430a52f4861551b092a01b419b8eacefc7c995eacb9dc132fe32" +checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb" dependencies = [ "crypto-bigint", "hmac 0.12.1", @@ -6984,34 +7567,70 @@ dependencies = [ [[package]] name = "rpassword" -version = "7.0.0" +version = "7.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b763cb66df1c928432cc35053f8bd4cec3335d8559fc16010017d16b3c1680" +checksum = "6678cf63ab3491898c0d021b493c94c9b221d91295294a2a5746eacbe5928322" dependencies = [ "libc", + "rtoolbox", "winapi", ] +[[package]] +name = "rtcp" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1919efd6d4a6a85d13388f9487549bb8e359f17198cc03ffd72f79b553873691" +dependencies = [ + "bytes", + "thiserror", + "webrtc-util", +] + [[package]] name = "rtnetlink" version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "322c53fd76a18698f1c27381d58091de3a043d356aa5bd0d510608b565f469a0" dependencies = [ - "async-global-executor", "futures", "log", "netlink-packet-route", "netlink-proto", - "nix 0.24.2", + "nix 0.24.3", + "thiserror", + "tokio", +] + +[[package]] +name = "rtoolbox" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "034e22c514f5c0cb8a10ff341b9b048b5ceb21591f31c8f44c43b960f9b3524a" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "rtp" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2a095411ff00eed7b12e4c6a118ba984d113e1079582570d56a5ee723f11f80" +dependencies = [ + "async-trait", + "bytes", + "rand 0.8.5", + "serde", "thiserror", + "webrtc-util", ] [[package]] name = "rustc-demangle" -version = "0.1.18" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e3bad0ee36814ca07d7968269dd4b7ec89ec2da10c4bb613928d3077083c232" +checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" [[package]] name = "rustc-hash" @@ -7040,40 +7659,76 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 1.0.4", + "semver 1.0.16", +] + +[[package]] +name = "rusticata-macros" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" +dependencies = [ + "nom", ] [[package]] name = "rustix" -version = "0.35.9" +version = "0.35.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72c825b8aa8010eb9ee99b75f05e10180b9278d161583034d7574c9d617aeada" +checksum = "727a1a6d65f786ec22df8a81ca3121107f235970dc1705ed681d3e6e8b9cd5f9" dependencies = [ "bitflags", "errno", - "io-lifetimes", + "io-lifetimes 0.7.5", "libc", - "linux-raw-sys", - "windows-sys 0.36.1", + "linux-raw-sys 0.0.46", + "windows-sys 0.42.0", +] + +[[package]] +name = "rustix" +version = "0.36.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4feacf7db682c6c329c4ede12649cd36ecab0f3be5b7d74e6a20304725db4549" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes 1.0.3", + "libc", + "linux-raw-sys 0.1.4", + "windows-sys 0.42.0", +] + +[[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.1", + "webpki 0.21.4", ] [[package]] name = "rustls" -version = "0.20.2" +version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d37e5e2290f3e040b594b1a9e04377c2c671f1a1cfd9bfdef82106ac1c113f84" +checksum = "539a2bfe908f471bfa933876bd1eb6a19cf2176d375f82ef7f99530a40e48c2c" dependencies = [ "log", "ring", - "sct", - "webpki", + "sct 0.7.0", + "webpki 0.22.0", ] [[package]] name = "rustls-native-certs" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca9ebdfa27d3fc180e42879037b5338ab1c040c06affd00d8338598e7800943" +checksum = "0167bac7a9f490495f3c33013e7722b53cb087ecbe082fb0c6387c96f634ea50" dependencies = [ "openssl-probe", "rustls-pemfile", @@ -7083,18 +7738,18 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "0.2.1" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eebeaeb360c87bfb72e84abdb3447159c0eaececf1bef2aecd65a8be949d1c9" +checksum = "0864aeff53f8c05aa08d86e5ef839d3dfcf07aeba2db32f12db0ef716e87bd55" dependencies = [ "base64", ] [[package]] name = "rustversion" -version = "1.0.6" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f" +checksum = "5583e89e108996506031660fe09baa5011b9dd0341b89029313006d1fb508d70" [[package]] name = "rusty-fork" @@ -7120,9 +7775,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.5" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" +checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" [[package]] name = "safe-mix" @@ -7252,7 +7907,7 @@ version = "0.10.0-dev" dependencies = [ "array-bytes", "chrono", - "clap 4.0.11", + "clap 4.0.32", "fdlimit", "futures", "futures-timer", @@ -7624,7 +8279,7 @@ dependencies = [ "tempfile", "tracing", "tracing-subscriber 0.2.25", - "wasmi 0.13.0", + "wasmi 0.13.2", "wat", ] @@ -7637,7 +8292,7 @@ dependencies = [ "sp-wasm-interface", "thiserror", "wasm-instrument 0.3.0", - "wasmi 0.13.0", + "wasmi 0.13.2", ] [[package]] @@ -7649,7 +8304,7 @@ dependencies = [ "sc-executor-common", "sp-runtime-interface", "sp-wasm-interface", - "wasmi 0.13.0", + "wasmi 0.13.2", ] [[package]] @@ -7662,7 +8317,7 @@ dependencies = [ "once_cell", "parity-scale-codec", "paste", - "rustix", + "rustix 0.35.13", "sc-allocator", "sc-executor-common", "sc-runtime-test", @@ -7819,7 +8474,7 @@ dependencies = [ "tempfile", "thiserror", "tokio", - "tokio-util 0.7.4", + "tokio-util", "unsigned-varint", "zeroize", ] @@ -8441,9 +9096,9 @@ dependencies = [ [[package]] name = "scale-info" -version = "2.2.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "333af15b02563b8182cd863f925bd31ef8fa86a0e095d30c091956057d436153" +checksum = "001cf62ece89779fd16105b5f515ad0e5cedcd5440d3dd806bb067978e7c3608" dependencies = [ "bitvec", "cfg-if", @@ -8455,9 +9110,9 @@ dependencies = [ [[package]] name = "scale-info-derive" -version = "2.2.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53f56acbd0743d29ffa08f911ab5397def774ad01bab3786804cf6ee057fb5e1" +checksum = "303959cf613a6f6efd19ed4b4ad5bf79966a13352716299ad532cfb115f4205c" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -8467,12 +9122,12 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.19" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75" +checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2" dependencies = [ "lazy_static", - "winapi", + "windows-sys 0.36.1", ] [[package]] @@ -8483,7 +9138,7 @@ checksum = "021b403afe70d81eea68f6ea12f6b3c9588e5d536a94c3bf80f15e7faa267862" dependencies = [ "arrayref", "arrayvec 0.5.2", - "curve25519-dalek 2.1.2", + "curve25519-dalek 2.1.3", "getrandom 0.1.16", "merlin", "rand 0.7.3", @@ -8501,9 +9156,19 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "scratch" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898" +checksum = "ddccb15bcce173023b3fedd9436f882a0739b8dfb45e4f6b6002bee5929f61b2" + +[[package]] +name = "sct" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b362b83898e0e69f38515b82ee15aa80636befe47c3b6d3d89a911e78fc228ce" +dependencies = [ + "ring", + "untrusted", +] [[package]] name = "sct" @@ -8515,6 +9180,18 @@ dependencies = [ "untrusted", ] +[[package]] +name = "sdp" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d22a5ef407871893fd72b4562ee15e4742269b173959db4b8df6f538c414e13" +dependencies = [ + "rand 0.8.5", + "substring", + "thiserror", + "url", +] + [[package]] name = "sec1" version = "0.3.0" @@ -8523,7 +9200,7 @@ checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" dependencies = [ "base16ct", "der", - "generic-array 0.14.4", + "generic-array 0.14.6", "pkcs8", "subtle", "zeroize", @@ -8531,18 +9208,18 @@ dependencies = [ [[package]] name = "secp256k1" -version = "0.24.0" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7649a0b3ffb32636e60c7ce0d70511eda9c52c658cd0634e194d5a19943aeff" +checksum = "d9512ffd81e3a3503ed401f79c33168b9148c75038956039166cd750eaa037c3" dependencies = [ "secp256k1-sys", ] [[package]] name = "secp256k1-sys" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7058dc8eaf3f2810d7828680320acda0b25a288f6d288e19278e249bbf74226b" +checksum = "83080e2c2fc1006e625be82e5d1eb6a43b7fd9578b617fcc55814daf286bba4b" dependencies = [ "cc", ] @@ -8558,9 +9235,9 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.3.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b239a3d5db51252f6f48f42172c65317f37202f4a21021bf5f9d40a408f4592c" +checksum = "2bc1bb97804af6631813c55739f771071e0f2ed33ee20b68c86ec505d906356c" dependencies = [ "bitflags", "core-foundation", @@ -8571,9 +9248,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.3.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e4effb91b4b8b6fb7732e670b6cee160278ff8e6bf485c7805d9e319d76e284" +checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" dependencies = [ "core-foundation-sys", "libc", @@ -8599,9 +9276,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.4" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012" +checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a" dependencies = [ "serde", ] @@ -8614,18 +9291,18 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.145" +version = "1.0.152" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728eb6351430bccb993660dfffc5a72f91ccc1295abaa8ce19b27ebe4f75568b" +checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" dependencies = [ "serde_derive", ] [[package]] name = "serde_cbor" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e18acfa2f90e8b735b2836ab8d538de304cbb6729a7360729ea5a895d15a622" +checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" dependencies = [ "half", "serde", @@ -8633,9 +9310,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.145" +version = "1.0.152" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fa1584d3d1bcacd84c277a0dfe21f5b0f6accf4a23d04d4c6d61f1af522b4c" +checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" dependencies = [ "proc-macro2", "quote", @@ -8644,37 +9321,37 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.85" +version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44" +checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883" dependencies = [ - "itoa 1.0.4", + "itoa 1.0.5", "ryu", "serde", ] [[package]] name = "sha-1" -version = "0.9.4" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfebf75d25bd900fd1e7d11501efab59bc846dbc76196839663e6637bba9f25f" +checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" dependencies = [ "block-buffer 0.9.0", "cfg-if", - "cpuid-bool", + "cpufeatures", "digest 0.9.0", "opaque-debug 0.3.0", ] [[package]] name = "sha1" -version = "0.10.4" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "006769ba83e921b3085caa8334186b00cf92b4cb1a6cf4632fbccc8eff5c7549" +checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" dependencies = [ "cfg-if", "cpufeatures", - "digest 0.10.3", + "digest 0.10.6", ] [[package]] @@ -8691,9 +9368,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.9.8" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b69f9a4c9740d74c5baa3fd2e547f9525fa8088a8a958e0ca2409a514e33f5fa" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" dependencies = [ "block-buffer 0.9.0", "cfg-if", @@ -8704,22 +9381,22 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.2" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" +checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" dependencies = [ "cfg-if", "cpufeatures", - "digest 0.10.3", + "digest 0.10.6", ] [[package]] name = "sha3" -version = "0.10.0" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f935e31cf406e8c0e96c2815a5516181b7004ae8c5f296293221e9b1e356bd" +checksum = "bdf0c33fae925bdc080598b84bc15c55e7b9a4a43b3c704da051f977469691c9" dependencies = [ - "digest 0.10.3", + "digest 0.10.6", "keccak", ] @@ -8734,27 +9411,27 @@ dependencies = [ [[package]] name = "shlex" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42a568c8f2cd051a4d283bd6eb0343ac214c1b0f1ac19f93e1175b2dee38c73d" +checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" [[package]] name = "signal-hook-registry" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16f1d0fef1604ba8f7a073c7e701f213e056707210e9020af4528e0101ce11a6" +checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" dependencies = [ "libc", ] [[package]] name = "signature" -version = "1.6.3" +version = "1.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "deb766570a2825fa972bceff0d195727876a9cdf2460ab2e52d455dc2de47fd9" +checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" dependencies = [ - "digest 0.10.3", - "rand_core 0.6.2", + "digest 0.10.6", + "rand_core 0.6.4", ] [[package]] @@ -8771,9 +9448,12 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.2" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" +checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +dependencies = [ + "autocfg", +] [[package]] name = "slice-group-by" @@ -8789,9 +9469,9 @@ checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" [[package]] name = "snap" -version = "1.0.5" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45456094d1983e2ee2a18fdfebce3189fa451699d0502cb8e3b49dba5ba41451" +checksum = "5e9f0ab6ef7eb7353d9119c170a436d1bf248eea575ac42d19d12f4e34130831" [[package]] name = "snow" @@ -8799,22 +9479,22 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "774d05a3edae07ce6d68ea6984f3c05e9bba8927e3dd591e3b479e5b03213d0d" dependencies = [ - "aes-gcm", + "aes-gcm 0.9.4", "blake2", "chacha20poly1305", - "curve25519-dalek 4.0.0-pre.1", - "rand_core 0.6.2", + "curve25519-dalek 4.0.0-pre.5", + "rand_core 0.6.4", "ring", "rustc_version 0.4.0", - "sha2 0.10.2", + "sha2 0.10.6", "subtle", ] [[package]] name = "socket2" -version = "0.4.4" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" +checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" dependencies = [ "libc", "winapi", @@ -9149,8 +9829,8 @@ version = "5.0.0" dependencies = [ "blake2", "byteorder", - "digest 0.10.3", - "sha2 0.10.2", + "digest 0.10.6", + "sha2 0.10.6", "sha3", "sp-std", "twox-hash", @@ -9321,7 +10001,7 @@ dependencies = [ name = "sp-npos-elections-fuzzer" version = "2.0.0-alpha.5" dependencies = [ - "clap 4.0.11", + "clap 4.0.32", "honggfuzz", "parity-scale-codec", "rand 0.8.5", @@ -9597,7 +10277,7 @@ dependencies = [ "array-bytes", "criterion", "hash-db", - "hashbrown 0.12.3", + "hashbrown", "lazy_static", "lru", "memory-db", @@ -9651,7 +10331,7 @@ dependencies = [ "log", "parity-scale-codec", "sp-std", - "wasmi 0.13.0", + "wasmi 0.13.2", "wasmtime", ] @@ -9693,9 +10373,9 @@ dependencies = [ [[package]] name = "ss58-registry" -version = "1.34.0" +version = "1.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37a9821878e1f13aba383aa40a86fb1b33c7265774ec91e32563cb1dd1577496" +checksum = "23d92659e7d18d82b803824a9ba5a6022cff101c3491d027c1c1d8d30e749284" dependencies = [ "Inflector", "num-format", @@ -9728,7 +10408,7 @@ dependencies = [ "cfg_aliases", "libc", "parking_lot 0.11.2", - "parking_lot_core 0.8.5", + "parking_lot_core 0.8.6", "static_init_macro", "winapi", ] @@ -9776,9 +10456,9 @@ dependencies = [ [[package]] name = "strum_macros" -version = "0.24.2" +version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4faebde00e8ff94316c01800f9054fd2ba77d30d9e922541913051d1d978918b" +checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" dependencies = [ "heck", "proc-macro2", @@ -9787,11 +10467,30 @@ dependencies = [ "syn", ] +[[package]] +name = "stun" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7e94b1ec00bad60e6410e058b52f1c66de3dc5fe4d62d09b3e52bb7d3b73e25" +dependencies = [ + "base64", + "crc", + "lazy_static", + "md-5", + "rand 0.8.5", + "ring", + "subtle", + "thiserror", + "tokio", + "url", + "webrtc-util", +] + [[package]] name = "subkey" version = "2.0.2" dependencies = [ - "clap 4.0.11", + "clap 4.0.32", "sc-cli", ] @@ -9804,7 +10503,7 @@ dependencies = [ "hmac 0.11.0", "pbkdf2 0.8.0", "schnorrkel", - "sha2 0.9.8", + "sha2 0.9.9", "zeroize", ] @@ -9812,14 +10511,14 @@ dependencies = [ name = "substrate-build-script-utils" version = "3.0.0" dependencies = [ - "platforms", + "platforms 2.0.0", ] [[package]] name = "substrate-frame-cli" version = "4.0.0-dev" dependencies = [ - "clap 4.0.11", + "clap 4.0.32", "frame-support", "frame-system", "sc-cli", @@ -10062,17 +10761,26 @@ dependencies = [ "wasm-opt", ] +[[package]] +name = "substring" +version = "1.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ee6433ecef213b2e72f587ef64a2f5943e7cd16fbd82dbe8bc07486c534c86" +dependencies = [ + "autocfg", +] + [[package]] name = "subtle" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e81da0851ada1f3e9d4312c704aa4f8806f0f9d69faaf8df2f3464b4a9437c2" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" -version = "1.0.98" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" +checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" dependencies = [ "proc-macro2", "quote", @@ -10081,9 +10789,9 @@ dependencies = [ [[package]] name = "synstructure" -version = "0.12.4" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" dependencies = [ "proc-macro2", "quote", @@ -10120,9 +10828,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "target-lexicon" -version = "0.12.3" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7fa7e55043acb85fca6b3c01485a2eeb6b69c5d21002e273c79e465f43b7ac1" +checksum = "9410d0f6853b1d94f0e519fb95df60f29d2c1eff2d921ffdf01a4c8a3b54f12d" [[package]] name = "tempfile" @@ -10140,13 +10848,19 @@ dependencies = [ [[package]] name = "termcolor" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" +checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" dependencies = [ "winapi-util", ] +[[package]] +name = "termtree" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95059e91184749cb66be6dc994f67f182b6d897cb3df74a5bf66b5e709295fd8" + [[package]] name = "textwrap" version = "0.11.0" @@ -10158,18 +10872,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.37" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" +checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.37" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" +checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" dependencies = [ "proc-macro2", "quote", @@ -10202,9 +10916,9 @@ dependencies = [ [[package]] name = "tikv-jemalloc-sys" -version = "0.5.1+5.3.0-patched" +version = "0.5.2+5.3.0-patched" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "931e876f91fed0827f863a2d153897790da0b24d882c721a79cb3beb0b903261" +checksum = "ec45c14da997d0925c7835883e4d5c181f196fa142f8c19d7643d1e9af2592c3" dependencies = [ "cc", "fs_extra", @@ -10213,15 +10927,42 @@ dependencies = [ [[package]] name = "time" -version = "0.1.44" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" +checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" dependencies = [ "libc", "wasi 0.10.0+wasi-snapshot-preview1", "winapi", ] +[[package]] +name = "time" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376" +dependencies = [ + "itoa 1.0.5", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" + +[[package]] +name = "time-macros" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d967f99f534ca7e495c575c62638eebc2898a8c84c119b89e250477bc4ba16b2" +dependencies = [ + "time-core", +] + [[package]] name = "tiny-bip39" version = "1.0.0" @@ -10234,7 +10975,7 @@ dependencies = [ "pbkdf2 0.11.0", "rand 0.8.5", "rustc-hash", - "sha2 0.10.2", + "sha2 0.10.6", "thiserror", "unicode-normalization", "wasm-bindgen", @@ -10262,9 +11003,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.1.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317cca572a0e89c3ce0ca1f1bdc9369547fe318a683418e42ac8f59d14701023" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" dependencies = [ "tinyvec_macros", ] @@ -10277,9 +11018,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.22.0" +version = "1.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d76ce4a75fb488c605c54bf610f221cea8b0dafb53333c1a67e8ee199dcd2ae3" +checksum = "eab6d665857cc6ca78d6e80303a02cea7a7851e85dfbd77cbdc09bd129f1ef46" dependencies = [ "autocfg", "bytes", @@ -10292,14 +11033,14 @@ dependencies = [ "signal-hook-registry", "socket2", "tokio-macros", - "winapi", + "windows-sys 0.42.0", ] [[package]] name = "tokio-macros" -version = "1.7.0" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7" +checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8" dependencies = [ "proc-macro2", "quote", @@ -10308,25 +11049,25 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.23.2" +version = "0.23.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a27d5f2b839802bd8267fa19b0530f5a08b9c08cd417976be2a65d130fe1c11b" +checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" dependencies = [ - "rustls", + "rustls 0.20.7", "tokio", - "webpki", + "webpki 0.22.0", ] [[package]] name = "tokio-stream" -version = "0.1.7" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b2f3f698253f03119ac0102beaa64f67a67e08074d03a22d18784104543727f" +checksum = "d660770404473ccd7bc9f8b28494a811bc18542b915c0855c51e8f419d5223ce" dependencies = [ "futures-core", "pin-project-lite 0.2.9", "tokio", - "tokio-util 0.6.10", + "tokio-util", ] [[package]] @@ -10344,38 +11085,24 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.6.10" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36943ee01a6d67977dd3f84a5a1d2efeb4ada3a1ae771cadfaa535d9d9fc6507" +checksum = "0bb2e075f03b3d66d8d8785356224ba688d2906a371015e225beeb65ca92c740" dependencies = [ "bytes", "futures-core", + "futures-io", "futures-sink", - "log", "pin-project-lite 0.2.9", "tokio", + "tracing", ] [[package]] -name = "tokio-util" -version = "0.7.4" +name = "toml" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bb2e075f03b3d66d8d8785356224ba688d2906a371015e225beeb65ca92c740" -dependencies = [ - "bytes", - "futures-core", - "futures-io", - "futures-sink", - "pin-project-lite 0.2.9", - "tokio", - "tracing", -] - -[[package]] -name = "toml" -version = "0.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" +checksum = "1333c76748e868a4d9d1017b5ab53171dfd095f70c712fdb4653a406547f598f" dependencies = [ "serde", ] @@ -10417,15 +11144,15 @@ checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" [[package]] name = "tower-service" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.35" +version = "0.1.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a400e31aa60b9d44a52a8ee0343b5b18566b03a8321e0d321f695cf56e940160" +checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" dependencies = [ "cfg-if", "log", @@ -10436,9 +11163,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11c75893af559bc8e10716548bdef5cb2b983f8e637db9d0e15126b61b484ee2" +checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" dependencies = [ "proc-macro2", "quote", @@ -10478,9 +11205,9 @@ dependencies = [ [[package]] name = "tracing-serde" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb65ea441fbb84f9f6748fd496cf7f63ec9af5bca94dd86456978d055e8eb28b" +checksum = "bc6b213177105856957181934e4920de57730fc69bf42c37ee5bb664d406d9e1" dependencies = [ "serde", "tracing-core", @@ -10527,12 +11254,6 @@ dependencies = [ "tracing-log", ] -[[package]] -name = "treeline" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7f741b240f1a48843f9b8e0444fb55fb2a4ff67293b50a9179dfd5ea67f8d41" - [[package]] name = "trie-bench" version = "0.33.0" @@ -10556,7 +11277,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "004e1e8f92535694b4cb1444dc5a8073ecf0815e3357f729638b9f8fc4062908" dependencies = [ "hash-db", - "hashbrown 0.12.3", + "hashbrown", "log", "rustc-hex", "smallvec", @@ -10594,11 +11315,12 @@ dependencies = [ "futures-channel", "futures-io", "futures-util", - "idna", + "idna 0.2.3", "ipnet", "lazy_static", "rand 0.8.5", "smallvec", + "socket2", "thiserror", "tinyvec", "tokio", @@ -10636,7 +11358,7 @@ checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" name = "try-runtime-cli" version = "0.10.0-dev" dependencies = [ - "clap 4.0.11", + "clap 4.0.32", "frame-remote-externalities", "frame-try-runtime", "hex", @@ -10665,9 +11387,9 @@ dependencies = [ [[package]] name = "trybuild" -version = "1.0.60" +version = "1.0.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0da18123d1316f5a65fc9b94e30a0fcf58afb1daff1b8e18f41dc30f5bfc38c8" +checksum = "ed01de3de062db82c0920b5cabe804f88d599a3f217932292597c678c903754d" dependencies = [ "dissimilar", "glob", @@ -10681,9 +11403,28 @@ dependencies = [ [[package]] name = "tt-call" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e66dcbec4290c69dd03c57e76c2469ea5c7ce109c6dd4351c13055cf71ea055" +checksum = "f4f195fd851901624eee5a58c4bb2b4f06399148fcd0ed336e6f1cb60a9881df" + +[[package]] +name = "turn" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4712ee30d123ec7ae26d1e1b218395a16c87cdbaf4b3925d170d684af62ea5e8" +dependencies = [ + "async-trait", + "base64", + "futures", + "log", + "md-5", + "rand 0.8.5", + "ring", + "stun", + "thiserror", + "tokio", + "webrtc-util", +] [[package]] name = "twox-hash" @@ -10692,28 +11433,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" dependencies = [ "cfg-if", - "digest 0.10.3", + "digest 0.10.6", "rand 0.8.5", "static_assertions", ] [[package]] name = "typenum" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" [[package]] name = "ucd-trie" -version = "0.1.3" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" +checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" [[package]] name = "uint" -version = "0.9.0" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e11fe9a9348741cf134085ad57c249508345fe16411b3d7fb4ff2da2f1d6382e" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" dependencies = [ "byteorder", "crunchy", @@ -10723,18 +11464,15 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.4" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" -dependencies = [ - "matches", -] +checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" [[package]] name = "unicode-ident" -version = "1.0.1" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" +checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" [[package]] name = "unicode-normalization" @@ -10747,15 +11485,15 @@ dependencies = [ [[package]] name = "unicode-width" -version = "0.1.8" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" [[package]] name = "unicode-xid" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" [[package]] name = "universal-hash" @@ -10763,7 +11501,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05" dependencies = [ - "generic-array 0.14.4", + "generic-array 0.14.6", "subtle", ] @@ -10787,16 +11525,24 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" [[package]] name = "url" -version = "2.2.1" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ccd964113622c8e9322cfac19eb1004a07e636c545f325da085d5cdde6f1f8b" +checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" dependencies = [ "form_urlencoded", - "idna", - "matches", + "idna 0.3.0", "percent-encoding", ] +[[package]] +name = "uuid" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "422ee0de9031b5b948b97a8fc04e3aa35230001a722ddd27943e0be31564ce4c" +dependencies = [ + "getrandom 0.2.8", +] + [[package]] name = "valuable" version = "0.1.0" @@ -10805,21 +11551,15 @@ checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" [[package]] name = "vcpkg" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b00bca6106a5e23f3eee943593759b7fcddb00554332e856d990c893966879fb" - -[[package]] -name = "vec-arena" -version = "1.0.0" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eafc1b9b2dfc6f5529177b62cf806484db55b32dc7c9658a118e11bbeb33061d" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "version_check" -version = "0.9.2" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "void" @@ -10836,6 +11576,15 @@ dependencies = [ "libc", ] +[[package]] +name = "waitgroup" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1f50000a783467e6c0200f9d10642f4bc424e39efc1b770203e88b488f79292" +dependencies = [ + "atomic-waker", +] + [[package]] name = "waker-fn" version = "1.1.0" @@ -10883,9 +11632,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.77" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e68338db6becec24d3c7977b5bf8a48be992c934b5d07177e3931f5dc9b076c" +checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -10893,13 +11642,13 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.77" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f34c405b4f0658583dba0c1c7c9b694f3cac32655db463b56c254a1c75269523" +checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" dependencies = [ "bumpalo", - "lazy_static", "log", + "once_cell", "proc-macro2", "quote", "syn", @@ -10908,9 +11657,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.20" +version = "0.4.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3de431a2910c86679c34283a33f66f4e4abd7e0aec27b6669060148872aadf94" +checksum = "23639446165ca5a5de86ae1d8896b737ae80319560fbaa4c2887b7da6e7ebd7d" dependencies = [ "cfg-if", "js-sys", @@ -10920,9 +11669,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.77" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d5a6580be83b19dc570a8f9c324251687ab2184e57086f71625feb57ec77c8" +checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -10930,9 +11679,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.77" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3775a030dc6f5a0afd8a84981a21cc92a781eb429acef9ecce476d0c9113e92" +checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" dependencies = [ "proc-macro2", "quote", @@ -10943,9 +11692,18 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.77" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c279e376c7a8e8752a8f1eaa35b7b0bee6bb9fb0cdacfa97cc3f1f289c87e2b4" +checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" + +[[package]] +name = "wasm-encoder" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05632e0a66a6ed8cca593c24223aabd6262f256c3693ad9822c315285f010614" +dependencies = [ + "leb128", +] [[package]] name = "wasm-instrument" @@ -11023,13 +11781,13 @@ dependencies = [ [[package]] name = "wasmi" -version = "0.13.0" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc13b3c219ca9aafeec59150d80d89851df02e0061bc357b4d66fc55a8d38787" +checksum = "06c326c93fbf86419608361a2c925a31754cf109da1b8b55737070b4d6669422" dependencies = [ "parity-wasm", "wasmi-validation", - "wasmi_core 0.2.0", + "wasmi_core 0.2.1", ] [[package]] @@ -11061,12 +11819,12 @@ checksum = "a1ea379cbb0b41f3a9f0bf7b47036d036aae7f43383d8cc487d4deccf40dee0a" [[package]] name = "wasmi_core" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a088e8c4c59c6f2b9eae169bf86328adccc477c00b56d3661e3e9fb397b184" +checksum = "57d20cb3c59b788653d99541c646c561c9dd26506f25c0cebfe810659c54c6d7" dependencies = [ "downcast-rs", - "libm", + "libm 0.2.6", "memory_units", "num-rational", "num-traits", @@ -11079,7 +11837,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c5bf998ab792be85e20e771fe14182b4295571ad1d4f89d3da521c1bef5f597a" dependencies = [ "downcast-rs", - "libm", + "libm 0.2.6", "num-traits", ] @@ -11103,9 +11861,9 @@ dependencies = [ [[package]] name = "wasmtime" -version = "1.0.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a10dc9784d8c3a33c970e3939180424955f08af2e7f20368ec02685a0e8f065" +checksum = "4ad5af6ba38311282f2a21670d96e78266e8c8e2f38cbcd52c254df6ccbc7731" dependencies = [ "anyhow", "bincode", @@ -11131,18 +11889,18 @@ dependencies = [ [[package]] name = "wasmtime-asm-macros" -version = "1.0.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee4dbdc6daf68528cad1275ac91e3f51848ce9824385facc94c759f529decdf8" +checksum = "45de63ddfc8b9223d1adc8f7b2ee5f35d1f6d112833934ad7ea66e4f4339e597" dependencies = [ "cfg-if", ] [[package]] name = "wasmtime-cache" -version = "1.0.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f507f3fa1ee1b2f9a83644e2514242b1dfe580782c0eb042f1ef70255bc4ffe" +checksum = "bcd849399d17d2270141cfe47fa0d91ee52d5f8ea9b98cf7ddde0d53e5f79882" dependencies = [ "anyhow", "base64", @@ -11150,9 +11908,9 @@ dependencies = [ "directories-next", "file-per-thread-logger", "log", - "rustix", + "rustix 0.35.13", "serde", - "sha2 0.9.8", + "sha2 0.9.9", "toml", "windows-sys 0.36.1", "zstd", @@ -11160,9 +11918,9 @@ dependencies = [ [[package]] name = "wasmtime-cranelift" -version = "1.0.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f03cf79d982fc68e94ba0bea6a300a3b94621c4eb9705eece0a4f06b235a3b5" +checksum = "4bd91339b742ff20bfed4532a27b73c86b5bcbfedd6bea2dcdf2d64471e1b5c6" dependencies = [ "anyhow", "cranelift-codegen", @@ -11170,7 +11928,7 @@ dependencies = [ "cranelift-frontend", "cranelift-native", "cranelift-wasm", - "gimli 0.26.1", + "gimli 0.26.2", "log", "object 0.29.0", "target-lexicon", @@ -11181,13 +11939,13 @@ dependencies = [ [[package]] name = "wasmtime-environ" -version = "1.0.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c587c62e91c5499df62012b87b88890d0eb470b2ffecc5964e9da967b70c77c" +checksum = "ebb881c61f4f627b5d45c54e629724974f8a8890d455bcbe634330cc27309644" dependencies = [ "anyhow", "cranelift-entity", - "gimli 0.26.1", + "gimli 0.26.2", "indexmap", "log", "object 0.29.0", @@ -11200,20 +11958,20 @@ dependencies = [ [[package]] name = "wasmtime-jit" -version = "1.0.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "047839b5dabeae5424a078c19b8cc897e5943a7fadc69e3d888b9c9a897666b3" +checksum = "1985c628011fe26adf5e23a5301bdc79b245e0e338f14bb58b39e4e25e4d8681" dependencies = [ "addr2line 0.17.0", "anyhow", "bincode", "cfg-if", "cpp_demangle", - "gimli 0.26.1", + "gimli 0.26.2", "log", "object 0.29.0", "rustc-demangle", - "rustix", + "rustix 0.35.13", "serde", "target-lexicon", "thiserror", @@ -11225,20 +11983,20 @@ dependencies = [ [[package]] name = "wasmtime-jit-debug" -version = "1.0.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b299569abf6f99b7b8e020afaf84a700e8636c6a42e242069267322cd5818235" +checksum = "f671b588486f5ccec8c5a3dba6b4c07eac2e66ab8c60e6f4e53717c77f709731" dependencies = [ "object 0.29.0", "once_cell", - "rustix", + "rustix 0.35.13", ] [[package]] name = "wasmtime-runtime" -version = "1.0.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae79e0515160bd5abee5df50a16c4eb8db9f71b530fc988ae1d9ce34dcb8dd01" +checksum = "ee8f92ad4b61736339c29361da85769ebc200f184361959d1792832e592a1afd" dependencies = [ "anyhow", "cc", @@ -11248,10 +12006,10 @@ dependencies = [ "log", "mach", "memfd", - "memoffset", + "memoffset 0.6.5", "paste", "rand 0.8.5", - "rustix", + "rustix 0.35.13", "thiserror", "wasmtime-asm-macros", "wasmtime-environ", @@ -11261,9 +12019,9 @@ dependencies = [ [[package]] name = "wasmtime-types" -version = "1.0.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "790cf43ee8e2d5dad1780af30f00d7a972b74725fb1e4f90c28d62733819b185" +checksum = "d23d61cb4c46e837b431196dd06abb11731541021916d03476a178b54dc07aeb" dependencies = [ "cranelift-entity", "serde", @@ -11273,32 +12031,45 @@ dependencies = [ [[package]] name = "wast" -version = "38.0.0" +version = "50.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ebc29df4629f497e0893aacd40f13a4a56b85ef6eb4ab6d603f07244f1a7bf2" +checksum = "a2cbb59d4ac799842791fe7e806fa5dbbf6b5554d538e51cc8e176db6ff0ae34" dependencies = [ "leb128", + "memchr", + "unicode-width", + "wasm-encoder", ] [[package]] name = "wat" -version = "1.0.40" +version = "1.0.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adcfaeb27e2578d2c6271a45609f4a055e6d7ba3a12eff35b1fd5ba147bdf046" +checksum = "584aaf7a1ecf4d383bbe1a25eeab0cbb8ff96acc6796707ff65cde48f4632f15" dependencies = [ "wast", ] [[package]] name = "web-sys" -version = "0.3.54" +version = "0.3.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a84d70d1ec7d2da2d26a5bd78f4bca1b8c3254805363ce743b7a05bc30d195a" +checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" dependencies = [ "js-sys", "wasm-bindgen", ] +[[package]] +name = "webpki" +version = "0.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "webpki" version = "0.22.0" @@ -11311,11 +12082,223 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.22.2" +version = "0.22.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87" +dependencies = [ + "webpki 0.22.0", +] + +[[package]] +name = "webrtc" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d3bc9049bdb2cea52f5fd4f6f728184225bdb867ed0dc2410eab6df5bdd67bb" +dependencies = [ + "arc-swap", + "async-trait", + "bytes", + "hex", + "interceptor", + "lazy_static", + "log", + "rand 0.8.5", + "rcgen 0.9.3", + "regex", + "ring", + "rtcp", + "rtp", + "rustls 0.19.1", + "sdp", + "serde", + "serde_json", + "sha2 0.10.6", + "stun", + "thiserror", + "time 0.3.17", + "tokio", + "turn", + "url", + "waitgroup", + "webrtc-data", + "webrtc-dtls", + "webrtc-ice", + "webrtc-mdns", + "webrtc-media", + "webrtc-sctp", + "webrtc-srtp", + "webrtc-util", +] + +[[package]] +name = "webrtc-data" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ef36a4d12baa6e842582fe9ec16a57184ba35e1a09308307b67d43ec8883100" +dependencies = [ + "bytes", + "derive_builder", + "log", + "thiserror", + "tokio", + "webrtc-sctp", + "webrtc-util", +] + +[[package]] +name = "webrtc-dtls" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7021987ae0a2ed6c8cd33f68e98e49bb6e74ffe9543310267b48a1bbe3900e5f" +dependencies = [ + "aes 0.6.0", + "aes-gcm 0.8.0", + "async-trait", + "bincode", + "block-modes", + "byteorder", + "ccm", + "curve25519-dalek 3.2.0", + "der-parser 8.1.0", + "elliptic-curve", + "hkdf", + "hmac 0.10.1", + "log", + "oid-registry 0.6.1", + "p256", + "p384", + "rand 0.8.5", + "rand_core 0.6.4", + "rcgen 0.9.3", + "ring", + "rustls 0.19.1", + "sec1", + "serde", + "sha-1", + "sha2 0.9.9", + "signature", + "subtle", + "thiserror", + "tokio", + "webpki 0.21.4", + "webrtc-util", + "x25519-dalek 2.0.0-pre.1", + "x509-parser 0.13.2", +] + +[[package]] +name = "webrtc-ice" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "552ceb903e957524388c4d3475725ff2c8b7960922063af6ce53c9a43da07449" +checksum = "494483fbb2f5492620871fdc78b084aed8807377f6e3fe88b2e49f0a9c9c41d7" dependencies = [ - "webpki", + "arc-swap", + "async-trait", + "crc", + "log", + "rand 0.8.5", + "serde", + "serde_json", + "stun", + "thiserror", + "tokio", + "turn", + "url", + "uuid", + "waitgroup", + "webrtc-mdns", + "webrtc-util", +] + +[[package]] +name = "webrtc-mdns" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f08dfd7a6e3987e255c4dbe710dde5d94d0f0574f8a21afa95d171376c143106" +dependencies = [ + "log", + "socket2", + "thiserror", + "tokio", + "webrtc-util", +] + +[[package]] +name = "webrtc-media" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee2a3c157a040324e5049bcbd644ffc9079e6738fa2cfab2bcff64e5cc4c00d7" +dependencies = [ + "byteorder", + "bytes", + "derive_builder", + "displaydoc", + "rand 0.8.5", + "rtp", + "thiserror", + "webrtc-util", +] + +[[package]] +name = "webrtc-sctp" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d47adcd9427eb3ede33d5a7f3424038f63c965491beafcc20bc650a2f6679c0" +dependencies = [ + "arc-swap", + "async-trait", + "bytes", + "crc", + "log", + "rand 0.8.5", + "thiserror", + "tokio", + "webrtc-util", +] + +[[package]] +name = "webrtc-srtp" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6183edc4c1c6c0175f8812eefdce84dfa0aea9c3ece71c2bf6ddd3c964de3da5" +dependencies = [ + "aead 0.4.3", + "aes 0.7.5", + "aes-gcm 0.9.4", + "async-trait", + "byteorder", + "bytes", + "ctr 0.8.0", + "hmac 0.11.0", + "log", + "rtcp", + "rtp", + "sha-1", + "subtle", + "thiserror", + "tokio", + "webrtc-util", +] + +[[package]] +name = "webrtc-util" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93f1db1727772c05cf7a2cfece52c3aca8045ca1e176cd517d323489aa3c6d87" +dependencies = [ + "async-trait", + "bitflags", + "bytes", + "cc", + "ipnet", + "lazy_static", + "libc", + "log", + "nix 0.24.3", + "rand 0.8.5", + "thiserror", + "tokio", + "winapi", ] [[package]] @@ -11329,12 +12312,13 @@ dependencies = [ [[package]] name = "which" -version = "4.0.2" +version = "4.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87c14ef7e1b8b8ecfc75d5eca37949410046e66f15d185c01d70824f1f8111ef" +checksum = "1c831fbbee9e129a8cf93e7747a82da9d95ba8e16621cae60ec2cdc849bacb7b" dependencies = [ + "either", "libc", - "thiserror", + "once_cell", ] [[package]] @@ -11387,19 +12371,6 @@ dependencies = [ "windows_x86_64_msvc 0.34.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 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-sys" version = "0.36.1" @@ -11414,10 +12385,25 @@ dependencies = [ ] [[package]] -name = "windows_aarch64_msvc" -version = "0.32.0" +name = "windows-sys" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc 0.42.0", + "windows_i686_gnu 0.42.0", + "windows_i686_msvc 0.42.0", + "windows_x86_64_gnu 0.42.0", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc 0.42.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8e92753b1c443191654ec532f14c199742964a061be25d77d7a96f09db20bf5" +checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" [[package]] name = "windows_aarch64_msvc" @@ -11432,10 +12418,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" [[package]] -name = "windows_i686_gnu" -version = "0.32.0" +name = "windows_aarch64_msvc" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a711c68811799e017b6038e0922cb27a5e2f43a2ddb609fe0b6f3eeda9de615" +checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" [[package]] name = "windows_i686_gnu" @@ -11450,10 +12436,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" [[package]] -name = "windows_i686_msvc" -version = "0.32.0" +name = "windows_i686_gnu" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "146c11bb1a02615db74680b32a68e2d61f553cc24c4eb5b4ca10311740e44172" +checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" [[package]] name = "windows_i686_msvc" @@ -11468,10 +12454,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" [[package]] -name = "windows_x86_64_gnu" -version = "0.32.0" +name = "windows_i686_msvc" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c912b12f7454c6620635bbff3450962753834be2a594819bd5e945af18ec64bc" +checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" [[package]] name = "windows_x86_64_gnu" @@ -11486,10 +12472,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" [[package]] -name = "windows_x86_64_msvc" -version = "0.32.0" +name = "windows_x86_64_gnu" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "504a2476202769977a040c6364301a3f65d0cc9e3fb08600b2bda150a0488316" +checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" [[package]] name = "windows_x86_64_msvc" @@ -11503,20 +12495,26 @@ version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" + [[package]] name = "winreg" -version = "0.7.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69" +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" dependencies = [ "winapi", ] [[package]] name = "wyz" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30b31594f29d27036c383b53b59ed3476874d518f0efb151b27a4c275141390e" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" dependencies = [ "tap", ] @@ -11527,11 +12525,59 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a0c105152107e3b96f6a00a65e86ce82d9b125230e1c4302940eca58ff71f4f" dependencies = [ - "curve25519-dalek 3.0.2", + "curve25519-dalek 3.2.0", "rand_core 0.5.1", "zeroize", ] +[[package]] +name = "x25519-dalek" +version = "2.0.0-pre.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5da623d8af10a62342bcbbb230e33e58a63255a58012f8653c578e54bab48df" +dependencies = [ + "curve25519-dalek 3.2.0", + "rand_core 0.6.4", + "zeroize", +] + +[[package]] +name = "x509-parser" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb9bace5b5589ffead1afb76e43e34cff39cd0f3ce7e170ae0c29e53b88eb1c" +dependencies = [ + "asn1-rs 0.3.1", + "base64", + "data-encoding", + "der-parser 7.0.0", + "lazy_static", + "nom", + "oid-registry 0.4.0", + "ring", + "rusticata-macros", + "thiserror", + "time 0.3.17", +] + +[[package]] +name = "x509-parser" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0ecbeb7b67ce215e40e3cc7f2ff902f94a223acf44995934763467e7b1febc8" +dependencies = [ + "asn1-rs 0.5.1", + "base64", + "data-encoding", + "der-parser 8.1.0", + "lazy_static", + "nom", + "oid-registry 0.6.1", + "rusticata-macros", + "thiserror", + "time 0.3.17", +] + [[package]] name = "yamux" version = "0.10.2" @@ -11546,6 +12592,21 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "yansi" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" + +[[package]] +name = "yasna" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aed2e7a52e3744ab4d0c05c20aa065258e84c49fd4226f5191b2ed29712710b4" +dependencies = [ + "time 0.3.17", +] + [[package]] name = "zeroize" version = "1.5.7" @@ -11557,9 +12618,9 @@ dependencies = [ [[package]] name = "zeroize_derive" -version = "1.3.2" +version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f8f187641dad4f680d25c4bfc4225b418165984179f26ca76ec4fb6441d3a17" +checksum = "44bf07cb3e50ea2003396695d58bf46bc9887a1f362260446fad6bc4e79bd36c" dependencies = [ "proc-macro2", "quote", @@ -11588,9 +12649,9 @@ dependencies = [ [[package]] name = "zstd-sys" -version = "2.0.1+zstd.1.5.2" +version = "2.0.4+zstd.1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fd07cbbc53846d9145dbffdf6dd09a7a0aa52be46741825f5c97bdd4f73f12b" +checksum = "4fa202f2ef00074143e219d15b62ffc317d17cc33909feac471c044087cad7b0" dependencies = [ "cc", "libc", diff --git a/client/authority-discovery/Cargo.toml b/client/authority-discovery/Cargo.toml index 5b07e4b7bbeab..a24002517cca8 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.49.0", default-features = false, features = ["kad"] } +libp2p = { version = "0.50.0", features = ["kad"] } log = "0.4.17" prost = "0.11" rand = "0.8.5" diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index ee4426b91dbb8..5e1f2bab4be9f 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -18,7 +18,7 @@ chrono = "0.4.10" clap = { version = "4.0.9", features = ["derive", "string"] } fdlimit = "0.2.1" futures = "0.3.21" -libp2p = "0.49.0" +libp2p = "0.50.0" log = "0.4.17" names = { version = "0.13.0", default-features = false } parity-scale-codec = "3.0.0" diff --git a/client/cli/src/runner.rs b/client/cli/src/runner.rs index 1a532b3bbc6fb..c7a6f1f3c0f99 100644 --- a/client/cli/src/runner.rs +++ b/client/cli/src/runner.rs @@ -228,7 +228,7 @@ impl Runner { pub fn print_node_infos(config: &Configuration) { info!("{}", C::impl_name()); info!("✌️ version {}", C::impl_version()); - info!("❤️ by {}, {}-{}", C::author(), C::copyright_start_year(), Local::today().year()); + info!("❤️ by {}, {}-{}", C::author(), C::copyright_start_year(), Local::now().year()); info!("📋 Chain specification: {}", config.chain_spec.name()); info!("🏷 Node name: {}", config.network.node_name); info!("👤 Role: {}", config.display_role()); diff --git a/client/consensus/common/Cargo.toml b/client/consensus/common/Cargo.toml index b61c6a4334285..87b052d434e93 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.49.0", default-features = false } +libp2p = "0.50.0" log = "0.4.17" mockall = "0.11.2" parking_lot = "0.12.1" diff --git a/client/network-gossip/Cargo.toml b/client/network-gossip/Cargo.toml index c40a830f9219b..ef23062768d1e 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.49.0", default-features = false } +libp2p = "0.50.0" log = "0.4.17" lru = "0.8.1" tracing = "0.1.29" diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index 35d4253f6b37f..4356cc5df1b13 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -25,7 +25,7 @@ fnv = "1.0.6" futures = "0.3.21" futures-timer = "3.0.2" ip_network = "0.4.1" -libp2p = { version = "0.49.0", features = ["dns", "identify", "kad", "mdns", "mplex", "noise", "ping", "tcp", "tokio", "yamux", "websocket"] } +libp2p = { version = "0.50.0", features = ["dns", "identify", "kad", "macros", "mdns", "mplex", "noise", "ping", "tcp", "tokio", "yamux", "websocket"] } log = "0.4.17" lru = "0.8.1" parking_lot = "0.12.1" diff --git a/client/network/bitswap/Cargo.toml b/client/network/bitswap/Cargo.toml index c4c7850b7170b..0bbb5ff09e4b9 100644 --- a/client/network/bitswap/Cargo.toml +++ b/client/network/bitswap/Cargo.toml @@ -18,7 +18,7 @@ prost-build = "0.11" [dependencies] cid = "0.8.6" futures = "0.3.21" -libp2p = "0.49.0" +libp2p = "0.50.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 545ae8a8af514..e2dd7d0894eb0 100644 --- a/client/network/common/Cargo.toml +++ b/client/network/common/Cargo.toml @@ -24,7 +24,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", features = [ ] } futures = "0.3.21" futures-timer = "3.0.2" -libp2p = { version = "0.49.0", features = [ "request-response", "kad" ] } +libp2p = { version = "0.50.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 5b84a0adde20f..8a3e9037729a8 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.49.0" +libp2p = "0.50.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 3a977edbca574..eac74f7e6e37d 100644 --- a/client/network/src/behaviour.rs +++ b/client/network/src/behaviour.rs @@ -29,7 +29,7 @@ use libp2p::{ core::{Multiaddr, PeerId, PublicKey}, identify::Info as IdentifyInfo, kad::record, - NetworkBehaviour, + swarm::NetworkBehaviour, }; use sc_network_common::{ diff --git a/client/network/src/discovery.rs b/client/network/src/discovery.rs index 13b153be11d59..16dbc7662c192 100644 --- a/client/network/src/discovery.rs +++ b/client/network/src/discovery.rs @@ -51,23 +51,23 @@ use futures::prelude::*; use futures_timer::Delay; use ip_network::IpNetwork; use libp2p::{ - core::{ - connection::ConnectionId, transport::ListenerId, ConnectedPoint, Multiaddr, PeerId, - PublicKey, - }, + core::{connection::ConnectionId, Multiaddr, PeerId, PublicKey}, kad::{ handler::KademliaHandlerProto, record::{ self, store::{MemoryStore, RecordStore}, }, - GetClosestPeersError, Kademlia, KademliaBucketInserts, KademliaConfig, KademliaEvent, - QueryId, QueryResult, Quorum, Record, + GetClosestPeersError, GetRecordOk, Kademlia, KademliaBucketInserts, KademliaConfig, + KademliaEvent, QueryId, QueryResult, Quorum, Record, }, - mdns::{MdnsConfig, MdnsEvent, TokioMdns}, + mdns::{self, tokio::Behaviour as TokioMdns}, multiaddr::Protocol, swarm::{ - behaviour::toggle::{Toggle, ToggleIntoConnectionHandler}, + behaviour::{ + toggle::{Toggle, ToggleIntoConnectionHandler}, + DialFailure, FromSwarm, NewExternalAddr, + }, ConnectionHandler, DialError, IntoConnectionHandler, NetworkBehaviour, NetworkBehaviourAction, PollParameters, }, @@ -78,7 +78,6 @@ use sp_core::hexdisplay::HexDisplay; use std::{ cmp, collections::{HashMap, HashSet, VecDeque}, - io, num::NonZeroUsize, task::{Context, Poll}, time::Duration, @@ -235,7 +234,7 @@ impl DiscoveryConfig { allow_private_ipv4, discovery_only_if_under_num, mdns: if enable_mdns { - match TokioMdns::new(MdnsConfig::default()) { + match TokioMdns::new(mdns::Config::default()) { Ok(mdns) => Some(mdns), Err(err) => { warn!(target: "sub-libp2p", "Failed to initialize mDNS: {:?}", err); @@ -250,6 +249,7 @@ impl DiscoveryConfig { NonZeroUsize::new(MAX_KNOWN_EXTERNAL_ADDRESSES) .expect("value is a constant; constant is non-zero; qed."), ), + outbound_query_records: Vec::new(), } } } @@ -287,6 +287,8 @@ pub struct DiscoveryBehaviour { allow_non_globals_in_dht: bool, /// A cache of discovered external addresses. Only used for logging purposes. known_external_addresses: LruHashSet, + /// A cache of outbound query records. + outbound_query_records: Vec<(record::Key, Vec)>, } impl DiscoveryBehaviour { @@ -367,7 +369,7 @@ impl DiscoveryBehaviour { /// A corresponding `ValueFound` or `ValueNotFound` event will later be generated. pub fn get_value(&mut self, key: record::Key) { if let Some(k) = self.kademlia.as_mut() { - k.get_record(key.clone(), Quorum::One); + k.get_record(key.clone()); } } @@ -516,127 +518,84 @@ impl NetworkBehaviour for DiscoveryBehaviour { list } - fn inject_address_change( - &mut self, - peer_id: &PeerId, - connection_id: &ConnectionId, - old: &ConnectedPoint, - new: &ConnectedPoint, - ) { - self.kademlia.inject_address_change(peer_id, connection_id, old, new) - } - - fn inject_connection_established( - &mut self, - peer_id: &PeerId, - conn: &ConnectionId, - endpoint: &ConnectedPoint, - failed_addresses: Option<&Vec>, - other_established: usize, - ) { - self.num_connections += 1; - self.kademlia.inject_connection_established( - peer_id, - conn, - endpoint, - failed_addresses, - other_established, - ) - } + fn on_swarm_event(&mut self, event: FromSwarm) { + match event { + FromSwarm::ConnectionEstablished(e) => { + self.num_connections += 1; + self.kademlia.on_swarm_event(FromSwarm::ConnectionEstablished(e)); + }, + FromSwarm::ConnectionClosed(e) => { + self.num_connections -= 1; + self.kademlia.on_swarm_event(FromSwarm::ConnectionClosed(e)); + }, + FromSwarm::DialFailure(e @ DialFailure { peer_id, error, .. }) => { + if let Some(peer_id) = peer_id { + 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); + } + } + } + } - fn inject_connection_closed( - &mut self, - peer_id: &PeerId, - conn: &ConnectionId, - endpoint: &ConnectedPoint, - handler: ::Handler, - remaining_established: usize, - ) { - self.num_connections -= 1; - self.kademlia.inject_connection_closed( - peer_id, - conn, - endpoint, - handler, - remaining_established, - ) - } + self.kademlia.on_swarm_event(FromSwarm::DialFailure(e)); + }, + FromSwarm::ListenerClosed(e) => { + self.kademlia.on_swarm_event(FromSwarm::ListenerClosed(e)); + }, + FromSwarm::ListenFailure(e) => { + self.kademlia.on_swarm_event(FromSwarm::ListenFailure(e)); + }, + FromSwarm::ListenerError(e) => { + self.kademlia.on_swarm_event(FromSwarm::ListenerError(e)); + }, + FromSwarm::ExpiredExternalAddr(e) => { + // We intentionally don't remove the element from `known_external_addresses` in + // order to not print the log line again. - fn inject_dial_failure( - &mut self, - peer_id: Option, - handler: Self::ConnectionHandler, - error: &DialError, - ) { - if let Some(peer_id) = peer_id { - 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); + self.kademlia.on_swarm_event(FromSwarm::ExpiredExternalAddr(e)); + }, + FromSwarm::NewListener(e) => { + self.kademlia.on_swarm_event(FromSwarm::NewListener(e)); + }, + FromSwarm::ExpiredListenAddr(e) => { + self.kademlia.on_swarm_event(FromSwarm::ExpiredListenAddr(e)); + }, + FromSwarm::NewExternalAddr(e @ NewExternalAddr { addr }) => { + let new_addr = addr.clone().with(Protocol::P2p(self.local_peer_id.into())); + + 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, + ); } } - } - } - self.kademlia.inject_dial_failure(peer_id, handler, error) + self.kademlia.on_swarm_event(FromSwarm::NewExternalAddr(e)); + }, + FromSwarm::AddressChange(e) => { + self.kademlia.on_swarm_event(FromSwarm::AddressChange(e)); + }, + FromSwarm::NewListenAddr(e) => { + self.kademlia.on_swarm_event(FromSwarm::NewListenAddr(e)); + }, + } } - fn inject_event( + fn on_connection_handler_event( &mut self, peer_id: PeerId, - connection: ConnectionId, - event: <::Handler as ConnectionHandler>::OutEvent, + connection_id: ConnectionId, + event: <::Handler as + ConnectionHandler>::OutEvent, ) { - 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) { - // 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, - ); - } - } - - 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. - - self.kademlia.inject_expired_external_addr(addr) - } - - fn inject_expired_listen_addr(&mut self, id: ListenerId, addr: &Multiaddr) { - self.kademlia.inject_expired_listen_addr(id, addr) - } - - fn inject_new_listener(&mut self, id: ListenerId) { - self.kademlia.inject_new_listener(id) - } - - fn inject_new_listen_addr(&mut self, id: ListenerId, addr: &Multiaddr) { - self.kademlia.inject_new_listen_addr(id, addr) - } - - fn inject_listen_failure(&mut self, _: &Multiaddr, _: &Multiaddr, _: Self::ConnectionHandler) { - // NetworkBehaviour::inject_listen_failure on Kademlia does nothing. - } - - fn inject_listener_error(&mut self, id: ListenerId, err: &(dyn std::error::Error + 'static)) { - self.kademlia.inject_listener_error(id, err) - } - - fn inject_listener_closed(&mut self, id: ListenerId, reason: Result<(), &io::Error>) { - self.kademlia.inject_listener_closed(id, reason) + self.kademlia.on_connection_handler_event(peer_id, connection_id, event); } fn poll( @@ -705,7 +664,7 @@ impl NetworkBehaviour for DiscoveryBehaviour { KademliaEvent::InboundRequest { .. } => { // We are not interested in this event at the moment. }, - KademliaEvent::OutboundQueryCompleted { + KademliaEvent::OutboundQueryProgressed { result: QueryResult::GetClosestPeers(res), .. } => match res { @@ -730,24 +689,36 @@ impl NetworkBehaviour for DiscoveryBehaviour { } }, }, - KademliaEvent::OutboundQueryCompleted { + KademliaEvent::OutboundQueryProgressed { result: QueryResult::GetRecord(res), stats, + step, .. } => { 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(), - ) - }, + Ok(ok) => + if let GetRecordOk::FoundRecord(r) = ok { + self.outbound_query_records + .push((r.record.key, r.record.value)); + continue + } else { + debug!( + target: "sub-libp2p", + "Libp2p => Query progressed to {:?} step (last: {:?})", + step.count, + step.last, + ); + if step.last { + let records = + self.outbound_query_records.drain(..).collect(); + DiscoveryOut::ValueFound( + records, + stats.duration().unwrap_or_default(), + ) + } else { + continue + } + }, Err(e @ libp2p::kad::GetRecordError::NotFound { .. }) => { trace!( target: "sub-libp2p", @@ -773,7 +744,7 @@ impl NetworkBehaviour for DiscoveryBehaviour { }; return Poll::Ready(NetworkBehaviourAction::GenerateEvent(ev)) }, - KademliaEvent::OutboundQueryCompleted { + KademliaEvent::OutboundQueryProgressed { result: QueryResult::PutRecord(res), stats, .. @@ -795,7 +766,7 @@ impl NetworkBehaviour for DiscoveryBehaviour { }; return Poll::Ready(NetworkBehaviourAction::GenerateEvent(ev)) }, - KademliaEvent::OutboundQueryCompleted { + KademliaEvent::OutboundQueryProgressed { result: QueryResult::RepublishRecord(res), .. } => match res { @@ -811,7 +782,7 @@ impl NetworkBehaviour for DiscoveryBehaviour { ), }, // We never start any other type of query. - KademliaEvent::OutboundQueryCompleted { result: e, .. } => { + KademliaEvent::OutboundQueryProgressed { result: e, .. } => { warn!(target: "sub-libp2p", "Libp2p => Unhandled Kademlia event: {:?}", e) }, }, @@ -841,7 +812,7 @@ impl NetworkBehaviour for DiscoveryBehaviour { while let Poll::Ready(ev) = mdns.poll(cx, params) { match ev { NetworkBehaviourAction::GenerateEvent(event) => match event { - MdnsEvent::Discovered(list) => { + mdns::Event::Discovered(list) => { if self.num_connections >= self.discovery_only_if_under_num { continue } @@ -852,7 +823,7 @@ impl NetworkBehaviour for DiscoveryBehaviour { return Poll::Ready(NetworkBehaviourAction::GenerateEvent(ev)) } }, - MdnsEvent::Expired(_) => {}, + mdns::Event::Expired(_) => {}, }, NetworkBehaviourAction::Dial { .. } => { unreachable!("mDNS never dials!"); @@ -907,12 +878,19 @@ mod tests { }, identity::{ed25519, Keypair}, noise, - swarm::{Swarm, SwarmEvent}, + swarm::{Executor, Swarm, SwarmEvent}, yamux, Multiaddr, }; use sc_network_common::config::ProtocolId; use sp_core::hash::H256; - use std::{collections::HashSet, task::Poll}; + use std::{collections::HashSet, pin::Pin, task::Poll}; + + struct TokioExecutor(tokio::runtime::Runtime); + impl Executor for TokioExecutor { + fn exec(&self, f: Pin + Send>>) { + let _ = self.0.spawn(f); + } + } #[test] fn discovery_working() { @@ -949,7 +927,13 @@ mod tests { config.finish() }; - let mut swarm = Swarm::new(transport, behaviour, keypair.public().to_peer_id()); + let runtime = tokio::runtime::Runtime::new().unwrap(); + let mut swarm = Swarm::with_executor( + transport, + behaviour, + keypair.public().to_peer_id(), + TokioExecutor(runtime), + ); let listen_addr: Multiaddr = format!("/memory/{}", rand::random::()).parse().unwrap(); diff --git a/client/network/src/peer_info.rs b/client/network/src/peer_info.rs index e04d006f50501..97604a82c35b0 100644 --- a/client/network/src/peer_info.rs +++ b/client/network/src/peer_info.rs @@ -19,16 +19,17 @@ use fnv::FnvHashMap; use futures::prelude::*; use libp2p::{ - core::{ - connection::ConnectionId, either::EitherOutput, transport::ListenerId, ConnectedPoint, - PeerId, PublicKey, - }, + core::{connection::ConnectionId, either::EitherOutput, ConnectedPoint, PeerId, PublicKey}, 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::{ + behaviour::{ + AddressChange, ConnectionClosed, ConnectionEstablished, DialFailure, FromSwarm, + ListenFailure, + }, ConnectionHandler, IntoConnectionHandler, IntoConnectionHandlerSelect, NetworkBehaviour, NetworkBehaviourAction, PollParameters, }, @@ -39,7 +40,6 @@ use sc_network_common::utils::interval; use smallvec::SmallVec; use std::{ collections::hash_map::Entry, - error, io, pin::Pin, task::{Context, Poll}, time::{Duration, Instant}, @@ -188,172 +188,151 @@ 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); - - 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( - &mut self, - peer_id: &PeerId, - conn: &ConnectionId, - endpoint: &ConnectedPoint, - failed_addresses: Option<&Vec>, - other_established: usize, - ) { - 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())); + fn on_swarm_event(&mut self, event: FromSwarm) { + match event { + FromSwarm::ConnectionEstablished( + e @ ConnectionEstablished { peer_id, endpoint, .. }, + ) => { + self.ping.on_swarm_event(FromSwarm::ConnectionEstablished(e)); + self.identify.on_swarm_event(FromSwarm::ConnectionEstablished(e)); + + match self.nodes_info.entry(peer_id) { + Entry::Vacant(e) => { + e.insert(NodeInfo::new(endpoint.clone())); + }, + Entry::Occupied(e) => { + let e = e.into_mut(); + if e.info_expire.as_ref().map(|exp| *exp < Instant::now()).unwrap_or(false) + { + e.client_version = None; + e.latest_ping = None; + } + e.info_expire = None; + e.endpoints.push(endpoint.clone()); + }, + } }, - Entry::Occupied(e) => { - let e = e.into_mut(); - if e.info_expire.as_ref().map(|exp| *exp < Instant::now()).unwrap_or(false) { - e.client_version = None; - e.latest_ping = None; + FromSwarm::ConnectionClosed(ConnectionClosed { + peer_id, + connection_id, + endpoint, + handler, + remaining_established, + }) => { + let (ping_handler, identity_handler) = handler.into_inner(); + self.ping.on_swarm_event(FromSwarm::ConnectionClosed(ConnectionClosed { + peer_id, + connection_id, + endpoint, + handler: ping_handler, + remaining_established, + })); + self.identify.on_swarm_event(FromSwarm::ConnectionClosed(ConnectionClosed { + peer_id, + connection_id, + endpoint, + handler: identity_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", + "Unknown connection to {:?} closed: {:?}", peer_id, endpoint); } - e.info_expire = None; - e.endpoints.push(endpoint.clone()); + }, + FromSwarm::DialFailure(DialFailure { peer_id, handler, error }) => { + let (ping_handler, identity_handler) = handler.into_inner(); + self.ping.on_swarm_event(FromSwarm::DialFailure(DialFailure { + peer_id, + handler: ping_handler, + error, + })); + self.identify.on_swarm_event(FromSwarm::DialFailure(DialFailure { + peer_id, + handler: identity_handler, + error, + })); + }, + FromSwarm::ListenerClosed(e) => { + self.ping.on_swarm_event(FromSwarm::ListenerClosed(e)); + self.identify.on_swarm_event(FromSwarm::ListenerClosed(e)); + }, + FromSwarm::ListenFailure(ListenFailure { local_addr, send_back_addr, handler }) => { + let (ping_handler, identity_handler) = handler.into_inner(); + self.ping.on_swarm_event(FromSwarm::ListenFailure(ListenFailure { + local_addr, + send_back_addr, + handler: ping_handler, + })); + self.identify.on_swarm_event(FromSwarm::ListenFailure(ListenFailure { + local_addr, + send_back_addr, + handler: identity_handler, + })); + }, + FromSwarm::ListenerError(e) => { + self.ping.on_swarm_event(FromSwarm::ListenerError(e)); + self.identify.on_swarm_event(FromSwarm::ListenerError(e)); + }, + FromSwarm::ExpiredExternalAddr(e) => { + self.ping.on_swarm_event(FromSwarm::ExpiredExternalAddr(e)); + self.identify.on_swarm_event(FromSwarm::ExpiredExternalAddr(e)); + }, + FromSwarm::NewListener(e) => { + self.ping.on_swarm_event(FromSwarm::NewListener(e)); + self.identify.on_swarm_event(FromSwarm::NewListener(e)); + }, + FromSwarm::ExpiredListenAddr(e) => { + self.ping.on_swarm_event(FromSwarm::ExpiredListenAddr(e)); + self.identify.on_swarm_event(FromSwarm::ExpiredListenAddr(e)); + }, + FromSwarm::NewExternalAddr(e) => { + self.ping.on_swarm_event(FromSwarm::NewExternalAddr(e)); + self.identify.on_swarm_event(FromSwarm::NewExternalAddr(e)); + }, + FromSwarm::AddressChange(e @ AddressChange { peer_id, old, new, .. }) => { + self.ping.on_swarm_event(FromSwarm::AddressChange(e)); + self.identify.on_swarm_event(FromSwarm::AddressChange(e)); + + 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); + } + }, + FromSwarm::NewListenAddr(e) => { + self.ping.on_swarm_event(FromSwarm::NewListenAddr(e)); + self.identify.on_swarm_event(FromSwarm::NewListenAddr(e)); }, } } - fn inject_connection_closed( - &mut self, - peer_id: &PeerId, - conn: &ConnectionId, - endpoint: &ConnectedPoint, - handler: ::Handler, - remaining_established: usize, - ) { - let (ping_handler, identity_handler) = handler.into_inner(); - 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", - "Unknown connection to {:?} closed: {:?}", peer_id, endpoint); - } - } - - fn inject_event( + fn on_connection_handler_event( &mut self, peer_id: PeerId, - connection: ConnectionId, - event: <::Handler as ConnectionHandler>::OutEvent, + connection_id: ConnectionId, + event: <::Handler as + ConnectionHandler>::OutEvent, ) { match event { - EitherOutput::First(event) => self.ping.inject_event(peer_id, connection, event), - EitherOutput::Second(event) => self.identify.inject_event(peer_id, connection, event), + EitherOutput::First(event) => + self.ping.on_connection_handler_event(peer_id, connection_id, event), + EitherOutput::Second(event) => + self.identify.on_connection_handler_event(peer_id, connection_id, event), } } - fn inject_dial_failure( - &mut self, - peer_id: Option, - handler: Self::ConnectionHandler, - error: &libp2p::swarm::DialError, - ) { - 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) { - self.ping.inject_new_listener(id); - self.identify.inject_new_listener(id); - } - - fn inject_new_listen_addr(&mut self, id: ListenerId, addr: &Multiaddr) { - self.ping.inject_new_listen_addr(id, addr); - self.identify.inject_new_listen_addr(id, addr); - } - - fn inject_expired_listen_addr(&mut self, id: ListenerId, addr: &Multiaddr) { - self.ping.inject_expired_listen_addr(id, addr); - self.identify.inject_expired_listen_addr(id, addr); - } - - fn inject_new_external_addr(&mut self, addr: &Multiaddr) { - self.ping.inject_new_external_addr(addr); - self.identify.inject_new_external_addr(addr); - } - - fn inject_expired_external_addr(&mut self, addr: &Multiaddr) { - self.ping.inject_expired_external_addr(addr); - self.identify.inject_expired_external_addr(addr); - } - - fn inject_listen_failure( - &mut self, - local_addr: &Multiaddr, - send_back_addr: &Multiaddr, - handler: Self::ConnectionHandler, - ) { - 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); - } - - fn inject_listener_closed(&mut self, id: ListenerId, reason: Result<(), &io::Error>) { - self.ping.inject_listener_closed(id, reason); - self.identify.inject_listener_closed(id, reason); - } - fn poll( &mut self, cx: &mut Context, diff --git a/client/network/src/protocol.rs b/client/network/src/protocol.rs index 1f0ec9c0d120d..fd25c6526ff12 100644 --- a/client/network/src/protocol.rs +++ b/client/network/src/protocol.rs @@ -22,10 +22,10 @@ use bytes::Bytes; use codec::{Decode, DecodeAll, Encode}; use futures::prelude::*; use libp2p::{ - core::{connection::ConnectionId, transport::ListenerId, ConnectedPoint}, + core::connection::ConnectionId, swarm::{ - ConnectionHandler, IntoConnectionHandler, NetworkBehaviour, NetworkBehaviourAction, - PollParameters, + behaviour::FromSwarm, ConnectionHandler, IntoConnectionHandler, NetworkBehaviour, + NetworkBehaviourAction, PollParameters, }, Multiaddr, PeerId, }; @@ -49,7 +49,7 @@ use sp_arithmetic::traits::SaturatedConversion; use sp_runtime::traits::{Block as BlockT, CheckedSub, Header as HeaderT, NumberFor, Zero}; use std::{ collections::{HashMap, HashSet, VecDeque}, - io, iter, + iter, num::NonZeroUsize, pin::Pin, sync::Arc, @@ -969,47 +969,18 @@ where self.behaviour.addresses_of_peer(peer_id) } - fn inject_connection_established( - &mut self, - peer_id: &PeerId, - conn: &ConnectionId, - endpoint: &ConnectedPoint, - failed_addresses: Option<&Vec>, - other_established: usize, - ) { - self.behaviour.inject_connection_established( - peer_id, - conn, - endpoint, - failed_addresses, - other_established, - ) + fn on_swarm_event(&mut self, event: FromSwarm) { + self.behaviour.on_swarm_event(event); } - fn inject_connection_closed( - &mut self, - peer_id: &PeerId, - conn: &ConnectionId, - endpoint: &ConnectedPoint, - handler: ::Handler, - remaining_established: usize, - ) { - self.behaviour.inject_connection_closed( - peer_id, - conn, - endpoint, - handler, - remaining_established, - ) - } - - fn inject_event( + fn on_connection_handler_event( &mut self, peer_id: PeerId, - connection: ConnectionId, - event: <::Handler as ConnectionHandler>::OutEvent, + connection_id: ConnectionId, + event: <::Handler as + ConnectionHandler>::OutEvent, ) { - self.behaviour.inject_event(peer_id, connection, event) + self.behaviour.on_connection_handler_event(peer_id, connection_id, event); } fn poll( @@ -1245,41 +1216,4 @@ where cx.waker().wake_by_ref(); Poll::Pending } - - fn inject_dial_failure( - &mut self, - peer_id: Option, - handler: Self::ConnectionHandler, - error: &libp2p::swarm::DialError, - ) { - self.behaviour.inject_dial_failure(peer_id, handler, error); - } - - fn inject_new_listener(&mut self, id: ListenerId) { - self.behaviour.inject_new_listener(id) - } - - fn inject_new_listen_addr(&mut self, id: ListenerId, addr: &Multiaddr) { - self.behaviour.inject_new_listen_addr(id, addr) - } - - fn inject_expired_listen_addr(&mut self, id: ListenerId, addr: &Multiaddr) { - self.behaviour.inject_expired_listen_addr(id, addr) - } - - fn inject_new_external_addr(&mut self, addr: &Multiaddr) { - self.behaviour.inject_new_external_addr(addr) - } - - fn inject_expired_external_addr(&mut self, addr: &Multiaddr) { - self.behaviour.inject_expired_external_addr(addr) - } - - fn inject_listener_error(&mut self, id: ListenerId, err: &(dyn std::error::Error + 'static)) { - self.behaviour.inject_listener_error(id, err); - } - - fn inject_listener_closed(&mut self, id: ListenerId, reason: Result<(), &io::Error>) { - self.behaviour.inject_listener_closed(id, reason); - } } diff --git a/client/network/src/protocol/notifications/behaviour.rs b/client/network/src/protocol/notifications/behaviour.rs index 04f6fe445ac63..2db46867128ac 100644 --- a/client/network/src/protocol/notifications/behaviour.rs +++ b/client/network/src/protocol/notifications/behaviour.rs @@ -24,8 +24,10 @@ use bytes::BytesMut; use fnv::FnvHashMap; use futures::prelude::*; use libp2p::{ - core::{connection::ConnectionId, ConnectedPoint, Multiaddr, PeerId}, + core::{connection::ConnectionId, Multiaddr, PeerId}, swarm::{ + behaviour::{ConnectionClosed, ConnectionEstablished, DialFailure, FromSwarm}, + handler::ConnectionHandler, DialError, IntoConnectionHandler, NetworkBehaviour, NetworkBehaviourAction, NotifyHandler, PollParameters, }, @@ -1060,202 +1062,310 @@ impl NetworkBehaviour for Notifications { Vec::new() } - 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) { - // Requested | PendingRequest => Enabled - st @ &mut PeerState::Requested | st @ &mut PeerState::PendingRequest { .. } => { - trace!(target: "sub-libp2p", - "Libp2p => Connected({}, {:?}, {:?}): Connection was requested by PSM.", - peer_id, set_id, endpoint - ); - trace!(target: "sub-libp2p", "Handler({:?}, {:?}) <= Open({:?})", peer_id, *conn, set_id); - self.events.push_back(NetworkBehaviourAction::NotifyHandler { - peer_id: *peer_id, - handler: NotifyHandler::One(*conn), - event: NotifsHandlerIn::Open { protocol_index: set_id.into() }, - }); + fn on_swarm_event(&mut self, event: FromSwarm) { + match event { + FromSwarm::ConnectionEstablished(ConnectionEstablished { + peer_id, + endpoint, + connection_id, + .. + }) => { + 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) { + // Requested | PendingRequest => Enabled + st @ &mut PeerState::Requested | + st @ &mut PeerState::PendingRequest { .. } => { + trace!(target: "sub-libp2p", + "Libp2p => Connected({}, {:?}, {:?}): Connection was requested by PSM.", + peer_id, set_id, endpoint + ); + trace!(target: "sub-libp2p", "Handler({:?}, {:?}) <= Open({:?})", peer_id, connection_id, set_id); + self.events.push_back(NetworkBehaviourAction::NotifyHandler { + peer_id, + handler: NotifyHandler::One(connection_id), + event: NotifsHandlerIn::Open { protocol_index: set_id.into() }, + }); + + let mut connections = SmallVec::new(); + connections.push((connection_id, ConnectionState::Opening)); + *st = PeerState::Enabled { connections }; + }, - let mut connections = SmallVec::new(); - connections.push((*conn, ConnectionState::Opening)); - *st = PeerState::Enabled { connections }; - }, + // Poisoned gets inserted above if the entry was missing. + // Ø | Backoff => Disabled + st @ &mut PeerState::Poisoned | st @ &mut PeerState::Backoff { .. } => { + let backoff_until = + if let PeerState::Backoff { timer_deadline, .. } = st { + Some(*timer_deadline) + } else { + None + }; + trace!(target: "sub-libp2p", + "Libp2p => Connected({}, {:?}, {:?}, {:?}): Not requested by PSM, disabling.", + peer_id, set_id, endpoint, connection_id); + + let mut connections = SmallVec::new(); + connections.push((connection_id, ConnectionState::Closed)); + *st = PeerState::Disabled { connections, backoff_until }; + }, - // Poisoned gets inserted above if the entry was missing. - // Ø | Backoff => Disabled - st @ &mut PeerState::Poisoned | st @ &mut PeerState::Backoff { .. } => { - let backoff_until = if let PeerState::Backoff { timer_deadline, .. } = st { - Some(*timer_deadline) + // In all other states, add this new connection to the list of closed + // inactive connections. + PeerState::Incoming { connections, .. } | + PeerState::Disabled { connections, .. } | + PeerState::DisabledPendingEnable { connections, .. } | + PeerState::Enabled { connections, .. } => { + trace!(target: "sub-libp2p", + "Libp2p => Connected({}, {:?}, {:?}, {:?}): Secondary connection. Leaving closed.", + peer_id, set_id, endpoint, connection_id); + connections.push((connection_id, ConnectionState::Closed)); + }, + } + } + }, + FromSwarm::ConnectionClosed(ConnectionClosed { peer_id, connection_id, .. }) => { + 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)) + { + entry } else { - None + error!(target: "sub-libp2p", "inject_connection_closed: State mismatch in the custom protos handler"); + debug_assert!(false); + return }; - trace!(target: "sub-libp2p", - "Libp2p => Connected({}, {:?}, {:?}, {:?}): Not requested by PSM, disabling.", - peer_id, set_id, endpoint, *conn); - - let mut connections = SmallVec::new(); - connections.push((*conn, ConnectionState::Closed)); - *st = PeerState::Disabled { connections, backoff_until }; - }, - // In all other states, add this new connection to the list of closed inactive - // connections. - PeerState::Incoming { connections, .. } | - PeerState::Disabled { connections, .. } | - PeerState::DisabledPendingEnable { connections, .. } | - PeerState::Enabled { connections, .. } => { - trace!(target: "sub-libp2p", - "Libp2p => Connected({}, {:?}, {:?}, {:?}): Secondary connection. Leaving closed.", - peer_id, set_id, endpoint, *conn); - connections.push((*conn, ConnectionState::Closed)); - }, - } - } - } + match mem::replace(entry.get_mut(), PeerState::Poisoned) { + // Disabled => Disabled | Backoff | Ø + PeerState::Disabled { mut connections, backoff_until } => { + trace!(target: "sub-libp2p", "Libp2p => Disconnected({}, {:?}, {:?}): Disabled.", + peer_id, set_id, connection_id); - fn inject_connection_closed( - &mut self, - peer_id: &PeerId, - conn: &ConnectionId, - _endpoint: &ConnectedPoint, - _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)) { - entry - } else { - error!(target: "sub-libp2p", "inject_connection_closed: State mismatch in the custom protos handler"); - debug_assert!(false); - return - }; + if let Some(pos) = + connections.iter().position(|(c, _)| *c == connection_id) + { + connections.remove(pos); + } else { + debug_assert!(false); + error!(target: "sub-libp2p", + "inject_connection_closed: State mismatch in the custom protos handler"); + } - match mem::replace(entry.get_mut(), PeerState::Poisoned) { - // Disabled => Disabled | Backoff | Ø - PeerState::Disabled { mut connections, backoff_until } => { - trace!(target: "sub-libp2p", "Libp2p => Disconnected({}, {:?}, {:?}): Disabled.", - peer_id, set_id, *conn); + if connections.is_empty() { + if let Some(until) = backoff_until { + let now = Instant::now(); + if until > now { + let delay_id = self.next_delay_id; + self.next_delay_id.0 += 1; + let delay = futures_timer::Delay::new(until - now); + self.delays.push( + async move { + delay.await; + (delay_id, peer_id, set_id) + } + .boxed(), + ); + + *entry.get_mut() = PeerState::Backoff { + timer: delay_id, + timer_deadline: until, + }; + } else { + entry.remove(); + } + } else { + entry.remove(); + } + } else { + *entry.get_mut() = + PeerState::Disabled { connections, backoff_until }; + } + }, - if let Some(pos) = connections.iter().position(|(c, _)| *c == *conn) { - connections.remove(pos); - } else { - debug_assert!(false); - error!(target: "sub-libp2p", - "inject_connection_closed: State mismatch in the custom protos handler"); - } + // DisabledPendingEnable => DisabledPendingEnable | Backoff + PeerState::DisabledPendingEnable { + mut connections, + timer_deadline, + timer, + } => { + trace!( + target: "sub-libp2p", + "Libp2p => Disconnected({}, {:?}, {:?}): Disabled but pending enable.", + peer_id, set_id, connection_id + ); - if connections.is_empty() { - if let Some(until) = backoff_until { - let now = Instant::now(); - if until > now { - let delay_id = self.next_delay_id; - self.next_delay_id.0 += 1; - let delay = futures_timer::Delay::new(until - now); - let peer_id = *peer_id; - self.delays.push( - async move { - delay.await; - (delay_id, peer_id, set_id) - } - .boxed(), - ); + if let Some(pos) = + connections.iter().position(|(c, _)| *c == connection_id) + { + connections.remove(pos); + } else { + error!(target: "sub-libp2p", + "inject_connection_closed: State mismatch in the custom protos handler"); + debug_assert!(false); + } - *entry.get_mut() = - PeerState::Backoff { timer: delay_id, timer_deadline: until }; + if connections.is_empty() { + trace!(target: "sub-libp2p", "PSM <= Dropped({}, {:?})", peer_id, set_id); + self.peerset.dropped(set_id, peer_id, DropReason::Unknown); + *entry.get_mut() = PeerState::Backoff { timer, timer_deadline }; } else { - entry.remove(); + *entry.get_mut() = PeerState::DisabledPendingEnable { + connections, + timer_deadline, + timer, + }; } - } else { - entry.remove(); - } - } else { - *entry.get_mut() = PeerState::Disabled { connections, backoff_until }; - } - }, + }, - // DisabledPendingEnable => DisabledPendingEnable | Backoff - PeerState::DisabledPendingEnable { mut connections, timer_deadline, timer } => { - trace!( - target: "sub-libp2p", - "Libp2p => Disconnected({}, {:?}, {:?}): Disabled but pending enable.", - peer_id, set_id, *conn - ); + // Incoming => Incoming | Disabled | Backoff | Ø + PeerState::Incoming { mut connections, backoff_until } => { + trace!( + target: "sub-libp2p", + "Libp2p => Disconnected({}, {:?}, {:?}): OpenDesiredByRemote.", + peer_id, set_id, connection_id + ); - if let Some(pos) = connections.iter().position(|(c, _)| *c == *conn) { - connections.remove(pos); - } else { - error!(target: "sub-libp2p", - "inject_connection_closed: State mismatch in the custom protos handler"); - debug_assert!(false); - } + debug_assert!(connections + .iter() + .any(|(_, s)| matches!(s, ConnectionState::OpenDesiredByRemote))); - if connections.is_empty() { - trace!(target: "sub-libp2p", "PSM <= Dropped({}, {:?})", peer_id, set_id); - self.peerset.dropped(set_id, *peer_id, DropReason::Unknown); - *entry.get_mut() = PeerState::Backoff { timer, timer_deadline }; - } else { - *entry.get_mut() = - PeerState::DisabledPendingEnable { connections, timer_deadline, timer }; - } - }, + if let Some(pos) = + connections.iter().position(|(c, _)| *c == connection_id) + { + connections.remove(pos); + } else { + error!(target: "sub-libp2p", + "inject_connection_closed: State mismatch in the custom protos handler"); + debug_assert!(false); + } - // Incoming => Incoming | Disabled | Backoff | Ø - PeerState::Incoming { mut connections, backoff_until } => { - trace!( - target: "sub-libp2p", - "Libp2p => Disconnected({}, {:?}, {:?}): OpenDesiredByRemote.", - peer_id, set_id, *conn - ); + let no_desired_left = !connections + .iter() + .any(|(_, s)| matches!(s, ConnectionState::OpenDesiredByRemote)); + + // If no connection is `OpenDesiredByRemote` anymore, clean up the + // peerset incoming request. + if no_desired_left { + // In the incoming state, we don't report "Dropped". Instead we will + // just ignore the corresponding Accept/Reject. + if let Some(state) = self + .incoming + .iter_mut() + .find(|i| i.alive && i.set_id == set_id && i.peer_id == peer_id) + { + state.alive = false; + } else { + error!(target: "sub-libp2p", "State mismatch in libp2p: no entry in \ + incoming corresponding to an incoming state in peers"); + debug_assert!(false); + } + } - debug_assert!(connections - .iter() - .any(|(_, s)| matches!(s, ConnectionState::OpenDesiredByRemote))); + if connections.is_empty() { + if let Some(until) = backoff_until { + let now = Instant::now(); + if until > now { + let delay_id = self.next_delay_id; + self.next_delay_id.0 += 1; + let delay = futures_timer::Delay::new(until - now); + self.delays.push( + async move { + delay.await; + (delay_id, peer_id, set_id) + } + .boxed(), + ); + + *entry.get_mut() = PeerState::Backoff { + timer: delay_id, + timer_deadline: until, + }; + } else { + entry.remove(); + } + } else { + entry.remove(); + } + } else if no_desired_left { + // If no connection is `OpenDesiredByRemote` anymore, switch to + // `Disabled`. + *entry.get_mut() = + PeerState::Disabled { connections, backoff_until }; + } else { + *entry.get_mut() = + PeerState::Incoming { connections, backoff_until }; + } + }, - if let Some(pos) = connections.iter().position(|(c, _)| *c == *conn) { - connections.remove(pos); - } else { - error!(target: "sub-libp2p", - "inject_connection_closed: State mismatch in the custom protos handler"); - debug_assert!(false); - } + // Enabled => Enabled | Backoff + // Peers are always backed-off when disconnecting while Enabled. + PeerState::Enabled { mut connections } => { + trace!( + target: "sub-libp2p", + "Libp2p => Disconnected({}, {:?}, {:?}): Enabled.", + peer_id, set_id, connection_id + ); - let no_desired_left = !connections - .iter() - .any(|(_, s)| matches!(s, ConnectionState::OpenDesiredByRemote)); - - // If no connection is `OpenDesiredByRemote` anymore, clean up the peerset - // incoming request. - if no_desired_left { - // In the incoming state, we don't report "Dropped". Instead we will just - // ignore the corresponding Accept/Reject. - if let Some(state) = self - .incoming - .iter_mut() - .find(|i| i.alive && i.set_id == set_id && i.peer_id == *peer_id) - { - state.alive = false; - } else { - error!(target: "sub-libp2p", "State mismatch in libp2p: no entry in \ - incoming corresponding to an incoming state in peers"); - debug_assert!(false); - } - } + debug_assert!(connections.iter().any(|(_, s)| matches!( + s, + ConnectionState::Opening | ConnectionState::Open(_) + ))); + + if let Some(pos) = + connections.iter().position(|(c, _)| *c == connection_id) + { + let (_, state) = connections.remove(pos); + if let ConnectionState::Open(_) = state { + if let Some((replacement_pos, replacement_sink)) = connections + .iter() + .enumerate() + .find_map(|(num, (_, s))| match s { + ConnectionState::Open(s) => Some((num, s.clone())), + _ => None, + }) { + if pos <= replacement_pos { + trace!( + target: "sub-libp2p", + "External API <= Sink replaced({}, {:?})", + peer_id, set_id + ); + let event = NotificationsOut::CustomProtocolReplaced { + peer_id, + set_id, + notifications_sink: replacement_sink, + }; + self.events.push_back( + NetworkBehaviourAction::GenerateEvent(event), + ); + } + } else { + trace!( + target: "sub-libp2p", "External API <= Closed({}, {:?})", + peer_id, set_id + ); + let event = NotificationsOut::CustomProtocolClosed { + peer_id, + set_id, + }; + self.events.push_back( + NetworkBehaviourAction::GenerateEvent(event), + ); + } + } + } else { + error!(target: "sub-libp2p", + "inject_connection_closed: State mismatch in the custom protos handler"); + debug_assert!(false); + } + + if connections.is_empty() { + trace!(target: "sub-libp2p", "PSM <= Dropped({}, {:?})", peer_id, set_id); + self.peerset.dropped(set_id, peer_id, DropReason::Unknown); + let ban_dur = Uniform::new(5, 10).sample(&mut rand::thread_rng()); - if connections.is_empty() { - if let Some(until) = backoff_until { - let now = Instant::now(); - if until > now { let delay_id = self.next_delay_id; self.next_delay_id.0 += 1; - let delay = futures_timer::Delay::new(until - now); - let peer_id = *peer_id; + let delay = futures_timer::Delay::new(Duration::from_secs(ban_dur)); self.delays.push( async move { delay.await; @@ -1264,209 +1374,137 @@ impl NetworkBehaviour for Notifications { .boxed(), ); + *entry.get_mut() = PeerState::Backoff { + timer: delay_id, + timer_deadline: Instant::now() + Duration::from_secs(ban_dur), + }; + } else if !connections.iter().any(|(_, s)| { + matches!(s, ConnectionState::Opening | ConnectionState::Open(_)) + }) { + trace!(target: "sub-libp2p", "PSM <= Dropped({}, {:?})", peer_id, set_id); + self.peerset.dropped(set_id, peer_id, DropReason::Unknown); + *entry.get_mut() = - PeerState::Backoff { timer: delay_id, timer_deadline: until }; + PeerState::Disabled { connections, backoff_until: None }; } else { - entry.remove(); + *entry.get_mut() = PeerState::Enabled { connections }; } - } else { - entry.remove(); - } - } else if no_desired_left { - // If no connection is `OpenDesiredByRemote` anymore, switch to `Disabled`. - *entry.get_mut() = PeerState::Disabled { connections, backoff_until }; - } else { - *entry.get_mut() = PeerState::Incoming { connections, backoff_until }; + }, + + PeerState::Requested | + PeerState::PendingRequest { .. } | + PeerState::Backoff { .. } => { + // This is a serious bug either in this state machine or in libp2p. + error!(target: "sub-libp2p", + "`inject_connection_closed` called for unknown peer {}", + peer_id); + debug_assert!(false); + }, + PeerState::Poisoned => { + error!(target: "sub-libp2p", "State of peer {} is poisoned", peer_id); + debug_assert!(false); + }, } - }, + } + }, + FromSwarm::DialFailure(DialFailure { peer_id, 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); + } + } - // Enabled => Enabled | Backoff - // Peers are always backed-off when disconnecting while Enabled. - PeerState::Enabled { mut connections } => { - trace!( - target: "sub-libp2p", - "Libp2p => Disconnected({}, {:?}, {:?}): Enabled.", - peer_id, set_id, *conn - ); + 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, 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); + + 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), + }; - debug_assert!(connections.iter().any(|(_, s)| matches!( - s, - ConnectionState::Opening | ConnectionState::Open(_) - ))); - - if let Some(pos) = connections.iter().position(|(c, _)| *c == *conn) { - let (_, state) = connections.remove(pos); - if let ConnectionState::Open(_) = state { - if let Some((replacement_pos, replacement_sink)) = - connections.iter().enumerate().find_map(|(num, (_, s))| match s { - ConnectionState::Open(s) => Some((num, s.clone())), - _ => None, - }) { - if pos <= replacement_pos { - trace!( - target: "sub-libp2p", - "External API <= Sink replaced({}, {:?})", - peer_id, set_id + 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(), ); - let event = NotificationsOut::CustomProtocolReplaced { - peer_id: *peer_id, - set_id, - notifications_sink: replacement_sink, + + *entry.into_mut() = PeerState::Backoff { + timer: delay_id, + timer_deadline: now + ban_duration, }; - self.events - .push_back(NetworkBehaviourAction::GenerateEvent(event)); - } - } else { - trace!( - target: "sub-libp2p", "External API <= Closed({}, {:?})", - peer_id, set_id - ); - let event = NotificationsOut::CustomProtocolClosed { - peer_id: *peer_id, - set_id, - }; - self.events.push_back(NetworkBehaviourAction::GenerateEvent(event)); + }, + + // 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); + }, } } - } else { - error!(target: "sub-libp2p", - "inject_connection_closed: State mismatch in the custom protos handler"); - debug_assert!(false); } - - if connections.is_empty() { - trace!(target: "sub-libp2p", "PSM <= Dropped({}, {:?})", peer_id, set_id); - self.peerset.dropped(set_id, *peer_id, DropReason::Unknown); - let ban_dur = Uniform::new(5, 10).sample(&mut rand::thread_rng()); - - let delay_id = self.next_delay_id; - self.next_delay_id.0 += 1; - let delay = futures_timer::Delay::new(Duration::from_secs(ban_dur)); - let peer_id = *peer_id; - self.delays.push( - async move { - delay.await; - (delay_id, peer_id, set_id) - } - .boxed(), - ); - - *entry.get_mut() = PeerState::Backoff { - timer: delay_id, - timer_deadline: Instant::now() + Duration::from_secs(ban_dur), - }; - } else if !connections.iter().any(|(_, s)| { - matches!(s, ConnectionState::Opening | ConnectionState::Open(_)) - }) { - trace!(target: "sub-libp2p", "PSM <= Dropped({}, {:?})", peer_id, set_id); - self.peerset.dropped(set_id, *peer_id, DropReason::Unknown); - - *entry.get_mut() = PeerState::Disabled { connections, backoff_until: None }; - } else { - *entry.get_mut() = PeerState::Enabled { connections }; - } - }, - - PeerState::Requested | - PeerState::PendingRequest { .. } | - PeerState::Backoff { .. } => { - // This is a serious bug either in this state machine or in libp2p. - error!(target: "sub-libp2p", - "`inject_connection_closed` called for unknown peer {}", - peer_id); - debug_assert!(false); - }, - PeerState::Poisoned => { - error!(target: "sub-libp2p", "State of peer {} is poisoned", peer_id); - debug_assert!(false); - }, - } + } + }, + FromSwarm::ListenerClosed(_) => {}, + FromSwarm::ListenFailure(_) => {}, + FromSwarm::ListenerError(_) => {}, + FromSwarm::ExpiredExternalAddr(_) => {}, + FromSwarm::NewListener(_) => {}, + FromSwarm::ExpiredListenAddr(_) => {}, + FromSwarm::NewExternalAddr(_) => {}, + FromSwarm::AddressChange(_) => {}, + FromSwarm::NewListenAddr(_) => {}, } } - fn inject_dial_failure( + fn on_connection_handler_event( &mut self, - peer_id: Option, - _: Self::ConnectionHandler, - error: &DialError, + peer_id: PeerId, + connection_id: ConnectionId, + event: <::Handler as + ConnectionHandler>::OutEvent, ) { - 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); - } - } - - 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, 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); - - 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), - }; - - 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, - }; - }, - - // 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); - }, - } - } - } - } - } - - fn inject_event(&mut self, source: PeerId, connection: ConnectionId, event: NotifsHandlerOut) { match event { NotifsHandlerOut::OpenDesiredByRemote { protocol_index } => { let set_id = sc_peerset::SetId::from(protocol_index); trace!(target: "sub-libp2p", "Handler({:?}, {:?}]) => OpenDesiredByRemote({:?})", - source, connection, set_id); + peer_id, connection_id, set_id); - let mut entry = if let Entry::Occupied(entry) = self.peers.entry((source, set_id)) { + let mut entry = if let Entry::Occupied(entry) = self.peers.entry((peer_id, set_id)) + { entry } else { error!( @@ -1484,7 +1522,7 @@ impl NetworkBehaviour for Notifications { .iter() .any(|(_, s)| matches!(s, ConnectionState::OpenDesiredByRemote))); if let Some((_, connec_state)) = - connections.iter_mut().find(|(c, _)| *c == connection) + connections.iter_mut().find(|(c, _)| *c == connection_id) { if let ConnectionState::Closed = *connec_state { *connec_state = ConnectionState::OpenDesiredByRemote; @@ -1517,14 +1555,14 @@ impl NetworkBehaviour for Notifications { ))); if let Some((_, connec_state)) = - connections.iter_mut().find(|(c, _)| *c == connection) + connections.iter_mut().find(|(c, _)| *c == connection_id) { if let ConnectionState::Closed = *connec_state { trace!(target: "sub-libp2p", "Handler({:?}, {:?}) <= Open({:?})", - source, connection, set_id); + peer_id, connection_id, set_id); self.events.push_back(NetworkBehaviourAction::NotifyHandler { - peer_id: source, - handler: NotifyHandler::One(connection), + peer_id, + handler: NotifyHandler::One(connection_id), event: NotifsHandlerIn::Open { protocol_index: set_id.into() }, }); *connec_state = ConnectionState::Opening; @@ -1554,7 +1592,7 @@ impl NetworkBehaviour for Notifications { // Disabled => Disabled | Incoming PeerState::Disabled { mut connections, backoff_until } => { if let Some((_, connec_state)) = - connections.iter_mut().find(|(c, _)| *c == connection) + connections.iter_mut().find(|(c, _)| *c == connection_id) { if let ConnectionState::Closed = *connec_state { *connec_state = ConnectionState::OpenDesiredByRemote; @@ -1563,10 +1601,10 @@ impl NetworkBehaviour for Notifications { self.next_incoming_index.0 += 1; trace!(target: "sub-libp2p", "PSM <= Incoming({}, {:?}).", - source, incoming_id); - self.peerset.incoming(set_id, source, incoming_id); + peer_id, incoming_id); + self.peerset.incoming(set_id, peer_id, incoming_id); self.incoming.push(IncomingPeer { - peer_id: source, + peer_id, set_id, alive: true, incoming_id, @@ -1598,14 +1636,14 @@ impl NetworkBehaviour for Notifications { // DisabledPendingEnable => Enabled | DisabledPendingEnable PeerState::DisabledPendingEnable { mut connections, timer, timer_deadline } => { if let Some((_, connec_state)) = - connections.iter_mut().find(|(c, _)| *c == connection) + connections.iter_mut().find(|(c, _)| *c == connection_id) { if let ConnectionState::Closed = *connec_state { trace!(target: "sub-libp2p", "Handler({:?}, {:?}) <= Open({:?})", - source, connection, set_id); + peer_id, connection_id, set_id); self.events.push_back(NetworkBehaviourAction::NotifyHandler { - peer_id: source, - handler: NotifyHandler::One(connection), + peer_id, + handler: NotifyHandler::One(connection_id), event: NotifsHandlerIn::Open { protocol_index: set_id.into() }, }); *connec_state = ConnectionState::Opening; @@ -1649,9 +1687,10 @@ impl NetworkBehaviour for Notifications { trace!(target: "sub-libp2p", "Handler({}, {:?}) => CloseDesired({:?})", - source, connection, set_id); + peer_id, connection_id, set_id); - let mut entry = if let Entry::Occupied(entry) = self.peers.entry((source, set_id)) { + let mut entry = if let Entry::Occupied(entry) = self.peers.entry((peer_id, set_id)) + { entry } else { error!(target: "sub-libp2p", "CloseDesired: State mismatch in the custom protos handler"); @@ -1668,7 +1707,7 @@ impl NetworkBehaviour for Notifications { ))); let pos = if let Some(pos) = - connections.iter().position(|(c, _)| *c == connection) + connections.iter().position(|(c, _)| *c == connection_id) { pos } else { @@ -1686,10 +1725,10 @@ impl NetworkBehaviour for Notifications { debug_assert!(matches!(connections[pos].1, ConnectionState::Open(_))); connections[pos].1 = ConnectionState::Closing; - trace!(target: "sub-libp2p", "Handler({}, {:?}) <= Close({:?})", source, connection, set_id); + trace!(target: "sub-libp2p", "Handler({}, {:?}) <= Close({:?})", peer_id, connection_id, set_id); self.events.push_back(NetworkBehaviourAction::NotifyHandler { - peer_id: source, - handler: NotifyHandler::One(connection), + peer_id, + handler: NotifyHandler::One(connection_id), event: NotifsHandlerIn::Close { protocol_index: set_id.into() }, }); @@ -1699,9 +1738,9 @@ impl NetworkBehaviour for Notifications { _ => None, }) { if pos <= replacement_pos { - trace!(target: "sub-libp2p", "External API <= Sink replaced({:?})", source); + trace!(target: "sub-libp2p", "External API <= Sink replaced({:?})", peer_id); let event = NotificationsOut::CustomProtocolReplaced { - peer_id: source, + peer_id, set_id, notifications_sink: replacement_sink, }; @@ -1715,17 +1754,16 @@ impl NetworkBehaviour for Notifications { .iter() .any(|(_, s)| matches!(s, ConnectionState::Opening)) { - trace!(target: "sub-libp2p", "PSM <= Dropped({}, {:?})", source, set_id); - self.peerset.dropped(set_id, source, DropReason::Refused); + trace!(target: "sub-libp2p", "PSM <= Dropped({}, {:?})", peer_id, set_id); + self.peerset.dropped(set_id, peer_id, DropReason::Refused); *entry.into_mut() = PeerState::Disabled { connections, backoff_until: None }; } else { *entry.into_mut() = PeerState::Enabled { connections }; } - trace!(target: "sub-libp2p", "External API <= Closed({}, {:?})", source, set_id); - let event = - NotificationsOut::CustomProtocolClosed { peer_id: source, set_id }; + trace!(target: "sub-libp2p", "External API <= Closed({}, {:?})", peer_id, set_id); + let event = NotificationsOut::CustomProtocolClosed { peer_id, set_id }; self.events.push_back(NetworkBehaviourAction::GenerateEvent(event)); } }, @@ -1749,16 +1787,16 @@ impl NetworkBehaviour for Notifications { trace!(target: "sub-libp2p", "Handler({}, {:?}) => CloseResult({:?})", - source, connection, set_id); + peer_id, connection_id, set_id); - match self.peers.get_mut(&(source, set_id)) { + match self.peers.get_mut(&(peer_id, set_id)) { // Move the connection from `Closing` to `Closed`. Some(PeerState::Incoming { connections, .. }) | Some(PeerState::DisabledPendingEnable { connections, .. }) | Some(PeerState::Disabled { connections, .. }) | Some(PeerState::Enabled { connections, .. }) => { if let Some((_, connec_state)) = connections.iter_mut().find(|(c, s)| { - *c == connection && matches!(s, ConnectionState::Closing) + *c == connection_id && matches!(s, ConnectionState::Closing) }) { *connec_state = ConnectionState::Closed; } else { @@ -1787,9 +1825,9 @@ impl NetworkBehaviour for Notifications { let set_id = sc_peerset::SetId::from(protocol_index); trace!(target: "sub-libp2p", "Handler({}, {:?}) => OpenResultOk({:?})", - source, connection, set_id); + peer_id, connection_id, set_id); - match self.peers.get_mut(&(source, set_id)) { + match self.peers.get_mut(&(peer_id, set_id)) { Some(PeerState::Enabled { connections, .. }) => { debug_assert!(connections.iter().any(|(_, s)| matches!( s, @@ -1799,12 +1837,12 @@ impl NetworkBehaviour for Notifications { connections.iter().any(|(_, s)| matches!(s, ConnectionState::Open(_))); if let Some((_, connec_state)) = connections.iter_mut().find(|(c, s)| { - *c == connection && matches!(s, ConnectionState::Opening) + *c == connection_id && matches!(s, ConnectionState::Opening) }) { if !any_open { - trace!(target: "sub-libp2p", "External API <= Open({}, {:?})", source, set_id); + trace!(target: "sub-libp2p", "External API <= Open({}, {:?})", peer_id, set_id); let event = NotificationsOut::CustomProtocolOpen { - peer_id: source, + peer_id, set_id, negotiated_fallback, received_handshake, @@ -1815,7 +1853,8 @@ impl NetworkBehaviour for Notifications { *connec_state = ConnectionState::Open(notifications_sink); } else if let Some((_, connec_state)) = connections.iter_mut().find(|(c, s)| { - *c == connection && matches!(s, ConnectionState::OpeningThenClosing) + *c == connection_id && + matches!(s, ConnectionState::OpeningThenClosing) }) { *connec_state = ConnectionState::Closing; } else { @@ -1829,7 +1868,7 @@ impl NetworkBehaviour for Notifications { Some(PeerState::DisabledPendingEnable { connections, .. }) | Some(PeerState::Disabled { connections, .. }) => { if let Some((_, connec_state)) = connections.iter_mut().find(|(c, s)| { - *c == connection && matches!(s, ConnectionState::OpeningThenClosing) + *c == connection_id && matches!(s, ConnectionState::OpeningThenClosing) }) { *connec_state = ConnectionState::Closing; } else { @@ -1852,9 +1891,10 @@ impl NetworkBehaviour for Notifications { let set_id = sc_peerset::SetId::from(protocol_index); trace!(target: "sub-libp2p", "Handler({:?}, {:?}) => OpenResultErr({:?})", - source, connection, set_id); + peer_id, connection_id, set_id); - let mut entry = if let Entry::Occupied(entry) = self.peers.entry((source, set_id)) { + let mut entry = if let Entry::Occupied(entry) = self.peers.entry((peer_id, set_id)) + { entry } else { error!(target: "sub-libp2p", "OpenResultErr: State mismatch in the custom protos handler"); @@ -1870,12 +1910,13 @@ impl NetworkBehaviour for Notifications { ))); if let Some((_, connec_state)) = connections.iter_mut().find(|(c, s)| { - *c == connection && matches!(s, ConnectionState::Opening) + *c == connection_id && matches!(s, ConnectionState::Opening) }) { *connec_state = ConnectionState::Closed; } else if let Some((_, connec_state)) = connections.iter_mut().find(|(c, s)| { - *c == connection && matches!(s, ConnectionState::OpeningThenClosing) + *c == connection_id && + matches!(s, ConnectionState::OpeningThenClosing) }) { *connec_state = ConnectionState::Closing; } else { @@ -1887,8 +1928,8 @@ impl NetworkBehaviour for Notifications { if !connections.iter().any(|(_, s)| { matches!(s, ConnectionState::Opening | ConnectionState::Open(_)) }) { - trace!(target: "sub-libp2p", "PSM <= Dropped({:?})", source); - self.peerset.dropped(set_id, source, DropReason::Refused); + trace!(target: "sub-libp2p", "PSM <= Dropped({:?})", peer_id); + self.peerset.dropped(set_id, peer_id, DropReason::Refused); let ban_dur = Uniform::new(5, 10).sample(&mut rand::thread_rng()); *entry.into_mut() = PeerState::Disabled { @@ -1908,7 +1949,7 @@ impl NetworkBehaviour for Notifications { PeerState::DisabledPendingEnable { connections, .. } => { if let Some((_, connec_state)) = connections.iter_mut().find(|(c, s)| { - *c == connection && + *c == connection_id && matches!(s, ConnectionState::OpeningThenClosing) }) { *connec_state = ConnectionState::Closing; @@ -1937,30 +1978,30 @@ impl NetworkBehaviour for Notifications { NotifsHandlerOut::Notification { protocol_index, message } => { let set_id = sc_peerset::SetId::from(protocol_index); - if self.is_open(&source, set_id) { + if self.is_open(&peer_id, set_id) { trace!( target: "sub-libp2p", "Handler({:?}) => Notification({}, {:?}, {} bytes)", - connection, - source, + connection_id, + peer_id, set_id, message.len() ); trace!( target: "sub-libp2p", "External API <= Message({}, {:?})", - source, + peer_id, set_id, ); - let event = NotificationsOut::Notification { peer_id: source, set_id, message }; + let event = NotificationsOut::Notification { peer_id, set_id, message }; self.events.push_back(NetworkBehaviourAction::GenerateEvent(event)); } else { trace!( target: "sub-libp2p", "Handler({:?}) => Post-close notification({}, {:?}, {} bytes)", - connection, - source, + connection_id, + peer_id, set_id, message.len() ); diff --git a/client/network/src/protocol/notifications/tests.rs b/client/network/src/protocol/notifications/tests.rs index fa79366d20283..6e858697486ea 100644 --- a/client/network/src/protocol/notifications/tests.rs +++ b/client/network/src/protocol/notifications/tests.rs @@ -22,24 +22,28 @@ use crate::protocol::notifications::{Notifications, NotificationsOut, ProtocolCo use futures::prelude::*; use libp2p::{ - core::{ - connection::ConnectionId, - transport::{ListenerId, MemoryTransport}, - upgrade, ConnectedPoint, - }, + core::{connection::ConnectionId, transport::MemoryTransport, upgrade}, identity, noise, swarm::{ - ConnectionHandler, DialError, IntoConnectionHandler, NetworkBehaviour, + behaviour::FromSwarm, ConnectionHandler, Executor, IntoConnectionHandler, NetworkBehaviour, NetworkBehaviourAction, PollParameters, Swarm, SwarmEvent, }, yamux, Multiaddr, PeerId, Transport, }; use std::{ - error, io, iter, + iter, + pin::Pin, task::{Context, Poll}, time::Duration, }; +struct TokioExecutor(tokio::runtime::Runtime); +impl Executor for TokioExecutor { + fn exec(&self, f: Pin + Send>>) { + let _ = self.0.spawn(f); + } +} + /// Builds two nodes that have each other as bootstrap nodes. /// This is to be used only for testing, and a panic will happen if something goes wrong. fn build_nodes() -> (Swarm, Swarm) { @@ -100,7 +104,13 @@ fn build_nodes() -> (Swarm, Swarm) { .collect(), }; - let mut swarm = Swarm::new(transport, behaviour, keypairs[index].public().to_peer_id()); + let runtime = tokio::runtime::Runtime::new().unwrap(); + let mut swarm = Swarm::with_executor( + transport, + behaviour, + keypairs[index].public().to_peer_id(), + TokioExecutor(runtime), + ); swarm.listen_on(addrs[index].clone()).unwrap(); out.push(swarm); } @@ -150,42 +160,18 @@ impl NetworkBehaviour for CustomProtoWithAddr { list } - 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, - other_established, - ) - } - - fn inject_connection_closed( - &mut self, - peer_id: &PeerId, - conn: &ConnectionId, - endpoint: &ConnectedPoint, - handler: ::Handler, - remaining_established: usize, - ) { - self.inner - .inject_connection_closed(peer_id, conn, endpoint, handler, remaining_established) + fn on_swarm_event(&mut self, event: FromSwarm) { + self.inner.on_swarm_event(event); } - fn inject_event( + fn on_connection_handler_event( &mut self, peer_id: PeerId, - connection: ConnectionId, - event: <::Handler as ConnectionHandler>::OutEvent, + connection_id: ConnectionId, + event: <::Handler as + ConnectionHandler>::OutEvent, ) { - self.inner.inject_event(peer_id, connection, event) + self.inner.on_connection_handler_event(peer_id, connection_id, event); } fn poll( @@ -195,43 +181,6 @@ impl NetworkBehaviour for CustomProtoWithAddr { ) -> Poll> { self.inner.poll(cx, params) } - - fn inject_dial_failure( - &mut self, - peer_id: Option, - handler: Self::ConnectionHandler, - error: &DialError, - ) { - self.inner.inject_dial_failure(peer_id, handler, error) - } - - fn inject_new_listener(&mut self, id: ListenerId) { - self.inner.inject_new_listener(id) - } - - fn inject_new_listen_addr(&mut self, id: ListenerId, addr: &Multiaddr) { - self.inner.inject_new_listen_addr(id, addr) - } - - fn inject_expired_listen_addr(&mut self, id: ListenerId, addr: &Multiaddr) { - self.inner.inject_expired_listen_addr(id, addr) - } - - fn inject_new_external_addr(&mut self, addr: &Multiaddr) { - self.inner.inject_new_external_addr(addr) - } - - fn inject_expired_external_addr(&mut self, addr: &Multiaddr) { - self.inner.inject_expired_external_addr(addr) - } - - fn inject_listener_error(&mut self, id: ListenerId, err: &(dyn error::Error + 'static)) { - self.inner.inject_listener_error(id, err); - } - - fn inject_listener_closed(&mut self, id: ListenerId, reason: Result<(), &io::Error>) { - self.inner.inject_listener_closed(id, reason); - } } #[test] diff --git a/client/network/src/request_responses.rs b/client/network/src/request_responses.rs index d49cbd8051341..45f1030400908 100644 --- a/client/network/src/request_responses.rs +++ b/client/network/src/request_responses.rs @@ -40,14 +40,16 @@ use futures::{ prelude::*, }; use libp2p::{ - core::{connection::ConnectionId, transport::ListenerId, ConnectedPoint, Multiaddr, PeerId}, + core::{connection::ConnectionId, Multiaddr, PeerId}, request_response::{ handler::RequestResponseHandler, ProtocolSupport, RequestResponse, RequestResponseCodec, RequestResponseConfig, RequestResponseEvent, RequestResponseMessage, ResponseChannel, }, swarm::{ - handler::multi::MultiHandler, ConnectionHandler, IntoConnectionHandler, NetworkBehaviour, - NetworkBehaviourAction, PollParameters, + behaviour::{ConnectionClosed, DialFailure, FromSwarm, ListenFailure}, + handler::multi::MultiHandler, + ConnectionHandler, IntoConnectionHandler, NetworkBehaviour, NetworkBehaviourAction, + PollParameters, }, }; use sc_network_common::{ @@ -312,120 +314,119 @@ impl NetworkBehaviour for RequestResponsesBehaviour { Vec::new() } - fn inject_connection_established( - &mut self, - peer_id: &PeerId, - conn: &ConnectionId, - endpoint: &ConnectedPoint, - failed_addresses: Option<&Vec>, - other_established: usize, - ) { - for (p, _) in self.protocols.values_mut() { - NetworkBehaviour::inject_connection_established( - p, + fn on_swarm_event(&mut self, event: FromSwarm) { + match event { + FromSwarm::ConnectionEstablished(e) => + for (p, _) in self.protocols.values_mut() { + NetworkBehaviour::on_swarm_event(p, FromSwarm::ConnectionEstablished(e)); + }, + FromSwarm::ConnectionClosed(ConnectionClosed { peer_id, - conn, + connection_id, endpoint, - failed_addresses, - other_established, - ) - } - } - - fn inject_connection_closed( - &mut self, - peer_id: &PeerId, - conn: &ConnectionId, - endpoint: &ConnectedPoint, - handler: ::Handler, - remaining_established: usize, - ) { - 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, - ) - } + handler, + remaining_established, + }) => + for (p_name, p_handler) in handler.into_iter() { + if let Some((proto, _)) = self.protocols.get_mut(p_name.as_str()) { + proto.on_swarm_event(FromSwarm::ConnectionClosed(ConnectionClosed { + peer_id, + connection_id, + endpoint, + handler: p_handler, + remaining_established, + })); + } else { + log::error!( + target: "sub-libp2p", + "on_swarm_event/connection_closed: no request-response instance registered for protocol {:?}", + p_name, + ) + } + }, + FromSwarm::DialFailure(DialFailure { peer_id, error, handler }) => + for (p_name, p_handler) in handler.into_iter() { + if let Some((proto, _)) = self.protocols.get_mut(p_name.as_str()) { + proto.on_swarm_event(FromSwarm::DialFailure(DialFailure { + peer_id, + handler: p_handler, + error, + })); + } else { + log::error!( + target: "sub-libp2p", + "on_swarm_event/dial_failure: no request-response instance registered for protocol {:?}", + p_name, + ) + } + }, + FromSwarm::ListenerClosed(e) => + for (p, _) in self.protocols.values_mut() { + NetworkBehaviour::on_swarm_event(p, FromSwarm::ListenerClosed(e)); + }, + FromSwarm::ListenFailure(ListenFailure { local_addr, send_back_addr, handler }) => + for (p_name, p_handler) in handler.into_iter() { + if let Some((proto, _)) = self.protocols.get_mut(p_name.as_str()) { + proto.on_swarm_event(FromSwarm::ListenFailure(ListenFailure { + local_addr, + send_back_addr, + handler: p_handler, + })); + } else { + log::error!( + target: "sub-libp2p", + "on_swarm_event/listen_failure: no request-response instance registered for protocol {:?}", + p_name, + ) + } + }, + FromSwarm::ListenerError(e) => + for (p, _) in self.protocols.values_mut() { + NetworkBehaviour::on_swarm_event(p, FromSwarm::ListenerError(e)); + }, + FromSwarm::ExpiredExternalAddr(e) => + for (p, _) in self.protocols.values_mut() { + NetworkBehaviour::on_swarm_event(p, FromSwarm::ExpiredExternalAddr(e)); + }, + FromSwarm::NewListener(e) => + for (p, _) in self.protocols.values_mut() { + NetworkBehaviour::on_swarm_event(p, FromSwarm::NewListener(e)); + }, + FromSwarm::ExpiredListenAddr(e) => + for (p, _) in self.protocols.values_mut() { + NetworkBehaviour::on_swarm_event(p, FromSwarm::ExpiredListenAddr(e)); + }, + FromSwarm::NewExternalAddr(e) => + for (p, _) in self.protocols.values_mut() { + NetworkBehaviour::on_swarm_event(p, FromSwarm::NewExternalAddr(e)); + }, + FromSwarm::AddressChange(e) => + for (p, _) in self.protocols.values_mut() { + NetworkBehaviour::on_swarm_event(p, FromSwarm::AddressChange(e)); + }, + FromSwarm::NewListenAddr(e) => + for (p, _) in self.protocols.values_mut() { + NetworkBehaviour::on_swarm_event(p, FromSwarm::NewListenAddr(e)); + }, } } - fn inject_event( + fn on_connection_handler_event( &mut self, peer_id: PeerId, - connection: ConnectionId, - (p_name, event): ::OutEvent, + connection_id: ConnectionId, + (p_name, event): <::Handler as + ConnectionHandler>::OutEvent, ) { if let Some((proto, _)) = self.protocols.get_mut(&*p_name) { - return proto.inject_event(peer_id, connection, event) + return proto.on_connection_handler_event(peer_id, connection_id, event) } - log::warn!(target: "sub-libp2p", - "inject_node_event: no request-response instance registered for protocol {:?}", - p_name) - } - - fn inject_new_external_addr(&mut self, addr: &Multiaddr) { - for (p, _) in self.protocols.values_mut() { - NetworkBehaviour::inject_new_external_addr(p, addr) - } - } - - fn inject_expired_external_addr(&mut self, addr: &Multiaddr) { - for (p, _) in self.protocols.values_mut() { - NetworkBehaviour::inject_expired_external_addr(p, addr) - } - } - - fn inject_expired_listen_addr(&mut self, id: ListenerId, addr: &Multiaddr) { - for (p, _) in self.protocols.values_mut() { - NetworkBehaviour::inject_expired_listen_addr(p, id, addr) - } - } - - fn inject_dial_failure( - &mut self, - peer_id: Option, - _: Self::ConnectionHandler, - error: &libp2p::swarm::DialError, - ) { - for (p, _) in self.protocols.values_mut() { - let handler = p.new_handler(); - NetworkBehaviour::inject_dial_failure(p, peer_id, handler, error) - } - } - - fn inject_new_listener(&mut self, id: ListenerId) { - for (p, _) in self.protocols.values_mut() { - NetworkBehaviour::inject_new_listener(p, id) - } - } - - fn inject_new_listen_addr(&mut self, id: ListenerId, addr: &Multiaddr) { - for (p, _) in self.protocols.values_mut() { - NetworkBehaviour::inject_new_listen_addr(p, id, addr) - } - } - - fn inject_listener_error(&mut self, id: ListenerId, err: &(dyn std::error::Error + 'static)) { - for (p, _) in self.protocols.values_mut() { - NetworkBehaviour::inject_listener_error(p, id, err) - } - } - - fn inject_listener_closed(&mut self, id: ListenerId, reason: Result<(), &io::Error>) { - for (p, _) in self.protocols.values_mut() { - NetworkBehaviour::inject_listener_closed(p, id, reason) - } + log::warn!( + target: "sub-libp2p", + "on_connection_handler_event: no request-response instance registered for protocol {:?}", + p_name + ); } fn poll( @@ -919,12 +920,19 @@ mod tests { }, identity::Keypair, noise, - swarm::{Swarm, SwarmEvent}, + swarm::{Executor, Swarm, SwarmEvent}, Multiaddr, }; use sc_peerset::{Peerset, PeersetConfig, SetConfig}; use std::{iter, time::Duration}; + struct TokioExecutor(tokio::runtime::Runtime); + impl Executor for TokioExecutor { + fn exec(&self, f: Pin + Send>>) { + let _ = self.0.spawn(f); + } + } + fn build_swarm( list: impl Iterator, ) -> (Swarm, Multiaddr, Peerset) { @@ -953,7 +961,13 @@ mod tests { let behaviour = RequestResponsesBehaviour::new(list, handle).unwrap(); - let mut swarm = Swarm::new(transport, behaviour, keypair.public().to_peer_id()); + let runtime = tokio::runtime::Runtime::new().unwrap(); + let mut swarm = Swarm::with_executor( + transport, + behaviour, + keypair.public().to_peer_id(), + TokioExecutor(runtime), + ); 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 66de263a19a3e..f943a03f50b38 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -40,13 +40,13 @@ use crate::{ use futures::{channel::oneshot, prelude::*}; use libp2p::{ - core::{either::EitherError, upgrade, ConnectedPoint, Executor}, + core::{either::EitherError, upgrade, ConnectedPoint}, identify::Info as IdentifyInfo, kad::record::Key as KademliaKey, multiaddr, ping::Failure as PingFailure, swarm::{ - AddressScore, ConnectionError, ConnectionLimits, DialError, NetworkBehaviour, + AddressScore, ConnectionError, ConnectionLimits, DialError, Executor, NetworkBehaviour, PendingConnectionError, Swarm, SwarmBuilder, SwarmEvent, }, Multiaddr, PeerId, @@ -370,7 +370,21 @@ where } }; - let mut builder = SwarmBuilder::new(transport, behaviour, local_peer_id) + let builder = { + struct SpawnImpl(F); + impl + Send>>)> Executor for SpawnImpl { + fn exec(&self, f: Pin + Send>>) { + (self.0)(f) + } + } + SwarmBuilder::with_executor( + transport, + behaviour, + local_peer_id, + SpawnImpl(params.executor), + ) + }; + let builder = builder .connection_limits( ConnectionLimits::default() .with_max_established_per_peer(Some(crate::MAX_CONNECTIONS_PER_PEER as u32)) @@ -383,14 +397,6 @@ where .connection_event_buffer_size(1024) .max_negotiating_inbound_streams(2048); - struct SpawnImpl(F); - impl + Send>>)> Executor for SpawnImpl { - fn exec(&self, f: Pin + Send>>) { - (self.0)(f) - } - } - builder = builder.executor(Box::new(SpawnImpl(params.executor))); - (builder.build(), bandwidth) }; diff --git a/client/network/src/transport.rs b/client/network/src/transport.rs index b0d5f0235b6e4..6c792a0c38042 100644 --- a/client/network/src/transport.rs +++ b/client/network/src/transport.rs @@ -54,17 +54,17 @@ pub fn build_transport( ) -> (Boxed<(PeerId, StreamMuxerBox)>, Arc) { // Build the base layer of the transport. let transport = if !memory_only { - let tcp_config = tcp::GenTcpConfig::new().nodelay(true); - let desktop_trans = tcp::TokioTcpTransport::new(tcp_config.clone()); + let tcp_config = tcp::Config::new().nodelay(true); + let desktop_trans = tcp::tokio::Transport::new(tcp_config.clone()); let desktop_trans = websocket::WsConfig::new(desktop_trans) - .or_transport(tcp::TokioTcpTransport::new(tcp_config.clone())); + .or_transport(tcp::tokio::Transport::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::TokioTcpTransport::new(tcp_config.clone()); + let desktop_trans = tcp::tokio::Transport::new(tcp_config.clone()); let desktop_trans = websocket::WsConfig::new(desktop_trans) - .or_transport(tcp::TokioTcpTransport::new(tcp_config)); + .or_transport(tcp::tokio::Transport::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 e29d8047161ce..d2cbeb5ec1f1d 100644 --- a/client/network/sync/Cargo.toml +++ b/client/network/sync/Cargo.toml @@ -20,7 +20,7 @@ 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" +libp2p = "0.50.0" log = "0.4.17" lru = "0.8.1" mockall = "0.11.2" diff --git a/client/network/test/Cargo.toml b/client/network/test/Cargo.toml index 25e4df00e01de..8368fa278712a 100644 --- a/client/network/test/Cargo.toml +++ b/client/network/test/Cargo.toml @@ -17,7 +17,7 @@ tokio = "1.22.0" async-trait = "0.1.57" futures = "0.3.21" futures-timer = "3.0.1" -libp2p = { version = "0.49.0", default-features = false } +libp2p = "0.50.0" log = "0.4.17" parking_lot = "0.12.1" rand = "0.8.5" diff --git a/client/network/transactions/Cargo.toml b/client/network/transactions/Cargo.toml index 1255dededc3eb..df13cdcb820d2 100644 --- a/client/network/transactions/Cargo.toml +++ b/client/network/transactions/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] array-bytes = "4.1" codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } futures = "0.3.21" -libp2p = "0.49.0" +libp2p = "0.50.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 baeec0b6d731a..09df9187fb2d5 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.49.0", default-features = false } +libp2p = "0.50.0" 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 8625fe40c20d4..a09508c831189 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.49.0", default-features = false } +libp2p = "0.50.0" 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 6ef69d1d97afd..4d09a28370e6d 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", "tcp", "tokio", "wasm-ext", "websocket"] } +libp2p = { version = "0.50.0", 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 d8bd138c5af25..5e940bbe54eb5 100644 --- a/client/telemetry/src/transport.rs +++ b/client/telemetry/src/transport.rs @@ -30,7 +30,7 @@ const CONNECT_TIMEOUT: Duration = Duration::from_secs(20); pub(crate) fn initialize_transport() -> Result { let transport = { - let tcp_transport = libp2p::tcp::TokioTcpTransport::new(libp2p::tcp::GenTcpConfig::new()); + let tcp_transport = libp2p::tcp::tokio::Transport::new(libp2p::tcp::Config::new()); let inner = libp2p::dns::TokioDnsConfig::system(tcp_transport)?; libp2p::websocket::framed::WsConfig::new(inner).and_then(|connec, _| { let connec = connec 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 be31b39c11725..c9de991135082 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 @@ -26,5 +26,5 @@ error[E0277]: the trait bound `Vec: 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 79 others + and $N others = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageMyStorage, Vec>` to implement `StorageInfoTrait` 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 364eb5e6d5bb1..bc6d98b8da84d 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 281 others + and $N others = note: required for `Bar` to implement `FullEncode` = note: required for `Bar` to implement `FullCodec` = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `PartialStorageInfoTrait` @@ -48,7 +48,7 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied Rc Vec bytes::bytes::Bytes - and 3 others + and $N others = note: required for `Bar` to implement `Encode` = note: required for `Bar` to implement `FullEncode` = note: required for `Bar` to implement `FullCodec` @@ -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 163 others + and $N 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 281 others + and $N others = note: required for `Bar` to implement `FullEncode` = note: required for `Bar` to implement `FullCodec` = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `StorageEntryMetadataBuilder` @@ -123,7 +123,7 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied Rc Vec bytes::bytes::Bytes - and 3 others + and $N others = note: required for `Bar` to implement `Encode` = note: required for `Bar` to implement `FullEncode` = note: required for `Bar` to implement `FullCodec` 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 371e90323d9cb..1c010d662d07a 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 281 others + and $N others = note: required for `Bar` to implement `FullEncode` = note: required for `Bar` to implement `FullCodec` = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `PartialStorageInfoTrait` @@ -48,7 +48,7 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied Rc Vec bytes::bytes::Bytes - and 3 others + and $N others = note: required for `Bar` to implement `Encode` = note: required for `Bar` to implement `FullEncode` = note: required for `Bar` to implement `FullCodec` @@ -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 163 others + and $N 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 281 others + and $N others = note: required for `Bar` to implement `FullEncode` = note: required for `Bar` to implement `FullCodec` = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `StorageEntryMetadataBuilder` @@ -123,7 +123,7 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied Rc Vec bytes::bytes::Bytes - and 3 others + and $N others = note: required for `Bar` to implement `Encode` = note: required for `Bar` to implement `FullEncode` = note: required for `Bar` to implement `FullCodec` 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 b5443c6f327e4..c17f9eaa03251 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 79 others + and $N others = 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 afc7aaa8768cf..c34c796fe59c1 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 79 others + and $N others = note: required for `Key` to implement `KeyGeneratorMaxEncodedLen` = note: required for `frame_support::pallet_prelude::StorageNMap<_GeneratedPrefixForStorageFoo, Key, u32>` to implement `StorageInfoTrait` From fb22096d2ec6bf38e67ce811ad2c31415237a9a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= <123550+andresilva@users.noreply.github.com> Date: Thu, 5 Jan 2023 12:33:08 +0000 Subject: [PATCH 254/715] grandpa: remove deprecated afg log target (#13064) * grandpa: remove deprecated afg log target * grandpa: define log targets in primitives --- client/finality-grandpa/src/lib.rs | 6 +++--- client/tracing/src/logging/mod.rs | 8 ++++---- frame/grandpa/src/lib.rs | 4 +--- primitives/finality-grandpa/Cargo.toml | 4 ++-- primitives/finality-grandpa/src/lib.rs | 11 +++++++---- 5 files changed, 17 insertions(+), 16 deletions(-) diff --git a/client/finality-grandpa/src/lib.rs b/client/finality-grandpa/src/lib.rs index 1597e60bd6061..8758efef6037f 100644 --- a/client/finality-grandpa/src/lib.rs +++ b/client/finality-grandpa/src/lib.rs @@ -76,6 +76,9 @@ use sp_application_crypto::AppKey; use sp_blockchain::{Error as ClientError, HeaderBackend, HeaderMetadata, Result as ClientResult}; use sp_consensus::SelectChain; use sp_core::crypto::ByteArray; +use sp_finality_grandpa::{ + AuthorityList, AuthoritySignature, SetId, CLIENT_LOG_TARGET as LOG_TARGET, +}; use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; use sp_runtime::{ generic::BlockId, @@ -93,8 +96,6 @@ use std::{ time::Duration, }; -const LOG_TARGET: &str = "grandpa"; - // utility logging macro that takes as first argument a conditional to // decide whether to log under debug or info level (useful to restrict // logging under initial sync). @@ -142,7 +143,6 @@ pub use voting_rule::{ use aux_schema::PersistentData; use communication::{Network as NetworkT, NetworkBridge}; use environment::{Environment, VoterSetState}; -use sp_finality_grandpa::{AuthorityList, AuthoritySignature, SetId}; use until_imported::UntilGlobalMessageBlocksImported; // Re-export these two because it's just so damn convenient. diff --git a/client/tracing/src/logging/mod.rs b/client/tracing/src/logging/mod.rs index 978e24df68d78..77307ad999daf 100644 --- a/client/tracing/src/logging/mod.rs +++ b/client/tracing/src/logging/mod.rs @@ -377,7 +377,7 @@ mod tests { fn test_logger_filters() { run_test_in_another_process("test_logger_filters", || { let test_directives = - "afg=debug,sync=trace,client=warn,telemetry,something-with-dash=error"; + "grandpa=debug,sync=trace,client=warn,telemetry,something-with-dash=error"; init_logger(&test_directives); tracing::dispatcher::get_default(|dispatcher| { @@ -402,9 +402,9 @@ mod tests { dispatcher.enabled(&metadata) }; - assert!(test_filter("afg", Level::INFO)); - assert!(test_filter("afg", Level::DEBUG)); - assert!(!test_filter("afg", Level::TRACE)); + assert!(test_filter("grandpa", Level::INFO)); + assert!(test_filter("grandpa", Level::DEBUG)); + assert!(!test_filter("grandpa", Level::TRACE)); assert!(test_filter("sync", Level::TRACE)); assert!(test_filter("client", Level::WARN)); diff --git a/frame/grandpa/src/lib.rs b/frame/grandpa/src/lib.rs index 716cf54865773..aa09b445c6bdd 100644 --- a/frame/grandpa/src/lib.rs +++ b/frame/grandpa/src/lib.rs @@ -37,7 +37,7 @@ 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, - GRANDPA_ENGINE_ID, + GRANDPA_ENGINE_ID, RUNTIME_LOG_TARGET as LOG_TARGET, }; use frame_support::{ dispatch::{DispatchResultWithPostInfo, Pays}, @@ -70,8 +70,6 @@ pub use equivocation::{ pub use pallet::*; -const LOG_TARGET: &str = "runtime::grandpa"; - #[frame_support::pallet] pub mod pallet { use super::*; diff --git a/primitives/finality-grandpa/Cargo.toml b/primitives/finality-grandpa/Cargo.toml index 1c8011ff764e3..de8de99eed891 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.16.0", default-features = false, features = ["derive-codec"] } -log = { version = "0.4.17", 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", features = ["derive"], optional = true } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } @@ -31,7 +31,7 @@ default = ["std"] std = [ "codec/std", "grandpa/std", - "log", + "log/std", "scale-info/std", "serde", "sp-api/std", diff --git a/primitives/finality-grandpa/src/lib.rs b/primitives/finality-grandpa/src/lib.rs index f92fee4f12963..7b3b55f49cee0 100644 --- a/primitives/finality-grandpa/src/lib.rs +++ b/primitives/finality-grandpa/src/lib.rs @@ -35,8 +35,10 @@ use sp_runtime::{ }; use sp_std::{borrow::Cow, vec::Vec}; -#[cfg(feature = "std")] -use log::debug; +/// The log target to be used by client code. +pub const CLIENT_LOG_TARGET: &str = "grandpa"; +/// The log target to be used by runtime code. +pub const RUNTIME_LOG_TARGET: &str = "runtime::grandpa"; /// Key type for GRANDPA module. pub const KEY_TYPE: sp_core::crypto::KeyTypeId = sp_application_crypto::key_types::GRANDPA; @@ -428,8 +430,9 @@ where let valid = id.verify(&buf, signature); if !valid { - #[cfg(feature = "std")] - debug!(target: "afg", "Bad signature on message from {:?}", id); + let log_target = if cfg!(feature = "std") { CLIENT_LOG_TARGET } else { RUNTIME_LOG_TARGET }; + + log::debug!(target: log_target, "Bad signature on message from {:?}", id); } valid From 6376f13ac0bf8811be3ffc87fa535357699feefc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Thu, 5 Jan 2023 13:45:40 +0100 Subject: [PATCH 255/715] Return `RuntimeVersion` of overwritten/substituted wasm binary (#13066) * Adds test * Ensure we are using the runtime version of the override/substitute wasm * Update client/service/src/client/call_executor.rs Co-authored-by: Anton Co-authored-by: Anton --- client/service/src/client/call_executor.rs | 151 +++++++++++++----- client/service/src/client/wasm_override.rs | 31 ++-- client/service/src/client/wasm_substitutes.rs | 33 ++-- 3 files changed, 145 insertions(+), 70 deletions(-) diff --git a/client/service/src/client/call_executor.rs b/client/service/src/client/call_executor.rs index bf7e8b3a6555e..7ee19671dd688 100644 --- a/client/service/src/client/call_executor.rs +++ b/client/service/src/client/call_executor.rs @@ -37,7 +37,6 @@ pub struct LocalCallExecutor { wasm_override: Arc>, wasm_substitutes: WasmSubstitutes, spawn_handle: Box, - client_config: ClientConfig, execution_extensions: Arc>, } @@ -61,7 +60,7 @@ where .transpose()?; let wasm_substitutes = WasmSubstitutes::new( - client_config.wasm_runtime_substitutes.clone(), + client_config.wasm_runtime_substitutes, executor.clone(), backend.clone(), )?; @@ -71,7 +70,6 @@ where executor, wasm_override: Arc::new(wasm_override), spawn_handle, - client_config, wasm_substitutes, execution_extensions: Arc::new(execution_extensions), }) @@ -84,34 +82,55 @@ where &'a self, onchain_code: RuntimeCode<'a>, id: &BlockId, - ) -> sp_blockchain::Result> + ) -> sp_blockchain::Result<(RuntimeCode<'a>, RuntimeVersion)> where Block: BlockT, B: backend::Backend, { - let spec = CallExecutor::runtime_version(self, id)?; - 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) + let on_chain_version = self.on_chain_runtime_version(id)?; + let code_and_version = if let Some(d) = self.wasm_override.as_ref().as_ref().and_then(|o| { + o.get( + &on_chain_version.spec_version, + onchain_code.heap_pages, + &on_chain_version.spec_name, + ) + }) { + log::debug!(target: "wasm_overrides", "using WASM override for block {}", id); + d + } else if let Some(s) = + self.wasm_substitutes + .get(on_chain_version.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", + "Neither WASM override nor substitute available for block {id}, using onchain code", + ); + (onchain_code, on_chain_version) + }; + + Ok(code_and_version) + } + + /// Returns the on chain runtime version. + fn on_chain_runtime_version( + &self, + id: &BlockId, + ) -> sp_blockchain::Result { + 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 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); + let runtime_code = + 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())) } } @@ -125,7 +144,6 @@ where executor: self.executor.clone(), wasm_override: self.wasm_override.clone(), spawn_handle: self.spawn_handle.clone(), - client_config: self.client_config.clone(), wasm_substitutes: self.wasm_substitutes.clone(), execution_extensions: self.execution_extensions.clone(), } @@ -162,7 +180,7 @@ where let runtime_code = state_runtime_code.runtime_code().map_err(sp_blockchain::Error::RuntimeCode)?; - let runtime_code = self.check_override(runtime_code, at)?; + let runtime_code = self.check_override(runtime_code, at)?.0; let extensions = self.execution_extensions.extensions( at_hash, @@ -214,7 +232,7 @@ where let runtime_code = state_runtime_code.runtime_code().map_err(sp_blockchain::Error::RuntimeCode)?; - let runtime_code = self.check_override(runtime_code, at)?; + let runtime_code = self.check_override(runtime_code, at)?.0; match recorder { Some(recorder) => { @@ -258,18 +276,13 @@ where } fn runtime_version(&self, id: &BlockId) -> sp_blockchain::Result { - 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 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); + let runtime_code = 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())) + self.check_override(runtime_code, id).map(|(_, v)| v) } fn prove_execution( @@ -287,7 +300,7 @@ where let state_runtime_code = sp_state_machine::backend::BackendRuntimeCode::new(trie_backend); let runtime_code = state_runtime_code.runtime_code().map_err(sp_blockchain::Error::RuntimeCode)?; - let runtime_code = self.check_override(runtime_code, at)?; + let runtime_code = self.check_override(runtime_code, at)?.0; sp_state_machine::prove_execution_on_trie_backend( trie_backend, @@ -352,6 +365,7 @@ mod tests { testing::TaskExecutor, traits::{FetchRuntimeCode, WrappedRuntimeCode}, }; + use std::collections::HashMap; use substrate_test_runtime_client::{runtime, GenesisInit, LocalExecutorDispatch}; #[test] @@ -395,7 +409,7 @@ mod tests { Box::new(TaskExecutor::new()), None, None, - Default::default(), + client_config, ) .expect("Creates a client"); @@ -404,7 +418,6 @@ mod tests { executor: executor.clone(), wasm_override: Arc::new(Some(overrides)), spawn_handle: Box::new(TaskExecutor::new()), - client_config, wasm_substitutes: WasmSubstitutes::new( Default::default(), executor.clone(), @@ -420,8 +433,64 @@ mod tests { let check = call_executor .check_override(onchain_code, &BlockId::Number(Default::default())) - .expect("RuntimeCode override"); + .expect("RuntimeCode override") + .0; assert_eq!(Some(vec![2, 2, 2, 2, 2, 2, 2, 2]), check.fetch_runtime_code().map(Into::into)); } + + #[test] + fn returns_runtime_version_from_substitute() { + const SUBSTITUTE_SPEC_NAME: &str = "substitute-spec-name-cool"; + + let executor = NativeElseWasmExecutor::::new( + WasmExecutionMethod::Interpreted, + Some(128), + 1, + 2, + ); + + let backend = Arc::new(in_mem::Backend::::new()); + + // Let's only override the `spec_name` for our testing purposes. + let substitute = sp_version::embed::embed_runtime_version( + &substrate_test_runtime::WASM_BINARY_BLOATY.unwrap(), + sp_version::RuntimeVersion { + spec_name: SUBSTITUTE_SPEC_NAME.into(), + ..substrate_test_runtime::VERSION + }, + ) + .unwrap(); + + let client_config = crate::client::ClientConfig { + wasm_runtime_substitutes: vec![(0, substitute)].into_iter().collect::>(), + ..Default::default() + }; + + let genesis_block_builder = crate::GenesisBlockBuilder::new( + &substrate_test_runtime_client::GenesisParameters::default().genesis_storage(), + !client_config.no_genesis, + backend.clone(), + executor.clone(), + ) + .expect("Creates genesis block builder"); + + // client is used for the convenience of creating and inserting the genesis block. + let client = + crate::client::new_with_backend::<_, _, runtime::Block, _, runtime::RuntimeApi>( + backend.clone(), + executor.clone(), + genesis_block_builder, + None, + Box::new(TaskExecutor::new()), + None, + None, + client_config, + ) + .expect("Creates a client"); + + let version = client.runtime_version_at(&BlockId::Number(0)).unwrap(); + + assert_eq!(SUBSTITUTE_SPEC_NAME, &*version.spec_name); + } } diff --git a/client/service/src/client/wasm_override.rs b/client/service/src/client/wasm_override.rs index 5fc748f3e88b9..03a5704adf8bf 100644 --- a/client/service/src/client/wasm_override.rs +++ b/client/service/src/client/wasm_override.rs @@ -62,16 +62,16 @@ struct WasmBlob { 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, + /// The runtime version of this blob. + version: RuntimeVersion, /// 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, hash: Vec, path: PathBuf, spec_name: String) -> Self { - Self { code, hash, path, spec_name, last_warn: Default::default() } + fn new(code: Vec, hash: Vec, path: PathBuf, version: RuntimeVersion) -> Self { + Self { code, hash, path, version, last_warn: Default::default() } } fn runtime_code(&self, heap_pages: Option) -> RuntimeCode { @@ -141,10 +141,10 @@ impl WasmOverride { spec: &u32, pages: Option, spec_name: &str, - ) -> Option> { + ) -> Option<(RuntimeCode<'a>, RuntimeVersion)> { self.overrides.get(spec).and_then(|w| { - if spec_name == w.spec_name { - Some(w.runtime_code(pages)) + if spec_name == &*w.version.spec_name { + Some((w.runtime_code(pages), w.version.clone())) } else { let mut last_warn = w.last_warn.lock(); let now = Instant::now(); @@ -155,7 +155,7 @@ impl WasmOverride { tracing::warn!( target = "wasm_overrides", on_chain_spec_name = %spec_name, - override_spec_name = %w.spec_name, + override_spec_name = %w.version, spec_version = %spec, wasm_file = %w.path.display(), "On chain and override `spec_name` do not match! Ignoring override.", @@ -197,8 +197,7 @@ impl WasmOverride { "Found wasm override.", ); - let wasm = - WasmBlob::new(code, code_hash, path.clone(), version.spec_name.to_string()); + let wasm = WasmBlob::new(code, code_hash, path.clone(), version.clone()); if let Some(other) = overrides.insert(version.spec_version, wasm) { tracing::info!( @@ -246,19 +245,19 @@ impl WasmOverride { /// Returns a WasmOverride struct filled with dummy data for testing. #[cfg(test)] pub fn dummy_overrides() -> WasmOverride { + let version = RuntimeVersion { spec_name: "test".into(), ..Default::default() }; let mut overrides = HashMap::new(); overrides.insert( 0, - WasmBlob::new(vec![0, 0, 0, 0, 0, 0, 0, 0], vec![0], PathBuf::new(), "test".into()), + WasmBlob::new(vec![0, 0, 0, 0, 0, 0, 0, 0], vec![0], PathBuf::new(), version.clone()), ); 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()), + WasmBlob::new(vec![1, 1, 1, 1, 1, 1, 1, 1], vec![1], PathBuf::new(), version.clone()), ); + overrides + .insert(2, WasmBlob::new(vec![2, 2, 2, 2, 2, 2, 2, 2], vec![2], PathBuf::new(), version)); + WasmOverride { overrides } } diff --git a/client/service/src/client/wasm_substitutes.rs b/client/service/src/client/wasm_substitutes.rs index f826fa3613c84..a7a3b2cbb2b35 100644 --- a/client/service/src/client/wasm_substitutes.rs +++ b/client/service/src/client/wasm_substitutes.rs @@ -21,7 +21,7 @@ use sc_client_api::backend; use sc_executor::RuntimeVersionOf; use sp_blockchain::{HeaderBackend, Result}; -use sp_core::traits::{FetchRuntimeCode, RuntimeCode}; +use sp_core::traits::{FetchRuntimeCode, RuntimeCode, WrappedRuntimeCode}; use sp_runtime::{ generic::BlockId, traits::{Block as BlockT, NumberFor}, @@ -41,12 +41,13 @@ struct WasmSubstitute { hash: Vec, /// The block number on which we should start using the substitute. block_number: NumberFor, + version: RuntimeVersion, } impl WasmSubstitute { - fn new(code: Vec, block_number: NumberFor) -> Self { + fn new(code: Vec, block_number: NumberFor, version: RuntimeVersion) -> Self { let hash = make_hash(&code); - Self { code, hash, block_number } + Self { code, hash, block_number, version } } fn runtime_code(&self, heap_pages: Option) -> RuntimeCode { @@ -122,9 +123,17 @@ where let substitutes = substitutes .into_iter() .map(|(block_number, code)| { - let substitute = WasmSubstitute::new(code, block_number); - let version = Self::runtime_version(&executor, &substitute)?; - Ok((version.spec_version, substitute)) + let runtime_code = RuntimeCode { + code_fetcher: &WrappedRuntimeCode((&code).into()), + heap_pages: None, + hash: Vec::new(), + }; + let version = Self::runtime_version(&executor, &runtime_code)?; + let spec_version = version.spec_version; + + let substitute = WasmSubstitute::new(code, block_number, version); + + Ok((spec_version, substitute)) }) .collect::>>()?; @@ -139,18 +148,16 @@ where spec: u32, pages: Option, block_id: &BlockId, - ) -> Option> { + ) -> Option<(RuntimeCode<'_>, RuntimeVersion)> { let s = self.substitutes.get(&spec)?; - s.matches(block_id, &*self.backend).then(|| s.runtime_code(pages)) + s.matches(block_id, &*self.backend) + .then(|| (s.runtime_code(pages), s.version.clone())) } - fn runtime_version( - executor: &Executor, - code: &WasmSubstitute, - ) -> Result { + fn runtime_version(executor: &Executor, code: &RuntimeCode) -> Result { let mut ext = BasicExternalities::default(); executor - .runtime_version(&mut ext, &code.runtime_code(None)) + .runtime_version(&mut ext, code) .map_err(|e| WasmSubstituteError::VersionInvalid(e.to_string()).into()) } } From e4a4436732d1c77eabf25cc0c5b3ca8f7d29d117 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= <123550+andresilva@users.noreply.github.com> Date: Thu, 5 Jan 2023 15:19:24 +0000 Subject: [PATCH 256/715] aura: remove stale check to skip execution (#13074) --- client/consensus/aura/src/import_queue.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/client/consensus/aura/src/import_queue.rs b/client/consensus/aura/src/import_queue.rs index 0973b33d402e6..3ac26345db25e 100644 --- a/client/consensus/aura/src/import_queue.rs +++ b/client/consensus/aura/src/import_queue.rs @@ -246,14 +246,14 @@ where // 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())? + if 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(), From 934d42aefb51b797ee9ef41270bc041b1c1c6025 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Thu, 5 Jan 2023 22:11:27 +0100 Subject: [PATCH 257/715] Kademlia: Speed-up the record fetching (#13081) Before libp2p 0.50.0 we used a quorum of one to fetch records from the DHT. In the pr that upgraded to libp2p 0.50.0 we accidentally changed this behavior. This pr brings back the old behavior of using a qorum of one and thus, a faster discovery. After finding the first value, we directly finish the query. There was also another behavior change in libp2p, they stopped automatic caching on remote nodes. This pr also brings back the remote caching on nodes that are nearest to the key from our point of view of the network. The pr that changed the behavior in libp2p: https://github.com/libp2p/rust-libp2p/pull/2712 --- client/network/src/discovery.rs | 75 ++++++++++++++++++++++----------- 1 file changed, 50 insertions(+), 25 deletions(-) diff --git a/client/network/src/discovery.rs b/client/network/src/discovery.rs index 16dbc7662c192..7abc723c4047e 100644 --- a/client/network/src/discovery.rs +++ b/client/network/src/discovery.rs @@ -249,7 +249,7 @@ impl DiscoveryConfig { NonZeroUsize::new(MAX_KNOWN_EXTERNAL_ADDRESSES) .expect("value is a constant; constant is non-zero; qed."), ), - outbound_query_records: Vec::new(), + records_to_publish: Default::default(), } } } @@ -287,8 +287,12 @@ pub struct DiscoveryBehaviour { allow_non_globals_in_dht: bool, /// A cache of discovered external addresses. Only used for logging purposes. known_external_addresses: LruHashSet, - /// A cache of outbound query records. - outbound_query_records: Vec<(record::Key, Vec)>, + /// Records to publish per QueryId. + /// + /// After finishing a Kademlia query, libp2p will return us a list of the closest peers that + /// did not return the record(in `FinishedWithNoAdditionalRecord`). We will then put the record + /// to these peers. + records_to_publish: HashMap, } impl DiscoveryBehaviour { @@ -692,33 +696,54 @@ impl NetworkBehaviour for DiscoveryBehaviour { KademliaEvent::OutboundQueryProgressed { result: QueryResult::GetRecord(res), stats, - step, + id, .. } => { let ev = match res { - Ok(ok) => - if let GetRecordOk::FoundRecord(r) = ok { - self.outbound_query_records - .push((r.record.key, r.record.value)); + Ok(GetRecordOk::FoundRecord(r)) => { + debug!( + target: "sub-libp2p", + "Libp2p => Found record ({:?}) with value: {:?}", + r.record.key, + r.record.value, + ); + + // Let's directly finish the query, as we are only interested in a + // quorum of 1. + if let Some(kad) = self.kademlia.as_mut() { + if let Some(mut query) = kad.query_mut(&id) { + query.finish(); + } + } + + self.records_to_publish.insert(id, r.record.clone()); + + DiscoveryOut::ValueFound( + vec![(r.record.key, r.record.value)], + stats.duration().unwrap_or_default(), + ) + }, + Ok(GetRecordOk::FinishedWithNoAdditionalRecord { + cache_candidates, + }) => { + if cache_candidates.is_empty() { continue - } else { - debug!( - target: "sub-libp2p", - "Libp2p => Query progressed to {:?} step (last: {:?})", - step.count, - step.last, - ); - if step.last { - let records = - self.outbound_query_records.drain(..).collect(); - DiscoveryOut::ValueFound( - records, - stats.duration().unwrap_or_default(), - ) - } else { - continue + } + + // Put the record to the `cache_candidates` that are nearest to the + // record key from our point of view of the network. + if let Some(record) = self.records_to_publish.remove(&id) { + if let Some(kad) = self.kademlia.as_mut() { + kad.put_record_to( + record, + cache_candidates.into_iter().map(|v| v.1), + Quorum::One, + ); } - }, + } + + continue + }, Err(e @ libp2p::kad::GetRecordError::NotFound { .. }) => { trace!( target: "sub-libp2p", From 8d17a16a5653974ec17ed617306606e9dbb6e4b4 Mon Sep 17 00:00:00 2001 From: Sasha Gryaznov Date: Fri, 6 Jan 2023 01:22:43 +0200 Subject: [PATCH 258/715] [contracts] Add docs generator for the contracts API to the `#[define_env]` macro (#13032) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * macro to expand traits for host functions documentation * other way: same Doc trait in seal modules * added docs for macro, and remove `doc` attribute * fmt * Apply suggestions from code review Co-authored-by: Alexander Theißen * make docs to be generated into re-exported `api_doc` module; fix unrelated elder docs; * make it compile without `doc` attr passed to macro * make alias functions indicated explicitly in docs * tidy up docs * refactored a bit * macro to auto-add doc warning for unstable functions * invoke macro with no doc generation by default * addressed review comments * hide api_doc module behind cfg(doc) Co-authored-by: Alexander Theißen --- frame/contracts/proc-macro/src/lib.rs | 153 ++++++++++++++++++--- frame/contracts/src/exec.rs | 2 +- frame/contracts/src/lib.rs | 3 + frame/contracts/src/wasm/mod.rs | 9 +- frame/contracts/src/wasm/runtime.rs | 191 +++++++++++++------------- 5 files changed, 242 insertions(+), 116 deletions(-) diff --git a/frame/contracts/proc-macro/src/lib.rs b/frame/contracts/proc-macro/src/lib.rs index ded5880a2df4d..a31d39f47e215 100644 --- a/frame/contracts/proc-macro/src/lib.rs +++ b/frame/contracts/proc-macro/src/lib.rs @@ -30,9 +30,12 @@ use alloc::{ vec::Vec, }; use proc_macro::TokenStream; -use proc_macro2::TokenStream as TokenStream2; +use proc_macro2::{Span, TokenStream as TokenStream2}; use quote::{quote, quote_spanned, ToTokens}; -use syn::{parse_macro_input, spanned::Spanned, Data, DeriveInput, FnArg, Ident}; +use syn::{ + parse_macro_input, punctuated::Punctuated, spanned::Spanned, token::Comma, 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 @@ -158,6 +161,7 @@ struct HostFn { name: String, returns: HostFnReturn, is_stable: bool, + alias_to: Option, } enum HostFnReturn { @@ -187,7 +191,7 @@ impl ToTokens for HostFn { } impl HostFn { - pub fn try_from(item: syn::ItemFn) -> syn::Result { + pub fn try_from(mut item: syn::ItemFn) -> syn::Result { let err = |span, msg| { let msg = format!("Invalid host function definition. {}", msg); syn::Error::new(span, msg) @@ -198,10 +202,10 @@ impl HostFn { "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(); + attrs.retain(|a| !a.path.is_ident("doc")); let mut maybe_module = None; let mut is_stable = true; + let mut alias_to = None; while let Some(attr) = attrs.pop() { let ident = attr.path.get_ident().ok_or(err(span, msg))?.to_string(); match ident.as_str() { @@ -219,9 +223,17 @@ impl HostFn { } is_stable = false; }, + "prefixed_alias" => { + alias_to = Some(item.sig.ident.to_string()); + item.sig.ident = syn::Ident::new( + &format!("seal_{}", &item.sig.ident.to_string()), + item.sig.ident.span(), + ); + }, _ => return Err(err(span, msg)), } } + let name = item.sig.ident.to_string(); // process arguments: The first and second arg are treated differently (ctx, memory) // they must exist and be `ctx: _` and `memory: _`. @@ -317,6 +329,7 @@ impl HostFn { name, returns, is_stable, + alias_to, }) }, _ => Err(err(span, &msg)), @@ -348,19 +361,15 @@ impl EnvDef { .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() .filter_map(extract_fn) + .map(|mut i| { + i.attrs.retain(|i| !selector(i)); + i + }) .map(|i| HostFn::try_from(i)) .chain(aliases) .collect::, _>>()?; @@ -383,16 +392,111 @@ fn is_valid_special_arg(idx: usize, arg: &FnArg) -> bool { matches!(*pat.ty, syn::Type::Infer(_)) } +/// Expands documentation for host functions. +fn expand_docs(def: &mut EnvDef) -> TokenStream2 { + let mut modules = def.host_funcs.iter().map(|f| f.module.clone()).collect::>(); + modules.sort(); + modules.dedup(); + + let doc_selector = |a: &syn::Attribute| a.path.is_ident("doc"); + let docs = modules.iter().map(|m| { + let funcs = def.host_funcs.iter_mut().map(|f| { + if *m == f.module { + // Remove auxiliary args: `ctx: _` and `memory: _` + f.item.sig.inputs = f + .item + .sig + .inputs + .iter() + .skip(2) + .map(|p| p.clone()) + .collect::>(); + let func_decl = f.item.sig.to_token_stream(); + let func_doc = if let Some(origin_fn) = &f.alias_to { + let alias_doc = format!( + "This is just an alias function to [`{0}()`][`Self::{0}`] with backwards-compatible prefixed identifier.", + origin_fn, + ); + quote! { #[doc = #alias_doc] } + + } else { + let func_docs = f.item.attrs.iter().filter(|a| doc_selector(a)).map(|d| { + let docs = d.to_token_stream(); + quote! { #docs } + }); + let unstable_notice = if !f.is_stable { + let warning = "\n # Unstable\n\n \ + This function is unstable and it is a subject to change (or removal) in the future.\n \ + Do not deploy a contract using it to a production chain."; + quote! { #[doc = #warning] } + } else { + quote! {} + }; + quote! { + #( #func_docs )* + #unstable_notice + } + }; + quote! { + #func_doc + #func_decl; + } + } else { + quote! {} + } + }); + + let module = Ident::new(m, Span::call_site()); + let module_doc = format!( + "Documentation of the API available to contracts by importing `{}` WASM module.", + module + ); + + quote! { + #[doc = #module_doc] + pub mod #module { + use crate::wasm::runtime::{TrapReason, ReturnCode}; + /// Every function in this trait represents (at least) one function that can be imported by a contract. + /// + /// The function's identifier is to be set as the name in the import definition. + /// Where it is specifically indicated, an _alias_ function having `seal_`-prefixed identifier and + /// just the same signature and body, is also available (for backwards-compatibility purposes). + pub trait Api { + #( #funcs )* + } + } + } + }); + quote! { + #( #docs )* + } +} + /// Expands environment definiton. /// Should generate source code for: /// - implementations of the host functions to be added to the wasm runtime environment (see /// `expand_impls()`). -fn expand_env(def: &mut EnvDef) -> TokenStream2 { +fn expand_env(def: &mut EnvDef, docs: bool) -> TokenStream2 { let impls = expand_impls(def); + let docs = docs.then_some(expand_docs(def)).unwrap_or(TokenStream2::new()); quote! { pub struct Env; #impls + /// Contains the documentation of the API available to contracts. + /// + /// In order to generate this documentation, pass `doc` attribute to the [`#[define_env]`][`macro@define_env`] macro: + /// `#[define_env(doc)]`, and then run `cargo doc`. + /// + /// This module is not meant to be used by any code. Rather, it is meant to be consumed by humans through rustdoc. + /// + /// Every function described in this module's sub module's traits uses this sub module's identifier + /// as its imported module name. The identifier of the function is the function's imported name. + /// According to the [WASM spec of imports](https://webassembly.github.io/spec/core/text/modules.html#text-import). + #[cfg(doc)] + pub mod api_doc { + #docs + } } } @@ -579,10 +683,25 @@ fn expand_functions( /// /// 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. +/// +/// # Generating Documentation +/// +/// Passing `doc` attribute to the macro (like `#[define_env(doc)]`) will make it also expand +/// additional `pallet_contracts::api_doc::seal0`, `pallet_contracts::api_doc::seal1`, +/// `...` modules each having its `Api` trait containing functions holding documentation for every +/// host function defined by the macro. +/// +/// To build up these docs, run: +/// +/// ```nocompile +/// cargo doc +/// ``` #[proc_macro_attribute] 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]`."; + if !attr.is_empty() && !(attr.to_string() == "doc".to_string()) { + let msg = r#"Invalid `define_env` attribute macro: expected either no attributes or a single `doc` attibute: + - `#[define_env]` + - `#[define_env(doc)]`"#; let span = TokenStream2::from(attr).span(); return syn::Error::new(span, msg).to_compile_error().into() } @@ -590,7 +709,7 @@ pub fn define_env(attr: TokenStream, item: TokenStream) -> TokenStream { let item = syn::parse_macro_input!(item as syn::ItemMod); match EnvDef::try_from(item) { - Ok(mut def) => expand_env(&mut def).into(), + Ok(mut def) => expand_env(&mut def, !attr.is_empty()).into(), Err(e) => e.to_compile_error().into(), } } diff --git a/frame/contracts/src/exec.rs b/frame/contracts/src/exec.rs index df1dd24856a8a..8ae70b804d69b 100644 --- a/frame/contracts/src/exec.rs +++ b/frame/contracts/src/exec.rs @@ -462,7 +462,7 @@ enum FrameArgs<'a, T: Config, E> { /// 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 + /// what is stored at [`Self::Call::dest`]. Its caller ([`DelegatedCall::caller`]) is the /// account which called the caller contract delegated_call: Option>, }, diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index 778ceec961500..9df790e09a1e8 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -134,6 +134,9 @@ pub use crate::{ wasm::Determinism, }; +#[cfg(doc)] +pub use crate::wasm::api_doc; + type CodeHash = ::Hash; type TrieId = BoundedVec>; type BalanceOf = diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index 553bae59e78b9..f1d0ccc7c216b 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -28,6 +28,10 @@ pub use crate::wasm::{ prepare::TryInstantiate, runtime::{CallFlags, Environment, ReturnCode, Runtime, RuntimeCosts}, }; + +#[cfg(doc)] +pub use crate::wasm::runtime::api_doc; + use crate::{ exec::{ExecResult, Executable, ExportedFunction, Ext}, gas::GasMeter, @@ -144,7 +148,7 @@ impl PrefabWasmModule { /// 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`]. + /// or [`::execute`][`Executable::execute`]. pub fn from_code( original_code: Vec, schedule: &Schedule, @@ -164,7 +168,8 @@ impl PrefabWasmModule { /// Store the code without instantiating it. /// - /// Otherwise the code is stored when [`::execute`] is called. + /// Otherwise the code is stored when [`::execute`][`Executable::execute`] + /// is called. pub fn store(self) -> DispatchResult { code_cache::store(self, false) } diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index 7d67adc3ded33..098f8d280e6a9 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -52,7 +52,7 @@ pub trait Environment { /// Type of a storage key. #[allow(dead_code)] enum KeyType { - /// Deprecated fix sized key [0;32]. + /// Deprecated fix sized key `[u8;32]`. Fix, /// Variable sized key used in transparent hashing, /// cannot be larger than MaxStorageKeyLen. @@ -996,14 +996,14 @@ impl<'a, E: Ext + 'a> Runtime<'a, E> { // 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] +#[define_env(doc)] 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. + /// - `amount`: How much gas is used. fn gas(ctx: _, _memory: _, amount: u64) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::MeteringBlock(amount))?; Ok(()) @@ -1011,8 +1011,8 @@ pub mod env { /// 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. + /// Equivalent to the newer version [`super::seal1::Api::set_storage`] with the exception of the + /// return type. Still a valid thing to call when not interested in the return value. #[prefixed_alias] fn set_storage( ctx: _, @@ -1085,8 +1085,8 @@ pub mod env { /// 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. + /// Equivalent to the newer version [`super::seal1::Api::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: _, memory: _, key_ptr: u32) -> Result<(), TrapReason> { ctx.clear_storage(memory, KeyType::Fix, key_ptr).map(|_| ()) @@ -1152,7 +1152,7 @@ pub mod env { /// /// # Errors /// - /// `ReturnCode::KeyNotFound` + /// - `ReturnCode::KeyNotFound` #[version(1)] #[prefixed_alias] fn get_storage( @@ -1215,7 +1215,7 @@ pub mod env { /// /// # Errors /// - /// `ReturnCode::KeyNotFound` + /// - `ReturnCode::KeyNotFound` #[prefixed_alias] fn take_storage( ctx: _, @@ -1245,16 +1245,16 @@ pub mod env { /// /// # 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. + /// - `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` + /// - `ReturnCode::TransferFailed` #[prefixed_alias] fn transfer( ctx: _, @@ -1288,8 +1288,9 @@ pub mod env { /// # 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. + /// of those types are fixed through + /// [`codec::MaxEncodedLen`]. The fields exist + /// for backwards compatibility. Consider switching to the newest version of this function. #[prefixed_alias] fn call( ctx: _, @@ -1323,16 +1324,16 @@ pub mod env { /// /// # 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 + /// - `flags`: See `crate::wasm::runtime::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 + /// - `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 @@ -1340,10 +1341,10 @@ pub mod env { /// 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` + /// - `ReturnCode::CalleeReverted`: Output buffer is returned. + /// - `ReturnCode::CalleeTrapped` + /// - `ReturnCode::TransferFailed` + /// - `ReturnCode::NotCallable` #[version(1)] #[prefixed_alias] fn call( @@ -1377,12 +1378,12 @@ pub mod env { /// /// # 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 + /// - `flags`: see `crate::wasm::runtime::CallFlags` for a documentation of the supported flags. + /// - `code_hash`: a pointer to the hash of the code to be called. + /// - `input_data_ptr`: a pointer to a buffer to be used as input data to the callee. + /// - `input_data_len`: length of the input data buffer. + /// - `output_ptr`: a pointer where the output buffer is copied to. + /// - `output_len_ptr`: in-out pointer to where the length of the buffer is read from and the /// actual length is written to. /// /// # Errors @@ -1390,9 +1391,9 @@ pub mod env { /// 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` + /// - `ReturnCode::CalleeReverted`: Output buffer is returned. + /// - `ReturnCode::CalleeTrapped` + /// - `ReturnCode::CodeNotFound` #[prefixed_alias] fn delegate_call( ctx: _, @@ -1425,8 +1426,9 @@ pub mod env { /// # 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. + /// of those types are fixed through + /// [`codec::MaxEncodedLen`]. The fields exist + /// for backwards compatibility. Consider switching to the newest version of this function. #[prefixed_alias] fn instantiate( ctx: _, @@ -1474,20 +1476,20 @@ pub mod env { /// /// # 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 + /// - `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 + /// - `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. + /// - `salt_ptr`: Pointer to raw bytes used for address derivation. See `fn contract_address`. + /// - `salt_len`: length in bytes of the supplied salt. /// /// # Errors /// @@ -1497,10 +1499,10 @@ pub mod env { /// 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` + /// - `ReturnCode::CalleeReverted`: Output buffer is returned. + /// - `ReturnCode::CalleeTrapped` + /// - `ReturnCode::TransferFailed` + /// - `ReturnCode::CodeNotFound` #[version(1)] #[prefixed_alias] fn instantiate( @@ -1562,7 +1564,7 @@ pub mod env { /// 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 + /// - `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. /// @@ -1586,7 +1588,7 @@ pub mod env { /// /// # Note /// - /// This function traps if the input was previously forwarded by a `seal_call`. + /// This function traps if the input was previously forwarded by a [`call()`][`Self::call()`]. #[prefixed_alias] fn input(ctx: _, memory: _, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::InputBase)?; @@ -1606,7 +1608,7 @@ pub mod env { /// This function never returns as it stops execution of the caller. /// This is the only way to return a data buffer to the caller. Returning from /// execution without calling this function is equivalent to calling: - /// ``` + /// ```nocompile /// seal_return(0, 0, 0); /// ``` /// @@ -1659,10 +1661,10 @@ pub mod env { /// /// # Parameters /// - /// - account_ptr: a pointer to the address of the beneficiary account Should be decodable as an - /// `T::AccountId`. Traps otherwise. + /// - `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). + /// Returned value is a `u32`-encoded boolean: (0 = false, 1 = true). #[prefixed_alias] fn is_contract(ctx: _, memory: _, account_ptr: u32) -> Result { ctx.charge_gas(RuntimeCosts::IsContract)?; @@ -1684,7 +1686,7 @@ pub mod env { /// /// # Errors /// - /// `ReturnCode::KeyNotFound` + /// - `ReturnCode::KeyNotFound` #[prefixed_alias] fn code_hash( ctx: _, @@ -1734,14 +1736,14 @@ pub mod env { /// 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. + /// Prefer this over [`is_contract()`][`Self::is_contract`] when checking whether your contract + /// is being called by a contract or a plain account. The reason is that it performs better + /// since it does not need to do any storage lookups. /// - /// A return value of`true` indicates that this contract is being called by a plain account + /// 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). + /// Returned value is a `u32`-encoded boolean: (`0 = false`, `1 = true`). #[prefixed_alias] fn caller_is_origin(ctx: _, _memory: _) -> Result { ctx.charge_gas(RuntimeCosts::CallerIsOrigin)?; @@ -1774,7 +1776,7 @@ 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. /// - /// The data is encoded as T::Balance. + /// The data is encoded as `T::Balance`. /// /// # Note /// @@ -1822,14 +1824,14 @@ pub mod env { )?) } - /// Stores the **free* 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 /// `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. + /// The data is encoded as `T::Balance`. #[prefixed_alias] fn balance(ctx: _, memory: _, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::Balance)?; @@ -1846,11 +1848,11 @@ pub mod env { /// Stores the value transferred along with this call/instantiate into the supplied buffer. /// /// The value is stored to linear memory at the address pointed to by `out_ptr`. - /// `out_len_ptr` must point to a u32 value that describes the available space at + /// `out_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. + /// The data is encoded as `T::Balance`. #[prefixed_alias] fn value_transferred( ctx: _, @@ -1876,11 +1878,12 @@ 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. /// - /// The data is encoded as T::Hash. + /// The data is encoded as `T::Hash`. /// /// # Deprecation /// - /// This function is deprecated. Users should migrate to the version in the "seal1" module. + /// This function is deprecated. Users should migrate to the [`super::seal1::Api::random()`] + /// version. #[prefixed_alias] fn random( ctx: _, @@ -1972,7 +1975,7 @@ pub mod env { /// Stores the minimum balance (a.k.a. existential deposit) into the supplied buffer. /// - /// The data is encoded as T::Balance. + /// The data is encoded as `T::Balance`. #[prefixed_alias] fn minimum_balance( ctx: _, @@ -2000,7 +2003,7 @@ pub mod env { /// /// # Deprecation /// - /// There is no longer a tombstone deposit. This function always returns 0. + /// There is no longer a tombstone deposit. This function always returns `0`. #[prefixed_alias] fn tombstone_deposit( ctx: _, @@ -2067,11 +2070,12 @@ pub mod env { /// Deposit a contract event with the data buffer and optional list of topics. There is a limit /// on the maximum number of topics specified by `event_topics`. /// - /// - topics_ptr - a pointer to the buffer of topics encoded as `Vec`. The value of - /// this is ignored if `topics_len` is set to 0. The topics list can't contain duplicates. - /// - topics_len - the length of the topics buffer. Pass 0 if you want to pass an empty vector. - /// - data_ptr - a pointer to a raw data buffer which will saved along the event. - /// - data_len - the length of the data buffer. + /// - `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. #[prefixed_alias] fn deposit_event( ctx: _, @@ -2422,11 +2426,6 @@ pub mod env { /// - 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] #[prefixed_alias] fn call_runtime( @@ -2466,7 +2465,7 @@ pub mod env { /// /// # Errors /// - /// `ReturnCode::EcdsaRecoverFailed` + /// - `ReturnCode::EcdsaRecoverFailed` #[prefixed_alias] fn ecdsa_recover( ctx: _, @@ -2513,8 +2512,8 @@ pub mod env { /// /// 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. + /// would revert the changes made by [`set_code_hash()`][`Self::set_code_hash`] and the next + /// caller would use the old code. /// /// # Parameters /// @@ -2522,7 +2521,7 @@ pub mod env { /// /// # Errors /// - /// `ReturnCode::CodeNotFound` + /// - `ReturnCode::CodeNotFound` #[prefixed_alias] fn set_code_hash(ctx: _, memory: _, code_hash_ptr: u32) -> Result { ctx.charge_gas(RuntimeCosts::SetCodeHash)?; @@ -2552,7 +2551,7 @@ pub mod env { /// /// # Errors /// - /// `ReturnCode::EcdsaRecoverFailed` + /// - `ReturnCode::EcdsaRecoverFailed` #[prefixed_alias] fn ecdsa_to_eth_address( ctx: _, @@ -2578,7 +2577,7 @@ pub mod env { /// /// # Return Value /// - /// Returns 0 when there is no reentrancy. + /// Returns `0` when there is no reentrancy. #[unstable] fn reentrance_count(ctx: _, memory: _) -> Result { ctx.charge_gas(RuntimeCosts::ReentrantCount)?; @@ -2594,7 +2593,7 @@ pub mod env { /// /// # Return Value /// - /// Returns 0 when the contract does not exist on the call stack. + /// Returns `0` when the contract does not exist on the call stack. #[unstable] fn account_reentrance_count(ctx: _, memory: _, account_ptr: u32) -> Result { ctx.charge_gas(RuntimeCosts::AccountEntranceCount)?; From bc73ebf85039dad2cad399be6effe343ad9552e9 Mon Sep 17 00:00:00 2001 From: Falco Hirschenberger Date: Fri, 6 Jan 2023 09:45:56 +0100 Subject: [PATCH 259/715] Update trybuild to avoid random test failures. (#13073) * Update trybuild to avoid random test failures. A feature was added to trybuild >1.0.70 avoid failing on different variant counts in the line `and 278 others` fixes #12955 * Update all trybuild deps to latest version * Update Cargo.lock --- Cargo.lock | 4 ++-- 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 +- test-utils/Cargo.toml | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d333b79c8c403..a3dc04a39718f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11387,9 +11387,9 @@ dependencies = [ [[package]] name = "trybuild" -version = "1.0.73" +version = "1.0.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed01de3de062db82c0920b5cabe804f88d599a3f217932292597c678c903754d" +checksum = "654bfc024d30963fce210f22f98956407fe8c8365eb85a1fa530f6f8844137ed" dependencies = [ "dissimilar", "glob", diff --git a/frame/election-provider-support/solution-type/Cargo.toml b/frame/election-provider-support/solution-type/Cargo.toml index 5a0c46cb83a0d..50c39c547fb9b 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 = "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" } -trybuild = "1.0.60" +trybuild = "1.0.74" diff --git a/frame/support/test/Cargo.toml b/frame/support/test/Cargo.toml index 0ac3d90f59e07..7fe1bcb5674bb 100644 --- a/frame/support/test/Cargo.toml +++ b/frame/support/test/Cargo.toml @@ -23,7 +23,7 @@ sp-runtime = { version = "7.0.0", default-features = false, path = "../../../pri 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" ] } +trybuild = { version = "1.0.74", features = [ "diff" ] } pretty_assertions = "1.2.1" 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 edc0d43e91437..7f15287cf36d6 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.13.0", path = "../../state-machine" } -trybuild = "1.0.60" +trybuild = "1.0.74" rustversion = "1.0.6" [dev-dependencies] diff --git a/primitives/runtime-interface/Cargo.toml b/primitives/runtime-interface/Cargo.toml index 09f4b83d68b34..da746179e281d 100644 --- a/primitives/runtime-interface/Cargo.toml +++ b/primitives/runtime-interface/Cargo.toml @@ -32,7 +32,7 @@ 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" +trybuild = "1.0.74" [features] default = [ "std" ] diff --git a/test-utils/Cargo.toml b/test-utils/Cargo.toml index cd4839fa1cbd7..1b98b23e0b254 100644 --- a/test-utils/Cargo.toml +++ b/test-utils/Cargo.toml @@ -18,5 +18,5 @@ tokio = { version = "1.22.0", features = ["macros", "time"] } substrate-test-utils-derive = { version = "0.10.0-dev", path = "./derive" } [dev-dependencies] -trybuild = { version = "1.0.53", features = [ "diff" ] } +trybuild = { version = "1.0.74", features = [ "diff" ] } sc-service = { version = "0.10.0-dev", path = "../client/service" } From 363ce0a9a8df4fa8071f35974b917333b0ef300d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Fri, 6 Jan 2023 10:41:17 +0100 Subject: [PATCH 260/715] Do not leak records (#13086) --- client/network/src/discovery.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/client/network/src/discovery.rs b/client/network/src/discovery.rs index 7abc723c4047e..5421db8194456 100644 --- a/client/network/src/discovery.rs +++ b/client/network/src/discovery.rs @@ -716,6 +716,8 @@ impl NetworkBehaviour for DiscoveryBehaviour { } } + // Will be removed below when we receive + // `FinishedWithNoAdditionalRecord`. self.records_to_publish.insert(id, r.record.clone()); DiscoveryOut::ValueFound( @@ -726,13 +728,14 @@ impl NetworkBehaviour for DiscoveryBehaviour { Ok(GetRecordOk::FinishedWithNoAdditionalRecord { cache_candidates, }) => { - if cache_candidates.is_empty() { - continue - } - - // Put the record to the `cache_candidates` that are nearest to the - // record key from our point of view of the network. + // We always need to remove the record to not leak any data! if let Some(record) = self.records_to_publish.remove(&id) { + if cache_candidates.is_empty() { + continue + } + + // Put the record to the `cache_candidates` that are nearest to + // the record key from our point of view of the network. if let Some(kad) = self.kademlia.as_mut() { kad.put_record_to( record, From 90ffe716b88f6dc64eeb530332267a86e66668b4 Mon Sep 17 00:00:00 2001 From: Nazar Mokrynskyi Date: Fri, 6 Jan 2023 12:24:12 +0200 Subject: [PATCH 261/715] Only use `substrate-wasm-builder` when `std` feature is enabled. (#12790) Co-authored-by: parity-processbot <> --- bin/node-template/runtime/Cargo.toml | 3 +- bin/node-template/runtime/build.rs | 15 +++---- bin/node/runtime/Cargo.toml | 3 +- bin/node/runtime/build.rs | 15 +++---- client/executor/runtime-test/Cargo.toml | 3 +- client/executor/runtime-test/build.rs | 32 ++++++++------- .../test-wasm-deprecated/Cargo.toml | 10 ++++- .../test-wasm-deprecated/build.rs | 15 +++---- .../runtime-interface/test-wasm/Cargo.toml | 10 ++++- .../runtime-interface/test-wasm/build.rs | 15 +++---- test-utils/runtime/Cargo.toml | 3 +- test-utils/runtime/build.rs | 40 ++++++++++--------- utils/wasm-builder/README.md | 25 ++++++------ 13 files changed, 109 insertions(+), 80 deletions(-) diff --git a/bin/node-template/runtime/Cargo.toml b/bin/node-template/runtime/Cargo.toml index 1a3c5bd84223b..5dc7b03d39a81 100644 --- a/bin/node-template/runtime/Cargo.toml +++ b/bin/node-template/runtime/Cargo.toml @@ -51,7 +51,7 @@ frame-system-benchmarking = { version = "4.0.0-dev", default-features = false, p 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" } +substrate-wasm-builder = { version = "5.0.0-dev", path = "../../../utils/wasm-builder", optional = true } [features] default = ["std"] @@ -86,6 +86,7 @@ std = [ "sp-std/std", "sp-transaction-pool/std", "sp-version/std", + "substrate-wasm-builder", ] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", diff --git a/bin/node-template/runtime/build.rs b/bin/node-template/runtime/build.rs index 9b53d2457dffd..c03d618535be0 100644 --- a/bin/node-template/runtime/build.rs +++ b/bin/node-template/runtime/build.rs @@ -1,9 +1,10 @@ -use substrate_wasm_builder::WasmBuilder; - fn main() { - WasmBuilder::new() - .with_current_project() - .export_heap_base() - .import_memory() - .build() + #[cfg(feature = "std")] + { + substrate_wasm_builder::WasmBuilder::new() + .with_current_project() + .export_heap_base() + .import_memory() + .build(); + } } diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index 201e3a85f8941..7037be9d7c54d 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -113,7 +113,7 @@ pallet-vesting = { version = "4.0.0-dev", default-features = false, path = "../. 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" } +substrate-wasm-builder = { version = "5.0.0-dev", path = "../../../utils/wasm-builder", optional = true } [features] default = ["std"] @@ -205,6 +205,7 @@ std = [ "sp-io/std", "pallet-child-bounties/std", "pallet-alliance/std", + "substrate-wasm-builder", ] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", diff --git a/bin/node/runtime/build.rs b/bin/node/runtime/build.rs index b773ed9cf6fb7..70f84bc00a817 100644 --- a/bin/node/runtime/build.rs +++ b/bin/node/runtime/build.rs @@ -15,12 +15,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -use substrate_wasm_builder::WasmBuilder; - fn main() { - WasmBuilder::new() - .with_current_project() - .export_heap_base() - .import_memory() - .build() + #[cfg(feature = "std")] + { + substrate_wasm_builder::WasmBuilder::new() + .with_current_project() + .export_heap_base() + .import_memory() + .build(); + } } diff --git a/client/executor/runtime-test/Cargo.toml b/client/executor/runtime-test/Cargo.toml index eadf547823bb2..e99f3caa9447e 100644 --- a/client/executor/runtime-test/Cargo.toml +++ b/client/executor/runtime-test/Cargo.toml @@ -19,7 +19,7 @@ sp-runtime = { version = "7.0.0", default-features = false, path = "../../../pri 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" } +substrate-wasm-builder = { version = "5.0.0-dev", path = "../../../utils/wasm-builder", optional = true } [features] default = ["std"] @@ -28,4 +28,5 @@ std = [ "sp-io/std", "sp-runtime/std", "sp-std/std", + "substrate-wasm-builder", ] diff --git a/client/executor/runtime-test/build.rs b/client/executor/runtime-test/build.rs index 27f931a542d4a..d3aceedf9ed95 100644 --- a/client/executor/runtime-test/build.rs +++ b/client/executor/runtime-test/build.rs @@ -16,22 +16,26 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use substrate_wasm_builder::WasmBuilder; - fn main() { // regular build - WasmBuilder::new() - .with_current_project() - .export_heap_base() - .import_memory() - .build(); + #[cfg(feature = "std")] + { + substrate_wasm_builder::WasmBuilder::new() + .with_current_project() + .export_heap_base() + .import_memory() + .build(); + } // and building with tracing activated - WasmBuilder::new() - .with_current_project() - .export_heap_base() - .import_memory() - .set_file_name("wasm_binary_with_tracing.rs") - .append_to_rust_flags(r#"--cfg feature="with-tracing""#) - .build(); + #[cfg(feature = "std")] + { + substrate_wasm_builder::WasmBuilder::new() + .with_current_project() + .export_heap_base() + .import_memory() + .set_file_name("wasm_binary_with_tracing.rs") + .append_to_rust_flags(r#"--cfg feature="with-tracing""#) + .build(); + } } diff --git a/primitives/runtime-interface/test-wasm-deprecated/Cargo.toml b/primitives/runtime-interface/test-wasm-deprecated/Cargo.toml index 32d78ec2cee41..ec07481234e91 100644 --- a/primitives/runtime-interface/test-wasm-deprecated/Cargo.toml +++ b/primitives/runtime-interface/test-wasm-deprecated/Cargo.toml @@ -19,8 +19,14 @@ 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" } +substrate-wasm-builder = { version = "5.0.0-dev", path = "../../../utils/wasm-builder", optional = true } [features] default = [ "std" ] -std = [ "sp-core/std", "sp-io/std", "sp-runtime-interface/std", "sp-std/std" ] +std = [ + "sp-core/std", + "sp-io/std", + "sp-runtime-interface/std", + "sp-std/std", + "substrate-wasm-builder", +] diff --git a/primitives/runtime-interface/test-wasm-deprecated/build.rs b/primitives/runtime-interface/test-wasm-deprecated/build.rs index b773ed9cf6fb7..70f84bc00a817 100644 --- a/primitives/runtime-interface/test-wasm-deprecated/build.rs +++ b/primitives/runtime-interface/test-wasm-deprecated/build.rs @@ -15,12 +15,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -use substrate_wasm_builder::WasmBuilder; - fn main() { - WasmBuilder::new() - .with_current_project() - .export_heap_base() - .import_memory() - .build() + #[cfg(feature = "std")] + { + substrate_wasm_builder::WasmBuilder::new() + .with_current_project() + .export_heap_base() + .import_memory() + .build(); + } } diff --git a/primitives/runtime-interface/test-wasm/Cargo.toml b/primitives/runtime-interface/test-wasm/Cargo.toml index 5fb4850af8d9b..1061a54d7f1b8 100644 --- a/primitives/runtime-interface/test-wasm/Cargo.toml +++ b/primitives/runtime-interface/test-wasm/Cargo.toml @@ -20,8 +20,14 @@ 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" } +substrate-wasm-builder = { version = "5.0.0-dev", path = "../../../utils/wasm-builder", optional = true } [features] default = [ "std" ] -std = [ "sp-core/std", "sp-io/std", "sp-runtime-interface/std", "sp-std/std" ] +std = [ + "sp-core/std", + "sp-io/std", + "sp-runtime-interface/std", + "sp-std/std", + "substrate-wasm-builder", +] diff --git a/primitives/runtime-interface/test-wasm/build.rs b/primitives/runtime-interface/test-wasm/build.rs index b773ed9cf6fb7..70f84bc00a817 100644 --- a/primitives/runtime-interface/test-wasm/build.rs +++ b/primitives/runtime-interface/test-wasm/build.rs @@ -15,12 +15,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -use substrate_wasm_builder::WasmBuilder; - fn main() { - WasmBuilder::new() - .with_current_project() - .export_heap_base() - .import_memory() - .build() + #[cfg(feature = "std")] + { + substrate_wasm_builder::WasmBuilder::new() + .with_current_project() + .export_heap_base() + .import_memory() + .build(); + } } diff --git a/test-utils/runtime/Cargo.toml b/test-utils/runtime/Cargo.toml index 7576a63ac3eb1..cff0227d03184 100644 --- a/test-utils/runtime/Cargo.toml +++ b/test-utils/runtime/Cargo.toml @@ -59,7 +59,7 @@ substrate-test-runtime-client = { version = "2.0.0", path = "./client" } futures = "0.3.21" [build-dependencies] -substrate-wasm-builder = { version = "5.0.0-dev", path = "../../utils/wasm-builder" } +substrate-wasm-builder = { version = "5.0.0-dev", path = "../../utils/wasm-builder", optional = true } [features] default = [ @@ -101,6 +101,7 @@ std = [ "sp-trie/std", "sp-transaction-pool/std", "trie-db/std", + "substrate-wasm-builder", ] # Special feature to disable logging disable-logging = [ "sp-api/disable-logging" ] diff --git a/test-utils/runtime/build.rs b/test-utils/runtime/build.rs index 5a7b518d0bd75..870d8ac43825b 100644 --- a/test-utils/runtime/build.rs +++ b/test-utils/runtime/build.rs @@ -15,24 +15,28 @@ // See the License for the specific language governing permissions and // limitations under the License. -use substrate_wasm_builder::WasmBuilder; - fn main() { - WasmBuilder::new() - .with_current_project() - .export_heap_base() - // Note that we set the stack-size to 1MB explicitly even though it is set - // to this value by default. This is because some of our tests (`restoration_of_globals`) - // depend on the stack-size. - .append_to_rust_flags("-Clink-arg=-zstack-size=1048576") - .import_memory() - .build(); + #[cfg(feature = "std")] + { + substrate_wasm_builder::WasmBuilder::new() + .with_current_project() + .export_heap_base() + // Note that we set the stack-size to 1MB explicitly even though it is set + // to this value by default. This is because some of our tests + // (`restoration_of_globals`) depend on the stack-size. + .append_to_rust_flags("-Clink-arg=-zstack-size=1048576") + .import_memory() + .build(); + } - WasmBuilder::new() - .with_current_project() - .export_heap_base() - .import_memory() - .set_file_name("wasm_binary_logging_disabled.rs") - .enable_feature("disable-logging") - .build(); + #[cfg(feature = "std")] + { + substrate_wasm_builder::WasmBuilder::new() + .with_current_project() + .export_heap_base() + .import_memory() + .set_file_name("wasm_binary_logging_disabled.rs") + .enable_feature("disable-logging") + .build(); + } } diff --git a/utils/wasm-builder/README.md b/utils/wasm-builder/README.md index 547468c7ca11d..a10611cc26a00 100644 --- a/utils/wasm-builder/README.md +++ b/utils/wasm-builder/README.md @@ -8,23 +8,24 @@ The Wasm builder is a tool that integrates the process of building the WASM bina A project that should be compiled as a Wasm binary needs to: 1. Add a `build.rs` file. -2. Add `wasm-builder` as dependency into `build-dependencies`. +2. Add `wasm-builder` as dependency into `build-dependencies` (can be made optional and only enabled when `std` feature is used). The `build.rs` file needs to contain the following code: ```rust -use substrate_wasm_builder::WasmBuilder; - fn main() { - WasmBuilder::new() - // Tell the builder to build the project (crate) this `build.rs` is part of. - .with_current_project() - // Make sure to export the `heap_base` global, this is required by Substrate - .export_heap_base() - // Build the Wasm file so that it imports the memory (need to be provided by at instantiation) - .import_memory() - // Build it. - .build() + #[cfg(feature = "std")] + { + substrate_wasm_builder::WasmBuilder::new() + // Tell the builder to build the project (crate) this `build.rs` is part of. + .with_current_project() + // Make sure to export the `heap_base` global, this is required by Substrate + .export_heap_base() + // Build the Wasm file so that it imports the memory (need to be provided by at instantiation) + .import_memory() + // Build it. + .build(); + } } ``` From 4692572ecf8de0f9420972f8bf2f072243cf5a94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= <123550+andresilva@users.noreply.github.com> Date: Fri, 6 Jan 2023 11:52:38 +0000 Subject: [PATCH 262/715] grandpa: bump version to v0.16.1 (#13080) --- Cargo.lock | 4 ++-- client/finality-grandpa/Cargo.toml | 4 ++-- client/finality-grandpa/rpc/Cargo.toml | 2 +- frame/grandpa/Cargo.toml | 2 +- primitives/finality-grandpa/Cargo.toml | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a3dc04a39718f..eb644202ae382 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2028,9 +2028,9 @@ dependencies = [ [[package]] name = "finality-grandpa" -version = "0.16.0" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b22349c6a11563a202d95772a68e0fcf56119e74ea8a2a19cf2301460fcd0df5" +checksum = "e24e6c429951433ccb7c87fd528c60084834dcd14763182c1f83291bcde24c34" dependencies = [ "either", "futures", diff --git a/client/finality-grandpa/Cargo.toml b/client/finality-grandpa/Cargo.toml index b47c8032482be..95195bfc2d946 100644 --- a/client/finality-grandpa/Cargo.toml +++ b/client/finality-grandpa/Cargo.toml @@ -18,7 +18,7 @@ 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"] } +finality-grandpa = { version = "0.16.1", features = ["derive-codec"] } futures = "0.3.21" futures-timer = "3.0.1" log = "0.4.17" @@ -50,7 +50,7 @@ sp-runtime = { version = "7.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.1", features = ["derive-codec", "test-helpers"] } serde = "1.0.136" tokio = "1.22.0" sc-network = { version = "0.10.0-dev", path = "../network" } diff --git a/client/finality-grandpa/rpc/Cargo.toml b/client/finality-grandpa/rpc/Cargo.toml index 15b9d3887ba95..429331e96a65f 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.16.0", features = ["derive-codec"] } +finality-grandpa = { version = "0.16.1", features = ["derive-codec"] } futures = "0.3.16" jsonrpsee = { version = "0.16.2", features = ["client-core", "server", "macros"] } log = "0.4.8" diff --git a/frame/grandpa/Cargo.toml b/frame/grandpa/Cargo.toml index 5a85a3682db82..93dd4143af2d7 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 = "5.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] -grandpa = { package = "finality-grandpa", version = "0.16.0", features = ["derive-codec"] } +grandpa = { package = "finality-grandpa", version = "0.16.1", 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 de8de99eed891..c33646e3cd2b8 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.16.0", default-features = false, features = ["derive-codec"] } +grandpa = { package = "finality-grandpa", version = "0.16.1", default-features = false, features = ["derive-codec"] } 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 } From 19da1116ee20a062a15d64cd0e05197eb417e358 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Fri, 6 Jan 2023 21:09:57 +0100 Subject: [PATCH 263/715] Remove unused finalization_displaced variable in db (#13090) --- client/db/src/lib.rs | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index c8495c4a0252b..99fa786e04036 100644 --- a/client/db/src/lib.rs +++ b/client/db/src/lib.rs @@ -1291,14 +1291,13 @@ impl Backend { header: &Block::Header, last_finalized: Option, justification: Option, - finalization_displaced: &mut Option>>, ) -> ClientResult> { // 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); - self.note_finalized(transaction, header, hash, finalization_displaced, with_state)?; + self.note_finalized(transaction, header, hash, with_state)?; if let Some(justification) = justification { transaction.set_from_vec( @@ -1362,7 +1361,6 @@ impl Backend { fn try_commit_operation(&self, mut operation: BlockImportOperation) -> ClientResult<()> { let mut transaction = Transaction::new(); - let mut finalization_displaced_leaves = None; operation.apply_aux(&mut transaction); operation.apply_offchain(&mut transaction); @@ -1381,7 +1379,6 @@ impl Backend { &block_header, Some(last_finalized_hash), justification, - &mut finalization_displaced_leaves, )?); last_finalized_hash = block_hash; last_finalized_num = *block_header.number(); @@ -1554,13 +1551,7 @@ impl Backend { if finalized { // TODO: ensure best chain contains this block. self.ensure_sequential_finalization(header, Some(last_finalized_hash))?; - self.note_finalized( - &mut transaction, - header, - hash, - &mut finalization_displaced_leaves, - operation.commit_state, - )?; + self.note_finalized(&mut transaction, header, hash, operation.commit_state)?; } else { // canonicalize blocks which are old enough, regardless of finality. self.force_delayed_canonicalize(&mut transaction)? @@ -1692,7 +1683,6 @@ impl Backend { transaction: &mut Transaction, f_header: &Block::Header, f_hash: Block::Hash, - displaced: &mut Option>>, with_state: bool, ) -> ClientResult<()> { let f_num = *f_header.number(); @@ -1720,10 +1710,6 @@ impl Backend { let new_displaced = self.blockchain.leaves.write().finalize_height(f_num); self.prune_blocks(transaction, f_num, &new_displaced)?; - match displaced { - x @ &mut None => *x = Some(new_displaced), - &mut Some(ref mut displaced) => displaced.merge(new_displaced), - } Ok(()) } @@ -2013,7 +1999,6 @@ impl sc_client_api::backend::Backend for Backend { ) -> ClientResult<()> { let mut transaction = Transaction::new(); let header = self.blockchain.expect_header(hash)?; - let mut displaced = None; let m = self.finalize_block_with_transaction( &mut transaction, @@ -2021,8 +2006,8 @@ impl sc_client_api::backend::Backend for Backend { &header, None, justification, - &mut displaced, )?; + self.storage.db.commit(transaction)?; self.blockchain.update_meta(m); Ok(()) From e7814a35cbe506ba153fda24ebd068f4b5617854 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Sat, 7 Jan 2023 14:42:44 +0100 Subject: [PATCH 264/715] Remove unused types (#13091) Signed-off-by: Oliver Tale-Yazdi Signed-off-by: Oliver Tale-Yazdi --- frame/atomic-swap/src/tests.rs | 9 +-------- frame/aura/src/mock.rs | 5 ----- frame/authority-discovery/src/lib.rs | 2 -- frame/authorship/src/lib.rs | 6 ------ frame/babe/src/mock.rs | 5 ----- frame/collective/src/tests.rs | 2 -- frame/conviction-voting/src/tests.rs | 5 ----- frame/examples/basic/src/tests.rs | 5 ----- frame/examples/offchain-worker/src/tests.rs | 4 ---- frame/grandpa/src/mock.rs | 5 ----- frame/identity/src/tests.rs | 4 ---- frame/im-online/src/mock.rs | 5 ----- frame/indices/src/mock.rs | 10 +--------- frame/membership/src/lib.rs | 2 -- frame/message-queue/src/integration_test.rs | 4 ---- frame/message-queue/src/mock.rs | 4 ---- frame/multisig/src/tests.rs | 6 +----- frame/nicks/src/lib.rs | 6 +----- frame/offences/benchmarking/src/mock.rs | 8 -------- frame/offences/src/mock.rs | 11 +---------- frame/preimage/src/mock.rs | 14 ++------------ frame/proxy/src/tests.rs | 5 ----- frame/randomness-collective-flip/src/lib.rs | 2 -- frame/ranked-collective/src/tests.rs | 5 ----- frame/recovery/src/mock.rs | 5 ----- frame/referenda/src/mock.rs | 2 -- frame/root-offences/src/mock.rs | 5 ----- frame/scored-pool/src/mock.rs | 2 -- frame/session/src/mock.rs | 5 ----- frame/society/src/mock.rs | 2 -- frame/staking/src/mock.rs | 4 ---- frame/sudo/src/mock.rs | 11 +---------- frame/system/benches/bench.rs | 4 ---- frame/timestamp/src/mock.rs | 4 ---- frame/treasury/src/tests.rs | 4 ---- frame/vesting/src/mock.rs | 4 ---- frame/whitelist/src/mock.rs | 6 +----- 37 files changed, 9 insertions(+), 183 deletions(-) diff --git a/frame/atomic-swap/src/tests.rs b/frame/atomic-swap/src/tests.rs index 5ad63dfce55b4..081a449ec9a2e 100644 --- a/frame/atomic-swap/src/tests.rs +++ b/frame/atomic-swap/src/tests.rs @@ -3,10 +3,7 @@ use super::*; use crate as pallet_atomic_swap; -use frame_support::{ - parameter_types, - traits::{ConstU32, ConstU64}, -}; +use frame_support::traits::{ConstU32, ConstU64}; use sp_core::H256; use sp_runtime::{ testing::Header, @@ -28,10 +25,6 @@ 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)); -} impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/frame/aura/src/mock.rs b/frame/aura/src/mock.rs index 07fa9aa680e80..7a07fe99ae25d 100644 --- a/frame/aura/src/mock.rs +++ b/frame/aura/src/mock.rs @@ -46,11 +46,6 @@ 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)); -} - impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/frame/authority-discovery/src/lib.rs b/frame/authority-discovery/src/lib.rs index b642a9ac283f2..39e01dba43b2b 100644 --- a/frame/authority-discovery/src/lib.rs +++ b/frame/authority-discovery/src/lib.rs @@ -226,8 +226,6 @@ mod tests { parameter_types! { pub const Period: BlockNumber = 1; pub const Offset: BlockNumber = 0; - 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 { diff --git a/frame/authorship/src/lib.rs b/frame/authorship/src/lib.rs index a40f32d36c265..4065472d92368 100644 --- a/frame/authorship/src/lib.rs +++ b/frame/authorship/src/lib.rs @@ -434,7 +434,6 @@ mod tests { use super::*; use crate as pallet_authorship; use frame_support::{ - parameter_types, traits::{ConstU32, ConstU64, OnFinalize, OnInitialize}, ConsensusEngineId, }; @@ -459,11 +458,6 @@ mod tests { } ); - 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 = (); diff --git a/frame/babe/src/mock.rs b/frame/babe/src/mock.rs index dbeb588c1830e..abae1b7e33157 100644 --- a/frame/babe/src/mock.rs +++ b/frame/babe/src/mock.rs @@ -64,11 +64,6 @@ 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)); -} - impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/frame/collective/src/tests.rs b/frame/collective/src/tests.rs index 648b6f88ec86c..5c90de9f91bf7 100644 --- a/frame/collective/src/tests.rs +++ b/frame/collective/src/tests.rs @@ -91,8 +91,6 @@ pub type MaxMembers = ConstU32<100>; parameter_types! { pub const MotionDuration: u64 = 3; 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)); } impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; diff --git a/frame/conviction-voting/src/tests.rs b/frame/conviction-voting/src/tests.rs index d20dcb66d6198..9caa451e0dae8 100644 --- a/frame/conviction-voting/src/tests.rs +++ b/frame/conviction-voting/src/tests.rs @@ -22,7 +22,6 @@ 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::{ @@ -56,10 +55,6 @@ 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)); -} impl frame_system::Config for Test { type BaseCallFilter = BaseFilter; type BlockWeights = (); diff --git a/frame/examples/basic/src/tests.rs b/frame/examples/basic/src/tests.rs index 97fbddfbc41e0..891c7c78628a1 100644 --- a/frame/examples/basic/src/tests.rs +++ b/frame/examples/basic/src/tests.rs @@ -21,7 +21,6 @@ use crate::*; use frame_support::{ assert_ok, dispatch::{DispatchInfo, GetDispatchInfo}, - parameter_types, traits::{ConstU64, OnInitialize}, }; use sp_core::H256; @@ -51,10 +50,6 @@ 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)); -} impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/frame/examples/offchain-worker/src/tests.rs b/frame/examples/offchain-worker/src/tests.rs index 72c001fd6e6cc..2050d76a241ff 100644 --- a/frame/examples/offchain-worker/src/tests.rs +++ b/frame/examples/offchain-worker/src/tests.rs @@ -51,10 +51,6 @@ 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)); -} impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/frame/grandpa/src/mock.rs b/frame/grandpa/src/mock.rs index 131f6cafcd179..c618705af0651 100644 --- a/frame/grandpa/src/mock.rs +++ b/frame/grandpa/src/mock.rs @@ -69,11 +69,6 @@ impl_opaque_keys! { } } -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 = (); diff --git a/frame/identity/src/tests.rs b/frame/identity/src/tests.rs index 6b0006971f0e6..baca70e2795fc 100644 --- a/frame/identity/src/tests.rs +++ b/frame/identity/src/tests.rs @@ -48,10 +48,6 @@ 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)); -} impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/frame/im-online/src/mock.rs b/frame/im-online/src/mock.rs index 5782e1a615b8e..bcb13fa1be837 100644 --- a/frame/im-online/src/mock.rs +++ b/frame/im-online/src/mock.rs @@ -117,11 +117,6 @@ pub fn new_test_ext() -> sp_io::TestExternalities { result } -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 Runtime { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/frame/indices/src/mock.rs b/frame/indices/src/mock.rs index fd2e9fff16885..6b5373bb43b5a 100644 --- a/frame/indices/src/mock.rs +++ b/frame/indices/src/mock.rs @@ -20,10 +20,7 @@ #![cfg(test)] use crate::{self as pallet_indices, Config}; -use frame_support::{ - parameter_types, - traits::{ConstU32, ConstU64}, -}; +use frame_support::traits::{ConstU32, ConstU64}; use sp_core::H256; use sp_runtime::testing::Header; @@ -42,11 +39,6 @@ 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)); -} - impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/frame/membership/src/lib.rs b/frame/membership/src/lib.rs index 77b53aa72dad8..8531af120ec88 100644 --- a/frame/membership/src/lib.rs +++ b/frame/membership/src/lib.rs @@ -539,8 +539,6 @@ mod tests { ); parameter_types! { - pub BlockWeights: frame_system::limits::BlockWeights = - 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/message-queue/src/integration_test.rs b/frame/message-queue/src/integration_test.rs index f4b1b7a125449..c9e3b2e870fd8 100644 --- a/frame/message-queue/src/integration_test.rs +++ b/frame/message-queue/src/integration_test.rs @@ -54,10 +54,6 @@ 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)); -} impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/frame/message-queue/src/mock.rs b/frame/message-queue/src/mock.rs index 7159840d1c01b..37e504ac50033 100644 --- a/frame/message-queue/src/mock.rs +++ b/frame/message-queue/src/mock.rs @@ -47,10 +47,6 @@ frame_support::construct_runtime!( 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 = (); diff --git a/frame/multisig/src/tests.rs b/frame/multisig/src/tests.rs index 206e566cf4cb6..13493587caa2b 100644 --- a/frame/multisig/src/tests.rs +++ b/frame/multisig/src/tests.rs @@ -23,7 +23,7 @@ use super::*; use crate as pallet_multisig; use frame_support::{ - assert_noop, assert_ok, parameter_types, + assert_noop, assert_ok, traits::{ConstU32, ConstU64, Contains}, }; use sp_core::H256; @@ -47,10 +47,6 @@ 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)); -} impl frame_system::Config for Test { type BaseCallFilter = TestBaseCallFilter; type BlockWeights = (); diff --git a/frame/nicks/src/lib.rs b/frame/nicks/src/lib.rs index 79daeb9bdb9a8..3d8307c434107 100644 --- a/frame/nicks/src/lib.rs +++ b/frame/nicks/src/lib.rs @@ -250,7 +250,7 @@ mod tests { use crate as pallet_nicks; use frame_support::{ - assert_noop, assert_ok, ord_parameter_types, parameter_types, + assert_noop, assert_ok, ord_parameter_types, traits::{ConstU32, ConstU64}, }; use frame_system::EnsureSignedBy; @@ -275,10 +275,6 @@ mod tests { } ); - 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 = (); diff --git a/frame/offences/benchmarking/src/mock.rs b/frame/offences/benchmarking/src/mock.rs index 223f551a6e5c1..592e821a81d8c 100644 --- a/frame/offences/benchmarking/src/mock.rs +++ b/frame/offences/benchmarking/src/mock.rs @@ -24,7 +24,6 @@ use frame_election_provider_support::{onchain, SequentialPhragmen}; use frame_support::{ parameter_types, traits::{ConstU32, ConstU64}, - weights::{constants::WEIGHT_REF_TIME_PER_SECOND, Weight}, }; use frame_system as system; use pallet_session::historical as pallet_session_historical; @@ -38,13 +37,6 @@ type AccountIndex = u32; type BlockNumber = u64; type Balance = u64; -parameter_types! { - pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max( - Weight::from_parts(2u64 * WEIGHT_REF_TIME_PER_SECOND, u64::MAX) - ); -} - impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/frame/offences/src/mock.rs b/frame/offences/src/mock.rs index 8e4256ec3d3e6..63d2b0de34780 100644 --- a/frame/offences/src/mock.rs +++ b/frame/offences/src/mock.rs @@ -25,10 +25,7 @@ use codec::Encode; use frame_support::{ parameter_types, traits::{ConstU32, ConstU64}, - weights::{ - constants::{RocksDbWeight, WEIGHT_REF_TIME_PER_SECOND}, - Weight, - }, + weights::{constants::RocksDbWeight, Weight}, }; use sp_core::H256; use sp_runtime::{ @@ -83,12 +80,6 @@ frame_support::construct_runtime!( } ); -parameter_types! { - pub BlockWeights: frame_system::limits::BlockWeights = - 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; type BlockWeights = (); diff --git a/frame/preimage/src/mock.rs b/frame/preimage/src/mock.rs index ce74ea65bd8aa..d81f5a9c3232c 100644 --- a/frame/preimage/src/mock.rs +++ b/frame/preimage/src/mock.rs @@ -15,13 +15,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! # Scheduler test environment. +//! # Preimage test environment. use super::*; use crate as pallet_preimage; use frame_support::{ - ord_parameter_types, parameter_types, + ord_parameter_types, traits::{ConstU32, ConstU64, Everything}, weights::constants::RocksDbWeight, }; @@ -30,7 +30,6 @@ use sp_core::H256; use sp_runtime::{ testing::Header, traits::{BlakeTwo256, IdentityLookup}, - Perbill, }; type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; @@ -48,10 +47,6 @@ frame_support::construct_runtime!( } ); -parameter_types! { - pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(Weight::from_ref_time(2_000_000_000_000)); -} impl frame_system::Config for Test { type BaseCallFilter = Everything; type BlockWeights = (); @@ -91,11 +86,6 @@ impl pallet_balances::Config for Test { type ReserveIdentifier = [u8; 8]; } -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; } diff --git a/frame/proxy/src/tests.rs b/frame/proxy/src/tests.rs index 17bc7bcb92ee1..3eb3ab3705332 100644 --- a/frame/proxy/src/tests.rs +++ b/frame/proxy/src/tests.rs @@ -26,7 +26,6 @@ use codec::{Decode, Encode}; use frame_support::{ assert_noop, assert_ok, dispatch::DispatchError, - parameter_types, traits::{ConstU32, ConstU64, Contains}, RuntimeDebug, }; @@ -52,10 +51,6 @@ 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)); -} impl frame_system::Config for Test { type BaseCallFilter = BaseFilter; type BlockWeights = (); diff --git a/frame/randomness-collective-flip/src/lib.rs b/frame/randomness-collective-flip/src/lib.rs index be970ba2a8422..d92b053655dc9 100644 --- a/frame/randomness-collective-flip/src/lib.rs +++ b/frame/randomness-collective-flip/src/lib.rs @@ -186,8 +186,6 @@ mod tests { ); parameter_types! { - pub BlockWeights: limits::BlockWeights = limits::BlockWeights - ::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 68bb79f3d07f7..c11d4877d3577 100644 --- a/frame/ranked-collective/src/tests.rs +++ b/frame/ranked-collective/src/tests.rs @@ -22,7 +22,6 @@ 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}, }; @@ -49,10 +48,6 @@ frame_support::construct_runtime!( } ); -parameter_types! { - pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(Weight::from_ref_time(1_000_000)); -} impl frame_system::Config for Test { type BaseCallFilter = Everything; type BlockWeights = (); diff --git a/frame/recovery/src/mock.rs b/frame/recovery/src/mock.rs index 2a29390fdd20f..05ca8e6a30a0e 100644 --- a/frame/recovery/src/mock.rs +++ b/frame/recovery/src/mock.rs @@ -45,11 +45,6 @@ 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)); -} - impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/frame/referenda/src/mock.rs b/frame/referenda/src/mock.rs index c98fbf9a676b1..e957027e561ab 100644 --- a/frame/referenda/src/mock.rs +++ b/frame/referenda/src/mock.rs @@ -63,8 +63,6 @@ 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(MaxWeight::get()); } impl frame_system::Config for Test { type BaseCallFilter = BaseFilter; diff --git a/frame/root-offences/src/mock.rs b/frame/root-offences/src/mock.rs index e1d9ee14ee2fc..273fbf614169d 100644 --- a/frame/root-offences/src/mock.rs +++ b/frame/root-offences/src/mock.rs @@ -84,11 +84,6 @@ 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 = (); diff --git a/frame/scored-pool/src/mock.rs b/frame/scored-pool/src/mock.rs index d6f653b32ad2d..951871dd83c5c 100644 --- a/frame/scored-pool/src/mock.rs +++ b/frame/scored-pool/src/mock.rs @@ -48,8 +48,6 @@ construct_runtime!( parameter_types! { pub const CandidateDeposit: u64 = 25; - pub BlockWeights: frame_system::limits::BlockWeights = - 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/mock.rs b/frame/session/src/mock.rs index aa13eacba9564..1138bd9543989 100644 --- a/frame/session/src/mock.rs +++ b/frame/session/src/mock.rs @@ -238,11 +238,6 @@ pub fn new_test_ext() -> sp_io::TestExternalities { sp_io::TestExternalities::new(t) } -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 = (); diff --git a/frame/society/src/mock.rs b/frame/society/src/mock.rs index 0b1b93aeae761..24544bf9e82dd 100644 --- a/frame/society/src/mock.rs +++ b/frame/society/src/mock.rs @@ -49,8 +49,6 @@ 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(frame_support::weights::Weight::from_ref_time(1024)); } ord_parameter_types! { diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index 843e452125a6e..ad27a82910a6f 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -114,10 +114,6 @@ impl FindAuthor for Author11 { } parameter_types! { - pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max( - 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; pub static SlashDeferDuration: EraIndex = 0; diff --git a/frame/sudo/src/mock.rs b/frame/sudo/src/mock.rs index 639e81ceaa308..f8a03836f8f0f 100644 --- a/frame/sudo/src/mock.rs +++ b/frame/sudo/src/mock.rs @@ -19,12 +19,7 @@ use super::*; use crate as sudo; -use frame_support::{ - parameter_types, - traits::{ConstU32, ConstU64, Contains, GenesisBuild}, - weights::Weight, -}; -use frame_system::limits; +use frame_support::traits::{ConstU32, ConstU64, Contains, GenesisBuild}; use sp_core::H256; use sp_io; use sp_runtime::{ @@ -111,10 +106,6 @@ frame_support::construct_runtime!( } ); -parameter_types! { - pub BlockWeights: limits::BlockWeights = limits::BlockWeights::simple_max(Weight::from_ref_time(1024)); -} - pub struct BlockEverything; impl Contains for BlockEverything { fn contains(_: &RuntimeCall) -> bool { diff --git a/frame/system/benches/bench.rs b/frame/system/benches/bench.rs index 0881b81eaca7d..a623a17dc49b2 100644 --- a/frame/system/benches/bench.rs +++ b/frame/system/benches/bench.rs @@ -62,10 +62,6 @@ frame_support::construct_runtime!( ); frame_support::parameter_types! { - pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::with_sensible_defaults( - 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( 4 * 1024 * 1024, Perbill::from_percent(75), diff --git a/frame/timestamp/src/mock.rs b/frame/timestamp/src/mock.rs index 2208510f24fe5..e1ba5cd11e615 100644 --- a/frame/timestamp/src/mock.rs +++ b/frame/timestamp/src/mock.rs @@ -46,10 +46,6 @@ 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)); -} impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/frame/treasury/src/tests.rs b/frame/treasury/src/tests.rs index 9cfe147ec4ce4..e6a1ea0f543fe 100644 --- a/frame/treasury/src/tests.rs +++ b/frame/treasury/src/tests.rs @@ -51,10 +51,6 @@ 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)); -} impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/frame/vesting/src/mock.rs b/frame/vesting/src/mock.rs index 0bd371a0353f1..da9490bea66c0 100644 --- a/frame/vesting/src/mock.rs +++ b/frame/vesting/src/mock.rs @@ -43,10 +43,6 @@ 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)); -} impl frame_system::Config for Test { type AccountData = pallet_balances::AccountData; type AccountId = u64; diff --git a/frame/whitelist/src/mock.rs b/frame/whitelist/src/mock.rs index ef5d3d4fb4d34..e08c2875aec51 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::{ - construct_runtime, parameter_types, + construct_runtime, traits::{ConstU32, ConstU64, Nothing}, }; use frame_system::EnsureRoot; @@ -49,10 +49,6 @@ construct_runtime!( } ); -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 = Nothing; type BlockWeights = (); From 5cbd12605e2ef0882e9cd4de5149619f55954bd4 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Sun, 8 Jan 2023 18:03:51 +0100 Subject: [PATCH 265/715] Run `frame_system` integrity tests in Externalities (#13092) * Run frame_system integrity tests in Externalities Signed-off-by: Oliver Tale-Yazdi * Use feature = 'std' Signed-off-by: Oliver Tale-Yazdi Signed-off-by: Oliver Tale-Yazdi --- frame/system/src/lib.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index a77d1ca31b50f..c790d33adddd7 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -360,8 +360,11 @@ pub mod pallet { #[pallet::hooks] impl Hooks> for Pallet { + #[cfg(feature = "std")] fn integrity_test() { - T::BlockWeights::get().validate().expect("The weights are invalid."); + sp_io::TestExternalities::default().execute_with(|| { + T::BlockWeights::get().validate().expect("The weights are invalid."); + }); } } From 911f65be7949342e12601cc3015d5c47e9339de4 Mon Sep 17 00:00:00 2001 From: Ankan <10196091+Ank4n@users.noreply.github.com> Date: Mon, 9 Jan 2023 08:33:29 +0100 Subject: [PATCH 266/715] add note on usage of twox hash (#13089) --- frame/fast-unstake/src/lib.rs | 2 ++ frame/nomination-pools/src/lib.rs | 2 ++ frame/staking/src/pallet/mod.rs | 8 ++++++++ 3 files changed, 12 insertions(+) diff --git a/frame/fast-unstake/src/lib.rs b/frame/fast-unstake/src/lib.rs index f2faeebc13478..c0bffc4427a11 100644 --- a/frame/fast-unstake/src/lib.rs +++ b/frame/fast-unstake/src/lib.rs @@ -147,6 +147,8 @@ pub mod pallet { /// The map of all accounts wishing to be unstaked. /// /// Keeps track of `AccountId` wishing to unstake and it's corresponding deposit. + /// + /// TWOX-NOTE: SAFE since `AccountId` is a secure hash. #[pallet::storage] pub type Queue = CountedStorageMap<_, Twox64Concat, T::AccountId, BalanceOf>; diff --git a/frame/nomination-pools/src/lib.rs b/frame/nomination-pools/src/lib.rs index 99bfc8b8c36a5..3cb8abedda2fb 100644 --- a/frame/nomination-pools/src/lib.rs +++ b/frame/nomination-pools/src/lib.rs @@ -1277,6 +1277,8 @@ pub mod pallet { pub type MaxPoolMembersPerPool = StorageValue<_, u32, OptionQuery>; /// Active members. + /// + /// TWOX-NOTE: SAFE since `AccountId` is a secure hash. #[pallet::storage] pub type PoolMembers = CountedStorageMap<_, Twox64Concat, T::AccountId, PoolMember>; diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 92502949ef1a0..ce4f2494621b4 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -292,6 +292,8 @@ pub mod pallet { pub type Invulnerables = StorageValue<_, Vec, ValueQuery>; /// Map from all locked "stash" accounts to the controller account. + /// + /// TWOX-NOTE: SAFE since `AccountId` is a secure hash. #[pallet::storage] #[pallet::getter(fn bonded)] pub type Bonded = StorageMap<_, Twox64Concat, T::AccountId, T::AccountId>; @@ -320,12 +322,16 @@ pub mod pallet { pub type Ledger = StorageMap<_, Blake2_128Concat, T::AccountId, StakingLedger>; /// Where the reward payment should be made. Keyed by stash. + /// + /// TWOX-NOTE: SAFE since `AccountId` is a secure hash. #[pallet::storage] #[pallet::getter(fn payee)] pub type Payee = StorageMap<_, Twox64Concat, T::AccountId, RewardDestination, ValueQuery>; /// The map from (wannabe) validator stash key to the preferences of that validator. + /// + /// TWOX-NOTE: SAFE since `AccountId` is a secure hash. #[pallet::storage] #[pallet::getter(fn validators)] pub type Validators = @@ -353,6 +359,8 @@ pub mod pallet { /// /// Lastly, if any of the nominators become non-decodable, they can be chilled immediately via /// [`Call::chill_other`] dispatchable by anyone. + /// + /// TWOX-NOTE: SAFE since `AccountId` is a secure hash. #[pallet::storage] #[pallet::getter(fn nominators)] pub type Nominators = From f31588b6e5e3f0dac4b0142002dbe18deb5bda59 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Mon, 9 Jan 2023 14:46:09 +0100 Subject: [PATCH 267/715] Remove unused code in state-db (#13103) --- client/state-db/src/noncanonical.rs | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/client/state-db/src/noncanonical.rs b/client/state-db/src/noncanonical.rs index b7eec8ab60ee0..e950d245dcec9 100644 --- a/client/state-db/src/noncanonical.rs +++ b/client/state-db/src/noncanonical.rs @@ -323,7 +323,6 @@ impl NonCanonicalOverlay { &self, level_index: usize, discarded_journals: &mut Vec>, - discarded_blocks: &mut Vec, hash: &BlockHash, ) { if let Some(level) = self.levels.get(level_index) { @@ -335,13 +334,7 @@ impl NonCanonicalOverlay { .clone(); if parent == *hash { discarded_journals.push(overlay.journal_key.clone()); - discarded_blocks.push(overlay.hash.clone()); - self.discard_journals( - level_index + 1, - discarded_journals, - discarded_blocks, - &overlay.hash, - ); + self.discard_journals(level_index + 1, discarded_journals, &overlay.hash); } }); } @@ -393,7 +386,6 @@ impl NonCanonicalOverlay { self.pinned_canonincalized.push(hash.clone()); let mut discarded_journals = Vec::new(); - let mut discarded_blocks = Vec::new(); for (i, overlay) in level.blocks.into_iter().enumerate() { let mut pinned_children = 0; // That's the one we need to canonicalize @@ -411,12 +403,7 @@ impl NonCanonicalOverlay { commit.data.deleted.extend(overlay.deleted.clone()); } else { // Discard this overlay - self.discard_journals( - 0, - &mut discarded_journals, - &mut discarded_blocks, - &overlay.hash, - ); + self.discard_journals(0, &mut discarded_journals, &overlay.hash); pinned_children = discard_descendants( &mut self.levels.as_mut_slices(), &mut self.values, @@ -437,7 +424,6 @@ impl NonCanonicalOverlay { discard_values(&mut self.values, overlay.inserted); } discarded_journals.push(overlay.journal_key.clone()); - discarded_blocks.push(overlay.hash.clone()); } commit.meta.deleted.append(&mut discarded_journals); @@ -548,9 +534,6 @@ impl NonCanonicalOverlay { trace!(target: "state-db-pin", "Discarding unpinned non-canon block: {:?}", hash); discard_values(&mut self.values, inserted); self.parents.remove(&hash); - true - } else { - false } }, Entry::Vacant(_) => break, From 6c7e94127c5f5f8f44b81536a6105d0e1a0d9276 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Mon, 9 Jan 2023 16:06:47 +0000 Subject: [PATCH 268/715] EPM and staking events improvement (#13035) * EPM and staking events improvement * Uses RawOrigin in ElectionCompute event * Refactors new phase events to PhaseTransition event * PhaseTransitioned and remove RawOrigin from event * Adds helpers for epm phase transition and staking force new * addresses review comments * nit: removes unecessary clone * fixes benchmarks Co-authored-by: parity-processbot <> --- .../src/benchmarking.rs | 7 +- .../election-provider-multi-phase/src/lib.rs | 281 +++++++++++++----- .../src/signed.rs | 128 ++++++-- .../src/unsigned.rs | 30 +- frame/staking/src/pallet/impls.rs | 11 +- frame/staking/src/pallet/mod.rs | 8 +- frame/staking/src/tests.rs | 28 +- 7 files changed, 369 insertions(+), 124 deletions(-) diff --git a/frame/election-provider-multi-phase/src/benchmarking.rs b/frame/election-provider-multi-phase/src/benchmarking.rs index 10041f6aec07c..16263d97da586 100644 --- a/frame/election-provider-multi-phase/src/benchmarking.rs +++ b/frame/election-provider-multi-phase/src/benchmarking.rs @@ -200,7 +200,7 @@ frame_benchmarking::benchmarks! { assert!(>::snapshot().is_none()); assert!(>::current_phase().is_off()); }: { - >::on_initialize_open_signed(); + >::phase_transition(Phase::Signed); } verify { assert!(>::snapshot().is_none()); assert!(>::current_phase().is_signed()); @@ -210,7 +210,8 @@ frame_benchmarking::benchmarks! { assert!(>::snapshot().is_none()); assert!(>::current_phase().is_off()); }: { - >::on_initialize_open_unsigned(true, 1u32.into()) + let now = frame_system::Pallet::::block_number(); + >::phase_transition(Phase::Unsigned((true, now))); } verify { assert!(>::snapshot().is_none()); assert!(>::current_phase().is_unsigned()); @@ -318,7 +319,7 @@ frame_benchmarking::benchmarks! { submit { // the queue is full and the solution is only better than the worse. >::create_snapshot().map_err(<&str>::from)?; - MultiPhase::::on_initialize_open_signed(); + >::phase_transition(Phase::Signed); >::put(1); let mut signed_submissions = SignedSubmissions::::get(); diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index 6c4a55800f7e8..6c1b1d163d0fb 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -758,7 +758,7 @@ pub mod pallet { // NOTE: if signed-phase length is zero, second part of the if-condition fails. match Self::create_snapshot() { Ok(_) => { - Self::on_initialize_open_signed(); + Self::phase_transition(Phase::Signed); T::WeightInfo::on_initialize_open_signed() }, Err(why) => { @@ -797,7 +797,7 @@ pub mod pallet { if need_snapshot { match Self::create_snapshot() { Ok(_) => { - Self::on_initialize_open_unsigned(enabled, now); + Self::phase_transition(Phase::Unsigned((enabled, now))); T::WeightInfo::on_initialize_open_unsigned() }, Err(why) => { @@ -806,7 +806,7 @@ pub mod pallet { }, } } else { - Self::on_initialize_open_unsigned(enabled, now); + Self::phase_transition(Phase::Unsigned((enabled, now))); T::WeightInfo::on_initialize_open_unsigned() } }, @@ -931,6 +931,7 @@ pub mod pallet { >::put(ready); Self::deposit_event(Event::SolutionStored { compute: ElectionCompute::Unsigned, + origin: None, prev_ejected: ejected_a_solution, }); @@ -983,6 +984,7 @@ pub mod pallet { Self::deposit_event(Event::SolutionStored { compute: ElectionCompute::Emergency, + origin: None, prev_ejected: QueuedSolution::::exists(), }); @@ -1060,6 +1062,7 @@ pub mod pallet { signed_submissions.put(); Self::deposit_event(Event::SolutionStored { compute: ElectionCompute::Signed, + origin: Some(who), prev_ejected: ejected_a_solution, }); Ok(()) @@ -1102,6 +1105,7 @@ pub mod pallet { Self::deposit_event(Event::SolutionStored { compute: ElectionCompute::Fallback, + origin: None, prev_ejected: QueuedSolution::::exists(), }); @@ -1115,11 +1119,16 @@ pub mod pallet { pub enum Event { /// A solution was stored with the given compute. /// - /// If the solution is signed, this means that it hasn't yet been processed. If the - /// 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 { compute: ElectionCompute, prev_ejected: bool }, + /// The `origin` indicates the origin of the solution. If `origin` is `Some(AccountId)`, + /// the stored solution was submited in the signed phase by a miner with the `AccountId`. + /// Otherwise, the solution was stored either during the unsigned phase or by + /// `T::ForceOrigin`. The `bool` is `true` when a previous solution was ejected to make + /// room for this one. + SolutionStored { + compute: ElectionCompute, + origin: Option, + prev_ejected: bool, + }, /// The election has been finalized, with the given computation and score. ElectionFinalized { compute: ElectionCompute, score: ElectionScore }, /// An election failed. @@ -1130,10 +1139,8 @@ pub mod pallet { Rewarded { account: ::AccountId, value: BalanceOf }, /// An account has been slashed for submitting an invalid signed submission. Slashed { account: ::AccountId, value: BalanceOf }, - /// The signed phase of the given round has started. - SignedPhaseStarted { round: u32 }, - /// The unsigned phase of the given round has started. - UnsignedPhaseStarted { round: u32 }, + /// There was a phase transition in a given round. + PhaseTransitioned { from: Phase, to: Phase, round: u32 }, } /// Error of the pallet that can be returned in response to dispatches. @@ -1349,19 +1356,15 @@ impl Pallet { } } - /// 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. - pub fn on_initialize_open_unsigned(enabled: bool, now: T::BlockNumber) { - let round = Self::round(); - log!(info, "Starting unsigned phase round {} enabled {}.", round, enabled); - >::put(Phase::Unsigned((enabled, now))); - Self::deposit_event(Event::UnsignedPhaseStarted { round }); + /// Phase transition helper. + pub(crate) fn phase_transition(to: Phase) { + log!(info, "Starting phase {:?}, round {}.", to, Self::round()); + Self::deposit_event(Event::PhaseTransitioned { + from: >::get(), + to, + round: Self::round(), + }); + >::put(to); } /// Parts of [`create_snapshot`] that happen inside of this pallet. @@ -1571,7 +1574,7 @@ impl Pallet { >::mutate(|r| *r += 1); // Phase is off now. - >::put(Phase::Off); + Self::phase_transition(Phase::Off); // Kill snapshots. Self::kill_snapshot(); @@ -1652,7 +1655,7 @@ impl ElectionProvider for Pallet { }, Err(why) => { log!(error, "Entering emergency mode: {:?}", why); - >::put(Phase::Emergency); + Self::phase_transition(Phase::Emergency); Err(why) }, } @@ -1898,7 +1901,10 @@ mod tests { roll_to_signed(); assert_eq!(MultiPhase::current_phase(), Phase::Signed); - assert_eq!(multi_phase_events(), vec![Event::SignedPhaseStarted { round: 1 }]); + assert_eq!( + multi_phase_events(), + vec![Event::PhaseTransitioned { from: Phase::Off, to: Phase::Signed, round: 1 }] + ); assert!(MultiPhase::snapshot().is_some()); assert_eq!(MultiPhase::round(), 1); @@ -1912,8 +1918,12 @@ mod tests { assert_eq!( multi_phase_events(), vec![ - Event::SignedPhaseStarted { round: 1 }, - Event::UnsignedPhaseStarted { round: 1 } + Event::PhaseTransitioned { from: Phase::Off, to: Phase::Signed, round: 1 }, + Event::PhaseTransitioned { + from: Phase::Signed, + to: Phase::Unsigned((true, 25)), + round: 1 + }, ], ); assert!(MultiPhase::snapshot().is_some()); @@ -1949,8 +1959,12 @@ mod tests { assert_eq!( multi_phase_events(), vec![ - Event::SignedPhaseStarted { round: 1 }, - Event::UnsignedPhaseStarted { round: 1 }, + Event::PhaseTransitioned { from: Phase::Off, to: Phase::Signed, round: 1 }, + Event::PhaseTransitioned { + from: Phase::Signed, + to: Phase::Unsigned((true, 25)), + round: 1 + }, Event::ElectionFinalized { compute: ElectionCompute::Fallback, score: ElectionScore { @@ -1959,8 +1973,17 @@ mod tests { sum_stake_squared: 0 } }, - Event::SignedPhaseStarted { round: 2 }, - Event::UnsignedPhaseStarted { round: 2 } + Event::PhaseTransitioned { + from: Phase::Unsigned((true, 25)), + to: Phase::Off, + round: 2 + }, + Event::PhaseTransitioned { from: Phase::Off, to: Phase::Signed, round: 2 }, + Event::PhaseTransitioned { + from: Phase::Signed, + to: Phase::Unsigned((true, 55)), + round: 2 + }, ] ); }) @@ -1990,7 +2013,11 @@ mod tests { assert_eq!( multi_phase_events(), vec![ - Event::UnsignedPhaseStarted { round: 1 }, + Event::PhaseTransitioned { + from: Phase::Off, + to: Phase::Unsigned((true, 20)), + round: 1 + }, Event::ElectionFinalized { compute: ElectionCompute::Fallback, score: ElectionScore { @@ -1998,7 +2025,12 @@ mod tests { sum_stake: 0, sum_stake_squared: 0 } - } + }, + Event::PhaseTransitioned { + from: Phase::Unsigned((true, 20)), + to: Phase::Off, + round: 2 + }, ] ); }); @@ -2028,7 +2060,7 @@ mod tests { assert_eq!( multi_phase_events(), vec![ - Event::SignedPhaseStarted { round: 1 }, + Event::PhaseTransitioned { from: Phase::Off, to: Phase::Signed, round: 1 }, Event::ElectionFinalized { compute: ElectionCompute::Fallback, score: ElectionScore { @@ -2036,7 +2068,8 @@ mod tests { sum_stake: 0, sum_stake_squared: 0 } - } + }, + Event::PhaseTransitioned { from: Phase::Signed, to: Phase::Off, round: 2 }, ] ) }); @@ -2064,10 +2097,17 @@ mod tests { assert_eq!( multi_phase_events(), - vec![Event::ElectionFinalized { - compute: ElectionCompute::Fallback, - score: ElectionScore { minimal_stake: 0, sum_stake: 0, sum_stake_squared: 0 } - }] + vec![ + Event::ElectionFinalized { + compute: ElectionCompute::Fallback, + score: ElectionScore { + minimal_stake: 0, + sum_stake: 0, + sum_stake_squared: 0 + } + }, + Event::PhaseTransitioned { from: Phase::Off, to: Phase::Off, round: 2 }, + ] ); }); } @@ -2079,7 +2119,10 @@ mod tests { // Signed phase started at block 15 and will end at 25. roll_to_signed(); - assert_eq!(multi_phase_events(), vec![Event::SignedPhaseStarted { round: 1 }]); + assert_eq!( + multi_phase_events(), + vec![Event::PhaseTransitioned { from: Phase::Off, to: Phase::Signed, round: 1 }] + ); assert_eq!(MultiPhase::current_phase(), Phase::Signed); assert_eq!(MultiPhase::round(), 1); @@ -2090,11 +2133,12 @@ mod tests { assert_eq!( multi_phase_events(), vec![ - Event::SignedPhaseStarted { round: 1 }, + Event::PhaseTransitioned { from: Phase::Off, to: Phase::Signed, round: 1 }, Event::ElectionFinalized { compute: ElectionCompute::Fallback, score: Default::default() - } + }, + Event::PhaseTransitioned { from: Phase::Signed, to: Phase::Off, round: 2 }, ], ); // All storage items must be cleared. @@ -2114,7 +2158,10 @@ mod tests { // signed phase started at block 15 and will end at 25. roll_to_signed(); - assert_eq!(multi_phase_events(), vec![Event::SignedPhaseStarted { round: 1 }]); + assert_eq!( + multi_phase_events(), + vec![Event::PhaseTransitioned { from: Phase::Off, to: Phase::Signed, round: 1 }] + ); assert_eq!(MultiPhase::current_phase(), Phase::Signed); assert_eq!(MultiPhase::round(), 1); @@ -2144,12 +2191,32 @@ mod tests { 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::PhaseTransitioned { from: Phase::Off, to: Phase::Signed, round: 1 }, + Event::SolutionStored { + compute: ElectionCompute::Signed, + origin: Some(99), + prev_ejected: false + }, + Event::SolutionStored { + compute: ElectionCompute::Signed, + origin: Some(99), + prev_ejected: false + }, + Event::SolutionStored { + compute: ElectionCompute::Signed, + origin: Some(99), + prev_ejected: false + }, + Event::SolutionStored { + compute: ElectionCompute::Signed, + origin: Some(99), + prev_ejected: false + }, + Event::SolutionStored { + compute: ElectionCompute::Signed, + origin: Some(99), + prev_ejected: false + }, Event::Slashed { account: 99, value: 5 }, Event::Slashed { account: 99, value: 5 }, Event::Slashed { account: 99, value: 5 }, @@ -2162,7 +2229,8 @@ mod tests { sum_stake: 0, sum_stake_squared: 0 } - } + }, + Event::PhaseTransitioned { from: Phase::Signed, to: Phase::Off, round: 2 }, ] ); }) @@ -2186,10 +2254,18 @@ mod tests { assert_eq!( multi_phase_events(), vec![ - Event::SignedPhaseStarted { round: 1 }, - Event::SolutionStored { compute: ElectionCompute::Signed, prev_ejected: false }, + Event::PhaseTransitioned { from: Phase::Off, to: Phase::Signed, round: 1 }, + Event::SolutionStored { + compute: ElectionCompute::Signed, + origin: Some(99), + prev_ejected: false + }, Event::Rewarded { account: 99, value: 7 }, - Event::UnsignedPhaseStarted { round: 1 }, + Event::PhaseTransitioned { + from: Phase::Signed, + to: Phase::Unsigned((true, 25)), + round: 1 + }, Event::ElectionFinalized { compute: ElectionCompute::Signed, score: ElectionScore { @@ -2197,7 +2273,12 @@ mod tests { sum_stake: 100, sum_stake_squared: 5200 } - } + }, + Event::PhaseTransitioned { + from: Phase::Unsigned((true, 25)), + to: Phase::Off, + round: 2 + }, ], ); }) @@ -2230,10 +2311,15 @@ mod tests { assert_eq!( multi_phase_events(), vec![ - Event::SignedPhaseStarted { round: 1 }, - Event::UnsignedPhaseStarted { round: 1 }, + Event::PhaseTransitioned { from: Phase::Off, to: Phase::Signed, round: 1 }, + Event::PhaseTransitioned { + from: Phase::Signed, + to: Phase::Unsigned((true, 25)), + round: 1 + }, Event::SolutionStored { compute: ElectionCompute::Unsigned, + origin: None, prev_ejected: false }, Event::ElectionFinalized { @@ -2243,7 +2329,12 @@ mod tests { sum_stake: 100, sum_stake_squared: 5200 } - } + }, + Event::PhaseTransitioned { + from: Phase::Unsigned((true, 25)), + to: Phase::Off, + round: 2 + }, ], ); }) @@ -2270,8 +2361,12 @@ mod tests { assert_eq!( multi_phase_events(), vec![ - Event::SignedPhaseStarted { round: 1 }, - Event::UnsignedPhaseStarted { round: 1 }, + Event::PhaseTransitioned { from: Phase::Off, to: Phase::Signed, round: 1 }, + Event::PhaseTransitioned { + from: Phase::Signed, + to: Phase::Unsigned((true, 25)), + round: 1 + }, Event::ElectionFinalized { compute: ElectionCompute::Fallback, score: ElectionScore { @@ -2279,7 +2374,12 @@ mod tests { sum_stake: 0, sum_stake_squared: 0 } - } + }, + Event::PhaseTransitioned { + from: Phase::Unsigned((true, 25)), + to: Phase::Off, + round: 2 + }, ] ); }); @@ -2299,9 +2399,18 @@ mod tests { assert_eq!( multi_phase_events(), vec![ - Event::SignedPhaseStarted { round: 1 }, - Event::UnsignedPhaseStarted { round: 1 }, - Event::ElectionFailed + Event::PhaseTransitioned { from: Phase::Off, to: Phase::Signed, round: 1 }, + Event::PhaseTransitioned { + from: Phase::Signed, + to: Phase::Unsigned((true, 25)), + round: 1 + }, + Event::ElectionFailed, + Event::PhaseTransitioned { + from: Phase::Unsigned((true, 25)), + to: Phase::Emergency, + round: 1 + }, ] ); }) @@ -2339,17 +2448,28 @@ mod tests { assert_eq!( multi_phase_events(), vec![ - Event::SignedPhaseStarted { round: 1 }, - Event::UnsignedPhaseStarted { round: 1 }, + Event::PhaseTransitioned { from: Phase::Off, to: Phase::Signed, round: 1 }, + Event::PhaseTransitioned { + from: Phase::Signed, + to: Phase::Unsigned((true, 25)), + round: 1 + }, Event::ElectionFailed, + Event::PhaseTransitioned { + from: Phase::Unsigned((true, 25)), + to: Phase::Emergency, + round: 1 + }, Event::SolutionStored { compute: ElectionCompute::Fallback, + origin: None, prev_ejected: false }, Event::ElectionFinalized { compute: ElectionCompute::Fallback, score: Default::default() - } + }, + Event::PhaseTransitioned { from: Phase::Emergency, to: Phase::Off, round: 2 }, ] ); }) @@ -2375,10 +2495,17 @@ mod tests { assert_eq!( multi_phase_events(), - vec![Event::ElectionFinalized { - compute: ElectionCompute::Fallback, - score: ElectionScore { minimal_stake: 0, sum_stake: 0, sum_stake_squared: 0 } - }] + vec![ + Event::ElectionFinalized { + compute: ElectionCompute::Fallback, + score: ElectionScore { + minimal_stake: 0, + sum_stake: 0, + sum_stake_squared: 0 + } + }, + Event::PhaseTransitioned { from: Phase::Off, to: Phase::Off, round: 2 }, + ] ); }); } @@ -2404,7 +2531,13 @@ mod tests { assert_eq!(err, ElectionError::Fallback("NoFallback.")); assert_eq!(MultiPhase::current_phase(), Phase::Emergency); - assert_eq!(multi_phase_events(), vec![Event::ElectionFailed]); + assert_eq!( + multi_phase_events(), + vec![ + Event::ElectionFailed, + Event::PhaseTransitioned { from: Phase::Off, to: Phase::Emergency, round: 1 } + ] + ); }); } diff --git a/frame/election-provider-multi-phase/src/signed.rs b/frame/election-provider-multi-phase/src/signed.rs index 12d39e83b6c09..895f3670a7f0d 100644 --- a/frame/election-provider-multi-phase/src/signed.rs +++ b/frame/election-provider-multi-phase/src/signed.rs @@ -620,8 +620,12 @@ mod tests { assert_eq!( multi_phase_events(), vec![ - Event::SignedPhaseStarted { round: 1 }, - Event::SolutionStored { compute: ElectionCompute::Signed, prev_ejected: false } + Event::PhaseTransitioned { from: Phase::Off, to: Phase::Signed, round: 1 }, + Event::SolutionStored { + compute: ElectionCompute::Signed, + origin: Some(99), + prev_ejected: false + } ] ); }) @@ -645,8 +649,12 @@ mod tests { assert_eq!( multi_phase_events(), vec![ - Event::SignedPhaseStarted { round: 1 }, - Event::SolutionStored { compute: ElectionCompute::Signed, prev_ejected: false }, + Event::PhaseTransitioned { from: Phase::Off, to: Phase::Signed, round: 1 }, + Event::SolutionStored { + compute: ElectionCompute::Signed, + origin: Some(99), + prev_ejected: false + }, Event::Rewarded { account: 99, value: 7 } ] ); @@ -676,8 +684,12 @@ mod tests { assert_eq!( multi_phase_events(), vec![ - Event::SignedPhaseStarted { round: 1 }, - Event::SolutionStored { compute: ElectionCompute::Signed, prev_ejected: false }, + Event::PhaseTransitioned { from: Phase::Off, to: Phase::Signed, round: 1 }, + Event::SolutionStored { + compute: ElectionCompute::Signed, + origin: Some(99), + prev_ejected: false + }, Event::Slashed { account: 99, value: 5 } ] ); @@ -713,9 +725,17 @@ mod tests { 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::PhaseTransitioned { from: Phase::Off, to: Phase::Signed, round: 1 }, + Event::SolutionStored { + compute: ElectionCompute::Signed, + origin: Some(99), + prev_ejected: false + }, + Event::SolutionStored { + compute: ElectionCompute::Signed, + origin: Some(999), + prev_ejected: false + }, Event::Rewarded { account: 99, value: 7 } ] ); @@ -788,12 +808,32 @@ mod tests { 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::PhaseTransitioned { from: Phase::Off, to: Phase::Signed, round: 1 }, + Event::SolutionStored { + compute: ElectionCompute::Signed, + origin: Some(99), + prev_ejected: false + }, + Event::SolutionStored { + compute: ElectionCompute::Signed, + origin: Some(100), + prev_ejected: false + }, + Event::SolutionStored { + compute: ElectionCompute::Signed, + origin: Some(101), + prev_ejected: false + }, + Event::SolutionStored { + compute: ElectionCompute::Signed, + origin: Some(102), + prev_ejected: false + }, + Event::SolutionStored { + compute: ElectionCompute::Signed, + origin: Some(103), + prev_ejected: false + }, Event::Rewarded { account: 99, value: 7 }, Event::ElectionFinalized { compute: ElectionCompute::Signed, @@ -856,13 +896,15 @@ mod tests { assert_eq!( multi_phase_events(), vec![ - Event::SignedPhaseStarted { round: 1 }, + Event::PhaseTransitioned { from: Phase::Off, to: Phase::Signed, round: 1 }, Event::SolutionStored { compute: ElectionCompute::Signed, + origin: Some(99), prev_ejected: false }, Event::SolutionStored { compute: ElectionCompute::Signed, + origin: Some(99), prev_ejected: true } ] @@ -1112,12 +1154,28 @@ mod tests { 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::PhaseTransitioned { from: Phase::Off, to: Phase::Signed, round: 1 }, + Event::SolutionStored { + compute: ElectionCompute::Signed, + origin: Some(100), + prev_ejected: false + }, + Event::SolutionStored { + compute: ElectionCompute::Signed, + origin: Some(101), + prev_ejected: false + }, + Event::SolutionStored { + compute: ElectionCompute::Signed, + origin: Some(102), + prev_ejected: false + }, Event::Rewarded { account: 100, value: 7 }, - Event::UnsignedPhaseStarted { round: 1 } + Event::PhaseTransitioned { + from: Phase::Signed, + to: Phase::Unsigned((true, 25)), + round: 1 + }, ] ); }) @@ -1170,10 +1228,22 @@ mod tests { 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::PhaseTransitioned { from: Phase::Off, to: Phase::Signed, round: 1 }, + Event::SolutionStored { + compute: ElectionCompute::Signed, + origin: Some(99), + prev_ejected: false + }, + Event::SolutionStored { + compute: ElectionCompute::Signed, + origin: Some(999), + prev_ejected: false + }, + Event::SolutionStored { + compute: ElectionCompute::Signed, + origin: Some(9999), + prev_ejected: false + }, Event::Slashed { account: 999, value: 5 }, Event::Rewarded { account: 99, value: 7 } ] @@ -1304,8 +1374,12 @@ mod tests { assert_eq!( multi_phase_events(), vec![ - Event::SignedPhaseStarted { round: 1 }, - Event::SolutionStored { compute: ElectionCompute::Signed, prev_ejected: false }, + Event::PhaseTransitioned { from: Phase::Off, to: Phase::Signed, round: 1 }, + Event::SolutionStored { + compute: ElectionCompute::Signed, + origin: Some(99), + 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 7340605dfe621..cdc71f7bf5bf0 100644 --- a/frame/election-provider-multi-phase/src/unsigned.rs +++ b/frame/election-provider-multi-phase/src/unsigned.rs @@ -1055,7 +1055,7 @@ mod tests { Runtime, RuntimeCall, RuntimeOrigin, System, TestNposSolution, TrimHelpers, UnsignedPhase, }, - CurrentPhase, Event, InvalidTransaction, Phase, QueuedSolution, TransactionSource, + Event, InvalidTransaction, Phase, QueuedSolution, TransactionSource, TransactionValidityError, }; use codec::Decode; @@ -1128,7 +1128,7 @@ mod tests { assert!(::pre_dispatch(&call).is_ok()); // unsigned -- but not enabled. - >::put(Phase::Unsigned((false, 25))); + MultiPhase::phase_transition(Phase::Unsigned((false, 25))); assert!(MultiPhase::current_phase().is_unsigned()); assert!(matches!( ::validate_unsigned( @@ -1321,10 +1321,15 @@ mod tests { assert_eq!( multi_phase_events(), vec![ - Event::SignedPhaseStarted { round: 1 }, - Event::UnsignedPhaseStarted { round: 1 }, + Event::PhaseTransitioned { from: Phase::Off, to: Phase::Signed, round: 1 }, + Event::PhaseTransitioned { + from: Phase::Signed, + to: Phase::Unsigned((true, 25)), + round: 1 + }, Event::SolutionStored { compute: ElectionCompute::Unsigned, + origin: None, prev_ejected: false } ] @@ -1661,7 +1666,7 @@ mod tests { 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))); + MultiPhase::phase_transition(Phase::Unsigned((true, current_block))); // clear the cache and create a solution since we are on the first block of the unsigned // phase. @@ -1673,8 +1678,12 @@ mod tests { assert_eq!( multi_phase_events(), vec![ - Event::SignedPhaseStarted { round: 1 }, - Event::UnsignedPhaseStarted { round: 1 }, + Event::PhaseTransitioned { from: Phase::Off, to: Phase::Signed, round: 1 }, + Event::PhaseTransitioned { + from: Phase::Signed, + to: Phase::Unsigned((true, 25)), + round: 1 + }, Event::ElectionFinalized { compute: ElectionCompute::Fallback, score: ElectionScore { @@ -1682,7 +1691,12 @@ mod tests { sum_stake: 0, sum_stake_squared: 0 } - } + }, + Event::PhaseTransitioned { + from: Phase::Unsigned((true, 25)), + to: Phase::Unsigned((true, 37)), + round: 1 + }, ] ); }) diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index db9aeba6fb58e..7af9b0aaaa04a 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -339,7 +339,7 @@ impl Pallet { if maybe_new_era_validators.is_some() && matches!(ForceEra::::get(), Forcing::ForceNew) { - ForceEra::::put(Forcing::NotForcing); + Self::set_force_era(Forcing::NotForcing); } maybe_new_era_validators @@ -717,11 +717,18 @@ impl Pallet { } } + /// Helper to set a new `ForceEra` mode. + pub(crate) fn set_force_era(mode: Forcing) { + log!(info, "Setting force era mode {:?}.", mode); + ForceEra::::put(mode); + Self::deposit_event(Event::::ForceEra { mode }); + } + /// Ensures that at the end of the current session there will be a new era. pub(crate) fn ensure_new_era() { match ForceEra::::get() { Forcing::ForceAlways | Forcing::ForceNew => (), - _ => ForceEra::::put(Forcing::ForceNew), + _ => Self::set_force_era(Forcing::ForceNew), } } diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index ce4f2494621b4..c0c18b40cf02f 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -714,6 +714,8 @@ pub mod pallet { PayoutStarted { era_index: EraIndex, validator_stash: T::AccountId }, /// A validator has set their preferences. ValidatorPrefsSet { stash: T::AccountId, prefs: ValidatorPrefs }, + /// A new force era mode was set. + ForceEra { mode: Forcing }, } #[pallet::error] @@ -1377,7 +1379,7 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::force_no_eras())] pub fn force_no_eras(origin: OriginFor) -> DispatchResult { ensure_root(origin)?; - ForceEra::::put(Forcing::ForceNone); + Self::set_force_era(Forcing::ForceNone); Ok(()) } @@ -1401,7 +1403,7 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::force_new_era())] pub fn force_new_era(origin: OriginFor) -> DispatchResult { ensure_root(origin)?; - ForceEra::::put(Forcing::ForceNew); + Self::set_force_era(Forcing::ForceNew); Ok(()) } @@ -1452,7 +1454,7 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::force_new_era_always())] pub fn force_new_era_always(origin: OriginFor) -> DispatchResult { ensure_root(origin)?; - ForceEra::::put(Forcing::ForceAlways); + Self::set_force_era(Forcing::ForceAlways); Ok(()) } diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 46c3c97441938..acd41895287c5 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -899,7 +899,7 @@ fn forcing_new_era_works() { assert_eq!(active_era(), 1); // no era change. - ForceEra::::put(Forcing::ForceNone); + Staking::set_force_era(Forcing::ForceNone); start_session(4); assert_eq!(active_era(), 1); @@ -915,7 +915,7 @@ fn forcing_new_era_works() { // back to normal. // this immediately starts a new session. - ForceEra::::put(Forcing::NotForcing); + Staking::set_force_era(Forcing::NotForcing); start_session(8); assert_eq!(active_era(), 1); @@ -923,7 +923,7 @@ fn forcing_new_era_works() { start_session(9); assert_eq!(active_era(), 2); // forceful change - ForceEra::::put(Forcing::ForceAlways); + Staking::set_force_era(Forcing::ForceAlways); start_session(10); assert_eq!(active_era(), 2); @@ -935,7 +935,7 @@ fn forcing_new_era_works() { assert_eq!(active_era(), 4); // just one forceful change - ForceEra::::put(Forcing::ForceNew); + Staking::set_force_era(Forcing::ForceNew); start_session(13); assert_eq!(active_era(), 5); assert_eq!(ForceEra::::get(), Forcing::NotForcing); @@ -2303,7 +2303,7 @@ fn era_is_always_same_length() { ); let session = Session::current_index(); - ForceEra::::put(Forcing::ForceNew); + Staking::set_force_era(Forcing::ForceNew); advance_session(); advance_session(); assert_eq!(current_era(), 3); @@ -2914,7 +2914,10 @@ fn deferred_slashes_are_deferred() { staking_events_since_last_call().as_slice(), &[ Event::Chilled { stash: 11 }, + Event::ForceEra { mode: Forcing::ForceNew }, Event::SlashReported { validator: 11, slash_era: 1, .. }, + Event::StakersElected, + Event::ForceEra { mode: Forcing::NotForcing }, .., Event::Slashed { staker: 11, amount: 100 }, Event::Slashed { staker: 101, amount: 12 } @@ -2949,6 +2952,7 @@ fn retroactive_deferred_slashes_two_eras_before() { staking_events_since_last_call().as_slice(), &[ Event::Chilled { stash: 11 }, + Event::ForceEra { mode: Forcing::ForceNew }, Event::SlashReported { validator: 11, slash_era: 1, .. }, .., Event::Slashed { staker: 11, amount: 100 }, @@ -3251,6 +3255,7 @@ fn slash_kicks_validators_not_nominators_and_disables_nominator_for_kicked_valid Event::StakersElected, Event::EraPaid { era_index: 0, validator_payout: 11075, remainder: 33225 }, Event::Chilled { stash: 11 }, + Event::ForceEra { mode: Forcing::ForceNew }, Event::SlashReported { validator: 11, fraction: Perbill::from_percent(10), @@ -3318,6 +3323,7 @@ fn non_slashable_offence_doesnt_disable_validator() { Event::StakersElected, Event::EraPaid { era_index: 0, validator_payout: 11075, remainder: 33225 }, Event::Chilled { stash: 11 }, + Event::ForceEra { mode: Forcing::ForceNew }, Event::SlashReported { validator: 11, fraction: Perbill::from_percent(0), @@ -3380,6 +3386,7 @@ fn slashing_independent_of_disabling_validator() { Event::StakersElected, Event::EraPaid { era_index: 0, validator_payout: 11075, remainder: 33225 }, Event::Chilled { stash: 11 }, + Event::ForceEra { mode: Forcing::ForceNew }, Event::SlashReported { validator: 11, fraction: Perbill::from_percent(0), @@ -4662,8 +4669,15 @@ mod election_data_provider { MinimumValidatorCount::::put(2); run_to_block(55); assert_eq!(Staking::next_election_prediction(System::block_number()), 55 + 25); - assert_eq!(staking_events().len(), 6); - assert_eq!(*staking_events().last().unwrap(), Event::StakersElected); + assert_eq!(staking_events().len(), 10); + assert_eq!( + *staking_events().last().unwrap(), + Event::ForceEra { mode: Forcing::NotForcing } + ); + assert_eq!( + *staking_events().get(staking_events().len() - 2).unwrap(), + Event::StakersElected + ); // The new era has been planned, forcing is changed from `ForceNew` to `NotForcing`. assert_eq!(ForceEra::::get(), Forcing::NotForcing); }) From dc18d1380e6cbb0c140cf907f66e9aa143cfff4c Mon Sep 17 00:00:00 2001 From: Vlad Date: Mon, 9 Jan 2023 21:36:27 +0400 Subject: [PATCH 269/715] CI: configure `cargo-nextest`'s reporter options explicitly (#13104) --- .gitlab-ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a0b1464bae23e..f6347e51e62c5 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -53,6 +53,8 @@ variables: RUSTY_CACHIER_SINGLE_BRANCH: master RUSTY_CACHIER_DONT_OPERATE_ON_MAIN_BRANCH: "true" RUSTY_CACHIER_COMPRESSION_METHOD: zstd + NEXTEST_FAILURE_OUTPUT: immediate-final + NEXTEST_SUCCESS_OUTPUT: final ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.3.22" default: From b85246bf1156f9f58825f0be48e6086128cc0bbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Enrique=20Mu=C3=B1oz=20Mart=C3=ADn?= Date: Mon, 9 Jan 2023 20:04:24 +0100 Subject: [PATCH 270/715] Add ensure_pow method (#13042) * add ensure_pow method * reexport checked_pow and ensure_pow --- primitives/arithmetic/src/traits.rs | 52 +++++++++++++++++++++++------ primitives/runtime/src/traits.rs | 10 +++--- 2 files changed, 47 insertions(+), 15 deletions(-) diff --git a/primitives/arithmetic/src/traits.rs b/primitives/arithmetic/src/traits.rs index 9e9dff8e6f9ea..dfba046754373 100644 --- a/primitives/arithmetic/src/traits.rs +++ b/primitives/arithmetic/src/traits.rs @@ -19,9 +19,9 @@ use codec::HasCompact; pub use ensure::{ - Ensure, EnsureAdd, EnsureAddAssign, EnsureDiv, EnsureDivAssign, EnsureFixedPointNumber, - EnsureFrom, EnsureInto, EnsureMul, EnsureMulAssign, EnsureOp, EnsureOpAssign, EnsureSub, - EnsureSubAssign, + ensure_pow, Ensure, EnsureAdd, EnsureAddAssign, EnsureDiv, EnsureDivAssign, + EnsureFixedPointNumber, EnsureFrom, EnsureInto, EnsureMul, EnsureMulAssign, EnsureOp, + EnsureOpAssign, EnsureSub, EnsureSubAssign, }; pub use integer_sqrt::IntegerSquareRoot; pub use num_traits::{ @@ -342,7 +342,7 @@ impl SaturatedConversion for T {} /// The *EnsureOps* family functions follows the same behavior as *CheckedOps* but /// returning an [`ArithmeticError`](crate::ArithmeticError) instead of `None`. mod ensure { - use super::{CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, Zero}; + use super::{checked_pow, CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, One, Zero}; use crate::{ArithmeticError, FixedPointNumber, FixedPointOperand}; /// Performs addition that returns [`ArithmeticError`] instead of wrapping around on overflow. @@ -511,6 +511,27 @@ mod ensure { } } + /// Raises a value to the power of exp, returning `ArithmeticError` if an overflow occurred. + /// + /// Check [`checked_pow`] for more info about border cases. + /// + /// ``` + /// use sp_arithmetic::{traits::ensure_pow, ArithmeticError}; + /// + /// fn overflow() -> Result<(), ArithmeticError> { + /// ensure_pow(2u64, 64)?; + /// Ok(()) + /// } + /// + /// assert_eq!(overflow(), Err(ArithmeticError::Overflow)); + /// ``` + pub fn ensure_pow( + base: T, + exp: usize, + ) -> Result { + checked_pow(base, exp).ok_or(ArithmeticError::Overflow) + } + impl EnsureAdd for T {} impl EnsureSub for T {} impl EnsureMul for T {} @@ -953,6 +974,15 @@ mod tests { test_ensure(values(), &EnsureDiv::ensure_div, &CheckedDiv::checked_div); } + #[test] + fn ensure_pow_works() { + test_ensure( + values().into_iter().map(|(base, exp)| (base, exp as usize)).collect(), + ensure_pow, + |&a, &b| checked_pow(a, b), + ); + } + #[test] fn ensure_add_assign_works() { test_ensure_assign(values(), &EnsureAddAssign::ensure_add_assign, &EnsureAdd::ensure_add); @@ -974,11 +1004,12 @@ mod tests { } /// Test that the ensured function returns the expected un-ensured value. - fn test_ensure(pairs: Vec<(V, V)>, ensured: E, unensured: P) + fn test_ensure(pairs: Vec<(V, W)>, ensured: E, unensured: P) where V: Ensure + core::fmt::Debug + Copy, - E: Fn(V, V) -> Result, - P: Fn(&V, &V) -> Option, + W: Ensure + core::fmt::Debug + Copy, + E: Fn(V, W) -> Result, + P: Fn(&V, &W) -> Option, { for (a, b) in pairs.into_iter() { match ensured(a, b) { @@ -993,11 +1024,12 @@ mod tests { } /// Test that the ensured function modifies `self` to the expected un-ensured value. - fn test_ensure_assign(pairs: Vec<(V, V)>, ensured: E, unensured: P) + fn test_ensure_assign(pairs: Vec<(V, W)>, ensured: E, unensured: P) where V: Ensure + std::panic::RefUnwindSafe + std::panic::UnwindSafe + core::fmt::Debug + Copy, - E: Fn(&mut V, V) -> Result<(), ArithmeticError>, - P: Fn(V, V) -> Result + std::panic::RefUnwindSafe, + W: Ensure + std::panic::RefUnwindSafe + std::panic::UnwindSafe + core::fmt::Debug + Copy, + E: Fn(&mut V, W) -> Result<(), ArithmeticError>, + P: Fn(V, W) -> Result + std::panic::RefUnwindSafe, { for (mut a, b) in pairs.into_iter() { let old_a = a; diff --git a/primitives/runtime/src/traits.rs b/primitives/runtime/src/traits.rs index 8978cdb11c0c6..6eb19683b4439 100644 --- a/primitives/runtime/src/traits.rs +++ b/primitives/runtime/src/traits.rs @@ -32,11 +32,11 @@ use impl_trait_for_tuples::impl_for_tuples; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use sp_application_crypto::AppKey; pub use sp_arithmetic::traits::{ - AtLeast32Bit, AtLeast32BitUnsigned, Bounded, CheckedAdd, CheckedDiv, CheckedMul, CheckedShl, - CheckedShr, CheckedSub, Ensure, EnsureAdd, EnsureAddAssign, EnsureDiv, EnsureDivAssign, - EnsureFixedPointNumber, EnsureFrom, EnsureInto, EnsureMul, EnsureMulAssign, EnsureOp, - EnsureOpAssign, EnsureSub, EnsureSubAssign, IntegerSquareRoot, One, SaturatedConversion, - Saturating, UniqueSaturatedFrom, UniqueSaturatedInto, Zero, + checked_pow, ensure_pow, AtLeast32Bit, AtLeast32BitUnsigned, Bounded, CheckedAdd, CheckedDiv, + CheckedMul, CheckedShl, CheckedShr, CheckedSub, Ensure, EnsureAdd, EnsureAddAssign, EnsureDiv, + EnsureDivAssign, EnsureFixedPointNumber, EnsureFrom, EnsureInto, EnsureMul, EnsureMulAssign, + EnsureOp, EnsureOpAssign, EnsureSub, EnsureSubAssign, IntegerSquareRoot, One, + SaturatedConversion, Saturating, UniqueSaturatedFrom, UniqueSaturatedInto, Zero, }; use sp_core::{self, storage::StateVersion, Hasher, RuntimeDebug, TypeId}; #[doc(hidden)] From 75d10c73daa03c98f3acbeb65203d39586f6cf8f Mon Sep 17 00:00:00 2001 From: alexgparity <115470171+alexgparity@users.noreply.github.com> Date: Tue, 10 Jan 2023 12:32:19 +0100 Subject: [PATCH 271/715] Add solution hint to error message (#13111) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add solution hint to error message * make it compile * Update frame/support/procedural/src/pallet/expand/hooks.rs Co-authored-by: Bastian Köcher * Update frame/support/procedural/src/pallet/expand/storage.rs Co-authored-by: Bastian Köcher * Update frame/support/procedural/src/pallet/expand/storage.rs Co-authored-by: Bastian Köcher * Update frame/support/procedural/src/pallet/expand/storage.rs Co-authored-by: Bastian Köcher Co-authored-by: Bastian Köcher --- frame/support/procedural/src/pallet/expand/hooks.rs | 2 +- frame/support/procedural/src/pallet/expand/storage.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/frame/support/procedural/src/pallet/expand/hooks.rs b/frame/support/procedural/src/pallet/expand/hooks.rs index 0aa7c1e7aaf06..c2b70c5632f94 100644 --- a/frame/support/procedural/src/pallet/expand/hooks.rs +++ b/frame/support/procedural/src/pallet/expand/hooks.rs @@ -63,7 +63,7 @@ pub fn expand_hooks(def: &mut Def) -> proc_macro2::TokenStream { ::PalletInfo as #frame_support::traits::PalletInfo - >::name::().expect("Every active pallet has a name in the runtime; qed"); + >::name::().expect("No name found for the pallet! This usually means that the pallet wasn't added to `construct_runtime!`."); #frame_support::log::debug!( target: #frame_support::LOG_TARGET, "🩺 try-state pallet {:?}", diff --git a/frame/support/procedural/src/pallet/expand/storage.rs b/frame/support/procedural/src/pallet/expand/storage.rs index 181f35b545496..195a62431f279 100644 --- a/frame/support/procedural/src/pallet/expand/storage.rs +++ b/frame/support/procedural/src/pallet/expand/storage.rs @@ -535,7 +535,7 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream { ::PalletInfo as #frame_support::traits::PalletInfo >::name::>() - .expect("Every active pallet has a name in the runtime; qed") + .expect("No name found for the pallet in the runtime! This usually means that the pallet wasn't added to `construct_runtime!`.") } const STORAGE_PREFIX: &'static str = #counter_prefix_struct_const; } @@ -569,7 +569,7 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream { ::PalletInfo as #frame_support::traits::PalletInfo >::name::>() - .expect("Every active pallet has a name in the runtime; qed") + .expect("No name found for the pallet in the runtime! This usually means that the pallet wasn't added to `construct_runtime!`.") } const STORAGE_PREFIX: &'static str = #prefix_struct_const; } @@ -648,7 +648,7 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream { ::PalletInfo as #frame_support::traits::PalletInfo >::name::<#pallet_ident<#type_use_gen>>() - .expect("Every active pallet has a name in the runtime; qed"), + .expect("No name found for the pallet in the runtime! This usually means that the pallet wasn't added to `construct_runtime!`."), entries: { #[allow(unused_mut)] let mut entries = #frame_support::sp_std::vec![]; From 4e383428ffc6d4eba173ca257c1aaf53d1ec339c Mon Sep 17 00:00:00 2001 From: JP <77391175+joao-paulo-parity@users.noreply.github.com> Date: Tue, 10 Jan 2023 09:01:44 -0300 Subject: [PATCH 272/715] Avoid unintentionally canceling the scheduled crate publishing job (#13088) * avoid unintentionally canceling the scheduled crate publishing job because publish-crates and publish-crates-manual share the resource group "crates-publishing", any instance of publish-crates-manual cancels a running instance of publish-crates, as demonstrated by https://gitlab.parity.io/parity/mirrors/substrate/-/jobs/2212179 a workaround for that unintended interaction is to avoid creating instances of publish-crates-manual and instead require pipelines to be triggered manually by checking $CI_JOB_MANUAL == "true" * check manual pipelines by $CI_PIPELINE_SOURCE instead of $CI_JOB_MANUAL * make crate-publishing pipelines uninterruptible * use conditional includes to work around interruptible limitations * organize comments * remove interruptible from common pipeline * wip: check include * wip: check include * fix include * fix include * fix include * fix yaml * fix yaml * remove shared common-pipeline * wip: retry common-pipeline * move .default-template to .gitlab-ci.yml * fix the pipeline add comments * fix default-pipeline.yml * revert publish-crates-manual to when: manual * move "needs:" back to publish-crates * avoid manual repetition * improve previous commit * try to avoid manual repetition * fix indentation * minor adjustments * move defaults to top of .gitlab-ci.yml * fix positioning on default in the diff * comments * indentation * Apply suggestions from code review Co-authored-by: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Co-authored-by: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> --- .gitlab-ci.yml | 42 +++++++++++++++++-- .../ci/gitlab/crate-publishing-pipeline.yml | 1 + scripts/ci/gitlab/default-pipeline.yml | 1 + scripts/ci/gitlab/pipeline/publish.yml | 3 +- 4 files changed, 43 insertions(+), 4 deletions(-) create mode 100644 scripts/ci/gitlab/crate-publishing-pipeline.yml create mode 100644 scripts/ci/gitlab/default-pipeline.yml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f6347e51e62c5..ecc27d016a811 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -57,16 +57,30 @@ variables: NEXTEST_SUCCESS_OUTPUT: final ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.3.22" -default: +.shared-default: &shared-default retry: max: 2 when: - runner_system_failure - unknown_failure - api_failure - interruptible: true cache: {} +.default-pipeline-definitions: + default: + <<: *shared-default + interruptible: true + +.crate-publishing-pipeline-definitions: + default: + <<: *shared-default + # The crate-publishing pipeline defaults to `interruptible: false` so that we'll be able to + # reach and run the publishing jobs despite the "Auto-cancel redundant pipelines" CI setting. + # The setting is relevant because the crate-publishing pipeline runs on `master`, thus future + # pipelines on `master` (e.g. created for new commits or other schedules) might unintendedly + # cancel the publishing jobs or its dependencies before we get to actually publish the crates. + interruptible: false + .collect-artifacts: artifacts: name: "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}" @@ -215,9 +229,15 @@ 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" +.crate-publishing-pipeline: + rules: + - if: $CI_COMMIT_REF_NAME != "master" + when: never + .scheduled-crate-publishing-pipeline: rules: - - if: $CI_COMMIT_REF_NAME == "master" && $CI_PIPELINE_SOURCE == "schedule" && $PIPELINE == "automatic-crate-publishing" + - !reference [.crate-publishing-pipeline, rules] + - if: $CI_PIPELINE_SOURCE == "schedule" && $PIPELINE == "automatic-crate-publishing" .crates-publishing-template: stage: test @@ -265,6 +285,22 @@ include: - scripts/ci/gitlab/pipeline/publish.yml # zombienet jobs - scripts/ci/gitlab/pipeline/zombienet.yml + # The crate-publishing pipeline requires a customized `interruptible` configuration. Unfortunately + # `interruptible` can't currently be dynamically set based on variables as per: + # - https://gitlab.com/gitlab-org/gitlab/-/issues/38349 + # - https://gitlab.com/gitlab-org/gitlab/-/issues/194023 + # Thus we work around that limitation by using conditional includes. + # For crate-publishing pipelines: run it with defaults + `interruptible: false`. The WHOLE + # pipeline is made uninterruptible to ensure that test jobs also get a chance to run to + # completion, because the publishing jobs depends on them AS INTENDED: crates should not be + # published before their source code is checked. + - local: scripts/ci/gitlab/crate-publishing-pipeline.yml + rules: + - if: $PIPELINE == "automatic-crate-publishing" + # For normal pipelines: run it with defaults + `interruptible: true` + - local: scripts/ci/gitlab/default-pipeline.yml + rules: + - if: $PIPELINE != "automatic-crate-publishing" #### stage: deploy diff --git a/scripts/ci/gitlab/crate-publishing-pipeline.yml b/scripts/ci/gitlab/crate-publishing-pipeline.yml new file mode 100644 index 0000000000000..9d5303952e6ef --- /dev/null +++ b/scripts/ci/gitlab/crate-publishing-pipeline.yml @@ -0,0 +1 @@ +default: !reference [.crate-publishing-pipeline-definitions, default] diff --git a/scripts/ci/gitlab/default-pipeline.yml b/scripts/ci/gitlab/default-pipeline.yml new file mode 100644 index 0000000000000..19f6c320c3c24 --- /dev/null +++ b/scripts/ci/gitlab/default-pipeline.yml @@ -0,0 +1 @@ +default: !reference [.default-pipeline-definitions, default] diff --git a/scripts/ci/gitlab/pipeline/publish.yml b/scripts/ci/gitlab/pipeline/publish.yml index cc7451a9fbb22..dff1b508625fb 100644 --- a/scripts/ci/gitlab/pipeline/publish.yml +++ b/scripts/ci/gitlab/pipeline/publish.yml @@ -214,7 +214,7 @@ update-node-template: timeout: 9h # A custom publishing environment is used for us to be able to set up protected secrets # specifically for it - environment: publish-crates + environment: publish-crates script: - rusty-cachier snapshot create - git clone @@ -234,5 +234,6 @@ publish-crates: publish-crates-manual: extends: .publish-crates-template + rules: !reference [.crate-publishing-pipeline, rules] when: manual allow_failure: true From ad844bef26bac6c7d885d8259064b08189572d8f Mon Sep 17 00:00:00 2001 From: Anthony Alaribe Date: Tue, 10 Jan 2023 20:18:12 +0100 Subject: [PATCH 273/715] introduce log-target constant to more frame pallets (#13116) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * introduce log-target constant to more frame pallets * cargo fmt * make LOG_TARGET in session public * Update frame/elections-phragmen/src/lib.rs Co-authored-by: Bastian Köcher * Update frame/elections-phragmen/src/migrations/v3.rs Co-authored-by: Bastian Köcher * Update frame/elections-phragmen/src/migrations/v3.rs Co-authored-by: Bastian Köcher * Update frame/elections-phragmen/src/migrations/v3.rs Co-authored-by: Bastian Köcher * move LOG_TARGET=runtime::session_historical to migrations module, where it's actually used Co-authored-by: Bastian Köcher --- frame/assets/src/lib.rs | 1 + frame/assets/src/migration.rs | 12 +++++++-- frame/balances/src/lib.rs | 6 +++-- frame/balances/src/migration.rs | 14 ++++++++--- frame/collective/src/lib.rs | 8 +++--- frame/collective/src/migrations/v4.rs | 9 ++++--- frame/elections-phragmen/src/lib.rs | 15 ++++------- frame/elections-phragmen/src/migrations/v3.rs | 25 ++++++------------- frame/elections-phragmen/src/migrations/v4.rs | 7 +++--- frame/membership/src/lib.rs | 2 ++ frame/membership/src/migrations/v4.rs | 9 ++++--- frame/session/src/migrations/v1.rs | 10 +++++--- frame/system/src/lib.rs | 16 ++++++------ frame/system/src/migrations/mod.rs | 7 +++--- frame/tips/src/lib.rs | 2 ++ frame/tips/src/migrations/v4.rs | 9 ++++--- frame/uniques/src/lib.rs | 2 ++ frame/uniques/src/migration.rs | 6 ++--- 18 files changed, 89 insertions(+), 71 deletions(-) diff --git a/frame/assets/src/lib.rs b/frame/assets/src/lib.rs index 1853ef75f52be..93e416c3bec4c 100644 --- a/frame/assets/src/lib.rs +++ b/frame/assets/src/lib.rs @@ -175,6 +175,7 @@ pub use pallet::*; pub use weights::WeightInfo; type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; +const LOG_TARGET: &str = "runtime::assets"; /// Trait with callbacks that are executed after successfull asset creation or destruction. pub trait AssetsCallback { diff --git a/frame/assets/src/migration.rs b/frame/assets/src/migration.rs index 89f8d39a9049c..9f8905ceff6c4 100644 --- a/frame/assets/src/migration.rs +++ b/frame/assets/src/migration.rs @@ -75,10 +75,18 @@ pub mod v1 { Some(old_value.migrate_to_v1()) }); current_version.put::>(); - log::info!(target: "runtime::assets", "Upgraded {} pools, storage to version {:?}", translated, current_version); + log::info!( + target: LOG_TARGET, + "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"); + log::info!( + target: LOG_TARGET, + "Migration did not execute. This probably should be removed" + ); T::DbWeight::get().reads(1) } } diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index 57f76b1ff679d..99d77a3e73361 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -193,6 +193,8 @@ pub use weights::WeightInfo; pub use pallet::*; +const LOG_TARGET: &str = "runtime::balances"; + type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; #[frame_support::pallet] @@ -950,7 +952,7 @@ impl, I: 'static> Pallet { if locks.len() as u32 > T::MaxLocks::get() { log::warn!( - target: "runtime::balances", + target: LOG_TARGET, "Warning: A user has more currency locks than expected. \ A runtime configuration adjustment may be needed." ); @@ -985,7 +987,7 @@ impl, I: 'static> Pallet { // 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", + target: LOG_TARGET, "Warning: Attempt to introduce lock consumer reference, yet no providers. \ This is unexpected but should be safe." ); diff --git a/frame/balances/src/migration.rs b/frame/balances/src/migration.rs index b660ec9fd3235..80d1bcd35ba9e 100644 --- a/frame/balances/src/migration.rs +++ b/frame/balances/src/migration.rs @@ -40,10 +40,13 @@ fn migrate_v0_to_v1, I: 'static>(accounts: &[T::AccountId]) -> Weig // Set storage version to `1`. StorageVersion::new(1).put::>(); - log::info!(target: "runtime::balances", "Storage to version 1"); + log::info!(target: LOG_TARGET, "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"); + log::info!( + target: LOG_TARGET, + "Migration did not execute. This probably should be removed" + ); T::DbWeight::get().reads(1) } } @@ -87,10 +90,13 @@ impl, I: 'static> OnRuntimeUpgrade for ResetInactive { // Set storage version to `0`. StorageVersion::new(0).put::>(); - log::info!(target: "runtime::balances", "Storage to version 0"); + log::info!(target: LOG_TARGET, "Storage to version 0"); T::DbWeight::get().reads_writes(1, 2) } else { - log::info!(target: "runtime::balances", "Migration did not execute. This probably should be removed"); + log::info!( + target: LOG_TARGET, + "Migration did not execute. This probably should be removed" + ); T::DbWeight::get().reads(1) } } diff --git a/frame/collective/src/lib.rs b/frame/collective/src/lib.rs index c522b71891b3c..0fe05dbb01ac0 100644 --- a/frame/collective/src/lib.rs +++ b/frame/collective/src/lib.rs @@ -71,6 +71,8 @@ pub mod weights; pub use pallet::*; pub use weights::WeightInfo; +const LOG_TARGET: &str = "runtime::collective"; + /// Simple index type for proposal counting. pub type ProposalIndex = u32; @@ -390,7 +392,7 @@ pub mod pallet { ensure_root(origin)?; if new_members.len() > T::MaxMembers::get() as usize { log::error!( - target: "runtime::collective", + target: LOG_TARGET, "New members count ({}) exceeds maximum amount of members expected ({}).", new_members.len(), T::MaxMembers::get(), @@ -400,7 +402,7 @@ pub mod pallet { let old = Members::::get(); if old.len() > old_count as usize { log::warn!( - target: "runtime::collective", + target: LOG_TARGET, "Wrong count used to estimate set_members weight. expected ({}) vs actual ({})", old_count, old.len(), @@ -1040,7 +1042,7 @@ impl, I: 'static> ChangeMembers for Pallet { ) { if new.len() > T::MaxMembers::get() as usize { log::error!( - target: "runtime::collective", + target: LOG_TARGET, "New members count ({}) exceeds maximum amount of members expected ({}).", new.len(), T::MaxMembers::get(), diff --git a/frame/collective/src/migrations/v4.rs b/frame/collective/src/migrations/v4.rs index 483c3f9fa9e69..2756b3fd15a6b 100644 --- a/frame/collective/src/migrations/v4.rs +++ b/frame/collective/src/migrations/v4.rs @@ -17,6 +17,7 @@ use sp_io::hashing::twox_128; +use super::super::LOG_TARGET; use frame_support::{ traits::{ Get, GetStorageVersion, PalletInfoAccess, StorageVersion, @@ -42,7 +43,7 @@ pub fn migrate::on_chain_storage_version(); log::info!( - target: "runtime::collective", + target: LOG_TARGET, "Running migration to v4 for collective with storage version {:?}", on_chain_storage_version, ); @@ -66,7 +67,7 @@ pub fn migrate::BlockWeights::get().max_block } else { log::warn!( - target: "runtime::collective", + target: LOG_TARGET, "Attempted to apply migration to v4 but failed because storage version is {:?}", on_chain_storage_version, ); @@ -138,7 +139,7 @@ pub fn post_migrate>(old_ fn log_migration(stage: &str, old_pallet_name: &str, new_pallet_name: &str) { log::info!( - target: "runtime::collective", + target: LOG_TARGET, "{}, prefix: '{}' ==> '{}'", stage, old_pallet_name, diff --git a/frame/elections-phragmen/src/lib.rs b/frame/elections-phragmen/src/lib.rs index 1cfdc25fd9b47..1a020adb28632 100644 --- a/frame/elections-phragmen/src/lib.rs +++ b/frame/elections-phragmen/src/lib.rs @@ -122,6 +122,8 @@ pub use weights::WeightInfo; /// All migrations. pub mod migrations; +const LOG_TARGET: &str = "runtime::elections-phragmen"; + /// The maximum votes allowed per voter. pub const MAXIMUM_VOTE: usize = 16; @@ -789,10 +791,7 @@ impl Pallet { } else { // overlap. This can never happen. If so, it seems like our intended replacement // is already a member, so not much more to do. - log::error!( - target: "runtime::elections-phragmen", - "A member seems to also be a runner-up.", - ); + log::error!(target: LOG_TARGET, "A member seems to also be a runner-up."); } next_best }); @@ -939,7 +938,7 @@ impl Pallet { Ok(_) => (), Err(_) => { log::error!( - target: "runtime::elections-phragmen", + target: LOG_TARGET, "Failed to run election. Number of voters exceeded", ); Self::deposit_event(Event::ElectionError); @@ -1103,11 +1102,7 @@ impl Pallet { >::mutate(|v| *v += 1); }) .map_err(|e| { - log::error!( - target: "runtime::elections-phragmen", - "Failed to run election [{:?}].", - e, - ); + log::error!(target: LOG_TARGET, "Failed to run election [{:?}].", e,); Self::deposit_event(Event::ElectionError); }); diff --git a/frame/elections-phragmen/src/migrations/v3.rs b/frame/elections-phragmen/src/migrations/v3.rs index 9ec9c6e7eea6c..e48cd6c1a8056 100644 --- a/frame/elections-phragmen/src/migrations/v3.rs +++ b/frame/elections-phragmen/src/migrations/v3.rs @@ -17,6 +17,7 @@ //! Migrations to version [`3.0.0`], as denoted by the changelog. +use super::super::LOG_TARGET; use crate::{Config, Pallet}; use codec::{Decode, Encode, FullCodec}; use frame_support::{ @@ -88,7 +89,7 @@ pub fn apply( ) -> Weight { let storage_version = StorageVersion::get::>(); log::info!( - target: "runtime::elections-phragmen", + target: LOG_TARGET, "Running migration for elections-phragmen with storage version {:?}", storage_version, ); @@ -104,7 +105,7 @@ pub fn apply( Weight::MAX } else { log::warn!( - target: "runtime::elections-phragmen", + target: LOG_TARGET, "Attempted to apply migration to V3 but failed because storage version is {:?}", storage_version, ); @@ -118,22 +119,14 @@ pub fn migrate_voters_to_recorded_deposit(old_deposit: V:: Some(Voter { votes, stake, deposit: old_deposit }) }); - log::info!( - target: "runtime::elections-phragmen", - "migrated {} voter accounts.", - >::iter().count(), - ); + log::info!(target: LOG_TARGET, "migrated {} voter accounts.", >::iter().count()); } /// Migrate all candidates to recorded deposit. 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", - "migrated {} candidate accounts.", - old_candidates.len(), - ); + log::info!(target: LOG_TARGET, "migrated {} candidate accounts.", old_candidates.len()); old_candidates.into_iter().map(|c| (c, old_deposit)).collect::>() }) }); @@ -143,11 +136,7 @@ pub fn migrate_candidates_to_recorded_deposit(old_deposit: 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", - "migrated {} member accounts.", - old_members.len(), - ); + log::info!(target: LOG_TARGET, "migrated {} member accounts.", old_members.len()); old_members .into_iter() .map(|(who, stake)| SeatHolder { who, stake, deposit: old_deposit }) @@ -162,7 +151,7 @@ pub fn migrate_runners_up_to_recorded_deposit(old_deposit: |maybe_old_runners_up| { maybe_old_runners_up.map(|old_runners_up| { log::info!( - target: "runtime::elections-phragmen", + target: LOG_TARGET, "migrated {} runner-up accounts.", old_runners_up.len(), ); diff --git a/frame/elections-phragmen/src/migrations/v4.rs b/frame/elections-phragmen/src/migrations/v4.rs index 76ef630706c50..535a9fb8201d7 100644 --- a/frame/elections-phragmen/src/migrations/v4.rs +++ b/frame/elections-phragmen/src/migrations/v4.rs @@ -17,6 +17,7 @@ //! Migrations to version [`4.0.0`], as denoted by the changelog. +use super::super::LOG_TARGET; use frame_support::{ traits::{Get, StorageVersion}, weights::Weight, @@ -35,14 +36,14 @@ pub const OLD_PREFIX: &[u8] = b"PhragmenElection"; pub fn migrate>(new_pallet_name: N) -> Weight { if new_pallet_name.as_ref().as_bytes() == OLD_PREFIX { log::info!( - target: "runtime::elections-phragmen", + target: LOG_TARGET, "New pallet name is equal to the old prefix. No migration needs to be done.", ); return Weight::zero() } let storage_version = StorageVersion::get::>(); log::info!( - target: "runtime::elections-phragmen", + target: LOG_TARGET, "Running migration to v4 for elections-phragmen with storage version {:?}", storage_version, ); @@ -59,7 +60,7 @@ pub fn migrate>(new_pallet_name: N) -> Weight { ::BlockWeights::get().max_block } else { log::warn!( - target: "runtime::elections-phragmen", + target: LOG_TARGET, "Attempted to apply migration to v4 but failed because storage version is {:?}", storage_version, ); diff --git a/frame/membership/src/lib.rs b/frame/membership/src/lib.rs index 8531af120ec88..934abb996df80 100644 --- a/frame/membership/src/lib.rs +++ b/frame/membership/src/lib.rs @@ -36,6 +36,8 @@ pub mod weights; pub use pallet::*; pub use weights::WeightInfo; +const LOG_TARGET: &str = "runtime::membership"; + type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; #[frame_support::pallet] diff --git a/frame/membership/src/migrations/v4.rs b/frame/membership/src/migrations/v4.rs index 5b8735aa2bac9..cbc58cd6ae917 100644 --- a/frame/membership/src/migrations/v4.rs +++ b/frame/membership/src/migrations/v4.rs @@ -15,6 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +use super::super::LOG_TARGET; use sp_io::hashing::twox_128; use frame_support::{ @@ -43,7 +44,7 @@ pub fn migrate::on_chain_storage_version(); log::info!( - target: "runtime::membership", + target: LOG_TARGET, "Running migration to v4 for membership with storage version {:?}", on_chain_storage_version, ); @@ -67,7 +68,7 @@ pub fn migrate::BlockWeights::get().max_block } else { log::warn!( - target: "runtime::membership", + target: LOG_TARGET, "Attempted to apply migration to v4 but failed because storage version is {:?}", on_chain_storage_version, ); @@ -139,7 +140,7 @@ pub fn post_migrate>(old_pallet_name: N, new fn log_migration(stage: &str, old_pallet_name: &str, new_pallet_name: &str) { log::info!( - target: "runtime::membership", + target: LOG_TARGET, "{}, prefix: '{}' ==> '{}'", stage, old_pallet_name, diff --git a/frame/session/src/migrations/v1.rs b/frame/session/src/migrations/v1.rs index c0dce422fe8b5..6689ca7299f1e 100644 --- a/frame/session/src/migrations/v1.rs +++ b/frame/session/src/migrations/v1.rs @@ -29,6 +29,8 @@ use frame_support::{ use crate::historical as pallet_session_historical; +const LOG_TARGET: &str = "runtime::session_historical"; + const OLD_PREFIX: &str = "Session"; /// Migrate the entire storage of this pallet to a new prefix. @@ -44,7 +46,7 @@ pub fn migrate::on_chain_storage_version(); log::info!( - target: "runtime::session_historical", + target: LOG_TARGET, "Running migration to v1 for session_historical with storage version {:?}", on_chain_storage_version, ); @@ -78,7 +80,7 @@ pub fn migrate::BlockWeights::get().max_block } else { log::warn!( - target: "runtime::session_historical", + target: LOG_TARGET, "Attempted to apply migration to v1 but failed because storage version is {:?}", on_chain_storage_version, ); @@ -184,7 +186,7 @@ pub fn post_migrate< fn log_migration(stage: &str, storage_prefix: &[u8], old_pallet_name: &str, new_pallet_name: &str) { log::info!( - target: "runtime::session_historical", + target: LOG_TARGET, "{} prefix of storage '{}': '{}' ==> '{}'", stage, str::from_utf8(storage_prefix).unwrap_or(""), diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index c790d33adddd7..3909b1e9c5257 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -129,6 +129,8 @@ pub use extensions::check_mortality::CheckMortality as CheckEra; pub use frame_support::dispatch::RawOrigin; pub use weights::WeightInfo; +const LOG_TARGET: &str = "runtime::system"; + /// Compute the trie root of a list of extrinsics. /// /// The merkle proof is using the same trie as runtime state with @@ -1075,7 +1077,7 @@ impl Pallet { if account.providers == 0 { // Logic error - cannot decrement beyond zero. log::error!( - target: "runtime::system", + target: LOG_TARGET, "Logic error: Unexpected underflow in reducing provider", ); account.providers = 1; @@ -1101,7 +1103,7 @@ impl Pallet { } } else { log::error!( - target: "runtime::system", + target: LOG_TARGET, "Logic error: Account already dead when reducing provider", ); Ok(DecRefStatus::Reaped) @@ -1133,7 +1135,7 @@ impl Pallet { if account.sufficients == 0 { // Logic error - cannot decrement beyond zero. log::error!( - target: "runtime::system", + target: LOG_TARGET, "Logic error: Unexpected underflow in reducing sufficients", ); } @@ -1150,7 +1152,7 @@ impl Pallet { } } else { log::error!( - target: "runtime::system", + target: LOG_TARGET, "Logic error: Account already dead when reducing provider", ); DecRefStatus::Reaped @@ -1215,7 +1217,7 @@ impl Pallet { a.consumers -= 1; } else { log::error!( - target: "runtime::system", + target: LOG_TARGET, "Logic error: Unexpected underflow in reducing consumer", ); } @@ -1337,7 +1339,7 @@ impl Pallet { /// resulting header for this block. pub fn finalize() -> T::Header { log::debug!( - target: "runtime::system", + target: LOG_TARGET, "[{:?}] {} extrinsics, length: {} (normal {}%, op: {}%, mandatory {}%) / normal weight:\ {} ({}%) op weight {} ({}%) / mandatory weight {} ({}%)", Self::block_number(), @@ -1547,7 +1549,7 @@ impl Pallet { Ok(_) => Event::ExtrinsicSuccess { dispatch_info: info }, Err(err) => { log::trace!( - target: "runtime::system", + target: LOG_TARGET, "Extrinsic failed at block({:?}): {:?}", Self::block_number(), err, diff --git a/frame/system/src/migrations/mod.rs b/frame/system/src/migrations/mod.rs index 15746d7376ac5..90b88de1ab11c 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 super::LOG_TARGET; use crate::{Config, Pallet}; use codec::{Decode, Encode, FullCodec}; use frame_support::{ @@ -75,7 +76,7 @@ pub fn migrate_from_single_u8_to_triple_ref_count() -> Wei Some(AccountInfo { nonce, consumers: rc as RefCount, providers: 1, sufficients: 0, data }) }); log::info!( - target: "runtime::system", + target: LOG_TARGET, "Applied migration from single u8 to triple reference counting to {:?} elements.", translated ); @@ -94,7 +95,7 @@ pub fn migrate_from_single_to_triple_ref_count() -> Weight }, ); log::info!( - target: "runtime::system", + target: LOG_TARGET, "Applied migration from single to triple reference counting to {:?} elements.", translated ); @@ -112,7 +113,7 @@ pub fn migrate_from_dual_to_triple_ref_count() -> Weight { }, ); log::info!( - target: "runtime::system", + target: LOG_TARGET, "Applied migration from dual to triple reference counting to {:?} elements.", translated ); diff --git a/frame/tips/src/lib.rs b/frame/tips/src/lib.rs index dd9ebc9813233..43002c7b5f196 100644 --- a/frame/tips/src/lib.rs +++ b/frame/tips/src/lib.rs @@ -78,6 +78,8 @@ use frame_support::{ pub use pallet::*; pub use weights::WeightInfo; +const LOG_TARGET: &str = "runtime::tips"; + pub type BalanceOf = pallet_treasury::BalanceOf; pub type NegativeImbalanceOf = pallet_treasury::NegativeImbalanceOf; type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; diff --git a/frame/tips/src/migrations/v4.rs b/frame/tips/src/migrations/v4.rs index 5e10fa7dd2c6d..0107e96a41168 100644 --- a/frame/tips/src/migrations/v4.rs +++ b/frame/tips/src/migrations/v4.rs @@ -18,6 +18,7 @@ use sp_io::hashing::twox_128; use sp_std::str; +use super::super::LOG_TARGET; use frame_support::{ storage::StoragePrefixedMap, traits::{ @@ -46,7 +47,7 @@ pub fn migrate::on_chain_storage_version(); log::info!( - target: "runtime::tips", + target: LOG_TARGET, "Running migration to v4 for tips with storage version {:?}", on_chain_storage_version, ); @@ -80,7 +81,7 @@ pub fn migrate::BlockWeights::get().max_block } else { log::warn!( - target: "runtime::tips", + target: LOG_TARGET, "Attempted to apply migration to v4 but failed because storage version is {:?}", on_chain_storage_version, ); @@ -185,7 +186,7 @@ pub fn post_migrate< fn log_migration(stage: &str, storage_prefix: &[u8], old_pallet_name: &str, new_pallet_name: &str) { log::info!( - target: "runtime::tips", + target: LOG_TARGET, "{} prefix of storage '{}': '{}' ==> '{}'", stage, str::from_utf8(storage_prefix).unwrap_or(""), diff --git a/frame/uniques/src/lib.rs b/frame/uniques/src/lib.rs index 6b21477be4340..da0f0e0560674 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; +const LOG_TARGET: &str = "runtime::uniques"; + type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; #[frame_support::pallet] diff --git a/frame/uniques/src/migration.rs b/frame/uniques/src/migration.rs index 8a2a0ef808d90..fd98c030d7f1b 100644 --- a/frame/uniques/src/migration.rs +++ b/frame/uniques/src/migration.rs @@ -24,7 +24,7 @@ pub fn migrate_to_v1, I: 'static, P: GetStorageVersion + PalletInfo ) -> frame_support::weights::Weight { let on_chain_storage_version =

::on_chain_storage_version(); log::info!( - target: "runtime::uniques", + target: LOG_TARGET, "Running migration storage v1 for uniques with storage version {:?}", on_chain_storage_version, ); @@ -37,7 +37,7 @@ pub fn migrate_to_v1, I: 'static, P: GetStorageVersion + PalletInfo } StorageVersion::new(1).put::

(); log::info!( - target: "runtime::uniques", + target: LOG_TARGET, "Running migration storage v1 for uniques with storage version {:?} was complete", on_chain_storage_version, ); @@ -45,7 +45,7 @@ pub fn migrate_to_v1, I: 'static, P: GetStorageVersion + PalletInfo T::DbWeight::get().reads_writes(count as u64 + 1, count as u64 + 1) } else { log::warn!( - target: "runtime::uniques", + target: LOG_TARGET, "Attempted to apply migration to v1 but failed because storage version is {:?}", on_chain_storage_version, ); From cb63d3dafc986faf5f2181288737ba8513253a02 Mon Sep 17 00:00:00 2001 From: Vladimir Istyufeev Date: Wed, 11 Jan 2023 01:08:28 +0400 Subject: [PATCH 274/715] Update tests for 1.66 and switch CI to stable Rust 1.66 (#13118) * Update UI tests for 1.66 * Fix `test_enum` assertion for Rust 1.66 * Fix another `test_enum` assertion for Rust 1.66 * Fix another `test_enum` assertion for Rust 1.66 * Fix another `test_enum` assertion for Rust 1.66 --- .gitlab-ci.yml | 2 +- .../construct_runtime_ui/invalid_module_details.stderr | 4 ++-- frame/support/test/tests/derive_no_bound.rs | 8 ++++---- .../test/tests/pallet_ui/call_invalid_return.stderr | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ecc27d016a811..90298297a89c6 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -48,7 +48,7 @@ variables: CARGO_INCREMENTAL: 0 DOCKER_OS: "debian:stretch" ARCH: "x86_64" - CI_IMAGE: "paritytech/ci-linux:production" + CI_IMAGE: "paritytech/ci-linux@sha256:9140bc3c843a8b12a3bcf6f5886346536092795bbadfd7f1836362cb28dfcc71" BUILDAH_IMAGE: "quay.io/buildah/stable:v1.27" RUSTY_CACHIER_SINGLE_BRANCH: master RUSTY_CACHIER_DONT_OPERATE_ON_MAIN_BRANCH: "true" 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 db96b8749ca11..0a20cf4e39a88 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: Unexpected tokens, expected one of `::$ident` `::{`, `exclude_parts`, `use_parts`, `=`, `,` - --> $DIR/invalid_module_details.rs:9:17 + --> tests/construct_runtime_ui/invalid_module_details.rs:9:17 | 9 | system: System::(), - | ^^ + | ^ diff --git a/frame/support/test/tests/derive_no_bound.rs b/frame/support/test/tests/derive_no_bound.rs index f891b3a2d2db8..9162b5013bcdc 100644 --- a/frame/support/test/tests/derive_no_bound.rs +++ b/frame/support/test/tests/derive_no_bound.rs @@ -72,7 +72,7 @@ fn test_struct_named() { assert_eq!(a_2, a_1); assert_eq!( format!("{:?}", a_1), - String::from("StructNamed { a: 1, b: 2, c: 3, phantom: PhantomData }") + String::from("StructNamed { a: 1, b: 2, c: 3, phantom: PhantomData<(derive_no_bound::ImplNone, derive_no_bound::ImplNone)> }") ); let b = StructNamed:: { @@ -103,7 +103,7 @@ fn test_struct_unnamed() { assert_eq!(a_2.1, 2); assert_eq!(a_2.2, 3); assert_eq!(a_2, a_1); - assert_eq!(format!("{:?}", a_1), String::from("StructUnnamed(1, 2, 3, PhantomData)")); + assert_eq!(format!("{:?}", a_1), String::from("StructUnnamed(1, 2, 3, PhantomData<(derive_no_bound::ImplNone, derive_no_bound::ImplNone)>)")); let b = StructUnnamed::(1, 2, 4, Default::default()); @@ -211,11 +211,11 @@ fn test_enum() { assert_eq!( format!("{:?}", variant_0), - String::from("Enum::VariantUnnamed(1, 2, 3, PhantomData)"), + String::from("Enum::VariantUnnamed(1, 2, 3, PhantomData<(derive_no_bound::ImplNone, derive_no_bound::ImplNone)>)"), ); assert_eq!( format!("{:?}", variant_1), - String::from("Enum::VariantNamed { a: 1, b: 2, c: 3, phantom: PhantomData }"), + String::from("Enum::VariantNamed { a: 1, b: 2, c: 3, phantom: PhantomData<(derive_no_bound::ImplNone, derive_no_bound::ImplNone)> }"), ); assert_eq!(format!("{:?}", variant_2), String::from("Enum::VariantUnit")); assert_eq!(format!("{:?}", variant_3), String::from("Enum::VariantUnit2")); diff --git a/frame/support/test/tests/pallet_ui/call_invalid_return.stderr b/frame/support/test/tests/pallet_ui/call_invalid_return.stderr index 6a851ed3fc283..8803bbba01326 100644 --- a/frame/support/test/tests/pallet_ui/call_invalid_return.stderr +++ b/frame/support/test/tests/pallet_ui/call_invalid_return.stderr @@ -1,5 +1,5 @@ error: expected `DispatchResultWithPostInfo` or `DispatchResult` - --> $DIR/call_invalid_return.rs:17:39 + --> tests/pallet_ui/call_invalid_return.rs:17:39 | 17 | pub fn foo(origin: OriginFor) -> ::DispatchResult { todo!() } - | ^^ + | ^ From 946507ba9ef13e263534176b7b74e26fc56efbd4 Mon Sep 17 00:00:00 2001 From: JP <77391175+joao-paulo-parity@users.noreply.github.com> Date: Wed, 11 Jan 2023 06:03:24 -0300 Subject: [PATCH 275/715] remove update-node-template (#13100) will be moved to polkadot's pipeline ref https://github.com/paritytech/release-engineering/issues/142 --- scripts/ci/gitlab/pipeline/publish.yml | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/scripts/ci/gitlab/pipeline/publish.yml b/scripts/ci/gitlab/pipeline/publish.yml index dff1b508625fb..d1a7514d1707b 100644 --- a/scripts/ci/gitlab/pipeline/publish.yml +++ b/scripts/ci/gitlab/pipeline/publish.yml @@ -182,20 +182,6 @@ publish-draft-release: - ./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" - .publish-crates-template: stage: publish extends: .crates-publishing-template From 2c029fd0cb1ca710c74363b4a3f359577dcc51cf Mon Sep 17 00:00:00 2001 From: Green Baneling Date: Wed, 11 Jan 2023 13:22:22 +0000 Subject: [PATCH 276/715] Allow duplicate topics in smart contract events (#13065) * Removed `has_duplicates` check form the `deposit_event`. Removed the usage of `Error::DuplicateTopics`. * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_contracts Co-authored-by: command-bot <> --- frame/contracts/src/lib.rs | 2 - frame/contracts/src/wasm/mod.rs | 56 +- frame/contracts/src/wasm/runtime.rs | 18 +- frame/contracts/src/weights.rs | 1874 ++++++++++++++------------- 4 files changed, 972 insertions(+), 978 deletions(-) diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index 9df790e09a1e8..9efeec65f51f5 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -816,8 +816,6 @@ pub mod pallet { RandomSubjectTooLong, /// The amount of topics passed to `seal_deposit_events` exceeds the limit. TooManyTopics, - /// The topics passed to `seal_deposit_events` contains at least one duplicate. - DuplicateTopics, /// The chain does not provide a chain extension. Calling the chain extension results /// in this error. Note that this usually shouldn't happen as deploying such contracts /// is rejected. diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index f1d0ccc7c216b..b540b3deb448d 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -1988,7 +1988,7 @@ mod tests { assert!(mock_ext.gas_meter.gas_left().ref_time() > 0); } - const CODE_DEPOSIT_EVENT_MAX_TOPICS: &str = r#" + const CODE_DEPOSIT_EVENT_DUPLICATES: &str = r#" (module (import "seal0" "seal_deposit_event" (func $seal_deposit_event (param i32 i32 i32 i32))) (import "env" "memory" (memory 1 1)) @@ -1996,7 +1996,7 @@ mod tests { (func (export "call") (call $seal_deposit_event (i32.const 32) ;; Pointer to the start of topics buffer - (i32.const 161) ;; The length of the topics buffer. + (i32.const 129) ;; The length of the topics buffer. (i32.const 8) ;; Pointer to the start of the data buffer (i32.const 13) ;; Length of the buffer ) @@ -2005,29 +2005,36 @@ mod tests { (data (i32.const 8) "\00\01\2A\00\00\00\00\00\00\00\E5\14\00") - ;; Encoded Vec>, the buffer has length of 161 bytes. - (data (i32.const 32) "\14" + ;; Encoded Vec>, the buffer has length of 129 bytes. + (data (i32.const 32) "\10" "\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01" "\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02" -"\03\03\03\03\03\03\03\03\03\03\03\03\03\03\03\03\03\03\03\03\03\03\03\03\03\03\03\03\03\03\03\03" -"\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04" -"\05\05\05\05\05\05\05\05\05\05\05\05\05\05\05\05\05\05\05\05\05\05\05\05\05\05\05\05\05\05\05\05") +"\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01" +"\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04") ) "#; - /// Checks that the runtime traps if there are more than `max_topic_events` topics. + /// Checks that the runtime allows duplicate topics. #[test] - fn deposit_event_max_topics() { + fn deposit_event_duplicates_allowed() { + let mut mock_ext = MockExt::default(); + assert_ok!(execute(CODE_DEPOSIT_EVENT_DUPLICATES, vec![], &mut mock_ext,)); + assert_eq!( - execute(CODE_DEPOSIT_EVENT_MAX_TOPICS, vec![], MockExt::default(),), - Err(ExecError { - error: Error::::TooManyTopics.into(), - origin: ErrorOrigin::Caller, - }) + mock_ext.events, + vec![( + vec![ + H256::repeat_byte(0x01), + H256::repeat_byte(0x02), + H256::repeat_byte(0x01), + H256::repeat_byte(0x04) + ], + vec![0x00, 0x01, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe5, 0x14, 0x00] + )] ); } - const CODE_DEPOSIT_EVENT_DUPLICATES: &str = r#" + const CODE_DEPOSIT_EVENT_MAX_TOPICS: &str = r#" (module (import "seal0" "seal_deposit_event" (func $seal_deposit_event (param i32 i32 i32 i32))) (import "env" "memory" (memory 1 1)) @@ -2035,7 +2042,7 @@ mod tests { (func (export "call") (call $seal_deposit_event (i32.const 32) ;; Pointer to the start of topics buffer - (i32.const 129) ;; The length of the topics buffer. + (i32.const 161) ;; The length of the topics buffer. (i32.const 8) ;; Pointer to the start of the data buffer (i32.const 13) ;; Length of the buffer ) @@ -2044,22 +2051,23 @@ mod tests { (data (i32.const 8) "\00\01\2A\00\00\00\00\00\00\00\E5\14\00") - ;; Encoded Vec>, the buffer has length of 129 bytes. - (data (i32.const 32) "\10" + ;; Encoded Vec>, the buffer has length of 161 bytes. + (data (i32.const 32) "\14" "\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01" "\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02" -"\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01" -"\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04") +"\03\03\03\03\03\03\03\03\03\03\03\03\03\03\03\03\03\03\03\03\03\03\03\03\03\03\03\03\03\03\03\03" +"\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04" +"\05\05\05\05\05\05\05\05\05\05\05\05\05\05\05\05\05\05\05\05\05\05\05\05\05\05\05\05\05\05\05\05") ) "#; - /// Checks that the runtime traps if there are duplicates. + /// Checks that the runtime traps if there are more than `max_topic_events` topics. #[test] - fn deposit_event_duplicates() { + fn deposit_event_max_topics() { assert_eq!( - execute(CODE_DEPOSIT_EVENT_DUPLICATES, vec![], MockExt::default(),), + execute(CODE_DEPOSIT_EVENT_MAX_TOPICS, vec![], MockExt::default(),), Err(ExecError { - error: Error::::DuplicateTopics.into(), + error: Error::::TooManyTopics.into(), origin: ErrorOrigin::Caller, }) ); diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index 098f8d280e6a9..b5398bb6206c5 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -2085,15 +2085,6 @@ pub mod env { data_ptr: u32, data_len: u32, ) -> Result<(), TrapReason> { - fn has_duplicates(items: &mut Vec) -> bool { - items.sort(); - // Find any two consecutive equal elements. - 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")?; @@ -2102,7 +2093,7 @@ pub mod env { return Err(Error::::ValueTooLarge.into()) } - let mut topics: Vec::T>> = match topics_len { + let topics: Vec::T>> = match topics_len { 0 => Vec::new(), _ => ctx.read_sandbox_memory_as_unbounded(memory, topics_ptr, topics_len)?, }; @@ -2112,13 +2103,6 @@ pub mod env { 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()) - } - let event_data = ctx.read_sandbox_memory(memory, data_ptr, data_len)?; ctx.ext.deposit_event(topics, event_data); diff --git a/frame/contracts/src/weights.rs b/frame/contracts/src/weights.rs index 69fcbd6eec983..7ae1a9c594671 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-12-09, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-01-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 @@ -172,17 +172,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_196 nanoseconds. - Weight::from_ref_time(3_293_000) + // Minimum execution time: 3_326 nanoseconds. + Weight::from_ref_time(3_433_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: 14_857 nanoseconds. - Weight::from_ref_time(14_957_593) - // Standard Error: 1_015 - .saturating_add(Weight::from_ref_time(935_359).saturating_mul(k.into())) + // Minimum execution time: 15_703 nanoseconds. + Weight::from_ref_time(15_288_927) + // Standard Error: 951 + .saturating_add(Weight::from_ref_time(940_816).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()))) @@ -190,10 +190,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_231 nanoseconds. - Weight::from_ref_time(14_859_580) - // Standard Error: 3_479 - .saturating_add(Weight::from_ref_time(1_185_600).saturating_mul(q.into())) + // Minimum execution time: 3_548 nanoseconds. + Weight::from_ref_time(15_764_121) + // Standard Error: 3_339 + .saturating_add(Weight::from_ref_time(1_214_890).saturating_mul(q.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -201,10 +201,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: 34_565 nanoseconds. - Weight::from_ref_time(29_199_016) - // Standard Error: 70 - .saturating_add(Weight::from_ref_time(47_107).saturating_mul(c.into())) + // Minimum execution time: 29_801 nanoseconds. + Weight::from_ref_time(27_932_706) + // Standard Error: 49 + .saturating_add(Weight::from_ref_time(50_532).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -215,10 +215,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: 392_074 nanoseconds. - Weight::from_ref_time(404_090_909) - // Standard Error: 24 - .saturating_add(Weight::from_ref_time(30_454).saturating_mul(c.into())) + // Minimum execution time: 307_894 nanoseconds. + Weight::from_ref_time(322_346_319) + // Standard Error: 25 + .saturating_add(Weight::from_ref_time(30_678).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -234,14 +234,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `i` is `[0, 1048576]`. /// The range of component `s` is `[0, 1048576]`. fn instantiate_with_code(c: u32, i: u32, s: u32, ) -> Weight { - // Minimum execution time: 3_785_934 nanoseconds. - Weight::from_ref_time(683_143_843) - // Standard Error: 272 - .saturating_add(Weight::from_ref_time(87_620).saturating_mul(c.into())) + // Minimum execution time: 3_610_424 nanoseconds. + Weight::from_ref_time(583_426_386) + // Standard Error: 277 + .saturating_add(Weight::from_ref_time(90_224).saturating_mul(c.into())) // Standard Error: 16 - .saturating_add(Weight::from_ref_time(1_363).saturating_mul(i.into())) + .saturating_add(Weight::from_ref_time(1_325).saturating_mul(i.into())) // Standard Error: 16 - .saturating_add(Weight::from_ref_time(1_778).saturating_mul(s.into())) + .saturating_add(Weight::from_ref_time(1_727).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(9)) } @@ -255,12 +255,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `i` is `[0, 1048576]`. /// The range of component `s` is `[0, 1048576]`. fn instantiate(i: u32, s: u32, ) -> Weight { - // Minimum execution time: 1_935_310 nanoseconds. - Weight::from_ref_time(203_531_122) + // Minimum execution time: 1_892_996 nanoseconds. + Weight::from_ref_time(202_958_196) // Standard Error: 8 - .saturating_add(Weight::from_ref_time(1_674).saturating_mul(i.into())) + .saturating_add(Weight::from_ref_time(1_627).saturating_mul(i.into())) // Standard Error: 8 - .saturating_add(Weight::from_ref_time(1_789).saturating_mul(s.into())) + .saturating_add(Weight::from_ref_time(1_755).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(7)) } @@ -270,8 +270,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: 151_999 nanoseconds. - Weight::from_ref_time(153_527_000) + // Minimum execution time: 157_347 nanoseconds. + Weight::from_ref_time(159_084_000) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -281,10 +281,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: 391_165 nanoseconds. - Weight::from_ref_time(394_519_487) - // Standard Error: 75 - .saturating_add(Weight::from_ref_time(89_736).saturating_mul(c.into())) + // Minimum execution time: 299_987 nanoseconds. + Weight::from_ref_time(305_274_879) + // Standard Error: 72 + .saturating_add(Weight::from_ref_time(91_916).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -293,8 +293,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: 39_354 nanoseconds. - Weight::from_ref_time(39_855_000) + // Minimum execution time: 40_795 nanoseconds. + Weight::from_ref_time(41_297_000) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -302,8 +302,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_909 nanoseconds. - Weight::from_ref_time(41_275_000) + // Minimum execution time: 41_957 nanoseconds. + Weight::from_ref_time(42_536_000) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(6)) } @@ -314,10 +314,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: 380_150 nanoseconds. - Weight::from_ref_time(384_429_035) - // Standard Error: 34_740 - .saturating_add(Weight::from_ref_time(15_582_218).saturating_mul(r.into())) + // Minimum execution time: 293_544 nanoseconds. + Weight::from_ref_time(298_981_222) + // Standard Error: 39_139 + .saturating_add(Weight::from_ref_time(17_278_436).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -328,10 +328,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: 380_608 nanoseconds. - Weight::from_ref_time(326_544_805) - // Standard Error: 475_381 - .saturating_add(Weight::from_ref_time(190_717_772).saturating_mul(r.into())) + // Minimum execution time: 293_500 nanoseconds. + Weight::from_ref_time(237_825_284) + // Standard Error: 450_234 + .saturating_add(Weight::from_ref_time(198_995_806).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)) @@ -343,10 +343,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: 382_780 nanoseconds. - Weight::from_ref_time(333_775_113) - // Standard Error: 446_086 - .saturating_add(Weight::from_ref_time(232_531_042).saturating_mul(r.into())) + // Minimum execution time: 295_851 nanoseconds. + Weight::from_ref_time(258_113_447) + // Standard Error: 408_747 + .saturating_add(Weight::from_ref_time(237_490_216).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)) @@ -358,10 +358,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: 381_815 nanoseconds. - Weight::from_ref_time(390_931_793) - // Standard Error: 61_918 - .saturating_add(Weight::from_ref_time(18_798_438).saturating_mul(r.into())) + // Minimum execution time: 294_614 nanoseconds. + Weight::from_ref_time(301_528_998) + // Standard Error: 40_613 + .saturating_add(Weight::from_ref_time(20_815_088).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -372,10 +372,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: 379_162 nanoseconds. - Weight::from_ref_time(383_796_363) - // Standard Error: 25_555 - .saturating_add(Weight::from_ref_time(10_843_721).saturating_mul(r.into())) + // Minimum execution time: 293_088 nanoseconds. + Weight::from_ref_time(299_120_595) + // Standard Error: 23_277 + .saturating_add(Weight::from_ref_time(11_130_334).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -386,10 +386,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: 380_307 nanoseconds. - Weight::from_ref_time(390_211_779) - // Standard Error: 53_326 - .saturating_add(Weight::from_ref_time(15_311_171).saturating_mul(r.into())) + // Minimum execution time: 295_110 nanoseconds. + Weight::from_ref_time(305_295_787) + // Standard Error: 48_521 + .saturating_add(Weight::from_ref_time(16_610_806).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -400,10 +400,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: 380_230 nanoseconds. - Weight::from_ref_time(383_470_453) - // Standard Error: 45_007 - .saturating_add(Weight::from_ref_time(15_582_472).saturating_mul(r.into())) + // Minimum execution time: 293_414 nanoseconds. + Weight::from_ref_time(299_960_283) + // Standard Error: 32_003 + .saturating_add(Weight::from_ref_time(16_652_433).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -414,10 +414,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: 380_244 nanoseconds. - Weight::from_ref_time(388_092_461) - // Standard Error: 98_199 - .saturating_add(Weight::from_ref_time(97_339_528).saturating_mul(r.into())) + // Minimum execution time: 292_429 nanoseconds. + Weight::from_ref_time(301_025_128) + // Standard Error: 92_155 + .saturating_add(Weight::from_ref_time(92_731_719).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -428,10 +428,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: 380_242 nanoseconds. - Weight::from_ref_time(384_078_258) - // Standard Error: 28_510 - .saturating_add(Weight::from_ref_time(15_423_359).saturating_mul(r.into())) + // Minimum execution time: 293_516 nanoseconds. + Weight::from_ref_time(300_071_428) + // Standard Error: 25_871 + .saturating_add(Weight::from_ref_time(16_599_369).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -442,10 +442,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: 379_890 nanoseconds. - Weight::from_ref_time(383_658_430) - // Standard Error: 44_976 - .saturating_add(Weight::from_ref_time(15_451_905).saturating_mul(r.into())) + // Minimum execution time: 293_666 nanoseconds. + Weight::from_ref_time(299_803_599) + // Standard Error: 24_508 + .saturating_add(Weight::from_ref_time(16_500_973).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -456,10 +456,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: 380_269 nanoseconds. - Weight::from_ref_time(383_580_481) - // Standard Error: 31_862 - .saturating_add(Weight::from_ref_time(15_230_473).saturating_mul(r.into())) + // Minimum execution time: 289_193 nanoseconds. + Weight::from_ref_time(297_946_784) + // Standard Error: 43_719 + .saturating_add(Weight::from_ref_time(16_442_254).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -470,10 +470,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: 380_308 nanoseconds. - Weight::from_ref_time(383_732_372) - // Standard Error: 38_359 - .saturating_add(Weight::from_ref_time(15_358_775).saturating_mul(r.into())) + // Minimum execution time: 288_897 nanoseconds. + Weight::from_ref_time(298_856_658) + // Standard Error: 31_003 + .saturating_add(Weight::from_ref_time(16_490_508).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -485,10 +485,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: 380_834 nanoseconds. - Weight::from_ref_time(388_999_459) - // Standard Error: 96_447 - .saturating_add(Weight::from_ref_time(86_714_414).saturating_mul(r.into())) + // Minimum execution time: 289_850 nanoseconds. + Weight::from_ref_time(302_898_449) + // Standard Error: 92_822 + .saturating_add(Weight::from_ref_time(86_376_874).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -499,10 +499,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: 140_955 nanoseconds. - Weight::from_ref_time(144_716_423) - // Standard Error: 11_370 - .saturating_add(Weight::from_ref_time(7_858_807).saturating_mul(r.into())) + // Minimum execution time: 145_105 nanoseconds. + Weight::from_ref_time(152_388_934) + // Standard Error: 29_988 + .saturating_add(Weight::from_ref_time(7_761_947).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -513,10 +513,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: 380_210 nanoseconds. - Weight::from_ref_time(384_185_776) - // Standard Error: 49_038 - .saturating_add(Weight::from_ref_time(13_649_793).saturating_mul(r.into())) + // Minimum execution time: 289_319 nanoseconds. + Weight::from_ref_time(298_390_911) + // Standard Error: 27_329 + .saturating_add(Weight::from_ref_time(14_225_527).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -527,10 +527,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: 396_209 nanoseconds. - Weight::from_ref_time(424_522_611) - // Standard Error: 3_917 - .saturating_add(Weight::from_ref_time(9_627_216).saturating_mul(n.into())) + // Minimum execution time: 305_538 nanoseconds. + Weight::from_ref_time(339_734_596) + // Standard Error: 4_636 + .saturating_add(Weight::from_ref_time(9_592_149).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -541,10 +541,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: 378_412 nanoseconds. - Weight::from_ref_time(380_502_085) - // Standard Error: 201_552 - .saturating_add(Weight::from_ref_time(1_434_214).saturating_mul(r.into())) + // Minimum execution time: 287_189 nanoseconds. + Weight::from_ref_time(295_472_383) + // Standard Error: 314_142 + .saturating_add(Weight::from_ref_time(214_016).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -555,10 +555,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: 381_463 nanoseconds. - Weight::from_ref_time(383_955_553) - // Standard Error: 998 - .saturating_add(Weight::from_ref_time(230_512).saturating_mul(n.into())) + // Minimum execution time: 289_380 nanoseconds. + Weight::from_ref_time(296_302_404) + // Standard Error: 889 + .saturating_add(Weight::from_ref_time(190_017).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -571,10 +571,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: 379_877 nanoseconds. - Weight::from_ref_time(381_729_546) - // Standard Error: 214_004 - .saturating_add(Weight::from_ref_time(52_528_353).saturating_mul(r.into())) + // Minimum execution time: 292_383 nanoseconds. + Weight::from_ref_time(297_557_691) + // Standard Error: 251_228 + .saturating_add(Weight::from_ref_time(56_688_008).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)) @@ -588,10 +588,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: 380_275 nanoseconds. - Weight::from_ref_time(386_495_777) - // Standard Error: 94_674 - .saturating_add(Weight::from_ref_time(108_432_929).saturating_mul(r.into())) + // Minimum execution time: 293_019 nanoseconds. + Weight::from_ref_time(301_747_439) + // Standard Error: 92_043 + .saturating_add(Weight::from_ref_time(109_861_144).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -602,10 +602,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: 379_095 nanoseconds. - Weight::from_ref_time(393_997_924) - // Standard Error: 141_916 - .saturating_add(Weight::from_ref_time(212_937_170).saturating_mul(r.into())) + // Minimum execution time: 287_586 nanoseconds. + Weight::from_ref_time(304_751_302) + // Standard Error: 127_698 + .saturating_add(Weight::from_ref_time(221_525_053).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -617,12 +617,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_241_001 nanoseconds. - Weight::from_ref_time(548_526_917) - // Standard Error: 496_807 - .saturating_add(Weight::from_ref_time(177_087_769).saturating_mul(t.into())) - // Standard Error: 136_447 - .saturating_add(Weight::from_ref_time(71_558_402).saturating_mul(n.into())) + // Minimum execution time: 1_182_204 nanoseconds. + Weight::from_ref_time(508_607_957) + // Standard Error: 503_533 + .saturating_add(Weight::from_ref_time(173_998_655).saturating_mul(t.into())) + // Standard Error: 138_294 + .saturating_add(Weight::from_ref_time(67_991_373).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)) @@ -635,20 +635,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: 159_158 nanoseconds. - Weight::from_ref_time(163_427_712) - // Standard Error: 22_442 - .saturating_add(Weight::from_ref_time(12_647_838).saturating_mul(r.into())) + // Minimum execution time: 157_706 nanoseconds. + Weight::from_ref_time(161_895_583) + // Standard Error: 14_952 + .saturating_add(Weight::from_ref_time(12_990_237).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: 381_068 nanoseconds. - Weight::from_ref_time(341_041_230) - // Standard Error: 464_053 - .saturating_add(Weight::from_ref_time(402_677_314).saturating_mul(r.into())) + // Minimum execution time: 290_063 nanoseconds. + Weight::from_ref_time(256_404_853) + // Standard Error: 436_195 + .saturating_add(Weight::from_ref_time(406_569_743).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)) @@ -657,10 +657,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: 508_695 nanoseconds. - Weight::from_ref_time(663_159_695) - // Standard Error: 1_419_342 - .saturating_add(Weight::from_ref_time(96_558_570).saturating_mul(n.into())) + // Minimum execution time: 426_295 nanoseconds. + Weight::from_ref_time(582_989_911) + // Standard Error: 1_404_141 + .saturating_add(Weight::from_ref_time(89_545_963).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)) @@ -669,10 +669,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: 508_542 nanoseconds. - Weight::from_ref_time(634_146_978) - // Standard Error: 1_168_252 - .saturating_add(Weight::from_ref_time(64_231_947).saturating_mul(n.into())) + // Minimum execution time: 425_062 nanoseconds. + Weight::from_ref_time(552_380_900) + // Standard Error: 1_140_169 + .saturating_add(Weight::from_ref_time(64_085_108).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)) @@ -681,10 +681,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: 381_743 nanoseconds. - Weight::from_ref_time(337_309_674) - // Standard Error: 527_407 - .saturating_add(Weight::from_ref_time(395_767_068).saturating_mul(r.into())) + // Minimum execution time: 294_421 nanoseconds. + Weight::from_ref_time(260_897_072) + // Standard Error: 474_135 + .saturating_add(Weight::from_ref_time(403_191_862).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)) @@ -693,10 +693,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: 478_283 nanoseconds. - Weight::from_ref_time(616_673_245) - // Standard Error: 1_290_784 - .saturating_add(Weight::from_ref_time(66_534_552).saturating_mul(n.into())) + // Minimum execution time: 391_743 nanoseconds. + Weight::from_ref_time(535_327_545) + // Standard Error: 1_297_157 + .saturating_add(Weight::from_ref_time(67_222_981).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)) @@ -705,10 +705,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: 381_916 nanoseconds. - Weight::from_ref_time(349_150_912) - // Standard Error: 443_388 - .saturating_add(Weight::from_ref_time(316_975_558).saturating_mul(r.into())) + // Minimum execution time: 294_947 nanoseconds. + Weight::from_ref_time(266_280_887) + // Standard Error: 382_477 + .saturating_add(Weight::from_ref_time(323_306_898).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)) @@ -716,10 +716,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: 459_294 nanoseconds. - Weight::from_ref_time(579_698_524) - // Standard Error: 1_111_681 - .saturating_add(Weight::from_ref_time(159_276_087).saturating_mul(n.into())) + // Minimum execution time: 375_487 nanoseconds. + Weight::from_ref_time(497_019_365) + // Standard Error: 1_141_672 + .saturating_add(Weight::from_ref_time(152_354_482).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)) @@ -727,10 +727,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: 381_700 nanoseconds. - Weight::from_ref_time(352_544_675) - // Standard Error: 401_504 - .saturating_add(Weight::from_ref_time(304_380_106).saturating_mul(r.into())) + // Minimum execution time: 294_716 nanoseconds. + Weight::from_ref_time(266_187_186) + // Standard Error: 395_323 + .saturating_add(Weight::from_ref_time(309_907_221).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)) @@ -738,10 +738,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: 455_595 nanoseconds. - Weight::from_ref_time(560_428_166) - // Standard Error: 991_088 - .saturating_add(Weight::from_ref_time(61_810_610).saturating_mul(n.into())) + // Minimum execution time: 371_667 nanoseconds. + Weight::from_ref_time(478_075_482) + // Standard Error: 979_116 + .saturating_add(Weight::from_ref_time(62_075_707).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)) @@ -749,10 +749,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: 382_000 nanoseconds. - Weight::from_ref_time(336_164_219) - // Standard Error: 601_744 - .saturating_add(Weight::from_ref_time(406_198_079).saturating_mul(r.into())) + // Minimum execution time: 292_147 nanoseconds. + Weight::from_ref_time(254_374_598) + // Standard Error: 442_367 + .saturating_add(Weight::from_ref_time(413_674_705).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)) @@ -761,10 +761,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: 482_335 nanoseconds. - Weight::from_ref_time(634_245_177) - // Standard Error: 1_418_845 - .saturating_add(Weight::from_ref_time(164_352_113).saturating_mul(n.into())) + // Minimum execution time: 398_554 nanoseconds. + Weight::from_ref_time(553_715_911) + // Standard Error: 1_415_272 + .saturating_add(Weight::from_ref_time(158_254_544).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)) @@ -777,10 +777,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: 382_142 nanoseconds. - Weight::from_ref_time(317_581_708) - // Standard Error: 682_156 - .saturating_add(Weight::from_ref_time(1_305_289_569).saturating_mul(r.into())) + // Minimum execution time: 295_081 nanoseconds. + Weight::from_ref_time(253_461_581) + // Standard Error: 740_198 + .saturating_add(Weight::from_ref_time(1_369_153_623).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)) @@ -793,10 +793,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: 383_580 nanoseconds. - Weight::from_ref_time(384_176_000) - // Standard Error: 6_483_482 - .saturating_add(Weight::from_ref_time(28_047_685_517).saturating_mul(r.into())) + // Minimum execution time: 296_089 nanoseconds. + Weight::from_ref_time(297_193_000) + // Standard Error: 6_571_547 + .saturating_add(Weight::from_ref_time(21_080_280_397).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)) @@ -809,10 +809,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: 384_523 nanoseconds. - Weight::from_ref_time(385_105_000) - // Standard Error: 6_156_142 - .saturating_add(Weight::from_ref_time(27_780_652_513).saturating_mul(r.into())) + // Minimum execution time: 296_828 nanoseconds. + Weight::from_ref_time(297_685_000) + // Standard Error: 6_864_880 + .saturating_add(Weight::from_ref_time(20_770_321_946).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)) @@ -826,12 +826,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: 9_509_961 nanoseconds. - Weight::from_ref_time(8_509_991_348) - // Standard Error: 6_614_757 - .saturating_add(Weight::from_ref_time(1_244_514_376).saturating_mul(t.into())) - // Standard Error: 9_918 - .saturating_add(Weight::from_ref_time(9_856_517).saturating_mul(c.into())) + // Minimum execution time: 9_824_671 nanoseconds. + Weight::from_ref_time(8_713_861_450) + // Standard Error: 7_388_925 + .saturating_add(Weight::from_ref_time(1_327_819_806).saturating_mul(t.into())) + // Standard Error: 11_079 + .saturating_add(Weight::from_ref_time(9_789_514).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)) @@ -846,10 +846,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: 384_604 nanoseconds. - Weight::from_ref_time(385_278_000) - // Standard Error: 21_140_468 - .saturating_add(Weight::from_ref_time(33_100_726_150).saturating_mul(r.into())) + // Minimum execution time: 293_374 nanoseconds. + Weight::from_ref_time(302_067_000) + // Standard Error: 20_137_097 + .saturating_add(Weight::from_ref_time(26_444_812_817).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)) @@ -866,12 +866,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `i` is `[0, 960]`. /// The range of component `s` is `[0, 960]`. fn seal_instantiate_per_transfer_input_salt_kb(t: u32, i: u32, s: u32, ) -> Weight { - // Minimum execution time: 129_699_480 nanoseconds. - Weight::from_ref_time(10_187_699_005) - // Standard Error: 155_040 - .saturating_add(Weight::from_ref_time(125_284_310).saturating_mul(i.into())) - // Standard Error: 155_040 - .saturating_add(Weight::from_ref_time(125_850_564).saturating_mul(s.into())) + // Minimum execution time: 126_456_770 nanoseconds. + Weight::from_ref_time(9_223_715_752) + // Standard Error: 96_040_318 + .saturating_add(Weight::from_ref_time(19_550_519).saturating_mul(t.into())) + // Standard Error: 156_614 + .saturating_add(Weight::from_ref_time(122_958_298).saturating_mul(i.into())) + // Standard Error: 156_614 + .saturating_add(Weight::from_ref_time(123_316_079).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)) @@ -884,10 +886,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: 380_397 nanoseconds. - Weight::from_ref_time(382_881_855) - // Standard Error: 290_948 - .saturating_add(Weight::from_ref_time(41_017_644).saturating_mul(r.into())) + // Minimum execution time: 289_275 nanoseconds. + Weight::from_ref_time(297_803_961) + // Standard Error: 303_405 + .saturating_add(Weight::from_ref_time(40_800_138).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -898,10 +900,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: 422_439 nanoseconds. - Weight::from_ref_time(423_480_000) - // Standard Error: 56_072 - .saturating_add(Weight::from_ref_time(329_103_825).saturating_mul(n.into())) + // Minimum execution time: 336_077 nanoseconds. + Weight::from_ref_time(336_846_000) + // Standard Error: 51_610 + .saturating_add(Weight::from_ref_time(322_208_787).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -912,10 +914,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: 380_433 nanoseconds. - Weight::from_ref_time(382_325_624) - // Standard Error: 139_248 - .saturating_add(Weight::from_ref_time(53_159_175).saturating_mul(r.into())) + // Minimum execution time: 290_189 nanoseconds. + Weight::from_ref_time(298_454_259) + // Standard Error: 252_946 + .saturating_add(Weight::from_ref_time(55_034_240).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -926,10 +928,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: 434_834 nanoseconds. - Weight::from_ref_time(435_383_000) - // Standard Error: 59_824 - .saturating_add(Weight::from_ref_time(251_297_967).saturating_mul(n.into())) + // Minimum execution time: 350_030 nanoseconds. + Weight::from_ref_time(351_356_000) + // Standard Error: 57_422 + .saturating_add(Weight::from_ref_time(256_912_844).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -940,10 +942,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: 379_088 nanoseconds. - Weight::from_ref_time(381_627_077) - // Standard Error: 152_561 - .saturating_add(Weight::from_ref_time(31_696_922).saturating_mul(r.into())) + // Minimum execution time: 288_480 nanoseconds. + Weight::from_ref_time(297_613_263) + // Standard Error: 456_736 + .saturating_add(Weight::from_ref_time(38_100_936).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -954,10 +956,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: 411_630 nanoseconds. - Weight::from_ref_time(412_354_000) - // Standard Error: 50_788 - .saturating_add(Weight::from_ref_time(103_105_715).saturating_mul(n.into())) + // Minimum execution time: 321_195 nanoseconds. + Weight::from_ref_time(325_561_000) + // Standard Error: 46_289 + .saturating_add(Weight::from_ref_time(99_536_902).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -968,10 +970,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: 379_549 nanoseconds. - Weight::from_ref_time(382_406_346) - // Standard Error: 701_449 - .saturating_add(Weight::from_ref_time(31_066_353).saturating_mul(r.into())) + // Minimum execution time: 287_659 nanoseconds. + Weight::from_ref_time(295_963_340) + // Standard Error: 433_889 + .saturating_add(Weight::from_ref_time(30_251_859).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -982,10 +984,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: 412_112 nanoseconds. - Weight::from_ref_time(412_710_000) - // Standard Error: 54_875 - .saturating_add(Weight::from_ref_time(103_169_035).saturating_mul(n.into())) + // Minimum execution time: 324_298 nanoseconds. + Weight::from_ref_time(325_738_000) + // Standard Error: 48_563 + .saturating_add(Weight::from_ref_time(99_479_838).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -996,10 +998,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: 381_994 nanoseconds. - Weight::from_ref_time(383_832_551) - // Standard Error: 676_656 - .saturating_add(Weight::from_ref_time(3_020_035_748).saturating_mul(r.into())) + // Minimum execution time: 294_257 nanoseconds. + Weight::from_ref_time(299_467_620) + // Standard Error: 589_749 + .saturating_add(Weight::from_ref_time(3_015_389_579).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -1010,10 +1012,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: 381_472 nanoseconds. - Weight::from_ref_time(383_590_834) - // Standard Error: 538_574 - .saturating_add(Weight::from_ref_time(2_077_926_265).saturating_mul(r.into())) + // Minimum execution time: 289_480 nanoseconds. + Weight::from_ref_time(298_762_412) + // Standard Error: 397_004 + .saturating_add(Weight::from_ref_time(743_937_087).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -1025,10 +1027,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: 381_527 nanoseconds. - Weight::from_ref_time(382_291_000) - // Standard Error: 2_760_840 - .saturating_add(Weight::from_ref_time(1_356_115_009).saturating_mul(r.into())) + // Minimum execution time: 293_494 nanoseconds. + Weight::from_ref_time(297_756_000) + // Standard Error: 2_731_227 + .saturating_add(Weight::from_ref_time(1_387_380_436).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)) @@ -1041,10 +1043,10 @@ 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: 382_722 nanoseconds. - Weight::from_ref_time(387_231_409) - // Standard Error: 28_817 - .saturating_add(Weight::from_ref_time(11_349_809).saturating_mul(r.into())) + // Minimum execution time: 295_339 nanoseconds. + Weight::from_ref_time(301_577_907) + // Standard Error: 23_836 + .saturating_add(Weight::from_ref_time(10_876_508).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -1055,10 +1057,10 @@ 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: 383_568 nanoseconds. - Weight::from_ref_time(419_835_108) - // Standard Error: 125_982 - .saturating_add(Weight::from_ref_time(25_241_800).saturating_mul(r.into())) + // Minimum execution time: 297_096 nanoseconds. + Weight::from_ref_time(336_319_823) + // Standard Error: 128_941 + .saturating_add(Weight::from_ref_time(25_211_374).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -1070,376 +1072,376 @@ impl WeightInfo for SubstrateWeight { // 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: 382_084 nanoseconds. - Weight::from_ref_time(388_155_568) - // Standard Error: 29_161 - .saturating_add(Weight::from_ref_time(9_015_217).saturating_mul(r.into())) + // Minimum execution time: 293_819 nanoseconds. + Weight::from_ref_time(302_765_659) + // Standard Error: 28_518 + .saturating_add(Weight::from_ref_time(9_325_552).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: 593 nanoseconds. - Weight::from_ref_time(816_706) - // Standard Error: 173 - .saturating_add(Weight::from_ref_time(344_732).saturating_mul(r.into())) + // Minimum execution time: 805 nanoseconds. + Weight::from_ref_time(1_002_066) + // Standard Error: 609 + .saturating_add(Weight::from_ref_time(346_608).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64load(r: u32, ) -> Weight { - // Minimum execution time: 705 nanoseconds. - Weight::from_ref_time(1_191_205) - // Standard Error: 600 - .saturating_add(Weight::from_ref_time(986_102).saturating_mul(r.into())) + // Minimum execution time: 917 nanoseconds. + Weight::from_ref_time(1_247_710) + // Standard Error: 1_069 + .saturating_add(Weight::from_ref_time(984_608).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64store(r: u32, ) -> Weight { - // Minimum execution time: 717 nanoseconds. - Weight::from_ref_time(1_019_448) - // Standard Error: 421 - .saturating_add(Weight::from_ref_time(882_531).saturating_mul(r.into())) + // Minimum execution time: 917 nanoseconds. + Weight::from_ref_time(1_244_315) + // Standard Error: 524 + .saturating_add(Weight::from_ref_time(882_167).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_select(r: u32, ) -> Weight { - // Minimum execution time: 642 nanoseconds. - Weight::from_ref_time(917_880) - // Standard Error: 362 - .saturating_add(Weight::from_ref_time(957_235).saturating_mul(r.into())) + // Minimum execution time: 791 nanoseconds. + Weight::from_ref_time(1_119_053) + // Standard Error: 379 + .saturating_add(Weight::from_ref_time(956_169).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_if(r: u32, ) -> Weight { - // Minimum execution time: 630 nanoseconds. - Weight::from_ref_time(694_427) - // Standard Error: 1_506 - .saturating_add(Weight::from_ref_time(1_298_411).saturating_mul(r.into())) + // Minimum execution time: 782 nanoseconds. + Weight::from_ref_time(773_373) + // Standard Error: 463 + .saturating_add(Weight::from_ref_time(1_299_306).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_br(r: u32, ) -> Weight { - // Minimum execution time: 634 nanoseconds. - Weight::from_ref_time(1_101_754) - // Standard Error: 840 - .saturating_add(Weight::from_ref_time(526_433).saturating_mul(r.into())) + // Minimum execution time: 743 nanoseconds. + Weight::from_ref_time(1_273_896) + // Standard Error: 925 + .saturating_add(Weight::from_ref_time(527_015).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_br_if(r: u32, ) -> Weight { - // Minimum execution time: 651 nanoseconds. - Weight::from_ref_time(790_908) - // Standard Error: 849 - .saturating_add(Weight::from_ref_time(800_188).saturating_mul(r.into())) + // Minimum execution time: 761 nanoseconds. + Weight::from_ref_time(929_565) + // Standard Error: 1_275 + .saturating_add(Weight::from_ref_time(805_592).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_br_table(r: u32, ) -> Weight { - // Minimum execution time: 622 nanoseconds. - Weight::from_ref_time(416_266) - // Standard Error: 1_574 - .saturating_add(Weight::from_ref_time(1_080_225).saturating_mul(r.into())) + // Minimum execution time: 813 nanoseconds. + Weight::from_ref_time(703_802) + // Standard Error: 1_665 + .saturating_add(Weight::from_ref_time(1_074_321).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_131 nanoseconds. - Weight::from_ref_time(2_540_446) - // Standard Error: 75 - .saturating_add(Weight::from_ref_time(4_997).saturating_mul(e.into())) + // Minimum execution time: 2_347 nanoseconds. + Weight::from_ref_time(2_752_638) + // Standard Error: 69 + .saturating_add(Weight::from_ref_time(4_771).saturating_mul(e.into())) } /// The range of component `r` is `[0, 50]`. fn instr_call(r: u32, ) -> Weight { - // Minimum execution time: 650 nanoseconds. - Weight::from_ref_time(1_577_978) - // Standard Error: 2_696 - .saturating_add(Weight::from_ref_time(2_204_044).saturating_mul(r.into())) + // Minimum execution time: 826 nanoseconds. + Weight::from_ref_time(1_784_596) + // Standard Error: 1_646 + .saturating_add(Weight::from_ref_time(2_189_993).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_call_indirect(r: u32, ) -> Weight { - // Minimum execution time: 742 nanoseconds. - Weight::from_ref_time(1_947_575) - // Standard Error: 1_651 - .saturating_add(Weight::from_ref_time(2_799_445).saturating_mul(r.into())) + // Minimum execution time: 926 nanoseconds. + Weight::from_ref_time(1_898_358) + // Standard Error: 2_678 + .saturating_add(Weight::from_ref_time(2_811_379).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_230 nanoseconds. - Weight::from_ref_time(5_079_432) - // Standard Error: 315 - .saturating_add(Weight::from_ref_time(179_278).saturating_mul(p.into())) + // Minimum execution time: 4_428 nanoseconds. + Weight::from_ref_time(5_257_445) + // Standard Error: 306 + .saturating_add(Weight::from_ref_time(178_882).saturating_mul(p.into())) } /// The range of component `l` is `[0, 1024]`. fn instr_call_per_local(l: u32, ) -> Weight { - // Minimum execution time: 2_830 nanoseconds. - Weight::from_ref_time(3_601_633) - // Standard Error: 31 - .saturating_add(Weight::from_ref_time(92_499).saturating_mul(l.into())) + // Minimum execution time: 2_945 nanoseconds. + Weight::from_ref_time(4_240_619) + // Standard Error: 39 + .saturating_add(Weight::from_ref_time(46_640).saturating_mul(l.into())) } /// The range of component `r` is `[0, 50]`. fn instr_local_get(r: u32, ) -> Weight { - // Minimum execution time: 2_896 nanoseconds. - Weight::from_ref_time(3_137_247) - // Standard Error: 245 - .saturating_add(Weight::from_ref_time(364_431).saturating_mul(r.into())) + // Minimum execution time: 2_204 nanoseconds. + Weight::from_ref_time(2_430_272) + // Standard Error: 270 + .saturating_add(Weight::from_ref_time(365_718).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_local_set(r: u32, ) -> Weight { - // Minimum execution time: 2_795 nanoseconds. - Weight::from_ref_time(3_199_878) - // Standard Error: 549 - .saturating_add(Weight::from_ref_time(380_524).saturating_mul(r.into())) + // Minimum execution time: 2_117 nanoseconds. + Weight::from_ref_time(2_429_354) + // Standard Error: 240 + .saturating_add(Weight::from_ref_time(381_830).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_local_tee(r: u32, ) -> Weight { - // Minimum execution time: 2_807 nanoseconds. - Weight::from_ref_time(3_130_120) - // Standard Error: 319 - .saturating_add(Weight::from_ref_time(525_857).saturating_mul(r.into())) + // Minimum execution time: 2_123 nanoseconds. + Weight::from_ref_time(2_460_016) + // Standard Error: 262 + .saturating_add(Weight::from_ref_time(526_554).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_global_get(r: u32, ) -> Weight { - // Minimum execution time: 678 nanoseconds. - Weight::from_ref_time(1_013_348) - // Standard Error: 362 - .saturating_add(Weight::from_ref_time(810_232).saturating_mul(r.into())) + // Minimum execution time: 892 nanoseconds. + Weight::from_ref_time(1_234_618) + // Standard Error: 485 + .saturating_add(Weight::from_ref_time(813_721).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_global_set(r: u32, ) -> Weight { - // Minimum execution time: 624 nanoseconds. - Weight::from_ref_time(973_583) - // Standard Error: 373 - .saturating_add(Weight::from_ref_time(829_360).saturating_mul(r.into())) + // Minimum execution time: 901 nanoseconds. + Weight::from_ref_time(1_182_838) + // Standard Error: 482 + .saturating_add(Weight::from_ref_time(831_308).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_memory_current(r: u32, ) -> Weight { - // Minimum execution time: 698 nanoseconds. - Weight::from_ref_time(904_862) - // Standard Error: 360 - .saturating_add(Weight::from_ref_time(694_614).saturating_mul(r.into())) + // Minimum execution time: 929 nanoseconds. + Weight::from_ref_time(1_221_388) + // Standard Error: 434 + .saturating_add(Weight::from_ref_time(693_301).saturating_mul(r.into())) } /// The range of component `r` is `[0, 1]`. fn instr_memory_grow(r: u32, ) -> Weight { - // Minimum execution time: 642 nanoseconds. - Weight::from_ref_time(735_085) - // Standard Error: 105_815 - .saturating_add(Weight::from_ref_time(233_816_514).saturating_mul(r.into())) + // Minimum execution time: 808 nanoseconds. + Weight::from_ref_time(906_944) + // Standard Error: 6_164 + .saturating_add(Weight::from_ref_time(187_445_255).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64clz(r: u32, ) -> Weight { - // Minimum execution time: 606 nanoseconds. - Weight::from_ref_time(850_590) - // Standard Error: 262 - .saturating_add(Weight::from_ref_time(507_721).saturating_mul(r.into())) + // Minimum execution time: 807 nanoseconds. + Weight::from_ref_time(1_064_776) + // Standard Error: 287 + .saturating_add(Weight::from_ref_time(507_278).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ctz(r: u32, ) -> Weight { - // Minimum execution time: 663 nanoseconds. - Weight::from_ref_time(853_060) - // Standard Error: 250 - .saturating_add(Weight::from_ref_time(514_225).saturating_mul(r.into())) + // Minimum execution time: 776 nanoseconds. + Weight::from_ref_time(1_033_205) + // Standard Error: 443 + .saturating_add(Weight::from_ref_time(512_445).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64popcnt(r: u32, ) -> Weight { - // Minimum execution time: 605 nanoseconds. - Weight::from_ref_time(849_563) - // Standard Error: 275 - .saturating_add(Weight::from_ref_time(511_494).saturating_mul(r.into())) + // Minimum execution time: 909 nanoseconds. + Weight::from_ref_time(1_089_083) + // Standard Error: 335 + .saturating_add(Weight::from_ref_time(510_392).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64eqz(r: u32, ) -> Weight { - // Minimum execution time: 618 nanoseconds. - Weight::from_ref_time(839_855) - // Standard Error: 228 - .saturating_add(Weight::from_ref_time(524_614).saturating_mul(r.into())) + // Minimum execution time: 791 nanoseconds. + Weight::from_ref_time(1_063_118) + // Standard Error: 210 + .saturating_add(Weight::from_ref_time(522_817).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendsi32(r: u32, ) -> Weight { - // Minimum execution time: 637 nanoseconds. - Weight::from_ref_time(860_326) + // Minimum execution time: 789 nanoseconds. + Weight::from_ref_time(1_056_006) // Standard Error: 240 - .saturating_add(Weight::from_ref_time(504_847).saturating_mul(r.into())) + .saturating_add(Weight::from_ref_time(505_198).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendui32(r: u32, ) -> Weight { - // Minimum execution time: 623 nanoseconds. - Weight::from_ref_time(844_585) - // Standard Error: 235 - .saturating_add(Weight::from_ref_time(505_821).saturating_mul(r.into())) + // Minimum execution time: 804 nanoseconds. + Weight::from_ref_time(1_087_882) + // Standard Error: 234 + .saturating_add(Weight::from_ref_time(503_830).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i32wrapi64(r: u32, ) -> Weight { - // Minimum execution time: 672 nanoseconds. - Weight::from_ref_time(826_784) - // Standard Error: 225 - .saturating_add(Weight::from_ref_time(504_632).saturating_mul(r.into())) + // Minimum execution time: 756 nanoseconds. + Weight::from_ref_time(1_050_994) + // Standard Error: 172 + .saturating_add(Weight::from_ref_time(503_343).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64eq(r: u32, ) -> Weight { - // Minimum execution time: 642 nanoseconds. - Weight::from_ref_time(867_080) - // Standard Error: 231 - .saturating_add(Weight::from_ref_time(732_430).saturating_mul(r.into())) + // Minimum execution time: 775 nanoseconds. + Weight::from_ref_time(1_061_228) + // Standard Error: 232 + .saturating_add(Weight::from_ref_time(730_751).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ne(r: u32, ) -> Weight { - // Minimum execution time: 639 nanoseconds. - Weight::from_ref_time(866_094) - // Standard Error: 272 - .saturating_add(Weight::from_ref_time(732_560).saturating_mul(r.into())) + // Minimum execution time: 809 nanoseconds. + Weight::from_ref_time(1_080_957) + // Standard Error: 320 + .saturating_add(Weight::from_ref_time(732_246).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64lts(r: u32, ) -> Weight { - // Minimum execution time: 619 nanoseconds. - Weight::from_ref_time(928_672) - // Standard Error: 484 - .saturating_add(Weight::from_ref_time(739_523).saturating_mul(r.into())) + // Minimum execution time: 808 nanoseconds. + Weight::from_ref_time(1_055_752) + // Standard Error: 496 + .saturating_add(Weight::from_ref_time(740_084).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ltu(r: u32, ) -> Weight { - // Minimum execution time: 612 nanoseconds. - Weight::from_ref_time(863_312) - // Standard Error: 328 - .saturating_add(Weight::from_ref_time(743_687).saturating_mul(r.into())) + // Minimum execution time: 792 nanoseconds. + Weight::from_ref_time(1_111_972) + // Standard Error: 270 + .saturating_add(Weight::from_ref_time(741_581).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64gts(r: u32, ) -> Weight { - // Minimum execution time: 648 nanoseconds. - Weight::from_ref_time(931_331) - // Standard Error: 612 - .saturating_add(Weight::from_ref_time(747_653).saturating_mul(r.into())) + // Minimum execution time: 862 nanoseconds. + Weight::from_ref_time(1_111_246) + // Standard Error: 263 + .saturating_add(Weight::from_ref_time(746_026).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64gtu(r: u32, ) -> Weight { - // Minimum execution time: 632 nanoseconds. - Weight::from_ref_time(868_901) - // Standard Error: 276 - .saturating_add(Weight::from_ref_time(744_778).saturating_mul(r.into())) + // Minimum execution time: 810 nanoseconds. + Weight::from_ref_time(1_094_933) + // Standard Error: 271 + .saturating_add(Weight::from_ref_time(743_645).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64les(r: u32, ) -> Weight { - // Minimum execution time: 629 nanoseconds. - Weight::from_ref_time(898_516) - // Standard Error: 288 - .saturating_add(Weight::from_ref_time(734_393).saturating_mul(r.into())) + // Minimum execution time: 769 nanoseconds. + Weight::from_ref_time(819_933) + // Standard Error: 4_528 + .saturating_add(Weight::from_ref_time(751_599).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64leu(r: u32, ) -> Weight { - // Minimum execution time: 603 nanoseconds. - Weight::from_ref_time(853_744) - // Standard Error: 204 - .saturating_add(Weight::from_ref_time(739_499).saturating_mul(r.into())) + // Minimum execution time: 797 nanoseconds. + Weight::from_ref_time(1_107_352) + // Standard Error: 344 + .saturating_add(Weight::from_ref_time(738_684).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(885_174) - // Standard Error: 238 - .saturating_add(Weight::from_ref_time(734_010).saturating_mul(r.into())) + // Minimum execution time: 784 nanoseconds. + Weight::from_ref_time(1_068_487) + // Standard Error: 3_796 + .saturating_add(Weight::from_ref_time(741_207).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64geu(r: u32, ) -> Weight { - // Minimum execution time: 602 nanoseconds. - Weight::from_ref_time(915_329) - // Standard Error: 273 - .saturating_add(Weight::from_ref_time(738_209).saturating_mul(r.into())) + // Minimum execution time: 813 nanoseconds. + Weight::from_ref_time(1_067_278) + // Standard Error: 459 + .saturating_add(Weight::from_ref_time(737_841).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64add(r: u32, ) -> Weight { - // Minimum execution time: 585 nanoseconds. - Weight::from_ref_time(862_239) - // Standard Error: 294 - .saturating_add(Weight::from_ref_time(719_000).saturating_mul(r.into())) + // Minimum execution time: 798 nanoseconds. + Weight::from_ref_time(1_100_254) + // Standard Error: 297 + .saturating_add(Weight::from_ref_time(717_622).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64sub(r: u32, ) -> Weight { - // Minimum execution time: 633 nanoseconds. - Weight::from_ref_time(881_696) - // Standard Error: 195 - .saturating_add(Weight::from_ref_time(713_153).saturating_mul(r.into())) + // Minimum execution time: 778 nanoseconds. + Weight::from_ref_time(1_063_748) + // Standard Error: 378 + .saturating_add(Weight::from_ref_time(713_577).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64mul(r: u32, ) -> Weight { - // Minimum execution time: 629 nanoseconds. - Weight::from_ref_time(856_238) - // Standard Error: 269 - .saturating_add(Weight::from_ref_time(715_451).saturating_mul(r.into())) + // Minimum execution time: 780 nanoseconds. + Weight::from_ref_time(1_088_755) + // Standard Error: 316 + .saturating_add(Weight::from_ref_time(714_127).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64divs(r: u32, ) -> Weight { - // Minimum execution time: 633 nanoseconds. - Weight::from_ref_time(880_804) - // Standard Error: 725 - .saturating_add(Weight::from_ref_time(1_349_577).saturating_mul(r.into())) + // Minimum execution time: 776 nanoseconds. + Weight::from_ref_time(1_062_591) + // Standard Error: 610 + .saturating_add(Weight::from_ref_time(1_355_430).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64divu(r: u32, ) -> Weight { - // Minimum execution time: 639 nanoseconds. - Weight::from_ref_time(867_528) - // Standard Error: 1_940 - .saturating_add(Weight::from_ref_time(1_287_959).saturating_mul(r.into())) + // Minimum execution time: 801 nanoseconds. + Weight::from_ref_time(1_092_395) + // Standard Error: 423 + .saturating_add(Weight::from_ref_time(1_282_356).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64rems(r: u32, ) -> Weight { - // Minimum execution time: 595 nanoseconds. - Weight::from_ref_time(851_253) - // Standard Error: 503 - .saturating_add(Weight::from_ref_time(1_398_668).saturating_mul(r.into())) + // Minimum execution time: 822 nanoseconds. + Weight::from_ref_time(1_083_079) + // Standard Error: 562 + .saturating_add(Weight::from_ref_time(1_398_522).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64remu(r: u32, ) -> Weight { - // Minimum execution time: 604 nanoseconds. - Weight::from_ref_time(804_977) - // Standard Error: 812 - .saturating_add(Weight::from_ref_time(1_288_816).saturating_mul(r.into())) + // Minimum execution time: 798 nanoseconds. + Weight::from_ref_time(1_088_997) + // Standard Error: 401 + .saturating_add(Weight::from_ref_time(1_283_442).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64and(r: u32, ) -> Weight { - // Minimum execution time: 609 nanoseconds. - Weight::from_ref_time(890_945) - // Standard Error: 1_645 - .saturating_add(Weight::from_ref_time(719_770).saturating_mul(r.into())) + // Minimum execution time: 815 nanoseconds. + Weight::from_ref_time(1_081_903) + // Standard Error: 264 + .saturating_add(Weight::from_ref_time(718_069).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64or(r: u32, ) -> Weight { - // Minimum execution time: 628 nanoseconds. - Weight::from_ref_time(897_973) - // Standard Error: 1_641 - .saturating_add(Weight::from_ref_time(718_838).saturating_mul(r.into())) + // Minimum execution time: 813 nanoseconds. + Weight::from_ref_time(1_091_426) + // Standard Error: 296 + .saturating_add(Weight::from_ref_time(717_894).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64xor(r: u32, ) -> Weight { - // Minimum execution time: 634 nanoseconds. - Weight::from_ref_time(848_440) - // Standard Error: 249 - .saturating_add(Weight::from_ref_time(718_206).saturating_mul(r.into())) + // Minimum execution time: 794 nanoseconds. + Weight::from_ref_time(1_040_144) + // Standard Error: 400 + .saturating_add(Weight::from_ref_time(719_886).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64shl(r: u32, ) -> Weight { - // Minimum execution time: 625 nanoseconds. - Weight::from_ref_time(881_579) - // Standard Error: 273 - .saturating_add(Weight::from_ref_time(736_934).saturating_mul(r.into())) + // Minimum execution time: 774 nanoseconds. + Weight::from_ref_time(1_092_466) + // Standard Error: 4_173 + .saturating_add(Weight::from_ref_time(739_873).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64shrs(r: u32, ) -> Weight { - // Minimum execution time: 630 nanoseconds. - Weight::from_ref_time(897_813) - // Standard Error: 249 - .saturating_add(Weight::from_ref_time(734_657).saturating_mul(r.into())) + // Minimum execution time: 793 nanoseconds. + Weight::from_ref_time(1_105_611) + // Standard Error: 394 + .saturating_add(Weight::from_ref_time(735_358).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64shru(r: u32, ) -> Weight { - // Minimum execution time: 607 nanoseconds. - Weight::from_ref_time(871_660) - // Standard Error: 312 - .saturating_add(Weight::from_ref_time(735_377).saturating_mul(r.into())) + // Minimum execution time: 805 nanoseconds. + Weight::from_ref_time(1_130_462) + // Standard Error: 327 + .saturating_add(Weight::from_ref_time(734_198).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotl(r: u32, ) -> Weight { - // Minimum execution time: 610 nanoseconds. - Weight::from_ref_time(861_640) - // Standard Error: 293 - .saturating_add(Weight::from_ref_time(735_524).saturating_mul(r.into())) + // Minimum execution time: 831 nanoseconds. + Weight::from_ref_time(1_118_894) + // Standard Error: 389 + .saturating_add(Weight::from_ref_time(733_834).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotr(r: u32, ) -> Weight { - // Minimum execution time: 625 nanoseconds. - Weight::from_ref_time(880_203) - // Standard Error: 373 - .saturating_add(Weight::from_ref_time(737_354).saturating_mul(r.into())) + // Minimum execution time: 772 nanoseconds. + Weight::from_ref_time(1_123_733) + // Standard Error: 337 + .saturating_add(Weight::from_ref_time(733_923).saturating_mul(r.into())) } } @@ -1447,17 +1449,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_196 nanoseconds. - Weight::from_ref_time(3_293_000) + // Minimum execution time: 3_326 nanoseconds. + Weight::from_ref_time(3_433_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: 14_857 nanoseconds. - Weight::from_ref_time(14_957_593) - // Standard Error: 1_015 - .saturating_add(Weight::from_ref_time(935_359).saturating_mul(k.into())) + // Minimum execution time: 15_703 nanoseconds. + Weight::from_ref_time(15_288_927) + // Standard Error: 951 + .saturating_add(Weight::from_ref_time(940_816).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()))) @@ -1465,10 +1467,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_231 nanoseconds. - Weight::from_ref_time(14_859_580) - // Standard Error: 3_479 - .saturating_add(Weight::from_ref_time(1_185_600).saturating_mul(q.into())) + // Minimum execution time: 3_548 nanoseconds. + Weight::from_ref_time(15_764_121) + // Standard Error: 3_339 + .saturating_add(Weight::from_ref_time(1_214_890).saturating_mul(q.into())) .saturating_add(RocksDbWeight::get().reads(1)) .saturating_add(RocksDbWeight::get().writes(1)) } @@ -1476,10 +1478,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: 34_565 nanoseconds. - Weight::from_ref_time(29_199_016) - // Standard Error: 70 - .saturating_add(Weight::from_ref_time(47_107).saturating_mul(c.into())) + // Minimum execution time: 29_801 nanoseconds. + Weight::from_ref_time(27_932_706) + // Standard Error: 49 + .saturating_add(Weight::from_ref_time(50_532).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(1)) .saturating_add(RocksDbWeight::get().writes(1)) } @@ -1490,10 +1492,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: 392_074 nanoseconds. - Weight::from_ref_time(404_090_909) - // Standard Error: 24 - .saturating_add(Weight::from_ref_time(30_454).saturating_mul(c.into())) + // Minimum execution time: 307_894 nanoseconds. + Weight::from_ref_time(322_346_319) + // Standard Error: 25 + .saturating_add(Weight::from_ref_time(30_678).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(4)) } @@ -1509,14 +1511,14 @@ impl WeightInfo for () { /// The range of component `i` is `[0, 1048576]`. /// The range of component `s` is `[0, 1048576]`. fn instantiate_with_code(c: u32, i: u32, s: u32, ) -> Weight { - // Minimum execution time: 3_785_934 nanoseconds. - Weight::from_ref_time(683_143_843) - // Standard Error: 272 - .saturating_add(Weight::from_ref_time(87_620).saturating_mul(c.into())) + // Minimum execution time: 3_610_424 nanoseconds. + Weight::from_ref_time(583_426_386) + // Standard Error: 277 + .saturating_add(Weight::from_ref_time(90_224).saturating_mul(c.into())) // Standard Error: 16 - .saturating_add(Weight::from_ref_time(1_363).saturating_mul(i.into())) + .saturating_add(Weight::from_ref_time(1_325).saturating_mul(i.into())) // Standard Error: 16 - .saturating_add(Weight::from_ref_time(1_778).saturating_mul(s.into())) + .saturating_add(Weight::from_ref_time(1_727).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(8)) .saturating_add(RocksDbWeight::get().writes(9)) } @@ -1530,12 +1532,12 @@ impl WeightInfo for () { /// The range of component `i` is `[0, 1048576]`. /// The range of component `s` is `[0, 1048576]`. fn instantiate(i: u32, s: u32, ) -> Weight { - // Minimum execution time: 1_935_310 nanoseconds. - Weight::from_ref_time(203_531_122) + // Minimum execution time: 1_892_996 nanoseconds. + Weight::from_ref_time(202_958_196) // Standard Error: 8 - .saturating_add(Weight::from_ref_time(1_674).saturating_mul(i.into())) + .saturating_add(Weight::from_ref_time(1_627).saturating_mul(i.into())) // Standard Error: 8 - .saturating_add(Weight::from_ref_time(1_789).saturating_mul(s.into())) + .saturating_add(Weight::from_ref_time(1_755).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(8)) .saturating_add(RocksDbWeight::get().writes(7)) } @@ -1545,8 +1547,8 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: System EventTopics (r:2 w:2) fn call() -> Weight { - // Minimum execution time: 151_999 nanoseconds. - Weight::from_ref_time(153_527_000) + // Minimum execution time: 157_347 nanoseconds. + Weight::from_ref_time(159_084_000) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(4)) } @@ -1556,10 +1558,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: 391_165 nanoseconds. - Weight::from_ref_time(394_519_487) - // Standard Error: 75 - .saturating_add(Weight::from_ref_time(89_736).saturating_mul(c.into())) + // Minimum execution time: 299_987 nanoseconds. + Weight::from_ref_time(305_274_879) + // Standard Error: 72 + .saturating_add(Weight::from_ref_time(91_916).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(2)) .saturating_add(RocksDbWeight::get().writes(4)) } @@ -1568,8 +1570,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: 39_354 nanoseconds. - Weight::from_ref_time(39_855_000) + // Minimum execution time: 40_795 nanoseconds. + Weight::from_ref_time(41_297_000) .saturating_add(RocksDbWeight::get().reads(2)) .saturating_add(RocksDbWeight::get().writes(4)) } @@ -1577,8 +1579,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_909 nanoseconds. - Weight::from_ref_time(41_275_000) + // Minimum execution time: 41_957 nanoseconds. + Weight::from_ref_time(42_536_000) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(6)) } @@ -1589,10 +1591,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: 380_150 nanoseconds. - Weight::from_ref_time(384_429_035) - // Standard Error: 34_740 - .saturating_add(Weight::from_ref_time(15_582_218).saturating_mul(r.into())) + // Minimum execution time: 293_544 nanoseconds. + Weight::from_ref_time(298_981_222) + // Standard Error: 39_139 + .saturating_add(Weight::from_ref_time(17_278_436).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -1603,10 +1605,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: 380_608 nanoseconds. - Weight::from_ref_time(326_544_805) - // Standard Error: 475_381 - .saturating_add(Weight::from_ref_time(190_717_772).saturating_mul(r.into())) + // Minimum execution time: 293_500 nanoseconds. + Weight::from_ref_time(237_825_284) + // Standard Error: 450_234 + .saturating_add(Weight::from_ref_time(198_995_806).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)) @@ -1618,10 +1620,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: 382_780 nanoseconds. - Weight::from_ref_time(333_775_113) - // Standard Error: 446_086 - .saturating_add(Weight::from_ref_time(232_531_042).saturating_mul(r.into())) + // Minimum execution time: 295_851 nanoseconds. + Weight::from_ref_time(258_113_447) + // Standard Error: 408_747 + .saturating_add(Weight::from_ref_time(237_490_216).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)) @@ -1633,10 +1635,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: 381_815 nanoseconds. - Weight::from_ref_time(390_931_793) - // Standard Error: 61_918 - .saturating_add(Weight::from_ref_time(18_798_438).saturating_mul(r.into())) + // Minimum execution time: 294_614 nanoseconds. + Weight::from_ref_time(301_528_998) + // Standard Error: 40_613 + .saturating_add(Weight::from_ref_time(20_815_088).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -1647,10 +1649,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: 379_162 nanoseconds. - Weight::from_ref_time(383_796_363) - // Standard Error: 25_555 - .saturating_add(Weight::from_ref_time(10_843_721).saturating_mul(r.into())) + // Minimum execution time: 293_088 nanoseconds. + Weight::from_ref_time(299_120_595) + // Standard Error: 23_277 + .saturating_add(Weight::from_ref_time(11_130_334).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -1661,10 +1663,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: 380_307 nanoseconds. - Weight::from_ref_time(390_211_779) - // Standard Error: 53_326 - .saturating_add(Weight::from_ref_time(15_311_171).saturating_mul(r.into())) + // Minimum execution time: 295_110 nanoseconds. + Weight::from_ref_time(305_295_787) + // Standard Error: 48_521 + .saturating_add(Weight::from_ref_time(16_610_806).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -1675,10 +1677,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: 380_230 nanoseconds. - Weight::from_ref_time(383_470_453) - // Standard Error: 45_007 - .saturating_add(Weight::from_ref_time(15_582_472).saturating_mul(r.into())) + // Minimum execution time: 293_414 nanoseconds. + Weight::from_ref_time(299_960_283) + // Standard Error: 32_003 + .saturating_add(Weight::from_ref_time(16_652_433).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -1689,10 +1691,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: 380_244 nanoseconds. - Weight::from_ref_time(388_092_461) - // Standard Error: 98_199 - .saturating_add(Weight::from_ref_time(97_339_528).saturating_mul(r.into())) + // Minimum execution time: 292_429 nanoseconds. + Weight::from_ref_time(301_025_128) + // Standard Error: 92_155 + .saturating_add(Weight::from_ref_time(92_731_719).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -1703,10 +1705,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: 380_242 nanoseconds. - Weight::from_ref_time(384_078_258) - // Standard Error: 28_510 - .saturating_add(Weight::from_ref_time(15_423_359).saturating_mul(r.into())) + // Minimum execution time: 293_516 nanoseconds. + Weight::from_ref_time(300_071_428) + // Standard Error: 25_871 + .saturating_add(Weight::from_ref_time(16_599_369).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -1717,10 +1719,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: 379_890 nanoseconds. - Weight::from_ref_time(383_658_430) - // Standard Error: 44_976 - .saturating_add(Weight::from_ref_time(15_451_905).saturating_mul(r.into())) + // Minimum execution time: 293_666 nanoseconds. + Weight::from_ref_time(299_803_599) + // Standard Error: 24_508 + .saturating_add(Weight::from_ref_time(16_500_973).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -1731,10 +1733,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: 380_269 nanoseconds. - Weight::from_ref_time(383_580_481) - // Standard Error: 31_862 - .saturating_add(Weight::from_ref_time(15_230_473).saturating_mul(r.into())) + // Minimum execution time: 289_193 nanoseconds. + Weight::from_ref_time(297_946_784) + // Standard Error: 43_719 + .saturating_add(Weight::from_ref_time(16_442_254).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -1745,10 +1747,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: 380_308 nanoseconds. - Weight::from_ref_time(383_732_372) - // Standard Error: 38_359 - .saturating_add(Weight::from_ref_time(15_358_775).saturating_mul(r.into())) + // Minimum execution time: 288_897 nanoseconds. + Weight::from_ref_time(298_856_658) + // Standard Error: 31_003 + .saturating_add(Weight::from_ref_time(16_490_508).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -1760,10 +1762,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: 380_834 nanoseconds. - Weight::from_ref_time(388_999_459) - // Standard Error: 96_447 - .saturating_add(Weight::from_ref_time(86_714_414).saturating_mul(r.into())) + // Minimum execution time: 289_850 nanoseconds. + Weight::from_ref_time(302_898_449) + // Standard Error: 92_822 + .saturating_add(Weight::from_ref_time(86_376_874).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -1774,10 +1776,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: 140_955 nanoseconds. - Weight::from_ref_time(144_716_423) - // Standard Error: 11_370 - .saturating_add(Weight::from_ref_time(7_858_807).saturating_mul(r.into())) + // Minimum execution time: 145_105 nanoseconds. + Weight::from_ref_time(152_388_934) + // Standard Error: 29_988 + .saturating_add(Weight::from_ref_time(7_761_947).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -1788,10 +1790,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: 380_210 nanoseconds. - Weight::from_ref_time(384_185_776) - // Standard Error: 49_038 - .saturating_add(Weight::from_ref_time(13_649_793).saturating_mul(r.into())) + // Minimum execution time: 289_319 nanoseconds. + Weight::from_ref_time(298_390_911) + // Standard Error: 27_329 + .saturating_add(Weight::from_ref_time(14_225_527).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -1802,10 +1804,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: 396_209 nanoseconds. - Weight::from_ref_time(424_522_611) - // Standard Error: 3_917 - .saturating_add(Weight::from_ref_time(9_627_216).saturating_mul(n.into())) + // Minimum execution time: 305_538 nanoseconds. + Weight::from_ref_time(339_734_596) + // Standard Error: 4_636 + .saturating_add(Weight::from_ref_time(9_592_149).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -1816,10 +1818,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: 378_412 nanoseconds. - Weight::from_ref_time(380_502_085) - // Standard Error: 201_552 - .saturating_add(Weight::from_ref_time(1_434_214).saturating_mul(r.into())) + // Minimum execution time: 287_189 nanoseconds. + Weight::from_ref_time(295_472_383) + // Standard Error: 314_142 + .saturating_add(Weight::from_ref_time(214_016).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -1830,10 +1832,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: 381_463 nanoseconds. - Weight::from_ref_time(383_955_553) - // Standard Error: 998 - .saturating_add(Weight::from_ref_time(230_512).saturating_mul(n.into())) + // Minimum execution time: 289_380 nanoseconds. + Weight::from_ref_time(296_302_404) + // Standard Error: 889 + .saturating_add(Weight::from_ref_time(190_017).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -1846,10 +1848,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: 379_877 nanoseconds. - Weight::from_ref_time(381_729_546) - // Standard Error: 214_004 - .saturating_add(Weight::from_ref_time(52_528_353).saturating_mul(r.into())) + // Minimum execution time: 292_383 nanoseconds. + Weight::from_ref_time(297_557_691) + // Standard Error: 251_228 + .saturating_add(Weight::from_ref_time(56_688_008).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)) @@ -1863,10 +1865,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: 380_275 nanoseconds. - Weight::from_ref_time(386_495_777) - // Standard Error: 94_674 - .saturating_add(Weight::from_ref_time(108_432_929).saturating_mul(r.into())) + // Minimum execution time: 293_019 nanoseconds. + Weight::from_ref_time(301_747_439) + // Standard Error: 92_043 + .saturating_add(Weight::from_ref_time(109_861_144).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -1877,10 +1879,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: 379_095 nanoseconds. - Weight::from_ref_time(393_997_924) - // Standard Error: 141_916 - .saturating_add(Weight::from_ref_time(212_937_170).saturating_mul(r.into())) + // Minimum execution time: 287_586 nanoseconds. + Weight::from_ref_time(304_751_302) + // Standard Error: 127_698 + .saturating_add(Weight::from_ref_time(221_525_053).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -1892,12 +1894,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_241_001 nanoseconds. - Weight::from_ref_time(548_526_917) - // Standard Error: 496_807 - .saturating_add(Weight::from_ref_time(177_087_769).saturating_mul(t.into())) - // Standard Error: 136_447 - .saturating_add(Weight::from_ref_time(71_558_402).saturating_mul(n.into())) + // Minimum execution time: 1_182_204 nanoseconds. + Weight::from_ref_time(508_607_957) + // Standard Error: 503_533 + .saturating_add(Weight::from_ref_time(173_998_655).saturating_mul(t.into())) + // Standard Error: 138_294 + .saturating_add(Weight::from_ref_time(67_991_373).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)) @@ -1910,20 +1912,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: 159_158 nanoseconds. - Weight::from_ref_time(163_427_712) - // Standard Error: 22_442 - .saturating_add(Weight::from_ref_time(12_647_838).saturating_mul(r.into())) + // Minimum execution time: 157_706 nanoseconds. + Weight::from_ref_time(161_895_583) + // Standard Error: 14_952 + .saturating_add(Weight::from_ref_time(12_990_237).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: 381_068 nanoseconds. - Weight::from_ref_time(341_041_230) - // Standard Error: 464_053 - .saturating_add(Weight::from_ref_time(402_677_314).saturating_mul(r.into())) + // Minimum execution time: 290_063 nanoseconds. + Weight::from_ref_time(256_404_853) + // Standard Error: 436_195 + .saturating_add(Weight::from_ref_time(406_569_743).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)) @@ -1932,10 +1934,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: 508_695 nanoseconds. - Weight::from_ref_time(663_159_695) - // Standard Error: 1_419_342 - .saturating_add(Weight::from_ref_time(96_558_570).saturating_mul(n.into())) + // Minimum execution time: 426_295 nanoseconds. + Weight::from_ref_time(582_989_911) + // Standard Error: 1_404_141 + .saturating_add(Weight::from_ref_time(89_545_963).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)) @@ -1944,10 +1946,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: 508_542 nanoseconds. - Weight::from_ref_time(634_146_978) - // Standard Error: 1_168_252 - .saturating_add(Weight::from_ref_time(64_231_947).saturating_mul(n.into())) + // Minimum execution time: 425_062 nanoseconds. + Weight::from_ref_time(552_380_900) + // Standard Error: 1_140_169 + .saturating_add(Weight::from_ref_time(64_085_108).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)) @@ -1956,10 +1958,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: 381_743 nanoseconds. - Weight::from_ref_time(337_309_674) - // Standard Error: 527_407 - .saturating_add(Weight::from_ref_time(395_767_068).saturating_mul(r.into())) + // Minimum execution time: 294_421 nanoseconds. + Weight::from_ref_time(260_897_072) + // Standard Error: 474_135 + .saturating_add(Weight::from_ref_time(403_191_862).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)) @@ -1968,10 +1970,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: 478_283 nanoseconds. - Weight::from_ref_time(616_673_245) - // Standard Error: 1_290_784 - .saturating_add(Weight::from_ref_time(66_534_552).saturating_mul(n.into())) + // Minimum execution time: 391_743 nanoseconds. + Weight::from_ref_time(535_327_545) + // Standard Error: 1_297_157 + .saturating_add(Weight::from_ref_time(67_222_981).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)) @@ -1980,10 +1982,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: 381_916 nanoseconds. - Weight::from_ref_time(349_150_912) - // Standard Error: 443_388 - .saturating_add(Weight::from_ref_time(316_975_558).saturating_mul(r.into())) + // Minimum execution time: 294_947 nanoseconds. + Weight::from_ref_time(266_280_887) + // Standard Error: 382_477 + .saturating_add(Weight::from_ref_time(323_306_898).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)) @@ -1991,10 +1993,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: 459_294 nanoseconds. - Weight::from_ref_time(579_698_524) - // Standard Error: 1_111_681 - .saturating_add(Weight::from_ref_time(159_276_087).saturating_mul(n.into())) + // Minimum execution time: 375_487 nanoseconds. + Weight::from_ref_time(497_019_365) + // Standard Error: 1_141_672 + .saturating_add(Weight::from_ref_time(152_354_482).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)) @@ -2002,10 +2004,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: 381_700 nanoseconds. - Weight::from_ref_time(352_544_675) - // Standard Error: 401_504 - .saturating_add(Weight::from_ref_time(304_380_106).saturating_mul(r.into())) + // Minimum execution time: 294_716 nanoseconds. + Weight::from_ref_time(266_187_186) + // Standard Error: 395_323 + .saturating_add(Weight::from_ref_time(309_907_221).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)) @@ -2013,10 +2015,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: 455_595 nanoseconds. - Weight::from_ref_time(560_428_166) - // Standard Error: 991_088 - .saturating_add(Weight::from_ref_time(61_810_610).saturating_mul(n.into())) + // Minimum execution time: 371_667 nanoseconds. + Weight::from_ref_time(478_075_482) + // Standard Error: 979_116 + .saturating_add(Weight::from_ref_time(62_075_707).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)) @@ -2024,10 +2026,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: 382_000 nanoseconds. - Weight::from_ref_time(336_164_219) - // Standard Error: 601_744 - .saturating_add(Weight::from_ref_time(406_198_079).saturating_mul(r.into())) + // Minimum execution time: 292_147 nanoseconds. + Weight::from_ref_time(254_374_598) + // Standard Error: 442_367 + .saturating_add(Weight::from_ref_time(413_674_705).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)) @@ -2036,10 +2038,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: 482_335 nanoseconds. - Weight::from_ref_time(634_245_177) - // Standard Error: 1_418_845 - .saturating_add(Weight::from_ref_time(164_352_113).saturating_mul(n.into())) + // Minimum execution time: 398_554 nanoseconds. + Weight::from_ref_time(553_715_911) + // Standard Error: 1_415_272 + .saturating_add(Weight::from_ref_time(158_254_544).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)) @@ -2052,10 +2054,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: 382_142 nanoseconds. - Weight::from_ref_time(317_581_708) - // Standard Error: 682_156 - .saturating_add(Weight::from_ref_time(1_305_289_569).saturating_mul(r.into())) + // Minimum execution time: 295_081 nanoseconds. + Weight::from_ref_time(253_461_581) + // Standard Error: 740_198 + .saturating_add(Weight::from_ref_time(1_369_153_623).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)) @@ -2068,10 +2070,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: 383_580 nanoseconds. - Weight::from_ref_time(384_176_000) - // Standard Error: 6_483_482 - .saturating_add(Weight::from_ref_time(28_047_685_517).saturating_mul(r.into())) + // Minimum execution time: 296_089 nanoseconds. + Weight::from_ref_time(297_193_000) + // Standard Error: 6_571_547 + .saturating_add(Weight::from_ref_time(21_080_280_397).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)) @@ -2084,10 +2086,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: 384_523 nanoseconds. - Weight::from_ref_time(385_105_000) - // Standard Error: 6_156_142 - .saturating_add(Weight::from_ref_time(27_780_652_513).saturating_mul(r.into())) + // Minimum execution time: 296_828 nanoseconds. + Weight::from_ref_time(297_685_000) + // Standard Error: 6_864_880 + .saturating_add(Weight::from_ref_time(20_770_321_946).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)) @@ -2101,12 +2103,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: 9_509_961 nanoseconds. - Weight::from_ref_time(8_509_991_348) - // Standard Error: 6_614_757 - .saturating_add(Weight::from_ref_time(1_244_514_376).saturating_mul(t.into())) - // Standard Error: 9_918 - .saturating_add(Weight::from_ref_time(9_856_517).saturating_mul(c.into())) + // Minimum execution time: 9_824_671 nanoseconds. + Weight::from_ref_time(8_713_861_450) + // Standard Error: 7_388_925 + .saturating_add(Weight::from_ref_time(1_327_819_806).saturating_mul(t.into())) + // Standard Error: 11_079 + .saturating_add(Weight::from_ref_time(9_789_514).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)) @@ -2121,10 +2123,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: 384_604 nanoseconds. - Weight::from_ref_time(385_278_000) - // Standard Error: 21_140_468 - .saturating_add(Weight::from_ref_time(33_100_726_150).saturating_mul(r.into())) + // Minimum execution time: 293_374 nanoseconds. + Weight::from_ref_time(302_067_000) + // Standard Error: 20_137_097 + .saturating_add(Weight::from_ref_time(26_444_812_817).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)) @@ -2141,12 +2143,14 @@ impl WeightInfo for () { /// The range of component `i` is `[0, 960]`. /// The range of component `s` is `[0, 960]`. fn seal_instantiate_per_transfer_input_salt_kb(t: u32, i: u32, s: u32, ) -> Weight { - // Minimum execution time: 129_699_480 nanoseconds. - Weight::from_ref_time(10_187_699_005) - // Standard Error: 155_040 - .saturating_add(Weight::from_ref_time(125_284_310).saturating_mul(i.into())) - // Standard Error: 155_040 - .saturating_add(Weight::from_ref_time(125_850_564).saturating_mul(s.into())) + // Minimum execution time: 126_456_770 nanoseconds. + Weight::from_ref_time(9_223_715_752) + // Standard Error: 96_040_318 + .saturating_add(Weight::from_ref_time(19_550_519).saturating_mul(t.into())) + // Standard Error: 156_614 + .saturating_add(Weight::from_ref_time(122_958_298).saturating_mul(i.into())) + // Standard Error: 156_614 + .saturating_add(Weight::from_ref_time(123_316_079).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)) @@ -2159,10 +2163,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: 380_397 nanoseconds. - Weight::from_ref_time(382_881_855) - // Standard Error: 290_948 - .saturating_add(Weight::from_ref_time(41_017_644).saturating_mul(r.into())) + // Minimum execution time: 289_275 nanoseconds. + Weight::from_ref_time(297_803_961) + // Standard Error: 303_405 + .saturating_add(Weight::from_ref_time(40_800_138).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -2173,10 +2177,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: 422_439 nanoseconds. - Weight::from_ref_time(423_480_000) - // Standard Error: 56_072 - .saturating_add(Weight::from_ref_time(329_103_825).saturating_mul(n.into())) + // Minimum execution time: 336_077 nanoseconds. + Weight::from_ref_time(336_846_000) + // Standard Error: 51_610 + .saturating_add(Weight::from_ref_time(322_208_787).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -2187,10 +2191,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: 380_433 nanoseconds. - Weight::from_ref_time(382_325_624) - // Standard Error: 139_248 - .saturating_add(Weight::from_ref_time(53_159_175).saturating_mul(r.into())) + // Minimum execution time: 290_189 nanoseconds. + Weight::from_ref_time(298_454_259) + // Standard Error: 252_946 + .saturating_add(Weight::from_ref_time(55_034_240).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -2201,10 +2205,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: 434_834 nanoseconds. - Weight::from_ref_time(435_383_000) - // Standard Error: 59_824 - .saturating_add(Weight::from_ref_time(251_297_967).saturating_mul(n.into())) + // Minimum execution time: 350_030 nanoseconds. + Weight::from_ref_time(351_356_000) + // Standard Error: 57_422 + .saturating_add(Weight::from_ref_time(256_912_844).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -2215,10 +2219,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: 379_088 nanoseconds. - Weight::from_ref_time(381_627_077) - // Standard Error: 152_561 - .saturating_add(Weight::from_ref_time(31_696_922).saturating_mul(r.into())) + // Minimum execution time: 288_480 nanoseconds. + Weight::from_ref_time(297_613_263) + // Standard Error: 456_736 + .saturating_add(Weight::from_ref_time(38_100_936).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -2229,10 +2233,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: 411_630 nanoseconds. - Weight::from_ref_time(412_354_000) - // Standard Error: 50_788 - .saturating_add(Weight::from_ref_time(103_105_715).saturating_mul(n.into())) + // Minimum execution time: 321_195 nanoseconds. + Weight::from_ref_time(325_561_000) + // Standard Error: 46_289 + .saturating_add(Weight::from_ref_time(99_536_902).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -2243,10 +2247,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: 379_549 nanoseconds. - Weight::from_ref_time(382_406_346) - // Standard Error: 701_449 - .saturating_add(Weight::from_ref_time(31_066_353).saturating_mul(r.into())) + // Minimum execution time: 287_659 nanoseconds. + Weight::from_ref_time(295_963_340) + // Standard Error: 433_889 + .saturating_add(Weight::from_ref_time(30_251_859).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -2257,10 +2261,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: 412_112 nanoseconds. - Weight::from_ref_time(412_710_000) - // Standard Error: 54_875 - .saturating_add(Weight::from_ref_time(103_169_035).saturating_mul(n.into())) + // Minimum execution time: 324_298 nanoseconds. + Weight::from_ref_time(325_738_000) + // Standard Error: 48_563 + .saturating_add(Weight::from_ref_time(99_479_838).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -2271,10 +2275,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: 381_994 nanoseconds. - Weight::from_ref_time(383_832_551) - // Standard Error: 676_656 - .saturating_add(Weight::from_ref_time(3_020_035_748).saturating_mul(r.into())) + // Minimum execution time: 294_257 nanoseconds. + Weight::from_ref_time(299_467_620) + // Standard Error: 589_749 + .saturating_add(Weight::from_ref_time(3_015_389_579).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -2285,10 +2289,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: 381_472 nanoseconds. - Weight::from_ref_time(383_590_834) - // Standard Error: 538_574 - .saturating_add(Weight::from_ref_time(2_077_926_265).saturating_mul(r.into())) + // Minimum execution time: 289_480 nanoseconds. + Weight::from_ref_time(298_762_412) + // Standard Error: 397_004 + .saturating_add(Weight::from_ref_time(743_937_087).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -2300,10 +2304,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: 381_527 nanoseconds. - Weight::from_ref_time(382_291_000) - // Standard Error: 2_760_840 - .saturating_add(Weight::from_ref_time(1_356_115_009).saturating_mul(r.into())) + // Minimum execution time: 293_494 nanoseconds. + Weight::from_ref_time(297_756_000) + // Standard Error: 2_731_227 + .saturating_add(Weight::from_ref_time(1_387_380_436).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)) @@ -2316,10 +2320,10 @@ 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: 382_722 nanoseconds. - Weight::from_ref_time(387_231_409) - // Standard Error: 28_817 - .saturating_add(Weight::from_ref_time(11_349_809).saturating_mul(r.into())) + // Minimum execution time: 295_339 nanoseconds. + Weight::from_ref_time(301_577_907) + // Standard Error: 23_836 + .saturating_add(Weight::from_ref_time(10_876_508).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -2330,10 +2334,10 @@ 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: 383_568 nanoseconds. - Weight::from_ref_time(419_835_108) - // Standard Error: 125_982 - .saturating_add(Weight::from_ref_time(25_241_800).saturating_mul(r.into())) + // Minimum execution time: 297_096 nanoseconds. + Weight::from_ref_time(336_319_823) + // Standard Error: 128_941 + .saturating_add(Weight::from_ref_time(25_211_374).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -2345,375 +2349,375 @@ impl WeightInfo for () { // 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: 382_084 nanoseconds. - Weight::from_ref_time(388_155_568) - // Standard Error: 29_161 - .saturating_add(Weight::from_ref_time(9_015_217).saturating_mul(r.into())) + // Minimum execution time: 293_819 nanoseconds. + Weight::from_ref_time(302_765_659) + // Standard Error: 28_518 + .saturating_add(Weight::from_ref_time(9_325_552).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: 593 nanoseconds. - Weight::from_ref_time(816_706) - // Standard Error: 173 - .saturating_add(Weight::from_ref_time(344_732).saturating_mul(r.into())) + // Minimum execution time: 805 nanoseconds. + Weight::from_ref_time(1_002_066) + // Standard Error: 609 + .saturating_add(Weight::from_ref_time(346_608).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64load(r: u32, ) -> Weight { - // Minimum execution time: 705 nanoseconds. - Weight::from_ref_time(1_191_205) - // Standard Error: 600 - .saturating_add(Weight::from_ref_time(986_102).saturating_mul(r.into())) + // Minimum execution time: 917 nanoseconds. + Weight::from_ref_time(1_247_710) + // Standard Error: 1_069 + .saturating_add(Weight::from_ref_time(984_608).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64store(r: u32, ) -> Weight { - // Minimum execution time: 717 nanoseconds. - Weight::from_ref_time(1_019_448) - // Standard Error: 421 - .saturating_add(Weight::from_ref_time(882_531).saturating_mul(r.into())) + // Minimum execution time: 917 nanoseconds. + Weight::from_ref_time(1_244_315) + // Standard Error: 524 + .saturating_add(Weight::from_ref_time(882_167).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_select(r: u32, ) -> Weight { - // Minimum execution time: 642 nanoseconds. - Weight::from_ref_time(917_880) - // Standard Error: 362 - .saturating_add(Weight::from_ref_time(957_235).saturating_mul(r.into())) + // Minimum execution time: 791 nanoseconds. + Weight::from_ref_time(1_119_053) + // Standard Error: 379 + .saturating_add(Weight::from_ref_time(956_169).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_if(r: u32, ) -> Weight { - // Minimum execution time: 630 nanoseconds. - Weight::from_ref_time(694_427) - // Standard Error: 1_506 - .saturating_add(Weight::from_ref_time(1_298_411).saturating_mul(r.into())) + // Minimum execution time: 782 nanoseconds. + Weight::from_ref_time(773_373) + // Standard Error: 463 + .saturating_add(Weight::from_ref_time(1_299_306).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_br(r: u32, ) -> Weight { - // Minimum execution time: 634 nanoseconds. - Weight::from_ref_time(1_101_754) - // Standard Error: 840 - .saturating_add(Weight::from_ref_time(526_433).saturating_mul(r.into())) + // Minimum execution time: 743 nanoseconds. + Weight::from_ref_time(1_273_896) + // Standard Error: 925 + .saturating_add(Weight::from_ref_time(527_015).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_br_if(r: u32, ) -> Weight { - // Minimum execution time: 651 nanoseconds. - Weight::from_ref_time(790_908) - // Standard Error: 849 - .saturating_add(Weight::from_ref_time(800_188).saturating_mul(r.into())) + // Minimum execution time: 761 nanoseconds. + Weight::from_ref_time(929_565) + // Standard Error: 1_275 + .saturating_add(Weight::from_ref_time(805_592).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_br_table(r: u32, ) -> Weight { - // Minimum execution time: 622 nanoseconds. - Weight::from_ref_time(416_266) - // Standard Error: 1_574 - .saturating_add(Weight::from_ref_time(1_080_225).saturating_mul(r.into())) + // Minimum execution time: 813 nanoseconds. + Weight::from_ref_time(703_802) + // Standard Error: 1_665 + .saturating_add(Weight::from_ref_time(1_074_321).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_131 nanoseconds. - Weight::from_ref_time(2_540_446) - // Standard Error: 75 - .saturating_add(Weight::from_ref_time(4_997).saturating_mul(e.into())) + // Minimum execution time: 2_347 nanoseconds. + Weight::from_ref_time(2_752_638) + // Standard Error: 69 + .saturating_add(Weight::from_ref_time(4_771).saturating_mul(e.into())) } /// The range of component `r` is `[0, 50]`. fn instr_call(r: u32, ) -> Weight { - // Minimum execution time: 650 nanoseconds. - Weight::from_ref_time(1_577_978) - // Standard Error: 2_696 - .saturating_add(Weight::from_ref_time(2_204_044).saturating_mul(r.into())) + // Minimum execution time: 826 nanoseconds. + Weight::from_ref_time(1_784_596) + // Standard Error: 1_646 + .saturating_add(Weight::from_ref_time(2_189_993).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_call_indirect(r: u32, ) -> Weight { - // Minimum execution time: 742 nanoseconds. - Weight::from_ref_time(1_947_575) - // Standard Error: 1_651 - .saturating_add(Weight::from_ref_time(2_799_445).saturating_mul(r.into())) + // Minimum execution time: 926 nanoseconds. + Weight::from_ref_time(1_898_358) + // Standard Error: 2_678 + .saturating_add(Weight::from_ref_time(2_811_379).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_230 nanoseconds. - Weight::from_ref_time(5_079_432) - // Standard Error: 315 - .saturating_add(Weight::from_ref_time(179_278).saturating_mul(p.into())) + // Minimum execution time: 4_428 nanoseconds. + Weight::from_ref_time(5_257_445) + // Standard Error: 306 + .saturating_add(Weight::from_ref_time(178_882).saturating_mul(p.into())) } /// The range of component `l` is `[0, 1024]`. fn instr_call_per_local(l: u32, ) -> Weight { - // Minimum execution time: 2_830 nanoseconds. - Weight::from_ref_time(3_601_633) - // Standard Error: 31 - .saturating_add(Weight::from_ref_time(92_499).saturating_mul(l.into())) + // Minimum execution time: 2_945 nanoseconds. + Weight::from_ref_time(4_240_619) + // Standard Error: 39 + .saturating_add(Weight::from_ref_time(46_640).saturating_mul(l.into())) } /// The range of component `r` is `[0, 50]`. fn instr_local_get(r: u32, ) -> Weight { - // Minimum execution time: 2_896 nanoseconds. - Weight::from_ref_time(3_137_247) - // Standard Error: 245 - .saturating_add(Weight::from_ref_time(364_431).saturating_mul(r.into())) + // Minimum execution time: 2_204 nanoseconds. + Weight::from_ref_time(2_430_272) + // Standard Error: 270 + .saturating_add(Weight::from_ref_time(365_718).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_local_set(r: u32, ) -> Weight { - // Minimum execution time: 2_795 nanoseconds. - Weight::from_ref_time(3_199_878) - // Standard Error: 549 - .saturating_add(Weight::from_ref_time(380_524).saturating_mul(r.into())) + // Minimum execution time: 2_117 nanoseconds. + Weight::from_ref_time(2_429_354) + // Standard Error: 240 + .saturating_add(Weight::from_ref_time(381_830).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_local_tee(r: u32, ) -> Weight { - // Minimum execution time: 2_807 nanoseconds. - Weight::from_ref_time(3_130_120) - // Standard Error: 319 - .saturating_add(Weight::from_ref_time(525_857).saturating_mul(r.into())) + // Minimum execution time: 2_123 nanoseconds. + Weight::from_ref_time(2_460_016) + // Standard Error: 262 + .saturating_add(Weight::from_ref_time(526_554).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_global_get(r: u32, ) -> Weight { - // Minimum execution time: 678 nanoseconds. - Weight::from_ref_time(1_013_348) - // Standard Error: 362 - .saturating_add(Weight::from_ref_time(810_232).saturating_mul(r.into())) + // Minimum execution time: 892 nanoseconds. + Weight::from_ref_time(1_234_618) + // Standard Error: 485 + .saturating_add(Weight::from_ref_time(813_721).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_global_set(r: u32, ) -> Weight { - // Minimum execution time: 624 nanoseconds. - Weight::from_ref_time(973_583) - // Standard Error: 373 - .saturating_add(Weight::from_ref_time(829_360).saturating_mul(r.into())) + // Minimum execution time: 901 nanoseconds. + Weight::from_ref_time(1_182_838) + // Standard Error: 482 + .saturating_add(Weight::from_ref_time(831_308).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_memory_current(r: u32, ) -> Weight { - // Minimum execution time: 698 nanoseconds. - Weight::from_ref_time(904_862) - // Standard Error: 360 - .saturating_add(Weight::from_ref_time(694_614).saturating_mul(r.into())) + // Minimum execution time: 929 nanoseconds. + Weight::from_ref_time(1_221_388) + // Standard Error: 434 + .saturating_add(Weight::from_ref_time(693_301).saturating_mul(r.into())) } /// The range of component `r` is `[0, 1]`. fn instr_memory_grow(r: u32, ) -> Weight { - // Minimum execution time: 642 nanoseconds. - Weight::from_ref_time(735_085) - // Standard Error: 105_815 - .saturating_add(Weight::from_ref_time(233_816_514).saturating_mul(r.into())) + // Minimum execution time: 808 nanoseconds. + Weight::from_ref_time(906_944) + // Standard Error: 6_164 + .saturating_add(Weight::from_ref_time(187_445_255).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64clz(r: u32, ) -> Weight { - // Minimum execution time: 606 nanoseconds. - Weight::from_ref_time(850_590) - // Standard Error: 262 - .saturating_add(Weight::from_ref_time(507_721).saturating_mul(r.into())) + // Minimum execution time: 807 nanoseconds. + Weight::from_ref_time(1_064_776) + // Standard Error: 287 + .saturating_add(Weight::from_ref_time(507_278).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ctz(r: u32, ) -> Weight { - // Minimum execution time: 663 nanoseconds. - Weight::from_ref_time(853_060) - // Standard Error: 250 - .saturating_add(Weight::from_ref_time(514_225).saturating_mul(r.into())) + // Minimum execution time: 776 nanoseconds. + Weight::from_ref_time(1_033_205) + // Standard Error: 443 + .saturating_add(Weight::from_ref_time(512_445).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64popcnt(r: u32, ) -> Weight { - // Minimum execution time: 605 nanoseconds. - Weight::from_ref_time(849_563) - // Standard Error: 275 - .saturating_add(Weight::from_ref_time(511_494).saturating_mul(r.into())) + // Minimum execution time: 909 nanoseconds. + Weight::from_ref_time(1_089_083) + // Standard Error: 335 + .saturating_add(Weight::from_ref_time(510_392).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64eqz(r: u32, ) -> Weight { - // Minimum execution time: 618 nanoseconds. - Weight::from_ref_time(839_855) - // Standard Error: 228 - .saturating_add(Weight::from_ref_time(524_614).saturating_mul(r.into())) + // Minimum execution time: 791 nanoseconds. + Weight::from_ref_time(1_063_118) + // Standard Error: 210 + .saturating_add(Weight::from_ref_time(522_817).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendsi32(r: u32, ) -> Weight { - // Minimum execution time: 637 nanoseconds. - Weight::from_ref_time(860_326) + // Minimum execution time: 789 nanoseconds. + Weight::from_ref_time(1_056_006) // Standard Error: 240 - .saturating_add(Weight::from_ref_time(504_847).saturating_mul(r.into())) + .saturating_add(Weight::from_ref_time(505_198).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendui32(r: u32, ) -> Weight { - // Minimum execution time: 623 nanoseconds. - Weight::from_ref_time(844_585) - // Standard Error: 235 - .saturating_add(Weight::from_ref_time(505_821).saturating_mul(r.into())) + // Minimum execution time: 804 nanoseconds. + Weight::from_ref_time(1_087_882) + // Standard Error: 234 + .saturating_add(Weight::from_ref_time(503_830).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i32wrapi64(r: u32, ) -> Weight { - // Minimum execution time: 672 nanoseconds. - Weight::from_ref_time(826_784) - // Standard Error: 225 - .saturating_add(Weight::from_ref_time(504_632).saturating_mul(r.into())) + // Minimum execution time: 756 nanoseconds. + Weight::from_ref_time(1_050_994) + // Standard Error: 172 + .saturating_add(Weight::from_ref_time(503_343).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64eq(r: u32, ) -> Weight { - // Minimum execution time: 642 nanoseconds. - Weight::from_ref_time(867_080) - // Standard Error: 231 - .saturating_add(Weight::from_ref_time(732_430).saturating_mul(r.into())) + // Minimum execution time: 775 nanoseconds. + Weight::from_ref_time(1_061_228) + // Standard Error: 232 + .saturating_add(Weight::from_ref_time(730_751).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ne(r: u32, ) -> Weight { - // Minimum execution time: 639 nanoseconds. - Weight::from_ref_time(866_094) - // Standard Error: 272 - .saturating_add(Weight::from_ref_time(732_560).saturating_mul(r.into())) + // Minimum execution time: 809 nanoseconds. + Weight::from_ref_time(1_080_957) + // Standard Error: 320 + .saturating_add(Weight::from_ref_time(732_246).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64lts(r: u32, ) -> Weight { - // Minimum execution time: 619 nanoseconds. - Weight::from_ref_time(928_672) - // Standard Error: 484 - .saturating_add(Weight::from_ref_time(739_523).saturating_mul(r.into())) + // Minimum execution time: 808 nanoseconds. + Weight::from_ref_time(1_055_752) + // Standard Error: 496 + .saturating_add(Weight::from_ref_time(740_084).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ltu(r: u32, ) -> Weight { - // Minimum execution time: 612 nanoseconds. - Weight::from_ref_time(863_312) - // Standard Error: 328 - .saturating_add(Weight::from_ref_time(743_687).saturating_mul(r.into())) + // Minimum execution time: 792 nanoseconds. + Weight::from_ref_time(1_111_972) + // Standard Error: 270 + .saturating_add(Weight::from_ref_time(741_581).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64gts(r: u32, ) -> Weight { - // Minimum execution time: 648 nanoseconds. - Weight::from_ref_time(931_331) - // Standard Error: 612 - .saturating_add(Weight::from_ref_time(747_653).saturating_mul(r.into())) + // Minimum execution time: 862 nanoseconds. + Weight::from_ref_time(1_111_246) + // Standard Error: 263 + .saturating_add(Weight::from_ref_time(746_026).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64gtu(r: u32, ) -> Weight { - // Minimum execution time: 632 nanoseconds. - Weight::from_ref_time(868_901) - // Standard Error: 276 - .saturating_add(Weight::from_ref_time(744_778).saturating_mul(r.into())) + // Minimum execution time: 810 nanoseconds. + Weight::from_ref_time(1_094_933) + // Standard Error: 271 + .saturating_add(Weight::from_ref_time(743_645).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64les(r: u32, ) -> Weight { - // Minimum execution time: 629 nanoseconds. - Weight::from_ref_time(898_516) - // Standard Error: 288 - .saturating_add(Weight::from_ref_time(734_393).saturating_mul(r.into())) + // Minimum execution time: 769 nanoseconds. + Weight::from_ref_time(819_933) + // Standard Error: 4_528 + .saturating_add(Weight::from_ref_time(751_599).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64leu(r: u32, ) -> Weight { - // Minimum execution time: 603 nanoseconds. - Weight::from_ref_time(853_744) - // Standard Error: 204 - .saturating_add(Weight::from_ref_time(739_499).saturating_mul(r.into())) + // Minimum execution time: 797 nanoseconds. + Weight::from_ref_time(1_107_352) + // Standard Error: 344 + .saturating_add(Weight::from_ref_time(738_684).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(885_174) - // Standard Error: 238 - .saturating_add(Weight::from_ref_time(734_010).saturating_mul(r.into())) + // Minimum execution time: 784 nanoseconds. + Weight::from_ref_time(1_068_487) + // Standard Error: 3_796 + .saturating_add(Weight::from_ref_time(741_207).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64geu(r: u32, ) -> Weight { - // Minimum execution time: 602 nanoseconds. - Weight::from_ref_time(915_329) - // Standard Error: 273 - .saturating_add(Weight::from_ref_time(738_209).saturating_mul(r.into())) + // Minimum execution time: 813 nanoseconds. + Weight::from_ref_time(1_067_278) + // Standard Error: 459 + .saturating_add(Weight::from_ref_time(737_841).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64add(r: u32, ) -> Weight { - // Minimum execution time: 585 nanoseconds. - Weight::from_ref_time(862_239) - // Standard Error: 294 - .saturating_add(Weight::from_ref_time(719_000).saturating_mul(r.into())) + // Minimum execution time: 798 nanoseconds. + Weight::from_ref_time(1_100_254) + // Standard Error: 297 + .saturating_add(Weight::from_ref_time(717_622).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64sub(r: u32, ) -> Weight { - // Minimum execution time: 633 nanoseconds. - Weight::from_ref_time(881_696) - // Standard Error: 195 - .saturating_add(Weight::from_ref_time(713_153).saturating_mul(r.into())) + // Minimum execution time: 778 nanoseconds. + Weight::from_ref_time(1_063_748) + // Standard Error: 378 + .saturating_add(Weight::from_ref_time(713_577).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64mul(r: u32, ) -> Weight { - // Minimum execution time: 629 nanoseconds. - Weight::from_ref_time(856_238) - // Standard Error: 269 - .saturating_add(Weight::from_ref_time(715_451).saturating_mul(r.into())) + // Minimum execution time: 780 nanoseconds. + Weight::from_ref_time(1_088_755) + // Standard Error: 316 + .saturating_add(Weight::from_ref_time(714_127).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64divs(r: u32, ) -> Weight { - // Minimum execution time: 633 nanoseconds. - Weight::from_ref_time(880_804) - // Standard Error: 725 - .saturating_add(Weight::from_ref_time(1_349_577).saturating_mul(r.into())) + // Minimum execution time: 776 nanoseconds. + Weight::from_ref_time(1_062_591) + // Standard Error: 610 + .saturating_add(Weight::from_ref_time(1_355_430).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64divu(r: u32, ) -> Weight { - // Minimum execution time: 639 nanoseconds. - Weight::from_ref_time(867_528) - // Standard Error: 1_940 - .saturating_add(Weight::from_ref_time(1_287_959).saturating_mul(r.into())) + // Minimum execution time: 801 nanoseconds. + Weight::from_ref_time(1_092_395) + // Standard Error: 423 + .saturating_add(Weight::from_ref_time(1_282_356).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64rems(r: u32, ) -> Weight { - // Minimum execution time: 595 nanoseconds. - Weight::from_ref_time(851_253) - // Standard Error: 503 - .saturating_add(Weight::from_ref_time(1_398_668).saturating_mul(r.into())) + // Minimum execution time: 822 nanoseconds. + Weight::from_ref_time(1_083_079) + // Standard Error: 562 + .saturating_add(Weight::from_ref_time(1_398_522).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64remu(r: u32, ) -> Weight { - // Minimum execution time: 604 nanoseconds. - Weight::from_ref_time(804_977) - // Standard Error: 812 - .saturating_add(Weight::from_ref_time(1_288_816).saturating_mul(r.into())) + // Minimum execution time: 798 nanoseconds. + Weight::from_ref_time(1_088_997) + // Standard Error: 401 + .saturating_add(Weight::from_ref_time(1_283_442).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64and(r: u32, ) -> Weight { - // Minimum execution time: 609 nanoseconds. - Weight::from_ref_time(890_945) - // Standard Error: 1_645 - .saturating_add(Weight::from_ref_time(719_770).saturating_mul(r.into())) + // Minimum execution time: 815 nanoseconds. + Weight::from_ref_time(1_081_903) + // Standard Error: 264 + .saturating_add(Weight::from_ref_time(718_069).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64or(r: u32, ) -> Weight { - // Minimum execution time: 628 nanoseconds. - Weight::from_ref_time(897_973) - // Standard Error: 1_641 - .saturating_add(Weight::from_ref_time(718_838).saturating_mul(r.into())) + // Minimum execution time: 813 nanoseconds. + Weight::from_ref_time(1_091_426) + // Standard Error: 296 + .saturating_add(Weight::from_ref_time(717_894).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64xor(r: u32, ) -> Weight { - // Minimum execution time: 634 nanoseconds. - Weight::from_ref_time(848_440) - // Standard Error: 249 - .saturating_add(Weight::from_ref_time(718_206).saturating_mul(r.into())) + // Minimum execution time: 794 nanoseconds. + Weight::from_ref_time(1_040_144) + // Standard Error: 400 + .saturating_add(Weight::from_ref_time(719_886).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64shl(r: u32, ) -> Weight { - // Minimum execution time: 625 nanoseconds. - Weight::from_ref_time(881_579) - // Standard Error: 273 - .saturating_add(Weight::from_ref_time(736_934).saturating_mul(r.into())) + // Minimum execution time: 774 nanoseconds. + Weight::from_ref_time(1_092_466) + // Standard Error: 4_173 + .saturating_add(Weight::from_ref_time(739_873).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64shrs(r: u32, ) -> Weight { - // Minimum execution time: 630 nanoseconds. - Weight::from_ref_time(897_813) - // Standard Error: 249 - .saturating_add(Weight::from_ref_time(734_657).saturating_mul(r.into())) + // Minimum execution time: 793 nanoseconds. + Weight::from_ref_time(1_105_611) + // Standard Error: 394 + .saturating_add(Weight::from_ref_time(735_358).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64shru(r: u32, ) -> Weight { - // Minimum execution time: 607 nanoseconds. - Weight::from_ref_time(871_660) - // Standard Error: 312 - .saturating_add(Weight::from_ref_time(735_377).saturating_mul(r.into())) + // Minimum execution time: 805 nanoseconds. + Weight::from_ref_time(1_130_462) + // Standard Error: 327 + .saturating_add(Weight::from_ref_time(734_198).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotl(r: u32, ) -> Weight { - // Minimum execution time: 610 nanoseconds. - Weight::from_ref_time(861_640) - // Standard Error: 293 - .saturating_add(Weight::from_ref_time(735_524).saturating_mul(r.into())) + // Minimum execution time: 831 nanoseconds. + Weight::from_ref_time(1_118_894) + // Standard Error: 389 + .saturating_add(Weight::from_ref_time(733_834).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotr(r: u32, ) -> Weight { - // Minimum execution time: 625 nanoseconds. - Weight::from_ref_time(880_203) - // Standard Error: 373 - .saturating_add(Weight::from_ref_time(737_354).saturating_mul(r.into())) + // Minimum execution time: 772 nanoseconds. + Weight::from_ref_time(1_123_733) + // Standard Error: 337 + .saturating_add(Weight::from_ref_time(733_923).saturating_mul(r.into())) } } From 293c1f24e968a8d956250324fb7e91b7df4507df Mon Sep 17 00:00:00 2001 From: Jegor Sidorenko <5252494+jsidorenko@users.noreply.github.com> Date: Wed, 11 Jan 2023 15:27:59 +0200 Subject: [PATCH 277/715] [NFTs] Track item's metadata depositor (#13124) * Refactor do_mint() * Track the depositor of item's metadata * Revert back the access control * On collection destroy return the metadata deposit * Clear the metadata on item burn returning the deposit * Address comments * Fix clippy * Don't return Ok on non-existing attribute removal --- frame/nfts/src/features/attributes.rs | 105 +++++++++--------- .../src/features/create_delete_collection.rs | 13 ++- frame/nfts/src/features/create_delete_item.rs | 31 ++++-- frame/nfts/src/features/metadata.rs | 69 ++++++++---- frame/nfts/src/impl_nonfungibles.rs | 6 +- frame/nfts/src/lib.rs | 17 +-- frame/nfts/src/tests.rs | 4 +- frame/nfts/src/types.rs | 22 +++- 8 files changed, 161 insertions(+), 106 deletions(-) diff --git a/frame/nfts/src/features/attributes.rs b/frame/nfts/src/features/attributes.rs index da663d39a4ef5..b25f2a60cd62d 100644 --- a/frame/nfts/src/features/attributes.rs +++ b/frame/nfts/src/features/attributes.rs @@ -152,65 +152,68 @@ impl, I: 'static> Pallet { namespace: AttributeNamespace, key: BoundedVec, ) -> DispatchResult { - if let Some((_, deposit)) = - Attribute::::take((collection, maybe_item, &namespace, &key)) - { - let mut collection_details = - Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; - - if let Some(check_owner) = &maybe_check_owner { - if deposit.account != maybe_check_owner { - ensure!( - Self::is_valid_namespace( - &check_owner, - &namespace, - &collection, - &collection_details.owner, - &maybe_item, - )?, - Error::::NoPermission - ); - } + let (_, deposit) = Attribute::::take((collection, maybe_item, &namespace, &key)) + .ok_or(Error::::AttributeNotFound)?; + let mut collection_details = + Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; - // can't clear `CollectionOwner` type attributes if the collection/item is locked - match namespace { - AttributeNamespace::CollectionOwner => match maybe_item { - None => { - let collection_config = Self::get_collection_config(&collection)?; - ensure!( - collection_config - .is_setting_enabled(CollectionSetting::UnlockedAttributes), - Error::::LockedCollectionAttributes - ) - }, - Some(item) => { - // NOTE: if the item was previously burned, the ItemConfigOf record - // might not exist. In that case, we allow to clear the attribute. - let maybe_is_locked = Self::get_item_config(&collection, &item) - .map_or(false, |c| { - c.has_disabled_setting(ItemSetting::UnlockedAttributes) - }); - ensure!(!maybe_is_locked, Error::::LockedItemAttributes); - }, - }, - _ => (), - }; + if let Some(check_owner) = &maybe_check_owner { + // validate the provided namespace when it's not a root call and the caller is not + // the same as the `deposit.account` (e.g. the deposit was paid by different account) + if deposit.account != maybe_check_owner { + ensure!( + Self::is_valid_namespace( + &check_owner, + &namespace, + &collection, + &collection_details.owner, + &maybe_item, + )?, + Error::::NoPermission + ); } - collection_details.attributes.saturating_dec(); + // can't clear `CollectionOwner` type attributes if the collection/item is locked match namespace { - AttributeNamespace::CollectionOwner => { - collection_details.owner_deposit.saturating_reduce(deposit.amount); - T::Currency::unreserve(&collection_details.owner, deposit.amount); + AttributeNamespace::CollectionOwner => match maybe_item { + None => { + let collection_config = Self::get_collection_config(&collection)?; + ensure!( + collection_config + .is_setting_enabled(CollectionSetting::UnlockedAttributes), + Error::::LockedCollectionAttributes + ) + }, + Some(item) => { + // NOTE: if the item was previously burned, the ItemConfigOf record + // might not exist. In that case, we allow to clear the attribute. + let maybe_is_locked = Self::get_item_config(&collection, &item) + .map_or(false, |c| { + c.has_disabled_setting(ItemSetting::UnlockedAttributes) + }); + ensure!(!maybe_is_locked, Error::::LockedItemAttributes); + }, }, _ => (), }; - if let Some(deposit_account) = deposit.account { - T::Currency::unreserve(&deposit_account, deposit.amount); - } - Collection::::insert(collection, &collection_details); - Self::deposit_event(Event::AttributeCleared { collection, maybe_item, key, namespace }); } + + collection_details.attributes.saturating_dec(); + match namespace { + AttributeNamespace::CollectionOwner => { + collection_details.owner_deposit.saturating_reduce(deposit.amount); + T::Currency::unreserve(&collection_details.owner, deposit.amount); + }, + _ => (), + }; + + if let Some(deposit_account) = deposit.account { + T::Currency::unreserve(&deposit_account, deposit.amount); + } + + Collection::::insert(collection, &collection_details); + Self::deposit_event(Event::AttributeCleared { collection, maybe_item, key, namespace }); + Ok(()) } diff --git a/frame/nfts/src/features/create_delete_collection.rs b/frame/nfts/src/features/create_delete_collection.rs index 86625bf49efb2..a2caa04bc8dc3 100644 --- a/frame/nfts/src/features/create_delete_collection.rs +++ b/frame/nfts/src/features/create_delete_collection.rs @@ -82,12 +82,13 @@ impl, I: 'static> Pallet { Account::::remove((&details.owner, &collection, &item)); T::Currency::unreserve(&details.deposit.account, details.deposit.amount); } - #[allow(deprecated)] - ItemMetadataOf::::remove_prefix(&collection, None); - #[allow(deprecated)] - ItemPriceOf::::remove_prefix(&collection, None); - #[allow(deprecated)] - PendingSwapOf::::remove_prefix(&collection, None); + for (_, metadata) in ItemMetadataOf::::drain_prefix(&collection) { + if let Some(depositor) = metadata.deposit.account { + T::Currency::unreserve(&depositor, metadata.deposit.amount); + } + } + let _ = ItemPriceOf::::clear_prefix(&collection, witness.items, None); + let _ = PendingSwapOf::::clear_prefix(&collection, witness.items, None); CollectionMetadataOf::::remove(&collection); Self::clear_roles(&collection)?; diff --git a/frame/nfts/src/features/create_delete_item.rs b/frame/nfts/src/features/create_delete_item.rs index 8d6c8a280956c..f724fe5c63b43 100644 --- a/frame/nfts/src/features/create_delete_item.rs +++ b/frame/nfts/src/features/create_delete_item.rs @@ -22,10 +22,9 @@ impl, I: 'static> Pallet { pub fn do_mint( collection: T::CollectionId, item: T::ItemId, - depositor: T::AccountId, + maybe_depositor: Option, mint_to: T::AccountId, item_config: ItemConfig, - deposit_collection_owner: bool, with_details_and_config: impl FnOnce( &CollectionDetailsFor, &CollectionConfigFor, @@ -55,9 +54,9 @@ impl, I: 'static> Pallet { true => T::ItemDeposit::get(), false => Zero::zero(), }; - let deposit_account = match deposit_collection_owner { - true => collection_details.owner.clone(), - false => depositor, + let deposit_account = match maybe_depositor { + None => collection_details.owner.clone(), + Some(depositor) => depositor, }; let item_owner = mint_to.clone(); @@ -92,6 +91,7 @@ impl, I: 'static> Pallet { with_details: impl FnOnce(&ItemDetailsFor) -> DispatchResult, ) -> DispatchResult { ensure!(!T::Locker::is_locked(collection, item), Error::::ItemLocked); + let item_config = Self::get_item_config(&collection, &item)?; let owner = Collection::::try_mutate( &collection, |maybe_collection_details| -> Result { @@ -104,6 +104,24 @@ impl, I: 'static> Pallet { // Return the deposit. T::Currency::unreserve(&details.deposit.account, details.deposit.amount); collection_details.items.saturating_dec(); + + // Clear the metadata if it's not locked. + if item_config.is_setting_enabled(ItemSetting::UnlockedMetadata) { + if let Some(metadata) = ItemMetadataOf::::take(&collection, &item) { + let depositor_account = + metadata.deposit.account.unwrap_or(collection_details.owner.clone()); + + T::Currency::unreserve(&depositor_account, metadata.deposit.amount); + collection_details.item_metadatas.saturating_dec(); + + if depositor_account == collection_details.owner { + collection_details + .owner_deposit + .saturating_reduce(metadata.deposit.amount); + } + } + } + Ok(details.owner) }, )?; @@ -116,8 +134,7 @@ impl, I: 'static> Pallet { // NOTE: if item's settings are not empty (e.g. item's metadata is locked) // then we keep the record and don't remove it - let config = Self::get_item_config(&collection, &item)?; - if !config.has_disabled_settings() { + if !item_config.has_disabled_settings() { ItemConfigOf::::remove(&collection, &item); } diff --git a/frame/nfts/src/features/metadata.rs b/frame/nfts/src/features/metadata.rs index 942f377141a33..272b2247426d6 100644 --- a/frame/nfts/src/features/metadata.rs +++ b/frame/nfts/src/features/metadata.rs @@ -19,19 +19,21 @@ use crate::*; use frame_support::pallet_prelude::*; impl, I: 'static> Pallet { + /// Note: if `maybe_depositor` is None, that means the depositor will be a collection's owner pub(crate) fn do_set_item_metadata( maybe_check_owner: Option, collection: T::CollectionId, item: T::ItemId, data: BoundedVec, + maybe_depositor: Option, ) -> DispatchResult { + let is_root = maybe_check_owner.is_none(); let mut collection_details = Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; let item_config = Self::get_item_config(&collection, &item)?; ensure!( - maybe_check_owner.is_none() || - item_config.is_setting_enabled(ItemSetting::UnlockedMetadata), + is_root || item_config.is_setting_enabled(ItemSetting::UnlockedMetadata), Error::::LockedItemMetadata ); @@ -45,24 +47,38 @@ impl, I: 'static> Pallet { if metadata.is_none() { collection_details.item_metadatas.saturating_inc(); } - let old_deposit = metadata.take().map_or(Zero::zero(), |m| m.deposit); - collection_details.owner_deposit.saturating_reduce(old_deposit); + + let old_deposit = metadata + .take() + .map_or(ItemMetadataDeposit { account: None, amount: Zero::zero() }, |m| m.deposit); + let mut deposit = Zero::zero(); - if collection_config.is_setting_enabled(CollectionSetting::DepositRequired) && - maybe_check_owner.is_some() + if collection_config.is_setting_enabled(CollectionSetting::DepositRequired) && !is_root { deposit = T::DepositPerByte::get() .saturating_mul(((data.len()) as u32).into()) .saturating_add(T::MetadataDepositBase::get()); } - if deposit > old_deposit { - T::Currency::reserve(&collection_details.owner, deposit - old_deposit)?; - } else if deposit < old_deposit { - T::Currency::unreserve(&collection_details.owner, old_deposit - deposit); + + // the previous deposit was taken from the item's owner + if old_deposit.account.is_some() && maybe_depositor.is_none() { + T::Currency::unreserve(&old_deposit.account.unwrap(), old_deposit.amount); + T::Currency::reserve(&collection_details.owner, deposit)?; + } else if deposit > old_deposit.amount { + T::Currency::reserve(&collection_details.owner, deposit - old_deposit.amount)?; + } else if deposit < old_deposit.amount { + T::Currency::unreserve(&collection_details.owner, old_deposit.amount - deposit); + } + + if maybe_depositor.is_none() { + collection_details.owner_deposit.saturating_accrue(deposit); + collection_details.owner_deposit.saturating_reduce(old_deposit.amount); } - collection_details.owner_deposit.saturating_accrue(deposit); - *metadata = Some(ItemMetadata { deposit, data: data.clone() }); + *metadata = Some(ItemMetadata { + deposit: ItemMetadataDeposit { account: maybe_depositor, amount: deposit }, + data: data.clone(), + }); Collection::::insert(&collection, &collection_details); Self::deposit_event(Event::ItemMetadataSet { collection, item, data }); @@ -75,8 +91,14 @@ impl, I: 'static> Pallet { collection: T::CollectionId, item: T::ItemId, ) -> DispatchResult { + let is_root = maybe_check_owner.is_none(); + let metadata = ItemMetadataOf::::take(collection, item) + .ok_or(Error::::MetadataNotFound)?; let mut collection_details = Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; + let depositor_account = + metadata.deposit.account.unwrap_or(collection_details.owner.clone()); + if let Some(check_owner) = &maybe_check_owner { ensure!(check_owner == &collection_details.owner, Error::::NoPermission); } @@ -85,20 +107,19 @@ impl, I: 'static> Pallet { let is_locked = Self::get_item_config(&collection, &item) .map_or(false, |c| c.has_disabled_setting(ItemSetting::UnlockedMetadata)); - ensure!(maybe_check_owner.is_none() || !is_locked, Error::::LockedItemMetadata); + ensure!(is_root || !is_locked, Error::::LockedItemMetadata); - ItemMetadataOf::::try_mutate_exists(collection, item, |metadata| { - if metadata.is_some() { - collection_details.item_metadatas.saturating_dec(); - } - let deposit = metadata.take().ok_or(Error::::UnknownItem)?.deposit; - T::Currency::unreserve(&collection_details.owner, deposit); - collection_details.owner_deposit.saturating_reduce(deposit); + collection_details.item_metadatas.saturating_dec(); + T::Currency::unreserve(&depositor_account, metadata.deposit.amount); - Collection::::insert(&collection, &collection_details); - Self::deposit_event(Event::ItemMetadataCleared { collection, item }); - Ok(()) - }) + if depositor_account == collection_details.owner { + collection_details.owner_deposit.saturating_reduce(metadata.deposit.amount); + } + + Collection::::insert(&collection, &collection_details); + Self::deposit_event(Event::ItemMetadataCleared { collection, item }); + + Ok(()) } pub(crate) fn do_set_collection_metadata( diff --git a/frame/nfts/src/impl_nonfungibles.rs b/frame/nfts/src/impl_nonfungibles.rs index ab4d7a16ec215..86d82b4021517 100644 --- a/frame/nfts/src/impl_nonfungibles.rs +++ b/frame/nfts/src/impl_nonfungibles.rs @@ -157,10 +157,12 @@ impl, I: 'static> Mutate<::AccountId, ItemConfig Self::do_mint( *collection, *item, - who.clone(), + match deposit_collection_owner { + true => None, + false => Some(who.clone()), + }, who.clone(), *item_config, - deposit_collection_owner, |_, _| Ok(()), ) } diff --git a/frame/nfts/src/lib.rs b/frame/nfts/src/lib.rs index 9a6242143aedb..8f24c8dcd6e98 100644 --- a/frame/nfts/src/lib.rs +++ b/frame/nfts/src/lib.rs @@ -263,7 +263,7 @@ pub mod pallet { T::CollectionId, Blake2_128Concat, T::ItemId, - ItemMetadata, T::StringLimit>, + ItemMetadata, T::StringLimit>, OptionQuery, >; @@ -559,6 +559,10 @@ pub mod pallet { UnknownItem, /// Swap doesn't exist. UnknownSwap, + /// The given item has no metadata set. + MetadataNotFound, + /// The provided attribute can't be found. + AttributeNotFound, /// Item is not for sale. NotForSale, /// The provided bid is too low. @@ -746,10 +750,9 @@ pub mod pallet { Self::do_mint( collection, item, - caller.clone(), + Some(caller.clone()), mint_to.clone(), item_config, - false, |collection_details, collection_config| { // Issuer can mint regardless of mint settings if Self::has_role(&collection, &caller, CollectionRole::Issuer) { @@ -849,9 +852,7 @@ pub mod pallet { Error::::NoPermission ); } - Self::do_mint(collection, item, mint_to.clone(), mint_to, item_config, true, |_, _| { - Ok(()) - }) + Self::do_mint(collection, item, None, mint_to, item_config, |_, _| Ok(())) } /// Destroy a single item. @@ -1362,7 +1363,7 @@ pub mod pallet { /// Clear an attribute for a collection or item. /// /// Origin must be either `ForceOrigin` or Signed and the sender should be the Owner of the - /// `collection`. + /// attribute. /// /// Any deposit is freed for the collection's owner. /// @@ -1464,7 +1465,7 @@ pub mod pallet { let maybe_check_owner = T::ForceOrigin::try_origin(origin) .map(|_| None) .or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?; - Self::do_set_item_metadata(maybe_check_owner, collection, item, data) + Self::do_set_item_metadata(maybe_check_owner, collection, item, data, None) } /// Clear the metadata for an item. diff --git a/frame/nfts/src/tests.rs b/frame/nfts/src/tests.rs index f8187b3777ebd..ebbba33b04fa2 100644 --- a/frame/nfts/src/tests.rs +++ b/frame/nfts/src/tests.rs @@ -608,7 +608,7 @@ fn set_item_metadata_should_work() { ); assert_noop!( Nfts::clear_metadata(RuntimeOrigin::signed(1), 1, 42), - Error::::UnknownCollection, + Error::::MetadataNotFound, ); assert_ok!(Nfts::clear_metadata(RuntimeOrigin::root(), 0, 42)); assert!(!ItemMetadataOf::::contains_key(0, 42)); @@ -1267,7 +1267,7 @@ fn burn_works() { assert_noop!( Nfts::burn(RuntimeOrigin::signed(5), 0, 42, Some(5)), - Error::::UnknownCollection + Error::::UnknownItem ); assert_ok!(Nfts::force_mint(RuntimeOrigin::signed(2), 0, 42, 5, default_item_config())); diff --git a/frame/nfts/src/types.rs b/frame/nfts/src/types.rs index 9b89fb964b316..d8938aab4377a 100644 --- a/frame/nfts/src/types.rs +++ b/frame/nfts/src/types.rs @@ -43,6 +43,8 @@ pub(super) type ItemDepositOf = ItemDeposit, ::AccountId>; pub(super) type AttributeDepositOf = AttributeDeposit, ::AccountId>; +pub(super) type ItemMetadataDepositOf = + ItemMetadataDeposit, ::AccountId>; pub(super) type ItemDetailsFor = ItemDetails<::AccountId, ItemDepositOf, ApprovalsOf>; pub(super) type BalanceOf = @@ -137,12 +139,12 @@ pub struct ItemDeposit { /// Information about the collection's metadata. #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, Default, TypeInfo, MaxEncodedLen)] #[scale_info(skip_type_params(StringLimit))] -#[codec(mel_bound(DepositBalance: MaxEncodedLen))] -pub struct CollectionMetadata> { +#[codec(mel_bound(Deposit: MaxEncodedLen))] +pub struct CollectionMetadata> { /// The balance deposited for this metadata. /// /// This pays for the data stored in this struct. - pub(super) deposit: DepositBalance, + pub(super) deposit: Deposit, /// 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. @@ -152,12 +154,11 @@ pub struct CollectionMetadata> { /// Information about the item's metadata. #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, Default, TypeInfo, MaxEncodedLen)] #[scale_info(skip_type_params(StringLimit))] -#[codec(mel_bound(DepositBalance: MaxEncodedLen))] -pub struct ItemMetadata> { +pub struct ItemMetadata> { /// The balance deposited for this metadata. /// /// This pays for the data stored in this struct. - pub(super) deposit: DepositBalance, + pub(super) deposit: Deposit, /// 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. @@ -199,6 +200,15 @@ pub struct AttributeDeposit { pub(super) amount: DepositBalance, } +/// Information about the reserved item's metadata deposit. +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +pub struct ItemMetadataDeposit { + /// A depositor account, None means the deposit is collection's owner. + pub(super) account: Option, + /// An amount that gets reserved. + pub(super) amount: DepositBalance, +} + /// Specifies whether the tokens will be sent or received. #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub enum PriceDirection { From e752af116c0b92e37bb5aeef19d3934cc9347439 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 11 Jan 2023 16:40:52 +0100 Subject: [PATCH 278/715] `IntegrityTest` implementation should be feature gated (#13094) * `IntegrityTest` implementation should be feature gated The initial implementation for the old declarative macros is still feature gating the implementation. As we only call this in a test, there is no need to have this compiled for wasm. * Don't assume that all "consumers" have a `std` feature --- .../procedural/src/pallet/expand/hooks.rs | 19 +++++++++++-------- frame/support/src/lib.rs | 3 +++ frame/system/benches/bench.rs | 5 +---- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/frame/support/procedural/src/pallet/expand/hooks.rs b/frame/support/procedural/src/pallet/expand/hooks.rs index c2b70c5632f94..c41a65b57b57a 100644 --- a/frame/support/procedural/src/pallet/expand/hooks.rs +++ b/frame/support/procedural/src/pallet/expand/hooks.rs @@ -191,16 +191,19 @@ pub fn expand_hooks(def: &mut Def) -> proc_macro2::TokenStream { } } - impl<#type_impl_gen> - #frame_support::traits::IntegrityTest + // Integrity tests are only required for when `std` is enabled. + #frame_support::std_enabled! { + impl<#type_impl_gen> + #frame_support::traits::IntegrityTest for #pallet_ident<#type_use_gen> #where_clause - { - fn integrity_test() { - < - Self as #frame_support::traits::Hooks< + { + fn integrity_test() { + < + Self as #frame_support::traits::Hooks< ::BlockNumber - > - >::integrity_test() + > + >::integrity_test() + } } } diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index efecbb75f9c62..902893972f0b1 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -2744,3 +2744,6 @@ pub mod pallet_macros { type_value, unbounded, validate_unsigned, weight, whitelist_storage, }; } + +// Generate a macro that will enable/disable code based on `std` feature being active. +sp_core::generate_feature_enabled_macro!(std_enabled, feature = "std", $); diff --git a/frame/system/benches/bench.rs b/frame/system/benches/bench.rs index a623a17dc49b2..f2acc319d3f5d 100644 --- a/frame/system/benches/bench.rs +++ b/frame/system/benches/bench.rs @@ -16,10 +16,7 @@ // limitations under the License. use criterion::{black_box, criterion_group, criterion_main, Criterion}; -use frame_support::{ - traits::{ConstU32, ConstU64}, - weights::Weight, -}; +use frame_support::traits::{ConstU32, ConstU64}; use sp_core::H256; use sp_runtime::{ testing::Header, From ad58606c403e13cb1819174ec311d82a02e40028 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 11 Jan 2023 15:59:13 +0000 Subject: [PATCH 279/715] Bump git2 from 0.14.4 to 0.16.0 (#13123) Bumps [git2](https://github.com/rust-lang/git2-rs) from 0.14.4 to 0.16.0. - [Release notes](https://github.com/rust-lang/git2-rs/releases) - [Commits](https://github.com/rust-lang/git2-rs/compare/0.14.4...git2-curl-0.16.0) --- updated-dependencies: - dependency-name: git2 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 | 8 ++++---- utils/frame/generate-bags/Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index eb644202ae382..68c144b3f177e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2705,9 +2705,9 @@ checksum = "dec7af912d60cdbd3677c1af9352ebae6fb8394d165568a2234df0fa00f87793" [[package]] name = "git2" -version = "0.14.4" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0155506aab710a86160ddb504a480d2964d7ab5b9e62419be69e0032bc5931c" +checksum = "be36bc9e0546df253c0cc41fd0af34f5e92845ad8509462ec76672fac6997f5b" dependencies = [ "bitflags", "libc", @@ -3570,9 +3570,9 @@ checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" [[package]] name = "libgit2-sys" -version = "0.13.4+1.4.2" +version = "0.14.1+1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0fa6563431ede25f5cc7f6d803c6afbc1c5d3ad3d4925d12c882bf2b526f5d1" +checksum = "4a07fb2692bc3593bda59de45a502bb3071659f2c515e28c71e728306b038e17" dependencies = [ "cc", "libc", diff --git a/utils/frame/generate-bags/Cargo.toml b/utils/frame/generate-bags/Cargo.toml index 6006cdb5da0e5..a24af6a2704ae 100644 --- a/utils/frame/generate-bags/Cargo.toml +++ b/utils/frame/generate-bags/Cargo.toml @@ -17,5 +17,5 @@ pallet-staking = { version = "4.0.0-dev", path = "../../../frame/staking" } # third party chrono = { version = "0.4.19" } -git2 = { version = "0.14.2", default-features = false } +git2 = { version = "0.16.0", default-features = false } num-format = "0.4.3" From 6d3596f8a04873f965cf401a84e52d4404337424 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Wed, 11 Jan 2023 17:16:56 +0100 Subject: [PATCH 280/715] Scheduler is already at V4 (#13105) * Scheduler is already at V4 Signed-off-by: Oliver Tale-Yazdi * Fix Referenda log target Signed-off-by: Oliver Tale-Yazdi * Fix test Signed-off-by: Oliver Tale-Yazdi Signed-off-by: Oliver Tale-Yazdi --- frame/referenda/src/migration.rs | 2 +- frame/scheduler/src/lib.rs | 2 +- frame/scheduler/src/tests.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/frame/referenda/src/migration.rs b/frame/referenda/src/migration.rs index e495090c13754..39575556e4096 100644 --- a/frame/referenda/src/migration.rs +++ b/frame/referenda/src/migration.rs @@ -88,7 +88,7 @@ pub mod v1 { use super::*; /// The log target. - const TARGET: &'static str = "runtime::democracy::migration::v1"; + const TARGET: &'static str = "runtime::referenda::migration::v1"; /// Transforms a submission deposit of ReferendumInfo(Approved|Rejected|Cancelled|TimedOut) to /// optional value, making it refundable. diff --git a/frame/scheduler/src/lib.rs b/frame/scheduler/src/lib.rs index 20e14206767aa..afc4fd66e76cb 100644 --- a/frame/scheduler/src/lib.rs +++ b/frame/scheduler/src/lib.rs @@ -169,7 +169,7 @@ pub mod pallet { use frame_system::pallet_prelude::*; /// The current storage version. - const STORAGE_VERSION: StorageVersion = StorageVersion::new(3); + const STORAGE_VERSION: StorageVersion = StorageVersion::new(4); #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] diff --git a/frame/scheduler/src/tests.rs b/frame/scheduler/src/tests.rs index 7c261fdd74bfd..e5467fc8db55f 100644 --- a/frame/scheduler/src/tests.rs +++ b/frame/scheduler/src/tests.rs @@ -973,7 +973,7 @@ fn migration_to_v4_works() { } assert_eq_uvec!(x, expected); - assert_eq!(Scheduler::current_storage_version(), 3); + assert_eq!(Scheduler::on_chain_storage_version(), 4); }); } From f9d1dcdfa1f0a2edc2b933a0b11ffd499c22c73a Mon Sep 17 00:00:00 2001 From: David Dunn <26876072+doubledup@users.noreply.github.com> Date: Thu, 12 Jan 2023 07:23:57 +0200 Subject: [PATCH 281/715] Optimize merkle proofs for efficient verification in Solidity (#12857) * Sort hashes when generating & verifying MMR proofs * Remove unused variables * Double-hash leaves in beefy-merkle-tree * Revert "Double-hash leaves in beefy-merkle-tree" This reverts commit f788f5ed85e575a866639316aaef29dffbcd1c8c. * Retry Polkadot companion CI jobs --- frame/beefy-mmr/primitives/src/lib.rs | 46 ++++++++++++++------------ frame/beefy-mmr/src/tests.rs | 10 +++--- frame/merkle-mountain-range/src/lib.rs | 3 +- 3 files changed, 31 insertions(+), 28 deletions(-) diff --git a/frame/beefy-mmr/primitives/src/lib.rs b/frame/beefy-mmr/primitives/src/lib.rs index f88fb89acaaab..e6f8acefb039a 100644 --- a/frame/beefy-mmr/primitives/src/lib.rs +++ b/frame/beefy-mmr/primitives/src/lib.rs @@ -27,7 +27,8 @@ //! 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. +//! sorts each pair of hashes before every hash operation. This makes proof verification more +//! efficient by removing the need to track which side each intermediate hash is concatenated on. //! //! If the number of leaves is not even, last leaf (hash of) is promoted to the upper layer. @@ -45,7 +46,7 @@ use beefy_primitives::mmr::{BeefyAuthoritySet, BeefyNextAuthoritySet}; pub fn merkle_root(leaves: I) -> H::Output where H: HashT, - H::Output: Default + AsRef<[u8]>, + H::Output: Default + AsRef<[u8]> + PartialOrd, I: IntoIterator, I::Item: AsRef<[u8]>, { @@ -56,7 +57,7 @@ where fn merkelize(leaves: I, visitor: &mut V) -> H::Output where H: HashT, - H::Output: Default + AsRef<[u8]>, + H::Output: Default + AsRef<[u8]> + PartialOrd, V: Visitor, I: Iterator, { @@ -141,7 +142,7 @@ impl Visitor for () { pub fn merkle_proof(leaves: I, leaf_index: usize) -> MerkleProof where H: HashT, - H::Output: Default + Copy + AsRef<[u8]>, + H::Output: Default + Copy + AsRef<[u8]> + PartialOrd, I: IntoIterator, I::IntoIter: ExactSizeIterator, T: AsRef<[u8]>, @@ -241,7 +242,7 @@ pub fn verify_proof<'a, H, P, L>( ) -> bool where H: HashT, - H::Output: PartialEq + AsRef<[u8]>, + H::Output: PartialEq + AsRef<[u8]> + PartialOrd, P: IntoIterator, L: Into>, { @@ -256,15 +257,13 @@ where 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[..hash_len].copy_from_slice(&b.as_ref()); - combined[hash_len..].copy_from_slice(&a.as_ref()); - } else { + if a < b { combined[..hash_len].copy_from_slice(&a.as_ref()); combined[hash_len..].copy_from_slice(&b.as_ref()); + } else { + combined[..hash_len].copy_from_slice(&b.as_ref()); + combined[hash_len..].copy_from_slice(&a.as_ref()); } let hash = ::hash(&combined); #[cfg(feature = "debug")] @@ -275,8 +274,6 @@ where array_bytes::bytes2hex("", &hash.as_ref()), array_bytes::bytes2hex("", &combined.as_ref()) ); - position /= 2; - width = ((width - 1) / 2) + 1; hash }); @@ -295,7 +292,7 @@ fn merkelize_row( ) -> Result> where H: HashT, - H::Output: AsRef<[u8]>, + H::Output: AsRef<[u8]> + PartialOrd, V: Visitor, I: Iterator, { @@ -321,8 +318,13 @@ where index += 2; match (a, b) { (Some(a), Some(b)) => { - combined[..hash_len].copy_from_slice(a.as_ref()); - combined[hash_len..].copy_from_slice(b.as_ref()); + if a < b { + combined[..hash_len].copy_from_slice(a.as_ref()); + combined[hash_len..].copy_from_slice(b.as_ref()); + } else { + combined[..hash_len].copy_from_slice(b.as_ref()); + combined[hash_len..].copy_from_slice(a.as_ref()); + } next.push(::hash(&combined)); }, @@ -428,12 +430,12 @@ mod tests { }; test( - "aff1208e69c9e8be9b584b07ebac4e48a1ee9d15ce3afe20b77a4d29e4175aa3", + "5842148bc6ebeb52af882a317c765fccd3ae80589b21a9b8cbf21abb630e46a7", vec!["a", "b", "c"], ); test( - "b8912f7269068901f231a965adfefbc10f0eedcfa61852b103efd54dac7db3d7", + "7b84bec68b13c39798c6c50e9e40a0b268e3c1634db8f4cb97314eb243d4c514", vec!["a", "b", "a"], ); @@ -443,7 +445,7 @@ mod tests { ); test( - "fb3b3be94be9e983ba5e094c9c51a7d96a4fa2e5d8e891df00ca89ba05bb1239", + "cc50382cfd3c9a617741e9a85efee8752b8feb95a2cbecd6365fb21366ce0c8c", vec!["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"], ); } @@ -761,7 +763,7 @@ mod tests { "0xc26B34D375533fFc4c5276282Fa5D660F3d8cbcB", ]; let root: H256 = array_bytes::hex2array_unchecked( - "72b0acd7c302a84f1f6b6cefe0ba7194b7398afb440e1b44a9dbbe270394ca53", + "7b2c6eebec6e85b2e272325a11c31af71df52bc0534d2d4f903e0ced191f022e", ) .into(); @@ -806,11 +808,11 @@ mod tests { ) .into(), array_bytes::hex2array_unchecked( - "d02609d2bbdb28aa25f58b85afec937d5a4c85d37925bce6d0cf802f9d76ba79" + "1fad92ed8d0504ef6c0231bbbeeda960a40693f297c64e87b582beb92ecfb00f" ) .into(), array_bytes::hex2array_unchecked( - "ae3f8991955ed884613b0a5f40295902eea0e0abe5858fc520b72959bc016d4e" + "0b84c852cbcf839d562d826fd935e1b37975ccaa419e1def8d219df4b83dcbf4" ) .into(), ], diff --git a/frame/beefy-mmr/src/tests.rs b/frame/beefy-mmr/src/tests.rs index 1826331f59e53..0f7804e544aa4 100644 --- a/frame/beefy-mmr/src/tests.rs +++ b/frame/beefy-mmr/src/tests.rs @@ -70,7 +70,7 @@ fn should_contain_mmr_digest() { ValidatorSet::new(vec![mock_beefy_id(1), mock_beefy_id(2)], 1).unwrap() )), beefy_log(ConsensusLog::MmrRoot(array_bytes::hex_n_into_unchecked( - "95803defe6ea9f41e7ec6afa497064f21bfded027d8812efacbdf984e630cbdc" + "200e73880940ac0b66735ffb560fa0a3989292463d262deac6ad61e78a3e46a4" ))) ] ); @@ -85,13 +85,13 @@ fn should_contain_mmr_digest() { ValidatorSet::new(vec![mock_beefy_id(1), mock_beefy_id(2)], 1).unwrap() )), beefy_log(ConsensusLog::MmrRoot(array_bytes::hex_n_into_unchecked( - "95803defe6ea9f41e7ec6afa497064f21bfded027d8812efacbdf984e630cbdc" + "200e73880940ac0b66735ffb560fa0a3989292463d262deac6ad61e78a3e46a4" ))), beefy_log(ConsensusLog::AuthoritiesChange( ValidatorSet::new(vec![mock_beefy_id(3), mock_beefy_id(4)], 2).unwrap() )), beefy_log(ConsensusLog::MmrRoot(array_bytes::hex_n_into_unchecked( - "a73271a0974f1e67d6e9b8dd58e506177a2e556519a330796721e98279a753e2" + "ba37d8d5d195ac8caec391da35472f9ecf1116ff1642409148b62e08896d3884" ))), ] ); @@ -124,7 +124,7 @@ fn should_contain_valid_leaf_data() { ) }, leaf_extra: array_bytes::hex2bytes_unchecked( - "55b8e9e1cc9f0db7776fac0ca66318ef8acfb8ec26db11e373120583e07ee648" + "5572d58c82bddf323f4fc7aecab8a8f0ad6ed2f06ab2bfb8ade36a77a45fcc68" ) } ); @@ -149,7 +149,7 @@ fn should_contain_valid_leaf_data() { ) }, leaf_extra: array_bytes::hex2bytes_unchecked( - "55b8e9e1cc9f0db7776fac0ca66318ef8acfb8ec26db11e373120583e07ee648" + "5572d58c82bddf323f4fc7aecab8a8f0ad6ed2f06ab2bfb8ade36a77a45fcc68" ) } ); diff --git a/frame/merkle-mountain-range/src/lib.rs b/frame/merkle-mountain-range/src/lib.rs index 46af84d218247..170c1d724f3a2 100644 --- a/frame/merkle-mountain-range/src/lib.rs +++ b/frame/merkle-mountain-range/src/lib.rs @@ -164,7 +164,8 @@ pub mod pallet { + codec::Codec + codec::EncodeLike + scale_info::TypeInfo - + MaxEncodedLen; + + MaxEncodedLen + + PartialOrd; /// Data stored in the leaf nodes. /// From e9b0facf70eeb08032cc7e83548c62f0b4a24bb1 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Thu, 12 Jan 2023 15:49:01 +0200 Subject: [PATCH 282/715] client/beefy: fix logs (#13130) Minor change to logs but required to minimize spamming during initial BEEFY deployment. --- client/beefy/src/worker.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/beefy/src/worker.rs b/client/beefy/src/worker.rs index b48dfa369eb2d..8ec1403bb32d9 100644 --- a/client/beefy/src/worker.rs +++ b/client/beefy/src/worker.rs @@ -498,7 +498,7 @@ where warn!(target: "beefy", "🥩 Buffer vote dropped for round: {:?}", block_num) } } else { - error!(target: "beefy", "🥩 Buffer justification dropped for round: {:?}.", block_num); + warn!(target: "beefy", "🥩 Buffer vote dropped for round: {:?}.", block_num); } }, RoundAction::Drop => (), @@ -528,7 +528,7 @@ where 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); + warn!(target: "beefy", "🥩 Buffer justification dropped for round: {:?}.", block_num); } }, RoundAction::Drop => (), From 2bfc1dd66ef32cf8beb90007dfb544a9d28f1b2f Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Thu, 12 Jan 2023 20:36:31 +0100 Subject: [PATCH 283/715] Stop keeping track of epoch changes for the sync gap (#13127) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Stop keeping track of epoch changes data within the sync gap * Fix docs * Apply suggestions from code review Co-authored-by: Bastian Köcher * Fix typo Co-authored-by: Bastian Köcher --- client/consensus/babe/src/lib.rs | 51 +-- client/consensus/epochs/src/lib.rs | 432 +---------------------- client/consensus/epochs/src/migration.rs | 4 +- 3 files changed, 33 insertions(+), 454 deletions(-) diff --git a/client/consensus/babe/src/lib.rs b/client/consensus/babe/src/lib.rs index 41c00169e5412..c9e171dbed887 100644 --- a/client/consensus/babe/src/lib.rs +++ b/client/consensus/babe/src/lib.rs @@ -111,7 +111,7 @@ 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, ForkBackend, HeaderBackend, HeaderMetadata, + Backend as _, BlockStatus, Error as ClientError, ForkBackend, HeaderBackend, HeaderMetadata, Result as ClientResult, }; use sp_consensus::{ @@ -1133,11 +1133,17 @@ where let hash = block.header.hash(); let parent_hash = *block.header.parent_hash(); - if block.with_state() { - // When importing whole state we don't calculate epoch descriptor, but rather - // read it from the state after import. We also skip all verifications - // because there's no parent state and we trust the sync module to verify - // that the state is correct and finalized. + let info = self.client.info(); + let number = *block.header.number(); + + if info.block_gap.map_or(false, |(s, e)| s <= number && number <= e) || block.with_state() { + // Verification for imported blocks is skipped in two cases: + // 1. When importing blocks below the last finalized block during network initial + // synchronization. + // 2. When importing whole state we don't calculate epoch descriptor, but rather + // read it from the state after import. We also skip all verifications + // because there's no parent state and we trust the sync module to verify + // that the state is correct and finalized. return Ok((block, Default::default())) } @@ -1399,18 +1405,24 @@ where ) -> Result { let hash = block.post_hash(); let number = *block.header.number(); + let info = self.client.info(); - // early exit if block already in chain, otherwise the check for - // epoch changes will error when trying to re-import an epoch change - match self.client.status(hash) { - Ok(sp_blockchain::BlockStatus::InChain) => { - // When re-importing existing block strip away intermediates. - 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) - }, - Ok(sp_blockchain::BlockStatus::Unknown) => {}, - Err(e) => return Err(ConsensusError::ClientImport(e.to_string())), + let block_status = self + .client + .status(hash) + .map_err(|e| ConsensusError::ClientImport(e.to_string()))?; + + // Skip babe logic if block already in chain or importing blocks during initial sync, + // otherwise the check for epoch changes will error because trying to re-import an + // epoch change or because of missing epoch data in the tree, respectivelly. + if info.block_gap.map_or(false, |(s, e)| s <= number && number <= e) || + block_status == BlockStatus::InChain + { + // When re-importing existing block strip away intermediates. + // In case of initial sync intermediates should not be present... + 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) } if block.with_state() { @@ -1506,8 +1518,6 @@ where )), } - let info = self.client.info(); - if let Some(next_epoch_descriptor) = next_epoch_digest { old_epoch_changes = Some((*epoch_changes).clone()); @@ -1701,9 +1711,6 @@ 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 c213a49b8e4e4..7784a99437626 100644 --- a/client/consensus/epochs/src/lib.rs +++ b/client/consensus/epochs/src/lib.rs @@ -320,106 +320,6 @@ 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. @@ -435,14 +335,10 @@ where /// same DAG entry, pinned to a specific block #1. /// /// Further epochs (epoch_2, ..., epoch_n) each get their own entry. -/// -/// 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. @@ -460,7 +356,7 @@ where Number: Ord, { fn default() -> Self { - EpochChanges { inner: ForkTree::new(), epochs: BTreeMap::new(), gap: None } + EpochChanges { inner: ForkTree::new(), epochs: BTreeMap::new() } } } @@ -480,11 +376,6 @@ 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 @@ -493,10 +384,6 @@ where { EpochChanges { 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() @@ -536,9 +423,6 @@ 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 => @@ -665,15 +549,6 @@ 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, - ))) - } - } - // 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 @@ -744,28 +619,9 @@ where ) -> Result<(), fork_tree::Error> { let is_descendent_of = descendent_of_builder.build_is_descendent_of(Some((hash, parent_hash))); - let slot = epoch.as_ref().start_slot(); - let IncrementedEpoch(mut epoch) = epoch; + let IncrementedEpoch(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, number, e) { - Ok(()) => return Ok(()), - Err(e) => PersistedEpoch::Regular(e), - } - } - } 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. - 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 { @@ -1278,288 +1134,4 @@ mod tests { 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() { - // 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); - - 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); - - 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. - let epoch_a = epoch_changes - .epoch_data_for_child_of(&is_descendent_of, b"A", 1, 101, &make_genesis) - .unwrap() - .unwrap(); - - 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] - 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); - - 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()); - } - - /// 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); - - 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); - - 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); - - 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); - } } diff --git a/client/consensus/epochs/src/migration.rs b/client/consensus/epochs/src/migration.rs index c4ed47e9c1c05..052d0b7be4a53 100644 --- a/client/consensus/epochs/src/migration.rs +++ b/client/consensus/epochs/src/migration.rs @@ -64,7 +64,7 @@ where header }); - EpochChanges { inner, epochs, gap: None } + EpochChanges { inner, epochs } } } @@ -75,6 +75,6 @@ where { /// Migrate the type into current epoch changes definition. pub fn migrate(self) -> EpochChanges { - EpochChanges { inner: self.inner, epochs: self.epochs, gap: None } + EpochChanges { inner: self.inner, epochs: self.epochs } } } From d92281a5634baf55a3dab058b904a3932b4ed340 Mon Sep 17 00:00:00 2001 From: Vladimir Istyufeev Date: Fri, 13 Jan 2023 14:32:29 +0400 Subject: [PATCH 284/715] CI: Unpin `ci-linux` and use Rust 1.66.1 (#13134) --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 90298297a89c6..ecc27d016a811 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -48,7 +48,7 @@ variables: CARGO_INCREMENTAL: 0 DOCKER_OS: "debian:stretch" ARCH: "x86_64" - CI_IMAGE: "paritytech/ci-linux@sha256:9140bc3c843a8b12a3bcf6f5886346536092795bbadfd7f1836362cb28dfcc71" + 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" From 88be4b64df842daf2dd5473a45eb9f8b85f466c4 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Fri, 13 Jan 2023 14:52:18 +0200 Subject: [PATCH 285/715] sp-beefy: align authority id key type with its signature type (#13131) Still allows custom message hasher, but ties together the crypto types used for private+public keys and the signature. Signed-off-by: acatangiu --- client/beefy/src/keystore.rs | 4 +-- primitives/beefy/src/lib.rs | 52 +++++++++++++++++------------------- 2 files changed, 27 insertions(+), 29 deletions(-) diff --git a/client/beefy/src/keystore.rs b/client/beefy/src/keystore.rs index 886c00fc5d817..8d77410746e52 100644 --- a/client/beefy/src/keystore.rs +++ b/client/beefy/src/keystore.rs @@ -25,7 +25,7 @@ use log::warn; use beefy_primitives::{ crypto::{Public, Signature}, - BeefyVerify, KEY_TYPE, + BeefyAuthorityId, KEY_TYPE, }; use crate::error; @@ -99,7 +99,7 @@ impl BeefyKeystore { /// /// Return `true` if the signature is authentic, `false` otherwise. pub fn verify(public: &Public, sig: &Signature, message: &[u8]) -> bool { - BeefyVerify::::verify(sig, message, public) + BeefyAuthorityId::::verify(public, sig, message) } } diff --git a/primitives/beefy/src/lib.rs b/primitives/beefy/src/lib.rs index d7ac091491bff..eb7b8db89b214 100644 --- a/primitives/beefy/src/lib.rs +++ b/primitives/beefy/src/lib.rs @@ -49,20 +49,14 @@ 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. +/// Trait representing BEEFY authority id, including custom signature verification. /// /// Accepts custom hashing fn for the message and custom convertor fn for the signer. -pub trait BeefyVerify { - /// Type of the signer. - type Signer: BeefyAuthorityId; - +pub trait BeefyAuthorityId: RuntimeAppPublic { /// Verify a signature. /// - /// Return `true` if signature is valid for the value. - fn verify(&self, msg: &[u8], signer: &Self::Signer) -> bool; + /// Return `true` if signature over `msg` is valid for this id. + fn verify(&self, signature: &::Signature, msg: &[u8]) -> bool; } /// BEEFY cryptographic types @@ -78,7 +72,7 @@ pub trait BeefyVerify { /// 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 super::{BeefyAuthorityId, Hash, RuntimeAppPublic}; use sp_application_crypto::{app_crypto, ecdsa}; use sp_core::crypto::Wraps; app_crypto!(ecdsa, crate::KEY_TYPE); @@ -89,21 +83,17 @@ 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 + impl BeefyAuthorityId for AuthorityId where ::Output: Into<[u8; 32]>, { - type Signer = AuthorityId; - - fn verify(&self, msg: &[u8], signer: &Self::Signer) -> bool { + fn verify(&self, signature: &::Signature, msg: &[u8]) -> bool { let msg_hash = ::hash(msg).into(); match sp_io::crypto::secp256k1_ecdsa_recover_compressed( - self.as_inner_ref().as_ref(), + signature.as_inner_ref().as_ref(), &msg_hash, ) { - Ok(raw_pubkey) => raw_pubkey.as_ref() == AsRef::<[u8]>::as_ref(signer), + Ok(raw_pubkey) => raw_pubkey.as_ref() == AsRef::<[u8]>::as_ref(self), _ => false, } } @@ -248,23 +238,31 @@ mod tests { 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())); + assert!(BeefyAuthorityId::::verify(&pair.public(), &keccak_256_signature, msg)); + assert!(BeefyAuthorityId::::verify( + &pair.public(), + &blake2_256_signature, + msg + )); // 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())); + assert!(!BeefyAuthorityId::::verify(&pair.public(), &blake2_256_signature, msg)); + assert!(!BeefyAuthorityId::::verify( + &pair.public(), + &keccak_256_signature, + msg + )); // Other public key doesn't work let (other_pair, _) = crypto::Pair::generate(); - assert!(!BeefyVerify::::verify( + assert!(!BeefyAuthorityId::::verify( + &other_pair.public(), &keccak_256_signature, msg, - &other_pair.public() )); - assert!(!BeefyVerify::::verify( + assert!(!BeefyAuthorityId::::verify( + &other_pair.public(), &blake2_256_signature, msg, - &other_pair.public() )); } } From cbc525f271146ba9c684736bfc5c26f77e849dae Mon Sep 17 00:00:00 2001 From: Squirrel Date: Fri, 13 Jan 2023 13:47:18 +0000 Subject: [PATCH 286/715] Use the balance trait as we have one (#13136) --- .../asset-tx-payment/src/payment.rs | 14 +++----------- frame/transaction-payment/src/payment.rs | 17 ++++------------- 2 files changed, 7 insertions(+), 24 deletions(-) diff --git a/frame/transaction-payment/asset-tx-payment/src/payment.rs b/frame/transaction-payment/asset-tx-payment/src/payment.rs index 80ff4e40dcffa..85d1bec4b275c 100644 --- a/frame/transaction-payment/asset-tx-payment/src/payment.rs +++ b/frame/transaction-payment/asset-tx-payment/src/payment.rs @@ -21,15 +21,13 @@ use codec::FullCodec; use frame_support::{ traits::{ fungibles::{Balanced, CreditOf, Inspect}, - tokens::BalanceConversion, + tokens::{Balance, BalanceConversion}, }, unsigned::TransactionValidityError, }; use scale_info::TypeInfo; use sp_runtime::{ - traits::{ - AtLeast32BitUnsigned, DispatchInfoOf, MaybeSerializeDeserialize, One, PostDispatchInfoOf, - }, + traits::{DispatchInfoOf, MaybeSerializeDeserialize, One, PostDispatchInfoOf}, transaction_validity::InvalidTransaction, }; use sp_std::{fmt::Debug, marker::PhantomData}; @@ -37,13 +35,7 @@ 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; + type Balance: Balance; /// 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. diff --git a/frame/transaction-payment/src/payment.rs b/frame/transaction-payment/src/payment.rs index ebc9c5c5afd62..bc871deafdc8b 100644 --- a/frame/transaction-payment/src/payment.rs +++ b/frame/transaction-payment/src/payment.rs @@ -1,15 +1,11 @@ /// ! Traits and default implementation for paying transaction fees. use crate::Config; -use codec::FullCodec; use sp_runtime::{ - traits::{ - AtLeast32BitUnsigned, DispatchInfoOf, MaybeSerializeDeserialize, PostDispatchInfoOf, - Saturating, Zero, - }, + traits::{DispatchInfoOf, PostDispatchInfoOf, Saturating, Zero}, transaction_validity::InvalidTransaction, }; -use sp_std::{fmt::Debug, marker::PhantomData}; +use sp_std::marker::PhantomData; use frame_support::{ traits::{Currency, ExistenceRequirement, Imbalance, OnUnbalanced, WithdrawReasons}, @@ -22,13 +18,8 @@ type NegativeImbalanceOf = /// Handle withdrawing, refunding and depositing of transaction fees. pub trait OnChargeTransaction { /// The underlying integer type in which fees are calculated. - type Balance: AtLeast32BitUnsigned - + FullCodec - + Copy - + MaybeSerializeDeserialize - + Debug - + Default - + scale_info::TypeInfo; + type Balance: frame_support::traits::tokens::Balance; + type LiquidityInfo: Default; /// Before the transaction is executed the payment of the transaction fees From 30641eed4763cc1ef466a0f447f2a1b2456910eb Mon Sep 17 00:00:00 2001 From: Vladimir Istyufeev Date: Fri, 13 Jan 2023 20:21:44 +0400 Subject: [PATCH 287/715] CI: Code mark to request a pipeline failure (#13139) --- scripts/ci/gitlab/pipeline/test.yml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/scripts/ci/gitlab/pipeline/test.yml b/scripts/ci/gitlab/pipeline/test.yml index a468a7b04caeb..466019e42e3e1 100644 --- a/scripts/ci/gitlab/pipeline/test.yml +++ b/scripts/ci/gitlab/pipeline/test.yml @@ -1,6 +1,27 @@ # This file is part of .gitlab-ci.yml # Here are all jobs that are executed during "test" stage + +# It's more like a check and it belongs to the previous stage, but we want to run this job with real tests in parallel +find-fail-ci-phrase: + stage: test + variables: + CI_IMAGE: "paritytech/tools:latest" + ASSERT_REGEX: "FAIL-CI" + GIT_DEPTH: 1 + extends: + - .kubernetes-env + script: + - set +e + - rg --line-number --hidden --type rust --glob '!{.git,target}' "$ASSERT_REGEX" .; exit_status=$? + - if [ $exit_status -eq 0 ]; then + echo "$ASSERT_REGEX was found, exiting with 1"; + exit 1; + else + echo "No $ASSERT_REGEX was found, exiting with 0"; + exit 0; + fi + cargo-deny: stage: test extends: From 49962f76ad9a1cc45086a80188f3d751ac15eb82 Mon Sep 17 00:00:00 2001 From: Jun Jiang Date: Sun, 15 Jan 2023 21:31:14 +0800 Subject: [PATCH 288/715] Annotate thiserror for sp_core::crypto::SecretStringError (#13144) --- primitives/core/src/crypto.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/primitives/core/src/crypto.rs b/primitives/core/src/crypto.rs index 06703acea7202..52c805bb6119f 100644 --- a/primitives/core/src/crypto.rs +++ b/primitives/core/src/crypto.rs @@ -84,20 +84,27 @@ impl> UncheckedInto for S { } /// An error with the interpretation of a secret. +#[cfg_attr(feature = "std", derive(thiserror::Error))] #[derive(Debug, Clone, PartialEq, Eq)] #[cfg(feature = "full_crypto")] pub enum SecretStringError { /// The overall format was invalid (e.g. the seed phrase contained symbols). + #[cfg_attr(feature = "std", error("Invalid format"))] InvalidFormat, /// The seed phrase provided is not a valid BIP39 phrase. + #[cfg_attr(feature = "std", error("Invalid phrase"))] InvalidPhrase, /// The supplied password was invalid. + #[cfg_attr(feature = "std", error("Invalid password"))] InvalidPassword, /// The seed is invalid (bad content). + #[cfg_attr(feature = "std", error("Invalid seed"))] InvalidSeed, /// The seed has an invalid length. + #[cfg_attr(feature = "std", error("Invalid seed length"))] InvalidSeedLength, /// The derivation path was invalid (e.g. contains soft junctions when they are not supported). + #[cfg_attr(feature = "std", error("Invalid path"))] InvalidPath, } From 70f2e364ab1ad57ce8d3abe228222b299393c5c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Mon, 16 Jan 2023 13:39:13 +0100 Subject: [PATCH 289/715] pallet-offences-benchmarking: Box events in verify (#13151) * pallet-offences-benchmarking: Box events in verify Events in frame are represented by an enum in the pallet and the runtime. The size of an enum in Rust depends on the size of biggest variant. This means we always need to allocate memory for the biggest variant when allocating memory for an event. The offences benchmarking is verifying the benchmarking results by checking the events. To check the events it is generating all the expected events. With the recent changes in Polkadot the events are too big and lead to issues when running this verify functions. The solution is to box each event, as the vector holding all the events will then only need to hold fat pointers * expected events, instead of size_of(event) * expected events. This issue isn't a problem in production, as we never read the events on chain. When we are reading the events, it is done in an offchain context and they are only decoded one by one. Besides that this also enables the benchmarking verification for everyone running these benchmarks. * FMT * Disable checking again --- Cargo.lock | 1 + frame/offences/benchmarking/Cargo.toml | 2 + frame/offences/benchmarking/src/lib.rs | 189 +++++++++++++------------ 3 files changed, 104 insertions(+), 88 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 68c144b3f177e..e4e3e1b84625c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6079,6 +6079,7 @@ dependencies = [ "frame-election-provider-support", "frame-support", "frame-system", + "log", "pallet-babe", "pallet-balances", "pallet-grandpa", diff --git a/frame/offences/benchmarking/Cargo.toml b/frame/offences/benchmarking/Cargo.toml index e20aefd69ad4d..e31e8bbed929f 100644 --- a/frame/offences/benchmarking/Cargo.toml +++ b/frame/offences/benchmarking/Cargo.toml @@ -29,6 +29,7 @@ pallet-staking = { version = "4.0.0-dev", default-features = false, path = "../. 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 = "5.0.0", default-features = false, path = "../../../primitives/std" } +log = { version = "0.4.17", default-features = false } [dev-dependencies] pallet-staking-reward-curve = { version = "4.0.0-dev", path = "../../staking/reward-curve" } @@ -55,6 +56,7 @@ std = [ "sp-runtime/std", "sp-staking/std", "sp-std/std", + "log/std", ] runtime-benchmarks = [ diff --git a/frame/offences/benchmarking/src/lib.rs b/frame/offences/benchmarking/src/lib.rs index e5ec2952f8114..7e586a96bbe3e 100644 --- a/frame/offences/benchmarking/src/lib.rs +++ b/frame/offences/benchmarking/src/lib.rs @@ -28,8 +28,10 @@ use frame_benchmarking::{account, benchmarks}; use frame_support::traits::{Currency, Get, ValidatorSet, ValidatorSetWithIdentification}; use frame_system::{Config as SystemConfig, Pallet as System, RawOrigin}; +#[cfg(test)] +use sp_runtime::traits::UniqueSaturatedInto; use sp_runtime::{ - traits::{Convert, Saturating, StaticLookup, UniqueSaturatedInto}, + traits::{Convert, Saturating, StaticLookup}, Perbill, }; use sp_staking::offence::{Offence, ReportOffence}; @@ -43,9 +45,11 @@ use pallet_session::{ historical::{Config as HistoricalConfig, IdentificationTuple}, Config as SessionConfig, SessionManager, }; +#[cfg(test)] +use pallet_staking::Event as StakingEvent; use pallet_staking::{ - Config as StakingConfig, Event as StakingEvent, Exposure, IndividualExposure, - Pallet as Staking, RewardDestination, ValidatorPrefs, + Config as StakingConfig, Exposure, IndividualExposure, Pallet as Staking, RewardDestination, + ValidatorPrefs, }; const SEED: u32 = 0; @@ -89,7 +93,9 @@ type BalanceOf = struct Offender { pub controller: T::AccountId, + #[allow(dead_code)] pub stash: T::AccountId, + #[allow(dead_code)] pub nominator_stashes: Vec, } @@ -217,55 +223,63 @@ fn make_offenders_im_online( } #[cfg(test)] -fn check_events::RuntimeEvent>>(expected: I) { +fn check_events< + T: Config, + I: Iterator, + Item: sp_std::borrow::Borrow<::RuntimeEvent> + sp_std::fmt::Debug, +>( + expected: I, +) { let events = System::::events() .into_iter() .map(|frame_system::EventRecord { event, .. }| event) .collect::>(); let expected = expected.collect::>(); - fn pretty(header: &str, ev: &[D], offset: usize) { - println!("{}", header); + fn pretty(header: &str, ev: &[D], offset: usize) { + log::info!("{}", header); for (idx, ev) in ev.iter().enumerate() { - println!("\t[{:04}] {:?}", idx + offset, ev); + log::info!("\t[{:04}] {:?}", idx + offset, ev); } } - fn print_events(idx: usize, events: &[D], expected: &[D]) { + fn print_events( + idx: usize, + events: &[D], + expected: &[E], + ) { let window = 10; let start = idx.saturating_sub(window / 2); let end_got = (idx + window / 2).min(events.len()); pretty("Got(window):", &events[start..end_got], start); let end_expected = (idx + window / 2).min(expected.len()); pretty("Expected(window):", &expected[start..end_expected], start); - println!("---------------"); + log::info!("---------------"); let start_got = events.len().saturating_sub(window); pretty("Got(end):", &events[start_got..], start_got); let start_expected = expected.len().saturating_sub(window); pretty("Expected(end):", &expected[start_expected..], start_expected); } - let events_copy = events.clone(); - let expected_copy = expected.clone(); - - for (idx, (a, b)) in events.into_iter().zip(expected).enumerate() { - 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!( + + for (idx, (a, b)) in events.iter().zip(expected.iter()).enumerate() { + if a != sp_std::borrow::Borrow::borrow(b) { + print_events(idx, &events, &expected); + log::info!("Mismatch at: {}", idx); + log::info!(" Got: {:?}", b); + log::info!("Expected: {:?}", a); + if events.len() != expected.len() { + log::info!( "Mismatching lengths. Got: {}, Expected: {}", - events_copy.len(), - expected_copy.len() + events.len(), + expected.len() ) } panic!("Mismatching events."); } } - 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()) + if events.len() != expected.len() { + print_events(0, &events, &expected); + panic!("Mismatching lengths. Got: {}, Expected: {}", events.len(), expected.len(),) } } @@ -304,79 +318,78 @@ benchmarks! { ); } verify { - let bond_amount: u32 = UniqueSaturatedInto::::unique_saturated_into(bond_amount::()); - let slash_amount = slash_fraction * bond_amount; - let reward_amount = slash_amount.saturating_mul(1 + n) / 2; - let reward = reward_amount / r; - let slash_report = |id| core::iter::once( - ::RuntimeEvent::from(StakingEvent::::SlashReported{ validator: id, fraction: slash_fraction, slash_era: 0}) - ); - let slash = |id| core::iter::once( - ::RuntimeEvent::from(StakingEvent::::Slashed{ staker: id, amount: BalanceOf::::from(slash_amount) }) - ); - let balance_slash = |id| core::iter::once( - ::RuntimeEvent::from(pallet_balances::Event::::Slashed{ who: id, amount: slash_amount.into() }) - ); - let chill = |id| core::iter::once( - ::RuntimeEvent::from(StakingEvent::::Chilled{ stash: id }) - ); - let balance_deposit = |id, amount: u32| + #[cfg(test)] + { + let bond_amount: u32 = UniqueSaturatedInto::::unique_saturated_into(bond_amount::()); + let slash_amount = slash_fraction * bond_amount; + let reward_amount = slash_amount.saturating_mul(1 + n) / 2; + let reward = reward_amount / r; + let slash_report = |id| core::iter::once( + ::RuntimeEvent::from(StakingEvent::::SlashReported{ validator: id, fraction: slash_fraction, slash_era: 0}) + ); + let slash = |id| core::iter::once( + ::RuntimeEvent::from(StakingEvent::::Slashed{ staker: id, amount: BalanceOf::::from(slash_amount) }) + ); + let balance_slash = |id| core::iter::once( + ::RuntimeEvent::from(pallet_balances::Event::::Slashed{ who: id, amount: slash_amount.into() }) + ); + let chill = |id| core::iter::once( + ::RuntimeEvent::from(StakingEvent::::Chilled{ stash: id }) + ); + let balance_deposit = |id, amount: u32| ::RuntimeEvent::from(pallet_balances::Event::::Deposit{ who: id, amount: amount.into() }); - let mut first = true; - let slash_events = raw_offenders.into_iter() - .flat_map(|offender| { - let nom_slashes = offender.nominator_stashes.into_iter().flat_map(|nom| { - balance_slash(nom.clone()).map(Into::into) - .chain(slash(nom).map(Into::into)) - }); - - 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) - .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(), - frame_system::Event::::NewAccount { account: reporter.clone() }.into(), - ::RuntimeEvent::from( - pallet_balances::Event::::Endowed{account: reporter, free_balance: reward.into()} - ).into(), - ]) + let mut first = true; + + // We need to box all events to prevent running into too big allocations in wasm. + // The event in FRAME is represented as an enum and the size of the enum depends on the biggest variant. + // So, instead of requiring `size_of() * expected_events` we only need to + // allocate `size_of>() * expected_events`. + let slash_events = raw_offenders.into_iter() + .flat_map(|offender| { + let nom_slashes = offender.nominator_stashes.into_iter().flat_map(|nom| { + balance_slash(nom.clone()).map(Into::into).chain(slash(nom).map(Into::into)).map(Box::new) + }); + + let events = chill(offender.stash.clone()).map(Into::into).map(Box::new) + .chain(slash_report(offender.stash.clone()).map(Into::into).map(Box::new)) + .chain(balance_slash(offender.stash.clone()).map(Into::into).map(Box::new)) + .chain(slash(offender.stash).map(Into::into).map(Box::new)) + .chain(nom_slashes) .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()) - .collect::>(); - events.append(&mut reward_events); - events.into_iter() - } - }) - .collect::>(); - + // the first deposit creates endowed events, see `endowed_reward_events` + if first { + first = false; + let reward_events = reporters.iter() + .flat_map(|reporter| vec![ + Box::new(balance_deposit(reporter.clone(), reward).into()), + Box::new(frame_system::Event::::NewAccount { account: reporter.clone() }.into()), + Box::new(::RuntimeEvent::from( + pallet_balances::Event::::Endowed{ account: reporter.clone(), free_balance: reward.into() } + ).into()), + ]) + .collect::>(); + events.into_iter().chain(reward_events) + } else { + let reward_events = reporters.iter() + .map(|reporter| Box::new(balance_deposit(reporter.clone(), reward).into())) + .collect::>(); + events.into_iter().chain(reward_events) + } + }); - #[cfg(test)] - { // In case of error it's useful to see the inputs - println!("Inputs: r: {}, o: {}, n: {}", r, o, n); + log::info!("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(::RuntimeEvent::from( + check_events::( + sp_std::iter::empty() + .chain(slash_events) + .chain(sp_std::iter::once(Box::new(::RuntimeEvent::from( pallet_offences::Event::Offence{ kind: UnresponsivenessOffence::::ID, timeslot: 0_u32.to_le_bytes().to_vec(), } - ).into())) + ).into()))) ); } } From ea002409d10af3fb7a402b6948303233c6f46549 Mon Sep 17 00:00:00 2001 From: JP <77391175+joao-paulo-parity@users.noreply.github.com> Date: Mon, 16 Jan 2023 11:03:46 -0300 Subject: [PATCH 290/715] More improvements for the crate publishing pipeline (#13153) * more improvements for the crate publishing pipeline * move default definitions to the publish-crates script * add script to check the crate publishing pipeline at the start * fix yaml references * move more variables to .crates-publishing-pipeline * separate .crates-publishing-pipeline from .crates-publishing-variables * clean up redundant and unused code --- .gitlab-ci.yml | 39 ++++++++++++++++---------- scripts/ci/gitlab/pipeline/publish.yml | 28 ++++++++---------- scripts/ci/gitlab/pipeline/test.yml | 7 ++++- 3 files changed, 41 insertions(+), 33 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ecc27d016a811..ae25a2c5953f5 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -229,19 +229,21 @@ variables: # 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" -.crate-publishing-pipeline: - rules: - - if: $CI_COMMIT_REF_NAME != "master" - when: never +.crates-publishing-variables: + variables: + CRATESIO_CRATES_OWNER: parity-crate-owner + REPO: substrate + REPO_OWNER: paritytech -.scheduled-crate-publishing-pipeline: +.crates-publishing-pipeline: + extends: .crates-publishing-variables rules: - - !reference [.crate-publishing-pipeline, rules] - - if: $CI_PIPELINE_SOURCE == "schedule" && $PIPELINE == "automatic-crate-publishing" + - if: $CI_PIPELINE_SOURCE == "schedule" && $CI_COMMIT_REF_NAME == "master" && $PIPELINE == "automatic-crate-publishing" .crates-publishing-template: - stage: test - extends: .docker-env + extends: + - .docker-env + - .crates-publishing-variables # collect artifacts even on failure so that we know how the crates were generated (they'll be # generated to the artifacts folder according to SPUB_TMP further down) artifacts: @@ -251,12 +253,7 @@ variables: 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 + SPUB_TMP: artifacts #### stage: .pre @@ -274,6 +271,18 @@ skip-if-draft: - ./scripts/ci/gitlab/skip_if_draft.sh allow_failure: true +check-crates-publishing-pipeline: + stage: .pre + extends: + - .kubernetes-env + - .crates-publishing-pipeline + script: + - git clone + --depth 1 + --branch "$RELENG_SCRIPTS_BRANCH" + https://github.com/paritytech/releng-scripts.git + - ONLY_CHECK_PIPELINE=true ./releng-scripts/publish-crates + include: # check jobs - scripts/ci/gitlab/pipeline/check.yml diff --git a/scripts/ci/gitlab/pipeline/publish.yml b/scripts/ci/gitlab/pipeline/publish.yml index d1a7514d1707b..4eafb0a055399 100644 --- a/scripts/ci/gitlab/pipeline/publish.yml +++ b/scripts/ci/gitlab/pipeline/publish.yml @@ -184,19 +184,19 @@ publish-draft-release: .publish-crates-template: stage: publish - extends: .crates-publishing-template + extends: + - .crates-publishing-template + - .crates-publishing-pipeline # We don't want multiple jobs racing to publish crates as it's redundant and they might overwrite # the releases of one another. Use resource_group to ensure that at most one instance of this job # is running at any given time. resource_group: crates-publishing - 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. + # crates.io currently rate limits crate publishing at 1 per minute: + # https://github.com/paritytech/release-engineering/issues/123#issuecomment-1335509748 + # Taking into account the 202 (as of Dec 07, 2022) publishable Substrate crates, in the worst + # case, due to the rate limits alone, we'd have to wait through at least 202 minutes of delay. + # Taking into account also the verification steps and extra synchronization delays after + # publishing the crate, the job needs to have a much higher timeout than average. timeout: 9h # A custom publishing environment is used for us to be able to set up protected secrets # specifically for it @@ -211,15 +211,9 @@ publish-draft-release: - rusty-cachier cache upload publish-crates: - extends: - - .publish-crates-template - - .scheduled-crate-publishing-pipeline - needs: - - job: publish-crates-locally - artifacts: false + extends: .publish-crates-template publish-crates-manual: extends: .publish-crates-template - rules: !reference [.crate-publishing-pipeline, rules] when: manual - allow_failure: true + interruptible: false diff --git a/scripts/ci/gitlab/pipeline/test.yml b/scripts/ci/gitlab/pipeline/test.yml index 466019e42e3e1..f00857ffa9935 100644 --- a/scripts/ci/gitlab/pipeline/test.yml +++ b/scripts/ci/gitlab/pipeline/test.yml @@ -14,7 +14,7 @@ find-fail-ci-phrase: script: - set +e - rg --line-number --hidden --type rust --glob '!{.git,target}' "$ASSERT_REGEX" .; exit_status=$? - - if [ $exit_status -eq 0 ]; then + - if [ $exit_status -eq 0 ]; then echo "$ASSERT_REGEX was found, exiting with 1"; exit 1; else @@ -417,9 +417,14 @@ cargo-check-each-crate: parallel: 2 publish-crates-locally: + stage: test extends: - .test-refs - .crates-publishing-template + # When lots of crates are taken into account (for example on master where all crates are tested) + # the job might take a long time, as evidenced by: + # https://gitlab.parity.io/parity/mirrors/substrate/-/jobs/2269364 + timeout: 4h script: - rusty-cachier snapshot create - git clone From 7ff6fa2bfa47f288216fdc6e1585f69756c5ec75 Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Mon, 16 Jan 2023 23:15:22 +0100 Subject: [PATCH 291/715] txpool: don't maintain the pool during major sync (#13004) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * txpool: don't maintain the pool during major sync Fix shall prevent from wasting the CPU during the major sync. No actions are actually required in transaction pool during the major sync. Fixes: #12903 * passing sync_oracle to maintain method * fixed: builder, txpool tests * do not maintain tx-pool if node gone out of sync * EnactmentAction: all logic moved to EnactmentState Tests to be done. * maintain guard logic moved directly to MaintainedTransactionPool * minor fixes * EnactmentAction: all logic moved to EnactmentState (again) * SyncOracle fixes here and there * Update client/transaction-pool/src/enactment_state.rs Co-authored-by: Bastian Köcher * Update client/transaction-pool/src/enactment_state.rs Co-authored-by: Bastian Köcher * sync_oracle removed * spelling + fmt + doc * Review suggestions applied * log::info -> debug * Update client/transaction-pool/src/enactment_state.rs Co-authored-by: Bastian Köcher * ".git/.scripts/commands/fmt/fmt.sh" Co-authored-by: parity-processbot <> Co-authored-by: Bastian Köcher --- Cargo.lock | 1 + client/transaction-pool/Cargo.toml | 1 + .../transaction-pool/src/enactment_state.rs | 185 +++++++++++++----- client/transaction-pool/src/lib.rs | 14 +- 4 files changed, 145 insertions(+), 56 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e4e3e1b84625c..446638277202a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9046,6 +9046,7 @@ dependencies = [ "futures-timer", "linked-hash-map", "log", + "num-traits", "parity-scale-codec", "parking_lot 0.12.1", "sc-block-builder", diff --git a/client/transaction-pool/Cargo.toml b/client/transaction-pool/Cargo.toml index 7a3ab042d5a13..4b69b6d0f2fe0 100644 --- a/client/transaction-pool/Cargo.toml +++ b/client/transaction-pool/Cargo.toml @@ -19,6 +19,7 @@ futures = "0.3.21" futures-timer = "3.0.2" linked-hash-map = "0.5.4" log = "0.4.17" +num-traits = "0.2.8" parking_lot = "0.12.1" serde = { version = "1.0.136", features = ["derive"] } thiserror = "1.0.30" diff --git a/client/transaction-pool/src/enactment_state.rs b/client/transaction-pool/src/enactment_state.rs index 6aac98641cf85..382b2683156b6 100644 --- a/client/transaction-pool/src/enactment_state.rs +++ b/client/transaction-pool/src/enactment_state.rs @@ -18,13 +18,21 @@ //! Substrate transaction pool implementation. +use num_traits::CheckedSub; use sc_transaction_pool_api::ChainEvent; use sp_blockchain::TreeRoute; -use sp_runtime::traits::Block as BlockT; +use sp_runtime::traits::{Block as BlockT, NumberFor}; + +/// The threshold since the last update where we will skip any maintenance for blocks. +/// +/// This includes tracking re-orgs and sending out certain notifications. In general this shouldn't +/// happen and may only happen when the node is doing a full sync. +const SKIP_MAINTENANCE_THRESHOLD: u16 = 20; /// 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. +/// is to figure out which phases (enactment / finalization) of transaction pool +/// maintenance are needed. /// /// Given the following chain: /// @@ -54,6 +62,17 @@ where recent_finalized_block: Block::Hash, } +/// Enactment action that should be performed after processing the `ChainEvent` +#[derive(Debug)] +pub enum EnactmentAction { + /// Both phases of maintenance shall be skipped + Skip, + /// Both phases of maintenance shall be performed + HandleEnactment(TreeRoute), + /// Enactment phase of maintenance shall be skipped + HandleFinalization, +} + impl EnactmentState where Block: BlockT, @@ -71,23 +90,38 @@ where /// 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( + pub fn update( &mut self, event: &ChainEvent, - tree_route: &F, - ) -> Result>, String> + tree_route: &TreeRouteF, + hash_to_number: &BlockNumberF, + ) -> Result, String> where - F: Fn(Block::Hash, Block::Hash) -> Result, String>, + TreeRouteF: Fn(Block::Hash, Block::Hash) -> Result, String>, + BlockNumberF: Fn(Block::Hash) -> Result>, String>, { - let (new_hash, finalized) = match event { - ChainEvent::NewBestBlock { hash, .. } => (*hash, false), - ChainEvent::Finalized { hash, .. } => (*hash, true), + let (new_hash, current_hash, finalized) = match event { + ChainEvent::NewBestBlock { hash, .. } => (*hash, self.recent_best_block, false), + ChainEvent::Finalized { hash, .. } => (*hash, self.recent_finalized_block, true), }; + // do not proceed with txpool maintain if block distance is to high + let skip_maintenance = match (hash_to_number(new_hash), hash_to_number(current_hash)) { + (Ok(Some(new)), Ok(Some(current))) => + new.checked_sub(¤t) > Some(SKIP_MAINTENANCE_THRESHOLD.into()), + _ => true, + }; + + if skip_maintenance { + log::debug!(target: "txpool", "skip maintain: tree_route would be too long"); + self.force_update(event); + return Ok(EnactmentAction::Skip) + } + // block was already finalized if self.recent_finalized_block == new_hash { log::debug!(target: "txpool", "handle_enactment: block already finalized"); - return Ok(None) + return Ok(EnactmentAction::Skip) } // compute actual tree route from best_block to notified block, and use @@ -109,7 +143,7 @@ where "Recently finalized block {} would be retracted by ChainEvent {}, skipping", self.recent_finalized_block, new_hash ); - return Ok(None) + return Ok(EnactmentAction::Skip) } if finalized { @@ -124,7 +158,7 @@ where target: "txpool", "handle_enactment: no newly enacted blocks since recent best block" ); - return Ok(None) + return Ok(EnactmentAction::HandleFinalization) } // otherwise enacted finalized block becomes best block... @@ -132,7 +166,7 @@ where self.recent_best_block = new_hash; - Ok(Some(tree_route)) + Ok(EnactmentAction::HandleEnactment(tree_route)) } /// Forces update of the state according to the given `ChainEvent`. Intended to be used as a @@ -148,9 +182,10 @@ where #[cfg(test)] mod enactment_state_tests { - use super::EnactmentState; + use super::{EnactmentAction, EnactmentState}; use sc_transaction_pool_api::ChainEvent; use sp_blockchain::{HashAndNumber, TreeRoute}; + use sp_runtime::traits::NumberFor; use std::sync::Arc; use substrate_test_runtime_client::runtime::{Block, Hash}; @@ -170,6 +205,9 @@ mod enactment_state_tests { fn e1() -> HashAndNumber { HashAndNumber { number: 5, hash: Hash::from([0xE1; 32]) } } + fn x1() -> HashAndNumber { + HashAndNumber { number: 22, hash: Hash::from([0x1E; 32]) } + } fn b2() -> HashAndNumber { HashAndNumber { number: 2, hash: Hash::from([0xB2; 32]) } } @@ -182,11 +220,22 @@ mod enactment_state_tests { fn e2() -> HashAndNumber { HashAndNumber { number: 5, hash: Hash::from([0xE2; 32]) } } + fn x2() -> HashAndNumber { + HashAndNumber { number: 22, hash: Hash::from([0x2E; 32]) } + } + + fn test_chain() -> Vec> { + vec![x1(), e1(), d1(), c1(), b1(), a(), b2(), c2(), d2(), e2(), x2()] + } + + fn block_hash_to_block_number(hash: Hash) -> Result>, String> { + Ok(test_chain().iter().find(|x| x.hash == hash).map(|x| x.number)) + } /// 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 chain = test_chain(); + let pivot = chain.iter().position(|x| x.number == a().number).unwrap(); let from = chain .iter() @@ -197,13 +246,13 @@ mod enactment_state_tests { .position(|bn| bn.hash == to) .ok_or("existing block should be given")?; - // B1-C1-D1-E1 + // B1-C1-D1-E1-..-X1 // / // A // \ - // B2-C2-D2-E2 + // B2-C2-D2-E2-..-X2 // - // [E1 D1 C1 B1 A B2 C2 D2 E2] + // [X1 E1 D1 C1 B1 A B2 C2 D2 E2 X2] let vec: Vec> = if from < to { chain.into_iter().skip(from).take(to - from + 1).collect() @@ -373,13 +422,20 @@ mod enactment_state_tests { let expected = TreeRoute::new(vec![a()], 0); assert_treeroute_eq(result, expected); } + + #[test] + fn tree_route_mock_test_17() { + let result = tree_route(x2().hash, b1().hash); + let expected = TreeRoute::new(vec![x2(), e2(), d2(), c2(), b2(), a(), b1()], 5); + assert_treeroute_eq(result, expected); + } } fn trigger_new_best_block( state: &mut EnactmentState, from: HashAndNumber, acted_on: HashAndNumber, - ) -> bool { + ) -> EnactmentAction { let (from, acted_on) = (from.hash, acted_on.hash); let event_tree_route = tree_route(from, acted_on).expect("Tree route exists"); @@ -391,16 +447,16 @@ mod enactment_state_tests { tree_route: Some(Arc::new(event_tree_route)), }, &tree_route, + &block_hash_to_block_number, ) .unwrap() - .is_some() } fn trigger_finalized( state: &mut EnactmentState, from: HashAndNumber, acted_on: HashAndNumber, - ) -> bool { + ) -> EnactmentAction { let (from, acted_on) = (from.hash, acted_on.hash); let v = tree_route(from, acted_on) @@ -411,9 +467,12 @@ mod enactment_state_tests { .collect::>(); state - .update(&ChainEvent::Finalized { hash: acted_on, tree_route: v.into() }, &tree_route) + .update( + &ChainEvent::Finalized { hash: acted_on, tree_route: v.into() }, + &tree_route, + &block_hash_to_block_number, + ) .unwrap() - .is_some() } fn assert_es_eq( @@ -437,51 +496,51 @@ mod enactment_state_tests { // B2-C2-D2-E2 let result = trigger_new_best_block(&mut es, a(), d1()); - assert!(result); + assert!(matches!(result, EnactmentAction::HandleEnactment { .. })); assert_es_eq(&es, d1(), a()); let result = trigger_new_best_block(&mut es, d1(), e1()); - assert!(result); + assert!(matches!(result, EnactmentAction::HandleEnactment { .. })); assert_es_eq(&es, e1(), a()); let result = trigger_finalized(&mut es, a(), d2()); - assert!(result); + assert!(matches!(result, EnactmentAction::HandleEnactment { .. })); assert_es_eq(&es, d2(), d2()); let result = trigger_new_best_block(&mut es, d2(), e1()); - assert_eq!(result, false); + assert!(matches!(result, EnactmentAction::Skip)); assert_es_eq(&es, d2(), d2()); let result = trigger_finalized(&mut es, a(), b2()); - assert_eq!(result, false); + assert!(matches!(result, EnactmentAction::Skip)); assert_es_eq(&es, d2(), d2()); let result = trigger_finalized(&mut es, a(), b1()); - assert_eq!(result, false); + assert!(matches!(result, EnactmentAction::Skip)); assert_es_eq(&es, d2(), d2()); let result = trigger_new_best_block(&mut es, a(), d2()); - assert_eq!(result, false); + assert!(matches!(result, EnactmentAction::Skip)); assert_es_eq(&es, d2(), d2()); let result = trigger_finalized(&mut es, a(), d2()); - assert_eq!(result, false); + assert!(matches!(result, EnactmentAction::Skip)); assert_es_eq(&es, d2(), d2()); let result = trigger_new_best_block(&mut es, a(), c2()); - assert_eq!(result, false); + assert!(matches!(result, EnactmentAction::Skip)); assert_es_eq(&es, d2(), d2()); let result = trigger_new_best_block(&mut es, a(), c1()); - assert_eq!(result, false); + assert!(matches!(result, EnactmentAction::Skip)); assert_es_eq(&es, d2(), d2()); let result = trigger_new_best_block(&mut es, d2(), e2()); - assert!(result); + assert!(matches!(result, EnactmentAction::HandleEnactment { .. })); assert_es_eq(&es, e2(), d2()); let result = trigger_finalized(&mut es, d2(), e2()); - assert_eq!(result, false); + assert!(matches!(result, EnactmentAction::HandleFinalization)); assert_es_eq(&es, e2(), e2()); } @@ -493,27 +552,27 @@ mod enactment_state_tests { // A-B1-C1-D1-E1 let result = trigger_new_best_block(&mut es, a(), b1()); - assert!(result); + assert!(matches!(result, EnactmentAction::HandleEnactment { .. })); assert_es_eq(&es, b1(), a()); let result = trigger_new_best_block(&mut es, b1(), c1()); - assert!(result); + assert!(matches!(result, EnactmentAction::HandleEnactment { .. })); assert_es_eq(&es, c1(), a()); let result = trigger_new_best_block(&mut es, c1(), d1()); - assert!(result); + assert!(matches!(result, EnactmentAction::HandleEnactment { .. })); assert_es_eq(&es, d1(), a()); let result = trigger_new_best_block(&mut es, d1(), e1()); - assert!(result); + assert!(matches!(result, EnactmentAction::HandleEnactment { .. })); assert_es_eq(&es, e1(), a()); let result = trigger_finalized(&mut es, a(), c1()); - assert_eq!(result, false); + assert!(matches!(result, EnactmentAction::HandleFinalization)); assert_es_eq(&es, e1(), c1()); let result = trigger_finalized(&mut es, c1(), e1()); - assert_eq!(result, false); + assert!(matches!(result, EnactmentAction::HandleFinalization)); assert_es_eq(&es, e1(), e1()); } @@ -525,11 +584,11 @@ mod enactment_state_tests { // A-B1-C1-D1-E1 let result = trigger_new_best_block(&mut es, a(), e1()); - assert!(result); + assert!(matches!(result, EnactmentAction::HandleEnactment { .. })); assert_es_eq(&es, e1(), a()); let result = trigger_finalized(&mut es, a(), b1()); - assert_eq!(result, false); + assert!(matches!(result, EnactmentAction::HandleFinalization)); assert_es_eq(&es, e1(), b1()); } @@ -541,11 +600,11 @@ mod enactment_state_tests { // A-B1-C1-D1-E1 let result = trigger_finalized(&mut es, a(), e1()); - assert!(result); + assert!(matches!(result, EnactmentAction::HandleEnactment { .. })); assert_es_eq(&es, e1(), e1()); let result = trigger_finalized(&mut es, e1(), b1()); - assert_eq!(result, false); + assert!(matches!(result, EnactmentAction::Skip)); assert_es_eq(&es, e1(), e1()); } @@ -561,11 +620,11 @@ mod enactment_state_tests { // B2-C2-D2-E2 let result = trigger_finalized(&mut es, a(), e1()); - assert!(result); + assert!(matches!(result, EnactmentAction::HandleEnactment { .. })); assert_es_eq(&es, e1(), e1()); let result = trigger_finalized(&mut es, e1(), e2()); - assert_eq!(result, false); + assert!(matches!(result, EnactmentAction::Skip)); assert_es_eq(&es, e1(), e1()); } @@ -577,19 +636,19 @@ mod enactment_state_tests { // A-B1-C1-D1-E1 let result = trigger_new_best_block(&mut es, a(), b1()); - assert!(result); + assert!(matches!(result, EnactmentAction::HandleEnactment { .. })); assert_es_eq(&es, b1(), a()); let result = trigger_finalized(&mut es, a(), d1()); - assert!(result); + assert!(matches!(result, EnactmentAction::HandleEnactment { .. })); assert_es_eq(&es, d1(), d1()); let result = trigger_new_best_block(&mut es, a(), e1()); - assert!(result); + assert!(matches!(result, EnactmentAction::HandleEnactment { .. })); assert_es_eq(&es, e1(), d1()); let result = trigger_new_best_block(&mut es, a(), c1()); - assert_eq!(result, false); + assert!(matches!(result, EnactmentAction::Skip)); assert_es_eq(&es, e1(), d1()); } @@ -610,4 +669,26 @@ mod enactment_state_tests { es.force_update(&ChainEvent::Finalized { hash: b1().hash, tree_route: Arc::from([]) }); assert_es_eq(&es, a(), b1()); } + + #[test] + fn test_enactment_skip_long_enacted_path() { + sp_tracing::try_init_simple(); + let mut es = EnactmentState::new(a().hash, a().hash); + + // A-B1-C1-..-X1 + let result = trigger_new_best_block(&mut es, a(), x1()); + assert!(matches!(result, EnactmentAction::Skip)); + assert_es_eq(&es, x1(), a()); + } + + #[test] + fn test_enactment_proceed_with_enacted_path_at_threshold() { + sp_tracing::try_init_simple(); + let mut es = EnactmentState::new(b1().hash, b1().hash); + + // A-B1-C1-..-X1 + let result = trigger_new_best_block(&mut es, b1(), x1()); + assert!(matches!(result, EnactmentAction::HandleEnactment { .. })); + assert_es_eq(&es, x1(), b1()); + } } diff --git a/client/transaction-pool/src/lib.rs b/client/transaction-pool/src/lib.rs index f3797b180f14d..1cd9bef77bc69 100644 --- a/client/transaction-pool/src/lib.rs +++ b/client/transaction-pool/src/lib.rs @@ -33,7 +33,7 @@ mod tests; pub use crate::api::FullChainApi; use async_trait::async_trait; -use enactment_state::EnactmentState; +use enactment_state::{EnactmentAction, EnactmentState}; use futures::{ channel::oneshot, future::{self, ready}, @@ -732,16 +732,22 @@ where )), } }; + let block_id_to_number = + |hash| self.api.block_id_to_number(&BlockId::Hash(hash)).map_err(|e| format!("{}", e)); - let result = self.enactment_state.lock().update(&event, &compute_tree_route); + let result = + self.enactment_state + .lock() + .update(&event, &compute_tree_route, &block_id_to_number); match result { Err(msg) => { log::debug!(target: "txpool", "{msg}"); self.enactment_state.lock().force_update(&event); }, - Ok(None) => {}, - Ok(Some(tree_route)) => { + Ok(EnactmentAction::Skip) => return, + Ok(EnactmentAction::HandleFinalization) => {}, + Ok(EnactmentAction::HandleEnactment(tree_route)) => { self.handle_enactment(tree_route).await; }, }; From 28937302694787cd1e6dbd846ff2ba4b1cf82025 Mon Sep 17 00:00:00 2001 From: Anton Date: Tue, 17 Jan 2023 14:28:17 +0400 Subject: [PATCH 292/715] [client/network] Add support for `/wss` addresses (#13152) * join dns with another instance of WS transport Secure Websocket transport needs unresolved addresses, so we join DNS transport with yet another instance of Websocket transport. Closes #12024 * WSS transport itself need to wrap DNS transport in order to resolve addresses before passing them down to TCP transport Refs https://github.com/libp2p/rust-libp2p/issues/3330 * reverse order * simplify code: remove WS from WSS inner DNS transport * remove the 2nd instance of WS transport --- client/network/src/transport.rs | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/client/network/src/transport.rs b/client/network/src/transport.rs index 6c792a0c38042..51a8483e0e4e6 100644 --- a/client/network/src/transport.rs +++ b/client/network/src/transport.rs @@ -54,18 +54,27 @@ pub fn build_transport( ) -> (Boxed<(PeerId, StreamMuxerBox)>, Arc) { // Build the base layer of the transport. let transport = if !memory_only { + // Main transport: DNS(TCP) let tcp_config = tcp::Config::new().nodelay(true); - let desktop_trans = tcp::tokio::Transport::new(tcp_config.clone()); - let desktop_trans = websocket::WsConfig::new(desktop_trans) - .or_transport(tcp::tokio::Transport::new(tcp_config.clone())); - let dns_init = dns::TokioDnsConfig::system(desktop_trans); + let tcp_trans = tcp::tokio::Transport::new(tcp_config.clone()); + let dns_init = dns::TokioDnsConfig::system(tcp_trans); + EitherTransport::Left(if let Ok(dns) = dns_init { - EitherTransport::Left(dns) + // WS + WSS transport + // + // Main transport can't be used for `/wss` addresses because WSS transport needs + // unresolved addresses (BUT WSS transport itself needs an instance of DNS transport to + // resolve and dial addresses). + let tcp_trans = tcp::tokio::Transport::new(tcp_config); + let dns_for_wss = dns::TokioDnsConfig::system(tcp_trans) + .expect("same system_conf & resolver to work"); + EitherTransport::Left(websocket::WsConfig::new(dns_for_wss).or_transport(dns)) } else { - let desktop_trans = tcp::tokio::Transport::new(tcp_config.clone()); - let desktop_trans = websocket::WsConfig::new(desktop_trans) + // In case DNS can't be constructed, fallback to TCP + WS (WSS won't work) + let tcp_trans = tcp::tokio::Transport::new(tcp_config.clone()); + let desktop_trans = websocket::WsConfig::new(tcp_trans) .or_transport(tcp::tokio::Transport::new(tcp_config)); - EitherTransport::Right(desktop_trans.map_err(dns::DnsErr::Transport)) + EitherTransport::Right(desktop_trans) }) } else { EitherTransport::Right(OptionalTransport::some( From 6bac243eec55cb17ac598e2bb689b5303e633b01 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Tue, 17 Jan 2023 11:37:59 -0300 Subject: [PATCH 293/715] NIS should retain funds in reserve (#12928) * Keep funds with receipt holder * Counterpart is optional * Use named reserves * Tests * Benchmarks * Fixes * Update frame/nis/src/lib.rs Co-authored-by: Keith Yeung * Update frame/nis/src/lib.rs Co-authored-by: Keith Yeung * Update frame/nis/src/lib.rs * Update frame/nis/src/lib.rs * Update frame/nis/src/tests.rs * Update frame/nis/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * Update frame/nis/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * Update frame/nis/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * Update frame/nis/src/lib.rs * Update frame/nis/src/lib.rs * Update frame/nis/src/lib.rs * Update frame/nis/src/lib.rs * Formatting Co-authored-by: Keith Yeung Co-authored-by: Oliver Tale-Yazdi --- bin/node/runtime/src/lib.rs | 2 + frame/nis/src/benchmarking.rs | 41 +- frame/nis/src/lib.rs | 312 +++++++++++--- frame/nis/src/mock.rs | 4 +- frame/nis/src/tests.rs | 453 ++++++++++++++------ frame/nis/src/weights.rs | 320 ++++++++------ frame/support/src/traits/tokens/fungible.rs | 5 + 7 files changed, 828 insertions(+), 309 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index a9e93a16f0713..d34c04fcb5d3c 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1499,6 +1499,7 @@ parameter_types! { pub const ThawThrottle: (Perquintill, BlockNumber) = (Perquintill::from_percent(25), 5); pub Target: Perquintill = Perquintill::zero(); pub const NisPalletId: PalletId = PalletId(*b"py/nis "); + pub const NisReserveId: [u8; 8] = *b"py/nis "; } impl pallet_nis::Config for Runtime { @@ -1522,6 +1523,7 @@ impl pallet_nis::Config for Runtime { type IntakePeriod = IntakePeriod; type MaxIntakeWeight = MaxIntakeWeight; type ThawThrottle = ThawThrottle; + type ReserveId = NisReserveId; } parameter_types! { diff --git a/frame/nis/src/benchmarking.rs b/frame/nis/src/benchmarking.rs index 606b1c484b1e8..b45c982bd150a 100644 --- a/frame/nis/src/benchmarking.rs +++ b/frame/nis/src/benchmarking.rs @@ -21,7 +21,7 @@ use super::*; use frame_benchmarking::{account, benchmarks, whitelisted_caller}; -use frame_support::traits::{Currency, EnsureOrigin, Get}; +use frame_support::traits::{nonfungible::Inspect, Currency, EnsureOrigin, Get}; use frame_system::RawOrigin; use sp_arithmetic::Perquintill; use sp_runtime::{ @@ -106,6 +106,7 @@ benchmarks! { 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()); + Nis::::communify(RawOrigin::Signed(caller.clone()).into(), 0)?; let original = T::Currency::free_balance(&Nis::::account_id()); T::Currency::make_free_balance_be(&Nis::::account_id(), BalanceOf::::min_value()); }: _(origin) @@ -116,7 +117,7 @@ benchmarks! { assert!(missing <= Perquintill::one() / 100_000); } - thaw { + thaw_private { 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)?; @@ -128,6 +129,42 @@ benchmarks! { assert!(Receipts::::get(0).is_none()); } + thaw_communal { + 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() }); + Nis::::communify(RawOrigin::Signed(caller.clone()).into(), 0)?; + }: _(RawOrigin::Signed(caller.clone()), 0) + verify { + assert!(Receipts::::get(0).is_none()); + } + + privatize { + 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()); + Nis::::communify(RawOrigin::Signed(caller.clone()).into(), 0)?; + }: _(RawOrigin::Signed(caller.clone()), 0) + verify { + assert_eq!(Nis::::owner(&0), Some(caller)); + } + + communify { + 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()); + }: _(RawOrigin::Signed(caller.clone()), 0) + verify { + assert_eq!(Nis::::owner(&0), None); + } + process_queues { fill_queues::()?; }: { diff --git a/frame/nis/src/lib.rs b/frame/nis/src/lib.rs index dff64625a3654..fa0163fb60bfe 100644 --- a/frame/nis/src/lib.rs +++ b/frame/nis/src/lib.rs @@ -169,7 +169,7 @@ pub mod pallet { nonfungible::{Inspect as NonfungibleInspect, Transfer as NonfungibleTransfer}, Currency, Defensive, DefensiveSaturating, ExistenceRequirement::AllowDeath, - OnUnbalanced, ReservableCurrency, + NamedReservableCurrency, OnUnbalanced, }, PalletId, }; @@ -189,9 +189,10 @@ pub mod pallet { type ReceiptRecordOf = ReceiptRecord< ::AccountId, ::BlockNumber, + BalanceOf, >; type IssuanceInfoOf = IssuanceInfo>; - type SummaryRecordOf = SummaryRecord<::BlockNumber>; + type SummaryRecordOf = SummaryRecord<::BlockNumber, BalanceOf>; type BidOf = Bid, ::AccountId>; type QueueTotalsTypeOf = BoundedVec<(u32, BalanceOf), ::QueueCount>; @@ -208,7 +209,7 @@ pub mod pallet { type PalletId: Get; /// Currency type that this works on. - type Currency: ReservableCurrency; + type Currency: NamedReservableCurrency; /// Just the `Currency::Balance` type; we have this item to allow us to constrain it to /// `From`. @@ -300,6 +301,12 @@ pub mod pallet { /// The maximum proportion which may be thawed and the period over which it is reset. #[pallet::constant] type ThawThrottle: Get<(Perquintill, Self::BlockNumber)>; + + /// The name for the reserve ID. + #[pallet::constant] + type ReserveId: Get< + >::ReserveIdentifier, + >; } #[pallet::pallet] @@ -321,11 +328,13 @@ pub mod pallet { #[derive( Clone, Eq, PartialEq, Default, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen, )] - pub struct ReceiptRecord { + pub struct ReceiptRecord { /// The proportion of the effective total issuance. pub proportion: Perquintill, - /// The account to whom this receipt belongs. - pub who: AccountId, + /// The account to whom this receipt belongs and the amount of funds on hold in their + /// account for servicing this receipt. If `None`, then it is a communal receipt and + /// fungible counterparts have been issued. + pub owner: Option<(AccountId, Balance)>, /// The time after which this receipt can be thawed. pub expiry: BlockNumber, } @@ -344,7 +353,7 @@ pub mod pallet { #[derive( Clone, Eq, PartialEq, Default, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen, )] - pub struct SummaryRecord { + pub struct SummaryRecord { /// The total proportion over all outstanding receipts. pub proportion_owed: Perquintill, /// The total number of receipts created so far. @@ -353,6 +362,9 @@ pub mod pallet { pub thawed: Perquintill, /// The current thaw period's beginning. pub last_period: BlockNumber, + /// The total amount of funds on hold for receipts. This doesn't include the pot or funds + /// on hold for bids. + pub receipts_on_hold: Balance, } pub struct OnEmptyQueueTotals(sp_std::marker::PhantomData); @@ -440,24 +452,28 @@ pub mod pallet { /// 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, + /// Receipt index is unknown. + UnknownReceipt, /// Not the owner of the receipt. NotOwner, /// Bond not yet at expiry date. NotExpired, /// The given bid for retraction is not found. - NotFound, + UnknownBid, /// The portion supplied is beyond the value of the receipt. - TooMuch, + PortionTooBig, /// Not enough funds are held to pay out. Unfunded, /// There are enough funds for what is required. - Funded, + AlreadyFunded, /// The thaw throttle has been reached for this period. Throttled, /// The operation would result in a receipt worth an insignficant value. MakesDust, + /// The receipt is already communal. + AlreadyCommunal, + /// The receipt is already private. + AlreadyPrivate, } pub(crate) struct WeightCounter { @@ -539,13 +555,17 @@ pub mod pallet { |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)?; + T::Currency::reserve_named(&T::ReserveId::get(), &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); + let _ = T::Currency::unreserve_named( + &T::ReserveId::get(), + &bid.who, + bid.amount, + ); Self::deposit_event(Event::::BidDropped { who: bid.who, amount: bid.amount, @@ -597,7 +617,7 @@ pub mod pallet { 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)?; + let pos = q.iter().position(|i| i == &bid).ok_or(Error::::UnknownBid)?; q.remove(pos); Ok(q.len() as u32) })?; @@ -608,7 +628,7 @@ pub mod pallet { qs[queue_index].1.saturating_reduce(bid.amount); }); - T::Currency::unreserve(&bid.who, bid.amount); + T::Currency::unreserve_named(&T::ReserveId::get(), &bid.who, bid.amount); Self::deposit_event(Event::BidRetracted { who: bid.who, amount: bid.amount, duration }); Ok(()) @@ -625,7 +645,7 @@ pub mod pallet { 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); + ensure!(!deficit.is_zero(), Error::::AlreadyFunded); T::Deficit::on_unbalanced(T::Currency::deposit_creating(&our_account, deficit)); Self::deposit_event(Event::::Funded { deficit }); Ok(()) @@ -640,27 +660,28 @@ pub mod pallet { /// - `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( + #[pallet::weight(T::WeightInfo::thaw_private())] + pub fn thaw_private( origin: OriginFor, #[pallet::compact] index: ReceiptIndex, - portion: Option<>::Balance>, + maybe_proportion: Option, ) -> DispatchResult { let who = ensure_signed(origin)?; // Look for `index` let mut receipt: ReceiptRecordOf = - Receipts::::get(index).ok_or(Error::::Unknown)?; + Receipts::::get(index).ok_or(Error::::UnknownReceipt)?; // If found, check the owner is `who`. - ensure!(receipt.who == who, Error::::NotOwner); + let (owner, mut on_hold) = receipt.owner.ok_or(Error::::AlreadyCommunal)?; + ensure!(owner == 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 proportion = if let Some(proportion) = maybe_proportion { + ensure!(proportion <= receipt.proportion, Error::::PortionTooBig); let remaining = receipt.proportion.saturating_sub(proportion); ensure!( remaining.is_zero() || remaining >= T::MinReceipt::get(), @@ -679,8 +700,6 @@ pub mod pallet { 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; @@ -689,13 +708,55 @@ pub mod pallet { 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 amount > on_hold { + T::Currency::unreserve_named(&T::ReserveId::get(), &who, on_hold); + let deficit = amount - on_hold; + // Try to transfer deficit from pot to receipt owner. + summary.receipts_on_hold.saturating_reduce(on_hold); + on_hold = Zero::zero(); + T::Currency::transfer(&our_account, &who, deficit, AllowDeath) + .map_err(|_| Error::::Unfunded)?; + } else { + T::Currency::unreserve_named(&T::ReserveId::get(), &who, amount); + on_hold.saturating_reduce(amount); + summary.receipts_on_hold.saturating_reduce(amount); + if dropped && !on_hold.is_zero() { + // Reclaim any remainder: + // Transfer `excess` to the pot if we have now fully compensated for the + // receipt. + // + // This will legitimately fail if there is no pot account in existance. + // There's nothing we can do about this so we just swallow the error. + // This code is not ideal and could fail in the second phase leaving + // the system in an invalid state. It can be fixed properly with the + // new API in https://github.com/paritytech/substrate/pull/12951 + // + // Below is what it should look like then: + // let _ = T::Currency::repatriate_reserved_named( + // &T::ReserveId::get(), + // &who, + // &our_account, + // excess, + // BalanceStatus::Free, + // ).defensive(); + T::Currency::unreserve_named(&T::ReserveId::get(), &who, on_hold); + // It could theoretically be locked, so really we should be using a more + // forceful variant. But the alternative `repatriate_reserved_named` will + // fail if the destination account doesn't exist. This should be fixed when + // we move to the `fungible::*` traits, which should include a force + // transfer function to transfer the reserved balance into free balance in + // the destination regardless of locks and create it if it doesn't exist. + let _ = T::Currency::transfer(&who, &Self::account_id(), on_hold, AllowDeath); + summary.receipts_on_hold.saturating_reduce(on_hold); + } + } + if dropped { Receipts::::remove(index); } else { + receipt.owner = Some((owner, on_hold)); Receipts::::insert(index, &receipt); } Summary::::put(&summary); @@ -704,20 +765,159 @@ pub mod pallet { 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 fungible counterpart + /// for receipt `index`. + /// - `index`: The index of the receipt. + #[pallet::call_index(4)] + #[pallet::weight(T::WeightInfo::thaw_communal())] + pub fn thaw_communal( + origin: OriginFor, + #[pallet::compact] index: ReceiptIndex, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + + // Look for `index` + let receipt: ReceiptRecordOf = + Receipts::::get(index).ok_or(Error::::UnknownReceipt)?; + // If found, check it is actually communal. + ensure!(receipt.owner.is_none(), Error::::NotOwner); + let now = frame_system::Pallet::::block_number(); + ensure!(now >= receipt.expiry, Error::::NotExpired); + + let mut summary: SummaryRecordOf = Summary::::get(); + + 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(receipt.proportion); + ensure!(summary.thawed <= throttle, Error::::Throttled); + + T::Counterpart::burn_from(&who, T::CounterpartAmount::convert(receipt.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 = receipt.proportion * effective_issuance; + + summary.proportion_owed.saturating_reduce(receipt.proportion); + + // Try to transfer amount owed from pot to receipt owner. + T::Currency::transfer(&our_account, &who, amount, AllowDeath) + .map_err(|_| Error::::Unfunded)?; + + Receipts::::remove(index); + Summary::::put(&summary); + + let e = + Event::Thawed { index, who, amount, proportion: receipt.proportion, dropped: true }; + Self::deposit_event(e); + + Ok(()) + } + + /// Make a private receipt communal and create fungible counterparts for its owner. + #[pallet::call_index(5)] + #[pallet::weight(T::WeightInfo::communify())] + pub fn communify( + origin: OriginFor, + #[pallet::compact] index: ReceiptIndex, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + + // Look for `index` + let mut receipt: ReceiptRecordOf = + Receipts::::get(index).ok_or(Error::::UnknownReceipt)?; + + // Check it's not already communal and make it so. + let (owner, on_hold) = receipt.owner.take().ok_or(Error::::AlreadyCommunal)?; + + // If found, check the owner is `who`. + ensure!(owner == who, Error::::NotOwner); + + // Unreserve and transfer the funds to the pot. + T::Currency::unreserve_named(&T::ReserveId::get(), &who, on_hold); + // Transfer `excess` to the pot if we have now fully compensated for the receipt. + T::Currency::transfer(&who, &Self::account_id(), on_hold, AllowDeath) + .map_err(|_| Error::::Unfunded)?; + // TODO #12951: ^^^ The above should be done in a single operation `transfer_on_hold`. + + // Record that we've moved the amount reserved. + let mut summary: SummaryRecordOf = Summary::::get(); + summary.receipts_on_hold.saturating_reduce(on_hold); + Summary::::put(&summary); + Receipts::::insert(index, &receipt); + + // Mint fungibles. + let fung_eq = T::CounterpartAmount::convert(receipt.proportion); + let _ = T::Counterpart::mint_into(&who, fung_eq).defensive(); + + Ok(()) + } + + /// Make a communal receipt private and burn fungible counterparts from its owner. + #[pallet::call_index(6)] + #[pallet::weight(T::WeightInfo::privatize())] + pub fn privatize( + origin: OriginFor, + #[pallet::compact] index: ReceiptIndex, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + + // Look for `index` + let mut receipt: ReceiptRecordOf = + Receipts::::get(index).ok_or(Error::::UnknownReceipt)?; + + // If found, check there is no owner. + ensure!(receipt.owner.is_none(), Error::::AlreadyPrivate); + + // Multiply the proportion it is by the total issued. + let mut summary: SummaryRecordOf = Summary::::get(); + let our_account = Self::account_id(); + let effective_issuance = Self::issuance_with(&our_account, &summary).effective; + let max_amount = receipt.proportion * effective_issuance; + // Avoid trying to place more in the account's reserve than we have available in the pot + let amount = max_amount.min(T::Currency::free_balance(&our_account)); + + // Burn fungible counterparts. + T::Counterpart::burn_from(&who, T::CounterpartAmount::convert(receipt.proportion))?; + + // Transfer the funds from the pot to the owner and reserve + T::Currency::transfer(&Self::account_id(), &who, amount, AllowDeath) + .map_err(|_| Error::::Unfunded)?; + T::Currency::reserve_named(&T::ReserveId::get(), &who, amount)?; + // TODO: ^^^ The above should be done in a single operation `transfer_and_hold`. + + // Record that we've moved the amount reserved. + summary.receipts_on_hold.saturating_accrue(amount); + + receipt.owner = Some((who, amount)); + + Summary::::put(&summary); + Receipts::::insert(index, &receipt); + + Ok(()) + } } /// Issuance information returned by `issuance()`. - #[derive(RuntimeDebug)] + #[derive(Debug)] pub struct IssuanceInfo { - /// The balance held in reserve by this pallet instance. + /// The balance held by this pallet instance together with the balances on hold across + /// all receipt-owning accounts. 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. + /// The amount needed to be accessible to this pallet in case all outstanding receipts were + /// thawed at present. If it is more than `holdings`, then the pallet will need funding. pub required: Balance, } @@ -725,7 +925,7 @@ pub mod pallet { type ItemId = ReceiptIndex; fn owner(item: &ReceiptIndex) -> Option { - Receipts::::get(item).map(|r| r.who) + Receipts::::get(item).and_then(|r| r.owner).map(|(who, _)| who) } fn attribute(item: &Self::ItemId, key: &[u8]) -> Option> { @@ -733,6 +933,8 @@ pub mod pallet { match key { b"proportion" => Some(item.proportion.encode()), b"expiry" => Some(item.expiry.encode()), + b"owner" => item.owner.as_ref().map(|x| x.0.encode()), + b"on_hold" => item.owner.as_ref().map(|x| x.1.encode()), _ => None, } } @@ -741,12 +943,28 @@ pub mod pallet { 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(); + let (owner, on_hold) = item.owner.take().ok_or(Error::::AlreadyCommunal)?; + + // TODO: This should all be replaced by a single call `transfer_held`. + let shortfall = T::Currency::unreserve_named(&T::ReserveId::get(), &owner, on_hold); + if !shortfall.is_zero() { + let _ = + T::Currency::reserve_named(&T::ReserveId::get(), &owner, on_hold - shortfall); + return Err(TokenError::NoFunds.into()) + } + if let Err(e) = T::Currency::transfer(&owner, destination, on_hold, AllowDeath) { + let _ = T::Currency::reserve_named(&T::ReserveId::get(), &owner, on_hold); + return Err(e) + } + // This can never fail, and if it somehow does, then we can't handle this gracefully. + let _ = + T::Currency::reserve_named(&T::ReserveId::get(), destination, on_hold).defensive(); + + item.owner = Some((destination.clone(), on_hold)); Receipts::::insert(&index, &item); Pallet::::deposit_event(Event::::Transferred { - from, - to: item.who, + from: owner, + to: destination.clone(), index: *index, }); Ok(()) @@ -781,7 +999,8 @@ pub mod pallet { ) -> IssuanceInfo> { let total_issuance = T::Currency::total_issuance().saturating_sub(T::IgnoredIssuance::get()); - let holdings = T::Currency::free_balance(our_account); + let holdings = + T::Currency::free_balance(our_account).saturating_add(summary.receipts_on_hold); let other = total_issuance.saturating_sub(holdings); let effective = summary.proportion_owed.left_from_one().saturating_reciprocal_mul(other); @@ -893,7 +1112,7 @@ pub mod pallet { pub(crate) fn process_bid( mut bid: BidOf, expiry: T::BlockNumber, - our_account: &T::AccountId, + _our_account: &T::AccountId, issuance: &IssuanceInfo>, remaining: &mut BalanceOf, queue_amount: &mut BalanceOf, @@ -906,10 +1125,8 @@ pub mod pallet { } 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 - } + let amount = bid.amount; + summary.receipts_on_hold.saturating_accrue(amount); // Can never overflow due to block above. remaining.saturating_reduce(amount); @@ -928,12 +1145,9 @@ pub mod pallet { let e = Event::Issued { index, expiry, who: who.clone(), amount, proportion }; Self::deposit_event(e); - let receipt = ReceiptRecord { proportion, who: who.clone(), expiry }; + let receipt = ReceiptRecord { proportion, owner: Some((who, amount)), 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/nis/src/mock.rs b/frame/nis/src/mock.rs index ebe073d683309..585ed2d8b278f 100644 --- a/frame/nis/src/mock.rs +++ b/frame/nis/src/mock.rs @@ -84,7 +84,7 @@ impl pallet_balances::Config for Test { type AccountStore = System; type WeightInfo = (); type MaxLocks = (); - type MaxReserves = (); + type MaxReserves = ConstU32<1>; type ReserveIdentifier = [u8; 8]; } @@ -112,6 +112,7 @@ parameter_types! { 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); + pub const ReserveId: [u8; 8] = *b"py/nis "; } ord_parameter_types! { @@ -139,6 +140,7 @@ impl pallet_nis::Config for Test { type MaxIntakeWeight = MaxIntakeWeight; type MinReceipt = MinReceipt; type ThawThrottle = ThawThrottle; + type ReserveId = ReserveId; } // This function basically just builds a genesis storage key/value store according to diff --git a/frame/nis/src/tests.rs b/frame/nis/src/tests.rs index f0c45cc80b0e5..b5feb4df16aab 100644 --- a/frame/nis/src/tests.rs +++ b/frame/nis/src/tests.rs @@ -34,8 +34,16 @@ fn pot() -> u64 { Balances::free_balance(&Nis::account_id()) } +fn holdings() -> u64 { + Nis::issuance().holdings +} + +fn signed(who: u64) -> RuntimeOrigin { + RuntimeOrigin::signed(who) +} + fn enlarge(amount: u64, max_bids: u32) { - let summary: SummaryRecord = Summary::::get(); + 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()); @@ -55,7 +63,8 @@ fn basic_setup_works() { proportion_owed: Perquintill::zero(), index: 0, last_period: 0, - thawed: Perquintill::zero() + thawed: Perquintill::zero(), + receipts_on_hold: 0, } ); }); @@ -65,16 +74,13 @@ fn basic_setup_works() { 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(signed(1), 1, 2), Error::::AmountTooSmall); assert_noop!( - Nis::place_bid(RuntimeOrigin::signed(1), 101, 2), + Nis::place_bid(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_noop!(Nis::place_bid(signed(1), 10, 4), Error::::DurationTooBig); + assert_ok!(Nis::place_bid(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)]); @@ -85,16 +91,16 @@ fn place_bid_works() { 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_ok!(Nis::place_bid(signed(1), 20, 2)); + assert_ok!(Nis::place_bid(signed(1), 10, 2)); + assert_ok!(Nis::place_bid(signed(1), 5, 2)); + assert_noop!(Nis::place_bid(signed(1), 5, 2), Error::::BidTooLow); + assert_ok!(Nis::place_bid(signed(1), 15, 2)); assert_eq!(Balances::reserved_balance(1), 45); - assert_ok!(Nis::place_bid(RuntimeOrigin::signed(1), 25, 2)); + assert_ok!(Nis::place_bid(signed(1), 25, 2)); assert_eq!(Balances::reserved_balance(1), 60); - assert_noop!(Nis::place_bid(RuntimeOrigin::signed(1), 10, 2), Error::::BidTooLow); + assert_noop!(Nis::place_bid(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!(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)); + assert_ok!(Nis::place_bid(signed(1), 10, 2)); + assert_ok!(Nis::place_bid(signed(2), 10, 2)); + assert_ok!(Nis::place_bid(signed(3), 10, 2)); + assert_noop!(Nis::place_bid(signed(4), 10, 2), Error::::BidTooLow); + assert_ok!(Nis::place_bid(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!(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_ok!(Nis::place_bid(signed(1), 10, 1)); + assert_ok!(Nis::place_bid(signed(1), 10, 2)); + assert_ok!(Nis::place_bid(signed(1), 10, 2)); + assert_ok!(Nis::place_bid(signed(1), 10, 3)); + assert_ok!(Nis::place_bid(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!(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_ok!(Nis::place_bid(signed(1), 10, 1)); + assert_ok!(Nis::place_bid(signed(1), 10, 2)); + assert_ok!(Nis::retract_bid(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!(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::place_bid(signed(1), 10, 1)); + assert_ok!(Nis::place_bid(signed(1), 10, 2)); + assert_ok!(Nis::place_bid(signed(1), 10, 2)); + assert_ok!(Nis::place_bid(signed(2), 10, 2)); - assert_ok!(Nis::retract_bid(RuntimeOrigin::signed(1), 10, 2)); + assert_ok!(Nis::retract_bid(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 },]); @@ -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!(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); + assert_noop!(Nis::retract_bid(signed(1), 10, 1), Error::::UnknownBid); + assert_ok!(Nis::place_bid(signed(1), 10, 1)); + assert_noop!(Nis::retract_bid(signed(1), 20, 1), Error::::UnknownBid); + assert_noop!(Nis::retract_bid(signed(1), 10, 2), Error::::UnknownBid); + assert_noop!(Nis::retract_bid(signed(2), 10, 1), Error::::UnknownBid); }); } @@ -197,14 +203,14 @@ fn retract_non_existent_item_fails() { 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)); + assert_ok!(Nis::place_bid(signed(1), 40, 1)); + assert_ok!(Nis::place_bid(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!(Balances::reserved_balance(2), 40); + assert_eq!(holdings(), 40); assert_eq!(Queues::::get(1), vec![Bid { amount: 40, who: 1 }]); assert_eq!(Queues::::get(2), vec![]); @@ -216,12 +222,17 @@ fn basic_enlarge_works() { proportion_owed: Perquintill::from_percent(10), index: 1, last_period: 0, - thawed: Perquintill::zero() + thawed: Perquintill::zero(), + receipts_on_hold: 40, } ); assert_eq!( Receipts::::get(0).unwrap(), - ReceiptRecord { proportion: Perquintill::from_percent(10), who: 2, expiry: 7 } + ReceiptRecord { + proportion: Perquintill::from_percent(10), + owner: Some((2, 40)), + expiry: 7 + } ); }); } @@ -230,10 +241,10 @@ fn basic_enlarge_works() { 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)); + assert_ok!(Nis::place_bid(signed(1), 40, 1)); + assert_ok!(Nis::place_bid(signed(2), 40, 2)); + assert_ok!(Nis::place_bid(signed(3), 40, 2)); + assert_ok!(Nis::place_bid(signed(4), 40, 3)); enlarge(100, 2); // Should have taken 4/3 and 2/2, then stopped because it's only allowed 2. @@ -244,11 +255,19 @@ fn enlarge_respects_bids_limit() { assert_eq!( Receipts::::get(0).unwrap(), - ReceiptRecord { proportion: Perquintill::from_percent(10), who: 4, expiry: 10 } + ReceiptRecord { + proportion: Perquintill::from_percent(10), + owner: Some((4, 40)), + expiry: 10 + } ); assert_eq!( Receipts::::get(1).unwrap(), - ReceiptRecord { proportion: Perquintill::from_percent(10), who: 2, expiry: 7 } + ReceiptRecord { + proportion: Perquintill::from_percent(10), + owner: Some((2, 40)), + expiry: 7 + } ); assert_eq!( Summary::::get(), @@ -256,7 +275,8 @@ fn enlarge_respects_bids_limit() { proportion_owed: Perquintill::from_percent(20), index: 2, last_period: 0, - thawed: Perquintill::zero() + thawed: Perquintill::zero(), + receipts_on_hold: 80, } ); }); @@ -266,7 +286,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!(Nis::place_bid(RuntimeOrigin::signed(1), 80, 1)); + assert_ok!(Nis::place_bid(signed(1), 80, 1)); enlarge(40, 2); // Takes 2/2, then stopped because it reaches its max amount @@ -275,7 +295,11 @@ fn enlarge_respects_amount_limit_and_will_split() { assert_eq!( Receipts::::get(0).unwrap(), - ReceiptRecord { proportion: Perquintill::from_percent(10), who: 1, expiry: 4 } + ReceiptRecord { + proportion: Perquintill::from_percent(10), + owner: Some((1, 40)), + expiry: 4 + } ); assert_eq!( Summary::::get(), @@ -283,7 +307,8 @@ fn enlarge_respects_amount_limit_and_will_split() { proportion_owed: Perquintill::from_percent(10), index: 1, last_period: 0, - thawed: Perquintill::zero() + thawed: Perquintill::zero(), + receipts_on_hold: 40, } ); }); @@ -293,25 +318,25 @@ fn enlarge_respects_amount_limit_and_will_split() { fn basic_thaw_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(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); + assert_eq!(holdings(), 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); + assert_eq!(Balances::reserved_balance(1), 40); + assert_eq!(holdings(), 40); run_to_block(3); - assert_noop!(Nis::thaw(RuntimeOrigin::signed(1), 0, None), Error::::NotExpired); + assert_noop!(Nis::thaw_private(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_noop!(Nis::thaw_private(signed(1), 1, None), Error::::UnknownReceipt); + assert_noop!(Nis::thaw_private(signed(2), 0, None), Error::::NotOwner); - assert_ok!(Nis::thaw(RuntimeOrigin::signed(1), 0, None)); + assert_ok!(Nis::thaw_private(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); @@ -323,7 +348,8 @@ fn basic_thaw_works() { proportion_owed: Perquintill::zero(), index: 1, last_period: 0, - thawed: Perquintill::from_percent(10) + thawed: Perquintill::from_percent(10), + receipts_on_hold: 0, } ); assert_eq!(Receipts::::get(0), None); @@ -334,18 +360,16 @@ fn basic_thaw_works() { fn partial_thaw_works() { new_test_ext().execute_with(|| { run_to_block(1); - assert_ok!(Nis::place_bid(RuntimeOrigin::signed(1), 80, 1)); + assert_ok!(Nis::place_bid(signed(1), 80, 1)); enlarge(80, 1); - assert_eq!(pot(), 80); + assert_eq!(holdings(), 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))); + let prop = Perquintill::from_rational(4_100_000, 21_000_000u64); + assert_noop!(Nis::thaw_private(signed(1), 0, Some(prop)), Error::::MakesDust); + let prop = Perquintill::from_rational(1_050_000, 21_000_000u64); + assert_ok!(Nis::thaw_private(signed(1), 0, Some(prop))); - 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)), @@ -353,9 +377,9 @@ fn partial_thaw_works() { assert_eq!(Nis::issuance().effective, 400); assert_eq!(Balances::free_balance(1), 40); - assert_eq!(pot(), 60); + assert_eq!(holdings(), 60); - assert_ok!(Nis::thaw(RuntimeOrigin::signed(1), 0, None)); + assert_ok!(Nis::thaw_private(signed(1), 0, None)); assert_eq!(Nis::issuance().effective, 400); assert_eq!(Balances::free_balance(1), 100); @@ -367,7 +391,8 @@ fn partial_thaw_works() { proportion_owed: Perquintill::zero(), index: 1, last_period: 0, - thawed: Perquintill::from_percent(20) + thawed: Perquintill::from_percent(20), + receipts_on_hold: 0, } ); assert_eq!(Receipts::::get(0), None); @@ -378,35 +403,144 @@ fn partial_thaw_works() { fn thaw_respects_transfers() { new_test_ext().execute_with(|| { run_to_block(1); - assert_ok!(Nis::place_bid(RuntimeOrigin::signed(1), 40, 1)); + assert_ok!(Nis::place_bid(signed(1), 40, 1)); enlarge(40, 1); run_to_block(4); assert_eq!(Nis::owner(&0), Some(1)); + assert_eq!(Balances::reserved_balance(&1), 40); + assert_eq!(Balances::reserved_balance(&2), 0); assert_ok!(Nis::transfer(&0, &2)); + assert_eq!(Balances::reserved_balance(&1), 0); + assert_eq!(Balances::reserved_balance(&2), 40); // 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); + assert_noop!(Nis::thaw_private(signed(1), 0, None), Error::::NotOwner); - // 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_ok!(Nis::thaw_private(signed(2), 0, None)); - assert_eq!(Balances::free_balance(2), 140); - assert_eq!(Balances::free_balance(1), 60); + assert_eq!(Balances::total_balance(&2), 140); + assert_eq!(Balances::total_balance(&1), 60); + }); +} + +#[test] +fn communify_works() { + new_test_ext().execute_with(|| { + run_to_block(1); + assert_ok!(Nis::place_bid(signed(1), 40, 1)); + enlarge(40, 1); + run_to_block(4); + + assert_eq!(Nis::owner(&0), Some(1)); + assert_eq!(Balances::reserved_balance(&1), 40); + assert_eq!(pot(), 0); + assert_eq!(NisBalances::free_balance(&1), 0); + assert_ok!(Nis::communify(signed(1), 0)); + assert_eq!(Nis::owner(&0), None); + assert_eq!(Balances::reserved_balance(&1), 0); + assert_eq!(pot(), 40); + // We now have fungibles. + assert_eq!(NisBalances::free_balance(&1), 2_100_000); + + // Can't transfer the NFT or thaw it as a private. + assert_noop!(Nis::thaw_private(signed(1), 0, None), Error::::AlreadyCommunal); + assert_noop!(Nis::transfer(&0, &2), Error::::AlreadyCommunal); + // Communal thawing would be possible, except it's the wrong receipt. + assert_noop!(Nis::thaw_communal(signed(1), 1), Error::::UnknownReceipt); + + // Transfer some of the fungibles away. + assert_ok!(NisBalances::transfer(signed(1), 2, 100_000)); + assert_eq!(NisBalances::free_balance(&1), 2_000_000); + assert_eq!(NisBalances::free_balance(&2), 100_000); + + // Communal thawing with the correct index is not possible now. + assert_noop!(Nis::thaw_communal(signed(1), 0), TokenError::NoFunds); + assert_noop!(Nis::thaw_communal(signed(2), 0), TokenError::NoFunds); + + // Transfer the rest to 2... + assert_ok!(NisBalances::transfer(signed(1), 2, 2_000_000)); + assert_eq!(NisBalances::free_balance(&1), 0); + assert_eq!(NisBalances::free_balance(&2), 2_100_000); + + // ...and thawing becomes possible. + assert_ok!(Nis::thaw_communal(signed(2), 0)); + assert_eq!(NisBalances::free_balance(&1), 0); + assert_eq!(NisBalances::free_balance(&2), 0); + assert_eq!(pot(), 0); + assert_eq!(Balances::total_balance(&1), 60); + assert_eq!(Balances::total_balance(&2), 140); + + assert_noop!(Nis::thaw_communal(signed(2), 0), Error::::UnknownReceipt); + }); +} + +#[test] +fn privatize_works() { + new_test_ext().execute_with(|| { + run_to_block(1); + assert_ok!(Nis::place_bid(signed(1), 40, 1)); + enlarge(40, 1); + run_to_block(4); + assert_noop!(Nis::privatize(signed(2), 0), Error::::AlreadyPrivate); + assert_ok!(Nis::communify(signed(1), 0)); + + // Transfer the fungibles to #2 + assert_ok!(NisBalances::transfer(signed(1), 2, 2_100_000)); + assert_noop!(Nis::privatize(signed(1), 0), TokenError::NoFunds); + + // Privatize + assert_ok!(Nis::privatize(signed(2), 0)); + assert_noop!(Nis::privatize(signed(2), 0), Error::::AlreadyPrivate); + assert_eq!(NisBalances::free_balance(&2), 0); + assert_eq!(Nis::owner(&0), Some(2)); + assert_eq!(Balances::reserved_balance(&2), 40); + assert_eq!(pot(), 0); }); } #[test] -fn thaw_when_issuance_higher_works() { +fn privatize_and_thaw_with_another_receipt_works() { new_test_ext().execute_with(|| { run_to_block(1); - assert_ok!(Nis::place_bid(RuntimeOrigin::signed(1), 100, 1)); + assert_ok!(Nis::place_bid(signed(1), 40, 1)); + assert_ok!(Nis::place_bid(signed(2), 40, 1)); + enlarge(80, 2); + run_to_block(4); + + assert_ok!(Nis::communify(signed(1), 0)); + assert_ok!(Nis::communify(signed(2), 1)); + + // Transfer half of fungibles to #3 from each of #1 and #2, and the other half from #2 to #4 + assert_ok!(NisBalances::transfer(signed(1), 3, 1_050_000)); + assert_ok!(NisBalances::transfer(signed(2), 3, 1_050_000)); + assert_ok!(NisBalances::transfer(signed(2), 4, 1_050_000)); + + // #3 privatizes, partially thaws, then re-communifies with #0, then transfers the fungibles + // to #2 + assert_ok!(Nis::privatize(signed(3), 0)); + assert_ok!(Nis::thaw_private(signed(3), 0, Some(Perquintill::from_percent(5)))); + assert_ok!(Nis::communify(signed(3), 0)); + assert_ok!(NisBalances::transfer(signed(3), 1, 1_050_000)); + + // #1 now has enough to thaw using receipt 1 + assert_ok!(Nis::thaw_communal(signed(1), 1)); + + // #4 now has enough to thaw using receipt 0 + assert_ok!(Nis::thaw_communal(signed(4), 0)); + }); +} + +#[test] +fn communal_thaw_when_issuance_higher_works() { + new_test_ext().execute_with(|| { + run_to_block(1); + assert_ok!(Nis::place_bid(signed(1), 100, 1)); enlarge(100, 1); + assert_ok!(Nis::communify(signed(1), 0)); + assert_eq!(NisBalances::free_balance(1), 5_250_000); // (25% of 21m) // Everybody else's balances goes up by 50% @@ -417,19 +551,45 @@ fn thaw_when_issuance_higher_works() { run_to_block(4); // Unfunded initially... - assert_noop!(Nis::thaw(RuntimeOrigin::signed(1), 0, None), Error::::Unfunded); + assert_noop!(Nis::thaw_communal(signed(1), 0), Error::::Unfunded); // ...so we fund. - assert_ok!(Nis::fund_deficit(RuntimeOrigin::signed(1))); + assert_ok!(Nis::fund_deficit(signed(1))); - // Transfer counterpart away... - assert_ok!(NisBalances::transfer(RuntimeOrigin::signed(1), 2, 250_000)); + // Transfer counterparts away... + assert_ok!(NisBalances::transfer(signed(1), 2, 250_000)); // ...and it's not thawable. - assert_noop!(Nis::thaw(RuntimeOrigin::signed(1), 0, None), TokenError::NoFunds); + assert_noop!(Nis::thaw_communal(signed(1), 0), TokenError::NoFunds); - // Transfer counterpart back... - assert_ok!(NisBalances::transfer(RuntimeOrigin::signed(2), 1, 250_000)); + // Transfer counterparts back... + assert_ok!(NisBalances::transfer(signed(2), 1, 250_000)); // ...and it is. - assert_ok!(Nis::thaw(RuntimeOrigin::signed(1), 0, None)); + assert_ok!(Nis::thaw_communal(signed(1), 0)); + + assert_eq!(Balances::free_balance(1), 150); + assert_eq!(Balances::reserved_balance(1), 0); + }); +} + +#[test] +fn private_thaw_when_issuance_higher_works() { + new_test_ext().execute_with(|| { + run_to_block(1); + assert_ok!(Nis::place_bid(signed(1), 100, 1)); + 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); + + // Unfunded initially... + assert_noop!(Nis::thaw_private(signed(1), 0, None), Error::::Unfunded); + // ...so we fund. + assert_ok!(Nis::fund_deficit(signed(1))); + + assert_ok!(Nis::thaw_private(signed(1), 0, None)); assert_eq!(Balances::free_balance(1), 150); assert_eq!(Balances::reserved_balance(1), 0); @@ -443,21 +603,21 @@ fn thaw_with_ignored_issuance_works() { // Give account zero some balance. Balances::make_free_balance_be(&0, 200); - assert_ok!(Nis::place_bid(RuntimeOrigin::signed(1), 100, 1)); + assert_ok!(Nis::place_bid(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)); + assert_ok!(Balances::transfer(signed(0), 2, 50)); + assert_ok!(Balances::transfer(signed(0), 3, 50)); + assert_ok!(Balances::transfer(signed(0), 4, 50)); run_to_block(4); // Unfunded initially... - assert_noop!(Nis::thaw(RuntimeOrigin::signed(1), 0, None), Error::::Unfunded); + assert_noop!(Nis::thaw_private(signed(1), 0, None), Error::::Unfunded); // ...so we fund... - assert_ok!(Nis::fund_deficit(RuntimeOrigin::signed(1))); + assert_ok!(Nis::fund_deficit(signed(1))); // ...and then it's ok. - assert_ok!(Nis::thaw(RuntimeOrigin::signed(1), 0, None)); + assert_ok!(Nis::thaw_private(signed(1), 0, None)); // Account zero changes have been ignored. assert_eq!(Balances::free_balance(1), 150); @@ -469,7 +629,7 @@ fn thaw_with_ignored_issuance_works() { 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)); + assert_ok!(Nis::place_bid(signed(1), 100, 1)); enlarge(100, 1); // Everybody else's balances goes down by 25% @@ -478,7 +638,7 @@ fn thaw_when_issuance_lower_works() { Balances::make_free_balance_be(&4, 75); run_to_block(4); - assert_ok!(Nis::thaw(RuntimeOrigin::signed(1), 0, None)); + assert_ok!(Nis::thaw_private(signed(1), 0, None)); assert_eq!(Balances::free_balance(1), 75); assert_eq!(Balances::reserved_balance(1), 0); @@ -489,23 +649,23 @@ fn thaw_when_issuance_lower_works() { 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)); + assert_ok!(Nis::place_bid(signed(1), 40, 1)); + assert_ok!(Nis::place_bid(signed(1), 60, 1)); + assert_ok!(Nis::place_bid(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))); + assert_ok!(Nis::fund_deficit(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); + assert_ok!(Nis::thaw_private(signed(1), 0, None)); + assert_ok!(Nis::thaw_private(signed(1), 1, None)); + assert_noop!(Nis::thaw_private(signed(2), 2, None), Error::::Throttled); run_to_block(5); - assert_ok!(Nis::thaw(RuntimeOrigin::signed(2), 2, None)); + assert_ok!(Nis::thaw_private(signed(2), 2, None)); assert_eq!(Balances::free_balance(1), 200); assert_eq!(Balances::free_balance(2), 200); @@ -516,24 +676,24 @@ fn multiple_thaws_works() { 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)); + assert_ok!(Nis::place_bid(signed(1), 40, 1)); + assert_ok!(Nis::place_bid(signed(1), 60, 1)); + assert_ok!(Nis::place_bid(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))); + assert_ok!(Nis::fund_deficit(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)); + assert_ok!(Nis::thaw_private(signed(2), 2, None)); + assert_noop!(Nis::thaw_private(signed(1), 1, None), Error::::Throttled); + assert_ok!(Nis::thaw_private(signed(1), 0, None)); run_to_block(5); - assert_ok!(Nis::thaw(RuntimeOrigin::signed(1), 1, None)); + assert_ok!(Nis::thaw_private(signed(1), 1, None)); assert_eq!(Balances::free_balance(1), 200); assert_eq!(Balances::free_balance(2), 200); @@ -548,11 +708,11 @@ fn enlargement_to_target_works() { <() 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)); + assert_ok!(Nis::place_bid(signed(1), 40, 1)); + assert_ok!(Nis::place_bid(signed(1), 40, 2)); + assert_ok!(Nis::place_bid(signed(2), 40, 2)); + assert_ok!(Nis::place_bid(signed(2), 40, 3)); + assert_ok!(Nis::place_bid(signed(3), 40, 3)); Target::set(Perquintill::from_percent(40)); run_to_block(3); @@ -571,11 +731,19 @@ fn enlargement_to_target_works() { // 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 } + ReceiptRecord { + proportion: Perquintill::from_percent(10), + owner: Some((2, 40)), + expiry: 13 + } ); assert_eq!( Receipts::::get(1).unwrap(), - ReceiptRecord { proportion: Perquintill::from_percent(10), who: 3, expiry: 13 } + ReceiptRecord { + proportion: Perquintill::from_percent(10), + owner: Some((3, 40)), + expiry: 13 + } ); assert_eq!( Summary::::get(), @@ -584,6 +752,7 @@ fn enlargement_to_target_works() { index: 2, last_period: 0, thawed: Perquintill::zero(), + receipts_on_hold: 80, } ); @@ -595,7 +764,8 @@ fn enlargement_to_target_works() { proportion_owed: Perquintill::from_percent(20), index: 2, last_period: 0, - thawed: Perquintill::zero() + thawed: Perquintill::zero(), + receipts_on_hold: 80, } ); @@ -603,11 +773,19 @@ fn enlargement_to_target_works() { // 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 } + ReceiptRecord { + proportion: Perquintill::from_percent(10), + owner: Some((1, 40)), + expiry: 12 + } ); assert_eq!( Receipts::::get(3).unwrap(), - ReceiptRecord { proportion: Perquintill::from_percent(10), who: 2, expiry: 12 } + ReceiptRecord { + proportion: Perquintill::from_percent(10), + owner: Some((2, 40)), + expiry: 12 + } ); assert_eq!( Summary::::get(), @@ -615,7 +793,8 @@ fn enlargement_to_target_works() { proportion_owed: Perquintill::from_percent(40), index: 4, last_period: 0, - thawed: Perquintill::zero() + thawed: Perquintill::zero(), + receipts_on_hold: 160, } ); @@ -627,7 +806,8 @@ fn enlargement_to_target_works() { proportion_owed: Perquintill::from_percent(40), index: 4, last_period: 0, - thawed: Perquintill::zero() + thawed: Perquintill::zero(), + receipts_on_hold: 160, } ); @@ -635,10 +815,14 @@ fn enlargement_to_target_works() { 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. + // One new item should have been issued to 1 for 40 each & duration of 2. assert_eq!( Receipts::::get(4).unwrap(), - ReceiptRecord { proportion: Perquintill::from_percent(10), who: 1, expiry: 13 } + ReceiptRecord { + proportion: Perquintill::from_percent(10), + owner: Some((1, 40)), + expiry: 13 + } ); assert_eq!( @@ -647,7 +831,8 @@ fn enlargement_to_target_works() { proportion_owed: Perquintill::from_percent(50), index: 5, last_period: 0, - thawed: Perquintill::zero() + thawed: Perquintill::zero(), + receipts_on_hold: 200, } ); }); diff --git a/frame/nis/src/weights.rs b/frame/nis/src/weights.rs index 71577075ada91..769ff795514c6 100644 --- a/frame/nis/src/weights.rs +++ b/frame/nis/src/weights.rs @@ -1,40 +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. //! 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: `[]` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! DATE: 2022-12-15, STEPS: `5`, REPEAT: 2, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `Workhorse.local`, CPU: `` //! EXECUTION: Some(Wasm), 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_nis -// --extrinsic=* +// --chain +// dev +// --steps +// 5 +// --repeat +// 2 +// --pallet +// pallet_nis +// --extrinsic +// * // --execution=wasm // --wasm-execution=compiled -// --template=./.maintain/frame-weight-template.hbs -// --output=./frame/nis/src/weights.rs +// --output +// ../../../frame/nis/src/weights.rs +// --template +// ../../../.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -48,8 +39,11 @@ pub trait WeightInfo { fn place_bid(l: u32, ) -> Weight; fn place_bid_max() -> Weight; fn retract_bid(l: u32, ) -> Weight; - fn thaw() -> Weight; fn fund_deficit() -> Weight; + fn thaw_private() -> Weight; + fn thaw_communal() -> Weight; + fn privatize() -> Weight; + fn communify() -> Weight; fn process_queues() -> Weight; fn process_queue() -> Weight; fn process_bid() -> Weight; @@ -59,143 +53,223 @@ pub trait WeightInfo { pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Nis Queues (r:1 w:1) + // Storage: Balances Reserves (r:1 w:1) // Storage: Nis QueueTotals (r:1 w:1) + /// The range of component `l` is `[0, 999]`. fn place_bid(l: u32, ) -> Weight { - // 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)) + // Minimum execution time: 47_000 nanoseconds. + Weight::from_ref_time(53_822_030) + // Standard Error: 4_869 + .saturating_add(Weight::from_ref_time(47_431).saturating_mul(l.into())) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: Nis Queues (r:1 w:1) + // Storage: Balances Reserves (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)) + // Minimum execution time: 109_000 nanoseconds. + Weight::from_ref_time(109_000_000) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) } // Storage: Nis Queues (r:1 w:1) // Storage: Nis QueueTotals (r:1 w:1) + // Storage: Balances Reserves (r:1 w:1) + /// The range of component `l` is `[1, 1000]`. fn retract_bid(l: u32, ) -> Weight { - // 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: 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: Nis Active (r:1 w:1) - // Storage: Nis ActiveTotal (r:1 w:1) + // Minimum execution time: 50_000 nanoseconds. + Weight::from_ref_time(54_479_879) + // Standard Error: 4_891 + .saturating_add(Weight::from_ref_time(38_224).saturating_mul(l.into())) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) + } + // Storage: Nis Summary (r:1 w:0) + // Storage: System Account (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)) + // Minimum execution time: 57_000 nanoseconds. + Weight::from_ref_time(62_000_000) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) } - // 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: Nis Receipts (r:1 w:1) + // Storage: Nis Summary (r:1 w:1) + // Storage: System Account (r:1 w:0) + // Storage: Balances Reserves (r:1 w:1) + fn thaw_private() -> Weight { + // Minimum execution time: 84_000 nanoseconds. + Weight::from_ref_time(85_000_000) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + // Storage: Nis Receipts (r:1 w:1) + // Storage: Nis Summary (r:1 w:1) + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Account (r:1 w:1) + // Storage: System Account (r:1 w:1) + fn thaw_communal() -> Weight { + // Minimum execution time: 108_000 nanoseconds. + Weight::from_ref_time(115_000_000) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(5)) } - // Storage: Nis ActiveTotal (r:1 w:1) + // Storage: Nis Receipts (r:1 w:1) + // Storage: Nis Summary (r:1 w:1) + // Storage: System Account (r:1 w:1) + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Account (r:1 w:1) + // Storage: Balances Reserves (r:1 w:1) + fn privatize() -> Weight { + // Minimum execution time: 107_000 nanoseconds. + Weight::from_ref_time(110_000_000) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(6)) + } + // Storage: Nis Receipts (r:1 w:1) + // Storage: Balances Reserves (r:1 w:1) + // Storage: System Account (r:1 w:1) + // Storage: Nis Summary (r:1 w:1) + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Account (r:1 w:1) + fn communify() -> Weight { + // Minimum execution time: 89_000 nanoseconds. + Weight::from_ref_time(89_000_000) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(6)) + } + // Storage: Nis Summary (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Nis QueueTotals (r:1 w:1) + fn process_queues() -> Weight { + // Minimum execution time: 34_000 nanoseconds. + Weight::from_ref_time(38_000_000) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } // 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)) + // Minimum execution time: 6_000 nanoseconds. + Weight::from_ref_time(7_000_000) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) } - // 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) + // Storage: Nis Receipts (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().writes(2 as u64)) + // Minimum execution time: 14_000 nanoseconds. + Weight::from_ref_time(15_000_000) + .saturating_add(T::DbWeight::get().writes(1)) } } // For backwards compatibility and tests impl WeightInfo for () { // Storage: Nis Queues (r:1 w:1) + // Storage: Balances Reserves (r:1 w:1) // Storage: Nis QueueTotals (r:1 w:1) + /// The range of component `l` is `[0, 999]`. fn place_bid(l: u32, ) -> Weight { - // 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)) + // Minimum execution time: 47_000 nanoseconds. + Weight::from_ref_time(53_822_030) + // Standard Error: 4_869 + .saturating_add(Weight::from_ref_time(47_431).saturating_mul(l.into())) + .saturating_add(RocksDbWeight::get().reads(3)) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: Nis Queues (r:1 w:1) + // Storage: Balances Reserves (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)) + // Minimum execution time: 109_000 nanoseconds. + Weight::from_ref_time(109_000_000) + .saturating_add(RocksDbWeight::get().reads(3)) + .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: Nis Queues (r:1 w:1) // Storage: Nis QueueTotals (r:1 w:1) + // Storage: Balances Reserves (r:1 w:1) + /// The range of component `l` is `[1, 1000]`. fn retract_bid(l: u32, ) -> Weight { - // 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: 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: Nis Active (r:1 w:1) - // Storage: Nis ActiveTotal (r:1 w:1) + // Minimum execution time: 50_000 nanoseconds. + Weight::from_ref_time(54_479_879) + // Standard Error: 4_891 + .saturating_add(Weight::from_ref_time(38_224).saturating_mul(l.into())) + .saturating_add(RocksDbWeight::get().reads(3)) + .saturating_add(RocksDbWeight::get().writes(3)) + } + // Storage: Nis Summary (r:1 w:0) + // Storage: System Account (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)) + // Minimum execution time: 57_000 nanoseconds. + Weight::from_ref_time(62_000_000) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(1)) } - // 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: Nis Receipts (r:1 w:1) + // Storage: Nis Summary (r:1 w:1) + // Storage: System Account (r:1 w:0) + // Storage: Balances Reserves (r:1 w:1) + fn thaw_private() -> Weight { + // Minimum execution time: 84_000 nanoseconds. + Weight::from_ref_time(85_000_000) + .saturating_add(RocksDbWeight::get().reads(4)) + .saturating_add(RocksDbWeight::get().writes(3)) + } + // Storage: Nis Receipts (r:1 w:1) + // Storage: Nis Summary (r:1 w:1) + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Account (r:1 w:1) + // Storage: System Account (r:1 w:1) + fn thaw_communal() -> Weight { + // Minimum execution time: 108_000 nanoseconds. + Weight::from_ref_time(115_000_000) + .saturating_add(RocksDbWeight::get().reads(5)) + .saturating_add(RocksDbWeight::get().writes(5)) + } + // Storage: Nis Receipts (r:1 w:1) + // Storage: Nis Summary (r:1 w:1) + // Storage: System Account (r:1 w:1) + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Account (r:1 w:1) + // Storage: Balances Reserves (r:1 w:1) + fn privatize() -> Weight { + // Minimum execution time: 107_000 nanoseconds. + Weight::from_ref_time(110_000_000) + .saturating_add(RocksDbWeight::get().reads(6)) + .saturating_add(RocksDbWeight::get().writes(6)) } - // Storage: Nis ActiveTotal (r:1 w:1) + // Storage: Nis Receipts (r:1 w:1) + // Storage: Balances Reserves (r:1 w:1) + // Storage: System Account (r:1 w:1) + // Storage: Nis Summary (r:1 w:1) + // Storage: Assets Asset (r:1 w:1) + // Storage: Assets Account (r:1 w:1) + fn communify() -> Weight { + // Minimum execution time: 89_000 nanoseconds. + Weight::from_ref_time(89_000_000) + .saturating_add(RocksDbWeight::get().reads(6)) + .saturating_add(RocksDbWeight::get().writes(6)) + } + // Storage: Nis Summary (r:1 w:1) + // Storage: System Account (r:1 w:0) // Storage: Nis QueueTotals (r:1 w:1) + fn process_queues() -> Weight { + // Minimum execution time: 34_000 nanoseconds. + Weight::from_ref_time(38_000_000) + .saturating_add(RocksDbWeight::get().reads(3)) + .saturating_add(RocksDbWeight::get().writes(2)) + } // 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)) + // Minimum execution time: 6_000 nanoseconds. + Weight::from_ref_time(7_000_000) + .saturating_add(RocksDbWeight::get().reads(1)) + .saturating_add(RocksDbWeight::get().writes(1)) } - // 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) + // Storage: Nis Receipts (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().writes(2 as u64)) + // Minimum execution time: 14_000 nanoseconds. + Weight::from_ref_time(15_000_000) + .saturating_add(RocksDbWeight::get().writes(1)) } } diff --git a/frame/support/src/traits/tokens/fungible.rs b/frame/support/src/traits/tokens/fungible.rs index 05e109b870ec0..a36e63e717f94 100644 --- a/frame/support/src/traits/tokens/fungible.rs +++ b/frame/support/src/traits/tokens/fungible.rs @@ -78,6 +78,7 @@ pub trait Mutate: Inspect { /// returned and nothing is changed. If successful, the amount of tokens reduced is returned. fn burn_from(who: &AccountId, amount: Self::Balance) -> Result; + // TODO: Remove. /// Attempt to reduce the balance of `who` by as much as possible up to `amount`, and possibly /// slightly more due to minimum_balance requirements. If no decrease is possible then an `Err` /// is returned and nothing is changed. If successful, the amount of tokens reduced is returned. @@ -143,6 +144,7 @@ pub trait InspectHold: Inspect { fn can_hold(who: &AccountId, amount: Self::Balance) -> bool; } +// TODO: Introduce `HoldReason`. /// Trait for mutating a fungible asset which can be reserved. pub trait MutateHold: InspectHold + Transfer { /// Hold some funds in an account. @@ -160,6 +162,8 @@ pub trait MutateHold: InspectHold + Transfer { best_effort: bool, ) -> Result; + // TODO: Introduce repatriate_held + /// Transfer held funds into a destination account. /// /// If `on_hold` is `true`, then the destination account must already exist and the assets @@ -195,6 +199,7 @@ pub trait BalancedHold: Balanced + MutateHold { } impl + MutateHold> BalancedHold for T { + // TODO: This should be implemented properly, and `slash` should be removed. fn slash_held( who: &AccountId, amount: Self::Balance, From 414caffad1ce634352676d1884942282a8ec6ebb Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Tue, 17 Jan 2023 16:55:11 +0100 Subject: [PATCH 294/715] Refactory of `next_slot` method (#13155) Refactory of `next_slot` method * Prevents slot worker exit if inherent data provider creation fails * Failure is not possible anymore * Fix potential failure after warp-sync where block headers of not already downloaded blocks are used by the inherent data provider --- client/consensus/slots/src/lib.rs | 8 +--- client/consensus/slots/src/slots.rs | 59 ++++++++++++++++------------- 2 files changed, 34 insertions(+), 33 deletions(-) diff --git a/client/consensus/slots/src/lib.rs b/client/consensus/slots/src/lib.rs index 6126647e6190d..30d2c1761c712 100644 --- a/client/consensus/slots/src/lib.rs +++ b/client/consensus/slots/src/lib.rs @@ -524,13 +524,7 @@ pub async fn start_slot_worker( let mut slots = Slots::new(slot_duration.as_duration(), create_inherent_data_providers, client); loop { - let slot_info = match slots.next_slot().await { - Ok(r) => r, - Err(e) => { - warn!(target: LOG_TARGET, "Error while polling for next slot: {}", e); - return - }, - }; + let slot_info = slots.next_slot().await; if sync_oracle.is_major_syncing() { debug!(target: LOG_TARGET, "Skipping proposal slot due to sync."); diff --git a/client/consensus/slots/src/slots.rs b/client/consensus/slots/src/slots.rs index 9bb5650b313d5..7bb263b2bdba7 100644 --- a/client/consensus/slots/src/slots.rs +++ b/client/consensus/slots/src/slots.rs @@ -21,7 +21,7 @@ //! This is used instead of `futures_timer::Interval` because it was unreliable. use super::{InherentDataProviderExt, Slot, LOG_TARGET}; -use sp_consensus::{Error, SelectChain}; +use sp_consensus::SelectChain; use sp_inherents::{CreateInherentDataProviders, InherentDataProvider}; use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; @@ -90,7 +90,7 @@ impl SlotInfo { pub(crate) struct Slots { last_slot: Slot, slot_duration: Duration, - inner_delay: Option, + until_next_slot: Option, create_inherent_data_providers: IDP, select_chain: SC, _phantom: std::marker::PhantomData, @@ -106,7 +106,7 @@ impl Slots { Slots { last_slot: 0.into(), slot_duration, - inner_delay: None, + until_next_slot: None, create_inherent_data_providers, select_chain, _phantom: Default::default(), @@ -122,26 +122,22 @@ where IDP::InherentDataProviders: crate::InherentDataProviderExt, { /// Returns a future that fires when the next slot starts. - pub async fn next_slot(&mut self) -> Result, Error> { + pub async fn next_slot(&mut self) -> SlotInfo { loop { - self.inner_delay = match self.inner_delay.take() { - None => { - // schedule wait. + // Wait for slot timeout + self.until_next_slot + .take() + .unwrap_or_else(|| { + // Schedule first timeout. let wait_dur = time_until_next_slot(self.slot_duration); - Some(Delay::new(wait_dur)) - }, - Some(d) => Some(d), - }; - - if let Some(inner_delay) = self.inner_delay.take() { - inner_delay.await; - } - // timeout has fired. + Delay::new(wait_dur) + }) + .await; - let ends_in = time_until_next_slot(self.slot_duration); + // Schedule delay for next slot. + let wait_dur = time_until_next_slot(self.slot_duration); + self.until_next_slot = Some(Delay::new(wait_dur)); - // reschedule delay for next slot. - self.inner_delay = Some(Delay::new(ends_in)); let chain_head = match self.select_chain.best_chain().await { Ok(x) => x, Err(e) => { @@ -150,30 +146,41 @@ where "Unable to author block in slot. No best block header: {}", e, ); - // Let's try at the next slot.. - self.inner_delay.take(); + // Let's retry at the next slot. continue }, }; - let inherent_data_providers = self + let inherent_data_providers = match self .create_inherent_data_providers .create_inherent_data_providers(chain_head.hash(), ()) - .await?; + .await + { + Ok(x) => x, + Err(e) => { + log::warn!( + target: LOG_TARGET, + "Unable to author block in slot. Failure creating inherent data provider: {}", + e, + ); + // Let's retry at the next slot. + continue + }, + }; let slot = inherent_data_providers.slot(); - // never yield the same slot twice. + // Never yield the same slot twice. if slot > self.last_slot { self.last_slot = slot; - break Ok(SlotInfo::new( + break SlotInfo::new( slot, Box::new(inherent_data_providers), self.slot_duration, chain_head, None, - )) + ) } } } From f7e53fe1a8c0e15604cc30177c312241624831bf Mon Sep 17 00:00:00 2001 From: Squirrel Date: Tue, 17 Jan 2023 16:26:10 +0000 Subject: [PATCH 295/715] Breakout mock runtimes to separate files (#13150) * break out moch runtimes to separate files * tranaction-payment: break out tests & mock runtime to separate files --- .../asset-tx-payment/src/lib.rs | 2 + .../asset-tx-payment/src/mock.rs | 213 ++++ .../asset-tx-payment/src/tests.rs | 197 +--- frame/transaction-payment/src/lib.rs | 961 +----------------- frame/transaction-payment/src/mock.rs | 162 +++ frame/transaction-payment/src/tests.rs | 836 +++++++++++++++ 6 files changed, 1223 insertions(+), 1148 deletions(-) create mode 100644 frame/transaction-payment/asset-tx-payment/src/mock.rs create mode 100644 frame/transaction-payment/src/mock.rs create mode 100644 frame/transaction-payment/src/tests.rs diff --git a/frame/transaction-payment/asset-tx-payment/src/lib.rs b/frame/transaction-payment/asset-tx-payment/src/lib.rs index 43cc1efa0858e..230b307317f8b 100644 --- a/frame/transaction-payment/asset-tx-payment/src/lib.rs +++ b/frame/transaction-payment/asset-tx-payment/src/lib.rs @@ -59,6 +59,8 @@ use sp_runtime::{ FixedPointOperand, }; +#[cfg(test)] +mod mock; #[cfg(test)] mod tests; diff --git a/frame/transaction-payment/asset-tx-payment/src/mock.rs b/frame/transaction-payment/asset-tx-payment/src/mock.rs new file mode 100644 index 0000000000000..ddb02f5a611ff --- /dev/null +++ b/frame/transaction-payment/asset-tx-payment/src/mock.rs @@ -0,0 +1,213 @@ +// 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. + +use super::*; +use crate as pallet_asset_tx_payment; + +use codec; +use frame_support::{ + dispatch::DispatchClass, + pallet_prelude::*, + parameter_types, + traits::{AsEnsureOriginWithArg, ConstU32, ConstU64, ConstU8, FindAuthor}, + weights::{Weight, WeightToFee as WeightToFeeT}, + ConsensusEngineId, +}; +use frame_system as system; +use frame_system::EnsureRoot; +use pallet_transaction_payment::CurrencyAdapter; +use sp_core::H256; +use sp_runtime::{ + testing::Header, + traits::{BlakeTwo256, ConvertInto, IdentityLookup, SaturatedConversion}, +}; + +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, Event}, + Assets: pallet_assets::{Pallet, Call, Storage, Event}, + Authorship: pallet_authorship::{Pallet, Call, Storage}, + AssetTxPayment: pallet_asset_tx_payment::{Pallet, Event}, + } +); + +parameter_types! { + pub(crate) static ExtrinsicBaseWeight: Weight = Weight::zero(); +} + +pub struct BlockWeights; +impl Get for BlockWeights { + fn get() -> frame_system::limits::BlockWeights { + frame_system::limits::BlockWeights::builder() + .base_block(Weight::zero()) + .for_class(DispatchClass::all(), |weights| { + weights.base_extrinsic = ExtrinsicBaseWeight::get().into(); + }) + .for_class(DispatchClass::non_mandatory(), |weights| { + weights.max_total = Weight::from_ref_time(1024).set_proof_size(u64::MAX).into(); + }) + .build_or_panic() + } +} + +parameter_types! { + pub static WeightToFee: u64 = 1; + pub static TransactionByteFee: u64 = 1; +} + +impl frame_system::Config for Runtime { + type BaseCallFilter = frame_support::traits::Everything; + type BlockWeights = BlockWeights; + type BlockLength = (); + type DbWeight = (); + type RuntimeOrigin = RuntimeOrigin; + type Index = u64; + type BlockNumber = u64; + type RuntimeCall = RuntimeCall; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type Header = Header; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = ConstU64<250>; + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = ConstU32<16>; +} + +parameter_types! { + pub const ExistentialDeposit: u64 = 10; +} + +impl pallet_balances::Config for Runtime { + type Balance = Balance; + type RuntimeEvent = RuntimeEvent; + type DustRemoval = (); + type ExistentialDeposit = ConstU64<10>; + type AccountStore = System; + type MaxLocks = (); + type WeightInfo = (); + type MaxReserves = ConstU32<50>; + type ReserveIdentifier = [u8; 8]; +} + +impl WeightToFeeT for WeightToFee { + type Balance = u64; + + fn weight_to_fee(weight: &Weight) -> Self::Balance { + Self::Balance::saturated_from(weight.ref_time()) + .saturating_mul(WEIGHT_TO_FEE.with(|v| *v.borrow())) + } +} + +impl WeightToFeeT for TransactionByteFee { + type Balance = u64; + + fn weight_to_fee(weight: &Weight) -> Self::Balance { + Self::Balance::saturated_from(weight.ref_time()) + .saturating_mul(TRANSACTION_BYTE_FEE.with(|v| *v.borrow())) + } +} + +impl pallet_transaction_payment::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type OnChargeTransaction = CurrencyAdapter; + type WeightToFee = WeightToFee; + type LengthToFee = TransactionByteFee; + type FeeMultiplierUpdate = (); + type OperationalFeeMultiplier = ConstU8<5>; +} + +type AssetId = u32; + +impl pallet_assets::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type AssetId = AssetId; + type AssetIdParameter = codec::Compact; + type Currency = Balances; + type CreateOrigin = AsEnsureOriginWithArg>; + type ForceOrigin = EnsureRoot; + 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 CallbackHandle = (); + type WeightInfo = (); + type RemoveItemsLimit = ConstU32<1000>; + pallet_assets::runtime_benchmarks_enabled! { + type BenchmarkHelper = (); + } +} + +pub struct HardcodedAuthor; +pub(crate) 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) { + 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); + } + } +} + +impl Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Fungibles = Assets; + type OnChargeAssetTransaction = FungiblesAdapter< + pallet_assets::BalanceToAssetBalance, + CreditToBlockAuthor, + >; +} diff --git a/frame/transaction-payment/asset-tx-payment/src/tests.rs b/frame/transaction-payment/asset-tx-payment/src/tests.rs index b79b87a93c7a4..f76293f456497 100644 --- a/frame/transaction-payment/asset-tx-payment/src/tests.rs +++ b/frame/transaction-payment/asset-tx-payment/src/tests.rs @@ -14,209 +14,22 @@ // limitations under the License. use super::*; -use crate as pallet_asset_tx_payment; -use codec; use frame_support::{ assert_ok, - dispatch::{DispatchClass, DispatchInfo, PostDispatchInfo}, + dispatch::{DispatchInfo, PostDispatchInfo}, pallet_prelude::*, - parameter_types, - traits::{fungibles::Mutate, AsEnsureOriginWithArg, ConstU32, ConstU64, ConstU8, FindAuthor}, - weights::{Weight, WeightToFee as WeightToFeeT}, - ConsensusEngineId, + traits::fungibles::Mutate, + weights::Weight, }; use frame_system as system; -use frame_system::EnsureRoot; +use mock::{ExtrinsicBaseWeight, *}; use pallet_balances::Call as BalancesCall; -use pallet_transaction_payment::CurrencyAdapter; -use sp_core::H256; -use sp_runtime::{ - testing::Header, - traits::{BlakeTwo256, ConvertInto, IdentityLookup, SaturatedConversion, StaticLookup}, -}; - -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, Event}, - Assets: pallet_assets::{Pallet, Call, Storage, Event}, - Authorship: pallet_authorship::{Pallet, Call, Storage}, - AssetTxPayment: pallet_asset_tx_payment::{Pallet, Event}, - } -); +use sp_runtime::traits::StaticLookup; const CALL: &::RuntimeCall = &RuntimeCall::Balances(BalancesCall::transfer { dest: 2, value: 69 }); -parameter_types! { - static ExtrinsicBaseWeight: Weight = Weight::zero(); -} - -pub struct BlockWeights; -impl Get for BlockWeights { - fn get() -> frame_system::limits::BlockWeights { - frame_system::limits::BlockWeights::builder() - .base_block(Weight::zero()) - .for_class(DispatchClass::all(), |weights| { - weights.base_extrinsic = ExtrinsicBaseWeight::get().into(); - }) - .for_class(DispatchClass::non_mandatory(), |weights| { - weights.max_total = Weight::from_ref_time(1024).set_proof_size(u64::MAX).into(); - }) - .build_or_panic() - } -} - -parameter_types! { - pub static WeightToFee: u64 = 1; - pub static TransactionByteFee: u64 = 1; -} - -impl frame_system::Config for Runtime { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = BlockWeights; - type BlockLength = (); - type DbWeight = (); - type RuntimeOrigin = RuntimeOrigin; - type Index = u64; - type BlockNumber = u64; - type RuntimeCall = RuntimeCall; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = AccountId; - type Lookup = IdentityLookup; - type Header = Header; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = ConstU32<16>; -} - -parameter_types! { - pub const ExistentialDeposit: u64 = 10; -} - -impl pallet_balances::Config for Runtime { - type Balance = Balance; - type RuntimeEvent = RuntimeEvent; - type DustRemoval = (); - type ExistentialDeposit = ConstU64<10>; - type AccountStore = System; - type MaxLocks = (); - type WeightInfo = (); - type MaxReserves = ConstU32<50>; - type ReserveIdentifier = [u8; 8]; -} - -impl WeightToFeeT for WeightToFee { - type Balance = u64; - - fn weight_to_fee(weight: &Weight) -> Self::Balance { - Self::Balance::saturated_from(weight.ref_time()) - .saturating_mul(WEIGHT_TO_FEE.with(|v| *v.borrow())) - } -} - -impl WeightToFeeT for TransactionByteFee { - type Balance = u64; - - fn weight_to_fee(weight: &Weight) -> Self::Balance { - Self::Balance::saturated_from(weight.ref_time()) - .saturating_mul(TRANSACTION_BYTE_FEE.with(|v| *v.borrow())) - } -} - -impl pallet_transaction_payment::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type OnChargeTransaction = CurrencyAdapter; - type WeightToFee = WeightToFee; - type LengthToFee = TransactionByteFee; - type FeeMultiplierUpdate = (); - type OperationalFeeMultiplier = ConstU8<5>; -} - -type AssetId = u32; - -impl pallet_assets::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Balance = Balance; - type AssetId = AssetId; - type AssetIdParameter = codec::Compact; - type Currency = Balances; - type CreateOrigin = AsEnsureOriginWithArg>; - type ForceOrigin = EnsureRoot; - 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 CallbackHandle = (); - type WeightInfo = (); - type RemoveItemsLimit = ConstU32<1000>; - pallet_assets::runtime_benchmarks_enabled! { - type BenchmarkHelper = (); - } -} - -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) { - 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); - } - } -} - -impl Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Fungibles = Assets; - type OnChargeAssetTransaction = FungiblesAdapter< - pallet_assets::BalanceToAssetBalance, - CreditToBlockAuthor, - >; -} - pub struct ExtBuilder { balance_factor: u64, base_weight: Weight, diff --git a/frame/transaction-payment/src/lib.rs b/frame/transaction-payment/src/lib.rs index ce747fa6bd85c..13adbf89c4270 100644 --- a/frame/transaction-payment/src/lib.rs +++ b/frame/transaction-payment/src/lib.rs @@ -70,6 +70,11 @@ use frame_support::{ weights::{Weight, WeightToFee}, }; +#[cfg(test)] +mod mock; +#[cfg(test)] +mod tests; + mod payment; mod types; @@ -847,959 +852,3 @@ where Self::compute_actual_fee(len, &info, &post_info, Zero::zero()) } } - -#[cfg(test)] -mod tests { - use super::*; - use crate as pallet_transaction_payment; - - use codec::Encode; - - use sp_core::H256; - use sp_runtime::{ - testing::{Header, TestXt}, - traits::{BlakeTwo256, IdentityLookup, One}, - transaction_validity::InvalidTransaction, - }; - - use frame_support::{ - assert_noop, assert_ok, - dispatch::{DispatchClass, DispatchInfo, GetDispatchInfo, PostDispatchInfo}, - parameter_types, - traits::{ConstU32, ConstU64, Currency, GenesisBuild, Imbalance, OnUnbalanced}, - weights::{Weight, WeightToFee as WeightToFeeT}, - }; - use frame_system as system; - use pallet_balances::Call as BalancesCall; - - 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: system::{Pallet, Call, Config, Storage, Event}, - Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, - TransactionPayment: pallet_transaction_payment::{Pallet, Storage, Event}, - } - ); - - const CALL: &::RuntimeCall = - &RuntimeCall::Balances(BalancesCall::transfer { dest: 2, value: 69 }); - - parameter_types! { - static ExtrinsicBaseWeight: Weight = Weight::zero(); - } - - pub struct BlockWeights; - impl Get for BlockWeights { - fn get() -> frame_system::limits::BlockWeights { - frame_system::limits::BlockWeights::builder() - .base_block(Weight::zero()) - .for_class(DispatchClass::all(), |weights| { - weights.base_extrinsic = ExtrinsicBaseWeight::get().into(); - }) - .for_class(DispatchClass::non_mandatory(), |weights| { - weights.max_total = Weight::from_ref_time(1024).set_proof_size(u64::MAX).into(); - }) - .build_or_panic() - } - } - - parameter_types! { - pub static WeightToFee: u64 = 1; - pub static TransactionByteFee: u64 = 1; - pub static OperationalFeeMultiplier: u8 = 5; - } - - impl frame_system::Config for Runtime { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = BlockWeights; - type BlockLength = (); - type DbWeight = (); - type RuntimeOrigin = RuntimeOrigin; - type Index = u64; - type BlockNumber = u64; - type RuntimeCall = RuntimeCall; - type Hash = H256; - 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 Runtime { - type Balance = u64; - type RuntimeEvent = RuntimeEvent; - type DustRemoval = (); - type ExistentialDeposit = ConstU64<1>; - type AccountStore = System; - type MaxLocks = (); - type MaxReserves = (); - type ReserveIdentifier = [u8; 8]; - type WeightInfo = (); - } - - impl WeightToFeeT for WeightToFee { - type Balance = u64; - - fn weight_to_fee(weight: &Weight) -> Self::Balance { - Self::Balance::saturated_from(weight.ref_time()) - .saturating_mul(WEIGHT_TO_FEE.with(|v| *v.borrow())) - } - } - - impl WeightToFeeT for TransactionByteFee { - type Balance = u64; - - fn weight_to_fee(weight: &Weight) -> Self::Balance { - Self::Balance::saturated_from(weight.ref_time()) - .saturating_mul(TRANSACTION_BYTE_FEE.with(|v| *v.borrow())) - } - } - - parameter_types! { - static TipUnbalancedAmount: u64 = 0; - static FeeUnbalancedAmount: u64 = 0; - } - - pub struct DealWithFees; - impl OnUnbalanced> for DealWithFees { - fn on_unbalanceds( - mut fees_then_tips: impl Iterator>, - ) { - if let Some(fees) = fees_then_tips.next() { - FeeUnbalancedAmount::mutate(|a| *a += fees.peek()); - if let Some(tips) = fees_then_tips.next() { - TipUnbalancedAmount::mutate(|a| *a += tips.peek()); - } - } - } - } - - impl Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type OnChargeTransaction = CurrencyAdapter; - type OperationalFeeMultiplier = OperationalFeeMultiplier; - type WeightToFee = WeightToFee; - type LengthToFee = TransactionByteFee; - type FeeMultiplierUpdate = (); - } - - pub struct ExtBuilder { - balance_factor: u64, - 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, - initial_multiplier: None, - } - } - } - - impl ExtBuilder { - pub fn base_weight(mut self, base_weight: Weight) -> Self { - self.base_weight = base_weight; - self - } - pub fn byte_fee(mut self, byte_fee: u64) -> Self { - self.byte_fee = byte_fee; - self - } - pub fn weight_fee(mut self, weight_to_fee: u64) -> Self { - self.weight_to_fee = weight_to_fee; - self - } - pub fn balance_factor(mut self, factor: u64) -> Self { - 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) { - 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); - } - 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(); - - if let Some(multiplier) = self.initial_multiplier { - let genesis = pallet::GenesisConfig { multiplier }; - GenesisBuild::::assimilate_storage(&genesis, &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 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 signed_extension_transaction_payment_work() { - ExtBuilder::default() - .balance_factor(10) - .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(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(Weight::from_ref_time(5)), - &default_post_info(), - len, - &Ok(()) - )); - assert_eq!(Balances::free_balance(1), 100 - 5 - 5 - 10); - assert_eq!(FeeUnbalancedAmount::get(), 5 + 5 + 10); - assert_eq!(TipUnbalancedAmount::get(), 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) - .unwrap(); - assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 100 - 5); - - assert_ok!(ChargeTransactionPayment::::post_dispatch( - Some(pre), - &info_from_weight(Weight::from_ref_time(100)), - &post_info_from_weight(Weight::from_ref_time(50)), - len, - &Ok(()) - )); - assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 50 - 5); - assert_eq!(FeeUnbalancedAmount::get(), 5 + 10 + 50); - assert_eq!(TipUnbalancedAmount::get(), 5); - }); - } - - #[test] - fn signed_extension_transaction_payment_multiplied_refund_works() { - ExtBuilder::default() - .balance_factor(10) - .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(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(Weight::from_ref_time(100)), - &post_info_from_weight(Weight::from_ref_time(50)), - len, - &Ok(()) - )); - // 75 (3/2 of the returned 50 units of weight) is refunded - assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 75 - 5); - }); - } - - #[test] - fn signed_extension_transaction_payment_is_bounded() { - ExtBuilder::default().balance_factor(1000).byte_fee(0).build().execute_with(|| { - // maximum weight possible - assert_ok!(ChargeTransactionPayment::::from(0).pre_dispatch( - &1, - CALL, - &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.ref_time()) as u64 - ); - }); - } - - #[test] - fn signed_extension_allows_free_transactions() { - ExtBuilder::default() - .base_weight(Weight::from_ref_time(100)) - .balance_factor(0) - .build() - .execute_with(|| { - // 1 ain't have a penny. - assert_eq!(Balances::free_balance(1), 0); - - let len = 100; - - // This is a completely free (and thus wholly insecure/DoS-ridden) transaction. - let operational_transaction = DispatchInfo { - weight: Weight::from_ref_time(0), - class: DispatchClass::Operational, - pays_fee: Pays::No, - }; - assert_ok!(ChargeTransactionPayment::::from(0).validate( - &1, - CALL, - &operational_transaction, - len - )); - - // like a InsecureFreeNormal - let free_transaction = DispatchInfo { - weight: Weight::from_ref_time(0), - class: DispatchClass::Normal, - pays_fee: Pays::Yes, - }; - assert_noop!( - ChargeTransactionPayment::::from(0).validate( - &1, - CALL, - &free_transaction, - len - ), - TransactionValidityError::Invalid(InvalidTransaction::Payment), - ); - }); - } - - #[test] - fn signed_ext_length_fee_is_also_updated_per_congestion() { - ExtBuilder::default() - .base_weight(Weight::from_ref_time(5)) - .balance_factor(10) - .build() - .execute_with(|| { - // all fees should be x1.5 - >::put(Multiplier::saturating_from_rational(3, 2)); - let len = 10; - - 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 - - 10 // tip - - 5 // base - - 10 // len - - (3 * 3 / 2) // adjusted weight - ); - }) - } - - #[test] - fn query_info_and_fee_details_works() { - let call = RuntimeCall::Balances(BalancesCall::transfer { dest: 2, value: 69 }); - let origin = 111111; - let 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(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 */ - + len as u64 /* len * 1 */ - + 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_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 }, - ); - }); - } - - #[test] - fn query_call_info_and_fee_details_works() { - 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; - - 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 */ - + len as u64 /* len * 1 */ - + 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) - .ref_time() as u64 * 2 * 3 / 2 /* weight * weight_fee * multipler */ - }), - tip: 0, - }, - ); - }); - } - - #[test] - fn compute_fee_works_without_multiplier() { - ExtBuilder::default() - .base_weight(Weight::from_ref_time(100)) - .byte_fee(10) - .balance_factor(0) - .build() - .execute_with(|| { - // Next fee multiplier is zero - assert_eq!(>::get(), Multiplier::one()); - - // Tip only, no fees works - let dispatch_info = DispatchInfo { - 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: Weight::from_ref_time(0), - class: DispatchClass::Operational, - pays_fee: Pays::Yes, - }; - assert_eq!(Pallet::::compute_fee(0, &dispatch_info, 0), 100); - // Tip + base fee works - assert_eq!(Pallet::::compute_fee(0, &dispatch_info, 69), 169); - // Len (byte fee) + base fee works - assert_eq!(Pallet::::compute_fee(42, &dispatch_info, 0), 520); - // Weight fee + base fee works - let dispatch_info = DispatchInfo { - weight: Weight::from_ref_time(1000), - class: DispatchClass::Operational, - pays_fee: Pays::Yes, - }; - assert_eq!(Pallet::::compute_fee(0, &dispatch_info, 0), 1100); - }); - } - - #[test] - fn compute_fee_works_with_multiplier() { - ExtBuilder::default() - .base_weight(Weight::from_ref_time(100)) - .byte_fee(10) - .balance_factor(0) - .build() - .execute_with(|| { - // Add a next fee multiplier. Fees will be x3/2. - >::put(Multiplier::saturating_from_rational(3, 2)); - // Base fee is unaffected by multiplier - let dispatch_info = DispatchInfo { - weight: Weight::from_ref_time(0), - class: DispatchClass::Operational, - pays_fee: Pays::Yes, - }; - assert_eq!(Pallet::::compute_fee(0, &dispatch_info, 0), 100); - - // Everything works together :) - let dispatch_info = DispatchInfo { - weight: Weight::from_ref_time(123), - class: DispatchClass::Operational, - pays_fee: Pays::Yes, - }; - // 123 weight, 456 length, 100 base - assert_eq!( - Pallet::::compute_fee(456, &dispatch_info, 789), - 100 + (3 * 123 / 2) + 4560 + 789, - ); - }); - } - - #[test] - fn compute_fee_works_with_negative_multiplier() { - ExtBuilder::default() - .base_weight(Weight::from_ref_time(100)) - .byte_fee(10) - .balance_factor(0) - .build() - .execute_with(|| { - // Add a next fee multiplier. All fees will be x1/2. - >::put(Multiplier::saturating_from_rational(1, 2)); - - // Base fee is unaffected by multiplier. - let dispatch_info = DispatchInfo { - weight: Weight::from_ref_time(0), - class: DispatchClass::Operational, - pays_fee: Pays::Yes, - }; - assert_eq!(Pallet::::compute_fee(0, &dispatch_info, 0), 100); - - // Everything works together. - let dispatch_info = DispatchInfo { - weight: Weight::from_ref_time(123), - class: DispatchClass::Operational, - pays_fee: Pays::Yes, - }; - // 123 weight, 456 length, 100 base - assert_eq!( - Pallet::::compute_fee(456, &dispatch_info, 789), - 100 + (123 / 2) + 4560 + 789, - ); - }); - } - - #[test] - fn compute_fee_does_not_overflow() { - ExtBuilder::default() - .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, - class: DispatchClass::Operational, - pays_fee: Pays::Yes, - }; - assert_eq!( - Pallet::::compute_fee(u32::MAX, &dispatch_info, u64::MAX), - u64::MAX - ); - }); - } - - #[test] - fn refund_does_not_recreate_account() { - ExtBuilder::default() - .balance_factor(10) - .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(Weight::from_ref_time(100)), len) - .unwrap(); - assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 100 - 5); - - // kill the account between pre and post dispatch - assert_ok!(Balances::transfer(Some(2).into(), 3, Balances::free_balance(2))); - assert_eq!(Balances::free_balance(2), 0); - - assert_ok!(ChargeTransactionPayment::::post_dispatch( - Some(pre), - &info_from_weight(Weight::from_ref_time(100)), - &post_info_from_weight(Weight::from_ref_time(50)), - len, - &Ok(()) - )); - assert_eq!(Balances::free_balance(2), 0); - // Transfer Event - System::assert_has_event(RuntimeEvent::Balances( - pallet_balances::Event::Transfer { from: 2, to: 3, amount: 80 }, - )); - // Killed Event - System::assert_has_event(RuntimeEvent::System(system::Event::KilledAccount { - account: 2, - })); - }); - } - - #[test] - fn actual_weight_higher_than_max_refunds_nothing() { - ExtBuilder::default() - .balance_factor(10) - .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(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(Weight::from_ref_time(100)), - &post_info_from_weight(Weight::from_ref_time(101)), - len, - &Ok(()) - )); - assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 100 - 5); - }); - } - - #[test] - fn zero_transfer_on_free_transaction() { - ExtBuilder::default() - .balance_factor(10) - .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: 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) - .unwrap(); - assert_eq!(Balances::total_balance(&user), 0); - assert_ok!(ChargeTransactionPayment::::post_dispatch( - Some(pre), - &dispatch_info, - &default_post_info(), - len, - &Ok(()) - )); - assert_eq!(Balances::total_balance(&user), 0); - // TransactionFeePaid Event - System::assert_has_event(RuntimeEvent::TransactionPayment( - pallet_transaction_payment::Event::TransactionFeePaid { - who: user, - actual_fee: 0, - tip: 0, - }, - )); - }); - } - - #[test] - fn refund_consistent_with_actual_weight() { - ExtBuilder::default() - .balance_factor(10) - .base_weight(Weight::from_ref_time(7)) - .build() - .execute_with(|| { - 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; - - >::put(Multiplier::saturating_from_rational(5, 4)); - - let pre = ChargeTransactionPayment::::from(tip) - .pre_dispatch(&2, CALL, &info, len) - .unwrap(); - - ChargeTransactionPayment::::post_dispatch( - Some(pre), - &info, - &post_info, - len, - &Ok(()), - ) - .unwrap(); - - let refund_based_fee = prev_balance - Balances::free_balance(2); - let actual_fee = - Pallet::::compute_actual_fee(len as u32, &info, &post_info, tip); - - // 33 weight, 10 length, 7 base, 5 tip - assert_eq!(actual_fee, 7 + 10 + (33 * 5 / 4) + 5); - assert_eq!(refund_based_fee, actual_fee); - }); - } - - #[test] - fn should_alter_operational_priority() { - let tip = 5; - let len = 10; - - ExtBuilder::default().balance_factor(100).build().execute_with(|| { - 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() - .priority; - - assert_eq!(priority, 60); - - let priority = ChargeTransactionPayment::(2 * tip) - .validate(&2, CALL, &normal, len) - .unwrap() - .priority; - - assert_eq!(priority, 110); - }); - - ExtBuilder::default().balance_factor(100).build().execute_with(|| { - let op = DispatchInfo { - weight: Weight::from_ref_time(100), - class: DispatchClass::Operational, - pays_fee: Pays::Yes, - }; - let priority = ChargeTransactionPayment::(tip) - .validate(&2, CALL, &op, len) - .unwrap() - .priority; - assert_eq!(priority, 5810); - - let priority = ChargeTransactionPayment::(2 * tip) - .validate(&2, CALL, &op, len) - .unwrap() - .priority; - assert_eq!(priority, 6110); - }); - } - - #[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: Weight::from_ref_time(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: Weight::from_ref_time(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 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: Weight::from_ref_time(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: Weight::from_ref_time(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() - .balance_factor(10) - .base_weight(Weight::from_ref_time(7)) - .build() - .execute_with(|| { - 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; - let tip = 5; - - >::put(Multiplier::saturating_from_rational(5, 4)); - - let pre = ChargeTransactionPayment::::from(tip) - .pre_dispatch(&2, CALL, &info, len) - .unwrap(); - - ChargeTransactionPayment::::post_dispatch( - Some(pre), - &info, - &post_info, - len, - &Ok(()), - ) - .unwrap(); - - let refund_based_fee = prev_balance - Balances::free_balance(2); - let actual_fee = - Pallet::::compute_actual_fee(len as u32, &info, &post_info, tip); - - // Only 5 tip is paid - assert_eq!(actual_fee, 5); - 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)); - }); - } -} diff --git a/frame/transaction-payment/src/mock.rs b/frame/transaction-payment/src/mock.rs new file mode 100644 index 0000000000000..e214458b3766e --- /dev/null +++ b/frame/transaction-payment/src/mock.rs @@ -0,0 +1,162 @@ +// 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 super::*; +use crate as pallet_transaction_payment; + +use sp_core::H256; +use sp_runtime::{ + testing::Header, + traits::{BlakeTwo256, IdentityLookup}, +}; + +use frame_support::{ + dispatch::DispatchClass, + parameter_types, + traits::{ConstU32, ConstU64, Imbalance, OnUnbalanced}, + weights::{Weight, WeightToFee as WeightToFeeT}, +}; +use frame_system as system; +use pallet_balances::Call as BalancesCall; + +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: system::{Pallet, Call, Config, Storage, Event}, + Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, + TransactionPayment: pallet_transaction_payment::{Pallet, Storage, Event}, + } +); + +pub(crate) const CALL: &::RuntimeCall = + &RuntimeCall::Balances(BalancesCall::transfer { dest: 2, value: 69 }); + +parameter_types! { + pub(crate) static ExtrinsicBaseWeight: Weight = Weight::zero(); +} + +pub struct BlockWeights; +impl Get for BlockWeights { + fn get() -> frame_system::limits::BlockWeights { + frame_system::limits::BlockWeights::builder() + .base_block(Weight::zero()) + .for_class(DispatchClass::all(), |weights| { + weights.base_extrinsic = ExtrinsicBaseWeight::get().into(); + }) + .for_class(DispatchClass::non_mandatory(), |weights| { + weights.max_total = Weight::from_ref_time(1024).set_proof_size(u64::MAX).into(); + }) + .build_or_panic() + } +} + +parameter_types! { + pub static WeightToFee: u64 = 1; + pub static TransactionByteFee: u64 = 1; + pub static OperationalFeeMultiplier: u8 = 5; +} + +impl frame_system::Config for Runtime { + type BaseCallFilter = frame_support::traits::Everything; + type BlockWeights = BlockWeights; + type BlockLength = (); + type DbWeight = (); + type RuntimeOrigin = RuntimeOrigin; + type Index = u64; + type BlockNumber = u64; + type RuntimeCall = RuntimeCall; + type Hash = H256; + 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 Runtime { + type Balance = u64; + type RuntimeEvent = RuntimeEvent; + type DustRemoval = (); + type ExistentialDeposit = ConstU64<1>; + type AccountStore = System; + type MaxLocks = (); + type MaxReserves = (); + type ReserveIdentifier = [u8; 8]; + type WeightInfo = (); +} + +impl WeightToFeeT for WeightToFee { + type Balance = u64; + + fn weight_to_fee(weight: &Weight) -> Self::Balance { + Self::Balance::saturated_from(weight.ref_time()) + .saturating_mul(WEIGHT_TO_FEE.with(|v| *v.borrow())) + } +} + +impl WeightToFeeT for TransactionByteFee { + type Balance = u64; + + fn weight_to_fee(weight: &Weight) -> Self::Balance { + Self::Balance::saturated_from(weight.ref_time()) + .saturating_mul(TRANSACTION_BYTE_FEE.with(|v| *v.borrow())) + } +} + +parameter_types! { + pub(crate) static TipUnbalancedAmount: u64 = 0; + pub(crate) static FeeUnbalancedAmount: u64 = 0; +} + +pub struct DealWithFees; +impl OnUnbalanced> for DealWithFees { + fn on_unbalanceds( + mut fees_then_tips: impl Iterator>, + ) { + if let Some(fees) = fees_then_tips.next() { + FeeUnbalancedAmount::mutate(|a| *a += fees.peek()); + if let Some(tips) = fees_then_tips.next() { + TipUnbalancedAmount::mutate(|a| *a += tips.peek()); + } + } + } +} + +impl Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type OnChargeTransaction = CurrencyAdapter; + type OperationalFeeMultiplier = OperationalFeeMultiplier; + type WeightToFee = WeightToFee; + type LengthToFee = TransactionByteFee; + type FeeMultiplierUpdate = (); +} diff --git a/frame/transaction-payment/src/tests.rs b/frame/transaction-payment/src/tests.rs new file mode 100644 index 0000000000000..ee54c1130e699 --- /dev/null +++ b/frame/transaction-payment/src/tests.rs @@ -0,0 +1,836 @@ +// 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 super::*; +use crate as pallet_transaction_payment; + +use codec::Encode; + +use sp_runtime::{testing::TestXt, traits::One, transaction_validity::InvalidTransaction}; + +use frame_support::{ + assert_noop, assert_ok, + dispatch::{DispatchClass, DispatchInfo, GetDispatchInfo, PostDispatchInfo}, + traits::{Currency, GenesisBuild}, + weights::Weight, +}; +use frame_system as system; +use mock::*; +use pallet_balances::Call as BalancesCall; + +pub struct ExtBuilder { + balance_factor: u64, + 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, + initial_multiplier: None, + } + } +} + +impl ExtBuilder { + pub fn base_weight(mut self, base_weight: Weight) -> Self { + self.base_weight = base_weight; + self + } + pub fn byte_fee(mut self, byte_fee: u64) -> Self { + self.byte_fee = byte_fee; + self + } + pub fn weight_fee(mut self, weight_to_fee: u64) -> Self { + self.weight_to_fee = weight_to_fee; + self + } + pub fn balance_factor(mut self, factor: u64) -> Self { + 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) { + 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); + } + 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(); + + if let Some(multiplier) = self.initial_multiplier { + let genesis = pallet::GenesisConfig { multiplier }; + GenesisBuild::::assimilate_storage(&genesis, &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 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 signed_extension_transaction_payment_work() { + ExtBuilder::default() + .balance_factor(10) + .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(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(Weight::from_ref_time(5)), + &default_post_info(), + len, + &Ok(()) + )); + assert_eq!(Balances::free_balance(1), 100 - 5 - 5 - 10); + assert_eq!(FeeUnbalancedAmount::get(), 5 + 5 + 10); + assert_eq!(TipUnbalancedAmount::get(), 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) + .unwrap(); + assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 100 - 5); + + assert_ok!(ChargeTransactionPayment::::post_dispatch( + Some(pre), + &info_from_weight(Weight::from_ref_time(100)), + &post_info_from_weight(Weight::from_ref_time(50)), + len, + &Ok(()) + )); + assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 50 - 5); + assert_eq!(FeeUnbalancedAmount::get(), 5 + 10 + 50); + assert_eq!(TipUnbalancedAmount::get(), 5); + }); +} + +#[test] +fn signed_extension_transaction_payment_multiplied_refund_works() { + ExtBuilder::default() + .balance_factor(10) + .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(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(Weight::from_ref_time(100)), + &post_info_from_weight(Weight::from_ref_time(50)), + len, + &Ok(()) + )); + // 75 (3/2 of the returned 50 units of weight) is refunded + assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 75 - 5); + }); +} + +#[test] +fn signed_extension_transaction_payment_is_bounded() { + ExtBuilder::default().balance_factor(1000).byte_fee(0).build().execute_with(|| { + // maximum weight possible + assert_ok!(ChargeTransactionPayment::::from(0).pre_dispatch( + &1, + CALL, + &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.ref_time()) + as u64 + ); + }); +} + +#[test] +fn signed_extension_allows_free_transactions() { + ExtBuilder::default() + .base_weight(Weight::from_ref_time(100)) + .balance_factor(0) + .build() + .execute_with(|| { + // 1 ain't have a penny. + assert_eq!(Balances::free_balance(1), 0); + + let len = 100; + + // This is a completely free (and thus wholly insecure/DoS-ridden) transaction. + let operational_transaction = DispatchInfo { + weight: Weight::from_ref_time(0), + class: DispatchClass::Operational, + pays_fee: Pays::No, + }; + assert_ok!(ChargeTransactionPayment::::from(0).validate( + &1, + CALL, + &operational_transaction, + len + )); + + // like a InsecureFreeNormal + let free_transaction = DispatchInfo { + weight: Weight::from_ref_time(0), + class: DispatchClass::Normal, + pays_fee: Pays::Yes, + }; + assert_noop!( + ChargeTransactionPayment::::from(0).validate( + &1, + CALL, + &free_transaction, + len + ), + TransactionValidityError::Invalid(InvalidTransaction::Payment), + ); + }); +} + +#[test] +fn signed_ext_length_fee_is_also_updated_per_congestion() { + ExtBuilder::default() + .base_weight(Weight::from_ref_time(5)) + .balance_factor(10) + .build() + .execute_with(|| { + // all fees should be x1.5 + >::put(Multiplier::saturating_from_rational(3, 2)); + let len = 10; + + 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 + - 10 // tip + - 5 // base + - 10 // len + - (3 * 3 / 2) // adjusted weight + ); + }) +} + +#[test] +fn query_info_and_fee_details_works() { + let call = RuntimeCall::Balances(BalancesCall::transfer { dest: 2, value: 69 }); + let origin = 111111; + let 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(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 */ + + len as u64 /* len * 1 */ + + 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_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 }, + ); + }); +} + +#[test] +fn query_call_info_and_fee_details_works() { + 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; + + 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 */ + + len as u64 /* len * 1 */ + + 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) + .ref_time() as u64 * 2 * 3 / 2 /* weight * weight_fee * multipler */ + }), + tip: 0, + }, + ); + }); +} + +#[test] +fn compute_fee_works_without_multiplier() { + ExtBuilder::default() + .base_weight(Weight::from_ref_time(100)) + .byte_fee(10) + .balance_factor(0) + .build() + .execute_with(|| { + // Next fee multiplier is zero + assert_eq!(>::get(), Multiplier::one()); + + // Tip only, no fees works + let dispatch_info = DispatchInfo { + 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: Weight::from_ref_time(0), + class: DispatchClass::Operational, + pays_fee: Pays::Yes, + }; + assert_eq!(Pallet::::compute_fee(0, &dispatch_info, 0), 100); + // Tip + base fee works + assert_eq!(Pallet::::compute_fee(0, &dispatch_info, 69), 169); + // Len (byte fee) + base fee works + assert_eq!(Pallet::::compute_fee(42, &dispatch_info, 0), 520); + // Weight fee + base fee works + let dispatch_info = DispatchInfo { + weight: Weight::from_ref_time(1000), + class: DispatchClass::Operational, + pays_fee: Pays::Yes, + }; + assert_eq!(Pallet::::compute_fee(0, &dispatch_info, 0), 1100); + }); +} + +#[test] +fn compute_fee_works_with_multiplier() { + ExtBuilder::default() + .base_weight(Weight::from_ref_time(100)) + .byte_fee(10) + .balance_factor(0) + .build() + .execute_with(|| { + // Add a next fee multiplier. Fees will be x3/2. + >::put(Multiplier::saturating_from_rational(3, 2)); + // Base fee is unaffected by multiplier + let dispatch_info = DispatchInfo { + weight: Weight::from_ref_time(0), + class: DispatchClass::Operational, + pays_fee: Pays::Yes, + }; + assert_eq!(Pallet::::compute_fee(0, &dispatch_info, 0), 100); + + // Everything works together :) + let dispatch_info = DispatchInfo { + weight: Weight::from_ref_time(123), + class: DispatchClass::Operational, + pays_fee: Pays::Yes, + }; + // 123 weight, 456 length, 100 base + assert_eq!( + Pallet::::compute_fee(456, &dispatch_info, 789), + 100 + (3 * 123 / 2) + 4560 + 789, + ); + }); +} + +#[test] +fn compute_fee_works_with_negative_multiplier() { + ExtBuilder::default() + .base_weight(Weight::from_ref_time(100)) + .byte_fee(10) + .balance_factor(0) + .build() + .execute_with(|| { + // Add a next fee multiplier. All fees will be x1/2. + >::put(Multiplier::saturating_from_rational(1, 2)); + + // Base fee is unaffected by multiplier. + let dispatch_info = DispatchInfo { + weight: Weight::from_ref_time(0), + class: DispatchClass::Operational, + pays_fee: Pays::Yes, + }; + assert_eq!(Pallet::::compute_fee(0, &dispatch_info, 0), 100); + + // Everything works together. + let dispatch_info = DispatchInfo { + weight: Weight::from_ref_time(123), + class: DispatchClass::Operational, + pays_fee: Pays::Yes, + }; + // 123 weight, 456 length, 100 base + assert_eq!( + Pallet::::compute_fee(456, &dispatch_info, 789), + 100 + (123 / 2) + 4560 + 789, + ); + }); +} + +#[test] +fn compute_fee_does_not_overflow() { + ExtBuilder::default() + .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, + class: DispatchClass::Operational, + pays_fee: Pays::Yes, + }; + assert_eq!( + Pallet::::compute_fee(u32::MAX, &dispatch_info, u64::MAX), + u64::MAX + ); + }); +} + +#[test] +fn refund_does_not_recreate_account() { + ExtBuilder::default() + .balance_factor(10) + .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(Weight::from_ref_time(100)), len) + .unwrap(); + assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 100 - 5); + + // kill the account between pre and post dispatch + assert_ok!(Balances::transfer(Some(2).into(), 3, Balances::free_balance(2))); + assert_eq!(Balances::free_balance(2), 0); + + assert_ok!(ChargeTransactionPayment::::post_dispatch( + Some(pre), + &info_from_weight(Weight::from_ref_time(100)), + &post_info_from_weight(Weight::from_ref_time(50)), + len, + &Ok(()) + )); + assert_eq!(Balances::free_balance(2), 0); + // Transfer Event + System::assert_has_event(RuntimeEvent::Balances(pallet_balances::Event::Transfer { + from: 2, + to: 3, + amount: 80, + })); + // Killed Event + System::assert_has_event(RuntimeEvent::System(system::Event::KilledAccount { + account: 2, + })); + }); +} + +#[test] +fn actual_weight_higher_than_max_refunds_nothing() { + ExtBuilder::default() + .balance_factor(10) + .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(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(Weight::from_ref_time(100)), + &post_info_from_weight(Weight::from_ref_time(101)), + len, + &Ok(()) + )); + assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 100 - 5); + }); +} + +#[test] +fn zero_transfer_on_free_transaction() { + ExtBuilder::default() + .balance_factor(10) + .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: 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) + .unwrap(); + assert_eq!(Balances::total_balance(&user), 0); + assert_ok!(ChargeTransactionPayment::::post_dispatch( + Some(pre), + &dispatch_info, + &default_post_info(), + len, + &Ok(()) + )); + assert_eq!(Balances::total_balance(&user), 0); + // TransactionFeePaid Event + System::assert_has_event(RuntimeEvent::TransactionPayment( + pallet_transaction_payment::Event::TransactionFeePaid { + who: user, + actual_fee: 0, + tip: 0, + }, + )); + }); +} + +#[test] +fn refund_consistent_with_actual_weight() { + ExtBuilder::default() + .balance_factor(10) + .base_weight(Weight::from_ref_time(7)) + .build() + .execute_with(|| { + 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; + + >::put(Multiplier::saturating_from_rational(5, 4)); + + let pre = ChargeTransactionPayment::::from(tip) + .pre_dispatch(&2, CALL, &info, len) + .unwrap(); + + ChargeTransactionPayment::::post_dispatch( + Some(pre), + &info, + &post_info, + len, + &Ok(()), + ) + .unwrap(); + + let refund_based_fee = prev_balance - Balances::free_balance(2); + let actual_fee = + Pallet::::compute_actual_fee(len as u32, &info, &post_info, tip); + + // 33 weight, 10 length, 7 base, 5 tip + assert_eq!(actual_fee, 7 + 10 + (33 * 5 / 4) + 5); + assert_eq!(refund_based_fee, actual_fee); + }); +} + +#[test] +fn should_alter_operational_priority() { + let tip = 5; + let len = 10; + + ExtBuilder::default().balance_factor(100).build().execute_with(|| { + 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() + .priority; + + assert_eq!(priority, 60); + + let priority = ChargeTransactionPayment::(2 * tip) + .validate(&2, CALL, &normal, len) + .unwrap() + .priority; + + assert_eq!(priority, 110); + }); + + ExtBuilder::default().balance_factor(100).build().execute_with(|| { + let op = DispatchInfo { + weight: Weight::from_ref_time(100), + class: DispatchClass::Operational, + pays_fee: Pays::Yes, + }; + let priority = ChargeTransactionPayment::(tip) + .validate(&2, CALL, &op, len) + .unwrap() + .priority; + assert_eq!(priority, 5810); + + let priority = ChargeTransactionPayment::(2 * tip) + .validate(&2, CALL, &op, len) + .unwrap() + .priority; + assert_eq!(priority, 6110); + }); +} + +#[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: Weight::from_ref_time(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: Weight::from_ref_time(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 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: Weight::from_ref_time(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: Weight::from_ref_time(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() + .balance_factor(10) + .base_weight(Weight::from_ref_time(7)) + .build() + .execute_with(|| { + 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; + let tip = 5; + + >::put(Multiplier::saturating_from_rational(5, 4)); + + let pre = ChargeTransactionPayment::::from(tip) + .pre_dispatch(&2, CALL, &info, len) + .unwrap(); + + ChargeTransactionPayment::::post_dispatch( + Some(pre), + &info, + &post_info, + len, + &Ok(()), + ) + .unwrap(); + + let refund_based_fee = prev_balance - Balances::free_balance(2); + let actual_fee = + Pallet::::compute_actual_fee(len as u32, &info, &post_info, tip); + + // Only 5 tip is paid + assert_eq!(actual_fee, 5); + 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 42f38dbd961342cd965154858e50f0253b0b7c0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 17 Jan 2023 20:17:08 +0100 Subject: [PATCH 296/715] frame-benchmarking: Macros should not force a particular env (#13161) The macros in frame-benchmarking relied on having all the macros imported, which isn't a behavior for a proper macro :D This pr fixes this by making all internal macro usages absolute. --- bin/node/runtime/src/lib.rs | 6 +---- frame/benchmarking/src/lib.rs | 49 +++++++++++++++++------------------ 2 files changed, 25 insertions(+), 30 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index d34c04fcb5d3c..fb5da9749a2d1 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1823,13 +1823,9 @@ 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::define_benchmarks!( [frame_benchmarking, BaselineBench::] [pallet_alliance, Alliance] [pallet_assets, Assets] diff --git a/frame/benchmarking/src/lib.rs b/frame/benchmarking/src/lib.rs index 29fa0b6a6af70..e4ebd2f228afe 100644 --- a/frame/benchmarking/src/lib.rs +++ b/frame/benchmarking/src/lib.rs @@ -1836,15 +1836,15 @@ macro_rules! add_benchmark { /// Callback for `define_benchmarks` to call `add_benchmark`. #[macro_export] macro_rules! cb_add_benchmarks { - // anchor + // anchor ( $params:ident, $batches:ident, [ $name:path, $( $location:tt )* ] ) => { - add_benchmark!( $params, $batches, $name, $( $location )* ); + $crate::add_benchmark!( $params, $batches, $name, $( $location )* ); }; - // recursion tail + // 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 )* ])+ ); - } + $crate::cb_add_benchmarks!( $params, $batches, [ $name, $( $location )* ] ); + $crate::cb_add_benchmarks!( $params, $batches, $([ $names, $( $locations )* ])+ ); + } } /// This macro allows users to easily generate a list of benchmarks for the pallets configured @@ -1884,24 +1884,23 @@ macro_rules! list_benchmark { /// Callback for `define_benchmarks` to call `list_benchmark`. #[macro_export] macro_rules! cb_list_benchmarks { - // anchor + // anchor ( $list:ident, $extra:ident, [ $name:path, $( $location:tt )* ] ) => { - list_benchmark!( $list, $extra, $name, $( $location )* ); + $crate::list_benchmark!( $list, $extra, $name, $( $location )* ); }; - // recursion tail + // 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 )* ])+ ); - } + $crate::cb_list_benchmarks!( $list, $extra, [ $name, $( $location )* ] ); + $crate::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 )* ])* ) => { + ( $([ $names:path, $( $locations:tt )* ])* ) => { /// Calls `list_benchmark` with all configs from `define_benchmarks` /// and passes the first two parameters on. /// @@ -1910,11 +1909,11 @@ macro_rules! define_benchmarks { /// list_benchmarks!(list, extra); /// ``` #[macro_export] - macro_rules! list_benchmarks { - ( $list:ident, $extra:ident ) => { - cb_list_benchmarks!( $list, $extra, $([ $names, $( $locations )* ])+ ); - } - } + macro_rules! list_benchmarks { + ( $list:ident, $extra:ident ) => { + $crate::cb_list_benchmarks!( $list, $extra, $([ $names, $( $locations )* ])+ ); + } + } /// Calls `add_benchmark` with all configs from `define_benchmarks` /// and passes the first two parameters on. @@ -1924,10 +1923,10 @@ macro_rules! define_benchmarks { /// add_benchmarks!(params, batches); /// ``` #[macro_export] - macro_rules! add_benchmarks { - ( $params:ident, $batches:ident ) => { - cb_add_benchmarks!( $params, $batches, $([ $names, $( $locations )* ])+ ); - } - } - } + macro_rules! add_benchmarks { + ( $params:ident, $batches:ident ) => { + $crate::cb_add_benchmarks!( $params, $batches, $([ $names, $( $locations )* ])+ ); + } + } + } } From cfe926282a284f7bdbf7b336eb78e80f51858577 Mon Sep 17 00:00:00 2001 From: Koute Date: Wed, 18 Jan 2023 15:28:27 +0900 Subject: [PATCH 297/715] Fix the `storage_size`/`state_getStorageSize` RPC call (#13154) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Have `KeyIterator` clone the `prefix` it receives * Stream keys in `storage_size` RPC and add a runtime limit * Update client/rpc/Cargo.toml Co-authored-by: Bastian Köcher * Update client/rpc/src/state/utils.rs Co-authored-by: Bastian Köcher * Rename the types to signify that the cancellation is due to a timeout * Move the test into a `mod tests` * Add a comment regarding `biased` in `tokio::select` * Make the `clone` explicit when calling `KeyIterator::{new, new_child}` Co-authored-by: Bastian Köcher --- client/api/src/backend.rs | 26 +++--- client/rpc-api/src/state/mod.rs | 4 +- client/rpc/Cargo.toml | 4 +- client/rpc/src/state/mod.rs | 19 +++- client/rpc/src/state/state_full.rs | 67 +++++++++---- client/rpc/src/state/tests.rs | 7 +- client/rpc/src/state/utils.rs | 140 ++++++++++++++++++++++++++++ client/service/src/client/client.rs | 16 ++-- 8 files changed, 232 insertions(+), 51 deletions(-) create mode 100644 client/rpc/src/state/utils.rs diff --git a/client/api/src/backend.rs b/client/api/src/backend.rs index 79cc0d7a16bcc..21d213ffb15cf 100644 --- a/client/api/src/backend.rs +++ b/client/api/src/backend.rs @@ -303,17 +303,17 @@ pub trait AuxStore { } /// An `Iterator` that iterates keys in a given block under a prefix. -pub struct KeyIterator<'a, State, Block> { +pub struct KeyIterator { state: State, child_storage: Option, - prefix: Option<&'a StorageKey>, + prefix: Option, current_key: Vec, _phantom: PhantomData, } -impl<'a, State, Block> KeyIterator<'a, State, Block> { +impl KeyIterator { /// create a KeyIterator instance - pub fn new(state: State, prefix: Option<&'a StorageKey>, current_key: Vec) -> Self { + pub fn new(state: State, prefix: Option, current_key: Vec) -> Self { Self { state, child_storage: None, prefix, current_key, _phantom: PhantomData } } @@ -321,14 +321,14 @@ impl<'a, State, Block> KeyIterator<'a, State, Block> { pub fn new_child( state: State, child_info: ChildInfo, - prefix: Option<&'a StorageKey>, + prefix: Option, current_key: Vec, ) -> Self { Self { state, child_storage: Some(child_info), prefix, current_key, _phantom: PhantomData } } } -impl<'a, State, Block> Iterator for KeyIterator<'a, State, Block> +impl Iterator for KeyIterator where Block: BlockT, State: StateBackend>, @@ -344,7 +344,7 @@ where .ok() .flatten()?; // this terminates the iterator the first time it fails. - if let Some(prefix) = self.prefix { + if let Some(ref prefix) = self.prefix { if !next_key.starts_with(&prefix.0[..]) { return None } @@ -387,12 +387,12 @@ pub trait StorageProvider> { /// Given a block's `Hash` and a key prefix, return a `KeyIterator` iterates matching storage /// keys in that block. - fn storage_keys_iter<'a>( + fn storage_keys_iter( &self, hash: Block::Hash, - prefix: Option<&'a StorageKey>, + prefix: Option<&StorageKey>, start_key: Option<&StorageKey>, - ) -> sp_blockchain::Result>; + ) -> sp_blockchain::Result>; /// Given a block's `Hash`, a key and a child storage key, return the value under the key in /// that block. @@ -414,13 +414,13 @@ pub trait StorageProvider> { /// 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>( + fn child_storage_keys_iter( &self, hash: Block::Hash, child_info: ChildInfo, - prefix: Option<&'a StorageKey>, + prefix: Option<&StorageKey>, start_key: Option<&StorageKey>, - ) -> sp_blockchain::Result>; + ) -> sp_blockchain::Result>; /// Given a block's `Hash`, a key and a child storage key, return the hash under the key in that /// block. diff --git a/client/rpc-api/src/state/mod.rs b/client/rpc-api/src/state/mod.rs index 40e208c2eba8d..323e6ad1d41a3 100644 --- a/client/rpc-api/src/state/mod.rs +++ b/client/rpc-api/src/state/mod.rs @@ -71,8 +71,8 @@ pub trait StateApi { 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"], blocking)] - fn storage_size(&self, key: StorageKey, hash: Option) -> RpcResult>; + #[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. #[method(name = "state_getMetadata", blocking)] diff --git a/client/rpc/Cargo.toml b/client/rpc/Cargo.toml index d97170ddf42e6..d39d8d8581ff6 100644 --- a/client/rpc/Cargo.toml +++ b/client/rpc/Cargo.toml @@ -36,7 +36,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.22.0", optional = true } +tokio = "1.22.0" [dev-dependencies] env_logger = "0.9" @@ -51,4 +51,4 @@ sp-io = { version = "7.0.0", path = "../../primitives/io" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } [features] -test-helpers = ["tokio"] +test-helpers = [] diff --git a/client/rpc/src/state/mod.rs b/client/rpc/src/state/mod.rs index fd802e5a80391..9ba4c8218dd79 100644 --- a/client/rpc/src/state/mod.rs +++ b/client/rpc/src/state/mod.rs @@ -19,6 +19,7 @@ //! Substrate state API. mod state_full; +mod utils; #[cfg(test)] mod tests; @@ -28,7 +29,7 @@ use std::sync::Arc; use crate::SubscriptionTaskExecutor; use jsonrpsee::{ - core::{server::rpc_module::SubscriptionSink, Error as JsonRpseeError, RpcResult}, + core::{async_trait, server::rpc_module::SubscriptionSink, Error as JsonRpseeError, RpcResult}, types::SubscriptionResult, }; @@ -53,6 +54,7 @@ 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, @@ -107,10 +109,11 @@ 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. - fn storage_size( + async fn storage_size( &self, block: Option, key: StorageKey, + deny_unsafe: DenyUnsafe, ) -> Result, Error>; /// Returns the runtime metadata as an opaque blob. @@ -202,6 +205,7 @@ pub struct State { deny_unsafe: DenyUnsafe, } +#[async_trait] impl StateApiServer for State where Block: BlockT + 'static, @@ -262,8 +266,15 @@ where self.backend.storage_hash(block, key).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 storage_size( + &self, + key: StorageKey, + block: Option, + ) -> RpcResult> { + self.backend + .storage_size(block, key, self.deny_unsafe) + .await + .map_err(Into::into) } fn metadata(&self, block: Option) -> RpcResult { diff --git a/client/rpc/src/state/state_full.rs b/client/rpc/src/state/state_full.rs index 58aeac66e5c79..d8fe39030aa82 100644 --- a/client/rpc/src/state/state_full.rs +++ b/client/rpc/src/state/state_full.rs @@ -18,17 +18,20 @@ //! State API backend for full nodes. -use std::{collections::HashMap, marker::PhantomData, sync::Arc}; +use std::{collections::HashMap, marker::PhantomData, sync::Arc, time::Duration}; use super::{ client_err, error::{Error, Result}, ChildStateBackend, StateBackend, }; -use crate::SubscriptionTaskExecutor; +use crate::{DenyUnsafe, SubscriptionTaskExecutor}; use futures::{future, stream, FutureExt, StreamExt}; -use jsonrpsee::{core::Error as JsonRpseeError, SubscriptionSink}; +use jsonrpsee::{ + core::{async_trait, Error as JsonRpseeError}, + SubscriptionSink, +}; use sc_client_api::{ Backend, BlockBackend, BlockchainEvents, CallExecutor, ExecutorProvider, ProofProvider, StorageProvider, @@ -48,6 +51,9 @@ use sp_core::{ use sp_runtime::{generic::BlockId, traits::Block as BlockT}; use sp_version::RuntimeVersion; +/// The maximum time allowed for an RPC call when running without unsafe RPC enabled. +const MAXIMUM_SAFE_RPC_CALL_TIMEOUT: Duration = Duration::from_secs(30); + /// Ranges to query in state_queryStorage. struct QueryStorageRange { /// Hashes of all the blocks in the range. @@ -166,6 +172,7 @@ where } } +#[async_trait] impl StateBackend for FullState where Block: BlockT + 'static, @@ -251,33 +258,53 @@ where .map_err(client_err) } - fn storage_size( + async fn storage_size( &self, block: Option, key: StorageKey, + deny_unsafe: DenyUnsafe, ) -> std::result::Result, Error> { let block = match self.block_or_best(block) { Ok(b) => b, Err(e) => return Err(client_err(e)), }; - 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) => {}, - } + let client = self.client.clone(); + let timeout = match deny_unsafe { + DenyUnsafe::Yes => Some(MAXIMUM_SAFE_RPC_CALL_TIMEOUT), + DenyUnsafe::No => None, + }; - self.client - .storage_pairs(block, &key) - .map(|kv| { - let item_sum = kv.iter().map(|(_, v)| v.0.len() as u64).sum::(); - if item_sum > 0 { - Some(item_sum) - } else { - None - } - }) - .map_err(client_err) + super::utils::spawn_blocking_with_timeout(timeout, move |is_timed_out| { + // Does the key point to a concrete entry in the database? + match client.storage(block, &key) { + Ok(Some(d)) => return Ok(Ok(Some(d.0.len() as u64))), + Err(e) => return Ok(Err(client_err(e))), + Ok(None) => {}, + } + + // The key doesn't point to anything, so it's probably a prefix. + let iter = match client.storage_keys_iter(block, Some(&key), None).map_err(client_err) { + Ok(iter) => iter, + Err(e) => return Ok(Err(e)), + }; + + let mut sum = 0; + for storage_key in iter { + let value = client.storage(block, &storage_key).ok().flatten().unwrap_or_default(); + sum += value.0.len() as u64; + + is_timed_out.check_if_timed_out()?; + } + + if sum > 0 { + Ok(Ok(Some(sum))) + } else { + Ok(Ok(None)) + } + }) + .await + .map_err(|error| Error::Client(Box::new(error)))? } fn storage_hash( diff --git a/client/rpc/src/state/tests.rs b/client/rpc/src/state/tests.rs index 3ef59e5ca9a7c..fe8bdf0ac2da8 100644 --- a/client/rpc/src/state/tests.rs +++ b/client/rpc/src/state/tests.rs @@ -70,9 +70,12 @@ async fn should_return_storage() { 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(StorageKey(b":map".to_vec()), None).unwrap().unwrap() as usize, + 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, 2 + 3, ); assert_eq!( diff --git a/client/rpc/src/state/utils.rs b/client/rpc/src/state/utils.rs new file mode 100644 index 0000000000000..81476cdd34262 --- /dev/null +++ b/client/rpc/src/state/utils.rs @@ -0,0 +1,140 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2023 Parity Technologies (UK) Ltd. +// SPDX-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::{ + atomic::{AtomicBool, Ordering}, + Arc, + }, + time::Duration, +}; + +/// An error signifying that a task has been cancelled due to a timeout. +#[derive(Debug)] +pub struct Timeout; + +impl std::error::Error for Timeout {} +impl std::fmt::Display for Timeout { + fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { + fmt.write_str("task has been running too long") + } +} + +/// A handle which can be used to check whether the task has been cancelled due to a timeout. +#[repr(transparent)] +pub struct IsTimedOut(Arc); + +impl IsTimedOut { + #[must_use] + pub fn check_if_timed_out(&self) -> std::result::Result<(), Timeout> { + if self.0.load(Ordering::Relaxed) { + Err(Timeout) + } else { + Ok(()) + } + } +} + +/// An error for a task which either panicked, or has been cancelled due to a timeout. +#[derive(Debug)] +pub enum SpawnWithTimeoutError { + JoinError(tokio::task::JoinError), + Timeout, +} + +impl std::error::Error for SpawnWithTimeoutError {} +impl std::fmt::Display for SpawnWithTimeoutError { + fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + SpawnWithTimeoutError::JoinError(error) => error.fmt(fmt), + SpawnWithTimeoutError::Timeout => Timeout.fmt(fmt), + } + } +} + +struct CancelOnDrop(Arc); +impl Drop for CancelOnDrop { + fn drop(&mut self) { + self.0.store(true, Ordering::Relaxed) + } +} + +/// Spawns a new blocking task with a given `timeout`. +/// +/// The `callback` should continuously call [`IsTimedOut::check_if_timed_out`], +/// which will return an error once the task runs for longer than `timeout`. +/// +/// If `timeout` is `None` then this works just as a regular `spawn_blocking`. +pub async fn spawn_blocking_with_timeout( + timeout: Option, + callback: impl FnOnce(IsTimedOut) -> std::result::Result + Send + 'static, +) -> Result +where + R: Send + 'static, +{ + let is_timed_out_arc = Arc::new(AtomicBool::new(false)); + let is_timed_out = IsTimedOut(is_timed_out_arc.clone()); + let _cancel_on_drop = CancelOnDrop(is_timed_out_arc); + let task = tokio::task::spawn_blocking(move || callback(is_timed_out)); + + let result = if let Some(timeout) = timeout { + tokio::select! { + // Shouldn't really matter, but make sure the task is polled before the timeout, + // in case the task finishes after the timeout and the timeout is really short. + biased; + + task_result = task => task_result, + _ = tokio::time::sleep(timeout) => Ok(Err(Timeout)) + } + } else { + task.await + }; + + match result { + Ok(Ok(result)) => Ok(result), + Ok(Err(Timeout)) => Err(SpawnWithTimeoutError::Timeout), + Err(error) => Err(SpawnWithTimeoutError::JoinError(error)), + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[tokio::test] + async fn spawn_blocking_with_timeout_works() { + let task: Result<(), SpawnWithTimeoutError> = + spawn_blocking_with_timeout(Some(Duration::from_millis(100)), |is_timed_out| { + std::thread::sleep(Duration::from_millis(200)); + is_timed_out.check_if_timed_out()?; + unreachable!(); + }) + .await; + + assert_matches::assert_matches!(task, Err(SpawnWithTimeoutError::Timeout)); + + let task = spawn_blocking_with_timeout(Some(Duration::from_millis(100)), |is_timed_out| { + std::thread::sleep(Duration::from_millis(20)); + is_timed_out.check_if_timed_out()?; + Ok(()) + }) + .await; + + assert_matches::assert_matches!(task, Ok(())); + } +} diff --git a/client/service/src/client/client.rs b/client/service/src/client/client.rs index 18012fc1931fe..8e10a7b2eda0a 100644 --- a/client/service/src/client/client.rs +++ b/client/service/src/client/client.rs @@ -1432,27 +1432,27 @@ where Ok(keys) } - fn storage_keys_iter<'a>( + fn storage_keys_iter( &self, hash: ::Hash, - prefix: Option<&'a StorageKey>, + prefix: Option<&StorageKey>, start_key: Option<&StorageKey>, - ) -> sp_blockchain::Result> { + ) -> sp_blockchain::Result> { 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)) + Ok(KeyIterator::new(state, prefix.cloned(), start_key)) } - fn child_storage_keys_iter<'a>( + fn child_storage_keys_iter( &self, hash: ::Hash, child_info: ChildInfo, - prefix: Option<&'a StorageKey>, + prefix: Option<&StorageKey>, start_key: Option<&StorageKey>, - ) -> sp_blockchain::Result> { + ) -> sp_blockchain::Result> { 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)) + Ok(KeyIterator::new_child(state, child_info, prefix.cloned(), start_key)) } fn storage( From a447f03727ffd84020682f3e0e4044d5d282d274 Mon Sep 17 00:00:00 2001 From: Sasha Gryaznov Date: Wed, 18 Jan 2023 12:36:09 +0200 Subject: [PATCH 298/715] [contracts] Adapt storage reading host functions to Weights V2 (#12976) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * update RuntimeCosts to Weights V2, update tests * improve docs * clearer naming and docs to compat_weight helper * Apply suggestions from code review Co-authored-by: Alexander Theißen * save before master merge * HostFnWeights to Weight * added to_weight! macro * Apply suggestions from code review Co-authored-by: Alexander Theißen * RuntimeCosts::ChainExtension to weight_v2 * chain extension to weight v2 Co-authored-by: Alexander Theißen --- frame/contracts/proc-macro/src/lib.rs | 14 +- frame/contracts/src/benchmarking/mod.rs | 2 +- frame/contracts/src/chain_extension.rs | 7 +- frame/contracts/src/gas.rs | 4 +- frame/contracts/src/lib.rs | 22 +- frame/contracts/src/schedule.rs | 278 +++++++++++++----------- frame/contracts/src/tests.rs | 4 +- frame/contracts/src/wasm/mod.rs | 2 +- frame/contracts/src/wasm/runtime.rs | 10 +- 9 files changed, 189 insertions(+), 154 deletions(-) diff --git a/frame/contracts/proc-macro/src/lib.rs b/frame/contracts/proc-macro/src/lib.rs index a31d39f47e215..d0247d720a39a 100644 --- a/frame/contracts/proc-macro/src/lib.rs +++ b/frame/contracts/proc-macro/src/lib.rs @@ -122,23 +122,23 @@ fn iterate_fields(data: &syn::DataStruct, fmt: impl Fn(&Ident) -> TokenStream2) fn format_weight(field: &Ident) -> TokenStream2 { quote_spanned! { field.span() => - &if self.#field > 1_000_000_000 { + &if self.#field.ref_time() > 1_000_000_000 { format!( "{:.1?} ms", - Fixed::saturating_from_rational(self.#field, 1_000_000_000).to_float() + Fixed::saturating_from_rational(self.#field.ref_time(), 1_000_000_000).to_float() ) - } else if self.#field > 1_000_000 { + } else if self.#field.ref_time() > 1_000_000 { format!( "{:.1?} µs", - Fixed::saturating_from_rational(self.#field, 1_000_000).to_float() + Fixed::saturating_from_rational(self.#field.ref_time(), 1_000_000).to_float() ) - } else if self.#field > 1_000 { + } else if self.#field.ref_time() > 1_000 { format!( "{:.1?} ns", - Fixed::saturating_from_rational(self.#field, 1_000).to_float() + Fixed::saturating_from_rational(self.#field.ref_time(), 1_000).to_float() ) } else { - format!("{} ps", self.#field) + format!("{} ps", self.#field.ref_time()) } } } diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index d46da8469eb41..a750a6b1728d6 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -2928,7 +2928,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 --extra --dev --execution=native \ + // --features runtime-benchmarks -- benchmark pallet --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/chain_extension.rs b/frame/contracts/src/chain_extension.rs index dfa9c7c2de268..3974bdba30d14 100644 --- a/frame/contracts/src/chain_extension.rs +++ b/frame/contracts/src/chain_extension.rs @@ -227,7 +227,7 @@ impl<'a, 'b, E: Ext, S: State> Environment<'a, 'b, E, S> { /// /// Weight is synonymous with gas in substrate. pub fn charge_weight(&mut self, amount: Weight) -> Result { - self.inner.runtime.charge_gas(RuntimeCosts::ChainExtension(amount.ref_time())) + self.inner.runtime.charge_gas(RuntimeCosts::ChainExtension(amount)) } /// Adjust a previously charged amount down to its actual amount. @@ -237,7 +237,7 @@ impl<'a, 'b, E: Ext, S: State> Environment<'a, 'b, E, S> { pub fn adjust_weight(&mut self, charged: ChargedAmount, actual_weight: Weight) { self.inner .runtime - .adjust_gas(charged, RuntimeCosts::ChainExtension(actual_weight.ref_time())) + .adjust_gas(charged, RuntimeCosts::ChainExtension(actual_weight)) } /// Grants access to the execution environment of the current contract call. @@ -408,8 +408,7 @@ impl<'a, 'b, E: Ext, S: BufOut> Environment<'a, 'b, E, S> { buffer, allow_skip, |len| { - weight_per_byte - .map(|w| RuntimeCosts::ChainExtension(w.ref_time().saturating_mul(len.into()))) + weight_per_byte.map(|w| RuntimeCosts::ChainExtension(w.saturating_mul(len.into()))) }, ) } diff --git a/frame/contracts/src/gas.rs b/frame/contracts/src/gas.rs index ccbe680b2f767..c8383f307c0ea 100644 --- a/frame/contracts/src/gas.rs +++ b/frame/contracts/src/gas.rs @@ -153,8 +153,8 @@ impl GasMeter { /// Returns `OutOfGas` if there is not enough gas or addition of the specified /// amount of gas has lead to overflow. On success returns `Proceed`. /// - /// NOTE that amount is always consumed, i.e. if there is not enough gas - /// then the counter will be set to zero. + /// NOTE that amount isn't consumed if there is not enough gas. This is considered + /// safe because we always charge gas before performing any resource-spending action. #[inline] pub fn charge>(&mut self, token: Tok) -> Result { #[cfg(test)] diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index 9efeec65f51f5..581798e4488d6 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -381,7 +381,7 @@ pub mod pallet { { /// 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)))] + #[pallet::weight(T::WeightInfo::call().saturating_add(>::compat_weight_limit(*gas_limit)))] #[allow(deprecated)] #[deprecated(note = "1D weight is used in this extrinsic, please migrate to `call`")] pub fn call_old_weight( @@ -396,7 +396,7 @@ pub mod pallet { origin, dest, value, - >::compat_weight(gas_limit), + >::compat_weight_limit(gas_limit), storage_deposit_limit, data, ) @@ -406,7 +406,7 @@ pub mod pallet { #[pallet::call_index(1)] #[pallet::weight( T::WeightInfo::instantiate_with_code(code.len() as u32, data.len() as u32, salt.len() as u32) - .saturating_add(>::compat_weight(*gas_limit)) + .saturating_add(>::compat_weight_limit(*gas_limit)) )] #[allow(deprecated)] #[deprecated( @@ -424,7 +424,7 @@ pub mod pallet { Self::instantiate_with_code( origin, value, - >::compat_weight(gas_limit), + >::compat_weight_limit(gas_limit), storage_deposit_limit, code, data, @@ -435,7 +435,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(data.len() as u32, salt.len() as u32).saturating_add(>::compat_weight(*gas_limit)) + T::WeightInfo::instantiate(data.len() as u32, salt.len() as u32).saturating_add(>::compat_weight_limit(*gas_limit)) )] #[allow(deprecated)] #[deprecated(note = "1D weight is used in this extrinsic, please migrate to `instantiate`")] @@ -451,7 +451,7 @@ pub mod pallet { Self::instantiate( origin, value, - >::compat_weight(gas_limit), + >::compat_weight_limit(gas_limit), storage_deposit_limit, code_hash, data, @@ -1216,12 +1216,12 @@ impl Pallet { >>::minimum_balance() } - /// Convert a 1D Weight to a 2D weight. + /// Convert gas_limit from 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) + /// Used by backwards compatible extrinsics. We cannot just set the proof_size weight limit to + /// zero or an old `Call` will just fail with OutOfGas. + fn compat_weight_limit(gas_limit: OldWeight) -> Weight { + Weight::from_parts(gas_limit.0, u64::from(T::MaxCodeLen::get()) * 2) } } diff --git a/frame/contracts/src/schedule.rs b/frame/contracts/src/schedule.rs index 912e58b048ff4..dabdc70135916 100644 --- a/frame/contracts/src/schedule.rs +++ b/frame/contracts/src/schedule.rs @@ -21,7 +21,7 @@ use crate::{wasm::Determinism, weights::WeightInfo, Config}; use codec::{Decode, Encode}; -use frame_support::DefaultNoBound; +use frame_support::{weights::Weight, DefaultNoBound}; use pallet_contracts_proc_macro::{ScheduleDebug, WeightDebug}; use scale_info::TypeInfo; #[cfg(feature = "std")] @@ -169,7 +169,7 @@ impl Limits { /// that use them as supporting instructions. Supporting means mainly pushing arguments /// and dropping return values in order to maintain a valid module. #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] -#[derive(Clone, Encode, Decode, PartialEq, Eq, WeightDebug, TypeInfo)] +#[derive(Clone, Encode, Decode, PartialEq, Eq, ScheduleDebug, TypeInfo)] #[scale_info(skip_type_params(T))] pub struct InstructionWeights { /// Version of the instruction weights. @@ -255,178 +255,178 @@ pub struct InstructionWeights { #[scale_info(skip_type_params(T))] pub struct HostFnWeights { /// Weight of calling `seal_caller`. - pub caller: u64, + pub caller: Weight, /// Weight of calling `seal_is_contract`. - pub is_contract: u64, + pub is_contract: Weight, /// Weight of calling `seal_code_hash`. - pub code_hash: u64, + pub code_hash: Weight, /// Weight of calling `seal_own_code_hash`. - pub own_code_hash: u64, + pub own_code_hash: Weight, /// Weight of calling `seal_caller_is_origin`. - pub caller_is_origin: u64, + pub caller_is_origin: Weight, /// Weight of calling `seal_address`. - pub address: u64, + pub address: Weight, /// Weight of calling `seal_gas_left`. - pub gas_left: u64, + pub gas_left: Weight, /// Weight of calling `seal_balance`. - pub balance: u64, + pub balance: Weight, /// Weight of calling `seal_value_transferred`. - pub value_transferred: u64, + pub value_transferred: Weight, /// Weight of calling `seal_minimum_balance`. - pub minimum_balance: u64, + pub minimum_balance: Weight, /// Weight of calling `seal_block_number`. - pub block_number: u64, + pub block_number: Weight, /// Weight of calling `seal_now`. - pub now: u64, + pub now: Weight, /// Weight of calling `seal_weight_to_fee`. - pub weight_to_fee: u64, + pub weight_to_fee: Weight, /// Weight of calling `gas`. - pub gas: u64, + pub gas: Weight, /// Weight of calling `seal_input`. - pub input: u64, + pub input: Weight, /// Weight per input byte copied to contract memory by `seal_input`. - pub input_per_byte: u64, + pub input_per_byte: Weight, /// Weight of calling `seal_return`. - pub r#return: u64, + pub r#return: Weight, /// Weight per byte returned through `seal_return`. - pub return_per_byte: u64, + pub return_per_byte: Weight, /// Weight of calling `seal_terminate`. - pub terminate: u64, + pub terminate: Weight, /// Weight of calling `seal_random`. - pub random: u64, + pub random: Weight, /// Weight of calling `seal_reposit_event`. - pub deposit_event: u64, + pub deposit_event: Weight, /// Weight per topic supplied to `seal_deposit_event`. - pub deposit_event_per_topic: u64, + pub deposit_event_per_topic: Weight, /// Weight per byte of an event deposited through `seal_deposit_event`. - pub deposit_event_per_byte: u64, + pub deposit_event_per_byte: Weight, /// Weight of calling `seal_debug_message`. - pub debug_message: u64, + pub debug_message: Weight, /// Weight of calling `seal_set_storage`. - pub set_storage: u64, + pub set_storage: Weight, /// Weight per written byten of an item stored with `seal_set_storage`. - pub set_storage_per_new_byte: u64, + 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: u64, + pub set_storage_per_old_byte: Weight, /// Weight of calling `seal_set_code_hash`. - pub set_code_hash: u64, + pub set_code_hash: Weight, /// Weight of calling `seal_clear_storage`. - pub clear_storage: u64, + pub clear_storage: Weight, /// Weight of calling `seal_clear_storage` per byte of the stored item. - pub clear_storage_per_byte: u64, + pub clear_storage_per_byte: Weight, /// Weight of calling `seal_contains_storage`. - pub contains_storage: u64, + pub contains_storage: Weight, /// Weight of calling `seal_contains_storage` per byte of the stored item. - pub contains_storage_per_byte: u64, + pub contains_storage_per_byte: Weight, /// Weight of calling `seal_get_storage`. - pub get_storage: u64, + pub get_storage: Weight, /// Weight per byte of an item received via `seal_get_storage`. - pub get_storage_per_byte: u64, + pub get_storage_per_byte: Weight, /// Weight of calling `seal_take_storage`. - pub take_storage: u64, + pub take_storage: Weight, /// Weight per byte of an item received via `seal_take_storage`. - pub take_storage_per_byte: u64, + pub take_storage_per_byte: Weight, /// Weight of calling `seal_transfer`. - pub transfer: u64, + pub transfer: Weight, /// Weight of calling `seal_call`. - pub call: u64, + pub call: Weight, /// Weight of calling `seal_delegate_call`. - pub delegate_call: u64, + pub delegate_call: Weight, /// Weight surcharge that is claimed if `seal_call` does a balance transfer. - pub call_transfer_surcharge: u64, + pub call_transfer_surcharge: Weight, /// Weight per byte that is cloned by supplying the `CLONE_INPUT` flag. - pub call_per_cloned_byte: u64, + pub call_per_cloned_byte: Weight, /// Weight of calling `seal_instantiate`. - pub instantiate: u64, + pub instantiate: Weight, /// Weight surcharge that is claimed if `seal_instantiate` does a balance transfer. - pub instantiate_transfer_surcharge: u64, + pub instantiate_transfer_surcharge: Weight, /// Weight per input byte supplied to `seal_instantiate`. - pub instantiate_per_input_byte: u64, + pub instantiate_per_input_byte: Weight, /// Weight per salt byte supplied to `seal_instantiate`. - pub instantiate_per_salt_byte: u64, + pub instantiate_per_salt_byte: Weight, /// Weight of calling `seal_hash_sha_256`. - pub hash_sha2_256: u64, + pub hash_sha2_256: Weight, /// Weight per byte hashed by `seal_hash_sha_256`. - pub hash_sha2_256_per_byte: u64, + pub hash_sha2_256_per_byte: Weight, /// Weight of calling `seal_hash_keccak_256`. - pub hash_keccak_256: u64, + pub hash_keccak_256: Weight, /// Weight per byte hashed by `seal_hash_keccak_256`. - pub hash_keccak_256_per_byte: u64, + pub hash_keccak_256_per_byte: Weight, /// Weight of calling `seal_hash_blake2_256`. - pub hash_blake2_256: u64, + pub hash_blake2_256: Weight, /// Weight per byte hashed by `seal_hash_blake2_256`. - pub hash_blake2_256_per_byte: u64, + pub hash_blake2_256_per_byte: Weight, /// Weight of calling `seal_hash_blake2_128`. - pub hash_blake2_128: u64, + pub hash_blake2_128: Weight, /// Weight per byte hashed by `seal_hash_blake2_128`. - pub hash_blake2_128_per_byte: u64, + pub hash_blake2_128_per_byte: Weight, /// Weight of calling `seal_ecdsa_recover`. - pub ecdsa_recover: u64, + pub ecdsa_recover: Weight, /// Weight of calling `seal_ecdsa_to_eth_address`. - pub ecdsa_to_eth_address: u64, + pub ecdsa_to_eth_address: Weight, /// Weight of calling `reentrance_count`. - pub reentrance_count: u64, + pub reentrance_count: Weight, /// Weight of calling `account_reentrance_count`. - pub account_reentrance_count: u64, + pub account_reentrance_count: Weight, /// Weight of calling `instantiation_nonce`. - pub instantiation_nonce: u64, + pub instantiation_nonce: Weight, /// The type parameter is used in the default implementation. #[codec(skip)] @@ -514,6 +514,12 @@ macro_rules! cost_byte_batched { }; } +macro_rules! to_weight { + ($ref_time:expr $(, $proof_size:expr )?) => { + Weight::from_ref_time($ref_time)$(.set_proof_size($proof_size))? + }; +} + impl Default for Limits { fn default() -> Self { Self { @@ -596,85 +602,115 @@ impl Default for InstructionWeights { } impl Default for HostFnWeights { + /// PoV should contain all trie nodes that are read during state transition (i.e. block + /// production). Hence we need to charge the `proof_size` weight for every host function which + /// reads storage, namely: + /// - get_storage, + /// - take_storage, + /// - contains_storage, + /// - clear_storage, + /// - set_storage. + /// + /// The last two functions write to storage, but they also do read storage in order to return + /// the size of the pre-existed value. Till we have PoV benchmarks implemented, we approximate + /// `proof_size` as being equal to the size of storage read. fn default() -> Self { 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), - balance: cost_batched!(seal_balance), - value_transferred: cost_batched!(seal_value_transferred), - minimum_balance: cost_batched!(seal_minimum_balance), - block_number: cost_batched!(seal_block_number), - now: cost_batched!(seal_now), - weight_to_fee: cost_batched!(seal_weight_to_fee), - gas: cost_batched!(seal_gas), - input: cost_batched!(seal_input), - input_per_byte: cost_byte_batched!(seal_input_per_kb), - r#return: cost!(seal_return), - return_per_byte: cost_byte!(seal_return_per_kb), - terminate: cost!(seal_terminate), - random: cost_batched!(seal_random), - deposit_event: cost_batched!(seal_deposit_event), - deposit_event_per_topic: cost_batched_args!(seal_deposit_event_per_topic_and_kb, 1, 0), - deposit_event_per_byte: cost_byte_batched_args!( + caller: to_weight!(cost_batched!(seal_caller)), + is_contract: to_weight!(cost_batched!(seal_is_contract)), + code_hash: to_weight!(cost_batched!(seal_code_hash)), + own_code_hash: to_weight!(cost_batched!(seal_own_code_hash)), + caller_is_origin: to_weight!(cost_batched!(seal_caller_is_origin)), + address: to_weight!(cost_batched!(seal_address)), + gas_left: to_weight!(cost_batched!(seal_gas_left)), + balance: to_weight!(cost_batched!(seal_balance)), + value_transferred: to_weight!(cost_batched!(seal_value_transferred)), + minimum_balance: to_weight!(cost_batched!(seal_minimum_balance)), + block_number: to_weight!(cost_batched!(seal_block_number)), + now: to_weight!(cost_batched!(seal_now)), + weight_to_fee: to_weight!(cost_batched!(seal_weight_to_fee)), + gas: to_weight!(cost_batched!(seal_gas)), + input: to_weight!(cost_batched!(seal_input)), + input_per_byte: to_weight!(cost_byte_batched!(seal_input_per_kb)), + r#return: to_weight!(cost!(seal_return)), + return_per_byte: to_weight!(cost_byte!(seal_return_per_kb)), + terminate: to_weight!(cost!(seal_terminate)), + random: to_weight!(cost_batched!(seal_random)), + deposit_event: to_weight!(cost_batched!(seal_deposit_event)), + deposit_event_per_topic: to_weight!(cost_batched_args!( + seal_deposit_event_per_topic_and_kb, + 1, + 0 + )), + deposit_event_per_byte: to_weight!(cost_byte_batched_args!( seal_deposit_event_per_topic_and_kb, 0, 1 + )), + debug_message: to_weight!(cost_batched!(seal_debug_message)), + set_storage: to_weight!(cost_batched!(seal_set_storage)), + set_code_hash: to_weight!(cost_batched!(seal_set_code_hash)), + set_storage_per_new_byte: to_weight!(cost_byte_batched!(seal_set_storage_per_new_kb)), + set_storage_per_old_byte: to_weight!( + cost_byte_batched!(seal_set_storage_per_old_kb), + 1u64 ), - 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), - 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), - 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_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_transfer_surcharge: cost_byte_batched_args!( + clear_storage: to_weight!(cost_batched!(seal_clear_storage)), + clear_storage_per_byte: to_weight!(cost_byte_batched!(seal_clear_storage_per_kb), 1u64), + contains_storage: to_weight!(cost_batched!(seal_contains_storage)), + contains_storage_per_byte: to_weight!( + cost_byte_batched!(seal_contains_storage_per_kb), + 1u64 + ), + get_storage: to_weight!(cost_batched!(seal_get_storage)), + get_storage_per_byte: to_weight!(cost_byte_batched!(seal_get_storage_per_kb), 1u64), + take_storage: to_weight!(cost_batched!(seal_take_storage)), + take_storage_per_byte: to_weight!(cost_byte_batched!(seal_take_storage_per_kb), 1u64), + transfer: to_weight!(cost_batched!(seal_transfer)), + call: to_weight!(cost_batched!(seal_call)), + delegate_call: to_weight!(cost_batched!(seal_delegate_call)), + call_transfer_surcharge: to_weight!(cost_batched_args!( + seal_call_per_transfer_clone_kb, + 1, + 0 + )), + call_per_cloned_byte: to_weight!(cost_batched_args!( + seal_call_per_transfer_clone_kb, + 0, + 1 + )), + instantiate: to_weight!(cost_batched!(seal_instantiate)), + instantiate_transfer_surcharge: to_weight!(cost_byte_batched_args!( seal_instantiate_per_transfer_input_salt_kb, 1, 0, 0 - ), - instantiate_per_input_byte: cost_byte_batched_args!( + )), + instantiate_per_input_byte: to_weight!(cost_byte_batched_args!( seal_instantiate_per_transfer_input_salt_kb, 0, 1, 0 - ), - instantiate_per_salt_byte: cost_byte_batched_args!( + )), + instantiate_per_salt_byte: to_weight!(cost_byte_batched_args!( seal_instantiate_per_transfer_input_salt_kb, 0, 0, 1 - ), - hash_sha2_256: cost_batched!(seal_hash_sha2_256), - hash_sha2_256_per_byte: cost_byte_batched!(seal_hash_sha2_256_per_kb), - hash_keccak_256: cost_batched!(seal_hash_keccak_256), - hash_keccak_256_per_byte: cost_byte_batched!(seal_hash_keccak_256_per_kb), - hash_blake2_256: cost_batched!(seal_hash_blake2_256), - hash_blake2_256_per_byte: cost_byte_batched!(seal_hash_blake2_256_per_kb), - 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), - reentrance_count: cost_batched!(seal_reentrance_count), - account_reentrance_count: cost_batched!(seal_account_reentrance_count), - instantiation_nonce: cost_batched!(seal_instantiation_nonce), + )), + hash_sha2_256: to_weight!(cost_batched!(seal_hash_sha2_256)), + hash_sha2_256_per_byte: to_weight!(cost_byte_batched!(seal_hash_sha2_256_per_kb)), + hash_keccak_256: to_weight!(cost_batched!(seal_hash_keccak_256)), + hash_keccak_256_per_byte: to_weight!(cost_byte_batched!(seal_hash_keccak_256_per_kb)), + hash_blake2_256: to_weight!(cost_batched!(seal_hash_blake2_256)), + hash_blake2_256_per_byte: to_weight!(cost_byte_batched!(seal_hash_blake2_256_per_kb)), + hash_blake2_128: to_weight!(cost_batched!(seal_hash_blake2_128)), + hash_blake2_128_per_byte: to_weight!(cost_byte_batched!(seal_hash_blake2_128_per_kb)), + ecdsa_recover: to_weight!(cost_batched!(seal_ecdsa_recover)), + ecdsa_to_eth_address: to_weight!(cost_batched!(seal_ecdsa_to_eth_address)), + reentrance_count: to_weight!(cost_batched!(seal_reentrance_count)), + account_reentrance_count: to_weight!(cost_batched!(seal_account_reentrance_count)), + instantiation_nonce: to_weight!(cost_batched!(seal_instantiation_nonce)), _phantom: PhantomData, } } diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index 7a0736d1ed61a..b9462ce45ec2f 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -416,7 +416,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(256 * 1024); +pub const GAS_LIMIT: Weight = Weight::from_parts(100_000_000_000, 512 * 1024); pub struct ExtBuilder { existential_deposit: u64, @@ -2837,7 +2837,7 @@ fn gas_estimation_call_runtime() { let call = RuntimeCall::Contracts(crate::Call::call { dest: addr_callee, value: 0, - gas_limit: GAS_LIMIT.set_ref_time(GAS_LIMIT.ref_time() / 3), + gas_limit: GAS_LIMIT / 3, storage_deposit_limit: None, data: vec![], }); diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index b540b3deb448d..c2b0611769429 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -430,7 +430,7 @@ mod tests { events: Default::default(), runtime_calls: Default::default(), schedule: Default::default(), - gas_meter: GasMeter::new(Weight::from_ref_time(10_000_000_000)), + gas_meter: GasMeter::new(Weight::from_parts(10_000_000_000, 10 * 1024 * 1024)), debug_buffer: Default::default(), ecdsa_recover: Default::default(), } diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index b5398bb6206c5..745583b337653 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -253,7 +253,7 @@ pub enum RuntimeCosts { /// Weight of calling `seal_ecdsa_recover`. EcdsaRecovery, /// Weight charged by a chain extension through `seal_call_chain_extension`. - ChainExtension(u64), + ChainExtension(Weight), /// Weight charged for calling into the runtime. CallRuntime(Weight), /// Weight of calling `seal_set_code_hash` @@ -272,7 +272,7 @@ impl RuntimeCosts { fn token(&self, s: &HostFnWeights) -> RuntimeToken { use self::RuntimeCosts::*; let weight = match *self { - MeteringBlock(amount) => s.gas.saturating_add(amount), + MeteringBlock(amount) => s.gas.saturating_add(Weight::from_ref_time(amount)), CopyFromContract(len) => s.return_per_byte.saturating_mul(len.into()), CopyToContract(len) => s.input_per_byte.saturating_mul(len.into()), Caller => s.caller, @@ -335,8 +335,8 @@ impl RuntimeCosts { .hash_blake2_128 .saturating_add(s.hash_blake2_128_per_byte.saturating_mul(len.into())), EcdsaRecovery => s.ecdsa_recover, - ChainExtension(amount) => amount, - CallRuntime(weight) => weight.ref_time(), + ChainExtension(weight) => weight, + CallRuntime(weight) => weight, SetCodeHash => s.set_code_hash, EcdsaToEthAddress => s.ecdsa_to_eth_address, ReentrantCount => s.reentrance_count, @@ -346,7 +346,7 @@ impl RuntimeCosts { RuntimeToken { #[cfg(test)] _created_from: *self, - weight: Weight::from_ref_time(weight), + weight, } } } From af5a499a269542cfd7f1aef415c801575f083d4a Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Wed, 18 Jan 2023 16:26:12 +0100 Subject: [PATCH 299/715] zobmienet tests are not supposed to fail (#13015) * zobmienet tests are not supposed to fail * Update scripts/ci/gitlab/pipeline/zombienet.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/zombienet.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/ci/gitlab/pipeline/zombienet.yml b/scripts/ci/gitlab/pipeline/zombienet.yml index 8d772ff51f9a7..7dc98c006808f 100644 --- a/scripts/ci/gitlab/pipeline/zombienet.yml +++ b/scripts/ci/gitlab/pipeline/zombienet.yml @@ -30,7 +30,6 @@ after_script: - mkdir -p ./zombienet-logs - cp /tmp/zombie*/logs/* ./zombienet-logs/ - allow_failure: true retry: 2 tags: - zombienet-polkadot-integration-test From cba59778aa5207b11f7513e5cbb127ea47dd8924 Mon Sep 17 00:00:00 2001 From: Sasha Gryaznov Date: Wed, 18 Jan 2023 18:03:52 +0200 Subject: [PATCH 300/715] [contracts] Add integrity checks by pallet hook (#12993) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * integrity test for MaxCodeLen and CallStack::len() * integrity test for MaxDebugBufferLen * addressed review comments * fix append_debug_buffer() * ci fix * updated code_len_limit formula after further discussion * enlarged mem safe margin after discussion * +doc to Config trait associated types * Apply suggestions from code review Co-authored-by: Alexander Theißen * more lil fixes from code review feedback * lowered max call depth to satisfy mem limits * fix node runtime pallet params to satisfy integrity check * fix max call depth value calc Co-authored-by: Alexander Theißen --- bin/node/runtime/src/lib.rs | 4 +- frame/contracts/src/exec.rs | 24 ++++++----- frame/contracts/src/lib.rs | 75 ++++++++++++++++++++++++++++++++- frame/contracts/src/schedule.rs | 4 -- frame/contracts/src/tests.rs | 4 +- 5 files changed, 91 insertions(+), 20 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index fb5da9749a2d1..0ac6ade9127e8 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1206,7 +1206,7 @@ impl pallet_contracts::Config for Runtime { type CallFilter = Nothing; type DepositPerItem = DepositPerItem; type DepositPerByte = DepositPerByte; - type CallStack = [pallet_contracts::Frame; 31]; + type CallStack = [pallet_contracts::Frame; 5]; type WeightPrice = pallet_transaction_payment::Pallet; type WeightInfo = pallet_contracts::weights::SubstrateWeight; type ChainExtension = (); @@ -1214,7 +1214,7 @@ impl pallet_contracts::Config for Runtime { type DeletionWeightLimit = DeletionWeightLimit; type Schedule = Schedule; type AddressGenerator = pallet_contracts::DefaultAddressGenerator; - type MaxCodeLen = ConstU32<{ 128 * 1024 }>; + type MaxCodeLen = ConstU32<{ 123 * 1024 }>; type MaxStorageKeyLen = ConstU32<128>; type UnsafeUnstableInterface = ConstBool; type MaxDebugBufferLen = ConstU32<{ 2 * 1024 * 1024 }>; diff --git a/frame/contracts/src/exec.rs b/frame/contracts/src/exec.rs index 8ae70b804d69b..b5b630653667b 100644 --- a/frame/contracts/src/exec.rs +++ b/frame/contracts/src/exec.rs @@ -1336,7 +1336,18 @@ where fn append_debug_buffer(&mut self, msg: &str) -> bool { if let Some(buffer) = &mut self.debug_message { - let mut msg = msg.bytes(); + let err_msg = scale_info::prelude::format!( + "Debug message too big (size={}) for debug buffer (bound={})", + msg.len(), + DebugBufferVec::::bound(), + ); + + let mut msg = if msg.len() > DebugBufferVec::::bound() { + err_msg.bytes() + } else { + msg.bytes() + }; + let num_drain = { let capacity = DebugBufferVec::::bound().checked_sub(buffer.len()).expect( " @@ -1349,16 +1360,7 @@ where msg.len().saturating_sub(capacity).min(buffer.len()) }; buffer.drain(0..num_drain); - buffer - .try_extend(&mut msg) - .map_err(|_| { - log::debug!( - target: "runtime::contracts", - "Debug message to big (size={}) for debug buffer (bound={})", - msg.len(), DebugBufferVec::::bound(), - ); - }) - .ok(); + buffer.try_extend(&mut msg).ok(); true } else { false diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index 581798e4488d6..672c4517d06a1 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -123,6 +123,7 @@ use pallet_contracts_primitives::{ StorageDeposit, }; use scale_info::TypeInfo; +use smallvec::Array; use sp_runtime::traits::{Convert, Hash, Saturating, StaticLookup, TrailingZeroInput}; use sp_std::{fmt::Debug, marker::PhantomData, prelude::*}; @@ -272,7 +273,10 @@ pub mod pallet { /// The allowed depth is `CallStack::size() + 1`. /// Therefore a size of `0` means that a contract cannot use call or instantiate. /// In other words only the origin called "root contract" is allowed to execute then. - type CallStack: smallvec::Array>; + /// + /// This setting along with [`MaxCodeLen`](#associatedtype.MaxCodeLen) directly affects + /// memory usage of your runtime. + type CallStack: Array>; /// The maximum number of contracts that can be pending for deletion. /// @@ -323,6 +327,10 @@ 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. + /// + /// The value should be chosen carefully taking into the account the overall memory limit + /// your runtime has, as well as the [maximum allowed callstack + /// depth](#associatedtype.CallStack). Look into the `integrity_test()` for some insights. #[pallet::constant] type MaxCodeLen: Get; @@ -372,6 +380,71 @@ pub mod pallet { T::WeightInfo::on_process_deletion_queue_batch() } } + + fn integrity_test() { + // Total runtime memory is expected to have 128Mb upper limit + const MAX_RUNTIME_MEM: u32 = 1024 * 1024 * 128; + // Memory limits for a single contract: + // Value stack size: 1Mb per contract, default defined in wasmi + const MAX_STACK_SIZE: u32 = 1024 * 1024; + // Heap limit is normally 16 mempages of 64kb each = 1Mb per contract + let max_heap_size = T::Schedule::get().limits.max_memory_size(); + // Max call depth is CallStack::size() + 1 + let max_call_depth = u32::try_from(T::CallStack::size().saturating_add(1)) + .expect("CallStack size is too big"); + + // Check that given configured `MaxCodeLen`, runtime heap memory limit can't be broken. + // + // In worst case, the decoded wasm contract code would be `x16` times larger than the + // encoded one. This is because even a single-byte wasm instruction has 16-byte size in + // wasmi. This gives us `MaxCodeLen*16` safety margin. + // + // Next, the pallet keeps both the original and instrumented wasm blobs for each + // contract, hence we add up `MaxCodeLen*2` more to the safety margin. + // + // Finally, the inefficiencies of the freeing-bump allocator + // being used in the client for the runtime memory allocations, could lead to possible + // memory allocations for contract code grow up to `x4` times in some extreme cases, + // which gives us total multiplier of `18*4` for `MaxCodeLen`. + // + // That being said, for every contract executed in runtime, at least `MaxCodeLen*18*4` + // memory should be available. Note that maximum allowed heap memory and stack size per + // each contract (stack frame) should also be counted. + // + // Finally, we allow 50% of the runtime memory to be utilized by the contracts call + // stack, keeping the rest for other facilities, such as PoV, etc. + // + // This gives us the following formula: + // + // `(MaxCodeLen * 18 * 4 + MAX_STACK_SIZE + max_heap_size) * max_call_depth < + // MAX_RUNTIME_MEM/2` + // + // Hence the upper limit for the `MaxCodeLen` can be defined as follows: + let code_len_limit = MAX_RUNTIME_MEM + .saturating_div(2) + .saturating_div(max_call_depth) + .saturating_sub(max_heap_size) + .saturating_sub(MAX_STACK_SIZE) + .saturating_div(18 * 4); + + assert!( + T::MaxCodeLen::get() < code_len_limit, + "Given `CallStack` height {:?}, `MaxCodeLen` should be set less than {:?} \ + (current value is {:?}), to avoid possible runtime oom issues.", + max_call_depth, + code_len_limit, + T::MaxCodeLen::get(), + ); + + // Debug buffer should at least be large enough to accomodate a simple error message + const MIN_DEBUG_BUF_SIZE: u32 = 256; + assert!( + T::MaxDebugBufferLen::get() > MIN_DEBUG_BUF_SIZE, + "Debug buffer should have minimum size of {} (current setting is {})", + MIN_DEBUG_BUF_SIZE, + T::MaxDebugBufferLen::get(), + ) + } } #[pallet::call] diff --git a/frame/contracts/src/schedule.rs b/frame/contracts/src/schedule.rs index dabdc70135916..eabd18c818952 100644 --- a/frame/contracts/src/schedule.rs +++ b/frame/contracts/src/schedule.rs @@ -134,9 +134,6 @@ pub struct Limits { /// The maximum length of a subject in bytes used for PRNG generation. pub subject_len: u32, - /// The maximum nesting level of the call stack. - pub call_depth: u32, - /// The maximum size of a storage value and event payload in bytes. pub payload_len: u32, } @@ -532,7 +529,6 @@ impl Default for Limits { table_size: 4096, br_table_size: 256, subject_len: 32, - call_depth: 32, payload_len: 16 * 1024, } } diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index b9462ce45ec2f..ce84da743d112 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -394,7 +394,7 @@ impl Config for Test { type RuntimeEvent = RuntimeEvent; type RuntimeCall = RuntimeCall; type CallFilter = TestFilter; - type CallStack = [Frame; 31]; + type CallStack = [Frame; 5]; type WeightPrice = Self; type WeightInfo = (); type ChainExtension = @@ -405,7 +405,7 @@ impl Config for Test { type DepositPerByte = DepositPerByte; type DepositPerItem = DepositPerItem; type AddressGenerator = DefaultAddressGenerator; - type MaxCodeLen = ConstU32<{ 128 * 1024 }>; + type MaxCodeLen = ConstU32<{ 123 * 1024 }>; type MaxStorageKeyLen = ConstU32<128>; type UnsafeUnstableInterface = UnstableInterface; type MaxDebugBufferLen = ConstU32<{ 2 * 1024 * 1024 }>; From 911c9ab067d3cf487cfef61906ed2525cb87a5c9 Mon Sep 17 00:00:00 2001 From: Tsvetomir Dimitrov Date: Thu, 19 Jan 2023 13:32:50 +0200 Subject: [PATCH 301/715] Expose `UnknownBlock` error via `ApiError` (#12707) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Expose `UnknownBlock` error via `ApiError` In [certain cases](https://github.com/paritytech/polkadot/issues/5885) a runtime api is called for an unknown block. For example a block which is already pruned or on an abandon fork. In such cases the correct error is returned but it is wrapped in `ApiError::Application` and the only way to figure out what is the problem is to inspect the actual message in the error. In polkadot for example this usually happens when the runtime api version is being queried. It's beneficial to be able to clearly separate such errors so i that when they occur the client side can handle them more gracefully. E.g. log less stressful error message than `State already discarded for BlockId` or cancel any pending work related on this block. * Update primitives/api/src/lib.rs Co-authored-by: Bastian Köcher Co-authored-by: Bastian Köcher --- primitives/api/src/lib.rs | 2 ++ primitives/blockchain/src/error.rs | 1 + 2 files changed, 3 insertions(+) diff --git a/primitives/api/src/lib.rs b/primitives/api/src/lib.rs index 91d4b07a1cefc..4ff4becb80f48 100644 --- a/primitives/api/src/lib.rs +++ b/primitives/api/src/lib.rs @@ -519,6 +519,8 @@ pub enum ApiError { StateBackendIsNotTrie, #[error(transparent)] Application(#[from] Box), + #[error("Api called for an unknown Block: {0}")] + UnknownBlock(String), } /// Extends the runtime api implementation with some common functionality. diff --git a/primitives/blockchain/src/error.rs b/primitives/blockchain/src/error.rs index 783c40c4061ad..6585cc54f1582 100644 --- a/primitives/blockchain/src/error.rs +++ b/primitives/blockchain/src/error.rs @@ -191,6 +191,7 @@ impl From> for Error { impl From for ApiError { fn from(err: Error) -> ApiError { match err { + Error::UnknownBlock(msg) => ApiError::UnknownBlock(msg), Error::RuntimeApiError(err) => err, e => ApiError::Application(Box::new(e)), } From d4384f242f48fd62516aac02c3f18b5a8c9e5793 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Thu, 19 Jan 2023 16:13:16 +0100 Subject: [PATCH 302/715] Notification-based block pinning (#13157) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Worker * Reorganize and unpin onnotification drop * Pin in state-db, pass block number * Pin blocks in blockchain db * Switch to reference counted LRU * Disable pinning when we keep all blocks * Fix pinning hint for state-db * Remove pinning from backend layer * Improve readability * Add justifications to test * Fix justification behaviour * Remove debug prints * Convert channels to tracing_unbounded * Add comments to the test * Documentation and Cleanup * Move task start to client * Simplify cache * Improve test, remove unwanted log * Add tracing logs, remove expect for block number * Cleanup * Add conversion method for unpin handle to Finalitynotification * Revert unwanted changes * Improve naming * Make clippy happy * Fix docs Co-authored-by: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> * Use `NumberFor` instead of u64 in API * Hand over weak reference to unpin worker task * Unwanted * &Hash -> Hash * Remove number from interface, rename `_unpin_handle`, LOG_TARGET * Move RwLock one layer up * Apply code style suggestions * Improve comments * Replace lru crate by schnellru * Only insert values for pinned items + better docs * Apply suggestions from code review Co-authored-by: Bastian Köcher * Improve comments, log target and test Co-authored-by: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Co-authored-by: Bastian Köcher --- Cargo.lock | 52 +- client/api/src/backend.rs | 22 +- client/api/src/client.rs | 109 +++- client/api/src/in_mem.rs | 6 + client/db/Cargo.toml | 1 + client/db/src/lib.rs | 531 ++++++++++++++++-- client/db/src/pinned_blocks_cache.rs | 231 ++++++++ client/finality-grandpa/src/until_imported.rs | 13 +- client/service/src/builder.rs | 4 +- client/service/src/client/client.rs | 77 ++- test-utils/client/src/lib.rs | 7 +- 11 files changed, 954 insertions(+), 99 deletions(-) create mode 100644 client/db/src/pinned_blocks_cache.rs diff --git a/Cargo.lock b/Cargo.lock index 446638277202a..100e0d2152096 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -137,6 +137,18 @@ dependencies = [ "version_check", ] +[[package]] +name = "ahash" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf6ccdb167abbf410dcb915cabd428929d7f6a04980b54a11f26a39f1c7f7107" +dependencies = [ + "cfg-if", + "getrandom 0.2.8", + "once_cell", + "version_check", +] + [[package]] name = "aho-corasick" version = "0.7.20" @@ -1836,7 +1848,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c24f403d068ad0b359e577a77f92392118be3f3c927538f2bb544a5ecd828c6" dependencies = [ "curve25519-dalek 3.2.0", - "hashbrown", + "hashbrown 0.12.3", "hex", "rand_core 0.6.4", "sha2 0.9.9", @@ -2806,9 +2818,15 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ - "ahash", + "ahash 0.7.6", ] +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" + [[package]] name = "heck" version = "0.4.0" @@ -3122,7 +3140,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" dependencies = [ "autocfg", - "hashbrown", + "hashbrown 0.12.3", "serde", ] @@ -4172,7 +4190,7 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6e8aaa3f231bb4bd57b84b2d5dc3ae7f350265df8aa96492e0bc394a1571909" dependencies = [ - "hashbrown", + "hashbrown 0.12.3", ] [[package]] @@ -4310,7 +4328,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e0c7cba9ce19ac7ffd2053ac9f49843bbd3f4318feedfd74e85c19d5fb0ba66" dependencies = [ "hash-db", - "hashbrown", + "hashbrown 0.12.3", ] [[package]] @@ -5085,7 +5103,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53" dependencies = [ "crc32fast", - "hashbrown", + "hashbrown 0.12.3", "indexmap", "memchr", ] @@ -7991,6 +8009,7 @@ dependencies = [ "rand 0.8.5", "sc-client-api", "sc-state-db", + "schnellru", "sp-arithmetic", "sp-blockchain", "sp-core", @@ -8334,7 +8353,7 @@ dependencies = [ name = "sc-finality-grandpa" version = "0.10.0-dev" dependencies = [ - "ahash", + "ahash 0.7.6", "array-bytes", "assert_matches", "async-trait", @@ -8534,7 +8553,7 @@ dependencies = [ name = "sc-network-gossip" version = "0.10.0-dev" dependencies = [ - "ahash", + "ahash 0.7.6", "futures", "futures-timer", "libp2p", @@ -9132,6 +9151,17 @@ dependencies = [ "windows-sys 0.36.1", ] +[[package]] +name = "schnellru" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "772575a524feeb803e5b0fcbc6dd9f367e579488197c94c6e4023aad2305774d" +dependencies = [ + "ahash 0.8.2", + "cfg-if", + "hashbrown 0.13.2", +] + [[package]] name = "schnorrkel" version = "0.9.1" @@ -10275,11 +10305,11 @@ dependencies = [ name = "sp-trie" version = "7.0.0" dependencies = [ - "ahash", + "ahash 0.7.6", "array-bytes", "criterion", "hash-db", - "hashbrown", + "hashbrown 0.12.3", "lazy_static", "lru", "memory-db", @@ -11279,7 +11309,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "004e1e8f92535694b4cb1444dc5a8073ecf0815e3357f729638b9f8fc4062908" dependencies = [ "hash-db", - "hashbrown", + "hashbrown 0.12.3", "log", "rustc-hex", "smallvec", diff --git a/client/api/src/backend.rs b/client/api/src/backend.rs index 21d213ffb15cf..4ef609bdd4525 100644 --- a/client/api/src/backend.rs +++ b/client/api/src/backend.rs @@ -436,12 +436,24 @@ pub trait StorageProvider> { /// /// Manages the data layer. /// -/// Note on state pruning: while an object from `state_at` is alive, the state +/// # State Pruning +/// +/// While an object from `state_at` is alive, the state /// should not be pruned. The backend should internally reference-count /// its state objects. /// /// The same applies for live `BlockImportOperation`s: while an import operation building on a /// parent `P` is alive, the state for `P` should not be pruned. +/// +/// # Block Pruning +/// +/// Users can pin blocks in memory by calling `pin_block`. When +/// a block would be pruned, its value is kept in an in-memory cache +/// until it is unpinned via `unpin_block`. +/// +/// While a block is pinned, its state is also preserved. +/// +/// The backend should internally reference count the number of pin / unpin calls. pub trait Backend: AuxStore + Send + Sync { /// Associated block insertion operation type. type BlockImportOperation: BlockImportOperation; @@ -502,6 +514,14 @@ pub trait Backend: AuxStore + Send + Sync { /// Returns a handle to offchain storage. fn offchain_storage(&self) -> Option; + /// Pin the block to keep body, justification and state available after pruning. + /// Number of pins are reference counted. Users need to make sure to perform + /// one call to [`Self::unpin_block`] per call to [`Self::pin_block`]. + fn pin_block(&self, hash: Block::Hash) -> sp_blockchain::Result<()>; + + /// Unpin the block to allow pruning. + fn unpin_block(&self, hash: Block::Hash); + /// Returns true if state for given block is available. fn have_state_at(&self, hash: Block::Hash, _number: NumberFor) -> bool { self.state_at(hash).is_ok() diff --git a/client/api/src/client.rs b/client/api/src/client.rs index 0d00257fa7b06..8e7ceb68704b2 100644 --- a/client/api/src/client.rs +++ b/client/api/src/client.rs @@ -30,7 +30,7 @@ use std::{collections::HashSet, fmt, sync::Arc}; use crate::{blockchain::Info, notifications::StorageEventStream, FinalizeSummary, ImportSummary}; use sc_transaction_pool_api::ChainEvent; -use sc_utils::mpsc::TracingUnboundedReceiver; +use sc_utils::mpsc::{TracingUnboundedReceiver, TracingUnboundedSender}; use sp_blockchain; /// Type that implements `futures::Stream` of block import events. @@ -264,6 +264,53 @@ impl fmt::Display for UsageInfo { } } +/// Sends a message to the pinning-worker once dropped to unpin a block in the backend. +#[derive(Debug)] +pub struct UnpinHandleInner { + /// Hash of the block pinned by this handle + hash: Block::Hash, + unpin_worker_sender: TracingUnboundedSender, +} + +impl UnpinHandleInner { + /// Create a new [`UnpinHandleInner`] + pub fn new( + hash: Block::Hash, + unpin_worker_sender: TracingUnboundedSender, + ) -> Self { + Self { hash, unpin_worker_sender } + } +} + +impl Drop for UnpinHandleInner { + fn drop(&mut self) { + if let Err(err) = self.unpin_worker_sender.unbounded_send(self.hash) { + log::debug!(target: "db", "Unable to unpin block with hash: {}, error: {:?}", self.hash, err); + }; + } +} + +/// Keeps a specific block pinned while the handle is alive. +/// Once the last handle instance for a given block is dropped, the +/// block is unpinned in the [`Backend`](crate::backend::Backend::unpin_block). +#[derive(Debug, Clone)] +pub struct UnpinHandle(Arc>); + +impl UnpinHandle { + /// Create a new [`UnpinHandle`] + pub fn new( + hash: Block::Hash, + unpin_worker_sender: TracingUnboundedSender, + ) -> UnpinHandle { + UnpinHandle(Arc::new(UnpinHandleInner::new(hash, unpin_worker_sender))) + } + + /// Hash of the block this handle is unpinning on drop + pub fn hash(&self) -> Block::Hash { + self.0.hash + } +} + /// Summary of an imported block #[derive(Clone, Debug)] pub struct BlockImportNotification { @@ -279,6 +326,36 @@ pub struct BlockImportNotification { /// /// If `None`, there was no re-org while importing. pub tree_route: Option>>, + /// Handle to unpin the block this notification is for + unpin_handle: UnpinHandle, +} + +impl BlockImportNotification { + /// Create new notification + pub fn new( + hash: Block::Hash, + origin: BlockOrigin, + header: Block::Header, + is_new_best: bool, + tree_route: Option>>, + unpin_worker_sender: TracingUnboundedSender, + ) -> Self { + Self { + hash, + origin, + header, + is_new_best, + tree_route, + unpin_handle: UnpinHandle::new(hash, unpin_worker_sender), + } + } + + /// Consume this notification and extract the unpin handle. + /// + /// Note: Only use this if you want to keep the block pinned in the backend. + pub fn into_unpin_handle(self) -> UnpinHandle { + self.unpin_handle + } } /// Summary of a finalized block. @@ -294,6 +371,8 @@ pub struct FinalityNotification { pub tree_route: Arc<[Block::Hash]>, /// Stale branches heads. pub stale_heads: Arc<[Block::Hash]>, + /// Handle to unpin the block this notification is for + unpin_handle: UnpinHandle, } impl TryFrom> for ChainEvent { @@ -314,26 +393,44 @@ impl From> for ChainEvent { } } -impl From> for FinalityNotification { - fn from(mut summary: FinalizeSummary) -> Self { +impl FinalityNotification { + /// Create finality notification from finality summary. + pub fn from_summary( + mut summary: FinalizeSummary, + unpin_worker_sender: TracingUnboundedSender, + ) -> FinalityNotification { let hash = summary.finalized.pop().unwrap_or_default(); FinalityNotification { hash, header: summary.header, tree_route: Arc::from(summary.finalized), stale_heads: Arc::from(summary.stale_heads), + unpin_handle: UnpinHandle::new(hash, unpin_worker_sender), } } + + /// Consume this notification and extract the unpin handle. + /// + /// Note: Only use this if you want to keep the block pinned in the backend. + pub fn into_unpin_handle(self) -> UnpinHandle { + self.unpin_handle + } } -impl From> for BlockImportNotification { - fn from(summary: ImportSummary) -> Self { +impl BlockImportNotification { + /// Create finality notification from finality summary. + pub fn from_summary( + summary: ImportSummary, + unpin_worker_sender: TracingUnboundedSender, + ) -> BlockImportNotification { + let hash = summary.hash; BlockImportNotification { - hash: summary.hash, + hash, origin: summary.origin, header: summary.header, is_new_best: summary.is_new_best, tree_route: summary.tree_route.map(Arc::new), + unpin_handle: UnpinHandle::new(hash, unpin_worker_sender), } } } diff --git a/client/api/src/in_mem.rs b/client/api/src/in_mem.rs index 144aa352f5533..5e82757e7d9cd 100644 --- a/client/api/src/in_mem.rs +++ b/client/api/src/in_mem.rs @@ -788,6 +788,12 @@ where fn requires_full_sync(&self) -> bool { false } + + fn pin_block(&self, _: ::Hash) -> blockchain::Result<()> { + Ok(()) + } + + fn unpin_block(&self, _: ::Hash) {} } impl backend::LocalBackend for Backend where Block::Hash: Ord {} diff --git a/client/db/Cargo.toml b/client/db/Cargo.toml index 562a94f1900d6..2d7291a014d6e 100644 --- a/client/db/Cargo.toml +++ b/client/db/Cargo.toml @@ -26,6 +26,7 @@ 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" } +schnellru = "0.2.1" sp-arithmetic = { version = "6.0.0", path = "../../primitives/arithmetic" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-core = { version = "7.0.0", path = "../../primitives/core" } diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index 99fa786e04036..09ccfef1cc28b 100644 --- a/client/db/src/lib.rs +++ b/client/db/src/lib.rs @@ -34,6 +34,7 @@ pub mod bench; mod children; mod parity_db; +mod pinned_blocks_cache; mod record_stats_state; mod stats; #[cfg(any(feature = "rocksdb", test))] @@ -51,6 +52,7 @@ use std::{ }; use crate::{ + pinned_blocks_cache::PinnedBlocksCache, record_stats_state::RecordStatsState, stats::StateUsageStats, utils::{meta_keys, read_db, read_meta, DatabaseType, Meta}, @@ -481,6 +483,7 @@ pub struct BlockchainDb { leaves: RwLock>>, header_metadata_cache: Arc>, header_cache: Mutex>>, + pinned_blocks_cache: Arc>>, } impl BlockchainDb { @@ -493,6 +496,7 @@ impl BlockchainDb { meta: Arc::new(RwLock::new(meta)), header_metadata_cache: Arc::new(HeaderMetadataCache::default()), header_cache: Default::default(), + pinned_blocks_cache: Arc::new(RwLock::new(PinnedBlocksCache::new())), }) } @@ -521,62 +525,83 @@ impl BlockchainDb { let mut meta = self.meta.write(); meta.block_gap = gap; } -} -impl sc_client_api::blockchain::HeaderBackend for BlockchainDb { - fn header(&self, hash: Block::Hash) -> ClientResult> { - let mut cache = self.header_cache.lock(); - if let Some(result) = cache.get_refresh(&hash) { - return Ok(result.clone()) + /// Empty the cache of pinned items. + fn clear_pinning_cache(&self) { + self.pinned_blocks_cache.write().clear(); + } + + /// Load a justification into the cache of pinned items. + /// Reference count of the item will not be increased. Use this + /// to load values for items into the cache which have already been pinned. + fn insert_justifications_if_pinned(&self, hash: Block::Hash, justification: Justification) { + let mut cache = self.pinned_blocks_cache.write(); + if !cache.contains(hash) { + return } - let header = utils::read_header( - &*self.db, - columns::KEY_LOOKUP, - columns::HEADER, - BlockId::::Hash(hash), - )?; - cache_header(&mut cache, hash, header.clone()); - Ok(header) + + let justifications = Justifications::from(justification); + cache.insert_justifications(hash, Some(justifications)); } - fn info(&self) -> sc_client_api::blockchain::Info { - let meta = self.meta.read(); - sc_client_api::blockchain::Info { - best_hash: meta.best_hash, - best_number: meta.best_number, - genesis_hash: meta.genesis_hash, - finalized_hash: meta.finalized_hash, - finalized_number: meta.finalized_number, - finalized_state: meta.finalized_state, - number_leaves: self.leaves.read().count(), - block_gap: meta.block_gap, + /// Load a justification from the db into the cache of pinned items. + /// Reference count of the item will not be increased. Use this + /// to load values for items into the cache which have already been pinned. + fn insert_persisted_justifications_if_pinned(&self, hash: Block::Hash) -> ClientResult<()> { + let mut cache = self.pinned_blocks_cache.write(); + if !cache.contains(hash) { + return Ok(()) } + + let justifications = self.justifications_uncached(hash)?; + cache.insert_justifications(hash, justifications); + Ok(()) } - fn status(&self, hash: Block::Hash) -> ClientResult { - match self.header(hash)?.is_some() { - true => Ok(sc_client_api::blockchain::BlockStatus::InChain), - false => Ok(sc_client_api::blockchain::BlockStatus::Unknown), + /// Load a block body from the db into the cache of pinned items. + /// Reference count of the item will not be increased. Use this + /// to load values for items items into the cache which have already been pinned. + fn insert_persisted_body_if_pinned(&self, hash: Block::Hash) -> ClientResult<()> { + let mut cache = self.pinned_blocks_cache.write(); + if !cache.contains(hash) { + return Ok(()) } + + let body = self.body_uncached(hash)?; + cache.insert_body(hash, body); + Ok(()) } - fn number(&self, hash: Block::Hash) -> ClientResult>> { - Ok(self.header_metadata(hash).ok().map(|header_metadata| header_metadata.number)) + /// Bump reference count for pinned item. + fn bump_ref(&self, hash: Block::Hash) { + self.pinned_blocks_cache.write().pin(hash); } - fn hash(&self, number: NumberFor) -> ClientResult> { - Ok(utils::read_header::( + /// Decrease reference count for pinned item and remove if reference count is 0. + fn unpin(&self, hash: Block::Hash) { + self.pinned_blocks_cache.write().unpin(hash); + } + + fn justifications_uncached(&self, hash: Block::Hash) -> ClientResult> { + match read_db( &*self.db, columns::KEY_LOOKUP, - columns::HEADER, - BlockId::Number(number), - )? - .map(|header| header.hash())) + columns::JUSTIFICATIONS, + BlockId::::Hash(hash), + )? { + Some(justifications) => match Decode::decode(&mut &justifications[..]) { + Ok(justifications) => Ok(Some(justifications)), + Err(err) => + return Err(sp_blockchain::Error::Backend(format!( + "Error decoding justifications: {}", + err + ))), + }, + None => Ok(None), + } } -} -impl sc_client_api::blockchain::Backend for BlockchainDb { - fn body(&self, hash: Block::Hash) -> ClientResult>> { + fn body_uncached(&self, hash: Block::Hash) -> ClientResult>> { if let Some(body) = read_db(&*self.db, columns::KEY_LOOKUP, columns::BODY, BlockId::Hash::(hash))? { @@ -640,24 +665,77 @@ impl sc_client_api::blockchain::Backend for BlockchainDb ClientResult> { - match read_db( +impl sc_client_api::blockchain::HeaderBackend for BlockchainDb { + fn header(&self, hash: Block::Hash) -> ClientResult> { + let mut cache = self.header_cache.lock(); + if let Some(result) = cache.get_refresh(&hash) { + return Ok(result.clone()) + } + let header = utils::read_header( &*self.db, columns::KEY_LOOKUP, - columns::JUSTIFICATIONS, + columns::HEADER, BlockId::::Hash(hash), - )? { - Some(justifications) => match Decode::decode(&mut &justifications[..]) { - Ok(justifications) => Ok(Some(justifications)), - Err(err) => - return Err(sp_blockchain::Error::Backend(format!( - "Error decoding justifications: {}", - err - ))), - }, - None => Ok(None), + )?; + cache_header(&mut cache, hash, header.clone()); + Ok(header) + } + + fn info(&self) -> sc_client_api::blockchain::Info { + let meta = self.meta.read(); + sc_client_api::blockchain::Info { + best_hash: meta.best_hash, + best_number: meta.best_number, + genesis_hash: meta.genesis_hash, + finalized_hash: meta.finalized_hash, + finalized_number: meta.finalized_number, + finalized_state: meta.finalized_state, + number_leaves: self.leaves.read().count(), + block_gap: meta.block_gap, + } + } + + fn status(&self, hash: Block::Hash) -> ClientResult { + match self.header(hash)?.is_some() { + true => Ok(sc_client_api::blockchain::BlockStatus::InChain), + false => Ok(sc_client_api::blockchain::BlockStatus::Unknown), + } + } + + fn number(&self, hash: Block::Hash) -> ClientResult>> { + Ok(self.header_metadata(hash).ok().map(|header_metadata| header_metadata.number)) + } + + fn hash(&self, number: NumberFor) -> ClientResult> { + Ok(utils::read_header::( + &*self.db, + columns::KEY_LOOKUP, + columns::HEADER, + BlockId::Number(number), + )? + .map(|header| header.hash())) + } +} + +impl sc_client_api::blockchain::Backend for BlockchainDb { + fn body(&self, hash: Block::Hash) -> ClientResult>> { + let cache = self.pinned_blocks_cache.read(); + if let Some(result) = cache.body(&hash) { + return Ok(result.clone()) + } + + self.body_uncached(hash) + } + + fn justifications(&self, hash: Block::Hash) -> ClientResult> { + let cache = self.pinned_blocks_cache.read(); + if let Some(result) = cache.justifications(&hash) { + return Ok(result.clone()) } + + self.justifications_uncached(hash) } fn last_finalized(&self) -> ClientResult { @@ -1291,20 +1369,28 @@ impl Backend { header: &Block::Header, last_finalized: Option, justification: Option, + current_transaction_justifications: &mut HashMap, ) -> ClientResult> { // 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); - self.note_finalized(transaction, header, hash, with_state)?; + self.note_finalized( + transaction, + header, + hash, + with_state, + current_transaction_justifications, + )?; if let Some(justification) = justification { transaction.set_from_vec( columns::JUSTIFICATIONS, &utils::number_and_hash_to_lookup_key(number, hash)?, - Justifications::from(justification).encode(), + Justifications::from(justification.clone()).encode(), ); + current_transaction_justifications.insert(hash, justification); } Ok(MetaUpdate { hash, number, is_best: false, is_finalized: true, with_state }) } @@ -1371,6 +1457,8 @@ impl Backend { (meta.best_number, meta.finalized_hash, meta.finalized_number, meta.block_gap) }; + let mut current_transaction_justifications: HashMap = + HashMap::new(); for (block_hash, justification) in operation.finalized_blocks { let block_header = self.blockchain.expect_header(block_hash)?; meta_updates.push(self.finalize_block_with_transaction( @@ -1379,6 +1467,7 @@ impl Backend { &block_header, Some(last_finalized_hash), justification, + &mut current_transaction_justifications, )?); last_finalized_hash = block_hash; last_finalized_num = *block_header.number(); @@ -1551,7 +1640,14 @@ impl Backend { if finalized { // TODO: ensure best chain contains this block. self.ensure_sequential_finalization(header, Some(last_finalized_hash))?; - self.note_finalized(&mut transaction, header, hash, operation.commit_state)?; + let mut current_transaction_justifications = HashMap::new(); + self.note_finalized( + &mut transaction, + header, + hash, + operation.commit_state, + &mut current_transaction_justifications, + )?; } else { // canonicalize blocks which are old enough, regardless of finality. self.force_delayed_canonicalize(&mut transaction)? @@ -1684,6 +1780,7 @@ impl Backend { f_header: &Block::Header, f_hash: Block::Hash, with_state: bool, + current_transaction_justifications: &mut HashMap, ) -> ClientResult<()> { let f_num = *f_header.number(); @@ -1709,7 +1806,7 @@ impl Backend { } let new_displaced = self.blockchain.leaves.write().finalize_height(f_num); - self.prune_blocks(transaction, f_num, &new_displaced)?; + self.prune_blocks(transaction, f_num, &new_displaced, current_transaction_justifications)?; Ok(()) } @@ -1717,22 +1814,39 @@ impl Backend { fn prune_blocks( &self, transaction: &mut Transaction, - finalized: NumberFor, + finalized_number: NumberFor, displaced: &FinalizationOutcome>, + current_transaction_justifications: &mut HashMap, ) -> ClientResult<()> { 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()); + if finalized_number >= keep.into() { + let number = finalized_number.saturating_sub(keep.into()); + + // Before we prune a block, check if it is pinned + if let Some(hash) = self.blockchain.hash(number)? { + self.blockchain.insert_persisted_body_if_pinned(hash)?; + + // If the block was finalized in this transaction, it will not be in the db + // yet. + if let Some(justification) = + current_transaction_justifications.remove(&hash) + { + self.blockchain.insert_justifications_if_pinned(hash, justification); + } else { + self.blockchain.insert_persisted_justifications_if_pinned(hash)?; + } + }; + self.prune_block(transaction, BlockId::::number(number))?; } - self.prune_displaced_branches(transaction, finalized, displaced)?; + self.prune_displaced_branches(transaction, finalized_number, displaced)?; }, BlocksPruning::KeepFinalized => { - self.prune_displaced_branches(transaction, finalized, displaced)?; + self.prune_displaced_branches(transaction, finalized_number, displaced)?; }, } Ok(()) @@ -1755,6 +1869,8 @@ impl Backend { while self.blockchain.hash(number)? != Some(hash) { match self.blockchain.header(hash)? { Some(header) => { + self.blockchain.insert_persisted_body_if_pinned(hash)?; + self.prune_block(transaction, BlockId::::hash(hash))?; number = header.number().saturating_sub(One::one()); hash = *header.parent_hash(); @@ -1985,6 +2101,7 @@ impl sc_client_api::backend::Backend for Backend { .state_db .reset(state_meta_db) .map_err(sp_blockchain::Error::from_state_db)?; + self.blockchain.clear_pinning_cache(); Err(e) } else { self.storage.state_db.sync(); @@ -2000,12 +2117,14 @@ impl sc_client_api::backend::Backend for Backend { let mut transaction = Transaction::new(); let header = self.blockchain.expect_header(hash)?; + let mut current_transaction_justifications = HashMap::new(); let m = self.finalize_block_with_transaction( &mut transaction, hash, &header, None, justification, + &mut current_transaction_justifications, )?; self.storage.db.commit(transaction)?; @@ -2382,6 +2501,49 @@ impl sc_client_api::backend::Backend for Backend { PruningMode::ArchiveAll | PruningMode::ArchiveCanonical ) } + + fn pin_block(&self, hash: ::Hash) -> sp_blockchain::Result<()> { + let hint = || { + let header_metadata = self.blockchain.header_metadata(hash); + header_metadata + .map(|hdr| { + sc_state_db::NodeDb::get(self.storage.as_ref(), hdr.state_root.as_ref()) + .unwrap_or(None) + .is_some() + }) + .unwrap_or(false) + }; + + if let Some(number) = self.blockchain.number(hash)? { + self.storage.state_db.pin(&hash, number.saturated_into::(), hint).map_err( + |_| { + sp_blockchain::Error::UnknownBlock(format!( + "State already discarded for `{:?}`", + hash + )) + }, + )?; + } else { + return Err(ClientError::UnknownBlock(format!( + "Can not pin block with hash `{:?}`. Block not found.", + hash + ))) + } + + if self.blocks_pruning != BlocksPruning::KeepAll { + // Only increase reference count for this hash. Value is loaded once we prune. + self.blockchain.bump_ref(hash); + } + Ok(()) + } + + fn unpin_block(&self, hash: ::Hash) { + self.storage.state_db.unpin(&hash); + + if self.blocks_pruning != BlocksPruning::KeepAll { + self.blockchain.unpin(hash); + } + } } impl sc_client_api::backend::LocalBackend for Backend {} @@ -4009,4 +4171,249 @@ pub(crate) mod tests { assert_eq!(block4, backend.blockchain().hash(4).unwrap().unwrap()); } } + + #[test] + fn test_pinned_blocks_on_finalize() { + let backend = Backend::::new_test_with_tx_storage(BlocksPruning::Some(1), 10); + let mut blocks = Vec::new(); + let mut prev_hash = Default::default(); + + let build_justification = |i: u64| ([0, 0, 0, 0], vec![i.try_into().unwrap()]); + // Block tree: + // 0 -> 1 -> 2 -> 3 -> 4 + for i in 0..5 { + let hash = insert_block( + &backend, + i, + prev_hash, + None, + Default::default(), + vec![i.into()], + None, + ) + .unwrap(); + blocks.push(hash); + // Avoid block pruning. + backend.pin_block(blocks[i as usize]).unwrap(); + + prev_hash = hash; + } + + let bc = backend.blockchain(); + + // Check that we can properly access values when there is reference count + // but no value. + assert_eq!(Some(vec![1.into()]), bc.body(blocks[1]).unwrap()); + + // Block 1 gets pinned three times + backend.pin_block(blocks[1]).unwrap(); + backend.pin_block(blocks[1]).unwrap(); + + // Finalize all blocks. This will trigger pruning. + let mut op = backend.begin_operation().unwrap(); + backend.begin_state_operation(&mut op, blocks[4]).unwrap(); + for i in 1..5 { + op.mark_finalized(blocks[i], Some(build_justification(i.try_into().unwrap()))) + .unwrap(); + } + backend.commit_operation(op).unwrap(); + + // Block 0, 1, 2, 3 are pinned, so all values should be cached. + // Block 4 is inside the pruning window, its value is in db. + 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(Justifications::from(build_justification(1))), + bc.justifications(blocks[1]).unwrap() + ); + + assert_eq!(Some(vec![2.into()]), bc.body(blocks[2]).unwrap()); + assert_eq!( + Some(Justifications::from(build_justification(2))), + bc.justifications(blocks[2]).unwrap() + ); + + assert_eq!(Some(vec![3.into()]), bc.body(blocks[3]).unwrap()); + assert_eq!( + Some(Justifications::from(build_justification(3))), + bc.justifications(blocks[3]).unwrap() + ); + + assert_eq!(Some(vec![4.into()]), bc.body(blocks[4]).unwrap()); + assert_eq!( + Some(Justifications::from(build_justification(4))), + bc.justifications(blocks[4]).unwrap() + ); + + // Unpin all blocks. Values should be removed from cache. + for block in &blocks { + backend.unpin_block(*block); + } + + assert!(bc.body(blocks[0]).unwrap().is_none()); + // Block 1 was pinned twice, we expect it to be still cached + assert!(bc.body(blocks[1]).unwrap().is_some()); + assert!(bc.justifications(blocks[1]).unwrap().is_some()); + // Headers should also be available while pinned + assert!(bc.header(blocks[1]).ok().flatten().is_some()); + assert!(bc.body(blocks[2]).unwrap().is_none()); + assert!(bc.justifications(blocks[2]).unwrap().is_none()); + assert!(bc.body(blocks[3]).unwrap().is_none()); + assert!(bc.justifications(blocks[3]).unwrap().is_none()); + + // After these unpins, block 1 should also be removed + backend.unpin_block(blocks[1]); + assert!(bc.body(blocks[1]).unwrap().is_some()); + assert!(bc.justifications(blocks[1]).unwrap().is_some()); + backend.unpin_block(blocks[1]); + assert!(bc.body(blocks[1]).unwrap().is_none()); + assert!(bc.justifications(blocks[1]).unwrap().is_none()); + + // Block 4 is inside the pruning window and still kept + assert_eq!(Some(vec![4.into()]), bc.body(blocks[4]).unwrap()); + assert_eq!( + Some(Justifications::from(build_justification(4))), + bc.justifications(blocks[4]).unwrap() + ); + + // Block tree: + // 0 -> 1 -> 2 -> 3 -> 4 -> 5 + let hash = + insert_block(&backend, 5, prev_hash, None, Default::default(), vec![5.into()], None) + .unwrap(); + blocks.push(hash); + + backend.pin_block(blocks[4]).unwrap(); + // Mark block 5 as finalized. + let mut op = backend.begin_operation().unwrap(); + backend.begin_state_operation(&mut op, blocks[5]).unwrap(); + op.mark_finalized(blocks[5], Some(build_justification(5))).unwrap(); + backend.commit_operation(op).unwrap(); + + assert!(bc.body(blocks[0]).unwrap().is_none()); + assert!(bc.body(blocks[1]).unwrap().is_none()); + assert!(bc.body(blocks[2]).unwrap().is_none()); + assert!(bc.body(blocks[3]).unwrap().is_none()); + + assert_eq!(Some(vec![4.into()]), bc.body(blocks[4]).unwrap()); + assert_eq!( + Some(Justifications::from(build_justification(4))), + bc.justifications(blocks[4]).unwrap() + ); + assert_eq!(Some(vec![5.into()]), bc.body(blocks[5]).unwrap()); + assert!(bc.header(blocks[5]).ok().flatten().is_some()); + + backend.unpin_block(blocks[4]); + assert!(bc.body(blocks[4]).unwrap().is_none()); + assert!(bc.justifications(blocks[4]).unwrap().is_none()); + + // Append a justification to block 5. + backend.append_justification(blocks[5], ([0, 0, 0, 1], vec![42])).unwrap(); + + let hash = + insert_block(&backend, 6, blocks[5], None, Default::default(), vec![6.into()], None) + .unwrap(); + blocks.push(hash); + + // Pin block 5 so it gets loaded into the cache on prune + backend.pin_block(blocks[5]).unwrap(); + + // Finalize block 6 so block 5 gets pruned. Since it is pinned both justifications should be + // in memory. + let mut op = backend.begin_operation().unwrap(); + backend.begin_state_operation(&mut op, blocks[6]).unwrap(); + op.mark_finalized(blocks[6], None).unwrap(); + backend.commit_operation(op).unwrap(); + + assert_eq!(Some(vec![5.into()]), bc.body(blocks[5]).unwrap()); + assert!(bc.header(blocks[5]).ok().flatten().is_some()); + let mut expected = Justifications::from(build_justification(5)); + expected.append(([0, 0, 0, 1], vec![42])); + assert_eq!(Some(expected), bc.justifications(blocks[5]).unwrap()); + } + + #[test] + fn test_pinned_blocks_on_finalize_with_fork() { + let backend = Backend::::new_test_with_tx_storage(BlocksPruning::Some(1), 10); + let mut blocks = Vec::new(); + let mut prev_hash = Default::default(); + + // Block tree: + // 0 -> 1 -> 2 -> 3 -> 4 + for i in 0..5 { + let hash = insert_block( + &backend, + i, + prev_hash, + None, + Default::default(), + vec![i.into()], + None, + ) + .unwrap(); + blocks.push(hash); + + // Avoid block pruning. + backend.pin_block(blocks[i as usize]).unwrap(); + + prev_hash = hash; + } + + // Insert a fork at the second block. + // Block tree: + // 0 -> 1 -> 2 -> 3 -> 4 + // \ -> 2 -> 3 + let fork_hash_root = + insert_block(&backend, 2, blocks[1], None, H256::random(), vec![2.into()], None) + .unwrap(); + let fork_hash_3 = insert_block( + &backend, + 3, + fork_hash_root, + None, + H256::random(), + vec![3.into(), 11.into()], + None, + ) + .unwrap(); + + // Do not prune the fork hash. + backend.pin_block(fork_hash_3).unwrap(); + + let mut op = backend.begin_operation().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.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()); + // Check the fork hashes. + assert_eq!(None, bc.body(fork_hash_root).unwrap()); + assert_eq!(Some(vec![3.into(), 11.into()]), bc.body(fork_hash_3).unwrap()); + + // Unpin all blocks, except the forked one. + for block in &blocks { + backend.unpin_block(*block); + } + assert!(bc.body(blocks[0]).unwrap().is_none()); + assert!(bc.body(blocks[1]).unwrap().is_none()); + assert!(bc.body(blocks[2]).unwrap().is_none()); + assert!(bc.body(blocks[3]).unwrap().is_none()); + + assert!(bc.body(fork_hash_3).unwrap().is_some()); + backend.unpin_block(fork_hash_3); + assert!(bc.body(fork_hash_3).unwrap().is_none()); + } } diff --git a/client/db/src/pinned_blocks_cache.rs b/client/db/src/pinned_blocks_cache.rs new file mode 100644 index 0000000000000..39ff1c5277871 --- /dev/null +++ b/client/db/src/pinned_blocks_cache.rs @@ -0,0 +1,231 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2023 Parity Technologies (UK) Ltd. +// SPDX-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 schnellru::{Limiter, LruMap}; +use sp_runtime::{traits::Block as BlockT, Justifications}; + +const LOG_TARGET: &str = "db::pin"; +const PINNING_CACHE_SIZE: usize = 1024; + +/// Entry for pinned blocks cache. +struct PinnedBlockCacheEntry { + /// How many times this item has been pinned + ref_count: u32, + + /// Cached justifications for this block + pub justifications: Option>, + + /// Cached body for this block + pub body: Option>>, +} + +impl Default for PinnedBlockCacheEntry { + fn default() -> Self { + Self { ref_count: 0, justifications: None, body: None } + } +} + +impl PinnedBlockCacheEntry { + pub fn decrease_ref(&mut self) { + self.ref_count = self.ref_count.saturating_sub(1); + } + + pub fn increase_ref(&mut self) { + self.ref_count = self.ref_count.saturating_add(1); + } + + pub fn has_no_references(&self) -> bool { + self.ref_count == 0 + } +} + +/// A limiter for a map which is limited by the number of elements. +#[derive(Copy, Clone, Debug)] +struct LoggingByLengthLimiter { + max_length: usize, +} + +impl LoggingByLengthLimiter { + /// Creates a new length limiter with a given `max_length`. + pub const fn new(max_length: usize) -> LoggingByLengthLimiter { + LoggingByLengthLimiter { max_length } + } +} + +impl Limiter> for LoggingByLengthLimiter { + type KeyToInsert<'a> = Block::Hash; + type LinkType = usize; + + fn is_over_the_limit(&self, length: usize) -> bool { + length > self.max_length + } + + fn on_insert( + &mut self, + _length: usize, + key: Self::KeyToInsert<'_>, + value: PinnedBlockCacheEntry, + ) -> Option<(Block::Hash, PinnedBlockCacheEntry)> { + if self.max_length > 0 { + Some((key, value)) + } else { + None + } + } + + fn on_replace( + &mut self, + _length: usize, + _old_key: &mut Block::Hash, + _new_key: Block::Hash, + _old_value: &mut PinnedBlockCacheEntry, + _new_value: &mut PinnedBlockCacheEntry, + ) -> bool { + true + } + + fn on_removed(&mut self, key: &mut Block::Hash, value: &mut PinnedBlockCacheEntry) { + // If reference count was larger than 0 on removal, + // the item was removed due to capacity limitations. + // Since the cache should be large enough for pinned items, + // we want to know about these evictions. + if value.ref_count > 0 { + log::warn!( + target: LOG_TARGET, + "Pinned block cache limit reached. Evicting value. hash = {}", + key + ); + } else { + log::trace!( + target: LOG_TARGET, + "Evicting value from pinned block cache. hash = {}", + key + ) + } + } + + fn on_cleared(&mut self) {} + + fn on_grow(&mut self, _new_memory_usage: usize) -> bool { + true + } +} + +/// Reference counted cache for pinned block bodies and justifications. +pub struct PinnedBlocksCache { + cache: LruMap, LoggingByLengthLimiter>, +} + +impl PinnedBlocksCache { + pub fn new() -> Self { + Self { cache: LruMap::new(LoggingByLengthLimiter::new(PINNING_CACHE_SIZE)) } + } + + /// Increase reference count of an item. + /// Create an entry with empty value in the cache if necessary. + pub fn pin(&mut self, hash: Block::Hash) { + match self.cache.get_or_insert(hash, Default::default) { + Some(entry) => { + entry.increase_ref(); + log::trace!( + target: LOG_TARGET, + "Bumped cache refcount. hash = {}, num_entries = {}", + hash, + self.cache.len() + ); + }, + None => + log::warn!(target: LOG_TARGET, "Unable to bump reference count. hash = {}", hash), + }; + } + + /// Clear the cache + pub fn clear(&mut self) { + self.cache.clear(); + } + + /// Check if item is contained in the cache + pub fn contains(&self, hash: Block::Hash) -> bool { + self.cache.peek(&hash).is_some() + } + + /// Attach body to an existing cache item + pub fn insert_body(&mut self, hash: Block::Hash, extrinsics: Option>) { + match self.cache.peek_mut(&hash) { + Some(mut entry) => { + entry.body = Some(extrinsics); + log::trace!( + target: LOG_TARGET, + "Cached body. hash = {}, num_entries = {}", + hash, + self.cache.len() + ); + }, + None => log::warn!( + target: LOG_TARGET, + "Unable to insert body for uncached item. hash = {}", + hash + ), + } + } + + /// Attach justification to an existing cache item + pub fn insert_justifications( + &mut self, + hash: Block::Hash, + justifications: Option, + ) { + match self.cache.peek_mut(&hash) { + Some(mut entry) => { + entry.justifications = Some(justifications); + log::trace!( + target: LOG_TARGET, + "Cached justification. hash = {}, num_entries = {}", + hash, + self.cache.len() + ); + }, + None => log::warn!( + target: LOG_TARGET, + "Unable to insert justifications for uncached item. hash = {}", + hash + ), + } + } + + /// Decreases reference count of an item. + /// If the count hits 0, the item is removed. + pub fn unpin(&mut self, hash: Block::Hash) { + if let Some(entry) = self.cache.peek_mut(&hash) { + entry.decrease_ref(); + if entry.has_no_references() { + self.cache.remove(&hash); + } + } + } + + /// Get justifications for cached block + pub fn justifications(&self, hash: &Block::Hash) -> Option<&Option> { + self.cache.peek(hash).and_then(|entry| entry.justifications.as_ref()) + } + + /// Get body for cached block + pub fn body(&self, hash: &Block::Hash) -> Option<&Option>> { + self.cache.peek(hash).and_then(|entry| entry.body.as_ref()) + } +} diff --git a/client/finality-grandpa/src/until_imported.rs b/client/finality-grandpa/src/until_imported.rs index 776411f8fb493..3bca77ae8393f 100644 --- a/client/finality-grandpa/src/until_imported.rs +++ b/client/finality-grandpa/src/until_imported.rs @@ -593,16 +593,17 @@ mod tests { fn import_header(&self, header: Header) { let hash = header.hash(); let number = *header.number(); - + let (tx, _rx) = tracing_unbounded("unpin-worker-channel", 10_000); self.known_blocks.lock().insert(hash, number); self.sender - .unbounded_send(BlockImportNotification { + .unbounded_send(BlockImportNotification::::new( hash, - origin: BlockOrigin::File, + BlockOrigin::File, header, - is_new_best: false, - tree_route: None, - }) + false, + None, + tx, + )) .unwrap(); } } diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index 1f94f96fae89e..0b09f550ce338 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -329,13 +329,15 @@ where let executor = crate::client::LocalCallExecutor::new( backend.clone(), executor, - spawn_handle, + spawn_handle.clone(), config.clone(), execution_extensions, )?; + crate::client::Client::new( backend, executor, + spawn_handle, genesis_block_builder, fork_blocks, bad_blocks, diff --git a/client/service/src/client/client.rs b/client/service/src/client/client.rs index 8e10a7b2eda0a..d32baa671f54c 100644 --- a/client/service/src/client/client.rs +++ b/client/service/src/client/client.rs @@ -22,7 +22,8 @@ use super::{ block_rules::{BlockRules, LookupResult as BlockLookupResult}, genesis::BuildGenesisBlock, }; -use log::{info, trace, warn}; +use futures::{FutureExt, StreamExt}; +use log::{error, info, trace, warn}; use parking_lot::{Mutex, RwLock}; use prometheus_endpoint::Registry; use rand::Rng; @@ -58,9 +59,12 @@ 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, +use sp_core::{ + storage::{ + well_known_keys, ChildInfo, ChildType, PrefixedStorageKey, Storage, StorageChild, + StorageData, StorageKey, + }, + traits::SpawnNamed, }; #[cfg(feature = "test-helpers")] use sp_keystore::SyncCryptoStorePtr; @@ -88,9 +92,7 @@ use std::{ #[cfg(feature = "test-helpers")] use { - super::call_executor::LocalCallExecutor, - sc_client_api::in_mem, - sp_core::traits::{CodeExecutor, SpawnNamed}, + super::call_executor::LocalCallExecutor, sc_client_api::in_mem, sp_core::traits::CodeExecutor, }; type NotificationSinks = Mutex>>; @@ -116,6 +118,7 @@ where block_rules: BlockRules, config: ClientConfig, telemetry: Option, + unpin_worker_sender: TracingUnboundedSender, _phantom: PhantomData, } @@ -246,7 +249,7 @@ where let call_executor = LocalCallExecutor::new( backend.clone(), executor, - spawn_handle, + spawn_handle.clone(), config.clone(), extensions, )?; @@ -254,6 +257,7 @@ where Client::new( backend, call_executor, + spawn_handle, genesis_block_builder, Default::default(), Default::default(), @@ -296,11 +300,20 @@ where let ClientImportOperation { mut op, notify_imported, notify_finalized } = op; - let finality_notification = notify_finalized.map(|summary| summary.into()); + let finality_notification = notify_finalized.map(|summary| { + FinalityNotification::from_summary(summary, self.unpin_worker_sender.clone()) + }); + let (import_notification, storage_changes) = match notify_imported { Some(mut summary) => { let storage_changes = summary.storage_changes.take(); - (Some(summary.into()), storage_changes) + ( + Some(BlockImportNotification::from_summary( + summary, + self.unpin_worker_sender.clone(), + )), + storage_changes, + ) }, None => (None, None), }; @@ -318,6 +331,27 @@ where self.backend.commit_operation(op)?; + // We need to pin the block in the backend once + // for each notification. Once all notifications are + // dropped, the block will be unpinned automatically. + if let Some(ref notification) = finality_notification { + if let Err(err) = self.backend.pin_block(notification.hash) { + error!( + "Unable to pin block for finality notification. hash: {}, Error: {}", + notification.hash, err + ); + }; + } + + if let Some(ref notification) = import_notification { + if let Err(err) = self.backend.pin_block(notification.hash) { + error!( + "Unable to pin block for import notification. hash: {}, Error: {}", + notification.hash, err + ); + }; + } + self.notify_finalized(finality_notification)?; self.notify_imported(import_notification, storage_changes)?; @@ -357,6 +391,7 @@ where pub fn new( backend: Arc, executor: E, + spawn_handle: Box, genesis_block_builder: G, fork_blocks: ForkBlocks, bad_blocks: BadBlocks, @@ -369,6 +404,7 @@ where Block, BlockImportOperation = >::BlockImportOperation, >, + B: 'static, { let info = backend.blockchain().info(); if info.finalized_state.is_none() { @@ -390,6 +426,26 @@ where backend.commit_operation(op)?; } + let (unpin_worker_sender, mut rx) = + tracing_unbounded::("unpin-worker-channel", 10_000); + let task_backend = Arc::downgrade(&backend); + spawn_handle.spawn( + "unpin-worker", + None, + async move { + while let Some(message) = rx.next().await { + if let Some(backend) = task_backend.upgrade() { + backend.unpin_block(message); + } else { + log::debug!("Terminating unpin-worker, backend reference was dropped."); + return + } + } + log::debug!("Terminating unpin-worker, stream terminated.") + } + .boxed(), + ); + Ok(Client { backend, executor, @@ -402,6 +458,7 @@ where block_rules: BlockRules::new(fork_blocks, bad_blocks), config, telemetry, + unpin_worker_sender, _phantom: Default::default(), }) } diff --git a/test-utils/client/src/lib.rs b/test-utils/client/src/lib.rs index 5dc93da13fe74..ff744b80cbff4 100644 --- a/test-utils/client/src/lib.rs +++ b/test-utils/client/src/lib.rs @@ -41,7 +41,7 @@ use futures::{future::Future, stream::StreamExt}; use sc_client_api::BlockchainEvents; use sc_service::client::{ClientConfig, LocalCallExecutor}; use serde::Deserialize; -use sp_core::storage::ChildInfo; +use sp_core::{storage::ChildInfo, testing::TaskExecutor}; use sp_runtime::{codec::Encode, traits::Block as BlockT, OpaqueExtrinsic}; use std::{ collections::{HashMap, HashSet}, @@ -62,7 +62,7 @@ impl GenesisInit for () { } /// A builder for creating a test client instance. -pub struct TestClientBuilder { +pub struct TestClientBuilder { execution_strategies: ExecutionStrategies, genesis_init: G, /// The key is an unprefixed storage key, this only contains @@ -237,9 +237,12 @@ impl ) .expect("Creates genesis block builder"); + let spawn_handle = Box::new(TaskExecutor::new()); + let client = client::Client::new( self.backend.clone(), executor, + spawn_handle, genesis_block_builder, self.fork_blocks, self.bad_blocks, From 0b6aec52a90870c999856cd37f7d04789cdd8dfc Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Thu, 19 Jan 2023 13:47:47 -0300 Subject: [PATCH 303/715] Make DispatchError impl MEL (#13169) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Make DispatchError impl MEL * Upgrade SCALE codec to support `codec(skip)` for MEL Co-authored-by: Bastian Köcher --- Cargo.lock | 12 ++++++------ bin/node-template/pallets/template/Cargo.toml | 2 +- bin/node-template/runtime/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 +- 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/cli/Cargo.toml | 2 +- client/consensus/aura/Cargo.toml | 2 +- client/consensus/babe/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/db/Cargo.toml | 2 +- client/executor/Cargo.toml | 2 +- client/executor/wasmtime/Cargo.toml | 2 +- client/finality-grandpa/Cargo.toml | 2 +- client/finality-grandpa/rpc/Cargo.toml | 2 +- client/merkle-mountain-range/Cargo.toml | 2 +- client/merkle-mountain-range/rpc/Cargo.toml | 2 +- client/network/Cargo.toml | 2 +- client/network/common/Cargo.toml | 2 +- client/network/light/Cargo.toml | 2 +- client/network/sync/Cargo.toml | 2 +- client/network/transactions/Cargo.toml | 2 +- client/offchain/Cargo.toml | 2 +- client/rpc-api/Cargo.toml | 2 +- client/rpc-spec-v2/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/transaction-pool/Cargo.toml | 2 +- frame/alliance/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/primitives/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 +- .../benchmarking/Cargo.toml | 2 +- .../solution-type/Cargo.toml | 2 +- .../solution-type/fuzzer/Cargo.toml | 2 +- frame/elections-phragmen/Cargo.toml | 2 +- frame/examples/basic/Cargo.toml | 2 +- frame/examples/offchain-worker/Cargo.toml | 2 +- frame/executive/Cargo.toml | 2 +- frame/fast-unstake/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/message-queue/Cargo.toml | 2 +- frame/multisig/Cargo.toml | 2 +- frame/nfts/Cargo.toml | 2 +- frame/nicks/Cargo.toml | 2 +- frame/nis/Cargo.toml | 2 +- frame/node-authorization/Cargo.toml | 2 +- frame/nomination-pools/Cargo.toml | 2 +- frame/nomination-pools/benchmarking/Cargo.toml | 2 +- frame/nomination-pools/runtime-api/Cargo.toml | 2 +- frame/nomination-pools/test-staking/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/ranked-collective/Cargo.toml | 2 +- frame/recovery/Cargo.toml | 2 +- frame/referenda/Cargo.toml | 2 +- frame/remark/Cargo.toml | 2 +- frame/root-offences/Cargo.toml | 2 +- frame/root-testing/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/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 +- .../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 +- frame/whitelist/Cargo.toml | 2 +- primitives/api/Cargo.toml | 2 +- primitives/api/test/Cargo.toml | 2 +- primitives/application-crypto/Cargo.toml | 2 +- primitives/arithmetic/Cargo.toml | 2 +- primitives/arithmetic/src/lib.rs | 4 ++-- 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/externalities/Cargo.toml | 2 +- primitives/finality-grandpa/Cargo.toml | 2 +- primitives/inherents/Cargo.toml | 2 +- primitives/io/Cargo.toml | 2 +- primitives/keystore/Cargo.toml | 2 +- primitives/merkle-mountain-range/Cargo.toml | 2 +- primitives/npos-elections/Cargo.toml | 2 +- primitives/npos-elections/fuzzer/Cargo.toml | 2 +- primitives/runtime-interface/Cargo.toml | 2 +- primitives/runtime/Cargo.toml | 2 +- primitives/runtime/src/lib.rs | 8 ++++---- primitives/session/Cargo.toml | 2 +- primitives/staking/Cargo.toml | 2 +- primitives/state-machine/Cargo.toml | 2 +- primitives/storage/Cargo.toml | 2 +- primitives/test-primitives/Cargo.toml | 2 +- primitives/timestamp/Cargo.toml | 2 +- primitives/tracing/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 +- primitives/weights/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/fork-tree/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/support/Cargo.toml | 2 +- utils/frame/rpc/system/Cargo.toml | 2 +- utils/frame/try-runtime/cli/Cargo.toml | 2 +- 180 files changed, 189 insertions(+), 189 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 100e0d2152096..dbb046ccd86af 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6679,9 +6679,9 @@ dependencies = [ [[package]] name = "parity-scale-codec" -version = "3.2.1" +version = "3.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "366e44391a8af4cfd6002ef6ba072bae071a96aafca98d7d448a34c5dca38b6a" +checksum = "e7ab01d0f889e957861bc65888d5ccbe82c158d0270136ba46820d43837cdf72" dependencies = [ "arrayvec 0.7.2", "bitvec", @@ -6694,9 +6694,9 @@ dependencies = [ [[package]] name = "parity-scale-codec-derive" -version = "3.1.3" +version = "3.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9299338969a3d2f491d65f140b00ddec470858402f888af98e8642fb5e8965cd" +checksum = "86b26a931f824dd4eca30b3e43bb4f31cd5f0d3a403c5f5ff27106b805bfde7b" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -7128,9 +7128,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.49" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5" +checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2" dependencies = [ "unicode-ident", ] diff --git a/bin/node-template/pallets/template/Cargo.toml b/bin/node-template/pallets/template/Cargo.toml index 7c04838cae319..6dec5c8da6e5d 100644 --- a/bin/node-template/pallets/template/Cargo.toml +++ b/bin/node-template/pallets/template/Cargo.toml @@ -13,7 +13,7 @@ repository = "https://github.com/substrate-developer-hub/substrate-node-template targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = [ "derive", ] } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } diff --git a/bin/node-template/runtime/Cargo.toml b/bin/node-template/runtime/Cargo.toml index 5dc7b03d39a81..5560eb6721377 100644 --- a/bin/node-template/runtime/Cargo.toml +++ b/bin/node-template/runtime/Cargo.toml @@ -13,7 +13,7 @@ repository = "https://github.com/substrate-developer-hub/substrate-node-template targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.2.2", 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" } diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index 6b50115fd9a00..4d9279b857eed 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -37,7 +37,7 @@ crate-type = ["cdylib", "rlib"] # third-party dependencies array-bytes = "4.1" clap = { version = "4.0.9", features = ["derive"], optional = true } -codec = { package = "parity-scale-codec", version = "3.0.0" } +codec = { package = "parity-scale-codec", version = "3.2.2" } serde = { version = "1.0.136", features = ["derive"] } jsonrpsee = { version = "0.16.2", features = ["server"] } futures = "0.3.21" diff --git a/bin/node/executor/Cargo.toml b/bin/node/executor/Cargo.toml index 8b3add78a9a26..edcc4df9c8176 100644 --- a/bin/node/executor/Cargo.toml +++ b/bin/node/executor/Cargo.toml @@ -13,7 +13,7 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0" } +codec = { package = "parity-scale-codec", version = "3.2.2" } 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" } diff --git a/bin/node/inspect/Cargo.toml b/bin/node/inspect/Cargo.toml index a7343b3ca827f..d6a8755179f3e 100644 --- a/bin/node/inspect/Cargo.toml +++ b/bin/node/inspect/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] clap = { version = "4.0.9", features = ["derive"] } -codec = { package = "parity-scale-codec", version = "3.0.0" } +codec = { package = "parity-scale-codec", version = "3.2.2" } 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 1aa0a8f0e27a3..1f515f3e3a5b5 100644 --- a/bin/node/primitives/Cargo.toml +++ b/bin/node/primitives/Cargo.toml @@ -13,7 +13,7 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = [ "derive", ] } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index 7037be9d7c54d..76fca730ef7d0 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] # third-party dependencies -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = [ "derive", "max-encoded-len", ] } diff --git a/bin/node/testing/Cargo.toml b/bin/node/testing/Cargo.toml index 0154a778457fc..a43b2b9ba13e5 100644 --- a/bin/node/testing/Cargo.toml +++ b/bin/node/testing/Cargo.toml @@ -13,7 +13,7 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0" } +codec = { package = "parity-scale-codec", version = "3.2.2" } fs_extra = "1" futures = "0.3.21" log = "0.4.17" diff --git a/client/api/Cargo.toml b/client/api/Cargo.toml index bd1f6f34b0eff..f494200852729 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 = "3.0.0", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = [ "derive", ] } fnv = "1.0.6" diff --git a/client/authority-discovery/Cargo.toml b/client/authority-discovery/Cargo.toml index a24002517cca8..b37507662bfeb 100644 --- a/client/authority-discovery/Cargo.toml +++ b/client/authority-discovery/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] prost-build = "0.11" [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false } futures = "0.3.21" futures-timer = "3.0.1" ip_network = "0.4.1" diff --git a/client/basic-authorship/Cargo.toml b/client/basic-authorship/Cargo.toml index 09b5c47394491..c4f1d2e245f92 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 = "3.0.0" } +codec = { package = "parity-scale-codec", version = "3.2.2" } futures = "0.3.21" futures-timer = "3.0.1" log = "0.4.17" diff --git a/client/beefy/Cargo.toml b/client/beefy/Cargo.toml index b039faa2d095d..d81ff2587cf2c 100644 --- a/client/beefy/Cargo.toml +++ b/client/beefy/Cargo.toml @@ -11,7 +11,7 @@ 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"] } +codec = { package = "parity-scale-codec", version = "3.2.2", features = ["derive"] } fnv = "1.0.6" futures = "0.3" log = "0.4" diff --git a/client/beefy/rpc/Cargo.toml b/client/beefy/rpc/Cargo.toml index f853af8a81c74..ab3e6921f3cfe 100644 --- a/client/beefy/rpc/Cargo.toml +++ b/client/beefy/rpc/Cargo.toml @@ -9,7 +9,7 @@ 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"] } +codec = { package = "parity-scale-codec", version = "3.2.2", features = ["derive"] } futures = "0.3.21" jsonrpsee = { version = "0.16.2", features = ["client-core", "server", "macros"] } log = "0.4" diff --git a/client/block-builder/Cargo.toml b/client/block-builder/Cargo.toml index 2516374864bc1..3b4bea9818c9e 100644 --- a/client/block-builder/Cargo.toml +++ b/client/block-builder/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", features = [ +codec = { package = "parity-scale-codec", version = "3.2.2", features = [ "derive", ] } sc-client-api = { version = "4.0.0-dev", path = "../api" } diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index 5e1f2bab4be9f..c0da53ad129d5 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -21,7 +21,7 @@ futures = "0.3.21" libp2p = "0.50.0" log = "0.4.17" names = { version = "0.13.0", default-features = false } -parity-scale-codec = "3.0.0" +parity-scale-codec = "3.2.2" rand = "0.8.5" regex = "1.6.0" rpassword = "7.0.0" diff --git a/client/consensus/aura/Cargo.toml b/client/consensus/aura/Cargo.toml index 47aee0ec084eb..4c0305e9f66e7 100644 --- a/client/consensus/aura/Cargo.toml +++ b/client/consensus/aura/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-trait = "0.1.57" -codec = { package = "parity-scale-codec", version = "3.0.0" } +codec = { package = "parity-scale-codec", version = "3.2.2" } futures = "0.3.21" log = "0.4.17" thiserror = "1.0" diff --git a/client/consensus/babe/Cargo.toml b/client/consensus/babe/Cargo.toml index 312cc25dd0b59..f0ff0080fd610 100644 --- a/client/consensus/babe/Cargo.toml +++ b/client/consensus/babe/Cargo.toml @@ -15,7 +15,7 @@ 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.2.2", features = ["derive"] } futures = "0.3.21" log = "0.4.17" merlin = "2.0" diff --git a/client/consensus/epochs/Cargo.toml b/client/consensus/epochs/Cargo.toml index c88b5c52ba18e..89588cc7d4c5c 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 = "3.0.0", features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.2.2", features = ["derive"] } 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" } diff --git a/client/consensus/manual-seal/Cargo.toml b/client/consensus/manual-seal/Cargo.toml index fb89445a97002..19c4b22247e0f 100644 --- a/client/consensus/manual-seal/Cargo.toml +++ b/client/consensus/manual-seal/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] 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" } +codec = { package = "parity-scale-codec", version = "3.2.2" } futures = "0.3.21" log = "0.4.17" serde = { version = "1.0", features = ["derive"] } diff --git a/client/consensus/pow/Cargo.toml b/client/consensus/pow/Cargo.toml index 480d9b23b06a3..b5454e35f994e 100644 --- a/client/consensus/pow/Cargo.toml +++ b/client/consensus/pow/Cargo.toml @@ -14,7 +14,7 @@ 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.2.2", features = ["derive"] } futures = "0.3.21" futures-timer = "3.0.1" log = "0.4.17" diff --git a/client/consensus/slots/Cargo.toml b/client/consensus/slots/Cargo.toml index 6acd656d21a06..5cacf4f476281 100644 --- a/client/consensus/slots/Cargo.toml +++ b/client/consensus/slots/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-trait = "0.1.57" -codec = { package = "parity-scale-codec", version = "3.0.0" } +codec = { package = "parity-scale-codec", version = "3.2.2" } futures = "0.3.21" futures-timer = "3.0.1" log = "0.4.17" diff --git a/client/db/Cargo.toml b/client/db/Cargo.toml index 2d7291a014d6e..028af5d6e45c9 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] -codec = { package = "parity-scale-codec", version = "3.0.0", features = [ +codec = { package = "parity-scale-codec", version = "3.2.2", features = [ "derive", ] } hash-db = "0.15.2" diff --git a/client/executor/Cargo.toml b/client/executor/Cargo.toml index 83d4801d1c92b..4604b976b4248 100644 --- a/client/executor/Cargo.toml +++ b/client/executor/Cargo.toml @@ -19,7 +19,7 @@ parking_lot = "0.12.1" tracing = "0.1.29" wasmi = "0.13" -codec = { package = "parity-scale-codec", version = "3.0.0" } +codec = { package = "parity-scale-codec", version = "3.2.2" } 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" } diff --git a/client/executor/wasmtime/Cargo.toml b/client/executor/wasmtime/Cargo.toml index 7e38929f05a13..983ca3c44fba0 100644 --- a/client/executor/wasmtime/Cargo.toml +++ b/client/executor/wasmtime/Cargo.toml @@ -47,4 +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" } +codec = { package = "parity-scale-codec", version = "3.2.2" } diff --git a/client/finality-grandpa/Cargo.toml b/client/finality-grandpa/Cargo.toml index 95195bfc2d946..9a31a1d4bf6a7 100644 --- a/client/finality-grandpa/Cargo.toml +++ b/client/finality-grandpa/Cargo.toml @@ -22,7 +22,7 @@ finality-grandpa = { version = "0.16.1", features = ["derive-codec"] } futures = "0.3.21" futures-timer = "3.0.1" log = "0.4.17" -parity-scale-codec = { version = "3.0.0", features = ["derive"] } +parity-scale-codec = { version = "3.2.2", features = ["derive"] } parking_lot = "0.12.1" rand = "0.8.5" serde_json = "1.0.85" diff --git a/client/finality-grandpa/rpc/Cargo.toml b/client/finality-grandpa/rpc/Cargo.toml index 429331e96a65f..e20ff174d41c5 100644 --- a/client/finality-grandpa/rpc/Cargo.toml +++ b/client/finality-grandpa/rpc/Cargo.toml @@ -14,7 +14,7 @@ finality-grandpa = { version = "0.16.1", features = ["derive-codec"] } futures = "0.3.16" jsonrpsee = { version = "0.16.2", features = ["client-core", "server", "macros"] } log = "0.4.8" -parity-scale-codec = { version = "3.0.0", features = ["derive"] } +parity-scale-codec = { version = "3.2.2", features = ["derive"] } serde = { version = "1.0.105", features = ["derive"] } thiserror = "1.0" sc-client-api = { version = "4.0.0-dev", path = "../../api" } diff --git a/client/merkle-mountain-range/Cargo.toml b/client/merkle-mountain-range/Cargo.toml index cd7d9442492e1..90fb65453ba12 100644 --- a/client/merkle-mountain-range/Cargo.toml +++ b/client/merkle-mountain-range/Cargo.toml @@ -11,7 +11,7 @@ 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" } +codec = { package = "parity-scale-codec", version = "3.2.2" } futures = "0.3" log = "0.4" beefy-primitives = { version = "4.0.0-dev", path = "../../primitives/beefy", package = "sp-beefy" } diff --git a/client/merkle-mountain-range/rpc/Cargo.toml b/client/merkle-mountain-range/rpc/Cargo.toml index dcc5e49c52051..ce71158808e1e 100644 --- a/client/merkle-mountain-range/rpc/Cargo.toml +++ b/client/merkle-mountain-range/rpc/Cargo.toml @@ -12,7 +12,7 @@ description = "Node-specific RPC methods for interaction with Merkle Mountain Ra targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0" } +codec = { package = "parity-scale-codec", version = "3.2.2" } 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" } diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index 4356cc5df1b13..44a7973b33659 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -19,7 +19,7 @@ async-trait = "0.1" asynchronous-codec = "0.6" backtrace = "0.3.67" bytes = "1" -codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.2.2", features = ["derive"] } either = "1.5.3" fnv = "1.0.6" futures = "0.3.21" diff --git a/client/network/common/Cargo.toml b/client/network/common/Cargo.toml index e2dd7d0894eb0..2aaada021f0fa 100644 --- a/client/network/common/Cargo.toml +++ b/client/network/common/Cargo.toml @@ -19,7 +19,7 @@ prost-build = "0.11" async-trait = "0.1.57" bitflags = "1.3.2" bytes = "1" -codec = { package = "parity-scale-codec", version = "3.0.0", features = [ +codec = { package = "parity-scale-codec", version = "3.2.2", features = [ "derive", ] } futures = "0.3.21" diff --git a/client/network/light/Cargo.toml b/client/network/light/Cargo.toml index 8a3e9037729a8..f3e94790df61e 100644 --- a/client/network/light/Cargo.toml +++ b/client/network/light/Cargo.toml @@ -17,7 +17,7 @@ prost-build = "0.11" [dependencies] array-bytes = "4.1" -codec = { package = "parity-scale-codec", version = "3.0.0", features = [ +codec = { package = "parity-scale-codec", version = "3.2.2", features = [ "derive", ] } futures = "0.3.21" diff --git a/client/network/sync/Cargo.toml b/client/network/sync/Cargo.toml index d2cbeb5ec1f1d..ff72b4e993026 100644 --- a/client/network/sync/Cargo.toml +++ b/client/network/sync/Cargo.toml @@ -18,7 +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"] } +codec = { package = "parity-scale-codec", version = "3.2.2", features = ["derive"] } futures = "0.3.21" libp2p = "0.50.0" log = "0.4.17" diff --git a/client/network/transactions/Cargo.toml b/client/network/transactions/Cargo.toml index df13cdcb820d2..cab702fbd7a6c 100644 --- a/client/network/transactions/Cargo.toml +++ b/client/network/transactions/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] array-bytes = "4.1" -codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.2.2", features = ["derive"] } futures = "0.3.21" libp2p = "0.50.0" log = "0.4.17" diff --git a/client/offchain/Cargo.toml b/client/offchain/Cargo.toml index 09df9187fb2d5..dd6e2e44caf55 100644 --- a/client/offchain/Cargo.toml +++ b/client/offchain/Cargo.toml @@ -15,7 +15,7 @@ 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"] } +codec = { package = "parity-scale-codec", version = "3.2.2", features = ["derive"] } fnv = "1.0.6" futures = "0.3.21" futures-timer = "3.0.2" diff --git a/client/rpc-api/Cargo.toml b/client/rpc-api/Cargo.toml index f697f53e98283..261339f131888 100644 --- a/client/rpc-api/Cargo.toml +++ b/client/rpc-api/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0" } +codec = { package = "parity-scale-codec", version = "3.2.2" } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"] } serde_json = "1.0.85" diff --git a/client/rpc-spec-v2/Cargo.toml b/client/rpc-spec-v2/Cargo.toml index f9598b3c1abc9..43fb189081bae 100644 --- a/client/rpc-spec-v2/Cargo.toml +++ b/client/rpc-spec-v2/Cargo.toml @@ -24,7 +24,7 @@ sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-version = { version = "5.0.0", path = "../../primitives/version" } sc-client-api = { version = "4.0.0-dev", path = "../api" } -codec = { package = "parity-scale-codec", version = "3.0.0" } +codec = { package = "parity-scale-codec", version = "3.2.2" } thiserror = "1.0" serde = "1.0" hex = "0.4" diff --git a/client/rpc/Cargo.toml b/client/rpc/Cargo.toml index d39d8d8581ff6..a22f657878812 100644 --- a/client/rpc/Cargo.toml +++ b/client/rpc/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0" } +codec = { package = "parity-scale-codec", version = "3.2.2" } futures = "0.3.21" jsonrpsee = { version = "0.16.2", features = ["server"] } log = "0.4.17" diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index 45b1c02620fb2..6122895d2300c 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -57,7 +57,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 = "3.0.0" } +codec = { package = "parity-scale-codec", version = "3.2.2" } 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" } diff --git a/client/service/test/Cargo.toml b/client/service/test/Cargo.toml index d3bc39aa3486c..488fe76c333bc 100644 --- a/client/service/test/Cargo.toml +++ b/client/service/test/Cargo.toml @@ -16,7 +16,7 @@ array-bytes = "4.1" fdlimit = "0.2.1" futures = "0.3.21" log = "0.4.17" -parity-scale-codec = "3.0.0" +parity-scale-codec = "3.2.2" parking_lot = "0.12.1" tempfile = "3.1.0" tokio = { version = "1.22.0", features = ["time"] } diff --git a/client/state-db/Cargo.toml b/client/state-db/Cargo.toml index fb70f5fc6a8ba..13439de110155 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] -codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.2.2", features = ["derive"] } log = "0.4.17" parking_lot = "0.12.1" 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 a72b4106ba873..3a964521c505b 100644 --- a/client/sync-state-rpc/Cargo.toml +++ b/client/sync-state-rpc/Cargo.toml @@ -12,7 +12,7 @@ repository = "https://github.com/paritytech/substrate/" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0" } +codec = { package = "parity-scale-codec", version = "3.2.2" } jsonrpsee = { version = "0.16.2", features = ["client-core", "server", "macros"] } serde = { version = "1.0.136", features = ["derive"] } serde_json = "1.0.85" diff --git a/client/transaction-pool/Cargo.toml b/client/transaction-pool/Cargo.toml index 4b69b6d0f2fe0..bbb5ebae440a0 100644 --- a/client/transaction-pool/Cargo.toml +++ b/client/transaction-pool/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-trait = "0.1.57" -codec = { package = "parity-scale-codec", version = "3.0.0" } +codec = { package = "parity-scale-codec", version = "3.2.2" } futures = "0.3.21" futures-timer = "3.0.2" linked-hash-map = "0.5.4" diff --git a/frame/alliance/Cargo.toml b/frame/alliance/Cargo.toml index da0a7d665747d..d6a16e2c32e36 100644 --- a/frame/alliance/Cargo.toml +++ b/frame/alliance/Cargo.toml @@ -17,7 +17,7 @@ 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 } -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } diff --git a/frame/assets/Cargo.toml b/frame/assets/Cargo.toml index 84bfd9535a461..6fe0e3e6c3042 100644 --- a/frame/assets/Cargo.toml +++ b/frame/assets/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } # Needed for various traits. In our case, `OnFinalize`. diff --git a/frame/atomic-swap/Cargo.toml b/frame/atomic-swap/Cargo.toml index 5220edb9d17c7..9c3bcf73af985 100644 --- a/frame/atomic-swap/Cargo.toml +++ b/frame/atomic-swap/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +codec = { package = "parity-scale-codec", version = "3.2.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" } diff --git a/frame/aura/Cargo.toml b/frame/aura/Cargo.toml index 552f13301d311..d2fd5a5b9c372 100644 --- a/frame/aura/Cargo.toml +++ b/frame/aura/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive", "max-encoded-len"] } 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" } diff --git a/frame/authority-discovery/Cargo.toml b/frame/authority-discovery/Cargo.toml index 47bd1a126f4da..50c6c411c5ae0 100644 --- a/frame/authority-discovery/Cargo.toml +++ b/frame/authority-discovery/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = [ "derive", ] } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } diff --git a/frame/authorship/Cargo.toml b/frame/authorship/Cargo.toml index 7c0289909f806..84d00a6fbc54e 100644 --- a/frame/authorship/Cargo.toml +++ b/frame/authorship/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = [ "derive", ] } impl-trait-for-tuples = "0.2.2" diff --git a/frame/babe/Cargo.toml b/frame/babe/Cargo.toml index a3232f6f981d0..aa581392721ae 100644 --- a/frame/babe/Cargo.toml +++ b/frame/babe/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } log = { version = "0.4.17", 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" } diff --git a/frame/bags-list/Cargo.toml b/frame/bags-list/Cargo.toml index 52dd14b7d01c8..e3a4965f6c086 100644 --- a/frame/bags-list/Cargo.toml +++ b/frame/bags-list/Cargo.toml @@ -13,7 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] # parity -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } # primitives diff --git a/frame/balances/Cargo.toml b/frame/balances/Cargo.toml index 934138a900214..15ef136aa3800 100644 --- a/frame/balances/Cargo.toml +++ b/frame/balances/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive", "max-encoded-len"] } log = { version = "0.4.17", 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" } diff --git a/frame/beefy-mmr/Cargo.toml b/frame/beefy-mmr/Cargo.toml index f65270acdc3f8..54da26c394f0c 100644 --- a/frame/beefy-mmr/Cargo.toml +++ b/frame/beefy-mmr/Cargo.toml @@ -10,7 +10,7 @@ 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"] } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } 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 } diff --git a/frame/beefy/Cargo.toml b/frame/beefy/Cargo.toml index 707e8e25712ab..4db8c05682840 100644 --- a/frame/beefy/Cargo.toml +++ b/frame/beefy/Cargo.toml @@ -9,7 +9,7 @@ description = "BEEFY FRAME pallet" homepage = "https://substrate.io" [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.2.2", 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", package = "sp-beefy" } diff --git a/frame/benchmarking/Cargo.toml b/frame/benchmarking/Cargo.toml index 7c18b69401884..168b2605738ab 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] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false } linregress = { version = "0.4.4", optional = true } log = { version = "0.4.17", default-features = false } paste = "1.0" diff --git a/frame/bounties/Cargo.toml b/frame/bounties/Cargo.toml index a5411952a385a..dcb1adae05777 100644 --- a/frame/bounties/Cargo.toml +++ b/frame/bounties/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = [ "derive", ] } log = { version = "0.4.17", default-features = false } diff --git a/frame/child-bounties/Cargo.toml b/frame/child-bounties/Cargo.toml index 6b0a672d04225..8d29b7619759d 100644 --- a/frame/child-bounties/Cargo.toml +++ b/frame/child-bounties/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = [ "derive", ] } log = { version = "0.4.17", default-features = false } diff --git a/frame/collective/Cargo.toml b/frame/collective/Cargo.toml index 0e8c5421f5ff1..26cd5a8ab44cc 100644 --- a/frame/collective/Cargo.toml +++ b/frame/collective/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } log = { version = "0.4.17", 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" } diff --git a/frame/contracts/Cargo.toml b/frame/contracts/Cargo.toml index 8e6368490f6d7..c238bdd14e73b 100644 --- a/frame/contracts/Cargo.toml +++ b/frame/contracts/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] bitflags = "1.3" -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = [ "derive", "max-encoded-len", ] } diff --git a/frame/contracts/primitives/Cargo.toml b/frame/contracts/primitives/Cargo.toml index d0c3a34ddfccb..aafcd912af657 100644 --- a/frame/contracts/primitives/Cargo.toml +++ b/frame/contracts/primitives/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] bitflags = "1.0" -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } # Substrate Dependencies (This crate should not rely on frame) sp-std = { version = "5.0.0", default-features = false, path = "../../../primitives/std" } diff --git a/frame/conviction-voting/Cargo.toml b/frame/conviction-voting/Cargo.toml index 9bfc93f2d9ff5..d112c54fb64a7 100644 --- a/frame/conviction-voting/Cargo.toml +++ b/frame/conviction-voting/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] assert_matches = "1.3.0" -codec = { package = "parity-scale-codec", version = "3.0.3", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = [ "derive", "max-encoded-len", ] } diff --git a/frame/democracy/Cargo.toml b/frame/democracy/Cargo.toml index 49dbe133d6919..fa107218cf698 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] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = [ "derive", ] } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } diff --git a/frame/election-provider-multi-phase/Cargo.toml b/frame/election-provider-multi-phase/Cargo.toml index a21740dd72a02..aa734850aae43 100644 --- a/frame/election-provider-multi-phase/Cargo.toml +++ b/frame/election-provider-multi-phase/Cargo.toml @@ -12,7 +12,7 @@ description = "PALLET two phase election providers" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = [ "derive", ] } scale-info = { version = "2.1.1", default-features = false, features = [ diff --git a/frame/election-provider-support/Cargo.toml b/frame/election-provider-support/Cargo.toml index 108a49eb08abc..c7f47e721d1aa 100644 --- a/frame/election-provider-support/Cargo.toml +++ b/frame/election-provider-support/Cargo.toml @@ -12,7 +12,7 @@ description = "election provider supporting traits" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.2.2", 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" } diff --git a/frame/election-provider-support/benchmarking/Cargo.toml b/frame/election-provider-support/benchmarking/Cargo.toml index 60538997773d4..bef371ec5efbf 100644 --- a/frame/election-provider-support/benchmarking/Cargo.toml +++ b/frame/election-provider-support/benchmarking/Cargo.toml @@ -12,7 +12,7 @@ description = "Benchmarking for election provider support onchain config trait" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = [ "derive", ] } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../../benchmarking" } diff --git a/frame/election-provider-support/solution-type/Cargo.toml b/frame/election-provider-support/solution-type/Cargo.toml index 50c39c547fb9b..eb9598dca20b8 100644 --- a/frame/election-provider-support/solution-type/Cargo.toml +++ b/frame/election-provider-support/solution-type/Cargo.toml @@ -21,7 +21,7 @@ proc-macro2 = "1.0.37" proc-macro-crate = "1.1.3" [dev-dependencies] -parity-scale-codec = "3.0.0" +parity-scale-codec = "3.2.2" scale-info = "2.1.1" sp-arithmetic = { version = "6.0.0", path = "../../../primitives/arithmetic" } # used by generate_solution_type: diff --git a/frame/election-provider-support/solution-type/fuzzer/Cargo.toml b/frame/election-provider-support/solution-type/fuzzer/Cargo.toml index 34aeaf9300352..9275692788d48 100644 --- a/frame/election-provider-support/solution-type/fuzzer/Cargo.toml +++ b/frame/election-provider-support/solution-type/fuzzer/Cargo.toml @@ -17,7 +17,7 @@ clap = { version = "4.0.9", 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"] } +codec = { package = "parity-scale-codec", version = "3.2.2", 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 = "../.." } diff --git a/frame/elections-phragmen/Cargo.toml b/frame/elections-phragmen/Cargo.toml index fb1d924dbd1bd..ce39e42b8eeb5 100644 --- a/frame/elections-phragmen/Cargo.toml +++ b/frame/elections-phragmen/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = [ "derive", ] } log = { version = "0.4.14", default-features = false } diff --git a/frame/examples/basic/Cargo.toml b/frame/examples/basic/Cargo.toml index 8c69dc6c3e9ce..47f623f45381c 100644 --- a/frame/examples/basic/Cargo.toml +++ b/frame/examples/basic/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false } log = { version = "0.4.17", 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" } diff --git a/frame/examples/offchain-worker/Cargo.toml b/frame/examples/offchain-worker/Cargo.toml index 446af8dda9198..f94cf36b2b992 100644 --- a/frame/examples/offchain-worker/Cargo.toml +++ b/frame/examples/offchain-worker/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +codec = { package = "parity-scale-codec", version = "3.2.2", 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"] } diff --git a/frame/executive/Cargo.toml b/frame/executive/Cargo.toml index a6d16e9b0793f..1636cb3929d92 100644 --- a/frame/executive/Cargo.toml +++ b/frame/executive/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = [ "derive", ] } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } diff --git a/frame/fast-unstake/Cargo.toml b/frame/fast-unstake/Cargo.toml index b61060e775a9f..36b4c3a5ec1cb 100644 --- a/frame/fast-unstake/Cargo.toml +++ b/frame/fast-unstake/Cargo.toml @@ -12,7 +12,7 @@ description = "FRAME fast unstake pallet" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } diff --git a/frame/grandpa/Cargo.toml b/frame/grandpa/Cargo.toml index 93dd4143af2d7..fa63b8427523a 100644 --- a/frame/grandpa/Cargo.toml +++ b/frame/grandpa/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } log = { version = "0.4.17", 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" } diff --git a/frame/identity/Cargo.toml b/frame/identity/Cargo.toml index 8c7655af6ab34..c1a250368fade 100644 --- a/frame/identity/Cargo.toml +++ b/frame/identity/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive", "max-encoded-len"] } enumflags2 = { version = "0.7.4" } 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" } diff --git a/frame/im-online/Cargo.toml b/frame/im-online/Cargo.toml index c0058e9f2371d..d76fba4fb6495 100644 --- a/frame/im-online/Cargo.toml +++ b/frame/im-online/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } log = { version = "0.4.17", 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" } diff --git a/frame/indices/Cargo.toml b/frame/indices/Cargo.toml index b3afa397c45f5..b667916ebcb49 100644 --- a/frame/indices/Cargo.toml +++ b/frame/indices/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.2.2", 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" } diff --git a/frame/lottery/Cargo.toml b/frame/lottery/Cargo.toml index 9ac69d63eb983..8c1bf30106852 100644 --- a/frame/lottery/Cargo.toml +++ b/frame/lottery/Cargo.toml @@ -12,7 +12,7 @@ description = "FRAME Participation Lottery Pallet" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = [ "derive", ] } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } diff --git a/frame/membership/Cargo.toml b/frame/membership/Cargo.toml index b457c4c2911bd..bba5700cdd848 100644 --- a/frame/membership/Cargo.toml +++ b/frame/membership/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false } log = { version = "0.4.17", 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" } diff --git a/frame/merkle-mountain-range/Cargo.toml b/frame/merkle-mountain-range/Cargo.toml index cf26cfb231c85..3f7180f79adbe 100644 --- a/frame/merkle-mountain-range/Cargo.toml +++ b/frame/merkle-mountain-range/Cargo.toml @@ -12,7 +12,7 @@ description = "FRAME Merkle Mountain Range pallet." targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +codec = { package = "parity-scale-codec", version = "3.2.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/message-queue/Cargo.toml b/frame/message-queue/Cargo.toml index 47d114902f52c..115200b826763 100644 --- a/frame/message-queue/Cargo.toml +++ b/frame/message-queue/Cargo.toml @@ -9,7 +9,7 @@ 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"] } +codec = { package = "parity-scale-codec", version = "3.2.2", 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 } diff --git a/frame/multisig/Cargo.toml b/frame/multisig/Cargo.toml index 4e9f4f5d832e6..5cd744124ef24 100644 --- a/frame/multisig/Cargo.toml +++ b/frame/multisig/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +codec = { package = "parity-scale-codec", version = "3.2.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/nfts/Cargo.toml b/frame/nfts/Cargo.toml index d2cdb48532fd0..9e010cb557958 100644 --- a/frame/nfts/Cargo.toml +++ b/frame/nfts/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false } enumflags2 = { version = "0.7.5" } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } diff --git a/frame/nicks/Cargo.toml b/frame/nicks/Cargo.toml index 2390060c71698..1c829efc2d601 100644 --- a/frame/nicks/Cargo.toml +++ b/frame/nicks/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.2.2", 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" } diff --git a/frame/nis/Cargo.toml b/frame/nis/Cargo.toml index be12d97dd871d..a5fc29cd79150 100644 --- a/frame/nis/Cargo.toml +++ b/frame/nis/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.2.2", 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" } diff --git a/frame/node-authorization/Cargo.toml b/frame/node-authorization/Cargo.toml index fbf486644e15c..c60ce1d12ce09 100644 --- a/frame/node-authorization/Cargo.toml +++ b/frame/node-authorization/Cargo.toml @@ -12,7 +12,7 @@ description = "FRAME pallet for node authorization" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } 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/nomination-pools/Cargo.toml b/frame/nomination-pools/Cargo.toml index 3eb2d4bc5fd9b..d51bcec51f478 100644 --- a/frame/nomination-pools/Cargo.toml +++ b/frame/nomination-pools/Cargo.toml @@ -13,7 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] # parity -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } # FRAME diff --git a/frame/nomination-pools/benchmarking/Cargo.toml b/frame/nomination-pools/benchmarking/Cargo.toml index 74b71a353fe7f..b96024af7d3c5 100644 --- a/frame/nomination-pools/benchmarking/Cargo.toml +++ b/frame/nomination-pools/benchmarking/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"] } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } # FRAME diff --git a/frame/nomination-pools/runtime-api/Cargo.toml b/frame/nomination-pools/runtime-api/Cargo.toml index cf72d795c9faa..d1e4fbb30df52 100644 --- a/frame/nomination-pools/runtime-api/Cargo.toml +++ b/frame/nomination-pools/runtime-api/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/api" } sp-std = { version = "5.0.0", default-features = false, path = "../../../primitives/std" } diff --git a/frame/nomination-pools/test-staking/Cargo.toml b/frame/nomination-pools/test-staking/Cargo.toml index a45c7852d4151..fbe5feca0febe 100644 --- a/frame/nomination-pools/test-staking/Cargo.toml +++ b/frame/nomination-pools/test-staking/Cargo.toml @@ -13,7 +13,7 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dev-dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.2.2", features = ["derive"] } scale-info = { version = "2.0.1", features = ["derive"] } sp-runtime = { version = "7.0.0", path = "../../../primitives/runtime" } diff --git a/frame/offences/Cargo.toml b/frame/offences/Cargo.toml index 107a0489cd594..47ae264a69cf8 100644 --- a/frame/offences/Cargo.toml +++ b/frame/offences/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } 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 } diff --git a/frame/offences/benchmarking/Cargo.toml b/frame/offences/benchmarking/Cargo.toml index e31e8bbed929f..23377f7883dae 100644 --- a/frame/offences/benchmarking/Cargo.toml +++ b/frame/offences/benchmarking/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +codec = { package = "parity-scale-codec", version = "3.2.2", 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" } diff --git a/frame/preimage/Cargo.toml b/frame/preimage/Cargo.toml index def39d61d5175..6bc6c8c53c012 100644 --- a/frame/preimage/Cargo.toml +++ b/frame/preimage/Cargo.toml @@ -9,7 +9,7 @@ repository = "https://github.com/paritytech/substrate/" description = "FRAME pallet for storing preimages of hashes" [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.2.2", 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" } diff --git a/frame/proxy/Cargo.toml b/frame/proxy/Cargo.toml index 1674e408668d2..5c69fcfb9f55e 100644 --- a/frame/proxy/Cargo.toml +++ b/frame/proxy/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["max-encoded-len"] } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["max-encoded-len"] } 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/randomness-collective-flip/Cargo.toml b/frame/randomness-collective-flip/Cargo.toml index 5a20949e9f243..435c38d632b69 100644 --- a/frame/randomness-collective-flip/Cargo.toml +++ b/frame/randomness-collective-flip/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } 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" } diff --git a/frame/ranked-collective/Cargo.toml b/frame/ranked-collective/Cargo.toml index c5e79eb68f24d..e19aaa4439716 100644 --- a/frame/ranked-collective/Cargo.toml +++ b/frame/ranked-collective/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.2.2", 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" } diff --git a/frame/recovery/Cargo.toml b/frame/recovery/Cargo.toml index cdcebbec161bc..3c25c0002b709 100644 --- a/frame/recovery/Cargo.toml +++ b/frame/recovery/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.2.2", 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" } diff --git a/frame/referenda/Cargo.toml b/frame/referenda/Cargo.toml index 02894e1499d93..ac4c8044da359 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.3", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = [ "derive", ] } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } diff --git a/frame/remark/Cargo.toml b/frame/remark/Cargo.toml index a827d165f8389..151cc38884490 100644 --- a/frame/remark/Cargo.toml +++ b/frame/remark/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false } 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" } diff --git a/frame/root-offences/Cargo.toml b/frame/root-offences/Cargo.toml index 76eb832c88e1b..fd1f7c6325ea2 100644 --- a/frame/root-offences/Cargo.toml +++ b/frame/root-offences/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.2.2", 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 } diff --git a/frame/root-testing/Cargo.toml b/frame/root-testing/Cargo.toml index 4d3f70c5d0d9f..09262b3d31db2 100644 --- a/frame/root-testing/Cargo.toml +++ b/frame/root-testing/Cargo.toml @@ -14,7 +14,7 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.2.2", 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" } diff --git a/frame/scheduler/Cargo.toml b/frame/scheduler/Cargo.toml index 25ac602681cc0..9a67e68a01640 100644 --- a/frame/scheduler/Cargo.toml +++ b/frame/scheduler/Cargo.toml @@ -10,7 +10,7 @@ description = "FRAME Scheduler pallet" readme = "README.md" [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } log = { version = "0.4.17", 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" } diff --git a/frame/scored-pool/Cargo.toml b/frame/scored-pool/Cargo.toml index a1e8dc453df6c..d44fc1b2f1548 100644 --- a/frame/scored-pool/Cargo.toml +++ b/frame/scored-pool/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.2.2", 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" } diff --git a/frame/session/Cargo.toml b/frame/session/Cargo.toml index 57b519e81e59b..bd28bffffd8d9 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] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } impl-trait-for-tuples = "0.2.2" log = { version = "0.4.17", default-features = false } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } diff --git a/frame/session/benchmarking/Cargo.toml b/frame/session/benchmarking/Cargo.toml index 53d6ff0cd18a0..4d1d9b4eda491 100644 --- a/frame/session/benchmarking/Cargo.toml +++ b/frame/session/benchmarking/Cargo.toml @@ -24,7 +24,7 @@ sp-session = { version = "4.0.0-dev", default-features = false, path = "../../.. 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"] } +codec = { package = "parity-scale-codec", version = "3.2.2", features = ["derive"] } 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" } diff --git a/frame/society/Cargo.toml b/frame/society/Cargo.toml index 40b78c8922299..ddc6ea6aac7d7 100644 --- a/frame/society/Cargo.toml +++ b/frame/society/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } 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" } diff --git a/frame/staking/Cargo.toml b/frame/staking/Cargo.toml index f6b3b95d0beb9..3d5cf1161e8e5 100644 --- a/frame/staking/Cargo.toml +++ b/frame/staking/Cargo.toml @@ -14,7 +14,7 @@ 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, features = [ +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = [ "derive", ] } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } diff --git a/frame/state-trie-migration/Cargo.toml b/frame/state-trie-migration/Cargo.toml index 90c8f426d0e10..36b5912a60302 100644 --- a/frame/state-trie-migration/Cargo.toml +++ b/frame/state-trie-migration/Cargo.toml @@ -12,7 +12,7 @@ description = "FRAME pallet migration of trie" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.133", optional = true } diff --git a/frame/sudo/Cargo.toml b/frame/sudo/Cargo.toml index b0e38b0139c11..56d04b172c268 100644 --- a/frame/sudo/Cargo.toml +++ b/frame/sudo/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.2.2", 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" } diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index 4945b5ab915f9..4f62ae42ef78f 100644 --- a/frame/support/Cargo.toml +++ b/frame/support/Cargo.toml @@ -14,7 +14,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"] } +codec = { package = "parity-scale-codec", version = "3.2.2", 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" } diff --git a/frame/support/test/Cargo.toml b/frame/support/test/Cargo.toml index 7fe1bcb5674bb..fc211d77132f5 100644 --- a/frame/support/test/Cargo.toml +++ b/frame/support/test/Cargo.toml @@ -13,7 +13,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"] } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } sp-arithmetic = { version = "6.0.0", default-features = false, path = "../../../primitives/arithmetic" } sp-io = { version = "7.0.0", path = "../../../primitives/io", default-features = false } diff --git a/frame/support/test/compile_pass/Cargo.toml b/frame/support/test/compile_pass/Cargo.toml index ea22a735b3698..dd5e1b996db9c 100644 --- a/frame/support/test/compile_pass/Cargo.toml +++ b/frame/support/test/compile_pass/Cargo.toml @@ -12,7 +12,7 @@ repository = "https://github.com/paritytech/substrate/" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.2.2", 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" } diff --git a/frame/support/test/pallet/Cargo.toml b/frame/support/test/pallet/Cargo.toml index bf5febeb45441..135d0e64b8ff4 100644 --- a/frame/support/test/pallet/Cargo.toml +++ b/frame/support/test/pallet/Cargo.toml @@ -12,7 +12,7 @@ repository = "https://github.com/paritytech/substrate/" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.2.2", 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/system/Cargo.toml b/frame/system/Cargo.toml index 55c9b5bda54fa..7f573a9cbd575 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] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } 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 } diff --git a/frame/system/benchmarking/Cargo.toml b/frame/system/benchmarking/Cargo.toml index 30b299ea6a56e..8f00097254609 100644 --- a/frame/system/benchmarking/Cargo.toml +++ b/frame/system/benchmarking/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +codec = { package = "parity-scale-codec", version = "3.2.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, path = "../../benchmarking" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } diff --git a/frame/system/rpc/runtime-api/Cargo.toml b/frame/system/rpc/runtime-api/Cargo.toml index 63d76d731e26e..cedb4e35be0b8 100644 --- a/frame/system/rpc/runtime-api/Cargo.toml +++ b/frame/system/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 = "3.0.0", default-features = false } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../../primitives/api" } [features] diff --git a/frame/timestamp/Cargo.toml b/frame/timestamp/Cargo.toml index df63ed0d72b8e..84c56da24e9d4 100644 --- a/frame/timestamp/Cargo.toml +++ b/frame/timestamp/Cargo.toml @@ -14,7 +14,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive", "max-encoded-len"] } log = { version = "0.4.17", 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" } diff --git a/frame/tips/Cargo.toml b/frame/tips/Cargo.toml index 7d0576ec28cce..c7db61613c03a 100644 --- a/frame/tips/Cargo.toml +++ b/frame/tips/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } 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 } diff --git a/frame/transaction-payment/Cargo.toml b/frame/transaction-payment/Cargo.toml index a2f77b6cf2279..0c98796e4d1a7 100644 --- a/frame/transaction-payment/Cargo.toml +++ b/frame/transaction-payment/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = [ "derive", ] } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } diff --git a/frame/transaction-payment/asset-tx-payment/Cargo.toml b/frame/transaction-payment/asset-tx-payment/Cargo.toml index 8e4645a2677f9..324e17a0808a4 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, 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"] } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", optional = true } diff --git a/frame/transaction-payment/rpc/Cargo.toml b/frame/transaction-payment/rpc/Cargo.toml index b77143201ffd4..b9bf226e2da9e 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 = "3.0.0" } +codec = { package = "parity-scale-codec", version = "3.2.2" } 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" } diff --git a/frame/transaction-payment/rpc/runtime-api/Cargo.toml b/frame/transaction-payment/rpc/runtime-api/Cargo.toml index 86753526fef47..854e4310b46dd 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 = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.2.2", 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 = "7.0.0", default-features = false, path = "../../../../primitives/runtime" } diff --git a/frame/transaction-storage/Cargo.toml b/frame/transaction-storage/Cargo.toml index 73867c3643a69..527ff4f240169 100644 --- a/frame/transaction-storage/Cargo.toml +++ b/frame/transaction-storage/Cargo.toml @@ -14,7 +14,7 @@ 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 } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false } 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" } diff --git a/frame/treasury/Cargo.toml b/frame/treasury/Cargo.toml index 993f89ff0faa5..1fd1d7b3d4620 100644 --- a/frame/treasury/Cargo.toml +++ b/frame/treasury/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = [ "derive", "max-encoded-len", ] } diff --git a/frame/try-runtime/Cargo.toml b/frame/try-runtime/Cargo.toml index 87aca0d1ed9f0..042dba5ed88ad 100644 --- a/frame/try-runtime/Cargo.toml +++ b/frame/try-runtime/Cargo.toml @@ -12,7 +12,7 @@ description = "FRAME pallet for democracy" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"]} +codec = { package = "parity-scale-codec", version = "3.2.2", 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 = "7.0.0", default-features = false, path = "../../primitives/runtime" } diff --git a/frame/uniques/Cargo.toml b/frame/uniques/Cargo.toml index 6e36240748c4b..a01ea60d8c3e5 100644 --- a/frame/uniques/Cargo.toml +++ b/frame/uniques/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false } log = { version = "0.4.17", 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" } diff --git a/frame/utility/Cargo.toml b/frame/utility/Cargo.toml index de293ed5df8af..099526d3dcb9e 100644 --- a/frame/utility/Cargo.toml +++ b/frame/utility/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +codec = { package = "parity-scale-codec", version = "3.2.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/vesting/Cargo.toml b/frame/vesting/Cargo.toml index 23fa06454b23c..c18d1f45e038b 100644 --- a/frame/vesting/Cargo.toml +++ b/frame/vesting/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = [ "derive", ] } log = { version = "0.4.17", default-features = false } diff --git a/frame/whitelist/Cargo.toml b/frame/whitelist/Cargo.toml index f3f44d3187a8e..56ceaca9f81a4 100644 --- a/frame/whitelist/Cargo.toml +++ b/frame/whitelist/Cargo.toml @@ -12,7 +12,7 @@ description = "FRAME pallet for whitelisting call, and dispatch from specific or targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive", "max-encoded-len"] } 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" } diff --git a/primitives/api/Cargo.toml b/primitives/api/Cargo.toml index 3139c66cef921..75197bcaea900 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 = "3.0.0", default-features = false } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false } sp-api-proc-macro = { version = "4.0.0-dev", path = "proc-macro" } sp-core = { version = "7.0.0", default-features = false, path = "../core" } sp-std = { version = "5.0.0", default-features = false, path = "../std" } diff --git a/primitives/api/test/Cargo.toml b/primitives/api/test/Cargo.toml index 7f15287cf36d6..b3ceb14fe0d66 100644 --- a/primitives/api/test/Cargo.toml +++ b/primitives/api/test/Cargo.toml @@ -19,7 +19,7 @@ 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" } +codec = { package = "parity-scale-codec", version = "3.2.2" } sp-state-machine = { version = "0.13.0", path = "../../state-machine" } trybuild = "1.0.74" rustversion = "1.0.6" diff --git a/primitives/application-crypto/Cargo.toml b/primitives/application-crypto/Cargo.toml index 39a3413bcf981..e7aa118dfd6ac 100644 --- a/primitives/application-crypto/Cargo.toml +++ b/primitives/application-crypto/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] 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"] } +codec = { package = "parity-scale-codec", version = "3.2.2", 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 = "5.0.0", default-features = false, path = "../std" } diff --git a/primitives/arithmetic/Cargo.toml b/primitives/arithmetic/Cargo.toml index 2da8767fd2a7d..bbb4bbd1776b1 100644 --- a/primitives/arithmetic/Cargo.toml +++ b/primitives/arithmetic/Cargo.toml @@ -14,7 +14,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = [ "derive", "max-encoded-len", ] } diff --git a/primitives/arithmetic/src/lib.rs b/primitives/arithmetic/src/lib.rs index f1f8fc8b59830..590aaa3166448 100644 --- a/primitives/arithmetic/src/lib.rs +++ b/primitives/arithmetic/src/lib.rs @@ -50,14 +50,14 @@ pub use rational::{Rational128, RationalInfinite}; use sp_std::{cmp::Ordering, fmt::Debug, prelude::*}; use traits::{BaseArithmetic, One, SaturatedConversion, Unsigned, Zero}; -use codec::{Decode, Encode}; +use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; /// Arithmetic errors. -#[derive(Eq, PartialEq, Clone, Copy, Encode, Decode, Debug, TypeInfo)] +#[derive(Eq, PartialEq, Clone, Copy, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] pub enum ArithmeticError { /// Underflow. diff --git a/primitives/authority-discovery/Cargo.toml b/primitives/authority-discovery/Cargo.toml index 4b450a4da4a88..ff36cf58d366e 100644 --- a/primitives/authority-discovery/Cargo.toml +++ b/primitives/authority-discovery/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +codec = { package = "parity-scale-codec", version = "3.2.2", 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 = "7.0.0", default-features = false, path = "../application-crypto" } diff --git a/primitives/authorship/Cargo.toml b/primitives/authorship/Cargo.toml index 49107ebed1db0..31ea3b2d4c8f3 100644 --- a/primitives/authorship/Cargo.toml +++ b/primitives/authorship/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-trait = { version = "0.1.57", optional = true } -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../inherents" } sp-runtime = { version = "7.0.0", default-features = false, path = "../runtime" } sp-std = { version = "5.0.0", default-features = false, path = "../std" } diff --git a/primitives/beefy/Cargo.toml b/primitives/beefy/Cargo.toml index b286d9878b44e..6a22f0383a3d0 100644 --- a/primitives/beefy/Cargo.toml +++ b/primitives/beefy/Cargo.toml @@ -12,7 +12,7 @@ description = "Primitives for BEEFY protocol." targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.2.2", 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" } diff --git a/primitives/block-builder/Cargo.toml b/primitives/block-builder/Cargo.toml index 7770a0e210c63..6ccb7980df36e 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] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +codec = { package = "parity-scale-codec", version = "3.2.2", 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 = "7.0.0", default-features = false, path = "../runtime" } diff --git a/primitives/blockchain/Cargo.toml b/primitives/blockchain/Cargo.toml index 7f5f22fe09b73..68791852d8458 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] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } futures = "0.3.21" log = "0.4.17" lru = "0.8.1" diff --git a/primitives/consensus/aura/Cargo.toml b/primitives/consensus/aura/Cargo.toml index 51b20e4fb7e01..001dc4a69aca4 100644 --- a/primitives/consensus/aura/Cargo.toml +++ b/primitives/consensus/aura/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-trait = { version = "0.1.57", optional = true } -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +codec = { package = "parity-scale-codec", version = "3.2.2", 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 = "7.0.0", default-features = false, path = "../../application-crypto" } diff --git a/primitives/consensus/babe/Cargo.toml b/primitives/consensus/babe/Cargo.toml index 25cb8a2bf64da..334fff2811941 100644 --- a/primitives/consensus/babe/Cargo.toml +++ b/primitives/consensus/babe/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-trait = { version = "0.1.57", optional = true } -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false } 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 } diff --git a/primitives/consensus/common/Cargo.toml b/primitives/consensus/common/Cargo.toml index 9b4cac722adcd..83b09f9eb47e2 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.57" -codec = { package = "parity-scale-codec", version = "3.0.0", features = [ +codec = { package = "parity-scale-codec", version = "3.2.2", features = [ "derive", ] } futures = { version = "0.3.21", features = ["thread-pool"] } diff --git a/primitives/consensus/pow/Cargo.toml b/primitives/consensus/pow/Cargo.toml index 495372089e195..6cc832b5afa5f 100644 --- a/primitives/consensus/pow/Cargo.toml +++ b/primitives/consensus/pow/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../api" } sp-core = { version = "7.0.0", default-features = false, path = "../../core" } sp-runtime = { version = "7.0.0", default-features = false, path = "../../runtime" } diff --git a/primitives/consensus/slots/Cargo.toml b/primitives/consensus/slots/Cargo.toml index 3360e80772084..a4d85dff6ea85 100644 --- a/primitives/consensus/slots/Cargo.toml +++ b/primitives/consensus/slots/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } +codec = { package = "parity-scale-codec", version = "3.2.2", 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-std = { version = "5.0.0", default-features = false, path = "../../std" } diff --git a/primitives/consensus/vrf/Cargo.toml b/primitives/consensus/vrf/Cargo.toml index 7159da2aa1883..a4f92c30cca03 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 = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +codec = { package = "parity-scale-codec", version = "3.2.2", 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 = "7.0.0", default-features = false, path = "../../core" } diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index 68c780c473f0a..f9a522178f4c8 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -13,7 +13,7 @@ documentation = "https://docs.rs/sp-core" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = [ "derive", "max-encoded-len", ] } diff --git a/primitives/externalities/Cargo.toml b/primitives/externalities/Cargo.toml index c3d32370dc32f..0777111d88c22 100644 --- a/primitives/externalities/Cargo.toml +++ b/primitives/externalities/Cargo.toml @@ -14,7 +14,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false } environmental = { version = "1.1.3", default-features = false } sp-std = { version = "5.0.0", default-features = false, path = "../std" } sp-storage = { version = "7.0.0", default-features = false, path = "../storage" } diff --git a/primitives/finality-grandpa/Cargo.toml b/primitives/finality-grandpa/Cargo.toml index c33646e3cd2b8..39bb6713a2394 100644 --- a/primitives/finality-grandpa/Cargo.toml +++ b/primitives/finality-grandpa/Cargo.toml @@ -14,7 +14,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } grandpa = { package = "finality-grandpa", version = "0.16.1", default-features = false, features = ["derive-codec"] } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } diff --git a/primitives/inherents/Cargo.toml b/primitives/inherents/Cargo.toml index 8f6d8aef155ac..c901a6e68a181 100644 --- a/primitives/inherents/Cargo.toml +++ b/primitives/inherents/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-trait = { version = "0.1.57", optional = true } -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } impl-trait-for-tuples = "0.2.2" thiserror = { version = "1.0.30", optional = true } sp-core = { version = "7.0.0", default-features = false, path = "../core" } diff --git a/primitives/io/Cargo.toml b/primitives/io/Cargo.toml index d83c82c02227b..e56bfcf56041a 100644 --- a/primitives/io/Cargo.toml +++ b/primitives/io/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] bytes = { version = "1.1.0", default-features = false } -codec = { package = "parity-scale-codec", version = "3.1.3", default-features = false, features = ["bytes"] } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["bytes"] } 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" } diff --git a/primitives/keystore/Cargo.toml b/primitives/keystore/Cargo.toml index 0d5d7ca5637eb..9386cb5d104d2 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.57" -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } futures = "0.3.21" merlin = { version = "2.0", default-features = false } parking_lot = { version = "0.12.1", default-features = false } diff --git a/primitives/merkle-mountain-range/Cargo.toml b/primitives/merkle-mountain-range/Cargo.toml index 2e532990a5caf..97add1ed1d37c 100644 --- a/primitives/merkle-mountain-range/Cargo.toml +++ b/primitives/merkle-mountain-range/Cargo.toml @@ -12,7 +12,7 @@ description = "Merkle Mountain Range primitives." targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +codec = { package = "parity-scale-codec", version = "3.2.2", 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 } diff --git a/primitives/npos-elections/Cargo.toml b/primitives/npos-elections/Cargo.toml index 702986da309ef..7a4bdbd679f0e 100644 --- a/primitives/npos-elections/Cargo.toml +++ b/primitives/npos-elections/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.2.2", 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 = "6.0.0", default-features = false, path = "../arithmetic" } diff --git a/primitives/npos-elections/fuzzer/Cargo.toml b/primitives/npos-elections/fuzzer/Cargo.toml index 860ed6b18810d..8a058cc92edcf 100644 --- a/primitives/npos-elections/fuzzer/Cargo.toml +++ b/primitives/npos-elections/fuzzer/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] clap = { version = "4.0.9", features = ["derive"] } -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } honggfuzz = "0.5" rand = { version = "0.8", features = ["std", "small_rng"] } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } diff --git a/primitives/runtime-interface/Cargo.toml b/primitives/runtime-interface/Cargo.toml index da746179e281d..f2ddc84b1e2c2 100644 --- a/primitives/runtime-interface/Cargo.toml +++ b/primitives/runtime-interface/Cargo.toml @@ -20,7 +20,7 @@ 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"] } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["bytes"] } static_assertions = "1.0.0" primitive-types = { version = "0.12.0", default-features = false } sp-storage = { version = "7.0.0", default-features = false, path = "../storage" } diff --git a/primitives/runtime/Cargo.toml b/primitives/runtime/Cargo.toml index 79bbda700de29..3976de60cdcf9 100644 --- a/primitives/runtime/Cargo.toml +++ b/primitives/runtime/Cargo.toml @@ -14,7 +14,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } +codec = { package = "parity-scale-codec", version = "3.2.2", 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" diff --git a/primitives/runtime/src/lib.rs b/primitives/runtime/src/lib.rs index 96fe7d2487f48..8a32d0b9b4221 100644 --- a/primitives/runtime/src/lib.rs +++ b/primitives/runtime/src/lib.rs @@ -474,7 +474,7 @@ pub type DispatchResult = sp_std::result::Result<(), DispatchError>; pub type DispatchResultWithInfo = sp_std::result::Result>; /// Reason why a pallet call failed. -#[derive(Eq, Clone, Copy, Encode, Decode, Debug, TypeInfo)] +#[derive(Eq, Clone, Copy, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] pub struct ModuleError { /// Module index, matching the metadata module index. @@ -494,7 +494,7 @@ impl PartialEq for ModuleError { } /// Errors related to transactional storage layers. -#[derive(Eq, PartialEq, Clone, Copy, Encode, Decode, Debug, TypeInfo)] +#[derive(Eq, PartialEq, Clone, Copy, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] pub enum TransactionalError { /// Too many transactional layers have been spawned. @@ -519,7 +519,7 @@ impl From for DispatchError { } /// Reason why a dispatch call failed. -#[derive(Eq, Clone, Copy, Encode, Decode, Debug, TypeInfo, PartialEq)] +#[derive(Eq, Clone, Copy, Encode, Decode, Debug, TypeInfo, PartialEq, MaxEncodedLen)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] pub enum DispatchError { /// Some error occurred. @@ -602,7 +602,7 @@ impl From for DispatchError { } /// Description of what went wrong when trying to complete an operation on a token. -#[derive(Eq, PartialEq, Clone, Copy, Encode, Decode, Debug, TypeInfo)] +#[derive(Eq, PartialEq, Clone, Copy, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] pub enum TokenError { /// Funds are unavailable. diff --git a/primitives/session/Cargo.toml b/primitives/session/Cargo.toml index 94f9e8a23505a..31ec009ab2c64 100644 --- a/primitives/session/Cargo.toml +++ b/primitives/session/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.2.2", 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 = "7.0.0", default-features = false, path = "../core" } diff --git a/primitives/staking/Cargo.toml b/primitives/staking/Cargo.toml index 35feae43ebb8c..a8e5a543dbf75 100644 --- a/primitives/staking/Cargo.toml +++ b/primitives/staking/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } sp-core = { version = "7.0.0", default-features = false, path = "../core" } sp-runtime = { version = "7.0.0", default-features = false, path = "../runtime" } diff --git a/primitives/state-machine/Cargo.toml b/primitives/state-machine/Cargo.toml index 06419c5925cf8..595dfe286d225 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] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false } hash-db = { version = "0.15.2", default-features = false } log = { version = "0.4.17", optional = true } parking_lot = { version = "0.12.1", optional = true } diff --git a/primitives/storage/Cargo.toml b/primitives/storage/Cargo.toml index eb166ee3730ff..72ebc40fc1135 100644 --- a/primitives/storage/Cargo.toml +++ b/primitives/storage/Cargo.toml @@ -14,7 +14,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } impl-serde = { version = "0.4.0", optional = true } ref-cast = "1.0.0" serde = { version = "1.0.136", features = ["derive"], optional = true } diff --git a/primitives/test-primitives/Cargo.toml b/primitives/test-primitives/Cargo.toml index 1d12ed74ee6ce..deb120104b717 100644 --- a/primitives/test-primitives/Cargo.toml +++ b/primitives/test-primitives/Cargo.toml @@ -12,7 +12,7 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } 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" } diff --git a/primitives/timestamp/Cargo.toml b/primitives/timestamp/Cargo.toml index 5d015086c4d79..27e306040f654 100644 --- a/primitives/timestamp/Cargo.toml +++ b/primitives/timestamp/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-trait = { version = "0.1.57", optional = true } -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } futures-timer = { version = "3.0.2", optional = true } log = { version = "0.4.17", optional = true } thiserror = { version = "1.0.30", optional = true } diff --git a/primitives/tracing/Cargo.toml b/primitives/tracing/Cargo.toml index 794785085c8b4..602f83c7b4939 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 = "5.0.0", path = "../std", default-features = false } -codec = { version = "3.0.0", package = "parity-scale-codec", default-features = false, features = [ +codec = { version = "3.2.2", 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 ea6419dfaa1ba..565d3d8d29f1c 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] async-trait = { version = "0.1.57", optional = true } -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.2.2", 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 = "7.0.0", optional = true, path = "../core" } diff --git a/primitives/trie/Cargo.toml b/primitives/trie/Cargo.toml index 68a5fb17c3c34..3f045a1cb216d 100644 --- a/primitives/trie/Cargo.toml +++ b/primitives/trie/Cargo.toml @@ -19,7 +19,7 @@ harness = false [dependencies] ahash = { version = "0.7.6", optional = true } -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +codec = { package = "parity-scale-codec", version = "3.2.2", 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 } diff --git a/primitives/version/Cargo.toml b/primitives/version/Cargo.toml index 56fabcd566475..7d32c540f9a10 100644 --- a/primitives/version/Cargo.toml +++ b/primitives/version/Cargo.toml @@ -14,7 +14,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } 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"] } diff --git a/primitives/version/proc-macro/Cargo.toml b/primitives/version/proc-macro/Cargo.toml index 3d129d4753a15..abe9e579a20da 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] -codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive" ] } +codec = { package = "parity-scale-codec", version = "3.2.2", features = [ "derive" ] } proc-macro2 = "1.0.37" quote = "1.0.10" syn = { version = "1.0.98", features = ["full", "fold", "extra-traits", "visit"] } diff --git a/primitives/wasm-interface/Cargo.toml b/primitives/wasm-interface/Cargo.toml index 1822ae43edb68..69937e6b05205 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] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } impl-trait-for-tuples = "0.2.2" log = { version = "0.4.17", optional = true } wasmi = { version = "0.13", optional = true } diff --git a/primitives/weights/Cargo.toml b/primitives/weights/Cargo.toml index 00da83069e388..2368b913b3b2f 100644 --- a/primitives/weights/Cargo.toml +++ b/primitives/weights/Cargo.toml @@ -13,7 +13,7 @@ documentation = "https://docs.rs/sp-wasm-interface" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.2.2", 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"] } smallvec = "1.8.0" diff --git a/test-utils/client/Cargo.toml b/test-utils/client/Cargo.toml index 106ec21d79464..682c868f290d2 100644 --- a/test-utils/client/Cargo.toml +++ b/test-utils/client/Cargo.toml @@ -15,7 +15,7 @@ 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" } +codec = { package = "parity-scale-codec", version = "3.2.2" } futures = "0.3.21" serde = "1.0.136" serde_json = "1.0.85" diff --git a/test-utils/runtime/Cargo.toml b/test-utils/runtime/Cargo.toml index cff0227d03184..2c943c47f32b0 100644 --- a/test-utils/runtime/Cargo.toml +++ b/test-utils/runtime/Cargo.toml @@ -19,7 +19,7 @@ sp-application-crypto = { version = "7.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 = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.2.2", 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 = "7.0.0", optional = true, path = "../../primitives/keyring" } diff --git a/test-utils/runtime/client/Cargo.toml b/test-utils/runtime/client/Cargo.toml index 2ac944edc637f..7d5c9673f6e21 100644 --- a/test-utils/runtime/client/Cargo.toml +++ b/test-utils/runtime/client/Cargo.toml @@ -12,7 +12,7 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0" } +codec = { package = "parity-scale-codec", version = "3.2.2" } futures = "0.3.21" sc-block-builder = { version = "0.10.0-dev", path = "../../../client/block-builder" } sc-client-api = { version = "4.0.0-dev", path = "../../../client/api" } diff --git a/test-utils/runtime/transaction-pool/Cargo.toml b/test-utils/runtime/transaction-pool/Cargo.toml index f5cba2b99be56..5ce397474fec6 100644 --- a/test-utils/runtime/transaction-pool/Cargo.toml +++ b/test-utils/runtime/transaction-pool/Cargo.toml @@ -12,7 +12,7 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0" } +codec = { package = "parity-scale-codec", version = "3.2.2" } futures = "0.3.21" parking_lot = "0.12.1" thiserror = "1.0" diff --git a/utils/fork-tree/Cargo.toml b/utils/fork-tree/Cargo.toml index 4ac176f645bd1..c60ef8fd33e82 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 = "3.0.0", features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.2.2", features = ["derive"] } diff --git a/utils/frame/benchmarking-cli/Cargo.toml b/utils/frame/benchmarking-cli/Cargo.toml index 9e231b8173fb1..fc23d07b6216f 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"] array-bytes = "4.1" chrono = "0.4" clap = { version = "4.0.9", features = ["derive"] } -codec = { package = "parity-scale-codec", version = "3.0.0" } +codec = { package = "parity-scale-codec", version = "3.2.2" } comfy-table = { version = "6.0.0", default-features = false } handlebars = "4.2.2" Inflector = "0.11.4" diff --git a/utils/frame/remote-externalities/Cargo.toml b/utils/frame/remote-externalities/Cargo.toml index 5a51dbc661c90..8611ae4980f12 100644 --- a/utils/frame/remote-externalities/Cargo.toml +++ b/utils/frame/remote-externalities/Cargo.toml @@ -12,7 +12,7 @@ description = "An externalities provided environment that can load itself from r targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0" } +codec = { package = "parity-scale-codec", version = "3.2.2" } log = "0.4.17" serde = "1.0.136" 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 dd6456f714a3e..17a68e2f4cbe8 100644 --- a/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml +++ b/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +codec = { package = "parity-scale-codec", version = "3.2.2", 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 066038469292d..d75d3a5af5da4 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] -codec = { package = "parity-scale-codec", version = "3.0.0" } +codec = { package = "parity-scale-codec", version = "3.2.2" } jsonrpsee = { version = "0.16.2", features = ["jsonrpsee-types"] } serde = "1" frame-support = { version = "4.0.0-dev", path = "../../../../frame/support" } diff --git a/utils/frame/rpc/system/Cargo.toml b/utils/frame/rpc/system/Cargo.toml index 55fc4b27dbf73..b6848ceb2911e 100644 --- a/utils/frame/rpc/system/Cargo.toml +++ b/utils/frame/rpc/system/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0" } +codec = { package = "parity-scale-codec", version = "3.2.2" } jsonrpsee = { version = "0.16.2", features = ["client-core", "server", "macros"] } futures = "0.3.21" log = "0.4.17" diff --git a/utils/frame/try-runtime/cli/Cargo.toml b/utils/frame/try-runtime/cli/Cargo.toml index ed0f25cae7a36..8c14ddc2916b0 100644 --- a/utils/frame/try-runtime/cli/Cargo.toml +++ b/utils/frame/try-runtime/cli/Cargo.toml @@ -33,7 +33,7 @@ substrate-rpc-client = { path = "../../rpc/client" } clap = { version = "4.0.9", features = ["derive"] } hex = { version = "0.4.3", default-features = false } log = "0.4.17" -parity-scale-codec = "3.0.0" +parity-scale-codec = "3.2.2" serde = "1.0.136" serde_json = "1.0.85" zstd = { version = "0.11.2", default-features = false } From b85d631d49b93d446074b364eb0e036c5ff12e22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Thu, 19 Jan 2023 17:56:35 -0300 Subject: [PATCH 304/715] Remove fixtures from crate (#13181) --- frame/contracts/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/frame/contracts/Cargo.toml b/frame/contracts/Cargo.toml index c238bdd14e73b..0ee9e36f1dc78 100644 --- a/frame/contracts/Cargo.toml +++ b/frame/contracts/Cargo.toml @@ -8,6 +8,7 @@ homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME pallet for WASM contracts" readme = "README.md" +include = ["src/**/*", "README.md", "CHANGELOG.md"] [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] From d7acf9effdbb3a869fb3af75ce4adbb86c29918a Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Thu, 19 Jan 2023 23:21:41 +0100 Subject: [PATCH 305/715] txpool: LOG_TARGET const added (#13180) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * txpool: LOG_TARGET const added part of: #12873 * LOG_TARGET added to tests mod * txpool::api for api * Apply suggestions from code review Co-authored-by: Bastian Köcher * ".git/.scripts/commands/fmt/fmt.sh" Co-authored-by: Bastian Köcher Co-authored-by: command-bot <> --- client/transaction-pool/api/src/lib.rs | 6 ++-- client/transaction-pool/src/api.rs | 3 +- .../transaction-pool/src/enactment_state.rs | 27 +++++++++----- .../transaction-pool/src/graph/base_pool.rs | 14 +++++--- client/transaction-pool/src/graph/listener.rs | 20 +++++++---- client/transaction-pool/src/graph/pool.rs | 15 +++++--- client/transaction-pool/src/graph/ready.rs | 10 +++--- .../src/graph/validated_pool.rs | 27 ++++++++------ client/transaction-pool/src/lib.rs | 26 +++++++------- client/transaction-pool/src/revalidation.rs | 32 ++++++++++++----- client/transaction-pool/tests/pool.rs | 36 ++++++++++--------- 11 files changed, 135 insertions(+), 81 deletions(-) diff --git a/client/transaction-pool/api/src/lib.rs b/client/transaction-pool/api/src/lib.rs index c1e49ad07d7b1..870760962a520 100644 --- a/client/transaction-pool/api/src/lib.rs +++ b/client/transaction-pool/api/src/lib.rs @@ -30,6 +30,8 @@ use sp_runtime::{ }; use std::{collections::HashMap, hash::Hash, pin::Pin, sync::Arc}; +const LOG_TARGET: &str = "txpool::api"; + pub use sp_runtime::transaction_validity::{ TransactionLongevity, TransactionPriority, TransactionSource, TransactionTag, }; @@ -353,7 +355,7 @@ impl OffchainSubmitTransaction for TP extrinsic: ::Extrinsic, ) -> Result<(), ()> { log::debug!( - target: "txpool", + target: LOG_TARGET, "(offchain call) Submitting a transaction to the pool: {:?}", extrinsic ); @@ -362,7 +364,7 @@ impl OffchainSubmitTransaction for TP result.map(|_| ()).map_err(|e| { log::warn!( - target: "txpool", + target: LOG_TARGET, "(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 a2b317cfb3998..0166dfaced208 100644 --- a/client/transaction-pool/src/api.rs +++ b/client/transaction-pool/src/api.rs @@ -18,6 +18,7 @@ //! Chain api required for the transaction pool. +use crate::LOG_TARGET; use codec::Encode; use futures::{ channel::{mpsc, oneshot}, @@ -85,7 +86,7 @@ impl FullChainApi { let metrics = prometheus.map(ApiMetrics::register).and_then(|r| match r { Err(err) => { log::warn!( - target: "txpool", + target: LOG_TARGET, "Failed to register transaction pool api prometheus metrics: {:?}", err, ); diff --git a/client/transaction-pool/src/enactment_state.rs b/client/transaction-pool/src/enactment_state.rs index 382b2683156b6..7252c0dec7f2a 100644 --- a/client/transaction-pool/src/enactment_state.rs +++ b/client/transaction-pool/src/enactment_state.rs @@ -18,6 +18,7 @@ //! Substrate transaction pool implementation. +use crate::LOG_TARGET; use num_traits::CheckedSub; use sc_transaction_pool_api::ChainEvent; use sp_blockchain::TreeRoute; @@ -113,14 +114,14 @@ where }; if skip_maintenance { - log::debug!(target: "txpool", "skip maintain: tree_route would be too long"); + log::debug!(target: LOG_TARGET, "skip maintain: tree_route would be too long"); self.force_update(event); return Ok(EnactmentAction::Skip) } // block was already finalized if self.recent_finalized_block == new_hash { - log::debug!(target: "txpool", "handle_enactment: block already finalized"); + log::debug!(target: LOG_TARGET, "handle_enactment: block already finalized"); return Ok(EnactmentAction::Skip) } @@ -129,9 +130,13 @@ where let tree_route = tree_route(self.recent_best_block, new_hash)?; log::debug!( - target: "txpool", + target: LOG_TARGET, "resolve hash:{:?} finalized:{:?} tree_route:{:?} best_block:{:?} finalized_block:{:?}", - new_hash, finalized, tree_route, self.recent_best_block, self.recent_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 @@ -139,9 +144,10 @@ where // 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", + target: LOG_TARGET, "Recently finalized block {} would be retracted by ChainEvent {}, skipping", - self.recent_finalized_block, new_hash + self.recent_finalized_block, + new_hash ); return Ok(EnactmentAction::Skip) } @@ -155,7 +161,7 @@ where // remains valid. if tree_route.enacted().is_empty() { log::trace!( - target: "txpool", + target: LOG_TARGET, "handle_enactment: no newly enacted blocks since recent best block" ); return Ok(EnactmentAction::HandleFinalization) @@ -176,7 +182,12 @@ where 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); + log::debug!( + target: LOG_TARGET, + "forced update: {:?}, {:?}", + self.recent_best_block, + self.recent_finalized_block, + ); } } diff --git a/client/transaction-pool/src/graph/base_pool.rs b/client/transaction-pool/src/graph/base_pool.rs index 67580d698b8c1..44371be62c621 100644 --- a/client/transaction-pool/src/graph/base_pool.rs +++ b/client/transaction-pool/src/graph/base_pool.rs @@ -22,6 +22,7 @@ use std::{cmp::Ordering, collections::HashSet, fmt, hash, sync::Arc}; +use crate::LOG_TARGET; use log::{debug, trace, warn}; use sc_transaction_pool_api::{error, InPoolTransaction, PoolStatus}; use serde::Serialize; @@ -272,9 +273,9 @@ impl BasePool BasePool if first { - debug!(target: "txpool", "[{:?}] Error importing: {:?}", current_hash, e); + debug!(target: LOG_TARGET, "[{:?}] Error importing: {:?}", current_hash, e); return Err(e) } else { failed.push(current_hash); @@ -347,7 +348,7 @@ impl BasePool BasePool promoted.push(res), Err(e) => { - warn!(target: "txpool", "[{:?}] Failed to promote during pruning: {:?}", hash, e); + warn!( + target: LOG_TARGET, + "[{:?}] Failed to promote during pruning: {:?}", hash, e, + ); failed.push(hash) }, } diff --git a/client/transaction-pool/src/graph/listener.rs b/client/transaction-pool/src/graph/listener.rs index 776749abf2d5d..c603a542c2767 100644 --- a/client/transaction-pool/src/graph/listener.rs +++ b/client/transaction-pool/src/graph/listener.rs @@ -18,6 +18,7 @@ use std::{collections::HashMap, fmt::Debug, hash}; +use crate::LOG_TARGET; use linked_hash_map::LinkedHashMap; use log::{debug, trace}; use serde::Serialize; @@ -67,13 +68,13 @@ impl Listener { /// Notify the listeners about extrinsic broadcast. pub fn broadcasted(&mut self, hash: &H, peers: Vec) { - trace!(target: "txpool", "[{:?}] Broadcasted", hash); + trace!(target: LOG_TARGET, "[{:?}] Broadcasted", hash); self.fire(hash, |watcher| watcher.broadcast(peers)); } /// New transaction was added to the ready pool or promoted from the future pool. pub fn ready(&mut self, tx: &H, old: Option<&H>) { - trace!(target: "txpool", "[{:?}] Ready (replaced with {:?})", tx, old); + trace!(target: LOG_TARGET, "[{:?}] Ready (replaced with {:?})", tx, old); self.fire(tx, |watcher| watcher.ready()); if let Some(old) = old { self.fire(old, |watcher| watcher.usurped(tx.clone())); @@ -82,13 +83,13 @@ impl Listener { /// New transaction was added to the future pool. pub fn future(&mut self, tx: &H) { - trace!(target: "txpool", "[{:?}] Future", tx); + trace!(target: LOG_TARGET, "[{:?}] Future", tx); self.fire(tx, |watcher| watcher.future()); } /// Transaction was dropped from the pool because of the limit. pub fn dropped(&mut self, tx: &H, by: Option<&H>) { - trace!(target: "txpool", "[{:?}] Dropped (replaced with {:?})", tx, by); + trace!(target: LOG_TARGET, "[{:?}] Dropped (replaced with {:?})", tx, by); self.fire(tx, |watcher| match by { Some(t) => watcher.usurped(t.clone()), None => watcher.dropped(), @@ -97,13 +98,13 @@ impl Listener { /// Transaction was removed as invalid. pub fn invalid(&mut self, tx: &H) { - debug!(target: "txpool", "[{:?}] Extrinsic invalid", tx); + debug!(target: LOG_TARGET, "[{:?}] Extrinsic invalid", tx); self.fire(tx, |watcher| watcher.invalid()); } /// Transaction was pruned from the pool. pub fn pruned(&mut self, block_hash: BlockHash, tx: &H) { - debug!(target: "txpool", "[{:?}] Pruned at {:?}", tx, block_hash); + debug!(target: LOG_TARGET, "[{:?}] Pruned at {:?}", tx, block_hash); // Get the transactions included in the given block hash. let txs = self.finality_watchers.entry(block_hash).or_insert(vec![]); txs.push(tx.clone()); @@ -134,7 +135,12 @@ impl Listener { pub fn finalized(&mut self, block_hash: BlockHash) { if let Some(hashes) = self.finality_watchers.remove(&block_hash) { for (tx_index, hash) in hashes.into_iter().enumerate() { - log::debug!(target: "txpool", "[{:?}] Sent finalization event (block {:?})", hash, block_hash); + log::debug!( + target: LOG_TARGET, + "[{:?}] Sent finalization event (block {:?})", + hash, + 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 8e3570d1dbd1f..14217d56aaa57 100644 --- a/client/transaction-pool/src/graph/pool.rs +++ b/client/transaction-pool/src/graph/pool.rs @@ -18,6 +18,7 @@ use std::{collections::HashMap, sync::Arc, time::Duration}; +use crate::LOG_TARGET; use futures::{channel::mpsc::Receiver, Future}; use sc_transaction_pool_api::error; use sp_blockchain::TreeRoute; @@ -208,7 +209,8 @@ impl Pool { ) { let now = Instant::now(); self.validated_pool.resubmit(revalidated_transactions); - log::debug!(target: "txpool", + log::debug!( + target: LOG_TARGET, "Resubmitted. Took {} ms. Status: {:?}", now.elapsed().as_millis(), self.validated_pool.status() @@ -249,7 +251,7 @@ impl Pool { extrinsics: &[ExtrinsicFor], ) -> Result<(), B::Error> { log::debug!( - target: "txpool", + target: LOG_TARGET, "Starting pruning of block {:?} (extrinsics: {})", at, extrinsics.len() @@ -287,7 +289,10 @@ impl Pool { future_tags.extend(validity.provides); } } else { - log::trace!(target: "txpool", "txpool is empty, skipping validation for block {at:?}"); + log::trace!( + target: LOG_TARGET, + "txpool is empty, skipping validation for block {at:?}", + ); } }, } @@ -323,7 +328,7 @@ impl Pool { tags: impl IntoIterator, known_imported_hashes: impl IntoIterator> + Clone, ) -> Result<(), B::Error> { - log::debug!(target: "txpool", "Pruning at {:?}", at); + log::debug!(target: LOG_TARGET, "Pruning at {:?}", at); // Prune all transactions that provide given tags let prune_status = self.validated_pool.prune_tags(tags)?; @@ -342,7 +347,7 @@ impl Pool { let reverified_transactions = self.verify(at, pruned_transactions, CheckBannedBeforeVerify::Yes).await?; - log::trace!(target: "txpool", "Pruning at {:?}. Resubmitting transactions.", at); + log::trace!(target: LOG_TARGET, "Pruning at {:?}. Resubmitting transactions.", at); // And finally - submit reverified transactions back to the pool self.validated_pool.resubmit_pruned( diff --git a/client/transaction-pool/src/graph/ready.rs b/client/transaction-pool/src/graph/ready.rs index b52372a3c4d10..9040c81b3c434 100644 --- a/client/transaction-pool/src/graph/ready.rs +++ b/client/transaction-pool/src/graph/ready.rs @@ -23,6 +23,7 @@ use std::{ sync::Arc, }; +use crate::LOG_TARGET; use log::{debug, trace}; use sc_transaction_pool_api::error; use serde::Serialize; @@ -314,7 +315,7 @@ impl ReadyTransactions { } // add to removed - trace!(target: "txpool", "[{:?}] Removed as part of the subtree.", hash); + trace!(target: LOG_TARGET, "[{:?}] Removed as part of the subtree.", hash); removed.push(tx.transaction.transaction); } } @@ -521,7 +522,7 @@ impl BestIterator { pub fn report_invalid(&mut self, tx: &Arc>) { if let Some(to_report) = self.all.get(&tx.hash) { debug!( - target: "txpool", + target: LOG_TARGET, "[{:?}] Reported as invalid. Will skip sub-chains while iterating.", to_report.transaction.transaction.hash ); @@ -544,9 +545,8 @@ impl Iterator for BestIterator { // Check if the transaction was marked invalid. if self.invalid.contains(hash) { debug!( - target: "txpool", - "[{:?}] Skipping invalid child transaction while iterating.", - hash + target: LOG_TARGET, + "[{:?}] Skipping invalid child transaction while iterating.", hash, ); continue } diff --git a/client/transaction-pool/src/graph/validated_pool.rs b/client/transaction-pool/src/graph/validated_pool.rs index ab99a090e5654..bf8a059af2ff1 100644 --- a/client/transaction-pool/src/graph/validated_pool.rs +++ b/client/transaction-pool/src/graph/validated_pool.rs @@ -22,6 +22,7 @@ use std::{ sync::Arc, }; +use crate::LOG_TARGET; use futures::channel::mpsc::{channel, Sender}; use parking_lot::{Mutex, RwLock}; use sc_transaction_pool_api::{error, PoolStatus, ReadyTransactions}; @@ -199,7 +200,7 @@ impl ValidatedPool { Err(e) => if e.is_full() { log::warn!( - target: "txpool", + target: LOG_TARGET, "[{:?}] Trying to notify an import but the channel is full", hash, ); @@ -230,15 +231,17 @@ impl ValidatedPool { let ready_limit = &self.options.ready; let future_limit = &self.options.future; - log::debug!(target: "txpool", "Pool Status: {:?}", status); + log::debug!(target: LOG_TARGET, "Pool Status: {:?}", status); if ready_limit.is_exceeded(status.ready, status.ready_bytes) || future_limit.is_exceeded(status.future, status.future_bytes) { log::debug!( - target: "txpool", + target: LOG_TARGET, "Enforcing limits ({}/{}kB ready, {}/{}kB future", - ready_limit.count, ready_limit.total_bytes / 1024, - future_limit.count, future_limit.total_bytes / 1024, + ready_limit.count, + ready_limit.total_bytes / 1024, + future_limit.count, + future_limit.total_bytes / 1024, ); // clean up the pool @@ -254,7 +257,7 @@ impl ValidatedPool { removed }; if !removed.is_empty() { - log::debug!(target: "txpool", "Enforcing limits: {} dropped", removed.len()); + log::debug!(target: LOG_TARGET, "Enforcing limits: {} dropped", removed.len()); } // run notifications @@ -385,7 +388,7 @@ impl ValidatedPool { // unknown to caller => let's just notify listeners (and issue debug // message) log::warn!( - target: "txpool", + target: LOG_TARGET, "[{:?}] Removing invalid transaction from update: {}", hash, err, @@ -595,14 +598,14 @@ impl ValidatedPool { return vec![] } - log::debug!(target: "txpool", "Removing invalid transactions: {:?}", hashes); + log::debug!(target: LOG_TARGET, "Removing invalid transactions: {:?}", hashes); // temporarily ban invalid transactions self.rotator.ban(&Instant::now(), hashes.iter().cloned()); let invalid = self.pool.write().remove_subtree(hashes); - log::debug!(target: "txpool", "Removed invalid transactions: {:?}", invalid); + log::debug!(target: LOG_TARGET, "Removed invalid transactions: {:?}", invalid); let mut listener = self.listener.write(); for tx in &invalid { @@ -629,7 +632,11 @@ impl ValidatedPool { /// Notify all watchers that transactions in the block with hash have been finalized pub async fn on_block_finalized(&self, block_hash: BlockHash) -> Result<(), B::Error> { - log::trace!(target: "txpool", "Attempting to notify watchers of finalization for {}", block_hash); + log::trace!( + target: LOG_TARGET, + "Attempting to notify watchers of finalization for {}", + block_hash, + ); self.listener.write().finalized(block_hash); Ok(()) } diff --git a/client/transaction-pool/src/lib.rs b/client/transaction-pool/src/lib.rs index 1cd9bef77bc69..44bda82da38a1 100644 --- a/client/transaction-pool/src/lib.rs +++ b/client/transaction-pool/src/lib.rs @@ -67,6 +67,8 @@ use prometheus_endpoint::Registry as PrometheusRegistry; use sp_blockchain::{HashAndNumber, TreeRoute}; +pub(crate) const LOG_TARGET: &str = "txpool"; + type BoxedReadyIterator = Box>> + Send>; @@ -116,7 +118,7 @@ impl ReadyPoll { while idx < self.pollers.len() { if self.pollers[idx].0 <= number { let poller_sender = self.pollers.swap_remove(idx); - log::debug!(target: "txpool", "Sending ready signal at block {}", number); + log::debug!(target: LOG_TARGET, "Sending ready signal at block {}", number); let _ = poller_sender.1.send(iterator_factory()); } else { idx += 1; @@ -336,7 +338,7 @@ where } if self.ready_poll.lock().updated_at() >= at { - log::trace!(target: "txpool", "Transaction pool already processed block #{}", at); + log::trace!(target: LOG_TARGET, "Transaction pool already processed block #{}", at); let iterator: ReadyIteratorFor = Box::new(self.pool.validated_pool().ready()); return async move { iterator }.boxed() } @@ -554,16 +556,16 @@ async fn prune_known_txs_for_block>(); - log::trace!(target: "txpool", "Pruning transactions: {:?}", hashes); + log::trace!(target: LOG_TARGET, "Pruning transactions: {:?}", hashes); let header = match api.block_header(block_hash) { Ok(Some(h)) => h, Ok(None) => { - log::debug!(target: "txpool", "Could not find header for {:?}.", block_hash); + log::debug!(target: LOG_TARGET, "Could not find header for {:?}.", block_hash); return hashes }, Err(e) => { - log::debug!(target: "txpool", "Error retrieving header for {:?}: {}", block_hash, e); + log::debug!(target: LOG_TARGET, "Error retrieving header for {:?}: {}", block_hash, e); return hashes }, }; @@ -587,7 +589,7 @@ where /// (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:?}"); + log::trace!(target: LOG_TARGET, "handle_enactment tree_route: {tree_route:?}"); let pool = self.pool.clone(); let api = self.api.clone(); @@ -595,7 +597,7 @@ where Some(HashAndNumber { hash, number }) => (hash, number), None => { log::warn!( - target: "txpool", + target: LOG_TARGET, "Skipping ChainEvent - no last block in tree route {:?}", tree_route, ); @@ -666,7 +668,7 @@ where if !contains { log::debug!( - target: "txpool", + target: LOG_TARGET, "[{:?}]: Resubmitting from retracted block {:?}", tx_hash, hash, @@ -691,7 +693,7 @@ where .await { log::debug!( - target: "txpool", + target: LOG_TARGET, "[{:?}] Error re-submitting transactions: {}", hash, e, @@ -742,7 +744,7 @@ where match result { Err(msg) => { - log::debug!(target: "txpool", "{msg}"); + log::debug!(target: LOG_TARGET, "{msg}"); self.enactment_state.lock().force_update(&event); }, Ok(EnactmentAction::Skip) => return, @@ -754,7 +756,7 @@ where if let ChainEvent::Finalized { hash, tree_route } = event { log::trace!( - target: "txpool", + target: LOG_TARGET, "on-finalized enacted: {tree_route:?}, previously finalized: \ {prev_finalized_block:?}", ); @@ -762,7 +764,7 @@ where 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", + target: LOG_TARGET, "Error occurred while attempting to notify watchers about finalization {}: {}", hash, e ) diff --git a/client/transaction-pool/src/revalidation.rs b/client/transaction-pool/src/revalidation.rs index d8c8bea625fb3..99602b50a2269 100644 --- a/client/transaction-pool/src/revalidation.rs +++ b/client/transaction-pool/src/revalidation.rs @@ -24,7 +24,10 @@ use std::{ sync::Arc, }; -use crate::graph::{ChainApi, ExtrinsicHash, NumberFor, Pool, ValidatedTransaction}; +use crate::{ + graph::{ChainApi, ExtrinsicHash, NumberFor, Pool, ValidatedTransaction}, + LOG_TARGET, +}; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; use sp_runtime::{ generic::BlockId, @@ -82,13 +85,23 @@ async fn batch_revalidate( for (validation_result, ext_hash, ext) in validation_results { match validation_result { Ok(Err(TransactionValidityError::Invalid(err))) => { - log::debug!(target: "txpool", "[{:?}]: Revalidation: invalid {:?}", ext_hash, err); + log::debug!( + target: LOG_TARGET, + "[{:?}]: Revalidation: invalid {:?}", + ext_hash, + err, + ); invalid_hashes.push(ext_hash); }, Ok(Err(TransactionValidityError::Unknown(err))) => { // skipping unknown, they might be pushed by valid or invalid transaction // when latter resubmitted. - log::trace!(target: "txpool", "[{:?}]: Unknown during revalidation: {:?}", ext_hash, err); + log::trace!( + target: LOG_TARGET, + "[{:?}]: Unknown during revalidation: {:?}", + ext_hash, + err, + ); }, Ok(Ok(validity)) => { revalidated.insert( @@ -105,7 +118,7 @@ async fn batch_revalidate( }, Err(validation_err) => { log::debug!( - target: "txpool", + target: LOG_TARGET, "[{:?}]: Removing due to error during revalidation: {}", ext_hash, validation_err @@ -183,7 +196,7 @@ impl RevalidationWorker { // we don't add something that already scheduled for revalidation if self.members.contains_key(&ext_hash) { log::trace!( - target: "txpool", + target: LOG_TARGET, "[{:?}] Skipped adding for revalidation: Already there.", ext_hash, ); @@ -231,7 +244,7 @@ impl RevalidationWorker { if batch_len > 0 || this.len() > 0 { log::debug!( - target: "txpool", + target: LOG_TARGET, "Revalidated {} transactions. Left in the queue for revalidation: {}.", batch_len, this.len(), @@ -248,7 +261,7 @@ impl RevalidationWorker { if this.members.len() > 0 { log::debug!( - target: "txpool", + target: LOG_TARGET, "Updated revalidation queue at {:?}. Transactions: {:?}", this.best_block, this.members, @@ -320,14 +333,15 @@ where ) { if transactions.len() > 0 { log::debug!( - target: "txpool", "Sent {} transactions to revalidation queue", + target: LOG_TARGET, + "Sent {} transactions to revalidation queue", transactions.len(), ); } if let Some(ref to_worker) = self.background { if let Err(e) = to_worker.unbounded_send(WorkerPayload { at, transactions }) { - log::warn!(target: "txpool", "Failed to update background worker: {:?}", e); + log::warn!(target: LOG_TARGET, "Failed to update background worker: {:?}", e); } } else { let pool = self.pool.clone(); diff --git a/client/transaction-pool/tests/pool.rs b/client/transaction-pool/tests/pool.rs index 27d62c3250abc..511f6d9e24b5f 100644 --- a/client/transaction-pool/tests/pool.rs +++ b/client/transaction-pool/tests/pool.rs @@ -45,6 +45,8 @@ use substrate_test_runtime_client::{ }; use substrate_test_runtime_transaction_pool::{uxt, TestApi}; +const LOG_TARGET: &str = "txpool"; + fn pool() -> Pool { Pool::new(Default::default(), true.into(), TestApi::with_alice_nonce(209).into()) } @@ -505,7 +507,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); + log::trace!(target: LOG_TARGET, ">> B1: {:?} {:?}", header.hash(), header); let event = ChainEvent::NewBestBlock { hash: header.hash(), tree_route: None }; b1 = header.hash(); block_on(pool.maintain(event)); @@ -521,7 +523,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); + log::trace!(target: LOG_TARGET, ">> C2: {:?} {:?}", header.hash(), header); let event = ChainEvent::NewBestBlock { hash: header.hash(), tree_route: None }; c2 = header.hash(); block_on(pool.maintain(event)); @@ -536,7 +538,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); + log::trace!(target: LOG_TARGET, ">> D2: {:?} {:?}", header.hash(), header); let event = ChainEvent::NewBestBlock { hash: header.hash(), tree_route: None }; d2 = header.hash(); block_on(pool.maintain(event)); @@ -550,7 +552,7 @@ fn fork_aware_finalization() { .expect("1.Imported"); assert_eq!(pool.status().ready, 1); let header = pool.api().push_block_with_parent(b1, vec![from_charlie.clone()], true); - log::trace!(target:"txpool", ">> C1: {:?} {:?}", header.hash(), header); + log::trace!(target: LOG_TARGET, ">> C1: {:?} {:?}", header.hash(), header); c1 = header.hash(); canon_watchers.push((watcher, header.hash())); let event = block_event_with_retracted(header.clone(), d2, pool.api()); @@ -568,7 +570,7 @@ fn fork_aware_finalization() { .expect("1. Imported"); assert_eq!(pool.status().ready, 3); let header = pool.api().push_block_with_parent(c1, vec![xt.clone()], true); - log::trace!(target:"txpool", ">> D1: {:?} {:?}", header.hash(), header); + log::trace!(target: LOG_TARGET, ">> D1: {:?} {:?}", header.hash(), header); d1 = header.hash(); canon_watchers.push((w, header.hash())); @@ -584,7 +586,7 @@ fn fork_aware_finalization() { // block E1 { let header = pool.api().push_block_with_parent(d1, vec![from_dave, from_bob], true); - log::trace!(target:"txpool", ">> E1: {:?} {:?}", header.hash(), header); + log::trace!(target: LOG_TARGET, ">> E1: {:?} {:?}", header.hash(), header); e1 = header.hash(); let event = ChainEvent::NewBestBlock { hash: header.hash(), tree_route: None }; block_on(pool.maintain(event)); @@ -1115,7 +1117,7 @@ fn switching_fork_with_finalized_works() { 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); + log::trace!(target: LOG_TARGET, ">> B1: {:?} {:?}", header.hash(), header); b1_header = header; } @@ -1131,7 +1133,7 @@ fn switching_fork_with_finalized_works() { ); assert_eq!(pool.status().ready, 2); - log::trace!(target:"txpool", ">> B2: {:?} {:?}", header.hash(), header); + log::trace!(target: LOG_TARGET, ">> B2: {:?} {:?}", header.hash(), header); b2_header = header; } @@ -1193,7 +1195,7 @@ fn switching_fork_multiple_times_works() { 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); + log::trace!(target: LOG_TARGET, ">> B1: {:?} {:?}", header.hash(), header); b1_header = header; } @@ -1209,7 +1211,7 @@ fn switching_fork_multiple_times_works() { ); assert_eq!(pool.status().ready, 2); - log::trace!(target:"txpool", ">> B2: {:?} {:?}", header.hash(), header); + log::trace!(target: LOG_TARGET, ">> B2: {:?} {:?}", header.hash(), header); b2_header = header; } @@ -1306,7 +1308,7 @@ fn two_blocks_delayed_finalization_works() { .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); + log::trace!(target: LOG_TARGET, ">> B1: {:?} {:?}", header.hash(), header); b1_header = header; } @@ -1320,7 +1322,7 @@ fn two_blocks_delayed_finalization_works() { .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); + log::trace!(target: LOG_TARGET, ">> C1: {:?} {:?}", header.hash(), header); c1_header = header; } @@ -1334,7 +1336,7 @@ fn two_blocks_delayed_finalization_works() { .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); + log::trace!(target: LOG_TARGET, ">> D1: {:?} {:?}", header.hash(), header); d1_header = header; } @@ -1418,7 +1420,7 @@ fn delayed_finalization_does_not_retract() { .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); + log::trace!(target: LOG_TARGET, ">> B1: {:?} {:?}", header.hash(), header); b1_header = header; } @@ -1432,7 +1434,7 @@ fn delayed_finalization_does_not_retract() { .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); + log::trace!(target: LOG_TARGET, ">> C1: {:?} {:?}", header.hash(), header); c1_header = header; } @@ -1513,7 +1515,7 @@ fn best_block_after_finalization_does_not_retract() { .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); + log::trace!(target: LOG_TARGET, ">> B1: {:?} {:?}", header.hash(), header); b1_header = header; } @@ -1527,7 +1529,7 @@ fn best_block_after_finalization_does_not_retract() { .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); + log::trace!(target: LOG_TARGET, ">> C1: {:?} {:?}", header.hash(), header); c1_header = header; } From de943ee152ccedc0b418caac6061409431f74a49 Mon Sep 17 00:00:00 2001 From: Marcin S Date: Fri, 20 Jan 2023 11:19:30 +0100 Subject: [PATCH 306/715] Fix potential huge allocation as a result of `validate_block` output (#13183) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix potential huge allocation as a result of `validate_block` output * Address review comments; add more tests * Update client/executor/wasmtime/src/runtime.rs * Remove unnecessary comments Co-authored-by: Bastian Köcher --- Cargo.lock | 2 + client/executor/Cargo.toml | 1 + client/executor/runtime-test/Cargo.toml | 1 + client/executor/runtime-test/src/lib.rs | 37 +++++++++- client/executor/src/integration_tests/mod.rs | 71 +++++++++++++++++++- client/executor/wasmtime/src/runtime.rs | 17 ++++- 6 files changed, 125 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dbb046ccd86af..348f23d736d37 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8270,6 +8270,7 @@ name = "sc-executor" version = "0.10.0-dev" dependencies = [ "array-bytes", + "assert_matches", "criterion", "env_logger", "lru", @@ -8842,6 +8843,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", + "sp-runtime-interface", "sp-std", "substrate-wasm-builder", ] diff --git a/client/executor/Cargo.toml b/client/executor/Cargo.toml index 4604b976b4248..8bedcd3edcff3 100644 --- a/client/executor/Cargo.toml +++ b/client/executor/Cargo.toml @@ -35,6 +35,7 @@ sp-wasm-interface = { version = "7.0.0", path = "../../primitives/wasm-interface [dev-dependencies] array-bytes = "4.1" +assert_matches = "1.3.0" wat = "1.0" sc-runtime-test = { version = "2.0.0", path = "runtime-test" } substrate-test-runtime = { version = "2.0.0", path = "../../test-utils/runtime" } diff --git a/client/executor/runtime-test/Cargo.toml b/client/executor/runtime-test/Cargo.toml index e99f3caa9447e..07626c2343361 100644 --- a/client/executor/runtime-test/Cargo.toml +++ b/client/executor/runtime-test/Cargo.toml @@ -16,6 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] 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-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" } [build-dependencies] diff --git a/client/executor/runtime-test/src/lib.rs b/client/executor/runtime-test/src/lib.rs index fc98d1909d00d..0aa30e4bc9675 100644 --- a/client/executor/runtime-test/src/lib.rs +++ b/client/executor/runtime-test/src/lib.rs @@ -29,6 +29,8 @@ use sp_runtime::{ print, traits::{BlakeTwo256, Hash}, }; +#[cfg(not(feature = "std"))] +use sp_runtime_interface::pack_ptr_and_len; extern "C" { #[allow(dead_code)] @@ -38,6 +40,10 @@ extern "C" { fn yet_another_missing_external(); } +#[cfg(not(feature = "std"))] +/// The size of a WASM page in bytes. +const WASM_PAGE_SIZE: usize = 65536; + #[cfg(not(feature = "std"))] /// Mutable static variables should be always observed to have /// the initialized value at the start of a runtime call. @@ -92,7 +98,7 @@ sp_core::wasm_export_functions! { let heap_ptr = heap_base as usize; // Find the next wasm page boundary. - let heap_ptr = round_up_to(heap_ptr, 65536); + let heap_ptr = round_up_to(heap_ptr, WASM_PAGE_SIZE); // Make it an actual pointer let heap_ptr = heap_ptr as *mut u8; @@ -337,3 +343,32 @@ sp_core::wasm_export_functions! { return 1234; } } + +// Returns a huge len. It should result in an error, and not an allocation. +#[no_mangle] +#[cfg(not(feature = "std"))] +pub extern "C" fn test_return_huge_len(_params: *const u8, _len: usize) -> u64 { + pack_ptr_and_len(0, u32::MAX) +} + +// Returns an offset right at the edge of the wasm memory boundary. With length 0, it should +// succeed. +#[no_mangle] +#[cfg(not(feature = "std"))] +pub extern "C" fn test_return_max_memory_offset(_params: *const u8, _len: usize) -> u64 { + pack_ptr_and_len((core::arch::wasm32::memory_size(0) * WASM_PAGE_SIZE) as u32, 0) +} + +// Returns an offset right at the edge of the wasm memory boundary. With length 1, it should fail. +#[no_mangle] +#[cfg(not(feature = "std"))] +pub extern "C" fn test_return_max_memory_offset_plus_one(_params: *const u8, _len: usize) -> u64 { + pack_ptr_and_len((core::arch::wasm32::memory_size(0) * WASM_PAGE_SIZE) as u32, 1) +} + +// Returns an output that overflows the u32 range. It should result in an error. +#[no_mangle] +#[cfg(not(feature = "std"))] +pub extern "C" fn test_return_overflow(_params: *const u8, _len: usize) -> u64 { + pack_ptr_and_len(u32::MAX, 1) +} diff --git a/client/executor/src/integration_tests/mod.rs b/client/executor/src/integration_tests/mod.rs index 25b999f115363..22e651abe98e2 100644 --- a/client/executor/src/integration_tests/mod.rs +++ b/client/executor/src/integration_tests/mod.rs @@ -19,8 +19,13 @@ #[cfg(target_os = "linux")] mod linux; +use assert_matches::assert_matches; use codec::{Decode, Encode}; -use sc_executor_common::{error::Error, runtime_blob::RuntimeBlob, wasm_runtime::WasmModule}; +use sc_executor_common::{ + error::{Error, WasmError}, + runtime_blob::RuntimeBlob, + wasm_runtime::WasmModule, +}; use sc_runtime_test::wasm_binary_unwrap; use sp_core::{ blake2_128, blake2_256, ed25519, map, @@ -781,3 +786,67 @@ fn return_value(wasm_method: WasmExecutionMethod) { (1234u64).encode() ); } + +test_wasm_execution!(return_huge_len); +fn return_huge_len(wasm_method: WasmExecutionMethod) { + let mut ext = TestExternalities::default(); + let mut ext = ext.ext(); + + match call_in_wasm("test_return_huge_len", &[], wasm_method, &mut ext).unwrap_err() { + Error::Runtime => { + assert_matches!(wasm_method, WasmExecutionMethod::Interpreted); + }, + Error::RuntimeConstruction(WasmError::Other(error)) => { + assert_matches!(wasm_method, WasmExecutionMethod::Compiled { .. }); + assert_eq!(error, "output exceeds bounds of wasm memory"); + }, + error => panic!("unexpected error: {:?}", error), + } +} + +test_wasm_execution!(return_max_memory_offset); +fn return_max_memory_offset(wasm_method: WasmExecutionMethod) { + let mut ext = TestExternalities::default(); + let mut ext = ext.ext(); + + assert_eq!( + call_in_wasm("test_return_max_memory_offset", &[], wasm_method, &mut ext).unwrap(), + ().encode() + ); +} + +test_wasm_execution!(return_max_memory_offset_plus_one); +fn return_max_memory_offset_plus_one(wasm_method: WasmExecutionMethod) { + let mut ext = TestExternalities::default(); + let mut ext = ext.ext(); + + match call_in_wasm("test_return_max_memory_offset_plus_one", &[], wasm_method, &mut ext) + .unwrap_err() + { + Error::Runtime => { + assert_matches!(wasm_method, WasmExecutionMethod::Interpreted); + }, + Error::RuntimeConstruction(WasmError::Other(error)) => { + assert_matches!(wasm_method, WasmExecutionMethod::Compiled { .. }); + assert_eq!(error, "output exceeds bounds of wasm memory"); + }, + error => panic!("unexpected error: {:?}", error), + } +} + +test_wasm_execution!(return_overflow); +fn return_overflow(wasm_method: WasmExecutionMethod) { + let mut ext = TestExternalities::default(); + let mut ext = ext.ext(); + + match call_in_wasm("test_return_overflow", &[], wasm_method, &mut ext).unwrap_err() { + Error::Runtime => { + assert_matches!(wasm_method, WasmExecutionMethod::Interpreted); + }, + Error::RuntimeConstruction(WasmError::Other(error)) => { + assert_matches!(wasm_method, WasmExecutionMethod::Compiled { .. }); + assert_eq!(error, "output exceeds bounds of wasm memory"); + }, + error => panic!("unexpected error: {:?}", error), + } +} diff --git a/client/executor/wasmtime/src/runtime.rs b/client/executor/wasmtime/src/runtime.rs index b124fd627dc69..a45dfa59b954a 100644 --- a/client/executor/wasmtime/src/runtime.rs +++ b/client/executor/wasmtime/src/runtime.rs @@ -30,6 +30,7 @@ use sc_executor_common::{ runtime_blob::{ self, DataSegmentsSnapshot, ExposedMutableGlobalsSet, GlobalsSnapshot, RuntimeBlob, }, + util::checked_range, wasm_runtime::{InvokeMethod, WasmInstance, WasmModule}, }; use sp_runtime_interface::unpack_ptr_and_len; @@ -41,7 +42,7 @@ use std::{ Arc, }, }; -use wasmtime::{Engine, Memory, StoreLimits, Table}; +use wasmtime::{AsContext, Engine, Memory, StoreLimits, Table}; pub(crate) struct StoreData { /// The limits we apply to the store. We need to store it here to return a reference to this @@ -793,7 +794,19 @@ fn extract_output_data( output_ptr: u32, output_len: u32, ) -> Result> { + let ctx = instance.store(); + + // Do a length check before allocating. The returned output should not be bigger than the + // available WASM memory. Otherwise, a malicious parachain can trigger a large allocation, + // potentially causing memory exhaustion. + // + // Get the size of the WASM memory in bytes. + let memory_size = ctx.as_context().data().memory().data_size(ctx); + if checked_range(output_ptr as usize, output_len as usize, memory_size).is_none() { + Err(WasmError::Other("output exceeds bounds of wasm memory".into()))? + } let mut output = vec![0; output_len as usize]; - util::read_memory_into(instance.store(), Pointer::new(output_ptr), &mut output)?; + + util::read_memory_into(ctx, Pointer::new(output_ptr), &mut output)?; Ok(output) } From 593c76b7e0249fbacd68b87be71a42a557b47b8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Fri, 20 Jan 2023 16:59:16 +0100 Subject: [PATCH 307/715] sc-network: Ensure private addresses are disabled if requested (#13185) When running with `--no-private-ipv4` the node should not trying to connect to any private ip addresses. With the switch to libp2p this behavior was broken. Part of this version upgrade was the following pr: https://github.com/libp2p/rust-libp2p/pull/2995. This pr changed the default cache size of `libp2p-identity` from `0` aka disabled to `100`. Together with our implementation that was calling into `identity` to request addresses for a given peer. Before the switch to libp2p 0.50.0 this was returning zero addresses, but now with the cache enabled it started to return addresses. This pr fixes this by only letting discovery return addresses for a peer. It also ensures that we filter private addresses if requested. The cache is also disabled to restore the previous caching behavior, but it will actually not be called anymore. --- client/network/src/peer_info.rs | 12 +++++++----- client/network/src/protocol.rs | 6 ++++-- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/client/network/src/peer_info.rs b/client/network/src/peer_info.rs index 97604a82c35b0..f3402c0af110c 100644 --- a/client/network/src/peer_info.rs +++ b/client/network/src/peer_info.rs @@ -89,7 +89,9 @@ impl PeerInfoBehaviour { pub fn new(user_agent: String, local_public_key: PublicKey) -> Self { let identify = { let cfg = IdentifyConfig::new("/substrate/1.0".to_string(), local_public_key) - .with_agent_version(user_agent); + .with_agent_version(user_agent) + // We don't need any peer information cached. + .with_cache_size(0); Identify::new(cfg) }; @@ -182,10 +184,10 @@ impl NetworkBehaviour for PeerInfoBehaviour { IntoConnectionHandler::select(self.ping.new_handler(), self.identify.new_handler()) } - fn addresses_of_peer(&mut self, peer_id: &PeerId) -> Vec { - let mut list = self.ping.addresses_of_peer(peer_id); - list.extend_from_slice(&self.identify.addresses_of_peer(peer_id)); - list + fn addresses_of_peer(&mut self, _: &PeerId) -> Vec { + // Only `Discovery::addresses_of_peer` must be returning addresses to ensure that we + // don't return unwanted addresses. + Vec::new() } fn on_swarm_event(&mut self, event: FromSwarm) { diff --git a/client/network/src/protocol.rs b/client/network/src/protocol.rs index fd25c6526ff12..cd232334e3b6a 100644 --- a/client/network/src/protocol.rs +++ b/client/network/src/protocol.rs @@ -965,8 +965,10 @@ where self.behaviour.new_handler() } - fn addresses_of_peer(&mut self, peer_id: &PeerId) -> Vec { - self.behaviour.addresses_of_peer(peer_id) + fn addresses_of_peer(&mut self, _: &PeerId) -> Vec { + // Only `Discovery::addresses_of_peer` must be returning addresses to ensure that we + // don't return unwanted addresses. + Vec::new() } fn on_swarm_event(&mut self, event: FromSwarm) { From 38ec2d8957d843fa424397f79a484d773eea1454 Mon Sep 17 00:00:00 2001 From: Sergej Sakac <73715684+Szegoo@users.noreply.github.com> Date: Fri, 20 Jan 2023 20:26:12 +0100 Subject: [PATCH 308/715] Warn validators with slow hardware (#12620) * move Metric * run hardware bench if validiator flag is being used * fix rustdoc & update node-template * fix * unused improt * warn * move Requirement * bench_result * ensure_requirements * make the code compile * check if authority * Update client/sysinfo/src/sysinfo.rs Co-authored-by: Oliver Tale-Yazdi * nit fixes * warning signs * Update client/sysinfo/src/sysinfo.rs Co-authored-by: Oliver Tale-Yazdi Co-authored-by: Oliver Tale-Yazdi --- bin/node/cli/src/service.rs | 7 +- client/sysinfo/src/lib.rs | 3 +- client/sysinfo/src/sysinfo.rs | 135 +++++++++++++++++- utils/frame/benchmarking-cli/src/lib.rs | 2 +- .../benchmarking-cli/src/machine/hardware.rs | 91 +----------- .../frame/benchmarking-cli/src/machine/mod.rs | 5 +- 6 files changed, 144 insertions(+), 99 deletions(-) diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs index cdee61af3f500..ace24f186d4c2 100644 --- a/bin/node/cli/src/service.rs +++ b/bin/node/cli/src/service.rs @@ -21,6 +21,7 @@ //! Service implementation. Specialized wrapper over substrate service. use codec::Encode; +use frame_benchmarking_cli::SUBSTRATE_REFERENCE_HARDWARE; use frame_system_rpc_runtime_api::AccountNonceApi; use futures::prelude::*; use kitchensink_runtime::RuntimeApi; @@ -320,7 +321,11 @@ pub fn new_full_base( 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)) + sc_sysinfo::gather_hwbench( + Some(database_path), + SUBSTRATE_REFERENCE_HARDWARE.clone(), + config.role.is_authority(), + ) }) } else { None diff --git a/client/sysinfo/src/lib.rs b/client/sysinfo/src/lib.rs index cef5a4d210df1..f623bdae53e66 100644 --- a/client/sysinfo/src/lib.rs +++ b/client/sysinfo/src/lib.rs @@ -29,7 +29,8 @@ 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, + serialize_throughput, serialize_throughput_option, Metric, Requirement, Requirements, + Throughput, }; /// The operating system part of the current target triplet. diff --git a/client/sysinfo/src/sysinfo.rs b/client/sysinfo/src/sysinfo.rs index c66a6f6a62aed..800df4b8a41a9 100644 --- a/client/sysinfo/src/sysinfo.rs +++ b/client/sysinfo/src/sysinfo.rs @@ -21,10 +21,10 @@ use crate::{ExecutionLimit, HwBench}; use sc_telemetry::SysInfo; use sp_core::{sr25519, Pair}; use sp_io::crypto::sr25519_verify; -use sp_std::{fmt, prelude::*}; +use sp_std::{fmt, fmt::Formatter, prelude::*}; use rand::{seq::SliceRandom, Rng, RngCore}; -use serde::Serializer; +use serde::{de::Visitor, Deserialize, Deserializer, Serialize, Serializer}; use std::{ fs::File, io::{Seek, SeekFrom, Write}, @@ -33,6 +33,43 @@ use std::{ time::{Duration, Instant}, }; +/// A single hardware metric. +#[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, +} + +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", + } + } +} + /// The unit in which the [`Throughput`] (bytes per second) is denoted. pub enum Unit { GiBs, @@ -137,6 +174,54 @@ where serializer.serialize_none() } +/// 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))? +} + +/// 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. + #[serde( + serialize_with = "serialize_throughput_as_f64", + deserialize_with = "deserialize_throughput" + )] + pub minimum: Throughput, +} + #[inline(always)] pub(crate) fn benchmark( name: &str, @@ -503,8 +588,14 @@ pub fn benchmark_sr25519_verify(limit: ExecutionLimit) -> Throughput { /// 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 { +/// Optionally accepts a path to a `scratch_directory` to use to benchmark the +/// disk. Also accepts the `requirements` for the hardware benchmark and a +/// boolean to specify if the node is an authority. +pub fn gather_hwbench( + scratch_directory: Option<&Path>, + requirements: Requirements, + is_authority: bool, +) -> HwBench { #[allow(unused_mut)] let mut hwbench = HwBench { cpu_hashrate_score: benchmark_cpu(DEFAULT_CPU_EXECUTION_LIMIT), @@ -534,9 +625,45 @@ pub fn gather_hwbench(scratch_directory: Option<&Path>) -> HwBench { }; } + if is_authority { + ensure_requirements(hwbench.clone(), requirements); + } + hwbench } +fn ensure_requirements(hwbench: HwBench, requirements: Requirements) { + let mut failed = 0; + for requirement in requirements.0.iter() { + match requirement.metric { + Metric::Blake2256 => + if requirement.minimum > hwbench.cpu_hashrate_score { + failed += 1; + }, + Metric::MemCopy => + if requirement.minimum > hwbench.memory_memcpy_score { + failed += 1; + }, + Metric::DiskSeqWrite => + if let Some(score) = hwbench.disk_sequential_write_score { + if requirement.minimum > score { + failed += 1; + } + }, + Metric::DiskRndWrite => + if let Some(score) = hwbench.disk_random_write_score { + if requirement.minimum > score { + failed += 1; + } + }, + Metric::Sr25519Verify => {}, + } + } + if failed != 0 { + log::warn!("⚠️ Your hardware performance score was less than expected for role 'Authority'. See https://wiki.polkadot.network/docs/maintain-guides-how-to-validate-polkadot#reference-hardware"); + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/utils/frame/benchmarking-cli/src/lib.rs b/utils/frame/benchmarking-cli/src/lib.rs index a44a208b16ae9..5723a8038fdbb 100644 --- a/utils/frame/benchmarking-cli/src/lib.rs +++ b/utils/frame/benchmarking-cli/src/lib.rs @@ -27,7 +27,7 @@ mod storage; pub use block::BlockCmd; pub use extrinsic::{ExtrinsicBuilder, ExtrinsicCmd, ExtrinsicFactory}; -pub use machine::{MachineCmd, Requirements, SUBSTRATE_REFERENCE_HARDWARE}; +pub use machine::{MachineCmd, SUBSTRATE_REFERENCE_HARDWARE}; pub use overhead::OverheadCmd; pub use pallet::PalletCmd; pub use sc_service::BasePath; diff --git a/utils/frame/benchmarking-cli/src/machine/hardware.rs b/utils/frame/benchmarking-cli/src/machine/hardware.rs index 50c88ec74646c..318c193d7c08c 100644 --- a/utils/frame/benchmarking-cli/src/machine/hardware.rs +++ b/utils/frame/benchmarking-cli/src/machine/hardware.rs @@ -18,40 +18,7 @@ //! Contains types to define hardware requirements. use lazy_static::lazy_static; -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))? -} +use sc_sysinfo::Requirements; lazy_static! { /// The hardware requirements as measured on reference hardware. @@ -67,62 +34,6 @@ lazy_static! { }; } -/// 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. - #[serde( - serialize_with = "serialize_throughput_as_f64", - deserialize_with = "deserialize_throughput" - )] - 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, -} - -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", - } - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/utils/frame/benchmarking-cli/src/machine/mod.rs b/utils/frame/benchmarking-cli/src/machine/mod.rs index 82b4e5be7358e..bcffef255e5b5 100644 --- a/utils/frame/benchmarking-cli/src/machine/mod.rs +++ b/utils/frame/benchmarking-cli/src/machine/mod.rs @@ -30,11 +30,12 @@ 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, Throughput, + benchmark_memory, benchmark_sr25519_verify, ExecutionLimit, Metric, Requirement, Requirements, + Throughput, }; use crate::shared::check_build_profile; -pub use hardware::{Metric, Requirement, Requirements, SUBSTRATE_REFERENCE_HARDWARE}; +pub use hardware::SUBSTRATE_REFERENCE_HARDWARE; /// Command to benchmark the hardware. /// From 2c16842143b92bbfe333498fe1a6dd97733f2080 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Sat, 21 Jan 2023 00:42:00 +0100 Subject: [PATCH 309/715] Use year 2023 in the License headers (#13193) Signed-off-by: Oliver Tale-Yazdi Signed-off-by: Oliver Tale-Yazdi --- HEADER-APACHE2 | 2 +- HEADER-GPL3 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/HEADER-APACHE2 b/HEADER-APACHE2 index 58baa53894ca7..403497a86907f 100644 --- a/HEADER-APACHE2 +++ b/HEADER-APACHE2 @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2023 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 9412b5a70bb35..ed7daba723272 100644 --- a/HEADER-GPL3 +++ b/HEADER-GPL3 @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2023 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify From 355e4a9c87f85637185c0852bda9aeb3db404b6d Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Sat, 21 Jan 2023 11:53:07 +0100 Subject: [PATCH 310/715] Move slow hardware warning print logic to CLI (#13198) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Move slow hardware warning print logic to CLI Signed-off-by: Oliver Tale-Yazdi * Update client/sysinfo/src/sysinfo.rs Co-authored-by: Bastian Köcher * fmt Signed-off-by: Oliver Tale-Yazdi Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Bastian Köcher --- bin/node/cli/src/service.rs | 21 ++++++----- client/sysinfo/src/sysinfo.rs | 66 +++++++++++++++-------------------- 2 files changed, 39 insertions(+), 48 deletions(-) diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs index ace24f186d4c2..d77a333dfa220 100644 --- a/bin/node/cli/src/service.rs +++ b/bin/node/cli/src/service.rs @@ -318,18 +318,12 @@ pub fn new_full_base( &sc_consensus_babe::BabeLink, ), ) -> Result { - let hwbench = if !disable_hardware_benchmarks { - config.database.path().map(|database_path| { + let hwbench = (!disable_hardware_benchmarks) + .then_some(config.database.path().map(|database_path| { let _ = std::fs::create_dir_all(&database_path); - sc_sysinfo::gather_hwbench( - Some(database_path), - SUBSTRATE_REFERENCE_HARDWARE.clone(), - config.role.is_authority(), - ) - }) - } else { - None - }; + sc_sysinfo::gather_hwbench(Some(database_path)) + })) + .flatten(); let sc_service::PartialComponents { client, @@ -403,6 +397,11 @@ pub fn new_full_base( if let Some(hwbench) = hwbench { sc_sysinfo::print_hwbench(&hwbench); + if !SUBSTRATE_REFERENCE_HARDWARE.check_hardware(&hwbench) && role.is_authority() { + log::warn!( + "⚠️ The hardware does not meet the minimal requirements for role 'Authority'." + ); + } if let Some(ref mut telemetry) = telemetry { let telemetry_handle = telemetry.handle(); diff --git a/client/sysinfo/src/sysinfo.rs b/client/sysinfo/src/sysinfo.rs index 800df4b8a41a9..1fbca7d37efb7 100644 --- a/client/sysinfo/src/sysinfo.rs +++ b/client/sysinfo/src/sysinfo.rs @@ -591,11 +591,7 @@ pub fn benchmark_sr25519_verify(limit: ExecutionLimit) -> Throughput { /// Optionally accepts a path to a `scratch_directory` to use to benchmark the /// disk. Also accepts the `requirements` for the hardware benchmark and a /// boolean to specify if the node is an authority. -pub fn gather_hwbench( - scratch_directory: Option<&Path>, - requirements: Requirements, - is_authority: bool, -) -> HwBench { +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), @@ -625,42 +621,38 @@ pub fn gather_hwbench( }; } - if is_authority { - ensure_requirements(hwbench.clone(), requirements); - } - hwbench } -fn ensure_requirements(hwbench: HwBench, requirements: Requirements) { - let mut failed = 0; - for requirement in requirements.0.iter() { - match requirement.metric { - Metric::Blake2256 => - if requirement.minimum > hwbench.cpu_hashrate_score { - failed += 1; - }, - Metric::MemCopy => - if requirement.minimum > hwbench.memory_memcpy_score { - failed += 1; - }, - Metric::DiskSeqWrite => - if let Some(score) = hwbench.disk_sequential_write_score { - if requirement.minimum > score { - failed += 1; - } - }, - Metric::DiskRndWrite => - if let Some(score) = hwbench.disk_random_write_score { - if requirement.minimum > score { - failed += 1; - } - }, - Metric::Sr25519Verify => {}, +impl Requirements { + /// Whether the hardware requirements are met by the provided benchmark results. + pub fn check_hardware(&self, hwbench: &HwBench) -> bool { + for requirement in self.0.iter() { + match requirement.metric { + Metric::Blake2256 => + if requirement.minimum > hwbench.cpu_hashrate_score { + return false + }, + Metric::MemCopy => + if requirement.minimum > hwbench.memory_memcpy_score { + return false + }, + Metric::DiskSeqWrite => + if let Some(score) = hwbench.disk_sequential_write_score { + if requirement.minimum > score { + return false + } + }, + Metric::DiskRndWrite => + if let Some(score) = hwbench.disk_random_write_score { + if requirement.minimum > score { + return false + } + }, + Metric::Sr25519Verify => {}, + } } - } - if failed != 0 { - log::warn!("⚠️ Your hardware performance score was less than expected for role 'Authority'. See https://wiki.polkadot.network/docs/maintain-guides-how-to-validate-polkadot#reference-hardware"); + true } } From 79cb2e63312b16dc3e50d6df5283f7f7842f9bfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Sat, 21 Jan 2023 20:00:24 +0100 Subject: [PATCH 311/715] Fix flaky BABE test (#13199) The `authoring_blocks` test of BABE was calculating the slot based on the timestamp it sometimes failed in CI. The problem is that we combine all the notifications and authoring futures in one big future. This one big future may first polls one authoring future to build a block. Then it polls all notification futures again to import the block. Then some other authoring future is polled and builds on the imported block using the same slot and making the import fail. The solution is that we just artificially increase the slot to make the test work. --- client/consensus/babe/src/tests.rs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/client/consensus/babe/src/tests.rs b/client/consensus/babe/src/tests.rs index f74864a003e2a..304bc9fc22ca9 100644 --- a/client/consensus/babe/src/tests.rs +++ b/client/consensus/babe/src/tests.rs @@ -432,6 +432,7 @@ async fn run_one_test(mutator: impl Fn(&mut TestHeader, Stage) + Send + Sync + ' .for_each(|_| future::ready(())), ); + let client_clone = client.clone(); babe_futures.push( start_babe(BabeParams { block_import: data.block_import.lock().take().expect("import set up during init"), @@ -439,12 +440,19 @@ async fn run_one_test(mutator: impl Fn(&mut TestHeader, Stage) + Send + Sync + ' client, env: environ, sync_oracle: DummyOracle, - create_inherent_data_providers: Box::new(|_, _| async { - let slot = InherentDataProvider::from_timestamp_and_slot_duration( - Timestamp::current(), - SlotDuration::from_millis(SLOT_DURATION_MS), + create_inherent_data_providers: Box::new(move |parent, _| { + // Get the slot of the parent header and just increase this slot. + // + // Below we will running everything in one big future. If we would use + // time based slot, it can happen that on babe instance imports a block from + // another babe instance and then tries to build a block in the same slot making + // this test fail. + let parent_header = client_clone.header(parent).ok().flatten().unwrap(); + let slot = Slot::from( + find_pre_digest::(&parent_header).unwrap().slot() + 1, ); - Ok((slot,)) + + async move { Ok((InherentDataProvider::new(slot),)) } }), force_authoring: false, backoff_authoring_blocks: Some(BackoffAuthoringOnFinalizedHeadLagging::default()), From 1f70226a61807064f3cf95c616d36094358eeb70 Mon Sep 17 00:00:00 2001 From: zjb0807 Date: Sun, 22 Jan 2023 21:34:57 +1300 Subject: [PATCH 312/715] Add debug info in assert_has_event and assert_last_event (#12979) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * improve debug info in assert_has_event and assert_last_event * Apply suggestions from code review Co-authored-by: Bastian Köcher Co-authored-by: Bastian Köcher --- frame/system/src/lib.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 3909b1e9c5257..32627896e86a0 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -1503,13 +1503,21 @@ impl Pallet { /// Assert the given `event` exists. #[cfg(any(feature = "std", feature = "runtime-benchmarks", test))] pub fn assert_has_event(event: T::RuntimeEvent) { - assert!(Self::events().iter().any(|record| record.event == event)) + let events = Self::events(); + assert!( + events.iter().any(|record| record.event == event), + "expected event {event:?} not found in events {events:?}", + ); } /// Assert the last event equal to the given `event`. #[cfg(any(feature = "std", feature = "runtime-benchmarks", test))] pub fn assert_last_event(event: T::RuntimeEvent) { - assert_eq!(Self::events().last().expect("events expected").event, event); + let last_event = Self::events().last().expect("events expected").event.clone(); + assert_eq!( + last_event, event, + "expected event {event:?} is not equal to the last event {last_event:?}", + ); } /// Return the chain's current runtime version. From ed3f055907116e7c194c1e5d0f884b8329ba70cb Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Mon, 23 Jan 2023 02:07:48 -0500 Subject: [PATCH 313/715] new proc-macro-based benchmarking syntax (#12924) * add stub for new benchmark macro * benchmark syntax * add #[extrinsic call] separator * parse #[benchmark] item as a function * proper emission of error when #[extrinsic_call] annotation is missing * clean up * enclosing module via benchmarks! { } working * use an attribute macro on the module instead of benchmarks! { } * cargo fmt * working component implementation * WIP * working * add syntax for Linear * parsing of param ranges (still need to build tuple though) * params parsing WIP * clean up (don't need extrinsic call name) * use proper Result syntax for BenchmarkDef parsing * proper parsing of Linear<0, 1> style args * successfully parse and make use of linear component ranges :boom: * rename support variable => home because eventually will be moved * compile-time check that param range types implement ParamRange * switch to using balances as example, failing on instance pallet * successfully set up __origin and __call with balances :boom: * clean up * use a module * don't need a variable for transfer * rename benchmark_transfer -> transfer because no longer conflicts * clean up * working with transfer_increasing_users as well :boom: * re-add BareBlock * add comments for undocumented structs+functions+traits * refactor in preparation for removing module requirements * switch to a block instead of a module * use the outer macro pattern to to enable #[benchmarks] aggregation * successfully generate SelectedBenchmark :boom: * implement components for SelectedBenchmark * implement instance for SelectedBenchmark * properly track #[extra] * working impl for fn benchmarks() * run_benchmarks WIP * finish run_benchmark! impl :boom: * import balances transfer_best_case benchmark * import transfer_keep_alive balances pallet benchmark * import set_balance_creating balances pallet benchmark * import set_balance_killing balances pallet benchmark * import force_transfer balances pallet benchmark * add #[extra] annotation and docs to transfer_increasing_users * import transfer_all balances pallet benchmark * import force_unreserve balances pallet benchmark * prepare to implement impl_benchmark_test_suite! * ensure tests cover #[extra] before and after #[benchmark] tag * refactor * clean up * fix * move to outer * switch to benchmarks/instance_benchmarks * test impl almost done, strange compiler error * benchmark test suites working :boom: * clean up * add stub and basic parsing for where_clause * working except where clause and extrinsic calls containing method chains * assume option (2) for now wrt https://github.com/paritytech/substrate/pull/12924#issuecomment-1372938718 * clean up * switch to attribute-style * properly handle where clauses * fix subtle missing where clause, now just MessageQueue issues * fix block formatting in message-queue pallet * switch to block vs non-block parsing of extrinsic call * working now but some benchmark tests failing * message-queue tests working (run order issue fixed) :tada: * add comments and internal docs for fame_support_procedural::benchmark * fix license years * docs for lib.rs * add docs to new support procedural macros * don't allow #[benchmark] outside of benchmarking module * add docs * use benchmark(extra, skip_meta) style args * update docs accordingly * appease clippy * bump ci * add notes about `extra` and `skip_meta` * fix doc tests * re-run CI * use `ignore` instead of `no_run` on doc examples * bump CI * replace some if-lets with if-elses * more refactoring of if-let statements * fix remaining if-lets in BenchmarkDef::from() * fix if-lets in benchmarks() * fix remaining if-lets, use nested find_map for extrinsic call * switch to use #[extrinsic_call] or #[block] situationally * refactor ExtrinsicCallDef => BenchmarkCallDef * update docs with info about #[block] * add macro stub for #[extrinsic_call] * fix docs and add stub for #[block] as well * remove unused extern crate line * fix clippy nits * Use V2 bench syntax in pallet-example-basic Just testing the dev-ex... Signed-off-by: Oliver Tale-Yazdi * carry over comment * use curly-brace style for impl_benchmark_test_suite! * remove unneeded parenthesis * proper handling of _() extrinsic call style * add docs for _() syntax * fix crate access * simplify keyword access Co-authored-by: Keith Yeung * simplify module content destructuring Co-authored-by: Keith Yeung * fix crate access "frame_benchmarking" => "frame-benchmarking", compiles * use _() extrinsic call syntax where possible in balances * simplify attr.path.segments.last() Co-authored-by: Keith Yeung * fix compile error being suppressed * simplify extrinsic call keyword parsing Co-authored-by: Keith Yeung * use ? operator instead of return None Co-authored-by: Keith Yeung * rename generics => type_use_generics rename full_generics => type_impl_generics * simplify extrinsic call extraction with transpose * bump CI * nit * proper handling of too many + too few block/extrinsic call annotations * change to B >= A Co-authored-by: Oliver Tale-Yazdi * remove unneeded ignore Co-authored-by: Oliver Tale-Yazdi * remove another ignore Co-authored-by: Oliver Tale-Yazdi * add ui tests * use _() style extrinsic call on accumulate_dummy Co-authored-by: Oliver Tale-Yazdi * add range check to ParamRange * ui test for bad param ranges * fix failing example * add ignore back to other failing example * tweak expr_call span Co-authored-by: Keith Yeung * fix typo * eliminate a match Co-authored-by: Keith Yeung * change pub fn benchmarks to return Result * fix origin error span * more informative error for invalid benchmark parameter name * fix spans on a few benchmark errors * remove unneeded clone * refactor inner loop of benchmark function parsing * preserve mod attributes * refactor outer loop of benchmark def parsing code, greatly simplified * simplify to use a ? operator when parsing benchmark attr path * fix another ? operator * further simplify benchmark function attr parsing with more ? ops * refactor extrinsic call handling to use if let rather than match * replace is_ok => is_err Co-authored-by: Keith Yeung * re-use name during expansion of benchmark def * remove unneeded clone * fix span for origin missing error * fix missing semi Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Oliver Tale-Yazdi Co-authored-by: Keith Yeung Co-authored-by: parity-processbot <> --- Cargo.lock | 14 + frame/balances/src/benchmarking.rs | 127 ++- frame/examples/basic/src/benchmarking.rs | 62 +- frame/message-queue/src/benchmarking.rs | 217 +++-- frame/support/Cargo.toml | 1 + frame/support/procedural/Cargo.toml | 1 + frame/support/procedural/src/benchmark.rs | 860 ++++++++++++++++++ frame/support/procedural/src/lib.rs | 64 ++ frame/support/src/lib.rs | 223 +++++ frame/support/test/Cargo.toml | 2 + frame/support/test/tests/benchmark_ui.rs | 36 + .../test/tests/benchmark_ui/bad_param_name.rs | 18 + .../tests/benchmark_ui/bad_param_name.stderr | 5 + .../benchmark_ui/bad_param_name_too_long.rs | 14 + .../bad_param_name_too_long.stderr | 5 + .../benchmark_ui/bad_param_name_upper_case.rs | 14 + .../bad_param_name_upper_case.stderr | 5 + .../tests/benchmark_ui/bad_param_range.rs | 16 + .../tests/benchmark_ui/bad_param_range.stderr | 5 + .../test/tests/benchmark_ui/bad_params.rs | 18 + .../test/tests/benchmark_ui/bad_params.stderr | 5 + .../test/tests/benchmark_ui/dup_block.rs | 20 + .../test/tests/benchmark_ui/dup_block.stderr | 5 + .../tests/benchmark_ui/dup_extrinsic_call.rs | 20 + .../benchmark_ui/dup_extrinsic_call.stderr | 5 + .../test/tests/benchmark_ui/extra_extra.rs | 16 + .../tests/benchmark_ui/extra_extra.stderr | 5 + .../tests/benchmark_ui/extra_skip_meta.rs | 16 + .../tests/benchmark_ui/extra_skip_meta.stderr | 5 + .../benchmark_ui/extrinsic_call_out_of_fn.rs | 6 + .../extrinsic_call_out_of_fn.stderr | 7 + .../test/tests/benchmark_ui/missing_call.rs | 13 + .../tests/benchmark_ui/missing_call.stderr | 5 + .../test/tests/benchmark_ui/missing_origin.rs | 16 + .../tests/benchmark_ui/missing_origin.stderr | 5 + .../tests/benchmark_ui/pass/valid_basic.rs | 17 + .../tests/benchmark_ui/unrecognized_option.rs | 16 + .../benchmark_ui/unrecognized_option.stderr | 5 + 38 files changed, 1760 insertions(+), 134 deletions(-) create mode 100644 frame/support/procedural/src/benchmark.rs create mode 100644 frame/support/test/tests/benchmark_ui.rs create mode 100644 frame/support/test/tests/benchmark_ui/bad_param_name.rs create mode 100644 frame/support/test/tests/benchmark_ui/bad_param_name.stderr create mode 100644 frame/support/test/tests/benchmark_ui/bad_param_name_too_long.rs create mode 100644 frame/support/test/tests/benchmark_ui/bad_param_name_too_long.stderr create mode 100644 frame/support/test/tests/benchmark_ui/bad_param_name_upper_case.rs create mode 100644 frame/support/test/tests/benchmark_ui/bad_param_name_upper_case.stderr create mode 100644 frame/support/test/tests/benchmark_ui/bad_param_range.rs create mode 100644 frame/support/test/tests/benchmark_ui/bad_param_range.stderr create mode 100644 frame/support/test/tests/benchmark_ui/bad_params.rs create mode 100644 frame/support/test/tests/benchmark_ui/bad_params.stderr create mode 100644 frame/support/test/tests/benchmark_ui/dup_block.rs create mode 100644 frame/support/test/tests/benchmark_ui/dup_block.stderr create mode 100644 frame/support/test/tests/benchmark_ui/dup_extrinsic_call.rs create mode 100644 frame/support/test/tests/benchmark_ui/dup_extrinsic_call.stderr create mode 100644 frame/support/test/tests/benchmark_ui/extra_extra.rs create mode 100644 frame/support/test/tests/benchmark_ui/extra_extra.stderr create mode 100644 frame/support/test/tests/benchmark_ui/extra_skip_meta.rs create mode 100644 frame/support/test/tests/benchmark_ui/extra_skip_meta.stderr create mode 100644 frame/support/test/tests/benchmark_ui/extrinsic_call_out_of_fn.rs create mode 100644 frame/support/test/tests/benchmark_ui/extrinsic_call_out_of_fn.stderr create mode 100644 frame/support/test/tests/benchmark_ui/missing_call.rs create mode 100644 frame/support/test/tests/benchmark_ui/missing_call.stderr create mode 100644 frame/support/test/tests/benchmark_ui/missing_origin.rs create mode 100644 frame/support/test/tests/benchmark_ui/missing_origin.stderr create mode 100644 frame/support/test/tests/benchmark_ui/pass/valid_basic.rs create mode 100644 frame/support/test/tests/benchmark_ui/unrecognized_option.rs create mode 100644 frame/support/test/tests/benchmark_ui/unrecognized_option.stderr diff --git a/Cargo.lock b/Cargo.lock index 348f23d736d37..08948ffbd970b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1614,6 +1614,17 @@ dependencies = [ "rusticata-macros", ] +[[package]] +name = "derive-syn-parse" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e79116f119dd1dba1abf1f3405f03b9b0e79a27a3883864bfebded8a3dc768cd" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "derive_builder" version = "0.11.2" @@ -2326,6 +2337,7 @@ dependencies = [ "sp-std", "sp-tracing", "sp-weights", + "static_assertions", "tt-call", ] @@ -2335,6 +2347,7 @@ version = "4.0.0-dev" dependencies = [ "Inflector", "cfg-expr", + "derive-syn-parse", "frame-support-procedural-tools", "itertools", "proc-macro2", @@ -2366,6 +2379,7 @@ dependencies = [ name = "frame-support-test" version = "3.0.0" dependencies = [ + "frame-benchmarking", "frame-support", "frame-support-test-pallet", "frame-system", diff --git a/frame/balances/src/benchmarking.rs b/frame/balances/src/benchmarking.rs index 206adba0f044b..f85ff43b715fe 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2023 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,22 +20,25 @@ #![cfg(feature = "runtime-benchmarks")] use super::*; +use crate::Pallet as Balances; -use frame_benchmarking::{account, benchmarks_instance_pallet, whitelisted_caller}; +use frame_benchmarking::{account, impl_benchmark_test_suite, whitelisted_caller}; +use frame_support::benchmarking::*; use frame_system::RawOrigin; -use sp_runtime::traits::Bounded; - -use crate::Pallet as Balances; const SEED: u32 = 0; // existential deposit multiplier const ED_MULTIPLIER: u32 = 10; -benchmarks_instance_pallet! { +#[instance_benchmarks] +mod benchmarks { + use super::*; + // Benchmark `transfer` extrinsic with the worst possible conditions: // * Transfer will kill the sender account. // * Transfer will create the recipient account. - transfer { + #[benchmark] + fn transfer() { let existential_deposit = T::ExistentialDeposit::get(); let caller = whitelisted_caller(); @@ -47,53 +50,66 @@ benchmarks_instance_pallet! { // and reap this user. let recipient: T::AccountId = account("recipient", 0, SEED); 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 { + let transfer_amount = + existential_deposit.saturating_mul((ED_MULTIPLIER - 1).into()) + 1u32.into(); + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone()), recipient_lookup, transfer_amount); + assert_eq!(Balances::::free_balance(&caller), Zero::zero()); assert_eq!(Balances::::free_balance(&recipient), transfer_amount); } // Benchmark `transfer` with the best possible condition: // * Both accounts exist and will continue to exist. - #[extra] - transfer_best_case { + #[benchmark(extra)] + fn transfer_best_case() { let caller = whitelisted_caller(); let recipient: T::AccountId = account("recipient", 0, SEED); 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()); + // 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()); // Give the recipient account existential deposit (thus their account already exists). let existential_deposit = T::ExistentialDeposit::get(); - let _ = as Currency<_>>::make_free_balance_be(&recipient, existential_deposit); + let _ = + as Currency<_>>::make_free_balance_be(&recipient, existential_deposit); let transfer_amount = existential_deposit.saturating_mul(ED_MULTIPLIER.into()); - }: transfer(RawOrigin::Signed(caller.clone()), recipient_lookup, transfer_amount) - verify { + + #[extrinsic_call] + transfer(RawOrigin::Signed(caller.clone()), recipient_lookup, transfer_amount); + assert!(!Balances::::free_balance(&caller).is_zero()); assert!(!Balances::::free_balance(&recipient).is_zero()); } // Benchmark `transfer_keep_alive` with the worst possible condition: // * The recipient account is created. - transfer_keep_alive { + #[benchmark] + fn transfer_keep_alive() { let caller = whitelisted_caller(); let recipient: T::AccountId = account("recipient", 0, SEED); 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()); + let _ = + as Currency<_>>::make_free_balance_be(&caller, T::Balance::max_value()); let existential_deposit = T::ExistentialDeposit::get(); let transfer_amount = existential_deposit.saturating_mul(ED_MULTIPLIER.into()); - }: _(RawOrigin::Signed(caller.clone()), recipient_lookup, transfer_amount) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone()), recipient_lookup, transfer_amount); + assert!(!Balances::::free_balance(&caller).is_zero()); assert_eq!(Balances::::free_balance(&recipient), transfer_amount); } // Benchmark `set_balance` coming from ROOT account. This always creates an account. - set_balance_creating { + #[benchmark] + fn set_balance_creating() { let user: T::AccountId = account("user", 0, SEED); let user_lookup = T::Lookup::unlookup(user.clone()); @@ -101,14 +117,17 @@ benchmarks_instance_pallet! { let existential_deposit = T::ExistentialDeposit::get(); let balance_amount = existential_deposit.saturating_mul(ED_MULTIPLIER.into()); let _ = as Currency<_>>::make_free_balance_be(&user, balance_amount); - }: set_balance(RawOrigin::Root, user_lookup, balance_amount, balance_amount) - verify { + + #[extrinsic_call] + set_balance(RawOrigin::Root, user_lookup, balance_amount, balance_amount); + assert_eq!(Balances::::free_balance(&user), balance_amount); assert_eq!(Balances::::reserved_balance(&user), balance_amount); } // Benchmark `set_balance` coming from ROOT account. This always kills an account. - set_balance_killing { + #[benchmark] + fn set_balance_killing() { let user: T::AccountId = account("user", 0, SEED); let user_lookup = T::Lookup::unlookup(user.clone()); @@ -116,15 +135,18 @@ benchmarks_instance_pallet! { let existential_deposit = T::ExistentialDeposit::get(); let balance_amount = existential_deposit.saturating_mul(ED_MULTIPLIER.into()); let _ = as Currency<_>>::make_free_balance_be(&user, balance_amount); - }: set_balance(RawOrigin::Root, user_lookup, Zero::zero(), Zero::zero()) - verify { + + #[extrinsic_call] + set_balance(RawOrigin::Root, user_lookup, Zero::zero(), Zero::zero()); + assert!(Balances::::free_balance(&user).is_zero()); } // Benchmark `force_transfer` extrinsic with the worst possible conditions: // * Transfer will kill the sender account. // * Transfer will create the recipient account. - force_transfer { + #[benchmark] + fn force_transfer() { let existential_deposit = T::ExistentialDeposit::get(); let source: T::AccountId = account("source", 0, SEED); let source_lookup = T::Lookup::unlookup(source.clone()); @@ -133,12 +155,16 @@ benchmarks_instance_pallet! { let balance = existential_deposit.saturating_mul(ED_MULTIPLIER.into()); let _ = as Currency<_>>::make_free_balance_be(&source, balance); - // Transfer `e - 1` existential deposits + 1 unit, which guarantees to create one account, and reap this user. + // 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 = 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 { + let transfer_amount = + existential_deposit.saturating_mul((ED_MULTIPLIER - 1).into()) + 1u32.into(); + + #[extrinsic_call] + _(RawOrigin::Root, source_lookup, recipient_lookup, transfer_amount); + assert_eq!(Balances::::free_balance(&source), Zero::zero()); assert_eq!(Balances::::free_balance(&recipient), transfer_amount); } @@ -146,10 +172,9 @@ benchmarks_instance_pallet! { // This benchmark performs the same operation as `transfer` in the worst case scenario, // but additionally introduces many new users into the storage, increasing the the merkle // trie and PoV size. - #[extra] - transfer_increasing_users { + #[benchmark(extra)] + fn transfer_increasing_users(u: Linear<0, 1_000>) { // 1_000 is not very much, but this upper bound can be controlled by the CLI. - let u in 0 .. 1_000; let existential_deposit = T::ExistentialDeposit::get(); let caller = whitelisted_caller(); @@ -161,17 +186,20 @@ benchmarks_instance_pallet! { // and reap this user. let recipient: T::AccountId = account("recipient", 0, SEED); let recipient_lookup = T::Lookup::unlookup(recipient.clone()); - let transfer_amount = existential_deposit.saturating_mul((ED_MULTIPLIER - 1).into()) + 1u32.into(); + let transfer_amount = + existential_deposit.saturating_mul((ED_MULTIPLIER - 1).into()) + 1u32.into(); // Create a bunch of users in storage. - for i in 0 .. u { + for i in 0..u { // The `account` function uses `blake2_256` to generate unique accounts, so these // should be quite random and evenly distributed in the trie. let new_user: T::AccountId = account("new_user", i, SEED); let _ = as Currency<_>>::make_free_balance_be(&new_user, balance); } - }: transfer(RawOrigin::Signed(caller.clone()), recipient_lookup, transfer_amount) - verify { + + #[extrinsic_call] + transfer(RawOrigin::Signed(caller.clone()), recipient_lookup, transfer_amount); + assert_eq!(Balances::::free_balance(&caller), Zero::zero()); assert_eq!(Balances::::free_balance(&recipient), transfer_amount); } @@ -179,7 +207,8 @@ benchmarks_instance_pallet! { // Benchmark `transfer_all` with the worst possible condition: // * The recipient account is created // * The sender is killed - transfer_all { + #[benchmark] + fn transfer_all() { let caller = whitelisted_caller(); let recipient: T::AccountId = account("recipient", 0, SEED); let recipient_lookup = T::Lookup::unlookup(recipient.clone()); @@ -188,13 +217,16 @@ benchmarks_instance_pallet! { let existential_deposit = T::ExistentialDeposit::get(); let balance = existential_deposit.saturating_mul(ED_MULTIPLIER.into()); let _ = as Currency<_>>::make_free_balance_be(&caller, balance); - }: _(RawOrigin::Signed(caller.clone()), recipient_lookup, false) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone()), recipient_lookup, false); + assert!(Balances::::free_balance(&caller).is_zero()); assert_eq!(Balances::::free_balance(&recipient), balance); } - force_unreserve { + #[benchmark] + fn force_unreserve() { let user: T::AccountId = account("user", 0, SEED); let user_lookup = T::Lookup::unlookup(user.clone()); @@ -208,15 +240,16 @@ benchmarks_instance_pallet! { assert_eq!(Balances::::reserved_balance(&user), balance); assert!(Balances::::free_balance(&user).is_zero()); - }: _(RawOrigin::Root, user_lookup, balance) - verify { + #[extrinsic_call] + _(RawOrigin::Root, user_lookup, balance); + assert!(Balances::::reserved_balance(&user).is_zero()); assert_eq!(Balances::::free_balance(&user), balance); } - impl_benchmark_test_suite!( + impl_benchmark_test_suite! { Balances, crate::tests_composite::ExtBuilder::default().build(), crate::tests_composite::Test, - ) + } } diff --git a/frame/examples/basic/src/benchmarking.rs b/frame/examples/basic/src/benchmarking.rs index 13f069c23e27b..699e56685fbe9 100644 --- a/frame/examples/basic/src/benchmarking.rs +++ b/frame/examples/basic/src/benchmarking.rs @@ -15,12 +15,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Benchmarking for pallet-example-basic. +//! Benchmarking for `pallet-example-basic`. +// Only enable this module for benchmarking. #![cfg(feature = "runtime-benchmarks")] use crate::*; -use frame_benchmarking::{benchmarks, whitelisted_caller}; +use frame_benchmarking::{impl_benchmark_test_suite, whitelisted_caller}; +use frame_support::benchmarking::{benchmarks, Linear}; use frame_system::RawOrigin; // To actually run this benchmark on pallet-example-basic, we need to put this pallet into the @@ -33,14 +35,19 @@ 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! { +#[benchmarks] +mod benchmarks { + use super::*; + // This will measure the execution time of `set_dummy`. - set_dummy_benchmark { + #[benchmark] + fn set_dummy_benchmark() { // 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 { + #[extrinsic_call] + set_dummy(RawOrigin::Root, value); // The execution phase is just running `set_dummy` extrinsic call + // This is the optional benchmark verification phase, asserting certain states. assert_eq!(Pallet::::dummy(), Some(value)) } @@ -49,22 +56,43 @@ benchmarks! { // 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 { + #[benchmark] + fn accumulate_dummy() { 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), value) + + // You can use `_` if the name of the Call matches the benchmark name. + #[extrinsic_call] + _(RawOrigin::Signed(caller), value); + } + + /// You can write helper functions in here since its a normal Rust module. + fn setup_vector(len: u32) -> Vec { + let mut vector = Vec::::new(); + for i in (0..len).rev() { + vector.push(i); + } + vector + } // This will measure the execution time of sorting a vector. - sort_vector { - let x in 0 .. 10000; - let mut m = Vec::::new(); - for i in (0..x).rev() { - m.push(i); + // + // Define `x` as a linear component with range `[0, =10_000]`. This means that the benchmarking + // will assume that the weight grows at a linear rate depending on `x`. + #[benchmark] + fn sort_vector(x: Linear<0, 10_000>) { + let mut vector = setup_vector(x); + + // The benchmark execution phase could also be a closure with custom code: + #[block] + { + vector.sort(); } - }: { - // The benchmark execution phase could also be a closure with custom code - m.sort(); + + // Check that it was sorted correctly. This will not be benchmarked and is just for + // verification. + vector.windows(2).for_each(|w| assert!(w[0] <= w[1])); } // This line generates test cases for benchmarking, and could be run by: @@ -75,5 +103,5 @@ benchmarks! { // // 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) + impl_benchmark_test_suite!(Pallet, crate::tests::new_test_ext(), crate::tests::Test); } diff --git a/frame/message-queue/src/benchmarking.rs b/frame/message-queue/src/benchmarking.rs index 9cd6b75e4d0ae..9651c81e5e66d 100644 --- a/frame/message-queue/src/benchmarking.rs +++ b/frame/message-queue/src/benchmarking.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2023 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,68 +22,85 @@ use super::{mock_helpers::*, Pallet as MessageQueue, *}; -use frame_benchmarking::{benchmarks, whitelisted_caller}; -use frame_support::traits::Get; +use frame_benchmarking::{impl_benchmark_test_suite, whitelisted_caller}; +use frame_support::{benchmarking::*, 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, - } +#[benchmarks( + where + <::MessageProcessor as ProcessMessage>::Origin: From + PartialEq, + ::Size: From, + // 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. +)] +mod benchmarks { + use super::*; // Worst case path of `ready_ring_knit`. - ready_ring_knit { - let mid: MessageOriginOf:: = 1.into(); + #[benchmark] + fn 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 { + + #[block] + { + neighbours = MessageQueue::::ready_ring_knit(&mid).ok(); + } + // The neighbours needs to be modified manually. - BookStateFor::::mutate(&mid, |b| { b.ready_neighbours = neighbours }); + 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 { + #[benchmark] + fn 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 o: MessageOriginOf = 0.into(); let neighbours = BookStateFor::::get(&o).ready_neighbours.unwrap(); - }: { - MessageQueue::::ready_ring_unknit(&o, neighbours); - } verify { + + #[block] + { + MessageQueue::::ready_ring_unknit(&o, neighbours); + } + 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) + #[benchmark] + fn service_queue_base() { + #[block] + { + 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 { + #[benchmark] + fn 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) + + #[block] + { + 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 { + #[benchmark] + fn 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`. @@ -93,49 +110,73 @@ benchmarks! { 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) + + #[block] + { + MessageQueue::::service_page(&origin, &mut book_state, &mut meter, limit); + } } // Processing a single message from a page. - service_page_item { + #[benchmark] + fn 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 { + + #[block] + { + let status = MessageQueue::::service_page_item( + &0u32.into(), + 0, + &mut book, + &mut page, + &mut weight, + Weight::MAX, + ); + assert_eq!(status, ItemExecutionStatus::Executed(true)); + } + // 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()); + 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 { + #[benchmark] + fn bump_service_head() { setup_bump_service_head::(0.into(), 10.into()); let mut weight = WeightMeter::max_limit(); - }: { - MessageQueue::::bump_service_head(&mut weight); - } verify { + + #[block] + { + MessageQueue::::bump_service_head(&mut weight); + } + assert_eq!(ServiceHead::::get().unwrap(), 10u32.into()); assert_eq!(weight.consumed, T::WeightInfo::bump_service_head()); } - reap_page { + #[benchmark] + fn 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() { + for p in 0..T::MaxStale::get() * T::MaxStale::get() { if p == 0 { Pages::::insert(&origin, p, &page); } @@ -148,16 +189,19 @@ benchmarks! { 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()); + #[extrinsic_call] + _(RawOrigin::Signed(whitelisted_caller()), 0u32.into(), 0); + + 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 { + // 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. + #[benchmark] + fn execute_overweight_page_removed() { let origin: MessageOriginOf = 0.into(); let (mut page, msgs) = full_page::(); // Skip all messages. @@ -168,19 +212,34 @@ benchmarks! { 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()); + + #[block] + { + MessageQueue::::execute_overweight( + RawOrigin::Signed(whitelisted_caller()).into(), + 0u32.into(), + 0u32, + ((msgs - 1) as u32).into(), + Weight::MAX, + ) + .unwrap(); + } + + 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 { + #[benchmark] + fn execute_overweight_page_updated() { let origin: MessageOriginOf = 0.into(); let (mut page, msgs) = full_page::(); // Skip all messages. @@ -190,16 +249,34 @@ benchmarks! { 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()); + + #[block] + { + MessageQueue::::execute_overweight( + RawOrigin::Signed(whitelisted_caller()).into(), + 0u32.into(), + 0u32, + ((msgs - 1) as u32).into(), + Weight::MAX, + ) + .unwrap(); + } + + 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); + impl_benchmark_test_suite! { + MessageQueue, + crate::mock::new_test_ext::(), + crate::integration_test::Test + } } diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index 4f62ae42ef78f..ae2fc358974b6 100644 --- a/frame/support/Cargo.toml +++ b/frame/support/Cargo.toml @@ -27,6 +27,7 @@ sp-arithmetic = { version = "6.0.0", default-features = false, path = "../../pri 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" } +static_assertions = "1.1.0" tt-call = "1.0.8" frame-support-procedural = { version = "4.0.0-dev", default-features = false, path = "./procedural" } paste = "1.0" diff --git a/frame/support/procedural/Cargo.toml b/frame/support/procedural/Cargo.toml index 06b8056aff982..ee1ca4dff8873 100644 --- a/frame/support/procedural/Cargo.toml +++ b/frame/support/procedural/Cargo.toml @@ -15,6 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] proc-macro = true [dependencies] +derive-syn-parse = "0.1.5" Inflector = "0.11.4" cfg-expr = "0.10.3" itertools = "0.10.3" diff --git a/frame/support/procedural/src/benchmark.rs b/frame/support/procedural/src/benchmark.rs new file mode 100644 index 0000000000000..43e3e47de5259 --- /dev/null +++ b/frame/support/procedural/src/benchmark.rs @@ -0,0 +1,860 @@ +// This file is part of Substrate. + +// Copyright (C) 2023 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Home of the parsing and expansion code for the new pallet benchmarking syntax + +use derive_syn_parse::Parse; +use frame_support_procedural_tools::generate_crate_access_2018; +use proc_macro::TokenStream; +use proc_macro2::{Ident, Span, TokenStream as TokenStream2}; +use quote::{quote, quote_spanned, ToTokens}; +use syn::{ + parenthesized, + parse::{Nothing, ParseStream}, + punctuated::Punctuated, + spanned::Spanned, + token::{Colon2, Comma, Gt, Lt, Paren}, + Attribute, Error, Expr, ExprBlock, ExprCall, ExprPath, FnArg, Item, ItemFn, ItemMod, LitInt, + Pat, Path, PathArguments, PathSegment, Result, Stmt, Token, Type, WhereClause, +}; + +mod keywords { + use syn::custom_keyword; + + custom_keyword!(benchmark); + custom_keyword!(benchmarks); + custom_keyword!(block); + custom_keyword!(extra); + custom_keyword!(extrinsic_call); + custom_keyword!(skip_meta); +} + +/// This represents the raw parsed data for a param definition such as `x: Linear<10, 20>`. +#[derive(Clone)] +struct ParamDef { + name: String, + typ: Type, + start: u32, + end: u32, +} + +/// Allows easy parsing of the `<10, 20>` component of `x: Linear<10, 20>`. +#[derive(Parse)] +struct RangeArgs { + _lt_token: Lt, + start: LitInt, + _comma: Comma, + end: LitInt, + _gt_token: Gt, +} + +#[derive(Clone, Debug)] +struct BenchmarkAttrs { + skip_meta: bool, + extra: bool, +} + +/// Represents a single benchmark option +enum BenchmarkAttrKeyword { + Extra, + SkipMeta, +} + +impl syn::parse::Parse for BenchmarkAttrKeyword { + fn parse(input: ParseStream) -> Result { + let lookahead = input.lookahead1(); + if lookahead.peek(keywords::extra) { + let _extra: keywords::extra = input.parse()?; + return Ok(BenchmarkAttrKeyword::Extra) + } else if lookahead.peek(keywords::skip_meta) { + let _skip_meta: keywords::skip_meta = input.parse()?; + return Ok(BenchmarkAttrKeyword::SkipMeta) + } else { + return Err(lookahead.error()) + } + } +} + +impl syn::parse::Parse for BenchmarkAttrs { + fn parse(input: ParseStream) -> syn::Result { + let lookahead = input.lookahead1(); + if !lookahead.peek(Paren) { + let _nothing: Nothing = input.parse()?; + return Ok(BenchmarkAttrs { skip_meta: false, extra: false }) + } + let content; + let _paren: Paren = parenthesized!(content in input); + let mut extra = false; + let mut skip_meta = false; + let args = Punctuated::::parse_terminated(&content)?; + for arg in args.into_iter() { + match arg { + BenchmarkAttrKeyword::Extra => { + if extra { + return Err(content.error("`extra` can only be specified once")) + } + extra = true; + }, + BenchmarkAttrKeyword::SkipMeta => { + if skip_meta { + return Err(content.error("`skip_meta` can only be specified once")) + } + skip_meta = true; + }, + } + } + Ok(BenchmarkAttrs { extra, skip_meta }) + } +} + +/// Represents the parsed extrinsic call for a benchmark +#[derive(Clone)] +enum BenchmarkCallDef { + ExtrinsicCall { origin: Expr, expr_call: ExprCall, attr_span: Span }, // #[extrinsic_call] + Block { block: ExprBlock, attr_span: Span }, // #[block] +} + +impl BenchmarkCallDef { + /// Returns the `span()` for attribute + fn attr_span(&self) -> Span { + match self { + BenchmarkCallDef::ExtrinsicCall { origin: _, expr_call: _, attr_span } => *attr_span, + BenchmarkCallDef::Block { block: _, attr_span } => *attr_span, + } + } +} + +/// Represents a parsed `#[benchmark]` or `#[instance_banchmark]` item. +#[derive(Clone)] +struct BenchmarkDef { + params: Vec, + setup_stmts: Vec, + call_def: BenchmarkCallDef, + verify_stmts: Vec, + extra: bool, + skip_meta: bool, +} + +impl BenchmarkDef { + /// Constructs a [`BenchmarkDef`] by traversing an existing [`ItemFn`] node. + pub fn from(item_fn: &ItemFn, extra: bool, skip_meta: bool) -> Result { + let mut params: Vec = Vec::new(); + + // parse params such as "x: Linear<0, 1>" + for arg in &item_fn.sig.inputs { + let invalid_param = |span| { + return Err(Error::new(span, "Invalid benchmark function param. A valid example would be `x: Linear<5, 10>`.", )) + }; + + let FnArg::Typed(arg) = arg else { return invalid_param(arg.span()) }; + let Pat::Ident(ident) = &*arg.pat else { return invalid_param(arg.span()) }; + + // check param name + let var_span = ident.span(); + let invalid_param_name = || { + return Err(Error::new( + var_span, + "Benchmark parameter names must consist of a single lowercase letter (a-z) and no other characters.", + )) + }; + let name = ident.ident.to_token_stream().to_string(); + if name.len() > 1 { + return invalid_param_name() + }; + let Some(name_char) = name.chars().next() else { return invalid_param_name() }; + if !name_char.is_alphabetic() || !name_char.is_lowercase() { + return invalid_param_name() + } + + // parse type + let typ = &*arg.ty; + let Type::Path(tpath) = typ else { return invalid_param(typ.span()) }; + let Some(segment) = tpath.path.segments.last() else { return invalid_param(typ.span()) }; + let args = segment.arguments.to_token_stream().into(); + let Ok(args) = syn::parse::(args) else { return invalid_param(typ.span()) }; + let Ok(start) = args.start.base10_parse::() else { return invalid_param(args.start.span()) }; + let Ok(end) = args.end.base10_parse::() else { return invalid_param(args.end.span()) }; + + if end < start { + return Err(Error::new( + args.start.span(), + "The start of a `ParamRange` must be less than or equal to the end", + )) + } + + params.push(ParamDef { name, typ: typ.clone(), start, end }); + } + + // #[extrinsic_call] / #[block] handling + let call_defs = item_fn.block.stmts.iter().enumerate().filter_map(|(i, child)| { + if let Stmt::Semi(Expr::Call(expr_call), _semi) = child { + // #[extrinsic_call] case + expr_call.attrs.iter().enumerate().find_map(|(k, attr)| { + let segment = attr.path.segments.last()?; + let _: keywords::extrinsic_call = syn::parse(segment.ident.to_token_stream().into()).ok()?; + let mut expr_call = expr_call.clone(); + + // consume #[extrinsic_call] tokens + expr_call.attrs.remove(k); + + // extract origin from expr_call + let Some(origin) = expr_call.args.first().cloned() else { + return Some(Err(Error::new(expr_call.span(), "Single-item extrinsic calls must specify their origin as the first argument."))) + }; + + Some(Ok((i, BenchmarkCallDef::ExtrinsicCall { origin, expr_call, attr_span: attr.span() }))) + }) + } else if let Stmt::Expr(Expr::Block(block)) = child { + // #[block] case + block.attrs.iter().enumerate().find_map(|(k, attr)| { + let segment = attr.path.segments.last()?; + let _: keywords::block = syn::parse(segment.ident.to_token_stream().into()).ok()?; + let mut block = block.clone(); + + // consume #[block] tokens + block.attrs.remove(k); + + Some(Ok((i, BenchmarkCallDef::Block { block, attr_span: attr.span() }))) + }) + } else { + None + } + }).collect::>>()?; + let (i, call_def) = match &call_defs[..] { + [(i, call_def)] => (*i, call_def.clone()), // = 1 + [] => return Err(Error::new( // = 0 + item_fn.block.brace_token.span, + "No valid #[extrinsic_call] or #[block] annotation could be found in benchmark function body." + )), + _ => return Err(Error::new( // > 1 + call_defs[1].1.attr_span(), + "Only one #[extrinsic_call] or #[block] attribute is allowed per benchmark." + )), + }; + + Ok(BenchmarkDef { + params, + setup_stmts: Vec::from(&item_fn.block.stmts[0..i]), + call_def, + verify_stmts: Vec::from(&item_fn.block.stmts[(i + 1)..item_fn.block.stmts.len()]), + extra, + skip_meta, + }) + } +} + +/// Parses and expands a `#[benchmarks]` or `#[instance_benchmarks]` invocation +pub fn benchmarks( + attrs: TokenStream, + tokens: TokenStream, + instance: bool, +) -> syn::Result { + // gather module info + let module: ItemMod = syn::parse(tokens)?; + let mod_span = module.span(); + let where_clause = match syn::parse::(attrs.clone()) { + Ok(_) => quote!(), + Err(_) => syn::parse::(attrs)?.predicates.to_token_stream(), + }; + let mod_vis = module.vis; + let mod_name = module.ident; + + // consume #[benchmarks] attribute by exclusing it from mod_attrs + let mod_attrs: Vec<&Attribute> = module + .attrs + .iter() + .filter(|attr| syn::parse2::(attr.to_token_stream()).is_err()) + .collect(); + + let mut benchmark_names: Vec = Vec::new(); + let mut extra_benchmark_names: Vec = Vec::new(); + let mut skip_meta_benchmark_names: Vec = Vec::new(); + + let (_brace, mut content) = + module.content.ok_or(syn::Error::new(mod_span, "Module cannot be empty!"))?; + + // find all function defs marked with #[benchmark] + let benchmark_fn_metas = content.iter_mut().filter_map(|stmt| { + // parse as a function def first + let Item::Fn(func) = stmt else { return None }; + + // find #[benchmark] attribute on function def + let benchmark_attr = func.attrs.iter().find_map(|attr| { + let seg = attr.path.segments.last()?; + syn::parse::(seg.ident.to_token_stream().into()).ok()?; + Some(attr) + })?; + + Some((benchmark_attr.clone(), func.clone(), stmt)) + }); + + // parse individual benchmark defs and args + for (benchmark_attr, func, stmt) in benchmark_fn_metas { + // parse any args provided to #[benchmark] + let attr_tokens = benchmark_attr.tokens.to_token_stream().into(); + let benchmark_args: BenchmarkAttrs = syn::parse(attr_tokens)?; + + // parse benchmark def + let benchmark_def = + BenchmarkDef::from(&func, benchmark_args.extra, benchmark_args.skip_meta)?; + + // record benchmark name + let name = &func.sig.ident; + benchmark_names.push(name.clone()); + + // record name sets + if benchmark_def.extra { + extra_benchmark_names.push(name.clone()); + } + if benchmark_def.skip_meta { + skip_meta_benchmark_names.push(name.clone()) + } + + // expand benchmark + let expanded = expand_benchmark(benchmark_def, name, instance, where_clause.clone()); + + // replace original function def with expanded code + *stmt = Item::Verbatim(expanded); + } + + // generics + let type_use_generics = match instance { + false => quote!(T), + true => quote!(T, I), + }; + let type_impl_generics = match instance { + false => quote!(T: Config), + true => quote!(T: Config, I: 'static), + }; + + let krate = generate_crate_access_2018("frame-benchmarking")?; + let support = quote!(#krate::frame_support); + + // benchmark name variables + let benchmark_names_str: Vec = benchmark_names.iter().map(|n| n.to_string()).collect(); + let extra_benchmark_names_str: Vec = + extra_benchmark_names.iter().map(|n| n.to_string()).collect(); + let skip_meta_benchmark_names_str: Vec = + skip_meta_benchmark_names.iter().map(|n| n.to_string()).collect(); + let mut selected_benchmark_mappings: Vec = Vec::new(); + let mut benchmarks_by_name_mappings: Vec = Vec::new(); + let test_idents: Vec = benchmark_names_str + .iter() + .map(|n| Ident::new(format!("test_{}", n).as_str(), Span::call_site())) + .collect(); + for i in 0..benchmark_names.len() { + let name_ident = &benchmark_names[i]; + let name_str = &benchmark_names_str[i]; + let test_ident = &test_idents[i]; + selected_benchmark_mappings.push(quote!(#name_str => SelectedBenchmark::#name_ident)); + benchmarks_by_name_mappings.push(quote!(#name_str => Self::#test_ident())) + } + + // emit final quoted tokens + let res = quote! { + #(#mod_attrs) + * + #mod_vis mod #mod_name { + #(#content) + * + + #[allow(non_camel_case_types)] + enum SelectedBenchmark { + #(#benchmark_names), + * + } + + impl<#type_impl_generics> #krate::BenchmarkingSetup<#type_use_generics> for SelectedBenchmark where #where_clause { + fn components(&self) -> #krate::Vec<(#krate::BenchmarkParameter, u32, u32)> { + match self { + #( + Self::#benchmark_names => { + <#benchmark_names as #krate::BenchmarkingSetup<#type_use_generics>>::components(&#benchmark_names) + } + ) + * + } + } + + fn instance( + &self, + components: &[(#krate::BenchmarkParameter, u32)], + verify: bool, + ) -> Result< + #krate::Box Result<(), #krate::BenchmarkError>>, + #krate::BenchmarkError, + > { + match self { + #( + Self::#benchmark_names => { + <#benchmark_names as #krate::BenchmarkingSetup< + #type_use_generics + >>::instance(&#benchmark_names, components, verify) + } + ) + * + } + } + } + #[cfg(any(feature = "runtime-benchmarks", test))] + impl<#type_impl_generics> #krate::Benchmarking for Pallet<#type_use_generics> + where T: frame_system::Config, #where_clause + { + fn benchmarks( + extra: bool, + ) -> #krate::Vec<#krate::BenchmarkMetadata> { + let mut all_names = #krate::vec![ + #(#benchmark_names_str), + * + ]; + if !extra { + let extra = [ + #(#extra_benchmark_names_str), + * + ]; + all_names.retain(|x| !extra.contains(x)); + } + all_names.into_iter().map(|benchmark| { + let selected_benchmark = match benchmark { + #(#selected_benchmark_mappings), + *, + _ => panic!("all benchmarks should be selectable") + }; + let components = >::components(&selected_benchmark); + #krate::BenchmarkMetadata { + name: benchmark.as_bytes().to_vec(), + components, + } + }).collect::<#krate::Vec<_>>() + } + + fn run_benchmark( + extrinsic: &[u8], + c: &[(#krate::BenchmarkParameter, u32)], + whitelist: &[#krate::TrackedStorageKey], + verify: bool, + internal_repeats: u32, + ) -> Result<#krate::Vec<#krate::BenchmarkResult>, #krate::BenchmarkError> { + let extrinsic = #krate::str::from_utf8(extrinsic).map_err(|_| "`extrinsic` is not a valid utf-8 string!")?; + let selected_benchmark = match extrinsic { + #(#selected_benchmark_mappings), + *, + _ => return Err("Could not find extrinsic.".into()), + }; + let mut whitelist = whitelist.to_vec(); + let whitelisted_caller_key = as #support::storage::StorageMap<_, _,>>::hashed_key_for( + #krate::whitelisted_caller::() + ); + whitelist.push(whitelisted_caller_key.into()); + let transactional_layer_key = #krate::TrackedStorageKey::new( + #support::storage::transactional::TRANSACTION_LEVEL_KEY.into(), + ); + whitelist.push(transactional_layer_key); + #krate::benchmarking::set_whitelist(whitelist); + let mut results: #krate::Vec<#krate::BenchmarkResult> = #krate::Vec::new(); + + // Always do at least one internal repeat... + for _ in 0 .. internal_repeats.max(1) { + // Always reset the state after the benchmark. + #krate::defer!(#krate::benchmarking::wipe_db()); + + // Set up the externalities environment for the setup we want to + // benchmark. + let closure_to_benchmark = < + SelectedBenchmark as #krate::BenchmarkingSetup<#type_use_generics> + >::instance(&selected_benchmark, c, verify)?; + + // Set the block number to at least 1 so events are deposited. + if #krate::Zero::is_zero(&frame_system::Pallet::::block_number()) { + frame_system::Pallet::::set_block_number(1u32.into()); + } + + // Commit the externalities to the database, flushing the DB cache. + // This will enable worst case scenario for reading from the database. + #krate::benchmarking::commit_db(); + + // Reset the read/write counter so we don't count operations in the setup process. + #krate::benchmarking::reset_read_write_count(); + + // Time the extrinsic logic. + #krate::log::trace!( + target: "benchmark", + "Start Benchmark: {} ({:?})", + extrinsic, + c + ); + + let start_pov = #krate::benchmarking::proof_size(); + let start_extrinsic = #krate::benchmarking::current_time(); + + closure_to_benchmark()?; + + let finish_extrinsic = #krate::benchmarking::current_time(); + let end_pov = #krate::benchmarking::proof_size(); + + // Calculate the diff caused by the benchmark. + let elapsed_extrinsic = finish_extrinsic.saturating_sub(start_extrinsic); + let diff_pov = match (start_pov, end_pov) { + (Some(start), Some(end)) => end.saturating_sub(start), + _ => Default::default(), + }; + + // Commit the changes to get proper write count + #krate::benchmarking::commit_db(); + #krate::log::trace!( + target: "benchmark", + "End Benchmark: {} ns", elapsed_extrinsic + ); + let read_write_count = #krate::benchmarking::read_write_count(); + #krate::log::trace!( + target: "benchmark", + "Read/Write Count {:?}", read_write_count + ); + + // Time the storage root recalculation. + let start_storage_root = #krate::benchmarking::current_time(); + #krate::storage_root(#krate::StateVersion::V1); + let finish_storage_root = #krate::benchmarking::current_time(); + let elapsed_storage_root = finish_storage_root - start_storage_root; + + let skip_meta = [ #(#skip_meta_benchmark_names_str),* ]; + let read_and_written_keys = if skip_meta.contains(&extrinsic) { + #krate::vec![(b"Skipped Metadata".to_vec(), 0, 0, false)] + } else { + #krate::benchmarking::get_read_and_written_keys() + }; + + results.push(#krate::BenchmarkResult { + components: c.to_vec(), + extrinsic_time: elapsed_extrinsic, + storage_root_time: elapsed_storage_root, + reads: read_write_count.0, + repeat_reads: read_write_count.1, + writes: read_write_count.2, + repeat_writes: read_write_count.3, + proof_size: diff_pov, + keys: read_and_written_keys, + }); + } + + return Ok(results); + } + } + + #[cfg(test)] + impl<#type_impl_generics> Pallet<#type_use_generics> where T: ::frame_system::Config, #where_clause { + /// Test a particular benchmark by name. + /// + /// This isn't called `test_benchmark_by_name` just in case some end-user eventually + /// writes a benchmark, itself called `by_name`; the function would be shadowed in + /// that case. + /// + /// This is generally intended to be used by child test modules such as those created + /// by the `impl_benchmark_test_suite` macro. However, it is not an error if a pallet + /// author chooses not to implement benchmarks. + #[allow(unused)] + fn test_bench_by_name(name: &[u8]) -> Result<(), #krate::BenchmarkError> { + let name = #krate::str::from_utf8(name) + .map_err(|_| -> #krate::BenchmarkError { "`name` is not a valid utf8 string!".into() })?; + match name { + #(#benchmarks_by_name_mappings), + *, + _ => Err("Could not find test for requested benchmark.".into()), + } + } + } + } + #mod_vis use #mod_name::*; + }; + Ok(res.into()) +} + +/// Prepares a [`Vec`] to be interpolated by [`quote!`] by creating easily-iterable +/// arrays formatted in such a way that they can be interpolated directly. +struct UnrolledParams { + param_ranges: Vec, + param_names: Vec, + param_types: Vec, +} + +impl UnrolledParams { + /// Constructs an [`UnrolledParams`] from a [`Vec`] + fn from(params: &Vec) -> UnrolledParams { + let param_ranges: Vec = params + .iter() + .map(|p| { + let name = Ident::new(&p.name, Span::call_site()); + let start = p.start; + let end = p.end; + quote!(#name, #start, #end) + }) + .collect(); + let param_names: Vec = params + .iter() + .map(|p| { + let name = Ident::new(&p.name, Span::call_site()); + quote!(#name) + }) + .collect(); + let param_types: Vec = params + .iter() + .map(|p| { + let typ = &p.typ; + quote!(#typ) + }) + .collect(); + UnrolledParams { param_ranges, param_names, param_types } + } +} + +/// Performs expansion of an already-parsed [`BenchmarkDef`]. +fn expand_benchmark( + benchmark_def: BenchmarkDef, + name: &Ident, + is_instance: bool, + where_clause: TokenStream2, +) -> TokenStream2 { + // set up variables needed during quoting + let krate = match generate_crate_access_2018("frame-benchmarking") { + Ok(ident) => ident, + Err(err) => return err.to_compile_error().into(), + }; + let home = quote!(#krate::frame_support::benchmarking); + let codec = quote!(#krate::frame_support::codec); + let traits = quote!(#krate::frame_support::traits); + let setup_stmts = benchmark_def.setup_stmts; + let verify_stmts = benchmark_def.verify_stmts; + let test_ident = Ident::new(format!("test_{}", name.to_string()).as_str(), Span::call_site()); + + // unroll params (prepare for quoting) + let unrolled = UnrolledParams::from(&benchmark_def.params); + let param_names = unrolled.param_names; + let param_ranges = unrolled.param_ranges; + let param_types = unrolled.param_types; + + let type_use_generics = match is_instance { + false => quote!(T), + true => quote!(T, I), + }; + + let type_impl_generics = match is_instance { + false => quote!(T: Config), + true => quote!(T: Config, I: 'static), + }; + + let (pre_call, post_call) = match benchmark_def.call_def { + BenchmarkCallDef::ExtrinsicCall { origin, expr_call, attr_span: _ } => { + let mut expr_call = expr_call.clone(); + + // remove first arg from expr_call + let mut final_args = Punctuated::::new(); + let args: Vec<&Expr> = expr_call.args.iter().collect(); + for arg in &args[1..] { + final_args.push((*(*arg)).clone()); + } + expr_call.args = final_args; + + // determine call name (handles `_` and normal call syntax) + let expr_span = expr_call.span(); + let call_err = || { + quote_spanned!(expr_span=> "Extrinsic call must be a function call or `_`".to_compile_error()).into() + }; + let call_name = match *expr_call.func { + Expr::Path(expr_path) => { + // normal function call + let Some(segment) = expr_path.path.segments.last() else { return call_err(); }; + segment.ident.to_string() + }, + Expr::Verbatim(tokens) => { + // `_` style + // replace `_` with fn name + let Ok(_) = syn::parse::(tokens.to_token_stream().into()) else { return call_err(); }; + name.to_string() + }, + _ => return call_err(), + }; + + // modify extrinsic call to be prefixed with "new_call_variant" + let call_name = format!("new_call_variant_{}", call_name); + let mut punct: Punctuated = Punctuated::new(); + punct.push(PathSegment { + arguments: PathArguments::None, + ident: Ident::new(call_name.as_str(), Span::call_site()), + }); + *expr_call.func = Expr::Path(ExprPath { + attrs: vec![], + qself: None, + path: Path { leading_colon: None, segments: punct }, + }); + + ( + // (pre_call, post_call): + quote! { + let __call = Call::<#type_use_generics>::#expr_call; + let __benchmarked_call_encoded = #codec::Encode::encode(&__call); + }, + quote! { + let __call_decoded = as #codec::Decode> + ::decode(&mut &__benchmarked_call_encoded[..]) + .expect("call is encoded above, encoding must be correct"); + let __origin = #origin.into(); + as #traits::UnfilteredDispatchable>::dispatch_bypass_filter( + __call_decoded, + __origin, + )?; + }, + ) + }, + BenchmarkCallDef::Block { block, attr_span: _ } => (quote!(), quote!(#block)), + }; + + // generate final quoted tokens + let res = quote! { + // compile-time assertions that each referenced param type implements ParamRange + #( + #home::assert_impl_all!(#param_types: #home::ParamRange); + )* + + #[allow(non_camel_case_types)] + struct #name; + + #[allow(unused_variables)] + impl<#type_impl_generics> #krate::BenchmarkingSetup<#type_use_generics> + for #name where #where_clause { + fn components(&self) -> #krate::Vec<(#krate::BenchmarkParameter, u32, u32)> { + #krate::vec! [ + #( + (#krate::BenchmarkParameter::#param_ranges) + ),* + ] + } + + fn instance( + &self, + components: &[(#krate::BenchmarkParameter, u32)], + verify: bool + ) -> Result<#krate::Box Result<(), #krate::BenchmarkError>>, #krate::BenchmarkError> { + #( + // prepare instance #param_names + let #param_names = components.iter() + .find(|&c| c.0 == #krate::BenchmarkParameter::#param_names) + .ok_or("Could not find component during benchmark preparation.")? + .1; + )* + + // benchmark setup code + #( + #setup_stmts + )* + #pre_call + Ok(#krate::Box::new(move || -> Result<(), #krate::BenchmarkError> { + #post_call + if verify { + #( + #verify_stmts + )* + } + Ok(()) + })) + } + } + + #[cfg(test)] + impl<#type_impl_generics> Pallet<#type_use_generics> where T: ::frame_system::Config, #where_clause { + #[allow(unused)] + fn #test_ident() -> Result<(), #krate::BenchmarkError> { + let selected_benchmark = SelectedBenchmark::#name; + let components = < + SelectedBenchmark as #krate::BenchmarkingSetup + >::components(&selected_benchmark); + let execute_benchmark = | + c: #krate::Vec<(#krate::BenchmarkParameter, u32)> + | -> Result<(), #krate::BenchmarkError> { + // Always reset the state after the benchmark. + #krate::defer!(#krate::benchmarking::wipe_db()); + + // Set up the benchmark, return execution + verification function. + let closure_to_verify = < + SelectedBenchmark as #krate::BenchmarkingSetup + >::instance(&selected_benchmark, &c, true)?; + + // Set the block number to at least 1 so events are deposited. + if #krate::Zero::is_zero(&frame_system::Pallet::::block_number()) { + frame_system::Pallet::::set_block_number(1u32.into()); + } + + // Run execution + verification + closure_to_verify() + }; + + if components.is_empty() { + execute_benchmark(Default::default())?; + } else { + let num_values: u32 = if let Ok(ev) = std::env::var("VALUES_PER_COMPONENT") { + ev.parse().map_err(|_| { + #krate::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 = #krate::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: #krate::Vec<(#krate::BenchmarkParameter, u32)> = components + .iter() + .map(|(n, _, h)| + if *n == name { + (*n, component_value) + } else { + (*n, *h) + } + ) + .collect(); + + execute_benchmark(c)?; + } + } + } + return Ok(()); + } + } + }; + res +} diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index 41dbc4ee9592c..9bdbbd1f27bb2 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -19,6 +19,7 @@ #![recursion_limit = "512"] +mod benchmark; mod clone_no_bound; mod construct_runtime; mod crate_version; @@ -479,6 +480,69 @@ pub fn pallet(attr: TokenStream, item: TokenStream) -> TokenStream { pallet::pallet(attr, item) } +/// An attribute macro that can be attached to a (non-empty) module declaration. Doing so will +/// designate that module as a benchmarking module. +/// +/// See `frame_support::benchmarking` for more info. +#[proc_macro_attribute] +pub fn benchmarks(attr: TokenStream, tokens: TokenStream) -> TokenStream { + match benchmark::benchmarks(attr, tokens, false) { + Ok(tokens) => tokens, + Err(err) => err.to_compile_error().into(), + } +} + +/// An attribute macro that can be attached to a (non-empty) module declaration. Doing so will +/// designate that module as an instance benchmarking module. +/// +/// See `frame_support::benchmarking` for more info. +#[proc_macro_attribute] +pub fn instance_benchmarks(attr: TokenStream, tokens: TokenStream) -> TokenStream { + match benchmark::benchmarks(attr, tokens, true) { + Ok(tokens) => tokens, + Err(err) => err.to_compile_error().into(), + } +} + +/// An attribute macro used to declare a benchmark within a benchmarking module. Must be +/// attached to a function definition containing an `#[extrinsic_call]` or `#[block]` +/// attribute. +/// +/// See `frame_support::benchmarking` for more info. +#[proc_macro_attribute] +pub fn benchmark(_attrs: TokenStream, _tokens: TokenStream) -> TokenStream { + quote!(compile_error!( + "`#[benchmark]` must be in a module labeled with #[benchmarks] or #[instance_benchmarks]." + )) + .into() +} + +/// An attribute macro used to specify the extrinsic call inside a benchmark function, and also +/// used as a boundary designating where the benchmark setup code ends, and the benchmark +/// verification code begins. +/// +/// See `frame_support::benchmarking` for more info. +#[proc_macro_attribute] +pub fn extrinsic_call(_attrs: TokenStream, _tokens: TokenStream) -> TokenStream { + quote!(compile_error!( + "`#[extrinsic_call]` must be in a benchmark function definition labeled with `#[benchmark]`." + );) + .into() +} + +/// An attribute macro used to specify that a block should be the measured portion of the +/// enclosing benchmark function, This attribute is also used as a boundary designating where +/// the benchmark setup code ends, and the benchmark verification code begins. +/// +/// See `frame_support::benchmarking` for more info. +#[proc_macro_attribute] +pub fn block(_attrs: TokenStream, _tokens: TokenStream) -> TokenStream { + quote!(compile_error!( + "`#[block]` must be in a benchmark function definition labeled with `#[benchmark]`." + )) + .into() +} + /// Execute the annotated function in a new storage transaction. /// /// The return type of the annotated function must be `Result`. All changes to storage performed diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 902893972f0b1..40bc878cff365 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -2745,5 +2745,228 @@ pub mod pallet_macros { }; } +/// Contains macros, structs, and traits associated with v2 of the pallet benchmarking syntax. +/// This module contains macros, structs, and traits associated with v2 of the pallet +/// benchmarking syntax. +/// +/// The [`benchmarking::benchmarks`] and [`benchmarking::instance_benchmarks`] macros can be +/// used to designate a module as a benchmarking module that can contain benchmarks and +/// benchmark tests. The `#[benchmarks]` variant will set up a regular, non-instance +/// benchmarking module, and the `#[instance_benchmarks]` variant will set up the module in +/// instance benchmarking mode. +/// +/// Benchmarking modules should be gated behind a `#[cfg(feature = "runtime-benchmarks")]` +/// feature gate to ensure benchmarking code that is only compiled when the +/// `runtime-benchmarks` feature is enabled is not referenced. +/// +/// The following is the general syntax for a benchmarks (or instance benchmarks) module: +/// +/// ## General Syntax +/// +/// ```ignore +/// #![cfg(feature = "runtime-benchmarks")] +/// +/// use super::{mock_helpers::*, Pallet as MyPallet}; +/// use frame_support::benchmarking::*; +/// use frame_benchmarking::whitelisted_caller; +/// +/// #[benchmarks] +/// mod benchmarks { +/// use super::*; +/// +/// #[benchmark] +/// fn bench_name_1(x: Linear<7, 1_000>, y: Linear<1_000, 100_0000>) { +/// // setup code +/// let z = x + y; +/// let caller = whitelisted_caller(); +/// +/// #[extrinsic_call] +/// extrinsic_name(SystemOrigin::Signed(caller), other, arguments); +/// +/// // verification code +/// assert_eq!(MyPallet::::my_var(), z); +/// } +/// +/// #[benchmark] +/// fn bench_name_2() { +/// // setup code +/// let caller = whitelisted_caller(); +/// +/// #[block] +/// { +/// something(some, thing); +/// my_extrinsic(RawOrigin::Signed(caller), some, argument); +/// something_else(foo, bar); +/// } +/// +/// // verification code +/// assert_eq!(MyPallet::::something(), 37); +/// } +/// } +/// ``` +/// +/// ## Benchmark Definitions +/// +/// Within a `#[benchmarks]` or `#[instance_benchmarks]` module, you can define individual +/// benchmarks using the `#[benchmark]` attribute, as shown in the example above. +/// +/// The `#[benchmark]` attribute expects a function definition with a blank return type and +/// zero or more arguments whose names are valid `frame_benchmarking::BenchmarkParamater` +/// parameters, such as `x`, `y`, `a`, `b`, etc., and whose param types must implement +/// [`benchmarking::ParamRange`]. At the moment the only valid type that implements +/// [`benchmarking::ParamRange`] is [`benchmarking::Linear`]. +/// +/// The valid syntax for defining a `Linear` is `Linear` where `A`, and `B` are +/// valid integer literals (that fit in a `u32`), such that `B` >= `A`. +/// +/// Note that the benchmark function definition does not actually expand as a function +/// definition, but rather is used to automatically create a number of impls and structs +/// required by the benchmarking engine. For this reason, the visibility of the function +/// definition as well as the return type are not used for any purpose and are discarded by the +/// expansion code. +/// +/// Also note that the `// setup code` and `// verification code` comments shown above are not +/// required and are included simply for demonstration purposes. +/// +/// ### `#[extrinsic_call]` and `#[block]` +/// +/// Within the benchmark function body, either an `#[extrinsic_call]` or a `#[block]` +/// annotation is required. These attributes should be attached to a block (shown in +/// `bench_name_2` above) or a one-line function call (shown in `bench_name_1` above, in `syn` +/// parlance this should be an `ExprCall`), respectively. +/// +/// The `#[block]` syntax is broad and will benchmark any code contained within the block the +/// attribute is attached to. If `#[block]` is attached to something other than a block, a +/// compiler error will be emitted. +/// +/// The one-line `#[extrinsic_call]` syntax must consist of a function call to an extrinsic, +/// where the first argument is the origin. If `#[extrinsic_call]` is attached to an item that +/// doesn't meet these requirements, a compiler error will be emitted. +/// +/// As a short-hand, you may substitute the name of the extrinsic call with `_`, such as the +/// following: +/// +/// ```ignore +/// #[extrinsic_call] +/// _(RawOrigin::Signed(whitelisted_caller()), 0u32.into(), 0); +/// ``` +/// +/// The underscore will be substituted with the name of the benchmark (i.e. the name of the +/// function in the benchmark function definition). +/// +/// Regardless of whether `#[extrinsic_call]` or `#[block]` is used, this attribute also serves +/// the purpose of designating the boundary between the setup code portion of the benchmark +/// (everything before the `#[extrinsic_call]` or `#[block]` attribute) and the verification +/// stage (everything after the item that the `#[extrinsic_call]` or `#[block]` attribute is +/// attached to). The setup code section should contain any code that needs to execute before +/// the measured portion of the benchmark executes. The verification section is where you can +/// perform assertions to verify that the extrinsic call (or whatever is happening in your +/// block, if you used the `#[block]` syntax) executed successfully. +/// +/// Note that neither `#[extrinsic_call]` nor `#[block]` are real attribute macros and are +/// instead consumed by the outer macro pattern as part of the enclosing benchmark function +/// definition. This is why we are able to use `#[extrinsic_call]` and `#[block]` within a +/// function definition even though this behavior has not been stabilized +/// yet—`#[extrinsic_call]` and `#[block]` are parsed and consumed as part of the benchmark +/// definition parsing code, so they never expand as their own attribute macros. +/// +/// ### Optional Attributes +/// +/// The keywords `extra` and `skip_meta` can be provided as optional arguments to the +/// `#[benchmark]` attribute, i.e. `#[benchmark(extra, skip_meta)]`. Including either of these +/// will enable the `extra` or `skip_meta` option, respectively. These options enable the same +/// behavior they did in the old benchmarking syntax in `frame_benchmarking`, namely: +/// +/// #### `extra` +/// +/// Specifies that this benchmark should not normally run. To run benchmarks marked with +/// `extra`, you will need to invoke the `frame-benchmarking-cli` with `--extra`. +/// +/// #### `skip_meta` +/// +/// Specifies that the benchmarking framework should not analyze the storage keys that +/// benchmarked code read or wrote. This useful to suppress the prints in the form of unknown +/// 0x… in case a storage key that does not have metadata. Note that this skips the analysis +/// of all accesses, not just ones without metadata. +/// +/// ## Where Clause +/// +/// Some pallets require a where clause specifying constraints on their generics to make +/// writing benchmarks feasible. To accomodate this situation, you can provide such a where +/// clause as the (only) argument to the `#[benchmarks]` or `#[instance_benchmarks]` attribute +/// macros. Below is an example of this taken from the `message-queue` pallet. +/// +/// ```ignore +/// #[benchmarks( +/// where +/// <::MessageProcessor as ProcessMessage>::Origin: From + PartialEq, +/// ::Size: From, +/// )] +/// mod benchmarks { +/// use super::*; +/// // ... +/// } +/// ``` +/// +/// ## Benchmark Tests +/// +/// Benchmark tests can be generated using the old syntax in `frame_benchmarking`, +/// including the `frame_benchmarking::impl_benchmark_test_suite` macro. +/// +/// An example is shown below (taken from the `message-queue` pallet's `benchmarking` module): +/// ```ignore +/// #[benchmarks] +/// mod benchmarks { +/// use super::*; +/// // ... +/// impl_benchmark_test_suite!( +/// MessageQueue, +/// crate::mock::new_test_ext::(), +/// crate::integration_test::Test +/// ); +/// } +/// ``` +pub mod benchmarking { + pub use frame_support_procedural::{ + benchmark, benchmarks, block, extrinsic_call, instance_benchmarks, + }; + + // Used in #[benchmark] implementation to ensure that benchmark function arguments + // implement [`ParamRange`]. + #[doc(hidden)] + pub use static_assertions::assert_impl_all; + + /// Used by the new benchmarking code to specify that a benchmarking variable is linear + /// over some specified range, i.e. `Linear<0, 1_000>` means that the corresponding variable + /// is allowed to range from `0` to `1000`, inclusive. + /// + /// See [`frame_support::benchmarking`] for more info. + pub struct Linear; + + /// Trait that must be implemented by all structs that can be used as parameter range types + /// in the new benchmarking code (i.e. `Linear<0, 1_000>`). Right now there is just + /// [`Linear`] but this could later be extended to support additional non-linear parameter + /// ranges. + /// + /// See [`frame_support::benchmarking`] for more info. + pub trait ParamRange { + /// Represents the (inclusive) starting number of this [`ParamRange`]. + fn start(&self) -> u32; + + /// Represents the (inclusive) ending number of this [`ParamRange`] + fn end(&self) -> u32; + } + + impl ParamRange for Linear { + fn start(&self) -> u32 { + return A + } + + fn end(&self) -> u32 { + return B + } + } +} + // Generate a macro that will enable/disable code based on `std` feature being active. sp_core::generate_feature_enabled_macro!(std_enabled, feature = "std", $); diff --git a/frame/support/test/Cargo.toml b/frame/support/test/Cargo.toml index fc211d77132f5..90ef243eed6c6 100644 --- a/frame/support/test/Cargo.toml +++ b/frame/support/test/Cargo.toml @@ -19,6 +19,7 @@ sp-arithmetic = { version = "6.0.0", default-features = false, path = "../../../ 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 = "../" } +frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../../benchmarking" } 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" } @@ -36,6 +37,7 @@ std = [ "serde/std", "codec/std", "scale-info/std", + "frame-benchmarking/std", "frame-support/std", "frame-system/std", "sp-core/std", diff --git a/frame/support/test/tests/benchmark_ui.rs b/frame/support/test/tests/benchmark_ui.rs new file mode 100644 index 0000000000000..243030bd07fcd --- /dev/null +++ b/frame/support/test/tests/benchmark_ui.rs @@ -0,0 +1,36 @@ +// This file is part of Substrate. + +// Copyright (C) 2020-2023 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#[rustversion::attr(not(stable), ignore)] +#[cfg(not(feature = "disable-ui-tests"))] +#[test] +fn benchmark_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"); + + // Deny all warnings since we emit warnings as part of a Pallet's UI. + std::env::set_var("RUSTFLAGS", "--deny warnings"); + + let t = trybuild::TestCases::new(); + t.compile_fail("tests/benchmark_ui/*.rs"); + t.pass("tests/benchmark_ui/pass/*.rs"); +} diff --git a/frame/support/test/tests/benchmark_ui/bad_param_name.rs b/frame/support/test/tests/benchmark_ui/bad_param_name.rs new file mode 100644 index 0000000000000..ad4db4f0a4ba4 --- /dev/null +++ b/frame/support/test/tests/benchmark_ui/bad_param_name.rs @@ -0,0 +1,18 @@ +use frame_support::benchmarking::*; +#[allow(unused_imports)] +use frame_support_test::Config; + +#[benchmarks] +mod benches { + use super::*; + + #[benchmark] + fn bench(winton: Linear<1, 2>) { + let a = 2 + 2; + #[block] + {} + assert_eq!(a, 4); + } +} + +fn main() {} diff --git a/frame/support/test/tests/benchmark_ui/bad_param_name.stderr b/frame/support/test/tests/benchmark_ui/bad_param_name.stderr new file mode 100644 index 0000000000000..4e2d63a6b5030 --- /dev/null +++ b/frame/support/test/tests/benchmark_ui/bad_param_name.stderr @@ -0,0 +1,5 @@ +error: Benchmark parameter names must consist of a single lowercase letter (a-z) and no other characters. + --> tests/benchmark_ui/bad_param_name.rs:10:11 + | +10 | fn bench(winton: Linear<1, 2>) { + | ^^^^^^ diff --git a/frame/support/test/tests/benchmark_ui/bad_param_name_too_long.rs b/frame/support/test/tests/benchmark_ui/bad_param_name_too_long.rs new file mode 100644 index 0000000000000..50e4dc6fd4609 --- /dev/null +++ b/frame/support/test/tests/benchmark_ui/bad_param_name_too_long.rs @@ -0,0 +1,14 @@ +use frame_support::benchmarking::*; +#[allow(unused_imports)] +use frame_support_test::Config; + +#[benchmarks] +mod benches { + #[benchmark] + fn bench(xx: Linear<1, 2>) { + #[block] + {} + } +} + +fn main() {} diff --git a/frame/support/test/tests/benchmark_ui/bad_param_name_too_long.stderr b/frame/support/test/tests/benchmark_ui/bad_param_name_too_long.stderr new file mode 100644 index 0000000000000..32f6bf8e47d09 --- /dev/null +++ b/frame/support/test/tests/benchmark_ui/bad_param_name_too_long.stderr @@ -0,0 +1,5 @@ +error: Benchmark parameter names must consist of a single lowercase letter (a-z) and no other characters. + --> tests/benchmark_ui/bad_param_name_too_long.rs:8:11 + | +8 | fn bench(xx: Linear<1, 2>) { + | ^^ diff --git a/frame/support/test/tests/benchmark_ui/bad_param_name_upper_case.rs b/frame/support/test/tests/benchmark_ui/bad_param_name_upper_case.rs new file mode 100644 index 0000000000000..0270582b3b85b --- /dev/null +++ b/frame/support/test/tests/benchmark_ui/bad_param_name_upper_case.rs @@ -0,0 +1,14 @@ +use frame_support::benchmarking::*; +#[allow(unused_imports)] +use frame_support_test::Config; + +#[benchmarks] +mod benches { + #[benchmark] + fn bench(D: Linear<1, 2>) { + #[block] + {} + } +} + +fn main() {} diff --git a/frame/support/test/tests/benchmark_ui/bad_param_name_upper_case.stderr b/frame/support/test/tests/benchmark_ui/bad_param_name_upper_case.stderr new file mode 100644 index 0000000000000..48dd41d3262d7 --- /dev/null +++ b/frame/support/test/tests/benchmark_ui/bad_param_name_upper_case.stderr @@ -0,0 +1,5 @@ +error: Benchmark parameter names must consist of a single lowercase letter (a-z) and no other characters. + --> tests/benchmark_ui/bad_param_name_upper_case.rs:8:11 + | +8 | fn bench(D: Linear<1, 2>) { + | ^ diff --git a/frame/support/test/tests/benchmark_ui/bad_param_range.rs b/frame/support/test/tests/benchmark_ui/bad_param_range.rs new file mode 100644 index 0000000000000..aabb9fa7403a1 --- /dev/null +++ b/frame/support/test/tests/benchmark_ui/bad_param_range.rs @@ -0,0 +1,16 @@ +use frame_support::benchmarking::*; +#[allow(unused_imports)] +use frame_support_test::Config; + +#[benchmarks] +mod benches { + use super::*; + + #[benchmark] + fn bench(x: Linear<3, 1>) { + #[block] + {} + } +} + +fn main() {} diff --git a/frame/support/test/tests/benchmark_ui/bad_param_range.stderr b/frame/support/test/tests/benchmark_ui/bad_param_range.stderr new file mode 100644 index 0000000000000..1347af0a07b8e --- /dev/null +++ b/frame/support/test/tests/benchmark_ui/bad_param_range.stderr @@ -0,0 +1,5 @@ +error: The start of a `ParamRange` must be less than or equal to the end + --> tests/benchmark_ui/bad_param_range.rs:10:21 + | +10 | fn bench(x: Linear<3, 1>) { + | ^ diff --git a/frame/support/test/tests/benchmark_ui/bad_params.rs b/frame/support/test/tests/benchmark_ui/bad_params.rs new file mode 100644 index 0000000000000..a0c9236982c62 --- /dev/null +++ b/frame/support/test/tests/benchmark_ui/bad_params.rs @@ -0,0 +1,18 @@ +use frame_support::benchmarking::*; +#[allow(unused_imports)] +use frame_support_test::Config; + +#[benchmarks] +mod benches { + use super::*; + + #[benchmark] + fn bench(y: Linear<1, 2>, x: u32) { + let a = 2 + 2; + #[block] + {} + assert_eq!(a, 4); + } +} + +fn main() {} diff --git a/frame/support/test/tests/benchmark_ui/bad_params.stderr b/frame/support/test/tests/benchmark_ui/bad_params.stderr new file mode 100644 index 0000000000000..068eaedd531b9 --- /dev/null +++ b/frame/support/test/tests/benchmark_ui/bad_params.stderr @@ -0,0 +1,5 @@ +error: Invalid benchmark function param. A valid example would be `x: Linear<5, 10>`. + --> tests/benchmark_ui/bad_params.rs:10:31 + | +10 | fn bench(y: Linear<1, 2>, x: u32) { + | ^^^ diff --git a/frame/support/test/tests/benchmark_ui/dup_block.rs b/frame/support/test/tests/benchmark_ui/dup_block.rs new file mode 100644 index 0000000000000..4c4a8fc11d30a --- /dev/null +++ b/frame/support/test/tests/benchmark_ui/dup_block.rs @@ -0,0 +1,20 @@ +use frame_support::benchmarking::*; +#[allow(unused_imports)] +use frame_support_test::Config; + +#[benchmarks] +mod benches { + use super::*; + + #[benchmark] + fn bench() { + let a = 2 + 2; + #[block] + {} + #[block] + {} + assert_eq!(a, 4); + } +} + +fn main() {} diff --git a/frame/support/test/tests/benchmark_ui/dup_block.stderr b/frame/support/test/tests/benchmark_ui/dup_block.stderr new file mode 100644 index 0000000000000..3d73c3d6609b1 --- /dev/null +++ b/frame/support/test/tests/benchmark_ui/dup_block.stderr @@ -0,0 +1,5 @@ +error: Only one #[extrinsic_call] or #[block] attribute is allowed per benchmark. + --> tests/benchmark_ui/dup_block.rs:14:3 + | +14 | #[block] + | ^ diff --git a/frame/support/test/tests/benchmark_ui/dup_extrinsic_call.rs b/frame/support/test/tests/benchmark_ui/dup_extrinsic_call.rs new file mode 100644 index 0000000000000..1a91b7c16d6a5 --- /dev/null +++ b/frame/support/test/tests/benchmark_ui/dup_extrinsic_call.rs @@ -0,0 +1,20 @@ +use frame_support::benchmarking::*; +#[allow(unused_imports)] +use frame_support_test::Config; + +#[benchmarks] +mod benches { + use super::*; + + #[benchmark] + fn bench() { + let a = 2 + 2; + #[extrinsic_call] + _(stuff); + #[extrinsic_call] + _(other_stuff); + assert_eq!(a, 4); + } +} + +fn main() {} diff --git a/frame/support/test/tests/benchmark_ui/dup_extrinsic_call.stderr b/frame/support/test/tests/benchmark_ui/dup_extrinsic_call.stderr new file mode 100644 index 0000000000000..593f7072bfa51 --- /dev/null +++ b/frame/support/test/tests/benchmark_ui/dup_extrinsic_call.stderr @@ -0,0 +1,5 @@ +error: Only one #[extrinsic_call] or #[block] attribute is allowed per benchmark. + --> tests/benchmark_ui/dup_extrinsic_call.rs:14:3 + | +14 | #[extrinsic_call] + | ^ diff --git a/frame/support/test/tests/benchmark_ui/extra_extra.rs b/frame/support/test/tests/benchmark_ui/extra_extra.rs new file mode 100644 index 0000000000000..021106c7afc85 --- /dev/null +++ b/frame/support/test/tests/benchmark_ui/extra_extra.rs @@ -0,0 +1,16 @@ +use frame_support::benchmarking::*; +#[allow(unused_imports)] +use frame_support_test::Config; + +#[benchmarks] +mod benches { + use super::*; + + #[benchmark(extra, extra)] + fn bench() { + #[block] + {} + } +} + +fn main() {} diff --git a/frame/support/test/tests/benchmark_ui/extra_extra.stderr b/frame/support/test/tests/benchmark_ui/extra_extra.stderr new file mode 100644 index 0000000000000..bf36b4f08054a --- /dev/null +++ b/frame/support/test/tests/benchmark_ui/extra_extra.stderr @@ -0,0 +1,5 @@ +error: unexpected end of input, `extra` can only be specified once + --> tests/benchmark_ui/extra_extra.rs:9:26 + | +9 | #[benchmark(extra, extra)] + | ^ diff --git a/frame/support/test/tests/benchmark_ui/extra_skip_meta.rs b/frame/support/test/tests/benchmark_ui/extra_skip_meta.rs new file mode 100644 index 0000000000000..1940f4cf1f040 --- /dev/null +++ b/frame/support/test/tests/benchmark_ui/extra_skip_meta.rs @@ -0,0 +1,16 @@ +use frame_support::benchmarking::*; +#[allow(unused_imports)] +use frame_support_test::Config; + +#[benchmarks] +mod benches { + use super::*; + + #[benchmark(skip_meta, skip_meta)] + fn bench() { + #[block] + {} + } +} + +fn main() {} diff --git a/frame/support/test/tests/benchmark_ui/extra_skip_meta.stderr b/frame/support/test/tests/benchmark_ui/extra_skip_meta.stderr new file mode 100644 index 0000000000000..4d48a8ad77a45 --- /dev/null +++ b/frame/support/test/tests/benchmark_ui/extra_skip_meta.stderr @@ -0,0 +1,5 @@ +error: unexpected end of input, `skip_meta` can only be specified once + --> tests/benchmark_ui/extra_skip_meta.rs:9:34 + | +9 | #[benchmark(skip_meta, skip_meta)] + | ^ diff --git a/frame/support/test/tests/benchmark_ui/extrinsic_call_out_of_fn.rs b/frame/support/test/tests/benchmark_ui/extrinsic_call_out_of_fn.rs new file mode 100644 index 0000000000000..4cb6bfc34c58e --- /dev/null +++ b/frame/support/test/tests/benchmark_ui/extrinsic_call_out_of_fn.rs @@ -0,0 +1,6 @@ +use frame_support::benchmarking::*; + +#[extrinsic_call] +mod stuff {} + +fn main() {} diff --git a/frame/support/test/tests/benchmark_ui/extrinsic_call_out_of_fn.stderr b/frame/support/test/tests/benchmark_ui/extrinsic_call_out_of_fn.stderr new file mode 100644 index 0000000000000..c5194d7a66502 --- /dev/null +++ b/frame/support/test/tests/benchmark_ui/extrinsic_call_out_of_fn.stderr @@ -0,0 +1,7 @@ +error: `#[extrinsic_call]` must be in a benchmark function definition labeled with `#[benchmark]`. + --> tests/benchmark_ui/extrinsic_call_out_of_fn.rs:3:1 + | +3 | #[extrinsic_call] + | ^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the attribute macro `extrinsic_call` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/frame/support/test/tests/benchmark_ui/missing_call.rs b/frame/support/test/tests/benchmark_ui/missing_call.rs new file mode 100644 index 0000000000000..74370493542c4 --- /dev/null +++ b/frame/support/test/tests/benchmark_ui/missing_call.rs @@ -0,0 +1,13 @@ +use frame_support::benchmarking::*; +#[allow(unused_imports)] +use frame_support_test::Config; + +#[benchmarks] +mod benches { + use super::*; + + #[benchmark] + fn bench() {} +} + +fn main() {} diff --git a/frame/support/test/tests/benchmark_ui/missing_call.stderr b/frame/support/test/tests/benchmark_ui/missing_call.stderr new file mode 100644 index 0000000000000..3b55f77d42562 --- /dev/null +++ b/frame/support/test/tests/benchmark_ui/missing_call.stderr @@ -0,0 +1,5 @@ +error: No valid #[extrinsic_call] or #[block] annotation could be found in benchmark function body. + --> tests/benchmark_ui/missing_call.rs:10:13 + | +10 | fn bench() {} + | ^^ diff --git a/frame/support/test/tests/benchmark_ui/missing_origin.rs b/frame/support/test/tests/benchmark_ui/missing_origin.rs new file mode 100644 index 0000000000000..aad91bc79f825 --- /dev/null +++ b/frame/support/test/tests/benchmark_ui/missing_origin.rs @@ -0,0 +1,16 @@ +use frame_support::benchmarking::*; +#[allow(unused_imports)] +use frame_support_test::Config; + +#[benchmarks] +mod benches { + use super::*; + + #[benchmark] + fn bench() { + #[extrinsic_call] + thing(); + } +} + +fn main() {} diff --git a/frame/support/test/tests/benchmark_ui/missing_origin.stderr b/frame/support/test/tests/benchmark_ui/missing_origin.stderr new file mode 100644 index 0000000000000..0e72bff4747a3 --- /dev/null +++ b/frame/support/test/tests/benchmark_ui/missing_origin.stderr @@ -0,0 +1,5 @@ +error: Single-item extrinsic calls must specify their origin as the first argument. + --> tests/benchmark_ui/missing_origin.rs:12:3 + | +12 | thing(); + | ^^^^^ diff --git a/frame/support/test/tests/benchmark_ui/pass/valid_basic.rs b/frame/support/test/tests/benchmark_ui/pass/valid_basic.rs new file mode 100644 index 0000000000000..5c84d7f76d874 --- /dev/null +++ b/frame/support/test/tests/benchmark_ui/pass/valid_basic.rs @@ -0,0 +1,17 @@ +use frame_support::benchmarking::*; +use frame_support_test::Config; + +#[benchmarks] +mod benches { + use super::*; + + #[benchmark(skip_meta, extra)] + fn bench() { + let a = 2 + 2; + #[block] + {} + assert_eq!(a, 4); + } +} + +fn main() {} diff --git a/frame/support/test/tests/benchmark_ui/unrecognized_option.rs b/frame/support/test/tests/benchmark_ui/unrecognized_option.rs new file mode 100644 index 0000000000000..4c2cea139f80c --- /dev/null +++ b/frame/support/test/tests/benchmark_ui/unrecognized_option.rs @@ -0,0 +1,16 @@ +use frame_support::benchmarking::*; +#[allow(unused_imports)] +use frame_support_test::Config; + +#[benchmarks] +mod benches { + use super::*; + + #[benchmark(skip_meta, extra, bad)] + fn bench() { + #[block] + {} + } +} + +fn main() {} diff --git a/frame/support/test/tests/benchmark_ui/unrecognized_option.stderr b/frame/support/test/tests/benchmark_ui/unrecognized_option.stderr new file mode 100644 index 0000000000000..5cebe9eab05e9 --- /dev/null +++ b/frame/support/test/tests/benchmark_ui/unrecognized_option.stderr @@ -0,0 +1,5 @@ +error: expected `extra` or `skip_meta` + --> tests/benchmark_ui/unrecognized_option.rs:9:32 + | +9 | #[benchmark(skip_meta, extra, bad)] + | ^^^ From d0a2c4ab86232a9a762d03f559715a14727bef3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Mon, 23 Jan 2023 12:35:04 +0100 Subject: [PATCH 314/715] Rename `*-private-ipv4` to `*-private-ip` CLI args (#13208) * Rename `*-private-ipv4` to `*-private-ip` CLI args Renames the `*-private-ipv4` to `*-private-ip` in the CLI interface. The old names are staying as alias, thus it will not break for anyone. Besides that it also fixes the naming in the rest of the code. * FMT --- client/cli/src/params/network_params.rs | 18 ++++++++--------- client/network/common/src/config.rs | 4 ++-- client/network/src/config.rs | 2 +- client/network/src/discovery.rs | 26 ++++++++++++------------- client/network/src/service.rs | 10 +++++++--- client/service/test/src/lib.rs | 2 +- 6 files changed, 33 insertions(+), 29 deletions(-) diff --git a/client/cli/src/params/network_params.rs b/client/cli/src/params/network_params.rs index 5580dea45bde6..984789da752d1 100644 --- a/client/cli/src/params/network_params.rs +++ b/client/cli/src/params/network_params.rs @@ -68,18 +68,18 @@ pub struct NetworkParams { #[arg(long, value_name = "PORT", conflicts_with_all = &[ "listen_addr" ])] pub port: Option, - /// Always forbid connecting to private IPv4 addresses (as specified in + /// Always forbid connecting to private IPv4/IPv6 addresses (as specified in /// [RFC1918](https://tools.ietf.org/html/rfc1918)), unless the address was passed with /// `--reserved-nodes` or `--bootnodes`. Enabled by default for chains marked as "live" in /// their chain specifications. - #[arg(long, conflicts_with_all = &["allow_private_ipv4"])] - pub no_private_ipv4: bool, + #[arg(long, alias = "no-private-ipv4", conflicts_with_all = &["allow_private_ip"])] + pub no_private_ip: bool, - /// Always accept connecting to private IPv4 addresses (as specified in + /// Always accept connecting to private IPv4/IPv6 addresses (as specified in /// [RFC1918](https://tools.ietf.org/html/rfc1918)). Enabled by default for chains marked as /// "local" in their chain specifications, or when `--dev` is passed. - #[arg(long, conflicts_with_all = &["no_private_ipv4"])] - pub allow_private_ipv4: bool, + #[arg(long, alias = "allow-private-ipv4", conflicts_with_all = &["no_private_ip"])] + pub allow_private_ip: bool, /// Specify the number of outgoing connections we're trying to maintain. #[arg(long, value_name = "COUNT", default_value_t = 15)] @@ -200,8 +200,8 @@ impl NetworkParams { self.discover_local || is_dev || matches!(chain_type, ChainType::Local | ChainType::Development); - let allow_private_ipv4 = match (self.allow_private_ipv4, self.no_private_ipv4) { - (true, true) => unreachable!("`*_private_ipv4` flags are mutually exclusive; qed"), + let allow_private_ip = match (self.allow_private_ip, self.no_private_ip) { + (true, true) => unreachable!("`*_private_ip` flags are mutually exclusive; qed"), (true, false) => true, (false, true) => false, (false, false) => @@ -231,7 +231,7 @@ impl NetworkParams { client_version: client_id.to_string(), transport: TransportConfig::Normal { enable_mdns: !is_dev && !self.no_mdns, - allow_private_ipv4, + allow_private_ip, }, max_parallel_downloads: self.max_parallel_downloads, enable_dht_random_walk: !self.reserved_only, diff --git a/client/network/common/src/config.rs b/client/network/common/src/config.rs index 96c7c11ec2696..c35d8a42a8c0c 100644 --- a/client/network/common/src/config.rs +++ b/client/network/common/src/config.rs @@ -301,10 +301,10 @@ pub enum TransportConfig { /// and connect to them if they support the same chain. enable_mdns: bool, - /// If true, allow connecting to private IPv4 addresses (as defined in + /// If true, allow connecting to private IPv4/IPv6 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, + allow_private_ip: bool, }, /// Only allow connections within the same process. diff --git a/client/network/src/config.rs b/client/network/src/config.rs index 52993e2519400..8ca8d75f1681c 100644 --- a/client/network/src/config.rs +++ b/client/network/src/config.rs @@ -223,7 +223,7 @@ impl NetworkConfiguration { extra_sets: Vec::new(), client_version: client_version.into(), node_name: node_name.into(), - transport: TransportConfig::Normal { enable_mdns: false, allow_private_ipv4: true }, + transport: TransportConfig::Normal { enable_mdns: false, allow_private_ip: true }, max_parallel_downloads: 5, sync_mode: SyncMode::Full, enable_dht_random_walk: true, diff --git a/client/network/src/discovery.rs b/client/network/src/discovery.rs index 5421db8194456..7329ebf15cf0d 100644 --- a/client/network/src/discovery.rs +++ b/client/network/src/discovery.rs @@ -96,7 +96,7 @@ pub struct DiscoveryConfig { local_peer_id: PeerId, permanent_addresses: Vec<(PeerId, Multiaddr)>, dht_random_walk: bool, - allow_private_ipv4: bool, + allow_private_ip: bool, allow_non_globals_in_dht: bool, discovery_only_if_under_num: u64, enable_mdns: bool, @@ -111,7 +111,7 @@ impl DiscoveryConfig { local_peer_id: local_public_key.to_peer_id(), permanent_addresses: Vec::new(), dht_random_walk: true, - allow_private_ipv4: true, + allow_private_ip: true, allow_non_globals_in_dht: false, discovery_only_if_under_num: std::u64::MAX, enable_mdns: false, @@ -142,9 +142,9 @@ impl DiscoveryConfig { self } - /// Should private IPv4 addresses be reported? - pub fn allow_private_ipv4(&mut self, value: bool) -> &mut Self { - self.allow_private_ipv4 = value; + /// Should private IPv4/IPv6 addresses be reported? + pub fn allow_private_ip(&mut self, value: bool) -> &mut Self { + self.allow_private_ip = value; self } @@ -189,7 +189,7 @@ impl DiscoveryConfig { local_peer_id, permanent_addresses, dht_random_walk, - allow_private_ipv4, + allow_private_ip, allow_non_globals_in_dht, discovery_only_if_under_num, enable_mdns, @@ -231,7 +231,7 @@ impl DiscoveryConfig { pending_events: VecDeque::new(), local_peer_id, num_connections: 0, - allow_private_ipv4, + allow_private_ip, discovery_only_if_under_num, mdns: if enable_mdns { match TokioMdns::new(mdns::Config::default()) { @@ -278,9 +278,9 @@ pub struct DiscoveryBehaviour { local_peer_id: PeerId, /// Number of nodes we're currently connected to. num_connections: u64, - /// If false, `addresses_of_peer` won't return any private IPv4 address, except for the ones - /// stored in `permanent_addresses` or `ephemeral_addresses`. - allow_private_ipv4: bool, + /// If false, `addresses_of_peer` won't return any private IPv4/IPv6 address, except for the + /// ones stored in `permanent_addresses` or `ephemeral_addresses`. + allow_private_ip: bool, /// Number of active connections over which we interrupt the discovery process. discovery_only_if_under_num: u64, /// Should non-global addresses be added to the DHT? @@ -506,7 +506,7 @@ impl NetworkBehaviour for DiscoveryBehaviour { list_to_filter.extend(mdns.addresses_of_peer(peer_id)); } - if !self.allow_private_ipv4 { + if !self.allow_private_ip { 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, @@ -947,7 +947,7 @@ mod tests { let mut config = DiscoveryConfig::new(keypair.public()); config .with_permanent_addresses(first_swarm_peer_id_and_addr.clone()) - .allow_private_ipv4(true) + .allow_private_ip(true) .allow_non_globals_in_dht(true) .discovery_limit(50) .with_kademlia(genesis_hash, fork_id, &protocol_id); @@ -1065,7 +1065,7 @@ mod tests { let keypair = Keypair::generate_ed25519(); let mut config = DiscoveryConfig::new(keypair.public()); config - .allow_private_ipv4(true) + .allow_private_ip(true) .allow_non_globals_in_dht(true) .discovery_limit(50) .with_kademlia(supported_genesis_hash, None, &supported_protocol_id); diff --git a/client/network/src/service.rs b/client/network/src/service.rs index f943a03f50b38..f3afb58e8e0e0 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -291,11 +291,15 @@ where match params.network_config.transport { TransportConfig::MemoryOnly => { config.with_mdns(false); - config.allow_private_ipv4(false); + config.allow_private_ip(false); }, - TransportConfig::Normal { enable_mdns, allow_private_ipv4, .. } => { + TransportConfig::Normal { + enable_mdns, + allow_private_ip: allow_private_ipv4, + .. + } => { config.with_mdns(enable_mdns); - config.allow_private_ipv4(allow_private_ipv4); + config.allow_private_ip(allow_private_ipv4); }, } diff --git a/client/service/test/src/lib.rs b/client/service/test/src/lib.rs index 5f75e3521e235..6533fe13961b5 100644 --- a/client/service/test/src/lib.rs +++ b/client/service/test/src/lib.rs @@ -220,7 +220,7 @@ fn node_config< ); network_config.transport = - TransportConfig::Normal { enable_mdns: false, allow_private_ipv4: true }; + TransportConfig::Normal { enable_mdns: false, allow_private_ip: true }; Configuration { impl_name: String::from("network-test-impl"), From e72f72fc9f493d5219328158f182b1b99f2f0208 Mon Sep 17 00:00:00 2001 From: Koute Date: Mon, 23 Jan 2023 23:08:51 +0900 Subject: [PATCH 315/715] Remove dead code (#13213) --- client/db/src/storage_cache.rs | 1975 -------------------------------- 1 file changed, 1975 deletions(-) delete mode 100644 client/db/src/storage_cache.rs diff --git a/client/db/src/storage_cache.rs b/client/db/src/storage_cache.rs deleted file mode 100644 index 474599e5d74e8..0000000000000 --- a/client/db/src/storage_cache.rs +++ /dev/null @@ -1,1975 +0,0 @@ -// 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 . - -//! Global state cache. Maintains recently queried/committed state values -//! Tracks changes over the span of a few recent blocks and handles forks -//! by tracking/removing cache entries for conflicting changes. - -use crate::{stats::StateUsageStats, utils::Meta}; -use hash_db::Hasher; -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}, - StateVersion, -}; -use sp_state_machine::{ - backend::Backend as StateBackend, ChildStorageCollection, StorageCollection, StorageKey, - StorageValue, TrieBackend, -}; -use std::{ - collections::{HashMap, HashSet, VecDeque}, - hash::Hash as StdHash, - sync::Arc, -}; - -const STATE_CACHE_BLOCKS: usize = 12; - -type ChildStorageKey = (Vec, Vec); - -/// Shared canonical state cache. -pub struct Cache { - /// Storage cache. `None` indicates that key is known to be missing. - lru_storage: LRUMap>, - /// Storage hashes cache. `None` indicates that key is known to be missing. - lru_hashes: LRUMap>, - /// Storage cache for child trie. `None` indicates that key is known to be missing. - lru_child_storage: LRUMap>, - /// Information on the modifications in recently committed blocks; specifically which keys - /// changed in which block. Ordered by block number. - modifications: VecDeque>, -} - -struct LRUMap(LinkedHashMap, usize, usize); - -/// Internal trait similar to `heapsize` but using a simple estimation. -/// -/// This should not be made public, it is an implementation detail trait. -trait EstimateSize { - /// Return a size estimation of the additional size needed to cache this struct (in bytes). - fn estimate_size(&self) -> usize; -} - -impl EstimateSize for Vec { - fn estimate_size(&self) -> usize { - self.capacity() - } -} - -impl EstimateSize for Option> { - fn estimate_size(&self) -> usize { - self.as_ref().map(|v| v.capacity()).unwrap_or(0) - } -} - -struct OptionHOut>(Option); - -impl> EstimateSize for OptionHOut { - fn estimate_size(&self) -> usize { - // capacity would be better - self.0.as_ref().map(|v| v.as_ref().len()).unwrap_or(0) - } -} - -impl EstimateSize for (T, T) { - fn estimate_size(&self) -> usize { - self.0.estimate_size() + self.1.estimate_size() - } -} - -impl LRUMap { - fn remove(&mut self, k: &K) { - let map = &mut self.0; - let storage_used_size = &mut self.1; - if let Some(v) = map.remove(k) { - *storage_used_size -= k.estimate_size(); - *storage_used_size -= v.estimate_size(); - } - } - - fn add(&mut self, k: K, v: V) { - let lmap = &mut self.0; - let storage_used_size = &mut self.1; - let limit = self.2; - let klen = k.estimate_size(); - *storage_used_size += v.estimate_size(); - // TODO assert k v size fit into limit?? to avoid insert remove? - match lmap.entry(k) { - Entry::Occupied(mut entry) => { - // note that in this case we are not running pure lru as - // it would require to remove first - *storage_used_size -= entry.get().estimate_size(); - entry.insert(v); - }, - Entry::Vacant(entry) => { - *storage_used_size += klen; - entry.insert(v); - }, - }; - - while *storage_used_size > limit { - if let Some((k, v)) = lmap.pop_front() { - *storage_used_size -= k.estimate_size(); - *storage_used_size -= v.estimate_size(); - } else { - // can happen fairly often as we get value from multiple lru - // and only remove from a single lru - break - } - } - } - - fn get(&mut self, k: &Q) -> Option<&mut V> - where - K: std::borrow::Borrow, - Q: StdHash + Eq, - { - self.0.get_refresh(k) - } - - fn used_size(&self) -> usize { - self.1 - } - fn clear(&mut self) { - self.0.clear(); - self.1 = 0; - } -} - -impl Cache { - /// Returns the used memory size of the storage cache in bytes. - pub fn used_storage_cache_size(&self) -> usize { - self.lru_storage.used_size() + self.lru_child_storage.used_size() - // ignore small hashes storage and self.lru_hashes.used_size() - } - - /// Synchronize the shared cache with the best block state. - /// - /// This function updates the shared cache by removing entries - /// that are invalidated by chain reorganization. It should be called - /// externally when chain reorg happens without importing a new block. - pub fn sync(&mut self, enacted: &[B::Hash], retracted: &[B::Hash]) { - trace!("Syncing shared cache, enacted = {:?}, retracted = {:?}", enacted, retracted); - - // Purge changes from re-enacted and retracted blocks. - let mut clear = false; - for block in enacted { - clear = clear || { - if let Some(m) = self.modifications.iter_mut().find(|m| &m.hash == block) { - trace!("Reverting enacted block {:?}", block); - m.is_canon = true; - for a in &m.storage { - trace!("Reverting enacted key {:?}", HexDisplay::from(a)); - self.lru_storage.remove(a); - self.lru_hashes.remove(a); - } - for a in &m.child_storage { - trace!("Reverting enacted child key {:?}", a); - self.lru_child_storage.remove(a); - } - false - } else { - true - } - }; - } - - for block in retracted { - clear = clear || { - if let Some(m) = self.modifications.iter_mut().find(|m| &m.hash == block) { - trace!("Retracting block {:?}", block); - m.is_canon = false; - for a in &m.storage { - trace!("Retracted key {:?}", HexDisplay::from(a)); - self.lru_storage.remove(a); - self.lru_hashes.remove(a); - } - for a in &m.child_storage { - trace!("Retracted child key {:?}", a); - self.lru_child_storage.remove(a); - } - false - } else { - true - } - }; - } - if clear { - // We don't know anything about the block; clear everything - trace!("Wiping cache"); - self.lru_storage.clear(); - self.lru_child_storage.clear(); - self.lru_hashes.clear(); - self.modifications.clear(); - } - } -} - -pub type SharedCache = Arc>>; - -/// Fix lru storage size for hash (small 64ko). -const FIX_LRU_HASH_SIZE: usize = 65_536; - -/// Create a new shared cache instance with given max memory usage. -pub fn new_shared_cache( - shared_cache_size: usize, - child_ratio: (usize, usize), -) -> SharedCache { - let top = child_ratio.1.saturating_sub(child_ratio.0); - Arc::new(RwLock::new(Cache { - lru_storage: LRUMap(LinkedHashMap::new(), 0, shared_cache_size * top / child_ratio.1), - lru_hashes: LRUMap(LinkedHashMap::new(), 0, FIX_LRU_HASH_SIZE), - lru_child_storage: LRUMap( - LinkedHashMap::new(), - 0, - shared_cache_size * child_ratio.0 / child_ratio.1, - ), - modifications: VecDeque::new(), - })) -} - -#[derive(Debug)] -/// Accumulates a list of storage changed in a block. -struct BlockChanges { - /// Block number. - number: B::Number, - /// Block hash. - hash: B::Hash, - /// Parent block hash. - parent: B::Hash, - /// A set of modified storage keys. - storage: HashSet, - /// A set of modified child storage keys. - child_storage: HashSet, - /// Block is part of the canonical chain. - is_canon: bool, -} - -/// Cached values specific to a state. -struct LocalCache { - /// Storage cache. - /// - /// `None` indicates that key is known to be missing. - storage: HashMap>, - /// Storage hashes cache. - /// - /// `None` indicates that key is known to be missing. - hashes: HashMap>, - /// Child storage cache. - /// - /// `None` indicates that key is known to be missing. - child_storage: HashMap>, -} - -/// Cache changes. -pub struct CacheChanges { - /// Shared canonical state cache. - shared_cache: SharedCache, - /// Local cache of values for this state. - local_cache: RwLock>>, - /// Hash of the block on top of which this instance was created or - /// `None` if cache is disabled - pub parent_hash: Option, -} - -/// State cache abstraction. -/// -/// Manages shared global state cache which reflects the canonical -/// state as it is on the disk. -/// -/// A instance of `CachingState` may be created as canonical or not. -/// For canonical instances local cache is accumulated and applied -/// in `sync_cache` along with the change overlay. -/// For non-canonical clones local cache and changes are dropped. -pub struct CachingState { - /// Usage statistics - usage: StateUsageStats, - /// State machine registered stats - overlay_stats: sp_state_machine::StateMachineStats, - /// Backing state. - state: S, - /// Cache data. - cache: CacheChanges, -} - -impl std::fmt::Debug for CachingState { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "Block {:?}", self.cache.parent_hash) - } -} - -impl CacheChanges { - /// Propagate local cache into the shared cache and synchronize - /// the shared cache with the best block state. - /// - /// This function updates the shared cache by removing entries - /// that are invalidated by chain reorganization. `sync_cache` - /// should be called after the block has been committed and the - /// blockchain route has been calculated. - pub fn sync_cache( - &mut self, - enacted: &[B::Hash], - retracted: &[B::Hash], - changes: StorageCollection, - child_changes: ChildStorageCollection, - commit_hash: Option, - commit_number: Option>, - is_best: bool, - ) { - let mut cache = self.shared_cache.write(); - trace!( - "Syncing cache, id = (#{:?}, {:?}), parent={:?}, best={}", - commit_number, - commit_hash, - self.parent_hash, - is_best, - ); - let cache = &mut *cache; - // Filter out committing block if any. - let mut enacted: Vec<_> = enacted - .iter() - .filter(|h| commit_hash.as_ref().map_or(true, |p| *h != p)) - .cloned() - .collect(); - - let mut retracted = std::borrow::Cow::Borrowed(retracted); - if let Some(commit_hash) = &commit_hash { - if let Some(m) = cache.modifications.iter_mut().find(|m| &m.hash == commit_hash) { - if m.is_canon != is_best { - // Same block comitted twice with different state changes. - // Treat it as reenacted/retracted. - if is_best { - enacted.push(*commit_hash); - } else { - retracted.to_mut().push(*commit_hash); - } - } - } - } - cache.sync(&enacted, &retracted); - // 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 self.parent_hash.is_some() { - let mut local_cache = self.local_cache.write(); - if is_best { - trace!( - "Committing {} local, {} hashes, {} modified root entries, {} modified child entries", - local_cache.storage.len(), - local_cache.hashes.len(), - changes.len(), - child_changes.iter().map(|v|v.1.len()).sum::(), - ); - for (k, v) in local_cache.storage.drain() { - cache.lru_storage.add(k, v); - } - for (k, v) in local_cache.child_storage.drain() { - cache.lru_child_storage.add(k, v); - } - for (k, v) in local_cache.hashes.drain() { - cache.lru_hashes.add(k, OptionHOut(v)); - } - } - } - - if let (Some(ref number), Some(ref hash), Some(ref parent)) = - (commit_number, commit_hash, self.parent_hash) - { - if cache.modifications.len() == STATE_CACHE_BLOCKS { - cache.modifications.pop_back(); - } - let mut modifications = HashSet::new(); - let mut child_modifications = HashSet::new(); - child_changes.into_iter().for_each(|(sk, changes)| { - for (k, v) in changes.into_iter() { - let k = (sk.clone(), k); - if is_best { - cache.lru_child_storage.add(k.clone(), v); - } - child_modifications.insert(k); - } - }); - for (k, v) in changes.into_iter() { - if is_best { - cache.lru_hashes.remove(&k); - cache.lru_storage.add(k.clone(), v); - } - modifications.insert(k); - } - - // Save modified storage. These are ordered by the block number in reverse. - let block_changes = BlockChanges { - storage: modifications, - child_storage: child_modifications, - number: *number, - hash: *hash, - is_canon: is_best, - parent: *parent, - }; - let insert_at = cache - .modifications - .iter() - .enumerate() - .find(|(_, m)| m.number < *number) - .map(|(i, _)| i); - trace!("Inserting modifications at {:?}", insert_at); - if let Some(insert_at) = insert_at { - cache.modifications.insert(insert_at, block_changes); - } else { - cache.modifications.push_back(block_changes); - } - } - } -} - -impl>, B: BlockT> CachingState { - /// Create a new instance wrapping generic State and shared cache. - pub(crate) fn new( - state: S, - shared_cache: SharedCache, - parent_hash: Option, - ) -> Self { - CachingState { - usage: StateUsageStats::new(), - overlay_stats: sp_state_machine::StateMachineStats::default(), - state, - cache: CacheChanges { - shared_cache, - local_cache: RwLock::new(LocalCache { - storage: Default::default(), - hashes: Default::default(), - child_storage: Default::default(), - }), - parent_hash, - }, - } - } - - /// Check if the key can be returned from cache by matching current block parent hash against - /// canonical state and filtering out entries modified in later blocks. - fn is_allowed( - key: Option<&[u8]>, - child_key: Option<&ChildStorageKey>, - parent_hash: &Option, - modifications: &VecDeque>, - ) -> bool { - let mut parent = match *parent_hash { - None => { - trace!( - "Cache lookup skipped for {:?}: no parent hash", - key.as_ref().map(HexDisplay::from) - ); - return false - }, - Some(ref parent) => parent, - }; - // Ignore all storage entries modified in later blocks. - // Modifications contains block ordered by the number - // We search for our parent in that list first and then for - // all its parents until we hit the canonical block, - // checking against all the intermediate modifications. - for m in modifications { - if &m.hash == parent { - if m.is_canon { - return true - } - parent = &m.parent; - } - if let Some(key) = key { - if m.storage.contains(key) { - trace!( - "Cache lookup skipped for {:?}: modified in a later block", - HexDisplay::from(&key) - ); - return false - } - } - if let Some(child_key) = child_key { - if m.child_storage.contains(child_key) { - trace!("Cache lookup skipped for {:?}: modified in a later block", child_key); - return false - } - } - } - trace!( - "Cache lookup skipped for {:?}: parent hash is unknown", - key.as_ref().map(HexDisplay::from), - ); - false - } -} - -impl>, B: BlockT> StateBackend> for CachingState { - type Error = S::Error; - type Transaction = S::Transaction; - type TrieBackendStorage = S::TrieBackendStorage; - - fn storage(&self, key: &[u8]) -> Result>, Self::Error> { - let local_cache = self.cache.local_cache.upgradable_read(); - // Note that local cache makes that lru is not refreshed - if let Some(entry) = local_cache.storage.get(key).cloned() { - trace!("Found in local cache: {:?}", HexDisplay::from(&key)); - self.usage.tally_key_read(key, entry.as_ref(), true); - - return Ok(entry) - } - { - 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_storage.get(key).map(|a| a.clone()) { - trace!("Found in shared cache: {:?}", HexDisplay::from(&key)); - self.usage.tally_key_read(key, entry.as_ref(), true); - return Ok(entry) - } - } - } - trace!("Cache miss: {:?}", HexDisplay::from(&key)); - let value = self.state.storage(key)?; - RwLockUpgradableReadGuard::upgrade(local_cache) - .storage - .insert(key.to_vec(), value.clone()); - self.usage.tally_key_read(key, value.as_ref(), false); - Ok(value) - } - - fn storage_hash(&self, key: &[u8]) -> Result, Self::Error> { - let local_cache = self.cache.local_cache.upgradable_read(); - if let Some(entry) = local_cache.hashes.get(key).cloned() { - trace!("Found hash in local cache: {:?}", HexDisplay::from(&key)); - return Ok(entry) - } - { - 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) { - trace!("Found hash in shared cache: {:?}", HexDisplay::from(&key)); - return Ok(entry) - } - } - } - trace!("Cache hash miss: {:?}", HexDisplay::from(&key)); - let hash = self.state.storage_hash(key)?; - RwLockUpgradableReadGuard::upgrade(local_cache) - .hashes - .insert(key.to_vec(), hash); - Ok(hash) - } - - fn child_storage( - &self, - child_info: &ChildInfo, - key: &[u8], - ) -> Result>, Self::Error> { - let key = (child_info.storage_key().to_vec(), key.to_vec()); - let local_cache = self.cache.local_cache.upgradable_read(); - if let Some(entry) = local_cache.child_storage.get(&key).cloned() { - trace!("Found in local cache: {:?}", key); - return Ok(self.usage.tally_child_key_read(&key, entry, true)) - } - { - let cache = self.cache.shared_cache.upgradable_read(); - if Self::is_allowed(None, Some(&key), &self.cache.parent_hash, &cache.modifications) { - let mut cache = RwLockUpgradableReadGuard::upgrade(cache); - if let Some(entry) = cache.lru_child_storage.get(&key).map(|a| a.clone()) { - trace!("Found in shared cache: {:?}", key); - return Ok(self.usage.tally_child_key_read(&key, entry, true)) - } - } - } - trace!("Cache miss: {:?}", key); - 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); - - RwLockUpgradableReadGuard::upgrade(local_cache) - .child_storage - .insert(key, value.clone()); - Ok(value) - } - - fn exists_storage(&self, key: &[u8]) -> Result { - Ok(self.storage(key)?.is_some()) - } - - 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 as_trie_backend(&self) -> Option<&TrieBackend>> { - self.state.as_trie_backend() - } - - 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 - } -} - -/// Extended [`CachingState`] that will sync the caches on drop. -pub struct SyncingCachingState { - /// The usage statistics of the backend. These will be updated on drop. - state_usage: Arc, - /// Reference to the meta db. - meta: Arc, Block::Hash>>>, - /// Mutex to lock get exlusive access to the backend. - lock: Arc>, - /// The wrapped caching state. - /// - /// This is required to be a `Option`, because sometimes we want to extract - /// the cache changes and Rust does not allow to move fields from types that - /// implement `Drop`. - caching_state: Option>, - /// Disable syncing of the cache. This is by default always `false`. However, - /// we need to disable syncing when this is a state in a - /// [`BlockImportOperation`](crate::BlockImportOperation). The import operation - /// takes care to sync the cache and more importantly we want to prevent a dead - /// lock. - disable_syncing: bool, -} - -impl SyncingCachingState { - /// Create new automatic syncing state. - pub fn new( - caching_state: CachingState, - state_usage: Arc, - meta: Arc, B::Hash>>>, - lock: Arc>, - ) -> Self { - Self { caching_state: Some(caching_state), state_usage, meta, lock, disable_syncing: false } - } - - /// Returns the reference to the internal [`CachingState`]. - fn caching_state(&self) -> &CachingState { - self.caching_state - .as_ref() - .expect("`caching_state` is always valid for the lifetime of the object; qed") - } - - /// Convert `Self` into the cache changes. - pub fn into_cache_changes(mut self) -> CacheChanges { - self.caching_state - .take() - .expect("`caching_state` is always valid for the lifetime of the object; qed") - .cache - } - - /// Disable syncing the cache on drop. - pub fn disable_syncing(&mut self) { - self.disable_syncing = true; - } -} - -impl std::fmt::Debug for SyncingCachingState { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.caching_state().fmt(f) - } -} - -impl>, B: BlockT> StateBackend> - for SyncingCachingState -{ - type Error = S::Error; - type Transaction = S::Transaction; - type TrieBackendStorage = S::TrieBackendStorage; - - fn storage(&self, key: &[u8]) -> Result>, Self::Error> { - self.caching_state().storage(key) - } - - fn storage_hash(&self, key: &[u8]) -> Result, Self::Error> { - self.caching_state().storage_hash(key) - } - - fn child_storage( - &self, - child_info: &ChildInfo, - key: &[u8], - ) -> Result>, Self::Error> { - self.caching_state().child_storage(child_info, key) - } - - fn exists_storage(&self, key: &[u8]) -> Result { - self.caching_state().exists_storage(key) - } - - fn exists_child_storage( - &self, - child_info: &ChildInfo, - key: &[u8], - ) -> Result { - self.caching_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.caching_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.caching_state().apply_to_keys_while(child_info, prefix, start_at, f) - } - - fn next_storage_key(&self, key: &[u8]) -> Result>, Self::Error> { - self.caching_state().next_storage_key(key) - } - - fn next_child_storage_key( - &self, - child_info: &ChildInfo, - key: &[u8], - ) -> Result>, Self::Error> { - self.caching_state().next_child_storage_key(child_info, key) - } - - fn for_keys_with_prefix(&self, prefix: &[u8], f: F) { - self.caching_state().for_keys_with_prefix(prefix, f) - } - - fn for_key_values_with_prefix(&self, prefix: &[u8], f: F) { - self.caching_state().for_key_values_with_prefix(prefix, f) - } - - fn for_child_keys_with_prefix( - &self, - child_info: &ChildInfo, - prefix: &[u8], - f: F, - ) { - self.caching_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.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, state_version) - } - - fn pairs(&self) -> Vec<(Vec, Vec)> { - self.caching_state().pairs() - } - - fn keys(&self, prefix: &[u8]) -> Vec> { - self.caching_state().keys(prefix) - } - - fn child_keys(&self, child_info: &ChildInfo, prefix: &[u8]) -> Vec> { - self.caching_state().child_keys(child_info, prefix) - } - - fn as_trie_backend(&self) -> Option<&TrieBackend>> { - self.caching_state - .as_ref() - .expect("`caching_state` is valid for the lifetime of the object; qed") - .as_trie_backend() - } - - fn register_overlay_stats(&self, stats: &sp_state_machine::StateMachineStats) { - self.caching_state().register_overlay_stats(stats); - } - - fn usage_info(&self) -> sp_state_machine::UsageInfo { - self.caching_state().usage_info() - } -} - -impl Drop for SyncingCachingState { - fn drop(&mut self) { - if self.disable_syncing { - return - } - - if let Some(mut caching_state) = self.caching_state.take() { - let _lock = self.lock.read(); - - self.state_usage.merge_sm(caching_state.usage.take()); - 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); - } - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use sp_runtime::{ - testing::{Block as RawBlock, ExtrinsicWrapper, H256}, - traits::BlakeTwo256, - }; - use sp_state_machine::InMemoryBackend; - - type Block = RawBlock>; - - #[test] - fn smoke() { - // init_log(); - let root_parent = H256::random(); - let key = H256::random()[..].to_vec(); - let h0 = H256::random(); - let h1a = H256::random(); - let h1b = H256::random(); - let h2a = H256::random(); - let h2b = H256::random(); - let h3a = H256::random(); - let h3b = H256::random(); - - let shared = new_shared_cache::(256 * 1024, (0, 1)); - - // blocks [ 3a(c) 2a(c) 2b 1b 1a(c) 0 ] - // state [ 5 5 4 3 2 2 ] - let mut s = CachingState::new( - InMemoryBackend::::default(), - shared.clone(), - Some(root_parent), - ); - s.cache.sync_cache( - &[], - &[], - vec![(key.clone(), Some(vec![2]))], - vec![], - Some(h0), - Some(0), - true, - ); - - let mut s = - CachingState::new(InMemoryBackend::::default(), shared.clone(), Some(h0)); - s.cache.sync_cache(&[], &[], vec![], vec![], Some(h1a), Some(1), true); - - let mut s = - CachingState::new(InMemoryBackend::::default(), shared.clone(), Some(h0)); - s.cache.sync_cache( - &[], - &[], - vec![(key.clone(), Some(vec![3]))], - vec![], - Some(h1b), - Some(1), - false, - ); - - let mut s = - CachingState::new(InMemoryBackend::::default(), shared.clone(), Some(h1b)); - s.cache.sync_cache( - &[], - &[], - vec![(key.clone(), Some(vec![4]))], - vec![], - Some(h2b), - Some(2), - false, - ); - - let mut s = - CachingState::new(InMemoryBackend::::default(), shared.clone(), Some(h1a)); - s.cache.sync_cache( - &[], - &[], - vec![(key.clone(), Some(vec![5]))], - vec![], - Some(h2a), - Some(2), - true, - ); - - let mut s = - CachingState::new(InMemoryBackend::::default(), shared.clone(), Some(h2a)); - s.cache.sync_cache(&[], &[], vec![], vec![], Some(h3a), Some(3), true); - - let s = - CachingState::new(InMemoryBackend::::default(), shared.clone(), Some(h3a)); - assert_eq!(s.storage(&key).unwrap().unwrap(), vec![5]); - - let s = - CachingState::new(InMemoryBackend::::default(), shared.clone(), Some(h1a)); - assert!(s.storage(&key).unwrap().is_none()); - - let s = - CachingState::new(InMemoryBackend::::default(), shared.clone(), Some(h2b)); - assert!(s.storage(&key).unwrap().is_none()); - - let s = - CachingState::new(InMemoryBackend::::default(), shared.clone(), Some(h1b)); - assert!(s.storage(&key).unwrap().is_none()); - - // reorg to 3b - // blocks [ 3b(c) 3a 2a 2b(c) 1b 1a 0 ] - let mut s = - CachingState::new(InMemoryBackend::::default(), shared.clone(), Some(h2b)); - s.cache.sync_cache( - &[h1b, h2b, h3b], - &[h1a, h2a, h3a], - vec![], - vec![], - Some(h3b), - Some(3), - true, - ); - let s = - CachingState::new(InMemoryBackend::::default(), shared.clone(), Some(h3a)); - assert!(s.storage(&key).unwrap().is_none()); - } - - #[test] - fn simple_fork() { - sp_tracing::try_init_simple(); - - let root_parent = H256::random(); - let key = H256::random()[..].to_vec(); - let h1 = H256::random(); - let h2a = H256::random(); - let h2b = H256::random(); - let h3b = H256::random(); - - let shared = new_shared_cache::(256 * 1024, (0, 1)); - - let mut s = CachingState::new( - InMemoryBackend::::default(), - shared.clone(), - Some(root_parent), - ); - s.cache.sync_cache( - &[], - &[], - vec![(key.clone(), Some(vec![2]))], - vec![], - Some(h1), - Some(1), - true, - ); - - let mut s = - CachingState::new(InMemoryBackend::::default(), shared.clone(), Some(h1)); - s.cache.sync_cache(&[], &[], vec![], vec![], Some(h2a), Some(2), true); - - let mut s = - CachingState::new(InMemoryBackend::::default(), shared.clone(), Some(h1)); - s.cache.sync_cache( - &[], - &[], - vec![(key.clone(), Some(vec![3]))], - vec![], - Some(h2b), - Some(2), - false, - ); - - let mut s = - CachingState::new(InMemoryBackend::::default(), shared.clone(), Some(h2b)); - s.cache.sync_cache( - &[], - &[], - vec![(key.clone(), Some(vec![3]))], - vec![], - Some(h3b), - Some(2), - false, - ); - - let s = - CachingState::new(InMemoryBackend::::default(), shared.clone(), Some(h2a)); - assert_eq!(s.storage(&key).unwrap().unwrap(), vec![2]); - } - - #[test] - fn double_fork() { - let root_parent = H256::random(); - let key = H256::random()[..].to_vec(); - let h1 = H256::random(); - let h2a = H256::random(); - let h2b = H256::random(); - let h3a = H256::random(); - let h3b = H256::random(); - - let shared = new_shared_cache::(256 * 1024, (0, 1)); - - let mut s = CachingState::new( - InMemoryBackend::::default(), - shared.clone(), - Some(root_parent), - ); - s.cache.sync_cache(&[], &[], vec![], vec![], Some(h1), Some(1), true); - - let mut s = - CachingState::new(InMemoryBackend::::default(), shared.clone(), Some(h1)); - s.cache.sync_cache(&[], &[], vec![], vec![], Some(h2a), Some(2), true); - - let mut s = - CachingState::new(InMemoryBackend::::default(), shared.clone(), Some(h2a)); - s.cache.sync_cache( - &[], - &[], - vec![(key.clone(), Some(vec![2]))], - vec![], - Some(h3a), - Some(3), - true, - ); - - let mut s = - CachingState::new(InMemoryBackend::::default(), shared.clone(), Some(h1)); - s.cache.sync_cache(&[], &[], vec![], vec![], Some(h2b), Some(2), false); - - let mut s = - CachingState::new(InMemoryBackend::::default(), shared.clone(), Some(h2b)); - s.cache.sync_cache( - &[], - &[], - vec![(key.clone(), Some(vec![3]))], - vec![], - Some(h3b), - Some(3), - false, - ); - - let s = - CachingState::new(InMemoryBackend::::default(), shared.clone(), Some(h3a)); - assert_eq!(s.storage(&key).unwrap().unwrap(), vec![2]); - } - - #[test] - fn reverts_storage_hash() { - let root_parent = H256::random(); - let key = H256::random()[..].to_vec(); - let h1a = H256::random(); - let h1b = H256::random(); - - 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]))])), - Default::default(), - ); - - let mut s = CachingState::new(backend.clone(), shared.clone(), Some(root_parent)); - s.cache.sync_cache( - &[], - &[], - vec![(key.clone(), Some(vec![2]))], - vec![], - Some(h1a), - Some(1), - true, - ); - - let mut s = CachingState::new(backend.clone(), shared.clone(), Some(root_parent)); - s.cache.sync_cache(&[], &[h1a], vec![], vec![], Some(h1b), Some(1), true); - - let s = CachingState::new(backend.clone(), shared.clone(), Some(h1b)); - assert_eq!(s.storage_hash(&key).unwrap().unwrap(), BlakeTwo256::hash(&vec![1])); - } - - #[test] - fn should_track_used_size_correctly() { - let root_parent = H256::random(); - let shared = new_shared_cache::(109, ((109 - 36), 109)); - let h0 = H256::random(); - - let mut s = CachingState::new( - InMemoryBackend::::default(), - shared.clone(), - Some(root_parent), - ); - - let key = H256::random()[..].to_vec(); - let s_key = H256::random()[..].to_vec(); - s.cache.sync_cache( - &[], - &[], - vec![(key.clone(), Some(vec![1, 2, 3]))], - vec![], - Some(h0), - Some(0), - true, - ); - // 32 key, 3 byte size - assert_eq!(shared.read().used_storage_cache_size(), 35 /* bytes */); - - let key = H256::random()[..].to_vec(); - s.cache.sync_cache( - &[], - &[], - vec![], - vec![(s_key.clone(), vec![(key.clone(), Some(vec![1, 2]))])], - Some(h0), - Some(0), - true, - ); - // 35 + (2 * 32) key, 2 byte size - assert_eq!(shared.read().used_storage_cache_size(), 101 /* bytes */); - } - - #[test] - fn should_remove_lru_items_based_on_tracking_used_size() { - let root_parent = H256::random(); - let shared = new_shared_cache::(36 * 3, (2, 3)); - let h0 = H256::random(); - - let mut s = CachingState::new( - InMemoryBackend::::default(), - shared.clone(), - Some(root_parent), - ); - - let key = H256::random()[..].to_vec(); - s.cache.sync_cache( - &[], - &[], - vec![(key.clone(), Some(vec![1, 2, 3, 4]))], - vec![], - Some(h0), - Some(0), - true, - ); - // 32 key, 4 byte size - assert_eq!(shared.read().used_storage_cache_size(), 36 /* bytes */); - - let key = H256::random()[..].to_vec(); - s.cache.sync_cache( - &[], - &[], - vec![(key.clone(), Some(vec![1, 2]))], - vec![], - Some(h0), - Some(0), - true, - ); - // 32 key, 2 byte size - assert_eq!(shared.read().used_storage_cache_size(), 34 /* bytes */); - } - - #[test] - fn fix_storage_mismatch_issue() { - sp_tracing::try_init_simple(); - let root_parent = H256::random(); - - let key = H256::random()[..].to_vec(); - - let h0 = H256::random(); - let h1 = H256::random(); - - let shared = new_shared_cache::(256 * 1024, (0, 1)); - let mut s = CachingState::new( - InMemoryBackend::::default(), - shared.clone(), - Some(root_parent), - ); - s.cache.sync_cache( - &[], - &[], - vec![(key.clone(), Some(vec![2]))], - vec![], - Some(h0), - Some(0), - true, - ); - - let mut s = - CachingState::new(InMemoryBackend::::default(), shared.clone(), Some(h0)); - s.cache.sync_cache( - &[], - &[], - vec![(key.clone(), Some(vec![3]))], - vec![], - Some(h1), - Some(1), - true, - ); - - let mut s = - CachingState::new(InMemoryBackend::::default(), shared.clone(), Some(h1)); - assert_eq!(s.storage(&key).unwrap(), Some(vec![3])); - - // Restart (or unknown block?), clear caches. - { - let mut cache = s.cache.shared_cache.write(); - let cache = &mut *cache; - cache.lru_storage.clear(); - cache.lru_hashes.clear(); - cache.lru_child_storage.clear(); - cache.modifications.clear(); - } - - // New value is written because of cache miss. - s.cache.local_cache.write().storage.insert(key.clone(), Some(vec![42])); - - // New value is propagated. - s.cache.sync_cache(&[], &[], vec![], vec![], None, None, true); - - let s = - CachingState::new(InMemoryBackend::::default(), shared.clone(), Some(h1)); - assert_eq!(s.storage(&key).unwrap(), None); - } - - #[test] - fn same_block_no_changes() { - sp_tracing::try_init_simple(); - - let root_parent = H256::random(); - let key = H256::random()[..].to_vec(); - let h1 = H256::random(); - let h2 = H256::random(); - - let shared = new_shared_cache::(256 * 1024, (0, 1)); - - let mut s = CachingState::new( - InMemoryBackend::::default(), - shared.clone(), - Some(root_parent), - ); - s.cache.sync_cache( - &[], - &[], - vec![(key.clone(), Some(vec![1]))], - vec![], - Some(h1), - Some(1), - true, - ); - assert_eq!(shared.write().lru_storage.get(&key).unwrap(), &Some(vec![1])); - - let mut s = - CachingState::new(InMemoryBackend::::default(), shared.clone(), Some(h1)); - - // commit as non-best - s.cache.sync_cache( - &[], - &[], - vec![(key.clone(), Some(vec![2]))], - vec![], - Some(h2), - Some(2), - false, - ); - - assert_eq!(shared.write().lru_storage.get(&key).unwrap(), &Some(vec![1])); - - let mut s = - CachingState::new(InMemoryBackend::::default(), shared.clone(), Some(h1)); - - // commit again as best with no changes - s.cache.sync_cache(&[], &[], vec![], vec![], Some(h2), Some(2), true); - assert_eq!(s.storage(&key).unwrap(), None); - } -} - -#[cfg(test)] -mod qc { - use std::collections::{hash_map::Entry, HashMap}; - - use quickcheck::{quickcheck, Arbitrary, TestResult}; - - use super::*; - use sp_runtime::{ - testing::{Block as RawBlock, ExtrinsicWrapper, H256}, - traits::BlakeTwo256, - }; - use sp_state_machine::InMemoryBackend; - - type Block = RawBlock>; - - type KeySet = Vec<(Vec, Option>)>; - - type KeyMap = HashMap, Option>>; - - #[derive(Debug, Clone)] - struct Node { - hash: H256, - #[allow(unused)] - parent: H256, - state: KeyMap, - changes: KeySet, - } - - impl Node { - fn new_next(&self, hash: H256, changes: KeySet) -> Self { - let mut state = self.state.clone(); - - for (k, v) in self.state.iter() { - state.insert(k.clone(), v.clone()); - } - for (k, v) in changes.clone().into_iter() { - state.insert(k, v); - } - - Self { hash, parent: self.hash, changes, state } - } - - fn new(hash: H256, parent: H256, changes: KeySet) -> Self { - let mut state = KeyMap::new(); - - for (k, v) in changes.clone().into_iter() { - state.insert(k, v); - } - - Self { hash, parent, state, changes } - } - - fn purge(&mut self, other_changes: &KeySet) { - for (k, _) in other_changes.iter() { - self.state.remove(k); - } - } - } - - #[derive(Debug, Clone)] - enum Action { - Next { hash: H256, changes: KeySet }, - Fork { depth: usize, hash: H256, changes: KeySet }, - ReorgWithImport { depth: usize, hash: H256 }, - FinalizationReorg { fork_depth: usize, depth: usize }, - } - - impl Arbitrary for Action { - fn arbitrary(gen: &mut quickcheck::Gen) -> Self { - let path = u8::arbitrary(gen); - let buf = (0..32).map(|_| u8::arbitrary(gen)).collect::>(); - - match path { - 0..=175 => Action::Next { - hash: H256::from_slice(&buf[..]), - changes: { - let mut set = Vec::new(); - for _ in 0..::arbitrary(gen) / (64 * 256 * 256 * 256) { - set.push((vec![u8::arbitrary(gen)], Some(vec![u8::arbitrary(gen)]))); - } - set - }, - }, - 176..=220 => Action::Fork { - hash: H256::from_slice(&buf[..]), - depth: ((u8::arbitrary(gen)) / 32) as usize, - changes: { - let mut set = Vec::new(); - for _ in 0..::arbitrary(gen) / (64 * 256 * 256 * 256) { - set.push((vec![u8::arbitrary(gen)], Some(vec![u8::arbitrary(gen)]))); - } - set - }, - }, - 221..=240 => { - Action::ReorgWithImport { - hash: H256::from_slice(&buf[..]), - depth: ((u8::arbitrary(gen)) / 32) as usize, // 0-7 - } - }, - _ => { - Action::FinalizationReorg { - fork_depth: ((u8::arbitrary(gen)) / 32) as usize, // 0-7 - depth: ((u8::arbitrary(gen)) / 64) as usize, // 0-3 - } - }, - } - } - } - - struct Mutator { - shared: SharedCache, - canon: Vec, - forks: HashMap>, - } - - impl Mutator { - fn new_empty() -> Self { - let shared = new_shared_cache::(256 * 1024, (0, 1)); - - Self { shared, canon: vec![], forks: HashMap::new() } - } - - fn head_state(&self, hash: H256) -> CachingState, Block> { - CachingState::new( - InMemoryBackend::::default(), - self.shared.clone(), - Some(hash), - ) - } - - fn canon_head_state(&self) -> CachingState, Block> { - self.head_state(self.canon.last().expect("Expected to be one commit").hash) - } - - fn mutate_static( - &mut self, - action: Action, - ) -> CachingState, Block> { - self.mutate(action) - .expect("Expected to provide only valid actions to the mutate_static") - } - - fn canon_len(&self) -> usize { - return self.canon.len() - } - - fn head_storage_ref(&self) -> &KeyMap { - &self.canon.last().expect("Expected to be one commit").state - } - - fn key_permutations() -> Vec> { - (0u8..255).map(|x| vec![x]).collect() - } - - fn mutate( - &mut self, - action: Action, - ) -> Result, Block>, ()> { - let state = match action { - Action::Fork { depth, hash, changes } => { - let pos = self.canon.len() as isize - depth as isize; - if pos < 0 || self.canon.len() == 0 || pos >= (self.canon.len() - 1) as isize - // no fork on top also, thus len-1 - { - return Err(()) - } - - let pos = pos as usize; - - let fork_at = self.canon[pos].hash; - - let (total_h, parent) = match self.forks.entry(fork_at) { - Entry::Occupied(occupied) => { - let chain = occupied.into_mut(); - let parent = - chain.last().expect("No empty forks are ever created").clone(); - let mut node = parent.new_next(hash, changes.clone()); - - for earlier in chain.iter() { - node.purge(&earlier.changes.clone()); - } - - chain.push(node); - - (pos + chain.len(), parent.hash) - }, - Entry::Vacant(vacant) => { - let canon_parent = &self.canon[pos]; - vacant.insert(vec![canon_parent.new_next(hash, changes.clone())]); - - (pos + 1, fork_at) - }, - }; - - let mut state = CachingState::new( - InMemoryBackend::::default(), - self.shared.clone(), - Some(parent), - ); - - state.cache.sync_cache( - &[], - &[], - changes, - vec![], - Some(hash), - Some(total_h as u64), - false, - ); - - state - }, - Action::Next { hash, changes } => { - let (next, parent_hash) = match self.canon.last() { - None => { - let parent_hash = H256::from(&[0u8; 32]); - (Node::new(hash, parent_hash, changes.clone()), parent_hash) - }, - Some(parent) => (parent.new_next(hash, changes.clone()), parent.hash), - }; - - // delete cache entries for earlier - for node in self.canon.iter_mut() { - node.purge(&next.changes); - if let Some(fork) = self.forks.get_mut(&node.hash) { - for node in fork.iter_mut() { - node.purge(&next.changes); - } - } - } - - let mut state = CachingState::new( - InMemoryBackend::::default(), - self.shared.clone(), - Some(parent_hash), - ); - - state.cache.sync_cache( - &[], - &[], - next.changes.clone(), - vec![], - Some(hash), - Some(self.canon.len() as u64 + 1), - true, - ); - - self.canon.push(next); - - state - }, - Action::ReorgWithImport { depth, hash } => { - let pos = self.canon.len() as isize - depth as isize; - if pos < 0 || pos + 1 >= self.canon.len() as isize { - return Err(()) - } - let fork_at = self.canon[pos as usize].hash; - let pos = pos as usize; - - match self.forks.get_mut(&fork_at) { - Some(chain) => { - let mut new_fork = self.canon.drain(pos + 1..).collect::>(); - - let retracted: Vec = - new_fork.iter().map(|node| node.hash).collect(); - let enacted: Vec = chain.iter().map(|node| node.hash).collect(); - - std::mem::swap(chain, &mut new_fork); - - let mut node = new_fork - .last() - .map(|node| node.new_next(hash, vec![])) - .expect("No empty fork ever created!"); - - for invalidators in chain.iter().chain(new_fork.iter()) { - node.purge(&invalidators.changes); - } - - self.canon.extend(new_fork.into_iter()); - - self.canon.push(node); - - let mut state = CachingState::new( - InMemoryBackend::::default(), - self.shared.clone(), - Some(fork_at), - ); - - let height = pos as u64 + enacted.len() as u64 + 2; - state.cache.sync_cache( - &enacted[..], - &retracted[..], - vec![], - vec![], - Some(hash), - Some(height), - true, - ); - - state - }, - None => { - return Err(()) // no reorg without a fork atm! - }, - } - }, - Action::FinalizationReorg { fork_depth, depth } => { - let pos = self.canon.len() as isize - fork_depth as isize; - if pos < 0 || pos + 1 >= self.canon.len() as isize { - return Err(()) - } - let fork_at = self.canon[pos as usize].hash; - let pos = pos as usize; - - match self.forks.get_mut(&fork_at) { - Some(fork_chain) => { - let sync_pos = fork_chain.len() as isize - - fork_chain.len() as isize - depth as isize; - if sync_pos < 0 || sync_pos >= fork_chain.len() as isize { - return Err(()) - } - let sync_pos = sync_pos as usize; - - let mut new_fork = self.canon.drain(pos + 1..).collect::>(); - - let retracted: Vec = - new_fork.iter().map(|node| node.hash).collect(); - let enacted: Vec = fork_chain - .iter() - .take(sync_pos + 1) - .map(|node| node.hash) - .collect(); - - std::mem::swap(fork_chain, &mut new_fork); - - self.shared.write().sync(&retracted, &enacted); - - self.head_state( - self.canon - .last() - .expect("wasn't forking to emptiness so there should be one!") - .hash, - ) - }, - None => { - return Err(()) // no reorg to nothing pls! - }, - } - }, - }; - - Ok(state) - } - } - - #[test] - fn smoke() { - let key = H256::random()[..].to_vec(); - let h0 = H256::random(); - let h1a = H256::random(); - let h1b = H256::random(); - let h2a = H256::random(); - let h2b = H256::random(); - let h3a = H256::random(); - let h3b = H256::random(); - - let mut mutator = Mutator::new_empty(); - mutator - .mutate_static(Action::Next { hash: h0, changes: vec![(key.clone(), Some(vec![2]))] }); - mutator.mutate_static(Action::Next { hash: h1a, changes: vec![] }); - mutator.mutate_static(Action::Fork { - depth: 2, - hash: h1b, - changes: vec![(key.clone(), Some(vec![3]))], - }); - mutator.mutate_static(Action::Fork { - depth: 2, - hash: h2b, - changes: vec![(key.clone(), Some(vec![4]))], - }); - mutator - .mutate_static(Action::Next { hash: h2a, changes: vec![(key.clone(), Some(vec![5]))] }); - mutator.mutate_static(Action::Next { hash: h3a, changes: vec![] }); - - assert_eq!( - mutator.head_state(h3a).storage(&key).unwrap().expect("there should be a value"), - vec![5] - ); - assert!(mutator.head_state(h1a).storage(&key).unwrap().is_none()); - assert!(mutator.head_state(h2b).storage(&key).unwrap().is_none()); - assert!(mutator.head_state(h1b).storage(&key).unwrap().is_none()); - - mutator.mutate_static(Action::ReorgWithImport { depth: 4, hash: h3b }); - assert!(mutator.head_state(h3a).storage(&key).unwrap().is_none()); - } - - fn is_head_match(mutator: &Mutator) -> bool { - let head_state = mutator.canon_head_state(); - - for key in Mutator::key_permutations() { - match (head_state.storage(&key).unwrap(), mutator.head_storage_ref().get(&key)) { - (Some(x), Some(y)) => - if Some(&x) != y.as_ref() { - eprintln!("{:?} != {:?}", x, y); - return false - }, - (None, Some(_y)) => { - // TODO: cache miss is not tracked atm - }, - (Some(x), None) => { - eprintln!("{:?} != ", x); - return false - }, - _ => continue, - } - } - true - } - - fn is_canon_match(mutator: &Mutator) -> bool { - for node in mutator.canon.iter() { - let head_state = mutator.head_state(node.hash); - for key in Mutator::key_permutations() { - match (head_state.storage(&key).unwrap(), node.state.get(&key)) { - (Some(x), Some(y)) => - if Some(&x) != y.as_ref() { - eprintln!("at [{}]: {:?} != {:?}", node.hash, x, y); - return false - }, - (None, Some(_y)) => { - // cache miss is not tracked atm - }, - (Some(x), None) => { - eprintln!("at [{}]: {:?} != ", node.hash, x); - return false - }, - _ => continue, - } - } - } - true - } - - #[test] - fn reorg() { - let key = H256::random()[..].to_vec(); - let h0 = H256::random(); - let h1 = H256::random(); - let h2 = H256::random(); - let h1b = H256::random(); - let h2b = H256::random(); - - let mut mutator = Mutator::new_empty(); - mutator.mutate_static(Action::Next { hash: h0, changes: vec![] }); - mutator.mutate_static(Action::Next { hash: h1, changes: vec![] }); - mutator - .mutate_static(Action::Next { hash: h2, changes: vec![(key.clone(), Some(vec![2]))] }); - mutator.mutate_static(Action::Fork { - depth: 2, - hash: h1b, - changes: vec![(key.clone(), Some(vec![3]))], - }); - mutator.mutate_static(Action::ReorgWithImport { depth: 2, hash: h2b }); - - assert!(is_head_match(&mutator)) - } - - fn key(k: u8) -> Vec { - vec![k] - } - fn val(v: u8) -> Option> { - Some(vec![v]) - } - fn keyval(k: u8, v: u8) -> KeySet { - vec![(key(k), val(v))] - } - - #[test] - fn reorg2() { - let h0 = H256::random(); - let h1a = H256::random(); - let h1b = H256::random(); - let h2b = H256::random(); - let h2a = H256::random(); - let h3a = H256::random(); - - let mut mutator = Mutator::new_empty(); - mutator.mutate_static(Action::Next { hash: h0, changes: keyval(1, 1) }); - mutator.mutate_static(Action::Next { hash: h1a, changes: keyval(1, 1) }); - mutator.mutate_static(Action::Fork { depth: 2, hash: h1b, changes: keyval(2, 2) }); - - mutator.mutate_static(Action::Next { hash: h2a, changes: keyval(3, 3) }); - mutator.mutate_static(Action::Next { hash: h3a, changes: keyval(4, 4) }); - mutator.mutate_static(Action::ReorgWithImport { depth: 4, hash: h2b }); - - assert!(is_head_match(&mutator)) - } - - #[test] - fn fork2() { - let h1 = H256::random(); - let h2a = H256::random(); - let h2b = H256::random(); - let h3a = H256::random(); - let h3b = H256::random(); - - let mut mutator = Mutator::new_empty(); - mutator.mutate_static(Action::Next { hash: h1, changes: vec![] }); - mutator.mutate_static(Action::Next { hash: h2a, changes: vec![] }); - mutator.mutate_static(Action::Next { hash: h3a, changes: keyval(1, 1) }); - - mutator.mutate_static(Action::Fork { depth: 2, hash: h2b, changes: vec![] }); - mutator.mutate_static(Action::Fork { depth: 2, hash: h3b, changes: keyval(1, 2) }); - - assert!(is_head_match(&mutator)) - } - - #[test] - fn fork3() { - let h1 = H256::random(); - let h2a = H256::random(); - let h2b = H256::random(); - let h3a = H256::random(); - - let mut mutator = Mutator::new_empty(); - mutator.mutate_static(Action::Next { hash: h1, changes: keyval(1, 1) }); - mutator.mutate_static(Action::Next { hash: h2a, changes: keyval(2, 2) }); - mutator.mutate_static(Action::Next { hash: h3a, changes: keyval(3, 3) }); - - mutator.mutate_static(Action::Fork { depth: 2, hash: h2b, changes: keyval(1, 3) }); - - assert!(is_canon_match(&mutator)) - } - - quickcheck! { - fn head_complete(actions: Vec) -> TestResult { - let mut mutator = Mutator::new_empty(); - - for action in actions.into_iter() { - if let Err(_) = mutator.mutate(action) { - return TestResult::discard(); - } - } - - if mutator.canon_len() == 0 { - return TestResult::discard(); - } - - TestResult::from_bool(is_head_match(&mutator)) - } - - fn canon_complete(actions: Vec) -> TestResult { - let mut mutator = Mutator::new_empty(); - - for action in actions.into_iter() { - if let Err(_) = mutator.mutate(action) { - return TestResult::discard(); - } - } - - if mutator.canon_len() == 0 { - return TestResult::discard(); - } - - TestResult::from_bool(is_canon_match(&mutator)) - } - } -} From 419b840fa1f170a1c2027b63310549d1bf6d2ed0 Mon Sep 17 00:00:00 2001 From: Roman Useinov Date: Mon, 23 Jan 2023 15:32:09 +0100 Subject: [PATCH 316/715] [Fix] CountedMap::set now takes Counter into account (#13214) * [Fix] CountedMap::set now takes Counter into account * introduce tests for StorageMap --- .../support/src/storage/types/counted_map.rs | 55 ++++++++++++++++++- frame/support/src/storage/types/map.rs | 42 ++++++++++++++ 2 files changed, 96 insertions(+), 1 deletion(-) diff --git a/frame/support/src/storage/types/counted_map.rs b/frame/support/src/storage/types/counted_map.rs index 8c19434767f49..3361c4093dce0 100644 --- a/frame/support/src/storage/types/counted_map.rs +++ b/frame/support/src/storage/types/counted_map.rs @@ -134,7 +134,10 @@ where /// 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) + match QueryKind::from_query_to_optional_value(q) { + Some(v) => Self::insert(key, v), + None => Self::remove(key), + } } /// Swap the values of two keys. @@ -745,6 +748,22 @@ mod test { // Test initialize_counter. assert_eq!(A::initialize_counter(), 2); + + // Set non-existing. + A::set(30, 100); + + assert_eq!(A::contains_key(30), true); + assert_eq!(A::get(30), 100); + assert_eq!(A::try_get(30), Ok(100)); + assert_eq!(A::count(), 3); + + // Set existing. + A::set(30, 101); + + assert_eq!(A::contains_key(30), true); + assert_eq!(A::get(30), 101); + assert_eq!(A::try_get(30), Ok(101)); + assert_eq!(A::count(), 3); }) } @@ -976,6 +995,40 @@ mod test { // Test initialize_counter. assert_eq!(B::initialize_counter(), 2); + + // Set non-existing. + B::set(30, Some(100)); + + assert_eq!(B::contains_key(30), true); + assert_eq!(B::get(30), Some(100)); + assert_eq!(B::try_get(30), Ok(100)); + assert_eq!(B::count(), 3); + + // Set existing. + B::set(30, Some(101)); + + assert_eq!(B::contains_key(30), true); + assert_eq!(B::get(30), Some(101)); + assert_eq!(B::try_get(30), Ok(101)); + assert_eq!(B::count(), 3); + + // Unset existing. + B::set(30, None); + + assert_eq!(B::contains_key(30), false); + assert_eq!(B::get(30), None); + assert_eq!(B::try_get(30), Err(())); + + assert_eq!(B::count(), 2); + + // Unset non-existing. + B::set(31, None); + + assert_eq!(B::contains_key(31), false); + assert_eq!(B::get(31), None); + assert_eq!(B::try_get(31), Err(())); + + assert_eq!(B::count(), 2); }) } diff --git a/frame/support/src/storage/types/map.rs b/frame/support/src/storage/types/map.rs index 0f89e2378a55d..3e2b744d72f89 100644 --- a/frame/support/src/storage/types/map.rs +++ b/frame/support/src/storage/types/map.rs @@ -627,6 +627,48 @@ mod test { assert_eq!(AValueQueryWithAnOnEmpty::take(2), 97); assert_eq!(A::contains_key(2), false); + // Set non-existing. + B::set(30, 100); + + assert_eq!(B::contains_key(30), true); + assert_eq!(B::get(30), 100); + assert_eq!(B::try_get(30), Ok(100)); + + // Set existing. + B::set(30, 101); + + assert_eq!(B::contains_key(30), true); + assert_eq!(B::get(30), 101); + assert_eq!(B::try_get(30), Ok(101)); + + // Set non-existing. + A::set(30, Some(100)); + + assert_eq!(A::contains_key(30), true); + assert_eq!(A::get(30), Some(100)); + assert_eq!(A::try_get(30), Ok(100)); + + // Set existing. + A::set(30, Some(101)); + + assert_eq!(A::contains_key(30), true); + assert_eq!(A::get(30), Some(101)); + assert_eq!(A::try_get(30), Ok(101)); + + // Unset existing. + A::set(30, None); + + assert_eq!(A::contains_key(30), false); + assert_eq!(A::get(30), None); + assert_eq!(A::try_get(30), Err(())); + + // Unset non-existing. + A::set(31, None); + + assert_eq!(A::contains_key(31), false); + assert_eq!(A::get(31), None); + assert_eq!(A::try_get(31), Err(())); + B::insert(2, 10); assert_eq!(A::migrate_key::(2), Some(10)); assert_eq!(A::contains_key(2), true); From 52d72b396393696fefd2cb50cd6a48707675ee60 Mon Sep 17 00:00:00 2001 From: Muharem Ismailov Date: Mon, 23 Jan 2023 16:39:11 +0100 Subject: [PATCH 317/715] debug assert events at genesis (#13217) --- frame/system/src/lib.rs | 14 ++++++++++++++ frame/system/src/tests.rs | 3 ++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 32627896e86a0..4bd5cf629873b 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -1247,6 +1247,8 @@ impl Pallet { } /// Deposits an event into this block's event record. + /// + /// NOTE: Events not registered at the genesis block and quietly omitted. pub fn deposit_event(event: impl Into) { Self::deposit_event_indexed(&[], event.into()); } @@ -1256,6 +1258,8 @@ impl Pallet { /// /// This will update storage entries that correspond to the specified topics. /// It is expected that light-clients could subscribe to this topics. + /// + /// NOTE: Events not registered at the genesis block and quietly omitted. pub fn deposit_event_indexed(topics: &[T::Hash], event: T::RuntimeEvent) { let block_number = Self::block_number(); // Don't populate events on genesis. @@ -1445,8 +1449,14 @@ impl Pallet { /// NOTE: This should only be used in tests. Reading events from the runtime can have a large /// impact on the PoV size of a block. Users should use alternative and well bounded storage /// items for any behavior like this. + /// + /// NOTE: Events not registered at the genesis block and quietly omitted. #[cfg(any(feature = "std", feature = "runtime-benchmarks", test))] pub fn events() -> Vec> { + debug_assert!( + !Self::block_number().is_zero(), + "events not registered at the genesis block" + ); // Dereferencing the events here is fine since we are not in the // memory-restricted runtime. Self::read_events_no_consensus().map(|e| *e).collect() @@ -1501,6 +1511,8 @@ impl Pallet { } /// Assert the given `event` exists. + /// + /// NOTE: Events not registered at the genesis block and quietly omitted. #[cfg(any(feature = "std", feature = "runtime-benchmarks", test))] pub fn assert_has_event(event: T::RuntimeEvent) { let events = Self::events(); @@ -1511,6 +1523,8 @@ impl Pallet { } /// Assert the last event equal to the given `event`. + /// + /// NOTE: Events not registered at the genesis block and quietly omitted. #[cfg(any(feature = "std", feature = "runtime-benchmarks", test))] pub fn assert_last_event(event: T::RuntimeEvent) { let last_event = Self::events().last().expect("events expected").event.clone(); diff --git a/frame/system/src/tests.rs b/frame/system/src/tests.rs index c42131c450228..8223f66744151 100644 --- a/frame/system/src/tests.rs +++ b/frame/system/src/tests.rs @@ -627,7 +627,8 @@ fn events_not_emitted_during_genesis() { assert!(System::block_number().is_zero()); let mut account_data = AccountInfo::default(); System::on_created_account(Default::default(), &mut account_data); - assert!(System::events().is_empty()); + // No events registered at the genesis block + assert!(!System::read_events_no_consensus().any(|_| true)); // Events will be emitted starting on block 1 System::set_block_number(1); System::on_created_account(Default::default(), &mut account_data); From 9052607ad7a808e7a5e9e735460840a15d48aee7 Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Tue, 24 Jan 2023 13:52:01 +0100 Subject: [PATCH 318/715] BlockId removal: refactor: CallExecutor trait (#13173) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * BlockId removal: refactor: CallExecutor trait It changes the arguments of CallExecutor methods: - `call`, 'contextual_call', 'runtime_version', 'prove_execution' from: `BlockId` to: `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 * ".git/.scripts/commands/fmt/fmt.sh" Co-authored-by: Bastian Köcher Co-authored-by: command-bot <> --- client/api/src/call_executor.rs | 10 ++-- client/finality-grandpa/src/lib.rs | 6 +-- .../rpc-spec-v2/src/chain_head/chain_head.rs | 2 +- client/rpc/src/state/state_full.rs | 2 +- client/service/src/client/call_executor.rs | 54 +++++++++---------- client/service/src/client/client.rs | 11 ++-- client/service/src/client/wasm_substitutes.rs | 20 +++---- primitives/version/src/lib.rs | 6 +-- 8 files changed, 55 insertions(+), 56 deletions(-) diff --git a/client/api/src/call_executor.rs b/client/api/src/call_executor.rs index 7a42385010c68..74a2b8b8557c6 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 sc_executor::{RuntimeVersion, RuntimeVersionOf}; -use sp_runtime::{generic::BlockId, traits::Block as BlockT}; +use sp_runtime::traits::Block as BlockT; use sp_state_machine::{ExecutionStrategy, OverlayedChanges, StorageProof}; use std::cell::RefCell; @@ -54,7 +54,7 @@ pub trait CallExecutor: RuntimeVersionOf { /// No changes are made. fn call( &self, - id: &BlockId, + at_hash: B::Hash, method: &str, call_data: &[u8], strategy: ExecutionStrategy, @@ -67,7 +67,7 @@ pub trait CallExecutor: RuntimeVersionOf { /// of the execution context. fn contextual_call( &self, - at: &BlockId, + at_hash: B::Hash, method: &str, call_data: &[u8], changes: &RefCell, @@ -83,14 +83,14 @@ pub trait CallExecutor: RuntimeVersionOf { /// Extract RuntimeVersion of given block /// /// No changes are made. - fn runtime_version(&self, id: &BlockId) -> Result; + fn runtime_version(&self, at_hash: B::Hash) -> Result; /// Prove the execution of the given `method`. /// /// No changes are made. fn prove_execution( &self, - at: &BlockId, + at_hash: B::Hash, method: &str, call_data: &[u8], ) -> Result<(Vec, StorageProof), sp_blockchain::Error>; diff --git a/client/finality-grandpa/src/lib.rs b/client/finality-grandpa/src/lib.rs index 8758efef6037f..15d689e917d20 100644 --- a/client/finality-grandpa/src/lib.rs +++ b/client/finality-grandpa/src/lib.rs @@ -464,10 +464,10 @@ pub trait GenesisAuthoritySetProvider { fn get(&self) -> Result; } -impl GenesisAuthoritySetProvider - for Arc> +impl GenesisAuthoritySetProvider for Arc where E: CallExecutor, + Client: ExecutorProvider + HeaderBackend, { fn get(&self) -> Result { // This implementation uses the Grandpa runtime API instead of reading directly from the @@ -475,7 +475,7 @@ where // the chain, whereas the runtime API is backwards compatible. self.executor() .call( - &BlockId::Number(Zero::zero()), + self.expect_block_hash_from_id(&BlockId::Number(Zero::zero()))?, "GrandpaApi_grandpa_authorities", &[], ExecutionStrategy::NativeElseWasm, diff --git a/client/rpc-spec-v2/src/chain_head/chain_head.rs b/client/rpc-spec-v2/src/chain_head/chain_head.rs index c63d373e04f16..2a9cabaf2b310 100644 --- a/client/rpc-spec-v2/src/chain_head/chain_head.rs +++ b/client/rpc-spec-v2/src/chain_head/chain_head.rs @@ -744,7 +744,7 @@ where let res = client .executor() .call( - &BlockId::Hash(hash), + hash, &function, &call_parameters, client.execution_extensions().strategies().other, diff --git a/client/rpc/src/state/state_full.rs b/client/rpc/src/state/state_full.rs index d8fe39030aa82..58dfd9ea876a1 100644 --- a/client/rpc/src/state/state_full.rs +++ b/client/rpc/src/state/state_full.rs @@ -203,7 +203,7 @@ where self.client .executor() .call( - &BlockId::Hash(block), + block, &method, &call_data, self.client.execution_extensions().strategies().other, diff --git a/client/service/src/client/call_executor.rs b/client/service/src/client/call_executor.rs index 7ee19671dd688..7906d62240e0b 100644 --- a/client/service/src/client/call_executor.rs +++ b/client/service/src/client/call_executor.rs @@ -81,13 +81,13 @@ where fn check_override<'a>( &'a self, onchain_code: RuntimeCode<'a>, - id: &BlockId, + hash: ::Hash, ) -> sp_blockchain::Result<(RuntimeCode<'a>, RuntimeVersion)> where Block: BlockT, B: backend::Backend, { - let on_chain_version = self.on_chain_runtime_version(id)?; + let on_chain_version = self.on_chain_runtime_version(hash)?; let code_and_version = if let Some(d) = self.wasm_override.as_ref().as_ref().and_then(|o| { o.get( &on_chain_version.spec_version, @@ -95,18 +95,18 @@ where &on_chain_version.spec_name, ) }) { - log::debug!(target: "wasm_overrides", "using WASM override for block {}", id); + log::debug!(target: "wasm_overrides", "using WASM override for block {}", hash); d } else if let Some(s) = self.wasm_substitutes - .get(on_chain_version.spec_version, onchain_code.heap_pages, id) + .get(on_chain_version.spec_version, onchain_code.heap_pages, hash) { - log::debug!(target: "wasm_substitutes", "Using WASM substitute for block {:?}", id); + log::debug!(target: "wasm_substitutes", "Using WASM substitute for block {:?}", hash); s } else { log::debug!( target: "wasm_overrides", - "Neither WASM override nor substitute available for block {id}, using onchain code", + "Neither WASM override nor substitute available for block {hash}, using onchain code", ); (onchain_code, on_chain_version) }; @@ -115,14 +115,10 @@ where } /// Returns the on chain runtime version. - fn on_chain_runtime_version( - &self, - id: &BlockId, - ) -> sp_blockchain::Result { + fn on_chain_runtime_version(&self, hash: Block::Hash) -> sp_blockchain::Result { 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(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); @@ -166,21 +162,21 @@ where fn call( &self, - at: &BlockId, + at_hash: Block::Hash, method: &str, call_data: &[u8], strategy: ExecutionStrategy, ) -> 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 at_number = + self.backend.blockchain().expect_block_number_from_id(&BlockId::Hash(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)?; - let runtime_code = self.check_override(runtime_code, at)?.0; + let runtime_code = self.check_override(runtime_code, at_hash)?.0; let extensions = self.execution_extensions.extensions( at_hash, @@ -206,7 +202,7 @@ where fn contextual_call( &self, - at: &BlockId, + at_hash: Block::Hash, method: &str, call_data: &[u8], changes: &RefCell, @@ -216,8 +212,8 @@ where ) -> 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 at_number = + self.backend.blockchain().expect_block_number_from_id(&BlockId::Hash(at_hash))?; let state = self.backend.state_at(at_hash)?; let (execution_manager, extensions) = @@ -232,7 +228,7 @@ where let runtime_code = state_runtime_code.runtime_code().map_err(sp_blockchain::Error::RuntimeCode)?; - let runtime_code = self.check_override(runtime_code, at)?.0; + let runtime_code = self.check_override(runtime_code, at_hash)?.0; match recorder { Some(recorder) => { @@ -275,24 +271,23 @@ where .map_err(Into::into) } - fn runtime_version(&self, id: &BlockId) -> sp_blockchain::Result { - let at_hash = self.backend.blockchain().expect_block_hash_from_id(id)?; + fn runtime_version(&self, at_hash: Block::Hash) -> sp_blockchain::Result { 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)?; - self.check_override(runtime_code, id).map(|(_, v)| v) + self.check_override(runtime_code, at_hash).map(|(_, v)| v) } fn prove_execution( &self, - at: &BlockId, + at_hash: Block::Hash, method: &str, 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 at_number = + self.backend.blockchain().expect_block_number_from_id(&BlockId::Hash(at_hash))?; let state = self.backend.state_at(at_hash)?; let trie_backend = state.as_trie_backend(); @@ -300,7 +295,7 @@ where let state_runtime_code = sp_state_machine::backend::BackendRuntimeCode::new(trie_backend); let runtime_code = state_runtime_code.runtime_code().map_err(sp_blockchain::Error::RuntimeCode)?; - let runtime_code = self.check_override(runtime_code, at)?.0; + let runtime_code = self.check_override(runtime_code, at_hash)?.0; sp_state_machine::prove_execution_on_trie_backend( trie_backend, @@ -340,7 +335,7 @@ where E: CodeExecutor + RuntimeVersionOf + Clone + 'static, Block: BlockT, { - fn runtime_version(&self, at: &BlockId) -> Result { + fn runtime_version(&self, at: Block::Hash) -> Result { CallExecutor::runtime_version(self, at).map_err(|e| e.to_string()) } } @@ -359,6 +354,7 @@ where #[cfg(test)] mod tests { use super::*; + use backend::Backend; use sc_client_api::in_mem; use sc_executor::{NativeElseWasmExecutor, WasmExecutionMethod}; use sp_core::{ @@ -432,7 +428,7 @@ mod tests { }; let check = call_executor - .check_override(onchain_code, &BlockId::Number(Default::default())) + .check_override(onchain_code, backend.blockchain().info().genesis_hash) .expect("RuntimeCode override") .0; diff --git a/client/service/src/client/client.rs b/client/service/src/client/client.rs index d32baa671f54c..6a75fad628681 100644 --- a/client/service/src/client/client.rs +++ b/client/service/src/client/client.rs @@ -493,7 +493,8 @@ where /// Get the RuntimeVersion at a given block. pub fn runtime_version_at(&self, id: &BlockId) -> sp_blockchain::Result { - CallExecutor::runtime_version(&self.executor, id) + let hash = self.backend.blockchain().expect_block_hash_from_id(id)?; + CallExecutor::runtime_version(&self.executor, hash) } /// Apply a checked and validated block to an operation. If a justification is provided @@ -1241,7 +1242,7 @@ where method: &str, call_data: &[u8], ) -> sp_blockchain::Result<(Vec, StorageProof)> { - self.executor.prove_execution(&BlockId::Hash(hash), method, call_data) + self.executor.prove_execution(hash, method, call_data) } fn read_proof_collection( @@ -1726,9 +1727,10 @@ where &self, params: CallApiAtParams, ) -> Result, sp_api::ApiError> { + let at_hash = self.expect_block_hash_from_id(params.at)?; self.executor .contextual_call( - params.at, + at_hash, params.function, ¶ms.arguments, params.overlayed_changes, @@ -1740,7 +1742,8 @@ where } fn runtime_version_at(&self, at: &BlockId) -> Result { - CallExecutor::runtime_version(&self.executor, at).map_err(Into::into) + let hash = self.backend.blockchain().expect_block_hash_from_id(at)?; + CallExecutor::runtime_version(&self.executor, hash).map_err(Into::into) } fn state_at(&self, at: &BlockId) -> Result { diff --git a/client/service/src/client/wasm_substitutes.rs b/client/service/src/client/wasm_substitutes.rs index a7a3b2cbb2b35..ed931d3dae213 100644 --- a/client/service/src/client/wasm_substitutes.rs +++ b/client/service/src/client/wasm_substitutes.rs @@ -22,10 +22,7 @@ use sc_client_api::backend; use sc_executor::RuntimeVersionOf; use sp_blockchain::{HeaderBackend, Result}; use sp_core::traits::{FetchRuntimeCode, RuntimeCode, WrappedRuntimeCode}; -use sp_runtime::{ - generic::BlockId, - traits::{Block as BlockT, NumberFor}, -}; +use sp_runtime::traits::{Block as BlockT, NumberFor}; use sp_state_machine::BasicExternalities; use sp_version::RuntimeVersion; use std::{ @@ -54,10 +51,13 @@ impl WasmSubstitute { RuntimeCode { code_fetcher: self, hash: self.hash.clone(), heap_pages } } - /// 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(); + /// Returns `true` when the substitute matches for the given `hash`. + fn matches( + &self, + hash: ::Hash, + backend: &impl backend::Backend, + ) -> bool { + let requested_block_number = backend.blockchain().number(hash).ok().flatten(); Some(self.block_number) <= requested_block_number } @@ -147,10 +147,10 @@ where &self, spec: u32, pages: Option, - block_id: &BlockId, + hash: Block::Hash, ) -> Option<(RuntimeCode<'_>, RuntimeVersion)> { let s = self.substitutes.get(&spec)?; - s.matches(block_id, &*self.backend) + s.matches(hash, &*self.backend) .then(|| (s.runtime_code(pages), s.version.clone())) } diff --git a/primitives/version/src/lib.rs b/primitives/version/src/lib.rs index 0bd62f0bac5aa..37bb15afb29e6 100644 --- a/primitives/version/src/lib.rs +++ b/primitives/version/src/lib.rs @@ -48,7 +48,7 @@ pub use sp_runtime::{create_runtime_str, StateVersion}; pub use sp_std; #[cfg(feature = "std")] -use sp_runtime::{generic::BlockId, traits::Block as BlockT}; +use sp_runtime::traits::Block as BlockT; #[cfg(feature = "std")] pub mod embed; @@ -370,14 +370,14 @@ pub trait GetNativeVersion { #[cfg(feature = "std")] pub trait GetRuntimeVersionAt { /// Returns the version of runtime at the given block. - fn runtime_version(&self, at: &BlockId) -> Result; + fn runtime_version(&self, at: ::Hash) -> Result; } #[cfg(feature = "std")] impl, Block: BlockT> GetRuntimeVersionAt for std::sync::Arc { - fn runtime_version(&self, at: &BlockId) -> Result { + fn runtime_version(&self, at: ::Hash) -> Result { (&**self).runtime_version(at) } } From ca5a505b7085f7af51eb76c686cc80b55bf6d5ed Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Tue, 24 Jan 2023 14:26:04 +0100 Subject: [PATCH 319/715] service: storage monitor added (#13082) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * service: storage monitor added Storage monitor added. It uses `notify` create to get notifications about any changes to monitored path (which is database path). Notifications are consumed in essential task which terminates when available storage space drops below given threshold. Closes: #12399 * Cargo.lock updated * misspell * fs events throttling added * minor updates * filter out non mutating events * misspell * ".git/.scripts/commands/fmt/fmt.sh" * Update client/service/src/storage_monitor.rs Co-authored-by: Anton * storage-monitor crate added * cleanup: configuration + service builder * storage_monitor in custom service (wip) * copy-paste bad desc fixed * notify removed * storage_monitor added to node * fix for clippy * publish = false * Update bin/node/cli/src/command.rs Co-authored-by: Dmitry Markin * Apply suggestions from code review Co-authored-by: Bastian Köcher * crate name: storage-monitor -> sc-storage-monitor * error handling improved * Apply suggestions from code review Co-authored-by: Bastian Köcher * publish=false removed Co-authored-by: command-bot <> Co-authored-by: Anton Co-authored-by: Dmitry Markin Co-authored-by: Bastian Köcher --- Cargo.lock | 31 +++++ Cargo.toml | 1 + bin/node/cli/Cargo.toml | 2 + bin/node/cli/src/cli.rs | 4 + bin/node/cli/src/command.rs | 3 +- bin/node/cli/src/service.rs | 19 ++- client/cli/src/params/database_params.rs | 4 +- client/service/Cargo.toml | 1 + client/service/src/error.rs | 3 + client/storage-monitor/Cargo.toml | 20 +++ client/storage-monitor/src/lib.rs | 149 +++++++++++++++++++++++ 11 files changed, 227 insertions(+), 10 deletions(-) create mode 100644 client/storage-monitor/Cargo.toml create mode 100644 client/storage-monitor/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 08948ffbd970b..214c4f72c7d0d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4665,6 +4665,20 @@ dependencies = [ "memoffset 0.6.5", ] +[[package]] +name = "nix" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46a58d1d356c6597d08cde02c2f09d785b09e28711837b1ed667dc652c08a694" +dependencies = [ + "bitflags", + "cfg-if", + "libc", + "memoffset 0.7.1", + "pin-utils", + "static_assertions", +] + [[package]] name = "node-bench" version = "0.9.0-dev" @@ -4752,6 +4766,7 @@ dependencies = [ "sc-rpc", "sc-service", "sc-service-test", + "sc-storage-monitor", "sc-sync-state-rpc", "sc-sysinfo", "sc-telemetry", @@ -8895,6 +8910,7 @@ dependencies = [ "sc-rpc", "sc-rpc-server", "sc-rpc-spec-v2", + "sc-storage-monitor", "sc-sysinfo", "sc-telemetry", "sc-tracing", @@ -8973,6 +8989,21 @@ dependencies = [ "sp-core", ] +[[package]] +name = "sc-storage-monitor" +version = "0.1.0" +dependencies = [ + "clap 4.0.32", + "futures", + "log", + "nix 0.26.1", + "sc-client-db", + "sc-utils", + "sp-core", + "thiserror", + "tokio", +] + [[package]] name = "sc-sync-state-rpc" version = "0.10.0-dev" diff --git a/Cargo.toml b/Cargo.toml index 8f55d8e527ecd..f7eedadd1e8d7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -64,6 +64,7 @@ members = [ "client/service", "client/service/test", "client/state-db", + "client/storage-monitor", "client/sysinfo", "client/sync-state-rpc", "client/telemetry", diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index 4d9279b857eed..8a883ee0119ec 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -81,6 +81,7 @@ 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" } +sc-storage-monitor = { version = "0.1.0", path = "../../../client/storage-monitor" } # frame dependencies frame-system = { version = "4.0.0-dev", path = "../../../frame/system" } @@ -138,6 +139,7 @@ substrate-frame-cli = { version = "4.0.0-dev", optional = true, path = "../../.. 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" } +sc-storage-monitor = { version = "0.1.0", path = "../../../client/storage-monitor" } [features] default = ["cli"] diff --git a/bin/node/cli/src/cli.rs b/bin/node/cli/src/cli.rs index bb7f8a4c60aa9..7bea336c8e41a 100644 --- a/bin/node/cli/src/cli.rs +++ b/bin/node/cli/src/cli.rs @@ -36,6 +36,10 @@ pub struct Cli { /// telemetry, if telemetry is enabled. #[arg(long)] pub no_hardware_benchmarks: bool, + + #[allow(missing_docs)] + #[clap(flatten)] + pub storage_monitor: sc_storage_monitor::StorageMonitorParams, } /// Possible subcommands of the main binary. diff --git a/bin/node/cli/src/command.rs b/bin/node/cli/src/command.rs index fd464bbc914a5..2ed8a2c754018 100644 --- a/bin/node/cli/src/command.rs +++ b/bin/node/cli/src/command.rs @@ -87,8 +87,7 @@ pub fn run() -> Result<()> { None => { let runner = cli.create_runner(&cli.run)?; runner.run_node_until_exit(|config| async move { - service::new_full(config, cli.no_hardware_benchmarks) - .map_err(sc_cli::Error::Service) + service::new_full(config, cli).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 d77a333dfa220..e329087947c98 100644 --- a/bin/node/cli/src/service.rs +++ b/bin/node/cli/src/service.rs @@ -20,6 +20,7 @@ //! Service implementation. Specialized wrapper over substrate service. +use crate::Cli; use codec::Encode; use frame_benchmarking_cli::SUBSTRATE_REFERENCE_HARDWARE; use frame_system_rpc_runtime_api::AccountNonceApi; @@ -556,12 +557,18 @@ pub fn new_full_base( } /// Builds a new service for a full client. -pub fn new_full( - config: Configuration, - disable_hardware_benchmarks: bool, -) -> Result { - new_full_base(config, disable_hardware_benchmarks, |_, _| ()) - .map(|NewFullBase { task_manager, .. }| task_manager) +pub fn new_full(config: Configuration, cli: Cli) -> Result { + let database_source = config.database.clone(); + let task_manager = new_full_base(config, cli.no_hardware_benchmarks, |_, _| ()) + .map(|NewFullBase { task_manager, .. }| task_manager)?; + + sc_storage_monitor::StorageMonitorService::try_spawn( + cli.storage_monitor, + database_source, + &task_manager.spawn_essential_handle(), + )?; + + Ok(task_manager) } #[cfg(test)] diff --git a/client/cli/src/params/database_params.rs b/client/cli/src/params/database_params.rs index fdd3622580a6d..06a154fd60867 100644 --- a/client/cli/src/params/database_params.rs +++ b/client/cli/src/params/database_params.rs @@ -19,7 +19,7 @@ use crate::arg_enums::Database; use clap::Args; -/// Parameters for block import. +/// Parameters for database #[derive(Debug, Clone, PartialEq, Args)] pub struct DatabaseParams { /// Select database backend to use. @@ -32,7 +32,7 @@ pub struct DatabaseParams { } impl DatabaseParams { - /// Limit the memory the database cache can use. + /// Database backend pub fn database(&self) -> Option { self.database } diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index 6122895d2300c..b4ce3bbbb7f1c 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -73,6 +73,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" } sc-sysinfo = { version = "6.0.0-dev", path = "../sysinfo" } +sc-storage-monitor = { version = "0.1.0", path = "../storage-monitor" } tracing = "0.1.29" tracing-futures = { version = "0.2.4" } async-trait = "0.1.57" diff --git a/client/service/src/error.rs b/client/service/src/error.rs index 001a83922d776..ec2951193964c 100644 --- a/client/service/src/error.rs +++ b/client/service/src/error.rs @@ -48,6 +48,9 @@ pub enum Error { #[error(transparent)] Telemetry(#[from] sc_telemetry::Error), + #[error(transparent)] + Storage(#[from] sc_storage_monitor::Error), + #[error("Best chain selection strategy (SelectChain) is not provided.")] SelectChainRequired, diff --git a/client/storage-monitor/Cargo.toml b/client/storage-monitor/Cargo.toml new file mode 100644 index 0000000000000..2ba24f9e2e718 --- /dev/null +++ b/client/storage-monitor/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "sc-storage-monitor" +version = "0.1.0" +authors = ["Parity Technologies "] +edition = "2021" +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +repository = "https://github.com/paritytech/substrate" +description = "Storage monitor service for substrate" +homepage = "https://substrate.io" + +[dependencies] +clap = { version = "4.0.9", features = ["derive", "string"] } +futures = "0.3.21" +log = "0.4.17" +nix = { version = "0.26.1", features = ["fs"] } +sc-client-db = { version = "0.10.0-dev", default-features = false, path = "../db" } +sc-utils = { version = "4.0.0-dev", path = "../utils" } +sp-core = { version = "7.0.0", path = "../../primitives/core" } +tokio = "1.22.0" +thiserror = "1.0.30" diff --git a/client/storage-monitor/src/lib.rs b/client/storage-monitor/src/lib.rs new file mode 100644 index 0000000000000..39bd15675b350 --- /dev/null +++ b/client/storage-monitor/src/lib.rs @@ -0,0 +1,149 @@ +// 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 clap::Args; +use nix::{errno::Errno, sys::statvfs::statvfs}; +use sc_client_db::DatabaseSource; +use sp_core::traits::SpawnEssentialNamed; +use std::{ + path::{Path, PathBuf}, + time::Duration, +}; + +const LOG_TARGET: &str = "storage-monitor"; + +/// Error type used in this crate. +#[derive(Debug, thiserror::Error)] +pub enum Error { + #[error("IO Error")] + IOError(#[from] Errno), + #[error("Out of storage space: available {0}MB, required {1}MB")] + StorageOutOfSpace(u64, u64), +} + +/// Parameters used to create the storage monitor. +#[derive(Default, Debug, Clone, Args)] +pub struct StorageMonitorParams { + /// Required available space on database storage. If available space for DB storage drops below + /// the given threshold, node will be gracefully terminated. If `0` is given monitoring will be + /// disabled. + #[arg(long = "db-storage-threshold", value_name = "MB", default_value_t = 1000)] + pub threshold: u64, + + /// How often available space is polled. + #[arg(long = "db-storage-polling-period", value_name = "SECONDS", default_value_t = 5, value_parser = clap::value_parser!(u32).range(1..))] + pub polling_period: u32, +} + +/// Storage monitor service: checks the available space for the filesystem for fiven path. +pub struct StorageMonitorService { + /// watched path + path: PathBuf, + /// number of megabytes that shall be free on the filesystem for watched path + threshold: u64, + /// storage space polling period (seconds) + polling_period: u32, +} + +impl StorageMonitorService { + /// Creates new StorageMonitorService for given client config + pub fn try_spawn( + parameters: StorageMonitorParams, + database: DatabaseSource, + spawner: &impl SpawnEssentialNamed, + ) -> Result<(), Error> { + Ok(match (parameters.threshold, database.path()) { + (0, _) => { + log::info!( + target: LOG_TARGET, + "StorageMonitorService: threshold `0` given, storage monitoring disabled", + ); + }, + (_, None) => { + log::warn!( + target: LOG_TARGET, + "StorageMonitorService: no database path to observe", + ); + }, + (threshold, Some(path)) => { + log::debug!( + target: LOG_TARGET, + "Initializing StorageMonitorService for db path: {:?}", + path, + ); + + Self::check_free_space(&path, threshold)?; + + let storage_monitor_service = StorageMonitorService { + path: path.to_path_buf(), + threshold, + polling_period: parameters.polling_period, + }; + + spawner.spawn_essential( + "storage-monitor", + None, + Box::pin(storage_monitor_service.run()), + ); + }, + }) + } + + /// Main monitoring loop, intended to be spawned as essential task. Quits if free space drop + /// below threshold. + async fn run(self) { + loop { + tokio::time::sleep(Duration::from_secs(self.polling_period.into())).await; + if Self::check_free_space(&self.path, self.threshold).is_err() { + break + }; + } + } + + /// Returns free space in MB, or error if statvfs failed. + fn free_space(path: &Path) -> Result { + statvfs(path) + .map(|stats| stats.blocks_available() * stats.block_size() / 1_000_000) + .map_err(Error::from) + } + + /// Checks if the amount of free space for given `path` is above given `threshold`. + /// If it dropped below, error is returned. + /// System errors are silently ignored. + fn check_free_space(path: &Path, threshold: u64) -> Result<(), Error> { + match StorageMonitorService::free_space(path) { + Ok(available_space) => { + log::trace!( + target: LOG_TARGET, + "free: {available_space} , threshold: {threshold}.", + ); + + if available_space < threshold { + log::error!(target: LOG_TARGET, "Available space {available_space}MB for path `{}` dropped below threshold: {threshold}MB , terminating...", path.display()); + Err(Error::StorageOutOfSpace(available_space, threshold)) + } else { + Ok(()) + } + }, + Err(e) => { + log::error!(target: LOG_TARGET, "Could not read available space: {:?}.", e); + Err(e) + }, + } + } +} From 84af67204b422fc2b7d05db55cb75eb2d941246b Mon Sep 17 00:00:00 2001 From: Alejandro Martinez Andres <11448715+al3mart@users.noreply.github.com> Date: Tue, 24 Jan 2023 15:55:42 +0100 Subject: [PATCH 320/715] beefy: Add LOG_TARGET constant (#13222) * LOG_TARGET const * fmt --- client/beefy/src/aux_schema.rs | 6 +- client/beefy/src/communication/gossip.rs | 15 ++- .../incoming_requests_handler.rs | 8 +- .../src/communication/request_response/mod.rs | 2 + .../outgoing_requests_engine.rs | 41 +++--- client/beefy/src/import.rs | 11 +- client/beefy/src/keystore.rs | 9 +- client/beefy/src/lib.rs | 33 +++-- client/beefy/src/round.rs | 10 +- client/beefy/src/worker.rs | 120 ++++++++++-------- 10 files changed, 153 insertions(+), 102 deletions(-) diff --git a/client/beefy/src/aux_schema.rs b/client/beefy/src/aux_schema.rs index 67deee19b58b0..fafa9948c5444 100644 --- a/client/beefy/src/aux_schema.rs +++ b/client/beefy/src/aux_schema.rs @@ -18,7 +18,7 @@ //! Schema for BEEFY state persisted in the aux-db. -use crate::worker::PersistedState; +use crate::{worker::PersistedState, LOG_TARGET}; use codec::{Decode, Encode}; use log::{info, trace}; use sc_client_api::{backend::AuxStore, Backend}; @@ -31,7 +31,7 @@ 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); + info!(target: LOG_TARGET, "🥩 write aux schema version {:?}", CURRENT_VERSION); AuxStore::insert_aux(backend, &[(VERSION_KEY, CURRENT_VERSION.encode().as_slice())], &[]) } @@ -40,7 +40,7 @@ pub(crate) fn write_voter_state( backend: &B, state: &PersistedState, ) -> ClientResult<()> { - trace!(target: "beefy", "🥩 persisting {:?}", state); + trace!(target: LOG_TARGET, "🥩 persisting {:?}", state); backend.insert_aux(&[(WORKER_STATE, state.encode().as_slice())], &[]) } diff --git a/client/beefy/src/communication/gossip.rs b/client/beefy/src/communication/gossip.rs index bbc35ac8e526e..116a6286ed54d 100644 --- a/client/beefy/src/communication/gossip.rs +++ b/client/beefy/src/communication/gossip.rs @@ -28,7 +28,7 @@ use log::{debug, trace}; use parking_lot::{Mutex, RwLock}; use wasm_timer::Instant; -use crate::{communication::peers::KnownPeers, keystore::BeefyKeystore}; +use crate::{communication::peers::KnownPeers, keystore::BeefyKeystore, LOG_TARGET}; use beefy_primitives::{ crypto::{Public, Signature}, VoteMessage, @@ -122,7 +122,7 @@ where /// /// Noting round will start a live `round`. pub(crate) fn note_round(&self, round: NumberFor) { - debug!(target: "beefy", "🥩 About to note gossip round #{}", round); + debug!(target: LOG_TARGET, "🥩 About to note gossip round #{}", round); self.known_votes.write().insert(round); } @@ -130,7 +130,7 @@ where /// /// 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); + debug!(target: LOG_TARGET, "🥩 About to drop gossip round #{}", round); self.known_votes.write().conclude(round); } } @@ -174,7 +174,10 @@ where return ValidationResult::ProcessAndKeep(self.topic) } else { // TODO: report peer - debug!(target: "beefy", "🥩 Bad signature on message: {:?}, from: {:?}", msg, sender); + debug!( + target: LOG_TARGET, + "🥩 Bad signature on message: {:?}, from: {:?}", msg, sender + ); } } @@ -192,7 +195,7 @@ where let round = msg.commitment.block_number; let expired = !known_votes.is_live(&round); - trace!(target: "beefy", "🥩 Message for round #{} expired: {}", round, expired); + trace!(target: LOG_TARGET, "🥩 Message for round #{} expired: {}", round, expired); expired }) @@ -226,7 +229,7 @@ where let round = msg.commitment.block_number; let allowed = known_votes.is_live(&round); - trace!(target: "beefy", "🥩 Message for round #{} allowed: {}", round, allowed); + trace!(target: LOG_TARGET, "🥩 Message for round #{} allowed: {}", round, allowed); allowed }) 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 9f02b7162b54c..d3be73dc06a43 100644 --- a/client/beefy/src/communication/request_response/incoming_requests_handler.rs +++ b/client/beefy/src/communication/request_response/incoming_requests_handler.rs @@ -30,7 +30,7 @@ use sp_runtime::traits::Block; use std::{marker::PhantomData, sync::Arc}; use crate::communication::request_response::{ - on_demand_justifications_protocol_config, Error, JustificationRequest, + on_demand_justifications_protocol_config, Error, JustificationRequest, BEEFY_SYNC_LOG_TARGET, }; /// A request coming in, including a sender for sending responses. @@ -174,21 +174,21 @@ where /// Run [`BeefyJustifsRequestHandler`]. pub async fn run(mut self) { - trace!(target: "beefy::sync", "🥩 Running BeefyJustifsRequestHandler"); + trace!(target: BEEFY_SYNC_LOG_TARGET, "🥩 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", + target: BEEFY_SYNC_LOG_TARGET, "🥩 Handled BEEFY justification request from {:?}.", peer ) }, Err(e) => { // TODO (issue #12293): apply reputation changes here based on error type. debug!( - target: "beefy::sync", + target: BEEFY_SYNC_LOG_TARGET, "🥩 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 index c83bb9d57e91b..22a20c247086d 100644 --- a/client/beefy/src/communication/request_response/mod.rs +++ b/client/beefy/src/communication/request_response/mod.rs @@ -40,6 +40,8 @@ const JUSTIF_CHANNEL_SIZE: usize = 10; const MAX_RESPONSE_SIZE: u64 = 1024 * 1024; const JUSTIF_REQUEST_TIMEOUT: Duration = Duration::from_secs(3); +const BEEFY_SYNC_LOG_TARGET: &str = "beefy::sync"; + /// Get the configuration for the BEEFY justifications Request/response protocol. /// /// Returns a receiver for messages received on this protocol and the requested 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 00ee7610dd4f0..c7dc269b495cc 100644 --- a/client/beefy/src/communication/request_response/outgoing_requests_engine.rs +++ b/client/beefy/src/communication/request_response/outgoing_requests_engine.rs @@ -32,7 +32,7 @@ use sp_runtime::traits::{Block, NumberFor}; use std::{collections::VecDeque, result::Result, sync::Arc}; use crate::{ - communication::request_response::{Error, JustificationRequest}, + communication::request_response::{Error, JustificationRequest, BEEFY_SYNC_LOG_TARGET}, justification::{decode_and_verify_finality_proof, BeefyVersionedFinalityProof}, KnownPeers, }; @@ -96,10 +96,8 @@ impl OnDemandJustificationsEngine { fn request_from_peer(&mut self, peer: PeerId, req_info: RequestInfo) { debug!( - target: "beefy::sync", - "🥩 requesting justif #{:?} from peer {:?}", - req_info.block, - peer, + target: BEEFY_SYNC_LOG_TARGET, + "🥩 requesting justif #{:?} from peer {:?}", req_info.block, peer, ); let payload = JustificationRequest:: { begin: req_info.block }.encode(); @@ -132,7 +130,10 @@ impl OnDemandJustificationsEngine { if let Some(peer) = self.try_next_peer() { self.request_from_peer(peer, RequestInfo { block, active_set }); } else { - debug!(target: "beefy::sync", "🥩 no good peers to request justif #{:?} from", block); + debug!( + target: BEEFY_SYNC_LOG_TARGET, + "🥩 no good peers to request justif #{:?} from", block + ); } } @@ -141,8 +142,8 @@ impl OnDemandJustificationsEngine { match &self.state { State::AwaitingResponse(_, req_info, _) if req_info.block <= block => { debug!( - target: "beefy::sync", "🥩 cancel pending request for justification #{:?}", - req_info.block + target: BEEFY_SYNC_LOG_TARGET, + "🥩 cancel pending request for justification #{:?}", req_info.block ); self.state = State::Idle; }, @@ -159,17 +160,21 @@ impl OnDemandJustificationsEngine { response .map_err(|e| { debug!( - target: "beefy::sync", + target: BEEFY_SYNC_LOG_TARGET, "🥩 for on demand justification #{:?}, peer {:?} hung up: {:?}", - req_info.block, peer, e + req_info.block, + peer, + e ); Error::InvalidResponse })? .map_err(|e| { debug!( - target: "beefy::sync", + target: BEEFY_SYNC_LOG_TARGET, "🥩 for on demand justification #{:?}, peer {:?} error: {:?}", - req_info.block, peer, e + req_info.block, + peer, + e ); Error::InvalidResponse }) @@ -181,7 +186,7 @@ impl OnDemandJustificationsEngine { ) .map_err(|e| { debug!( - target: "beefy::sync", + target: BEEFY_SYNC_LOG_TARGET, "🥩 for on demand justification #{:?}, peer {:?} responded with invalid proof: {:?}", req_info.block, peer, e ); @@ -213,14 +218,16 @@ impl OnDemandJustificationsEngine { if let Some(peer) = self.try_next_peer() { self.request_from_peer(peer, req_info); } else { - warn!(target: "beefy::sync", "🥩 ran out of peers to request justif #{:?} from", block); + warn!( + target: BEEFY_SYNC_LOG_TARGET, + "🥩 ran out of peers to request justif #{:?} from", block + ); } }) .map(|proof| { debug!( - target: "beefy::sync", - "🥩 received valid on-demand justif #{:?} from {:?}", - block, peer + target: BEEFY_SYNC_LOG_TARGET, + "🥩 received valid on-demand justif #{:?} from {:?}", block, peer ); proof }) diff --git a/client/beefy/src/import.rs b/client/beefy/src/import.rs index 0ed50d0ec8c98..f0fe3bfa024dc 100644 --- a/client/beefy/src/import.rs +++ b/client/beefy/src/import.rs @@ -35,6 +35,7 @@ use sc_consensus::{BlockCheckParams, BlockImport, BlockImportParams, ImportResul use crate::{ communication::notification::BeefyVersionedFinalityProofSender, justification::{decode_and_verify_finality_proof, BeefyVersionedFinalityProof}, + LOG_TARGET, }; /// A block-import handler for BEEFY. @@ -138,16 +139,20 @@ where (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. - debug!(target: "beefy", "🥩 import justif {:?} for block number {:?}.", proof, number); + debug!( + target: LOG_TARGET, + "🥩 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 { debug!( - target: "beefy", + target: LOG_TARGET, "🥩 error decoding justification: {:?} for imported block {:?}", - encoded, number, + encoded, + number, ); } }, diff --git a/client/beefy/src/keystore.rs b/client/beefy/src/keystore.rs index 8d77410746e52..d1f5615a93701 100644 --- a/client/beefy/src/keystore.rs +++ b/client/beefy/src/keystore.rs @@ -28,7 +28,7 @@ use beefy_primitives::{ BeefyAuthorityId, KEY_TYPE, }; -use crate::error; +use crate::{error, LOG_TARGET}; /// A BEEFY specific keystore implemented as a `Newtype`. This is basically a /// wrapper around [`sp_keystore::SyncCryptoStore`] and allows to customize @@ -53,7 +53,12 @@ impl BeefyKeystore { .collect(); if public.len() > 1 { - warn!(target: "beefy", "🥩 Multiple private keys found for: {:?} ({})", public, public.len()); + warn!( + target: LOG_TARGET, + "🥩 Multiple private keys found for: {:?} ({})", + public, + public.len() + ); } public.get(0).cloned() diff --git a/client/beefy/src/lib.rs b/client/beefy/src/lib.rs index 5b6531822a0a1..185f3b1ad502e 100644 --- a/client/beefy/src/lib.rs +++ b/client/beefy/src/lib.rs @@ -75,6 +75,8 @@ pub use communication::beefy_protocol_name::{ #[cfg(test)] mod tests; +const LOG_TARGET: &str = "beefy"; + /// 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 @@ -252,11 +254,11 @@ where prometheus_registry.as_ref().map(metrics::Metrics::register).and_then( |result| match result { Ok(metrics) => { - debug!(target: "beefy", "🥩 Registered metrics"); + debug!(target: LOG_TARGET, "🥩 Registered metrics"); Some(metrics) }, Err(err) => { - debug!(target: "beefy", "🥩 Failed to register metrics: {:?}", err); + debug!(target: LOG_TARGET, "🥩 Failed to register metrics: {:?}", err); None }, }, @@ -276,7 +278,7 @@ where }) { Ok(state) => state, Err(e) => { - error!(target: "beefy", "Error: {:?}. Terminating.", e); + error!(target: LOG_TARGET, "Error: {:?}. Terminating.", e); return }, }; @@ -321,7 +323,7 @@ where 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); + info!(target: LOG_TARGET, "🥩 Loading BEEFY voter state from db: {:?}.", state); Ok(state) } else { initialize_voter_state(backend, runtime, best_grandpa, min_block_delta) @@ -357,7 +359,7 @@ where .map(|justifs| justifs.get(BEEFY_ENGINE_ID).is_some()) { info!( - target: "beefy", + target: LOG_TARGET, "🥩 Initialize BEEFY voter at last BEEFY finalized block: {:?}.", *header.number() ); @@ -382,10 +384,11 @@ where let genesis_set = expect_validator_set(runtime, BlockId::hash(header.hash())) .and_then(genesis_set_sanity_check)?; info!( - target: "beefy", + target: LOG_TARGET, "🥩 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, + genesis_num, + genesis_set, ); sessions.push_front(Rounds::new(genesis_num, genesis_set)); @@ -394,7 +397,11 @@ where } if let Some(active) = worker::find_authorities_change::(&header) { - info!(target: "beefy", "🥩 Marking block {:?} as BEEFY Mandatory.", *header.number()); + info!( + target: LOG_TARGET, + "🥩 Marking block {:?} as BEEFY Mandatory.", + *header.number() + ); sessions.push_front(Rounds::new(*header.number(), active)); } @@ -407,7 +414,7 @@ where .flatten() .ok_or_else(|| { let msg = format!("{}. Could not initialize BEEFY voter.", parent_hash); - error!(target: "beefy", "🥩 {}", msg); + error!(target: LOG_TARGET, "🥩 {}", msg); ClientError::Consensus(sp_consensus::Error::StateUnavailable(msg)) })?; @@ -432,7 +439,7 @@ where R: ProvideRuntimeApi, R::Api: BeefyApi, { - info!(target: "beefy", "🥩 BEEFY gadget waiting for BEEFY pallet to become available..."); + info!(target: LOG_TARGET, "🥩 BEEFY gadget waiting for BEEFY pallet to become available..."); loop { futures::select! { notif = finality.next() => { @@ -444,7 +451,7 @@ where 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 {:?}", + target: LOG_TARGET, "🥩 BEEFY pallet available: block {:?} validator set {:?}", notif.header.number(), active ); return Ok(notif.header) @@ -456,7 +463,7 @@ where } } let err_msg = "🥩 Gossip engine has unexpectedly terminated.".into(); - error!(target: "beefy", "{}", err_msg); + error!(target: LOG_TARGET, "{}", err_msg); Err(ClientError::Backend(err_msg)) } @@ -466,7 +473,7 @@ fn genesis_set_sanity_check( if active.id() == GENESIS_AUTHORITY_SET_ID { Ok(active) } else { - error!(target: "beefy", "🥩 Unexpected ID for genesis validator set {:?}.", active); + error!(target: LOG_TARGET, "🥩 Unexpected ID for genesis validator set {:?}.", active); Err(ClientError::Backend("BEEFY Genesis sanity check failed.".into())) } } diff --git a/client/beefy/src/round.rs b/client/beefy/src/round.rs index 48d3d087299d0..647d42110e926 100644 --- a/client/beefy/src/round.rs +++ b/client/beefy/src/round.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 crate::LOG_TARGET; + use beefy_primitives::{ crypto::{Public, Signature}, ValidatorSet, ValidatorSetId, @@ -122,11 +124,11 @@ where ) -> bool { 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); + debug!(target: LOG_TARGET, "🥩 received vote for old stale round {:?}, ignoring", num); false } else if !self.validators().iter().any(|id| vote.0 == *id) { debug!( - target: "beefy", + target: LOG_TARGET, "🥩 received vote {:?} from validator that is not in the validator set, ignoring", vote ); @@ -145,7 +147,7 @@ where .get(round) .map(|tracker| tracker.is_done(threshold(self.validator_set.len()))) .unwrap_or(false); - trace!(target: "beefy", "🥩 Round #{} done: {}", round.1, done); + trace!(target: LOG_TARGET, "🥩 Round #{} done: {}", round.1, done); if done { let signatures = self.rounds.remove(round)?.votes; @@ -165,7 +167,7 @@ where 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); + debug!(target: LOG_TARGET, "🥩 Concluded round #{}", round_num); } } diff --git a/client/beefy/src/worker.rs b/client/beefy/src/worker.rs index 8ec1403bb32d9..19ab52f520225 100644 --- a/client/beefy/src/worker.rs +++ b/client/beefy/src/worker.rs @@ -27,7 +27,7 @@ use crate::{ metric_inc, metric_set, metrics::Metrics, round::Rounds, - BeefyVoterLinks, + BeefyVoterLinks, LOG_TARGET, }; use beefy_primitives::{ crypto::{AuthorityId, Signature}, @@ -129,7 +129,7 @@ impl VoterOracle { min_block_delta: min_block_delta.max(1), }) } else { - error!(target: "beefy", "🥩 Invalid sessions queue: {:?}.", sessions); + error!(target: LOG_TARGET, "🥩 Invalid sessions queue: {:?}.", sessions); None } } @@ -227,7 +227,7 @@ impl VoterOracle { let rounds = if let Some(r) = self.sessions.front() { r } else { - debug!(target: "beefy", "🥩 No voting round started"); + debug!(target: LOG_TARGET, "🥩 No voting round started"); return None }; @@ -235,7 +235,7 @@ impl VoterOracle { let target = vote_target(best_grandpa, best_beefy, rounds.session_start(), self.min_block_delta); trace!( - target: "beefy", + target: LOG_TARGET, "🥩 best beefy: #{:?}, best finalized: #{:?}, current_vote_target: {:?}", best_beefy, best_grandpa, @@ -405,7 +405,7 @@ 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); + debug!(target: LOG_TARGET, "🥩 for block {:?} {}", block, msg); Err(Error::Keystore(msg)) } else { Ok(()) @@ -418,13 +418,14 @@ where validator_set: ValidatorSet, new_session_start: NumberFor, ) { - debug!(target: "beefy", "🥩 New active validator set: {:?}", validator_set); + debug!(target: LOG_TARGET, "🥩 New active validator set: {:?}", validator_set); // BEEFY should finalize a mandatory block during each session. if let Some(active_session) = self.active_rounds() { if !active_session.mandatory_done() { debug!( - target: "beefy", "🥩 New session {} while active session {} is still lagging.", + target: LOG_TARGET, + "🥩 New session {} while active session {} is still lagging.", validator_set.id(), active_session.validator_set_id(), ); @@ -432,7 +433,7 @@ where } } - if log_enabled!(target: "beefy", log::Level::Debug) { + if log_enabled!(target: LOG_TARGET, 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, &validator_set); } @@ -443,14 +444,15 @@ where .add_session(Rounds::new(new_session_start, validator_set)); metric_set!(self, beefy_validator_set_id, id); info!( - target: "beefy", + target: LOG_TARGET, "🥩 New Rounds for validator set id: {:?} with session_start {:?}", - id, new_session_start + id, + new_session_start ); } fn handle_finality_notification(&mut self, notification: &FinalityNotification) { - debug!(target: "beefy", "🥩 Finality notification: {:?}", notification); + debug!(target: LOG_TARGET, "🥩 Finality notification: {:?}", notification); let header = ¬ification.header; if *header.number() > self.best_grandpa_block() { @@ -491,14 +493,17 @@ where false, )?, RoundAction::Enqueue => { - debug!(target: "beefy", "🥩 Buffer vote for round: {:?}.", block_num); + debug!(target: LOG_TARGET, "🥩 Buffer vote for round: {:?}.", block_num); 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) + warn!( + target: LOG_TARGET, + "🥩 Buffer vote dropped for round: {:?}", block_num + ) } } else { - warn!(target: "beefy", "🥩 Buffer vote dropped for round: {:?}.", block_num); + warn!(target: LOG_TARGET, "🥩 Buffer vote dropped for round: {:?}.", block_num); } }, RoundAction::Drop => (), @@ -520,15 +525,18 @@ where 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); + debug!(target: LOG_TARGET, "🥩 Process justification for round: {:?}.", block_num); self.finalize(justification)? }, RoundAction::Enqueue => { - debug!(target: "beefy", "🥩 Buffer justification for round: {:?}.", block_num); + debug!(target: LOG_TARGET, "🥩 Buffer justification for round: {:?}.", block_num); if self.pending_justifications.len() < MAX_BUFFERED_JUSTIFICATIONS { self.pending_justifications.entry(block_num).or_insert(justification); } else { - warn!(target: "beefy", "🥩 Buffer justification dropped for round: {:?}.", block_num); + warn!( + target: LOG_TARGET, + "🥩 Buffer justification dropped for round: {:?}.", block_num + ); } }, RoundAction::Drop => (), @@ -566,7 +574,10 @@ where metric_set!(self, beefy_round_concluded, block_num); - info!(target: "beefy", "🥩 Round #{} concluded, finality_proof: {:?}.", round.1, finality_proof); + info!( + target: LOG_TARGET, + "🥩 Round #{} concluded, finality_proof: {:?}.", round.1, finality_proof + ); // We created the `finality_proof` and know to be valid. // New state is persisted after finalization. @@ -627,7 +638,10 @@ where self.backend .append_justification(hash, (BEEFY_ENGINE_ID, finality_proof.encode())) }) { - error!(target: "beefy", "🥩 Error {:?} on appending justification: {:?}", e, finality_proof); + error!( + target: LOG_TARGET, + "🥩 Error {:?} on appending justification: {:?}", e, finality_proof + ); } self.links @@ -635,7 +649,7 @@ where .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); + debug!(target: LOG_TARGET, "🥩 Can't set best beefy to older: {}", block_num); } Ok(()) } @@ -666,9 +680,9 @@ where if !self.pending_justifications.is_empty() { let justifs_to_handle = to_process_for(&mut self.pending_justifications, interval, _ph); for (num, justification) in justifs_to_handle.into_iter() { - debug!(target: "beefy", "🥩 Handle buffered justification for: {:?}.", num); + debug!(target: LOG_TARGET, "🥩 Handle buffered justification for: {:?}.", num); if let Err(err) = self.finalize(justification) { - error!(target: "beefy", "🥩 Error finalizing block: {}", err); + error!(target: LOG_TARGET, "🥩 Error finalizing block: {}", err); } } // Possibly new interval after processing justifications. @@ -679,14 +693,14 @@ where 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); + debug!(target: LOG_TARGET, "🥩 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); + error!(target: LOG_TARGET, "🥩 Error handling buffered vote: {}", err); }; } } @@ -711,7 +725,7 @@ where /// /// Also handle this self vote by calling `self.handle_vote()` for it. fn do_vote(&mut self, target_number: NumberFor) -> Result<(), Error> { - debug!(target: "beefy", "🥩 Try voting on {}", target_number); + debug!(target: LOG_TARGET, "🥩 Try voting on {}", target_number); // Most of the time we get here, `target` is actually `best_grandpa`, // avoid getting header from backend in that case. @@ -743,7 +757,7 @@ where 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); + warn!(target: LOG_TARGET, "🥩 No MMR root digest found for: {:?}", target_hash); return Ok(()) }; @@ -753,16 +767,22 @@ where .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); + debug!( + target: LOG_TARGET, + "🥩 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); + debug!(target: LOG_TARGET, "🥩 Local authority id: {:?}", id); id } else { - debug!(target: "beefy", "🥩 Missing validator id - can't vote for: {:?}", target_hash); + debug!( + target: LOG_TARGET, + "🥩 Missing validator id - can't vote for: {:?}", target_hash + ); return Ok(()) }; @@ -772,13 +792,13 @@ where let signature = match self.key_store.sign(&authority_id, &encoded_commitment) { Ok(sig) => sig, Err(err) => { - warn!(target: "beefy", "🥩 Error signing commitment: {:?}", err); + warn!(target: LOG_TARGET, "🥩 Error signing commitment: {:?}", err); return Ok(()) }, }; trace!( - target: "beefy", + target: LOG_TARGET, "🥩 Produced signature using {:?}, is_valid: {:?}", authority_id, BeefyKeystore::verify(&authority_id, &signature, &encoded_commitment) @@ -790,14 +810,14 @@ where metric_inc!(self, beefy_votes_sent); - debug!(target: "beefy", "🥩 Sent vote message: {:?}", message); + debug!(target: LOG_TARGET, "🥩 Sent vote message: {:?}", message); 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); + error!(target: LOG_TARGET, "🥩 Error handling self vote: {}", err); } self.gossip_engine.gossip_message(topic::(), encoded_message, false); @@ -808,14 +828,14 @@ where fn process_new_state(&mut self) { // Handle pending justifications and/or votes for now GRANDPA finalized blocks. if let Err(err) = self.try_pending_justif_and_votes() { - debug!(target: "beefy", "🥩 {}", err); + debug!(target: LOG_TARGET, "🥩 {}", 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); + debug!(target: LOG_TARGET, "🥩 {}", err); } // If the current target is a mandatory block, // make sure there's also an on-demand justification request out for it. @@ -835,13 +855,17 @@ where mut block_import_justif: Fuse>>, mut finality_notifications: Fuse>, ) { - info!(target: "beefy", "🥩 run BEEFY worker, best grandpa: #{:?}.", self.best_grandpa_block()); + info!( + target: LOG_TARGET, + "🥩 run BEEFY worker, best grandpa: #{:?}.", + self.best_grandpa_block() + ); let mut votes = Box::pin( self.gossip_engine .messages_for(topic::()) .filter_map(|notification| async move { - trace!(target: "beefy", "🥩 Got vote message: {:?}", notification); + trace!(target: LOG_TARGET, "🥩 Got vote message: {:?}", notification); VoteMessage::, AuthorityId, Signature>::decode( &mut ¬ification.message[..], @@ -863,7 +887,7 @@ where // Use `select_biased!` to prioritize order below. // Make sure to pump gossip engine. _ = gossip_engine => { - error!(target: "beefy", "🥩 Gossip engine has terminated, closing worker."); + error!(target: LOG_TARGET, "🥩 Gossip engine has terminated, closing worker."); return; }, // Process finality notifications first since these drive the voter. @@ -871,7 +895,7 @@ where if let Some(notification) = notification { self.handle_finality_notification(¬ification); } else { - error!(target: "beefy", "🥩 Finality stream terminated, closing worker."); + error!(target: LOG_TARGET, "🥩 Finality stream terminated, closing worker."); return; } }, @@ -879,7 +903,7 @@ where 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); + debug!(target: LOG_TARGET, "🥩 {}", err); } } }, @@ -888,10 +912,10 @@ where // 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); + debug!(target: LOG_TARGET, "🥩 {}", err); } } else { - error!(target: "beefy", "🥩 Block import stream terminated, closing worker."); + error!(target: LOG_TARGET, "🥩 Block import stream terminated, closing worker."); return; } }, @@ -900,10 +924,10 @@ where if let Some(vote) = vote { // 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); + debug!(target: LOG_TARGET, "🥩 {}", err); } } else { - error!(target: "beefy", "🥩 Votes gossiping stream terminated, closing worker."); + error!(target: LOG_TARGET, "🥩 Votes gossiping stream terminated, closing worker."); return; } }, @@ -937,18 +961,14 @@ where // if the mandatory block (session_start) does not have a beefy justification yet, // we vote on it let target = if best_beefy < session_start { - debug!( - target: "beefy", - "🥩 vote target - mandatory block: #{:?}", - session_start, - ); + debug!(target: LOG_TARGET, "🥩 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", + target: LOG_TARGET, "🥩 vote target - diff: {:?}, next_power_of_two: {:?}, target block: #{:?}", diff, diff.next_power_of_two(), From 09de7b41599add51cf27eca8f1bc4c50ed8e9453 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 24 Jan 2023 12:21:52 -0600 Subject: [PATCH 321/715] Upgrade wasm-opt to 0.111.0 (#13038) --- Cargo.lock | 12 ++++++------ utils/wasm-builder/Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 214c4f72c7d0d..5d34dd81e16eb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11804,9 +11804,9 @@ dependencies = [ [[package]] name = "wasm-opt" -version = "0.110.2" +version = "0.111.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b68e8037b4daf711393f4be2056246d12d975651b14d581520ad5d1f19219cec" +checksum = "84a303793cbc01fb96551badfc7367db6007396bba6bac97936b3c8b6f7fdb41" dependencies = [ "anyhow", "libc", @@ -11820,9 +11820,9 @@ dependencies = [ [[package]] name = "wasm-opt-cxx-sys" -version = "0.110.2" +version = "0.111.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91adbad477e97bba3fbd21dd7bfb594e7ad5ceb9169ab1c93ab9cb0ada636b6f" +checksum = "d9c9deb56f8a9f2ec177b3bd642a8205621835944ed5da55f2388ef216aca5a4" dependencies = [ "anyhow", "cxx", @@ -11832,9 +11832,9 @@ dependencies = [ [[package]] name = "wasm-opt-sys" -version = "0.110.2" +version = "0.111.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec4fa5a322a4e6ac22fd141f498d56afbdbf9df5debeac32380d2dcaa3e06941" +checksum = "4432e28b542738a9776cedf92e8a99d8991c7b4667ee2c7ccddfb479dd2856a7" dependencies = [ "anyhow", "cc", diff --git a/utils/wasm-builder/Cargo.toml b/utils/wasm-builder/Cargo.toml index 46c5929969fbb..84693f5eec049 100644 --- a/utils/wasm-builder/Cargo.toml +++ b/utils/wasm-builder/Cargo.toml @@ -22,4 +22,4 @@ toml = "0.5.4" walkdir = "2.3.2" 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 +wasm-opt = "0.111" \ No newline at end of file From 5749760b7d95bd82599be2b1a23e129dcfa5be28 Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Tue, 24 Jan 2023 20:22:47 +0100 Subject: [PATCH 322/715] storage-monitor: statvfs arithmetic bug fixed (#13234) --- client/storage-monitor/src/lib.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/client/storage-monitor/src/lib.rs b/client/storage-monitor/src/lib.rs index 39bd15675b350..162fcfe34a52b 100644 --- a/client/storage-monitor/src/lib.rs +++ b/client/storage-monitor/src/lib.rs @@ -118,7 +118,10 @@ impl StorageMonitorService { /// Returns free space in MB, or error if statvfs failed. fn free_space(path: &Path) -> Result { statvfs(path) - .map(|stats| stats.blocks_available() * stats.block_size() / 1_000_000) + .map(|stats| { + u64::from(stats.blocks_available()).saturating_mul(u64::from(stats.block_size())) / + 1_000_000 + }) .map_err(Error::from) } From d2afb5d97bc0ddad72b02b1e2e6ea8c56835bb6a Mon Sep 17 00:00:00 2001 From: Arkadiy Paronyan Date: Tue, 24 Jan 2023 23:10:21 +0100 Subject: [PATCH 323/715] Bump parity-db (#13226) --- Cargo.lock | 4 ++-- bin/node/bench/Cargo.toml | 2 +- client/db/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5d34dd81e16eb..53e5d4882b9dd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6689,9 +6689,9 @@ dependencies = [ [[package]] name = "parity-db" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a7511a0bec4a336b5929999d02b560d2439c993cccf98c26481484e811adc43" +checksum = "dd684a725651d9588ef21f140a328b6b4f64e646b2e931f3e6f14f75eedf9980" dependencies = [ "blake2", "crc32fast", diff --git a/bin/node/bench/Cargo.toml b/bin/node/bench/Cargo.toml index 9732faf6e10bd..0097b51ab008e 100644 --- a/bin/node/bench/Cargo.toml +++ b/bin/node/bench/Cargo.toml @@ -38,7 +38,7 @@ tempfile = "3.1.0" fs_extra = "1" rand = { version = "0.8.5", features = ["small_rng"] } lazy_static = "1.4.0" -parity-db = "0.4.2" +parity-db = "0.4.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.21", features = ["thread-pool"] } diff --git a/client/db/Cargo.toml b/client/db/Cargo.toml index 028af5d6e45c9..a9f5e28c73159 100644 --- a/client/db/Cargo.toml +++ b/client/db/Cargo.toml @@ -22,7 +22,7 @@ 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" +parity-db = "0.4.3" 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 1314eeca18c2b1a3094a6d8fca378da1b0c386a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 25 Jan 2023 12:57:01 +0100 Subject: [PATCH 324/715] pallet-assets: Rename `total_supply` to `amount` (#13229) * pallet-assets: Rename `total_supply` to `amount` We are actually passing the `amount` on assets being minted and not the total supply. Closes: https://github.com/paritytech/substrate/issues/13210 * ".git/.scripts/commands/fmt/fmt.sh" * Fix compilation * FMT Co-authored-by: command-bot <> --- frame/assets/src/benchmarking.rs | 2 +- frame/assets/src/functions.rs | 15 ++++++--------- frame/assets/src/lib.rs | 8 +++----- 3 files changed, 10 insertions(+), 15 deletions(-) diff --git a/frame/assets/src/benchmarking.rs b/frame/assets/src/benchmarking.rs index ede5b4e77fac6..235d1d9374504 100644 --- a/frame/assets/src/benchmarking.rs +++ b/frame/assets/src/benchmarking.rs @@ -220,7 +220,7 @@ benchmarks_instance_pallet! { let amount = T::Balance::from(100u32); }: _(SystemOrigin::Signed(caller.clone()), asset_id, caller_lookup, amount) verify { - assert_last_event::(Event::Issued { asset_id: asset_id.into(), owner: caller, total_supply: amount }.into()); + assert_last_event::(Event::Issued { asset_id: asset_id.into(), owner: caller, amount }.into()); } burn { diff --git a/frame/assets/src/functions.rs b/frame/assets/src/functions.rs index 2cdf2d7c4c8f6..b540f02b87c82 100644 --- a/frame/assets/src/functions.rs +++ b/frame/assets/src/functions.rs @@ -354,18 +354,15 @@ impl, I: 'static> Pallet { if let Some(check_issuer) = maybe_check_issuer { ensure!(check_issuer == details.issuer, Error::::NoPermission); } - debug_assert!( - T::Balance::max_value() - details.supply >= amount, - "checked in prep; qed" - ); + debug_assert!(details.supply.checked_add(&amount).is_some(), "checked in prep; qed"); + details.supply = details.supply.saturating_add(amount); + Ok(()) })?; - Self::deposit_event(Event::Issued { - asset_id: id, - owner: beneficiary.clone(), - total_supply: amount, - }); + + Self::deposit_event(Event::Issued { asset_id: id, owner: beneficiary.clone(), amount }); + Ok(()) } diff --git a/frame/assets/src/lib.rs b/frame/assets/src/lib.rs index 93e416c3bec4c..c2480a20636b0 100644 --- a/frame/assets/src/lib.rs +++ b/frame/assets/src/lib.rs @@ -151,9 +151,7 @@ pub use types::*; use scale_info::TypeInfo; use sp_runtime::{ - traits::{ - AtLeast32BitUnsigned, Bounded, CheckedAdd, CheckedSub, Saturating, StaticLookup, Zero, - }, + traits::{AtLeast32BitUnsigned, CheckedAdd, CheckedSub, Saturating, StaticLookup, Zero}, ArithmeticError, TokenError, }; use sp_std::{borrow::Borrow, prelude::*}; @@ -427,7 +425,7 @@ pub mod pallet { *amount, |details| -> DispatchResult { debug_assert!( - T::Balance::max_value() - details.supply >= *amount, + details.supply.checked_add(&amount).is_some(), "checked in prep; qed" ); details.supply = details.supply.saturating_add(*amount); @@ -445,7 +443,7 @@ pub mod pallet { /// 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 }, + Issued { asset_id: T::AssetId, owner: T::AccountId, amount: T::Balance }, /// Some assets were transferred. Transferred { asset_id: T::AssetId, From e3938747cdc201a6c3fbf920d0e983e2b7be01c7 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Wed, 25 Jan 2023 12:57:59 +0100 Subject: [PATCH 325/715] Babe: bad epoch index with skipped epochs and warp sync (#13135) * Detect and correct epoch-index for skipped epochs * Code refactory * Epoch index should be also be fixed for secondary claims with VRF * Fix typo * Make clippy happy * Fix typo * Trigger pipeline --- client/consensus/babe/src/authorship.rs | 21 +++- client/consensus/babe/src/lib.rs | 75 +++++++----- client/consensus/babe/src/tests.rs | 141 +++++++++++++++++----- client/consensus/babe/src/verification.rs | 17 ++- 4 files changed, 187 insertions(+), 67 deletions(-) diff --git a/client/consensus/babe/src/authorship.rs b/client/consensus/babe/src/authorship.rs index b39153faa6d1a..3a92aa5c6b224 100644 --- a/client/consensus/babe/src/authorship.rs +++ b/client/consensus/babe/src/authorship.rs @@ -20,6 +20,7 @@ use super::Epoch; use codec::Encode; +use sc_consensus_epochs::Epoch as EpochT; use schnorrkel::{keys::PublicKey, vrf::VRFInOut}; use sp_application_crypto::AppKey; use sp_consensus_babe::{ @@ -135,18 +136,23 @@ fn claim_secondary_slot( keystore: &SyncCryptoStorePtr, author_secondary_vrf: bool, ) -> Option<(PreDigest, AuthorityId)> { - let Epoch { authorities, randomness, epoch_index, .. } = epoch; + let Epoch { authorities, randomness, mut epoch_index, .. } = epoch; if authorities.is_empty() { return None } + if epoch.end_slot() <= slot { + // Slot doesn't strictly belong to the epoch, create a clone with fixed values. + epoch_index = epoch.clone_for_slot(slot).epoch_index; + } + let expected_author = secondary_slot_author(slot, authorities, *randomness)?; for (authority_id, authority_index) in keys { if authority_id == expected_author { let pre_digest = if author_secondary_vrf { - let transcript_data = make_transcript_data(randomness, slot, *epoch_index); + let transcript_data = make_transcript_data(randomness, slot, epoch_index); let result = SyncCryptoStore::sr25519_vrf_sign( &**keystore, AuthorityId::ID, @@ -238,11 +244,16 @@ fn claim_primary_slot( keystore: &SyncCryptoStorePtr, keys: &[(AuthorityId, usize)], ) -> Option<(PreDigest, AuthorityId)> { - let Epoch { authorities, randomness, epoch_index, .. } = epoch; + let Epoch { authorities, randomness, mut epoch_index, .. } = epoch; + + if epoch.end_slot() <= slot { + // Slot doesn't strictly belong to the epoch, create a clone with fixed values. + epoch_index = epoch.clone_for_slot(slot).epoch_index; + } 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); + let transcript = make_transcript(randomness, slot, epoch_index); + let transcript_data = make_transcript_data(randomness, slot, epoch_index); let result = SyncCryptoStore::sr25519_vrf_sign( &**keystore, AuthorityId::ID, diff --git a/client/consensus/babe/src/lib.rs b/client/consensus/babe/src/lib.rs index c9e171dbed887..5ba523665b4ef 100644 --- a/client/consensus/babe/src/lib.rs +++ b/client/consensus/babe/src/lib.rs @@ -209,8 +209,9 @@ 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. + /// Create the genesis epoch (epoch #0). + /// + /// This is defined to start at the slot of the first block, so that has to be provided. pub fn genesis(genesis_config: &BabeConfiguration, slot: Slot) -> Epoch { Epoch { epoch_index: 0, @@ -224,6 +225,38 @@ impl Epoch { }, } } + + /// Clone and tweak epoch information to refer to the specified slot. + /// + /// All the information which depends on the slot value is recomputed and assigned + /// to the returned epoch instance. + /// + /// The `slot` must be greater than or equal the original epoch start slot, + /// if is less this operation is equivalent to a simple clone. + pub fn clone_for_slot(&self, slot: Slot) -> Epoch { + let mut epoch = self.clone(); + + let skipped_epochs = *slot.saturating_sub(self.start_slot) / self.duration; + + let epoch_index = epoch.epoch_index.checked_add(skipped_epochs).expect( + "epoch number is u64; it should be strictly smaller than number of slots; \ + slots relate in some way to wall clock time; \ + if u64 is not enough we should crash for safety; qed.", + ); + + let start_slot = skipped_epochs + .checked_mul(epoch.duration) + .and_then(|skipped_slots| epoch.start_slot.checked_add(skipped_slots)) + .expect( + "slot number is u64; it should relate in some way to wall clock time; \ + if u64 is not enough we should crash for safety; qed.", + ); + + epoch.epoch_index = epoch_index; + epoch.start_slot = Slot::from(start_slot); + + epoch + } } /// Errors encountered by the babe authorship task. @@ -1540,45 +1573,27 @@ where }; if viable_epoch.as_ref().end_slot() <= slot { - // some epochs must have been skipped as our current slot - // fits outside the current epoch. we will figure out - // which epoch it belongs to and we will re-use the same - // data for that epoch - let mut epoch_data = viable_epoch.as_mut(); - let skipped_epochs = - *slot.saturating_sub(epoch_data.start_slot) / epoch_data.duration; - - // NOTE: notice that we are only updating a local copy of the `Epoch`, this + // Some epochs must have been skipped as our current slot fits outside the + // current epoch. We will figure out which epoch it belongs to and we will + // re-use the same data for that epoch. + // Notice that we are only updating a local copy of the `Epoch`, this // makes it so that when we insert the next epoch into `EpochChanges` below // (after incrementing it), it will use the correct epoch index and start slot. - // we do not update the original epoch that will be re-used because there might + // We do not update the original epoch that will be re-used because there might // be other forks (that we haven't imported) where the epoch isn't skipped, and - // to import those forks we want to keep the original epoch data. not updating + // to import those forks we want to keep the original epoch data. Not updating // the original epoch works because when we search the tree for which epoch to // use for a given slot, we will search in-depth with the predicate // `epoch.start_slot <= slot` which will still match correctly without updating // `start_slot` to the correct value as below. - let epoch_index = epoch_data.epoch_index.checked_add(skipped_epochs).expect( - "epoch number is u64; it should be strictly smaller than number of slots; \ - slots relate in some way to wall clock time; \ - if u64 is not enough we should crash for safety; qed.", - ); - - let start_slot = skipped_epochs - .checked_mul(epoch_data.duration) - .and_then(|skipped_slots| epoch_data.start_slot.checked_add(skipped_slots)) - .expect( - "slot number is u64; it should relate in some way to wall clock time; \ - if u64 is not enough we should crash for safety; qed.", - ); + let epoch = viable_epoch.as_mut(); + let prev_index = epoch.epoch_index; + *epoch = epoch.clone_for_slot(slot); warn!( target: LOG_TARGET, - "👶 Epoch(s) skipped: from {} to {}", epoch_data.epoch_index, epoch_index, + "👶 Epoch(s) skipped: from {} to {}", prev_index, epoch.epoch_index, ); - - epoch_data.epoch_index = epoch_index; - epoch_data.start_slot = Slot::from(start_slot); } log!( diff --git a/client/consensus/babe/src/tests.rs b/client/consensus/babe/src/tests.rs index 304bc9fc22ca9..0dd0b59dd69c0 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 log::debug; use rand_chacha::{ rand_core::{RngCore, SeedableRng}, ChaChaRng, @@ -35,9 +34,10 @@ use sp_application_crypto::key_types::BABE; use sp_consensus::{DisableProofRecording, NoNetwork as DummyOracle, Proposal}; use sp_consensus_babe::{ inherents::InherentDataProvider, make_transcript, make_transcript_data, AllowedSlots, - AuthorityPair, Slot, + AuthorityId, AuthorityPair, Slot, }; use sp_consensus_slots::SlotDuration; +use sp_consensus_vrf::schnorrkel::VRFOutput; use sp_core::crypto::Pair; use sp_keyring::Sr25519Keyring; use sp_keystore::{ @@ -553,52 +553,133 @@ fn sig_is_not_pre_digest() { } #[test] -fn can_author_block() { - sp_tracing::try_init_simple(); +fn claim_epoch_slots() { + // We don't require the full claim information, thus as a shorter alias we're + // going to use a simple integer value. Generally not verbose enough, but good enough + // to be used within the narrow scope of a single test. + // 0 -> None (i.e. unable to claim the slot), + // 1 -> Primary + // 2 -> Secondary + // 3 -> Secondary with VRF + const EPOCH_DURATION: u64 = 10; let authority = Sr25519Keyring::Alice; let keystore = create_keystore(authority); - let mut i = 0; - let epoch = Epoch { + let mut epoch = Epoch { start_slot: 0.into(), authorities: vec![(authority.public().into(), 1)], randomness: [0; 32], epoch_index: 1, - duration: 100, + duration: EPOCH_DURATION, config: BabeEpochConfiguration { c: (3, 10), allowed_slots: AllowedSlots::PrimaryAndSecondaryPlainSlots, }, }; - let mut config = crate::BabeConfiguration { - slot_duration: 1000, - epoch_length: 100, - c: (3, 10), - authorities: Vec::new(), + let claim_slot_wrap = |s, e| match claim_slot(Slot::from(s as u64), &e, &keystore) { + None => 0, + Some((PreDigest::Primary(_), _)) => 1, + Some((PreDigest::SecondaryPlain(_), _)) => 2, + Some((PreDigest::SecondaryVRF(_), _)) => 3, + }; + + // With secondary mechanism we should be able to claim all slots. + let claims: Vec<_> = (0..EPOCH_DURATION) + .into_iter() + .map(|slot| claim_slot_wrap(slot, epoch.clone())) + .collect(); + assert_eq!(claims, [1, 2, 2, 1, 2, 2, 2, 2, 2, 1]); + + // With secondary with VRF mechanism we should be able to claim all the slots. + epoch.config.allowed_slots = AllowedSlots::PrimaryAndSecondaryVRFSlots; + let claims: Vec<_> = (0..EPOCH_DURATION) + .into_iter() + .map(|slot| claim_slot_wrap(slot, epoch.clone())) + .collect(); + assert_eq!(claims, [1, 3, 3, 1, 3, 3, 3, 3, 3, 1]); + + // Otherwise with only vrf-based primary slots we are able to claim a subset of the slots. + epoch.config.allowed_slots = AllowedSlots::PrimarySlots; + let claims: Vec<_> = (0..EPOCH_DURATION) + .into_iter() + .map(|slot| claim_slot_wrap(slot, epoch.clone())) + .collect(); + assert_eq!(claims, [1, 0, 0, 1, 0, 0, 0, 0, 0, 1]); +} + +#[test] +fn claim_vrf_check() { + let authority = Sr25519Keyring::Alice; + let keystore = create_keystore(authority); + + let public = authority.public(); + + let epoch = Epoch { + start_slot: 0.into(), + authorities: vec![(public.into(), 1)], randomness: [0; 32], - allowed_slots: AllowedSlots::PrimaryAndSecondaryPlainSlots, + epoch_index: 1, + duration: 10, + config: BabeEpochConfiguration { + c: (3, 10), + allowed_slots: AllowedSlots::PrimaryAndSecondaryVRFSlots, + }, }; - // with secondary slots enabled it should never be empty - match claim_slot(i.into(), &epoch, &keystore) { - None => i += 1, - Some(s) => debug!(target: LOG_TARGET, "Authored block {:?}", s.0), - } + // We leverage the predictability of claim types given a constant randomness. - // otherwise with only vrf-based primary slots we might need to try a couple - // of times. - config.allowed_slots = AllowedSlots::PrimarySlots; - loop { - match claim_slot(i.into(), &epoch, &keystore) { - None => i += 1, - Some(s) => { - debug!(target: LOG_TARGET, "Authored block {:?}", s.0); - break - }, - } - } + // We expect a Primary claim for slot 0 + + let pre_digest = match claim_slot(0.into(), &epoch, &keystore).unwrap().0 { + PreDigest::Primary(d) => d, + v => panic!("Unexpected pre-digest variant {:?}", v), + }; + let transcript = make_transcript_data(&epoch.randomness.clone(), 0.into(), epoch.epoch_index); + let sign = SyncCryptoStore::sr25519_vrf_sign(&*keystore, AuthorityId::ID, &public, transcript) + .unwrap() + .unwrap(); + assert_eq!(pre_digest.vrf_output, VRFOutput(sign.output)); + + // We expect a SecondaryVRF claim for slot 1 + let pre_digest = match claim_slot(1.into(), &epoch, &keystore).unwrap().0 { + PreDigest::SecondaryVRF(d) => d, + v => panic!("Unexpected pre-digest variant {:?}", v), + }; + let transcript = make_transcript_data(&epoch.randomness.clone(), 1.into(), epoch.epoch_index); + let sign = SyncCryptoStore::sr25519_vrf_sign(&*keystore, AuthorityId::ID, &public, transcript) + .unwrap() + .unwrap(); + assert_eq!(pre_digest.vrf_output, VRFOutput(sign.output)); + + // Check that correct epoch index has been used if epochs are skipped (primary VRF) + let slot = Slot::from(103); + let claim = match claim_slot(slot, &epoch, &keystore).unwrap().0 { + PreDigest::Primary(d) => d, + v => panic!("Unexpected claim variant {:?}", v), + }; + let fixed_epoch = epoch.clone_for_slot(slot); + let transcript = make_transcript_data(&epoch.randomness.clone(), slot, fixed_epoch.epoch_index); + let sign = SyncCryptoStore::sr25519_vrf_sign(&*keystore, AuthorityId::ID, &public, transcript) + .unwrap() + .unwrap(); + assert_eq!(fixed_epoch.epoch_index, 11); + assert_eq!(claim.vrf_output, VRFOutput(sign.output)); + + // Check that correct epoch index has been used if epochs are skipped (secondary VRF) + let slot = Slot::from(100); + let pre_digest = match claim_slot(slot, &epoch, &keystore).unwrap().0 { + PreDigest::SecondaryVRF(d) => d, + v => panic!("Unexpected claim variant {:?}", v), + }; + let fixed_epoch = epoch.clone_for_slot(slot); + let transcript = make_transcript_data(&epoch.randomness.clone(), slot, fixed_epoch.epoch_index); + let sign = SyncCryptoStore::sr25519_vrf_sign(&*keystore, AuthorityId::ID, &public, transcript) + .unwrap() + .unwrap(); + assert_eq!(fixed_epoch.epoch_index, 11); + assert_eq!(pre_digest.vrf_output, VRFOutput(sign.output)); } // Propose and import a new BABE block on top of the given parent. diff --git a/client/consensus/babe/src/verification.rs b/client/consensus/babe/src/verification.rs index e77a70c8e465a..8e8f5d998f884 100644 --- a/client/consensus/babe/src/verification.rs +++ b/client/consensus/babe/src/verification.rs @@ -22,6 +22,7 @@ use crate::{ babe_err, find_pre_digest, BlockT, Epoch, Error, LOG_TARGET, }; use log::{debug, trace}; +use sc_consensus_epochs::Epoch as EpochT; use sc_consensus_slots::CheckedHeader; use sp_consensus_babe::{ digests::{ @@ -155,10 +156,16 @@ fn check_primary_header( c: (u64, u64), ) -> Result<(), Error> { let author = &epoch.authorities[pre_digest.authority_index as usize].0; + let mut epoch_index = epoch.epoch_index; + + if epoch.end_slot() <= pre_digest.slot { + // Slot doesn't strictly belong to this epoch, create a clone with fixed values. + epoch_index = epoch.clone_for_slot(pre_digest.slot).epoch_index; + } if AuthorityPair::verify(&signature, pre_hash, author) { let (inout, _) = { - let transcript = make_transcript(&epoch.randomness, pre_digest.slot, epoch.epoch_index); + let transcript = make_transcript(&epoch.randomness, pre_digest.slot, epoch_index); schnorrkel::PublicKey::from_bytes(author.as_slice()) .and_then(|p| { @@ -228,8 +235,14 @@ fn check_secondary_vrf_header( return Err(Error::InvalidAuthor(expected_author.clone(), author.clone())) } + let mut epoch_index = epoch.epoch_index; + if epoch.end_slot() <= pre_digest.slot { + // Slot doesn't strictly belong to this epoch, create a clone with fixed values. + epoch_index = epoch.clone_for_slot(pre_digest.slot).epoch_index; + } + if AuthorityPair::verify(&signature, pre_hash.as_ref(), author) { - let transcript = make_transcript(&epoch.randomness, pre_digest.slot, epoch.epoch_index); + let transcript = make_transcript(&epoch.randomness, pre_digest.slot, epoch_index); schnorrkel::PublicKey::from_bytes(author.as_slice()) .and_then(|p| p.vrf_verify(transcript, &pre_digest.vrf_output, &pre_digest.vrf_proof)) From 1a1600b827020cae62c9b856cb9ba4b823ab080a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Wed, 25 Jan 2023 10:48:40 -0300 Subject: [PATCH 326/715] contracts: Deprecate random interface (#13204) * Deprecate random interface * Revert change to runtime file * Fix docs * Fix tests * Rename to not_deprecated * Apply suggestions from code review Co-authored-by: Sasha Gryaznov * Deprecate `set_rent_allowance` Co-authored-by: Sasha Gryaznov --- frame/contracts/proc-macro/src/lib.rs | 55 ++++- frame/contracts/src/benchmarking/sandbox.rs | 13 +- frame/contracts/src/exec.rs | 31 +++ frame/contracts/src/lib.rs | 9 +- frame/contracts/src/wasm/mod.rs | 217 +++++++++++++++++--- frame/contracts/src/wasm/prepare.rs | 72 +++++-- frame/contracts/src/wasm/runtime.rs | 132 ++++++------ 7 files changed, 416 insertions(+), 113 deletions(-) diff --git a/frame/contracts/proc-macro/src/lib.rs b/frame/contracts/proc-macro/src/lib.rs index d0247d720a39a..eaf437c150c89 100644 --- a/frame/contracts/proc-macro/src/lib.rs +++ b/frame/contracts/proc-macro/src/lib.rs @@ -162,6 +162,8 @@ struct HostFn { returns: HostFnReturn, is_stable: bool, alias_to: Option, + /// Formulating the predicate inverted makes the expression using it simpler. + not_deprecated: bool, } enum HostFnReturn { @@ -199,13 +201,14 @@ impl HostFn { // process attributes let msg = - "only #[version()], #[unstable] and #[prefixed_alias] attributes are allowed."; + "only #[version()], #[unstable], #[prefixed_alias] and #[deprecated] attributes are allowed."; let span = item.span(); let mut attrs = item.attrs.clone(); attrs.retain(|a| !a.path.is_ident("doc")); let mut maybe_module = None; let mut is_stable = true; let mut alias_to = None; + let mut not_deprecated = true; while let Some(attr) = attrs.pop() { let ident = attr.path.get_ident().ok_or(err(span, msg))?.to_string(); match ident.as_str() { @@ -230,12 +233,22 @@ impl HostFn { item.sig.ident.span(), ); }, + "deprecated" => { + if !not_deprecated { + return Err(err(span, "#[deprecated] can only be specified once")) + } + not_deprecated = false; + }, _ => return Err(err(span, msg)), } } let name = item.sig.ident.to_string(); - // process arguments: The first and second arg are treated differently (ctx, memory) + if !(is_stable || not_deprecated) { + return Err(err(span, "#[deprecated] is mutually exclusive with #[unstable]")) + } + + // process arguments: The first and second args 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 @@ -330,6 +343,7 @@ impl HostFn { returns, is_stable, alias_to, + not_deprecated, }) }, _ => Err(err(span, &msg)), @@ -510,7 +524,12 @@ fn expand_impls(def: &mut EnvDef) -> TokenStream2 { quote! { impl<'a, E: Ext> crate::wasm::Environment> for Env { - fn define(store: &mut ::wasmi::Store>, linker: &mut ::wasmi::Linker>, allow_unstable: bool) -> Result<(), ::wasmi::errors::LinkerError> { + fn define( + store: &mut ::wasmi::Store>, + linker: &mut ::wasmi::Linker>, + allow_unstable: AllowUnstableInterface, + allow_deprecated: AllowDeprecatedInterface, + ) -> Result<(),::wasmi::errors::LinkerError> { #impls Ok(()) } @@ -518,7 +537,12 @@ fn expand_impls(def: &mut EnvDef) -> TokenStream2 { impl crate::wasm::Environment<()> for Env { - fn define(store: &mut ::wasmi::Store<()>, linker: &mut ::wasmi::Linker<()>, allow_unstable: bool) -> Result<(), ::wasmi::errors::LinkerError> { + fn define( + store: &mut ::wasmi::Store<()>, + linker: &mut ::wasmi::Linker<()>, + allow_unstable: AllowUnstableInterface, + allow_deprecated: AllowDeprecatedInterface, + ) -> Result<(), ::wasmi::errors::LinkerError> { #dummy_impls Ok(()) } @@ -542,6 +566,7 @@ fn expand_functions( &f.item.sig.output ); let is_stable = f.is_stable; + let not_deprecated = f.not_deprecated; // If we don't expand blocks (implementing for `()`) we change a few things: // - We replace any code by unreachable! @@ -582,9 +607,13 @@ fn expand_functions( }; quote! { - // 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 { + // We need to allow all interfaces when runtime benchmarks are performed because + // we generate the weights even when those interfaces are not enabled. This + // is necessary as the decision whether we allow unstable or deprecated functions + // is a decision made at runtime. Generation of the weights happens statically. + if ::core::cfg!(feature = "runtime-benchmarks") || + ((#is_stable || __allow_unstable__) && (#not_deprecated || __allow_deprecated__)) + { #allow_unused linker.define(#module, #name, ::wasmi::Func::wrap(&mut*store, |mut __caller__: ::wasmi::Caller<#host_state>, #( #params, )*| -> #wasm_output { let mut func = #inner; @@ -596,6 +625,8 @@ fn expand_functions( } }); quote! { + let __allow_unstable__ = matches!(allow_unstable, AllowUnstableInterface::Yes); + let __allow_deprecated__ = matches!(allow_deprecated, AllowDeprecatedInterface::Yes); #( #impls )* } } @@ -691,6 +722,16 @@ fn expand_functions( /// `...` modules each having its `Api` trait containing functions holding documentation for every /// host function defined by the macro. /// +/// # Deprecated Interfaces +/// +/// An interface can be annotated with `#[deprecated]`. It is mutually exclusive with `#[unstable]`. +/// Deprecated interfaces have the following properties: +/// - New contract codes utilizing those interfaces cannot be uploaded. +/// - New contracts from existing codes utilizing those interfaces cannot be instantiated. +/// - Existing contracts containing those interfaces still work. +/// +/// Those interfaces will eventually be removed. +/// /// To build up these docs, run: /// /// ```nocompile diff --git a/frame/contracts/src/benchmarking/sandbox.rs b/frame/contracts/src/benchmarking/sandbox.rs index 5d080bad92516..a6a97d11acbe3 100644 --- a/frame/contracts/src/benchmarking/sandbox.rs +++ b/frame/contracts/src/benchmarking/sandbox.rs @@ -19,7 +19,9 @@ /// ! 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 crate::wasm::{ + AllowDeprecatedInterface, AllowUnstableInterface, Environment, PrefabWasmModule, +}; use wasmi::{errors::LinkerError, Func, Linker, StackLimits, Store}; /// Minimal execution environment without any imported functions. @@ -49,6 +51,8 @@ impl From<&WasmModule> for Sandbox { (), memory, StackLimits::default(), + // We are testing with an empty environment anyways + AllowDeprecatedInterface::No, ) .expect("Failed to create benchmarking Sandbox instance"); let entry_point = instance.get_export(&store, "call").unwrap().into_func().unwrap(); @@ -59,7 +63,12 @@ impl From<&WasmModule> for Sandbox { struct EmptyEnv; impl Environment<()> for EmptyEnv { - fn define(_: &mut Store<()>, _: &mut Linker<()>, _: bool) -> Result<(), LinkerError> { + fn define( + _: &mut Store<()>, + _: &mut Linker<()>, + _: AllowUnstableInterface, + _: AllowDeprecatedInterface, + ) -> Result<(), LinkerError> { Ok(()) } } diff --git a/frame/contracts/src/exec.rs b/frame/contracts/src/exec.rs index b5b630653667b..7a07b01d27c2a 100644 --- a/frame/contracts/src/exec.rs +++ b/frame/contracts/src/exec.rs @@ -3440,4 +3440,35 @@ mod tests { )); }); } + + /// This works even though random interface is deprecated, as the check to ban deprecated + /// functions happens in the wasm stack which is mocked for exec tests. + #[test] + fn randomness_works() { + let subject = b"nice subject".as_ref(); + let code_hash = MockLoader::insert(Call, move |ctx, _| { + let rand = ::Randomness::random(subject); + assert_eq!(rand, ctx.ext.random(subject)); + exec_success() + }); + + ExtBuilder::default().build().execute_with(|| { + let schedule = ::Schedule::get(); + 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 GasMeter::::new(GAS_LIMIT), + &mut storage_meter, + &schedule, + 0, + vec![], + None, + Determinism::Deterministic, + ); + assert_matches!(result, Ok(_)); + }); + } } diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index 672c4517d06a1..84a72b7016079 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -216,7 +216,14 @@ 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`. + /// + /// # Deprecated + /// + /// Codes using the randomness functionality cannot be uploaded. Neither can contracts + /// be instantiated from existing codes that use this deprecated functionality. It will + /// be removed eventually. Hence for new `pallet-contracts` deployments it is okay + /// to supply a dummy implementation for this type (because it is never used). type Randomness: Randomness; /// The currency in which fees are paid and contract balances are held. diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index c2b0611769429..6b9cefcdd2d96 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -24,14 +24,16 @@ mod runtime; #[cfg(feature = "runtime-benchmarks")] pub use crate::wasm::code_cache::reinstrument; +#[cfg(doc)] +pub use crate::wasm::runtime::api_doc; pub use crate::wasm::{ prepare::TryInstantiate, - runtime::{CallFlags, Environment, ReturnCode, Runtime, RuntimeCosts}, + runtime::{ + AllowDeprecatedInterface, AllowUnstableInterface, CallFlags, Environment, ReturnCode, + Runtime, RuntimeCosts, + }, }; -#[cfg(doc)] -pub use crate::wasm::runtime::api_doc; - use crate::{ exec::{ExecResult, Executable, ExportedFunction, Ext}, gas::GasMeter, @@ -205,6 +207,7 @@ impl PrefabWasmModule { host_state: H, memory: (u32, u32), stack_limits: StackLimits, + allow_deprecated: AllowDeprecatedInterface, ) -> Result<(Store, Memory, Instance), wasmi::Error> where E: Environment, @@ -220,7 +223,16 @@ impl PrefabWasmModule { 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, T::UnsafeUnstableInterface::get())?; + E::define( + &mut store, + &mut linker, + if T::UnsafeUnstableInterface::get() { + AllowUnstableInterface::Yes + } else { + AllowUnstableInterface::No + }, + allow_deprecated, + )?; 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", ); @@ -233,20 +245,14 @@ impl PrefabWasmModule { Ok((store, memory, instance)) } - /// Create and store the module without checking nor instrumenting the passed code. - /// - /// # Note - /// - /// This is useful for benchmarking where we don't want instrumentation to skew - /// our results. This also does not collect any deposit from the `owner`. + /// See [`Self::from_code_unchecked`]. #[cfg(feature = "runtime-benchmarks")] pub fn store_code_unchecked( original_code: Vec, schedule: &Schedule, owner: T::AccountId, ) -> DispatchResult { - let executable = prepare::benchmarking::prepare(original_code, schedule, owner) - .map_err::(Into::into)?; + let executable = Self::from_code_unchecked(original_code, schedule, owner)?; code_cache::store(executable, false) } @@ -255,6 +261,23 @@ impl PrefabWasmModule { pub fn decrement_version(&mut self) { self.instruction_weights_version = self.instruction_weights_version.checked_sub(1).unwrap(); } + + /// Create the module without checking nor instrumenting the passed code. + /// + /// # Note + /// + /// This is useful for benchmarking where we don't want instrumentation to skew + /// our results. This also does not collect any deposit from the `owner`. Also useful + /// during testing when we want to deploy codes that do not pass the instantiation checks. + #[cfg(any(test, feature = "runtime-benchmarks"))] + fn from_code_unchecked( + original_code: Vec, + schedule: &Schedule, + owner: T::AccountId, + ) -> Result { + prepare::benchmarking::prepare(original_code, schedule, owner) + .map_err::(Into::into) + } } impl OwnerInfo { @@ -294,6 +317,10 @@ impl Executable for PrefabWasmModule { runtime, (self.initial, self.maximum), StackLimits::default(), + match function { + ExportedFunction::Constructor => AllowDeprecatedInterface::No, + ExportedFunction::Call => AllowDeprecatedInterface::Yes, + }, ) .map_err(|msg| { log::debug!(target: "runtime::contracts", "failed to instantiate code: {}", msg); @@ -629,38 +656,77 @@ mod tests { } } + /// Execute the supplied code. + /// + /// Not used directly but through the wrapper functions defined below. fn execute_internal>( wat: &str, input_data: Vec, mut ext: E, + entry_point: &ExportedFunction, unstable_interface: bool, + skip_checks: 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::::from_code( - wasm, - &schedule, - ALICE, - Determinism::Deterministic, - TryInstantiate::Skip, - ) - .map_err(|err| err.0)?; - executable.execute(ext.borrow_mut(), &ExportedFunction::Call, input_data) + let executable = if skip_checks { + PrefabWasmModule::::from_code_unchecked(wasm, &schedule, ALICE)? + } else { + PrefabWasmModule::::from_code( + wasm, + &schedule, + ALICE, + Determinism::Deterministic, + TryInstantiate::Instantiate, + ) + .map_err(|err| err.0)? + }; + executable.execute(ext.borrow_mut(), entry_point, input_data) } + /// Execute the suppplied code. fn execute>(wat: &str, input_data: Vec, ext: E) -> ExecResult { - execute_internal(wat, input_data, ext, true) + execute_internal(wat, input_data, ext, &ExportedFunction::Call, true, false) } + /// Execute the supplied code with disabled unstable functions. + /// + /// In our test config unstable functions are disabled so that we can test them. + /// In order to test that code using them is properly rejected we temporarily disable + /// them when this test is run. #[cfg(not(feature = "runtime-benchmarks"))] fn execute_no_unstable>( wat: &str, input_data: Vec, ext: E, ) -> ExecResult { - execute_internal(wat, input_data, ext, false) + execute_internal(wat, input_data, ext, &ExportedFunction::Call, false, false) + } + + /// Execute code without validating it first. + /// + /// This is mainly useful in order to test code which uses deprecated functions. Those + /// would fail when validating the code. + fn execute_unvalidated>( + wat: &str, + input_data: Vec, + ext: E, + ) -> ExecResult { + execute_internal(wat, input_data, ext, &ExportedFunction::Call, false, true) + } + + /// Execute instantiation entry point of code without validating it first. + /// + /// Same as `execute_unvalidated` except that the `deploy` entry point is ran. + #[cfg(not(feature = "runtime-benchmarks"))] + fn execute_instantiate_unvalidated>( + wat: &str, + input_data: Vec, + ext: E, + ) -> ExecResult { + execute_internal(wat, input_data, ext, &ExportedFunction::Constructor, false, true) } const CODE_TRANSFER: &str = r#" @@ -1861,7 +1927,7 @@ mod tests { #[test] fn random() { - let output = execute(CODE_RANDOM, vec![], MockExt::default()).unwrap(); + let output = execute_unvalidated(CODE_RANDOM, vec![], MockExt::default()).unwrap(); // The mock ext just returns the same data that was passed as the subject. assert_eq!( @@ -1931,7 +1997,7 @@ mod tests { #[test] fn random_v1() { - let output = execute(CODE_RANDOM_V1, vec![], MockExt::default()).unwrap(); + let output = execute_unvalidated(CODE_RANDOM_V1, vec![], MockExt::default()).unwrap(); // The mock ext just returns the same data that was passed as the subject. assert_eq!( @@ -3007,6 +3073,29 @@ mod tests { execute(CODE, vec![], &mut mock_ext).unwrap(); } + /// Code with deprecated functions cannot be uploaded or instantiated. However, we + /// need to make sure that it still can be re-instrumented. + #[test] + fn can_reinstrument_deprecated() { + const CODE_RANDOM: &str = r#" +(module + (import "seal0" "random" (func $seal_random (param i32 i32 i32 i32))) + (func (export "call")) + (func (export "deploy")) +) + "#; + let wasm = wat::parse_str(CODE_RANDOM).unwrap(); + let schedule = crate::Schedule::::default(); + #[cfg(not(feature = "runtime-benchmarks"))] + assert_err!(execute(CODE_RANDOM, vec![], MockExt::default()), >::CodeRejected); + self::prepare::reinstrument::( + &wasm, + &schedule, + Determinism::Deterministic, + ) + .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. @@ -3026,4 +3115,80 @@ mod tests { ); assert_ok!(execute(CANNOT_DEPLOY_UNSTABLE, vec![], MockExt::default())); } + + /// The random interface is deprecated and hence new contracts using it should not be deployed. + /// In case of runtime benchmarks we always allow deprecated interfaces. This is why this + /// test doesn't work if this feature is enabled. + #[cfg(not(feature = "runtime-benchmarks"))] + #[test] + fn cannot_deploy_deprecated() { + const CODE_RANDOM_0: &str = r#" +(module + (import "seal0" "seal_random" (func $seal_random (param i32 i32 i32 i32))) + (func (export "call")) + (func (export "deploy")) +) + "#; + const CODE_RANDOM_1: &str = r#" +(module + (import "seal1" "seal_random" (func $seal_random (param i32 i32 i32 i32))) + (func (export "call")) + (func (export "deploy")) +) + "#; + const CODE_RANDOM_2: &str = r#" +(module + (import "seal0" "random" (func $seal_random (param i32 i32 i32 i32))) + (func (export "call")) + (func (export "deploy")) +) + "#; + const CODE_RANDOM_3: &str = r#" +(module + (import "seal1" "random" (func $seal_random (param i32 i32 i32 i32))) + (func (export "call")) + (func (export "deploy")) +) + "#; + + assert_ok!(execute_unvalidated(CODE_RANDOM_0, vec![], MockExt::default())); + assert_err!( + execute_instantiate_unvalidated(CODE_RANDOM_0, vec![], MockExt::default()), + >::CodeRejected, + ); + assert_err!( + execute(CODE_RANDOM_0, vec![], MockExt::default()), + >::CodeRejected, + ); + + assert_ok!(execute_unvalidated(CODE_RANDOM_1, vec![], MockExt::default())); + assert_err!( + execute_instantiate_unvalidated(CODE_RANDOM_1, vec![], MockExt::default()), + >::CodeRejected, + ); + assert_err!( + execute(CODE_RANDOM_1, vec![], MockExt::default()), + >::CodeRejected, + ); + + assert_ok!(execute_unvalidated(CODE_RANDOM_2, vec![], MockExt::default())); + assert_err!( + execute_instantiate_unvalidated(CODE_RANDOM_2, vec![], MockExt::default()), + >::CodeRejected, + ); + assert_err!( + execute(CODE_RANDOM_2, vec![], MockExt::default()), + >::CodeRejected, + ); + + assert_ok!(execute_unvalidated(CODE_RANDOM_3, vec![], MockExt::default())); + assert_err!( + execute_instantiate_unvalidated(CODE_RANDOM_3, vec![], MockExt::default()), + >::CodeRejected, + ); + assert_err!( + execute(CODE_RANDOM_3, vec![], MockExt::default()), + >::CodeRejected, + ); + } } diff --git a/frame/contracts/src/wasm/prepare.rs b/frame/contracts/src/wasm/prepare.rs index dfe25bc3af89f..787b97d31acce 100644 --- a/frame/contracts/src/wasm/prepare.rs +++ b/frame/contracts/src/wasm/prepare.rs @@ -22,7 +22,9 @@ use crate::{ chain_extension::ChainExtension, storage::meter::Diff, - wasm::{Determinism, Environment, OwnerInfo, PrefabWasmModule}, + wasm::{ + runtime::AllowDeprecatedInterface, Determinism, Environment, OwnerInfo, PrefabWasmModule, + }, AccountIdOf, CodeVec, Config, Error, Schedule, }; use codec::{Encode, MaxEncodedLen}; @@ -54,6 +56,14 @@ pub enum TryInstantiate { Skip, } +/// The reason why a contract is instrumented. +enum InstrumentReason { + /// A new code is uploaded. + New, + /// Existing code is re-instrumented. + Reinstrument, +} + struct ContractModule<'a, T: Config> { /// A deserialized module. The module is valid (this is Guaranteed by `new` method). module: elements::Module, @@ -381,6 +391,7 @@ fn instrument( schedule: &Schedule, determinism: Determinism, try_instantiate: TryInstantiate, + reason: InstrumentReason, ) -> Result<(Vec, (u32, u32)), (DispatchError, &'static str)> where E: Environment<()>, @@ -454,11 +465,20 @@ where // 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") - })?; + PrefabWasmModule::::instantiate::( + &code, + (), + (initial, maximum), + stack_limits, + match reason { + InstrumentReason::New => AllowDeprecatedInterface::No, + InstrumentReason::Reinstrument => AllowDeprecatedInterface::Yes, + }, + ) + .map_err(|err| { + log::debug!(target: "runtime::contracts", "{}", err); + (Error::::CodeRejected.into(), "new code rejected after instrumentation") + })?; } Ok((code, (initial, maximum))) @@ -486,8 +506,13 @@ where E: Environment<()>, T: Config, { - let (code, (initial, maximum)) = - instrument::(original_code.as_ref(), schedule, determinism, try_instantiate)?; + let (code, (initial, maximum)) = instrument::( + original_code.as_ref(), + schedule, + determinism, + try_instantiate, + InstrumentReason::New, + )?; let original_code_len = original_code.len(); @@ -532,21 +557,30 @@ where E: Environment<()>, T: Config, { - instrument::(original_code, schedule, determinism, TryInstantiate::Skip) - .map_err(|(err, msg)| { - log::error!(target: "runtime::contracts", "CodeRejected during reinstrument: {}", msg); - err - }) - .map(|(code, _)| code) + instrument::( + original_code, + schedule, + determinism, + // This function was triggered by an interaction with an existing contract code + // that will try to instantiate anyways. Failing here would not help + // as the contract is already on chain. + TryInstantiate::Skip, + InstrumentReason::Reinstrument, + ) + .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. +/// Alternate (possibly unsafe) preparation functions used only for benchmarking and testing. /// /// For benchmarking we need to construct special contracts that might not pass our /// sanity checks or need to skip instrumentation for correct results. We hide functions -/// allowing this behind a feature that is only set during benchmarking to prevent usage -/// in production code. -#[cfg(feature = "runtime-benchmarks")] +/// allowing this behind a feature that is only set during benchmarking or testing to +/// prevent usage in production code. +#[cfg(any(test, feature = "runtime-benchmarks"))] pub mod benchmarking { use super::*; @@ -600,7 +634,7 @@ mod tests { #[allow(unreachable_code)] mod env { use super::*; - use crate::wasm::runtime::TrapReason; + use crate::wasm::runtime::{AllowDeprecatedInterface, AllowUnstableInterface, TrapReason}; // Define test environment for tests. We need ImportSatisfyCheck // implementation from it. So actual implementations doesn't matter. diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index 745583b337653..9cdf0bf0928a9 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -37,6 +37,22 @@ 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; +/// Passed to [`Environment`] to determine whether it should expose deprecated interfaces. +pub enum AllowDeprecatedInterface { + /// No deprecated interfaces are exposed. + No, + /// Deprecated interfaces are exposed. + Yes, +} + +/// Passed to [`Environment`] to determine whether it should expose unstable interfaces. +pub enum AllowUnstableInterface { + /// No unstable interfaces are exposed. + No, + /// Unstable interfaces are exposed. + Yes, +} + /// Trait implemented by the [`define_env`](pallet_contracts_proc_macro::define_env) macro for the /// emitted `Env` struct. pub trait Environment { @@ -45,14 +61,15 @@ pub trait Environment { fn define( store: &mut Store, linker: &mut Linker, - allow_unstable: bool, + allow_unstable: AllowUnstableInterface, + allow_deprecated: AllowDeprecatedInterface, ) -> Result<(), LinkerError>; } /// Type of a storage key. #[allow(dead_code)] enum KeyType { - /// Deprecated fix sized key `[u8;32]`. + /// Legacy fix sized key `[u8;32]`. Fix, /// Variable sized key used in transparent hashing, /// cannot be larger than MaxStorageKeyLen. @@ -91,12 +108,8 @@ pub enum ReturnCode { CalleeReverted = 2, /// The passed key does not exist in storage. KeyNotFound = 3, - /// Deprecated and no longer returned: There is only the minimum balance. - _BelowSubsistenceThreshold = 4, /// See [`Error::TransferFailed`]. TransferFailed = 5, - /// Deprecated and no longer returned: Endowment is no longer required. - _EndowmentTooLow = 6, /// No code could be found at the supplied code hash. CodeNotFound = 7, /// The contract that was called is no contract (a plain account). @@ -1280,7 +1293,7 @@ pub mod env { /// Make a call to another contract. /// - /// # Deprecation + /// # New version available /// /// This is equivalent to calling the newer version of this function with /// `flags` set to `ALLOW_REENTRY`. See the newer version for documentation. @@ -1418,7 +1431,7 @@ pub mod env { /// Instantiate a contract with the specified code hash. /// - /// # Deprecation + /// # New version available /// /// This is equivalent to calling the newer version of this function. The newer version /// drops the now unnecessary length fields. @@ -1538,7 +1551,7 @@ pub mod env { /// Remove the calling account and transfer remaining balance. /// - /// # Deprecation + /// # New version available /// /// This is equivalent to calling the newer version of this function. The newer version /// drops the now unnecessary length fields. @@ -1879,12 +1892,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::Hash`. - /// - /// # Deprecation - /// - /// This function is deprecated. Users should migrate to the [`super::seal1::Api::random()`] - /// version. #[prefixed_alias] + #[deprecated] fn random( ctx: _, memory: _, @@ -1931,6 +1940,7 @@ pub mod env { /// commitment. #[version(1)] #[prefixed_alias] + #[deprecated] fn random( ctx: _, memory: _, @@ -2001,10 +2011,11 @@ 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. /// - /// # Deprecation + /// # Note /// /// There is no longer a tombstone deposit. This function always returns `0`. #[prefixed_alias] + #[deprecated] fn tombstone_deposit( ctx: _, memory: _, @@ -2030,6 +2041,7 @@ pub mod env { /// The state rent functionality was removed. This is stub only exists for /// backwards compatiblity #[prefixed_alias] + #[deprecated] fn restore_to( ctx: _, memory: _, @@ -2054,6 +2066,7 @@ pub mod env { /// backwards compatiblity #[version(1)] #[prefixed_alias] + #[deprecated] fn restore_to( ctx: _, memory: _, @@ -2067,49 +2080,6 @@ pub mod env { 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. - #[prefixed_alias] - fn deposit_event( - ctx: _, - memory: _, - topics_ptr: u32, - topics_len: u32, - data_ptr: u32, - data_len: u32, - ) -> Result<(), TrapReason> { - 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 })?; - if data_len > ctx.ext.max_value_size() { - return Err(Error::::ValueTooLarge.into()) - } - - let topics: Vec::T>> = match topics_len { - 0 => Vec::new(), - _ => ctx.read_sandbox_memory_as_unbounded(memory, 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()) - } - - let event_data = ctx.read_sandbox_memory(memory, data_ptr, data_len)?; - - ctx.ext.deposit_event(topics, event_data); - - Ok(()) - } - /// Was used to set rent allowance of the contract. /// /// # Note @@ -2117,6 +2087,7 @@ pub mod env { /// The state rent functionality was removed. This is stub only exists for /// backwards compatiblity. #[prefixed_alias] + #[deprecated] fn set_rent_allowance( ctx: _, memory: _, @@ -2135,6 +2106,7 @@ pub mod env { /// backwards compatiblity. #[version(1)] #[prefixed_alias] + #[deprecated] fn set_rent_allowance(ctx: _, _memory: _, _value_ptr: u32) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::DebugMessage)?; Ok(()) @@ -2147,6 +2119,7 @@ pub mod env { /// The state rent functionality was removed. This is stub only exists for /// backwards compatiblity. #[prefixed_alias] + #[deprecated] 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(); @@ -2160,6 +2133,49 @@ pub mod env { )?) } + /// Deposit a contract event with the data buffer and optional list of topics. There is a limit + /// on the maximum number of topics specified by `event_topics`. + /// + /// - `topics_ptr`: a pointer to the buffer of topics encoded as `Vec`. The value of + /// this is ignored if `topics_len` is set to `0`. The topics list can't contain duplicates. + /// - `topics_len`: the length of the topics buffer. Pass 0 if you want to pass an empty + /// vector. + /// - `data_ptr`: a pointer to a raw data buffer which will saved along the event. + /// - `data_len`: the length of the data buffer. + #[prefixed_alias] + fn deposit_event( + ctx: _, + memory: _, + topics_ptr: u32, + topics_len: u32, + data_ptr: u32, + data_len: u32, + ) -> Result<(), TrapReason> { + 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 })?; + if data_len > ctx.ext.max_value_size() { + return Err(Error::::ValueTooLarge.into()) + } + + let topics: Vec::T>> = match topics_len { + 0 => Vec::new(), + _ => ctx.read_sandbox_memory_as_unbounded(memory, 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()) + } + + let event_data = ctx.read_sandbox_memory(memory, data_ptr, data_len)?; + + ctx.ext.deposit_event(topics, event_data); + + Ok(()) + } + /// 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`. From d74eab8801538ac1218d89833f572697c3fae77b Mon Sep 17 00:00:00 2001 From: Sasha Gryaznov Date: Wed, 25 Jan 2023 20:12:29 +0200 Subject: [PATCH 327/715] [contracts] Add upfront weight of merkle trie proofs for storage reading functions (#13236) * Add upfront weight of merkle trie proofs for storage reading functions * drive-by fixes --- frame/contracts/proc-macro/src/lib.rs | 17 ++++++++++------- frame/contracts/src/lib.rs | 2 +- frame/contracts/src/schedule.rs | 10 +++++----- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/frame/contracts/proc-macro/src/lib.rs b/frame/contracts/proc-macro/src/lib.rs index eaf437c150c89..de7b9b881d305 100644 --- a/frame/contracts/proc-macro/src/lib.rs +++ b/frame/contracts/proc-macro/src/lib.rs @@ -124,21 +124,24 @@ fn format_weight(field: &Ident) -> TokenStream2 { quote_spanned! { field.span() => &if self.#field.ref_time() > 1_000_000_000 { format!( - "{:.1?} ms", - Fixed::saturating_from_rational(self.#field.ref_time(), 1_000_000_000).to_float() + "{:.1?} ms, {} bytes", + Fixed::saturating_from_rational(self.#field.ref_time(), 1_000_000_000).to_float(), + self.#field.proof_size() ) } else if self.#field.ref_time() > 1_000_000 { format!( - "{:.1?} µs", - Fixed::saturating_from_rational(self.#field.ref_time(), 1_000_000).to_float() + "{:.1?} µs, {} bytes", + Fixed::saturating_from_rational(self.#field.ref_time(), 1_000_000).to_float(), + self.#field.proof_size() ) } else if self.#field.ref_time() > 1_000 { format!( - "{:.1?} ns", - Fixed::saturating_from_rational(self.#field.ref_time(), 1_000).to_float() + "{:.1?} ns, {} bytes", + Fixed::saturating_from_rational(self.#field.ref_time(), 1_000).to_float(), + self.#field.proof_size() ) } else { - format!("{} ps", self.#field.ref_time()) + format!("{} ps, {} bytes", self.#field.ref_time(), self.#field.proof_size()) } } } diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index 84a72b7016079..f97b4b790cf6e 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -78,7 +78,7 @@ //! //! * [`ink`](https://github.com/paritytech/ink) is //! an [`eDSL`](https://wiki.haskell.org/Embedded_domain_specific_language) that enables writing -//! WebAssembly based smart contracts in the Rust programming language. This is a work in progress. +//! WebAssembly based smart contracts in the Rust programming language. #![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(feature = "runtime-benchmarks", recursion_limit = "512")] diff --git a/frame/contracts/src/schedule.rs b/frame/contracts/src/schedule.rs index eabd18c818952..7e09d55b44c58 100644 --- a/frame/contracts/src/schedule.rs +++ b/frame/contracts/src/schedule.rs @@ -644,23 +644,23 @@ impl Default for HostFnWeights { 1 )), debug_message: to_weight!(cost_batched!(seal_debug_message)), - set_storage: to_weight!(cost_batched!(seal_set_storage)), + set_storage: to_weight!(cost_batched!(seal_set_storage), 1024u64), set_code_hash: to_weight!(cost_batched!(seal_set_code_hash)), set_storage_per_new_byte: to_weight!(cost_byte_batched!(seal_set_storage_per_new_kb)), set_storage_per_old_byte: to_weight!( cost_byte_batched!(seal_set_storage_per_old_kb), 1u64 ), - clear_storage: to_weight!(cost_batched!(seal_clear_storage)), + clear_storage: to_weight!(cost_batched!(seal_clear_storage), 1024u64), clear_storage_per_byte: to_weight!(cost_byte_batched!(seal_clear_storage_per_kb), 1u64), - contains_storage: to_weight!(cost_batched!(seal_contains_storage)), + contains_storage: to_weight!(cost_batched!(seal_contains_storage), 1024u64), contains_storage_per_byte: to_weight!( cost_byte_batched!(seal_contains_storage_per_kb), 1u64 ), - get_storage: to_weight!(cost_batched!(seal_get_storage)), + get_storage: to_weight!(cost_batched!(seal_get_storage), 1024u64), get_storage_per_byte: to_weight!(cost_byte_batched!(seal_get_storage_per_kb), 1u64), - take_storage: to_weight!(cost_batched!(seal_take_storage)), + take_storage: to_weight!(cost_batched!(seal_take_storage), 1024u64), take_storage_per_byte: to_weight!(cost_byte_batched!(seal_take_storage_per_kb), 1u64), transfer: to_weight!(cost_batched!(seal_transfer)), call: to_weight!(cost_batched!(seal_call)), From d22e68ccb67788a1f1ad5a044568abd3e0a2c904 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 25 Jan 2023 23:49:03 +0100 Subject: [PATCH 328/715] CI: Rewrite `check-each-crate` in python (#13238) * CI: Rewrite `check-each-crate` in python This is a much better readable version of the script and it should also work on Macos and not siltently fail ;) * Fix dumb bugs and print everything to stderr * Don't buffer Python output * :facepalm: * :facepalm: :facepalm: * Use check all until we have more macos runners * Update scripts/ci/gitlab/check-each-crate.py Co-authored-by: Oliver Tale-Yazdi * Update scripts/ci/gitlab/pipeline/test.yml Co-authored-by: Vladimir Istyufeev Co-authored-by: Oliver Tale-Yazdi --- scripts/ci/gitlab/check-each-crate.py | 57 +++++++++++++++++++++++++++ scripts/ci/gitlab/check-each-crate.sh | 54 ------------------------- scripts/ci/gitlab/pipeline/test.yml | 5 ++- 3 files changed, 60 insertions(+), 56 deletions(-) create mode 100755 scripts/ci/gitlab/check-each-crate.py delete mode 100755 scripts/ci/gitlab/check-each-crate.sh diff --git a/scripts/ci/gitlab/check-each-crate.py b/scripts/ci/gitlab/check-each-crate.py new file mode 100755 index 0000000000000..adad4f5bd5835 --- /dev/null +++ b/scripts/ci/gitlab/check-each-crate.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python3 + +# A script that checks each workspace crate individually. +# It's relevant to check workspace crates individually because otherwise their compilation problems +# due to feature misconfigurations won't be caught, as exemplified by +# https://github.com/paritytech/substrate/issues/12705 +# +# `check-each-crate.py target_group groups_total` +# +# - `target_group`: Integer starting from 1, the group this script should execute. +# - `groups_total`: Integer starting from 1, total number of groups. + +import subprocess, sys + +# Get all crates +output = subprocess.check_output(["cargo", "tree", "--locked", "--workspace", "--depth", "0", "--prefix", "none"]) + +# Convert the output into a proper list +crates = [] +for line in output.splitlines(): + if line != b"": + crates.append(line.decode('utf8').split(" ")[0]) + +# Make the list unique and sorted +crates = list(set(crates)) +crates.sort() + +target_group = int(sys.argv[1]) - 1 +groups_total = int(sys.argv[2]) + +if len(crates) == 0: + print("No crates detected!", file=sys.stderr) + sys.exit(1) + +print(f"Total crates: {len(crates)}", file=sys.stderr) + +crates_per_group = len(crates) // groups_total + +# If this is the last runner, we need to take care of crates +# after the group that we lost because of the integer division. +if target_group + 1 == groups_total: + overflow_crates = len(crates) % groups_total +else: + overflow_crates = 0 + +print(f"Crates per group: {crates_per_group}", file=sys.stderr) + +# Check each crate +for i in range(0, crates_per_group + overflow_crates): + crate = crates_per_group * target_group + i + + print(f"Checking {crates[crate]}", file=sys.stderr) + + res = subprocess.run(["cargo", "check", "--locked", "-p", crates[crate]]) + + if res.returncode != 0: + sys.exit(1) diff --git a/scripts/ci/gitlab/check-each-crate.sh b/scripts/ci/gitlab/check-each-crate.sh deleted file mode 100755 index 24cad67007e73..0000000000000 --- a/scripts/ci/gitlab/check-each-crate.sh +++ /dev/null @@ -1,54 +0,0 @@ -#!/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 -vx - -target_group="$1" -groups_total="$2" - -readarray -t workspace_crates < <(\ - 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 - 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 - 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 - fi - group=$(( group + 1 )) -done diff --git a/scripts/ci/gitlab/pipeline/test.yml b/scripts/ci/gitlab/pipeline/test.yml index f00857ffa9935..02e05752fd01f 100644 --- a/scripts/ci/gitlab/pipeline/test.yml +++ b/scripts/ci/gitlab/pipeline/test.yml @@ -411,7 +411,7 @@ cargo-check-each-crate: 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" + - PYTHONUNBUFFERED=x time ./scripts/ci/gitlab/check-each-crate.py "$CI_NODE_INDEX" "$CI_NODE_TOTAL" # need to update cache only from one job - if [ "$CI_NODE_INDEX" == 1 ]; then rusty-cachier cache upload; fi parallel: 2 @@ -449,6 +449,7 @@ cargo-check-each-crate-macos: 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 + # - time ./scripts/ci/gitlab/check-each-crate.py 1 1 + - time cargo check --workspace --locked tags: - osx From d02922585673cb626df11a39927502d2ba040ff9 Mon Sep 17 00:00:00 2001 From: zjb0807 Date: Thu, 26 Jan 2023 12:12:19 +1300 Subject: [PATCH 329/715] Fix try-runtime with create-snapshot (#13223) * Fix try-runtime with create-snapshot * Apply review suggestions --- .../frame/try-runtime/cli/src/commands/create_snapshot.rs | 2 +- utils/frame/try-runtime/cli/src/commands/execute_block.rs | 2 +- utils/frame/try-runtime/cli/src/commands/follow_chain.rs | 2 +- .../frame/try-runtime/cli/src/commands/offchain_worker.rs | 2 +- .../try-runtime/cli/src/commands/on_runtime_upgrade.rs | 2 +- utils/frame/try-runtime/cli/src/lib.rs | 7 +++++-- 6 files changed, 10 insertions(+), 7 deletions(-) diff --git a/utils/frame/try-runtime/cli/src/commands/create_snapshot.rs b/utils/frame/try-runtime/cli/src/commands/create_snapshot.rs index ef39c3d9846ce..8d6144f84c1e8 100644 --- a/utils/frame/try-runtime/cli/src/commands/create_snapshot.rs +++ b/utils/frame/try-runtime/cli/src/commands/create_snapshot.rs @@ -71,7 +71,7 @@ where let executor = build_executor::(&shared); let _ = State::Live(command.from) - .into_ext::(&shared, &executor, Some(path.into())) + .into_ext::(&shared, &executor, Some(path.into()), false) .await?; Ok(()) 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 ee5e21af5d3ba..e054c8ab87932 100644 --- a/utils/frame/try-runtime/cli/src/commands/execute_block.rs +++ b/utils/frame/try-runtime/cli/src/commands/execute_block.rs @@ -99,7 +99,7 @@ where HostFns: HostFunctions, { let executor = build_executor::(&shared); - let ext = command.state.into_ext::(&shared, &executor, None).await?; + let ext = command.state.into_ext::(&shared, &executor, None, true).await?; // get the block number associated with this block. let block_ws_uri = command.block_ws_uri::(); 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 e4f166fe7ada7..d887757b1646e 100644 --- a/utils/frame/try-runtime/cli/src/commands/follow_chain.rs +++ b/utils/frame/try-runtime/cli/src/commands/follow_chain.rs @@ -137,7 +137,7 @@ where pallet: vec![], child_tree: true, }); - let ext = state.into_ext::(&shared, &executor, None).await?; + let ext = state.into_ext::(&shared, &executor, None, true).await?; maybe_state_ext = Some(ext); } 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 c55de7da64817..985b04bfb1cac 100644 --- a/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs +++ b/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs @@ -78,7 +78,7 @@ where { let executor = build_executor(&shared); // we first build the externalities with the remote code. - let ext = command.state.into_ext::(&shared, &executor, None).await?; + let ext = command.state.into_ext::(&shared, &executor, None, true).await?; let header_ws_uri = command.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 81f81d6a551b9..61b5847ed8ffc 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 @@ -62,7 +62,7 @@ where HostFns: HostFunctions, { let executor = build_executor(&shared); - let ext = command.state.into_ext::(&shared, &executor, None).await?; + let ext = command.state.into_ext::(&shared, &executor, None, true).await?; let (_, encoded_result) = state_machine_call_with_proof::( &ext, diff --git a/utils/frame/try-runtime/cli/src/lib.rs b/utils/frame/try-runtime/cli/src/lib.rs index aac2ad4238431..dea20febb9c58 100644 --- a/utils/frame/try-runtime/cli/src/lib.rs +++ b/utils/frame/try-runtime/cli/src/lib.rs @@ -609,6 +609,7 @@ impl State { shared: &SharedParams, executor: &WasmExecutor, state_snapshot: Option, + try_runtime_check: bool, ) -> sc_cli::Result> where Block::Hash: FromStr, @@ -707,8 +708,10 @@ impl State { } // whatever runtime we have in store now must have been compiled with try-runtime feature. - if !ensure_try_runtime::(&executor, &mut ext) { - return Err("given runtime is NOT compiled with try-runtime feature!".into()) + if try_runtime_check { + if !ensure_try_runtime::(&executor, &mut ext) { + return Err("given runtime is NOT compiled with try-runtime feature!".into()) + } } Ok(ext) From 8b4331c27bba6d9f178b8be093e39153350b9be8 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Wed, 25 Jan 2023 20:59:19 -0300 Subject: [PATCH 330/715] reduce exec time of fast-unstake benchmarks (#13120) * reduce exec time of fast-unstake benchmarks * fix test * fmt * fix patch the tests * fix patch the tests * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_fast_unstake * add batch size as well * update some benches to be better * fix one last test * fix * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_fast_unstake * reduce time even more * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_fast_unstake * fix tests * nit * remove * improve the weight calc further * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_fast_unstake * fix benchmarks * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_fast_unstake * update * fix * fix * fmt * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_fast_unstake * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_fast_unstake * lots of changes again... * smaller input * update * fmt * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_fast_unstake * cleanup * small simplification * fmt * reduce exec time a bit * fix * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_fast_unstake * test * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_fast_unstake * increase again * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_fast_unstake * review comments * fmt * fix * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_fast_unstake Co-authored-by: command-bot <> --- bin/node/runtime/src/lib.rs | 5 +- frame/fast-unstake/src/benchmarking.rs | 38 +++--- frame/fast-unstake/src/lib.rs | 126 ++++++++++++------ frame/fast-unstake/src/mock.rs | 3 + frame/fast-unstake/src/tests.rs | 173 ++++++------------------- frame/fast-unstake/src/weights.rs | 155 ++++++++++++---------- 6 files changed, 237 insertions(+), 263 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 0ac6ade9127e8..1f85d118ea534 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -591,10 +591,13 @@ 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 BatchSize = ConstU32<64>; type Deposit = ConstU128<{ DOLLARS }>; type Currency = Balances; type Staking = Staking; + type MaxErasToCheckPerBlock = ConstU32<1>; + #[cfg(feature = "runtime-benchmarks")] + type MaxBackersPerValidator = MaxNominatorRewardedPerValidator; type WeightInfo = (); } diff --git a/frame/fast-unstake/src/benchmarking.rs b/frame/fast-unstake/src/benchmarking.rs index b4a5e21dcfc13..de85502f7b411 100644 --- a/frame/fast-unstake/src/benchmarking.rs +++ b/frame/fast-unstake/src/benchmarking.rs @@ -31,13 +31,11 @@ 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 create_unexposed_nominators() -> Vec { - (0..T::BatchSize::get()) +fn create_unexposed_batch(batch_size: u32) -> Vec { + (0..batch_size) .map(|i| { let account = frame_benchmarking::account::("unexposed_nominator", i, USER_SEED); @@ -76,7 +74,7 @@ fn setup_staking(v: u32, until: EraIndex) { .collect::>(); for era in 0..=until { - let others = (0..DEFAULT_BACKER_PER_VALIDATOR) + let others = (0..T::MaxBackersPerValidator::get()) .map(|s| { let who = frame_benchmarking::account::("nominator", era, s); let value = ed; @@ -97,8 +95,10 @@ fn on_idle_full_block() { benchmarks! { // on_idle, we don't check anyone, but fully unbond them. on_idle_unstake { + let b in 1 .. T::BatchSize::get(); + ErasToCheckPerBlock::::put(1); - for who in create_unexposed_nominators::() { + for who in create_unexposed_batch::(b).into_iter() { assert_ok!(FastUnstake::::register_fast_unstake( RawOrigin::Signed(who.clone()).into(), )); @@ -114,7 +114,7 @@ benchmarks! { checked, stashes, .. - }) if checked.len() == 1 && stashes.len() as u32 == T::BatchSize::get() + }) if checked.len() == 1 && stashes.len() as u32 == b )); } : { @@ -123,25 +123,23 @@ benchmarks! { verify { assert!(matches!( fast_unstake_events::().last(), - Some(Event::BatchFinished) + Some(Event::BatchFinished { size: b }) )); } - // on_idle, when we check some number of eras, + // on_idle, when we check some number of eras and the queue is already set. on_idle_check { - // number of eras multiplied by validators in that era. - let x in (T::Staking::bonding_duration() * 1) .. (T::Staking::bonding_duration() * MAX_VALIDATORS); - - let u = T::Staking::bonding_duration(); - let v = x / u; + let v in 1 .. 256; + let b in 1 .. T::BatchSize::get(); + let u = T::MaxErasToCheckPerBlock::get().min(T::Staking::bonding_duration()); ErasToCheckPerBlock::::put(u); T::Staking::set_current_era(u); - // setup staking with v validators and u eras of data (0..=u) + // setup staking with v validators and u eras of data (0..=u+1) setup_staking::(v, u); - let stashes = create_unexposed_nominators::().into_iter().map(|s| { + let stashes = create_unexposed_batch::(b).into_iter().map(|s| { assert_ok!(FastUnstake::::register_fast_unstake( RawOrigin::Signed(s.clone()).into(), )); @@ -150,6 +148,8 @@ benchmarks! { // no one is queued thus far. assert_eq!(Head::::get(), None); + + Head::::put(UnstakeRequest { stashes: stashes.clone().try_into().unwrap(), checked: Default::default() }); } : { on_idle_full_block::(); @@ -167,7 +167,7 @@ benchmarks! { register_fast_unstake { ErasToCheckPerBlock::::put(1); - let who = create_unexposed_nominators::().get(0).cloned().unwrap(); + let who = create_unexposed_batch::(1).get(0).cloned().unwrap(); whitelist_account!(who); assert_eq!(Queue::::count(), 0); @@ -179,7 +179,7 @@ benchmarks! { deregister { ErasToCheckPerBlock::::put(1); - let who = create_unexposed_nominators::().get(0).cloned().unwrap(); + let who = create_unexposed_batch::(1).get(0).cloned().unwrap(); assert_ok!(FastUnstake::::register_fast_unstake( RawOrigin::Signed(who.clone()).into(), )); @@ -194,7 +194,7 @@ benchmarks! { control { let origin = ::ControlOrigin::successful_origin(); } - : _(origin, 128) + : _(origin, T::MaxErasToCheckPerBlock::get()) 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 index c0bffc4427a11..82454a4b8ac7d 100644 --- a/frame/fast-unstake/src/lib.rs +++ b/frame/fast-unstake/src/lib.rs @@ -86,12 +86,9 @@ pub mod pallet { traits::{Defensive, ReservableCurrency, StorageVersion}, }; use frame_system::pallet_prelude::*; - use sp_runtime::{ - traits::{Saturating, Zero}, - DispatchResult, - }; + use sp_runtime::{traits::Zero, DispatchResult}; use sp_staking::{EraIndex, StakingInterface}; - use sp_std::{collections::btree_set::BTreeSet, prelude::*, vec::Vec}; + use sp_std::{prelude::*, vec::Vec}; pub use weights::WeightInfo; #[derive(scale_info::TypeInfo, codec::Encode, codec::Decode, codec::MaxEncodedLen)] @@ -138,6 +135,14 @@ pub mod pallet { /// The weight information of this pallet. type WeightInfo: WeightInfo; + + /// Maximum value for `ErasToCheckPerBlock`. This should be as close as possible, but more + /// than the actual value, in order to have accurate benchmarks. + type MaxErasToCheckPerBlock: Get; + + /// Use only for benchmarking. + #[cfg(feature = "runtime-benchmarks")] + type MaxBackersPerValidator: Get; } /// The current "head of the queue" being unstaked. @@ -173,11 +178,11 @@ pub mod pallet { InternalError, /// A batch was partially checked for the given eras, but the process did not finish. BatchChecked { eras: Vec }, - /// A batch was terminated. + /// A batch of a given size 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, + BatchFinished { size: u32 }, } #[pallet::error] @@ -208,6 +213,31 @@ pub mod pallet { Self::do_on_idle(remaining_weight) } + + fn integrity_test() { + sp_std::if_std! { + sp_io::TestExternalities::new_empty().execute_with(|| { + // ensure that the value of `ErasToCheckPerBlock` is less than + // `T::MaxErasToCheckPerBlock`. + assert!( + ErasToCheckPerBlock::::get() <= T::MaxErasToCheckPerBlock::get(), + "the value of `ErasToCheckPerBlock` is greater than `T::MaxErasToCheckPerBlock`", + ); + }); + } + } + + #[cfg(feature = "try-runtime")] + fn try_state(_n: T::BlockNumber) -> Result<(), &'static str> { + // ensure that the value of `ErasToCheckPerBlock` is less than + // `T::MaxErasToCheckPerBlock`. + assert!( + ErasToCheckPerBlock::::get() <= T::MaxErasToCheckPerBlock::get(), + "the value of `ErasToCheckPerBlock` is greater than `T::MaxErasToCheckPerBlock`", + ); + + Ok(()) + } } #[pallet::call] @@ -288,9 +318,10 @@ pub mod 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 { + pub fn control(origin: OriginFor, eras_to_check: EraIndex) -> DispatchResult { let _ = T::ControlOrigin::ensure_origin(origin)?; - ErasToCheckPerBlock::::put(unchecked_eras_to_check); + ensure!(eras_to_check <= T::MaxErasToCheckPerBlock::get(), Error::::CallNotAllowed); + ErasToCheckPerBlock::::put(eras_to_check); Ok(()) } } @@ -324,27 +355,38 @@ pub mod pallet { /// 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(); + // any weight that is unaccounted for + let mut unaccounted_weight = Weight::from_ref_time(0); + + let eras_to_check_per_block = ErasToCheckPerBlock::::get(); if eras_to_check_per_block.is_zero() { - return T::DbWeight::get().reads(1) + return T::DbWeight::get().reads(1).saturating_add(unaccounted_weight) } // 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 = T::Staking::desired_validator_count(); + let (next_batch_size, reads_from_queue) = Head::::get() + .map_or((Queue::::count().min(T::BatchSize::get()), true), |head| { + (head.stashes.len() as u32, false) + }); // 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()) + let max_weight = |v, b| { + // NOTE: this potentially under-counts by up to `BatchSize` reads from the queue. + ::WeightInfo::on_idle_check(v, b) + .max(::WeightInfo::on_idle_unstake(b)) + .saturating_add(if reads_from_queue { + T::DbWeight::get().reads(next_batch_size.into()) + } else { + Zero::zero() + }) }; - 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 max_weight(validator_count, next_batch_size).any_gt(remaining_weight) { + log!(debug, "early exit because eras_to_check_per_block is zero"); + return T::DbWeight::get().reads(3).saturating_add(unaccounted_weight) } if T::Staking::election_ongoing() { @@ -352,7 +394,7 @@ pub mod pallet { // 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) + return T::DbWeight::get().reads(4).saturating_add(unaccounted_weight) } let UnstakeRequest { stashes, mut checked } = match Head::::take().or_else(|| { @@ -362,6 +404,9 @@ pub mod pallet { .collect::>() .try_into() .expect("take ensures bound is met; qed"); + unaccounted_weight.saturating_accrue( + T::DbWeight::get().reads_writes(stashes.len() as u64, stashes.len() as u64), + ); if stashes.is_empty() { None } else { @@ -377,10 +422,11 @@ pub mod pallet { log!( debug, - "checking {:?} stashes, eras_to_check_per_block = {:?}, remaining_weight = {:?}", + "checking {:?} stashes, eras_to_check_per_block = {:?}, checked {:?}, remaining_weight = {:?}", stashes.len(), eras_to_check_per_block, - remaining_weight + checked, + remaining_weight, ); // the range that we're allowed to check in this round. @@ -431,11 +477,10 @@ pub mod pallet { } }; - let check_stash = |stash, deposit, eras_checked: &mut BTreeSet| { - let is_exposed = unchecked_eras_to_check.iter().any(|e| { - eras_checked.insert(*e); - T::Staking::is_exposed_in_era(&stash, e) - }); + let check_stash = |stash, deposit| { + let is_exposed = unchecked_eras_to_check + .iter() + .any(|e| T::Staking::is_exposed_in_era(&stash, e)); if is_exposed { T::Currency::slash_reserved(&stash, deposit); @@ -448,20 +493,16 @@ 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. + // `stashes` are not exposed in any era now -- we can let go of them now. + let size = stashes.len() as u32; stashes.into_iter().for_each(|(stash, deposit)| unstake_stash(stash, deposit)); - Self::deposit_event(Event::::BatchFinished); - ::WeightInfo::on_idle_unstake() + Self::deposit_event(Event::::BatchFinished { size }); + ::WeightInfo::on_idle_unstake(size).saturating_add(unaccounted_weight) } else { - // eras checked so far. - let mut eras_checked = BTreeSet::::new(); - 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) - }) + .filter(|(stash, deposit)| check_stash(stash.clone(), *deposit)) .collect::>() .try_into() .expect("filter can only lessen the length; still in bound; qed"); @@ -469,8 +510,8 @@ pub mod pallet { log!( debug, - "checked {:?} eras, pre stashes: {:?}, post: {:?}", - eras_checked.len(), + "checked {:?}, pre stashes: {:?}, post: {:?}", + unchecked_eras_to_check, pre_length, post_length, ); @@ -478,7 +519,7 @@ pub mod pallet { match checked.try_extend(unchecked_eras_to_check.clone().into_iter()) { Ok(_) => if stashes.is_empty() { - Self::deposit_event(Event::::BatchFinished); + Self::deposit_event(Event::::BatchFinished { size: 0 }); } else { Head::::put(UnstakeRequest { stashes, checked }); Self::deposit_event(Event::::BatchChecked { @@ -491,9 +532,8 @@ pub mod pallet { }, } - ::WeightInfo::on_idle_check( - validator_count * eras_checked.len() as u32, - ) + ::WeightInfo::on_idle_check(validator_count, pre_length as u32) + .saturating_add(unaccounted_weight) } } } diff --git a/frame/fast-unstake/src/mock.rs b/frame/fast-unstake/src/mock.rs index 3f974e5e1a9d6..38cf41fdebe8b 100644 --- a/frame/fast-unstake/src/mock.rs +++ b/frame/fast-unstake/src/mock.rs @@ -185,6 +185,9 @@ impl fast_unstake::Config for Runtime { type ControlOrigin = frame_system::EnsureRoot; type BatchSize = BatchSize; type WeightInfo = (); + type MaxErasToCheckPerBlock = ConstU32<16>; + #[cfg(feature = "runtime-benchmarks")] + type MaxBackersPerValidator = ConstU32<128>; } type Block = frame_system::mocking::MockBlock; diff --git a/frame/fast-unstake/src/tests.rs b/frame/fast-unstake/src/tests.rs index 522aa1d0fac28..3e62146ae299f 100644 --- a/frame/fast-unstake/src/tests.rs +++ b/frame/fast-unstake/src/tests.rs @@ -18,7 +18,7 @@ //! Tests for pallet-fast-unstake. use super::*; -use crate::{mock::*, types::*, weights::WeightInfo, Event}; +use crate::{mock::*, types::*, Event}; use frame_support::{assert_noop, assert_ok, bounded_vec, pallet_prelude::*, traits::Currency}; use pallet_staking::{CurrentEra, RewardDestination}; @@ -236,120 +236,6 @@ mod on_idle { }); } - #[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))); - assert_eq!(Queue::::get(1), Some(Deposit::get())); - - 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::BatchChecked { eras: vec![3] }] - ); - assert_eq!( - Head::::get(), - Some(UnstakeRequest { - stashes: bounded_vec![(1, Deposit::get())], - checked: bounded_vec![3] - }) - ); - - // 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::BatchChecked { eras: bounded_vec![2] }] - ); - assert_eq!( - Head::::get(), - Some(UnstakeRequest { - stashes: bounded_vec![(1, Deposit::get())], - checked: bounded_vec![3, 2] - }) - ); - - // 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::BatchChecked { eras: vec![1, 0] }] - ); - assert_eq!( - Head::::get(), - Some(UnstakeRequest { - stashes: bounded_vec![(1, Deposit::get())], - checked: bounded_vec![3, 2, 1, 0] - }) - ); - - // 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 { - stashes: bounded_vec![(1, Deposit::get())], - checked: bounded_vec![3, 2, 1, 0] - }) - ); - - // 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, result: Ok(()) }, Event::BatchFinished], - ); - assert_eq!(Head::::get(), None,); - - assert_unstaked(&1); - }); - } - #[test] fn if_head_not_set_one_random_fetched_from_queue() { ExtBuilder::default().build_and_execute(|| { @@ -410,7 +296,7 @@ mod on_idle { vec![ Event::BatchChecked { eras: vec![3, 2, 1, 0] }, Event::Unstaked { stash: 1, result: Ok(()) }, - Event::BatchFinished, + Event::BatchFinished { size: 1 }, Event::BatchChecked { eras: vec![3, 2, 1, 0] } ] ); @@ -458,10 +344,10 @@ mod on_idle { vec![ Event::BatchChecked { eras: vec![3, 2, 1, 0] }, Event::Unstaked { stash: 1, result: Ok(()) }, - Event::BatchFinished, + Event::BatchFinished { size: 1 }, Event::BatchChecked { eras: vec![3, 2, 1, 0] }, Event::Unstaked { stash: 3, result: Ok(()) }, - Event::BatchFinished, + Event::BatchFinished { size: 1 }, ] ); @@ -503,7 +389,7 @@ mod on_idle { vec![ Event::BatchChecked { eras: vec![3, 2, 1, 0] }, Event::Unstaked { stash: 1, result: Ok(()) }, - Event::BatchFinished + Event::BatchFinished { size: 1 } ] ); assert_unstaked(&1); @@ -545,7 +431,7 @@ mod on_idle { vec![ Event::BatchChecked { eras: vec![3, 2, 1, 0] }, Event::Unstaked { stash: 1, result: Ok(()) }, - Event::BatchFinished + Event::BatchFinished { size: 1 } ] ); assert_unstaked(&1); @@ -620,7 +506,7 @@ mod on_idle { Event::BatchChecked { eras: vec![1] }, Event::BatchChecked { eras: vec![0] }, Event::Unstaked { stash: 1, result: Ok(()) }, - Event::BatchFinished + Event::BatchFinished { size: 1 } ] ); assert_unstaked(&1); @@ -704,7 +590,7 @@ mod on_idle { Event::BatchChecked { eras: vec![0] }, Event::BatchChecked { eras: vec![4] }, Event::Unstaked { stash: 1, result: Ok(()) }, - Event::BatchFinished + Event::BatchFinished { size: 1 } ] ); assert_unstaked(&1); @@ -799,7 +685,7 @@ mod on_idle { Event::BatchChecked { eras: vec![4] }, Event::BatchChecked { eras: vec![1] }, Event::Unstaked { stash: 1, result: Ok(()) }, - Event::BatchFinished + Event::BatchFinished { size: 1 } ] ); @@ -843,7 +729,7 @@ mod on_idle { Event::BatchChecked { eras: vec![3] }, Event::BatchChecked { eras: vec![2] }, Event::Slashed { stash: exposed, amount: Deposit::get() }, - Event::BatchFinished + Event::BatchFinished { size: 0 } ] ); }); @@ -879,7 +765,7 @@ mod on_idle { vec![ Event::BatchChecked { eras: vec![3, 2] }, Event::Slashed { stash: exposed, amount: Deposit::get() }, - Event::BatchFinished + Event::BatchFinished { size: 0 } ] ); }); @@ -910,7 +796,10 @@ mod on_idle { assert_eq!( fast_unstake_events_since_last_call(), - vec![Event::Slashed { stash: 100, amount: Deposit::get() }, Event::BatchFinished] + vec![ + Event::Slashed { stash: 100, amount: Deposit::get() }, + Event::BatchFinished { size: 0 } + ] ); }); } @@ -946,7 +835,7 @@ mod on_idle { vec![ Event::BatchChecked { eras: vec![3, 2, 1, 0] }, Event::Unstaked { stash: 42, result: Ok(()) }, - Event::BatchFinished + Event::BatchFinished { size: 1 } ] ); }); @@ -1001,7 +890,7 @@ mod batched { Event::Unstaked { stash: 1, result: Ok(()) }, Event::Unstaked { stash: 5, result: Ok(()) }, Event::Unstaked { stash: 7, result: Ok(()) }, - Event::BatchFinished + Event::BatchFinished { size: 3 } ] ); }); @@ -1067,7 +956,7 @@ mod batched { Event::Unstaked { stash: 1, result: Ok(()) }, Event::Unstaked { stash: 5, result: Ok(()) }, Event::Unstaked { stash: 7, result: Ok(()) }, - Event::BatchFinished + Event::BatchFinished { size: 3 } ] ); }); @@ -1132,7 +1021,7 @@ mod batched { Event::BatchChecked { eras: vec![1, 0] }, Event::Unstaked { stash: 1, result: Ok(()) }, Event::Unstaked { stash: 3, result: Ok(()) }, - Event::BatchFinished + Event::BatchFinished { size: 2 } ] ); }); @@ -1191,10 +1080,32 @@ mod batched { Event::Slashed { stash: 666, amount: Deposit::get() }, Event::BatchChecked { eras: vec![3] }, Event::Slashed { stash: 667, amount: Deposit::get() }, - Event::BatchFinished, + Event::BatchFinished { size: 0 }, Event::BatchChecked { eras: vec![3] } ] ); }); } } + +#[test] +fn kusama_estimate() { + use crate::WeightInfo; + let block_time = frame_support::weights::Weight::from_ref_time( + frame_support::weights::constants::WEIGHT_REF_TIME_PER_SECOND * 2, + ) + .ref_time() as f32; + let on_idle = crate::weights::SubstrateWeight::::on_idle_check(1000, 64).ref_time() as f32; + dbg!(block_time, on_idle, on_idle / block_time); +} + +#[test] +fn polkadot_estimate() { + use crate::WeightInfo; + let block_time = frame_support::weights::Weight::from_ref_time( + frame_support::weights::constants::WEIGHT_REF_TIME_PER_SECOND * 2, + ) + .ref_time() as f32; + let on_idle = crate::weights::SubstrateWeight::::on_idle_check(300, 64).ref_time() as f32; + dbg!(block_time, on_idle, on_idle / block_time); +} diff --git a/frame/fast-unstake/src/weights.rs b/frame/fast-unstake/src/weights.rs index 6001250e8c24d..f7d0cacba0bcf 100644 --- a/frame/fast-unstake/src/weights.rs +++ b/frame/fast-unstake/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2023 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_fast_unstake //! //! 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: 2023-01-25, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `runner-b3zmxxc-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! 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_fast_unstake // --extrinsic=* // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/fast-unstake/src/weights.rs +// --json-file=/builds/parity/mirrors/substrate/.git/.artifacts/bench.json +// --pallet=pallet_fast_unstake +// --chain=dev // --header=./HEADER-APACHE2 +// --output=./frame/fast-unstake/src/weights.rs // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -47,8 +48,8 @@ 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 on_idle_unstake(b: u32, ) -> Weight; + fn on_idle_check(v: u32, b: u32, ) -> Weight; fn register_fast_unstake() -> Weight; fn deregister() -> Weight; fn control() -> Weight; @@ -59,8 +60,9 @@ 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: FastUnstake CounterForQueue (r:1 w:0) + // Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) // Storage: Staking CurrentEra (r:1 w:0) // Storage: Staking SlashingSpans (r:1 w:0) // Storage: Staking Bonded (r:1 w:1) @@ -70,29 +72,36 @@ impl WeightInfo for SubstrateWeight { // 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 { - // 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)) + /// The range of component `b` is `[1, 64]`. + fn on_idle_unstake(b: u32, ) -> Weight { + // Minimum execution time: 92_833 nanoseconds. + Weight::from_ref_time(62_136_346) + // Standard Error: 25_541 + .saturating_add(Weight::from_ref_time(42_904_859).saturating_mul(b.into())) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().reads((6_u64).saturating_mul(b.into()))) + .saturating_add(T::DbWeight::get().writes(1)) + .saturating_add(T::DbWeight::get().writes((5_u64).saturating_mul(b.into()))) } // 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: FastUnstake CounterForQueue (r:1 w:0) + // Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) // 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 { - // 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: Staking ErasStakers (r:2 w:0) + /// The range of component `v` is `[1, 256]`. + /// The range of component `b` is `[1, 64]`. + fn on_idle_check(v: u32, b: u32, ) -> Weight { + // Minimum execution time: 1_775_293 nanoseconds. + Weight::from_ref_time(1_787_133_000) + // Standard Error: 17_109_142 + .saturating_add(Weight::from_ref_time(546_766_552).saturating_mul(v.into())) + // Standard Error: 68_455_625 + .saturating_add(Weight::from_ref_time(2_135_980_830).saturating_mul(b.into())) + .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) + .saturating_add(T::DbWeight::get().writes(1)) } // Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) // Storage: Staking Ledger (r:1 w:1) @@ -109,10 +118,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: FastUnstake CounterForQueue (r:1 w:1) fn register_fast_unstake() -> Weight { - // 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)) + // Minimum execution time: 124_849 nanoseconds. + Weight::from_ref_time(128_176_000) + .saturating_add(T::DbWeight::get().reads(14)) + .saturating_add(T::DbWeight::get().writes(9)) } // Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) // Storage: Staking Ledger (r:1 w:0) @@ -120,16 +129,16 @@ impl WeightInfo for SubstrateWeight { // Storage: FastUnstake Head (r:1 w:0) // Storage: FastUnstake CounterForQueue (r:1 w:1) fn deregister() -> Weight { - // 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)) + // Minimum execution time: 48_246 nanoseconds. + Weight::from_ref_time(49_720_000) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(2)) } // Storage: FastUnstake ErasToCheckPerBlock (r:0 w:1) fn control() -> Weight { - // Minimum execution time: 4_814 nanoseconds. - Weight::from_ref_time(4_997_000 as u64) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + // Minimum execution time: 4_611 nanoseconds. + Weight::from_ref_time(4_844_000) + .saturating_add(T::DbWeight::get().writes(1)) } } @@ -137,8 +146,9 @@ impl WeightInfo for SubstrateWeight { 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: FastUnstake CounterForQueue (r:1 w:0) + // Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) // Storage: Staking CurrentEra (r:1 w:0) // Storage: Staking SlashingSpans (r:1 w:0) // Storage: Staking Bonded (r:1 w:1) @@ -148,29 +158,36 @@ impl WeightInfo for () { // 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 { - // 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)) + /// The range of component `b` is `[1, 64]`. + fn on_idle_unstake(b: u32, ) -> Weight { + // Minimum execution time: 92_833 nanoseconds. + Weight::from_ref_time(62_136_346) + // Standard Error: 25_541 + .saturating_add(Weight::from_ref_time(42_904_859).saturating_mul(b.into())) + .saturating_add(RocksDbWeight::get().reads(6)) + .saturating_add(RocksDbWeight::get().reads((6_u64).saturating_mul(b.into()))) + .saturating_add(RocksDbWeight::get().writes(1)) + .saturating_add(RocksDbWeight::get().writes((5_u64).saturating_mul(b.into()))) } // 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: FastUnstake CounterForQueue (r:1 w:0) + // Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) // 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 { - // 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: Staking ErasStakers (r:2 w:0) + /// The range of component `v` is `[1, 256]`. + /// The range of component `b` is `[1, 64]`. + fn on_idle_check(v: u32, b: u32, ) -> Weight { + // Minimum execution time: 1_775_293 nanoseconds. + Weight::from_ref_time(1_787_133_000) + // Standard Error: 17_109_142 + .saturating_add(Weight::from_ref_time(546_766_552).saturating_mul(v.into())) + // Standard Error: 68_455_625 + .saturating_add(Weight::from_ref_time(2_135_980_830).saturating_mul(b.into())) + .saturating_add(RocksDbWeight::get().reads(7)) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(v.into()))) + .saturating_add(RocksDbWeight::get().writes(1)) } // Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) // Storage: Staking Ledger (r:1 w:1) @@ -187,10 +204,10 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: FastUnstake CounterForQueue (r:1 w:1) fn register_fast_unstake() -> Weight { - // 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)) + // Minimum execution time: 124_849 nanoseconds. + Weight::from_ref_time(128_176_000) + .saturating_add(RocksDbWeight::get().reads(14)) + .saturating_add(RocksDbWeight::get().writes(9)) } // Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) // Storage: Staking Ledger (r:1 w:0) @@ -198,15 +215,15 @@ impl WeightInfo for () { // Storage: FastUnstake Head (r:1 w:0) // Storage: FastUnstake CounterForQueue (r:1 w:1) fn deregister() -> Weight { - // 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)) + // Minimum execution time: 48_246 nanoseconds. + Weight::from_ref_time(49_720_000) + .saturating_add(RocksDbWeight::get().reads(5)) + .saturating_add(RocksDbWeight::get().writes(2)) } // Storage: FastUnstake ErasToCheckPerBlock (r:0 w:1) fn control() -> Weight { - // Minimum execution time: 4_814 nanoseconds. - Weight::from_ref_time(4_997_000 as u64) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + // Minimum execution time: 4_611 nanoseconds. + Weight::from_ref_time(4_844_000) + .saturating_add(RocksDbWeight::get().writes(1)) } } From 9db957cea255802d50231347ebef393d0707b909 Mon Sep 17 00:00:00 2001 From: Koute Date: Thu, 26 Jan 2023 14:38:00 +0900 Subject: [PATCH 331/715] Rework the trie cache (#12982) * Rework the trie cache * Align `state-machine` tests * Bump `schnellru` to 0.1.1 * Fix off-by-one * Align to review comments * Bump `ahash` to 0.8.2 * Bump `schnellru` to 0.2.0 * Bump `schnellru` to 0.2.1 * Remove unnecessary bound * Remove unnecessary loop when calculating maximum memory usage * Remove unnecessary `mut`s --- Cargo.lock | 8 +- client/db/src/bench.rs | 2 +- client/db/src/lib.rs | 2 +- client/finality-grandpa/Cargo.toml | 2 +- client/network-gossip/Cargo.toml | 2 +- primitives/state-machine/src/trie_backend.rs | 20 +- primitives/trie/Cargo.toml | 6 +- primitives/trie/src/cache/mod.rs | 576 ++++++++--- primitives/trie/src/cache/shared_cache.rs | 948 +++++++++++-------- 9 files changed, 1016 insertions(+), 550 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 53e5d4882b9dd..7c412030d560c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8383,7 +8383,7 @@ dependencies = [ name = "sc-finality-grandpa" version = "0.10.0-dev" dependencies = [ - "ahash 0.7.6", + "ahash 0.8.2", "array-bytes", "assert_matches", "async-trait", @@ -8583,7 +8583,7 @@ dependencies = [ name = "sc-network-gossip" version = "0.10.0-dev" dependencies = [ - "ahash 0.7.6", + "ahash 0.8.2", "futures", "futures-timer", "libp2p", @@ -10352,18 +10352,18 @@ dependencies = [ name = "sp-trie" version = "7.0.0" dependencies = [ - "ahash 0.7.6", + "ahash 0.8.2", "array-bytes", "criterion", "hash-db", "hashbrown 0.12.3", "lazy_static", - "lru", "memory-db", "nohash-hasher", "parity-scale-codec", "parking_lot 0.12.1", "scale-info", + "schnellru", "sp-core", "sp-runtime", "sp-std", diff --git a/client/db/src/bench.rs b/client/db/src/bench.rs index 13d91fff0b555..e53209f27706c 100644 --- a/client/db/src/bench.rs +++ b/client/db/src/bench.rs @@ -110,7 +110,7 @@ impl BenchmarkingState { 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)), + shared_trie_cache: SharedTrieCache::new(CacheSize::new(0)), }; state.add_whitelist_to_tracker(); diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index 09ccfef1cc28b..f217eb6480abc 100644 --- a/client/db/src/lib.rs +++ b/client/db/src/lib.rs @@ -1243,7 +1243,7 @@ impl Backend { 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)) + SharedTrieCache::new(sp_trie::cache::CacheSize::new(maximum_size)) }), }; diff --git a/client/finality-grandpa/Cargo.toml b/client/finality-grandpa/Cargo.toml index 9a31a1d4bf6a7..8a4e0449f2d1c 100644 --- a/client/finality-grandpa/Cargo.toml +++ b/client/finality-grandpa/Cargo.toml @@ -14,7 +14,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -ahash = "0.7.6" +ahash = "0.8.2" array-bytes = "4.1" async-trait = "0.1.57" dyn-clone = "1.0" diff --git a/client/network-gossip/Cargo.toml b/client/network-gossip/Cargo.toml index ef23062768d1e..7811e86c095ba 100644 --- a/client/network-gossip/Cargo.toml +++ b/client/network-gossip/Cargo.toml @@ -14,7 +14,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -ahash = "0.7.6" +ahash = "0.8.2" futures = "0.3.21" futures-timer = "3.0.1" libp2p = "0.50.0" diff --git a/primitives/state-machine/src/trie_backend.rs b/primitives/state-machine/src/trie_backend.rs index da4250b6ba3e1..ff5cce24c5124 100644 --- a/primitives/state-machine/src/trie_backend.rs +++ b/primitives/state-machine/src/trie_backend.rs @@ -412,19 +412,19 @@ pub mod tests { fn $name() { let parameters = vec![ (StateVersion::V0, None, None), - (StateVersion::V0, Some(SharedCache::new(CacheSize::Unlimited)), None), + (StateVersion::V0, Some(SharedCache::new(CacheSize::unlimited())), None), (StateVersion::V0, None, Some(Recorder::default())), ( StateVersion::V0, - Some(SharedCache::new(CacheSize::Unlimited)), + Some(SharedCache::new(CacheSize::unlimited())), Some(Recorder::default()), ), (StateVersion::V1, None, None), - (StateVersion::V1, Some(SharedCache::new(CacheSize::Unlimited)), None), + (StateVersion::V1, Some(SharedCache::new(CacheSize::unlimited())), None), (StateVersion::V1, None, Some(Recorder::default())), ( StateVersion::V1, - Some(SharedCache::new(CacheSize::Unlimited)), + Some(SharedCache::new(CacheSize::unlimited())), Some(Recorder::default()), ), ]; @@ -760,7 +760,7 @@ pub mod tests { .clone() .for_each(|i| assert_eq!(trie.storage(&[i]).unwrap().unwrap(), vec![i; size_content])); - for cache in [Some(SharedTrieCache::new(CacheSize::Unlimited)), None] { + 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 { @@ -793,7 +793,7 @@ pub mod tests { 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] { + 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 { @@ -870,7 +870,7 @@ pub mod tests { assert_eq!(in_memory.child_storage(child_info_2, &[i]).unwrap().unwrap(), vec![i]) }); - for cache in [Some(SharedTrieCache::new(CacheSize::Unlimited)), None] { + 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); @@ -1002,7 +1002,7 @@ pub mod tests { nodes }; - let cache = SharedTrieCache::::new(CacheSize::Unlimited); + 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); @@ -1093,7 +1093,7 @@ pub mod tests { #[test] fn new_data_is_added_to_the_cache() { - let shared_cache = SharedTrieCache::new(CacheSize::Unlimited); + let shared_cache = SharedTrieCache::new(CacheSize::unlimited()); let new_data = vec![ (&b"new_data0"[..], Some(&b"0"[..])), (&b"new_data1"[..], Some(&b"1"[..])), @@ -1159,7 +1159,7 @@ pub mod tests { 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] { + 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); diff --git a/primitives/trie/Cargo.toml b/primitives/trie/Cargo.toml index 3f045a1cb216d..78b0b5d1bbda3 100644 --- a/primitives/trie/Cargo.toml +++ b/primitives/trie/Cargo.toml @@ -18,12 +18,11 @@ name = "bench" harness = false [dependencies] -ahash = { version = "0.7.6", optional = true } +ahash = { version = "0.8.2", optional = true } codec = { package = "parity-scale-codec", version = "3.2.2", 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.8.1", optional = true } 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 } @@ -34,6 +33,7 @@ trie-db = { version = "0.24.0", default-features = false } trie-root = { version = "0.17.0", default-features = false } sp-core = { version = "7.0.0", default-features = false, path = "../core" } sp-std = { version = "5.0.0", default-features = false, path = "../std" } +schnellru = { version = "0.2.1", optional = true } [dev-dependencies] array-bytes = "4.1" @@ -50,7 +50,7 @@ std = [ "hashbrown", "hash-db/std", "lazy_static", - "lru", + "schnellru", "memory-db/std", "nohash-hasher", "parking_lot", diff --git a/primitives/trie/src/cache/mod.rs b/primitives/trie/src/cache/mod.rs index 85539cf626857..3c1e5b8d0ff0b 100644 --- a/primitives/trie/src/cache/mod.rs +++ b/primitives/trie/src/cache/mod.rs @@ -36,13 +36,17 @@ 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 parking_lot::{Mutex, MutexGuard}; +use schnellru::LruMap; +use shared_cache::{ValueCacheKey, ValueCacheRef}; use std::{ - collections::{hash_map::Entry as MapEntry, HashMap}, - sync::Arc, + collections::HashMap, + sync::{ + atomic::{AtomicU64, Ordering}, + Arc, + }, + time::Duration, }; use trie_db::{node::NodeOwned, CachedValue}; @@ -50,29 +54,267 @@ mod shared_cache; pub use shared_cache::SharedTrieCache; -use self::shared_cache::{SharedTrieCacheInner, ValueCacheKeyHash}; +use self::shared_cache::ValueCacheKeyHash; const LOG_TARGET: &str = "trie-cache"; -/// The size of the cache. +/// The maximum amount of time we'll wait trying to acquire the shared cache lock +/// when the local cache is dropped and synchronized with the share cache. +/// +/// This is just a failsafe; normally this should never trigger. +const SHARED_CACHE_WRITE_LOCK_TIMEOUT: Duration = Duration::from_millis(100); + +/// The maximum number of existing keys in the shared cache that a single local cache +/// can promote to the front of the LRU cache in one go. +/// +/// If we have a big shared cache and the local cache hits all of those keys we don't +/// want to spend forever bumping all of them. +const SHARED_NODE_CACHE_MAX_PROMOTED_KEYS: u32 = 1792; +/// Same as [`SHARED_NODE_CACHE_MAX_PROMOTED_KEYS`]. +const SHARED_VALUE_CACHE_MAX_PROMOTED_KEYS: u32 = 1792; + +/// The maximum portion of the shared cache (in percent) that a single local +/// cache can replace in one go. +/// +/// We don't want a single local cache instance to have the ability to replace +/// everything in the shared cache. +const SHARED_NODE_CACHE_MAX_REPLACE_PERCENT: usize = 33; +/// Same as [`SHARED_NODE_CACHE_MAX_REPLACE_PERCENT`]. +const SHARED_VALUE_CACHE_MAX_REPLACE_PERCENT: usize = 33; + +/// The maximum inline capacity of the local cache, in bytes. +/// +/// This is just an upper limit; since the maps are resized in powers of two +/// their actual size will most likely not exactly match this. +const LOCAL_NODE_CACHE_MAX_INLINE_SIZE: usize = 512 * 1024; +/// Same as [`LOCAL_NODE_CACHE_MAX_INLINE_SIZE`]. +const LOCAL_VALUE_CACHE_MAX_INLINE_SIZE: usize = 512 * 1024; + +/// The maximum size of the memory allocated on the heap by the local cache, in bytes. +const LOCAL_NODE_CACHE_MAX_HEAP_SIZE: usize = 2 * 1024 * 1024; +/// Same as [`LOCAL_NODE_CACHE_MAX_HEAP_SIZE`]. +const LOCAL_VALUE_CACHE_MAX_HEAP_SIZE: usize = 4 * 1024 * 1024; + +/// The size of the shared 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), -} +pub struct CacheSize(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, + /// An unlimited cache size. + pub const fn unlimited() -> Self { + CacheSize(usize::MAX) + } + + /// A cache size `bytes` big. + pub const fn new(bytes: usize) -> Self { + CacheSize(bytes) + } +} + +/// A limiter for the local node cache. This makes sure the local cache doesn't grow too big. +#[derive(Default)] +pub struct LocalNodeCacheLimiter { + /// The current size (in bytes) of data allocated by this cache on the heap. + /// + /// This doesn't include the size of the map itself. + current_heap_size: usize, +} + +impl schnellru::Limiter> for LocalNodeCacheLimiter +where + H: AsRef<[u8]> + std::fmt::Debug, +{ + type KeyToInsert<'a> = H; + type LinkType = u32; + + #[inline] + fn is_over_the_limit(&self, length: usize) -> bool { + // Only enforce the limit if there's more than one element to make sure + // we can always add a new element to the cache. + if length <= 1 { + return false } + + self.current_heap_size > LOCAL_NODE_CACHE_MAX_HEAP_SIZE + } + + #[inline] + fn on_insert<'a>( + &mut self, + _length: usize, + key: H, + cached_node: NodeCached, + ) -> Option<(H, NodeCached)> { + self.current_heap_size += cached_node.heap_size(); + Some((key, cached_node)) + } + + #[inline] + fn on_replace( + &mut self, + _length: usize, + _old_key: &mut H, + _new_key: H, + old_node: &mut NodeCached, + new_node: &mut NodeCached, + ) -> bool { + debug_assert_eq!(_old_key.as_ref().len(), _new_key.as_ref().len()); + self.current_heap_size = + self.current_heap_size + new_node.heap_size() - old_node.heap_size(); + true + } + + #[inline] + fn on_removed(&mut self, _key: &mut H, cached_node: &mut NodeCached) { + self.current_heap_size -= cached_node.heap_size(); + } + + #[inline] + fn on_cleared(&mut self) { + self.current_heap_size = 0; + } + + #[inline] + fn on_grow(&mut self, new_memory_usage: usize) -> bool { + new_memory_usage <= LOCAL_NODE_CACHE_MAX_INLINE_SIZE + } +} + +/// A limiter for the local value cache. This makes sure the local cache doesn't grow too big. +#[derive(Default)] +pub struct LocalValueCacheLimiter { + /// The current size (in bytes) of data allocated by this cache on the heap. + /// + /// This doesn't include the size of the map itself. + current_heap_size: usize, +} + +impl schnellru::Limiter, CachedValue> for LocalValueCacheLimiter +where + H: AsRef<[u8]>, +{ + type KeyToInsert<'a> = ValueCacheRef<'a, H>; + type LinkType = u32; + + #[inline] + fn is_over_the_limit(&self, length: usize) -> bool { + // Only enforce the limit if there's more than one element to make sure + // we can always add a new element to the cache. + if length <= 1 { + return false + } + + self.current_heap_size > LOCAL_VALUE_CACHE_MAX_HEAP_SIZE + } + + #[inline] + fn on_insert( + &mut self, + _length: usize, + key: Self::KeyToInsert<'_>, + value: CachedValue, + ) -> Option<(ValueCacheKey, CachedValue)> { + self.current_heap_size += key.storage_key.len(); + Some((key.into(), value)) + } + + #[inline] + fn on_replace( + &mut self, + _length: usize, + _old_key: &mut ValueCacheKey, + _new_key: ValueCacheRef, + _old_value: &mut CachedValue, + _new_value: &mut CachedValue, + ) -> bool { + debug_assert_eq!(_old_key.storage_key.len(), _new_key.storage_key.len()); + true + } + + #[inline] + fn on_removed(&mut self, key: &mut ValueCacheKey, _: &mut CachedValue) { + self.current_heap_size -= key.storage_key.len(); + } + + #[inline] + fn on_cleared(&mut self) { + self.current_heap_size = 0; + } + + #[inline] + fn on_grow(&mut self, new_memory_usage: usize) -> bool { + new_memory_usage <= LOCAL_VALUE_CACHE_MAX_INLINE_SIZE + } +} + +/// A struct to gather hit/miss stats to aid in debugging the performance of the cache. +#[derive(Default)] +struct HitStats { + shared_hits: AtomicU64, + shared_fetch_attempts: AtomicU64, + local_hits: AtomicU64, + local_fetch_attempts: AtomicU64, +} + +impl std::fmt::Display for HitStats { + fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { + let shared_hits = self.shared_hits.load(Ordering::Relaxed); + let shared_fetch_attempts = self.shared_fetch_attempts.load(Ordering::Relaxed); + let local_hits = self.local_hits.load(Ordering::Relaxed); + let local_fetch_attempts = self.local_fetch_attempts.load(Ordering::Relaxed); + if shared_fetch_attempts == 0 && local_hits == 0 { + write!(fmt, "empty") + } else { + let percent_local = (local_hits as f32 / local_fetch_attempts as f32) * 100.0; + let percent_shared = (shared_hits as f32 / shared_fetch_attempts as f32) * 100.0; + write!( + fmt, + "local hit rate = {}% [{}/{}], shared hit rate = {}% [{}/{}]", + percent_local as u32, + local_hits, + local_fetch_attempts, + percent_shared as u32, + shared_hits, + shared_fetch_attempts + ) + } + } +} + +/// A struct to gather hit/miss stats for the node cache and the value cache. +#[derive(Default)] +struct TrieHitStats { + node_cache: HitStats, + value_cache: HitStats, +} + +/// An internal struct to store the cached trie nodes. +pub(crate) struct NodeCached { + /// The cached node. + pub node: NodeOwned, + /// Whether this node was fetched from the shared cache or not. + pub is_from_shared_cache: bool, +} + +impl NodeCached { + /// Returns the number of bytes allocated on the heap by this node. + fn heap_size(&self) -> usize { + self.node.size_in_bytes() - std::mem::size_of::>() } } +type NodeCacheMap = LruMap, LocalNodeCacheLimiter, schnellru::RandomState>; + +type ValueCacheMap = LruMap< + ValueCacheKey, + CachedValue, + LocalValueCacheLimiter, + BuildNoHashHasher>, +>; + +type ValueAccessSet = + LruMap>; + /// The local trie cache. /// /// This cache should be used per state instance created by the backend. One state instance is @@ -86,21 +328,13 @@ impl CacheSize { 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>, + node_cache: Mutex>, + /// The local cache for the values. - value_cache: Mutex< - HashMap< - ValueCacheKey<'static, H::Out>, - CachedValue, - BuildNoHashHasher>, - >, - >, + value_cache: Mutex>, + /// 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 @@ -109,8 +343,9 @@ pub struct LocalTrieCache { /// 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>>, + shared_value_cache_access: Mutex, + + stats: TrieHitStats, } impl LocalTrieCache { @@ -118,19 +353,18 @@ impl LocalTrieCache { /// /// 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(), + buffered_value: None, }; TrieCache { - shared_inner, + shared_cache: self.shared.clone(), local_cache: self.node_cache.lock(), value_cache, - shared_node_cache_access: self.shared_node_cache_access.lock(), + stats: &self.stats, } } @@ -143,63 +377,89 @@ impl LocalTrieCache { /// would break because of this. pub fn as_trie_db_mut_cache(&self) -> TrieCache<'_, H> { TrieCache { - shared_inner: self.shared.read_lock_inner(), + shared_cache: self.shared.clone(), local_cache: self.node_cache.lock(), value_cache: ValueCache::Fresh(Default::default()), - shared_node_cache_access: self.shared_node_cache_access.lock(), + stats: &self.stats, } } } impl Drop for LocalTrieCache { fn drop(&mut self) { - let mut shared_inner = self.shared.write_lock_inner(); + tracing::debug!( + target: LOG_TARGET, + "Local node trie cache dropped: {}", + self.stats.node_cache + ); + + tracing::debug!( + target: LOG_TARGET, + "Local value trie cache dropped: {}", + self.stats.value_cache + ); - shared_inner - .node_cache_mut() - .update(self.node_cache.lock().drain(), self.shared_node_cache_access.lock().drain()); + let mut shared_inner = match self.shared.write_lock_inner() { + Some(inner) => inner, + None => { + tracing::warn!( + target: LOG_TARGET, + "Timeout while trying to acquire a write lock for the shared trie cache" + ); + return + }, + }; - shared_inner - .value_cache_mut() - .update(self.value_cache.lock().drain(), self.shared_value_cache_access.lock().drain()); + shared_inner.node_cache_mut().update(self.node_cache.get_mut().drain()); + + shared_inner.value_cache_mut().update( + self.value_cache.get_mut().drain(), + self.shared_value_cache_access.get_mut().drain().map(|(key, ())| key), + ); } } /// The abstraction of the value cache for the [`TrieCache`]. -enum ValueCache<'a, H> { +enum ValueCache<'a, H: Hasher> { /// 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>), + 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, + shared_value_cache_access: MutexGuard<'a, ValueAccessSet>, + local_value_cache: MutexGuard<'a, ValueCacheMap>, + storage_root: H::Out, + // The shared value cache needs to be temporarily locked when reading from it + // so we need to clone the value that is returned, but we need to be able to + // return a reference to the value, so we just buffer it here. + buffered_value: Option>, }, } -impl + std::hash::Hash + Eq + Clone + Copy> ValueCache<'_, H> { +impl 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); + shared_cache: &SharedTrieCache, + stats: &HitStats, + ) -> Option<&CachedValue> { + stats.local_fetch_attempts.fetch_add(1, Ordering::Relaxed); + match self { + Self::Fresh(map) => + if let Some(value) = map.get(key) { + stats.local_hits.fetch_add(1, Ordering::Relaxed); + Some(value) + } else { + None + }, + Self::ForStorageRoot { + local_value_cache, + shared_value_cache_access, + storage_root, + buffered_value, + } => { // 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 @@ -207,35 +467,39 @@ impl + std::hash::Hash + Eq + Clone + Copy> ValueCache<'_, H> { // // 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 - }) - }) + + let hash = ValueCacheKey::hash_data(key, storage_root); + + if let Some(value) = local_value_cache + .peek_by_hash(hash.raw(), |existing_key, _| { + existing_key.is_eq(storage_root, key) + }) { + stats.local_hits.fetch_add(1, Ordering::Relaxed); + + return Some(value) + } + + stats.shared_fetch_attempts.fetch_add(1, Ordering::Relaxed); + if let Some(value) = shared_cache.peek_value_by_hash(hash, storage_root, key) { + stats.shared_hits.fetch_add(1, Ordering::Relaxed); + shared_value_cache_access.insert(hash, ()); + *buffered_value = Some(value.clone()); + return buffered_value.as_ref() + } + + None }, } } /// Insert some new `value` under the given `key`. - fn insert(&mut self, key: &[u8], value: CachedValue) { + 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); + local_value_cache.insert(ValueCacheRef::new(key, *storage_root), value); }, } } @@ -247,10 +511,10 @@ impl + std::hash::Hash + Eq + Clone + Copy> ValueCache<'_, H> { /// 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>, + shared_cache: SharedTrieCache, + local_cache: MutexGuard<'a, NodeCacheMap>, + value_cache: ValueCache<'a, H>, + stats: &'a TrieHitStats, } impl<'a, H: Hasher> TrieCache<'a, H> { @@ -267,16 +531,11 @@ impl<'a, H: Hasher> TrieCache<'a, H> { 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); - }); + cache.into_iter().for_each(|(k, v)| { + let hash = ValueCacheKeyHash::from_hasher_and_storage_key(partial_hash.clone(), &k); + let k = ValueCacheRef { storage_root, storage_key: &k, hash }; + value_cache.insert(k, v); + }); } } } @@ -287,53 +546,85 @@ impl<'a, H: Hasher> trie_db::TrieCache> for TrieCache<'a, H> { 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) - } + let mut is_local_cache_hit = true; + self.stats.node_cache.local_fetch_attempts.fetch_add(1, Ordering::Relaxed); - 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)(); + // First try to grab the node from the local cache. + let node = self.local_cache.get_or_insert_fallible(hash, || { + is_local_cache_hit = false; - tracing::trace!( - target: LOG_TARGET, - ?hash, - fetch_successful = node.is_ok(), - "Node not found, needed to fetch it." - ); + // It was not in the local cache; try the shared cache. + self.stats.node_cache.shared_fetch_attempts.fetch_add(1, Ordering::Relaxed); + if let Some(node) = self.shared_cache.peek_node(&hash) { + self.stats.node_cache.shared_hits.fetch_add(1, Ordering::Relaxed); + tracing::trace!(target: LOG_TARGET, ?hash, "Serving node from shared cache"); - Ok(vacant.insert(node?)) - }, + return Ok(NodeCached:: { node: node.clone(), is_from_shared_cache: true }) + } + + // It was not in the shared cache; try fetching it from the database. + match fetch_node() { + Ok(node) => { + tracing::trace!(target: LOG_TARGET, ?hash, "Serving node from database"); + Ok(NodeCached:: { node, is_from_shared_cache: false }) + }, + Err(error) => { + tracing::trace!(target: LOG_TARGET, ?hash, "Serving node from database failed"); + Err(error) + }, + } + }); + + if is_local_cache_hit { + tracing::trace!(target: LOG_TARGET, ?hash, "Serving node from local cache"); + self.stats.node_cache.local_hits.fetch_add(1, Ordering::Relaxed); } + + Ok(&node? + .expect("you can always insert at least one element into the local cache; qed") + .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 mut is_local_cache_hit = true; + self.stats.node_cache.local_fetch_attempts.fetch_add(1, Ordering::Relaxed); - let res = self.local_cache.get(hash); + // First try to grab the node from the local cache. + let cached_node = self.local_cache.get_or_insert_fallible(*hash, || { + is_local_cache_hit = false; - tracing::trace!( - target: LOG_TARGET, - ?hash, - found = res.is_some(), - "Getting node from local cache" - ); + // It was not in the local cache; try the shared cache. + self.stats.node_cache.shared_fetch_attempts.fetch_add(1, Ordering::Relaxed); + if let Some(node) = self.shared_cache.peek_node(&hash) { + self.stats.node_cache.shared_hits.fetch_add(1, Ordering::Relaxed); + tracing::trace!(target: LOG_TARGET, ?hash, "Serving node from shared cache"); - res + Ok(NodeCached:: { node: node.clone(), is_from_shared_cache: true }) + } else { + tracing::trace!(target: LOG_TARGET, ?hash, "Serving node from cache failed"); + + Err(()) + } + }); + + if is_local_cache_hit { + tracing::trace!(target: LOG_TARGET, ?hash, "Serving node from local cache"); + self.stats.node_cache.local_hits.fetch_add(1, Ordering::Relaxed); + } + + match cached_node { + Ok(Some(cached_node)) => Some(&cached_node.node), + Ok(None) => { + unreachable!( + "you can always insert at least one element into the local cache; qed" + ); + }, + Err(()) => None, + } } fn lookup_value_for_key(&mut self, key: &[u8]) -> Option<&CachedValue> { - let res = self.value_cache.get(key, self.shared_inner.value_cache()); + let res = self.value_cache.get(key, &self.shared_cache, &self.stats.value_cache); tracing::trace!( target: LOG_TARGET, @@ -352,7 +643,7 @@ impl<'a, H: Hasher> trie_db::TrieCache> for TrieCache<'a, H> { "Caching value for key", ); - self.value_cache.insert(key.into(), data); + self.value_cache.insert(key, data); } } @@ -369,7 +660,7 @@ mod tests { 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); + const CACHE_SIZE: CacheSize = CacheSize::new(CACHE_SIZE_RAW); fn create_trie() -> (MemoryDB, TrieHash) { let mut db = MemoryDB::default(); @@ -418,7 +709,7 @@ mod tests { 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( + shared_cache.write_lock_inner().unwrap().value_cache_mut().lru.insert( ValueCacheKey::new_value(TEST_DATA[1].0, root), (fake_data.clone(), Default::default()).into(), ); @@ -591,7 +882,7 @@ mod tests { .lru .iter() .map(|d| d.0) - .all(|l| TEST_DATA.iter().any(|d| l.storage_key().unwrap() == d.0))); + .all(|l| TEST_DATA.iter().any(|d| &*l.storage_key == d.0))); // 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. @@ -617,7 +908,7 @@ mod tests { .iter() .take(2) .map(|d| d.0) - .all(|l| { TEST_DATA.iter().take(2).any(|d| l.storage_key().unwrap() == d.0) })); + .all(|l| { TEST_DATA.iter().take(2).any(|d| &*l.storage_key == d.0) })); // Delete the value cache, so that we access the nodes. shared_cache.reset_value_cache(); @@ -684,9 +975,6 @@ mod tests { } } - 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); + assert!(shared_cache.used_memory_size() < CACHE_SIZE_RAW); } } diff --git a/primitives/trie/src/cache/shared_cache.rs b/primitives/trie/src/cache/shared_cache.rs index 9d4d36b83a28a..8c60d5043d062 100644 --- a/primitives/trie/src/cache/shared_cache.rs +++ b/primitives/trie/src/cache/shared_cache.rs @@ -17,15 +17,14 @@ ///! Provides the [`SharedNodeCache`], the [`SharedValueCache`] and the [`SharedTrieCache`] ///! that combines both caches and is exported to the outside. -use super::{CacheSize, LOG_TARGET}; +use super::{CacheSize, NodeCached}; 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 parking_lot::{Mutex, RwLock, RwLockWriteGuard}; +use schnellru::LruMap; use std::{ hash::{BuildHasher, Hasher as _}, - mem, sync::Arc, }; use trie_db::{node::NodeOwned, CachedValue}; @@ -34,94 +33,300 @@ lazy_static::lazy_static! { static ref RANDOM_STATE: ahash::RandomState = ahash::RandomState::default(); } -/// No hashing [`LruCache`]. -type NoHashingLruCache = LruCache>; +pub struct SharedNodeCacheLimiter { + /// The maximum size (in bytes) the cache can hold inline. + /// + /// This space is always consumed whether there are any items in the map or not. + max_inline_size: usize, + + /// The maximum size (in bytes) the cache can hold on the heap. + max_heap_size: usize, + + /// The current size (in bytes) of data allocated by this cache on the heap. + /// + /// This doesn't include the size of the map itself. + heap_size: usize, + + /// A counter with the number of elements that got evicted from the cache. + /// + /// Reset to zero before every update. + items_evicted: usize, + + /// The maximum number of elements that we allow to be evicted. + /// + /// Reset on every update. + max_items_evicted: usize, +} + +impl schnellru::Limiter> for SharedNodeCacheLimiter +where + H: AsRef<[u8]>, +{ + type KeyToInsert<'a> = H; + type LinkType = u32; + + #[inline] + fn is_over_the_limit(&self, _length: usize) -> bool { + // Once we hit the limit of max items evicted this will return `false` and prevent + // any further evictions, but this is fine because the outer loop which inserts + // items into this cache will just detect this and stop inserting new items. + self.items_evicted <= self.max_items_evicted && self.heap_size > self.max_heap_size + } + + #[inline] + fn on_insert( + &mut self, + _length: usize, + key: Self::KeyToInsert<'_>, + node: NodeOwned, + ) -> Option<(H, NodeOwned)> { + let new_item_heap_size = node.size_in_bytes() - std::mem::size_of::>(); + if new_item_heap_size > self.max_heap_size { + // Item's too big to add even if the cache's empty; bail. + return None + } + + self.heap_size += new_item_heap_size; + Some((key, node)) + } + + #[inline] + fn on_replace( + &mut self, + _length: usize, + _old_key: &mut H, + _new_key: H, + old_node: &mut NodeOwned, + new_node: &mut NodeOwned, + ) -> bool { + debug_assert_eq!(_old_key.as_ref(), _new_key.as_ref()); + + let new_item_heap_size = new_node.size_in_bytes() - std::mem::size_of::>(); + if new_item_heap_size > self.max_heap_size { + // Item's too big to add even if the cache's empty; bail. + return false + } + + let old_item_heap_size = old_node.size_in_bytes() - std::mem::size_of::>(); + self.heap_size = self.heap_size - old_item_heap_size + new_item_heap_size; + true + } + + #[inline] + fn on_cleared(&mut self) { + self.heap_size = 0; + } + + #[inline] + fn on_removed(&mut self, _: &mut H, node: &mut NodeOwned) { + self.heap_size -= node.size_in_bytes() - std::mem::size_of::>(); + self.items_evicted += 1; + } + + #[inline] + fn on_grow(&mut self, new_memory_usage: usize) -> bool { + new_memory_usage <= self.max_inline_size + } +} + +pub struct SharedValueCacheLimiter { + /// The maximum size (in bytes) the cache can hold inline. + /// + /// This space is always consumed whether there are any items in the map or not. + max_inline_size: usize, + + /// The maximum size (in bytes) the cache can hold on the heap. + max_heap_size: usize, + + /// The current size (in bytes) of data allocated by this cache on the heap. + /// + /// This doesn't include the size of the map itself. + heap_size: usize, + + /// A set with all of the keys deduplicated to save on memory. + known_storage_keys: HashSet>, + + /// A counter with the number of elements that got evicted from the cache. + /// + /// Reset to zero before every update. + items_evicted: usize, + + /// The maximum number of elements that we allow to be evicted. + /// + /// Reset on every update. + max_items_evicted: usize, +} + +impl schnellru::Limiter, CachedValue> for SharedValueCacheLimiter +where + H: AsRef<[u8]>, +{ + type KeyToInsert<'a> = ValueCacheKey; + type LinkType = u32; + + #[inline] + fn is_over_the_limit(&self, _length: usize) -> bool { + self.items_evicted <= self.max_items_evicted && self.heap_size > self.max_heap_size + } + + #[inline] + fn on_insert( + &mut self, + _length: usize, + mut key: Self::KeyToInsert<'_>, + value: CachedValue, + ) -> Option<(ValueCacheKey, CachedValue)> { + match self.known_storage_keys.entry(key.storage_key.clone()) { + SetEntry::Vacant(entry) => { + let new_item_heap_size = key.storage_key.len(); + if new_item_heap_size > self.max_heap_size { + // Item's too big to add even if the cache's empty; bail. + return None + } + + self.heap_size += new_item_heap_size; + entry.insert(); + }, + SetEntry::Occupied(entry) => { + key.storage_key = entry.get().clone(); + }, + } + + Some((key, value)) + } + + #[inline] + fn on_replace( + &mut self, + _length: usize, + _old_key: &mut ValueCacheKey, + _new_key: ValueCacheKey, + _old_value: &mut CachedValue, + _new_value: &mut CachedValue, + ) -> bool { + debug_assert_eq!(_new_key.storage_key, _old_key.storage_key); + true + } + + #[inline] + fn on_removed(&mut self, key: &mut ValueCacheKey, _: &mut CachedValue) { + if Arc::strong_count(&key.storage_key) == 2 { + // There are only two instances of this key: + // 1) one memoized in `known_storage_keys`, + // 2) one inside the map. + // + // This means that after this remove goes through the `Arc` will be deallocated. + self.heap_size -= key.storage_key.len(); + self.known_storage_keys.remove(&key.storage_key); + } + self.items_evicted += 1; + } + + #[inline] + fn on_cleared(&mut self) { + self.heap_size = 0; + self.known_storage_keys.clear(); + } + + #[inline] + fn on_grow(&mut self, new_memory_usage: usize) -> bool { + new_memory_usage <= self.max_inline_size + } +} + +type SharedNodeCacheMap = + LruMap, SharedNodeCacheLimiter, schnellru::RandomState>; /// The shared node cache. /// -/// Internally this stores all cached nodes in a [`LruCache`]. It ensures that when updating the +/// Internally this stores all cached nodes in a [`LruMap`]. It ensures that when updating the /// cache, that the cache stays within its allowed bounds. -pub(super) struct SharedNodeCache { +pub(super) struct SharedNodeCache +where + H: AsRef<[u8]>, +{ /// 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, + pub(super) lru: SharedNodeCacheMap, } 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 } + fn new(max_inline_size: usize, max_heap_size: usize) -> Self { + Self { + lru: LruMap::new(SharedNodeCacheLimiter { + max_inline_size, + max_heap_size, + heap_size: 0, + items_evicted: 0, + max_items_evicted: 0, // Will be set during `update`. + }), + } } - /// 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 `list` of nodes which were either newly added or accessed. + pub fn update(&mut self, list: impl IntoIterator)>) { + let mut access_count = 0; + let mut add_count = 0; - /// 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!",); - } - }; + self.lru.limiter_mut().items_evicted = 0; + self.lru.limiter_mut().max_items_evicted = + self.lru.len() * 100 / super::SHARED_NODE_CACHE_MAX_REPLACE_PERCENT; - 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(); + for (key, cached_node) in list { + if cached_node.is_from_shared_cache { + if self.lru.get(&key).is_some() { + access_count += 1; - 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); - } + if access_count >= super::SHARED_NODE_CACHE_MAX_PROMOTED_KEYS { + // Stop when we've promoted a large enough number of items. + break + } - // 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); + continue } } - }); + + self.lru.insert(key, cached_node.node); + add_count += 1; + + if self.lru.limiter().items_evicted > self.lru.limiter().max_items_evicted { + // Stop when we've evicted a big enough chunk of the shared cache. + break + } + } + + tracing::debug!( + target: super::LOG_TARGET, + "Updated the shared node cache: {} accesses, {} new values, {}/{} evicted (length = {}, inline size={}/{}, heap size={}/{})", + access_count, + add_count, + self.lru.limiter().items_evicted, + self.lru.limiter().max_items_evicted, + self.lru.len(), + self.lru.memory_usage(), + self.lru.limiter().max_inline_size, + self.lru.limiter().heap_size, + self.lru.limiter().max_heap_size, + ); } /// Reset the cache. fn reset(&mut self) { - self.size_in_bytes = 0; self.lru.clear(); } } /// The hash of [`ValueCacheKey`]. -#[derive(Eq, Clone, Copy)] +#[derive(PartialEq, Eq, Clone, Copy, Hash)] +#[repr(transparent)] pub struct ValueCacheKeyHash(u64); +impl ValueCacheKeyHash { + pub fn raw(self) -> u64 { + self.0 + } +} + impl ValueCacheKeyHash { pub fn from_hasher_and_storage_key( mut hasher: impl std::hash::Hasher, @@ -133,88 +338,75 @@ impl ValueCacheKeyHash { } } -impl PartialEq for ValueCacheKeyHash { - fn eq(&self, other: &Self) -> bool { - self.0 == other.0 - } +impl nohash_hasher::IsEnabled for ValueCacheKeyHash {} + +/// The key type that is being used to address a [`CachedValue`]. +#[derive(Eq)] +pub(super) struct ValueCacheKey { + /// The storage root of the trie this key belongs to. + pub storage_root: H, + /// The key to access the value in the storage. + pub storage_key: Arc<[u8]>, + /// The hash that identifies this instance of `storage_root` and `storage_key`. + pub hash: ValueCacheKeyHash, } -impl std::hash::Hash for ValueCacheKeyHash { - fn hash(&self, state: &mut Hasher) { - state.write_u64(self.0); +/// A borrowed variant of [`ValueCacheKey`]. +pub(super) struct ValueCacheRef<'a, H> { + /// The storage root of the trie this key belongs to. + pub storage_root: H, + /// The key to access the value in the storage. + pub storage_key: &'a [u8], + /// The hash that identifies this instance of `storage_root` and `storage_key`. + pub hash: ValueCacheKeyHash, +} + +impl<'a, H> ValueCacheRef<'a, H> { + pub fn new(storage_key: &'a [u8], storage_root: H) -> Self + where + H: AsRef<[u8]>, + { + let hash = ValueCacheKey::::hash_data(&storage_key, &storage_root); + Self { storage_root, storage_key, hash } } } -impl nohash_hasher::IsEnabled for ValueCacheKeyHash {} +impl<'a, H> From> for ValueCacheKey { + fn from(value: ValueCacheRef<'a, H>) -> Self { + ValueCacheKey { + storage_root: value.storage_root, + storage_key: value.storage_key.into(), + hash: value.hash, + } + } +} -/// 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(()); +impl<'a, H: std::hash::Hash> std::hash::Hash for ValueCacheRef<'a, H> { + fn hash(&self, state: &mut Hasher) { + self.hash.hash(state) + } +} -/// 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> PartialEq> for ValueCacheRef<'a, H> +where + H: AsRef<[u8]>, +{ + fn eq(&self, rhs: &ValueCacheKey) -> bool { + self.storage_root.as_ref() == rhs.storage_root.as_ref() && + self.storage_key == &*rhs.storage_key + } } -impl<'a, H> ValueCacheKey<'a, H> { +impl ValueCacheKey { /// Constructs [`Self::Value`]. + #[cfg(test)] // Only used in tests. 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 } + Self { storage_root, storage_key, hash } } /// Returns a hasher prepared to build the final hash to identify [`Self`]. @@ -241,231 +433,133 @@ impl<'a, H> ValueCacheKey<'a, H> { 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, - } + /// Checks whether the key is equal to the given `storage_key` and `storage_root`. + #[inline] + pub fn is_eq(&self, storage_root: &H, storage_key: &[u8]) -> bool + where + H: PartialEq, + { + self.storage_root == *storage_root && *self.storage_key == *storage_key } } -// Implement manually to ensure that the `Value` and `Hash` are treated equally. -impl std::hash::Hash for ValueCacheKey<'_, H> { +// Implement manually so that only `hash` is accessed. +impl std::hash::Hash for ValueCacheKey { fn hash(&self, state: &mut Hasher) { - self.get_hash().hash(state) + self.hash.hash(state) } } -impl nohash_hasher::IsEnabled for ValueCacheKey<'_, H> {} +impl nohash_hasher::IsEnabled for ValueCacheKey {} -// Implement manually to ensure that the `Value` and `Hash` are treated equally. -impl PartialEq for ValueCacheKey<'_, H> { +// Implement manually to not have to compare `hash`. +impl PartialEq for ValueCacheKey { + #[inline] 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(), - } + self.is_eq(&other.storage_root, &other.storage_key) } } +type SharedValueCacheMap = schnellru::LruMap< + ValueCacheKey, + CachedValue, + SharedValueCacheLimiter, + BuildNoHashHasher>, +>; + /// The shared value cache. /// /// The cache ensures that it stays in the configured size bounds. -pub(super) struct SharedValueCache { +pub(super) struct SharedValueCache +where + H: AsRef<[u8]>, +{ /// 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>, + pub(super) lru: SharedValueCacheMap, } impl> SharedValueCache { /// Create a new instance. - fn new(cache_size: CacheSize) -> Self { + fn new(max_inline_size: usize, max_heap_size: usize) -> Self { Self { - lru: NoHashingLruCache::unbounded_with_hasher(Default::default()), - size_in_bytes: 0, - maximum_cache_size: cache_size, - known_storage_keys: Default::default(), + lru: schnellru::LruMap::with_hasher( + SharedValueCacheLimiter { + max_inline_size, + max_heap_size, + heap_size: 0, + known_storage_keys: Default::default(), + items_evicted: 0, + max_items_evicted: 0, // Will be set during `update`. + }, + 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`]). + /// [`ValueCacheKeyHash`] and represent the values that were retrieved from this shared cache. + /// These `accessed` values are being put to the front of the internal [`LruMap`] like the + /// `added` ones. pub fn update( &mut self, - added: impl IntoIterator, CachedValue)>, + 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, - ); - } - } + let mut access_count = 0; + let mut add_count = 0; - // 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, - ); - } - } + for hash in accessed { + // Access every node in the map to put it to the front. + // + // Since we are only comparing the hashes here it may lead us to promoting the wrong + // values as the most recently accessed ones. However this is harmless as the only + // consequence is that we may accidentally prune a recently used value too early. + self.lru.get_by_hash(hash.raw(), |existing_key, _| existing_key.hash == hash); + access_count += 1; + } + + // Insert all of the new items which were *not* found in the shared cache. + // + // Limit how many items we'll replace in the shared cache in one go so that + // we don't evict the whole shared cache nor we keep spinning our wheels + // evicting items which we've added ourselves in previous iterations of this loop. + + self.lru.limiter_mut().items_evicted = 0; + self.lru.limiter_mut().max_items_evicted = + self.lru.len() * 100 / super::SHARED_VALUE_CACHE_MAX_REPLACE_PERCENT; + + for (key, value) in added { + self.lru.insert(key, value); + add_count += 1; + + if self.lru.limiter().items_evicted > self.lru.limiter().max_items_evicted { + // Stop when we've evicted a big enough chunk of the shared cache. + break } - }); + } + + tracing::debug!( + target: super::LOG_TARGET, + "Updated the shared value cache: {} accesses, {} new values, {}/{} evicted (length = {}, known_storage_keys = {}, inline size={}/{}, heap size={}/{})", + access_count, + add_count, + self.lru.limiter().items_evicted, + self.lru.limiter().max_items_evicted, + self.lru.len(), + self.lru.limiter().known_storage_keys.len(), + self.lru.memory_usage(), + self.lru.limiter().max_inline_size, + self.lru.limiter().heap_size, + self.lru.limiter().max_heap_size + ); } /// Reset the cache. fn reset(&mut self) { - self.size_in_bytes = 0; self.lru.clear(); - self.known_storage_keys.clear(); } } @@ -477,6 +571,7 @@ pub(super) struct SharedTrieCacheInner { impl SharedTrieCacheInner { /// Returns a reference to the [`SharedValueCache`]. + #[cfg(test)] pub(super) fn value_cache(&self) -> &SharedValueCache { &self.value_cache } @@ -487,6 +582,7 @@ impl SharedTrieCacheInner { } /// Returns a reference to the [`SharedNodeCache`]. + #[cfg(test)] pub(super) fn node_cache(&self) -> &SharedNodeCache { &self.node_cache } @@ -517,23 +613,50 @@ impl Clone for SharedTrieCache { 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), - }; + let total_budget = cache_size.0; + + // Split our memory budget between the two types of caches. + let value_cache_budget = (total_budget as f32 * 0.20) as usize; // 20% for the value cache + let node_cache_budget = total_budget - value_cache_budget; // 80% for the node cache + + // Split our memory budget between what we'll be holding inline in the map, + // and what we'll be holding on the heap. + let value_cache_inline_budget = (value_cache_budget as f32 * 0.70) as usize; + let node_cache_inline_budget = (node_cache_budget as f32 * 0.70) as usize; + + // Calculate how much memory the maps will be allowed to hold inline given our budget. + let value_cache_max_inline_size = + SharedValueCacheMap::::memory_usage_for_memory_budget( + value_cache_inline_budget, + ); + + let node_cache_max_inline_size = + SharedNodeCacheMap::::memory_usage_for_memory_budget(node_cache_inline_budget); + + // And this is how much data we'll at most keep on the heap for each cache. + let value_cache_max_heap_size = value_cache_budget - value_cache_max_inline_size; + let node_cache_max_heap_size = node_cache_budget - node_cache_max_inline_size; + + tracing::debug!( + target: super::LOG_TARGET, + "Configured a shared trie cache with a budget of ~{} bytes (node_cache_max_inline_size = {}, node_cache_max_heap_size = {}, value_cache_max_inline_size = {}, value_cache_max_heap_size = {})", + total_budget, + node_cache_max_inline_size, + node_cache_max_heap_size, + value_cache_max_inline_size, + value_cache_max_heap_size, + ); Self { inner: Arc::new(RwLock::new(SharedTrieCacheInner { - node_cache: SharedNodeCache::new(node_cache_size), - value_cache: SharedValueCache::new(value_cache_size), + node_cache: SharedNodeCache::new( + node_cache_max_inline_size, + node_cache_max_heap_size, + ), + value_cache: SharedValueCache::new( + value_cache_max_inline_size, + value_cache_max_heap_size, + ), })), } } @@ -544,16 +667,50 @@ impl SharedTrieCache { shared: self.clone(), node_cache: Default::default(), value_cache: Default::default(), - shared_node_cache_access: Default::default(), - shared_value_cache_access: Default::default(), + shared_value_cache_access: Mutex::new(super::ValueAccessSet::with_hasher( + schnellru::ByLength::new(super::SHARED_VALUE_CACHE_MAX_PROMOTED_KEYS), + Default::default(), + )), + stats: Default::default(), } } + /// Get a copy of the node for `key`. + /// + /// This will temporarily lock the shared cache for reading. + /// + /// This doesn't change the least recently order in the internal [`LruMap`]. + #[inline] + pub fn peek_node(&self, key: &H::Out) -> Option> { + self.inner.read().node_cache.lru.peek(key).cloned() + } + + /// Get a copy of the [`CachedValue`] for `key`. + /// + /// This will temporarily lock the shared cache for reading. + /// + /// This doesn't reorder any of the elements in the internal [`LruMap`]. + pub fn peek_value_by_hash( + &self, + hash: ValueCacheKeyHash, + storage_root: &H::Out, + storage_key: &[u8], + ) -> Option> { + self.inner + .read() + .value_cache + .lru + .peek_by_hash(hash.0, |existing_key, _| existing_key.is_eq(storage_root, storage_key)) + .cloned() + } + /// 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; + let value_cache_size = + inner.value_cache.lru.memory_usage() + inner.value_cache.lru.limiter().heap_size; + let node_cache_size = + inner.node_cache.lru.memory_usage() + inner.node_cache.lru.limiter().heap_size; node_cache_size + value_cache_size } @@ -575,13 +732,19 @@ impl SharedTrieCache { } /// Returns the read locked inner. - pub(super) fn read_lock_inner(&self) -> RwLockReadGuard<'_, SharedTrieCacheInner> { + #[cfg(test)] + pub(super) fn read_lock_inner( + &self, + ) -> parking_lot::RwLockReadGuard<'_, SharedTrieCacheInner> { self.inner.read() } /// Returns the write locked inner. - pub(super) fn write_lock_inner(&self) -> RwLockWriteGuard<'_, SharedTrieCacheInner> { - self.inner.write() + pub(super) fn write_lock_inner(&self) -> Option>> { + // This should never happen, but we *really* don't want to deadlock. So let's have it + // timeout, just in case. At worst it'll do nothing, and at best it'll avert a catastrophe + // and notify us that there's a problem. + self.inner.try_write_for(super::SHARED_CACHE_WRITE_LOCK_TIMEOUT) } } @@ -592,12 +755,7 @@ mod tests { #[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 mut cache = SharedValueCache::::new(usize::MAX, 10 * 10); let key = vec![0; 10]; @@ -613,65 +771,85 @@ mod tests { ); // 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); + assert_eq!(1, cache.lru.limiter_mut().known_storage_keys.len()); + assert_eq!( + 3, // Two instances inside the cache + one extra in `known_storage_keys`. + Arc::strong_count(cache.lru.limiter_mut().known_storage_keys.get(&key[..]).unwrap()) + ); + assert_eq!(key.len(), cache.lru.limiter().heap_size); + assert_eq!(cache.lru.len(), 2); + assert_eq!(cache.lru.peek_newest().unwrap().0.storage_root, root1); + assert_eq!(cache.lru.peek_oldest().unwrap().0.storage_root, root0); + assert!(cache.lru.limiter().heap_size <= cache.lru.limiter().max_heap_size); + assert_eq!(cache.lru.limiter().heap_size, 10); // 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`. + assert_eq!(1, cache.lru.limiter_mut().known_storage_keys.len()); + assert_eq!( + 3, + Arc::strong_count(cache.lru.limiter_mut().known_storage_keys.get(&key[..]).unwrap()) + ); + assert_eq!(key.len(), cache.lru.limiter().heap_size); + assert_eq!(cache.lru.len(), 2); + assert_eq!(cache.lru.peek_newest().unwrap().0.storage_root, root0); + assert_eq!(cache.lru.peek_oldest().unwrap().0.storage_root, root1); + assert!(cache.lru.limiter().heap_size <= cache.lru.limiter().max_heap_size); + assert_eq!(cache.lru.limiter().heap_size, 10); + + // Updating the cache again with exactly the same data should not change anything. cache.update( - (1..10) + vec![ + (ValueCacheKey::new_value(&key[..], root1), CachedValue::NonExisting), + (ValueCacheKey::new_value(&key[..], root0), CachedValue::NonExisting), + ], + vec![], + ); + assert_eq!(1, cache.lru.limiter_mut().known_storage_keys.len()); + assert_eq!( + 3, + Arc::strong_count(cache.lru.limiter_mut().known_storage_keys.get(&key[..]).unwrap()) + ); + assert_eq!(key.len(), cache.lru.limiter().heap_size); + assert_eq!(cache.lru.len(), 2); + assert_eq!(cache.lru.peek_newest().unwrap().0.storage_root, root0); + assert_eq!(cache.lru.peek_oldest().unwrap().0.storage_root, root1); + assert!(cache.lru.limiter().heap_size <= cache.lru.limiter().max_heap_size); + assert_eq!(cache.lru.limiter().items_evicted, 0); + assert_eq!(cache.lru.limiter().heap_size, 10); + + // Add 10 other entries and this should move out two of the initial entries. + cache.update( + (1..11) .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_eq!(cache.lru.limiter().items_evicted, 2); + assert_eq!(10, cache.lru.len()); + assert_eq!(10, cache.lru.limiter_mut().known_storage_keys.len()); + assert!(cache.lru.limiter_mut().known_storage_keys.get(&key[..]).is_none()); + assert_eq!(key.len() * 10, cache.lru.limiter().heap_size); + assert_eq!(cache.lru.len(), 10); + assert!(cache.lru.limiter().heap_size <= cache.lru.limiter().max_heap_size); + assert_eq!(cache.lru.limiter().heap_size, 100); + assert!(matches!( - cache.get(&ValueCacheKey::new_ref(&key, root0)).unwrap(), + cache.lru.peek(&ValueCacheKey::new_value(&[1; 10][..], root0)).unwrap(), CachedValue::::NonExisting )); - assert!(cache.get(&ValueCacheKey::new_ref(&key, root1)).is_none()); + + assert!(cache.lru.peek(&ValueCacheKey::new_value(&[1; 10][..], root1)).is_none(),); + + assert!(cache.lru.peek(&ValueCacheKey::new_value(&key[..], root0)).is_none()); + assert!(cache.lru.peek(&ValueCacheKey::new_value(&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); + assert!(cache.lru.limiter_mut().known_storage_keys.get(&key[..]).is_none()); } } From 64a1a360eaf5c467c0f836a1ca4ae4cde8663e43 Mon Sep 17 00:00:00 2001 From: Andrei Sandu <54316454+sandreim@users.noreply.github.com> Date: Thu, 26 Jan 2023 08:22:51 +0200 Subject: [PATCH 332/715] Add task type label to metrics (#13240) Signed-off-by: Andrei Sandu Signed-off-by: Andrei Sandu --- client/service/src/task_manager/mod.rs | 41 +++++++++++++++++++------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/client/service/src/task_manager/mod.rs b/client/service/src/task_manager/mod.rs index d792122576444..f2987e684d9dc 100644 --- a/client/service/src/task_manager/mod.rs +++ b/client/service/src/task_manager/mod.rs @@ -129,12 +129,20 @@ impl SpawnTaskHandle { GroupName::Default => DEFAULT_GROUP_NAME, }; + let task_type_label = match task_type { + TaskType::Blocking => "blocking", + TaskType::Async => "async", + }; + // 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, group]).inc(); + metrics.tasks_spawned.with_label_values(&[name, group, task_type_label]).inc(); // We do a dummy increase in order for the task to show up in metrics. - metrics.tasks_ended.with_label_values(&[name, "finished", group]).inc_by(0); + metrics + .tasks_ended + .with_label_values(&[name, "finished", group, task_type_label]) + .inc_by(0); } let future = async move { @@ -145,8 +153,10 @@ impl SpawnTaskHandle { if let Some(metrics) = metrics { // Add some wrappers around `task`. let task = { - let poll_duration = metrics.poll_duration.with_label_values(&[name, group]); - let poll_start = metrics.poll_start.with_label_values(&[name, group]); + let poll_duration = + metrics.poll_duration.with_label_values(&[name, group, task_type_label]); + let poll_start = + metrics.poll_start.with_label_values(&[name, group, task_type_label]); let inner = prometheus_future::with_poll_durations(poll_duration, poll_start, task); // The logic of `AssertUnwindSafe` here is ok considering that we throw @@ -157,15 +167,24 @@ impl SpawnTaskHandle { match select(on_exit, task).await { Either::Right((Err(payload), _)) => { - metrics.tasks_ended.with_label_values(&[name, "panic", group]).inc(); + metrics + .tasks_ended + .with_label_values(&[name, "panic", group, task_type_label]) + .inc(); panic::resume_unwind(payload) }, Either::Right((Ok(()), _)) => { - metrics.tasks_ended.with_label_values(&[name, "finished", group]).inc(); + metrics + .tasks_ended + .with_label_values(&[name, "finished", group, task_type_label]) + .inc(); }, Either::Left(((), _)) => { // The `on_exit` has triggered. - metrics.tasks_ended.with_label_values(&[name, "interrupted", group]).inc(); + metrics + .tasks_ended + .with_label_values(&[name, "interrupted", group, task_type_label]) + .inc(); }, } } else { @@ -433,28 +452,28 @@ impl Metrics { buckets: exponential_buckets(0.001, 4.0, 9) .expect("function parameters are constant and always valid; qed"), }, - &["task_name", "task_group"] + &["task_name", "task_group", "kind"] )?, registry)?, poll_start: register(CounterVec::new( Opts::new( "substrate_tasks_polling_started_total", "Total number of times we started invoking Future::poll" ), - &["task_name", "task_group"] + &["task_name", "task_group", "kind"] )?, registry)?, tasks_spawned: register(CounterVec::new( Opts::new( "substrate_tasks_spawned_total", "Total number of tasks that have been spawned on the Service" ), - &["task_name", "task_group"] + &["task_name", "task_group", "kind"] )?, registry)?, tasks_ended: register(CounterVec::new( Opts::new( "substrate_tasks_ended_total", "Total number of tasks for which Future::poll has returned Ready(()) or panicked" ), - &["task_name", "reason", "task_group"] + &["task_name", "reason", "task_group", "kind"] )?, registry)?, }) } From f4bc99303e6faa0ae0461b4606c1699b4463ff4b Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Thu, 26 Jan 2023 08:59:18 +0100 Subject: [PATCH 333/715] upgrade nix to 0.26.1 (#13230) --- Cargo.lock | 15 +-------------- bin/node/cli/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7c412030d560c..43f67695faa11 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4640,19 +4640,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "nix" -version = "0.23.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f3790c00a0150112de0f4cd161e3d7fc4b2d8a5542ffc35f099a2562aecb35c" -dependencies = [ - "bitflags", - "cc", - "cfg-if", - "libc", - "memoffset 0.6.5", -] - [[package]] name = "nix" version = "0.24.3" @@ -4731,7 +4718,7 @@ dependencies = [ "jsonrpsee", "kitchensink-runtime", "log", - "nix 0.23.2", + "nix 0.26.1", "node-executor", "node-inspect", "node-primitives", diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index 8a883ee0119ec..b55b35c05652d 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -117,7 +117,7 @@ sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" futures = "0.3.21" tempfile = "3.1.0" assert_cmd = "2.0.2" -nix = "0.23" +nix = { version = "0.26.1", features = ["signal"] } serde_json = "1.0" regex = "1.6.0" platforms = "2.0" From 2dbf62591fd35725c6e39f8ddfd27c3695dab594 Mon Sep 17 00:00:00 2001 From: Stephen Shelton Date: Thu, 26 Jan 2023 07:39:20 -0700 Subject: [PATCH 334/715] Add WeightToFee and LengthToFee impls to transaction-payment Runtime API (#13110) * Add WeightToFee and LengthToFee impls to RPC * Remove RPC additions * Update frame/transaction-payment/rpc/runtime-api/src/lib.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Add comments to length_to_fee and weight_to_fee Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> Co-authored-by: Oliver Tale-Yazdi --- bin/node-template/runtime/src/lib.rs | 12 ++++++++++++ bin/node/runtime/src/lib.rs | 12 ++++++++++++ frame/transaction-payment/rpc/runtime-api/src/lib.rs | 12 ++++++++++-- frame/transaction-payment/src/lib.rs | 7 +++++-- 4 files changed, 39 insertions(+), 4 deletions(-) diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs index f4372af525da5..baba5d9b05e59 100644 --- a/bin/node-template/runtime/src/lib.rs +++ b/bin/node-template/runtime/src/lib.rs @@ -477,6 +477,12 @@ impl_runtime_apis! { ) -> pallet_transaction_payment::FeeDetails { TransactionPayment::query_fee_details(uxt, len) } + fn query_weight_to_fee(weight: Weight) -> Balance { + TransactionPayment::weight_to_fee(weight) + } + fn query_length_to_fee(length: u32) -> Balance { + TransactionPayment::length_to_fee(length) + } } impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentCallApi @@ -494,6 +500,12 @@ impl_runtime_apis! { ) -> pallet_transaction_payment::FeeDetails { TransactionPayment::query_call_fee_details(call, len) } + fn query_weight_to_fee(weight: Weight) -> Balance { + TransactionPayment::weight_to_fee(weight) + } + fn query_length_to_fee(length: u32) -> Balance { + TransactionPayment::length_to_fee(length) + } } #[cfg(feature = "runtime-benchmarks")] diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 1f85d118ea534..0121f1ee3a8ca 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -2120,6 +2120,12 @@ impl_runtime_apis! { fn query_fee_details(uxt: ::Extrinsic, len: u32) -> FeeDetails { TransactionPayment::query_fee_details(uxt, len) } + fn query_weight_to_fee(weight: Weight) -> Balance { + TransactionPayment::weight_to_fee(weight) + } + fn query_length_to_fee(length: u32) -> Balance { + TransactionPayment::length_to_fee(length) + } } impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentCallApi @@ -2131,6 +2137,12 @@ impl_runtime_apis! { fn query_call_fee_details(call: RuntimeCall, len: u32) -> FeeDetails { TransactionPayment::query_call_fee_details(call, len) } + fn query_weight_to_fee(weight: Weight) -> Balance { + TransactionPayment::weight_to_fee(weight) + } + fn query_length_to_fee(length: u32) -> Balance { + TransactionPayment::length_to_fee(length) + } } impl pallet_mmr::primitives::MmrApi< diff --git a/frame/transaction-payment/rpc/runtime-api/src/lib.rs b/frame/transaction-payment/rpc/runtime-api/src/lib.rs index 10fd2a9e61fc1..760f9e3693417 100644 --- a/frame/transaction-payment/rpc/runtime-api/src/lib.rs +++ b/frame/transaction-payment/rpc/runtime-api/src/lib.rs @@ -25,7 +25,7 @@ use sp_runtime::traits::MaybeDisplay; pub use pallet_transaction_payment::{FeeDetails, InclusionFee, RuntimeDispatchInfo}; sp_api::decl_runtime_apis! { - #[api_version(2)] + #[api_version(3)] pub trait TransactionPaymentApi where Balance: Codec + MaybeDisplay, { @@ -33,9 +33,11 @@ sp_api::decl_runtime_apis! { 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; + fn query_weight_to_fee(weight: sp_weights::Weight) -> Balance; + fn query_length_to_fee(length: u32) -> Balance; } - #[api_version(2)] + #[api_version(3)] pub trait TransactionPaymentCallApi where Balance: Codec + MaybeDisplay, @@ -46,5 +48,11 @@ sp_api::decl_runtime_apis! { /// Query fee details of a given encoded `Call`. fn query_call_fee_details(call: Call, len: u32) -> FeeDetails; + + /// Query the output of the current `WeightToFee` given some input. + fn query_weight_to_fee(weight: sp_weights::Weight) -> Balance; + + /// Query the output of the current `LengthToFee` given some input. + fn query_length_to_fee(length: u32) -> Balance; } } diff --git a/frame/transaction-payment/src/lib.rs b/frame/transaction-payment/src/lib.rs index 13adbf89c4270..fb4381c5242c6 100644 --- a/frame/transaction-payment/src/lib.rs +++ b/frame/transaction-payment/src/lib.rs @@ -612,11 +612,14 @@ where } } - fn length_to_fee(length: u32) -> BalanceOf { + /// Compute the length portion of a fee by invoking the configured `LengthToFee` impl. + pub fn length_to_fee(length: u32) -> BalanceOf { T::LengthToFee::weight_to_fee(&Weight::from_ref_time(length as u64)) } - fn weight_to_fee(weight: Weight) -> BalanceOf { + /// Compute the unadjusted portion of the weight fee by invoking the configured `WeightToFee` + /// impl. Note that the input `weight` is capped by the maximum block weight before computation. + pub 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); From 495cc0e2b3b06bd3f6b746416fc0d635adcefa7c Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Thu, 26 Jan 2023 17:13:38 +0100 Subject: [PATCH 335/715] Correct arithmetical semantic of `PerDispatchClass` (#13194) * Fix PerDispatchClass arithmetic Signed-off-by: Oliver Tale-Yazdi * Test PerDispatchClass arithmetic Signed-off-by: Oliver Tale-Yazdi * Add helpers for Weight Signed-off-by: Oliver Tale-Yazdi * Remove stale doc Signed-off-by: Oliver Tale-Yazdi * Dont mention Polkadot in Substrate Signed-off-by: Oliver Tale-Yazdi * Tests Signed-off-by: Oliver Tale-Yazdi * fmt Signed-off-by: Oliver Tale-Yazdi * Remove saturating_ prefix Signed-off-by: Oliver Tale-Yazdi * Fix tests Signed-off-by: Oliver Tale-Yazdi * Fix usage Signed-off-by: Oliver Tale-Yazdi Signed-off-by: Oliver Tale-Yazdi --- frame/support/src/dispatch.rs | 209 ++++++++++++++++++-- frame/support/src/weights.rs | 10 +- frame/system/src/extensions/check_weight.rs | 6 +- frame/system/src/lib.rs | 2 +- primitives/weights/src/lib.rs | 7 - primitives/weights/src/weight_v2.rs | 109 ++++++++++ 6 files changed, 307 insertions(+), 36 deletions(-) diff --git a/frame/support/src/dispatch.rs b/frame/support/src/dispatch.rs index 93cf08c131641..291abdd12893f 100644 --- a/frame/support/src/dispatch.rs +++ b/frame/support/src/dispatch.rs @@ -423,33 +423,35 @@ impl PerDispatchClass { impl PerDispatchClass { /// Returns the total weight consumed by all extrinsics in the block. + /// + /// Saturates on overflow. pub fn total(&self) -> Weight { let mut sum = Weight::zero(); for class in DispatchClass::all() { - sum = sum.saturating_add(*self.get(*class)); + sum.saturating_accrue(*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); + /// Add some weight to the given class. Saturates at the numeric bounds. + pub fn add(mut self, weight: Weight, class: DispatchClass) -> Self { + self.accrue(weight, class); + self + } + + /// Increase the weight of the given class. Saturates at the numeric bounds. + pub fn accrue(&mut self, weight: Weight, class: DispatchClass) { + self.get_mut(class).saturating_accrue(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(()) + /// Try to increase the weight of the given class. Saturates at the numeric bounds. + pub fn checked_accrue(&mut self, weight: Weight, class: DispatchClass) -> Result<(), ()> { + self.get_mut(class).checked_accrue(weight).ok_or(()) } - /// 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); + /// Reduce the weight of the given class. Saturates at the numeric bounds. + pub fn reduce(&mut self, weight: Weight, class: DispatchClass) { + self.get_mut(class).saturating_reduce(weight); } } @@ -3693,3 +3695,178 @@ mod weight_tests { assert_eq!(extract_actual_pays_fee(&Ok((Some(1000), Pays::Yes).into()), &pre), Pays::No); } } + +#[cfg(test)] +mod per_dispatch_class_tests { + use super::*; + use sp_runtime::traits::Zero; + use DispatchClass::*; + + #[test] + fn add_works() { + let a = PerDispatchClass { + normal: (5, 10).into(), + operational: (20, 30).into(), + mandatory: Weight::MAX, + }; + assert_eq!( + a.clone() + .add((20, 5).into(), Normal) + .add((10, 10).into(), Operational) + .add((u64::MAX, 3).into(), Mandatory), + PerDispatchClass { + normal: (25, 15).into(), + operational: (30, 40).into(), + mandatory: Weight::MAX + } + ); + let b = a + .add(Weight::MAX, Normal) + .add(Weight::MAX, Operational) + .add(Weight::MAX, Mandatory); + assert_eq!( + b, + PerDispatchClass { + normal: Weight::MAX, + operational: Weight::MAX, + mandatory: Weight::MAX + } + ); + assert_eq!(b.total(), Weight::MAX); + } + + #[test] + fn accrue_works() { + let mut a = PerDispatchClass::default(); + + a.accrue((10, 15).into(), Normal); + assert_eq!(a.normal, (10, 15).into()); + assert_eq!(a.total(), (10, 15).into()); + + a.accrue((20, 25).into(), Operational); + assert_eq!(a.operational, (20, 25).into()); + assert_eq!(a.total(), (30, 40).into()); + + a.accrue((30, 35).into(), Mandatory); + assert_eq!(a.mandatory, (30, 35).into()); + assert_eq!(a.total(), (60, 75).into()); + + a.accrue((u64::MAX, 10).into(), Operational); + assert_eq!(a.operational, (u64::MAX, 35).into()); + assert_eq!(a.total(), (u64::MAX, 85).into()); + + a.accrue((10, u64::MAX).into(), Normal); + assert_eq!(a.normal, (20, u64::MAX).into()); + assert_eq!(a.total(), Weight::MAX); + } + + #[test] + fn reduce_works() { + let mut a = PerDispatchClass { + normal: (10, u64::MAX).into(), + mandatory: (u64::MAX, 10).into(), + operational: (20, 20).into(), + }; + + a.reduce((5, 100).into(), Normal); + assert_eq!(a.normal, (5, u64::MAX - 100).into()); + assert_eq!(a.total(), (u64::MAX, u64::MAX - 70).into()); + + a.reduce((15, 5).into(), Operational); + assert_eq!(a.operational, (5, 15).into()); + assert_eq!(a.total(), (u64::MAX, u64::MAX - 75).into()); + + a.reduce((50, 0).into(), Mandatory); + assert_eq!(a.mandatory, (u64::MAX - 50, 10).into()); + assert_eq!(a.total(), (u64::MAX - 40, u64::MAX - 75).into()); + + a.reduce((u64::MAX, 100).into(), Operational); + assert!(a.operational.is_zero()); + assert_eq!(a.total(), (u64::MAX - 45, u64::MAX - 90).into()); + + a.reduce((5, u64::MAX).into(), Normal); + assert!(a.normal.is_zero()); + assert_eq!(a.total(), (u64::MAX - 50, 10).into()); + } + + #[test] + fn checked_accrue_works() { + let mut a = PerDispatchClass::default(); + + a.checked_accrue((1, 2).into(), Normal).unwrap(); + a.checked_accrue((3, 4).into(), Operational).unwrap(); + a.checked_accrue((5, 6).into(), Mandatory).unwrap(); + a.checked_accrue((7, 8).into(), Operational).unwrap(); + a.checked_accrue((9, 0).into(), Normal).unwrap(); + + assert_eq!( + a, + PerDispatchClass { + normal: (10, 2).into(), + operational: (10, 12).into(), + mandatory: (5, 6).into(), + } + ); + + a.checked_accrue((u64::MAX - 10, u64::MAX - 2).into(), Normal).unwrap(); + a.checked_accrue((0, 0).into(), Normal).unwrap(); + a.checked_accrue((1, 0).into(), Normal).unwrap_err(); + a.checked_accrue((0, 1).into(), Normal).unwrap_err(); + + assert_eq!( + a, + PerDispatchClass { + normal: Weight::MAX, + operational: (10, 12).into(), + mandatory: (5, 6).into(), + } + ); + } + + #[test] + fn checked_accrue_does_not_modify_on_error() { + let mut a = PerDispatchClass { + normal: 0.into(), + operational: Weight::MAX / 2 + 2.into(), + mandatory: 10.into(), + }; + + a.checked_accrue(Weight::MAX / 2, Operational).unwrap_err(); + a.checked_accrue(Weight::MAX - 9.into(), Mandatory).unwrap_err(); + a.checked_accrue(Weight::MAX, Normal).unwrap(); // This one works + + assert_eq!( + a, + PerDispatchClass { + normal: Weight::MAX, + operational: Weight::MAX / 2 + 2.into(), + mandatory: 10.into(), + } + ); + } + + #[test] + fn total_works() { + assert!(PerDispatchClass::default().total().is_zero()); + + assert_eq!( + PerDispatchClass { + normal: 0.into(), + operational: (10, 20).into(), + mandatory: (20, u64::MAX).into(), + } + .total(), + (30, u64::MAX).into() + ); + + assert_eq!( + PerDispatchClass { + normal: (u64::MAX - 10, 10).into(), + operational: (3, u64::MAX).into(), + mandatory: (4, u64::MAX).into(), + } + .total(), + (u64::MAX - 3, u64::MAX).into() + ); + } +} diff --git a/frame/support/src/weights.rs b/frame/support/src/weights.rs index 9ff49b97bf21f..d52380b832fc4 100644 --- a/frame/support/src/weights.rs +++ b/frame/support/src/weights.rs @@ -15,15 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! 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 -//! - 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) +//! Re-exports `sp-weights` public API, and contains benchmarked weight constants specific to FRAME. mod block_weights; mod extrinsic_weights; diff --git a/frame/system/src/extensions/check_weight.rs b/frame/system/src/extensions/check_weight.rs index 757b2197bc238..590d05474f91a 100644 --- a/frame/system/src/extensions/check_weight.rs +++ b/frame/system/src/extensions/check_weight.rs @@ -135,10 +135,10 @@ where // add the weight. If class is unlimited, use saturating add instead of checked one. if limit_per_class.max_total.is_none() && limit_per_class.reserved.is_none() { - all_weight.add(extrinsic_weight, info.class) + all_weight.accrue(extrinsic_weight, info.class) } else { all_weight - .checked_add(extrinsic_weight, info.class) + .checked_accrue(extrinsic_weight, info.class) .map_err(|_| InvalidTransaction::ExhaustsResources)?; } @@ -229,7 +229,7 @@ where let unspent = post_info.calc_unspent(info); if unspent.any_gt(Weight::zero()) { crate::BlockWeight::::mutate(|current_weight| { - current_weight.sub(unspent, info.class); + current_weight.reduce(unspent, info.class); }) } diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 4bd5cf629873b..c5d1706006154 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -1321,7 +1321,7 @@ impl Pallet { /// Another potential use-case could be for the `on_initialize` and `on_finalize` hooks. pub fn register_extra_weight_unchecked(weight: Weight, class: DispatchClass) { BlockWeight::::mutate(|current_weight| { - current_weight.add(weight, class); + current_weight.accrue(weight, class); }); } diff --git a/primitives/weights/src/lib.rs b/primitives/weights/src/lib.rs index 928080d139864..59852815d7aef 100644 --- a/primitives/weights/src/lib.rs +++ b/primitives/weights/src/lib.rs @@ -16,13 +16,6 @@ // 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)] diff --git a/primitives/weights/src/weight_v2.rs b/primitives/weights/src/weight_v2.rs index 2933d80099dd7..33e61b6954a37 100644 --- a/primitives/weights/src/weight_v2.rs +++ b/primitives/weights/src/weight_v2.rs @@ -117,6 +117,11 @@ impl Weight { Self { ref_time, proof_size } } + /// Construct [`Weight`] from the same weight for all parts. + pub const fn from_all(value: u64) -> Self { + Self { ref_time: value, proof_size: value } + } + /// 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 { @@ -167,6 +172,11 @@ impl Weight { *self = self.saturating_add(amount); } + /// Reduce [`Weight`] by `amount` via saturating subtraction. + pub fn saturating_reduce(&mut self, amount: Self) { + *self = self.saturating_sub(amount); + } + /// Checked [`Weight`] addition. Computes `self + rhs`, returning `None` if overflow occurred. pub const fn checked_add(&self, rhs: &Self) -> Option { let ref_time = match self.ref_time.checked_add(rhs.ref_time) { @@ -222,6 +232,16 @@ impl Weight { Some(Self { ref_time, proof_size }) } + /// Try to increase `self` by `amount` via checked addition. + pub fn checked_accrue(&mut self, amount: Self) -> Option<()> { + self.checked_add(&amount).map(|new_self| *self = new_self) + } + + /// Try to reduce `self` by `amount` via checked subtraction. + pub fn checked_reduce(&mut self, amount: Self) -> Option<()> { + self.checked_sub(&amount).map(|new_self| *self = new_self) + } + /// Return a [`Weight`] where all fields are zero. pub const fn zero() -> Self { Self { ref_time: 0, proof_size: 0 } @@ -352,6 +372,20 @@ where } } +#[cfg(any(test, feature = "std", feature = "runtime-benchmarks"))] +impl From for Weight { + fn from(value: u64) -> Self { + Self::from_parts(value, value) + } +} + +#[cfg(any(test, feature = "std", feature = "runtime-benchmarks"))] +impl From<(u64, u64)> for Weight { + fn from(value: (u64, u64)) -> Self { + Self::from_parts(value.0, value.1) + } +} + macro_rules! weight_mul_per_impl { ($($t:ty),* $(,)?) => { $( @@ -459,4 +493,79 @@ mod tests { assert!(!Weight::from_parts(0, 1).is_zero()); assert!(!Weight::MAX.is_zero()); } + + #[test] + fn from_parts_works() { + assert_eq!(Weight::from_parts(0, 0), Weight { ref_time: 0, proof_size: 0 }); + assert_eq!(Weight::from_parts(5, 5), Weight { ref_time: 5, proof_size: 5 }); + assert_eq!( + Weight::from_parts(u64::MAX, u64::MAX), + Weight { ref_time: u64::MAX, proof_size: u64::MAX } + ); + } + + #[test] + fn from_all_works() { + assert_eq!(Weight::from_all(0), Weight::from_parts(0, 0)); + assert_eq!(Weight::from_all(5), Weight::from_parts(5, 5)); + assert_eq!(Weight::from_all(u64::MAX), Weight::from_parts(u64::MAX, u64::MAX)); + } + + #[test] + fn from_u64_works() { + assert_eq!(Weight::from_all(0), 0_u64.into()); + assert_eq!(Weight::from_all(123), 123_u64.into()); + assert_eq!(Weight::from_all(u64::MAX), u64::MAX.into()); + } + + #[test] + fn from_u64_pair_works() { + assert_eq!(Weight::from_parts(0, 1), (0, 1).into()); + assert_eq!(Weight::from_parts(123, 321), (123u64, 321u64).into()); + assert_eq!(Weight::from_parts(u64::MAX, 0), (u64::MAX, 0).into()); + } + + #[test] + fn saturating_reduce_works() { + let mut weight = Weight::from_parts(10, 20); + weight.saturating_reduce(Weight::from_all(5)); + assert_eq!(weight, Weight::from_parts(5, 15)); + weight.saturating_reduce(Weight::from_all(5)); + assert_eq!(weight, Weight::from_parts(0, 10)); + weight.saturating_reduce(Weight::from_all(11)); + assert!(weight.is_zero()); + weight.saturating_reduce(Weight::from_all(u64::MAX)); + assert!(weight.is_zero()); + } + + #[test] + fn checked_accrue_works() { + let mut weight = Weight::from_parts(10, 20); + assert!(weight.checked_accrue(Weight::from_all(2)).is_some()); + assert_eq!(weight, Weight::from_parts(12, 22)); + assert!(weight.checked_accrue(Weight::from_parts(u64::MAX, 0)).is_none()); + assert!(weight.checked_accrue(Weight::from_parts(0, u64::MAX)).is_none()); + assert_eq!(weight, Weight::from_parts(12, 22)); + assert!(weight + .checked_accrue(Weight::from_parts(u64::MAX - 12, u64::MAX - 22)) + .is_some()); + assert_eq!(weight, Weight::MAX); + assert!(weight.checked_accrue(Weight::from_parts(1, 0)).is_none()); + assert!(weight.checked_accrue(Weight::from_parts(0, 1)).is_none()); + assert_eq!(weight, Weight::MAX); + } + + #[test] + fn checked_reduce_works() { + let mut weight = Weight::from_parts(10, 20); + assert!(weight.checked_reduce(Weight::from_all(2)).is_some()); + assert_eq!(weight, Weight::from_parts(8, 18)); + assert!(weight.checked_reduce(Weight::from_parts(9, 0)).is_none()); + assert!(weight.checked_reduce(Weight::from_parts(0, 19)).is_none()); + assert_eq!(weight, Weight::from_parts(8, 18)); + assert!(weight.checked_reduce(Weight::from_parts(8, 0)).is_some()); + assert_eq!(weight, Weight::from_parts(0, 18)); + assert!(weight.checked_reduce(Weight::from_parts(0, 18)).is_some()); + assert!(weight.is_zero()); + } } From 65d1d03ff6551afeebf4bb4ca8b972db5e8869a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Thu, 26 Jan 2023 21:37:51 +0100 Subject: [PATCH 336/715] Aura: Fix warp syncing (#13221) * Aura: Fix warp syncing We need to set the fork choice rule! When using Cumulus this is done by the `ParachainsBlockImport`, but for standalone chains we still need this! Closes: https://github.com/paritytech/substrate/issues/13220 * Improve fork choice --- client/consensus/aura/src/import_queue.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/client/consensus/aura/src/import_queue.rs b/client/consensus/aura/src/import_queue.rs index 3ac26345db25e..4c8722c31f206 100644 --- a/client/consensus/aura/src/import_queue.rs +++ b/client/consensus/aura/src/import_queue.rs @@ -186,16 +186,15 @@ where &mut self, mut block: BlockImportParams, ) -> Result<(BlockImportParams, Option)>>), String> { - // When importing whole state we don't verify the seal as the state is not available. - if block.with_state() { - return Ok((block, Default::default())) - } - - // Skip checks that include execution, if being told so. + // Skip checks that include execution, if being told so or when importing only state. // // This is done for example when gap syncing and it is expected that the block after the gap // was checked/chosen properly, e.g. by warp syncing to this block using a finality proof. - if block.state_action.skip_execution_checks() { + // Or when we are importing state only and can not verify the seal. + if block.with_state() || block.state_action.skip_execution_checks() { + // When we are importing only the state of a block, it will be the best block. + block.fork_choice = Some(ForkChoiceStrategy::Custom(block.with_state())); + return Ok((block, Default::default())) } From ff9921a260a67e3a71f25c8b402cd5c7da787a96 Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Thu, 26 Jan 2023 19:35:39 -0300 Subject: [PATCH 337/715] Add Proof Size to Weight Output (#11637) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * initial impl * add template test * linear fit proof size * always record proof when tracking storage * calculate worst case pov * remove duplicate worst case * 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_assets --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/assets/src/weights.rs --template=./.maintain/frame-weight-template.hbs * more comment output * add cli for worst case map size * update name * clap does not support underscores * rename * expose worst case map values * improve some comments * 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_assets --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/assets/src/weights.rs --template=./.maintain/frame-weight-template.hbs * update template * 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_assets --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/assets/src/weights.rs --template=./.maintain/frame-weight-template.hbs * fix fmt * more fmt * more fmt * Dont panic when there is no proof Signed-off-by: Oliver Tale-Yazdi * Fix test features Signed-off-by: Oliver Tale-Yazdi * Whitelist :extrinsic_index Signed-off-by: Oliver Tale-Yazdi * Use whitelist when recording proof Signed-off-by: Oliver Tale-Yazdi * Add logs Signed-off-by: Oliver Tale-Yazdi * Add PoV testing pallet Signed-off-by: Oliver Tale-Yazdi * Deploy PoV testing pallet Signed-off-by: Oliver Tale-Yazdi * Storage benches reside in the PoV pallet Signed-off-by: Oliver Tale-Yazdi * Linear regress PoV per component Splits the PoV calculation into "measured" and "estimated". The measured part is reported by the Proof recorder and linear regressed over all components at once. The estimated part is calculated as worst-case by using the max PoV size per storage access and calculating one linear regress per component. This gives each component a (possibly) independent PoV. For now the measured size will always be lower than the PoV on Polkadot since it is measured on an empty snapshot. The measured part is therefor only used as diagnostic for debugging. Signed-off-by: Oliver Tale-Yazdi * Put PoV into the weight templates Signed-off-by: Oliver Tale-Yazdi * fmt Signed-off-by: Oliver Tale-Yazdi * Extra alanysis choise for PoV Signed-off-by: Oliver Tale-Yazdi * Add+Fix tests Signed-off-by: Oliver Tale-Yazdi * Make benches faster Signed-off-by: Oliver Tale-Yazdi * Cleanup Signed-off-by: Oliver Tale-Yazdi * Use same template comments Signed-off-by: Oliver Tale-Yazdi * ".git/.scripts/bench-bot.sh" pallet dev pallet_balances * ".git/.scripts/bench-bot.sh" pallet dev pallet_democracy * Update referenda mock BlockWeights Signed-off-by: Oliver Tale-Yazdi * Take measured value size into account Signed-off-by: Oliver Tale-Yazdi * clippy Signed-off-by: Oliver Tale-Yazdi * ".git/.scripts/bench-bot.sh" pallet dev pallet_scheduler * WIP Signed-off-by: Oliver Tale-Yazdi * proof_size: None Signed-off-by: Oliver Tale-Yazdi * WIP Signed-off-by: Oliver Tale-Yazdi * WIP Signed-off-by: Oliver Tale-Yazdi * WIP Signed-off-by: Oliver Tale-Yazdi * ugly, but works Signed-off-by: Oliver Tale-Yazdi * WIP Signed-off-by: Oliver Tale-Yazdi * WIP Signed-off-by: Oliver Tale-Yazdi * WIP Signed-off-by: Oliver Tale-Yazdi * wup Signed-off-by: Oliver Tale-Yazdi * WIP Signed-off-by: Oliver Tale-Yazdi * WIP Signed-off-by: Oliver Tale-Yazdi * WIP Signed-off-by: Oliver Tale-Yazdi * WIP Signed-off-by: Oliver Tale-Yazdi * Add pov_mode attribute to the benchmarks! macro Signed-off-by: Oliver Tale-Yazdi * Use pov_mode attribute in PoV benchmarking Signed-off-by: Oliver Tale-Yazdi * Update tests Signed-off-by: Oliver Tale-Yazdi * Scheduler, Whitelist: Add pov_mode attr Signed-off-by: Oliver Tale-Yazdi * Update PoV weights * Add CLI arg: default-pov-mode Signed-off-by: Oliver Tale-Yazdi * Fix tests Signed-off-by: Oliver Tale-Yazdi * fmt Signed-off-by: Oliver Tale-Yazdi * fix Signed-off-by: Oliver Tale-Yazdi * Revert "Update PoV weights" This reverts commit 2f3ac2387396470b118122a6ff8fa4ee12216f4b. * Revert "WIP" This reverts commit c34b538cd2bc45da4544e887180184e30957904a. * Revert first approach This reverts commit range 8ddaa2fffe5930f225a30bee314d0b7c94c344dd^..4c84f8748e5395852a9e0e25b0404953fee1a59e Signed-off-by: Oliver Tale-Yazdi * Clippy Signed-off-by: Oliver Tale-Yazdi * Add extra benchmarks Signed-off-by: Oliver Tale-Yazdi * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_alliance * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_whitelist * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_scheduler * fmt Signed-off-by: Oliver Tale-Yazdi * Clippy Signed-off-by: Oliver Tale-Yazdi * Clippy 🤦 Signed-off-by: Oliver Tale-Yazdi * Add reference benchmarks Signed-off-by: Oliver Tale-Yazdi * Fix doc comments Signed-off-by: Oliver Tale-Yazdi * Undo logging Signed-off-by: Oliver Tale-Yazdi * Add 'Ignored' pov_mode Signed-off-by: Oliver Tale-Yazdi * Allow multiple attributes per benchmark Turns out that the current benchmarking syntax does not support multiple attributes per bench 🤦. Changing it to support that since otherwise the `pov_mode` would conflict with the others. Signed-off-by: Oliver Tale-Yazdi * Validate pov_mode syntax Signed-off-by: Oliver Tale-Yazdi * Ignore PoV for all contract benchmarks Signed-off-by: Oliver Tale-Yazdi * Test Signed-off-by: Oliver Tale-Yazdi * test Signed-off-by: Oliver Tale-Yazdi * Bump macro recursion limit Signed-off-by: Oliver Tale-Yazdi * fmt Signed-off-by: Oliver Tale-Yazdi * Update contract weights They dont have a PoV component anymore. Signed-off-by: Oliver Tale-Yazdi * fix test ffs Signed-off-by: Oliver Tale-Yazdi * pov_mode is unsupported in V2 syntax Signed-off-by: Oliver Tale-Yazdi * Fix pallet ui tests Signed-off-by: Oliver Tale-Yazdi * update pallet ui Signed-off-by: Oliver Tale-Yazdi * Fix pallet ui tests Signed-off-by: Oliver Tale-Yazdi * Update weights Signed-off-by: Oliver Tale-Yazdi Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Parity Bot Co-authored-by: Oliver Tale-Yazdi Co-authored-by: command-bot <> Co-authored-by: Your Name --- .maintain/frame-weight-template.hbs | 35 +- Cargo.lock | 15 + Cargo.toml | 1 + bin/node/runtime/Cargo.toml | 8 +- bin/node/runtime/src/lib.rs | 6 + client/db/src/bench.rs | 4 + client/db/src/upgrade.rs | 2 +- client/db/src/utils.rs | 7 +- frame/alliance/src/weights.rs | 1174 ++-- frame/assets/src/weights.rs | 1061 ++-- frame/bags-list/src/weights.rs | 149 +- frame/balances/src/weights.rs | 201 +- frame/benchmarking/Cargo.toml | 1 + frame/benchmarking/pov/Cargo.toml | 43 + frame/benchmarking/pov/src/benchmarking.rs | 371 ++ frame/benchmarking/pov/src/lib.rs | 131 + frame/benchmarking/pov/src/tests.rs | 211 + frame/benchmarking/pov/src/weights.rs | 807 +++ frame/benchmarking/src/baseline.rs | 63 +- frame/benchmarking/src/lib.rs | 132 +- frame/benchmarking/src/utils.rs | 1 + frame/benchmarking/src/weights.rs | 147 +- frame/bounties/src/weights.rs | 450 +- frame/child-bounties/src/weights.rs | 411 +- frame/collective/src/weights.rs | 659 ++- frame/contracts/src/benchmarking/mod.rs | 120 + frame/contracts/src/lib.rs | 2 +- frame/contracts/src/weights.rs | 4964 +++++++++++------ frame/conviction-voting/src/weights.rs | 351 +- frame/democracy/src/weights.rs | 995 ++-- .../src/weights.rs | 553 +- frame/elections-phragmen/src/weights.rs | 649 ++- frame/identity/src/weights.rs | 829 +-- frame/im-online/src/weights.rs | 77 +- frame/indices/src/weights.rs | 157 +- frame/lottery/src/weights.rs | 290 +- frame/membership/src/weights.rs | 397 +- frame/message-queue/src/weights.rs | 318 +- frame/multisig/src/weights.rs | 277 +- frame/nfts/src/weights.rs | 1814 +++--- frame/nis/src/weights.rs | 522 +- frame/nomination-pools/src/weights.rs | 1199 ++-- frame/preimage/src/weights.rs | 389 +- frame/proxy/src/weights.rs | 431 +- frame/ranked-collective/src/weights.rs | 317 +- frame/recovery/src/weights.rs | 345 +- frame/referenda/src/mock.rs | 2 +- frame/referenda/src/weights.rs | 1162 ++-- frame/remark/src/weights.rs | 27 +- frame/scheduler/src/benchmarking.rs | 4 + frame/scheduler/src/weights.rs | 351 +- frame/session/src/weights.rs | 85 +- frame/staking/src/weights.rs | 1914 ++++--- frame/state-trie-migration/src/weights.rs | 185 +- frame/support/procedural/src/benchmark.rs | 3 + frame/support/src/storage/transactional.rs | 2 + frame/support/src/weights/block_weights.rs | 20 +- .../support/src/weights/extrinsic_weights.rs | 20 +- frame/system/src/weights.rs | 173 +- frame/timestamp/src/weights.rs | 53 +- frame/tips/src/weights.rs | 281 +- frame/transaction-storage/src/weights.rs | 151 +- frame/treasury/src/weights.rs | 241 +- frame/uniques/src/weights.rs | 1127 ++-- frame/utility/src/weights.rs | 99 +- frame/vesting/src/weights.rs | 441 +- frame/whitelist/src/benchmarking.rs | 4 + frame/whitelist/src/weights.rs | 172 +- primitives/storage/src/lib.rs | 2 + scripts/run_all_benchmarks.sh | 2 + .../benchmarking-cli/src/pallet/command.rs | 178 +- .../frame/benchmarking-cli/src/pallet/mod.rs | 31 +- .../benchmarking-cli/src/pallet/template.hbs | 15 +- .../benchmarking-cli/src/pallet/writer.rs | 868 ++- 74 files changed, 19128 insertions(+), 9571 deletions(-) create mode 100644 frame/benchmarking/pov/Cargo.toml create mode 100644 frame/benchmarking/pov/src/benchmarking.rs create mode 100644 frame/benchmarking/pov/src/lib.rs create mode 100644 frame/benchmarking/pov/src/tests.rs create mode 100644 frame/benchmarking/pov/src/weights.rs diff --git a/.maintain/frame-weight-template.hbs b/.maintain/frame-weight-template.hbs index 9c9e297800869..ff69fcb4a2d3d 100644 --- a/.maintain/frame-weight-template.hbs +++ b/.maintain/frame-weight-template.hbs @@ -2,7 +2,8 @@ //! Autogenerated weights for {{pallet}} //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION {{version}} -//! DATE: {{date}}, STEPS: `{{cmd.steps}}`, REPEAT: {{cmd.repeat}}, LOW RANGE: `{{cmd.lowest_range_values}}`, HIGH RANGE: `{{cmd.highest_range_values}}` +//! DATE: {{date}}, STEPS: `{{cmd.steps}}`, REPEAT: `{{cmd.repeat}}`, LOW RANGE: `{{cmd.lowest_range_values}}`, HIGH RANGE: `{{cmd.highest_range_values}}` +//! WORST CASE MAP SIZE: `{{cmd.worst_case_map_values}}` //! HOSTNAME: `{{hostname}}`, CPU: `{{cpuname}}` //! EXECUTION: {{cmd.execution}}, WASM-EXECUTION: {{cmd.wasm_execution}}, CHAIN: {{cmd.chain}}, DB CACHE: {{cmd.db_cache}} @@ -38,7 +39,7 @@ impl WeightInfo for SubstrateWeight { {{/if}} {{#each benchmarks as |benchmark|}} {{#each benchmark.comments as |comment|}} - // {{comment}} + /// {{comment}} {{/each}} {{#each benchmark.component_ranges as |range|}} /// The range of component `{{range.name}}` is `[{{range.min}}, {{range.max}}]`. @@ -48,24 +49,34 @@ impl WeightInfo for SubstrateWeight { {{~#each benchmark.components as |c| ~}} {{~#if (not c.is_used)}}_{{/if}}{{c.name}}: u32, {{/each~}} ) -> Weight { + // Proof Size summary in bytes: + // Measured: `{{benchmark.base_recorded_proof_size}}{{#each benchmark.component_recorded_proof_size as |cp|}} + {{cp.name}} * ({{cp.slope}} ±{{underscore cp.error}}){{/each}}` + // Estimated: `{{benchmark.base_calculated_proof_size}}{{#each benchmark.component_calculated_proof_size as |cp|}} + {{cp.name}} * ({{cp.slope}} ±{{underscore cp.error}}){{/each}}` // Minimum execution time: {{underscore benchmark.min_execution_time}} nanoseconds. + {{#if (ne benchmark.base_calculated_proof_size "0")}} + Weight::from_parts({{underscore benchmark.base_weight}}, {{benchmark.base_calculated_proof_size}}) + {{else}} Weight::from_ref_time({{underscore benchmark.base_weight}}) + {{/if}} {{#each benchmark.component_weight as |cw|}} // Standard Error: {{underscore cw.error}} .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}})) + .saturating_add(T::DbWeight::get().reads({{benchmark.base_reads}}_u64)) {{/if}} {{#each benchmark.component_reads as |cr|}} .saturating_add(T::DbWeight::get().reads(({{cr.slope}}_u64).saturating_mul({{cr.name}}.into()))) {{/each}} {{#if (ne benchmark.base_writes "0")}} - .saturating_add(T::DbWeight::get().writes({{benchmark.base_writes}})) + .saturating_add(T::DbWeight::get().writes({{benchmark.base_writes}}_u64)) {{/if}} {{#each benchmark.component_writes as |cw|}} .saturating_add(T::DbWeight::get().writes(({{cw.slope}}_u64).saturating_mul({{cw.name}}.into()))) {{/each}} + {{#each benchmark.component_calculated_proof_size as |cp|}} + .saturating_add(Weight::from_proof_size({{cp.slope}}).saturating_mul({{cp.name}}.into())) + {{/each}} } {{/each}} } @@ -74,7 +85,7 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { {{#each benchmarks as |benchmark|}} {{#each benchmark.comments as |comment|}} - // {{comment}} + /// {{comment}} {{/each}} {{#each benchmark.component_ranges as |range|}} /// The range of component `{{range.name}}` is `[{{range.min}}, {{range.max}}]`. @@ -84,24 +95,34 @@ impl WeightInfo for () { {{~#each benchmark.components as |c| ~}} {{~#if (not c.is_used)}}_{{/if}}{{c.name}}: u32, {{/each~}} ) -> Weight { + // Proof Size summary in bytes: + // Measured: `{{benchmark.base_recorded_proof_size}}{{#each benchmark.component_recorded_proof_size as |cp|}} + {{cp.name}} * ({{cp.slope}} ±{{underscore cp.error}}){{/each}}` + // Estimated: `{{benchmark.base_calculated_proof_size}}{{#each benchmark.component_calculated_proof_size as |cp|}} + {{cp.name}} * ({{cp.slope}} ±{{underscore cp.error}}){{/each}}` // Minimum execution time: {{underscore benchmark.min_execution_time}} nanoseconds. + {{#if (ne benchmark.base_calculated_proof_size "0")}} + Weight::from_parts({{underscore benchmark.base_weight}}, {{benchmark.base_calculated_proof_size}}) + {{else}} Weight::from_ref_time({{underscore benchmark.base_weight}}) + {{/if}} {{#each benchmark.component_weight as |cw|}} // Standard Error: {{underscore cw.error}} .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}})) + .saturating_add(RocksDbWeight::get().reads({{benchmark.base_reads}}_u64)) {{/if}} {{#each benchmark.component_reads as |cr|}} .saturating_add(RocksDbWeight::get().reads(({{cr.slope}}_u64).saturating_mul({{cr.name}}.into()))) {{/each}} {{#if (ne benchmark.base_writes "0")}} - .saturating_add(RocksDbWeight::get().writes({{benchmark.base_writes}})) + .saturating_add(RocksDbWeight::get().writes({{benchmark.base_writes}}_u64)) {{/if}} {{#each benchmark.component_writes as |cw|}} .saturating_add(RocksDbWeight::get().writes(({{cw.slope}}_u64).saturating_mul({{cw.name}}.into()))) {{/each}} + {{#each benchmark.component_calculated_proof_size as |cp|}} + .saturating_add(Weight::from_proof_size({{cp.slope}}).saturating_mul({{cp.name}}.into())) + {{/each}} } {{/each}} } diff --git a/Cargo.lock b/Cargo.lock index 43f67695faa11..7bbe5469212b2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2203,6 +2203,20 @@ dependencies = [ "thousands", ] +[[package]] +name = "frame-benchmarking-pallet-pov" +version = "4.0.0-dev" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-io", + "sp-runtime", + "sp-std", +] + [[package]] name = "frame-election-provider-solution-type" version = "4.0.0-dev" @@ -3453,6 +3467,7 @@ name = "kitchensink-runtime" version = "3.0.0-dev" dependencies = [ "frame-benchmarking", + "frame-benchmarking-pallet-pov", "frame-election-provider-support", "frame-executive", "frame-support", diff --git a/Cargo.toml b/Cargo.toml index f7eedadd1e8d7..bb52305162ef1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -88,6 +88,7 @@ members = [ "frame/beefy-mmr", "frame/beefy-mmr/primitives", "frame/benchmarking", + "frame/benchmarking/pov", "frame/bounties", "frame/child-bounties", "frame/collective", diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index 76fca730ef7d0..1ff8eb0abd948 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -43,7 +43,8 @@ sp-io = { version = "7.0.0", default-features = false, path = "../../../primitiv # frame dependencies frame-executive = { version = "4.0.0-dev", default-features = false, path = "../../../frame/executive" } -frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../../../frame/benchmarking", optional = true } +frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../../../frame/benchmarking" } +frame-benchmarking-pallet-pov = { version = "4.0.0-dev", default-features = false, path = "../../../frame/benchmarking/pov" } 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" } frame-system-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../../../frame/system/benchmarking", optional = true } @@ -178,7 +179,8 @@ std = [ "sp-session/std", "pallet-sudo/std", "frame-support/std", - "frame-benchmarking?/std", + "frame-benchmarking/std", + "frame-benchmarking-pallet-pov/std", "frame-system-rpc-runtime-api/std", "frame-system/std", "pallet-election-provider-multi-phase/std", @@ -209,6 +211,7 @@ std = [ ] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", + "frame-benchmarking-pallet-pov/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", "sp-runtime/runtime-benchmarks", @@ -263,6 +266,7 @@ runtime-benchmarks = [ ] try-runtime = [ "frame-try-runtime/try-runtime", + "frame-benchmarking-pallet-pov/try-runtime", "frame-executive/try-runtime", "frame-system/try-runtime", "frame-support/try-runtime", diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 0121f1ee3a8ca..bd8a395d15243 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1696,6 +1696,10 @@ impl pallet_alliance::Config for Runtime { type RetirementPeriod = RetirementPeriod; } +impl frame_benchmarking_pallet_pov::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} + construct_runtime!( pub enum Runtime where Block = Block, @@ -1762,6 +1766,7 @@ construct_runtime!( RankedCollective: pallet_ranked_collective, FastUnstake: pallet_fast_unstake, MessageQueue: pallet_message_queue, + Pov: frame_benchmarking_pallet_pov, } ); @@ -1830,6 +1835,7 @@ mod mmr { mod benches { frame_benchmarking::define_benchmarks!( [frame_benchmarking, BaselineBench::] + [frame_benchmarking_pallet_pov, Pov] [pallet_alliance, Alliance] [pallet_assets, Assets] [pallet_babe, Babe] diff --git a/client/db/src/bench.rs b/client/db/src/bench.rs index e53209f27706c..a744762876440 100644 --- a/client/db/src/bench.rs +++ b/client/db/src/bench.rs @@ -606,10 +606,14 @@ impl StateBackend> for BenchmarkingState { let proof_recorder_root = self.proof_recorder_root.get(); if proof_recorder_root == Default::default() || proof_size == 1 { // empty trie + log::debug!(target: "benchmark", "Some proof size: {}", &proof_size); proof_size } else { if let Some(size) = proof.encoded_compact_size::>(proof_recorder_root) { size as u32 + } else if proof_recorder_root == self.root.get() { + log::debug!(target: "benchmark", "No changes - no proof"); + 0 } else { panic!( "proof rec root {:?}, root {:?}, genesis {:?}, rec_len {:?}", diff --git a/client/db/src/upgrade.rs b/client/db/src/upgrade.rs index 51750bf689759..98517acad6e0b 100644 --- a/client/db/src/upgrade.rs +++ b/client/db/src/upgrade.rs @@ -190,7 +190,7 @@ fn version_file_path(path: &Path) -> PathBuf { file_path } -#[cfg(test)] +#[cfg(all(test, feature = "rocksdb"))] mod tests { use super::*; use crate::{tests::Block, DatabaseSource}; diff --git a/client/db/src/utils.rs b/client/db/src/utils.rs index 567950d089e1b..e998511016a67 100644 --- a/client/db/src/utils.rs +++ b/client/db/src/utils.rs @@ -583,12 +583,12 @@ mod tests { use super::*; use codec::Input; use sp_runtime::testing::{Block as RawBlock, ExtrinsicWrapper}; - use std::path::PathBuf; type Block = RawBlock>; - #[cfg(any(feature = "rocksdb", test))] + #[cfg(feature = "rocksdb")] #[test] fn database_type_subdir_migration() { + use std::path::PathBuf; type Block = RawBlock>; fn check_dir_for_db_type( @@ -685,6 +685,7 @@ mod tests { assert_eq!(joined.remaining_len().unwrap(), Some(0)); } + #[cfg(feature = "rocksdb")] #[test] fn test_open_database_auto_new() { let db_dir = tempfile::TempDir::new().unwrap(); @@ -730,6 +731,7 @@ mod tests { } } + #[cfg(feature = "rocksdb")] #[test] fn test_open_database_rocksdb_new() { let db_dir = tempfile::TempDir::new().unwrap(); @@ -780,6 +782,7 @@ mod tests { } } + #[cfg(feature = "rocksdb")] #[test] fn test_open_database_paritydb_new() { let db_dir = tempfile::TempDir::new().unwrap(); diff --git a/frame/alliance/src/weights.rs b/frame/alliance/src/weights.rs index 1cfc83dfc4bbd..9ff6ce612f36e 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) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2023 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,25 +18,25 @@ //! Autogenerated weights for pallet_alliance //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-12-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! 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 -// --json-file=/var/lib/gitlab-runner/builds/zyw4fam_/0/parity/mirrors/substrate/.git/.artifacts/bench.json -// --pallet=pallet_alliance -// --chain=dev -// --header=./HEADER-APACHE2 // --output=./frame/alliance/src/weights.rs +// --header=./HEADER-APACHE2 // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -73,530 +73,832 @@ pub trait WeightInfo { /// 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) + /// Storage: Alliance Members (r:1 w:0) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: AllianceMotion ProposalOf (r:1 w:1) + /// Proof Skipped: AllianceMotion ProposalOf (max_values: None, max_size: None, mode: Measured) + /// Storage: AllianceMotion Proposals (r:1 w:1) + /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion ProposalCount (r:1 w:1) + /// Proof Skipped: AllianceMotion ProposalCount (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion Voting (r:0 w:1) + /// Proof Skipped: AllianceMotion Voting (max_values: None, max_size: None, mode: Measured) /// The range of component `b` is `[1, 1024]`. /// The range of component `m` is `[2, 100]`. /// The range of component `p` is `[1, 100]`. - fn propose_proposed(_b: u32, m: u32, p: u32, ) -> Weight { - // Minimum execution time: 45_945 nanoseconds. - Weight::from_ref_time(44_195_340) - // Standard Error: 2_212 - .saturating_add(Weight::from_ref_time(73_715).saturating_mul(m.into())) - // Standard Error: 2_184 - .saturating_add(Weight::from_ref_time(172_373).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(4)) - } - // Storage: Alliance Members (r:1 w:0) - // Storage: AllianceMotion Voting (r:1 w:1) + fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `692 + m * (32 ±0) + p * (36 ±0)` + // Estimated: `11659 + m * (132 ±0) + p * (144 ±0)` + // Minimum execution time: 28_849 nanoseconds. + Weight::from_parts(29_823_933, 11659) + // Standard Error: 74 + .saturating_add(Weight::from_ref_time(830).saturating_mul(b.into())) + // Standard Error: 775 + .saturating_add(Weight::from_ref_time(22_980).saturating_mul(m.into())) + // Standard Error: 765 + .saturating_add(Weight::from_ref_time(90_520).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + .saturating_add(Weight::from_proof_size(132).saturating_mul(m.into())) + .saturating_add(Weight::from_proof_size(144).saturating_mul(p.into())) + } + /// Storage: Alliance Members (r:1 w:0) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: AllianceMotion Voting (r:1 w:1) + /// Proof Skipped: AllianceMotion Voting (max_values: None, max_size: None, mode: Measured) /// The range of component `m` is `[5, 100]`. fn vote(m: u32, ) -> Weight { - // Minimum execution time: 41_578 nanoseconds. - Weight::from_ref_time(44_299_385) - // Standard Error: 3_727 - .saturating_add(Weight::from_ref_time(138_681).saturating_mul(m.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - // Storage: Alliance Members (r:1 w:0) - // 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) + // Proof Size summary in bytes: + // Measured: `1177 + m * (64 ±0)` + // Estimated: `9337 + m * (64 ±0)` + // Minimum execution time: 23_570 nanoseconds. + Weight::from_parts(25_473_196, 9337) + // Standard Error: 824 + .saturating_add(Weight::from_ref_time(54_603).saturating_mul(m.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + .saturating_add(Weight::from_proof_size(64).saturating_mul(m.into())) + } + /// Storage: Alliance Members (r:1 w:0) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: AllianceMotion Voting (r:1 w:1) + /// Proof Skipped: AllianceMotion Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: AllianceMotion Members (r:1 w:0) + /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion Proposals (r:1 w:1) + /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion ProposalOf (r:0 w:1) + /// Proof Skipped: AllianceMotion ProposalOf (max_values: None, max_size: None, mode: Measured) /// The range of component `m` is `[4, 100]`. /// The range of component `p` is `[1, 100]`. fn close_early_disapproved(m: u32, p: u32, ) -> Weight { - // Minimum execution time: 53_033 nanoseconds. - Weight::from_ref_time(44_608_804) - // Standard Error: 2_306 - .saturating_add(Weight::from_ref_time(102_842).saturating_mul(m.into())) - // Standard Error: 2_248 - .saturating_add(Weight::from_ref_time(172_018).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } - // Storage: Alliance Members (r:1 w:0) - // 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) + // Proof Size summary in bytes: + // Measured: `730 + m * (96 ±0) + p * (36 ±0)` + // Estimated: `11979 + m * (388 ±0) + p * (148 ±0)` + // Minimum execution time: 35_373 nanoseconds. + Weight::from_parts(32_763_656, 11979) + // Standard Error: 2_041 + .saturating_add(Weight::from_ref_time(52_915).saturating_mul(m.into())) + // Standard Error: 1_991 + .saturating_add(Weight::from_ref_time(78_594).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(388).saturating_mul(m.into())) + .saturating_add(Weight::from_proof_size(148).saturating_mul(p.into())) + } + /// Storage: Alliance Members (r:1 w:0) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: AllianceMotion Voting (r:1 w:1) + /// Proof Skipped: AllianceMotion Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: AllianceMotion Members (r:1 w:0) + /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion ProposalOf (r:1 w:1) + /// Proof Skipped: AllianceMotion ProposalOf (max_values: None, max_size: None, mode: Measured) + /// Storage: AllianceMotion Proposals (r:1 w:1) + /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `b` is `[1, 1024]`. /// The range of component `m` is `[4, 100]`. /// The range of component `p` is `[1, 100]`. fn close_early_approved(b: u32, m: u32, p: u32, ) -> Weight { - // Minimum execution time: 61_157 nanoseconds. - Weight::from_ref_time(53_647_510) - // Standard Error: 235 - .saturating_add(Weight::from_ref_time(88).saturating_mul(b.into())) - // Standard Error: 2_486 - .saturating_add(Weight::from_ref_time(103_912).saturating_mul(m.into())) - // Standard Error: 2_424 - .saturating_add(Weight::from_ref_time(197_471).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(3)) - } - // Storage: Alliance Members (r:1 w:0) - // 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) - // Storage: AllianceMotion ProposalOf (r:0 w:1) + // Proof Size summary in bytes: + // Measured: `1139 + m * (96 ±0) + p * (41 ±0)` + // Estimated: `15730 + m * (388 ±0) + p * (164 ±0)` + // Minimum execution time: 44_590 nanoseconds. + Weight::from_parts(43_367_913, 15730) + // Standard Error: 71 + .saturating_add(Weight::from_ref_time(819).saturating_mul(b.into())) + // Standard Error: 751 + .saturating_add(Weight::from_ref_time(39_124).saturating_mul(m.into())) + // Standard Error: 732 + .saturating_add(Weight::from_ref_time(90_469).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(388).saturating_mul(m.into())) + .saturating_add(Weight::from_proof_size(164).saturating_mul(p.into())) + } + /// Storage: Alliance Members (r:1 w:0) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: AllianceMotion Voting (r:1 w:1) + /// Proof Skipped: AllianceMotion Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: AllianceMotion Members (r:1 w:0) + /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion Prime (r:1 w:0) + /// Proof Skipped: AllianceMotion Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion Proposals (r:1 w:1) + /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion ProposalOf (r:0 w:1) + /// Proof Skipped: AllianceMotion ProposalOf (max_values: None, max_size: None, mode: Measured) /// The range of component `m` is `[2, 100]`. /// The range of component `p` is `[1, 100]`. fn close_disapproved(m: u32, p: u32, ) -> Weight { - // Minimum execution time: 53_830 nanoseconds. - Weight::from_ref_time(43_926_698) - // Standard Error: 2_495 - .saturating_add(Weight::from_ref_time(112_814).saturating_mul(m.into())) - // Standard Error: 2_465 - .saturating_add(Weight::from_ref_time(186_422).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(3)) - } - // Storage: Alliance Members (r:1 w:0) - // 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) - // Storage: AllianceMotion ProposalOf (r:0 w:1) + // Proof Size summary in bytes: + // Measured: `730 + m * (96 ±0) + p * (36 ±0)` + // Estimated: `13201 + m * (485 ±0) + p * (185 ±0)` + // Minimum execution time: 36_796 nanoseconds. + Weight::from_parts(34_578_765, 13201) + // Standard Error: 1_037 + .saturating_add(Weight::from_ref_time(43_508).saturating_mul(m.into())) + // Standard Error: 1_024 + .saturating_add(Weight::from_ref_time(77_084).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(485).saturating_mul(m.into())) + .saturating_add(Weight::from_proof_size(185).saturating_mul(p.into())) + } + /// Storage: Alliance Members (r:1 w:0) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: AllianceMotion Voting (r:1 w:1) + /// Proof Skipped: AllianceMotion Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: AllianceMotion Members (r:1 w:0) + /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion Prime (r:1 w:0) + /// Proof Skipped: AllianceMotion Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion Proposals (r:1 w:1) + /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion ProposalOf (r:0 w:1) + /// Proof Skipped: AllianceMotion ProposalOf (max_values: None, max_size: None, mode: Measured) /// The range of component `b` is `[1, 1024]`. /// The range of component `m` is `[5, 100]`. /// The range of component `p` is `[1, 100]`. - fn close_approved(_b: u32, m: u32, p: u32, ) -> Weight { - // Minimum execution time: 53_665 nanoseconds. - Weight::from_ref_time(44_914_913) - // Standard Error: 2_244 - .saturating_add(Weight::from_ref_time(105_848).saturating_mul(m.into())) - // Standard Error: 2_164 - .saturating_add(Weight::from_ref_time(190_830).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(3)) - } - // Storage: Alliance Members (r:2 w:2) - // Storage: AllianceMotion Members (r:1 w:1) + fn close_approved(b: u32, m: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `757 + m * (96 ±0) + p * (36 ±0)` + // Estimated: `13146 + m * (480 ±0) + p * (185 ±0)` + // Minimum execution time: 36_897 nanoseconds. + Weight::from_parts(34_169_666, 13146) + // Standard Error: 47 + .saturating_add(Weight::from_ref_time(972).saturating_mul(b.into())) + // Standard Error: 510 + .saturating_add(Weight::from_ref_time(38_084).saturating_mul(m.into())) + // Standard Error: 492 + .saturating_add(Weight::from_ref_time(78_576).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(480).saturating_mul(m.into())) + .saturating_add(Weight::from_proof_size(185).saturating_mul(p.into())) + } + /// Storage: Alliance Members (r:2 w:2) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: AllianceMotion Members (r:1 w:1) + /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `m` is `[1, 100]`. /// The range of component `z` is `[0, 100]`. fn init_members(m: u32, z: u32, ) -> Weight { - // Minimum execution time: 46_486 nanoseconds. - Weight::from_ref_time(34_596_922) - // Standard Error: 1_807 - .saturating_add(Weight::from_ref_time(143_225).saturating_mul(m.into())) - // Standard Error: 1_786 - .saturating_add(Weight::from_ref_time(125_729).saturating_mul(z.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - } - // Storage: Alliance Members (r:2 w:2) - // 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) + // Proof Size summary in bytes: + // Measured: `217` + // Estimated: `12084` + // Minimum execution time: 29_313 nanoseconds. + Weight::from_parts(20_502_244, 12084) + // Standard Error: 304 + .saturating_add(Weight::from_ref_time(107_994).saturating_mul(m.into())) + // Standard Error: 300 + .saturating_add(Weight::from_ref_time(92_645).saturating_mul(z.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: Alliance Members (r:2 w:2) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: AllianceMotion Proposals (r:1 w:0) + /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Alliance DepositOf (r:200 w:50) + /// Proof: Alliance DepositOf (max_values: None, max_size: Some(64), added: 2539, mode: MaxEncodedLen) + /// Storage: System Account (r:50 w:50) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: AllianceMotion Members (r:0 w:1) + /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion Prime (r:0 w:1) + /// Proof Skipped: AllianceMotion Prime (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `x` is `[1, 100]`. /// The range of component `y` is `[0, 100]`. /// The range of component `z` is `[0, 50]`. fn disband(x: u32, y: u32, z: u32, ) -> Weight { - // Minimum execution time: 251_640 nanoseconds. - Weight::from_ref_time(252_446_000) - // Standard Error: 20_419 - .saturating_add(Weight::from_ref_time(486_667).saturating_mul(x.into())) - // Standard Error: 20_320 - .saturating_add(Weight::from_ref_time(498_890).saturating_mul(y.into())) - // Standard Error: 40_604 - .saturating_add(Weight::from_ref_time(9_411_242).saturating_mul(z.into())) - .saturating_add(T::DbWeight::get().reads(3)) + // Proof Size summary in bytes: + // Measured: `0 + x * (50 ±0) + y * (51 ±0) + z * (283 ±0)` + // Estimated: `32201 + x * (2587 ±0) + y * (2590 ±0) + z * (3209 ±1)` + // Minimum execution time: 232_895 nanoseconds. + Weight::from_parts(233_860_000, 32201) + // Standard Error: 19_092 + .saturating_add(Weight::from_ref_time(445_664).saturating_mul(x.into())) + // Standard Error: 19_000 + .saturating_add(Weight::from_ref_time(432_571).saturating_mul(y.into())) + // Standard Error: 37_965 + .saturating_add(Weight::from_ref_time(9_386_151).saturating_mul(z.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(x.into()))) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(y.into()))) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(z.into()))) - .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(z.into()))) + .saturating_add(Weight::from_proof_size(2587).saturating_mul(x.into())) + .saturating_add(Weight::from_proof_size(2590).saturating_mul(y.into())) + .saturating_add(Weight::from_proof_size(3209).saturating_mul(z.into())) } - // Storage: Alliance Rule (r:0 w:1) + /// Storage: Alliance Rule (r:0 w:1) + /// Proof: Alliance Rule (max_values: Some(1), max_size: Some(87), added: 582, mode: MaxEncodedLen) fn set_rule() -> Weight { - // Minimum execution time: 18_867 nanoseconds. - Weight::from_ref_time(19_155_000) - .saturating_add(T::DbWeight::get().writes(1)) - } - // Storage: Alliance Announcements (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 9_156 nanoseconds. + Weight::from_ref_time(9_376_000) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Alliance Announcements (r:1 w:1) + /// Proof: Alliance Announcements (max_values: Some(1), max_size: Some(8702), added: 9197, mode: MaxEncodedLen) fn announce() -> Weight { - // Minimum execution time: 21_942 nanoseconds. - Weight::from_ref_time(22_319_000) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - // Storage: Alliance Announcements (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `246` + // Estimated: `9197` + // Minimum execution time: 12_163 nanoseconds. + Weight::from_parts(12_397_000, 9197) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Alliance Announcements (r:1 w:1) + /// Proof: Alliance Announcements (max_values: Some(1), max_size: Some(8702), added: 9197, mode: MaxEncodedLen) fn remove_announcement() -> Weight { - // Minimum execution time: 23_419 nanoseconds. - Weight::from_ref_time(23_854_000) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(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) + // Proof Size summary in bytes: + // Measured: `351` + // Estimated: `9197` + // Minimum execution time: 12_778 nanoseconds. + Weight::from_parts(12_991_000, 9197) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Alliance Members (r:3 w:1) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: Alliance UnscrupulousAccounts (r:1 w:0) + /// Proof: Alliance UnscrupulousAccounts (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Alliance DepositOf (r:0 w:1) + /// Proof: Alliance DepositOf (max_values: None, max_size: Some(64), added: 2539, mode: MaxEncodedLen) fn join_alliance() -> Weight { - // Minimum execution time: 53_016 nanoseconds. - Weight::from_ref_time(53_768_000) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(3)) - } - // Storage: Alliance Members (r:3 w:1) - // Storage: Alliance UnscrupulousAccounts (r:1 w:0) + // Proof Size summary in bytes: + // Measured: `562` + // Estimated: `23358` + // Minimum execution time: 40_216 nanoseconds. + Weight::from_parts(40_535_000, 23358) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: Alliance Members (r:3 w:1) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: Alliance UnscrupulousAccounts (r:1 w:0) + /// Proof: Alliance UnscrupulousAccounts (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) fn nominate_ally() -> Weight { - // Minimum execution time: 40_019 nanoseconds. - Weight::from_ref_time(41_087_000) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(1)) - } - // 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) + // Proof Size summary in bytes: + // Measured: `429` + // Estimated: `20755` + // Minimum execution time: 28_027 nanoseconds. + Weight::from_parts(28_392_000, 20755) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Alliance Members (r:2 w:2) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: AllianceMotion Proposals (r:1 w:0) + /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion Members (r:0 w:1) + /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion Prime (r:0 w:1) + /// Proof Skipped: AllianceMotion Prime (max_values: Some(1), max_size: None, mode: Measured) fn elevate_ally() -> Weight { - // Minimum execution time: 35_973 nanoseconds. - Weight::from_ref_time(36_365_000) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(4)) - } - // Storage: Alliance Members (r:4 w:2) - // Storage: AllianceMotion Proposals (r:1 w:0) - // Storage: AllianceMotion Members (r:0 w:1) - // Storage: AllianceMotion Prime (r:0 w:1) - // Storage: Alliance RetiringMembers (r:0 w:1) + // Proof Size summary in bytes: + // Measured: `505` + // Estimated: `13382` + // Minimum execution time: 24_427 nanoseconds. + Weight::from_parts(24_952_000, 13382) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: Alliance Members (r:4 w:2) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: AllianceMotion Proposals (r:1 w:0) + /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion Members (r:0 w:1) + /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion Prime (r:0 w:1) + /// Proof Skipped: AllianceMotion Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Alliance RetiringMembers (r:0 w:1) + /// Proof: Alliance RetiringMembers (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) fn give_retirement_notice() -> Weight { - // Minimum execution time: 44_949 nanoseconds. - Weight::from_ref_time(46_284_000) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(5)) - } - // 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) + // Proof Size summary in bytes: + // Measured: `505` + // Estimated: `24754` + // Minimum execution time: 33_163 nanoseconds. + Weight::from_parts(33_556_000, 24754) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) + } + /// Storage: Alliance RetiringMembers (r:1 w:1) + /// Proof: Alliance RetiringMembers (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: Alliance Members (r:1 w:1) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: Alliance DepositOf (r:1 w:1) + /// Proof: Alliance DepositOf (max_values: None, max_size: Some(64), added: 2539, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn retire() -> Weight { - // Minimum execution time: 45_989 nanoseconds. - Weight::from_ref_time(46_586_000) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(4)) - } - // 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) + // Proof Size summary in bytes: + // Measured: `750` + // Estimated: `13355` + // Minimum execution time: 32_980 nanoseconds. + Weight::from_parts(33_452_000, 13355) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: Alliance Members (r:3 w:1) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: AllianceMotion Proposals (r:1 w:0) + /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Alliance DepositOf (r:1 w:1) + /// Proof: Alliance DepositOf (max_values: None, max_size: Some(64), added: 2539, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: AllianceMotion Members (r:0 w:1) + /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion Prime (r:0 w:1) + /// Proof Skipped: AllianceMotion Prime (max_values: Some(1), max_size: None, mode: Measured) fn kick_member() -> Weight { - // Minimum execution time: 67_333 nanoseconds. - Weight::from_ref_time(68_302_000) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(5)) - } - // Storage: Alliance UnscrupulousAccounts (r:1 w:1) - // Storage: Alliance UnscrupulousWebsites (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `801` + // Estimated: `25098` + // Minimum execution time: 54_660 nanoseconds. + Weight::from_parts(55_186_000, 25098) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) + } + /// Storage: Alliance UnscrupulousAccounts (r:1 w:1) + /// Proof: Alliance UnscrupulousAccounts (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) + /// Storage: Alliance UnscrupulousWebsites (r:1 w:1) + /// Proof: Alliance UnscrupulousWebsites (max_values: Some(1), max_size: Some(25702), added: 26197, mode: MaxEncodedLen) /// The range of component `n` is `[0, 100]`. /// The range of component `l` is `[0, 255]`. fn add_unscrupulous_items(n: u32, l: u32, ) -> Weight { - // Minimum execution time: 16_911 nanoseconds. - Weight::from_ref_time(17_204_000) - // Standard Error: 2_688 - .saturating_add(Weight::from_ref_time(1_324_527).saturating_mul(n.into())) - // Standard Error: 1_052 - .saturating_add(Weight::from_ref_time(73_828).saturating_mul(l.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - // Storage: Alliance UnscrupulousAccounts (r:1 w:1) - // Storage: Alliance UnscrupulousWebsites (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `246` + // Estimated: `29894` + // Minimum execution time: 7_709 nanoseconds. + Weight::from_parts(7_773_000, 29894) + // Standard Error: 2_645 + .saturating_add(Weight::from_ref_time(1_266_755).saturating_mul(n.into())) + // Standard Error: 1_036 + .saturating_add(Weight::from_ref_time(67_359).saturating_mul(l.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: Alliance UnscrupulousAccounts (r:1 w:1) + /// Proof: Alliance UnscrupulousAccounts (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) + /// Storage: Alliance UnscrupulousWebsites (r:1 w:1) + /// Proof: Alliance UnscrupulousWebsites (max_values: Some(1), max_size: Some(25702), added: 26197, mode: MaxEncodedLen) /// The range of component `n` is `[0, 100]`. /// The range of component `l` is `[0, 255]`. fn remove_unscrupulous_items(n: u32, l: u32, ) -> Weight { - // Minimum execution time: 17_117 nanoseconds. - Weight::from_ref_time(17_291_000) - // Standard Error: 166_132 - .saturating_add(Weight::from_ref_time(13_173_211).saturating_mul(n.into())) - // Standard Error: 65_064 - .saturating_add(Weight::from_ref_time(478_626).saturating_mul(l.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - // Storage: Alliance Members (r:3 w:2) - // Storage: AllianceMotion Proposals (r:1 w:0) - // Storage: AllianceMotion Members (r:0 w:1) - // Storage: AllianceMotion Prime (r:0 w:1) + // Proof Size summary in bytes: + // Measured: `0 + n * (289 ±0) + l * (100 ±0)` + // Estimated: `29894` + // Minimum execution time: 7_438 nanoseconds. + Weight::from_parts(7_570_000, 29894) + // Standard Error: 165_072 + .saturating_add(Weight::from_ref_time(13_026_975).saturating_mul(n.into())) + // Standard Error: 64_649 + .saturating_add(Weight::from_ref_time(485_565).saturating_mul(l.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: Alliance Members (r:3 w:2) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: AllianceMotion Proposals (r:1 w:0) + /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion Members (r:0 w:1) + /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion Prime (r:0 w:1) + /// Proof Skipped: AllianceMotion Prime (max_values: Some(1), max_size: None, mode: Measured) fn abdicate_fellow_status() -> Weight { - // Minimum execution time: 43_347 nanoseconds. - Weight::from_ref_time(43_986_000) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(4)) + // Proof Size summary in bytes: + // Measured: `505` + // Estimated: `19068` + // Minimum execution time: 31_326 nanoseconds. + Weight::from_parts(31_768_000, 19068) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) } } // For backwards compatibility and tests impl WeightInfo for () { - // Storage: 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) + /// Storage: Alliance Members (r:1 w:0) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: AllianceMotion ProposalOf (r:1 w:1) + /// Proof Skipped: AllianceMotion ProposalOf (max_values: None, max_size: None, mode: Measured) + /// Storage: AllianceMotion Proposals (r:1 w:1) + /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion ProposalCount (r:1 w:1) + /// Proof Skipped: AllianceMotion ProposalCount (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion Voting (r:0 w:1) + /// Proof Skipped: AllianceMotion Voting (max_values: None, max_size: None, mode: Measured) /// The range of component `b` is `[1, 1024]`. /// The range of component `m` is `[2, 100]`. /// The range of component `p` is `[1, 100]`. - fn propose_proposed(_b: u32, m: u32, p: u32, ) -> Weight { - // Minimum execution time: 45_945 nanoseconds. - Weight::from_ref_time(44_195_340) - // Standard Error: 2_212 - .saturating_add(Weight::from_ref_time(73_715).saturating_mul(m.into())) - // Standard Error: 2_184 - .saturating_add(Weight::from_ref_time(172_373).saturating_mul(p.into())) - .saturating_add(RocksDbWeight::get().reads(4)) - .saturating_add(RocksDbWeight::get().writes(4)) - } - // Storage: Alliance Members (r:1 w:0) - // Storage: AllianceMotion Voting (r:1 w:1) + fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `692 + m * (32 ±0) + p * (36 ±0)` + // Estimated: `11659 + m * (132 ±0) + p * (144 ±0)` + // Minimum execution time: 28_849 nanoseconds. + Weight::from_parts(29_823_933, 11659) + // Standard Error: 74 + .saturating_add(Weight::from_ref_time(830).saturating_mul(b.into())) + // Standard Error: 775 + .saturating_add(Weight::from_ref_time(22_980).saturating_mul(m.into())) + // Standard Error: 765 + .saturating_add(Weight::from_ref_time(90_520).saturating_mul(p.into())) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + .saturating_add(Weight::from_proof_size(132).saturating_mul(m.into())) + .saturating_add(Weight::from_proof_size(144).saturating_mul(p.into())) + } + /// Storage: Alliance Members (r:1 w:0) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: AllianceMotion Voting (r:1 w:1) + /// Proof Skipped: AllianceMotion Voting (max_values: None, max_size: None, mode: Measured) /// The range of component `m` is `[5, 100]`. fn vote(m: u32, ) -> Weight { - // Minimum execution time: 41_578 nanoseconds. - Weight::from_ref_time(44_299_385) - // Standard Error: 3_727 - .saturating_add(Weight::from_ref_time(138_681).saturating_mul(m.into())) - .saturating_add(RocksDbWeight::get().reads(2)) - .saturating_add(RocksDbWeight::get().writes(1)) - } - // Storage: Alliance Members (r:1 w:0) - // 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) + // Proof Size summary in bytes: + // Measured: `1177 + m * (64 ±0)` + // Estimated: `9337 + m * (64 ±0)` + // Minimum execution time: 23_570 nanoseconds. + Weight::from_parts(25_473_196, 9337) + // Standard Error: 824 + .saturating_add(Weight::from_ref_time(54_603).saturating_mul(m.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + .saturating_add(Weight::from_proof_size(64).saturating_mul(m.into())) + } + /// Storage: Alliance Members (r:1 w:0) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: AllianceMotion Voting (r:1 w:1) + /// Proof Skipped: AllianceMotion Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: AllianceMotion Members (r:1 w:0) + /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion Proposals (r:1 w:1) + /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion ProposalOf (r:0 w:1) + /// Proof Skipped: AllianceMotion ProposalOf (max_values: None, max_size: None, mode: Measured) /// The range of component `m` is `[4, 100]`. /// The range of component `p` is `[1, 100]`. fn close_early_disapproved(m: u32, p: u32, ) -> Weight { - // Minimum execution time: 53_033 nanoseconds. - Weight::from_ref_time(44_608_804) - // Standard Error: 2_306 - .saturating_add(Weight::from_ref_time(102_842).saturating_mul(m.into())) - // Standard Error: 2_248 - .saturating_add(Weight::from_ref_time(172_018).saturating_mul(p.into())) - .saturating_add(RocksDbWeight::get().reads(4)) - .saturating_add(RocksDbWeight::get().writes(3)) - } - // Storage: Alliance Members (r:1 w:0) - // 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) + // Proof Size summary in bytes: + // Measured: `730 + m * (96 ±0) + p * (36 ±0)` + // Estimated: `11979 + m * (388 ±0) + p * (148 ±0)` + // Minimum execution time: 35_373 nanoseconds. + Weight::from_parts(32_763_656, 11979) + // Standard Error: 2_041 + .saturating_add(Weight::from_ref_time(52_915).saturating_mul(m.into())) + // Standard Error: 1_991 + .saturating_add(Weight::from_ref_time(78_594).saturating_mul(p.into())) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(388).saturating_mul(m.into())) + .saturating_add(Weight::from_proof_size(148).saturating_mul(p.into())) + } + /// Storage: Alliance Members (r:1 w:0) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: AllianceMotion Voting (r:1 w:1) + /// Proof Skipped: AllianceMotion Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: AllianceMotion Members (r:1 w:0) + /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion ProposalOf (r:1 w:1) + /// Proof Skipped: AllianceMotion ProposalOf (max_values: None, max_size: None, mode: Measured) + /// Storage: AllianceMotion Proposals (r:1 w:1) + /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `b` is `[1, 1024]`. /// The range of component `m` is `[4, 100]`. /// The range of component `p` is `[1, 100]`. fn close_early_approved(b: u32, m: u32, p: u32, ) -> Weight { - // Minimum execution time: 61_157 nanoseconds. - Weight::from_ref_time(53_647_510) - // Standard Error: 235 - .saturating_add(Weight::from_ref_time(88).saturating_mul(b.into())) - // Standard Error: 2_486 - .saturating_add(Weight::from_ref_time(103_912).saturating_mul(m.into())) - // Standard Error: 2_424 - .saturating_add(Weight::from_ref_time(197_471).saturating_mul(p.into())) - .saturating_add(RocksDbWeight::get().reads(5)) - .saturating_add(RocksDbWeight::get().writes(3)) - } - // Storage: Alliance Members (r:1 w:0) - // 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) - // Storage: AllianceMotion ProposalOf (r:0 w:1) + // Proof Size summary in bytes: + // Measured: `1139 + m * (96 ±0) + p * (41 ±0)` + // Estimated: `15730 + m * (388 ±0) + p * (164 ±0)` + // Minimum execution time: 44_590 nanoseconds. + Weight::from_parts(43_367_913, 15730) + // Standard Error: 71 + .saturating_add(Weight::from_ref_time(819).saturating_mul(b.into())) + // Standard Error: 751 + .saturating_add(Weight::from_ref_time(39_124).saturating_mul(m.into())) + // Standard Error: 732 + .saturating_add(Weight::from_ref_time(90_469).saturating_mul(p.into())) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(388).saturating_mul(m.into())) + .saturating_add(Weight::from_proof_size(164).saturating_mul(p.into())) + } + /// Storage: Alliance Members (r:1 w:0) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: AllianceMotion Voting (r:1 w:1) + /// Proof Skipped: AllianceMotion Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: AllianceMotion Members (r:1 w:0) + /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion Prime (r:1 w:0) + /// Proof Skipped: AllianceMotion Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion Proposals (r:1 w:1) + /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion ProposalOf (r:0 w:1) + /// Proof Skipped: AllianceMotion ProposalOf (max_values: None, max_size: None, mode: Measured) /// The range of component `m` is `[2, 100]`. /// The range of component `p` is `[1, 100]`. fn close_disapproved(m: u32, p: u32, ) -> Weight { - // Minimum execution time: 53_830 nanoseconds. - Weight::from_ref_time(43_926_698) - // Standard Error: 2_495 - .saturating_add(Weight::from_ref_time(112_814).saturating_mul(m.into())) - // Standard Error: 2_465 - .saturating_add(Weight::from_ref_time(186_422).saturating_mul(p.into())) - .saturating_add(RocksDbWeight::get().reads(5)) - .saturating_add(RocksDbWeight::get().writes(3)) - } - // Storage: Alliance Members (r:1 w:0) - // 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) - // Storage: AllianceMotion ProposalOf (r:0 w:1) + // Proof Size summary in bytes: + // Measured: `730 + m * (96 ±0) + p * (36 ±0)` + // Estimated: `13201 + m * (485 ±0) + p * (185 ±0)` + // Minimum execution time: 36_796 nanoseconds. + Weight::from_parts(34_578_765, 13201) + // Standard Error: 1_037 + .saturating_add(Weight::from_ref_time(43_508).saturating_mul(m.into())) + // Standard Error: 1_024 + .saturating_add(Weight::from_ref_time(77_084).saturating_mul(p.into())) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(485).saturating_mul(m.into())) + .saturating_add(Weight::from_proof_size(185).saturating_mul(p.into())) + } + /// Storage: Alliance Members (r:1 w:0) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: AllianceMotion Voting (r:1 w:1) + /// Proof Skipped: AllianceMotion Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: AllianceMotion Members (r:1 w:0) + /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion Prime (r:1 w:0) + /// Proof Skipped: AllianceMotion Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion Proposals (r:1 w:1) + /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion ProposalOf (r:0 w:1) + /// Proof Skipped: AllianceMotion ProposalOf (max_values: None, max_size: None, mode: Measured) /// The range of component `b` is `[1, 1024]`. /// The range of component `m` is `[5, 100]`. /// The range of component `p` is `[1, 100]`. - fn close_approved(_b: u32, m: u32, p: u32, ) -> Weight { - // Minimum execution time: 53_665 nanoseconds. - Weight::from_ref_time(44_914_913) - // Standard Error: 2_244 - .saturating_add(Weight::from_ref_time(105_848).saturating_mul(m.into())) - // Standard Error: 2_164 - .saturating_add(Weight::from_ref_time(190_830).saturating_mul(p.into())) - .saturating_add(RocksDbWeight::get().reads(5)) - .saturating_add(RocksDbWeight::get().writes(3)) - } - // Storage: Alliance Members (r:2 w:2) - // Storage: AllianceMotion Members (r:1 w:1) + fn close_approved(b: u32, m: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `757 + m * (96 ±0) + p * (36 ±0)` + // Estimated: `13146 + m * (480 ±0) + p * (185 ±0)` + // Minimum execution time: 36_897 nanoseconds. + Weight::from_parts(34_169_666, 13146) + // Standard Error: 47 + .saturating_add(Weight::from_ref_time(972).saturating_mul(b.into())) + // Standard Error: 510 + .saturating_add(Weight::from_ref_time(38_084).saturating_mul(m.into())) + // Standard Error: 492 + .saturating_add(Weight::from_ref_time(78_576).saturating_mul(p.into())) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(480).saturating_mul(m.into())) + .saturating_add(Weight::from_proof_size(185).saturating_mul(p.into())) + } + /// Storage: Alliance Members (r:2 w:2) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: AllianceMotion Members (r:1 w:1) + /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `m` is `[1, 100]`. /// The range of component `z` is `[0, 100]`. fn init_members(m: u32, z: u32, ) -> Weight { - // Minimum execution time: 46_486 nanoseconds. - Weight::from_ref_time(34_596_922) - // Standard Error: 1_807 - .saturating_add(Weight::from_ref_time(143_225).saturating_mul(m.into())) - // Standard Error: 1_786 - .saturating_add(Weight::from_ref_time(125_729).saturating_mul(z.into())) - .saturating_add(RocksDbWeight::get().reads(3)) - .saturating_add(RocksDbWeight::get().writes(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) - // Storage: AllianceMotion Members (r:0 w:1) - // Storage: AllianceMotion Prime (r:0 w:1) + // Proof Size summary in bytes: + // Measured: `217` + // Estimated: `12084` + // Minimum execution time: 29_313 nanoseconds. + Weight::from_parts(20_502_244, 12084) + // Standard Error: 304 + .saturating_add(Weight::from_ref_time(107_994).saturating_mul(m.into())) + // Standard Error: 300 + .saturating_add(Weight::from_ref_time(92_645).saturating_mul(z.into())) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: Alliance Members (r:2 w:2) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: AllianceMotion Proposals (r:1 w:0) + /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Alliance DepositOf (r:200 w:50) + /// Proof: Alliance DepositOf (max_values: None, max_size: Some(64), added: 2539, mode: MaxEncodedLen) + /// Storage: System Account (r:50 w:50) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: AllianceMotion Members (r:0 w:1) + /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion Prime (r:0 w:1) + /// Proof Skipped: AllianceMotion Prime (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `x` is `[1, 100]`. /// The range of component `y` is `[0, 100]`. /// The range of component `z` is `[0, 50]`. fn disband(x: u32, y: u32, z: u32, ) -> Weight { - // Minimum execution time: 251_640 nanoseconds. - Weight::from_ref_time(252_446_000) - // Standard Error: 20_419 - .saturating_add(Weight::from_ref_time(486_667).saturating_mul(x.into())) - // Standard Error: 20_320 - .saturating_add(Weight::from_ref_time(498_890).saturating_mul(y.into())) - // Standard Error: 40_604 - .saturating_add(Weight::from_ref_time(9_411_242).saturating_mul(z.into())) - .saturating_add(RocksDbWeight::get().reads(3)) + // Proof Size summary in bytes: + // Measured: `0 + x * (50 ±0) + y * (51 ±0) + z * (283 ±0)` + // Estimated: `32201 + x * (2587 ±0) + y * (2590 ±0) + z * (3209 ±1)` + // Minimum execution time: 232_895 nanoseconds. + Weight::from_parts(233_860_000, 32201) + // Standard Error: 19_092 + .saturating_add(Weight::from_ref_time(445_664).saturating_mul(x.into())) + // Standard Error: 19_000 + .saturating_add(Weight::from_ref_time(432_571).saturating_mul(y.into())) + // Standard Error: 37_965 + .saturating_add(Weight::from_ref_time(9_386_151).saturating_mul(z.into())) + .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(x.into()))) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(y.into()))) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(z.into()))) - .saturating_add(RocksDbWeight::get().writes(4)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(RocksDbWeight::get().writes((2_u64).saturating_mul(z.into()))) + .saturating_add(Weight::from_proof_size(2587).saturating_mul(x.into())) + .saturating_add(Weight::from_proof_size(2590).saturating_mul(y.into())) + .saturating_add(Weight::from_proof_size(3209).saturating_mul(z.into())) } - // Storage: Alliance Rule (r:0 w:1) + /// Storage: Alliance Rule (r:0 w:1) + /// Proof: Alliance Rule (max_values: Some(1), max_size: Some(87), added: 582, mode: MaxEncodedLen) fn set_rule() -> Weight { - // Minimum execution time: 18_867 nanoseconds. - Weight::from_ref_time(19_155_000) - .saturating_add(RocksDbWeight::get().writes(1)) - } - // Storage: Alliance Announcements (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 9_156 nanoseconds. + Weight::from_ref_time(9_376_000) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Alliance Announcements (r:1 w:1) + /// Proof: Alliance Announcements (max_values: Some(1), max_size: Some(8702), added: 9197, mode: MaxEncodedLen) fn announce() -> Weight { - // Minimum execution time: 21_942 nanoseconds. - Weight::from_ref_time(22_319_000) - .saturating_add(RocksDbWeight::get().reads(1)) - .saturating_add(RocksDbWeight::get().writes(1)) - } - // Storage: Alliance Announcements (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `246` + // Estimated: `9197` + // Minimum execution time: 12_163 nanoseconds. + Weight::from_parts(12_397_000, 9197) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Alliance Announcements (r:1 w:1) + /// Proof: Alliance Announcements (max_values: Some(1), max_size: Some(8702), added: 9197, mode: MaxEncodedLen) fn remove_announcement() -> Weight { - // Minimum execution time: 23_419 nanoseconds. - Weight::from_ref_time(23_854_000) - .saturating_add(RocksDbWeight::get().reads(1)) - .saturating_add(RocksDbWeight::get().writes(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) + // Proof Size summary in bytes: + // Measured: `351` + // Estimated: `9197` + // Minimum execution time: 12_778 nanoseconds. + Weight::from_parts(12_991_000, 9197) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Alliance Members (r:3 w:1) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: Alliance UnscrupulousAccounts (r:1 w:0) + /// Proof: Alliance UnscrupulousAccounts (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Alliance DepositOf (r:0 w:1) + /// Proof: Alliance DepositOf (max_values: None, max_size: Some(64), added: 2539, mode: MaxEncodedLen) fn join_alliance() -> Weight { - // Minimum execution time: 53_016 nanoseconds. - Weight::from_ref_time(53_768_000) - .saturating_add(RocksDbWeight::get().reads(5)) - .saturating_add(RocksDbWeight::get().writes(3)) - } - // Storage: Alliance Members (r:3 w:1) - // Storage: Alliance UnscrupulousAccounts (r:1 w:0) + // Proof Size summary in bytes: + // Measured: `562` + // Estimated: `23358` + // Minimum execution time: 40_216 nanoseconds. + Weight::from_parts(40_535_000, 23358) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: Alliance Members (r:3 w:1) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: Alliance UnscrupulousAccounts (r:1 w:0) + /// Proof: Alliance UnscrupulousAccounts (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) fn nominate_ally() -> Weight { - // Minimum execution time: 40_019 nanoseconds. - Weight::from_ref_time(41_087_000) - .saturating_add(RocksDbWeight::get().reads(4)) - .saturating_add(RocksDbWeight::get().writes(1)) - } - // 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) + // Proof Size summary in bytes: + // Measured: `429` + // Estimated: `20755` + // Minimum execution time: 28_027 nanoseconds. + Weight::from_parts(28_392_000, 20755) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Alliance Members (r:2 w:2) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: AllianceMotion Proposals (r:1 w:0) + /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion Members (r:0 w:1) + /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion Prime (r:0 w:1) + /// Proof Skipped: AllianceMotion Prime (max_values: Some(1), max_size: None, mode: Measured) fn elevate_ally() -> Weight { - // Minimum execution time: 35_973 nanoseconds. - Weight::from_ref_time(36_365_000) - .saturating_add(RocksDbWeight::get().reads(3)) - .saturating_add(RocksDbWeight::get().writes(4)) - } - // Storage: Alliance Members (r:4 w:2) - // Storage: AllianceMotion Proposals (r:1 w:0) - // Storage: AllianceMotion Members (r:0 w:1) - // Storage: AllianceMotion Prime (r:0 w:1) - // Storage: Alliance RetiringMembers (r:0 w:1) + // Proof Size summary in bytes: + // Measured: `505` + // Estimated: `13382` + // Minimum execution time: 24_427 nanoseconds. + Weight::from_parts(24_952_000, 13382) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + } + /// Storage: Alliance Members (r:4 w:2) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: AllianceMotion Proposals (r:1 w:0) + /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion Members (r:0 w:1) + /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion Prime (r:0 w:1) + /// Proof Skipped: AllianceMotion Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Alliance RetiringMembers (r:0 w:1) + /// Proof: Alliance RetiringMembers (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) fn give_retirement_notice() -> Weight { - // Minimum execution time: 44_949 nanoseconds. - Weight::from_ref_time(46_284_000) - .saturating_add(RocksDbWeight::get().reads(5)) - .saturating_add(RocksDbWeight::get().writes(5)) - } - // 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) + // Proof Size summary in bytes: + // Measured: `505` + // Estimated: `24754` + // Minimum execution time: 33_163 nanoseconds. + Weight::from_parts(33_556_000, 24754) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(5_u64)) + } + /// Storage: Alliance RetiringMembers (r:1 w:1) + /// Proof: Alliance RetiringMembers (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: Alliance Members (r:1 w:1) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: Alliance DepositOf (r:1 w:1) + /// Proof: Alliance DepositOf (max_values: None, max_size: Some(64), added: 2539, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn retire() -> Weight { - // Minimum execution time: 45_989 nanoseconds. - Weight::from_ref_time(46_586_000) - .saturating_add(RocksDbWeight::get().reads(4)) - .saturating_add(RocksDbWeight::get().writes(4)) - } - // 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) + // Proof Size summary in bytes: + // Measured: `750` + // Estimated: `13355` + // Minimum execution time: 32_980 nanoseconds. + Weight::from_parts(33_452_000, 13355) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + } + /// Storage: Alliance Members (r:3 w:1) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: AllianceMotion Proposals (r:1 w:0) + /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Alliance DepositOf (r:1 w:1) + /// Proof: Alliance DepositOf (max_values: None, max_size: Some(64), added: 2539, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: AllianceMotion Members (r:0 w:1) + /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion Prime (r:0 w:1) + /// Proof Skipped: AllianceMotion Prime (max_values: Some(1), max_size: None, mode: Measured) fn kick_member() -> Weight { - // Minimum execution time: 67_333 nanoseconds. - Weight::from_ref_time(68_302_000) - .saturating_add(RocksDbWeight::get().reads(6)) - .saturating_add(RocksDbWeight::get().writes(5)) - } - // Storage: Alliance UnscrupulousAccounts (r:1 w:1) - // Storage: Alliance UnscrupulousWebsites (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `801` + // Estimated: `25098` + // Minimum execution time: 54_660 nanoseconds. + Weight::from_parts(55_186_000, 25098) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(5_u64)) + } + /// Storage: Alliance UnscrupulousAccounts (r:1 w:1) + /// Proof: Alliance UnscrupulousAccounts (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) + /// Storage: Alliance UnscrupulousWebsites (r:1 w:1) + /// Proof: Alliance UnscrupulousWebsites (max_values: Some(1), max_size: Some(25702), added: 26197, mode: MaxEncodedLen) /// The range of component `n` is `[0, 100]`. /// The range of component `l` is `[0, 255]`. fn add_unscrupulous_items(n: u32, l: u32, ) -> Weight { - // Minimum execution time: 16_911 nanoseconds. - Weight::from_ref_time(17_204_000) - // Standard Error: 2_688 - .saturating_add(Weight::from_ref_time(1_324_527).saturating_mul(n.into())) - // Standard Error: 1_052 - .saturating_add(Weight::from_ref_time(73_828).saturating_mul(l.into())) - .saturating_add(RocksDbWeight::get().reads(2)) - .saturating_add(RocksDbWeight::get().writes(2)) - } - // Storage: Alliance UnscrupulousAccounts (r:1 w:1) - // Storage: Alliance UnscrupulousWebsites (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `246` + // Estimated: `29894` + // Minimum execution time: 7_709 nanoseconds. + Weight::from_parts(7_773_000, 29894) + // Standard Error: 2_645 + .saturating_add(Weight::from_ref_time(1_266_755).saturating_mul(n.into())) + // Standard Error: 1_036 + .saturating_add(Weight::from_ref_time(67_359).saturating_mul(l.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: Alliance UnscrupulousAccounts (r:1 w:1) + /// Proof: Alliance UnscrupulousAccounts (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) + /// Storage: Alliance UnscrupulousWebsites (r:1 w:1) + /// Proof: Alliance UnscrupulousWebsites (max_values: Some(1), max_size: Some(25702), added: 26197, mode: MaxEncodedLen) /// The range of component `n` is `[0, 100]`. /// The range of component `l` is `[0, 255]`. fn remove_unscrupulous_items(n: u32, l: u32, ) -> Weight { - // Minimum execution time: 17_117 nanoseconds. - Weight::from_ref_time(17_291_000) - // Standard Error: 166_132 - .saturating_add(Weight::from_ref_time(13_173_211).saturating_mul(n.into())) - // Standard Error: 65_064 - .saturating_add(Weight::from_ref_time(478_626).saturating_mul(l.into())) - .saturating_add(RocksDbWeight::get().reads(2)) - .saturating_add(RocksDbWeight::get().writes(2)) - } - // 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) + // Proof Size summary in bytes: + // Measured: `0 + n * (289 ±0) + l * (100 ±0)` + // Estimated: `29894` + // Minimum execution time: 7_438 nanoseconds. + Weight::from_parts(7_570_000, 29894) + // Standard Error: 165_072 + .saturating_add(Weight::from_ref_time(13_026_975).saturating_mul(n.into())) + // Standard Error: 64_649 + .saturating_add(Weight::from_ref_time(485_565).saturating_mul(l.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: Alliance Members (r:3 w:2) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: AllianceMotion Proposals (r:1 w:0) + /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion Members (r:0 w:1) + /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion Prime (r:0 w:1) + /// Proof Skipped: AllianceMotion Prime (max_values: Some(1), max_size: None, mode: Measured) fn abdicate_fellow_status() -> Weight { - // Minimum execution time: 43_347 nanoseconds. - Weight::from_ref_time(43_986_000) - .saturating_add(RocksDbWeight::get().reads(4)) - .saturating_add(RocksDbWeight::get().writes(4)) + // Proof Size summary in bytes: + // Measured: `505` + // Estimated: `19068` + // Minimum execution time: 31_326 nanoseconds. + Weight::from_parts(31_768_000, 19068) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) } } diff --git a/frame/assets/src/weights.rs b/frame/assets/src/weights.rs index 747198ae3e5ad..c2028105cd4b7 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) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2023 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,7 +18,8 @@ //! Autogenerated weights for pallet_assets //! //! 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: `[]` +//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -50,8 +51,8 @@ pub trait WeightInfo { fn create() -> Weight; fn force_create() -> Weight; fn start_destroy() -> Weight; - fn destroy_accounts(c: u32) -> Weight; - fn destroy_approvals(m: u32) -> Weight; + fn destroy_accounts(c: u32, ) -> Weight; + fn destroy_approvals(a: u32, ) -> Weight; fn finish_destroy() -> Weight; fn mint() -> Weight; fn burn() -> Weight; @@ -78,464 +79,728 @@ pub trait WeightInfo { /// Weights for pallet_assets using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - // Storage: Assets Asset (r:1 w:1) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn create() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `325` + // Estimated: `5288` + // Minimum execution time: 23_623 nanoseconds. + Weight::from_parts(24_072_000, 5288) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) fn force_create() -> Weight { - // 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)) - } - - // Storage: Assets Asset (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `153` + // Estimated: `2685` + // Minimum execution time: 13_145 nanoseconds. + Weight::from_parts(13_572_000, 2685) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) fn start_destroy() -> Weight { - 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) + // Proof Size summary in bytes: + // Measured: `417` + // Estimated: `2685` + // Minimum execution time: 13_420 nanoseconds. + Weight::from_parts(13_649_000, 2685) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Account (r:1001 w:1000) + /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) + /// Storage: System Account (r:1000 w:1000) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `c` is `[0, 1000]`. 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().writes(1 as u64)) - .saturating_add(T::DbWeight::get().writes((2 as u64).saturating_mul(c as u64))) - } - - // Storage: Assets Asset (r:1 w:1) - // Storage: Assets Approvals (r:1 w:0) + // Proof Size summary in bytes: + // Measured: `25 + c * (240 ±0)` + // Estimated: `5262 + c * (5180 ±0)` + // Minimum execution time: 17_565 nanoseconds. + Weight::from_parts(17_757_000, 5262) + // Standard Error: 15_192 + .saturating_add(Weight::from_ref_time(13_799_167).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(c.into()))) + .saturating_add(T::DbWeight::get().writes(1_u64)) + .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(c.into()))) + .saturating_add(Weight::from_proof_size(5180).saturating_mul(c.into())) + } + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Approvals (r:1001 w:1000) + /// Proof: Assets Approvals (max_values: None, max_size: Some(148), added: 2623, mode: MaxEncodedLen) /// The range of component `a` is `[0, 1000]`. 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) + // Proof Size summary in bytes: + // Measured: `554 + a * (86 ±0)` + // Estimated: `5308 + a * (2623 ±0)` + // Minimum execution time: 18_251 nanoseconds. + Weight::from_parts(18_359_000, 5308) + // Standard Error: 10_051 + .saturating_add(Weight::from_ref_time(13_613_342).saturating_mul(a.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(a.into()))) + .saturating_add(T::DbWeight::get().writes(1_u64)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(a.into()))) + .saturating_add(Weight::from_proof_size(2623).saturating_mul(a.into())) + } + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Metadata (r:1 w:0) + /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) fn finish_destroy() -> Weight { - 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) + // Proof Size summary in bytes: + // Measured: `383` + // Estimated: `5300` + // Minimum execution time: 14_344 nanoseconds. + Weight::from_parts(14_619_000, 5300) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Account (r:1 w:1) + /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) fn mint() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `383` + // Estimated: `5262` + // Minimum execution time: 24_992 nanoseconds. + Weight::from_parts(25_784_000, 5262) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Account (r:1 w:1) + /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) fn burn() -> Weight { - // 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)) - } - // Storage: Assets Asset (r:1 w:1) - // Storage: Assets Account (r:2 w:2) - // Storage: System Account (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `491` + // Estimated: `5262` + // Minimum execution time: 31_233 nanoseconds. + Weight::from_parts(31_511_000, 5262) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Account (r:2 w:2) + /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer() -> Weight { - // 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)) - } - // Storage: Assets Asset (r:1 w:1) - // Storage: Assets Account (r:2 w:2) - // Storage: System Account (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `530` + // Estimated: `10442` + // Minimum execution time: 43_002 nanoseconds. + Weight::from_parts(43_533_000, 10442) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Account (r:2 w:2) + /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer_keep_alive() -> Weight { - // 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)) - } - // Storage: Assets Asset (r:1 w:1) - // Storage: Assets Account (r:2 w:2) - // Storage: System Account (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `530` + // Estimated: `10442` + // Minimum execution time: 38_220 nanoseconds. + Weight::from_parts(38_639_000, 10442) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Account (r:2 w:2) + /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn force_transfer() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `530` + // Estimated: `10442` + // Minimum execution time: 43_171 nanoseconds. + Weight::from_parts(43_543_000, 10442) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: Assets Asset (r:1 w:0) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Account (r:1 w:1) + /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) fn freeze() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `491` + // Estimated: `5262` + // Minimum execution time: 16_972 nanoseconds. + Weight::from_parts(17_498_000, 5262) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Assets Asset (r:1 w:0) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Account (r:1 w:1) + /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) fn thaw() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `491` + // Estimated: `5262` + // Minimum execution time: 17_471 nanoseconds. + Weight::from_parts(17_842_000, 5262) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) fn freeze_asset() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `417` + // Estimated: `2685` + // Minimum execution time: 13_497 nanoseconds. + Weight::from_parts(13_719_000, 2685) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) fn thaw_asset() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `417` + // Estimated: `2685` + // Minimum execution time: 13_424 nanoseconds. + Weight::from_parts(13_764_000, 2685) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Metadata (r:1 w:0) + /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) fn transfer_ownership() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `383` + // Estimated: `5300` + // Minimum execution time: 15_028 nanoseconds. + Weight::from_parts(15_366_000, 5300) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) fn set_team() -> Weight { - // 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)) - } - // Storage: Assets Asset (r:1 w:0) - // Storage: Assets Metadata (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `383` + // Estimated: `2685` + // Minimum execution time: 14_197 nanoseconds. + Weight::from_parts(14_437_000, 2685) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Assets Asset (r:1 w:0) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Metadata (r:1 w:1) + /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) /// The range of component `n` is `[0, 50]`. /// The range of component `s` is `[0, 50]`. - 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 set_metadata(n: u32, s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `383` + // Estimated: `5300` + // Minimum execution time: 23_707 nanoseconds. + Weight::from_parts(24_466_834, 5300) + // Standard Error: 635 + .saturating_add(Weight::from_ref_time(730).saturating_mul(n.into())) + // Standard Error: 635 + .saturating_add(Weight::from_ref_time(3_975).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Assets Asset (r:1 w:0) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Metadata (r:1 w:1) + /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) fn clear_metadata() -> Weight { - // 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)) - } - // Storage: Assets Asset (r:1 w:0) - // Storage: Assets Metadata (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `579` + // Estimated: `5300` + // Minimum execution time: 23_997 nanoseconds. + Weight::from_parts(24_812_000, 5300) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Assets Asset (r:1 w:0) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Metadata (r:1 w:1) + /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) /// The range of component `n` is `[0, 50]`. /// The range of component `s` is `[0, 50]`. - fn force_set_metadata(n: u32, s: u32, ) -> Weight { - // 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_set_metadata(_n: u32, s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `190` + // Estimated: `5300` + // Minimum execution time: 14_028 nanoseconds. + Weight::from_parts(15_217_669, 5300) + // Standard Error: 2_266 + .saturating_add(Weight::from_ref_time(2_045).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Assets Asset (r:1 w:0) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Metadata (r:1 w:1) + /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) fn force_clear_metadata() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `579` + // Estimated: `5300` + // Minimum execution time: 23_754 nanoseconds. + Weight::from_parts(24_154_000, 5300) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) fn force_asset_status() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `383` + // Estimated: `2685` + // Minimum execution time: 13_128 nanoseconds. + Weight::from_parts(13_428_000, 2685) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Approvals (r:1 w:1) + /// Proof: Assets Approvals (max_values: None, max_size: Some(148), added: 2623, mode: MaxEncodedLen) fn approve_transfer() -> Weight { - // 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)) - } - // 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) + // Proof Size summary in bytes: + // Measured: `417` + // Estimated: `5308` + // Minimum execution time: 27_224 nanoseconds. + Weight::from_parts(27_665_000, 5308) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Approvals (r:1 w:1) + /// Proof: Assets Approvals (max_values: None, max_size: Some(148), added: 2623, mode: MaxEncodedLen) + /// Storage: Assets Account (r:2 w:2) + /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer_approved() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `700` + // Estimated: `13065` + // Minimum execution time: 55_837 nanoseconds. + Weight::from_parts(56_636_000, 13065) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) + } + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Approvals (r:1 w:1) + /// Proof: Assets Approvals (max_values: None, max_size: Some(148), added: 2623, mode: MaxEncodedLen) fn cancel_approval() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `587` + // Estimated: `5308` + // Minimum execution time: 28_915 nanoseconds. + Weight::from_parts(29_325_000, 5308) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Approvals (r:1 w:1) + /// Proof: Assets Approvals (max_values: None, max_size: Some(148), added: 2623, mode: MaxEncodedLen) fn force_cancel_approval() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `587` + // Estimated: `5308` + // Minimum execution time: 29_103 nanoseconds. + Weight::from_parts(29_599_000, 5308) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } } // For backwards compatibility and tests impl WeightInfo for () { - // Storage: Assets Asset (r:1 w:1) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn create() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `325` + // Estimated: `5288` + // Minimum execution time: 23_623 nanoseconds. + Weight::from_parts(24_072_000, 5288) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) fn force_create() -> Weight { - // 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)) - } - - // Storage: Assets Asset (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `153` + // Estimated: `2685` + // Minimum execution time: 13_145 nanoseconds. + Weight::from_parts(13_572_000, 2685) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) fn start_destroy() -> Weight { - 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) + // Proof Size summary in bytes: + // Measured: `417` + // Estimated: `2685` + // Minimum execution time: 13_420 nanoseconds. + Weight::from_parts(13_649_000, 2685) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Account (r:1001 w:1000) + /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) + /// Storage: System Account (r:1000 w:1000) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `c` is `[0, 1000]`. 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().writes(1 as u64)) - .saturating_add(RocksDbWeight::get().writes((2 as u64).saturating_mul(c as u64))) - } - - // Storage: Assets Asset (r:1 w:1) - // Storage: Assets Approvals (r:1 w:0) + // Proof Size summary in bytes: + // Measured: `25 + c * (240 ±0)` + // Estimated: `5262 + c * (5180 ±0)` + // Minimum execution time: 17_565 nanoseconds. + Weight::from_parts(17_757_000, 5262) + // Standard Error: 15_192 + .saturating_add(Weight::from_ref_time(13_799_167).saturating_mul(c.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(c.into()))) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + .saturating_add(RocksDbWeight::get().writes((2_u64).saturating_mul(c.into()))) + .saturating_add(Weight::from_proof_size(5180).saturating_mul(c.into())) + } + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Approvals (r:1001 w:1000) + /// Proof: Assets Approvals (max_values: None, max_size: Some(148), added: 2623, mode: MaxEncodedLen) /// The range of component `a` is `[0, 1000]`. 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) + // Proof Size summary in bytes: + // Measured: `554 + a * (86 ±0)` + // Estimated: `5308 + a * (2623 ±0)` + // Minimum execution time: 18_251 nanoseconds. + Weight::from_parts(18_359_000, 5308) + // Standard Error: 10_051 + .saturating_add(Weight::from_ref_time(13_613_342).saturating_mul(a.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(a.into()))) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(a.into()))) + .saturating_add(Weight::from_proof_size(2623).saturating_mul(a.into())) + } + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Metadata (r:1 w:0) + /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) fn finish_destroy() -> Weight { - 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) + // Proof Size summary in bytes: + // Measured: `383` + // Estimated: `5300` + // Minimum execution time: 14_344 nanoseconds. + Weight::from_parts(14_619_000, 5300) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Account (r:1 w:1) + /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) fn mint() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `383` + // Estimated: `5262` + // Minimum execution time: 24_992 nanoseconds. + Weight::from_parts(25_784_000, 5262) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Account (r:1 w:1) + /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) fn burn() -> Weight { - // 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)) - } - // Storage: Assets Asset (r:1 w:1) - // Storage: Assets Account (r:2 w:2) - // Storage: System Account (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `491` + // Estimated: `5262` + // Minimum execution time: 31_233 nanoseconds. + Weight::from_parts(31_511_000, 5262) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Account (r:2 w:2) + /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer() -> Weight { - // 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)) - } - // Storage: Assets Asset (r:1 w:1) - // Storage: Assets Account (r:2 w:2) - // Storage: System Account (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `530` + // Estimated: `10442` + // Minimum execution time: 43_002 nanoseconds. + Weight::from_parts(43_533_000, 10442) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + } + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Account (r:2 w:2) + /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer_keep_alive() -> Weight { - // 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)) - } - // Storage: Assets Asset (r:1 w:1) - // Storage: Assets Account (r:2 w:2) - // Storage: System Account (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `530` + // Estimated: `10442` + // Minimum execution time: 38_220 nanoseconds. + Weight::from_parts(38_639_000, 10442) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + } + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Account (r:2 w:2) + /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn force_transfer() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `530` + // Estimated: `10442` + // Minimum execution time: 43_171 nanoseconds. + Weight::from_parts(43_543_000, 10442) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + } + /// Storage: Assets Asset (r:1 w:0) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Account (r:1 w:1) + /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) fn freeze() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `491` + // Estimated: `5262` + // Minimum execution time: 16_972 nanoseconds. + Weight::from_parts(17_498_000, 5262) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Assets Asset (r:1 w:0) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Account (r:1 w:1) + /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) fn thaw() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `491` + // Estimated: `5262` + // Minimum execution time: 17_471 nanoseconds. + Weight::from_parts(17_842_000, 5262) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) fn freeze_asset() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `417` + // Estimated: `2685` + // Minimum execution time: 13_497 nanoseconds. + Weight::from_parts(13_719_000, 2685) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) fn thaw_asset() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `417` + // Estimated: `2685` + // Minimum execution time: 13_424 nanoseconds. + Weight::from_parts(13_764_000, 2685) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Metadata (r:1 w:0) + /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) fn transfer_ownership() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `383` + // Estimated: `5300` + // Minimum execution time: 15_028 nanoseconds. + Weight::from_parts(15_366_000, 5300) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) fn set_team() -> Weight { - // 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)) - } - // Storage: Assets Asset (r:1 w:0) - // Storage: Assets Metadata (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `383` + // Estimated: `2685` + // Minimum execution time: 14_197 nanoseconds. + Weight::from_parts(14_437_000, 2685) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Assets Asset (r:1 w:0) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Metadata (r:1 w:1) + /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) /// The range of component `n` is `[0, 50]`. /// The range of component `s` is `[0, 50]`. - 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 set_metadata(n: u32, s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `383` + // Estimated: `5300` + // Minimum execution time: 23_707 nanoseconds. + Weight::from_parts(24_466_834, 5300) + // Standard Error: 635 + .saturating_add(Weight::from_ref_time(730).saturating_mul(n.into())) + // Standard Error: 635 + .saturating_add(Weight::from_ref_time(3_975).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Assets Asset (r:1 w:0) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Metadata (r:1 w:1) + /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) fn clear_metadata() -> Weight { - // 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)) - } - // Storage: Assets Asset (r:1 w:0) - // Storage: Assets Metadata (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `579` + // Estimated: `5300` + // Minimum execution time: 23_997 nanoseconds. + Weight::from_parts(24_812_000, 5300) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Assets Asset (r:1 w:0) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Metadata (r:1 w:1) + /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) /// The range of component `n` is `[0, 50]`. /// The range of component `s` is `[0, 50]`. - fn force_set_metadata(n: u32, s: u32, ) -> Weight { - // 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_set_metadata(_n: u32, s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `190` + // Estimated: `5300` + // Minimum execution time: 14_028 nanoseconds. + Weight::from_parts(15_217_669, 5300) + // Standard Error: 2_266 + .saturating_add(Weight::from_ref_time(2_045).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Assets Asset (r:1 w:0) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Metadata (r:1 w:1) + /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) fn force_clear_metadata() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `579` + // Estimated: `5300` + // Minimum execution time: 23_754 nanoseconds. + Weight::from_parts(24_154_000, 5300) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) fn force_asset_status() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `383` + // Estimated: `2685` + // Minimum execution time: 13_128 nanoseconds. + Weight::from_parts(13_428_000, 2685) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Approvals (r:1 w:1) + /// Proof: Assets Approvals (max_values: None, max_size: Some(148), added: 2623, mode: MaxEncodedLen) fn approve_transfer() -> Weight { - // 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)) - } - // 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) + // Proof Size summary in bytes: + // Measured: `417` + // Estimated: `5308` + // Minimum execution time: 27_224 nanoseconds. + Weight::from_parts(27_665_000, 5308) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Approvals (r:1 w:1) + /// Proof: Assets Approvals (max_values: None, max_size: Some(148), added: 2623, mode: MaxEncodedLen) + /// Storage: Assets Account (r:2 w:2) + /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer_approved() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `700` + // Estimated: `13065` + // Minimum execution time: 55_837 nanoseconds. + Weight::from_parts(56_636_000, 13065) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(5_u64)) + } + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Approvals (r:1 w:1) + /// Proof: Assets Approvals (max_values: None, max_size: Some(148), added: 2623, mode: MaxEncodedLen) fn cancel_approval() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `587` + // Estimated: `5308` + // Minimum execution time: 28_915 nanoseconds. + Weight::from_parts(29_325_000, 5308) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Approvals (r:1 w:1) + /// Proof: Assets Approvals (max_values: None, max_size: Some(148), added: 2623, mode: MaxEncodedLen) fn force_cancel_approval() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `587` + // Estimated: `5308` + // Minimum execution time: 29_103 nanoseconds. + Weight::from_parts(29_599_000, 5308) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } } diff --git a/frame/bags-list/src/weights.rs b/frame/bags-list/src/weights.rs index a298dc3172f79..d06f7b0db603c 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) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2023 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -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-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -55,70 +56,114 @@ pub trait WeightInfo { /// 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: VoterList ListNodes (r:4 w:4) - // Storage: VoterList ListBags (r:1 w:1) + /// Storage: Staking Bonded (r:1 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:1 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:4 w:4) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:1 w:1) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) fn rebag_non_terminal() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `1916` + // Estimated: `19186` + // Minimum execution time: 54_348 nanoseconds. + Weight::from_parts(55_024_000, 19186) + .saturating_add(T::DbWeight::get().reads(7_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) } - // Storage: Staking Bonded (r:1 w:0) - // Storage: Staking Ledger (r:1 w:0) - // Storage: VoterList ListNodes (r:3 w:3) - // Storage: VoterList ListBags (r:2 w:2) + /// Storage: Staking Bonded (r:1 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:1 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:3 w:3) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:2 w:2) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) fn rebag_terminal() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `1810` + // Estimated: `19114` + // Minimum execution time: 53_306 nanoseconds. + Weight::from_parts(54_263_000, 19114) + .saturating_add(T::DbWeight::get().reads(7_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) } - // Storage: VoterList ListNodes (r:4 w:4) - // Storage: Staking Bonded (r:2 w:0) - // Storage: Staking Ledger (r:2 w:0) - // Storage: VoterList CounterForListNodes (r:1 w:1) - // Storage: VoterList ListBags (r:1 w:1) + /// Storage: VoterList ListNodes (r:4 w:4) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:2 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:2 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: VoterList CounterForListNodes (r:1 w:1) + /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:1 w:1) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) fn put_in_front_of() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `2154` + // Estimated: `25798` + // Minimum execution time: 59_513 nanoseconds. + Weight::from_parts(60_717_000, 25798) + .saturating_add(T::DbWeight::get().reads(10_u64)) + .saturating_add(T::DbWeight::get().writes(6_u64)) } } // For backwards compatibility and tests impl WeightInfo for () { - // Storage: Staking Bonded (r:1 w:0) - // Storage: Staking Ledger (r:1 w:0) - // Storage: VoterList ListNodes (r:4 w:4) - // Storage: VoterList ListBags (r:1 w:1) + /// Storage: Staking Bonded (r:1 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:1 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:4 w:4) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:1 w:1) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) fn rebag_non_terminal() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `1916` + // Estimated: `19186` + // Minimum execution time: 54_348 nanoseconds. + Weight::from_parts(55_024_000, 19186) + .saturating_add(RocksDbWeight::get().reads(7_u64)) + .saturating_add(RocksDbWeight::get().writes(5_u64)) } - // Storage: Staking Bonded (r:1 w:0) - // Storage: Staking Ledger (r:1 w:0) - // Storage: VoterList ListNodes (r:3 w:3) - // Storage: VoterList ListBags (r:2 w:2) + /// Storage: Staking Bonded (r:1 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:1 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:3 w:3) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:2 w:2) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) fn rebag_terminal() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `1810` + // Estimated: `19114` + // Minimum execution time: 53_306 nanoseconds. + Weight::from_parts(54_263_000, 19114) + .saturating_add(RocksDbWeight::get().reads(7_u64)) + .saturating_add(RocksDbWeight::get().writes(5_u64)) } - // Storage: VoterList ListNodes (r:4 w:4) - // Storage: Staking Bonded (r:2 w:0) - // Storage: Staking Ledger (r:2 w:0) - // Storage: VoterList CounterForListNodes (r:1 w:1) - // Storage: VoterList ListBags (r:1 w:1) + /// Storage: VoterList ListNodes (r:4 w:4) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:2 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:2 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: VoterList CounterForListNodes (r:1 w:1) + /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:1 w:1) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) fn put_in_front_of() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `2154` + // Estimated: `25798` + // Minimum execution time: 59_513 nanoseconds. + Weight::from_parts(60_717_000, 25798) + .saturating_add(RocksDbWeight::get().reads(10_u64)) + .saturating_add(RocksDbWeight::get().writes(6_u64)) } } diff --git a/frame/balances/src/weights.rs b/frame/balances/src/weights.rs index 6324745fd4310..3266fcbcd4805 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) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2023 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -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-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -59,106 +60,162 @@ pub trait WeightInfo { /// Weights for pallet_balances using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - // Storage: System Account (r:1 w:1) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `1723` + // Estimated: `2603` + // Minimum execution time: 47_557 nanoseconds. + Weight::from_parts(48_314_000, 2603) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - // Storage: System Account (r:1 w:1) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer_keep_alive() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `1607` + // Estimated: `2603` + // Minimum execution time: 36_372 nanoseconds. + Weight::from_parts(37_432_000, 2603) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - // Storage: System Account (r:1 w:1) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn set_balance_creating() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `1757` + // Estimated: `2603` + // Minimum execution time: 26_671 nanoseconds. + Weight::from_parts(28_287_000, 2603) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - // Storage: System Account (r:1 w:1) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn set_balance_killing() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `1757` + // Estimated: `2603` + // Minimum execution time: 30_122 nanoseconds. + Weight::from_parts(30_615_000, 2603) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - // Storage: System Account (r:2 w:2) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn force_transfer() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `1719` + // Estimated: `5206` + // Minimum execution time: 47_891 nanoseconds. + Weight::from_parts(48_496_000, 5206) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } - // Storage: System Account (r:1 w:1) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer_all() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `1607` + // Estimated: `2603` + // Minimum execution time: 42_470 nanoseconds. + Weight::from_parts(42_950_000, 2603) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - // Storage: System Account (r:1 w:1) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn force_unreserve() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `1641` + // Estimated: `2603` + // Minimum execution time: 23_230 nanoseconds. + Weight::from_parts(23_951_000, 2603) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } } // For backwards compatibility and tests impl WeightInfo for () { - // Storage: System Account (r:1 w:1) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `1723` + // Estimated: `2603` + // Minimum execution time: 47_557 nanoseconds. + Weight::from_parts(48_314_000, 2603) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - // Storage: System Account (r:1 w:1) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer_keep_alive() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `1607` + // Estimated: `2603` + // Minimum execution time: 36_372 nanoseconds. + Weight::from_parts(37_432_000, 2603) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - // Storage: System Account (r:1 w:1) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn set_balance_creating() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `1757` + // Estimated: `2603` + // Minimum execution time: 26_671 nanoseconds. + Weight::from_parts(28_287_000, 2603) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - // Storage: System Account (r:1 w:1) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn set_balance_killing() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `1757` + // Estimated: `2603` + // Minimum execution time: 30_122 nanoseconds. + Weight::from_parts(30_615_000, 2603) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - // Storage: System Account (r:2 w:2) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn force_transfer() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `1719` + // Estimated: `5206` + // Minimum execution time: 47_891 nanoseconds. + Weight::from_parts(48_496_000, 5206) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } - // Storage: System Account (r:1 w:1) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer_all() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `1607` + // Estimated: `2603` + // Minimum execution time: 42_470 nanoseconds. + Weight::from_parts(42_950_000, 2603) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - // Storage: System Account (r:1 w:1) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn force_unreserve() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `1641` + // Estimated: `2603` + // Minimum execution time: 23_230 nanoseconds. + Weight::from_parts(23_951_000, 2603) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } } diff --git a/frame/benchmarking/Cargo.toml b/frame/benchmarking/Cargo.toml index 168b2605738ab..b2a9621ebf250 100644 --- a/frame/benchmarking/Cargo.toml +++ b/frame/benchmarking/Cargo.toml @@ -56,4 +56,5 @@ std = [ ] runtime-benchmarks = [ "frame-system/runtime-benchmarks", + "frame-support/runtime-benchmarks", ] diff --git a/frame/benchmarking/pov/Cargo.toml b/frame/benchmarking/pov/Cargo.toml new file mode 100644 index 0000000000000..d885821bc1fc7 --- /dev/null +++ b/frame/benchmarking/pov/Cargo.toml @@ -0,0 +1,43 @@ +[package] +name = "frame-benchmarking-pallet-pov" +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 = "Pallet for testing FRAME PoV benchmarking" + +[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-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-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"] +std = [ + "codec/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-system/runtime-benchmarks", + "frame-benchmarking/runtime-benchmarks", +] +try-runtime = [ + "frame-support/try-runtime", + "frame-system/try-runtime", +] diff --git a/frame/benchmarking/pov/src/benchmarking.rs b/frame/benchmarking/pov/src/benchmarking.rs new file mode 100644 index 0000000000000..608077e2df806 --- /dev/null +++ b/frame/benchmarking/pov/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. + +//! All benchmarks in this file are just for debugging the PoV calculation logic, they are unused. + +#![cfg(feature = "runtime-benchmarks")] + +use super::*; + +use frame_support::traits::UnfilteredDispatchable; +use frame_system::{Pallet as System, RawOrigin}; +use sp_runtime::traits::Hash; + +frame_benchmarking::benchmarks! { + storage_single_value_read { + Value::::put(123); + }: { + assert_eq!(Value::::get(), Some(123)); + } + + #[pov_mode = Ignored] + storage_single_value_ignored_read { + Value::::put(123); + }: { + assert_eq!(Value::::get(), Some(123)); + } + + storage_single_value_read_twice { + Value::::put(123); + }: { + assert_eq!(Value::::get(), Some(123)); + assert_eq!(Value::::get(), Some(123)); + } + + storage_single_value_write { + }: { + Value::::put(123); + } verify { + assert_eq!(Value::::get(), Some(123)); + } + + storage_single_value_kill { + Value::::put(123); + }: { + Value::::kill(); + } verify { + assert!(!Value::::exists()); + } + + // This benchmark and the following are testing a storage map with adjacent storage items. + // + // First a storage map is filled and a specific number of other storage items is + // created. Then the one value is read from the map. This demonstrates that the number of other + // nodes in the Trie influences the proof size. The number of inserted nodes can be interpreted + // as the number of `StorageMap`/`StorageValue` in the whole runtime. + #[pov_mode = Measured] + storage_1m_map_read_one_value_two_additional_layers { + (0..(1<<10)).for_each(|i| Map1M::::insert(i, i)); + // Assume there are 16-256 other storage items. + (0..(1u32<<4)).for_each(|i| { + let k = T::Hashing::hash(&i.to_be_bytes()); + frame_support::storage::unhashed::put(k.as_ref(), &i); + }); + }: { + assert_eq!(Map1M::::get(1<<9), Some(1<<9)); + } + + #[pov_mode = Measured] + storage_1m_map_read_one_value_three_additional_layers { + (0..(1<<10)).for_each(|i| Map1M::::insert(i, i)); + // Assume there are 256-4096 other storage items. + (0..(1u32<<8)).for_each(|i| { + let k = T::Hashing::hash(&i.to_be_bytes()); + frame_support::storage::unhashed::put(k.as_ref(), &i); + }); + }: { + assert_eq!(Map1M::::get(1<<9), Some(1<<9)); + } + + #[pov_mode = Measured] + storage_1m_map_read_one_value_four_additional_layers { + (0..(1<<10)).for_each(|i| Map1M::::insert(i, i)); + // Assume there are 4096-65536 other storage items. + (0..(1u32<<12)).for_each(|i| { + let k = T::Hashing::hash(&i.to_be_bytes()); + frame_support::storage::unhashed::put(k.as_ref(), &i); + }); + }: { + assert_eq!(Map1M::::get(1<<9), Some(1<<9)); + } + + // Reads from both storage maps each `n` and `m` times. Should result in two linear components. + storage_map_read_per_component { + let n in 0 .. 100; + let m in 0 .. 100; + + (0..m*10).for_each(|i| Map1M::::insert(i, i)); + (0..n*10).for_each(|i| Map16M::::insert(i, i)); + }: { + (0..m).for_each(|i| + assert_eq!(Map1M::::get(i*10), Some(i*10))); + (0..n).for_each(|i| + assert_eq!(Map16M::::get(i*10), Some(i*10))); + } + + #[pov_mode = MaxEncodedLen { + Pov::Map1M: Ignored + }] + storage_map_read_per_component_one_ignored { + let n in 0 .. 100; + let m in 0 .. 100; + + (0..m*10).for_each(|i| Map1M::::insert(i, i)); + (0..n*10).for_each(|i| Map16M::::insert(i, i)); + }: { + (0..m).for_each(|i| + assert_eq!(Map1M::::get(i*10), Some(i*10))); + (0..n).for_each(|i| + assert_eq!(Map16M::::get(i*10), Some(i*10))); + } + + // Reads the same value from a storage map. Should not result in a component. + storage_1m_map_one_entry_repeated_read { + let n in 0 .. 100; + Map1M::::insert(0, 0); + }: { + (0..n).for_each(|i| + assert_eq!(Map1M::::get(0), Some(0))); + } + + // Reads the same values from a storage map. Should result in a `1x` linear component. + storage_1m_map_multiple_entry_repeated_read { + let n in 0 .. 100; + (0..n).for_each(|i| Map1M::::insert(i, i)); + }: { + (0..n).for_each(|i| { + // Reading the same value 10 times does nothing. + (0..10).for_each(|j| + assert_eq!(Map1M::::get(i), Some(i))); + }); + } + + storage_1m_double_map_read_per_component { + let n in 0 .. 1024; + (0..(1<<10)).for_each(|i| DoubleMap1M::::insert(i, i, i)); + }: { + (0..n).for_each(|i| + assert_eq!(DoubleMap1M::::get(i, i), Some(i))); + } + + storage_value_bounded_read { + }: { + assert!(BoundedValue::::get().is_none()); + } + + // Reading unbounded values will produce no mathematical worst case PoV size for this component. + storage_value_unbounded_read { + }: { + assert!(UnboundedValue::::get().is_none()); + } + + #[pov_mode = Ignored] + storage_value_unbounded_ignored_read { + }: { + assert!(UnboundedValue::::get().is_none()); + } + + // Same as above, but we still expect a mathematical worst case PoV size for the bounded one. + storage_value_bounded_and_unbounded_read { + }: { + assert!(UnboundedValue::::get().is_none()); + assert!(BoundedValue::::get().is_none()); + } + + #[pov_mode = Measured] + measured_storage_value_read_linear_size { + let l in 0 .. 1<<22; + let v: sp_runtime::BoundedVec = sp_std::vec![0u8; l as usize].try_into().unwrap(); + LargeValue::::put(&v); + }: { + assert!(LargeValue::::get().is_some()); + } + + #[pov_mode = MaxEncodedLen] + mel_storage_value_read_linear_size { + let l in 0 .. 1<<22; + let v: sp_runtime::BoundedVec = sp_std::vec![0u8; l as usize].try_into().unwrap(); + LargeValue::::put(&v); + }: { + assert!(LargeValue::::get().is_some()); + } + + #[pov_mode = Measured] + measured_storage_double_value_read_linear_size { + let l in 0 .. 1<<22; + let v: sp_runtime::BoundedVec = sp_std::vec![0u8; l as usize].try_into().unwrap(); + LargeValue::::put(&v); + LargeValue2::::put(&v); + }: { + assert!(LargeValue::::get().is_some()); + assert!(LargeValue2::::get().is_some()); + } + + #[pov_mode = MaxEncodedLen] + mel_storage_double_value_read_linear_size { + let l in 0 .. 1<<22; + let v: sp_runtime::BoundedVec = sp_std::vec![0u8; l as usize].try_into().unwrap(); + LargeValue::::put(&v); + LargeValue2::::put(&v); + }: { + assert!(LargeValue::::get().is_some()); + assert!(LargeValue2::::get().is_some()); + } + + #[pov_mode = MaxEncodedLen { + Pov::LargeValue2: Measured + }] + mel_mixed_storage_double_value_read_linear_size { + let l in 0 .. 1<<22; + let v: sp_runtime::BoundedVec = sp_std::vec![0u8; l as usize].try_into().unwrap(); + LargeValue::::put(&v); + LargeValue2::::put(&v); + }: { + assert!(LargeValue::::get().is_some()); + assert!(LargeValue2::::get().is_some()); + } + + #[pov_mode = Measured { + Pov::LargeValue2: MaxEncodedLen + }] + measured_mixed_storage_double_value_read_linear_size { + let l in 0 .. 1<<22; + let v: sp_runtime::BoundedVec = sp_std::vec![0u8; l as usize].try_into().unwrap(); + LargeValue::::put(&v); + LargeValue2::::put(&v); + }: { + assert!(LargeValue::::get().is_some()); + assert!(LargeValue2::::get().is_some()); + } + + #[pov_mode = Measured] + storage_map_unbounded_both_measured_read { + let i in 0 .. 1000; + + UnboundedMap::::insert(i, sp_std::vec![0; i as usize]); + UnboundedMap2::::insert(i, sp_std::vec![0; i as usize]); + }: { + assert!(UnboundedMap::::get(i).is_some()); + assert!(UnboundedMap2::::get(i).is_some()); + } + + #[pov_mode = MaxEncodedLen { + Pov::UnboundedMap: Measured + }] + storage_map_partial_unbounded_read { + let i in 0 .. 1000; + + Map1M::::insert(i, 0); + UnboundedMap::::insert(i, sp_std::vec![0; i as usize]); + }: { + assert!(Map1M::::get(i).is_some()); + assert!(UnboundedMap::::get(i).is_some()); + } + + #[pov_mode = MaxEncodedLen { + Pov::UnboundedMap: Ignored + }] + storage_map_partial_unbounded_ignored_read { + let i in 0 .. 1000; + + Map1M::::insert(i, 0); + UnboundedMap::::insert(i, sp_std::vec![0; i as usize]); + }: { + assert!(Map1M::::get(i).is_some()); + assert!(UnboundedMap::::get(i).is_some()); + } + + // Emitting an event will not incur any PoV. + emit_event { + // Emit a single event. + let call = Call::::emit_event { }; + }: { call.dispatch_bypass_filter(RawOrigin::Root.into()).unwrap(); } + verify { + assert_eq!(System::::events().len(), 1); + } + + // A No-OP will not incur any PoV. + noop { + let call = Call::::noop { }; + }: { + call.dispatch_bypass_filter(RawOrigin::Root.into()).unwrap(); + } + + impl_benchmark_test_suite!( + Pallet, + mock::new_test_ext(), + mock::Test, + ); +} + +#[cfg(test)] +mod mock { + use sp_runtime::testing::H256; + + 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}, + Baseline: crate::{Pallet, Call, Storage, Event}, + } + ); + + impl frame_system::Config for Test { + type BaseCallFilter = frame_support::traits::Everything; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type RuntimeOrigin = RuntimeOrigin; + type Index = AccountIndex; + type BlockNumber = BlockNumber; + type RuntimeCall = RuntimeCall; + type Hash = H256; + type Hashing = ::sp_runtime::traits::BlakeTwo256; + type AccountId = AccountId; + type Lookup = sp_runtime::traits::IdentityLookup; + type Header = sp_runtime::testing::Header; + type RuntimeEvent = RuntimeEvent; + type 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 crate::Config for Test { + type RuntimeEvent = RuntimeEvent; + } + + pub fn new_test_ext() -> sp_io::TestExternalities { + frame_system::GenesisConfig::default().build_storage::().unwrap().into() + } +} diff --git a/frame/benchmarking/pov/src/lib.rs b/frame/benchmarking/pov/src/lib.rs new file mode 100644 index 0000000000000..6618ce60d8ec8 --- /dev/null +++ b/frame/benchmarking/pov/src/lib.rs @@ -0,0 +1,131 @@ +// 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. + +//! End-to-end testing pallet for PoV benchmarking. Should only be deployed in a testing runtime. + +#![cfg_attr(not(feature = "std"), no_std)] + +mod benchmarking; +mod tests; +mod weights; + +pub use pallet::*; + +#[frame_support::pallet] +pub mod pallet { + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + use sp_std::prelude::*; + + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + pub struct Pallet(PhantomData); + + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + } + + #[pallet::storage] + pub(crate) type Value = StorageValue; + + #[pallet::storage] + pub(crate) type Value2 = StorageValue; + + /// A value without a MEL bound. + #[pallet::storage] + #[pallet::unbounded] + pub(crate) type UnboundedValue = + StorageValue, QueryKind = OptionQuery>; + + /// A value with a MEL bound of 32 byte. + #[pallet::storage] + pub(crate) type BoundedValue = + StorageValue>, QueryKind = OptionQuery>; + + /// 4MiB value. + #[pallet::storage] + pub(crate) type LargeValue = + StorageValue>, QueryKind = OptionQuery>; + + #[pallet::storage] + pub(crate) type LargeValue2 = + StorageValue>, QueryKind = OptionQuery>; + + /// A map with a maximum of 1M entries. + #[pallet::storage] + pub(crate) type Map1M = StorageMap< + Hasher = Blake2_256, + Key = u32, + Value = u32, + QueryKind = OptionQuery, + MaxValues = ConstU32<1_000_000>, + >; + + /// A map with a maximum of 16M entries. + #[pallet::storage] + pub(crate) type Map16M = StorageMap< + Hasher = Blake2_256, + Key = u32, + Value = u32, + QueryKind = OptionQuery, + MaxValues = ConstU32<16_000_000>, + >; + + #[pallet::storage] + pub(crate) type DoubleMap1M = StorageDoubleMap< + Hasher1 = Blake2_256, + Hasher2 = Blake2_256, + Key1 = u32, + Key2 = u32, + Value = u32, + QueryKind = OptionQuery, + MaxValues = ConstU32<1_000_000>, + >; + + #[pallet::storage] + #[pallet::unbounded] + pub(crate) type UnboundedMap = + StorageMap, QueryKind = OptionQuery>; + + #[pallet::storage] + #[pallet::unbounded] + pub(crate) type UnboundedMap2 = + StorageMap, QueryKind = OptionQuery>; + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + TestEvent, + } + + #[pallet::call] + impl Pallet { + #[pallet::call_index(0)] + #[pallet::weight(0)] + pub fn emit_event(_origin: OriginFor) -> DispatchResult { + Self::deposit_event(Event::TestEvent); + Ok(()) + } + + #[pallet::call_index(1)] + #[pallet::weight(0)] + pub fn noop(_origin: OriginFor) -> DispatchResult { + Ok(()) + } + } +} diff --git a/frame/benchmarking/pov/src/tests.rs b/frame/benchmarking/pov/src/tests.rs new file mode 100644 index 0000000000000..1100fdc46f813 --- /dev/null +++ b/frame/benchmarking/pov/src/tests.rs @@ -0,0 +1,211 @@ +// 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. + +//! Test the produces weight functions. + +#![cfg(test)] + +use super::weights::WeightInfo; +use mock::Test as T; +type W = crate::weights::SubstrateWeight; + +#[test] +fn writing_is_free() { + let w = W::storage_single_value_write().proof_size(); + assert_eq!(w, 0, "Writing is free"); +} + +#[test] +fn killing_is_free() { + // NOTE: This only applies to state version 1. + let w = W::storage_single_value_kill().proof_size(); + assert_eq!(w, 0, "Killing is free"); +} + +#[test] +fn reading_twice_is_the_same_as_once() { + let w = W::storage_single_value_read().proof_size(); + let w2 = W::storage_single_value_read_twice().proof_size(); + assert_eq!(w, w2, "Reading twice is the same as once"); +} + +#[test] +fn storage_single_value_ignored_read_no_pov() { + let w = W::storage_single_value_ignored_read(); + assert_eq!(w.proof_size(), 0, "Ignored PoV does not result in PoV"); +} + +#[test] +fn storage_single_value_ignored_some_read_has_pov() { + let w = W::storage_single_value_ignored_some_read(); + assert!(w.proof_size() != 0, "Ignored some does result in PoV"); +} + +/// Reading the same value from a map does not increase the PoV. +#[test] +fn storage_1m_map_one_entry_repeated_read_const() { + let weight = W::storage_1m_map_one_entry_repeated_read; + let w0 = weight(0).proof_size(); + assert!(w0 > 0, "There is a base weight"); + + let w1 = weight(1).proof_size(); + assert_eq!(w0, w1, "Component does not matter"); +} + +/// Reading multiple values multiple times from a map increases the PoV by the number of reads. +#[test] +fn storage_1m_map_multiple_entry_repeated_read_single_linear() { + let weight = W::storage_1m_map_multiple_entry_repeated_read; + let w0 = weight(0).proof_size(); + + let w1 = weight(1).proof_size() - w0; + assert!(w1 > 0, "Component matters"); + + let wm = weight(1000).proof_size(); + assert_eq!(w1 * 1000 + w0, wm, "x scales linearly"); +} + +/// Check that reading two maps at once increases the PoV linearly per map. +#[test] +fn storage_map_read_per_component_double_linear() { + let weight = W::storage_map_read_per_component; + let w00 = weight(0, 0).proof_size(); + + let w10 = weight(1, 0).proof_size() - w00; + let w01 = weight(0, 1).proof_size() - w00; + assert!(w10 > 0 && w01 > 0, "Components matter"); + assert!(w10 != w01, "Each map has its own component"); + + let wm0 = weight(1000, 0).proof_size(); + let w0m = weight(0, 1000).proof_size(); + assert_eq!(w00 + w10 * 1000, wm0, "x scales linearly"); + assert_eq!(w00 + w01 * 1000, w0m, "y scales linearly"); + + let wmm = weight(1000, 1000).proof_size(); + assert_eq!(wmm + w00, wm0 + w0m, "x + y scales linearly"); +} + +/// The proof size estimation takes the measured sizes into account and therefore increases with the +/// number of layers. +#[test] +fn additional_layers_do_not_matter() { + let w2 = W::storage_1m_map_read_one_value_two_additional_layers().proof_size(); + let w3 = W::storage_1m_map_read_one_value_three_additional_layers().proof_size(); + let w4 = W::storage_1m_map_read_one_value_four_additional_layers().proof_size(); + assert!(w3 > w2 && w4 > w3, "Additional layers do matter"); +} + +/// Check that the measured value size instead of the MEL is used. +#[test] +fn linear_measured_size_works() { + let weight = W::measured_storage_value_read_linear_size; + + let w0 = weight(0).proof_size(); + let w1 = weight(1).proof_size() - w0; + + assert_eq!(w1, 1, "x scales with a factor of 1"); + let wm = weight(1000).proof_size(); + assert_eq!(w1 * 1000 + w0, wm, "x scales linearly"); +} + +// vice-versa of above `linear_measured_size_works`. +#[test] +fn linear_mel_size_works() { + let weight = W::mel_storage_value_read_linear_size; + + let w1 = weight(1).proof_size(); + let wm = weight(1000).proof_size(); + assert_eq!(w1, wm, "PoV size is const"); +} + +/// Although there is no estimation possible, it uses the recorded proof size as best effort. +#[test] +fn unbounded_read_best_effort() { + let w = W::storage_value_unbounded_read().proof_size(); + assert!(w > 0, "There is a weight"); +} + +/// For mixed unbounded and bounded reads, the bounded part still increases the PoV. +#[test] +fn partial_unbounded_read_best_effort() { + let w_unbounded = W::storage_value_unbounded_read().proof_size(); + let w_bounded = W::storage_value_bounded_read().proof_size(); + let w_partial = W::storage_value_bounded_and_unbounded_read().proof_size(); + + assert_eq!(w_bounded + w_unbounded, w_partial, "The bounded part increases the PoV"); +} + +#[test] +fn emit_event_is_free() { + let w = W::emit_event().proof_size(); + assert_eq!(w, 0, "Emitting an event is free"); +} + +#[test] +fn noop_is_free() { + let w = W::noop().proof_size(); + assert_eq!(w, 0, "Noop is free"); +} + +mod mock { + use sp_runtime::testing::H256; + + 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}, + Baseline: crate::{Pallet, Call, Storage, Event}, + } + ); + + impl frame_system::Config for Test { + type BaseCallFilter = frame_support::traits::Everything; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type RuntimeOrigin = RuntimeOrigin; + type Index = u32; + type BlockNumber = u64; + type RuntimeCall = RuntimeCall; + type Hash = H256; + type Hashing = ::sp_runtime::traits::BlakeTwo256; + type AccountId = u32; + type Lookup = sp_runtime::traits::IdentityLookup; + type Header = sp_runtime::testing::Header; + type RuntimeEvent = RuntimeEvent; + type 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 crate::Config for Test { + type RuntimeEvent = RuntimeEvent; + } +} diff --git a/frame/benchmarking/pov/src/weights.rs b/frame/benchmarking/pov/src/weights.rs new file mode 100644 index 0000000000000..e890e9b2ef88a --- /dev/null +++ b/frame/benchmarking/pov/src/weights.rs @@ -0,0 +1,807 @@ + +//! Autogenerated weights for frame_benchmarking_pallet_pov +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-01-23, STEPS: `50`, REPEAT: `1`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `oty-parity`, CPU: `11th Gen Intel(R) Core(TM) i7-1165G7 @ 2.80GHz` +//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 1024 + +// Executed Command: +// ./target/release/substrate +// benchmark +// pallet +// --dev +// --pallet +// frame-benchmarking-pallet-pov +// --extrinsic +// +// --steps +// 50 +// --repeat +// 1 +// --template=.maintain/frame-weight-template.hbs +// --output=frame/benchmarking/pov/src/weights.rs + +#![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_pallet_pov. +pub trait WeightInfo { + fn storage_single_value_read() -> Weight; + fn storage_single_value_ignored_read() -> Weight; + fn storage_single_value_ignored_some_read() -> Weight; + fn storage_single_value_read_twice() -> Weight; + fn storage_single_value_write() -> Weight; + fn storage_single_value_kill() -> Weight; + fn storage_1m_map_read_one_value_two_additional_layers() -> Weight; + fn storage_1m_map_read_one_value_three_additional_layers() -> Weight; + fn storage_1m_map_read_one_value_four_additional_layers() -> Weight; + fn storage_map_read_per_component(n: u32, m: u32, ) -> Weight; + fn storage_map_read_per_component_one_ignored(n: u32, m: u32, ) -> Weight; + fn storage_1m_map_one_entry_repeated_read(n: u32, ) -> Weight; + fn storage_1m_map_multiple_entry_repeated_read(n: u32, ) -> Weight; + fn storage_1m_double_map_read_per_component(n: u32, ) -> Weight; + fn storage_value_bounded_read() -> Weight; + fn storage_value_unbounded_read() -> Weight; + fn storage_value_unbounded_ignored_read() -> Weight; + fn storage_value_bounded_and_unbounded_read() -> Weight; + fn measured_storage_value_read_linear_size(l: u32, ) -> Weight; + fn mel_storage_value_read_linear_size(l: u32, ) -> Weight; + fn measured_storage_double_value_read_linear_size(l: u32, ) -> Weight; + fn mel_storage_double_value_read_linear_size(l: u32, ) -> Weight; + fn mel_mixed_storage_double_value_read_linear_size(l: u32, ) -> Weight; + fn measured_mixed_storage_double_value_read_linear_size(l: u32, ) -> Weight; + fn storage_map_unbounded_both_measured_read(i: u32, ) -> Weight; + fn storage_map_partial_unbounded_read(i: u32, ) -> Weight; + fn storage_map_partial_unbounded_ignored_read(i: u32, ) -> Weight; + fn emit_event() -> Weight; + fn noop() -> Weight; +} + +/// Weights for frame_benchmarking_pallet_pov using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + /// Storage: Pov Value (r:1 w:0) + /// Proof: Pov Value (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + fn storage_single_value_read() -> Weight { + // Proof Size summary in bytes: + // Measured: `136` + // Estimated: `499` + // Minimum execution time: 3_291 nanoseconds. + Weight::from_parts(3_291_000, 499) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + /// Storage: Pov Value (r:1 w:0) + /// Proof: Pov Value (max_values: Some(1), max_size: Some(4), added: 499, mode: Ignored) + fn storage_single_value_ignored_read() -> Weight { + // Proof Size summary in bytes: + // Measured: `136` + // Estimated: `0` + // Minimum execution time: 2_918 nanoseconds. + Weight::from_ref_time(2_918_000) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + /// Storage: Pov Value (r:1 w:0) + /// Proof: Pov Value (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Pov Value2 (r:1 w:0) + /// Proof: Pov Value2 (max_values: Some(1), max_size: Some(4), added: 499, mode: Ignored) + fn storage_single_value_ignored_some_read() -> Weight { + // Proof Size summary in bytes: + // Measured: `160` + // Estimated: `659` + // Minimum execution time: 4_056 nanoseconds. + Weight::from_parts(4_056_000, 659) + .saturating_add(T::DbWeight::get().reads(2_u64)) + } + /// Storage: Pov Value (r:1 w:0) + /// Proof: Pov Value (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + fn storage_single_value_read_twice() -> Weight { + // Proof Size summary in bytes: + // Measured: `136` + // Estimated: `499` + // Minimum execution time: 3_552 nanoseconds. + Weight::from_parts(3_552_000, 499) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + /// Storage: Pov Value (r:0 w:1) + /// Proof: Pov Value (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + fn storage_single_value_write() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 795 nanoseconds. + Weight::from_ref_time(795_000) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Pov Value (r:0 w:1) + /// Proof: Pov Value (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + fn storage_single_value_kill() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 865 nanoseconds. + Weight::from_ref_time(865_000) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Pov Map1M (r:1 w:0) + /// Proof: Pov Map1M (max_values: Some(1000000), max_size: Some(36), added: 2511, mode: Measured) + fn storage_1m_map_read_one_value_two_additional_layers() -> Weight { + // Proof Size summary in bytes: + // Measured: `1275` + // Estimated: `3750` + // Minimum execution time: 9_571 nanoseconds. + Weight::from_parts(9_571_000, 3750) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + /// Storage: Pov Map1M (r:1 w:0) + /// Proof: Pov Map1M (max_values: Some(1000000), max_size: Some(36), added: 2511, mode: Measured) + fn storage_1m_map_read_one_value_three_additional_layers() -> Weight { + // Proof Size summary in bytes: + // Measured: `1544` + // Estimated: `4019` + // Minimum execution time: 14_597 nanoseconds. + Weight::from_parts(14_597_000, 4019) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + /// Storage: Pov Map1M (r:1 w:0) + /// Proof: Pov Map1M (max_values: Some(1000000), max_size: Some(36), added: 2511, mode: Measured) + fn storage_1m_map_read_one_value_four_additional_layers() -> Weight { + // Proof Size summary in bytes: + // Measured: `2044` + // Estimated: `4519` + // Minimum execution time: 19_793 nanoseconds. + Weight::from_parts(19_793_000, 4519) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + /// Storage: Pov Map1M (r:100 w:0) + /// Proof: Pov Map1M (max_values: Some(1000000), max_size: Some(36), added: 2511, mode: MaxEncodedLen) + /// Storage: Pov Map16M (r:100 w:0) + /// Proof: Pov Map16M (max_values: Some(16000000), max_size: Some(36), added: 3006, mode: MaxEncodedLen) + /// The range of component `n` is `[0, 100]`. + /// The range of component `m` is `[0, 100]`. + fn storage_map_read_per_component(n: u32, m: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `515 + n * (188 ±0) + m * (188 ±0)` + // Estimated: `0 + n * (3006 ±0) + m * (2511 ±0)` + // Minimum execution time: 266_160 nanoseconds. + Weight::from_ref_time(190_477_747) + // Standard Error: 96_405 + .saturating_add(Weight::from_ref_time(1_049_993).saturating_mul(n.into())) + // Standard Error: 96_405 + .saturating_add(Weight::from_ref_time(1_202_546).saturating_mul(m.into())) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(m.into()))) + .saturating_add(Weight::from_proof_size(3006).saturating_mul(n.into())) + .saturating_add(Weight::from_proof_size(2511).saturating_mul(m.into())) + } + /// Storage: Pov Map1M (r:100 w:0) + /// Proof: Pov Map1M (max_values: Some(1000000), max_size: Some(36), added: 2511, mode: Ignored) + /// Storage: Pov Map16M (r:100 w:0) + /// Proof: Pov Map16M (max_values: Some(16000000), max_size: Some(36), added: 3006, mode: MaxEncodedLen) + /// The range of component `n` is `[0, 100]`. + /// The range of component `m` is `[0, 100]`. + fn storage_map_read_per_component_one_ignored(n: u32, m: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `515 + n * (188 ±0) + m * (188 ±0)` + // Estimated: `695 + n * (3195 ±2) + m * (189 ±2)` + // Minimum execution time: 265_113 nanoseconds. + Weight::from_parts(215_943_973, 695) + // Standard Error: 199_907 + .saturating_add(Weight::from_ref_time(988_371).saturating_mul(n.into())) + // Standard Error: 199_907 + .saturating_add(Weight::from_ref_time(1_145_693).saturating_mul(m.into())) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(m.into()))) + .saturating_add(Weight::from_proof_size(3195).saturating_mul(n.into())) + .saturating_add(Weight::from_proof_size(189).saturating_mul(m.into())) + } + /// Storage: Pov Map1M (r:1 w:0) + /// Proof: Pov Map1M (max_values: Some(1000000), max_size: Some(36), added: 2511, mode: MaxEncodedLen) + /// The range of component `n` is `[0, 100]`. + fn storage_1m_map_one_entry_repeated_read(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `170` + // Estimated: `2511` + // Minimum execution time: 119 nanoseconds. + Weight::from_parts(3_649_405, 2511) + // Standard Error: 4_472 + .saturating_add(Weight::from_ref_time(432_147).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + /// Storage: Pov Map1M (r:100 w:0) + /// Proof: Pov Map1M (max_values: Some(1000000), max_size: Some(36), added: 2511, mode: MaxEncodedLen) + /// The range of component `n` is `[0, 100]`. + fn storage_1m_map_multiple_entry_repeated_read(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `147 + n * (40 ±0)` + // Estimated: `0 + n * (2511 ±0)` + // Minimum execution time: 106 nanoseconds. + Weight::from_ref_time(59_892_609) + // Standard Error: 418_004 + .saturating_add(Weight::from_ref_time(5_919_793).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_proof_size(2511).saturating_mul(n.into())) + } + /// Storage: Pov DoubleMap1M (r:1024 w:0) + /// Proof: Pov DoubleMap1M (max_values: Some(1000000), max_size: Some(68), added: 2543, mode: MaxEncodedLen) + /// The range of component `n` is `[0, 1024]`. + fn storage_1m_double_map_read_per_component(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `21938 + n * (57 ±0)` + // Estimated: `0 + n * (2543 ±0)` + // Minimum execution time: 550 nanoseconds. + Weight::from_ref_time(65_431_603) + // Standard Error: 66_935 + .saturating_add(Weight::from_ref_time(2_825_371).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_proof_size(2543).saturating_mul(n.into())) + } + /// Storage: Pov BoundedValue (r:1 w:0) + /// Proof: Pov BoundedValue (max_values: Some(1), max_size: Some(33), added: 528, mode: MaxEncodedLen) + fn storage_value_bounded_read() -> Weight { + // Proof Size summary in bytes: + // Measured: `109` + // Estimated: `528` + // Minimum execution time: 2_541 nanoseconds. + Weight::from_parts(2_541_000, 528) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + /// Storage: Pov UnboundedValue (r:1 w:0) + /// Proof Skipped: Pov UnboundedValue (max_values: Some(1), max_size: None, mode: Measured) + fn storage_value_unbounded_read() -> Weight { + // Proof Size summary in bytes: + // Measured: `109` + // Estimated: `604` + // Minimum execution time: 2_226 nanoseconds. + Weight::from_parts(2_226_000, 604) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + /// Storage: Pov UnboundedValue (r:1 w:0) + /// Proof Skipped: Pov UnboundedValue (max_values: Some(1), max_size: None, mode: Ignored) + fn storage_value_unbounded_ignored_read() -> Weight { + // Proof Size summary in bytes: + // Measured: `109` + // Estimated: `0` + // Minimum execution time: 2_100 nanoseconds. + Weight::from_ref_time(2_100_000) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + /// Storage: Pov UnboundedValue (r:1 w:0) + /// Proof Skipped: Pov UnboundedValue (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Pov BoundedValue (r:1 w:0) + /// Proof: Pov BoundedValue (max_values: Some(1), max_size: Some(33), added: 528, mode: MaxEncodedLen) + fn storage_value_bounded_and_unbounded_read() -> Weight { + // Proof Size summary in bytes: + // Measured: `109` + // Estimated: `1132` + // Minimum execution time: 2_808 nanoseconds. + Weight::from_parts(2_808_000, 1132) + .saturating_add(T::DbWeight::get().reads(2_u64)) + } + /// Storage: Pov LargeValue (r:1 w:0) + /// Proof: Pov LargeValue (max_values: Some(1), max_size: Some(4194308), added: 4194803, mode: Measured) + /// The range of component `l` is `[0, 4194304]`. + fn measured_storage_value_read_linear_size(l: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `174 + l * (1 ±0)` + // Estimated: `666 + l * (1 ±0)` + // Minimum execution time: 3_385 nanoseconds. + Weight::from_parts(3_385_000, 666) + // Standard Error: 10 + .saturating_add(Weight::from_ref_time(356).saturating_mul(l.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(Weight::from_proof_size(1).saturating_mul(l.into())) + } + /// Storage: Pov LargeValue (r:1 w:0) + /// Proof: Pov LargeValue (max_values: Some(1), max_size: Some(4194308), added: 4194803, mode: MaxEncodedLen) + /// The range of component `l` is `[0, 4194304]`. + fn mel_storage_value_read_linear_size(l: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `174 + l * (1 ±0)` + // Estimated: `4194803` + // Minimum execution time: 3_342 nanoseconds. + Weight::from_parts(3_342_000, 4194803) + // Standard Error: 6 + .saturating_add(Weight::from_ref_time(345).saturating_mul(l.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + /// Storage: Pov LargeValue (r:1 w:0) + /// Proof: Pov LargeValue (max_values: Some(1), max_size: Some(4194308), added: 4194803, mode: Measured) + /// Storage: Pov LargeValue2 (r:1 w:0) + /// Proof: Pov LargeValue2 (max_values: Some(1), max_size: Some(4194308), added: 4194803, mode: Measured) + /// The range of component `l` is `[0, 4194304]`. + fn measured_storage_double_value_read_linear_size(l: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `235 + l * (2 ±0)` + // Estimated: `1448 + l * (4 ±0)` + // Minimum execution time: 4_519 nanoseconds. + Weight::from_parts(4_519_000, 1448) + // Standard Error: 9 + .saturating_add(Weight::from_ref_time(560).saturating_mul(l.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(Weight::from_proof_size(4).saturating_mul(l.into())) + } + /// Storage: Pov LargeValue (r:1 w:0) + /// Proof: Pov LargeValue (max_values: Some(1), max_size: Some(4194308), added: 4194803, mode: MaxEncodedLen) + /// Storage: Pov LargeValue2 (r:1 w:0) + /// Proof: Pov LargeValue2 (max_values: Some(1), max_size: Some(4194308), added: 4194803, mode: MaxEncodedLen) + /// The range of component `l` is `[0, 4194304]`. + fn mel_storage_double_value_read_linear_size(l: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `235 + l * (2 ±0)` + // Estimated: `8389606` + // Minimum execution time: 4_462 nanoseconds. + Weight::from_parts(4_462_000, 8389606) + // Standard Error: 7 + .saturating_add(Weight::from_ref_time(538).saturating_mul(l.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + } + /// Storage: Pov LargeValue (r:1 w:0) + /// Proof: Pov LargeValue (max_values: Some(1), max_size: Some(4194308), added: 4194803, mode: MaxEncodedLen) + /// Storage: Pov LargeValue2 (r:1 w:0) + /// Proof: Pov LargeValue2 (max_values: Some(1), max_size: Some(4194308), added: 4194803, mode: Measured) + /// The range of component `l` is `[0, 4194304]`. + fn mel_mixed_storage_double_value_read_linear_size(l: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `235 + l * (2 ±0)` + // Estimated: `4195527 + l * (2 ±0)` + // Minimum execution time: 4_552 nanoseconds. + Weight::from_parts(4_552_000, 4195527) + // Standard Error: 6 + .saturating_add(Weight::from_ref_time(507).saturating_mul(l.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(Weight::from_proof_size(2).saturating_mul(l.into())) + } + /// Storage: Pov LargeValue (r:1 w:0) + /// Proof: Pov LargeValue (max_values: Some(1), max_size: Some(4194308), added: 4194803, mode: Measured) + /// Storage: Pov LargeValue2 (r:1 w:0) + /// Proof: Pov LargeValue2 (max_values: Some(1), max_size: Some(4194308), added: 4194803, mode: MaxEncodedLen) + /// The range of component `l` is `[0, 4194304]`. + fn measured_mixed_storage_double_value_read_linear_size(l: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `235 + l * (2 ±0)` + // Estimated: `4195527 + l * (2 ±0)` + // Minimum execution time: 4_236 nanoseconds. + Weight::from_parts(4_236_000, 4195527) + // Standard Error: 8 + .saturating_add(Weight::from_ref_time(517).saturating_mul(l.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(Weight::from_proof_size(2).saturating_mul(l.into())) + } + /// Storage: Pov UnboundedMap (r:1 w:0) + /// Proof Skipped: Pov UnboundedMap (max_values: None, max_size: None, mode: Measured) + /// Storage: Pov UnboundedMap2 (r:1 w:0) + /// Proof Skipped: Pov UnboundedMap2 (max_values: None, max_size: None, mode: Measured) + /// The range of component `i` is `[0, 1000]`. + fn storage_map_unbounded_both_measured_read(i: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `293 + i * (8 ±0)` + // Estimated: `5524 + i * (16 ±0)` + // Minimum execution time: 5_649 nanoseconds. + Weight::from_parts(6_111_237, 5524) + // Standard Error: 1_060 + .saturating_add(Weight::from_ref_time(2_693).saturating_mul(i.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(Weight::from_proof_size(16).saturating_mul(i.into())) + } + /// Storage: Pov Map1M (r:1 w:0) + /// Proof: Pov Map1M (max_values: Some(1000000), max_size: Some(36), added: 2511, mode: MaxEncodedLen) + /// Storage: Pov UnboundedMap (r:1 w:0) + /// Proof Skipped: Pov UnboundedMap (max_values: None, max_size: None, mode: Measured) + /// The range of component `i` is `[0, 1000]`. + fn storage_map_partial_unbounded_read(i: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `260 + i * (4 ±0)` + // Estimated: `5243 + i * (4 ±0)` + // Minimum execution time: 5_997 nanoseconds. + Weight::from_parts(7_996_508, 5243) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(Weight::from_proof_size(4).saturating_mul(i.into())) + } + /// Storage: Pov Map1M (r:1 w:0) + /// Proof: Pov Map1M (max_values: Some(1000000), max_size: Some(36), added: 2511, mode: MaxEncodedLen) + /// Storage: Pov UnboundedMap (r:1 w:0) + /// Proof Skipped: Pov UnboundedMap (max_values: None, max_size: None, mode: Ignored) + /// The range of component `i` is `[0, 1000]`. + fn storage_map_partial_unbounded_ignored_read(i: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `260 + i * (4 ±0)` + // Estimated: `2768 + i * (4 ±0)` + // Minimum execution time: 5_679 nanoseconds. + Weight::from_parts(6_496_804, 2768) + // Standard Error: 611 + .saturating_add(Weight::from_ref_time(930).saturating_mul(i.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(Weight::from_proof_size(4).saturating_mul(i.into())) + } + fn emit_event() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 7_087 nanoseconds. + Weight::from_ref_time(7_087_000) + } + fn noop() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_719 nanoseconds. + Weight::from_ref_time(2_719_000) + } +} + +// For backwards compatibility and tests +impl WeightInfo for () { + /// Storage: Pov Value (r:1 w:0) + /// Proof: Pov Value (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + fn storage_single_value_read() -> Weight { + // Proof Size summary in bytes: + // Measured: `136` + // Estimated: `499` + // Minimum execution time: 3_291 nanoseconds. + Weight::from_parts(3_291_000, 499) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + } + /// Storage: Pov Value (r:1 w:0) + /// Proof: Pov Value (max_values: Some(1), max_size: Some(4), added: 499, mode: Ignored) + fn storage_single_value_ignored_read() -> Weight { + // Proof Size summary in bytes: + // Measured: `136` + // Estimated: `0` + // Minimum execution time: 2_918 nanoseconds. + Weight::from_ref_time(2_918_000) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + } + /// Storage: Pov Value (r:1 w:0) + /// Proof: Pov Value (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Pov Value2 (r:1 w:0) + /// Proof: Pov Value2 (max_values: Some(1), max_size: Some(4), added: 499, mode: Ignored) + fn storage_single_value_ignored_some_read() -> Weight { + // Proof Size summary in bytes: + // Measured: `160` + // Estimated: `659` + // Minimum execution time: 4_056 nanoseconds. + Weight::from_parts(4_056_000, 659) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + } + /// Storage: Pov Value (r:1 w:0) + /// Proof: Pov Value (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + fn storage_single_value_read_twice() -> Weight { + // Proof Size summary in bytes: + // Measured: `136` + // Estimated: `499` + // Minimum execution time: 3_552 nanoseconds. + Weight::from_parts(3_552_000, 499) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + } + /// Storage: Pov Value (r:0 w:1) + /// Proof: Pov Value (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + fn storage_single_value_write() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 795 nanoseconds. + Weight::from_ref_time(795_000) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Pov Value (r:0 w:1) + /// Proof: Pov Value (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + fn storage_single_value_kill() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 865 nanoseconds. + Weight::from_ref_time(865_000) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Pov Map1M (r:1 w:0) + /// Proof: Pov Map1M (max_values: Some(1000000), max_size: Some(36), added: 2511, mode: Measured) + fn storage_1m_map_read_one_value_two_additional_layers() -> Weight { + // Proof Size summary in bytes: + // Measured: `1275` + // Estimated: `3750` + // Minimum execution time: 9_571 nanoseconds. + Weight::from_parts(9_571_000, 3750) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + } + /// Storage: Pov Map1M (r:1 w:0) + /// Proof: Pov Map1M (max_values: Some(1000000), max_size: Some(36), added: 2511, mode: Measured) + fn storage_1m_map_read_one_value_three_additional_layers() -> Weight { + // Proof Size summary in bytes: + // Measured: `1544` + // Estimated: `4019` + // Minimum execution time: 14_597 nanoseconds. + Weight::from_parts(14_597_000, 4019) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + } + /// Storage: Pov Map1M (r:1 w:0) + /// Proof: Pov Map1M (max_values: Some(1000000), max_size: Some(36), added: 2511, mode: Measured) + fn storage_1m_map_read_one_value_four_additional_layers() -> Weight { + // Proof Size summary in bytes: + // Measured: `2044` + // Estimated: `4519` + // Minimum execution time: 19_793 nanoseconds. + Weight::from_parts(19_793_000, 4519) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + } + /// Storage: Pov Map1M (r:100 w:0) + /// Proof: Pov Map1M (max_values: Some(1000000), max_size: Some(36), added: 2511, mode: MaxEncodedLen) + /// Storage: Pov Map16M (r:100 w:0) + /// Proof: Pov Map16M (max_values: Some(16000000), max_size: Some(36), added: 3006, mode: MaxEncodedLen) + /// The range of component `n` is `[0, 100]`. + /// The range of component `m` is `[0, 100]`. + fn storage_map_read_per_component(n: u32, m: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `515 + n * (188 ±0) + m * (188 ±0)` + // Estimated: `0 + n * (3006 ±0) + m * (2511 ±0)` + // Minimum execution time: 266_160 nanoseconds. + Weight::from_ref_time(190_477_747) + // Standard Error: 96_405 + .saturating_add(Weight::from_ref_time(1_049_993).saturating_mul(n.into())) + // Standard Error: 96_405 + .saturating_add(Weight::from_ref_time(1_202_546).saturating_mul(m.into())) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(m.into()))) + .saturating_add(Weight::from_proof_size(3006).saturating_mul(n.into())) + .saturating_add(Weight::from_proof_size(2511).saturating_mul(m.into())) + } + /// Storage: Pov Map1M (r:100 w:0) + /// Proof: Pov Map1M (max_values: Some(1000000), max_size: Some(36), added: 2511, mode: Ignored) + /// Storage: Pov Map16M (r:100 w:0) + /// Proof: Pov Map16M (max_values: Some(16000000), max_size: Some(36), added: 3006, mode: MaxEncodedLen) + /// The range of component `n` is `[0, 100]`. + /// The range of component `m` is `[0, 100]`. + fn storage_map_read_per_component_one_ignored(n: u32, m: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `515 + n * (188 ±0) + m * (188 ±0)` + // Estimated: `695 + n * (3195 ±2) + m * (189 ±2)` + // Minimum execution time: 265_113 nanoseconds. + Weight::from_parts(215_943_973, 695) + // Standard Error: 199_907 + .saturating_add(Weight::from_ref_time(988_371).saturating_mul(n.into())) + // Standard Error: 199_907 + .saturating_add(Weight::from_ref_time(1_145_693).saturating_mul(m.into())) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(m.into()))) + .saturating_add(Weight::from_proof_size(3195).saturating_mul(n.into())) + .saturating_add(Weight::from_proof_size(189).saturating_mul(m.into())) + } + /// Storage: Pov Map1M (r:1 w:0) + /// Proof: Pov Map1M (max_values: Some(1000000), max_size: Some(36), added: 2511, mode: MaxEncodedLen) + /// The range of component `n` is `[0, 100]`. + fn storage_1m_map_one_entry_repeated_read(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `170` + // Estimated: `2511` + // Minimum execution time: 119 nanoseconds. + Weight::from_parts(3_649_405, 2511) + // Standard Error: 4_472 + .saturating_add(Weight::from_ref_time(432_147).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + } + /// Storage: Pov Map1M (r:100 w:0) + /// Proof: Pov Map1M (max_values: Some(1000000), max_size: Some(36), added: 2511, mode: MaxEncodedLen) + /// The range of component `n` is `[0, 100]`. + fn storage_1m_map_multiple_entry_repeated_read(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `147 + n * (40 ±0)` + // Estimated: `0 + n * (2511 ±0)` + // Minimum execution time: 106 nanoseconds. + Weight::from_ref_time(59_892_609) + // Standard Error: 418_004 + .saturating_add(Weight::from_ref_time(5_919_793).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_proof_size(2511).saturating_mul(n.into())) + } + /// Storage: Pov DoubleMap1M (r:1024 w:0) + /// Proof: Pov DoubleMap1M (max_values: Some(1000000), max_size: Some(68), added: 2543, mode: MaxEncodedLen) + /// The range of component `n` is `[0, 1024]`. + fn storage_1m_double_map_read_per_component(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `21938 + n * (57 ±0)` + // Estimated: `0 + n * (2543 ±0)` + // Minimum execution time: 550 nanoseconds. + Weight::from_ref_time(65_431_603) + // Standard Error: 66_935 + .saturating_add(Weight::from_ref_time(2_825_371).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_proof_size(2543).saturating_mul(n.into())) + } + /// Storage: Pov BoundedValue (r:1 w:0) + /// Proof: Pov BoundedValue (max_values: Some(1), max_size: Some(33), added: 528, mode: MaxEncodedLen) + fn storage_value_bounded_read() -> Weight { + // Proof Size summary in bytes: + // Measured: `109` + // Estimated: `528` + // Minimum execution time: 2_541 nanoseconds. + Weight::from_parts(2_541_000, 528) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + } + /// Storage: Pov UnboundedValue (r:1 w:0) + /// Proof Skipped: Pov UnboundedValue (max_values: Some(1), max_size: None, mode: Measured) + fn storage_value_unbounded_read() -> Weight { + // Proof Size summary in bytes: + // Measured: `109` + // Estimated: `604` + // Minimum execution time: 2_226 nanoseconds. + Weight::from_parts(2_226_000, 604) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + } + /// Storage: Pov UnboundedValue (r:1 w:0) + /// Proof Skipped: Pov UnboundedValue (max_values: Some(1), max_size: None, mode: Ignored) + fn storage_value_unbounded_ignored_read() -> Weight { + // Proof Size summary in bytes: + // Measured: `109` + // Estimated: `0` + // Minimum execution time: 2_100 nanoseconds. + Weight::from_ref_time(2_100_000) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + } + /// Storage: Pov UnboundedValue (r:1 w:0) + /// Proof Skipped: Pov UnboundedValue (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Pov BoundedValue (r:1 w:0) + /// Proof: Pov BoundedValue (max_values: Some(1), max_size: Some(33), added: 528, mode: MaxEncodedLen) + fn storage_value_bounded_and_unbounded_read() -> Weight { + // Proof Size summary in bytes: + // Measured: `109` + // Estimated: `1132` + // Minimum execution time: 2_808 nanoseconds. + Weight::from_parts(2_808_000, 1132) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + } + /// Storage: Pov LargeValue (r:1 w:0) + /// Proof: Pov LargeValue (max_values: Some(1), max_size: Some(4194308), added: 4194803, mode: Measured) + /// The range of component `l` is `[0, 4194304]`. + fn measured_storage_value_read_linear_size(l: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `174 + l * (1 ±0)` + // Estimated: `666 + l * (1 ±0)` + // Minimum execution time: 3_385 nanoseconds. + Weight::from_parts(3_385_000, 666) + // Standard Error: 10 + .saturating_add(Weight::from_ref_time(356).saturating_mul(l.into())) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(Weight::from_proof_size(1).saturating_mul(l.into())) + } + /// Storage: Pov LargeValue (r:1 w:0) + /// Proof: Pov LargeValue (max_values: Some(1), max_size: Some(4194308), added: 4194803, mode: MaxEncodedLen) + /// The range of component `l` is `[0, 4194304]`. + fn mel_storage_value_read_linear_size(l: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `174 + l * (1 ±0)` + // Estimated: `4194803` + // Minimum execution time: 3_342 nanoseconds. + Weight::from_parts(3_342_000, 4194803) + // Standard Error: 6 + .saturating_add(Weight::from_ref_time(345).saturating_mul(l.into())) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + } + /// Storage: Pov LargeValue (r:1 w:0) + /// Proof: Pov LargeValue (max_values: Some(1), max_size: Some(4194308), added: 4194803, mode: Measured) + /// Storage: Pov LargeValue2 (r:1 w:0) + /// Proof: Pov LargeValue2 (max_values: Some(1), max_size: Some(4194308), added: 4194803, mode: Measured) + /// The range of component `l` is `[0, 4194304]`. + fn measured_storage_double_value_read_linear_size(l: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `235 + l * (2 ±0)` + // Estimated: `1448 + l * (4 ±0)` + // Minimum execution time: 4_519 nanoseconds. + Weight::from_parts(4_519_000, 1448) + // Standard Error: 9 + .saturating_add(Weight::from_ref_time(560).saturating_mul(l.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(Weight::from_proof_size(4).saturating_mul(l.into())) + } + /// Storage: Pov LargeValue (r:1 w:0) + /// Proof: Pov LargeValue (max_values: Some(1), max_size: Some(4194308), added: 4194803, mode: MaxEncodedLen) + /// Storage: Pov LargeValue2 (r:1 w:0) + /// Proof: Pov LargeValue2 (max_values: Some(1), max_size: Some(4194308), added: 4194803, mode: MaxEncodedLen) + /// The range of component `l` is `[0, 4194304]`. + fn mel_storage_double_value_read_linear_size(l: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `235 + l * (2 ±0)` + // Estimated: `8389606` + // Minimum execution time: 4_462 nanoseconds. + Weight::from_parts(4_462_000, 8389606) + // Standard Error: 7 + .saturating_add(Weight::from_ref_time(538).saturating_mul(l.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + } + /// Storage: Pov LargeValue (r:1 w:0) + /// Proof: Pov LargeValue (max_values: Some(1), max_size: Some(4194308), added: 4194803, mode: MaxEncodedLen) + /// Storage: Pov LargeValue2 (r:1 w:0) + /// Proof: Pov LargeValue2 (max_values: Some(1), max_size: Some(4194308), added: 4194803, mode: Measured) + /// The range of component `l` is `[0, 4194304]`. + fn mel_mixed_storage_double_value_read_linear_size(l: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `235 + l * (2 ±0)` + // Estimated: `4195527 + l * (2 ±0)` + // Minimum execution time: 4_552 nanoseconds. + Weight::from_parts(4_552_000, 4195527) + // Standard Error: 6 + .saturating_add(Weight::from_ref_time(507).saturating_mul(l.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(Weight::from_proof_size(2).saturating_mul(l.into())) + } + /// Storage: Pov LargeValue (r:1 w:0) + /// Proof: Pov LargeValue (max_values: Some(1), max_size: Some(4194308), added: 4194803, mode: Measured) + /// Storage: Pov LargeValue2 (r:1 w:0) + /// Proof: Pov LargeValue2 (max_values: Some(1), max_size: Some(4194308), added: 4194803, mode: MaxEncodedLen) + /// The range of component `l` is `[0, 4194304]`. + fn measured_mixed_storage_double_value_read_linear_size(l: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `235 + l * (2 ±0)` + // Estimated: `4195527 + l * (2 ±0)` + // Minimum execution time: 4_236 nanoseconds. + Weight::from_parts(4_236_000, 4195527) + // Standard Error: 8 + .saturating_add(Weight::from_ref_time(517).saturating_mul(l.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(Weight::from_proof_size(2).saturating_mul(l.into())) + } + /// Storage: Pov UnboundedMap (r:1 w:0) + /// Proof Skipped: Pov UnboundedMap (max_values: None, max_size: None, mode: Measured) + /// Storage: Pov UnboundedMap2 (r:1 w:0) + /// Proof Skipped: Pov UnboundedMap2 (max_values: None, max_size: None, mode: Measured) + /// The range of component `i` is `[0, 1000]`. + fn storage_map_unbounded_both_measured_read(i: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `293 + i * (8 ±0)` + // Estimated: `5524 + i * (16 ±0)` + // Minimum execution time: 5_649 nanoseconds. + Weight::from_parts(6_111_237, 5524) + // Standard Error: 1_060 + .saturating_add(Weight::from_ref_time(2_693).saturating_mul(i.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(Weight::from_proof_size(16).saturating_mul(i.into())) + } + /// Storage: Pov Map1M (r:1 w:0) + /// Proof: Pov Map1M (max_values: Some(1000000), max_size: Some(36), added: 2511, mode: MaxEncodedLen) + /// Storage: Pov UnboundedMap (r:1 w:0) + /// Proof Skipped: Pov UnboundedMap (max_values: None, max_size: None, mode: Measured) + /// The range of component `i` is `[0, 1000]`. + fn storage_map_partial_unbounded_read(i: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `260 + i * (4 ±0)` + // Estimated: `5243 + i * (4 ±0)` + // Minimum execution time: 5_997 nanoseconds. + Weight::from_parts(7_996_508, 5243) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(Weight::from_proof_size(4).saturating_mul(i.into())) + } + /// Storage: Pov Map1M (r:1 w:0) + /// Proof: Pov Map1M (max_values: Some(1000000), max_size: Some(36), added: 2511, mode: MaxEncodedLen) + /// Storage: Pov UnboundedMap (r:1 w:0) + /// Proof Skipped: Pov UnboundedMap (max_values: None, max_size: None, mode: Ignored) + /// The range of component `i` is `[0, 1000]`. + fn storage_map_partial_unbounded_ignored_read(i: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `260 + i * (4 ±0)` + // Estimated: `2768 + i * (4 ±0)` + // Minimum execution time: 5_679 nanoseconds. + Weight::from_parts(6_496_804, 2768) + // Standard Error: 611 + .saturating_add(Weight::from_ref_time(930).saturating_mul(i.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(Weight::from_proof_size(4).saturating_mul(i.into())) + } + fn emit_event() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 7_087 nanoseconds. + Weight::from_ref_time(7_087_000) + } + fn noop() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_719 nanoseconds. + Weight::from_ref_time(2_719_000) + } +} diff --git a/frame/benchmarking/src/baseline.rs b/frame/benchmarking/src/baseline.rs index 5fd845551daca..0d511cbff4b86 100644 --- a/frame/benchmarking/src/baseline.rs +++ b/frame/benchmarking/src/baseline.rs @@ -16,29 +16,25 @@ // limitations under the License. //! A set of benchmarks which can establish a global baseline for all other -//! benchmarking. +//! benchmarking. These benchmarks do not require a pallet to be deployed. #![cfg(feature = "runtime-benchmarks")] +use super::*; use crate::benchmarks; -use codec::Encode; use frame_system::Pallet as System; -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 crypto { + use sp_application_crypto::{app_crypto, sr25519, KeyTypeId}; -mod app_sr25519 { - use super::TEST_KEY_TYPE_ID; - use sp_application_crypto::{app_crypto, sr25519}; + pub const TEST_KEY_TYPE_ID: KeyTypeId = KeyTypeId(*b"test"); app_crypto!(sr25519, TEST_KEY_TYPE_ID); } - -type SignerId = app_sr25519::Public; +pub type SignerId = crypto::Public; pub struct Pallet(System); pub trait Config: frame_system::Config {} @@ -81,7 +77,6 @@ benchmarks! { } 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())); @@ -106,53 +101,17 @@ benchmarks! { }); } - #[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, + mock::new_test_ext(), + mock::Test, ); } #[cfg(test)] pub mod mock { - use sp_runtime::{testing::H256, traits::IdentityLookup}; + use super::*; + use sp_runtime::testing::H256; type AccountId = u64; type AccountIndex = u32; @@ -183,7 +142,7 @@ pub mod mock { type Hash = H256; type Hashing = ::sp_runtime::traits::BlakeTwo256; type AccountId = AccountId; - type Lookup = IdentityLookup; + type Lookup = sp_runtime::traits::IdentityLookup; type Header = sp_runtime::testing::Header; type RuntimeEvent = RuntimeEvent; type BlockHashCount = (); diff --git a/frame/benchmarking/src/lib.rs b/frame/benchmarking/src/lib.rs index e4ebd2f228afe..525370e23385a 100644 --- a/frame/benchmarking/src/lib.rs +++ b/frame/benchmarking/src/lib.rs @@ -47,7 +47,7 @@ pub use sp_runtime::traits::Zero; 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 sp_storage::{well_known_keys, TrackedStorageKey}; pub use utils::*; /// Whitelist the given account. @@ -211,6 +211,7 @@ macro_rules! benchmarks { ( ) ( ) ( ) + ( ) $( $rest )* ); } @@ -231,6 +232,7 @@ macro_rules! benchmarks_instance { ( ) ( ) ( ) + ( ) $( $rest )* ); } @@ -251,6 +253,7 @@ macro_rules! benchmarks_instance_pallet { ( ) ( ) ( ) + ( ) $( $rest )* ); } @@ -268,6 +271,7 @@ macro_rules! benchmarks_iter { ( $( $names:tt )* ) ( $( $names_extra:tt )* ) ( $( $names_skip_meta:tt )* ) + ( $( $pov_name:ident: $( $storage:path = $pov_mode:ident )*; )* ) impl_benchmark_test_suite!( $bench_module:ident, $new_test_ext:expr, @@ -282,6 +286,7 @@ macro_rules! benchmarks_iter { ( $( $names )* ) ( $( $names_extra )* ) ( $( $names_skip_meta )* ) + ( $( $pov_name: $( $storage = $pov_mode )*; )* ) $( $rest )* } }; @@ -293,6 +298,7 @@ macro_rules! benchmarks_iter { ( $( $names:tt )* ) ( $( $names_extra:tt )* ) ( $( $names_skip_meta:tt )* ) + ( $( $pov_name:ident: $( $storage:path = $pov_mode:ident )*; )* ) impl_benchmark_test_suite!( $bench_module:ident, $new_test_ext:expr, @@ -307,6 +313,7 @@ macro_rules! benchmarks_iter { ( $( $names )* ) ( $( $names_extra )* ) ( $( $names_skip_meta )* ) + ( $( $pov_name: $( $storage = $pov_mode )*; )* ) $( $rest )* } }; @@ -318,6 +325,7 @@ macro_rules! benchmarks_iter { ( $( $names:tt )* ) ( $( $names_extra:tt )* ) ( $( $names_skip_meta:tt )* ) + ( $( $pov_name:ident: $( $storage:path = $pov_mode:ident )*; )* ) where_clause { where $( $where_bound:tt )* } $( $rest:tt )* ) => { @@ -328,6 +336,7 @@ macro_rules! benchmarks_iter { ( $( $names )* ) ( $( $names_extra )* ) ( $( $names_skip_meta )* ) + ( $( $pov_name: $( $storage = $pov_mode )*; )* ) $( $rest )* } }; @@ -339,7 +348,9 @@ macro_rules! benchmarks_iter { ( $( $names:tt )* ) ( $( $names_extra:tt )* ) ( $( $names_skip_meta:tt )* ) + ( $( $pov_name:ident: $( $storage:path = $pov_mode:ident )*; )* ) #[skip_meta] + $( #[ $($attributes:tt)+ ] )* $name:ident $( $rest:tt )* ) => { @@ -350,6 +361,8 @@ macro_rules! benchmarks_iter { ( $( $names )* ) ( $( $names_extra )* ) ( $( $names_skip_meta )* $name ) + ( $( $pov_name: $( $storage = $pov_mode )*; )* ) + $( #[ $( $attributes )+ ] )* $name $( $rest )* } @@ -362,7 +375,9 @@ macro_rules! benchmarks_iter { ( $( $names:tt )* ) ( $( $names_extra:tt )* ) ( $( $names_skip_meta:tt )* ) + ( $( $pov_name:ident: $( $storage:path = $pov_mode:ident )*; )* ) #[extra] + $( #[ $($attributes:tt)+ ] )* $name:ident $( $rest:tt )* ) => { @@ -373,6 +388,35 @@ macro_rules! benchmarks_iter { ( $( $names )* ) ( $( $names_extra )* $name ) ( $( $names_skip_meta )* ) + ( $( $pov_name: $( $storage = $pov_mode )*; )* ) + $( #[ $( $attributes )+ ] )* + $name + $( $rest )* + } + }; + // detect and extract `#[pov_mode = Mode { Pallet::Storage: Mode ... }]` tag: + ( + { $($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 )* ) + ( $( $old_pov_name:ident: $( $old_storage:path = $old_pov_mode:ident )*; )* ) + #[pov_mode = $mode:ident $( { $( $storage:path: $pov_mode:ident )* } )?] + $( #[ $($attributes:tt)+ ] )* + $name:ident + $( $rest:tt )* + ) => { + $crate::benchmarks_iter! { + { $($bench_module, $new_test_ext, $test $(, $( $args )* )?)? } + { $( $instance: $instance_bound )? } + { $( $where_clause )* } + ( $( $names )* ) + ( $( $names_extra )* ) + ( $( $names_skip_meta )* ) + ( $name: ALL = $mode $($( $storage = $pov_mode )*)?; $( $old_pov_name: $( $old_storage = $old_pov_mode )*; )* ) + $( #[ $( $attributes )+ ] )* $name $( $rest )* } @@ -385,6 +429,7 @@ macro_rules! benchmarks_iter { ( $( $names:tt )* ) // This contains $( $( { $instance } )? $name:ident )* ( $( $names_extra:tt )* ) ( $( $names_skip_meta:tt )* ) + ( $( $pov_name:ident: $( $storage:path = $pov_mode:ident )*; )* ) $name:ident { $( $code:tt )* }: _ $(< $origin_type:ty>)? ( $origin:expr $( , $arg:expr )* ) verify $postcode:block $( $rest:tt )* @@ -396,6 +441,7 @@ macro_rules! benchmarks_iter { ( $( $names )* ) ( $( $names_extra )* ) ( $( $names_skip_meta )* ) + ( $( $pov_name: $( $storage = $pov_mode )*; )* ) $name { $( $code )* }: $name $(< $origin_type >)? ( $origin $( , $arg )* ) verify $postcode $( $rest )* @@ -409,6 +455,7 @@ macro_rules! benchmarks_iter { ( $( $names:tt )* ) ( $( $names_extra:tt )* ) ( $( $names_skip_meta:tt )* ) + ( $( $pov_name:ident: $( $storage:path = $pov_mode:ident )*; )* ) $name:ident { $( $code:tt )* }: $dispatch:ident $(<$origin_type:ty>)? ( $origin:expr $( , $arg:expr )* ) verify $postcode:block $( $rest:tt )* @@ -421,6 +468,7 @@ macro_rules! benchmarks_iter { ( $( $names )* ) ( $( $names_extra )* ) ( $( $names_skip_meta )* ) + ( $( $pov_name: $( $storage = $pov_mode )*; )* ) $name { $( $code )* let __call = Call::< @@ -455,6 +503,7 @@ macro_rules! benchmarks_iter { ( $( $names:tt )* ) ( $( $names_extra:tt )* ) ( $( $names_skip_meta:tt )* ) + ( $( $pov_name:ident: $( $storage:path = $pov_mode:ident )*; )* ) $name:ident { $( $code:tt )* }: $eval:block verify $postcode:block $( $rest:tt )* @@ -483,6 +532,7 @@ macro_rules! benchmarks_iter { ( $( $names )* { $( $instance )? } $name ) ( $( $names_extra )* ) ( $( $names_skip_meta )* ) + ( $( $pov_name: $( $storage = $pov_mode )*; )* ) $( $rest )* ); }; @@ -494,6 +544,7 @@ macro_rules! benchmarks_iter { ( $( $names:tt )* ) ( $( $names_extra:tt )* ) ( $( $names_skip_meta:tt )* ) + ( $( $pov_name:ident: $( $storage:path = $pov_mode:ident )*; )* ) ) => { $crate::selected_benchmark!( { $( $where_clause)* } @@ -506,6 +557,7 @@ macro_rules! benchmarks_iter { ( $( $names )* ) ( $( $names_extra ),* ) ( $( $names_skip_meta ),* ) + ( $( $pov_name: $( $storage = $pov_mode )*; )* ) ); $crate::impl_test_function!( ( $( $names )* ) @@ -525,6 +577,7 @@ macro_rules! benchmarks_iter { ( $( $names:tt )* ) ( $( $names_extra:tt )* ) ( $( $names_skip_meta:tt )* ) + ( $( $pov_name:ident: $( $storage:path = $pov_mode:ident )*; )* ) ) => { $crate::selected_benchmark!( { $( $where_clause)* } @@ -537,6 +590,7 @@ macro_rules! benchmarks_iter { ( $( $names )* ) ( $( $names_extra ),* ) ( $( $names_skip_meta ),* ) + ( $( $pov_name: $( $storage = $pov_mode )*; )* ) ); }; // add verify block to _() format @@ -547,6 +601,7 @@ macro_rules! benchmarks_iter { ( $( $names:tt )* ) ( $( $names_extra:tt )* ) ( $( $names_skip_meta:tt )* ) + ( $( $pov_name:ident: $( $storage:path = $pov_mode:ident )*; )* ) $name:ident { $( $code:tt )* }: _ $(<$origin_type:ty>)? ( $origin:expr $( , $arg:expr )* ) $( $rest:tt )* ) => { @@ -557,6 +612,7 @@ macro_rules! benchmarks_iter { ( $( $names )* ) ( $( $names_extra )* ) ( $( $names_skip_meta )* ) + ( $( $pov_name: $( $storage = $pov_mode )*; )* ) $name { $( $code )* }: _ $(<$origin_type>)? ( $origin $( , $arg )* ) verify { } $( $rest )* @@ -570,6 +626,7 @@ macro_rules! benchmarks_iter { ( $( $names:tt )* ) ( $( $names_extra:tt )* ) ( $( $names_skip_meta:tt )* ) + ( $( $pov_name:ident: $( $storage:path = $pov_mode:ident )*; )* ) $name:ident { $( $code:tt )* }: $dispatch:ident $(<$origin_type:ty>)? ( $origin:expr $( , $arg:expr )* ) $( $rest:tt )* ) => { @@ -580,6 +637,7 @@ macro_rules! benchmarks_iter { ( $( $names )* ) ( $( $names_extra )* ) ( $( $names_skip_meta )* ) + ( $( $pov_name: $( $storage = $pov_mode )*; )* ) $name { $( $code )* }: $dispatch $(<$origin_type>)? ( $origin $( , $arg )* ) verify { } $( $rest )* @@ -593,6 +651,7 @@ macro_rules! benchmarks_iter { ( $( $names:tt )* ) ( $( $names_extra:tt )* ) ( $( $names_skip_meta:tt )* ) + ( $( $pov_name:ident: $( $storage:path = $pov_mode:ident )*; )* ) $name:ident { $( $code:tt )* }: $(<$origin_type:ty>)? $eval:block $( $rest:tt )* ) => { @@ -603,6 +662,7 @@ macro_rules! benchmarks_iter { ( $( $names )* ) ( $( $names_extra )* ) ( $( $names_skip_meta )* ) + ( $( $pov_name: $( $storage = $pov_mode )*; )* ) $name { $( $code )* }: $(<$origin_type>)? $eval verify { } $( $rest )* @@ -981,6 +1041,7 @@ macro_rules! impl_benchmark { ( $( { $( $name_inst:ident )? } $name:ident )* ) ( $( $name_extra:ident ),* ) ( $( $name_skip_meta:ident ),* ) + ( $( $pov_name:ident: $( $storage:path = $pov_mode:ident )*; )* ) ) => { // We only need to implement benchmarks for the runtime-benchmarks feature or testing. #[cfg(any(feature = "runtime-benchmarks", test))] @@ -989,23 +1050,37 @@ macro_rules! impl_benchmark { where T: frame_system::Config, $( $where_clause )* { fn benchmarks(extra: bool) -> $crate::Vec<$crate::BenchmarkMetadata> { + $($crate::validate_pov_mode!( + $pov_name: $( $storage = $pov_mode )*; + );)* let mut all_names = $crate::vec![ $( stringify!($name).as_ref() ),* ]; if !extra { let extra = [ $( stringify!($name_extra).as_ref() ),* ]; all_names.retain(|x| !extra.contains(x)); } + let pov_modes: $crate::Vec<($crate::Vec, $crate::Vec<($crate::Vec, $crate::Vec)>)> = $crate::vec![ + $( + (stringify!($pov_name).as_bytes().to_vec(), + $crate::vec![ + $( ( stringify!($storage).as_bytes().to_vec(), + stringify!($pov_mode).as_bytes().to_vec() ), )* + ]), + )* + ]; all_names.into_iter().map(|benchmark| { let selected_benchmark = match benchmark { $( stringify!($name) => SelectedBenchmark::$name, )* _ => panic!("all benchmarks should be selectable"), }; + let name = benchmark.as_bytes().to_vec(); let components = < SelectedBenchmark as $crate::BenchmarkingSetup >::components(&selected_benchmark); $crate::BenchmarkMetadata { - name: benchmark.as_bytes().to_vec(), + name: name.clone(), components, + pov_modes: pov_modes.iter().find(|p| p.0 == name).map(|p| p.1.clone()).unwrap_or_default(), } }).collect::<$crate::Vec<_>>() } @@ -1037,8 +1112,13 @@ macro_rules! impl_benchmark { $crate::frame_support::storage::transactional::TRANSACTION_LEVEL_KEY.into() ); whitelist.push(transactional_layer_key); + // Whitelist the `:extrinsic_index`. + let extrinsic_index = $crate::TrackedStorageKey::new( + $crate::well_known_keys::EXTRINSIC_INDEX.into() + ); + whitelist.push(extrinsic_index); - $crate::benchmarking::set_whitelist(whitelist); + $crate::benchmarking::set_whitelist(whitelist.clone()); let mut results: $crate::Vec<$crate::BenchmarkResult> = $crate::Vec::new(); @@ -1062,15 +1142,22 @@ macro_rules! impl_benchmark { // This will enable worst case scenario for reading from the database. $crate::benchmarking::commit_db(); + // Access all whitelisted keys to get them into the proof recorder since the + // recorder does now have a whitelist. + for key in &whitelist { + $crate::frame_support::storage::unhashed::get_raw(&key.key); + } + // Reset the read/write counter so we don't count operations in the setup process. $crate::benchmarking::reset_read_write_count(); // Time the extrinsic logic. $crate::log::trace!( target: "benchmark", - "Start Benchmark: {} ({:?})", + "Start Benchmark: {} ({:?}) verify {}", extrinsic, - c + c, + verify ); let start_pov = $crate::benchmarking::proof_size(); @@ -1099,6 +1186,10 @@ macro_rules! impl_benchmark { target: "benchmark", "Read/Write Count {:?}", read_write_count ); + $crate::log::trace!( + target: "benchmark", + "Proof sizes: before {:?} after {:?} diff {}", &start_pov, &end_pov, &diff_pov + ); // Time the storage root recalculation. let start_storage_root = $crate::benchmarking::current_time(); @@ -1421,6 +1512,37 @@ macro_rules! impl_benchmark_test_suite { } } +/// Validates the passed `pov_mode`s. +/// +/// Checks that: +/// - a top-level `ignored` is exclusive +/// - all modes are valid +#[macro_export] +macro_rules! validate_pov_mode { + () => {}; + ( $_bench:ident: ; ) => { }; + ( $_bench:ident: $_car:path = Ignored ; ) => { }; + ( $bench:ident: $_car:path = Ignored $( $storage:path = $_pov_mode:ident )+; ) => { + compile_error!( + concat!(concat!("`pov_mode = Ignored` is exclusive. Please remove the attribute from keys: ", $( stringify!($storage) )+), " on benchmark '", stringify!($bench), "'")); + }; + ( $bench:ident: $car:path = Measured $( $storage:path = $pov_mode:ident )*; ) => { + $crate::validate_pov_mode!( + $bench: $( $storage = $pov_mode )*; + ); + }; + ( $bench:ident: $car:path = MaxEncodedLen $( $storage:path = $pov_mode:ident )*; ) => { + $crate::validate_pov_mode!( + $bench: $( $storage = $pov_mode )*; + ); + }; + ( $bench:ident: $key:path = $unknown:ident $( $_storage:path = $_pov_mode:ident )*; ) => { + compile_error!( + concat!("Unknown pov_mode '", stringify!($unknown) ,"' for benchmark '", stringify!($bench), "' on key '", stringify!($key), "'. Must be one of: Ignored, Measured, MaxEncodedLen") + ); + }; +} + // Takes all arguments from `impl_benchmark_test_suite` and three additional arguments. // // Can be configured to generate one #[test] fn per bench case or diff --git a/frame/benchmarking/src/utils.rs b/frame/benchmarking/src/utils.rs index 654b1c34c0658..6ad9ac7bb0bd6 100644 --- a/frame/benchmarking/src/utils.rs +++ b/frame/benchmarking/src/utils.rs @@ -227,6 +227,7 @@ pub struct BenchmarkList { pub struct BenchmarkMetadata { pub name: Vec, pub components: Vec<(BenchmarkParameter, u32, u32)>, + pub pov_modes: Vec<(Vec, Vec)>, } sp_api::decl_runtime_apis! { diff --git a/frame/benchmarking/src/weights.rs b/frame/benchmarking/src/weights.rs index 5e5a2e7ee343c..dea95947122af 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) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2023 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -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-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -51,10 +52,8 @@ pub trait WeightInfo { fn subtraction(i: u32, ) -> Weight; fn multiplication(i: u32, ) -> Weight; fn division(i: u32, ) -> Weight; - fn hashing(i: u32, ) -> Weight; + fn hashing() -> Weight; fn sr25519_verification(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. @@ -62,53 +61,52 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { /// The range of component `i` is `[0, 1000000]`. fn addition(_i: u32, ) -> Weight { - // Minimum execution time: 108 nanoseconds. - Weight::from_ref_time(137_610 as u64) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 138 nanoseconds. + Weight::from_ref_time(199_805) } /// The range of component `i` is `[0, 1000000]`. fn subtraction(_i: u32, ) -> Weight { - // Minimum execution time: 104 nanoseconds. - Weight::from_ref_time(133_508 as u64) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 142 nanoseconds. + Weight::from_ref_time(201_435) } /// The range of component `i` is `[0, 1000000]`. fn multiplication(_i: u32, ) -> Weight { - // Minimum execution time: 110 nanoseconds. - Weight::from_ref_time(140_230 as u64) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 138 nanoseconds. + Weight::from_ref_time(207_037) } /// The range of component `i` is `[0, 1000000]`. fn division(_i: u32, ) -> Weight { - // 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 { - // Minimum execution time: 21_804_747 nanoseconds. - Weight::from_ref_time(22_013_681_386 as u64) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 151 nanoseconds. + Weight::from_ref_time(205_150) + } + fn hashing() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 21_950_884 nanoseconds. + Weight::from_ref_time(21_994_001_000) } /// The range of component `i` is `[0, 100]`. fn sr25519_verification(i: u32, ) -> Weight { - // 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 { - // 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 { - // 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))) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 168 nanoseconds. + Weight::from_ref_time(1_680_898) + // Standard Error: 10_291 + .saturating_add(Weight::from_ref_time(46_867_301).saturating_mul(i.into())) } } @@ -116,52 +114,51 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { /// The range of component `i` is `[0, 1000000]`. fn addition(_i: u32, ) -> Weight { - // Minimum execution time: 108 nanoseconds. - Weight::from_ref_time(137_610 as u64) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 138 nanoseconds. + Weight::from_ref_time(199_805) } /// The range of component `i` is `[0, 1000000]`. fn subtraction(_i: u32, ) -> Weight { - // Minimum execution time: 104 nanoseconds. - Weight::from_ref_time(133_508 as u64) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 142 nanoseconds. + Weight::from_ref_time(201_435) } /// The range of component `i` is `[0, 1000000]`. fn multiplication(_i: u32, ) -> Weight { - // Minimum execution time: 110 nanoseconds. - Weight::from_ref_time(140_230 as u64) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 138 nanoseconds. + Weight::from_ref_time(207_037) } /// The range of component `i` is `[0, 1000000]`. fn division(_i: u32, ) -> Weight { - // 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 { - // Minimum execution time: 21_804_747 nanoseconds. - Weight::from_ref_time(22_013_681_386 as u64) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 151 nanoseconds. + Weight::from_ref_time(205_150) + } + fn hashing() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 21_950_884 nanoseconds. + Weight::from_ref_time(21_994_001_000) } /// The range of component `i` is `[0, 100]`. fn sr25519_verification(i: u32, ) -> Weight { - // 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 { - // 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 { - // 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))) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 168 nanoseconds. + Weight::from_ref_time(1_680_898) + // Standard Error: 10_291 + .saturating_add(Weight::from_ref_time(46_867_301).saturating_mul(i.into())) } } diff --git a/frame/bounties/src/weights.rs b/frame/bounties/src/weights.rs index 34e78bfa556e7..1ae8ab2983704 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) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2023 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,25 +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-30, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! 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_bounties // --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_bounties -// --chain=dev -// --header=./HEADER-APACHE2 // --output=./frame/bounties/src/weights.rs +// --header=./HEADER-APACHE2 // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -64,214 +64,340 @@ pub trait WeightInfo { /// Weights for pallet_bounties using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - // Storage: Bounties BountyCount (r:1 w:1) - // Storage: System Account (r:1 w:1) - // Storage: Bounties BountyDescriptions (r:0 w:1) - // Storage: Bounties Bounties (r:0 w:1) + /// Storage: Bounties BountyCount (r:1 w:1) + /// Proof: Bounties BountyCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Bounties BountyDescriptions (r:0 w:1) + /// Proof: Bounties BountyDescriptions (max_values: None, max_size: Some(314), added: 2789, mode: MaxEncodedLen) + /// Storage: Bounties Bounties (r:0 w:1) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) /// The range of component `d` is `[0, 300]`. fn propose_bounty(d: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `308` + // Estimated: `3102` + // Minimum execution time: 22_787 nanoseconds. + Weight::from_parts(23_898_632, 3102) + // Standard Error: 141 + .saturating_add(Weight::from_ref_time(568).saturating_mul(d.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) } - // Storage: Bounties Bounties (r:1 w:1) - // Storage: Bounties BountyApprovals (r:1 w:1) + /// Storage: Bounties Bounties (r:1 w:1) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: Bounties BountyApprovals (r:1 w:1) + /// Proof: Bounties BountyApprovals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) fn approve_bounty() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `400` + // Estimated: `3549` + // Minimum execution time: 10_526 nanoseconds. + Weight::from_parts(10_729_000, 3549) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } - // Storage: Bounties Bounties (r:1 w:1) + /// Storage: Bounties Bounties (r:1 w:1) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) fn propose_curator() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `420` + // Estimated: `2652` + // Minimum execution time: 9_193 nanoseconds. + Weight::from_parts(9_455_000, 2652) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - // Storage: Bounties Bounties (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: Bounties Bounties (r:1 w:1) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn unassign_curator() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `628` + // Estimated: `5255` + // Minimum execution time: 22_592 nanoseconds. + Weight::from_parts(22_952_000, 5255) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } - // Storage: Bounties Bounties (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: Bounties Bounties (r:1 w:1) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn accept_curator() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `624` + // Estimated: `5255` + // Minimum execution time: 20_920 nanoseconds. + Weight::from_parts(21_369_000, 5255) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } - // Storage: Bounties Bounties (r:1 w:1) - // Storage: ChildBounties ParentChildBounties (r:1 w:0) + /// Storage: Bounties Bounties (r:1 w:1) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: ChildBounties ParentChildBounties (r:1 w:0) + /// Proof: ChildBounties ParentChildBounties (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) fn award_bounty() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `570` + // Estimated: `5143` + // Minimum execution time: 17_853 nanoseconds. + Weight::from_parts(18_280_000, 5143) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_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) + /// Storage: Bounties Bounties (r:1 w:1) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: System Account (r:3 w:3) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) + /// Proof: ChildBounties ChildrenCuratorFees (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) + /// Storage: Bounties BountyDescriptions (r:0 w:1) + /// Proof: Bounties BountyDescriptions (max_values: None, max_size: Some(314), added: 2789, mode: MaxEncodedLen) fn claim_bounty() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `998` + // Estimated: `12964` + // Minimum execution time: 67_538 nanoseconds. + Weight::from_parts(67_974_000, 12964) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(6_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) + /// Storage: Bounties Bounties (r:1 w:1) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: ChildBounties ParentChildBounties (r:1 w:0) + /// Proof: ChildBounties ParentChildBounties (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Bounties BountyDescriptions (r:0 w:1) + /// Proof: Bounties BountyDescriptions (max_values: None, max_size: Some(314), added: 2789, mode: MaxEncodedLen) fn close_bounty_proposed() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `646` + // Estimated: `7746` + // Minimum execution time: 28_380 nanoseconds. + Weight::from_parts(28_859_000, 7746) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_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) + /// Storage: Bounties Bounties (r:1 w:1) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: ChildBounties ParentChildBounties (r:1 w:0) + /// Proof: ChildBounties ParentChildBounties (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Bounties BountyDescriptions (r:0 w:1) + /// Proof: Bounties BountyDescriptions (max_values: None, max_size: Some(314), added: 2789, mode: MaxEncodedLen) fn close_bounty_active() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `914` + // Estimated: `10349` + // Minimum execution time: 47_739 nanoseconds. + Weight::from_parts(48_388_000, 10349) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) } - // Storage: Bounties Bounties (r:1 w:1) + /// Storage: Bounties Bounties (r:1 w:1) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) fn extend_bounty_expiry() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `456` + // Estimated: `2652` + // Minimum execution time: 14_188 nanoseconds. + Weight::from_parts(14_801_000, 2652) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - // Storage: Bounties BountyApprovals (r:1 w:1) - // Storage: Bounties Bounties (r:2 w:2) - // Storage: System Account (r:4 w:4) + /// Storage: Bounties BountyApprovals (r:1 w:1) + /// Proof: Bounties BountyApprovals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) + /// Storage: Bounties Bounties (r:100 w:100) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: System Account (r:200 w:200) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `b` is `[0, 100]`. fn spend_funds(b: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `31 + b * (360 ±0)` + // Estimated: `897 + b * (7858 ±0)` + // Minimum execution time: 4_685 nanoseconds. + Weight::from_parts(9_932_840, 897) + // Standard Error: 14_301 + .saturating_add(Weight::from_ref_time(27_178_347).saturating_mul(b.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) .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(1_u64)) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(b.into()))) + .saturating_add(Weight::from_proof_size(7858).saturating_mul(b.into())) } } // For backwards compatibility and tests impl WeightInfo for () { - // Storage: Bounties BountyCount (r:1 w:1) - // Storage: System Account (r:1 w:1) - // Storage: Bounties BountyDescriptions (r:0 w:1) - // Storage: Bounties Bounties (r:0 w:1) + /// Storage: Bounties BountyCount (r:1 w:1) + /// Proof: Bounties BountyCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Bounties BountyDescriptions (r:0 w:1) + /// Proof: Bounties BountyDescriptions (max_values: None, max_size: Some(314), added: 2789, mode: MaxEncodedLen) + /// Storage: Bounties Bounties (r:0 w:1) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) /// The range of component `d` is `[0, 300]`. fn propose_bounty(d: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `308` + // Estimated: `3102` + // Minimum execution time: 22_787 nanoseconds. + Weight::from_parts(23_898_632, 3102) + // Standard Error: 141 + .saturating_add(Weight::from_ref_time(568).saturating_mul(d.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) } - // Storage: Bounties Bounties (r:1 w:1) - // Storage: Bounties BountyApprovals (r:1 w:1) + /// Storage: Bounties Bounties (r:1 w:1) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: Bounties BountyApprovals (r:1 w:1) + /// Proof: Bounties BountyApprovals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) fn approve_bounty() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `400` + // Estimated: `3549` + // Minimum execution time: 10_526 nanoseconds. + Weight::from_parts(10_729_000, 3549) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } - // Storage: Bounties Bounties (r:1 w:1) + /// Storage: Bounties Bounties (r:1 w:1) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) fn propose_curator() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `420` + // Estimated: `2652` + // Minimum execution time: 9_193 nanoseconds. + Weight::from_parts(9_455_000, 2652) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - // Storage: Bounties Bounties (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: Bounties Bounties (r:1 w:1) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn unassign_curator() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `628` + // Estimated: `5255` + // Minimum execution time: 22_592 nanoseconds. + Weight::from_parts(22_952_000, 5255) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } - // Storage: Bounties Bounties (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: Bounties Bounties (r:1 w:1) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn accept_curator() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `624` + // Estimated: `5255` + // Minimum execution time: 20_920 nanoseconds. + Weight::from_parts(21_369_000, 5255) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } - // Storage: Bounties Bounties (r:1 w:1) - // Storage: ChildBounties ParentChildBounties (r:1 w:0) + /// Storage: Bounties Bounties (r:1 w:1) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: ChildBounties ParentChildBounties (r:1 w:0) + /// Proof: ChildBounties ParentChildBounties (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) fn award_bounty() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `570` + // Estimated: `5143` + // Minimum execution time: 17_853 nanoseconds. + Weight::from_parts(18_280_000, 5143) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_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) + /// Storage: Bounties Bounties (r:1 w:1) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: System Account (r:3 w:3) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) + /// Proof: ChildBounties ChildrenCuratorFees (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) + /// Storage: Bounties BountyDescriptions (r:0 w:1) + /// Proof: Bounties BountyDescriptions (max_values: None, max_size: Some(314), added: 2789, mode: MaxEncodedLen) fn claim_bounty() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `998` + // Estimated: `12964` + // Minimum execution time: 67_538 nanoseconds. + Weight::from_parts(67_974_000, 12964) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(6_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) + /// Storage: Bounties Bounties (r:1 w:1) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: ChildBounties ParentChildBounties (r:1 w:0) + /// Proof: ChildBounties ParentChildBounties (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Bounties BountyDescriptions (r:0 w:1) + /// Proof: Bounties BountyDescriptions (max_values: None, max_size: Some(314), added: 2789, mode: MaxEncodedLen) fn close_bounty_proposed() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `646` + // Estimated: `7746` + // Minimum execution time: 28_380 nanoseconds. + Weight::from_parts(28_859_000, 7746) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(3_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) + /// Storage: Bounties Bounties (r:1 w:1) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: ChildBounties ParentChildBounties (r:1 w:0) + /// Proof: ChildBounties ParentChildBounties (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Bounties BountyDescriptions (r:0 w:1) + /// Proof: Bounties BountyDescriptions (max_values: None, max_size: Some(314), added: 2789, mode: MaxEncodedLen) fn close_bounty_active() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `914` + // Estimated: `10349` + // Minimum execution time: 47_739 nanoseconds. + Weight::from_parts(48_388_000, 10349) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) } - // Storage: Bounties Bounties (r:1 w:1) + /// Storage: Bounties Bounties (r:1 w:1) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) fn extend_bounty_expiry() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `456` + // Estimated: `2652` + // Minimum execution time: 14_188 nanoseconds. + Weight::from_parts(14_801_000, 2652) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - // Storage: Bounties BountyApprovals (r:1 w:1) - // Storage: Bounties Bounties (r:2 w:2) - // Storage: System Account (r:4 w:4) + /// Storage: Bounties BountyApprovals (r:1 w:1) + /// Proof: Bounties BountyApprovals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) + /// Storage: Bounties Bounties (r:100 w:100) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: System Account (r:200 w:200) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `b` is `[0, 100]`. fn spend_funds(b: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `31 + b * (360 ±0)` + // Estimated: `897 + b * (7858 ±0)` + // Minimum execution time: 4_685 nanoseconds. + Weight::from_parts(9_932_840, 897) + // Standard Error: 14_301 + .saturating_add(Weight::from_ref_time(27_178_347).saturating_mul(b.into())) + .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(b.into()))) - .saturating_add(RocksDbWeight::get().writes(1)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(b.into()))) + .saturating_add(Weight::from_proof_size(7858).saturating_mul(b.into())) } } diff --git a/frame/child-bounties/src/weights.rs b/frame/child-bounties/src/weights.rs index 235c84320effa..77ab24488e1b2 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) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2023 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -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-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -60,176 +61,290 @@ pub trait WeightInfo { /// 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) + /// Storage: ChildBounties ParentChildBounties (r:1 w:1) + /// Proof: ChildBounties ParentChildBounties (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) + /// Storage: Bounties Bounties (r:1 w:0) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildBountyCount (r:1 w:1) + /// Proof: ChildBounties ChildBountyCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) + /// Proof: ChildBounties ChildBountyDescriptions (max_values: None, max_size: Some(314), added: 2789, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildBounties (r:0 w:1) + /// Proof: ChildBounties ChildBounties (max_values: None, max_size: Some(145), added: 2620, mode: MaxEncodedLen) /// The range of component `d` is `[0, 300]`. fn add_child_bounty(d: u32, ) -> Weight { - // 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)) - } - // Storage: Bounties Bounties (r:1 w:0) - // Storage: ChildBounties ChildBounties (r:1 w:1) - // Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `742` + // Estimated: `10848` + // Minimum execution time: 46_743 nanoseconds. + Weight::from_parts(47_762_924, 10848) + // Standard Error: 135 + .saturating_add(Weight::from_ref_time(599).saturating_mul(d.into())) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(6_u64)) + } + /// Storage: Bounties Bounties (r:1 w:0) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildBounties (r:1 w:1) + /// Proof: ChildBounties ChildBounties (max_values: None, max_size: Some(145), added: 2620, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) + /// Proof: ChildBounties ChildrenCuratorFees (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) fn propose_curator() -> Weight { - // 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)) - } - // Storage: Bounties Bounties (r:1 w:0) - // Storage: ChildBounties ChildBounties (r:1 w:1) - // Storage: System Account (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `796` + // Estimated: `7775` + // Minimum execution time: 16_417 nanoseconds. + Weight::from_parts(16_712_000, 7775) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: Bounties Bounties (r:1 w:0) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildBounties (r:1 w:1) + /// Proof: ChildBounties ChildBounties (max_values: None, max_size: Some(145), added: 2620, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn accept_curator() -> Weight { - // 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)) - } - // Storage: ChildBounties ChildBounties (r:1 w:1) - // Storage: Bounties Bounties (r:1 w:0) - // Storage: System Account (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `974` + // Estimated: `7875` + // Minimum execution time: 25_548 nanoseconds. + Weight::from_parts(25_919_000, 7875) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: ChildBounties ChildBounties (r:1 w:1) + /// Proof: ChildBounties ChildBounties (max_values: None, max_size: Some(145), added: 2620, mode: MaxEncodedLen) + /// Storage: Bounties Bounties (r:1 w:0) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn unassign_curator() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `974` + // Estimated: `7875` + // Minimum execution time: 27_645 nanoseconds. + Weight::from_parts(27_947_000, 7875) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } - // Storage: Bounties Bounties (r:1 w:0) - // Storage: ChildBounties ChildBounties (r:1 w:1) + /// Storage: Bounties Bounties (r:1 w:0) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildBounties (r:1 w:1) + /// Proof: ChildBounties ChildBounties (max_values: None, max_size: Some(145), added: 2620, mode: MaxEncodedLen) fn award_child_bounty() -> Weight { - // 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)) - } - // 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) + // Proof Size summary in bytes: + // Measured: `839` + // Estimated: `5272` + // Minimum execution time: 20_002 nanoseconds. + Weight::from_parts(20_512_000, 5272) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: ChildBounties ChildBounties (r:1 w:1) + /// Proof: ChildBounties ChildBounties (max_values: None, max_size: Some(145), added: 2620, mode: MaxEncodedLen) + /// Storage: System Account (r:3 w:3) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: ChildBounties ParentChildBounties (r:1 w:1) + /// Proof: ChildBounties ParentChildBounties (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) + /// Proof: ChildBounties ChildBountyDescriptions (max_values: None, max_size: Some(314), added: 2789, mode: MaxEncodedLen) fn claim_child_bounty() -> Weight { - // 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)) - } - // 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) + // Proof Size summary in bytes: + // Measured: `744` + // Estimated: `12920` + // Minimum execution time: 63_752 nanoseconds. + Weight::from_parts(64_179_000, 12920) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(6_u64)) + } + /// Storage: Bounties Bounties (r:1 w:0) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildBounties (r:1 w:1) + /// Proof: ChildBounties ChildBounties (max_values: None, max_size: Some(145), added: 2620, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) + /// Proof: ChildBounties ChildrenCuratorFees (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) + /// Storage: ChildBounties ParentChildBounties (r:1 w:1) + /// Proof: ChildBounties ParentChildBounties (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) + /// Proof: ChildBounties ChildBountyDescriptions (max_values: None, max_size: Some(314), added: 2789, mode: MaxEncodedLen) fn close_child_bounty_added() -> Weight { - // 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)) - } - // 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) + // Proof Size summary in bytes: + // Measured: `1106` + // Estimated: `15472` + // Minimum execution time: 47_388 nanoseconds. + Weight::from_parts(47_946_000, 15472) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(6_u64)) + } + /// Storage: Bounties Bounties (r:1 w:0) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildBounties (r:1 w:1) + /// Proof: ChildBounties ChildBounties (max_values: None, max_size: Some(145), added: 2620, mode: MaxEncodedLen) + /// Storage: System Account (r:3 w:3) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) + /// Proof: ChildBounties ChildrenCuratorFees (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) + /// Storage: ChildBounties ParentChildBounties (r:1 w:1) + /// Proof: ChildBounties ParentChildBounties (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) + /// Proof: ChildBounties ChildBountyDescriptions (max_values: None, max_size: Some(314), added: 2789, mode: MaxEncodedLen) fn close_child_bounty_active() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `1325` + // Estimated: `18075` + // Minimum execution time: 58_008 nanoseconds. + Weight::from_parts(58_586_000, 18075) + .saturating_add(T::DbWeight::get().reads(7_u64)) + .saturating_add(T::DbWeight::get().writes(7_u64)) } } // 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) + /// Storage: ChildBounties ParentChildBounties (r:1 w:1) + /// Proof: ChildBounties ParentChildBounties (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) + /// Storage: Bounties Bounties (r:1 w:0) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildBountyCount (r:1 w:1) + /// Proof: ChildBounties ChildBountyCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) + /// Proof: ChildBounties ChildBountyDescriptions (max_values: None, max_size: Some(314), added: 2789, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildBounties (r:0 w:1) + /// Proof: ChildBounties ChildBounties (max_values: None, max_size: Some(145), added: 2620, mode: MaxEncodedLen) /// The range of component `d` is `[0, 300]`. fn add_child_bounty(d: u32, ) -> Weight { - // 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)) - } - // Storage: Bounties Bounties (r:1 w:0) - // Storage: ChildBounties ChildBounties (r:1 w:1) - // Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `742` + // Estimated: `10848` + // Minimum execution time: 46_743 nanoseconds. + Weight::from_parts(47_762_924, 10848) + // Standard Error: 135 + .saturating_add(Weight::from_ref_time(599).saturating_mul(d.into())) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(6_u64)) + } + /// Storage: Bounties Bounties (r:1 w:0) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildBounties (r:1 w:1) + /// Proof: ChildBounties ChildBounties (max_values: None, max_size: Some(145), added: 2620, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) + /// Proof: ChildBounties ChildrenCuratorFees (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) fn propose_curator() -> Weight { - // 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)) - } - // Storage: Bounties Bounties (r:1 w:0) - // Storage: ChildBounties ChildBounties (r:1 w:1) - // Storage: System Account (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `796` + // Estimated: `7775` + // Minimum execution time: 16_417 nanoseconds. + Weight::from_parts(16_712_000, 7775) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: Bounties Bounties (r:1 w:0) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildBounties (r:1 w:1) + /// Proof: ChildBounties ChildBounties (max_values: None, max_size: Some(145), added: 2620, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn accept_curator() -> Weight { - // 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)) - } - // Storage: ChildBounties ChildBounties (r:1 w:1) - // Storage: Bounties Bounties (r:1 w:0) - // Storage: System Account (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `974` + // Estimated: `7875` + // Minimum execution time: 25_548 nanoseconds. + Weight::from_parts(25_919_000, 7875) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: ChildBounties ChildBounties (r:1 w:1) + /// Proof: ChildBounties ChildBounties (max_values: None, max_size: Some(145), added: 2620, mode: MaxEncodedLen) + /// Storage: Bounties Bounties (r:1 w:0) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn unassign_curator() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `974` + // Estimated: `7875` + // Minimum execution time: 27_645 nanoseconds. + Weight::from_parts(27_947_000, 7875) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } - // Storage: Bounties Bounties (r:1 w:0) - // Storage: ChildBounties ChildBounties (r:1 w:1) + /// Storage: Bounties Bounties (r:1 w:0) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildBounties (r:1 w:1) + /// Proof: ChildBounties ChildBounties (max_values: None, max_size: Some(145), added: 2620, mode: MaxEncodedLen) fn award_child_bounty() -> Weight { - // 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)) - } - // 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) + // Proof Size summary in bytes: + // Measured: `839` + // Estimated: `5272` + // Minimum execution time: 20_002 nanoseconds. + Weight::from_parts(20_512_000, 5272) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: ChildBounties ChildBounties (r:1 w:1) + /// Proof: ChildBounties ChildBounties (max_values: None, max_size: Some(145), added: 2620, mode: MaxEncodedLen) + /// Storage: System Account (r:3 w:3) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: ChildBounties ParentChildBounties (r:1 w:1) + /// Proof: ChildBounties ParentChildBounties (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) + /// Proof: ChildBounties ChildBountyDescriptions (max_values: None, max_size: Some(314), added: 2789, mode: MaxEncodedLen) fn claim_child_bounty() -> Weight { - // 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)) - } - // 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) + // Proof Size summary in bytes: + // Measured: `744` + // Estimated: `12920` + // Minimum execution time: 63_752 nanoseconds. + Weight::from_parts(64_179_000, 12920) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(6_u64)) + } + /// Storage: Bounties Bounties (r:1 w:0) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildBounties (r:1 w:1) + /// Proof: ChildBounties ChildBounties (max_values: None, max_size: Some(145), added: 2620, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) + /// Proof: ChildBounties ChildrenCuratorFees (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) + /// Storage: ChildBounties ParentChildBounties (r:1 w:1) + /// Proof: ChildBounties ParentChildBounties (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) + /// Proof: ChildBounties ChildBountyDescriptions (max_values: None, max_size: Some(314), added: 2789, mode: MaxEncodedLen) fn close_child_bounty_added() -> Weight { - // 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)) - } - // 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) + // Proof Size summary in bytes: + // Measured: `1106` + // Estimated: `15472` + // Minimum execution time: 47_388 nanoseconds. + Weight::from_parts(47_946_000, 15472) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(6_u64)) + } + /// Storage: Bounties Bounties (r:1 w:0) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildBounties (r:1 w:1) + /// Proof: ChildBounties ChildBounties (max_values: None, max_size: Some(145), added: 2620, mode: MaxEncodedLen) + /// Storage: System Account (r:3 w:3) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) + /// Proof: ChildBounties ChildrenCuratorFees (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) + /// Storage: ChildBounties ParentChildBounties (r:1 w:1) + /// Proof: ChildBounties ParentChildBounties (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) + /// Proof: ChildBounties ChildBountyDescriptions (max_values: None, max_size: Some(314), added: 2789, mode: MaxEncodedLen) fn close_child_bounty_active() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `1325` + // Estimated: `18075` + // Minimum execution time: 58_008 nanoseconds. + Weight::from_parts(58_586_000, 18075) + .saturating_add(RocksDbWeight::get().reads(7_u64)) + .saturating_add(RocksDbWeight::get().writes(7_u64)) } } diff --git a/frame/collective/src/weights.rs b/frame/collective/src/weights.rs index 052550de7bd7e..fe6a222017919 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) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2023 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,7 +18,8 @@ //! Autogenerated weights for pallet_collective //! //! 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: `[]` +//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -62,326 +63,492 @@ pub trait WeightInfo { /// Weights for pallet_collective using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - // Storage: Council Members (r:1 w:1) - // Storage: Council Proposals (r:1 w:0) - // Storage: Council Prime (r:0 w:1) - // Storage: Council Voting (r:100 w:100) + /// Storage: Council Members (r:1 w:1) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:0) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Voting (r:100 w:100) + /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Prime (r:0 w:1) + /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `m` is `[0, 100]`. /// The range of component `n` is `[0, 100]`. /// The range of component `p` is `[0, 100]`. fn set_members(m: u32, _n: u32, p: u32, ) -> Weight { - // 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)) - .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(p as u64))) + // Proof Size summary in bytes: + // Measured: `0 + m * (3233 ±0) + p * (3223 ±0)` + // Estimated: `16586 + m * (7809 ±24) + p * (10238 ±24)` + // Minimum execution time: 17_093 nanoseconds. + Weight::from_parts(17_284_000, 16586) + // Standard Error: 64_700 + .saturating_add(Weight::from_ref_time(5_143_145).saturating_mul(m.into())) + // Standard Error: 64_700 + .saturating_add(Weight::from_ref_time(7_480_941).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(p.into()))) + .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(p.into()))) + .saturating_add(Weight::from_proof_size(7809).saturating_mul(m.into())) + .saturating_add(Weight::from_proof_size(10238).saturating_mul(p.into())) } - // Storage: Council Members (r:1 w:0) - /// The range of component `b` is `[1, 1024]`. + /// Storage: Council Members (r:1 w:0) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// The range of component `b` is `[2, 1024]`. /// The range of component `m` is `[1, 100]`. fn execute(b: u32, m: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `234 + m * (32 ±0)` + // Estimated: `730 + m * (32 ±0)` + // Minimum execution time: 15_972 nanoseconds. + Weight::from_parts(14_971_445, 730) + // Standard Error: 32 + .saturating_add(Weight::from_ref_time(1_775).saturating_mul(b.into())) + // Standard Error: 334 + .saturating_add(Weight::from_ref_time(17_052).saturating_mul(m.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(Weight::from_proof_size(32).saturating_mul(m.into())) } - // Storage: Council Members (r:1 w:0) - // Storage: Council ProposalOf (r:1 w:0) - /// The range of component `b` is `[1, 1024]`. + /// Storage: Council Members (r:1 w:0) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council ProposalOf (r:1 w:0) + /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) + /// The range of component `b` is `[2, 1024]`. /// The range of component `m` is `[1, 100]`. fn propose_execute(b: u32, m: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `234 + m * (32 ±0)` + // Estimated: `3440 + m * (64 ±0)` + // Minimum execution time: 17_950 nanoseconds. + Weight::from_parts(17_019_558, 3440) + // Standard Error: 41 + .saturating_add(Weight::from_ref_time(1_807).saturating_mul(b.into())) + // Standard Error: 432 + .saturating_add(Weight::from_ref_time(27_986).saturating_mul(m.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(Weight::from_proof_size(64).saturating_mul(m.into())) } - // 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) - /// The range of component `b` is `[1, 1024]`. + /// Storage: Council Members (r:1 w:0) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council ProposalOf (r:1 w:1) + /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:1) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council ProposalCount (r:1 w:1) + /// Proof Skipped: Council ProposalCount (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Voting (r:0 w:1) + /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) + /// The range of component `b` is `[2, 1024]`. /// The range of component `m` is `[2, 100]`. /// The range of component `p` is `[1, 100]`. fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `556 + m * (32 ±0) + p * (36 ±0)` + // Estimated: `6355 + m * (165 ±0) + p * (180 ±0)` + // Minimum execution time: 24_817 nanoseconds. + Weight::from_parts(24_778_955, 6355) + // Standard Error: 73 + .saturating_add(Weight::from_ref_time(2_355).saturating_mul(b.into())) + // Standard Error: 765 + .saturating_add(Weight::from_ref_time(20_518).saturating_mul(m.into())) + // Standard Error: 755 + .saturating_add(Weight::from_ref_time(85_670).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + .saturating_add(Weight::from_proof_size(165).saturating_mul(m.into())) + .saturating_add(Weight::from_proof_size(180).saturating_mul(p.into())) } - // Storage: Council Members (r:1 w:0) - // Storage: Council Voting (r:1 w:1) + /// Storage: Council Members (r:1 w:0) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Voting (r:1 w:1) + /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) /// The range of component `m` is `[5, 100]`. fn vote(m: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `1006 + m * (64 ±0)` + // Estimated: `4980 + m * (128 ±0)` + // Minimum execution time: 19_790 nanoseconds. + Weight::from_parts(20_528_275, 4980) + // Standard Error: 651 + .saturating_add(Weight::from_ref_time(48_856).saturating_mul(m.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + .saturating_add(Weight::from_proof_size(128).saturating_mul(m.into())) } - // 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) + /// Storage: Council Voting (r:1 w:1) + /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Members (r:1 w:0) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:1) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council ProposalOf (r:0 w:1) + /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) /// The range of component `m` is `[4, 100]`. /// The range of component `p` is `[1, 100]`. fn close_early_disapproved(m: u32, p: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `626 + m * (64 ±0) + p * (36 ±0)` + // Estimated: `5893 + m * (260 ±0) + p * (144 ±0)` + // Minimum execution time: 25_564 nanoseconds. + Weight::from_parts(25_535_497, 5893) + // Standard Error: 610 + .saturating_add(Weight::from_ref_time(27_956).saturating_mul(m.into())) + // Standard Error: 595 + .saturating_add(Weight::from_ref_time(84_835).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(260).saturating_mul(m.into())) + .saturating_add(Weight::from_proof_size(144).saturating_mul(p.into())) } - // 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) - /// The range of component `b` is `[1, 1024]`. + /// Storage: Council Voting (r:1 w:1) + /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Members (r:1 w:0) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council ProposalOf (r:1 w:1) + /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:1) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// The range of component `b` is `[2, 1024]`. /// The range of component `m` is `[4, 100]`. /// The range of component `p` is `[1, 100]`. fn close_early_approved(b: u32, m: u32, p: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `962 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` + // Estimated: `9164 + b * (4 ±0) + m * (264 ±0) + p * (160 ±0)` + // Minimum execution time: 36_515 nanoseconds. + Weight::from_parts(36_626_648, 9164) + // Standard Error: 98 + .saturating_add(Weight::from_ref_time(2_295).saturating_mul(b.into())) + // Standard Error: 1_036 + .saturating_add(Weight::from_ref_time(22_182).saturating_mul(m.into())) + // Standard Error: 1_010 + .saturating_add(Weight::from_ref_time(100_034).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(4).saturating_mul(b.into())) + .saturating_add(Weight::from_proof_size(264).saturating_mul(m.into())) + .saturating_add(Weight::from_proof_size(160).saturating_mul(p.into())) } - // 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) + /// Storage: Council Voting (r:1 w:1) + /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Members (r:1 w:0) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Prime (r:1 w:0) + /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:1) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council ProposalOf (r:0 w:1) + /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) /// The range of component `m` is `[4, 100]`. /// The range of component `p` is `[1, 100]`. fn close_disapproved(m: u32, p: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `646 + m * (64 ±0) + p * (36 ±0)` + // Estimated: `7095 + m * (325 ±0) + p * (180 ±0)` + // Minimum execution time: 28_858 nanoseconds. + Weight::from_parts(28_050_047, 7095) + // Standard Error: 614 + .saturating_add(Weight::from_ref_time(34_031).saturating_mul(m.into())) + // Standard Error: 599 + .saturating_add(Weight::from_ref_time(85_744).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(325).saturating_mul(m.into())) + .saturating_add(Weight::from_proof_size(180).saturating_mul(p.into())) } - // 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) - /// The range of component `b` is `[1, 1024]`. + /// Storage: Council Voting (r:1 w:1) + /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Members (r:1 w:0) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Prime (r:1 w:0) + /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council ProposalOf (r:1 w:1) + /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:1) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// The range of component `b` is `[2, 1024]`. /// The range of component `m` is `[4, 100]`. /// The range of component `p` is `[1, 100]`. fn close_approved(b: u32, m: u32, p: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `982 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` + // Estimated: `10565 + b * (5 ±0) + m * (330 ±0) + p * (200 ±0)` + // Minimum execution time: 38_608 nanoseconds. + Weight::from_parts(39_948_329, 10565) + // Standard Error: 84 + .saturating_add(Weight::from_ref_time(2_045).saturating_mul(b.into())) + // Standard Error: 895 + .saturating_add(Weight::from_ref_time(22_669).saturating_mul(m.into())) + // Standard Error: 872 + .saturating_add(Weight::from_ref_time(95_525).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(5).saturating_mul(b.into())) + .saturating_add(Weight::from_proof_size(330).saturating_mul(m.into())) + .saturating_add(Weight::from_proof_size(200).saturating_mul(p.into())) } - // Storage: Council Proposals (r:1 w:1) - // Storage: Council Voting (r:0 w:1) - // Storage: Council ProposalOf (r:0 w:1) + /// Storage: Council Proposals (r:1 w:1) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Voting (r:0 w:1) + /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Council ProposalOf (r:0 w:1) + /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) /// The range of component `p` is `[1, 100]`. fn disapprove_proposal(p: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `391 + p * (32 ±0)` + // Estimated: `1668 + p * (96 ±0)` + // Minimum execution time: 14_785 nanoseconds. + Weight::from_parts(16_393_818, 1668) + // Standard Error: 612 + .saturating_add(Weight::from_ref_time(76_786).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(96).saturating_mul(p.into())) } } // For backwards compatibility and tests impl WeightInfo for () { - // Storage: Council Members (r:1 w:1) - // Storage: Council Proposals (r:1 w:0) - // Storage: Council Prime (r:0 w:1) - // Storage: Council Voting (r:100 w:100) + /// Storage: Council Members (r:1 w:1) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:0) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Voting (r:100 w:100) + /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Prime (r:0 w:1) + /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `m` is `[0, 100]`. /// The range of component `n` is `[0, 100]`. /// The range of component `p` is `[0, 100]`. fn set_members(m: u32, _n: u32, p: u32, ) -> Weight { - // 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)) - .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(p as u64))) + // Proof Size summary in bytes: + // Measured: `0 + m * (3233 ±0) + p * (3223 ±0)` + // Estimated: `16586 + m * (7809 ±24) + p * (10238 ±24)` + // Minimum execution time: 17_093 nanoseconds. + Weight::from_parts(17_284_000, 16586) + // Standard Error: 64_700 + .saturating_add(Weight::from_ref_time(5_143_145).saturating_mul(m.into())) + // Standard Error: 64_700 + .saturating_add(Weight::from_ref_time(7_480_941).saturating_mul(p.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(p.into()))) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(p.into()))) + .saturating_add(Weight::from_proof_size(7809).saturating_mul(m.into())) + .saturating_add(Weight::from_proof_size(10238).saturating_mul(p.into())) } - // Storage: Council Members (r:1 w:0) - /// The range of component `b` is `[1, 1024]`. + /// Storage: Council Members (r:1 w:0) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// The range of component `b` is `[2, 1024]`. /// The range of component `m` is `[1, 100]`. fn execute(b: u32, m: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `234 + m * (32 ±0)` + // Estimated: `730 + m * (32 ±0)` + // Minimum execution time: 15_972 nanoseconds. + Weight::from_parts(14_971_445, 730) + // Standard Error: 32 + .saturating_add(Weight::from_ref_time(1_775).saturating_mul(b.into())) + // Standard Error: 334 + .saturating_add(Weight::from_ref_time(17_052).saturating_mul(m.into())) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(Weight::from_proof_size(32).saturating_mul(m.into())) } - // Storage: Council Members (r:1 w:0) - // Storage: Council ProposalOf (r:1 w:0) - /// The range of component `b` is `[1, 1024]`. + /// Storage: Council Members (r:1 w:0) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council ProposalOf (r:1 w:0) + /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) + /// The range of component `b` is `[2, 1024]`. /// The range of component `m` is `[1, 100]`. fn propose_execute(b: u32, m: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `234 + m * (32 ±0)` + // Estimated: `3440 + m * (64 ±0)` + // Minimum execution time: 17_950 nanoseconds. + Weight::from_parts(17_019_558, 3440) + // Standard Error: 41 + .saturating_add(Weight::from_ref_time(1_807).saturating_mul(b.into())) + // Standard Error: 432 + .saturating_add(Weight::from_ref_time(27_986).saturating_mul(m.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(Weight::from_proof_size(64).saturating_mul(m.into())) } - // 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) - /// The range of component `b` is `[1, 1024]`. + /// Storage: Council Members (r:1 w:0) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council ProposalOf (r:1 w:1) + /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:1) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council ProposalCount (r:1 w:1) + /// Proof Skipped: Council ProposalCount (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Voting (r:0 w:1) + /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) + /// The range of component `b` is `[2, 1024]`. /// The range of component `m` is `[2, 100]`. /// The range of component `p` is `[1, 100]`. fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `556 + m * (32 ±0) + p * (36 ±0)` + // Estimated: `6355 + m * (165 ±0) + p * (180 ±0)` + // Minimum execution time: 24_817 nanoseconds. + Weight::from_parts(24_778_955, 6355) + // Standard Error: 73 + .saturating_add(Weight::from_ref_time(2_355).saturating_mul(b.into())) + // Standard Error: 765 + .saturating_add(Weight::from_ref_time(20_518).saturating_mul(m.into())) + // Standard Error: 755 + .saturating_add(Weight::from_ref_time(85_670).saturating_mul(p.into())) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + .saturating_add(Weight::from_proof_size(165).saturating_mul(m.into())) + .saturating_add(Weight::from_proof_size(180).saturating_mul(p.into())) } - // Storage: Council Members (r:1 w:0) - // Storage: Council Voting (r:1 w:1) + /// Storage: Council Members (r:1 w:0) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Voting (r:1 w:1) + /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) /// The range of component `m` is `[5, 100]`. fn vote(m: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `1006 + m * (64 ±0)` + // Estimated: `4980 + m * (128 ±0)` + // Minimum execution time: 19_790 nanoseconds. + Weight::from_parts(20_528_275, 4980) + // Standard Error: 651 + .saturating_add(Weight::from_ref_time(48_856).saturating_mul(m.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + .saturating_add(Weight::from_proof_size(128).saturating_mul(m.into())) } - // 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) + /// Storage: Council Voting (r:1 w:1) + /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Members (r:1 w:0) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:1) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council ProposalOf (r:0 w:1) + /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) /// The range of component `m` is `[4, 100]`. /// The range of component `p` is `[1, 100]`. fn close_early_disapproved(m: u32, p: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `626 + m * (64 ±0) + p * (36 ±0)` + // Estimated: `5893 + m * (260 ±0) + p * (144 ±0)` + // Minimum execution time: 25_564 nanoseconds. + Weight::from_parts(25_535_497, 5893) + // Standard Error: 610 + .saturating_add(Weight::from_ref_time(27_956).saturating_mul(m.into())) + // Standard Error: 595 + .saturating_add(Weight::from_ref_time(84_835).saturating_mul(p.into())) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(260).saturating_mul(m.into())) + .saturating_add(Weight::from_proof_size(144).saturating_mul(p.into())) } - // 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) - /// The range of component `b` is `[1, 1024]`. + /// Storage: Council Voting (r:1 w:1) + /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Members (r:1 w:0) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council ProposalOf (r:1 w:1) + /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:1) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// The range of component `b` is `[2, 1024]`. /// The range of component `m` is `[4, 100]`. /// The range of component `p` is `[1, 100]`. fn close_early_approved(b: u32, m: u32, p: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `962 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` + // Estimated: `9164 + b * (4 ±0) + m * (264 ±0) + p * (160 ±0)` + // Minimum execution time: 36_515 nanoseconds. + Weight::from_parts(36_626_648, 9164) + // Standard Error: 98 + .saturating_add(Weight::from_ref_time(2_295).saturating_mul(b.into())) + // Standard Error: 1_036 + .saturating_add(Weight::from_ref_time(22_182).saturating_mul(m.into())) + // Standard Error: 1_010 + .saturating_add(Weight::from_ref_time(100_034).saturating_mul(p.into())) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(4).saturating_mul(b.into())) + .saturating_add(Weight::from_proof_size(264).saturating_mul(m.into())) + .saturating_add(Weight::from_proof_size(160).saturating_mul(p.into())) } - // 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) + /// Storage: Council Voting (r:1 w:1) + /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Members (r:1 w:0) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Prime (r:1 w:0) + /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:1) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council ProposalOf (r:0 w:1) + /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) /// The range of component `m` is `[4, 100]`. /// The range of component `p` is `[1, 100]`. fn close_disapproved(m: u32, p: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `646 + m * (64 ±0) + p * (36 ±0)` + // Estimated: `7095 + m * (325 ±0) + p * (180 ±0)` + // Minimum execution time: 28_858 nanoseconds. + Weight::from_parts(28_050_047, 7095) + // Standard Error: 614 + .saturating_add(Weight::from_ref_time(34_031).saturating_mul(m.into())) + // Standard Error: 599 + .saturating_add(Weight::from_ref_time(85_744).saturating_mul(p.into())) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(325).saturating_mul(m.into())) + .saturating_add(Weight::from_proof_size(180).saturating_mul(p.into())) } - // 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) - /// The range of component `b` is `[1, 1024]`. + /// Storage: Council Voting (r:1 w:1) + /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Members (r:1 w:0) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Prime (r:1 w:0) + /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council ProposalOf (r:1 w:1) + /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:1) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// The range of component `b` is `[2, 1024]`. /// The range of component `m` is `[4, 100]`. /// The range of component `p` is `[1, 100]`. fn close_approved(b: u32, m: u32, p: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `982 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` + // Estimated: `10565 + b * (5 ±0) + m * (330 ±0) + p * (200 ±0)` + // Minimum execution time: 38_608 nanoseconds. + Weight::from_parts(39_948_329, 10565) + // Standard Error: 84 + .saturating_add(Weight::from_ref_time(2_045).saturating_mul(b.into())) + // Standard Error: 895 + .saturating_add(Weight::from_ref_time(22_669).saturating_mul(m.into())) + // Standard Error: 872 + .saturating_add(Weight::from_ref_time(95_525).saturating_mul(p.into())) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(5).saturating_mul(b.into())) + .saturating_add(Weight::from_proof_size(330).saturating_mul(m.into())) + .saturating_add(Weight::from_proof_size(200).saturating_mul(p.into())) } - // Storage: Council Proposals (r:1 w:1) - // Storage: Council Voting (r:0 w:1) - // Storage: Council ProposalOf (r:0 w:1) + /// Storage: Council Proposals (r:1 w:1) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Voting (r:0 w:1) + /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Council ProposalOf (r:0 w:1) + /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) /// The range of component `p` is `[1, 100]`. fn disapprove_proposal(p: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `391 + p * (32 ±0)` + // Estimated: `1668 + p * (96 ±0)` + // Minimum execution time: 14_785 nanoseconds. + Weight::from_parts(16_393_818, 1668) + // Standard Error: 612 + .saturating_add(Weight::from_ref_time(76_786).saturating_mul(p.into())) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(96).saturating_mul(p.into())) } } diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index a750a6b1728d6..2bd807dfb758f 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -205,11 +205,13 @@ benchmarks! { } // The base weight consumed on processing contracts deletion queue. + #[pov_mode = Ignored] on_process_deletion_queue_batch {}: { Storage::::process_deletion_queue_batch(Weight::MAX) } #[skip_meta] + #[pov_mode = Ignored] on_initialize_per_trie_key { let k in 0..1024; let instance = Contract::::with_storage(WasmModule::dummy(), k, T::Schedule::get().limits.payload_len)?; @@ -218,6 +220,7 @@ benchmarks! { Storage::::process_deletion_queue_batch(Weight::MAX) } + #[pov_mode = Ignored] on_initialize_per_queue_item { let q in 0..1024.min(T::DeletionQueueDepth::get()); for i in 0 .. q { @@ -232,6 +235,7 @@ 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. + #[pov_mode = Ignored] reinstrument { let c in 0 .. Perbill::from_percent(49).mul_ceil(T::MaxCodeLen::get()); let WasmModule { code, hash, .. } = WasmModule::::sized(c, Location::Call); @@ -248,6 +252,7 @@ benchmarks! { // 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)`. + #[pov_mode = Ignored] call_with_code_per_byte { let c in 0 .. T::MaxCodeLen::get(); let instance = Contract::::with_caller( @@ -273,6 +278,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**. + #[pov_mode = Ignored] instantiate_with_code { let c in 0 .. Perbill::from_percent(49).mul_ceil(T::MaxCodeLen::get()); let i in 0 .. code::max_pages::() * 64 * 1024; @@ -304,6 +310,7 @@ benchmarks! { // Instantiate uses a dummy contract constructor to measure the overhead of the instantiate. // `i`: Size of the input in kilobytes. // `s`: Size of the salt in kilobytes. + #[pov_mode = Ignored] instantiate { let i in 0 .. code::max_pages::() * 64 * 1024; let s in 0 .. code::max_pages::() * 64 * 1024; @@ -335,6 +342,7 @@ benchmarks! { // 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. + #[pov_mode = Ignored] call { let data = vec![42u8; 1024]; let instance = Contract::::with_caller( @@ -367,6 +375,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**. + #[pov_mode = Ignored] upload_code { let c in 0 .. Perbill::from_percent(49).mul_ceil(T::MaxCodeLen::get()); let caller = whitelisted_caller(); @@ -383,6 +392,7 @@ benchmarks! { // 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`). + #[pov_mode = Ignored] remove_code { let caller = whitelisted_caller(); T::Currency::make_free_balance_be(&caller, caller_funding::()); @@ -399,6 +409,7 @@ benchmarks! { assert!(>::code_removed(&hash)); } + #[pov_mode = Ignored] set_code { let instance = >::with_caller( whitelisted_caller(), WasmModule::dummy(), vec![], @@ -413,6 +424,7 @@ benchmarks! { assert_eq!(instance.info()?.code_hash, hash); } + #[pov_mode = Ignored] seal_caller { let r in 0 .. API_BENCHMARK_BATCHES; let instance = Contract::::new(WasmModule::getter( @@ -421,6 +433,7 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[pov_mode = Ignored] seal_is_contract { let r in 0 .. API_BENCHMARK_BATCHES; let accounts = (0 .. r * API_BENCHMARK_BATCH_SIZE) @@ -458,6 +471,7 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[pov_mode = Ignored] seal_code_hash { let r in 0 .. API_BENCHMARK_BATCHES; let accounts = (0 .. r * API_BENCHMARK_BATCH_SIZE) @@ -503,6 +517,7 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[pov_mode = Ignored] seal_own_code_hash { let r in 0 .. API_BENCHMARK_BATCHES; let instance = Contract::::new(WasmModule::getter( @@ -511,6 +526,7 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[pov_mode = Ignored] seal_caller_is_origin { let r in 0 .. API_BENCHMARK_BATCHES; let code = WasmModule::::from(ModuleDefinition { @@ -531,6 +547,7 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[pov_mode = Ignored] seal_address { let r in 0 .. API_BENCHMARK_BATCHES; let instance = Contract::::new(WasmModule::getter( @@ -539,6 +556,7 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[pov_mode = Ignored] seal_gas_left { let r in 0 .. API_BENCHMARK_BATCHES; let instance = Contract::::new(WasmModule::getter( @@ -547,6 +565,7 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[pov_mode = Ignored] seal_balance { let r in 0 .. API_BENCHMARK_BATCHES; let instance = Contract::::new(WasmModule::getter( @@ -555,6 +574,7 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[pov_mode = Ignored] seal_value_transferred { let r in 0 .. API_BENCHMARK_BATCHES; let instance = Contract::::new(WasmModule::getter( @@ -563,6 +583,7 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[pov_mode = Ignored] seal_minimum_balance { let r in 0 .. API_BENCHMARK_BATCHES; let instance = Contract::::new(WasmModule::getter( @@ -571,6 +592,7 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[pov_mode = Ignored] seal_block_number { let r in 0 .. API_BENCHMARK_BATCHES; let instance = Contract::::new(WasmModule::getter( @@ -579,6 +601,7 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[pov_mode = Ignored] seal_now { let r in 0 .. API_BENCHMARK_BATCHES; let instance = Contract::::new(WasmModule::getter( @@ -587,6 +610,7 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[pov_mode = Ignored] seal_weight_to_fee { let r in 0 .. API_BENCHMARK_BATCHES; let pages = code::max_pages::(); @@ -614,6 +638,7 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[pov_mode = Ignored] seal_gas { let r in 0 .. API_BENCHMARK_BATCHES; let code = WasmModule::::from(ModuleDefinition { @@ -634,6 +659,7 @@ benchmarks! { }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[pov_mode = Ignored] seal_input { let r in 0 .. API_BENCHMARK_BATCHES; let code = WasmModule::::from(ModuleDefinition { @@ -661,6 +687,7 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[pov_mode = Ignored] seal_input_per_kb { let n in 0 .. code::max_pages::() * 64; let pages = code::max_pages::(); @@ -694,6 +721,7 @@ benchmarks! { // 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 // contract it cannot be used as an attack vector. + #[pov_mode = Ignored] seal_return { let r in 0 .. 1; let code = WasmModule::::from(ModuleDefinition { @@ -716,6 +744,7 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[pov_mode = Ignored] seal_return_per_kb { let n in 0 .. code::max_pages::() * 64; let code = WasmModule::::from(ModuleDefinition { @@ -740,6 +769,7 @@ benchmarks! { }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) // The same argument as for `seal_return` is true here. + #[pov_mode = Ignored] seal_terminate { let r in 0 .. 1; let beneficiary = account::("beneficiary", 0, 0); @@ -782,6 +812,7 @@ benchmarks! { // We benchmark only for the maximum subject length. We assume that this is some lowish // number (< 1 KB). Therefore we are not overcharging too much in case a smaller subject is // used. + #[pov_mode = Ignored] seal_random { let r in 0 .. API_BENCHMARK_BATCHES; let pages = code::max_pages::(); @@ -816,6 +847,7 @@ benchmarks! { // Overhead of calling the function without any topic. // We benchmark for the worst case (largest event). + #[pov_mode = Ignored] seal_deposit_event { let r in 0 .. API_BENCHMARK_BATCHES; let code = WasmModule::::from(ModuleDefinition { @@ -842,6 +874,7 @@ benchmarks! { // Benchmark the overhead that topics generate. // `t`: Number of topics // `n`: Size of event payload in kb + #[pov_mode = Ignored] seal_deposit_event_per_topic_and_kb { let t in 0 .. T::Schedule::get().limits.event_topics; let n in 0 .. T::Schedule::get().limits.payload_len / 1024; @@ -880,6 +913,7 @@ benchmarks! { // 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 // when the contract is called as RPC where weights do not matter. + #[pov_mode = Ignored] seal_debug_message { let r in 0 .. API_BENCHMARK_BATCHES; let max_bytes = code::max_pages::() * 64 * 1024; @@ -910,6 +944,7 @@ benchmarks! { // because re-writing at an existing key is always more expensive than writing // it at a virgin key. #[skip_meta] + #[pov_mode = Ignored] seal_set_storage { let r in 0 .. API_BENCHMARK_BATCHES/2; let max_key_len = T::MaxStorageKeyLen::get(); @@ -958,6 +993,7 @@ benchmarks! { }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) #[skip_meta] + #[pov_mode = Ignored] seal_set_storage_per_new_kb { 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(); @@ -1006,6 +1042,7 @@ benchmarks! { }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) #[skip_meta] + #[pov_mode = Ignored] seal_set_storage_per_old_kb { 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(); @@ -1058,6 +1095,7 @@ benchmarks! { // 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] + #[pov_mode = Ignored] seal_clear_storage { let r in 0 .. API_BENCHMARK_BATCHES/2; let max_key_len = T::MaxStorageKeyLen::get(); @@ -1105,6 +1143,7 @@ benchmarks! { }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) #[skip_meta] + #[pov_mode = Ignored] seal_clear_storage_per_kb { 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(); @@ -1152,6 +1191,7 @@ benchmarks! { // We make sure that all storage accesses are to unique keys. #[skip_meta] + #[pov_mode = Ignored] seal_get_storage { let r in 0 .. API_BENCHMARK_BATCHES/2; let max_key_len = T::MaxStorageKeyLen::get(); @@ -1206,6 +1246,7 @@ benchmarks! { }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) #[skip_meta] + #[pov_mode = Ignored] seal_get_storage_per_kb { 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(); @@ -1261,6 +1302,7 @@ benchmarks! { // We make sure that all storage accesses are to unique keys. #[skip_meta] + #[pov_mode = Ignored] seal_contains_storage { let r in 0 .. API_BENCHMARK_BATCHES/2; let max_key_len = T::MaxStorageKeyLen::get(); @@ -1309,6 +1351,7 @@ benchmarks! { }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) #[skip_meta] + #[pov_mode = Ignored] seal_contains_storage_per_kb { 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(); @@ -1356,6 +1399,7 @@ benchmarks! { }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) #[skip_meta] + #[pov_mode = Ignored] seal_take_storage { let r in 0 .. API_BENCHMARK_BATCHES/2; let max_key_len = T::MaxStorageKeyLen::get(); @@ -1410,6 +1454,7 @@ benchmarks! { }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) #[skip_meta] + #[pov_mode = Ignored] seal_take_storage_per_kb { 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(); @@ -1464,6 +1509,7 @@ benchmarks! { }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) // We transfer to unique accounts. + #[pov_mode = Ignored] seal_transfer { let r in 0 .. API_BENCHMARK_BATCHES; let accounts = (0..r * API_BENCHMARK_BATCH_SIZE) @@ -1517,6 +1563,7 @@ benchmarks! { } // We call unique accounts. + #[pov_mode = Ignored] seal_call { let r in 0 .. API_BENCHMARK_BATCHES; let dummy_code = WasmModule::::dummy_with_bytes(0); @@ -1575,6 +1622,7 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[pov_mode = Ignored] seal_delegate_call { let r in 0 .. API_BENCHMARK_BATCHES; let hashes = (0..r * API_BENCHMARK_BATCH_SIZE) @@ -1627,6 +1675,7 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller); }: call(origin, callee, 0u32.into(), Weight::MAX, None, vec![]) + #[pov_mode = Ignored] seal_call_per_transfer_clone_kb { let t in 0 .. 1; let c in 0 .. code::max_pages::() * 64; @@ -1685,6 +1734,7 @@ benchmarks! { }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, bytes) // We assume that every instantiate sends at least the minimum balance. + #[pov_mode = Ignored] seal_instantiate { let r in 0 .. API_BENCHMARK_BATCHES; let hashes = (0..r * API_BENCHMARK_BATCH_SIZE) @@ -1798,6 +1848,7 @@ benchmarks! { } } + #[pov_mode = Ignored] seal_instantiate_per_transfer_input_salt_kb { let t in 0 .. 1; let i in 0 .. (code::max_pages::() - 1) * 64; @@ -1892,6 +1943,7 @@ benchmarks! { }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) // Only the overhead of calling the function itself with minimal arguments. + #[pov_mode = Ignored] seal_hash_sha2_256 { let r in 0 .. 1; let instance = Contract::::new(WasmModule::hasher( @@ -1901,6 +1953,7 @@ benchmarks! { }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) // `n`: Input to hash in kilobytes + #[pov_mode = Ignored] seal_hash_sha2_256_per_kb { let n in 0 .. code::max_pages::() * 64; let instance = Contract::::new(WasmModule::hasher( @@ -1910,6 +1963,7 @@ benchmarks! { }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) // Only the overhead of calling the function itself with minimal arguments. + #[pov_mode = Ignored] seal_hash_keccak_256 { let r in 0 .. 1; let instance = Contract::::new(WasmModule::hasher( @@ -1919,6 +1973,7 @@ benchmarks! { }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) // `n`: Input to hash in kilobytes + #[pov_mode = Ignored] seal_hash_keccak_256_per_kb { let n in 0 .. code::max_pages::() * 64; let instance = Contract::::new(WasmModule::hasher( @@ -1928,6 +1983,7 @@ benchmarks! { }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) // Only the overhead of calling the function itself with minimal arguments. + #[pov_mode = Ignored] seal_hash_blake2_256 { let r in 0 .. 1; let instance = Contract::::new(WasmModule::hasher( @@ -1937,6 +1993,7 @@ benchmarks! { }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) // `n`: Input to hash in kilobytes + #[pov_mode = Ignored] seal_hash_blake2_256_per_kb { let n in 0 .. code::max_pages::() * 64; let instance = Contract::::new(WasmModule::hasher( @@ -1946,6 +2003,7 @@ benchmarks! { }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) // Only the overhead of calling the function itself with minimal arguments. + #[pov_mode = Ignored] seal_hash_blake2_128 { let r in 0 .. 1; let instance = Contract::::new(WasmModule::hasher( @@ -1955,6 +2013,7 @@ benchmarks! { }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) // `n`: Input to hash in kilobytes + #[pov_mode = Ignored] seal_hash_blake2_128_per_kb { let n in 0 .. code::max_pages::() * 64; let instance = Contract::::new(WasmModule::hasher( @@ -1965,6 +2024,7 @@ benchmarks! { // Only calling the function itself with valid arguments. // It generates different private keys and signatures for the message "Hello world". + #[pov_mode = Ignored] seal_ecdsa_recover { let r in 0 .. 1; @@ -2013,6 +2073,7 @@ benchmarks! { // Only calling the function itself for the list of // generated different ECDSA keys. + #[pov_mode = Ignored] seal_ecdsa_to_eth_address { let r in 0 .. 1; let key_type = sp_core::crypto::KeyTypeId(*b"code"); @@ -2048,6 +2109,7 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[pov_mode = Ignored] seal_set_code_hash { let r in 0 .. API_BENCHMARK_BATCHES; let code_hashes = (0..r * API_BENCHMARK_BATCH_SIZE) @@ -2088,6 +2150,7 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[pov_mode = Ignored] seal_reentrance_count { let r in 0 .. API_BENCHMARK_BATCHES; let code = WasmModule::::from(ModuleDefinition { @@ -2108,6 +2171,7 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[pov_mode = Ignored] seal_account_reentrance_count { let r in 0 .. API_BENCHMARK_BATCHES; let dummy_code = WasmModule::::dummy_with_bytes(0); @@ -2141,6 +2205,7 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[pov_mode = Ignored] seal_instantiation_nonce { let r in 0 .. API_BENCHMARK_BATCHES; let code = WasmModule::::from(ModuleDefinition { @@ -2171,6 +2236,7 @@ benchmarks! { // The weight that would result from the respective benchmark we call: `w_bench`. // // w_i{32,64}const = w_drop = w_bench / 2 + #[pov_mode = Ignored] instr_i64const { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::from(ModuleDefinition { @@ -2185,6 +2251,7 @@ benchmarks! { } // w_i{32,64}load = w_bench - 2 * w_param + #[pov_mode = Ignored] instr_i64load { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::from(ModuleDefinition { @@ -2201,6 +2268,7 @@ benchmarks! { } // w_i{32,64}store{...} = w_bench - 2 * w_param + #[pov_mode = Ignored] instr_i64store { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::from(ModuleDefinition { @@ -2217,6 +2285,7 @@ benchmarks! { } // w_select = w_bench - 4 * w_param + #[pov_mode = Ignored] instr_select { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::from(ModuleDefinition { @@ -2234,6 +2303,7 @@ benchmarks! { } // w_if = w_bench - 3 * w_param + #[pov_mode = Ignored] instr_if { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::from(ModuleDefinition { @@ -2254,6 +2324,7 @@ benchmarks! { // w_br = w_bench - 2 * w_param // Block instructions are not counted. + #[pov_mode = Ignored] instr_br { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::from(ModuleDefinition { @@ -2280,6 +2351,7 @@ benchmarks! { // w_br_if = w_bench - 3 * w_param // Block instructions are not counted. + #[pov_mode = Ignored] instr_br_if { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::from(ModuleDefinition { @@ -2307,6 +2379,7 @@ benchmarks! { // w_br_table = w_bench - 3 * w_param // Block instructions are not counted. + #[pov_mode = Ignored] instr_br_table { let r in 0 .. INSTR_BENCHMARK_BATCHES; let table = Box::new(BrTableData { @@ -2337,6 +2410,7 @@ benchmarks! { } // w_br_table_per_entry = w_bench + #[pov_mode = Ignored] instr_br_table_per_entry { let e in 1 .. T::Schedule::get().limits.br_table_size; let entry: Vec = [0, 1].iter() @@ -2371,6 +2445,7 @@ benchmarks! { } // w_call = w_bench - 2 * w_param + #[pov_mode = Ignored] instr_call { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::from(ModuleDefinition { @@ -2391,6 +2466,7 @@ benchmarks! { } // w_call_indrect = w_bench - 3 * w_param + #[pov_mode = Ignored] instr_call_indirect { let r in 0 .. INSTR_BENCHMARK_BATCHES; let num_elements = T::Schedule::get().limits.table_size; @@ -2421,6 +2497,7 @@ benchmarks! { // Calling a function indirectly causes it to go through a thunk function whose runtime // linearly depend on the amount of parameters to this function. // Please note that this is not necessary with a direct call. + #[pov_mode = Ignored] instr_call_indirect_per_param { let p in 0 .. T::Schedule::get().limits.parameters; let num_elements = T::Schedule::get().limits.table_size; @@ -2450,6 +2527,7 @@ benchmarks! { } // w_per_local = w_bench + #[pov_mode = Ignored] instr_call_per_local { let l in 0 .. T::Schedule::get().limits.locals; let mut aux_body = body::plain(vec![ @@ -2468,6 +2546,7 @@ benchmarks! { } // w_local_get = w_bench - 1 * w_param + #[pov_mode = Ignored] instr_local_get { let r in 0 .. INSTR_BENCHMARK_BATCHES; let max_locals = T::Schedule::get().limits.locals; @@ -2485,6 +2564,7 @@ benchmarks! { } // w_local_set = w_bench - 1 * w_param + #[pov_mode = Ignored] instr_local_set { let r in 0 .. INSTR_BENCHMARK_BATCHES; let max_locals = T::Schedule::get().limits.locals; @@ -2502,6 +2582,7 @@ benchmarks! { } // w_local_tee = w_bench - 2 * w_param + #[pov_mode = Ignored] instr_local_tee { let r in 0 .. INSTR_BENCHMARK_BATCHES; let max_locals = T::Schedule::get().limits.locals; @@ -2520,6 +2601,7 @@ benchmarks! { } // w_global_get = w_bench - 1 * w_param + #[pov_mode = Ignored] instr_global_get { let r in 0 .. INSTR_BENCHMARK_BATCHES; let max_globals = T::Schedule::get().limits.globals; @@ -2536,6 +2618,7 @@ benchmarks! { } // w_global_set = w_bench - 1 * w_param + #[pov_mode = Ignored] instr_global_set { let r in 0 .. INSTR_BENCHMARK_BATCHES; let max_globals = T::Schedule::get().limits.globals; @@ -2552,6 +2635,7 @@ benchmarks! { } // w_memory_get = w_bench - 1 * w_param + #[pov_mode = Ignored] instr_memory_current { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::from(ModuleDefinition { @@ -2571,6 +2655,7 @@ benchmarks! { // 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. + #[pov_mode = Ignored] instr_memory_grow { let r in 0 .. 1; let max_pages = ImportedMemory::max::().max_pages; @@ -2593,6 +2678,7 @@ benchmarks! { // Unary numeric instructions. // All use w = w_bench - 2 * w_param. + #[pov_mode = Ignored] instr_i64clz { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::unary_instr( @@ -2603,6 +2689,7 @@ benchmarks! { sbox.invoke(); } + #[pov_mode = Ignored] instr_i64ctz { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::unary_instr( @@ -2613,6 +2700,7 @@ benchmarks! { sbox.invoke(); } + #[pov_mode = Ignored] instr_i64popcnt { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::unary_instr( @@ -2623,6 +2711,7 @@ benchmarks! { sbox.invoke(); } + #[pov_mode = Ignored] instr_i64eqz { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::unary_instr( @@ -2633,6 +2722,7 @@ benchmarks! { sbox.invoke(); } + #[pov_mode = Ignored] instr_i64extendsi32 { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::from(ModuleDefinition { @@ -2647,6 +2737,7 @@ benchmarks! { sbox.invoke(); } + #[pov_mode = Ignored] instr_i64extendui32 { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::from(ModuleDefinition { @@ -2661,6 +2752,7 @@ benchmarks! { sbox.invoke(); } + #[pov_mode = Ignored] instr_i32wrapi64 { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::unary_instr( @@ -2674,6 +2766,7 @@ benchmarks! { // Binary numeric instructions. // All use w = w_bench - 3 * w_param. + #[pov_mode = Ignored] instr_i64eq { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( @@ -2684,6 +2777,7 @@ benchmarks! { sbox.invoke(); } + #[pov_mode = Ignored] instr_i64ne { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( @@ -2694,6 +2788,7 @@ benchmarks! { sbox.invoke(); } + #[pov_mode = Ignored] instr_i64lts { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( @@ -2704,6 +2799,7 @@ benchmarks! { sbox.invoke(); } + #[pov_mode = Ignored] instr_i64ltu { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( @@ -2714,6 +2810,7 @@ benchmarks! { sbox.invoke(); } + #[pov_mode = Ignored] instr_i64gts { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( @@ -2724,6 +2821,7 @@ benchmarks! { sbox.invoke(); } + #[pov_mode = Ignored] instr_i64gtu { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( @@ -2734,6 +2832,7 @@ benchmarks! { sbox.invoke(); } + #[pov_mode = Ignored] instr_i64les { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( @@ -2744,6 +2843,7 @@ benchmarks! { sbox.invoke(); } + #[pov_mode = Ignored] instr_i64leu { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( @@ -2754,6 +2854,7 @@ benchmarks! { sbox.invoke(); } + #[pov_mode = Ignored] instr_i64ges { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( @@ -2764,6 +2865,7 @@ benchmarks! { sbox.invoke(); } + #[pov_mode = Ignored] instr_i64geu { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( @@ -2774,6 +2876,7 @@ benchmarks! { sbox.invoke(); } + #[pov_mode = Ignored] instr_i64add { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( @@ -2784,6 +2887,7 @@ benchmarks! { sbox.invoke(); } + #[pov_mode = Ignored] instr_i64sub { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( @@ -2794,6 +2898,7 @@ benchmarks! { sbox.invoke(); } + #[pov_mode = Ignored] instr_i64mul { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( @@ -2804,6 +2909,7 @@ benchmarks! { sbox.invoke(); } + #[pov_mode = Ignored] instr_i64divs { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( @@ -2814,6 +2920,7 @@ benchmarks! { sbox.invoke(); } + #[pov_mode = Ignored] instr_i64divu { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( @@ -2824,6 +2931,7 @@ benchmarks! { sbox.invoke(); } + #[pov_mode = Ignored] instr_i64rems { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( @@ -2834,6 +2942,7 @@ benchmarks! { sbox.invoke(); } + #[pov_mode = Ignored] instr_i64remu { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( @@ -2844,6 +2953,7 @@ benchmarks! { sbox.invoke(); } + #[pov_mode = Ignored] instr_i64and { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( @@ -2854,6 +2964,7 @@ benchmarks! { sbox.invoke(); } + #[pov_mode = Ignored] instr_i64or { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( @@ -2864,6 +2975,7 @@ benchmarks! { sbox.invoke(); } + #[pov_mode = Ignored] instr_i64xor { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( @@ -2874,6 +2986,7 @@ benchmarks! { sbox.invoke(); } + #[pov_mode = Ignored] instr_i64shl { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( @@ -2884,6 +2997,7 @@ benchmarks! { sbox.invoke(); } + #[pov_mode = Ignored] instr_i64shrs { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( @@ -2894,6 +3008,7 @@ benchmarks! { sbox.invoke(); } + #[pov_mode = Ignored] instr_i64shru { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( @@ -2904,6 +3019,7 @@ benchmarks! { sbox.invoke(); } + #[pov_mode = Ignored] instr_i64rotl { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( @@ -2914,6 +3030,7 @@ benchmarks! { sbox.invoke(); } + #[pov_mode = Ignored] instr_i64rotr { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( @@ -2931,6 +3048,7 @@ benchmarks! { // --features runtime-benchmarks -- benchmark pallet --extra --dev --execution=native \ // -p pallet_contracts -e print_schedule --no-median-slopes --no-min-squares #[extra] + #[pov_mode = Ignored] print_schedule { #[cfg(feature = "std")] { @@ -2956,6 +3074,7 @@ benchmarks! { // `g` is used to enable gas instrumentation to compare the performance impact of // that instrumentation at runtime. #[extra] + #[pov_mode = Ignored] ink_erc20_transfer { let g in 0 .. 1; let gas_metering = g != 0; @@ -2994,6 +3113,7 @@ benchmarks! { // `g` is used to enable gas instrumentation to compare the performance impact of // that instrumentation at runtime. #[extra] + #[pov_mode = Ignored] solang_erc20_transfer { let g in 0 .. 1; let gas_metering = g != 0; diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index f97b4b790cf6e..c067b264477e9 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -81,7 +81,7 @@ //! WebAssembly based smart contracts in the Rust programming language. #![cfg_attr(not(feature = "std"), no_std)] -#![cfg_attr(feature = "runtime-benchmarks", recursion_limit = "512")] +#![cfg_attr(feature = "runtime-benchmarks", recursion_limit = "1024")] #[macro_use] mod gas; diff --git a/frame/contracts/src/weights.rs b/frame/contracts/src/weights.rs index 7ae1a9c594671..d9ec1b10b2d37 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) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2023 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -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: 2023-01-10, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! 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=* // --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 -// --header=./HEADER-APACHE2 // --output=./frame/contracts/src/weights.rs +// --header=./HEADER-APACHE2 // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -170,2554 +170,3810 @@ pub trait WeightInfo { /// Weights for pallet_contracts using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - // Storage: Contracts DeletionQueue (r:1 w:0) + /// Storage: Contracts DeletionQueue (r:1 w:0) + /// Proof: Contracts DeletionQueue (max_values: Some(1), max_size: Some(16642), added: 17137, mode: Ignored) fn on_process_deletion_queue_batch() -> Weight { - // Minimum execution time: 3_326 nanoseconds. - Weight::from_ref_time(3_433_000) - .saturating_add(T::DbWeight::get().reads(1)) - } - // Storage: Skipped Metadata (r:0 w:0) + // Proof Size summary in bytes: + // Measured: `109` + // Estimated: `0` + // Minimum execution time: 2_305 nanoseconds. + Weight::from_ref_time(2_560_000) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + /// Storage: Skipped Metadata (r:0 w:0) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Ignored) /// The range of component `k` is `[0, 1024]`. fn on_initialize_per_trie_key(k: u32, ) -> Weight { - // Minimum execution time: 15_703 nanoseconds. - Weight::from_ref_time(15_288_927) - // Standard Error: 951 - .saturating_add(Weight::from_ref_time(940_816).saturating_mul(k.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) + // Proof Size summary in bytes: + // Measured: `481 + k * (69 ±0)` + // Estimated: `0` + // Minimum execution time: 9_311 nanoseconds. + Weight::from_ref_time(5_419_288) + // Standard Error: 562 + .saturating_add(Weight::from_ref_time(911_962).saturating_mul(k.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(k.into()))) } - // Storage: Contracts DeletionQueue (r:1 w:0) + /// Storage: Contracts DeletionQueue (r:1 w:1) + /// Proof: Contracts DeletionQueue (max_values: Some(1), max_size: Some(16642), added: 17137, mode: Ignored) /// The range of component `q` is `[0, 128]`. fn on_initialize_per_queue_item(q: u32, ) -> Weight { - // Minimum execution time: 3_548 nanoseconds. - Weight::from_ref_time(15_764_121) - // Standard Error: 3_339 - .saturating_add(Weight::from_ref_time(1_214_890).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]`. + // Proof Size summary in bytes: + // Measured: `281 + q * (33 ±0)` + // Estimated: `0` + // Minimum execution time: 2_288 nanoseconds. + Weight::from_ref_time(9_442_437) + // Standard Error: 2_720 + .saturating_add(Weight::from_ref_time(1_076_950).saturating_mul(q.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Contracts PristineCode (r:1 w:0) + /// Proof: Contracts PristineCode (max_values: None, max_size: Some(125988), added: 128463, mode: Ignored) + /// Storage: Contracts CodeStorage (r:0 w:1) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// The range of component `c` is `[0, 61717]`. fn reinstrument(c: u32, ) -> Weight { - // Minimum execution time: 29_801 nanoseconds. - Weight::from_ref_time(27_932_706) - // Standard Error: 49 - .saturating_add(Weight::from_ref_time(50_532).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) - // 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]`. + // Proof Size summary in bytes: + // Measured: `270 + c * (1 ±0)` + // Estimated: `0` + // Minimum execution time: 27_539 nanoseconds. + Weight::from_ref_time(23_554_889) + // Standard Error: 56 + .saturating_add(Weight::from_ref_time(46_766).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// The range of component `c` is `[0, 125952]`. fn call_with_code_per_byte(c: u32, ) -> Weight { - // Minimum execution time: 307_894 nanoseconds. - Weight::from_ref_time(322_346_319) - // Standard Error: 25 - .saturating_add(Weight::from_ref_time(30_678).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) - // 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]`. + // Proof Size summary in bytes: + // Measured: `771` + // Estimated: `0` + // Minimum execution time: 297_710 nanoseconds. + Weight::from_ref_time(307_327_529) + // Standard Error: 18 + .saturating_add(Weight::from_ref_time(29_849).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: Contracts CodeStorage (r:1 w:1) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Contracts Nonce (r:1 w:1) + /// Proof: Contracts Nonce (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: System EventTopics (r:3 w:3) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Storage: Contracts PristineCode (r:0 w:1) + /// Proof: Contracts PristineCode (max_values: None, max_size: Some(125988), added: 128463, mode: Ignored) + /// Storage: Contracts OwnerInfoOf (r:0 w:1) + /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Ignored) + /// The range of component `c` is `[0, 61717]`. /// The range of component `i` is `[0, 1048576]`. /// The range of component `s` is `[0, 1048576]`. fn instantiate_with_code(c: u32, i: u32, s: u32, ) -> Weight { - // Minimum execution time: 3_610_424 nanoseconds. - Weight::from_ref_time(583_426_386) - // Standard Error: 277 - .saturating_add(Weight::from_ref_time(90_224).saturating_mul(c.into())) + // Proof Size summary in bytes: + // Measured: `257` + // Estimated: `0` + // Minimum execution time: 3_586_223 nanoseconds. + Weight::from_ref_time(561_614_281) + // Standard Error: 274 + .saturating_add(Weight::from_ref_time(87_557).saturating_mul(c.into())) // Standard Error: 16 - .saturating_add(Weight::from_ref_time(1_325).saturating_mul(i.into())) + .saturating_add(Weight::from_ref_time(1_307).saturating_mul(i.into())) // Standard Error: 16 - .saturating_add(Weight::from_ref_time(1_727).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) - // 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) - // Storage: System EventTopics (r:2 w:2) + .saturating_add(Weight::from_ref_time(1_721).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(8_u64)) + .saturating_add(T::DbWeight::get().writes(9_u64)) + } + /// Storage: Contracts CodeStorage (r:1 w:1) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Contracts Nonce (r:1 w:1) + /// Proof: Contracts Nonce (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts OwnerInfoOf (r:1 w:1) + /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `i` is `[0, 1048576]`. /// The range of component `s` is `[0, 1048576]`. fn instantiate(i: u32, s: u32, ) -> Weight { - // Minimum execution time: 1_892_996 nanoseconds. - Weight::from_ref_time(202_958_196) + // Proof Size summary in bytes: + // Measured: `533` + // Estimated: `0` + // Minimum execution time: 1_885_437 nanoseconds. + Weight::from_ref_time(199_943_867) // Standard Error: 8 - .saturating_add(Weight::from_ref_time(1_627).saturating_mul(i.into())) + .saturating_add(Weight::from_ref_time(1_611).saturating_mul(i.into())) // Standard Error: 8 - .saturating_add(Weight::from_ref_time(1_755).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) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System Account (r:1 w:1) - // Storage: System EventTopics (r:2 w:2) + .saturating_add(Weight::from_ref_time(1_737).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(8_u64)) + .saturating_add(T::DbWeight::get().writes(7_u64)) + } + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) fn call() -> Weight { - // Minimum execution time: 157_347 nanoseconds. - Weight::from_ref_time(159_084_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) - // Storage: Contracts PristineCode (r:0 w:1) - // Storage: Contracts OwnerInfoOf (r:0 w:1) - /// The range of component `c` is `[0, 64226]`. + // Proof Size summary in bytes: + // Measured: `823` + // Estimated: `0` + // Minimum execution time: 150_604 nanoseconds. + Weight::from_ref_time(151_777_000) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: Contracts CodeStorage (r:1 w:1) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: System EventTopics (r:1 w:1) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Storage: Contracts PristineCode (r:0 w:1) + /// Proof: Contracts PristineCode (max_values: None, max_size: Some(125988), added: 128463, mode: Ignored) + /// Storage: Contracts OwnerInfoOf (r:0 w:1) + /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Ignored) + /// The range of component `c` is `[0, 61717]`. fn upload_code(c: u32, ) -> Weight { - // Minimum execution time: 299_987 nanoseconds. - Weight::from_ref_time(305_274_879) - // Standard Error: 72 - .saturating_add(Weight::from_ref_time(91_916).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) + // Proof Size summary in bytes: + // Measured: `109` + // Estimated: `0` + // Minimum execution time: 295_505 nanoseconds. + Weight::from_ref_time(305_609_098) + // Standard Error: 58 + .saturating_add(Weight::from_ref_time(88_676).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: Contracts OwnerInfoOf (r:1 w:1) + /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Ignored) + /// Storage: System EventTopics (r:1 w:1) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Storage: Contracts CodeStorage (r:0 w:1) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Contracts PristineCode (r:0 w:1) + /// Proof: Contracts PristineCode (max_values: None, max_size: Some(125988), added: 128463, mode: Ignored) fn remove_code() -> Weight { - // Minimum execution time: 40_795 nanoseconds. - Weight::from_ref_time(41_297_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) + // Proof Size summary in bytes: + // Measured: `287` + // Estimated: `0` + // Minimum execution time: 25_949 nanoseconds. + Weight::from_ref_time(26_316_000) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts OwnerInfoOf (r:2 w:2) + /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Ignored) + /// Storage: System EventTopics (r:3 w:3) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) fn set_code() -> Weight { - // Minimum execution time: 41_957 nanoseconds. - Weight::from_ref_time(42_536_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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `634` + // Estimated: `0` + // Minimum execution time: 29_005 nanoseconds. + Weight::from_ref_time(29_370_000) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(6_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 20]`. fn seal_caller(r: u32, ) -> Weight { - // Minimum execution time: 293_544 nanoseconds. - Weight::from_ref_time(298_981_222) - // Standard Error: 39_139 - .saturating_add(Weight::from_ref_time(17_278_436).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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `845 + r * (480 ±0)` + // Estimated: `0` + // Minimum execution time: 281_880 nanoseconds. + Weight::from_ref_time(289_637_700) + // Standard Error: 22_662 + .saturating_add(Weight::from_ref_time(16_866_274).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1601 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 20]`. fn seal_is_contract(r: u32, ) -> Weight { - // Minimum execution time: 293_500 nanoseconds. - Weight::from_ref_time(237_825_284) - // Standard Error: 450_234 - .saturating_add(Weight::from_ref_time(198_995_806).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(6)) + // Proof Size summary in bytes: + // Measured: `882 + r * (19218 ±0)` + // Estimated: `0` + // Minimum execution time: 285_590 nanoseconds. + Weight::from_ref_time(231_277_523) + // Standard Error: 425_084 + .saturating_add(Weight::from_ref_time(192_985_377).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) .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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1601 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 20]`. fn seal_code_hash(r: u32, ) -> Weight { - // Minimum execution time: 295_851 nanoseconds. - Weight::from_ref_time(258_113_447) - // Standard Error: 408_747 - .saturating_add(Weight::from_ref_time(237_490_216).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(6)) + // Proof Size summary in bytes: + // Measured: `889 + r * (19539 ±0)` + // Estimated: `0` + // Minimum execution time: 282_966 nanoseconds. + Weight::from_ref_time(236_127_328) + // Standard Error: 405_193 + .saturating_add(Weight::from_ref_time(235_541_377).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) .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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 20]`. fn seal_own_code_hash(r: u32, ) -> Weight { - // Minimum execution time: 294_614 nanoseconds. - Weight::from_ref_time(301_528_998) - // Standard Error: 40_613 - .saturating_add(Weight::from_ref_time(20_815_088).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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `852 + r * (480 ±0)` + // Estimated: `0` + // Minimum execution time: 286_021 nanoseconds. + Weight::from_ref_time(290_200_599) + // Standard Error: 19_224 + .saturating_add(Weight::from_ref_time(20_692_099).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 20]`. fn seal_caller_is_origin(r: u32, ) -> Weight { - // Minimum execution time: 293_088 nanoseconds. - Weight::from_ref_time(299_120_595) - // Standard Error: 23_277 - .saturating_add(Weight::from_ref_time(11_130_334).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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `842 + r * (240 ±0)` + // Estimated: `0` + // Minimum execution time: 284_175 nanoseconds. + Weight::from_ref_time(286_665_694) + // Standard Error: 14_104 + .saturating_add(Weight::from_ref_time(11_196_944).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 20]`. fn seal_address(r: u32, ) -> Weight { - // Minimum execution time: 295_110 nanoseconds. - Weight::from_ref_time(305_295_787) - // Standard Error: 48_521 - .saturating_add(Weight::from_ref_time(16_610_806).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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `846 + r * (480 ±0)` + // Estimated: `0` + // Minimum execution time: 285_315 nanoseconds. + Weight::from_ref_time(289_734_189) + // Standard Error: 15_980 + .saturating_add(Weight::from_ref_time(16_940_657).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 20]`. fn seal_gas_left(r: u32, ) -> Weight { - // Minimum execution time: 293_414 nanoseconds. - Weight::from_ref_time(299_960_283) - // Standard Error: 32_003 - .saturating_add(Weight::from_ref_time(16_652_433).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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `847 + r * (480 ±0)` + // Estimated: `0` + // Minimum execution time: 285_708 nanoseconds. + Weight::from_ref_time(289_872_393) + // Standard Error: 16_551 + .saturating_add(Weight::from_ref_time(16_672_944).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:2 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 20]`. fn seal_balance(r: u32, ) -> Weight { - // Minimum execution time: 292_429 nanoseconds. - Weight::from_ref_time(301_025_128) - // Standard Error: 92_155 - .saturating_add(Weight::from_ref_time(92_731_719).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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `1017 + r * (480 ±0)` + // Estimated: `0` + // Minimum execution time: 285_698 nanoseconds. + Weight::from_ref_time(295_636_093) + // Standard Error: 97_582 + .saturating_add(Weight::from_ref_time(92_891_252).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(7_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 20]`. fn seal_value_transferred(r: u32, ) -> Weight { - // Minimum execution time: 293_516 nanoseconds. - Weight::from_ref_time(300_071_428) - // Standard Error: 25_871 - .saturating_add(Weight::from_ref_time(16_599_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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `856 + r * (480 ±0)` + // Estimated: `0` + // Minimum execution time: 282_057 nanoseconds. + Weight::from_ref_time(289_304_621) + // Standard Error: 17_818 + .saturating_add(Weight::from_ref_time(16_725_632).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 20]`. fn seal_minimum_balance(r: u32, ) -> Weight { - // Minimum execution time: 293_666 nanoseconds. - Weight::from_ref_time(299_803_599) - // Standard Error: 24_508 - .saturating_add(Weight::from_ref_time(16_500_973).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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `854 + r * (480 ±0)` + // Estimated: `0` + // Minimum execution time: 282_478 nanoseconds. + Weight::from_ref_time(289_682_366) + // Standard Error: 20_379 + .saturating_add(Weight::from_ref_time(16_517_079).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 20]`. fn seal_block_number(r: u32, ) -> Weight { - // Minimum execution time: 289_193 nanoseconds. - Weight::from_ref_time(297_946_784) - // Standard Error: 43_719 - .saturating_add(Weight::from_ref_time(16_442_254).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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `851 + r * (480 ±0)` + // Estimated: `0` + // Minimum execution time: 283_826 nanoseconds. + Weight::from_ref_time(289_935_300) + // Standard Error: 15_180 + .saturating_add(Weight::from_ref_time(16_268_515).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 20]`. fn seal_now(r: u32, ) -> Weight { - // Minimum execution time: 288_897 nanoseconds. - Weight::from_ref_time(298_856_658) - // Standard Error: 31_003 - .saturating_add(Weight::from_ref_time(16_490_508).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) - // 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) + // Proof Size summary in bytes: + // Measured: `842 + r * (480 ±0)` + // Estimated: `0` + // Minimum execution time: 285_455 nanoseconds. + Weight::from_ref_time(289_682_526) + // Standard Error: 18_667 + .saturating_add(Weight::from_ref_time(16_502_025).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) + /// Proof: TransactionPayment NextFeeMultiplier (max_values: Some(1), max_size: Some(16), added: 511, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 20]`. fn seal_weight_to_fee(r: u32, ) -> Weight { - // Minimum execution time: 289_850 nanoseconds. - Weight::from_ref_time(302_898_449) - // Standard Error: 92_822 - .saturating_add(Weight::from_ref_time(86_376_874).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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `919 + r * (800 ±0)` + // Estimated: `0` + // Minimum execution time: 286_106 nanoseconds. + Weight::from_ref_time(294_493_680) + // Standard Error: 76_469 + .saturating_add(Weight::from_ref_time(87_055_837).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(7_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 20]`. fn seal_gas(r: u32, ) -> Weight { - // Minimum execution time: 145_105 nanoseconds. - Weight::from_ref_time(152_388_934) - // Standard Error: 29_988 - .saturating_add(Weight::from_ref_time(7_761_947).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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `809 + r * (320 ±0)` + // Estimated: `0` + // Minimum execution time: 137_877 nanoseconds. + Weight::from_ref_time(141_863_027) + // Standard Error: 10_200 + .saturating_add(Weight::from_ref_time(7_925_232).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 20]`. fn seal_input(r: u32, ) -> Weight { - // Minimum execution time: 289_319 nanoseconds. - Weight::from_ref_time(298_390_911) - // Standard Error: 27_329 - .saturating_add(Weight::from_ref_time(14_225_527).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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `844 + r * (480 ±0)` + // Estimated: `0` + // Minimum execution time: 282_034 nanoseconds. + Weight::from_ref_time(289_388_799) + // Standard Error: 21_999 + .saturating_add(Weight::from_ref_time(15_039_420).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `n` is `[0, 1024]`. fn seal_input_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 305_538 nanoseconds. - Weight::from_ref_time(339_734_596) - // Standard Error: 4_636 - .saturating_add(Weight::from_ref_time(9_592_149).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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `1324` + // Estimated: `0` + // Minimum execution time: 303_229 nanoseconds. + Weight::from_ref_time(321_863_704) + // Standard Error: 2_754 + .saturating_add(Weight::from_ref_time(9_545_103).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 1]`. fn seal_return(r: u32, ) -> Weight { - // Minimum execution time: 287_189 nanoseconds. - Weight::from_ref_time(295_472_383) - // Standard Error: 314_142 - .saturating_add(Weight::from_ref_time(214_016).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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `832 + r * (45 ±0)` + // Estimated: `0` + // Minimum execution time: 278_824 nanoseconds. + Weight::from_ref_time(285_019_861) + // Standard Error: 101_646 + .saturating_add(Weight::from_ref_time(1_757_938).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `n` is `[0, 1024]`. fn seal_return_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 289_380 nanoseconds. - Weight::from_ref_time(296_302_404) - // Standard Error: 889 - .saturating_add(Weight::from_ref_time(190_017).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) - // 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) + // Proof Size summary in bytes: + // Measured: `842` + // Estimated: `0` + // Minimum execution time: 286_316 nanoseconds. + Weight::from_ref_time(287_206_936) + // Standard Error: 589 + .saturating_add(Weight::from_ref_time(186_684).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:3 w:3) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: Contracts DeletionQueue (r:1 w:1) + /// Proof: Contracts DeletionQueue (max_values: Some(1), max_size: Some(16642), added: 17137, mode: Ignored) + /// Storage: Contracts OwnerInfoOf (r:1 w:1) + /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Ignored) + /// Storage: System EventTopics (r:3 w:3) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 1]`. fn seal_terminate(r: u32, ) -> Weight { - // Minimum execution time: 292_383 nanoseconds. - Weight::from_ref_time(297_557_691) - // Standard Error: 251_228 - .saturating_add(Weight::from_ref_time(56_688_008).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(6)) + // Proof Size summary in bytes: + // Measured: `874 + r * (280 ±0)` + // Estimated: `0` + // Minimum execution time: 282_428 nanoseconds. + Weight::from_ref_time(287_101_148) + // Standard Error: 145_605 + .saturating_add(Weight::from_ref_time(58_079_551).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(r.into()))) - .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().writes(3_u64)) .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) - // 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) + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) + /// Proof: RandomnessCollectiveFlip RandomMaterial (max_values: Some(1), max_size: Some(2594), added: 3089, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 20]`. fn seal_random(r: u32, ) -> Weight { - // Minimum execution time: 293_019 nanoseconds. - Weight::from_ref_time(301_747_439) - // Standard Error: 92_043 - .saturating_add(Weight::from_ref_time(109_861_144).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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `889 + r * (800 ±0)` + // Estimated: `0` + // Minimum execution time: 281_516 nanoseconds. + Weight::from_ref_time(292_759_183) + // Standard Error: 152_698 + .saturating_add(Weight::from_ref_time(112_729_555).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(7_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 20]`. fn seal_deposit_event(r: u32, ) -> Weight { - // Minimum execution time: 287_586 nanoseconds. - Weight::from_ref_time(304_751_302) - // Standard Error: 127_698 - .saturating_add(Weight::from_ref_time(221_525_053).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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `842 + r * (800 ±0)` + // Estimated: `0` + // Minimum execution time: 280_100 nanoseconds. + Weight::from_ref_time(299_862_082) + // Standard Error: 95_658 + .saturating_add(Weight::from_ref_time(234_211_246).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:322 w:322) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// 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_182_204 nanoseconds. - Weight::from_ref_time(508_607_957) - // Standard Error: 503_533 - .saturating_add(Weight::from_ref_time(173_998_655).saturating_mul(t.into())) - // Standard Error: 138_294 - .saturating_add(Weight::from_ref_time(67_991_373).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(6)) + // Proof Size summary in bytes: + // Measured: `1778 + t * (2608 ±0) + n * (8 ±0)` + // Estimated: `0` + // Minimum execution time: 1_197_721 nanoseconds. + Weight::from_ref_time(508_692_255) + // Standard Error: 538_596 + .saturating_add(Weight::from_ref_time(174_792_656).saturating_mul(t.into())) + // Standard Error: 147_924 + .saturating_add(Weight::from_ref_time(67_443_118).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) .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(3_u64)) .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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 20]`. fn seal_debug_message(r: u32, ) -> Weight { - // Minimum execution time: 157_706 nanoseconds. - Weight::from_ref_time(161_895_583) - // Standard Error: 14_952 - .saturating_add(Weight::from_ref_time(12_990_237).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) + // Proof Size summary in bytes: + // Measured: `841 + r * (800 ±0)` + // Estimated: `0` + // Minimum execution time: 149_687 nanoseconds. + Weight::from_ref_time(153_589_818) + // Standard Error: 13_361 + .saturating_add(Weight::from_ref_time(13_379_131).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: Skipped Metadata (r:0 w:0) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 10]`. fn seal_set_storage(r: u32, ) -> Weight { - // Minimum execution time: 290_063 nanoseconds. - Weight::from_ref_time(256_404_853) - // Standard Error: 436_195 - .saturating_add(Weight::from_ref_time(406_569_743).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(6)) + // Proof Size summary in bytes: + // Measured: `883 + r * (23417 ±0)` + // Estimated: `0` + // Minimum execution time: 281_920 nanoseconds. + Weight::from_ref_time(242_057_723) + // Standard Error: 464_911 + .saturating_add(Weight::from_ref_time(404_673_309).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) .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(3_u64)) .saturating_add(T::DbWeight::get().writes((80_u64).saturating_mul(r.into()))) } - // Storage: Skipped Metadata (r:0 w:0) + /// Storage: Skipped Metadata (r:0 w:0) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Ignored) /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_new_kb(n: u32, ) -> Weight { - // Minimum execution time: 426_295 nanoseconds. - Weight::from_ref_time(582_989_911) - // Standard Error: 1_404_141 - .saturating_add(Weight::from_ref_time(89_545_963).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(52)) + // Proof Size summary in bytes: + // Measured: `12583 + n * (11969 ±0)` + // Estimated: `0` + // Minimum execution time: 423_923 nanoseconds. + Weight::from_ref_time(573_806_626) + // Standard Error: 1_371_107 + .saturating_add(Weight::from_ref_time(85_963_445).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(52_u64)) .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(50_u64)) .saturating_add(T::DbWeight::get().writes((7_u64).saturating_mul(n.into()))) } - // Storage: Skipped Metadata (r:0 w:0) + /// Storage: Skipped Metadata (r:0 w:0) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Ignored) /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_old_kb(n: u32, ) -> Weight { - // Minimum execution time: 425_062 nanoseconds. - Weight::from_ref_time(552_380_900) - // Standard Error: 1_140_169 - .saturating_add(Weight::from_ref_time(64_085_108).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(51)) + // Proof Size summary in bytes: + // Measured: `15138 + n * (175775 ±0)` + // Estimated: `0` + // Minimum execution time: 424_048 nanoseconds. + Weight::from_ref_time(542_298_050) + // Standard Error: 1_092_010 + .saturating_add(Weight::from_ref_time(60_111_206).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(51_u64)) .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(49_u64)) .saturating_add(T::DbWeight::get().writes((7_u64).saturating_mul(n.into()))) } - // Storage: Skipped Metadata (r:0 w:0) + /// Storage: Skipped Metadata (r:0 w:0) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 10]`. fn seal_clear_storage(r: u32, ) -> Weight { - // Minimum execution time: 294_421 nanoseconds. - Weight::from_ref_time(260_897_072) - // Standard Error: 474_135 - .saturating_add(Weight::from_ref_time(403_191_862).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(6)) + // Proof Size summary in bytes: + // Measured: `876 + r * (23098 ±0)` + // Estimated: `0` + // Minimum execution time: 285_714 nanoseconds. + Weight::from_ref_time(245_068_941) + // Standard Error: 417_796 + .saturating_add(Weight::from_ref_time(394_288_572).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) .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(3_u64)) .saturating_add(T::DbWeight::get().writes((80_u64).saturating_mul(r.into()))) } - // Storage: Skipped Metadata (r:0 w:0) + /// Storage: Skipped Metadata (r:0 w:0) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Ignored) /// The range of component `n` is `[0, 8]`. fn seal_clear_storage_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 391_743 nanoseconds. - Weight::from_ref_time(535_327_545) - // Standard Error: 1_297_157 - .saturating_add(Weight::from_ref_time(67_222_981).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(51)) + // Proof Size summary in bytes: + // Measured: `14863 + n * (175768 ±0)` + // Estimated: `0` + // Minimum execution time: 385_278 nanoseconds. + Weight::from_ref_time(522_656_525) + // Standard Error: 1_259_587 + .saturating_add(Weight::from_ref_time(62_799_142).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(51_u64)) .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(48_u64)) .saturating_add(T::DbWeight::get().writes((7_u64).saturating_mul(n.into()))) } - // Storage: Skipped Metadata (r:0 w:0) + /// Storage: Skipped Metadata (r:0 w:0) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 10]`. fn seal_get_storage(r: u32, ) -> Weight { - // Minimum execution time: 294_947 nanoseconds. - Weight::from_ref_time(266_280_887) - // Standard Error: 382_477 - .saturating_add(Weight::from_ref_time(323_306_898).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(6)) + // Proof Size summary in bytes: + // Measured: `878 + r * (23740 ±0)` + // Estimated: `0` + // Minimum execution time: 282_513 nanoseconds. + Weight::from_ref_time(256_242_753) + // Standard Error: 362_571 + .saturating_add(Weight::from_ref_time(317_951_687).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) .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(3_u64)) } - // Storage: Skipped Metadata (r:0 w:0) + /// Storage: Skipped Metadata (r:0 w:0) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Ignored) /// The range of component `n` is `[0, 8]`. fn seal_get_storage_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 375_487 nanoseconds. - Weight::from_ref_time(497_019_365) - // Standard Error: 1_141_672 - .saturating_add(Weight::from_ref_time(152_354_482).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(51)) + // Proof Size summary in bytes: + // Measured: `15469 + n * (175775 ±0)` + // Estimated: `0` + // Minimum execution time: 370_576 nanoseconds. + Weight::from_ref_time(487_764_999) + // Standard Error: 1_073_165 + .saturating_add(Weight::from_ref_time(147_588_190).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(51_u64)) .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().writes(3_u64)) } - // Storage: Skipped Metadata (r:0 w:0) + /// Storage: Skipped Metadata (r:0 w:0) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 10]`. fn seal_contains_storage(r: u32, ) -> Weight { - // Minimum execution time: 294_716 nanoseconds. - Weight::from_ref_time(266_187_186) - // Standard Error: 395_323 - .saturating_add(Weight::from_ref_time(309_907_221).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(6)) + // Proof Size summary in bytes: + // Measured: `871 + r * (23100 ±0)` + // Estimated: `0` + // Minimum execution time: 285_917 nanoseconds. + Weight::from_ref_time(259_066_807) + // Standard Error: 340_183 + .saturating_add(Weight::from_ref_time(306_291_698).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) .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(3_u64)) } - // Storage: Skipped Metadata (r:0 w:0) + /// Storage: Skipped Metadata (r:0 w:0) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Ignored) /// The range of component `n` is `[0, 8]`. fn seal_contains_storage_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 371_667 nanoseconds. - Weight::from_ref_time(478_075_482) - // Standard Error: 979_116 - .saturating_add(Weight::from_ref_time(62_075_707).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(51)) + // Proof Size summary in bytes: + // Measured: `14814 + n * (175782 ±0)` + // Estimated: `0` + // Minimum execution time: 366_225 nanoseconds. + Weight::from_ref_time(470_470_223) + // Standard Error: 953_976 + .saturating_add(Weight::from_ref_time(57_748_742).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(51_u64)) .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().writes(3_u64)) } - // Storage: Skipped Metadata (r:0 w:0) + /// Storage: Skipped Metadata (r:0 w:0) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 10]`. fn seal_take_storage(r: u32, ) -> Weight { - // Minimum execution time: 292_147 nanoseconds. - Weight::from_ref_time(254_374_598) - // Standard Error: 442_367 - .saturating_add(Weight::from_ref_time(413_674_705).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(6)) + // Proof Size summary in bytes: + // Measured: `879 + r * (23740 ±0)` + // Estimated: `0` + // Minimum execution time: 286_867 nanoseconds. + Weight::from_ref_time(244_403_664) + // Standard Error: 435_431 + .saturating_add(Weight::from_ref_time(409_282_991).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) .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(3_u64)) .saturating_add(T::DbWeight::get().writes((80_u64).saturating_mul(r.into()))) } - // Storage: Skipped Metadata (r:0 w:0) + /// Storage: Skipped Metadata (r:0 w:0) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Ignored) /// The range of component `n` is `[0, 8]`. fn seal_take_storage_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 398_554 nanoseconds. - Weight::from_ref_time(553_715_911) - // Standard Error: 1_415_272 - .saturating_add(Weight::from_ref_time(158_254_544).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(51)) + // Proof Size summary in bytes: + // Measured: `15470 + n * (175775 ±0)` + // Estimated: `0` + // Minimum execution time: 393_392 nanoseconds. + Weight::from_ref_time(540_938_487) + // Standard Error: 1_361_411 + .saturating_add(Weight::from_ref_time(153_456_560).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(51_u64)) .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(48_u64)) .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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + /// Storage: System Account (r:1602 w:1601) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 20]`. fn seal_transfer(r: u32, ) -> Weight { - // Minimum execution time: 295_081 nanoseconds. - Weight::from_ref_time(253_461_581) - // Standard Error: 740_198 - .saturating_add(Weight::from_ref_time(1_369_153_623).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(7)) + // Proof Size summary in bytes: + // Measured: `1393 + r * (3602 ±0)` + // Estimated: `0` + // Minimum execution time: 286_766 nanoseconds. + Weight::from_ref_time(221_458_774) + // Standard Error: 714_182 + .saturating_add(Weight::from_ref_time(1_402_610_222).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(7_u64)) .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(4_u64)) .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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1601 w:1601) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:2 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:1602 w:1602) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 20]`. fn seal_call(r: u32, ) -> Weight { - // Minimum execution time: 296_089 nanoseconds. - Weight::from_ref_time(297_193_000) - // Standard Error: 6_571_547 - .saturating_add(Weight::from_ref_time(21_080_280_397).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(7)) + // Proof Size summary in bytes: + // Measured: `1551 + r * (20511 ±0)` + // Estimated: `0` + // Minimum execution time: 287_158 nanoseconds. + Weight::from_ref_time(288_377_000) + // Standard Error: 6_108_706 + .saturating_add(Weight::from_ref_time(21_691_098_517).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(7_u64)) .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(3_u64)) .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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1536 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:1537 w:1537) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 20]`. fn seal_delegate_call(r: u32, ) -> Weight { - // Minimum execution time: 296_828 nanoseconds. - Weight::from_ref_time(297_685_000) - // Standard Error: 6_864_880 - .saturating_add(Weight::from_ref_time(20_770_321_946).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(6)) + // Proof Size summary in bytes: + // Measured: `0 + r * (71670 ±0)` + // Estimated: `0` + // Minimum execution time: 287_380 nanoseconds. + Weight::from_ref_time(288_241_000) + // Standard Error: 7_007_658 + .saturating_add(Weight::from_ref_time(21_428_850_764).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) .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(3_u64)) .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) - // Storage: Contracts CodeStorage (r:2 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:82 w:82) + /// Storage: System Account (r:82 w:81) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:81 w:81) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:2 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:82 w:82) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// 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_824_671 nanoseconds. - Weight::from_ref_time(8_713_861_450) - // Standard Error: 7_388_925 - .saturating_add(Weight::from_ref_time(1_327_819_806).saturating_mul(t.into())) - // Standard Error: 11_079 - .saturating_add(Weight::from_ref_time(9_789_514).saturating_mul(c.into())) - .saturating_add(T::DbWeight::get().reads(167)) + // Proof Size summary in bytes: + // Measured: `21611 + t * (15369 ±0)` + // Estimated: `0` + // Minimum execution time: 10_644_986 nanoseconds. + Weight::from_ref_time(9_596_635_640) + // Standard Error: 6_393_384 + .saturating_add(Weight::from_ref_time(1_304_764_528).saturating_mul(t.into())) + // Standard Error: 9_586 + .saturating_add(Weight::from_ref_time(9_663_819).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(167_u64)) .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(163_u64)) .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) - // 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) + /// Storage: System Account (r:1602 w:1602) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1601 w:1601) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1601 w:1600) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: Contracts Nonce (r:1 w:1) + /// Proof: Contracts Nonce (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: Contracts OwnerInfoOf (r:1600 w:1600) + /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Ignored) + /// Storage: System EventTopics (r:1602 w:1602) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 20]`. fn seal_instantiate(r: u32, ) -> Weight { - // Minimum execution time: 293_374 nanoseconds. - Weight::from_ref_time(302_067_000) - // Standard Error: 20_137_097 - .saturating_add(Weight::from_ref_time(26_444_812_817).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(8)) + // Proof Size summary in bytes: + // Measured: `1613 + r * (25576 ±0)` + // Estimated: `0` + // Minimum execution time: 284_948 nanoseconds. + Weight::from_ref_time(289_276_000) + // Standard Error: 18_674_951 + .saturating_add(Weight::from_ref_time(27_090_355_673).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(8_u64)) .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(5_u64)) .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) - // 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) - // Storage: System EventTopics (r:82 w:82) + /// Storage: System Account (r:82 w:82) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:81 w:81) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:2 w:1) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: Contracts Nonce (r:1 w:1) + /// Proof: Contracts Nonce (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: Contracts OwnerInfoOf (r:1 w:1) + /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Ignored) + /// Storage: System EventTopics (r:82 w:82) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `t` is `[0, 1]`. /// The range of component `i` is `[0, 960]`. /// The range of component `s` is `[0, 960]`. fn seal_instantiate_per_transfer_input_salt_kb(t: u32, i: u32, s: u32, ) -> Weight { - // Minimum execution time: 126_456_770 nanoseconds. - Weight::from_ref_time(9_223_715_752) - // Standard Error: 96_040_318 - .saturating_add(Weight::from_ref_time(19_550_519).saturating_mul(t.into())) - // Standard Error: 156_614 - .saturating_add(Weight::from_ref_time(122_958_298).saturating_mul(i.into())) - // Standard Error: 156_614 - .saturating_add(Weight::from_ref_time(123_316_079).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(249)) + // Proof Size summary in bytes: + // Measured: `5666 + t * (17 ±0)` + // Estimated: `0` + // Minimum execution time: 127_857_642 nanoseconds. + Weight::from_ref_time(11_399_054_049) + // Standard Error: 95_033_651 + .saturating_add(Weight::from_ref_time(434_246_236).saturating_mul(t.into())) + // Standard Error: 154_973 + .saturating_add(Weight::from_ref_time(121_130_672).saturating_mul(i.into())) + // Standard Error: 154_973 + .saturating_add(Weight::from_ref_time(121_554_853).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(249_u64)) .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(247_u64)) .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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 1]`. fn seal_hash_sha2_256(r: u32, ) -> Weight { - // Minimum execution time: 289_275 nanoseconds. - Weight::from_ref_time(297_803_961) - // Standard Error: 303_405 - .saturating_add(Weight::from_ref_time(40_800_138).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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `839 + r * (642 ±0)` + // Estimated: `0` + // Minimum execution time: 280_949 nanoseconds. + Weight::from_ref_time(286_538_475) + // Standard Error: 124_866 + .saturating_add(Weight::from_ref_time(42_531_824).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `n` is `[0, 1024]`. fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 336_077 nanoseconds. - Weight::from_ref_time(336_846_000) - // Standard Error: 51_610 - .saturating_add(Weight::from_ref_time(322_208_787).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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `1641` + // Estimated: `0` + // Minimum execution time: 328_414 nanoseconds. + Weight::from_ref_time(329_293_000) + // Standard Error: 50_816 + .saturating_add(Weight::from_ref_time(318_312_506).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 1]`. fn seal_hash_keccak_256(r: u32, ) -> Weight { - // Minimum execution time: 290_189 nanoseconds. - Weight::from_ref_time(298_454_259) - // Standard Error: 252_946 - .saturating_add(Weight::from_ref_time(55_034_240).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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `841 + r * (642 ±0)` + // Estimated: `0` + // Minimum execution time: 282_208 nanoseconds. + Weight::from_ref_time(286_848_187) + // Standard Error: 106_214 + .saturating_add(Weight::from_ref_time(56_342_512).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `n` is `[0, 1024]`. fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 350_030 nanoseconds. - Weight::from_ref_time(351_356_000) - // Standard Error: 57_422 - .saturating_add(Weight::from_ref_time(256_912_844).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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `1643` + // Estimated: `0` + // Minimum execution time: 342_478 nanoseconds. + Weight::from_ref_time(342_947_000) + // Standard Error: 60_809 + .saturating_add(Weight::from_ref_time(255_492_149).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 1]`. fn seal_hash_blake2_256(r: u32, ) -> Weight { - // Minimum execution time: 288_480 nanoseconds. - Weight::from_ref_time(297_613_263) - // Standard Error: 456_736 - .saturating_add(Weight::from_ref_time(38_100_936).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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `841 + r * (642 ±0)` + // Estimated: `0` + // Minimum execution time: 279_059 nanoseconds. + Weight::from_ref_time(285_413_659) + // Standard Error: 123_081 + .saturating_add(Weight::from_ref_time(33_154_840).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 321_195 nanoseconds. - Weight::from_ref_time(325_561_000) - // Standard Error: 46_289 - .saturating_add(Weight::from_ref_time(99_536_902).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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `1643` + // Estimated: `0` + // Minimum execution time: 317_518 nanoseconds. + Weight::from_ref_time(318_178_000) + // Standard Error: 60_074 + .saturating_add(Weight::from_ref_time(99_403_819).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 1]`. fn seal_hash_blake2_128(r: u32, ) -> Weight { - // Minimum execution time: 287_659 nanoseconds. - Weight::from_ref_time(295_963_340) - // Standard Error: 433_889 - .saturating_add(Weight::from_ref_time(30_251_859).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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `841 + r * (679 ±0)` + // Estimated: `0` + // Minimum execution time: 280_145 nanoseconds. + Weight::from_ref_time(285_483_032) + // Standard Error: 106_113 + .saturating_add(Weight::from_ref_time(33_475_067).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 324_298 nanoseconds. - Weight::from_ref_time(325_738_000) - // Standard Error: 48_563 - .saturating_add(Weight::from_ref_time(99_479_838).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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `1643` + // Estimated: `0` + // Minimum execution time: 318_141 nanoseconds. + Weight::from_ref_time(318_699_000) + // Standard Error: 55_136 + .saturating_add(Weight::from_ref_time(99_275_434).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 1]`. fn seal_ecdsa_recover(r: u32, ) -> Weight { - // Minimum execution time: 294_257 nanoseconds. - Weight::from_ref_time(299_467_620) - // Standard Error: 589_749 - .saturating_add(Weight::from_ref_time(3_015_389_579).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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `885 + r * (6083 ±0)` + // Estimated: `0` + // Minimum execution time: 282_474 nanoseconds. + Weight::from_ref_time(288_078_802) + // Standard Error: 302_968 + .saturating_add(Weight::from_ref_time(2_944_967_597).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 1]`. fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight { - // Minimum execution time: 289_480 nanoseconds. - Weight::from_ref_time(298_762_412) - // Standard Error: 397_004 - .saturating_add(Weight::from_ref_time(743_937_087).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) - // 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) + // Proof Size summary in bytes: + // Measured: `854 + r * (3362 ±0)` + // Estimated: `0` + // Minimum execution time: 281_514 nanoseconds. + Weight::from_ref_time(287_458_651) + // Standard Error: 146_715 + .saturating_add(Weight::from_ref_time(731_367_948).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1536 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: Contracts OwnerInfoOf (r:1536 w:1536) + /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Ignored) + /// Storage: System EventTopics (r:1538 w:1538) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 20]`. fn seal_set_code_hash(r: u32, ) -> Weight { - // Minimum execution time: 293_494 nanoseconds. - Weight::from_ref_time(297_756_000) - // Standard Error: 2_731_227 - .saturating_add(Weight::from_ref_time(1_387_380_436).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(6)) + // Proof Size summary in bytes: + // Measured: `0 + r * (79300 ±0)` + // Estimated: `0` + // Minimum execution time: 282_591 nanoseconds. + Weight::from_ref_time(286_842_000) + // Standard Error: 2_645_254 + .saturating_add(Weight::from_ref_time(1_394_535_676).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) .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(3_u64)) .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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 20]`. fn seal_reentrance_count(r: u32, ) -> Weight { - // Minimum execution time: 295_339 nanoseconds. - Weight::from_ref_time(301_577_907) - // Standard Error: 23_836 - .saturating_add(Weight::from_ref_time(10_876_508).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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `837 + r * (240 ±0)` + // Estimated: `0` + // Minimum execution time: 286_631 nanoseconds. + Weight::from_ref_time(288_787_650) + // Standard Error: 29_802 + .saturating_add(Weight::from_ref_time(11_115_811).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 20]`. fn seal_account_reentrance_count(r: u32, ) -> Weight { - // Minimum execution time: 297_096 nanoseconds. - Weight::from_ref_time(336_319_823) - // Standard Error: 128_941 - .saturating_add(Weight::from_ref_time(25_211_374).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) - // 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) + // Proof Size summary in bytes: + // Measured: `2056 + r * (3153 ±0)` + // Estimated: `0` + // Minimum execution time: 287_775 nanoseconds. + Weight::from_ref_time(319_806_123) + // Standard Error: 111_808 + .saturating_add(Weight::from_ref_time(17_641_181).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: Contracts Nonce (r:1 w:1) + /// Proof: Contracts Nonce (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 20]`. fn seal_instantiation_nonce(r: u32, ) -> Weight { - // Minimum execution time: 293_819 nanoseconds. - Weight::from_ref_time(302_765_659) - // Standard Error: 28_518 - .saturating_add(Weight::from_ref_time(9_325_552).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(7)) - .saturating_add(T::DbWeight::get().writes(4)) + // Proof Size summary in bytes: + // Measured: `840 + r * (240 ±0)` + // Estimated: `0` + // Minimum execution time: 285_077 nanoseconds. + Weight::from_ref_time(289_980_475) + // Standard Error: 14_535 + .saturating_add(Weight::from_ref_time(9_295_346).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(7_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64const(r: u32, ) -> Weight { - // Minimum execution time: 805 nanoseconds. - Weight::from_ref_time(1_002_066) - // Standard Error: 609 - .saturating_add(Weight::from_ref_time(346_608).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 777 nanoseconds. + Weight::from_ref_time(1_014_498) + // Standard Error: 154 + .saturating_add(Weight::from_ref_time(405_551).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64load(r: u32, ) -> Weight { - // Minimum execution time: 917 nanoseconds. - Weight::from_ref_time(1_247_710) - // Standard Error: 1_069 - .saturating_add(Weight::from_ref_time(984_608).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 862 nanoseconds. + Weight::from_ref_time(1_345_826) + // Standard Error: 457 + .saturating_add(Weight::from_ref_time(1_033_909).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64store(r: u32, ) -> Weight { - // Minimum execution time: 917 nanoseconds. - Weight::from_ref_time(1_244_315) - // Standard Error: 524 - .saturating_add(Weight::from_ref_time(882_167).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 892 nanoseconds. + Weight::from_ref_time(1_233_601) + // Standard Error: 341 + .saturating_add(Weight::from_ref_time(885_275).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_select(r: u32, ) -> Weight { - // Minimum execution time: 791 nanoseconds. - Weight::from_ref_time(1_119_053) - // Standard Error: 379 - .saturating_add(Weight::from_ref_time(956_169).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 771 nanoseconds. + Weight::from_ref_time(1_099_906) + // Standard Error: 261 + .saturating_add(Weight::from_ref_time(1_092_031).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_if(r: u32, ) -> Weight { - // Minimum execution time: 782 nanoseconds. - Weight::from_ref_time(773_373) - // Standard Error: 463 - .saturating_add(Weight::from_ref_time(1_299_306).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 785 nanoseconds. + Weight::from_ref_time(929_328) + // Standard Error: 333 + .saturating_add(Weight::from_ref_time(1_374_749).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_br(r: u32, ) -> Weight { - // Minimum execution time: 743 nanoseconds. - Weight::from_ref_time(1_273_896) - // Standard Error: 925 - .saturating_add(Weight::from_ref_time(527_015).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 772 nanoseconds. + Weight::from_ref_time(979_702) + // Standard Error: 351 + .saturating_add(Weight::from_ref_time(621_385).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_br_if(r: u32, ) -> Weight { - // Minimum execution time: 761 nanoseconds. - Weight::from_ref_time(929_565) - // Standard Error: 1_275 - .saturating_add(Weight::from_ref_time(805_592).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 766 nanoseconds. + Weight::from_ref_time(1_303_783) + // Standard Error: 1_556 + .saturating_add(Weight::from_ref_time(841_842).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_br_table(r: u32, ) -> Weight { - // Minimum execution time: 813 nanoseconds. - Weight::from_ref_time(703_802) - // Standard Error: 1_665 - .saturating_add(Weight::from_ref_time(1_074_321).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 792 nanoseconds. + Weight::from_ref_time(1_093_901) + // Standard Error: 1_383 + .saturating_add(Weight::from_ref_time(1_145_435).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_347 nanoseconds. - Weight::from_ref_time(2_752_638) - // Standard Error: 69 - .saturating_add(Weight::from_ref_time(4_771).saturating_mul(e.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_526 nanoseconds. + Weight::from_ref_time(2_872_561) + // Standard Error: 60 + .saturating_add(Weight::from_ref_time(4_365).saturating_mul(e.into())) } /// The range of component `r` is `[0, 50]`. fn instr_call(r: u32, ) -> Weight { - // Minimum execution time: 826 nanoseconds. - Weight::from_ref_time(1_784_596) - // Standard Error: 1_646 - .saturating_add(Weight::from_ref_time(2_189_993).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 834 nanoseconds. + Weight::from_ref_time(1_431_876) + // Standard Error: 1_448 + .saturating_add(Weight::from_ref_time(2_268_715).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_call_indirect(r: u32, ) -> Weight { - // Minimum execution time: 926 nanoseconds. - Weight::from_ref_time(1_898_358) - // Standard Error: 2_678 - .saturating_add(Weight::from_ref_time(2_811_379).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 920 nanoseconds. + Weight::from_ref_time(2_167_004) + // Standard Error: 2_060 + .saturating_add(Weight::from_ref_time(2_921_443).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_428 nanoseconds. - Weight::from_ref_time(5_257_445) - // Standard Error: 306 - .saturating_add(Weight::from_ref_time(178_882).saturating_mul(p.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 4_624 nanoseconds. + Weight::from_ref_time(5_534_325) + // Standard Error: 326 + .saturating_add(Weight::from_ref_time(184_307).saturating_mul(p.into())) } /// The range of component `l` is `[0, 1024]`. fn instr_call_per_local(l: u32, ) -> Weight { - // Minimum execution time: 2_945 nanoseconds. - Weight::from_ref_time(4_240_619) - // Standard Error: 39 - .saturating_add(Weight::from_ref_time(46_640).saturating_mul(l.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_062 nanoseconds. + Weight::from_ref_time(4_432_879) + // Standard Error: 64 + .saturating_add(Weight::from_ref_time(46_196).saturating_mul(l.into())) } /// The range of component `r` is `[0, 50]`. fn instr_local_get(r: u32, ) -> Weight { - // Minimum execution time: 2_204 nanoseconds. - Weight::from_ref_time(2_430_272) - // Standard Error: 270 - .saturating_add(Weight::from_ref_time(365_718).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_036 nanoseconds. + Weight::from_ref_time(2_318_877) + // Standard Error: 172 + .saturating_add(Weight::from_ref_time(500_498).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_local_set(r: u32, ) -> Weight { - // Minimum execution time: 2_117 nanoseconds. - Weight::from_ref_time(2_429_354) - // Standard Error: 240 - .saturating_add(Weight::from_ref_time(381_830).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_027 nanoseconds. + Weight::from_ref_time(2_355_900) + // Standard Error: 220 + .saturating_add(Weight::from_ref_time(461_393).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_local_tee(r: u32, ) -> Weight { - // Minimum execution time: 2_123 nanoseconds. - Weight::from_ref_time(2_460_016) - // Standard Error: 262 - .saturating_add(Weight::from_ref_time(526_554).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_038 nanoseconds. + Weight::from_ref_time(2_350_330) + // Standard Error: 224 + .saturating_add(Weight::from_ref_time(586_808).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_global_get(r: u32, ) -> Weight { - // Minimum execution time: 892 nanoseconds. - Weight::from_ref_time(1_234_618) - // Standard Error: 485 - .saturating_add(Weight::from_ref_time(813_721).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 897 nanoseconds. + Weight::from_ref_time(1_267_115) + // Standard Error: 189 + .saturating_add(Weight::from_ref_time(884_926).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_global_set(r: u32, ) -> Weight { - // Minimum execution time: 901 nanoseconds. - Weight::from_ref_time(1_182_838) - // Standard Error: 482 - .saturating_add(Weight::from_ref_time(831_308).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 892 nanoseconds. + Weight::from_ref_time(1_202_122) + // Standard Error: 286 + .saturating_add(Weight::from_ref_time(885_157).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_memory_current(r: u32, ) -> Weight { - // Minimum execution time: 929 nanoseconds. - Weight::from_ref_time(1_221_388) - // Standard Error: 434 - .saturating_add(Weight::from_ref_time(693_301).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 852 nanoseconds. + Weight::from_ref_time(1_132_479) + // Standard Error: 224 + .saturating_add(Weight::from_ref_time(719_603).saturating_mul(r.into())) } /// The range of component `r` is `[0, 1]`. fn instr_memory_grow(r: u32, ) -> Weight { - // Minimum execution time: 808 nanoseconds. - Weight::from_ref_time(906_944) - // Standard Error: 6_164 - .saturating_add(Weight::from_ref_time(187_445_255).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 786 nanoseconds. + Weight::from_ref_time(874_044) + // Standard Error: 91_309 + .saturating_add(Weight::from_ref_time(181_849_955).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64clz(r: u32, ) -> Weight { - // Minimum execution time: 807 nanoseconds. - Weight::from_ref_time(1_064_776) - // Standard Error: 287 - .saturating_add(Weight::from_ref_time(507_278).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 763 nanoseconds. + Weight::from_ref_time(1_055_236) + // Standard Error: 207 + .saturating_add(Weight::from_ref_time(554_985).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ctz(r: u32, ) -> Weight { - // Minimum execution time: 776 nanoseconds. - Weight::from_ref_time(1_033_205) - // Standard Error: 443 - .saturating_add(Weight::from_ref_time(512_445).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 756 nanoseconds. + Weight::from_ref_time(1_053_050) + // Standard Error: 165 + .saturating_add(Weight::from_ref_time(555_401).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64popcnt(r: u32, ) -> Weight { - // Minimum execution time: 909 nanoseconds. - Weight::from_ref_time(1_089_083) - // Standard Error: 335 - .saturating_add(Weight::from_ref_time(510_392).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 791 nanoseconds. + Weight::from_ref_time(1_080_240) + // Standard Error: 164 + .saturating_add(Weight::from_ref_time(554_698).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64eqz(r: u32, ) -> Weight { - // Minimum execution time: 791 nanoseconds. - Weight::from_ref_time(1_063_118) - // Standard Error: 210 - .saturating_add(Weight::from_ref_time(522_817).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 766 nanoseconds. + Weight::from_ref_time(1_074_739) + // Standard Error: 178 + .saturating_add(Weight::from_ref_time(565_891).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendsi32(r: u32, ) -> Weight { - // Minimum execution time: 789 nanoseconds. - Weight::from_ref_time(1_056_006) - // Standard Error: 240 - .saturating_add(Weight::from_ref_time(505_198).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 781 nanoseconds. + Weight::from_ref_time(1_077_122) + // Standard Error: 177 + .saturating_add(Weight::from_ref_time(548_846).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendui32(r: u32, ) -> Weight { - // Minimum execution time: 804 nanoseconds. - Weight::from_ref_time(1_087_882) - // Standard Error: 234 - .saturating_add(Weight::from_ref_time(503_830).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 793 nanoseconds. + Weight::from_ref_time(1_086_278) + // Standard Error: 163 + .saturating_add(Weight::from_ref_time(548_765).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i32wrapi64(r: u32, ) -> Weight { - // Minimum execution time: 756 nanoseconds. - Weight::from_ref_time(1_050_994) - // Standard Error: 172 - .saturating_add(Weight::from_ref_time(503_343).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 769 nanoseconds. + Weight::from_ref_time(1_096_044) + // Standard Error: 134 + .saturating_add(Weight::from_ref_time(547_353).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64eq(r: u32, ) -> Weight { - // Minimum execution time: 775 nanoseconds. - Weight::from_ref_time(1_061_228) - // Standard Error: 232 - .saturating_add(Weight::from_ref_time(730_751).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 766 nanoseconds. + Weight::from_ref_time(1_072_610) + // Standard Error: 161 + .saturating_add(Weight::from_ref_time(774_895).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ne(r: u32, ) -> Weight { - // Minimum execution time: 809 nanoseconds. - Weight::from_ref_time(1_080_957) - // Standard Error: 320 - .saturating_add(Weight::from_ref_time(732_246).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 751 nanoseconds. + Weight::from_ref_time(1_038_676) + // Standard Error: 158 + .saturating_add(Weight::from_ref_time(775_194).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64lts(r: u32, ) -> Weight { - // Minimum execution time: 808 nanoseconds. - Weight::from_ref_time(1_055_752) - // Standard Error: 496 - .saturating_add(Weight::from_ref_time(740_084).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 798 nanoseconds. + Weight::from_ref_time(1_089_712) + // Standard Error: 144 + .saturating_add(Weight::from_ref_time(774_377).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ltu(r: u32, ) -> Weight { - // Minimum execution time: 792 nanoseconds. - Weight::from_ref_time(1_111_972) - // Standard Error: 270 - .saturating_add(Weight::from_ref_time(741_581).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 758 nanoseconds. + Weight::from_ref_time(1_078_460) + // Standard Error: 180 + .saturating_add(Weight::from_ref_time(779_861).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64gts(r: u32, ) -> Weight { - // Minimum execution time: 862 nanoseconds. - Weight::from_ref_time(1_111_246) - // Standard Error: 263 - .saturating_add(Weight::from_ref_time(746_026).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 758 nanoseconds. + Weight::from_ref_time(1_089_007) + // Standard Error: 164 + .saturating_add(Weight::from_ref_time(779_372).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64gtu(r: u32, ) -> Weight { - // Minimum execution time: 810 nanoseconds. - Weight::from_ref_time(1_094_933) - // Standard Error: 271 - .saturating_add(Weight::from_ref_time(743_645).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 772 nanoseconds. + Weight::from_ref_time(1_077_512) + // Standard Error: 165 + .saturating_add(Weight::from_ref_time(779_513).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64les(r: u32, ) -> Weight { - // Minimum execution time: 769 nanoseconds. - Weight::from_ref_time(819_933) - // Standard Error: 4_528 - .saturating_add(Weight::from_ref_time(751_599).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 760 nanoseconds. + Weight::from_ref_time(1_078_546) + // Standard Error: 168 + .saturating_add(Weight::from_ref_time(779_138).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64leu(r: u32, ) -> Weight { - // Minimum execution time: 797 nanoseconds. - Weight::from_ref_time(1_107_352) - // Standard Error: 344 - .saturating_add(Weight::from_ref_time(738_684).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 757 nanoseconds. + Weight::from_ref_time(1_080_251) + // Standard Error: 168 + .saturating_add(Weight::from_ref_time(779_391).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ges(r: u32, ) -> Weight { - // Minimum execution time: 784 nanoseconds. - Weight::from_ref_time(1_068_487) - // Standard Error: 3_796 - .saturating_add(Weight::from_ref_time(741_207).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 786 nanoseconds. + Weight::from_ref_time(1_072_690) + // Standard Error: 219 + .saturating_add(Weight::from_ref_time(780_381).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64geu(r: u32, ) -> Weight { - // Minimum execution time: 813 nanoseconds. - Weight::from_ref_time(1_067_278) - // Standard Error: 459 - .saturating_add(Weight::from_ref_time(737_841).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 771 nanoseconds. + Weight::from_ref_time(1_063_735) + // Standard Error: 162 + .saturating_add(Weight::from_ref_time(779_906).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64add(r: u32, ) -> Weight { - // Minimum execution time: 798 nanoseconds. - Weight::from_ref_time(1_100_254) - // Standard Error: 297 - .saturating_add(Weight::from_ref_time(717_622).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 785 nanoseconds. + Weight::from_ref_time(1_059_585) + // Standard Error: 155 + .saturating_add(Weight::from_ref_time(756_828).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64sub(r: u32, ) -> Weight { - // Minimum execution time: 778 nanoseconds. - Weight::from_ref_time(1_063_748) - // Standard Error: 378 - .saturating_add(Weight::from_ref_time(713_577).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 800 nanoseconds. + Weight::from_ref_time(1_066_659) + // Standard Error: 154 + .saturating_add(Weight::from_ref_time(754_318).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64mul(r: u32, ) -> Weight { - // Minimum execution time: 780 nanoseconds. - Weight::from_ref_time(1_088_755) - // Standard Error: 316 - .saturating_add(Weight::from_ref_time(714_127).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 769 nanoseconds. + Weight::from_ref_time(1_078_854) + // Standard Error: 172 + .saturating_add(Weight::from_ref_time(754_183).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64divs(r: u32, ) -> Weight { - // Minimum execution time: 776 nanoseconds. - Weight::from_ref_time(1_062_591) - // Standard Error: 610 - .saturating_add(Weight::from_ref_time(1_355_430).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 770 nanoseconds. + Weight::from_ref_time(1_057_476) + // Standard Error: 191 + .saturating_add(Weight::from_ref_time(1_443_902).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64divu(r: u32, ) -> Weight { - // Minimum execution time: 801 nanoseconds. - Weight::from_ref_time(1_092_395) - // Standard Error: 423 - .saturating_add(Weight::from_ref_time(1_282_356).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 764 nanoseconds. + Weight::from_ref_time(1_063_821) + // Standard Error: 193 + .saturating_add(Weight::from_ref_time(1_324_496).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64rems(r: u32, ) -> Weight { - // Minimum execution time: 822 nanoseconds. - Weight::from_ref_time(1_083_079) - // Standard Error: 562 - .saturating_add(Weight::from_ref_time(1_398_522).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 747 nanoseconds. + Weight::from_ref_time(1_093_209) + // Standard Error: 270 + .saturating_add(Weight::from_ref_time(1_447_180).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64remu(r: u32, ) -> Weight { - // Minimum execution time: 798 nanoseconds. - Weight::from_ref_time(1_088_997) - // Standard Error: 401 - .saturating_add(Weight::from_ref_time(1_283_442).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 805 nanoseconds. + Weight::from_ref_time(1_033_953) + // Standard Error: 152 + .saturating_add(Weight::from_ref_time(1_336_911).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64and(r: u32, ) -> Weight { - // Minimum execution time: 815 nanoseconds. - Weight::from_ref_time(1_081_903) - // Standard Error: 264 - .saturating_add(Weight::from_ref_time(718_069).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 766 nanoseconds. + Weight::from_ref_time(1_059_430) + // Standard Error: 160 + .saturating_add(Weight::from_ref_time(757_265).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64or(r: u32, ) -> Weight { - // Minimum execution time: 813 nanoseconds. - Weight::from_ref_time(1_091_426) - // Standard Error: 296 - .saturating_add(Weight::from_ref_time(717_894).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 760 nanoseconds. + Weight::from_ref_time(1_077_376) + // Standard Error: 160 + .saturating_add(Weight::from_ref_time(755_800).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64xor(r: u32, ) -> Weight { - // Minimum execution time: 794 nanoseconds. - Weight::from_ref_time(1_040_144) - // Standard Error: 400 - .saturating_add(Weight::from_ref_time(719_886).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 798 nanoseconds. + Weight::from_ref_time(1_070_570) + // Standard Error: 157 + .saturating_add(Weight::from_ref_time(756_839).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64shl(r: u32, ) -> Weight { - // Minimum execution time: 774 nanoseconds. - Weight::from_ref_time(1_092_466) - // Standard Error: 4_173 - .saturating_add(Weight::from_ref_time(739_873).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 761 nanoseconds. + Weight::from_ref_time(1_074_645) + // Standard Error: 169 + .saturating_add(Weight::from_ref_time(771_486).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64shrs(r: u32, ) -> Weight { - // Minimum execution time: 793 nanoseconds. - Weight::from_ref_time(1_105_611) - // Standard Error: 394 - .saturating_add(Weight::from_ref_time(735_358).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 779 nanoseconds. + Weight::from_ref_time(1_107_671) + // Standard Error: 185 + .saturating_add(Weight::from_ref_time(769_168).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64shru(r: u32, ) -> Weight { - // Minimum execution time: 805 nanoseconds. - Weight::from_ref_time(1_130_462) - // Standard Error: 327 - .saturating_add(Weight::from_ref_time(734_198).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 755 nanoseconds. + Weight::from_ref_time(1_075_769) + // Standard Error: 164 + .saturating_add(Weight::from_ref_time(770_334).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotl(r: u32, ) -> Weight { - // Minimum execution time: 831 nanoseconds. - Weight::from_ref_time(1_118_894) - // Standard Error: 389 - .saturating_add(Weight::from_ref_time(733_834).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 767 nanoseconds. + Weight::from_ref_time(608_749) + // Standard Error: 2_059 + .saturating_add(Weight::from_ref_time(804_228).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotr(r: u32, ) -> Weight { - // Minimum execution time: 772 nanoseconds. - Weight::from_ref_time(1_123_733) - // Standard Error: 337 - .saturating_add(Weight::from_ref_time(733_923).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 779 nanoseconds. + Weight::from_ref_time(1_054_998) + // Standard Error: 191 + .saturating_add(Weight::from_ref_time(770_225).saturating_mul(r.into())) } } // For backwards compatibility and tests impl WeightInfo for () { - // Storage: Contracts DeletionQueue (r:1 w:0) + /// Storage: Contracts DeletionQueue (r:1 w:0) + /// Proof: Contracts DeletionQueue (max_values: Some(1), max_size: Some(16642), added: 17137, mode: Ignored) fn on_process_deletion_queue_batch() -> Weight { - // Minimum execution time: 3_326 nanoseconds. - Weight::from_ref_time(3_433_000) - .saturating_add(RocksDbWeight::get().reads(1)) - } - // Storage: Skipped Metadata (r:0 w:0) + // Proof Size summary in bytes: + // Measured: `109` + // Estimated: `0` + // Minimum execution time: 2_305 nanoseconds. + Weight::from_ref_time(2_560_000) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + } + /// Storage: Skipped Metadata (r:0 w:0) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Ignored) /// The range of component `k` is `[0, 1024]`. fn on_initialize_per_trie_key(k: u32, ) -> Weight { - // Minimum execution time: 15_703 nanoseconds. - Weight::from_ref_time(15_288_927) - // Standard Error: 951 - .saturating_add(Weight::from_ref_time(940_816).saturating_mul(k.into())) - .saturating_add(RocksDbWeight::get().reads(1)) - .saturating_add(RocksDbWeight::get().writes(1)) + // Proof Size summary in bytes: + // Measured: `481 + k * (69 ±0)` + // Estimated: `0` + // Minimum execution time: 9_311 nanoseconds. + Weight::from_ref_time(5_419_288) + // Standard Error: 562 + .saturating_add(Weight::from_ref_time(911_962).saturating_mul(k.into())) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(k.into()))) } - // Storage: Contracts DeletionQueue (r:1 w:0) + /// Storage: Contracts DeletionQueue (r:1 w:1) + /// Proof: Contracts DeletionQueue (max_values: Some(1), max_size: Some(16642), added: 17137, mode: Ignored) /// The range of component `q` is `[0, 128]`. fn on_initialize_per_queue_item(q: u32, ) -> Weight { - // Minimum execution time: 3_548 nanoseconds. - Weight::from_ref_time(15_764_121) - // Standard Error: 3_339 - .saturating_add(Weight::from_ref_time(1_214_890).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]`. + // Proof Size summary in bytes: + // Measured: `281 + q * (33 ±0)` + // Estimated: `0` + // Minimum execution time: 2_288 nanoseconds. + Weight::from_ref_time(9_442_437) + // Standard Error: 2_720 + .saturating_add(Weight::from_ref_time(1_076_950).saturating_mul(q.into())) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Contracts PristineCode (r:1 w:0) + /// Proof: Contracts PristineCode (max_values: None, max_size: Some(125988), added: 128463, mode: Ignored) + /// Storage: Contracts CodeStorage (r:0 w:1) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// The range of component `c` is `[0, 61717]`. fn reinstrument(c: u32, ) -> Weight { - // Minimum execution time: 29_801 nanoseconds. - Weight::from_ref_time(27_932_706) - // Standard Error: 49 - .saturating_add(Weight::from_ref_time(50_532).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) - // 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]`. + // Proof Size summary in bytes: + // Measured: `270 + c * (1 ±0)` + // Estimated: `0` + // Minimum execution time: 27_539 nanoseconds. + Weight::from_ref_time(23_554_889) + // Standard Error: 56 + .saturating_add(Weight::from_ref_time(46_766).saturating_mul(c.into())) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// The range of component `c` is `[0, 125952]`. fn call_with_code_per_byte(c: u32, ) -> Weight { - // Minimum execution time: 307_894 nanoseconds. - Weight::from_ref_time(322_346_319) - // Standard Error: 25 - .saturating_add(Weight::from_ref_time(30_678).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) - // 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]`. + // Proof Size summary in bytes: + // Measured: `771` + // Estimated: `0` + // Minimum execution time: 297_710 nanoseconds. + Weight::from_ref_time(307_327_529) + // Standard Error: 18 + .saturating_add(Weight::from_ref_time(29_849).saturating_mul(c.into())) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + } + /// Storage: Contracts CodeStorage (r:1 w:1) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Contracts Nonce (r:1 w:1) + /// Proof: Contracts Nonce (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: System EventTopics (r:3 w:3) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Storage: Contracts PristineCode (r:0 w:1) + /// Proof: Contracts PristineCode (max_values: None, max_size: Some(125988), added: 128463, mode: Ignored) + /// Storage: Contracts OwnerInfoOf (r:0 w:1) + /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Ignored) + /// The range of component `c` is `[0, 61717]`. /// The range of component `i` is `[0, 1048576]`. /// The range of component `s` is `[0, 1048576]`. fn instantiate_with_code(c: u32, i: u32, s: u32, ) -> Weight { - // Minimum execution time: 3_610_424 nanoseconds. - Weight::from_ref_time(583_426_386) - // Standard Error: 277 - .saturating_add(Weight::from_ref_time(90_224).saturating_mul(c.into())) + // Proof Size summary in bytes: + // Measured: `257` + // Estimated: `0` + // Minimum execution time: 3_586_223 nanoseconds. + Weight::from_ref_time(561_614_281) + // Standard Error: 274 + .saturating_add(Weight::from_ref_time(87_557).saturating_mul(c.into())) // Standard Error: 16 - .saturating_add(Weight::from_ref_time(1_325).saturating_mul(i.into())) + .saturating_add(Weight::from_ref_time(1_307).saturating_mul(i.into())) // Standard Error: 16 - .saturating_add(Weight::from_ref_time(1_727).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) - // 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) - // Storage: System EventTopics (r:2 w:2) + .saturating_add(Weight::from_ref_time(1_721).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(8_u64)) + .saturating_add(RocksDbWeight::get().writes(9_u64)) + } + /// Storage: Contracts CodeStorage (r:1 w:1) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Contracts Nonce (r:1 w:1) + /// Proof: Contracts Nonce (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts OwnerInfoOf (r:1 w:1) + /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `i` is `[0, 1048576]`. /// The range of component `s` is `[0, 1048576]`. fn instantiate(i: u32, s: u32, ) -> Weight { - // Minimum execution time: 1_892_996 nanoseconds. - Weight::from_ref_time(202_958_196) + // Proof Size summary in bytes: + // Measured: `533` + // Estimated: `0` + // Minimum execution time: 1_885_437 nanoseconds. + Weight::from_ref_time(199_943_867) // Standard Error: 8 - .saturating_add(Weight::from_ref_time(1_627).saturating_mul(i.into())) + .saturating_add(Weight::from_ref_time(1_611).saturating_mul(i.into())) // Standard Error: 8 - .saturating_add(Weight::from_ref_time(1_755).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) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System Account (r:1 w:1) - // Storage: System EventTopics (r:2 w:2) + .saturating_add(Weight::from_ref_time(1_737).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(8_u64)) + .saturating_add(RocksDbWeight::get().writes(7_u64)) + } + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) fn call() -> Weight { - // Minimum execution time: 157_347 nanoseconds. - Weight::from_ref_time(159_084_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) - // Storage: Contracts PristineCode (r:0 w:1) - // Storage: Contracts OwnerInfoOf (r:0 w:1) - /// The range of component `c` is `[0, 64226]`. + // Proof Size summary in bytes: + // Measured: `823` + // Estimated: `0` + // Minimum execution time: 150_604 nanoseconds. + Weight::from_ref_time(151_777_000) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + } + /// Storage: Contracts CodeStorage (r:1 w:1) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: System EventTopics (r:1 w:1) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Storage: Contracts PristineCode (r:0 w:1) + /// Proof: Contracts PristineCode (max_values: None, max_size: Some(125988), added: 128463, mode: Ignored) + /// Storage: Contracts OwnerInfoOf (r:0 w:1) + /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Ignored) + /// The range of component `c` is `[0, 61717]`. fn upload_code(c: u32, ) -> Weight { - // Minimum execution time: 299_987 nanoseconds. - Weight::from_ref_time(305_274_879) - // Standard Error: 72 - .saturating_add(Weight::from_ref_time(91_916).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) + // Proof Size summary in bytes: + // Measured: `109` + // Estimated: `0` + // Minimum execution time: 295_505 nanoseconds. + Weight::from_ref_time(305_609_098) + // Standard Error: 58 + .saturating_add(Weight::from_ref_time(88_676).saturating_mul(c.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + } + /// Storage: Contracts OwnerInfoOf (r:1 w:1) + /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Ignored) + /// Storage: System EventTopics (r:1 w:1) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Storage: Contracts CodeStorage (r:0 w:1) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Contracts PristineCode (r:0 w:1) + /// Proof: Contracts PristineCode (max_values: None, max_size: Some(125988), added: 128463, mode: Ignored) fn remove_code() -> Weight { - // Minimum execution time: 40_795 nanoseconds. - Weight::from_ref_time(41_297_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) + // Proof Size summary in bytes: + // Measured: `287` + // Estimated: `0` + // Minimum execution time: 25_949 nanoseconds. + Weight::from_ref_time(26_316_000) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + } + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts OwnerInfoOf (r:2 w:2) + /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Ignored) + /// Storage: System EventTopics (r:3 w:3) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) fn set_code() -> Weight { - // Minimum execution time: 41_957 nanoseconds. - Weight::from_ref_time(42_536_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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `634` + // Estimated: `0` + // Minimum execution time: 29_005 nanoseconds. + Weight::from_ref_time(29_370_000) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(6_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 20]`. fn seal_caller(r: u32, ) -> Weight { - // Minimum execution time: 293_544 nanoseconds. - Weight::from_ref_time(298_981_222) - // Standard Error: 39_139 - .saturating_add(Weight::from_ref_time(17_278_436).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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `845 + r * (480 ±0)` + // Estimated: `0` + // Minimum execution time: 281_880 nanoseconds. + Weight::from_ref_time(289_637_700) + // Standard Error: 22_662 + .saturating_add(Weight::from_ref_time(16_866_274).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1601 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 20]`. fn seal_is_contract(r: u32, ) -> Weight { - // Minimum execution time: 293_500 nanoseconds. - Weight::from_ref_time(237_825_284) - // Standard Error: 450_234 - .saturating_add(Weight::from_ref_time(198_995_806).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(6)) + // Proof Size summary in bytes: + // Measured: `882 + r * (19218 ±0)` + // Estimated: `0` + // Minimum execution time: 285_590 nanoseconds. + Weight::from_ref_time(231_277_523) + // Standard Error: 425_084 + .saturating_add(Weight::from_ref_time(192_985_377).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6_u64)) .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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1601 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 20]`. fn seal_code_hash(r: u32, ) -> Weight { - // Minimum execution time: 295_851 nanoseconds. - Weight::from_ref_time(258_113_447) - // Standard Error: 408_747 - .saturating_add(Weight::from_ref_time(237_490_216).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(6)) + // Proof Size summary in bytes: + // Measured: `889 + r * (19539 ±0)` + // Estimated: `0` + // Minimum execution time: 282_966 nanoseconds. + Weight::from_ref_time(236_127_328) + // Standard Error: 405_193 + .saturating_add(Weight::from_ref_time(235_541_377).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6_u64)) .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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 20]`. fn seal_own_code_hash(r: u32, ) -> Weight { - // Minimum execution time: 294_614 nanoseconds. - Weight::from_ref_time(301_528_998) - // Standard Error: 40_613 - .saturating_add(Weight::from_ref_time(20_815_088).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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `852 + r * (480 ±0)` + // Estimated: `0` + // Minimum execution time: 286_021 nanoseconds. + Weight::from_ref_time(290_200_599) + // Standard Error: 19_224 + .saturating_add(Weight::from_ref_time(20_692_099).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 20]`. fn seal_caller_is_origin(r: u32, ) -> Weight { - // Minimum execution time: 293_088 nanoseconds. - Weight::from_ref_time(299_120_595) - // Standard Error: 23_277 - .saturating_add(Weight::from_ref_time(11_130_334).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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `842 + r * (240 ±0)` + // Estimated: `0` + // Minimum execution time: 284_175 nanoseconds. + Weight::from_ref_time(286_665_694) + // Standard Error: 14_104 + .saturating_add(Weight::from_ref_time(11_196_944).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 20]`. fn seal_address(r: u32, ) -> Weight { - // Minimum execution time: 295_110 nanoseconds. - Weight::from_ref_time(305_295_787) - // Standard Error: 48_521 - .saturating_add(Weight::from_ref_time(16_610_806).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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `846 + r * (480 ±0)` + // Estimated: `0` + // Minimum execution time: 285_315 nanoseconds. + Weight::from_ref_time(289_734_189) + // Standard Error: 15_980 + .saturating_add(Weight::from_ref_time(16_940_657).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 20]`. fn seal_gas_left(r: u32, ) -> Weight { - // Minimum execution time: 293_414 nanoseconds. - Weight::from_ref_time(299_960_283) - // Standard Error: 32_003 - .saturating_add(Weight::from_ref_time(16_652_433).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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `847 + r * (480 ±0)` + // Estimated: `0` + // Minimum execution time: 285_708 nanoseconds. + Weight::from_ref_time(289_872_393) + // Standard Error: 16_551 + .saturating_add(Weight::from_ref_time(16_672_944).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:2 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 20]`. fn seal_balance(r: u32, ) -> Weight { - // Minimum execution time: 292_429 nanoseconds. - Weight::from_ref_time(301_025_128) - // Standard Error: 92_155 - .saturating_add(Weight::from_ref_time(92_731_719).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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `1017 + r * (480 ±0)` + // Estimated: `0` + // Minimum execution time: 285_698 nanoseconds. + Weight::from_ref_time(295_636_093) + // Standard Error: 97_582 + .saturating_add(Weight::from_ref_time(92_891_252).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(7_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 20]`. fn seal_value_transferred(r: u32, ) -> Weight { - // Minimum execution time: 293_516 nanoseconds. - Weight::from_ref_time(300_071_428) - // Standard Error: 25_871 - .saturating_add(Weight::from_ref_time(16_599_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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `856 + r * (480 ±0)` + // Estimated: `0` + // Minimum execution time: 282_057 nanoseconds. + Weight::from_ref_time(289_304_621) + // Standard Error: 17_818 + .saturating_add(Weight::from_ref_time(16_725_632).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 20]`. fn seal_minimum_balance(r: u32, ) -> Weight { - // Minimum execution time: 293_666 nanoseconds. - Weight::from_ref_time(299_803_599) - // Standard Error: 24_508 - .saturating_add(Weight::from_ref_time(16_500_973).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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `854 + r * (480 ±0)` + // Estimated: `0` + // Minimum execution time: 282_478 nanoseconds. + Weight::from_ref_time(289_682_366) + // Standard Error: 20_379 + .saturating_add(Weight::from_ref_time(16_517_079).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 20]`. fn seal_block_number(r: u32, ) -> Weight { - // Minimum execution time: 289_193 nanoseconds. - Weight::from_ref_time(297_946_784) - // Standard Error: 43_719 - .saturating_add(Weight::from_ref_time(16_442_254).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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `851 + r * (480 ±0)` + // Estimated: `0` + // Minimum execution time: 283_826 nanoseconds. + Weight::from_ref_time(289_935_300) + // Standard Error: 15_180 + .saturating_add(Weight::from_ref_time(16_268_515).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 20]`. fn seal_now(r: u32, ) -> Weight { - // Minimum execution time: 288_897 nanoseconds. - Weight::from_ref_time(298_856_658) - // Standard Error: 31_003 - .saturating_add(Weight::from_ref_time(16_490_508).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) - // 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) + // Proof Size summary in bytes: + // Measured: `842 + r * (480 ±0)` + // Estimated: `0` + // Minimum execution time: 285_455 nanoseconds. + Weight::from_ref_time(289_682_526) + // Standard Error: 18_667 + .saturating_add(Weight::from_ref_time(16_502_025).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) + /// Proof: TransactionPayment NextFeeMultiplier (max_values: Some(1), max_size: Some(16), added: 511, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 20]`. fn seal_weight_to_fee(r: u32, ) -> Weight { - // Minimum execution time: 289_850 nanoseconds. - Weight::from_ref_time(302_898_449) - // Standard Error: 92_822 - .saturating_add(Weight::from_ref_time(86_376_874).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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `919 + r * (800 ±0)` + // Estimated: `0` + // Minimum execution time: 286_106 nanoseconds. + Weight::from_ref_time(294_493_680) + // Standard Error: 76_469 + .saturating_add(Weight::from_ref_time(87_055_837).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(7_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 20]`. fn seal_gas(r: u32, ) -> Weight { - // Minimum execution time: 145_105 nanoseconds. - Weight::from_ref_time(152_388_934) - // Standard Error: 29_988 - .saturating_add(Weight::from_ref_time(7_761_947).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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `809 + r * (320 ±0)` + // Estimated: `0` + // Minimum execution time: 137_877 nanoseconds. + Weight::from_ref_time(141_863_027) + // Standard Error: 10_200 + .saturating_add(Weight::from_ref_time(7_925_232).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 20]`. fn seal_input(r: u32, ) -> Weight { - // Minimum execution time: 289_319 nanoseconds. - Weight::from_ref_time(298_390_911) - // Standard Error: 27_329 - .saturating_add(Weight::from_ref_time(14_225_527).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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `844 + r * (480 ±0)` + // Estimated: `0` + // Minimum execution time: 282_034 nanoseconds. + Weight::from_ref_time(289_388_799) + // Standard Error: 21_999 + .saturating_add(Weight::from_ref_time(15_039_420).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `n` is `[0, 1024]`. fn seal_input_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 305_538 nanoseconds. - Weight::from_ref_time(339_734_596) - // Standard Error: 4_636 - .saturating_add(Weight::from_ref_time(9_592_149).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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `1324` + // Estimated: `0` + // Minimum execution time: 303_229 nanoseconds. + Weight::from_ref_time(321_863_704) + // Standard Error: 2_754 + .saturating_add(Weight::from_ref_time(9_545_103).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 1]`. fn seal_return(r: u32, ) -> Weight { - // Minimum execution time: 287_189 nanoseconds. - Weight::from_ref_time(295_472_383) - // Standard Error: 314_142 - .saturating_add(Weight::from_ref_time(214_016).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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `832 + r * (45 ±0)` + // Estimated: `0` + // Minimum execution time: 278_824 nanoseconds. + Weight::from_ref_time(285_019_861) + // Standard Error: 101_646 + .saturating_add(Weight::from_ref_time(1_757_938).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `n` is `[0, 1024]`. fn seal_return_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 289_380 nanoseconds. - Weight::from_ref_time(296_302_404) - // Standard Error: 889 - .saturating_add(Weight::from_ref_time(190_017).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) - // 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) + // Proof Size summary in bytes: + // Measured: `842` + // Estimated: `0` + // Minimum execution time: 286_316 nanoseconds. + Weight::from_ref_time(287_206_936) + // Standard Error: 589 + .saturating_add(Weight::from_ref_time(186_684).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:3 w:3) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: Contracts DeletionQueue (r:1 w:1) + /// Proof: Contracts DeletionQueue (max_values: Some(1), max_size: Some(16642), added: 17137, mode: Ignored) + /// Storage: Contracts OwnerInfoOf (r:1 w:1) + /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Ignored) + /// Storage: System EventTopics (r:3 w:3) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 1]`. fn seal_terminate(r: u32, ) -> Weight { - // Minimum execution time: 292_383 nanoseconds. - Weight::from_ref_time(297_557_691) - // Standard Error: 251_228 - .saturating_add(Weight::from_ref_time(56_688_008).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(6)) + // Proof Size summary in bytes: + // Measured: `874 + r * (280 ±0)` + // Estimated: `0` + // Minimum execution time: 282_428 nanoseconds. + Weight::from_ref_time(287_101_148) + // Standard Error: 145_605 + .saturating_add(Weight::from_ref_time(58_079_551).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(r.into()))) - .saturating_add(RocksDbWeight::get().writes(3)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) .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) - // 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) + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) + /// Proof: RandomnessCollectiveFlip RandomMaterial (max_values: Some(1), max_size: Some(2594), added: 3089, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 20]`. fn seal_random(r: u32, ) -> Weight { - // Minimum execution time: 293_019 nanoseconds. - Weight::from_ref_time(301_747_439) - // Standard Error: 92_043 - .saturating_add(Weight::from_ref_time(109_861_144).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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `889 + r * (800 ±0)` + // Estimated: `0` + // Minimum execution time: 281_516 nanoseconds. + Weight::from_ref_time(292_759_183) + // Standard Error: 152_698 + .saturating_add(Weight::from_ref_time(112_729_555).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(7_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 20]`. fn seal_deposit_event(r: u32, ) -> Weight { - // Minimum execution time: 287_586 nanoseconds. - Weight::from_ref_time(304_751_302) - // Standard Error: 127_698 - .saturating_add(Weight::from_ref_time(221_525_053).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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `842 + r * (800 ±0)` + // Estimated: `0` + // Minimum execution time: 280_100 nanoseconds. + Weight::from_ref_time(299_862_082) + // Standard Error: 95_658 + .saturating_add(Weight::from_ref_time(234_211_246).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:322 w:322) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// 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_182_204 nanoseconds. - Weight::from_ref_time(508_607_957) - // Standard Error: 503_533 - .saturating_add(Weight::from_ref_time(173_998_655).saturating_mul(t.into())) - // Standard Error: 138_294 - .saturating_add(Weight::from_ref_time(67_991_373).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(6)) + // Proof Size summary in bytes: + // Measured: `1778 + t * (2608 ±0) + n * (8 ±0)` + // Estimated: `0` + // Minimum execution time: 1_197_721 nanoseconds. + Weight::from_ref_time(508_692_255) + // Standard Error: 538_596 + .saturating_add(Weight::from_ref_time(174_792_656).saturating_mul(t.into())) + // Standard Error: 147_924 + .saturating_add(Weight::from_ref_time(67_443_118).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(t.into()))) - .saturating_add(RocksDbWeight::get().writes(3)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) .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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 20]`. fn seal_debug_message(r: u32, ) -> Weight { - // Minimum execution time: 157_706 nanoseconds. - Weight::from_ref_time(161_895_583) - // Standard Error: 14_952 - .saturating_add(Weight::from_ref_time(12_990_237).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(6)) - .saturating_add(RocksDbWeight::get().writes(3)) - } - // Storage: Skipped Metadata (r:0 w:0) + // Proof Size summary in bytes: + // Measured: `841 + r * (800 ±0)` + // Estimated: `0` + // Minimum execution time: 149_687 nanoseconds. + Weight::from_ref_time(153_589_818) + // Standard Error: 13_361 + .saturating_add(Weight::from_ref_time(13_379_131).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: Skipped Metadata (r:0 w:0) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 10]`. fn seal_set_storage(r: u32, ) -> Weight { - // Minimum execution time: 290_063 nanoseconds. - Weight::from_ref_time(256_404_853) - // Standard Error: 436_195 - .saturating_add(Weight::from_ref_time(406_569_743).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(6)) + // Proof Size summary in bytes: + // Measured: `883 + r * (23417 ±0)` + // Estimated: `0` + // Minimum execution time: 281_920 nanoseconds. + Weight::from_ref_time(242_057_723) + // Standard Error: 464_911 + .saturating_add(Weight::from_ref_time(404_673_309).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) - .saturating_add(RocksDbWeight::get().writes(3)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((80_u64).saturating_mul(r.into()))) } - // Storage: Skipped Metadata (r:0 w:0) + /// Storage: Skipped Metadata (r:0 w:0) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Ignored) /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_new_kb(n: u32, ) -> Weight { - // Minimum execution time: 426_295 nanoseconds. - Weight::from_ref_time(582_989_911) - // Standard Error: 1_404_141 - .saturating_add(Weight::from_ref_time(89_545_963).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(52)) + // Proof Size summary in bytes: + // Measured: `12583 + n * (11969 ±0)` + // Estimated: `0` + // Minimum execution time: 423_923 nanoseconds. + Weight::from_ref_time(573_806_626) + // Standard Error: 1_371_107 + .saturating_add(Weight::from_ref_time(85_963_445).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(52_u64)) .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(n.into()))) - .saturating_add(RocksDbWeight::get().writes(50)) + .saturating_add(RocksDbWeight::get().writes(50_u64)) .saturating_add(RocksDbWeight::get().writes((7_u64).saturating_mul(n.into()))) } - // Storage: Skipped Metadata (r:0 w:0) + /// Storage: Skipped Metadata (r:0 w:0) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Ignored) /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_old_kb(n: u32, ) -> Weight { - // Minimum execution time: 425_062 nanoseconds. - Weight::from_ref_time(552_380_900) - // Standard Error: 1_140_169 - .saturating_add(Weight::from_ref_time(64_085_108).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(51)) + // Proof Size summary in bytes: + // Measured: `15138 + n * (175775 ±0)` + // Estimated: `0` + // Minimum execution time: 424_048 nanoseconds. + Weight::from_ref_time(542_298_050) + // Standard Error: 1_092_010 + .saturating_add(Weight::from_ref_time(60_111_206).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(51_u64)) .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(n.into()))) - .saturating_add(RocksDbWeight::get().writes(49)) + .saturating_add(RocksDbWeight::get().writes(49_u64)) .saturating_add(RocksDbWeight::get().writes((7_u64).saturating_mul(n.into()))) } - // Storage: Skipped Metadata (r:0 w:0) + /// Storage: Skipped Metadata (r:0 w:0) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 10]`. fn seal_clear_storage(r: u32, ) -> Weight { - // Minimum execution time: 294_421 nanoseconds. - Weight::from_ref_time(260_897_072) - // Standard Error: 474_135 - .saturating_add(Weight::from_ref_time(403_191_862).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(6)) + // Proof Size summary in bytes: + // Measured: `876 + r * (23098 ±0)` + // Estimated: `0` + // Minimum execution time: 285_714 nanoseconds. + Weight::from_ref_time(245_068_941) + // Standard Error: 417_796 + .saturating_add(Weight::from_ref_time(394_288_572).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) - .saturating_add(RocksDbWeight::get().writes(3)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((80_u64).saturating_mul(r.into()))) } - // Storage: Skipped Metadata (r:0 w:0) + /// Storage: Skipped Metadata (r:0 w:0) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Ignored) /// The range of component `n` is `[0, 8]`. fn seal_clear_storage_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 391_743 nanoseconds. - Weight::from_ref_time(535_327_545) - // Standard Error: 1_297_157 - .saturating_add(Weight::from_ref_time(67_222_981).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(51)) + // Proof Size summary in bytes: + // Measured: `14863 + n * (175768 ±0)` + // Estimated: `0` + // Minimum execution time: 385_278 nanoseconds. + Weight::from_ref_time(522_656_525) + // Standard Error: 1_259_587 + .saturating_add(Weight::from_ref_time(62_799_142).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(51_u64)) .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(n.into()))) - .saturating_add(RocksDbWeight::get().writes(48)) + .saturating_add(RocksDbWeight::get().writes(48_u64)) .saturating_add(RocksDbWeight::get().writes((7_u64).saturating_mul(n.into()))) } - // Storage: Skipped Metadata (r:0 w:0) + /// Storage: Skipped Metadata (r:0 w:0) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 10]`. fn seal_get_storage(r: u32, ) -> Weight { - // Minimum execution time: 294_947 nanoseconds. - Weight::from_ref_time(266_280_887) - // Standard Error: 382_477 - .saturating_add(Weight::from_ref_time(323_306_898).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(6)) + // Proof Size summary in bytes: + // Measured: `878 + r * (23740 ±0)` + // Estimated: `0` + // Minimum execution time: 282_513 nanoseconds. + Weight::from_ref_time(256_242_753) + // Standard Error: 362_571 + .saturating_add(Weight::from_ref_time(317_951_687).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) - .saturating_add(RocksDbWeight::get().writes(3)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) } - // Storage: Skipped Metadata (r:0 w:0) + /// Storage: Skipped Metadata (r:0 w:0) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Ignored) /// The range of component `n` is `[0, 8]`. fn seal_get_storage_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 375_487 nanoseconds. - Weight::from_ref_time(497_019_365) - // Standard Error: 1_141_672 - .saturating_add(Weight::from_ref_time(152_354_482).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(51)) + // Proof Size summary in bytes: + // Measured: `15469 + n * (175775 ±0)` + // Estimated: `0` + // Minimum execution time: 370_576 nanoseconds. + Weight::from_ref_time(487_764_999) + // Standard Error: 1_073_165 + .saturating_add(Weight::from_ref_time(147_588_190).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(51_u64)) .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(n.into()))) - .saturating_add(RocksDbWeight::get().writes(3)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) } - // Storage: Skipped Metadata (r:0 w:0) + /// Storage: Skipped Metadata (r:0 w:0) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 10]`. fn seal_contains_storage(r: u32, ) -> Weight { - // Minimum execution time: 294_716 nanoseconds. - Weight::from_ref_time(266_187_186) - // Standard Error: 395_323 - .saturating_add(Weight::from_ref_time(309_907_221).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(6)) + // Proof Size summary in bytes: + // Measured: `871 + r * (23100 ±0)` + // Estimated: `0` + // Minimum execution time: 285_917 nanoseconds. + Weight::from_ref_time(259_066_807) + // Standard Error: 340_183 + .saturating_add(Weight::from_ref_time(306_291_698).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) - .saturating_add(RocksDbWeight::get().writes(3)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) } - // Storage: Skipped Metadata (r:0 w:0) + /// Storage: Skipped Metadata (r:0 w:0) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Ignored) /// The range of component `n` is `[0, 8]`. fn seal_contains_storage_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 371_667 nanoseconds. - Weight::from_ref_time(478_075_482) - // Standard Error: 979_116 - .saturating_add(Weight::from_ref_time(62_075_707).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(51)) + // Proof Size summary in bytes: + // Measured: `14814 + n * (175782 ±0)` + // Estimated: `0` + // Minimum execution time: 366_225 nanoseconds. + Weight::from_ref_time(470_470_223) + // Standard Error: 953_976 + .saturating_add(Weight::from_ref_time(57_748_742).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(51_u64)) .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(n.into()))) - .saturating_add(RocksDbWeight::get().writes(3)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) } - // Storage: Skipped Metadata (r:0 w:0) + /// Storage: Skipped Metadata (r:0 w:0) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 10]`. fn seal_take_storage(r: u32, ) -> Weight { - // Minimum execution time: 292_147 nanoseconds. - Weight::from_ref_time(254_374_598) - // Standard Error: 442_367 - .saturating_add(Weight::from_ref_time(413_674_705).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(6)) + // Proof Size summary in bytes: + // Measured: `879 + r * (23740 ±0)` + // Estimated: `0` + // Minimum execution time: 286_867 nanoseconds. + Weight::from_ref_time(244_403_664) + // Standard Error: 435_431 + .saturating_add(Weight::from_ref_time(409_282_991).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) - .saturating_add(RocksDbWeight::get().writes(3)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((80_u64).saturating_mul(r.into()))) } - // Storage: Skipped Metadata (r:0 w:0) + /// Storage: Skipped Metadata (r:0 w:0) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Ignored) /// The range of component `n` is `[0, 8]`. fn seal_take_storage_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 398_554 nanoseconds. - Weight::from_ref_time(553_715_911) - // Standard Error: 1_415_272 - .saturating_add(Weight::from_ref_time(158_254_544).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(51)) + // Proof Size summary in bytes: + // Measured: `15470 + n * (175775 ±0)` + // Estimated: `0` + // Minimum execution time: 393_392 nanoseconds. + Weight::from_ref_time(540_938_487) + // Standard Error: 1_361_411 + .saturating_add(Weight::from_ref_time(153_456_560).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(51_u64)) .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(n.into()))) - .saturating_add(RocksDbWeight::get().writes(48)) + .saturating_add(RocksDbWeight::get().writes(48_u64)) .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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + /// Storage: System Account (r:1602 w:1601) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 20]`. fn seal_transfer(r: u32, ) -> Weight { - // Minimum execution time: 295_081 nanoseconds. - Weight::from_ref_time(253_461_581) - // Standard Error: 740_198 - .saturating_add(Weight::from_ref_time(1_369_153_623).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(7)) + // Proof Size summary in bytes: + // Measured: `1393 + r * (3602 ±0)` + // Estimated: `0` + // Minimum execution time: 286_766 nanoseconds. + Weight::from_ref_time(221_458_774) + // Standard Error: 714_182 + .saturating_add(Weight::from_ref_time(1_402_610_222).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) - .saturating_add(RocksDbWeight::get().writes(4)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) .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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1601 w:1601) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:2 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:1602 w:1602) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 20]`. fn seal_call(r: u32, ) -> Weight { - // Minimum execution time: 296_089 nanoseconds. - Weight::from_ref_time(297_193_000) - // Standard Error: 6_571_547 - .saturating_add(Weight::from_ref_time(21_080_280_397).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(7)) + // Proof Size summary in bytes: + // Measured: `1551 + r * (20511 ±0)` + // Estimated: `0` + // Minimum execution time: 287_158 nanoseconds. + Weight::from_ref_time(288_377_000) + // Standard Error: 6_108_706 + .saturating_add(Weight::from_ref_time(21_691_098_517).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().reads((160_u64).saturating_mul(r.into()))) - .saturating_add(RocksDbWeight::get().writes(3)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) .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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1536 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:1537 w:1537) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 20]`. fn seal_delegate_call(r: u32, ) -> Weight { - // Minimum execution time: 296_828 nanoseconds. - Weight::from_ref_time(297_685_000) - // Standard Error: 6_864_880 - .saturating_add(Weight::from_ref_time(20_770_321_946).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(6)) + // Proof Size summary in bytes: + // Measured: `0 + r * (71670 ±0)` + // Estimated: `0` + // Minimum execution time: 287_380 nanoseconds. + Weight::from_ref_time(288_241_000) + // Standard Error: 7_007_658 + .saturating_add(Weight::from_ref_time(21_428_850_764).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((150_u64).saturating_mul(r.into()))) - .saturating_add(RocksDbWeight::get().writes(3)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) .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) - // Storage: Contracts CodeStorage (r:2 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:82 w:82) + /// Storage: System Account (r:82 w:81) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:81 w:81) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:2 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:82 w:82) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// 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_824_671 nanoseconds. - Weight::from_ref_time(8_713_861_450) - // Standard Error: 7_388_925 - .saturating_add(Weight::from_ref_time(1_327_819_806).saturating_mul(t.into())) - // Standard Error: 11_079 - .saturating_add(Weight::from_ref_time(9_789_514).saturating_mul(c.into())) - .saturating_add(RocksDbWeight::get().reads(167)) + // Proof Size summary in bytes: + // Measured: `21611 + t * (15369 ±0)` + // Estimated: `0` + // Minimum execution time: 10_644_986 nanoseconds. + Weight::from_ref_time(9_596_635_640) + // Standard Error: 6_393_384 + .saturating_add(Weight::from_ref_time(1_304_764_528).saturating_mul(t.into())) + // Standard Error: 9_586 + .saturating_add(Weight::from_ref_time(9_663_819).saturating_mul(c.into())) + .saturating_add(RocksDbWeight::get().reads(167_u64)) .saturating_add(RocksDbWeight::get().reads((81_u64).saturating_mul(t.into()))) - .saturating_add(RocksDbWeight::get().writes(163)) + .saturating_add(RocksDbWeight::get().writes(163_u64)) .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) - // 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) + /// Storage: System Account (r:1602 w:1602) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1601 w:1601) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1601 w:1600) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: Contracts Nonce (r:1 w:1) + /// Proof: Contracts Nonce (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: Contracts OwnerInfoOf (r:1600 w:1600) + /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Ignored) + /// Storage: System EventTopics (r:1602 w:1602) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 20]`. fn seal_instantiate(r: u32, ) -> Weight { - // Minimum execution time: 293_374 nanoseconds. - Weight::from_ref_time(302_067_000) - // Standard Error: 20_137_097 - .saturating_add(Weight::from_ref_time(26_444_812_817).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(8)) + // Proof Size summary in bytes: + // Measured: `1613 + r * (25576 ±0)` + // Estimated: `0` + // Minimum execution time: 284_948 nanoseconds. + Weight::from_ref_time(289_276_000) + // Standard Error: 18_674_951 + .saturating_add(Weight::from_ref_time(27_090_355_673).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().reads((400_u64).saturating_mul(r.into()))) - .saturating_add(RocksDbWeight::get().writes(5)) + .saturating_add(RocksDbWeight::get().writes(5_u64)) .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) - // 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) - // Storage: System EventTopics (r:82 w:82) + /// Storage: System Account (r:82 w:82) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:81 w:81) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:2 w:1) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: Contracts Nonce (r:1 w:1) + /// Proof: Contracts Nonce (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: Contracts OwnerInfoOf (r:1 w:1) + /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Ignored) + /// Storage: System EventTopics (r:82 w:82) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `t` is `[0, 1]`. /// The range of component `i` is `[0, 960]`. /// The range of component `s` is `[0, 960]`. fn seal_instantiate_per_transfer_input_salt_kb(t: u32, i: u32, s: u32, ) -> Weight { - // Minimum execution time: 126_456_770 nanoseconds. - Weight::from_ref_time(9_223_715_752) - // Standard Error: 96_040_318 - .saturating_add(Weight::from_ref_time(19_550_519).saturating_mul(t.into())) - // Standard Error: 156_614 - .saturating_add(Weight::from_ref_time(122_958_298).saturating_mul(i.into())) - // Standard Error: 156_614 - .saturating_add(Weight::from_ref_time(123_316_079).saturating_mul(s.into())) - .saturating_add(RocksDbWeight::get().reads(249)) + // Proof Size summary in bytes: + // Measured: `5666 + t * (17 ±0)` + // Estimated: `0` + // Minimum execution time: 127_857_642 nanoseconds. + Weight::from_ref_time(11_399_054_049) + // Standard Error: 95_033_651 + .saturating_add(Weight::from_ref_time(434_246_236).saturating_mul(t.into())) + // Standard Error: 154_973 + .saturating_add(Weight::from_ref_time(121_130_672).saturating_mul(i.into())) + // Standard Error: 154_973 + .saturating_add(Weight::from_ref_time(121_554_853).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(249_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(t.into()))) - .saturating_add(RocksDbWeight::get().writes(247)) + .saturating_add(RocksDbWeight::get().writes(247_u64)) .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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 1]`. fn seal_hash_sha2_256(r: u32, ) -> Weight { - // Minimum execution time: 289_275 nanoseconds. - Weight::from_ref_time(297_803_961) - // Standard Error: 303_405 - .saturating_add(Weight::from_ref_time(40_800_138).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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `839 + r * (642 ±0)` + // Estimated: `0` + // Minimum execution time: 280_949 nanoseconds. + Weight::from_ref_time(286_538_475) + // Standard Error: 124_866 + .saturating_add(Weight::from_ref_time(42_531_824).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `n` is `[0, 1024]`. fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 336_077 nanoseconds. - Weight::from_ref_time(336_846_000) - // Standard Error: 51_610 - .saturating_add(Weight::from_ref_time(322_208_787).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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `1641` + // Estimated: `0` + // Minimum execution time: 328_414 nanoseconds. + Weight::from_ref_time(329_293_000) + // Standard Error: 50_816 + .saturating_add(Weight::from_ref_time(318_312_506).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 1]`. fn seal_hash_keccak_256(r: u32, ) -> Weight { - // Minimum execution time: 290_189 nanoseconds. - Weight::from_ref_time(298_454_259) - // Standard Error: 252_946 - .saturating_add(Weight::from_ref_time(55_034_240).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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `841 + r * (642 ±0)` + // Estimated: `0` + // Minimum execution time: 282_208 nanoseconds. + Weight::from_ref_time(286_848_187) + // Standard Error: 106_214 + .saturating_add(Weight::from_ref_time(56_342_512).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `n` is `[0, 1024]`. fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 350_030 nanoseconds. - Weight::from_ref_time(351_356_000) - // Standard Error: 57_422 - .saturating_add(Weight::from_ref_time(256_912_844).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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `1643` + // Estimated: `0` + // Minimum execution time: 342_478 nanoseconds. + Weight::from_ref_time(342_947_000) + // Standard Error: 60_809 + .saturating_add(Weight::from_ref_time(255_492_149).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 1]`. fn seal_hash_blake2_256(r: u32, ) -> Weight { - // Minimum execution time: 288_480 nanoseconds. - Weight::from_ref_time(297_613_263) - // Standard Error: 456_736 - .saturating_add(Weight::from_ref_time(38_100_936).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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `841 + r * (642 ±0)` + // Estimated: `0` + // Minimum execution time: 279_059 nanoseconds. + Weight::from_ref_time(285_413_659) + // Standard Error: 123_081 + .saturating_add(Weight::from_ref_time(33_154_840).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 321_195 nanoseconds. - Weight::from_ref_time(325_561_000) - // Standard Error: 46_289 - .saturating_add(Weight::from_ref_time(99_536_902).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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `1643` + // Estimated: `0` + // Minimum execution time: 317_518 nanoseconds. + Weight::from_ref_time(318_178_000) + // Standard Error: 60_074 + .saturating_add(Weight::from_ref_time(99_403_819).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 1]`. fn seal_hash_blake2_128(r: u32, ) -> Weight { - // Minimum execution time: 287_659 nanoseconds. - Weight::from_ref_time(295_963_340) - // Standard Error: 433_889 - .saturating_add(Weight::from_ref_time(30_251_859).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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `841 + r * (679 ±0)` + // Estimated: `0` + // Minimum execution time: 280_145 nanoseconds. + Weight::from_ref_time(285_483_032) + // Standard Error: 106_113 + .saturating_add(Weight::from_ref_time(33_475_067).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - // Minimum execution time: 324_298 nanoseconds. - Weight::from_ref_time(325_738_000) - // Standard Error: 48_563 - .saturating_add(Weight::from_ref_time(99_479_838).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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `1643` + // Estimated: `0` + // Minimum execution time: 318_141 nanoseconds. + Weight::from_ref_time(318_699_000) + // Standard Error: 55_136 + .saturating_add(Weight::from_ref_time(99_275_434).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 1]`. fn seal_ecdsa_recover(r: u32, ) -> Weight { - // Minimum execution time: 294_257 nanoseconds. - Weight::from_ref_time(299_467_620) - // Standard Error: 589_749 - .saturating_add(Weight::from_ref_time(3_015_389_579).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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `885 + r * (6083 ±0)` + // Estimated: `0` + // Minimum execution time: 282_474 nanoseconds. + Weight::from_ref_time(288_078_802) + // Standard Error: 302_968 + .saturating_add(Weight::from_ref_time(2_944_967_597).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 1]`. fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight { - // Minimum execution time: 289_480 nanoseconds. - Weight::from_ref_time(298_762_412) - // Standard Error: 397_004 - .saturating_add(Weight::from_ref_time(743_937_087).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) - // 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) + // Proof Size summary in bytes: + // Measured: `854 + r * (3362 ±0)` + // Estimated: `0` + // Minimum execution time: 281_514 nanoseconds. + Weight::from_ref_time(287_458_651) + // Standard Error: 146_715 + .saturating_add(Weight::from_ref_time(731_367_948).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1536 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: Contracts OwnerInfoOf (r:1536 w:1536) + /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Ignored) + /// Storage: System EventTopics (r:1538 w:1538) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 20]`. fn seal_set_code_hash(r: u32, ) -> Weight { - // Minimum execution time: 293_494 nanoseconds. - Weight::from_ref_time(297_756_000) - // Standard Error: 2_731_227 - .saturating_add(Weight::from_ref_time(1_387_380_436).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(6)) + // Proof Size summary in bytes: + // Measured: `0 + r * (79300 ±0)` + // Estimated: `0` + // Minimum execution time: 282_591 nanoseconds. + Weight::from_ref_time(286_842_000) + // Standard Error: 2_645_254 + .saturating_add(Weight::from_ref_time(1_394_535_676).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((225_u64).saturating_mul(r.into()))) - .saturating_add(RocksDbWeight::get().writes(3)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) .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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 20]`. fn seal_reentrance_count(r: u32, ) -> Weight { - // Minimum execution time: 295_339 nanoseconds. - Weight::from_ref_time(301_577_907) - // Standard Error: 23_836 - .saturating_add(Weight::from_ref_time(10_876_508).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) - // Storage: Contracts CodeStorage (r:1 w:0) - // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `837 + r * (240 ±0)` + // Estimated: `0` + // Minimum execution time: 286_631 nanoseconds. + Weight::from_ref_time(288_787_650) + // Standard Error: 29_802 + .saturating_add(Weight::from_ref_time(11_115_811).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 20]`. fn seal_account_reentrance_count(r: u32, ) -> Weight { - // Minimum execution time: 297_096 nanoseconds. - Weight::from_ref_time(336_319_823) - // Standard Error: 128_941 - .saturating_add(Weight::from_ref_time(25_211_374).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) - // 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) + // Proof Size summary in bytes: + // Measured: `2056 + r * (3153 ±0)` + // Estimated: `0` + // Minimum execution time: 287_775 nanoseconds. + Weight::from_ref_time(319_806_123) + // Standard Error: 111_808 + .saturating_add(Weight::from_ref_time(17_641_181).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: Contracts Nonce (r:1 w:1) + /// Proof: Contracts Nonce (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) /// The range of component `r` is `[0, 20]`. fn seal_instantiation_nonce(r: u32, ) -> Weight { - // Minimum execution time: 293_819 nanoseconds. - Weight::from_ref_time(302_765_659) - // Standard Error: 28_518 - .saturating_add(Weight::from_ref_time(9_325_552).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(7)) - .saturating_add(RocksDbWeight::get().writes(4)) + // Proof Size summary in bytes: + // Measured: `840 + r * (240 ±0)` + // Estimated: `0` + // Minimum execution time: 285_077 nanoseconds. + Weight::from_ref_time(289_980_475) + // Standard Error: 14_535 + .saturating_add(Weight::from_ref_time(9_295_346).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(7_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64const(r: u32, ) -> Weight { - // Minimum execution time: 805 nanoseconds. - Weight::from_ref_time(1_002_066) - // Standard Error: 609 - .saturating_add(Weight::from_ref_time(346_608).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 777 nanoseconds. + Weight::from_ref_time(1_014_498) + // Standard Error: 154 + .saturating_add(Weight::from_ref_time(405_551).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64load(r: u32, ) -> Weight { - // Minimum execution time: 917 nanoseconds. - Weight::from_ref_time(1_247_710) - // Standard Error: 1_069 - .saturating_add(Weight::from_ref_time(984_608).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 862 nanoseconds. + Weight::from_ref_time(1_345_826) + // Standard Error: 457 + .saturating_add(Weight::from_ref_time(1_033_909).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64store(r: u32, ) -> Weight { - // Minimum execution time: 917 nanoseconds. - Weight::from_ref_time(1_244_315) - // Standard Error: 524 - .saturating_add(Weight::from_ref_time(882_167).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 892 nanoseconds. + Weight::from_ref_time(1_233_601) + // Standard Error: 341 + .saturating_add(Weight::from_ref_time(885_275).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_select(r: u32, ) -> Weight { - // Minimum execution time: 791 nanoseconds. - Weight::from_ref_time(1_119_053) - // Standard Error: 379 - .saturating_add(Weight::from_ref_time(956_169).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 771 nanoseconds. + Weight::from_ref_time(1_099_906) + // Standard Error: 261 + .saturating_add(Weight::from_ref_time(1_092_031).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_if(r: u32, ) -> Weight { - // Minimum execution time: 782 nanoseconds. - Weight::from_ref_time(773_373) - // Standard Error: 463 - .saturating_add(Weight::from_ref_time(1_299_306).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 785 nanoseconds. + Weight::from_ref_time(929_328) + // Standard Error: 333 + .saturating_add(Weight::from_ref_time(1_374_749).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_br(r: u32, ) -> Weight { - // Minimum execution time: 743 nanoseconds. - Weight::from_ref_time(1_273_896) - // Standard Error: 925 - .saturating_add(Weight::from_ref_time(527_015).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 772 nanoseconds. + Weight::from_ref_time(979_702) + // Standard Error: 351 + .saturating_add(Weight::from_ref_time(621_385).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_br_if(r: u32, ) -> Weight { - // Minimum execution time: 761 nanoseconds. - Weight::from_ref_time(929_565) - // Standard Error: 1_275 - .saturating_add(Weight::from_ref_time(805_592).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 766 nanoseconds. + Weight::from_ref_time(1_303_783) + // Standard Error: 1_556 + .saturating_add(Weight::from_ref_time(841_842).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_br_table(r: u32, ) -> Weight { - // Minimum execution time: 813 nanoseconds. - Weight::from_ref_time(703_802) - // Standard Error: 1_665 - .saturating_add(Weight::from_ref_time(1_074_321).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 792 nanoseconds. + Weight::from_ref_time(1_093_901) + // Standard Error: 1_383 + .saturating_add(Weight::from_ref_time(1_145_435).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_347 nanoseconds. - Weight::from_ref_time(2_752_638) - // Standard Error: 69 - .saturating_add(Weight::from_ref_time(4_771).saturating_mul(e.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_526 nanoseconds. + Weight::from_ref_time(2_872_561) + // Standard Error: 60 + .saturating_add(Weight::from_ref_time(4_365).saturating_mul(e.into())) } /// The range of component `r` is `[0, 50]`. fn instr_call(r: u32, ) -> Weight { - // Minimum execution time: 826 nanoseconds. - Weight::from_ref_time(1_784_596) - // Standard Error: 1_646 - .saturating_add(Weight::from_ref_time(2_189_993).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 834 nanoseconds. + Weight::from_ref_time(1_431_876) + // Standard Error: 1_448 + .saturating_add(Weight::from_ref_time(2_268_715).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_call_indirect(r: u32, ) -> Weight { - // Minimum execution time: 926 nanoseconds. - Weight::from_ref_time(1_898_358) - // Standard Error: 2_678 - .saturating_add(Weight::from_ref_time(2_811_379).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 920 nanoseconds. + Weight::from_ref_time(2_167_004) + // Standard Error: 2_060 + .saturating_add(Weight::from_ref_time(2_921_443).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_428 nanoseconds. - Weight::from_ref_time(5_257_445) - // Standard Error: 306 - .saturating_add(Weight::from_ref_time(178_882).saturating_mul(p.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 4_624 nanoseconds. + Weight::from_ref_time(5_534_325) + // Standard Error: 326 + .saturating_add(Weight::from_ref_time(184_307).saturating_mul(p.into())) } /// The range of component `l` is `[0, 1024]`. fn instr_call_per_local(l: u32, ) -> Weight { - // Minimum execution time: 2_945 nanoseconds. - Weight::from_ref_time(4_240_619) - // Standard Error: 39 - .saturating_add(Weight::from_ref_time(46_640).saturating_mul(l.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_062 nanoseconds. + Weight::from_ref_time(4_432_879) + // Standard Error: 64 + .saturating_add(Weight::from_ref_time(46_196).saturating_mul(l.into())) } /// The range of component `r` is `[0, 50]`. fn instr_local_get(r: u32, ) -> Weight { - // Minimum execution time: 2_204 nanoseconds. - Weight::from_ref_time(2_430_272) - // Standard Error: 270 - .saturating_add(Weight::from_ref_time(365_718).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_036 nanoseconds. + Weight::from_ref_time(2_318_877) + // Standard Error: 172 + .saturating_add(Weight::from_ref_time(500_498).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_local_set(r: u32, ) -> Weight { - // Minimum execution time: 2_117 nanoseconds. - Weight::from_ref_time(2_429_354) - // Standard Error: 240 - .saturating_add(Weight::from_ref_time(381_830).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_027 nanoseconds. + Weight::from_ref_time(2_355_900) + // Standard Error: 220 + .saturating_add(Weight::from_ref_time(461_393).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_local_tee(r: u32, ) -> Weight { - // Minimum execution time: 2_123 nanoseconds. - Weight::from_ref_time(2_460_016) - // Standard Error: 262 - .saturating_add(Weight::from_ref_time(526_554).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_038 nanoseconds. + Weight::from_ref_time(2_350_330) + // Standard Error: 224 + .saturating_add(Weight::from_ref_time(586_808).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_global_get(r: u32, ) -> Weight { - // Minimum execution time: 892 nanoseconds. - Weight::from_ref_time(1_234_618) - // Standard Error: 485 - .saturating_add(Weight::from_ref_time(813_721).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 897 nanoseconds. + Weight::from_ref_time(1_267_115) + // Standard Error: 189 + .saturating_add(Weight::from_ref_time(884_926).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_global_set(r: u32, ) -> Weight { - // Minimum execution time: 901 nanoseconds. - Weight::from_ref_time(1_182_838) - // Standard Error: 482 - .saturating_add(Weight::from_ref_time(831_308).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 892 nanoseconds. + Weight::from_ref_time(1_202_122) + // Standard Error: 286 + .saturating_add(Weight::from_ref_time(885_157).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_memory_current(r: u32, ) -> Weight { - // Minimum execution time: 929 nanoseconds. - Weight::from_ref_time(1_221_388) - // Standard Error: 434 - .saturating_add(Weight::from_ref_time(693_301).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 852 nanoseconds. + Weight::from_ref_time(1_132_479) + // Standard Error: 224 + .saturating_add(Weight::from_ref_time(719_603).saturating_mul(r.into())) } /// The range of component `r` is `[0, 1]`. fn instr_memory_grow(r: u32, ) -> Weight { - // Minimum execution time: 808 nanoseconds. - Weight::from_ref_time(906_944) - // Standard Error: 6_164 - .saturating_add(Weight::from_ref_time(187_445_255).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 786 nanoseconds. + Weight::from_ref_time(874_044) + // Standard Error: 91_309 + .saturating_add(Weight::from_ref_time(181_849_955).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64clz(r: u32, ) -> Weight { - // Minimum execution time: 807 nanoseconds. - Weight::from_ref_time(1_064_776) - // Standard Error: 287 - .saturating_add(Weight::from_ref_time(507_278).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 763 nanoseconds. + Weight::from_ref_time(1_055_236) + // Standard Error: 207 + .saturating_add(Weight::from_ref_time(554_985).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ctz(r: u32, ) -> Weight { - // Minimum execution time: 776 nanoseconds. - Weight::from_ref_time(1_033_205) - // Standard Error: 443 - .saturating_add(Weight::from_ref_time(512_445).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 756 nanoseconds. + Weight::from_ref_time(1_053_050) + // Standard Error: 165 + .saturating_add(Weight::from_ref_time(555_401).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64popcnt(r: u32, ) -> Weight { - // Minimum execution time: 909 nanoseconds. - Weight::from_ref_time(1_089_083) - // Standard Error: 335 - .saturating_add(Weight::from_ref_time(510_392).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 791 nanoseconds. + Weight::from_ref_time(1_080_240) + // Standard Error: 164 + .saturating_add(Weight::from_ref_time(554_698).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64eqz(r: u32, ) -> Weight { - // Minimum execution time: 791 nanoseconds. - Weight::from_ref_time(1_063_118) - // Standard Error: 210 - .saturating_add(Weight::from_ref_time(522_817).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 766 nanoseconds. + Weight::from_ref_time(1_074_739) + // Standard Error: 178 + .saturating_add(Weight::from_ref_time(565_891).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendsi32(r: u32, ) -> Weight { - // Minimum execution time: 789 nanoseconds. - Weight::from_ref_time(1_056_006) - // Standard Error: 240 - .saturating_add(Weight::from_ref_time(505_198).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 781 nanoseconds. + Weight::from_ref_time(1_077_122) + // Standard Error: 177 + .saturating_add(Weight::from_ref_time(548_846).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendui32(r: u32, ) -> Weight { - // Minimum execution time: 804 nanoseconds. - Weight::from_ref_time(1_087_882) - // Standard Error: 234 - .saturating_add(Weight::from_ref_time(503_830).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 793 nanoseconds. + Weight::from_ref_time(1_086_278) + // Standard Error: 163 + .saturating_add(Weight::from_ref_time(548_765).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i32wrapi64(r: u32, ) -> Weight { - // Minimum execution time: 756 nanoseconds. - Weight::from_ref_time(1_050_994) - // Standard Error: 172 - .saturating_add(Weight::from_ref_time(503_343).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 769 nanoseconds. + Weight::from_ref_time(1_096_044) + // Standard Error: 134 + .saturating_add(Weight::from_ref_time(547_353).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64eq(r: u32, ) -> Weight { - // Minimum execution time: 775 nanoseconds. - Weight::from_ref_time(1_061_228) - // Standard Error: 232 - .saturating_add(Weight::from_ref_time(730_751).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 766 nanoseconds. + Weight::from_ref_time(1_072_610) + // Standard Error: 161 + .saturating_add(Weight::from_ref_time(774_895).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ne(r: u32, ) -> Weight { - // Minimum execution time: 809 nanoseconds. - Weight::from_ref_time(1_080_957) - // Standard Error: 320 - .saturating_add(Weight::from_ref_time(732_246).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 751 nanoseconds. + Weight::from_ref_time(1_038_676) + // Standard Error: 158 + .saturating_add(Weight::from_ref_time(775_194).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64lts(r: u32, ) -> Weight { - // Minimum execution time: 808 nanoseconds. - Weight::from_ref_time(1_055_752) - // Standard Error: 496 - .saturating_add(Weight::from_ref_time(740_084).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 798 nanoseconds. + Weight::from_ref_time(1_089_712) + // Standard Error: 144 + .saturating_add(Weight::from_ref_time(774_377).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ltu(r: u32, ) -> Weight { - // Minimum execution time: 792 nanoseconds. - Weight::from_ref_time(1_111_972) - // Standard Error: 270 - .saturating_add(Weight::from_ref_time(741_581).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 758 nanoseconds. + Weight::from_ref_time(1_078_460) + // Standard Error: 180 + .saturating_add(Weight::from_ref_time(779_861).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64gts(r: u32, ) -> Weight { - // Minimum execution time: 862 nanoseconds. - Weight::from_ref_time(1_111_246) - // Standard Error: 263 - .saturating_add(Weight::from_ref_time(746_026).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 758 nanoseconds. + Weight::from_ref_time(1_089_007) + // Standard Error: 164 + .saturating_add(Weight::from_ref_time(779_372).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64gtu(r: u32, ) -> Weight { - // Minimum execution time: 810 nanoseconds. - Weight::from_ref_time(1_094_933) - // Standard Error: 271 - .saturating_add(Weight::from_ref_time(743_645).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 772 nanoseconds. + Weight::from_ref_time(1_077_512) + // Standard Error: 165 + .saturating_add(Weight::from_ref_time(779_513).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64les(r: u32, ) -> Weight { - // Minimum execution time: 769 nanoseconds. - Weight::from_ref_time(819_933) - // Standard Error: 4_528 - .saturating_add(Weight::from_ref_time(751_599).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 760 nanoseconds. + Weight::from_ref_time(1_078_546) + // Standard Error: 168 + .saturating_add(Weight::from_ref_time(779_138).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64leu(r: u32, ) -> Weight { - // Minimum execution time: 797 nanoseconds. - Weight::from_ref_time(1_107_352) - // Standard Error: 344 - .saturating_add(Weight::from_ref_time(738_684).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 757 nanoseconds. + Weight::from_ref_time(1_080_251) + // Standard Error: 168 + .saturating_add(Weight::from_ref_time(779_391).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ges(r: u32, ) -> Weight { - // Minimum execution time: 784 nanoseconds. - Weight::from_ref_time(1_068_487) - // Standard Error: 3_796 - .saturating_add(Weight::from_ref_time(741_207).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 786 nanoseconds. + Weight::from_ref_time(1_072_690) + // Standard Error: 219 + .saturating_add(Weight::from_ref_time(780_381).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64geu(r: u32, ) -> Weight { - // Minimum execution time: 813 nanoseconds. - Weight::from_ref_time(1_067_278) - // Standard Error: 459 - .saturating_add(Weight::from_ref_time(737_841).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 771 nanoseconds. + Weight::from_ref_time(1_063_735) + // Standard Error: 162 + .saturating_add(Weight::from_ref_time(779_906).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64add(r: u32, ) -> Weight { - // Minimum execution time: 798 nanoseconds. - Weight::from_ref_time(1_100_254) - // Standard Error: 297 - .saturating_add(Weight::from_ref_time(717_622).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 785 nanoseconds. + Weight::from_ref_time(1_059_585) + // Standard Error: 155 + .saturating_add(Weight::from_ref_time(756_828).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64sub(r: u32, ) -> Weight { - // Minimum execution time: 778 nanoseconds. - Weight::from_ref_time(1_063_748) - // Standard Error: 378 - .saturating_add(Weight::from_ref_time(713_577).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 800 nanoseconds. + Weight::from_ref_time(1_066_659) + // Standard Error: 154 + .saturating_add(Weight::from_ref_time(754_318).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64mul(r: u32, ) -> Weight { - // Minimum execution time: 780 nanoseconds. - Weight::from_ref_time(1_088_755) - // Standard Error: 316 - .saturating_add(Weight::from_ref_time(714_127).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 769 nanoseconds. + Weight::from_ref_time(1_078_854) + // Standard Error: 172 + .saturating_add(Weight::from_ref_time(754_183).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64divs(r: u32, ) -> Weight { - // Minimum execution time: 776 nanoseconds. - Weight::from_ref_time(1_062_591) - // Standard Error: 610 - .saturating_add(Weight::from_ref_time(1_355_430).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 770 nanoseconds. + Weight::from_ref_time(1_057_476) + // Standard Error: 191 + .saturating_add(Weight::from_ref_time(1_443_902).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64divu(r: u32, ) -> Weight { - // Minimum execution time: 801 nanoseconds. - Weight::from_ref_time(1_092_395) - // Standard Error: 423 - .saturating_add(Weight::from_ref_time(1_282_356).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 764 nanoseconds. + Weight::from_ref_time(1_063_821) + // Standard Error: 193 + .saturating_add(Weight::from_ref_time(1_324_496).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64rems(r: u32, ) -> Weight { - // Minimum execution time: 822 nanoseconds. - Weight::from_ref_time(1_083_079) - // Standard Error: 562 - .saturating_add(Weight::from_ref_time(1_398_522).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 747 nanoseconds. + Weight::from_ref_time(1_093_209) + // Standard Error: 270 + .saturating_add(Weight::from_ref_time(1_447_180).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64remu(r: u32, ) -> Weight { - // Minimum execution time: 798 nanoseconds. - Weight::from_ref_time(1_088_997) - // Standard Error: 401 - .saturating_add(Weight::from_ref_time(1_283_442).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 805 nanoseconds. + Weight::from_ref_time(1_033_953) + // Standard Error: 152 + .saturating_add(Weight::from_ref_time(1_336_911).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64and(r: u32, ) -> Weight { - // Minimum execution time: 815 nanoseconds. - Weight::from_ref_time(1_081_903) - // Standard Error: 264 - .saturating_add(Weight::from_ref_time(718_069).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 766 nanoseconds. + Weight::from_ref_time(1_059_430) + // Standard Error: 160 + .saturating_add(Weight::from_ref_time(757_265).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64or(r: u32, ) -> Weight { - // Minimum execution time: 813 nanoseconds. - Weight::from_ref_time(1_091_426) - // Standard Error: 296 - .saturating_add(Weight::from_ref_time(717_894).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 760 nanoseconds. + Weight::from_ref_time(1_077_376) + // Standard Error: 160 + .saturating_add(Weight::from_ref_time(755_800).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64xor(r: u32, ) -> Weight { - // Minimum execution time: 794 nanoseconds. - Weight::from_ref_time(1_040_144) - // Standard Error: 400 - .saturating_add(Weight::from_ref_time(719_886).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 798 nanoseconds. + Weight::from_ref_time(1_070_570) + // Standard Error: 157 + .saturating_add(Weight::from_ref_time(756_839).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64shl(r: u32, ) -> Weight { - // Minimum execution time: 774 nanoseconds. - Weight::from_ref_time(1_092_466) - // Standard Error: 4_173 - .saturating_add(Weight::from_ref_time(739_873).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 761 nanoseconds. + Weight::from_ref_time(1_074_645) + // Standard Error: 169 + .saturating_add(Weight::from_ref_time(771_486).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64shrs(r: u32, ) -> Weight { - // Minimum execution time: 793 nanoseconds. - Weight::from_ref_time(1_105_611) - // Standard Error: 394 - .saturating_add(Weight::from_ref_time(735_358).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 779 nanoseconds. + Weight::from_ref_time(1_107_671) + // Standard Error: 185 + .saturating_add(Weight::from_ref_time(769_168).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64shru(r: u32, ) -> Weight { - // Minimum execution time: 805 nanoseconds. - Weight::from_ref_time(1_130_462) - // Standard Error: 327 - .saturating_add(Weight::from_ref_time(734_198).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 755 nanoseconds. + Weight::from_ref_time(1_075_769) + // Standard Error: 164 + .saturating_add(Weight::from_ref_time(770_334).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotl(r: u32, ) -> Weight { - // Minimum execution time: 831 nanoseconds. - Weight::from_ref_time(1_118_894) - // Standard Error: 389 - .saturating_add(Weight::from_ref_time(733_834).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 767 nanoseconds. + Weight::from_ref_time(608_749) + // Standard Error: 2_059 + .saturating_add(Weight::from_ref_time(804_228).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotr(r: u32, ) -> Weight { - // Minimum execution time: 772 nanoseconds. - Weight::from_ref_time(1_123_733) - // Standard Error: 337 - .saturating_add(Weight::from_ref_time(733_923).saturating_mul(r.into())) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 779 nanoseconds. + Weight::from_ref_time(1_054_998) + // Standard Error: 191 + .saturating_add(Weight::from_ref_time(770_225).saturating_mul(r.into())) } } diff --git a/frame/conviction-voting/src/weights.rs b/frame/conviction-voting/src/weights.rs index e50842449f88a..c5c7123837755 100644 --- a/frame/conviction-voting/src/weights.rs +++ b/frame/conviction-voting/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2023 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -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-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -59,164 +60,262 @@ pub trait WeightInfo { /// 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) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: ConvictionVoting VotingFor (r:1 w:1) + /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) + /// Storage: ConvictionVoting ClassLocksFor (r:1 w:1) + /// Proof: ConvictionVoting ClassLocksFor (max_values: None, max_size: Some(59), added: 2534, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:2 w:2) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn vote_new() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `13168` + // Estimated: `257859` + // Minimum execution time: 85_569 nanoseconds. + Weight::from_parts(86_492_000, 257859) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(6_u64)) } - // 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) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: ConvictionVoting VotingFor (r:1 w:1) + /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) + /// Storage: ConvictionVoting ClassLocksFor (r:1 w:1) + /// Proof: ConvictionVoting ClassLocksFor (max_values: None, max_size: Some(59), added: 2534, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:2 w:2) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn vote_existing() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `20342` + // Estimated: `257859` + // Minimum execution time: 212_727 nanoseconds. + Weight::from_parts(213_741_000, 257859) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(6_u64)) } - // Storage: ConvictionVoting VotingFor (r:1 w:1) - // Storage: Referenda ReferendumInfoFor (r:1 w:1) - // Storage: Scheduler Agenda (r:2 w:2) + /// Storage: ConvictionVoting VotingFor (r:1 w:1) + /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:2 w:2) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn remove_vote() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `20062` + // Estimated: `251551` + // Minimum execution time: 200_513 nanoseconds. + Weight::from_parts(201_589_000, 251551) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) } - // Storage: ConvictionVoting VotingFor (r:1 w:1) - // Storage: Referenda ReferendumInfoFor (r:1 w:0) + /// Storage: ConvictionVoting VotingFor (r:1 w:1) + /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) + /// Storage: Referenda ReferendumInfoFor (r:1 w:0) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) fn remove_other_vote() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `12738` + // Estimated: `32557` + // Minimum execution time: 43_083 nanoseconds. + Weight::from_parts(43_763_000, 32557) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - // 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) + /// Storage: ConvictionVoting VotingFor (r:2 w:2) + /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:2 w:2) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: ConvictionVoting ClassLocksFor (r:1 w:1) + /// Proof: ConvictionVoting ClassLocksFor (max_values: None, max_size: Some(59), added: 2534, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) /// The range of component `r` is `[0, 1]`. fn delegate(r: u32, ) -> Weight { - // 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)) - .saturating_add(T::DbWeight::get().writes((3 as u64).saturating_mul(r as u64))) + // Proof Size summary in bytes: + // Measured: `272 + r * (1689 ±0)` + // Estimated: `176657 + r * (110917 ±0)` + // Minimum execution time: 33_246 nanoseconds. + Weight::from_parts(34_560_391, 176657) + // Standard Error: 63_925 + .saturating_add(Weight::from_ref_time(34_500_408).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(r.into()))) + .saturating_add(T::DbWeight::get().writes(4_u64)) + .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_proof_size(110917).saturating_mul(r.into())) } - // Storage: ConvictionVoting VotingFor (r:2 w:2) - // Storage: Referenda ReferendumInfoFor (r:1 w:1) - // Storage: Scheduler Agenda (r:2 w:2) + /// Storage: ConvictionVoting VotingFor (r:2 w:2) + /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:2 w:2) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) /// The range of component `r` is `[0, 1]`. fn undelegate(r: u32, ) -> Weight { - // 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)) - .saturating_add(T::DbWeight::get().writes((3 as u64).saturating_mul(r as u64))) + // Proof Size summary in bytes: + // Measured: `470 + r * (1407 ±0)` + // Estimated: `170349 + r * (110917 ±0)` + // Minimum execution time: 20_508 nanoseconds. + Weight::from_parts(21_240_024, 170349) + // Standard Error: 37_314 + .saturating_add(Weight::from_ref_time(30_890_875).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(r.into()))) + .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_proof_size(110917).saturating_mul(r.into())) } - // Storage: ConvictionVoting VotingFor (r:1 w:1) - // Storage: ConvictionVoting ClassLocksFor (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) + /// Storage: ConvictionVoting VotingFor (r:1 w:1) + /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) + /// Storage: ConvictionVoting ClassLocksFor (r:1 w:1) + /// Proof: ConvictionVoting ClassLocksFor (max_values: None, max_size: Some(59), added: 2534, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) fn unlock() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `11797` + // Estimated: `36024` + // Minimum execution time: 50_305 nanoseconds. + Weight::from_parts(51_226_000, 36024) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) } } // 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) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: ConvictionVoting VotingFor (r:1 w:1) + /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) + /// Storage: ConvictionVoting ClassLocksFor (r:1 w:1) + /// Proof: ConvictionVoting ClassLocksFor (max_values: None, max_size: Some(59), added: 2534, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:2 w:2) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn vote_new() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `13168` + // Estimated: `257859` + // Minimum execution time: 85_569 nanoseconds. + Weight::from_parts(86_492_000, 257859) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(6_u64)) } - // 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) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: ConvictionVoting VotingFor (r:1 w:1) + /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) + /// Storage: ConvictionVoting ClassLocksFor (r:1 w:1) + /// Proof: ConvictionVoting ClassLocksFor (max_values: None, max_size: Some(59), added: 2534, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:2 w:2) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn vote_existing() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `20342` + // Estimated: `257859` + // Minimum execution time: 212_727 nanoseconds. + Weight::from_parts(213_741_000, 257859) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(6_u64)) } - // Storage: ConvictionVoting VotingFor (r:1 w:1) - // Storage: Referenda ReferendumInfoFor (r:1 w:1) - // Storage: Scheduler Agenda (r:2 w:2) + /// Storage: ConvictionVoting VotingFor (r:1 w:1) + /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:2 w:2) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn remove_vote() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `20062` + // Estimated: `251551` + // Minimum execution time: 200_513 nanoseconds. + Weight::from_parts(201_589_000, 251551) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) } - // Storage: ConvictionVoting VotingFor (r:1 w:1) - // Storage: Referenda ReferendumInfoFor (r:1 w:0) + /// Storage: ConvictionVoting VotingFor (r:1 w:1) + /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) + /// Storage: Referenda ReferendumInfoFor (r:1 w:0) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) fn remove_other_vote() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `12738` + // Estimated: `32557` + // Minimum execution time: 43_083 nanoseconds. + Weight::from_parts(43_763_000, 32557) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - // 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) + /// Storage: ConvictionVoting VotingFor (r:2 w:2) + /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:2 w:2) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: ConvictionVoting ClassLocksFor (r:1 w:1) + /// Proof: ConvictionVoting ClassLocksFor (max_values: None, max_size: Some(59), added: 2534, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) /// The range of component `r` is `[0, 1]`. fn delegate(r: u32, ) -> Weight { - // 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)) - .saturating_add(RocksDbWeight::get().writes((3 as u64).saturating_mul(r as u64))) + // Proof Size summary in bytes: + // Measured: `272 + r * (1689 ±0)` + // Estimated: `176657 + r * (110917 ±0)` + // Minimum execution time: 33_246 nanoseconds. + Weight::from_parts(34_560_391, 176657) + // Standard Error: 63_925 + .saturating_add(Weight::from_ref_time(34_500_408).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(r.into()))) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_proof_size(110917).saturating_mul(r.into())) } - // Storage: ConvictionVoting VotingFor (r:2 w:2) - // Storage: Referenda ReferendumInfoFor (r:1 w:1) - // Storage: Scheduler Agenda (r:2 w:2) + /// Storage: ConvictionVoting VotingFor (r:2 w:2) + /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:2 w:2) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) /// The range of component `r` is `[0, 1]`. fn undelegate(r: u32, ) -> Weight { - // 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)) - .saturating_add(RocksDbWeight::get().writes((3 as u64).saturating_mul(r as u64))) + // Proof Size summary in bytes: + // Measured: `470 + r * (1407 ±0)` + // Estimated: `170349 + r * (110917 ±0)` + // Minimum execution time: 20_508 nanoseconds. + Weight::from_parts(21_240_024, 170349) + // Standard Error: 37_314 + .saturating_add(Weight::from_ref_time(30_890_875).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(r.into()))) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_proof_size(110917).saturating_mul(r.into())) } - // Storage: ConvictionVoting VotingFor (r:1 w:1) - // Storage: ConvictionVoting ClassLocksFor (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) + /// Storage: ConvictionVoting VotingFor (r:1 w:1) + /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) + /// Storage: ConvictionVoting ClassLocksFor (r:1 w:1) + /// Proof: ConvictionVoting ClassLocksFor (max_values: None, max_size: Some(59), added: 2534, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) fn unlock() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `11797` + // Estimated: `36024` + // Minimum execution time: 50_305 nanoseconds. + Weight::from_parts(51_226_000, 36024) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) } } diff --git a/frame/democracy/src/weights.rs b/frame/democracy/src/weights.rs index db3969d400b97..985fe8fbde781 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) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2023 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,7 +18,8 @@ //! Autogenerated weights for pallet_democracy //! //! 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: `[]` +//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -74,438 +75,692 @@ pub trait WeightInfo { /// Weights for pallet_democracy using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - // Storage: Democracy PublicPropCount (r:1 w:1) - // Storage: Democracy PublicProps (r:1 w:1) - // Storage: Democracy Blacklist (r:1 w:0) - // Storage: Democracy DepositOf (r:0 w:1) + /// Storage: Democracy PublicPropCount (r:1 w:1) + /// Proof: Democracy PublicPropCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Democracy PublicProps (r:1 w:1) + /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) + /// Storage: Democracy Blacklist (r:1 w:0) + /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) + /// Storage: Democracy DepositOf (r:0 w:1) + /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) fn propose() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `4864` + // Estimated: `23409` + // Minimum execution time: 34_509 nanoseconds. + Weight::from_parts(34_781_000, 23409) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: Democracy DepositOf (r:1 w:1) + /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) fn second() -> Weight { - // 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)) - } - // Storage: Democracy ReferendumInfoOf (r:1 w:1) - // Storage: Democracy VotingOf (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `3620` + // Estimated: `5705` + // Minimum execution time: 31_151 nanoseconds. + Weight::from_parts(31_566_000, 5705) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Democracy ReferendumInfoOf (r:1 w:1) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: Democracy VotingOf (r:1 w:1) + /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) fn vote_new() -> Weight { - // 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)) - } - // Storage: Democracy ReferendumInfoOf (r:1 w:1) - // Storage: Democracy VotingOf (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `3555` + // Estimated: `12720` + // Minimum execution time: 42_618 nanoseconds. + Weight::from_parts(43_231_000, 12720) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: Democracy ReferendumInfoOf (r:1 w:1) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: Democracy VotingOf (r:1 w:1) + /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) fn vote_existing() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `3577` + // Estimated: `12720` + // Minimum execution time: 42_875 nanoseconds. + Weight::from_parts(43_338_000, 12720) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: Democracy ReferendumInfoOf (r:1 w:1) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: Democracy Cancellations (r:1 w:1) + /// Proof: Democracy Cancellations (max_values: None, max_size: Some(33), added: 2508, mode: MaxEncodedLen) fn emergency_cancel() -> Weight { - // 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)) - } - // 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) + // Proof Size summary in bytes: + // Measured: `320` + // Estimated: `5184` + // Minimum execution time: 16_543 nanoseconds. + Weight::from_parts(16_762_000, 5184) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: Democracy PublicProps (r:1 w:1) + /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) + /// Storage: Democracy DepositOf (r:1 w:1) + /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Democracy NextExternal (r:1 w:1) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumInfoOf (r:1 w:1) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: Democracy Blacklist (r:0 w:1) + /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) fn blacklist() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `5958` + // Estimated: `28808` + // Minimum execution time: 70_135 nanoseconds. + Weight::from_parts(70_616_000, 28808) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(6_u64)) + } + /// Storage: Democracy NextExternal (r:1 w:1) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) + /// Storage: Democracy Blacklist (r:1 w:0) + /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) fn external_propose() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `3448` + // Estimated: `6340` + // Minimum execution time: 12_580 nanoseconds. + Weight::from_parts(12_987_000, 6340) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Democracy NextExternal (r:0 w:1) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) fn external_propose_majority() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_320 nanoseconds. + Weight::from_ref_time(3_513_000) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Democracy NextExternal (r:0 w:1) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) fn external_propose_default() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_407 nanoseconds. + Weight::from_ref_time(3_565_000) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Democracy NextExternal (r:1 w:1) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumCount (r:1 w:1) + /// Proof: Democracy ReferendumCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumInfoOf (r:0 w:1) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) fn fast_track() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `212` + // Estimated: `1126` + // Minimum execution time: 16_831 nanoseconds. + Weight::from_parts(17_155_000, 1126) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: Democracy NextExternal (r:1 w:1) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) + /// Storage: Democracy Blacklist (r:1 w:1) + /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) fn veto_external() -> Weight { - // 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)) - } - // Storage: Democracy PublicProps (r:1 w:1) - // Storage: Democracy DepositOf (r:1 w:1) - // Storage: System Account (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `3477` + // Estimated: `6340` + // Minimum execution time: 22_072 nanoseconds. + Weight::from_parts(22_517_000, 6340) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: Democracy PublicProps (r:1 w:1) + /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) + /// Storage: Democracy DepositOf (r:1 w:1) + /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn cancel_proposal() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `5837` + // Estimated: `25505` + // Minimum execution time: 56_925 nanoseconds. + Weight::from_parts(57_253_000, 25505) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: Democracy ReferendumInfoOf (r:0 w:1) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) fn cancel_referendum() -> Weight { - // 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) - // Storage: Democracy ReferendumCount (r:1 w:0) - // Storage: Democracy ReferendumInfoOf (r:2 w:0) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 8_582 nanoseconds. + Weight::from_ref_time(8_754_000) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Democracy LowestUnbaked (r:1 w:1) + /// Proof: Democracy LowestUnbaked (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumCount (r:1 w:0) + /// Proof: Democracy ReferendumCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumInfoOf (r:99 w:0) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) /// The range of component `r` is `[0, 99]`. fn on_initialize_base(r: u32, ) -> Weight { - // 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)) - } - // 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:2 w:0) + // Proof Size summary in bytes: + // Measured: `207 + r * (117 ±0)` + // Estimated: `998 + r * (2676 ±0)` + // Minimum execution time: 6_665 nanoseconds. + Weight::from_parts(9_219_932, 998) + // Standard Error: 4_236 + .saturating_add(Weight::from_ref_time(2_194_623).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) + .saturating_add(T::DbWeight::get().writes(1_u64)) + .saturating_add(Weight::from_proof_size(2676).saturating_mul(r.into())) + } + /// Storage: Democracy LowestUnbaked (r:1 w:1) + /// Proof: Democracy LowestUnbaked (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumCount (r:1 w:0) + /// Proof: Democracy ReferendumCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Democracy LastTabledWasExternal (r:1 w:0) + /// Proof: Democracy LastTabledWasExternal (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// Storage: Democracy NextExternal (r:1 w:0) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) + /// Storage: Democracy PublicProps (r:1 w:0) + /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumInfoOf (r:99 w:0) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) /// The range of component `r` is `[0, 99]`. fn on_initialize_base_with_launch_period(r: u32, ) -> Weight { - // 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)) - } - // Storage: Democracy VotingOf (r:3 w:3) - // Storage: Balances Locks (r:1 w:1) - // Storage: Democracy ReferendumInfoOf (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `207 + r * (117 ±0)` + // Estimated: `19318 + r * (2676 ±0)` + // Minimum execution time: 9_842 nanoseconds. + Weight::from_parts(11_932_535, 19318) + // Standard Error: 4_413 + .saturating_add(Weight::from_ref_time(2_199_644).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) + .saturating_add(T::DbWeight::get().writes(1_u64)) + .saturating_add(Weight::from_proof_size(2676).saturating_mul(r.into())) + } + /// Storage: Democracy VotingOf (r:3 w:3) + /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumInfoOf (r:99 w:99) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) /// The range of component `r` is `[0, 99]`. fn delegate(r: u32, ) -> Weight { - // 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)) - .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:2 w:2) + // Proof Size summary in bytes: + // Measured: `948 + r * (139 ±0)` + // Estimated: `22584 + r * (2676 ±0)` + // Minimum execution time: 34_740 nanoseconds. + Weight::from_parts(38_366_374, 22584) + // Standard Error: 4_868 + .saturating_add(Weight::from_ref_time(3_286_516).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) + .saturating_add(T::DbWeight::get().writes(4_u64)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_proof_size(2676).saturating_mul(r.into())) + } + /// Storage: Democracy VotingOf (r:2 w:2) + /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumInfoOf (r:99 w:99) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) /// The range of component `r` is `[0, 99]`. fn undelegate(r: u32, ) -> Weight { - // 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)) - .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(r as u64))) - } - // Storage: Democracy PublicProps (r:0 w:1) + // Proof Size summary in bytes: + // Measured: `547 + r * (139 ±0)` + // Estimated: `12540 + r * (2676 ±0)` + // Minimum execution time: 19_516 nanoseconds. + Weight::from_parts(21_629_605, 12540) + // Standard Error: 4_401 + .saturating_add(Weight::from_ref_time(3_238_187).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) + .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_proof_size(2676).saturating_mul(r.into())) + } + /// Storage: Democracy PublicProps (r:0 w:1) + /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) fn clear_public_proposals() -> Weight { - // 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) - // Storage: Balances Locks (r:1 w:1) - // Storage: System Account (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_291 nanoseconds. + Weight::from_ref_time(3_485_000) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Democracy VotingOf (r:1 w:1) + /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `r` is `[0, 99]`. fn unlock_remove(r: u32, ) -> Weight { - // 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)) - } - // Storage: Democracy VotingOf (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) - // Storage: System Account (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `617` + // Estimated: `12647` + // Minimum execution time: 19_357 nanoseconds. + Weight::from_parts(24_014_517, 12647) + // Standard Error: 994 + .saturating_add(Weight::from_ref_time(17_096).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: Democracy VotingOf (r:1 w:1) + /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `r` is `[0, 99]`. fn unlock_set(r: u32, ) -> Weight { - // 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)) - } - // Storage: Democracy ReferendumInfoOf (r:1 w:1) - // Storage: Democracy VotingOf (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `618 + r * (22 ±0)` + // Estimated: `12647` + // Minimum execution time: 22_340 nanoseconds. + Weight::from_parts(23_355_734, 12647) + // Standard Error: 548 + .saturating_add(Weight::from_ref_time(64_308).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: Democracy ReferendumInfoOf (r:1 w:1) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: Democracy VotingOf (r:1 w:1) + /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) /// The range of component `r` is `[1, 100]`. fn remove_vote(r: u32, ) -> Weight { - // 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)) - } - // Storage: Democracy ReferendumInfoOf (r:1 w:1) - // Storage: Democracy VotingOf (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `781 + r * (26 ±0)` + // Estimated: `8946` + // Minimum execution time: 14_542 nanoseconds. + Weight::from_parts(16_411_916, 8946) + // Standard Error: 839 + .saturating_add(Weight::from_ref_time(73_268).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: Democracy ReferendumInfoOf (r:1 w:1) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: Democracy VotingOf (r:1 w:1) + /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) /// The range of component `r` is `[1, 100]`. fn remove_other_vote(r: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `781 + r * (26 ±0)` + // Estimated: `8946` + // Minimum execution time: 14_463 nanoseconds. + Weight::from_parts(16_302_901, 8946) + // Standard Error: 809 + .saturating_add(Weight::from_ref_time(73_692).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } } // For backwards compatibility and tests impl WeightInfo for () { - // Storage: Democracy PublicPropCount (r:1 w:1) - // Storage: Democracy PublicProps (r:1 w:1) - // Storage: Democracy Blacklist (r:1 w:0) - // Storage: Democracy DepositOf (r:0 w:1) + /// Storage: Democracy PublicPropCount (r:1 w:1) + /// Proof: Democracy PublicPropCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Democracy PublicProps (r:1 w:1) + /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) + /// Storage: Democracy Blacklist (r:1 w:0) + /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) + /// Storage: Democracy DepositOf (r:0 w:1) + /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) fn propose() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `4864` + // Estimated: `23409` + // Minimum execution time: 34_509 nanoseconds. + Weight::from_parts(34_781_000, 23409) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: Democracy DepositOf (r:1 w:1) + /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) fn second() -> Weight { - // 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)) - } - // Storage: Democracy ReferendumInfoOf (r:1 w:1) - // Storage: Democracy VotingOf (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `3620` + // Estimated: `5705` + // Minimum execution time: 31_151 nanoseconds. + Weight::from_parts(31_566_000, 5705) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Democracy ReferendumInfoOf (r:1 w:1) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: Democracy VotingOf (r:1 w:1) + /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) fn vote_new() -> Weight { - // 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)) - } - // Storage: Democracy ReferendumInfoOf (r:1 w:1) - // Storage: Democracy VotingOf (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `3555` + // Estimated: `12720` + // Minimum execution time: 42_618 nanoseconds. + Weight::from_parts(43_231_000, 12720) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: Democracy ReferendumInfoOf (r:1 w:1) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: Democracy VotingOf (r:1 w:1) + /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) fn vote_existing() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `3577` + // Estimated: `12720` + // Minimum execution time: 42_875 nanoseconds. + Weight::from_parts(43_338_000, 12720) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: Democracy ReferendumInfoOf (r:1 w:1) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: Democracy Cancellations (r:1 w:1) + /// Proof: Democracy Cancellations (max_values: None, max_size: Some(33), added: 2508, mode: MaxEncodedLen) fn emergency_cancel() -> Weight { - // 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)) - } - // 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) + // Proof Size summary in bytes: + // Measured: `320` + // Estimated: `5184` + // Minimum execution time: 16_543 nanoseconds. + Weight::from_parts(16_762_000, 5184) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: Democracy PublicProps (r:1 w:1) + /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) + /// Storage: Democracy DepositOf (r:1 w:1) + /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Democracy NextExternal (r:1 w:1) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumInfoOf (r:1 w:1) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: Democracy Blacklist (r:0 w:1) + /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) fn blacklist() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `5958` + // Estimated: `28808` + // Minimum execution time: 70_135 nanoseconds. + Weight::from_parts(70_616_000, 28808) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(6_u64)) + } + /// Storage: Democracy NextExternal (r:1 w:1) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) + /// Storage: Democracy Blacklist (r:1 w:0) + /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) fn external_propose() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `3448` + // Estimated: `6340` + // Minimum execution time: 12_580 nanoseconds. + Weight::from_parts(12_987_000, 6340) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Democracy NextExternal (r:0 w:1) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) fn external_propose_majority() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_320 nanoseconds. + Weight::from_ref_time(3_513_000) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Democracy NextExternal (r:0 w:1) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) fn external_propose_default() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_407 nanoseconds. + Weight::from_ref_time(3_565_000) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Democracy NextExternal (r:1 w:1) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumCount (r:1 w:1) + /// Proof: Democracy ReferendumCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumInfoOf (r:0 w:1) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) fn fast_track() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `212` + // Estimated: `1126` + // Minimum execution time: 16_831 nanoseconds. + Weight::from_parts(17_155_000, 1126) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: Democracy NextExternal (r:1 w:1) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) + /// Storage: Democracy Blacklist (r:1 w:1) + /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) fn veto_external() -> Weight { - // 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)) - } - // Storage: Democracy PublicProps (r:1 w:1) - // Storage: Democracy DepositOf (r:1 w:1) - // Storage: System Account (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `3477` + // Estimated: `6340` + // Minimum execution time: 22_072 nanoseconds. + Weight::from_parts(22_517_000, 6340) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: Democracy PublicProps (r:1 w:1) + /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) + /// Storage: Democracy DepositOf (r:1 w:1) + /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn cancel_proposal() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `5837` + // Estimated: `25505` + // Minimum execution time: 56_925 nanoseconds. + Weight::from_parts(57_253_000, 25505) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: Democracy ReferendumInfoOf (r:0 w:1) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) fn cancel_referendum() -> Weight { - // 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) - // Storage: Democracy ReferendumCount (r:1 w:0) - // Storage: Democracy ReferendumInfoOf (r:2 w:0) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 8_582 nanoseconds. + Weight::from_ref_time(8_754_000) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Democracy LowestUnbaked (r:1 w:1) + /// Proof: Democracy LowestUnbaked (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumCount (r:1 w:0) + /// Proof: Democracy ReferendumCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumInfoOf (r:99 w:0) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) /// The range of component `r` is `[0, 99]`. fn on_initialize_base(r: u32, ) -> Weight { - // 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)) - } - // 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:2 w:0) + // Proof Size summary in bytes: + // Measured: `207 + r * (117 ±0)` + // Estimated: `998 + r * (2676 ±0)` + // Minimum execution time: 6_665 nanoseconds. + Weight::from_parts(9_219_932, 998) + // Standard Error: 4_236 + .saturating_add(Weight::from_ref_time(2_194_623).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + .saturating_add(Weight::from_proof_size(2676).saturating_mul(r.into())) + } + /// Storage: Democracy LowestUnbaked (r:1 w:1) + /// Proof: Democracy LowestUnbaked (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumCount (r:1 w:0) + /// Proof: Democracy ReferendumCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Democracy LastTabledWasExternal (r:1 w:0) + /// Proof: Democracy LastTabledWasExternal (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// Storage: Democracy NextExternal (r:1 w:0) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) + /// Storage: Democracy PublicProps (r:1 w:0) + /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumInfoOf (r:99 w:0) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) /// The range of component `r` is `[0, 99]`. fn on_initialize_base_with_launch_period(r: u32, ) -> Weight { - // 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)) - } - // Storage: Democracy VotingOf (r:3 w:3) - // Storage: Balances Locks (r:1 w:1) - // Storage: Democracy ReferendumInfoOf (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `207 + r * (117 ±0)` + // Estimated: `19318 + r * (2676 ±0)` + // Minimum execution time: 9_842 nanoseconds. + Weight::from_parts(11_932_535, 19318) + // Standard Error: 4_413 + .saturating_add(Weight::from_ref_time(2_199_644).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + .saturating_add(Weight::from_proof_size(2676).saturating_mul(r.into())) + } + /// Storage: Democracy VotingOf (r:3 w:3) + /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumInfoOf (r:99 w:99) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) /// The range of component `r` is `[0, 99]`. fn delegate(r: u32, ) -> Weight { - // 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)) - .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(r as u64))) - } - // Storage: Democracy VotingOf (r:2 w:2) - // Storage: Democracy ReferendumInfoOf (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `948 + r * (139 ±0)` + // Estimated: `22584 + r * (2676 ±0)` + // Minimum execution time: 34_740 nanoseconds. + Weight::from_parts(38_366_374, 22584) + // Standard Error: 4_868 + .saturating_add(Weight::from_ref_time(3_286_516).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_proof_size(2676).saturating_mul(r.into())) + } + /// Storage: Democracy VotingOf (r:2 w:2) + /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumInfoOf (r:99 w:99) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) /// The range of component `r` is `[0, 99]`. fn undelegate(r: u32, ) -> Weight { - // 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)) - .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(r as u64))) - } - // Storage: Democracy PublicProps (r:0 w:1) + // Proof Size summary in bytes: + // Measured: `547 + r * (139 ±0)` + // Estimated: `12540 + r * (2676 ±0)` + // Minimum execution time: 19_516 nanoseconds. + Weight::from_parts(21_629_605, 12540) + // Standard Error: 4_401 + .saturating_add(Weight::from_ref_time(3_238_187).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_proof_size(2676).saturating_mul(r.into())) + } + /// Storage: Democracy PublicProps (r:0 w:1) + /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) fn clear_public_proposals() -> Weight { - // 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) - // Storage: Balances Locks (r:1 w:1) - // Storage: System Account (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_291 nanoseconds. + Weight::from_ref_time(3_485_000) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Democracy VotingOf (r:1 w:1) + /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `r` is `[0, 99]`. fn unlock_remove(r: u32, ) -> Weight { - // 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)) - } - // Storage: Democracy VotingOf (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) - // Storage: System Account (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `617` + // Estimated: `12647` + // Minimum execution time: 19_357 nanoseconds. + Weight::from_parts(24_014_517, 12647) + // Standard Error: 994 + .saturating_add(Weight::from_ref_time(17_096).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: Democracy VotingOf (r:1 w:1) + /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `r` is `[0, 99]`. fn unlock_set(r: u32, ) -> Weight { - // 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)) - } - // Storage: Democracy ReferendumInfoOf (r:1 w:1) - // Storage: Democracy VotingOf (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `618 + r * (22 ±0)` + // Estimated: `12647` + // Minimum execution time: 22_340 nanoseconds. + Weight::from_parts(23_355_734, 12647) + // Standard Error: 548 + .saturating_add(Weight::from_ref_time(64_308).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: Democracy ReferendumInfoOf (r:1 w:1) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: Democracy VotingOf (r:1 w:1) + /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) /// The range of component `r` is `[1, 100]`. fn remove_vote(r: u32, ) -> Weight { - // 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)) - } - // Storage: Democracy ReferendumInfoOf (r:1 w:1) - // Storage: Democracy VotingOf (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `781 + r * (26 ±0)` + // Estimated: `8946` + // Minimum execution time: 14_542 nanoseconds. + Weight::from_parts(16_411_916, 8946) + // Standard Error: 839 + .saturating_add(Weight::from_ref_time(73_268).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: Democracy ReferendumInfoOf (r:1 w:1) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: Democracy VotingOf (r:1 w:1) + /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) /// The range of component `r` is `[1, 100]`. fn remove_other_vote(r: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `781 + r * (26 ±0)` + // Estimated: `8946` + // Minimum execution time: 14_463 nanoseconds. + Weight::from_parts(16_302_901, 8946) + // Standard Error: 809 + .saturating_add(Weight::from_ref_time(73_692).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } } diff --git a/frame/election-provider-multi-phase/src/weights.rs b/frame/election-provider-multi-phase/src/weights.rs index 221fd5837f7b7..51bb7b0f10eba 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) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2023 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -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-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -62,262 +63,422 @@ pub trait WeightInfo { /// Weights for pallet_election_provider_multi_phase using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - // Storage: Staking CurrentEra (r:1 w:0) - // Storage: Staking CurrentPlannedSession (r:1 w:0) - // Storage: Staking ErasStartSessionIndex (r:1 w:0) - // Storage: Babe EpochIndex (r:1 w:0) - // Storage: Babe GenesisSlot (r:1 w:0) - // Storage: Babe CurrentSlot (r:1 w:0) - // Storage: Staking ForceEra (r:1 w:0) - // Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) + /// Storage: Staking CurrentEra (r:1 w:0) + /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking CurrentPlannedSession (r:1 w:0) + /// Proof: Staking CurrentPlannedSession (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking ErasStartSessionIndex (r:1 w:0) + /// Proof: Staking ErasStartSessionIndex (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) + /// Storage: Babe EpochIndex (r:1 w:0) + /// Proof: Babe EpochIndex (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Babe GenesisSlot (r:1 w:0) + /// Proof: Babe GenesisSlot (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Babe CurrentSlot (r:1 w:0) + /// Proof: Babe CurrentSlot (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Staking ForceEra (r:1 w:0) + /// Proof: Staking ForceEra (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) fn on_initialize_nothing() -> Weight { - // Minimum execution time: 17_309 nanoseconds. - Weight::from_ref_time(17_646_000 as u64) - .saturating_add(T::DbWeight::get().reads(8 as u64)) + // Proof Size summary in bytes: + // Measured: `994` + // Estimated: `6983` + // Minimum execution time: 17_801 nanoseconds. + Weight::from_parts(18_364_000, 6983) + .saturating_add(T::DbWeight::get().reads(8_u64)) } - // Storage: ElectionProviderMultiPhase Round (r:1 w:0) - // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) + /// Storage: ElectionProviderMultiPhase Round (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase Round (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:1) + /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) fn on_initialize_open_signed() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `114` + // Estimated: `1218` + // Minimum execution time: 12_814 nanoseconds. + Weight::from_parts(13_154_000, 1218) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - // Storage: ElectionProviderMultiPhase Round (r:1 w:0) - // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) + /// Storage: ElectionProviderMultiPhase Round (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase Round (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:1) + /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) fn on_initialize_open_unsigned() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `114` + // Estimated: `1218` + // Minimum execution time: 14_565 nanoseconds. + Weight::from_parts(15_097_000, 1218) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - // Storage: System Account (r:1 w:1) - // Storage: ElectionProviderMultiPhase QueuedSolution (r:0 w:1) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: ElectionProviderMultiPhase QueuedSolution (r:0 w:1) + /// Proof Skipped: ElectionProviderMultiPhase QueuedSolution (max_values: Some(1), max_size: None, mode: Measured) fn finalize_signed_phase_accept_solution() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `206` + // Estimated: `2809` + // Minimum execution time: 23_341 nanoseconds. + Weight::from_parts(23_770_000, 2809) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } - // Storage: System Account (r:1 w:1) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn finalize_signed_phase_reject_solution() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `206` + // Estimated: `2603` + // Minimum execution time: 16_662 nanoseconds. + Weight::from_parts(16_898_000, 2603) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - // Storage: ElectionProviderMultiPhase SnapshotMetadata (r:0 w:1) - // Storage: ElectionProviderMultiPhase DesiredTargets (r:0 w:1) - // Storage: ElectionProviderMultiPhase Snapshot (r:0 w:1) + /// Storage: ElectionProviderMultiPhase SnapshotMetadata (r:0 w:1) + /// Proof Skipped: ElectionProviderMultiPhase SnapshotMetadata (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase DesiredTargets (r:0 w:1) + /// Proof Skipped: ElectionProviderMultiPhase DesiredTargets (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase Snapshot (r:0 w:1) + /// Proof Skipped: ElectionProviderMultiPhase Snapshot (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `v` is `[1000, 2000]`. /// The range of component `t` is `[500, 1000]`. fn create_snapshot_internal(v: u32, _t: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 215_168 nanoseconds. + Weight::from_ref_time(219_887_000) + // Standard Error: 1_444 + .saturating_add(Weight::from_ref_time(146_388).saturating_mul(v.into())) + .saturating_add(T::DbWeight::get().writes(3_u64)) } - // Storage: ElectionProviderMultiPhase SignedSubmissionIndices (r:1 w:1) - // Storage: ElectionProviderMultiPhase SignedSubmissionNextIndex (r:1 w:1) - // Storage: ElectionProviderMultiPhase SnapshotMetadata (r:1 w:1) - // Storage: ElectionProviderMultiPhase SignedSubmissionsMap (r:1 w:0) - // Storage: ElectionProviderMultiPhase QueuedSolution (r:1 w:1) - // Storage: ElectionProviderMultiPhase Round (r:1 w:1) - // Storage: ElectionProviderMultiPhase DesiredTargets (r:0 w:1) - // Storage: ElectionProviderMultiPhase Snapshot (r:0 w:1) - // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) + /// Storage: ElectionProviderMultiPhase SignedSubmissionIndices (r:1 w:1) + /// Proof Skipped: ElectionProviderMultiPhase SignedSubmissionIndices (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase SignedSubmissionNextIndex (r:1 w:1) + /// Proof Skipped: ElectionProviderMultiPhase SignedSubmissionNextIndex (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase SnapshotMetadata (r:1 w:1) + /// Proof Skipped: ElectionProviderMultiPhase SnapshotMetadata (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase SignedSubmissionsMap (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase SignedSubmissionsMap (max_values: None, max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase QueuedSolution (r:1 w:1) + /// Proof Skipped: ElectionProviderMultiPhase QueuedSolution (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase Round (r:1 w:1) + /// Proof Skipped: ElectionProviderMultiPhase Round (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:1) + /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase DesiredTargets (r:0 w:1) + /// Proof Skipped: ElectionProviderMultiPhase DesiredTargets (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase Snapshot (r:0 w:1) + /// Proof Skipped: ElectionProviderMultiPhase Snapshot (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `a` is `[500, 800]`. /// The range of component `d` is `[200, 400]`. fn elect_queued(a: u32, d: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `368 + a * (768 ±0) + d * (48 ±0)` + // Estimated: `9540 + a * (6912 ±0) + d * (441 ±0)` + // Minimum execution time: 268_021 nanoseconds. + Weight::from_parts(72_491_937, 9540) + // Standard Error: 2_910 + .saturating_add(Weight::from_ref_time(303_955).saturating_mul(a.into())) + // Standard Error: 4_363 + .saturating_add(Weight::from_ref_time(167_369).saturating_mul(d.into())) + .saturating_add(T::DbWeight::get().reads(7_u64)) + .saturating_add(T::DbWeight::get().writes(8_u64)) + .saturating_add(Weight::from_proof_size(6912).saturating_mul(a.into())) + .saturating_add(Weight::from_proof_size(441).saturating_mul(d.into())) } - // 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) + /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase SnapshotMetadata (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase SnapshotMetadata (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) + /// Proof: TransactionPayment NextFeeMultiplier (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: ElectionProviderMultiPhase SignedSubmissionIndices (r:1 w:1) + /// Proof Skipped: ElectionProviderMultiPhase SignedSubmissionIndices (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase SignedSubmissionNextIndex (r:1 w:1) + /// Proof Skipped: ElectionProviderMultiPhase SignedSubmissionNextIndex (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase SignedSubmissionsMap (r:0 w:1) + /// Proof Skipped: ElectionProviderMultiPhase SignedSubmissionsMap (max_values: None, max_size: None, mode: Measured) fn submit() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `924` + // Estimated: `7111` + // Minimum execution time: 44_177 nanoseconds. + Weight::from_parts(44_663_000, 7111) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) } - // Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) - // Storage: ElectionProviderMultiPhase Round (r:1 w:0) - // Storage: ElectionProviderMultiPhase DesiredTargets (r:1 w:0) - // Storage: ElectionProviderMultiPhase QueuedSolution (r:1 w:1) - // Storage: ElectionProviderMultiPhase SnapshotMetadata (r:1 w:0) - // Storage: ElectionProviderMultiPhase MinimumUntrustedScore (r:1 w:0) - // Storage: ElectionProviderMultiPhase Snapshot (r:1 w:0) + /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase Round (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase Round (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase DesiredTargets (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase DesiredTargets (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase QueuedSolution (r:1 w:1) + /// Proof Skipped: ElectionProviderMultiPhase QueuedSolution (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase SnapshotMetadata (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase SnapshotMetadata (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase MinimumUntrustedScore (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase MinimumUntrustedScore (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase Snapshot (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase Snapshot (max_values: Some(1), max_size: None, mode: Measured) /// 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)) + fn submit_unsigned(v: u32, t: u32, a: u32, _d: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `251 + v * (553 ±0) + t * (32 ±0)` + // Estimated: `5222 + v * (3871 ±0) + t * (224 ±0)` + // Minimum execution time: 4_425_457 nanoseconds. + Weight::from_parts(4_445_889_000, 5222) + // Standard Error: 13_250 + .saturating_add(Weight::from_ref_time(48_844).saturating_mul(v.into())) + // Standard Error: 39_266 + .saturating_add(Weight::from_ref_time(4_144_034).saturating_mul(a.into())) + .saturating_add(T::DbWeight::get().reads(7_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + .saturating_add(Weight::from_proof_size(3871).saturating_mul(v.into())) + .saturating_add(Weight::from_proof_size(224).saturating_mul(t.into())) } - // 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) + /// Storage: ElectionProviderMultiPhase Round (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase Round (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase DesiredTargets (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase DesiredTargets (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase MinimumUntrustedScore (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase MinimumUntrustedScore (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase Snapshot (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase Snapshot (max_values: Some(1), max_size: None, mode: Measured) /// 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)) + fn feasibility_check(v: u32, t: u32, a: u32, _d: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `226 + v * (553 ±0) + t * (32 ±0)` + // Estimated: `2884 + v * (2212 ±0) + t * (128 ±0)` + // Minimum execution time: 3_812_071 nanoseconds. + Weight::from_parts(3_826_375_000, 2884) + // Standard Error: 11_601 + .saturating_add(Weight::from_ref_time(145_309).saturating_mul(v.into())) + // Standard Error: 34_378 + .saturating_add(Weight::from_ref_time(3_223_977).saturating_mul(a.into())) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(Weight::from_proof_size(2212).saturating_mul(v.into())) + .saturating_add(Weight::from_proof_size(128).saturating_mul(t.into())) } } // For backwards compatibility and tests impl WeightInfo for () { - // Storage: Staking CurrentEra (r:1 w:0) - // Storage: Staking CurrentPlannedSession (r:1 w:0) - // Storage: Staking ErasStartSessionIndex (r:1 w:0) - // Storage: Babe EpochIndex (r:1 w:0) - // Storage: Babe GenesisSlot (r:1 w:0) - // Storage: Babe CurrentSlot (r:1 w:0) - // Storage: Staking ForceEra (r:1 w:0) - // Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) + /// Storage: Staking CurrentEra (r:1 w:0) + /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking CurrentPlannedSession (r:1 w:0) + /// Proof: Staking CurrentPlannedSession (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking ErasStartSessionIndex (r:1 w:0) + /// Proof: Staking ErasStartSessionIndex (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) + /// Storage: Babe EpochIndex (r:1 w:0) + /// Proof: Babe EpochIndex (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Babe GenesisSlot (r:1 w:0) + /// Proof: Babe GenesisSlot (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Babe CurrentSlot (r:1 w:0) + /// Proof: Babe CurrentSlot (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Staking ForceEra (r:1 w:0) + /// Proof: Staking ForceEra (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) fn on_initialize_nothing() -> Weight { - // Minimum execution time: 17_309 nanoseconds. - Weight::from_ref_time(17_646_000 as u64) - .saturating_add(RocksDbWeight::get().reads(8 as u64)) + // Proof Size summary in bytes: + // Measured: `994` + // Estimated: `6983` + // Minimum execution time: 17_801 nanoseconds. + Weight::from_parts(18_364_000, 6983) + .saturating_add(RocksDbWeight::get().reads(8_u64)) } - // Storage: ElectionProviderMultiPhase Round (r:1 w:0) - // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) + /// Storage: ElectionProviderMultiPhase Round (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase Round (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:1) + /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) fn on_initialize_open_signed() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `114` + // Estimated: `1218` + // Minimum execution time: 12_814 nanoseconds. + Weight::from_parts(13_154_000, 1218) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - // Storage: ElectionProviderMultiPhase Round (r:1 w:0) - // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) + /// Storage: ElectionProviderMultiPhase Round (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase Round (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:1) + /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) fn on_initialize_open_unsigned() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `114` + // Estimated: `1218` + // Minimum execution time: 14_565 nanoseconds. + Weight::from_parts(15_097_000, 1218) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - // Storage: System Account (r:1 w:1) - // Storage: ElectionProviderMultiPhase QueuedSolution (r:0 w:1) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: ElectionProviderMultiPhase QueuedSolution (r:0 w:1) + /// Proof Skipped: ElectionProviderMultiPhase QueuedSolution (max_values: Some(1), max_size: None, mode: Measured) fn finalize_signed_phase_accept_solution() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `206` + // Estimated: `2809` + // Minimum execution time: 23_341 nanoseconds. + Weight::from_parts(23_770_000, 2809) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } - // Storage: System Account (r:1 w:1) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn finalize_signed_phase_reject_solution() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `206` + // Estimated: `2603` + // Minimum execution time: 16_662 nanoseconds. + Weight::from_parts(16_898_000, 2603) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - // Storage: ElectionProviderMultiPhase SnapshotMetadata (r:0 w:1) - // Storage: ElectionProviderMultiPhase DesiredTargets (r:0 w:1) - // Storage: ElectionProviderMultiPhase Snapshot (r:0 w:1) + /// Storage: ElectionProviderMultiPhase SnapshotMetadata (r:0 w:1) + /// Proof Skipped: ElectionProviderMultiPhase SnapshotMetadata (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase DesiredTargets (r:0 w:1) + /// Proof Skipped: ElectionProviderMultiPhase DesiredTargets (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase Snapshot (r:0 w:1) + /// Proof Skipped: ElectionProviderMultiPhase Snapshot (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `v` is `[1000, 2000]`. /// The range of component `t` is `[500, 1000]`. fn create_snapshot_internal(v: u32, _t: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 215_168 nanoseconds. + Weight::from_ref_time(219_887_000) + // Standard Error: 1_444 + .saturating_add(Weight::from_ref_time(146_388).saturating_mul(v.into())) + .saturating_add(RocksDbWeight::get().writes(3_u64)) } - // Storage: ElectionProviderMultiPhase SignedSubmissionIndices (r:1 w:1) - // Storage: ElectionProviderMultiPhase SignedSubmissionNextIndex (r:1 w:1) - // Storage: ElectionProviderMultiPhase SnapshotMetadata (r:1 w:1) - // Storage: ElectionProviderMultiPhase SignedSubmissionsMap (r:1 w:0) - // Storage: ElectionProviderMultiPhase QueuedSolution (r:1 w:1) - // Storage: ElectionProviderMultiPhase Round (r:1 w:1) - // Storage: ElectionProviderMultiPhase DesiredTargets (r:0 w:1) - // Storage: ElectionProviderMultiPhase Snapshot (r:0 w:1) - // Storage: ElectionProviderMultiPhase CurrentPhase (r:0 w:1) + /// Storage: ElectionProviderMultiPhase SignedSubmissionIndices (r:1 w:1) + /// Proof Skipped: ElectionProviderMultiPhase SignedSubmissionIndices (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase SignedSubmissionNextIndex (r:1 w:1) + /// Proof Skipped: ElectionProviderMultiPhase SignedSubmissionNextIndex (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase SnapshotMetadata (r:1 w:1) + /// Proof Skipped: ElectionProviderMultiPhase SnapshotMetadata (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase SignedSubmissionsMap (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase SignedSubmissionsMap (max_values: None, max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase QueuedSolution (r:1 w:1) + /// Proof Skipped: ElectionProviderMultiPhase QueuedSolution (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase Round (r:1 w:1) + /// Proof Skipped: ElectionProviderMultiPhase Round (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:1) + /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase DesiredTargets (r:0 w:1) + /// Proof Skipped: ElectionProviderMultiPhase DesiredTargets (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase Snapshot (r:0 w:1) + /// Proof Skipped: ElectionProviderMultiPhase Snapshot (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `a` is `[500, 800]`. /// The range of component `d` is `[200, 400]`. fn elect_queued(a: u32, d: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `368 + a * (768 ±0) + d * (48 ±0)` + // Estimated: `9540 + a * (6912 ±0) + d * (441 ±0)` + // Minimum execution time: 268_021 nanoseconds. + Weight::from_parts(72_491_937, 9540) + // Standard Error: 2_910 + .saturating_add(Weight::from_ref_time(303_955).saturating_mul(a.into())) + // Standard Error: 4_363 + .saturating_add(Weight::from_ref_time(167_369).saturating_mul(d.into())) + .saturating_add(RocksDbWeight::get().reads(7_u64)) + .saturating_add(RocksDbWeight::get().writes(8_u64)) + .saturating_add(Weight::from_proof_size(6912).saturating_mul(a.into())) + .saturating_add(Weight::from_proof_size(441).saturating_mul(d.into())) } - // 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) + /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase SnapshotMetadata (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase SnapshotMetadata (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) + /// Proof: TransactionPayment NextFeeMultiplier (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: ElectionProviderMultiPhase SignedSubmissionIndices (r:1 w:1) + /// Proof Skipped: ElectionProviderMultiPhase SignedSubmissionIndices (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase SignedSubmissionNextIndex (r:1 w:1) + /// Proof Skipped: ElectionProviderMultiPhase SignedSubmissionNextIndex (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase SignedSubmissionsMap (r:0 w:1) + /// Proof Skipped: ElectionProviderMultiPhase SignedSubmissionsMap (max_values: None, max_size: None, mode: Measured) fn submit() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `924` + // Estimated: `7111` + // Minimum execution time: 44_177 nanoseconds. + Weight::from_parts(44_663_000, 7111) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) } - // Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) - // Storage: ElectionProviderMultiPhase Round (r:1 w:0) - // Storage: ElectionProviderMultiPhase DesiredTargets (r:1 w:0) - // Storage: ElectionProviderMultiPhase QueuedSolution (r:1 w:1) - // Storage: ElectionProviderMultiPhase SnapshotMetadata (r:1 w:0) - // Storage: ElectionProviderMultiPhase MinimumUntrustedScore (r:1 w:0) - // Storage: ElectionProviderMultiPhase Snapshot (r:1 w:0) + /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase Round (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase Round (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase DesiredTargets (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase DesiredTargets (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase QueuedSolution (r:1 w:1) + /// Proof Skipped: ElectionProviderMultiPhase QueuedSolution (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase SnapshotMetadata (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase SnapshotMetadata (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase MinimumUntrustedScore (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase MinimumUntrustedScore (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase Snapshot (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase Snapshot (max_values: Some(1), max_size: None, mode: Measured) /// 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)) + fn submit_unsigned(v: u32, t: u32, a: u32, _d: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `251 + v * (553 ±0) + t * (32 ±0)` + // Estimated: `5222 + v * (3871 ±0) + t * (224 ±0)` + // Minimum execution time: 4_425_457 nanoseconds. + Weight::from_parts(4_445_889_000, 5222) + // Standard Error: 13_250 + .saturating_add(Weight::from_ref_time(48_844).saturating_mul(v.into())) + // Standard Error: 39_266 + .saturating_add(Weight::from_ref_time(4_144_034).saturating_mul(a.into())) + .saturating_add(RocksDbWeight::get().reads(7_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + .saturating_add(Weight::from_proof_size(3871).saturating_mul(v.into())) + .saturating_add(Weight::from_proof_size(224).saturating_mul(t.into())) } - // 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) + /// Storage: ElectionProviderMultiPhase Round (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase Round (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase DesiredTargets (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase DesiredTargets (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase MinimumUntrustedScore (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase MinimumUntrustedScore (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase Snapshot (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase Snapshot (max_values: Some(1), max_size: None, mode: Measured) /// 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)) + fn feasibility_check(v: u32, t: u32, a: u32, _d: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `226 + v * (553 ±0) + t * (32 ±0)` + // Estimated: `2884 + v * (2212 ±0) + t * (128 ±0)` + // Minimum execution time: 3_812_071 nanoseconds. + Weight::from_parts(3_826_375_000, 2884) + // Standard Error: 11_601 + .saturating_add(Weight::from_ref_time(145_309).saturating_mul(v.into())) + // Standard Error: 34_378 + .saturating_add(Weight::from_ref_time(3_223_977).saturating_mul(a.into())) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(Weight::from_proof_size(2212).saturating_mul(v.into())) + .saturating_add(Weight::from_proof_size(128).saturating_mul(t.into())) } } diff --git a/frame/elections-phragmen/src/weights.rs b/frame/elections-phragmen/src/weights.rs index ddc55b08750d5..dc5d937e33eaf 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) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2023 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,7 +18,8 @@ //! Autogenerated weights for pallet_elections_phragmen //! //! 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: `[]` +//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -64,306 +65,494 @@ pub trait WeightInfo { /// Weights for pallet_elections_phragmen using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - // Storage: Elections Candidates (r:1 w:0) - // Storage: Elections Members (r:1 w:0) - // Storage: Elections RunnersUp (r:1 w:0) - // Storage: Elections Voting (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) + /// Storage: Elections Candidates (r:1 w:0) + /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Members (r:1 w:0) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections RunnersUp (r:1 w:0) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Voting (r:1 w:1) + /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) /// The range of component `v` is `[1, 16]`. fn vote_equal(v: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `499 + v * (80 ±0)` + // Estimated: `9726 + v * (320 ±0)` + // Minimum execution time: 25_407 nanoseconds. + Weight::from_parts(26_035_742, 9726) + // Standard Error: 2_162 + .saturating_add(Weight::from_ref_time(120_321).saturating_mul(v.into())) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_proof_size(320).saturating_mul(v.into())) } - // Storage: Elections Candidates (r:1 w:0) - // Storage: Elections Members (r:1 w:0) - // Storage: Elections RunnersUp (r:1 w:0) - // Storage: Elections Voting (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) + /// Storage: Elections Candidates (r:1 w:0) + /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Members (r:1 w:0) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections RunnersUp (r:1 w:0) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Voting (r:1 w:1) + /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) /// The range of component `v` is `[2, 16]`. fn vote_more(v: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `467 + v * (80 ±0)` + // Estimated: `9598 + v * (320 ±0)` + // Minimum execution time: 34_477 nanoseconds. + Weight::from_parts(35_197_694, 9598) + // Standard Error: 2_089 + .saturating_add(Weight::from_ref_time(116_792).saturating_mul(v.into())) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_proof_size(320).saturating_mul(v.into())) } - // Storage: Elections Candidates (r:1 w:0) - // Storage: Elections Members (r:1 w:0) - // Storage: Elections RunnersUp (r:1 w:0) - // Storage: Elections Voting (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) + /// Storage: Elections Candidates (r:1 w:0) + /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Members (r:1 w:0) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections RunnersUp (r:1 w:0) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Voting (r:1 w:1) + /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) /// The range of component `v` is `[2, 16]`. fn vote_less(v: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `499 + v * (80 ±0)` + // Estimated: `9726 + v * (320 ±0)` + // Minimum execution time: 34_573 nanoseconds. + Weight::from_parts(35_254_508, 9726) + // Standard Error: 2_076 + .saturating_add(Weight::from_ref_time(110_656).saturating_mul(v.into())) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_proof_size(320).saturating_mul(v.into())) } - // Storage: Elections Voting (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) + /// Storage: Elections Voting (r:1 w:1) + /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) fn remove_voter() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `989` + // Estimated: `7238` + // Minimum execution time: 31_469 nanoseconds. + Weight::from_parts(31_877_000, 7238) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } - // Storage: Elections Candidates (r:1 w:1) - // Storage: Elections Members (r:1 w:0) - // Storage: Elections RunnersUp (r:1 w:0) + /// Storage: Elections Candidates (r:1 w:1) + /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Members (r:1 w:0) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections RunnersUp (r:1 w:0) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `c` is `[1, 1000]`. fn submit_candidacy(c: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `1687 + c * (48 ±0)` + // Estimated: `6540 + c * (144 ±0)` + // Minimum execution time: 26_969 nanoseconds. + Weight::from_parts(28_584_266, 6540) + // Standard Error: 93 + .saturating_add(Weight::from_ref_time(52_393).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + .saturating_add(Weight::from_proof_size(144).saturating_mul(c.into())) } - // Storage: Elections Candidates (r:1 w:1) + /// Storage: Elections Candidates (r:1 w:1) + /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `c` is `[1, 1000]`. fn renounce_candidacy_candidate(c: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `348 + c * (48 ±0)` + // Estimated: `830 + c * (48 ±0)` + // Minimum execution time: 23_635 nanoseconds. + Weight::from_parts(23_482_193, 830) + // Standard Error: 103 + .saturating_add(Weight::from_ref_time(33_759).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + .saturating_add(Weight::from_proof_size(48).saturating_mul(c.into())) } - // Storage: Elections Members (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) + /// Storage: Elections Members (r:1 w:1) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections RunnersUp (r:1 w:1) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Prime (r:1 w:1) + /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:0) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Members (r:0 w:1) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) fn renounce_candidacy_members() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `2027` + // Estimated: `12115` + // Minimum execution time: 39_124 nanoseconds. + Weight::from_parts(39_575_000, 12115) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) } - // Storage: Elections RunnersUp (r:1 w:1) + /// Storage: Elections RunnersUp (r:1 w:1) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) fn renounce_candidacy_runners_up() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `975` + // Estimated: `1470` + // Minimum execution time: 25_377 nanoseconds. + Weight::from_parts(25_696_000, 1470) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - // Storage: Benchmark Override (r:0 w:0) + /// Storage: Benchmark Override (r:0 w:0) + /// Proof Skipped: Benchmark Override (max_values: None, max_size: None, mode: Measured) fn remove_member_without_replacement() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` // Minimum execution time: 2_000_000_000 nanoseconds. - Weight::from_ref_time(2_000_000_000_000 as u64) + Weight::from_ref_time(2_000_000_000_000) } - // 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) + /// Storage: Elections Members (r:1 w:1) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Elections RunnersUp (r:1 w:1) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Prime (r:1 w:1) + /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:0) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Members (r:0 w:1) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) fn remove_member_with_replacement() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `2027` + // Estimated: `14718` + // Minimum execution time: 44_919 nanoseconds. + Weight::from_parts(45_548_000, 14718) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) } - // 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:5000 w:5000) - // Storage: System Account (r:5000 w:5000) + /// Storage: Elections Voting (r:10001 w:10000) + /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Elections Members (r:1 w:0) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections RunnersUp (r:1 w:0) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Candidates (r:1 w:0) + /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Balances Locks (r:10000 w:10000) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: System Account (r:10000 w:10000) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `v` is `[5000, 10000]`. /// The range of component `d` is `[0, 5000]`. fn clean_defunct_voters(v: u32, _d: u32, ) -> Weight { - // 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))) + // Proof Size summary in bytes: + // Measured: `36028 + v * (872 ±0)` + // Estimated: `149172 + v * (12340 ±0)` + // Minimum execution time: 297_544_939 nanoseconds. + Weight::from_parts(298_088_024_000, 149172) + // Standard Error: 264_599 + .saturating_add(Weight::from_ref_time(38_142_857).saturating_mul(v.into())) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(v.into()))) + .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(v.into()))) + .saturating_add(Weight::from_proof_size(12340).saturating_mul(v.into())) } - // 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: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:1 w:1) + /// Storage: Elections Candidates (r:1 w:1) + /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Members (r:1 w:1) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections RunnersUp (r:1 w:1) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Voting (r:10001 w:0) + /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:0) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: System Account (r:980 w:980) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Elections ElectionRounds (r:1 w:1) + /// Proof Skipped: Elections ElectionRounds (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Members (r:0 w:1) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Prime (r:0 w:1) + /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `c` is `[1, 1000]`. /// The range of component `v` is `[1, 10000]`. /// The range of component `e` is `[10000, 160000]`. fn election_phragmen(c: u32, v: u32, e: u32, ) -> Weight { - // 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))) + // Proof Size summary in bytes: + // Measured: `0 + v * (639 ±0) + e * (28 ±0)` + // Estimated: `5350105 + c * (2582 ±0) + v * (5721 ±6) + e * (123 ±0)` + // Minimum execution time: 21_844_965 nanoseconds. + Weight::from_parts(21_979_826_000, 5350105) + // Standard Error: 229_799 + .saturating_add(Weight::from_ref_time(24_976_612).saturating_mul(v.into())) + // Standard Error: 14_747 + .saturating_add(Weight::from_ref_time(1_025_848).saturating_mul(e.into())) + .saturating_add(T::DbWeight::get().reads(280_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(c.into()))) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) + .saturating_add(T::DbWeight::get().writes(6_u64)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(c.into()))) + .saturating_add(Weight::from_proof_size(2582).saturating_mul(c.into())) + .saturating_add(Weight::from_proof_size(5721).saturating_mul(v.into())) + .saturating_add(Weight::from_proof_size(123).saturating_mul(e.into())) } } // For backwards compatibility and tests impl WeightInfo for () { - // Storage: Elections Candidates (r:1 w:0) - // Storage: Elections Members (r:1 w:0) - // Storage: Elections RunnersUp (r:1 w:0) - // Storage: Elections Voting (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) + /// Storage: Elections Candidates (r:1 w:0) + /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Members (r:1 w:0) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections RunnersUp (r:1 w:0) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Voting (r:1 w:1) + /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) /// The range of component `v` is `[1, 16]`. fn vote_equal(v: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `499 + v * (80 ±0)` + // Estimated: `9726 + v * (320 ±0)` + // Minimum execution time: 25_407 nanoseconds. + Weight::from_parts(26_035_742, 9726) + // Standard Error: 2_162 + .saturating_add(Weight::from_ref_time(120_321).saturating_mul(v.into())) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_proof_size(320).saturating_mul(v.into())) } - // Storage: Elections Candidates (r:1 w:0) - // Storage: Elections Members (r:1 w:0) - // Storage: Elections RunnersUp (r:1 w:0) - // Storage: Elections Voting (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) + /// Storage: Elections Candidates (r:1 w:0) + /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Members (r:1 w:0) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections RunnersUp (r:1 w:0) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Voting (r:1 w:1) + /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) /// The range of component `v` is `[2, 16]`. fn vote_more(v: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `467 + v * (80 ±0)` + // Estimated: `9598 + v * (320 ±0)` + // Minimum execution time: 34_477 nanoseconds. + Weight::from_parts(35_197_694, 9598) + // Standard Error: 2_089 + .saturating_add(Weight::from_ref_time(116_792).saturating_mul(v.into())) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_proof_size(320).saturating_mul(v.into())) } - // Storage: Elections Candidates (r:1 w:0) - // Storage: Elections Members (r:1 w:0) - // Storage: Elections RunnersUp (r:1 w:0) - // Storage: Elections Voting (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) + /// Storage: Elections Candidates (r:1 w:0) + /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Members (r:1 w:0) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections RunnersUp (r:1 w:0) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Voting (r:1 w:1) + /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) /// The range of component `v` is `[2, 16]`. fn vote_less(v: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `499 + v * (80 ±0)` + // Estimated: `9726 + v * (320 ±0)` + // Minimum execution time: 34_573 nanoseconds. + Weight::from_parts(35_254_508, 9726) + // Standard Error: 2_076 + .saturating_add(Weight::from_ref_time(110_656).saturating_mul(v.into())) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_proof_size(320).saturating_mul(v.into())) } - // Storage: Elections Voting (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) + /// Storage: Elections Voting (r:1 w:1) + /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) fn remove_voter() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `989` + // Estimated: `7238` + // Minimum execution time: 31_469 nanoseconds. + Weight::from_parts(31_877_000, 7238) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } - // Storage: Elections Candidates (r:1 w:1) - // Storage: Elections Members (r:1 w:0) - // Storage: Elections RunnersUp (r:1 w:0) + /// Storage: Elections Candidates (r:1 w:1) + /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Members (r:1 w:0) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections RunnersUp (r:1 w:0) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `c` is `[1, 1000]`. fn submit_candidacy(c: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `1687 + c * (48 ±0)` + // Estimated: `6540 + c * (144 ±0)` + // Minimum execution time: 26_969 nanoseconds. + Weight::from_parts(28_584_266, 6540) + // Standard Error: 93 + .saturating_add(Weight::from_ref_time(52_393).saturating_mul(c.into())) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + .saturating_add(Weight::from_proof_size(144).saturating_mul(c.into())) } - // Storage: Elections Candidates (r:1 w:1) + /// Storage: Elections Candidates (r:1 w:1) + /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `c` is `[1, 1000]`. fn renounce_candidacy_candidate(c: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `348 + c * (48 ±0)` + // Estimated: `830 + c * (48 ±0)` + // Minimum execution time: 23_635 nanoseconds. + Weight::from_parts(23_482_193, 830) + // Standard Error: 103 + .saturating_add(Weight::from_ref_time(33_759).saturating_mul(c.into())) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + .saturating_add(Weight::from_proof_size(48).saturating_mul(c.into())) } - // Storage: Elections Members (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) + /// Storage: Elections Members (r:1 w:1) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections RunnersUp (r:1 w:1) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Prime (r:1 w:1) + /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:0) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Members (r:0 w:1) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) fn renounce_candidacy_members() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `2027` + // Estimated: `12115` + // Minimum execution time: 39_124 nanoseconds. + Weight::from_parts(39_575_000, 12115) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) } - // Storage: Elections RunnersUp (r:1 w:1) + /// Storage: Elections RunnersUp (r:1 w:1) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) fn renounce_candidacy_runners_up() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `975` + // Estimated: `1470` + // Minimum execution time: 25_377 nanoseconds. + Weight::from_parts(25_696_000, 1470) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - // Storage: Benchmark Override (r:0 w:0) + /// Storage: Benchmark Override (r:0 w:0) + /// Proof Skipped: Benchmark Override (max_values: None, max_size: None, mode: Measured) fn remove_member_without_replacement() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` // Minimum execution time: 2_000_000_000 nanoseconds. - Weight::from_ref_time(2_000_000_000_000 as u64) + Weight::from_ref_time(2_000_000_000_000) } - // 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) + /// Storage: Elections Members (r:1 w:1) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Elections RunnersUp (r:1 w:1) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Prime (r:1 w:1) + /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:0) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Members (r:0 w:1) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) fn remove_member_with_replacement() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `2027` + // Estimated: `14718` + // Minimum execution time: 44_919 nanoseconds. + Weight::from_parts(45_548_000, 14718) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(5_u64)) } - // 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:5000 w:5000) - // Storage: System Account (r:5000 w:5000) + /// Storage: Elections Voting (r:10001 w:10000) + /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Elections Members (r:1 w:0) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections RunnersUp (r:1 w:0) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Candidates (r:1 w:0) + /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Balances Locks (r:10000 w:10000) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: System Account (r:10000 w:10000) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `v` is `[5000, 10000]`. /// The range of component `d` is `[0, 5000]`. fn clean_defunct_voters(v: u32, _d: u32, ) -> Weight { - // 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))) + // Proof Size summary in bytes: + // Measured: `36028 + v * (872 ±0)` + // Estimated: `149172 + v * (12340 ±0)` + // Minimum execution time: 297_544_939 nanoseconds. + Weight::from_parts(298_088_024_000, 149172) + // Standard Error: 264_599 + .saturating_add(Weight::from_ref_time(38_142_857).saturating_mul(v.into())) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(v.into()))) + .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(v.into()))) + .saturating_add(Weight::from_proof_size(12340).saturating_mul(v.into())) } - // 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: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:1 w:1) + /// Storage: Elections Candidates (r:1 w:1) + /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Members (r:1 w:1) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections RunnersUp (r:1 w:1) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Voting (r:10001 w:0) + /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:0) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: System Account (r:980 w:980) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Elections ElectionRounds (r:1 w:1) + /// Proof Skipped: Elections ElectionRounds (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Members (r:0 w:1) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Prime (r:0 w:1) + /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `c` is `[1, 1000]`. /// The range of component `v` is `[1, 10000]`. /// The range of component `e` is `[10000, 160000]`. fn election_phragmen(c: u32, v: u32, e: u32, ) -> Weight { - // 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))) + // Proof Size summary in bytes: + // Measured: `0 + v * (639 ±0) + e * (28 ±0)` + // Estimated: `5350105 + c * (2582 ±0) + v * (5721 ±6) + e * (123 ±0)` + // Minimum execution time: 21_844_965 nanoseconds. + Weight::from_parts(21_979_826_000, 5350105) + // Standard Error: 229_799 + .saturating_add(Weight::from_ref_time(24_976_612).saturating_mul(v.into())) + // Standard Error: 14_747 + .saturating_add(Weight::from_ref_time(1_025_848).saturating_mul(e.into())) + .saturating_add(RocksDbWeight::get().reads(280_u64)) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(c.into()))) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(v.into()))) + .saturating_add(RocksDbWeight::get().writes(6_u64)) + .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(c.into()))) + .saturating_add(Weight::from_proof_size(2582).saturating_mul(c.into())) + .saturating_add(Weight::from_proof_size(5721).saturating_mul(v.into())) + .saturating_add(Weight::from_proof_size(123).saturating_mul(e.into())) } } diff --git a/frame/identity/src/weights.rs b/frame/identity/src/weights.rs index 1f2e8f98e988b..7bcbf539d617a 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) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2023 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,7 +18,8 @@ //! Autogenerated weights for pallet_identity //! //! 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: `[]` +//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -68,420 +69,584 @@ pub trait WeightInfo { /// Weights for pallet_identity using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - // Storage: Identity Registrars (r:1 w:1) + /// Storage: Identity Registrars (r:1 w:1) + /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) /// The range of component `r` is `[1, 19]`. fn add_registrar(r: u32, ) -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `64 + r * (57 ±0)` + // Estimated: `1636` + // Minimum execution time: 10_964 nanoseconds. + Weight::from_parts(11_800_935, 1636) + // Standard Error: 1_334 + .saturating_add(Weight::from_ref_time(96_038).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Identity IdentityOf (r:1 w:1) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) /// The range of component `r` is `[1, 20]`. /// The range of component `x` is `[0, 100]`. fn set_identity(r: u32, x: u32, ) -> Weight { - // 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:2 w:2) + // Proof Size summary in bytes: + // Measured: `474 + r * (5 ±0)` + // Estimated: `10013` + // Minimum execution time: 26_400 nanoseconds. + Weight::from_parts(26_060_549, 10013) + // Standard Error: 1_561 + .saturating_add(Weight::from_ref_time(72_083).saturating_mul(r.into())) + // Standard Error: 304 + .saturating_add(Weight::from_ref_time(306_994).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Identity IdentityOf (r:1 w:0) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: Identity SubsOf (r:1 w:1) + /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) + /// Storage: Identity SuperOf (r:100 w:100) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) /// The range of component `s` is `[0, 100]`. fn set_subs_new(s: u32, ) -> Weight { - // 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)) - .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:2) + // Proof Size summary in bytes: + // Measured: `101` + // Estimated: `15746 + s * (2589 ±0)` + // Minimum execution time: 8_492 nanoseconds. + Weight::from_parts(21_645_924, 15746) + // Standard Error: 3_452 + .saturating_add(Weight::from_ref_time(2_442_604).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(s.into()))) + .saturating_add(T::DbWeight::get().writes(1_u64)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) + .saturating_add(Weight::from_proof_size(2589).saturating_mul(s.into())) + } + /// Storage: Identity IdentityOf (r:1 w:0) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: Identity SubsOf (r:1 w:1) + /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) + /// Storage: Identity SuperOf (r:0 w:100) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) /// The range of component `p` is `[0, 100]`. fn set_subs_old(p: u32, ) -> Weight { - // 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))) - } - // Storage: Identity SubsOf (r:1 w:1) - // Storage: Identity IdentityOf (r:1 w:1) - // Storage: Identity SuperOf (r:0 w:100) + // Proof Size summary in bytes: + // Measured: `226 + p * (32 ±0)` + // Estimated: `15746` + // Minimum execution time: 8_488 nanoseconds. + Weight::from_parts(20_202_601, 15746) + // Standard Error: 2_834 + .saturating_add(Weight::from_ref_time(1_082_941).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(p.into()))) + } + /// Storage: Identity SubsOf (r:1 w:1) + /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) + /// Storage: Identity IdentityOf (r:1 w:1) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: Identity SuperOf (r:0 w:100) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) /// The range of component `r` is `[1, 20]`. /// The range of component `s` is `[0, 100]`. /// The range of component `x` is `[0, 100]`. fn clear_identity(r: u32, s: u32, x: u32, ) -> Weight { - // 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))) - } - // Storage: Identity Registrars (r:1 w:0) - // Storage: Identity IdentityOf (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `533 + r * (5 ±0) + s * (32 ±0) + x * (66 ±0)` + // Estimated: `15746` + // Minimum execution time: 41_319 nanoseconds. + Weight::from_parts(25_850_055, 15746) + // Standard Error: 4_144 + .saturating_add(Weight::from_ref_time(59_619).saturating_mul(r.into())) + // Standard Error: 809 + .saturating_add(Weight::from_ref_time(1_076_550).saturating_mul(s.into())) + // Standard Error: 809 + .saturating_add(Weight::from_ref_time(163_191).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) + } + /// Storage: Identity Registrars (r:1 w:0) + /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) + /// Storage: Identity IdentityOf (r:1 w:1) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) /// The range of component `r` is `[1, 20]`. /// The range of component `x` is `[0, 100]`. fn request_judgement(r: u32, x: u32, ) -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `431 + r * (57 ±0) + x * (66 ±0)` + // Estimated: `11649` + // Minimum execution time: 28_118 nanoseconds. + Weight::from_parts(27_359_471, 11649) + // Standard Error: 2_707 + .saturating_add(Weight::from_ref_time(107_279).saturating_mul(r.into())) + // Standard Error: 528 + .saturating_add(Weight::from_ref_time(325_165).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Identity IdentityOf (r:1 w:1) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) /// The range of component `r` is `[1, 20]`. /// The range of component `x` is `[0, 100]`. fn cancel_request(r: u32, x: u32, ) -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `430 + x * (66 ±0)` + // Estimated: `10013` + // Minimum execution time: 24_817 nanoseconds. + Weight::from_parts(24_749_808, 10013) + // Standard Error: 1_938 + .saturating_add(Weight::from_ref_time(63_396).saturating_mul(r.into())) + // Standard Error: 378 + .saturating_add(Weight::from_ref_time(327_083).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Identity Registrars (r:1 w:1) + /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) /// The range of component `r` is `[1, 19]`. fn set_fee(r: u32, ) -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `121 + r * (57 ±0)` + // Estimated: `1636` + // Minimum execution time: 6_664 nanoseconds. + Weight::from_parts(7_286_307, 1636) + // Standard Error: 1_560 + .saturating_add(Weight::from_ref_time(96_416).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Identity Registrars (r:1 w:1) + /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) /// The range of component `r` is `[1, 19]`. fn set_account_id(r: u32, ) -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `121 + r * (57 ±0)` + // Estimated: `1636` + // Minimum execution time: 7_054 nanoseconds. + Weight::from_parts(7_382_954, 1636) + // Standard Error: 1_621 + .saturating_add(Weight::from_ref_time(101_595).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Identity Registrars (r:1 w:1) + /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) /// The range of component `r` is `[1, 19]`. fn set_fields(r: u32, ) -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `121 + r * (57 ±0)` + // Estimated: `1636` + // Minimum execution time: 6_659 nanoseconds. + Weight::from_parts(7_188_883, 1636) + // Standard Error: 1_377 + .saturating_add(Weight::from_ref_time(98_965).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Identity Registrars (r:1 w:0) + /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) + /// Storage: Identity IdentityOf (r:1 w:1) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) /// The range of component `r` is `[1, 19]`. /// The range of component `x` is `[0, 100]`. fn provide_judgement(r: u32, x: u32, ) -> Weight { - // 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)) - } - // Storage: Identity SubsOf (r:1 w:1) - // Storage: Identity IdentityOf (r:1 w:1) - // Storage: System Account (r:1 w:1) - // Storage: Identity SuperOf (r:0 w:100) + // Proof Size summary in bytes: + // Measured: `509 + r * (57 ±0) + x * (66 ±0)` + // Estimated: `11649` + // Minimum execution time: 21_567 nanoseconds. + Weight::from_parts(21_015_310, 11649) + // Standard Error: 2_516 + .saturating_add(Weight::from_ref_time(123_992).saturating_mul(r.into())) + // Standard Error: 465 + .saturating_add(Weight::from_ref_time(552_116).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Identity SubsOf (r:1 w:1) + /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) + /// Storage: Identity IdentityOf (r:1 w:1) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Identity SuperOf (r:0 w:100) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) /// The range of component `r` is `[1, 20]`. /// The range of component `s` is `[0, 100]`. /// The range of component `x` is `[0, 100]`. fn kill_identity(r: u32, s: u32, x: u32, ) -> Weight { - // 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))) - } - // Storage: Identity IdentityOf (r:1 w:0) - // Storage: Identity SuperOf (r:1 w:1) - // Storage: Identity SubsOf (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `772 + r * (5 ±0) + s * (32 ±0) + x * (66 ±0)` + // Estimated: `18349` + // Minimum execution time: 52_881 nanoseconds. + Weight::from_parts(38_504_388, 18349) + // Standard Error: 3_909 + .saturating_add(Weight::from_ref_time(51_452).saturating_mul(r.into())) + // Standard Error: 763 + .saturating_add(Weight::from_ref_time(1_069_924).saturating_mul(s.into())) + // Standard Error: 763 + .saturating_add(Weight::from_ref_time(164_906).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) + } + /// Storage: Identity IdentityOf (r:1 w:0) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: Identity SuperOf (r:1 w:1) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) + /// Storage: Identity SubsOf (r:1 w:1) + /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) /// The range of component `s` is `[0, 99]`. fn add_sub(s: u32, ) -> Weight { - // 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)) - } - // Storage: Identity IdentityOf (r:1 w:0) - // Storage: Identity SuperOf (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `507 + s * (36 ±0)` + // Estimated: `18335` + // Minimum execution time: 24_556 nanoseconds. + Weight::from_parts(28_641_160, 18335) + // Standard Error: 1_327 + .saturating_add(Weight::from_ref_time(66_150).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: Identity IdentityOf (r:1 w:0) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: Identity SuperOf (r:1 w:1) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) /// The range of component `s` is `[1, 100]`. fn rename_sub(s: u32, ) -> Weight { - // 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)) - } - // Storage: Identity IdentityOf (r:1 w:0) - // Storage: Identity SuperOf (r:1 w:1) - // Storage: Identity SubsOf (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `623 + s * (3 ±0)` + // Estimated: `12602` + // Minimum execution time: 11_347 nanoseconds. + Weight::from_parts(13_299_367, 12602) + // Standard Error: 525 + .saturating_add(Weight::from_ref_time(16_472).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Identity IdentityOf (r:1 w:0) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: Identity SuperOf (r:1 w:1) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) + /// Storage: Identity SubsOf (r:1 w:1) + /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) /// The range of component `s` is `[1, 100]`. fn remove_sub(s: u32, ) -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `702 + s * (35 ±0)` + // Estimated: `18335` + // Minimum execution time: 27_810 nanoseconds. + Weight::from_parts(30_347_763, 18335) + // Standard Error: 928 + .saturating_add(Weight::from_ref_time(55_342).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: Identity SuperOf (r:1 w:1) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) + /// Storage: Identity SubsOf (r:1 w:1) + /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) /// The range of component `s` is `[0, 99]`. fn quit_sub(s: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `628 + s * (37 ±0)` + // Estimated: `8322` + // Minimum execution time: 17_601 nanoseconds. + Weight::from_parts(19_794_971, 8322) + // Standard Error: 934 + .saturating_add(Weight::from_ref_time(59_289).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } } // For backwards compatibility and tests impl WeightInfo for () { - // Storage: Identity Registrars (r:1 w:1) + /// Storage: Identity Registrars (r:1 w:1) + /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) /// The range of component `r` is `[1, 19]`. fn add_registrar(r: u32, ) -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `64 + r * (57 ±0)` + // Estimated: `1636` + // Minimum execution time: 10_964 nanoseconds. + Weight::from_parts(11_800_935, 1636) + // Standard Error: 1_334 + .saturating_add(Weight::from_ref_time(96_038).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Identity IdentityOf (r:1 w:1) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) /// The range of component `r` is `[1, 20]`. /// The range of component `x` is `[0, 100]`. fn set_identity(r: u32, x: u32, ) -> Weight { - // 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:2 w:2) + // Proof Size summary in bytes: + // Measured: `474 + r * (5 ±0)` + // Estimated: `10013` + // Minimum execution time: 26_400 nanoseconds. + Weight::from_parts(26_060_549, 10013) + // Standard Error: 1_561 + .saturating_add(Weight::from_ref_time(72_083).saturating_mul(r.into())) + // Standard Error: 304 + .saturating_add(Weight::from_ref_time(306_994).saturating_mul(x.into())) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Identity IdentityOf (r:1 w:0) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: Identity SubsOf (r:1 w:1) + /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) + /// Storage: Identity SuperOf (r:100 w:100) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) /// The range of component `s` is `[0, 100]`. fn set_subs_new(s: u32, ) -> Weight { - // 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)) - .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:2) + // Proof Size summary in bytes: + // Measured: `101` + // Estimated: `15746 + s * (2589 ±0)` + // Minimum execution time: 8_492 nanoseconds. + Weight::from_parts(21_645_924, 15746) + // Standard Error: 3_452 + .saturating_add(Weight::from_ref_time(2_442_604).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(s.into()))) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) + .saturating_add(Weight::from_proof_size(2589).saturating_mul(s.into())) + } + /// Storage: Identity IdentityOf (r:1 w:0) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: Identity SubsOf (r:1 w:1) + /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) + /// Storage: Identity SuperOf (r:0 w:100) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) /// The range of component `p` is `[0, 100]`. fn set_subs_old(p: u32, ) -> Weight { - // 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))) - } - // Storage: Identity SubsOf (r:1 w:1) - // Storage: Identity IdentityOf (r:1 w:1) - // Storage: Identity SuperOf (r:0 w:100) + // Proof Size summary in bytes: + // Measured: `226 + p * (32 ±0)` + // Estimated: `15746` + // Minimum execution time: 8_488 nanoseconds. + Weight::from_parts(20_202_601, 15746) + // Standard Error: 2_834 + .saturating_add(Weight::from_ref_time(1_082_941).saturating_mul(p.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(p.into()))) + } + /// Storage: Identity SubsOf (r:1 w:1) + /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) + /// Storage: Identity IdentityOf (r:1 w:1) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: Identity SuperOf (r:0 w:100) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) /// The range of component `r` is `[1, 20]`. /// The range of component `s` is `[0, 100]`. /// The range of component `x` is `[0, 100]`. fn clear_identity(r: u32, s: u32, x: u32, ) -> Weight { - // 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))) - } - // Storage: Identity Registrars (r:1 w:0) - // Storage: Identity IdentityOf (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `533 + r * (5 ±0) + s * (32 ±0) + x * (66 ±0)` + // Estimated: `15746` + // Minimum execution time: 41_319 nanoseconds. + Weight::from_parts(25_850_055, 15746) + // Standard Error: 4_144 + .saturating_add(Weight::from_ref_time(59_619).saturating_mul(r.into())) + // Standard Error: 809 + .saturating_add(Weight::from_ref_time(1_076_550).saturating_mul(s.into())) + // Standard Error: 809 + .saturating_add(Weight::from_ref_time(163_191).saturating_mul(x.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) + } + /// Storage: Identity Registrars (r:1 w:0) + /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) + /// Storage: Identity IdentityOf (r:1 w:1) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) /// The range of component `r` is `[1, 20]`. /// The range of component `x` is `[0, 100]`. fn request_judgement(r: u32, x: u32, ) -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `431 + r * (57 ±0) + x * (66 ±0)` + // Estimated: `11649` + // Minimum execution time: 28_118 nanoseconds. + Weight::from_parts(27_359_471, 11649) + // Standard Error: 2_707 + .saturating_add(Weight::from_ref_time(107_279).saturating_mul(r.into())) + // Standard Error: 528 + .saturating_add(Weight::from_ref_time(325_165).saturating_mul(x.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Identity IdentityOf (r:1 w:1) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) /// The range of component `r` is `[1, 20]`. /// The range of component `x` is `[0, 100]`. fn cancel_request(r: u32, x: u32, ) -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `430 + x * (66 ±0)` + // Estimated: `10013` + // Minimum execution time: 24_817 nanoseconds. + Weight::from_parts(24_749_808, 10013) + // Standard Error: 1_938 + .saturating_add(Weight::from_ref_time(63_396).saturating_mul(r.into())) + // Standard Error: 378 + .saturating_add(Weight::from_ref_time(327_083).saturating_mul(x.into())) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Identity Registrars (r:1 w:1) + /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) /// The range of component `r` is `[1, 19]`. fn set_fee(r: u32, ) -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `121 + r * (57 ±0)` + // Estimated: `1636` + // Minimum execution time: 6_664 nanoseconds. + Weight::from_parts(7_286_307, 1636) + // Standard Error: 1_560 + .saturating_add(Weight::from_ref_time(96_416).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Identity Registrars (r:1 w:1) + /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) /// The range of component `r` is `[1, 19]`. fn set_account_id(r: u32, ) -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `121 + r * (57 ±0)` + // Estimated: `1636` + // Minimum execution time: 7_054 nanoseconds. + Weight::from_parts(7_382_954, 1636) + // Standard Error: 1_621 + .saturating_add(Weight::from_ref_time(101_595).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Identity Registrars (r:1 w:1) + /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) /// The range of component `r` is `[1, 19]`. fn set_fields(r: u32, ) -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `121 + r * (57 ±0)` + // Estimated: `1636` + // Minimum execution time: 6_659 nanoseconds. + Weight::from_parts(7_188_883, 1636) + // Standard Error: 1_377 + .saturating_add(Weight::from_ref_time(98_965).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Identity Registrars (r:1 w:0) + /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) + /// Storage: Identity IdentityOf (r:1 w:1) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) /// The range of component `r` is `[1, 19]`. /// The range of component `x` is `[0, 100]`. fn provide_judgement(r: u32, x: u32, ) -> Weight { - // 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)) - } - // Storage: Identity SubsOf (r:1 w:1) - // Storage: Identity IdentityOf (r:1 w:1) - // Storage: System Account (r:1 w:1) - // Storage: Identity SuperOf (r:0 w:100) + // Proof Size summary in bytes: + // Measured: `509 + r * (57 ±0) + x * (66 ±0)` + // Estimated: `11649` + // Minimum execution time: 21_567 nanoseconds. + Weight::from_parts(21_015_310, 11649) + // Standard Error: 2_516 + .saturating_add(Weight::from_ref_time(123_992).saturating_mul(r.into())) + // Standard Error: 465 + .saturating_add(Weight::from_ref_time(552_116).saturating_mul(x.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Identity SubsOf (r:1 w:1) + /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) + /// Storage: Identity IdentityOf (r:1 w:1) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Identity SuperOf (r:0 w:100) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) /// The range of component `r` is `[1, 20]`. /// The range of component `s` is `[0, 100]`. /// The range of component `x` is `[0, 100]`. fn kill_identity(r: u32, s: u32, x: u32, ) -> Weight { - // 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))) - } - // Storage: Identity IdentityOf (r:1 w:0) - // Storage: Identity SuperOf (r:1 w:1) - // Storage: Identity SubsOf (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `772 + r * (5 ±0) + s * (32 ±0) + x * (66 ±0)` + // Estimated: `18349` + // Minimum execution time: 52_881 nanoseconds. + Weight::from_parts(38_504_388, 18349) + // Standard Error: 3_909 + .saturating_add(Weight::from_ref_time(51_452).saturating_mul(r.into())) + // Standard Error: 763 + .saturating_add(Weight::from_ref_time(1_069_924).saturating_mul(s.into())) + // Standard Error: 763 + .saturating_add(Weight::from_ref_time(164_906).saturating_mul(x.into())) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) + } + /// Storage: Identity IdentityOf (r:1 w:0) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: Identity SuperOf (r:1 w:1) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) + /// Storage: Identity SubsOf (r:1 w:1) + /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) /// The range of component `s` is `[0, 99]`. fn add_sub(s: u32, ) -> Weight { - // 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)) - } - // Storage: Identity IdentityOf (r:1 w:0) - // Storage: Identity SuperOf (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `507 + s * (36 ±0)` + // Estimated: `18335` + // Minimum execution time: 24_556 nanoseconds. + Weight::from_parts(28_641_160, 18335) + // Standard Error: 1_327 + .saturating_add(Weight::from_ref_time(66_150).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: Identity IdentityOf (r:1 w:0) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: Identity SuperOf (r:1 w:1) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) /// The range of component `s` is `[1, 100]`. fn rename_sub(s: u32, ) -> Weight { - // 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)) - } - // Storage: Identity IdentityOf (r:1 w:0) - // Storage: Identity SuperOf (r:1 w:1) - // Storage: Identity SubsOf (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `623 + s * (3 ±0)` + // Estimated: `12602` + // Minimum execution time: 11_347 nanoseconds. + Weight::from_parts(13_299_367, 12602) + // Standard Error: 525 + .saturating_add(Weight::from_ref_time(16_472).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Identity IdentityOf (r:1 w:0) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: Identity SuperOf (r:1 w:1) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) + /// Storage: Identity SubsOf (r:1 w:1) + /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) /// The range of component `s` is `[1, 100]`. fn remove_sub(s: u32, ) -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `702 + s * (35 ±0)` + // Estimated: `18335` + // Minimum execution time: 27_810 nanoseconds. + Weight::from_parts(30_347_763, 18335) + // Standard Error: 928 + .saturating_add(Weight::from_ref_time(55_342).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: Identity SuperOf (r:1 w:1) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) + /// Storage: Identity SubsOf (r:1 w:1) + /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) /// The range of component `s` is `[0, 99]`. fn quit_sub(s: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `628 + s * (37 ±0)` + // Estimated: `8322` + // Minimum execution time: 17_601 nanoseconds. + Weight::from_parts(19_794_971, 8322) + // Standard Error: 934 + .saturating_add(Weight::from_ref_time(59_289).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } } diff --git a/frame/im-online/src/weights.rs b/frame/im-online/src/weights.rs index f81db997c303d..4ea275a33f792 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) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2023 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -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-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -53,42 +54,62 @@ pub trait WeightInfo { /// Weights for pallet_im_online using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - // Storage: Session Validators (r:1 w:0) - // Storage: Session CurrentIndex (r:1 w:0) - // Storage: ImOnline ReceivedHeartbeats (r:1 w:1) - // Storage: ImOnline AuthoredBlocks (r:1 w:0) - // Storage: ImOnline Keys (r:1 w:0) + /// Storage: Session Validators (r:1 w:0) + /// Proof Skipped: Session Validators (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Session CurrentIndex (r:1 w:0) + /// Proof Skipped: Session CurrentIndex (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ImOnline Keys (r:1 w:0) + /// Proof: ImOnline Keys (max_values: Some(1), max_size: Some(320002), added: 320497, mode: MaxEncodedLen) + /// Storage: ImOnline ReceivedHeartbeats (r:1 w:1) + /// Proof: ImOnline ReceivedHeartbeats (max_values: None, max_size: Some(10021032), added: 10023507, mode: MaxEncodedLen) + /// Storage: ImOnline AuthoredBlocks (r:1 w:0) + /// Proof: ImOnline AuthoredBlocks (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) /// The range of component `k` is `[1, 1000]`. /// The range of component `e` is `[1, 100]`. fn validate_unsigned_and_then_heartbeat(k: u32, e: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `359 + k * (32 ±0)` + // Estimated: `10345712 + e * (25 ±0) + k * (64 ±0)` + // Minimum execution time: 91_116 nanoseconds. + Weight::from_parts(72_526_877, 10345712) + // Standard Error: 95 + .saturating_add(Weight::from_ref_time(20_461).saturating_mul(k.into())) + // Standard Error: 967 + .saturating_add(Weight::from_ref_time(307_869).saturating_mul(e.into())) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + .saturating_add(Weight::from_proof_size(25).saturating_mul(e.into())) + .saturating_add(Weight::from_proof_size(64).saturating_mul(k.into())) } } // For backwards compatibility and tests impl WeightInfo for () { - // Storage: Session Validators (r:1 w:0) - // Storage: Session CurrentIndex (r:1 w:0) - // Storage: ImOnline ReceivedHeartbeats (r:1 w:1) - // Storage: ImOnline AuthoredBlocks (r:1 w:0) - // Storage: ImOnline Keys (r:1 w:0) + /// Storage: Session Validators (r:1 w:0) + /// Proof Skipped: Session Validators (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Session CurrentIndex (r:1 w:0) + /// Proof Skipped: Session CurrentIndex (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ImOnline Keys (r:1 w:0) + /// Proof: ImOnline Keys (max_values: Some(1), max_size: Some(320002), added: 320497, mode: MaxEncodedLen) + /// Storage: ImOnline ReceivedHeartbeats (r:1 w:1) + /// Proof: ImOnline ReceivedHeartbeats (max_values: None, max_size: Some(10021032), added: 10023507, mode: MaxEncodedLen) + /// Storage: ImOnline AuthoredBlocks (r:1 w:0) + /// Proof: ImOnline AuthoredBlocks (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) /// The range of component `k` is `[1, 1000]`. /// The range of component `e` is `[1, 100]`. fn validate_unsigned_and_then_heartbeat(k: u32, e: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `359 + k * (32 ±0)` + // Estimated: `10345712 + e * (25 ±0) + k * (64 ±0)` + // Minimum execution time: 91_116 nanoseconds. + Weight::from_parts(72_526_877, 10345712) + // Standard Error: 95 + .saturating_add(Weight::from_ref_time(20_461).saturating_mul(k.into())) + // Standard Error: 967 + .saturating_add(Weight::from_ref_time(307_869).saturating_mul(e.into())) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + .saturating_add(Weight::from_proof_size(25).saturating_mul(e.into())) + .saturating_add(Weight::from_proof_size(64).saturating_mul(k.into())) } } diff --git a/frame/indices/src/weights.rs b/frame/indices/src/weights.rs index 7b974875cdf51..36dd79ece4c9e 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) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2023 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -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-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -57,82 +58,126 @@ pub trait WeightInfo { /// Weights for pallet_indices using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - // Storage: Indices Accounts (r:1 w:1) + /// Storage: Indices Accounts (r:1 w:1) + /// Proof: Indices Accounts (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) fn claim() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `76` + // Estimated: `2544` + // Minimum execution time: 19_738 nanoseconds. + Weight::from_parts(20_029_000, 2544) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - // Storage: Indices Accounts (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: Indices Accounts (r:1 w:1) + /// Proof: Indices Accounts (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `339` + // Estimated: `5147` + // Minimum execution time: 24_494 nanoseconds. + Weight::from_parts(24_794_000, 5147) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } - // Storage: Indices Accounts (r:1 w:1) + /// Storage: Indices Accounts (r:1 w:1) + /// Proof: Indices Accounts (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) fn free() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `204` + // Estimated: `2544` + // Minimum execution time: 20_041 nanoseconds. + Weight::from_parts(20_473_000, 2544) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - // Storage: Indices Accounts (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: Indices Accounts (r:1 w:1) + /// Proof: Indices Accounts (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn force_transfer() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `339` + // Estimated: `5147` + // Minimum execution time: 21_874 nanoseconds. + Weight::from_parts(22_438_000, 5147) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } - // Storage: Indices Accounts (r:1 w:1) + /// Storage: Indices Accounts (r:1 w:1) + /// Proof: Indices Accounts (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) fn freeze() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `204` + // Estimated: `2544` + // Minimum execution time: 22_407 nanoseconds. + Weight::from_parts(22_768_000, 2544) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } } // For backwards compatibility and tests impl WeightInfo for () { - // Storage: Indices Accounts (r:1 w:1) + /// Storage: Indices Accounts (r:1 w:1) + /// Proof: Indices Accounts (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) fn claim() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `76` + // Estimated: `2544` + // Minimum execution time: 19_738 nanoseconds. + Weight::from_parts(20_029_000, 2544) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - // Storage: Indices Accounts (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: Indices Accounts (r:1 w:1) + /// Proof: Indices Accounts (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `339` + // Estimated: `5147` + // Minimum execution time: 24_494 nanoseconds. + Weight::from_parts(24_794_000, 5147) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } - // Storage: Indices Accounts (r:1 w:1) + /// Storage: Indices Accounts (r:1 w:1) + /// Proof: Indices Accounts (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) fn free() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `204` + // Estimated: `2544` + // Minimum execution time: 20_041 nanoseconds. + Weight::from_parts(20_473_000, 2544) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - // Storage: Indices Accounts (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: Indices Accounts (r:1 w:1) + /// Proof: Indices Accounts (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn force_transfer() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `339` + // Estimated: `5147` + // Minimum execution time: 21_874 nanoseconds. + Weight::from_parts(22_438_000, 5147) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } - // Storage: Indices Accounts (r:1 w:1) + /// Storage: Indices Accounts (r:1 w:1) + /// Proof: Indices Accounts (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) fn freeze() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `204` + // Estimated: `2544` + // Minimum execution time: 22_407 nanoseconds. + Weight::from_parts(22_768_000, 2544) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } } diff --git a/frame/lottery/src/weights.rs b/frame/lottery/src/weights.rs index e9ee528cc43b8..e2cf9ea2b74cc 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) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2023 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,25 +18,25 @@ //! Autogenerated weights for pallet_lottery //! //! 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` +//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! 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_lottery // --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_lottery -// --chain=dev -// --header=./HEADER-APACHE2 // --output=./frame/lottery/src/weights.rs +// --header=./HEADER-APACHE2 // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -59,130 +59,212 @@ pub trait WeightInfo { /// Weights for pallet_lottery using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - // Storage: Lottery Lottery (r:1 w:0) - // Storage: Lottery CallIndices (r:1 w:0) - // Storage: Lottery TicketsCount (r:1 w:1) - // Storage: Lottery Participants (r:1 w:1) - // Storage: Lottery LotteryIndex (r:1 w:0) - // Storage: System Account (r:1 w:1) - // Storage: Lottery Tickets (r:0 w:1) + /// Storage: Lottery Lottery (r:1 w:0) + /// Proof: Lottery Lottery (max_values: Some(1), max_size: Some(29), added: 524, mode: MaxEncodedLen) + /// Storage: Lottery CallIndices (r:1 w:0) + /// Proof: Lottery CallIndices (max_values: Some(1), max_size: Some(21), added: 516, mode: MaxEncodedLen) + /// Storage: Lottery TicketsCount (r:1 w:1) + /// Proof: Lottery TicketsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Lottery Participants (r:1 w:1) + /// Proof: Lottery Participants (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) + /// Storage: Lottery LotteryIndex (r:1 w:0) + /// Proof: Lottery LotteryIndex (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Lottery Tickets (r:0 w:1) + /// Proof: Lottery Tickets (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) fn buy_ticket() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `484` + // Estimated: `7181` + // Minimum execution time: 62_125 nanoseconds. + Weight::from_parts(63_145_000, 7181) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) } - // Storage: Lottery CallIndices (r:0 w:1) + /// Storage: Lottery CallIndices (r:0 w:1) + /// Proof: Lottery CallIndices (max_values: Some(1), max_size: Some(21), added: 516, mode: MaxEncodedLen) /// The range of component `n` is `[0, 10]`. fn set_calls(n: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 7_650 nanoseconds. + Weight::from_ref_time(8_344_960) + // Standard Error: 2_629 + .saturating_add(Weight::from_ref_time(268_557).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - // Storage: Lottery Lottery (r:1 w:1) - // Storage: Lottery LotteryIndex (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: Lottery Lottery (r:1 w:1) + /// Proof: Lottery Lottery (max_values: Some(1), max_size: Some(29), added: 524, mode: MaxEncodedLen) + /// Storage: Lottery LotteryIndex (r:1 w:1) + /// Proof: Lottery LotteryIndex (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn start_lottery() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `161` + // Estimated: `3626` + // Minimum execution time: 31_324 nanoseconds. + Weight::from_parts(31_985_000, 3626) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) } - // Storage: Lottery Lottery (r:1 w:1) + /// Storage: Lottery Lottery (r:1 w:1) + /// Proof: Lottery Lottery (max_values: Some(1), max_size: Some(29), added: 524, mode: MaxEncodedLen) fn stop_repeat() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `219` + // Estimated: `524` + // Minimum execution time: 7_124 nanoseconds. + Weight::from_parts(7_285_000, 524) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) - // Storage: Lottery Lottery (r:1 w:1) - // Storage: System Account (r:2 w:2) - // Storage: Lottery TicketsCount (r:1 w:1) - // Storage: Lottery Tickets (r:1 w:0) + /// Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) + /// Proof: RandomnessCollectiveFlip RandomMaterial (max_values: Some(1), max_size: Some(2594), added: 3089, mode: MaxEncodedLen) + /// Storage: Lottery Lottery (r:1 w:1) + /// Proof: Lottery Lottery (max_values: Some(1), max_size: Some(29), added: 524, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Lottery TicketsCount (r:1 w:1) + /// Proof: Lottery TicketsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Lottery Tickets (r:1 w:0) + /// Proof: Lottery Tickets (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) fn on_initialize_end() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `556` + // Estimated: `11837` + // Minimum execution time: 50_745 nanoseconds. + Weight::from_parts(52_232_000, 11837) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) } - // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) - // Storage: Lottery Lottery (r:1 w:1) - // Storage: System Account (r:2 w:2) - // Storage: Lottery TicketsCount (r:1 w:1) - // Storage: Lottery Tickets (r:1 w:0) - // Storage: Lottery LotteryIndex (r:1 w:1) + /// Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) + /// Proof: RandomnessCollectiveFlip RandomMaterial (max_values: Some(1), max_size: Some(2594), added: 3089, mode: MaxEncodedLen) + /// Storage: Lottery Lottery (r:1 w:1) + /// Proof: Lottery Lottery (max_values: Some(1), max_size: Some(29), added: 524, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Lottery TicketsCount (r:1 w:1) + /// Proof: Lottery TicketsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Lottery Tickets (r:1 w:0) + /// Proof: Lottery Tickets (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) + /// Storage: Lottery LotteryIndex (r:1 w:1) + /// Proof: Lottery LotteryIndex (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn on_initialize_repeat() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `556` + // Estimated: `12336` + // Minimum execution time: 52_437 nanoseconds. + Weight::from_parts(53_063_000, 12336) + .saturating_add(T::DbWeight::get().reads(7_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) } } // For backwards compatibility and tests impl WeightInfo for () { - // Storage: Lottery Lottery (r:1 w:0) - // Storage: Lottery CallIndices (r:1 w:0) - // Storage: Lottery TicketsCount (r:1 w:1) - // Storage: Lottery Participants (r:1 w:1) - // Storage: Lottery LotteryIndex (r:1 w:0) - // Storage: System Account (r:1 w:1) - // Storage: Lottery Tickets (r:0 w:1) + /// Storage: Lottery Lottery (r:1 w:0) + /// Proof: Lottery Lottery (max_values: Some(1), max_size: Some(29), added: 524, mode: MaxEncodedLen) + /// Storage: Lottery CallIndices (r:1 w:0) + /// Proof: Lottery CallIndices (max_values: Some(1), max_size: Some(21), added: 516, mode: MaxEncodedLen) + /// Storage: Lottery TicketsCount (r:1 w:1) + /// Proof: Lottery TicketsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Lottery Participants (r:1 w:1) + /// Proof: Lottery Participants (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) + /// Storage: Lottery LotteryIndex (r:1 w:0) + /// Proof: Lottery LotteryIndex (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Lottery Tickets (r:0 w:1) + /// Proof: Lottery Tickets (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) fn buy_ticket() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `484` + // Estimated: `7181` + // Minimum execution time: 62_125 nanoseconds. + Weight::from_parts(63_145_000, 7181) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) } - // Storage: Lottery CallIndices (r:0 w:1) + /// Storage: Lottery CallIndices (r:0 w:1) + /// Proof: Lottery CallIndices (max_values: Some(1), max_size: Some(21), added: 516, mode: MaxEncodedLen) /// The range of component `n` is `[0, 10]`. fn set_calls(n: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 7_650 nanoseconds. + Weight::from_ref_time(8_344_960) + // Standard Error: 2_629 + .saturating_add(Weight::from_ref_time(268_557).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - // Storage: Lottery Lottery (r:1 w:1) - // Storage: Lottery LotteryIndex (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: Lottery Lottery (r:1 w:1) + /// Proof: Lottery Lottery (max_values: Some(1), max_size: Some(29), added: 524, mode: MaxEncodedLen) + /// Storage: Lottery LotteryIndex (r:1 w:1) + /// Proof: Lottery LotteryIndex (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn start_lottery() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `161` + // Estimated: `3626` + // Minimum execution time: 31_324 nanoseconds. + Weight::from_parts(31_985_000, 3626) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) } - // Storage: Lottery Lottery (r:1 w:1) + /// Storage: Lottery Lottery (r:1 w:1) + /// Proof: Lottery Lottery (max_values: Some(1), max_size: Some(29), added: 524, mode: MaxEncodedLen) fn stop_repeat() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `219` + // Estimated: `524` + // Minimum execution time: 7_124 nanoseconds. + Weight::from_parts(7_285_000, 524) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) - // Storage: Lottery Lottery (r:1 w:1) - // Storage: System Account (r:2 w:2) - // Storage: Lottery TicketsCount (r:1 w:1) - // Storage: Lottery Tickets (r:1 w:0) + /// Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) + /// Proof: RandomnessCollectiveFlip RandomMaterial (max_values: Some(1), max_size: Some(2594), added: 3089, mode: MaxEncodedLen) + /// Storage: Lottery Lottery (r:1 w:1) + /// Proof: Lottery Lottery (max_values: Some(1), max_size: Some(29), added: 524, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Lottery TicketsCount (r:1 w:1) + /// Proof: Lottery TicketsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Lottery Tickets (r:1 w:0) + /// Proof: Lottery Tickets (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) fn on_initialize_end() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `556` + // Estimated: `11837` + // Minimum execution time: 50_745 nanoseconds. + Weight::from_parts(52_232_000, 11837) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) } - // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) - // Storage: Lottery Lottery (r:1 w:1) - // Storage: System Account (r:2 w:2) - // Storage: Lottery TicketsCount (r:1 w:1) - // Storage: Lottery Tickets (r:1 w:0) - // Storage: Lottery LotteryIndex (r:1 w:1) + /// Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) + /// Proof: RandomnessCollectiveFlip RandomMaterial (max_values: Some(1), max_size: Some(2594), added: 3089, mode: MaxEncodedLen) + /// Storage: Lottery Lottery (r:1 w:1) + /// Proof: Lottery Lottery (max_values: Some(1), max_size: Some(29), added: 524, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Lottery TicketsCount (r:1 w:1) + /// Proof: Lottery TicketsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Lottery Tickets (r:1 w:0) + /// Proof: Lottery Tickets (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) + /// Storage: Lottery LotteryIndex (r:1 w:1) + /// Proof: Lottery LotteryIndex (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn on_initialize_repeat() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `556` + // Estimated: `12336` + // Minimum execution time: 52_437 nanoseconds. + Weight::from_parts(53_063_000, 12336) + .saturating_add(RocksDbWeight::get().reads(7_u64)) + .saturating_add(RocksDbWeight::get().writes(5_u64)) } } diff --git a/frame/membership/src/weights.rs b/frame/membership/src/weights.rs index 11574bc8fa399..1be50afc5254d 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) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2023 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -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-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -59,190 +60,302 @@ pub trait WeightInfo { /// Weights for pallet_membership using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - // 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) + /// Storage: TechnicalMembership Members (r:1 w:1) + /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) + /// Storage: TechnicalCommittee Proposals (r:1 w:0) + /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: TechnicalCommittee Members (r:0 w:1) + /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: TechnicalCommittee Prime (r:0 w:1) + /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `m` is `[1, 99]`. fn add_member(m: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `238 + m * (64 ±0)` + // Estimated: `4903 + m * (192 ±0)` + // Minimum execution time: 15_673 nanoseconds. + Weight::from_parts(16_830_288, 4903) + // Standard Error: 570 + .saturating_add(Weight::from_ref_time(41_959).saturating_mul(m.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(192).saturating_mul(m.into())) } - // 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) + /// Storage: TechnicalMembership Members (r:1 w:1) + /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) + /// Storage: TechnicalCommittee Proposals (r:1 w:0) + /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: TechnicalMembership Prime (r:1 w:0) + /// Proof: TechnicalMembership Prime (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + /// Storage: TechnicalCommittee Members (r:0 w:1) + /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: TechnicalCommittee Prime (r:0 w:1) + /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `m` is `[2, 100]`. fn remove_member(m: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `342 + m * (64 ±0)` + // Estimated: `5742 + m * (192 ±0)` + // Minimum execution time: 18_231 nanoseconds. + Weight::from_parts(19_081_297, 5742) + // Standard Error: 571 + .saturating_add(Weight::from_ref_time(41_331).saturating_mul(m.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(192).saturating_mul(m.into())) } - // 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) + /// Storage: TechnicalMembership Members (r:1 w:1) + /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) + /// Storage: TechnicalCommittee Proposals (r:1 w:0) + /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: TechnicalMembership Prime (r:1 w:0) + /// Proof: TechnicalMembership Prime (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + /// Storage: TechnicalCommittee Members (r:0 w:1) + /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: TechnicalCommittee Prime (r:0 w:1) + /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `m` is `[2, 100]`. fn swap_member(m: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `342 + m * (64 ±0)` + // Estimated: `5742 + m * (192 ±0)` + // Minimum execution time: 18_517 nanoseconds. + Weight::from_parts(19_388_310, 5742) + // Standard Error: 625 + .saturating_add(Weight::from_ref_time(51_422).saturating_mul(m.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(192).saturating_mul(m.into())) } - // 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) + /// Storage: TechnicalMembership Members (r:1 w:1) + /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) + /// Storage: TechnicalCommittee Proposals (r:1 w:0) + /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: TechnicalMembership Prime (r:1 w:0) + /// Proof: TechnicalMembership Prime (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + /// Storage: TechnicalCommittee Members (r:0 w:1) + /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: TechnicalCommittee Prime (r:0 w:1) + /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `m` is `[1, 100]`. fn reset_member(m: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `342 + m * (64 ±0)` + // Estimated: `5742 + m * (192 ±0)` + // Minimum execution time: 17_628 nanoseconds. + Weight::from_parts(19_258_882, 5742) + // Standard Error: 820 + .saturating_add(Weight::from_ref_time(153_956).saturating_mul(m.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(192).saturating_mul(m.into())) } - // 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) + /// Storage: TechnicalMembership Members (r:1 w:1) + /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) + /// Storage: TechnicalCommittee Proposals (r:1 w:0) + /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: TechnicalMembership Prime (r:1 w:1) + /// Proof: TechnicalMembership Prime (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + /// Storage: TechnicalCommittee Members (r:0 w:1) + /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: TechnicalCommittee Prime (r:0 w:1) + /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `m` is `[1, 100]`. fn change_key(m: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `342 + m * (64 ±0)` + // Estimated: `5742 + m * (192 ±0)` + // Minimum execution time: 19_031 nanoseconds. + Weight::from_parts(20_264_948, 5742) + // Standard Error: 707 + .saturating_add(Weight::from_ref_time(51_060).saturating_mul(m.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + .saturating_add(Weight::from_proof_size(192).saturating_mul(m.into())) } - // Storage: TechnicalMembership Members (r:1 w:0) - // Storage: TechnicalMembership Prime (r:0 w:1) - // Storage: TechnicalCommittee Prime (r:0 w:1) + /// Storage: TechnicalMembership Members (r:1 w:0) + /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) + /// Storage: TechnicalMembership Prime (r:0 w:1) + /// Proof: TechnicalMembership Prime (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + /// Storage: TechnicalCommittee Prime (r:0 w:1) + /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `m` is `[1, 100]`. fn set_prime(m: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `64 + m * (32 ±0)` + // Estimated: `3761 + m * (32 ±0)` + // Minimum execution time: 6_897 nanoseconds. + Weight::from_parts(7_455_387, 3761) + // Standard Error: 326 + .saturating_add(Weight::from_ref_time(16_653).saturating_mul(m.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_proof_size(32).saturating_mul(m.into())) } - // Storage: TechnicalMembership Prime (r:0 w:1) - // Storage: TechnicalCommittee Prime (r:0 w:1) + /// Storage: TechnicalMembership Prime (r:0 w:1) + /// Proof: TechnicalMembership Prime (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + /// Storage: TechnicalCommittee Prime (r:0 w:1) + /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `m` is `[1, 100]`. fn clear_prime(m: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_400 nanoseconds. + Weight::from_ref_time(3_703_421) + // Standard Error: 119 + .saturating_add(Weight::from_ref_time(915).saturating_mul(m.into())) + .saturating_add(T::DbWeight::get().writes(2_u64)) } } // For backwards compatibility and tests impl WeightInfo for () { - // 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) + /// Storage: TechnicalMembership Members (r:1 w:1) + /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) + /// Storage: TechnicalCommittee Proposals (r:1 w:0) + /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: TechnicalCommittee Members (r:0 w:1) + /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: TechnicalCommittee Prime (r:0 w:1) + /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `m` is `[1, 99]`. fn add_member(m: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `238 + m * (64 ±0)` + // Estimated: `4903 + m * (192 ±0)` + // Minimum execution time: 15_673 nanoseconds. + Weight::from_parts(16_830_288, 4903) + // Standard Error: 570 + .saturating_add(Weight::from_ref_time(41_959).saturating_mul(m.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(192).saturating_mul(m.into())) } - // 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) + /// Storage: TechnicalMembership Members (r:1 w:1) + /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) + /// Storage: TechnicalCommittee Proposals (r:1 w:0) + /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: TechnicalMembership Prime (r:1 w:0) + /// Proof: TechnicalMembership Prime (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + /// Storage: TechnicalCommittee Members (r:0 w:1) + /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: TechnicalCommittee Prime (r:0 w:1) + /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `m` is `[2, 100]`. fn remove_member(m: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `342 + m * (64 ±0)` + // Estimated: `5742 + m * (192 ±0)` + // Minimum execution time: 18_231 nanoseconds. + Weight::from_parts(19_081_297, 5742) + // Standard Error: 571 + .saturating_add(Weight::from_ref_time(41_331).saturating_mul(m.into())) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(192).saturating_mul(m.into())) } - // 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) + /// Storage: TechnicalMembership Members (r:1 w:1) + /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) + /// Storage: TechnicalCommittee Proposals (r:1 w:0) + /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: TechnicalMembership Prime (r:1 w:0) + /// Proof: TechnicalMembership Prime (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + /// Storage: TechnicalCommittee Members (r:0 w:1) + /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: TechnicalCommittee Prime (r:0 w:1) + /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `m` is `[2, 100]`. fn swap_member(m: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `342 + m * (64 ±0)` + // Estimated: `5742 + m * (192 ±0)` + // Minimum execution time: 18_517 nanoseconds. + Weight::from_parts(19_388_310, 5742) + // Standard Error: 625 + .saturating_add(Weight::from_ref_time(51_422).saturating_mul(m.into())) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(192).saturating_mul(m.into())) } - // 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) + /// Storage: TechnicalMembership Members (r:1 w:1) + /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) + /// Storage: TechnicalCommittee Proposals (r:1 w:0) + /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: TechnicalMembership Prime (r:1 w:0) + /// Proof: TechnicalMembership Prime (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + /// Storage: TechnicalCommittee Members (r:0 w:1) + /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: TechnicalCommittee Prime (r:0 w:1) + /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `m` is `[1, 100]`. fn reset_member(m: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `342 + m * (64 ±0)` + // Estimated: `5742 + m * (192 ±0)` + // Minimum execution time: 17_628 nanoseconds. + Weight::from_parts(19_258_882, 5742) + // Standard Error: 820 + .saturating_add(Weight::from_ref_time(153_956).saturating_mul(m.into())) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(192).saturating_mul(m.into())) } - // 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) + /// Storage: TechnicalMembership Members (r:1 w:1) + /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) + /// Storage: TechnicalCommittee Proposals (r:1 w:0) + /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: TechnicalMembership Prime (r:1 w:1) + /// Proof: TechnicalMembership Prime (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + /// Storage: TechnicalCommittee Members (r:0 w:1) + /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: TechnicalCommittee Prime (r:0 w:1) + /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `m` is `[1, 100]`. fn change_key(m: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `342 + m * (64 ±0)` + // Estimated: `5742 + m * (192 ±0)` + // Minimum execution time: 19_031 nanoseconds. + Weight::from_parts(20_264_948, 5742) + // Standard Error: 707 + .saturating_add(Weight::from_ref_time(51_060).saturating_mul(m.into())) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + .saturating_add(Weight::from_proof_size(192).saturating_mul(m.into())) } - // Storage: TechnicalMembership Members (r:1 w:0) - // Storage: TechnicalMembership Prime (r:0 w:1) - // Storage: TechnicalCommittee Prime (r:0 w:1) + /// Storage: TechnicalMembership Members (r:1 w:0) + /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) + /// Storage: TechnicalMembership Prime (r:0 w:1) + /// Proof: TechnicalMembership Prime (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + /// Storage: TechnicalCommittee Prime (r:0 w:1) + /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `m` is `[1, 100]`. fn set_prime(m: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `64 + m * (32 ±0)` + // Estimated: `3761 + m * (32 ±0)` + // Minimum execution time: 6_897 nanoseconds. + Weight::from_parts(7_455_387, 3761) + // Standard Error: 326 + .saturating_add(Weight::from_ref_time(16_653).saturating_mul(m.into())) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_proof_size(32).saturating_mul(m.into())) } - // Storage: TechnicalMembership Prime (r:0 w:1) - // Storage: TechnicalCommittee Prime (r:0 w:1) + /// Storage: TechnicalMembership Prime (r:0 w:1) + /// Proof: TechnicalMembership Prime (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + /// Storage: TechnicalCommittee Prime (r:0 w:1) + /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `m` is `[1, 100]`. fn clear_prime(m: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_400 nanoseconds. + Weight::from_ref_time(3_703_421) + // Standard Error: 119 + .saturating_add(Weight::from_ref_time(915).saturating_mul(m.into())) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } } diff --git a/frame/message-queue/src/weights.rs b/frame/message-queue/src/weights.rs index cd9268ffde224..325fc208301de 100644 --- a/frame/message-queue/src/weights.rs +++ b/frame/message-queue/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2023 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,25 +18,25 @@ //! 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` +//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! 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_message_queue // --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 +// --header=./HEADER-APACHE2 // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -63,154 +63,244 @@ pub trait WeightInfo { /// 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) + /// Storage: MessageQueue ServiceHead (r:1 w:0) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + /// Storage: MessageQueue BookStateFor (r:2 w:2) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) fn ready_ring_knit() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `837` + // Estimated: `5554` + // Minimum execution time: 12_676 nanoseconds. + Weight::from_parts(13_113_000, 5554) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } - // Storage: MessageQueue BookStateFor (r:2 w:2) - // Storage: MessageQueue ServiceHead (r:1 w:1) + /// Storage: MessageQueue BookStateFor (r:2 w:2) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue ServiceHead (r:1 w:1) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) fn ready_ring_unknit() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `837` + // Estimated: `5554` + // Minimum execution time: 12_654 nanoseconds. + Weight::from_parts(12_969_000, 5554) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) } - // Storage: MessageQueue BookStateFor (r:1 w:1) + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) 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)) + // Proof Size summary in bytes: + // Measured: `576` + // Estimated: `2527` + // Minimum execution time: 5_096 nanoseconds. + Weight::from_parts(5_280_000, 2527) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - // Storage: MessageQueue Pages (r:1 w:1) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) fn service_page_base_completion() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `648` + // Estimated: `68060` + // Minimum execution time: 7_291 nanoseconds. + Weight::from_parts(7_564_000, 68060) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - // Storage: MessageQueue Pages (r:1 w:1) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) fn service_page_base_no_completion() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `648` + // Estimated: `68060` + // Minimum execution time: 7_401 nanoseconds. + Weight::from_parts(7_681_000, 68060) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } fn service_page_item() -> Weight { - // Minimum execution time: 79_657 nanoseconds. - Weight::from_ref_time(80_050_000) + // Proof Size summary in bytes: + // Measured: `972` + // Estimated: `0` + // Minimum execution time: 79_412 nanoseconds. + Weight::from_ref_time(79_816_000) } - // Storage: MessageQueue ServiceHead (r:1 w:1) - // Storage: MessageQueue BookStateFor (r:1 w:0) + /// Storage: MessageQueue ServiceHead (r:1 w:1) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + /// Storage: MessageQueue BookStateFor (r:1 w:0) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) fn bump_service_head() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `712` + // Estimated: `3027` + // Minimum execution time: 8_258 nanoseconds. + Weight::from_parts(8_438_000, 3027) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - // Storage: MessageQueue BookStateFor (r:1 w:1) - // Storage: MessageQueue Pages (r:1 w:1) + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) 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)) + // Proof Size summary in bytes: + // Measured: `66827` + // Estimated: `70587` + // Minimum execution time: 61_361 nanoseconds. + Weight::from_parts(62_103_000, 70587) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } - // Storage: MessageQueue BookStateFor (r:1 w:1) - // Storage: MessageQueue Pages (r:1 w:1) + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) fn execute_overweight_page_removed() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `66827` + // Estimated: `70587` + // Minimum execution time: 75_153 nanoseconds. + Weight::from_parts(76_093_000, 70587) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } - // Storage: MessageQueue BookStateFor (r:1 w:1) - // Storage: MessageQueue Pages (r:1 w:1) + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) fn execute_overweight_page_updated() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `66827` + // Estimated: `70587` + // Minimum execution time: 88_272 nanoseconds. + Weight::from_parts(89_373_000, 70587) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } } // For backwards compatibility and tests impl WeightInfo for () { - // Storage: MessageQueue ServiceHead (r:1 w:0) - // Storage: MessageQueue BookStateFor (r:2 w:2) + /// Storage: MessageQueue ServiceHead (r:1 w:0) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + /// Storage: MessageQueue BookStateFor (r:2 w:2) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) fn ready_ring_knit() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `837` + // Estimated: `5554` + // Minimum execution time: 12_676 nanoseconds. + Weight::from_parts(13_113_000, 5554) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } - // Storage: MessageQueue BookStateFor (r:2 w:2) - // Storage: MessageQueue ServiceHead (r:1 w:1) + /// Storage: MessageQueue BookStateFor (r:2 w:2) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue ServiceHead (r:1 w:1) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) fn ready_ring_unknit() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `837` + // Estimated: `5554` + // Minimum execution time: 12_654 nanoseconds. + Weight::from_parts(12_969_000, 5554) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) } - // Storage: MessageQueue BookStateFor (r:1 w:1) + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) 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)) + // Proof Size summary in bytes: + // Measured: `576` + // Estimated: `2527` + // Minimum execution time: 5_096 nanoseconds. + Weight::from_parts(5_280_000, 2527) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - // Storage: MessageQueue Pages (r:1 w:1) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) fn service_page_base_completion() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `648` + // Estimated: `68060` + // Minimum execution time: 7_291 nanoseconds. + Weight::from_parts(7_564_000, 68060) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - // Storage: MessageQueue Pages (r:1 w:1) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) fn service_page_base_no_completion() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `648` + // Estimated: `68060` + // Minimum execution time: 7_401 nanoseconds. + Weight::from_parts(7_681_000, 68060) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } fn service_page_item() -> Weight { - // Minimum execution time: 79_657 nanoseconds. - Weight::from_ref_time(80_050_000) + // Proof Size summary in bytes: + // Measured: `972` + // Estimated: `0` + // Minimum execution time: 79_412 nanoseconds. + Weight::from_ref_time(79_816_000) } - // Storage: MessageQueue ServiceHead (r:1 w:1) - // Storage: MessageQueue BookStateFor (r:1 w:0) + /// Storage: MessageQueue ServiceHead (r:1 w:1) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + /// Storage: MessageQueue BookStateFor (r:1 w:0) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) fn bump_service_head() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `712` + // Estimated: `3027` + // Minimum execution time: 8_258 nanoseconds. + Weight::from_parts(8_438_000, 3027) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - // Storage: MessageQueue BookStateFor (r:1 w:1) - // Storage: MessageQueue Pages (r:1 w:1) + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) 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)) + // Proof Size summary in bytes: + // Measured: `66827` + // Estimated: `70587` + // Minimum execution time: 61_361 nanoseconds. + Weight::from_parts(62_103_000, 70587) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } - // Storage: MessageQueue BookStateFor (r:1 w:1) - // Storage: MessageQueue Pages (r:1 w:1) + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) fn execute_overweight_page_removed() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `66827` + // Estimated: `70587` + // Minimum execution time: 75_153 nanoseconds. + Weight::from_parts(76_093_000, 70587) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } - // Storage: MessageQueue BookStateFor (r:1 w:1) - // Storage: MessageQueue Pages (r:1 w:1) + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) fn execute_overweight_page_updated() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `66827` + // Estimated: `70587` + // Minimum execution time: 88_272 nanoseconds. + Weight::from_parts(89_373_000, 70587) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } } diff --git a/frame/multisig/src/weights.rs b/frame/multisig/src/weights.rs index 1f435cb9f9087..46bf911f273d6 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) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2023 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,7 +18,8 @@ //! Autogenerated weights for pallet_multisig //! //! 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: `[]` +//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -61,82 +62,108 @@ 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_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)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 12_086 nanoseconds. + Weight::from_ref_time(12_464_828) + // Standard Error: 1 + .saturating_add(Weight::from_ref_time(494).saturating_mul(z.into())) } - // Storage: Multisig Multisigs (r:1 w:1) - // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) + /// Storage: Multisig Multisigs (r:1 w:1) + /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) /// The range of component `s` is `[2, 100]`. /// The range of component `z` is `[0, 10000]`. fn as_multi_create(s: u32, z: u32, ) -> Weight { - // 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_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)) + // Proof Size summary in bytes: + // Measured: `352 + s * (2 ±0)` + // Estimated: `5821` + // Minimum execution time: 35_377 nanoseconds. + Weight::from_parts(29_088_956, 5821) + // Standard Error: 335 + .saturating_add(Weight::from_ref_time(67_846).saturating_mul(s.into())) + // Standard Error: 3 + .saturating_add(Weight::from_ref_time(1_523).saturating_mul(z.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - // Storage: Multisig Multisigs (r:1 w:1) + /// Storage: Multisig Multisigs (r:1 w:1) + /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) /// The range of component `s` is `[3, 100]`. /// The range of component `z` is `[0, 10000]`. fn as_multi_approve(s: u32, z: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `351` + // Estimated: `5821` + // Minimum execution time: 26_138 nanoseconds. + Weight::from_parts(20_479_380, 5821) + // Standard Error: 259 + .saturating_add(Weight::from_ref_time(64_116).saturating_mul(s.into())) + // Standard Error: 2 + .saturating_add(Weight::from_ref_time(1_520).saturating_mul(z.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - // Storage: Multisig Multisigs (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: Multisig Multisigs (r:1 w:1) + /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `s` is `[2, 100]`. /// The range of component `z` is `[0, 10000]`. fn as_multi_complete(s: u32, z: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `489 + s * (33 ±0)` + // Estimated: `8424` + // Minimum execution time: 40_323 nanoseconds. + Weight::from_parts(32_311_615, 8424) + // Standard Error: 401 + .saturating_add(Weight::from_ref_time(85_999).saturating_mul(s.into())) + // Standard Error: 3 + .saturating_add(Weight::from_ref_time(1_534).saturating_mul(z.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } - // Storage: Multisig Multisigs (r:1 w:1) - // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) + /// Storage: Multisig Multisigs (r:1 w:1) + /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) /// The range of component `s` is `[2, 100]`. fn approve_as_multi_create(s: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `359 + s * (2 ±0)` + // Estimated: `5821` + // Minimum execution time: 26_938 nanoseconds. + Weight::from_parts(27_802_216, 5821) + // Standard Error: 342 + .saturating_add(Weight::from_ref_time(69_282).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - // Storage: Multisig Multisigs (r:1 w:1) + /// Storage: Multisig Multisigs (r:1 w:1) + /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) /// The range of component `s` is `[2, 100]`. fn approve_as_multi_approve(s: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `351` + // Estimated: `5821` + // Minimum execution time: 18_050 nanoseconds. + Weight::from_parts(19_095_404, 5821) + // Standard Error: 419 + .saturating_add(Weight::from_ref_time(66_914).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - // Storage: Multisig Multisigs (r:1 w:1) + /// Storage: Multisig Multisigs (r:1 w:1) + /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) /// The range of component `s` is `[2, 100]`. fn cancel_as_multi(s: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `555 + s * (1 ±0)` + // Estimated: `5821` + // Minimum execution time: 27_508 nanoseconds. + Weight::from_parts(28_702_686, 5821) + // Standard Error: 466 + .saturating_add(Weight::from_ref_time(69_419).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } } @@ -144,81 +171,107 @@ 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_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)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 12_086 nanoseconds. + Weight::from_ref_time(12_464_828) + // Standard Error: 1 + .saturating_add(Weight::from_ref_time(494).saturating_mul(z.into())) } - // Storage: Multisig Multisigs (r:1 w:1) - // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) + /// Storage: Multisig Multisigs (r:1 w:1) + /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) /// The range of component `s` is `[2, 100]`. /// The range of component `z` is `[0, 10000]`. fn as_multi_create(s: u32, z: u32, ) -> Weight { - // 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_508 as u64).saturating_mul(z as u64)) - .saturating_add(RocksDbWeight::get().reads(2 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + // Proof Size summary in bytes: + // Measured: `352 + s * (2 ±0)` + // Estimated: `5821` + // Minimum execution time: 35_377 nanoseconds. + Weight::from_parts(29_088_956, 5821) + // Standard Error: 335 + .saturating_add(Weight::from_ref_time(67_846).saturating_mul(s.into())) + // Standard Error: 3 + .saturating_add(Weight::from_ref_time(1_523).saturating_mul(z.into())) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - // Storage: Multisig Multisigs (r:1 w:1) + /// Storage: Multisig Multisigs (r:1 w:1) + /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) /// The range of component `s` is `[3, 100]`. /// The range of component `z` is `[0, 10000]`. fn as_multi_approve(s: u32, z: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `351` + // Estimated: `5821` + // Minimum execution time: 26_138 nanoseconds. + Weight::from_parts(20_479_380, 5821) + // Standard Error: 259 + .saturating_add(Weight::from_ref_time(64_116).saturating_mul(s.into())) + // Standard Error: 2 + .saturating_add(Weight::from_ref_time(1_520).saturating_mul(z.into())) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - // Storage: Multisig Multisigs (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: Multisig Multisigs (r:1 w:1) + /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `s` is `[2, 100]`. /// The range of component `z` is `[0, 10000]`. fn as_multi_complete(s: u32, z: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `489 + s * (33 ±0)` + // Estimated: `8424` + // Minimum execution time: 40_323 nanoseconds. + Weight::from_parts(32_311_615, 8424) + // Standard Error: 401 + .saturating_add(Weight::from_ref_time(85_999).saturating_mul(s.into())) + // Standard Error: 3 + .saturating_add(Weight::from_ref_time(1_534).saturating_mul(z.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } - // Storage: Multisig Multisigs (r:1 w:1) - // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) + /// Storage: Multisig Multisigs (r:1 w:1) + /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) /// The range of component `s` is `[2, 100]`. fn approve_as_multi_create(s: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `359 + s * (2 ±0)` + // Estimated: `5821` + // Minimum execution time: 26_938 nanoseconds. + Weight::from_parts(27_802_216, 5821) + // Standard Error: 342 + .saturating_add(Weight::from_ref_time(69_282).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - // Storage: Multisig Multisigs (r:1 w:1) + /// Storage: Multisig Multisigs (r:1 w:1) + /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) /// The range of component `s` is `[2, 100]`. fn approve_as_multi_approve(s: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `351` + // Estimated: `5821` + // Minimum execution time: 18_050 nanoseconds. + Weight::from_parts(19_095_404, 5821) + // Standard Error: 419 + .saturating_add(Weight::from_ref_time(66_914).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - // Storage: Multisig Multisigs (r:1 w:1) + /// Storage: Multisig Multisigs (r:1 w:1) + /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) /// The range of component `s` is `[2, 100]`. fn cancel_as_multi(s: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `555 + s * (1 ±0)` + // Estimated: `5821` + // Minimum execution time: 27_508 nanoseconds. + Weight::from_parts(28_702_686, 5821) + // Standard Error: 466 + .saturating_add(Weight::from_ref_time(69_419).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } } diff --git a/frame/nfts/src/weights.rs b/frame/nfts/src/weights.rs index f05f8ca514c3e..81be145b67c88 100644 --- a/frame/nfts/src/weights.rs +++ b/frame/nfts/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2023 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,25 +18,25 @@ //! Autogenerated weights for pallet_nfts //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-12-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! 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_nfts // --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_nfts -// --chain=dev -// --header=./HEADER-APACHE2 // --output=./frame/nfts/src/weights.rs +// --header=./HEADER-APACHE2 // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -90,762 +90,1264 @@ pub trait WeightInfo { /// Weights for pallet_nfts using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - // Storage: Nfts NextCollectionId (r:1 w:1) - // Storage: Nfts Collection (r:1 w:1) - // Storage: Nfts CollectionRoleOf (r:0 w:1) - // Storage: Nfts CollectionConfigOf (r:0 w:1) - // Storage: Nfts CollectionAccount (r:0 w:1) + /// Storage: Nfts NextCollectionId (r:1 w:1) + /// Proof: Nfts NextCollectionId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts CollectionRoleOf (r:0 w:1) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:0 w:1) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts CollectionAccount (r:0 w:1) + /// Proof: Nfts CollectionAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) fn create() -> Weight { - // Minimum execution time: 44_312 nanoseconds. - Weight::from_ref_time(44_871_000) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(5)) - } - // Storage: Nfts NextCollectionId (r:1 w:1) - // Storage: Nfts Collection (r:1 w:1) - // Storage: Nfts CollectionRoleOf (r:0 w:1) - // Storage: Nfts CollectionConfigOf (r:0 w:1) - // Storage: Nfts CollectionAccount (r:0 w:1) + // Proof Size summary in bytes: + // Measured: `214` + // Estimated: `3054` + // Minimum execution time: 32_467 nanoseconds. + Weight::from_parts(33_236_000, 3054) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) + } + /// Storage: Nfts NextCollectionId (r:1 w:1) + /// Proof: Nfts NextCollectionId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts CollectionRoleOf (r:0 w:1) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:0 w:1) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts CollectionAccount (r:0 w:1) + /// Proof: Nfts CollectionAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) fn force_create() -> Weight { - // Minimum execution time: 31_654 nanoseconds. - Weight::from_ref_time(32_078_000) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(5)) - } - // Storage: Nfts Collection (r:1 w:1) - // Storage: Nfts Item (r:1001 w:1000) - // Storage: Nfts Attribute (r:1001 w:1000) - // Storage: Nfts ItemMetadataOf (r:0 w:1000) - // Storage: Nfts CollectionRoleOf (r:0 w:1) - // Storage: Nfts CollectionMetadataOf (r:0 w:1) - // Storage: Nfts CollectionConfigOf (r:0 w:1) - // Storage: Nfts ItemConfigOf (r:0 w:1000) - // Storage: Nfts Account (r:0 w:1000) - // Storage: Nfts CollectionAccount (r:0 w:1) + // Proof Size summary in bytes: + // Measured: `42` + // Estimated: `3054` + // Minimum execution time: 22_198 nanoseconds. + Weight::from_parts(22_776_000, 3054) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) + } + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts Item (r:1001 w:1000) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts ItemMetadataOf (r:1001 w:1000) + /// Proof: Nfts ItemMetadataOf (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) + /// Storage: Nfts Attribute (r:1001 w:1000) + /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) + /// Storage: Nfts CollectionRoleOf (r:0 w:1) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: Nfts CollectionMetadataOf (r:0 w:1) + /// Proof: Nfts CollectionMetadataOf (max_values: None, max_size: Some(87), added: 2562, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:0 w:1) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:0 w:1000) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Nfts Account (r:0 w:1000) + /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) + /// Storage: Nfts CollectionAccount (r:0 w:1) + /// Proof: Nfts CollectionAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) /// The range of component `n` is `[0, 1000]`. /// The range of component `m` is `[0, 1000]`. /// The range of component `a` is `[0, 1000]`. fn destroy(n: u32, m: u32, a: u32, ) -> Weight { - // Minimum execution time: 19_183_393 nanoseconds. - Weight::from_ref_time(17_061_526_855) - // Standard Error: 16_689 - .saturating_add(Weight::from_ref_time(353_523).saturating_mul(n.into())) - // Standard Error: 16_689 - .saturating_add(Weight::from_ref_time(1_861_080).saturating_mul(m.into())) - // Standard Error: 16_689 - .saturating_add(Weight::from_ref_time(8_858_987).saturating_mul(a.into())) - .saturating_add(T::DbWeight::get().reads(1003)) + // Proof Size summary in bytes: + // Measured: `172781 + m * (127 ±0) + a * (402 ±0)` + // Estimated: `3347427 + a * (2921 ±0) + m * (2615 ±0)` + // Minimum execution time: 24_021_657 nanoseconds. + Weight::from_parts(16_029_391_606, 3347427) + // Standard Error: 20_364 + .saturating_add(Weight::from_ref_time(300_580).saturating_mul(n.into())) + // Standard Error: 20_364 + .saturating_add(Weight::from_ref_time(7_748_502).saturating_mul(m.into())) + // Standard Error: 20_364 + .saturating_add(Weight::from_ref_time(9_183_566).saturating_mul(a.into())) + .saturating_add(T::DbWeight::get().reads(1004_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(m.into()))) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(a.into()))) - .saturating_add(T::DbWeight::get().writes(3005)) + .saturating_add(T::DbWeight::get().writes(3005_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(m.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(a.into()))) - } - // Storage: Nfts CollectionConfigOf (r:1 w:0) - // Storage: Nfts Item (r:1 w:1) - // Storage: Nfts Collection (r:1 w:1) - // Storage: Nfts CollectionRoleOf (r:1 w:0) - // Storage: Nfts ItemConfigOf (r:1 w:1) - // Storage: Nfts Account (r:0 w:1) + .saturating_add(Weight::from_proof_size(2921).saturating_mul(a.into())) + .saturating_add(Weight::from_proof_size(2615).saturating_mul(m.into())) + } + /// Storage: Nfts CollectionConfigOf (r:1 w:0) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts Item (r:1 w:1) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:1 w:1) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Nfts Account (r:0 w:1) + /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) fn mint() -> Weight { - // Minimum execution time: 57_753 nanoseconds. - Weight::from_ref_time(58_313_000) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(4)) - } - // Storage: Nfts CollectionRoleOf (r:1 w:0) - // Storage: Nfts Item (r:1 w:1) - // Storage: Nfts Collection (r:1 w:1) - // Storage: Nfts CollectionConfigOf (r:1 w:0) - // Storage: Nfts ItemConfigOf (r:1 w:1) - // Storage: Nfts Account (r:0 w:1) + // Proof Size summary in bytes: + // Measured: `448` + // Estimated: `13506` + // Minimum execution time: 42_634 nanoseconds. + Weight::from_parts(43_231_000, 13506) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: Nfts Item (r:1 w:1) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:0) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:1 w:1) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Nfts Account (r:0 w:1) + /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) fn force_mint() -> Weight { - // Minimum execution time: 56_429 nanoseconds. - Weight::from_ref_time(57_202_000) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(4)) - } - // Storage: Nfts Collection (r:1 w:1) - // Storage: Nfts Item (r:1 w:1) - // Storage: Nfts CollectionRoleOf (r:1 w:0) - // Storage: Nfts ItemConfigOf (r:1 w:1) - // Storage: Nfts Account (r:0 w:1) - // Storage: Nfts ItemPriceOf (r:0 w:1) - // Storage: Nfts ItemAttributesApprovalsOf (r:0 w:1) - // Storage: Nfts PendingSwapOf (r:0 w:1) + // Proof Size summary in bytes: + // Measured: `448` + // Estimated: `13506` + // Minimum execution time: 41_686 nanoseconds. + Weight::from_parts(41_991_000, 13506) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: Nfts ItemConfigOf (r:1 w:1) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts Item (r:1 w:1) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: Nfts ItemMetadataOf (r:1 w:0) + /// Proof: Nfts ItemMetadataOf (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) + /// Storage: Nfts Account (r:0 w:1) + /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) + /// Storage: Nfts ItemPriceOf (r:0 w:1) + /// Proof: Nfts ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) + /// Storage: Nfts ItemAttributesApprovalsOf (r:0 w:1) + /// Proof: Nfts ItemAttributesApprovalsOf (max_values: None, max_size: Some(681), added: 3156, mode: MaxEncodedLen) + /// Storage: Nfts PendingSwapOf (r:0 w:1) + /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) fn burn() -> Weight { - // Minimum execution time: 59_681 nanoseconds. - Weight::from_ref_time(60_058_000) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(7)) - } - // Storage: Nfts Collection (r:1 w:0) - // Storage: Nfts CollectionConfigOf (r:1 w:0) - // Storage: Nfts ItemConfigOf (r:1 w:0) - // Storage: Nfts Item (r:1 w:1) - // Storage: Nfts CollectionRoleOf (r:1 w:0) - // Storage: System Account (r:1 w:1) - // Storage: Nfts Account (r:0 w:2) - // Storage: Nfts ItemPriceOf (r:0 w:1) - // Storage: Nfts PendingSwapOf (r:0 w:1) + // Proof Size summary in bytes: + // Measured: `647` + // Estimated: `13573` + // Minimum execution time: 45_192 nanoseconds. + Weight::from_parts(45_792_000, 13573) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(7_u64)) + } + /// Storage: Nfts Collection (r:1 w:0) + /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:0) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:1 w:0) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Nfts Item (r:1 w:1) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Nfts Account (r:0 w:2) + /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) + /// Storage: Nfts ItemPriceOf (r:0 w:1) + /// Proof: Nfts ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) + /// Storage: Nfts PendingSwapOf (r:0 w:1) + /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) fn transfer() -> Weight { - // Minimum execution time: 66_085 nanoseconds. - Weight::from_ref_time(67_065_000) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(6)) - } - // Storage: Nfts Collection (r:1 w:0) - // Storage: Nfts CollectionConfigOf (r:1 w:0) - // Storage: Nfts Item (r:102 w:102) + // Proof Size summary in bytes: + // Measured: `882` + // Estimated: `16109` + // Minimum execution time: 51_962 nanoseconds. + Weight::from_parts(52_367_000, 16109) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(6_u64)) + } + /// Storage: Nfts Collection (r:1 w:0) + /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:0) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts Item (r:5000 w:5000) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { - // Minimum execution time: 25_949 nanoseconds. - Weight::from_ref_time(26_106_000) - // Standard Error: 10_326 - .saturating_add(Weight::from_ref_time(11_496_776).saturating_mul(i.into())) - .saturating_add(T::DbWeight::get().reads(2)) + // Proof Size summary in bytes: + // Measured: `756 + i * (140 ±0)` + // Estimated: `5103 + i * (3336 ±0)` + // Minimum execution time: 15_512 nanoseconds. + Weight::from_parts(15_731_000, 5103) + // Standard Error: 9_495 + .saturating_add(Weight::from_ref_time(11_462_413).saturating_mul(i.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(i.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) + .saturating_add(Weight::from_proof_size(3336).saturating_mul(i.into())) } - // Storage: Nfts CollectionRoleOf (r:1 w:0) - // Storage: Nfts ItemConfigOf (r:1 w:1) + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:1 w:1) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) fn lock_item_transfer() -> Weight { - // Minimum execution time: 30_080 nanoseconds. - Weight::from_ref_time(30_825_000) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - // Storage: Nfts CollectionRoleOf (r:1 w:0) - // Storage: Nfts ItemConfigOf (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `401` + // Estimated: `5067` + // Minimum execution time: 19_273 nanoseconds. + Weight::from_parts(19_508_000, 5067) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:1 w:1) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) fn unlock_item_transfer() -> Weight { - // Minimum execution time: 30_612 nanoseconds. - Weight::from_ref_time(31_422_000) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - // Storage: Nfts CollectionRoleOf (r:1 w:0) - // Storage: Nfts CollectionConfigOf (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `401` + // Estimated: `5067` + // Minimum execution time: 19_022 nanoseconds. + Weight::from_parts(19_430_000, 5067) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:1) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) fn lock_collection() -> Weight { - // Minimum execution time: 27_470 nanoseconds. - Weight::from_ref_time(28_015_000) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - // Storage: Nfts OwnershipAcceptance (r:1 w:1) - // Storage: Nfts Collection (r:1 w:1) - // Storage: Nfts CollectionAccount (r:0 w:2) + // Proof Size summary in bytes: + // Measured: `289` + // Estimated: `5092` + // Minimum execution time: 17_593 nanoseconds. + Weight::from_parts(17_950_000, 5092) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Nfts OwnershipAcceptance (r:1 w:1) + /// Proof: Nfts OwnershipAcceptance (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts CollectionAccount (r:0 w:2) + /// Proof: Nfts CollectionAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) fn transfer_ownership() -> Weight { - // Minimum execution time: 33_750 nanoseconds. - Weight::from_ref_time(34_139_000) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(4)) - } - // Storage: Nfts Collection (r:1 w:1) - // Storage: Nfts CollectionRoleOf (r:0 w:4) + // Proof Size summary in bytes: + // Measured: `381` + // Estimated: `5082` + // Minimum execution time: 22_068 nanoseconds. + Weight::from_parts(22_235_000, 5082) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts CollectionRoleOf (r:0 w:4) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) fn set_team() -> Weight { - // Minimum execution time: 36_565 nanoseconds. - Weight::from_ref_time(37_464_000) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(5)) - } - // Storage: Nfts Collection (r:1 w:1) - // Storage: Nfts CollectionAccount (r:0 w:2) + // Proof Size summary in bytes: + // Measured: `362` + // Estimated: `2555` + // Minimum execution time: 25_056 nanoseconds. + Weight::from_parts(25_767_000, 2555) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) + } + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts CollectionAccount (r:0 w:2) + /// Proof: Nfts CollectionAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) fn force_collection_owner() -> Weight { - // Minimum execution time: 29_028 nanoseconds. - Weight::from_ref_time(29_479_000) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(3)) - } - // Storage: Nfts Collection (r:1 w:0) - // Storage: Nfts CollectionConfigOf (r:0 w:1) + // Proof Size summary in bytes: + // Measured: `304` + // Estimated: `2555` + // Minimum execution time: 17_398 nanoseconds. + Weight::from_parts(17_684_000, 2555) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: Nfts Collection (r:1 w:0) + /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:0 w:1) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) fn force_collection_config() -> Weight { - // Minimum execution time: 24_695 nanoseconds. - Weight::from_ref_time(25_304_000) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - // Storage: Nfts Collection (r:1 w:0) - // Storage: Nfts ItemConfigOf (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `242` + // Estimated: `2555` + // Minimum execution time: 14_054 nanoseconds. + Weight::from_parts(14_243_000, 2555) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Nfts Collection (r:1 w:0) + /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:1 w:1) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) fn lock_item_properties() -> Weight { - // Minimum execution time: 28_910 nanoseconds. - Weight::from_ref_time(29_186_000) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - // Storage: Nfts Collection (r:1 w:1) - // Storage: Nfts CollectionConfigOf (r:1 w:0) - // Storage: Nfts ItemConfigOf (r:1 w:0) - // Storage: Nfts Attribute (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `445` + // Estimated: `5078` + // Minimum execution time: 17_662 nanoseconds. + Weight::from_parts(18_073_000, 5078) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:0) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:1 w:0) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Nfts Attribute (r:1 w:1) + /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) fn set_attribute() -> Weight { - // Minimum execution time: 56_407 nanoseconds. - Weight::from_ref_time(58_176_000) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(2)) - } - // Storage: Nfts Collection (r:1 w:1) - // Storage: Nfts Attribute (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `474` + // Estimated: `10547` + // Minimum execution time: 40_098 nanoseconds. + Weight::from_parts(40_649_000, 10547) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts Attribute (r:1 w:1) + /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) fn force_set_attribute() -> Weight { - // Minimum execution time: 36_402 nanoseconds. - Weight::from_ref_time(37_034_000) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - // Storage: Nfts Attribute (r:1 w:1) - // Storage: Nfts Collection (r:1 w:1) - // Storage: Nfts ItemConfigOf (r:1 w:0) + // Proof Size summary in bytes: + // Measured: `337` + // Estimated: `5476` + // Minimum execution time: 25_178 nanoseconds. + Weight::from_parts(25_473_000, 5476) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: Nfts Attribute (r:1 w:1) + /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:1 w:0) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) fn clear_attribute() -> Weight { - // Minimum execution time: 52_022 nanoseconds. - Weight::from_ref_time(54_059_000) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - // Storage: Nfts Item (r:1 w:0) - // Storage: Nfts ItemAttributesApprovalsOf (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `916` + // Estimated: `7999` + // Minimum execution time: 35_202 nanoseconds. + Weight::from_parts(35_518_000, 7999) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: Nfts Item (r:1 w:0) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts ItemAttributesApprovalsOf (r:1 w:1) + /// Proof: Nfts ItemAttributesApprovalsOf (max_values: None, max_size: Some(681), added: 3156, mode: MaxEncodedLen) fn approve_item_attributes() -> Weight { - // Minimum execution time: 28_475 nanoseconds. - Weight::from_ref_time(29_162_000) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - // Storage: Nfts Item (r:1 w:0) - // Storage: Nfts ItemAttributesApprovalsOf (r:1 w:1) - // Storage: Nfts Attribute (r:1 w:0) - // Storage: System Account (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `379` + // Estimated: `6492` + // Minimum execution time: 17_260 nanoseconds. + Weight::from_parts(17_498_000, 6492) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Nfts Item (r:1 w:0) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts ItemAttributesApprovalsOf (r:1 w:1) + /// Proof: Nfts ItemAttributesApprovalsOf (max_values: None, max_size: Some(681), added: 3156, mode: MaxEncodedLen) + /// Storage: Nfts Attribute (r:1001 w:1000) + /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `n` is `[0, 1000]`. fn cancel_item_attributes_approval(n: u32, ) -> Weight { - // Minimum execution time: 37_529 nanoseconds. - Weight::from_ref_time(38_023_000) - // Standard Error: 8_136 - .saturating_add(Weight::from_ref_time(7_452_872).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(4)) + // Proof Size summary in bytes: + // Measured: `865 + n * (367 ±0)` + // Estimated: `12016 + n * (2921 ±0)` + // Minimum execution time: 25_579 nanoseconds. + Weight::from_parts(25_846_000, 12016) + // Standard Error: 7_759 + .saturating_add(Weight::from_ref_time(7_159_200).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(2)) + .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) - } - // Storage: Nfts Collection (r:1 w:1) - // Storage: Nfts ItemConfigOf (r:1 w:0) - // Storage: Nfts CollectionConfigOf (r:1 w:0) - // Storage: Nfts ItemMetadataOf (r:1 w:1) + .saturating_add(Weight::from_proof_size(2921).saturating_mul(n.into())) + } + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:1 w:0) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:0) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts ItemMetadataOf (r:1 w:1) + /// Proof: Nfts ItemMetadataOf (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) fn set_metadata() -> Weight { - // Minimum execution time: 49_300 nanoseconds. - Weight::from_ref_time(49_790_000) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(2)) - } - // Storage: Nfts Collection (r:1 w:1) - // Storage: Nfts ItemConfigOf (r:1 w:0) - // Storage: Nfts ItemMetadataOf (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `474` + // Estimated: `10241` + // Minimum execution time: 33_285 nanoseconds. + Weight::from_parts(33_692_000, 10241) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: Nfts ItemMetadataOf (r:1 w:1) + /// Proof: Nfts ItemMetadataOf (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:1 w:0) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) fn clear_metadata() -> Weight { - // Minimum execution time: 47_248 nanoseconds. - Weight::from_ref_time(48_094_000) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - // Storage: Nfts CollectionConfigOf (r:1 w:0) - // Storage: Nfts Collection (r:1 w:1) - // Storage: Nfts CollectionMetadataOf (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `609` + // Estimated: `7693` + // Minimum execution time: 30_670 nanoseconds. + Weight::from_parts(31_282_000, 7693) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: Nfts CollectionConfigOf (r:1 w:0) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts CollectionMetadataOf (r:1 w:1) + /// Proof: Nfts CollectionMetadataOf (max_values: None, max_size: Some(87), added: 2562, mode: MaxEncodedLen) fn set_collection_metadata() -> Weight { - // Minimum execution time: 44_137 nanoseconds. - Weight::from_ref_time(44_905_000) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - // Storage: Nfts Collection (r:1 w:0) - // Storage: Nfts CollectionConfigOf (r:1 w:0) - // Storage: Nfts CollectionMetadataOf (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `333` + // Estimated: `7665` + // Minimum execution time: 28_313 nanoseconds. + Weight::from_parts(28_724_000, 7665) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: Nfts Collection (r:1 w:0) + /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:0) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts CollectionMetadataOf (r:1 w:1) + /// Proof: Nfts CollectionMetadataOf (max_values: None, max_size: Some(87), added: 2562, mode: MaxEncodedLen) fn clear_collection_metadata() -> Weight { - // Minimum execution time: 43_005 nanoseconds. - Weight::from_ref_time(43_898_000) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(1)) - } - // Storage: Nfts Item (r:1 w:1) - // Storage: Nfts CollectionConfigOf (r:1 w:0) - // Storage: Nfts CollectionRoleOf (r:1 w:0) + // Proof Size summary in bytes: + // Measured: `476` + // Estimated: `7665` + // Minimum execution time: 27_034 nanoseconds. + Weight::from_parts(27_655_000, 7665) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Nfts Item (r:1 w:1) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:0) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) fn approve_transfer() -> Weight { - // Minimum execution time: 36_344 nanoseconds. - Weight::from_ref_time(36_954_000) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(1)) - } - // Storage: Nfts Item (r:1 w:1) - // Storage: Nfts CollectionRoleOf (r:1 w:0) + // Proof Size summary in bytes: + // Measured: `466` + // Estimated: `8428` + // Minimum execution time: 23_408 nanoseconds. + Weight::from_parts(23_916_000, 8428) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Nfts Item (r:1 w:1) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) fn cancel_approval() -> Weight { - // Minimum execution time: 32_418 nanoseconds. - Weight::from_ref_time(33_029_000) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - // Storage: Nfts Item (r:1 w:1) - // Storage: Nfts CollectionRoleOf (r:1 w:0) + // Proof Size summary in bytes: + // Measured: `474` + // Estimated: `5880` + // Minimum execution time: 21_177 nanoseconds. + Weight::from_parts(21_492_000, 5880) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Nfts Item (r:1 w:1) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) fn clear_all_transfer_approvals() -> Weight { - // Minimum execution time: 31_448 nanoseconds. - Weight::from_ref_time(31_979_000) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - // Storage: Nfts OwnershipAcceptance (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `474` + // Estimated: `5880` + // Minimum execution time: 20_279 nanoseconds. + Weight::from_parts(20_919_000, 5880) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Nfts OwnershipAcceptance (r:1 w:1) + /// Proof: Nfts OwnershipAcceptance (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) fn set_accept_ownership() -> Weight { - // Minimum execution time: 27_487 nanoseconds. - Weight::from_ref_time(28_080_000) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - // Storage: Nfts CollectionConfigOf (r:1 w:1) - // Storage: Nfts Collection (r:1 w:0) + // Proof Size summary in bytes: + // Measured: `42` + // Estimated: `2527` + // Minimum execution time: 14_921 nanoseconds. + Weight::from_parts(15_382_000, 2527) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Nfts CollectionConfigOf (r:1 w:1) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:0) + /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) fn set_collection_max_supply() -> Weight { - // Minimum execution time: 28_235 nanoseconds. - Weight::from_ref_time(28_967_000) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - // Storage: Nfts Collection (r:1 w:0) - // Storage: Nfts CollectionConfigOf (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `333` + // Estimated: `5103` + // Minimum execution time: 18_201 nanoseconds. + Weight::from_parts(18_628_000, 5103) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Nfts Collection (r:1 w:0) + /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:1) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) fn update_mint_settings() -> Weight { - // Minimum execution time: 28_172 nanoseconds. - Weight::from_ref_time(28_636_000) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - // Storage: Nfts Item (r:1 w:0) - // Storage: Nfts CollectionConfigOf (r:1 w:0) - // Storage: Nfts ItemConfigOf (r:1 w:0) - // Storage: Nfts ItemPriceOf (r:0 w:1) + // Proof Size summary in bytes: + // Measured: `333` + // Estimated: `5103` + // Minimum execution time: 16_870 nanoseconds. + Weight::from_parts(17_318_000, 5103) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Nfts Item (r:1 w:0) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:0) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:1 w:0) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Nfts ItemPriceOf (r:0 w:1) + /// Proof: Nfts ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) fn set_price() -> Weight { - // Minimum execution time: 35_336 nanoseconds. - Weight::from_ref_time(36_026_000) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(1)) - } - // Storage: Nfts Item (r:1 w:1) - // Storage: Nfts ItemPriceOf (r:1 w:1) - // Storage: Nfts Collection (r:1 w:0) - // Storage: Nfts CollectionConfigOf (r:1 w:0) - // Storage: Nfts ItemConfigOf (r:1 w:0) - // Storage: System Account (r:1 w:1) - // Storage: Nfts Account (r:0 w:2) - // Storage: Nfts PendingSwapOf (r:0 w:1) + // Proof Size summary in bytes: + // Measured: `516` + // Estimated: `8407` + // Minimum execution time: 22_604 nanoseconds. + Weight::from_parts(22_867_000, 8407) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Nfts Item (r:1 w:1) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts ItemPriceOf (r:1 w:1) + /// Proof: Nfts ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:0) + /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:0) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:1 w:0) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Nfts Account (r:0 w:2) + /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) + /// Storage: Nfts PendingSwapOf (r:0 w:1) + /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) fn buy_item() -> Weight { - // Minimum execution time: 70_971 nanoseconds. - Weight::from_ref_time(72_036_000) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(6)) + // Proof Size summary in bytes: + // Measured: `934` + // Estimated: `16129` + // Minimum execution time: 56_849 nanoseconds. + Weight::from_parts(57_336_000, 16129) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(6_u64)) } /// The range of component `n` is `[0, 10]`. fn pay_tips(n: u32, ) -> Weight { - // Minimum execution time: 5_151 nanoseconds. - Weight::from_ref_time(11_822_888) - // Standard Error: 38_439 - .saturating_add(Weight::from_ref_time(3_511_844).saturating_mul(n.into())) - } - // Storage: Nfts Item (r:2 w:0) - // Storage: Nfts PendingSwapOf (r:0 w:1) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_308 nanoseconds. + Weight::from_ref_time(4_805_401) + // Standard Error: 13_875 + .saturating_add(Weight::from_ref_time(3_167_190).saturating_mul(n.into())) + } + /// Storage: Nfts Item (r:2 w:0) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts PendingSwapOf (r:0 w:1) + /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) fn create_swap() -> Weight { - // Minimum execution time: 33_027 nanoseconds. - Weight::from_ref_time(33_628_000) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - // Storage: Nfts PendingSwapOf (r:1 w:1) - // Storage: Nfts Item (r:1 w:0) + // Proof Size summary in bytes: + // Measured: `524` + // Estimated: `6672` + // Minimum execution time: 20_395 nanoseconds. + Weight::from_parts(20_716_000, 6672) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Nfts PendingSwapOf (r:1 w:1) + /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) + /// Storage: Nfts Item (r:1 w:0) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) fn cancel_swap() -> Weight { - // Minimum execution time: 35_890 nanoseconds. - Weight::from_ref_time(36_508_000) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - // Storage: Nfts Item (r:2 w:2) - // Storage: Nfts PendingSwapOf (r:1 w:2) - // Storage: Nfts Collection (r:1 w:0) - // Storage: Nfts CollectionConfigOf (r:1 w:0) - // Storage: Nfts ItemConfigOf (r:2 w:0) - // Storage: System Account (r:1 w:1) - // Storage: Nfts Account (r:0 w:4) - // Storage: Nfts ItemPriceOf (r:0 w:2) + // Proof Size summary in bytes: + // Measured: `511` + // Estimated: `5882` + // Minimum execution time: 19_936 nanoseconds. + Weight::from_parts(20_344_000, 5882) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Nfts Item (r:2 w:2) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts PendingSwapOf (r:1 w:2) + /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:0) + /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:0) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:2 w:0) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Nfts Account (r:0 w:4) + /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) + /// Storage: Nfts ItemPriceOf (r:0 w:2) + /// Proof: Nfts ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) fn claim_swap() -> Weight { - // Minimum execution time: 101_076 nanoseconds. - Weight::from_ref_time(101_863_000) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(11)) + // Proof Size summary in bytes: + // Measured: `1097` + // Estimated: `21970` + // Minimum execution time: 80_884 nanoseconds. + Weight::from_parts(81_643_000, 21970) + .saturating_add(T::DbWeight::get().reads(8_u64)) + .saturating_add(T::DbWeight::get().writes(11_u64)) } } // For backwards compatibility and tests impl WeightInfo for () { - // Storage: Nfts NextCollectionId (r:1 w:1) - // Storage: Nfts Collection (r:1 w:1) - // Storage: Nfts CollectionRoleOf (r:0 w:1) - // Storage: Nfts CollectionConfigOf (r:0 w:1) - // Storage: Nfts CollectionAccount (r:0 w:1) + /// Storage: Nfts NextCollectionId (r:1 w:1) + /// Proof: Nfts NextCollectionId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts CollectionRoleOf (r:0 w:1) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:0 w:1) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts CollectionAccount (r:0 w:1) + /// Proof: Nfts CollectionAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) fn create() -> Weight { - // Minimum execution time: 44_312 nanoseconds. - Weight::from_ref_time(44_871_000) - .saturating_add(RocksDbWeight::get().reads(2)) - .saturating_add(RocksDbWeight::get().writes(5)) - } - // Storage: Nfts NextCollectionId (r:1 w:1) - // Storage: Nfts Collection (r:1 w:1) - // Storage: Nfts CollectionRoleOf (r:0 w:1) - // Storage: Nfts CollectionConfigOf (r:0 w:1) - // Storage: Nfts CollectionAccount (r:0 w:1) + // Proof Size summary in bytes: + // Measured: `214` + // Estimated: `3054` + // Minimum execution time: 32_467 nanoseconds. + Weight::from_parts(33_236_000, 3054) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(5_u64)) + } + /// Storage: Nfts NextCollectionId (r:1 w:1) + /// Proof: Nfts NextCollectionId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts CollectionRoleOf (r:0 w:1) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:0 w:1) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts CollectionAccount (r:0 w:1) + /// Proof: Nfts CollectionAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) fn force_create() -> Weight { - // Minimum execution time: 31_654 nanoseconds. - Weight::from_ref_time(32_078_000) - .saturating_add(RocksDbWeight::get().reads(2)) - .saturating_add(RocksDbWeight::get().writes(5)) - } - // Storage: Nfts Collection (r:1 w:1) - // Storage: Nfts Item (r:1001 w:1000) - // Storage: Nfts Attribute (r:1001 w:1000) - // Storage: Nfts ItemMetadataOf (r:0 w:1000) - // Storage: Nfts CollectionRoleOf (r:0 w:1) - // Storage: Nfts CollectionMetadataOf (r:0 w:1) - // Storage: Nfts CollectionConfigOf (r:0 w:1) - // Storage: Nfts ItemConfigOf (r:0 w:1000) - // Storage: Nfts Account (r:0 w:1000) - // Storage: Nfts CollectionAccount (r:0 w:1) + // Proof Size summary in bytes: + // Measured: `42` + // Estimated: `3054` + // Minimum execution time: 22_198 nanoseconds. + Weight::from_parts(22_776_000, 3054) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(5_u64)) + } + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts Item (r:1001 w:1000) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts ItemMetadataOf (r:1001 w:1000) + /// Proof: Nfts ItemMetadataOf (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) + /// Storage: Nfts Attribute (r:1001 w:1000) + /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) + /// Storage: Nfts CollectionRoleOf (r:0 w:1) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: Nfts CollectionMetadataOf (r:0 w:1) + /// Proof: Nfts CollectionMetadataOf (max_values: None, max_size: Some(87), added: 2562, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:0 w:1) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:0 w:1000) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Nfts Account (r:0 w:1000) + /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) + /// Storage: Nfts CollectionAccount (r:0 w:1) + /// Proof: Nfts CollectionAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) /// The range of component `n` is `[0, 1000]`. /// The range of component `m` is `[0, 1000]`. /// The range of component `a` is `[0, 1000]`. fn destroy(n: u32, m: u32, a: u32, ) -> Weight { - // Minimum execution time: 19_183_393 nanoseconds. - Weight::from_ref_time(17_061_526_855) - // Standard Error: 16_689 - .saturating_add(Weight::from_ref_time(353_523).saturating_mul(n.into())) - // Standard Error: 16_689 - .saturating_add(Weight::from_ref_time(1_861_080).saturating_mul(m.into())) - // Standard Error: 16_689 - .saturating_add(Weight::from_ref_time(8_858_987).saturating_mul(a.into())) - .saturating_add(RocksDbWeight::get().reads(1003)) + // Proof Size summary in bytes: + // Measured: `172781 + m * (127 ±0) + a * (402 ±0)` + // Estimated: `3347427 + a * (2921 ±0) + m * (2615 ±0)` + // Minimum execution time: 24_021_657 nanoseconds. + Weight::from_parts(16_029_391_606, 3347427) + // Standard Error: 20_364 + .saturating_add(Weight::from_ref_time(300_580).saturating_mul(n.into())) + // Standard Error: 20_364 + .saturating_add(Weight::from_ref_time(7_748_502).saturating_mul(m.into())) + // Standard Error: 20_364 + .saturating_add(Weight::from_ref_time(9_183_566).saturating_mul(a.into())) + .saturating_add(RocksDbWeight::get().reads(1004_u64)) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(m.into()))) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(a.into()))) - .saturating_add(RocksDbWeight::get().writes(3005)) + .saturating_add(RocksDbWeight::get().writes(3005_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(m.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(a.into()))) - } - // Storage: Nfts CollectionConfigOf (r:1 w:0) - // Storage: Nfts Item (r:1 w:1) - // Storage: Nfts Collection (r:1 w:1) - // Storage: Nfts CollectionRoleOf (r:1 w:0) - // Storage: Nfts ItemConfigOf (r:1 w:1) - // Storage: Nfts Account (r:0 w:1) + .saturating_add(Weight::from_proof_size(2921).saturating_mul(a.into())) + .saturating_add(Weight::from_proof_size(2615).saturating_mul(m.into())) + } + /// Storage: Nfts CollectionConfigOf (r:1 w:0) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts Item (r:1 w:1) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:1 w:1) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Nfts Account (r:0 w:1) + /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) fn mint() -> Weight { - // Minimum execution time: 57_753 nanoseconds. - Weight::from_ref_time(58_313_000) - .saturating_add(RocksDbWeight::get().reads(5)) - .saturating_add(RocksDbWeight::get().writes(4)) - } - // Storage: Nfts CollectionRoleOf (r:1 w:0) - // Storage: Nfts Item (r:1 w:1) - // Storage: Nfts Collection (r:1 w:1) - // Storage: Nfts CollectionConfigOf (r:1 w:0) - // Storage: Nfts ItemConfigOf (r:1 w:1) - // Storage: Nfts Account (r:0 w:1) + // Proof Size summary in bytes: + // Measured: `448` + // Estimated: `13506` + // Minimum execution time: 42_634 nanoseconds. + Weight::from_parts(43_231_000, 13506) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + } + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: Nfts Item (r:1 w:1) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:0) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:1 w:1) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Nfts Account (r:0 w:1) + /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) fn force_mint() -> Weight { - // Minimum execution time: 56_429 nanoseconds. - Weight::from_ref_time(57_202_000) - .saturating_add(RocksDbWeight::get().reads(5)) - .saturating_add(RocksDbWeight::get().writes(4)) - } - // Storage: Nfts Collection (r:1 w:1) - // Storage: Nfts Item (r:1 w:1) - // Storage: Nfts CollectionRoleOf (r:1 w:0) - // Storage: Nfts ItemConfigOf (r:1 w:1) - // Storage: Nfts Account (r:0 w:1) - // Storage: Nfts ItemPriceOf (r:0 w:1) - // Storage: Nfts ItemAttributesApprovalsOf (r:0 w:1) - // Storage: Nfts PendingSwapOf (r:0 w:1) + // Proof Size summary in bytes: + // Measured: `448` + // Estimated: `13506` + // Minimum execution time: 41_686 nanoseconds. + Weight::from_parts(41_991_000, 13506) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + } + /// Storage: Nfts ItemConfigOf (r:1 w:1) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts Item (r:1 w:1) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: Nfts ItemMetadataOf (r:1 w:0) + /// Proof: Nfts ItemMetadataOf (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) + /// Storage: Nfts Account (r:0 w:1) + /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) + /// Storage: Nfts ItemPriceOf (r:0 w:1) + /// Proof: Nfts ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) + /// Storage: Nfts ItemAttributesApprovalsOf (r:0 w:1) + /// Proof: Nfts ItemAttributesApprovalsOf (max_values: None, max_size: Some(681), added: 3156, mode: MaxEncodedLen) + /// Storage: Nfts PendingSwapOf (r:0 w:1) + /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) fn burn() -> Weight { - // Minimum execution time: 59_681 nanoseconds. - Weight::from_ref_time(60_058_000) - .saturating_add(RocksDbWeight::get().reads(4)) - .saturating_add(RocksDbWeight::get().writes(7)) - } - // Storage: Nfts Collection (r:1 w:0) - // Storage: Nfts CollectionConfigOf (r:1 w:0) - // Storage: Nfts ItemConfigOf (r:1 w:0) - // Storage: Nfts Item (r:1 w:1) - // Storage: Nfts CollectionRoleOf (r:1 w:0) - // Storage: System Account (r:1 w:1) - // Storage: Nfts Account (r:0 w:2) - // Storage: Nfts ItemPriceOf (r:0 w:1) - // Storage: Nfts PendingSwapOf (r:0 w:1) + // Proof Size summary in bytes: + // Measured: `647` + // Estimated: `13573` + // Minimum execution time: 45_192 nanoseconds. + Weight::from_parts(45_792_000, 13573) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(7_u64)) + } + /// Storage: Nfts Collection (r:1 w:0) + /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:0) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:1 w:0) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Nfts Item (r:1 w:1) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Nfts Account (r:0 w:2) + /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) + /// Storage: Nfts ItemPriceOf (r:0 w:1) + /// Proof: Nfts ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) + /// Storage: Nfts PendingSwapOf (r:0 w:1) + /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) fn transfer() -> Weight { - // Minimum execution time: 66_085 nanoseconds. - Weight::from_ref_time(67_065_000) - .saturating_add(RocksDbWeight::get().reads(6)) - .saturating_add(RocksDbWeight::get().writes(6)) - } - // Storage: Nfts Collection (r:1 w:0) - // Storage: Nfts CollectionConfigOf (r:1 w:0) - // Storage: Nfts Item (r:102 w:102) + // Proof Size summary in bytes: + // Measured: `882` + // Estimated: `16109` + // Minimum execution time: 51_962 nanoseconds. + Weight::from_parts(52_367_000, 16109) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(6_u64)) + } + /// Storage: Nfts Collection (r:1 w:0) + /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:0) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts Item (r:5000 w:5000) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { - // Minimum execution time: 25_949 nanoseconds. - Weight::from_ref_time(26_106_000) - // Standard Error: 10_326 - .saturating_add(Weight::from_ref_time(11_496_776).saturating_mul(i.into())) - .saturating_add(RocksDbWeight::get().reads(2)) + // Proof Size summary in bytes: + // Measured: `756 + i * (140 ±0)` + // Estimated: `5103 + i * (3336 ±0)` + // Minimum execution time: 15_512 nanoseconds. + Weight::from_parts(15_731_000, 5103) + // Standard Error: 9_495 + .saturating_add(Weight::from_ref_time(11_462_413).saturating_mul(i.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(i.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(i.into()))) + .saturating_add(Weight::from_proof_size(3336).saturating_mul(i.into())) } - // Storage: Nfts CollectionRoleOf (r:1 w:0) - // Storage: Nfts ItemConfigOf (r:1 w:1) + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:1 w:1) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) fn lock_item_transfer() -> Weight { - // Minimum execution time: 30_080 nanoseconds. - Weight::from_ref_time(30_825_000) - .saturating_add(RocksDbWeight::get().reads(2)) - .saturating_add(RocksDbWeight::get().writes(1)) - } - // Storage: Nfts CollectionRoleOf (r:1 w:0) - // Storage: Nfts ItemConfigOf (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `401` + // Estimated: `5067` + // Minimum execution time: 19_273 nanoseconds. + Weight::from_parts(19_508_000, 5067) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:1 w:1) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) fn unlock_item_transfer() -> Weight { - // Minimum execution time: 30_612 nanoseconds. - Weight::from_ref_time(31_422_000) - .saturating_add(RocksDbWeight::get().reads(2)) - .saturating_add(RocksDbWeight::get().writes(1)) - } - // Storage: Nfts CollectionRoleOf (r:1 w:0) - // Storage: Nfts CollectionConfigOf (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `401` + // Estimated: `5067` + // Minimum execution time: 19_022 nanoseconds. + Weight::from_parts(19_430_000, 5067) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:1) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) fn lock_collection() -> Weight { - // Minimum execution time: 27_470 nanoseconds. - Weight::from_ref_time(28_015_000) - .saturating_add(RocksDbWeight::get().reads(2)) - .saturating_add(RocksDbWeight::get().writes(1)) - } - // Storage: Nfts OwnershipAcceptance (r:1 w:1) - // Storage: Nfts Collection (r:1 w:1) - // Storage: Nfts CollectionAccount (r:0 w:2) + // Proof Size summary in bytes: + // Measured: `289` + // Estimated: `5092` + // Minimum execution time: 17_593 nanoseconds. + Weight::from_parts(17_950_000, 5092) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Nfts OwnershipAcceptance (r:1 w:1) + /// Proof: Nfts OwnershipAcceptance (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts CollectionAccount (r:0 w:2) + /// Proof: Nfts CollectionAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) fn transfer_ownership() -> Weight { - // Minimum execution time: 33_750 nanoseconds. - Weight::from_ref_time(34_139_000) - .saturating_add(RocksDbWeight::get().reads(2)) - .saturating_add(RocksDbWeight::get().writes(4)) - } - // Storage: Nfts Collection (r:1 w:1) - // Storage: Nfts CollectionRoleOf (r:0 w:4) + // Proof Size summary in bytes: + // Measured: `381` + // Estimated: `5082` + // Minimum execution time: 22_068 nanoseconds. + Weight::from_parts(22_235_000, 5082) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + } + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts CollectionRoleOf (r:0 w:4) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) fn set_team() -> Weight { - // Minimum execution time: 36_565 nanoseconds. - Weight::from_ref_time(37_464_000) - .saturating_add(RocksDbWeight::get().reads(1)) - .saturating_add(RocksDbWeight::get().writes(5)) - } - // Storage: Nfts Collection (r:1 w:1) - // Storage: Nfts CollectionAccount (r:0 w:2) + // Proof Size summary in bytes: + // Measured: `362` + // Estimated: `2555` + // Minimum execution time: 25_056 nanoseconds. + Weight::from_parts(25_767_000, 2555) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(5_u64)) + } + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts CollectionAccount (r:0 w:2) + /// Proof: Nfts CollectionAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) fn force_collection_owner() -> Weight { - // Minimum execution time: 29_028 nanoseconds. - Weight::from_ref_time(29_479_000) - .saturating_add(RocksDbWeight::get().reads(1)) - .saturating_add(RocksDbWeight::get().writes(3)) - } - // Storage: Nfts Collection (r:1 w:0) - // Storage: Nfts CollectionConfigOf (r:0 w:1) + // Proof Size summary in bytes: + // Measured: `304` + // Estimated: `2555` + // Minimum execution time: 17_398 nanoseconds. + Weight::from_parts(17_684_000, 2555) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: Nfts Collection (r:1 w:0) + /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:0 w:1) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) fn force_collection_config() -> Weight { - // Minimum execution time: 24_695 nanoseconds. - Weight::from_ref_time(25_304_000) - .saturating_add(RocksDbWeight::get().reads(1)) - .saturating_add(RocksDbWeight::get().writes(1)) - } - // Storage: Nfts Collection (r:1 w:0) - // Storage: Nfts ItemConfigOf (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `242` + // Estimated: `2555` + // Minimum execution time: 14_054 nanoseconds. + Weight::from_parts(14_243_000, 2555) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Nfts Collection (r:1 w:0) + /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:1 w:1) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) fn lock_item_properties() -> Weight { - // Minimum execution time: 28_910 nanoseconds. - Weight::from_ref_time(29_186_000) - .saturating_add(RocksDbWeight::get().reads(2)) - .saturating_add(RocksDbWeight::get().writes(1)) - } - // Storage: Nfts Collection (r:1 w:1) - // Storage: Nfts CollectionConfigOf (r:1 w:0) - // Storage: Nfts ItemConfigOf (r:1 w:0) - // Storage: Nfts Attribute (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `445` + // Estimated: `5078` + // Minimum execution time: 17_662 nanoseconds. + Weight::from_parts(18_073_000, 5078) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:0) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:1 w:0) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Nfts Attribute (r:1 w:1) + /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) fn set_attribute() -> Weight { - // Minimum execution time: 56_407 nanoseconds. - Weight::from_ref_time(58_176_000) - .saturating_add(RocksDbWeight::get().reads(4)) - .saturating_add(RocksDbWeight::get().writes(2)) - } - // Storage: Nfts Collection (r:1 w:1) - // Storage: Nfts Attribute (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `474` + // Estimated: `10547` + // Minimum execution time: 40_098 nanoseconds. + Weight::from_parts(40_649_000, 10547) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts Attribute (r:1 w:1) + /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) fn force_set_attribute() -> Weight { - // Minimum execution time: 36_402 nanoseconds. - Weight::from_ref_time(37_034_000) - .saturating_add(RocksDbWeight::get().reads(2)) - .saturating_add(RocksDbWeight::get().writes(2)) - } - // Storage: Nfts Attribute (r:1 w:1) - // Storage: Nfts Collection (r:1 w:1) - // Storage: Nfts ItemConfigOf (r:1 w:0) + // Proof Size summary in bytes: + // Measured: `337` + // Estimated: `5476` + // Minimum execution time: 25_178 nanoseconds. + Weight::from_parts(25_473_000, 5476) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: Nfts Attribute (r:1 w:1) + /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:1 w:0) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) fn clear_attribute() -> Weight { - // Minimum execution time: 52_022 nanoseconds. - Weight::from_ref_time(54_059_000) - .saturating_add(RocksDbWeight::get().reads(3)) - .saturating_add(RocksDbWeight::get().writes(2)) - } - // Storage: Nfts Item (r:1 w:0) - // Storage: Nfts ItemAttributesApprovalsOf (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `916` + // Estimated: `7999` + // Minimum execution time: 35_202 nanoseconds. + Weight::from_parts(35_518_000, 7999) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: Nfts Item (r:1 w:0) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts ItemAttributesApprovalsOf (r:1 w:1) + /// Proof: Nfts ItemAttributesApprovalsOf (max_values: None, max_size: Some(681), added: 3156, mode: MaxEncodedLen) fn approve_item_attributes() -> Weight { - // Minimum execution time: 28_475 nanoseconds. - Weight::from_ref_time(29_162_000) - .saturating_add(RocksDbWeight::get().reads(2)) - .saturating_add(RocksDbWeight::get().writes(1)) - } - // Storage: Nfts Item (r:1 w:0) - // Storage: Nfts ItemAttributesApprovalsOf (r:1 w:1) - // Storage: Nfts Attribute (r:1 w:0) - // Storage: System Account (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `379` + // Estimated: `6492` + // Minimum execution time: 17_260 nanoseconds. + Weight::from_parts(17_498_000, 6492) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Nfts Item (r:1 w:0) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts ItemAttributesApprovalsOf (r:1 w:1) + /// Proof: Nfts ItemAttributesApprovalsOf (max_values: None, max_size: Some(681), added: 3156, mode: MaxEncodedLen) + /// Storage: Nfts Attribute (r:1001 w:1000) + /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `n` is `[0, 1000]`. fn cancel_item_attributes_approval(n: u32, ) -> Weight { - // Minimum execution time: 37_529 nanoseconds. - Weight::from_ref_time(38_023_000) - // Standard Error: 8_136 - .saturating_add(Weight::from_ref_time(7_452_872).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(4)) + // Proof Size summary in bytes: + // Measured: `865 + n * (367 ±0)` + // Estimated: `12016 + n * (2921 ±0)` + // Minimum execution time: 25_579 nanoseconds. + Weight::from_parts(25_846_000, 12016) + // Standard Error: 7_759 + .saturating_add(Weight::from_ref_time(7_159_200).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) - .saturating_add(RocksDbWeight::get().writes(2)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) - } - // Storage: Nfts Collection (r:1 w:1) - // Storage: Nfts ItemConfigOf (r:1 w:0) - // Storage: Nfts CollectionConfigOf (r:1 w:0) - // Storage: Nfts ItemMetadataOf (r:1 w:1) + .saturating_add(Weight::from_proof_size(2921).saturating_mul(n.into())) + } + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:1 w:0) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:0) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts ItemMetadataOf (r:1 w:1) + /// Proof: Nfts ItemMetadataOf (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) fn set_metadata() -> Weight { - // Minimum execution time: 49_300 nanoseconds. - Weight::from_ref_time(49_790_000) - .saturating_add(RocksDbWeight::get().reads(4)) - .saturating_add(RocksDbWeight::get().writes(2)) - } - // Storage: Nfts Collection (r:1 w:1) - // Storage: Nfts ItemConfigOf (r:1 w:0) - // Storage: Nfts ItemMetadataOf (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `474` + // Estimated: `10241` + // Minimum execution time: 33_285 nanoseconds. + Weight::from_parts(33_692_000, 10241) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: Nfts ItemMetadataOf (r:1 w:1) + /// Proof: Nfts ItemMetadataOf (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:1 w:0) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) fn clear_metadata() -> Weight { - // Minimum execution time: 47_248 nanoseconds. - Weight::from_ref_time(48_094_000) - .saturating_add(RocksDbWeight::get().reads(3)) - .saturating_add(RocksDbWeight::get().writes(2)) - } - // Storage: Nfts CollectionConfigOf (r:1 w:0) - // Storage: Nfts Collection (r:1 w:1) - // Storage: Nfts CollectionMetadataOf (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `609` + // Estimated: `7693` + // Minimum execution time: 30_670 nanoseconds. + Weight::from_parts(31_282_000, 7693) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: Nfts CollectionConfigOf (r:1 w:0) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts CollectionMetadataOf (r:1 w:1) + /// Proof: Nfts CollectionMetadataOf (max_values: None, max_size: Some(87), added: 2562, mode: MaxEncodedLen) fn set_collection_metadata() -> Weight { - // Minimum execution time: 44_137 nanoseconds. - Weight::from_ref_time(44_905_000) - .saturating_add(RocksDbWeight::get().reads(3)) - .saturating_add(RocksDbWeight::get().writes(2)) - } - // Storage: Nfts Collection (r:1 w:0) - // Storage: Nfts CollectionConfigOf (r:1 w:0) - // Storage: Nfts CollectionMetadataOf (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `333` + // Estimated: `7665` + // Minimum execution time: 28_313 nanoseconds. + Weight::from_parts(28_724_000, 7665) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: Nfts Collection (r:1 w:0) + /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:0) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts CollectionMetadataOf (r:1 w:1) + /// Proof: Nfts CollectionMetadataOf (max_values: None, max_size: Some(87), added: 2562, mode: MaxEncodedLen) fn clear_collection_metadata() -> Weight { - // Minimum execution time: 43_005 nanoseconds. - Weight::from_ref_time(43_898_000) - .saturating_add(RocksDbWeight::get().reads(3)) - .saturating_add(RocksDbWeight::get().writes(1)) - } - // Storage: Nfts Item (r:1 w:1) - // Storage: Nfts CollectionConfigOf (r:1 w:0) - // Storage: Nfts CollectionRoleOf (r:1 w:0) + // Proof Size summary in bytes: + // Measured: `476` + // Estimated: `7665` + // Minimum execution time: 27_034 nanoseconds. + Weight::from_parts(27_655_000, 7665) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Nfts Item (r:1 w:1) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:0) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) fn approve_transfer() -> Weight { - // Minimum execution time: 36_344 nanoseconds. - Weight::from_ref_time(36_954_000) - .saturating_add(RocksDbWeight::get().reads(3)) - .saturating_add(RocksDbWeight::get().writes(1)) - } - // Storage: Nfts Item (r:1 w:1) - // Storage: Nfts CollectionRoleOf (r:1 w:0) + // Proof Size summary in bytes: + // Measured: `466` + // Estimated: `8428` + // Minimum execution time: 23_408 nanoseconds. + Weight::from_parts(23_916_000, 8428) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Nfts Item (r:1 w:1) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) fn cancel_approval() -> Weight { - // Minimum execution time: 32_418 nanoseconds. - Weight::from_ref_time(33_029_000) - .saturating_add(RocksDbWeight::get().reads(2)) - .saturating_add(RocksDbWeight::get().writes(1)) - } - // Storage: Nfts Item (r:1 w:1) - // Storage: Nfts CollectionRoleOf (r:1 w:0) + // Proof Size summary in bytes: + // Measured: `474` + // Estimated: `5880` + // Minimum execution time: 21_177 nanoseconds. + Weight::from_parts(21_492_000, 5880) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Nfts Item (r:1 w:1) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) fn clear_all_transfer_approvals() -> Weight { - // Minimum execution time: 31_448 nanoseconds. - Weight::from_ref_time(31_979_000) - .saturating_add(RocksDbWeight::get().reads(2)) - .saturating_add(RocksDbWeight::get().writes(1)) - } - // Storage: Nfts OwnershipAcceptance (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `474` + // Estimated: `5880` + // Minimum execution time: 20_279 nanoseconds. + Weight::from_parts(20_919_000, 5880) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Nfts OwnershipAcceptance (r:1 w:1) + /// Proof: Nfts OwnershipAcceptance (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) fn set_accept_ownership() -> Weight { - // Minimum execution time: 27_487 nanoseconds. - Weight::from_ref_time(28_080_000) - .saturating_add(RocksDbWeight::get().reads(1)) - .saturating_add(RocksDbWeight::get().writes(1)) - } - // Storage: Nfts CollectionConfigOf (r:1 w:1) - // Storage: Nfts Collection (r:1 w:0) + // Proof Size summary in bytes: + // Measured: `42` + // Estimated: `2527` + // Minimum execution time: 14_921 nanoseconds. + Weight::from_parts(15_382_000, 2527) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Nfts CollectionConfigOf (r:1 w:1) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:0) + /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) fn set_collection_max_supply() -> Weight { - // Minimum execution time: 28_235 nanoseconds. - Weight::from_ref_time(28_967_000) - .saturating_add(RocksDbWeight::get().reads(2)) - .saturating_add(RocksDbWeight::get().writes(1)) - } - // Storage: Nfts Collection (r:1 w:0) - // Storage: Nfts CollectionConfigOf (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `333` + // Estimated: `5103` + // Minimum execution time: 18_201 nanoseconds. + Weight::from_parts(18_628_000, 5103) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Nfts Collection (r:1 w:0) + /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:1) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) fn update_mint_settings() -> Weight { - // Minimum execution time: 28_172 nanoseconds. - Weight::from_ref_time(28_636_000) - .saturating_add(RocksDbWeight::get().reads(2)) - .saturating_add(RocksDbWeight::get().writes(1)) - } - // Storage: Nfts Item (r:1 w:0) - // Storage: Nfts CollectionConfigOf (r:1 w:0) - // Storage: Nfts ItemConfigOf (r:1 w:0) - // Storage: Nfts ItemPriceOf (r:0 w:1) + // Proof Size summary in bytes: + // Measured: `333` + // Estimated: `5103` + // Minimum execution time: 16_870 nanoseconds. + Weight::from_parts(17_318_000, 5103) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Nfts Item (r:1 w:0) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:0) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:1 w:0) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Nfts ItemPriceOf (r:0 w:1) + /// Proof: Nfts ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) fn set_price() -> Weight { - // Minimum execution time: 35_336 nanoseconds. - Weight::from_ref_time(36_026_000) - .saturating_add(RocksDbWeight::get().reads(3)) - .saturating_add(RocksDbWeight::get().writes(1)) - } - // Storage: Nfts Item (r:1 w:1) - // Storage: Nfts ItemPriceOf (r:1 w:1) - // Storage: Nfts Collection (r:1 w:0) - // Storage: Nfts CollectionConfigOf (r:1 w:0) - // Storage: Nfts ItemConfigOf (r:1 w:0) - // Storage: System Account (r:1 w:1) - // Storage: Nfts Account (r:0 w:2) - // Storage: Nfts PendingSwapOf (r:0 w:1) + // Proof Size summary in bytes: + // Measured: `516` + // Estimated: `8407` + // Minimum execution time: 22_604 nanoseconds. + Weight::from_parts(22_867_000, 8407) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Nfts Item (r:1 w:1) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts ItemPriceOf (r:1 w:1) + /// Proof: Nfts ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:0) + /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:0) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:1 w:0) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Nfts Account (r:0 w:2) + /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) + /// Storage: Nfts PendingSwapOf (r:0 w:1) + /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) fn buy_item() -> Weight { - // Minimum execution time: 70_971 nanoseconds. - Weight::from_ref_time(72_036_000) - .saturating_add(RocksDbWeight::get().reads(6)) - .saturating_add(RocksDbWeight::get().writes(6)) + // Proof Size summary in bytes: + // Measured: `934` + // Estimated: `16129` + // Minimum execution time: 56_849 nanoseconds. + Weight::from_parts(57_336_000, 16129) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(6_u64)) } /// The range of component `n` is `[0, 10]`. fn pay_tips(n: u32, ) -> Weight { - // Minimum execution time: 5_151 nanoseconds. - Weight::from_ref_time(11_822_888) - // Standard Error: 38_439 - .saturating_add(Weight::from_ref_time(3_511_844).saturating_mul(n.into())) - } - // Storage: Nfts Item (r:2 w:0) - // Storage: Nfts PendingSwapOf (r:0 w:1) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_308 nanoseconds. + Weight::from_ref_time(4_805_401) + // Standard Error: 13_875 + .saturating_add(Weight::from_ref_time(3_167_190).saturating_mul(n.into())) + } + /// Storage: Nfts Item (r:2 w:0) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts PendingSwapOf (r:0 w:1) + /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) fn create_swap() -> Weight { - // Minimum execution time: 33_027 nanoseconds. - Weight::from_ref_time(33_628_000) - .saturating_add(RocksDbWeight::get().reads(2)) - .saturating_add(RocksDbWeight::get().writes(1)) - } - // Storage: Nfts PendingSwapOf (r:1 w:1) - // Storage: Nfts Item (r:1 w:0) + // Proof Size summary in bytes: + // Measured: `524` + // Estimated: `6672` + // Minimum execution time: 20_395 nanoseconds. + Weight::from_parts(20_716_000, 6672) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Nfts PendingSwapOf (r:1 w:1) + /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) + /// Storage: Nfts Item (r:1 w:0) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) fn cancel_swap() -> Weight { - // Minimum execution time: 35_890 nanoseconds. - Weight::from_ref_time(36_508_000) - .saturating_add(RocksDbWeight::get().reads(2)) - .saturating_add(RocksDbWeight::get().writes(1)) - } - // Storage: Nfts Item (r:2 w:2) - // Storage: Nfts PendingSwapOf (r:1 w:2) - // Storage: Nfts Collection (r:1 w:0) - // Storage: Nfts CollectionConfigOf (r:1 w:0) - // Storage: Nfts ItemConfigOf (r:2 w:0) - // Storage: System Account (r:1 w:1) - // Storage: Nfts Account (r:0 w:4) - // Storage: Nfts ItemPriceOf (r:0 w:2) + // Proof Size summary in bytes: + // Measured: `511` + // Estimated: `5882` + // Minimum execution time: 19_936 nanoseconds. + Weight::from_parts(20_344_000, 5882) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Nfts Item (r:2 w:2) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts PendingSwapOf (r:1 w:2) + /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:0) + /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:0) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:2 w:0) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Nfts Account (r:0 w:4) + /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) + /// Storage: Nfts ItemPriceOf (r:0 w:2) + /// Proof: Nfts ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) fn claim_swap() -> Weight { - // Minimum execution time: 101_076 nanoseconds. - Weight::from_ref_time(101_863_000) - .saturating_add(RocksDbWeight::get().reads(8)) - .saturating_add(RocksDbWeight::get().writes(11)) + // Proof Size summary in bytes: + // Measured: `1097` + // Estimated: `21970` + // Minimum execution time: 80_884 nanoseconds. + Weight::from_parts(81_643_000, 21970) + .saturating_add(RocksDbWeight::get().reads(8_u64)) + .saturating_add(RocksDbWeight::get().writes(11_u64)) } } diff --git a/frame/nis/src/weights.rs b/frame/nis/src/weights.rs index 769ff795514c6..07221f358cab6 100644 --- a/frame/nis/src/weights.rs +++ b/frame/nis/src/weights.rs @@ -1,31 +1,43 @@ +// This file is part of Substrate. + +// Copyright (C) 2023 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. //! Autogenerated weights for pallet_nis //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-12-15, STEPS: `5`, REPEAT: 2, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `Workhorse.local`, CPU: `` +//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! 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 -// 5 -// --repeat -// 2 -// --pallet -// pallet_nis -// --extrinsic -// * +// --chain=dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_nis +// --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --output -// ../../../frame/nis/src/weights.rs -// --template -// ../../../.maintain/frame-weight-template.hbs +// --heap-pages=4096 +// --output=./frame/nis/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -52,224 +64,364 @@ pub trait WeightInfo { /// Weights for pallet_nis using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - // Storage: Nis Queues (r:1 w:1) - // Storage: Balances Reserves (r:1 w:1) - // Storage: Nis QueueTotals (r:1 w:1) + /// Storage: Nis Queues (r:1 w:1) + /// Proof: Nis Queues (max_values: None, max_size: Some(48022), added: 50497, mode: MaxEncodedLen) + /// Storage: Balances Reserves (r:1 w:1) + /// Proof: Balances Reserves (max_values: None, max_size: Some(1249), added: 3724, mode: MaxEncodedLen) + /// Storage: Nis QueueTotals (r:1 w:1) + /// Proof: Nis QueueTotals (max_values: Some(1), max_size: Some(6002), added: 6497, mode: MaxEncodedLen) /// The range of component `l` is `[0, 999]`. fn place_bid(l: u32, ) -> Weight { - // Minimum execution time: 47_000 nanoseconds. - Weight::from_ref_time(53_822_030) - // Standard Error: 4_869 - .saturating_add(Weight::from_ref_time(47_431).saturating_mul(l.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) + // Proof Size summary in bytes: + // Measured: `6245 + l * (48 ±0)` + // Estimated: `60718` + // Minimum execution time: 28_814 nanoseconds. + Weight::from_parts(35_245_917, 60718) + // Standard Error: 189 + .saturating_add(Weight::from_ref_time(45_322).saturating_mul(l.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) } - // Storage: Nis Queues (r:1 w:1) - // Storage: Balances Reserves (r:1 w:1) - // Storage: Nis QueueTotals (r:1 w:1) + /// Storage: Nis Queues (r:1 w:1) + /// Proof: Nis Queues (max_values: None, max_size: Some(48022), added: 50497, mode: MaxEncodedLen) + /// Storage: Balances Reserves (r:1 w:1) + /// Proof: Balances Reserves (max_values: None, max_size: Some(1249), added: 3724, mode: MaxEncodedLen) + /// Storage: Nis QueueTotals (r:1 w:1) + /// Proof: Nis QueueTotals (max_values: Some(1), max_size: Some(6002), added: 6497, mode: MaxEncodedLen) fn place_bid_max() -> Weight { - // Minimum execution time: 109_000 nanoseconds. - Weight::from_ref_time(109_000_000) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) + // Proof Size summary in bytes: + // Measured: `54247` + // Estimated: `60718` + // Minimum execution time: 80_332 nanoseconds. + Weight::from_parts(81_050_000, 60718) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) } - // Storage: Nis Queues (r:1 w:1) - // Storage: Nis QueueTotals (r:1 w:1) - // Storage: Balances Reserves (r:1 w:1) + /// Storage: Nis Queues (r:1 w:1) + /// Proof: Nis Queues (max_values: None, max_size: Some(48022), added: 50497, mode: MaxEncodedLen) + /// Storage: Nis QueueTotals (r:1 w:1) + /// Proof: Nis QueueTotals (max_values: Some(1), max_size: Some(6002), added: 6497, mode: MaxEncodedLen) + /// Storage: Balances Reserves (r:1 w:1) + /// Proof: Balances Reserves (max_values: None, max_size: Some(1249), added: 3724, mode: MaxEncodedLen) /// The range of component `l` is `[1, 1000]`. fn retract_bid(l: u32, ) -> Weight { - // Minimum execution time: 50_000 nanoseconds. - Weight::from_ref_time(54_479_879) - // Standard Error: 4_891 - .saturating_add(Weight::from_ref_time(38_224).saturating_mul(l.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) + // Proof Size summary in bytes: + // Measured: `6245 + l * (48 ±0)` + // Estimated: `60718` + // Minimum execution time: 34_426 nanoseconds. + Weight::from_parts(36_434_166, 60718) + // Standard Error: 135 + .saturating_add(Weight::from_ref_time(33_923).saturating_mul(l.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) } - // Storage: Nis Summary (r:1 w:0) - // Storage: System Account (r:1 w:1) + /// Storage: Nis Summary (r:1 w:0) + /// Proof: Nis Summary (max_values: Some(1), max_size: Some(40), added: 535, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn fund_deficit() -> Weight { - // Minimum execution time: 57_000 nanoseconds. - Weight::from_ref_time(62_000_000) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) + // Proof Size summary in bytes: + // Measured: `222` + // Estimated: `3138` + // Minimum execution time: 32_566 nanoseconds. + Weight::from_parts(32_880_000, 3138) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - // Storage: Nis Receipts (r:1 w:1) - // Storage: Nis Summary (r:1 w:1) - // Storage: System Account (r:1 w:0) - // Storage: Balances Reserves (r:1 w:1) + /// Storage: Nis Receipts (r:1 w:1) + /// Proof: Nis Receipts (max_values: None, max_size: Some(81), added: 2556, mode: MaxEncodedLen) + /// Storage: Nis Summary (r:1 w:1) + /// Proof: Nis Summary (max_values: Some(1), max_size: Some(40), added: 535, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Balances Reserves (r:1 w:1) + /// Proof: Balances Reserves (max_values: None, max_size: Some(1249), added: 3724, mode: MaxEncodedLen) fn thaw_private() -> Weight { - // Minimum execution time: 84_000 nanoseconds. - Weight::from_ref_time(85_000_000) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) + // Proof Size summary in bytes: + // Measured: `423` + // Estimated: `9418` + // Minimum execution time: 46_212 nanoseconds. + Weight::from_parts(46_748_000, 9418) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) } - // Storage: Nis Receipts (r:1 w:1) - // Storage: Nis Summary (r:1 w:1) - // Storage: Assets Asset (r:1 w:1) - // Storage: Assets Account (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: Nis Receipts (r:1 w:1) + /// Proof: Nis Receipts (max_values: None, max_size: Some(81), added: 2556, mode: MaxEncodedLen) + /// Storage: Nis Summary (r:1 w:1) + /// Proof: Nis Summary (max_values: Some(1), max_size: Some(40), added: 535, mode: MaxEncodedLen) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Account (r:1 w:1) + /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn thaw_communal() -> Weight { - // Minimum execution time: 108_000 nanoseconds. - Weight::from_ref_time(115_000_000) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(5)) + // Proof Size summary in bytes: + // Measured: `868` + // Estimated: `10956` + // Minimum execution time: 68_791 nanoseconds. + Weight::from_parts(69_504_000, 10956) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) } - // Storage: Nis Receipts (r:1 w:1) - // Storage: Nis Summary (r:1 w:1) - // Storage: System Account (r:1 w:1) - // Storage: Assets Asset (r:1 w:1) - // Storage: Assets Account (r:1 w:1) - // Storage: Balances Reserves (r:1 w:1) + /// Storage: Nis Receipts (r:1 w:1) + /// Proof: Nis Receipts (max_values: None, max_size: Some(81), added: 2556, mode: MaxEncodedLen) + /// Storage: Nis Summary (r:1 w:1) + /// Proof: Nis Summary (max_values: Some(1), max_size: Some(40), added: 535, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Account (r:1 w:1) + /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) + /// Storage: Balances Reserves (r:1 w:1) + /// Proof: Balances Reserves (max_values: None, max_size: Some(1249), added: 3724, mode: MaxEncodedLen) fn privatize() -> Weight { - // Minimum execution time: 107_000 nanoseconds. - Weight::from_ref_time(110_000_000) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(6)) + // Proof Size summary in bytes: + // Measured: `930` + // Estimated: `14680` + // Minimum execution time: 76_784 nanoseconds. + Weight::from_parts(77_575_000, 14680) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(6_u64)) } - // Storage: Nis Receipts (r:1 w:1) - // Storage: Balances Reserves (r:1 w:1) - // Storage: System Account (r:1 w:1) - // Storage: Nis Summary (r:1 w:1) - // Storage: Assets Asset (r:1 w:1) - // Storage: Assets Account (r:1 w:1) + /// Storage: Nis Receipts (r:1 w:1) + /// Proof: Nis Receipts (max_values: None, max_size: Some(81), added: 2556, mode: MaxEncodedLen) + /// Storage: Balances Reserves (r:1 w:1) + /// Proof: Balances Reserves (max_values: None, max_size: Some(1249), added: 3724, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Nis Summary (r:1 w:1) + /// Proof: Nis Summary (max_values: Some(1), max_size: Some(40), added: 535, mode: MaxEncodedLen) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Account (r:1 w:1) + /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) fn communify() -> Weight { - // Minimum execution time: 89_000 nanoseconds. - Weight::from_ref_time(89_000_000) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(6)) + // Proof Size summary in bytes: + // Measured: `769` + // Estimated: `14680` + // Minimum execution time: 64_543 nanoseconds. + Weight::from_parts(65_258_000, 14680) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(6_u64)) } - // Storage: Nis Summary (r:1 w:1) - // Storage: System Account (r:1 w:0) - // Storage: Nis QueueTotals (r:1 w:1) + /// Storage: Nis Summary (r:1 w:1) + /// Proof: Nis Summary (max_values: Some(1), max_size: Some(40), added: 535, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Nis QueueTotals (r:1 w:1) + /// Proof: Nis QueueTotals (max_values: Some(1), max_size: Some(6002), added: 6497, mode: MaxEncodedLen) fn process_queues() -> Weight { - // Minimum execution time: 34_000 nanoseconds. - Weight::from_ref_time(38_000_000) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) + // Proof Size summary in bytes: + // Measured: `6655` + // Estimated: `9635` + // Minimum execution time: 21_379 nanoseconds. + Weight::from_parts(21_736_000, 9635) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } - // Storage: Nis Queues (r:1 w:1) + /// Storage: Nis Queues (r:1 w:1) + /// Proof: Nis Queues (max_values: None, max_size: Some(48022), added: 50497, mode: MaxEncodedLen) fn process_queue() -> Weight { - // Minimum execution time: 6_000 nanoseconds. - Weight::from_ref_time(7_000_000) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) + // Proof Size summary in bytes: + // Measured: `42` + // Estimated: `50497` + // Minimum execution time: 4_302 nanoseconds. + Weight::from_parts(4_440_000, 50497) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - // Storage: Nis Receipts (r:0 w:1) + /// Storage: Nis Receipts (r:0 w:1) + /// Proof: Nis Receipts (max_values: None, max_size: Some(81), added: 2556, mode: MaxEncodedLen) fn process_bid() -> Weight { - // Minimum execution time: 14_000 nanoseconds. - Weight::from_ref_time(15_000_000) - .saturating_add(T::DbWeight::get().writes(1)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 6_758 nanoseconds. + Weight::from_ref_time(6_911_000) + .saturating_add(T::DbWeight::get().writes(1_u64)) } } // For backwards compatibility and tests impl WeightInfo for () { - // Storage: Nis Queues (r:1 w:1) - // Storage: Balances Reserves (r:1 w:1) - // Storage: Nis QueueTotals (r:1 w:1) + /// Storage: Nis Queues (r:1 w:1) + /// Proof: Nis Queues (max_values: None, max_size: Some(48022), added: 50497, mode: MaxEncodedLen) + /// Storage: Balances Reserves (r:1 w:1) + /// Proof: Balances Reserves (max_values: None, max_size: Some(1249), added: 3724, mode: MaxEncodedLen) + /// Storage: Nis QueueTotals (r:1 w:1) + /// Proof: Nis QueueTotals (max_values: Some(1), max_size: Some(6002), added: 6497, mode: MaxEncodedLen) /// The range of component `l` is `[0, 999]`. fn place_bid(l: u32, ) -> Weight { - // Minimum execution time: 47_000 nanoseconds. - Weight::from_ref_time(53_822_030) - // Standard Error: 4_869 - .saturating_add(Weight::from_ref_time(47_431).saturating_mul(l.into())) - .saturating_add(RocksDbWeight::get().reads(3)) - .saturating_add(RocksDbWeight::get().writes(3)) + // Proof Size summary in bytes: + // Measured: `6245 + l * (48 ±0)` + // Estimated: `60718` + // Minimum execution time: 28_814 nanoseconds. + Weight::from_parts(35_245_917, 60718) + // Standard Error: 189 + .saturating_add(Weight::from_ref_time(45_322).saturating_mul(l.into())) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) } - // Storage: Nis Queues (r:1 w:1) - // Storage: Balances Reserves (r:1 w:1) - // Storage: Nis QueueTotals (r:1 w:1) + /// Storage: Nis Queues (r:1 w:1) + /// Proof: Nis Queues (max_values: None, max_size: Some(48022), added: 50497, mode: MaxEncodedLen) + /// Storage: Balances Reserves (r:1 w:1) + /// Proof: Balances Reserves (max_values: None, max_size: Some(1249), added: 3724, mode: MaxEncodedLen) + /// Storage: Nis QueueTotals (r:1 w:1) + /// Proof: Nis QueueTotals (max_values: Some(1), max_size: Some(6002), added: 6497, mode: MaxEncodedLen) fn place_bid_max() -> Weight { - // Minimum execution time: 109_000 nanoseconds. - Weight::from_ref_time(109_000_000) - .saturating_add(RocksDbWeight::get().reads(3)) - .saturating_add(RocksDbWeight::get().writes(3)) + // Proof Size summary in bytes: + // Measured: `54247` + // Estimated: `60718` + // Minimum execution time: 80_332 nanoseconds. + Weight::from_parts(81_050_000, 60718) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) } - // Storage: Nis Queues (r:1 w:1) - // Storage: Nis QueueTotals (r:1 w:1) - // Storage: Balances Reserves (r:1 w:1) + /// Storage: Nis Queues (r:1 w:1) + /// Proof: Nis Queues (max_values: None, max_size: Some(48022), added: 50497, mode: MaxEncodedLen) + /// Storage: Nis QueueTotals (r:1 w:1) + /// Proof: Nis QueueTotals (max_values: Some(1), max_size: Some(6002), added: 6497, mode: MaxEncodedLen) + /// Storage: Balances Reserves (r:1 w:1) + /// Proof: Balances Reserves (max_values: None, max_size: Some(1249), added: 3724, mode: MaxEncodedLen) /// The range of component `l` is `[1, 1000]`. fn retract_bid(l: u32, ) -> Weight { - // Minimum execution time: 50_000 nanoseconds. - Weight::from_ref_time(54_479_879) - // Standard Error: 4_891 - .saturating_add(Weight::from_ref_time(38_224).saturating_mul(l.into())) - .saturating_add(RocksDbWeight::get().reads(3)) - .saturating_add(RocksDbWeight::get().writes(3)) + // Proof Size summary in bytes: + // Measured: `6245 + l * (48 ±0)` + // Estimated: `60718` + // Minimum execution time: 34_426 nanoseconds. + Weight::from_parts(36_434_166, 60718) + // Standard Error: 135 + .saturating_add(Weight::from_ref_time(33_923).saturating_mul(l.into())) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) } - // Storage: Nis Summary (r:1 w:0) - // Storage: System Account (r:1 w:1) + /// Storage: Nis Summary (r:1 w:0) + /// Proof: Nis Summary (max_values: Some(1), max_size: Some(40), added: 535, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn fund_deficit() -> Weight { - // Minimum execution time: 57_000 nanoseconds. - Weight::from_ref_time(62_000_000) - .saturating_add(RocksDbWeight::get().reads(2)) - .saturating_add(RocksDbWeight::get().writes(1)) + // Proof Size summary in bytes: + // Measured: `222` + // Estimated: `3138` + // Minimum execution time: 32_566 nanoseconds. + Weight::from_parts(32_880_000, 3138) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - // Storage: Nis Receipts (r:1 w:1) - // Storage: Nis Summary (r:1 w:1) - // Storage: System Account (r:1 w:0) - // Storage: Balances Reserves (r:1 w:1) + /// Storage: Nis Receipts (r:1 w:1) + /// Proof: Nis Receipts (max_values: None, max_size: Some(81), added: 2556, mode: MaxEncodedLen) + /// Storage: Nis Summary (r:1 w:1) + /// Proof: Nis Summary (max_values: Some(1), max_size: Some(40), added: 535, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Balances Reserves (r:1 w:1) + /// Proof: Balances Reserves (max_values: None, max_size: Some(1249), added: 3724, mode: MaxEncodedLen) fn thaw_private() -> Weight { - // Minimum execution time: 84_000 nanoseconds. - Weight::from_ref_time(85_000_000) - .saturating_add(RocksDbWeight::get().reads(4)) - .saturating_add(RocksDbWeight::get().writes(3)) + // Proof Size summary in bytes: + // Measured: `423` + // Estimated: `9418` + // Minimum execution time: 46_212 nanoseconds. + Weight::from_parts(46_748_000, 9418) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) } - // Storage: Nis Receipts (r:1 w:1) - // Storage: Nis Summary (r:1 w:1) - // Storage: Assets Asset (r:1 w:1) - // Storage: Assets Account (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: Nis Receipts (r:1 w:1) + /// Proof: Nis Receipts (max_values: None, max_size: Some(81), added: 2556, mode: MaxEncodedLen) + /// Storage: Nis Summary (r:1 w:1) + /// Proof: Nis Summary (max_values: Some(1), max_size: Some(40), added: 535, mode: MaxEncodedLen) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Account (r:1 w:1) + /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn thaw_communal() -> Weight { - // Minimum execution time: 108_000 nanoseconds. - Weight::from_ref_time(115_000_000) - .saturating_add(RocksDbWeight::get().reads(5)) - .saturating_add(RocksDbWeight::get().writes(5)) + // Proof Size summary in bytes: + // Measured: `868` + // Estimated: `10956` + // Minimum execution time: 68_791 nanoseconds. + Weight::from_parts(69_504_000, 10956) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(5_u64)) } - // Storage: Nis Receipts (r:1 w:1) - // Storage: Nis Summary (r:1 w:1) - // Storage: System Account (r:1 w:1) - // Storage: Assets Asset (r:1 w:1) - // Storage: Assets Account (r:1 w:1) - // Storage: Balances Reserves (r:1 w:1) + /// Storage: Nis Receipts (r:1 w:1) + /// Proof: Nis Receipts (max_values: None, max_size: Some(81), added: 2556, mode: MaxEncodedLen) + /// Storage: Nis Summary (r:1 w:1) + /// Proof: Nis Summary (max_values: Some(1), max_size: Some(40), added: 535, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Account (r:1 w:1) + /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) + /// Storage: Balances Reserves (r:1 w:1) + /// Proof: Balances Reserves (max_values: None, max_size: Some(1249), added: 3724, mode: MaxEncodedLen) fn privatize() -> Weight { - // Minimum execution time: 107_000 nanoseconds. - Weight::from_ref_time(110_000_000) - .saturating_add(RocksDbWeight::get().reads(6)) - .saturating_add(RocksDbWeight::get().writes(6)) + // Proof Size summary in bytes: + // Measured: `930` + // Estimated: `14680` + // Minimum execution time: 76_784 nanoseconds. + Weight::from_parts(77_575_000, 14680) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(6_u64)) } - // Storage: Nis Receipts (r:1 w:1) - // Storage: Balances Reserves (r:1 w:1) - // Storage: System Account (r:1 w:1) - // Storage: Nis Summary (r:1 w:1) - // Storage: Assets Asset (r:1 w:1) - // Storage: Assets Account (r:1 w:1) + /// Storage: Nis Receipts (r:1 w:1) + /// Proof: Nis Receipts (max_values: None, max_size: Some(81), added: 2556, mode: MaxEncodedLen) + /// Storage: Balances Reserves (r:1 w:1) + /// Proof: Balances Reserves (max_values: None, max_size: Some(1249), added: 3724, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Nis Summary (r:1 w:1) + /// Proof: Nis Summary (max_values: Some(1), max_size: Some(40), added: 535, mode: MaxEncodedLen) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Account (r:1 w:1) + /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) fn communify() -> Weight { - // Minimum execution time: 89_000 nanoseconds. - Weight::from_ref_time(89_000_000) - .saturating_add(RocksDbWeight::get().reads(6)) - .saturating_add(RocksDbWeight::get().writes(6)) + // Proof Size summary in bytes: + // Measured: `769` + // Estimated: `14680` + // Minimum execution time: 64_543 nanoseconds. + Weight::from_parts(65_258_000, 14680) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(6_u64)) } - // Storage: Nis Summary (r:1 w:1) - // Storage: System Account (r:1 w:0) - // Storage: Nis QueueTotals (r:1 w:1) + /// Storage: Nis Summary (r:1 w:1) + /// Proof: Nis Summary (max_values: Some(1), max_size: Some(40), added: 535, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Nis QueueTotals (r:1 w:1) + /// Proof: Nis QueueTotals (max_values: Some(1), max_size: Some(6002), added: 6497, mode: MaxEncodedLen) fn process_queues() -> Weight { - // Minimum execution time: 34_000 nanoseconds. - Weight::from_ref_time(38_000_000) - .saturating_add(RocksDbWeight::get().reads(3)) - .saturating_add(RocksDbWeight::get().writes(2)) + // Proof Size summary in bytes: + // Measured: `6655` + // Estimated: `9635` + // Minimum execution time: 21_379 nanoseconds. + Weight::from_parts(21_736_000, 9635) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } - // Storage: Nis Queues (r:1 w:1) + /// Storage: Nis Queues (r:1 w:1) + /// Proof: Nis Queues (max_values: None, max_size: Some(48022), added: 50497, mode: MaxEncodedLen) fn process_queue() -> Weight { - // Minimum execution time: 6_000 nanoseconds. - Weight::from_ref_time(7_000_000) - .saturating_add(RocksDbWeight::get().reads(1)) - .saturating_add(RocksDbWeight::get().writes(1)) + // Proof Size summary in bytes: + // Measured: `42` + // Estimated: `50497` + // Minimum execution time: 4_302 nanoseconds. + Weight::from_parts(4_440_000, 50497) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - // Storage: Nis Receipts (r:0 w:1) + /// Storage: Nis Receipts (r:0 w:1) + /// Proof: Nis Receipts (max_values: None, max_size: Some(81), added: 2556, mode: MaxEncodedLen) fn process_bid() -> Weight { - // Minimum execution time: 14_000 nanoseconds. - Weight::from_ref_time(15_000_000) - .saturating_add(RocksDbWeight::get().writes(1)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 6_758 nanoseconds. + Weight::from_ref_time(6_911_000) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } } diff --git a/frame/nomination-pools/src/weights.rs b/frame/nomination-pools/src/weights.rs index 1062b1749d417..ae73015940f80 100644 --- a/frame/nomination-pools/src/weights.rs +++ b/frame/nomination-pools/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2023 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,7 +18,8 @@ //! Autogenerated weights for pallet_nomination_pools //! //! 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: `[]` +//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -67,492 +68,854 @@ pub trait WeightInfo { /// Weights for pallet_nomination_pools using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - // Storage: NominationPools MinJoinBond (r:1 w:0) - // 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: Balances Locks (r:1 w:1) - // Storage: VoterList ListNodes (r:3 w:3) - // Storage: VoterList ListBags (r:2 w:2) + /// Storage: NominationPools MinJoinBond (r:1 w:0) + /// Proof: NominationPools MinJoinBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: NominationPools PoolMembers (r:1 w:1) + /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(237), added: 2712, mode: MaxEncodedLen) + /// Storage: NominationPools BondedPools (r:1 w:1) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:1 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:1 w:1) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: NominationPools RewardPools (r:1 w:1) + /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(60), added: 2535, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: NominationPools MaxPoolMembersPerPool (r:1 w:0) + /// Proof: NominationPools MaxPoolMembersPerPool (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: NominationPools MaxPoolMembers (r:1 w:0) + /// Proof: NominationPools MaxPoolMembers (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: NominationPools CounterForPoolMembers (r:1 w:1) + /// Proof: NominationPools CounterForPoolMembers (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:3 w:3) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:2 w:2) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) fn join() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `3573` + // Estimated: `37988` + // Minimum execution time: 140_155 nanoseconds. + Weight::from_parts(141_098_000, 37988) + .saturating_add(T::DbWeight::get().reads(17_u64)) + .saturating_add(T::DbWeight::get().writes(12_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:3 w:2) - // Storage: Staking Bonded (r:1 w:0) - // Storage: Staking Ledger (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) - // Storage: VoterList ListNodes (r:3 w:3) - // Storage: VoterList ListBags (r:2 w:2) + /// Storage: NominationPools PoolMembers (r:1 w:1) + /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(237), added: 2712, mode: MaxEncodedLen) + /// Storage: NominationPools BondedPools (r:1 w:1) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) + /// Storage: NominationPools RewardPools (r:1 w:1) + /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(60), added: 2535, mode: MaxEncodedLen) + /// Storage: System Account (r:3 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:1 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:1 w:1) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:3 w:3) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:2 w:2) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) fn bond_extra_transfer() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `3615` + // Estimated: `38583` + // Minimum execution time: 136_048 nanoseconds. + Weight::from_parts(136_767_000, 38583) + .saturating_add(T::DbWeight::get().reads(14_u64)) + .saturating_add(T::DbWeight::get().writes(12_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:3 w:3) - // Storage: Staking Bonded (r:1 w:0) - // Storage: Staking Ledger (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) - // Storage: VoterList ListNodes (r:3 w:3) - // Storage: VoterList ListBags (r:2 w:2) + /// Storage: NominationPools PoolMembers (r:1 w:1) + /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(237), added: 2712, mode: MaxEncodedLen) + /// Storage: NominationPools BondedPools (r:1 w:1) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) + /// Storage: NominationPools RewardPools (r:1 w:1) + /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(60), added: 2535, mode: MaxEncodedLen) + /// Storage: System Account (r:3 w:3) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:1 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:1 w:1) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:3 w:3) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:2 w:2) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) fn bond_extra_reward() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `3615` + // Estimated: `38583` + // Minimum execution time: 151_473 nanoseconds. + Weight::from_parts(152_375_000, 38583) + .saturating_add(T::DbWeight::get().reads(14_u64)) + .saturating_add(T::DbWeight::get().writes(13_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) + /// Storage: NominationPools PoolMembers (r:1 w:1) + /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(237), added: 2712, mode: MaxEncodedLen) + /// Storage: NominationPools BondedPools (r:1 w:1) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) + /// Storage: NominationPools RewardPools (r:1 w:1) + /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(60), added: 2535, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn claim_payout() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `1189` + // Estimated: `10489` + // Minimum execution time: 51_146 nanoseconds. + Weight::from_parts(51_570_000, 10489) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(4_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 Nominators (r:1 w:0) - // Storage: Staking MinNominatorBond (r:1 w:0) - // Storage: Balances Locks (r:1 w:1) - // 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) + /// Storage: NominationPools PoolMembers (r:1 w:1) + /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(237), added: 2712, mode: MaxEncodedLen) + /// Storage: NominationPools BondedPools (r:1 w:1) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) + /// Storage: NominationPools RewardPools (r:1 w:1) + /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(60), added: 2535, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:1 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:1 w:1) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Staking CurrentEra (r:1 w:0) + /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:1 w:0) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) + /// Storage: Staking MinNominatorBond (r:1 w:0) + /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:3 w:3) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:2 w:2) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: NominationPools SubPoolsStorage (r:1 w:1) + /// Proof: NominationPools SubPoolsStorage (max_values: None, max_size: Some(24382), added: 26857, mode: MaxEncodedLen) + /// Storage: NominationPools CounterForSubPoolsStorage (r:1 w:1) + /// Proof: NominationPools CounterForSubPoolsStorage (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn unbond() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `3858` + // Estimated: `67379` + // Minimum execution time: 141_400 nanoseconds. + Weight::from_parts(141_822_000, 67379) + .saturating_add(T::DbWeight::get().reads(18_u64)) + .saturating_add(T::DbWeight::get().writes(13_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) + /// Storage: NominationPools BondedPools (r:1 w:0) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:1 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:1 w:1) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking CurrentEra (r:1 w:0) + /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) /// The range of component `s` is `[0, 100]`. fn pool_withdraw_unbonded(s: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `1779` + // Estimated: `13025` + // Minimum execution time: 49_021 nanoseconds. + Weight::from_parts(49_954_282, 13025) + // Standard Error: 378 + .saturating_add(Weight::from_ref_time(5_165).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(2_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) + /// Storage: NominationPools PoolMembers (r:1 w:1) + /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(237), added: 2712, mode: MaxEncodedLen) + /// Storage: Staking CurrentEra (r:1 w:0) + /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: NominationPools BondedPools (r:1 w:1) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) + /// Storage: NominationPools SubPoolsStorage (r:1 w:1) + /// Proof: NominationPools SubPoolsStorage (max_values: None, max_size: Some(24382), added: 26857, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:1 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:1 w:1) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: NominationPools CounterForPoolMembers (r:1 w:1) + /// Proof: NominationPools CounterForPoolMembers (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `2303` + // Estimated: `45696` + // Minimum execution time: 92_473 nanoseconds. + Weight::from_parts(93_901_972, 45696) + // Standard Error: 618 + .saturating_add(Weight::from_ref_time(12_032).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(9_u64)) + .saturating_add(T::DbWeight::get().writes(7_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: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) - // 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 Metadata (r:1 w:1) - // Storage: NominationPools CounterForBondedPools (r:1 w:1) - // Storage: Staking Payee (r:0 w:1) + /// Storage: NominationPools PoolMembers (r:1 w:1) + /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(237), added: 2712, mode: MaxEncodedLen) + /// Storage: Staking CurrentEra (r:1 w:0) + /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: NominationPools BondedPools (r:1 w:1) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) + /// Storage: NominationPools SubPoolsStorage (r:1 w:1) + /// Proof: NominationPools SubPoolsStorage (max_values: None, max_size: Some(24382), added: 26857, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:1 w:1) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:1 w:1) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking SlashingSpans (r:1 w:0) + /// Proof Skipped: Staking SlashingSpans (max_values: None, max_size: None, mode: Measured) + /// Storage: Staking Validators (r:1 w:0) + /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:1 w:0) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: NominationPools CounterForPoolMembers (r:1 w:1) + /// Proof: NominationPools CounterForPoolMembers (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: NominationPools ReversePoolIdLookup (r:1 w:1) + /// Proof: NominationPools ReversePoolIdLookup (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) + /// Storage: NominationPools CounterForReversePoolIdLookup (r:1 w:1) + /// Proof: NominationPools CounterForReversePoolIdLookup (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: NominationPools RewardPools (r:1 w:1) + /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(60), added: 2535, mode: MaxEncodedLen) + /// Storage: NominationPools CounterForRewardPools (r:1 w:1) + /// Proof: NominationPools CounterForRewardPools (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: NominationPools CounterForSubPoolsStorage (r:1 w:1) + /// Proof: NominationPools CounterForSubPoolsStorage (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: NominationPools Metadata (r:1 w:1) + /// Proof: NominationPools Metadata (max_values: None, max_size: Some(270), added: 2745, mode: MaxEncodedLen) + /// Storage: NominationPools CounterForBondedPools (r:1 w:1) + /// Proof: NominationPools CounterForBondedPools (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking Payee (r:0 w:1) + /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) /// The range of component `s` is `[0, 100]`. - 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)) + fn withdraw_unbonded_kill(_s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `2690` + // Estimated: `68812` + // Minimum execution time: 150_063 nanoseconds. + Weight::from_parts(152_321_387, 68812) + .saturating_add(T::DbWeight::get().reads(20_u64)) + .saturating_add(T::DbWeight::get().writes(17_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 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 Bonded (r:1 w:1) - // Storage: Staking Ledger (r:1 w:1) - // Storage: Staking CurrentEra (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) + /// Storage: NominationPools LastPoolId (r:1 w:1) + /// Proof: NominationPools LastPoolId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking MinNominatorBond (r:1 w:0) + /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: NominationPools MinCreateBond (r:1 w:0) + /// Proof: NominationPools MinCreateBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: NominationPools MinJoinBond (r:1 w:0) + /// Proof: NominationPools MinJoinBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: NominationPools MaxPools (r:1 w:0) + /// Proof: NominationPools MaxPools (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: NominationPools CounterForBondedPools (r:1 w:1) + /// Proof: NominationPools CounterForBondedPools (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: NominationPools PoolMembers (r:1 w:1) + /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(237), added: 2712, mode: MaxEncodedLen) + /// Storage: NominationPools MaxPoolMembersPerPool (r:1 w:0) + /// Proof: NominationPools MaxPoolMembersPerPool (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: NominationPools MaxPoolMembers (r:1 w:0) + /// Proof: NominationPools MaxPoolMembers (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: NominationPools CounterForPoolMembers (r:1 w:1) + /// Proof: NominationPools CounterForPoolMembers (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:1 w:1) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:1 w:1) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking CurrentEra (r:1 w:0) + /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: NominationPools RewardPools (r:1 w:1) + /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(60), added: 2535, mode: MaxEncodedLen) + /// Storage: NominationPools CounterForRewardPools (r:1 w:1) + /// Proof: NominationPools CounterForRewardPools (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: NominationPools ReversePoolIdLookup (r:1 w:1) + /// Proof: NominationPools ReversePoolIdLookup (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) + /// Storage: NominationPools CounterForReversePoolIdLookup (r:1 w:1) + /// Proof: NominationPools CounterForReversePoolIdLookup (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: NominationPools BondedPools (r:1 w:1) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) + /// Storage: Staking Payee (r:0 w:1) + /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) fn create() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `1321` + // Estimated: `31522` + // Minimum execution time: 131_430 nanoseconds. + Weight::from_parts(132_214_000, 31522) + .saturating_add(T::DbWeight::get().reads(21_u64)) + .saturating_add(T::DbWeight::get().writes(15_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: 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) + /// Storage: NominationPools BondedPools (r:1 w:0) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:1 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:1 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking MinNominatorBond (r:1 w:0) + /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:1 w:1) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) + /// Storage: Staking MaxNominatorsCount (r:1 w:0) + /// Proof: Staking MaxNominatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking Validators (r:17 w:0) + /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) + /// Storage: Staking CurrentEra (r:1 w:0) + /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:1 w:1) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:1 w:1) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: VoterList CounterForListNodes (r:1 w:1) + /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking CounterForNominators (r:1 w:1) + /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `1909` + // Estimated: `21998 + n * (2520 ±0)` + // Minimum execution time: 61_798 nanoseconds. + Weight::from_parts(61_504_758, 21998) + // Standard Error: 4_046 + .saturating_add(Weight::from_ref_time(1_159_175).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(12_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes(5_u64)) + .saturating_add(Weight::from_proof_size(2520).saturating_mul(n.into())) } - // Storage: NominationPools BondedPools (r:1 w:1) - // Storage: Staking Bonded (r:1 w:0) - // Storage: Staking Ledger (r:1 w:0) + /// Storage: NominationPools BondedPools (r:1 w:1) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:1 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:1 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) fn set_state() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `1498` + // Estimated: `8752` + // Minimum execution time: 32_433 nanoseconds. + Weight::from_parts(32_894_000, 8752) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - // Storage: NominationPools BondedPools (r:1 w:0) - // Storage: NominationPools Metadata (r:1 w:1) - // Storage: NominationPools CounterForMetadata (r:1 w:1) + /// Storage: NominationPools BondedPools (r:1 w:0) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) + /// Storage: NominationPools Metadata (r:1 w:1) + /// Proof: NominationPools Metadata (max_values: None, max_size: Some(270), added: 2745, mode: MaxEncodedLen) + /// Storage: NominationPools CounterForMetadata (r:1 w:1) + /// Proof: NominationPools CounterForMetadata (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// The range of component `n` is `[1, 256]`. fn set_metadata(n: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `559` + // Estimated: `5883` + // Minimum execution time: 13_608 nanoseconds. + Weight::from_parts(13_966_346, 5883) + // Standard Error: 44 + .saturating_add(Weight::from_ref_time(1_511).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } - // Storage: NominationPools MinJoinBond (r:0 w:1) - // 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) + /// Storage: NominationPools MinJoinBond (r:0 w:1) + /// Proof: NominationPools MinJoinBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: NominationPools MaxPoolMembers (r:0 w:1) + /// Proof: NominationPools MaxPoolMembers (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: NominationPools MaxPoolMembersPerPool (r:0 w:1) + /// Proof: NominationPools MaxPoolMembersPerPool (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: NominationPools MinCreateBond (r:0 w:1) + /// Proof: NominationPools MinCreateBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: NominationPools MaxPools (r:0 w:1) + /// Proof: NominationPools MaxPools (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn set_configs() -> Weight { - // Minimum execution time: 9_231 nanoseconds. - Weight::from_ref_time(9_526_000 as u64) - .saturating_add(T::DbWeight::get().writes(5 as u64)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 5_832 nanoseconds. + Weight::from_ref_time(6_117_000) + .saturating_add(T::DbWeight::get().writes(5_u64)) } - // Storage: NominationPools BondedPools (r:1 w:1) + /// Storage: NominationPools BondedPools (r:1 w:1) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) fn update_roles() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `559` + // Estimated: `2639` + // Minimum execution time: 18_160 nanoseconds. + Weight::from_parts(18_567_000, 2639) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_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: VoterList ListNodes (r:1 w:1) - // Storage: VoterList ListBags (r:1 w:1) - // Storage: VoterList CounterForListNodes (r:1 w:1) + /// Storage: NominationPools BondedPools (r:1 w:0) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:1 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:1 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking Validators (r:1 w:0) + /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:1 w:1) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) + /// Storage: Staking CounterForNominators (r:1 w:1) + /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:1 w:1) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:1 w:1) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: VoterList CounterForListNodes (r:1 w:1) + /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn chill() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `2136` + // Estimated: `20489` + // Minimum execution time: 58_991 nanoseconds. + Weight::from_parts(59_528_000, 20489) + .saturating_add(T::DbWeight::get().reads(9_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) } } // For backwards compatibility and tests 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: Balances Locks (r:1 w:1) - // Storage: VoterList ListNodes (r:3 w:3) - // Storage: VoterList ListBags (r:2 w:2) + /// Storage: NominationPools MinJoinBond (r:1 w:0) + /// Proof: NominationPools MinJoinBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: NominationPools PoolMembers (r:1 w:1) + /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(237), added: 2712, mode: MaxEncodedLen) + /// Storage: NominationPools BondedPools (r:1 w:1) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:1 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:1 w:1) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: NominationPools RewardPools (r:1 w:1) + /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(60), added: 2535, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: NominationPools MaxPoolMembersPerPool (r:1 w:0) + /// Proof: NominationPools MaxPoolMembersPerPool (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: NominationPools MaxPoolMembers (r:1 w:0) + /// Proof: NominationPools MaxPoolMembers (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: NominationPools CounterForPoolMembers (r:1 w:1) + /// Proof: NominationPools CounterForPoolMembers (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:3 w:3) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:2 w:2) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) fn join() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `3573` + // Estimated: `37988` + // Minimum execution time: 140_155 nanoseconds. + Weight::from_parts(141_098_000, 37988) + .saturating_add(RocksDbWeight::get().reads(17_u64)) + .saturating_add(RocksDbWeight::get().writes(12_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:3 w:2) - // Storage: Staking Bonded (r:1 w:0) - // Storage: Staking Ledger (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) - // Storage: VoterList ListNodes (r:3 w:3) - // Storage: VoterList ListBags (r:2 w:2) + /// Storage: NominationPools PoolMembers (r:1 w:1) + /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(237), added: 2712, mode: MaxEncodedLen) + /// Storage: NominationPools BondedPools (r:1 w:1) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) + /// Storage: NominationPools RewardPools (r:1 w:1) + /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(60), added: 2535, mode: MaxEncodedLen) + /// Storage: System Account (r:3 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:1 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:1 w:1) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:3 w:3) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:2 w:2) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) fn bond_extra_transfer() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `3615` + // Estimated: `38583` + // Minimum execution time: 136_048 nanoseconds. + Weight::from_parts(136_767_000, 38583) + .saturating_add(RocksDbWeight::get().reads(14_u64)) + .saturating_add(RocksDbWeight::get().writes(12_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:3 w:3) - // Storage: Staking Bonded (r:1 w:0) - // Storage: Staking Ledger (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) - // Storage: VoterList ListNodes (r:3 w:3) - // Storage: VoterList ListBags (r:2 w:2) + /// Storage: NominationPools PoolMembers (r:1 w:1) + /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(237), added: 2712, mode: MaxEncodedLen) + /// Storage: NominationPools BondedPools (r:1 w:1) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) + /// Storage: NominationPools RewardPools (r:1 w:1) + /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(60), added: 2535, mode: MaxEncodedLen) + /// Storage: System Account (r:3 w:3) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:1 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:1 w:1) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:3 w:3) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:2 w:2) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) fn bond_extra_reward() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `3615` + // Estimated: `38583` + // Minimum execution time: 151_473 nanoseconds. + Weight::from_parts(152_375_000, 38583) + .saturating_add(RocksDbWeight::get().reads(14_u64)) + .saturating_add(RocksDbWeight::get().writes(13_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) + /// Storage: NominationPools PoolMembers (r:1 w:1) + /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(237), added: 2712, mode: MaxEncodedLen) + /// Storage: NominationPools BondedPools (r:1 w:1) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) + /// Storage: NominationPools RewardPools (r:1 w:1) + /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(60), added: 2535, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn claim_payout() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `1189` + // Estimated: `10489` + // Minimum execution time: 51_146 nanoseconds. + Weight::from_parts(51_570_000, 10489) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(4_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 Nominators (r:1 w:0) - // Storage: Staking MinNominatorBond (r:1 w:0) - // Storage: Balances Locks (r:1 w:1) - // 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) + /// Storage: NominationPools PoolMembers (r:1 w:1) + /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(237), added: 2712, mode: MaxEncodedLen) + /// Storage: NominationPools BondedPools (r:1 w:1) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) + /// Storage: NominationPools RewardPools (r:1 w:1) + /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(60), added: 2535, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:1 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:1 w:1) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Staking CurrentEra (r:1 w:0) + /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:1 w:0) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) + /// Storage: Staking MinNominatorBond (r:1 w:0) + /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:3 w:3) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:2 w:2) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: NominationPools SubPoolsStorage (r:1 w:1) + /// Proof: NominationPools SubPoolsStorage (max_values: None, max_size: Some(24382), added: 26857, mode: MaxEncodedLen) + /// Storage: NominationPools CounterForSubPoolsStorage (r:1 w:1) + /// Proof: NominationPools CounterForSubPoolsStorage (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn unbond() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `3858` + // Estimated: `67379` + // Minimum execution time: 141_400 nanoseconds. + Weight::from_parts(141_822_000, 67379) + .saturating_add(RocksDbWeight::get().reads(18_u64)) + .saturating_add(RocksDbWeight::get().writes(13_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) + /// Storage: NominationPools BondedPools (r:1 w:0) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:1 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:1 w:1) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking CurrentEra (r:1 w:0) + /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) /// The range of component `s` is `[0, 100]`. fn pool_withdraw_unbonded(s: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `1779` + // Estimated: `13025` + // Minimum execution time: 49_021 nanoseconds. + Weight::from_parts(49_954_282, 13025) + // Standard Error: 378 + .saturating_add(Weight::from_ref_time(5_165).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(2_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) + /// Storage: NominationPools PoolMembers (r:1 w:1) + /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(237), added: 2712, mode: MaxEncodedLen) + /// Storage: Staking CurrentEra (r:1 w:0) + /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: NominationPools BondedPools (r:1 w:1) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) + /// Storage: NominationPools SubPoolsStorage (r:1 w:1) + /// Proof: NominationPools SubPoolsStorage (max_values: None, max_size: Some(24382), added: 26857, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:1 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:1 w:1) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: NominationPools CounterForPoolMembers (r:1 w:1) + /// Proof: NominationPools CounterForPoolMembers (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `2303` + // Estimated: `45696` + // Minimum execution time: 92_473 nanoseconds. + Weight::from_parts(93_901_972, 45696) + // Standard Error: 618 + .saturating_add(Weight::from_ref_time(12_032).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(9_u64)) + .saturating_add(RocksDbWeight::get().writes(7_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: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) - // 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 Metadata (r:1 w:1) - // Storage: NominationPools CounterForBondedPools (r:1 w:1) - // Storage: Staking Payee (r:0 w:1) + /// Storage: NominationPools PoolMembers (r:1 w:1) + /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(237), added: 2712, mode: MaxEncodedLen) + /// Storage: Staking CurrentEra (r:1 w:0) + /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: NominationPools BondedPools (r:1 w:1) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) + /// Storage: NominationPools SubPoolsStorage (r:1 w:1) + /// Proof: NominationPools SubPoolsStorage (max_values: None, max_size: Some(24382), added: 26857, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:1 w:1) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:1 w:1) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking SlashingSpans (r:1 w:0) + /// Proof Skipped: Staking SlashingSpans (max_values: None, max_size: None, mode: Measured) + /// Storage: Staking Validators (r:1 w:0) + /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:1 w:0) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: NominationPools CounterForPoolMembers (r:1 w:1) + /// Proof: NominationPools CounterForPoolMembers (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: NominationPools ReversePoolIdLookup (r:1 w:1) + /// Proof: NominationPools ReversePoolIdLookup (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) + /// Storage: NominationPools CounterForReversePoolIdLookup (r:1 w:1) + /// Proof: NominationPools CounterForReversePoolIdLookup (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: NominationPools RewardPools (r:1 w:1) + /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(60), added: 2535, mode: MaxEncodedLen) + /// Storage: NominationPools CounterForRewardPools (r:1 w:1) + /// Proof: NominationPools CounterForRewardPools (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: NominationPools CounterForSubPoolsStorage (r:1 w:1) + /// Proof: NominationPools CounterForSubPoolsStorage (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: NominationPools Metadata (r:1 w:1) + /// Proof: NominationPools Metadata (max_values: None, max_size: Some(270), added: 2745, mode: MaxEncodedLen) + /// Storage: NominationPools CounterForBondedPools (r:1 w:1) + /// Proof: NominationPools CounterForBondedPools (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking Payee (r:0 w:1) + /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) /// The range of component `s` is `[0, 100]`. - 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)) + fn withdraw_unbonded_kill(_s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `2690` + // Estimated: `68812` + // Minimum execution time: 150_063 nanoseconds. + Weight::from_parts(152_321_387, 68812) + .saturating_add(RocksDbWeight::get().reads(20_u64)) + .saturating_add(RocksDbWeight::get().writes(17_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 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 Bonded (r:1 w:1) - // Storage: Staking Ledger (r:1 w:1) - // Storage: Staking CurrentEra (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) + /// Storage: NominationPools LastPoolId (r:1 w:1) + /// Proof: NominationPools LastPoolId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking MinNominatorBond (r:1 w:0) + /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: NominationPools MinCreateBond (r:1 w:0) + /// Proof: NominationPools MinCreateBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: NominationPools MinJoinBond (r:1 w:0) + /// Proof: NominationPools MinJoinBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: NominationPools MaxPools (r:1 w:0) + /// Proof: NominationPools MaxPools (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: NominationPools CounterForBondedPools (r:1 w:1) + /// Proof: NominationPools CounterForBondedPools (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: NominationPools PoolMembers (r:1 w:1) + /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(237), added: 2712, mode: MaxEncodedLen) + /// Storage: NominationPools MaxPoolMembersPerPool (r:1 w:0) + /// Proof: NominationPools MaxPoolMembersPerPool (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: NominationPools MaxPoolMembers (r:1 w:0) + /// Proof: NominationPools MaxPoolMembers (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: NominationPools CounterForPoolMembers (r:1 w:1) + /// Proof: NominationPools CounterForPoolMembers (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:1 w:1) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:1 w:1) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking CurrentEra (r:1 w:0) + /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: NominationPools RewardPools (r:1 w:1) + /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(60), added: 2535, mode: MaxEncodedLen) + /// Storage: NominationPools CounterForRewardPools (r:1 w:1) + /// Proof: NominationPools CounterForRewardPools (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: NominationPools ReversePoolIdLookup (r:1 w:1) + /// Proof: NominationPools ReversePoolIdLookup (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) + /// Storage: NominationPools CounterForReversePoolIdLookup (r:1 w:1) + /// Proof: NominationPools CounterForReversePoolIdLookup (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: NominationPools BondedPools (r:1 w:1) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) + /// Storage: Staking Payee (r:0 w:1) + /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) fn create() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `1321` + // Estimated: `31522` + // Minimum execution time: 131_430 nanoseconds. + Weight::from_parts(132_214_000, 31522) + .saturating_add(RocksDbWeight::get().reads(21_u64)) + .saturating_add(RocksDbWeight::get().writes(15_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: 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) + /// Storage: NominationPools BondedPools (r:1 w:0) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:1 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:1 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking MinNominatorBond (r:1 w:0) + /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:1 w:1) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) + /// Storage: Staking MaxNominatorsCount (r:1 w:0) + /// Proof: Staking MaxNominatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking Validators (r:17 w:0) + /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) + /// Storage: Staking CurrentEra (r:1 w:0) + /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:1 w:1) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:1 w:1) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: VoterList CounterForListNodes (r:1 w:1) + /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking CounterForNominators (r:1 w:1) + /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `1909` + // Estimated: `21998 + n * (2520 ±0)` + // Minimum execution time: 61_798 nanoseconds. + Weight::from_parts(61_504_758, 21998) + // Standard Error: 4_046 + .saturating_add(Weight::from_ref_time(1_159_175).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(12_u64)) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) + .saturating_add(RocksDbWeight::get().writes(5_u64)) + .saturating_add(Weight::from_proof_size(2520).saturating_mul(n.into())) } - // Storage: NominationPools BondedPools (r:1 w:1) - // Storage: Staking Bonded (r:1 w:0) - // Storage: Staking Ledger (r:1 w:0) + /// Storage: NominationPools BondedPools (r:1 w:1) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:1 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:1 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) fn set_state() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `1498` + // Estimated: `8752` + // Minimum execution time: 32_433 nanoseconds. + Weight::from_parts(32_894_000, 8752) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - // Storage: NominationPools BondedPools (r:1 w:0) - // Storage: NominationPools Metadata (r:1 w:1) - // Storage: NominationPools CounterForMetadata (r:1 w:1) + /// Storage: NominationPools BondedPools (r:1 w:0) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) + /// Storage: NominationPools Metadata (r:1 w:1) + /// Proof: NominationPools Metadata (max_values: None, max_size: Some(270), added: 2745, mode: MaxEncodedLen) + /// Storage: NominationPools CounterForMetadata (r:1 w:1) + /// Proof: NominationPools CounterForMetadata (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// The range of component `n` is `[1, 256]`. fn set_metadata(n: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `559` + // Estimated: `5883` + // Minimum execution time: 13_608 nanoseconds. + Weight::from_parts(13_966_346, 5883) + // Standard Error: 44 + .saturating_add(Weight::from_ref_time(1_511).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } - // Storage: NominationPools MinJoinBond (r:0 w:1) - // 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) + /// Storage: NominationPools MinJoinBond (r:0 w:1) + /// Proof: NominationPools MinJoinBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: NominationPools MaxPoolMembers (r:0 w:1) + /// Proof: NominationPools MaxPoolMembers (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: NominationPools MaxPoolMembersPerPool (r:0 w:1) + /// Proof: NominationPools MaxPoolMembersPerPool (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: NominationPools MinCreateBond (r:0 w:1) + /// Proof: NominationPools MinCreateBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: NominationPools MaxPools (r:0 w:1) + /// Proof: NominationPools MaxPools (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn set_configs() -> Weight { - // Minimum execution time: 9_231 nanoseconds. - Weight::from_ref_time(9_526_000 as u64) - .saturating_add(RocksDbWeight::get().writes(5 as u64)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 5_832 nanoseconds. + Weight::from_ref_time(6_117_000) + .saturating_add(RocksDbWeight::get().writes(5_u64)) } - // Storage: NominationPools BondedPools (r:1 w:1) + /// Storage: NominationPools BondedPools (r:1 w:1) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) fn update_roles() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `559` + // Estimated: `2639` + // Minimum execution time: 18_160 nanoseconds. + Weight::from_parts(18_567_000, 2639) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_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: VoterList ListNodes (r:1 w:1) - // Storage: VoterList ListBags (r:1 w:1) - // Storage: VoterList CounterForListNodes (r:1 w:1) + /// Storage: NominationPools BondedPools (r:1 w:0) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:1 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:1 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking Validators (r:1 w:0) + /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:1 w:1) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) + /// Storage: Staking CounterForNominators (r:1 w:1) + /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:1 w:1) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:1 w:1) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: VoterList CounterForListNodes (r:1 w:1) + /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn chill() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `2136` + // Estimated: `20489` + // Minimum execution time: 58_991 nanoseconds. + Weight::from_parts(59_528_000, 20489) + .saturating_add(RocksDbWeight::get().reads(9_u64)) + .saturating_add(RocksDbWeight::get().writes(5_u64)) } } diff --git a/frame/preimage/src/weights.rs b/frame/preimage/src/weights.rs index e73c986891ccd..394c76956db87 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) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2023 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,7 +18,8 @@ //! Autogenerated weights for pallet_preimage //! //! 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: `[]` +//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -64,206 +65,314 @@ pub trait WeightInfo { /// Weights for pallet_preimage using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - // Storage: Preimage StatusFor (r:1 w:1) - // Storage: Preimage PreimageFor (r:0 w:1) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Preimage PreimageFor (r:0 w:1) + /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) /// The range of component `s` is `[0, 4194304]`. fn note_preimage(s: u32, ) -> Weight { - // Minimum execution time: 33_810 nanoseconds. - Weight::from_ref_time(34_299_000 as u64) + // Proof Size summary in bytes: + // Measured: `175` + // Estimated: `2566` + // Minimum execution time: 23_484 nanoseconds. + Weight::from_parts(23_828_000, 2566) // Standard Error: 0 - .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)) + .saturating_add(Weight::from_ref_time(1_705).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } - // Storage: Preimage StatusFor (r:1 w:1) - // Storage: Preimage PreimageFor (r:0 w:1) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Preimage PreimageFor (r:0 w:1) + /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) /// The range of component `s` is `[0, 4194304]`. fn note_requested_preimage(s: u32, ) -> Weight { - // Minimum execution time: 24_398 nanoseconds. - Weight::from_ref_time(24_839_000 as u64) + // Proof Size summary in bytes: + // Measured: `106` + // Estimated: `2566` + // Minimum execution time: 14_812 nanoseconds. + Weight::from_parts(14_949_000, 2566) // Standard Error: 0 - .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)) + .saturating_add(Weight::from_ref_time(1_707).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } - // Storage: Preimage StatusFor (r:1 w:1) - // Storage: Preimage PreimageFor (r:0 w:1) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Preimage PreimageFor (r:0 w:1) + /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) /// The range of component `s` is `[0, 4194304]`. fn note_no_deposit_preimage(s: u32, ) -> Weight { - // Minimum execution time: 22_235 nanoseconds. - Weight::from_ref_time(22_473_000 as u64) + // Proof Size summary in bytes: + // Measured: `106` + // Estimated: `2566` + // Minimum execution time: 14_185 nanoseconds. + Weight::from_parts(14_398_000, 2566) // Standard Error: 0 - .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)) + .saturating_add(Weight::from_ref_time(1_709).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } - // Storage: Preimage StatusFor (r:1 w:1) - // Storage: Preimage PreimageFor (r:0 w:1) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Preimage PreimageFor (r:0 w:1) + /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) fn unnote_preimage() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `353` + // Estimated: `2566` + // Minimum execution time: 29_917 nanoseconds. + Weight::from_parts(30_691_000, 2566) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } - // Storage: Preimage StatusFor (r:1 w:1) - // Storage: Preimage PreimageFor (r:0 w:1) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Preimage PreimageFor (r:0 w:1) + /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) fn unnote_no_deposit_preimage() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `144` + // Estimated: `2566` + // Minimum execution time: 19_281 nanoseconds. + Weight::from_parts(20_121_000, 2566) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } - // Storage: Preimage StatusFor (r:1 w:1) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) fn request_preimage() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `220` + // Estimated: `2566` + // Minimum execution time: 17_192 nanoseconds. + Weight::from_parts(18_637_000, 2566) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - // Storage: Preimage StatusFor (r:1 w:1) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) fn request_no_deposit_preimage() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `144` + // Estimated: `2566` + // Minimum execution time: 10_139 nanoseconds. + Weight::from_parts(10_773_000, 2566) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - // Storage: Preimage StatusFor (r:1 w:1) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) fn request_unnoted_preimage() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `42` + // Estimated: `2566` + // Minimum execution time: 11_721 nanoseconds. + Weight::from_parts(12_313_000, 2566) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - // Storage: Preimage StatusFor (r:1 w:1) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) fn request_requested_preimage() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `106` + // Estimated: `2566` + // Minimum execution time: 7_263 nanoseconds. + Weight::from_parts(7_547_000, 2566) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - // Storage: Preimage StatusFor (r:1 w:1) - // Storage: Preimage PreimageFor (r:0 w:1) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Preimage PreimageFor (r:0 w:1) + /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) fn unrequest_preimage() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `144` + // Estimated: `2566` + // Minimum execution time: 17_785 nanoseconds. + Weight::from_parts(18_501_000, 2566) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } - // Storage: Preimage StatusFor (r:1 w:1) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) fn unrequest_unnoted_preimage() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `106` + // Estimated: `2566` + // Minimum execution time: 7_090 nanoseconds. + Weight::from_parts(7_319_000, 2566) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - // Storage: Preimage StatusFor (r:1 w:1) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) fn unrequest_multi_referenced_preimage() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `106` + // Estimated: `2566` + // Minimum execution time: 7_253 nanoseconds. + Weight::from_parts(7_508_000, 2566) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } } // For backwards compatibility and tests impl WeightInfo for () { - // Storage: Preimage StatusFor (r:1 w:1) - // Storage: Preimage PreimageFor (r:0 w:1) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Preimage PreimageFor (r:0 w:1) + /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) /// The range of component `s` is `[0, 4194304]`. fn note_preimage(s: u32, ) -> Weight { - // Minimum execution time: 33_810 nanoseconds. - Weight::from_ref_time(34_299_000 as u64) + // Proof Size summary in bytes: + // Measured: `175` + // Estimated: `2566` + // Minimum execution time: 23_484 nanoseconds. + Weight::from_parts(23_828_000, 2566) // Standard Error: 0 - .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)) + .saturating_add(Weight::from_ref_time(1_705).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } - // Storage: Preimage StatusFor (r:1 w:1) - // Storage: Preimage PreimageFor (r:0 w:1) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Preimage PreimageFor (r:0 w:1) + /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) /// The range of component `s` is `[0, 4194304]`. fn note_requested_preimage(s: u32, ) -> Weight { - // Minimum execution time: 24_398 nanoseconds. - Weight::from_ref_time(24_839_000 as u64) + // Proof Size summary in bytes: + // Measured: `106` + // Estimated: `2566` + // Minimum execution time: 14_812 nanoseconds. + Weight::from_parts(14_949_000, 2566) // Standard Error: 0 - .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)) + .saturating_add(Weight::from_ref_time(1_707).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } - // Storage: Preimage StatusFor (r:1 w:1) - // Storage: Preimage PreimageFor (r:0 w:1) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Preimage PreimageFor (r:0 w:1) + /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) /// The range of component `s` is `[0, 4194304]`. fn note_no_deposit_preimage(s: u32, ) -> Weight { - // Minimum execution time: 22_235 nanoseconds. - Weight::from_ref_time(22_473_000 as u64) + // Proof Size summary in bytes: + // Measured: `106` + // Estimated: `2566` + // Minimum execution time: 14_185 nanoseconds. + Weight::from_parts(14_398_000, 2566) // Standard Error: 0 - .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)) + .saturating_add(Weight::from_ref_time(1_709).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } - // Storage: Preimage StatusFor (r:1 w:1) - // Storage: Preimage PreimageFor (r:0 w:1) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Preimage PreimageFor (r:0 w:1) + /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) fn unnote_preimage() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `353` + // Estimated: `2566` + // Minimum execution time: 29_917 nanoseconds. + Weight::from_parts(30_691_000, 2566) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } - // Storage: Preimage StatusFor (r:1 w:1) - // Storage: Preimage PreimageFor (r:0 w:1) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Preimage PreimageFor (r:0 w:1) + /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) fn unnote_no_deposit_preimage() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `144` + // Estimated: `2566` + // Minimum execution time: 19_281 nanoseconds. + Weight::from_parts(20_121_000, 2566) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } - // Storage: Preimage StatusFor (r:1 w:1) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) fn request_preimage() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `220` + // Estimated: `2566` + // Minimum execution time: 17_192 nanoseconds. + Weight::from_parts(18_637_000, 2566) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - // Storage: Preimage StatusFor (r:1 w:1) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) fn request_no_deposit_preimage() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `144` + // Estimated: `2566` + // Minimum execution time: 10_139 nanoseconds. + Weight::from_parts(10_773_000, 2566) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - // Storage: Preimage StatusFor (r:1 w:1) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) fn request_unnoted_preimage() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `42` + // Estimated: `2566` + // Minimum execution time: 11_721 nanoseconds. + Weight::from_parts(12_313_000, 2566) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - // Storage: Preimage StatusFor (r:1 w:1) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) fn request_requested_preimage() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `106` + // Estimated: `2566` + // Minimum execution time: 7_263 nanoseconds. + Weight::from_parts(7_547_000, 2566) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - // Storage: Preimage StatusFor (r:1 w:1) - // Storage: Preimage PreimageFor (r:0 w:1) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Preimage PreimageFor (r:0 w:1) + /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) fn unrequest_preimage() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `144` + // Estimated: `2566` + // Minimum execution time: 17_785 nanoseconds. + Weight::from_parts(18_501_000, 2566) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } - // Storage: Preimage StatusFor (r:1 w:1) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) fn unrequest_unnoted_preimage() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `106` + // Estimated: `2566` + // Minimum execution time: 7_090 nanoseconds. + Weight::from_parts(7_319_000, 2566) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - // Storage: Preimage StatusFor (r:1 w:1) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) fn unrequest_multi_referenced_preimage() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `106` + // Estimated: `2566` + // Minimum execution time: 7_253 nanoseconds. + Weight::from_parts(7_508_000, 2566) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } } diff --git a/frame/proxy/src/weights.rs b/frame/proxy/src/weights.rs index 706810d3402ec..53e368acae3f7 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) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2023 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -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-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -62,244 +63,334 @@ pub trait WeightInfo { /// Weights for pallet_proxy using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - // Storage: Proxy Proxies (r:1 w:0) + /// Storage: Proxy Proxies (r:1 w:0) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) /// The range of component `p` is `[1, 31]`. fn proxy(p: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `193 + p * (37 ±0)` + // Estimated: `3716` + // Minimum execution time: 14_461 nanoseconds. + Weight::from_parts(14_913_927, 3716) + // Standard Error: 1_174 + .saturating_add(Weight::from_ref_time(36_087).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) } - // Storage: Proxy Proxies (r:1 w:0) - // Storage: Proxy Announcements (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: Proxy Proxies (r:1 w:0) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) + /// Storage: Proxy Announcements (r:1 w:1) + /// Proof: Proxy Announcements (max_values: None, max_size: Some(2233), added: 4708, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `a` is `[0, 31]`. /// The range of component `p` is `[1, 31]`. fn proxy_announced(a: u32, p: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `584 + a * (68 ±0) + p * (37 ±0)` + // Estimated: `11027` + // Minimum execution time: 31_523 nanoseconds. + Weight::from_parts(31_116_270, 11027) + // Standard Error: 1_789 + .saturating_add(Weight::from_ref_time(135_656).saturating_mul(a.into())) + // Standard Error: 1_849 + .saturating_add(Weight::from_ref_time(53_893).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } - // Storage: Proxy Announcements (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: Proxy Announcements (r:1 w:1) + /// Proof: Proxy Announcements (max_values: None, max_size: Some(2233), added: 4708, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `a` is `[0, 31]`. /// The range of component `p` is `[1, 31]`. fn remove_announcement(a: u32, p: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `467 + a * (68 ±0)` + // Estimated: `7311` + // Minimum execution time: 19_363 nanoseconds. + Weight::from_parts(20_282_191, 7311) + // Standard Error: 1_084 + .saturating_add(Weight::from_ref_time(133_825).saturating_mul(a.into())) + // Standard Error: 1_120 + .saturating_add(Weight::from_ref_time(3_434).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } - // Storage: Proxy Announcements (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: Proxy Announcements (r:1 w:1) + /// Proof: Proxy Announcements (max_values: None, max_size: Some(2233), added: 4708, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `a` is `[0, 31]`. /// The range of component `p` is `[1, 31]`. fn reject_announcement(a: u32, p: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `467 + a * (68 ±0)` + // Estimated: `7311` + // Minimum execution time: 19_363 nanoseconds. + Weight::from_parts(20_211_584, 7311) + // Standard Error: 1_171 + .saturating_add(Weight::from_ref_time(136_984).saturating_mul(a.into())) + // Standard Error: 1_210 + .saturating_add(Weight::from_ref_time(3_686).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } - // Storage: Proxy Proxies (r:1 w:0) - // Storage: Proxy Announcements (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: Proxy Proxies (r:1 w:0) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) + /// Storage: Proxy Announcements (r:1 w:1) + /// Proof: Proxy Announcements (max_values: None, max_size: Some(2233), added: 4708, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `a` is `[0, 31]`. /// The range of component `p` is `[1, 31]`. fn announce(a: u32, p: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `516 + a * (68 ±0) + p * (37 ±0)` + // Estimated: `11027` + // Minimum execution time: 27_811 nanoseconds. + Weight::from_parts(27_965_813, 11027) + // Standard Error: 1_987 + .saturating_add(Weight::from_ref_time(124_133).saturating_mul(a.into())) + // Standard Error: 2_053 + .saturating_add(Weight::from_ref_time(54_692).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } - // Storage: Proxy Proxies (r:1 w:1) + /// Storage: Proxy Proxies (r:1 w:1) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) /// The range of component `p` is `[1, 31]`. fn add_proxy(p: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `193 + p * (37 ±0)` + // Estimated: `3716` + // Minimum execution time: 20_922 nanoseconds. + Weight::from_parts(21_551_797, 3716) + // Standard Error: 1_425 + .saturating_add(Weight::from_ref_time(58_434).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - // Storage: Proxy Proxies (r:1 w:1) + /// Storage: Proxy Proxies (r:1 w:1) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) /// The range of component `p` is `[1, 31]`. fn remove_proxy(p: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `193 + p * (37 ±0)` + // Estimated: `3716` + // Minimum execution time: 20_812 nanoseconds. + Weight::from_parts(21_660_732, 3716) + // Standard Error: 1_438 + .saturating_add(Weight::from_ref_time(68_740).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - // Storage: Proxy Proxies (r:1 w:1) + /// Storage: Proxy Proxies (r:1 w:1) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) /// The range of component `p` is `[1, 31]`. fn remove_proxies(p: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `193 + p * (37 ±0)` + // Estimated: `3716` + // Minimum execution time: 16_786 nanoseconds. + Weight::from_parts(17_249_958, 3716) + // Standard Error: 1_007 + .saturating_add(Weight::from_ref_time(37_546).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) - // Storage: Proxy Proxies (r:1 w:1) + /// Storage: Proxy Proxies (r:1 w:1) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) /// The range of component `p` is `[1, 31]`. fn create_pure(p: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `173` + // Estimated: `3716` + // Minimum execution time: 22_764 nanoseconds. + Weight::from_parts(23_539_039, 3716) + // Standard Error: 814 + .saturating_add(Weight::from_ref_time(144).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - // Storage: Proxy Proxies (r:1 w:1) + /// Storage: Proxy Proxies (r:1 w:1) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) /// The range of component `p` is `[0, 30]`. fn kill_pure(p: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `230 + p * (37 ±0)` + // Estimated: `3716` + // Minimum execution time: 17_720 nanoseconds. + Weight::from_parts(18_428_849, 3716) + // Standard Error: 1_093 + .saturating_add(Weight::from_ref_time(34_600).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } } // For backwards compatibility and tests impl WeightInfo for () { - // Storage: Proxy Proxies (r:1 w:0) + /// Storage: Proxy Proxies (r:1 w:0) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) /// The range of component `p` is `[1, 31]`. fn proxy(p: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `193 + p * (37 ±0)` + // Estimated: `3716` + // Minimum execution time: 14_461 nanoseconds. + Weight::from_parts(14_913_927, 3716) + // Standard Error: 1_174 + .saturating_add(Weight::from_ref_time(36_087).saturating_mul(p.into())) + .saturating_add(RocksDbWeight::get().reads(1_u64)) } - // Storage: Proxy Proxies (r:1 w:0) - // Storage: Proxy Announcements (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: Proxy Proxies (r:1 w:0) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) + /// Storage: Proxy Announcements (r:1 w:1) + /// Proof: Proxy Announcements (max_values: None, max_size: Some(2233), added: 4708, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `a` is `[0, 31]`. /// The range of component `p` is `[1, 31]`. fn proxy_announced(a: u32, p: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `584 + a * (68 ±0) + p * (37 ±0)` + // Estimated: `11027` + // Minimum execution time: 31_523 nanoseconds. + Weight::from_parts(31_116_270, 11027) + // Standard Error: 1_789 + .saturating_add(Weight::from_ref_time(135_656).saturating_mul(a.into())) + // Standard Error: 1_849 + .saturating_add(Weight::from_ref_time(53_893).saturating_mul(p.into())) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } - // Storage: Proxy Announcements (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: Proxy Announcements (r:1 w:1) + /// Proof: Proxy Announcements (max_values: None, max_size: Some(2233), added: 4708, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `a` is `[0, 31]`. /// The range of component `p` is `[1, 31]`. fn remove_announcement(a: u32, p: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `467 + a * (68 ±0)` + // Estimated: `7311` + // Minimum execution time: 19_363 nanoseconds. + Weight::from_parts(20_282_191, 7311) + // Standard Error: 1_084 + .saturating_add(Weight::from_ref_time(133_825).saturating_mul(a.into())) + // Standard Error: 1_120 + .saturating_add(Weight::from_ref_time(3_434).saturating_mul(p.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } - // Storage: Proxy Announcements (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: Proxy Announcements (r:1 w:1) + /// Proof: Proxy Announcements (max_values: None, max_size: Some(2233), added: 4708, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `a` is `[0, 31]`. /// The range of component `p` is `[1, 31]`. fn reject_announcement(a: u32, p: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `467 + a * (68 ±0)` + // Estimated: `7311` + // Minimum execution time: 19_363 nanoseconds. + Weight::from_parts(20_211_584, 7311) + // Standard Error: 1_171 + .saturating_add(Weight::from_ref_time(136_984).saturating_mul(a.into())) + // Standard Error: 1_210 + .saturating_add(Weight::from_ref_time(3_686).saturating_mul(p.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } - // Storage: Proxy Proxies (r:1 w:0) - // Storage: Proxy Announcements (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: Proxy Proxies (r:1 w:0) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) + /// Storage: Proxy Announcements (r:1 w:1) + /// Proof: Proxy Announcements (max_values: None, max_size: Some(2233), added: 4708, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `a` is `[0, 31]`. /// The range of component `p` is `[1, 31]`. fn announce(a: u32, p: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `516 + a * (68 ±0) + p * (37 ±0)` + // Estimated: `11027` + // Minimum execution time: 27_811 nanoseconds. + Weight::from_parts(27_965_813, 11027) + // Standard Error: 1_987 + .saturating_add(Weight::from_ref_time(124_133).saturating_mul(a.into())) + // Standard Error: 2_053 + .saturating_add(Weight::from_ref_time(54_692).saturating_mul(p.into())) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } - // Storage: Proxy Proxies (r:1 w:1) + /// Storage: Proxy Proxies (r:1 w:1) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) /// The range of component `p` is `[1, 31]`. fn add_proxy(p: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `193 + p * (37 ±0)` + // Estimated: `3716` + // Minimum execution time: 20_922 nanoseconds. + Weight::from_parts(21_551_797, 3716) + // Standard Error: 1_425 + .saturating_add(Weight::from_ref_time(58_434).saturating_mul(p.into())) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - // Storage: Proxy Proxies (r:1 w:1) + /// Storage: Proxy Proxies (r:1 w:1) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) /// The range of component `p` is `[1, 31]`. fn remove_proxy(p: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `193 + p * (37 ±0)` + // Estimated: `3716` + // Minimum execution time: 20_812 nanoseconds. + Weight::from_parts(21_660_732, 3716) + // Standard Error: 1_438 + .saturating_add(Weight::from_ref_time(68_740).saturating_mul(p.into())) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - // Storage: Proxy Proxies (r:1 w:1) + /// Storage: Proxy Proxies (r:1 w:1) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) /// The range of component `p` is `[1, 31]`. fn remove_proxies(p: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `193 + p * (37 ±0)` + // Estimated: `3716` + // Minimum execution time: 16_786 nanoseconds. + Weight::from_parts(17_249_958, 3716) + // Standard Error: 1_007 + .saturating_add(Weight::from_ref_time(37_546).saturating_mul(p.into())) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) - // Storage: Proxy Proxies (r:1 w:1) + /// Storage: Proxy Proxies (r:1 w:1) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) /// The range of component `p` is `[1, 31]`. fn create_pure(p: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `173` + // Estimated: `3716` + // Minimum execution time: 22_764 nanoseconds. + Weight::from_parts(23_539_039, 3716) + // Standard Error: 814 + .saturating_add(Weight::from_ref_time(144).saturating_mul(p.into())) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - // Storage: Proxy Proxies (r:1 w:1) + /// Storage: Proxy Proxies (r:1 w:1) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) /// The range of component `p` is `[0, 30]`. fn kill_pure(p: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `230 + p * (37 ±0)` + // Estimated: `3716` + // Minimum execution time: 17_720 nanoseconds. + Weight::from_parts(18_428_849, 3716) + // Standard Error: 1_093 + .saturating_add(Weight::from_ref_time(34_600).saturating_mul(p.into())) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } } diff --git a/frame/ranked-collective/src/weights.rs b/frame/ranked-collective/src/weights.rs index c054d200452e8..2d5ed3afdb1e2 100644 --- a/frame/ranked-collective/src/weights.rs +++ b/frame/ranked-collective/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2023 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,7 +18,8 @@ //! Autogenerated weights for pallet_ranked_collective //! //! 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: `[]` +//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -58,154 +59,238 @@ pub trait WeightInfo { /// 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) + /// Storage: RankedCollective Members (r:1 w:1) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: RankedCollective MemberCount (r:1 w:1) + /// Proof: RankedCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: RankedCollective IndexToId (r:0 w:1) + /// Proof: RankedCollective IndexToId (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) + /// Storage: RankedCollective IdToIndex (r:0 w:1) + /// Proof: RankedCollective IdToIndex (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) fn add_member() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `109` + // Estimated: `5006` + // Minimum execution time: 16_334 nanoseconds. + Weight::from_parts(16_784_000, 5006) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(4_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) + /// Storage: RankedCollective Members (r:1 w:1) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: RankedCollective MemberCount (r:11 w:11) + /// Proof: RankedCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: RankedCollective IdToIndex (r:11 w:11) + /// Proof: RankedCollective IdToIndex (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) + /// Storage: RankedCollective IndexToId (r:11 w:11) + /// Proof: RankedCollective IndexToId (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) /// The range of component `r` is `[0, 10]`. fn remove_member(r: u32, ) -> Weight { - // 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)) - .saturating_add(T::DbWeight::get().writes((3 as u64).saturating_mul(r as u64))) + // Proof Size summary in bytes: + // Measured: `583 + r * (281 ±0)` + // Estimated: `10064 + r * (7547 ±0)` + // Minimum execution time: 26_177 nanoseconds. + Weight::from_parts(29_245_248, 10064) + // Standard Error: 18_611 + .saturating_add(Weight::from_ref_time(10_916_516).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(r.into()))) + .saturating_add(T::DbWeight::get().writes(4_u64)) + .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_proof_size(7547).saturating_mul(r.into())) } - // 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) + /// Storage: RankedCollective Members (r:1 w:1) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: RankedCollective MemberCount (r:1 w:1) + /// Proof: RankedCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: RankedCollective IndexToId (r:0 w:1) + /// Proof: RankedCollective IndexToId (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) + /// Storage: RankedCollective IdToIndex (r:0 w:1) + /// Proof: RankedCollective IdToIndex (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) /// The range of component `r` is `[0, 10]`. fn promote_member(r: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `281 + r * (17 ±0)` + // Estimated: `5006` + // Minimum execution time: 18_953 nanoseconds. + Weight::from_parts(19_570_567, 5006) + // Standard Error: 4_156 + .saturating_add(Weight::from_ref_time(263_843).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(4_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) + /// Storage: RankedCollective Members (r:1 w:1) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: RankedCollective MemberCount (r:1 w:1) + /// Proof: RankedCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: RankedCollective IdToIndex (r:1 w:1) + /// Proof: RankedCollective IdToIndex (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) + /// Storage: RankedCollective IndexToId (r:1 w:1) + /// Proof: RankedCollective IndexToId (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) /// The range of component `r` is `[0, 10]`. fn demote_member(r: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `599 + r * (72 ±0)` + // Estimated: `10064` + // Minimum execution time: 26_243 nanoseconds. + Weight::from_parts(28_532_816, 10064) + // Standard Error: 22_689 + .saturating_add(Weight::from_ref_time(614_464).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(4_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) + /// Storage: RankedCollective Members (r:1 w:0) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: RankedPolls ReferendumInfoFor (r:1 w:1) + /// Proof: RankedPolls ReferendumInfoFor (max_values: None, max_size: Some(330), added: 2805, mode: MaxEncodedLen) + /// Storage: RankedCollective Voting (r:1 w:1) + /// Proof: RankedCollective Voting (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:2 w:2) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn vote() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `626` + // Estimated: `226856` + // Minimum execution time: 41_121 nanoseconds. + Weight::from_parts(41_606_000, 226856) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) } - // Storage: RankedPolls ReferendumInfoFor (r:1 w:0) - // Storage: RankedCollective VotingCleanup (r:1 w:0) - // Storage: RankedCollective Voting (r:0 w:2) + /// Storage: RankedPolls ReferendumInfoFor (r:1 w:0) + /// Proof: RankedPolls ReferendumInfoFor (max_values: None, max_size: Some(330), added: 2805, mode: MaxEncodedLen) + /// Storage: RankedCollective VotingCleanup (r:1 w:0) + /// Proof: RankedCollective VotingCleanup (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) + /// Storage: RankedCollective Voting (r:0 w:100) + /// Proof: RankedCollective Voting (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) /// The range of component `n` is `[0, 100]`. fn cleanup_poll(n: u32, ) -> Weight { - // 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))) + // Proof Size summary in bytes: + // Measured: `461 + n * (50 ±0)` + // Estimated: `5394` + // Minimum execution time: 13_245 nanoseconds. + Weight::from_parts(17_420_271, 5394) + // Standard Error: 1_503 + .saturating_add(Weight::from_ref_time(952_500).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) } } // 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) + /// Storage: RankedCollective Members (r:1 w:1) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: RankedCollective MemberCount (r:1 w:1) + /// Proof: RankedCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: RankedCollective IndexToId (r:0 w:1) + /// Proof: RankedCollective IndexToId (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) + /// Storage: RankedCollective IdToIndex (r:0 w:1) + /// Proof: RankedCollective IdToIndex (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) fn add_member() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `109` + // Estimated: `5006` + // Minimum execution time: 16_334 nanoseconds. + Weight::from_parts(16_784_000, 5006) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(4_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) + /// Storage: RankedCollective Members (r:1 w:1) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: RankedCollective MemberCount (r:11 w:11) + /// Proof: RankedCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: RankedCollective IdToIndex (r:11 w:11) + /// Proof: RankedCollective IdToIndex (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) + /// Storage: RankedCollective IndexToId (r:11 w:11) + /// Proof: RankedCollective IndexToId (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) /// The range of component `r` is `[0, 10]`. fn remove_member(r: u32, ) -> Weight { - // 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)) - .saturating_add(RocksDbWeight::get().writes((3 as u64).saturating_mul(r as u64))) + // Proof Size summary in bytes: + // Measured: `583 + r * (281 ±0)` + // Estimated: `10064 + r * (7547 ±0)` + // Minimum execution time: 26_177 nanoseconds. + Weight::from_parts(29_245_248, 10064) + // Standard Error: 18_611 + .saturating_add(Weight::from_ref_time(10_916_516).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(r.into()))) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_proof_size(7547).saturating_mul(r.into())) } - // 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) + /// Storage: RankedCollective Members (r:1 w:1) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: RankedCollective MemberCount (r:1 w:1) + /// Proof: RankedCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: RankedCollective IndexToId (r:0 w:1) + /// Proof: RankedCollective IndexToId (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) + /// Storage: RankedCollective IdToIndex (r:0 w:1) + /// Proof: RankedCollective IdToIndex (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) /// The range of component `r` is `[0, 10]`. fn promote_member(r: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `281 + r * (17 ±0)` + // Estimated: `5006` + // Minimum execution time: 18_953 nanoseconds. + Weight::from_parts(19_570_567, 5006) + // Standard Error: 4_156 + .saturating_add(Weight::from_ref_time(263_843).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(4_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) + /// Storage: RankedCollective Members (r:1 w:1) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: RankedCollective MemberCount (r:1 w:1) + /// Proof: RankedCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: RankedCollective IdToIndex (r:1 w:1) + /// Proof: RankedCollective IdToIndex (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) + /// Storage: RankedCollective IndexToId (r:1 w:1) + /// Proof: RankedCollective IndexToId (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) /// The range of component `r` is `[0, 10]`. fn demote_member(r: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `599 + r * (72 ±0)` + // Estimated: `10064` + // Minimum execution time: 26_243 nanoseconds. + Weight::from_parts(28_532_816, 10064) + // Standard Error: 22_689 + .saturating_add(Weight::from_ref_time(614_464).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(4_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) + /// Storage: RankedCollective Members (r:1 w:0) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: RankedPolls ReferendumInfoFor (r:1 w:1) + /// Proof: RankedPolls ReferendumInfoFor (max_values: None, max_size: Some(330), added: 2805, mode: MaxEncodedLen) + /// Storage: RankedCollective Voting (r:1 w:1) + /// Proof: RankedCollective Voting (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:2 w:2) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn vote() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `626` + // Estimated: `226856` + // Minimum execution time: 41_121 nanoseconds. + Weight::from_parts(41_606_000, 226856) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) } - // Storage: RankedPolls ReferendumInfoFor (r:1 w:0) - // Storage: RankedCollective VotingCleanup (r:1 w:0) - // Storage: RankedCollective Voting (r:0 w:2) + /// Storage: RankedPolls ReferendumInfoFor (r:1 w:0) + /// Proof: RankedPolls ReferendumInfoFor (max_values: None, max_size: Some(330), added: 2805, mode: MaxEncodedLen) + /// Storage: RankedCollective VotingCleanup (r:1 w:0) + /// Proof: RankedCollective VotingCleanup (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) + /// Storage: RankedCollective Voting (r:0 w:100) + /// Proof: RankedCollective Voting (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) /// The range of component `n` is `[0, 100]`. fn cleanup_poll(n: u32, ) -> Weight { - // 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))) + // Proof Size summary in bytes: + // Measured: `461 + n * (50 ±0)` + // Estimated: `5394` + // Minimum execution time: 13_245 nanoseconds. + Weight::from_parts(17_420_271, 5394) + // Standard Error: 1_503 + .saturating_add(Weight::from_ref_time(952_500).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) } } diff --git a/frame/recovery/src/weights.rs b/frame/recovery/src/weights.rs index 39a8d09a38261..73f61654a619a 100644 --- a/frame/recovery/src/weights.rs +++ b/frame/recovery/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2023 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -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-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -61,172 +62,256 @@ pub trait WeightInfo { /// 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) + /// Storage: Recovery Proxy (r:1 w:0) + /// Proof: Recovery Proxy (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) fn as_recovered() -> Weight { - // Minimum execution time: 10_672 nanoseconds. - Weight::from_ref_time(10_946_000 as u64) - .saturating_add(T::DbWeight::get().reads(1 as u64)) + // Proof Size summary in bytes: + // Measured: `281` + // Estimated: `2555` + // Minimum execution time: 8_866 nanoseconds. + Weight::from_parts(9_065_000, 2555) + .saturating_add(T::DbWeight::get().reads(1_u64)) } - // Storage: Recovery Proxy (r:0 w:1) + /// Storage: Recovery Proxy (r:0 w:1) + /// Proof: Recovery Proxy (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) fn set_recovered() -> Weight { - // Minimum execution time: 17_092 nanoseconds. - Weight::from_ref_time(17_660_000 as u64) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 8_893 nanoseconds. + Weight::from_ref_time(9_177_000) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - // Storage: Recovery Recoverable (r:1 w:1) + /// Storage: Recovery Recoverable (r:1 w:1) + /// Proof: Recovery Recoverable (max_values: None, max_size: Some(351), added: 2826, mode: MaxEncodedLen) /// The range of component `n` is `[1, 9]`. fn create_recovery(n: u32, ) -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `175` + // Estimated: `2826` + // Minimum execution time: 20_662 nanoseconds. + Weight::from_parts(21_378_064, 2826) + // Standard Error: 3_350 + .saturating_add(Weight::from_ref_time(83_738).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Recovery Recoverable (r:1 w:0) + /// Proof: Recovery Recoverable (max_values: None, max_size: Some(351), added: 2826, mode: MaxEncodedLen) + /// Storage: Recovery ActiveRecoveries (r:1 w:1) + /// Proof: Recovery ActiveRecoveries (max_values: None, max_size: Some(389), added: 2864, mode: MaxEncodedLen) fn initiate_recovery() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `272` + // Estimated: `5690` + // Minimum execution time: 24_805 nanoseconds. + Weight::from_parts(25_273_000, 5690) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - // Storage: Recovery Recoverable (r:1 w:0) - // Storage: Recovery ActiveRecoveries (r:1 w:1) + /// Storage: Recovery Recoverable (r:1 w:0) + /// Proof: Recovery Recoverable (max_values: None, max_size: Some(351), added: 2826, mode: MaxEncodedLen) + /// Storage: Recovery ActiveRecoveries (r:1 w:1) + /// Proof: Recovery ActiveRecoveries (max_values: None, max_size: Some(389), added: 2864, mode: MaxEncodedLen) /// The range of component `n` is `[1, 9]`. fn vouch_recovery(n: u32, ) -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `423 + n * (64 ±0)` + // Estimated: `5690` + // Minimum execution time: 17_837 nanoseconds. + Weight::from_parts(18_429_664, 5690) + // Standard Error: 3_187 + .saturating_add(Weight::from_ref_time(143_648).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Recovery Recoverable (r:1 w:0) + /// Proof: Recovery Recoverable (max_values: None, max_size: Some(351), added: 2826, mode: MaxEncodedLen) + /// Storage: Recovery ActiveRecoveries (r:1 w:0) + /// Proof: Recovery ActiveRecoveries (max_values: None, max_size: Some(389), added: 2864, mode: MaxEncodedLen) + /// Storage: Recovery Proxy (r:1 w:1) + /// Proof: Recovery Proxy (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) /// The range of component `n` is `[1, 9]`. fn claim_recovery(n: u32, ) -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `455 + n * (64 ±0)` + // Estimated: `8245` + // Minimum execution time: 21_960 nanoseconds. + Weight::from_parts(22_529_644, 8245) + // Standard Error: 2_945 + .saturating_add(Weight::from_ref_time(85_604).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Recovery ActiveRecoveries (r:1 w:1) + /// Proof: Recovery ActiveRecoveries (max_values: None, max_size: Some(389), added: 2864, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `n` is `[1, 9]`. fn close_recovery(n: u32, ) -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `576 + n * (32 ±0)` + // Estimated: `5467` + // Minimum execution time: 26_054 nanoseconds. + Weight::from_parts(26_724_866, 5467) + // Standard Error: 2_645 + .saturating_add(Weight::from_ref_time(104_301).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: Recovery ActiveRecoveries (r:1 w:0) + /// Proof: Recovery ActiveRecoveries (max_values: None, max_size: Some(389), added: 2864, mode: MaxEncodedLen) + /// Storage: Recovery Recoverable (r:1 w:1) + /// Proof: Recovery Recoverable (max_values: None, max_size: Some(351), added: 2826, mode: MaxEncodedLen) /// The range of component `n` is `[1, 9]`. fn remove_recovery(n: u32, ) -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `302 + n * (32 ±0)` + // Estimated: `5690` + // Minimum execution time: 25_110 nanoseconds. + Weight::from_parts(25_805_837, 5690) + // Standard Error: 2_732 + .saturating_add(Weight::from_ref_time(73_458).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Recovery Proxy (r:1 w:1) + /// Proof: Recovery Proxy (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) fn cancel_recovered() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `281` + // Estimated: `2555` + // Minimum execution time: 11_061 nanoseconds. + Weight::from_parts(11_291_000, 2555) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } } // For backwards compatibility and tests impl WeightInfo for () { - // Storage: Recovery Proxy (r:1 w:0) + /// Storage: Recovery Proxy (r:1 w:0) + /// Proof: Recovery Proxy (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) fn as_recovered() -> Weight { - // Minimum execution time: 10_672 nanoseconds. - Weight::from_ref_time(10_946_000 as u64) - .saturating_add(RocksDbWeight::get().reads(1 as u64)) + // Proof Size summary in bytes: + // Measured: `281` + // Estimated: `2555` + // Minimum execution time: 8_866 nanoseconds. + Weight::from_parts(9_065_000, 2555) + .saturating_add(RocksDbWeight::get().reads(1_u64)) } - // Storage: Recovery Proxy (r:0 w:1) + /// Storage: Recovery Proxy (r:0 w:1) + /// Proof: Recovery Proxy (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) fn set_recovered() -> Weight { - // Minimum execution time: 17_092 nanoseconds. - Weight::from_ref_time(17_660_000 as u64) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 8_893 nanoseconds. + Weight::from_ref_time(9_177_000) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - // Storage: Recovery Recoverable (r:1 w:1) + /// Storage: Recovery Recoverable (r:1 w:1) + /// Proof: Recovery Recoverable (max_values: None, max_size: Some(351), added: 2826, mode: MaxEncodedLen) /// The range of component `n` is `[1, 9]`. fn create_recovery(n: u32, ) -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `175` + // Estimated: `2826` + // Minimum execution time: 20_662 nanoseconds. + Weight::from_parts(21_378_064, 2826) + // Standard Error: 3_350 + .saturating_add(Weight::from_ref_time(83_738).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Recovery Recoverable (r:1 w:0) + /// Proof: Recovery Recoverable (max_values: None, max_size: Some(351), added: 2826, mode: MaxEncodedLen) + /// Storage: Recovery ActiveRecoveries (r:1 w:1) + /// Proof: Recovery ActiveRecoveries (max_values: None, max_size: Some(389), added: 2864, mode: MaxEncodedLen) fn initiate_recovery() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `272` + // Estimated: `5690` + // Minimum execution time: 24_805 nanoseconds. + Weight::from_parts(25_273_000, 5690) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - // Storage: Recovery Recoverable (r:1 w:0) - // Storage: Recovery ActiveRecoveries (r:1 w:1) + /// Storage: Recovery Recoverable (r:1 w:0) + /// Proof: Recovery Recoverable (max_values: None, max_size: Some(351), added: 2826, mode: MaxEncodedLen) + /// Storage: Recovery ActiveRecoveries (r:1 w:1) + /// Proof: Recovery ActiveRecoveries (max_values: None, max_size: Some(389), added: 2864, mode: MaxEncodedLen) /// The range of component `n` is `[1, 9]`. fn vouch_recovery(n: u32, ) -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `423 + n * (64 ±0)` + // Estimated: `5690` + // Minimum execution time: 17_837 nanoseconds. + Weight::from_parts(18_429_664, 5690) + // Standard Error: 3_187 + .saturating_add(Weight::from_ref_time(143_648).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Recovery Recoverable (r:1 w:0) + /// Proof: Recovery Recoverable (max_values: None, max_size: Some(351), added: 2826, mode: MaxEncodedLen) + /// Storage: Recovery ActiveRecoveries (r:1 w:0) + /// Proof: Recovery ActiveRecoveries (max_values: None, max_size: Some(389), added: 2864, mode: MaxEncodedLen) + /// Storage: Recovery Proxy (r:1 w:1) + /// Proof: Recovery Proxy (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) /// The range of component `n` is `[1, 9]`. fn claim_recovery(n: u32, ) -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `455 + n * (64 ±0)` + // Estimated: `8245` + // Minimum execution time: 21_960 nanoseconds. + Weight::from_parts(22_529_644, 8245) + // Standard Error: 2_945 + .saturating_add(Weight::from_ref_time(85_604).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Recovery ActiveRecoveries (r:1 w:1) + /// Proof: Recovery ActiveRecoveries (max_values: None, max_size: Some(389), added: 2864, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `n` is `[1, 9]`. fn close_recovery(n: u32, ) -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `576 + n * (32 ±0)` + // Estimated: `5467` + // Minimum execution time: 26_054 nanoseconds. + Weight::from_parts(26_724_866, 5467) + // Standard Error: 2_645 + .saturating_add(Weight::from_ref_time(104_301).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: Recovery ActiveRecoveries (r:1 w:0) + /// Proof: Recovery ActiveRecoveries (max_values: None, max_size: Some(389), added: 2864, mode: MaxEncodedLen) + /// Storage: Recovery Recoverable (r:1 w:1) + /// Proof: Recovery Recoverable (max_values: None, max_size: Some(351), added: 2826, mode: MaxEncodedLen) /// The range of component `n` is `[1, 9]`. fn remove_recovery(n: u32, ) -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `302 + n * (32 ±0)` + // Estimated: `5690` + // Minimum execution time: 25_110 nanoseconds. + Weight::from_parts(25_805_837, 5690) + // Standard Error: 2_732 + .saturating_add(Weight::from_ref_time(73_458).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Recovery Proxy (r:1 w:1) + /// Proof: Recovery Proxy (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) fn cancel_recovered() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `281` + // Estimated: `2555` + // Minimum execution time: 11_061 nanoseconds. + Weight::from_parts(11_291_000, 2555) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } } diff --git a/frame/referenda/src/mock.rs b/frame/referenda/src/mock.rs index e957027e561ab..82ae508d52b6f 100644 --- a/frame/referenda/src/mock.rs +++ b/frame/referenda/src/mock.rs @@ -62,7 +62,7 @@ impl Contains for BaseFilter { } parameter_types! { - pub MaxWeight: Weight = Weight::from_ref_time(2_000_000_000_000); + pub MaxWeight: Weight = Weight::from_parts(2_000_000_000_000, u64::MAX); } impl frame_system::Config for Test { type BaseCallFilter = BaseFilter; diff --git a/frame/referenda/src/weights.rs b/frame/referenda/src/weights.rs index f0eae517af743..68b44e8beff90 100644 --- a/frame/referenda/src/weights.rs +++ b/frame/referenda/src/weights.rs @@ -1,3 +1,8 @@ +// This file is part of Substrate. + +// Copyright (C) 2023 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at @@ -13,22 +18,25 @@ //! Autogenerated weights for pallet_referenda //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! 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 +//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! 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=20 -// --repeat=1 -// --pallet=pallet-referenda +// --steps=50 +// --repeat=20 +// --pallet=pallet_referenda // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/referenda/src/._weights.rs +// --output=./frame/referenda/src/weights.rs +// --header=./HEADER-APACHE2 // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -73,482 +81,788 @@ pub trait WeightInfo { /// 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) + /// Storage: Referenda ReferendumCount (r:1 w:1) + /// Proof: Referenda ReferendumCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: Referenda ReferendumInfoFor (r:0 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) fn submit() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `251` + // Estimated: `109996` + // Minimum execution time: 32_207 nanoseconds. + Weight::from_parts(32_639_000, 109996) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:2 w:2) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn place_decision_deposit_preparing() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `536` + // Estimated: `221835` + // Minimum execution time: 43_766 nanoseconds. + Weight::from_parts(44_494_000, 221835) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Referenda DecidingCount (r:1 w:0) + /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: Referenda TrackQueue (r:1 w:1) + /// Proof: Referenda TrackQueue (max_values: None, max_size: Some(2012), added: 4487, mode: MaxEncodedLen) fn place_decision_deposit_queued() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `3203` + // Estimated: `9817` + // Minimum execution time: 41_561 nanoseconds. + Weight::from_parts(42_180_000, 9817) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Referenda DecidingCount (r:1 w:0) + /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: Referenda TrackQueue (r:1 w:1) + /// Proof: Referenda TrackQueue (max_values: None, max_size: Some(2012), added: 4487, mode: MaxEncodedLen) fn place_decision_deposit_not_queued() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `3223` + // Estimated: `9817` + // Minimum execution time: 41_039 nanoseconds. + Weight::from_parts(41_673_000, 9817) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Referenda DecidingCount (r:1 w:1) + /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:2 w:2) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn place_decision_deposit_passing() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `536` + // Estimated: `224324` + // Minimum execution time: 52_922 nanoseconds. + Weight::from_parts(53_395_000, 224324) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Referenda DecidingCount (r:1 w:1) + /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:2 w:2) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn place_decision_deposit_failing() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `536` + // Estimated: `224324` + // Minimum execution time: 51_050 nanoseconds. + Weight::from_parts(51_736_000, 224324) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) fn refund_decision_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) + // Proof Size summary in bytes: + // Measured: `415` + // Estimated: `2841` + // Minimum execution time: 24_102 nanoseconds. + Weight::from_parts(24_372_000, 2841) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) 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) + // Proof Size summary in bytes: + // Measured: `405` + // Estimated: `2841` + // Minimum execution time: 24_162 nanoseconds. + Weight::from_parts(24_547_000, 2841) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:2 w:2) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn cancel() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `412` + // Estimated: `221835` + // Minimum execution time: 32_247 nanoseconds. + Weight::from_parts(32_731_000, 221835) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:2 w:2) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn kill() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `717` + // Estimated: `221835` + // Minimum execution time: 59_900 nanoseconds. + Weight::from_parts(60_659_000, 221835) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: Referenda TrackQueue (r:1 w:0) + /// Proof: Referenda TrackQueue (max_values: None, max_size: Some(2012), added: 4487, mode: MaxEncodedLen) + /// Storage: Referenda DecidingCount (r:1 w:1) + /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) fn one_fewer_deciding_queue_empty() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `174` + // Estimated: `6976` + // Minimum execution time: 9_322 nanoseconds. + Weight::from_parts(9_638_000, 6976) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Referenda TrackQueue (r:1 w:1) + /// Proof: Referenda TrackQueue (max_values: None, max_size: Some(2012), added: 4487, mode: MaxEncodedLen) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:2 w:2) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn one_fewer_deciding_failing() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `4661` + // Estimated: `226322` + // Minimum execution time: 76_976 nanoseconds. + Weight::from_parts(77_597_000, 226322) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: Referenda TrackQueue (r:1 w:1) + /// Proof: Referenda TrackQueue (max_values: None, max_size: Some(2012), added: 4487, mode: MaxEncodedLen) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:2 w:2) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn one_fewer_deciding_passing() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `4661` + // Estimated: `226322` + // Minimum execution time: 78_405 nanoseconds. + Weight::from_parts(78_972_000, 226322) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Referenda TrackQueue (r:1 w:1) + /// Proof: Referenda TrackQueue (max_values: None, max_size: Some(2012), added: 4487, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_requeued_insertion() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `4682` + // Estimated: `116825` + // Minimum execution time: 51_360 nanoseconds. + Weight::from_parts(51_737_000, 116825) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Referenda TrackQueue (r:1 w:1) + /// Proof: Referenda TrackQueue (max_values: None, max_size: Some(2012), added: 4487, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_requeued_slide() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `4668` + // Estimated: `116825` + // Minimum execution time: 50_485 nanoseconds. + Weight::from_parts(51_601_000, 116825) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Referenda DecidingCount (r:1 w:0) + /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: Referenda TrackQueue (r:1 w:1) + /// Proof: Referenda TrackQueue (max_values: None, max_size: Some(2012), added: 4487, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_queued() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `4642` + // Estimated: `119314` + // Minimum execution time: 53_075 nanoseconds. + Weight::from_parts(54_014_000, 119314) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Referenda DecidingCount (r:1 w:0) + /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: Referenda TrackQueue (r:1 w:1) + /// Proof: Referenda TrackQueue (max_values: None, max_size: Some(2012), added: 4487, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_not_queued() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `4676` + // Estimated: `119314` + // Minimum execution time: 52_916 nanoseconds. + Weight::from_parts(53_716_000, 119314) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_no_deposit() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `364` + // Estimated: `112338` + // Minimum execution time: 21_920 nanoseconds. + Weight::from_parts(22_172_000, 112338) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_preparing() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `412` + // Estimated: `112338` + // Minimum execution time: 22_094 nanoseconds. + Weight::from_parts(22_314_000, 112338) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) fn nudge_referendum_timed_out() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `310` + // Estimated: `2841` + // Minimum execution time: 15_696 nanoseconds. + Weight::from_parts(15_964_000, 2841) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Referenda DecidingCount (r:1 w:1) + /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_begin_deciding_failing() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `412` + // Estimated: `114827` + // Minimum execution time: 30_604 nanoseconds. + Weight::from_parts(31_126_000, 114827) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Referenda DecidingCount (r:1 w:1) + /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_begin_deciding_passing() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `412` + // Estimated: `114827` + // Minimum execution time: 32_961 nanoseconds. + Weight::from_parts(33_295_000, 114827) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_begin_confirming() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `465` + // Estimated: `112338` + // Minimum execution time: 27_072 nanoseconds. + Weight::from_parts(27_405_000, 112338) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_end_confirming() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `448` + // Estimated: `112338` + // Minimum execution time: 27_056 nanoseconds. + Weight::from_parts(27_768_000, 112338) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_continue_not_confirming() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `465` + // Estimated: `112338` + // Minimum execution time: 24_599 nanoseconds. + Weight::from_parts(25_170_000, 112338) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_continue_confirming() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `469` + // Estimated: `112338` + // Minimum execution time: 23_737 nanoseconds. + Weight::from_parts(24_184_000, 112338) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:2 w:2) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: Scheduler Lookup (r:1 w:1) + /// Proof: Scheduler Lookup (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) fn nudge_referendum_approved() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `469` + // Estimated: `224358` + // Minimum execution time: 37_880 nanoseconds. + Weight::from_parts(38_537_000, 224358) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_rejected() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `465` + // Estimated: `112338` + // Minimum execution time: 26_898 nanoseconds. + Weight::from_parts(27_496_000, 112338) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } } // For backwards compatibility and tests impl WeightInfo for () { - // Storage: Referenda ReferendumCount (r:1 w:1) - // Storage: Scheduler Agenda (r:1 w:1) - // Storage: Referenda ReferendumInfoFor (r:0 w:1) + /// Storage: Referenda ReferendumCount (r:1 w:1) + /// Proof: Referenda ReferendumCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: Referenda ReferendumInfoFor (r:0 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) fn submit() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `251` + // Estimated: `109996` + // Minimum execution time: 32_207 nanoseconds. + Weight::from_parts(32_639_000, 109996) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:2 w:2) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn place_decision_deposit_preparing() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `536` + // Estimated: `221835` + // Minimum execution time: 43_766 nanoseconds. + Weight::from_parts(44_494_000, 221835) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Referenda DecidingCount (r:1 w:0) + /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: Referenda TrackQueue (r:1 w:1) + /// Proof: Referenda TrackQueue (max_values: None, max_size: Some(2012), added: 4487, mode: MaxEncodedLen) fn place_decision_deposit_queued() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `3203` + // Estimated: `9817` + // Minimum execution time: 41_561 nanoseconds. + Weight::from_parts(42_180_000, 9817) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Referenda DecidingCount (r:1 w:0) + /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: Referenda TrackQueue (r:1 w:1) + /// Proof: Referenda TrackQueue (max_values: None, max_size: Some(2012), added: 4487, mode: MaxEncodedLen) fn place_decision_deposit_not_queued() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `3223` + // Estimated: `9817` + // Minimum execution time: 41_039 nanoseconds. + Weight::from_parts(41_673_000, 9817) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Referenda DecidingCount (r:1 w:1) + /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:2 w:2) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn place_decision_deposit_passing() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `536` + // Estimated: `224324` + // Minimum execution time: 52_922 nanoseconds. + Weight::from_parts(53_395_000, 224324) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + } + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Referenda DecidingCount (r:1 w:1) + /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:2 w:2) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn place_decision_deposit_failing() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `536` + // Estimated: `224324` + // Minimum execution time: 51_050 nanoseconds. + Weight::from_parts(51_736_000, 224324) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + } + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) fn refund_decision_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) + // Proof Size summary in bytes: + // Measured: `415` + // Estimated: `2841` + // Minimum execution time: 24_102 nanoseconds. + Weight::from_parts(24_372_000, 2841) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) 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) + // Proof Size summary in bytes: + // Measured: `405` + // Estimated: `2841` + // Minimum execution time: 24_162 nanoseconds. + Weight::from_parts(24_547_000, 2841) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:2 w:2) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn cancel() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `412` + // Estimated: `221835` + // Minimum execution time: 32_247 nanoseconds. + Weight::from_parts(32_731_000, 221835) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:2 w:2) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn kill() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `717` + // Estimated: `221835` + // Minimum execution time: 59_900 nanoseconds. + Weight::from_parts(60_659_000, 221835) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: Referenda TrackQueue (r:1 w:0) + /// Proof: Referenda TrackQueue (max_values: None, max_size: Some(2012), added: 4487, mode: MaxEncodedLen) + /// Storage: Referenda DecidingCount (r:1 w:1) + /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) fn one_fewer_deciding_queue_empty() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `174` + // Estimated: `6976` + // Minimum execution time: 9_322 nanoseconds. + Weight::from_parts(9_638_000, 6976) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Referenda TrackQueue (r:1 w:1) + /// Proof: Referenda TrackQueue (max_values: None, max_size: Some(2012), added: 4487, mode: MaxEncodedLen) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:2 w:2) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn one_fewer_deciding_failing() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `4661` + // Estimated: `226322` + // Minimum execution time: 76_976 nanoseconds. + Weight::from_parts(77_597_000, 226322) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + } + /// Storage: Referenda TrackQueue (r:1 w:1) + /// Proof: Referenda TrackQueue (max_values: None, max_size: Some(2012), added: 4487, mode: MaxEncodedLen) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:2 w:2) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn one_fewer_deciding_passing() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `4661` + // Estimated: `226322` + // Minimum execution time: 78_405 nanoseconds. + Weight::from_parts(78_972_000, 226322) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + } + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Referenda TrackQueue (r:1 w:1) + /// Proof: Referenda TrackQueue (max_values: None, max_size: Some(2012), added: 4487, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_requeued_insertion() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `4682` + // Estimated: `116825` + // Minimum execution time: 51_360 nanoseconds. + Weight::from_parts(51_737_000, 116825) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Referenda TrackQueue (r:1 w:1) + /// Proof: Referenda TrackQueue (max_values: None, max_size: Some(2012), added: 4487, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_requeued_slide() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `4668` + // Estimated: `116825` + // Minimum execution time: 50_485 nanoseconds. + Weight::from_parts(51_601_000, 116825) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Referenda DecidingCount (r:1 w:0) + /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: Referenda TrackQueue (r:1 w:1) + /// Proof: Referenda TrackQueue (max_values: None, max_size: Some(2012), added: 4487, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_queued() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `4642` + // Estimated: `119314` + // Minimum execution time: 53_075 nanoseconds. + Weight::from_parts(54_014_000, 119314) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Referenda DecidingCount (r:1 w:0) + /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: Referenda TrackQueue (r:1 w:1) + /// Proof: Referenda TrackQueue (max_values: None, max_size: Some(2012), added: 4487, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_not_queued() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `4676` + // Estimated: `119314` + // Minimum execution time: 52_916 nanoseconds. + Weight::from_parts(53_716_000, 119314) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_no_deposit() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `364` + // Estimated: `112338` + // Minimum execution time: 21_920 nanoseconds. + Weight::from_parts(22_172_000, 112338) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_preparing() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `412` + // Estimated: `112338` + // Minimum execution time: 22_094 nanoseconds. + Weight::from_parts(22_314_000, 112338) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) fn nudge_referendum_timed_out() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `310` + // Estimated: `2841` + // Minimum execution time: 15_696 nanoseconds. + Weight::from_parts(15_964_000, 2841) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Referenda DecidingCount (r:1 w:1) + /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_begin_deciding_failing() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `412` + // Estimated: `114827` + // Minimum execution time: 30_604 nanoseconds. + Weight::from_parts(31_126_000, 114827) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Referenda DecidingCount (r:1 w:1) + /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_begin_deciding_passing() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `412` + // Estimated: `114827` + // Minimum execution time: 32_961 nanoseconds. + Weight::from_parts(33_295_000, 114827) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_begin_confirming() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `465` + // Estimated: `112338` + // Minimum execution time: 27_072 nanoseconds. + Weight::from_parts(27_405_000, 112338) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_end_confirming() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `448` + // Estimated: `112338` + // Minimum execution time: 27_056 nanoseconds. + Weight::from_parts(27_768_000, 112338) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_continue_not_confirming() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `465` + // Estimated: `112338` + // Minimum execution time: 24_599 nanoseconds. + Weight::from_parts(25_170_000, 112338) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_continue_confirming() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `469` + // Estimated: `112338` + // Minimum execution time: 23_737 nanoseconds. + Weight::from_parts(24_184_000, 112338) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:2 w:2) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: Scheduler Lookup (r:1 w:1) + /// Proof: Scheduler Lookup (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) fn nudge_referendum_approved() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `469` + // Estimated: `224358` + // Minimum execution time: 37_880 nanoseconds. + Weight::from_parts(38_537_000, 224358) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + } + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_rejected() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `465` + // Estimated: `112338` + // Minimum execution time: 26_898 nanoseconds. + Weight::from_parts(27_496_000, 112338) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } } diff --git a/frame/remark/src/weights.rs b/frame/remark/src/weights.rs index 0d739657c852b..9142ed04c5108 100644 --- a/frame/remark/src/weights.rs +++ b/frame/remark/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2023 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -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-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -53,26 +54,28 @@ pub trait WeightInfo { /// 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) /// The range of component `l` is `[1, 1048576]`. fn store(l: u32, ) -> Weight { - // Minimum execution time: 17_017 nanoseconds. - Weight::from_ref_time(8_269_935 as u64) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 8_404 nanoseconds. + Weight::from_ref_time(343_031) // 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)) + .saturating_add(Weight::from_ref_time(1_404).saturating_mul(l.into())) } } // 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 { - // Minimum execution time: 17_017 nanoseconds. - Weight::from_ref_time(8_269_935 as u64) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 8_404 nanoseconds. + Weight::from_ref_time(343_031) // 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)) + .saturating_add(Weight::from_ref_time(1_404).saturating_mul(l.into())) } } diff --git a/frame/scheduler/src/benchmarking.rs b/frame/scheduler/src/benchmarking.rs index ca98cabc3c08b..8e2876290be55 100644 --- a/frame/scheduler/src/benchmarking.rs +++ b/frame/scheduler/src/benchmarking.rs @@ -160,6 +160,10 @@ benchmarks! { // `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). + #[pov_mode = MaxEncodedLen { + // Use measured PoV size for the Preimages since we pass in a length witness. + Preimage::PreimageFor: Measured + }] service_task_fetched { let s in (BoundedInline::bound() as u32) .. (T::Preimages::MAX_LENGTH as u32); let now = BLOCK_NUMBER.into(); diff --git a/frame/scheduler/src/weights.rs b/frame/scheduler/src/weights.rs index 5b86e7a143e7a..9be3bfaef5723 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) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2023 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,7 +18,8 @@ //! Autogenerated weights for pallet_scheduler //! //! 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: `[]` +//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -64,194 +65,292 @@ pub trait WeightInfo { /// Weights for pallet_scheduler using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - // Storage: Scheduler IncompleteSince (r:1 w:1) + /// Storage: Scheduler IncompleteSince (r:1 w:1) + /// Proof: Scheduler IncompleteSince (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn service_agendas_base() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `30` + // Estimated: `499` + // Minimum execution time: 3_670 nanoseconds. + Weight::from_parts(3_838_000, 499) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - // Storage: Scheduler Agenda (r:1 w:1) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) /// The range of component `s` is `[0, 512]`. fn service_agenda_base(s: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `112 + s * (177 ±0)` + // Estimated: `109497` + // Minimum execution time: 3_079 nanoseconds. + Weight::from_parts(7_087_647, 109497) + // Standard Error: 658 + .saturating_add(Weight::from_ref_time(279_320).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } fn service_task_base() -> Weight { - // Minimum execution time: 10_880 nanoseconds. - Weight::from_ref_time(11_194_000 as u64) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 5_192 nanoseconds. + Weight::from_ref_time(5_528_000) } - // Storage: Preimage PreimageFor (r:1 w:1) - // Storage: Preimage StatusFor (r:1 w:1) + /// Storage: Preimage PreimageFor (r:1 w:1) + /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: Measured) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) /// The range of component `s` is `[128, 4194304]`. fn service_task_fetched(s: u32, ) -> Weight { - // Minimum execution time: 25_347 nanoseconds. - Weight::from_ref_time(25_717_000 as u64) + // Proof Size summary in bytes: + // Measured: `211 + s * (1 ±0)` + // Estimated: `5252 + s * (1 ±0)` + // Minimum execution time: 17_284 nanoseconds. + Weight::from_parts(17_574_000, 5252) // 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)) + .saturating_add(Weight::from_ref_time(1_126).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_proof_size(1).saturating_mul(s.into())) } - // Storage: Scheduler Lookup (r:0 w:1) + /// Storage: Scheduler Lookup (r:0 w:1) + /// Proof: Scheduler Lookup (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) fn service_task_named() -> Weight { - // Minimum execution time: 12_894 nanoseconds. - Weight::from_ref_time(13_108_000 as u64) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 7_020 nanoseconds. + Weight::from_ref_time(7_262_000) + .saturating_add(T::DbWeight::get().writes(1_u64)) } fn service_task_periodic() -> Weight { - // Minimum execution time: 10_667 nanoseconds. - Weight::from_ref_time(10_908_000 as u64) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 5_187 nanoseconds. + Weight::from_ref_time(5_368_000) } fn execute_dispatch_signed() -> Weight { - // Minimum execution time: 4_124 nanoseconds. - Weight::from_ref_time(4_680_000 as u64) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_313 nanoseconds. + Weight::from_ref_time(2_404_000) } fn execute_dispatch_unsigned() -> Weight { - // Minimum execution time: 4_156 nanoseconds. - Weight::from_ref_time(4_361_000 as u64) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_187 nanoseconds. + Weight::from_ref_time(2_362_000) } - // Storage: Scheduler Agenda (r:1 w:1) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) /// The range of component `s` is `[0, 511]`. fn schedule(s: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `112 + s * (177 ±0)` + // Estimated: `109497` + // Minimum execution time: 11_971 nanoseconds. + Weight::from_parts(16_060_361, 109497) + // Standard Error: 665 + .saturating_add(Weight::from_ref_time(286_324).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - // Storage: Scheduler Agenda (r:1 w:1) - // Storage: Scheduler Lookup (r:0 w:1) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: Scheduler Lookup (r:0 w:1) + /// Proof: Scheduler Lookup (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) /// The range of component `s` is `[1, 512]`. fn cancel(s: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `112 + s * (177 ±0)` + // Estimated: `109497` + // Minimum execution time: 15_594 nanoseconds. + Weight::from_parts(17_191_501, 109497) + // Standard Error: 626 + .saturating_add(Weight::from_ref_time(425_572).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } - // Storage: Scheduler Lookup (r:1 w:1) - // Storage: Scheduler Agenda (r:1 w:1) + /// Storage: Scheduler Lookup (r:1 w:1) + /// Proof: Scheduler Lookup (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) /// The range of component `s` is `[0, 511]`. fn schedule_named(s: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `627 + s * (178 ±0)` + // Estimated: `112020` + // Minimum execution time: 15_127 nanoseconds. + Weight::from_parts(20_932_642, 112020) + // Standard Error: 692 + .saturating_add(Weight::from_ref_time(288_344).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } - // Storage: Scheduler Lookup (r:1 w:1) - // Storage: Scheduler Agenda (r:1 w:1) + /// Storage: Scheduler Lookup (r:1 w:1) + /// Proof: Scheduler Lookup (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) /// The range of component `s` is `[1, 512]`. fn cancel_named(s: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `740 + s * (177 ±0)` + // Estimated: `112020` + // Minimum execution time: 16_859 nanoseconds. + Weight::from_parts(19_736_937, 112020) + // Standard Error: 676 + .saturating_add(Weight::from_ref_time(429_770).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } } // For backwards compatibility and tests impl WeightInfo for () { - // Storage: Scheduler IncompleteSince (r:1 w:1) + /// Storage: Scheduler IncompleteSince (r:1 w:1) + /// Proof: Scheduler IncompleteSince (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn service_agendas_base() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `30` + // Estimated: `499` + // Minimum execution time: 3_670 nanoseconds. + Weight::from_parts(3_838_000, 499) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - // Storage: Scheduler Agenda (r:1 w:1) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) /// The range of component `s` is `[0, 512]`. fn service_agenda_base(s: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `112 + s * (177 ±0)` + // Estimated: `109497` + // Minimum execution time: 3_079 nanoseconds. + Weight::from_parts(7_087_647, 109497) + // Standard Error: 658 + .saturating_add(Weight::from_ref_time(279_320).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } fn service_task_base() -> Weight { - // Minimum execution time: 10_880 nanoseconds. - Weight::from_ref_time(11_194_000 as u64) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 5_192 nanoseconds. + Weight::from_ref_time(5_528_000) } - // Storage: Preimage PreimageFor (r:1 w:1) - // Storage: Preimage StatusFor (r:1 w:1) + /// Storage: Preimage PreimageFor (r:1 w:1) + /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: Measured) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) /// The range of component `s` is `[128, 4194304]`. fn service_task_fetched(s: u32, ) -> Weight { - // Minimum execution time: 25_347 nanoseconds. - Weight::from_ref_time(25_717_000 as u64) + // Proof Size summary in bytes: + // Measured: `211 + s * (1 ±0)` + // Estimated: `5252 + s * (1 ±0)` + // Minimum execution time: 17_284 nanoseconds. + Weight::from_parts(17_574_000, 5252) // 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)) + .saturating_add(Weight::from_ref_time(1_126).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_proof_size(1).saturating_mul(s.into())) } - // Storage: Scheduler Lookup (r:0 w:1) + /// Storage: Scheduler Lookup (r:0 w:1) + /// Proof: Scheduler Lookup (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) fn service_task_named() -> Weight { - // Minimum execution time: 12_894 nanoseconds. - Weight::from_ref_time(13_108_000 as u64) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 7_020 nanoseconds. + Weight::from_ref_time(7_262_000) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } fn service_task_periodic() -> Weight { - // Minimum execution time: 10_667 nanoseconds. - Weight::from_ref_time(10_908_000 as u64) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 5_187 nanoseconds. + Weight::from_ref_time(5_368_000) } fn execute_dispatch_signed() -> Weight { - // Minimum execution time: 4_124 nanoseconds. - Weight::from_ref_time(4_680_000 as u64) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_313 nanoseconds. + Weight::from_ref_time(2_404_000) } fn execute_dispatch_unsigned() -> Weight { - // Minimum execution time: 4_156 nanoseconds. - Weight::from_ref_time(4_361_000 as u64) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_187 nanoseconds. + Weight::from_ref_time(2_362_000) } - // Storage: Scheduler Agenda (r:1 w:1) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) /// The range of component `s` is `[0, 511]`. fn schedule(s: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `112 + s * (177 ±0)` + // Estimated: `109497` + // Minimum execution time: 11_971 nanoseconds. + Weight::from_parts(16_060_361, 109497) + // Standard Error: 665 + .saturating_add(Weight::from_ref_time(286_324).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - // Storage: Scheduler Agenda (r:1 w:1) - // Storage: Scheduler Lookup (r:0 w:1) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: Scheduler Lookup (r:0 w:1) + /// Proof: Scheduler Lookup (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) /// The range of component `s` is `[1, 512]`. fn cancel(s: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `112 + s * (177 ±0)` + // Estimated: `109497` + // Minimum execution time: 15_594 nanoseconds. + Weight::from_parts(17_191_501, 109497) + // Standard Error: 626 + .saturating_add(Weight::from_ref_time(425_572).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } - // Storage: Scheduler Lookup (r:1 w:1) - // Storage: Scheduler Agenda (r:1 w:1) + /// Storage: Scheduler Lookup (r:1 w:1) + /// Proof: Scheduler Lookup (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) /// The range of component `s` is `[0, 511]`. fn schedule_named(s: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `627 + s * (178 ±0)` + // Estimated: `112020` + // Minimum execution time: 15_127 nanoseconds. + Weight::from_parts(20_932_642, 112020) + // Standard Error: 692 + .saturating_add(Weight::from_ref_time(288_344).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } - // Storage: Scheduler Lookup (r:1 w:1) - // Storage: Scheduler Agenda (r:1 w:1) + /// Storage: Scheduler Lookup (r:1 w:1) + /// Proof: Scheduler Lookup (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) /// The range of component `s` is `[1, 512]`. fn cancel_named(s: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `740 + s * (177 ±0)` + // Estimated: `112020` + // Minimum execution time: 16_859 nanoseconds. + Weight::from_parts(19_736_937, 112020) + // Standard Error: 676 + .saturating_add(Weight::from_ref_time(429_770).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } } diff --git a/frame/session/src/weights.rs b/frame/session/src/weights.rs index d29413a33dd17..aea9d9dbf526d 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) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2023 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -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-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -54,44 +55,68 @@ pub trait WeightInfo { /// Weights for pallet_session using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - // Storage: Staking Ledger (r:1 w:0) - // Storage: Session NextKeys (r:1 w:1) - // Storage: Session KeyOwner (r:4 w:4) + /// Storage: Staking Ledger (r:1 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Session NextKeys (r:1 w:1) + /// Proof Skipped: Session NextKeys (max_values: None, max_size: None, mode: Measured) + /// Storage: Session KeyOwner (r:4 w:4) + /// Proof Skipped: Session KeyOwner (max_values: None, max_size: None, mode: Measured) fn set_keys() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `1955` + // Estimated: `19851` + // Minimum execution time: 40_867 nanoseconds. + Weight::from_parts(41_319_000, 19851) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) } - // Storage: Staking Ledger (r:1 w:0) - // Storage: Session NextKeys (r:1 w:1) - // Storage: Session KeyOwner (r:0 w:4) + /// Storage: Staking Ledger (r:1 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Session NextKeys (r:1 w:1) + /// Proof Skipped: Session NextKeys (max_values: None, max_size: None, mode: Measured) + /// Storage: Session KeyOwner (r:0 w:4) + /// Proof Skipped: Session KeyOwner (max_values: None, max_size: None, mode: Measured) fn purge_keys() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `1854` + // Estimated: `9749` + // Minimum execution time: 30_286 nanoseconds. + Weight::from_parts(30_620_000, 9749) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) } } // For backwards compatibility and tests impl WeightInfo for () { - // Storage: Staking Ledger (r:1 w:0) - // Storage: Session NextKeys (r:1 w:1) - // Storage: Session KeyOwner (r:4 w:4) + /// Storage: Staking Ledger (r:1 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Session NextKeys (r:1 w:1) + /// Proof Skipped: Session NextKeys (max_values: None, max_size: None, mode: Measured) + /// Storage: Session KeyOwner (r:4 w:4) + /// Proof Skipped: Session KeyOwner (max_values: None, max_size: None, mode: Measured) fn set_keys() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `1955` + // Estimated: `19851` + // Minimum execution time: 40_867 nanoseconds. + Weight::from_parts(41_319_000, 19851) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(5_u64)) } - // Storage: Staking Ledger (r:1 w:0) - // Storage: Session NextKeys (r:1 w:1) - // Storage: Session KeyOwner (r:0 w:4) + /// Storage: Staking Ledger (r:1 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Session NextKeys (r:1 w:1) + /// Proof Skipped: Session NextKeys (max_values: None, max_size: None, mode: Measured) + /// Storage: Session KeyOwner (r:0 w:4) + /// Proof Skipped: Session KeyOwner (max_values: None, max_size: None, mode: Measured) fn purge_keys() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `1854` + // Estimated: `9749` + // Minimum execution time: 30_286 nanoseconds. + Weight::from_parts(30_620_000, 9749) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(5_u64)) } } diff --git a/frame/staking/src/weights.rs b/frame/staking/src/weights.rs index 9c283f5a065e3..af2afa2b538d6 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) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2023 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,25 +18,25 @@ //! Autogenerated weights for pallet_staking //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-12-25, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! DATE: 2023-01-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! 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 -// --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 +// --header=./HEADER-APACHE2 // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -83,838 +83,1404 @@ pub trait WeightInfo { /// Weights for pallet_staking using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - // Storage: Staking Bonded (r:1 w:1) - // Storage: Staking Ledger (r:1 w:1) - // Storage: Staking CurrentEra (r:1 w:0) - // Storage: Balances Locks (r:1 w:1) - // Storage: Staking Payee (r:0 w:1) + /// Storage: Staking Bonded (r:1 w:1) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:1 w:1) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking CurrentEra (r:1 w:0) + /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Staking Payee (r:0 w:1) + /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) fn bond() -> Weight { - // Minimum execution time: 54_884 nanoseconds. - Weight::from_ref_time(55_487_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) - // Storage: Balances Locks (r:1 w:1) - // Storage: VoterList ListNodes (r:3 w:3) - // Storage: VoterList ListBags (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `1079` + // Estimated: `10386` + // Minimum execution time: 40_015 nanoseconds. + Weight::from_parts(40_601_000, 10386) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: Staking Bonded (r:1 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:1 w:1) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:3 w:3) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:2 w:2) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) fn bond_extra() -> Weight { - // Minimum execution time: 95_115 nanoseconds. - Weight::from_ref_time(96_213_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) - // 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: VoterList ListNodes (r:3 w:3) - // Storage: Staking Bonded (r:1 w:0) - // Storage: VoterList ListBags (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `2252` + // Estimated: `22888` + // Minimum execution time: 74_781 nanoseconds. + Weight::from_parts(75_188_000, 22888) + .saturating_add(T::DbWeight::get().reads(8_u64)) + .saturating_add(T::DbWeight::get().writes(7_u64)) + } + /// Storage: Staking Ledger (r:1 w:1) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:1 w:0) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) + /// Storage: Staking MinNominatorBond (r:1 w:0) + /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: Staking CurrentEra (r:1 w:0) + /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:3 w:3) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:1 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:2 w:2) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) fn unbond() -> Weight { - // Minimum execution time: 102_031 nanoseconds. - Weight::from_ref_time(102_842_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) - // Storage: Balances Locks (r:1 w:1) - // Storage: System Account (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `2457` + // Estimated: `29534` + // Minimum execution time: 81_299 nanoseconds. + Weight::from_parts(82_242_000, 29534) + .saturating_add(T::DbWeight::get().reads(12_u64)) + .saturating_add(T::DbWeight::get().writes(8_u64)) + } + /// Storage: Staking Ledger (r:1 w:1) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking CurrentEra (r:1 w:0) + /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { - // Minimum execution time: 46_569 nanoseconds. - Weight::from_ref_time(48_034_493) - // Standard Error: 654 - .saturating_add(Weight::from_ref_time(63_628).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) - // 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:1) - // Storage: Staking CounterForNominators (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) - // Storage: Staking SpanSlash (r:0 w:2) + // Proof Size summary in bytes: + // Measured: `1085` + // Estimated: `10442` + // Minimum execution time: 31_479 nanoseconds. + Weight::from_parts(32_410_035, 10442) + // Standard Error: 313 + .saturating_add(Weight::from_ref_time(9_090).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: Staking Ledger (r:1 w:1) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking CurrentEra (r:1 w:0) + /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:1 w:1) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking SlashingSpans (r:1 w:1) + /// Proof Skipped: Staking SlashingSpans (max_values: None, max_size: None, mode: Measured) + /// Storage: Staking Validators (r:1 w:0) + /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:1 w:1) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) + /// Storage: Staking CounterForNominators (r:1 w:1) + /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:2 w:2) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:1 w:1) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: VoterList CounterForListNodes (r:1 w:1) + /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Staking Payee (r:0 w:1) + /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Staking SpanSlash (r:0 w:100) + /// Proof: Staking SpanSlash (max_values: None, max_size: Some(76), added: 2551, mode: MaxEncodedLen) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_kill(s: u32, ) -> Weight { - // Minimum execution time: 90_154 nanoseconds. - Weight::from_ref_time(95_725_631) - // Standard Error: 2_491 - .saturating_add(Weight::from_ref_time(1_110_795).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(13)) - .saturating_add(T::DbWeight::get().writes(12)) + // Proof Size summary in bytes: + // Measured: `2486 + s * (4 ±0)` + // Estimated: `32303 + s * (4 ±0)` + // Minimum execution time: 71_968 nanoseconds. + Weight::from_parts(76_631_804, 32303) + // Standard Error: 1_613 + .saturating_add(Weight::from_ref_time(1_058_968).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(13_u64)) + .saturating_add(T::DbWeight::get().writes(12_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) + .saturating_add(Weight::from_proof_size(4).saturating_mul(s.into())) } - // 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:0) - // Storage: Staking Bonded (r:1 w:0) - // 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) + /// Storage: Staking Ledger (r:1 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking MinValidatorBond (r:1 w:0) + /// Proof: Staking MinValidatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: Staking MinCommission (r:1 w:0) + /// Proof: Staking MinCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking Validators (r:1 w:1) + /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) + /// Storage: Staking MaxValidatorsCount (r:1 w:0) + /// Proof: Staking MaxValidatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:1 w:0) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:1 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:1 w:1) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:1 w:1) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: VoterList CounterForListNodes (r:1 w:1) + /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking CounterForValidators (r:1 w:1) + /// Proof: Staking CounterForValidators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn validate() -> Weight { - // Minimum execution time: 67_978 nanoseconds. - Weight::from_ref_time(69_153_000) - .saturating_add(T::DbWeight::get().reads(11)) - .saturating_add(T::DbWeight::get().writes(5)) + // Proof Size summary in bytes: + // Measured: `1446` + // Estimated: `19359` + // Minimum execution time: 51_963 nanoseconds. + Weight::from_parts(52_418_000, 19359) + .saturating_add(T::DbWeight::get().reads(11_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) } - // Storage: Staking Ledger (r:1 w:0) - // Storage: Staking Nominators (r:1 w:1) + /// Storage: Staking Ledger (r:1 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:128 w:128) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) /// The range of component `k` is `[1, 128]`. fn kick(k: u32, ) -> Weight { - // Minimum execution time: 45_328 nanoseconds. - Weight::from_ref_time(47_719_103) - // Standard Error: 14_458 - .saturating_add(Weight::from_ref_time(6_999_252).saturating_mul(k.into())) - .saturating_add(T::DbWeight::get().reads(1)) + // Proof Size summary in bytes: + // Measured: `1292 + k * (601 ±0)` + // Estimated: `3566 + k * (3033 ±0)` + // Minimum execution time: 25_685 nanoseconds. + Weight::from_parts(25_290_286, 3566) + // Standard Error: 5_164 + .saturating_add(Weight::from_ref_time(6_445_608).saturating_mul(k.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(k.into()))) + .saturating_add(Weight::from_proof_size(3033).saturating_mul(k.into())) } - // 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: 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) + /// Storage: Staking Ledger (r:1 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking MinNominatorBond (r:1 w:0) + /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:1 w:1) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) + /// Storage: Staking MaxNominatorsCount (r:1 w:0) + /// Proof: Staking MaxNominatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking Validators (r:17 w:0) + /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) + /// Storage: Staking CurrentEra (r:1 w:0) + /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:1 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:2 w:2) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:1 w:1) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: VoterList CounterForListNodes (r:1 w:1) + /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking CounterForNominators (r:1 w:1) + /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { - // Minimum execution time: 74_650 nanoseconds. - Weight::from_ref_time(74_350_075) - // Standard Error: 10_527 - .saturating_add(Weight::from_ref_time(2_878_737).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(12)) + // Proof Size summary in bytes: + // Measured: `1984 + n * (105 ±0)` + // Estimated: `21988 + n * (2520 ±0)` + // Minimum execution time: 59_542 nanoseconds. + Weight::from_parts(57_558_678, 21988) + // Standard Error: 10_364 + .saturating_add(Weight::from_ref_time(2_759_713).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(6)) - } - // 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: VoterList ListNodes (r:2 w:2) - // Storage: VoterList ListBags (r:1 w:1) - // Storage: VoterList CounterForListNodes (r:1 w:1) + .saturating_add(T::DbWeight::get().writes(6_u64)) + .saturating_add(Weight::from_proof_size(2520).saturating_mul(n.into())) + } + /// Storage: Staking Ledger (r:1 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking Validators (r:1 w:0) + /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:1 w:1) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) + /// Storage: Staking CounterForNominators (r:1 w:1) + /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:2 w:2) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:1 w:1) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: VoterList CounterForListNodes (r:1 w:1) + /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn chill() -> Weight { - // Minimum execution time: 67_790 nanoseconds. - Weight::from_ref_time(68_738_000) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(6)) + // Proof Size summary in bytes: + // Measured: `1876` + // Estimated: `17932` + // Minimum execution time: 52_132 nanoseconds. + Weight::from_parts(52_648_000, 17932) + .saturating_add(T::DbWeight::get().reads(8_u64)) + .saturating_add(T::DbWeight::get().writes(6_u64)) } - // Storage: Staking Ledger (r:1 w:0) - // Storage: Staking Payee (r:0 w:1) + /// Storage: Staking Ledger (r:1 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking Payee (r:0 w:1) + /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) fn set_payee() -> Weight { - // Minimum execution time: 19_237 nanoseconds. - Weight::from_ref_time(19_534_000) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) + // Proof Size summary in bytes: + // Measured: `840` + // Estimated: `3566` + // Minimum execution time: 13_399 nanoseconds. + Weight::from_parts(13_567_000, 3566) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - // Storage: Staking Bonded (r:1 w:1) - // Storage: Staking Ledger (r:2 w:2) + /// Storage: Staking Bonded (r:1 w:1) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:2 w:2) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) fn set_controller() -> Weight { - // Minimum execution time: 27_288 nanoseconds. - Weight::from_ref_time(27_667_000) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) + // Proof Size summary in bytes: + // Measured: `939` + // Estimated: `9679` + // Minimum execution time: 20_425 nanoseconds. + Weight::from_parts(20_713_000, 9679) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) } - // Storage: Staking ValidatorCount (r:0 w:1) + /// Storage: Staking ValidatorCount (r:0 w:1) + /// Proof: Staking ValidatorCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn set_validator_count() -> Weight { - // Minimum execution time: 5_155 nanoseconds. - Weight::from_ref_time(5_464_000) - .saturating_add(T::DbWeight::get().writes(1)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_069 nanoseconds. + Weight::from_ref_time(3_176_000) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - // Storage: Staking ForceEra (r:0 w:1) + /// Storage: Staking ForceEra (r:0 w:1) + /// Proof: Staking ForceEra (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) fn force_no_eras() -> Weight { - // Minimum execution time: 5_405 nanoseconds. - Weight::from_ref_time(5_670_000) - .saturating_add(T::DbWeight::get().writes(1)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 11_386 nanoseconds. + Weight::from_ref_time(11_672_000) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - // Storage: Staking ForceEra (r:0 w:1) + /// Storage: Staking ForceEra (r:0 w:1) + /// Proof: Staking ForceEra (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) fn force_new_era() -> Weight { - // Minimum execution time: 5_459 nanoseconds. - Weight::from_ref_time(5_616_000) - .saturating_add(T::DbWeight::get().writes(1)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 11_591 nanoseconds. + Weight::from_ref_time(11_799_000) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - // Storage: Staking ForceEra (r:0 w:1) + /// Storage: Staking ForceEra (r:0 w:1) + /// Proof: Staking ForceEra (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) fn force_new_era_always() -> Weight { - // Minimum execution time: 5_476 nanoseconds. - Weight::from_ref_time(5_692_000) - .saturating_add(T::DbWeight::get().writes(1)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 11_553 nanoseconds. + Weight::from_ref_time(11_871_000) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - // Storage: Staking Invulnerables (r:0 w:1) + /// Storage: Staking Invulnerables (r:0 w:1) + /// Proof Skipped: Staking Invulnerables (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `v` is `[0, 1000]`. fn set_invulnerables(v: u32, ) -> Weight { - // Minimum execution time: 5_544 nanoseconds. - Weight::from_ref_time(6_513_190) - // Standard Error: 76 - .saturating_add(Weight::from_ref_time(9_975).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) - // Storage: Staking Validators (r:1 w:0) - // Storage: Staking Nominators (r:1 w:1) - // Storage: Staking CounterForNominators (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) - // Storage: Staking Payee (r:0 w:1) - // Storage: Staking SpanSlash (r:0 w:2) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_292 nanoseconds. + Weight::from_ref_time(3_754_352) + // Standard Error: 40 + .saturating_add(Weight::from_ref_time(9_838).saturating_mul(v.into())) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Staking Bonded (r:1 w:1) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking SlashingSpans (r:1 w:1) + /// Proof Skipped: Staking SlashingSpans (max_values: None, max_size: None, mode: Measured) + /// Storage: Staking Validators (r:1 w:0) + /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:1 w:1) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) + /// Storage: Staking CounterForNominators (r:1 w:1) + /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:2 w:2) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:1 w:1) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: VoterList CounterForListNodes (r:1 w:1) + /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:0 w:1) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking Payee (r:0 w:1) + /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Staking SpanSlash (r:0 w:100) + /// Proof: Staking SpanSlash (max_values: None, max_size: Some(76), added: 2551, mode: MaxEncodedLen) /// The range of component `s` is `[0, 100]`. fn force_unstake(s: u32, ) -> Weight { - // Minimum execution time: 82_414 nanoseconds. - Weight::from_ref_time(88_511_246) - // Standard Error: 2_622 - .saturating_add(Weight::from_ref_time(1_131_814).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(11)) - .saturating_add(T::DbWeight::get().writes(12)) + // Proof Size summary in bytes: + // Measured: `2178 + s * (4 ±0)` + // Estimated: `27930 + s * (4 ±0)` + // Minimum execution time: 65_307 nanoseconds. + Weight::from_parts(70_227_980, 27930) + // Standard Error: 2_113 + .saturating_add(Weight::from_ref_time(1_059_856).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(11_u64)) + .saturating_add(T::DbWeight::get().writes(12_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) + .saturating_add(Weight::from_proof_size(4).saturating_mul(s.into())) } - // Storage: Staking UnappliedSlashes (r:1 w:1) + /// Storage: Staking UnappliedSlashes (r:1 w:1) + /// Proof Skipped: Staking UnappliedSlashes (max_values: None, max_size: None, mode: Measured) /// The range of component `s` is `[1, 1000]`. fn cancel_deferred_slash(s: u32, ) -> Weight { - // Minimum execution time: 94_197 nanoseconds. - Weight::from_ref_time(903_418_326) - // Standard Error: 59_354 - .saturating_add(Weight::from_ref_time(4_948_354).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) - // 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:1 w:0) - // Storage: System Account (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `66671` + // Estimated: `69146` + // Minimum execution time: 89_123 nanoseconds. + Weight::from_parts(890_989_741, 69146) + // Standard Error: 58_282 + .saturating_add(Weight::from_ref_time(4_920_413).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Staking CurrentEra (r:1 w:0) + /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking ErasValidatorReward (r:1 w:0) + /// Proof: Staking ErasValidatorReward (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:257 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:1 w:1) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking ErasStakersClipped (r:1 w:0) + /// Proof Skipped: Staking ErasStakersClipped (max_values: None, max_size: None, mode: Measured) + /// Storage: Staking ErasRewardPoints (r:1 w:0) + /// Proof Skipped: Staking ErasRewardPoints (max_values: None, max_size: None, mode: Measured) + /// Storage: Staking ErasValidatorPrefs (r:1 w:0) + /// Proof: Staking ErasValidatorPrefs (max_values: None, max_size: Some(57), added: 2532, mode: MaxEncodedLen) + /// Storage: Staking Payee (r:257 w:0) + /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: System Account (r:257 w:257) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `n` is `[0, 256]`. fn payout_stakers_dead_controller(n: u32, ) -> Weight { - // Minimum execution time: 133_065 nanoseconds. - Weight::from_ref_time(197_555_906) - // Standard Error: 19_561 - .saturating_add(Weight::from_ref_time(22_683_426).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(9)) + // Proof Size summary in bytes: + // Measured: `20345 + n * (143 ±0)` + // Estimated: `54756 + n * (8024 ±1)` + // Minimum execution time: 73_652 nanoseconds. + Weight::from_parts(127_839_483, 54756) + // Standard Error: 14_195 + .saturating_add(Weight::from_ref_time(21_932_079).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(9_u64)) .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(2_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_proof_size(8024).saturating_mul(n.into())) } - // Storage: Staking CurrentEra (r:1 w:0) - // Storage: Staking ErasValidatorReward (r:1 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:1 w:0) - // Storage: System Account (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) + /// Storage: Staking CurrentEra (r:1 w:0) + /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking ErasValidatorReward (r:1 w:0) + /// Proof: Staking ErasValidatorReward (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:257 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:257 w:257) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking ErasStakersClipped (r:1 w:0) + /// Proof Skipped: Staking ErasStakersClipped (max_values: None, max_size: None, mode: Measured) + /// Storage: Staking ErasRewardPoints (r:1 w:0) + /// Proof Skipped: Staking ErasRewardPoints (max_values: None, max_size: None, mode: Measured) + /// Storage: Staking ErasValidatorPrefs (r:1 w:0) + /// Proof: Staking ErasValidatorPrefs (max_values: None, max_size: Some(57), added: 2532, mode: MaxEncodedLen) + /// Storage: Staking Payee (r:257 w:0) + /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: System Account (r:257 w:257) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:257 w:257) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) /// The range of component `n` is `[0, 256]`. fn payout_stakers_alive_staked(n: u32, ) -> Weight { - // Minimum execution time: 164_719 nanoseconds. - Weight::from_ref_time(226_304_276) - // Standard Error: 31_675 - .saturating_add(Weight::from_ref_time(32_622_427).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(10)) + // Proof Size summary in bytes: + // Measured: `35099 + n * (465 ±0)` + // Estimated: `83594 + n * (16026 ±0)` + // Minimum execution time: 94_560 nanoseconds. + Weight::from_parts(154_033_219, 83594) + // Standard Error: 26_663 + .saturating_add(Weight::from_ref_time(31_269_223).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(10_u64)) .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_add(T::DbWeight::get().writes((3_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_proof_size(16026).saturating_mul(n.into())) } - // Storage: Staking Ledger (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) - // Storage: System Account (r:1 w:1) - // Storage: VoterList ListNodes (r:3 w:3) - // Storage: Staking Bonded (r:1 w:0) - // Storage: VoterList ListBags (r:2 w:2) + /// Storage: Staking Ledger (r:1 w:1) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:3 w:3) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:1 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:2 w:2) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) /// The range of component `l` is `[1, 32]`. fn rebond(l: u32, ) -> Weight { - // Minimum execution time: 95_631 nanoseconds. - Weight::from_ref_time(96_861_556) - // Standard Error: 2_114 - .saturating_add(Weight::from_ref_time(37_543).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) - // 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) - // Storage: Staking CounterForNominators (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) + // Proof Size summary in bytes: + // Measured: `2253 + l * (7 ±0)` + // Estimated: `25491` + // Minimum execution time: 74_764 nanoseconds. + Weight::from_parts(75_814_067, 25491) + // Standard Error: 1_217 + .saturating_add(Weight::from_ref_time(64_725).saturating_mul(l.into())) + .saturating_add(T::DbWeight::get().reads(9_u64)) + .saturating_add(T::DbWeight::get().writes(8_u64)) + } + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:1 w:1) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:1 w:1) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking SlashingSpans (r:1 w:1) + /// Proof Skipped: Staking SlashingSpans (max_values: None, max_size: None, mode: Measured) + /// Storage: Staking Validators (r:1 w:0) + /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:1 w:1) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) + /// Storage: Staking CounterForNominators (r:1 w:1) + /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:2 w:2) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:1 w:1) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: VoterList CounterForListNodes (r:1 w:1) + /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Staking Payee (r:0 w:1) + /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Staking SpanSlash (r:0 w:100) + /// Proof: Staking SpanSlash (max_values: None, max_size: Some(76), added: 2551, mode: MaxEncodedLen) /// The range of component `s` is `[1, 100]`. fn reap_stash(s: u32, ) -> Weight { - // Minimum execution time: 95_251 nanoseconds. - Weight::from_ref_time(97_818_954) - // Standard Error: 2_356 - .saturating_add(Weight::from_ref_time(1_104_695).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(12)) - .saturating_add(T::DbWeight::get().writes(12)) + // Proof Size summary in bytes: + // Measured: `2486 + s * (4 ±0)` + // Estimated: `31810 + s * (4 ±0)` + // Minimum execution time: 77_611 nanoseconds. + Weight::from_parts(79_760_034, 31810) + // Standard Error: 1_597 + .saturating_add(Weight::from_ref_time(1_039_268).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(12_u64)) + .saturating_add(T::DbWeight::get().writes(12_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) + .saturating_add(Weight::from_proof_size(4).saturating_mul(s.into())) } - // Storage: VoterList CounterForListNodes (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) - // Storage: Staking Validators (r:2 w:0) - // Storage: Staking Bonded (r:101 w:0) - // Storage: Staking Ledger (r:101 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) - // 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) - // Storage: Staking MinimumActiveStake (r:0 w:1) + /// Storage: VoterList CounterForListNodes (r:1 w:0) + /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:200 w:0) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:110 w:0) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:110 w:0) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) + /// Storage: Staking Validators (r:11 w:0) + /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:110 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:110 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking CounterForValidators (r:1 w:0) + /// Proof: Staking CounterForValidators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking ValidatorCount (r:1 w:0) + /// Proof: Staking ValidatorCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking MinimumValidatorCount (r:1 w:0) + /// Proof: Staking MinimumValidatorCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking CurrentEra (r:1 w:1) + /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking ErasStakersClipped (r:0 w:10) + /// Proof Skipped: Staking ErasStakersClipped (max_values: None, max_size: None, mode: Measured) + /// Storage: Staking ErasValidatorPrefs (r:0 w:10) + /// Proof: Staking ErasValidatorPrefs (max_values: None, max_size: Some(57), added: 2532, mode: MaxEncodedLen) + /// Storage: Staking ErasStakers (r:0 w:10) + /// Proof Skipped: Staking ErasStakers (max_values: None, max_size: None, mode: Measured) + /// Storage: Staking ErasTotalStake (r:0 w:1) + /// Proof: Staking ErasTotalStake (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) + /// Storage: Staking ErasStartSessionIndex (r:0 w:1) + /// Proof: Staking ErasStartSessionIndex (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) + /// Storage: Staking MinimumActiveStake (r:0 w:1) + /// Proof: Staking MinimumActiveStake (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) /// 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: 512_923 nanoseconds. - Weight::from_ref_time(514_740_000) - // Standard Error: 1_790_238 - .saturating_add(Weight::from_ref_time(59_320_539).saturating_mul(v.into())) - // Standard Error: 178_387 - .saturating_add(Weight::from_ref_time(13_902_705).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(206)) + // Proof Size summary in bytes: + // Measured: `0 + v * (3662 ±0) + n * (816 ±0)` + // Estimated: `528203 + v * (16743 ±0) + n * (12947 ±0)` + // Minimum execution time: 489_824 nanoseconds. + Weight::from_parts(491_687_000, 528203) + // Standard Error: 1_787_577 + .saturating_add(Weight::from_ref_time(58_719_498).saturating_mul(v.into())) + // Standard Error: 178_122 + .saturating_add(Weight::from_ref_time(13_273_555).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(206_u64)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(v.into()))) + .saturating_add(Weight::from_proof_size(16743).saturating_mul(v.into())) + .saturating_add(Weight::from_proof_size(12947).saturating_mul(n.into())) } - // Storage: VoterList CounterForListNodes (r:1 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) - // Storage: Staking Ledger (r:1500 w:0) - // Storage: Staking MinimumActiveStake (r:0 w:1) + /// Storage: VoterList CounterForListNodes (r:1 w:0) + /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:200 w:0) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:2000 w:0) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:2000 w:0) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) + /// Storage: Staking Validators (r:1000 w:0) + /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:2000 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:2000 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking MinimumActiveStake (r:0 w:1) + /// Proof: Staking MinimumActiveStake (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) /// The range of component `v` is `[500, 1000]`. /// The range of component `n` is `[500, 1000]`. fn get_npos_voters(v: u32, n: u32, ) -> Weight { - // Minimum execution time: 24_913_316 nanoseconds. - Weight::from_ref_time(25_053_596_000) - // Standard Error: 324_610 - .saturating_add(Weight::from_ref_time(3_454_859).saturating_mul(v.into())) - // Standard Error: 324_610 - .saturating_add(Weight::from_ref_time(3_020_267).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(201)) + // Proof Size summary in bytes: + // Measured: `3167 + v * (459 ±0) + n * (1007 ±0)` + // Estimated: `511899 + v * (14295 ±0) + n * (11775 ±0)` + // Minimum execution time: 23_373_467 nanoseconds. + Weight::from_parts(23_497_257_000, 511899) + // Standard Error: 299_205 + .saturating_add(Weight::from_ref_time(3_434_000).saturating_mul(v.into())) + // Standard Error: 299_205 + .saturating_add(Weight::from_ref_time(2_568_954).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(201_u64)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(1)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + .saturating_add(Weight::from_proof_size(14295).saturating_mul(v.into())) + .saturating_add(Weight::from_proof_size(11775).saturating_mul(n.into())) } - // Storage: Staking CounterForValidators (r:1 w:0) - // Storage: Staking Validators (r:501 w:0) + /// Storage: Staking CounterForValidators (r:1 w:0) + /// Proof: Staking CounterForValidators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking Validators (r:1001 w:0) + /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) /// The range of component `v` is `[500, 1000]`. fn get_npos_targets(v: u32, ) -> Weight { - // Minimum execution time: 4_916_401 nanoseconds. - Weight::from_ref_time(81_160_966) - // Standard Error: 23_829 - .saturating_add(Weight::from_ref_time(9_883_413).saturating_mul(v.into())) - .saturating_add(T::DbWeight::get().reads(2)) + // Proof Size summary in bytes: + // Measured: `983 + v * (50 ±0)` + // Estimated: `3019 + v * (2520 ±0)` + // Minimum execution time: 3_882_120 nanoseconds. + Weight::from_parts(3_951_993_000, 3019) + // Standard Error: 46_729 + .saturating_add(Weight::from_ref_time(2_856_043).saturating_mul(v.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) + .saturating_add(Weight::from_proof_size(2520).saturating_mul(v.into())) } - // 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) + /// Storage: Staking MinCommission (r:0 w:1) + /// Proof: Staking MinCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking MinValidatorBond (r:0 w:1) + /// Proof: Staking MinValidatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: Staking MaxValidatorsCount (r:0 w:1) + /// Proof: Staking MaxValidatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking ChillThreshold (r:0 w:1) + /// Proof: Staking ChillThreshold (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// Storage: Staking MaxNominatorsCount (r:0 w:1) + /// Proof: Staking MaxNominatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking MinNominatorBond (r:0 w:1) + /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) fn set_staking_configs_all_set() -> Weight { - // Minimum execution time: 10_937 nanoseconds. - Weight::from_ref_time(11_324_000) - .saturating_add(T::DbWeight::get().writes(6)) - } - // 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) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 8_427 nanoseconds. + Weight::from_ref_time(8_794_000) + .saturating_add(T::DbWeight::get().writes(6_u64)) + } + /// Storage: Staking MinCommission (r:0 w:1) + /// Proof: Staking MinCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking MinValidatorBond (r:0 w:1) + /// Proof: Staking MinValidatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: Staking MaxValidatorsCount (r:0 w:1) + /// Proof: Staking MaxValidatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking ChillThreshold (r:0 w:1) + /// Proof: Staking ChillThreshold (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// Storage: Staking MaxNominatorsCount (r:0 w:1) + /// Proof: Staking MaxNominatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking MinNominatorBond (r:0 w:1) + /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) fn set_staking_configs_all_remove() -> Weight { - // Minimum execution time: 9_424 nanoseconds. - Weight::from_ref_time(10_021_000) - .saturating_add(T::DbWeight::get().writes(6)) - } - // Storage: Staking Ledger (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) - // Storage: Staking Validators (r:1 w:0) - // Storage: VoterList ListNodes (r:2 w:2) - // Storage: VoterList ListBags (r:1 w:1) - // Storage: VoterList CounterForListNodes (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 7_620 nanoseconds. + Weight::from_ref_time(7_901_000) + .saturating_add(T::DbWeight::get().writes(6_u64)) + } + /// Storage: Staking Ledger (r:1 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:1 w:1) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) + /// Storage: Staking ChillThreshold (r:1 w:0) + /// Proof: Staking ChillThreshold (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// Storage: Staking MaxNominatorsCount (r:1 w:0) + /// Proof: Staking MaxNominatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking CounterForNominators (r:1 w:1) + /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking MinNominatorBond (r:1 w:0) + /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: Staking Validators (r:1 w:0) + /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:2 w:2) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:1 w:1) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: VoterList CounterForListNodes (r:1 w:1) + /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn chill_other() -> Weight { - // Minimum execution time: 84_495 nanoseconds. - Weight::from_ref_time(85_559_000) - .saturating_add(T::DbWeight::get().reads(11)) - .saturating_add(T::DbWeight::get().writes(6)) + // Proof Size summary in bytes: + // Measured: `2031` + // Estimated: `19438` + // Minimum execution time: 66_188 nanoseconds. + Weight::from_parts(66_767_000, 19438) + .saturating_add(T::DbWeight::get().reads(11_u64)) + .saturating_add(T::DbWeight::get().writes(6_u64)) } - // Storage: Staking MinCommission (r:1 w:0) - // Storage: Staking Validators (r:1 w:1) + /// Storage: Staking MinCommission (r:1 w:0) + /// Proof: Staking MinCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking Validators (r:1 w:1) + /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) fn force_apply_min_commission() -> Weight { - // Minimum execution time: 20_385 nanoseconds. - Weight::from_ref_time(20_824_000) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) + // Proof Size summary in bytes: + // Measured: `694` + // Estimated: `3019` + // Minimum execution time: 14_703 nanoseconds. + Weight::from_parts(15_031_000, 3019) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - // Storage: Staking MinCommission (r:0 w:1) + /// Storage: Staking MinCommission (r:0 w:1) + /// Proof: Staking MinCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn set_min_commission() -> Weight { - // Minimum execution time: 6_995 nanoseconds. - Weight::from_ref_time(7_213_000) - .saturating_add(T::DbWeight::get().writes(1)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 4_518 nanoseconds. + Weight::from_ref_time(4_656_000) + .saturating_add(T::DbWeight::get().writes(1_u64)) } } // For backwards compatibility and tests 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: Balances Locks (r:1 w:1) - // Storage: Staking Payee (r:0 w:1) + /// Storage: Staking Bonded (r:1 w:1) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:1 w:1) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking CurrentEra (r:1 w:0) + /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Staking Payee (r:0 w:1) + /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) fn bond() -> Weight { - // Minimum execution time: 54_884 nanoseconds. - Weight::from_ref_time(55_487_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) - // Storage: Balances Locks (r:1 w:1) - // Storage: VoterList ListNodes (r:3 w:3) - // Storage: VoterList ListBags (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `1079` + // Estimated: `10386` + // Minimum execution time: 40_015 nanoseconds. + Weight::from_parts(40_601_000, 10386) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + } + /// Storage: Staking Bonded (r:1 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:1 w:1) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:3 w:3) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:2 w:2) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) fn bond_extra() -> Weight { - // Minimum execution time: 95_115 nanoseconds. - Weight::from_ref_time(96_213_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) - // 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: VoterList ListNodes (r:3 w:3) - // Storage: Staking Bonded (r:1 w:0) - // Storage: VoterList ListBags (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `2252` + // Estimated: `22888` + // Minimum execution time: 74_781 nanoseconds. + Weight::from_parts(75_188_000, 22888) + .saturating_add(RocksDbWeight::get().reads(8_u64)) + .saturating_add(RocksDbWeight::get().writes(7_u64)) + } + /// Storage: Staking Ledger (r:1 w:1) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:1 w:0) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) + /// Storage: Staking MinNominatorBond (r:1 w:0) + /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: Staking CurrentEra (r:1 w:0) + /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:3 w:3) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:1 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:2 w:2) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) fn unbond() -> Weight { - // Minimum execution time: 102_031 nanoseconds. - Weight::from_ref_time(102_842_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) - // Storage: Balances Locks (r:1 w:1) - // Storage: System Account (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `2457` + // Estimated: `29534` + // Minimum execution time: 81_299 nanoseconds. + Weight::from_parts(82_242_000, 29534) + .saturating_add(RocksDbWeight::get().reads(12_u64)) + .saturating_add(RocksDbWeight::get().writes(8_u64)) + } + /// Storage: Staking Ledger (r:1 w:1) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking CurrentEra (r:1 w:0) + /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { - // Minimum execution time: 46_569 nanoseconds. - Weight::from_ref_time(48_034_493) - // Standard Error: 654 - .saturating_add(Weight::from_ref_time(63_628).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) - // 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:1) - // Storage: Staking CounterForNominators (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) - // Storage: Staking SpanSlash (r:0 w:2) + // Proof Size summary in bytes: + // Measured: `1085` + // Estimated: `10442` + // Minimum execution time: 31_479 nanoseconds. + Weight::from_parts(32_410_035, 10442) + // Standard Error: 313 + .saturating_add(Weight::from_ref_time(9_090).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: Staking Ledger (r:1 w:1) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking CurrentEra (r:1 w:0) + /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:1 w:1) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking SlashingSpans (r:1 w:1) + /// Proof Skipped: Staking SlashingSpans (max_values: None, max_size: None, mode: Measured) + /// Storage: Staking Validators (r:1 w:0) + /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:1 w:1) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) + /// Storage: Staking CounterForNominators (r:1 w:1) + /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:2 w:2) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:1 w:1) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: VoterList CounterForListNodes (r:1 w:1) + /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Staking Payee (r:0 w:1) + /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Staking SpanSlash (r:0 w:100) + /// Proof: Staking SpanSlash (max_values: None, max_size: Some(76), added: 2551, mode: MaxEncodedLen) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_kill(s: u32, ) -> Weight { - // Minimum execution time: 90_154 nanoseconds. - Weight::from_ref_time(95_725_631) - // Standard Error: 2_491 - .saturating_add(Weight::from_ref_time(1_110_795).saturating_mul(s.into())) - .saturating_add(RocksDbWeight::get().reads(13)) - .saturating_add(RocksDbWeight::get().writes(12)) + // Proof Size summary in bytes: + // Measured: `2486 + s * (4 ±0)` + // Estimated: `32303 + s * (4 ±0)` + // Minimum execution time: 71_968 nanoseconds. + Weight::from_parts(76_631_804, 32303) + // Standard Error: 1_613 + .saturating_add(Weight::from_ref_time(1_058_968).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(13_u64)) + .saturating_add(RocksDbWeight::get().writes(12_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) + .saturating_add(Weight::from_proof_size(4).saturating_mul(s.into())) } - // 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:0) - // Storage: Staking Bonded (r:1 w:0) - // 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) + /// Storage: Staking Ledger (r:1 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking MinValidatorBond (r:1 w:0) + /// Proof: Staking MinValidatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: Staking MinCommission (r:1 w:0) + /// Proof: Staking MinCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking Validators (r:1 w:1) + /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) + /// Storage: Staking MaxValidatorsCount (r:1 w:0) + /// Proof: Staking MaxValidatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:1 w:0) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:1 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:1 w:1) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:1 w:1) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: VoterList CounterForListNodes (r:1 w:1) + /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking CounterForValidators (r:1 w:1) + /// Proof: Staking CounterForValidators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn validate() -> Weight { - // Minimum execution time: 67_978 nanoseconds. - Weight::from_ref_time(69_153_000) - .saturating_add(RocksDbWeight::get().reads(11)) - .saturating_add(RocksDbWeight::get().writes(5)) + // Proof Size summary in bytes: + // Measured: `1446` + // Estimated: `19359` + // Minimum execution time: 51_963 nanoseconds. + Weight::from_parts(52_418_000, 19359) + .saturating_add(RocksDbWeight::get().reads(11_u64)) + .saturating_add(RocksDbWeight::get().writes(5_u64)) } - // Storage: Staking Ledger (r:1 w:0) - // Storage: Staking Nominators (r:1 w:1) + /// Storage: Staking Ledger (r:1 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:128 w:128) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) /// The range of component `k` is `[1, 128]`. fn kick(k: u32, ) -> Weight { - // Minimum execution time: 45_328 nanoseconds. - Weight::from_ref_time(47_719_103) - // Standard Error: 14_458 - .saturating_add(Weight::from_ref_time(6_999_252).saturating_mul(k.into())) - .saturating_add(RocksDbWeight::get().reads(1)) + // Proof Size summary in bytes: + // Measured: `1292 + k * (601 ±0)` + // Estimated: `3566 + k * (3033 ±0)` + // Minimum execution time: 25_685 nanoseconds. + Weight::from_parts(25_290_286, 3566) + // Standard Error: 5_164 + .saturating_add(Weight::from_ref_time(6_445_608).saturating_mul(k.into())) + .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(k.into()))) + .saturating_add(Weight::from_proof_size(3033).saturating_mul(k.into())) } - // 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: 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) + /// Storage: Staking Ledger (r:1 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking MinNominatorBond (r:1 w:0) + /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:1 w:1) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) + /// Storage: Staking MaxNominatorsCount (r:1 w:0) + /// Proof: Staking MaxNominatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking Validators (r:17 w:0) + /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) + /// Storage: Staking CurrentEra (r:1 w:0) + /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:1 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:2 w:2) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:1 w:1) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: VoterList CounterForListNodes (r:1 w:1) + /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking CounterForNominators (r:1 w:1) + /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { - // Minimum execution time: 74_650 nanoseconds. - Weight::from_ref_time(74_350_075) - // Standard Error: 10_527 - .saturating_add(Weight::from_ref_time(2_878_737).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(12)) + // Proof Size summary in bytes: + // Measured: `1984 + n * (105 ±0)` + // Estimated: `21988 + n * (2520 ±0)` + // Minimum execution time: 59_542 nanoseconds. + Weight::from_parts(57_558_678, 21988) + // Standard Error: 10_364 + .saturating_add(Weight::from_ref_time(2_759_713).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) - .saturating_add(RocksDbWeight::get().writes(6)) - } - // 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: VoterList ListNodes (r:2 w:2) - // Storage: VoterList ListBags (r:1 w:1) - // Storage: VoterList CounterForListNodes (r:1 w:1) + .saturating_add(RocksDbWeight::get().writes(6_u64)) + .saturating_add(Weight::from_proof_size(2520).saturating_mul(n.into())) + } + /// Storage: Staking Ledger (r:1 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking Validators (r:1 w:0) + /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:1 w:1) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) + /// Storage: Staking CounterForNominators (r:1 w:1) + /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:2 w:2) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:1 w:1) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: VoterList CounterForListNodes (r:1 w:1) + /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn chill() -> Weight { - // Minimum execution time: 67_790 nanoseconds. - Weight::from_ref_time(68_738_000) - .saturating_add(RocksDbWeight::get().reads(8)) - .saturating_add(RocksDbWeight::get().writes(6)) + // Proof Size summary in bytes: + // Measured: `1876` + // Estimated: `17932` + // Minimum execution time: 52_132 nanoseconds. + Weight::from_parts(52_648_000, 17932) + .saturating_add(RocksDbWeight::get().reads(8_u64)) + .saturating_add(RocksDbWeight::get().writes(6_u64)) } - // Storage: Staking Ledger (r:1 w:0) - // Storage: Staking Payee (r:0 w:1) + /// Storage: Staking Ledger (r:1 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking Payee (r:0 w:1) + /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) fn set_payee() -> Weight { - // Minimum execution time: 19_237 nanoseconds. - Weight::from_ref_time(19_534_000) - .saturating_add(RocksDbWeight::get().reads(1)) - .saturating_add(RocksDbWeight::get().writes(1)) + // Proof Size summary in bytes: + // Measured: `840` + // Estimated: `3566` + // Minimum execution time: 13_399 nanoseconds. + Weight::from_parts(13_567_000, 3566) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - // Storage: Staking Bonded (r:1 w:1) - // Storage: Staking Ledger (r:2 w:2) + /// Storage: Staking Bonded (r:1 w:1) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:2 w:2) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) fn set_controller() -> Weight { - // Minimum execution time: 27_288 nanoseconds. - Weight::from_ref_time(27_667_000) - .saturating_add(RocksDbWeight::get().reads(3)) - .saturating_add(RocksDbWeight::get().writes(3)) + // Proof Size summary in bytes: + // Measured: `939` + // Estimated: `9679` + // Minimum execution time: 20_425 nanoseconds. + Weight::from_parts(20_713_000, 9679) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) } - // Storage: Staking ValidatorCount (r:0 w:1) + /// Storage: Staking ValidatorCount (r:0 w:1) + /// Proof: Staking ValidatorCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn set_validator_count() -> Weight { - // Minimum execution time: 5_155 nanoseconds. - Weight::from_ref_time(5_464_000) - .saturating_add(RocksDbWeight::get().writes(1)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_069 nanoseconds. + Weight::from_ref_time(3_176_000) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - // Storage: Staking ForceEra (r:0 w:1) + /// Storage: Staking ForceEra (r:0 w:1) + /// Proof: Staking ForceEra (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) fn force_no_eras() -> Weight { - // Minimum execution time: 5_405 nanoseconds. - Weight::from_ref_time(5_670_000) - .saturating_add(RocksDbWeight::get().writes(1)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 11_386 nanoseconds. + Weight::from_ref_time(11_672_000) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - // Storage: Staking ForceEra (r:0 w:1) + /// Storage: Staking ForceEra (r:0 w:1) + /// Proof: Staking ForceEra (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) fn force_new_era() -> Weight { - // Minimum execution time: 5_459 nanoseconds. - Weight::from_ref_time(5_616_000) - .saturating_add(RocksDbWeight::get().writes(1)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 11_591 nanoseconds. + Weight::from_ref_time(11_799_000) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - // Storage: Staking ForceEra (r:0 w:1) + /// Storage: Staking ForceEra (r:0 w:1) + /// Proof: Staking ForceEra (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) fn force_new_era_always() -> Weight { - // Minimum execution time: 5_476 nanoseconds. - Weight::from_ref_time(5_692_000) - .saturating_add(RocksDbWeight::get().writes(1)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 11_553 nanoseconds. + Weight::from_ref_time(11_871_000) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - // Storage: Staking Invulnerables (r:0 w:1) + /// Storage: Staking Invulnerables (r:0 w:1) + /// Proof Skipped: Staking Invulnerables (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `v` is `[0, 1000]`. fn set_invulnerables(v: u32, ) -> Weight { - // Minimum execution time: 5_544 nanoseconds. - Weight::from_ref_time(6_513_190) - // Standard Error: 76 - .saturating_add(Weight::from_ref_time(9_975).saturating_mul(v.into())) - .saturating_add(RocksDbWeight::get().writes(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:1) - // Storage: Staking CounterForNominators (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) - // Storage: Staking Payee (r:0 w:1) - // Storage: Staking SpanSlash (r:0 w:2) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_292 nanoseconds. + Weight::from_ref_time(3_754_352) + // Standard Error: 40 + .saturating_add(Weight::from_ref_time(9_838).saturating_mul(v.into())) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Staking Bonded (r:1 w:1) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking SlashingSpans (r:1 w:1) + /// Proof Skipped: Staking SlashingSpans (max_values: None, max_size: None, mode: Measured) + /// Storage: Staking Validators (r:1 w:0) + /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:1 w:1) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) + /// Storage: Staking CounterForNominators (r:1 w:1) + /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:2 w:2) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:1 w:1) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: VoterList CounterForListNodes (r:1 w:1) + /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:0 w:1) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking Payee (r:0 w:1) + /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Staking SpanSlash (r:0 w:100) + /// Proof: Staking SpanSlash (max_values: None, max_size: Some(76), added: 2551, mode: MaxEncodedLen) /// The range of component `s` is `[0, 100]`. fn force_unstake(s: u32, ) -> Weight { - // Minimum execution time: 82_414 nanoseconds. - Weight::from_ref_time(88_511_246) - // Standard Error: 2_622 - .saturating_add(Weight::from_ref_time(1_131_814).saturating_mul(s.into())) - .saturating_add(RocksDbWeight::get().reads(11)) - .saturating_add(RocksDbWeight::get().writes(12)) + // Proof Size summary in bytes: + // Measured: `2178 + s * (4 ±0)` + // Estimated: `27930 + s * (4 ±0)` + // Minimum execution time: 65_307 nanoseconds. + Weight::from_parts(70_227_980, 27930) + // Standard Error: 2_113 + .saturating_add(Weight::from_ref_time(1_059_856).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(11_u64)) + .saturating_add(RocksDbWeight::get().writes(12_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) + .saturating_add(Weight::from_proof_size(4).saturating_mul(s.into())) } - // Storage: Staking UnappliedSlashes (r:1 w:1) + /// Storage: Staking UnappliedSlashes (r:1 w:1) + /// Proof Skipped: Staking UnappliedSlashes (max_values: None, max_size: None, mode: Measured) /// The range of component `s` is `[1, 1000]`. fn cancel_deferred_slash(s: u32, ) -> Weight { - // Minimum execution time: 94_197 nanoseconds. - Weight::from_ref_time(903_418_326) - // Standard Error: 59_354 - .saturating_add(Weight::from_ref_time(4_948_354).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) - // 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:1 w:0) - // Storage: System Account (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `66671` + // Estimated: `69146` + // Minimum execution time: 89_123 nanoseconds. + Weight::from_parts(890_989_741, 69146) + // Standard Error: 58_282 + .saturating_add(Weight::from_ref_time(4_920_413).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Staking CurrentEra (r:1 w:0) + /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking ErasValidatorReward (r:1 w:0) + /// Proof: Staking ErasValidatorReward (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:257 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:1 w:1) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking ErasStakersClipped (r:1 w:0) + /// Proof Skipped: Staking ErasStakersClipped (max_values: None, max_size: None, mode: Measured) + /// Storage: Staking ErasRewardPoints (r:1 w:0) + /// Proof Skipped: Staking ErasRewardPoints (max_values: None, max_size: None, mode: Measured) + /// Storage: Staking ErasValidatorPrefs (r:1 w:0) + /// Proof: Staking ErasValidatorPrefs (max_values: None, max_size: Some(57), added: 2532, mode: MaxEncodedLen) + /// Storage: Staking Payee (r:257 w:0) + /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: System Account (r:257 w:257) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `n` is `[0, 256]`. fn payout_stakers_dead_controller(n: u32, ) -> Weight { - // Minimum execution time: 133_065 nanoseconds. - Weight::from_ref_time(197_555_906) - // Standard Error: 19_561 - .saturating_add(Weight::from_ref_time(22_683_426).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(9)) + // Proof Size summary in bytes: + // Measured: `20345 + n * (143 ±0)` + // Estimated: `54756 + n * (8024 ±1)` + // Minimum execution time: 73_652 nanoseconds. + Weight::from_parts(127_839_483, 54756) + // Standard Error: 14_195 + .saturating_add(Weight::from_ref_time(21_932_079).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(n.into()))) - .saturating_add(RocksDbWeight::get().writes(2)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_proof_size(8024).saturating_mul(n.into())) } - // Storage: Staking CurrentEra (r:1 w:0) - // Storage: Staking ErasValidatorReward (r:1 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:1 w:0) - // Storage: System Account (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) + /// Storage: Staking CurrentEra (r:1 w:0) + /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking ErasValidatorReward (r:1 w:0) + /// Proof: Staking ErasValidatorReward (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:257 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:257 w:257) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking ErasStakersClipped (r:1 w:0) + /// Proof Skipped: Staking ErasStakersClipped (max_values: None, max_size: None, mode: Measured) + /// Storage: Staking ErasRewardPoints (r:1 w:0) + /// Proof Skipped: Staking ErasRewardPoints (max_values: None, max_size: None, mode: Measured) + /// Storage: Staking ErasValidatorPrefs (r:1 w:0) + /// Proof: Staking ErasValidatorPrefs (max_values: None, max_size: Some(57), added: 2532, mode: MaxEncodedLen) + /// Storage: Staking Payee (r:257 w:0) + /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: System Account (r:257 w:257) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:257 w:257) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) /// The range of component `n` is `[0, 256]`. fn payout_stakers_alive_staked(n: u32, ) -> Weight { - // Minimum execution time: 164_719 nanoseconds. - Weight::from_ref_time(226_304_276) - // Standard Error: 31_675 - .saturating_add(Weight::from_ref_time(32_622_427).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(10)) + // Proof Size summary in bytes: + // Measured: `35099 + n * (465 ±0)` + // Estimated: `83594 + n * (16026 ±0)` + // Minimum execution time: 94_560 nanoseconds. + Weight::from_parts(154_033_219, 83594) + // Standard Error: 26_663 + .saturating_add(Weight::from_ref_time(31_269_223).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(10_u64)) .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_add(RocksDbWeight::get().writes((3_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_proof_size(16026).saturating_mul(n.into())) } - // Storage: Staking Ledger (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) - // Storage: System Account (r:1 w:1) - // Storage: VoterList ListNodes (r:3 w:3) - // Storage: Staking Bonded (r:1 w:0) - // Storage: VoterList ListBags (r:2 w:2) + /// Storage: Staking Ledger (r:1 w:1) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:3 w:3) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:1 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:2 w:2) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) /// The range of component `l` is `[1, 32]`. fn rebond(l: u32, ) -> Weight { - // Minimum execution time: 95_631 nanoseconds. - Weight::from_ref_time(96_861_556) - // Standard Error: 2_114 - .saturating_add(Weight::from_ref_time(37_543).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) - // 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) - // Storage: Staking CounterForNominators (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) + // Proof Size summary in bytes: + // Measured: `2253 + l * (7 ±0)` + // Estimated: `25491` + // Minimum execution time: 74_764 nanoseconds. + Weight::from_parts(75_814_067, 25491) + // Standard Error: 1_217 + .saturating_add(Weight::from_ref_time(64_725).saturating_mul(l.into())) + .saturating_add(RocksDbWeight::get().reads(9_u64)) + .saturating_add(RocksDbWeight::get().writes(8_u64)) + } + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:1 w:1) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:1 w:1) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking SlashingSpans (r:1 w:1) + /// Proof Skipped: Staking SlashingSpans (max_values: None, max_size: None, mode: Measured) + /// Storage: Staking Validators (r:1 w:0) + /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:1 w:1) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) + /// Storage: Staking CounterForNominators (r:1 w:1) + /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:2 w:2) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:1 w:1) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: VoterList CounterForListNodes (r:1 w:1) + /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Staking Payee (r:0 w:1) + /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Staking SpanSlash (r:0 w:100) + /// Proof: Staking SpanSlash (max_values: None, max_size: Some(76), added: 2551, mode: MaxEncodedLen) /// The range of component `s` is `[1, 100]`. fn reap_stash(s: u32, ) -> Weight { - // Minimum execution time: 95_251 nanoseconds. - Weight::from_ref_time(97_818_954) - // Standard Error: 2_356 - .saturating_add(Weight::from_ref_time(1_104_695).saturating_mul(s.into())) - .saturating_add(RocksDbWeight::get().reads(12)) - .saturating_add(RocksDbWeight::get().writes(12)) + // Proof Size summary in bytes: + // Measured: `2486 + s * (4 ±0)` + // Estimated: `31810 + s * (4 ±0)` + // Minimum execution time: 77_611 nanoseconds. + Weight::from_parts(79_760_034, 31810) + // Standard Error: 1_597 + .saturating_add(Weight::from_ref_time(1_039_268).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(12_u64)) + .saturating_add(RocksDbWeight::get().writes(12_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) + .saturating_add(Weight::from_proof_size(4).saturating_mul(s.into())) } - // Storage: VoterList CounterForListNodes (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) - // Storage: Staking Validators (r:2 w:0) - // Storage: Staking Bonded (r:101 w:0) - // Storage: Staking Ledger (r:101 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) - // 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) - // Storage: Staking MinimumActiveStake (r:0 w:1) + /// Storage: VoterList CounterForListNodes (r:1 w:0) + /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:200 w:0) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:110 w:0) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:110 w:0) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) + /// Storage: Staking Validators (r:11 w:0) + /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:110 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:110 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking CounterForValidators (r:1 w:0) + /// Proof: Staking CounterForValidators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking ValidatorCount (r:1 w:0) + /// Proof: Staking ValidatorCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking MinimumValidatorCount (r:1 w:0) + /// Proof: Staking MinimumValidatorCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking CurrentEra (r:1 w:1) + /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking ErasStakersClipped (r:0 w:10) + /// Proof Skipped: Staking ErasStakersClipped (max_values: None, max_size: None, mode: Measured) + /// Storage: Staking ErasValidatorPrefs (r:0 w:10) + /// Proof: Staking ErasValidatorPrefs (max_values: None, max_size: Some(57), added: 2532, mode: MaxEncodedLen) + /// Storage: Staking ErasStakers (r:0 w:10) + /// Proof Skipped: Staking ErasStakers (max_values: None, max_size: None, mode: Measured) + /// Storage: Staking ErasTotalStake (r:0 w:1) + /// Proof: Staking ErasTotalStake (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) + /// Storage: Staking ErasStartSessionIndex (r:0 w:1) + /// Proof: Staking ErasStartSessionIndex (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) + /// Storage: Staking MinimumActiveStake (r:0 w:1) + /// Proof: Staking MinimumActiveStake (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) /// 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: 512_923 nanoseconds. - Weight::from_ref_time(514_740_000) - // Standard Error: 1_790_238 - .saturating_add(Weight::from_ref_time(59_320_539).saturating_mul(v.into())) - // Standard Error: 178_387 - .saturating_add(Weight::from_ref_time(13_902_705).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(206)) + // Proof Size summary in bytes: + // Measured: `0 + v * (3662 ±0) + n * (816 ±0)` + // Estimated: `528203 + v * (16743 ±0) + n * (12947 ±0)` + // Minimum execution time: 489_824 nanoseconds. + Weight::from_parts(491_687_000, 528203) + // Standard Error: 1_787_577 + .saturating_add(Weight::from_ref_time(58_719_498).saturating_mul(v.into())) + // Standard Error: 178_122 + .saturating_add(Weight::from_ref_time(13_273_555).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(206_u64)) .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(n.into()))) - .saturating_add(RocksDbWeight::get().writes(4)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(v.into()))) + .saturating_add(Weight::from_proof_size(16743).saturating_mul(v.into())) + .saturating_add(Weight::from_proof_size(12947).saturating_mul(n.into())) } - // Storage: VoterList CounterForListNodes (r:1 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) - // Storage: Staking Ledger (r:1500 w:0) - // Storage: Staking MinimumActiveStake (r:0 w:1) + /// Storage: VoterList CounterForListNodes (r:1 w:0) + /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:200 w:0) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:2000 w:0) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:2000 w:0) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) + /// Storage: Staking Validators (r:1000 w:0) + /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:2000 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:2000 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking MinimumActiveStake (r:0 w:1) + /// Proof: Staking MinimumActiveStake (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) /// The range of component `v` is `[500, 1000]`. /// The range of component `n` is `[500, 1000]`. fn get_npos_voters(v: u32, n: u32, ) -> Weight { - // Minimum execution time: 24_913_316 nanoseconds. - Weight::from_ref_time(25_053_596_000) - // Standard Error: 324_610 - .saturating_add(Weight::from_ref_time(3_454_859).saturating_mul(v.into())) - // Standard Error: 324_610 - .saturating_add(Weight::from_ref_time(3_020_267).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(201)) + // Proof Size summary in bytes: + // Measured: `3167 + v * (459 ±0) + n * (1007 ±0)` + // Estimated: `511899 + v * (14295 ±0) + n * (11775 ±0)` + // Minimum execution time: 23_373_467 nanoseconds. + Weight::from_parts(23_497_257_000, 511899) + // Standard Error: 299_205 + .saturating_add(Weight::from_ref_time(3_434_000).saturating_mul(v.into())) + // Standard Error: 299_205 + .saturating_add(Weight::from_ref_time(2_568_954).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(201_u64)) .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(n.into()))) - .saturating_add(RocksDbWeight::get().writes(1)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + .saturating_add(Weight::from_proof_size(14295).saturating_mul(v.into())) + .saturating_add(Weight::from_proof_size(11775).saturating_mul(n.into())) } - // Storage: Staking CounterForValidators (r:1 w:0) - // Storage: Staking Validators (r:501 w:0) + /// Storage: Staking CounterForValidators (r:1 w:0) + /// Proof: Staking CounterForValidators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking Validators (r:1001 w:0) + /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) /// The range of component `v` is `[500, 1000]`. fn get_npos_targets(v: u32, ) -> Weight { - // Minimum execution time: 4_916_401 nanoseconds. - Weight::from_ref_time(81_160_966) - // Standard Error: 23_829 - .saturating_add(Weight::from_ref_time(9_883_413).saturating_mul(v.into())) - .saturating_add(RocksDbWeight::get().reads(2)) + // Proof Size summary in bytes: + // Measured: `983 + v * (50 ±0)` + // Estimated: `3019 + v * (2520 ±0)` + // Minimum execution time: 3_882_120 nanoseconds. + Weight::from_parts(3_951_993_000, 3019) + // Standard Error: 46_729 + .saturating_add(Weight::from_ref_time(2_856_043).saturating_mul(v.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(v.into()))) + .saturating_add(Weight::from_proof_size(2520).saturating_mul(v.into())) } - // 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) + /// Storage: Staking MinCommission (r:0 w:1) + /// Proof: Staking MinCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking MinValidatorBond (r:0 w:1) + /// Proof: Staking MinValidatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: Staking MaxValidatorsCount (r:0 w:1) + /// Proof: Staking MaxValidatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking ChillThreshold (r:0 w:1) + /// Proof: Staking ChillThreshold (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// Storage: Staking MaxNominatorsCount (r:0 w:1) + /// Proof: Staking MaxNominatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking MinNominatorBond (r:0 w:1) + /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) fn set_staking_configs_all_set() -> Weight { - // Minimum execution time: 10_937 nanoseconds. - Weight::from_ref_time(11_324_000) - .saturating_add(RocksDbWeight::get().writes(6)) - } - // 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) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 8_427 nanoseconds. + Weight::from_ref_time(8_794_000) + .saturating_add(RocksDbWeight::get().writes(6_u64)) + } + /// Storage: Staking MinCommission (r:0 w:1) + /// Proof: Staking MinCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking MinValidatorBond (r:0 w:1) + /// Proof: Staking MinValidatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: Staking MaxValidatorsCount (r:0 w:1) + /// Proof: Staking MaxValidatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking ChillThreshold (r:0 w:1) + /// Proof: Staking ChillThreshold (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// Storage: Staking MaxNominatorsCount (r:0 w:1) + /// Proof: Staking MaxNominatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking MinNominatorBond (r:0 w:1) + /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) fn set_staking_configs_all_remove() -> Weight { - // Minimum execution time: 9_424 nanoseconds. - Weight::from_ref_time(10_021_000) - .saturating_add(RocksDbWeight::get().writes(6)) - } - // Storage: Staking Ledger (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) - // Storage: Staking Validators (r:1 w:0) - // Storage: VoterList ListNodes (r:2 w:2) - // Storage: VoterList ListBags (r:1 w:1) - // Storage: VoterList CounterForListNodes (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 7_620 nanoseconds. + Weight::from_ref_time(7_901_000) + .saturating_add(RocksDbWeight::get().writes(6_u64)) + } + /// Storage: Staking Ledger (r:1 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:1 w:1) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) + /// Storage: Staking ChillThreshold (r:1 w:0) + /// Proof: Staking ChillThreshold (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// Storage: Staking MaxNominatorsCount (r:1 w:0) + /// Proof: Staking MaxNominatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking CounterForNominators (r:1 w:1) + /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking MinNominatorBond (r:1 w:0) + /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: Staking Validators (r:1 w:0) + /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:2 w:2) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:1 w:1) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: VoterList CounterForListNodes (r:1 w:1) + /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn chill_other() -> Weight { - // Minimum execution time: 84_495 nanoseconds. - Weight::from_ref_time(85_559_000) - .saturating_add(RocksDbWeight::get().reads(11)) - .saturating_add(RocksDbWeight::get().writes(6)) + // Proof Size summary in bytes: + // Measured: `2031` + // Estimated: `19438` + // Minimum execution time: 66_188 nanoseconds. + Weight::from_parts(66_767_000, 19438) + .saturating_add(RocksDbWeight::get().reads(11_u64)) + .saturating_add(RocksDbWeight::get().writes(6_u64)) } - // Storage: Staking MinCommission (r:1 w:0) - // Storage: Staking Validators (r:1 w:1) + /// Storage: Staking MinCommission (r:1 w:0) + /// Proof: Staking MinCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking Validators (r:1 w:1) + /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) fn force_apply_min_commission() -> Weight { - // Minimum execution time: 20_385 nanoseconds. - Weight::from_ref_time(20_824_000) - .saturating_add(RocksDbWeight::get().reads(2)) - .saturating_add(RocksDbWeight::get().writes(1)) + // Proof Size summary in bytes: + // Measured: `694` + // Estimated: `3019` + // Minimum execution time: 14_703 nanoseconds. + Weight::from_parts(15_031_000, 3019) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - // Storage: Staking MinCommission (r:0 w:1) + /// Storage: Staking MinCommission (r:0 w:1) + /// Proof: Staking MinCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn set_min_commission() -> Weight { - // Minimum execution time: 6_995 nanoseconds. - Weight::from_ref_time(7_213_000) - .saturating_add(RocksDbWeight::get().writes(1)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 4_518 nanoseconds. + Weight::from_ref_time(4_656_000) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } } diff --git a/frame/state-trie-migration/src/weights.rs b/frame/state-trie-migration/src/weights.rs index 7414bb9038fdd..29b7f7ad47ca9 100644 --- a/frame/state-trie-migration/src/weights.rs +++ b/frame/state-trie-migration/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2023 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -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-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-01-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -59,100 +60,156 @@ 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) + /// Storage: StateTrieMigration SignedMigrationMaxLimits (r:1 w:0) + /// Proof: StateTrieMigration SignedMigrationMaxLimits (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: StateTrieMigration MigrationProcess (r:1 w:1) + /// Proof: StateTrieMigration MigrationProcess (max_values: Some(1), max_size: Some(1042), added: 1537, mode: MaxEncodedLen) fn continue_migrate() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `108` + // Estimated: `2040` + // Minimum execution time: 15_563 nanoseconds. + Weight::from_parts(15_783_000, 2040) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - // Storage: StateTrieMigration SignedMigrationMaxLimits (r:1 w:0) + /// Storage: StateTrieMigration SignedMigrationMaxLimits (r:1 w:0) + /// Proof: StateTrieMigration SignedMigrationMaxLimits (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) fn continue_migrate_wrong_witness() -> Weight { - // Minimum execution time: 6_119 nanoseconds. - Weight::from_ref_time(6_325_000 as u64) - .saturating_add(T::DbWeight::get().reads(1 as u64)) + // Proof Size summary in bytes: + // Measured: `76` + // Estimated: `503` + // Minimum execution time: 4_347 nanoseconds. + Weight::from_parts(4_558_000, 503) + .saturating_add(T::DbWeight::get().reads(1_u64)) } fn migrate_custom_top_success() -> Weight { - // Minimum execution time: 20_365 nanoseconds. - Weight::from_ref_time(20_790_000 as u64) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 8_817 nanoseconds. + Weight::from_ref_time(9_027_000) } - // Storage: unknown [0x666f6f] (r:1 w:1) + /// Storage: unknown `0x666f6f` (r:1 w:1) + /// Proof Skipped: unknown `0x666f6f` (r:1 w:1) fn migrate_custom_top_fail() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `144` + // Estimated: `2619` + // Minimum execution time: 23_854 nanoseconds. + Weight::from_parts(24_850_000, 2619) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } fn migrate_custom_child_success() -> Weight { - // Minimum execution time: 21_217 nanoseconds. - Weight::from_ref_time(21_526_000 as u64) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 9_020 nanoseconds. + Weight::from_ref_time(9_234_000) } - // Storage: unknown [0x666f6f] (r:1 w:1) + /// Storage: unknown `0x666f6f` (r:1 w:1) + /// Proof Skipped: unknown `0x666f6f` (r:1 w:1) fn migrate_custom_child_fail() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `136` + // Estimated: `2611` + // Minimum execution time: 24_136 nanoseconds. + Weight::from_parts(24_810_000, 2611) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - // Storage: unknown [0x6b6579] (r:1 w:1) + /// Storage: unknown `0x6b6579` (r:1 w:1) + /// Proof Skipped: unknown `0x6b6579` (r:1 w:1) /// The range of component `v` is `[1, 4194304]`. fn process_top_key(v: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `228 + v * (1 ±0)` + // Estimated: `2700 + v * (1 ±0)` + // Minimum execution time: 5_279 nanoseconds. + Weight::from_parts(5_517_000, 2700) + // Standard Error: 1 + .saturating_add(Weight::from_ref_time(1_230).saturating_mul(v.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + .saturating_add(Weight::from_proof_size(1).saturating_mul(v.into())) } } // For backwards compatibility and tests impl WeightInfo for () { - // Storage: StateTrieMigration SignedMigrationMaxLimits (r:1 w:0) - // Storage: StateTrieMigration MigrationProcess (r:1 w:1) + /// Storage: StateTrieMigration SignedMigrationMaxLimits (r:1 w:0) + /// Proof: StateTrieMigration SignedMigrationMaxLimits (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: StateTrieMigration MigrationProcess (r:1 w:1) + /// Proof: StateTrieMigration MigrationProcess (max_values: Some(1), max_size: Some(1042), added: 1537, mode: MaxEncodedLen) fn continue_migrate() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `108` + // Estimated: `2040` + // Minimum execution time: 15_563 nanoseconds. + Weight::from_parts(15_783_000, 2040) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - // Storage: StateTrieMigration SignedMigrationMaxLimits (r:1 w:0) + /// Storage: StateTrieMigration SignedMigrationMaxLimits (r:1 w:0) + /// Proof: StateTrieMigration SignedMigrationMaxLimits (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) fn continue_migrate_wrong_witness() -> Weight { - // Minimum execution time: 6_119 nanoseconds. - Weight::from_ref_time(6_325_000 as u64) - .saturating_add(RocksDbWeight::get().reads(1 as u64)) + // Proof Size summary in bytes: + // Measured: `76` + // Estimated: `503` + // Minimum execution time: 4_347 nanoseconds. + Weight::from_parts(4_558_000, 503) + .saturating_add(RocksDbWeight::get().reads(1_u64)) } fn migrate_custom_top_success() -> Weight { - // Minimum execution time: 20_365 nanoseconds. - Weight::from_ref_time(20_790_000 as u64) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 8_817 nanoseconds. + Weight::from_ref_time(9_027_000) } - // Storage: unknown [0x666f6f] (r:1 w:1) + /// Storage: unknown `0x666f6f` (r:1 w:1) + /// Proof Skipped: unknown `0x666f6f` (r:1 w:1) fn migrate_custom_top_fail() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `144` + // Estimated: `2619` + // Minimum execution time: 23_854 nanoseconds. + Weight::from_parts(24_850_000, 2619) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } fn migrate_custom_child_success() -> Weight { - // Minimum execution time: 21_217 nanoseconds. - Weight::from_ref_time(21_526_000 as u64) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 9_020 nanoseconds. + Weight::from_ref_time(9_234_000) } - // Storage: unknown [0x666f6f] (r:1 w:1) + /// Storage: unknown `0x666f6f` (r:1 w:1) + /// Proof Skipped: unknown `0x666f6f` (r:1 w:1) fn migrate_custom_child_fail() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `136` + // Estimated: `2611` + // Minimum execution time: 24_136 nanoseconds. + Weight::from_parts(24_810_000, 2611) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - // Storage: unknown [0x6b6579] (r:1 w:1) + /// Storage: unknown `0x6b6579` (r:1 w:1) + /// Proof Skipped: unknown `0x6b6579` (r:1 w:1) /// The range of component `v` is `[1, 4194304]`. fn process_top_key(v: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `228 + v * (1 ±0)` + // Estimated: `2700 + v * (1 ±0)` + // Minimum execution time: 5_279 nanoseconds. + Weight::from_parts(5_517_000, 2700) + // Standard Error: 1 + .saturating_add(Weight::from_ref_time(1_230).saturating_mul(v.into())) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + .saturating_add(Weight::from_proof_size(1).saturating_mul(v.into())) } } diff --git a/frame/support/procedural/src/benchmark.rs b/frame/support/procedural/src/benchmark.rs index 43e3e47de5259..f3bd5c2cfe6bf 100644 --- a/frame/support/procedural/src/benchmark.rs +++ b/frame/support/procedural/src/benchmark.rs @@ -438,6 +438,9 @@ pub fn benchmarks( #krate::BenchmarkMetadata { name: benchmark.as_bytes().to_vec(), components, + // TODO: Not supported by V2 syntax as of yet. + // https://github.com/paritytech/substrate/issues/13132 + pov_modes: vec![], } }).collect::<#krate::Vec<_>>() } diff --git a/frame/support/src/storage/transactional.rs b/frame/support/src/storage/transactional.rs index 909d5909ed8bd..b7ae22d86727c 100644 --- a/frame/support/src/storage/transactional.rs +++ b/frame/support/src/storage/transactional.rs @@ -32,6 +32,8 @@ use sp_runtime::{DispatchError, TransactionOutcome, TransactionalError}; /// The type that is being used to store the current number of active layers. pub type Layer = u32; /// The key that is holds the current number of active layers. +/// +/// Encodes to `0x3a7472616e73616374696f6e5f6c6576656c3a`. pub const TRANSACTION_LEVEL_KEY: &[u8] = b":transaction_level:"; /// The maximum number of nested layers. pub const TRANSACTIONAL_LIMIT: Layer = 255; diff --git a/frame/support/src/weights/block_weights.rs b/frame/support/src/weights/block_weights.rs index b68c1fb508b01..dc01107cec01f 100644 --- a/frame/support/src/weights/block_weights.rs +++ b/frame/support/src/weights/block_weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2023 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -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-11-07 (Y/M/D) +//! DATE: 2023-01-25 (Y/M/D) //! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! //! SHORT-NAME: `block`, LONG-NAME: `BlockExecution`, RUNTIME: `Development` @@ -44,17 +44,17 @@ parameter_types! { /// Calculated by multiplying the *Average* with `1.0` and adding `0`. /// /// Stats nanoseconds: - /// Min, Max: 351_000, 392_617 - /// Average: 358_523 - /// Median: 359_836 - /// Std-Dev: 6698.67 + /// Min, Max: 377_722, 414_752 + /// Average: 381_015 + /// Median: 379_751 + /// Std-Dev: 5462.64 /// /// Percentiles nanoseconds: - /// 99th: 390_723 - /// 95th: 365_799 - /// 75th: 361_582 + /// 99th: 413_074 + /// 95th: 384_876 + /// 75th: 380_642 pub const BlockExecutionWeight: Weight = - Weight::from_ref_time(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(358_523)); + Weight::from_ref_time(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(381_015)); } #[cfg(test)] diff --git a/frame/support/src/weights/extrinsic_weights.rs b/frame/support/src/weights/extrinsic_weights.rs index ced1fb91621f6..3d25d5a4025c9 100644 --- a/frame/support/src/weights/extrinsic_weights.rs +++ b/frame/support/src/weights/extrinsic_weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2023 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -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-11-07 (Y/M/D) +//! DATE: 2023-01-25 (Y/M/D) //! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! //! SHORT-NAME: `extrinsic`, LONG-NAME: `ExtrinsicBase`, RUNTIME: `Development` @@ -44,17 +44,17 @@ parameter_types! { /// Calculated by multiplying the *Average* with `1.0` and adding `0`. /// /// Stats nanoseconds: - /// Min, Max: 98_722, 101_420 - /// Average: 98_974 - /// Median: 98_951 - /// Std-Dev: 271.62 + /// Min, Max: 99_481, 103_304 + /// Average: 99_840 + /// Median: 99_795 + /// Std-Dev: 376.17 /// /// Percentiles nanoseconds: - /// 99th: 99_202 - /// 95th: 99_163 - /// 75th: 99_030 + /// 99th: 100_078 + /// 95th: 100_051 + /// 75th: 99_916 pub const ExtrinsicBaseWeight: Weight = - Weight::from_ref_time(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(98_974)); + Weight::from_ref_time(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(99_840)); } #[cfg(test)] diff --git a/frame/system/src/weights.rs b/frame/system/src/weights.rs index 696a6a09b8f80..d189afd4a549f 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) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2023 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,7 +18,8 @@ //! Autogenerated weights for frame_system //! //! 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: `[]` +//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -60,52 +61,76 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { /// The range of component `b` is `[0, 3932160]`. fn remark(b: u32, ) -> Weight { - // Minimum execution time: 3_951 nanoseconds. - Weight::from_ref_time(1_307_232 as u64) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_018 nanoseconds. + Weight::from_ref_time(2_091_000) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(363 as u64).saturating_mul(b as u64)) + .saturating_add(Weight::from_ref_time(362).saturating_mul(b.into())) } /// The range of component `b` is `[0, 3932160]`. fn remark_with_event(b: u32, ) -> Weight { - // Minimum execution time: 14_880 nanoseconds. - Weight::from_ref_time(15_173_000 as u64) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 7_449 nanoseconds. + Weight::from_ref_time(7_748_000) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_424 as u64).saturating_mul(b as u64)) + .saturating_add(Weight::from_ref_time(1_423).saturating_mul(b.into())) } - // Storage: System Digest (r:1 w:1) - // Storage: unknown [0x3a686561707061676573] (r:0 w:1) + /// Storage: System Digest (r:1 w:1) + /// Proof Skipped: System Digest (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: unknown `0x3a686561707061676573` (r:0 w:1) + /// Proof Skipped: unknown `0x3a686561707061676573` (r:0 w:1) fn set_heap_pages() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `495` + // Minimum execution time: 4_440 nanoseconds. + Weight::from_parts(4_605_000, 495) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } - // Storage: Skipped Metadata (r:0 w:0) + /// Storage: Skipped Metadata (r:0 w:0) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `i` is `[0, 1000]`. fn set_storage(i: u32, ) -> Weight { - // 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))) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_981 nanoseconds. + Weight::from_ref_time(2_114_000) + // Standard Error: 804 + .saturating_add(Weight::from_ref_time(631_438).saturating_mul(i.into())) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) } - // Storage: Skipped Metadata (r:0 w:0) + /// Storage: Skipped Metadata (r:0 w:0) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `i` is `[0, 1000]`. fn kill_storage(i: u32, ) -> Weight { - // 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))) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_061 nanoseconds. + Weight::from_ref_time(2_153_000) + // Standard Error: 952 + .saturating_add(Weight::from_ref_time(502_629).saturating_mul(i.into())) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) } - // Storage: Skipped Metadata (r:0 w:0) + /// Storage: Skipped Metadata (r:0 w:0) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `p` is `[0, 1000]`. fn kill_prefix(p: u32, ) -> Weight { - // 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))) + // Proof Size summary in bytes: + // Measured: `116 + p * (69 ±0)` + // Estimated: `121 + p * (70 ±0)` + // Minimum execution time: 4_026 nanoseconds. + Weight::from_parts(4_174_000, 121) + // Standard Error: 1_148 + .saturating_add(Weight::from_ref_time(1_093_099).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(p.into()))) + .saturating_add(Weight::from_proof_size(70).saturating_mul(p.into())) } } @@ -113,51 +138,75 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { /// The range of component `b` is `[0, 3932160]`. fn remark(b: u32, ) -> Weight { - // Minimum execution time: 3_951 nanoseconds. - Weight::from_ref_time(1_307_232 as u64) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_018 nanoseconds. + Weight::from_ref_time(2_091_000) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(363 as u64).saturating_mul(b as u64)) + .saturating_add(Weight::from_ref_time(362).saturating_mul(b.into())) } /// The range of component `b` is `[0, 3932160]`. fn remark_with_event(b: u32, ) -> Weight { - // Minimum execution time: 14_880 nanoseconds. - Weight::from_ref_time(15_173_000 as u64) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 7_449 nanoseconds. + Weight::from_ref_time(7_748_000) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_424 as u64).saturating_mul(b as u64)) + .saturating_add(Weight::from_ref_time(1_423).saturating_mul(b.into())) } - // Storage: System Digest (r:1 w:1) - // Storage: unknown [0x3a686561707061676573] (r:0 w:1) + /// Storage: System Digest (r:1 w:1) + /// Proof Skipped: System Digest (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: unknown `0x3a686561707061676573` (r:0 w:1) + /// Proof Skipped: unknown `0x3a686561707061676573` (r:0 w:1) fn set_heap_pages() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `495` + // Minimum execution time: 4_440 nanoseconds. + Weight::from_parts(4_605_000, 495) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } - // Storage: Skipped Metadata (r:0 w:0) + /// Storage: Skipped Metadata (r:0 w:0) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `i` is `[0, 1000]`. fn set_storage(i: u32, ) -> Weight { - // 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))) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_981 nanoseconds. + Weight::from_ref_time(2_114_000) + // Standard Error: 804 + .saturating_add(Weight::from_ref_time(631_438).saturating_mul(i.into())) + .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(i.into()))) } - // Storage: Skipped Metadata (r:0 w:0) + /// Storage: Skipped Metadata (r:0 w:0) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `i` is `[0, 1000]`. fn kill_storage(i: u32, ) -> Weight { - // 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))) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_061 nanoseconds. + Weight::from_ref_time(2_153_000) + // Standard Error: 952 + .saturating_add(Weight::from_ref_time(502_629).saturating_mul(i.into())) + .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(i.into()))) } - // Storage: Skipped Metadata (r:0 w:0) + /// Storage: Skipped Metadata (r:0 w:0) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `p` is `[0, 1000]`. fn kill_prefix(p: u32, ) -> Weight { - // 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))) + // Proof Size summary in bytes: + // Measured: `116 + p * (69 ±0)` + // Estimated: `121 + p * (70 ±0)` + // Minimum execution time: 4_026 nanoseconds. + Weight::from_parts(4_174_000, 121) + // Standard Error: 1_148 + .saturating_add(Weight::from_ref_time(1_093_099).saturating_mul(p.into())) + .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(p.into()))) + .saturating_add(Weight::from_proof_size(70).saturating_mul(p.into())) } } diff --git a/frame/timestamp/src/weights.rs b/frame/timestamp/src/weights.rs index 52123920977da..4c7dfd5ed17a5 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) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2023 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -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-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-01-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -54,32 +55,48 @@ pub trait WeightInfo { /// Weights for pallet_timestamp using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - // Storage: Timestamp Now (r:1 w:1) - // Storage: Babe CurrentSlot (r:1 w:0) + /// Storage: Timestamp Now (r:1 w:1) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Babe CurrentSlot (r:1 w:0) + /// Proof: Babe CurrentSlot (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) fn set() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `312` + // Estimated: `1006` + // Minimum execution time: 9_106 nanoseconds. + Weight::from_parts(9_258_000, 1006) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } fn on_finalize() -> Weight { - // Minimum execution time: 5_280 nanoseconds. - Weight::from_ref_time(5_412_000 as u64) + // Proof Size summary in bytes: + // Measured: `161` + // Estimated: `0` + // Minimum execution time: 3_927 nanoseconds. + Weight::from_ref_time(4_078_000) } } // For backwards compatibility and tests impl WeightInfo for () { - // Storage: Timestamp Now (r:1 w:1) - // Storage: Babe CurrentSlot (r:1 w:0) + /// Storage: Timestamp Now (r:1 w:1) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Babe CurrentSlot (r:1 w:0) + /// Proof: Babe CurrentSlot (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) fn set() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `312` + // Estimated: `1006` + // Minimum execution time: 9_106 nanoseconds. + Weight::from_parts(9_258_000, 1006) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } fn on_finalize() -> Weight { - // Minimum execution time: 5_280 nanoseconds. - Weight::from_ref_time(5_412_000 as u64) + // Proof Size summary in bytes: + // Measured: `161` + // Estimated: `0` + // Minimum execution time: 3_927 nanoseconds. + Weight::from_ref_time(4_078_000) } } diff --git a/frame/tips/src/weights.rs b/frame/tips/src/weights.rs index 1aa3fd8fa2eb7..a568aaa870f0f 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) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2023 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -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-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-01-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -58,146 +59,218 @@ pub trait WeightInfo { /// Weights for pallet_tips using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - // Storage: Tips Reasons (r:1 w:1) - // Storage: Tips Tips (r:1 w:1) + /// Storage: Tips Reasons (r:1 w:1) + /// Proof Skipped: Tips Reasons (max_values: None, max_size: None, mode: Measured) + /// Storage: Tips Tips (r:1 w:1) + /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 300]`. fn report_awesome(r: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `4` + // Estimated: `4958` + // Minimum execution time: 23_262 nanoseconds. + Weight::from_parts(24_104_224, 4958) + // Standard Error: 148 + .saturating_add(Weight::from_ref_time(1_963).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } - // Storage: Tips Tips (r:1 w:1) - // Storage: Tips Reasons (r:0 w:1) + /// Storage: Tips Tips (r:1 w:1) + /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) + /// Storage: Tips Reasons (r:0 w:1) + /// Proof Skipped: Tips Reasons (max_values: None, max_size: None, mode: Measured) fn retract_tip() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `253` + // Estimated: `2981` + // Minimum execution time: 22_282 nanoseconds. + Weight::from_parts(22_737_000, 2981) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } - // Storage: Elections Members (r:1 w:0) - // Storage: Tips Reasons (r:1 w:1) - // Storage: Tips Tips (r:0 w:1) + /// Storage: Elections Members (r:1 w:0) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Tips Reasons (r:1 w:1) + /// Proof Skipped: Tips Reasons (max_values: None, max_size: None, mode: Measured) + /// Storage: Tips Tips (r:0 w:1) + /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 300]`. /// The range of component `t` is `[1, 13]`. fn tip_new(r: u32, t: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `558 + t * (64 ±0)` + // Estimated: `4644 + t * (192 ±0)` + // Minimum execution time: 18_382 nanoseconds. + Weight::from_parts(18_195_288, 4644) + // Standard Error: 103 + .saturating_add(Weight::from_ref_time(2_096).saturating_mul(r.into())) + // Standard Error: 2_469 + .saturating_add(Weight::from_ref_time(97_092).saturating_mul(t.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_proof_size(192).saturating_mul(t.into())) } - // Storage: Elections Members (r:1 w:0) - // Storage: Tips Tips (r:1 w:1) + /// Storage: Elections Members (r:1 w:0) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Tips Tips (r:1 w:1) + /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) /// The range of component `t` is `[1, 13]`. fn tip(t: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `811 + t * (112 ±0)` + // Estimated: `4592 + t * (224 ±0)` + // Minimum execution time: 13_564 nanoseconds. + Weight::from_parts(13_867_280, 4592) + // Standard Error: 4_245 + .saturating_add(Weight::from_ref_time(206_587).saturating_mul(t.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + .saturating_add(Weight::from_proof_size(224).saturating_mul(t.into())) } - // 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) + /// Storage: Tips Tips (r:1 w:1) + /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) + /// Storage: Elections Members (r:1 w:0) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Tips Reasons (r:0 w:1) + /// Proof Skipped: Tips Reasons (max_values: None, max_size: None, mode: Measured) /// The range of component `t` is `[1, 13]`. fn close_tip(t: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `850 + t * (112 ±0)` + // Estimated: `8096 + t * (336 ±0)` + // Minimum execution time: 39_902 nanoseconds. + Weight::from_parts(40_747_650, 8096) + // Standard Error: 5_322 + .saturating_add(Weight::from_ref_time(144_298).saturating_mul(t.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(336).saturating_mul(t.into())) } - // Storage: Tips Tips (r:1 w:1) - // Storage: Tips Reasons (r:0 w:1) + /// Storage: Tips Tips (r:1 w:1) + /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) + /// Storage: Tips Reasons (r:0 w:1) + /// Proof Skipped: Tips Reasons (max_values: None, max_size: None, mode: Measured) /// The range of component `t` is `[1, 13]`. fn slash_tip(t: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `301` + // Estimated: `3077` + // Minimum execution time: 13_511 nanoseconds. + Weight::from_parts(14_114_101, 3077) + // Standard Error: 1_815 + .saturating_add(Weight::from_ref_time(7_825).saturating_mul(t.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } } // For backwards compatibility and tests impl WeightInfo for () { - // Storage: Tips Reasons (r:1 w:1) - // Storage: Tips Tips (r:1 w:1) + /// Storage: Tips Reasons (r:1 w:1) + /// Proof Skipped: Tips Reasons (max_values: None, max_size: None, mode: Measured) + /// Storage: Tips Tips (r:1 w:1) + /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 300]`. fn report_awesome(r: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `4` + // Estimated: `4958` + // Minimum execution time: 23_262 nanoseconds. + Weight::from_parts(24_104_224, 4958) + // Standard Error: 148 + .saturating_add(Weight::from_ref_time(1_963).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } - // Storage: Tips Tips (r:1 w:1) - // Storage: Tips Reasons (r:0 w:1) + /// Storage: Tips Tips (r:1 w:1) + /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) + /// Storage: Tips Reasons (r:0 w:1) + /// Proof Skipped: Tips Reasons (max_values: None, max_size: None, mode: Measured) fn retract_tip() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `253` + // Estimated: `2981` + // Minimum execution time: 22_282 nanoseconds. + Weight::from_parts(22_737_000, 2981) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } - // Storage: Elections Members (r:1 w:0) - // Storage: Tips Reasons (r:1 w:1) - // Storage: Tips Tips (r:0 w:1) + /// Storage: Elections Members (r:1 w:0) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Tips Reasons (r:1 w:1) + /// Proof Skipped: Tips Reasons (max_values: None, max_size: None, mode: Measured) + /// Storage: Tips Tips (r:0 w:1) + /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 300]`. /// The range of component `t` is `[1, 13]`. fn tip_new(r: u32, t: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `558 + t * (64 ±0)` + // Estimated: `4644 + t * (192 ±0)` + // Minimum execution time: 18_382 nanoseconds. + Weight::from_parts(18_195_288, 4644) + // Standard Error: 103 + .saturating_add(Weight::from_ref_time(2_096).saturating_mul(r.into())) + // Standard Error: 2_469 + .saturating_add(Weight::from_ref_time(97_092).saturating_mul(t.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_proof_size(192).saturating_mul(t.into())) } - // Storage: Elections Members (r:1 w:0) - // Storage: Tips Tips (r:1 w:1) + /// Storage: Elections Members (r:1 w:0) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Tips Tips (r:1 w:1) + /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) /// The range of component `t` is `[1, 13]`. fn tip(t: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `811 + t * (112 ±0)` + // Estimated: `4592 + t * (224 ±0)` + // Minimum execution time: 13_564 nanoseconds. + Weight::from_parts(13_867_280, 4592) + // Standard Error: 4_245 + .saturating_add(Weight::from_ref_time(206_587).saturating_mul(t.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + .saturating_add(Weight::from_proof_size(224).saturating_mul(t.into())) } - // 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) + /// Storage: Tips Tips (r:1 w:1) + /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) + /// Storage: Elections Members (r:1 w:0) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Tips Reasons (r:0 w:1) + /// Proof Skipped: Tips Reasons (max_values: None, max_size: None, mode: Measured) /// The range of component `t` is `[1, 13]`. fn close_tip(t: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `850 + t * (112 ±0)` + // Estimated: `8096 + t * (336 ±0)` + // Minimum execution time: 39_902 nanoseconds. + Weight::from_parts(40_747_650, 8096) + // Standard Error: 5_322 + .saturating_add(Weight::from_ref_time(144_298).saturating_mul(t.into())) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(336).saturating_mul(t.into())) } - // Storage: Tips Tips (r:1 w:1) - // Storage: Tips Reasons (r:0 w:1) + /// Storage: Tips Tips (r:1 w:1) + /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) + /// Storage: Tips Reasons (r:0 w:1) + /// Proof Skipped: Tips Reasons (max_values: None, max_size: None, mode: Measured) /// The range of component `t` is `[1, 13]`. fn slash_tip(t: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `301` + // Estimated: `3077` + // Minimum execution time: 13_511 nanoseconds. + Weight::from_parts(14_114_101, 3077) + // Standard Error: 1_815 + .saturating_add(Weight::from_ref_time(7_825).saturating_mul(t.into())) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } } diff --git a/frame/transaction-storage/src/weights.rs b/frame/transaction-storage/src/weights.rs index 16d12aa75ab4d..9ee7b37b3dc48 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) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2023 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -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-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-01-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -55,78 +56,116 @@ 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 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 ByteFee (r:1 w:0) + /// Proof: TransactionStorage ByteFee (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: TransactionStorage EntryFee (r:1 w:0) + /// Proof: TransactionStorage EntryFee (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: TransactionStorage BlockTransactions (r:1 w:1) + /// Proof: TransactionStorage BlockTransactions (max_values: Some(1), max_size: Some(36866), added: 37361, mode: MaxEncodedLen) /// The range of component `l` is `[1, 8388608]`. fn store(l: u32, ) -> Weight { - // Minimum execution time: 46_730 nanoseconds. - Weight::from_ref_time(46_922_000 as u64) + // Proof Size summary in bytes: + // Measured: `176` + // Estimated: `38383` + // Minimum execution time: 28_702 nanoseconds. + Weight::from_parts(29_164_000, 38383) // 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)) + .saturating_add(Weight::from_ref_time(5_601).saturating_mul(l.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(1_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: TransactionStorage BlockTransactions (r:1 w:1) + /// Storage: TransactionStorage Transactions (r:1 w:0) + /// Proof: TransactionStorage Transactions (max_values: None, max_size: Some(36886), added: 39361, mode: MaxEncodedLen) + /// Storage: TransactionStorage ByteFee (r:1 w:0) + /// Proof: TransactionStorage ByteFee (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: TransactionStorage EntryFee (r:1 w:0) + /// Proof: TransactionStorage EntryFee (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: TransactionStorage BlockTransactions (r:1 w:1) + /// Proof: TransactionStorage BlockTransactions (max_values: Some(1), max_size: Some(36866), added: 37361, mode: MaxEncodedLen) fn renew() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `358` + // Estimated: `77744` + // Minimum execution time: 36_219 nanoseconds. + Weight::from_parts(36_979_000, 77744) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - // Storage: TransactionStorage ProofChecked (r:1 w:1) - // Storage: TransactionStorage StoragePeriod (r:1 w:0) - // Storage: TransactionStorage ChunkCount (r:1 w:0) - // Storage: System ParentHash (r:1 w:0) - // Storage: TransactionStorage Transactions (r:1 w:0) + /// Storage: TransactionStorage ProofChecked (r:1 w:1) + /// Proof: TransactionStorage ProofChecked (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// Storage: TransactionStorage StoragePeriod (r:1 w:0) + /// Proof: TransactionStorage StoragePeriod (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: TransactionStorage ChunkCount (r:1 w:0) + /// Proof: TransactionStorage ChunkCount (max_values: None, max_size: Some(24), added: 2499, mode: MaxEncodedLen) + /// Storage: System ParentHash (r:1 w:0) + /// Proof: System ParentHash (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + /// Storage: TransactionStorage Transactions (r:1 w:0) + /// Proof: TransactionStorage Transactions (max_values: None, max_size: Some(36886), added: 39361, mode: MaxEncodedLen) fn check_proof_max() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `37177` + // Estimated: `43382` + // Minimum execution time: 55_793 nanoseconds. + Weight::from_parts(57_128_000, 43382) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } } // For backwards compatibility and tests impl WeightInfo for () { - // 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 ByteFee (r:1 w:0) + /// Proof: TransactionStorage ByteFee (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: TransactionStorage EntryFee (r:1 w:0) + /// Proof: TransactionStorage EntryFee (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: TransactionStorage BlockTransactions (r:1 w:1) + /// Proof: TransactionStorage BlockTransactions (max_values: Some(1), max_size: Some(36866), added: 37361, mode: MaxEncodedLen) /// The range of component `l` is `[1, 8388608]`. fn store(l: u32, ) -> Weight { - // Minimum execution time: 46_730 nanoseconds. - Weight::from_ref_time(46_922_000 as u64) + // Proof Size summary in bytes: + // Measured: `176` + // Estimated: `38383` + // Minimum execution time: 28_702 nanoseconds. + Weight::from_parts(29_164_000, 38383) // 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)) + .saturating_add(Weight::from_ref_time(5_601).saturating_mul(l.into())) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(1_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: TransactionStorage BlockTransactions (r:1 w:1) + /// Storage: TransactionStorage Transactions (r:1 w:0) + /// Proof: TransactionStorage Transactions (max_values: None, max_size: Some(36886), added: 39361, mode: MaxEncodedLen) + /// Storage: TransactionStorage ByteFee (r:1 w:0) + /// Proof: TransactionStorage ByteFee (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: TransactionStorage EntryFee (r:1 w:0) + /// Proof: TransactionStorage EntryFee (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: TransactionStorage BlockTransactions (r:1 w:1) + /// Proof: TransactionStorage BlockTransactions (max_values: Some(1), max_size: Some(36866), added: 37361, mode: MaxEncodedLen) fn renew() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `358` + // Estimated: `77744` + // Minimum execution time: 36_219 nanoseconds. + Weight::from_parts(36_979_000, 77744) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - // Storage: TransactionStorage ProofChecked (r:1 w:1) - // Storage: TransactionStorage StoragePeriod (r:1 w:0) - // Storage: TransactionStorage ChunkCount (r:1 w:0) - // Storage: System ParentHash (r:1 w:0) - // Storage: TransactionStorage Transactions (r:1 w:0) + /// Storage: TransactionStorage ProofChecked (r:1 w:1) + /// Proof: TransactionStorage ProofChecked (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// Storage: TransactionStorage StoragePeriod (r:1 w:0) + /// Proof: TransactionStorage StoragePeriod (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: TransactionStorage ChunkCount (r:1 w:0) + /// Proof: TransactionStorage ChunkCount (max_values: None, max_size: Some(24), added: 2499, mode: MaxEncodedLen) + /// Storage: System ParentHash (r:1 w:0) + /// Proof: System ParentHash (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + /// Storage: TransactionStorage Transactions (r:1 w:0) + /// Proof: TransactionStorage Transactions (max_values: None, max_size: Some(36886), added: 39361, mode: MaxEncodedLen) fn check_proof_max() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `37177` + // Estimated: `43382` + // Minimum execution time: 55_793 nanoseconds. + Weight::from_parts(57_128_000, 43382) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } } diff --git a/frame/treasury/src/weights.rs b/frame/treasury/src/weights.rs index 3ee071ac700f1..aff593d88a0f9 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) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2023 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -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-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-01-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -58,114 +59,194 @@ 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) + /// Proof: Treasury ProposalCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Treasury Approvals (r:1 w:1) + /// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) + /// Storage: Treasury Proposals (r:0 w:1) + /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) fn spend() -> Weight { - // Minimum execution time: 137 nanoseconds. - Weight::from_ref_time(153_000 as u64) + // Proof Size summary in bytes: + // Measured: `42` + // Estimated: `1396` + // Minimum execution time: 14_277 nanoseconds. + Weight::from_parts(14_749_000, 1396) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) } - // Storage: Treasury ProposalCount (r:1 w:1) - // Storage: Treasury Proposals (r:0 w:1) + /// Storage: Treasury ProposalCount (r:1 w:1) + /// Proof: Treasury ProposalCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Treasury Proposals (r:0 w:1) + /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) fn propose_spend() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `175` + // Estimated: `499` + // Minimum execution time: 23_297 nanoseconds. + Weight::from_parts(23_585_000, 499) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } - // Storage: Treasury Proposals (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: Treasury Proposals (r:1 w:1) + /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn reject_proposal() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `365` + // Estimated: `5186` + // Minimum execution time: 23_996 nanoseconds. + Weight::from_parts(24_548_000, 5186) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } - // Storage: Treasury Proposals (r:1 w:0) - // Storage: Treasury Approvals (r:1 w:1) + /// Storage: Treasury Proposals (r:1 w:0) + /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) + /// Storage: Treasury Approvals (r:1 w:1) + /// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) /// The range of component `p` is `[0, 99]`. fn approve_proposal(p: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `501 + p * (8 ±0)` + // Estimated: `3480` + // Minimum execution time: 9_366 nanoseconds. + Weight::from_parts(11_731_455, 3480) + // Standard Error: 761 + .saturating_add(Weight::from_ref_time(21_665).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - // Storage: Treasury Approvals (r:1 w:1) + /// Storage: Treasury Approvals (r:1 w:1) + /// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) fn remove_approval() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `127` + // Estimated: `897` + // Minimum execution time: 7_012 nanoseconds. + Weight::from_parts(7_270_000, 897) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_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) + /// Storage: Treasury Deactivated (r:1 w:1) + /// Proof: Treasury Deactivated (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: Treasury Approvals (r:1 w:1) + /// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) + /// Storage: Treasury Proposals (r:100 w:100) + /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) + /// Storage: System Account (r:200 w:200) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Bounties BountyApprovals (r:1 w:1) + /// Proof: Bounties BountyApprovals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) /// The range of component `p` is `[0, 100]`. fn on_initialize_proposals(p: u32, ) -> Weight { - // 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)) - .saturating_add(T::DbWeight::get().writes((3 as u64).saturating_mul(p as u64))) + // Proof Size summary in bytes: + // Measured: `415 + p * (314 ±0)` + // Estimated: `2305 + p * (7789 ±0)` + // Minimum execution time: 37_834 nanoseconds. + Weight::from_parts(47_496_917, 2305) + // Standard Error: 12_505 + .saturating_add(Weight::from_ref_time(26_902_474).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(p.into()))) + .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(p.into()))) + .saturating_add(Weight::from_proof_size(7789).saturating_mul(p.into())) } } // For backwards compatibility and tests impl WeightInfo for () { + /// Storage: Treasury ProposalCount (r:1 w:1) + /// Proof: Treasury ProposalCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Treasury Approvals (r:1 w:1) + /// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) + /// Storage: Treasury Proposals (r:0 w:1) + /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) fn spend() -> Weight { - // Minimum execution time: 137 nanoseconds. - Weight::from_ref_time(153_000 as u64) + // Proof Size summary in bytes: + // Measured: `42` + // Estimated: `1396` + // Minimum execution time: 14_277 nanoseconds. + Weight::from_parts(14_749_000, 1396) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) } - // Storage: Treasury ProposalCount (r:1 w:1) - // Storage: Treasury Proposals (r:0 w:1) + /// Storage: Treasury ProposalCount (r:1 w:1) + /// Proof: Treasury ProposalCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Treasury Proposals (r:0 w:1) + /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) fn propose_spend() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `175` + // Estimated: `499` + // Minimum execution time: 23_297 nanoseconds. + Weight::from_parts(23_585_000, 499) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } - // Storage: Treasury Proposals (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: Treasury Proposals (r:1 w:1) + /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn reject_proposal() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `365` + // Estimated: `5186` + // Minimum execution time: 23_996 nanoseconds. + Weight::from_parts(24_548_000, 5186) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } - // Storage: Treasury Proposals (r:1 w:0) - // Storage: Treasury Approvals (r:1 w:1) + /// Storage: Treasury Proposals (r:1 w:0) + /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) + /// Storage: Treasury Approvals (r:1 w:1) + /// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) /// The range of component `p` is `[0, 99]`. fn approve_proposal(p: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `501 + p * (8 ±0)` + // Estimated: `3480` + // Minimum execution time: 9_366 nanoseconds. + Weight::from_parts(11_731_455, 3480) + // Standard Error: 761 + .saturating_add(Weight::from_ref_time(21_665).saturating_mul(p.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - // Storage: Treasury Approvals (r:1 w:1) + /// Storage: Treasury Approvals (r:1 w:1) + /// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) fn remove_approval() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `127` + // Estimated: `897` + // Minimum execution time: 7_012 nanoseconds. + Weight::from_parts(7_270_000, 897) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_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) + /// Storage: Treasury Deactivated (r:1 w:1) + /// Proof: Treasury Deactivated (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: Treasury Approvals (r:1 w:1) + /// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) + /// Storage: Treasury Proposals (r:100 w:100) + /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) + /// Storage: System Account (r:200 w:200) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Bounties BountyApprovals (r:1 w:1) + /// Proof: Bounties BountyApprovals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) /// The range of component `p` is `[0, 100]`. fn on_initialize_proposals(p: u32, ) -> Weight { - // 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)) - .saturating_add(RocksDbWeight::get().writes((3 as u64).saturating_mul(p as u64))) + // Proof Size summary in bytes: + // Measured: `415 + p * (314 ±0)` + // Estimated: `2305 + p * (7789 ±0)` + // Minimum execution time: 37_834 nanoseconds. + Weight::from_parts(47_496_917, 2305) + // Standard Error: 12_505 + .saturating_add(Weight::from_ref_time(26_902_474).saturating_mul(p.into())) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(p.into()))) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(p.into()))) + .saturating_add(Weight::from_proof_size(7789).saturating_mul(p.into())) } } diff --git a/frame/uniques/src/weights.rs b/frame/uniques/src/weights.rs index 8a8e1090bb718..3c1b102ba066a 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) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2023 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,7 +18,8 @@ //! Autogenerated weights for pallet_uniques //! //! 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: `[]` +//! DATE: 2023-01-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -78,486 +79,776 @@ pub trait WeightInfo { /// Weights for pallet_uniques using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - // Storage: Uniques Class (r:1 w:1) - // Storage: Uniques ClassAccount (r:0 w:1) + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) + /// Storage: Uniques ClassAccount (r:0 w:1) + /// Proof: Uniques ClassAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) fn create() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `281` + // Estimated: `2653` + // Minimum execution time: 24_242 nanoseconds. + Weight::from_parts(24_682_000, 2653) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) + /// Storage: Uniques ClassAccount (r:0 w:1) + /// Proof: Uniques ClassAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) fn force_create() -> Weight { - // 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)) - } - // 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 CollectionMaxSupply (r:0 w:1) - // Storage: Uniques Account (r:0 w:20) + // Proof Size summary in bytes: + // Measured: `109` + // Estimated: `2653` + // Minimum execution time: 14_145 nanoseconds. + Weight::from_parts(14_598_000, 2653) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) + /// Storage: Uniques Asset (r:1001 w:1000) + /// Proof: Uniques Asset (max_values: None, max_size: Some(122), added: 2597, mode: MaxEncodedLen) + /// Storage: Uniques ClassAccount (r:0 w:1) + /// Proof: Uniques ClassAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) + /// Storage: Uniques Attribute (r:0 w:1000) + /// Proof: Uniques Attribute (max_values: None, max_size: Some(364), added: 2839, mode: MaxEncodedLen) + /// Storage: Uniques ClassMetadataOf (r:0 w:1) + /// Proof: Uniques ClassMetadataOf (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) + /// Storage: Uniques InstanceMetadataOf (r:0 w:1000) + /// Proof: Uniques InstanceMetadataOf (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) + /// Storage: Uniques Account (r:0 w:1000) + /// Proof: Uniques Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) + /// Storage: Uniques CollectionMaxSupply (r:0 w:1) + /// Proof: Uniques CollectionMaxSupply (max_values: None, max_size: Some(24), added: 2499, mode: MaxEncodedLen) /// The range of component `n` is `[0, 1000]`. /// The range of component `m` is `[0, 1000]`. /// The range of component `a` is `[0, 1000]`. fn destroy(n: u32, m: u32, a: u32, ) -> Weight { - // 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)) - .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) + // Proof Size summary in bytes: + // Measured: `450 + n * (108 ±0) + m * (56 ±0) + a * (107 ±0)` + // Estimated: `5250 + n * (2597 ±0)` + // Minimum execution time: 2_404_081 nanoseconds. + Weight::from_parts(2_419_004_000, 5250) + // Standard Error: 27_175 + .saturating_add(Weight::from_ref_time(8_616_904).saturating_mul(n.into())) + // Standard Error: 27_175 + .saturating_add(Weight::from_ref_time(334_249).saturating_mul(m.into())) + // Standard Error: 27_175 + .saturating_add(Weight::from_ref_time(213_038).saturating_mul(a.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes(4_u64)) + .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(m.into()))) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(a.into()))) + .saturating_add(Weight::from_proof_size(2597).saturating_mul(n.into())) + } + /// Storage: Uniques Asset (r:1 w:1) + /// Proof: Uniques Asset (max_values: None, max_size: Some(122), added: 2597, mode: MaxEncodedLen) + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) + /// Storage: Uniques CollectionMaxSupply (r:1 w:0) + /// Proof: Uniques CollectionMaxSupply (max_values: None, max_size: Some(24), added: 2499, mode: MaxEncodedLen) + /// Storage: Uniques Account (r:0 w:1) + /// Proof: Uniques Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) fn mint() -> Weight { - // 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)) - } - // 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) + // Proof Size summary in bytes: + // Measured: `381` + // Estimated: `7749` + // Minimum execution time: 29_326 nanoseconds. + Weight::from_parts(29_671_000, 7749) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) + /// Storage: Uniques Asset (r:1 w:1) + /// Proof: Uniques Asset (max_values: None, max_size: Some(122), added: 2597, mode: MaxEncodedLen) + /// Storage: Uniques Account (r:0 w:1) + /// Proof: Uniques Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) + /// Storage: Uniques ItemPriceOf (r:0 w:1) + /// Proof: Uniques ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) fn burn() -> Weight { - // 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)) - } - // 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) + // Proof Size summary in bytes: + // Measured: `559` + // Estimated: `5250` + // Minimum execution time: 30_497 nanoseconds. + Weight::from_parts(30_714_000, 5250) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: Uniques Class (r:1 w:0) + /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) + /// Storage: Uniques Asset (r:1 w:1) + /// Proof: Uniques Asset (max_values: None, max_size: Some(122), added: 2597, mode: MaxEncodedLen) + /// Storage: Uniques Account (r:0 w:2) + /// Proof: Uniques Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) + /// Storage: Uniques ItemPriceOf (r:0 w:1) + /// Proof: Uniques ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) fn transfer() -> Weight { - // 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)) - } - // Storage: Uniques Class (r:1 w:1) - // Storage: Uniques Asset (r:102 w:102) + // Proof Size summary in bytes: + // Measured: `559` + // Estimated: `5250` + // Minimum execution time: 24_212 nanoseconds. + Weight::from_parts(24_681_000, 5250) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) + /// Storage: Uniques Asset (r:5000 w:5000) + /// Proof: Uniques Asset (max_values: None, max_size: Some(122), added: 2597, mode: MaxEncodedLen) /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { - // 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)) - .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) + // Proof Size summary in bytes: + // Measured: `837 + i * (108 ±0)` + // Estimated: `2653 + i * (2597 ±0)` + // Minimum execution time: 13_633 nanoseconds. + Weight::from_parts(13_797_000, 2653) + // Standard Error: 9_293 + .saturating_add(Weight::from_ref_time(11_163_914).saturating_mul(i.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(i.into()))) + .saturating_add(T::DbWeight::get().writes(1_u64)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) + .saturating_add(Weight::from_proof_size(2597).saturating_mul(i.into())) + } + /// Storage: Uniques Asset (r:1 w:1) + /// Proof: Uniques Asset (max_values: None, max_size: Some(122), added: 2597, mode: MaxEncodedLen) + /// Storage: Uniques Class (r:1 w:0) + /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) fn freeze() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `559` + // Estimated: `5250` + // Minimum execution time: 17_126 nanoseconds. + Weight::from_parts(17_572_000, 5250) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Uniques Asset (r:1 w:1) + /// Proof: Uniques Asset (max_values: None, max_size: Some(122), added: 2597, mode: MaxEncodedLen) + /// Storage: Uniques Class (r:1 w:0) + /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) fn thaw() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `559` + // Estimated: `5250` + // Minimum execution time: 17_209 nanoseconds. + Weight::from_parts(17_411_000, 5250) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) fn freeze_collection() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `381` + // Estimated: `2653` + // Minimum execution time: 13_048 nanoseconds. + Weight::from_parts(13_589_000, 2653) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) fn thaw_collection() -> Weight { - // 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)) - } - // Storage: Uniques OwnershipAcceptance (r:1 w:1) - // Storage: Uniques Class (r:1 w:1) - // Storage: Uniques ClassAccount (r:0 w:2) + // Proof Size summary in bytes: + // Measured: `381` + // Estimated: `2653` + // Minimum execution time: 12_908 nanoseconds. + Weight::from_parts(13_098_000, 2653) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Uniques OwnershipAcceptance (r:1 w:1) + /// Proof: Uniques OwnershipAcceptance (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) + /// Storage: Uniques ClassAccount (r:0 w:2) + /// Proof: Uniques ClassAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) fn transfer_ownership() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `455` + // Estimated: `5180` + // Minimum execution time: 20_629 nanoseconds. + Weight::from_parts(21_448_000, 5180) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) fn set_team() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `381` + // Estimated: `2653` + // Minimum execution time: 13_740 nanoseconds. + Weight::from_parts(14_020_000, 2653) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) + /// Storage: Uniques ClassAccount (r:0 w:1) + /// Proof: Uniques ClassAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) fn force_item_status() -> Weight { - // 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)) - } - // Storage: Uniques Class (r:1 w:1) - // Storage: Uniques InstanceMetadataOf (r:1 w:0) - // Storage: Uniques Attribute (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `381` + // Estimated: `2653` + // Minimum execution time: 16_293 nanoseconds. + Weight::from_parts(16_509_000, 2653) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) + /// Storage: Uniques InstanceMetadataOf (r:1 w:0) + /// Proof: Uniques InstanceMetadataOf (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) + /// Storage: Uniques Attribute (r:1 w:1) + /// Proof: Uniques Attribute (max_values: None, max_size: Some(364), added: 2839, mode: MaxEncodedLen) fn set_attribute() -> Weight { - // 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)) - } - // Storage: Uniques Class (r:1 w:1) - // Storage: Uniques InstanceMetadataOf (r:1 w:0) - // Storage: Uniques Attribute (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `611` + // Estimated: `8075` + // Minimum execution time: 33_560 nanoseconds. + Weight::from_parts(34_263_000, 8075) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) + /// Storage: Uniques InstanceMetadataOf (r:1 w:0) + /// Proof: Uniques InstanceMetadataOf (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) + /// Storage: Uniques Attribute (r:1 w:1) + /// Proof: Uniques Attribute (max_values: None, max_size: Some(364), added: 2839, mode: MaxEncodedLen) fn clear_attribute() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `1031` + // Estimated: `8075` + // Minimum execution time: 31_955 nanoseconds. + Weight::from_parts(32_447_000, 8075) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) + /// Storage: Uniques InstanceMetadataOf (r:1 w:1) + /// Proof: Uniques InstanceMetadataOf (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) fn set_metadata() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `447` + // Estimated: `5236` + // Minimum execution time: 25_520 nanoseconds. + Weight::from_parts(25_843_000, 5236) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) + /// Storage: Uniques InstanceMetadataOf (r:1 w:1) + /// Proof: Uniques InstanceMetadataOf (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) fn clear_metadata() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `611` + // Estimated: `5236` + // Minimum execution time: 25_812 nanoseconds. + Weight::from_parts(26_141_000, 5236) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) + /// Storage: Uniques ClassMetadataOf (r:1 w:1) + /// Proof: Uniques ClassMetadataOf (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) fn set_collection_metadata() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `381` + // Estimated: `5216` + // Minimum execution time: 25_055 nanoseconds. + Weight::from_parts(25_244_000, 5216) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: Uniques Class (r:1 w:0) + /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) + /// Storage: Uniques ClassMetadataOf (r:1 w:1) + /// Proof: Uniques ClassMetadataOf (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) fn clear_collection_metadata() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `525` + // Estimated: `5216` + // Minimum execution time: 23_311 nanoseconds. + Weight::from_parts(23_682_000, 5216) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Uniques Class (r:1 w:0) + /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) + /// Storage: Uniques Asset (r:1 w:1) + /// Proof: Uniques Asset (max_values: None, max_size: Some(122), added: 2597, mode: MaxEncodedLen) fn approve_transfer() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `559` + // Estimated: `5250` + // Minimum execution time: 17_709 nanoseconds. + Weight::from_parts(18_308_000, 5250) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Uniques Class (r:1 w:0) + /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) + /// Storage: Uniques Asset (r:1 w:1) + /// Proof: Uniques Asset (max_values: None, max_size: Some(122), added: 2597, mode: MaxEncodedLen) fn cancel_approval() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `592` + // Estimated: `5250` + // Minimum execution time: 17_656 nanoseconds. + Weight::from_parts(18_039_000, 5250) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Uniques OwnershipAcceptance (r:1 w:1) + /// Proof: Uniques OwnershipAcceptance (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) fn set_accept_ownership() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `109` + // Estimated: `2527` + // Minimum execution time: 14_615 nanoseconds. + Weight::from_parts(14_931_000, 2527) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Uniques CollectionMaxSupply (r:1 w:1) + /// Proof: Uniques CollectionMaxSupply (max_values: None, max_size: Some(24), added: 2499, mode: MaxEncodedLen) + /// Storage: Uniques Class (r:1 w:0) + /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) fn set_collection_max_supply() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `381` + // Estimated: `5152` + // Minimum execution time: 14_974 nanoseconds. + Weight::from_parts(15_314_000, 5152) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Uniques Asset (r:1 w:0) + /// Proof: Uniques Asset (max_values: None, max_size: Some(122), added: 2597, mode: MaxEncodedLen) + /// Storage: Uniques ItemPriceOf (r:0 w:1) + /// Proof: Uniques ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) fn set_price() -> Weight { - // 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)) - } - // 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) + // Proof Size summary in bytes: + // Measured: `358` + // Estimated: `2597` + // Minimum execution time: 15_444 nanoseconds. + Weight::from_parts(15_886_000, 2597) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Uniques Asset (r:1 w:1) + /// Proof: Uniques Asset (max_values: None, max_size: Some(122), added: 2597, mode: MaxEncodedLen) + /// Storage: Uniques ItemPriceOf (r:1 w:1) + /// Proof: Uniques ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) + /// Storage: Uniques Class (r:1 w:0) + /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) + /// Storage: Uniques Account (r:0 w:2) + /// Proof: Uniques Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) fn buy_item() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `703` + // Estimated: `7814` + // Minimum execution time: 35_628 nanoseconds. + Weight::from_parts(35_886_000, 7814) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) } } // For backwards compatibility and tests impl WeightInfo for () { - // Storage: Uniques Class (r:1 w:1) - // Storage: Uniques ClassAccount (r:0 w:1) + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) + /// Storage: Uniques ClassAccount (r:0 w:1) + /// Proof: Uniques ClassAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) fn create() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `281` + // Estimated: `2653` + // Minimum execution time: 24_242 nanoseconds. + Weight::from_parts(24_682_000, 2653) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) + /// Storage: Uniques ClassAccount (r:0 w:1) + /// Proof: Uniques ClassAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) fn force_create() -> Weight { - // 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)) - } - // 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 CollectionMaxSupply (r:0 w:1) - // Storage: Uniques Account (r:0 w:20) + // Proof Size summary in bytes: + // Measured: `109` + // Estimated: `2653` + // Minimum execution time: 14_145 nanoseconds. + Weight::from_parts(14_598_000, 2653) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) + /// Storage: Uniques Asset (r:1001 w:1000) + /// Proof: Uniques Asset (max_values: None, max_size: Some(122), added: 2597, mode: MaxEncodedLen) + /// Storage: Uniques ClassAccount (r:0 w:1) + /// Proof: Uniques ClassAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) + /// Storage: Uniques Attribute (r:0 w:1000) + /// Proof: Uniques Attribute (max_values: None, max_size: Some(364), added: 2839, mode: MaxEncodedLen) + /// Storage: Uniques ClassMetadataOf (r:0 w:1) + /// Proof: Uniques ClassMetadataOf (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) + /// Storage: Uniques InstanceMetadataOf (r:0 w:1000) + /// Proof: Uniques InstanceMetadataOf (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) + /// Storage: Uniques Account (r:0 w:1000) + /// Proof: Uniques Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) + /// Storage: Uniques CollectionMaxSupply (r:0 w:1) + /// Proof: Uniques CollectionMaxSupply (max_values: None, max_size: Some(24), added: 2499, mode: MaxEncodedLen) /// The range of component `n` is `[0, 1000]`. /// The range of component `m` is `[0, 1000]`. /// The range of component `a` is `[0, 1000]`. fn destroy(n: u32, m: u32, a: u32, ) -> Weight { - // 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)) - .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) + // Proof Size summary in bytes: + // Measured: `450 + n * (108 ±0) + m * (56 ±0) + a * (107 ±0)` + // Estimated: `5250 + n * (2597 ±0)` + // Minimum execution time: 2_404_081 nanoseconds. + Weight::from_parts(2_419_004_000, 5250) + // Standard Error: 27_175 + .saturating_add(Weight::from_ref_time(8_616_904).saturating_mul(n.into())) + // Standard Error: 27_175 + .saturating_add(Weight::from_ref_time(334_249).saturating_mul(m.into())) + // Standard Error: 27_175 + .saturating_add(Weight::from_ref_time(213_038).saturating_mul(a.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + .saturating_add(RocksDbWeight::get().writes((2_u64).saturating_mul(n.into()))) + .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(m.into()))) + .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(a.into()))) + .saturating_add(Weight::from_proof_size(2597).saturating_mul(n.into())) + } + /// Storage: Uniques Asset (r:1 w:1) + /// Proof: Uniques Asset (max_values: None, max_size: Some(122), added: 2597, mode: MaxEncodedLen) + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) + /// Storage: Uniques CollectionMaxSupply (r:1 w:0) + /// Proof: Uniques CollectionMaxSupply (max_values: None, max_size: Some(24), added: 2499, mode: MaxEncodedLen) + /// Storage: Uniques Account (r:0 w:1) + /// Proof: Uniques Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) fn mint() -> Weight { - // 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)) - } - // 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) + // Proof Size summary in bytes: + // Measured: `381` + // Estimated: `7749` + // Minimum execution time: 29_326 nanoseconds. + Weight::from_parts(29_671_000, 7749) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) + /// Storage: Uniques Asset (r:1 w:1) + /// Proof: Uniques Asset (max_values: None, max_size: Some(122), added: 2597, mode: MaxEncodedLen) + /// Storage: Uniques Account (r:0 w:1) + /// Proof: Uniques Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) + /// Storage: Uniques ItemPriceOf (r:0 w:1) + /// Proof: Uniques ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) fn burn() -> Weight { - // 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)) - } - // 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) + // Proof Size summary in bytes: + // Measured: `559` + // Estimated: `5250` + // Minimum execution time: 30_497 nanoseconds. + Weight::from_parts(30_714_000, 5250) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + } + /// Storage: Uniques Class (r:1 w:0) + /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) + /// Storage: Uniques Asset (r:1 w:1) + /// Proof: Uniques Asset (max_values: None, max_size: Some(122), added: 2597, mode: MaxEncodedLen) + /// Storage: Uniques Account (r:0 w:2) + /// Proof: Uniques Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) + /// Storage: Uniques ItemPriceOf (r:0 w:1) + /// Proof: Uniques ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) fn transfer() -> Weight { - // 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)) - } - // Storage: Uniques Class (r:1 w:1) - // Storage: Uniques Asset (r:102 w:102) + // Proof Size summary in bytes: + // Measured: `559` + // Estimated: `5250` + // Minimum execution time: 24_212 nanoseconds. + Weight::from_parts(24_681_000, 5250) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + } + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) + /// Storage: Uniques Asset (r:5000 w:5000) + /// Proof: Uniques Asset (max_values: None, max_size: Some(122), added: 2597, mode: MaxEncodedLen) /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { - // 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)) - .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) + // Proof Size summary in bytes: + // Measured: `837 + i * (108 ±0)` + // Estimated: `2653 + i * (2597 ±0)` + // Minimum execution time: 13_633 nanoseconds. + Weight::from_parts(13_797_000, 2653) + // Standard Error: 9_293 + .saturating_add(Weight::from_ref_time(11_163_914).saturating_mul(i.into())) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(i.into()))) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(i.into()))) + .saturating_add(Weight::from_proof_size(2597).saturating_mul(i.into())) + } + /// Storage: Uniques Asset (r:1 w:1) + /// Proof: Uniques Asset (max_values: None, max_size: Some(122), added: 2597, mode: MaxEncodedLen) + /// Storage: Uniques Class (r:1 w:0) + /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) fn freeze() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `559` + // Estimated: `5250` + // Minimum execution time: 17_126 nanoseconds. + Weight::from_parts(17_572_000, 5250) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Uniques Asset (r:1 w:1) + /// Proof: Uniques Asset (max_values: None, max_size: Some(122), added: 2597, mode: MaxEncodedLen) + /// Storage: Uniques Class (r:1 w:0) + /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) fn thaw() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `559` + // Estimated: `5250` + // Minimum execution time: 17_209 nanoseconds. + Weight::from_parts(17_411_000, 5250) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) fn freeze_collection() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `381` + // Estimated: `2653` + // Minimum execution time: 13_048 nanoseconds. + Weight::from_parts(13_589_000, 2653) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) fn thaw_collection() -> Weight { - // 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)) - } - // Storage: Uniques OwnershipAcceptance (r:1 w:1) - // Storage: Uniques Class (r:1 w:1) - // Storage: Uniques ClassAccount (r:0 w:2) + // Proof Size summary in bytes: + // Measured: `381` + // Estimated: `2653` + // Minimum execution time: 12_908 nanoseconds. + Weight::from_parts(13_098_000, 2653) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Uniques OwnershipAcceptance (r:1 w:1) + /// Proof: Uniques OwnershipAcceptance (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) + /// Storage: Uniques ClassAccount (r:0 w:2) + /// Proof: Uniques ClassAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) fn transfer_ownership() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `455` + // Estimated: `5180` + // Minimum execution time: 20_629 nanoseconds. + Weight::from_parts(21_448_000, 5180) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + } + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) fn set_team() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `381` + // Estimated: `2653` + // Minimum execution time: 13_740 nanoseconds. + Weight::from_parts(14_020_000, 2653) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) + /// Storage: Uniques ClassAccount (r:0 w:1) + /// Proof: Uniques ClassAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) fn force_item_status() -> Weight { - // 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)) - } - // Storage: Uniques Class (r:1 w:1) - // Storage: Uniques InstanceMetadataOf (r:1 w:0) - // Storage: Uniques Attribute (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `381` + // Estimated: `2653` + // Minimum execution time: 16_293 nanoseconds. + Weight::from_parts(16_509_000, 2653) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) + /// Storage: Uniques InstanceMetadataOf (r:1 w:0) + /// Proof: Uniques InstanceMetadataOf (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) + /// Storage: Uniques Attribute (r:1 w:1) + /// Proof: Uniques Attribute (max_values: None, max_size: Some(364), added: 2839, mode: MaxEncodedLen) fn set_attribute() -> Weight { - // 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)) - } - // Storage: Uniques Class (r:1 w:1) - // Storage: Uniques InstanceMetadataOf (r:1 w:0) - // Storage: Uniques Attribute (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `611` + // Estimated: `8075` + // Minimum execution time: 33_560 nanoseconds. + Weight::from_parts(34_263_000, 8075) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) + /// Storage: Uniques InstanceMetadataOf (r:1 w:0) + /// Proof: Uniques InstanceMetadataOf (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) + /// Storage: Uniques Attribute (r:1 w:1) + /// Proof: Uniques Attribute (max_values: None, max_size: Some(364), added: 2839, mode: MaxEncodedLen) fn clear_attribute() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `1031` + // Estimated: `8075` + // Minimum execution time: 31_955 nanoseconds. + Weight::from_parts(32_447_000, 8075) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) + /// Storage: Uniques InstanceMetadataOf (r:1 w:1) + /// Proof: Uniques InstanceMetadataOf (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) fn set_metadata() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `447` + // Estimated: `5236` + // Minimum execution time: 25_520 nanoseconds. + Weight::from_parts(25_843_000, 5236) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) + /// Storage: Uniques InstanceMetadataOf (r:1 w:1) + /// Proof: Uniques InstanceMetadataOf (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) fn clear_metadata() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `611` + // Estimated: `5236` + // Minimum execution time: 25_812 nanoseconds. + Weight::from_parts(26_141_000, 5236) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: Uniques Class (r:1 w:1) + /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) + /// Storage: Uniques ClassMetadataOf (r:1 w:1) + /// Proof: Uniques ClassMetadataOf (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) fn set_collection_metadata() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `381` + // Estimated: `5216` + // Minimum execution time: 25_055 nanoseconds. + Weight::from_parts(25_244_000, 5216) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: Uniques Class (r:1 w:0) + /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) + /// Storage: Uniques ClassMetadataOf (r:1 w:1) + /// Proof: Uniques ClassMetadataOf (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) fn clear_collection_metadata() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `525` + // Estimated: `5216` + // Minimum execution time: 23_311 nanoseconds. + Weight::from_parts(23_682_000, 5216) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Uniques Class (r:1 w:0) + /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) + /// Storage: Uniques Asset (r:1 w:1) + /// Proof: Uniques Asset (max_values: None, max_size: Some(122), added: 2597, mode: MaxEncodedLen) fn approve_transfer() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `559` + // Estimated: `5250` + // Minimum execution time: 17_709 nanoseconds. + Weight::from_parts(18_308_000, 5250) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Uniques Class (r:1 w:0) + /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) + /// Storage: Uniques Asset (r:1 w:1) + /// Proof: Uniques Asset (max_values: None, max_size: Some(122), added: 2597, mode: MaxEncodedLen) fn cancel_approval() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `592` + // Estimated: `5250` + // Minimum execution time: 17_656 nanoseconds. + Weight::from_parts(18_039_000, 5250) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Uniques OwnershipAcceptance (r:1 w:1) + /// Proof: Uniques OwnershipAcceptance (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) fn set_accept_ownership() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `109` + // Estimated: `2527` + // Minimum execution time: 14_615 nanoseconds. + Weight::from_parts(14_931_000, 2527) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Uniques CollectionMaxSupply (r:1 w:1) + /// Proof: Uniques CollectionMaxSupply (max_values: None, max_size: Some(24), added: 2499, mode: MaxEncodedLen) + /// Storage: Uniques Class (r:1 w:0) + /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) fn set_collection_max_supply() -> Weight { - // 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) + // Proof Size summary in bytes: + // Measured: `381` + // Estimated: `5152` + // Minimum execution time: 14_974 nanoseconds. + Weight::from_parts(15_314_000, 5152) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Uniques Asset (r:1 w:0) + /// Proof: Uniques Asset (max_values: None, max_size: Some(122), added: 2597, mode: MaxEncodedLen) + /// Storage: Uniques ItemPriceOf (r:0 w:1) + /// Proof: Uniques ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) fn set_price() -> Weight { - // 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)) - } - // 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) + // Proof Size summary in bytes: + // Measured: `358` + // Estimated: `2597` + // Minimum execution time: 15_444 nanoseconds. + Weight::from_parts(15_886_000, 2597) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Uniques Asset (r:1 w:1) + /// Proof: Uniques Asset (max_values: None, max_size: Some(122), added: 2597, mode: MaxEncodedLen) + /// Storage: Uniques ItemPriceOf (r:1 w:1) + /// Proof: Uniques ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) + /// Storage: Uniques Class (r:1 w:0) + /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) + /// Storage: Uniques Account (r:0 w:2) + /// Proof: Uniques Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) fn buy_item() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `703` + // Estimated: `7814` + // Minimum execution time: 35_628 nanoseconds. + Weight::from_parts(35_886_000, 7814) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) } } diff --git a/frame/utility/src/weights.rs b/frame/utility/src/weights.rs index eac94e44b8dbf..7b8c261d1db8b 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) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2023 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,7 +18,8 @@ //! Autogenerated weights for pallet_utility //! //! 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: `[]` +//! DATE: 2023-01-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -59,32 +60,47 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { /// The range of component `c` is `[0, 1000]`. fn batch(c: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 6_742 nanoseconds. + Weight::from_ref_time(16_087_635) + // Standard Error: 2_411 + .saturating_add(Weight::from_ref_time(3_665_506).saturating_mul(c.into())) } fn as_derivative() -> Weight { - // Minimum execution time: 6_799 nanoseconds. - Weight::from_ref_time(6_976_000 as u64) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 4_802 nanoseconds. + Weight::from_ref_time(5_269_000) } /// The range of component `c` is `[0, 1000]`. fn batch_all(c: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 7_100 nanoseconds. + Weight::from_ref_time(14_090_381) + // Standard Error: 1_917 + .saturating_add(Weight::from_ref_time(3_744_891).saturating_mul(c.into())) } fn dispatch_as() -> Weight { - // Minimum execution time: 16_597 nanoseconds. - Weight::from_ref_time(16_950_000 as u64) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 8_840 nanoseconds. + Weight::from_ref_time(9_280_000) } /// The range of component `c` is `[0, 1000]`. fn force_batch(c: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 7_245 nanoseconds. + Weight::from_ref_time(14_292_923) + // Standard Error: 1_803 + .saturating_add(Weight::from_ref_time(3_645_950).saturating_mul(c.into())) } } @@ -92,31 +108,46 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { /// The range of component `c` is `[0, 1000]`. fn batch(c: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 6_742 nanoseconds. + Weight::from_ref_time(16_087_635) + // Standard Error: 2_411 + .saturating_add(Weight::from_ref_time(3_665_506).saturating_mul(c.into())) } fn as_derivative() -> Weight { - // Minimum execution time: 6_799 nanoseconds. - Weight::from_ref_time(6_976_000 as u64) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 4_802 nanoseconds. + Weight::from_ref_time(5_269_000) } /// The range of component `c` is `[0, 1000]`. fn batch_all(c: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 7_100 nanoseconds. + Weight::from_ref_time(14_090_381) + // Standard Error: 1_917 + .saturating_add(Weight::from_ref_time(3_744_891).saturating_mul(c.into())) } fn dispatch_as() -> Weight { - // Minimum execution time: 16_597 nanoseconds. - Weight::from_ref_time(16_950_000 as u64) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 8_840 nanoseconds. + Weight::from_ref_time(9_280_000) } /// The range of component `c` is `[0, 1000]`. fn force_batch(c: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 7_245 nanoseconds. + Weight::from_ref_time(14_292_923) + // Standard Error: 1_803 + .saturating_add(Weight::from_ref_time(3_645_950).saturating_mul(c.into())) } } diff --git a/frame/vesting/src/weights.rs b/frame/vesting/src/weights.rs index 5462445414719..a6a70fb56f45a 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) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2023 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -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-11-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-01-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -60,244 +61,336 @@ pub trait WeightInfo { /// Weights for pallet_vesting using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - // Storage: Vesting Vesting (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[1, 28]`. fn vest_locked(l: u32, s: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `444 + l * (25 ±0) + s * (36 ±0)` + // Estimated: `7306` + // Minimum execution time: 28_062 nanoseconds. + Weight::from_parts(26_857_563, 7306) + // Standard Error: 623 + .saturating_add(Weight::from_ref_time(55_988).saturating_mul(l.into())) + // Standard Error: 1_109 + .saturating_add(Weight::from_ref_time(59_714).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } - // Storage: Vesting Vesting (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[1, 28]`. fn vest_unlocked(l: u32, s: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `444 + l * (25 ±0) + s * (36 ±0)` + // Estimated: `7306` + // Minimum execution time: 27_027 nanoseconds. + Weight::from_parts(26_509_364, 7306) + // Standard Error: 815 + .saturating_add(Weight::from_ref_time(54_711).saturating_mul(l.into())) + // Standard Error: 1_451 + .saturating_add(Weight::from_ref_time(32_792).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } - // Storage: Vesting Vesting (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[1, 28]`. fn vest_other_locked(l: u32, s: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `579 + l * (25 ±0) + s * (36 ±0)` + // Estimated: `9909` + // Minimum execution time: 29_554 nanoseconds. + Weight::from_parts(28_269_203, 9909) + // Standard Error: 623 + .saturating_add(Weight::from_ref_time(59_058).saturating_mul(l.into())) + // Standard Error: 1_108 + .saturating_add(Weight::from_ref_time(63_429).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) } - // Storage: Vesting Vesting (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[1, 28]`. fn vest_other_unlocked(l: u32, s: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `579 + l * (25 ±0) + s * (36 ±0)` + // Estimated: `9909` + // Minimum execution time: 28_546 nanoseconds. + Weight::from_parts(28_299_251, 9909) + // Standard Error: 786 + .saturating_add(Weight::from_ref_time(53_401).saturating_mul(l.into())) + // Standard Error: 1_399 + .saturating_add(Weight::from_ref_time(29_713).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) } - // Storage: Vesting Vesting (r:1 w:1) - // Storage: System Account (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[0, 27]`. fn vested_transfer(l: u32, s: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `650 + l * (25 ±0) + s * (36 ±0)` + // Estimated: `9909` + // Minimum execution time: 43_436 nanoseconds. + Weight::from_parts(44_885_707, 9909) + // Standard Error: 1_516 + .saturating_add(Weight::from_ref_time(59_066).saturating_mul(l.into())) + // Standard Error: 2_698 + .saturating_add(Weight::from_ref_time(32_053).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) } - // Storage: Vesting Vesting (r:1 w:1) - // Storage: System Account (r:2 w:2) - // Storage: Balances Locks (r:1 w:1) + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) /// 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 { - // 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)) + // Proof Size summary in bytes: + // Measured: `785 + l * (25 ±0) + s * (36 ±0)` + // Estimated: `12512` + // Minimum execution time: 45_805 nanoseconds. + Weight::from_parts(46_869_490, 12512) + // Standard Error: 1_445 + .saturating_add(Weight::from_ref_time(52_654).saturating_mul(l.into())) + // Standard Error: 2_571 + .saturating_add(Weight::from_ref_time(34_202).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) } - // Storage: Vesting Vesting (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[2, 28]`. fn not_unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `577 + l * (25 ±0) + s * (36 ±0)` + // Estimated: `9909` + // Minimum execution time: 30_460 nanoseconds. + Weight::from_parts(29_407_637, 9909) + // Standard Error: 794 + .saturating_add(Weight::from_ref_time(63_757).saturating_mul(l.into())) + // Standard Error: 1_466 + .saturating_add(Weight::from_ref_time(56_032).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) } - // Storage: Vesting Vesting (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[2, 28]`. fn unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `577 + l * (25 ±0) + s * (36 ±0)` + // Estimated: `9909` + // Minimum execution time: 30_413 nanoseconds. + Weight::from_parts(29_350_467, 9909) + // Standard Error: 724 + .saturating_add(Weight::from_ref_time(65_366).saturating_mul(l.into())) + // Standard Error: 1_337 + .saturating_add(Weight::from_ref_time(53_799).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) } } // For backwards compatibility and tests impl WeightInfo for () { - // Storage: Vesting Vesting (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[1, 28]`. fn vest_locked(l: u32, s: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `444 + l * (25 ±0) + s * (36 ±0)` + // Estimated: `7306` + // Minimum execution time: 28_062 nanoseconds. + Weight::from_parts(26_857_563, 7306) + // Standard Error: 623 + .saturating_add(Weight::from_ref_time(55_988).saturating_mul(l.into())) + // Standard Error: 1_109 + .saturating_add(Weight::from_ref_time(59_714).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } - // Storage: Vesting Vesting (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[1, 28]`. fn vest_unlocked(l: u32, s: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `444 + l * (25 ±0) + s * (36 ±0)` + // Estimated: `7306` + // Minimum execution time: 27_027 nanoseconds. + Weight::from_parts(26_509_364, 7306) + // Standard Error: 815 + .saturating_add(Weight::from_ref_time(54_711).saturating_mul(l.into())) + // Standard Error: 1_451 + .saturating_add(Weight::from_ref_time(32_792).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } - // Storage: Vesting Vesting (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[1, 28]`. fn vest_other_locked(l: u32, s: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `579 + l * (25 ±0) + s * (36 ±0)` + // Estimated: `9909` + // Minimum execution time: 29_554 nanoseconds. + Weight::from_parts(28_269_203, 9909) + // Standard Error: 623 + .saturating_add(Weight::from_ref_time(59_058).saturating_mul(l.into())) + // Standard Error: 1_108 + .saturating_add(Weight::from_ref_time(63_429).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) } - // Storage: Vesting Vesting (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[1, 28]`. fn vest_other_unlocked(l: u32, s: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `579 + l * (25 ±0) + s * (36 ±0)` + // Estimated: `9909` + // Minimum execution time: 28_546 nanoseconds. + Weight::from_parts(28_299_251, 9909) + // Standard Error: 786 + .saturating_add(Weight::from_ref_time(53_401).saturating_mul(l.into())) + // Standard Error: 1_399 + .saturating_add(Weight::from_ref_time(29_713).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) } - // Storage: Vesting Vesting (r:1 w:1) - // Storage: System Account (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[0, 27]`. fn vested_transfer(l: u32, s: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `650 + l * (25 ±0) + s * (36 ±0)` + // Estimated: `9909` + // Minimum execution time: 43_436 nanoseconds. + Weight::from_parts(44_885_707, 9909) + // Standard Error: 1_516 + .saturating_add(Weight::from_ref_time(59_066).saturating_mul(l.into())) + // Standard Error: 2_698 + .saturating_add(Weight::from_ref_time(32_053).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) } - // Storage: Vesting Vesting (r:1 w:1) - // Storage: System Account (r:2 w:2) - // Storage: Balances Locks (r:1 w:1) + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) /// 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 { - // 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)) + // Proof Size summary in bytes: + // Measured: `785 + l * (25 ±0) + s * (36 ±0)` + // Estimated: `12512` + // Minimum execution time: 45_805 nanoseconds. + Weight::from_parts(46_869_490, 12512) + // Standard Error: 1_445 + .saturating_add(Weight::from_ref_time(52_654).saturating_mul(l.into())) + // Standard Error: 2_571 + .saturating_add(Weight::from_ref_time(34_202).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) } - // Storage: Vesting Vesting (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[2, 28]`. fn not_unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `577 + l * (25 ±0) + s * (36 ±0)` + // Estimated: `9909` + // Minimum execution time: 30_460 nanoseconds. + Weight::from_parts(29_407_637, 9909) + // Standard Error: 794 + .saturating_add(Weight::from_ref_time(63_757).saturating_mul(l.into())) + // Standard Error: 1_466 + .saturating_add(Weight::from_ref_time(56_032).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) } - // Storage: Vesting Vesting (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) - // Storage: System Account (r:1 w:1) + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[2, 28]`. fn unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `577 + l * (25 ±0) + s * (36 ±0)` + // Estimated: `9909` + // Minimum execution time: 30_413 nanoseconds. + Weight::from_parts(29_350_467, 9909) + // Standard Error: 724 + .saturating_add(Weight::from_ref_time(65_366).saturating_mul(l.into())) + // Standard Error: 1_337 + .saturating_add(Weight::from_ref_time(53_799).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) } } diff --git a/frame/whitelist/src/benchmarking.rs b/frame/whitelist/src/benchmarking.rs index 923adc6ccf8ca..569b13c12da31 100644 --- a/frame/whitelist/src/benchmarking.rs +++ b/frame/whitelist/src/benchmarking.rs @@ -62,6 +62,10 @@ benchmarks! { // 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. + #[pov_mode = MaxEncodedLen { + // Use measured PoV size for the Preimages since we pass in a length witness. + Preimage::PreimageFor: Measured + }] dispatch_whitelisted_call { // NOTE: we remove `10` because we need some bytes to encode the variants and vec length let n in 1 .. T::Preimages::MAX_LENGTH as u32 - 10; diff --git a/frame/whitelist/src/weights.rs b/frame/whitelist/src/weights.rs index efd48d657826b..d5bc37c5759c8 100644 --- a/frame/whitelist/src/weights.rs +++ b/frame/whitelist/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2023 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,25 +18,25 @@ //! Autogenerated weights for pallet_whitelist //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-12-05, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! DATE: 2023-01-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! 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_whitelist // --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_whitelist -// --chain=dev -// --header=./HEADER-APACHE2 // --output=./frame/whitelist/src/weights.rs +// --header=./HEADER-APACHE2 // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -57,86 +57,130 @@ pub trait WeightInfo { /// 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) + /// Storage: Whitelist WhitelistedCall (r:1 w:1) + /// Proof: Whitelist WhitelistedCall (max_values: None, max_size: Some(40), added: 2515, mode: MaxEncodedLen) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) fn whitelist_call() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `217` + // Estimated: `5081` + // Minimum execution time: 18_618 nanoseconds. + Weight::from_parts(19_133_000, 5081) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } - // Storage: Whitelist WhitelistedCall (r:1 w:1) - // Storage: Preimage StatusFor (r:1 w:1) + /// Storage: Whitelist WhitelistedCall (r:1 w:1) + /// Proof: Whitelist WhitelistedCall (max_values: None, max_size: Some(40), added: 2515, mode: MaxEncodedLen) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) fn remove_whitelisted_call() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `346` + // Estimated: `5081` + // Minimum execution time: 16_685 nanoseconds. + Weight::from_parts(17_325_000, 5081) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } - // Storage: Whitelist WhitelistedCall (r:1 w:1) - // Storage: Preimage PreimageFor (r:1 w:1) - // Storage: Preimage StatusFor (r:1 w:1) + /// Storage: Whitelist WhitelistedCall (r:1 w:1) + /// Proof: Whitelist WhitelistedCall (max_values: None, max_size: Some(40), added: 2515, mode: MaxEncodedLen) + /// Storage: Preimage PreimageFor (r:1 w:1) + /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: Measured) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) /// The range of component `n` is `[1, 4194294]`. fn dispatch_whitelisted_call(n: u32, ) -> Weight { - // Minimum execution time: 36_685 nanoseconds. - Weight::from_ref_time(37_167_000) + // Proof Size summary in bytes: + // Measured: `454 + n * (1 ±0)` + // Estimated: `8007 + n * (1 ±0)` + // Minimum execution time: 27_539 nanoseconds. + Weight::from_parts(27_950_000, 8007) // 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)) + .saturating_add(Weight::from_ref_time(1_134).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(1).saturating_mul(n.into())) } - // Storage: Whitelist WhitelistedCall (r:1 w:1) - // Storage: Preimage StatusFor (r:1 w:1) + /// Storage: Whitelist WhitelistedCall (r:1 w:1) + /// Proof: Whitelist WhitelistedCall (max_values: None, max_size: Some(40), added: 2515, mode: MaxEncodedLen) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) /// The range of component `n` is `[1, 10000]`. fn dispatch_whitelisted_call_with_preimage(n: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `346` + // Estimated: `5081` + // Minimum execution time: 20_581 nanoseconds. + Weight::from_parts(21_762_318, 5081) + // Standard Error: 4 + .saturating_add(Weight::from_ref_time(1_480).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } } // For backwards compatibility and tests impl WeightInfo for () { - // Storage: Whitelist WhitelistedCall (r:1 w:1) - // Storage: Preimage StatusFor (r:1 w:1) + /// Storage: Whitelist WhitelistedCall (r:1 w:1) + /// Proof: Whitelist WhitelistedCall (max_values: None, max_size: Some(40), added: 2515, mode: MaxEncodedLen) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) fn whitelist_call() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `217` + // Estimated: `5081` + // Minimum execution time: 18_618 nanoseconds. + Weight::from_parts(19_133_000, 5081) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } - // Storage: Whitelist WhitelistedCall (r:1 w:1) - // Storage: Preimage StatusFor (r:1 w:1) + /// Storage: Whitelist WhitelistedCall (r:1 w:1) + /// Proof: Whitelist WhitelistedCall (max_values: None, max_size: Some(40), added: 2515, mode: MaxEncodedLen) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) fn remove_whitelisted_call() -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `346` + // Estimated: `5081` + // Minimum execution time: 16_685 nanoseconds. + Weight::from_parts(17_325_000, 5081) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } - // Storage: Whitelist WhitelistedCall (r:1 w:1) - // Storage: Preimage PreimageFor (r:1 w:1) - // Storage: Preimage StatusFor (r:1 w:1) + /// Storage: Whitelist WhitelistedCall (r:1 w:1) + /// Proof: Whitelist WhitelistedCall (max_values: None, max_size: Some(40), added: 2515, mode: MaxEncodedLen) + /// Storage: Preimage PreimageFor (r:1 w:1) + /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: Measured) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) /// The range of component `n` is `[1, 4194294]`. fn dispatch_whitelisted_call(n: u32, ) -> Weight { - // Minimum execution time: 36_685 nanoseconds. - Weight::from_ref_time(37_167_000) + // Proof Size summary in bytes: + // Measured: `454 + n * (1 ±0)` + // Estimated: `8007 + n * (1 ±0)` + // Minimum execution time: 27_539 nanoseconds. + Weight::from_parts(27_950_000, 8007) // 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)) + .saturating_add(Weight::from_ref_time(1_134).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(1).saturating_mul(n.into())) } - // Storage: Whitelist WhitelistedCall (r:1 w:1) - // Storage: Preimage StatusFor (r:1 w:1) + /// Storage: Whitelist WhitelistedCall (r:1 w:1) + /// Proof: Whitelist WhitelistedCall (max_values: None, max_size: Some(40), added: 2515, mode: MaxEncodedLen) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) /// The range of component `n` is `[1, 10000]`. fn dispatch_whitelisted_call_with_preimage(n: u32, ) -> Weight { - // 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)) + // Proof Size summary in bytes: + // Measured: `346` + // Estimated: `5081` + // Minimum execution time: 20_581 nanoseconds. + Weight::from_parts(21_762_318, 5081) + // Standard Error: 4 + .saturating_add(Weight::from_ref_time(1_480).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } } diff --git a/primitives/storage/src/lib.rs b/primitives/storage/src/lib.rs index 237787710a7e7..68d7b90639886 100644 --- a/primitives/storage/src/lib.rs +++ b/primitives/storage/src/lib.rs @@ -200,6 +200,8 @@ pub mod well_known_keys { pub const HEAP_PAGES: &[u8] = b":heappages"; /// Current extrinsic index (u32) is stored under this key. + /// + /// Encodes to `0x3a65787472696e7369635f696e646578`. pub const EXTRINSIC_INDEX: &[u8] = b":extrinsic_index"; /// Prefix of child storage keys. diff --git a/scripts/run_all_benchmarks.sh b/scripts/run_all_benchmarks.sh index dd5d2e182baf2..f122be577c52d 100755 --- a/scripts/run_all_benchmarks.sh +++ b/scripts/run_all_benchmarks.sh @@ -74,6 +74,8 @@ EXCLUDED_PALLETS=( "pallet_grandpa" "pallet_mmr" "pallet_offences" + # Only used for testing, does not need real weights. + "frame_benchmarking_pallet_pov" ) # Load all pallet names in an array. diff --git a/utils/frame/benchmarking-cli/src/pallet/command.rs b/utils/frame/benchmarking-cli/src/pallet/command.rs index 242f0e685290f..ec1be27614cc9 100644 --- a/utils/frame/benchmarking-cli/src/pallet/command.rs +++ b/utils/frame/benchmarking-cli/src/pallet/command.rs @@ -38,7 +38,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::{collections::HashMap, fmt::Debug, fs, sync::Arc, time}; +use std::{collections::HashMap, fmt::Debug, fs, str::FromStr, sync::Arc, time}; /// Logging target const LOG_TARGET: &'static str = "frame::benchmark::pallet"; @@ -54,6 +54,34 @@ pub(crate) struct ComponentRange { max: u32, } +/// How the PoV size of a storage item should be estimated. +#[derive(clap::ValueEnum, Debug, Eq, PartialEq, Clone, Copy)] +pub enum PovEstimationMode { + /// Use the maximal encoded length as provided by [`codec::MaxEncodedLen`]. + MaxEncodedLen, + /// Measure the accessed value size in the pallet benchmarking and add some trie overhead. + Measured, + /// Do not estimate the PoV size for this storage item or benchmark. + Ignored, +} + +impl FromStr for PovEstimationMode { + type Err = &'static str; + + fn from_str(s: &str) -> std::result::Result { + match s { + "MaxEncodedLen" => Ok(Self::MaxEncodedLen), + "Measured" => Ok(Self::Measured), + "Ignored" => Ok(Self::Ignored), + _ => unreachable!("The benchmark! macro should have prevented this"), + } + } +} + +/// Maps (pallet, benchmark) -> ((pallet, storage) -> PovEstimationMode) +pub(crate) type PovModesMap = + HashMap<(Vec, Vec), HashMap<(String, String), PovEstimationMode>>; + // This takes multiple benchmark batches and combines all the results where the pallet, instance, // and benchmark are the same. fn combine_batches( @@ -165,11 +193,19 @@ impl PalletCmd { let state_with_tracking = BenchmarkingState::::new( genesis_storage.clone(), cache_size, - self.record_proof, + // Record proof size + true, + // Enable storage tracking true, )?; - let state_without_tracking = - BenchmarkingState::::new(genesis_storage, cache_size, self.record_proof, false)?; + let state_without_tracking = BenchmarkingState::::new( + genesis_storage, + cache_size, + // Do not record proof size + false, + // Do not enable storage tracking + false, + )?; let executor = NativeElseWasmExecutor::::new( execution_method_from_cli(self.wasm_method, self.wasmtime_instantiation_strategy), self.heap_pages, @@ -222,10 +258,27 @@ impl PalletCmd { item.pallet.clone(), benchmark.name.clone(), benchmark.components.clone(), + benchmark.pov_modes.clone(), )) } } }); + // Convert `Vec` to `String` for better readability. + let benchmarks_to_run: Vec<_> = benchmarks_to_run + .into_iter() + .map(|b| { + ( + b.0, + b.1, + b.2, + b.3.into_iter() + .map(|(p, s)| { + (String::from_utf8(p).unwrap(), String::from_utf8(s).unwrap()) + }) + .collect(), + ) + }) + .collect(); if benchmarks_to_run.is_empty() { return Err("No benchmarks found which match your input.".into()) @@ -243,8 +296,9 @@ impl PalletCmd { let mut timer = time::SystemTime::now(); // Maps (pallet, extrinsic) to its component ranges. let mut component_ranges = HashMap::<(Vec, Vec), Vec>::new(); + let pov_modes = Self::parse_pov_modes(&benchmarks_to_run)?; - for (pallet, extrinsic, components) in benchmarks_to_run { + for (pallet, extrinsic, components, _) in benchmarks_to_run.clone() { log::info!( target: LOG_TARGET, "Starting benchmark: {}::{}", @@ -429,7 +483,7 @@ impl PalletCmd { // Combine all of the benchmark results, so that benchmarks of the same pallet/function // are together. let batches = combine_batches(batches, batches_db); - self.output(&batches, &storage_info, &component_ranges) + self.output(&batches, &storage_info, &component_ranges, pov_modes) } fn output( @@ -437,21 +491,31 @@ impl PalletCmd { batches: &[BenchmarkBatchSplitResults], storage_info: &[StorageInfo], component_ranges: &HashMap<(Vec, Vec), Vec>, + pov_modes: PovModesMap, ) -> 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. - self.print_summary(&batches, &storage_info) + self.print_summary(&batches, &storage_info, pov_modes.clone()) } // Create the weights.rs file. if let Some(output_path) = &self.output { - writer::write_results(&batches, &storage_info, &component_ranges, output_path, self)?; + writer::write_results( + &batches, + &storage_info, + &component_ranges, + pov_modes, + self.default_pov_mode, + output_path, + self, + )?; } Ok(()) } + /// Re-analyze a batch historic benchmark timing data. Will not take the PoV into account. fn output_from_results(&self, batches: &[BenchmarkBatchSplitResults]) -> Result<()> { let mut component_ranges = HashMap::<(Vec, Vec), HashMap>::new(); @@ -484,7 +548,7 @@ impl PalletCmd { }) .collect(); - self.output(batches, &[], &component_ranges) + self.output(batches, &[], &component_ranges, Default::default()) } /// Jsonifies the passed batches and writes them to stdout or into a file. @@ -507,7 +571,12 @@ impl PalletCmd { } /// Prints the results as human-readable summary without raw timing data. - fn print_summary(&self, batches: &[BenchmarkBatchSplitResults], storage_info: &[StorageInfo]) { + fn print_summary( + &self, + batches: &[BenchmarkBatchSplitResults], + storage_info: &[StorageInfo], + pov_modes: PovModesMap, + ) { for batch in batches.iter() { // Print benchmark metadata println!( @@ -526,13 +595,32 @@ impl PalletCmd { } if !self.no_storage_info { - let mut comments: Vec = Default::default(); - writer::add_storage_comments(&mut comments, &batch.db_results, storage_info); + let mut storage_per_prefix = HashMap::, Vec>::new(); + let pov_mode = pov_modes + .get(&(batch.pallet.clone(), batch.benchmark.clone())) + .cloned() + .unwrap_or_default(); + + let comments = writer::process_storage_results( + &mut storage_per_prefix, + &batch.db_results, + storage_info, + &pov_mode, + self.default_pov_mode, + self.worst_case_map_values, + self.additional_trie_layers, + ); println!("Raw Storage Info\n========"); for comment in comments { println!("{}", comment); } println!(); + + println!("-- Proof Sizes --\n"); + for result in batch.db_results.iter() { + println!("{} bytes", result.proof_size); + } + println!(); } // Conduct analysis. @@ -553,6 +641,11 @@ impl PalletCmd { { println!("Writes = {:?}", analysis); } + if let Some(analysis) = + Analysis::median_slopes(&batch.db_results, BenchmarkSelector::ProofSize) + { + println!("Recorded proof Size = {:?}", analysis); + } println!(); } if !self.no_min_squares { @@ -572,10 +665,60 @@ impl PalletCmd { { println!("Writes = {:?}", analysis); } + if let Some(analysis) = + Analysis::min_squares_iqr(&batch.db_results, BenchmarkSelector::ProofSize) + { + println!("Recorded proof Size = {:?}", analysis); + } println!(); } } } + + /// Parses the PoV modes per benchmark that were specified by the `#[pov_mode]` attribute. + fn parse_pov_modes( + benchmarks: &Vec<( + Vec, + Vec, + Vec<(BenchmarkParameter, u32, u32)>, + Vec<(String, String)>, + )>, + ) -> Result { + use std::collections::hash_map::Entry; + let mut parsed = PovModesMap::new(); + + for (pallet, call, _components, pov_modes) in benchmarks { + for (pallet_storage, mode) in pov_modes { + let mode = PovEstimationMode::from_str(&mode)?; + let splits = pallet_storage.split("::").collect::>(); + if splits.is_empty() || splits.len() > 2 { + return Err(format!( + "Expected 'Pallet::Storage' as storage name but got: {}", + pallet_storage + ) + .into()) + } + let (pov_pallet, pov_storage) = (splits[0], splits.get(1).unwrap_or(&"ALL")); + + match parsed + .entry((pallet.clone(), call.clone())) + .or_default() + .entry((pov_pallet.to_string(), pov_storage.to_string())) + { + Entry::Occupied(_) => + return Err(format!( + "Cannot specify pov_mode tag twice for the same key: {}", + pallet_storage + ) + .into()), + Entry::Vacant(e) => { + e.insert(mode); + }, + } + } + } + Ok(parsed) + } } impl CliConfiguration for PalletCmd { @@ -592,9 +735,16 @@ impl CliConfiguration for PalletCmd { } /// List the benchmarks available in the runtime, in a CSV friendly format. -fn list_benchmark(benchmarks_to_run: Vec<(Vec, Vec, Vec<(BenchmarkParameter, u32, u32)>)>) { +fn list_benchmark( + benchmarks_to_run: Vec<( + Vec, + Vec, + Vec<(BenchmarkParameter, u32, u32)>, + Vec<(String, String)>, + )>, +) { println!("pallet, benchmark"); - for (pallet, extrinsic, _components) in benchmarks_to_run { + for (pallet, extrinsic, _, _) in benchmarks_to_run { println!("{}, {}", String::from_utf8_lossy(&pallet), String::from_utf8_lossy(&extrinsic)); } } diff --git a/utils/frame/benchmarking-cli/src/pallet/mod.rs b/utils/frame/benchmarking-cli/src/pallet/mod.rs index b10f531bc0aed..1fcf0cc1151dd 100644 --- a/utils/frame/benchmarking-cli/src/pallet/mod.rs +++ b/utils/frame/benchmarking-cli/src/pallet/mod.rs @@ -103,6 +103,14 @@ pub struct PalletCmd { #[arg(long)] pub output_analysis: Option, + /// Which analysis function to use when analyzing measured proof sizes. + #[arg(long, default_value("median-slopes"))] + pub output_pov_analysis: Option, + + /// The PoV estimation mode of a benchmark if no `pov_mode` attribute is present. + #[arg(long, default_value("max-encoded-len"), value_enum)] + pub default_pov_mode: command::PovEstimationMode, + /// Set the heap pages while running benchmarks. If not set, the default value from the client /// is used. #[arg(long)] @@ -117,10 +125,6 @@ pub struct PalletCmd { #[arg(long)] pub extra: bool, - /// Estimate PoV size. - #[arg(long)] - pub record_proof: bool, - #[allow(missing_docs)] #[clap(flatten)] pub shared_params: sc_cli::SharedParams, @@ -167,6 +171,25 @@ pub struct PalletCmd { #[arg(long)] pub no_storage_info: bool, + /// The assumed default maximum size of any `StorageMap`. + /// + /// When the maximum size of a map is not defined by the runtime developer, + /// this value is used as a worst case scenario. It will affect the calculated worst case + /// PoV size for accessing a value in a map, since the PoV will need to include the trie + /// nodes down to the underlying value. + #[clap(long = "map-size", default_value = "1000000")] + pub worst_case_map_values: u32, + + /// Adjust the PoV estimation by adding additional trie layers to it. + /// + /// This should be set to `log16(n)` where `n` is the number of top-level storage items in the + /// runtime, eg. `StorageMap`s and `StorageValue`s. A value of 2 to 3 is usually sufficient. + /// Each layer will result in an additional 495 bytes PoV per distinct top-level access. + /// Therefore multiple `StorageMap` accesses only suffer from this increase once. The exact + /// number of storage items depends on the runtime and the deployed pallets. + #[clap(long, default_value = "0")] + pub additional_trie_layers: u8, + /// 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. diff --git a/utils/frame/benchmarking-cli/src/pallet/template.hbs b/utils/frame/benchmarking-cli/src/pallet/template.hbs index 1a69a3ae20c5f..00dd1a3532d95 100644 --- a/utils/frame/benchmarking-cli/src/pallet/template.hbs +++ b/utils/frame/benchmarking-cli/src/pallet/template.hbs @@ -2,7 +2,8 @@ //! Autogenerated weights for `{{pallet}}` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION {{version}} -//! DATE: {{date}}, STEPS: `{{cmd.steps}}`, REPEAT: {{cmd.repeat}}, LOW RANGE: `{{cmd.lowest_range_values}}`, HIGH RANGE: `{{cmd.highest_range_values}}` +//! DATE: {{date}}, STEPS: `{{cmd.steps}}`, REPEAT: `{{cmd.repeat}}`, LOW RANGE: `{{cmd.lowest_range_values}}`, HIGH RANGE: `{{cmd.highest_range_values}}` +//! WORST CASE MAP SIZE: `{{cmd.worst_case_map_values}}` //! HOSTNAME: `{{hostname}}`, CPU: `{{cpuname}}` //! EXECUTION: {{cmd.execution}}, WASM-EXECUTION: {{cmd.wasm_execution}}, CHAIN: {{cmd.chain}}, DB CACHE: {{cmd.db_cache}} @@ -23,7 +24,7 @@ pub struct WeightInfo(PhantomData); impl {{pallet}}::WeightInfo for WeightInfo { {{#each benchmarks as |benchmark|}} {{#each benchmark.comments as |comment|}} - // {{comment}} + /// {{comment}} {{/each}} {{#each benchmark.component_ranges as |range|}} /// The range of component `{{range.name}}` is `[{{range.min}}, {{range.max}}]`. @@ -33,8 +34,15 @@ impl {{pallet}}::WeightInfo for WeightInfo { {{~#each benchmark.components as |c| ~}} {{~#if (not c.is_used)}}_{{/if}}{{c.name}}: u32, {{/each~}} ) -> Weight { + // Proof Size summary in bytes: + // Measured: `{{benchmark.base_recorded_proof_size}}{{#each benchmark.component_recorded_proof_size as |cp|}} + {{cp.name}} * ({{cp.slope}} ±{{underscore cp.error}}){{/each}}` + // Estimated: `{{benchmark.base_calculated_proof_size}}{{#each benchmark.component_calculated_proof_size as |cp|}} + {{cp.name}} * ({{cp.slope}} ±{{underscore cp.error}}){{/each}}` // Minimum execution time: {{underscore benchmark.min_execution_time}} nanoseconds. + {{#if (ne benchmark.base_calculated_proof_size "0")}} + Weight::from_parts({{underscore benchmark.base_weight}}, {{benchmark.base_calculated_proof_size}}) + {{else}} Weight::from_ref_time({{underscore benchmark.base_weight}}) + {{/if}} {{#each benchmark.component_weight as |cw|}} // Standard Error: {{underscore cw.error}} .saturating_add(Weight::from_ref_time({{underscore cw.slope}}).saturating_mul({{cw.name}}.into())) @@ -51,6 +59,9 @@ impl {{pallet}}::WeightInfo for WeightInfo { {{#each benchmark.component_writes as |cw|}} .saturating_add(T::DbWeight::get().writes(({{cw.slope}}_u64).saturating_mul({{cw.name}}.into()))) {{/each}} + {{#each benchmark.component_calculated_proof_size as |cp|}} + .saturating_add(Weight::from_proof_size({{cp.slope}}).saturating_mul({{cp.name}}.into())) + {{/each}} } {{/each}} } diff --git a/utils/frame/benchmarking-cli/src/pallet/writer.rs b/utils/frame/benchmarking-cli/src/pallet/writer.rs index a52bbcd229cb1..9359b272551f0 100644 --- a/utils/frame/benchmarking-cli/src/pallet/writer.rs +++ b/utils/frame/benchmarking-cli/src/pallet/writer.rs @@ -27,7 +27,11 @@ use inflector::Inflector; use itertools::Itertools; use serde::Serialize; -use crate::{pallet::command::ComponentRange, shared::UnderscoreHelper, PalletCmd}; +use crate::{ + pallet::command::{ComponentRange, PovEstimationMode, PovModesMap}, + shared::UnderscoreHelper, + PalletCmd, +}; use frame_benchmarking::{ Analysis, AnalysisChoice, BenchmarkBatchSplitResults, BenchmarkResult, BenchmarkSelector, }; @@ -54,7 +58,7 @@ struct TemplateData { } // This was the final data we have about each benchmark. -#[derive(Serialize, Default, Debug, Clone)] +#[derive(Serialize, Default, Debug, Clone, PartialEq)] struct BenchmarkData { name: String, components: Vec, @@ -64,9 +68,15 @@ struct BenchmarkData { base_reads: u128, #[serde(serialize_with = "string_serialize")] base_writes: u128, + #[serde(serialize_with = "string_serialize")] + base_calculated_proof_size: u128, + #[serde(serialize_with = "string_serialize")] + base_recorded_proof_size: u128, component_weight: Vec, component_reads: Vec, component_writes: Vec, + component_calculated_proof_size: Vec, + component_recorded_proof_size: Vec, component_ranges: Vec, comments: Vec, #[serde(serialize_with = "string_serialize")] @@ -85,6 +95,8 @@ struct CmdData { chain: String, db_cache: u32, analysis_choice: String, + worst_case_map_values: u32, + additional_trie_layers: u8, } // This encodes the component name and whether that component is used. @@ -122,7 +134,12 @@ fn map_results( batches: &[BenchmarkBatchSplitResults], storage_info: &[StorageInfo], component_ranges: &HashMap<(Vec, Vec), Vec>, + pov_modes: PovModesMap, + default_pov_mode: PovEstimationMode, analysis_choice: &AnalysisChoice, + pov_analysis_choice: &AnalysisChoice, + worst_case_map_values: u32, + additional_trie_layers: u8, ) -> Result>, std::io::Error> { // Skip if batches is empty. if batches.is_empty() { @@ -139,8 +156,17 @@ 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, &component_ranges, analysis_choice); + let benchmark_data = get_benchmark_data( + batch, + storage_info, + &component_ranges, + pov_modes.clone(), + default_pov_mode, + analysis_choice, + pov_analysis_choice, + worst_case_map_values, + additional_trie_layers, + ); let pallet_benchmarks = all_benchmarks.entry((pallet_string, instance_string)).or_default(); pallet_benchmarks.push(benchmark_data); } @@ -164,17 +190,24 @@ fn get_benchmark_data( storage_info: &[StorageInfo], // Per extrinsic component ranges. component_ranges: &HashMap<(Vec, Vec), Vec>, + pov_modes: PovModesMap, + default_pov_mode: PovEstimationMode, analysis_choice: &AnalysisChoice, + pov_analysis_choice: &AnalysisChoice, + worst_case_map_values: u32, + additional_trie_layers: u8, ) -> BenchmarkData { - // You can use this to put any additional comments with the benchmarking output. - let mut comments = Vec::::new(); - // Analyze benchmarks to get the linear regression. let analysis_function = match analysis_choice { AnalysisChoice::MinSquares => Analysis::min_squares_iqr, AnalysisChoice::MedianSlopes => Analysis::median_slopes, AnalysisChoice::Max => Analysis::max, }; + let pov_analysis_function = match pov_analysis_choice { + AnalysisChoice::MinSquares => Analysis::min_squares_iqr, + AnalysisChoice::MedianSlopes => Analysis::median_slopes, + AnalysisChoice::Max => Analysis::max, + }; let extrinsic_time = analysis_function(&batch.time_results, BenchmarkSelector::ExtrinsicTime) .expect("analysis function should return an extrinsic time for valid inputs"); @@ -182,6 +215,9 @@ fn get_benchmark_data( .expect("analysis function should return the number of reads for valid inputs"); let writes = analysis_function(&batch.db_results, BenchmarkSelector::Writes) .expect("analysis function should return the number of writes for valid inputs"); + let recorded_proof_size = + pov_analysis_function(&batch.db_results, BenchmarkSelector::ProofSize) + .expect("analysis function should return proof sizes for valid inputs"); // Analysis data may include components that are not used, this filters out anything whose value // is zero. @@ -189,6 +225,8 @@ fn get_benchmark_data( let mut used_extrinsic_time = Vec::new(); let mut used_reads = Vec::new(); let mut used_writes = Vec::new(); + let mut used_calculated_proof_size = Vec::::new(); + let mut used_recorded_proof_size = Vec::::new(); extrinsic_time .slopes @@ -229,6 +267,76 @@ fn get_benchmark_data( used_writes.push(ComponentSlope { name: name.clone(), slope, error }); } }); + recorded_proof_size + .slopes + .into_iter() + .zip(recorded_proof_size.names.iter()) + .zip(extract_errors(&recorded_proof_size.errors)) + .for_each(|((slope, name), error)| { + if !slope.is_zero() { + // These are only for comments, so don't touch the `used_components`. + used_recorded_proof_size.push(ComponentSlope { name: name.clone(), slope, error }); + } + }); + + // We add additional comments showing which storage items were touched. + // We find the worst case proof size, and use that as the final proof size result. + let mut storage_per_prefix = HashMap::, Vec>::new(); + let pov_mode = pov_modes + .get(&(batch.pallet.clone(), batch.benchmark.clone())) + .cloned() + .unwrap_or_default(); + let comments = process_storage_results( + &mut storage_per_prefix, + &batch.db_results, + storage_info, + &pov_mode, + default_pov_mode, + worst_case_map_values, + additional_trie_layers, + ); + + let proof_size_per_components = storage_per_prefix + .iter() + .map(|(prefix, results)| { + let proof_size = analysis_function(results, BenchmarkSelector::ProofSize) + .expect("analysis function should return proof sizes for valid inputs"); + let slope = proof_size + .slopes + .into_iter() + .zip(proof_size.names.iter()) + .zip(extract_errors(&proof_size.errors)) + .map(|((slope, name), error)| ComponentSlope { name: name.clone(), slope, error }) + .collect::>(); + (prefix.clone(), slope, proof_size.base) + }) + .collect::>(); + + let mut base_calculated_proof_size = 0; + // Sum up the proof sizes per component + for (_, slope, base) in proof_size_per_components.iter() { + base_calculated_proof_size += base; + for component in slope.iter() { + let mut found = false; + for used_component in used_calculated_proof_size.iter_mut() { + if used_component.name == component.name { + used_component.slope += component.slope; + found = true; + break + } + } + if !found && !component.slope.is_zero() { + if !used_components.contains(&&component.name) { + used_components.push(&component.name); + } + used_calculated_proof_size.push(ComponentSlope { + name: component.name.clone(), + slope: component.slope, + error: component.error, + }); + } + } + } // This puts a marker on any component which is entirely unused in the weight formula. let components = batch.time_results[0] @@ -241,8 +349,6 @@ fn get_benchmark_data( }) .collect::>(); - // 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()) @@ -254,9 +360,13 @@ fn get_benchmark_data( base_weight: extrinsic_time.base, base_reads: reads.base, base_writes: writes.base, + base_calculated_proof_size, + base_recorded_proof_size: recorded_proof_size.base, component_weight: used_extrinsic_time, component_reads: used_reads, component_writes: used_writes, + component_calculated_proof_size: used_calculated_proof_size, + component_recorded_proof_size: used_recorded_proof_size, component_ranges, comments, min_execution_time: extrinsic_time.minimum, @@ -268,6 +378,8 @@ pub(crate) fn write_results( batches: &[BenchmarkBatchSplitResults], storage_info: &[StorageInfo], component_ranges: &HashMap<(Vec, Vec), Vec>, + pov_modes: PovModesMap, + default_pov_mode: PovEstimationMode, path: &PathBuf, cmd: &PalletCmd, ) -> Result<(), std::io::Error> { @@ -295,6 +407,15 @@ pub(crate) fn write_results( // Which analysis function should be used when outputting benchmarks let analysis_choice: AnalysisChoice = cmd.output_analysis.clone().try_into().map_err(io_error)?; + let pov_analysis_choice: AnalysisChoice = + cmd.output_pov_analysis.clone().try_into().map_err(io_error)?; + + if cmd.additional_trie_layers > 4 { + println!( + "WARNING: `additional_trie_layers` is unexpectedly large. It assumes {} storage items.", + 16f64.powi(cmd.additional_trie_layers as i32) + ) + } // Capture individual args let cmd_data = CmdData { @@ -307,6 +428,8 @@ pub(crate) fn write_results( chain: format!("{:?}", cmd.shared_params.chain), db_cache: cmd.database_cache_size, analysis_choice: format!("{:?}", analysis_choice), + worst_case_map_values: cmd.worst_case_map_values, + additional_trie_layers: cmd.additional_trie_layers, }; // New Handlebars instance with helpers. @@ -317,7 +440,17 @@ pub(crate) 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, component_ranges, &analysis_choice)?; + let all_results = map_results( + batches, + storage_info, + component_ranges, + pov_modes, + default_pov_mode, + &analysis_choice, + &pov_analysis_choice, + cmd.worst_case_map_values, + cmd.additional_trie_layers, + )?; let mut created_files = Vec::new(); for ((pallet, instance), results) in all_results.iter() { @@ -365,14 +498,21 @@ pub(crate) fn write_results( Ok(()) } -// This function looks at the keys touched during the benchmark, and the storage info we collected -// from the pallets, and creates comments with information about the storage keys touched during -// each benchmark. -pub(crate) fn add_storage_comments( - comments: &mut Vec, +/// This function looks at the keys touched during the benchmark, and the storage info we collected +/// from the pallets, and creates comments with information about the storage keys touched during +/// each benchmark. +/// +/// It returns informational comments for human consumption. +pub(crate) fn process_storage_results( + storage_per_prefix: &mut HashMap, Vec>, results: &[BenchmarkResult], storage_info: &[StorageInfo], -) { + pov_modes: &HashMap<(String, String), PovEstimationMode>, + default_pov_mode: PovEstimationMode, + worst_case_map_values: u32, + additional_trie_layers: u8, +) -> Vec { + let mut comments = Vec::new(); let mut storage_info_map = storage_info .iter() .map(|info| (info.prefix.clone(), info)) @@ -399,48 +539,246 @@ pub(crate) fn add_storage_comments( storage_info_map.insert(benchmark_override.prefix.clone(), &benchmark_override); // This tracks the keys we already identified, so we only generate a single comment. - let mut identified = HashSet::>::new(); + let mut identified_prefix = HashSet::>::new(); + let mut identified_key = HashSet::>::new(); - for result in results { + // TODO Emit a warning for unused `pov_mode` attributes. + + // We have to iterate in reverse order to catch the largest values for read/write since the + // components start low and then increase and only the first value is used. + for result in results.iter().rev() { for (key, reads, writes, whitelisted) in &result.keys { // skip keys which are whitelisted if *whitelisted { continue } + let prefix_length = key.len().min(32); let prefix = key[0..prefix_length].to_vec(); - if identified.contains(&prefix) { - // skip adding comments for keys we already identified - continue - } else { - // track newly identified keys - identified.insert(prefix.clone()); + let is_key_identified = identified_key.contains(key); + let is_prefix_identified = identified_prefix.contains(&prefix); + + let mut prefix_result = result.clone(); + let key_info = storage_info_map.get(&prefix); + let max_size = key_info.and_then(|k| k.max_size); + + let override_pov_mode = match key_info { + Some(StorageInfo { pallet_name, storage_name, .. }) => { + let pallet_name = + String::from_utf8(pallet_name.clone()).expect("encoded from string"); + let storage_name = + String::from_utf8(storage_name.clone()).expect("encoded from string"); + + // Is there an override for the storage key? + pov_modes.get(&(pallet_name.clone(), storage_name)).or( + // .. or for the storage prefix? + pov_modes.get(&(pallet_name, "ALL".to_string())).or( + // .. or for the benchmark? + pov_modes.get(&("ALL".to_string(), "ALL".to_string())), + ), + ) + }, + None => None, + }; + let is_all_ignored = pov_modes.get(&("ALL".to_string(), "ALL".to_string())) == + Some(&PovEstimationMode::Ignored); + if is_all_ignored && override_pov_mode != Some(&PovEstimationMode::Ignored) { + panic!("The syntax currently does not allow to exclude single keys from a top-level `Ignored` pov-mode."); } - match storage_info_map.get(&prefix) { - Some(key_info) => { - let comment = format!( - "Storage: {} {} (r:{} w:{})", - String::from_utf8(key_info.pallet_name.clone()) - .expect("encoded from string"), - String::from_utf8(key_info.storage_name.clone()) - .expect("encoded from string"), - reads, - writes, - ); - comments.push(comment) + + let pov_overhead = single_read_pov_overhead( + key_info.and_then(|i| i.max_values), + worst_case_map_values, + ); + + let used_pov_mode = match (override_pov_mode, max_size, default_pov_mode) { + // All is ignored by default and no override: + (None, _, PovEstimationMode::Ignored) => { + prefix_result.proof_size = 0; + PovEstimationMode::Ignored + }, + // Some is ignored by override, maybe all: + (Some(PovEstimationMode::Ignored), _, _) => { + // If this is applied to All keys, then we also remove the base weight and just set all to zero. + if is_all_ignored { + prefix_result.proof_size = 0; + } else { + // Otherwise we just don't *increase* `proof_size` for this key. + } + PovEstimationMode::Ignored + }, + (Some(PovEstimationMode::Measured), _, _)| + (None, _, PovEstimationMode::Measured) | + // Use best effort in this case since failing would be really annoying. + (None, None, PovEstimationMode::MaxEncodedLen) => { + // We add the overhead for a single read each time. In a more advanced version + // we could take node re-using into account and over-estimate a bit less. + prefix_result.proof_size += pov_overhead * *reads; + PovEstimationMode::Measured + }, + (Some(PovEstimationMode::MaxEncodedLen), Some(max_size), _) | + (None, Some(max_size), PovEstimationMode::MaxEncodedLen) => { + prefix_result.proof_size = (pov_overhead + max_size) * *reads; + PovEstimationMode::MaxEncodedLen + }, + (Some(PovEstimationMode::MaxEncodedLen), None, _) => { + panic!("Key does not have MEL bound but MEL PoV estimation mode was specified {:?}", &key); + }, + }; + // Add the additional trie layer overhead for every new prefix. + if *reads > 0 { + prefix_result.proof_size += 15 * 33 * additional_trie_layers as u32; + } + storage_per_prefix.entry(prefix.clone()).or_default().push(prefix_result); + + match (is_key_identified, is_prefix_identified) { + // We already did everything, move on... + (true, true) => continue, + (false, true) => { + // track newly identified key + identified_key.insert(key.clone()); }, - None => { - let comment = format!( - "Storage: unknown [0x{}] (r:{} w:{})", - HexDisplay::from(key), - reads, - writes, - ); - comments.push(comment) + (false, false) => { + // track newly identified key and prefix + identified_key.insert(key.clone()); + identified_prefix.insert(prefix.clone()); }, + // Not possible. If the key is known, the prefix is too. + (true, false) => unreachable!(), + } + + // For any new prefix, we should write some comment about the number of reads and + // writes. + if !is_prefix_identified { + match key_info { + Some(key_info) => { + let comment = format!( + "Storage: {} {} (r:{} w:{})", + String::from_utf8(key_info.pallet_name.clone()) + .expect("encoded from string"), + String::from_utf8(key_info.storage_name.clone()) + .expect("encoded from string"), + reads, + writes, + ); + comments.push(comment) + }, + None => { + let comment = format!( + "Storage: unknown `0x{}` (r:{} w:{})", + HexDisplay::from(key), + reads, + writes, + ); + comments.push(comment) + }, + } + } + + // For any new key, we should add the PoV impact. + if !is_key_identified { + match key_info { + Some(key_info) => { + match worst_case_pov( + key_info.max_values, + key_info.max_size, + !is_prefix_identified, + worst_case_map_values, + ) { + Some(new_pov) => { + let comment = format!( + "Proof: {} {} (max_values: {:?}, max_size: {:?}, added: {}, mode: {:?})", + String::from_utf8(key_info.pallet_name.clone()) + .expect("encoded from string"), + String::from_utf8(key_info.storage_name.clone()) + .expect("encoded from string"), + key_info.max_values, + key_info.max_size, + new_pov, + used_pov_mode, + ); + comments.push(comment) + }, + None => { + let pallet = String::from_utf8(key_info.pallet_name.clone()) + .expect("encoded from string"); + let item = String::from_utf8(key_info.storage_name.clone()) + .expect("encoded from string"); + let comment = format!( + "Proof Skipped: {} {} (max_values: {:?}, max_size: {:?}, mode: {:?})", + pallet, item, key_info.max_values, key_info.max_size, + used_pov_mode, + ); + comments.push(comment); + }, + } + }, + None => { + let comment = format!( + "Proof Skipped: unknown `0x{}` (r:{} w:{})", + HexDisplay::from(key), + reads, + writes, + ); + comments.push(comment) + }, + } } } } + + comments +} + +/// The PoV overhead when reading a key the first time out of a map with `max_values` entries. +fn single_read_pov_overhead(max_values: Option, worst_case_map_values: u32) -> u32 { + let max_values = max_values.unwrap_or(worst_case_map_values); + let depth: u32 = easy_log_16(max_values); + // Normally we have 16 entries of 32 byte hashes per tree layer. In the new trie + // layout the hashes are prefixed by their compact length, hence 33 instead. The proof + // compaction can compress one node per layer since we send the value itself, + // therefore we end up with a size of `15 * 33` per layer. + depth * 15 * 33 +} + +/// Given the max values and max size of some storage item, calculate the worst +/// case PoV. +/// +/// # Arguments +/// * `max_values`: The maximum number of values in the storage item. `None` for unbounded items. +/// * `max_size`: The maximum size of the value in the storage. `None` for unbounded items. +fn worst_case_pov( + max_values: Option, + max_size: Option, + is_new_prefix: bool, + worst_case_map_values: u32, +) -> Option { + if let Some(max_size) = max_size { + let trie_size: u32 = if is_new_prefix { + single_read_pov_overhead(max_values, worst_case_map_values) + } else { + 0 + }; + + Some(trie_size + max_size) + } else { + None + } +} + +/// A simple match statement which outputs the log 16 of some value. +fn easy_log_16(i: u32) -> u32 { + match i { + i if i == 0 => 0, + i if i <= 16 => 1, + i if i <= 256 => 2, + i if i <= 4_096 => 3, + i if i <= 65_536 => 4, + i if i <= 1_048_576 => 5, + i if i <= 16_777_216 => 6, + i if i <= 268_435_456 => 7, + _ => 8, + } } // A helper to join a string of vectors. @@ -497,15 +835,16 @@ mod test { let mut results = Vec::new(); for i in 0..5 { results.push(BenchmarkResult { - components: vec![(param, i), (BenchmarkParameter::z, 0)], + components: vec![(param, i)], extrinsic_time: (base + slope * i).into(), storage_root_time: (base + slope * i).into(), reads: (base + slope * i).into(), repeat_reads: 0, writes: (base + slope * i).into(), repeat_writes: 0, - proof_size: 0, - keys: vec![], + proof_size: (i + 1) * 1024, + // All R/W come from this key: + keys: vec![(b"bounded".to_vec(), (base + slope * i), (base + slope * i), false)], }) } @@ -518,13 +857,31 @@ mod test { } } + fn test_storage_info() -> Vec { + vec![StorageInfo { + pallet_name: b"bounded".to_vec(), + storage_name: b"bounded".to_vec(), + prefix: b"bounded".to_vec(), + max_values: Some(1 << 20), + max_size: Some(32), + }] + } + + fn test_pov_mode() -> PovModesMap { + let mut map = PovModesMap::new(); + map.entry((b"scheduler".to_vec(), b"first_benchmark".to_vec())) + .or_default() + .insert(("scheduler".into(), "mel".into()), PovEstimationMode::MaxEncodedLen); + map.entry((b"scheduler".to_vec(), b"first_benchmark".to_vec())) + .or_default() + .insert(("scheduler".into(), "measured".into()), PovEstimationMode::Measured); + map + } + fn check_data(benchmark: &BenchmarkData, component: &str, base: u128, slope: u128) { assert_eq!( benchmark.components, - vec![ - Component { name: component.to_string(), is_used: true }, - Component { name: "z".to_string(), is_used: false }, - ], + vec![Component { name: component.to_string(), is_used: true },], ); // Weights multiplied by 1,000 assert_eq!(benchmark.base_weight, base * 1_000); @@ -543,6 +900,294 @@ mod test { benchmark.component_writes, vec![ComponentSlope { name: component.to_string(), slope, error: 0 }] ); + // Measure PoV is correct + assert_eq!(benchmark.base_recorded_proof_size, 1024); + assert_eq!( + benchmark.component_recorded_proof_size, + vec![ComponentSlope { name: component.to_string(), slope: 1024, error: 0 }] + ); + } + + /// We measure a linear proof size but select `pov_mode = MEL` with a present MEL bound for the + /// type. This should result in the measured PoV being ignored and the MEL used instead. + #[test] + fn pov_mode_mel_constant_works() { + let mut results = Vec::new(); + for i in 0..5 { + results.push(BenchmarkResult { + components: vec![(BenchmarkParameter::s, i)], + extrinsic_time: 0, + storage_root_time: 0, + reads: 1, + repeat_reads: 777, + writes: 888, + repeat_writes: 999, + proof_size: i * 1024, + keys: vec![(b"mel".to_vec(), 1, 1, false)], + }) + } + + let data = BenchmarkBatchSplitResults { + pallet: b"scheduler".to_vec(), + instance: b"instance".to_vec(), + benchmark: b"first_benchmark".to_vec(), + time_results: results.clone(), + db_results: results, + }; + + let storage_info = vec![StorageInfo { + pallet_name: b"scheduler".to_vec(), + storage_name: b"mel".to_vec(), + prefix: b"mel".to_vec(), + max_values: None, + max_size: Some(1 << 22), // MEL of 4 MiB + }]; + + let mapped_results = map_results( + &[data], + &storage_info, + &Default::default(), + test_pov_mode(), + PovEstimationMode::MaxEncodedLen, + &AnalysisChoice::default(), + &AnalysisChoice::MedianSlopes, + 1_000_000, + 0, + ) + .unwrap(); + let result = + mapped_results.get(&("scheduler".to_string(), "instance".to_string())).unwrap()[0] + .clone(); + + let base = result.base_calculated_proof_size; + assert!(result.component_calculated_proof_size.is_empty(), "There is no slope"); + // It's a map with 5 layers overhead: + assert_eq!(base, (1 << 22) + 15 * 33 * 5); + } + + /// Record a small linear proof size but since MEL is selected and available it should be used + /// instead. + #[test] + fn pov_mode_mel_linear_works() { + let mut results = Vec::new(); + for i in 0..5 { + results.push(BenchmarkResult { + components: vec![(BenchmarkParameter::s, i)], + extrinsic_time: 0, + storage_root_time: 0, + reads: 123, + repeat_reads: 777, + writes: 888, + repeat_writes: 999, + proof_size: i * 1024, + keys: vec![("mel".as_bytes().to_vec(), i, 1, false)], + }) + } + + let data = BenchmarkBatchSplitResults { + pallet: b"scheduler".to_vec(), + instance: b"instance".to_vec(), + benchmark: b"first_benchmark".to_vec(), + time_results: results.clone(), + db_results: results, + }; + + let storage_info = vec![StorageInfo { + pallet_name: b"scheduler".to_vec(), + storage_name: b"mel".to_vec(), + prefix: b"mel".to_vec(), + max_values: None, + max_size: Some(1 << 22), // MEL of 4 MiB + }]; + + let mapped_results = map_results( + &[data], + &storage_info, + &Default::default(), + test_pov_mode(), + PovEstimationMode::MaxEncodedLen, + &AnalysisChoice::default(), + &AnalysisChoice::MedianSlopes, + 1_000_000, + 0, + ) + .unwrap(); + let result = + mapped_results.get(&("scheduler".to_string(), "instance".to_string())).unwrap()[0] + .clone(); + + let base = result.base_calculated_proof_size; + assert_eq!(result.component_calculated_proof_size.len(), 1, "There is a slope"); + let slope = result.component_calculated_proof_size[0].clone().slope; + assert_eq!(base, 0); + // It's a map with 5 layers overhead: + assert_eq!(slope, (1 << 22) + 15 * 33 * 5); + } + + #[test] + fn pov_mode_measured_const_works() { + let mut results = Vec::new(); + for i in 0..5 { + results.push(BenchmarkResult { + components: vec![(BenchmarkParameter::s, i)], + extrinsic_time: 0, + storage_root_time: 0, + reads: 123, + repeat_reads: 777, + writes: 888, + repeat_writes: 999, + proof_size: 1024, + keys: vec![("measured".as_bytes().to_vec(), 1, 1, false)], + }) + } + + let data = BenchmarkBatchSplitResults { + pallet: b"scheduler".to_vec(), + instance: b"instance".to_vec(), + benchmark: b"first_benchmark".to_vec(), + time_results: results.clone(), + db_results: results, + }; + + let storage_info = vec![StorageInfo { + pallet_name: b"scheduler".to_vec(), + storage_name: b"measured".to_vec(), + prefix: b"measured".to_vec(), + max_values: None, + max_size: Some(1 << 22), // MEL of 4 MiB + }]; + + let mapped_results = map_results( + &[data], + &storage_info, + &Default::default(), + test_pov_mode(), + PovEstimationMode::MaxEncodedLen, + &AnalysisChoice::default(), + &AnalysisChoice::MedianSlopes, + 1_000_000, + 0, + ) + .unwrap(); + let result = + mapped_results.get(&("scheduler".to_string(), "instance".to_string())).unwrap()[0] + .clone(); + + let base = result.base_calculated_proof_size; + assert!(result.component_calculated_proof_size.is_empty(), "There is no slope"); + // 5 Trie layers overhead because of the 1M max elements in that map: + assert_eq!(base, 1024 + 15 * 33 * 5); + } + + #[test] + fn pov_mode_measured_linear_works() { + let mut results = Vec::new(); + for i in 0..5 { + results.push(BenchmarkResult { + components: vec![(BenchmarkParameter::s, i)], + extrinsic_time: 0, + storage_root_time: 0, + reads: 123, + repeat_reads: 777, + writes: 888, + repeat_writes: 999, + proof_size: i * 1024, + keys: vec![("measured".as_bytes().to_vec(), i, 1, false)], + }) + } + + let data = BenchmarkBatchSplitResults { + pallet: b"scheduler".to_vec(), + instance: b"instance".to_vec(), + benchmark: b"first_benchmark".to_vec(), + time_results: results.clone(), + db_results: results, + }; + + let storage_info = vec![StorageInfo { + pallet_name: b"scheduler".to_vec(), + storage_name: b"measured".to_vec(), + prefix: b"measured".to_vec(), + max_values: None, + max_size: Some(1 << 22), // MEL of 4 MiB + }]; + + let mapped_results = map_results( + &[data], + &storage_info, + &Default::default(), + test_pov_mode(), + PovEstimationMode::MaxEncodedLen, + &AnalysisChoice::default(), + &AnalysisChoice::MedianSlopes, + 1_000_000, + 0, + ) + .unwrap(); + let result = + mapped_results.get(&("scheduler".to_string(), "instance".to_string())).unwrap()[0] + .clone(); + + let base = result.base_calculated_proof_size; + assert_eq!(result.component_calculated_proof_size.len(), 1, "There is a slope"); + let slope = result.component_calculated_proof_size[0].clone().slope; + assert_eq!(base, 0); + // It's a map with 5 layers overhead: + assert_eq!(slope, 1024 + 15 * 33 * 5); + } + + #[test] + fn pov_mode_ignored_linear_works() { + let mut results = Vec::new(); + for i in 0..5 { + results.push(BenchmarkResult { + components: vec![(BenchmarkParameter::s, i)], + extrinsic_time: 0, + storage_root_time: 0, + reads: 123, + repeat_reads: 777, + writes: 888, + repeat_writes: 999, + proof_size: i * 1024, + keys: vec![("ignored".as_bytes().to_vec(), i, 1, false)], + }) + } + + let data = BenchmarkBatchSplitResults { + pallet: b"scheduler".to_vec(), + instance: b"instance".to_vec(), + benchmark: b"first_benchmark".to_vec(), + time_results: results.clone(), + db_results: results, + }; + + let storage_info = vec![StorageInfo { + pallet_name: b"scheduler".to_vec(), + storage_name: b"ignored".to_vec(), + prefix: b"ignored".to_vec(), + max_values: None, + max_size: Some(1 << 22), // MEL of 4 MiB + }]; + + let mapped_results = map_results( + &[data], + &storage_info, + &Default::default(), + test_pov_mode(), + PovEstimationMode::Ignored, + &AnalysisChoice::default(), + &AnalysisChoice::MedianSlopes, + 1_000_000, + 0, + ) + .unwrap(); + let result = + mapped_results.get(&("scheduler".to_string(), "instance".to_string())).unwrap()[0] + .clone(); + + let base = result.base_calculated_proof_size; + assert!(result.component_calculated_proof_size.is_empty(), "There is no slope"); + assert_eq!(base, 0); } #[test] @@ -552,10 +1197,16 @@ mod test { test_data(b"first", b"first", BenchmarkParameter::a, 10, 3), test_data(b"first", b"second", BenchmarkParameter::b, 9, 2), test_data(b"second", b"first", BenchmarkParameter::c, 3, 4), + test_data(b"bounded", b"bounded", BenchmarkParameter::d, 4, 6), ], - &[], + &test_storage_info(), &Default::default(), + Default::default(), + PovEstimationMode::MaxEncodedLen, &AnalysisChoice::default(), + &AnalysisChoice::MedianSlopes, + 1_000_000, + 0, ) .unwrap(); @@ -576,5 +1227,118 @@ mod test { .unwrap()[0]; assert_eq!(second_pallet_benchmark.name, "first_benchmark"); check_data(second_pallet_benchmark, "c", 3, 4); + + let bounded_pallet_benchmark = &mapped_results + .get(&("bounded_pallet".to_string(), "instance".to_string())) + .unwrap()[0]; + assert_eq!(bounded_pallet_benchmark.name, "bounded_benchmark"); + check_data(bounded_pallet_benchmark, "d", 4, 6); + // (5 * 15 * 33 + 32) * 4 = 10028 + assert_eq!(bounded_pallet_benchmark.base_calculated_proof_size, 10028); + // (5 * 15 * 33 + 32) * 6 = 15042 + assert_eq!( + bounded_pallet_benchmark.component_calculated_proof_size, + vec![ComponentSlope { name: "d".into(), slope: 15042, error: 0 }] + ); + } + + #[test] + fn additional_trie_layers_work() { + let mapped_results = map_results( + &[test_data(b"first", b"first", BenchmarkParameter::a, 10, 3)], + &test_storage_info(), + &Default::default(), + Default::default(), + PovEstimationMode::MaxEncodedLen, + &AnalysisChoice::default(), + &AnalysisChoice::MedianSlopes, + 1_000_000, + 2, + ) + .unwrap(); + let with_layer = &mapped_results + .get(&("first_pallet".to_string(), "instance".to_string())) + .unwrap()[0]; + let mapped_results = map_results( + &[test_data(b"first", b"first", BenchmarkParameter::a, 10, 3)], + &test_storage_info(), + &Default::default(), + Default::default(), + PovEstimationMode::MaxEncodedLen, + &AnalysisChoice::default(), + &AnalysisChoice::MedianSlopes, + 1_000_000, + 0, + ) + .unwrap(); + let without_layer = &mapped_results + .get(&("first_pallet".to_string(), "instance".to_string())) + .unwrap()[0]; + + assert_eq!( + without_layer.base_calculated_proof_size + 2 * 15 * 33, + with_layer.base_calculated_proof_size + ); + // The additional trie layers ONLY affect the base weight, not the components. + assert_eq!( + without_layer.component_calculated_proof_size, + with_layer.component_calculated_proof_size + ); + } + + #[test] + fn template_works() { + let all_results = map_results( + &[ + test_data(b"first", b"first", BenchmarkParameter::a, 10, 3), + test_data(b"first", b"second", BenchmarkParameter::b, 9, 2), + test_data(b"second", b"first", BenchmarkParameter::c, 3, 4), + ], + &test_storage_info(), + &Default::default(), + Default::default(), + PovEstimationMode::MaxEncodedLen, + &AnalysisChoice::default(), + &AnalysisChoice::MedianSlopes, + 1_000_000, + 0, + ) + .unwrap(); + + // New Handlebars instance with helpers. + let mut handlebars = handlebars::Handlebars::new(); + handlebars.register_helper("underscore", Box::new(UnderscoreHelper)); + handlebars.register_helper("join", Box::new(JoinHelper)); + // Don't HTML escape any characters. + handlebars.register_escape_fn(|s| -> String { s.to_string() }); + + for ((_pallet, _instance), results) in all_results.iter() { + let hbs_data = TemplateData { benchmarks: results.clone(), ..Default::default() }; + + let output = handlebars.render_template(&TEMPLATE, &hbs_data); + assert!(output.is_ok()); + println!("{:?}", output); + } + } + + #[test] + fn easy_log_16_works() { + assert_eq!(easy_log_16(0), 0); + assert_eq!(easy_log_16(1), 1); + assert_eq!(easy_log_16(16), 1); + assert_eq!(easy_log_16(17), 2); + assert_eq!(easy_log_16(16u32.pow(2)), 2); + assert_eq!(easy_log_16(16u32.pow(2) + 1), 3); + assert_eq!(easy_log_16(16u32.pow(3)), 3); + assert_eq!(easy_log_16(16u32.pow(3) + 1), 4); + assert_eq!(easy_log_16(16u32.pow(4)), 4); + assert_eq!(easy_log_16(16u32.pow(4) + 1), 5); + assert_eq!(easy_log_16(16u32.pow(5)), 5); + assert_eq!(easy_log_16(16u32.pow(5) + 1), 6); + assert_eq!(easy_log_16(16u32.pow(6)), 6); + assert_eq!(easy_log_16(16u32.pow(6) + 1), 7); + assert_eq!(easy_log_16(16u32.pow(7)), 7); + assert_eq!(easy_log_16(16u32.pow(7) + 1), 8); + assert_eq!(easy_log_16(u32::MAX), 8); } } From 248fdf0d4b5e3758cfdadb283b5eca5f0731e466 Mon Sep 17 00:00:00 2001 From: Dan Henton Date: Sat, 28 Jan 2023 00:31:17 +1300 Subject: [PATCH 338/715] Use non-binary pronouns in comments. (#13209) * use non binary pronouns in comments * cargo fmt * fix the use of "it" with "they" when dealing about an opperations identity --- bin/utils/subkey/README.md | 2 +- client/beefy/src/tests.rs | 7 ++++--- client/consensus/babe/src/lib.rs | 2 +- docs/README.adoc | 4 ++-- frame/contracts/src/exec.rs | 4 ++-- frame/elections-phragmen/src/benchmarking.rs | 2 +- frame/nfts/src/features/transfer.rs | 2 +- frame/nomination-pools/src/migration.rs | 2 +- frame/nomination-pools/test-staking/src/lib.rs | 2 +- frame/root-offences/src/tests.rs | 4 ++-- frame/staking/src/tests.rs | 2 +- frame/uniques/src/functions.rs | 4 ++-- 12 files changed, 19 insertions(+), 18 deletions(-) diff --git a/bin/utils/subkey/README.md b/bin/utils/subkey/README.md index e762a42c3e79e..768f1335ccdf9 100644 --- a/bin/utils/subkey/README.md +++ b/bin/utils/subkey/README.md @@ -255,7 +255,7 @@ Secret Key URI `0x8c9a73097f235b84021a446bc2826a00c690ea0be3e0d81a84931cb4146d66 SS58 Address: 1bobYxBPjZWRPbVo35aSwci1u5Zmq8P6J2jpa4kkudBZMqE ``` -`Bob` now got a nice address starting with his name: 1**bob**YxBPjZWRPbVo35aSwci1u5Zmq8P6J2jpa4kkudBZMqE. +`Bob` now got a nice address starting with their name: 1**bob**YxBPjZWRPbVo35aSwci1u5Zmq8P6J2jpa4kkudBZMqE. **Note**: While `Bob`, having a short name (3 chars), got a result rather quickly, it will take much longer for `Alice` who has a much longer name, thus the chances to generate a random address that contains the chain `alice` will be much smaller. diff --git a/client/beefy/src/tests.rs b/client/beefy/src/tests.rs index 66d3a210d7eba..2642035ba5dd5 100644 --- a/client/beefy/src/tests.rs +++ b/client/beefy/src/tests.rs @@ -151,7 +151,7 @@ impl BeefyTestNet { ) -> Vec { let mut all_hashes = Vec::with_capacity(count + 1); - // make sure genesis is the only block in network, so we can insert genesis at he beginning + // make sure genesis is the only block in network, so we can insert genesis at the beginning // of hashes, otherwise indexing would be broken assert!(self.peer(0).client().as_backend().blockchain().hash(1).unwrap().is_none()); @@ -926,7 +926,8 @@ async fn on_demand_beefy_justification_sync() { ) .await; - // Spawn Dave, he's now way behind voting and can only catch up through on-demand justif sync. + // Spawn Dave, they are now way behind voting and can only catch up through on-demand justif + // sync. tokio::spawn(dave_task); // give Dave a chance to spawn and init. run_for(Duration::from_millis(400), &net).await; @@ -937,7 +938,7 @@ async fn on_demand_beefy_justification_sync() { client.finalize_block(hashes[1], None).unwrap(); // Give Dave task some cpu cycles to process the finality notification, run_for(Duration::from_millis(100), &net).await; - // freshly spun up Dave now needs to listen for gossip to figure out the state of his peers. + // freshly spun up Dave now needs to listen for gossip to figure out the state of their peers. // Have the other peers do some gossip so Dave finds out about their progress. finalize_block_and_wait_for_beefy(&net, fast_peers, &[hashes[25]], &[25]).await; diff --git a/client/consensus/babe/src/lib.rs b/client/consensus/babe/src/lib.rs index 5ba523665b4ef..0eac4aca07479 100644 --- a/client/consensus/babe/src/lib.rs +++ b/client/consensus/babe/src/lib.rs @@ -1494,7 +1494,7 @@ where // this way we can revert it if there's any error let mut old_epoch_changes = None; - // Use an extra scope to make the compiler happy, because otherwise he complains about the + // Use an extra scope to make the compiler happy, because otherwise it complains about the // mutex, even if we dropped it... let mut epoch_changes = { let mut epoch_changes = self.epoch_changes.shared_data_locked(); diff --git a/docs/README.adoc b/docs/README.adoc index 5d7b0b52c5250..8e43757d10fb2 100644 --- a/docs/README.adoc +++ b/docs/README.adoc @@ -297,7 +297,7 @@ Detailed logs may be shown by running the node with the following environment va If you want to see the multi-node consensus algorithm in action locally, then you can create a local testnet with two validator nodes for Alice and Bob, who are the initial authorities of the genesis chain specification that have been endowed with a testnet DOTs. We'll give each node a name and expose them so they are listed on link:https://telemetry.polkadot.io/#/Local%20Testnet[Telemetry]. You'll need two terminal windows open. -We'll start Alice's Substrate node first on default TCP port 30333 with her chain database stored locally at `/tmp/alice`. The Bootnode ID of her node is `QmRpheLN4JWdAnY7HGJfWFNbfkQCb6tFf4vvA6hgjMZKrR`, which is generated from the `--node-key` value that we specify below: +We'll start Alice's Substrate node first on default TCP port 30333 with their chain database stored locally at `/tmp/alice`. The Bootnode ID of Alice's node is `QmRpheLN4JWdAnY7HGJfWFNbfkQCb6tFf4vvA6hgjMZKrR`, which is generated from the `--node-key` value that we specify below: [source, shell] cargo run --release \-- \ @@ -308,7 +308,7 @@ cargo run --release \-- \ --telemetry-url 'ws://telemetry.polkadot.io:1024 0' \ --validator -In the second terminal, we'll run the following to start Bob's Substrate node on a different TCP port of 30334, and with his chain database stored locally at `/tmp/bob`. We'll specify a value for the `--bootnodes` option that will connect his node to Alice's Bootnode ID on TCP port 30333: +In the second terminal, we'll run the following to start Bob's Substrate node on a different TCP port of 30334, and with their chain database stored locally at `/tmp/bob`. We'll specify a value for the `--bootnodes` option that will connect Bob's node to Alice's Bootnode ID on TCP port 30333: [source, shell] cargo run --release \-- \ diff --git a/frame/contracts/src/exec.rs b/frame/contracts/src/exec.rs index 7a07b01d27c2a..3eb59354d5c07 100644 --- a/frame/contracts/src/exec.rs +++ b/frame/contracts/src/exec.rs @@ -2056,9 +2056,9 @@ 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 + // ALICE is not a contract and hence they do not have a code_hash assert!(ctx.ext.code_hash(&ALICE).is_none()); - // BOB is a contract and hence he has a code_hash + // BOB is a contract and hence it has a code_hash assert!(ctx.ext.code_hash(&BOB).is_some()); exec_success() }); diff --git a/frame/elections-phragmen/src/benchmarking.rs b/frame/elections-phragmen/src/benchmarking.rs index 06ac8d7c60162..53157deaa961b 100644 --- a/frame/elections-phragmen/src/benchmarking.rs +++ b/frame/elections-phragmen/src/benchmarking.rs @@ -32,7 +32,7 @@ const BALANCE_FACTOR: u32 = 250; /// grab new account with infinite balance. 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 + // Fund each account with at-least their stake but still a sane amount as to not mess up // the vote calculation. let amount = default_stake::(T::MaxVoters::get()) * BalanceOf::::from(BALANCE_FACTOR); let _ = T::Currency::make_free_balance_be(&account, amount); diff --git a/frame/nfts/src/features/transfer.rs b/frame/nfts/src/features/transfer.rs index 7d6ae3553a361..3a34f0b8c9fe9 100644 --- a/frame/nfts/src/features/transfer.rs +++ b/frame/nfts/src/features/transfer.rs @@ -64,7 +64,7 @@ impl, I: 'static> Pallet { details.owner = dest; // The approved accounts have to be reset to None, because otherwise pre-approve attack - // would be possible, where the owner can approve his second account before making the + // would be possible, where the owner can approve their second account before making the // transaction and then claiming the item back. details.approvals.clear(); diff --git a/frame/nomination-pools/src/migration.rs b/frame/nomination-pools/src/migration.rs index b73141c95f72c..4a9b6ca0fe117 100644 --- a/frame/nomination-pools/src/migration.rs +++ b/frame/nomination-pools/src/migration.rs @@ -63,7 +63,7 @@ pub mod v1 { /// Trivial migration which makes the roles of each pool optional. /// - /// Note: The depositor is not optional since he can never change. + /// Note: The depositor is not optional since they can never change. pub struct MigrateToV1(sp_std::marker::PhantomData); impl OnRuntimeUpgrade for MigrateToV1 { fn on_runtime_upgrade() -> Weight { diff --git a/frame/nomination-pools/test-staking/src/lib.rs b/frame/nomination-pools/test-staking/src/lib.rs index 00e0e40ce33b0..933e42578d1a6 100644 --- a/frame/nomination-pools/test-staking/src/lib.rs +++ b/frame/nomination-pools/test-staking/src/lib.rs @@ -531,7 +531,7 @@ fn pool_slash_proportional() { #[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 + // A typical example where a pool member unbonds in era 99, and they 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 diff --git a/frame/root-offences/src/tests.rs b/frame/root-offences/src/tests.rs index a8b7d0a6d6aca..b0df4fcee5314 100644 --- a/frame/root-offences/src/tests.rs +++ b/frame/root-offences/src/tests.rs @@ -44,7 +44,7 @@ fn create_offence_works_given_root_origin() { // 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 + // the other validator should keep their balance, because we only created // an offences for the first validator. assert_eq!(Balances::free_balance(21), 1000); }) @@ -68,7 +68,7 @@ fn create_offence_wont_slash_non_active_validators() { // so 31 didn't get slashed. assert_eq!(Balances::free_balance(31), 500); - // but 11 is an active validator so he got slashed. + // but 11 is an active validator so they got slashed. assert_eq!(Balances::free_balance(11), 800); }) } diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index acd41895287c5..9635717d4cf5d 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -1901,7 +1901,7 @@ fn wrong_vote_is_moot() { #[test] fn bond_with_no_staked_value() { // Behavior when someone bonds with no staked value. - // Particularly when she votes and the candidate is elected. + // Particularly when they votes and the candidate is elected. ExtBuilder::default() .validator_count(3) .existential_deposit(5) diff --git a/frame/uniques/src/functions.rs b/frame/uniques/src/functions.rs index 03dba16eaa12b..f73e5c479de67 100644 --- a/frame/uniques/src/functions.rs +++ b/frame/uniques/src/functions.rs @@ -50,8 +50,8 @@ impl, I: 'static> Pallet { 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. + // be possible, where the owner can approve their second account before making the + // transaction and then claiming the item back. details.approved = None; Item::::insert(&collection, &item, &details); From ce2cee35f8f0fc5968ea6ffaffa6660dcd008804 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Fri, 27 Jan 2023 15:59:39 -0500 Subject: [PATCH 339/715] migrate new benchmarking syntax from `frame_support::benchmarking` to `frame_benchmarking::v2` (#13235) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * * re-export frame_support::benchmarking in frame_benchmarking:: * prefer use frame_benchmarking::*; in examples, etc * switch to frame_benchmarking::v2 * completely migrate new benchmarking code out of frame_support * fix doc links * remove unneeded return Co-authored-by: Bastian Köcher * remove another unneeded return Co-authored-by: Bastian Köcher * properly export all macros in v1 * refactor existing frame_benchmarking imports to use ::v1 --------- Co-authored-by: Bastian Köcher --- Cargo.lock | 3 +- .../pallets/template/src/benchmarking.rs | 2 +- frame/alliance/src/benchmarking.rs | 2 +- frame/assets/src/benchmarking.rs | 2 +- frame/babe/src/benchmarking.rs | 2 +- frame/bags-list/src/benchmarks.rs | 6 +- frame/balances/src/benchmarking.rs | 3 +- frame/benchmarking/Cargo.toml | 2 + frame/benchmarking/src/lib.rs | 2107 ++--------------- frame/benchmarking/src/v1.rs | 2043 ++++++++++++++++ frame/bounties/src/benchmarking.rs | 4 +- frame/child-bounties/src/benchmarking.rs | 2 +- frame/collective/src/benchmarking.rs | 2 +- frame/contracts/src/benchmarking/mod.rs | 2 +- frame/conviction-voting/src/benchmarking.rs | 2 +- frame/democracy/src/benchmarking.rs | 2 +- .../benchmarking/src/lib.rs | 2 +- frame/elections-phragmen/src/benchmarking.rs | 2 +- frame/examples/basic/src/benchmarking.rs | 7 +- frame/fast-unstake/src/benchmarking.rs | 2 +- frame/grandpa/src/benchmarking.rs | 2 +- frame/identity/src/benchmarking.rs | 2 +- frame/im-online/src/benchmarking.rs | 2 +- frame/indices/src/benchmarking.rs | 2 +- frame/lottery/src/benchmarking.rs | 2 +- frame/membership/src/lib.rs | 2 +- .../merkle-mountain-range/src/benchmarking.rs | 2 +- frame/message-queue/src/benchmarking.rs | 4 +- frame/multisig/src/benchmarking.rs | 2 +- frame/nfts/src/benchmarking.rs | 2 +- frame/nis/src/benchmarking.rs | 2 +- .../nomination-pools/benchmarking/src/lib.rs | 4 +- frame/offences/benchmarking/src/lib.rs | 2 +- frame/preimage/src/benchmarking.rs | 2 +- frame/proxy/src/benchmarking.rs | 2 +- frame/ranked-collective/src/benchmarking.rs | 2 +- frame/recovery/src/benchmarking.rs | 2 +- frame/referenda/src/benchmarking.rs | 2 +- frame/remark/src/benchmarking.rs | 2 +- frame/scheduler/src/benchmarking.rs | 2 +- frame/session/benchmarking/src/lib.rs | 2 +- frame/staking/src/benchmarking.rs | 2 +- frame/support/Cargo.toml | 1 - frame/support/procedural/src/benchmark.rs | 2 +- frame/support/procedural/src/lib.rs | 10 +- frame/support/src/lib.rs | 223 -- .../test/tests/benchmark_ui/bad_param_name.rs | 2 +- .../benchmark_ui/bad_param_name_too_long.rs | 4 +- .../benchmark_ui/bad_param_name_upper_case.rs | 2 +- .../tests/benchmark_ui/bad_param_range.rs | 2 +- .../test/tests/benchmark_ui/bad_params.rs | 2 +- .../test/tests/benchmark_ui/dup_block.rs | 2 +- .../tests/benchmark_ui/dup_extrinsic_call.rs | 2 +- .../test/tests/benchmark_ui/extra_extra.rs | 2 +- .../tests/benchmark_ui/extra_skip_meta.rs | 2 +- .../benchmark_ui/extrinsic_call_out_of_fn.rs | 2 +- .../test/tests/benchmark_ui/missing_call.rs | 2 +- .../test/tests/benchmark_ui/missing_origin.rs | 2 +- .../tests/benchmark_ui/pass/valid_basic.rs | 2 +- .../tests/benchmark_ui/unrecognized_option.rs | 2 +- frame/system/benchmarking/src/lib.rs | 2 +- frame/timestamp/src/benchmarking.rs | 2 +- frame/tips/src/benchmarking.rs | 2 +- frame/transaction-storage/src/benchmarking.rs | 2 +- frame/treasury/src/benchmarking.rs | 2 +- frame/uniques/src/benchmarking.rs | 2 +- frame/utility/src/benchmarking.rs | 2 +- frame/vesting/src/benchmarking.rs | 2 +- frame/whitelist/src/benchmarking.rs | 2 +- 69 files changed, 2291 insertions(+), 2240 deletions(-) create mode 100644 frame/benchmarking/src/v1.rs diff --git a/Cargo.lock b/Cargo.lock index 7bbe5469212b2..6aafb0e175d98 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2138,6 +2138,7 @@ version = "4.0.0-dev" dependencies = [ "array-bytes", "frame-support", + "frame-support-procedural", "frame-system", "linregress", "log", @@ -2155,6 +2156,7 @@ dependencies = [ "sp-runtime-interface", "sp-std", "sp-storage", + "static_assertions", ] [[package]] @@ -2351,7 +2353,6 @@ dependencies = [ "sp-std", "sp-tracing", "sp-weights", - "static_assertions", "tt-call", ] diff --git a/bin/node-template/pallets/template/src/benchmarking.rs b/bin/node-template/pallets/template/src/benchmarking.rs index d496a9fc89b1a..1790849970440 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, whitelisted_caller}; +use frame_benchmarking::v1::{benchmarks, whitelisted_caller}; use frame_system::RawOrigin; benchmarks! { diff --git a/frame/alliance/src/benchmarking.rs b/frame/alliance/src/benchmarking.rs index a34b76bd96ece..f312e032bbb0f 100644 --- a/frame/alliance/src/benchmarking.rs +++ b/frame/alliance/src/benchmarking.rs @@ -25,7 +25,7 @@ use sp_std::{ prelude::*, }; -use frame_benchmarking::{account, benchmarks_instance_pallet}; +use frame_benchmarking::v1::{account, benchmarks_instance_pallet}; use frame_support::traits::{EnsureOrigin, Get, UnfilteredDispatchable}; use frame_system::{Pallet as System, RawOrigin as SystemOrigin}; diff --git a/frame/assets/src/benchmarking.rs b/frame/assets/src/benchmarking.rs index 235d1d9374504..9acf69f1e4ef4 100644 --- a/frame/assets/src/benchmarking.rs +++ b/frame/assets/src/benchmarking.rs @@ -20,7 +20,7 @@ #![cfg(feature = "runtime-benchmarks")] use super::*; -use frame_benchmarking::{ +use frame_benchmarking::v1::{ account, benchmarks_instance_pallet, whitelist_account, whitelisted_caller, }; use frame_support::{ diff --git a/frame/babe/src/benchmarking.rs b/frame/babe/src/benchmarking.rs index 20002c97f8e56..70605e4cff34c 100644 --- a/frame/babe/src/benchmarking.rs +++ b/frame/babe/src/benchmarking.rs @@ -20,7 +20,7 @@ #![cfg(feature = "runtime-benchmarks")] use super::*; -use frame_benchmarking::benchmarks; +use frame_benchmarking::v1::benchmarks; type Header = sp_runtime::generic::Header; diff --git a/frame/bags-list/src/benchmarks.rs b/frame/bags-list/src/benchmarks.rs index 1f66697cb6765..74ae5f31ac81f 100644 --- a/frame/bags-list/src/benchmarks.rs +++ b/frame/bags-list/src/benchmarks.rs @@ -19,13 +19,15 @@ use super::*; use crate::list::List; -use frame_benchmarking::{account, whitelist_account, whitelisted_caller}; +use frame_benchmarking::v1::{ + account, benchmarks_instance_pallet, whitelist_account, whitelisted_caller, +}; 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_instance_pallet! { +benchmarks_instance_pallet! { rebag_non_terminal { // An expensive case for rebag-ing (rebag a non-terminal node): // diff --git a/frame/balances/src/benchmarking.rs b/frame/balances/src/benchmarking.rs index f85ff43b715fe..d80aa3ec8e57e 100644 --- a/frame/balances/src/benchmarking.rs +++ b/frame/balances/src/benchmarking.rs @@ -22,8 +22,7 @@ use super::*; use crate::Pallet as Balances; -use frame_benchmarking::{account, impl_benchmark_test_suite, whitelisted_caller}; -use frame_support::benchmarking::*; +use frame_benchmarking::v2::*; use frame_system::RawOrigin; const SEED: u32 = 0; diff --git a/frame/benchmarking/Cargo.toml b/frame/benchmarking/Cargo.toml index b2a9621ebf250..4ff2077d7f7c5 100644 --- a/frame/benchmarking/Cargo.toml +++ b/frame/benchmarking/Cargo.toml @@ -20,6 +20,7 @@ paste = "1.0" 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-support-procedural = { version = "4.0.0-dev", default-features = false, path = "../support/procedural" } 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 = "7.0.0", default-features = false, path = "../../primitives/application-crypto" } @@ -29,6 +30,7 @@ sp-runtime = { version = "7.0.0", default-features = false, path = "../../primit 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" } +static_assertions = "1.1.0" [dev-dependencies] array-bytes = "4.1" diff --git a/frame/benchmarking/src/lib.rs b/frame/benchmarking/src/lib.rs index 525370e23385a..a3bf809f6b9ba 100644 --- a/frame/benchmarking/src/lib.rs +++ b/frame/benchmarking/src/lib.rs @@ -50,2005 +50,226 @@ pub use sp_std::{self, boxed::Box, prelude::Vec, str, vec}; pub use sp_storage::{well_known_keys, TrackedStorageKey}; pub use utils::*; -/// Whitelist the given account. -#[macro_export] -macro_rules! whitelist { - ($acc:ident) => { - frame_benchmarking::benchmarking::add_to_whitelist( - frame_system::Account::::hashed_key_for(&$acc).into(), - ); - }; -} +pub mod v1; +pub use v1::*; -/// Construct pallet benchmarks for weighing dispatchables. -/// -/// Works around the idea of complexity parameters, named by a single letter (which is usually -/// upper cased in complexity notation but is lower-cased for use in this macro). -/// -/// Complexity parameters ("parameters") have a range which is a `u32` pair. Every time a benchmark -/// is prepared and run, this parameter takes a concrete value within the range. There is an -/// associated instancing block, which is a single expression that is evaluated during -/// preparation. It may use `?` (`i.e. `return Err(...)`) to bail with a string error. Here's a -/// few examples: -/// -/// ```ignore -/// // These two are equivalent: -/// let x in 0 .. 10; -/// let x in 0 .. 10 => (); -/// // This one calls a setup function and might return an error (which would be terminal). -/// let y in 0 .. 10 => setup(y)?; -/// // This one uses a code block to do lots of stuff: -/// let z in 0 .. 10 => { -/// let a = z * z / 5; -/// let b = do_something(a)?; -/// combine_into(z, b); -/// } -/// ``` +/// Contains macros, structs, and traits associated with v2 of the pallet benchmarking syntax. /// -/// 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 parenthesized. +/// The [`v2::benchmarks`] and [`v2::instance_benchmarks`] macros can be used to designate a +/// module as a benchmarking module that can contain benchmarks and benchmark tests. The +/// `#[benchmarks]` variant will set up a regular, non-instance benchmarking module, and the +/// `#[instance_benchmarks]` variant will set up the module in instance benchmarking mode. /// -/// 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 expressions to be evaluated in a benchmark (including for example, -/// `on_initialize`). +/// Benchmarking modules should be gated behind a `#[cfg(feature = "runtime-benchmarks")]` +/// feature gate to ensure benchmarking code that is only compiled when the +/// `runtime-benchmarks` feature is enabled is not referenced. /// -/// Note that the ranges are *inclusive* on both sides. This is in contrast to ranges in Rust which -/// are left-inclusive right-exclusive. +/// The following is the general syntax for a benchmarks (or instance benchmarks) module: /// -/// Each arm may also have a block of code which is run prior to any instancing and a block of code -/// which is run afterwards. All code blocks may draw upon the specific value of each parameter -/// at any time. Local variables are shared between the two pre- and post- code blocks, but do not -/// leak from the interior of any instancing expressions. +/// ## General Syntax /// -/// Example: /// ```ignore -/// benchmarks! { -/// where_clause { where T::A: From } // Optional line to give additional bound on `T`. -/// -/// // first dispatchable: foo; this is a user dispatchable and operates on a `u8` vector of -/// // size `l` -/// foo { -/// let caller = account::(b"caller", 0, benchmarks_seed); -/// let l in 1 .. MAX_LENGTH => initialize_l(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(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 -/// // pre-instancing block) within the code block. This is only allowed in the param instancers -/// // of arms. -/// baz1 { -/// let caller = account::(b"caller", 0, benchmarks_seed); -/// let c = 0 .. 10 => setup_c(&caller, c); -/// }: 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(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(RuntimeOrigin::Signed(caller), vec![0u8; l]) -/// -/// // this is benchmarking some code that is not a dispatchable. -/// populate_a_set { -/// let x in 0 .. 10_000; -/// let mut m = Vec::::new(); -/// for i in 0..x { -/// m.insert(i); -/// } -/// }: { m.into_iter().collect::() } -/// } -/// ``` -/// -/// Test functions are automatically generated for each benchmark and are accessible to you when you -/// run `cargo test`. All tests are named `test_benchmark_`, implemented on the -/// Pallet struct, and run them in a test externalities environment. The test function runs your -/// 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: -/// -/// ```ignore -/// sort_vector { -/// let x in 1 .. 10000; -/// let mut m = Vec::::new(); -/// for i in (0..x).rev() { -/// m.push(i); -/// } -/// }: { -/// m.sort(); -/// } verify { -/// ensure!(m[0] == 0, "You forgot to sort!") -/// } -/// ``` -/// -/// These `verify` blocks will not affect your benchmark results! -/// -/// You can construct benchmark by using the `impl_benchmark_test_suite` macro or -/// by manually implementing them like so: -/// -/// ```ignore -/// #[test] -/// fn test_benchmarks() { -/// new_test_ext().execute_with(|| { -/// assert_ok!(Pallet::::test_benchmark_dummy()); -/// assert_err!(Pallet::::test_benchmark_other_name(), "Bad origin"); -/// assert_ok!(Pallet::::test_benchmark_sort_vector()); -/// assert_err!(Pallet::::test_benchmark_broken_benchmark(), "You forgot to sort!"); -/// }); -/// } -/// ``` -#[macro_export] -macro_rules! benchmarks { - ( - $( $rest:tt )* - ) => { - $crate::benchmarks_iter!( - { } - { } - { } - ( ) - ( ) - ( ) - ( ) - $( $rest )* - ); - } -} - -/// Same as [`benchmarks`] but for instantiable module. -/// -/// NOTE: For pallet declared with [`frame_support::pallet`], use [`benchmarks_instance_pallet`]. -#[macro_export] -macro_rules! benchmarks_instance { - ( - $( $rest:tt )* - ) => { - $crate::benchmarks_iter!( - { } - { I: Instance } - { } - ( ) - ( ) - ( ) - ( ) - $( $rest )* - ); - } -} - -/// Same as [`benchmarks`] but for instantiable pallet declared [`frame_support::pallet`]. -/// -/// NOTE: For pallet declared with `decl_module!`, use [`benchmarks_instance`]. -#[macro_export] -macro_rules! benchmarks_instance_pallet { - ( - $( $rest:tt )* - ) => { - $crate::benchmarks_iter!( - { } - { I: 'static } - { } - ( ) - ( ) - ( ) - ( ) - $( $rest )* - ); - } -} - -#[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 )* ) - ( $( $pov_name:ident: $( $storage:path = $pov_mode:ident )*; )* ) - 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 )* ) - ( $( $pov_name: $( $storage = $pov_mode )*; )* ) - $( $rest )* - } - }; - // - without a semicolon - ( - { } - { $( $instance:ident: $instance_bound:tt )? } - { $( $where_clause:tt )* } - ( $( $names:tt )* ) - ( $( $names_extra:tt )* ) - ( $( $names_skip_meta:tt )* ) - ( $( $pov_name:ident: $( $storage:path = $pov_mode:ident )*; )* ) - 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 )* ) - ( $( $pov_name: $( $storage = $pov_mode )*; )* ) - $( $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 )* ) - ( $( $names_extra:tt )* ) - ( $( $names_skip_meta:tt )* ) - ( $( $pov_name:ident: $( $storage:path = $pov_mode:ident )*; )* ) - where_clause { where $( $where_bound:tt )* } - $( $rest:tt )* - ) => { - $crate::benchmarks_iter! { - { $($bench_module, $new_test_ext, $test $(, $( $args )* )?)? } - { $( $instance: $instance_bound)? } - { $( $where_bound )* } - ( $( $names )* ) - ( $( $names_extra )* ) - ( $( $names_skip_meta )* ) - ( $( $pov_name: $( $storage = $pov_mode )*; )* ) - $( $rest )* - } - }; - // 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 )* ) - ( $( $names_extra:tt )* ) - ( $( $names_skip_meta:tt )* ) - ( $( $pov_name:ident: $( $storage:path = $pov_mode:ident )*; )* ) - #[skip_meta] - $( #[ $($attributes:tt)+ ] )* - $name:ident - $( $rest:tt )* - ) => { - $crate::benchmarks_iter! { - { $($bench_module, $new_test_ext, $test $(, $( $args )* )?)? } - { $( $instance: $instance_bound )? } - { $( $where_clause )* } - ( $( $names )* ) - ( $( $names_extra )* ) - ( $( $names_skip_meta )* $name ) - ( $( $pov_name: $( $storage = $pov_mode )*; )* ) - $( #[ $( $attributes )+ ] )* - $name - $( $rest )* - } - }; - // 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 )* ) - ( $( $names_extra:tt )* ) - ( $( $names_skip_meta:tt )* ) - ( $( $pov_name:ident: $( $storage:path = $pov_mode:ident )*; )* ) - #[extra] - $( #[ $($attributes:tt)+ ] )* - $name:ident - $( $rest:tt )* - ) => { - $crate::benchmarks_iter! { - { $($bench_module, $new_test_ext, $test $(, $( $args )* )?)? } - { $( $instance: $instance_bound )? } - { $( $where_clause )* } - ( $( $names )* ) - ( $( $names_extra )* $name ) - ( $( $names_skip_meta )* ) - ( $( $pov_name: $( $storage = $pov_mode )*; )* ) - $( #[ $( $attributes )+ ] )* - $name - $( $rest )* - } - }; - // detect and extract `#[pov_mode = Mode { Pallet::Storage: Mode ... }]` tag: - ( - { $($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 )* ) - ( $( $old_pov_name:ident: $( $old_storage:path = $old_pov_mode:ident )*; )* ) - #[pov_mode = $mode:ident $( { $( $storage:path: $pov_mode:ident )* } )?] - $( #[ $($attributes:tt)+ ] )* - $name:ident - $( $rest:tt )* - ) => { - $crate::benchmarks_iter! { - { $($bench_module, $new_test_ext, $test $(, $( $args )* )?)? } - { $( $instance: $instance_bound )? } - { $( $where_clause )* } - ( $( $names )* ) - ( $( $names_extra )* ) - ( $( $names_skip_meta )* ) - ( $name: ALL = $mode $($( $storage = $pov_mode )*)?; $( $old_pov_name: $( $old_storage = $old_pov_mode )*; )* ) - $( #[ $( $attributes )+ ] )* - $name - $( $rest )* - } - }; - // 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 )* - ( $( $names_extra:tt )* ) - ( $( $names_skip_meta:tt )* ) - ( $( $pov_name:ident: $( $storage:path = $pov_mode:ident )*; )* ) - $name:ident { $( $code:tt )* }: _ $(< $origin_type:ty>)? ( $origin:expr $( , $arg:expr )* ) - verify $postcode:block - $( $rest:tt )* - ) => { - $crate::benchmarks_iter! { - { $($bench_module, $new_test_ext, $test $(, $( $args )* )?)? } - { $( $instance: $instance_bound )? } - { $( $where_clause )* } - ( $( $names )* ) - ( $( $names_extra )* ) - ( $( $names_skip_meta )* ) - ( $( $pov_name: $( $storage = $pov_mode )*; )* ) - $name { $( $code )* }: $name $(< $origin_type >)? ( $origin $( , $arg )* ) - verify $postcode - $( $rest )* - } - }; - // mutation arm: - ( - { $($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 )* ) - ( $( $pov_name:ident: $( $storage:path = $pov_mode:ident )*; )* ) - $name:ident { $( $code:tt )* }: $dispatch:ident $(<$origin_type:ty>)? ( $origin:expr $( , $arg:expr )* ) - verify $postcode:block - $( $rest:tt )* - ) => { - $crate::paste::paste! { - $crate::benchmarks_iter! { - { $($bench_module, $new_test_ext, $test $(, $( $args )* )?)? } - { $( $instance: $instance_bound )? } - { $( $where_clause )* } - ( $( $names )* ) - ( $( $names_extra )* ) - ( $( $names_skip_meta )* ) - ( $( $pov_name: $( $storage = $pov_mode )*; )* ) - $name { - $( $code )* - let __call = Call::< - T - $( , $instance )? - >:: [< new_call_variant_ $dispatch >] ( - $($arg),* - ); - let __benchmarked_call_encoded = $crate::frame_support::codec::Encode::encode( - &__call - ); - }: { - let __call_decoded = < - Call - as $crate::frame_support::codec::Decode - >::decode(&mut &__benchmarked_call_encoded[..]) - .expect("call is encoded above, encoding must be correct"); - let __origin = $crate::to_origin!($origin $(, $origin_type)?); - as $crate::frame_support::traits::UnfilteredDispatchable - >::dispatch_bypass_filter(__call_decoded, __origin)?; - } - verify $postcode - $( $rest )* - } - } - }; - // iteration arm: - ( - { $($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 )* ) - ( $( $pov_name:ident: $( $storage:path = $pov_mode:ident )*; )* ) - $name:ident { $( $code:tt )* }: $eval:block - verify $postcode:block - $( $rest:tt )* - ) => { - $crate::benchmark_backend! { - { $( $instance: $instance_bound )? } - $name - { $( $where_clause )* } - { } - { $eval } - { $( $code )* } - $postcode - } - - #[cfg(test)] - $crate::impl_benchmark_test!( - { $( $where_clause )* } - { $( $instance: $instance_bound )? } - $name - ); - - $crate::benchmarks_iter!( - { $($bench_module, $new_test_ext, $test $(, $( $args )* )?)? } - { $( $instance: $instance_bound )? } - { $( $where_clause )* } - ( $( $names )* { $( $instance )? } $name ) - ( $( $names_extra )* ) - ( $( $names_skip_meta )* ) - ( $( $pov_name: $( $storage = $pov_mode )*; )* ) - $( $rest )* - ); - }; - // 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 )* ) - ( $( $pov_name:ident: $( $storage:path = $pov_mode:ident )*; )* ) - ) => { - $crate::selected_benchmark!( - { $( $where_clause)* } - { $( $instance: $instance_bound )? } - $( $names )* - ); - $crate::impl_benchmark!( - { $( $where_clause )* } - { $( $instance: $instance_bound )? } - ( $( $names )* ) - ( $( $names_extra ),* ) - ( $( $names_skip_meta ),* ) - ( $( $pov_name: $( $storage = $pov_mode )*; )* ) - ); - $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 )* ) - ( $( $names_extra:tt )* ) - ( $( $names_skip_meta:tt )* ) - ( $( $pov_name:ident: $( $storage:path = $pov_mode:ident )*; )* ) - ) => { - $crate::selected_benchmark!( - { $( $where_clause)* } - { $( $instance: $instance_bound )? } - $( $names )* - ); - $crate::impl_benchmark!( - { $( $where_clause )* } - { $( $instance: $instance_bound )? } - ( $( $names )* ) - ( $( $names_extra ),* ) - ( $( $names_skip_meta ),* ) - ( $( $pov_name: $( $storage = $pov_mode )*; )* ) - ); - }; - // 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 )* ) - ( $( $names_extra:tt )* ) - ( $( $names_skip_meta:tt )* ) - ( $( $pov_name:ident: $( $storage:path = $pov_mode:ident )*; )* ) - $name:ident { $( $code:tt )* }: _ $(<$origin_type:ty>)? ( $origin:expr $( , $arg:expr )* ) - $( $rest:tt )* - ) => { - $crate::benchmarks_iter! { - { $($bench_module, $new_test_ext, $test $(, $( $args )* )?)? } - { $( $instance: $instance_bound )? } - { $( $where_clause )* } - ( $( $names )* ) - ( $( $names_extra )* ) - ( $( $names_skip_meta )* ) - ( $( $pov_name: $( $storage = $pov_mode )*; )* ) - $name { $( $code )* }: _ $(<$origin_type>)? ( $origin $( , $arg )* ) - verify { } - $( $rest )* - } - }; - // 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 )* ) - ( $( $names_extra:tt )* ) - ( $( $names_skip_meta:tt )* ) - ( $( $pov_name:ident: $( $storage:path = $pov_mode:ident )*; )* ) - $name:ident { $( $code:tt )* }: $dispatch:ident $(<$origin_type:ty>)? ( $origin:expr $( , $arg:expr )* ) - $( $rest:tt )* - ) => { - $crate::benchmarks_iter! { - { $($bench_module, $new_test_ext, $test $(, $( $args )* )?)? } - { $( $instance: $instance_bound )? } - { $( $where_clause )* } - ( $( $names )* ) - ( $( $names_extra )* ) - ( $( $names_skip_meta )* ) - ( $( $pov_name: $( $storage = $pov_mode )*; )* ) - $name { $( $code )* }: $dispatch $(<$origin_type>)? ( $origin $( , $arg )* ) - verify { } - $( $rest )* - } - }; - // 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 )* ) - ( $( $names_extra:tt )* ) - ( $( $names_skip_meta:tt )* ) - ( $( $pov_name:ident: $( $storage:path = $pov_mode:ident )*; )* ) - $name:ident { $( $code:tt )* }: $(<$origin_type:ty>)? $eval:block - $( $rest:tt )* - ) => { - $crate::benchmarks_iter!( - { $($bench_module, $new_test_ext, $test $(, $( $args )* )?)? } - { $( $instance: $instance_bound )? } - { $( $where_clause )* } - ( $( $names )* ) - ( $( $names_extra )* ) - ( $( $names_skip_meta )* ) - ( $( $pov_name: $( $storage = $pov_mode )*; )* ) - $name { $( $code )* }: $(<$origin_type>)? $eval - verify { } - $( $rest )* - ); - }; -} - -#[macro_export] -#[doc(hidden)] -macro_rules! to_origin { - ($origin:expr) => { - $origin.into() - }; - ($origin:expr, $origin_type:ty) => { - <::RuntimeOrigin as From<$origin_type>>::from($origin) - }; -} - -#[macro_export] -#[doc(hidden)] -macro_rules! benchmark_backend { - // parsing arms - ( - { $( $instance:ident: $instance_bound:tt )? } - $name:ident - { $( $where_clause:tt )* } - { $( PRE { $( $pre_parsed:tt )* } )* } - { $eval:block } - { - let $pre_id:tt : $pre_ty:ty = $pre_ex:expr; - $( $rest:tt )* - } - $postcode:block - ) => { - $crate::benchmark_backend! { - { $( $instance: $instance_bound )? } - $name - { $( $where_clause )* } - { - $( PRE { $( $pre_parsed )* } )* - PRE { $pre_id , $pre_ty , $pre_ex } - } - { $eval } - { $( $rest )* } - $postcode - } - }; - ( - { $( $instance:ident: $instance_bound:tt )? } - $name:ident - { $( $where_clause:tt )* } - { $( $parsed:tt )* } - { $eval:block } - { - let $param:ident in ( $param_from:expr ) .. $param_to:expr => $param_instancer:expr; - $( $rest:tt )* - } - $postcode:block - ) => { - $crate::benchmark_backend! { - { $( $instance: $instance_bound )? } - $name - { $( $where_clause )* } - { - $( $parsed )* - PARAM { $param , $param_from , $param_to , $param_instancer } - } - { $eval } - { $( $rest )* } - $postcode - } - }; - // mutation arm to look after a single tt for param_from. - ( - { $( $instance:ident: $instance_bound:tt )? } - $name:ident - { $( $where_clause:tt )* } - { $( $parsed:tt )* } - { $eval:block } - { - let $param:ident in $param_from:tt .. $param_to:expr => $param_instancer:expr ; - $( $rest:tt )* - } - $postcode:block - ) => { - $crate::benchmark_backend! { - { $( $instance: $instance_bound )? } - $name - { $( $where_clause )* } - { $( $parsed )* } - { $eval } - { - let $param in ( $param_from ) .. $param_to => $param_instancer; - $( $rest )* - } - $postcode - } - }; - // mutation arm to look after the default tail of `=> ()` - ( - { $( $instance:ident: $instance_bound:tt )? } - $name:ident - { $( $where_clause:tt )* } - { $( $parsed:tt )* } - { $eval:block } - { - let $param:ident in $param_from:tt .. $param_to:expr; - $( $rest:tt )* - } - $postcode:block - ) => { - $crate::benchmark_backend! { - { $( $instance: $instance_bound )? } - $name - { $( $where_clause )* } - { $( $parsed )* } - { $eval } - { - let $param in $param_from .. $param_to => (); - $( $rest )* - } - $postcode - } - }; - // mutation arm to look after `let _ =` - ( - { $( $instance:ident: $instance_bound:tt )? } - $name:ident - { $( $where_clause:tt )* } - { $( $parsed:tt )* } - { $eval:block } - { - let $pre_id:tt = $pre_ex:expr; - $( $rest:tt )* - } - $postcode:block - ) => { - $crate::benchmark_backend! { - { $( $instance: $instance_bound )? } - $name - { $( $where_clause )* } - { $( $parsed )* } - { $eval } - { - let $pre_id : _ = $pre_ex; - $( $rest )* - } - $postcode - } - }; - // actioning arm - ( - { $( $instance:ident: $instance_bound:tt )? } - $name:ident - { $( $where_clause:tt )* } - { - $( PRE { $pre_id:tt , $pre_ty:ty , $pre_ex:expr } )* - $( PARAM { $param:ident , $param_from:expr , $param_to:expr , $param_instancer:expr } )* - } - { $eval:block } - { $( $post:tt )* } - $postcode:block - ) => { - #[allow(non_camel_case_types)] - struct $name; - #[allow(unused_variables)] - impl, $instance: $instance_bound )? > - $crate::BenchmarkingSetup for $name - where $( $where_clause )* - { - fn components(&self) -> $crate::Vec<($crate::BenchmarkParameter, u32, u32)> { - $crate::vec! [ - $( - ($crate::BenchmarkParameter::$param, $param_from, $param_to) - ),* - ] - } - - fn instance( - &self, - components: &[($crate::BenchmarkParameter, u32)], - verify: bool - ) -> Result<$crate::Box Result<(), $crate::BenchmarkError>>, $crate::BenchmarkError> { - $( - // Prepare instance - let $param = components.iter() - .find(|&c| c.0 == $crate::BenchmarkParameter::$param) - .ok_or("Could not find component in benchmark preparation.")? - .1; - )* - $( - let $pre_id : $pre_ty = $pre_ex; - )* - $( $param_instancer ; )* - $( $post )* - - Ok($crate::Box::new(move || -> Result<(), $crate::BenchmarkError> { - $eval; - if verify { - $postcode; - } - Ok(()) - })) - } - } - }; -} - -// 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), - ); - }, - $crate::BenchmarkError::Weightless => { - // This is considered a success condition. - $crate::log::error!( - "WARNING: benchmark weightless 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`]. -// -// ```nocompile -// -// struct Transfer; -// impl BenchmarkingSetup for Transfer { ... } -// -// struct SetBalance; -// impl BenchmarkingSetup for SetBalance { ... } -// -// selected_benchmark!({} Transfer {} SetBalance); -// ``` -#[macro_export] -#[doc(hidden)] -macro_rules! selected_benchmark { - ( - { $( $where_clause:tt )* } - { $( $instance:ident: $instance_bound:tt )? } - $( { $( $bench_inst:ident )? } $bench:ident )* - ) => { - // The list of available benchmarks for this pallet. - #[allow(non_camel_case_types)] - enum SelectedBenchmark { - $( $bench, )* - } - - // Allow us to select a benchmark from the list of available benchmarks. - impl, $instance: $instance_bound )? > - $crate::BenchmarkingSetup for SelectedBenchmark - where $( $where_clause )* - { - fn components(&self) -> $crate::Vec<($crate::BenchmarkParameter, u32, u32)> { - match self { - $( - Self::$bench => < - $bench as $crate::BenchmarkingSetup - >::components(&$bench), - )* - } - } - - fn instance( - &self, - components: &[($crate::BenchmarkParameter, u32)], - verify: bool - ) -> Result<$crate::Box Result<(), $crate::BenchmarkError>>, $crate::BenchmarkError> { - match self { - $( - Self::$bench => < - $bench as $crate::BenchmarkingSetup - >::instance(&$bench, components, verify), - )* - } - } - } - }; -} - -#[macro_export] -#[doc(hidden)] -macro_rules! impl_benchmark { - ( - { $( $where_clause:tt )* } - { $( $instance:ident: $instance_bound:tt )? } - ( $( { $( $name_inst:ident )? } $name:ident )* ) - ( $( $name_extra:ident ),* ) - ( $( $name_skip_meta:ident ),* ) - ( $( $pov_name:ident: $( $storage:path = $pov_mode: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 )* - { - fn benchmarks(extra: bool) -> $crate::Vec<$crate::BenchmarkMetadata> { - $($crate::validate_pov_mode!( - $pov_name: $( $storage = $pov_mode )*; - );)* - let mut all_names = $crate::vec![ $( stringify!($name).as_ref() ),* ]; - if !extra { - let extra = [ $( stringify!($name_extra).as_ref() ),* ]; - all_names.retain(|x| !extra.contains(x)); - } - let pov_modes: $crate::Vec<($crate::Vec, $crate::Vec<($crate::Vec, $crate::Vec)>)> = $crate::vec![ - $( - (stringify!($pov_name).as_bytes().to_vec(), - $crate::vec![ - $( ( stringify!($storage).as_bytes().to_vec(), - stringify!($pov_mode).as_bytes().to_vec() ), )* - ]), - )* - ]; - all_names.into_iter().map(|benchmark| { - let selected_benchmark = match benchmark { - $( stringify!($name) => SelectedBenchmark::$name, )* - _ => panic!("all benchmarks should be selectable"), - }; - let name = benchmark.as_bytes().to_vec(); - let components = < - SelectedBenchmark as $crate::BenchmarkingSetup - >::components(&selected_benchmark); - - $crate::BenchmarkMetadata { - name: name.clone(), - components, - pov_modes: pov_modes.iter().find(|p| p.0 == name).map(|p| p.1.clone()).unwrap_or_default(), - } - }).collect::<$crate::Vec<_>>() - } - - fn run_benchmark( - extrinsic: &[u8], - c: &[($crate::BenchmarkParameter, u32)], - whitelist: &[$crate::TrackedStorageKey], - verify: bool, - internal_repeats: u32, - ) -> Result<$crate::Vec<$crate::BenchmarkResult>, $crate::BenchmarkError> { - // Map the input to the selected benchmark. - let extrinsic = $crate::str::from_utf8(extrinsic) - .map_err(|_| "`extrinsic` is not a valid utf8 string!")?; - let selected_benchmark = match extrinsic { - $( stringify!($name) => SelectedBenchmark::$name, )* - _ => return Err("Could not find extrinsic.".into()), - }; - - // Add whitelist to DB including whitelisted caller - let mut whitelist = whitelist.to_vec(); - let whitelisted_caller_key = - as $crate::frame_support::storage::StorageMap<_,_>>::hashed_key_for( - $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); - // Whitelist the `:extrinsic_index`. - let extrinsic_index = $crate::TrackedStorageKey::new( - $crate::well_known_keys::EXTRINSIC_INDEX.into() - ); - whitelist.push(extrinsic_index); - - $crate::benchmarking::set_whitelist(whitelist.clone()); - - let mut results: $crate::Vec<$crate::BenchmarkResult> = $crate::Vec::new(); - - // 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 = < - SelectedBenchmark as $crate::BenchmarkingSetup - >::instance(&selected_benchmark, c, verify)?; - - // Set the block number to at least 1 so events are deposited. - if $crate::Zero::is_zero(&frame_system::Pallet::::block_number()) { - frame_system::Pallet::::set_block_number(1u32.into()); - } - - // Commit the externalities to the database, flushing the DB cache. - // This will enable worst case scenario for reading from the database. - $crate::benchmarking::commit_db(); - - // Access all whitelisted keys to get them into the proof recorder since the - // recorder does now have a whitelist. - for key in &whitelist { - $crate::frame_support::storage::unhashed::get_raw(&key.key); - } - - // Reset the read/write counter so we don't count operations in the setup process. - $crate::benchmarking::reset_read_write_count(); - - // Time the extrinsic logic. - $crate::log::trace!( - target: "benchmark", - "Start Benchmark: {} ({:?}) verify {}", - extrinsic, - c, - verify - ); - - let start_pov = $crate::benchmarking::proof_size(); - let start_extrinsic = $crate::benchmarking::current_time(); - - closure_to_benchmark()?; - - let finish_extrinsic = $crate::benchmarking::current_time(); - let end_pov = $crate::benchmarking::proof_size(); - - // Calculate the diff caused by the benchmark. - let elapsed_extrinsic = finish_extrinsic.saturating_sub(start_extrinsic); - let diff_pov = match (start_pov, end_pov) { - (Some(start), Some(end)) => end.saturating_sub(start), - _ => Default::default(), - }; - - // Commit the changes to get proper write count - $crate::benchmarking::commit_db(); - $crate::log::trace!( - target: "benchmark", - "End Benchmark: {} ns", elapsed_extrinsic - ); - let read_write_count = $crate::benchmarking::read_write_count(); - $crate::log::trace!( - target: "benchmark", - "Read/Write Count {:?}", read_write_count - ); - $crate::log::trace!( - target: "benchmark", - "Proof sizes: before {:?} after {:?} diff {}", &start_pov, &end_pov, &diff_pov - ); - - // Time the storage root recalculation. - let start_storage_root = $crate::benchmarking::current_time(); - $crate::storage_root($crate::StateVersion::V1); - let finish_storage_root = $crate::benchmarking::current_time(); - let elapsed_storage_root = finish_storage_root - start_storage_root; - - let skip_meta = [ $( stringify!($name_skip_meta).as_ref() ),* ]; - let read_and_written_keys = if skip_meta.contains(&extrinsic) { - $crate::vec![(b"Skipped Metadata".to_vec(), 0, 0, false)] - } else { - $crate::benchmarking::get_read_and_written_keys() - }; - - results.push($crate::BenchmarkResult { - components: c.to_vec(), - extrinsic_time: elapsed_extrinsic, - storage_root_time: elapsed_storage_root, - reads: read_write_count.0, - repeat_reads: read_write_count.1, - writes: read_write_count.2, - repeat_writes: read_write_count.3, - proof_size: diff_pov, - keys: read_and_written_keys, - }); - } - - return Ok(results); - } - } - - #[cfg(test)] - impl, $instance: $instance_bound )? > - Pallet - where T: frame_system::Config, $( $where_clause )* - { - /// Test a particular benchmark by name. - /// - /// This isn't called `test_benchmark_by_name` just in case some end-user eventually - /// writes a benchmark, itself called `by_name`; the function would be shadowed in - /// that case. - /// - /// This is generally intended to be used by child test modules such as those created - /// by the `impl_benchmark_test_suite` macro. However, it is not an error if a pallet - /// author chooses not to implement benchmarks. - #[allow(unused)] - fn test_bench_by_name(name: &[u8]) -> Result<(), $crate::BenchmarkError> { - let name = $crate::str::from_utf8(name) - .map_err(|_| -> $crate::BenchmarkError { "`name` is not a valid utf8 string!".into() })?; - match name { - $( stringify!($name) => { - $crate::paste::paste! { Self::[< test_benchmark_ $name >]() } - } )* - _ => Err("Could not find test for requested benchmark.".into()), - } - } - } - }; -} - -// 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 { - ( - { $( $where_clause:tt )* } - { $( $instance:ident: $instance_bound:tt )? } - $name:ident - ) => { - $crate::paste::item! { - #[cfg(test)] - impl, $instance: $instance_bound )? > - Pallet - where T: frame_system::Config, $( $where_clause )* - { - #[allow(unused)] - fn [] () -> Result<(), $crate::BenchmarkError> { - let selected_benchmark = SelectedBenchmark::$name; - let components = < - SelectedBenchmark as $crate::BenchmarkingSetup - >::components(&selected_benchmark); - - 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 - >::instance(&selected_benchmark, &c, true)?; - - // Set the block number to at least 1 so events are deposited. - if $crate::Zero::is_zero(&frame_system::Pallet::::block_number()) { - frame_system::Pallet::::set_block_number(1u32.into()); - } - - // Run execution + verification - closure_to_verify() - }; - - if components.is_empty() { - execute_benchmark(Default::default())?; - } else { - 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) - } else { - (*n, *h) - } - ) - .collect(); - - execute_benchmark(c)?; - } - } - } - Ok(()) - } - } - } - }; -} - -/// This creates a test suite which runs the module's benchmarks. +/// #![cfg(feature = "runtime-benchmarks")] /// -/// When called in `pallet_example_basic` as +/// use super::{mock_helpers::*, Pallet as MyPallet}; +/// use frame_benchmarking::v2::*; /// -/// ```rust,ignore -/// impl_benchmark_test_suite!(Pallet, crate::tests::new_test_ext(), crate::tests::Test); -/// ``` -/// -/// It expands to the equivalent of: -/// -/// ```rust,ignore -/// #[cfg(test)] -/// mod tests { +/// #[benchmarks] +/// mod benchmarks { /// use super::*; -/// use crate::tests::{new_test_ext, Test}; -/// use frame_support::assert_ok; /// -/// #[test] -/// fn test_benchmarks() { -/// new_test_ext().execute_with(|| { -/// assert_ok!(test_benchmark_accumulate_dummy::()); -/// assert_ok!(test_benchmark_set_dummy::()); -/// assert_ok!(test_benchmark_sort_vector::()); -/// }); -/// } -/// } -/// ``` -/// -/// When called inside the `benchmarks` macro of the `pallet_example_basic` as -/// -/// ```rust,ignore -/// benchmarks! { -/// // Benchmarks omitted for brevity +/// #[benchmark] +/// fn bench_name_1(x: Linear<7, 1_000>, y: Linear<1_000, 100_0000>) { +/// // setup code +/// let z = x + y; +/// let caller = whitelisted_caller(); /// -/// impl_benchmark_test_suite!(Pallet, crate::tests::new_test_ext(), crate::tests::Test); -/// } -/// ``` +/// #[extrinsic_call] +/// extrinsic_name(SystemOrigin::Signed(caller), other, arguments); /// -/// 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::()); -/// }) +/// // verification code +/// assert_eq!(MyPallet::::my_var(), z); /// } /// -/// #[test] -/// fn bench_set_dummy() { -/// new_test_ext().execute_with(|| { -/// assert_ok!(test_benchmark_set_dummy::()); -/// }) -/// } +/// #[benchmark] +/// fn bench_name_2() { +/// // setup code +/// let caller = whitelisted_caller(); /// -/// #[test] -/// fn bench_sort_vector() { -/// new_test_ext().execute_with(|| { -/// assert_ok!(test_benchmark_sort_vector::()); -/// }) +/// #[block] +/// { +/// something(some, thing); +/// my_extrinsic(RawOrigin::Signed(caller), some, argument); +/// something_else(foo, bar); +/// } +/// +/// // verification code +/// assert_eq!(MyPallet::::something(), 37); /// } /// } /// ``` /// -/// ## Arguments +/// ## Benchmark Definitions /// -/// The first argument, `module`, must be the path to this crate's module. +/// Within a `#[benchmarks]` or `#[instance_benchmarks]` module, you can define individual +/// benchmarks using the `#[benchmark]` attribute, as shown in the example above. /// -/// The second argument, `new_test_ext`, must be a function call which returns either a -/// `sp_io::TestExternalities`, or some other type with a similar interface. +/// The `#[benchmark]` attribute expects a function definition with a blank return type and +/// zero or more arguments whose names are valid +/// [BenchmarkParameter](`crate::BenchmarkParameter`) parameters, such as `x`, `y`, `a`, `b`, +/// etc., and whose param types must implement [ParamRange](`v2::ParamRange`). At the moment +/// the only valid type that implements [ParamRange](`v2::ParamRange`) is +/// [Linear](`v2::Linear`). /// -/// Note that this function call is _not_ evaluated at compile time, but is instead copied textually -/// into each appropriate invocation site. +/// The valid syntax for defining a [Linear](`v2::Linear`)is `Linear` where `A`, and `B` +/// are valid integer literals (that fit in a `u32`), such that `B` >= `A`. /// -/// The third argument, `test`, must be the path to the runtime. The item to which this must refer -/// will generally take the form: +/// Note that the benchmark function definition does not actually expand as a function +/// definition, but rather is used to automatically create a number of impls and structs +/// required by the benchmarking engine. For this reason, the visibility of the function +/// definition as well as the return type are not used for any purpose and are discarded by the +/// expansion code. /// -/// ```rust,ignore -/// frame_support::construct_runtime!( -/// pub enum Test where ... -/// { ... } -/// ); -/// ``` +/// Also note that the `// setup code` and `// verification code` comments shown above are not +/// required and are included simply for demonstration purposes. /// -/// There is an optional fourth argument, with keyword syntax: `benchmarks_path = -/// path_to_benchmarks_invocation`. In the typical case in which this macro is in the same module as -/// the `benchmarks!` invocation, you don't need to supply this. However, if the -/// `impl_benchmark_test_suite!` invocation is in a different module than the `benchmarks!` -/// invocation, then you should provide the path to the module containing the `benchmarks!` -/// invocation: +/// ### `#[extrinsic_call]` and `#[block]` /// -/// ```rust,ignore -/// mod benches { -/// benchmarks!{ -/// ... -/// } -/// } +/// Within the benchmark function body, either an `#[extrinsic_call]` or a `#[block]` +/// annotation is required. These attributes should be attached to a block (shown in +/// `bench_name_2` above) or a one-line function call (shown in `bench_name_1` above, in `syn` +/// parlance this should be an `ExprCall`), respectively. /// -/// mod tests { -/// // because of macro syntax limitations, neither Pallet nor benches can be paths, but both have -/// // to be idents in the scope of `impl_benchmark_test_suite`. -/// use crate::{benches, Pallet}; +/// The `#[block]` syntax is broad and will benchmark any code contained within the block the +/// attribute is attached to. If `#[block]` is attached to something other than a block, a +/// compiler error will be emitted. /// -/// impl_benchmark_test_suite!(Pallet, new_test_ext(), Test, benchmarks_path = benches); +/// The one-line `#[extrinsic_call]` syntax must consist of a function call to an extrinsic, +/// where the first argument is the origin. If `#[extrinsic_call]` is attached to an item that +/// doesn't meet these requirements, a compiler error will be emitted. /// -/// // new_test_ext and the Test item are defined later in this module -/// } -/// ``` -/// -/// There is an optional fifth argument, with keyword syntax: `extra = true` or `extra = false`. -/// By default, this generates a test suite which iterates over all benchmarks, including those -/// marked with the `#[extra]` annotation. Setting `extra = false` excludes those. -/// -/// There is an optional sixth argument, with keyword syntax: `exec_name = custom_exec_name`. -/// By default, this macro uses `execute_with` for this parameter. This argument, if set, is subject -/// to these restrictions: -/// -/// - It must be the name of a method applied to the output of the `new_test_ext` argument. -/// - That method must have a signature capable of receiving a single argument of the form `impl -/// FnOnce()`. -// ## Notes (not for rustdoc) -// -// The biggest challenge for this macro is communicating the actual test functions to be run. We -// can't just build an array of function pointers to each test function and iterate over it, because -// the test functions are parameterized by the `Test` type. That's incompatible with -// monomorphization: if it were legal, then even if the compiler detected and monomorphized the -// functions into only the types of the callers, which implementation would the function pointer -// point to? There would need to be some kind of syntax for selecting the destination of the pointer -// according to a generic argument, and in general it would be a huge mess and not worth it. -// -// Instead, we're going to steal a trick from `fn run_benchmark`: generate a function which is -// itself parametrized by `Test`, which accepts a `&[u8]` parameter containing the name of the -// benchmark, and dispatches based on that to the appropriate real test implementation. Then, we can -// 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 )* )? - ); - } -} - -/// Validates the passed `pov_mode`s. -/// -/// Checks that: -/// - a top-level `ignored` is exclusive -/// - all modes are valid -#[macro_export] -macro_rules! validate_pov_mode { - () => {}; - ( $_bench:ident: ; ) => { }; - ( $_bench:ident: $_car:path = Ignored ; ) => { }; - ( $bench:ident: $_car:path = Ignored $( $storage:path = $_pov_mode:ident )+; ) => { - compile_error!( - concat!(concat!("`pov_mode = Ignored` is exclusive. Please remove the attribute from keys: ", $( stringify!($storage) )+), " on benchmark '", stringify!($bench), "'")); - }; - ( $bench:ident: $car:path = Measured $( $storage:path = $pov_mode:ident )*; ) => { - $crate::validate_pov_mode!( - $bench: $( $storage = $pov_mode )*; - ); - }; - ( $bench:ident: $car:path = MaxEncodedLen $( $storage:path = $pov_mode:ident )*; ) => { - $crate::validate_pov_mode!( - $bench: $( $storage = $pov_mode )*; - ); - }; - ( $bench:ident: $key:path = $unknown:ident $( $_storage:path = $_pov_mode:ident )*; ) => { - compile_error!( - concat!("Unknown pov_mode '", stringify!($unknown) ,"' for benchmark '", stringify!($bench), "' on key '", stringify!($key), "'. Must be one of: Ignored, Measured, MaxEncodedLen") - ); - }; -} - -// 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_test_function!( - @cases: - ( $( $names )* ) - ( $( $names_extra )* ) - ( $( $names_skip_meta )* ) - @selected: - $bench_module, - $new_test_ext, - $test, - benchmarks_path = super, - extra = true, - exec_name = execute_with, - @user: - $( $( $rest )* )? - ); - }; - // 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, - $test:path, - benchmarks_path = $old:ident, - extra = $extra:expr, - exec_name = $exec_name:ident, - @user: - benchmarks_path = $benchmarks_path:ident - $(, $( $rest:tt )* )? - ) => { - $crate::impl_test_function!( - @cases: - ( $( $names )* ) - ( $( $names_extra )* ) - ( $( $names_skip_meta )* ) - @selected: - $bench_module, - $new_test_ext, - $test, - benchmarks_path = $benchmarks_path, - extra = $extra, - exec_name = $exec_name, - @user: - $( $( $rest )* )? - ); - }; - // pick off the extra keyword argument - ( - @cases: - ( $( $names:tt )* ) - ( $( $names_extra:tt )* ) - ( $( $names_skip_meta:tt )* ) - @selected: - $bench_module:ident, - $new_test_ext:expr, - $test:path, - benchmarks_path = $benchmarks_path:ident, - extra = $old:expr, - exec_name = $exec_name:ident, - @user: - extra = $extra:expr - $(, $( $rest:tt )* )? - ) => { - $crate::impl_test_function!( - @cases: - ( $( $names )* ) - ( $( $names_extra )* ) - ( $( $names_skip_meta )* ) - @selected: - $bench_module, - $new_test_ext, - $test, - benchmarks_path = $benchmarks_path, - extra = $extra, - exec_name = $exec_name, - @user: - $( $( $rest )* )? - ); - }; - // 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, - $test:path, - benchmarks_path = $benchmarks_path:ident, - extra = $extra:expr, - exec_name = $old:ident, - @user: - exec_name = $exec_name:ident - $(, $( $rest:tt )* )? - ) => { - $crate::impl_test_function!( - @cases: - ( $( $names )* ) - ( $( $names_extra )* ) - ( $( $names_skip_meta )* ) - @selected: - $bench_module, - $new_test_ext, - $test, - benchmarks_path = $benchmarks_path, - extra = $extra, - exec_name = $exec_name, - @user: - $( $( $rest )* )? - ); - }; - // 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, - $test:path, - benchmarks_path = $path_to_benchmarks_invocation:ident, - extra = $extra:expr, - exec_name = $exec_name:ident, - @user: - $(,)? - ) => { - #[cfg(test)] - mod benchmark_tests { - use super::$bench_module; - - #[test] - fn test_benchmarks() { - $new_test_ext.$exec_name(|| { - use $crate::Benchmarking; - - let mut anything_failed = false; - println!("failing benchmark tests:"); - for benchmark_metadata in $bench_module::<$test>::benchmarks($extra) { - let benchmark_name = &benchmark_metadata.name; - match std::panic::catch_unwind(|| { - $bench_module::<$test>::test_bench_by_name(benchmark_name) - }) { - Err(err) => { - println!( - "{}: {:?}", - $crate::str::from_utf8(benchmark_name) - .expect("benchmark name is always a valid string!"), - err, - ); - anything_failed = true; - }, - Ok(Err(err)) => { - match err { - $crate::BenchmarkError::Stop(err) => { - println!( - "{}: {:?}", - $crate::str::from_utf8(benchmark_name) - .expect("benchmark name is always a valid string!"), - err, - ); - anything_failed = true; - }, - $crate::BenchmarkError::Override(_) => { - // This is still considered a success condition. - $crate::log::error!( - "WARNING: benchmark error overrided - {}", - $crate::str::from_utf8(benchmark_name) - .expect("benchmark name is always a valid string!"), - ); - }, - $crate::BenchmarkError::Skip => { - // This is considered a success condition. - $crate::log::error!( - "WARNING: benchmark error skipped - {}", - $crate::str::from_utf8(benchmark_name) - .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(())) => (), - } - } - assert!(!anything_failed); - }); - } - } - }; -} - -/// show error message and debugging info for the case of an error happening -/// during a benchmark -pub fn show_benchmark_debug_info( - instance_string: &[u8], - benchmark: &[u8], - components: &[(BenchmarkParameter, u32)], - verify: &bool, - error_message: &str, -) -> sp_runtime::RuntimeString { - sp_runtime::format_runtime_string!( - "\n* Pallet: {}\n\ - * Benchmark: {}\n\ - * Components: {:?}\n\ - * Verify: {:?}\n\ - * Error message: {}", - sp_std::str::from_utf8(instance_string) - .expect("it's all just strings ran through the wasm interface. qed"), - sp_std::str::from_utf8(benchmark) - .expect("it's all just strings ran through the wasm interface. qed"), - components, - verify, - error_message, - ) -} - -/// This macro adds pallet benchmarks to a `Vec` object. -/// -/// First create an object that holds in the input parameters for the benchmark: +/// As a short-hand, you may substitute the name of the extrinsic call with `_`, such as the +/// following: /// /// ```ignore -/// let params = (&config, &whitelist); +/// #[extrinsic_call] +/// _(RawOrigin::Signed(whitelisted_caller()), 0u32.into(), 0); /// ``` /// -/// The `whitelist` is a parameter you pass to control the DB read/write tracking. -/// We use a vector of [TrackedStorageKey](./struct.TrackedStorageKey.html), which is a simple -/// struct used to set if a key has been read or written to. +/// The underscore will be substituted with the name of the benchmark (i.e. the name of the +/// function in the benchmark function definition). /// -/// For values that should be skipped entirely, we can just pass `key.into()`. For example: +/// Regardless of whether `#[extrinsic_call]` or `#[block]` is used, this attribute also serves +/// the purpose of designating the boundary between the setup code portion of the benchmark +/// (everything before the `#[extrinsic_call]` or `#[block]` attribute) and the verification +/// stage (everything after the item that the `#[extrinsic_call]` or `#[block]` attribute is +/// attached to). The setup code section should contain any code that needs to execute before +/// the measured portion of the benchmark executes. The verification section is where you can +/// perform assertions to verify that the extrinsic call (or whatever is happening in your +/// block, if you used the `#[block]` syntax) executed successfully. /// -/// ``` -/// use frame_benchmarking::TrackedStorageKey; -/// let whitelist: Vec = vec![ -/// // Block Number -/// array_bytes::hex_into_unchecked("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac"), -/// // Total Issuance -/// array_bytes::hex_into_unchecked("c2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80"), -/// // Execution Phase -/// array_bytes::hex_into_unchecked("26aa394eea5630e07c48ae0c9558cef7ff553b5a9862a516939d82b3d3d8661a"), -/// // Event Count -/// array_bytes::hex_into_unchecked("26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850"), -/// ]; -/// ``` +/// Note that neither `#[extrinsic_call]` nor `#[block]` are real attribute macros and are +/// instead consumed by the outer macro pattern as part of the enclosing benchmark function +/// definition. This is why we are able to use `#[extrinsic_call]` and `#[block]` within a +/// function definition even though this behavior has not been stabilized +/// yet—`#[extrinsic_call]` and `#[block]` are parsed and consumed as part of the benchmark +/// definition parsing code, so they never expand as their own attribute macros. /// -/// Then define a mutable local variable to hold your `BenchmarkBatch` object: +/// ### Optional Attributes /// -/// ```ignore -/// let mut batches = Vec::::new(); -/// ```` +/// The keywords `extra` and `skip_meta` can be provided as optional arguments to the +/// `#[benchmark]` attribute, i.e. `#[benchmark(extra, skip_meta)]`. Including either of these +/// will enable the `extra` or `skip_meta` option, respectively. These options enable the same +/// behavior they did in the old benchmarking syntax in `frame_benchmarking`, namely: /// -/// Then add the pallets you want to benchmark to this object, using their crate name and generated -/// module struct: +/// #### `extra` /// -/// ```ignore -/// add_benchmark!(params, batches, pallet_balances, Balances); -/// add_benchmark!(params, batches, pallet_session, SessionBench::); -/// add_benchmark!(params, batches, frame_system, SystemBench::); -/// ... -/// ``` +/// Specifies that this benchmark should not normally run. To run benchmarks marked with +/// `extra`, you will need to invoke the `frame-benchmarking-cli` with `--extra`. /// -/// At the end of `dispatch_benchmark`, you should return this batches object. +/// #### `skip_meta` /// -/// In the case where you have multiple instances of a pallet that you need to separately benchmark, -/// the name of your module struct will be used as a suffix to your outputted weight file. For -/// example: +/// Specifies that the benchmarking framework should not analyze the storage keys that +/// benchmarked code read or wrote. This useful to suppress the prints in the form of unknown +/// 0x… in case a storage key that does not have metadata. Note that this skips the analysis +/// of all accesses, not just ones without metadata. /// -/// ```ignore -/// add_benchmark!(params, batches, pallet_balances, Balances); // pallet_balances.rs -/// add_benchmark!(params, batches, pallet_collective, Council); // pallet_collective_council.rs -/// add_benchmark!(params, batches, pallet_collective, TechnicalCommittee); // pallet_collective_technical_committee.rs -/// ``` +/// ## Where Clause /// -/// You can manipulate this suffixed string by using a type alias if needed. For example: +/// Some pallets require a where clause specifying constraints on their generics to make +/// writing benchmarks feasible. To accomodate this situation, you can provide such a where +/// clause as the (only) argument to the `#[benchmarks]` or `#[instance_benchmarks]` attribute +/// macros. Below is an example of this taken from the `message-queue` pallet. /// /// ```ignore -/// type Council2 = TechnicalCommittee; -/// add_benchmark!(params, batches, pallet_collective, Council2); // pallet_collective_council_2.rs +/// #[benchmarks( +/// where +/// <::MessageProcessor as ProcessMessage>::Origin: From + PartialEq, +/// ::Size: From, +/// )] +/// mod benchmarks { +/// use super::*; +/// // ... +/// } /// ``` -#[macro_export] -macro_rules! add_benchmark { - ( $params:ident, $batches:ident, $name:path, $( $location:tt )* ) => ( - let name_string = stringify!($name).as_bytes(); - let instance_string = stringify!( $( $location )* ).as_bytes(); - let (config, whitelist) = $params; - let $crate::BenchmarkConfig { - pallet, - benchmark, - selected_components, - verify, - internal_repeats, - } = config; - if &pallet[..] == &name_string[..] { - let benchmark_result = $( $location )*::run_benchmark( - &benchmark[..], - &selected_components[..], - whitelist, - *verify, - *internal_repeats, - ); - - let final_results = match benchmark_result { - Ok(results) => Some(results), - Err($crate::BenchmarkError::Override(mut result)) => { - // Insert override warning as the first storage key. - $crate::log::error!( - "WARNING: benchmark error overrided - {}", - $crate::str::from_utf8(benchmark) - .expect("benchmark name is always a valid string!") - ); - result.keys.insert(0, - (b"Benchmark Override".to_vec(), 0, 0, false) - ); - Some($crate::vec![result]) - }, - Err($crate::BenchmarkError::Stop(e)) => { - $crate::show_benchmark_debug_info( - instance_string, - benchmark, - selected_components, - verify, - e, - ); - return Err(e.into()); - }, - Err($crate::BenchmarkError::Skip) => { - $crate::log::error!( - "WARNING: benchmark error skipped - {}", - $crate::str::from_utf8(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() - }]) - } - }; - - if let Some(final_results) = final_results { - $batches.push($crate::BenchmarkBatch { - pallet: name_string.to_vec(), - instance: instance_string.to_vec(), - benchmark: benchmark.clone(), - results: final_results, - }); - } - } - ) -} - -/// Callback for `define_benchmarks` to call `add_benchmark`. -#[macro_export] -macro_rules! cb_add_benchmarks { - // anchor - ( $params:ident, $batches:ident, [ $name:path, $( $location:tt )* ] ) => { - $crate::add_benchmark!( $params, $batches, $name, $( $location )* ); - }; - // recursion tail - ( $params:ident, $batches:ident, [ $name:path, $( $location:tt )* ] $([ $names:path, $( $locations:tt )* ])+ ) => { - $crate::cb_add_benchmarks!( $params, $batches, [ $name, $( $location )* ] ); - $crate::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. -/// -/// To use this macro, first create a an object to store the list: /// -/// ```ignore -/// let mut list = Vec::::new(); -/// ``` +/// ## Benchmark Tests /// -/// Then pass this `list` to the macro, along with the `extra` boolean, the pallet crate, and -/// pallet struct: +/// Benchmark tests can be generated using the old syntax in `frame_benchmarking`, +/// including the `frame_benchmarking::impl_benchmark_test_suite` macro. /// +/// An example is shown below (taken from the `message-queue` pallet's `benchmarking` module): /// ```ignore -/// list_benchmark!(list, extra, pallet_balances, Balances); -/// list_benchmark!(list, extra, pallet_session, SessionBench::); -/// list_benchmark!(list, extra, frame_system, SystemBench::); +/// #[benchmarks] +/// mod benchmarks { +/// use super::*; +/// // ... +/// impl_benchmark_test_suite!( +/// MessageQueue, +/// crate::mock::new_test_ext::(), +/// crate::integration_test::Test +/// ); +/// } /// ``` -/// -/// This should match what exists with the `add_benchmark!` macro. -#[macro_export] -macro_rules! list_benchmark { - ( $list:ident, $extra:ident, $name:path, $( $location:tt )* ) => ( - let pallet_string = stringify!($name).as_bytes(); - let instance_string = stringify!( $( $location )* ).as_bytes(); - let benchmarks = $( $location )*::benchmarks($extra); - let pallet_benchmarks = BenchmarkList { - pallet: pallet_string.to_vec(), - instance: instance_string.to_vec(), - benchmarks: benchmarks.to_vec(), - }; - $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 )* ] ) => { - $crate::list_benchmark!( $list, $extra, $name, $( $location )* ); - }; - // recursion tail - ( $list:ident, $extra:ident, [ $name:path, $( $location:tt )* ] $([ $names:path, $( $locations:tt )* ])+ ) => { - $crate::cb_list_benchmarks!( $list, $extra, [ $name, $( $location )* ] ); - $crate::cb_list_benchmarks!( $list, $extra, $([ $names, $( $locations )* ])+ ); +pub mod v2 { + pub use super::*; + pub use frame_support_procedural::{ + benchmark, benchmarks, block, extrinsic_call, instance_benchmarks, + }; + + // Used in #[benchmark] implementation to ensure that benchmark function arguments + // implement [`ParamRange`]. + #[doc(hidden)] + pub use static_assertions::assert_impl_all; + + /// Used by the new benchmarking code to specify that a benchmarking variable is linear + /// over some specified range, i.e. `Linear<0, 1_000>` means that the corresponding variable + /// is allowed to range from `0` to `1000`, inclusive. + /// + /// See [`v2`] for more info. + pub struct Linear; + + /// Trait that must be implemented by all structs that can be used as parameter range types + /// in the new benchmarking code (i.e. `Linear<0, 1_000>`). Right now there is just + /// [`Linear`] but this could later be extended to support additional non-linear parameter + /// ranges. + /// + /// See [`v2`] for more info. + pub trait ParamRange { + /// Represents the (inclusive) starting number of this `ParamRange`. + fn start(&self) -> u32; + + /// Represents the (inclusive) ending number of this `ParamRange`. + fn end(&self) -> u32; } -} -/// 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 ) => { - $crate::cb_list_benchmarks!( $list, $extra, $([ $names, $( $locations )* ])+ ); - } + impl ParamRange for Linear { + fn start(&self) -> u32 { + A } - /// 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 ) => { - $crate::cb_add_benchmarks!( $params, $batches, $([ $names, $( $locations )* ])+ ); - } + fn end(&self) -> u32 { + B } } } diff --git a/frame/benchmarking/src/v1.rs b/frame/benchmarking/src/v1.rs new file mode 100644 index 0000000000000..089083f85b982 --- /dev/null +++ b/frame/benchmarking/src/v1.rs @@ -0,0 +1,2043 @@ +// This file is part of Substrate. + +// Copyright (C) 2020-2023 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Macros for benchmarking a FRAME runtime. + +pub use super::*; + +/// Whitelist the given account. +#[macro_export] +macro_rules! whitelist { + ($acc:ident) => { + frame_benchmarking::benchmarking::add_to_whitelist( + frame_system::Account::::hashed_key_for(&$acc).into(), + ); + }; +} + +/// Construct pallet benchmarks for weighing dispatchables. +/// +/// Works around the idea of complexity parameters, named by a single letter (which is usually +/// upper cased in complexity notation but is lower-cased for use in this macro). +/// +/// Complexity parameters ("parameters") have a range which is a `u32` pair. Every time a benchmark +/// is prepared and run, this parameter takes a concrete value within the range. There is an +/// associated instancing block, which is a single expression that is evaluated during +/// preparation. It may use `?` (`i.e. `return Err(...)`) to bail with a string error. Here's a +/// few examples: +/// +/// ```ignore +/// // These two are equivalent: +/// let x in 0 .. 10; +/// let x in 0 .. 10 => (); +/// // This one calls a setup function and might return an error (which would be terminal). +/// let y in 0 .. 10 => setup(y)?; +/// // This one uses a code block to do lots of stuff: +/// let z in 0 .. 10 => { +/// let a = z * z / 5; +/// let b = do_something(a)?; +/// combine_into(z, b); +/// } +/// ``` +/// +/// 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 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 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 +/// are left-inclusive right-exclusive. +/// +/// Each arm may also have a block of code which is run prior to any instancing and a block of code +/// which is run afterwards. All code blocks may draw upon the specific value of each parameter +/// at any time. Local variables are shared between the two pre- and post- code blocks, but do not +/// leak from the interior of any instancing expressions. +/// +/// Example: +/// ```ignore +/// benchmarks! { +/// where_clause { where T::A: From } // Optional line to give additional bound on `T`. +/// +/// // first dispatchable: foo; this is a user dispatchable and operates on a `u8` vector of +/// // size `l` +/// foo { +/// let caller = account::(b"caller", 0, benchmarks_seed); +/// let l in 1 .. MAX_LENGTH => initialize_l(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(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 +/// // pre-instancing block) within the code block. This is only allowed in the param instancers +/// // of arms. +/// baz1 { +/// let caller = account::(b"caller", 0, benchmarks_seed); +/// let c = 0 .. 10 => setup_c(&caller, c); +/// }: 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(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(RuntimeOrigin::Signed(caller), vec![0u8; l]) +/// +/// // this is benchmarking some code that is not a dispatchable. +/// populate_a_set { +/// let x in 0 .. 10_000; +/// let mut m = Vec::::new(); +/// for i in 0..x { +/// m.insert(i); +/// } +/// }: { m.into_iter().collect::() } +/// } +/// ``` +/// +/// Test functions are automatically generated for each benchmark and are accessible to you when you +/// run `cargo test`. All tests are named `test_benchmark_`, implemented on the +/// Pallet struct, and run them in a test externalities environment. The test function runs your +/// 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: +/// +/// ```ignore +/// sort_vector { +/// let x in 1 .. 10000; +/// let mut m = Vec::::new(); +/// for i in (0..x).rev() { +/// m.push(i); +/// } +/// }: { +/// m.sort(); +/// } verify { +/// ensure!(m[0] == 0, "You forgot to sort!") +/// } +/// ``` +/// +/// These `verify` blocks will not affect your benchmark results! +/// +/// You can construct benchmark by using the `impl_benchmark_test_suite` macro or +/// by manually implementing them like so: +/// +/// ```ignore +/// #[test] +/// fn test_benchmarks() { +/// new_test_ext().execute_with(|| { +/// assert_ok!(Pallet::::test_benchmark_dummy()); +/// assert_err!(Pallet::::test_benchmark_other_name(), "Bad origin"); +/// assert_ok!(Pallet::::test_benchmark_sort_vector()); +/// assert_err!(Pallet::::test_benchmark_broken_benchmark(), "You forgot to sort!"); +/// }); +/// } +/// ``` +#[macro_export] +macro_rules! benchmarks { + ( + $( $rest:tt )* + ) => { + $crate::benchmarks_iter!( + { } + { } + { } + ( ) + ( ) + ( ) + ( ) + $( $rest )* + ); + } +} + +/// Same as [`benchmarks`] but for instantiable module. +/// +/// NOTE: For pallet declared with [`frame_support::pallet`], use [`benchmarks_instance_pallet`]. +#[macro_export] +macro_rules! benchmarks_instance { + ( + $( $rest:tt )* + ) => { + $crate::benchmarks_iter!( + { } + { I: Instance } + { } + ( ) + ( ) + ( ) + ( ) + $( $rest )* + ); + } +} + +/// Same as [`benchmarks`] but for instantiable pallet declared [`frame_support::pallet`]. +/// +/// NOTE: For pallet declared with `decl_module!`, use [`benchmarks_instance`]. +#[macro_export] +macro_rules! benchmarks_instance_pallet { + ( + $( $rest:tt )* + ) => { + $crate::benchmarks_iter!( + { } + { I: 'static } + { } + ( ) + ( ) + ( ) + ( ) + $( $rest )* + ); + } +} + +#[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 )* ) + ( $( $pov_name:ident: $( $storage:path = $pov_mode:ident )*; )* ) + 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 )* ) + ( $( $pov_name: $( $storage = $pov_mode )*; )* ) + $( $rest )* + } + }; + // - without a semicolon + ( + { } + { $( $instance:ident: $instance_bound:tt )? } + { $( $where_clause:tt )* } + ( $( $names:tt )* ) + ( $( $names_extra:tt )* ) + ( $( $names_skip_meta:tt )* ) + ( $( $pov_name:ident: $( $storage:path = $pov_mode:ident )*; )* ) + 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 )* ) + ( $( $pov_name: $( $storage = $pov_mode )*; )* ) + $( $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 )* ) + ( $( $names_extra:tt )* ) + ( $( $names_skip_meta:tt )* ) + ( $( $pov_name:ident: $( $storage:path = $pov_mode:ident )*; )* ) + where_clause { where $( $where_bound:tt )* } + $( $rest:tt )* + ) => { + $crate::benchmarks_iter! { + { $($bench_module, $new_test_ext, $test $(, $( $args )* )?)? } + { $( $instance: $instance_bound)? } + { $( $where_bound )* } + ( $( $names )* ) + ( $( $names_extra )* ) + ( $( $names_skip_meta )* ) + ( $( $pov_name: $( $storage = $pov_mode )*; )* ) + $( $rest )* + } + }; + // 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 )* ) + ( $( $names_extra:tt )* ) + ( $( $names_skip_meta:tt )* ) + ( $( $pov_name:ident: $( $storage:path = $pov_mode:ident )*; )* ) + #[skip_meta] + $( #[ $($attributes:tt)+ ] )* + $name:ident + $( $rest:tt )* + ) => { + $crate::benchmarks_iter! { + { $($bench_module, $new_test_ext, $test $(, $( $args )* )?)? } + { $( $instance: $instance_bound )? } + { $( $where_clause )* } + ( $( $names )* ) + ( $( $names_extra )* ) + ( $( $names_skip_meta )* $name ) + ( $( $pov_name: $( $storage = $pov_mode )*; )* ) + $( #[ $( $attributes )+ ] )* + $name + $( $rest )* + } + }; + // 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 )* ) + ( $( $names_extra:tt )* ) + ( $( $names_skip_meta:tt )* ) + ( $( $pov_name:ident: $( $storage:path = $pov_mode:ident )*; )* ) + #[extra] + $( #[ $($attributes:tt)+ ] )* + $name:ident + $( $rest:tt )* + ) => { + $crate::benchmarks_iter! { + { $($bench_module, $new_test_ext, $test $(, $( $args )* )?)? } + { $( $instance: $instance_bound )? } + { $( $where_clause )* } + ( $( $names )* ) + ( $( $names_extra )* $name ) + ( $( $names_skip_meta )* ) + ( $( $pov_name: $( $storage = $pov_mode )*; )* ) + $( #[ $( $attributes )+ ] )* + $name + $( $rest )* + } + }; + // detect and extract `#[pov_mode = Mode { Pallet::Storage: Mode ... }]` tag: + ( + { $($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 )* ) + ( $( $old_pov_name:ident: $( $old_storage:path = $old_pov_mode:ident )*; )* ) + #[pov_mode = $mode:ident $( { $( $storage:path: $pov_mode:ident )* } )?] + $( #[ $($attributes:tt)+ ] )* + $name:ident + $( $rest:tt )* + ) => { + $crate::benchmarks_iter! { + { $($bench_module, $new_test_ext, $test $(, $( $args )* )?)? } + { $( $instance: $instance_bound )? } + { $( $where_clause )* } + ( $( $names )* ) + ( $( $names_extra )* ) + ( $( $names_skip_meta )* ) + ( $name: ALL = $mode $($( $storage = $pov_mode )*)?; $( $old_pov_name: $( $old_storage = $old_pov_mode )*; )* ) + $( #[ $( $attributes )+ ] )* + $name + $( $rest )* + } + }; + // 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 )* + ( $( $names_extra:tt )* ) + ( $( $names_skip_meta:tt )* ) + ( $( $pov_name:ident: $( $storage:path = $pov_mode:ident )*; )* ) + $name:ident { $( $code:tt )* }: _ $(< $origin_type:ty>)? ( $origin:expr $( , $arg:expr )* ) + verify $postcode:block + $( $rest:tt )* + ) => { + $crate::benchmarks_iter! { + { $($bench_module, $new_test_ext, $test $(, $( $args )* )?)? } + { $( $instance: $instance_bound )? } + { $( $where_clause )* } + ( $( $names )* ) + ( $( $names_extra )* ) + ( $( $names_skip_meta )* ) + ( $( $pov_name: $( $storage = $pov_mode )*; )* ) + $name { $( $code )* }: $name $(< $origin_type >)? ( $origin $( , $arg )* ) + verify $postcode + $( $rest )* + } + }; + // mutation arm: + ( + { $($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 )* ) + ( $( $pov_name:ident: $( $storage:path = $pov_mode:ident )*; )* ) + $name:ident { $( $code:tt )* }: $dispatch:ident $(<$origin_type:ty>)? ( $origin:expr $( , $arg:expr )* ) + verify $postcode:block + $( $rest:tt )* + ) => { + $crate::paste::paste! { + $crate::benchmarks_iter! { + { $($bench_module, $new_test_ext, $test $(, $( $args )* )?)? } + { $( $instance: $instance_bound )? } + { $( $where_clause )* } + ( $( $names )* ) + ( $( $names_extra )* ) + ( $( $names_skip_meta )* ) + ( $( $pov_name: $( $storage = $pov_mode )*; )* ) + $name { + $( $code )* + let __call = Call::< + T + $( , $instance )? + >:: [< new_call_variant_ $dispatch >] ( + $($arg),* + ); + let __benchmarked_call_encoded = $crate::frame_support::codec::Encode::encode( + &__call + ); + }: { + let __call_decoded = < + Call + as $crate::frame_support::codec::Decode + >::decode(&mut &__benchmarked_call_encoded[..]) + .expect("call is encoded above, encoding must be correct"); + let __origin = $crate::to_origin!($origin $(, $origin_type)?); + as $crate::frame_support::traits::UnfilteredDispatchable + >::dispatch_bypass_filter(__call_decoded, __origin)?; + } + verify $postcode + $( $rest )* + } + } + }; + // iteration arm: + ( + { $($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 )* ) + ( $( $pov_name:ident: $( $storage:path = $pov_mode:ident )*; )* ) + $name:ident { $( $code:tt )* }: $eval:block + verify $postcode:block + $( $rest:tt )* + ) => { + $crate::benchmark_backend! { + { $( $instance: $instance_bound )? } + $name + { $( $where_clause )* } + { } + { $eval } + { $( $code )* } + $postcode + } + + #[cfg(test)] + $crate::impl_benchmark_test!( + { $( $where_clause )* } + { $( $instance: $instance_bound )? } + $name + ); + + $crate::benchmarks_iter!( + { $($bench_module, $new_test_ext, $test $(, $( $args )* )?)? } + { $( $instance: $instance_bound )? } + { $( $where_clause )* } + ( $( $names )* { $( $instance )? } $name ) + ( $( $names_extra )* ) + ( $( $names_skip_meta )* ) + ( $( $pov_name: $( $storage = $pov_mode )*; )* ) + $( $rest )* + ); + }; + // 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 )* ) + ( $( $pov_name:ident: $( $storage:path = $pov_mode:ident )*; )* ) + ) => { + $crate::selected_benchmark!( + { $( $where_clause)* } + { $( $instance: $instance_bound )? } + $( $names )* + ); + $crate::impl_benchmark!( + { $( $where_clause )* } + { $( $instance: $instance_bound )? } + ( $( $names )* ) + ( $( $names_extra ),* ) + ( $( $names_skip_meta ),* ) + ( $( $pov_name: $( $storage = $pov_mode )*; )* ) + ); + $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 )* ) + ( $( $names_extra:tt )* ) + ( $( $names_skip_meta:tt )* ) + ( $( $pov_name:ident: $( $storage:path = $pov_mode:ident )*; )* ) + ) => { + $crate::selected_benchmark!( + { $( $where_clause)* } + { $( $instance: $instance_bound )? } + $( $names )* + ); + $crate::impl_benchmark!( + { $( $where_clause )* } + { $( $instance: $instance_bound )? } + ( $( $names )* ) + ( $( $names_extra ),* ) + ( $( $names_skip_meta ),* ) + ( $( $pov_name: $( $storage = $pov_mode )*; )* ) + ); + }; + // 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 )* ) + ( $( $names_extra:tt )* ) + ( $( $names_skip_meta:tt )* ) + ( $( $pov_name:ident: $( $storage:path = $pov_mode:ident )*; )* ) + $name:ident { $( $code:tt )* }: _ $(<$origin_type:ty>)? ( $origin:expr $( , $arg:expr )* ) + $( $rest:tt )* + ) => { + $crate::benchmarks_iter! { + { $($bench_module, $new_test_ext, $test $(, $( $args )* )?)? } + { $( $instance: $instance_bound )? } + { $( $where_clause )* } + ( $( $names )* ) + ( $( $names_extra )* ) + ( $( $names_skip_meta )* ) + ( $( $pov_name: $( $storage = $pov_mode )*; )* ) + $name { $( $code )* }: _ $(<$origin_type>)? ( $origin $( , $arg )* ) + verify { } + $( $rest )* + } + }; + // 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 )* ) + ( $( $names_extra:tt )* ) + ( $( $names_skip_meta:tt )* ) + ( $( $pov_name:ident: $( $storage:path = $pov_mode:ident )*; )* ) + $name:ident { $( $code:tt )* }: $dispatch:ident $(<$origin_type:ty>)? ( $origin:expr $( , $arg:expr )* ) + $( $rest:tt )* + ) => { + $crate::benchmarks_iter! { + { $($bench_module, $new_test_ext, $test $(, $( $args )* )?)? } + { $( $instance: $instance_bound )? } + { $( $where_clause )* } + ( $( $names )* ) + ( $( $names_extra )* ) + ( $( $names_skip_meta )* ) + ( $( $pov_name: $( $storage = $pov_mode )*; )* ) + $name { $( $code )* }: $dispatch $(<$origin_type>)? ( $origin $( , $arg )* ) + verify { } + $( $rest )* + } + }; + // 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 )* ) + ( $( $names_extra:tt )* ) + ( $( $names_skip_meta:tt )* ) + ( $( $pov_name:ident: $( $storage:path = $pov_mode:ident )*; )* ) + $name:ident { $( $code:tt )* }: $(<$origin_type:ty>)? $eval:block + $( $rest:tt )* + ) => { + $crate::benchmarks_iter!( + { $($bench_module, $new_test_ext, $test $(, $( $args )* )?)? } + { $( $instance: $instance_bound )? } + { $( $where_clause )* } + ( $( $names )* ) + ( $( $names_extra )* ) + ( $( $names_skip_meta )* ) + ( $( $pov_name: $( $storage = $pov_mode )*; )* ) + $name { $( $code )* }: $(<$origin_type>)? $eval + verify { } + $( $rest )* + ); + }; +} + +#[macro_export] +#[doc(hidden)] +macro_rules! to_origin { + ($origin:expr) => { + $origin.into() + }; + ($origin:expr, $origin_type:ty) => { + <::RuntimeOrigin as From<$origin_type>>::from($origin) + }; +} + +#[macro_export] +#[doc(hidden)] +macro_rules! benchmark_backend { + // parsing arms + ( + { $( $instance:ident: $instance_bound:tt )? } + $name:ident + { $( $where_clause:tt )* } + { $( PRE { $( $pre_parsed:tt )* } )* } + { $eval:block } + { + let $pre_id:tt : $pre_ty:ty = $pre_ex:expr; + $( $rest:tt )* + } + $postcode:block + ) => { + $crate::benchmark_backend! { + { $( $instance: $instance_bound )? } + $name + { $( $where_clause )* } + { + $( PRE { $( $pre_parsed )* } )* + PRE { $pre_id , $pre_ty , $pre_ex } + } + { $eval } + { $( $rest )* } + $postcode + } + }; + ( + { $( $instance:ident: $instance_bound:tt )? } + $name:ident + { $( $where_clause:tt )* } + { $( $parsed:tt )* } + { $eval:block } + { + let $param:ident in ( $param_from:expr ) .. $param_to:expr => $param_instancer:expr; + $( $rest:tt )* + } + $postcode:block + ) => { + $crate::benchmark_backend! { + { $( $instance: $instance_bound )? } + $name + { $( $where_clause )* } + { + $( $parsed )* + PARAM { $param , $param_from , $param_to , $param_instancer } + } + { $eval } + { $( $rest )* } + $postcode + } + }; + // mutation arm to look after a single tt for param_from. + ( + { $( $instance:ident: $instance_bound:tt )? } + $name:ident + { $( $where_clause:tt )* } + { $( $parsed:tt )* } + { $eval:block } + { + let $param:ident in $param_from:tt .. $param_to:expr => $param_instancer:expr ; + $( $rest:tt )* + } + $postcode:block + ) => { + $crate::benchmark_backend! { + { $( $instance: $instance_bound )? } + $name + { $( $where_clause )* } + { $( $parsed )* } + { $eval } + { + let $param in ( $param_from ) .. $param_to => $param_instancer; + $( $rest )* + } + $postcode + } + }; + // mutation arm to look after the default tail of `=> ()` + ( + { $( $instance:ident: $instance_bound:tt )? } + $name:ident + { $( $where_clause:tt )* } + { $( $parsed:tt )* } + { $eval:block } + { + let $param:ident in $param_from:tt .. $param_to:expr; + $( $rest:tt )* + } + $postcode:block + ) => { + $crate::benchmark_backend! { + { $( $instance: $instance_bound )? } + $name + { $( $where_clause )* } + { $( $parsed )* } + { $eval } + { + let $param in $param_from .. $param_to => (); + $( $rest )* + } + $postcode + } + }; + // mutation arm to look after `let _ =` + ( + { $( $instance:ident: $instance_bound:tt )? } + $name:ident + { $( $where_clause:tt )* } + { $( $parsed:tt )* } + { $eval:block } + { + let $pre_id:tt = $pre_ex:expr; + $( $rest:tt )* + } + $postcode:block + ) => { + $crate::benchmark_backend! { + { $( $instance: $instance_bound )? } + $name + { $( $where_clause )* } + { $( $parsed )* } + { $eval } + { + let $pre_id : _ = $pre_ex; + $( $rest )* + } + $postcode + } + }; + // actioning arm + ( + { $( $instance:ident: $instance_bound:tt )? } + $name:ident + { $( $where_clause:tt )* } + { + $( PRE { $pre_id:tt , $pre_ty:ty , $pre_ex:expr } )* + $( PARAM { $param:ident , $param_from:expr , $param_to:expr , $param_instancer:expr } )* + } + { $eval:block } + { $( $post:tt )* } + $postcode:block + ) => { + #[allow(non_camel_case_types)] + struct $name; + #[allow(unused_variables)] + impl, $instance: $instance_bound )? > + $crate::BenchmarkingSetup for $name + where $( $where_clause )* + { + fn components(&self) -> $crate::Vec<($crate::BenchmarkParameter, u32, u32)> { + $crate::vec! [ + $( + ($crate::BenchmarkParameter::$param, $param_from, $param_to) + ),* + ] + } + + fn instance( + &self, + components: &[($crate::BenchmarkParameter, u32)], + verify: bool + ) -> Result<$crate::Box Result<(), $crate::BenchmarkError>>, $crate::BenchmarkError> { + $( + // Prepare instance + let $param = components.iter() + .find(|&c| c.0 == $crate::BenchmarkParameter::$param) + .ok_or("Could not find component in benchmark preparation.")? + .1; + )* + $( + let $pre_id : $pre_ty = $pre_ex; + )* + $( $param_instancer ; )* + $( $post )* + + Ok($crate::Box::new(move || -> Result<(), $crate::BenchmarkError> { + $eval; + if verify { + $postcode; + } + Ok(()) + })) + } + } + }; +} + +// 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), + ); + }, + $crate::BenchmarkError::Weightless => { + // This is considered a success condition. + $crate::log::error!( + "WARNING: benchmark weightless 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`]. +// +// ```nocompile +// +// struct Transfer; +// impl BenchmarkingSetup for Transfer { ... } +// +// struct SetBalance; +// impl BenchmarkingSetup for SetBalance { ... } +// +// selected_benchmark!({} Transfer {} SetBalance); +// ``` +#[macro_export] +#[doc(hidden)] +macro_rules! selected_benchmark { + ( + { $( $where_clause:tt )* } + { $( $instance:ident: $instance_bound:tt )? } + $( { $( $bench_inst:ident )? } $bench:ident )* + ) => { + // The list of available benchmarks for this pallet. + #[allow(non_camel_case_types)] + enum SelectedBenchmark { + $( $bench, )* + } + + // Allow us to select a benchmark from the list of available benchmarks. + impl, $instance: $instance_bound )? > + $crate::BenchmarkingSetup for SelectedBenchmark + where $( $where_clause )* + { + fn components(&self) -> $crate::Vec<($crate::BenchmarkParameter, u32, u32)> { + match self { + $( + Self::$bench => < + $bench as $crate::BenchmarkingSetup + >::components(&$bench), + )* + } + } + + fn instance( + &self, + components: &[($crate::BenchmarkParameter, u32)], + verify: bool + ) -> Result<$crate::Box Result<(), $crate::BenchmarkError>>, $crate::BenchmarkError> { + match self { + $( + Self::$bench => < + $bench as $crate::BenchmarkingSetup + >::instance(&$bench, components, verify), + )* + } + } + } + }; +} + +#[macro_export] +#[doc(hidden)] +macro_rules! impl_benchmark { + ( + { $( $where_clause:tt )* } + { $( $instance:ident: $instance_bound:tt )? } + ( $( { $( $name_inst:ident )? } $name:ident )* ) + ( $( $name_extra:ident ),* ) + ( $( $name_skip_meta:ident ),* ) + ( $( $pov_name:ident: $( $storage:path = $pov_mode: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 )* + { + fn benchmarks(extra: bool) -> $crate::Vec<$crate::BenchmarkMetadata> { + $($crate::validate_pov_mode!( + $pov_name: $( $storage = $pov_mode )*; + );)* + let mut all_names = $crate::vec![ $( stringify!($name).as_ref() ),* ]; + if !extra { + let extra = [ $( stringify!($name_extra).as_ref() ),* ]; + all_names.retain(|x| !extra.contains(x)); + } + let pov_modes: $crate::Vec<($crate::Vec, $crate::Vec<($crate::Vec, $crate::Vec)>)> = $crate::vec![ + $( + (stringify!($pov_name).as_bytes().to_vec(), + $crate::vec![ + $( ( stringify!($storage).as_bytes().to_vec(), + stringify!($pov_mode).as_bytes().to_vec() ), )* + ]), + )* + ]; + all_names.into_iter().map(|benchmark| { + let selected_benchmark = match benchmark { + $( stringify!($name) => SelectedBenchmark::$name, )* + _ => panic!("all benchmarks should be selectable"), + }; + let name = benchmark.as_bytes().to_vec(); + let components = < + SelectedBenchmark as $crate::BenchmarkingSetup + >::components(&selected_benchmark); + + $crate::BenchmarkMetadata { + name: name.clone(), + components, + pov_modes: pov_modes.iter().find(|p| p.0 == name).map(|p| p.1.clone()).unwrap_or_default(), + } + }).collect::<$crate::Vec<_>>() + } + + fn run_benchmark( + extrinsic: &[u8], + c: &[($crate::BenchmarkParameter, u32)], + whitelist: &[$crate::TrackedStorageKey], + verify: bool, + internal_repeats: u32, + ) -> Result<$crate::Vec<$crate::BenchmarkResult>, $crate::BenchmarkError> { + // Map the input to the selected benchmark. + let extrinsic = $crate::str::from_utf8(extrinsic) + .map_err(|_| "`extrinsic` is not a valid utf8 string!")?; + let selected_benchmark = match extrinsic { + $( stringify!($name) => SelectedBenchmark::$name, )* + _ => return Err("Could not find extrinsic.".into()), + }; + + // Add whitelist to DB including whitelisted caller + let mut whitelist = whitelist.to_vec(); + let whitelisted_caller_key = + as $crate::frame_support::storage::StorageMap<_,_>>::hashed_key_for( + $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); + // Whitelist the `:extrinsic_index`. + let extrinsic_index = $crate::TrackedStorageKey::new( + $crate::well_known_keys::EXTRINSIC_INDEX.into() + ); + whitelist.push(extrinsic_index); + + $crate::benchmarking::set_whitelist(whitelist.clone()); + + let mut results: $crate::Vec<$crate::BenchmarkResult> = $crate::Vec::new(); + + // 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 = < + SelectedBenchmark as $crate::BenchmarkingSetup + >::instance(&selected_benchmark, c, verify)?; + + // Set the block number to at least 1 so events are deposited. + if $crate::Zero::is_zero(&frame_system::Pallet::::block_number()) { + frame_system::Pallet::::set_block_number(1u32.into()); + } + + // Commit the externalities to the database, flushing the DB cache. + // This will enable worst case scenario for reading from the database. + $crate::benchmarking::commit_db(); + + // Access all whitelisted keys to get them into the proof recorder since the + // recorder does now have a whitelist. + for key in &whitelist { + $crate::frame_support::storage::unhashed::get_raw(&key.key); + } + + // Reset the read/write counter so we don't count operations in the setup process. + $crate::benchmarking::reset_read_write_count(); + + // Time the extrinsic logic. + $crate::log::trace!( + target: "benchmark", + "Start Benchmark: {} ({:?}) verify {}", + extrinsic, + c, + verify + ); + + let start_pov = $crate::benchmarking::proof_size(); + let start_extrinsic = $crate::benchmarking::current_time(); + + closure_to_benchmark()?; + + let finish_extrinsic = $crate::benchmarking::current_time(); + let end_pov = $crate::benchmarking::proof_size(); + + // Calculate the diff caused by the benchmark. + let elapsed_extrinsic = finish_extrinsic.saturating_sub(start_extrinsic); + let diff_pov = match (start_pov, end_pov) { + (Some(start), Some(end)) => end.saturating_sub(start), + _ => Default::default(), + }; + + // Commit the changes to get proper write count + $crate::benchmarking::commit_db(); + $crate::log::trace!( + target: "benchmark", + "End Benchmark: {} ns", elapsed_extrinsic + ); + let read_write_count = $crate::benchmarking::read_write_count(); + $crate::log::trace!( + target: "benchmark", + "Read/Write Count {:?}", read_write_count + ); + $crate::log::trace!( + target: "benchmark", + "Proof sizes: before {:?} after {:?} diff {}", &start_pov, &end_pov, &diff_pov + ); + + // Time the storage root recalculation. + let start_storage_root = $crate::benchmarking::current_time(); + $crate::storage_root($crate::StateVersion::V1); + let finish_storage_root = $crate::benchmarking::current_time(); + let elapsed_storage_root = finish_storage_root - start_storage_root; + + let skip_meta = [ $( stringify!($name_skip_meta).as_ref() ),* ]; + let read_and_written_keys = if skip_meta.contains(&extrinsic) { + $crate::vec![(b"Skipped Metadata".to_vec(), 0, 0, false)] + } else { + $crate::benchmarking::get_read_and_written_keys() + }; + + results.push($crate::BenchmarkResult { + components: c.to_vec(), + extrinsic_time: elapsed_extrinsic, + storage_root_time: elapsed_storage_root, + reads: read_write_count.0, + repeat_reads: read_write_count.1, + writes: read_write_count.2, + repeat_writes: read_write_count.3, + proof_size: diff_pov, + keys: read_and_written_keys, + }); + } + + return Ok(results); + } + } + + #[cfg(test)] + impl, $instance: $instance_bound )? > + Pallet + where T: frame_system::Config, $( $where_clause )* + { + /// Test a particular benchmark by name. + /// + /// This isn't called `test_benchmark_by_name` just in case some end-user eventually + /// writes a benchmark, itself called `by_name`; the function would be shadowed in + /// that case. + /// + /// This is generally intended to be used by child test modules such as those created + /// by the `impl_benchmark_test_suite` macro. However, it is not an error if a pallet + /// author chooses not to implement benchmarks. + #[allow(unused)] + fn test_bench_by_name(name: &[u8]) -> Result<(), $crate::BenchmarkError> { + let name = $crate::str::from_utf8(name) + .map_err(|_| -> $crate::BenchmarkError { "`name` is not a valid utf8 string!".into() })?; + match name { + $( stringify!($name) => { + $crate::paste::paste! { Self::[< test_benchmark_ $name >]() } + } )* + _ => Err("Could not find test for requested benchmark.".into()), + } + } + } + }; +} + +// 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 { + ( + { $( $where_clause:tt )* } + { $( $instance:ident: $instance_bound:tt )? } + $name:ident + ) => { + $crate::paste::item! { + #[cfg(test)] + impl, $instance: $instance_bound )? > + Pallet + where T: frame_system::Config, $( $where_clause )* + { + #[allow(unused)] + fn [] () -> Result<(), $crate::BenchmarkError> { + let selected_benchmark = SelectedBenchmark::$name; + let components = < + SelectedBenchmark as $crate::BenchmarkingSetup + >::components(&selected_benchmark); + + 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 + >::instance(&selected_benchmark, &c, true)?; + + // Set the block number to at least 1 so events are deposited. + if $crate::Zero::is_zero(&frame_system::Pallet::::block_number()) { + frame_system::Pallet::::set_block_number(1u32.into()); + } + + // Run execution + verification + closure_to_verify() + }; + + if components.is_empty() { + execute_benchmark(Default::default())?; + } else { + 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) + } else { + (*n, *h) + } + ) + .collect(); + + execute_benchmark(c)?; + } + } + } + Ok(()) + } + } + } + }; +} + +/// This creates a test suite which runs the module's benchmarks. +/// +/// When called in `pallet_example_basic` as +/// +/// ```rust,ignore +/// impl_benchmark_test_suite!(Pallet, crate::tests::new_test_ext(), crate::tests::Test); +/// ``` +/// +/// It expands to the equivalent of: +/// +/// ```rust,ignore +/// #[cfg(test)] +/// mod tests { +/// use super::*; +/// use crate::tests::{new_test_ext, Test}; +/// use frame_support::assert_ok; +/// +/// #[test] +/// fn test_benchmarks() { +/// new_test_ext().execute_with(|| { +/// assert_ok!(test_benchmark_accumulate_dummy::()); +/// assert_ok!(test_benchmark_set_dummy::()); +/// assert_ok!(test_benchmark_sort_vector::()); +/// }); +/// } +/// } +/// ``` +/// +/// When called inside the `benchmarks` macro of the `pallet_example_basic` 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. +/// +/// The second argument, `new_test_ext`, must be a function call which returns either a +/// `sp_io::TestExternalities`, or some other type with a similar interface. +/// +/// Note that this function call is _not_ evaluated at compile time, but is instead copied textually +/// into each appropriate invocation site. +/// +/// The third argument, `test`, must be the path to the runtime. The item to which this must refer +/// will generally take the form: +/// +/// ```rust,ignore +/// frame_support::construct_runtime!( +/// pub enum Test where ... +/// { ... } +/// ); +/// ``` +/// +/// There is an optional fourth argument, with keyword syntax: `benchmarks_path = +/// path_to_benchmarks_invocation`. In the typical case in which this macro is in the same module as +/// the `benchmarks!` invocation, you don't need to supply this. However, if the +/// `impl_benchmark_test_suite!` invocation is in a different module than the `benchmarks!` +/// invocation, then you should provide the path to the module containing the `benchmarks!` +/// invocation: +/// +/// ```rust,ignore +/// mod benches { +/// benchmarks!{ +/// ... +/// } +/// } +/// +/// mod tests { +/// // because of macro syntax limitations, neither Pallet nor benches can be paths, but both have +/// // to be idents in the scope of `impl_benchmark_test_suite`. +/// use crate::{benches, Pallet}; +/// +/// impl_benchmark_test_suite!(Pallet, new_test_ext(), Test, benchmarks_path = benches); +/// +/// // new_test_ext and the Test item are defined later in this module +/// } +/// ``` +/// +/// There is an optional fifth argument, with keyword syntax: `extra = true` or `extra = false`. +/// By default, this generates a test suite which iterates over all benchmarks, including those +/// marked with the `#[extra]` annotation. Setting `extra = false` excludes those. +/// +/// There is an optional sixth argument, with keyword syntax: `exec_name = custom_exec_name`. +/// By default, this macro uses `execute_with` for this parameter. This argument, if set, is subject +/// to these restrictions: +/// +/// - It must be the name of a method applied to the output of the `new_test_ext` argument. +/// - That method must have a signature capable of receiving a single argument of the form `impl +/// FnOnce()`. +// ## Notes (not for rustdoc) +// +// The biggest challenge for this macro is communicating the actual test functions to be run. We +// can't just build an array of function pointers to each test function and iterate over it, because +// the test functions are parameterized by the `Test` type. That's incompatible with +// monomorphization: if it were legal, then even if the compiler detected and monomorphized the +// functions into only the types of the callers, which implementation would the function pointer +// point to? There would need to be some kind of syntax for selecting the destination of the pointer +// according to a generic argument, and in general it would be a huge mess and not worth it. +// +// Instead, we're going to steal a trick from `fn run_benchmark`: generate a function which is +// itself parametrized by `Test`, which accepts a `&[u8]` parameter containing the name of the +// benchmark, and dispatches based on that to the appropriate real test implementation. Then, we can +// 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 )* )? + ); + } +} + +/// Validates the passed `pov_mode`s. +/// +/// Checks that: +/// - a top-level `ignored` is exclusive +/// - all modes are valid +#[macro_export] +macro_rules! validate_pov_mode { + () => {}; + ( $_bench:ident: ; ) => { }; + ( $_bench:ident: $_car:path = Ignored ; ) => { }; + ( $bench:ident: $_car:path = Ignored $( $storage:path = $_pov_mode:ident )+; ) => { + compile_error!( + concat!(concat!("`pov_mode = Ignored` is exclusive. Please remove the attribute from keys: ", $( stringify!($storage) )+), " on benchmark '", stringify!($bench), "'")); + }; + ( $bench:ident: $car:path = Measured $( $storage:path = $pov_mode:ident )*; ) => { + $crate::validate_pov_mode!( + $bench: $( $storage = $pov_mode )*; + ); + }; + ( $bench:ident: $car:path = MaxEncodedLen $( $storage:path = $pov_mode:ident )*; ) => { + $crate::validate_pov_mode!( + $bench: $( $storage = $pov_mode )*; + ); + }; + ( $bench:ident: $key:path = $unknown:ident $( $_storage:path = $_pov_mode:ident )*; ) => { + compile_error!( + concat!("Unknown pov_mode '", stringify!($unknown) ,"' for benchmark '", stringify!($bench), "' on key '", stringify!($key), "'. Must be one of: Ignored, Measured, MaxEncodedLen") + ); + }; +} + +// 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_test_function!( + @cases: + ( $( $names )* ) + ( $( $names_extra )* ) + ( $( $names_skip_meta )* ) + @selected: + $bench_module, + $new_test_ext, + $test, + benchmarks_path = super, + extra = true, + exec_name = execute_with, + @user: + $( $( $rest )* )? + ); + }; + // 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, + $test:path, + benchmarks_path = $old:ident, + extra = $extra:expr, + exec_name = $exec_name:ident, + @user: + benchmarks_path = $benchmarks_path:ident + $(, $( $rest:tt )* )? + ) => { + $crate::impl_test_function!( + @cases: + ( $( $names )* ) + ( $( $names_extra )* ) + ( $( $names_skip_meta )* ) + @selected: + $bench_module, + $new_test_ext, + $test, + benchmarks_path = $benchmarks_path, + extra = $extra, + exec_name = $exec_name, + @user: + $( $( $rest )* )? + ); + }; + // pick off the extra keyword argument + ( + @cases: + ( $( $names:tt )* ) + ( $( $names_extra:tt )* ) + ( $( $names_skip_meta:tt )* ) + @selected: + $bench_module:ident, + $new_test_ext:expr, + $test:path, + benchmarks_path = $benchmarks_path:ident, + extra = $old:expr, + exec_name = $exec_name:ident, + @user: + extra = $extra:expr + $(, $( $rest:tt )* )? + ) => { + $crate::impl_test_function!( + @cases: + ( $( $names )* ) + ( $( $names_extra )* ) + ( $( $names_skip_meta )* ) + @selected: + $bench_module, + $new_test_ext, + $test, + benchmarks_path = $benchmarks_path, + extra = $extra, + exec_name = $exec_name, + @user: + $( $( $rest )* )? + ); + }; + // 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, + $test:path, + benchmarks_path = $benchmarks_path:ident, + extra = $extra:expr, + exec_name = $old:ident, + @user: + exec_name = $exec_name:ident + $(, $( $rest:tt )* )? + ) => { + $crate::impl_test_function!( + @cases: + ( $( $names )* ) + ( $( $names_extra )* ) + ( $( $names_skip_meta )* ) + @selected: + $bench_module, + $new_test_ext, + $test, + benchmarks_path = $benchmarks_path, + extra = $extra, + exec_name = $exec_name, + @user: + $( $( $rest )* )? + ); + }; + // 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, + $test:path, + benchmarks_path = $path_to_benchmarks_invocation:ident, + extra = $extra:expr, + exec_name = $exec_name:ident, + @user: + $(,)? + ) => { + #[cfg(test)] + mod benchmark_tests { + use super::$bench_module; + + #[test] + fn test_benchmarks() { + $new_test_ext.$exec_name(|| { + use $crate::Benchmarking; + + let mut anything_failed = false; + println!("failing benchmark tests:"); + for benchmark_metadata in $bench_module::<$test>::benchmarks($extra) { + let benchmark_name = &benchmark_metadata.name; + match std::panic::catch_unwind(|| { + $bench_module::<$test>::test_bench_by_name(benchmark_name) + }) { + Err(err) => { + println!( + "{}: {:?}", + $crate::str::from_utf8(benchmark_name) + .expect("benchmark name is always a valid string!"), + err, + ); + anything_failed = true; + }, + Ok(Err(err)) => { + match err { + $crate::BenchmarkError::Stop(err) => { + println!( + "{}: {:?}", + $crate::str::from_utf8(benchmark_name) + .expect("benchmark name is always a valid string!"), + err, + ); + anything_failed = true; + }, + $crate::BenchmarkError::Override(_) => { + // This is still considered a success condition. + $crate::log::error!( + "WARNING: benchmark error overrided - {}", + $crate::str::from_utf8(benchmark_name) + .expect("benchmark name is always a valid string!"), + ); + }, + $crate::BenchmarkError::Skip => { + // This is considered a success condition. + $crate::log::error!( + "WARNING: benchmark error skipped - {}", + $crate::str::from_utf8(benchmark_name) + .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(())) => (), + } + } + assert!(!anything_failed); + }); + } + } + }; +} + +/// show error message and debugging info for the case of an error happening +/// during a benchmark +pub fn show_benchmark_debug_info( + instance_string: &[u8], + benchmark: &[u8], + components: &[(BenchmarkParameter, u32)], + verify: &bool, + error_message: &str, +) -> sp_runtime::RuntimeString { + sp_runtime::format_runtime_string!( + "\n* Pallet: {}\n\ + * Benchmark: {}\n\ + * Components: {:?}\n\ + * Verify: {:?}\n\ + * Error message: {}", + sp_std::str::from_utf8(instance_string) + .expect("it's all just strings ran through the wasm interface. qed"), + sp_std::str::from_utf8(benchmark) + .expect("it's all just strings ran through the wasm interface. qed"), + components, + verify, + error_message, + ) +} + +/// This macro adds pallet benchmarks to a `Vec` object. +/// +/// First create an object that holds in the input parameters for the benchmark: +/// +/// ```ignore +/// let params = (&config, &whitelist); +/// ``` +/// +/// The `whitelist` is a parameter you pass to control the DB read/write tracking. +/// We use a vector of [TrackedStorageKey](./struct.TrackedStorageKey.html), which is a simple +/// struct used to set if a key has been read or written to. +/// +/// For values that should be skipped entirely, we can just pass `key.into()`. For example: +/// +/// ``` +/// use frame_benchmarking::TrackedStorageKey; +/// let whitelist: Vec = vec![ +/// // Block Number +/// array_bytes::hex_into_unchecked("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac"), +/// // Total Issuance +/// array_bytes::hex_into_unchecked("c2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80"), +/// // Execution Phase +/// array_bytes::hex_into_unchecked("26aa394eea5630e07c48ae0c9558cef7ff553b5a9862a516939d82b3d3d8661a"), +/// // Event Count +/// array_bytes::hex_into_unchecked("26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850"), +/// ]; +/// ``` +/// +/// Then define a mutable local variable to hold your `BenchmarkBatch` object: +/// +/// ```ignore +/// let mut batches = Vec::::new(); +/// ```` +/// +/// Then add the pallets you want to benchmark to this object, using their crate name and generated +/// module struct: +/// +/// ```ignore +/// add_benchmark!(params, batches, pallet_balances, Balances); +/// add_benchmark!(params, batches, pallet_session, SessionBench::); +/// add_benchmark!(params, batches, frame_system, SystemBench::); +/// ... +/// ``` +/// +/// At the end of `dispatch_benchmark`, you should return this batches object. +/// +/// In the case where you have multiple instances of a pallet that you need to separately benchmark, +/// the name of your module struct will be used as a suffix to your outputted weight file. For +/// example: +/// +/// ```ignore +/// add_benchmark!(params, batches, pallet_balances, Balances); // pallet_balances.rs +/// add_benchmark!(params, batches, pallet_collective, Council); // pallet_collective_council.rs +/// add_benchmark!(params, batches, pallet_collective, TechnicalCommittee); // pallet_collective_technical_committee.rs +/// ``` +/// +/// You can manipulate this suffixed string by using a type alias if needed. For example: +/// +/// ```ignore +/// 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 )* ) => ( + let name_string = stringify!($name).as_bytes(); + let instance_string = stringify!( $( $location )* ).as_bytes(); + let (config, whitelist) = $params; + let $crate::BenchmarkConfig { + pallet, + benchmark, + selected_components, + verify, + internal_repeats, + } = config; + if &pallet[..] == &name_string[..] { + let benchmark_result = $( $location )*::run_benchmark( + &benchmark[..], + &selected_components[..], + whitelist, + *verify, + *internal_repeats, + ); + + let final_results = match benchmark_result { + Ok(results) => Some(results), + Err($crate::BenchmarkError::Override(mut result)) => { + // Insert override warning as the first storage key. + $crate::log::error!( + "WARNING: benchmark error overrided - {}", + $crate::str::from_utf8(benchmark) + .expect("benchmark name is always a valid string!") + ); + result.keys.insert(0, + (b"Benchmark Override".to_vec(), 0, 0, false) + ); + Some($crate::vec![result]) + }, + Err($crate::BenchmarkError::Stop(e)) => { + $crate::show_benchmark_debug_info( + instance_string, + benchmark, + selected_components, + verify, + e, + ); + return Err(e.into()); + }, + Err($crate::BenchmarkError::Skip) => { + $crate::log::error!( + "WARNING: benchmark error skipped - {}", + $crate::str::from_utf8(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() + }]) + } + }; + + if let Some(final_results) = final_results { + $batches.push($crate::BenchmarkBatch { + pallet: name_string.to_vec(), + instance: instance_string.to_vec(), + benchmark: benchmark.clone(), + results: final_results, + }); + } + } + ) +} + +/// Callback for `define_benchmarks` to call `add_benchmark`. +#[macro_export] +macro_rules! cb_add_benchmarks { + // anchor + ( $params:ident, $batches:ident, [ $name:path, $( $location:tt )* ] ) => { + $crate::add_benchmark!( $params, $batches, $name, $( $location )* ); + }; + // recursion tail + ( $params:ident, $batches:ident, [ $name:path, $( $location:tt )* ] $([ $names:path, $( $locations:tt )* ])+ ) => { + $crate::cb_add_benchmarks!( $params, $batches, [ $name, $( $location )* ] ); + $crate::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. +/// +/// To use this macro, first create a an object to store the list: +/// +/// ```ignore +/// let mut list = Vec::::new(); +/// ``` +/// +/// Then pass this `list` to the macro, along with the `extra` boolean, the pallet crate, and +/// pallet struct: +/// +/// ```ignore +/// list_benchmark!(list, extra, pallet_balances, Balances); +/// list_benchmark!(list, extra, pallet_session, SessionBench::); +/// list_benchmark!(list, extra, frame_system, SystemBench::); +/// ``` +/// +/// This should match what exists with the `add_benchmark!` macro. +#[macro_export] +macro_rules! list_benchmark { + ( $list:ident, $extra:ident, $name:path, $( $location:tt )* ) => ( + let pallet_string = stringify!($name).as_bytes(); + let instance_string = stringify!( $( $location )* ).as_bytes(); + let benchmarks = $( $location )*::benchmarks($extra); + let pallet_benchmarks = BenchmarkList { + pallet: pallet_string.to_vec(), + instance: instance_string.to_vec(), + benchmarks: benchmarks.to_vec(), + }; + $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 )* ] ) => { + $crate::list_benchmark!( $list, $extra, $name, $( $location )* ); + }; + // recursion tail + ( $list:ident, $extra:ident, [ $name:path, $( $location:tt )* ] $([ $names:path, $( $locations:tt )* ])+ ) => { + $crate::cb_list_benchmarks!( $list, $extra, [ $name, $( $location )* ] ); + $crate::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 ) => { + $crate::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 ) => { + $crate::cb_add_benchmarks!( $params, $batches, $([ $names, $( $locations )* ])+ ); + } + } + } +} + +pub use add_benchmark; +pub use benchmark_backend; +pub use benchmarks; +pub use benchmarks_instance; +pub use benchmarks_instance_pallet; +pub use benchmarks_iter; +pub use cb_add_benchmarks; +pub use cb_list_benchmarks; +pub use define_benchmarks; +pub use impl_bench_case_tests; +pub use impl_bench_name_tests; +pub use impl_benchmark; +pub use impl_benchmark_test; +pub use impl_benchmark_test_suite; +pub use impl_test_function; +pub use list_benchmark; +pub use selected_benchmark; +pub use to_origin; +pub use whitelist; diff --git a/frame/bounties/src/benchmarking.rs b/frame/bounties/src/benchmarking.rs index adadb3411ac65..a43372978e5ca 100644 --- a/frame/bounties/src/benchmarking.rs +++ b/frame/bounties/src/benchmarking.rs @@ -21,7 +21,9 @@ use super::*; -use frame_benchmarking::{account, benchmarks_instance_pallet, whitelisted_caller, BenchmarkError}; +use frame_benchmarking::v1::{ + account, benchmarks_instance_pallet, whitelisted_caller, BenchmarkError, +}; use frame_system::RawOrigin; use sp_runtime::traits::Bounded; diff --git a/frame/child-bounties/src/benchmarking.rs b/frame/child-bounties/src/benchmarking.rs index 04a8583f286f1..e7f18c1645823 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, BenchmarkError}; +use frame_benchmarking::v1::{account, benchmarks, whitelisted_caller, BenchmarkError}; use frame_system::RawOrigin; use crate::Pallet as ChildBounties; diff --git a/frame/collective/src/benchmarking.rs b/frame/collective/src/benchmarking.rs index 75a724623002e..5c9e55862d1a4 100644 --- a/frame/collective/src/benchmarking.rs +++ b/frame/collective/src/benchmarking.rs @@ -23,7 +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, whitelisted_caller}; +use frame_benchmarking::v1::{account, benchmarks_instance_pallet, whitelisted_caller}; use frame_system::{Call as SystemCall, Pallet as System, RawOrigin as SystemOrigin}; const SEED: u32 = 0; diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index 2bd807dfb758f..708d92766d488 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -37,7 +37,7 @@ use crate::{ Pallet as Contracts, *, }; use codec::{Encode, MaxEncodedLen}; -use frame_benchmarking::{account, benchmarks, whitelisted_caller}; +use frame_benchmarking::v1::{account, benchmarks, whitelisted_caller}; use frame_support::weights::Weight; use frame_system::RawOrigin; use sp_runtime::{ diff --git a/frame/conviction-voting/src/benchmarking.rs b/frame/conviction-voting/src/benchmarking.rs index 117bb7fe22989..8c168a34a739d 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_instance_pallet, whitelist_account}; +use frame_benchmarking::v1::{account, benchmarks_instance_pallet, whitelist_account}; use frame_support::{ dispatch::RawOrigin, traits::{fungible, Currency, Get}, diff --git a/frame/democracy/src/benchmarking.rs b/frame/democracy/src/benchmarking.rs index 424192e2521da..66d9e2a007afa 100644 --- a/frame/democracy/src/benchmarking.rs +++ b/frame/democracy/src/benchmarking.rs @@ -19,7 +19,7 @@ use super::*; -use frame_benchmarking::{account, benchmarks, whitelist_account}; +use frame_benchmarking::v1::{account, benchmarks, whitelist_account}; use frame_support::{ assert_noop, assert_ok, traits::{Currency, EnsureOrigin, Get, OnInitialize, UnfilteredDispatchable}, diff --git a/frame/election-provider-support/benchmarking/src/lib.rs b/frame/election-provider-support/benchmarking/src/lib.rs index 547e35bed36e8..5323513da98d5 100644 --- a/frame/election-provider-support/benchmarking/src/lib.rs +++ b/frame/election-provider-support/benchmarking/src/lib.rs @@ -22,7 +22,7 @@ #![cfg_attr(not(feature = "std"), no_std)] use codec::Decode; -use frame_benchmarking::{benchmarks, Vec}; +use frame_benchmarking::v1::{benchmarks, Vec}; use frame_election_provider_support::{NposSolver, PhragMMS, SequentialPhragmen}; pub struct Pallet(frame_system::Pallet); diff --git a/frame/elections-phragmen/src/benchmarking.rs b/frame/elections-phragmen/src/benchmarking.rs index 53157deaa961b..1fc500a8e3464 100644 --- a/frame/elections-phragmen/src/benchmarking.rs +++ b/frame/elections-phragmen/src/benchmarking.rs @@ -21,7 +21,7 @@ use super::*; -use frame_benchmarking::{account, benchmarks, whitelist, BenchmarkError, BenchmarkResult}; +use frame_benchmarking::v1::{account, benchmarks, whitelist, BenchmarkError, BenchmarkResult}; use frame_support::{dispatch::DispatchResultWithPostInfo, traits::OnInitialize}; use frame_system::RawOrigin; diff --git a/frame/examples/basic/src/benchmarking.rs b/frame/examples/basic/src/benchmarking.rs index 699e56685fbe9..a9e2013b0446c 100644 --- a/frame/examples/basic/src/benchmarking.rs +++ b/frame/examples/basic/src/benchmarking.rs @@ -21,8 +21,11 @@ #![cfg(feature = "runtime-benchmarks")] use crate::*; -use frame_benchmarking::{impl_benchmark_test_suite, whitelisted_caller}; -use frame_support::benchmarking::{benchmarks, Linear}; +use frame_benchmarking::v1::{ + impl_benchmark_test_suite, + v2::{benchmarks, Linear}, + whitelisted_caller, +}; use frame_system::RawOrigin; // To actually run this benchmark on pallet-example-basic, we need to put this pallet into the diff --git a/frame/fast-unstake/src/benchmarking.rs b/frame/fast-unstake/src/benchmarking.rs index de85502f7b411..77488b6447c61 100644 --- a/frame/fast-unstake/src/benchmarking.rs +++ b/frame/fast-unstake/src/benchmarking.rs @@ -20,7 +20,7 @@ #![cfg(feature = "runtime-benchmarks")] use crate::{types::*, Pallet as FastUnstake, *}; -use frame_benchmarking::{benchmarks, whitelist_account}; +use frame_benchmarking::v1::{benchmarks, whitelist_account}; use frame_support::{ assert_ok, traits::{Currency, EnsureOrigin, Get, Hooks}, diff --git a/frame/grandpa/src/benchmarking.rs b/frame/grandpa/src/benchmarking.rs index 1240859149920..6eee12ad98dbf 100644 --- a/frame/grandpa/src/benchmarking.rs +++ b/frame/grandpa/src/benchmarking.rs @@ -18,7 +18,7 @@ //! Benchmarks for the GRANDPA pallet. use super::{Pallet as Grandpa, *}; -use frame_benchmarking::benchmarks; +use frame_benchmarking::v1::benchmarks; use frame_system::RawOrigin; use sp_core::H256; diff --git a/frame/identity/src/benchmarking.rs b/frame/identity/src/benchmarking.rs index 3584eb954b399..356bcb2e80174 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, whitelisted_caller}; +use frame_benchmarking::v1::{account, benchmarks, whitelisted_caller}; use frame_support::{ ensure, traits::{EnsureOrigin, Get}, diff --git a/frame/im-online/src/benchmarking.rs b/frame/im-online/src/benchmarking.rs index edc21043c34de..e4d1a64651408 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; +use frame_benchmarking::v1::benchmarks; use frame_support::{traits::UnfilteredDispatchable, WeakBoundedVec}; use frame_system::RawOrigin; use sp_core::{offchain::OpaqueMultiaddr, OpaquePeerId}; diff --git a/frame/indices/src/benchmarking.rs b/frame/indices/src/benchmarking.rs index f462f22284d40..ce1ea9f4d39f3 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, whitelisted_caller}; +use frame_benchmarking::v1::{account, benchmarks, whitelisted_caller}; use frame_system::RawOrigin; use sp_runtime::traits::Bounded; diff --git a/frame/lottery/src/benchmarking.rs b/frame/lottery/src/benchmarking.rs index fba722a07fabd..658dd25a98a27 100644 --- a/frame/lottery/src/benchmarking.rs +++ b/frame/lottery/src/benchmarking.rs @@ -21,7 +21,7 @@ use super::*; -use frame_benchmarking::{account, benchmarks, whitelisted_caller}; +use frame_benchmarking::v1::{account, benchmarks, whitelisted_caller}; use frame_support::{ storage::bounded_vec::BoundedVec, traits::{EnsureOrigin, OnInitialize}, diff --git a/frame/membership/src/lib.rs b/frame/membership/src/lib.rs index 934abb996df80..6d973a15fe032 100644 --- a/frame/membership/src/lib.rs +++ b/frame/membership/src/lib.rs @@ -362,7 +362,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, whitelist}; + use frame_benchmarking::v1::{account, benchmarks_instance_pallet, whitelist}; use frame_support::{assert_ok, traits::EnsureOrigin}; use frame_system::RawOrigin; diff --git a/frame/merkle-mountain-range/src/benchmarking.rs b/frame/merkle-mountain-range/src/benchmarking.rs index d24364a55f9e6..7731c0e505c97 100644 --- a/frame/merkle-mountain-range/src/benchmarking.rs +++ b/frame/merkle-mountain-range/src/benchmarking.rs @@ -20,7 +20,7 @@ #![cfg(feature = "runtime-benchmarks")] use crate::*; -use frame_benchmarking::benchmarks_instance_pallet; +use frame_benchmarking::v1::benchmarks_instance_pallet; use frame_support::traits::OnInitialize; benchmarks_instance_pallet! { diff --git a/frame/message-queue/src/benchmarking.rs b/frame/message-queue/src/benchmarking.rs index 9651c81e5e66d..97ca71ce9d7d2 100644 --- a/frame/message-queue/src/benchmarking.rs +++ b/frame/message-queue/src/benchmarking.rs @@ -22,8 +22,8 @@ use super::{mock_helpers::*, Pallet as MessageQueue, *}; -use frame_benchmarking::{impl_benchmark_test_suite, whitelisted_caller}; -use frame_support::{benchmarking::*, traits::Get}; +use frame_benchmarking::v2::*; +use frame_support::traits::Get; use frame_system::RawOrigin; use sp_std::prelude::*; diff --git a/frame/multisig/src/benchmarking.rs b/frame/multisig/src/benchmarking.rs index d5faf9ae8ac1a..8993908b25acf 100644 --- a/frame/multisig/src/benchmarking.rs +++ b/frame/multisig/src/benchmarking.rs @@ -20,7 +20,7 @@ #![cfg(feature = "runtime-benchmarks")] use super::*; -use frame_benchmarking::{account, benchmarks}; +use frame_benchmarking::v1::{account, benchmarks}; use frame_system::RawOrigin; use sp_runtime::traits::Bounded; diff --git a/frame/nfts/src/benchmarking.rs b/frame/nfts/src/benchmarking.rs index 6517445da672d..17ff28b822814 100644 --- a/frame/nfts/src/benchmarking.rs +++ b/frame/nfts/src/benchmarking.rs @@ -21,7 +21,7 @@ use super::*; use enumflags2::{BitFlag, BitFlags}; -use frame_benchmarking::{ +use frame_benchmarking::v1::{ account, benchmarks_instance_pallet, whitelist_account, whitelisted_caller, }; use frame_support::{ diff --git a/frame/nis/src/benchmarking.rs b/frame/nis/src/benchmarking.rs index b45c982bd150a..b01d414c4b251 100644 --- a/frame/nis/src/benchmarking.rs +++ b/frame/nis/src/benchmarking.rs @@ -20,7 +20,7 @@ #![cfg(feature = "runtime-benchmarks")] use super::*; -use frame_benchmarking::{account, benchmarks, whitelisted_caller}; +use frame_benchmarking::v1::{account, benchmarks, whitelisted_caller}; use frame_support::traits::{nonfungible::Inspect, Currency, EnsureOrigin, Get}; use frame_system::RawOrigin; use sp_arithmetic::Perquintill; diff --git a/frame/nomination-pools/benchmarking/src/lib.rs b/frame/nomination-pools/benchmarking/src/lib.rs index 9b063539152b7..32708ff53e01c 100644 --- a/frame/nomination-pools/benchmarking/src/lib.rs +++ b/frame/nomination-pools/benchmarking/src/lib.rs @@ -23,7 +23,9 @@ #[cfg(test)] mod mock; -use frame_benchmarking::{account, frame_support::traits::Currency, vec, whitelist_account, Vec}; +use frame_benchmarking::v1::{ + 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 RuntimeOrigin; diff --git a/frame/offences/benchmarking/src/lib.rs b/frame/offences/benchmarking/src/lib.rs index 7e586a96bbe3e..b71321906cbdd 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_benchmarking::v1::{account, benchmarks}; use frame_support::traits::{Currency, Get, ValidatorSet, ValidatorSetWithIdentification}; use frame_system::{Config as SystemConfig, Pallet as System, RawOrigin}; diff --git a/frame/preimage/src/benchmarking.rs b/frame/preimage/src/benchmarking.rs index 8a61d7d780bfd..f9526b67d4bc8 100644 --- a/frame/preimage/src/benchmarking.rs +++ b/frame/preimage/src/benchmarking.rs @@ -18,7 +18,7 @@ //! Preimage pallet benchmarking. use super::*; -use frame_benchmarking::{account, benchmarks, whitelist_account}; +use frame_benchmarking::v1::{account, benchmarks, whitelist_account}; use frame_support::assert_ok; use frame_system::RawOrigin; use sp_runtime::traits::Bounded; diff --git a/frame/proxy/src/benchmarking.rs b/frame/proxy/src/benchmarking.rs index 58c0cb73011df..ef3df02dcc776 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, whitelisted_caller}; +use frame_benchmarking::v1::{account, benchmarks, whitelisted_caller}; use frame_system::RawOrigin; use sp_runtime::traits::Bounded; diff --git a/frame/ranked-collective/src/benchmarking.rs b/frame/ranked-collective/src/benchmarking.rs index eb629b330abb2..48df7f1f1e6ab 100644 --- a/frame/ranked-collective/src/benchmarking.rs +++ b/frame/ranked-collective/src/benchmarking.rs @@ -21,7 +21,7 @@ use super::*; #[allow(unused_imports)] use crate::Pallet as RankedCollective; -use frame_benchmarking::{account, benchmarks_instance_pallet, whitelisted_caller}; +use frame_benchmarking::v1::{account, benchmarks_instance_pallet, whitelisted_caller}; use frame_support::{assert_ok, dispatch::UnfilteredDispatchable}; use frame_system::RawOrigin as SystemOrigin; diff --git a/frame/recovery/src/benchmarking.rs b/frame/recovery/src/benchmarking.rs index 870543d9bd290..48ca7dad766bb 100644 --- a/frame/recovery/src/benchmarking.rs +++ b/frame/recovery/src/benchmarking.rs @@ -20,7 +20,7 @@ use super::*; use crate::Pallet; -use frame_benchmarking::{account, benchmarks, whitelisted_caller}; +use frame_benchmarking::v1::{account, benchmarks, whitelisted_caller}; use frame_support::traits::{Currency, Get}; use frame_system::RawOrigin; use sp_runtime::traits::Bounded; diff --git a/frame/referenda/src/benchmarking.rs b/frame/referenda/src/benchmarking.rs index e57b5f9859e5b..db5299e0d5bb2 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_instance_pallet, whitelist_account}; +use frame_benchmarking::v1::{account, benchmarks_instance_pallet, whitelist_account}; use frame_support::{ assert_ok, dispatch::UnfilteredDispatchable, diff --git a/frame/remark/src/benchmarking.rs b/frame/remark/src/benchmarking.rs index c0db8d5d3d59b..ee93cb24a3f34 100644 --- a/frame/remark/src/benchmarking.rs +++ b/frame/remark/src/benchmarking.rs @@ -20,7 +20,7 @@ #![cfg(feature = "runtime-benchmarks")] use super::*; -use frame_benchmarking::{benchmarks, whitelisted_caller}; +use frame_benchmarking::v1::{benchmarks, whitelisted_caller}; use frame_system::{EventRecord, Pallet as System, RawOrigin}; use sp_std::*; diff --git a/frame/scheduler/src/benchmarking.rs b/frame/scheduler/src/benchmarking.rs index 8e2876290be55..9ec82f5c8447e 100644 --- a/frame/scheduler/src/benchmarking.rs +++ b/frame/scheduler/src/benchmarking.rs @@ -18,7 +18,7 @@ //! Scheduler pallet benchmarking. use super::*; -use frame_benchmarking::{account, benchmarks}; +use frame_benchmarking::v1::{account, benchmarks}; use frame_support::{ ensure, traits::{schedule::Priority, BoundedInline}, diff --git a/frame/session/benchmarking/src/lib.rs b/frame/session/benchmarking/src/lib.rs index 9e478ada53cf2..a6c25f5e10549 100644 --- a/frame/session/benchmarking/src/lib.rs +++ b/frame/session/benchmarking/src/lib.rs @@ -26,7 +26,7 @@ mod mock; use sp_runtime::traits::{One, StaticLookup, TrailingZeroInput}; use sp_std::{prelude::*, vec}; -use frame_benchmarking::benchmarks; +use frame_benchmarking::v1::benchmarks; use frame_support::{ codec::Decode, traits::{Get, KeyOwnerProofSystem, OnInitialize}, diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index b3d32b26ec1f7..a4366bbd8aa9a 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -35,7 +35,7 @@ use sp_runtime::{ use sp_staking::SessionIndex; use sp_std::prelude::*; -pub use frame_benchmarking::{ +pub use frame_benchmarking::v1::{ account, benchmarks, impl_benchmark_test_suite, whitelist_account, whitelisted_caller, }; use frame_system::RawOrigin; diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index ae2fc358974b6..4f62ae42ef78f 100644 --- a/frame/support/Cargo.toml +++ b/frame/support/Cargo.toml @@ -27,7 +27,6 @@ sp-arithmetic = { version = "6.0.0", default-features = false, path = "../../pri 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" } -static_assertions = "1.1.0" tt-call = "1.0.8" frame-support-procedural = { version = "4.0.0-dev", default-features = false, path = "./procedural" } paste = "1.0" diff --git a/frame/support/procedural/src/benchmark.rs b/frame/support/procedural/src/benchmark.rs index f3bd5c2cfe6bf..fa7fd44928659 100644 --- a/frame/support/procedural/src/benchmark.rs +++ b/frame/support/procedural/src/benchmark.rs @@ -638,7 +638,7 @@ fn expand_benchmark( Ok(ident) => ident, Err(err) => return err.to_compile_error().into(), }; - let home = quote!(#krate::frame_support::benchmarking); + let home = quote!(#krate::v2); let codec = quote!(#krate::frame_support::codec); let traits = quote!(#krate::frame_support::traits); let setup_stmts = benchmark_def.setup_stmts; diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index 9bdbbd1f27bb2..8fa46b48d005f 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -483,7 +483,7 @@ pub fn pallet(attr: TokenStream, item: TokenStream) -> TokenStream { /// An attribute macro that can be attached to a (non-empty) module declaration. Doing so will /// designate that module as a benchmarking module. /// -/// See `frame_support::benchmarking` for more info. +/// See `frame_benchmarking::v2` for more info. #[proc_macro_attribute] pub fn benchmarks(attr: TokenStream, tokens: TokenStream) -> TokenStream { match benchmark::benchmarks(attr, tokens, false) { @@ -495,7 +495,7 @@ pub fn benchmarks(attr: TokenStream, tokens: TokenStream) -> TokenStream { /// An attribute macro that can be attached to a (non-empty) module declaration. Doing so will /// designate that module as an instance benchmarking module. /// -/// See `frame_support::benchmarking` for more info. +/// See `frame_benchmarking::v2` for more info. #[proc_macro_attribute] pub fn instance_benchmarks(attr: TokenStream, tokens: TokenStream) -> TokenStream { match benchmark::benchmarks(attr, tokens, true) { @@ -508,7 +508,7 @@ pub fn instance_benchmarks(attr: TokenStream, tokens: TokenStream) -> TokenStrea /// attached to a function definition containing an `#[extrinsic_call]` or `#[block]` /// attribute. /// -/// See `frame_support::benchmarking` for more info. +/// See `frame_benchmarking::v2` for more info. #[proc_macro_attribute] pub fn benchmark(_attrs: TokenStream, _tokens: TokenStream) -> TokenStream { quote!(compile_error!( @@ -521,7 +521,7 @@ pub fn benchmark(_attrs: TokenStream, _tokens: TokenStream) -> TokenStream { /// used as a boundary designating where the benchmark setup code ends, and the benchmark /// verification code begins. /// -/// See `frame_support::benchmarking` for more info. +/// See `frame_benchmarking::v2` for more info. #[proc_macro_attribute] pub fn extrinsic_call(_attrs: TokenStream, _tokens: TokenStream) -> TokenStream { quote!(compile_error!( @@ -534,7 +534,7 @@ pub fn extrinsic_call(_attrs: TokenStream, _tokens: TokenStream) -> TokenStream /// enclosing benchmark function, This attribute is also used as a boundary designating where /// the benchmark setup code ends, and the benchmark verification code begins. /// -/// See `frame_support::benchmarking` for more info. +/// See `frame_benchmarking::v2` for more info. #[proc_macro_attribute] pub fn block(_attrs: TokenStream, _tokens: TokenStream) -> TokenStream { quote!(compile_error!( diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 40bc878cff365..902893972f0b1 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -2745,228 +2745,5 @@ pub mod pallet_macros { }; } -/// Contains macros, structs, and traits associated with v2 of the pallet benchmarking syntax. -/// This module contains macros, structs, and traits associated with v2 of the pallet -/// benchmarking syntax. -/// -/// The [`benchmarking::benchmarks`] and [`benchmarking::instance_benchmarks`] macros can be -/// used to designate a module as a benchmarking module that can contain benchmarks and -/// benchmark tests. The `#[benchmarks]` variant will set up a regular, non-instance -/// benchmarking module, and the `#[instance_benchmarks]` variant will set up the module in -/// instance benchmarking mode. -/// -/// Benchmarking modules should be gated behind a `#[cfg(feature = "runtime-benchmarks")]` -/// feature gate to ensure benchmarking code that is only compiled when the -/// `runtime-benchmarks` feature is enabled is not referenced. -/// -/// The following is the general syntax for a benchmarks (or instance benchmarks) module: -/// -/// ## General Syntax -/// -/// ```ignore -/// #![cfg(feature = "runtime-benchmarks")] -/// -/// use super::{mock_helpers::*, Pallet as MyPallet}; -/// use frame_support::benchmarking::*; -/// use frame_benchmarking::whitelisted_caller; -/// -/// #[benchmarks] -/// mod benchmarks { -/// use super::*; -/// -/// #[benchmark] -/// fn bench_name_1(x: Linear<7, 1_000>, y: Linear<1_000, 100_0000>) { -/// // setup code -/// let z = x + y; -/// let caller = whitelisted_caller(); -/// -/// #[extrinsic_call] -/// extrinsic_name(SystemOrigin::Signed(caller), other, arguments); -/// -/// // verification code -/// assert_eq!(MyPallet::::my_var(), z); -/// } -/// -/// #[benchmark] -/// fn bench_name_2() { -/// // setup code -/// let caller = whitelisted_caller(); -/// -/// #[block] -/// { -/// something(some, thing); -/// my_extrinsic(RawOrigin::Signed(caller), some, argument); -/// something_else(foo, bar); -/// } -/// -/// // verification code -/// assert_eq!(MyPallet::::something(), 37); -/// } -/// } -/// ``` -/// -/// ## Benchmark Definitions -/// -/// Within a `#[benchmarks]` or `#[instance_benchmarks]` module, you can define individual -/// benchmarks using the `#[benchmark]` attribute, as shown in the example above. -/// -/// The `#[benchmark]` attribute expects a function definition with a blank return type and -/// zero or more arguments whose names are valid `frame_benchmarking::BenchmarkParamater` -/// parameters, such as `x`, `y`, `a`, `b`, etc., and whose param types must implement -/// [`benchmarking::ParamRange`]. At the moment the only valid type that implements -/// [`benchmarking::ParamRange`] is [`benchmarking::Linear`]. -/// -/// The valid syntax for defining a `Linear` is `Linear` where `A`, and `B` are -/// valid integer literals (that fit in a `u32`), such that `B` >= `A`. -/// -/// Note that the benchmark function definition does not actually expand as a function -/// definition, but rather is used to automatically create a number of impls and structs -/// required by the benchmarking engine. For this reason, the visibility of the function -/// definition as well as the return type are not used for any purpose and are discarded by the -/// expansion code. -/// -/// Also note that the `// setup code` and `// verification code` comments shown above are not -/// required and are included simply for demonstration purposes. -/// -/// ### `#[extrinsic_call]` and `#[block]` -/// -/// Within the benchmark function body, either an `#[extrinsic_call]` or a `#[block]` -/// annotation is required. These attributes should be attached to a block (shown in -/// `bench_name_2` above) or a one-line function call (shown in `bench_name_1` above, in `syn` -/// parlance this should be an `ExprCall`), respectively. -/// -/// The `#[block]` syntax is broad and will benchmark any code contained within the block the -/// attribute is attached to. If `#[block]` is attached to something other than a block, a -/// compiler error will be emitted. -/// -/// The one-line `#[extrinsic_call]` syntax must consist of a function call to an extrinsic, -/// where the first argument is the origin. If `#[extrinsic_call]` is attached to an item that -/// doesn't meet these requirements, a compiler error will be emitted. -/// -/// As a short-hand, you may substitute the name of the extrinsic call with `_`, such as the -/// following: -/// -/// ```ignore -/// #[extrinsic_call] -/// _(RawOrigin::Signed(whitelisted_caller()), 0u32.into(), 0); -/// ``` -/// -/// The underscore will be substituted with the name of the benchmark (i.e. the name of the -/// function in the benchmark function definition). -/// -/// Regardless of whether `#[extrinsic_call]` or `#[block]` is used, this attribute also serves -/// the purpose of designating the boundary between the setup code portion of the benchmark -/// (everything before the `#[extrinsic_call]` or `#[block]` attribute) and the verification -/// stage (everything after the item that the `#[extrinsic_call]` or `#[block]` attribute is -/// attached to). The setup code section should contain any code that needs to execute before -/// the measured portion of the benchmark executes. The verification section is where you can -/// perform assertions to verify that the extrinsic call (or whatever is happening in your -/// block, if you used the `#[block]` syntax) executed successfully. -/// -/// Note that neither `#[extrinsic_call]` nor `#[block]` are real attribute macros and are -/// instead consumed by the outer macro pattern as part of the enclosing benchmark function -/// definition. This is why we are able to use `#[extrinsic_call]` and `#[block]` within a -/// function definition even though this behavior has not been stabilized -/// yet—`#[extrinsic_call]` and `#[block]` are parsed and consumed as part of the benchmark -/// definition parsing code, so they never expand as their own attribute macros. -/// -/// ### Optional Attributes -/// -/// The keywords `extra` and `skip_meta` can be provided as optional arguments to the -/// `#[benchmark]` attribute, i.e. `#[benchmark(extra, skip_meta)]`. Including either of these -/// will enable the `extra` or `skip_meta` option, respectively. These options enable the same -/// behavior they did in the old benchmarking syntax in `frame_benchmarking`, namely: -/// -/// #### `extra` -/// -/// Specifies that this benchmark should not normally run. To run benchmarks marked with -/// `extra`, you will need to invoke the `frame-benchmarking-cli` with `--extra`. -/// -/// #### `skip_meta` -/// -/// Specifies that the benchmarking framework should not analyze the storage keys that -/// benchmarked code read or wrote. This useful to suppress the prints in the form of unknown -/// 0x… in case a storage key that does not have metadata. Note that this skips the analysis -/// of all accesses, not just ones without metadata. -/// -/// ## Where Clause -/// -/// Some pallets require a where clause specifying constraints on their generics to make -/// writing benchmarks feasible. To accomodate this situation, you can provide such a where -/// clause as the (only) argument to the `#[benchmarks]` or `#[instance_benchmarks]` attribute -/// macros. Below is an example of this taken from the `message-queue` pallet. -/// -/// ```ignore -/// #[benchmarks( -/// where -/// <::MessageProcessor as ProcessMessage>::Origin: From + PartialEq, -/// ::Size: From, -/// )] -/// mod benchmarks { -/// use super::*; -/// // ... -/// } -/// ``` -/// -/// ## Benchmark Tests -/// -/// Benchmark tests can be generated using the old syntax in `frame_benchmarking`, -/// including the `frame_benchmarking::impl_benchmark_test_suite` macro. -/// -/// An example is shown below (taken from the `message-queue` pallet's `benchmarking` module): -/// ```ignore -/// #[benchmarks] -/// mod benchmarks { -/// use super::*; -/// // ... -/// impl_benchmark_test_suite!( -/// MessageQueue, -/// crate::mock::new_test_ext::(), -/// crate::integration_test::Test -/// ); -/// } -/// ``` -pub mod benchmarking { - pub use frame_support_procedural::{ - benchmark, benchmarks, block, extrinsic_call, instance_benchmarks, - }; - - // Used in #[benchmark] implementation to ensure that benchmark function arguments - // implement [`ParamRange`]. - #[doc(hidden)] - pub use static_assertions::assert_impl_all; - - /// Used by the new benchmarking code to specify that a benchmarking variable is linear - /// over some specified range, i.e. `Linear<0, 1_000>` means that the corresponding variable - /// is allowed to range from `0` to `1000`, inclusive. - /// - /// See [`frame_support::benchmarking`] for more info. - pub struct Linear; - - /// Trait that must be implemented by all structs that can be used as parameter range types - /// in the new benchmarking code (i.e. `Linear<0, 1_000>`). Right now there is just - /// [`Linear`] but this could later be extended to support additional non-linear parameter - /// ranges. - /// - /// See [`frame_support::benchmarking`] for more info. - pub trait ParamRange { - /// Represents the (inclusive) starting number of this [`ParamRange`]. - fn start(&self) -> u32; - - /// Represents the (inclusive) ending number of this [`ParamRange`] - fn end(&self) -> u32; - } - - impl ParamRange for Linear { - fn start(&self) -> u32 { - return A - } - - fn end(&self) -> u32 { - return B - } - } -} - // Generate a macro that will enable/disable code based on `std` feature being active. sp_core::generate_feature_enabled_macro!(std_enabled, feature = "std", $); diff --git a/frame/support/test/tests/benchmark_ui/bad_param_name.rs b/frame/support/test/tests/benchmark_ui/bad_param_name.rs index ad4db4f0a4ba4..657e481a9430a 100644 --- a/frame/support/test/tests/benchmark_ui/bad_param_name.rs +++ b/frame/support/test/tests/benchmark_ui/bad_param_name.rs @@ -1,4 +1,4 @@ -use frame_support::benchmarking::*; +use frame_benchmarking::v2::*; #[allow(unused_imports)] use frame_support_test::Config; diff --git a/frame/support/test/tests/benchmark_ui/bad_param_name_too_long.rs b/frame/support/test/tests/benchmark_ui/bad_param_name_too_long.rs index 50e4dc6fd4609..f970126d12e7e 100644 --- a/frame/support/test/tests/benchmark_ui/bad_param_name_too_long.rs +++ b/frame/support/test/tests/benchmark_ui/bad_param_name_too_long.rs @@ -1,9 +1,9 @@ -use frame_support::benchmarking::*; +use frame_benchmarking::v2::*; #[allow(unused_imports)] use frame_support_test::Config; #[benchmarks] -mod benches { +mod benchmarks { #[benchmark] fn bench(xx: Linear<1, 2>) { #[block] diff --git a/frame/support/test/tests/benchmark_ui/bad_param_name_upper_case.rs b/frame/support/test/tests/benchmark_ui/bad_param_name_upper_case.rs index 0270582b3b85b..9970f32301672 100644 --- a/frame/support/test/tests/benchmark_ui/bad_param_name_upper_case.rs +++ b/frame/support/test/tests/benchmark_ui/bad_param_name_upper_case.rs @@ -1,4 +1,4 @@ -use frame_support::benchmarking::*; +use frame_benchmarking::v2::*; #[allow(unused_imports)] use frame_support_test::Config; diff --git a/frame/support/test/tests/benchmark_ui/bad_param_range.rs b/frame/support/test/tests/benchmark_ui/bad_param_range.rs index aabb9fa7403a1..993f2a0004103 100644 --- a/frame/support/test/tests/benchmark_ui/bad_param_range.rs +++ b/frame/support/test/tests/benchmark_ui/bad_param_range.rs @@ -1,4 +1,4 @@ -use frame_support::benchmarking::*; +use frame_benchmarking::v2::*; #[allow(unused_imports)] use frame_support_test::Config; diff --git a/frame/support/test/tests/benchmark_ui/bad_params.rs b/frame/support/test/tests/benchmark_ui/bad_params.rs index a0c9236982c62..5049f2eae2c2e 100644 --- a/frame/support/test/tests/benchmark_ui/bad_params.rs +++ b/frame/support/test/tests/benchmark_ui/bad_params.rs @@ -1,4 +1,4 @@ -use frame_support::benchmarking::*; +use frame_benchmarking::v2::*; #[allow(unused_imports)] use frame_support_test::Config; diff --git a/frame/support/test/tests/benchmark_ui/dup_block.rs b/frame/support/test/tests/benchmark_ui/dup_block.rs index 4c4a8fc11d30a..2c2ef9db9a45c 100644 --- a/frame/support/test/tests/benchmark_ui/dup_block.rs +++ b/frame/support/test/tests/benchmark_ui/dup_block.rs @@ -1,4 +1,4 @@ -use frame_support::benchmarking::*; +use frame_benchmarking::v2::*; #[allow(unused_imports)] use frame_support_test::Config; diff --git a/frame/support/test/tests/benchmark_ui/dup_extrinsic_call.rs b/frame/support/test/tests/benchmark_ui/dup_extrinsic_call.rs index 1a91b7c16d6a5..4d135d1a04f52 100644 --- a/frame/support/test/tests/benchmark_ui/dup_extrinsic_call.rs +++ b/frame/support/test/tests/benchmark_ui/dup_extrinsic_call.rs @@ -1,4 +1,4 @@ -use frame_support::benchmarking::*; +use frame_benchmarking::v2::*; #[allow(unused_imports)] use frame_support_test::Config; diff --git a/frame/support/test/tests/benchmark_ui/extra_extra.rs b/frame/support/test/tests/benchmark_ui/extra_extra.rs index 021106c7afc85..1aa6c9ecb7526 100644 --- a/frame/support/test/tests/benchmark_ui/extra_extra.rs +++ b/frame/support/test/tests/benchmark_ui/extra_extra.rs @@ -1,4 +1,4 @@ -use frame_support::benchmarking::*; +use frame_benchmarking::v2::*; #[allow(unused_imports)] use frame_support_test::Config; diff --git a/frame/support/test/tests/benchmark_ui/extra_skip_meta.rs b/frame/support/test/tests/benchmark_ui/extra_skip_meta.rs index 1940f4cf1f040..3418c7af73748 100644 --- a/frame/support/test/tests/benchmark_ui/extra_skip_meta.rs +++ b/frame/support/test/tests/benchmark_ui/extra_skip_meta.rs @@ -1,4 +1,4 @@ -use frame_support::benchmarking::*; +use frame_benchmarking::v2::*; #[allow(unused_imports)] use frame_support_test::Config; diff --git a/frame/support/test/tests/benchmark_ui/extrinsic_call_out_of_fn.rs b/frame/support/test/tests/benchmark_ui/extrinsic_call_out_of_fn.rs index 4cb6bfc34c58e..ce360ee7577f5 100644 --- a/frame/support/test/tests/benchmark_ui/extrinsic_call_out_of_fn.rs +++ b/frame/support/test/tests/benchmark_ui/extrinsic_call_out_of_fn.rs @@ -1,4 +1,4 @@ -use frame_support::benchmarking::*; +use frame_benchmarking::v2::*; #[extrinsic_call] mod stuff {} diff --git a/frame/support/test/tests/benchmark_ui/missing_call.rs b/frame/support/test/tests/benchmark_ui/missing_call.rs index 74370493542c4..bc04101dd384a 100644 --- a/frame/support/test/tests/benchmark_ui/missing_call.rs +++ b/frame/support/test/tests/benchmark_ui/missing_call.rs @@ -1,4 +1,4 @@ -use frame_support::benchmarking::*; +use frame_benchmarking::v2::*; #[allow(unused_imports)] use frame_support_test::Config; diff --git a/frame/support/test/tests/benchmark_ui/missing_origin.rs b/frame/support/test/tests/benchmark_ui/missing_origin.rs index aad91bc79f825..2aaed756b9a46 100644 --- a/frame/support/test/tests/benchmark_ui/missing_origin.rs +++ b/frame/support/test/tests/benchmark_ui/missing_origin.rs @@ -1,4 +1,4 @@ -use frame_support::benchmarking::*; +use frame_benchmarking::v2::*; #[allow(unused_imports)] use frame_support_test::Config; diff --git a/frame/support/test/tests/benchmark_ui/pass/valid_basic.rs b/frame/support/test/tests/benchmark_ui/pass/valid_basic.rs index 5c84d7f76d874..450ce4f9c50da 100644 --- a/frame/support/test/tests/benchmark_ui/pass/valid_basic.rs +++ b/frame/support/test/tests/benchmark_ui/pass/valid_basic.rs @@ -1,4 +1,4 @@ -use frame_support::benchmarking::*; +use frame_benchmarking::v2::*; use frame_support_test::Config; #[benchmarks] diff --git a/frame/support/test/tests/benchmark_ui/unrecognized_option.rs b/frame/support/test/tests/benchmark_ui/unrecognized_option.rs index 4c2cea139f80c..18cae4d5d5c8e 100644 --- a/frame/support/test/tests/benchmark_ui/unrecognized_option.rs +++ b/frame/support/test/tests/benchmark_ui/unrecognized_option.rs @@ -1,4 +1,4 @@ -use frame_support::benchmarking::*; +use frame_benchmarking::v2::*; #[allow(unused_imports)] use frame_support_test::Config; diff --git a/frame/system/benchmarking/src/lib.rs b/frame/system/benchmarking/src/lib.rs index 0f7603fe1dd9f..87d3c7fc7044b 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, whitelisted_caller}; +use frame_benchmarking::v1::{benchmarks, whitelisted_caller}; use frame_support::{dispatch::DispatchClass, storage, traits::Get}; use frame_system::{Call, Pallet as System, RawOrigin}; use sp_core::storage::well_known_keys; diff --git a/frame/timestamp/src/benchmarking.rs b/frame/timestamp/src/benchmarking.rs index 8974eb95692af..3a9297fda805e 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, TrackedStorageKey}; +use frame_benchmarking::v1::{benchmarks, TrackedStorageKey}; use frame_support::{ensure, traits::OnFinalize}; use frame_system::RawOrigin; diff --git a/frame/tips/src/benchmarking.rs b/frame/tips/src/benchmarking.rs index 312424e5799ec..8ffc53b45e4ca 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_instance_pallet, whitelisted_caller}; +use frame_benchmarking::v1::{account, benchmarks_instance_pallet, whitelisted_caller}; use frame_support::ensure; use frame_system::RawOrigin; use sp_runtime::traits::Saturating; diff --git a/frame/transaction-storage/src/benchmarking.rs b/frame/transaction-storage/src/benchmarking.rs index c7fbd00fb565d..736d2c40d0b39 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, whitelisted_caller}; +use frame_benchmarking::v1::{benchmarks, whitelisted_caller}; use frame_support::traits::{Currency, Get, OnFinalize, OnInitialize}; use frame_system::{EventRecord, Pallet as System, RawOrigin}; use sp_runtime::traits::{Bounded, One, Zero}; diff --git a/frame/treasury/src/benchmarking.rs b/frame/treasury/src/benchmarking.rs index d718a5fb89521..eb44744506bf4 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}; +use frame_benchmarking::v1::{account, benchmarks_instance_pallet}; use frame_support::{ dispatch::UnfilteredDispatchable, ensure, diff --git a/frame/uniques/src/benchmarking.rs b/frame/uniques/src/benchmarking.rs index ab34558f95eb3..5ecb093a5d010 100644 --- a/frame/uniques/src/benchmarking.rs +++ b/frame/uniques/src/benchmarking.rs @@ -20,7 +20,7 @@ #![cfg(feature = "runtime-benchmarks")] use super::*; -use frame_benchmarking::{ +use frame_benchmarking::v1::{ account, benchmarks_instance_pallet, whitelist_account, whitelisted_caller, }; use frame_support::{ diff --git a/frame/utility/src/benchmarking.rs b/frame/utility/src/benchmarking.rs index 07bc14951cb3b..f381b1e5f9e61 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, whitelisted_caller}; +use frame_benchmarking::v1::{account, benchmarks, whitelisted_caller}; use frame_system::RawOrigin; const SEED: u32 = 0; diff --git a/frame/vesting/src/benchmarking.rs b/frame/vesting/src/benchmarking.rs index dde5fe3ac7561..eb0d596b8a38b 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, whitelisted_caller}; +use frame_benchmarking::v1::{account, benchmarks, whitelisted_caller}; use frame_support::assert_ok; use frame_system::{Pallet as System, RawOrigin}; use sp_runtime::traits::{Bounded, CheckedDiv, CheckedMul}; diff --git a/frame/whitelist/src/benchmarking.rs b/frame/whitelist/src/benchmarking.rs index 569b13c12da31..e64842b34df59 100644 --- a/frame/whitelist/src/benchmarking.rs +++ b/frame/whitelist/src/benchmarking.rs @@ -20,7 +20,7 @@ #![cfg(feature = "runtime-benchmarks")] use super::*; -use frame_benchmarking::benchmarks; +use frame_benchmarking::v1::benchmarks; use frame_support::{ensure, traits::EnsureOrigin}; #[cfg(test)] From 9762613a130235317467f66d6e6f46bfa30a5674 Mon Sep 17 00:00:00 2001 From: Matteo Muraca <56828990+muraca@users.noreply.github.com> Date: Sat, 28 Jan 2023 00:47:17 +0100 Subject: [PATCH 340/715] mutate_exists for StorageValue with ValueQuery (#13245) * mutate_exists for StorageValue with ValueQuery Signed-off-by: muraca * added `#[crate::storage_alias]` to tests Signed-off-by: muraca * added StorageEntryMetadata Signed-off-by: muraca * Update frame/support/src/lib.rs --------- Signed-off-by: muraca Co-authored-by: Oliver Tale-Yazdi --- frame/support/src/lib.rs | 63 ++++++++++++++++++++ frame/support/src/storage/generator/value.rs | 24 ++++++++ frame/support/src/storage/mod.rs | 6 ++ frame/support/src/storage/types/value.rs | 12 ++++ 4 files changed, 105 insertions(+) diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 902893972f0b1..77ca89dc6f800 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -874,6 +874,7 @@ pub mod tests { decl_storage! { trait Store for Module as Test { + pub Value get(fn value): u64; pub Data get(fn data) build(|_| vec![(15u32, 42u64)]): map hasher(twox_64_concat) u32 => u64; pub OptionLinkedMap: map hasher(blake2_128_concat) u32 => Option; @@ -946,6 +947,61 @@ pub mod tests { }); } + #[test] + fn storage_value_mutate_exists_should_work() { + new_test_ext().execute_with(|| { + #[crate::storage_alias] + pub type Value = StorageValue; + + assert!(!Value::exists()); + + Value::mutate_exists(|v| *v = Some(1)); + assert!(Value::exists()); + assert_eq!(Value::get(), Some(1)); + + // removed if mutated to `None` + Value::mutate_exists(|v| *v = None); + assert!(!Value::exists()); + }); + } + + #[test] + fn storage_value_try_mutate_exists_should_work() { + new_test_ext().execute_with(|| { + #[crate::storage_alias] + pub type Value = StorageValue; + + type TestResult = result::Result<(), &'static str>; + + assert!(!Value::exists()); + + // mutated if `Ok` + assert_ok!(Value::try_mutate_exists(|v| -> TestResult { + *v = Some(1); + Ok(()) + })); + assert!(Value::exists()); + assert_eq!(Value::get(), Some(1)); + + // no-op if `Err` + assert_noop!( + Value::try_mutate_exists(|v| -> TestResult { + *v = Some(2); + Err("nah") + }), + "nah" + ); + assert_eq!(Value::get(), Some(1)); + + // removed if mutated to`None` + assert_ok!(Value::try_mutate_exists(|v| -> TestResult { + *v = None; + Ok(()) + })); + assert!(!Value::exists()); + }); + } + #[test] fn map_issue_3318() { new_test_ext().execute_with(|| { @@ -1257,6 +1313,13 @@ pub mod tests { PalletStorageMetadata { prefix: "Test", entries: vec![ + StorageEntryMetadata { + name: "Value", + modifier: StorageEntryModifier::Default, + ty: StorageEntryType::Plain(scale_info::meta_type::()), + default: vec![0, 0, 0, 0, 0, 0, 0, 0], + docs: vec![], + }, StorageEntryMetadata { name: "Data", modifier: StorageEntryModifier::Default, diff --git a/frame/support/src/storage/generator/value.rs b/frame/support/src/storage/generator/value.rs index 55b3487b1324c..4a1fd5c551d3f 100644 --- a/frame/support/src/storage/generator/value.rs +++ b/frame/support/src/storage/generator/value.rs @@ -118,6 +118,30 @@ impl> storage::StorageValue for G { ret } + fn mutate_exists(f: F) -> R + where + F: FnOnce(&mut Option) -> R, + { + Self::try_mutate_exists(|v| Ok::(f(v))) + .expect("`Never` can not be constructed; qed") + } + + fn try_mutate_exists(f: F) -> Result + where + F: FnOnce(&mut Option) -> Result, + { + let mut val = G::from_query_to_optional_value(Self::get()); + + let ret = f(&mut val); + if ret.is_ok() { + match val { + Some(ref val) => Self::put(val), + None => Self::kill(), + } + } + ret + } + fn take() -> G::Query { let key = Self::storage_value_final_key(); let value = unhashed::get(&key); diff --git a/frame/support/src/storage/mod.rs b/frame/support/src/storage/mod.rs index 8c0d6207c3f4d..28f2dee992281 100644 --- a/frame/support/src/storage/mod.rs +++ b/frame/support/src/storage/mod.rs @@ -114,6 +114,12 @@ pub trait StorageValue { /// Mutate the value if closure returns `Ok` fn try_mutate Result>(f: F) -> Result; + /// Mutate the value. Deletes the item if mutated to a `None`. + fn mutate_exists) -> R>(f: F) -> R; + + /// Mutate the value if closure returns `Ok`. Deletes the item if mutated to a `None`. + fn try_mutate_exists) -> Result>(f: F) -> Result; + /// Clear the storage value. fn kill(); diff --git a/frame/support/src/storage/types/value.rs b/frame/support/src/storage/types/value.rs index f145e9fb30414..15290f1b1e085 100644 --- a/frame/support/src/storage/types/value.rs +++ b/frame/support/src/storage/types/value.rs @@ -142,6 +142,18 @@ where >::try_mutate(f) } + /// Mutate the value. Deletes the item if mutated to a `None`. + pub fn mutate_exists) -> R>(f: F) -> R { + >::mutate_exists(f) + } + + /// Mutate the value if closure returns `Ok`. Deletes the item if mutated to a `None`. + pub fn try_mutate_exists) -> Result>( + f: F, + ) -> Result { + >::try_mutate_exists(f) + } + /// Clear the storage value. pub fn kill() { >::kill() From 1e6b8921b771debd18de54aae55787c467baeddd Mon Sep 17 00:00:00 2001 From: Jeeyong Um Date: Sat, 28 Jan 2023 09:09:06 +0900 Subject: [PATCH 341/715] Fix derive PassByInner with generics (#13247) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix derive PassByInner with generics * Update primitives/runtime-interface/proc-macro/src/pass_by/inner.rs --------- Co-authored-by: Bastian Köcher --- primitives/runtime-interface/proc-macro/src/pass_by/inner.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 7a527af129467..7c9bd63aba11d 100644 --- a/primitives/runtime-interface/proc-macro/src/pass_by/inner.rs +++ b/primitives/runtime-interface/proc-macro/src/pass_by/inner.rs @@ -52,7 +52,7 @@ pub fn derive_impl(mut input: DeriveInput) -> Result { #crate_include impl #impl_generics #crate_::pass_by::PassBy for #ident #ty_generics #where_clause { - type PassBy = #crate_::pass_by::Inner<#ident, #inner_ty>; + type PassBy = #crate_::pass_by::Inner; } impl #impl_generics #crate_::pass_by::PassByInner for #ident #ty_generics #where_clause { From ece32a72e934f6fe6705a7d418bbf3e71b4931ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathas=20Concei=C3=A7=C3=A3o?= Date: Fri, 27 Jan 2023 21:16:57 -0300 Subject: [PATCH 342/715] docs: Fix broken documentation links for pallets (#13241) Fixes broken links to `Config` and `Call`, for READMEs the link has been fixed by adding the missing "/pallet" path, and for rust docs we let the compiler figure out the type's link by itself Signed-off-by: Jonathas-Conceicao --- frame/multisig/README.md | 4 ++-- frame/multisig/src/lib.rs | 3 --- frame/nicks/README.md | 4 ++-- frame/proxy/README.md | 4 ++-- frame/sudo/README.md | 4 ++-- frame/utility/README.md | 4 ++-- frame/vesting/README.md | 4 ++-- 7 files changed, 12 insertions(+), 15 deletions(-) diff --git a/frame/multisig/README.md b/frame/multisig/README.md index 4eab00d108204..5f320377d3454 100644 --- a/frame/multisig/README.md +++ b/frame/multisig/README.md @@ -1,8 +1,8 @@ # Multisig Module A module for doing multisig dispatch. -- [`multisig::Config`](https://docs.rs/pallet-multisig/latest/pallet_multisig/trait.Config.html) -- [`Call`](https://docs.rs/pallet-multisig/latest/pallet_multisig/enum.Call.html) +- [`Config`](https://docs.rs/pallet-multisig/latest/pallet_multisig/pallet/trait.Config.html) +- [`Call`](https://docs.rs/pallet-multisig/latest/pallet_multisig/pallet/enum.Call.html) ## Overview diff --git a/frame/multisig/src/lib.rs b/frame/multisig/src/lib.rs index 076a289e06519..03d7ddec6a316 100644 --- a/frame/multisig/src/lib.rs +++ b/frame/multisig/src/lib.rs @@ -39,9 +39,6 @@ //! number of signed origins. //! * `approve_as_multi` - Approve a call from a composite origin. //! * `cancel_as_multi` - Cancel a call from a composite origin. -//! -//! [`Call`]: ./enum.Call.html -//! [`Config`]: ./trait.Config.html // Ensure we're `no_std` when compiling for Wasm. #![cfg_attr(not(feature = "std"), no_std)] diff --git a/frame/nicks/README.md b/frame/nicks/README.md index a2a897b044f10..768043ffb9bf9 100644 --- a/frame/nicks/README.md +++ b/frame/nicks/README.md @@ -1,7 +1,7 @@ # Nicks Module -- [`nicks::Config`](https://docs.rs/pallet-nicks/latest/pallet_nicks/trait.Config.html) -- [`Call`](https://docs.rs/pallet-nicks/latest/pallet_nicks/enum.Call.html) +- [`Config`](https://docs.rs/pallet-nicks/latest/pallet_nicks/pallet/trait.Config.html) +- [`Call`](https://docs.rs/pallet-nicks/latest/pallet_nicks/pallet/enum.Call.html) ## Overview diff --git a/frame/proxy/README.md b/frame/proxy/README.md index 2eb83fab6d727..bfe26d9aefbc4 100644 --- a/frame/proxy/README.md +++ b/frame/proxy/README.md @@ -6,8 +6,8 @@ The accounts to which permission is delegated may be requied to announce the act wish to execute some duration prior to execution happens. In this case, the target account may reject the announcement and in doing so, veto the execution. -- [`proxy::Config`](https://docs.rs/pallet-proxy/latest/pallet_proxy/trait.Config.html) -- [`Call`](https://docs.rs/pallet-proxy/latest/pallet_proxy/enum.Call.html) +- [`Config`](https://docs.rs/pallet-proxy/latest/pallet_proxy/pallet/trait.Config.html) +- [`Call`](https://docs.rs/pallet-proxy/latest/pallet_proxy/pallet/enum.Call.html) ## Overview diff --git a/frame/sudo/README.md b/frame/sudo/README.md index 7342832d2d7a7..886dc5981778d 100644 --- a/frame/sudo/README.md +++ b/frame/sudo/README.md @@ -1,7 +1,7 @@ # Sudo Module -- [`sudo::Config`](https://docs.rs/pallet-sudo/latest/pallet_sudo/trait.Config.html) -- [`Call`](https://docs.rs/pallet-sudo/latest/pallet_sudo/enum.Call.html) +- [`Config`](https://docs.rs/pallet-sudo/latest/pallet_sudo/pallet/trait.Config.html) +- [`Call`](https://docs.rs/pallet-sudo/latest/pallet_sudo/pallet/enum.Call.html) ## Overview diff --git a/frame/utility/README.md b/frame/utility/README.md index 1beeb66733dd4..db19b0cf8cf9e 100644 --- a/frame/utility/README.md +++ b/frame/utility/README.md @@ -1,8 +1,8 @@ # Utility Module A stateless module with helpers for dispatch management which does no re-authentication. -- [`utility::Config`](https://docs.rs/pallet-utility/latest/pallet_utility/trait.Config.html) -- [`Call`](https://docs.rs/pallet-utility/latest/pallet_utility/enum.Call.html) +- [`utility::Config`](https://docs.rs/pallet-utility/latest/pallet_utility/pallet/trait.Config.html) +- [`Call`](https://docs.rs/pallet-utility/latest/pallet_utility/pallet/enum.Call.html) ## Overview diff --git a/frame/vesting/README.md b/frame/vesting/README.md index b19a60c5b6824..1f3744d63592a 100644 --- a/frame/vesting/README.md +++ b/frame/vesting/README.md @@ -1,7 +1,7 @@ # Vesting Module -- [`vesting::Config`](https://docs.rs/pallet-vesting/latest/pallet_vesting/trait.Config.html) -- [`Call`](https://docs.rs/pallet-vesting/latest/pallet_vesting/enum.Call.html) +- [`Config`](https://docs.rs/pallet-vesting/latest/pallet_vesting/pallet/trait.Config.html) +- [`Call`](https://docs.rs/pallet-vesting/latest/pallet_vesting/pallet/enum.Call.html) ## Overview From 0100b3b96984f128a06f9701a3424a3a9cde26fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Sat, 28 Jan 2023 20:10:40 +0100 Subject: [PATCH 343/715] sc-finality-grandpa: Warp proof generation can not expect justifications (#13249) When a node is running with `--blocks-pruning` it will also prunes justifications. So, the warp proof generation can not use `expect` for unwrapping the justification. --- client/cli/src/params/pruning_params.rs | 1 + client/finality-grandpa/src/warp_proof.rs | 6 +----- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/client/cli/src/params/pruning_params.rs b/client/cli/src/params/pruning_params.rs index fd01ba67bab7d..66282fd08848c 100644 --- a/client/cli/src/params/pruning_params.rs +++ b/client/cli/src/params/pruning_params.rs @@ -49,6 +49,7 @@ pub struct PruningParams { /// [default: 256] #[arg(alias = "pruning", long, value_name = "PRUNING_MODE")] pub state_pruning: Option, + /// Specify the blocks pruning mode. /// /// This mode specifies when the block's body (including justifications) diff --git a/client/finality-grandpa/src/warp_proof.rs b/client/finality-grandpa/src/warp_proof.rs index c65a705d3e844..1169083ea1d51 100644 --- a/client/finality-grandpa/src/warp_proof.rs +++ b/client/finality-grandpa/src/warp_proof.rs @@ -135,11 +135,7 @@ impl WarpSyncProof { let justification = blockchain .justifications(header.hash())? .and_then(|just| just.into_justification(GRANDPA_ENGINE_ID)) - .expect( - "header is last in set and contains standard change signal; \ - must have justification; \ - qed.", - ); + .ok_or_else(|| Error::MissingData)?; let justification = GrandpaJustification::::decode(&mut &justification[..])?; From 6c1119016ff6b35e8ea79594edf20c03a39e3740 Mon Sep 17 00:00:00 2001 From: Qinxuan Chen Date: Sun, 29 Jan 2023 03:43:32 +0800 Subject: [PATCH 344/715] update criterion to v0.4.0 (#13142) --- Cargo.lock | 129 ++++++++++++++--------------- bin/node/cli/Cargo.toml | 2 +- bin/node/executor/Cargo.toml | 2 +- client/db/Cargo.toml | 2 +- client/executor/Cargo.toml | 2 +- client/tracing/Cargo.toml | 2 +- client/transaction-pool/Cargo.toml | 2 +- frame/system/Cargo.toml | 2 +- primitives/api/test/Cargo.toml | 2 +- primitives/arithmetic/Cargo.toml | 2 +- primitives/core/Cargo.toml | 4 +- primitives/core/benches/bench.rs | 5 +- primitives/trie/Cargo.toml | 4 +- 13 files changed, 78 insertions(+), 82 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6aafb0e175d98..c075f065fdd90 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -167,6 +167,12 @@ dependencies = [ "libc", ] +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + [[package]] name = "ansi_term" version = "0.12.1" @@ -705,10 +711,7 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" dependencies = [ - "lazy_static", "memchr", - "regex-automata", - "serde", ] [[package]] @@ -914,6 +917,33 @@ dependencies = [ "winapi", ] +[[package]] +name = "ciborium" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c137568cc60b904a7724001b35ce2630fd00d5d84805fbb608ab89509d788f" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "346de753af073cc87b52b2083a506b38ac176a44cfb05497b622e27be899b369" + +[[package]] +name = "ciborium-ll" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213030a2b5a4e0c0892b6652260cf6ccac84827b83a85a534e178e3906c4cf1b" +dependencies = [ + "ciborium-io", + "half", +] + [[package]] name = "cid" version = "0.8.6" @@ -967,13 +997,14 @@ dependencies = [ [[package]] name = "clap" -version = "2.34.0" +version = "3.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" +checksum = "71655c45cb9845d3270c9d6df84ebe72b4dad3c2ba3f7023ad47c144e4e473a5" dependencies = [ "bitflags", + "clap_lex 0.2.4", + "indexmap", "textwrap", - "unicode-width", ] [[package]] @@ -984,7 +1015,7 @@ checksum = "a7db700bc935f9e43e88d00b0850dae18a63773cfbec6d8e070fccf7fef89a39" dependencies = [ "bitflags", "clap_derive", - "clap_lex", + "clap_lex 0.3.0", "is-terminal", "once_cell", "strsim", @@ -1013,6 +1044,15 @@ dependencies = [ "syn", ] +[[package]] +name = "clap_lex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +dependencies = [ + "os_str_bytes", +] + [[package]] name = "clap_lex" version = "0.3.0" @@ -1243,15 +1283,16 @@ dependencies = [ [[package]] name = "criterion" -version = "0.3.6" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b01d6de93b2b6c65e17c634a26653a29d107b3c98c607c765bf38d041531cd8f" +checksum = "e7c76e09c1aae2bc52b3d2f29e13c6572553b30c4aa1b8a49fd70de6412654cb" dependencies = [ + "anes", "atty", "cast", - "clap 2.34.0", + "ciborium", + "clap 3.2.23", "criterion-plot", - "csv", "futures", "itertools", "lazy_static", @@ -1261,7 +1302,6 @@ dependencies = [ "rayon", "regex", "serde", - "serde_cbor", "serde_derive", "serde_json", "tinytemplate", @@ -1271,9 +1311,9 @@ dependencies = [ [[package]] name = "criterion-plot" -version = "0.4.5" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2673cc8207403546f45f5fd319a974b1e6983ad1a3ee7e6041650013be041876" +checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" dependencies = [ "cast", "itertools", @@ -1380,28 +1420,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "csv" -version = "1.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1" -dependencies = [ - "bstr 0.2.17", - "csv-core", - "itoa 0.4.8", - "ryu", - "serde", -] - -[[package]] -name = "csv-core" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" -dependencies = [ - "memchr", -] - [[package]] name = "ctor" version = "0.1.26" @@ -2976,7 +2994,7 @@ checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" dependencies = [ "bytes", "fnv", - "itoa 1.0.5", + "itoa", ] [[package]] @@ -3029,7 +3047,7 @@ dependencies = [ "http-body", "httparse", "httpdate", - "itoa 1.0.5", + "itoa", "pin-project-lite 0.2.9", "socket2", "tokio", @@ -3277,12 +3295,6 @@ dependencies = [ "either", ] -[[package]] -name = "itoa" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" - [[package]] name = "itoa" version = "1.0.5" @@ -5083,7 +5095,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a652d9771a63711fd3c3deb670acfbe5c30a4072e664d7a3bf5a9e1056ac72c3" dependencies = [ "arrayvec 0.7.2", - "itoa 1.0.5", + "itoa", ] [[package]] @@ -7188,7 +7200,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83cd1b99916654a69008fd66b4f9397fbe08e6e51dfe23d4417acf5d3b8cb87c" dependencies = [ "dtoa", - "itoa 1.0.5", + "itoa", "parking_lot 0.12.1", "prometheus-client-derive-text-encode", ] @@ -9380,16 +9392,6 @@ dependencies = [ "serde_derive", ] -[[package]] -name = "serde_cbor" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" -dependencies = [ - "half", - "serde", -] - [[package]] name = "serde_derive" version = "1.0.152" @@ -9407,7 +9409,7 @@ version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883" dependencies = [ - "itoa 1.0.5", + "itoa", "ryu", "serde", ] @@ -10945,12 +10947,9 @@ checksum = "95059e91184749cb66be6dc994f67f182b6d897cb3df74a5bf66b5e709295fd8" [[package]] name = "textwrap" -version = "0.11.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -dependencies = [ - "unicode-width", -] +checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] name = "thiserror" @@ -11024,7 +11023,7 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376" dependencies = [ - "itoa 1.0.5", + "itoa", "serde", "time-core", "time-macros", @@ -11338,9 +11337,9 @@ dependencies = [ [[package]] name = "trie-bench" -version = "0.33.0" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5b26bd2cdd7641c5beb476b314c0cb1f629832bf21a6235f545e2d47bc9d05a" +checksum = "2fbb0a830db7c42ae97ce4e21b30e2cf9dbcc1b4f7853bd1aedad3d806c281d0" dependencies = [ "criterion", "hash-db", diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index b55b35c05652d..c529c7c9b8dfd 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -122,7 +122,7 @@ serde_json = "1.0" regex = "1.6.0" platforms = "2.0" soketto = "0.7.1" -criterion = { version = "0.3.5", features = ["async_tokio"] } +criterion = { version = "0.4.0", features = ["async_tokio"] } tokio = { version = "1.22.0", features = ["macros", "time", "parking_lot"] } tokio-util = { version = "0.7.4", features = ["compat"] } wait-timeout = "0.2" diff --git a/bin/node/executor/Cargo.toml b/bin/node/executor/Cargo.toml index edcc4df9c8176..ffa8d38ee4b34 100644 --- a/bin/node/executor/Cargo.toml +++ b/bin/node/executor/Cargo.toml @@ -26,7 +26,7 @@ sp-tracing = { version = "6.0.0", path = "../../../primitives/tracing" } sp-trie = { version = "7.0.0", path = "../../../primitives/trie" } [dev-dependencies] -criterion = "0.3.0" +criterion = "0.4.0" futures = "0.3.21" wat = "1.0" frame-support = { version = "4.0.0-dev", path = "../../../frame/support" } diff --git a/client/db/Cargo.toml b/client/db/Cargo.toml index a9f5e28c73159..7a62cb1ea0f53 100644 --- a/client/db/Cargo.toml +++ b/client/db/Cargo.toml @@ -36,7 +36,7 @@ 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" +criterion = "0.4.0" kvdb-rocksdb = "0.17.0" rand = "0.8.5" tempfile = "3.1.0" diff --git a/client/executor/Cargo.toml b/client/executor/Cargo.toml index 8bedcd3edcff3..46b72565afefc 100644 --- a/client/executor/Cargo.toml +++ b/client/executor/Cargo.toml @@ -46,7 +46,7 @@ sc-tracing = { version = "4.0.0-dev", path = "../tracing" } tracing-subscriber = "0.2.19" paste = "1.0" regex = "1.6.0" -criterion = "0.3" +criterion = "0.4.0" env_logger = "0.9" num_cpus = "1.13.1" tempfile = "3.3.0" diff --git a/client/tracing/Cargo.toml b/client/tracing/Cargo.toml index be6237a344f52..9312c04e9f6db 100644 --- a/client/tracing/Cargo.toml +++ b/client/tracing/Cargo.toml @@ -39,7 +39,7 @@ sp-runtime = { version = "7.0.0", path = "../../primitives/runtime" } sp-tracing = { version = "6.0.0", path = "../../primitives/tracing" } [dev-dependencies] -criterion = "0.3" +criterion = "0.4.0" [[bench]] name = "bench" diff --git a/client/transaction-pool/Cargo.toml b/client/transaction-pool/Cargo.toml index bbb5ebae440a0..6338f8127aa1c 100644 --- a/client/transaction-pool/Cargo.toml +++ b/client/transaction-pool/Cargo.toml @@ -37,7 +37,7 @@ sp-transaction-pool = { version = "4.0.0-dev", path = "../../primitives/transact [dev-dependencies] array-bytes = "4.1" assert_matches = "1.3.0" -criterion = "0.3" +criterion = "0.4.0" 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/frame/system/Cargo.toml b/frame/system/Cargo.toml index 7f573a9cbd575..5a6c89aae32ea 100644 --- a/frame/system/Cargo.toml +++ b/frame/system/Cargo.toml @@ -26,7 +26,7 @@ sp-version = { version = "5.0.0", default-features = false, path = "../../primit sp-weights = { version = "4.0.0", default-features = false, path = "../../primitives/weights" } [dev-dependencies] -criterion = "0.3.3" +criterion = "0.4.0" sp-externalities = { version = "0.13.0", path = "../../primitives/externalities" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } diff --git a/primitives/api/test/Cargo.toml b/primitives/api/test/Cargo.toml index b3ceb14fe0d66..5b6c144ef3f6b 100644 --- a/primitives/api/test/Cargo.toml +++ b/primitives/api/test/Cargo.toml @@ -25,7 +25,7 @@ trybuild = "1.0.74" rustversion = "1.0.6" [dev-dependencies] -criterion = "0.3.0" +criterion = "0.4.0" futures = "0.3.21" log = "0.4.17" sp-core = { version = "7.0.0", path = "../../core" } diff --git a/primitives/arithmetic/Cargo.toml b/primitives/arithmetic/Cargo.toml index bbb4bbd1776b1..b3fc6abc33ffd 100644 --- a/primitives/arithmetic/Cargo.toml +++ b/primitives/arithmetic/Cargo.toml @@ -26,7 +26,7 @@ static_assertions = "1.1.0" sp-std = { version = "5.0.0", default-features = false, path = "../std" } [dev-dependencies] -criterion = "0.3" +criterion = "0.4.0" primitive-types = "0.12.0" sp-core = { version = "7.0.0", features = ["full_crypto"], path = "../core" } rand = "0.8.5" diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index f9a522178f4c8..5fd838de3538d 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -25,7 +25,7 @@ impl-serde = { version = "0.4.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.2.0", optional = true } -rand = { version = "0.8.5", optional = true, features = ["small_rng"] } +rand = { version = "0.8.5", features = ["small_rng"], optional = true } substrate-bip39 = { version = "0.4.4", optional = true } tiny-bip39 = { version = "1.0.0", optional = true } regex = { version = "1.6.0", optional = true } @@ -60,7 +60,7 @@ sp-runtime-interface = { version = "7.0.0", default-features = false, path = ".. [dev-dependencies] sp-serializer = { version = "4.0.0-dev", path = "../serializer" } rand = "0.8.5" -criterion = "0.3.3" +criterion = "0.4.0" serde_json = "1.0" sp-core-hashing-proc-macro = { version = "5.0.0", path = "./hashing/proc-macro" } diff --git a/primitives/core/benches/bench.rs b/primitives/core/benches/bench.rs index 53421278dca26..77e5bb63fef7a 100644 --- a/primitives/core/benches/bench.rs +++ b/primitives/core/benches/bench.rs @@ -12,10 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#[macro_use] -extern crate criterion; - -use criterion::{black_box, Bencher, BenchmarkId, Criterion}; +use criterion::{black_box, criterion_group, criterion_main, Bencher, BenchmarkId, Criterion}; use sp_core::{ crypto::Pair as _, hashing::{blake2_128, twox_128}, diff --git a/primitives/trie/Cargo.toml b/primitives/trie/Cargo.toml index 78b0b5d1bbda3..1e83a5d6dfec5 100644 --- a/primitives/trie/Cargo.toml +++ b/primitives/trie/Cargo.toml @@ -37,8 +37,8 @@ schnellru = { version = "0.2.1", optional = true } [dev-dependencies] array-bytes = "4.1" -criterion = "0.3.3" -trie-bench = "0.33.0" +criterion = "0.4.0" +trie-bench = "0.34.0" trie-standardmap = "0.15.2" sp-runtime = { version = "7.0.0", path = "../runtime" } From f4caddb2af951cac4ef3fcceb8079aa539f97af9 Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Sun, 29 Jan 2023 13:23:15 -0300 Subject: [PATCH 345/715] fix up template (#13205) --- bin/node-template/pallets/template/Cargo.toml | 6 +++--- bin/node-template/pallets/template/src/mock.rs | 5 ++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/bin/node-template/pallets/template/Cargo.toml b/bin/node-template/pallets/template/Cargo.toml index 6dec5c8da6e5d..f6607b25c4d62 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 = "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-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" } [features] default = ["std"] diff --git a/bin/node-template/pallets/template/src/mock.rs b/bin/node-template/pallets/template/src/mock.rs index 989681fa59a00..91a1bf6ed5fc8 100644 --- a/bin/node-template/pallets/template/src/mock.rs +++ b/bin/node-template/pallets/template/src/mock.rs @@ -1,6 +1,5 @@ use crate as pallet_template; use frame_support::traits::{ConstU16, ConstU64}; -use frame_system as system; use sp_core::H256; use sp_runtime::{ testing::Header, @@ -22,7 +21,7 @@ frame_support::construct_runtime!( } ); -impl system::Config for Test { +impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); type BlockLength = (); @@ -55,5 +54,5 @@ impl pallet_template::Config for Test { // Build genesis storage according to the mock runtime. pub fn new_test_ext() -> sp_io::TestExternalities { - system::GenesisConfig::default().build_storage::().unwrap().into() + frame_system::GenesisConfig::default().build_storage::().unwrap().into() } From fdff2b23009f25dd42d3a12fee6c998864399de3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Sun, 29 Jan 2023 21:56:10 +0100 Subject: [PATCH 346/715] Remove `uncles` related code (#13216) The code was added without any clear usage. The inherent for example is not benchmarked and not used. --- Cargo.lock | 24 - Cargo.toml | 2 - bin/node/cli/Cargo.toml | 2 - bin/node/cli/src/service.rs | 12 +- bin/node/runtime/src/lib.rs | 6 - client/consensus/uncles/Cargo.toml | 19 - client/consensus/uncles/README.md | 3 - client/consensus/uncles/src/lib.rs | 45 -- frame/authorship/Cargo.toml | 2 - frame/authorship/src/lib.rs | 602 +----------------- frame/babe/src/mock.rs | 20 +- frame/grandpa/src/mock.rs | 20 +- frame/im-online/src/lib.rs | 4 - frame/im-online/src/mock.rs | 2 - frame/im-online/src/tests.rs | 5 +- frame/staking/src/mock.rs | 18 +- frame/staking/src/pallet/impls.rs | 10 - frame/staking/src/tests.rs | 9 +- .../asset-tx-payment/src/mock.rs | 14 +- primitives/authorship/Cargo.toml | 30 - primitives/authorship/README.md | 3 - primitives/authorship/src/lib.rs | 101 --- 22 files changed, 47 insertions(+), 906 deletions(-) delete mode 100644 client/consensus/uncles/Cargo.toml delete mode 100644 client/consensus/uncles/README.md delete mode 100644 client/consensus/uncles/src/lib.rs delete mode 100644 primitives/authorship/Cargo.toml delete mode 100644 primitives/authorship/README.md delete mode 100644 primitives/authorship/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index c075f065fdd90..29ddf38328519 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4772,7 +4772,6 @@ dependencies = [ "sc-consensus-babe", "sc-consensus-epochs", "sc-consensus-slots", - "sc-consensus-uncles", "sc-executor", "sc-finality-grandpa", "sc-keystore", @@ -4792,7 +4791,6 @@ dependencies = [ "soketto", "sp-api", "sp-authority-discovery", - "sp-authorship", "sp-blockchain", "sp-consensus", "sp-consensus-babe", @@ -5379,7 +5377,6 @@ dependencies = [ "impl-trait-for-tuples", "parity-scale-codec", "scale-info", - "sp-authorship", "sp-core", "sp-io", "sp-runtime", @@ -8299,16 +8296,6 @@ dependencies = [ "substrate-test-runtime-client", ] -[[package]] -name = "sc-consensus-uncles" -version = "0.10.0-dev" -dependencies = [ - "sc-client-api", - "sp-authorship", - "sp-runtime", - "thiserror", -] - [[package]] name = "sc-executor" version = "0.10.0-dev" @@ -9714,17 +9701,6 @@ dependencies = [ "sp-std", ] -[[package]] -name = "sp-authorship" -version = "4.0.0-dev" -dependencies = [ - "async-trait", - "parity-scale-codec", - "sp-inherents", - "sp-runtime", - "sp-std", -] - [[package]] name = "sp-beefy" version = "4.0.0-dev" diff --git a/Cargo.toml b/Cargo.toml index bb52305162ef1..b004886e83f9a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,7 +32,6 @@ members = [ "client/consensus/manual-seal", "client/consensus/pow", "client/consensus/slots", - "client/consensus/uncles", "client/db", "client/executor", "client/executor/common", @@ -177,7 +176,6 @@ members = [ "primitives/arithmetic", "primitives/arithmetic/fuzzer", "primitives/authority-discovery", - "primitives/authorship", "primitives/beefy", "primitives/block-builder", "primitives/blockchain", diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index c529c7c9b8dfd..9ec06d9d9cab1 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -52,7 +52,6 @@ sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } 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 = "7.0.0", path = "../../../primitives/keyring" } sp-keystore = { version = "0.13.0", path = "../../../primitives/keystore" } @@ -71,7 +70,6 @@ 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" } grandpa = { version = "0.10.0-dev", package = "sc-finality-grandpa", path = "../../../client/finality-grandpa" } sc-rpc = { version = "4.0.0-dev", path = "../../../client/rpc" } sc-basic-authorship = { version = "0.10.0-dev", path = "../../../client/basic-authorship" } diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs index e329087947c98..b1e9360b4a6c4 100644 --- a/bin/node/cli/src/service.rs +++ b/bin/node/cli/src/service.rs @@ -222,10 +222,7 @@ pub fn new_partial( slot_duration, ); - let uncles = - sp_authorship::InherentDataProvider::<::Header>::check_inherents(); - - Ok((slot, timestamp, uncles)) + Ok((slot, timestamp)) }, &task_manager.spawn_essential_handle(), config.prometheus_registry(), @@ -440,11 +437,6 @@ pub fn new_full_base( create_inherent_data_providers: move |parent, ()| { let client_clone = client_clone.clone(); async move { - let uncles = sc_consensus_uncles::create_uncles_inherent_data_provider( - &*client_clone, - parent, - )?; - let timestamp = sp_timestamp::InherentDataProvider::from_system_time(); let slot = @@ -459,7 +451,7 @@ pub fn new_full_base( &parent, )?; - Ok((slot, timestamp, uncles, storage_proof)) + Ok((slot, timestamp, storage_proof)) } }, force_authoring, diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index bd8a395d15243..30165cdb6f6c7 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -488,14 +488,8 @@ impl pallet_timestamp::Config for Runtime { type WeightInfo = pallet_timestamp::weights::SubstrateWeight; } -parameter_types! { - pub const UncleGenerations: BlockNumber = 5; -} - impl pallet_authorship::Config for Runtime { type FindAuthor = pallet_session::FindAccountFromAuthorIndex; - type UncleGenerations = UncleGenerations; - type FilterUncle = (); type EventHandler = (Staking, ImOnline); } diff --git a/client/consensus/uncles/Cargo.toml b/client/consensus/uncles/Cargo.toml deleted file mode 100644 index 0be48659f9c77..0000000000000 --- a/client/consensus/uncles/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "sc-consensus-uncles" -version = "0.10.0-dev" -authors = ["Parity Technologies "] -description = "Generic uncle inclusion utilities for consensus" -edition = "2021" -license = "GPL-3.0-or-later WITH Classpath-exception-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"] - -[dependencies] -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 = "7.0.0", path = "../../../primitives/runtime" } diff --git a/client/consensus/uncles/README.md b/client/consensus/uncles/README.md deleted file mode 100644 index 1b6fed5b9772a..0000000000000 --- a/client/consensus/uncles/README.md +++ /dev/null @@ -1,3 +0,0 @@ -Uncles functionality for Substrate. - -License: GPL-3.0-or-later WITH Classpath-exception-2.0 \ No newline at end of file diff --git a/client/consensus/uncles/src/lib.rs b/client/consensus/uncles/src/lib.rs deleted file mode 100644 index d03c2f8aa6b49..0000000000000 --- a/client/consensus/uncles/src/lib.rs +++ /dev/null @@ -1,45 +0,0 @@ -// 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 . - -//! Uncles functionality for Substrate. - -use sc_client_api::ProvideUncles; -use sp_runtime::{generic::BlockId, traits::Block as BlockT}; - -#[derive(Debug, thiserror::Error)] -pub enum Error { - #[error("Could not retrieve the block hash for block id: {0:?}")] - NoHashForBlockId(BlockId), -} - -/// Maximum uncles generations we may provide to the runtime. -const MAX_UNCLE_GENERATIONS: u32 = 8; - -/// Create a new [`sp_authorship::InherentDataProvider`] at the given block. -pub fn create_uncles_inherent_data_provider( - client: &C, - parent: B::Hash, -) -> Result, sc_client_api::blockchain::Error> -where - B: BlockT, - C: ProvideUncles, -{ - let uncles = client.uncles(parent, MAX_UNCLE_GENERATIONS.into())?; - - Ok(sp_authorship::InherentDataProvider::new(uncles)) -} diff --git a/frame/authorship/Cargo.toml b/frame/authorship/Cargo.toml index 84d00a6fbc54e..a205c51f9c62d 100644 --- a/frame/authorship/Cargo.toml +++ b/frame/authorship/Cargo.toml @@ -20,7 +20,6 @@ impl-trait-for-tuples = "0.2.2" 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 = "7.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } @@ -35,7 +34,6 @@ std = [ "frame-support/std", "frame-system/std", "scale-info/std", - "sp-authorship/std", "sp-runtime/std", "sp-std/std", ] diff --git a/frame/authorship/src/lib.rs b/frame/authorship/src/lib.rs index 4065472d92368..b5568a6acf77c 100644 --- a/frame/authorship/src/lib.rs +++ b/frame/authorship/src/lib.rs @@ -17,36 +17,12 @@ //! Authorship tracking for FRAME runtimes. //! -//! This tracks the current author of the block and recent uncles. +//! This tracks the current author of the block. #![cfg_attr(not(feature = "std"), no_std)] -use codec::{Decode, Encode, MaxEncodedLen}; -use frame_support::{ - dispatch, - traits::{Defensive, FindAuthor, Get, VerifySeal}, - BoundedSlice, BoundedVec, -}; -use sp_authorship::{InherentError, UnclesInherentData, INHERENT_IDENTIFIER}; -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) - } -} +use frame_support::traits::FindAuthor; +use sp_std::prelude::*; pub use pallet::*; @@ -56,87 +32,8 @@ pub use pallet::*; pub trait EventHandler { /// Note that the given account ID is the author of the current block. fn note_author(author: Author); - - /// Note that the given account ID authored the given uncle, and how many - /// blocks older than the current block it is (age >= 0, so siblings are allowed) - fn note_uncle(author: Author, age: BlockNumber); -} - -/// Additional filtering on uncles that pass preliminary ancestry checks. -/// -/// This should do work such as checking seals -pub trait FilterUncle { - /// An accumulator of data about uncles included. - /// - /// In practice, this is used to validate uncles against others in the same block. - type Accumulator: Default; - - /// Do additional filtering on a seal-checked uncle block, with the accumulated - /// filter. - fn filter_uncle( - header: &Header, - acc: &mut Self::Accumulator, - ) -> Result, &'static str>; } -impl FilterUncle for () { - type Accumulator = (); - fn filter_uncle(_: &H, _acc: &mut Self::Accumulator) -> Result, &'static str> { - Ok(None) - } -} - -/// A filter on uncles which verifies seals and does no additional checks. -/// This is well-suited to consensus modes such as PoW where the cost of -/// equivocating is high. -pub struct SealVerify(sp_std::marker::PhantomData); - -impl> FilterUncle for SealVerify { - type Accumulator = (); - - fn filter_uncle(header: &Header, _acc: &mut ()) -> Result, &'static str> { - T::verify_seal(header) - } -} - -/// A filter on uncles which verifies seals and ensures that there is only -/// one uncle included per author per height. -/// -/// This does O(n log n) work in the number of uncles included. -pub struct OnePerAuthorPerHeight(sp_std::marker::PhantomData<(T, N)>); - -impl FilterUncle for OnePerAuthorPerHeight -where - Header: HeaderT + PartialEq, - Header::Number: Ord, - Author: Clone + PartialEq + Ord, - T: VerifySeal, -{ - type Accumulator = BTreeSet<(Header::Number, Author)>; - - fn filter_uncle( - header: &Header, - acc: &mut Self::Accumulator, - ) -> Result, &'static str> { - let author = T::verify_seal(header)?; - let number = header.number(); - - if let Some(ref author) = author { - if !acc.insert((*number, author.clone())) { - return Err("more than one uncle per number per author included") - } - } - - Ok(author) - } -} - -#[derive(Encode, Decode, sp_runtime::RuntimeDebug, scale_info::TypeInfo, MaxEncodedLen)] -#[cfg_attr(any(feature = "std", test), derive(PartialEq))] -enum UncleEntryItem { - InclusionHeight(BlockNumber), - Uncle(Hash, Option), -} #[frame_support::pallet] pub mod pallet { use super::*; @@ -147,25 +44,6 @@ pub mod pallet { pub trait Config: frame_system::Config { /// Find the author of a block. type FindAuthor: FindAuthor; - /// The number of blocks back we should accept uncles. - /// This means that we will deal with uncle-parents that are - /// `UncleGenerations + 1` before `now`. - #[pallet::constant] - type UncleGenerations: Get; - /// A filter for uncles within a block. This is for implementing - /// further constraints on what uncles can be included, other than their ancestry. - /// - /// For PoW, as long as the seals are checked, there is no need to use anything - /// but the `VerifySeal` implementation as the filter. This is because the cost of making - /// many equivocating uncles is high. - /// - /// For PoS, there is no such limitation, so a further constraint must be imposed - /// beyond a seal check in order to prevent an arbitrary number of - /// equivocating uncles from being included. - /// - /// The `OnePerAuthorPerHeight` filter is good for many slot-based PoS - /// engines. - type FilterUncle: FilterUncle; /// An event handler for authored blocks. type EventHandler: EventHandler; } @@ -176,16 +54,7 @@ pub mod pallet { #[pallet::hooks] impl Hooks> for Pallet { - fn on_initialize(now: T::BlockNumber) -> Weight { - let uncle_generations = T::UncleGenerations::get(); - // prune uncles that are older than the allowed number of generations. - if uncle_generations <= now { - let minimum_height = now - uncle_generations; - Self::prune_old_uncles(minimum_height) - } - - >::put(false); - + fn on_initialize(_: T::BlockNumber) -> Weight { if let Some(author) = Self::author() { T::EventHandler::note_author(author); } @@ -196,125 +65,12 @@ pub mod pallet { fn on_finalize(_: T::BlockNumber) { // ensure we never go to trie with these values. >::kill(); - >::kill(); } } - #[pallet::storage] - /// Uncles - pub(super) type Uncles = StorageValue< - _, - BoundedVec, MaxUncleEntryItems>, - ValueQuery, - >; - #[pallet::storage] /// Author of current block. pub(super) type Author = StorageValue<_, T::AccountId, OptionQuery>; - - #[pallet::storage] - /// Whether uncles were already set in this block. - pub(super) type DidSetUncles = StorageValue<_, bool, ValueQuery>; - - #[pallet::error] - pub enum Error { - /// The uncle parent not in the chain. - InvalidUncleParent, - /// Uncles already set in the block. - UnclesAlreadySet, - /// Too many uncles. - TooManyUncles, - /// The uncle is genesis. - GenesisUncle, - /// The uncle is too high in chain. - TooHighUncle, - /// The uncle is already included. - UncleAlreadyIncluded, - /// The uncle isn't recent enough to be included. - OldUncle, - } - - #[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)?; - ensure!(new_uncles.len() <= MAX_UNCLES, Error::::TooManyUncles); - - if >::get() { - return Err(Error::::UnclesAlreadySet.into()) - } - >::put(true); - - Self::verify_and_import_uncles(new_uncles) - } - } - - #[pallet::inherent] - impl ProvideInherent for Pallet { - type Call = Call; - type Error = InherentError; - const INHERENT_IDENTIFIER: InherentIdentifier = INHERENT_IDENTIFIER; - - fn create_inherent(data: &InherentData) -> Option { - let uncles = data.uncles().unwrap_or_default(); - let mut new_uncles = Vec::new(); - - if !uncles.is_empty() { - let prev_uncles = >::get(); - let mut existing_hashes: Vec<_> = prev_uncles - .into_iter() - .filter_map(|entry| match entry { - UncleEntryItem::InclusionHeight(_) => None, - UncleEntryItem::Uncle(h, _) => Some(h), - }) - .collect(); - - let mut acc: >::Accumulator = - Default::default(); - - for uncle in uncles { - match Self::verify_uncle(&uncle, &existing_hashes, &mut acc) { - Ok(_) => { - let hash = uncle.hash(); - new_uncles.push(uncle); - existing_hashes.push(hash); - - if new_uncles.len() == MAX_UNCLES { - break - } - }, - Err(_) => { - // skip this uncle - }, - } - } - } - - if new_uncles.is_empty() { - None - } else { - Some(Call::set_uncles { new_uncles }) - } - } - - fn check_inherent( - call: &Self::Call, - _data: &InherentData, - ) -> result::Result<(), Self::Error> { - match call { - Call::set_uncles { ref new_uncles } if new_uncles.len() > MAX_UNCLES => - Err(InherentError::Uncles(Error::::TooManyUncles.as_str().into())), - _ => Ok(()), - } - } - - fn is_inherent(call: &Self::Call) -> bool { - matches!(call, Call::set_uncles { .. }) - } - } } impl Pallet { @@ -323,7 +79,7 @@ impl Pallet { /// This is safe to invoke in `on_initialize` implementations, as well /// as afterwards. pub fn author() -> Option { - // Check the memoized storage value. + // Check the memorized storage value. if let Some(author) = >::get() { return Some(author) } @@ -335,113 +91,22 @@ impl Pallet { a }) } - - fn verify_and_import_uncles(new_uncles: Vec) -> dispatch::DispatchResult { - let now = >::block_number(); - - let mut uncles = >::get(); - 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(); - - for uncle in new_uncles { - let prev_uncles = uncles.iter().filter_map(|entry| match entry { - UncleEntryItem::InclusionHeight(_) => None, - UncleEntryItem::Uncle(h, _) => Some(h), - }); - let maybe_author = Self::verify_uncle(&uncle, prev_uncles, &mut acc)?; - let hash = uncle.hash(); - - if let Some(author) = maybe_author.clone() { - T::EventHandler::note_uncle(author, now - *uncle.number()); - } - 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); - Ok(()) - } - - fn verify_uncle<'a, I: IntoIterator>( - uncle: &T::Header, - existing_uncles: I, - accumulator: &mut >::Accumulator, - ) -> Result, dispatch::DispatchError> { - let now = >::block_number(); - - let (minimum_height, maximum_height) = { - let uncle_generations = T::UncleGenerations::get(); - let min = now.saturating_sub(uncle_generations); - - (min, now) - }; - - let hash = uncle.hash(); - - if uncle.number() < &One::one() { - return Err(Error::::GenesisUncle.into()) - } - - if uncle.number() > &maximum_height { - return Err(Error::::TooHighUncle.into()) - } - - { - 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()) - } - } - - if uncle.number() < &minimum_height { - return Err(Error::::OldUncle.into()) - } - - let duplicate = existing_uncles.into_iter().any(|h| *h == hash); - let in_chain = >::block_hash(uncle.number()) == hash; - - if duplicate || in_chain { - return Err(Error::::UncleAlreadyIncluded.into()) - } - - // check uncle validity. - T::FilterUncle::filter_uncle(uncle, accumulator).map_err(Into::into) - } - - fn prune_old_uncles(minimum_height: T::BlockNumber) { - let uncles = >::get(); - let prune_entries = uncles.iter().take_while(|item| match item { - UncleEntryItem::Uncle(_, _) => true, - 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(pruned_uncles); - } } #[cfg(test)] mod tests { use super::*; use crate as pallet_authorship; + use codec::{Decode, Encode}; use frame_support::{ - traits::{ConstU32, ConstU64, OnFinalize, OnInitialize}, + traits::{ConstU32, ConstU64}, ConsensusEngineId, }; use sp_core::H256; use sp_runtime::{ generic::DigestItem, testing::Header, - traits::{BlakeTwo256, IdentityLookup}, + traits::{BlakeTwo256, Header as HeaderT, IdentityLookup}, }; type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; @@ -454,7 +119,7 @@ mod tests { UncheckedExtrinsic = UncheckedExtrinsic, { System: frame_system::{Pallet, Call, Config, Storage, Event}, - Authorship: pallet_authorship::{Pallet, Call, Storage, Inherent}, + Authorship: pallet_authorship::{Pallet, Storage}, } ); @@ -487,8 +152,6 @@ mod tests { impl pallet::Config for Test { type FindAuthor = AuthorGiven; - type UncleGenerations = ConstU64<5>; - type FilterUncle = SealVerify; type EventHandler = (); } @@ -511,34 +174,6 @@ mod tests { } } - pub struct VerifyBlock; - - impl VerifySeal for VerifyBlock { - fn verify_seal(header: &Header) -> Result, &'static str> { - let pre_runtime_digests = header.digest.logs.iter().filter_map(|d| d.as_pre_runtime()); - let seals = header.digest.logs.iter().filter_map(|d| d.as_seal()); - - let author = - AuthorGiven::find_author(pre_runtime_digests).ok_or_else(|| "no author")?; - - for (id, mut seal) in seals { - if id == TEST_ID { - match u64::decode(&mut seal) { - Err(_) => return Err("wrong seal"), - Ok(a) => { - if a != author { - return Err("wrong author in seal") - } - break - }, - } - } - } - - Ok(Some(author)) - } - } - fn seal_header(mut header: Header, author: u64) -> Header { { let digest = header.digest_mut(); @@ -558,196 +193,6 @@ mod tests { t.into() } - #[test] - fn prune_old_uncles_works() { - use UncleEntryItem::*; - new_test_ext().execute_with(|| { - let hash = Default::default(); - let author = Default::default(); - let uncles = vec![ - InclusionHeight(1u64), - Uncle(hash, Some(author)), - Uncle(hash, None), - Uncle(hash, None), - InclusionHeight(2u64), - Uncle(hash, None), - InclusionHeight(3u64), - Uncle(hash, None), - ]; - let uncles = BoundedVec::try_from(uncles).unwrap(); - - ::Uncles::put(uncles); - Authorship::prune_old_uncles(3); - - let uncles = ::Uncles::get(); - assert_eq!(uncles, vec![InclusionHeight(3u64), Uncle(hash, None)]); - }) - } - - #[test] - fn rejects_bad_uncles() { - new_test_ext().execute_with(|| { - let author_a = 69; - - struct CanonChain { - inner: Vec

, - } - - impl CanonChain { - fn best_hash(&self) -> H256 { - self.inner.last().unwrap().hash() - } - - fn canon_hash(&self, index: usize) -> H256 { - self.inner[index].hash() - } - - fn header(&self, index: usize) -> &Header { - &self.inner[index] - } - - fn push(&mut self, header: Header) { - self.inner.push(header) - } - } - - let mut canon_chain = CanonChain { - inner: vec![seal_header( - create_header(0, Default::default(), Default::default()), - 999, - )], - }; - - let initialize_block = |number, hash: H256| { - System::reset_events(); - System::initialize(&number, &hash, &Default::default()) - }; - - for number in 1..8 { - initialize_block(number, canon_chain.best_hash()); - let header = seal_header(System::finalize(), author_a); - canon_chain.push(header); - } - - // initialize so system context is set up correctly. - initialize_block(8, canon_chain.best_hash()); - - // 2 of the same uncle at once - { - let uncle_a = seal_header( - create_header(3, canon_chain.canon_hash(2), [1; 32].into()), - author_a, - ); - assert_eq!( - Authorship::verify_and_import_uncles(vec![uncle_a.clone(), uncle_a.clone()]), - Err(Error::::UncleAlreadyIncluded.into()), - ); - } - - // 2 of the same uncle at different times. - { - let uncle_a = seal_header( - create_header(3, canon_chain.canon_hash(2), [1; 32].into()), - author_a, - ); - - assert!(Authorship::verify_and_import_uncles(vec![uncle_a.clone()]).is_ok()); - - assert_eq!( - Authorship::verify_and_import_uncles(vec![uncle_a.clone()]), - Err(Error::::UncleAlreadyIncluded.into()), - ); - } - - // same uncle as ancestor. - { - let uncle_clone = canon_chain.header(5).clone(); - - assert_eq!( - Authorship::verify_and_import_uncles(vec![uncle_clone]), - Err(Error::::UncleAlreadyIncluded.into()), - ); - } - - // uncle without valid seal. - { - let unsealed = create_header(3, canon_chain.canon_hash(2), [2; 32].into()); - assert_eq!( - Authorship::verify_and_import_uncles(vec![unsealed]), - Err("no author".into()), - ); - } - - // old uncles can't get in. - { - assert_eq!(System::block_number(), 8); - - let gen_2 = seal_header( - create_header(2, canon_chain.canon_hash(1), [3; 32].into()), - author_a, - ); - - assert_eq!( - Authorship::verify_and_import_uncles(vec![gen_2]), - Err(Error::::OldUncle.into()), - ); - } - - // siblings are also allowed - { - let other_8 = seal_header( - create_header(8, canon_chain.canon_hash(7), [1; 32].into()), - author_a, - ); - - assert!(Authorship::verify_and_import_uncles(vec![other_8]).is_ok()); - } - }); - } - - #[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(RuntimeOrigin::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(|| { @@ -762,33 +207,4 @@ mod tests { assert_eq!(Authorship::author(), Some(author)); }); } - - #[test] - fn one_uncle_per_author_per_number() { - type Filter = OnePerAuthorPerHeight; - - let author_a = 42; - let author_b = 43; - - let mut acc: >::Accumulator = Default::default(); - let header_a1 = seal_header(create_header(1, Default::default(), [1; 32].into()), author_a); - let header_b1 = seal_header(create_header(1, Default::default(), [1; 32].into()), author_b); - - let header_a2_1 = - seal_header(create_header(2, Default::default(), [1; 32].into()), author_a); - let header_a2_2 = - seal_header(create_header(2, Default::default(), [2; 32].into()), author_a); - - let mut check_filter = move |uncle| Filter::filter_uncle(uncle, &mut acc); - - // same height, different author is OK. - assert_eq!(check_filter(&header_a1), Ok(Some(author_a))); - assert_eq!(check_filter(&header_b1), Ok(Some(author_b))); - - // same author, different height. - assert_eq!(check_filter(&header_a2_1), Ok(Some(author_a))); - - // same author, same height (author a, height 2) - assert!(check_filter(&header_a2_2).is_err()); - } } diff --git a/frame/babe/src/mock.rs b/frame/babe/src/mock.rs index abae1b7e33157..b09dc29f6d60a 100644 --- a/frame/babe/src/mock.rs +++ b/frame/babe/src/mock.rs @@ -52,15 +52,15 @@ frame_support::construct_runtime!( NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic, { - System: frame_system::{Pallet, Call, Config, Storage, Event}, - Authorship: pallet_authorship::{Pallet, Call, Storage, Inherent}, - Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, - Historical: pallet_session_historical::{Pallet}, - Offences: pallet_offences::{Pallet, Storage, Event}, - Babe: pallet_babe::{Pallet, Call, Storage, Config, ValidateUnsigned}, - Staking: pallet_staking::{Pallet, Call, Storage, Config, Event}, - Session: pallet_session::{Pallet, Call, Storage, Event, Config}, - Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent}, + System: frame_system, + Authorship: pallet_authorship, + Balances: pallet_balances, + Historical: pallet_session_historical, + Offences: pallet_offences, + Babe: pallet_babe, + Staking: pallet_staking, + Session: pallet_session, + Timestamp: pallet_timestamp, } ); @@ -124,8 +124,6 @@ impl pallet_session::historical::Config for Test { impl pallet_authorship::Config for Test { type FindAuthor = pallet_session::FindAccountFromAuthorIndex; - type UncleGenerations = ConstU64<0>; - type FilterUncle = (); type EventHandler = (); } diff --git a/frame/grandpa/src/mock.rs b/frame/grandpa/src/mock.rs index c618705af0651..54f34008abc56 100644 --- a/frame/grandpa/src/mock.rs +++ b/frame/grandpa/src/mock.rs @@ -51,15 +51,15 @@ frame_support::construct_runtime!( NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic, { - System: frame_system::{Pallet, Call, Config, Storage, Event}, - Authorship: pallet_authorship::{Pallet, Call, Storage, Inherent}, - 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}, - Grandpa: pallet_grandpa::{Pallet, Call, Storage, Config, Event, ValidateUnsigned}, - Offences: pallet_offences::{Pallet, Storage, Event}, - Historical: pallet_session_historical::{Pallet}, + System: frame_system, + Authorship: pallet_authorship, + Timestamp: pallet_timestamp, + Balances: pallet_balances, + Staking: pallet_staking, + Session: pallet_session, + Grandpa: pallet_grandpa, + Offences: pallet_offences, + Historical: pallet_session_historical, } ); @@ -129,8 +129,6 @@ impl pallet_session::historical::Config for Test { impl pallet_authorship::Config for Test { type FindAuthor = (); - type UncleGenerations = ConstU64<0>; - type FilterUncle = (); type EventHandler = (); } diff --git a/frame/im-online/src/lib.rs b/frame/im-online/src/lib.rs index f23e610a4874d..8c1f46978e8bc 100644 --- a/frame/im-online/src/lib.rs +++ b/frame/im-online/src/lib.rs @@ -607,10 +607,6 @@ impl fn note_author(author: ValidatorId) { Self::note_authorship(author); } - - fn note_uncle(author: ValidatorId, _age: T::BlockNumber) { - Self::note_authorship(author); - } } impl Pallet { diff --git a/frame/im-online/src/mock.rs b/frame/im-online/src/mock.rs index bcb13fa1be837..783e68dfede9f 100644 --- a/frame/im-online/src/mock.rs +++ b/frame/im-online/src/mock.rs @@ -169,8 +169,6 @@ impl pallet_session::historical::Config for Runtime { impl pallet_authorship::Config for Runtime { type FindAuthor = (); - type UncleGenerations = ConstU64<5>; - type FilterUncle = (); type EventHandler = ImOnline; } diff --git a/frame/im-online/src/tests.rs b/frame/im-online/src/tests.rs index 366119278d836..2c026f7176b65 100644 --- a/frame/im-online/src/tests.rs +++ b/frame/im-online/src/tests.rs @@ -308,11 +308,10 @@ fn should_mark_online_validator_when_block_is_authored() { // when ImOnline::note_author(1); - ImOnline::note_uncle(2, 0); // then assert!(ImOnline::is_online(0)); - assert!(ImOnline::is_online(1)); + assert!(!ImOnline::is_online(1)); assert!(!ImOnline::is_online(2)); }); } @@ -338,7 +337,7 @@ fn should_not_send_a_report_if_already_online() { assert_eq!(Session::current_index(), 2); assert_eq!(Session::validators(), vec![1, 2, 3]); ImOnline::note_author(2); - ImOnline::note_uncle(3, 0); + ImOnline::note_author(3); // when UintAuthorityId::set_all_keys(vec![1, 2, 3]); diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index ad27a82910a6f..30db036d00056 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -91,14 +91,14 @@ frame_support::construct_runtime!( NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic, { - System: frame_system::{Pallet, Call, Config, Storage, Event}, - Authorship: pallet_authorship::{Pallet, Call, Storage, Inherent}, - 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}, - Historical: pallet_session::historical::{Pallet, Storage}, - VoterBagsList: pallet_bags_list::::{Pallet, Call, Storage, Event}, + System: frame_system, + Authorship: pallet_authorship, + Timestamp: pallet_timestamp, + Balances: pallet_balances, + Staking: pallet_staking, + Session: pallet_session, + Historical: pallet_session::historical, + VoterBagsList: pallet_bags_list::, } ); @@ -182,8 +182,6 @@ impl pallet_session::historical::Config for Test { } impl pallet_authorship::Config for Test { type FindAuthor = Author11; - type UncleGenerations = ConstU64<0>; - type FilterUncle = (); type EventHandler = Pallet; } diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 7af9b0aaaa04a..e59c2c5a0620e 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -1217,8 +1217,6 @@ impl historical::SessionManager pallet_authorship::EventHandler for Pallet where T: Config + pallet_authorship::Config + pallet_session::Config, @@ -1226,14 +1224,6 @@ where fn note_author(author: T::AccountId) { Self::reward_by_ids(vec![(author, 20)]) } - 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"); - } - } } /// This is intended to be used with `FilterHistoricalOffences`. diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 9635717d4cf5d..e200f621b3742 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -2237,9 +2237,7 @@ fn reward_from_authorship_event_handler_works() { assert_eq!(>::author(), Some(11)); Pallet::::note_author(11); - Pallet::::note_uncle(21, 1); - // Rewarding the same two times works. - Pallet::::note_uncle(11, 1); + Pallet::::note_author(11); // Not mandatory but must be coherent with rewards assert_eq_uvec!(Session::validators(), vec![11, 21]); @@ -2248,10 +2246,7 @@ fn reward_from_authorship_event_handler_works() { // 11 is rewarded as a block producer and uncle referencer and uncle producer assert_eq!( ErasRewardPoints::::get(active_era()), - EraRewardPoints { - individual: vec![(11, 20 + 2 * 2 + 1), (21, 1)].into_iter().collect(), - total: 26, - }, + EraRewardPoints { individual: vec![(11, 20 * 2)].into_iter().collect(), total: 40 }, ); }) } diff --git a/frame/transaction-payment/asset-tx-payment/src/mock.rs b/frame/transaction-payment/asset-tx-payment/src/mock.rs index ddb02f5a611ff..60fb2e6c5e03e 100644 --- a/frame/transaction-payment/asset-tx-payment/src/mock.rs +++ b/frame/transaction-payment/asset-tx-payment/src/mock.rs @@ -45,12 +45,12 @@ frame_support::construct_runtime!( 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, Event}, - Assets: pallet_assets::{Pallet, Call, Storage, Event}, - Authorship: pallet_authorship::{Pallet, Call, Storage}, - AssetTxPayment: pallet_asset_tx_payment::{Pallet, Event}, + System: system, + Balances: pallet_balances, + TransactionPayment: pallet_transaction_payment, + Assets: pallet_assets, + Authorship: pallet_authorship, + AssetTxPayment: pallet_asset_tx_payment, } ); @@ -187,8 +187,6 @@ impl FindAuthor for HardcodedAuthor { impl pallet_authorship::Config for Runtime { type FindAuthor = HardcodedAuthor; - type UncleGenerations = (); - type FilterUncle = (); type EventHandler = (); } diff --git a/primitives/authorship/Cargo.toml b/primitives/authorship/Cargo.toml deleted file mode 100644 index 31ea3b2d4c8f3..0000000000000 --- a/primitives/authorship/Cargo.toml +++ /dev/null @@ -1,30 +0,0 @@ -[package] -name = "sp-authorship" -version = "4.0.0-dev" -authors = ["Parity Technologies "] -description = "Authorship primitives" -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"] - -[dependencies] -async-trait = { version = "0.1.57", optional = true } -codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } -sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../inherents" } -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" ] -std = [ - "async-trait", - "codec/std", - "sp-inherents/std", - "sp-runtime/std", - "sp-std/std", -] diff --git a/primitives/authorship/README.md b/primitives/authorship/README.md deleted file mode 100644 index 1aa1805cfc5e7..0000000000000 --- a/primitives/authorship/README.md +++ /dev/null @@ -1,3 +0,0 @@ -Authorship Primitives - -License: Apache-2.0 \ No newline at end of file diff --git a/primitives/authorship/src/lib.rs b/primitives/authorship/src/lib.rs deleted file mode 100644 index 6ff6607a896cc..0000000000000 --- a/primitives/authorship/src/lib.rs +++ /dev/null @@ -1,101 +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. - -//! Authorship Primitives - -#![cfg_attr(not(feature = "std"), no_std)] - -use sp_std::{prelude::*, result::Result}; - -#[cfg(feature = "std")] -use codec::Decode; -use codec::Encode; -use sp_inherents::{Error, InherentData, InherentIdentifier, IsFatalError}; -use sp_runtime::{traits::Header as HeaderT, RuntimeString}; - -/// The identifier for the `uncles` inherent. -pub const INHERENT_IDENTIFIER: InherentIdentifier = *b"uncles00"; - -/// Errors that can occur while checking the authorship inherent. -#[derive(Encode, sp_runtime::RuntimeDebug)] -#[cfg_attr(feature = "std", derive(Decode))] -pub enum InherentError { - Uncles(RuntimeString), -} - -impl IsFatalError for InherentError { - fn is_fatal_error(&self) -> bool { - match self { - InherentError::Uncles(_) => true, - } - } -} - -/// Auxiliary trait to extract uncles inherent data. -pub trait UnclesInherentData { - /// Get uncles. - fn uncles(&self) -> Result, Error>; -} - -impl UnclesInherentData for InherentData { - fn uncles(&self) -> Result, Error> { - Ok(self.get_data(&INHERENT_IDENTIFIER)?.unwrap_or_default()) - } -} - -/// Provider for inherent data. -#[cfg(feature = "std")] -pub struct InherentDataProvider { - uncles: Vec, -} - -#[cfg(feature = "std")] -impl InherentDataProvider { - /// Create a new inherent data provider with the given `uncles`. - pub fn new(uncles: Vec) -> Self { - InherentDataProvider { uncles } - } - - /// Create a new instance that is usable for checking inherents. - /// - /// This will always return an empty vec of uncles. - pub fn check_inherents() -> Self { - Self { uncles: Vec::new() } - } -} - -#[cfg(feature = "std")] -#[async_trait::async_trait] -impl sp_inherents::InherentDataProvider for InherentDataProvider { - async fn provide_inherent_data(&self, inherent_data: &mut InherentData) -> Result<(), Error> { - inherent_data.put_data(INHERENT_IDENTIFIER, &self.uncles) - } - - async fn try_handle_error( - &self, - identifier: &InherentIdentifier, - mut error: &[u8], - ) -> Option> { - if *identifier != INHERENT_IDENTIFIER { - return None - } - - let error = InherentError::decode(&mut error).ok()?; - - Some(Err(Error::Application(Box::from(format!("{:?}", error))))) - } -} From a9c4334d96cbb63aff8e3141a5b3dcad8c636bb7 Mon Sep 17 00:00:00 2001 From: Jeeyong Um Date: Mon, 30 Jan 2023 14:32:09 +0900 Subject: [PATCH 347/715] Implement RIType traits for u8 array with an arbitrary size (#13256) --- primitives/runtime-interface/src/impls.rs | 115 +++++++++------------- 1 file changed, 48 insertions(+), 67 deletions(-) diff --git a/primitives/runtime-interface/src/impls.rs b/primitives/runtime-interface/src/impls.rs index e801931c306cf..e311b01dbefcf 100644 --- a/primitives/runtime-interface/src/impls.rs +++ b/primitives/runtime-interface/src/impls.rs @@ -276,84 +276,65 @@ impl IntoFFIValue for [T] { } } -/// Implement the traits for the `[u8; N]` arrays, where `N` is the input to this macro. -macro_rules! impl_traits_for_arrays { - ( - $( - $n:expr - ),* - $(,)? - ) => { - $( - /// The type is passed as `u32`. - /// - /// The `u32` is the pointer to the array. - impl RIType for [u8; $n] { - type FFIType = u32; - } - - #[cfg(not(feature = "std"))] - impl IntoFFIValue for [u8; $n] { - type Owned = (); +/// The type is passed as `u32`. +/// +/// The `u32` is the pointer to the array. +impl RIType for [u8; N] { + type FFIType = u32; +} - fn into_ffi_value(&self) -> WrappedFFIValue { - (self.as_ptr() as u32).into() - } - } +#[cfg(not(feature = "std"))] +impl IntoFFIValue for [u8; N] { + type Owned = (); - #[cfg(not(feature = "std"))] - impl FromFFIValue for [u8; $n] { - fn from_ffi_value(arg: u32) -> [u8; $n] { - let mut res = [0u8; $n]; - let data = unsafe { Vec::from_raw_parts(arg as *mut u8, $n, $n) }; + fn into_ffi_value(&self) -> WrappedFFIValue { + (self.as_ptr() as u32).into() + } +} - res.copy_from_slice(&data); +#[cfg(not(feature = "std"))] +impl FromFFIValue for [u8; N] { + fn from_ffi_value(arg: u32) -> [u8; N] { + let mut res = [0u8; N]; + let data = unsafe { Vec::from_raw_parts(arg as *mut u8, N, N) }; - res - } - } + res.copy_from_slice(&data); - #[cfg(feature = "std")] - impl FromFFIValue for [u8; $n] { - type SelfInstance = [u8; $n]; + res + } +} - fn from_ffi_value(context: &mut dyn FunctionContext, arg: u32) -> Result<[u8; $n]> { - let mut res = [0u8; $n]; - context.read_memory_into(Pointer::new(arg), &mut res)?; - Ok(res) - } - } +#[cfg(feature = "std")] +impl FromFFIValue for [u8; N] { + type SelfInstance = [u8; N]; - #[cfg(feature = "std")] - impl IntoFFIValue for [u8; $n] { - fn into_ffi_value(self, context: &mut dyn FunctionContext) -> Result { - let addr = context.allocate_memory($n)?; - context.write_memory(addr, &self)?; - Ok(addr.into()) - } - } + fn from_ffi_value(context: &mut dyn FunctionContext, arg: u32) -> Result<[u8; N]> { + let mut res = [0u8; N]; + context.read_memory_into(Pointer::new(arg), &mut res)?; + Ok(res) + } +} - #[cfg(feature = "std")] - impl IntoPreallocatedFFIValue for [u8; $n] { - type SelfInstance = [u8; $n]; - - fn into_preallocated_ffi_value( - self_instance: Self::SelfInstance, - context: &mut dyn FunctionContext, - allocated: u32, - ) -> Result<()> { - context.write_memory(Pointer::new(allocated), &self_instance) - } - } - )* +#[cfg(feature = "std")] +impl IntoFFIValue for [u8; N] { + fn into_ffi_value(self, context: &mut dyn FunctionContext) -> Result { + let addr = context.allocate_memory(N as u32)?; + context.write_memory(addr, &self)?; + Ok(addr.into()) } } -impl_traits_for_arrays! { - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, - 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, - 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, - 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, +#[cfg(feature = "std")] +impl IntoPreallocatedFFIValue for [u8; N] { + type SelfInstance = [u8; N]; + + fn into_preallocated_ffi_value( + self_instance: Self::SelfInstance, + context: &mut dyn FunctionContext, + allocated: u32, + ) -> Result<()> { + context.write_memory(Pointer::new(allocated), &self_instance) + } } impl PassBy for sp_std::result::Result { From 129fee774a6d185d117a57fd1e81b3d0d05ad747 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= <123550+andresilva@users.noreply.github.com> Date: Mon, 30 Jan 2023 15:25:11 +0000 Subject: [PATCH 348/715] grandpa: cleanup stale entries in set id session mapping (#13237) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * grandpa: cleanup stale entries in set id session mapping * Update frame/grandpa/src/migrations.rs Co-authored-by: Bastian Köcher * grandpa: remove unused import * grandpa: migration off-by-one * Update frame/grandpa/src/lib.rs Co-authored-by: Anton * Update frame/grandpa/src/lib.rs Co-authored-by: Anton * grandpa: MaxSetIdSessionEntries as u64 * node-template: fix MaxSetIdSessionEntries type --------- Co-authored-by: Bastian Köcher Co-authored-by: Anton --- bin/node-template/runtime/src/lib.rs | 1 + bin/node/runtime/src/lib.rs | 5 +++ frame/grandpa/src/lib.rs | 30 +++++++++++++++--- frame/grandpa/src/migrations.rs | 46 ++++++++++++++++++++++++++++ frame/grandpa/src/mock.rs | 2 ++ frame/grandpa/src/tests.rs | 27 ++++++++++++++++ 6 files changed, 107 insertions(+), 4 deletions(-) diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs index baba5d9b05e59..4840459816632 100644 --- a/bin/node-template/runtime/src/lib.rs +++ b/bin/node-template/runtime/src/lib.rs @@ -230,6 +230,7 @@ impl pallet_grandpa::Config for Runtime { type WeightInfo = (); type MaxAuthorities = ConstU32<32>; + type MaxSetIdSessionEntries = ConstU64<0>; } impl pallet_timestamp::Config for Runtime { diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 30165cdb6f6c7..8e8ecc125dba4 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1310,6 +1310,10 @@ impl pallet_authority_discovery::Config for Runtime { type MaxAuthorities = MaxAuthorities; } +parameter_types! { + pub const MaxSetIdSessionEntries: u32 = BondingDuration::get() * SessionsPerEra::get(); +} + impl pallet_grandpa::Config for Runtime { type RuntimeEvent = RuntimeEvent; @@ -1331,6 +1335,7 @@ impl pallet_grandpa::Config for Runtime { type WeightInfo = (); type MaxAuthorities = MaxAuthorities; + type MaxSetIdSessionEntries = MaxSetIdSessionEntries; } parameter_types! { diff --git a/frame/grandpa/src/lib.rs b/frame/grandpa/src/lib.rs index aa09b445c6bdd..ea534947ddd37 100644 --- a/frame/grandpa/src/lib.rs +++ b/frame/grandpa/src/lib.rs @@ -121,6 +121,15 @@ pub mod pallet { /// Max Authorities in use #[pallet::constant] type MaxAuthorities: Get; + + /// The maximum number of entries to keep in the set id to session index mapping. + /// + /// Since the `SetIdSession` map is only used for validating equivocations this + /// value should relate to the bonding duration of whatever staking system is + /// being used (if any). If equivocation handling is not enabled then this value + /// can be zero. + #[pallet::constant] + type MaxSetIdSessionEntries: Get; } #[pallet::hooks] @@ -323,6 +332,12 @@ pub mod pallet { /// A mapping from grandpa set ID to the index of the *most recent* session for which its /// members were responsible. /// + /// This is only used for validating equivocation proofs. An equivocation proof must + /// contains a key-ownership proof for a given session, therefore we need a way to tie + /// together sessions and GRANDPA set ids, i.e. we need to validate that a validator + /// was the owner of a given key on a given session, and what the active set ID was + /// during that session. + /// /// TWOX-NOTE: `SetId` is not under user control. #[pallet::storage] #[pallet::getter(fn session_for_set)] @@ -643,10 +658,17 @@ where }; if res.is_ok() { - CurrentSetId::::mutate(|s| { + let current_set_id = CurrentSetId::::mutate(|s| { *s += 1; *s - }) + }); + + let max_set_id_session_entries = T::MaxSetIdSessionEntries::get().max(1); + if current_set_id >= max_set_id_session_entries { + SetIdSession::::remove(current_set_id - max_set_id_session_entries); + } + + current_set_id } else { // either the session module signalled that the validators have changed // or the set was stalled. but since we didn't successfully schedule @@ -659,8 +681,8 @@ where Self::current_set_id() }; - // if we didn't issue a change, we update the mapping to note that the current - // set corresponds to the latest equivalent session (i.e. now). + // update the mapping to note that the current set corresponds to the + // latest equivalent session (i.e. now). let session_index = >::current_index(); SetIdSession::::insert(current_set_id, &session_index); } diff --git a/frame/grandpa/src/migrations.rs b/frame/grandpa/src/migrations.rs index 7795afcd8034f..f4a28fff13974 100644 --- a/frame/grandpa/src/migrations.rs +++ b/frame/grandpa/src/migrations.rs @@ -15,5 +15,51 @@ // See the License for the specific language governing permissions and // limitations under the License. +use frame_support::{ + traits::{Get, OnRuntimeUpgrade}, + weights::Weight, +}; + +use crate::{Config, CurrentSetId, SetIdSession, LOG_TARGET}; + /// Version 4. pub mod v4; + +/// This migration will clean up all stale set id -> session entries from the +/// `SetIdSession` storage map, only the latest `max_set_id_session_entries` +/// will be kept. +/// +/// This migration should be added with a runtime upgrade that introduces the +/// `MaxSetIdSessionEntries` constant to the pallet (although it could also be +/// done later on). +pub struct CleanupSetIdSessionMap(sp_std::marker::PhantomData); +impl OnRuntimeUpgrade for CleanupSetIdSessionMap { + fn on_runtime_upgrade() -> Weight { + // NOTE: since this migration will loop over all stale entries in the + // map we need to set some cutoff value, otherwise the migration might + // take too long to run. for scenarios where there are that many entries + // to cleanup a multiblock migration will be needed instead. + if CurrentSetId::::get() > 25_000 { + log::warn!( + target: LOG_TARGET, + "CleanupSetIdSessionMap migration was aborted since there are too many entries to cleanup." + ); + + return T::DbWeight::get().reads(1) + } + + cleanup_set_id_sesion_map::() + } +} + +fn cleanup_set_id_sesion_map() -> Weight { + let until_set_id = CurrentSetId::::get().saturating_sub(T::MaxSetIdSessionEntries::get()); + + for set_id in 0..=until_set_id { + SetIdSession::::remove(set_id); + } + + T::DbWeight::get() + .reads(1) + .saturating_add(T::DbWeight::get().writes(until_set_id + 1)) +} diff --git a/frame/grandpa/src/mock.rs b/frame/grandpa/src/mock.rs index 54f34008abc56..7d54966a498a6 100644 --- a/frame/grandpa/src/mock.rs +++ b/frame/grandpa/src/mock.rs @@ -219,6 +219,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 MaxSetIdSessionEntries: u32 = BondingDuration::get() * SessionsPerEra::get(); } impl Config for Test { @@ -239,6 +240,7 @@ impl Config for Test { type WeightInfo = (); type MaxAuthorities = ConstU32<100>; + type MaxSetIdSessionEntries = MaxSetIdSessionEntries; } pub fn grandpa_log(log: ConsensusLog) -> DigestItem { diff --git a/frame/grandpa/src/tests.rs b/frame/grandpa/src/tests.rs index 626decd12821e..e090dcebb60bf 100644 --- a/frame/grandpa/src/tests.rs +++ b/frame/grandpa/src/tests.rs @@ -781,6 +781,33 @@ fn on_new_session_doesnt_start_new_set_if_schedule_change_failed() { }); } +#[test] +fn cleans_up_old_set_id_session_mappings() { + new_test_ext(vec![(1, 1), (2, 1), (3, 1)]).execute_with(|| { + let max_set_id_session_entries = MaxSetIdSessionEntries::get(); + + start_era(max_set_id_session_entries); + + // we should have a session id mapping for all the set ids from + // `max_set_id_session_entries` eras we have observed + for i in 1..=max_set_id_session_entries { + assert!(Grandpa::session_for_set(i as u64).is_some()); + } + + start_era(max_set_id_session_entries * 2); + + // we should keep tracking the new mappings for new eras + for i in max_set_id_session_entries + 1..=max_set_id_session_entries * 2 { + assert!(Grandpa::session_for_set(i as u64).is_some()); + } + + // but the old ones should have been pruned by now + for i in 1..=max_set_id_session_entries { + assert!(Grandpa::session_for_set(i as u64).is_none()); + } + }); +} + #[test] fn always_schedules_a_change_on_new_session_when_stalled() { new_test_ext(vec![(1, 1), (2, 1), (3, 1)]).execute_with(|| { From 8cfe326e4e33c5077fc67f197d6a13dd871881c7 Mon Sep 17 00:00:00 2001 From: Muharem Ismailov Date: Wed, 1 Feb 2023 03:11:41 +0100 Subject: [PATCH 349/715] Benchmark's successful origin api update (#13146) * try successful origin unimplemented by default * error as a default impl for try_successful_origin * remove successful_origin func of EnsureOrigin trait * default impl -> unimplemented!() * update EnsureOriginWithArg * fix EnsureOriginWithArg * prefix unused arg with underscore * use try_successful_origin instead successful_origin, map err to Weightless * fix tests * remove default impl * unwrap for indirect origin dep * replace unwrap by expect with a message --------- Co-authored-by: parity-processbot <> --- frame/alliance/src/benchmarking.rs | 23 ++- frame/assets/src/benchmarking.rs | 14 +- frame/bounties/src/benchmarking.rs | 6 +- frame/democracy/src/benchmarking.rs | 42 +++-- frame/fast-unstake/src/benchmarking.rs | 5 +- frame/identity/src/benchmarking.rs | 23 ++- frame/lottery/src/benchmarking.rs | 14 +- frame/membership/src/lib.rs | 37 ++-- frame/nfts/src/benchmarking.rs | 11 +- frame/nis/src/benchmarking.rs | 5 +- frame/preimage/src/benchmarking.rs | 116 +++++++++---- frame/ranked-collective/src/benchmarking.rs | 37 ++-- frame/ranked-collective/src/lib.rs | 39 ----- frame/referenda/src/benchmarking.rs | 183 ++++++++++++++------ frame/scheduler/src/benchmarking.rs | 5 +- frame/support/src/traits/dispatch.rs | 38 +--- frame/system/src/tests.rs | 7 +- frame/tips/src/benchmarking.rs | 7 +- frame/treasury/src/benchmarking.rs | 11 +- frame/uniques/src/benchmarking.rs | 8 +- frame/whitelist/src/benchmarking.rs | 14 +- 21 files changed, 402 insertions(+), 243 deletions(-) diff --git a/frame/alliance/src/benchmarking.rs b/frame/alliance/src/benchmarking.rs index f312e032bbb0f..01b81ed66e999 100644 --- a/frame/alliance/src/benchmarking.rs +++ b/frame/alliance/src/benchmarking.rs @@ -25,7 +25,7 @@ use sp_std::{ prelude::*, }; -use frame_benchmarking::v1::{account, benchmarks_instance_pallet}; +use frame_benchmarking::v1::{account, benchmarks_instance_pallet, BenchmarkError}; use frame_support::traits::{EnsureOrigin, Get, UnfilteredDispatchable}; use frame_system::{Pallet as System, RawOrigin as SystemOrigin}; @@ -581,7 +581,8 @@ benchmarks_instance_pallet! { let rule = rule(b"hello world"); let call = Call::::set_rule { rule: rule.clone() }; - let origin = T::AdminOrigin::successful_origin(); + let origin = + T::AdminOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; }: { call.dispatch_bypass_filter(origin)? } verify { assert_eq!(Alliance::::rule(), Some(rule.clone())); @@ -594,7 +595,8 @@ benchmarks_instance_pallet! { let announcement = announcement(b"hello world"); let call = Call::::announce { announcement: announcement.clone() }; - let origin = T::AnnouncementOrigin::successful_origin(); + let origin = + T::AnnouncementOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; }: { call.dispatch_bypass_filter(origin)? } verify { assert!(Alliance::::announcements().contains(&announcement)); @@ -609,7 +611,8 @@ benchmarks_instance_pallet! { Announcements::::put(announcements); let call = Call::::remove_announcement { announcement: announcement.clone() }; - let origin = T::AnnouncementOrigin::successful_origin(); + let origin = + T::AnnouncementOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; }: { call.dispatch_bypass_filter(origin)? } verify { assert!(Alliance::::announcements().is_empty()); @@ -665,7 +668,8 @@ benchmarks_instance_pallet! { let ally1_lookup = T::Lookup::unlookup(ally1.clone()); let call = Call::::elevate_ally { ally: ally1_lookup }; - let origin = T::MembershipManager::successful_origin(); + let origin = + T::MembershipManager::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; }: { call.dispatch_bypass_filter(origin)? } verify { assert!(!Alliance::::is_ally(&ally1)); @@ -725,7 +729,8 @@ benchmarks_instance_pallet! { let fellow2_lookup = T::Lookup::unlookup(fellow2.clone()); let call = Call::::kick_member { who: fellow2_lookup }; - let origin = T::MembershipManager::successful_origin(); + let origin = + T::MembershipManager::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; }: { call.dispatch_bypass_filter(origin)? } verify { assert!(!Alliance::::is_member(&fellow2)); @@ -754,7 +759,8 @@ benchmarks_instance_pallet! { 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(); + let origin = + T::AnnouncementOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; }: { call.dispatch_bypass_filter(origin)? } verify { assert_last_event::(Event::UnscrupulousItemAdded { items: unscrupulous_list }.into()); @@ -784,7 +790,8 @@ benchmarks_instance_pallet! { unscrupulous_list.extend(websites.into_iter().map(UnscrupulousItem::Website)); let call = Call::::remove_unscrupulous_items { items: unscrupulous_list.clone() }; - let origin = T::AnnouncementOrigin::successful_origin(); + let origin = + T::AnnouncementOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; }: { call.dispatch_bypass_filter(origin)? } verify { assert_last_event::(Event::UnscrupulousItemRemoved { items: unscrupulous_list }.into()); diff --git a/frame/assets/src/benchmarking.rs b/frame/assets/src/benchmarking.rs index 9acf69f1e4ef4..cf0ec353f6350 100644 --- a/frame/assets/src/benchmarking.rs +++ b/frame/assets/src/benchmarking.rs @@ -21,7 +21,7 @@ use super::*; use frame_benchmarking::v1::{ - account, benchmarks_instance_pallet, whitelist_account, whitelisted_caller, + account, benchmarks_instance_pallet, whitelist_account, whitelisted_caller, BenchmarkError, }; use frame_support::{ dispatch::UnfilteredDispatchable, @@ -135,7 +135,8 @@ fn assert_event, I: 'static>(generic_event: >::Runti benchmarks_instance_pallet! { create { let asset_id = default_asset_id::(); - let origin = T::CreateOrigin::successful_origin(&asset_id.into()); + let origin = T::CreateOrigin::try_successful_origin(&asset_id.into()) + .map_err(|_| BenchmarkError::Weightless)?; 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()); @@ -362,7 +363,8 @@ benchmarks_instance_pallet! { let (asset_id, _, _) = create_default_asset::(true); - let origin = T::ForceOrigin::successful_origin(); + let origin = + T::ForceOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; let call = Call::::force_set_metadata { id: asset_id, name: name.clone(), @@ -382,7 +384,8 @@ benchmarks_instance_pallet! { let origin = SystemOrigin::Signed(caller).into(); Assets::::set_metadata(origin, asset_id, dummy.clone(), dummy, 12)?; - let origin = T::ForceOrigin::successful_origin(); + let origin = + T::ForceOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; let call = Call::::force_clear_metadata { id: asset_id }; }: { call.dispatch_bypass_filter(origin)? } verify { @@ -392,7 +395,8 @@ benchmarks_instance_pallet! { force_asset_status { let (asset_id, caller, caller_lookup) = create_default_asset::(true); - let origin = T::ForceOrigin::successful_origin(); + let origin = + T::ForceOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; let call = Call::::force_asset_status { id: asset_id, owner: caller_lookup.clone(), diff --git a/frame/bounties/src/benchmarking.rs b/frame/bounties/src/benchmarking.rs index a43372978e5ca..881f1c912e38b 100644 --- a/frame/bounties/src/benchmarking.rs +++ b/frame/bounties/src/benchmarking.rs @@ -173,7 +173,8 @@ 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; - let approve_origin = T::ApproveOrigin::successful_origin(); + let approve_origin = + T::ApproveOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; }: close_bounty(approve_origin, bounty_id) close_bounty_active { @@ -181,7 +182,8 @@ benchmarks_instance_pallet! { let (curator_lookup, bounty_id) = create_bounty::()?; Treasury::::on_initialize(T::BlockNumber::zero()); let bounty_id = BountyCount::::get() - 1; - let approve_origin = T::ApproveOrigin::successful_origin(); + let approve_origin = + T::ApproveOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; }: 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 66d9e2a007afa..f2d45b719f678 100644 --- a/frame/democracy/src/benchmarking.rs +++ b/frame/democracy/src/benchmarking.rs @@ -19,7 +19,7 @@ use super::*; -use frame_benchmarking::v1::{account, benchmarks, whitelist_account}; +use frame_benchmarking::v1::{account, benchmarks, whitelist_account, BenchmarkError}; use frame_support::{ assert_noop, assert_ok, traits::{Currency, EnsureOrigin, Get, OnInitialize, UnfilteredDispatchable}, @@ -177,7 +177,8 @@ benchmarks! { } emergency_cancel { - let origin = T::CancellationOrigin::successful_origin(); + let origin = + T::CancellationOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; let ref_index = add_referendum::(0).0; assert_ok!(Democracy::::referendum_status(ref_index)); }: _(origin, ref_index) @@ -200,10 +201,13 @@ benchmarks! { let (ref_index, hash) = add_referendum::(0); assert_ok!(Democracy::::referendum_status(ref_index)); // Place our proposal in the external queue, too. - assert_ok!( - Democracy::::external_propose(T::ExternalOrigin::successful_origin(), make_proposal::(0)) - ); - let origin = T::BlacklistOrigin::successful_origin(); + assert_ok!(Democracy::::external_propose( + T::ExternalOrigin::try_successful_origin() + .expect("ExternalOrigin has no successful origin required for the benchmark"), + make_proposal::(0) + )); + let origin = + T::BlacklistOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; }: _(origin, hash, Some(ref_index)) verify { // Referendum has been canceled @@ -215,7 +219,8 @@ benchmarks! { // Worst case scenario, we external propose a previously blacklisted proposal external_propose { - let origin = T::ExternalOrigin::successful_origin(); + let origin = + T::ExternalOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; let proposal = make_proposal::(0); // Add proposal to blacklist with block number 0 @@ -233,7 +238,8 @@ benchmarks! { } external_propose_majority { - let origin = T::ExternalMajorityOrigin::successful_origin(); + let origin = T::ExternalMajorityOrigin::try_successful_origin() + .map_err(|_| BenchmarkError::Weightless)?; let proposal = make_proposal::(0); }: _(origin, proposal) verify { @@ -242,7 +248,8 @@ benchmarks! { } external_propose_default { - let origin = T::ExternalDefaultOrigin::successful_origin(); + let origin = T::ExternalDefaultOrigin::try_successful_origin() + .map_err(|_| BenchmarkError::Weightless)?; let proposal = make_proposal::(0); }: _(origin, proposal) verify { @@ -251,13 +258,15 @@ benchmarks! { } fast_track { - let origin_propose = T::ExternalDefaultOrigin::successful_origin(); + let origin_propose = T::ExternalDefaultOrigin::try_successful_origin() + .expect("ExternalDefaultOrigin has no successful origin required for the benchmark"); 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(); + let origin_fast_track = + T::FastTrackOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; let voting_period = T::FastTrackVotingPeriod::get(); let delay = 0u32; }: _(origin_fast_track, proposal_hash, voting_period, delay.into()) @@ -269,7 +278,8 @@ benchmarks! { let proposal = make_proposal::(0); let proposal_hash = proposal.hash(); - let origin_propose = T::ExternalDefaultOrigin::successful_origin(); + let origin_propose = T::ExternalDefaultOrigin::try_successful_origin() + .expect("ExternalDefaultOrigin has no successful origin required for the benchmark"); Democracy::::external_propose_default(origin_propose, proposal)?; let mut vetoers: BoundedVec = Default::default(); @@ -279,7 +289,7 @@ benchmarks! { vetoers.sort(); Blacklist::::insert(proposal_hash, (T::BlockNumber::zero(), vetoers)); - let origin = T::VetoOrigin::successful_origin(); + let origin = T::VetoOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; ensure!(NextExternal::::get().is_some(), "no external proposal"); }: _(origin, proposal_hash) verify { @@ -293,7 +303,8 @@ benchmarks! { for i in 0 .. T::MaxProposals::get() { add_proposal::(i)?; } - let cancel_origin = T::CancelProposalOrigin::successful_origin(); + let cancel_origin = T::CancelProposalOrigin::try_successful_origin() + .map_err(|_| BenchmarkError::Weightless)?; }: _(cancel_origin, 0) cancel_referendum { @@ -313,7 +324,8 @@ benchmarks! { // Launch external LastTabledWasExternal::::put(false); - let origin = T::ExternalMajorityOrigin::successful_origin(); + let origin = T::ExternalMajorityOrigin::try_successful_origin() + .map_err(|_| BenchmarkError::Weightless)?; let proposal = make_proposal::(r); let call = Call::::external_propose_majority { proposal }; call.dispatch_bypass_filter(origin)?; diff --git a/frame/fast-unstake/src/benchmarking.rs b/frame/fast-unstake/src/benchmarking.rs index 77488b6447c61..e0e4186d78014 100644 --- a/frame/fast-unstake/src/benchmarking.rs +++ b/frame/fast-unstake/src/benchmarking.rs @@ -20,7 +20,7 @@ #![cfg(feature = "runtime-benchmarks")] use crate::{types::*, Pallet as FastUnstake, *}; -use frame_benchmarking::v1::{benchmarks, whitelist_account}; +use frame_benchmarking::v1::{benchmarks, whitelist_account, BenchmarkError}; use frame_support::{ assert_ok, traits::{Currency, EnsureOrigin, Get, Hooks}, @@ -192,7 +192,8 @@ benchmarks! { } control { - let origin = ::ControlOrigin::successful_origin(); + let origin = ::ControlOrigin::try_successful_origin() + .map_err(|_| BenchmarkError::Weightless)?; } : _(origin, T::MaxErasToCheckPerBlock::get()) verify {} diff --git a/frame/identity/src/benchmarking.rs b/frame/identity/src/benchmarking.rs index 356bcb2e80174..2d485af0f698b 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::v1::{account, benchmarks, whitelisted_caller}; +use frame_benchmarking::v1::{account, benchmarks, whitelisted_caller, BenchmarkError}; use frame_support::{ ensure, traits::{EnsureOrigin, Get}, @@ -42,7 +42,8 @@ fn add_registrars(r: u32) -> Result<(), &'static str> { 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(); + let registrar_origin = T::RegistrarOrigin::try_successful_origin() + .expect("RegistrarOrigin has no successful origin required for the benchmark"); Identity::::add_registrar(registrar_origin, registrar_lookup)?; Identity::::set_fee(RawOrigin::Signed(registrar.clone()).into(), i, 10u32.into())?; let fields = @@ -121,7 +122,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."); - let origin = T::RegistrarOrigin::successful_origin(); + let origin = + T::RegistrarOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; let account = T::Lookup::unlookup(account("registrar", r + 1, SEED)); }: _(origin, account) verify { @@ -280,7 +282,8 @@ benchmarks! { let r in 1 .. T::MaxRegistrars::get() - 1 => add_registrars::(r)?; - let registrar_origin = T::RegistrarOrigin::successful_origin(); + let registrar_origin = T::RegistrarOrigin::try_successful_origin() + .expect("RegistrarOrigin has no successful origin required for the benchmark"); Identity::::add_registrar(registrar_origin, caller_lookup)?; let registrars = Registrars::::get(); ensure!(registrars[r as usize].as_ref().unwrap().fee == 0u32.into(), "Fee already set."); @@ -297,7 +300,8 @@ benchmarks! { let r in 1 .. T::MaxRegistrars::get() - 1 => add_registrars::(r)?; - let registrar_origin = T::RegistrarOrigin::successful_origin(); + let registrar_origin = T::RegistrarOrigin::try_successful_origin() + .expect("RegistrarOrigin has no successful origin required for the benchmark"); Identity::::add_registrar(registrar_origin, caller_lookup)?; let registrars = Registrars::::get(); ensure!(registrars[r as usize].as_ref().unwrap().account == caller, "id not set."); @@ -315,7 +319,8 @@ benchmarks! { let r in 1 .. T::MaxRegistrars::get() - 1 => add_registrars::(r)?; - let registrar_origin = T::RegistrarOrigin::successful_origin(); + let registrar_origin = T::RegistrarOrigin::try_successful_origin() + .expect("RegistrarOrigin has no successful origin required for the benchmark"); Identity::::add_registrar(registrar_origin, caller_lookup)?; let fields = IdentityFields( IdentityField::Display | IdentityField::Legal | IdentityField::Web | IdentityField::Riot @@ -347,7 +352,8 @@ benchmarks! { let info_hash = T::Hashing::hash_of(&info); Identity::::set_identity(user_origin.clone(), Box::new(info))?; - let registrar_origin = T::RegistrarOrigin::successful_origin(); + let registrar_origin = T::RegistrarOrigin::try_successful_origin() + .expect("RegistrarOrigin has no successful origin required for the benchmark"); Identity::::add_registrar(registrar_origin, caller_lookup)?; Identity::::request_judgement(user_origin, r, 10u32.into())?; }: _(RawOrigin::Signed(caller), r, user_lookup, Judgement::Reasonable, info_hash) @@ -385,7 +391,8 @@ benchmarks! { )?; } ensure!(IdentityOf::::contains_key(&target), "Identity not set"); - let origin = T::ForceOrigin::successful_origin(); + let origin = + T::ForceOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; }: _(origin, target_lookup) verify { ensure!(!IdentityOf::::contains_key(&target), "Identity not removed"); diff --git a/frame/lottery/src/benchmarking.rs b/frame/lottery/src/benchmarking.rs index 658dd25a98a27..0db7fabb365ef 100644 --- a/frame/lottery/src/benchmarking.rs +++ b/frame/lottery/src/benchmarking.rs @@ -21,7 +21,7 @@ use super::*; -use frame_benchmarking::v1::{account, benchmarks, whitelisted_caller}; +use frame_benchmarking::v1::{account, benchmarks, whitelisted_caller, BenchmarkError}; use frame_support::{ storage::bounded_vec::BoundedVec, traits::{EnsureOrigin, OnInitialize}, @@ -43,7 +43,8 @@ fn setup_lottery(repeat: bool) -> Result<(), &'static str> { ]; // Last call will be the match for worst case scenario. calls.push(frame_system::Call::::remark { remark: vec![] }.into()); - let origin = T::ManagerOrigin::successful_origin(); + let origin = T::ManagerOrigin::try_successful_origin() + .expect("ManagerOrigin has no successful origin required for the benchmark"); Lottery::::set_calls(origin.clone(), calls)?; Lottery::::start_lottery(origin, price, length, delay, repeat)?; Ok(()) @@ -76,7 +77,8 @@ 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 origin = T::ManagerOrigin::successful_origin(); + let origin = + T::ManagerOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; assert!(CallIndices::::get().is_empty()); }: _(origin, calls) verify { @@ -89,7 +91,8 @@ benchmarks! { let price = BalanceOf::::max_value(); let end = 10u32.into(); let payout = 5u32.into(); - let origin = T::ManagerOrigin::successful_origin(); + let origin = + T::ManagerOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; }: _(origin, price, end, payout, true) verify { assert!(crate::Lottery::::get().is_some()); @@ -98,7 +101,8 @@ benchmarks! { stop_repeat { setup_lottery::(true)?; assert_eq!(crate::Lottery::::get().unwrap().repeat, true); - let origin = T::ManagerOrigin::successful_origin(); + let origin = + T::ManagerOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; }: _(origin) verify { assert_eq!(crate::Lottery::::get().unwrap().repeat, false); diff --git a/frame/membership/src/lib.rs b/frame/membership/src/lib.rs index 6d973a15fe032..8b39a08ce6699 100644 --- a/frame/membership/src/lib.rs +++ b/frame/membership/src/lib.rs @@ -362,15 +362,17 @@ impl, I: 'static> SortedMembers for Pallet { #[cfg(feature = "runtime-benchmarks")] mod benchmark { use super::{Pallet as Membership, *}; - use frame_benchmarking::v1::{account, benchmarks_instance_pallet, whitelist}; + use frame_benchmarking::v1::{account, benchmarks_instance_pallet, whitelist, BenchmarkError}; use frame_support::{assert_ok, traits::EnsureOrigin}; use frame_system::RawOrigin; const SEED: u32 = 0; fn set_members, I: 'static>(members: Vec, prime: Option) { - let reset_origin = T::ResetOrigin::successful_origin(); - let prime_origin = T::PrimeOrigin::successful_origin(); + let reset_origin = T::ResetOrigin::try_successful_origin() + .expect("ResetOrigin has no successful origin required for the benchmark"); + let prime_origin = T::PrimeOrigin::try_successful_origin() + .expect("PrimeOrigin has no successful origin required for the benchmark"); assert_ok!(>::reset_members(reset_origin, members.clone())); if let Some(prime) = prime.map(|i| members[i].clone()) { @@ -390,9 +392,11 @@ mod benchmark { 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_lookup)); - } - verify { + assert_ok!(>::add_member( + T::AddOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, + new_member_lookup, + )); + } verify { assert!(>::get().contains(&new_member)); #[cfg(test)] crate::tests::clean(); } @@ -408,7 +412,10 @@ mod benchmark { 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_lookup)); + assert_ok!(>::remove_member( + T::RemoveOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, + to_remove_lookup, + )); } verify { assert!(!>::get().contains(&to_remove)); // prime is rejigged @@ -428,7 +435,7 @@ mod benchmark { let remove_lookup = T::Lookup::unlookup(remove.clone()); }: { assert_ok!(>::swap_member( - T::SwapOrigin::successful_origin(), + T::SwapOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, remove_lookup, add_lookup, )); @@ -448,7 +455,10 @@ mod benchmark { set_members::(members.clone(), Some(members.len() - 1)); let mut new_members = (m..2*m).map(|i| account("member", i, SEED)).collect::>(); }: { - assert_ok!(>::reset_members(T::ResetOrigin::successful_origin(), new_members.clone())); + assert_ok!(>::reset_members( + T::ResetOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, + new_members.clone(), + )); } verify { new_members.sort(); assert_eq!(>::get(), new_members); @@ -485,7 +495,10 @@ mod benchmark { let prime_lookup = T::Lookup::unlookup(prime.clone()); set_members::(members, None); }: { - assert_ok!(>::set_prime(T::PrimeOrigin::successful_origin(), prime_lookup)); + assert_ok!(>::set_prime( + T::PrimeOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, + prime_lookup, + )); } verify { assert!(>::get().is_some()); assert!(::get_prime().is_some()); @@ -498,7 +511,9 @@ mod benchmark { let prime = members.last().cloned().unwrap(); set_members::(members, None); }: { - assert_ok!(>::clear_prime(T::PrimeOrigin::successful_origin())); + assert_ok!(>::clear_prime( + T::PrimeOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, + )); } verify { assert!(>::get().is_none()); assert!(::get_prime().is_none()); diff --git a/frame/nfts/src/benchmarking.rs b/frame/nfts/src/benchmarking.rs index 17ff28b822814..a4007f6b2c133 100644 --- a/frame/nfts/src/benchmarking.rs +++ b/frame/nfts/src/benchmarking.rs @@ -22,7 +22,7 @@ use super::*; use enumflags2::{BitFlag, BitFlags}; use frame_benchmarking::v1::{ - account, benchmarks_instance_pallet, whitelist_account, whitelisted_caller, + account, benchmarks_instance_pallet, whitelist_account, whitelisted_caller, BenchmarkError, }; use frame_support::{ assert_ok, @@ -151,7 +151,8 @@ fn default_item_config() -> ItemConfig { benchmarks_instance_pallet! { create { let collection = T::Helper::collection(0); - let origin = T::CreateOrigin::successful_origin(&collection); + let origin = T::CreateOrigin::try_successful_origin(&collection) + .map_err(|_| BenchmarkError::Weightless)?; let caller = T::CreateOrigin::ensure_origin(origin.clone(), &collection).unwrap(); whitelist_account!(caller); let admin = T::Lookup::unlookup(caller.clone()); @@ -311,7 +312,8 @@ benchmarks_instance_pallet! { force_collection_owner { let (collection, _, _) = create_collection::(); - let origin = T::ForceOrigin::successful_origin(); + let origin = + T::ForceOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; 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()); @@ -326,7 +328,8 @@ benchmarks_instance_pallet! { force_collection_config { let (collection, caller, _) = create_collection::(); - let origin = T::ForceOrigin::successful_origin(); + let origin = + T::ForceOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; let call = Call::::force_collection_config { collection, config: make_collection_config::(CollectionSetting::DepositRequired.into()), diff --git a/frame/nis/src/benchmarking.rs b/frame/nis/src/benchmarking.rs index b01d414c4b251..10d3a238a3f5e 100644 --- a/frame/nis/src/benchmarking.rs +++ b/frame/nis/src/benchmarking.rs @@ -20,7 +20,7 @@ #![cfg(feature = "runtime-benchmarks")] use super::*; -use frame_benchmarking::v1::{account, benchmarks, whitelisted_caller}; +use frame_benchmarking::v1::{account, benchmarks, whitelisted_caller, BenchmarkError}; use frame_support::traits::{nonfungible::Inspect, Currency, EnsureOrigin, Get}; use frame_system::RawOrigin; use sp_arithmetic::Perquintill; @@ -100,7 +100,8 @@ benchmarks! { } fund_deficit { - let origin = T::FundOrigin::successful_origin(); + let origin = + T::FundOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; let caller: T::AccountId = whitelisted_caller(); let bid = T::MinBid::get().max(One::one()); T::Currency::make_free_balance_be(&caller, bid); diff --git a/frame/preimage/src/benchmarking.rs b/frame/preimage/src/benchmarking.rs index f9526b67d4bc8..56361b88c2583 100644 --- a/frame/preimage/src/benchmarking.rs +++ b/frame/preimage/src/benchmarking.rs @@ -18,7 +18,7 @@ //! Preimage pallet benchmarking. use super::*; -use frame_benchmarking::v1::{account, benchmarks, whitelist_account}; +use frame_benchmarking::v1::{account, benchmarks, whitelist_account, BenchmarkError}; use frame_support::assert_ok; use frame_system::RawOrigin; use sp_runtime::traits::Bounded; @@ -62,7 +62,11 @@ 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)); + assert_ok!(Preimage::::request_preimage( + T::ManagerOrigin::try_successful_origin() + .expect("ManagerOrigin has no successful origin required for the benchmark"), + hash, + )); }: note_preimage(RawOrigin::Signed(caller), preimage) verify { assert!(Preimage::::have_preimage(&hash)); @@ -71,9 +75,15 @@ benchmarks! { note_no_deposit_preimage { 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) - verify { + assert_ok!(Preimage::::request_preimage( + T::ManagerOrigin::try_successful_origin() + .expect("ManagerOrigin has no successful origin required for the benchmark"), + hash, + )); + }: note_preimage( + T::ManagerOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, + preimage + ) verify { assert!(Preimage::::have_preimage(&hash)); } @@ -90,9 +100,15 @@ benchmarks! { // 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) - verify { + assert_ok!(Preimage::::note_preimage( + T::ManagerOrigin::try_successful_origin() + .expect("ManagerOrigin has no successful origin required for the benchmark"), + preimage, + )); + }: unnote_preimage( + T::ManagerOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, + hash + ) verify { assert!(!Preimage::::have_preimage(&hash)); } @@ -102,8 +118,10 @@ benchmarks! { let noter = funded_account::("noter", 0); whitelist_account!(noter); assert_ok!(Preimage::::note_preimage(RawOrigin::Signed(noter.clone()).into(), preimage)); - }: _(T::ManagerOrigin::successful_origin(), hash) - verify { + }: _( + T::ManagerOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, + hash + ) verify { let deposit = T::BaseDeposit::get() + T::ByteDeposit::get() * MAX_SIZE.into(); let s = RequestStatus::Requested { deposit: Some((noter, deposit)), count: 1, len: Some(MAX_SIZE) }; assert_eq!(StatusFor::::get(&hash), Some(s)); @@ -111,26 +129,40 @@ benchmarks! { // 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_ok!(Preimage::::note_preimage( + T::ManagerOrigin::try_successful_origin() + .expect("ManagerOrigin has no successful origin required for the benchmark"), + preimage, + )); + }: request_preimage( + T::ManagerOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, + hash + ) verify { let s = RequestStatus::Requested { deposit: None, count: 2, len: Some(MAX_SIZE) }; assert_eq!(StatusFor::::get(&hash), Some(s)); } // 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 { + }: request_preimage( + T::ManagerOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, + hash + ) verify { let s = RequestStatus::Requested { deposit: None, count: 1, len: None }; assert_eq!(StatusFor::::get(&hash), Some(s)); } // 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)); - }: request_preimage(T::ManagerOrigin::successful_origin(), hash) - verify { + assert_ok!(Preimage::::request_preimage( + T::ManagerOrigin::try_successful_origin() + .expect("ManagerOrigin has no successful origin required for the benchmark"), + hash, + )); + }: request_preimage( + T::ManagerOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, + hash + ) verify { let s = RequestStatus::Requested { deposit: None, count: 2, len: None }; assert_eq!(StatusFor::::get(&hash), Some(s)); } @@ -138,27 +170,53 @@ 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)); - assert_ok!(Preimage::::note_preimage(T::ManagerOrigin::successful_origin(), preimage)); - }: _(T::ManagerOrigin::successful_origin(), hash) - verify { + assert_ok!(Preimage::::request_preimage( + T::ManagerOrigin::try_successful_origin() + .expect("ManagerOrigin has no successful origin required for the benchmark"), + hash, + )); + assert_ok!(Preimage::::note_preimage( + T::ManagerOrigin::try_successful_origin() + .expect("ManagerOrigin has no successful origin required for the benchmark"), + preimage, + )); + }: _( + T::ManagerOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, + 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)); - }: unrequest_preimage(T::ManagerOrigin::successful_origin(), hash) - verify { + assert_ok!(Preimage::::request_preimage( + T::ManagerOrigin::try_successful_origin() + .expect("ManagerOrigin has no successful origin required for the benchmark"), + hash, + )); + }: unrequest_preimage( + T::ManagerOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, + 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)); - assert_ok!(Preimage::::request_preimage(T::ManagerOrigin::successful_origin(), hash)); - }: unrequest_preimage(T::ManagerOrigin::successful_origin(), hash) - verify { + assert_ok!(Preimage::::request_preimage( + T::ManagerOrigin::try_successful_origin() + .expect("ManagerOrigin has no successful origin required for the benchmark"), + hash, + )); + assert_ok!(Preimage::::request_preimage( + T::ManagerOrigin::try_successful_origin() + .expect("ManagerOrigin has no successful origin required for the benchmark"), + hash, + )); + }: unrequest_preimage( + T::ManagerOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, + hash + ) verify { let s = RequestStatus::Requested { deposit: None, count: 1, len: None }; assert_eq!(StatusFor::::get(&hash), Some(s)); } diff --git a/frame/ranked-collective/src/benchmarking.rs b/frame/ranked-collective/src/benchmarking.rs index 48df7f1f1e6ab..ad81325becb5e 100644 --- a/frame/ranked-collective/src/benchmarking.rs +++ b/frame/ranked-collective/src/benchmarking.rs @@ -21,7 +21,9 @@ use super::*; #[allow(unused_imports)] use crate::Pallet as RankedCollective; -use frame_benchmarking::v1::{account, benchmarks_instance_pallet, whitelisted_caller}; +use frame_benchmarking::v1::{ + account, benchmarks_instance_pallet, whitelisted_caller, BenchmarkError, +}; use frame_support::{assert_ok, dispatch::UnfilteredDispatchable}; use frame_system::RawOrigin as SystemOrigin; @@ -35,13 +37,15 @@ fn make_member, I: 'static>(rank: Rank) -> T::AccountId { let who = account::("member", MemberCount::::get(0), SEED); let who_lookup = T::Lookup::unlookup(who.clone()); assert_ok!(Pallet::::add_member( - T::PromoteOrigin::successful_origin(), - who_lookup.clone() + T::PromoteOrigin::try_successful_origin() + .expect("PromoteOrigin has no successful origin required for the benchmark"), + who_lookup.clone(), )); for _ in 0..rank { assert_ok!(Pallet::::promote_member( - T::PromoteOrigin::successful_origin(), - who_lookup.clone() + T::PromoteOrigin::try_successful_origin() + .expect("PromoteOrigin has no successful origin required for the benchmark"), + who_lookup.clone(), )); } who @@ -51,7 +55,8 @@ 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 origin = + T::PromoteOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; let call = Call::::add_member { who: who_lookup }; }: { call.dispatch_bypass_filter(origin)? } verify { @@ -67,7 +72,8 @@ benchmarks_instance_pallet! { 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 origin = + T::DemoteOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; let call = Call::::remove_member { who: who_lookup, min_rank: rank }; }: { call.dispatch_bypass_filter(origin)? } verify { @@ -83,7 +89,8 @@ benchmarks_instance_pallet! { 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 origin = + T::PromoteOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; let call = Call::::promote_member { who: who_lookup }; }: { call.dispatch_bypass_filter(origin)? } verify { @@ -99,7 +106,8 @@ benchmarks_instance_pallet! { 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 origin = + T::DemoteOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; let call = Call::::demote_member { who: who_lookup }; }: { call.dispatch_bypass_filter(origin)? } verify { @@ -115,14 +123,19 @@ benchmarks_instance_pallet! { vote { let caller: T::AccountId = whitelisted_caller(); let caller_lookup = T::Lookup::unlookup(caller.clone()); - assert_ok!(Pallet::::add_member(T::PromoteOrigin::successful_origin(), caller_lookup.clone())); + assert_ok!(Pallet::::add_member( + T::PromoteOrigin::try_successful_origin() + .expect("PromoteOrigin has no successful origin required for the benchmark"), + 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_lookup.clone() + T::PromoteOrigin::try_successful_origin() + .expect("PromoteOrigin has no successful origin required for the benchmark"), + caller_lookup.clone(), )); } diff --git a/frame/ranked-collective/src/lib.rs b/frame/ranked-collective/src/lib.rs index b057a57508023..84be1243c8afc 100644 --- a/frame/ranked-collective/src/lib.rs +++ b/frame/ranked-collective/src/lib.rs @@ -259,19 +259,6 @@ impl, I: 'static, const MIN_RANK: u16> EnsureOrigin::get(MIN_RANK, 0).ok_or(())?; Ok(frame_system::RawOrigin::Signed(who).into()) } - - #[cfg(feature = "runtime-benchmarks")] - fn successful_origin() -> T::RuntimeOrigin { - 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 @@ -295,19 +282,6 @@ impl, I: 'static, const MIN_RANK: u16> EnsureOrigin::get(MIN_RANK, 0).ok_or(())?; Ok(frame_system::RawOrigin::Signed(who).into()) } - - #[cfg(feature = "runtime-benchmarks")] - fn successful_origin() -> T::RuntimeOrigin { - 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 both the @@ -331,19 +305,6 @@ impl, I: 'static, const MIN_RANK: u16> EnsureOrigin::get(MIN_RANK, 0).ok_or(())?; Ok(frame_system::RawOrigin::Signed(who).into()) } - - #[cfg(feature = "runtime-benchmarks")] - fn successful_origin() -> T::RuntimeOrigin { - 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] diff --git a/frame/referenda/src/benchmarking.rs b/frame/referenda/src/benchmarking.rs index db5299e0d5bb2..62b37857f2567 100644 --- a/frame/referenda/src/benchmarking.rs +++ b/frame/referenda/src/benchmarking.rs @@ -20,7 +20,9 @@ use super::*; use crate::Pallet as Referenda; use assert_matches::assert_matches; -use frame_benchmarking::v1::{account, benchmarks_instance_pallet, whitelist_account}; +use frame_benchmarking::v1::{ + account, benchmarks_instance_pallet, whitelist_account, BenchmarkError, +}; use frame_support::{ assert_ok, dispatch::UnfilteredDispatchable, @@ -48,8 +50,7 @@ fn dummy_call, I: 'static>() -> Bounded<>::RuntimeCa T::Preimages::bound(call).unwrap() } -fn create_referendum, I: 'static>() -> (T::RuntimeOrigin, ReferendumIndex) { - let origin: T::RuntimeOrigin = T::SubmitOrigin::successful_origin(); +fn create_referendum, I: 'static>(origin: T::RuntimeOrigin) -> ReferendumIndex { if let Ok(caller) = frame_system::ensure_signed(origin.clone()) { T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); whitelist_account!(caller); @@ -61,7 +62,7 @@ fn create_referendum, I: 'static>() -> (T::RuntimeOrigin, Referendu 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) + index } fn place_deposit, I: 'static>(index: ReferendumIndex) { @@ -75,6 +76,7 @@ fn nudge, I: 'static>(index: ReferendumIndex) { } fn fill_queue, I: 'static>( + origin: T::RuntimeOrigin, index: ReferendumIndex, spaces: u32, pass_after: u32, @@ -82,7 +84,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 (_origin, index) = create_referendum::(); + let index = create_referendum::(origin.clone()); place_deposit::(index); others.push(index); } @@ -90,7 +92,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 (_origin, index) = create_referendum::(); + let index = create_referendum::(origin.clone()); place_deposit::(index); make_passing_after::(index, Perbill::from_percent(pass_after)); others.push(index); @@ -194,7 +196,8 @@ fn is_not_confirming, I: 'static>(index: ReferendumIndex) -> bool { benchmarks_instance_pallet! { submit { - let origin: T::RuntimeOrigin = T::SubmitOrigin::successful_origin(); + let origin = + T::SubmitOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; if let Ok(caller) = frame_system::ensure_signed(origin.clone()) { T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); whitelist_account!(caller); @@ -210,15 +213,19 @@ benchmarks_instance_pallet! { } place_decision_deposit_preparing { - let (origin, index) = create_referendum::(); + let origin = + T::SubmitOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; + let index = create_referendum::(origin.clone()); }: place_decision_deposit(origin, index) verify { assert!(Referenda::::ensure_ongoing(index).unwrap().decision_deposit.is_some()); } place_decision_deposit_queued { - let (origin, index) = create_referendum::(); - fill_queue::(index, 1, 90); + let origin = + T::SubmitOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; + let index = create_referendum::(origin.clone()); + fill_queue::(origin.clone(), index, 1, 90); }: place_decision_deposit(origin, index) verify { let track = Referenda::::ensure_ongoing(index).unwrap().track; @@ -227,8 +234,10 @@ benchmarks_instance_pallet! { } place_decision_deposit_not_queued { - let (origin, index) = create_referendum::(); - fill_queue::(index, 0, 90); + let origin = + T::SubmitOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; + let index = create_referendum::(origin.clone()); + fill_queue::(origin.clone(), index, 0, 90); 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)); @@ -239,7 +248,9 @@ benchmarks_instance_pallet! { } place_decision_deposit_passing { - let (origin, index) = create_referendum::(); + let origin = + T::SubmitOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; + let index = create_referendum::(origin.clone()); skip_prepare_period::(index); make_passing::(index); }: place_decision_deposit(origin, index) @@ -248,7 +259,9 @@ benchmarks_instance_pallet! { } place_decision_deposit_failing { - let (origin, index) = create_referendum::(); + let origin = + T::SubmitOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; + let index = create_referendum::(origin.clone()); skip_prepare_period::(index); }: place_decision_deposit(origin, index) verify { @@ -256,19 +269,31 @@ benchmarks_instance_pallet! { } refund_decision_deposit { - let (origin, index) = create_referendum::(); + let origin = + T::SubmitOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; + let index = create_referendum::(origin.clone()); place_deposit::(index); - assert_ok!(Referenda::::cancel(T::CancelOrigin::successful_origin(), index)); + assert_ok!(Referenda::::cancel( + T::CancelOrigin::try_successful_origin() + .expect("CancelOrigin has no successful origin required for the benchmark"), + index, + )); }: _(origin, index) verify { assert_matches!(ReferendumInfoFor::::get(index), Some(ReferendumInfo::Cancelled(_, _, None))); } refund_submission_deposit { - let (origin, index) = create_referendum::(); + let origin = + T::SubmitOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; + let index = create_referendum::(origin.clone()); 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_ok!(Referenda::::cancel( + T::CancelOrigin::try_successful_origin() + .expect("CancelOrigin has no successful origin required for the benchmark"), + index, + )); assert_matches!(ReferendumInfoFor::::get(index), Some(ReferendumInfo::Cancelled(_, Some(_), _))); }: _(origin, index) verify { @@ -279,28 +304,42 @@ benchmarks_instance_pallet! { } cancel { - let (_origin, index) = create_referendum::(); + let origin = T::SubmitOrigin::try_successful_origin() + .expect("SubmitOrigin has no successful origin required for the benchmark"); + let index = create_referendum::(origin); place_deposit::(index); - }: _(T::CancelOrigin::successful_origin(), index) - verify { + }: _( + T::CancelOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, + index + ) verify { assert_matches!(ReferendumInfoFor::::get(index), Some(ReferendumInfo::Cancelled(..))); } kill { - let (_origin, index) = create_referendum::(); + let origin = T::SubmitOrigin::try_successful_origin() + .expect("SubmitOrigin has no successful origin required for the benchmark"); + let index = create_referendum::(origin); place_deposit::(index); - }: _(T::KillOrigin::successful_origin(), index) - verify { + }: _( + T::KillOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, + index + ) verify { assert_matches!(ReferendumInfoFor::::get(index), Some(ReferendumInfo::Killed(..))); } one_fewer_deciding_queue_empty { - let (_origin, index) = create_referendum::(); + let origin = T::SubmitOrigin::try_successful_origin() + .expect("SubmitOrigin has no successful origin required for the benchmark"); + let index = create_referendum::(origin); 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_ok!(Referenda::::cancel( + T::CancelOrigin::try_successful_origin() + .expect("CancelOrigin has no successful origin required for the benchmark"), + index, + )); assert_eq!(DecidingCount::::get(&track), 1); }: one_fewer_deciding(RawOrigin::Root, track) verify { @@ -308,11 +347,17 @@ benchmarks_instance_pallet! { } one_fewer_deciding_failing { - let (_origin, index) = create_referendum::(); + let origin = T::SubmitOrigin::try_successful_origin() + .expect("SubmitOrigin has no successful origin required for the benchmark"); + let index = create_referendum::(origin.clone()); // No spaces free in the queue. - let queued = fill_queue::(index, 0, 90); + let queued = fill_queue::(origin, index, 0, 90); let track = Referenda::::ensure_ongoing(index).unwrap().track; - assert_ok!(Referenda::::cancel(T::CancelOrigin::successful_origin(), queued[0])); + assert_ok!(Referenda::::cancel( + T::CancelOrigin::try_successful_origin() + .expect("CancelOrigin has no successful origin required for the benchmark"), + 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) @@ -327,11 +372,17 @@ benchmarks_instance_pallet! { } one_fewer_deciding_passing { - let (_origin, index) = create_referendum::(); + let origin = T::SubmitOrigin::try_successful_origin() + .expect("SubmitOrigin has no successful origin required for the benchmark"); + let index = create_referendum::(origin.clone()); // No spaces free in the queue. - let queued = fill_queue::(index, 0, 0); + let queued = fill_queue::(origin, index, 0, 0); let track = Referenda::::ensure_ongoing(index).unwrap().track; - assert_ok!(Referenda::::cancel(T::CancelOrigin::successful_origin(), queued[0])); + assert_ok!(Referenda::::cancel( + T::CancelOrigin::try_successful_origin() + .expect("CancelOrigin has no successful origin required for the benchmark"), + 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) @@ -346,10 +397,12 @@ benchmarks_instance_pallet! { } nudge_referendum_requeued_insertion { + let origin = T::SubmitOrigin::try_successful_origin() + .expect("SubmitOrigin has no successful origin required for the benchmark"); // First create our referendum and place the deposit. It will be failing. - let (_origin, index) = create_referendum::(); + let index = create_referendum::(origin.clone()); place_deposit::(index); - fill_queue::(index, 0, 90); + fill_queue::(origin, 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. @@ -367,10 +420,12 @@ benchmarks_instance_pallet! { } nudge_referendum_requeued_slide { + let origin = T::SubmitOrigin::try_successful_origin() + .expect("SubmitOrigin has no successful origin required for the benchmark"); // First create our referendum and place the deposit. It will be failing. - let (_origin, index) = create_referendum::(); + let index = create_referendum::(origin.clone()); place_deposit::(index); - fill_queue::(index, 1, 90); + fill_queue::(origin, 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. @@ -393,10 +448,12 @@ benchmarks_instance_pallet! { // free and this failing. It would result in `QUEUE_SIZE - 1` items being shifted for the // insertion at the beginning. + let origin = T::SubmitOrigin::try_successful_origin() + .expect("SubmitOrigin has no successful origin required for the benchmark"); // First create our referendum and place the deposit. It will be failing. - let (_origin, index) = create_referendum::(); + let index = create_referendum::(origin.clone()); place_deposit::(index); - fill_queue::(index, 1, 0); + fill_queue::(origin, index, 1, 0); let track = Referenda::::ensure_ongoing(index).unwrap().track; assert_eq!(TrackQueue::::get(&track).len() as u32, T::MaxQueued::get() - 1); @@ -410,10 +467,12 @@ benchmarks_instance_pallet! { } nudge_referendum_not_queued { + let origin = T::SubmitOrigin::try_successful_origin() + .expect("SubmitOrigin has no successful origin required for the benchmark"); // First create our referendum and place the deposit. It will be failing. - let (_origin, index) = create_referendum::(); + let index = create_referendum::(origin.clone()); place_deposit::(index); - fill_queue::(index, 0, 0); + fill_queue::(origin, index, 0, 0); let track = Referenda::::ensure_ongoing(index).unwrap().track; assert_eq!(TrackQueue::::get(&track).len() as u32, T::MaxQueued::get()); @@ -427,7 +486,9 @@ benchmarks_instance_pallet! { } nudge_referendum_no_deposit { - let (_origin, index) = create_referendum::(); + let origin = T::SubmitOrigin::try_successful_origin() + .expect("SubmitOrigin has no successful origin required for the benchmark"); + let index = create_referendum::(origin); skip_prepare_period::(index); }: nudge_referendum(RawOrigin::Root, index) verify { @@ -436,7 +497,9 @@ benchmarks_instance_pallet! { } nudge_referendum_preparing { - let (_origin, index) = create_referendum::(); + let origin = T::SubmitOrigin::try_successful_origin() + .expect("SubmitOrigin has no successful origin required for the benchmark"); + let index = create_referendum::(origin); place_deposit::(index); }: nudge_referendum(RawOrigin::Root, index) verify { @@ -445,7 +508,9 @@ benchmarks_instance_pallet! { } nudge_referendum_timed_out { - let (_origin, index) = create_referendum::(); + let origin = T::SubmitOrigin::try_successful_origin() + .expect("SubmitOrigin has no successful origin required for the benchmark"); + let index = create_referendum::(origin); skip_timeout_period::(index); }: nudge_referendum(RawOrigin::Root, index) verify { @@ -454,7 +519,9 @@ benchmarks_instance_pallet! { } nudge_referendum_begin_deciding_failing { - let (_origin, index) = create_referendum::(); + let origin = T::SubmitOrigin::try_successful_origin() + .expect("SubmitOrigin has no successful origin required for the benchmark"); + let index = create_referendum::(origin); place_deposit::(index); skip_prepare_period::(index); }: nudge_referendum(RawOrigin::Root, index) @@ -463,7 +530,9 @@ benchmarks_instance_pallet! { } nudge_referendum_begin_deciding_passing { - let (_origin, index) = create_referendum::(); + let origin = T::SubmitOrigin::try_successful_origin() + .expect("SubmitOrigin has no successful origin required for the benchmark"); + let index = create_referendum::(origin); place_deposit::(index); make_passing::(index); skip_prepare_period::(index); @@ -473,7 +542,9 @@ benchmarks_instance_pallet! { } nudge_referendum_begin_confirming { - let (_origin, index) = create_referendum::(); + let origin = T::SubmitOrigin::try_successful_origin() + .expect("SubmitOrigin has no successful origin required for the benchmark"); + let index = create_referendum::(origin); place_deposit::(index); skip_prepare_period::(index); nudge::(index); @@ -485,7 +556,9 @@ benchmarks_instance_pallet! { } nudge_referendum_end_confirming { - let (_origin, index) = create_referendum::(); + let origin = T::SubmitOrigin::try_successful_origin() + .expect("SubmitOrigin has no successful origin required for the benchmark"); + let index = create_referendum::(origin); place_deposit::(index); skip_prepare_period::(index); make_passing::(index); @@ -498,7 +571,9 @@ benchmarks_instance_pallet! { } nudge_referendum_continue_not_confirming { - let (_origin, index) = create_referendum::(); + let origin = T::SubmitOrigin::try_successful_origin() + .expect("SubmitOrigin has no successful origin required for the benchmark"); + let index = create_referendum::(origin); place_deposit::(index); skip_prepare_period::(index); nudge::(index); @@ -512,7 +587,9 @@ benchmarks_instance_pallet! { } nudge_referendum_continue_confirming { - let (_origin, index) = create_referendum::(); + let origin = T::SubmitOrigin::try_successful_origin() + .expect("SubmitOrigin has no successful origin required for the benchmark"); + let index = create_referendum::(origin); place_deposit::(index); make_passing::(index); skip_prepare_period::(index); @@ -525,7 +602,9 @@ benchmarks_instance_pallet! { } nudge_referendum_approved { - let (_origin, index) = create_referendum::(); + let origin = T::SubmitOrigin::try_successful_origin() + .expect("SubmitOrigin has no successful origin required for the benchmark"); + let index = create_referendum::(origin); place_deposit::(index); skip_prepare_period::(index); make_passing::(index); @@ -538,7 +617,9 @@ benchmarks_instance_pallet! { } nudge_referendum_rejected { - let (_origin, index) = create_referendum::(); + let origin = T::SubmitOrigin::try_successful_origin() + .expect("SubmitOrigin has no successful origin required for the benchmark"); + let index = create_referendum::(origin); place_deposit::(index); skip_prepare_period::(index); make_failing::(index); diff --git a/frame/scheduler/src/benchmarking.rs b/frame/scheduler/src/benchmarking.rs index 9ec82f5c8447e..94a833bd98e0a 100644 --- a/frame/scheduler/src/benchmarking.rs +++ b/frame/scheduler/src/benchmarking.rs @@ -18,7 +18,7 @@ //! Scheduler pallet benchmarking. use super::*; -use frame_benchmarking::v1::{account, benchmarks}; +use frame_benchmarking::v1::{account, benchmarks, BenchmarkError}; use frame_support::{ ensure, traits::{schedule::Priority, BoundedInline}, @@ -244,7 +244,8 @@ benchmarks! { fill_schedule::(when, s)?; assert_eq!(Agenda::::get(when).len(), s as usize); - let schedule_origin = T::ScheduleOrigin::successful_origin(); + let schedule_origin = + T::ScheduleOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; }: _>(schedule_origin, when, 0) verify { ensure!( diff --git a/frame/support/src/traits/dispatch.rs b/frame/support/src/traits/dispatch.rs index 36ddf5b507c0c..50c6c22791944 100644 --- a/frame/support/src/traits/dispatch.rs +++ b/frame/support/src/traits/dispatch.rs @@ -40,25 +40,12 @@ pub trait EnsureOrigin { /// Perform the origin check. fn try_origin(o: OuterOrigin) -> Result; - /// Returns an outer origin capable of passing `try_origin` check. - /// - /// NOTE: This should generally *NOT* be reimplemented. Instead implement - /// `try_successful_origin`. + /// Attempt to get an outer origin capable of passing `try_origin` check. May return `Err` if it + /// is impossible. /// /// ** Should be used for benchmarking only!!! ** #[cfg(feature = "runtime-benchmarks")] - 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()) - } + fn try_successful_origin() -> Result; } /// [`EnsureOrigin`] implementation that always fails. @@ -171,25 +158,12 @@ pub trait EnsureOriginWithArg { /// 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. - /// - /// 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 { - 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()`. + /// Attempt to get an outer origin capable of passing `try_origin` check. May return `Err` if it + /// is impossible. /// /// ** Should be used for benchmarking only!!! ** #[cfg(feature = "runtime-benchmarks")] - fn try_successful_origin(a: &Argument) -> Result { - Ok(Self::successful_origin(a)) - } + fn try_successful_origin(a: &Argument) -> Result; } pub struct AsEnsureOriginWithArg(sp_std::marker::PhantomData); diff --git a/frame/system/src/tests.rs b/frame/system/src/tests.rs index 8223f66744151..f441e785599eb 100644 --- a/frame/system/src/tests.rs +++ b/frame/system/src/tests.rs @@ -679,10 +679,13 @@ fn ensure_signed_stuff_works() { #[cfg(feature = "runtime-benchmarks")] { - let successful_origin: RuntimeOrigin = EnsureSigned::successful_origin(); + let successful_origin: RuntimeOrigin = EnsureSigned::try_successful_origin() + .expect("EnsureSigned has no successful origin required for the test"); assert_ok!(EnsureSigned::try_origin(successful_origin)); - let successful_origin: RuntimeOrigin = EnsureSignedBy::::successful_origin(); + let successful_origin: RuntimeOrigin = + EnsureSignedBy::::try_successful_origin() + .expect("EnsureSignedBy has no successful origin required for the test"); assert_ok!(EnsureSignedBy::::try_origin(successful_origin)); } } diff --git a/frame/tips/src/benchmarking.rs b/frame/tips/src/benchmarking.rs index 8ffc53b45e4ca..5b1a102b8eb30 100644 --- a/frame/tips/src/benchmarking.rs +++ b/frame/tips/src/benchmarking.rs @@ -19,7 +19,9 @@ #![cfg(feature = "runtime-benchmarks")] -use frame_benchmarking::v1::{account, benchmarks_instance_pallet, whitelisted_caller}; +use frame_benchmarking::v1::{ + account, benchmarks_instance_pallet, whitelisted_caller, BenchmarkError, +}; use frame_support::ensure; use frame_system::RawOrigin; use sp_runtime::traits::Saturating; @@ -196,7 +198,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"); - let reject_origin = T::RejectOrigin::successful_origin(); + let reject_origin = + T::RejectOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; }: _(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 eb44744506bf4..0947618a2b02f 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::v1::{account, benchmarks_instance_pallet}; +use frame_benchmarking::v1::{account, benchmarks_instance_pallet, BenchmarkError}; use frame_support::{ dispatch::UnfilteredDispatchable, ensure, @@ -99,7 +99,8 @@ benchmarks_instance_pallet! { beneficiary_lookup )?; let proposal_id = Treasury::::proposal_count() - 1; - let reject_origin = T::RejectOrigin::successful_origin(); + let reject_origin = + T::RejectOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; }: _(reject_origin, proposal_id) approve_proposal { @@ -112,7 +113,8 @@ benchmarks_instance_pallet! { beneficiary_lookup )?; let proposal_id = Treasury::::proposal_count() - 1; - let approve_origin = T::ApproveOrigin::successful_origin(); + let approve_origin = + T::ApproveOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; }: _(approve_origin, proposal_id) remove_approval { @@ -124,7 +126,8 @@ 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(); + let reject_origin = + T::RejectOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; }: _(reject_origin, proposal_id) on_initialize_proposals { diff --git a/frame/uniques/src/benchmarking.rs b/frame/uniques/src/benchmarking.rs index 5ecb093a5d010..2656582f0e073 100644 --- a/frame/uniques/src/benchmarking.rs +++ b/frame/uniques/src/benchmarking.rs @@ -21,7 +21,7 @@ use super::*; use frame_benchmarking::v1::{ - account, benchmarks_instance_pallet, whitelist_account, whitelisted_caller, + account, benchmarks_instance_pallet, whitelist_account, whitelisted_caller, BenchmarkError, }; use frame_support::{ dispatch::UnfilteredDispatchable, @@ -137,7 +137,8 @@ fn assert_last_event, I: 'static>(generic_event: >:: benchmarks_instance_pallet! { create { let collection = T::Helper::collection(0); - let origin = T::CreateOrigin::successful_origin(&collection); + let origin = T::CreateOrigin::try_successful_origin(&collection) + .map_err(|_| BenchmarkError::Weightless)?; let caller = T::CreateOrigin::ensure_origin(origin.clone(), &collection).unwrap(); whitelist_account!(caller); let admin = T::Lookup::unlookup(caller.clone()); @@ -290,7 +291,8 @@ benchmarks_instance_pallet! { force_item_status { let (collection, caller, caller_lookup) = create_collection::(); - let origin = T::ForceOrigin::successful_origin(); + let origin = + T::ForceOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; let call = Call::::force_item_status { collection, owner: caller_lookup.clone(), diff --git a/frame/whitelist/src/benchmarking.rs b/frame/whitelist/src/benchmarking.rs index e64842b34df59..582f4a7997c67 100644 --- a/frame/whitelist/src/benchmarking.rs +++ b/frame/whitelist/src/benchmarking.rs @@ -20,7 +20,7 @@ #![cfg(feature = "runtime-benchmarks")] use super::*; -use frame_benchmarking::v1::benchmarks; +use frame_benchmarking::v1::{benchmarks, BenchmarkError}; use frame_support::{ensure, traits::EnsureOrigin}; #[cfg(test)] @@ -28,7 +28,8 @@ use crate::Pallet as Whitelist; benchmarks! { whitelist_call { - let origin = T::WhitelistOrigin::successful_origin(); + let origin = + T::WhitelistOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; let call_hash = Default::default(); }: _(origin, call_hash) verify { @@ -43,7 +44,8 @@ benchmarks! { } remove_whitelisted_call { - let origin = T::WhitelistOrigin::successful_origin(); + let origin = + T::WhitelistOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; let call_hash = Default::default(); Pallet::::whitelist_call(origin.clone(), call_hash) .expect("whitelisting call must be successful"); @@ -70,7 +72,8 @@ benchmarks! { // NOTE: we remove `10` because we need some bytes to encode the variants and vec length let n in 1 .. T::Preimages::MAX_LENGTH as u32 - 10; - let origin = T::DispatchWhitelistedOrigin::successful_origin(); + let origin = T::DispatchWhitelistedOrigin::try_successful_origin() + .map_err(|_| BenchmarkError::Weightless)?; 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; @@ -98,7 +101,8 @@ benchmarks! { dispatch_whitelisted_call_with_preimage { let n in 1 .. 10_000; - let origin = T::DispatchWhitelistedOrigin::successful_origin(); + let origin = T::DispatchWhitelistedOrigin::try_successful_origin() + .map_err(|_| BenchmarkError::Weightless)?; let remark = sp_std::vec![1u8; n as usize]; let call: ::RuntimeCall = frame_system::Call::remark { remark }.into(); From c4b2db5a050dad1129a18ebe9c4e3013038e1ad1 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Wed, 1 Feb 2023 10:38:41 -0300 Subject: [PATCH 350/715] hooks default impl missing where clause (#13264) * hooks default impl missing where clause * add tests * Update frame/support/test/tests/pallet_ui/pass/where_clause_missing_hooks.rs --------- Co-authored-by: parity-processbot <> --- .../procedural/src/pallet/expand/hooks.rs | 2 +- .../tests/pallet_ui/duplicate_store_attr.rs | 3 +-- .../pass/where_clause_missing_hooks.rs | 19 +++++++++++++++++++ 3 files changed, 21 insertions(+), 3 deletions(-) create mode 100644 frame/support/test/tests/pallet_ui/pass/where_clause_missing_hooks.rs diff --git a/frame/support/procedural/src/pallet/expand/hooks.rs b/frame/support/procedural/src/pallet/expand/hooks.rs index c41a65b57b57a..987d0691b1ecc 100644 --- a/frame/support/procedural/src/pallet/expand/hooks.rs +++ b/frame/support/procedural/src/pallet/expand/hooks.rs @@ -76,7 +76,7 @@ pub fn expand_hooks(def: &mut Def) -> proc_macro2::TokenStream { quote::quote! { impl<#type_impl_gen> #frame_support::traits::Hooks<::BlockNumber> - for Pallet<#type_use_gen> {} + for #pallet_ident<#type_use_gen> #where_clause {} } } else { proc_macro2::TokenStream::new() diff --git a/frame/support/test/tests/pallet_ui/duplicate_store_attr.rs b/frame/support/test/tests/pallet_ui/duplicate_store_attr.rs index d675ddefe985b..ab318034aca05 100644 --- a/frame/support/test/tests/pallet_ui/duplicate_store_attr.rs +++ b/frame/support/test/tests/pallet_ui/duplicate_store_attr.rs @@ -22,5 +22,4 @@ mod pallet { type Foo = StorageValue<_, u8>; } -fn main() { -} +fn main() {} diff --git a/frame/support/test/tests/pallet_ui/pass/where_clause_missing_hooks.rs b/frame/support/test/tests/pallet_ui/pass/where_clause_missing_hooks.rs new file mode 100644 index 0000000000000..bf5f22306207a --- /dev/null +++ b/frame/support/test/tests/pallet_ui/pass/where_clause_missing_hooks.rs @@ -0,0 +1,19 @@ +#[frame_support::pallet] +mod pallet { + #[pallet::config] + pub trait Config: frame_system::Config where ::Index: From {} + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::call] + impl Pallet where ::Index: From {} + + impl Pallet where ::Index: From { + fn foo(x: u128) { + let _index = ::Index::from(x); + } + } +} + +fn main() {} From b2b2e650f204d9ee2a7b67f5b9cc6ab146ded877 Mon Sep 17 00:00:00 2001 From: Matteo Muraca <56828990+muraca@users.noreply.github.com> Date: Wed, 1 Feb 2023 18:11:34 +0100 Subject: [PATCH 351/715] implemented `contains_prefix` for StorageDoubleMap and StorageNMap (#13232) * implemented `contains_prefix` for StorageDoubleMap and StorageNMap Signed-off-by: muraca * match prefix to next_key Signed-off-by: muraca * warning unexpected behaviour with empty keys Signed-off-by: muraca * clarifications for unhashed::contains_prefixed_key Signed-off-by: muraca * added tests for StorageNMap Signed-off-by: muraca --------- Signed-off-by: muraca --- .../src/storage/generator/double_map.rs | 7 +++ frame/support/src/storage/generator/nmap.rs | 7 +++ frame/support/src/storage/mod.rs | 47 ++++++++++++++++++- frame/support/src/storage/unhashed.rs | 10 ++++ 4 files changed, 70 insertions(+), 1 deletion(-) diff --git a/frame/support/src/storage/generator/double_map.rs b/frame/support/src/storage/generator/double_map.rs index c95dcee9d7e5c..b60bb79566d51 100644 --- a/frame/support/src/storage/generator/double_map.rs +++ b/frame/support/src/storage/generator/double_map.rs @@ -233,6 +233,13 @@ where .into() } + fn contains_prefix(k1: KArg1) -> bool + where + KArg1: EncodeLike, + { + unhashed::contains_prefixed_key(Self::storage_double_map_final_key1(k1).as_ref()) + } + fn iter_prefix_values(k1: KArg1) -> storage::PrefixIterator where KArg1: ?Sized + EncodeLike, diff --git a/frame/support/src/storage/generator/nmap.rs b/frame/support/src/storage/generator/nmap.rs index 79f3d72044e28..8cf1459431171 100755 --- a/frame/support/src/storage/generator/nmap.rs +++ b/frame/support/src/storage/generator/nmap.rs @@ -208,6 +208,13 @@ where ) } + fn contains_prefix(partial_key: KP) -> bool + where + K: HasKeyPrefix, + { + unhashed::contains_prefixed_key(&Self::storage_n_map_partial_key(partial_key)) + } + fn iter_prefix_values(partial_key: KP) -> PrefixIterator where K: HasKeyPrefix, diff --git a/frame/support/src/storage/mod.rs b/frame/support/src/storage/mod.rs index 28f2dee992281..dd91d8cc2a335 100644 --- a/frame/support/src/storage/mod.rs +++ b/frame/support/src/storage/mod.rs @@ -563,6 +563,12 @@ pub trait StorageDoubleMap { where KArg1: ?Sized + EncodeLike; + /// Does any value under the first key `k1` (explicitly) exist in storage? + /// Might have unexpected behaviour with empty keys, e.g. `[]`. + fn contains_prefix(k1: KArg1) -> bool + where + KArg1: EncodeLike; + /// Iterate over values that share the first key. fn iter_prefix_values(k1: KArg1) -> PrefixIterator where @@ -739,6 +745,12 @@ pub trait StorageNMap { where K: HasKeyPrefix; + /// Does any value under a `partial_key` prefix (explicitly) exist in storage? + /// Might have unexpected behaviour with empty keys, e.g. `[]`. + fn contains_prefix(partial_key: KP) -> bool + where + K: HasKeyPrefix; + /// Iterate over values that share the partial prefix key. fn iter_prefix_values(partial_key: KP) -> PrefixIterator where @@ -1485,7 +1497,7 @@ 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_ok, hash::Identity, pallet_prelude::NMapKey, Twox128}; use bounded_vec::BoundedVec; use frame_support::traits::ConstU32; use generator::StorageValue as _; @@ -1780,6 +1792,39 @@ mod test { #[crate::storage_alias] type FooDoubleMap = StorageDoubleMap>>; + #[crate::storage_alias] + type FooTripleMap = StorageNMap< + Prefix, + (NMapKey, NMapKey, NMapKey), + u64, + >; + + #[test] + fn contains_prefix_works() { + TestExternalities::default().execute_with(|| { + // Test double maps + assert!(FooDoubleMap::iter_prefix_values(1).next().is_none()); + assert_eq!(FooDoubleMap::contains_prefix(1), false); + + assert_ok!(FooDoubleMap::try_append(1, 1, 4)); + assert_ok!(FooDoubleMap::try_append(2, 1, 4)); + assert!(FooDoubleMap::iter_prefix_values(1).next().is_some()); + assert!(FooDoubleMap::contains_prefix(1)); + FooDoubleMap::remove(1, 1); + assert_eq!(FooDoubleMap::contains_prefix(1), false); + + // Test N Maps + assert!(FooTripleMap::iter_prefix_values((1,)).next().is_none()); + assert_eq!(FooTripleMap::contains_prefix((1,)), false); + + FooTripleMap::insert((1, 1, 1), 4); + FooTripleMap::insert((2, 1, 1), 4); + assert!(FooTripleMap::iter_prefix_values((1,)).next().is_some()); + assert!(FooTripleMap::contains_prefix((1,))); + FooTripleMap::remove((1, 1, 1)); + assert_eq!(FooTripleMap::contains_prefix((1,)), false); + }); + } #[test] fn try_append_works() { diff --git a/frame/support/src/storage/unhashed.rs b/frame/support/src/storage/unhashed.rs index 850e93e7d7fe4..8388c5f885c51 100644 --- a/frame/support/src/storage/unhashed.rs +++ b/frame/support/src/storage/unhashed.rs @@ -154,6 +154,16 @@ pub fn clear_prefix( MultiRemovalResults { maybe_cursor, backend: i, unique: i, loops: i } } +/// Returns `true` if the storage contains any key, which starts with a certain prefix, +/// and is longer than said prefix. +/// This means that a key which equals the prefix will not be counted. +pub fn contains_prefixed_key(prefix: &[u8]) -> bool { + match sp_io::storage::next_key(prefix) { + Some(key) => key.starts_with(prefix), + None => false, + } +} + /// Get a Vec of bytes from storage. pub fn get_raw(key: &[u8]) -> Option> { sp_io::storage::get(key).map(|value| value.to_vec()) From 3bc3742d5c0c5269353d7809d9f8f91104a93273 Mon Sep 17 00:00:00 2001 From: Sergej Sakac <73715684+Szegoo@users.noreply.github.com> Date: Wed, 1 Feb 2023 18:17:05 +0100 Subject: [PATCH 352/715] Calling proxy doesn't remove announcement (#13267) * Calling proxy doesn't remove announcement * Update frame/proxy/src/tests.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * fmt --------- Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- frame/proxy/src/lib.rs | 2 -- frame/proxy/src/tests.rs | 17 +++++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/frame/proxy/src/lib.rs b/frame/proxy/src/lib.rs index d98534d16a21b..dfe8c86ca5097 100644 --- a/frame/proxy/src/lib.rs +++ b/frame/proxy/src/lib.rs @@ -183,8 +183,6 @@ pub mod pallet { /// Dispatch the given `call` from an account that the sender is authorised for through /// `add_proxy`. /// - /// Removes any corresponding announcement(s). - /// /// The dispatch origin for this call must be _Signed_. /// /// Parameters: diff --git a/frame/proxy/src/tests.rs b/frame/proxy/src/tests.rs index 3eb3ab3705332..0e7db3512f15b 100644 --- a/frame/proxy/src/tests.rs +++ b/frame/proxy/src/tests.rs @@ -288,6 +288,23 @@ fn announcer_must_be_proxy() { }); } +#[test] +fn calling_proxy_doesnt_remove_announcement() { + new_test_ext().execute_with(|| { + assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(1), 2, ProxyType::Any, 0)); + + let call = Box::new(call_transfer(6, 1)); + let call_hash = BlakeTwo256::hash_of(&call); + + assert_ok!(Proxy::announce(RuntimeOrigin::signed(2), 1, call_hash)); + assert_ok!(Proxy::proxy(RuntimeOrigin::signed(2), 1, None, call)); + + // The announcement is not removed by calling proxy. + let announcements = Announcements::::get(2); + assert_eq!(announcements.0, vec![Announcement { real: 1, call_hash, height: 1 }]); + }); +} + #[test] fn delayed_requires_pre_announcement() { new_test_ext().execute_with(|| { From 68d00e2d5132ef32e564e0320e89dfac57e1c46e Mon Sep 17 00:00:00 2001 From: Sergej Sakac <73715684+Szegoo@users.noreply.github.com> Date: Thu, 2 Feb 2023 07:47:49 +0100 Subject: [PATCH 353/715] Fee and tip represented as asset ID inside `AssetTxFeePaid` (#13083) * fee & tip in the asset ID Balance type * docs * rewrite * update runtime config * docs --- .../asset-tx-payment/src/lib.rs | 26 ++++++++++--------- .../asset-tx-payment/src/payment.rs | 17 ++++++++---- 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/frame/transaction-payment/asset-tx-payment/src/lib.rs b/frame/transaction-payment/asset-tx-payment/src/lib.rs index 230b307317f8b..645ebb1e123be 100644 --- a/frame/transaction-payment/asset-tx-payment/src/lib.rs +++ b/frame/transaction-payment/asset-tx-payment/src/lib.rs @@ -134,8 +134,8 @@ pub mod pallet { /// has been paid by `who` in an asset `asset_id`. AssetTxFeePaid { who: T::AccountId, - actual_fee: BalanceOf, - tip: BalanceOf, + actual_fee: AssetBalanceOf, + tip: AssetBalanceOf, asset_id: Option>, }, } @@ -284,18 +284,20 @@ where 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(), - )?; + + let (converted_fee, converted_tip) = + T::OnChargeAssetTransaction::correct_and_deposit_fee( + &who, + info, + post_info, + actual_fee.into(), + tip.into(), + already_withdrawn.into(), + )?; Pallet::::deposit_event(Event::::AssetTxFeePaid { who, - actual_fee, - tip, + actual_fee: converted_fee, + tip: converted_tip, asset_id, }); }, diff --git a/frame/transaction-payment/asset-tx-payment/src/payment.rs b/frame/transaction-payment/asset-tx-payment/src/payment.rs index 85d1bec4b275c..ae8253b6e7d3e 100644 --- a/frame/transaction-payment/asset-tx-payment/src/payment.rs +++ b/frame/transaction-payment/asset-tx-payment/src/payment.rs @@ -58,6 +58,8 @@ pub trait OnChargeAssetTransaction { /// the corrected amount. /// /// Note: The `fee` already includes the `tip`. + /// + /// Returns the fee and tip in the asset used for payment as (fee, tip). fn correct_and_deposit_fee( who: &T::AccountId, dispatch_info: &DispatchInfoOf, @@ -65,7 +67,7 @@ pub trait OnChargeAssetTransaction { corrected_fee: Self::Balance, tip: Self::Balance, already_withdrawn: Self::LiquidityInfo, - ) -> Result<(), TransactionValidityError>; + ) -> Result<(AssetBalanceOf, AssetBalanceOf), TransactionValidityError>; } /// Allows specifying what to do with the withdrawn asset fees. @@ -132,19 +134,24 @@ where /// Since the predicted fee might have been too high, parts of the fee may be refunded. /// /// Note: The `corrected_fee` already includes the `tip`. + /// + /// Returns the fee and tip in the asset used for payment as (fee, tip). fn correct_and_deposit_fee( who: &T::AccountId, _dispatch_info: &DispatchInfoOf, _post_info: &PostDispatchInfoOf, corrected_fee: Self::Balance, - _tip: Self::Balance, + tip: Self::Balance, paid: Self::LiquidityInfo, - ) -> Result<(), TransactionValidityError> { + ) -> Result<(AssetBalanceOf, AssetBalanceOf), 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. + // Convert the corrected fee and tip into the asset used for payment. let converted_fee = CON::to_asset_balance(corrected_fee, paid.asset()) .map_err(|_| -> TransactionValidityError { InvalidTransaction::Payment.into() })? .max(min_converted_fee); + let converted_tip = CON::to_asset_balance(tip, paid.asset()) + .map_err(|_| -> TransactionValidityError { InvalidTransaction::Payment.into() })?; + // 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 @@ -152,6 +159,6 @@ where let _ = >::resolve(who, refund); // Handle the final fee, e.g. by transferring to the block author or burning. HC::handle_credit(final_fee); - Ok(()) + Ok((converted_fee, converted_tip)) } } From 5d0867c7dcdc50572422611128853ccff63ebd4d Mon Sep 17 00:00:00 2001 From: Davirain Date: Thu, 2 Feb 2023 18:07:48 +0800 Subject: [PATCH 354/715] Move beefy-merkle-tree to utils/binary-merkle-tree and make it generic (#13076) * move BeefyMmrApi to pallet-beefy-mmr * fix test_utils use pallet-beefy-mmr BeefyMmrApi * Move beefy-merkle-tree to utils and Rename to Merkle-tree * fix fmt and test * Update merkle-tree to binary-merkle-tree and Remove Keccak256 mod from merkle-tree * change merkle-tree name to binary-merkle-tree * mirr fix --- Cargo.lock | 11 +-- Cargo.toml | 2 +- frame/beefy-mmr/Cargo.toml | 6 +- frame/beefy-mmr/src/lib.rs | 16 +++- frame/beefy-mmr/src/mock.rs | 2 +- test-utils/runtime/Cargo.toml | 4 +- test-utils/runtime/src/lib.rs | 2 +- .../binary-merkle-tree}/Cargo.toml | 14 ++- .../binary-merkle-tree}/src/lib.rs | 89 ++++++++----------- 9 files changed, 75 insertions(+), 71 deletions(-) rename {frame/beefy-mmr/primitives => utils/binary-merkle-tree}/Cargo.toml (58%) rename {frame/beefy-mmr/primitives => utils/binary-merkle-tree}/src/lib.rs (93%) diff --git a/Cargo.lock b/Cargo.lock index 29ddf38328519..a0e9e0e636cdb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -543,14 +543,14 @@ dependencies = [ ] [[package]] -name = "beefy-merkle-tree" +name = "binary-merkle-tree" version = "4.0.0-dev" dependencies = [ "array-bytes", "env_logger", + "hash-db", "log", - "sp-api", - "sp-beefy", + "sp-core", "sp-runtime", ] @@ -5499,7 +5499,7 @@ name = "pallet-beefy-mmr" version = "4.0.0-dev" dependencies = [ "array-bytes", - "beefy-merkle-tree", + "binary-merkle-tree", "frame-support", "frame-system", "log", @@ -5509,6 +5509,7 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", + "sp-api", "sp-beefy", "sp-core", "sp-io", @@ -10699,7 +10700,6 @@ dependencies = [ name = "substrate-test-runtime" version = "2.0.0" dependencies = [ - "beefy-merkle-tree", "cfg-if", "frame-support", "frame-system", @@ -10708,6 +10708,7 @@ dependencies = [ "log", "memory-db", "pallet-babe", + "pallet-beefy-mmr", "pallet-timestamp", "parity-scale-codec", "sc-block-builder", diff --git a/Cargo.toml b/Cargo.toml index b004886e83f9a..f87172b5ebabd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -85,7 +85,6 @@ members = [ "frame/balances", "frame/beefy", "frame/beefy-mmr", - "frame/beefy-mmr/primitives", "frame/benchmarking", "frame/benchmarking/pov", "frame/bounties", @@ -246,6 +245,7 @@ members = [ "utils/frame/rpc/client", "utils/prometheus", "utils/wasm-builder", + "utils/binary-merkle-tree", ] # The list of dependencies below (which can be both direct and indirect dependencies) are crates diff --git a/frame/beefy-mmr/Cargo.toml b/frame/beefy-mmr/Cargo.toml index 54da26c394f0c..1d24e821c5012 100644 --- a/frame/beefy-mmr/Cargo.toml +++ b/frame/beefy-mmr/Cargo.toml @@ -14,7 +14,7 @@ codec = { package = "parity-scale-codec", version = "3.2.2", default-features = 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" } +binary-merkle-tree = { version = "4.0.0-dev", default-features = false, path = "../../utils/binary-merkle-tree" } 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" } @@ -25,6 +25,7 @@ sp-core = { version = "7.0.0", default-features = false, path = "../../primitive 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-api = { version = "4.0.0-dev", default-features = false, path = "../../primitives/api" } [dev-dependencies] array-bytes = "4.1" @@ -34,7 +35,7 @@ sp-staking = { version = "4.0.0-dev", path = "../../primitives/staking" } default = ["std"] std = [ "array-bytes", - "beefy-merkle-tree/std", + "binary-merkle-tree/std", "beefy-primitives/std", "codec/std", "frame-support/std", @@ -49,5 +50,6 @@ std = [ "sp-io/std", "sp-runtime/std", "sp-std/std", + "sp-api/std", ] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/beefy-mmr/src/lib.rs b/frame/beefy-mmr/src/lib.rs index 0b7fc22cd279b..e5506ecd01d6e 100644 --- a/frame/beefy-mmr/src/lib.rs +++ b/frame/beefy-mmr/src/lib.rs @@ -200,10 +200,24 @@ impl Pallet { .map(T::BeefyAuthorityToMerkleLeaf::convert) .collect::>(); let len = beefy_addresses.len() as u32; - let root = beefy_merkle_tree::merkle_root::<::Hashing, _>( + let root = binary_merkle_tree::merkle_root::<::Hashing, _>( beefy_addresses, ) .into(); BeefyAuthoritySet { id, len, root } } } + +sp_api::decl_runtime_apis! { + /// API useful for BEEFY light clients. + pub trait BeefyMmrApi + where + 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; + } +} diff --git a/frame/beefy-mmr/src/mock.rs b/frame/beefy-mmr/src/mock.rs index 0a64ad3fc9976..2de71cd5b320a 100644 --- a/frame/beefy-mmr/src/mock.rs +++ b/frame/beefy-mmr/src/mock.rs @@ -147,7 +147,7 @@ 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::<::Hashing, _>( + binary_merkle_tree::merkle_root::<::Hashing, _>( col.into_iter().map(|pair| pair.encode()), ) .as_ref() diff --git a/test-utils/runtime/Cargo.toml b/test-utils/runtime/Cargo.toml index 2c943c47f32b0..0852003a6808f 100644 --- a/test-utils/runtime/Cargo.toml +++ b/test-utils/runtime/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] 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" } +pallet-beefy-mmr = { version = "4.0.0-dev", default-features = false, path = "../../frame/beefy-mmr" } 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" } @@ -67,7 +67,7 @@ default = [ ] std = [ "beefy-primitives/std", - "beefy-merkle-tree/std", + "pallet-beefy-mmr/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 8b64528e243bd..5fc7c5e8558ea 100644 --- a/test-utils/runtime/src/lib.rs +++ b/test-utils/runtime/src/lib.rs @@ -978,7 +978,7 @@ cfg_if! { } } - impl beefy_merkle_tree::BeefyMmrApi for Runtime { + impl pallet_beefy_mmr::BeefyMmrApi for Runtime { fn authority_set_proof() -> beefy_primitives::mmr::BeefyAuthoritySet { Default::default() } diff --git a/frame/beefy-mmr/primitives/Cargo.toml b/utils/binary-merkle-tree/Cargo.toml similarity index 58% rename from frame/beefy-mmr/primitives/Cargo.toml rename to utils/binary-merkle-tree/Cargo.toml index c087bc2f37cd3..a59d27fb09bb9 100644 --- a/frame/beefy-mmr/primitives/Cargo.toml +++ b/utils/binary-merkle-tree/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "beefy-merkle-tree" +name = "binary-merkle-tree" version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2021" @@ -11,20 +11,18 @@ homepage = "https://substrate.io" [dependencies] 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", 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" } +hash-db = { version = "0.15.2", default-features = false } [dev-dependencies] array-bytes = "4.1" env_logger = "0.9" +sp-core = { version = "7.0.0", path = "../../primitives/core" } +sp-runtime = { version = "7.0.0", path = "../../primitives/runtime" } [features] debug = ["array-bytes", "log"] default = ["debug", "std"] std = [ - "beefy-primitives/std", - "sp-api/std", - "sp-runtime/std" + "log/std", + "hash-db/std" ] diff --git a/frame/beefy-mmr/primitives/src/lib.rs b/utils/binary-merkle-tree/src/lib.rs similarity index 93% rename from frame/beefy-mmr/primitives/src/lib.rs rename to utils/binary-merkle-tree/src/lib.rs index e6f8acefb039a..42f4e8a5bbf26 100644 --- a/frame/beefy-mmr/primitives/src/lib.rs +++ b/utils/binary-merkle-tree/src/lib.rs @@ -31,40 +31,42 @@ //! efficient by removing the need to track which side each intermediate hash is concatenated on. //! //! If the number of leaves is not even, last leaf (hash of) is promoted to the upper layer. +#[cfg(not(feature = "std"))] +extern crate alloc; +#[cfg(not(feature = "std"))] +use alloc::vec; +#[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}; +use hash_db::Hasher; /// 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) -> H::Output +pub fn merkle_root(leaves: I) -> H::Out where - H: HashT, - H::Output: Default + AsRef<[u8]> + PartialOrd, + H: Hasher, + H::Out: Default + AsRef<[u8]> + PartialOrd, I: IntoIterator, I::Item: AsRef<[u8]>, { - let iter = leaves.into_iter().map(|l| ::hash(l.as_ref())); + let iter = leaves.into_iter().map(|l| ::hash(l.as_ref())); merkelize::(iter, &mut ()).into() } -fn merkelize(leaves: I, visitor: &mut V) -> H::Output +fn merkelize(leaves: I, visitor: &mut V) -> H::Out where - H: HashT, - H::Output: Default + AsRef<[u8]> + PartialOrd, - V: Visitor, - I: Iterator, + H: Hasher, + H::Out: Default + AsRef<[u8]> + PartialOrd, + V: Visitor, + I: Iterator, { 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 H::Output::default(), + Err(next) if next.is_empty() => return H::Out::default(), Err(next) => next, }; @@ -139,17 +141,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: HashT, - H::Output: Default + Copy + AsRef<[u8]> + PartialOrd, + H: Hasher, + H::Out: Default + Copy + AsRef<[u8]> + PartialOrd, I: IntoIterator, I::IntoIter: ExactSizeIterator, T: AsRef<[u8]>, { let mut leaf = None; let iter = leaves.into_iter().enumerate().map(|(idx, l)| { - let hash = ::hash(l.as_ref()); + let hash = ::hash(l.as_ref()); if idx == leaf_index { leaf = Some(l); } @@ -234,28 +236,28 @@ impl<'a, H, T: AsRef<[u8]>> From<&'a T> for Leaf<'a, H> { /// /// The proof must not contain the root hash. pub fn verify_proof<'a, H, P, L>( - root: &'a H::Output, + root: &'a H::Out, proof: P, number_of_leaves: usize, leaf_index: usize, leaf: L, ) -> bool where - H: HashT, - H::Output: PartialEq + AsRef<[u8]> + PartialOrd, - P: IntoIterator, - L: Into>, + H: Hasher, + H::Out: PartialEq + AsRef<[u8]> + PartialOrd, + P: IntoIterator, + L: Into>, { if leaf_index >= number_of_leaves { return false } let leaf_hash = match leaf.into() { - Leaf::Value(content) => ::hash(content), + Leaf::Value(content) => ::hash(content), Leaf::Hash(hash) => hash, }; - let hash_len = ::LENGTH; + let hash_len = ::LENGTH; let mut combined = vec![0_u8; hash_len * 2]; let computed = proof.into_iter().fold(leaf_hash, |a, b| { if a < b { @@ -265,7 +267,7 @@ where combined[..hash_len].copy_from_slice(&b.as_ref()); combined[hash_len..].copy_from_slice(&a.as_ref()); } - let hash = ::hash(&combined); + let hash = ::hash(&combined); #[cfg(feature = "debug")] log::debug!( "[verify_proof]: (a, b) {:?}, {:?} => {:?} ({:?}) hash", @@ -287,20 +289,20 @@ 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: HashT, - H::Output: AsRef<[u8]> + PartialOrd, - V: Visitor, - I: Iterator, + H: Hasher, + H::Out: AsRef<[u8]> + PartialOrd, + V: Visitor, + I: Iterator, { #[cfg(feature = "debug")] log::debug!("[merkelize_row]"); next.clear(); - let hash_len = ::LENGTH; + let hash_len = ::LENGTH; let mut index = 0; let mut combined = vec![0_u8; hash_len * 2]; loop { @@ -326,7 +328,7 @@ where combined[hash_len..].copy_from_slice(a.as_ref()); } - next.push(::hash(&combined)); + next.push(::hash(&combined)); }, // Odd number of items. Promote the item to the upper layer. (Some(a), None) if !next.is_empty() => { @@ -347,24 +349,11 @@ where } } -sp_api::decl_runtime_apis! { - /// API useful for BEEFY light clients. - pub trait BeefyMmrApi - where - 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::*; - use crate::sp_core::H256; + use sp_core::H256; + use sp_runtime::traits::Keccak256; #[test] fn should_generate_empty_root() { From a69a08e424fca846ded0ce51ed4659342907cc1f Mon Sep 17 00:00:00 2001 From: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Date: Thu, 2 Feb 2023 19:14:40 +0200 Subject: [PATCH 355/715] Metadata V15: Derive `TypeInfo` for describing runtime types (#13272) * scale_info: Derive TypeInfo for types present in runtime API Signed-off-by: Alexandru Vasile * cargo: Update Cargo.lock Signed-off-by: Alexandru Vasile --------- Signed-off-by: Alexandru Vasile --- Cargo.lock | 3 +++ client/consensus/babe/Cargo.toml | 1 + client/consensus/babe/src/lib.rs | 2 +- frame/benchmarking/src/utils.rs | 13 +++++++------ frame/contracts/primitives/Cargo.toml | 2 ++ frame/contracts/primitives/src/lib.rs | 17 +++++++++-------- frame/support/src/traits/storage.rs | 4 +++- frame/support/src/traits/try_runtime.rs | 4 ++-- frame/transaction-payment/src/types.rs | 8 +++++--- primitives/consensus/babe/src/lib.rs | 6 +++--- primitives/core/src/lib.rs | 2 +- primitives/finality-grandpa/src/lib.rs | 2 +- primitives/inherents/Cargo.toml | 2 ++ primitives/inherents/src/lib.rs | 4 ++-- primitives/merkle-mountain-range/src/lib.rs | 4 ++-- primitives/runtime/src/generic/block.rs | 2 +- primitives/runtime/src/transaction_validity.rs | 4 ++-- test-utils/runtime/src/lib.rs | 2 +- 18 files changed, 48 insertions(+), 34 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a0e9e0e636cdb..dda127fdded77 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5615,6 +5615,7 @@ version = "7.0.0" dependencies = [ "bitflags", "parity-scale-codec", + "scale-info", "sp-runtime", "sp-std", "sp-weights", @@ -8151,6 +8152,7 @@ dependencies = [ "sc-network", "sc-network-test", "sc-telemetry", + "scale-info", "schnorrkel", "sp-api", "sp-application-crypto", @@ -9959,6 +9961,7 @@ dependencies = [ "futures", "impl-trait-for-tuples", "parity-scale-codec", + "scale-info", "sp-core", "sp-runtime", "sp-std", diff --git a/client/consensus/babe/Cargo.toml b/client/consensus/babe/Cargo.toml index f0ff0080fd610..8088bef9d7e1b 100644 --- a/client/consensus/babe/Cargo.toml +++ b/client/consensus/babe/Cargo.toml @@ -15,6 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-trait = "0.1.57" +scale-info = { version = "2.1.1", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.2.2", features = ["derive"] } futures = "0.3.21" log = "0.4.17" diff --git a/client/consensus/babe/src/lib.rs b/client/consensus/babe/src/lib.rs index 0eac4aca07479..99b29986ec8fc 100644 --- a/client/consensus/babe/src/lib.rs +++ b/client/consensus/babe/src/lib.rs @@ -152,7 +152,7 @@ mod tests; const LOG_TARGET: &str = "babe"; /// BABE epoch information -#[derive(Decode, Encode, PartialEq, Eq, Clone, Debug)] +#[derive(Decode, Encode, PartialEq, Eq, Clone, Debug, scale_info::TypeInfo)] pub struct Epoch { /// The epoch index. pub epoch_index: u64, diff --git a/frame/benchmarking/src/utils.rs b/frame/benchmarking/src/utils.rs index 6ad9ac7bb0bd6..74e44fbf91103 100644 --- a/frame/benchmarking/src/utils.rs +++ b/frame/benchmarking/src/utils.rs @@ -22,6 +22,7 @@ use frame_support::{ pallet_prelude::*, traits::StorageInfo, }; +use scale_info::TypeInfo; #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; use sp_io::hashing::blake2_256; @@ -31,7 +32,7 @@ use sp_storage::TrackedStorageKey; /// An alphabet of possible parameters to use for benchmarking. #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] -#[derive(Encode, Decode, Clone, Copy, PartialEq, Debug)] +#[derive(Encode, Decode, Clone, Copy, PartialEq, Debug, TypeInfo)] #[allow(missing_docs)] #[allow(non_camel_case_types)] pub enum BenchmarkParameter { @@ -72,7 +73,7 @@ impl std::fmt::Display for BenchmarkParameter { /// The results of a single of benchmark. #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] -#[derive(Encode, Decode, Clone, PartialEq, Debug)] +#[derive(Encode, Decode, Clone, PartialEq, Debug, TypeInfo)] pub struct BenchmarkBatch { /// The pallet containing this benchmark. #[cfg_attr(feature = "std", serde(with = "serde_as_str"))] @@ -111,7 +112,7 @@ pub struct BenchmarkBatchSplitResults { /// Contains duration of the function call in nanoseconds along with the benchmark parameters /// used for that benchmark result. #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] -#[derive(Encode, Decode, Default, Clone, PartialEq, Debug)] +#[derive(Encode, Decode, Default, Clone, PartialEq, Debug, TypeInfo)] pub struct BenchmarkResult { pub components: Vec<(BenchmarkParameter, u32)>, pub extrinsic_time: u128, @@ -199,7 +200,7 @@ impl From for BenchmarkError { } /// Configuration used to setup and run runtime benchmarks. -#[derive(Encode, Decode, Default, Clone, PartialEq, Debug)] +#[derive(Encode, Decode, Default, Clone, PartialEq, Debug, TypeInfo)] pub struct BenchmarkConfig { /// The encoded name of the pallet to benchmark. pub pallet: Vec, @@ -216,14 +217,14 @@ pub struct BenchmarkConfig { /// A list of benchmarks available for a particular pallet and instance. /// /// All `Vec` must be valid utf8 strings. -#[derive(Encode, Decode, Default, Clone, PartialEq, Debug)] +#[derive(Encode, Decode, Default, Clone, PartialEq, Debug, TypeInfo)] pub struct BenchmarkList { pub pallet: Vec, pub instance: Vec, pub benchmarks: Vec, } -#[derive(Encode, Decode, Default, Clone, PartialEq, Debug)] +#[derive(Encode, Decode, Default, Clone, PartialEq, Debug, TypeInfo)] pub struct BenchmarkMetadata { pub name: Vec, pub components: Vec<(BenchmarkParameter, u32, u32)>, diff --git a/frame/contracts/primitives/Cargo.toml b/frame/contracts/primitives/Cargo.toml index aafcd912af657..2460edc5a7b2f 100644 --- a/frame/contracts/primitives/Cargo.toml +++ b/frame/contracts/primitives/Cargo.toml @@ -14,6 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] bitflags = "1.0" +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } # Substrate Dependencies (This crate should not rely on frame) @@ -27,4 +28,5 @@ std = [ "codec/std", "sp-runtime/std", "sp-std/std", + "scale-info/std", ] diff --git a/frame/contracts/primitives/src/lib.rs b/frame/contracts/primitives/src/lib.rs index 4faea9eb3ee75..1811ae09c0572 100644 --- a/frame/contracts/primitives/src/lib.rs +++ b/frame/contracts/primitives/src/lib.rs @@ -21,6 +21,7 @@ use bitflags::bitflags; use codec::{Decode, Encode}; +use scale_info::TypeInfo; use sp_runtime::{ traits::{Saturating, Zero}, DispatchError, RuntimeDebug, @@ -31,7 +32,7 @@ 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)] +#[derive(Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)] pub struct ContractResult { /// How much weight was consumed during execution. pub gas_consumed: Weight, @@ -86,7 +87,7 @@ pub type CodeUploadResult = pub type GetStorageResult = Result>, ContractAccessError>; /// The possible errors that can happen querying the storage of a contract. -#[derive(Eq, PartialEq, Encode, Decode, RuntimeDebug)] +#[derive(Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)] pub enum ContractAccessError { /// The given address doesn't point to a contract. DoesntExist, @@ -96,7 +97,7 @@ pub enum ContractAccessError { bitflags! { /// Flags used by a contract to customize exit behaviour. - #[derive(Encode, Decode)] + #[derive(Encode, Decode, TypeInfo)] pub struct ReturnFlags: u32 { /// If this bit is set all changes made by the contract execution are rolled back. const REVERT = 0x0000_0001; @@ -104,7 +105,7 @@ bitflags! { } /// Output of a contract call or instantiation which ran to completion. -#[derive(PartialEq, Eq, Encode, Decode, RuntimeDebug)] +#[derive(PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)] pub struct ExecReturnValue { /// Flags passed along by `seal_return`. Empty when `seal_return` was never called. pub flags: ReturnFlags, @@ -120,7 +121,7 @@ impl ExecReturnValue { } /// The result of a successful contract instantiation. -#[derive(PartialEq, Eq, Encode, Decode, RuntimeDebug)] +#[derive(PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)] pub struct InstantiateReturnValue { /// The output of the called constructor. pub result: ExecReturnValue, @@ -129,7 +130,7 @@ pub struct InstantiateReturnValue { } /// The result of succesfully uploading a contract. -#[derive(PartialEq, Eq, Encode, Decode, RuntimeDebug)] +#[derive(PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)] pub struct CodeUploadReturnValue { /// The key under which the new code is stored. pub code_hash: CodeHash, @@ -138,7 +139,7 @@ pub struct CodeUploadReturnValue { } /// Reference to an existing code hash or a new wasm module. -#[derive(Eq, PartialEq, Encode, Decode, RuntimeDebug)] +#[derive(Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)] pub enum Code { /// A wasm module as raw bytes. Upload(Vec), @@ -153,7 +154,7 @@ impl>, Hash> From for Code { } /// 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)] +#[derive(Eq, PartialEq, Ord, PartialOrd, Encode, Decode, RuntimeDebug, Clone, TypeInfo)] pub enum StorageDeposit { /// The transaction reduced storage consumption. /// diff --git a/frame/support/src/traits/storage.rs b/frame/support/src/traits/storage.rs index 24653d1899836..8285ab988d5b1 100644 --- a/frame/support/src/traits/storage.rs +++ b/frame/support/src/traits/storage.rs @@ -53,7 +53,9 @@ pub trait StorageInstance { } /// Metadata about storage from the runtime. -#[derive(codec::Encode, codec::Decode, crate::RuntimeDebug, Eq, PartialEq, Clone)] +#[derive( + codec::Encode, codec::Decode, crate::RuntimeDebug, Eq, PartialEq, Clone, scale_info::TypeInfo, +)] pub struct StorageInfo { /// Encoded string of pallet name. pub pallet_name: Vec, diff --git a/frame/support/src/traits/try_runtime.rs b/frame/support/src/traits/try_runtime.rs index 273af09a145e5..cb4902201f1e8 100644 --- a/frame/support/src/traits/try_runtime.rs +++ b/frame/support/src/traits/try_runtime.rs @@ -22,7 +22,7 @@ use sp_arithmetic::traits::AtLeast32BitUnsigned; use sp_std::prelude::*; /// Which state tests to execute. -#[derive(codec::Encode, codec::Decode, Clone)] +#[derive(codec::Encode, codec::Decode, Clone, scale_info::TypeInfo)] pub enum Select { /// None of them. None, @@ -82,7 +82,7 @@ impl sp_std::str::FromStr for Select { } /// Select which checks should be run when trying a runtime upgrade upgrade. -#[derive(codec::Encode, codec::Decode, Clone, Debug, Copy)] +#[derive(codec::Encode, codec::Decode, Clone, Debug, Copy, scale_info::TypeInfo)] pub enum UpgradeCheckSelect { /// Run no checks. None, diff --git a/frame/transaction-payment/src/types.rs b/frame/transaction-payment/src/types.rs index d1a480b64e116..d9677861f434e 100644 --- a/frame/transaction-payment/src/types.rs +++ b/frame/transaction-payment/src/types.rs @@ -21,13 +21,15 @@ use codec::{Decode, Encode}; #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; +use scale_info::TypeInfo; + use sp_runtime::traits::{AtLeast32BitUnsigned, Zero}; use sp_std::prelude::*; use frame_support::dispatch::DispatchClass; /// The base fee and adjusted weight and length fees constitute the _inclusion fee_. -#[derive(Encode, Decode, Clone, Eq, PartialEq)] +#[derive(Encode, Decode, Clone, Eq, PartialEq, TypeInfo)] #[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))] #[cfg_attr(feature = "std", serde(rename_all = "camelCase"))] pub struct InclusionFee { @@ -63,7 +65,7 @@ impl InclusionFee { /// - (Optional) `inclusion_fee`: Only the `Pays::Yes` transaction can have the inclusion fee. /// - `tip`: If included in the transaction, the tip will be added on top. Only signed /// transactions can have a tip. -#[derive(Encode, Decode, Clone, Eq, PartialEq)] +#[derive(Encode, Decode, Clone, Eq, PartialEq, TypeInfo)] #[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))] #[cfg_attr(feature = "std", serde(rename_all = "camelCase"))] pub struct FeeDetails { @@ -91,7 +93,7 @@ impl FeeDetails { /// Information related to a dispatchable's class, weight, and fee that can be queried from the /// runtime. -#[derive(Eq, PartialEq, Encode, Decode, Default)] +#[derive(Eq, PartialEq, Encode, Decode, Default, TypeInfo)] #[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))] #[cfg_attr(feature = "std", serde(rename_all = "camelCase"))] #[cfg_attr( diff --git a/primitives/consensus/babe/src/lib.rs b/primitives/consensus/babe/src/lib.rs index cb44afcb8d4e4..10d027bd9162d 100644 --- a/primitives/consensus/babe/src/lib.rs +++ b/primitives/consensus/babe/src/lib.rs @@ -184,7 +184,7 @@ impl From for BabeConfiguration { } /// Configuration data used by the BABE consensus engine. -#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug)] +#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)] pub struct BabeConfiguration { /// The slot duration in milliseconds for BABE. Currently, only /// the value provided by this type at genesis will be used. @@ -327,7 +327,7 @@ where /// the runtime API boundary this type is unknown and as such we keep this /// opaque representation, implementors of the runtime API will have to make /// sure that all usages of `OpaqueKeyOwnershipProof` refer to the same type. -#[derive(Decode, Encode, PartialEq)] +#[derive(Decode, Encode, PartialEq, TypeInfo)] pub struct OpaqueKeyOwnershipProof(Vec); impl OpaqueKeyOwnershipProof { /// Create a new `OpaqueKeyOwnershipProof` using the given encoded @@ -344,7 +344,7 @@ impl OpaqueKeyOwnershipProof { } /// BABE epoch information -#[derive(Decode, Encode, PartialEq, Eq, Clone, Debug)] +#[derive(Decode, Encode, PartialEq, Eq, Clone, Debug, TypeInfo)] pub struct Epoch { /// The epoch index. pub epoch_index: u64, diff --git a/primitives/core/src/lib.rs b/primitives/core/src/lib.rs index 30d0cc199b74d..80e14b84d3ff4 100644 --- a/primitives/core/src/lib.rs +++ b/primitives/core/src/lib.rs @@ -165,7 +165,7 @@ impl sp_std::str::FromStr for Bytes { } /// Stores the encoded `RuntimeMetadata` for the native side as opaque type. -#[derive(Encode, Decode, PartialEq)] +#[derive(Encode, Decode, PartialEq, TypeInfo)] pub struct OpaqueMetadata(Vec); impl OpaqueMetadata { diff --git a/primitives/finality-grandpa/src/lib.rs b/primitives/finality-grandpa/src/lib.rs index 7b3b55f49cee0..f5307ab06bde7 100644 --- a/primitives/finality-grandpa/src/lib.rs +++ b/primitives/finality-grandpa/src/lib.rs @@ -529,7 +529,7 @@ impl<'a> Decode for VersionedAuthorityList<'a> { /// the runtime API boundary this type is unknown and as such we keep this /// opaque representation, implementors of the runtime API will have to make /// sure that all usages of `OpaqueKeyOwnershipProof` refer to the same type. -#[derive(Decode, Encode, PartialEq)] +#[derive(Decode, Encode, PartialEq, TypeInfo)] pub struct OpaqueKeyOwnershipProof(Vec); impl OpaqueKeyOwnershipProof { diff --git a/primitives/inherents/Cargo.toml b/primitives/inherents/Cargo.toml index c901a6e68a181..fd073db69a6af 100644 --- a/primitives/inherents/Cargo.toml +++ b/primitives/inherents/Cargo.toml @@ -16,6 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-trait = { version = "0.1.57", optional = true } codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } impl-trait-for-tuples = "0.2.2" thiserror = { version = "1.0.30", optional = true } sp-core = { version = "7.0.0", default-features = false, path = "../core" } @@ -30,6 +31,7 @@ default = [ "std" ] std = [ "async-trait", "codec/std", + "scale-info/std", "sp-core/std", "sp-runtime/std", "sp-std/std", diff --git a/primitives/inherents/src/lib.rs b/primitives/inherents/src/lib.rs index 59db5ef3e8802..f05c9a9ad552b 100644 --- a/primitives/inherents/src/lib.rs +++ b/primitives/inherents/src/lib.rs @@ -204,7 +204,7 @@ pub enum Error { pub type InherentIdentifier = [u8; 8]; /// Inherent data to include in a block. -#[derive(Clone, Default, Encode, Decode)] +#[derive(Clone, Default, Encode, Decode, scale_info::TypeInfo)] pub struct InherentData { /// All inherent data encoded with parity-scale-codec and an identifier. data: BTreeMap>, @@ -276,7 +276,7 @@ impl InherentData { /// /// When a fatal error occurs, all other errors are removed and the implementation needs to /// abort checking inherents. -#[derive(Encode, Decode, Clone)] +#[derive(Encode, Decode, Clone, scale_info::TypeInfo)] pub struct CheckInherentsResult { /// Did the check succeed? okay: bool, diff --git a/primitives/merkle-mountain-range/src/lib.rs b/primitives/merkle-mountain-range/src/lib.rs index 606906185077c..df0a7f75a73fb 100644 --- a/primitives/merkle-mountain-range/src/lib.rs +++ b/primitives/merkle-mountain-range/src/lib.rs @@ -142,7 +142,7 @@ impl FullLeaf for OpaqueLeaf { /// /// 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)] +#[derive(codec::Encode, codec::Decode, RuntimeDebug, PartialEq, Eq, TypeInfo)] pub struct EncodableOpaqueLeaf(pub Vec); impl EncodableOpaqueLeaf { @@ -361,7 +361,7 @@ pub struct Proof { /// Merkle Mountain Range operation error. #[cfg_attr(feature = "std", derive(thiserror::Error))] -#[derive(RuntimeDebug, codec::Encode, codec::Decode, PartialEq, Eq)] +#[derive(RuntimeDebug, codec::Encode, codec::Decode, PartialEq, Eq, TypeInfo)] pub enum Error { /// Error during translation of a block number into a leaf index. #[cfg_attr(feature = "std", error("Error performing numeric op"))] diff --git a/primitives/runtime/src/generic/block.rs b/primitives/runtime/src/generic/block.rs index 3b01633635c24..b03fab2904db5 100644 --- a/primitives/runtime/src/generic/block.rs +++ b/primitives/runtime/src/generic/block.rs @@ -78,7 +78,7 @@ impl fmt::Display for BlockId { } /// Abstraction over a substrate block. -#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug)] +#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, scale_info::TypeInfo)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] #[cfg_attr(feature = "std", serde(rename_all = "camelCase"))] #[cfg_attr(feature = "std", serde(deny_unknown_fields))] diff --git a/primitives/runtime/src/transaction_validity.rs b/primitives/runtime/src/transaction_validity.rs index 3b89644c28647..f47459f3eed16 100644 --- a/primitives/runtime/src/transaction_validity.rs +++ b/primitives/runtime/src/transaction_validity.rs @@ -226,7 +226,7 @@ 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)] +#[derive(Copy, Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)] pub enum TransactionSource { /// Transaction is already included in block. /// @@ -251,7 +251,7 @@ pub enum TransactionSource { } /// Information concerning a valid transaction. -#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug)] +#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)] pub struct ValidTransaction { /// Priority of the transaction. /// diff --git a/test-utils/runtime/src/lib.rs b/test-utils/runtime/src/lib.rs index 5fc7c5e8558ea..1c2d6ec8a0c81 100644 --- a/test-utils/runtime/src/lib.rs +++ b/test-utils/runtime/src/lib.rs @@ -297,7 +297,7 @@ pub fn run_tests(mut input: &[u8]) -> Vec { } /// A type that can not be decoded. -#[derive(PartialEq)] +#[derive(PartialEq, TypeInfo)] pub struct DecodeFails { _phantom: PhantomData, } From 9c00c9073829b93113f3cbd4183d940a6164f321 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Thu, 2 Feb 2023 18:47:50 +0100 Subject: [PATCH 356/715] benchmarks: EnsureRankedMember must add ranked members (#13297) Signed-off-by: Oliver Tale-Yazdi --- frame/ranked-collective/src/lib.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/frame/ranked-collective/src/lib.rs b/frame/ranked-collective/src/lib.rs index 84be1243c8afc..a65d184d6bf06 100644 --- a/frame/ranked-collective/src/lib.rs +++ b/frame/ranked-collective/src/lib.rs @@ -256,8 +256,7 @@ impl, I: 'static, const MIN_RANK: u16> EnsureOrigin Result { - let who = IndexToId::::get(MIN_RANK, 0).ok_or(())?; - Ok(frame_system::RawOrigin::Signed(who).into()) + EnsureRankedMember::::try_successful_origin() } } @@ -279,8 +278,7 @@ impl, I: 'static, const MIN_RANK: u16> EnsureOrigin Result { - let who = IndexToId::::get(MIN_RANK, 0).ok_or(())?; - Ok(frame_system::RawOrigin::Signed(who).into()) + EnsureRankedMember::::try_successful_origin() } } @@ -302,7 +300,9 @@ impl, I: 'static, const MIN_RANK: u16> EnsureOrigin Result { - let who = IndexToId::::get(MIN_RANK, 0).ok_or(())?; + let who = frame_benchmarking::account::("successful_origin", 0, 0); + crate::Pallet::::do_add_member_to_rank(who.clone(), MIN_RANK) + .expect("Could not add members for benchmarks"); Ok(frame_system::RawOrigin::Signed(who).into()) } } From 83de5099a3cae683ccbaf2ab7a4d688e2d602f57 Mon Sep 17 00:00:00 2001 From: Marcin S Date: Thu, 2 Feb 2023 19:41:40 +0100 Subject: [PATCH 357/715] Minor: Update output validity tests (#13190) * Minor: Update output validity tests Quick follow-up to https://github.com/paritytech/substrate/pull/13183. Mainly, I wanted to double check that the `test_return_max_memory_offset` test doesn't pass just because the output length is 0. I also: - Organized these tests into a module. - Added a comment explaining why we don't use the `wasm_export_functions` macro. * Update test based on review comment --- client/executor/runtime-test/src/lib.rs | 67 ++++++++++++-------- client/executor/src/integration_tests/mod.rs | 2 +- 2 files changed, 42 insertions(+), 27 deletions(-) diff --git a/client/executor/runtime-test/src/lib.rs b/client/executor/runtime-test/src/lib.rs index 0aa30e4bc9675..23584006a72c0 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_runtime_interface::pack_ptr_and_len; extern "C" { #[allow(dead_code)] @@ -344,31 +342,48 @@ sp_core::wasm_export_functions! { } } -// Returns a huge len. It should result in an error, and not an allocation. -#[no_mangle] -#[cfg(not(feature = "std"))] -pub extern "C" fn test_return_huge_len(_params: *const u8, _len: usize) -> u64 { - pack_ptr_and_len(0, u32::MAX) -} +// Tests that check output validity. We explicitly return the ptr and len, so we avoid using the +// `wasm_export_functions` macro. +mod output_validity { + #[cfg(not(feature = "std"))] + use super::WASM_PAGE_SIZE; -// Returns an offset right at the edge of the wasm memory boundary. With length 0, it should -// succeed. -#[no_mangle] -#[cfg(not(feature = "std"))] -pub extern "C" fn test_return_max_memory_offset(_params: *const u8, _len: usize) -> u64 { - pack_ptr_and_len((core::arch::wasm32::memory_size(0) * WASM_PAGE_SIZE) as u32, 0) -} + #[cfg(not(feature = "std"))] + use sp_runtime_interface::pack_ptr_and_len; -// Returns an offset right at the edge of the wasm memory boundary. With length 1, it should fail. -#[no_mangle] -#[cfg(not(feature = "std"))] -pub extern "C" fn test_return_max_memory_offset_plus_one(_params: *const u8, _len: usize) -> u64 { - pack_ptr_and_len((core::arch::wasm32::memory_size(0) * WASM_PAGE_SIZE) as u32, 1) -} + // Returns a huge len. It should result in an error, and not an allocation. + #[no_mangle] + #[cfg(not(feature = "std"))] + pub extern "C" fn test_return_huge_len(_params: *const u8, _len: usize) -> u64 { + pack_ptr_and_len(0, u32::MAX) + } -// Returns an output that overflows the u32 range. It should result in an error. -#[no_mangle] -#[cfg(not(feature = "std"))] -pub extern "C" fn test_return_overflow(_params: *const u8, _len: usize) -> u64 { - pack_ptr_and_len(u32::MAX, 1) + // Returns an offset right before the edge of the wasm memory boundary. It should succeed. + #[no_mangle] + #[cfg(not(feature = "std"))] + pub extern "C" fn test_return_max_memory_offset(_params: *const u8, _len: usize) -> u64 { + let output_ptr = (core::arch::wasm32::memory_size(0) * WASM_PAGE_SIZE) as u32 - 1; + let ptr = output_ptr as *mut u8; + unsafe { + ptr.write(u8::MAX); + } + pack_ptr_and_len(output_ptr, 1) + } + + // Returns an offset right after the edge of the wasm memory boundary. It should fail. + #[no_mangle] + #[cfg(not(feature = "std"))] + pub extern "C" fn test_return_max_memory_offset_plus_one( + _params: *const u8, + _len: usize, + ) -> u64 { + pack_ptr_and_len((core::arch::wasm32::memory_size(0) * WASM_PAGE_SIZE) as u32, 1) + } + + // Returns an output that overflows the u32 range. It should result in an error. + #[no_mangle] + #[cfg(not(feature = "std"))] + pub extern "C" fn test_return_overflow(_params: *const u8, _len: usize) -> u64 { + pack_ptr_and_len(u32::MAX, 1) + } } diff --git a/client/executor/src/integration_tests/mod.rs b/client/executor/src/integration_tests/mod.rs index 22e651abe98e2..bb2930803841b 100644 --- a/client/executor/src/integration_tests/mod.rs +++ b/client/executor/src/integration_tests/mod.rs @@ -811,7 +811,7 @@ fn return_max_memory_offset(wasm_method: WasmExecutionMethod) { assert_eq!( call_in_wasm("test_return_max_memory_offset", &[], wasm_method, &mut ext).unwrap(), - ().encode() + (u8::MAX).encode() ); } From 1d67b0f0a9d21c53ec9515d810fb4d298bffd1f7 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Fri, 3 Feb 2023 12:16:16 +0200 Subject: [PATCH 358/715] BEEFY: define on-chain beefy-genesis and use it to coordinate voter initialization (#13215) * beefy: add support to configure BEEFY genesis * client/beefy: more flexible test runtime api * client/beefy: add tests for custom BEEFY genesis * client/beefy: ignore old state that didn't account for pallet genesis * client/beefy: fix clippy * frame/beefy: default BEEFY-genesis is block One::one() * frame/beefy: add extra doc comments --------- Co-authored-by: parity-processbot <> --- client/beefy/src/aux_schema.rs | 5 +- client/beefy/src/lib.rs | 34 ++-- client/beefy/src/tests.rs | 273 +++++++++++++++++++++------------ client/beefy/src/worker.rs | 6 +- frame/beefy/src/lib.rs | 21 ++- primitives/beefy/src/lib.rs | 5 +- test-utils/runtime/src/lib.rs | 4 + 7 files changed, 234 insertions(+), 114 deletions(-) diff --git a/client/beefy/src/aux_schema.rs b/client/beefy/src/aux_schema.rs index fafa9948c5444..217ea4769d8b9 100644 --- a/client/beefy/src/aux_schema.rs +++ b/client/beefy/src/aux_schema.rs @@ -28,7 +28,7 @@ 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; +const CURRENT_VERSION: u32 = 2; pub(crate) fn write_current_version(backend: &B) -> ClientResult<()> { info!(target: LOG_TARGET, "🥩 write aux schema version {:?}", CURRENT_VERSION); @@ -63,7 +63,8 @@ where match version { None => (), - Some(1) => return load_decode::<_, PersistedState>(backend, WORKER_STATE), + Some(1) => (), // version 1 is totally obsolete and should be simply ignored + Some(2) => return load_decode::<_, PersistedState>(backend, WORKER_STATE), other => return Err(ClientError::Backend(format!("Unsupported BEEFY DB version: {:?}", other))), } diff --git a/client/beefy/src/lib.rs b/client/beefy/src/lib.rs index 185f3b1ad502e..d7de7295a4a11 100644 --- a/client/beefy/src/lib.rs +++ b/client/beefy/src/lib.rs @@ -53,7 +53,7 @@ use sp_keystore::SyncCryptoStorePtr; use sp_mmr_primitives::MmrApi; use sp_runtime::{ generic::BlockId, - traits::{Block, One, Zero}, + traits::{Block, Zero}, }; use std::{collections::VecDeque, marker::PhantomData, sync::Arc}; @@ -346,6 +346,12 @@ where R: ProvideRuntimeApi, R::Api: BeefyApi, { + let beefy_genesis = runtime + .runtime_api() + .beefy_genesis(&BlockId::hash(best_grandpa.hash())) + .ok() + .flatten() + .ok_or_else(|| ClientError::Backend("BEEFY pallet expected to be active.".into()))?; // 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(); @@ -378,20 +384,19 @@ where break state } - if *header.number() == One::one() { - // We've reached chain genesis, initialize voter here. - let genesis_num = *header.number(); + if *header.number() == beefy_genesis { + // We've reached BEEFY genesis, initialize voter here. let genesis_set = expect_validator_set(runtime, BlockId::hash(header.hash())) .and_then(genesis_set_sanity_check)?; info!( target: LOG_TARGET, "🥩 Loading BEEFY voter state from genesis on what appears to be first startup. \ Starting voting rounds at block {:?}, genesis validator set {:?}.", - genesis_num, + beefy_genesis, genesis_set, ); - sessions.push_front(Rounds::new(genesis_num, genesis_set)); + sessions.push_front(Rounds::new(beefy_genesis, genesis_set)); break PersistedState::checked_new(best_grandpa, Zero::zero(), sessions, min_block_delta) .ok_or_else(|| ClientError::Backend("Invalid BEEFY chain".into()))? } @@ -448,13 +453,16 @@ where 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: LOG_TARGET, "🥩 BEEFY pallet available: block {:?} validator set {:?}", - notif.header.number(), active - ); - return Ok(notif.header) + if let Some(start) = runtime.runtime_api().beefy_genesis(&at).ok().flatten() { + if *notif.header.number() >= start { + // Beefy pallet available, return header for best grandpa at the time. + info!( + target: LOG_TARGET, + "🥩 BEEFY pallet available: block {:?} beefy genesis {:?}", + notif.header.number(), start + ); + return Ok(notif.header) + } } }, _ = gossip_engine => { diff --git a/client/beefy/src/tests.rs b/client/beefy/src/tests.rs index 2642035ba5dd5..008137d9a9965 100644 --- a/client/beefy/src/tests.rs +++ b/client/beefy/src/tests.rs @@ -77,8 +77,8 @@ const BAD_MMR_ROOT: MmrRootHash = MmrRootHash::repeat_byte(0x42); type BeefyBlockImport = crate::BeefyBlockImport< Block, substrate_test_runtime_client::Backend, - two_validators::TestApi, - BlockImportAdapter>, + TestApi, + BlockImportAdapter>, >; pub(crate) type BeefyValidatorSet = ValidatorSet; @@ -198,12 +198,12 @@ impl TestNetFactory for BeefyTestNet { Option>, Self::PeerData, ) { + let keys = &[BeefyKeyring::Alice, BeefyKeyring::Bob]; + let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); + let api = Arc::new(TestApi::with_validator_set(&validator_set)); 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 (block_import, voter_links, rpc_links) = + beefy_block_import_and_links(inner, client.as_backend(), api); let peer_data = PeerData { beefy_rpc_links: Mutex::new(Some(rpc_links)), beefy_voter_links: Mutex::new(Some(voter_links)), @@ -230,79 +230,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 {} +#[derive(Clone)] +pub(crate) struct TestApi { + pub beefy_genesis: u64, + pub validator_set: BeefyValidatorSet, + pub mmr_root_hash: MmrRootHash, +} - // compiler gets confused and warns us about unused inner - #[allow(dead_code)] - pub(crate) struct RuntimeApi { - inner: TestApi, - } +impl TestApi { + pub fn new( + beefy_genesis: u64, + validator_set: &BeefyValidatorSet, + mmr_root_hash: MmrRootHash, + ) -> Self { + TestApi { beefy_genesis, validator_set: validator_set.clone(), mmr_root_hash } + } - 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 mmr_root() -> Result { - Ok($mmr_root) - } - - fn generate_proof( - _block_numbers: Vec, - _best_known_block_number: Option - ) -> Result<(Vec, Proof), MmrError> { - unimplemented!() - } - - fn verify_proof(_leaves: Vec, _proof: Proof) -> Result<(), MmrError> { - unimplemented!() - } - - fn verify_proof_stateless( - _root: MmrRootHash, - _leaves: Vec, - _proof: Proof - ) -> Result<(), MmrError> { - unimplemented!() - } - } - } + pub fn with_validator_set(validator_set: &BeefyValidatorSet) -> Self { + TestApi { + beefy_genesis: 1, + validator_set: validator_set.clone(), + mmr_root_hash: GOOD_MMR_ROOT, } - }; + } +} + +// 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(&self) -> ApiRef { + RuntimeApi { inner: self.clone() }.into() + } } +sp_api::mock_impl_runtime_apis! { + impl BeefyApi for RuntimeApi { + fn beefy_genesis() -> Option> { + Some(self.inner.beefy_genesis) + } + + fn validator_set() -> Option { + Some(self.inner.validator_set.clone()) + } + } + + impl MmrApi> for RuntimeApi { + fn mmr_root() -> Result { + Ok(self.inner.mmr_root_hash) + } + + fn generate_proof( + _block_numbers: Vec, + _best_known_block_number: Option + ) -> Result<(Vec, Proof), MmrError> { + unimplemented!() + } + + fn verify_proof(_leaves: Vec, _proof: Proof) -> Result<(), MmrError> { + unimplemented!() + } -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 verify_proof_stateless( + _root: MmrRootHash, + _leaves: Vec, + _proof: Proof + ) -> Result<(), MmrError> { + unimplemented!() + } + } +} fn add_mmr_digest(header: &mut Header, mmr_hash: MmrRootHash) { header.digest_mut().push(DigestItem::Consensus( @@ -332,9 +332,9 @@ pub(crate) fn create_beefy_keystore(authority: BeefyKeyring) -> SyncCryptoStoreP fn voter_init_setup( net: &mut BeefyTestNet, finality: &mut futures::stream::Fuse>, + api: &TestApi, ) -> 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)); @@ -345,9 +345,9 @@ fn voter_init_setup( None, ); let best_grandpa = - futures::executor::block_on(wait_for_runtime_pallet(&*api, &mut gossip_engine, finality)) + futures::executor::block_on(wait_for_runtime_pallet(api, &mut gossip_engine, finality)) .unwrap(); - load_or_init_voter_state(&*backend, &*api, best_grandpa, 1) + load_or_init_voter_state(&*backend, api, best_grandpa, 1) } // Spawns beefy voters. Returns a future to spawn on the runtime. @@ -357,7 +357,7 @@ fn initialize_beefy( min_block_delta: u32, ) -> impl Future where - API: ProvideRuntimeApi + Default + Sync + Send, + API: ProvideRuntimeApi + Sync + Send, API::Api: BeefyApi + MmrApi>, { let tasks = FuturesUnordered::new(); @@ -544,7 +544,7 @@ async fn beefy_finalizing_blocks() { let mut net = BeefyTestNet::new(2); - let api = Arc::new(two_validators::TestApi {}); + let api = Arc::new(TestApi::with_validator_set(&validator_set)); let beefy_peers = peers.iter().enumerate().map(|(id, key)| (id, key, api.clone())).collect(); tokio::spawn(initialize_beefy(&mut net, beefy_peers, min_block_delta)); @@ -582,7 +582,7 @@ async fn lagging_validators() { let min_block_delta = 1; let mut net = BeefyTestNet::new(2); - let api = Arc::new(two_validators::TestApi {}); + let api = Arc::new(TestApi::with_validator_set(&validator_set)); let beefy_peers = peers.iter().enumerate().map(|(id, key)| (id, key, api.clone())).collect(); tokio::spawn(initialize_beefy(&mut net, beefy_peers, min_block_delta)); @@ -660,7 +660,7 @@ async fn correct_beefy_payload() { let mut net = BeefyTestNet::new(4); // Alice, Bob, Charlie will vote on good payloads - let good_api = Arc::new(four_validators::TestApi {}); + let good_api = Arc::new(TestApi::new(1, &validator_set, GOOD_MMR_ROOT)); let good_peers = [BeefyKeyring::Alice, BeefyKeyring::Bob, BeefyKeyring::Charlie] .iter() .enumerate() @@ -669,7 +669,7 @@ async fn correct_beefy_payload() { tokio::spawn(initialize_beefy(&mut net, good_peers, min_block_delta)); // Dave will vote on bad mmr roots - let bad_api = Arc::new(bad_four_validators::TestApi {}); + let bad_api = Arc::new(TestApi::new(1, &validator_set, BAD_MMR_ROOT)); let bad_peers = vec![(3, &BeefyKeyring::Dave, bad_api)]; tokio::spawn(initialize_beefy(&mut net, bad_peers, min_block_delta)); @@ -714,6 +714,8 @@ async fn beefy_importing_blocks() { sp_tracing::try_init_simple(); let mut net = BeefyTestNet::new(2); + let keys = &[BeefyKeyring::Alice, BeefyKeyring::Bob]; + let good_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); let client = net.peer(0).client().clone(); let (mut block_import, _, peer_data) = net.make_block_import(client.clone()); @@ -769,9 +771,7 @@ async fn beefy_importing_blocks() { // 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_finality_proof(block_num, &validator_set, keys); + let proof = crate::justification::tests::new_finality_proof(block_num, &good_set, keys); let versioned_proof: VersionedFinalityProof, Signature> = proof.into(); let encoded = versioned_proof.encode(); let justif = Some(Justifications::from((BEEFY_ENGINE_ID, encoded))); @@ -814,8 +814,8 @@ async fn beefy_importing_blocks() { 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_finality_proof(block_num, &validator_set, keys); + let bad_set = ValidatorSet::new(make_beefy_ids(keys), 1).unwrap(); + let proof = crate::justification::tests::new_finality_proof(block_num, &bad_set, keys); let versioned_proof: VersionedFinalityProof, Signature> = proof.into(); let encoded = versioned_proof.encode(); let justif = Some(Justifications::from((BEEFY_ENGINE_ID, encoded))); @@ -865,7 +865,7 @@ async fn voter_initialization() { let min_block_delta = 10; let mut net = BeefyTestNet::new(2); - let api = Arc::new(two_validators::TestApi {}); + let api = Arc::new(TestApi::with_validator_set(&validator_set)); let beefy_peers = peers.iter().enumerate().map(|(id, key)| (id, key, api.clone())).collect(); tokio::spawn(initialize_beefy(&mut net, beefy_peers, min_block_delta)); @@ -898,7 +898,7 @@ async fn on_demand_beefy_justification_sync() { let mut net = BeefyTestNet::new(4); // Alice, Bob, Charlie start first and make progress through voting. - let api = Arc::new(four_validators::TestApi {}); + let api = Arc::new(TestApi::with_validator_set(&validator_set)); let fast_peers = [BeefyKeyring::Alice, BeefyKeyring::Bob, BeefyKeyring::Charlie]; let voting_peers = fast_peers.iter().enumerate().map(|(id, key)| (id, key, api.clone())).collect(); @@ -977,8 +977,9 @@ async fn should_initialize_voter_at_genesis() { // finalize 13 without justifications net.peer(0).client().as_client().finalize_block(hashes[13], None).unwrap(); - // load persistent state - nothing in DB, should init at session boundary - let persisted_state = voter_init_setup(&mut net, &mut finality).unwrap(); + let api = TestApi::with_validator_set(&validator_set); + // load persistent state - nothing in DB, should init at genesis + let persisted_state = voter_init_setup(&mut net, &mut finality, &api).unwrap(); // Test initialization at session boundary. // verify voter initialized with two sessions starting at blocks 1 and 10 @@ -1006,6 +1007,54 @@ async fn should_initialize_voter_at_genesis() { assert_eq!(state, persisted_state); } +#[tokio::test] +async fn should_initialize_voter_at_custom_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(); + // custom pallet genesis is block number 7 + let custom_pallet_genesis = 7; + let api = TestApi::new(custom_pallet_genesis, &validator_set, GOOD_MMR_ROOT); + + // push 15 blocks with `AuthorityChange` digests every 10 blocks + let hashes = net.generate_blocks_and_sync(15, 10, &validator_set, false).await; + + let mut finality = net.peer(0).client().as_client().finality_notification_stream().fuse(); + + // finalize 3, 5, 8 without justifications + net.peer(0).client().as_client().finalize_block(hashes[3], None).unwrap(); + net.peer(0).client().as_client().finalize_block(hashes[5], None).unwrap(); + net.peer(0).client().as_client().finalize_block(hashes[8], None).unwrap(); + + // load persistent state - nothing in DB, should init at genesis + let persisted_state = voter_init_setup(&mut net, &mut finality, &api).unwrap(); + + // Test initialization at session boundary. + // verify voter initialized with single session starting at block `custom_pallet_genesis` (7) + let sessions = persisted_state.voting_oracle().sessions(); + assert_eq!(sessions.len(), 1); + assert_eq!(sessions[0].session_start(), custom_pallet_genesis); + let rounds = persisted_state.active_round().unwrap(); + assert_eq!(rounds.session_start(), custom_pallet_genesis); + assert_eq!(rounds.validator_set_id(), validator_set.id()); + + // verify next vote target is mandatory block 7 + assert_eq!(persisted_state.best_beefy_block(), 0); + assert_eq!(persisted_state.best_grandpa_block(), 8); + assert_eq!( + persisted_state + .voting_oracle() + .voting_target(persisted_state.best_beefy_block(), 13), + Some(custom_pallet_genesis) + ); + + // verify state also saved to db + assert!(verify_persisted_version(&*backend)); + let state = load_persistent(&*backend).unwrap().unwrap(); + assert_eq!(state, persisted_state); +} + #[tokio::test] async fn should_initialize_voter_when_last_final_is_session_boundary() { let keys = &[BeefyKeyring::Alice]; @@ -1038,8 +1087,9 @@ async fn should_initialize_voter_when_last_final_is_session_boundary() { // Test corner-case where session boundary == last beefy finalized, // expect rounds initialized at last beefy finalized 10. + let api = TestApi::with_validator_set(&validator_set); // load persistent state - nothing in DB, should init at session boundary - let persisted_state = voter_init_setup(&mut net, &mut finality).unwrap(); + let persisted_state = voter_init_setup(&mut net, &mut finality, &api).unwrap(); // verify voter initialized with single session starting at block 10 assert_eq!(persisted_state.voting_oracle().sessions().len(), 1); @@ -1095,8 +1145,9 @@ async fn should_initialize_voter_at_latest_finalized() { // Test initialization at last BEEFY finalized. + let api = TestApi::with_validator_set(&validator_set); // load persistent state - nothing in DB, should init at last BEEFY finalized - let persisted_state = voter_init_setup(&mut net, &mut finality).unwrap(); + let persisted_state = voter_init_setup(&mut net, &mut finality, &api).unwrap(); // verify voter initialized with single session starting at block 12 assert_eq!(persisted_state.voting_oracle().sessions().len(), 1); @@ -1119,3 +1170,37 @@ async fn should_initialize_voter_at_latest_finalized() { let state = load_persistent(&*backend).unwrap().unwrap(); assert_eq!(state, persisted_state); } + +#[tokio::test] +async fn beefy_finalizing_after_pallet_genesis() { + sp_tracing::try_init_simple(); + + 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 = 1; + let pallet_genesis = 15; + + let mut net = BeefyTestNet::new(2); + + let api = Arc::new(TestApi::new(pallet_genesis, &validator_set, GOOD_MMR_ROOT)); + let beefy_peers = peers.iter().enumerate().map(|(id, key)| (id, key, api.clone())).collect(); + tokio::spawn(initialize_beefy(&mut net, beefy_peers, min_block_delta)); + + // push 42 blocks including `AuthorityChange` digests every 10 blocks. + let hashes = net.generate_blocks_and_sync(42, session_len, &validator_set, true).await; + + let net = Arc::new(Mutex::new(net)); + let peers = peers.into_iter().enumerate(); + + // Minimum BEEFY block delta is 1. + + // GRANDPA finalize blocks leading up to BEEFY pallet genesis -> BEEFY should finalize nothing. + finalize_block_and_wait_for_beefy(&net, peers.clone(), &hashes[1..14], &[]).await; + + // GRANDPA finalize block #16 -> BEEFY should finalize #15 (genesis mandatory) and #16. + finalize_block_and_wait_for_beefy(&net, peers.clone(), &[hashes[16]], &[15, 16]).await; + + // GRANDPA finalize #21 -> BEEFY finalize #20 (mandatory) and #21 + finalize_block_and_wait_for_beefy(&net, peers.clone(), &[hashes[21]], &[20, 21]).await; +} diff --git a/client/beefy/src/worker.rs b/client/beefy/src/worker.rs index 19ab52f520225..4d057bffc0cd9 100644 --- a/client/beefy/src/worker.rs +++ b/client/beefy/src/worker.rs @@ -994,8 +994,8 @@ pub(crate) mod tests { communication::notification::{BeefyBestBlockStream, BeefyVersionedFinalityProofStream}, keystore::tests::Keyring, tests::{ - create_beefy_keystore, get_beefy_streams, make_beefy_ids, two_validators::TestApi, - BeefyPeer, BeefyTestNet, + create_beefy_keystore, get_beefy_streams, make_beefy_ids, BeefyPeer, BeefyTestNet, + TestApi, }, BeefyRPCLinks, KnownPeers, }; @@ -1068,7 +1068,7 @@ pub(crate) mod tests { }; let backend = peer.client().as_backend(); - let api = Arc::new(TestApi {}); + let api = Arc::new(TestApi::with_validator_set(&genesis_validator_set)); let network = peer.network_service().clone(); let known_peers = Arc::new(Mutex::new(KnownPeers::new())); let gossip_validator = Arc::new(GossipValidator::new(known_peers.clone())); diff --git a/frame/beefy/src/lib.rs b/frame/beefy/src/lib.rs index 4cb23107e7843..86c8763a51dd3 100644 --- a/frame/beefy/src/lib.rs +++ b/frame/beefy/src/lib.rs @@ -49,6 +49,7 @@ pub use pallet::*; pub mod pallet { use super::*; use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::BlockNumberFor; #[pallet::config] pub trait Config: frame_system::Config { @@ -91,15 +92,32 @@ pub mod pallet { pub(super) type NextAuthorities = StorageValue<_, BoundedVec, ValueQuery>; + /// Block number where BEEFY consensus is enabled/started. + /// If changing this, make sure `Self::ValidatorSetId` is also reset to + /// `GENESIS_AUTHORITY_SET_ID` in the state of the new block number configured here. + #[pallet::storage] + #[pallet::getter(fn genesis_block)] + pub(super) type GenesisBlock = + StorageValue<_, Option>, ValueQuery>; + #[pallet::genesis_config] pub struct GenesisConfig { + /// Initial set of BEEFY authorities. pub authorities: Vec, + /// Block number where BEEFY consensus should start. + /// Should match the session where initial authorities are active. + /// *Note:* Ideally use block number where GRANDPA authorities are changed, + /// to guarantee the client gets a finality notification for exactly this block. + pub genesis_block: Option>, } #[cfg(feature = "std")] impl Default for GenesisConfig { fn default() -> Self { - Self { authorities: Vec::new() } + // BEEFY genesis will be first BEEFY-MANDATORY block, + // use block number one instead of chain-genesis. + let genesis_block = Some(sp_runtime::traits::One::one()); + Self { authorities: Vec::new(), genesis_block } } } @@ -110,6 +128,7 @@ pub mod pallet { // we panic here as runtime maintainers can simply reconfigure genesis and restart // the chain easily .expect("Authorities vec too big"); + >::put(&self.genesis_block); } } } diff --git a/primitives/beefy/src/lib.rs b/primitives/beefy/src/lib.rs index eb7b8db89b214..8c219040b3523 100644 --- a/primitives/beefy/src/lib.rs +++ b/primitives/beefy/src/lib.rs @@ -43,7 +43,7 @@ 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_runtime::traits::{Hash, NumberFor}; use sp_std::prelude::*; /// Key type for BEEFY module. @@ -201,6 +201,9 @@ sp_api::decl_runtime_apis! { /// API necessary for BEEFY voters. pub trait BeefyApi { + /// Return the block number where BEEFY consensus is enabled/started + fn beefy_genesis() -> Option>; + /// Return the current active BEEFY validator set fn validator_set() -> Option>; } diff --git a/test-utils/runtime/src/lib.rs b/test-utils/runtime/src/lib.rs index 1c2d6ec8a0c81..c1a66eb6acb5c 100644 --- a/test-utils/runtime/src/lib.rs +++ b/test-utils/runtime/src/lib.rs @@ -973,6 +973,10 @@ cfg_if! { } impl beefy_primitives::BeefyApi for Runtime { + fn beefy_genesis() -> Option { + None + } + fn validator_set() -> Option> { None } From 12823c2795c99d832bd2535f013c01a6e3f5e605 Mon Sep 17 00:00:00 2001 From: Deepanshu Hooda <43631678+gitofdeepanshu@users.noreply.github.com> Date: Fri, 3 Feb 2023 18:50:12 +0530 Subject: [PATCH 359/715] feat: add event SkepticsChosen event in society (#13291) * feat: add event SkepticsChosen event in society * feat: add test for SkepticsChosen event --- frame/society/src/lib.rs | 10 +++++++--- frame/society/src/tests.rs | 7 +++++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/frame/society/src/lib.rs b/frame/society/src/lib.rs index 0edf00ff80f6e..18152b9e29ec4 100644 --- a/frame/society/src/lib.rs +++ b/frame/society/src/lib.rs @@ -513,6 +513,8 @@ pub mod pallet { Unfounded { founder: T::AccountId }, /// Some funds were deposited into the society account. Deposit { value: BalanceOf }, + /// A group of members has been choosen as Skeptics + SkepticsChosen { skeptics: Vec }, } /// The first member. @@ -1610,12 +1612,14 @@ impl, I: 'static> Pallet { // Select sqrt(n) random members from the society and make them skeptics. let pick_member = - |_| pick_item(&mut rng, &members[..]).expect("exited if members empty; qed"); - for skeptic in (0..members.len().integer_sqrt()).map(pick_member) { + |_| pick_item(&mut rng, &members[..]).expect("exited if members empty; qed").clone(); + let skeptics = (0..members.len().integer_sqrt()).map(pick_member).collect::>(); + skeptics.iter().for_each(|skeptic| { for Bid { who: c, .. } in candidates.iter() { >::insert(c, skeptic, Vote::Skeptic); } - } + }); + Self::deposit_event(Event::::SkepticsChosen { skeptics }); } /// Attempt to slash the payout of some member. Return the total amount that was deducted. diff --git a/frame/society/src/tests.rs b/frame/society/src/tests.rs index 864735aa10cca..0b42f77035776 100644 --- a/frame/society/src/tests.rs +++ b/frame/society/src/tests.rs @@ -211,6 +211,9 @@ fn payout_works() { #[test] fn basic_new_member_skeptic_works() { EnvBuilder::new().execute(|| { + // NOTE: events are not deposited in the genesis event + System::set_block_number(1); + assert_eq!(Strikes::::get(10), 0); assert_ok!(Society::bid(RuntimeOrigin::signed(20), 0)); run_to_block(4); @@ -218,6 +221,10 @@ fn basic_new_member_skeptic_works() { run_to_block(8); assert_eq!(Society::members(), vec![10]); assert_eq!(Strikes::::get(10), 1); + + System::assert_last_event(mock::RuntimeEvent::Society(crate::Event::SkepticsChosen { + skeptics: vec![10], + })); }); } From 09ae0e08f2ee72bb390b83370b2e1e4048904d18 Mon Sep 17 00:00:00 2001 From: Hussein Ait-Lahcen Date: Fri, 3 Feb 2023 15:21:24 +0100 Subject: [PATCH 360/715] feat(client): significantly increase wasm instance limits (#13298) Following https://github.com/paritytech/substrate/issues/11949, this PR will allow parachains with runtimes bigger than Kusama to use the pooling strategy. --- client/executor/wasmtime/src/runtime.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/executor/wasmtime/src/runtime.rs b/client/executor/wasmtime/src/runtime.rs index a45dfa59b954a..0c3fe228f08d5 100644 --- a/client/executor/wasmtime/src/runtime.rs +++ b/client/executor/wasmtime/src/runtime.rs @@ -376,8 +376,8 @@ fn common_config(semantics: &Semantics) -> std::result::Result Date: Fri, 3 Feb 2023 12:32:55 -0300 Subject: [PATCH 361/715] Remove in-tree bounded types and use bounded-collections crate (#13243) * Remove in-tree bounded types and use bounded-collections crate * Fixes * Bump bounded-collections version * cargo fmt * Bump bounded-collections * Only export non-bounded types at the top level * Fixes * Bump bounded-collections --- Cargo.lock | 17 +- primitives/core/Cargo.toml | 2 + .../core/src/bounded/bounded_btree_map.rs | 625 -------- .../core/src/bounded/bounded_btree_set.rs | 482 ------ primitives/core/src/bounded/bounded_vec.rs | 1305 ----------------- .../core/src/bounded/weak_bounded_vec.rs | 524 ------- primitives/core/src/lib.rs | 244 +-- 7 files changed, 24 insertions(+), 3175 deletions(-) delete mode 100644 primitives/core/src/bounded/bounded_btree_map.rs delete mode 100644 primitives/core/src/bounded/bounded_btree_set.rs delete mode 100644 primitives/core/src/bounded/bounded_vec.rs delete mode 100644 primitives/core/src/bounded/weak_bounded_vec.rs diff --git a/Cargo.lock b/Cargo.lock index dda127fdded77..492c5b15de119 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -699,6 +699,18 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" +[[package]] +name = "bounded-collections" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de2aff4807e40f478132150d80b031f2461d88f061851afcab537d7600c24120" +dependencies = [ + "log", + "parity-scale-codec", + "scale-info", + "serde", +] + [[package]] name = "bs58" version = "0.4.0" @@ -6722,9 +6734,9 @@ dependencies = [ [[package]] name = "parity-scale-codec" -version = "3.2.2" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ab01d0f889e957861bc65888d5ccbe82c158d0270136ba46820d43837cdf72" +checksum = "c3840933452adf7b3b9145e27086a5a3376c619dca1a21b1e5a5af0d54979bed" dependencies = [ "arrayvec 0.7.2", "bitvec", @@ -9849,6 +9861,7 @@ dependencies = [ "base58", "bitflags", "blake2", + "bounded-collections", "criterion", "dyn-clonable", "ed25519-zebra", diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index 5fd838de3538d..7c045377571f6 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -20,6 +20,7 @@ codec = { package = "parity-scale-codec", version = "3.2.2", default-features = 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"] } +bounded-collections = { version = "0.1.4", default-features = false } primitive-types = { version = "0.12.0", default-features = false, features = ["codec", "scale-info"] } impl-serde = { version = "0.4.0", optional = true } hash-db = { version = "0.15.2", default-features = false } @@ -80,6 +81,7 @@ std = [ "thiserror", "lazy_static", "parking_lot", + "bounded-collections/std", "primitive-types/std", "primitive-types/serde", "primitive-types/byteorder", diff --git a/primitives/core/src/bounded/bounded_btree_map.rs b/primitives/core/src/bounded/bounded_btree_map.rs deleted file mode 100644 index d2c148d6de9c5..0000000000000 --- a/primitives/core/src/bounded/bounded_btree_map.rs +++ /dev/null @@ -1,625 +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. - -//! Traits, types and structs to support a bounded BTreeMap. - -use crate::{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) - } - - /// 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() - } - - /// 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 -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) - } -} - -impl sp_std::fmt::Debug for BoundedBTreeMap -where - BTreeMap: sp_std::fmt::Debug, - S: Get, -{ - fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_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::::unchecked_from(self.collect::>())) - } - } -} - -#[cfg(test)] -pub mod test { - use super::*; - use crate::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 won'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 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); - } - - #[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"))); - } -} diff --git a/primitives/core/src/bounded/bounded_btree_set.rs b/primitives/core/src/bounded/bounded_btree_set.rs deleted file mode 100644 index 5feac6b7150f0..0000000000000 --- a/primitives/core/src/bounded/bounded_btree_set.rs +++ /dev/null @@ -1,482 +0,0 @@ -// 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::{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) - } -} - -impl sp_std::fmt::Debug for BoundedBTreeSet -where - BTreeSet: sp_std::fmt::Debug, - S: Get, -{ - fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_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::::unchecked_from(self.collect::>())) - } - } -} - -#[cfg(test)] -pub mod test { - use super::*; - use crate::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/core/src/bounded/bounded_vec.rs b/primitives/core/src/bounded/bounded_vec.rs deleted file mode 100644 index 6e1e1c7cfda64..0000000000000 --- a/primitives/core/src/bounded/bounded_vec.rs +++ /dev/null @@ -1,1305 +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. - -//! 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::{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( - pub(super) Vec, - #[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 - 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)] -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> {} -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, 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<'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) - } -} - -impl<'a, T, S: Get> TryFrom<&'a [T]> for BoundedSlice<'a, T, S> { - type Error = &'a [T]; - fn try_from(t: &'a [T]) -> Result { - if t.len() <= S::get() as usize { - Ok(BoundedSlice(t, PhantomData)) - } else { - Err(t) - } - } -} - -impl<'a, T, S> From> for &'a [T] { - fn from(t: BoundedSlice<'a, T, S>) -> Self { - t.0 - } -} - -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> {} - -// 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>; - fn into_iter(self) -> Self::IntoIter { - self.0.iter() - } -} - -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)?; - 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_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. - 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<(), T> { - if self.len() < Self::bound() { - self.0.insert(index, element); - Ok(()) - } else { - Err(element) - } - } - - /// 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<(), T> { - if self.len() < Self::bound() { - self.0.push(element); - Ok(()) - } else { - Err(element) - } - } -} - -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 - Self::unchecked_from(Vec::default()) - } -} - -impl sp_std::fmt::Debug for BoundedVec -where - Vec: 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 = Vec; - fn try_from(t: Vec) -> Result { - if t.len() <= Self::bound() { - // explicit check just above - Ok(Self::unchecked_from(t)) - } else { - Err(t) - } - } -} - -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 { - &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 all immutable 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 { - 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 - } -} - -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 - } -} - -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, - 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: - // See: https://docs.substrate.io/reference/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, 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]; - 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_vec_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 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]; - 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()); - } - - #[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]; - // Sort by absolute value. - 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[..]); - } -} diff --git a/primitives/core/src/bounded/weak_bounded_vec.rs b/primitives/core/src/bounded/weak_bounded_vec.rs deleted file mode 100644 index 5aff35f010c8b..0000000000000 --- a/primitives/core/src/bounded/weak_bounded_vec.rs +++ /dev/null @@ -1,524 +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. - -//! 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::Get; -use codec::{Decode, Encode, MaxEncodedLen}; -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. -/// -/// 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. -#[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, - #[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 { - 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()) - } -} - -impl sp_std::fmt::Debug for WeakBoundedVec -where - Vec: sp_std::fmt::Debug, - S: Get, -{ - fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_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) - } -} - -impl PartialEq> for WeakBoundedVec -where - T: PartialEq, - BoundSelf: Get, - BoundRhs: Get, -{ - 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 - } -} - -impl> PartialEq> for WeakBoundedVec { - fn eq(&self, other: &Vec) -> bool { - &self.0 == other - } -} - -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 - 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: - // See: https://docs.substrate.io/reference/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::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/core/src/lib.rs b/primitives/core/src/lib.rs index 80e14b84d3ff4..13dbad66be9ff 100644 --- a/primitives/core/src/lib.rs +++ b/primitives/core/src/lib.rs @@ -51,7 +51,6 @@ 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; @@ -81,6 +80,13 @@ pub use self::hasher::blake2::Blake2Hasher; pub use self::hasher::keccak::KeccakHasher; pub use hash_db::Hasher; +pub use bounded_collections as bounded; +#[cfg(feature = "std")] +pub use bounded_collections::{bounded_btree_map, bounded_vec}; +pub use bounded_collections::{ + parameter_types, ConstBool, ConstI128, ConstI16, ConstI32, ConstI64, ConstI8, ConstU128, + ConstU16, ConstU32, ConstU64, ConstU8, Get, GetDefault, TryCollect, TypedGet, +}; pub use sp_storage as storage; #[doc(hidden)] @@ -387,242 +393,6 @@ macro_rules! impl_maybe_marker { // 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() - } - }; -} - /// Generates a macro for checking if a certain feature is enabled. /// /// These feature checking macros can be used to conditionally enable/disable code in a dependent From dfc9223f5d28b258c7762012ae7ef48a7a7f1359 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Sun, 5 Feb 2023 15:18:56 -0500 Subject: [PATCH 362/715] update linregress in frame-benchmarking to 0.5.1 (#13310) * update nalgebra in frame-benchmarking to 0.5.0 * upgrade to 0.5.1 to incorporate upstream fix in linregress --- Cargo.lock | 58 +++++++++++++++++------------- frame/benchmarking/Cargo.toml | 2 +- frame/benchmarking/src/analysis.rs | 2 +- 3 files changed, 36 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 492c5b15de119..52de03f647512 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -765,6 +765,12 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" +[[package]] +name = "bytemuck" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c041d3eab048880cb0b86b256447da3f18859a163c3b8d8893f4e6368abe6393" + [[package]] name = "byteorder" version = "1.4.3" @@ -4181,12 +4187,11 @@ dependencies = [ [[package]] name = "linregress" -version = "0.4.4" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6c601a85f5ecd1aba625247bca0031585fb1c446461b142878a16f8245ddeb8" +checksum = "475015a7f8f017edb28d2e69813be23500ad4b32cfe3421c4148efc97324ee52" dependencies = [ "nalgebra", - "statrs", ] [[package]] @@ -4578,9 +4583,9 @@ dependencies = [ [[package]] name = "nalgebra" -version = "0.27.1" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "462fffe4002f4f2e1f6a9dcf12cc1a6fc0e15989014efc02a941d3e0f5dc2120" +checksum = "f6515c882ebfddccaa73ead7320ca28036c4bc84c9bcca3cc0cbba8efe89223a" dependencies = [ "approx", "matrixmultiply", @@ -4588,17 +4593,15 @@ dependencies = [ "num-complex", "num-rational", "num-traits", - "rand 0.8.5", - "rand_distr", "simba", "typenum", ] [[package]] name = "nalgebra-macros" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01fcc0b8149b4632adc89ac3b7b31a12fb6099a0317a4eb2ebff574ef7de7218" +checksum = "d232c68884c0c99810a5a4d333ef7e47689cfd0edc85efc9e54e1e6bf5212766" dependencies = [ "proc-macro2", "quote", @@ -7862,6 +7865,15 @@ dependencies = [ "rustc_version 0.2.3", ] +[[package]] +name = "safe_arch" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "794821e4ccb0d9f979512f9c1973480123f9bd62a90d74ab0f9426fcf8f4a529" +dependencies = [ + "bytemuck", +] + [[package]] name = "same-file" version = "1.0.6" @@ -9522,14 +9534,15 @@ dependencies = [ [[package]] name = "simba" -version = "0.5.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e82063457853d00243beda9952e910b82593e4b07ae9f721b9278a99a0d3d5c" +checksum = "50582927ed6f77e4ac020c057f37a268fc6aebc29225050365aacbb9deeeddc4" dependencies = [ "approx", "num-complex", "num-traits", "paste", + "wide", ] [[package]] @@ -10503,19 +10516,6 @@ dependencies = [ "syn", ] -[[package]] -name = "statrs" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05bdbb8e4e78216a85785a85d3ec3183144f98d0097b9281802c019bb07a6f05" -dependencies = [ - "approx", - "lazy_static", - "nalgebra", - "num-traits", - "rand 0.8.5", -] - [[package]] name = "strsim" version = "0.10.0" @@ -12395,6 +12395,16 @@ dependencies = [ "once_cell", ] +[[package]] +name = "wide" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "feff0a412894d67223777b6cc8d68c0dab06d52d95e9890d5f2d47f10dd9366c" +dependencies = [ + "bytemuck", + "safe_arch", +] + [[package]] name = "widestring" version = "0.5.1" diff --git a/frame/benchmarking/Cargo.toml b/frame/benchmarking/Cargo.toml index 4ff2077d7f7c5..7b8a7c5eaa940 100644 --- a/frame/benchmarking/Cargo.toml +++ b/frame/benchmarking/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false } -linregress = { version = "0.4.4", optional = true } +linregress = { version = "0.5.1", optional = true } log = { version = "0.4.17", default-features = false } paste = "1.0" scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } diff --git a/frame/benchmarking/src/analysis.rs b/frame/benchmarking/src/analysis.rs index 0b77a92347d03..e5afe8103f29c 100644 --- a/frame/benchmarking/src/analysis.rs +++ b/frame/benchmarking/src/analysis.rs @@ -161,7 +161,7 @@ fn raw_linear_regression( 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)) + Some((model.parameters()[0], model.parameters()[1..].to_vec(), model.se().to_vec())) } fn linear_regression( From 550e6a1ac24d7dbff4f7e2458ce20ee4c27c3c57 Mon Sep 17 00:00:00 2001 From: Anton Date: Mon, 6 Feb 2023 10:21:51 +0400 Subject: [PATCH 363/715] [client/network] remove peer entry from `ephemeral_addresses` (#13084) * [client/network] remove peer entry from `ephemeral_addresses` if there are no addresses associated with that peer * refactor as per @bkchr suggestion https://github.com/paritytech/substrate/pull/13084#discussion_r1068028534 * add missing import * fix error --- client/network/src/discovery.rs | 26 ++++++++++++++++---------- client/network/src/service.rs | 2 +- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/client/network/src/discovery.rs b/client/network/src/discovery.rs index 7329ebf15cf0d..b8805d1b1229d 100644 --- a/client/network/src/discovery.rs +++ b/client/network/src/discovery.rs @@ -77,7 +77,7 @@ use sc_network_common::{config::ProtocolId, utils::LruHashSet}; use sp_core::hexdisplay::HexDisplay; use std::{ cmp, - collections::{HashMap, HashSet, VecDeque}, + collections::{hash_map::Entry, HashMap, HashSet, VecDeque}, num::NonZeroUsize, task::{Context, Poll}, time::Duration, @@ -318,14 +318,16 @@ impl DiscoveryBehaviour { /// If we didn't know this address before, also generates a `Discovered` event. 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) { - if let Some(k) = self.kademlia.as_mut() { - k.add_address(&peer_id, addr.clone()); - } + if addrs_list.contains(&addr) { + return + } - self.pending_events.push_back(DiscoveryOut::Discovered(peer_id)); - addrs_list.push(addr); + if let Some(k) = self.kademlia.as_mut() { + k.add_address(&peer_id, addr.clone()); } + + self.pending_events.push_back(DiscoveryOut::Discovered(peer_id)); + addrs_list.push(addr); } /// Add a self-reported address of a remote peer to the k-buckets of the DHT @@ -456,7 +458,7 @@ pub enum DiscoveryOut { /// The DHT yielded results for the record request. /// - /// Returning the result grouped in (key, value) pairs as well as the request duration.. + /// Returning the result grouped in (key, value) pairs as well as the request duration. ValueFound(Vec<(record::Key, Vec)>, Duration), /// The record requested was not found in the DHT. @@ -535,9 +537,13 @@ impl NetworkBehaviour for DiscoveryBehaviour { FromSwarm::DialFailure(e @ DialFailure { peer_id, error, .. }) => { if let Some(peer_id) = peer_id { if let DialError::Transport(errors) = error { - if let Some(list) = self.ephemeral_addresses.get_mut(&peer_id) { + if let Entry::Occupied(mut entry) = self.ephemeral_addresses.entry(peer_id) + { for (addr, _error) in errors { - list.retain(|a| a != addr); + entry.get_mut().retain(|a| a != addr); + } + if entry.get().is_empty() { + entry.remove(); } } } diff --git a/client/network/src/service.rs b/client/network/src/service.rs index f3afb58e8e0e0..dbe148c899395 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -534,7 +534,7 @@ where self.network_service.behaviour().user_protocol().num_sync_requests() } - /// Adds an address for a node. + /// Adds an address known to a node. pub fn add_known_address(&mut self, peer_id: PeerId, addr: Multiaddr) { self.network_service.behaviour_mut().add_known_address(peer_id, addr); } From f5e370da7f34622637a343f03420b4242b321891 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Date: Mon, 6 Feb 2023 11:17:22 +0200 Subject: [PATCH 364/715] rpc-spec-v2/tx: Fix error typo (#13307) Signed-off-by: Alexandru Vasile --- client/rpc-spec-v2/src/transaction/error.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/rpc-spec-v2/src/transaction/error.rs b/client/rpc-spec-v2/src/transaction/error.rs index 72a5959992f9e..901d7c58b1417 100644 --- a/client/rpc-spec-v2/src/transaction/error.rs +++ b/client/rpc-spec-v2/src/transaction/error.rs @@ -68,7 +68,7 @@ impl From for TransactionEvent { Error::Pool(PoolError::TooLowPriority { old, new }) => TransactionEvent::Invalid(TransactionError { error: format!( - "The priority of the transactin is too low (pool {} > current {})", + "The priority of the transaction is too low (pool {} > current {})", old, new ), }), From 51cf2e790f118f6cfe8d94fb9ca96bc580bd7c98 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Mon, 6 Feb 2023 14:42:54 +0200 Subject: [PATCH 365/715] BEEFY: client support for detecting equivocated votes (#13285) * client/beefy: detect equivocated votes * client/beefy: make sure to persist state after voting * client/beefy: drop never-used aux-schema v2 migration * impl review suggestion --------- Signed-off-by: Adrian Catangiu --- Cargo.lock | 3 +- client/beefy/Cargo.toml | 1 - client/beefy/src/aux_schema.rs | 16 +- client/beefy/src/communication/gossip.rs | 7 +- client/beefy/src/justification.rs | 5 +- client/beefy/src/keystore.rs | 62 +--- client/beefy/src/metrics.rs | 6 + client/beefy/src/round.rs | 411 +++++++++++------------ client/beefy/src/tests.rs | 2 +- client/beefy/src/worker.rs | 133 +++----- primitives/beefy/Cargo.toml | 2 + primitives/beefy/src/commitment.rs | 1 + primitives/beefy/src/lib.rs | 79 ++++- 13 files changed, 373 insertions(+), 355 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 52de03f647512..afebaabd6c06c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -512,7 +512,6 @@ dependencies = [ "sp-mmr-primitives", "sp-runtime", "sp-tracing", - "strum", "substrate-prometheus-endpoint", "substrate-test-runtime-client", "tempfile", @@ -9734,6 +9733,7 @@ name = "sp-beefy" version = "4.0.0-dev" dependencies = [ "array-bytes", + "lazy_static", "parity-scale-codec", "scale-info", "serde", @@ -9745,6 +9745,7 @@ dependencies = [ "sp-mmr-primitives", "sp-runtime", "sp-std", + "strum", ] [[package]] diff --git a/client/beefy/Cargo.toml b/client/beefy/Cargo.toml index d81ff2587cf2c..2976d1474012a 100644 --- a/client/beefy/Cargo.toml +++ b/client/beefy/Cargo.toml @@ -39,7 +39,6 @@ sp-runtime = { version = "7.0.0", path = "../../primitives/runtime" } [dev-dependencies] serde = "1.0.136" -strum = { version = "0.24.1", features = ["derive"] } tempfile = "3.1.0" tokio = "1.22.0" sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" } diff --git a/client/beefy/src/aux_schema.rs b/client/beefy/src/aux_schema.rs index 217ea4769d8b9..6e87956dac2db 100644 --- a/client/beefy/src/aux_schema.rs +++ b/client/beefy/src/aux_schema.rs @@ -26,25 +26,25 @@ 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 WORKER_STATE_KEY: &[u8] = b"beefy_voter_state"; const CURRENT_VERSION: u32 = 2; -pub(crate) fn write_current_version(backend: &B) -> ClientResult<()> { +pub(crate) fn write_current_version(backend: &BE) -> ClientResult<()> { info!(target: LOG_TARGET, "🥩 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, +pub(crate) fn write_voter_state( + backend: &BE, + state: &PersistedState, ) -> ClientResult<()> { trace!(target: LOG_TARGET, "🥩 persisting {:?}", state); - backend.insert_aux(&[(WORKER_STATE, state.encode().as_slice())], &[]) + AuxStore::insert_aux(backend, &[(WORKER_STATE_KEY, state.encode().as_slice())], &[]) } -fn load_decode(backend: &B, key: &[u8]) -> ClientResult> { +fn load_decode(backend: &BE, key: &[u8]) -> ClientResult> { match backend.get_aux(key)? { None => Ok(None), Some(t) => T::decode(&mut &t[..]) @@ -64,7 +64,7 @@ where match version { None => (), Some(1) => (), // version 1 is totally obsolete and should be simply ignored - Some(2) => return load_decode::<_, PersistedState>(backend, WORKER_STATE), + Some(2) => return load_decode::<_, PersistedState>(backend, WORKER_STATE_KEY), other => return Err(ClientError::Backend(format!("Unsupported BEEFY DB version: {:?}", other))), } diff --git a/client/beefy/src/communication/gossip.rs b/client/beefy/src/communication/gossip.rs index 116a6286ed54d..5d51610214610 100644 --- a/client/beefy/src/communication/gossip.rs +++ b/client/beefy/src/communication/gossip.rs @@ -120,7 +120,7 @@ where /// Note a voting round. /// - /// Noting round will start a live `round`. + /// Noting round will track gossiped votes for `round`. pub(crate) fn note_round(&self, round: NumberFor) { debug!(target: LOG_TARGET, "🥩 About to note gossip round #{}", round); self.known_votes.write().insert(round); @@ -242,9 +242,10 @@ mod tests { use sc_network_test::Block; use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; - use crate::keystore::{tests::Keyring, BeefyKeystore}; + use crate::keystore::BeefyKeystore; use beefy_primitives::{ - crypto::Signature, known_payloads, Commitment, MmrRootHash, Payload, VoteMessage, KEY_TYPE, + crypto::Signature, keyring::Keyring, known_payloads, Commitment, MmrRootHash, Payload, + VoteMessage, KEY_TYPE, }; use super::*; diff --git a/client/beefy/src/justification.rs b/client/beefy/src/justification.rs index 7243c692727f0..6f869015ba763 100644 --- a/client/beefy/src/justification.rs +++ b/client/beefy/src/justification.rs @@ -81,12 +81,13 @@ fn verify_with_validator_set( #[cfg(test)] pub(crate) mod tests { use beefy_primitives::{ - known_payloads, Commitment, Payload, SignedCommitment, VersionedFinalityProof, + keyring::Keyring, known_payloads, Commitment, Payload, SignedCommitment, + VersionedFinalityProof, }; use substrate_test_runtime_client::runtime::Block; use super::*; - use crate::{keystore::tests::Keyring, tests::make_beefy_ids}; + use crate::tests::make_beefy_ids; pub(crate) fn new_finality_proof( block_num: NumberFor, diff --git a/client/beefy/src/keystore.rs b/client/beefy/src/keystore.rs index d1f5615a93701..73788a31b7fdc 100644 --- a/client/beefy/src/keystore.rs +++ b/client/beefy/src/keystore.rs @@ -19,7 +19,6 @@ use sp_application_crypto::RuntimeAppPublic; use sp_core::keccak_256; use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; -use sp_runtime::traits::Keccak256; use log::warn; @@ -30,6 +29,9 @@ use beefy_primitives::{ use crate::{error, LOG_TARGET}; +/// Hasher used for BEEFY signatures. +pub(crate) type BeefySignatureHasher = sp_runtime::traits::Keccak256; + /// A BEEFY specific keystore implemented as a `Newtype`. This is basically a /// wrapper around [`sp_keystore::SyncCryptoStore`] and allows to customize /// common cryptographic functionality. @@ -104,7 +106,7 @@ impl BeefyKeystore { /// /// Return `true` if the signature is authentic, `false` otherwise. pub fn verify(public: &Public, sig: &Signature, message: &[u8]) -> bool { - BeefyAuthorityId::::verify(public, sig, message) + BeefyAuthorityId::::verify(public, sig, message) } } @@ -119,63 +121,13 @@ pub mod tests { use std::sync::Arc; use sc_keystore::LocalKeystore; - use sp_core::{ecdsa, keccak_256, Pair}; - use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; + use sp_core::{ecdsa, Pair}; - use beefy_primitives::{crypto, KEY_TYPE}; + use beefy_primitives::{crypto, keyring::Keyring}; - use super::BeefyKeystore; + use super::*; 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()) } diff --git a/client/beefy/src/metrics.rs b/client/beefy/src/metrics.rs index 71e34e24c4fa0..55fdecc36d4b0 100644 --- a/client/beefy/src/metrics.rs +++ b/client/beefy/src/metrics.rs @@ -30,6 +30,8 @@ pub(crate) struct Metrics { pub beefy_round_concluded: Gauge, /// Best block finalized by BEEFY pub beefy_best_block: Gauge, + /// Best block BEEFY voted on + pub beefy_best_voted: Gauge, /// Next block BEEFY should vote on pub beefy_should_vote_on: Gauge, /// Number of sessions with lagging signed commitment on mandatory block @@ -61,6 +63,10 @@ impl Metrics { Gauge::new("substrate_beefy_best_block", "Best block finalized by BEEFY")?, registry, )?, + beefy_best_voted: register( + Gauge::new("substrate_beefy_best_voted", "Best block voted on by BEEFY")?, + registry, + )?, beefy_should_vote_on: register( Gauge::new("substrate_beefy_should_vote_on", "Next block, BEEFY should vote on")?, registry, diff --git a/client/beefy/src/round.rs b/client/beefy/src/round.rs index 647d42110e926..9ad4e5d0232bf 100644 --- a/client/beefy/src/round.rs +++ b/client/beefy/src/round.rs @@ -19,39 +19,33 @@ use crate::LOG_TARGET; use beefy_primitives::{ - crypto::{Public, Signature}, - ValidatorSet, ValidatorSetId, + crypto::{AuthorityId, Public, Signature}, + Commitment, SignedCommitment, ValidatorSet, ValidatorSetId, VoteMessage, }; use codec::{Decode, Encode}; -use log::{debug, trace}; +use log::debug; use sp_runtime::traits::{Block, NumberFor}; -use std::{collections::BTreeMap, hash::Hash}; +use std::collections::BTreeMap; /// 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, Decode, Default, Encode, PartialEq)] -struct RoundTracker { - self_vote: bool, +pub(crate) struct RoundTracker { votes: BTreeMap, } impl RoundTracker { - fn add_vote(&mut self, vote: (Public, Signature), self_vote: bool) -> bool { + fn add_vote(&mut self, vote: (Public, Signature)) -> bool { if self.votes.contains_key(&vote.0) { return false } - 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 } @@ -63,27 +57,37 @@ pub fn threshold(authorities: usize) -> usize { authorities - faulty } +#[derive(Debug, PartialEq)] +pub enum VoteImportResult { + Ok, + RoundConcluded(SignedCommitment, Signature>), + Equivocation, /* TODO: (EquivocationProof, Public, Signature>) */ + Invalid, + Stale, +} + /// 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). #[derive(Debug, Decode, Encode, PartialEq)] -pub(crate) struct Rounds { - rounds: BTreeMap<(Payload, NumberFor), RoundTracker>, +pub(crate) struct Rounds { + rounds: BTreeMap>, RoundTracker>, + previous_votes: BTreeMap<(Public, NumberFor), VoteMessage, Public, Signature>>, session_start: NumberFor, validator_set: ValidatorSet, mandatory_done: bool, best_done: Option>, } -impl Rounds +impl Rounds where - P: Ord + Hash + Clone, B: Block, { pub(crate) fn new(session_start: NumberFor, validator_set: ValidatorSet) -> Self { Rounds { rounds: BTreeMap::new(), + previous_votes: BTreeMap::new(), session_start, validator_set, mandatory_done: false, @@ -111,60 +115,77 @@ where self.mandatory_done } - pub(crate) fn should_self_vote(&self, round: &(P, NumberFor)) -> bool { - Some(round.1) > 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 { - let num = round.1; + vote: VoteMessage, AuthorityId, Signature>, + ) -> VoteImportResult { + let num = vote.commitment.block_number; + let vote_key = (vote.id.clone(), num); + if num < self.session_start || Some(num) <= self.best_done { debug!(target: LOG_TARGET, "🥩 received vote for old stale round {:?}, ignoring", num); - false - } else if !self.validators().iter().any(|id| vote.0 == *id) { + return VoteImportResult::Stale + } else if vote.commitment.validator_set_id != self.validator_set_id() { + debug!( + target: LOG_TARGET, + "🥩 expected set_id {:?}, ignoring vote {:?}.", + self.validator_set_id(), + vote, + ); + return VoteImportResult::Invalid + } else if !self.validators().iter().any(|id| &vote.id == id) { debug!( target: LOG_TARGET, "🥩 received vote {:?} from validator that is not in the validator set, ignoring", vote ); - false + return VoteImportResult::Invalid + } + + if let Some(previous_vote) = self.previous_votes.get(&vote_key) { + // is the same public key voting for a different payload? + if previous_vote.commitment.payload != vote.commitment.payload { + debug!( + target: LOG_TARGET, + "🥩 detected equivocated vote: 1st: {:?}, 2nd: {:?}", previous_vote, vote + ); + // TODO: build `EquivocationProof` and return it here. + return VoteImportResult::Equivocation + } } else { - self.rounds.entry(round.clone()).or_default().add_vote(vote, self_vote) + // this is the first vote sent by `id` for `num`, all good + self.previous_votes.insert(vote_key, vote.clone()); } + + // add valid vote + let round = self.rounds.entry(vote.commitment.clone()).or_default(); + if round.add_vote((vote.id, vote.signature)) && + round.is_done(threshold(self.validator_set.len())) + { + if let Some(round) = self.rounds.remove_entry(&vote.commitment) { + return VoteImportResult::RoundConcluded(self.signed_commitment(round)) + } + } + VoteImportResult::Ok } - pub(crate) fn should_conclude( + fn signed_commitment( &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); - trace!(target: LOG_TARGET, "🥩 Round #{} done: {}", round.1, done); - - if done { - let signatures = self.rounds.remove(round)?.votes; - Some( - self.validators() - .iter() - .map(|authority_id| signatures.get(authority_id).cloned()) - .collect(), - ) - } else { - None - } + round: (Commitment>, RoundTracker), + ) -> SignedCommitment, Signature> { + let votes = round.1.votes; + let signatures = self + .validators() + .iter() + .map(|authority_id| votes.get(authority_id).cloned()) + .collect(); + SignedCommitment { commitment: round.0, signatures } } pub(crate) fn conclude(&mut self, round_num: NumberFor) { // Remove this and older (now stale) rounds. - self.rounds.retain(|&(_, number), _| number > round_num); + self.rounds.retain(|commitment, _| commitment.block_number > round_num); + self.previous_votes.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: LOG_TARGET, "🥩 Concluded round #{}", round_num); @@ -174,16 +195,17 @@ where #[cfg(test)] mod tests { use sc_network_test::Block; - use sp_core::H256; - use beefy_primitives::{crypto::Public, ValidatorSet}; + use beefy_primitives::{ + crypto::Public, keyring::Keyring, known_payloads::MMR_ROOT_ID, Commitment, Payload, + SignedCommitment, ValidatorSet, VoteMessage, + }; - use super::{threshold, Block as BlockT, Hash, RoundTracker, Rounds}; - use crate::keystore::tests::Keyring; + use super::{threshold, Block as BlockT, RoundTracker, Rounds}; + use crate::round::VoteImportResult; - impl Rounds + impl Rounds where - P: Ord + Hash + Clone, B: BlockT, { pub(crate) fn test_set_mandatory_done(&mut self, done: bool) { @@ -197,26 +219,18 @@ mod tests { 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)); + assert!(rt.add_vote(bob_vote.clone())); // adding existing vote not allowed - assert!(!rt.add_vote(bob_vote, false)); - - // self vote still not added yet - assert!(!rt.has_self_vote()); + assert!(!rt.add_vote(bob_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)); + assert!(rt.add_vote(alice_vote)); - // self vote registered - assert!(rt.has_self_vote()); // vote is now done assert!(rt.is_done(threshold)); } @@ -242,7 +256,7 @@ mod tests { .unwrap(); let session_start = 1u64.into(); - let rounds = Rounds::::new(session_start, validators); + let rounds = Rounds::::new(session_start, validators); assert_eq!(42, rounds.validator_set_id()); assert_eq!(1, rounds.session_start()); @@ -266,65 +280,56 @@ mod tests { Default::default(), ) .unwrap(); - let round = (H256::from_low_u64_le(1), 1); + let validator_set_id = validators.id(); let session_start = 1u64.into(); - let mut rounds = Rounds::::new(session_start, validators); - - // no self vote yet, should self vote - assert!(rounds.should_self_vote(&round)); - + let mut rounds = Rounds::::new(session_start, validators); + + let payload = Payload::from_single_entry(MMR_ROOT_ID, vec![]); + let block_number = 1; + let commitment = Commitment { block_number, payload, validator_set_id }; + let mut vote = VoteMessage { + id: Keyring::Alice.public(), + commitment: commitment.clone(), + signature: Keyring::Alice.sign(b"I am committed"), + }; // add 1st good vote - assert!(rounds.add_vote( - &round, - (Keyring::Alice.public(), Keyring::Alice.sign(b"I am committed")), - true - )); - // round not concluded - assert!(rounds.should_conclude(&round).is_none()); - // self vote already present, should not self vote - assert!(!rounds.should_self_vote(&round)); - - // double voting not allowed - assert!(!rounds.add_vote( - &round, - (Keyring::Alice.public(), Keyring::Alice.sign(b"I am committed")), - true - )); + assert_eq!(rounds.add_vote(vote.clone()), VoteImportResult::Ok); + // double voting (same vote), ok, no effect + assert_eq!(rounds.add_vote(vote.clone()), VoteImportResult::Ok); + + vote.id = Keyring::Dave.public(); + vote.signature = Keyring::Dave.sign(b"I am committed"); // 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.should_conclude(&round).is_none()); + assert_eq!(rounds.add_vote(vote.clone()), VoteImportResult::Invalid); + vote.id = Keyring::Bob.public(); + vote.signature = Keyring::Bob.sign(b"I am committed"); // add 2nd good vote - assert!(rounds.add_vote( - &round, - (Keyring::Bob.public(), Keyring::Bob.sign(b"I am committed")), - false - )); - // round not concluded - assert!(rounds.should_conclude(&round).is_none()); - - // add 3rd good vote - assert!(rounds.add_vote( - &round, - (Keyring::Charlie.public(), Keyring::Charlie.sign(b"I am committed")), - false - )); - // round concluded - assert!(rounds.should_conclude(&round).is_some()); - rounds.conclude(round.1); + assert_eq!(rounds.add_vote(vote.clone()), VoteImportResult::Ok); + vote.id = Keyring::Charlie.public(); + vote.signature = Keyring::Charlie.sign(b"I am committed"); + // add 3rd good vote -> round concluded -> signatures present + assert_eq!( + rounds.add_vote(vote.clone()), + VoteImportResult::RoundConcluded(SignedCommitment { + commitment, + signatures: vec![ + Some(Keyring::Alice.sign(b"I am committed")), + Some(Keyring::Bob.sign(b"I am committed")), + Some(Keyring::Charlie.sign(b"I am committed")), + None, + ] + }) + ); + rounds.conclude(block_number); + + vote.id = Keyring::Eve.public(); + vote.signature = Keyring::Eve.sign(b"I am committed"); // 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 - )); + assert_eq!(rounds.add_vote(vote), VoteImportResult::Stale); } #[test] @@ -336,30 +341,39 @@ mod tests { 42, ) .unwrap(); - let alice = (Keyring::Alice.public(), Keyring::Alice.sign(b"I am committed")); + let validator_set_id = validators.id(); + // active rounds starts at block 10 let session_start = 10u64.into(); - let mut rounds = Rounds::::new(session_start, validators); - - let mut vote = (H256::from_low_u64_le(1), 9); + let mut rounds = Rounds::::new(session_start, validators); + + // vote on round 9 + let block_number = 9; + let payload = Payload::from_single_entry(MMR_ROOT_ID, vec![]); + let commitment = Commitment { block_number, payload, validator_set_id }; + let mut vote = VoteMessage { + id: Keyring::Alice.public(), + commitment, + signature: Keyring::Alice.sign(b"I am committed"), + }; // add vote for previous session, should fail - assert!(!rounds.add_vote(&vote, alice.clone(), true)); + assert_eq!(rounds.add_vote(vote.clone()), VoteImportResult::Stale); // 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)); + vote.commitment.block_number = 10; + assert_eq!(rounds.add_vote(vote.clone()), VoteImportResult::Stale); + vote.commitment.block_number = 11; + assert_eq!(rounds.add_vote(vote.clone()), VoteImportResult::Stale); // no votes present assert!(rounds.rounds.is_empty()); - // add good vote - vote.1 = 12; - assert!(rounds.add_vote(&vote, alice, true)); + // add vote for active round 12 + vote.commitment.block_number = 12; + assert_eq!(rounds.add_vote(vote), VoteImportResult::Ok); // good vote present assert_eq!(rounds.rounds.len(), 1); } @@ -369,88 +383,73 @@ mod tests { sp_tracing::try_init_simple(); let validators = ValidatorSet::::new( - vec![ - Keyring::Alice.public(), - Keyring::Bob.public(), - Keyring::Charlie.public(), - Keyring::Dave.public(), - ], + vec![Keyring::Alice.public(), Keyring::Bob.public(), Keyring::Charlie.public()], Default::default(), ) .unwrap(); + let validator_set_id = validators.id(); let session_start = 1u64.into(); - let mut rounds = Rounds::::new(session_start, validators); - - // round 1 - assert!(rounds.add_vote( - &(H256::from_low_u64_le(1), 1), - (Keyring::Alice.public(), Keyring::Alice.sign(b"I am committed")), - 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 - assert!(rounds.add_vote( - &(H256::from_low_u64_le(2), 2), - (Keyring::Alice.public(), Keyring::Alice.sign(b"I am again committed")), - 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 - assert!(rounds.add_vote( - &(H256::from_low_u64_le(3), 3), - (Keyring::Alice.public(), Keyring::Alice.sign(b"I am still committed")), - 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()); - - // conclude unknown round - 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.should_conclude(&(H256::from_low_u64_le(2), 2)).unwrap(); - rounds.conclude(2); + let mut rounds = Rounds::::new(session_start, validators); + + let payload = Payload::from_single_entry(MMR_ROOT_ID, vec![]); + let commitment = Commitment { block_number: 1, payload, validator_set_id }; + let mut alice_vote = VoteMessage { + id: Keyring::Alice.public(), + commitment: commitment.clone(), + signature: Keyring::Alice.sign(b"I am committed"), + }; + let mut bob_vote = VoteMessage { + id: Keyring::Bob.public(), + commitment: commitment.clone(), + signature: Keyring::Bob.sign(b"I am committed"), + }; + let mut charlie_vote = VoteMessage { + id: Keyring::Charlie.public(), + commitment, + signature: Keyring::Charlie.sign(b"I am committed"), + }; + let expected_signatures = vec![ + Some(Keyring::Alice.sign(b"I am committed")), + Some(Keyring::Bob.sign(b"I am committed")), + Some(Keyring::Charlie.sign(b"I am committed")), + ]; + + // round 1 - only 2 out of 3 vote + assert_eq!(rounds.add_vote(alice_vote.clone()), VoteImportResult::Ok); + assert_eq!(rounds.add_vote(charlie_vote.clone()), VoteImportResult::Ok); + // should be 1 active round assert_eq!(1, rounds.rounds.len()); + // round 2 - only Charlie votes + charlie_vote.commitment.block_number = 2; + assert_eq!(rounds.add_vote(charlie_vote.clone()), VoteImportResult::Ok); + // should be 2 active rounds + assert_eq!(2, rounds.rounds.len()); + + // round 3 - all validators vote -> round is concluded + alice_vote.commitment.block_number = 3; + bob_vote.commitment.block_number = 3; + charlie_vote.commitment.block_number = 3; + assert_eq!(rounds.add_vote(alice_vote.clone()), VoteImportResult::Ok); + assert_eq!(rounds.add_vote(bob_vote.clone()), VoteImportResult::Ok); 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 - ] + rounds.add_vote(charlie_vote.clone()), + VoteImportResult::RoundConcluded(SignedCommitment { + commitment: charlie_vote.commitment, + signatures: expected_signatures + }) ); + // should be only 2 active since this one auto-concluded + assert_eq!(2, rounds.rounds.len()); + + // conclude round 2 + rounds.conclude(2); + // should be no more active rounds since 2 was officially concluded and round "1" is stale + assert!(rounds.rounds.is_empty()); + + // conclude round 3 + rounds.conclude(3); + assert!(rounds.previous_votes.is_empty()); } } diff --git a/client/beefy/src/tests.rs b/client/beefy/src/tests.rs index 008137d9a9965..69cc9b2f652c4 100644 --- a/client/beefy/src/tests.rs +++ b/client/beefy/src/tests.rs @@ -26,12 +26,12 @@ use crate::{ }, 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}, + keyring::Keyring as BeefyKeyring, known_payloads, mmr::MmrRootProvider, BeefyApi, Commitment, ConsensusLog, MmrRootHash, Payload, SignedCommitment, ValidatorSet, diff --git a/client/beefy/src/worker.rs b/client/beefy/src/worker.rs index 4d057bffc0cd9..be5443d3dead8 100644 --- a/client/beefy/src/worker.rs +++ b/client/beefy/src/worker.rs @@ -26,13 +26,13 @@ use crate::{ keystore::BeefyKeystore, metric_inc, metric_set, metrics::Metrics, - round::Rounds, + round::{Rounds, VoteImportResult}, BeefyVoterLinks, LOG_TARGET, }; use beefy_primitives::{ crypto::{AuthorityId, Signature}, - Commitment, ConsensusLog, Payload, PayloadProvider, SignedCommitment, ValidatorSet, - VersionedFinalityProof, VoteMessage, BEEFY_ENGINE_ID, + Commitment, ConsensusLog, PayloadProvider, ValidatorSet, VersionedFinalityProof, VoteMessage, + BEEFY_ENGINE_ID, }; use codec::{Codec, Decode, Encode}; use futures::{stream::Fuse, FutureExt, StreamExt}; @@ -55,6 +55,7 @@ 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. @@ -83,17 +84,14 @@ pub(crate) struct VoterOracle { /// 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>, + sessions: VecDeque>, /// Min delta in block numbers between two blocks, BEEFY should vote on. min_block_delta: u32, } impl VoterOracle { /// Verify provided `sessions` satisfies requirements, then build `VoterOracle`. - pub fn checked_new( - sessions: VecDeque>, - min_block_delta: u32, - ) -> Option { + 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 @@ -136,13 +134,13 @@ impl VoterOracle { // 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> { + 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> { + fn active_rounds_mut(&mut self) -> Option<&mut Rounds> { self.sessions.front_mut() } @@ -157,7 +155,7 @@ impl VoterOracle { } /// Add new observed session to the Oracle. - pub fn add_session(&mut self, rounds: Rounds) { + 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(); @@ -264,6 +262,8 @@ pub(crate) struct PersistedState { best_grandpa_block_header: ::Header, /// Best block a BEEFY voting round has been concluded for. best_beefy_block: NumberFor, + /// Best block we voted on. + best_voted: 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, @@ -273,12 +273,13 @@ impl PersistedState { pub fn checked_new( grandpa_header: ::Header, best_beefy: NumberFor, - sessions: VecDeque>, + 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, + best_voted: Zero::zero(), voting_oracle, }) } @@ -381,7 +382,7 @@ where &self.persisted_state.voting_oracle } - fn active_rounds(&mut self) -> Option<&Rounds> { + fn active_rounds(&mut self) -> Option<&Rounds> { self.persisted_state.voting_oracle.active_rounds() } @@ -486,12 +487,9 @@ where ) -> Result<(), Error> { let block_num = vote.commitment.block_number; let best_grandpa = self.best_grandpa_block(); + self.gossip_validator.note_round(block_num); 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::Process => self.handle_vote(vote)?, RoundAction::Enqueue => { debug!(target: LOG_TARGET, "🥩 Buffer vote for round: {:?}.", block_num); if self.pending_votes.len() < MAX_BUFFERED_VOTE_ROUNDS { @@ -546,57 +544,47 @@ where fn handle_vote( &mut self, - round: (Payload, NumberFor), - vote: (AuthorityId, Signature), - self_vote: bool, + vote: VoteMessage, AuthorityId, Signature>, ) -> Result<(), Error> { - self.gossip_validator.note_round(round.1); - 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) { - self.gossip_validator.conclude_round(round.1); - - let block_num = round.1; - let commitment = Commitment { - payload: round.0, - block_number: block_num, - validator_set_id: rounds.validator_set_id(), - }; - - let finality_proof = - VersionedFinalityProof::V1(SignedCommitment { commitment, signatures }); - - metric_set!(self, beefy_round_concluded, block_num); + let block_number = vote.commitment.block_number; + match rounds.add_vote(vote) { + VoteImportResult::RoundConcluded(signed_commitment) => { + self.gossip_validator.conclude_round(block_number); + metric_set!(self, beefy_round_concluded, block_number); + let finality_proof = VersionedFinalityProof::V1(signed_commitment); info!( target: LOG_TARGET, - "🥩 Round #{} concluded, finality_proof: {:?}.", round.1, finality_proof + "🥩 Round #{} concluded, finality_proof: {:?}.", block_number, finality_proof ); - // We created the `finality_proof` and know to be valid. // New state is persisted after finalization. self.finalize(finality_proof)?; - } else { - let mandatory_round = self + }, + VoteImportResult::Ok => { + // Persist state after handling mandatory block vote. + if 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 { + .map(|(mandatory_num, _)| mandatory_num == block_number) + .unwrap_or(false) + { crate::aux_schema::write_voter_state(&*self.backend, &self.persisted_state) .map_err(|e| Error::Backend(e.to_string()))?; } - } - } + }, + VoteImportResult::Equivocation => { + // TODO: report returned `EquivocationProof` to chain through `pallet-beefy`. + () + }, + VoteImportResult::Invalid | VoteImportResult::Stale => (), + }; Ok(()) } @@ -695,11 +683,7 @@ where for (num, votes) in votes_to_handle.into_iter() { debug!(target: LOG_TARGET, "🥩 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, - ) { + if let Err(err) = self.handle_vote(v) { error!(target: LOG_TARGET, "🥩 Error handling buffered vote: {}", err); }; } @@ -716,7 +700,9 @@ where .voting_target(self.best_beefy_block(), self.best_grandpa_block()) { metric_set!(self, beefy_should_vote_on, target); - self.do_vote(target)?; + if target > self.persisted_state.best_voted { + self.do_vote(target)?; + } } Ok(()) } @@ -766,13 +752,6 @@ where .voting_oracle .active_rounds_mut() .ok_or(Error::UninitSession)?; - if !rounds.should_self_vote(&(payload.clone(), target_number)) { - debug!( - target: LOG_TARGET, - "🥩 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) { @@ -812,17 +791,17 @@ where debug!(target: LOG_TARGET, "🥩 Sent vote message: {:?}", message); - if let Err(err) = self.handle_vote( - (message.commitment.payload, message.commitment.block_number), - (message.id, message.signature), - true, - ) { + if let Err(err) = self.handle_vote(message) { error!(target: LOG_TARGET, "🥩 Error handling self vote: {}", err); } self.gossip_engine.gossip_message(topic::(), encoded_message, false); - Ok(()) + // Persist state after vote to avoid double voting in case of voter restarts. + self.persisted_state.best_voted = target_number; + metric_set!(self, beefy_best_voted, target_number); + crate::aux_schema::write_voter_state(&*self.backend, &self.persisted_state) + .map_err(|e| Error::Backend(e.to_string())) } fn process_new_state(&mut self) { @@ -848,8 +827,7 @@ where /// 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. + /// Run the main async loop which is driven by finality notifications and gossiped votes. pub(crate) async fn run( mut self, mut block_import_justif: Fuse>>, @@ -992,14 +970,15 @@ pub(crate) mod tests { use super::*; use crate::{ communication::notification::{BeefyBestBlockStream, BeefyVersionedFinalityProofStream}, - keystore::tests::Keyring, tests::{ create_beefy_keystore, get_beefy_streams, make_beefy_ids, BeefyPeer, BeefyTestNet, TestApi, }, BeefyRPCLinks, KnownPeers, }; - use beefy_primitives::{known_payloads, mmr::MmrRootProvider}; + use beefy_primitives::{ + keyring::Keyring, known_payloads, mmr::MmrRootProvider, Payload, SignedCommitment, + }; use futures::{future::poll_fn, task::Poll}; use parking_lot::Mutex; use sc_client_api::{Backend as BackendT, HeaderBackend}; @@ -1007,7 +986,7 @@ pub(crate) mod tests { use sc_network_test::TestNetFactory; use sp_api::HeaderT; use sp_blockchain::Backend as BlockchainBackendT; - use sp_runtime::traits::{One, Zero}; + use sp_runtime::traits::One; use substrate_test_runtime_client::{ runtime::{Block, Digest, DigestItem, Header, H256}, Backend, @@ -1018,7 +997,7 @@ pub(crate) mod tests { &self.voting_oracle } - pub fn active_round(&self) -> Option<&Rounds> { + pub fn active_round(&self) -> Option<&Rounds> { self.voting_oracle.active_rounds() } @@ -1032,7 +1011,7 @@ pub(crate) mod tests { } impl VoterOracle { - pub fn sessions(&self) -> &VecDeque> { + pub fn sessions(&self) -> &VecDeque> { &self.sessions } } @@ -1090,7 +1069,7 @@ pub(crate) mod tests { min_block_delta, ) .unwrap(); - let payload_provider = MmrRootProvider::new(api); + let payload_provider = MmrRootProvider::new(api.clone()); let worker_params = crate::worker::WorkerParams { backend, payload_provider, diff --git a/primitives/beefy/Cargo.toml b/primitives/beefy/Cargo.toml index 6a22f0383a3d0..e4154071d26eb 100644 --- a/primitives/beefy/Cargo.toml +++ b/primitives/beefy/Cargo.toml @@ -22,6 +22,8 @@ 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 = "7.0.0", default-features = false, path = "../runtime" } sp-std = { version = "5.0.0", default-features = false, path = "../std" } +strum = { version = "0.24.1", features = ["derive"] } +lazy_static = "1.4.0" [dev-dependencies] array-bytes = "4.1" diff --git a/primitives/beefy/src/commitment.rs b/primitives/beefy/src/commitment.rs index 5765ff3609dbb..8642a83aae4be 100644 --- a/primitives/beefy/src/commitment.rs +++ b/primitives/beefy/src/commitment.rs @@ -77,6 +77,7 @@ where self.validator_set_id .cmp(&other.validator_set_id) .then_with(|| self.block_number.cmp(&other.block_number)) + .then_with(|| self.payload.cmp(&other.payload)) } } diff --git a/primitives/beefy/src/lib.rs b/primitives/beefy/src/lib.rs index 8c219040b3523..08467a723b704 100644 --- a/primitives/beefy/src/lib.rs +++ b/primitives/beefy/src/lib.rs @@ -173,7 +173,7 @@ pub enum ConsensusLog { /// /// A vote message is a direct vote created by a BEEFY node on every voting round /// and is gossiped to its peers. -#[derive(Debug, Decode, Encode, TypeInfo)] +#[derive(Clone, Debug, Decode, Encode, PartialEq, TypeInfo)] pub struct VoteMessage { /// Commit to information extracted from a finalized block pub commitment: Commitment, @@ -209,6 +209,83 @@ sp_api::decl_runtime_apis! { } } +#[cfg(feature = "std")] +/// Test accounts using [`crate::crypto`] types. +pub mod keyring { + use super::*; + use sp_core::{ecdsa, keccak_256, Pair}; + use std::collections::HashMap; + use strum::IntoEnumIterator; + + /// Set of test accounts using [`crate::crypto`] types. + #[allow(missing_docs)] + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, strum::Display, strum::EnumIter)] + pub enum Keyring { + Alice, + Bob, + Charlie, + Dave, + Eve, + Ferdie, + One, + Two, + } + + impl Keyring { + /// Sign `msg`. + pub fn sign(self, msg: &[u8]) -> crypto::Signature { + // todo: use custom signature hashing type + 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) + } + + /// Get Keyring from public key. + pub fn from_public(who: &crypto::Public) -> Option { + Self::iter().find(|&k| &crypto::Public::from(k) == who) + } + } + + lazy_static::lazy_static! { + static ref PRIVATE_KEYS: HashMap = + Keyring::iter().map(|i| (i, i.pair())).collect(); + static ref PUBLIC_KEYS: HashMap = + PRIVATE_KEYS.iter().map(|(&name, pair)| (name, pair.public())).collect(); + } + + 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() + } + } + + impl From for crypto::Public { + fn from(k: Keyring) -> Self { + (*PUBLIC_KEYS).get(&k).cloned().unwrap() + } + } +} + #[cfg(test)] mod tests { use super::*; From 47ecdb6ea686807479c4e5107dbdd8b5e855d843 Mon Sep 17 00:00:00 2001 From: Koute Date: Tue, 7 Feb 2023 00:40:50 +0900 Subject: [PATCH 366/715] Bump `wasmtime` to 5.0.0 (and a few other deps) (#13160) * Bump `wasmtime` to 4.0.0 (and a few other deps) * Use `Error::msg` instead of `anyhow!` * Bump `wasmtime` to 5.0.0 * Update `Cargo.lock` * Add `wasmtime` feature to `sp-wasm-interface` dependency --- Cargo.lock | 159 ++++++++---------- client/executor/wasmtime/Cargo.toml | 11 +- client/executor/wasmtime/src/imports.rs | 4 +- .../executor/wasmtime/src/instance_wrapper.rs | 34 ++-- client/executor/wasmtime/src/runtime.rs | 40 +++-- client/executor/wasmtime/src/tests.rs | 35 +++- .../host_function_interface.rs | 6 +- primitives/wasm-interface/Cargo.toml | 4 +- primitives/wasm-interface/src/lib.rs | 3 + utils/wasm-builder/Cargo.toml | 2 +- 10 files changed, 156 insertions(+), 142 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index afebaabd6c06c..a74ad26e7a9a9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -813,15 +813,16 @@ dependencies = [ [[package]] name = "cargo_metadata" -version = "0.14.2" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa" +checksum = "982a0cf6a99c350d7246035613882e376d58cebe571785abc5da4f648d53ac0a" dependencies = [ "camino", "cargo-platform", "semver 1.0.16", "serde", "serde_json", + "thiserror", ] [[package]] @@ -1178,18 +1179,18 @@ checksum = "dcb25d077389e53838a8158c8e99174c5a9d902dee4904320db714f3c653ffba" [[package]] name = "cranelift-bforest" -version = "0.88.2" +version = "0.92.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52056f6d0584484b57fa6c1a65c1fcb15f3780d8b6a758426d9e3084169b2ddd" +checksum = "2f3d54eab028f5805ae3b26fd60eca3f3a9cfb76b989d9bab173be3f61356cc3" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-codegen" -version = "0.88.2" +version = "0.92.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fed94c8770dc25d01154c3ffa64ed0b3ba9d583736f305fed7beebe5d9cf74" +checksum = "2be1d5f2c3cca1efb691844bc1988b89c77291f13f778499a3f3c0cf49c0ed61" dependencies = [ "arrayvec 0.7.2", "bumpalo", @@ -1199,6 +1200,7 @@ dependencies = [ "cranelift-entity", "cranelift-isle", "gimli 0.26.2", + "hashbrown 0.12.3", "log", "regalloc2", "smallvec", @@ -1207,33 +1209,33 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.88.2" +version = "0.92.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c451b81faf237d11c7e4f3165eeb6bac61112762c5cfe7b4c0fb7241474358f" +checksum = "3f9b1b1089750ce4005893af7ee00bb08a2cf1c9779999c0f7164cbc8ad2e0d2" dependencies = [ "cranelift-codegen-shared", ] [[package]] name = "cranelift-codegen-shared" -version = "0.88.2" +version = "0.92.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7c940133198426d26128f08be2b40b0bd117b84771fd36798969c4d712d81fc" +checksum = "cc5fbaec51de47297fd7304986fd53c8c0030abbe69728a60d72e1c63559318d" [[package]] name = "cranelift-entity" -version = "0.88.2" +version = "0.92.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87a0f1b2fdc18776956370cf8d9b009ded3f855350c480c1c52142510961f352" +checksum = "dab984c94593f876090fae92e984bdcc74d9b1acf740ab5f79036001c65cba13" dependencies = [ "serde", ] [[package]] name = "cranelift-frontend" -version = "0.88.2" +version = "0.92.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34897538b36b216cc8dd324e73263596d51b8cf610da6498322838b2546baf8a" +checksum = "6e0cb3102d21a2fe5f3210af608748ddd0cd09825ac12d42dc56ed5ed8725fe0" dependencies = [ "cranelift-codegen", "log", @@ -1243,15 +1245,15 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.88.2" +version = "0.92.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b2629a569fae540f16a76b70afcc87ad7decb38dc28fa6c648ac73b51e78470" +checksum = "72101dd1f441d629735143c41e00b3428f9267738176983ef588ff43382af0a0" [[package]] name = "cranelift-native" -version = "0.88.2" +version = "0.92.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20937dab4e14d3e225c5adfc9c7106bafd4ac669bdb43027b911ff794c6fb318" +checksum = "c22b0d9fcbe3fc5a1af9e7021b44ce42b930bcefac446ce22e02e8f9a0d67120" dependencies = [ "cranelift-codegen", "libc", @@ -1260,9 +1262,9 @@ dependencies = [ [[package]] name = "cranelift-wasm" -version = "0.88.2" +version = "0.92.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80fc2288957a94fd342a015811479de1837850924166d1f1856d8406e6f3609b" +checksum = "bddebe32fb14fbfd9efa5f130ffb8f4665795de019928dcd7247b136c46f9249" dependencies = [ "cranelift-codegen", "cranelift-entity", @@ -3251,12 +3253,6 @@ dependencies = [ "webrtc-util", ] -[[package]] -name = "io-lifetimes" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ce5ef949d49ee85593fc4d3f3f95ad61657076395cbbce23e2121fc5542074" - [[package]] name = "io-lifetimes" version = "1.0.3" @@ -3298,8 +3294,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189" dependencies = [ "hermit-abi 0.2.6", - "io-lifetimes 1.0.3", - "rustix 0.36.6", + "io-lifetimes", + "rustix", "windows-sys 0.42.0", ] @@ -4193,12 +4189,6 @@ dependencies = [ "nalgebra", ] -[[package]] -name = "linux-raw-sys" -version = "0.0.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4d2456c373231a208ad294c33dc5bff30051eafd954cd4caae83a712b12854d" - [[package]] name = "linux-raw-sys" version = "0.1.4" @@ -4349,7 +4339,7 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b20a59d985586e4a5aef64564ac77299f8586d8be6cf9106a5a40207e8908efb" dependencies = [ - "rustix 0.36.6", + "rustix", ] [[package]] @@ -7550,9 +7540,9 @@ dependencies = [ [[package]] name = "regalloc2" -version = "0.3.2" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d43a209257d978ef079f3d446331d0f1794f5e0fc19b306a199983857833a779" +checksum = "300d4fbfb40c1c66a78ba3ddd41c1110247cf52f97b87d0f2fc9209bd49b030c" dependencies = [ "fxhash", "log", @@ -7747,20 +7737,6 @@ dependencies = [ "nom", ] -[[package]] -name = "rustix" -version = "0.35.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "727a1a6d65f786ec22df8a81ca3121107f235970dc1705ed681d3e6e8b9cd5f9" -dependencies = [ - "bitflags", - "errno", - "io-lifetimes 0.7.5", - "libc", - "linux-raw-sys 0.0.46", - "windows-sys 0.42.0", -] - [[package]] name = "rustix" version = "0.36.6" @@ -7769,9 +7745,9 @@ checksum = "4feacf7db682c6c329c4ede12649cd36ecab0f3be5b7d74e6a20304725db4549" dependencies = [ "bitflags", "errno", - "io-lifetimes 1.0.3", + "io-lifetimes", "libc", - "linux-raw-sys 0.1.4", + "linux-raw-sys", "windows-sys 0.42.0", ] @@ -8389,13 +8365,15 @@ dependencies = [ name = "sc-executor-wasmtime" version = "0.10.0-dev" dependencies = [ + "anyhow", + "cargo_metadata", "cfg-if", "libc", "log", "once_cell", "parity-scale-codec", "paste", - "rustix 0.35.13", + "rustix", "sc-allocator", "sc-executor-common", "sc-runtime-test", @@ -10418,6 +10396,7 @@ dependencies = [ name = "sp-wasm-interface" version = "7.0.0" dependencies = [ + "anyhow", "impl-trait-for-tuples", "log", "parity-scale-codec", @@ -11918,11 +11897,12 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.89.1" +version = "0.96.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5d3e08b13876f96dd55608d03cd4883a0545884932d5adf11925876c96daef" +checksum = "adde01ade41ab9a5d10ec8ed0bb954238cf8625b5cd5a13093d6de2ad9c2be1a" dependencies = [ "indexmap", + "url", ] [[package]] @@ -11936,9 +11916,9 @@ dependencies = [ [[package]] name = "wasmtime" -version = "1.0.2" +version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ad5af6ba38311282f2a21670d96e78266e8c8e2f38cbcd52c254df6ccbc7731" +checksum = "4e5b183a159484980138cc05231419c536d395a7b25c1802091310ea2f74276a" dependencies = [ "anyhow", "bincode", @@ -11959,23 +11939,23 @@ dependencies = [ "wasmtime-environ", "wasmtime-jit", "wasmtime-runtime", - "windows-sys 0.36.1", + "windows-sys 0.42.0", ] [[package]] name = "wasmtime-asm-macros" -version = "1.0.2" +version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45de63ddfc8b9223d1adc8f7b2ee5f35d1f6d112833934ad7ea66e4f4339e597" +checksum = "c0aeb1cb256d76cf07b20264c808351c8b525ece56de1ef4d93f87a0aaf342db" dependencies = [ "cfg-if", ] [[package]] name = "wasmtime-cache" -version = "1.0.2" +version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcd849399d17d2270141cfe47fa0d91ee52d5f8ea9b98cf7ddde0d53e5f79882" +checksum = "830570847f905b8f6d2ca635c33cf42ce701dd8e4abd7d1806c631f8f06e9e4b" dependencies = [ "anyhow", "base64", @@ -11983,19 +11963,19 @@ dependencies = [ "directories-next", "file-per-thread-logger", "log", - "rustix 0.35.13", + "rustix", "serde", - "sha2 0.9.9", + "sha2 0.10.6", "toml", - "windows-sys 0.36.1", + "windows-sys 0.42.0", "zstd", ] [[package]] name = "wasmtime-cranelift" -version = "1.0.2" +version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bd91339b742ff20bfed4532a27b73c86b5bcbfedd6bea2dcdf2d64471e1b5c6" +checksum = "2f7695d3814dcb508bf4d1c181a86ea6b97a209f6444478e95d86e2ffab8d1a3" dependencies = [ "anyhow", "cranelift-codegen", @@ -12014,9 +11994,9 @@ dependencies = [ [[package]] name = "wasmtime-environ" -version = "1.0.2" +version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebb881c61f4f627b5d45c54e629724974f8a8890d455bcbe634330cc27309644" +checksum = "e5a2a5f0fb93aa837a727a48dd1076e8a9f882cc2fee20b433c04a18740ff63b" dependencies = [ "anyhow", "cranelift-entity", @@ -12033,9 +12013,9 @@ dependencies = [ [[package]] name = "wasmtime-jit" -version = "1.0.2" +version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1985c628011fe26adf5e23a5301bdc79b245e0e338f14bb58b39e4e25e4d8681" +checksum = "01c78f9fb2922dbb5a95f009539d4badb44866caeeb53d156bf2cf4d683c3afd" dependencies = [ "addr2line 0.17.0", "anyhow", @@ -12046,32 +12026,42 @@ dependencies = [ "log", "object 0.29.0", "rustc-demangle", - "rustix 0.35.13", "serde", "target-lexicon", - "thiserror", "wasmtime-environ", "wasmtime-jit-debug", + "wasmtime-jit-icache-coherence", "wasmtime-runtime", - "windows-sys 0.36.1", + "windows-sys 0.42.0", ] [[package]] name = "wasmtime-jit-debug" -version = "1.0.2" +version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f671b588486f5ccec8c5a3dba6b4c07eac2e66ab8c60e6f4e53717c77f709731" +checksum = "67cacdb52a77b8c8e744e510beeabf0bd698b1c94c59eed33c52b3fbd19639b0" dependencies = [ "object 0.29.0", "once_cell", - "rustix 0.35.13", + "rustix", +] + +[[package]] +name = "wasmtime-jit-icache-coherence" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08fcba5ebd96da2a9f0747ab6337fe9788adfb3f63fa2c180520d665562d257e" +dependencies = [ + "cfg-if", + "libc", + "windows-sys 0.42.0", ] [[package]] name = "wasmtime-runtime" -version = "1.0.2" +version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee8f92ad4b61736339c29361da85769ebc200f184361959d1792832e592a1afd" +checksum = "0793210acf50d4c69182c916abaee1d423dc5d172cdfde6acfea2f9446725940" dependencies = [ "anyhow", "cc", @@ -12084,19 +12074,18 @@ dependencies = [ "memoffset 0.6.5", "paste", "rand 0.8.5", - "rustix 0.35.13", - "thiserror", + "rustix", "wasmtime-asm-macros", "wasmtime-environ", "wasmtime-jit-debug", - "windows-sys 0.36.1", + "windows-sys 0.42.0", ] [[package]] name = "wasmtime-types" -version = "1.0.2" +version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d23d61cb4c46e837b431196dd06abb11731541021916d03476a178b54dc07aeb" +checksum = "50d015ba8b231248a811e323cf7a525cd3f982d4be0b9e62d27685102e5f12b1" dependencies = [ "cranelift-entity", "serde", diff --git a/client/executor/wasmtime/Cargo.toml b/client/executor/wasmtime/Cargo.toml index 983ca3c44fba0..acd1a5aef9391 100644 --- a/client/executor/wasmtime/Cargo.toml +++ b/client/executor/wasmtime/Cargo.toml @@ -19,18 +19,18 @@ log = "0.4.17" # When bumping wasmtime do not forget to also bump rustix # to exactly the same version as used by wasmtime! -wasmtime = { version = "1.0.0", default-features = false, features = [ +wasmtime = { version = "5.0.0", default-features = false, features = [ "cache", "cranelift", "jitdump", "parallel-compilation", - "memory-init-cow", - "pooling-allocator", + "pooling-allocator" ] } +anyhow = "1.0.68" 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-wasm-interface = { version = "7.0.0", path = "../../../primitives/wasm-interface" } +sp-wasm-interface = { version = "7.0.0", path = "../../../primitives/wasm-interface", features = ["wasmtime"] } # Here we include the rustix crate in the exactly same semver-compatible version as used by # wasmtime and enable its 'use-libc' flag. @@ -38,7 +38,7 @@ sp-wasm-interface = { version = "7.0.0", path = "../../../primitives/wasm-interf # By default rustix directly calls the appropriate syscalls completely bypassing libc; # this doesn't have any actual benefits for us besides making it harder to debug memory # problems (since then `mmap` etc. cannot be easily hooked into). -rustix = { version = "0.35.9", default-features = false, features = ["std", "mm", "fs", "param", "use-libc"] } +rustix = { version = "0.36.0", default-features = false, features = ["std", "mm", "fs", "param", "use-libc"] } once_cell = "1.12.0" [dev-dependencies] @@ -48,3 +48,4 @@ sp-io = { version = "7.0.0", path = "../../../primitives/io" } tempfile = "3.3.0" paste = "1.0" codec = { package = "parity-scale-codec", version = "3.2.2" } +cargo_metadata = "0.15.2" diff --git a/client/executor/wasmtime/src/imports.rs b/client/executor/wasmtime/src/imports.rs index c80952a2541ce..fad3195de93dc 100644 --- a/client/executor/wasmtime/src/imports.rs +++ b/client/executor/wasmtime/src/imports.rs @@ -20,7 +20,7 @@ use crate::{host::HostContext, runtime::StoreData}; use sc_executor_common::error::WasmError; use sp_wasm_interface::{FunctionContext, HostFunctions}; use std::collections::HashMap; -use wasmtime::{ExternType, FuncType, ImportType, Linker, Module, Trap}; +use wasmtime::{ExternType, FuncType, ImportType, Linker, Module}; /// 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. @@ -67,7 +67,7 @@ where log::debug!("Missing import: '{}' {:?}", name, func_ty); linker .func_new("env", &name, func_ty.clone(), move |_, _, _| { - Err(Trap::new(error.clone())) + Err(anyhow::Error::msg(error.clone())) }) .expect("adding a missing import stub can only fail when the item already exists, and it is missing here; qed"); } diff --git a/client/executor/wasmtime/src/instance_wrapper.rs b/client/executor/wasmtime/src/instance_wrapper.rs index feded4008068d..2117f1ebf2e91 100644 --- a/client/executor/wasmtime/src/instance_wrapper.rs +++ b/client/executor/wasmtime/src/instance_wrapper.rs @@ -76,27 +76,17 @@ impl EntryPoint { .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), - }) + let backtrace = trap.downcast_ref::().map(|backtrace| { + // The logic to print out a backtrace is somewhat complicated, + // so let's get wasmtime to print it out for us. + Backtrace { backtrace_string: backtrace.to_string() } + }); + + if let Some(message) = host_state.take_panic_message() { + Error::AbortedDueToPanic(MessageWithBacktrace { message, backtrace }) } else { - Error::AbortedDueToTrap(MessageWithBacktrace { - message: trap.display_reason().to_string(), - backtrace: Some(backtrace), - }) + let message = trap.root_cause().to_string(); + Error::AbortedDueToTrap(MessageWithBacktrace { message, backtrace }) } }) } @@ -106,7 +96,7 @@ impl EntryPoint { ctx: impl AsContext, ) -> std::result::Result { let entrypoint = func - .typed::<(u32, u32), u64, _>(ctx) + .typed::<(u32, u32), u64>(ctx) .map_err(|_| "Invalid signature for direct entry point")?; Ok(Self { call_type: EntryPointType::Direct { entrypoint } }) } @@ -117,7 +107,7 @@ impl EntryPoint { ctx: impl AsContext, ) -> std::result::Result { let dispatcher = dispatcher - .typed::<(u32, u32, u32), u64, _>(ctx) + .typed::<(u32, u32, u32), u64>(ctx) .map_err(|_| "Invalid signature for wrapped entry point")?; Ok(Self { call_type: EntryPointType::Wrapped { func, dispatcher } }) } diff --git a/client/executor/wasmtime/src/runtime.rs b/client/executor/wasmtime/src/runtime.rs index 0c3fe228f08d5..e54070065274b 100644 --- a/client/executor/wasmtime/src/runtime.rs +++ b/client/executor/wasmtime/src/runtime.rs @@ -366,29 +366,27 @@ fn common_config(semantics: &Semantics) -> std::result::Result String { // 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; +const CALL_DEPTH_LOWER_LIMIT: usize = 65455; +const CALL_DEPTH_UPPER_LIMIT: usize = 65503; 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) { @@ -555,3 +555,34 @@ fn test_instances_without_reuse_are_not_leaked() { instance.call_export("test_empty_return", &[0]).unwrap(); } } + +#[test] +fn test_rustix_version_matches_with_wasmtime() { + let metadata = cargo_metadata::MetadataCommand::new() + .manifest_path("../../../Cargo.toml") + .exec() + .unwrap(); + + let wasmtime_rustix = metadata + .packages + .iter() + .find(|pkg| pkg.name == "wasmtime-runtime") + .unwrap() + .dependencies + .iter() + .find(|dep| dep.name == "rustix") + .unwrap(); + let our_rustix = metadata + .packages + .iter() + .find(|pkg| pkg.name == "sc-executor-wasmtime") + .unwrap() + .dependencies + .iter() + .find(|dep| dep.name == "rustix") + .unwrap(); + + if wasmtime_rustix.req != our_rustix.req { + panic!("our version of rustix ({0}) doesn't match wasmtime's ({1}); bump the version in `sc-executor-wasmtime`'s `Cargo.toml' to '{1}' and try again", our_rustix.req, wasmtime_rustix.req); + } +} 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 03da0bed59815..280c13667fde3 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 @@ -371,14 +371,14 @@ fn generate_host_function_implementation( 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> + -> std::result::Result<#ffi_return_ty, #crate_::sp_wasm_interface::anyhow::Error> { T::with_function_context(caller, move |__function_context__| { 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) + ).map_err(#crate_::sp_wasm_interface::anyhow::Error::msg) })); match result { Ok(result) => result, @@ -391,7 +391,7 @@ fn generate_host_function_implementation( } else { "host code panicked while being called by the runtime".to_owned() }; - return Err(#crate_::sp_wasm_interface::wasmtime::Trap::new(message)); + return Err(#crate_::sp_wasm_interface::anyhow::Error::msg(message)); } } }) diff --git a/primitives/wasm-interface/Cargo.toml b/primitives/wasm-interface/Cargo.toml index 69937e6b05205..5f914ae3aa177 100644 --- a/primitives/wasm-interface/Cargo.toml +++ b/primitives/wasm-interface/Cargo.toml @@ -18,9 +18,11 @@ codec = { package = "parity-scale-codec", version = "3.2.2", default-features = 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 } +wasmtime = { version = "5.0.0", default-features = false, optional = true } +anyhow = { version = "1.0.68", optional = true } sp-std = { version = "5.0.0", default-features = false, path = "../std" } [features] default = [ "std" ] std = [ "codec/std", "log", "sp-std/std", "wasmi", "wasmtime" ] +wasmtime = [ "dep:wasmtime", "anyhow" ] diff --git a/primitives/wasm-interface/src/lib.rs b/primitives/wasm-interface/src/lib.rs index 1ecff5a0ce91e..c06eb43c7268b 100644 --- a/primitives/wasm-interface/src/lib.rs +++ b/primitives/wasm-interface/src/lib.rs @@ -41,6 +41,9 @@ macro_rules! if_wasmtime_is_enabled { if_wasmtime_is_enabled! { // Reexport wasmtime so that its types are accessible from the procedural macro. pub use wasmtime; + + // Wasmtime uses anyhow types but doesn't reexport them. + pub use anyhow; } /// Result type used by traits in this crate. diff --git a/utils/wasm-builder/Cargo.toml b/utils/wasm-builder/Cargo.toml index 84693f5eec049..c1ef006b5a92f 100644 --- a/utils/wasm-builder/Cargo.toml +++ b/utils/wasm-builder/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] ansi_term = "0.12.1" build-helper = "0.1.1" -cargo_metadata = "0.14.2" +cargo_metadata = "0.15.2" strum = { version = "0.24.1", features = ["derive"] } tempfile = "3.1.0" toml = "0.5.4" From fe7f0a90f6d8ee09c18cfcc9927b347fcc2afdc2 Mon Sep 17 00:00:00 2001 From: cuteolaf <53915161+cuteolaf@users.noreply.github.com> Date: Mon, 6 Feb 2023 09:34:52 -0800 Subject: [PATCH 367/715] Fix: Off-chain-worker example (#13300) * fix: divider * update comment --- frame/examples/offchain-worker/src/lib.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/frame/examples/offchain-worker/src/lib.rs b/frame/examples/offchain-worker/src/lib.rs index 46ff7725e3b16..203ea2f27bacb 100644 --- a/frame/examples/offchain-worker/src/lib.rs +++ b/frame/examples/offchain-worker/src/lib.rs @@ -410,15 +410,14 @@ impl Pallet { match res { // The value has been set correctly, which means we can safely send a transaction now. Ok(block_number) => { - // Depending if the block is even or odd we will send a `Signed` or `Unsigned` - // transaction. + // We will send different transactions based on a random number. // Note that this logic doesn't really guarantee that the transactions will be sent // in an alternating fashion (i.e. fairly distributed). Depending on the execution // order and lock acquisition, we may end up for instance sending two `Signed` // transactions in a row. If a strict order is desired, it's better to use // the storage entry for that. (for instance store both block number and a flag // indicating the type of next transaction to send). - let transaction_type = block_number % 3u32.into(); + let transaction_type = block_number % 4u32.into(); if transaction_type == Zero::zero() { TransactionType::Signed } else if transaction_type == T::BlockNumber::from(1u32) { From dd4497d8a459d5e3ecac367b991d5dae1f0940c5 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Mon, 6 Feb 2023 19:12:06 +0100 Subject: [PATCH 368/715] Rename `pallet-random-collective-flip` to Insecure... (#13301) * Rename pallet-random-collective-flip to Insecure... Signed-off-by: Oliver Tale-Yazdi * fmt Signed-off-by: Oliver Tale-Yazdi --------- Signed-off-by: Oliver Tale-Yazdi --- Cargo.lock | 36 +++++++++---------- Cargo.toml | 2 +- bin/node-template/runtime/Cargo.toml | 6 ++-- bin/node-template/runtime/src/lib.rs | 4 +-- bin/node/runtime/Cargo.toml | 6 ++-- bin/node/runtime/src/lib.rs | 4 +-- frame/contracts/Cargo.toml | 2 +- frame/contracts/src/tests.rs | 4 +-- .../Cargo.toml | 4 +-- .../README.md | 14 +++++--- .../src/lib.rs | 15 +++++--- 11 files changed, 53 insertions(+), 44 deletions(-) rename frame/{randomness-collective-flip => insecure-randomness-collective-flip}/Cargo.toml (89%) rename frame/{randomness-collective-flip => insecure-randomness-collective-flip}/README.md (59%) rename frame/{randomness-collective-flip => insecure-randomness-collective-flip}/src/lib.rs (93%) diff --git a/Cargo.lock b/Cargo.lock index a74ad26e7a9a9..c870fb0a930ac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3526,6 +3526,7 @@ dependencies = [ "pallet-identity", "pallet-im-online", "pallet-indices", + "pallet-insecure-randomness-collective-flip", "pallet-lottery", "pallet-membership", "pallet-message-queue", @@ -3540,7 +3541,6 @@ dependencies = [ "pallet-offences-benchmarking", "pallet-preimage", "pallet-proxy", - "pallet-randomness-collective-flip", "pallet-ranked-collective", "pallet-recovery", "pallet-referenda", @@ -4981,7 +4981,7 @@ dependencies = [ "pallet-aura", "pallet-balances", "pallet-grandpa", - "pallet-randomness-collective-flip", + "pallet-insecure-randomness-collective-flip", "pallet-sudo", "pallet-template", "pallet-timestamp", @@ -5591,7 +5591,7 @@ dependencies = [ "pallet-balances", "pallet-contracts-primitives", "pallet-contracts-proc-macro", - "pallet-randomness-collective-flip", + "pallet-insecure-randomness-collective-flip", "pallet-timestamp", "pallet-utility", "parity-scale-codec", @@ -5872,6 +5872,21 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-insecure-randomness-collective-flip" +version = "4.0.0-dev" +dependencies = [ + "frame-support", + "frame-system", + "parity-scale-codec", + "safe-mix", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-lottery" version = "4.0.0-dev" @@ -6197,21 +6212,6 @@ dependencies = [ "sp-std", ] -[[package]] -name = "pallet-randomness-collective-flip" -version = "4.0.0-dev" -dependencies = [ - "frame-support", - "frame-system", - "parity-scale-codec", - "safe-mix", - "scale-info", - "sp-core", - "sp-io", - "sp-runtime", - "sp-std", -] - [[package]] name = "pallet-ranked-collective" version = "4.0.0-dev" diff --git a/Cargo.toml b/Cargo.toml index f87172b5ebabd..aaa1c2a211183 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -128,7 +128,7 @@ members = [ "frame/nomination-pools/benchmarking", "frame/nomination-pools/test-staking", "frame/nomination-pools/runtime-api", - "frame/randomness-collective-flip", + "frame/insecure-randomness-collective-flip", "frame/ranked-collective", "frame/recovery", "frame/referenda", diff --git a/bin/node-template/runtime/Cargo.toml b/bin/node-template/runtime/Cargo.toml index 5560eb6721377..dd453d9f1ec79 100644 --- a/bin/node-template/runtime/Cargo.toml +++ b/bin/node-template/runtime/Cargo.toml @@ -20,7 +20,7 @@ pallet-aura = { version = "4.0.0-dev", default-features = false, path = "../../. pallet-balances = { version = "4.0.0-dev", default-features = false, path = "../../../frame/balances" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../../frame/support" } pallet-grandpa = { version = "4.0.0-dev", default-features = false, path = "../../../frame/grandpa" } -pallet-randomness-collective-flip = { version = "4.0.0-dev", default-features = false, path = "../../../frame/randomness-collective-flip" } +pallet-insecure-randomness-collective-flip = { version = "4.0.0-dev", default-features = false, path = "../../../frame/insecure-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 } @@ -69,7 +69,7 @@ std = [ "pallet-aura/std", "pallet-balances/std", "pallet-grandpa/std", - "pallet-randomness-collective-flip/std", + "pallet-insecure-randomness-collective-flip/std", "pallet-sudo/std", "pallet-template/std", "pallet-timestamp/std", @@ -107,7 +107,7 @@ try-runtime = [ "pallet-aura/try-runtime", "pallet-balances/try-runtime", "pallet-grandpa/try-runtime", - "pallet-randomness-collective-flip/try-runtime", + "pallet-insecure-randomness-collective-flip/try-runtime", "pallet-sudo/try-runtime", "pallet-template/try-runtime", "pallet-timestamp/try-runtime", diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs index 4840459816632..ff9ac66d6afec 100644 --- a/bin/node-template/runtime/src/lib.rs +++ b/bin/node-template/runtime/src/lib.rs @@ -205,7 +205,7 @@ impl frame_system::Config for Runtime { type MaxConsumers = frame_support::traits::ConstU32<16>; } -impl pallet_randomness_collective_flip::Config for Runtime {} +impl pallet_insecure_randomness_collective_flip::Config for Runtime {} impl pallet_aura::Config for Runtime { type AuthorityId = AuraId; @@ -290,7 +290,7 @@ construct_runtime!( UncheckedExtrinsic = UncheckedExtrinsic, { System: frame_system, - RandomnessCollectiveFlip: pallet_randomness_collective_flip, + RandomnessCollectiveFlip: pallet_insecure_randomness_collective_flip, Timestamp: pallet_timestamp, Aura: pallet_aura, Grandpa: pallet_grandpa, diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index 1ff8eb0abd948..1d2e6f057d517 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -87,7 +87,7 @@ pallet-offences = { version = "4.0.0-dev", default-features = false, path = "../ 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-insecure-randomness-collective-flip = { version = "4.0.0-dev", default-features = false, path = "../../../frame/insecure-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" } @@ -167,7 +167,7 @@ std = [ "pallet-preimage/std", "pallet-proxy/std", "sp-core/std", - "pallet-randomness-collective-flip/std", + "pallet-insecure-randomness-collective-flip/std", "sp-std/std", "pallet-session/std", "pallet-session-benchmarking?/std", @@ -300,7 +300,7 @@ try-runtime = [ "pallet-offences/try-runtime", "pallet-preimage/try-runtime", "pallet-proxy/try-runtime", - "pallet-randomness-collective-flip/try-runtime", + "pallet-insecure-randomness-collective-flip/try-runtime", "pallet-ranked-collective/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 8e8ecc125dba4..3f4c464241f8d 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -233,7 +233,7 @@ impl frame_system::Config for Runtime { type MaxConsumers = ConstU32<16>; } -impl pallet_randomness_collective_flip::Config for Runtime {} +impl pallet_insecure_randomness_collective_flip::Config for Runtime {} impl pallet_utility::Config for Runtime { type RuntimeEvent = RuntimeEvent; @@ -1732,7 +1732,7 @@ construct_runtime!( AuthorityDiscovery: pallet_authority_discovery, Offences: pallet_offences, Historical: pallet_session_historical::{Pallet}, - RandomnessCollectiveFlip: pallet_randomness_collective_flip, + RandomnessCollectiveFlip: pallet_insecure_randomness_collective_flip, Identity: pallet_identity, Society: pallet_society, Recovery: pallet_recovery, diff --git a/frame/contracts/Cargo.toml b/frame/contracts/Cargo.toml index 0ee9e36f1dc78..cd41ae2e39b55 100644 --- a/frame/contracts/Cargo.toml +++ b/frame/contracts/Cargo.toml @@ -56,7 +56,7 @@ wat = "1" # Substrate Dependencies 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-insecure-randomness-collective-flip = { version = "4.0.0-dev", path = "../insecure-randomness-collective-flip" } pallet-utility = { version = "4.0.0-dev", path = "../utility" } sp-keystore = { version = "0.13.0", path = "../../primitives/keystore" } diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index ce84da743d112..973fdefe141bf 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -67,7 +67,7 @@ frame_support::construct_runtime!( System: frame_system::{Pallet, Call, Config, Storage, Event}, Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent}, - Randomness: pallet_randomness_collective_flip::{Pallet, Storage}, + Randomness: pallet_insecure_randomness_collective_flip::{Pallet, Storage}, Utility: pallet_utility::{Pallet, Call, Storage, Event}, Contracts: pallet_contracts::{Pallet, Call, Storage, Event}, } @@ -311,7 +311,7 @@ impl frame_system::Config for Test { type OnSetCode = (); type MaxConsumers = frame_support::traits::ConstU32<16>; } -impl pallet_randomness_collective_flip::Config for Test {} +impl pallet_insecure_randomness_collective_flip::Config for Test {} impl pallet_balances::Config for Test { type MaxLocks = (); type MaxReserves = (); diff --git a/frame/randomness-collective-flip/Cargo.toml b/frame/insecure-randomness-collective-flip/Cargo.toml similarity index 89% rename from frame/randomness-collective-flip/Cargo.toml rename to frame/insecure-randomness-collective-flip/Cargo.toml index 435c38d632b69..68ccfadfc8edf 100644 --- a/frame/randomness-collective-flip/Cargo.toml +++ b/frame/insecure-randomness-collective-flip/Cargo.toml @@ -1,12 +1,12 @@ [package] -name = "pallet-randomness-collective-flip" +name = "pallet-insecure-randomness-collective-flip" 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 randomness collective flip pallet" +description = "Insecure do not use in production: FRAME randomness collective flip pallet" readme = "README.md" [package.metadata.docs.rs] diff --git a/frame/randomness-collective-flip/README.md b/frame/insecure-randomness-collective-flip/README.md similarity index 59% rename from frame/randomness-collective-flip/README.md rename to frame/insecure-randomness-collective-flip/README.md index 0730d4abf7cf2..ef02e4b5c8445 100644 --- a/frame/randomness-collective-flip/README.md +++ b/frame/insecure-randomness-collective-flip/README.md @@ -1,6 +1,10 @@ +# DO NOT USE IN PRODUCTION + +The produced values do not fulfill the cryptographic requirements for random numbers. Should not be used for high-stake production use-cases. + # Randomness Module -The Randomness Collective Flip module provides a [`random`](https://docs.rs/pallet-randomness-collective-flip/latest/pallet_randomness_collective_flip/struct.Module.html#method.random) +The Randomness Collective Flip module provides a [`random`](https://docs.rs/pallet-insecure-randomness-collective-flip/latest/pallet_insecure_randomness_collective_flip/struct.Module.html#method.random) function that generates low-influence random values based on the block hashes from the previous `81` blocks. Low-influence randomness can be useful when defending against relatively weak adversaries. Using this pallet as a randomness source is advisable primarily in low-security @@ -8,7 +12,7 @@ situations like testing. ## Public Functions -See the [`Module`](https://docs.rs/pallet-randomness-collective-flip/latest/pallet_randomness_collective_flip/struct.Module.html) struct for details of publicly available functions. +See the [`Module`](https://docs.rs/pallet-insecure-randomness-collective-flip/latest/pallet_insecure_randomness_collective_flip/struct.Module.html) struct for details of publicly available functions. ## Usage @@ -32,17 +36,17 @@ pub mod pallet { pub struct Pallet(_); #[pallet::config] - pub trait Config: frame_system::Config + pallet_randomness_collective_flip::Config {} + pub trait Config: frame_system::Config + pallet_insecure_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"[..]); + let _random_value = >::random(&b"my context"[..]); Ok(()) } } } ``` -License: Apache-2.0 \ No newline at end of file +License: Apache-2.0 diff --git a/frame/randomness-collective-flip/src/lib.rs b/frame/insecure-randomness-collective-flip/src/lib.rs similarity index 93% rename from frame/randomness-collective-flip/src/lib.rs rename to frame/insecure-randomness-collective-flip/src/lib.rs index d92b053655dc9..1d7ddc371173c 100644 --- a/frame/randomness-collective-flip/src/lib.rs +++ b/frame/insecure-randomness-collective-flip/src/lib.rs @@ -15,6 +15,11 @@ // See the License for the specific language governing permissions and // limitations under the License. +//! # DO NOT USE IN PRODUCTION +//! +//! The produced values do not fulfill the cryptographic requirements for random numbers. +//! Should not be used for high-stake production use-cases. +//! //! # Randomness Pallet //! //! The Randomness Collective Flip pallet provides a [`random`](./struct.Module.html#method.random) @@ -50,13 +55,13 @@ //! pub struct Pallet(_); //! //! #[pallet::config] -//! pub trait Config: frame_system::Config + pallet_randomness_collective_flip::Config {} +//! pub trait Config: frame_system::Config + pallet_insecure_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"[..]); +//! let _random_value = >::random(&b"my context"[..]); //! Ok(()) //! } //! } @@ -157,7 +162,7 @@ impl Randomness for Pallet { #[cfg(test)] mod tests { use super::*; - use crate as pallet_randomness_collective_flip; + use crate as pallet_insecure_randomness_collective_flip; use sp_core::H256; use sp_runtime::{ @@ -181,7 +186,7 @@ mod tests { UncheckedExtrinsic = UncheckedExtrinsic, { System: frame_system::{Pallet, Call, Config, Storage, Event}, - CollectiveFlip: pallet_randomness_collective_flip::{Pallet, Storage}, + CollectiveFlip: pallet_insecure_randomness_collective_flip::{Pallet, Storage}, } ); @@ -217,7 +222,7 @@ mod tests { type MaxConsumers = ConstU32<16>; } - impl pallet_randomness_collective_flip::Config for Test {} + impl pallet_insecure_randomness_collective_flip::Config for Test {} fn new_test_ext() -> sp_io::TestExternalities { let t = frame_system::GenesisConfig::default().build_storage::().unwrap(); From 41ae90843b070786ab53071479c141a7c6649ac9 Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Tue, 7 Feb 2023 10:28:18 +0100 Subject: [PATCH 369/715] `zombienet`: warp-sync tests for validators (#13078) * zombienet validators warp sync draft Sketch of warp-sync test for validators. Not tested. Follow-up of: #12769 * yet another warp-sync scenario added - all validators are synced from DB, - some full nodes are synced from DB, - full-node is warp-synced * fixes * fixes * missing files * path fixed --------- Co-authored-by: parity-processbot <> --- scripts/ci/gitlab/pipeline/zombienet.yml | 18 ++ zombienet/0002-validators-warp-sync/README.md | 4 + .../0002-validators-warp-sync/chain-spec.json | 192 ++++++++++++++++++ .../test-validators-warp-sync.toml | 35 ++++ .../test-validators-warp-sync.zndsl | 43 ++++ .../0003-block-building-warp-sync/README.md | 4 + .../chain-spec.json | 192 ++++++++++++++++++ .../test-block-building-warp-sync.toml | 30 +++ .../test-block-building-warp-sync.zndsl | 35 ++++ 9 files changed, 553 insertions(+) create mode 100644 zombienet/0002-validators-warp-sync/README.md create mode 100644 zombienet/0002-validators-warp-sync/chain-spec.json create mode 100644 zombienet/0002-validators-warp-sync/test-validators-warp-sync.toml create mode 100644 zombienet/0002-validators-warp-sync/test-validators-warp-sync.zndsl create mode 100644 zombienet/0003-block-building-warp-sync/README.md create mode 100644 zombienet/0003-block-building-warp-sync/chain-spec.json create mode 100644 zombienet/0003-block-building-warp-sync/test-block-building-warp-sync.toml create mode 100644 zombienet/0003-block-building-warp-sync/test-block-building-warp-sync.zndsl diff --git a/scripts/ci/gitlab/pipeline/zombienet.yml b/scripts/ci/gitlab/pipeline/zombienet.yml index 7dc98c006808f..3429621e4fe22 100644 --- a/scripts/ci/gitlab/pipeline/zombienet.yml +++ b/scripts/ci/gitlab/pipeline/zombienet.yml @@ -50,3 +50,21 @@ zombienet-0001-basic-warp-sync: - /home/nonroot/zombie-net/scripts/ci/run-test-env-manager.sh --github-remote-dir="${GH_DIR}/0001-basic-warp-sync" --test="test-warp-sync.zndsl" + + +zombienet-0002-validators-warp-sync: + extends: + - .zombienet-common + script: + - /home/nonroot/zombie-net/scripts/ci/run-test-env-manager.sh + --github-remote-dir="${GH_DIR}/0002-validators-warp-sync" + --test="test-validators-warp-sync.zndsl" + + +zombienet-0003-block-building-warp-sync: + extends: + - .zombienet-common + script: + - /home/nonroot/zombie-net/scripts/ci/run-test-env-manager.sh + --github-remote-dir="${GH_DIR}/0003-block-building-warp-sync" + --test="test-block-building-warp-sync.zndsl" diff --git a/zombienet/0002-validators-warp-sync/README.md b/zombienet/0002-validators-warp-sync/README.md new file mode 100644 index 0000000000000..662360fbf3c68 --- /dev/null +++ b/zombienet/0002-validators-warp-sync/README.md @@ -0,0 +1,4 @@ +Refer to ../0001-basic-warp-sync/README.md for more details. This test is nearly a clone. We want to warp-sync validators and make sure they can build blocks. +0001-basic-warp-sync chainspec (copied) and database are reused in this test. + + diff --git a/zombienet/0002-validators-warp-sync/chain-spec.json b/zombienet/0002-validators-warp-sync/chain-spec.json new file mode 100644 index 0000000000000..8c09e7c7b0321 --- /dev/null +++ b/zombienet/0002-validators-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/0002-validators-warp-sync/test-validators-warp-sync.toml b/zombienet/0002-validators-warp-sync/test-validators-warp-sync.toml new file mode 100644 index 0000000000000..dae6e406f04da --- /dev/null +++ b/zombienet/0002-validators-warp-sync/test-validators-warp-sync.toml @@ -0,0 +1,35 @@ +[settings] +enable_tracing = false + +[relaychain] +default_image = "{{ZOMBIENET_INTEGRATION_TEST_IMAGE}}" +default_command = "substrate" + +chain = "gen-db" +chain_spec_path = "zombienet/0002-validators-warp-sync/chain-spec.json" + + [[relaychain.nodes]] + name = "alice" + validator = true + args = ["--sync warp"] + + [[relaychain.nodes]] + name = "bob" + validator = true + args = ["--sync warp"] + + #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 + db_snapshot="https://storage.googleapis.com/zombienet-db-snaps/substrate/0001-basic-warp-sync/chains-0bb3f0be2ce41b5615b224215bcc8363aa0416a6.tgz" + + [[relaychain.nodes]] + name = "eve" + validator = false + db_snapshot="https://storage.googleapis.com/zombienet-db-snaps/substrate/0001-basic-warp-sync/chains-0bb3f0be2ce41b5615b224215bcc8363aa0416a6.tgz" diff --git a/zombienet/0002-validators-warp-sync/test-validators-warp-sync.zndsl b/zombienet/0002-validators-warp-sync/test-validators-warp-sync.zndsl new file mode 100644 index 0000000000000..2110d6373fa2c --- /dev/null +++ b/zombienet/0002-validators-warp-sync/test-validators-warp-sync.zndsl @@ -0,0 +1,43 @@ +Description: Warp sync +Network: ./test-validators-warp-sync.toml +Creds: config + +alice: is up within 30 seconds +bob: is up within 30 seconds +charlie: is up within 30 seconds +dave: is up within 30 seconds +eve: is up within 30 seconds + +alice: reports node_roles is 4 +bob: reports node_roles is 4 +charlie: reports node_roles is 1 +dave: reports node_roles is 1 +eve: reports node_roles is 1 + +alice: reports peers count is at least 4 within 60 seconds +bob: reports peers count is at least 4 within 60 seconds +charlie: reports peers count is at least 4 within 60 seconds +dave: reports peers count is at least 4 within 60 seconds +eve: reports peers count is at least 4 within 60 seconds + +# db snapshot has 12133 blocks +charlie: reports block height is at least 12133 within 60 seconds +dave: reports block height is at least 12133 within 60 seconds +eve: reports block height is at least 12133 within 60 seconds + +alice: log line matches "Warp sync is complete" within 60 seconds +bob: log line matches "Warp sync is complete" within 60 seconds + +# workaround for: https://github.com/paritytech/zombienet/issues/580 +alice: count of log lines containing "Block history download is complete" is 1 within 60 seconds +bob: count of log lines containing "Block history download is complete" is 1 within 60 seconds + +alice: reports block height is at least 12133 within 10 seconds +bob: reports block height is at least 12133 within 10 seconds + +alice: count of log lines containing "error" is 0 within 10 seconds +bob: count of log lines containing "verification failed" is 0 within 10 seconds + +# new block were built +alice: reports block height is at least 12136 within 90 seconds +bob: reports block height is at least 12136 within 90 seconds diff --git a/zombienet/0003-block-building-warp-sync/README.md b/zombienet/0003-block-building-warp-sync/README.md new file mode 100644 index 0000000000000..311d3550f7663 --- /dev/null +++ b/zombienet/0003-block-building-warp-sync/README.md @@ -0,0 +1,4 @@ +Refer to ../0001-basic-warp-sync/README.md for more details. This test is nearly a clone. We want to warp-sync full nodes in the presence of validators. +0001-basic-warp-sync chainspec (copied) and database are reused in this test. + + diff --git a/zombienet/0003-block-building-warp-sync/chain-spec.json b/zombienet/0003-block-building-warp-sync/chain-spec.json new file mode 100644 index 0000000000000..8c09e7c7b0321 --- /dev/null +++ b/zombienet/0003-block-building-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/0003-block-building-warp-sync/test-block-building-warp-sync.toml b/zombienet/0003-block-building-warp-sync/test-block-building-warp-sync.toml new file mode 100644 index 0000000000000..66176845cc78d --- /dev/null +++ b/zombienet/0003-block-building-warp-sync/test-block-building-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/0003-block-building-warp-sync/chain-spec.json" + + #we need at least 3 nodes for warp sync + [[relaychain.nodes]] + name = "alice" + validator = true + db_snapshot="https://storage.googleapis.com/zombienet-db-snaps/substrate/0001-basic-warp-sync/chains-0bb3f0be2ce41b5615b224215bcc8363aa0416a6.tgz" + + [[relaychain.nodes]] + name = "bob" + validator = true + db_snapshot="https://storage.googleapis.com/zombienet-db-snaps/substrate/0001-basic-warp-sync/chains-0bb3f0be2ce41b5615b224215bcc8363aa0416a6.tgz" + + [[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/0003-block-building-warp-sync/test-block-building-warp-sync.zndsl b/zombienet/0003-block-building-warp-sync/test-block-building-warp-sync.zndsl new file mode 100644 index 0000000000000..2041366a6d086 --- /dev/null +++ b/zombienet/0003-block-building-warp-sync/test-block-building-warp-sync.zndsl @@ -0,0 +1,35 @@ +Description: Warp sync +Network: ./test-block-building-warp-sync.toml +Creds: config + +alice: is up +bob: is up +charlie: is up +dave: is up + +alice: reports node_roles is 4 +bob: reports node_roles is 4 +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 3d60070c1373bc0383aa4f003a5b243c4c4f7118 Mon Sep 17 00:00:00 2001 From: Koute Date: Wed, 8 Feb 2023 00:29:14 +0900 Subject: [PATCH 370/715] Disable default features for `strum` (#13326) --- primitives/beefy/Cargo.toml | 2 +- primitives/keyring/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/primitives/beefy/Cargo.toml b/primitives/beefy/Cargo.toml index e4154071d26eb..5dfda3e378fab 100644 --- a/primitives/beefy/Cargo.toml +++ b/primitives/beefy/Cargo.toml @@ -22,7 +22,7 @@ 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 = "7.0.0", default-features = false, path = "../runtime" } sp-std = { version = "5.0.0", default-features = false, path = "../std" } -strum = { version = "0.24.1", features = ["derive"] } +strum = { version = "0.24.1", features = ["derive"], default-features = false } lazy_static = "1.4.0" [dev-dependencies] diff --git a/primitives/keyring/Cargo.toml b/primitives/keyring/Cargo.toml index 0646dde4f077a..db3a8de2b2433 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.24.1", features = ["derive"] } +strum = { version = "0.24.1", features = ["derive"], default-features = false } sp-core = { version = "7.0.0", path = "../core" } sp-runtime = { version = "7.0.0", path = "../runtime" } From 38c3e5ee10be760115a77a115ef0ac6ba381542b Mon Sep 17 00:00:00 2001 From: Arkadiy Paronyan Date: Tue, 7 Feb 2023 19:15:01 +0100 Subject: [PATCH 371/715] Fix block pruning (#13323) --- client/db/src/lib.rs | 84 +++++++++++++++++++++++++++++++++----------- 1 file changed, 64 insertions(+), 20 deletions(-) diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index f217eb6480abc..f54f1bdb131c7 100644 --- a/client/db/src/lib.rs +++ b/client/db/src/lib.rs @@ -1806,7 +1806,13 @@ impl Backend { } let new_displaced = self.blockchain.leaves.write().finalize_height(f_num); - self.prune_blocks(transaction, f_num, &new_displaced, current_transaction_justifications)?; + self.prune_blocks( + transaction, + f_num, + f_hash, + &new_displaced, + current_transaction_justifications, + )?; Ok(()) } @@ -1815,6 +1821,7 @@ impl Backend { &self, transaction: &mut Transaction, finalized_number: NumberFor, + finalized_hash: Block::Hash, displaced: &FinalizationOutcome>, current_transaction_justifications: &mut HashMap, ) -> ClientResult<()> { @@ -1843,10 +1850,10 @@ impl Backend { self.prune_block(transaction, BlockId::::number(number))?; } - self.prune_displaced_branches(transaction, finalized_number, displaced)?; + self.prune_displaced_branches(transaction, finalized_hash, displaced)?; }, BlocksPruning::KeepFinalized => { - self.prune_displaced_branches(transaction, finalized_number, displaced)?; + self.prune_displaced_branches(transaction, finalized_hash, displaced)?; }, } Ok(()) @@ -1855,28 +1862,21 @@ impl Backend { fn prune_displaced_branches( &self, transaction: &mut Transaction, - finalized: NumberFor, + finalized: Block::Hash, 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) { - match self.blockchain.header(hash)? { - Some(header) => { - self.blockchain.insert_persisted_body_if_pinned(hash)?; - - self.prune_block(transaction, BlockId::::hash(hash))?; - number = header.number().saturating_sub(One::one()); - hash = *header.parent_hash(); + match sp_blockchain::tree_route(&self.blockchain, *h, finalized) { + Ok(tree_route) => + for r in tree_route.retracted() { + self.blockchain.insert_persisted_body_if_pinned(r.hash)?; + self.prune_block(transaction, BlockId::::hash(r.hash))?; }, - None => break, - } + Err(sp_blockchain::Error::UnknownBlock(_)) => { + // Sometimes routes can't be calculated. E.g. after warp sync. + }, + Err(e) => Err(e)?, } } Ok(()) @@ -3569,6 +3569,50 @@ pub(crate) mod tests { assert_eq!(Some(vec![4.into()]), bc.body(blocks[4]).unwrap()); } + #[test] + fn prune_blocks_on_finalize_and_reorg() { + // 0 - 1b + // \ - 1a - 2a - 3a + // \ - 2b + + let backend = Backend::::new_test_with_tx_storage(BlocksPruning::Some(10), 10); + + let make_block = |index, parent, val: u64| { + insert_block(&backend, index, parent, None, H256::random(), vec![val.into()], None) + .unwrap() + }; + + let block_0 = make_block(0, Default::default(), 0x00); + let block_1a = make_block(1, block_0, 0x1a); + let block_1b = make_block(1, block_0, 0x1b); + let block_2a = make_block(2, block_1a, 0x2a); + let block_2b = make_block(2, block_1a, 0x2b); + let block_3a = make_block(3, block_2a, 0x3a); + + // Make sure 1b is head + let mut op = backend.begin_operation().unwrap(); + backend.begin_state_operation(&mut op, block_0).unwrap(); + op.mark_head(block_1b).unwrap(); + backend.commit_operation(op).unwrap(); + + // Finalize 3a + let mut op = backend.begin_operation().unwrap(); + backend.begin_state_operation(&mut op, block_0).unwrap(); + op.mark_head(block_3a).unwrap(); + op.mark_finalized(block_1a, None).unwrap(); + op.mark_finalized(block_2a, None).unwrap(); + op.mark_finalized(block_3a, None).unwrap(); + backend.commit_operation(op).unwrap(); + + let bc = backend.blockchain(); + assert_eq!(None, bc.body(block_1b).unwrap()); + assert_eq!(None, bc.body(block_2b).unwrap()); + assert_eq!(Some(vec![0x00.into()]), bc.body(block_0).unwrap()); + assert_eq!(Some(vec![0x1a.into()]), bc.body(block_1a).unwrap()); + assert_eq!(Some(vec![0x2a.into()]), bc.body(block_2a).unwrap()); + assert_eq!(Some(vec![0x3a.into()]), bc.body(block_3a).unwrap()); + } + #[test] fn indexed_data_block_body() { let backend = Backend::::new_test_with_tx_storage(BlocksPruning::Some(1), 10); From 2f1644860b318e23aa893bdd2955bb6bd6ec8d04 Mon Sep 17 00:00:00 2001 From: Muharem Ismailov Date: Wed, 8 Feb 2023 09:33:34 +0100 Subject: [PATCH 372/715] Referendum proposal's metadata (#12568) * referenda metadata * todo comment * remove TODO, update rustdocs * referenda clear_metadata origin signed or root * referenda metadata unit tests * drop schema type for referenda metadata * remove metadata type * referenda metadata benches * note different preimages * metadata for democracy pallet * metadata democracy pallet tests and benches * fix cargo clippy * update docs * ".git/.scripts/bench-bot.sh" pallet dev pallet_democracy * ".git/.scripts/bench-bot.sh" pallet dev pallet_referenda * Update the doc frame/democracy/src/lib.rs Co-authored-by: Roman Useinov * Update the doc frame/democracy/src/lib.rs Co-authored-by: Anthony Alaribe * reference instead clone for take Co-authored-by: Anthony Alaribe * error rename BadMetadata to PreimageNotExist * clear metadata within internal_cancel_referendum fn * remove redundant clone * collapse metadata api into one set_metadata method * fmt * review fixes * not request preimage on set_metadata * rename events and update docs * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_democracy * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_referenda * rename reset_metadata to transfer_metadata --------- Co-authored-by: command-bot <> Co-authored-by: Roman Useinov Co-authored-by: Anthony Alaribe --- frame/democracy/src/benchmarking.rs | 203 +++++- frame/democracy/src/lib.rs | 176 +++++- frame/democracy/src/tests.rs | 15 +- frame/democracy/src/tests/fast_tracking.rs | 11 + frame/democracy/src/tests/metadata.rs | 209 +++++++ frame/democracy/src/tests/public_proposals.rs | 14 +- frame/democracy/src/types.rs | 17 + frame/democracy/src/weights.rs | 581 ++++++++++++------ frame/referenda/src/benchmarking.rs | 26 +- frame/referenda/src/lib.rs | 72 ++- frame/referenda/src/mock.rs | 14 +- frame/referenda/src/tests.rs | 72 +++ frame/referenda/src/weights.rs | 307 +++++---- 13 files changed, 1367 insertions(+), 350 deletions(-) create mode 100644 frame/democracy/src/tests/metadata.rs diff --git a/frame/democracy/src/benchmarking.rs b/frame/democracy/src/benchmarking.rs index f2d45b719f678..f376b733aba6b 100644 --- a/frame/democracy/src/benchmarking.rs +++ b/frame/democracy/src/benchmarking.rs @@ -54,19 +54,20 @@ fn add_proposal(n: u32) -> Result { Ok(proposal.hash()) } -fn add_referendum(n: u32) -> (ReferendumIndex, H256) { +// add a referendum with a metadata. +fn add_referendum(n: u32) -> (ReferendumIndex, H256, PreimageHash) { let vote_threshold = VoteThreshold::SimpleMajority; let proposal = make_proposal::(n); let hash = proposal.hash(); - ( - Democracy::::inject_referendum( - T::LaunchPeriod::get(), - proposal, - vote_threshold, - 0u32.into(), - ), - hash, - ) + let index = Democracy::::inject_referendum( + T::LaunchPeriod::get(), + proposal, + vote_threshold, + 0u32.into(), + ); + let preimage_hash = note_preimage::(); + MetadataOf::::insert(crate::MetadataOwner::Referendum(index), preimage_hash.clone()); + (index, hash, preimage_hash) } fn account_vote(b: BalanceOf) -> AccountVote> { @@ -75,6 +76,25 @@ fn account_vote(b: BalanceOf) -> AccountVote> { AccountVote::Standard { vote: v, balance: b } } +fn assert_last_event(generic_event: ::RuntimeEvent) { + frame_system::Pallet::::assert_last_event(generic_event.into()); +} + +fn assert_has_event(generic_event: ::RuntimeEvent) { + frame_system::Pallet::::assert_has_event(generic_event.into()); +} + +// note a new preimage. +fn note_preimage() -> PreimageHash { + use core::sync::atomic::{AtomicU8, Ordering}; + use sp_std::borrow::Cow; + // note a new preimage on every function invoke. + static COUNTER: AtomicU8 = AtomicU8::new(0); + let data = Cow::from(vec![COUNTER.fetch_add(1, Ordering::Relaxed)]); + let hash = ::Preimages::note(data).unwrap(); + hash +} + benchmarks! { propose { let p = T::MaxProposals::get(); @@ -179,7 +199,7 @@ benchmarks! { emergency_cancel { let origin = T::CancellationOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; - let ref_index = add_referendum::(0).0; + let (ref_index, _, preimage_hash) = add_referendum::(0); assert_ok!(Democracy::::referendum_status(ref_index)); }: _(origin, ref_index) verify { @@ -188,6 +208,10 @@ benchmarks! { Democracy::::referendum_status(ref_index), Error::::ReferendumInvalid, ); + assert_last_event::(crate::Event::MetadataCleared { + owner: MetadataOwner::Referendum(ref_index), + hash: preimage_hash, + }.into()); } blacklist { @@ -198,7 +222,7 @@ benchmarks! { // 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); + let (ref_index, hash, preimage_hash) = add_referendum::(0); assert_ok!(Democracy::::referendum_status(ref_index)); // Place our proposal in the external queue, too. assert_ok!(Democracy::::external_propose( @@ -215,6 +239,10 @@ benchmarks! { Democracy::::referendum_status(ref_index), Error::::ReferendumInvalid ); + assert_has_event::(crate::Event::MetadataCleared { + owner: MetadataOwner::Referendum(ref_index), + hash: preimage_hash, + }.into()); } // Worst case scenario, we external propose a previously blacklisted proposal @@ -262,8 +290,13 @@ benchmarks! { .expect("ExternalDefaultOrigin has no successful origin required for the benchmark"); let proposal = make_proposal::(0); let proposal_hash = proposal.hash(); - Democracy::::external_propose_default(origin_propose, proposal)?; - + Democracy::::external_propose_default(origin_propose.clone(), proposal)?; + // Set metadata to the external proposal. + let preimage_hash = note_preimage::(); + assert_ok!(Democracy::::set_metadata( + origin_propose, + MetadataOwner::External, + Some(preimage_hash))); // NOTE: Instant origin may invoke a little bit more logic, but may not always succeed. let origin_fast_track = T::FastTrackOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; @@ -271,7 +304,12 @@ benchmarks! { let delay = 0u32; }: _(origin_fast_track, proposal_hash, voting_period, delay.into()) verify { - assert_eq!(Democracy::::referendum_count(), 1, "referendum not created") + assert_eq!(Democracy::::referendum_count(), 1, "referendum not created"); + assert_last_event::(crate::Event::MetadataTransferred { + prev_owner: MetadataOwner::External, + owner: MetadataOwner::Referendum(0), + hash: preimage_hash, + }.into()); } veto_external { @@ -280,7 +318,14 @@ benchmarks! { let origin_propose = T::ExternalDefaultOrigin::try_successful_origin() .expect("ExternalDefaultOrigin has no successful origin required for the benchmark"); - Democracy::::external_propose_default(origin_propose, proposal)?; + Democracy::::external_propose_default(origin_propose.clone(), proposal)?; + + let preimage_hash = note_preimage::(); + assert_ok!(Democracy::::set_metadata( + origin_propose, + MetadataOwner::External, + Some(preimage_hash)) + ); let mut vetoers: BoundedVec = Default::default(); for i in 0 .. (T::MaxBlacklisted::get() - 1) { @@ -303,13 +348,32 @@ benchmarks! { for i in 0 .. T::MaxProposals::get() { add_proposal::(i)?; } + // Add metadata to the first proposal. + let proposer = funded_account::("proposer", 0); + let preimage_hash = note_preimage::(); + assert_ok!(Democracy::::set_metadata( + RawOrigin::Signed(proposer).into(), + MetadataOwner::Proposal(0), + Some(preimage_hash))); let cancel_origin = T::CancelProposalOrigin::try_successful_origin() .map_err(|_| BenchmarkError::Weightless)?; }: _(cancel_origin, 0) + verify { + assert_last_event::(crate::Event::MetadataCleared { + owner: MetadataOwner::Proposal(0), + hash: preimage_hash, + }.into()); + } cancel_referendum { - let ref_index = add_referendum::(0).0; + let (ref_index, _, preimage_hash) = add_referendum::(0); }: _(RawOrigin::Root, ref_index) + verify { + assert_last_event::(crate::Event::MetadataCleared { + owner: MetadataOwner::Referendum(0), + hash: preimage_hash, + }.into()); + } #[extra] on_initialize_external { @@ -678,6 +742,111 @@ benchmarks! { assert_eq!(votes.len(), (r - 1) as usize, "Vote was not removed"); } + set_external_metadata { + let origin = T::ExternalOrigin::try_successful_origin() + .expect("ExternalOrigin has no successful origin required for the benchmark"); + assert_ok!( + Democracy::::external_propose(origin.clone(), make_proposal::(0)) + ); + let owner = MetadataOwner::External; + let hash = note_preimage::(); + }: set_metadata(origin, owner.clone(), Some(hash)) + verify { + assert_last_event::(crate::Event::MetadataSet { + owner, + hash, + }.into()); + } + + clear_external_metadata { + let origin = T::ExternalOrigin::try_successful_origin() + .expect("ExternalOrigin has no successful origin required for the benchmark"); + assert_ok!( + Democracy::::external_propose(origin.clone(), make_proposal::(0)) + ); + let owner = MetadataOwner::External; + let proposer = funded_account::("proposer", 0); + let hash = note_preimage::(); + assert_ok!(Democracy::::set_metadata(origin.clone(), owner.clone(), Some(hash))); + }: set_metadata(origin, owner.clone(), None) + verify { + assert_last_event::(crate::Event::MetadataCleared { + owner, + hash, + }.into()); + } + + set_proposal_metadata { + // Place our proposal at the end to make sure it's worst case. + for i in 0 .. T::MaxProposals::get() { + add_proposal::(i)?; + } + let owner = MetadataOwner::Proposal(0); + let proposer = funded_account::("proposer", 0); + let hash = note_preimage::(); + }: set_metadata(RawOrigin::Signed(proposer).into(), owner.clone(), Some(hash)) + verify { + assert_last_event::(crate::Event::MetadataSet { + owner, + hash, + }.into()); + } + + clear_proposal_metadata { + // Place our proposal at the end to make sure it's worst case. + for i in 0 .. T::MaxProposals::get() { + add_proposal::(i)?; + } + let proposer = funded_account::("proposer", 0); + let owner = MetadataOwner::Proposal(0); + let hash = note_preimage::(); + assert_ok!(Democracy::::set_metadata( + RawOrigin::Signed(proposer.clone()).into(), + owner.clone(), + Some(hash))); + }: set_metadata(RawOrigin::Signed(proposer).into(), owner.clone(), None) + verify { + assert_last_event::(crate::Event::MetadataCleared { + owner, + hash, + }.into()); + } + + set_referendum_metadata { + // create not ongoing referendum. + ReferendumInfoOf::::insert( + 0, + ReferendumInfo::Finished { end: T::BlockNumber::zero(), approved: true }, + ); + let owner = MetadataOwner::Referendum(0); + let caller = funded_account::("caller", 0); + let hash = note_preimage::(); + }: set_metadata(RawOrigin::Root.into(), owner.clone(), Some(hash)) + verify { + assert_last_event::(crate::Event::MetadataSet { + owner, + hash, + }.into()); + } + + clear_referendum_metadata { + // create not ongoing referendum. + ReferendumInfoOf::::insert( + 0, + ReferendumInfo::Finished { end: T::BlockNumber::zero(), approved: true }, + ); + let owner = MetadataOwner::Referendum(0); + let hash = note_preimage::(); + MetadataOf::::insert(owner.clone(), hash); + let caller = funded_account::("caller", 0); + }: set_metadata(RawOrigin::Signed(caller).into(), owner.clone(), None) + verify { + assert_last_event::(crate::Event::MetadataCleared { + owner, + hash, + }.into()); + } + impl_benchmark_test_suite!( Democracy, crate::tests::new_test_ext(), diff --git a/frame/democracy/src/lib.rs b/frame/democracy/src/lib.rs index 2c65e5d94bc46..3aa8bc0015d38 100644 --- a/frame/democracy/src/lib.rs +++ b/frame/democracy/src/lib.rs @@ -155,14 +155,17 @@ use codec::{Decode, Encode}; use frame_support::{ ensure, + error::BadOrigin, traits::{ defensive_prelude::*, schedule::{v3::Named as ScheduleNamed, DispatchTime}, - Bounded, Currency, Get, LockIdentifier, LockableCurrency, OnUnbalanced, QueryPreimage, - ReservableCurrency, StorePreimage, WithdrawReasons, + Bounded, Currency, EnsureOrigin, Get, Hash as PreimageHash, LockIdentifier, + LockableCurrency, OnUnbalanced, QueryPreimage, ReservableCurrency, StorePreimage, + WithdrawReasons, }, weights::Weight, }; +use frame_system::pallet_prelude::OriginFor; use sp_runtime::{ traits::{Bounded as ArithBounded, One, Saturating, StaticLookup, Zero}, ArithmeticError, DispatchError, DispatchResult, @@ -176,7 +179,10 @@ mod vote_threshold; pub mod weights; pub use conviction::Conviction; pub use pallet::*; -pub use types::{Delegations, ReferendumInfo, ReferendumStatus, Tally, UnvoteScope}; +pub use types::{ + Delegations, MetadataOwner, PropIndex, ReferendumIndex, ReferendumInfo, ReferendumStatus, + Tally, UnvoteScope, +}; pub use vote::{AccountVote, Vote, Voting}; pub use vote_threshold::{Approved, VoteThreshold}; pub use weights::WeightInfo; @@ -191,12 +197,6 @@ pub mod migrations; const DEMOCRACY_ID: LockIdentifier = *b"democrac"; -/// A proposal index. -pub type PropIndex = u32; - -/// A referendum index. -pub type ReferendumIndex = u32; - type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; type NegativeImbalanceOf = <::Currency as Currency< @@ -425,6 +425,15 @@ pub mod pallet { #[pallet::storage] pub type Cancellations = StorageMap<_, Identity, H256, bool, ValueQuery>; + /// General information concerning any proposal or referendum. + /// The `PreimageHash` refers to the preimage of the `Preimages` provider which can be a JSON + /// dump or IPFS hash of a JSON file. + /// + /// Consider a garbage collection for a metadata of finished referendums to `unrequest` (remove) + /// large preimages. + #[pallet::storage] + pub type MetadataOf = StorageMap<_, Blake2_128Concat, MetadataOwner, PreimageHash>; + #[pallet::genesis_config] pub struct GenesisConfig { _phantom: sp_std::marker::PhantomData, @@ -477,6 +486,29 @@ pub mod pallet { Seconded { seconder: T::AccountId, prop_index: PropIndex }, /// A proposal got canceled. ProposalCanceled { prop_index: PropIndex }, + /// Metadata for a proposal or a referendum has been set. + MetadataSet { + /// Metadata owner. + owner: MetadataOwner, + /// Preimage hash. + hash: PreimageHash, + }, + /// Metadata for a proposal or a referendum has been cleared. + MetadataCleared { + /// Metadata owner. + owner: MetadataOwner, + /// Preimage hash. + hash: PreimageHash, + }, + /// Metadata has been transferred to new owner. + MetadataTransferred { + /// Previous metadata owner. + prev_owner: MetadataOwner, + /// New metadata owner. + owner: MetadataOwner, + /// Preimage hash. + hash: PreimageHash, + }, } #[pallet::error] @@ -528,6 +560,8 @@ pub mod pallet { TooMany, /// Voting period too low VotingPeriodLow, + /// The preimage does not exist. + PreimageNotExist, } #[pallet::hooks] @@ -773,12 +807,13 @@ pub mod pallet { >::kill(); let now = >::block_number(); - Self::inject_referendum( + let ref_index = Self::inject_referendum( now.saturating_add(voting_period), ext_proposal, threshold, delay, ); + Self::transfer_metadata(MetadataOwner::External, MetadataOwner::Referendum(ref_index)); Ok(()) } @@ -816,6 +851,7 @@ pub mod pallet { Self::deposit_event(Event::::Vetoed { who, proposal_hash, until }); >::kill(); + Self::clear_metadata(MetadataOwner::External); Ok(()) } @@ -1025,12 +1061,14 @@ pub mod pallet { T::Slash::on_unbalanced(T::Currency::slash_reserved(&who, amount).0); } } + Self::clear_metadata(MetadataOwner::Proposal(prop_index)); } }); // Remove the external queued referendum, if it's there. if matches!(NextExternal::::get(), Some((p, ..)) if p.hash() == proposal_hash) { NextExternal::::kill(); + Self::clear_metadata(MetadataOwner::External); } // Remove the referendum, if it's there. @@ -1067,8 +1105,68 @@ pub mod pallet { T::Slash::on_unbalanced(T::Currency::slash_reserved(&who, amount).0); } } - Self::deposit_event(Event::::ProposalCanceled { prop_index }); + Self::clear_metadata(MetadataOwner::Proposal(prop_index)); + Ok(()) + } + + /// Set or clear a metadata of a proposal or a referendum. + /// + /// Parameters: + /// - `origin`: Must correspond to the `MetadataOwner`. + /// - `ExternalOrigin` for an external proposal with the `SuperMajorityApprove` + /// threshold. + /// - `ExternalDefaultOrigin` for an external proposal with the `SuperMajorityAgainst` + /// threshold. + /// - `ExternalMajorityOrigin` for an external proposal with the `SimpleMajority` + /// threshold. + /// - `Signed` by a creator for a public proposal. + /// - `Signed` to clear a metadata for a finished referendum. + /// - `Root` to set a metadata for an ongoing referendum. + /// - `owner`: an identifier of a metadata owner. + /// - `maybe_hash`: The hash of an on-chain stored preimage. `None` to clear a metadata. + #[pallet::call_index(18)] + #[pallet::weight( + match (owner, maybe_hash) { + (MetadataOwner::External, Some(_)) => T::WeightInfo::set_external_metadata(), + (MetadataOwner::External, None) => T::WeightInfo::clear_external_metadata(), + (MetadataOwner::Proposal(_), Some(_)) => T::WeightInfo::set_proposal_metadata(), + (MetadataOwner::Proposal(_), None) => T::WeightInfo::clear_proposal_metadata(), + (MetadataOwner::Referendum(_), Some(_)) => T::WeightInfo::set_referendum_metadata(), + (MetadataOwner::Referendum(_), None) => T::WeightInfo::clear_referendum_metadata(), + } + )] + pub fn set_metadata( + origin: OriginFor, + owner: MetadataOwner, + maybe_hash: Option, + ) -> DispatchResult { + match owner { + MetadataOwner::External => { + let (_, threshold) = >::get().ok_or(Error::::NoProposal)?; + Self::ensure_external_origin(threshold, origin)?; + }, + MetadataOwner::Proposal(index) => { + let who = ensure_signed(origin)?; + let (_, _, proposer) = Self::proposal(index)?; + ensure!(proposer == who, Error::::NoPermission); + }, + MetadataOwner::Referendum(index) => { + let is_root = ensure_signed_or_root(origin)?.is_none(); + ensure!(is_root || maybe_hash.is_none(), Error::::NoPermission); + ensure!( + is_root || Self::referendum_status(index).is_err(), + Error::::NoPermission + ); + }, + } + if let Some(hash) = maybe_hash { + ensure!(T::Preimages::len(&hash).is_some(), Error::::PreimageNotExist); + MetadataOf::::insert(owner.clone(), hash); + Self::deposit_event(Event::::MetadataSet { owner, hash }); + } else { + Self::clear_metadata(owner); + } Ok(()) } } @@ -1146,6 +1244,7 @@ impl Pallet { pub fn internal_cancel_referendum(ref_index: ReferendumIndex) { Self::deposit_event(Event::::Cancelled { ref_index }); ReferendumInfoOf::::remove(ref_index); + Self::clear_metadata(MetadataOwner::Referendum(ref_index)); } // private. @@ -1432,12 +1531,13 @@ impl Pallet { if let Some((proposal, threshold)) = >::take() { LastTabledWasExternal::::put(true); Self::deposit_event(Event::::ExternalTabled); - Self::inject_referendum( + let ref_index = Self::inject_referendum( now.saturating_add(T::VotingPeriod::get()), proposal, threshold, T::EnactmentPeriod::get(), ); + Self::transfer_metadata(MetadataOwner::External, MetadataOwner::Referendum(ref_index)); Ok(()) } else { return Err(Error::::NoneWaiting.into()) @@ -1460,12 +1560,16 @@ impl Pallet { T::Currency::unreserve(d, deposit); } Self::deposit_event(Event::::Tabled { proposal_index: prop_index, deposit }); - Self::inject_referendum( + let ref_index = Self::inject_referendum( now.saturating_add(T::VotingPeriod::get()), proposal, VoteThreshold::SuperMajorityApprove, T::EnactmentPeriod::get(), ); + Self::transfer_metadata( + MetadataOwner::Proposal(prop_index), + MetadataOwner::Referendum(ref_index), + ) } Ok(()) } else { @@ -1578,6 +1682,52 @@ impl Pallet { // `Compact`. decode_compact_u32_at(&>::hashed_key_for(proposal)) } + + /// Return a proposal of an index. + fn proposal(index: PropIndex) -> Result<(PropIndex, BoundedCallOf, T::AccountId), Error> { + PublicProps::::get() + .into_iter() + .find(|(prop_index, _, _)| prop_index == &index) + .ok_or(Error::::ProposalMissing) + } + + /// Clear metadata if exist for a given owner. + fn clear_metadata(owner: MetadataOwner) { + if let Some(hash) = MetadataOf::::take(&owner) { + Self::deposit_event(Event::::MetadataCleared { owner, hash }); + } + } + + /// Transfer the metadata of an `owner` to a `new_owner`. + fn transfer_metadata(owner: MetadataOwner, new_owner: MetadataOwner) { + if let Some(hash) = MetadataOf::::take(&owner) { + MetadataOf::::insert(&new_owner, hash); + Self::deposit_event(Event::::MetadataTransferred { + prev_owner: owner, + owner: new_owner, + hash, + }); + } + } + + /// Ensure external origin for corresponding vote threshold. + fn ensure_external_origin( + threshold: VoteThreshold, + origin: OriginFor, + ) -> Result<(), BadOrigin> { + match threshold { + VoteThreshold::SuperMajorityApprove => { + let _ = T::ExternalOrigin::ensure_origin(origin)?; + }, + VoteThreshold::SuperMajorityAgainst => { + let _ = T::ExternalDefaultOrigin::ensure_origin(origin)?; + }, + VoteThreshold::SimpleMajority => { + let _ = T::ExternalMajorityOrigin::ensure_origin(origin)?; + }, + }; + Ok(()) + } } /// Decode `Compact` from the trie at given key. diff --git a/frame/democracy/src/tests.rs b/frame/democracy/src/tests.rs index 41b279035028e..9c7ec2906c677 100644 --- a/frame/democracy/src/tests.rs +++ b/frame/democracy/src/tests.rs @@ -32,7 +32,7 @@ use pallet_balances::{BalanceLock, Error as BalancesError}; use sp_core::H256; use sp_runtime::{ testing::Header, - traits::{BadOrigin, BlakeTwo256, IdentityLookup}, + traits::{BadOrigin, BlakeTwo256, Hash, IdentityLookup}, Perbill, }; mod cancellation; @@ -41,6 +41,7 @@ mod delegation; mod external_proposing; mod fast_tracking; mod lock_voting; +mod metadata; mod public_proposals; mod scheduling; mod voting; @@ -276,3 +277,15 @@ fn big_nay(who: u64) -> AccountVote { fn tally(r: ReferendumIndex) -> Tally { Democracy::referendum_status(r).unwrap().tally } + +/// note a new preimage without registering. +fn note_preimage(who: u64) -> PreimageHash { + use std::sync::atomic::{AtomicU8, Ordering}; + // note a new preimage on every function invoke. + static COUNTER: AtomicU8 = AtomicU8::new(0); + let data = vec![COUNTER.fetch_add(1, Ordering::Relaxed)]; + assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(who), data.clone())); + let hash = BlakeTwo256::hash(&data); + assert!(!Preimage::is_requested(&hash)); + hash +} diff --git a/frame/democracy/src/tests/fast_tracking.rs b/frame/democracy/src/tests/fast_tracking.rs index 97bb7a63908ab..09af3dbf3b5dd 100644 --- a/frame/democracy/src/tests/fast_tracking.rs +++ b/frame/democracy/src/tests/fast_tracking.rs @@ -32,6 +32,14 @@ fn fast_track_referendum_works() { RuntimeOrigin::signed(3), set_balance_proposal(2) )); + let hash = note_preimage(1); + assert!(>::get(MetadataOwner::External).is_none()); + assert_ok!(Democracy::set_metadata( + RuntimeOrigin::signed(3), + MetadataOwner::External, + Some(hash), + ),); + assert!(>::get(MetadataOwner::External).is_some()); assert_noop!(Democracy::fast_track(RuntimeOrigin::signed(1), h, 3, 2), BadOrigin); assert_ok!(Democracy::fast_track(RuntimeOrigin::signed(5), h, 2, 0)); assert_eq!( @@ -44,6 +52,9 @@ fn fast_track_referendum_works() { tally: Tally { ayes: 0, nays: 0, turnout: 0 }, }) ); + // metadata reset from the external proposal to the referendum. + assert!(>::get(MetadataOwner::External).is_none()); + assert!(>::get(MetadataOwner::Referendum(0)).is_some()); }); } diff --git a/frame/democracy/src/tests/metadata.rs b/frame/democracy/src/tests/metadata.rs new file mode 100644 index 0000000000000..95b617e37b199 --- /dev/null +++ b/frame/democracy/src/tests/metadata.rs @@ -0,0 +1,209 @@ +// 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 tests for functionality concerning the metadata. + +use super::*; + +#[test] +fn set_external_metadata_works() { + new_test_ext().execute_with(|| { + use frame_support::traits::Hash as PreimageHash; + // invalid preimage hash. + let invalid_hash: PreimageHash = [1u8; 32].into(); + // metadata owner is an external proposal. + let owner = MetadataOwner::External; + // fails to set metadata if an external proposal does not exist. + assert_noop!( + Democracy::set_metadata(RuntimeOrigin::signed(2), owner.clone(), Some(invalid_hash)), + Error::::NoProposal, + ); + // create an external proposal. + assert_ok!(Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(2),)); + assert!(>::exists()); + // fails to set metadata with non external origin. + assert_noop!( + Democracy::set_metadata(RuntimeOrigin::signed(1), owner.clone(), Some(invalid_hash)), + BadOrigin, + ); + // fails to set non-existing preimage. + assert_noop!( + Democracy::set_metadata(RuntimeOrigin::signed(2), owner.clone(), Some(invalid_hash)), + Error::::PreimageNotExist, + ); + // set metadata successful. + let hash = note_preimage(1); + assert_ok!(Democracy::set_metadata(RuntimeOrigin::signed(2), owner.clone(), Some(hash),),); + System::assert_last_event(RuntimeEvent::Democracy(crate::Event::MetadataSet { + owner, + hash, + })); + }); +} + +#[test] +fn clear_metadata_works() { + new_test_ext().execute_with(|| { + // metadata owner is an external proposal. + let owner = MetadataOwner::External; + // create an external proposal. + assert_ok!(Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(2),)); + assert!(>::exists()); + // set metadata. + let hash = note_preimage(1); + assert_ok!(Democracy::set_metadata(RuntimeOrigin::signed(2), owner.clone(), Some(hash),)); + // fails to clear metadata with a wrong origin. + assert_noop!( + Democracy::set_metadata(RuntimeOrigin::signed(1), owner.clone(), None), + BadOrigin, + ); + // clear metadata successful. + assert_ok!(Democracy::set_metadata(RuntimeOrigin::signed(2), owner.clone(), None)); + System::assert_last_event(RuntimeEvent::Democracy(crate::Event::MetadataCleared { + owner, + hash, + })); + }); +} + +#[test] +fn set_proposal_metadata_works() { + new_test_ext().execute_with(|| { + use frame_support::traits::Hash as PreimageHash; + // invalid preimage hash. + let invalid_hash: PreimageHash = [1u8; 32].into(); + // create an external proposal. + assert_ok!(propose_set_balance(1, 2, 5)); + // metadata owner is a public proposal. + let owner = MetadataOwner::Proposal(Democracy::public_prop_count() - 1); + // fails to set non-existing preimage. + assert_noop!( + Democracy::set_metadata(RuntimeOrigin::signed(1), owner.clone(), Some(invalid_hash),), + Error::::PreimageNotExist, + ); + // note preimage. + let hash = note_preimage(1); + // fails to set a preimage if an origin is not a proposer. + assert_noop!( + Democracy::set_metadata(RuntimeOrigin::signed(3), owner.clone(), Some(hash),), + Error::::NoPermission, + ); + // set metadata successful. + assert_ok!(Democracy::set_metadata(RuntimeOrigin::signed(1), owner.clone(), Some(hash),),); + System::assert_last_event(RuntimeEvent::Democracy(crate::Event::MetadataSet { + owner, + hash, + })); + }); +} + +#[test] +fn clear_proposal_metadata_works() { + new_test_ext().execute_with(|| { + // create an external proposal. + assert_ok!(propose_set_balance(1, 2, 5)); + // metadata owner is a public proposal. + let owner = MetadataOwner::Proposal(Democracy::public_prop_count() - 1); + // set metadata. + let hash = note_preimage(1); + assert_ok!(Democracy::set_metadata(RuntimeOrigin::signed(1), owner.clone(), Some(hash),)); + // fails to clear metadata with a wrong origin. + assert_noop!( + Democracy::set_metadata(RuntimeOrigin::signed(3), owner.clone(), None), + Error::::NoPermission, + ); + // clear metadata successful. + assert_ok!(Democracy::set_metadata(RuntimeOrigin::signed(1), owner.clone(), None)); + System::assert_last_event(RuntimeEvent::Democracy(crate::Event::MetadataCleared { + owner, + hash, + })); + }); +} + +#[test] +fn set_referendum_metadata_by_root() { + new_test_ext().execute_with(|| { + let index = Democracy::inject_referendum( + 2, + set_balance_proposal(2), + VoteThreshold::SuperMajorityApprove, + 0, + ); + // metadata owner is a referendum. + let owner = MetadataOwner::Referendum(index); + // note preimage. + let hash = note_preimage(1); + // fails to set if not a root. + assert_noop!( + Democracy::set_metadata(RuntimeOrigin::signed(3), owner.clone(), Some(hash),), + Error::::NoPermission, + ); + // fails to clear if not a root. + assert_noop!( + Democracy::set_metadata(RuntimeOrigin::signed(3), owner.clone(), None,), + Error::::NoPermission, + ); + // succeed to set metadata by a root for an ongoing referendum. + assert_ok!(Democracy::set_metadata(RuntimeOrigin::root(), owner.clone(), Some(hash),)); + System::assert_last_event(RuntimeEvent::Democracy(crate::Event::MetadataSet { + owner: owner.clone(), + hash, + })); + // succeed to clear metadata by a root for an ongoing referendum. + assert_ok!(Democracy::set_metadata(RuntimeOrigin::root(), owner.clone(), None)); + System::assert_last_event(RuntimeEvent::Democracy(crate::Event::MetadataCleared { + owner, + hash, + })); + }); +} + +#[test] +fn clear_referendum_metadata_works() { + new_test_ext().execute_with(|| { + // create a referendum. + let index = Democracy::inject_referendum( + 2, + set_balance_proposal(2), + VoteThreshold::SuperMajorityApprove, + 0, + ); + // metadata owner is a referendum. + let owner = MetadataOwner::Referendum(index); + // set metadata. + let hash = note_preimage(1); + // referendum finished. + MetadataOf::::insert(owner.clone(), hash); + // no permission to clear metadata of an ongoing referendum. + assert_noop!( + Democracy::set_metadata(RuntimeOrigin::signed(1), owner.clone(), None), + Error::::NoPermission, + ); + // referendum finished. + ReferendumInfoOf::::insert( + index, + ReferendumInfo::Finished { end: 1, approved: true }, + ); + // clear metadata successful. + assert_ok!(Democracy::set_metadata(RuntimeOrigin::signed(1), owner.clone(), None)); + System::assert_last_event(RuntimeEvent::Democracy(crate::Event::MetadataCleared { + owner, + hash, + })); + }); +} diff --git a/frame/democracy/src/tests/public_proposals.rs b/frame/democracy/src/tests/public_proposals.rs index f48824dc95c5d..f9471442c6336 100644 --- a/frame/democracy/src/tests/public_proposals.rs +++ b/frame/democracy/src/tests/public_proposals.rs @@ -91,8 +91,20 @@ fn cancel_proposal_should_work() { 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); + let hash = note_preimage(1); + assert_ok!(Democracy::set_metadata( + RuntimeOrigin::signed(1), + MetadataOwner::Proposal(0), + Some(hash) + )); + assert!(>::get(MetadataOwner::Proposal(0)).is_some()); assert_ok!(Democracy::cancel_proposal(RuntimeOrigin::root(), 0)); - System::assert_last_event(crate::Event::ProposalCanceled { prop_index: 0 }.into()); + // metadata cleared, preimage unrequested. + assert!(>::get(MetadataOwner::Proposal(0)).is_none()); + System::assert_has_event(crate::Event::ProposalCanceled { prop_index: 0 }.into()); + System::assert_last_event( + crate::Event::MetadataCleared { owner: MetadataOwner::Proposal(0), hash }.into(), + ); assert_eq!(Democracy::backing_for(0), None); assert_eq!(Democracy::backing_for(1), Some(4)); }); diff --git a/frame/democracy/src/types.rs b/frame/democracy/src/types.rs index 4b7f1a0fac45c..25954e05498a6 100644 --- a/frame/democracy/src/types.rs +++ b/frame/democracy/src/types.rs @@ -25,6 +25,12 @@ use sp_runtime::{ RuntimeDebug, }; +/// A proposal index. +pub type PropIndex = u32; + +/// A referendum index. +pub type ReferendumIndex = u32; + /// Info regarding an ongoing referendum. #[derive(Encode, MaxEncodedLen, Decode, Default, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] pub struct Tally { @@ -206,3 +212,14 @@ pub enum UnvoteScope { /// Permitted to do only the changes that do not need the owner's permission. OnlyExpired, } + +/// Identifies an owner of a metadata. +#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +pub enum MetadataOwner { + /// External proposal. + External, + /// Public proposal of the index. + Proposal(PropIndex), + /// Referendum of the index. + Referendum(ReferendumIndex), +} diff --git a/frame/democracy/src/weights.rs b/frame/democracy/src/weights.rs index 985fe8fbde781..10d0744eac029 100644 --- a/frame/democracy/src/weights.rs +++ b/frame/democracy/src/weights.rs @@ -18,25 +18,26 @@ //! Autogenerated weights for pallet_democracy //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-01-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `runner-b3zmxxc-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! 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_democracy // --extrinsic=* // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/democracy/src/weights.rs +// --json-file=/builds/parity/mirrors/substrate/.git/.artifacts/bench.json +// --pallet=pallet_democracy +// --chain=dev // --header=./HEADER-APACHE2 +// --output=./frame/democracy/src/weights.rs // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -70,6 +71,12 @@ pub trait WeightInfo { fn unlock_set(r: u32, ) -> Weight; fn remove_vote(r: u32, ) -> Weight; fn remove_other_vote(r: u32, ) -> Weight; + fn set_external_metadata() -> Weight; + fn clear_external_metadata() -> Weight; + fn set_proposal_metadata() -> Weight; + fn clear_proposal_metadata() -> Weight; + fn set_referendum_metadata() -> Weight; + fn clear_referendum_metadata() -> Weight; } /// Weights for pallet_democracy using the Substrate node and recommended hardware. @@ -87,8 +94,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `4864` // Estimated: `23409` - // Minimum execution time: 34_509 nanoseconds. - Weight::from_parts(34_781_000, 23409) + // Minimum execution time: 42_939 nanoseconds. + Weight::from_parts(43_543_000, 23409) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -98,8 +105,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `3620` // Estimated: `5705` - // Minimum execution time: 31_151 nanoseconds. - Weight::from_parts(31_566_000, 5705) + // Minimum execution time: 36_475 nanoseconds. + Weight::from_parts(37_863_000, 5705) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -111,10 +118,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) fn vote_new() -> Weight { // Proof Size summary in bytes: - // Measured: `3555` + // Measured: `3565` // Estimated: `12720` - // Minimum execution time: 42_618 nanoseconds. - Weight::from_parts(43_231_000, 12720) + // Minimum execution time: 56_372 nanoseconds. + Weight::from_parts(57_483_000, 12720) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -126,10 +133,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) fn vote_existing() -> Weight { // Proof Size summary in bytes: - // Measured: `3577` + // Measured: `3587` // Estimated: `12720` - // Minimum execution time: 42_875 nanoseconds. - Weight::from_parts(43_338_000, 12720) + // Minimum execution time: 56_789 nanoseconds. + Weight::from_parts(57_737_000, 12720) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -137,14 +144,16 @@ impl WeightInfo for SubstrateWeight { /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) /// Storage: Democracy Cancellations (r:1 w:1) /// Proof: Democracy Cancellations (max_values: None, max_size: Some(33), added: 2508, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:1 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) fn emergency_cancel() -> Weight { // Proof Size summary in bytes: - // Measured: `320` - // Estimated: `5184` - // Minimum execution time: 16_543 nanoseconds. - Weight::from_parts(16_762_000, 5184) - .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(T::DbWeight::get().writes(2_u64)) + // Measured: `398` + // Estimated: `7712` + // Minimum execution time: 24_379 nanoseconds. + Weight::from_parts(25_302_000, 7712) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: Democracy PublicProps (r:1 w:1) /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) @@ -152,6 +161,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) /// Storage: System Account (r:1 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:3 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) /// Storage: Democracy NextExternal (r:1 w:1) /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) /// Storage: Democracy ReferendumInfoOf (r:1 w:1) @@ -160,12 +171,12 @@ impl WeightInfo for SubstrateWeight { /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) fn blacklist() -> Weight { // Proof Size summary in bytes: - // Measured: `5958` - // Estimated: `28808` - // Minimum execution time: 70_135 nanoseconds. - Weight::from_parts(70_616_000, 28808) - .saturating_add(T::DbWeight::get().reads(5_u64)) - .saturating_add(T::DbWeight::get().writes(6_u64)) + // Measured: `6036` + // Estimated: `36392` + // Minimum execution time: 100_345 nanoseconds. + Weight::from_parts(102_233_000, 36392) + .saturating_add(T::DbWeight::get().reads(8_u64)) + .saturating_add(T::DbWeight::get().writes(7_u64)) } /// Storage: Democracy NextExternal (r:1 w:1) /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) @@ -175,8 +186,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `3448` // Estimated: `6340` - // Minimum execution time: 12_580 nanoseconds. - Weight::from_parts(12_987_000, 6340) + // Minimum execution time: 13_155 nanoseconds. + Weight::from_parts(14_158_000, 6340) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -186,8 +197,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_320 nanoseconds. - Weight::from_ref_time(3_513_000) + // Minimum execution time: 2_961 nanoseconds. + Weight::from_ref_time(3_139_000) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Democracy NextExternal (r:0 w:1) @@ -196,37 +207,41 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_407 nanoseconds. - Weight::from_ref_time(3_565_000) + // Minimum execution time: 3_040 nanoseconds. + Weight::from_ref_time(3_261_000) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Democracy NextExternal (r:1 w:1) /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) /// Storage: Democracy ReferendumCount (r:1 w:1) /// Proof: Democracy ReferendumCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:1 w:2) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) /// Storage: Democracy ReferendumInfoOf (r:0 w:1) /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) fn fast_track() -> Weight { // Proof Size summary in bytes: - // Measured: `212` - // Estimated: `1126` - // Minimum execution time: 16_831 nanoseconds. - Weight::from_parts(17_155_000, 1126) - .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(T::DbWeight::get().writes(3_u64)) + // Measured: `286` + // Estimated: `3654` + // Minimum execution time: 26_666 nanoseconds. + Weight::from_parts(28_014_000, 3654) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) } /// Storage: Democracy NextExternal (r:1 w:1) /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) /// Storage: Democracy Blacklist (r:1 w:1) /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:1 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) fn veto_external() -> Weight { // Proof Size summary in bytes: - // Measured: `3477` - // Estimated: `6340` - // Minimum execution time: 22_072 nanoseconds. - Weight::from_parts(22_517_000, 6340) - .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(T::DbWeight::get().writes(2_u64)) + // Measured: `3551` + // Estimated: `8868` + // Minimum execution time: 30_180 nanoseconds. + Weight::from_parts(31_593_000, 8868) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: Democracy PublicProps (r:1 w:1) /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) @@ -234,24 +249,29 @@ impl WeightInfo for SubstrateWeight { /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) /// Storage: System Account (r:1 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:1 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) fn cancel_proposal() -> Weight { // Proof Size summary in bytes: - // Measured: `5837` - // Estimated: `25505` - // Minimum execution time: 56_925 nanoseconds. - Weight::from_parts(57_253_000, 25505) - .saturating_add(T::DbWeight::get().reads(3_u64)) - .saturating_add(T::DbWeight::get().writes(3_u64)) + // Measured: `5915` + // Estimated: `28033` + // Minimum execution time: 80_780 nanoseconds. + Weight::from_parts(82_070_000, 28033) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) } + /// Storage: Democracy MetadataOf (r:1 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) /// Storage: Democracy ReferendumInfoOf (r:0 w:1) /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) fn cancel_referendum() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 8_582 nanoseconds. - Weight::from_ref_time(8_754_000) - .saturating_add(T::DbWeight::get().writes(1_u64)) + // Measured: `271` + // Estimated: `2528` + // Minimum execution time: 18_117 nanoseconds. + Weight::from_parts(19_027_000, 2528) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: Democracy LowestUnbaked (r:1 w:1) /// Proof: Democracy LowestUnbaked (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -262,12 +282,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 99]`. fn on_initialize_base(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `207 + r * (117 ±0)` + // Measured: `244 + r * (117 ±0)` // Estimated: `998 + r * (2676 ±0)` - // Minimum execution time: 6_665 nanoseconds. - Weight::from_parts(9_219_932, 998) - // Standard Error: 4_236 - .saturating_add(Weight::from_ref_time(2_194_623).saturating_mul(r.into())) + // Minimum execution time: 7_093 nanoseconds. + Weight::from_parts(8_792_955, 998) + // Standard Error: 6_630 + .saturating_add(Weight::from_ref_time(3_091_565).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) @@ -288,12 +308,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 99]`. fn on_initialize_base_with_launch_period(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `207 + r * (117 ±0)` + // Measured: `244 + r * (117 ±0)` // Estimated: `19318 + r * (2676 ±0)` - // Minimum execution time: 9_842 nanoseconds. - Weight::from_parts(11_932_535, 19318) - // Standard Error: 4_413 - .saturating_add(Weight::from_ref_time(2_199_644).saturating_mul(r.into())) + // Minimum execution time: 10_372 nanoseconds. + Weight::from_parts(10_961_165, 19318) + // Standard Error: 7_284 + .saturating_add(Weight::from_ref_time(3_112_573).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) @@ -308,12 +328,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 99]`. fn delegate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `948 + r * (139 ±0)` + // Measured: `958 + r * (139 ±0)` // Estimated: `22584 + r * (2676 ±0)` - // Minimum execution time: 34_740 nanoseconds. - Weight::from_parts(38_366_374, 22584) - // Standard Error: 4_868 - .saturating_add(Weight::from_ref_time(3_286_516).saturating_mul(r.into())) + // Minimum execution time: 36_618 nanoseconds. + Weight::from_parts(42_803_184, 22584) + // Standard Error: 7_268 + .saturating_add(Weight::from_ref_time(4_537_902).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(4_u64)) @@ -327,12 +347,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 99]`. fn undelegate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `547 + r * (139 ±0)` + // Measured: `557 + r * (139 ±0)` // Estimated: `12540 + r * (2676 ±0)` - // Minimum execution time: 19_516 nanoseconds. - Weight::from_parts(21_629_605, 12540) - // Standard Error: 4_401 - .saturating_add(Weight::from_ref_time(3_238_187).saturating_mul(r.into())) + // Minimum execution time: 19_758 nanoseconds. + Weight::from_parts(21_641_793, 12540) + // Standard Error: 6_889 + .saturating_add(Weight::from_ref_time(4_478_884).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) @@ -345,8 +365,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_291 nanoseconds. - Weight::from_ref_time(3_485_000) + // Minimum execution time: 2_844 nanoseconds. + Weight::from_ref_time(3_017_000) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Democracy VotingOf (r:1 w:1) @@ -358,12 +378,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 99]`. fn unlock_remove(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `617` + // Measured: `627` // Estimated: `12647` - // Minimum execution time: 19_357 nanoseconds. - Weight::from_parts(24_014_517, 12647) - // Standard Error: 994 - .saturating_add(Weight::from_ref_time(17_096).saturating_mul(r.into())) + // Minimum execution time: 20_380 nanoseconds. + Weight::from_parts(28_295_875, 12647) + // Standard Error: 2_331 + .saturating_add(Weight::from_ref_time(67_348).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -376,12 +396,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 99]`. fn unlock_set(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `618 + r * (22 ±0)` + // Measured: `628 + r * (22 ±0)` // Estimated: `12647` - // Minimum execution time: 22_340 nanoseconds. - Weight::from_parts(23_355_734, 12647) - // Standard Error: 548 - .saturating_add(Weight::from_ref_time(64_308).saturating_mul(r.into())) + // Minimum execution time: 24_475 nanoseconds. + Weight::from_parts(27_102_576, 12647) + // Standard Error: 1_464 + .saturating_add(Weight::from_ref_time(128_921).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -392,12 +412,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[1, 100]`. fn remove_vote(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `781 + r * (26 ±0)` + // Measured: `791 + r * (26 ±0)` // Estimated: `8946` - // Minimum execution time: 14_542 nanoseconds. - Weight::from_parts(16_411_916, 8946) - // Standard Error: 839 - .saturating_add(Weight::from_ref_time(73_268).saturating_mul(r.into())) + // Minimum execution time: 15_039 nanoseconds. + Weight::from_parts(19_252_498, 8946) + // Standard Error: 1_798 + .saturating_add(Weight::from_ref_time(131_855).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -408,15 +428,97 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[1, 100]`. fn remove_other_vote(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `781 + r * (26 ±0)` + // Measured: `791 + r * (26 ±0)` // Estimated: `8946` - // Minimum execution time: 14_463 nanoseconds. - Weight::from_parts(16_302_901, 8946) - // Standard Error: 809 - .saturating_add(Weight::from_ref_time(73_692).saturating_mul(r.into())) + // Minimum execution time: 14_837 nanoseconds. + Weight::from_parts(19_144_929, 8946) + // Standard Error: 1_875 + .saturating_add(Weight::from_ref_time(136_819).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } + /// Storage: Democracy NextExternal (r:1 w:0) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) + /// Storage: Preimage StatusFor (r:1 w:0) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:0 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + fn set_external_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `356` + // Estimated: `3193` + // Minimum execution time: 17_338 nanoseconds. + Weight::from_parts(17_946_000, 3193) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Democracy NextExternal (r:1 w:0) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:1 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + fn clear_external_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `286` + // Estimated: `3155` + // Minimum execution time: 15_364 nanoseconds. + Weight::from_parts(15_990_000, 3155) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Democracy PublicProps (r:1 w:0) + /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) + /// Storage: Preimage StatusFor (r:1 w:0) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:0 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + fn set_proposal_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `4919` + // Estimated: `19763` + // Minimum execution time: 37_147 nanoseconds. + Weight::from_parts(37_778_000, 19763) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Democracy PublicProps (r:1 w:0) + /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:1 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + fn clear_proposal_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `4853` + // Estimated: `19725` + // Minimum execution time: 34_118 nanoseconds. + Weight::from_parts(34_737_000, 19725) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Preimage StatusFor (r:1 w:0) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:0 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + fn set_referendum_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `144` + // Estimated: `2566` + // Minimum execution time: 12_787 nanoseconds. + Weight::from_parts(13_463_000, 2566) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Democracy ReferendumInfoOf (r:1 w:0) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:1 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + fn clear_referendum_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `302` + // Estimated: `5204` + // Minimum execution time: 17_636 nanoseconds. + Weight::from_parts(18_399_000, 5204) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } } // For backwards compatibility and tests @@ -433,8 +535,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `4864` // Estimated: `23409` - // Minimum execution time: 34_509 nanoseconds. - Weight::from_parts(34_781_000, 23409) + // Minimum execution time: 42_939 nanoseconds. + Weight::from_parts(43_543_000, 23409) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -444,8 +546,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `3620` // Estimated: `5705` - // Minimum execution time: 31_151 nanoseconds. - Weight::from_parts(31_566_000, 5705) + // Minimum execution time: 36_475 nanoseconds. + Weight::from_parts(37_863_000, 5705) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -457,10 +559,10 @@ impl WeightInfo for () { /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) fn vote_new() -> Weight { // Proof Size summary in bytes: - // Measured: `3555` + // Measured: `3565` // Estimated: `12720` - // Minimum execution time: 42_618 nanoseconds. - Weight::from_parts(43_231_000, 12720) + // Minimum execution time: 56_372 nanoseconds. + Weight::from_parts(57_483_000, 12720) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -472,10 +574,10 @@ impl WeightInfo for () { /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) fn vote_existing() -> Weight { // Proof Size summary in bytes: - // Measured: `3577` + // Measured: `3587` // Estimated: `12720` - // Minimum execution time: 42_875 nanoseconds. - Weight::from_parts(43_338_000, 12720) + // Minimum execution time: 56_789 nanoseconds. + Weight::from_parts(57_737_000, 12720) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -483,14 +585,16 @@ impl WeightInfo for () { /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) /// Storage: Democracy Cancellations (r:1 w:1) /// Proof: Democracy Cancellations (max_values: None, max_size: Some(33), added: 2508, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:1 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) fn emergency_cancel() -> Weight { // Proof Size summary in bytes: - // Measured: `320` - // Estimated: `5184` - // Minimum execution time: 16_543 nanoseconds. - Weight::from_parts(16_762_000, 5184) - .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(RocksDbWeight::get().writes(2_u64)) + // Measured: `398` + // Estimated: `7712` + // Minimum execution time: 24_379 nanoseconds. + Weight::from_parts(25_302_000, 7712) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: Democracy PublicProps (r:1 w:1) /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) @@ -498,6 +602,8 @@ impl WeightInfo for () { /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) /// Storage: System Account (r:1 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:3 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) /// Storage: Democracy NextExternal (r:1 w:1) /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) /// Storage: Democracy ReferendumInfoOf (r:1 w:1) @@ -506,12 +612,12 @@ impl WeightInfo for () { /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) fn blacklist() -> Weight { // Proof Size summary in bytes: - // Measured: `5958` - // Estimated: `28808` - // Minimum execution time: 70_135 nanoseconds. - Weight::from_parts(70_616_000, 28808) - .saturating_add(RocksDbWeight::get().reads(5_u64)) - .saturating_add(RocksDbWeight::get().writes(6_u64)) + // Measured: `6036` + // Estimated: `36392` + // Minimum execution time: 100_345 nanoseconds. + Weight::from_parts(102_233_000, 36392) + .saturating_add(RocksDbWeight::get().reads(8_u64)) + .saturating_add(RocksDbWeight::get().writes(7_u64)) } /// Storage: Democracy NextExternal (r:1 w:1) /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) @@ -521,8 +627,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `3448` // Estimated: `6340` - // Minimum execution time: 12_580 nanoseconds. - Weight::from_parts(12_987_000, 6340) + // Minimum execution time: 13_155 nanoseconds. + Weight::from_parts(14_158_000, 6340) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -532,8 +638,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_320 nanoseconds. - Weight::from_ref_time(3_513_000) + // Minimum execution time: 2_961 nanoseconds. + Weight::from_ref_time(3_139_000) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Democracy NextExternal (r:0 w:1) @@ -542,37 +648,41 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_407 nanoseconds. - Weight::from_ref_time(3_565_000) + // Minimum execution time: 3_040 nanoseconds. + Weight::from_ref_time(3_261_000) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Democracy NextExternal (r:1 w:1) /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) /// Storage: Democracy ReferendumCount (r:1 w:1) /// Proof: Democracy ReferendumCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:1 w:2) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) /// Storage: Democracy ReferendumInfoOf (r:0 w:1) /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) fn fast_track() -> Weight { // Proof Size summary in bytes: - // Measured: `212` - // Estimated: `1126` - // Minimum execution time: 16_831 nanoseconds. - Weight::from_parts(17_155_000, 1126) - .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(RocksDbWeight::get().writes(3_u64)) + // Measured: `286` + // Estimated: `3654` + // Minimum execution time: 26_666 nanoseconds. + Weight::from_parts(28_014_000, 3654) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(5_u64)) } /// Storage: Democracy NextExternal (r:1 w:1) /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) /// Storage: Democracy Blacklist (r:1 w:1) /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:1 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) fn veto_external() -> Weight { // Proof Size summary in bytes: - // Measured: `3477` - // Estimated: `6340` - // Minimum execution time: 22_072 nanoseconds. - Weight::from_parts(22_517_000, 6340) - .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(RocksDbWeight::get().writes(2_u64)) + // Measured: `3551` + // Estimated: `8868` + // Minimum execution time: 30_180 nanoseconds. + Weight::from_parts(31_593_000, 8868) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: Democracy PublicProps (r:1 w:1) /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) @@ -580,24 +690,29 @@ impl WeightInfo for () { /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) /// Storage: System Account (r:1 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:1 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) fn cancel_proposal() -> Weight { // Proof Size summary in bytes: - // Measured: `5837` - // Estimated: `25505` - // Minimum execution time: 56_925 nanoseconds. - Weight::from_parts(57_253_000, 25505) - .saturating_add(RocksDbWeight::get().reads(3_u64)) - .saturating_add(RocksDbWeight::get().writes(3_u64)) + // Measured: `5915` + // Estimated: `28033` + // Minimum execution time: 80_780 nanoseconds. + Weight::from_parts(82_070_000, 28033) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) } + /// Storage: Democracy MetadataOf (r:1 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) /// Storage: Democracy ReferendumInfoOf (r:0 w:1) /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) fn cancel_referendum() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 8_582 nanoseconds. - Weight::from_ref_time(8_754_000) - .saturating_add(RocksDbWeight::get().writes(1_u64)) + // Measured: `271` + // Estimated: `2528` + // Minimum execution time: 18_117 nanoseconds. + Weight::from_parts(19_027_000, 2528) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: Democracy LowestUnbaked (r:1 w:1) /// Proof: Democracy LowestUnbaked (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -608,12 +723,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 99]`. fn on_initialize_base(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `207 + r * (117 ±0)` + // Measured: `244 + r * (117 ±0)` // Estimated: `998 + r * (2676 ±0)` - // Minimum execution time: 6_665 nanoseconds. - Weight::from_parts(9_219_932, 998) - // Standard Error: 4_236 - .saturating_add(Weight::from_ref_time(2_194_623).saturating_mul(r.into())) + // Minimum execution time: 7_093 nanoseconds. + Weight::from_parts(8_792_955, 998) + // Standard Error: 6_630 + .saturating_add(Weight::from_ref_time(3_091_565).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) @@ -634,12 +749,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 99]`. fn on_initialize_base_with_launch_period(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `207 + r * (117 ±0)` + // Measured: `244 + r * (117 ±0)` // Estimated: `19318 + r * (2676 ±0)` - // Minimum execution time: 9_842 nanoseconds. - Weight::from_parts(11_932_535, 19318) - // Standard Error: 4_413 - .saturating_add(Weight::from_ref_time(2_199_644).saturating_mul(r.into())) + // Minimum execution time: 10_372 nanoseconds. + Weight::from_parts(10_961_165, 19318) + // Standard Error: 7_284 + .saturating_add(Weight::from_ref_time(3_112_573).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) @@ -654,12 +769,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 99]`. fn delegate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `948 + r * (139 ±0)` + // Measured: `958 + r * (139 ±0)` // Estimated: `22584 + r * (2676 ±0)` - // Minimum execution time: 34_740 nanoseconds. - Weight::from_parts(38_366_374, 22584) - // Standard Error: 4_868 - .saturating_add(Weight::from_ref_time(3_286_516).saturating_mul(r.into())) + // Minimum execution time: 36_618 nanoseconds. + Weight::from_parts(42_803_184, 22584) + // Standard Error: 7_268 + .saturating_add(Weight::from_ref_time(4_537_902).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(4_u64)) @@ -673,12 +788,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 99]`. fn undelegate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `547 + r * (139 ±0)` + // Measured: `557 + r * (139 ±0)` // Estimated: `12540 + r * (2676 ±0)` - // Minimum execution time: 19_516 nanoseconds. - Weight::from_parts(21_629_605, 12540) - // Standard Error: 4_401 - .saturating_add(Weight::from_ref_time(3_238_187).saturating_mul(r.into())) + // Minimum execution time: 19_758 nanoseconds. + Weight::from_parts(21_641_793, 12540) + // Standard Error: 6_889 + .saturating_add(Weight::from_ref_time(4_478_884).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(2_u64)) @@ -691,8 +806,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_291 nanoseconds. - Weight::from_ref_time(3_485_000) + // Minimum execution time: 2_844 nanoseconds. + Weight::from_ref_time(3_017_000) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Democracy VotingOf (r:1 w:1) @@ -704,12 +819,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 99]`. fn unlock_remove(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `617` + // Measured: `627` // Estimated: `12647` - // Minimum execution time: 19_357 nanoseconds. - Weight::from_parts(24_014_517, 12647) - // Standard Error: 994 - .saturating_add(Weight::from_ref_time(17_096).saturating_mul(r.into())) + // Minimum execution time: 20_380 nanoseconds. + Weight::from_parts(28_295_875, 12647) + // Standard Error: 2_331 + .saturating_add(Weight::from_ref_time(67_348).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -722,12 +837,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 99]`. fn unlock_set(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `618 + r * (22 ±0)` + // Measured: `628 + r * (22 ±0)` // Estimated: `12647` - // Minimum execution time: 22_340 nanoseconds. - Weight::from_parts(23_355_734, 12647) - // Standard Error: 548 - .saturating_add(Weight::from_ref_time(64_308).saturating_mul(r.into())) + // Minimum execution time: 24_475 nanoseconds. + Weight::from_parts(27_102_576, 12647) + // Standard Error: 1_464 + .saturating_add(Weight::from_ref_time(128_921).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -738,12 +853,12 @@ impl WeightInfo for () { /// The range of component `r` is `[1, 100]`. fn remove_vote(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `781 + r * (26 ±0)` + // Measured: `791 + r * (26 ±0)` // Estimated: `8946` - // Minimum execution time: 14_542 nanoseconds. - Weight::from_parts(16_411_916, 8946) - // Standard Error: 839 - .saturating_add(Weight::from_ref_time(73_268).saturating_mul(r.into())) + // Minimum execution time: 15_039 nanoseconds. + Weight::from_parts(19_252_498, 8946) + // Standard Error: 1_798 + .saturating_add(Weight::from_ref_time(131_855).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -754,13 +869,95 @@ impl WeightInfo for () { /// The range of component `r` is `[1, 100]`. fn remove_other_vote(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `781 + r * (26 ±0)` + // Measured: `791 + r * (26 ±0)` // Estimated: `8946` - // Minimum execution time: 14_463 nanoseconds. - Weight::from_parts(16_302_901, 8946) - // Standard Error: 809 - .saturating_add(Weight::from_ref_time(73_692).saturating_mul(r.into())) + // Minimum execution time: 14_837 nanoseconds. + Weight::from_parts(19_144_929, 8946) + // Standard Error: 1_875 + .saturating_add(Weight::from_ref_time(136_819).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } + /// Storage: Democracy NextExternal (r:1 w:0) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) + /// Storage: Preimage StatusFor (r:1 w:0) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:0 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + fn set_external_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `356` + // Estimated: `3193` + // Minimum execution time: 17_338 nanoseconds. + Weight::from_parts(17_946_000, 3193) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Democracy NextExternal (r:1 w:0) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:1 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + fn clear_external_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `286` + // Estimated: `3155` + // Minimum execution time: 15_364 nanoseconds. + Weight::from_parts(15_990_000, 3155) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Democracy PublicProps (r:1 w:0) + /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) + /// Storage: Preimage StatusFor (r:1 w:0) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:0 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + fn set_proposal_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `4919` + // Estimated: `19763` + // Minimum execution time: 37_147 nanoseconds. + Weight::from_parts(37_778_000, 19763) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Democracy PublicProps (r:1 w:0) + /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:1 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + fn clear_proposal_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `4853` + // Estimated: `19725` + // Minimum execution time: 34_118 nanoseconds. + Weight::from_parts(34_737_000, 19725) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Preimage StatusFor (r:1 w:0) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:0 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + fn set_referendum_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `144` + // Estimated: `2566` + // Minimum execution time: 12_787 nanoseconds. + Weight::from_parts(13_463_000, 2566) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Democracy ReferendumInfoOf (r:1 w:0) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:1 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + fn clear_referendum_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `302` + // Estimated: `5204` + // Minimum execution time: 17_636 nanoseconds. + Weight::from_parts(18_399_000, 5204) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } } diff --git a/frame/referenda/src/benchmarking.rs b/frame/referenda/src/benchmarking.rs index 62b37857f2567..ea44beeb3994f 100644 --- a/frame/referenda/src/benchmarking.rs +++ b/frame/referenda/src/benchmarking.rs @@ -33,7 +33,6 @@ use sp_runtime::traits::Bounded as ArithBounded; const SEED: u32 = 0; -#[allow(dead_code)] fn assert_last_event, I: 'static>(generic_event: >::RuntimeEvent) { frame_system::Pallet::::assert_last_event(generic_event.into()); } @@ -631,6 +630,31 @@ benchmarks_instance_pallet! { assert_matches!(info, ReferendumInfo::Rejected(..)); } + set_some_metadata { + use sp_std::borrow::Cow; + let origin = T::SubmitOrigin::try_successful_origin() + .expect("SubmitOrigin has no successful origin required for the benchmark"); + let index = create_referendum::(origin.clone()); + let hash = T::Preimages::note(Cow::from(vec![5, 6])).unwrap(); + }: set_metadata(origin, index, Some(hash)) + verify { + assert_last_event::(Event::MetadataSet { index, hash }.into()); + } + + clear_metadata { + use sp_std::borrow::Cow; + let origin = T::SubmitOrigin::try_successful_origin() + .expect("SubmitOrigin has no successful origin required for the benchmark"); + let index = create_referendum::(origin.clone()); + let hash = T::Preimages::note(Cow::from(vec![6, 7, 8])).unwrap(); + assert_ok!( + Referenda::::set_metadata(origin.clone(), index, Some(hash)) + ); + }: set_metadata(origin, index, None) + verify { + assert_last_event::(Event::MetadataCleared { index, hash }.into()); + } + impl_benchmark_test_suite!( Referenda, crate::mock::new_test_ext(), diff --git a/frame/referenda/src/lib.rs b/frame/referenda/src/lib.rs index 0b846faf88558..4491c1b40d197 100644 --- a/frame/referenda/src/lib.rs +++ b/frame/referenda/src/lib.rs @@ -72,8 +72,8 @@ use frame_support::{ v3::{Anon as ScheduleAnon, Named as ScheduleNamed}, DispatchTime, }, - Currency, LockIdentifier, OnUnbalanced, OriginTrait, PollStatus, Polling, QueryPreimage, - ReservableCurrency, StorePreimage, VoteTally, + Currency, Hash as PreimageHash, LockIdentifier, OnUnbalanced, OriginTrait, PollStatus, + Polling, QueryPreimage, ReservableCurrency, StorePreimage, VoteTally, }, BoundedVec, }; @@ -251,6 +251,16 @@ pub mod pallet { pub type DecidingCount, I: 'static = ()> = StorageMap<_, Twox64Concat, TrackIdOf, u32, ValueQuery>; + /// The metadata is a general information concerning the referendum. + /// The `PreimageHash` refers to the preimage of the `Preimages` provider which can be a JSON + /// dump or IPFS hash of a JSON file. + /// + /// Consider a garbage collection for a metadata of finished referendums to `unrequest` (remove) + /// large preimages. + #[pallet::storage] + pub type MetadataOf, I: 'static = ()> = + StorageMap<_, Blake2_128Concat, ReferendumIndex, PreimageHash>; + #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event, I: 'static = ()> { @@ -356,6 +366,20 @@ pub mod pallet { /// The amount placed by the account. amount: BalanceOf, }, + /// Metadata for a referendum has been set. + MetadataSet { + /// Index of the referendum. + index: ReferendumIndex, + /// Preimage hash. + hash: PreimageHash, + }, + /// Metadata for a referendum has been cleared. + MetadataCleared { + /// Index of the referendum. + index: ReferendumIndex, + /// Preimage hash. + hash: PreimageHash, + }, } #[pallet::error] @@ -384,6 +408,8 @@ pub mod pallet { NoDeposit, /// The referendum status is invalid for this operation. BadStatus, + /// The preimage does not exist. + PreimageNotExist, } #[pallet::call] @@ -540,6 +566,7 @@ pub mod pallet { Self::deposit_event(Event::::Killed { index, tally: status.tally }); Self::slash_deposit(Some(status.submission_deposit.clone())); Self::slash_deposit(status.decision_deposit.clone()); + Self::do_clear_metadata(index); let info = ReferendumInfo::Killed(frame_system::Pallet::::block_number()); ReferendumInfoFor::::insert(index, info); Ok(()) @@ -633,6 +660,40 @@ pub mod pallet { Self::deposit_event(e); Ok(()) } + + /// Set or clear metadata of a referendum. + /// + /// Parameters: + /// - `origin`: Must be `Signed` by a creator of a referendum or by anyone to clear a + /// metadata of a finished referendum. + /// - `index`: The index of a referendum to set or clear metadata for. + /// - `maybe_hash`: The hash of an on-chain stored preimage. `None` to clear a metadata. + #[pallet::call_index(8)] + #[pallet::weight( + maybe_hash.map_or( + T::WeightInfo::clear_metadata(), |_| T::WeightInfo::set_some_metadata()) + )] + pub fn set_metadata( + origin: OriginFor, + index: ReferendumIndex, + maybe_hash: Option, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + if let Some(hash) = maybe_hash { + let status = Self::ensure_ongoing(index)?; + ensure!(status.submission_deposit.who == who, Error::::NoPermission); + ensure!(T::Preimages::len(&hash).is_some(), Error::::PreimageNotExist); + MetadataOf::::insert(index, hash); + Self::deposit_event(Event::::MetadataSet { index, hash }); + Ok(()) + } else { + if let Some(status) = Self::ensure_ongoing(index).ok() { + ensure!(status.submission_deposit.who == who, Error::::NoPermission); + } + Self::do_clear_metadata(index); + Ok(()) + } + } } } @@ -1204,4 +1265,11 @@ impl, I: 'static> Pallet { support_needed.passing(x, tally.support(id)) && approval_needed.passing(x, tally.approval(id)) } + + /// Clear metadata if exist for a given referendum index. + fn do_clear_metadata(index: ReferendumIndex) { + if let Some(hash) = MetadataOf::::take(index) { + Self::deposit_event(Event::::MetadataCleared { index, hash }); + } + } } diff --git a/frame/referenda/src/mock.rs b/frame/referenda/src/mock.rs index 82ae508d52b6f..f6e19d06ed5f3 100644 --- a/frame/referenda/src/mock.rs +++ b/frame/referenda/src/mock.rs @@ -32,7 +32,7 @@ use frame_system::{EnsureRoot, EnsureSignedBy}; use sp_core::H256; use sp_runtime::{ testing::Header, - traits::{BlakeTwo256, IdentityLookup}, + traits::{BlakeTwo256, Hash, IdentityLookup}, DispatchResult, Perbill, }; @@ -470,3 +470,15 @@ impl RefState { index } } + +/// note a new preimage without registering. +pub fn note_preimage(who: u64) -> PreimageHash { + use std::sync::atomic::{AtomicU8, Ordering}; + // note a new preimage on every function invoke. + static COUNTER: AtomicU8 = AtomicU8::new(0); + let data = vec![COUNTER.fetch_add(1, Ordering::Relaxed)]; + assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(who), data.clone())); + let hash = BlakeTwo256::hash(&data); + assert!(!Preimage::is_requested(&hash)); + hash +} diff --git a/frame/referenda/src/tests.rs b/frame/referenda/src/tests.rs index c109fafe332e2..034454cfcc265 100644 --- a/frame/referenda/src/tests.rs +++ b/frame/referenda/src/tests.rs @@ -578,3 +578,75 @@ fn curve_handles_all_inputs() { let threshold = test_curve.threshold(Perbill::one()); assert_eq!(threshold, Perbill::zero()); } + +#[test] +fn set_metadata_works() { + new_test_ext().execute_with(|| { + use frame_support::traits::Hash as PreimageHash; + // invalid preimage hash. + let invalid_hash: PreimageHash = [1u8; 32].into(); + // fails to set metadata for a finished referendum. + assert_ok!(Referenda::submit( + RuntimeOrigin::signed(1), + Box::new(RawOrigin::Root.into()), + set_balance_proposal_bounded(1), + DispatchTime::At(1), + )); + let index = ReferendumCount::::get() - 1; + assert_ok!(Referenda::kill(RuntimeOrigin::root(), index)); + assert_noop!( + Referenda::set_metadata(RuntimeOrigin::signed(1), index, Some(invalid_hash)), + Error::::NotOngoing, + ); + // no permission to set metadata. + assert_ok!(Referenda::submit( + RuntimeOrigin::signed(1), + Box::new(RawOrigin::Root.into()), + set_balance_proposal_bounded(1), + DispatchTime::At(1), + )); + let index = ReferendumCount::::get() - 1; + assert_noop!( + Referenda::set_metadata(RuntimeOrigin::signed(2), index, Some(invalid_hash)), + Error::::NoPermission, + ); + // preimage does not exist. + let index = ReferendumCount::::get() - 1; + assert_noop!( + Referenda::set_metadata(RuntimeOrigin::signed(1), index, Some(invalid_hash)), + Error::::PreimageNotExist, + ); + // metadata set. + let index = ReferendumCount::::get() - 1; + let hash = note_preimage(1); + assert_ok!(Referenda::set_metadata(RuntimeOrigin::signed(1), index, Some(hash))); + System::assert_last_event(RuntimeEvent::Referenda(crate::Event::MetadataSet { + index, + hash, + })); + }); +} + +#[test] +fn clear_metadata_works() { + new_test_ext().execute_with(|| { + let hash = note_preimage(1); + assert_ok!(Referenda::submit( + RuntimeOrigin::signed(1), + Box::new(RawOrigin::Root.into()), + set_balance_proposal_bounded(1), + DispatchTime::At(1), + )); + let index = ReferendumCount::::get() - 1; + assert_ok!(Referenda::set_metadata(RuntimeOrigin::signed(1), index, Some(hash))); + assert_noop!( + Referenda::set_metadata(RuntimeOrigin::signed(2), index, None), + Error::::NoPermission, + ); + assert_ok!(Referenda::set_metadata(RuntimeOrigin::signed(1), index, None),); + System::assert_last_event(RuntimeEvent::Referenda(crate::Event::MetadataCleared { + index, + hash, + })); + }); +} diff --git a/frame/referenda/src/weights.rs b/frame/referenda/src/weights.rs index 68b44e8beff90..ab49759516bd9 100644 --- a/frame/referenda/src/weights.rs +++ b/frame/referenda/src/weights.rs @@ -18,25 +18,26 @@ //! Autogenerated weights for pallet_referenda //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-01-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `runner-b3zmxxc-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! 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_referenda // --extrinsic=* // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/referenda/src/weights.rs +// --json-file=/builds/parity/mirrors/substrate/.git/.artifacts/bench.json +// --pallet=pallet_referenda +// --chain=dev // --header=./HEADER-APACHE2 +// --output=./frame/referenda/src/weights.rs // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -76,6 +77,8 @@ pub trait WeightInfo { fn nudge_referendum_continue_confirming() -> Weight; fn nudge_referendum_approved() -> Weight; fn nudge_referendum_rejected() -> Weight; + fn set_some_metadata() -> Weight; + fn clear_metadata() -> Weight; } /// Weights for pallet_referenda using the Substrate node and recommended hardware. @@ -91,8 +94,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `251` // Estimated: `109996` - // Minimum execution time: 32_207 nanoseconds. - Weight::from_parts(32_639_000, 109996) + // Minimum execution time: 34_540 nanoseconds. + Weight::from_parts(36_144_000, 109996) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -104,8 +107,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `536` // Estimated: `221835` - // Minimum execution time: 43_766 nanoseconds. - Weight::from_parts(44_494_000, 221835) + // Minimum execution time: 46_963 nanoseconds. + Weight::from_parts(48_459_000, 221835) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -119,8 +122,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `3203` // Estimated: `9817` - // Minimum execution time: 41_561 nanoseconds. - Weight::from_parts(42_180_000, 9817) + // Minimum execution time: 55_798 nanoseconds. + Weight::from_parts(58_260_000, 9817) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -134,8 +137,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `3223` // Estimated: `9817` - // Minimum execution time: 41_039 nanoseconds. - Weight::from_parts(41_673_000, 9817) + // Minimum execution time: 53_888 nanoseconds. + Weight::from_parts(57_919_000, 9817) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -149,8 +152,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `536` // Estimated: `224324` - // Minimum execution time: 52_922 nanoseconds. - Weight::from_parts(53_395_000, 224324) + // Minimum execution time: 56_121 nanoseconds. + Weight::from_parts(58_301_000, 224324) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -164,8 +167,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `536` // Estimated: `224324` - // Minimum execution time: 51_050 nanoseconds. - Weight::from_parts(51_736_000, 224324) + // Minimum execution time: 54_237 nanoseconds. + Weight::from_parts(55_681_000, 224324) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -175,8 +178,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `415` // Estimated: `2841` - // Minimum execution time: 24_102 nanoseconds. - Weight::from_parts(24_372_000, 2841) + // Minimum execution time: 25_734 nanoseconds. + Weight::from_parts(26_429_000, 2841) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -186,8 +189,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `405` // Estimated: `2841` - // Minimum execution time: 24_162 nanoseconds. - Weight::from_parts(24_547_000, 2841) + // Minimum execution time: 26_000 nanoseconds. + Weight::from_parts(26_786_000, 2841) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -199,8 +202,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `412` // Estimated: `221835` - // Minimum execution time: 32_247 nanoseconds. - Weight::from_parts(32_731_000, 221835) + // Minimum execution time: 34_567 nanoseconds. + Weight::from_parts(35_939_000, 221835) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -208,13 +211,15 @@ impl WeightInfo for SubstrateWeight { /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) /// Storage: Scheduler Agenda (r:2 w:2) /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: Referenda MetadataOf (r:1 w:0) + /// Proof: Referenda MetadataOf (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) fn kill() -> Weight { // Proof Size summary in bytes: // Measured: `717` - // Estimated: `221835` - // Minimum execution time: 59_900 nanoseconds. - Weight::from_parts(60_659_000, 221835) - .saturating_add(T::DbWeight::get().reads(3_u64)) + // Estimated: `224362` + // Minimum execution time: 67_744 nanoseconds. + Weight::from_parts(70_047_000, 224362) + .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: Referenda TrackQueue (r:1 w:0) @@ -225,8 +230,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `174` // Estimated: `6976` - // Minimum execution time: 9_322 nanoseconds. - Weight::from_parts(9_638_000, 6976) + // Minimum execution time: 9_886 nanoseconds. + Weight::from_parts(10_406_000, 6976) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -240,8 +245,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `4661` // Estimated: `226322` - // Minimum execution time: 76_976 nanoseconds. - Weight::from_parts(77_597_000, 226322) + // Minimum execution time: 100_449 nanoseconds. + Weight::from_parts(101_812_000, 226322) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -255,8 +260,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `4661` // Estimated: `226322` - // Minimum execution time: 78_405 nanoseconds. - Weight::from_parts(78_972_000, 226322) + // Minimum execution time: 101_430 nanoseconds. + Weight::from_parts(103_704_000, 226322) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -270,8 +275,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `4682` // Estimated: `116825` - // Minimum execution time: 51_360 nanoseconds. - Weight::from_parts(51_737_000, 116825) + // Minimum execution time: 67_224 nanoseconds. + Weight::from_parts(70_596_000, 116825) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -285,8 +290,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `4668` // Estimated: `116825` - // Minimum execution time: 50_485 nanoseconds. - Weight::from_parts(51_601_000, 116825) + // Minimum execution time: 65_461 nanoseconds. + Weight::from_parts(69_624_000, 116825) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -302,8 +307,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `4642` // Estimated: `119314` - // Minimum execution time: 53_075 nanoseconds. - Weight::from_parts(54_014_000, 119314) + // Minimum execution time: 69_848 nanoseconds. + Weight::from_parts(74_480_000, 119314) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -319,8 +324,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `4676` // Estimated: `119314` - // Minimum execution time: 52_916 nanoseconds. - Weight::from_parts(53_716_000, 119314) + // Minimum execution time: 70_042 nanoseconds. + Weight::from_parts(72_912_000, 119314) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -332,8 +337,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `364` // Estimated: `112338` - // Minimum execution time: 21_920 nanoseconds. - Weight::from_parts(22_172_000, 112338) + // Minimum execution time: 23_008 nanoseconds. + Weight::from_parts(23_767_000, 112338) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -345,8 +350,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `412` // Estimated: `112338` - // Minimum execution time: 22_094 nanoseconds. - Weight::from_parts(22_314_000, 112338) + // Minimum execution time: 23_550 nanoseconds. + Weight::from_parts(24_081_000, 112338) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -356,8 +361,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `310` // Estimated: `2841` - // Minimum execution time: 15_696 nanoseconds. - Weight::from_parts(15_964_000, 2841) + // Minimum execution time: 15_850 nanoseconds. + Weight::from_parts(16_773_000, 2841) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -371,8 +376,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `412` // Estimated: `114827` - // Minimum execution time: 30_604 nanoseconds. - Weight::from_parts(31_126_000, 114827) + // Minimum execution time: 32_126 nanoseconds. + Weight::from_parts(33_313_000, 114827) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -386,8 +391,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `412` // Estimated: `114827` - // Minimum execution time: 32_961 nanoseconds. - Weight::from_parts(33_295_000, 114827) + // Minimum execution time: 34_698 nanoseconds. + Weight::from_parts(35_802_000, 114827) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -399,8 +404,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `465` // Estimated: `112338` - // Minimum execution time: 27_072 nanoseconds. - Weight::from_parts(27_405_000, 112338) + // Minimum execution time: 28_710 nanoseconds. + Weight::from_parts(29_574_000, 112338) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -412,8 +417,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `448` // Estimated: `112338` - // Minimum execution time: 27_056 nanoseconds. - Weight::from_parts(27_768_000, 112338) + // Minimum execution time: 29_030 nanoseconds. + Weight::from_parts(30_308_000, 112338) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -425,8 +430,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `465` // Estimated: `112338` - // Minimum execution time: 24_599 nanoseconds. - Weight::from_parts(25_170_000, 112338) + // Minimum execution time: 26_382 nanoseconds. + Weight::from_parts(27_219_000, 112338) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -438,8 +443,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `469` // Estimated: `112338` - // Minimum execution time: 23_737 nanoseconds. - Weight::from_parts(24_184_000, 112338) + // Minimum execution time: 25_445 nanoseconds. + Weight::from_parts(26_010_000, 112338) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -453,8 +458,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `469` // Estimated: `224358` - // Minimum execution time: 37_880 nanoseconds. - Weight::from_parts(38_537_000, 224358) + // Minimum execution time: 41_064 nanoseconds. + Weight::from_parts(42_895_000, 224358) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -466,11 +471,39 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `465` // Estimated: `112338` - // Minimum execution time: 26_898 nanoseconds. - Weight::from_parts(27_496_000, 112338) + // Minimum execution time: 29_472 nanoseconds. + Weight::from_parts(30_011_000, 112338) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } + /// Storage: Referenda ReferendumInfoFor (r:1 w:0) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Preimage StatusFor (r:1 w:0) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Referenda MetadataOf (r:0 w:1) + /// Proof: Referenda MetadataOf (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + fn set_some_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `454` + // Estimated: `5407` + // Minimum execution time: 19_389 nanoseconds. + Weight::from_parts(20_490_000, 5407) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Referenda ReferendumInfoFor (r:1 w:0) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Referenda MetadataOf (r:1 w:1) + /// Proof: Referenda MetadataOf (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + fn clear_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `387` + // Estimated: `5368` + // Minimum execution time: 18_195 nanoseconds. + Weight::from_parts(19_917_000, 5368) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } } // For backwards compatibility and tests @@ -485,8 +518,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `251` // Estimated: `109996` - // Minimum execution time: 32_207 nanoseconds. - Weight::from_parts(32_639_000, 109996) + // Minimum execution time: 34_540 nanoseconds. + Weight::from_parts(36_144_000, 109996) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -498,8 +531,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `536` // Estimated: `221835` - // Minimum execution time: 43_766 nanoseconds. - Weight::from_parts(44_494_000, 221835) + // Minimum execution time: 46_963 nanoseconds. + Weight::from_parts(48_459_000, 221835) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -513,8 +546,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `3203` // Estimated: `9817` - // Minimum execution time: 41_561 nanoseconds. - Weight::from_parts(42_180_000, 9817) + // Minimum execution time: 55_798 nanoseconds. + Weight::from_parts(58_260_000, 9817) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -528,8 +561,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `3223` // Estimated: `9817` - // Minimum execution time: 41_039 nanoseconds. - Weight::from_parts(41_673_000, 9817) + // Minimum execution time: 53_888 nanoseconds. + Weight::from_parts(57_919_000, 9817) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -543,8 +576,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `536` // Estimated: `224324` - // Minimum execution time: 52_922 nanoseconds. - Weight::from_parts(53_395_000, 224324) + // Minimum execution time: 56_121 nanoseconds. + Weight::from_parts(58_301_000, 224324) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -558,8 +591,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `536` // Estimated: `224324` - // Minimum execution time: 51_050 nanoseconds. - Weight::from_parts(51_736_000, 224324) + // Minimum execution time: 54_237 nanoseconds. + Weight::from_parts(55_681_000, 224324) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -569,8 +602,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `415` // Estimated: `2841` - // Minimum execution time: 24_102 nanoseconds. - Weight::from_parts(24_372_000, 2841) + // Minimum execution time: 25_734 nanoseconds. + Weight::from_parts(26_429_000, 2841) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -580,8 +613,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `405` // Estimated: `2841` - // Minimum execution time: 24_162 nanoseconds. - Weight::from_parts(24_547_000, 2841) + // Minimum execution time: 26_000 nanoseconds. + Weight::from_parts(26_786_000, 2841) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -593,8 +626,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `412` // Estimated: `221835` - // Minimum execution time: 32_247 nanoseconds. - Weight::from_parts(32_731_000, 221835) + // Minimum execution time: 34_567 nanoseconds. + Weight::from_parts(35_939_000, 221835) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -602,13 +635,15 @@ impl WeightInfo for () { /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) /// Storage: Scheduler Agenda (r:2 w:2) /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: Referenda MetadataOf (r:1 w:0) + /// Proof: Referenda MetadataOf (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) fn kill() -> Weight { // Proof Size summary in bytes: // Measured: `717` - // Estimated: `221835` - // Minimum execution time: 59_900 nanoseconds. - Weight::from_parts(60_659_000, 221835) - .saturating_add(RocksDbWeight::get().reads(3_u64)) + // Estimated: `224362` + // Minimum execution time: 67_744 nanoseconds. + Weight::from_parts(70_047_000, 224362) + .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: Referenda TrackQueue (r:1 w:0) @@ -619,8 +654,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `174` // Estimated: `6976` - // Minimum execution time: 9_322 nanoseconds. - Weight::from_parts(9_638_000, 6976) + // Minimum execution time: 9_886 nanoseconds. + Weight::from_parts(10_406_000, 6976) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -634,8 +669,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `4661` // Estimated: `226322` - // Minimum execution time: 76_976 nanoseconds. - Weight::from_parts(77_597_000, 226322) + // Minimum execution time: 100_449 nanoseconds. + Weight::from_parts(101_812_000, 226322) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -649,8 +684,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `4661` // Estimated: `226322` - // Minimum execution time: 78_405 nanoseconds. - Weight::from_parts(78_972_000, 226322) + // Minimum execution time: 101_430 nanoseconds. + Weight::from_parts(103_704_000, 226322) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -664,8 +699,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `4682` // Estimated: `116825` - // Minimum execution time: 51_360 nanoseconds. - Weight::from_parts(51_737_000, 116825) + // Minimum execution time: 67_224 nanoseconds. + Weight::from_parts(70_596_000, 116825) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -679,8 +714,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `4668` // Estimated: `116825` - // Minimum execution time: 50_485 nanoseconds. - Weight::from_parts(51_601_000, 116825) + // Minimum execution time: 65_461 nanoseconds. + Weight::from_parts(69_624_000, 116825) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -696,8 +731,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `4642` // Estimated: `119314` - // Minimum execution time: 53_075 nanoseconds. - Weight::from_parts(54_014_000, 119314) + // Minimum execution time: 69_848 nanoseconds. + Weight::from_parts(74_480_000, 119314) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -713,8 +748,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `4676` // Estimated: `119314` - // Minimum execution time: 52_916 nanoseconds. - Weight::from_parts(53_716_000, 119314) + // Minimum execution time: 70_042 nanoseconds. + Weight::from_parts(72_912_000, 119314) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -726,8 +761,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `364` // Estimated: `112338` - // Minimum execution time: 21_920 nanoseconds. - Weight::from_parts(22_172_000, 112338) + // Minimum execution time: 23_008 nanoseconds. + Weight::from_parts(23_767_000, 112338) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -739,8 +774,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `412` // Estimated: `112338` - // Minimum execution time: 22_094 nanoseconds. - Weight::from_parts(22_314_000, 112338) + // Minimum execution time: 23_550 nanoseconds. + Weight::from_parts(24_081_000, 112338) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -750,8 +785,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `310` // Estimated: `2841` - // Minimum execution time: 15_696 nanoseconds. - Weight::from_parts(15_964_000, 2841) + // Minimum execution time: 15_850 nanoseconds. + Weight::from_parts(16_773_000, 2841) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -765,8 +800,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `412` // Estimated: `114827` - // Minimum execution time: 30_604 nanoseconds. - Weight::from_parts(31_126_000, 114827) + // Minimum execution time: 32_126 nanoseconds. + Weight::from_parts(33_313_000, 114827) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -780,8 +815,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `412` // Estimated: `114827` - // Minimum execution time: 32_961 nanoseconds. - Weight::from_parts(33_295_000, 114827) + // Minimum execution time: 34_698 nanoseconds. + Weight::from_parts(35_802_000, 114827) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -793,8 +828,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `465` // Estimated: `112338` - // Minimum execution time: 27_072 nanoseconds. - Weight::from_parts(27_405_000, 112338) + // Minimum execution time: 28_710 nanoseconds. + Weight::from_parts(29_574_000, 112338) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -806,8 +841,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `448` // Estimated: `112338` - // Minimum execution time: 27_056 nanoseconds. - Weight::from_parts(27_768_000, 112338) + // Minimum execution time: 29_030 nanoseconds. + Weight::from_parts(30_308_000, 112338) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -819,8 +854,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `465` // Estimated: `112338` - // Minimum execution time: 24_599 nanoseconds. - Weight::from_parts(25_170_000, 112338) + // Minimum execution time: 26_382 nanoseconds. + Weight::from_parts(27_219_000, 112338) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -832,8 +867,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `469` // Estimated: `112338` - // Minimum execution time: 23_737 nanoseconds. - Weight::from_parts(24_184_000, 112338) + // Minimum execution time: 25_445 nanoseconds. + Weight::from_parts(26_010_000, 112338) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -847,8 +882,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `469` // Estimated: `224358` - // Minimum execution time: 37_880 nanoseconds. - Weight::from_parts(38_537_000, 224358) + // Minimum execution time: 41_064 nanoseconds. + Weight::from_parts(42_895_000, 224358) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -860,9 +895,37 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `465` // Estimated: `112338` - // Minimum execution time: 26_898 nanoseconds. - Weight::from_parts(27_496_000, 112338) + // Minimum execution time: 29_472 nanoseconds. + Weight::from_parts(30_011_000, 112338) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } + /// Storage: Referenda ReferendumInfoFor (r:1 w:0) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Preimage StatusFor (r:1 w:0) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Referenda MetadataOf (r:0 w:1) + /// Proof: Referenda MetadataOf (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + fn set_some_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `454` + // Estimated: `5407` + // Minimum execution time: 19_389 nanoseconds. + Weight::from_parts(20_490_000, 5407) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Referenda ReferendumInfoFor (r:1 w:0) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Referenda MetadataOf (r:1 w:1) + /// Proof: Referenda MetadataOf (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + fn clear_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `387` + // Estimated: `5368` + // Minimum execution time: 18_195 nanoseconds. + Weight::from_parts(19_917_000, 5368) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } } From 2a636e26e9c200bb77910e4956210bce2bef0e22 Mon Sep 17 00:00:00 2001 From: Aaro Altonen <48052676+altonen@users.noreply.github.com> Date: Wed, 8 Feb 2023 11:04:02 +0200 Subject: [PATCH 373/715] Improve test coverage of the `Notifications` protocol (#13033) * Add handler and upgrade tests * Add tests for `behaviour.rs` * Apply review comments * Update dependencies * Apply suggestions from code review Co-authored-by: Dmitry Markin * Apply review comments * Fix clippy * Update mockall * Apply review comment --------- Co-authored-by: Dmitry Markin --- Cargo.lock | 702 +++-- client/consensus/common/Cargo.toml | 2 +- client/network/Cargo.toml | 4 + .../src/protocol/notifications/behaviour.rs | 2417 +++++++++++++++++ .../src/protocol/notifications/handler.rs | 1015 ++++++- .../src/protocol/notifications/upgrade.rs | 4 +- .../protocol/notifications/upgrade/collec.rs | 80 +- .../notifications/upgrade/notifications.rs | 18 +- client/network/sync/Cargo.toml | 2 +- 9 files changed, 3773 insertions(+), 471 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c870fb0a930ac..3e5ab65c0ce20 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -27,7 +27,7 @@ version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" dependencies = [ - "gimli 0.27.0", + "gimli 0.27.1", ] [[package]] @@ -139,9 +139,9 @@ dependencies = [ [[package]] name = "ahash" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf6ccdb167abbf410dcb915cabd428929d7f6a04980b54a11f26a39f1c7f7107" +checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" dependencies = [ "cfg-if", "getrandom 0.2.8", @@ -184,9 +184,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.68" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61" +checksum = "224afbd727c3d6e4b90103ece64b8d1b67fbb1973b1046c2281eed3f3803f800" [[package]] name = "approx" @@ -199,9 +199,9 @@ dependencies = [ [[package]] name = "arbitrary" -version = "1.2.0" +version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29d47fbf90d5149a107494b15a7dc8d69b351be2db3bb9691740e88ec17fd880" +checksum = "3e90af4de65aa7b293ef2d09daff88501eb254f58edde2e1ac02c82d873eadad" [[package]] name = "arc-swap" @@ -308,11 +308,11 @@ checksum = "e22d1f4b888c298a027c99dc9048015fac177587de20fc30232a057dfbe24a21" [[package]] name = "assert_cmd" -version = "2.0.7" +version = "2.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa3d466004a8b4cb1bc34044240a2fd29d17607e2e3bd613eb44fd48e8100da3" +checksum = "9834fcc22e0874394a010230586367d4a3e9f11b560f469262678547e1d2575e" dependencies = [ - "bstr 1.1.0", + "bstr", "doc-comment", "predicates", "predicates-core", @@ -379,9 +379,9 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.60" +version = "0.1.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d1d8ab452a3936018a687b20e6f7cf5363d713b732b8884001317b0e48aa3" +checksum = "1cd7fce9ba8c3c042128ce72d8b2ddbf3a05747efb67ea0313c635e10bda47a2" dependencies = [ "proc-macro2", "quote", @@ -403,9 +403,9 @@ dependencies = [ [[package]] name = "atomic-waker" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "065374052e7df7ee4047b1160cca5e1467a12351a40b3da123c870ba0b8eda2a" +checksum = "debc29dde2e69f9e47506b525f639ed42300fc014a3e007832592448fa8e4599" [[package]] name = "atty" @@ -435,7 +435,7 @@ dependencies = [ "cfg-if", "libc", "miniz_oxide", - "object 0.30.0", + "object 0.30.3", "rustc-demangle", ] @@ -463,12 +463,27 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" +[[package]] +name = "base64" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" + [[package]] name = "base64ct" version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b645a089122eccb6111b4f81cbc1a49f5900ac4666bb93ac027feaecf15607bf" +[[package]] +name = "basic-toml" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e819b667739967cd44d308b8c7b71305d8bb0729ac44a248aa08f33d01950b4" +dependencies = [ + "serde", +] + [[package]] name = "beef" version = "0.5.2" @@ -546,7 +561,7 @@ name = "binary-merkle-tree" version = "4.0.0-dev" dependencies = [ "array-bytes", - "env_logger", + "env_logger 0.9.3", "hash-db", "log", "sp-core", @@ -718,18 +733,9 @@ checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" [[package]] name = "bstr" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" -dependencies = [ - "memchr", -] - -[[package]] -name = "bstr" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45ea9b00a7b3f2988e9a65ad3917e62123c38dba709b666506207be96d1790b" +checksum = "b7f0778972c64420fdedc63f09919c8a88bda7b25135357fd25a5d9f3257e832" dependencies = [ "memchr", "once_cell", @@ -748,9 +754,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.11.1" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" [[package]] name = "byte-slice-cast" @@ -778,9 +784,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" [[package]] name = "bzip2-sys" @@ -795,9 +801,9 @@ dependencies = [ [[package]] name = "camino" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ad0e1e3e88dd237a156ab9f571021b8a158caa0ae44b1968a241efb5144c1e" +checksum = "c77df041dc383319cc661b428b6961a005db4d6808d5e12536931b1ca9556055" dependencies = [ "serde", ] @@ -813,9 +819,9 @@ dependencies = [ [[package]] name = "cargo_metadata" -version = "0.15.2" +version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "982a0cf6a99c350d7246035613882e376d58cebe571785abc5da4f648d53ac0a" +checksum = "08a1ec454bc3eead8719cb56e15dbbfecdbc14e4b3a3ae4936cc6e31f5fc0d07" dependencies = [ "camino", "cargo-platform", @@ -833,9 +839,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.0.78" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" dependencies = [ "jobserver", ] @@ -911,7 +917,7 @@ name = "chain-spec-builder" version = "2.0.0" dependencies = [ "ansi_term", - "clap 4.0.32", + "clap 4.1.4", "node-cli", "rand 0.8.5", "sc-chain-spec", @@ -1027,13 +1033,13 @@ dependencies = [ [[package]] name = "clap" -version = "4.0.32" +version = "4.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7db700bc935f9e43e88d00b0850dae18a63773cfbec6d8e070fccf7fef89a39" +checksum = "f13b9c79b5d1dd500d20ef541215a6423c75829ef43117e1b4d17fd8af0b5d76" dependencies = [ "bitflags", "clap_derive", - "clap_lex 0.3.0", + "clap_lex 0.3.1", "is-terminal", "once_cell", "strsim", @@ -1042,18 +1048,18 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.0.7" +version = "4.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10861370d2ba66b0f5989f83ebf35db6421713fd92351790e7fdd6c36774c56b" +checksum = "3d6540eedc41f8a5a76cf3d8d458057dcdf817be4158a55b5f861f7a5483de75" dependencies = [ - "clap 4.0.32", + "clap 4.1.4", ] [[package]] name = "clap_derive" -version = "4.0.21" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0177313f9f02afc995627906bbd8967e2be069f5261954222dac78290c2b9014" +checksum = "684a277d672e91966334af371f1a7b5833f9aa00b07c84e92fbce95e00208ce8" dependencies = [ "heck", "proc-macro-error", @@ -1073,9 +1079,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8" +checksum = "783fe232adfca04f90f56201b26d79682d4cd2625e0bc7290b95123afe558ade" dependencies = [ "os_str_bytes", ] @@ -1103,9 +1109,9 @@ dependencies = [ [[package]] name = "concurrent-queue" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd7bef69dc86e3c610e4e7aed41035e2a7ed12e72dd7530f61327a6579a4390b" +checksum = "c278839b831783b70278b14df4d45e1beb1aad306c07bb796637de9a0e323e8e" dependencies = [ "crossbeam-utils", ] @@ -1278,18 +1284,18 @@ dependencies = [ [[package]] name = "crc" -version = "3.0.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53757d12b596c16c78b83458d732a5d1a17ab3f53f2f7412f6fb57cc8a140ab3" +checksum = "86ec7a15cbe22e59248fc7eadb1907dab5ba09372595da4d73dd805ed4417dfe" dependencies = [ "crc-catalog", ] [[package]] name = "crc-catalog" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d0165d2900ae6778e36e80bbc4da3b5eefccee9ba939761f9c2882a5d9af3ff" +checksum = "9cace84e55f07e7301bae1c519df89cdad8cc3cd868413d3fdbdeca9ff3db484" [[package]] name = "crc32fast" @@ -1495,9 +1501,9 @@ dependencies = [ [[package]] name = "curve25519-dalek" -version = "4.0.0-pre.5" +version = "4.0.0-rc.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67bc65846be335cb20f4e52d49a437b773a2c1fdb42b19fc84e79e6f6771536f" +checksum = "8da00a7a9a4eb92a0a0f8e75660926d48f0d0f3c537e455c457bcdaa1e16b1ac" dependencies = [ "cfg-if", "fiat-crypto", @@ -1509,9 +1515,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.85" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5add3fc1717409d029b20c5b6903fc0c0b02fa6741d820054f4a2efa5e5816fd" +checksum = "bc831ee6a32dd495436e317595e639a587aa9907bef96fe6e6abc290ab6204e9" dependencies = [ "cc", "cxxbridge-flags", @@ -1521,9 +1527,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.85" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4c87959ba14bc6fbc61df77c3fcfe180fc32b93538c4f1031dd802ccb5f2ff0" +checksum = "94331d54f1b1a8895cd81049f7eaaaef9d05a7dcb4d1fd08bf3ff0806246789d" dependencies = [ "cc", "codespan-reporting", @@ -1536,15 +1542,15 @@ dependencies = [ [[package]] name = "cxxbridge-flags" -version = "1.0.85" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69a3e162fde4e594ed2b07d0f83c6c67b745e7f28ce58c6df5e6b6bef99dfb59" +checksum = "48dcd35ba14ca9b40d6e4b4b39961f23d835dbb8eed74565ded361d93e1feb8a" [[package]] name = "cxxbridge-macro" -version = "1.0.85" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e7e2adeb6a0d4a282e581096b06e1791532b7d576dcde5ccd9382acf55db8e6" +checksum = "81bbeb29798b407ccd82a3324ade1a7286e0d29851475990b612670f6f5124d2" dependencies = [ "proc-macro2", "quote", @@ -1553,9 +1559,9 @@ dependencies = [ [[package]] name = "darling" -version = "0.14.2" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0dd3cd20dc6b5a876612a6e5accfe7f3dd883db6d07acfbf14c128f61550dfa" +checksum = "c0808e1bd8671fb44a113a14e13497557533369847788fa2ae912b6ebfce9fa8" dependencies = [ "darling_core", "darling_macro", @@ -1563,9 +1569,9 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.14.2" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a784d2ccaf7c98501746bf0be29b2022ba41fd62a2e622af997a03e9f972859f" +checksum = "001d80444f28e193f30c2f293455da62dcf9a6b29918a4253152ae2b1de592cb" dependencies = [ "fnv", "ident_case", @@ -1577,9 +1583,9 @@ dependencies = [ [[package]] name = "darling_macro" -version = "0.14.2" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7618812407e9402654622dd402b0a89dff9ba93badd6540781526117b92aab7e" +checksum = "b36230598a2d5de7ec1c6f51f72d8a99a9208daff41de2084d06e3fd3ea56685" dependencies = [ "darling_core", "quote", @@ -1799,9 +1805,9 @@ dependencies = [ [[package]] name = "dissimilar" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd5f0c7e4bd266b8ab2550e6238d2e74977c23c15536ac7be45e9c95e2e3fbbb" +checksum = "210ec60ae7d710bed8683e333e9d2855a8a56a3e9892b38bad3bb0d4d29b0d5e" [[package]] name = "doc-comment" @@ -1868,9 +1874,9 @@ dependencies = [ [[package]] name = "ed25519" -version = "1.5.2" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9c280362032ea4203659fc489832d0204ef09f247a0506f170dafcac08c369" +checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" dependencies = [ "signature", ] @@ -1905,9 +1911,9 @@ dependencies = [ [[package]] name = "either" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" [[package]] name = "elliptic-curve" @@ -1976,6 +1982,19 @@ dependencies = [ "termcolor", ] +[[package]] +name = "env_logger" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" +dependencies = [ + "humantime", + "is-terminal", + "log", + "regex", + "termcolor", +] + [[package]] name = "environmental" version = "1.1.4" @@ -2066,11 +2085,11 @@ checksum = "a214f5bb88731d436478f3ae1f8a277b62124089ba9fb67f4f93fb100ef73c90" [[package]] name = "file-per-thread-logger" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21e16290574b39ee41c71aeb90ae960c504ebaf1e2a1c87bd52aa56ed6e1a02f" +checksum = "84f2e425d9790201ba4af4630191feac6dcc98765b118d4d18e91d23c2353866" dependencies = [ - "env_logger", + "env_logger 0.10.0", "log", ] @@ -2203,7 +2222,7 @@ dependencies = [ "Inflector", "array-bytes", "chrono", - "clap 4.0.32", + "clap 4.1.4", "comfy-table", "frame-benchmarking", "frame-support", @@ -2294,7 +2313,7 @@ dependencies = [ name = "frame-election-solution-type-fuzzer" version = "2.0.0-alpha.5" dependencies = [ - "clap 4.0.32", + "clap 4.1.4", "frame-election-provider-solution-type", "frame-election-provider-support", "frame-support", @@ -2539,9 +2558,9 @@ dependencies = [ [[package]] name = "fs_extra" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" [[package]] name = "funty" @@ -2551,9 +2570,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38390104763dc37a5145a53c29c63c1290b5d316d6086ec32c293f6736051bb0" +checksum = "13e2792b0ff0340399d58445b88fd9770e3489eff258a4cbc1523418f12abf84" dependencies = [ "futures-channel", "futures-core", @@ -2566,9 +2585,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed" +checksum = "2e5317663a9089767a1ec00a487df42e0ca174b61b4483213ac24448e4664df5" dependencies = [ "futures-core", "futures-sink", @@ -2576,15 +2595,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac" +checksum = "ec90ff4d0fe1f57d600049061dc6bb68ed03c7d2fbd697274c41805dcb3f8608" [[package]] name = "futures-executor" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7acc85df6714c176ab5edf386123fafe217be88c0840ec11f199441134a074e2" +checksum = "e8de0a35a6ab97ec8869e32a2473f4b1324459e14c29275d14b10cb1fd19b50e" dependencies = [ "futures-core", "futures-task", @@ -2594,9 +2613,9 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb" +checksum = "bfb8371b6fb2aeb2d280374607aeabfc99d95c72edfe51692e42d3d7f0d08531" [[package]] name = "futures-lite" @@ -2615,9 +2634,9 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d" +checksum = "95a73af87da33b5acf53acfebdc339fe592ecf5357ac7c0a7734ab9d8c876a70" dependencies = [ "proc-macro2", "quote", @@ -2631,21 +2650,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2411eed028cdf8c8034eaf21f9915f956b6c3abec4d4c7949ee67f0721127bd" dependencies = [ "futures-io", - "rustls 0.20.7", + "rustls 0.20.8", "webpki 0.22.0", ] [[package]] name = "futures-sink" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9" +checksum = "f310820bb3e8cfd46c80db4d7fb8353e15dfff853a127158425f31e0be6c8364" [[package]] name = "futures-task" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea" +checksum = "dcf79a1bf610b10f42aea489289c5a2c478a786509693b80cd39c44ccd936366" [[package]] name = "futures-timer" @@ -2655,9 +2674,9 @@ checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" [[package]] name = "futures-util" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6" +checksum = "9c1d6de3acfef38d2be4b1f543f553131788603495be83da675e180c8d6b7bd1" dependencies = [ "futures-channel", "futures-core", @@ -2777,15 +2796,15 @@ dependencies = [ [[package]] name = "gimli" -version = "0.27.0" +version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dec7af912d60cdbd3677c1af9352ebae6fb8394d165568a2234df0fa00f87793" +checksum = "221996f774192f0f718773def8201c4ae31f02616a54ccfc2d358bb0e5cefdec" [[package]] name = "git2" -version = "0.16.0" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be36bc9e0546df253c0cc41fd0af34f5e92845ad8509462ec76672fac6997f5b" +checksum = "ccf7f68c2995f392c49fffb4f95ae2c873297830eb25c6bc4c114ce8f4562acc" dependencies = [ "bitflags", "libc", @@ -2796,18 +2815,18 @@ dependencies = [ [[package]] name = "glob" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "globset" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a1e17342619edbc21a964c2afbeb6c820c6a2560032872f397bb97ea127bd0a" +checksum = "029d74589adefde59de1a0c4f4732695c32805624aec7b68d91503d4dba79afc" dependencies = [ "aho-corasick", - "bstr 0.2.17", + "bstr", "fnv", "log", "regex", @@ -2895,9 +2914,9 @@ checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" [[package]] name = "heck" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" @@ -2917,6 +2936,12 @@ dependencies = [ "libc", ] +[[package]] +name = "hermit-abi" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "856b5cb0902c2b6d65d5fd97dfa30f9b70c7538e770b98eab5ed52d8db923e01" + [[package]] name = "hex" version = "0.4.3" @@ -3053,9 +3078,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.23" +version = "0.14.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "034711faac9d2166cb1baf1a2fb0b60b1f277f8492fd72176c17f3515e1abd3c" +checksum = "5e011372fa0b68db8350aa7a248930ecc7839bf46d8485577d69f117a75f164c" dependencies = [ "bytes", "futures-channel", @@ -3084,7 +3109,7 @@ dependencies = [ "http", "hyper", "log", - "rustls 0.20.7", + "rustls 0.20.8", "rustls-native-certs", "tokio", "tokio-rustls", @@ -3255,12 +3280,12 @@ dependencies = [ [[package]] name = "io-lifetimes" -version = "1.0.3" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46112a93252b123d31a119a8d1a1ac19deac4fac6e0e8b0df58f0d4e5870e63c" +checksum = "1abeb7a0dd0f8181267ff8adc397075586500b81b28a73e8a0208b00fc170fb3" dependencies = [ "libc", - "windows-sys 0.42.0", + "windows-sys 0.45.0", ] [[package]] @@ -3283,20 +3308,20 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.7.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11b0d96e660696543b251e58030cf9787df56da39dab19ad60eae7353040917e" +checksum = "30e22bd8629359895450b59ea7a776c850561b96a3b1d31321c1949d9e6c9146" [[package]] name = "is-terminal" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189" +checksum = "22e18b0a45d56fe973d6db23972bf5bc46f988a4a2385deac9cc29572f09daef" dependencies = [ - "hermit-abi 0.2.6", + "hermit-abi 0.3.0", "io-lifetimes", "rustix", - "windows-sys 0.42.0", + "windows-sys 0.45.0", ] [[package]] @@ -3325,9 +3350,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.60" +version = "0.3.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" +checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" dependencies = [ "wasm-bindgen", ] @@ -3643,9 +3668,9 @@ checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" [[package]] name = "libgit2-sys" -version = "0.14.1+1.5.0" +version = "0.14.2+1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a07fb2692bc3593bda59de45a502bb3071659f2c515e28c71e728306b038e17" +checksum = "7f3d95f6b51075fe9810a7ae22c7095f12b98005ab364d8544797a825ce946a4" dependencies = [ "cc", "libc", @@ -3913,7 +3938,7 @@ dependencies = [ "parking_lot 0.12.1", "quinn-proto", "rand 0.8.5", - "rustls 0.20.7", + "rustls 0.20.8", "thiserror", "tokio", ] @@ -3996,7 +4021,7 @@ dependencies = [ "libp2p-core", "rcgen 0.10.0", "ring", - "rustls 0.20.7", + "rustls 0.20.8", "thiserror", "webpki 0.22.0", "x509-parser 0.14.0", @@ -4103,7 +4128,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95b09eff1b35ed3b33b877ced3a691fc7a481919c7e29c53c906226fcf55e2a1" dependencies = [ "arrayref", - "base64", + "base64 0.13.1", "digest 0.9.0", "hmac-drbg", "libsecp256k1-core", @@ -4305,9 +4330,9 @@ dependencies = [ [[package]] name = "matches" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" +checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" [[package]] name = "matrixmultiply" @@ -4538,9 +4563,9 @@ dependencies = [ [[package]] name = "multihash-derive" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc076939022111618a5026d3be019fd8b366e76314538ff9a1b59ffbcbf98bcd" +checksum = "1d6d4752e6230d8ef7adf7bd5d8c4b1f6561c1014c5ba9a37445ccefe18aa1db" dependencies = [ "proc-macro-crate", "proc-macro-error", @@ -4634,9 +4659,9 @@ dependencies = [ [[package]] name = "netlink-packet-utils" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25af9cf0dc55498b7bd94a1508af7a78706aa0ab715a73c5169273e03c84845e" +checksum = "0ede8a08c71ad5a95cdd0e4e52facd37190977039a4704eb82a283f713747d34" dependencies = [ "anyhow", "byteorder", @@ -4661,9 +4686,9 @@ dependencies = [ [[package]] name = "netlink-sys" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92b654097027250401127914afb37cb1f311df6610a9891ff07a757e94199027" +checksum = "260e21fbb6f3d253a14df90eb0000a6066780a15dd901a7519ce02d77a94985b" dependencies = [ "bytes", "futures", @@ -4686,9 +4711,9 @@ dependencies = [ [[package]] name = "nix" -version = "0.26.1" +version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46a58d1d356c6597d08cde02c2f09d785b09e28711837b1ed667dc652c08a694" +checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" dependencies = [ "bitflags", "cfg-if", @@ -4703,7 +4728,7 @@ name = "node-bench" version = "0.9.0-dev" dependencies = [ "array-bytes", - "clap 4.0.32", + "clap 4.1.4", "derive_more", "fs_extra", "futures", @@ -4740,7 +4765,7 @@ version = "3.0.0-dev" dependencies = [ "array-bytes", "assert_cmd", - "clap 4.0.32", + "clap 4.1.4", "clap_complete", "criterion", "frame-benchmarking-cli", @@ -4750,7 +4775,7 @@ dependencies = [ "jsonrpsee", "kitchensink-runtime", "log", - "nix 0.26.1", + "nix 0.26.2", "node-executor", "node-inspect", "node-primitives", @@ -4859,7 +4884,7 @@ dependencies = [ name = "node-inspect" version = "0.9.0-dev" dependencies = [ - "clap 4.0.32", + "clap 4.1.4", "parity-scale-codec", "sc-cli", "sc-client-api", @@ -4918,7 +4943,7 @@ dependencies = [ name = "node-runtime-generate-bags" version = "3.0.0" dependencies = [ - "clap 4.0.32", + "clap 4.1.4", "generate-bags", "kitchensink-runtime", ] @@ -4927,7 +4952,7 @@ dependencies = [ name = "node-template" version = "4.0.0-dev" dependencies = [ - "clap 4.0.32", + "clap 4.1.4", "frame-benchmarking", "frame-benchmarking-cli", "frame-system", @@ -5046,9 +5071,9 @@ checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" [[package]] name = "nom" -version = "7.1.2" +version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5507769c4919c998e69e49c839d9dc6e693ede4cc4290d6ad8b41d4f09c548c" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" dependencies = [ "memchr", "minimal-lexical", @@ -5083,9 +5108,9 @@ dependencies = [ [[package]] name = "num-complex" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ae39348c8bc5fbd7f40c727a9925f03517afd2ab27d46702108b6a7e5414c19" +checksum = "02e0d21255c828d6f128a1e41534206671e8c3ea0c62f32291e808dc82cff17d" dependencies = [ "num-traits", ] @@ -5156,9 +5181,9 @@ dependencies = [ [[package]] name = "object" -version = "0.30.0" +version = "0.30.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "239da7f290cfa979f43f85a8efeee9a8a76d0827c356d37f9d3d7254d6b537fb" +checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439" dependencies = [ "memchr", ] @@ -5582,7 +5607,7 @@ dependencies = [ "array-bytes", "assert_matches", "bitflags", - "env_logger", + "env_logger 0.9.3", "frame-benchmarking", "frame-support", "frame-system", @@ -5947,7 +5972,7 @@ name = "pallet-mmr" version = "4.0.0-dev" dependencies = [ "array-bytes", - "env_logger", + "env_logger 0.9.3", "frame-benchmarking", "frame-support", "frame-system", @@ -6787,7 +6812,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", - "parking_lot_core 0.9.5", + "parking_lot_core 0.9.7", ] [[package]] @@ -6806,15 +6831,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.5" +version = "0.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ff9f3fef3968a3ec5945535ed654cb38ff72d7495a25619e2247fb15a2ed9ba" +checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-sys 0.42.0", + "windows-sys 0.45.0", ] [[package]] @@ -6849,11 +6874,11 @@ checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" [[package]] name = "pem" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c64931a1a212348ec4f3b4362585eca7159d0d09cbdf4a7f74f02173596fd4" +checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8" dependencies = [ - "base64", + "base64 0.13.1", ] [[package]] @@ -6873,9 +6898,9 @@ checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" [[package]] name = "pest" -version = "2.5.2" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f6e86fb9e7026527a0d46bc308b841d73170ef8f443e1807f6ef88526a816d4" +checksum = "4ab62d2fa33726dbe6321cc97ef96d8cde531e3eeaf858a058de53a8a6d40d8f" dependencies = [ "thiserror", "ucd-trie", @@ -6883,9 +6908,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.5.2" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96504449aa860c8dcde14f9fba5c58dc6658688ca1fe363589d6327b8662c603" +checksum = "8bf026e2d0581559db66d837fe5242320f525d85c76283c61f4d51a1238d65ea" dependencies = [ "pest", "pest_generator", @@ -6893,9 +6918,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.5.2" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "798e0220d1111ae63d66cb66a5dcb3fc2d986d520b98e49e1852bfdb11d7c5e7" +checksum = "2b27bd18aa01d91c8ed2b61ea23406a676b42d82609c6e2581fba42f0c15f17f" dependencies = [ "pest", "pest_meta", @@ -6906,20 +6931,20 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.5.2" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "984298b75898e30a843e278a9f2452c31e349a073a0ce6fd950a12a74464e065" +checksum = "9f02b677c1859756359fc9983c2e56a0237f18624a3789528804406b7e915e5d" dependencies = [ "once_cell", "pest", - "sha1", + "sha2 0.10.6", ] [[package]] name = "petgraph" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5014253a1331579ce62aa67443b4a658c5e7dd03d4bc6d302b94474888143" +checksum = "4dd7d28ee937e54fe3080c91faa1c3a46c06de6252988a7f4592ba2310ef22a4" dependencies = [ "fixedbitset", "indexmap", @@ -7117,9 +7142,9 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c8992a85d8e93a28bdf76137db888d3874e3b230dee5ed8bebac4c9f7617773" +checksum = "e97e3215779627f01ee256d2fad52f3d95e8e1c11e9fc6fd08f7cd455d5d5c78" dependencies = [ "proc-macro2", "syn", @@ -7140,11 +7165,10 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "1.2.1" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eda0fc3b0fb7c975631757e14d9049da17374063edb6ebbcbc54d880d4fe94e9" +checksum = "e17d47ce914bf4de440332250b0edd23ce48c005f59fab39d3335866b114f11a" dependencies = [ - "once_cell", "thiserror", "toml", ] @@ -7175,9 +7199,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.50" +version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2" +checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" dependencies = [ "unicode-ident", ] @@ -7221,9 +7245,9 @@ dependencies = [ [[package]] name = "prost" -version = "0.11.5" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c01db6702aa05baa3f57dec92b8eeeeb4cb19e894e73996b32a4093289e54592" +checksum = "21dc42e00223fc37204bd4aa177e69420c604ca4a183209a8f9de30c6d934698" dependencies = [ "bytes", "prost-derive", @@ -7231,9 +7255,9 @@ dependencies = [ [[package]] name = "prost-build" -version = "0.11.5" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb5320c680de74ba083512704acb90fe00f28f79207286a848e730c45dd73ed6" +checksum = "a3f8ad728fb08fe212df3c05169e940fbb6d9d16a877ddde14644a983ba2012e" dependencies = [ "bytes", "heck", @@ -7266,9 +7290,9 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.11.5" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8842bad1a5419bca14eac663ba798f6bc19c413c2fdceb5f3ba3b0932d96720" +checksum = "8bda8c0881ea9f722eb9629376db3d0b903b462477c1aafcb0566610ac28ac5d" dependencies = [ "anyhow", "itertools", @@ -7279,9 +7303,9 @@ dependencies = [ [[package]] name = "prost-types" -version = "0.11.5" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "017f79637768cde62820bc2d4fe0e45daaa027755c323ad077767c6c5f173091" +checksum = "a5e0526209433e96d83d750dd81a99118edbc55739e7e61a46764fd2ad537788" dependencies = [ "bytes", "prost", @@ -7332,7 +7356,7 @@ dependencies = [ "rand 0.8.5", "ring", "rustc-hash", - "rustls 0.20.7", + "rustls 0.20.8", "slab", "thiserror", "tinyvec", @@ -7463,9 +7487,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.10.1" +version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cac410af5d00ab6884528b4ab69d1e8e146e8d471201800fa1b4524126de6ad3" +checksum = "356a0625f1954f730c0201cdab48611198dc6ce21f4acff55089b5a78e6e835b" dependencies = [ "crossbeam-channel", "crossbeam-deque", @@ -7552,9 +7576,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.7.0" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a" +checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" dependencies = [ "aho-corasick", "memchr", @@ -7739,16 +7763,16 @@ dependencies = [ [[package]] name = "rustix" -version = "0.36.6" +version = "0.36.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4feacf7db682c6c329c4ede12649cd36ecab0f3be5b7d74e6a20304725db4549" +checksum = "f43abb88211988493c1abb44a70efa56ff0ce98f233b7b276146f1f3f7ba9644" dependencies = [ "bitflags", "errno", "io-lifetimes", "libc", "linux-raw-sys", - "windows-sys 0.42.0", + "windows-sys 0.45.0", ] [[package]] @@ -7757,7 +7781,7 @@ version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7" dependencies = [ - "base64", + "base64 0.13.1", "log", "ring", "sct 0.6.1", @@ -7766,9 +7790,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.20.7" +version = "0.20.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "539a2bfe908f471bfa933876bd1eb6a19cf2176d375f82ef7f99530a40e48c2c" +checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" dependencies = [ "log", "ring", @@ -7790,11 +7814,11 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0864aeff53f8c05aa08d86e5ef839d3dfcf07aeba2db32f12db0ef716e87bd55" +checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" dependencies = [ - "base64", + "base64 0.21.0", ] [[package]] @@ -7968,7 +7992,7 @@ version = "0.10.0-dev" dependencies = [ "array-bytes", "chrono", - "clap 4.0.32", + "clap 4.1.4", "fdlimit", "futures", "futures-timer", @@ -8305,7 +8329,7 @@ dependencies = [ "array-bytes", "assert_matches", "criterion", - "env_logger", + "env_logger 0.9.3", "lru", "num_cpus", "parity-scale-codec", @@ -8389,7 +8413,7 @@ dependencies = [ name = "sc-finality-grandpa" version = "0.10.0-dev" dependencies = [ - "ahash 0.8.2", + "ahash 0.8.3", "array-bytes", "assert_matches", "async-trait", @@ -8502,6 +8526,8 @@ dependencies = [ "libp2p", "log", "lru", + "mockall", + "multistream-select", "parity-scale-codec", "parking_lot 0.12.1", "pin-project", @@ -8530,6 +8556,7 @@ dependencies = [ "tempfile", "thiserror", "tokio", + "tokio-test", "tokio-util", "unsigned-varint", "zeroize", @@ -8589,7 +8616,7 @@ dependencies = [ name = "sc-network-gossip" version = "0.10.0-dev" dependencies = [ - "ahash 0.8.2", + "ahash 0.8.3", "futures", "futures-timer", "libp2p", @@ -8774,7 +8801,7 @@ name = "sc-rpc" version = "4.0.0-dev" dependencies = [ "assert_matches", - "env_logger", + "env_logger 0.9.3", "futures", "jsonrpsee", "log", @@ -8999,10 +9026,10 @@ dependencies = [ name = "sc-storage-monitor" version = "0.1.0" dependencies = [ - "clap 4.0.32", + "clap 4.1.4", "futures", "log", - "nix 0.26.1", + "nix 0.26.2", "sc-client-db", "sc-utils", "sp-core", @@ -9196,12 +9223,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.20" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2" +checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" dependencies = [ - "lazy_static", - "windows-sys 0.36.1", + "windows-sys 0.42.0", ] [[package]] @@ -9210,7 +9236,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "772575a524feeb803e5b0fcbc6dd9f367e579488197c94c6e4023aad2305774d" dependencies = [ - "ahash 0.8.2", + "ahash 0.8.3", "cfg-if", "hashbrown 0.13.2", ] @@ -9293,9 +9319,9 @@ dependencies = [ [[package]] name = "secp256k1" -version = "0.24.2" +version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9512ffd81e3a3503ed401f79c33168b9148c75038956039166cd750eaa037c3" +checksum = "6b1629c9c557ef9b293568b338dddfc8208c98a18c59d722a9d53f859d9c9b62" dependencies = [ "secp256k1-sys", ] @@ -9320,9 +9346,9 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.7.0" +version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bc1bb97804af6631813c55739f771071e0f2ed33ee20b68c86ec505d906356c" +checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254" dependencies = [ "bitflags", "core-foundation", @@ -9333,9 +9359,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.6.1" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" +checksum = "31c9bb296072e961fcbd8853511dd39c2d8be2deb1e17c6860b1d30732b323b4" dependencies = [ "core-foundation-sys", "libc", @@ -9396,9 +9422,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.91" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883" +checksum = "7434af0dc1cbd59268aa98b4c22c131c0584d2232f6fb166efb993e2832e896a" dependencies = [ "itoa", "ryu", @@ -9418,17 +9444,6 @@ dependencies = [ "opaque-debug 0.3.0", ] -[[package]] -name = "sha1" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest 0.10.6", -] - [[package]] name = "sha2" version = "0.8.2" @@ -9551,14 +9566,14 @@ checksum = "5e9f0ab6ef7eb7353d9119c170a436d1bf248eea575ac42d19d12f4e34130831" [[package]] name = "snow" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "774d05a3edae07ce6d68ea6984f3c05e9bba8927e3dd591e3b479e5b03213d0d" +checksum = "12ba5f4d4ff12bdb6a169ed51b7c48c0e0ac4b0b4b31012b2571e97d78d3201d" dependencies = [ "aes-gcm 0.9.4", "blake2", "chacha20poly1305", - "curve25519-dalek 4.0.0-pre.5", + "curve25519-dalek 4.0.0-rc.0", "rand_core 0.6.4", "ring", "rustc_version 0.4.0", @@ -9582,7 +9597,7 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41d1c5305e39e09653383c2c7244f2f78b3bcae37cf50c64cb4789c9f5096ec2" dependencies = [ - "base64", + "base64 0.13.1", "bytes", "flate2", "futures", @@ -10070,7 +10085,7 @@ dependencies = [ name = "sp-npos-elections-fuzzer" version = "2.0.0-alpha.5" dependencies = [ - "clap 4.0.32", + "clap 4.1.4", "honggfuzz", "parity-scale-codec", "rand 0.8.5", @@ -10342,7 +10357,7 @@ dependencies = [ name = "sp-trie" version = "7.0.0" dependencies = [ - "ahash 0.8.2", + "ahash 0.8.3", "array-bytes", "criterion", "hash-db", @@ -10443,9 +10458,9 @@ dependencies = [ [[package]] name = "ss58-registry" -version = "1.36.0" +version = "1.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d92659e7d18d82b803824a9ba5a6022cff101c3491d027c1c1d8d30e749284" +checksum = "e40c020d72bc0a9c5660bb71e4a6fdef081493583062c474740a7d59f55f0e7b" dependencies = [ "Inflector", "num-format", @@ -10530,7 +10545,7 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7e94b1ec00bad60e6410e058b52f1c66de3dc5fe4d62d09b3e52bb7d3b73e25" dependencies = [ - "base64", + "base64 0.13.1", "crc", "lazy_static", "md-5", @@ -10547,7 +10562,7 @@ dependencies = [ name = "subkey" version = "2.0.2" dependencies = [ - "clap 4.0.32", + "clap 4.1.4", "sc-cli", ] @@ -10575,7 +10590,7 @@ dependencies = [ name = "substrate-frame-cli" version = "4.0.0-dev" dependencies = [ - "clap 4.0.32", + "clap 4.1.4", "frame-support", "frame-system", "sc-cli", @@ -10905,9 +10920,9 @@ dependencies = [ [[package]] name = "termcolor" -version = "1.1.3" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" dependencies = [ "winapi-util", ] @@ -10970,12 +10985,11 @@ dependencies = [ [[package]] name = "tikv-jemalloc-sys" -version = "0.5.2+5.3.0-patched" +version = "0.5.3+5.3.0-patched" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec45c14da997d0925c7835883e4d5c181f196fa142f8c19d7643d1e9af2592c3" +checksum = "a678df20055b43e57ef8cddde41cdfda9a3c1a060b67f4c5836dfb1d78543ba8" dependencies = [ "cc", - "fs_extra", "libc", ] @@ -11066,15 +11080,15 @@ dependencies = [ [[package]] name = "tinyvec_macros" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.23.0" +version = "1.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eab6d665857cc6ca78d6e80303a02cea7a7851e85dfbd77cbdc09bd129f1ef46" +checksum = "c8e00990ebabbe4c14c08aca901caed183ecd5c09562a12c824bb53d3c3fd3af" dependencies = [ "autocfg", "bytes", @@ -11107,7 +11121,7 @@ version = "0.23.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" dependencies = [ - "rustls 0.20.7", + "rustls 0.20.8", "tokio", "webpki 0.22.0", ] @@ -11154,9 +11168,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.5.10" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1333c76748e868a4d9d1017b5ab53171dfd095f70c712fdb4653a406547f598f" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" dependencies = [ "serde", ] @@ -11404,15 +11418,15 @@ dependencies = [ [[package]] name = "try-lock" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" +checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" [[package]] name = "try-runtime-cli" version = "0.10.0-dev" dependencies = [ - "clap 4.0.32", + "clap 4.1.4", "frame-remote-externalities", "frame-try-runtime", "hex", @@ -11441,10 +11455,11 @@ dependencies = [ [[package]] name = "trybuild" -version = "1.0.74" +version = "1.0.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "654bfc024d30963fce210f22f98956407fe8c8365eb85a1fa530f6f8844137ed" +checksum = "a44da5a6f2164c8e14d3bbc0657d69c5966af9f5f6930d4f600b1f5c4a673413" dependencies = [ + "basic-toml", "dissimilar", "glob", "once_cell", @@ -11452,7 +11467,6 @@ dependencies = [ "serde_derive", "serde_json", "termcolor", - "toml", ] [[package]] @@ -11468,7 +11482,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4712ee30d123ec7ae26d1e1b218395a16c87cdbaf4b3925d170d684af62ea5e8" dependencies = [ "async-trait", - "base64", + "base64 0.13.1", "futures", "log", "md-5", @@ -11518,9 +11532,9 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.8" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" +checksum = "d54675592c1dbefd78cbd98db9bacd89886e1ca50692a0692baefffdeb92dd58" [[package]] name = "unicode-ident" @@ -11590,9 +11604,9 @@ dependencies = [ [[package]] name = "uuid" -version = "1.2.2" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "422ee0de9031b5b948b97a8fc04e3aa35230001a722ddd27943e0be31564ce4c" +checksum = "1674845326ee10d37ca60470760d4288a6f80f304007d92e5c53bab78c9cfd79" dependencies = [ "getrandom 0.2.8", ] @@ -11686,9 +11700,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" +checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -11696,9 +11710,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" +checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" dependencies = [ "bumpalo", "log", @@ -11711,9 +11725,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.33" +version = "0.4.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23639446165ca5a5de86ae1d8896b737ae80319560fbaa4c2887b7da6e7ebd7d" +checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454" dependencies = [ "cfg-if", "js-sys", @@ -11723,9 +11737,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" +checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -11733,9 +11747,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" +checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" dependencies = [ "proc-macro2", "quote", @@ -11746,15 +11760,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" +checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" [[package]] name = "wasm-encoder" -version = "0.20.0" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05632e0a66a6ed8cca593c24223aabd6262f256c3693ad9822c315285f010614" +checksum = "9a584273ccc2d9311f1dd19dc3fb26054661fa3e373d53ede5d1144ba07a9acd" dependencies = [ "leb128", ] @@ -11958,7 +11972,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830570847f905b8f6d2ca635c33cf42ce701dd8e4abd7d1806c631f8f06e9e4b" dependencies = [ "anyhow", - "base64", + "base64 0.13.1", "bincode", "directories-next", "file-per-thread-logger", @@ -12095,9 +12109,9 @@ dependencies = [ [[package]] name = "wast" -version = "50.0.0" +version = "52.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2cbb59d4ac799842791fe7e806fa5dbbf6b5554d538e51cc8e176db6ff0ae34" +checksum = "15942180f265280eede7bc38b239e9770031d1821c02d905284216c645316430" dependencies = [ "leb128", "memchr", @@ -12107,18 +12121,18 @@ dependencies = [ [[package]] name = "wat" -version = "1.0.52" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "584aaf7a1ecf4d383bbe1a25eeab0cbb8ff96acc6796707ff65cde48f4632f15" +checksum = "37212100d4cbe6f0f6ff6e707f1e5a5b5b675f0451231ed9e4235e234e127ed3" dependencies = [ "wast", ] [[package]] name = "web-sys" -version = "0.3.60" +version = "0.3.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" +checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" dependencies = [ "js-sys", "wasm-bindgen", @@ -12376,9 +12390,9 @@ dependencies = [ [[package]] name = "which" -version = "4.3.0" +version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c831fbbee9e129a8cf93e7747a82da9d95ba8e16621cae60ec2cdc849bacb7b" +checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269" dependencies = [ "either", "libc", @@ -12447,37 +12461,48 @@ dependencies = [ [[package]] name = "windows-sys" -version = "0.36.1" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" 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", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc 0.42.1", + "windows_i686_gnu 0.42.1", + "windows_i686_msvc 0.42.1", + "windows_x86_64_gnu 0.42.1", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc 0.42.1", ] [[package]] name = "windows-sys" -version = "0.42.0" +version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" dependencies = [ "windows_aarch64_gnullvm", - "windows_aarch64_msvc 0.42.0", - "windows_i686_gnu 0.42.0", - "windows_i686_msvc 0.42.0", - "windows_x86_64_gnu 0.42.0", + "windows_aarch64_msvc 0.42.1", + "windows_i686_gnu 0.42.1", + "windows_i686_msvc 0.42.1", + "windows_x86_64_gnu 0.42.1", "windows_x86_64_gnullvm", - "windows_x86_64_msvc 0.42.0", + "windows_x86_64_msvc 0.42.1", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" +checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" [[package]] name = "windows_aarch64_msvc" @@ -12487,15 +12512,9 @@ checksum = "17cffbe740121affb56fad0fc0e421804adf0ae00891205213b5cecd30db881d" [[package]] name = "windows_aarch64_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" +checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" [[package]] name = "windows_i686_gnu" @@ -12505,15 +12524,9 @@ checksum = "2564fde759adb79129d9b4f54be42b32c89970c18ebf93124ca8870a498688ed" [[package]] name = "windows_i686_gnu" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" - -[[package]] -name = "windows_i686_gnu" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" +checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" [[package]] name = "windows_i686_msvc" @@ -12523,15 +12536,9 @@ checksum = "9cd9d32ba70453522332c14d38814bceeb747d80b3958676007acadd7e166956" [[package]] name = "windows_i686_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" +checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" [[package]] name = "windows_x86_64_gnu" @@ -12541,21 +12548,15 @@ checksum = "cfce6deae227ee8d356d19effc141a509cc503dfd1f850622ec4b0f84428e1f4" [[package]] name = "windows_x86_64_gnu" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" +checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" +checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" [[package]] name = "windows_x86_64_msvc" @@ -12565,15 +12566,9 @@ checksum = "d19538ccc21819d01deaf88d6a17eae6596a12e9aafdbb97916fb49896d89de9" [[package]] name = "windows_x86_64_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" +checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" [[package]] name = "winreg" @@ -12622,7 +12617,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fb9bace5b5589ffead1afb76e43e34cff39cd0f3ce7e170ae0c29e53b88eb1c" dependencies = [ "asn1-rs 0.3.1", - "base64", + "base64 0.13.1", "data-encoding", "der-parser 7.0.0", "lazy_static", @@ -12641,7 +12636,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0ecbeb7b67ce215e40e3cc7f2ff902f94a223acf44995934763467e7b1febc8" dependencies = [ "asn1-rs 0.5.1", - "base64", + "base64 0.13.1", "data-encoding", "der-parser 8.1.0", "lazy_static", @@ -12723,10 +12718,11 @@ dependencies = [ [[package]] name = "zstd-sys" -version = "2.0.4+zstd.1.5.2" +version = "2.0.6+zstd.1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fa202f2ef00074143e219d15b62ffc317d17cc33909feac471c044087cad7b0" +checksum = "68a3f9792c0c3dc6c165840a75f47ae1f4da402c2d006881129579f6597e801b" dependencies = [ "cc", "libc", + "pkg-config", ] diff --git a/client/consensus/common/Cargo.toml b/client/consensus/common/Cargo.toml index 87b052d434e93..d9e80e1e5ce99 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 = "0.50.0" log = "0.4.17" -mockall = "0.11.2" +mockall = "0.11.3" parking_lot = "0.12.1" serde = { version = "1.0", features = ["derive"] } thiserror = "1.0.30" diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index 44a7973b33659..b6b21247128d7 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -28,6 +28,7 @@ ip_network = "0.4.1" libp2p = { version = "0.50.0", features = ["dns", "identify", "kad", "macros", "mdns", "mplex", "noise", "ping", "tcp", "tokio", "yamux", "websocket"] } log = "0.4.17" lru = "0.8.1" +mockall = "0.11.3" parking_lot = "0.12.1" pin-project = "1.0.12" rand = "0.8.5" @@ -52,9 +53,12 @@ sp-runtime = { version = "7.0.0", path = "../../primitives/runtime" } [dev-dependencies] assert_matches = "1.3" +multistream-select = "0.12.1" +rand = "0.8.5" tempfile = "3.1.0" tokio = { version = "1.22.0", features = ["macros"] } tokio-util = { version = "0.7.4", features = ["compat"] } +tokio-test = "0.4.2" 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/src/protocol/notifications/behaviour.rs b/client/network/src/protocol/notifications/behaviour.rs index 2db46867128ac..c546f6b6f2c44 100644 --- a/client/network/src/protocol/notifications/behaviour.rs +++ b/client/network/src/protocol/notifications/behaviour.rs @@ -2111,3 +2111,2420 @@ impl NetworkBehaviour for Notifications { Poll::Pending } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::protocol::notifications::handler::tests::*; + use libp2p::{ + core::ConnectedPoint, + swarm::{behaviour::FromSwarm, AddressRecord}, + }; + use std::{collections::HashSet, iter}; + + impl PartialEq for ConnectionState { + fn eq(&self, other: &ConnectionState) -> bool { + match (self, other) { + (ConnectionState::Closed, ConnectionState::Closed) => true, + (ConnectionState::Closing, ConnectionState::Closing) => true, + (ConnectionState::Opening, ConnectionState::Opening) => true, + (ConnectionState::OpeningThenClosing, ConnectionState::OpeningThenClosing) => true, + (ConnectionState::OpenDesiredByRemote, ConnectionState::OpenDesiredByRemote) => + true, + (ConnectionState::Open(_), ConnectionState::Open(_)) => true, + _ => false, + } + } + } + + #[derive(Clone)] + struct MockPollParams { + peer_id: PeerId, + addr: Multiaddr, + } + + impl PollParameters for MockPollParams { + type SupportedProtocolsIter = std::vec::IntoIter>; + type ListenedAddressesIter = std::vec::IntoIter; + type ExternalAddressesIter = std::vec::IntoIter; + + fn supported_protocols(&self) -> Self::SupportedProtocolsIter { + vec![].into_iter() + } + + fn listened_addresses(&self) -> Self::ListenedAddressesIter { + vec![self.addr.clone()].into_iter() + } + + fn external_addresses(&self) -> Self::ExternalAddressesIter { + vec![].into_iter() + } + + fn local_peer_id(&self) -> &PeerId { + &self.peer_id + } + } + + fn development_notifs() -> (Notifications, sc_peerset::PeersetHandle) { + let (peerset, peerset_handle) = { + let mut sets = Vec::with_capacity(1); + + sets.push(sc_peerset::SetConfig { + in_peers: 25, + out_peers: 25, + bootnodes: Vec::new(), + reserved_nodes: HashSet::new(), + reserved_only: false, + }); + + sc_peerset::Peerset::from_config(sc_peerset::PeersetConfig { sets }) + }; + + ( + Notifications::new( + peerset, + iter::once(ProtocolConfig { + name: "/foo".into(), + fallback_names: Vec::new(), + handshake: vec![1, 2, 3, 4], + max_notification_size: u64::MAX, + }), + ), + peerset_handle, + ) + } + + #[test] + fn update_handshake() { + let (mut notif, _peerset) = development_notifs(); + + let inner = notif.notif_protocols.get_mut(0).unwrap().handshake.read().clone(); + assert_eq!(inner, vec![1, 2, 3, 4]); + + notif.set_notif_protocol_handshake(0.into(), vec![5, 6, 7, 8]); + + let inner = notif.notif_protocols.get_mut(0).unwrap().handshake.read().clone(); + assert_eq!(inner, vec![5, 6, 7, 8]); + } + + #[test] + #[should_panic] + #[cfg(debug_assertions)] + fn update_unknown_handshake() { + let (mut notif, _peerset) = development_notifs(); + + notif.set_notif_protocol_handshake(1337.into(), vec![5, 6, 7, 8]); + } + + #[test] + fn disconnect_backoff_peer() { + let (mut notif, _peerset) = development_notifs(); + + let peer = PeerId::random(); + notif.peers.insert( + (peer, 0.into()), + PeerState::Backoff { timer: DelayId(0), timer_deadline: Instant::now() }, + ); + notif.disconnect_peer(&peer, 0.into()); + + assert!(std::matches!( + notif.peers.get(&(peer, 0.into())), + Some(PeerState::Backoff { timer: DelayId(0), .. }) + )); + } + + #[test] + fn disconnect_pending_request() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + + notif.peers.insert( + (peer, 0.into()), + PeerState::PendingRequest { timer: DelayId(0), timer_deadline: Instant::now() }, + ); + notif.disconnect_peer(&peer, 0.into()); + + assert!(std::matches!( + notif.peers.get(&(peer, 0.into())), + Some(PeerState::PendingRequest { timer: DelayId(0), .. }) + )); + } + + #[test] + fn disconnect_requested_peer() { + let (mut notif, _peerset) = development_notifs(); + + let peer = PeerId::random(); + notif.peers.insert((peer, 0.into()), PeerState::Requested); + notif.disconnect_peer(&peer, 0.into()); + + assert!(std::matches!(notif.peers.get(&(peer, 0.into())), Some(PeerState::Requested))); + } + + #[test] + fn disconnect_disabled_peer() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + notif.peers.insert( + (peer, 0.into()), + PeerState::Disabled { backoff_until: None, connections: SmallVec::new() }, + ); + notif.disconnect_peer(&peer, 0.into()); + + assert!(std::matches!( + notif.peers.get(&(peer, 0.into())), + Some(PeerState::Disabled { backoff_until: None, .. }) + )); + } + + #[test] + fn remote_opens_connection_and_substream() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + + if let Some(&PeerState::Disabled { ref connections, backoff_until: None }) = + notif.peers.get(&(peer, 0.into())) + { + assert_eq!(connections[0], (conn, ConnectionState::Closed)); + } else { + panic!("invalid state"); + } + + // remote opens a substream, verify that peer state is updated to `Incoming` + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + + if let Some(&PeerState::Incoming { ref connections, backoff_until: None }) = + notif.peers.get(&(peer, 0.into())) + { + assert_eq!(connections.len(), 1); + assert_eq!(connections[0], (conn, ConnectionState::OpenDesiredByRemote)); + } else { + panic!("invalid state"); + } + + assert!(std::matches!( + notif.incoming.pop(), + Some(IncomingPeer { alive: true, incoming_id: sc_peerset::IncomingIndex(0), .. }), + )); + } + + #[tokio::test] + async fn disconnect_remote_substream_before_handled_by_peerset() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + notif.disconnect_peer(&peer, 0.into()); + + if let Some(&PeerState::Disabled { ref connections, backoff_until: None }) = + notif.peers.get(&(peer, 0.into())) + { + assert_eq!(connections.len(), 1); + assert_eq!(connections[0], (conn, ConnectionState::Closing)); + } else { + panic!("invalid state"); + } + } + + #[test] + fn peerset_report_connect_backoff() { + let (mut notif, _peerset) = development_notifs(); + let set_id = sc_peerset::SetId::from(0); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // manually add backoff for the entry + // + // there is not straight-forward way of adding backoff to `PeerState::Disabled` + // so manually adjust the value in order to progress on to the next stage. + // This modification together with `ConnectionClosed` will conver the peer + // state into `PeerState::Backoff`. + if let Some(PeerState::Disabled { ref mut backoff_until, .. }) = + notif.peers.get_mut(&(peer, set_id)) + { + *backoff_until = + Some(Instant::now().checked_add(std::time::Duration::from_secs(5)).unwrap()); + } + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + + let timer = if let Some(&PeerState::Backoff { timer_deadline, .. }) = + notif.peers.get(&(peer, set_id)) + { + timer_deadline + } else { + panic!("invalid state"); + }; + + // attempt to connect the backed-off peer and verify that the request is pending + notif.peerset_report_connect(peer, set_id); + + if let Some(&PeerState::PendingRequest { timer_deadline, .. }) = + notif.peers.get(&(peer, set_id)) + { + assert_eq!(timer, timer_deadline); + } else { + panic!("invalid state"); + } + } + + #[test] + fn peerset_connect_incoming() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // remote opens a substream, verify that peer state is updated to `Incoming` + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + + // attempt to connect to the peer and verify that the peer state is `Enabled` + notif.peerset_report_connect(peer, set_id); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Enabled { .. }))); + } + + #[test] + fn peerset_disconnect_disable_pending_enable() { + let (mut notif, _peerset) = development_notifs(); + let set_id = sc_peerset::SetId::from(0); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // manually add backoff for the entry + if let Some(PeerState::Disabled { ref mut backoff_until, .. }) = + notif.peers.get_mut(&(peer, set_id)) + { + *backoff_until = + Some(Instant::now().checked_add(std::time::Duration::from_secs(5)).unwrap()); + } + + // switch state to `DisabledPendingEnable` + notif.peerset_report_connect(peer, set_id); + assert!(std::matches!( + notif.peers.get(&(peer, set_id)), + Some(&PeerState::DisabledPendingEnable { .. }) + )); + + notif.peerset_report_disconnect(peer, set_id); + + if let Some(PeerState::Disabled { backoff_until, .. }) = notif.peers.get(&(peer, set_id)) { + assert!(backoff_until.is_some()); + assert!(backoff_until.unwrap() > Instant::now()); + } else { + panic!("invalid state"); + } + } + + #[test] + fn peerset_disconnect_enabled() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + // Set peer into `Enabled` state. + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + notif.peerset_report_connect(peer, set_id); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Enabled { .. }))); + + // disconnect peer and verify that the state is `Disabled` + notif.peerset_report_disconnect(peer, set_id); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + } + + #[test] + fn peerset_disconnect_requested() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let set_id = sc_peerset::SetId::from(0); + + // Set peer into `Requested` state. + notif.peerset_report_connect(peer, set_id); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Requested))); + + // disconnect peer and verify that the state is `Disabled` + notif.peerset_report_disconnect(peer, set_id); + assert!(notif.peers.get(&(peer, set_id)).is_none()); + } + + #[test] + fn peerset_disconnect_pending_request() { + let (mut notif, _peerset) = development_notifs(); + let set_id = sc_peerset::SetId::from(0); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // manually add backoff for the entry + if let Some(PeerState::Disabled { ref mut backoff_until, .. }) = + notif.peers.get_mut(&(peer, set_id)) + { + *backoff_until = + Some(Instant::now().checked_add(std::time::Duration::from_secs(5)).unwrap()); + } + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Backoff { .. }))); + + // attempt to connect the backed-off peer and verify that the request is pending + notif.peerset_report_connect(peer, set_id); + assert!(std::matches!( + notif.peers.get(&(peer, set_id)), + Some(&PeerState::PendingRequest { .. }) + )); + + // attempt to disconnect the backed-off peer and verify that the request is pending + notif.peerset_report_disconnect(peer, set_id); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Backoff { .. }))); + } + + #[test] + fn peerset_accept_peer_not_alive() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // remote opens a substream, verify that peer state is updated to `Incoming` + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + + assert!(std::matches!( + notif.incoming[0], + IncomingPeer { alive: true, incoming_id: sc_peerset::IncomingIndex(0), .. }, + )); + + notif.disconnect_peer(&peer, set_id); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + assert!(std::matches!( + notif.incoming[0], + IncomingPeer { alive: false, incoming_id: sc_peerset::IncomingIndex(0), .. }, + )); + + notif.peerset_report_accept(sc_peerset::IncomingIndex(0)); + assert_eq!(notif.incoming.len(), 0); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(PeerState::Disabled { .. }))); + } + + #[test] + fn secondary_connection_peer_state_incoming() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let conn2 = ConnectionId::new(1usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + if let Some(&PeerState::Incoming { ref connections, .. }) = notif.peers.get(&(peer, set_id)) + { + assert_eq!(connections.len(), 1); + assert_eq!(connections[0], (conn, ConnectionState::OpenDesiredByRemote)); + } else { + panic!("invalid state"); + } + + // add another connection + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn2, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + + if let Some(&PeerState::Incoming { ref connections, .. }) = notif.peers.get(&(peer, set_id)) + { + assert_eq!(connections.len(), 2); + assert_eq!(connections[0], (conn, ConnectionState::OpenDesiredByRemote)); + assert_eq!(connections[1], (conn2, ConnectionState::Closed)); + } else { + panic!("invalid state"); + } + } + + #[test] + fn close_connection_for_disabled_peer() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + assert!(notif.peers.get(&(peer, set_id)).is_none()); + } + + #[test] + fn close_connection_for_incoming_peer_one_connection() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + assert!(notif.peers.get(&(peer, set_id)).is_none()); + assert!(std::matches!( + notif.incoming[0], + IncomingPeer { alive: false, incoming_id: sc_peerset::IncomingIndex(0), .. }, + )); + } + + #[test] + fn close_connection_for_incoming_peer_two_connections() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let conn1 = ConnectionId::new(1usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + let mut conns = SmallVec::< + [(ConnectionId, ConnectionState); crate::MAX_CONNECTIONS_PER_PEER], + >::from(vec![(conn, ConnectionState::Closed)]); + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn1, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + conns.push((conn1, ConnectionState::Closed)); + + if let Some(PeerState::Incoming { ref connections, .. }) = notif.peers.get(&(peer, set_id)) + { + assert_eq!(connections.len(), 2); + assert_eq!(connections[0], (conn, ConnectionState::OpenDesiredByRemote)); + assert_eq!(connections[1], (conn1, ConnectionState::Closed)); + } + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + + if let Some(&PeerState::Disabled { ref connections, .. }) = notif.peers.get(&(peer, set_id)) + { + assert_eq!(connections.len(), 1); + assert_eq!(connections[0], (conn1, ConnectionState::Closed)); + } else { + panic!("invalid state"); + } + } + + #[test] + fn connection_and_substream_open() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + let mut conn_yielder = ConnectionYielder::new(); + + // move the peer to `Enabled` state + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + + notif.peerset_report_connect(peer, set_id); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Enabled { .. }))); + + // open new substream + let event = conn_yielder.open_substream(peer, 0, connected, vec![1, 2, 3, 4]); + + notif.on_connection_handler_event(peer, conn, event); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Enabled { .. }))); + + if let Some(PeerState::Enabled { ref connections, .. }) = notif.peers.get(&(peer, set_id)) { + assert_eq!(connections.len(), 1); + assert_eq!(connections[0].0, conn); + assert!(std::matches!(connections[0].1, ConnectionState::Open(_))); + } + + assert!(std::matches!( + notif.events[notif.events.len() - 1], + NetworkBehaviourAction::GenerateEvent(NotificationsOut::CustomProtocolOpen { .. }) + )); + } + + #[test] + fn connection_closed_sink_replaced() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn1 = ConnectionId::new(0usize); + let conn2 = ConnectionId::new(1usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + let mut conn_yielder = ConnectionYielder::new(); + + // open two connections + for conn_id in vec![conn1, conn2] { + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn_id, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + } + + if let Some(&PeerState::Disabled { ref connections, .. }) = notif.peers.get(&(peer, set_id)) + { + assert_eq!(connections[0], (conn1, ConnectionState::Closed)); + assert_eq!(connections[1], (conn2, ConnectionState::Closed)); + } else { + panic!("invalid state"); + } + + // open substreams on both active connections + notif.peerset_report_connect(peer, set_id); + notif.on_connection_handler_event( + peer, + conn2, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + + if let Some(&PeerState::Enabled { ref connections, .. }) = notif.peers.get(&(peer, set_id)) + { + assert_eq!(connections[0], (conn1, ConnectionState::Opening)); + assert_eq!(connections[1], (conn2, ConnectionState::Opening)); + } else { + panic!("invalid state"); + } + + // add two new substreams, one for each connection and verify that both are in open state + for conn in vec![conn1, conn2].iter() { + notif.on_connection_handler_event( + peer, + *conn, + conn_yielder.open_substream(peer, 0, connected.clone(), vec![1, 2, 3, 4]), + ); + } + + if let Some(PeerState::Enabled { ref connections, .. }) = notif.peers.get(&(peer, set_id)) { + assert_eq!(connections[0].0, conn1); + assert!(std::matches!(connections[0].1, ConnectionState::Open(_))); + assert_eq!(connections[1].0, conn2); + assert!(std::matches!(connections[1].1, ConnectionState::Open(_))); + } else { + panic!("invalid state"); + } + + // check peer information + assert_eq!(notif.open_peers().collect::>(), vec![&peer],); + assert_eq!(notif.reserved_peers(set_id).collect::>(), Vec::<&PeerId>::new(),); + assert_eq!(notif.num_discovered_peers(), 0usize); + + // close the other connection and verify that notification replacement event is emitted + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn1, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + + if let Some(PeerState::Enabled { ref connections, .. }) = notif.peers.get(&(peer, set_id)) { + assert_eq!(connections.len(), 1); + assert_eq!(connections[0].0, conn2); + assert!(std::matches!(connections[0].1, ConnectionState::Open(_))); + } else { + panic!("invalid state"); + } + + assert!(std::matches!( + notif.events[notif.events.len() - 1], + NetworkBehaviourAction::GenerateEvent(NotificationsOut::CustomProtocolReplaced { .. }) + )); + } + + #[test] + fn dial_failure_for_requested_peer() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let set_id = sc_peerset::SetId::from(0); + + // Set peer into `Requested` state. + notif.peerset_report_connect(peer, set_id); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Requested))); + + notif.on_swarm_event(FromSwarm::DialFailure(libp2p::swarm::behaviour::DialFailure { + peer_id: Some(peer), + handler: NotifsHandlerProto::new(vec![]), + error: &libp2p::swarm::DialError::Banned, + })); + + if let Some(PeerState::Backoff { timer_deadline, .. }) = notif.peers.get(&(peer, set_id)) { + assert!(timer_deadline > &Instant::now()); + } else { + panic!("invalid state"); + } + } + + #[tokio::test] + async fn write_notification() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + let mut conn_yielder = ConnectionYielder::new(); + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + notif.peerset_report_connect(peer, set_id); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Enabled { .. }))); + + notif.on_connection_handler_event( + peer, + conn, + conn_yielder.open_substream(peer, 0, connected, vec![1, 2, 3, 4]), + ); + + if let Some(PeerState::Enabled { ref connections, .. }) = notif.peers.get(&(peer, set_id)) { + assert_eq!(connections[0].0, conn); + assert!(std::matches!(connections[0].1, ConnectionState::Open(_))); + } else { + panic!("invalid state"); + } + + notif.write_notification(&peer, set_id, vec![1, 3, 3, 7]); + assert_eq!(conn_yielder.get_next_event(peer, set_id.into()).await, Some(vec![1, 3, 3, 7])); + } + + #[test] + fn peerset_report_connect_backoff_expired() { + let (mut notif, _peerset) = development_notifs(); + let set_id = sc_peerset::SetId::from(0); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + let backoff_duration = Duration::from_millis(100); + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // manually add backoff for the entry + if let Some(PeerState::Disabled { ref mut backoff_until, .. }) = + notif.peers.get_mut(&(peer, set_id)) + { + *backoff_until = Some(Instant::now().checked_add(backoff_duration).unwrap()); + } + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + + // wait until the backoff time has passed + std::thread::sleep(backoff_duration * 2); + + // attempt to connect the backed-off peer and verify that the request is pending + notif.peerset_report_connect(peer, set_id); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Requested { .. }))) + } + + #[test] + fn peerset_report_disconnect_disabled() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let set_id = sc_peerset::SetId::from(0); + let conn = ConnectionId::new(0usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + notif.peerset_report_disconnect(peer, set_id); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + } + + #[test] + fn peerset_report_disconnect_backoff() { + let (mut notif, _peerset) = development_notifs(); + let set_id = sc_peerset::SetId::from(0); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + let backoff_duration = Duration::from_secs(2); + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // manually add backoff for the entry + if let Some(PeerState::Disabled { ref mut backoff_until, .. }) = + notif.peers.get_mut(&(peer, set_id)) + { + *backoff_until = Some(Instant::now().checked_add(backoff_duration).unwrap()); + } + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Backoff { .. }))); + + notif.peerset_report_disconnect(peer, set_id); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Backoff { .. }))); + } + + #[test] + fn peer_is_backed_off_if_both_connections_get_closed_while_peer_is_disabled_with_back_off() { + let (mut notif, _peerset) = development_notifs(); + let set_id = sc_peerset::SetId::from(0); + let peer = PeerId::random(); + let conn1 = ConnectionId::new(0usize); + let conn2 = ConnectionId::new(0usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn1, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn2, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // manually add backoff for the entry + if let Some(PeerState::Disabled { ref mut backoff_until, .. }) = + notif.peers.get_mut(&(peer, set_id)) + { + *backoff_until = + Some(Instant::now().checked_add(std::time::Duration::from_secs(5)).unwrap()); + } + + // switch state to `DisabledPendingEnable` + notif.peerset_report_connect(peer, set_id); + assert!(std::matches!( + notif.peers.get(&(peer, set_id)), + Some(&PeerState::DisabledPendingEnable { .. }) + )); + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn1, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + assert!(std::matches!( + notif.peers.get(&(peer, set_id)), + Some(&PeerState::DisabledPendingEnable { .. }) + )); + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn2, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Backoff { .. }))); + } + + #[test] + fn inject_connection_closed_incoming_with_backoff() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let set_id = sc_peerset::SetId::from(0); + let conn = ConnectionId::new(0usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // remote opens a substream, verify that peer state is updated to `Incoming` + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + + // manually add backoff for the entry + if let Some(&mut PeerState::Incoming { ref mut backoff_until, .. }) = + notif.peers.get_mut(&(peer, 0.into())) + { + *backoff_until = + Some(Instant::now().checked_add(std::time::Duration::from_secs(5)).unwrap()); + } else { + panic!("invalid state"); + } + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Backoff { .. }))); + } + + #[test] + fn two_connections_inactive_connection_gets_closed_peer_state_is_still_incoming() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn1 = ConnectionId::new(0usize); + let conn2 = ConnectionId::new(1usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + // open two connections + for conn_id in vec![conn1, conn2] { + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn_id, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + } + + if let Some(&PeerState::Disabled { ref connections, .. }) = notif.peers.get(&(peer, set_id)) + { + assert_eq!(connections[0], (conn1, ConnectionState::Closed)); + assert_eq!(connections[1], (conn2, ConnectionState::Closed)); + } else { + panic!("invalid state"); + } + + // remote opens a substream, verify that peer state is updated to `Incoming` + notif.on_connection_handler_event( + peer, + conn1, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + assert!(std::matches!( + notif.peers.get_mut(&(peer, 0.into())), + Some(&mut PeerState::Incoming { .. }) + )); + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn2, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + } + + #[test] + fn two_connections_active_connection_gets_closed_peer_state_is_disabled() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn1 = ConnectionId::new(0usize); + let conn2 = ConnectionId::new(1usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + // open two connections + for conn_id in vec![conn1, conn2] { + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn_id, + endpoint: &ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }, + failed_addresses: &[], + other_established: 0usize, + }, + )); + } + + if let Some(&PeerState::Disabled { ref connections, .. }) = notif.peers.get(&(peer, set_id)) + { + assert_eq!(connections[0], (conn1, ConnectionState::Closed)); + assert_eq!(connections[1], (conn2, ConnectionState::Closed)); + } else { + panic!("invalid state"); + } + + // remote opens a substream, verify that peer state is updated to `Incoming` + notif.on_connection_handler_event( + peer, + conn1, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + assert!(std::matches!( + notif.peers.get_mut(&(peer, 0.into())), + Some(PeerState::Incoming { .. }) + )); + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn1, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + } + + #[test] + fn inject_connection_closed_for_active_connection() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn1 = ConnectionId::new(0usize); + let conn2 = ConnectionId::new(1usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + let mut conn_yielder = ConnectionYielder::new(); + + // open two connections + for conn_id in vec![conn1, conn2] { + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn_id, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + } + + if let Some(&PeerState::Disabled { ref connections, .. }) = notif.peers.get(&(peer, set_id)) + { + assert_eq!(connections[0], (conn1, ConnectionState::Closed)); + assert_eq!(connections[1], (conn2, ConnectionState::Closed)); + } else { + panic!("invalid state"); + } + + // open substreams on both active connections + notif.peerset_report_connect(peer, set_id); + + if let Some(&PeerState::Enabled { ref connections, .. }) = notif.peers.get(&(peer, set_id)) + { + assert_eq!(connections[0], (conn1, ConnectionState::Opening)); + assert_eq!(connections[1], (conn2, ConnectionState::Closed)); + } else { + panic!("invalid state"); + } + + notif.on_connection_handler_event( + peer, + conn1, + conn_yielder.open_substream(peer, 0, connected.clone(), vec![1, 2, 3, 4]), + ); + + if let Some(PeerState::Enabled { ref connections, .. }) = notif.peers.get(&(peer, set_id)) { + assert!(std::matches!(connections[0].1, ConnectionState::Open(_))); + assert_eq!(connections[0].0, conn1); + assert_eq!(connections[1], (conn2, ConnectionState::Closed)); + } else { + panic!("invalid state"); + } + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn1, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + } + + #[test] + fn inject_dial_failure_for_pending_request() { + let (mut notif, _peerset) = development_notifs(); + let set_id = sc_peerset::SetId::from(0); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // manually add backoff for the entry + if let Some(PeerState::Disabled { ref mut backoff_until, .. }) = + notif.peers.get_mut(&(peer, set_id)) + { + *backoff_until = + Some(Instant::now().checked_add(std::time::Duration::from_secs(5)).unwrap()); + } + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Backoff { .. }))); + + // attempt to connect the backed-off peer and verify that the request is pending + notif.peerset_report_connect(peer, set_id); + assert!(std::matches!( + notif.peers.get(&(peer, set_id)), + Some(&PeerState::PendingRequest { .. }) + )); + + let now = Instant::now(); + notif.on_swarm_event(FromSwarm::DialFailure(libp2p::swarm::behaviour::DialFailure { + peer_id: Some(peer), + handler: NotifsHandlerProto::new(vec![]), + error: &libp2p::swarm::DialError::Banned, + })); + + if let Some(PeerState::PendingRequest { ref timer_deadline, .. }) = + notif.peers.get(&(peer, set_id)) + { + assert!(timer_deadline > &(now + std::time::Duration::from_secs(5))); + } + } + + #[test] + fn peerstate_incoming_open_desired_by_remote() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let set_id = sc_peerset::SetId::from(0); + let conn1 = ConnectionId::new(0usize); + let conn2 = ConnectionId::new(1usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn1, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn2, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // remote opens a substream, verify that peer state is updated to `Incoming` + notif.on_connection_handler_event( + peer, + conn1, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + + // add another open event from remote + notif.on_connection_handler_event( + peer, + conn2, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + + if let Some(PeerState::Incoming { ref connections, .. }) = notif.peers.get(&(peer, set_id)) + { + assert_eq!(connections[0], (conn1, ConnectionState::OpenDesiredByRemote)); + assert_eq!(connections[1], (conn2, ConnectionState::OpenDesiredByRemote)); + } + } + + #[tokio::test] + async fn remove_backoff_peer_after_timeout() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let set_id = sc_peerset::SetId::from(0); + let conn = ConnectionId::new(0usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + + if let Some(&mut PeerState::Disabled { ref mut backoff_until, .. }) = + notif.peers.get_mut(&(peer, 0.into())) + { + *backoff_until = + Some(Instant::now().checked_add(std::time::Duration::from_millis(100)).unwrap()); + } else { + panic!("invalid state"); + } + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + + let until = if let Some(&PeerState::Backoff { timer_deadline, .. }) = + notif.peers.get(&(peer, set_id)) + { + timer_deadline + } else { + panic!("invalid state"); + }; + + if until > Instant::now() { + std::thread::sleep(until - Instant::now()); + } + + assert!(notif.peers.get(&(peer, set_id)).is_some()); + + if tokio::time::timeout(Duration::from_secs(5), async { + let mut params = MockPollParams { peer_id: PeerId::random(), addr: Multiaddr::empty() }; + + loop { + futures::future::poll_fn(|cx| { + let _ = notif.poll(cx, &mut params); + Poll::Ready(()) + }) + .await; + + if notif.peers.get(&(peer, set_id)).is_none() { + break + } + } + }) + .await + .is_err() + { + panic!("backoff peer was not removed in time"); + } + + assert!(notif.peers.get(&(peer, set_id)).is_none()); + } + + #[tokio::test] + async fn reschedule_disabled_pending_enable_when_connection_not_closed() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + let mut conn_yielder = ConnectionYielder::new(); + + // move the peer to `Enabled` state + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // open substream + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + + notif.peerset_report_connect(peer, set_id); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Enabled { .. }))); + + let event = conn_yielder.open_substream(peer, 0, connected, vec![1, 2, 3, 4]); + + notif.on_connection_handler_event(peer, conn, event); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Enabled { .. }))); + + if let Some(PeerState::Enabled { ref connections, .. }) = notif.peers.get(&(peer, set_id)) { + assert!(std::matches!(connections[0], (_, ConnectionState::Open(_)))); + assert_eq!(connections[0].0, conn); + } else { + panic!("invalid state"); + } + + notif.peerset_report_disconnect(peer, set_id); + + if let Some(PeerState::Disabled { ref connections, ref mut backoff_until }) = + notif.peers.get_mut(&(peer, set_id)) + { + assert!(std::matches!(connections[0], (_, ConnectionState::Closing))); + assert_eq!(connections[0].0, conn); + + *backoff_until = + Some(Instant::now().checked_add(std::time::Duration::from_secs(2)).unwrap()); + } else { + panic!("invalid state"); + } + + notif.peerset_report_connect(peer, set_id); + + let prev_instant = + if let Some(PeerState::DisabledPendingEnable { + ref connections, timer_deadline, .. + }) = notif.peers.get(&(peer, set_id)) + { + assert!(std::matches!(connections[0], (_, ConnectionState::Closing))); + assert_eq!(connections[0].0, conn); + + *timer_deadline + } else { + panic!("invalid state"); + }; + + // one of the peers has an active backoff timer so poll the notifications code until + // the timer has expired. Because the connection is still in the state of `Closing`, + // verify that the code continues to keep the peer disabled by resetting the timer + // after the first one expired. + if tokio::time::timeout(Duration::from_secs(5), async { + let mut params = MockPollParams { peer_id: PeerId::random(), addr: Multiaddr::empty() }; + + loop { + futures::future::poll_fn(|cx| { + let _ = notif.poll(cx, &mut params); + Poll::Ready(()) + }) + .await; + + if let Some(PeerState::DisabledPendingEnable { + timer_deadline, connections, .. + }) = notif.peers.get(&(peer, set_id)) + { + assert!(std::matches!(connections[0], (_, ConnectionState::Closing))); + + if timer_deadline != &prev_instant { + break + } + } else { + panic!("invalid state"); + } + } + }) + .await + .is_err() + { + panic!("backoff peer was not removed in time"); + } + } + + #[test] + #[should_panic] + #[cfg(debug_assertions)] + fn peerset_report_connect_with_enabled_peer() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + let mut conn_yielder = ConnectionYielder::new(); + + // move the peer to `Enabled` state + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + + notif.peerset_report_connect(peer, set_id); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Enabled { .. }))); + + let event = conn_yielder.open_substream(peer, 0, connected, vec![1, 2, 3, 4]); + + notif.on_connection_handler_event(peer, conn, event); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Enabled { .. }))); + + if let Some(PeerState::Enabled { ref connections, .. }) = notif.peers.get(&(peer, set_id)) { + assert!(std::matches!(connections[0], (_, ConnectionState::Open(_)))); + assert_eq!(connections[0].0, conn); + } else { + panic!("invalid state"); + } + + notif.peerset_report_connect(peer, set_id); + } + + #[test] + #[should_panic] + #[cfg(debug_assertions)] + fn peerset_report_connect_with_disabled_pending_enable_peer() { + let (mut notif, _peerset) = development_notifs(); + let set_id = sc_peerset::SetId::from(0); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // manually add backoff for the entry + if let Some(PeerState::Disabled { ref mut backoff_until, .. }) = + notif.peers.get_mut(&(peer, set_id)) + { + *backoff_until = + Some(Instant::now().checked_add(std::time::Duration::from_secs(5)).unwrap()); + } + + // switch state to `DisabledPendingEnable` + notif.peerset_report_connect(peer, set_id); + assert!(std::matches!( + notif.peers.get(&(peer, set_id)), + Some(&PeerState::DisabledPendingEnable { .. }) + )); + + notif.peerset_report_connect(peer, set_id); + } + + #[test] + #[should_panic] + #[cfg(debug_assertions)] + fn peerset_report_connect_with_requested_peer() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let set_id = sc_peerset::SetId::from(0); + + // Set peer into `Requested` state. + notif.peerset_report_connect(peer, set_id); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Requested))); + + notif.peerset_report_connect(peer, set_id); + } + + #[test] + #[should_panic] + #[cfg(debug_assertions)] + fn peerset_report_connect_with_pending_requested() { + let (mut notif, _peerset) = development_notifs(); + let set_id = sc_peerset::SetId::from(0); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // manually add backoff for the entry + if let Some(PeerState::Disabled { ref mut backoff_until, .. }) = + notif.peers.get_mut(&(peer, set_id)) + { + *backoff_until = + Some(Instant::now().checked_add(std::time::Duration::from_secs(5)).unwrap()); + } + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Backoff { .. }))); + + // attempt to connect the backed-off peer and verify that the request is pending + notif.peerset_report_connect(peer, set_id); + assert!(std::matches!( + notif.peers.get(&(peer, set_id)), + Some(&PeerState::PendingRequest { .. }) + )); + + notif.peerset_report_connect(peer, set_id); + } + + #[test] + #[should_panic] + #[cfg(debug_assertions)] + fn peerset_report_disconnect_with_incoming_peer() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let set_id = sc_peerset::SetId::from(0); + let conn = ConnectionId::new(0usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // remote opens a substream, verify that peer state is updated to `Incoming` + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + + notif.peerset_report_disconnect(peer, set_id); + } + + #[test] + #[should_panic] + #[cfg(debug_assertions)] + fn peerset_report_accept_incoming_peer() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // remote opens a substream, verify that peer state is updated to `Incoming` + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + + assert!(std::matches!( + notif.incoming[0], + IncomingPeer { alive: true, incoming_id: sc_peerset::IncomingIndex(0), .. }, + )); + + notif.peers.remove(&(peer, set_id)); + notif.peerset_report_accept(sc_peerset::IncomingIndex(0)); + } + + #[test] + #[should_panic] + #[cfg(debug_assertions)] + fn peerset_report_accept_not_incoming_peer() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + let mut conn_yielder = ConnectionYielder::new(); + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // remote opens a substream, verify that peer state is updated to `Incoming` + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + + assert!(std::matches!( + notif.incoming[0], + IncomingPeer { alive: true, incoming_id: sc_peerset::IncomingIndex(0), .. }, + )); + + notif.peerset_report_connect(peer, set_id); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Enabled { .. }))); + + let event = conn_yielder.open_substream(peer, 0, connected, vec![1, 2, 3, 4]); + notif.on_connection_handler_event(peer, conn, event); + + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Enabled { .. }))); + notif.incoming[0].alive = true; + notif.peerset_report_accept(sc_peerset::IncomingIndex(0)); + } + + #[test] + #[should_panic] + #[cfg(debug_assertions)] + fn inject_connection_closed_non_existent_peer() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let endpoint = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: ConnectionId::new(0usize), + endpoint: &endpoint, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &endpoint), + remaining_established: 0usize, + }, + )); + } + + #[test] + fn disconnect_non_existent_peer() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let set_id = sc_peerset::SetId::from(0); + + notif.peerset_report_disconnect(peer, set_id); + + assert!(notif.peers.is_empty()); + assert!(notif.incoming.is_empty()); + } + + #[test] + fn accept_non_existent_connection() { + let (mut notif, _peerset) = development_notifs(); + + notif.peerset_report_accept(0.into()); + + assert!(notif.peers.is_empty()); + assert!(notif.incoming.is_empty()); + } + + #[test] + fn reject_non_existent_connection() { + let (mut notif, _peerset) = development_notifs(); + + notif.peerset_report_reject(0.into()); + + assert!(notif.peers.is_empty()); + assert!(notif.incoming.is_empty()); + } + + #[test] + fn reject_non_active_connection() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // remote opens a substream, verify that peer state is updated to `Incoming` + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + + notif.incoming[0].alive = false; + notif.peerset_report_reject(0.into()); + + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + } + + #[test] + #[should_panic] + #[cfg(debug_assertions)] + fn reject_non_existent_peer_but_alive_connection() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // remote opens a substream, verify that peer state is updated to `Incoming` + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + assert!(std::matches!( + notif.incoming[0], + IncomingPeer { alive: true, incoming_id: sc_peerset::IncomingIndex(0), .. }, + )); + + notif.peers.remove(&(peer, set_id)); + notif.peerset_report_reject(0.into()); + } + + #[test] + #[should_panic] + #[cfg(debug_assertions)] + fn inject_non_existent_connection_closed_for_incoming_peer() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // remote opens a substream, verify that peer state is updated to `Incoming` + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: ConnectionId::new(1337usize), + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + } + + #[test] + #[should_panic] + #[cfg(debug_assertions)] + fn inject_non_existent_connection_closed_for_disabled_peer() { + let (mut notif, _peerset) = development_notifs(); + let set_id = sc_peerset::SetId::from(0); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: ConnectionId::new(1337usize), + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + } + + #[test] + #[should_panic] + #[cfg(debug_assertions)] + fn inject_non_existent_connection_closed_for_disabled_pending_enable() { + let (mut notif, _peerset) = development_notifs(); + let set_id = sc_peerset::SetId::from(0); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // manually add backoff for the entry + if let Some(PeerState::Disabled { ref mut backoff_until, .. }) = + notif.peers.get_mut(&(peer, set_id)) + { + *backoff_until = + Some(Instant::now().checked_add(std::time::Duration::from_secs(5)).unwrap()); + } + + // switch state to `DisabledPendingEnable` + notif.peerset_report_connect(peer, set_id); + + assert!(std::matches!( + notif.peers.get(&(peer, set_id)), + Some(&PeerState::DisabledPendingEnable { .. }) + )); + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: ConnectionId::new(1337usize), + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + } + + #[test] + #[should_panic] + #[cfg(debug_assertions)] + fn inject_connection_closed_for_incoming_peer_state_mismatch() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // remote opens a substream, verify that peer state is updated to `Incoming` + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + notif.incoming[0].alive = false; + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + } + + #[test] + #[should_panic] + #[cfg(debug_assertions)] + fn inject_connection_closed_for_enabled_state_mismatch() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // remote opens a substream, verify that peer state is updated to `Incoming` + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + + // attempt to connect to the peer and verify that the peer state is `Enabled` + notif.peerset_report_connect(peer, set_id); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Enabled { .. }))); + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: ConnectionId::new(1337usize), + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + } + + #[test] + #[should_panic] + #[cfg(debug_assertions)] + fn inject_connection_closed_for_backoff_peer() { + let (mut notif, _peerset) = development_notifs(); + let set_id = sc_peerset::SetId::from(0); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // manually add backoff for the entry + if let Some(PeerState::Disabled { ref mut backoff_until, .. }) = + notif.peers.get_mut(&(peer, set_id)) + { + *backoff_until = + Some(Instant::now().checked_add(std::time::Duration::from_secs(5)).unwrap()); + } + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Backoff { .. }))); + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + } + + #[test] + #[should_panic] + #[cfg(debug_assertions)] + fn open_result_ok_non_existent_peer() { + let (mut notif, _peerset) = development_notifs(); + let conn = ConnectionId::new(0usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + let mut conn_yielder = ConnectionYielder::new(); + + notif.on_connection_handler_event( + PeerId::random(), + conn, + conn_yielder.open_substream(PeerId::random(), 0, connected, vec![1, 2, 3, 4]), + ); + } +} diff --git a/client/network/src/protocol/notifications/handler.rs b/client/network/src/protocol/notifications/handler.rs index ea09cb76edce1..57561c7b9879d 100644 --- a/client/network/src/protocol/notifications/handler.rs +++ b/client/network/src/protocol/notifications/handler.rs @@ -58,8 +58,8 @@ //! [`NotifsHandlerIn::Open`] has gotten an answer. use crate::protocol::notifications::upgrade::{ - NotificationsHandshakeError, NotificationsIn, NotificationsInSubstream, NotificationsOut, - NotificationsOutSubstream, UpgradeCollec, + NotificationsIn, NotificationsInSubstream, NotificationsOut, NotificationsOutSubstream, + UpgradeCollec, }; use bytes::BytesMut; @@ -69,12 +69,9 @@ use futures::{ prelude::*, }; use libp2p::{ - core::{ - upgrade::{InboundUpgrade, OutboundUpgrade}, - ConnectedPoint, PeerId, - }, + core::{ConnectedPoint, PeerId}, swarm::{ - ConnectionHandler, ConnectionHandlerEvent, ConnectionHandlerUpgrErr, IntoConnectionHandler, + handler::ConnectionEvent, ConnectionHandler, ConnectionHandlerEvent, IntoConnectionHandler, KeepAlive, NegotiatedSubstream, SubstreamProtocol, }, }; @@ -494,98 +491,128 @@ impl ConnectionHandler for NotifsHandler { SubstreamProtocol::new(protocols, ()) } - fn inject_fully_negotiated_inbound( + fn on_connection_event( &mut self, - (mut in_substream_open, protocol_index): >::Output, - (): (), + event: ConnectionEvent< + '_, + Self::InboundProtocol, + Self::OutboundProtocol, + Self::InboundOpenInfo, + Self::OutboundOpenInfo, + >, ) { - let mut protocol_info = &mut self.protocols[protocol_index]; - match protocol_info.state { - State::Closed { pending_opening } => { - self.events_queue.push_back(ConnectionHandlerEvent::Custom( - NotifsHandlerOut::OpenDesiredByRemote { protocol_index }, - )); + match event { + ConnectionEvent::FullyNegotiatedInbound(inbound) => { + let (mut in_substream_open, protocol_index) = inbound.protocol; + let mut protocol_info = &mut self.protocols[protocol_index]; - protocol_info.state = State::OpenDesiredByRemote { - in_substream: in_substream_open.substream, - pending_opening, - }; - }, - State::OpenDesiredByRemote { .. } => { - // If a substream already exists, silently drop the new one. - // Note that we drop the substream, which will send an equivalent to a - // TCP "RST" to the remote and force-close the substream. It might - // seem like an unclean way to get rid of a substream. However, keep - // in mind that it is invalid for the remote to open multiple such - // substreams, and therefore sending a "RST" is the most correct thing - // to do. - return - }, - State::Opening { ref mut in_substream, .. } | - State::Open { ref mut in_substream, .. } => { - if in_substream.is_some() { - // Same remark as above. - return - } + match protocol_info.state { + State::Closed { pending_opening } => { + self.events_queue.push_back(ConnectionHandlerEvent::Custom( + NotifsHandlerOut::OpenDesiredByRemote { protocol_index }, + )); - // Create `handshake_message` on a separate line to be sure that the - // lock is released as soon as possible. - let handshake_message = protocol_info.config.handshake.read().clone(); - in_substream_open.substream.send_handshake(handshake_message); - *in_substream = Some(in_substream_open.substream); - }, - } - } + protocol_info.state = State::OpenDesiredByRemote { + in_substream: in_substream_open.substream, + pending_opening, + }; + }, + State::OpenDesiredByRemote { .. } => { + // If a substream already exists, silently drop the new one. + // Note that we drop the substream, which will send an equivalent to a + // TCP "RST" to the remote and force-close the substream. It might + // seem like an unclean way to get rid of a substream. However, keep + // in mind that it is invalid for the remote to open multiple such + // substreams, and therefore sending a "RST" is the most correct thing + // to do. + return + }, + State::Opening { ref mut in_substream, .. } | + State::Open { ref mut in_substream, .. } => { + if in_substream.is_some() { + // Same remark as above. + return + } - fn inject_fully_negotiated_outbound( - &mut self, - new_open: >::Output, - protocol_index: Self::OutboundOpenInfo, - ) { - match self.protocols[protocol_index].state { - State::Closed { ref mut pending_opening } | - State::OpenDesiredByRemote { ref mut pending_opening, .. } => { - debug_assert!(*pending_opening); - *pending_opening = false; - }, - State::Open { .. } => { - error!(target: "sub-libp2p", "☎️ State mismatch in notifications handler"); - debug_assert!(false); + // Create `handshake_message` on a separate line to be sure that the + // lock is released as soon as possible. + let handshake_message = protocol_info.config.handshake.read().clone(); + in_substream_open.substream.send_handshake(handshake_message); + *in_substream = Some(in_substream_open.substream); + }, + } }, - State::Opening { ref mut in_substream } => { - let (async_tx, async_rx) = mpsc::channel(ASYNC_NOTIFICATIONS_BUFFER_SIZE); - let (sync_tx, sync_rx) = mpsc::channel(SYNC_NOTIFICATIONS_BUFFER_SIZE); - let notifications_sink = NotificationsSink { - inner: Arc::new(NotificationsSinkInner { - peer_id: self.peer_id, - async_channel: FuturesMutex::new(async_tx), - sync_channel: Mutex::new(Some(sync_tx)), - }), - }; - - self.protocols[protocol_index].state = State::Open { - notifications_sink_rx: stream::select(async_rx.fuse(), sync_rx.fuse()) - .peekable(), - out_substream: Some(new_open.substream), - in_substream: in_substream.take(), - }; + ConnectionEvent::FullyNegotiatedOutbound(outbound) => { + let (new_open, protocol_index) = (outbound.protocol, outbound.info); - self.events_queue.push_back(ConnectionHandlerEvent::Custom( - NotifsHandlerOut::OpenResultOk { - protocol_index, - negotiated_fallback: new_open.negotiated_fallback, - endpoint: self.endpoint.clone(), - received_handshake: new_open.handshake, - notifications_sink, + match self.protocols[protocol_index].state { + State::Closed { ref mut pending_opening } | + State::OpenDesiredByRemote { ref mut pending_opening, .. } => { + debug_assert!(*pending_opening); + *pending_opening = false; }, - )); + State::Open { .. } => { + error!(target: "sub-libp2p", "☎️ State mismatch in notifications handler"); + debug_assert!(false); + }, + State::Opening { ref mut in_substream } => { + let (async_tx, async_rx) = mpsc::channel(ASYNC_NOTIFICATIONS_BUFFER_SIZE); + let (sync_tx, sync_rx) = mpsc::channel(SYNC_NOTIFICATIONS_BUFFER_SIZE); + let notifications_sink = NotificationsSink { + inner: Arc::new(NotificationsSinkInner { + peer_id: self.peer_id, + async_channel: FuturesMutex::new(async_tx), + sync_channel: Mutex::new(Some(sync_tx)), + }), + }; + + self.protocols[protocol_index].state = State::Open { + notifications_sink_rx: stream::select(async_rx.fuse(), sync_rx.fuse()) + .peekable(), + out_substream: Some(new_open.substream), + in_substream: in_substream.take(), + }; + + self.events_queue.push_back(ConnectionHandlerEvent::Custom( + NotifsHandlerOut::OpenResultOk { + protocol_index, + negotiated_fallback: new_open.negotiated_fallback, + endpoint: self.endpoint.clone(), + received_handshake: new_open.handshake, + notifications_sink, + }, + )); + }, + } }, + ConnectionEvent::AddressChange(_address_change) => {}, + ConnectionEvent::DialUpgradeError(dial_upgrade_error) => match self.protocols + [dial_upgrade_error.info] + .state + { + State::Closed { ref mut pending_opening } | + State::OpenDesiredByRemote { ref mut pending_opening, .. } => { + debug_assert!(*pending_opening); + *pending_opening = false; + }, + + State::Opening { .. } => { + self.protocols[dial_upgrade_error.info].state = + State::Closed { pending_opening: false }; + + self.events_queue.push_back(ConnectionHandlerEvent::Custom( + NotifsHandlerOut::OpenResultErr { protocol_index: dial_upgrade_error.info }, + )); + }, + + // No substream is being open when already `Open`. + State::Open { .. } => debug_assert!(false), + }, + ConnectionEvent::ListenUpgradeError(_listen_upgrade_error) => {}, } } - fn inject_event(&mut self, message: NotifsHandlerIn) { + fn on_behaviour_event(&mut self, message: NotifsHandlerIn) { match message { NotifsHandlerIn::Open { protocol_index } => { let protocol_info = &mut self.protocols[protocol_index]; @@ -676,31 +703,6 @@ impl ConnectionHandler for NotifsHandler { } } - fn inject_dial_upgrade_error( - &mut self, - num: usize, - _: ConnectionHandlerUpgrErr, - ) { - match self.protocols[num].state { - State::Closed { ref mut pending_opening } | - State::OpenDesiredByRemote { ref mut pending_opening, .. } => { - debug_assert!(*pending_opening); - *pending_opening = false; - }, - - State::Opening { .. } => { - self.protocols[num].state = State::Closed { pending_opening: false }; - - self.events_queue.push_back(ConnectionHandlerEvent::Custom( - NotifsHandlerOut::OpenResultErr { protocol_index: num }, - )); - }, - - // No substream is being open when already `Open`. - State::Open { .. } => debug_assert!(false), - } - } - fn connection_keep_alive(&self) -> KeepAlive { // `Yes` if any protocol has some activity. if self.protocols.iter().any(|p| !matches!(p.state, State::Closed { .. })) { @@ -850,3 +852,792 @@ impl ConnectionHandler for NotifsHandler { Poll::Pending } } + +#[cfg(test)] +pub mod tests { + use super::*; + use crate::protocol::notifications::upgrade::{ + NotificationsInOpen, NotificationsInSubstreamHandshake, NotificationsOutOpen, + }; + use asynchronous_codec::Framed; + use libp2p::{ + core::muxing::SubstreamBox, + swarm::{handler, ConnectionHandlerUpgrErr}, + Multiaddr, + }; + use multistream_select::{dialer_select_proto, listener_select_proto, Negotiated, Version}; + use std::{ + collections::HashMap, + io::{Error, IoSlice, IoSliceMut}, + }; + use tokio::sync::mpsc; + use unsigned_varint::codec::UviBytes; + + struct OpenSubstream { + notifications: stream::Peekable< + stream::Select< + stream::Fuse>, + stream::Fuse>, + >, + >, + _in_substream: MockSubstream, + _out_substream: MockSubstream, + } + + pub struct ConnectionYielder { + connections: HashMap<(PeerId, usize), OpenSubstream>, + } + + impl ConnectionYielder { + /// Create new [`ConnectionYielder`]. + pub fn new() -> Self { + Self { connections: HashMap::new() } + } + + /// Open a new substream for peer. + pub fn open_substream( + &mut self, + peer: PeerId, + protocol_index: usize, + endpoint: ConnectedPoint, + received_handshake: Vec, + ) -> NotifsHandlerOut { + let (async_tx, async_rx) = + futures::channel::mpsc::channel(ASYNC_NOTIFICATIONS_BUFFER_SIZE); + let (sync_tx, sync_rx) = + futures::channel::mpsc::channel(SYNC_NOTIFICATIONS_BUFFER_SIZE); + let notifications_sink = NotificationsSink { + inner: Arc::new(NotificationsSinkInner { + peer_id: peer, + async_channel: FuturesMutex::new(async_tx), + sync_channel: Mutex::new(Some(sync_tx)), + }), + }; + let (in_substream, out_substream) = MockSubstream::new(); + + self.connections.insert( + (peer, protocol_index), + OpenSubstream { + notifications: stream::select(async_rx.fuse(), sync_rx.fuse()).peekable(), + _in_substream: in_substream, + _out_substream: out_substream, + }, + ); + + NotifsHandlerOut::OpenResultOk { + protocol_index, + negotiated_fallback: None, + endpoint, + received_handshake, + notifications_sink, + } + } + + /// Attempt to get next pending event from one of the notification sinks. + pub async fn get_next_event(&mut self, peer: PeerId, set: usize) -> Option> { + let substream = if let Some(info) = self.connections.get_mut(&(peer, set)) { + info + } else { + return None + }; + + futures::future::poll_fn(|cx| match substream.notifications.poll_next_unpin(cx) { + Poll::Ready(Some(NotificationsSinkMessage::Notification { message })) => + Poll::Ready(Some(message)), + Poll::Pending => Poll::Ready(None), + Poll::Ready(Some(NotificationsSinkMessage::ForceClose)) | Poll::Ready(None) => + panic!("sink closed"), + }) + .await + } + } + + struct MockSubstream { + pub rx: mpsc::Receiver>, + pub tx: mpsc::Sender>, + rx_buffer: BytesMut, + } + + impl MockSubstream { + /// Create new substream pair. + pub fn new() -> (Self, Self) { + let (tx1, rx1) = mpsc::channel(32); + let (tx2, rx2) = mpsc::channel(32); + + ( + Self { rx: rx1, tx: tx2, rx_buffer: BytesMut::with_capacity(512) }, + Self { rx: rx2, tx: tx1, rx_buffer: BytesMut::with_capacity(512) }, + ) + } + + /// Create new negotiated substream pair. + pub async fn negotiated() -> (Negotiated, Negotiated) { + let (socket1, socket2) = Self::new(); + let socket1 = SubstreamBox::new(socket1); + let socket2 = SubstreamBox::new(socket2); + + let protos = vec![b"/echo/1.0.0", b"/echo/2.5.0"]; + let (res1, res2) = tokio::join!( + dialer_select_proto(socket1, protos.clone(), Version::V1), + listener_select_proto(socket2, protos), + ); + + (res1.unwrap().1, res2.unwrap().1) + } + } + + impl AsyncWrite for MockSubstream { + fn poll_write<'a>( + self: Pin<&mut Self>, + _cx: &mut Context<'a>, + buf: &[u8], + ) -> Poll> { + match self.tx.try_send(buf.to_vec()) { + Ok(_) => Poll::Ready(Ok(buf.len())), + Err(_) => Poll::Ready(Err(std::io::ErrorKind::UnexpectedEof.into())), + } + } + + fn poll_flush<'a>(self: Pin<&mut Self>, _cx: &mut Context<'a>) -> Poll> { + Poll::Ready(Ok(())) + } + + fn poll_close<'a>(self: Pin<&mut Self>, _cx: &mut Context<'a>) -> Poll> { + Poll::Ready(Ok(())) + } + + fn poll_write_vectored<'a, 'b>( + self: Pin<&mut Self>, + _cx: &mut Context<'a>, + _bufs: &[IoSlice<'b>], + ) -> Poll> { + unimplemented!(); + } + } + + impl AsyncRead for MockSubstream { + fn poll_read<'a>( + mut self: Pin<&mut Self>, + cx: &mut Context<'a>, + buf: &mut [u8], + ) -> Poll> { + match self.rx.poll_recv(cx) { + Poll::Ready(Some(data)) => self.rx_buffer.extend_from_slice(&data), + Poll::Ready(None) => + return Poll::Ready(Err(std::io::ErrorKind::UnexpectedEof.into())), + _ => {}, + } + + let nsize = std::cmp::min(self.rx_buffer.len(), buf.len()); + let data = self.rx_buffer.split_to(nsize); + buf[..nsize].copy_from_slice(&data[..]); + + if nsize > 0 { + return Poll::Ready(Ok(nsize)) + } + + Poll::Pending + } + + fn poll_read_vectored<'a, 'b>( + self: Pin<&mut Self>, + _cx: &mut Context<'a>, + _bufs: &mut [IoSliceMut<'b>], + ) -> Poll> { + unimplemented!(); + } + } + + /// Create new [`NotifsHandler`]. + fn notifs_handler() -> NotifsHandler { + let proto = Protocol { + config: ProtocolConfig { + name: "/foo".into(), + fallback_names: vec![], + handshake: Arc::new(RwLock::new(b"hello, world".to_vec())), + max_notification_size: u64::MAX, + }, + in_upgrade: NotificationsIn::new("/foo", Vec::new(), u64::MAX), + state: State::Closed { pending_opening: false }, + }; + + NotifsHandler { + protocols: vec![proto], + when_connection_open: Instant::now(), + endpoint: ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }, + peer_id: PeerId::random(), + events_queue: VecDeque::new(), + } + } + + // verify that if another substream is attempted to be opened by remote while an inbound + // substream already exists, the new inbound stream is rejected and closed by the local node. + #[tokio::test] + async fn second_open_desired_by_remote_rejected() { + let mut handler = notifs_handler(); + let (io, mut io2) = MockSubstream::negotiated().await; + let mut codec = UviBytes::default(); + codec.set_max_len(usize::MAX); + + let notif_in = NotificationsInOpen { + handshake: b"hello, world".to_vec(), + negotiated_fallback: None, + substream: NotificationsInSubstream::new( + Framed::new(io, codec), + NotificationsInSubstreamHandshake::NotSent, + ), + }; + + handler.on_connection_event(handler::ConnectionEvent::FullyNegotiatedInbound( + handler::FullyNegotiatedInbound { protocol: (notif_in, 0), info: () }, + )); + + // verify that the substream is in (partly) opened state + assert!(std::matches!(handler.protocols[0].state, State::OpenDesiredByRemote { .. })); + futures::future::poll_fn(|cx| { + let mut buf = Vec::with_capacity(512); + assert!(std::matches!(Pin::new(&mut io2).poll_read(cx, &mut buf), Poll::Pending)); + Poll::Ready(()) + }) + .await; + + // attempt to open another inbound substream and verify that it is rejected + let (io, mut io2) = MockSubstream::negotiated().await; + let mut codec = UviBytes::default(); + codec.set_max_len(usize::MAX); + + let notif_in = NotificationsInOpen { + handshake: b"hello, world".to_vec(), + negotiated_fallback: None, + substream: NotificationsInSubstream::new( + Framed::new(io, codec), + NotificationsInSubstreamHandshake::NotSent, + ), + }; + + handler.on_connection_event(handler::ConnectionEvent::FullyNegotiatedInbound( + handler::FullyNegotiatedInbound { protocol: (notif_in, 0), info: () }, + )); + + // verify that the new substream is rejected and closed + futures::future::poll_fn(|cx| { + let mut buf = Vec::with_capacity(512); + + if let Poll::Ready(Err(err)) = Pin::new(&mut io2).poll_read(cx, &mut buf) { + assert_eq!(err.kind(), std::io::ErrorKind::UnexpectedEof,); + } + + Poll::Ready(()) + }) + .await; + } + + #[tokio::test] + async fn open_rejected_if_substream_is_opening() { + let mut handler = notifs_handler(); + let (io, mut io2) = MockSubstream::negotiated().await; + let mut codec = UviBytes::default(); + codec.set_max_len(usize::MAX); + + let notif_in = NotificationsInOpen { + handshake: b"hello, world".to_vec(), + negotiated_fallback: None, + substream: NotificationsInSubstream::new( + Framed::new(io, codec), + NotificationsInSubstreamHandshake::NotSent, + ), + }; + + handler.on_connection_event(handler::ConnectionEvent::FullyNegotiatedInbound( + handler::FullyNegotiatedInbound { protocol: (notif_in, 0), info: () }, + )); + + // verify that the substream is in (partly) opened state + assert!(std::matches!(handler.protocols[0].state, State::OpenDesiredByRemote { .. })); + futures::future::poll_fn(|cx| { + let mut buf = Vec::with_capacity(512); + assert!(std::matches!(Pin::new(&mut io2).poll_read(cx, &mut buf), Poll::Pending)); + Poll::Ready(()) + }) + .await; + + // move the handler state to 'Opening' + handler.on_behaviour_event(NotifsHandlerIn::Open { protocol_index: 0 }); + assert!(std::matches!( + handler.protocols[0].state, + State::Opening { in_substream: Some(_) } + )); + + // remote now tries to open another substream, verify that it is rejected and closed + let (io, mut io2) = MockSubstream::negotiated().await; + let mut codec = UviBytes::default(); + codec.set_max_len(usize::MAX); + + let notif_in = NotificationsInOpen { + handshake: b"hello, world".to_vec(), + negotiated_fallback: None, + substream: NotificationsInSubstream::new( + Framed::new(io, codec), + NotificationsInSubstreamHandshake::NotSent, + ), + }; + + handler.on_connection_event(handler::ConnectionEvent::FullyNegotiatedInbound( + handler::FullyNegotiatedInbound { protocol: (notif_in, 0), info: () }, + )); + + // verify that the new substream is rejected and closed but that the first substream is + // still in correct state + futures::future::poll_fn(|cx| { + let mut buf = Vec::with_capacity(512); + + if let Poll::Ready(Err(err)) = Pin::new(&mut io2).poll_read(cx, &mut buf) { + assert_eq!(err.kind(), std::io::ErrorKind::UnexpectedEof,); + } else { + panic!("unexpected result"); + } + + Poll::Ready(()) + }) + .await; + assert!(std::matches!( + handler.protocols[0].state, + State::Opening { in_substream: Some(_) } + )); + } + + #[tokio::test] + async fn open_rejected_if_substream_already_open() { + let mut handler = notifs_handler(); + let (io, mut io2) = MockSubstream::negotiated().await; + let mut codec = UviBytes::default(); + codec.set_max_len(usize::MAX); + + let notif_in = NotificationsInOpen { + handshake: b"hello, world".to_vec(), + negotiated_fallback: None, + substream: NotificationsInSubstream::new( + Framed::new(io, codec), + NotificationsInSubstreamHandshake::NotSent, + ), + }; + handler.on_connection_event(handler::ConnectionEvent::FullyNegotiatedInbound( + handler::FullyNegotiatedInbound { protocol: (notif_in, 0), info: () }, + )); + + // verify that the substream is in (partly) opened state + assert!(std::matches!(handler.protocols[0].state, State::OpenDesiredByRemote { .. })); + futures::future::poll_fn(|cx| { + let mut buf = Vec::with_capacity(512); + assert!(std::matches!(Pin::new(&mut io2).poll_read(cx, &mut buf), Poll::Pending)); + Poll::Ready(()) + }) + .await; + + // move the handler state to 'Opening' + handler.on_behaviour_event(NotifsHandlerIn::Open { protocol_index: 0 }); + assert!(std::matches!( + handler.protocols[0].state, + State::Opening { in_substream: Some(_) } + )); + + // accept the substream and move its state to `Open` + let (io, _io2) = MockSubstream::negotiated().await; + let mut codec = UviBytes::default(); + codec.set_max_len(usize::MAX); + + let notif_out = NotificationsOutOpen { + handshake: b"hello, world".to_vec(), + negotiated_fallback: None, + substream: NotificationsOutSubstream::new(Framed::new(io, codec)), + }; + handler.on_connection_event(handler::ConnectionEvent::FullyNegotiatedOutbound( + handler::FullyNegotiatedOutbound { protocol: notif_out, info: 0 }, + )); + + assert!(std::matches!( + handler.protocols[0].state, + State::Open { in_substream: Some(_), .. } + )); + + // remote now tries to open another substream, verify that it is rejected and closed + let (io, mut io2) = MockSubstream::negotiated().await; + let mut codec = UviBytes::default(); + codec.set_max_len(usize::MAX); + let notif_in = NotificationsInOpen { + handshake: b"hello, world".to_vec(), + negotiated_fallback: None, + substream: NotificationsInSubstream::new( + Framed::new(io, codec), + NotificationsInSubstreamHandshake::NotSent, + ), + }; + handler.on_connection_event(handler::ConnectionEvent::FullyNegotiatedInbound( + handler::FullyNegotiatedInbound { protocol: (notif_in, 0), info: () }, + )); + + // verify that the new substream is rejected and closed but that the first substream is + // still in correct state + futures::future::poll_fn(|cx| { + let mut buf = Vec::with_capacity(512); + + if let Poll::Ready(Err(err)) = Pin::new(&mut io2).poll_read(cx, &mut buf) { + assert_eq!(err.kind(), std::io::ErrorKind::UnexpectedEof); + } else { + panic!("unexpected result"); + } + + Poll::Ready(()) + }) + .await; + assert!(std::matches!( + handler.protocols[0].state, + State::Open { in_substream: Some(_), .. } + )); + } + + #[tokio::test] + async fn fully_negotiated_resets_state_for_closed_substream() { + let mut handler = notifs_handler(); + let (io, mut io2) = MockSubstream::negotiated().await; + let mut codec = UviBytes::default(); + codec.set_max_len(usize::MAX); + + let notif_in = NotificationsInOpen { + handshake: b"hello, world".to_vec(), + negotiated_fallback: None, + substream: NotificationsInSubstream::new( + Framed::new(io, codec), + NotificationsInSubstreamHandshake::NotSent, + ), + }; + handler.on_connection_event(handler::ConnectionEvent::FullyNegotiatedInbound( + handler::FullyNegotiatedInbound { protocol: (notif_in, 0), info: () }, + )); + + // verify that the substream is in (partly) opened state + assert!(std::matches!(handler.protocols[0].state, State::OpenDesiredByRemote { .. })); + futures::future::poll_fn(|cx| { + let mut buf = Vec::with_capacity(512); + assert!(std::matches!(Pin::new(&mut io2).poll_read(cx, &mut buf), Poll::Pending)); + Poll::Ready(()) + }) + .await; + + // first instruct the handler to open a connection and then close it right after + // so the handler is in state `Closed { pending_opening: true }` + handler.on_behaviour_event(NotifsHandlerIn::Open { protocol_index: 0 }); + assert!(std::matches!( + handler.protocols[0].state, + State::Opening { in_substream: Some(_) } + )); + + handler.on_behaviour_event(NotifsHandlerIn::Close { protocol_index: 0 }); + assert!(std::matches!(handler.protocols[0].state, State::Closed { pending_opening: true })); + + // verify that if the the outbound substream is successfully negotiated, the state is not + // changed as the substream was commanded to be closed by the handler. + let (io, _io2) = MockSubstream::negotiated().await; + let mut codec = UviBytes::default(); + codec.set_max_len(usize::MAX); + + let notif_out = NotificationsOutOpen { + handshake: b"hello, world".to_vec(), + negotiated_fallback: None, + substream: NotificationsOutSubstream::new(Framed::new(io, codec)), + }; + handler.on_connection_event(handler::ConnectionEvent::FullyNegotiatedOutbound( + handler::FullyNegotiatedOutbound { protocol: notif_out, info: 0 }, + )); + + assert!(std::matches!( + handler.protocols[0].state, + State::Closed { pending_opening: false } + )); + } + + #[tokio::test] + async fn fully_negotiated_resets_state_for_open_desired_substream() { + let mut handler = notifs_handler(); + let (io, mut io2) = MockSubstream::negotiated().await; + let mut codec = UviBytes::default(); + codec.set_max_len(usize::MAX); + + let notif_in = NotificationsInOpen { + handshake: b"hello, world".to_vec(), + negotiated_fallback: None, + substream: NotificationsInSubstream::new( + Framed::new(io, codec), + NotificationsInSubstreamHandshake::NotSent, + ), + }; + handler.on_connection_event(handler::ConnectionEvent::FullyNegotiatedInbound( + handler::FullyNegotiatedInbound { protocol: (notif_in, 0), info: () }, + )); + + // verify that the substream is in (partly) opened state + assert!(std::matches!(handler.protocols[0].state, State::OpenDesiredByRemote { .. })); + futures::future::poll_fn(|cx| { + let mut buf = Vec::with_capacity(512); + assert!(std::matches!(Pin::new(&mut io2).poll_read(cx, &mut buf), Poll::Pending)); + Poll::Ready(()) + }) + .await; + + // first instruct the handler to open a connection and then close it right after + // so the handler is in state `Closed { pending_opening: true }` + handler.on_behaviour_event(NotifsHandlerIn::Open { protocol_index: 0 }); + assert!(std::matches!( + handler.protocols[0].state, + State::Opening { in_substream: Some(_) } + )); + + handler.on_behaviour_event(NotifsHandlerIn::Close { protocol_index: 0 }); + assert!(std::matches!(handler.protocols[0].state, State::Closed { pending_opening: true })); + + // attempt to open another inbound substream and verify that it is rejected + let (io, _io2) = MockSubstream::negotiated().await; + let mut codec = UviBytes::default(); + codec.set_max_len(usize::MAX); + + let notif_in = NotificationsInOpen { + handshake: b"hello, world".to_vec(), + negotiated_fallback: None, + substream: NotificationsInSubstream::new( + Framed::new(io, codec), + NotificationsInSubstreamHandshake::NotSent, + ), + }; + handler.on_connection_event(handler::ConnectionEvent::FullyNegotiatedInbound( + handler::FullyNegotiatedInbound { protocol: (notif_in, 0), info: () }, + )); + + assert!(std::matches!( + handler.protocols[0].state, + State::OpenDesiredByRemote { pending_opening: true, .. } + )); + + // verify that if the the outbound substream is successfully negotiated, the state is not + // changed as the substream was commanded to be closed by the handler. + let (io, _io2) = MockSubstream::negotiated().await; + let mut codec = UviBytes::default(); + codec.set_max_len(usize::MAX); + + let notif_out = NotificationsOutOpen { + handshake: b"hello, world".to_vec(), + negotiated_fallback: None, + substream: NotificationsOutSubstream::new(Framed::new(io, codec)), + }; + + handler.on_connection_event(handler::ConnectionEvent::FullyNegotiatedOutbound( + handler::FullyNegotiatedOutbound { protocol: notif_out, info: 0 }, + )); + + assert!(std::matches!( + handler.protocols[0].state, + State::OpenDesiredByRemote { pending_opening: false, .. } + )); + } + + #[tokio::test] + async fn dial_upgrade_error_resets_closed_outbound_state() { + let mut handler = notifs_handler(); + let (io, mut io2) = MockSubstream::negotiated().await; + let mut codec = UviBytes::default(); + codec.set_max_len(usize::MAX); + + let notif_in = NotificationsInOpen { + handshake: b"hello, world".to_vec(), + negotiated_fallback: None, + substream: NotificationsInSubstream::new( + Framed::new(io, codec), + NotificationsInSubstreamHandshake::NotSent, + ), + }; + handler.on_connection_event(handler::ConnectionEvent::FullyNegotiatedInbound( + handler::FullyNegotiatedInbound { protocol: (notif_in, 0), info: () }, + )); + + // verify that the substream is in (partly) opened state + assert!(std::matches!(handler.protocols[0].state, State::OpenDesiredByRemote { .. })); + futures::future::poll_fn(|cx| { + let mut buf = Vec::with_capacity(512); + assert!(std::matches!(Pin::new(&mut io2).poll_read(cx, &mut buf), Poll::Pending)); + Poll::Ready(()) + }) + .await; + + // first instruct the handler to open a connection and then close it right after + // so the handler is in state `Closed { pending_opening: true }` + handler.on_behaviour_event(NotifsHandlerIn::Open { protocol_index: 0 }); + assert!(std::matches!( + handler.protocols[0].state, + State::Opening { in_substream: Some(_) } + )); + + handler.on_behaviour_event(NotifsHandlerIn::Close { protocol_index: 0 }); + assert!(std::matches!(handler.protocols[0].state, State::Closed { pending_opening: true })); + + // inject dial failure to an already closed substream and verify outbound state is reset + handler.on_connection_event(handler::ConnectionEvent::DialUpgradeError( + handler::DialUpgradeError { info: 0, error: ConnectionHandlerUpgrErr::Timeout }, + )); + assert!(std::matches!( + handler.protocols[0].state, + State::Closed { pending_opening: false } + )); + } + + #[tokio::test] + async fn dial_upgrade_error_resets_open_desired_state() { + let mut handler = notifs_handler(); + let (io, mut io2) = MockSubstream::negotiated().await; + let mut codec = UviBytes::default(); + codec.set_max_len(usize::MAX); + + let notif_in = NotificationsInOpen { + handshake: b"hello, world".to_vec(), + negotiated_fallback: None, + substream: NotificationsInSubstream::new( + Framed::new(io, codec), + NotificationsInSubstreamHandshake::NotSent, + ), + }; + handler.on_connection_event(handler::ConnectionEvent::FullyNegotiatedInbound( + handler::FullyNegotiatedInbound { protocol: (notif_in, 0), info: () }, + )); + + // verify that the substream is in (partly) opened state + assert!(std::matches!(handler.protocols[0].state, State::OpenDesiredByRemote { .. })); + futures::future::poll_fn(|cx| { + let mut buf = Vec::with_capacity(512); + assert!(std::matches!(Pin::new(&mut io2).poll_read(cx, &mut buf), Poll::Pending)); + Poll::Ready(()) + }) + .await; + + // first instruct the handler to open a connection and then close it right after + // so the handler is in state `Closed { pending_opening: true }` + handler.on_behaviour_event(NotifsHandlerIn::Open { protocol_index: 0 }); + assert!(std::matches!( + handler.protocols[0].state, + State::Opening { in_substream: Some(_) } + )); + + handler.on_behaviour_event(NotifsHandlerIn::Close { protocol_index: 0 }); + assert!(std::matches!(handler.protocols[0].state, State::Closed { pending_opening: true })); + + let (io, _io2) = MockSubstream::negotiated().await; + let mut codec = UviBytes::default(); + codec.set_max_len(usize::MAX); + + let notif_in = NotificationsInOpen { + handshake: b"hello, world".to_vec(), + negotiated_fallback: None, + substream: NotificationsInSubstream::new( + Framed::new(io, codec), + NotificationsInSubstreamHandshake::NotSent, + ), + }; + handler.on_connection_event(handler::ConnectionEvent::FullyNegotiatedInbound( + handler::FullyNegotiatedInbound { protocol: (notif_in, 0), info: () }, + )); + + assert!(std::matches!( + handler.protocols[0].state, + State::OpenDesiredByRemote { pending_opening: true, .. } + )); + + // inject dial failure to an already closed substream and verify outbound state is reset + handler.on_connection_event(handler::ConnectionEvent::DialUpgradeError( + handler::DialUpgradeError { info: 0, error: ConnectionHandlerUpgrErr::Timeout }, + )); + assert!(std::matches!( + handler.protocols[0].state, + State::OpenDesiredByRemote { pending_opening: false, .. } + )); + } + + #[tokio::test] + async fn sync_notifications_clogged() { + let mut handler = notifs_handler(); + let (io, _) = MockSubstream::negotiated().await; + let codec = UviBytes::default(); + + let (async_tx, async_rx) = futures::channel::mpsc::channel(ASYNC_NOTIFICATIONS_BUFFER_SIZE); + let (sync_tx, sync_rx) = futures::channel::mpsc::channel(1); + let notifications_sink = NotificationsSink { + inner: Arc::new(NotificationsSinkInner { + peer_id: PeerId::random(), + async_channel: FuturesMutex::new(async_tx), + sync_channel: Mutex::new(Some(sync_tx)), + }), + }; + + handler.protocols[0].state = State::Open { + notifications_sink_rx: stream::select(async_rx.fuse(), sync_rx.fuse()).peekable(), + out_substream: Some(NotificationsOutSubstream::new(Framed::new(io, codec))), + in_substream: None, + }; + + notifications_sink.send_sync_notification(vec![1, 3, 3, 7]); + notifications_sink.send_sync_notification(vec![1, 3, 3, 8]); + notifications_sink.send_sync_notification(vec![1, 3, 3, 9]); + notifications_sink.send_sync_notification(vec![1, 3, 4, 0]); + + futures::future::poll_fn(|cx| { + assert!(std::matches!( + handler.poll(cx), + Poll::Ready(ConnectionHandlerEvent::Close( + NotifsHandlerError::SyncNotificationsClogged, + )) + )); + Poll::Ready(()) + }) + .await; + } + + #[tokio::test] + async fn close_desired_by_remote() { + let mut handler = notifs_handler(); + let (io, io2) = MockSubstream::negotiated().await; + let mut codec = UviBytes::default(); + codec.set_max_len(usize::MAX); + + let notif_in = NotificationsInOpen { + handshake: b"hello, world".to_vec(), + negotiated_fallback: None, + substream: NotificationsInSubstream::new( + Framed::new(io, codec), + NotificationsInSubstreamHandshake::PendingSend(vec![1, 2, 3, 4]), + ), + }; + + // add new inbound substream but close it immediately and verify that correct events are + // emitted + handler.on_connection_event(handler::ConnectionEvent::FullyNegotiatedInbound( + handler::FullyNegotiatedInbound { protocol: (notif_in, 0), info: () }, + )); + drop(io2); + + futures::future::poll_fn(|cx| { + assert!(std::matches!( + handler.poll(cx), + Poll::Ready(ConnectionHandlerEvent::Custom( + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + )) + )); + assert!(std::matches!( + handler.poll(cx), + Poll::Ready(ConnectionHandlerEvent::Custom(NotifsHandlerOut::CloseDesired { + protocol_index: 0 + },)) + )); + Poll::Ready(()) + }) + .await; + } +} diff --git a/client/network/src/protocol/notifications/upgrade.rs b/client/network/src/protocol/notifications/upgrade.rs index c273361acabdd..89fede25f6ae7 100644 --- a/client/network/src/protocol/notifications/upgrade.rs +++ b/client/network/src/protocol/notifications/upgrade.rs @@ -20,8 +20,8 @@ pub use self::{ collec::UpgradeCollec, notifications::{ NotificationsHandshakeError, NotificationsIn, NotificationsInOpen, - NotificationsInSubstream, NotificationsOut, NotificationsOutError, NotificationsOutOpen, - NotificationsOutSubstream, + NotificationsInSubstream, NotificationsInSubstreamHandshake, NotificationsOut, + NotificationsOutError, NotificationsOutOpen, NotificationsOutSubstream, }, }; diff --git a/client/network/src/protocol/notifications/upgrade/collec.rs b/client/network/src/protocol/notifications/upgrade/collec.rs index db9850c8da74b..288b8bfd4849c 100644 --- a/client/network/src/protocol/notifications/upgrade/collec.rs +++ b/client/network/src/protocol/notifications/upgrade/collec.rs @@ -73,7 +73,7 @@ where } /// Groups a `ProtocolName` with a `usize`. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub struct ProtoNameWithUsize(T, usize); impl ProtocolName for ProtoNameWithUsize { @@ -99,3 +99,81 @@ impl>, O, E> Future for FutWithUsize { } } } + +#[cfg(test)] +mod tests { + use super::*; + use libp2p::core::upgrade::{ProtocolName, UpgradeInfo}; + use sc_network_common::protocol::ProtocolName as ProtoName; + + // TODO: move to mocks + mockall::mock! { + pub ProtocolUpgrade {} + + impl UpgradeInfo for ProtocolUpgrade { + type Info = T; + type InfoIter = vec::IntoIter; + fn protocol_info(&self) -> vec::IntoIter; + } + } + + #[test] + fn protocol_info() { + let upgrades = (1..=3) + .map(|i| { + let mut upgrade = MockProtocolUpgrade::>::new(); + upgrade.expect_protocol_info().return_once(move || { + vec![ProtoNameWithUsize(ProtoName::from(format!("protocol{i}")), i)].into_iter() + }); + upgrade + }) + .collect::>(); + + let upgrade: UpgradeCollec<_> = upgrades.into_iter().collect::>(); + let protos = vec![ + ProtoNameWithUsize(ProtoNameWithUsize(ProtoName::from("protocol1".to_string()), 1), 0), + ProtoNameWithUsize(ProtoNameWithUsize(ProtoName::from("protocol2".to_string()), 2), 1), + ProtoNameWithUsize(ProtoNameWithUsize(ProtoName::from("protocol3".to_string()), 3), 2), + ]; + let upgrades = upgrade.protocol_info().collect::>(); + + assert_eq!(upgrades, protos,); + } + + #[test] + fn nested_protocol_info() { + let mut upgrades = (1..=2) + .map(|i| { + let mut upgrade = MockProtocolUpgrade::>::new(); + upgrade.expect_protocol_info().return_once(move || { + vec![ProtoNameWithUsize(ProtoName::from(format!("protocol{i}")), i)].into_iter() + }); + upgrade + }) + .collect::>(); + + upgrades.push({ + let mut upgrade = MockProtocolUpgrade::>::new(); + upgrade.expect_protocol_info().return_once(move || { + vec![ + ProtoNameWithUsize(ProtoName::from("protocol22".to_string()), 1), + ProtoNameWithUsize(ProtoName::from("protocol33".to_string()), 2), + ProtoNameWithUsize(ProtoName::from("protocol44".to_string()), 3), + ] + .into_iter() + }); + upgrade + }); + + let upgrade: UpgradeCollec<_> = upgrades.into_iter().collect::>(); + let protos = vec![ + ProtoNameWithUsize(ProtoNameWithUsize(ProtoName::from("protocol1".to_string()), 1), 0), + ProtoNameWithUsize(ProtoNameWithUsize(ProtoName::from("protocol2".to_string()), 2), 1), + ProtoNameWithUsize(ProtoNameWithUsize(ProtoName::from("protocol22".to_string()), 1), 2), + ProtoNameWithUsize(ProtoNameWithUsize(ProtoName::from("protocol33".to_string()), 2), 2), + ProtoNameWithUsize(ProtoNameWithUsize(ProtoName::from("protocol44".to_string()), 3), 2), + ]; + let upgrades = upgrade.protocol_info().collect::>(); + assert_eq!(upgrades, protos,); + } +} diff --git a/client/network/src/protocol/notifications/upgrade/notifications.rs b/client/network/src/protocol/notifications/upgrade/notifications.rs index 5a4ec832dbea1..71afc3c90e37f 100644 --- a/client/network/src/protocol/notifications/upgrade/notifications.rs +++ b/client/network/src/protocol/notifications/upgrade/notifications.rs @@ -88,7 +88,8 @@ pub struct NotificationsInSubstream { } /// State of the handshake sending back process. -enum NotificationsInSubstreamHandshake { +#[derive(Debug)] +pub enum NotificationsInSubstreamHandshake { /// Waiting for the user to give us the handshake message. NotSent, /// User gave us the handshake message. Trying to push it in the socket. @@ -111,6 +112,13 @@ pub struct NotificationsOutSubstream { socket: Framed>>>, } +#[cfg(test)] +impl NotificationsOutSubstream { + pub fn new(socket: Framed>>>) -> Self { + Self { socket } + } +} + impl NotificationsIn { /// Builds a new potential upgrade. pub fn new( @@ -193,6 +201,14 @@ impl NotificationsInSubstream where TSubstream: AsyncRead + AsyncWrite + Unpin, { + #[cfg(test)] + pub fn new( + socket: Framed>>>, + handshake: NotificationsInSubstreamHandshake, + ) -> Self { + Self { socket, handshake } + } + /// Sends the handshake in order to inform the remote that we accept the substream. pub fn send_handshake(&mut self, message: impl Into>) { if !matches!(self.handshake, NotificationsInSubstreamHandshake::NotSent) { diff --git a/client/network/sync/Cargo.toml b/client/network/sync/Cargo.toml index ff72b4e993026..532e873836204 100644 --- a/client/network/sync/Cargo.toml +++ b/client/network/sync/Cargo.toml @@ -23,7 +23,7 @@ futures = "0.3.21" libp2p = "0.50.0" log = "0.4.17" lru = "0.8.1" -mockall = "0.11.2" +mockall = "0.11.3" prost = "0.11" smallvec = "1.8.0" thiserror = "1.0" From 6a504b063cf66351b6e352ef18cc18d49146487b Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Wed, 8 Feb 2023 11:37:36 -0300 Subject: [PATCH 374/715] Configurable voting-degree in council elections pallet (#13305) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * configurable council elections pallet * configurable council elections pallet * add warning * reduce sizes * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_elections_phragmen * fix stuff * make assert * fix docs * fix docs again * fix docs again * Update frame/elections-phragmen/src/lib.rs Co-authored-by: Gonçalo Pestana * Update frame/elections-phragmen/src/lib.rs Co-authored-by: Gonçalo Pestana * Update frame/elections-phragmen/src/lib.rs Co-authored-by: Gonçalo Pestana * fix docs --------- Co-authored-by: command-bot <> Co-authored-by: Gonçalo Pestana --- bin/node/runtime/src/lib.rs | 6 +- frame/elections-phragmen/src/benchmarking.rs | 88 +----- frame/elections-phragmen/src/lib.rs | 96 +++++-- frame/elections-phragmen/src/weights.rs | 265 +++++++++--------- .../procedural/src/construct_runtime/mod.rs | 1 + 5 files changed, 216 insertions(+), 240 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 3f4c464241f8d..4298a6eced430 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1003,8 +1003,9 @@ 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 MaxVotesPerVoter: u32 = 16; + pub const MaxVoters: u32 = 512; + pub const MaxCandidates: u32 = 64; pub const ElectionsPhragmenPalletId: LockIdentifier = *b"phrelect"; } @@ -1029,6 +1030,7 @@ impl pallet_elections_phragmen::Config for Runtime { type DesiredRunnersUp = DesiredRunnersUp; type TermDuration = TermDuration; type MaxVoters = MaxVoters; + type MaxVotesPerVoter = MaxVotesPerVoter; 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 1fc500a8e3464..b7c04bad318b0 100644 --- a/frame/elections-phragmen/src/benchmarking.rs +++ b/frame/elections-phragmen/src/benchmarking.rs @@ -148,7 +148,7 @@ fn clean() { benchmarks! { // -- Signed ones vote_equal { - let v in 1 .. (MAXIMUM_VOTE as u32); + let v in 1 .. T::MaxVotesPerVoter::get(); clean::(); // create a bunch of candidates. @@ -168,7 +168,7 @@ benchmarks! { }: vote(RawOrigin::Signed(caller), votes, stake) vote_more { - let v in 2 .. (MAXIMUM_VOTE as u32); + let v in 2 .. T::MaxVotesPerVoter::get(); clean::(); // create a bunch of candidates. @@ -190,7 +190,7 @@ benchmarks! { }: vote(RawOrigin::Signed(caller), votes, stake / >::from(10u32)) vote_less { - let v in 2 .. (MAXIMUM_VOTE as u32); + let v in 2 .. T::MaxVotesPerVoter::get(); clean::(); // create a bunch of candidates. @@ -212,7 +212,7 @@ benchmarks! { remove_voter { // we fix the number of voted candidates to max - let v = MAXIMUM_VOTE as u32; + let v = T::MaxVotesPerVoter::get(); clean::(); // create a bunch of candidates. @@ -368,7 +368,7 @@ benchmarks! { clean::(); let all_candidates = submit_candidates::(T::MaxCandidates::get(), "candidates")?; - distribute_voters::(all_candidates, v, MAXIMUM_VOTE)?; + distribute_voters::(all_candidates, v, T::MaxVotesPerVoter::get() as usize)?; // all candidates leave. >::kill(); @@ -389,17 +389,17 @@ benchmarks! { // that we give all candidates a self vote to make sure they are all considered. 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; + let e in (T::MaxVoters::get()) .. T::MaxVoters::get() * T::MaxVotesPerVoter::get(); clean::(); // so we have a situation with v and e. we want e to basically always be in the range of `e - // -> e * MAXIMUM_VOTE`, but we cannot express that now with the benchmarks. So what we do - // is: when c is being iterated, v, and e are max and fine. when v is being iterated, e is - // being set to max and this is a problem. In these cases, we cap e to a lower value, namely - // v * MAXIMUM_VOTE. when e is being iterated, v is at max, and again fine. all in all, - // votes_per_voter can never be more than MAXIMUM_VOTE. Note that this might cause `v` to be - // an overestimate. - let votes_per_voter = (e / v).min(MAXIMUM_VOTE as u32); + // -> e * T::MaxVotesPerVoter::get()`, but we cannot express that now with the benchmarks. + // So what we do is: when c is being iterated, v, and e are max and fine. when v is being + // iterated, e is being set to max and this is a problem. In these cases, we cap e to a + // lower value, namely v * T::MaxVotesPerVoter::get(). when e is being iterated, v is at + // max, and again fine. all in all, votes_per_voter can never be more than + // T::MaxVotesPerVoter::get(). Note that this might cause `v` to be an overestimate. + let votes_per_voter = (e / v).min(T::MaxVotesPerVoter::get()); let all_candidates = submit_candidates_with_self_vote::(c, "candidates")?; let _ = distribute_voters::(all_candidates, v.saturating_sub(c), votes_per_voter as usize)?; @@ -421,68 +421,6 @@ benchmarks! { } } - #[extra] - election_phragmen_c_e { - 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; - - let all_candidates = submit_candidates_with_self_vote::(c, "candidates")?; - let _ = distribute_voters::( - all_candidates, - fixed_v - c, - votes_per_voter as usize, - )?; - }: { - >::on_initialize(T::TermDuration::get()); - } - verify { - assert_eq!(>::members().len() as u32, T::DesiredMembers::get().min(c)); - assert_eq!( - >::runners_up().len() as u32, - T::DesiredRunnersUp::get().min(c.saturating_sub(T::DesiredMembers::get())), - ); - - #[cfg(test)] - { - // reset members in between benchmark tests. - use crate::tests::MEMBERS; - MEMBERS.with(|m| *m.borrow_mut() = vec![]); - } - } - - #[extra] - election_phragmen_v { - let v in 4 .. 16; - let fixed_c = T::MaxCandidates::get() / 10; - let fixed_e = 64; - clean::(); - - let votes_per_voter = fixed_e / v; - - let all_candidates = submit_candidates_with_self_vote::(fixed_c, "candidates")?; - let _ = distribute_voters::(all_candidates, v, votes_per_voter as usize)?; - }: { - >::on_initialize(T::TermDuration::get()); - } - verify { - assert_eq!(>::members().len() as u32, T::DesiredMembers::get().min(fixed_c)); - assert_eq!( - >::runners_up().len() as u32, - T::DesiredRunnersUp::get().min(fixed_c.saturating_sub(T::DesiredMembers::get())), - ); - - #[cfg(test)] - { - // reset members in between benchmark tests. - use crate::tests::MEMBERS; - MEMBERS.with(|m| *m.borrow_mut() = vec![]); - } - } - impl_benchmark_test_suite!( Elections, crate::tests::ExtBuilder::default().desired_members(13).desired_runners_up(7), diff --git a/frame/elections-phragmen/src/lib.rs b/frame/elections-phragmen/src/lib.rs index 1a020adb28632..c655d4a16230b 100644 --- a/frame/elections-phragmen/src/lib.rs +++ b/frame/elections-phragmen/src/lib.rs @@ -43,14 +43,14 @@ //! ### Voting //! //! Voters can vote for a limited number of the candidates by providing a list of account ids, -//! bounded by [`MAXIMUM_VOTE`]. Invalid votes (voting for non-candidates) and duplicate votes are -//! ignored during election. Yet, a voter _might_ vote for a future candidate. Voters reserve a bond -//! as they vote. Each vote defines a `value`. This amount is locked from the account of the voter -//! and indicates the weight of the vote. Voters can update their votes at any time by calling -//! `vote()` again. This can update the vote targets (which might update the deposit) or update the -//! vote's stake ([`Voter::stake`]). After a round, votes are kept and might still be valid for -//! further rounds. A voter is responsible for calling `remove_voter` once they are done to have -//! their bond back and remove the lock. +//! bounded by [`Config::MaxVotesPerVoter`]. Invalid votes (voting for non-candidates) and duplicate +//! votes are ignored during election. Yet, a voter _might_ vote for a future candidate. Voters +//! reserve a bond as they vote. Each vote defines a `value`. This amount is locked from the account +//! of the voter and indicates the weight of the vote. Voters can update their votes at any time by +//! calling `vote()` again. This can update the vote targets (which might update the deposit) or +//! update the vote's stake ([`Voter::stake`]). After a round, votes are kept and might still be +//! valid for further rounds. A voter is responsible for calling `remove_voter` once they are done +//! to have their bond back and remove the lock. //! //! See [`Call::vote`], [`Call::remove_voter`]. //! @@ -124,9 +124,6 @@ pub mod migrations; const LOG_TARGET: &str = "runtime::elections-phragmen"; -/// The maximum votes allowed per voter. -pub const MAXIMUM_VOTE: usize = 16; - type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; type NegativeImbalanceOf = <::Currency as Currency< @@ -254,19 +251,29 @@ pub mod pallet { /// 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. + /// Warning: This impacts the size of the election which is run onchain. Chose wisely, and + /// consider how it will impact `T::WeightInfo::election_phragmen`. + /// + /// 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. + /// Warning: This impacts the size of the election which is run onchain. Chose wisely, and + /// consider how it will impact `T::WeightInfo::election_phragmen`. + /// /// When the limit is reached the new voters are ignored. #[pallet::constant] type MaxVoters: Get; + /// Maximum numbers of votes per voter. + /// + /// Warning: This impacts the size of the election which is run onchain. Chose wisely, and + /// consider how it will impact `T::WeightInfo::election_phragmen`. + #[pallet::constant] + type MaxVotesPerVoter: Get; + /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; } @@ -284,6 +291,41 @@ pub mod pallet { Weight::zero() } } + + fn integrity_test() { + let block_weight = T::BlockWeights::get().max_block; + // mind the order. + let election_weight = T::WeightInfo::election_phragmen( + T::MaxCandidates::get(), + T::MaxVoters::get(), + T::MaxVotesPerVoter::get() * T::MaxVoters::get(), + ); + + let to_seconds = |w: &Weight| { + w.ref_time() as f32 / + frame_support::weights::constants::WEIGHT_REF_TIME_PER_SECOND as f32 + }; + + frame_support::log::debug!( + target: LOG_TARGET, + "election weight {}s ({:?}) // chain's block weight {}s ({:?})", + to_seconds(&election_weight), + election_weight, + to_seconds(&block_weight), + block_weight, + ); + assert!( + election_weight.all_lt(block_weight), + "election weight {}s ({:?}) will exceed a {}s chain's block weight ({:?}) (MaxCandidates {}, MaxVoters {}, MaxVotesPerVoter {} -- tweak these parameters)", + election_weight, + to_seconds(&election_weight), + to_seconds(&block_weight), + block_weight, + T::MaxCandidates::get(), + T::MaxVoters::get(), + T::MaxVotesPerVoter::get(), + ); + } } #[pallet::call] @@ -307,10 +349,6 @@ pub mod pallet { /// /// It is the responsibility of the caller to **NOT** place all of their balance into the /// lock and keep some for further operations. - /// - /// # - /// 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) @@ -324,8 +362,10 @@ pub mod pallet { ) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; - // votes should not be empty and more than `MAXIMUM_VOTE` in any case. - ensure!(votes.len() <= MAXIMUM_VOTE, Error::::MaximumVotesExceeded); + ensure!( + votes.len() <= T::MaxVotesPerVoter::get() as usize, + Error::::MaximumVotesExceeded + ); ensure!(!votes.is_empty(), Error::::NoVotes); let candidates_count = >::decode_len().unwrap_or(0); @@ -1006,7 +1046,7 @@ impl Pallet { // 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) + // 15x multiplier, an so on... (assuming `T::MaxVotesPerVoter` = 16) let mut prime_votes = new_members_sorted_by_id .iter() .map(|c| (&c.0, BalanceOf::::zero())) @@ -1014,7 +1054,7 @@ impl Pallet { 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) + ((T::MaxVotesPerVoter::get() as usize - 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] @@ -1173,16 +1213,9 @@ mod tests { }; use substrate_test_utils::assert_eq_uvec; - parameter_types! { - pub BlockWeights: frame_system::limits::BlockWeights = - 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 { type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = BlockWeights; + type BlockWeights = (); type BlockLength = (); type DbWeight = (); type RuntimeOrigin = RuntimeOrigin; @@ -1297,6 +1330,7 @@ mod tests { type KickedMember = (); type WeightInfo = (); type MaxVoters = PhragmenMaxVoters; + type MaxVotesPerVoter = ConstU32<16>; type MaxCandidates = PhragmenMaxCandidates; } diff --git a/frame/elections-phragmen/src/weights.rs b/frame/elections-phragmen/src/weights.rs index dc5d937e33eaf..a13dadf210ec0 100644 --- a/frame/elections-phragmen/src/weights.rs +++ b/frame/elections-phragmen/src/weights.rs @@ -18,25 +18,26 @@ //! Autogenerated weights for pallet_elections_phragmen //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-02-03, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `runner-b3zmxxc-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! 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_elections_phragmen // --extrinsic=* // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/elections-phragmen/src/weights.rs +// --json-file=/builds/parity/mirrors/substrate/.git/.artifacts/bench.json +// --pallet=pallet_elections_phragmen +// --chain=dev // --header=./HEADER-APACHE2 +// --output=./frame/elections-phragmen/src/weights.rs // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -80,10 +81,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `499 + v * (80 ±0)` // Estimated: `9726 + v * (320 ±0)` - // Minimum execution time: 25_407 nanoseconds. - Weight::from_parts(26_035_742, 9726) - // Standard Error: 2_162 - .saturating_add(Weight::from_ref_time(120_321).saturating_mul(v.into())) + // Minimum execution time: 27_362 nanoseconds. + Weight::from_parts(28_497_963, 9726) + // Standard Error: 3_968 + .saturating_add(Weight::from_ref_time(176_840).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(Weight::from_proof_size(320).saturating_mul(v.into())) @@ -103,10 +104,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `467 + v * (80 ±0)` // Estimated: `9598 + v * (320 ±0)` - // Minimum execution time: 34_477 nanoseconds. - Weight::from_parts(35_197_694, 9598) - // Standard Error: 2_089 - .saturating_add(Weight::from_ref_time(116_792).saturating_mul(v.into())) + // Minimum execution time: 37_120 nanoseconds. + Weight::from_parts(38_455_302, 9598) + // Standard Error: 5_478 + .saturating_add(Weight::from_ref_time(219_678).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(Weight::from_proof_size(320).saturating_mul(v.into())) @@ -126,10 +127,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `499 + v * (80 ±0)` // Estimated: `9726 + v * (320 ±0)` - // Minimum execution time: 34_573 nanoseconds. - Weight::from_parts(35_254_508, 9726) - // Standard Error: 2_076 - .saturating_add(Weight::from_ref_time(110_656).saturating_mul(v.into())) + // Minimum execution time: 36_928 nanoseconds. + Weight::from_parts(38_334_669, 9726) + // Standard Error: 5_271 + .saturating_add(Weight::from_ref_time(232_355).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(Weight::from_proof_size(320).saturating_mul(v.into())) @@ -142,8 +143,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `989` // Estimated: `7238` - // Minimum execution time: 31_469 nanoseconds. - Weight::from_parts(31_877_000, 7238) + // Minimum execution time: 34_338 nanoseconds. + Weight::from_parts(35_672_000, 7238) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -153,30 +154,30 @@ impl WeightInfo for SubstrateWeight { /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) /// Storage: Elections RunnersUp (r:1 w:0) /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `c` is `[1, 1000]`. + /// The range of component `c` is `[1, 64]`. fn submit_candidacy(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1687 + c * (48 ±0)` - // Estimated: `6540 + c * (144 ±0)` - // Minimum execution time: 26_969 nanoseconds. - Weight::from_parts(28_584_266, 6540) - // Standard Error: 93 - .saturating_add(Weight::from_ref_time(52_393).saturating_mul(c.into())) + // Measured: `1697 + c * (48 ±0)` + // Estimated: `6576 + c * (144 ±0)` + // Minimum execution time: 31_864 nanoseconds. + Weight::from_parts(33_490_161, 6576) + // Standard Error: 2_643 + .saturating_add(Weight::from_ref_time(158_386).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_proof_size(144).saturating_mul(c.into())) } /// Storage: Elections Candidates (r:1 w:1) /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `c` is `[1, 1000]`. + /// The range of component `c` is `[1, 64]`. fn renounce_candidacy_candidate(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `348 + c * (48 ±0)` - // Estimated: `830 + c * (48 ±0)` - // Minimum execution time: 23_635 nanoseconds. - Weight::from_parts(23_482_193, 830) - // Standard Error: 103 - .saturating_add(Weight::from_ref_time(33_759).saturating_mul(c.into())) + // Measured: `349 + c * (48 ±0)` + // Estimated: `844 + c * (48 ±0)` + // Minimum execution time: 27_292 nanoseconds. + Weight::from_parts(28_364_955, 844) + // Standard Error: 1_335 + .saturating_add(Weight::from_ref_time(78_086).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_proof_size(48).saturating_mul(c.into())) @@ -195,8 +196,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `2027` // Estimated: `12115` - // Minimum execution time: 39_124 nanoseconds. - Weight::from_parts(39_575_000, 12115) + // Minimum execution time: 45_975 nanoseconds. + Weight::from_parts(47_103_000, 12115) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -206,8 +207,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `975` // Estimated: `1470` - // Minimum execution time: 25_377 nanoseconds. - Weight::from_parts(25_696_000, 1470) + // Minimum execution time: 29_243 nanoseconds. + Weight::from_parts(30_582_000, 1470) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -236,12 +237,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `2027` // Estimated: `14718` - // Minimum execution time: 44_919 nanoseconds. - Weight::from_parts(45_548_000, 14718) + // Minimum execution time: 52_527 nanoseconds. + Weight::from_parts(53_538_000, 14718) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } - /// Storage: Elections Voting (r:10001 w:10000) + /// Storage: Elections Voting (r:513 w:512) /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) /// Storage: Elections Members (r:1 w:0) /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) @@ -249,24 +250,24 @@ impl WeightInfo for SubstrateWeight { /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) /// Storage: Elections Candidates (r:1 w:0) /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Balances Locks (r:10000 w:10000) + /// Storage: Balances Locks (r:512 w:512) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: System Account (r:10000 w:10000) + /// Storage: System Account (r:512 w:512) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// The range of component `v` is `[5000, 10000]`. - /// The range of component `d` is `[0, 5000]`. + /// The range of component `v` is `[256, 512]`. + /// The range of component `d` is `[0, 256]`. fn clean_defunct_voters(v: u32, _d: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `36028 + v * (872 ±0)` - // Estimated: `149172 + v * (12340 ±0)` - // Minimum execution time: 297_544_939 nanoseconds. - Weight::from_parts(298_088_024_000, 149172) - // Standard Error: 264_599 - .saturating_add(Weight::from_ref_time(38_142_857).saturating_mul(v.into())) + // Measured: `1115 + v * (875 ±0)` + // Estimated: `8448 + v * (12352 ±0)` + // Minimum execution time: 14_934_185 nanoseconds. + Weight::from_parts(15_014_057_000, 8448) + // Standard Error: 245_588 + .saturating_add(Weight::from_ref_time(35_586_946).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(v.into()))) - .saturating_add(Weight::from_proof_size(12340).saturating_mul(v.into())) + .saturating_add(Weight::from_proof_size(12352).saturating_mul(v.into())) } /// Storage: Elections Candidates (r:1 w:1) /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) @@ -274,11 +275,11 @@ impl WeightInfo for SubstrateWeight { /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) /// Storage: Elections RunnersUp (r:1 w:1) /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections Voting (r:10001 w:0) + /// Storage: Elections Voting (r:513 w:0) /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) /// Storage: Council Proposals (r:1 w:0) /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: System Account (r:980 w:980) + /// Storage: System Account (r:44 w:44) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: Elections ElectionRounds (r:1 w:1) /// Proof Skipped: Elections ElectionRounds (max_values: Some(1), max_size: None, mode: Measured) @@ -286,27 +287,27 @@ impl WeightInfo for SubstrateWeight { /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) /// Storage: Council Prime (r:0 w:1) /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `c` is `[1, 1000]`. - /// The range of component `v` is `[1, 10000]`. - /// The range of component `e` is `[10000, 160000]`. + /// The range of component `c` is `[1, 64]`. + /// The range of component `v` is `[1, 512]`. + /// The range of component `e` is `[512, 8192]`. fn election_phragmen(c: u32, v: u32, e: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0 + v * (639 ±0) + e * (28 ±0)` - // Estimated: `5350105 + c * (2582 ±0) + v * (5721 ±6) + e * (123 ±0)` - // Minimum execution time: 21_844_965 nanoseconds. - Weight::from_parts(21_979_826_000, 5350105) - // Standard Error: 229_799 - .saturating_add(Weight::from_ref_time(24_976_612).saturating_mul(v.into())) - // Standard Error: 14_747 - .saturating_add(Weight::from_ref_time(1_025_848).saturating_mul(e.into())) - .saturating_add(T::DbWeight::get().reads(280_u64)) + // Measured: `0 + v * (638 ±0) + e * (28 ±0)` + // Estimated: `330033 + v * (5229 ±6) + e * (89 ±0) + c * (2135 ±7)` + // Minimum execution time: 1_273_671 nanoseconds. + Weight::from_parts(1_279_716_000, 330033) + // Standard Error: 543_277 + .saturating_add(Weight::from_ref_time(20_613_753).saturating_mul(v.into())) + // Standard Error: 34_857 + .saturating_add(Weight::from_ref_time(688_354).saturating_mul(e.into())) + .saturating_add(T::DbWeight::get().reads(21_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(c.into()))) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().writes(6_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(c.into()))) - .saturating_add(Weight::from_proof_size(2582).saturating_mul(c.into())) - .saturating_add(Weight::from_proof_size(5721).saturating_mul(v.into())) - .saturating_add(Weight::from_proof_size(123).saturating_mul(e.into())) + .saturating_add(Weight::from_proof_size(5229).saturating_mul(v.into())) + .saturating_add(Weight::from_proof_size(89).saturating_mul(e.into())) + .saturating_add(Weight::from_proof_size(2135).saturating_mul(c.into())) } } @@ -327,10 +328,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `499 + v * (80 ±0)` // Estimated: `9726 + v * (320 ±0)` - // Minimum execution time: 25_407 nanoseconds. - Weight::from_parts(26_035_742, 9726) - // Standard Error: 2_162 - .saturating_add(Weight::from_ref_time(120_321).saturating_mul(v.into())) + // Minimum execution time: 27_362 nanoseconds. + Weight::from_parts(28_497_963, 9726) + // Standard Error: 3_968 + .saturating_add(Weight::from_ref_time(176_840).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(Weight::from_proof_size(320).saturating_mul(v.into())) @@ -350,10 +351,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `467 + v * (80 ±0)` // Estimated: `9598 + v * (320 ±0)` - // Minimum execution time: 34_477 nanoseconds. - Weight::from_parts(35_197_694, 9598) - // Standard Error: 2_089 - .saturating_add(Weight::from_ref_time(116_792).saturating_mul(v.into())) + // Minimum execution time: 37_120 nanoseconds. + Weight::from_parts(38_455_302, 9598) + // Standard Error: 5_478 + .saturating_add(Weight::from_ref_time(219_678).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(Weight::from_proof_size(320).saturating_mul(v.into())) @@ -373,10 +374,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `499 + v * (80 ±0)` // Estimated: `9726 + v * (320 ±0)` - // Minimum execution time: 34_573 nanoseconds. - Weight::from_parts(35_254_508, 9726) - // Standard Error: 2_076 - .saturating_add(Weight::from_ref_time(110_656).saturating_mul(v.into())) + // Minimum execution time: 36_928 nanoseconds. + Weight::from_parts(38_334_669, 9726) + // Standard Error: 5_271 + .saturating_add(Weight::from_ref_time(232_355).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(Weight::from_proof_size(320).saturating_mul(v.into())) @@ -389,8 +390,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `989` // Estimated: `7238` - // Minimum execution time: 31_469 nanoseconds. - Weight::from_parts(31_877_000, 7238) + // Minimum execution time: 34_338 nanoseconds. + Weight::from_parts(35_672_000, 7238) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -400,30 +401,30 @@ impl WeightInfo for () { /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) /// Storage: Elections RunnersUp (r:1 w:0) /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `c` is `[1, 1000]`. + /// The range of component `c` is `[1, 64]`. fn submit_candidacy(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1687 + c * (48 ±0)` - // Estimated: `6540 + c * (144 ±0)` - // Minimum execution time: 26_969 nanoseconds. - Weight::from_parts(28_584_266, 6540) - // Standard Error: 93 - .saturating_add(Weight::from_ref_time(52_393).saturating_mul(c.into())) + // Measured: `1697 + c * (48 ±0)` + // Estimated: `6576 + c * (144 ±0)` + // Minimum execution time: 31_864 nanoseconds. + Weight::from_parts(33_490_161, 6576) + // Standard Error: 2_643 + .saturating_add(Weight::from_ref_time(158_386).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_proof_size(144).saturating_mul(c.into())) } /// Storage: Elections Candidates (r:1 w:1) /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `c` is `[1, 1000]`. + /// The range of component `c` is `[1, 64]`. fn renounce_candidacy_candidate(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `348 + c * (48 ±0)` - // Estimated: `830 + c * (48 ±0)` - // Minimum execution time: 23_635 nanoseconds. - Weight::from_parts(23_482_193, 830) - // Standard Error: 103 - .saturating_add(Weight::from_ref_time(33_759).saturating_mul(c.into())) + // Measured: `349 + c * (48 ±0)` + // Estimated: `844 + c * (48 ±0)` + // Minimum execution time: 27_292 nanoseconds. + Weight::from_parts(28_364_955, 844) + // Standard Error: 1_335 + .saturating_add(Weight::from_ref_time(78_086).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_proof_size(48).saturating_mul(c.into())) @@ -442,8 +443,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `2027` // Estimated: `12115` - // Minimum execution time: 39_124 nanoseconds. - Weight::from_parts(39_575_000, 12115) + // Minimum execution time: 45_975 nanoseconds. + Weight::from_parts(47_103_000, 12115) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -453,8 +454,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `975` // Estimated: `1470` - // Minimum execution time: 25_377 nanoseconds. - Weight::from_parts(25_696_000, 1470) + // Minimum execution time: 29_243 nanoseconds. + Weight::from_parts(30_582_000, 1470) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -483,12 +484,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `2027` // Estimated: `14718` - // Minimum execution time: 44_919 nanoseconds. - Weight::from_parts(45_548_000, 14718) + // Minimum execution time: 52_527 nanoseconds. + Weight::from_parts(53_538_000, 14718) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } - /// Storage: Elections Voting (r:10001 w:10000) + /// Storage: Elections Voting (r:513 w:512) /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) /// Storage: Elections Members (r:1 w:0) /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) @@ -496,24 +497,24 @@ impl WeightInfo for () { /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) /// Storage: Elections Candidates (r:1 w:0) /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Balances Locks (r:10000 w:10000) + /// Storage: Balances Locks (r:512 w:512) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: System Account (r:10000 w:10000) + /// Storage: System Account (r:512 w:512) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// The range of component `v` is `[5000, 10000]`. - /// The range of component `d` is `[0, 5000]`. + /// The range of component `v` is `[256, 512]`. + /// The range of component `d` is `[0, 256]`. fn clean_defunct_voters(v: u32, _d: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `36028 + v * (872 ±0)` - // Estimated: `149172 + v * (12340 ±0)` - // Minimum execution time: 297_544_939 nanoseconds. - Weight::from_parts(298_088_024_000, 149172) - // Standard Error: 264_599 - .saturating_add(Weight::from_ref_time(38_142_857).saturating_mul(v.into())) + // Measured: `1115 + v * (875 ±0)` + // Estimated: `8448 + v * (12352 ±0)` + // Minimum execution time: 14_934_185 nanoseconds. + Weight::from_parts(15_014_057_000, 8448) + // Standard Error: 245_588 + .saturating_add(Weight::from_ref_time(35_586_946).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(v.into()))) .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(v.into()))) - .saturating_add(Weight::from_proof_size(12340).saturating_mul(v.into())) + .saturating_add(Weight::from_proof_size(12352).saturating_mul(v.into())) } /// Storage: Elections Candidates (r:1 w:1) /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) @@ -521,11 +522,11 @@ impl WeightInfo for () { /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) /// Storage: Elections RunnersUp (r:1 w:1) /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections Voting (r:10001 w:0) + /// Storage: Elections Voting (r:513 w:0) /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) /// Storage: Council Proposals (r:1 w:0) /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: System Account (r:980 w:980) + /// Storage: System Account (r:44 w:44) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: Elections ElectionRounds (r:1 w:1) /// Proof Skipped: Elections ElectionRounds (max_values: Some(1), max_size: None, mode: Measured) @@ -533,26 +534,26 @@ impl WeightInfo for () { /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) /// Storage: Council Prime (r:0 w:1) /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `c` is `[1, 1000]`. - /// The range of component `v` is `[1, 10000]`. - /// The range of component `e` is `[10000, 160000]`. + /// The range of component `c` is `[1, 64]`. + /// The range of component `v` is `[1, 512]`. + /// The range of component `e` is `[512, 8192]`. fn election_phragmen(c: u32, v: u32, e: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0 + v * (639 ±0) + e * (28 ±0)` - // Estimated: `5350105 + c * (2582 ±0) + v * (5721 ±6) + e * (123 ±0)` - // Minimum execution time: 21_844_965 nanoseconds. - Weight::from_parts(21_979_826_000, 5350105) - // Standard Error: 229_799 - .saturating_add(Weight::from_ref_time(24_976_612).saturating_mul(v.into())) - // Standard Error: 14_747 - .saturating_add(Weight::from_ref_time(1_025_848).saturating_mul(e.into())) - .saturating_add(RocksDbWeight::get().reads(280_u64)) + // Measured: `0 + v * (638 ±0) + e * (28 ±0)` + // Estimated: `330033 + v * (5229 ±6) + e * (89 ±0) + c * (2135 ±7)` + // Minimum execution time: 1_273_671 nanoseconds. + Weight::from_parts(1_279_716_000, 330033) + // Standard Error: 543_277 + .saturating_add(Weight::from_ref_time(20_613_753).saturating_mul(v.into())) + // Standard Error: 34_857 + .saturating_add(Weight::from_ref_time(688_354).saturating_mul(e.into())) + .saturating_add(RocksDbWeight::get().reads(21_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(c.into()))) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(v.into()))) .saturating_add(RocksDbWeight::get().writes(6_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(c.into()))) - .saturating_add(Weight::from_proof_size(2582).saturating_mul(c.into())) - .saturating_add(Weight::from_proof_size(5721).saturating_mul(v.into())) - .saturating_add(Weight::from_proof_size(123).saturating_mul(e.into())) + .saturating_add(Weight::from_proof_size(5229).saturating_mul(v.into())) + .saturating_add(Weight::from_proof_size(89).saturating_mul(e.into())) + .saturating_add(Weight::from_proof_size(2135).saturating_mul(c.into())) } } diff --git a/frame/support/procedural/src/construct_runtime/mod.rs b/frame/support/procedural/src/construct_runtime/mod.rs index 9e22037a6782e..18b66ddff5ffa 100644 --- a/frame/support/procedural/src/construct_runtime/mod.rs +++ b/frame/support/procedural/src/construct_runtime/mod.rs @@ -579,6 +579,7 @@ fn decl_integrity_test(scrate: &TokenStream2) -> TokenStream2 { #[test] pub fn runtime_integrity_tests() { + #scrate::sp_tracing::try_init_simple(); ::integrity_test(); } } From 6f72780b87e41a025722284a52a7d85f41958a82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Wed, 8 Feb 2023 16:40:45 -0300 Subject: [PATCH 375/715] Rework generated API docs (#13178) --- frame/contracts/proc-macro/src/lib.rs | 219 +++++++++++++++----------- frame/contracts/src/wasm/mod.rs | 7 +- 2 files changed, 132 insertions(+), 94 deletions(-) diff --git a/frame/contracts/proc-macro/src/lib.rs b/frame/contracts/proc-macro/src/lib.rs index de7b9b881d305..c5f52f43a7d87 100644 --- a/frame/contracts/proc-macro/src/lib.rs +++ b/frame/contracts/proc-macro/src/lib.rs @@ -25,10 +25,12 @@ extern crate alloc; use alloc::{ + collections::BTreeMap, format, string::{String, ToString}, vec::Vec, }; +use core::cmp::Reverse; use proc_macro::TokenStream; use proc_macro2::{Span, TokenStream as TokenStream2}; use quote::{quote, quote_spanned, ToTokens}; @@ -160,7 +162,7 @@ struct EnvDef { /// Parsed host function definition. struct HostFn { item: syn::ItemFn, - module: String, + version: u8, name: String, returns: HostFnReturn, is_stable: bool, @@ -208,7 +210,7 @@ impl HostFn { let span = item.span(); let mut attrs = item.attrs.clone(); attrs.retain(|a| !a.path.is_ident("doc")); - let mut maybe_module = None; + let mut maybe_version = None; let mut is_stable = true; let mut alias_to = None; let mut not_deprecated = true; @@ -216,12 +218,11 @@ impl HostFn { let ident = attr.path.get_ident().ok_or(err(span, msg))?.to_string(); match ident.as_str() { "version" => { - if maybe_module.is_some() { + if maybe_version.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)); + maybe_version = + Some(attr.parse_args::().and_then(|lit| lit.base10_parse())?); }, "unstable" => { if !is_stable { @@ -341,7 +342,7 @@ impl HostFn { Ok(Self { item, - module: maybe_module.unwrap_or_else(|| "seal0".to_string()), + version: maybe_version.unwrap_or_default(), name, returns, is_stable, @@ -355,6 +356,10 @@ impl HostFn { _ => Err(err(span, &msg)), } } + + fn module(&self) -> String { + format!("seal{}", self.version) + } } impl EnvDef { @@ -409,83 +414,116 @@ fn is_valid_special_arg(idx: usize, arg: &FnArg) -> bool { matches!(*pat.ty, syn::Type::Infer(_)) } -/// Expands documentation for host functions. -fn expand_docs(def: &mut EnvDef) -> TokenStream2 { - let mut modules = def.host_funcs.iter().map(|f| f.module.clone()).collect::>(); - modules.sort(); - modules.dedup(); - - let doc_selector = |a: &syn::Attribute| a.path.is_ident("doc"); - let docs = modules.iter().map(|m| { - let funcs = def.host_funcs.iter_mut().map(|f| { - if *m == f.module { - // Remove auxiliary args: `ctx: _` and `memory: _` - f.item.sig.inputs = f - .item - .sig - .inputs - .iter() - .skip(2) - .map(|p| p.clone()) - .collect::>(); - let func_decl = f.item.sig.to_token_stream(); - let func_doc = if let Some(origin_fn) = &f.alias_to { - let alias_doc = format!( - "This is just an alias function to [`{0}()`][`Self::{0}`] with backwards-compatible prefixed identifier.", - origin_fn, - ); - quote! { #[doc = #alias_doc] } - - } else { - let func_docs = f.item.attrs.iter().filter(|a| doc_selector(a)).map(|d| { - let docs = d.to_token_stream(); - quote! { #docs } - }); - let unstable_notice = if !f.is_stable { - let warning = "\n # Unstable\n\n \ - This function is unstable and it is a subject to change (or removal) in the future.\n \ - Do not deploy a contract using it to a production chain."; - quote! { #[doc = #warning] } - } else { - quote! {} - }; - quote! { - #( #func_docs )* - #unstable_notice - } - }; - quote! { - #func_doc - #func_decl; - } - } else { - quote! {} - } - }); +fn expand_func_doc(func: &HostFn) -> TokenStream2 { + // Remove auxiliary args: `ctx: _` and `memory: _` + let func_decl = { + let mut sig = func.item.sig.clone(); + sig.inputs = sig + .inputs + .iter() + .skip(2) + .map(|p| p.clone()) + .collect::>(); + sig.to_token_stream() + }; + let func_doc = { + let func_docs = if let Some(origin_fn) = &func.alias_to { + let alias_doc = format!( + "This is just an alias function to [`{0}()`][`Self::{0}`] with backwards-compatible prefixed identifier.", + origin_fn, + ); + quote! { #[doc = #alias_doc] } + } else { + let docs = func.item.attrs.iter().filter(|a| a.path.is_ident("doc")).map(|d| { + let docs = d.to_token_stream(); + quote! { #docs } + }); + quote! { #( #docs )* } + }; + let deprecation_notice = if !func.not_deprecated { + let warning = "\n # Deprecated\n\n \ + This function is deprecated and will be removed in future versions.\n \ + No new code or contracts with this API can be deployed."; + quote! { #[doc = #warning] } + } else { + quote! {} + }; + let import_notice = { + let info = format!( + "\n# Wasm Import Statement\n```wat\n(import \"seal{}\" \"{}\" (func ...))\n```", + func.version, func.name, + ); + quote! { #[doc = #info] } + }; + let unstable_notice = if !func.is_stable { + let warning = "\n # Unstable\n\n \ + This function is unstable and it is a subject to change (or removal) in the future.\n \ + Do not deploy a contract using it to a production chain."; + quote! { #[doc = #warning] } + } else { + quote! {} + }; + quote! { + #deprecation_notice + #func_docs + #import_notice + #unstable_notice + } + }; + quote! { + #func_doc + #func_decl; + } +} - let module = Ident::new(m, Span::call_site()); - let module_doc = format!( - "Documentation of the API available to contracts by importing `{}` WASM module.", - module - ); +/// Expands documentation for host functions. +fn expand_docs(def: &EnvDef) -> TokenStream2 { + // Create the `Current` trait with only the newest versions + // we sort so that only the newest versions make it into `docs` + let mut current_docs = BTreeMap::new(); + let mut funcs: Vec<_> = def.host_funcs.iter().filter(|f| f.alias_to.is_none()).collect(); + funcs.sort_unstable_by_key(|func| Reverse(func.version)); + for func in funcs { + if current_docs.contains_key(&func.name) { + continue + } + current_docs.insert(func.name.clone(), expand_func_doc(&func)); + } + let current_docs = current_docs.values(); + // Create the `legacy` module with all functions + // Maps from version to list of functions that have this version + let mut legacy_doc = BTreeMap::>::new(); + for func in def.host_funcs.iter() { + legacy_doc.entry(func.version).or_default().push(expand_func_doc(&func)); + } + let legacy_doc = legacy_doc.into_iter().map(|(version, funcs)| { + let doc = format!("All functions available in the **seal{}** module", version); + let version = Ident::new(&format!("Version{version}"), Span::call_site()); quote! { - #[doc = #module_doc] - pub mod #module { - use crate::wasm::runtime::{TrapReason, ReturnCode}; - /// Every function in this trait represents (at least) one function that can be imported by a contract. - /// - /// The function's identifier is to be set as the name in the import definition. - /// Where it is specifically indicated, an _alias_ function having `seal_`-prefixed identifier and - /// just the same signature and body, is also available (for backwards-compatibility purposes). - pub trait Api { - #( #funcs )* - } + #[doc = #doc] + pub trait #version { + #( #funcs )* } } }); + quote! { - #( #docs )* + /// Contains only the latest version of each function. + /// + /// In reality there are more functions available but they are all obsolete: When a function + /// is updated a new **version** is added and the old versions stays available as-is. + /// We only list the newest version here. Some functions are available under additional + /// names (aliases) for historic reasons which are omitted here. + /// + /// If you want an overview of all the functions available to a contact all you need + /// to look at is this trait. It contains only the latest version of each + /// function and no aliases. If you are writing a contract(language) from scratch + /// this is where you should look at. + pub trait Current { + #( #current_docs )* + } + #( #legacy_doc )* } } @@ -493,25 +531,26 @@ fn expand_docs(def: &mut EnvDef) -> TokenStream2 { /// Should generate source code for: /// - implementations of the host functions to be added to the wasm runtime environment (see /// `expand_impls()`). -fn expand_env(def: &mut EnvDef, docs: bool) -> TokenStream2 { +fn expand_env(def: &EnvDef, docs: bool) -> TokenStream2 { let impls = expand_impls(def); let docs = docs.then_some(expand_docs(def)).unwrap_or(TokenStream2::new()); quote! { pub struct Env; #impls - /// Contains the documentation of the API available to contracts. + /// Documentation of the API (host functions) available to contracts. /// - /// In order to generate this documentation, pass `doc` attribute to the [`#[define_env]`][`macro@define_env`] macro: - /// `#[define_env(doc)]`, and then run `cargo doc`. + /// The `Current` trait might be the most useful doc to look at. The versioned + /// traits only exist for reference: If trying to find out if a specific version of + /// `pallet-contracts` contains a certain function. /// - /// This module is not meant to be used by any code. Rather, it is meant to be consumed by humans through rustdoc. + /// # Note /// - /// Every function described in this module's sub module's traits uses this sub module's identifier - /// as its imported module name. The identifier of the function is the function's imported name. - /// According to the [WASM spec of imports](https://webassembly.github.io/spec/core/text/modules.html#text-import). + /// This module is not meant to be used by any code. Rather, it is meant to be + /// consumed by humans through rustdoc. #[cfg(doc)] pub mod api_doc { + use super::{TrapReason, ReturnCode}; #docs } } @@ -520,7 +559,7 @@ fn expand_env(def: &mut EnvDef, docs: bool) -> TokenStream2 { /// 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 { +fn expand_impls(def: &EnvDef) -> TokenStream2 { let impls = expand_functions(def, true, quote! { crate::wasm::Runtime }); let dummy_impls = expand_functions(def, false, quote! { () }); @@ -553,16 +592,12 @@ fn expand_impls(def: &mut EnvDef) -> TokenStream2 { } } -fn expand_functions( - def: &mut EnvDef, - expand_blocks: bool, - host_state: TokenStream2, -) -> TokenStream2 { +fn expand_functions(def: &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.module(), &f.name, &f.item.block, f.returns.to_wasm_sig(), diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index 6b9cefcdd2d96..9bf36b47f0b06 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -24,8 +24,13 @@ mod runtime; #[cfg(feature = "runtime-benchmarks")] pub use crate::wasm::code_cache::reinstrument; + #[cfg(doc)] pub use crate::wasm::runtime::api_doc; + +#[cfg(test)] +pub use tests::MockExt; + pub use crate::wasm::{ prepare::TryInstantiate, runtime::{ @@ -45,8 +50,6 @@ use frame_support::dispatch::{DispatchError, DispatchResult}; use sp_core::Get; use sp_runtime::RuntimeDebug; use sp_std::prelude::*; -#[cfg(test)] -pub use tests::MockExt; use wasmi::{ Config as WasmiConfig, Engine, Instance, Linker, Memory, MemoryType, Module, StackLimits, Store, }; From 0d611e091178f220455e2ec929ce38b0e9be3253 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Thu, 9 Feb 2023 11:00:55 +0100 Subject: [PATCH 376/715] pallet-scheduler: Ensure we request a preimage (#13340) * pallet-scheduler: Ensure we request a preimage The scheduler was not requesting a preimage. When a preimage is requested, a user can deposit it without paying any fees. * Review changes --- frame/scheduler/src/lib.rs | 23 ++++++++++++++++-- frame/scheduler/src/tests.rs | 23 +++++++++++++----- frame/support/src/traits/preimages.rs | 35 ++++++++++++++++++--------- 3 files changed, 62 insertions(+), 19 deletions(-) diff --git a/frame/scheduler/src/lib.rs b/frame/scheduler/src/lib.rs index afc4fd66e76cb..dfec98d4e443a 100644 --- a/frame/scheduler/src/lib.rs +++ b/frame/scheduler/src/lib.rs @@ -777,6 +777,8 @@ impl Pallet { ) -> Result, DispatchError> { let when = Self::resolve_time(when)?; + let lookup_hash = call.lookup_hash(); + // sanitize maybe_periodic let maybe_periodic = maybe_periodic .filter(|p| p.1 > 1 && !p.0.is_zero()) @@ -790,7 +792,14 @@ impl Pallet { origin, _phantom: PhantomData, }; - Self::place_task(when, task).map_err(|x| x.0) + let res = Self::place_task(when, task).map_err(|x| x.0)?; + + if let Some(hash) = lookup_hash { + // Request the call to be made available. + T::Preimages::request(&hash); + } + + Ok(res) } fn do_cancel( @@ -862,6 +871,8 @@ impl Pallet { let when = Self::resolve_time(when)?; + let lookup_hash = call.lookup_hash(); + // sanitize maybe_periodic let maybe_periodic = maybe_periodic .filter(|p| p.1 > 1 && !p.0.is_zero()) @@ -876,7 +887,14 @@ impl Pallet { origin, _phantom: Default::default(), }; - Self::place_task(when, task).map_err(|x| x.0) + let res = Self::place_task(when, task).map_err(|x| x.0)?; + + if let Some(hash) = lookup_hash { + // Request the call to be made available. + T::Preimages::request(&hash); + } + + Ok(res) } fn do_cancel_named(origin: Option, id: TaskName) -> DispatchResult { @@ -1027,6 +1045,7 @@ impl Pallet { } else { Agenda::::remove(when); } + postponed == 0 } diff --git a/frame/scheduler/src/tests.rs b/frame/scheduler/src/tests.rs index e5467fc8db55f..a261c6718616d 100644 --- a/frame/scheduler/src/tests.rs +++ b/frame/scheduler/src/tests.rs @@ -58,9 +58,10 @@ fn scheduling_with_preimages_works() { RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) }); let hash = ::Hashing::hash_of(&call); 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())); + // Important to use here `Bounded::Lookup` to ensure that we request the hash. + let hashed = Bounded::Lookup { hash, len }; assert_ok!(Scheduler::do_schedule(DispatchTime::At(4), None, 127, root(), hashed)); + assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(0), call.encode())); assert!(Preimage::is_requested(&hash)); run_to_block(3); assert!(logger::log().is_empty()); @@ -479,8 +480,10 @@ fn scheduler_handles_periodic_unavailable_preimage() { 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())); + // Important to use here `Bounded::Lookup` to ensure that we request the hash. + let bound = Bounded::Lookup { hash, len }; + // The preimage isn't requested yet. + assert!(!Preimage::is_requested(&hash)); assert_ok!(Scheduler::do_schedule( DispatchTime::At(4), @@ -489,11 +492,18 @@ fn scheduler_handles_periodic_unavailable_preimage() { root(), bound.clone(), )); + + // The preimage is requested. + assert!(Preimage::is_requested(&hash)); + + // Note the preimage. + assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(1), call.encode())); + // Executes 1 times till block 4. run_to_block(4); assert_eq!(logger::log().len(), 1); - // Unnote the preimage. + // Unnote the preimage Preimage::unnote(&hash); // Does not ever execute again. @@ -1129,7 +1139,8 @@ fn postponed_named_task_cannot_be_rescheduled() { 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); + // Important to use here `Bounded::Lookup` to ensure that we request the hash. + let hashed = Bounded::Lookup { hash, len }; let name: [u8; 32] = hash.as_ref().try_into().unwrap(); let address = Scheduler::do_schedule_named( diff --git a/frame/support/src/traits/preimages.rs b/frame/support/src/traits/preimages.rs index 594532ba96903..ce3537c792c08 100644 --- a/frame/support/src/traits/preimages.rs +++ b/frame/support/src/traits/preimages.rs @@ -26,6 +26,9 @@ use sp_std::borrow::Cow; pub type Hash = H256; pub type BoundedInline = crate::BoundedVec>; +/// The maximum we expect a single legacy hash lookup to be. +const MAX_LEGACY_LEN: u32 = 1_000_000; + #[derive( Encode, Decode, MaxEncodedLen, Clone, Eq, PartialEq, scale_info::TypeInfo, RuntimeDebug, )] @@ -67,20 +70,25 @@ impl Bounded { /// Returns the hash of the preimage. /// /// The hash is re-calculated every time if the preimage is inlined. - pub fn hash(&self) -> H256 { + pub fn hash(&self) -> Hash { use Bounded::*; match self { - Legacy { hash, .. } => *hash, + Lookup { hash, .. } | 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; + /// Returns the hash to lookup the preimage. + /// + /// If this is a `Bounded::Inline`, `None` is returned as no lookup is required. + pub fn lookup_hash(&self) -> Option { + use Bounded::*; + match self { + Lookup { hash, .. } | Legacy { hash, .. } => Some(*hash), + Inline(_) => None, + } + } -impl Bounded { /// Returns the length of the preimage or `None` if the length is unknown. pub fn len(&self) -> Option { match self { @@ -168,8 +176,11 @@ pub trait QueryPreimage { } } - /// Create a `Bounded` instance based on the `hash` and `len` of the encoded value. This may not - /// be `peek`-able or `realize`-able. + /// Create a `Bounded` instance based on the `hash` and `len` of the encoded value. + /// + /// It also directly requests the given `hash` using [`Self::request`]. + /// + /// This may not be `peek`-able or `realize`-able. fn pick(hash: Hash, len: u32) -> Bounded { Self::request(&hash); Bounded::Lookup { hash, len } @@ -228,10 +239,12 @@ pub trait StorePreimage: QueryPreimage { 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. + /// 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`. + /// The value is also noted using [`Self::note`]. fn bound(t: T) -> Result, DispatchError> { let data = t.encode(); let len = data.len() as u32; From 2ced413e40eed0e294fbc4c0d539bac2376016f6 Mon Sep 17 00:00:00 2001 From: Roman Useinov Date: Thu, 9 Feb 2023 12:47:39 +0100 Subject: [PATCH 377/715] [Fix] Try-state feature-gated for BagsList (#13296) * [Fix] Try-state feature-gated for BagsList * fix comment * fix try_state remote-tests * feature-gate try-state remote test for bags-list * remove try-state from a migration * more SortedListProvider fixes * more fixes * more fixes to allow do_try_state usage in other crates * do-try-state for fuzz * more fixes * more fixes * remove feature-flag * do-try-state * fix review comments * Update frame/bags-list/src/mock.rs Co-authored-by: Anton --------- Co-authored-by: parity-processbot <> Co-authored-by: Anton --- frame/bags-list/Cargo.toml | 2 +- frame/bags-list/fuzzer/src/main.rs | 2 +- frame/bags-list/remote-tests/Cargo.toml | 2 +- frame/bags-list/remote-tests/src/try_state.rs | 5 ++-- frame/bags-list/src/lib.rs | 10 +++++++- frame/bags-list/src/list/mod.rs | 17 +++++++------ frame/bags-list/src/list/tests.rs | 25 ++++++++++--------- frame/bags-list/src/mock.rs | 2 +- frame/election-provider-support/Cargo.toml | 1 + frame/election-provider-support/src/lib.rs | 3 ++- frame/staking/Cargo.toml | 2 +- frame/staking/src/migrations.rs | 1 - frame/staking/src/pallet/impls.rs | 4 +++ 13 files changed, 46 insertions(+), 30 deletions(-) diff --git a/frame/bags-list/Cargo.toml b/frame/bags-list/Cargo.toml index e3a4965f6c086..379698b1d39e1 100644 --- a/frame/bags-list/Cargo.toml +++ b/frame/bags-list/Cargo.toml @@ -75,4 +75,4 @@ fuzz = [ "sp-tracing", "frame-election-provider-support/fuzz", ] -try-runtime = [ "frame-support/try-runtime" ] +try-runtime = [ "frame-support/try-runtime", "frame-election-provider-support/try-runtime" ] diff --git a/frame/bags-list/fuzzer/src/main.rs b/frame/bags-list/fuzzer/src/main.rs index 9f7ca464cc2b8..c78e2a13076d5 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::try_state().is_ok()); + assert!(BagsList::do_try_state().is_ok()); }) }); } diff --git a/frame/bags-list/remote-tests/Cargo.toml b/frame/bags-list/remote-tests/Cargo.toml index 9fb6d0154b302..6e951b43a4aeb 100644 --- a/frame/bags-list/remote-tests/Cargo.toml +++ b/frame/bags-list/remote-tests/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] # frame pallet-staking = { path = "../../staking", version = "4.0.0-dev" } -pallet-bags-list = { path = "../../bags-list", version = "4.0.0-dev" } +pallet-bags-list = { path = "../../bags-list", version = "4.0.0-dev", features = ["fuzz"] } 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" } diff --git a/frame/bags-list/remote-tests/src/try_state.rs b/frame/bags-list/remote-tests/src/try_state.rs index 514c80d72ab67..9ed877a43afe1 100644 --- a/frame/bags-list/remote-tests/src/try_state.rs +++ b/frame/bags-list/remote-tests/src/try_state.rs @@ -16,7 +16,6 @@ //! 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}, @@ -51,7 +50,9 @@ 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::::do_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 14f8a613eb798..f04c685ae386c 100644 --- a/frame/bags-list/src/lib.rs +++ b/frame/bags-list/src/lib.rs @@ -274,6 +274,13 @@ pub mod pallet { } } +#[cfg(any(test, feature = "try-runtime", feature = "fuzz"))] +impl, I: 'static> Pallet { + pub fn do_try_state() -> Result<(), &'static str> { + List::::do_try_state() + } +} + impl, I: 'static> Pallet { /// Move an account from one bag to another, depositing an event on success. /// @@ -348,8 +355,9 @@ impl, I: 'static> SortedListProvider for Pallet List::::unsafe_regenerate(all, score_of) } + #[cfg(feature = "try-runtime")] fn try_state() -> Result<(), &'static str> { - List::::try_state() + Self::do_try_state() } fn unsafe_clear() { diff --git a/frame/bags-list/src/list/mod.rs b/frame/bags-list/src/list/mod.rs index 272526ad1a636..4082a5324091b 100644 --- a/frame/bags-list/src/list/mod.rs +++ b/frame/bags-list/src/list/mod.rs @@ -220,9 +220,6 @@ impl, I: 'static> List { crate::ListBags::::remove(removed_bag); } - #[cfg(feature = "std")] - debug_assert_eq!(Self::try_state(), Ok(())); - num_affected } @@ -514,7 +511,8 @@ 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`. - pub(crate) fn try_state() -> Result<(), &'static str> { + #[cfg(any(test, feature = "try-runtime", feature = "fuzz"))] + pub(crate) fn do_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)), @@ -542,7 +540,7 @@ impl, I: 'static> List { thresholds.into_iter().filter_map(|t| Bag::::get(t)) }; - let _ = active_bags.clone().try_for_each(|b| b.try_state())?; + let _ = active_bags.clone().try_for_each(|b| b.do_try_state())?; let nodes_in_bags_count = active_bags.clone().fold(0u32, |acc, cur| acc + cur.iter().count() as u32); @@ -553,7 +551,7 @@ 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.try_state()? + node.do_try_state()? } Ok(()) @@ -751,7 +749,8 @@ 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. - fn try_state(&self) -> Result<(), &'static str> { + #[cfg(any(test, feature = "try-runtime", feature = "fuzz"))] + fn do_try_state(&self) -> Result<(), &'static str> { frame_support::ensure!( self.head() .map(|head| head.prev().is_none()) @@ -790,6 +789,7 @@ impl, I: 'static> Bag { } /// Check if the bag contains a node with `id`. + #[cfg(any(test, feature = "try-runtime", feature = "fuzz"))] fn contains(&self, id: &T::AccountId) -> bool { self.iter().any(|n| n.id() == id) } @@ -894,7 +894,8 @@ impl, I: 'static> Node { self.bag_upper } - fn try_state(&self) -> Result<(), &'static str> { + #[cfg(any(test, feature = "try-runtime", feature = "fuzz"))] + fn do_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 966ea1a74c71c..3c4aa7c86634d 100644 --- a/frame/bags-list/src/list/tests.rs +++ b/frame/bags-list/src/list/tests.rs @@ -137,6 +137,7 @@ fn migrate_works() { BagThresholds::set(NEW_THRESHOLDS); // and we call List::::migrate(old_thresholds); + assert_eq!(List::::do_try_state(), Ok(())); // then assert_eq!( @@ -352,13 +353,13 @@ mod list { #[test] fn try_state_works() { ExtBuilder::default().build_and_execute_no_post_check(|| { - assert_ok!(List::::try_state()); + assert_ok!(List::::do_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::::try_state(), Err("duplicate identified")); + assert_eq!(List::::do_try_state(), Err("duplicate identified")); }); // ensure count is in sync with `ListNodes::count()`. @@ -372,7 +373,7 @@ mod list { CounterForListNodes::::mutate(|counter| *counter += 1); assert_eq!(crate::ListNodes::::count(), 5); - assert_eq!(List::::try_state(), Err("iter_count != stored_count")); + assert_eq!(List::::do_try_state(), Err("iter_count != stored_count")); }); } @@ -804,7 +805,7 @@ mod bags { // then assert_eq!(bag_as_ids(&bag_1000), vec![2, 3, 13, 14]); - assert_ok!(bag_1000.try_state()); + assert_ok!(bag_1000.do_try_state()); // and the node isn't mutated when its removed assert_eq!(node_4, node_4_pre_remove); @@ -814,7 +815,7 @@ mod bags { // then assert_eq!(bag_as_ids(&bag_1000), vec![3, 13, 14]); - assert_ok!(bag_1000.try_state()); + assert_ok!(bag_1000.do_try_state()); // when removing a tail that is not pointing at the head let node_14 = Node::::get(&14).unwrap(); @@ -822,7 +823,7 @@ mod bags { // then assert_eq!(bag_as_ids(&bag_1000), vec![3, 13]); - assert_ok!(bag_1000.try_state()); + assert_ok!(bag_1000.do_try_state()); // when removing a tail that is pointing at the head let node_13 = Node::::get(&13).unwrap(); @@ -830,7 +831,7 @@ mod bags { // then assert_eq!(bag_as_ids(&bag_1000), vec![3]); - assert_ok!(bag_1000.try_state()); + assert_ok!(bag_1000.do_try_state()); // when removing a node that is both the head & tail let node_3 = Node::::get(&3).unwrap(); @@ -846,7 +847,7 @@ mod bags { // then assert_eq!(bag_as_ids(&bag_10), vec![1, 12]); - assert_ok!(bag_10.try_state()); + assert_ok!(bag_10.do_try_state()); // when removing a head that is pointing at the tail let node_1 = Node::::get(&1).unwrap(); @@ -854,7 +855,7 @@ mod bags { // then assert_eq!(bag_as_ids(&bag_10), vec![12]); - assert_ok!(bag_10.try_state()); + assert_ok!(bag_10.do_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 +866,7 @@ mod bags { // then assert_eq!(bag_as_ids(&bag_2000), vec![15, 17, 18, 19]); - assert_ok!(bag_2000.try_state()); + assert_ok!(bag_2000.do_try_state()); // when removing a node that is pointing at tail, but not head let node_18 = Node::::get(&18).unwrap(); @@ -873,7 +874,7 @@ mod bags { // then assert_eq!(bag_as_ids(&bag_2000), vec![15, 17, 19]); - assert_ok!(bag_2000.try_state()); + assert_ok!(bag_2000.do_try_state()); // finally, when reading from storage, the state of all bags is as expected assert_eq!( @@ -905,7 +906,7 @@ mod bags { // .. and the bag it was removed from let bag_1000 = Bag::::get(1_000).unwrap(); // is sane - assert_ok!(bag_1000.try_state()); + assert_ok!(bag_1000.do_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 8cc96a988e72a..32f6bb09e4772 100644 --- a/frame/bags-list/src/mock.rs +++ b/frame/bags-list/src/mock.rs @@ -148,7 +148,7 @@ impl ExtBuilder { pub fn build_and_execute(self, test: impl FnOnce() -> ()) { self.build().execute_with(|| { test(); - List::::try_state().expect("Try-state post condition failed") + List::::do_try_state().expect("do_try_state post condition failed") }) } diff --git a/frame/election-provider-support/Cargo.toml b/frame/election-provider-support/Cargo.toml index c7f47e721d1aa..114caee793f1a 100644 --- a/frame/election-provider-support/Cargo.toml +++ b/frame/election-provider-support/Cargo.toml @@ -43,3 +43,4 @@ std = [ "sp-std/std", ] runtime-benchmarks = [] +try-runtime = [] diff --git a/frame/election-provider-support/src/lib.rs b/frame/election-provider-support/src/lib.rs index 9d5d6c018e5e1..9e60eb3be1a6f 100644 --- a/frame/election-provider-support/src/lib.rs +++ b/frame/election-provider-support/src/lib.rs @@ -562,7 +562,8 @@ pub trait SortedListProvider { /// unbounded amount of storage accesses. fn unsafe_clear(); - /// Check internal state of list. Only meant for debugging. + /// Check internal state of the list. Only meant for debugging. + #[cfg(feature = "try-runtime")] fn try_state() -> Result<(), &'static str>; /// If `who` changes by the returned amount they are guaranteed to have a worst case change diff --git a/frame/staking/Cargo.toml b/frame/staking/Cargo.toml index 3d5cf1161e8e5..79c0bb5c2a32d 100644 --- a/frame/staking/Cargo.toml +++ b/frame/staking/Cargo.toml @@ -74,4 +74,4 @@ runtime-benchmarks = [ "rand_chacha", "sp-staking/runtime-benchmarks", ] -try-runtime = ["frame-support/try-runtime"] +try-runtime = ["frame-support/try-runtime", "frame-election-provider-support/try-runtime"] diff --git a/frame/staking/src/migrations.rs b/frame/staking/src/migrations.rs index 6253c3feed17d..a8d360c098137 100644 --- a/frame/staking/src/migrations.rs +++ b/frame/staking/src/migrations.rs @@ -386,7 +386,6 @@ pub mod v8 { Nominators::::iter().map(|(id, _)| id), Pallet::::weight_of_fn(), ); - debug_assert_eq!(T::VoterList::try_state(), Ok(())); StorageVersion::::put(ObsoleteReleases::V8_0_0); crate::log!( diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index e59c2c5a0620e..6a35e2b861565 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -1451,9 +1451,11 @@ impl SortedListProvider for UseValidatorsMap { // nothing to do upon regenerate. 0 } + #[cfg(feature = "try-runtime")] fn try_state() -> Result<(), &'static str> { Ok(()) } + fn unsafe_clear() { #[allow(deprecated)] Validators::::remove_all(); @@ -1525,6 +1527,8 @@ impl SortedListProvider for UseNominatorsAndValidatorsM // nothing to do upon regenerate. 0 } + + #[cfg(feature = "try-runtime")] fn try_state() -> Result<(), &'static str> { Ok(()) } From 21d58f6f7b3ed2ea529f3c118b2e042b29551672 Mon Sep 17 00:00:00 2001 From: Javier Viola Date: Fri, 10 Feb 2023 11:11:10 -0300 Subject: [PATCH 378/715] bump version of zombienet and update snaps links (#13359) --- .gitlab-ci.yml | 2 +- zombienet/0001-basic-warp-sync/test-warp-sync.toml | 6 +++--- .../test-validators-warp-sync.toml | 6 +++--- .../test-block-building-warp-sync.toml | 6 +++--- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ae25a2c5953f5..ab3fd84d6e9ee 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -55,7 +55,7 @@ variables: RUSTY_CACHIER_COMPRESSION_METHOD: zstd NEXTEST_FAILURE_OUTPUT: immediate-final NEXTEST_SUCCESS_OUTPUT: final - ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.3.22" + ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.3.34" .shared-default: &shared-default retry: diff --git a/zombienet/0001-basic-warp-sync/test-warp-sync.toml b/zombienet/0001-basic-warp-sync/test-warp-sync.toml index ae2810b6ecccd..272b5862e8e89 100644 --- a/zombienet/0001-basic-warp-sync/test-warp-sync.toml +++ b/zombienet/0001-basic-warp-sync/test-warp-sync.toml @@ -11,18 +11,18 @@ 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" + db_snapshot="https://storage.googleapis.com/zombienet-db-snaps/substrate/0001-basic-warp-sync/chains-a233bbacff650aac6bcb56b4e4ef7db7dc143cfb.tgz" [[relaychain.nodes]] name = "bob" validator = false - db_snapshot="https://storage.googleapis.com/zombienet-db-snaps/substrate/0001-basic-warp-sync/chains-0bb3f0be2ce41b5615b224215bcc8363aa0416a6.tgz" + db_snapshot="https://storage.googleapis.com/zombienet-db-snaps/substrate/0001-basic-warp-sync/chains-a233bbacff650aac6bcb56b4e4ef7db7dc143cfb.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" + db_snapshot="https://storage.googleapis.com/zombienet-db-snaps/substrate/0001-basic-warp-sync/chains-a233bbacff650aac6bcb56b4e4ef7db7dc143cfb.tgz" [[relaychain.nodes]] name = "dave" diff --git a/zombienet/0002-validators-warp-sync/test-validators-warp-sync.toml b/zombienet/0002-validators-warp-sync/test-validators-warp-sync.toml index dae6e406f04da..df4414f5c8b5f 100644 --- a/zombienet/0002-validators-warp-sync/test-validators-warp-sync.toml +++ b/zombienet/0002-validators-warp-sync/test-validators-warp-sync.toml @@ -22,14 +22,14 @@ chain_spec_path = "zombienet/0002-validators-warp-sync/chain-spec.json" [[relaychain.nodes]] name = "charlie" validator = false - db_snapshot="https://storage.googleapis.com/zombienet-db-snaps/substrate/0001-basic-warp-sync/chains-0bb3f0be2ce41b5615b224215bcc8363aa0416a6.tgz" + db_snapshot="https://storage.googleapis.com/zombienet-db-snaps/substrate/0001-basic-warp-sync/chains-a233bbacff650aac6bcb56b4e4ef7db7dc143cfb.tgz" [[relaychain.nodes]] name = "dave" validator = false - db_snapshot="https://storage.googleapis.com/zombienet-db-snaps/substrate/0001-basic-warp-sync/chains-0bb3f0be2ce41b5615b224215bcc8363aa0416a6.tgz" + db_snapshot="https://storage.googleapis.com/zombienet-db-snaps/substrate/0001-basic-warp-sync/chains-a233bbacff650aac6bcb56b4e4ef7db7dc143cfb.tgz" [[relaychain.nodes]] name = "eve" validator = false - db_snapshot="https://storage.googleapis.com/zombienet-db-snaps/substrate/0001-basic-warp-sync/chains-0bb3f0be2ce41b5615b224215bcc8363aa0416a6.tgz" + db_snapshot="https://storage.googleapis.com/zombienet-db-snaps/substrate/0001-basic-warp-sync/chains-a233bbacff650aac6bcb56b4e4ef7db7dc143cfb.tgz" diff --git a/zombienet/0003-block-building-warp-sync/test-block-building-warp-sync.toml b/zombienet/0003-block-building-warp-sync/test-block-building-warp-sync.toml index 66176845cc78d..5119c919c70c4 100644 --- a/zombienet/0003-block-building-warp-sync/test-block-building-warp-sync.toml +++ b/zombienet/0003-block-building-warp-sync/test-block-building-warp-sync.toml @@ -12,17 +12,17 @@ chain_spec_path = "zombienet/0003-block-building-warp-sync/chain-spec.json" [[relaychain.nodes]] name = "alice" validator = true - db_snapshot="https://storage.googleapis.com/zombienet-db-snaps/substrate/0001-basic-warp-sync/chains-0bb3f0be2ce41b5615b224215bcc8363aa0416a6.tgz" + db_snapshot="https://storage.googleapis.com/zombienet-db-snaps/substrate/0001-basic-warp-sync/chains-a233bbacff650aac6bcb56b4e4ef7db7dc143cfb.tgz" [[relaychain.nodes]] name = "bob" validator = true - db_snapshot="https://storage.googleapis.com/zombienet-db-snaps/substrate/0001-basic-warp-sync/chains-0bb3f0be2ce41b5615b224215bcc8363aa0416a6.tgz" + db_snapshot="https://storage.googleapis.com/zombienet-db-snaps/substrate/0001-basic-warp-sync/chains-a233bbacff650aac6bcb56b4e4ef7db7dc143cfb.tgz" [[relaychain.nodes]] name = "charlie" validator = false - db_snapshot="https://storage.googleapis.com/zombienet-db-snaps/substrate/0001-basic-warp-sync/chains-0bb3f0be2ce41b5615b224215bcc8363aa0416a6.tgz" + db_snapshot="https://storage.googleapis.com/zombienet-db-snaps/substrate/0001-basic-warp-sync/chains-a233bbacff650aac6bcb56b4e4ef7db7dc143cfb.tgz" [[relaychain.nodes]] name = "dave" From ccd768ffc2b0f0282e1687794451841dcffda785 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Sat, 11 Feb 2023 18:35:04 +0100 Subject: [PATCH 379/715] Fix longest chain finalization target lookup (#13289) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Finalization target should be chosed as some ancestor of SelectChain::best_chain * More test assertions * Improve docs * Removed stale docs * Rename 'target' to 'base' in lookup method * Fix typo * Apply suggestions from code review Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> * Rename 'target_hash' to 'base_hash' in 'SelectChain::finality_target()' * Apply suggestions from code review Co-authored-by: Anton * Docs improvement * Doc fix * Apply suggestions from code review Co-authored-by: Bastian Köcher * Apply more code suggestions --------- Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> Co-authored-by: Anton Co-authored-by: Bastian Köcher --- client/consensus/common/src/longest_chain.rs | 80 ++++++- client/finality-grandpa/src/tests.rs | 2 +- client/service/test/src/client/mod.rs | 217 ++++++++++++------ primitives/blockchain/src/backend.rs | 84 ++----- .../consensus/common/src/select_chain.rs | 8 +- 5 files changed, 242 insertions(+), 149 deletions(-) diff --git a/client/consensus/common/src/longest_chain.rs b/client/consensus/common/src/longest_chain.rs index fab2c3a4c06fd..ece2486209ff3 100644 --- a/client/consensus/common/src/longest_chain.rs +++ b/client/consensus/common/src/longest_chain.rs @@ -21,7 +21,7 @@ use sc_client_api::backend; use sp_blockchain::{Backend, HeaderBackend}; use sp_consensus::{Error as ConsensusError, SelectChain}; -use sp_runtime::traits::{Block as BlockT, NumberFor}; +use sp_runtime::traits::{Block as BlockT, Header, NumberFor}; use std::{marker::PhantomData, sync::Arc}; /// Implement Longest Chain Select implementation @@ -48,15 +48,19 @@ where LongestChain { backend, _phantom: Default::default() } } - fn best_block_header(&self) -> sp_blockchain::Result<::Header> { + fn best_hash(&self) -> sp_blockchain::Result<::Hash> { let info = self.backend.blockchain().info(); let import_lock = self.backend.get_import_lock(); let best_hash = self .backend .blockchain() - .best_containing(info.best_hash, None, import_lock)? + .longest_containing(info.best_hash, import_lock)? .unwrap_or(info.best_hash); + Ok(best_hash) + } + fn best_header(&self) -> sp_blockchain::Result<::Header> { + let best_hash = self.best_hash()?; Ok(self .backend .blockchain() @@ -64,6 +68,65 @@ where .expect("given block hash was fetched from block in db; qed")) } + /// Returns the highest descendant of the given block that is a valid + /// candidate to be finalized. + /// + /// In this context, being a valid target means being an ancestor of + /// the best chain according to the `best_header` method. + /// + /// If `maybe_max_number` is `Some(max_block_number)` the search is + /// limited to block `number <= max_block_number`. In other words + /// as if there were no blocks greater than `max_block_number`. + fn finality_target( + &self, + base_hash: Block::Hash, + maybe_max_number: Option>, + ) -> sp_blockchain::Result { + use sp_blockchain::Error::{Application, MissingHeader}; + let blockchain = self.backend.blockchain(); + + let mut current_head = self.best_header()?; + let mut best_hash = current_head.hash(); + + let base_header = blockchain + .header(base_hash)? + .ok_or_else(|| MissingHeader(base_hash.to_string()))?; + let base_number = *base_header.number(); + + if let Some(max_number) = maybe_max_number { + if max_number < base_number { + let msg = format!( + "Requested a finality target using max number {} below the base number {}", + max_number, base_number + ); + return Err(Application(msg.into())) + } + + while current_head.number() > &max_number { + best_hash = *current_head.parent_hash(); + current_head = blockchain + .header(best_hash)? + .ok_or_else(|| MissingHeader(format!("{best_hash:?}")))?; + } + } + + while current_head.hash() != base_hash { + if *current_head.number() < base_number { + let msg = format!( + "Requested a finality target using a base {:?} not in the best chain {:?}", + base_hash, best_hash, + ); + return Err(Application(msg.into())) + } + let current_hash = *current_head.parent_hash(); + current_head = blockchain + .header(current_hash)? + .ok_or_else(|| MissingHeader(format!("{best_hash:?}")))?; + } + + Ok(best_hash) + } + fn leaves(&self) -> Result::Hash>, sp_blockchain::Error> { self.backend.blockchain().leaves() } @@ -80,20 +143,15 @@ where } async fn best_chain(&self) -> Result<::Header, ConsensusError> { - LongestChain::best_block_header(self) - .map_err(|e| ConsensusError::ChainLookup(e.to_string())) + LongestChain::best_header(self).map_err(|e| ConsensusError::ChainLookup(e.to_string())) } async fn finality_target( &self, - target_hash: Block::Hash, + base_hash: Block::Hash, maybe_max_number: Option>, ) -> 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)) + LongestChain::finality_target(self, base_hash, maybe_max_number) .map_err(|e| ConsensusError::ChainLookup(e.to_string())) } } diff --git a/client/finality-grandpa/src/tests.rs b/client/finality-grandpa/src/tests.rs index 07ea4649148fb..62ef4709e1909 100644 --- a/client/finality-grandpa/src/tests.rs +++ b/client/finality-grandpa/src/tests.rs @@ -237,7 +237,7 @@ impl SelectChain for MockSelectChain { async fn finality_target( &self, - _target_hash: Hash, + _base_hash: Hash, _maybe_max_number: Option>, ) -> Result { Ok(self.finality_target.lock().take().unwrap()) diff --git a/client/service/test/src/client/mod.rs b/client/service/test/src/client/mod.rs index 97c22a1cb509e..12b92afc458b4 100644 --- a/client/service/test/src/client/mod.rs +++ b/client/service/test/src/client/mod.rs @@ -581,7 +581,7 @@ fn uncles_with_multiple_forks() { } #[test] -fn best_containing_on_longest_chain_with_single_chain_3_blocks() { +fn finality_target_on_longest_chain_with_single_chain_3_blocks() { // block tree: // G -> A1 -> A2 @@ -606,7 +606,7 @@ fn best_containing_on_longest_chain_with_single_chain_3_blocks() { } #[test] -fn best_containing_on_longest_chain_with_multiple_forks() { +fn finality_target_on_longest_chain_with_multiple_forks() { // block tree: // G -> A1 -> A2 -> A3 -> A4 -> A5 // A1 -> B2 -> B3 -> B4 @@ -731,8 +731,13 @@ 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() + // On error we return a quite improbable hash + let error_hash = Hash::from([0xff; 32]); + let finality_target = |target_hash, number| match block_on( + longest_chain_select.finality_target(target_hash, number), + ) { + Ok(hash) => hash, + Err(_) => error_hash, }; // search without restriction @@ -742,11 +747,11 @@ fn best_containing_on_longest_chain_with_multiple_forks() { 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)); + assert_eq!(error_hash, finality_target(b2.hash(), None)); + assert_eq!(error_hash, finality_target(b3.hash(), None)); + assert_eq!(error_hash, finality_target(b4.hash(), None)); + assert_eq!(error_hash, finality_target(c3.hash(), None)); + assert_eq!(error_hash, finality_target(d2.hash(), None)); // search only blocks with number <= 5. equivalent to without restriction for this scenario assert_eq!(a5.hash(), finality_target(genesis_hash, Some(5))); @@ -755,11 +760,11 @@ fn best_containing_on_longest_chain_with_multiple_forks() { 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))); + assert_eq!(error_hash, finality_target(b2.hash(), Some(5))); + assert_eq!(error_hash, finality_target(b3.hash(), Some(5))); + assert_eq!(error_hash, finality_target(b4.hash(), Some(5))); + assert_eq!(error_hash, finality_target(c3.hash(), Some(5))); + assert_eq!(error_hash, finality_target(d2.hash(), Some(5))); // search only blocks with number <= 4 assert_eq!(a4.hash(), finality_target(genesis_hash, Some(4))); @@ -767,73 +772,72 @@ fn best_containing_on_longest_chain_with_multiple_forks() { 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))); + assert_eq!(error_hash, finality_target(a5.hash(), Some(4))); + assert_eq!(error_hash, finality_target(b2.hash(), Some(4))); + assert_eq!(error_hash, finality_target(b3.hash(), Some(4))); + assert_eq!(error_hash, finality_target(b4.hash(), Some(4))); + assert_eq!(error_hash, finality_target(c3.hash(), Some(4))); + assert_eq!(error_hash, finality_target(d2.hash(), Some(4))); // search only blocks with number <= 3 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))); + assert_eq!(error_hash, finality_target(a4.hash(), Some(3))); + assert_eq!(error_hash, finality_target(a5.hash(), Some(3))); + assert_eq!(error_hash, finality_target(b2.hash(), Some(3))); + assert_eq!(error_hash, finality_target(b3.hash(), Some(3))); + assert_eq!(error_hash, finality_target(b4.hash(), Some(3))); + assert_eq!(error_hash, finality_target(c3.hash(), Some(3))); + assert_eq!(error_hash, finality_target(d2.hash(), Some(3))); // search only blocks with number <= 2 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))); + assert_eq!(error_hash, finality_target(a3.hash(), Some(2))); + assert_eq!(error_hash, finality_target(a4.hash(), Some(2))); + assert_eq!(error_hash, finality_target(a5.hash(), Some(2))); + assert_eq!(error_hash, finality_target(b2.hash(), Some(2))); + assert_eq!(error_hash, finality_target(b3.hash(), Some(2))); + assert_eq!(error_hash, finality_target(b4.hash(), Some(2))); + assert_eq!(error_hash, finality_target(c3.hash(), Some(2))); + assert_eq!(error_hash, finality_target(d2.hash(), Some(2))); // search only blocks with number <= 1 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))); + assert_eq!(error_hash, finality_target(a2.hash(), Some(1))); + assert_eq!(error_hash, finality_target(a3.hash(), Some(1))); + assert_eq!(error_hash, finality_target(a4.hash(), Some(1))); + assert_eq!(error_hash, finality_target(a5.hash(), Some(1))); + assert_eq!(error_hash, finality_target(b2.hash(), Some(1))); + assert_eq!(error_hash, finality_target(b3.hash(), Some(1))); + assert_eq!(error_hash, finality_target(b4.hash(), Some(1))); + assert_eq!(error_hash, finality_target(c3.hash(), Some(1))); + assert_eq!(error_hash, finality_target(d2.hash(), Some(1))); // search only blocks with number <= 0 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))); + assert_eq!(error_hash, finality_target(a1.hash(), Some(0))); + assert_eq!(error_hash, finality_target(a2.hash(), Some(0))); + assert_eq!(error_hash, finality_target(a3.hash(), Some(0))); + assert_eq!(error_hash, finality_target(a4.hash(), Some(0))); + assert_eq!(error_hash, finality_target(a5.hash(), Some(0))); + assert_eq!(error_hash, finality_target(b2.hash(), Some(0))); + assert_eq!(error_hash, finality_target(b3.hash(), Some(0))); + assert_eq!(error_hash, finality_target(b4.hash(), Some(0))); + assert_eq!(error_hash, finality_target(c3.hash(), Some(0))); + assert_eq!(error_hash, finality_target(d2.hash(), Some(0))); } #[test] -fn best_containing_on_longest_chain_with_max_depth_higher_than_best() { +fn finality_target_on_longest_chain_with_max_depth_higher_than_best() { // block tree: // G -> A1 -> A2 - let (mut client, longest_chain_select) = TestClientBuilder::new().build_with_longest_chain(); + let (mut client, chain_select) = TestClientBuilder::new().build_with_longest_chain(); // G -> A1 let a1 = client.new_block(Default::default()).unwrap().build().unwrap().block; @@ -845,10 +849,93 @@ fn best_containing_on_longest_chain_with_max_depth_higher_than_best() { let genesis_hash = client.chain_info().genesis_hash; - assert_eq!( - a2.hash(), - block_on(longest_chain_select.finality_target(genesis_hash, Some(10))).unwrap(), - ); + assert_eq!(a2.hash(), block_on(chain_select.finality_target(genesis_hash, Some(10))).unwrap(),); +} + +#[test] +fn finality_target_with_best_not_on_longest_chain() { + // block tree: + // G -> A1 -> A2 -> A3 -> A4 -> A5 + // -> B2 -> (B3) -> B4 + // ^best + + let (mut client, chain_select) = TestClientBuilder::new().build_with_longest_chain(); + let genesis_hash = client.chain_info().genesis_hash; + + // G -> A1 + let a1 = client.new_block(Default::default()).unwrap().build().unwrap().block; + block_on(client.import(BlockOrigin::Own, a1.clone())).unwrap(); + + // A1 -> A2 + let a2 = client.new_block(Default::default()).unwrap().build().unwrap().block; + block_on(client.import(BlockOrigin::Own, a2.clone())).unwrap(); + + // A2 -> A3 + let a3 = client.new_block(Default::default()).unwrap().build().unwrap().block; + block_on(client.import(BlockOrigin::Own, a3.clone())).unwrap(); + + // A3 -> A4 + let a4 = client.new_block(Default::default()).unwrap().build().unwrap().block; + block_on(client.import(BlockOrigin::Own, a4.clone())).unwrap(); + + // A3 -> A5 + let a5 = client.new_block(Default::default()).unwrap().build().unwrap().block; + block_on(client.import(BlockOrigin::Own, a5.clone())).unwrap(); + + // A1 -> B2 + let mut builder = client + .new_block_at(&BlockId::Hash(a1.hash()), Default::default(), false) + .unwrap(); + // this push is required as otherwise B2 has the same hash as A2 and won't get imported + builder + .push_transfer(Transfer { + from: AccountKeyring::Alice.into(), + to: AccountKeyring::Ferdie.into(), + amount: 41, + nonce: 0, + }) + .unwrap(); + let b2 = builder.build().unwrap().block; + block_on(client.import(BlockOrigin::Own, b2.clone())).unwrap(); + + assert_eq!(a5.hash(), block_on(chain_select.finality_target(genesis_hash, None)).unwrap()); + assert_eq!(a5.hash(), block_on(chain_select.finality_target(a1.hash(), None)).unwrap()); + assert_eq!(a5.hash(), block_on(chain_select.finality_target(a2.hash(), None)).unwrap()); + assert_eq!(a5.hash(), block_on(chain_select.finality_target(a3.hash(), None)).unwrap()); + assert_eq!(a5.hash(), block_on(chain_select.finality_target(a4.hash(), None)).unwrap()); + assert_eq!(a5.hash(), block_on(chain_select.finality_target(a5.hash(), None)).unwrap()); + + // B2 -> B3 + let b3 = client + .new_block_at(&BlockId::Hash(b2.hash()), Default::default(), false) + .unwrap() + .build() + .unwrap() + .block; + block_on(client.import_as_best(BlockOrigin::Own, b3.clone())).unwrap(); + + // B3 -> B4 + let b4 = client + .new_block_at(&BlockId::Hash(b3.hash()), Default::default(), false) + .unwrap() + .build() + .unwrap() + .block; + let (header, extrinsics) = b4.clone().deconstruct(); + let mut import_params = BlockImportParams::new(BlockOrigin::Own, header); + import_params.body = Some(extrinsics); + import_params.fork_choice = Some(ForkChoiceStrategy::Custom(false)); + block_on(client.import_block(import_params, Default::default())).unwrap(); + + // double check that B3 is still the best... + assert_eq!(client.info().best_hash, b3.hash()); + + assert_eq!(b4.hash(), block_on(chain_select.finality_target(genesis_hash, None)).unwrap()); + assert_eq!(b4.hash(), block_on(chain_select.finality_target(a1.hash(), None)).unwrap()); + assert!(block_on(chain_select.finality_target(a2.hash(), None)).is_err()); + assert_eq!(b4.hash(), block_on(chain_select.finality_target(b2.hash(), None)).unwrap()); + assert_eq!(b4.hash(), block_on(chain_select.finality_target(b3.hash(), None)).unwrap()); + assert_eq!(b4.hash(), block_on(chain_select.finality_target(b4.hash(), None)).unwrap()); } #[test] @@ -995,7 +1082,7 @@ fn finalizing_diverged_block_should_trigger_reorg() { .block; block_on(client.import(BlockOrigin::Own, b2.clone())).unwrap(); - // A2 is the current best since it's the longest chain + // A2 is the current best since it's the (first) longest chain assert_eq!(client.chain_info().best_hash, a2.hash()); // we finalize block B1 which is on a different branch from current best @@ -1012,8 +1099,7 @@ fn finalizing_diverged_block_should_trigger_reorg() { // `SelectChain` should report B2 as best block though assert_eq!(block_on(select_chain.best_chain()).unwrap().hash(), b2.hash()); - // after we build B3 on top of B2 and import it - // it should be the new best block, + // after we build B3 on top of B2 and import it, it should be the new best block let b3 = client .new_block_at(&BlockId::Hash(b2.hash()), Default::default(), false) .unwrap() @@ -1022,6 +1108,9 @@ fn finalizing_diverged_block_should_trigger_reorg() { .block; block_on(client.import(BlockOrigin::Own, b3.clone())).unwrap(); + // `SelectChain` should report B3 as best block though + assert_eq!(block_on(select_chain.best_chain()).unwrap().hash(), b3.hash()); + assert_eq!(client.chain_info().best_hash, b3.hash()); ClientExt::finalize_block(&client, b3.hash(), None).unwrap(); diff --git a/primitives/blockchain/src/backend.rs b/primitives/blockchain/src/backend.rs index ec9c8ac0d5780..7339d4c1a6804 100644 --- a/primitives/blockchain/src/backend.rs +++ b/primitives/blockchain/src/backend.rs @@ -183,96 +183,43 @@ pub trait Backend: /// Return hashes of all blocks that are children of the block with `parent_hash`. fn children(&self, parent_hash: Block::Hash) -> Result>; - /// Get the most recent block hash of the best (longest) chains - /// that contain block with the given `target_hash`. + /// Get the most recent block hash of the longest chain that contains + /// a block with the given `base_hash`. /// /// The search space is always limited to blocks which are in the finalized /// chain or descendents of it. /// - /// If `maybe_max_block_number` is `Some(max_block_number)` - /// the search is limited to block `numbers <= max_block_number`. - /// in other words as if there were no blocks greater `max_block_number`. - /// Returns `Ok(None)` if `target_hash` is not found in search space. - /// TODO: document time complexity of this, see [#1444](https://github.com/paritytech/substrate/issues/1444) - fn best_containing( + /// Returns `Ok(None)` if `base_hash` is not found in search space. + // TODO: document time complexity of this, see [#1444](https://github.com/paritytech/substrate/issues/1444) + fn longest_containing( &self, - target_hash: Block::Hash, - maybe_max_number: Option>, + base_hash: Block::Hash, import_lock: &RwLock<()>, ) -> Result> { - let target_header = { - match self.header(target_hash)? { - Some(x) => x, - // target not in blockchain - None => return Ok(None), - } + let Some(base_header) = self.header(base_hash)? else { + return Ok(None) }; - if let Some(max_number) = maybe_max_number { - // target outside search range - if target_header.number() > &max_number { - return Ok(None) - } - } - let leaves = { // ensure no blocks are imported during this code block. // an import could trigger a reorg which could change the canonical chain. // we depend on the canonical chain staying the same during this code block. let _import_guard = import_lock.read(); - let info = self.info(); - - // this can be `None` if the best chain is shorter than the target header. - let maybe_canon_hash = self.hash(*target_header.number())?; - - if maybe_canon_hash.as_ref() == Some(&target_hash) { - // if a `max_number` is given we try to fetch the block at the - // given depth, if it doesn't exist or `max_number` is not - // provided, we continue to search from all leaves below. - if let Some(max_number) = maybe_max_number { - if let Some(header) = self.hash(max_number)? { - return Ok(Some(header)) - } - } - } else if info.finalized_number >= *target_header.number() { - // header is on a dead fork. + if info.finalized_number > *base_header.number() { + // `base_header` is on a dead fork. return Ok(None) } - self.leaves()? }; // for each chain. longest chain first. shortest last for leaf_hash in leaves { - // start at the leaf let mut current_hash = leaf_hash; - - // if search is not restricted then the leaf is the best - let mut best_hash = leaf_hash; - - // go backwards entering the search space - // waiting until we are <= max_number - if let Some(max_number) = maybe_max_number { - loop { - let current_header = self - .header(current_hash)? - .ok_or_else(|| Error::MissingHeader(current_hash.to_string()))?; - - if current_header.number() <= &max_number { - best_hash = current_header.hash(); - break - } - - current_hash = *current_header.parent_hash(); - } - } - // go backwards through the chain (via parent links) loop { - // until we find target - if current_hash == target_hash { - return Ok(Some(best_hash)) + if current_hash == base_hash { + return Ok(Some(leaf_hash)) } let current_header = self @@ -280,7 +227,7 @@ pub trait Backend: .ok_or_else(|| Error::MissingHeader(current_hash.to_string()))?; // stop search in this chain once we go below the target's block number - if current_header.number() < target_header.number() { + if current_header.number() < base_header.number() { break } @@ -293,9 +240,8 @@ pub trait Backend: // // FIXME #1558 only issue this warning when not on a dead fork warn!( - "Block {:?} exists in chain but not found when following all \ - leaves backwards. Number limit = {:?}", - target_hash, maybe_max_number, + "Block {:?} exists in chain but not found when following all leaves backwards", + base_hash, ); Ok(None) diff --git a/primitives/consensus/common/src/select_chain.rs b/primitives/consensus/common/src/select_chain.rs index f366cd34c51ea..5beab6705046d 100644 --- a/primitives/consensus/common/src/select_chain.rs +++ b/primitives/consensus/common/src/select_chain.rs @@ -43,14 +43,14 @@ pub trait SelectChain: Sync + Send + Clone { /// finalize. async fn best_chain(&self) -> Result<::Header, Error>; - /// Get the best descendent of `target_hash` that we should attempt to - /// finalize next, if any. It is valid to return the given `target_hash` + /// Get the best descendent of `base_hash` that we should attempt to + /// finalize next, if any. It is valid to return the given `base_hash` /// itself if no better descendent exists. async fn finality_target( &self, - target_hash: ::Hash, + base_hash: ::Hash, _maybe_max_number: Option>, ) -> Result<::Hash, Error> { - Ok(target_hash) + Ok(base_hash) } } From 11bd6cdd06041f478ee9ae5e678c8fb78ab46d63 Mon Sep 17 00:00:00 2001 From: girazoki Date: Sun, 12 Feb 2023 11:43:03 +0100 Subject: [PATCH 380/715] SetMembers configurable origin (#13159) * SetMembers configurable origin * root origin comment replaced * fmt --- bin/node/runtime/src/lib.rs | 3 +++ frame/alliance/src/mock.rs | 1 + frame/collective/src/lib.rs | 7 +++++-- frame/collective/src/tests.rs | 5 ++++- frame/utility/src/tests.rs | 1 + 5 files changed, 14 insertions(+), 3 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 4298a6eced430..8f8a7ceef3cfe 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -992,6 +992,7 @@ impl pallet_collective::Config for Runtime { type MaxMembers = CouncilMaxMembers; type DefaultVote = pallet_collective::PrimeDefaultVote; type WeightInfo = pallet_collective::weights::SubstrateWeight; + type SetMembersOrigin = EnsureRoot; } parameter_types! { @@ -1051,6 +1052,7 @@ impl pallet_collective::Config for Runtime { type MaxMembers = TechnicalMaxMembers; type DefaultVote = pallet_collective::PrimeDefaultVote; type WeightInfo = pallet_collective::weights::SubstrateWeight; + type SetMembersOrigin = EnsureRoot; } type EnsureRootOrHalfCouncil = EitherOfDiverse< @@ -1652,6 +1654,7 @@ impl pallet_collective::Config for Runtime { type MaxMembers = AllianceMaxMembers; type DefaultVote = pallet_collective::PrimeDefaultVote; type WeightInfo = pallet_collective::weights::SubstrateWeight; + type SetMembersOrigin = EnsureRoot; } parameter_types! { diff --git a/frame/alliance/src/mock.rs b/frame/alliance/src/mock.rs index e708d29d529fe..0f774dc4853fa 100644 --- a/frame/alliance/src/mock.rs +++ b/frame/alliance/src/mock.rs @@ -104,6 +104,7 @@ impl pallet_collective::Config for Test { type MaxMembers = MaxMembers; type DefaultVote = pallet_collective::PrimeDefaultVote; type WeightInfo = (); + type SetMembersOrigin = EnsureRoot; } parameter_types! { diff --git a/frame/collective/src/lib.rs b/frame/collective/src/lib.rs index 0fe05dbb01ac0..7d625a69a4bf7 100644 --- a/frame/collective/src/lib.rs +++ b/frame/collective/src/lib.rs @@ -215,6 +215,9 @@ pub mod pallet { /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; + + /// Origin allowed to set collective members + type SetMembersOrigin: EnsureOrigin<::RuntimeOrigin>; } #[pallet::genesis_config] @@ -349,7 +352,7 @@ pub mod pallet { /// - `old_count`: The upper bound for the previous number of members in storage. Used for /// weight estimation. /// - /// Requires root origin. + /// The dispatch of this call must be `SetMembersOrigin`. /// /// NOTE: Does not enforce the expected `MaxMembers` limit on the amount of members, but /// the weight estimations rely on it to estimate dispatchable weight. @@ -389,7 +392,7 @@ pub mod pallet { prime: Option, old_count: MemberCount, ) -> DispatchResultWithPostInfo { - ensure_root(origin)?; + T::SetMembersOrigin::ensure_origin(origin)?; if new_members.len() > T::MaxMembers::get() as usize { log::error!( target: LOG_TARGET, diff --git a/frame/collective/src/tests.rs b/frame/collective/src/tests.rs index 5c90de9f91bf7..b7cdeb3383375 100644 --- a/frame/collective/src/tests.rs +++ b/frame/collective/src/tests.rs @@ -24,7 +24,7 @@ use frame_support::{ traits::{ConstU32, ConstU64, GenesisBuild, StorageVersion}, Hashable, }; -use frame_system::{EventRecord, Phase}; +use frame_system::{EnsureRoot, EventRecord, Phase}; use sp_core::H256; use sp_runtime::{ testing::Header, @@ -127,6 +127,7 @@ impl Config for Test { type MaxMembers = MaxMembers; type DefaultVote = PrimeDefaultVote; type WeightInfo = (); + type SetMembersOrigin = EnsureRoot; } impl Config for Test { type RuntimeOrigin = RuntimeOrigin; @@ -137,6 +138,7 @@ impl Config for Test { type MaxMembers = MaxMembers; type DefaultVote = MoreThanMajorityThenPrimeDefaultVote; type WeightInfo = (); + type SetMembersOrigin = EnsureRoot; } impl mock_democracy::Config for Test { type RuntimeEvent = RuntimeEvent; @@ -151,6 +153,7 @@ impl Config for Test { type MaxMembers = MaxMembers; type DefaultVote = PrimeDefaultVote; type WeightInfo = (); + type SetMembersOrigin = EnsureRoot; } pub fn new_test_ext() -> sp_io::TestExternalities { diff --git a/frame/utility/src/tests.rs b/frame/utility/src/tests.rs index f9d6a16c1a0d4..c63ed24c6aafb 100644 --- a/frame/utility/src/tests.rs +++ b/frame/utility/src/tests.rs @@ -217,6 +217,7 @@ impl pallet_collective::Config for Test { type MaxMembers = MaxMembers; type DefaultVote = pallet_collective::PrimeDefaultVote; type WeightInfo = (); + type SetMembersOrigin = frame_system::EnsureRoot; } impl example::Config for Test {} From 5590a4e0e793c98dd4d26ea34958c93775ce4635 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= <123550+andresilva@users.noreply.github.com> Date: Sun, 12 Feb 2023 12:35:01 +0000 Subject: [PATCH 381/715] grandpa: don't error if best block and finality target are inconsistent (#13364) * grandpa: don't error if best block and finality target are inconsistent * grandpa: add test for best block override * grandpa: make clippy happy * grandpa: log selectchain override as debug instead of warn --- client/finality-grandpa/src/environment.rs | 35 ++++- client/finality-grandpa/src/tests.rs | 144 +++++++++++++++++++-- 2 files changed, 166 insertions(+), 13 deletions(-) diff --git a/client/finality-grandpa/src/environment.rs b/client/finality-grandpa/src/environment.rs index 40ec720c4e7fe..a9aa204f12e2d 100644 --- a/client/finality-grandpa/src/environment.rs +++ b/client/finality-grandpa/src/environment.rs @@ -1213,7 +1213,7 @@ where // NOTE: this is purposefully done after `finality_target` to prevent a case // where in-between these two requests there is a block import and // `finality_target` returns something higher than `best_chain`. - let best_header = match select_chain.best_chain().await { + let mut best_header = match select_chain.best_chain().await { Ok(best_header) => best_header, Err(err) => { warn!( @@ -1227,12 +1227,30 @@ where }, }; - if target_header.number() > best_header.number() { - return Err(Error::Safety( - "SelectChain returned a finality target higher than its best block".into(), - )) + let is_descendent_of = is_descendent_of(&*client, None); + + if target_header.number() > best_header.number() || + target_header.number() == best_header.number() && + target_header.hash() != best_header.hash() || + !is_descendent_of(&target_header.hash(), &best_header.hash())? + { + debug!( + target: LOG_TARGET, + "SelectChain returned a finality target inconsistent with its best block. Restricting best block to target block" + ); + + best_header = target_header.clone(); } + debug!( + target: LOG_TARGET, + "SelectChain: finality target: #{} ({}), best block: #{} ({})", + target_header.number(), + target_header.hash(), + best_header.number(), + best_header.hash(), + ); + // check if our vote is currently being limited due to a pending change, // in which case we will restrict our target header to the given limit if let Some(target_number) = limit.filter(|limit| limit < target_header.number()) { @@ -1254,6 +1272,13 @@ where .header(*target_header.parent_hash())? .expect("Header known to exist after `finality_target` call; qed"); } + + debug!( + target: LOG_TARGET, + "Finality target restricted to #{} ({}) due to pending authority set change", + target_header.number(), + target_header.hash() + ) } // restrict vote according to the given voting rule, if the voting rule diff --git a/client/finality-grandpa/src/tests.rs b/client/finality-grandpa/src/tests.rs index 62ef4709e1909..d132abd940ba3 100644 --- a/client/finality-grandpa/src/tests.rs +++ b/client/finality-grandpa/src/tests.rs @@ -244,6 +244,35 @@ impl SelectChain for MockSelectChain { } } +// A mock voting rule that allows asserting an expected value for best block +#[derive(Clone, Default)] +struct AssertBestBlock(Arc>>); + +impl VotingRule for AssertBestBlock +where + B: HeaderBackend, +{ + fn restrict_vote( + &self, + _backend: Arc, + _base: &::Header, + best_target: &::Header, + _current_target: &::Header, + ) -> VotingRuleResult { + if let Some(expected) = *self.0.lock() { + assert_eq!(best_target.hash(), expected); + } + + Box::pin(std::future::ready(None)) + } +} + +impl AssertBestBlock { + fn set_expected_best_block(&self, hash: Hash) { + *self.0.lock() = Some(hash); + } +} + const TEST_GOSSIP_DURATION: Duration = Duration::from_millis(500); fn make_ids(keys: &[Ed25519Keyring]) -> AuthorityList { @@ -1566,16 +1595,115 @@ async fn grandpa_environment_passes_actual_best_block_to_voting_rules() { .1, 10, ); +} - // returning a finality target that's higher than the best block is an - // inconsistent state that should be handled - let hashof42 = client.expect_block_hash_from_id(&BlockId::Number(42)).unwrap(); - select_chain.set_best_chain(client.expect_header(hashof21).unwrap()); - select_chain.set_finality_target(client.expect_header(hashof42).unwrap().hash()); +#[tokio::test] +async fn grandpa_environment_checks_if_best_block_is_descendent_of_finality_target() { + use finality_grandpa::voter::Environment; + + let peers = &[Ed25519Keyring::Alice]; + let voters = make_ids(peers); + + let mut net = GrandpaTestNet::new(TestApi::new(voters), 1, 0); + let peer = net.peer(0); + let network_service = peer.network_service().clone(); + let link = peer.data.lock().take().unwrap(); + let client = peer.client().as_client().clone(); + let select_chain = MockSelectChain::default(); + let voting_rule = AssertBestBlock::default(); + let env = test_environment_with_select_chain( + &link, + None, + network_service.clone(), + select_chain.clone(), + voting_rule.clone(), + ); + + // create a chain that is 10 blocks long + peer.push_blocks(10, false); + + let hashof5_a = client.expect_block_hash_from_id(&BlockId::Number(5)).unwrap(); + let hashof10_a = client.expect_block_hash_from_id(&BlockId::Number(10)).unwrap(); + + // create a fork starting at block 4 that is 6 blocks long + let fork = peer.generate_blocks_at( + BlockId::Number(4), + 6, + 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, + ); + + let hashof5_b = *fork.first().unwrap(); + let hashof10_b = *fork.last().unwrap(); + + // returning a finality target that's higher than the best block is inconsistent, + // therefore the best block should be set to be the same block as the target + select_chain.set_best_chain(client.expect_header(hashof5_a).unwrap()); + select_chain.set_finality_target(client.expect_header(hashof10_a).unwrap().hash()); + voting_rule.set_expected_best_block(hashof10_a); + + // the voting rule will internally assert that the best block that was passed was `hashof10_a`, + // instead of the one returned by `SelectChain` + assert_eq!( + env.best_chain_containing(peer.client().info().finalized_hash) + .await + .unwrap() + .unwrap() + .0, + hashof10_a, + ); + + // best block and finality target are blocks at the same height but on different forks, + // we should override the initial best block (#5B) with the target block (#5A) + select_chain.set_best_chain(client.expect_header(hashof5_b).unwrap()); + select_chain.set_finality_target(client.expect_header(hashof5_a).unwrap().hash()); + voting_rule.set_expected_best_block(hashof5_a); + + assert_eq!( + env.best_chain_containing(peer.client().info().finalized_hash) + .await + .unwrap() + .unwrap() + .0, + hashof5_a, + ); - assert_matches!( - env.best_chain_containing(peer.client().info().finalized_hash).await, - Err(CommandOrError::Error(Error::Safety(_))) + // best block is higher than finality target but it's on a different fork, + // we should override the initial best block (#5A) with the target block (#5B) + select_chain.set_best_chain(client.expect_header(hashof10_b).unwrap()); + select_chain.set_finality_target(client.expect_header(hashof5_a).unwrap().hash()); + voting_rule.set_expected_best_block(hashof5_a); + + assert_eq!( + env.best_chain_containing(peer.client().info().finalized_hash) + .await + .unwrap() + .unwrap() + .0, + hashof5_a, + ); + + // best block is higher than finality target and it's on the same fork, + // the best block passed to the voting rule should not be overriden + select_chain.set_best_chain(client.expect_header(hashof10_a).unwrap()); + select_chain.set_finality_target(client.expect_header(hashof5_a).unwrap().hash()); + voting_rule.set_expected_best_block(hashof10_a); + + assert_eq!( + env.best_chain_containing(peer.client().info().finalized_hash) + .await + .unwrap() + .unwrap() + .0, + hashof5_a, ); } From 4fadc98e1fa6b3cbb158735007d46bfe48a74158 Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Sun, 12 Feb 2023 12:01:06 -0300 Subject: [PATCH 382/715] Improve Weight Template and API (#13355) * improve weights template and api * follow template --- .maintain/frame-weight-template.hbs | 10 ++----- primitives/weights/src/weight_v2.rs | 26 ++++++++++++++----- .../benchmarking-cli/src/pallet/template.hbs | 5 +--- 3 files changed, 23 insertions(+), 18 deletions(-) diff --git a/.maintain/frame-weight-template.hbs b/.maintain/frame-weight-template.hbs index ff69fcb4a2d3d..186e3cb23b333 100644 --- a/.maintain/frame-weight-template.hbs +++ b/.maintain/frame-weight-template.hbs @@ -53,11 +53,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `{{benchmark.base_recorded_proof_size}}{{#each benchmark.component_recorded_proof_size as |cp|}} + {{cp.name}} * ({{cp.slope}} ±{{underscore cp.error}}){{/each}}` // Estimated: `{{benchmark.base_calculated_proof_size}}{{#each benchmark.component_calculated_proof_size as |cp|}} + {{cp.name}} * ({{cp.slope}} ±{{underscore cp.error}}){{/each}}` // Minimum execution time: {{underscore benchmark.min_execution_time}} nanoseconds. - {{#if (ne benchmark.base_calculated_proof_size "0")}} - Weight::from_parts({{underscore benchmark.base_weight}}, {{benchmark.base_calculated_proof_size}}) - {{else}} Weight::from_ref_time({{underscore benchmark.base_weight}}) - {{/if}} + .saturating_add(Weight::from_proof_size({{benchmark.base_calculated_proof_size}})) {{#each benchmark.component_weight as |cw|}} // Standard Error: {{underscore cw.error}} .saturating_add(Weight::from_ref_time({{underscore cw.slope}}).saturating_mul({{cw.name}}.into())) @@ -99,11 +96,8 @@ impl WeightInfo for () { // Measured: `{{benchmark.base_recorded_proof_size}}{{#each benchmark.component_recorded_proof_size as |cp|}} + {{cp.name}} * ({{cp.slope}} ±{{underscore cp.error}}){{/each}}` // Estimated: `{{benchmark.base_calculated_proof_size}}{{#each benchmark.component_calculated_proof_size as |cp|}} + {{cp.name}} * ({{cp.slope}} ±{{underscore cp.error}}){{/each}}` // Minimum execution time: {{underscore benchmark.min_execution_time}} nanoseconds. - {{#if (ne benchmark.base_calculated_proof_size "0")}} - Weight::from_parts({{underscore benchmark.base_weight}}, {{benchmark.base_calculated_proof_size}}) - {{else}} Weight::from_ref_time({{underscore benchmark.base_weight}}) - {{/if}} + .saturating_add(Weight::from_proof_size({{benchmark.base_calculated_proof_size}})) {{#each benchmark.component_weight as |cw|}} // Standard Error: {{underscore cw.error}} .saturating_add(Weight::from_ref_time({{underscore cw.slope}}).saturating_mul({{cw.name}}.into())) diff --git a/primitives/weights/src/weight_v2.rs b/primitives/weights/src/weight_v2.rs index 33e61b6954a37..3a15b117955f2 100644 --- a/primitives/weights/src/weight_v2.rs +++ b/primitives/weights/src/weight_v2.rs @@ -247,18 +247,32 @@ impl Weight { Self { ref_time: 0, proof_size: 0 } } - /// Constant version of Add with u64. + /// Constant version of Add for `ref_time` component 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, proof_size: self.proof_size + scalar } + pub const fn add_ref_time(self, scalar: u64) -> Self { + Self { ref_time: self.ref_time + scalar, proof_size: self.proof_size } } - /// Constant version of Sub with u64. + /// Constant version of Add for `proof_size` component 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, proof_size: self.proof_size - scalar } + pub const fn add_proof_size(self, scalar: u64) -> Self { + Self { ref_time: self.ref_time, proof_size: self.proof_size + scalar } + } + + /// Constant version of Sub for `ref_time` component with u64. + /// + /// Is only overflow safe when evaluated at compile-time. + pub const fn sub_ref_time(self, scalar: u64) -> Self { + Self { ref_time: self.ref_time - scalar, proof_size: self.proof_size } + } + + /// Constant version of Sub for `proof_size` component with u64. + /// + /// Is only overflow safe when evaluated at compile-time. + pub const fn sub_proof_size(self, scalar: u64) -> Self { + Self { ref_time: self.ref_time, proof_size: self.proof_size - scalar } } /// Constant version of Div with u64. diff --git a/utils/frame/benchmarking-cli/src/pallet/template.hbs b/utils/frame/benchmarking-cli/src/pallet/template.hbs index 00dd1a3532d95..0bec34eaae774 100644 --- a/utils/frame/benchmarking-cli/src/pallet/template.hbs +++ b/utils/frame/benchmarking-cli/src/pallet/template.hbs @@ -38,11 +38,8 @@ impl {{pallet}}::WeightInfo for WeightInfo { // Measured: `{{benchmark.base_recorded_proof_size}}{{#each benchmark.component_recorded_proof_size as |cp|}} + {{cp.name}} * ({{cp.slope}} ±{{underscore cp.error}}){{/each}}` // Estimated: `{{benchmark.base_calculated_proof_size}}{{#each benchmark.component_calculated_proof_size as |cp|}} + {{cp.name}} * ({{cp.slope}} ±{{underscore cp.error}}){{/each}}` // Minimum execution time: {{underscore benchmark.min_execution_time}} nanoseconds. - {{#if (ne benchmark.base_calculated_proof_size "0")}} - Weight::from_parts({{underscore benchmark.base_weight}}, {{benchmark.base_calculated_proof_size}}) - {{else}} Weight::from_ref_time({{underscore benchmark.base_weight}}) - {{/if}} + .saturating_add(Weight::from_proof_size({{benchmark.base_calculated_proof_size}})) {{#each benchmark.component_weight as |cw|}} // Standard Error: {{underscore cw.error}} .saturating_add(Weight::from_ref_time({{underscore cw.slope}}).saturating_mul({{cw.name}}.into())) From 14fba11d9c474787bc8c46bba3c0b1883dc60099 Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Mon, 13 Feb 2023 10:54:47 +0100 Subject: [PATCH 383/715] [ci] Change label checker (#13360) * [ci] Change label checker * rm pr autolabel * fix specs file name to substrate --- .github/workflows/auto-label-prs.yml | 21 ------------ .github/workflows/check-D-labels.yml | 48 ++++++++++++++++++++++++++++ .github/workflows/check-labels.yml | 38 ++++++++++++++++++---- 3 files changed, 79 insertions(+), 28 deletions(-) delete mode 100644 .github/workflows/auto-label-prs.yml create mode 100644 .github/workflows/check-D-labels.yml diff --git a/.github/workflows/auto-label-prs.yml b/.github/workflows/auto-label-prs.yml deleted file mode 100644 index 50539b80b98b7..0000000000000 --- a/.github/workflows/auto-label-prs.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: Label PRs -on: - pull_request: - types: [opened,ready_for_review] - -jobs: - label-new-prs: - runs-on: ubuntu-latest - steps: - - name: Label drafts - 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@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' - remove-labels: 'A3-inprogress' diff --git a/.github/workflows/check-D-labels.yml b/.github/workflows/check-D-labels.yml new file mode 100644 index 0000000000000..7bb358ce1182e --- /dev/null +++ b/.github/workflows/check-D-labels.yml @@ -0,0 +1,48 @@ +name: Check D labels + +on: + pull_request: + types: [labeled, opened, synchronize, unlabeled] + paths: + - frame/** + - primitives/** + +env: + IMAGE: paritytech/ruled_labels:0.4.0 + +jobs: + check-labels: + runs-on: ubuntu-latest + steps: + - name: Pull image + run: docker pull $IMAGE + + - name: Check labels + env: + MOUNT: /work + GITHUB_PR: ${{ github.event.pull_request.number }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + API_BASE: https://api.github.com/repos + REPO: ${{ github.repository }} + RULES_PATH: labels/ruled_labels + CHECK_SPECS: specs_substrate.yaml + run: | + echo "REPO: ${REPO}" + echo "GITHUB_PR: ${GITHUB_PR}" + # Clone repo with labels specs + git clone https://github.com/paritytech/labels + # Fetch the labels for the PR under test + labels=$( curl -H "Authorization: token ${GITHUB_TOKEN}" -s "$API_BASE/${REPO}/pulls/${GITHUB_PR}" | jq '.labels | .[] | .name' | tr "\n" ",") + + if [ -z "${labels}" ]; then + docker run --rm -i -v $PWD/${RULES_PATH}/:$MOUNT $IMAGE check $MOUNT/$CHECK_SPECS --tags audit --no-label + fi + + labels_args=${labels: :-1} + printf "Checking labels: %s\n" "${labels_args}" + + # Prevent the shell from splitting labels with spaces + IFS="," + + # --dev is more useful to debug mode to debug + docker run --rm -i -v $PWD/${RULES_PATH}/:$MOUNT $IMAGE check $MOUNT/$CHECK_SPECS --labels ${labels_args} --dev --tags audit diff --git a/.github/workflows/check-labels.yml b/.github/workflows/check-labels.yml index de204ce9d3776..55b8f7389fa7f 100644 --- a/.github/workflows/check-labels.yml +++ b/.github/workflows/check-labels.yml @@ -4,18 +4,42 @@ on: pull_request: types: [labeled, opened, synchronize, unlabeled] +env: + IMAGE: paritytech/ruled_labels:0.4.0 + jobs: check-labels: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - with: - fetch-depth: 0 - ref: ${{ github.event.pull_request.head.ref }} - repository: ${{ github.event.pull_request.head.repo.full_name }} + - name: Pull image + run: docker pull $IMAGE + - name: Check labels - run: bash ${{ github.workspace }}/scripts/ci/github/check_labels.sh env: + MOUNT: /work GITHUB_PR: ${{ github.event.pull_request.number }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - HEAD_SHA: ${{ github.event.pull_request.head.sha }} + API_BASE: https://api.github.com/repos + REPO: ${{ github.repository }} + RULES_PATH: labels/ruled_labels + CHECK_SPECS: specs_substrate.yaml + run: | + echo "REPO: ${REPO}" + echo "GITHUB_PR: ${GITHUB_PR}" + # Clone repo with labels specs + git clone https://github.com/paritytech/labels + # Fetch the labels for the PR under test + labels=$( curl -H "Authorization: token ${GITHUB_TOKEN}" -s "$API_BASE/${REPO}/pulls/${GITHUB_PR}" | jq '.labels | .[] | .name' | tr "\n" ",") + + if [ -z "${labels}" ]; then + docker run --rm -i -v $PWD/${RULES_PATH}/:$MOUNT $IMAGE check $MOUNT/$CHECK_SPECS --tags PR --no-label + fi + + labels_args=${labels: :-1} + printf "Checking labels: %s\n" "${labels_args}" + + # Prevent the shell from splitting labels with spaces + IFS="," + + # --dev is more useful to debug mode to debug + docker run --rm -i -v $PWD/${RULES_PATH}/:$MOUNT $IMAGE check $MOUNT/$CHECK_SPECS --labels ${labels_args} --dev --tags PR From fc49dddda28bbf8dcc1e9c208346cdfb2565501b Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Mon, 13 Feb 2023 12:21:20 +0200 Subject: [PATCH 384/715] client/beefy: request justifs from peers further in consensus (#13343) For on-demand justifications, peer selection is based on witnessed gossip votes. This commit changes the condition for selecting a peer to request justification for `block` from "last voted on >= `block`" to "peer last voted on strict > `block`". When allowing `>=` we see nodes continuously spamming unsuccessful on-demand requests to nodes which are still voting on a block without having a justification available. One way to fix the spam would be to add some rate-limiting or backoff period when requesting justifications. The other solution (present in this commit) is to simply request justifications from peers that are voting on future blocks so we know they're _guaranteed_ to have the wanted mandatory justification available to send back. Signed-off-by: acatangiu --- client/beefy/src/communication/peers.rs | 32 +++++++++---------- .../outgoing_requests_engine.rs | 3 +- client/beefy/src/tests.rs | 12 +++---- client/beefy/src/worker.rs | 2 +- 4 files changed, 24 insertions(+), 25 deletions(-) diff --git a/client/beefy/src/communication/peers.rs b/client/beefy/src/communication/peers.rs index d7927ea72e661..50158126a0a07 100644 --- a/client/beefy/src/communication/peers.rs +++ b/client/beefy/src/communication/peers.rs @@ -57,11 +57,11 @@ impl KnownPeers { 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 { + /// Return _filtered and cloned_ list of peers that have voted on higher than `block`. + pub fn further_than(&self, block: NumberFor) -> VecDeque { self.live .iter() - .filter_map(|(k, v)| (v.last_voted_on >= block).then_some(k)) + .filter_map(|(k, v)| (v.last_voted_on > block).then_some(k)) .cloned() .collect() } @@ -92,22 +92,22 @@ mod tests { assert!(peers.contains(&bob)); assert!(peers.contains(&charlie)); - // Get peers at block >= 5 - let at_5 = peers.at_least_at_block(5); + // Get peers at block > 4 + let further_than_4 = peers.further_than(4); // Should be Bob and Charlie - assert_eq!(at_5.len(), 2); - assert!(at_5.contains(&bob)); - assert!(at_5.contains(&charlie)); + assert_eq!(further_than_4.len(), 2); + assert!(further_than_4.contains(&bob)); + assert!(further_than_4.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); + // Get peers at block > 9 + let further_than_9 = peers.further_than(9); // Should be Charlie and Alice - assert_eq!(at_9.len(), 2); - assert!(at_9.contains(&charlie)); - assert!(at_9.contains(&alice)); + assert_eq!(further_than_9.len(), 2); + assert!(further_than_9.contains(&charlie)); + assert!(further_than_9.contains(&alice)); // Remove Alice peers.remove(&alice); @@ -115,9 +115,9 @@ mod tests { assert!(!peers.contains(&alice)); // Get peers at block >= 9 - let at_9 = peers.at_least_at_block(9); + let further_than_9 = peers.further_than(9); // Now should be just Charlie - assert_eq!(at_9.len(), 1); - assert!(at_9.contains(&charlie)); + assert_eq!(further_than_9.len(), 1); + assert!(further_than_9.contains(&charlie)); } } 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 c7dc269b495cc..766480f781ff5 100644 --- a/client/beefy/src/communication/request_response/outgoing_requests_engine.rs +++ b/client/beefy/src/communication/request_response/outgoing_requests_engine.rs @@ -80,7 +80,7 @@ impl OnDemandJustificationsEngine { 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); + self.peers_cache = self.live_peers.lock().further_than(block); } fn try_next_peer(&mut self) -> Option { @@ -199,7 +199,6 @@ impl OnDemandJustificationsEngine { 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, req_info, receiver) => { diff --git a/client/beefy/src/tests.rs b/client/beefy/src/tests.rs index 69cc9b2f652c4..932897c775895 100644 --- a/client/beefy/src/tests.rs +++ b/client/beefy/src/tests.rs @@ -893,7 +893,7 @@ async fn on_demand_beefy_justification_sync() { [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 min_block_delta = 4; let mut net = BeefyTestNet::new(4); @@ -912,7 +912,7 @@ async fn on_demand_beefy_justification_sync() { let dave_index = 3; // push 30 blocks - let hashes = net.generate_blocks_and_sync(30, session_len, &validator_set, false).await; + let hashes = net.generate_blocks_and_sync(35, session_len, &validator_set, false).await; let fast_peers = fast_peers.into_iter().enumerate(); let net = Arc::new(Mutex::new(net)); @@ -921,7 +921,7 @@ async fn on_demand_beefy_justification_sync() { finalize_block_and_wait_for_beefy( &net, fast_peers.clone(), - &[hashes[1], hashes[6], hashes[10], hashes[17], hashes[24]], + &[hashes[1], hashes[6], hashes[10], hashes[17], hashes[23]], &[1, 5, 10, 15, 20], ) .await; @@ -941,12 +941,12 @@ async fn on_demand_beefy_justification_sync() { // freshly spun up Dave now needs to listen for gossip to figure out the state of their peers. // Have the other peers do some gossip so Dave finds out about their progress. - finalize_block_and_wait_for_beefy(&net, fast_peers, &[hashes[25]], &[25]).await; + finalize_block_and_wait_for_beefy(&net, fast_peers, &[hashes[25], hashes[29]], &[25, 29]).await; // Now verify Dave successfully finalized #1 (through on-demand justification request). wait_for_best_beefy_blocks(dave_best_blocks, &net, &[1]).await; - // Give Dave all tasks some cpu cycles to burn through their events queues, + // Give all tasks some cpu cycles to burn through their events queues, run_for(Duration::from_millis(100), &net).await; // then verify Dave catches up through on-demand justification requests. finalize_block_and_wait_for_beefy( @@ -959,7 +959,7 @@ async fn on_demand_beefy_justification_sync() { 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, &[hashes[30]], &[30]).await; + finalize_block_and_wait_for_beefy(&net, all_peers, &[hashes[30], hashes[34]], &[30]).await; } #[tokio::test] diff --git a/client/beefy/src/worker.rs b/client/beefy/src/worker.rs index be5443d3dead8..f367c8b46d037 100644 --- a/client/beefy/src/worker.rs +++ b/client/beefy/src/worker.rs @@ -555,7 +555,6 @@ where let block_number = vote.commitment.block_number; match rounds.add_vote(vote) { VoteImportResult::RoundConcluded(signed_commitment) => { - self.gossip_validator.conclude_round(block_number); metric_set!(self, beefy_round_concluded, block_number); let finality_proof = VersionedFinalityProof::V1(signed_commitment); @@ -602,6 +601,7 @@ where // Finalize inner round and update voting_oracle state. self.persisted_state.voting_oracle.finalize(block_num)?; + self.gossip_validator.conclude_round(block_num); if block_num > self.best_beefy_block() { // Set new best BEEFY block number. From 6142fc29163d9824aedace79027a418acc2bc955 Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Mon, 13 Feb 2023 12:27:52 +0100 Subject: [PATCH 385/715] [ci] Change GHA to add J2 labels instead Z0 (#13375) --- .github/workflows/auto-label-issues.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/auto-label-issues.yml b/.github/workflows/auto-label-issues.yml index 2633bf55f0789..629966ed39618 100644 --- a/.github/workflows/auto-label-issues.yml +++ b/.github/workflows/auto-label-issues.yml @@ -14,4 +14,4 @@ jobs: uses: andymckay/labeler@e6c4322d0397f3240f0e7e30a33b5c5df2d39e90 # 1.0.4 if: github.event.issue.author_association == 'NONE' with: - add-labels: 'Z0-unconfirmed' + add-labels: "J2-unconfirmed" From 10bf4bd0d9ed75c62bf9e094759fa9315e1c2017 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Mon, 13 Feb 2023 12:39:15 +0100 Subject: [PATCH 386/715] sc-client-db: Fix `PruningMode::ArchiveCanonical` (#13361) * sc-client-db: Fix `PruningMode::ArchiveCanonical` When running a node with `--state-pruning archive-canonical` it was directly failing on genesis. There was an issue in the state-db `pin` implementation. It was not checking the state of a block correctly when running with archive canonical (and also not for every other block after they are canonicalized). * FMT --- client/db/src/lib.rs | 367 +++++++++++++++---------------------- client/state-db/src/lib.rs | 15 +- 2 files changed, 160 insertions(+), 222 deletions(-) diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index f54f1bdb131c7..03de383f2c7f4 100644 --- a/client/db/src/lib.rs +++ b/client/db/src/lib.rs @@ -1929,13 +1929,13 @@ impl Backend { Ok(()) } - fn empty_state(&self) -> ClientResult, Block>> { + fn empty_state(&self) -> RecordStatsState, Block> { let root = EmptyStorage::::new().0; // Empty trie 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); - Ok(RecordStatsState::new(state, None, self.state_usage.clone())) + RecordStatsState::new(state, None, self.state_usage.clone()) } } @@ -2063,7 +2063,7 @@ impl sc_client_api::backend::Backend for Backend { fn begin_operation(&self) -> ClientResult { Ok(BlockImportOperation { pending_block: None, - old_state: self.empty_state()?, + old_state: self.empty_state(), db_updates: PrefixedMemoryDB::default(), storage_updates: Default::default(), child_storage_updates: Default::default(), @@ -2082,7 +2082,7 @@ impl sc_client_api::backend::Backend for Backend { block: Block::Hash, ) -> ClientResult<()> { if block == Default::default() { - operation.old_state = self.empty_state()?; + operation.old_state = self.empty_state(); } else { operation.old_state = self.state_at(block)?; } @@ -2439,6 +2439,7 @@ impl sc_client_api::backend::Backend for Backend { .unwrap_or(None) .is_some() }; + if let Ok(()) = self.storage.state_db.pin(&hash, hdr.number.saturated_into::(), hint) { @@ -2593,25 +2594,30 @@ pub(crate) mod tests { 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 header = + Header { number, parent_hash, state_root: Default::default(), digest, extrinsics_root }; 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(); - op.set_block_data(header, Some(body), None, None, NewBlockState::Best).unwrap(); if let Some(index) = transaction_index { op.update_transaction_index(index).unwrap(); } + + // Insert some fake data to ensure that the block can be found in the state column. + let (root, overlay) = op.old_state.storage_root( + vec![(block_hash.as_ref(), Some(block_hash.as_ref()))].into_iter(), + StateVersion::V1, + ); + op.update_db_storage(overlay).unwrap(); + header.state_root = root.into(); + + op.set_block_data(header.clone(), Some(body), None, None, NewBlockState::Best) + .unwrap(); + backend.commit_operation(op)?; - Ok(header_hash) + Ok(header.hash()) } pub fn insert_header_no_head( @@ -2623,18 +2629,31 @@ pub(crate) mod tests { 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 header = + Header { number, parent_hash, state_root: Default::default(), digest, extrinsics_root }; let mut op = backend.begin_operation().unwrap(); - op.set_block_data(header, None, None, None, NewBlockState::Normal).unwrap(); + + let root = backend + .state_at(parent_hash) + .unwrap_or_else(|_| { + if parent_hash == Default::default() { + backend.empty_state() + } else { + panic!("Unknown block: {parent_hash:?}") + } + }) + .storage_root( + vec![(parent_hash.as_ref(), Some(parent_hash.as_ref()))].into_iter(), + StateVersion::V1, + ) + .0; + header.state_root = root.into(); + + op.set_block_data(header.clone(), None, None, None, NewBlockState::Normal) + .unwrap(); backend.commit_operation(op).unwrap(); - header_hash + + header.hash() } #[test] @@ -3369,204 +3388,131 @@ pub(crate) mod tests { #[test] fn prune_blocks_on_finalize() { - 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 { - let hash = insert_block( - &backend, - i, - prev_hash, - None, - Default::default(), - vec![i.into()], - None, - ) - .unwrap(); - blocks.push(hash); - prev_hash = hash; - } + let pruning_modes = + vec![BlocksPruning::Some(2), BlocksPruning::KeepFinalized, BlocksPruning::KeepAll]; - { - let mut op = backend.begin_operation().unwrap(); - backend.begin_state_operation(&mut op, blocks[4]).unwrap(); - for i in 1..5 { - op.mark_finalized(blocks[i], None).unwrap(); + for pruning_mode in pruning_modes { + let backend = Backend::::new_test_with_tx_storage(pruning_mode, 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; } - 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()); - } - #[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, blocks[4]).unwrap(); + for i in 1..5 { + op.mark_finalized(blocks[i], None).unwrap(); + } + backend.commit_operation(op).unwrap(); + } + let bc = backend.blockchain(); - let mut op = backend.begin_operation().unwrap(); - backend.begin_state_operation(&mut op, blocks[4]).unwrap(); - for i in 1..3 { - op.mark_finalized(blocks[i], None).unwrap(); + if matches!(pruning_mode, BlocksPruning::Some(_)) { + 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()); + } else { + for i in 0..5 { + assert_eq!(Some(vec![(i as u64).into()]), bc.body(blocks[i]).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()); } #[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( + fn prune_blocks_on_finalize_with_fork() { + sp_tracing::try_init_simple(); + + let pruning_modes = + vec![BlocksPruning::Some(2), BlocksPruning::KeepFinalized, BlocksPruning::KeepAll]; + + for pruning in pruning_modes { + let backend = Backend::::new_test_with_tx_storage(pruning, 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, H256::random(), vec![2.into()], None) + .unwrap(); + insert_block( &backend, - i, - prev_hash, + 3, + fork_hash_root, None, - Default::default(), - vec![i.into()], + H256::random(), + vec![3.into(), 11.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, 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()); - - 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[4]).unwrap(); + op.mark_head(blocks[4]).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()); + 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()); - assert_eq!(bc.info().best_number, 4); - for i in 0..5 { - assert!(bc.hash(i).unwrap().is_some()); - } - } + 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.commit_operation(op).unwrap(); + } - #[test] - fn prune_blocks_on_finalize_with_fork() { - 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 { - let hash = insert_block( - &backend, - i, - prev_hash, - None, - Default::default(), - vec![i.into()], - None, - ) - .unwrap(); - blocks.push(hash); - prev_hash = hash; - } + if matches!(pruning, BlocksPruning::Some(_)) { + assert_eq!(None, bc.body(blocks[0]).unwrap()); + assert_eq!(None, bc.body(blocks[1]).unwrap()); + assert_eq!(None, bc.body(blocks[2]).unwrap()); - // 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, blocks[4]).unwrap(); - op.mark_head(blocks[4]).unwrap(); - backend.commit_operation(op).unwrap(); + assert_eq!(Some(vec![3.into()]), bc.body(blocks[3]).unwrap()); + assert_eq!(Some(vec![4.into()]), bc.body(blocks[4]).unwrap()); + } else { + for i in 0..5 { + assert_eq!(Some(vec![(i as u64).into()]), bc.body(blocks[i]).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.commit_operation(op).unwrap(); - } + if matches!(pruning, BlocksPruning::KeepAll) { + assert_eq!(Some(vec![2.into()]), bc.body(fork_hash_root).unwrap()); + } else { + assert_eq!(None, bc.body(fork_hash_root).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!(bc.info().best_number, 4); + for i in 0..5 { + assert!(bc.hash(i).unwrap().is_some()); + } + } } #[test] @@ -3841,13 +3787,7 @@ pub(crate) mod tests { assert!(matches!(backend.commit_operation(op), Err(sp_blockchain::Error::SetHeadTooOld))); // Insert 2 as best again. - let header = Header { - number: 2, - parent_hash: block1, - state_root: BlakeTwo256::trie_root(Vec::new(), StateVersion::V1), - digest: Default::default(), - extrinsics_root: Default::default(), - }; + let header = backend.blockchain().header(block2).unwrap().unwrap(); let mut op = backend.begin_operation().unwrap(); op.set_block_data(header, None, None, None, NewBlockState::Best).unwrap(); backend.commit_operation(op).unwrap(); @@ -3864,13 +3804,7 @@ pub(crate) mod tests { assert_eq!(backend.blockchain().info().finalized_hash, block0); // Insert 1 as final again. - let header = Header { - number: 1, - parent_hash: block0, - state_root: BlakeTwo256::trie_root(Vec::new(), StateVersion::V1), - digest: Default::default(), - extrinsics_root: Default::default(), - }; + let header = backend.blockchain().header(block1).unwrap().unwrap(); let mut op = backend.begin_operation().unwrap(); op.set_block_data(header, None, None, None, NewBlockState::Final).unwrap(); @@ -4021,7 +3955,8 @@ pub(crate) mod tests { #[test] fn force_delayed_canonicalize_waiting_for_blocks_to_be_finalized() { - let pruning_modes = [BlocksPruning::Some(10), BlocksPruning::KeepAll]; + let pruning_modes = + [BlocksPruning::Some(10), BlocksPruning::KeepAll, BlocksPruning::KeepFinalized]; for pruning_mode in pruning_modes { eprintln!("Running with pruning mode: {:?}", pruning_mode); diff --git a/client/state-db/src/lib.rs b/client/state-db/src/lib.rs index 1befd6dff3bc8..6186a45f3d646 100644 --- a/client/state-db/src/lib.rs +++ b/client/state-db/src/lib.rs @@ -152,6 +152,7 @@ impl From for Error { } /// Pinning error type. +#[derive(Debug)] pub enum PinError { /// Trying to pin invalid block. InvalidBlock, @@ -389,7 +390,8 @@ impl StateDbSync { } } else { match self.pruning.as_ref() { - None => IsPruned::NotPruned, + // We don't know for sure. + None => IsPruned::MaybePruned, Some(pruning) => match pruning.have_block(hash, number) { HaveBlock::No => IsPruned::Pruned, HaveBlock::Yes => IsPruned::NotPruned, @@ -457,13 +459,14 @@ impl StateDbSync { PruningMode::ArchiveAll => Ok(()), PruningMode::ArchiveCanonical | PruningMode::Constrained(_) => { let have_block = self.non_canonical.have_block(hash) || - self.pruning.as_ref().map_or(false, |pruning| { - match pruning.have_block(hash, number) { + self.pruning.as_ref().map_or_else( + || hint(), + |pruning| match pruning.have_block(hash, number) { HaveBlock::No => false, HaveBlock::Yes => true, HaveBlock::Maybe => hint(), - } - }); + }, + ); if have_block { let refs = self.pinned.entry(hash.clone()).or_default(); if *refs == 0 { @@ -642,7 +645,7 @@ impl StateDb { /// Check if block is pruned away. pub fn is_pruned(&self, hash: &BlockHash, number: u64) -> IsPruned { - return self.db.read().is_pruned(hash, number) + self.db.read().is_pruned(hash, number) } /// Reset in-memory changes to the last disk-backed state. From 1cc2a007290ce32314a17e7d03af7b986e0630dc Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Mon, 13 Feb 2023 17:09:34 +0100 Subject: [PATCH 387/715] subkey: only decode hex if requested, CLI `0x` prefixed hex for all `stdout` (#13258) * Only decode hex if requested Signed-off-by: Oliver Tale-Yazdi * Cleanup code Signed-off-by: Oliver Tale-Yazdi * Add some tests Signed-off-by: Oliver Tale-Yazdi * Add license Signed-off-by: Oliver Tale-Yazdi * Docs Signed-off-by: Oliver Tale-Yazdi * Clippy Signed-off-by: Oliver Tale-Yazdi * bump version, breaking (tiny) change in output. * Move integration tests to own folder Signed-off-by: Oliver Tale-Yazdi --------- Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Dan Shields --- Cargo.lock | 2 +- bin/utils/subkey/Cargo.toml | 2 +- client/cli/src/commands/mod.rs | 1 + client/cli/src/commands/sign.rs | 75 +++++++--- client/cli/src/commands/test/mod.rs | 21 +++ client/cli/src/commands/test/sig_verify.rs | 152 +++++++++++++++++++++ client/cli/src/commands/utils.rs | 19 +-- client/cli/src/commands/verify.rs | 69 ++++++++-- client/cli/src/params/message_params.rs | 121 ++++++++++++++++ client/cli/src/params/mod.rs | 3 +- 10 files changed, 412 insertions(+), 53 deletions(-) create mode 100644 client/cli/src/commands/test/mod.rs create mode 100644 client/cli/src/commands/test/sig_verify.rs create mode 100644 client/cli/src/params/message_params.rs diff --git a/Cargo.lock b/Cargo.lock index 3e5ab65c0ce20..ad3267984563a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10560,7 +10560,7 @@ dependencies = [ [[package]] name = "subkey" -version = "2.0.2" +version = "3.0.0" dependencies = [ "clap 4.1.4", "sc-cli", diff --git a/bin/utils/subkey/Cargo.toml b/bin/utils/subkey/Cargo.toml index 77c323821a508..5d2d0f7779ced 100644 --- a/bin/utils/subkey/Cargo.toml +++ b/bin/utils/subkey/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "subkey" -version = "2.0.2" +version = "3.0.0" authors = ["Parity Technologies "] edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" diff --git a/client/cli/src/commands/mod.rs b/client/cli/src/commands/mod.rs index 8e84afa34e24a..eeb9f3be3eb14 100644 --- a/client/cli/src/commands/mod.rs +++ b/client/cli/src/commands/mod.rs @@ -31,6 +31,7 @@ mod purge_chain_cmd; mod revert_cmd; mod run_cmd; mod sign; +mod test; pub mod utils; mod vanity; mod verify; diff --git a/client/cli/src/commands/sign.rs b/client/cli/src/commands/sign.rs index 2c3ff3a1575fd..b3da31e56658b 100644 --- a/client/cli/src/commands/sign.rs +++ b/client/cli/src/commands/sign.rs @@ -17,9 +17,13 @@ // along with this program. If not, see . //! Implementation of the `sign` subcommand -use crate::{error, utils, with_crypto_scheme, CryptoSchemeFlag, KeystoreParams}; +use crate::{ + error, params::MessageParams, utils, with_crypto_scheme, CryptoSchemeFlag, KeystoreParams, +}; +use array_bytes::bytes2hex; use clap::Parser; use sp_core::crypto::SecretString; +use std::io::{BufRead, Write}; /// The `sign` command #[derive(Debug, Clone, Parser)] @@ -31,14 +35,9 @@ pub struct SignCmd { #[arg(long)] suri: Option, - /// Message to sign, if not provided you will be prompted to - /// pass the message via STDIN - #[arg(long)] - message: Option, - - /// The message on STDIN is hex-encoded data - #[arg(long)] - hex: bool, + #[allow(missing_docs)] + #[clap(flatten)] + pub message_params: MessageParams, #[allow(missing_docs)] #[clap(flatten)] @@ -52,15 +51,26 @@ pub struct SignCmd { impl SignCmd { /// Run the command pub fn run(&self) -> error::Result<()> { - let message = utils::read_message(self.message.as_ref(), self.hex)?; + let sig = self.sign(|| std::io::stdin().lock())?; + std::io::stdout().lock().write_all(sig.as_bytes())?; + Ok(()) + } + + /// Sign a message. + /// + /// The message can either be provided as immediate argument via CLI or otherwise read from the + /// reader created by `create_reader`. The reader will only be created in case that the message + /// is not passed as immediate. + pub(crate) fn sign(&self, create_reader: F) -> error::Result + where + R: BufRead, + F: FnOnce() -> R, + { + let message = self.message_params.message_from(create_reader)?; let suri = utils::read_uri(self.suri.as_ref())?; let password = self.keystore_params.read_password()?; - let signature = - with_crypto_scheme!(self.crypto_scheme.scheme, sign(&suri, password, message))?; - - println!("{}", signature); - Ok(()) + with_crypto_scheme!(self.crypto_scheme.scheme, sign(&suri, password, message)) } } @@ -70,26 +80,47 @@ fn sign( message: Vec, ) -> error::Result { let pair = utils::pair_from_suri::

(suri, password)?; - Ok(array_bytes::bytes2hex("", pair.sign(&message).as_ref())) + Ok(bytes2hex("0x", pair.sign(&message).as_ref())) } #[cfg(test)] mod test { use super::*; + const SEED: &str = "0xe5be9a5092b81bca64be81d212e7f2f9eba183bb7a90954f7b76361f6edb5c0a"; + #[test] - fn sign() { - let seed = "0xad1fb77243b536b90cfe5f0d351ab1b1ac40e3890b41dc64f766ee56340cfca5"; + fn sign_arg() { + let cmd = SignCmd::parse_from(&[ + "sign", + "--suri", + &SEED, + "--message", + &SEED, + "--password", + "12345", + "--hex", + ]); + let sig = cmd.sign(|| std::io::stdin().lock()).expect("Must sign"); + + assert!(sig.starts_with("0x"), "Signature must start with 0x"); + assert!(array_bytes::hex2bytes(&sig).is_ok(), "Signature is valid hex"); + } - let sign = SignCmd::parse_from(&[ + #[test] + fn sign_stdin() { + let cmd = SignCmd::parse_from(&[ "sign", "--suri", - seed, + SEED, "--message", - &seed[2..], + &SEED, "--password", "12345", ]); - assert!(sign.run().is_ok()); + let sig = cmd.sign(|| SEED.as_bytes()).expect("Must sign"); + + assert!(sig.starts_with("0x"), "Signature must start with 0x"); + assert!(array_bytes::hex2bytes(&sig).is_ok(), "Signature is valid hex"); } } diff --git a/client/cli/src/commands/test/mod.rs b/client/cli/src/commands/test/mod.rs new file mode 100644 index 0000000000000..762918f70ff0c --- /dev/null +++ b/client/cli/src/commands/test/mod.rs @@ -0,0 +1,21 @@ +// This file is part of Substrate. + +// Copyright (C) 2023 Parity Technologies (UK) Ltd. +// SPDX-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 . + +//! Integration tests for subkey commands. + +mod sig_verify; diff --git a/client/cli/src/commands/test/sig_verify.rs b/client/cli/src/commands/test/sig_verify.rs new file mode 100644 index 0000000000000..8d7247480be87 --- /dev/null +++ b/client/cli/src/commands/test/sig_verify.rs @@ -0,0 +1,152 @@ +// This file is part of Substrate. + +// Copyright (C) 2023 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#![cfg(test)] + +//! Integration test that the `sign` and `verify` sub-commands work together. + +use crate::*; +use clap::Parser; + +const SEED: &str = "0xe5be9a5092b81bca64be81d212e7f2f9eba183bb7a90954f7b76361f6edb5c0a"; +const ALICE: &str = "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY"; +const BOB: &str = "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty"; + +/// Sign a valid UFT-8 message which can be `hex` and passed either via `stdin` or as an argument. +fn sign(msg: &str, hex: bool, stdin: bool) -> String { + sign_raw(msg.as_bytes(), hex, stdin) +} + +/// Sign a raw message which can be `hex` and passed either via `stdin` or as an argument. +fn sign_raw(msg: &[u8], hex: bool, stdin: bool) -> String { + let mut args = vec!["sign", "--suri", SEED]; + if !stdin { + args.push("--message"); + args.push(std::str::from_utf8(msg).expect("Can only pass valid UTF-8 as arg")); + } + if hex { + args.push("--hex"); + } + let cmd = SignCmd::parse_from(&args); + cmd.sign(|| msg).expect("Static data is good; Must sign; qed") +} + +/// Verify a valid UFT-8 message which can be `hex` and passed either via `stdin` or as an argument. +fn verify(msg: &str, hex: bool, stdin: bool, who: &str, sig: &str) -> bool { + verify_raw(msg.as_bytes(), hex, stdin, who, sig) +} + +/// Verify a raw message which can be `hex` and passed either via `stdin` or as an argument. +fn verify_raw(msg: &[u8], hex: bool, stdin: bool, who: &str, sig: &str) -> bool { + let mut args = vec!["verify", sig, who]; + if !stdin { + args.push("--message"); + args.push(std::str::from_utf8(msg).expect("Can only pass valid UTF-8 as arg")); + } + if hex { + args.push("--hex"); + } + let cmd = VerifyCmd::parse_from(&args); + cmd.verify(|| msg).is_ok() +} + +/// Test that sig/verify works with UTF-8 bytes passed as arg. +#[test] +fn sig_verify_arg_utf8_work() { + let sig = sign("Something", false, false); + + assert!(verify("Something", false, false, ALICE, &sig)); + assert!(!verify("Something", false, false, BOB, &sig)); + + assert!(!verify("Wrong", false, false, ALICE, &sig)); + assert!(!verify("Not hex", true, false, ALICE, &sig)); + assert!(!verify("0x1234", true, false, ALICE, &sig)); + assert!(!verify("Wrong", false, false, BOB, &sig)); + assert!(!verify("Not hex", true, false, BOB, &sig)); + assert!(!verify("0x1234", true, false, BOB, &sig)); +} + +/// Test that sig/verify works with UTF-8 bytes passed via stdin. +#[test] +fn sig_verify_stdin_utf8_work() { + let sig = sign("Something", false, true); + + assert!(verify("Something", false, true, ALICE, &sig)); + assert!(!verify("Something", false, true, BOB, &sig)); + + assert!(!verify("Wrong", false, true, ALICE, &sig)); + assert!(!verify("Not hex", true, true, ALICE, &sig)); + assert!(!verify("0x1234", true, true, ALICE, &sig)); + assert!(!verify("Wrong", false, true, BOB, &sig)); + assert!(!verify("Not hex", true, true, BOB, &sig)); + assert!(!verify("0x1234", true, true, BOB, &sig)); +} + +/// Test that sig/verify works with hex bytes passed as arg. +#[test] +fn sig_verify_arg_hex_work() { + let sig = sign("0xaabbcc", true, false); + + assert!(verify("0xaabbcc", true, false, ALICE, &sig)); + assert!(verify("aabBcc", true, false, ALICE, &sig)); + assert!(verify("0xaAbbCC", true, false, ALICE, &sig)); + assert!(!verify("0xaabbcc", true, false, BOB, &sig)); + + assert!(!verify("0xaabbcc", false, false, ALICE, &sig)); +} + +/// Test that sig/verify works with hex bytes passed via stdin. +#[test] +fn sig_verify_stdin_hex_work() { + let sig = sign("0xaabbcc", true, true); + + assert!(verify("0xaabbcc", true, true, ALICE, &sig)); + assert!(verify("aabBcc", true, true, ALICE, &sig)); + assert!(verify("0xaAbbCC", true, true, ALICE, &sig)); + assert!(!verify("0xaabbcc", true, true, BOB, &sig)); + + assert!(!verify("0xaabbcc", false, true, ALICE, &sig)); +} + +/// Test that sig/verify works with random bytes. +#[test] +fn sig_verify_stdin_non_utf8_work() { + use rand::RngCore; + let mut rng = rand::thread_rng(); + + for _ in 0..100 { + let mut raw = [0u8; 32]; + rng.fill_bytes(&mut raw); + let sig = sign_raw(&raw, false, true); + + assert!(verify_raw(&raw, false, true, ALICE, &sig)); + assert!(!verify_raw(&raw, false, true, BOB, &sig)); + } +} + +/// Test that sig/verify works with invalid UTF-8 bytes. +#[test] +fn sig_verify_stdin_invalid_utf8_work() { + let raw = vec![192u8, 193]; + assert!(String::from_utf8(raw.clone()).is_err(), "Must be invalid UTF-8"); + + let sig = sign_raw(&raw, false, true); + + assert!(verify_raw(&raw, false, true, ALICE, &sig)); + assert!(!verify_raw(&raw, false, true, BOB, &sig)); +} diff --git a/client/cli/src/commands/utils.rs b/client/cli/src/commands/utils.rs index 1ce2b23221691..8ced185d7f3bc 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::{io::Read, path::PathBuf}; +use std::path::PathBuf; /// Public key type for Runtime pub type PublicFor

=

`. A user of this crate may statically assert that this can never happen and safely +/// `expect` this to return `Ok`. +pub fn approval_voting( + to_elect: usize, + candidates: Vec, + voters: Vec<(AccountId, VoteWeight, impl IntoIterator)>, +) -> Result, crate::Error> { + let to_elect = to_elect.min(candidates.len()); + + let (mut candidates, mut voters) = setup_inputs(candidates, voters); + + candidates.sort_by_key(|c| Reverse(c.borrow().approval_stake)); + + let winners = candidates + .into_iter() + .take(to_elect) + .map(|w| { + w.borrow_mut().elected = true; + w + }) + .map(|w_ptr| (w_ptr.borrow().who.clone(), w_ptr.borrow().approval_stake)) + .collect(); + + for voter in &mut voters { + for edge in &mut voter.edges { + if edge.candidate.borrow().elected { + edge.weight = voter.budget + } else { + edge.weight = Zero::zero() + } + } + } + + let assignments = voters.into_iter().filter_map(|v| v.into_assignment()).collect::>(); + + Ok(ElectionResult { winners, assignments }) +} diff --git a/primitives/npos-elections/src/lib.rs b/primitives/npos-elections/src/lib.rs index 716c4b283c68e..a1a38b9b0df12 100644 --- a/primitives/npos-elections/src/lib.rs +++ b/primitives/npos-elections/src/lib.rs @@ -25,6 +25,8 @@ //! - [`balance`](balancing::balance): Implements the star balancing algorithm. This iterative //! process can push a solution toward being more "balanced", which in turn can increase its //! score. +//! - [`approval_voting`](approval_voting::approval_voting): Implements an approval voting electoral +//! system where voters can back multiple candidates with the same stake. //! //! ### Terminology //! @@ -90,6 +92,7 @@ mod mock; #[cfg(test)] mod tests; +pub mod approval_voting; mod assignments; pub mod balancing; pub mod helpers; @@ -100,6 +103,7 @@ pub mod pjr; pub mod reduce; pub mod traits; +pub use approval_voting::*; pub use assignments::{Assignment, StakedAssignment}; pub use balancing::*; pub use helpers::*; diff --git a/primitives/npos-elections/src/phragmen.rs b/primitives/npos-elections/src/phragmen.rs index c3578065f364c..b7204ce1c34d8 100644 --- a/primitives/npos-elections/src/phragmen.rs +++ b/primitives/npos-elections/src/phragmen.rs @@ -57,7 +57,7 @@ const DEN: ExtendedBalance = ExtendedBalance::max_value(); /// - The returning weight distribution is _normalized_, meaning that it is guaranteed that the sum /// of the ratios in each voter's distribution sums up to exactly `P::one()`. /// -/// 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`. diff --git a/primitives/npos-elections/src/tests.rs b/primitives/npos-elections/src/tests.rs index 72ae9a0222be1..5fea4c2506406 100644 --- a/primitives/npos-elections/src/tests.rs +++ b/primitives/npos-elections/src/tests.rs @@ -18,12 +18,57 @@ //! Tests for npos-elections. use crate::{ - balancing, helpers::*, mock::*, seq_phragmen, seq_phragmen_core, setup_inputs, to_support_map, - Assignment, BalancingConfig, ElectionResult, ExtendedBalance, StakedAssignment, Support, Voter, + approval_voting::*, balancing, helpers::*, mock::*, seq_phragmen, seq_phragmen_core, + setup_inputs, to_support_map, Assignment, BalancingConfig, ElectionResult, ExtendedBalance, + StakedAssignment, Support, Voter, }; use sp_arithmetic::{PerU16, Perbill, Percent, Permill}; use substrate_test_utils::assert_eq_uvec; +#[test] +fn approval_voting_works() { + let candidates = vec![1, 2, 3, 4]; + let voters = vec![(10, vec![1, 2]), (20, vec![1, 2]), (30, vec![1, 2, 3]), (40, vec![4])]; + let stake_of = create_stake_of(&[(10, 10), (20, 20), (30, 30), (40, 40)]); + + let voters = voters + .iter() + .map(|(ref v, ref vs)| (*v, stake_of(v), vs.clone())) + .collect::>(); + + let ElectionResult::<_, Perbill> { winners, assignments } = + approval_voting(3, candidates, voters).unwrap(); + + assert_eq_uvec!(winners, vec![(1, 60), (2, 60), (4, 40)]); + assert_eq_uvec!( + assignments, + vec![ + Assignment { + who: 10u64, + distribution: vec![ + (1, Perbill::from_percent(100)), + (2, Perbill::from_percent(100)) + ] + }, + Assignment { + who: 20u64, + distribution: vec![ + (1, Perbill::from_percent(100)), + (2, Perbill::from_percent(100)) + ] + }, + Assignment { + who: 30u64, + distribution: vec![ + (1, Perbill::from_percent(100)), + (2, Perbill::from_percent(100)) + ] + }, + Assignment { who: 40u64, distribution: vec![(4, Perbill::from_percent(100))] }, + ] + ); +} + #[test] fn float_phragmen_poc_works() { let candidates = vec![1, 2, 3]; diff --git a/scripts/run_all_benchmarks.sh b/scripts/run_all_benchmarks.sh index b632cb5c12f04..818a5df7f6d95 100755 --- a/scripts/run_all_benchmarks.sh +++ b/scripts/run_all_benchmarks.sh @@ -67,8 +67,6 @@ 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" diff --git a/utils/frame/remote-externalities/Cargo.toml b/utils/frame/remote-externalities/Cargo.toml index 8611ae4980f12..e55b64efbdc75 100644 --- a/utils/frame/remote-externalities/Cargo.toml +++ b/utils/frame/remote-externalities/Cargo.toml @@ -25,7 +25,7 @@ futures = "0.3" [dev-dependencies] frame-support = { version = "4.0.0-dev", path = "../../../frame/support" } -pallet-elections-phragmen = { version = "5.0.0-dev", path = "../../../frame/elections-phragmen" } +pallet-elections = { version = "5.0.0-dev", path = "../../../frame/elections" } tracing-subscriber = { version = "0.3.16", features = ["env-filter"] } [features] From 919d5cf3d4b188265a3dcc7da2e1697c68dfcdec Mon Sep 17 00:00:00 2001 From: Sergejs Kostjucenko <85877331+sergejparity@users.noreply.github.com> Date: Thu, 23 Feb 2023 16:53:03 +0200 Subject: [PATCH 432/715] Move rules into common place (#13428) --- scripts/ci/docker/substrate.Dockerfile.README.md | 1 + scripts/ci/gitlab/pipeline/publish.yml | 12 ++++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) create mode 100644 scripts/ci/docker/substrate.Dockerfile.README.md diff --git a/scripts/ci/docker/substrate.Dockerfile.README.md b/scripts/ci/docker/substrate.Dockerfile.README.md new file mode 100644 index 0000000000000..557fd8f835d73 --- /dev/null +++ b/scripts/ci/docker/substrate.Dockerfile.README.md @@ -0,0 +1 @@ +# Substrate Docker Image \ No newline at end of file diff --git a/scripts/ci/gitlab/pipeline/publish.yml b/scripts/ci/gitlab/pipeline/publish.yml index 0d2e0cac96afe..3c280dec7325c 100644 --- a/scripts/ci/gitlab/pipeline/publish.yml +++ b/scripts/ci/gitlab/pipeline/publish.yml @@ -60,6 +60,10 @@ DOCKER_USERNAME: $Docker_Hub_User_Parity DOCKER_PASSWORD: $Docker_Hub_Pass_Parity README_FILEPATH: $CI_PROJECT_DIR/scripts/ci/docker/$PRODUCT.Dockerfile.README.md + rules: + - if: $CI_COMMIT_REF_NAME == "master" + changes: + - scripts/ci/docker/$PRODUCT.Dockerfile.README.md script: - cd / && sh entrypoint.sh @@ -81,6 +85,12 @@ publish-docker-substrate: variables: PRODUCT: substrate +publish-docker-description-substrate: + extends: .push-docker-image-description + variables: + PRODUCT: substrate + SHORT_DESCRIPTION: "Substrate Docker Image." + publish-docker-substrate-temporary: extends: .build-push-image-temporary needs: @@ -105,8 +115,6 @@ publish-docker-subkey: publish-docker-description-subkey: extends: .push-docker-image-description - needs: - - job: build-subkey-linux variables: PRODUCT: subkey SHORT_DESCRIPTION: "The subkey program is a key management utility for Substrate-based blockchains." From 91b4739e25efb2a06932703d60484fc6c857a909 Mon Sep 17 00:00:00 2001 From: Daniel Shiposha Date: Thu, 23 Feb 2023 15:06:12 +0000 Subject: [PATCH 433/715] Nfts attribute read interface (#13349) * feat: add custom and system attributes to Inspect * feat: add nfts runtime api * fix: pass std feature to runtime api * fix: api copyright Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> --------- Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> --- Cargo.lock | 11 +++ Cargo.toml | 1 + bin/node/runtime/Cargo.toml | 2 + bin/node/runtime/src/lib.rs | 52 ++++++++++++- frame/nfts/runtime-api/Cargo.toml | 28 +++++++ frame/nfts/runtime-api/README.md | 3 + frame/nfts/runtime-api/src/lib.rs | 57 ++++++++++++++ frame/nfts/src/impl_nonfungibles.rs | 32 +++++++- .../src/traits/tokens/nonfungible_v2.rs | 76 ++++++++++++++----- .../src/traits/tokens/nonfungibles_v2.rs | 59 ++++++++++++-- 10 files changed, 291 insertions(+), 30 deletions(-) create mode 100644 frame/nfts/runtime-api/Cargo.toml create mode 100644 frame/nfts/runtime-api/README.md create mode 100644 frame/nfts/runtime-api/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index e485a6512250e..afe2b46ee5fef 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3558,6 +3558,7 @@ dependencies = [ "pallet-mmr", "pallet-multisig", "pallet-nfts", + "pallet-nfts-runtime-api", "pallet-nis", "pallet-nomination-pools", "pallet-nomination-pools-benchmarking", @@ -6038,6 +6039,16 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-nfts-runtime-api" +version = "4.0.0-dev" +dependencies = [ + "frame-support", + "pallet-nfts", + "parity-scale-codec", + "sp-api", +] + [[package]] name = "pallet-nicks" version = "4.0.0-dev" diff --git a/Cargo.toml b/Cargo.toml index 2ae924bf6e1eb..b9f89365cd050 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -122,6 +122,7 @@ members = [ "frame/proxy", "frame/message-queue", "frame/nfts", + "frame/nfts/runtime-api", "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 d7b42efd4d2d6..71fa9320a77d6 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -79,6 +79,7 @@ pallet-message-queue = { version = "7.0.0-dev", default-features = false, path = 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-nfts = { version = "4.0.0-dev", default-features = false, path = "../../../frame/nfts" } +pallet-nfts-runtime-api = { version = "4.0.0-dev", default-features = false, path = "../../../frame/nfts/runtime-api" } 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" } @@ -203,6 +204,7 @@ std = [ "pallet-recovery/std", "pallet-uniques/std", "pallet-nfts/std", + "pallet-nfts-runtime-api/std", "pallet-vesting/std", "log/std", "frame-try-runtime?/std", diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 1ed43c211f8a1..a332127fb8f00 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -33,10 +33,10 @@ 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, - WithdrawReasons, + fungible::ItemOf, tokens::nonfungibles_v2::Inspect, AsEnsureOriginWithArg, ConstBool, + ConstU128, ConstU16, ConstU32, Currency, EitherOfDiverse, EqualPrivilegeOnly, Everything, + Imbalance, InstanceFilter, KeyOwnerProofSystem, LockIdentifier, Nothing, OnUnbalanced, + U128CurrencyToVote, WithdrawReasons, }, weights::{ constants::{ @@ -2187,6 +2187,50 @@ impl_runtime_apis! { } } + impl pallet_nfts_runtime_api::NftsApi for Runtime { + fn owner(collection: u32, item: u32) -> Option { + >::owner(&collection, &item) + } + + fn collection_owner(collection: u32) -> Option { + >::collection_owner(&collection) + } + + fn attribute( + collection: u32, + item: u32, + key: Vec, + ) -> Option> { + >::attribute(&collection, &item, &key) + } + + fn custom_attribute( + account: AccountId, + collection: u32, + item: u32, + key: Vec, + ) -> Option> { + >::custom_attribute( + &account, + &collection, + &item, + &key, + ) + } + + fn system_attribute( + collection: u32, + item: u32, + key: Vec, + ) -> Option> { + >::system_attribute(&collection, &item, &key) + } + + fn collection_attribute(collection: u32, key: Vec) -> Option> { + >::collection_attribute(&collection, &key) + } + } + impl pallet_mmr::primitives::MmrApi< Block, mmr::Hash, diff --git a/frame/nfts/runtime-api/Cargo.toml b/frame/nfts/runtime-api/Cargo.toml new file mode 100644 index 0000000000000..29d79e7768515 --- /dev/null +++ b/frame/nfts/runtime-api/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "pallet-nfts-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 for the FRAME NFTs pallet." +readme = "README.md" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } +frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } +pallet-nfts = { version = "4.0.0-dev", default-features = false, path = "../../nfts" } +sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/api" } + +[features] +default = ["std"] +std = [ + "codec/std", + "frame-support/std", + "pallet-nfts/std", + "sp-api/std", +] diff --git a/frame/nfts/runtime-api/README.md b/frame/nfts/runtime-api/README.md new file mode 100644 index 0000000000000..289036d2c0d27 --- /dev/null +++ b/frame/nfts/runtime-api/README.md @@ -0,0 +1,3 @@ +RPC runtime API for the FRAME NFTs pallet. + +License: Apache-2.0 diff --git a/frame/nfts/runtime-api/src/lib.rs b/frame/nfts/runtime-api/src/lib.rs new file mode 100644 index 0000000000000..0c23d178107e7 --- /dev/null +++ b/frame/nfts/runtime-api/src/lib.rs @@ -0,0 +1,57 @@ +// This file is part of Substrate. + +// Copyright (C) 2023 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Runtime API definition for the FRAME NFTs pallet. + +#![cfg_attr(not(feature = "std"), no_std)] + +use codec::{Decode, Encode}; +use frame_support::dispatch::Vec; + +sp_api::decl_runtime_apis! { + pub trait NftsApi + where + AccountId: Encode + Decode, + CollectionId: Encode, + ItemId: Encode, + { + fn owner(collection: CollectionId, item: ItemId) -> Option; + + fn collection_owner(collection: CollectionId) -> Option; + + fn attribute( + collection: CollectionId, + item: ItemId, + key: Vec, + ) -> Option>; + + fn custom_attribute( + account: AccountId, + collection: CollectionId, + item: ItemId, + key: Vec, + ) -> Option>; + + fn system_attribute( + collection: CollectionId, + item: ItemId, + key: Vec, + ) -> Option>; + + fn collection_attribute(collection: CollectionId, key: Vec) -> Option>; + } +} diff --git a/frame/nfts/src/impl_nonfungibles.rs b/frame/nfts/src/impl_nonfungibles.rs index ac02355ba29ac..ef6bbe7656ef8 100644 --- a/frame/nfts/src/impl_nonfungibles.rs +++ b/frame/nfts/src/impl_nonfungibles.rs @@ -50,18 +50,48 @@ impl, I: 'static> Inspect<::AccountId> for Palle fn attribute( collection: &Self::CollectionId, item: &Self::ItemId, - namespace: &AttributeNamespace<::AccountId>, key: &[u8], ) -> Option> { if key.is_empty() { // We make the empty key map to the item metadata value. ItemMetadataOf::::get(collection, item).map(|m| m.data.into()) } else { + let namespace = AttributeNamespace::CollectionOwner; let key = BoundedSlice::<_, _>::try_from(key).ok()?; Attribute::::get((collection, Some(item), namespace, key)).map(|a| a.0.into()) } } + /// Returns the custom attribute value of `item` of `collection` corresponding to `key`. + /// + /// By default this is `None`; no attributes are defined. + fn custom_attribute( + account: &T::AccountId, + collection: &Self::CollectionId, + item: &Self::ItemId, + key: &[u8], + ) -> Option> { + let namespace = Account::::get((account, collection, item)) + .map(|_| AttributeNamespace::ItemOwner) + .unwrap_or_else(|| AttributeNamespace::Account(account.clone())); + + let key = BoundedSlice::<_, _>::try_from(key).ok()?; + Attribute::::get((collection, Some(item), namespace, key)).map(|a| a.0.into()) + } + + /// Returns the system attribute value of `item` of `collection` corresponding to `key`. + /// + /// By default this is `None`; no attributes are defined. + fn system_attribute( + collection: &Self::CollectionId, + item: &Self::ItemId, + key: &[u8], + ) -> Option> { + let namespace = AttributeNamespace::Pallet; + let key = BoundedSlice::<_, _>::try_from(key).ok()?; + Attribute::::get((collection, Some(item), namespace, key)).map(|a| a.0.into()) + } + /// Returns the attribute value of `item` of `collection` corresponding to `key`. /// /// When `key` is empty, we return the item metadata value. diff --git a/frame/support/src/traits/tokens/nonfungible_v2.rs b/frame/support/src/traits/tokens/nonfungible_v2.rs index 36ef9ab0aa63f..175d94324aaa4 100644 --- a/frame/support/src/traits/tokens/nonfungible_v2.rs +++ b/frame/support/src/traits/tokens/nonfungible_v2.rs @@ -25,10 +25,7 @@ //! use. use super::nonfungibles_v2 as nonfungibles; -use crate::{ - dispatch::DispatchResult, - traits::{tokens::misc::AttributeNamespace, Get}, -}; +use crate::{dispatch::DispatchResult, traits::Get}; use codec::{Decode, Encode}; use sp_runtime::TokenError; use sp_std::prelude::*; @@ -45,23 +42,53 @@ pub trait Inspect { /// Returns the attribute value of `item` corresponding to `key`. /// /// By default this is `None`; no attributes are defined. - fn attribute( + fn attribute(_item: &Self::ItemId, _key: &[u8]) -> Option> { + None + } + + /// Returns the custom attribute value of `item` corresponding to `key`. + /// + /// By default this is `None`; no attributes are defined. + fn custom_attribute( + _account: &AccountId, _item: &Self::ItemId, - _namespace: &AttributeNamespace, _key: &[u8], ) -> Option> { None } + /// Returns the system attribute value of `item` corresponding to `key`. + /// + /// By default this is `None`; no attributes are defined. + fn system_attribute(_item: &Self::ItemId, _key: &[u8]) -> Option> { + None + } + /// Returns the strongly-typed attribute value of `item` corresponding to `key`. /// /// By default this just attempts to use `attribute`. - fn typed_attribute( + 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 the strongly-typed custom attribute value of `item` corresponding to `key`. + /// + /// By default this just attempts to use `custom_attribute`. + fn typed_custom_attribute( + account: &AccountId, item: &Self::ItemId, - namespace: &AttributeNamespace, key: &K, ) -> Option { - key.using_encoded(|d| Self::attribute(item, namespace, d)) + key.using_encoded(|d| Self::custom_attribute(account, item, d)) + .and_then(|v| V::decode(&mut &v[..]).ok()) + } + + /// Returns the strongly-typed system attribute value of `item` corresponding to `key`. + /// + /// By default this just attempts to use `system_attribute`. + fn typed_system_attribute(item: &Self::ItemId, key: &K) -> Option { + key.using_encoded(|d| Self::system_attribute(item, d)) .and_then(|v| V::decode(&mut &v[..]).ok()) } @@ -167,19 +194,32 @@ impl< fn owner(item: &Self::ItemId) -> Option { >::owner(&A::get(), item) } - fn attribute( - item: &Self::ItemId, - namespace: &AttributeNamespace, - key: &[u8], - ) -> Option> { - >::attribute(&A::get(), item, namespace, key) + fn attribute(item: &Self::ItemId, key: &[u8]) -> Option> { + >::attribute(&A::get(), item, key) + } + fn custom_attribute(account: &AccountId, item: &Self::ItemId, key: &[u8]) -> Option> { + >::custom_attribute(account, &A::get(), item, key) } - fn typed_attribute( + fn system_attribute(item: &Self::ItemId, key: &[u8]) -> Option> { + >::system_attribute(&A::get(), item, key) + } + fn typed_attribute(item: &Self::ItemId, key: &K) -> Option { + >::typed_attribute(&A::get(), item, key) + } + fn typed_custom_attribute( + account: &AccountId, item: &Self::ItemId, - namespace: &AttributeNamespace, key: &K, ) -> Option { - >::typed_attribute(&A::get(), item, namespace, key) + >::typed_custom_attribute( + account, + &A::get(), + item, + key, + ) + } + fn typed_system_attribute(item: &Self::ItemId, key: &K) -> Option { + >::typed_system_attribute(&A::get(), item, key) } fn can_transfer(item: &Self::ItemId) -> bool { >::can_transfer(&A::get(), item) diff --git a/frame/support/src/traits/tokens/nonfungibles_v2.rs b/frame/support/src/traits/tokens/nonfungibles_v2.rs index 9331f966822a6..5deb0c568f431 100644 --- a/frame/support/src/traits/tokens/nonfungibles_v2.rs +++ b/frame/support/src/traits/tokens/nonfungibles_v2.rs @@ -27,10 +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::{DispatchError, DispatchResult}, - traits::tokens::misc::AttributeNamespace, -}; +use crate::dispatch::{DispatchError, DispatchResult}; use codec::{Decode, Encode}; use sp_runtime::TokenError; use sp_std::prelude::*; @@ -61,7 +58,29 @@ pub trait Inspect { fn attribute( _collection: &Self::CollectionId, _item: &Self::ItemId, - _namespace: &AttributeNamespace, + _key: &[u8], + ) -> Option> { + None + } + + /// Returns the custom attribute value of `item` of `collection` corresponding to `key`. + /// + /// By default this is `None`; no attributes are defined. + fn custom_attribute( + _account: &AccountId, + _collection: &Self::CollectionId, + _item: &Self::ItemId, + _key: &[u8], + ) -> Option> { + None + } + + /// Returns the system attribute value of `item` of `collection` corresponding to `key`. + /// + /// By default this is `None`; no attributes are defined. + fn system_attribute( + _collection: &Self::CollectionId, + _item: &Self::ItemId, _key: &[u8], ) -> Option> { None @@ -74,10 +93,36 @@ pub trait Inspect { fn typed_attribute( collection: &Self::CollectionId, item: &Self::ItemId, - namespace: &AttributeNamespace, key: &K, ) -> Option { - key.using_encoded(|d| Self::attribute(collection, item, namespace, d)) + key.using_encoded(|d| Self::attribute(collection, item, d)) + .and_then(|v| V::decode(&mut &v[..]).ok()) + } + + /// Returns the strongly-typed custom attribute value of `item` of `collection` corresponding to + /// `key`. + /// + /// By default this just attempts to use `custom_attribute`. + fn typed_custom_attribute( + account: &AccountId, + collection: &Self::CollectionId, + item: &Self::ItemId, + key: &K, + ) -> Option { + key.using_encoded(|d| Self::custom_attribute(account, collection, item, d)) + .and_then(|v| V::decode(&mut &v[..]).ok()) + } + + /// Returns the strongly-typed system attribute value of `item` of `collection` corresponding to + /// `key`. + /// + /// By default this just attempts to use `system_attribute`. + fn typed_system_attribute( + collection: &Self::CollectionId, + item: &Self::ItemId, + key: &K, + ) -> Option { + key.using_encoded(|d| Self::system_attribute(collection, item, d)) .and_then(|v| V::decode(&mut &v[..]).ok()) } From fbddfbd76c60c6fda0024e8a44e82ad776033e4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 23 Feb 2023 18:15:08 +0000 Subject: [PATCH 434/715] Revert "Abstracts elections-phragmen pallet to use NposSolver (#12588)" (#13451) This reverts commit 4be5dd2937ab9fffd4f13772b547450a95a59018. --- Cargo.lock | 265 +++++---- Cargo.toml | 3 +- bin/node/runtime/Cargo.toml | 12 +- bin/node/runtime/src/lib.rs | 30 +- .../election-provider-multi-phase/Cargo.toml | 2 + frame/election-provider-support/Cargo.toml | 8 +- .../benchmarking/Cargo.toml | 37 ++ .../src/lib.rs} | 18 +- frame/election-provider-support/src/lib.rs | 26 - .../election-provider-support/src/onchain.rs | 30 +- .../election-provider-support/src/weights.rs | 147 ++--- .../CHANGELOG.md | 11 - .../Cargo.toml | 5 +- .../README.md | 6 +- .../src/benchmarking.rs | 57 +- .../src/lib.rs | 482 ++++++--------- .../src/migrations/mod.rs | 0 .../src/migrations/v3.rs | 0 .../src/migrations/v4.rs | 0 .../src/migrations/v5.rs | 0 frame/elections-phragmen/src/weights.rs | 559 ++++++++++++++++++ frame/elections/src/weights.rs | 397 ------------- .../npos-elections/src/approval_voting.rs | 79 --- primitives/npos-elections/src/lib.rs | 4 - primitives/npos-elections/src/phragmen.rs | 2 +- primitives/npos-elections/src/tests.rs | 49 +- scripts/run_all_benchmarks.sh | 2 + utils/frame/remote-externalities/Cargo.toml | 2 +- 28 files changed, 1027 insertions(+), 1206 deletions(-) create mode 100644 frame/election-provider-support/benchmarking/Cargo.toml rename frame/election-provider-support/{src/benchmarking.rs => benchmarking/src/lib.rs} (86%) rename frame/{elections => elections-phragmen}/CHANGELOG.md (80%) rename frame/{elections => elections-phragmen}/Cargo.toml (90%) rename frame/{elections => elections-phragmen}/README.md (94%) rename frame/{elections => elections-phragmen}/src/benchmarking.rs (85%) rename frame/{elections => elections-phragmen}/src/lib.rs (90%) rename frame/{elections => elections-phragmen}/src/migrations/mod.rs (100%) rename frame/{elections => elections-phragmen}/src/migrations/v3.rs (100%) rename frame/{elections => elections-phragmen}/src/migrations/v4.rs (100%) rename frame/{elections => elections-phragmen}/src/migrations/v5.rs (100%) create mode 100644 frame/elections-phragmen/src/weights.rs delete mode 100644 frame/elections/src/weights.rs delete mode 100644 primitives/npos-elections/src/approval_voting.rs diff --git a/Cargo.lock b/Cargo.lock index afe2b46ee5fef..7cfde057041e3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -27,7 +27,7 @@ version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" dependencies = [ - "gimli 0.27.2", + "gimli 0.27.1", ] [[package]] @@ -246,7 +246,7 @@ dependencies = [ "num-traits", "rusticata-macros", "thiserror", - "time 0.3.19", + "time 0.3.17", ] [[package]] @@ -262,7 +262,7 @@ dependencies = [ "num-traits", "rusticata-macros", "thiserror", - "time 0.3.19", + "time 0.3.17", ] [[package]] @@ -358,20 +358,19 @@ dependencies = [ [[package]] name = "async-stream" -version = "0.3.4" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad445822218ce64be7a341abfb0b1ea43b5c23aa83902542a4542e78309d8e5e" +checksum = "dad5c83079eae9969be7fadefe640a1c566901f05ff91ab221de4b6f68d9507e" dependencies = [ "async-stream-impl", "futures-core", - "pin-project-lite 0.2.9", ] [[package]] name = "async-stream-impl" -version = "0.3.4" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4655ae1a7b0cdf149156f780c5bf3f1352bc53cbd9e0a361a7ef7b22947e965" +checksum = "10f203db73a71dfa2fb6dd22763990fa26f3d2625a6da2da900d23b87d26be27" dependencies = [ "proc-macro2", "quote", @@ -580,9 +579,9 @@ dependencies = [ [[package]] name = "bindgen" -version = "0.64.0" +version = "0.60.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4243e6031260db77ede97ad86c27e501d646a27ab57b59a574f725d98ab1fb4" +checksum = "062dddbc1ba4aca46de6338e2bf87771414c335f7b2f2036e8f3e9befebf88e6" dependencies = [ "bitflags", "cexpr", @@ -595,7 +594,6 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn", ] [[package]] @@ -627,24 +625,24 @@ dependencies = [ [[package]] name = "blake2b_simd" -version = "1.0.1" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c2f0dc9a68c6317d884f97cc36cf5a3d20ba14ce404227df55e1af708ab04bc" +checksum = "72936ee4afc7f8f736d1c38383b56480b5497b4617b4a77bdbf1d2ababc76127" dependencies = [ "arrayref", "arrayvec 0.7.2", - "constant_time_eq", + "constant_time_eq 0.1.5", ] [[package]] name = "blake2s_simd" -version = "1.0.1" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6637f448b9e61dfadbdcbae9a885fadee1f3eaffb1f8d3c1965d3ade8bdfd44f" +checksum = "db539cc2b5f6003621f1cd9ef92d7ded8ea5232c7de0f9faa2de251cd98730d4" dependencies = [ "arrayref", "arrayvec 0.7.2", - "constant_time_eq", + "constant_time_eq 0.1.5", ] [[package]] @@ -657,7 +655,7 @@ dependencies = [ "arrayvec 0.7.2", "cc", "cfg-if", - "constant_time_eq", + "constant_time_eq 0.2.4", ] [[package]] @@ -717,9 +715,9 @@ checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" [[package]] name = "bounded-collections" -version = "0.1.5" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a071c348a5ef6da1d3a87166b408170b46002382b1dda83992b5c2208cefb370" +checksum = "de2aff4807e40f478132150d80b031f2461d88f061851afcab537d7600c24120" dependencies = [ "log", "parity-scale-codec", @@ -735,9 +733,9 @@ checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" [[package]] name = "bstr" -version = "1.3.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ffdb39cb703212f3c11973452c2861b972f757b021158f3516ba10f2fa8b2c1" +checksum = "b7f0778972c64420fdedc63f09919c8a88bda7b25135357fd25a5d9f3257e832" dependencies = [ "memchr", "once_cell", @@ -919,7 +917,7 @@ name = "chain-spec-builder" version = "2.0.0" dependencies = [ "ansi_term", - "clap 4.1.6", + "clap 4.1.4", "node-cli", "rand 0.8.5", "sc-chain-spec", @@ -1012,9 +1010,9 @@ dependencies = [ [[package]] name = "clang-sys" -version = "1.6.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ed9a53e5d4d9c573ae844bfac6872b159cb1d1585a83b29e7a64b7eef7332a" +checksum = "fa2e27ae6ab525c3d369ded447057bca5438d86dc3a68f6faafb8269ba82ebf3" dependencies = [ "glob", "libc", @@ -1035,9 +1033,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.1.6" +version = "4.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0b0588d44d4d63a87dbd75c136c166bbfd9a86a31cb89e09906521c7d3f5e3" +checksum = "f13b9c79b5d1dd500d20ef541215a6423c75829ef43117e1b4d17fd8af0b5d76" dependencies = [ "bitflags", "clap_derive", @@ -1050,11 +1048,11 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.1.2" +version = "4.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd125be87bf4c255ebc50de0b7f4d2a6201e8ac3dc86e39c0ad081dc5e7236fe" +checksum = "3d6540eedc41f8a5a76cf3d8d458057dcdf817be4158a55b5f861f7a5483de75" dependencies = [ - "clap 4.1.6", + "clap 4.1.4", ] [[package]] @@ -1124,6 +1122,12 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cec318a675afcb6a1ea1d4340e2d377e56e47c266f28043ceccbf4412ddfdd3b" +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + [[package]] name = "constant_time_eq" version = "0.2.4" @@ -1511,9 +1515,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.91" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86d3488e7665a7a483b57e25bdd90d0aeb2bc7608c8d0346acf2ad3f1caf1d62" +checksum = "bc831ee6a32dd495436e317595e639a587aa9907bef96fe6e6abc290ab6204e9" dependencies = [ "cc", "cxxbridge-flags", @@ -1523,9 +1527,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.91" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48fcaf066a053a41a81dfb14d57d99738b767febb8b735c3016e469fac5da690" +checksum = "94331d54f1b1a8895cd81049f7eaaaef9d05a7dcb4d1fd08bf3ff0806246789d" dependencies = [ "cc", "codespan-reporting", @@ -1538,15 +1542,15 @@ dependencies = [ [[package]] name = "cxxbridge-flags" -version = "1.0.91" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2ef98b8b717a829ca5603af80e1f9e2e48013ab227b68ef37872ef84ee479bf" +checksum = "48dcd35ba14ca9b40d6e4b4b39961f23d835dbb8eed74565ded361d93e1feb8a" [[package]] name = "cxxbridge-macro" -version = "1.0.91" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "086c685979a698443656e5cf7856c95c642295a38599f12fb1ff76fb28d19892" +checksum = "81bbeb29798b407ccd82a3324ade1a7286e0d29851475990b612670f6f5124d2" dependencies = [ "proc-macro2", "quote", @@ -2047,9 +2051,9 @@ checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" [[package]] name = "fastrand" -version = "1.9.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" dependencies = [ "instant", ] @@ -2091,14 +2095,14 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.20" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a3de6e8d11b22ff9edc6d916f890800597d60f8b2da1caf2955c274638d6412" +checksum = "4e884668cd0c7480504233e951174ddc3b382f7c2666e3b7310b5c4e7b0c37f9" dependencies = [ "cfg-if", "libc", "redox_syscall", - "windows-sys 0.45.0", + "windows-sys 0.42.0", ] [[package]] @@ -2218,7 +2222,7 @@ dependencies = [ "Inflector", "array-bytes", "chrono", - "clap 4.1.6", + "clap 4.1.4", "comfy-table", "frame-benchmarking", "frame-support", @@ -2291,7 +2295,6 @@ dependencies = [ name = "frame-election-provider-support" version = "4.0.0-dev" dependencies = [ - "frame-benchmarking", "frame-election-provider-solution-type", "frame-support", "frame-system", @@ -2310,7 +2313,7 @@ dependencies = [ name = "frame-election-solution-type-fuzzer" version = "2.0.0-alpha.5" dependencies = [ - "clap 4.1.6", + "clap 4.1.4", "frame-election-provider-solution-type", "frame-election-provider-support", "frame-support", @@ -2363,7 +2366,7 @@ dependencies = [ "frame-support", "futures", "log", - "pallet-elections", + "pallet-elections-phragmen", "parity-scale-codec", "serde", "sp-core", @@ -2793,9 +2796,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.27.2" +version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" +checksum = "221996f774192f0f718773def8201c4ae31f02616a54ccfc2d358bb0e5cefdec" [[package]] name = "git2" @@ -2938,9 +2941,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.3.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" +checksum = "856b5cb0902c2b6d65d5fd97dfa30f9b70c7538e770b98eab5ed52d8db923e01" [[package]] name = "hex" @@ -3032,9 +3035,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.9" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" dependencies = [ "bytes", "fnv", @@ -3318,7 +3321,7 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22e18b0a45d56fe973d6db23972bf5bc46f988a4a2385deac9cc29572f09daef" dependencies = [ - "hermit-abi 0.3.1", + "hermit-abi 0.3.0", "io-lifetimes", "rustix", "windows-sys 0.45.0", @@ -3544,7 +3547,8 @@ dependencies = [ "pallet-conviction-voting", "pallet-democracy", "pallet-election-provider-multi-phase", - "pallet-elections", + "pallet-election-provider-support-benchmarking", + "pallet-elections-phragmen", "pallet-fast-unstake", "pallet-glutton", "pallet-grandpa", @@ -4110,9 +4114,9 @@ dependencies = [ [[package]] name = "librocksdb-sys" -version = "0.8.3+7.4.4" +version = "0.8.0+7.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "557b255ff04123fcc176162f56ed0c9cd42d8f357cf55b3fabeb60f7413741b3" +checksum = "611804e4666a25136fcc5f8cf425ab4d26c7f74ea245ffe92ea23b85b6420b5d" dependencies = [ "bindgen", "bzip2-sys", @@ -4371,9 +4375,9 @@ dependencies = [ [[package]] name = "memmap2" -version = "0.5.9" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2af2c65375e552a67fe3829ca63e8a7c27a378a62824594f43b2851d682b5ec2" +checksum = "4b182332558b18d807c4ce1ca8ca983b34c3ee32765e47b3f0f69b90355cc1dc" dependencies = [ "libc", ] @@ -4441,14 +4445,14 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.6" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" +checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" dependencies = [ "libc", "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.45.0", + "windows-sys 0.42.0", ] [[package]] @@ -4730,7 +4734,7 @@ name = "node-bench" version = "0.9.0-dev" dependencies = [ "array-bytes", - "clap 4.1.6", + "clap 4.1.4", "derive_more", "fs_extra", "futures", @@ -4767,7 +4771,7 @@ version = "3.0.0-dev" dependencies = [ "array-bytes", "assert_cmd", - "clap 4.1.6", + "clap 4.1.4", "clap_complete", "criterion", "frame-benchmarking-cli", @@ -4887,7 +4891,7 @@ dependencies = [ name = "node-inspect" version = "0.9.0-dev" dependencies = [ - "clap 4.1.6", + "clap 4.1.4", "parity-scale-codec", "sc-cli", "sc-client-api", @@ -4946,7 +4950,7 @@ dependencies = [ name = "node-runtime-generate-bags" version = "3.0.0" dependencies = [ - "clap 4.1.6", + "clap 4.1.4", "generate-bags", "kitchensink-runtime", ] @@ -4955,7 +4959,7 @@ dependencies = [ name = "node-template" version = "4.0.0-dev" dependencies = [ - "clap 4.1.6", + "clap 4.1.4", "frame-benchmarking", "frame-benchmarking-cli", "frame-system", @@ -5211,9 +5215,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.17.1" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" [[package]] name = "oorandom" @@ -5719,6 +5723,7 @@ dependencies = [ "frame-system", "log", "pallet-balances", + "pallet-election-provider-support-benchmarking", "parity-scale-codec", "parking_lot 0.12.1", "rand 0.8.5", @@ -5734,11 +5739,22 @@ dependencies = [ ] [[package]] -name = "pallet-elections" -version = "5.0.0-dev" +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" +dependencies = [ + "frame-benchmarking", "frame-support", "frame-system", "log", @@ -6788,9 +6804,9 @@ dependencies = [ [[package]] name = "parity-scale-codec" -version = "3.4.0" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "637935964ff85a605d114591d4d2c13c5d1ba2806dae97cea6bf180238a749ac" +checksum = "c3840933452adf7b3b9145e27086a5a3376c619dca1a21b1e5a5af0d54979bed" dependencies = [ "arrayvec 0.7.2", "bitvec", @@ -6935,9 +6951,9 @@ checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" [[package]] name = "pest" -version = "2.5.5" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "028accff104c4e513bad663bbcd2ad7cfd5304144404c31ed0a77ac103d00660" +checksum = "4ab62d2fa33726dbe6321cc97ef96d8cde531e3eeaf858a058de53a8a6d40d8f" dependencies = [ "thiserror", "ucd-trie", @@ -6945,9 +6961,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.5.5" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ac3922aac69a40733080f53c1ce7f91dcf57e1a5f6c52f421fadec7fbdc4b69" +checksum = "8bf026e2d0581559db66d837fe5242320f525d85c76283c61f4d51a1238d65ea" dependencies = [ "pest", "pest_generator", @@ -6955,9 +6971,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.5.5" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d06646e185566b5961b4058dd107e0a7f56e77c3f484549fb119867773c0f202" +checksum = "2b27bd18aa01d91c8ed2b61ea23406a676b42d82609c6e2581fba42f0c15f17f" dependencies = [ "pest", "pest_meta", @@ -6968,9 +6984,9 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.5.5" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6f60b2ba541577e2a0c307c8f39d1439108120eb7903adeb6497fa880c59616" +checksum = "9f02b677c1859756359fc9983c2e56a0237f18624a3789528804406b7e915e5d" dependencies = [ "once_cell", "pest", @@ -7542,7 +7558,7 @@ checksum = "6413f3de1edee53342e6138e75b56d32e7bc6e332b3bd62d497b1929d4cfbcdd" dependencies = [ "pem", "ring", - "time 0.3.19", + "time 0.3.17", "x509-parser 0.13.2", "yasna", ] @@ -7555,7 +7571,7 @@ checksum = "ffbe84efe2f38dea12e9bfc1f65377fdf03e53a18cb3b995faedf7934c7e785b" dependencies = [ "pem", "ring", - "time 0.3.19", + "time 0.3.17", "yasna", ] @@ -8029,7 +8045,7 @@ version = "0.10.0-dev" dependencies = [ "array-bytes", "chrono", - "clap 4.1.6", + "clap 4.1.4", "fdlimit", "futures", "futures-timer", @@ -9064,7 +9080,7 @@ dependencies = [ name = "sc-storage-monitor" version = "0.1.0" dependencies = [ - "clap 4.1.6", + "clap 4.1.4", "futures", "log", "nix 0.26.2", @@ -9460,9 +9476,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.93" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cad406b69c91885b5107daf2c29572f6c8cdb3c66826821e286c533490c0bc76" +checksum = "7434af0dc1cbd59268aa98b4c22c131c0584d2232f6fb166efb993e2832e896a" dependencies = [ "itoa", "ryu", @@ -9545,9 +9561,9 @@ checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" [[package]] name = "signal-hook-registry" -version = "1.4.1" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" dependencies = [ "libc", ] @@ -9577,9 +9593,9 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.8" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" dependencies = [ "autocfg", ] @@ -10123,7 +10139,7 @@ dependencies = [ name = "sp-npos-elections-fuzzer" version = "2.0.0-alpha.5" dependencies = [ - "clap 4.1.6", + "clap 4.1.4", "honggfuzz", "parity-scale-codec", "rand 0.8.5", @@ -10480,9 +10496,9 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" [[package]] name = "spin" -version = "0.9.5" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dccf47db1b41fa1573ed27ccf5e08e3ca771cb994f776668c5ebda893b248fc" +checksum = "7f6002a767bff9e83f8eeecf883ecb8011875a21ae8da43bffb817a57e78cc09" [[package]] name = "spki" @@ -10600,7 +10616,7 @@ dependencies = [ name = "subkey" version = "3.0.0" dependencies = [ - "clap 4.1.6", + "clap 4.1.4", "sc-cli", ] @@ -10628,7 +10644,7 @@ dependencies = [ name = "substrate-frame-cli" version = "4.0.0-dev" dependencies = [ - "clap 4.1.6", + "clap 4.1.4", "frame-support", "frame-system", "sc-cli", @@ -10938,9 +10954,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "target-lexicon" -version = "0.12.6" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae9980cab1db3fceee2f6c6f643d5d8de2997c58ee8d25fb0cc8a9e9e7348e5" +checksum = "9410d0f6853b1d94f0e519fb95df60f29d2c1eff2d921ffdf01a4c8a3b54f12d" [[package]] name = "tempfile" @@ -11005,11 +11021,10 @@ checksum = "3bf63baf9f5039dadc247375c29eb13706706cfde997d0330d05aa63a77d8820" [[package]] name = "thread_local" -version = "1.1.7" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" dependencies = [ - "cfg-if", "once_cell", ] @@ -11045,9 +11060,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.19" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53250a3b3fed8ff8fd988587d8925d26a83ac3845d9e03b220b37f34c2b8d6c2" +checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376" dependencies = [ "itoa", "serde", @@ -11063,9 +11078,9 @@ checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" [[package]] name = "time-macros" -version = "0.2.7" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a460aeb8de6dcb0f381e1ee05f1cd56fcf5a5f6eb8187ff3d8f0b11078d38b7c" +checksum = "d967f99f534ca7e495c575c62638eebc2898a8c84c119b89e250477bc4ba16b2" dependencies = [ "time-core", ] @@ -11167,9 +11182,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.12" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fb52b74f05dbf495a8fba459fdc331812b96aa086d9eb78101fa0d4569c3313" +checksum = "d660770404473ccd7bc9f8b28494a811bc18542b915c0855c51e8f419d5223ce" dependencies = [ "futures-core", "pin-project-lite 0.2.9", @@ -11192,9 +11207,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.7" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5427d89453009325de0d8f342c9490009f76e999cb7672d77e46267448f7e6b2" +checksum = "0bb2e075f03b3d66d8d8785356224ba688d2906a371015e225beeb65ca92c740" dependencies = [ "bytes", "futures-core", @@ -11466,7 +11481,7 @@ name = "try-runtime-cli" version = "0.10.0-dev" dependencies = [ "async-trait", - "clap 4.1.6", + "clap 4.1.4", "frame-remote-externalities", "frame-try-runtime", "hex", @@ -11811,9 +11826,9 @@ checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" [[package]] name = "wasm-encoder" -version = "0.24.0" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "704553b4d614a47080b4a457a976b3c16174b19ce95b931b847561b590dd09ba" +checksum = "9a584273ccc2d9311f1dd19dc3fb26054661fa3e373d53ede5d1144ba07a9acd" dependencies = [ "leb128", ] @@ -11909,7 +11924,7 @@ version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01bf50edb2ea9d922aa75a7bf3c15e26a6c9e2d18c56e862b49737a582901729" dependencies = [ - "spin 0.9.5", + "spin 0.9.4", "wasmi_arena", "wasmi_core 0.5.0", "wasmparser-nostd", @@ -12154,9 +12169,9 @@ dependencies = [ [[package]] name = "wast" -version = "54.0.0" +version = "52.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0d3df4a63b10958fe98ab9d7e9a57a7bc900209d2b4edd10535bfb0703e6516" +checksum = "15942180f265280eede7bc38b239e9770031d1821c02d905284216c645316430" dependencies = [ "leb128", "memchr", @@ -12166,9 +12181,9 @@ dependencies = [ [[package]] name = "wat" -version = "1.0.59" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e9a7c7d177696d0548178c36e377d49eba54170e885801d4270e2d44e82ac84" +checksum = "37212100d4cbe6f0f6ff6e707f1e5a5b5b675f0451231ed9e4235e234e127ed3" dependencies = [ "wast", ] @@ -12238,7 +12253,7 @@ dependencies = [ "sha2 0.10.6", "stun", "thiserror", - "time 0.3.19", + "time 0.3.17", "tokio", "turn", "url", @@ -12311,9 +12326,9 @@ dependencies = [ [[package]] name = "webrtc-ice" -version = "0.9.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "465a03cc11e9a7d7b4f9f99870558fe37a102b65b93f8045392fef7c67b39e80" +checksum = "494483fbb2f5492620871fdc78b084aed8807377f6e3fe88b2e49f0a9c9c41d7" dependencies = [ "arc-swap", "async-trait", @@ -12671,7 +12686,7 @@ dependencies = [ "ring", "rusticata-macros", "thiserror", - "time 0.3.19", + "time 0.3.17", ] [[package]] @@ -12689,7 +12704,7 @@ dependencies = [ "oid-registry 0.6.1", "rusticata-macros", "thiserror", - "time 0.3.19", + "time 0.3.17", ] [[package]] @@ -12718,7 +12733,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aed2e7a52e3744ab4d0c05c20aa065258e84c49fd4226f5191b2ed29712710b4" dependencies = [ - "time 0.3.19", + "time 0.3.17", ] [[package]] @@ -12763,9 +12778,9 @@ dependencies = [ [[package]] name = "zstd-sys" -version = "2.0.7+zstd.1.5.4" +version = "2.0.6+zstd.1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94509c3ba2fe55294d752b79842c530ccfab760192521df74a081a78d2b3c7f5" +checksum = "68a3f9792c0c3dc6c165840a75f47ae1f4da402c2d006881129579f6597e801b" dependencies = [ "cc", "libc", diff --git a/Cargo.toml b/Cargo.toml index b9f89365cd050..80dd2b90f85c2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -97,9 +97,10 @@ members = [ "frame/democracy", "frame/fast-unstake", "frame/try-runtime", - "frame/elections", + "frame/elections-phragmen", "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 71fa9320a77d6..3df4596aaad90 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -66,7 +66,8 @@ pallet-contracts-primitives = { version = "7.0.0", default-features = false, pat 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 = { version = "5.0.0-dev", default-features = false, path = "../../../frame/elections" } +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-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" } @@ -124,6 +125,7 @@ with-tracing = ["frame-executive/with-tracing"] 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", @@ -144,7 +146,7 @@ std = [ "pallet-contracts-primitives/std", "pallet-conviction-voting/std", "pallet-democracy/std", - "pallet-elections/std", + "pallet-elections-phragmen/std", "pallet-fast-unstake/std", "frame-executive/std", "pallet-nis/std", @@ -218,7 +220,6 @@ runtime-benchmarks = [ "frame-benchmarking-pallet-pov/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", - "frame-election-provider-support/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "pallet-alliance/runtime-benchmarks", "pallet-assets/runtime-benchmarks", @@ -232,7 +233,8 @@ runtime-benchmarks = [ "pallet-conviction-voting/runtime-benchmarks", "pallet-democracy/runtime-benchmarks", "pallet-election-provider-multi-phase/runtime-benchmarks", - "pallet-elections/runtime-benchmarks", + "pallet-election-provider-support-benchmarking/runtime-benchmarks", + "pallet-elections-phragmen/runtime-benchmarks", "pallet-fast-unstake/runtime-benchmarks", "pallet-nis/runtime-benchmarks", "pallet-grandpa/runtime-benchmarks", @@ -289,7 +291,7 @@ try-runtime = [ "pallet-conviction-voting/try-runtime", "pallet-democracy/try-runtime", "pallet-election-provider-multi-phase/try-runtime", - "pallet-elections/try-runtime", + "pallet-elections-phragmen/try-runtime", "pallet-fast-unstake/try-runtime", "pallet-nis/try-runtime", "pallet-grandpa/try-runtime", diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index a332127fb8f00..a869d309fa479 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -24,8 +24,7 @@ use codec::{Decode, Encode, MaxEncodedLen}; use frame_election_provider_support::{ - onchain, weights::SubstrateWeight, ApprovalVoting, BalancingConfig, ElectionDataProvider, - SequentialPhragmen, VoteWeight, + onchain, BalancingConfig, ElectionDataProvider, SequentialPhragmen, VoteWeight, }; use frame_support::{ construct_runtime, @@ -1011,21 +1010,18 @@ parameter_types! { pub const TermDuration: BlockNumber = 7 * DAYS; pub const DesiredMembers: u32 = 13; pub const DesiredRunnersUp: u32 = 7; + pub const MaxVotesPerVoter: u32 = 16; pub const MaxVoters: u32 = 512; pub const MaxCandidates: u32 = 64; - pub const MaxVotesPerVoter: u32 = 16; - // The ElectionsPalletId parameter name was changed along with the renaming of the elections - // pallet, but we keep the same lock ID to prevent a migration from current runtimes. - // Related to https://github.com/paritytech/substrate/issues/8250 - pub const ElectionsPalletId: LockIdentifier = *b"phrelect"; + pub const ElectionsPhragmenPalletId: LockIdentifier = *b"phrelect"; } // Make sure that there are no more than `MaxMembers` members elected via elections-phragmen. const_assert!(DesiredMembers::get() <= CouncilMaxMembers::get()); -impl pallet_elections::Config for Runtime { +impl pallet_elections_phragmen::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type PalletId = ElectionsPalletId; + type PalletId = ElectionsPhragmenPalletId; type Currency = Balances; type ChangeMembers = Council; // NOTE: this implies that council's genesis members cannot be set directly and must come from @@ -1043,9 +1039,7 @@ impl pallet_elections::Config for Runtime { type MaxVoters = MaxVoters; type MaxVotesPerVoter = MaxVotesPerVoter; type MaxCandidates = MaxCandidates; - type ElectionSolver = ApprovalVoting; - type SolverWeightInfo = SubstrateWeight; - type WeightInfo = pallet_elections::weights::SubstrateWeight; + type WeightInfo = pallet_elections_phragmen::weights::SubstrateWeight; } parameter_types! { @@ -1743,7 +1737,7 @@ construct_runtime!( Democracy: pallet_democracy, Council: pallet_collective::, TechnicalCommittee: pallet_collective::, - Elections: pallet_elections, + Elections: pallet_elections_phragmen, TechnicalMembership: pallet_membership::, Grandpa: pallet_grandpa, Treasury: pallet_treasury, @@ -1857,7 +1851,6 @@ mod benches { frame_benchmarking::define_benchmarks!( [frame_benchmarking, BaselineBench::] [frame_benchmarking_pallet_pov, Pov] - [frame_election_provider_support, EPSBench::] [pallet_alliance, Alliance] [pallet_assets, Assets] [pallet_babe, Babe] @@ -1870,7 +1863,8 @@ mod benches { [pallet_contracts, Contracts] [pallet_democracy, Democracy] [pallet_election_provider_multi_phase, ElectionProviderMultiPhase] - [pallet_elections, Elections] + [pallet_election_provider_support_benchmarking, EPSBench::] + [pallet_elections_phragmen, Elections] [pallet_fast_unstake, FastUnstake] [pallet_nis, Nis] [pallet_grandpa, Grandpa] @@ -2329,7 +2323,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 frame_election_provider_support::benchmarking::Pallet as EPSBench; + 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; @@ -2352,14 +2346,14 @@ 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 frame_election_provider_support::benchmarking::Pallet as EPSBench; + 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 frame_election_provider_support::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 {} diff --git a/frame/election-provider-multi-phase/Cargo.toml b/frame/election-provider-multi-phase/Cargo.toml index 996f40febdeba..aa734850aae43 100644 --- a/frame/election-provider-multi-phase/Cargo.toml +++ b/frame/election-provider-multi-phase/Cargo.toml @@ -33,6 +33,7 @@ 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.8.5", default-features = false, features = ["alloc", "small_rng"], optional = true } strum = { version = "0.24.1", default-features = false, features = ["derive"], optional = true } @@ -49,6 +50,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", diff --git a/frame/election-provider-support/Cargo.toml b/frame/election-provider-support/Cargo.toml index f9cb5233ced22..114caee793f1a 100644 --- a/frame/election-provider-support/Cargo.toml +++ b/frame/election-provider-support/Cargo.toml @@ -23,8 +23,6 @@ sp-runtime = { version = "7.0.0", default-features = false, path = "../../primit sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } sp-core = { version = "7.0.0", default-features = false, path = "../../primitives/core" } -frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } - [dev-dependencies] rand = { version = "0.8.5", features = ["small_rng"] } sp-io = { version = "7.0.0", path = "../../primitives/io" } @@ -43,10 +41,6 @@ std = [ "sp-core/std", "sp-runtime/std", "sp-std/std", - - "frame-benchmarking?/std", -] -runtime-benchmarks = [ - "frame-benchmarking/runtime-benchmarks", ] +runtime-benchmarks = [] try-runtime = [] diff --git a/frame/election-provider-support/benchmarking/Cargo.toml b/frame/election-provider-support/benchmarking/Cargo.toml new file mode 100644 index 0000000000000..bef371ec5efbf --- /dev/null +++ b/frame/election-provider-support/benchmarking/Cargo.toml @@ -0,0 +1,37 @@ +[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.2.2", 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 = "7.0.0", default-features = false, path = "../../../primitives/runtime" } + +[features] +default = ["std"] +std = [ + "codec/std", + "frame-benchmarking?/std", + "frame-election-provider-support/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/election-provider-support/src/benchmarking.rs b/frame/election-provider-support/benchmarking/src/lib.rs similarity index 86% rename from frame/election-provider-support/src/benchmarking.rs rename to frame/election-provider-support/benchmarking/src/lib.rs index 5c5b952b6dcc9..774b7036fd413 100644 --- a/frame/election-provider-support/src/benchmarking.rs +++ b/frame/election-provider-support/benchmarking/src/lib.rs @@ -18,9 +18,12 @@ //! Election provider support pallet benchmarking. //! This is separated into its own crate to avoid bloating the size of the runtime. -use crate::{ApprovalVoting, NposSolver, PhragMMS, SequentialPhragmen}; +#![cfg(feature = "runtime-benchmarks")] +#![cfg_attr(not(feature = "std"), no_std)] + use codec::Decode; use frame_benchmarking::v1::{benchmarks, Vec}; +use frame_election_provider_support::{NposSolver, PhragMMS, SequentialPhragmen}; pub struct Pallet(frame_system::Pallet); pub trait Config: frame_system::Config {} @@ -85,17 +88,4 @@ benchmarks! { ::solve(d as usize, targets, voters).is_ok() ); } - - approval_voting { - let v in (VOTERS[0]) .. VOTERS[1]; - let t in (TARGETS[0]) .. TARGETS[1]; - let d in (VOTES_PER_VOTER[0]) .. VOTES_PER_VOTER[1]; - - let (voters, targets) = set_up_voters_targets::(v, t, d as usize); - }: { - assert!( - ApprovalVoting:: - ::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 423ce3d67e8cb..750ccca46213f 100644 --- a/frame/election-provider-support/src/lib.rs +++ b/frame/election-provider-support/src/lib.rs @@ -199,9 +199,6 @@ pub use sp_arithmetic; #[doc(hidden)] pub use sp_std; -#[cfg(feature = "runtime-benchmarks")] -pub mod benchmarking; - pub mod weights; pub use weights::WeightInfo; @@ -663,29 +660,6 @@ impl(sp_std::marker::PhantomData<(AccountId, Accuracy)>); - -impl NposSolver - for ApprovalVoting -{ - type AccountId = AccountId; - type Accuracy = Accuracy; - type Error = sp_npos_elections::Error; - fn solve( - winners: usize, - targets: Vec, - voters: Vec<(Self::AccountId, VoteWeight, impl IntoIterator)>, - ) -> Result, Self::Error> { - sp_npos_elections::approval_voting(winners, targets, voters) - } - - fn weight(voters: u32, targets: u32, vote_degree: u32) -> Weight { - T::approval_voting(voters, targets, vote_degree) - } -} - /// A voter, at the level of abstraction of this crate. pub type Voter = (AccountId, VoteWeight, BoundedVec); diff --git a/frame/election-provider-support/src/onchain.rs b/frame/election-provider-support/src/onchain.rs index 60c7853c794dc..296ac976d59f3 100644 --- a/frame/election-provider-support/src/onchain.rs +++ b/frame/election-provider-support/src/onchain.rs @@ -185,7 +185,7 @@ impl ElectionProvider for OnChainExecution { #[cfg(test)] mod tests { use super::*; - use crate::{ApprovalVoting, ElectionProvider, PhragMMS, SequentialPhragmen}; + use crate::{ElectionProvider, PhragMMS, SequentialPhragmen}; use frame_support::{assert_noop, parameter_types, traits::ConstU32}; use sp_npos_elections::Support; use sp_runtime::Perbill; @@ -235,7 +235,6 @@ mod tests { struct PhragmenParams; struct PhragMMSParams; - struct ApprovalVotingParams; parameter_types! { pub static MaxWinners: u32 = 10; @@ -262,16 +261,6 @@ mod tests { type TargetsBound = ConstU32<400>; } - impl Config for ApprovalVotingParams { - type System = Runtime; - type Solver = ApprovalVoting; - type DataProvider = mock_data_provider::DataProvider; - type WeightInfo = (); - type MaxWinners = MaxWinners; - type VotersBound = ConstU32<600>; - type TargetsBound = ConstU32<400>; - } - mod mock_data_provider { use frame_support::{bounded_vec, traits::ConstU32}; @@ -344,21 +333,4 @@ mod tests { ); }) } - - #[test] - fn onchain_approval_voting_works() { - sp_io::TestExternalities::new_empty().execute_with(|| { - DesiredTargets::set(3); - - // note that the `OnChainExecution::elect` implementation normalizes the vote weights. - assert_eq!( - as ElectionProvider>::elect().unwrap(), - vec![ - (10, Support { total: 20, voters: vec![(1, 5), (3, 15)] }), - (20, Support { total: 15, voters: vec![(1, 5), (2, 10)] }), - (30, Support { total: 25, voters: vec![(2, 10), (3, 15)] }) - ] - ) - }) - } } diff --git a/frame/election-provider-support/src/weights.rs b/frame/election-provider-support/src/weights.rs index c28794267c640..fd4db1374ac4a 100644 --- a/frame/election-provider-support/src/weights.rs +++ b/frame/election-provider-support/src/weights.rs @@ -1,13 +1,13 @@ // This file is part of Substrate. -// Copyright (C) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -15,29 +15,25 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for frame_election_provider_support +//! Autogenerated weights for pallet_election_provider_support_benchmarking //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-22, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-ehxwxxsd-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! 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/production/substrate +// target/release/substrate // benchmark // pallet -// --steps=50 -// --repeat=20 +// --chain=dev +// --steps=1 +// --repeat=1 +// --pallet=pallet_election_provider_support_benchmarking // --extrinsic=* // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --json-file=/builds/parity/mirrors/substrate/.git/.artifacts/bench.json -// --pallet=frame_election_provider_support -// --chain=dev -// --header=./HEADER-APACHE2 -// --output=./frame/election-provider-support/src/weights.rs +// --output=frame/election-provider-support/src/weights.rs // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -47,108 +43,53 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; -/// Weight functions needed for frame_election_provider_support. +/// 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; - fn approval_voting(v: u32, t: u32, d: u32, ) -> Weight; } -/// Weights for frame_election_provider_support using the Substrate node and recommended hardware. +/// Weights for pallet_election_provider_support_benchmarking using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// The range of component `v` is `[1000, 2000]`. - /// The range of component `t` is `[500, 1000]`. - /// The range of component `d` is `[5, 16]`. - fn phragmen(v: u32, _t: u32, d: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 5_789_174 nanoseconds. - Weight::from_ref_time(5_826_449_000) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 130_342 - .saturating_add(Weight::from_ref_time(5_332_741).saturating_mul(v.into())) - // Standard Error: 13_325_769 - .saturating_add(Weight::from_ref_time(1_416_874_101).saturating_mul(d.into())) + fn phragmen(v: u32, t: u32, d: u32, ) -> Weight { + Weight::from_ref_time(0 as u64) + // Standard Error: 667_000 + .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 u64).saturating_mul(t as u64)) + // Standard Error: 60_644_000 + .saturating_add(Weight::from_ref_time(2_636_364_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 `d` is `[5, 16]`. - fn phragmms(v: u32, _t: u32, d: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 4_151_790 nanoseconds. - Weight::from_ref_time(4_215_936_000) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 125_135 - .saturating_add(Weight::from_ref_time(4_730_609).saturating_mul(v.into())) - // Standard Error: 12_793_390 - .saturating_add(Weight::from_ref_time(1_474_383_961).saturating_mul(d.into())) - } - /// The range of component `v` is `[1000, 2000]`. - /// The range of component `t` is `[500, 1000]`. - /// The range of component `d` is `[5, 16]`. - fn approval_voting(v: u32, _t: u32, d: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 1_800_445 nanoseconds. - Weight::from_ref_time(1_824_645_000) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 26_266 - .saturating_add(Weight::from_ref_time(1_229_576).saturating_mul(v.into())) - // Standard Error: 2_685_343 - .saturating_add(Weight::from_ref_time(213_080_804).saturating_mul(d.into())) + fn phragmms(v: u32, t: u32, d: u32, ) -> Weight { + Weight::from_ref_time(0 as u64) + // Standard Error: 73_000 + .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 u64).saturating_mul(t as u64)) + // Standard Error: 6_649_000 + .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 () { - /// The range of component `v` is `[1000, 2000]`. - /// The range of component `t` is `[500, 1000]`. - /// The range of component `d` is `[5, 16]`. - fn phragmen(v: u32, _t: u32, d: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 5_789_174 nanoseconds. - Weight::from_ref_time(5_826_449_000) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 130_342 - .saturating_add(Weight::from_ref_time(5_332_741).saturating_mul(v.into())) - // Standard Error: 13_325_769 - .saturating_add(Weight::from_ref_time(1_416_874_101).saturating_mul(d.into())) - } - /// The range of component `v` is `[1000, 2000]`. - /// The range of component `t` is `[500, 1000]`. - /// The range of component `d` is `[5, 16]`. - fn phragmms(v: u32, _t: u32, d: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 4_151_790 nanoseconds. - Weight::from_ref_time(4_215_936_000) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 125_135 - .saturating_add(Weight::from_ref_time(4_730_609).saturating_mul(v.into())) - // Standard Error: 12_793_390 - .saturating_add(Weight::from_ref_time(1_474_383_961).saturating_mul(d.into())) + fn phragmen(v: u32, t: u32, d: u32, ) -> Weight { + Weight::from_ref_time(0 as u64) + // Standard Error: 667_000 + .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 u64).saturating_mul(t as u64)) + // Standard Error: 60_644_000 + .saturating_add(Weight::from_ref_time(2_636_364_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 `d` is `[5, 16]`. - fn approval_voting(v: u32, _t: u32, d: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 1_800_445 nanoseconds. - Weight::from_ref_time(1_824_645_000) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 26_266 - .saturating_add(Weight::from_ref_time(1_229_576).saturating_mul(v.into())) - // Standard Error: 2_685_343 - .saturating_add(Weight::from_ref_time(213_080_804).saturating_mul(d.into())) + fn phragmms(v: u32, t: u32, d: u32, ) -> Weight { + Weight::from_ref_time(0 as u64) + // Standard Error: 73_000 + .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 u64).saturating_mul(t as u64)) + // Standard Error: 6_649_000 + .saturating_add(Weight::from_ref_time(1_711_424_000 as u64).saturating_mul(d as u64)) } } diff --git a/frame/elections/CHANGELOG.md b/frame/elections-phragmen/CHANGELOG.md similarity index 80% rename from frame/elections/CHANGELOG.md rename to frame/elections-phragmen/CHANGELOG.md index b173557be6feb..231de1d2e475e 100644 --- a/frame/elections/CHANGELOG.md +++ b/frame/elections-phragmen/CHANGELOG.md @@ -4,17 +4,6 @@ All notable changes to this crate will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this crate adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [5.0.0] - UNRELEASED - -### Added - -### Changed -Generalized the pallet to use `NposSolver` instead of hard coding the phragmen algorithm; Changed the name of the pallet from `pallet-elections-phragmen` to `pallet-elections` - -### Fixed - -### Security - ## [4.0.0] - UNRELEASED ### Added diff --git a/frame/elections/Cargo.toml b/frame/elections-phragmen/Cargo.toml similarity index 90% rename from frame/elections/Cargo.toml rename to frame/elections-phragmen/Cargo.toml index 14d07eca7dde7..ce39e42b8eeb5 100644 --- a/frame/elections/Cargo.toml +++ b/frame/elections-phragmen/Cargo.toml @@ -1,12 +1,12 @@ [package] -name = "pallet-elections" +name = "pallet-elections-phragmen" version = "5.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 generic elections." +description = "FRAME pallet based on seq-Phragmén election method." readme = "README.md" [package.metadata.docs.rs] @@ -24,7 +24,6 @@ frame-system = { version = "4.0.0-dev", default-features = false, path = "../sys 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" } -frame-election-provider-support = { version = "4.0.0-dev", default-features = false, path = "../election-provider-support" } 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/frame/elections/README.md b/frame/elections-phragmen/README.md similarity index 94% rename from frame/elections/README.md rename to frame/elections-phragmen/README.md index 0f27bdd189110..26b3f260da563 100644 --- a/frame/elections/README.md +++ b/frame/elections-phragmen/README.md @@ -1,6 +1,6 @@ -# Generic Elections Module. +# Phragmén Election Module. -A generic elections module. +An election module based on sequential phragmen. ### Term and Round @@ -60,7 +60,7 @@ being re-elected at the end of each round. ### Module Information -- [`elections::Config`](https://docs.rs/pallet-elections-phragmen/latest/pallet_elections_phragmen/trait.Config.html) +- [`election_sp_phragmen::Config`](https://docs.rs/pallet-elections-phragmen/latest/pallet_elections_phragmen/trait.Config.html) - [`Call`](https://docs.rs/pallet-elections-phragmen/latest/pallet_elections_phragmen/enum.Call.html) - [`Module`](https://docs.rs/pallet-elections-phragmen/latest/pallet_elections_phragmen/struct.Module.html) diff --git a/frame/elections/src/benchmarking.rs b/frame/elections-phragmen/src/benchmarking.rs similarity index 85% rename from frame/elections/src/benchmarking.rs rename to frame/elections-phragmen/src/benchmarking.rs index da755fe9b56c4..56ea19578c8f5 100644 --- a/frame/elections/src/benchmarking.rs +++ b/frame/elections-phragmen/src/benchmarking.rs @@ -15,14 +15,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Elections pallet benchmarking. +//! Elections-Phragmen pallet benchmarking. #![cfg(feature = "runtime-benchmarks")] use super::*; use frame_benchmarking::v1::{account, benchmarks, whitelist, BenchmarkError, BenchmarkResult}; -use frame_support::dispatch::DispatchResultWithPostInfo; +use frame_support::{dispatch::DispatchResultWithPostInfo, traits::OnInitialize}; use frame_system::RawOrigin; use crate::Pallet as Elections; @@ -37,7 +37,7 @@ fn endowed_account(name: &'static str, index: u32) -> T::AccountId { 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 - // the election to work. + // phragmen to work. T::Currency::issue(amount); account @@ -122,7 +122,7 @@ fn distribute_voters( fn fill_seats_up_to(m: u32) -> Result, &'static str> { let _ = submit_candidates_with_self_vote::(m, "fill_seats_up_to")?; assert_eq!(>::candidates().len() as u32, m, "wrong number of candidates."); - >::do_election(); + >::do_phragmen(); assert_eq!(>::candidates().len(), 0, "some candidates remaining."); assert_eq!( >::members().len() + >::runners_up().len(), @@ -382,11 +382,11 @@ benchmarks! { assert_eq!(>::iter().count() as u32, 0); } - pre_solve_election { - // We always select 20 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. + election_phragmen { + // This is just to focus on phragmen in the context of this module. We always select 20 + // 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 .. T::MaxCandidates::get(); let v in 1 .. T::MaxVoters::get(); let e in (T::MaxVoters::get()) .. T::MaxVoters::get() * T::MaxVotesPerVoter::get(); @@ -404,44 +404,7 @@ benchmarks! { let all_candidates = submit_candidates_with_self_vote::(c, "candidates")?; let _ = distribute_voters::(all_candidates, v.saturating_sub(c), votes_per_voter as usize)?; }: { - >::do_pre_solve_election().unwrap(); - } - - post_solve_election { - // We always select 20 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 .. T::MaxCandidates::get(); - let v in 1 .. T::MaxVoters::get(); - let e in (T::MaxVoters::get()) .. T::MaxVoters::get() as u32 * T::MaxVotesPerVoter::get() as u32; - clean::(); - - // so we have a situation with v and e. we want e to basically always be in the range of `e - // -> e * T::MaxVotesPerVoter`, but we cannot express that now with the benchmarks. So what we do - // is: when c is being iterated, v, and e are max and fine. when v is being iterated, e is - // being set to max and this is a problem. In these cases, we cap e to a lower value, namely - // v * `T::MaxVotesPerVoter`. when e is being iterated, v is at max, and again fine. all in all, - // votes_per_voter can never be more than `T::MaxVotesPerVoter`. Note that this might cause `v` to be - // an overestimate. - let votes_per_voter = (e / v).min(T::MaxVotesPerVoter::get() as u32); - - let all_candidates = submit_candidates_with_self_vote::(c, "candidates")?; - let _ = distribute_voters::(all_candidates, v.saturating_sub(c), votes_per_voter as usize)?; - - let pre_election_result = >::do_pre_solve_election().unwrap(); - let election_result = T::ElectionSolver::solve( - pre_election_result.num_to_elect, - pre_election_result.candidate_ids, - pre_election_result.voters_and_votes, - ).unwrap(); - - }: { - >::do_post_solve_election( - election_result.winners, - pre_election_result.candidates_and_deposit, - pre_election_result.voters_and_stakes, - ); + >::on_initialize(T::TermDuration::get()); } verify { assert_eq!(>::members().len() as u32, T::DesiredMembers::get().min(c)); diff --git a/frame/elections/src/lib.rs b/frame/elections-phragmen/src/lib.rs similarity index 90% rename from frame/elections/src/lib.rs rename to frame/elections-phragmen/src/lib.rs index bdf0161ba8ea0..fa63762c5e09a 100644 --- a/frame/elections/src/lib.rs +++ b/frame/elections-phragmen/src/lib.rs @@ -15,9 +15,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! # Generic Election Module. +//! # Phragmén Election Module. //! -//! An election module based on a generic election algorithm. +//! An election module based on sequential phragmen. //! //! ### Term and Round //! @@ -99,7 +99,6 @@ #![cfg_attr(not(feature = "std"), no_std)] use codec::{Decode, Encode}; -use frame_election_provider_support::NposSolver; use frame_support::{ traits::{ defensive_prelude::*, ChangeMembers, Contains, ContainsLengthBound, Currency, @@ -109,12 +108,12 @@ use frame_support::{ weights::Weight, }; use scale_info::TypeInfo; -use sp_npos_elections::{ElectionResult, ExtendedBalance, VoteWeight}; +use sp_npos_elections::{ElectionResult, ExtendedBalance}; use sp_runtime::{ traits::{Saturating, StaticLookup, Zero}, - DispatchError, RuntimeDebug, + DispatchError, Perbill, RuntimeDebug, }; -use sp_std::{cmp::Ordering, iter::IntoIterator, prelude::*}; +use sp_std::{cmp::Ordering, prelude::*}; mod benchmarking; pub mod weights; @@ -123,17 +122,7 @@ pub use weights::WeightInfo; /// All migrations. pub mod migrations; -pub(crate) const LOG_TARGET: &str = "runtime::elections"; - -// logging helper. -macro_rules! log { - ($level:tt, $patter:expr $(, $values:expr)* $(,)?) => { - log::$level!( - target: crate::LOG_TARGET, - concat!("[{:?}] 🗳️ ", $patter), >::block_number() $(, $values)* - ) - }; -} +const LOG_TARGET: &str = "runtime::elections-phragmen"; type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; @@ -184,17 +173,6 @@ pub struct SeatHolder { pub deposit: Balance, } -/// The results of running the pre-election step. -#[derive(Debug, Clone)] -struct PreElectionResults { - pub num_to_elect: usize, - pub candidate_ids: Vec, - pub candidates_and_deposit: Vec<(T::AccountId, BalanceOf)>, - pub voters_and_stakes: Vec<(T::AccountId, BalanceOf, Vec)>, - pub voters_and_votes: Vec<(T::AccountId, VoteWeight, Vec)>, - pub num_edges: u32, -} - pub use pallet::*; type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; @@ -218,7 +196,7 @@ pub mod pallet { pub trait Config: frame_system::Config { type RuntimeEvent: From> + IsType<::RuntimeEvent>; - /// Identifier for the elections pallet's lock + /// Identifier for the elections-phragmen pallet's lock #[pallet::constant] type PalletId: Get; @@ -271,7 +249,7 @@ pub mod pallet { #[pallet::constant] type TermDuration: Get; - /// The maximum number of candidates in an election. + /// The maximum number of candidates in a phragmen election. /// /// Warning: This impacts the size of the election which is run onchain. Chose wisely, and /// consider how it will impact `T::WeightInfo::election_phragmen`. @@ -280,7 +258,7 @@ pub mod pallet { #[pallet::constant] type MaxCandidates: Get; - /// The maximum number of voters to allow in an election. + /// The maximum number of voters to allow in a phragmen election. /// /// Warning: This impacts the size of the election which is run onchain. Chose wisely, and /// consider how it will impact `T::WeightInfo::election_phragmen`. @@ -289,12 +267,6 @@ pub mod pallet { #[pallet::constant] type MaxVoters: Get; - /// Something that will calculate the result of elections. - type ElectionSolver: NposSolver; - - /// Weight information for the [`Config::ElectionSolver`]. - type SolverWeightInfo: frame_election_provider_support::WeightInfo; - /// Maximum numbers of votes per voter. /// /// Warning: This impacts the size of the election which is run onchain. Chose wisely, and @@ -314,7 +286,7 @@ pub mod pallet { fn on_initialize(n: T::BlockNumber) -> Weight { let term_duration = T::TermDuration::get(); if !term_duration.is_zero() && (n % term_duration).is_zero() { - Self::do_election() + Self::do_phragmen() } else { Weight::zero() } @@ -323,26 +295,11 @@ pub mod pallet { fn integrity_test() { let block_weight = T::BlockWeights::get().max_block; // mind the order. - let pre_solve_weight = T::WeightInfo::pre_solve_election( + let election_weight = T::WeightInfo::election_phragmen( T::MaxCandidates::get(), T::MaxVoters::get(), T::MaxVotesPerVoter::get() * T::MaxVoters::get(), ); - // mind the order. - let post_solve_weight = T::WeightInfo::post_solve_election( - T::MaxCandidates::get(), - T::MaxVoters::get(), - T::MaxVotesPerVoter::get() * T::MaxVoters::get(), - ); - // mind the order. - let election_weight = T::ElectionSolver::weight::( - T::MaxCandidates::get(), - T::MaxVoters::get(), - T::MaxVotesPerVoter::get() * T::MaxVoters::get(), - ); - let election_weight = pre_solve_weight - .saturating_sub(post_solve_weight) - .saturating_add(election_weight); let to_seconds = |w: &Weight| { w.ref_time() as f32 / @@ -577,8 +534,8 @@ 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, if `rerun_election` is `true`, a new election is started, - /// else, nothing happens. + /// 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. @@ -608,7 +565,7 @@ pub mod pallet { Self::deposit_event(Event::MemberKicked { member: who }); if rerun_election { - Self::do_election(); + Self::do_phragmen(); } // no refund needed. @@ -707,8 +664,6 @@ pub mod pallet { InvalidRenouncing, /// Prediction regarding replacement after member removal is wrong. InvalidReplacement, - /// No candidates for the next term. - EmptyTerm, } /// The current elected members. @@ -787,7 +742,7 @@ pub mod pallet { Members::::mutate(|members| { match members.binary_search_by(|m| m.who.cmp(member)) { Ok(_) => { - panic!("Duplicate member in elections genesis: {}", member) + panic!("Duplicate member in elections-phragmen genesis: {}", member) }, Err(pos) => members.insert( pos, @@ -979,77 +934,11 @@ impl Pallet { debug_assert!(_remainder.is_zero()); } - /// Run an election with all required side processes and state updates, if election - /// succeeds. Else, it will emit an `ElectionError` event. The election algorithm is defined - /// by the implementor of `Self::ElectionSolver`. + /// Run the phragmen election with all required side processes and state updates, if election + /// succeeds. Else, it will emit an `ElectionError` event. /// /// Calls the appropriate [`ChangeMembers`] function variant internally. - fn do_election() -> Weight { - let PreElectionResults { - num_to_elect, - candidate_ids, - candidates_and_deposit, - voters_and_stakes, - voters_and_votes, - num_edges, - } = match Self::do_pre_solve_election() { - Ok(results) => results, - Err(err) => match err { - Error::EmptyTerm => { - Self::deposit_event(Event::EmptyTerm); - return T::DbWeight::get().reads(3) - }, - Error::TooManyVotes => { - Self::deposit_event(Event::ElectionError); - log!(error, "Failed to run election. Number of voters exceeded",); - let max_voters = ::MaxVoters::get() as usize; - return T::DbWeight::get().reads(3 + max_voters as u64) - }, - _ => { - log!(error, "Unexpected pre-election error",); - let max_voters = ::MaxVoters::get() as usize; - return T::DbWeight::get().reads(3 + max_voters as u64) - }, - }, - }; - - let num_candidates = candidates_and_deposit.len() as u32; - let num_voters = voters_and_votes.len() as u32; - let num_edges = num_edges; - - let election_winners = - T::ElectionSolver::solve(num_to_elect, candidate_ids, voters_and_votes) - .map( - |ElectionResult::< - T::AccountId, - ::Accuracy, - > { - winners, - assignments: _, - }| winners, - ) - .map_err(|e| { - log!(warn, "Failed to run election [{:?}].", e); - Self::deposit_event(Event::ElectionError); - }); - - let post_election_weight = if let Ok(winners) = election_winners { - Self::do_post_solve_election(winners, candidates_and_deposit, voters_and_stakes); - T::WeightInfo::post_solve_election(num_candidates, num_voters, num_edges) - } else { - Weight::zero() - }; - - T::ElectionSolver::weight::(num_candidates, num_voters, num_edges) - .saturating_add(T::WeightInfo::pre_solve_election( - num_candidates, - num_voters, - num_edges, - )) - .saturating_add(post_election_weight) - } - - fn do_pre_solve_election() -> Result, Error> { + fn do_phragmen() -> Weight { let desired_seats = T::DesiredMembers::get() as usize; let desired_runners_up = T::DesiredRunnersUp::get() as usize; let num_to_elect = desired_runners_up + desired_seats; @@ -1059,33 +948,44 @@ impl Pallet { candidates_and_deposit.append(&mut Self::implicit_candidates_with_deposit()); if candidates_and_deposit.len().is_zero() { - return Err(Error::EmptyTerm) + Self::deposit_event(Event::EmptyTerm); + return T::DbWeight::get().reads(3) } - // All of the new winners that come out of the election will thus have a deposit recorded. + // All of the new winners that come out of phragmen will thus have a deposit recorded. let candidate_ids = candidates_and_deposit.iter().map(|(x, _)| x).cloned().collect::>(); // helper closures to deal with balance/stake. let total_issuance = T::Currency::total_issuance(); let to_votes = |b: BalanceOf| T::CurrencyToVote::to_vote(b, total_issuance); + let to_balance = |e: ExtendedBalance| T::CurrencyToVote::to_currency(e, total_issuance); let mut num_edges: u32 = 0; let max_voters = ::MaxVoters::get() as usize; // used for prime election. let mut voters_and_stakes = Vec::new(); - - Voting::::iter().try_for_each(|(voter, Voter { stake, votes, .. })| { + match Voting::::iter().try_for_each(|(voter, Voter { stake, votes, .. })| { if voters_and_stakes.len() < max_voters { voters_and_stakes.push((voter, stake, votes)); Ok(()) } else { - Err(Error::TooManyVotes) + Err(()) } - })?; + }) { + Ok(_) => (), + Err(_) => { + log::error!( + target: LOG_TARGET, + "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 elections. + // used for phragmen. let voters_and_votes = voters_and_stakes .iter() .cloned() @@ -1095,144 +995,157 @@ impl Pallet { }) .collect::>(); - Ok(PreElectionResults { - num_to_elect, - candidate_ids, - candidates_and_deposit, - voters_and_stakes, - voters_and_votes, - num_edges, - }) - } - - fn do_post_solve_election( - winners: Vec<(T::AccountId, u128)>, - candidates_and_deposit: Vec<(T::AccountId, BalanceOf)>, - voters_and_stakes: Vec<(T::AccountId, BalanceOf, Vec)>, - ) { - let desired_seats = T::DesiredMembers::get() as usize; - let total_issuance = T::Currency::total_issuance(); - let to_balance = |e: ExtendedBalance| T::CurrencyToVote::to_currency(e, total_issuance); - - // this is already sorted by id. - let old_members_ids_sorted = - >::take().into_iter().map(|m| m.who).collect::>(); - // this one needs sorted by id. - let mut old_runners_up_ids_sorted = - >::take().into_iter().map(|r| r.who).collect::>(); - old_runners_up_ids_sorted.sort(); + 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, 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 `T::MaxVotesPerVoter` = 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)| { + ((T::MaxVotesPerVoter::get() as usize - 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, + }); + } + }); - // 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 `T::MaxVotesPerVoter` = 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)| { - ((T::MaxVotesPerVoter::get() as usize - 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()); + // 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::>(), + ); - // 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 }); - } - }); + // clean candidates. + >::kill(); - // 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 election 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, + Self::deposit_event(Event::NewTerm { new_members: new_members_sorted_by_id }); + >::mutate(|v| *v += 1); }) - .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(); - - log!(info, "New term election successful."); - Self::deposit_event(Event::NewTerm { new_members: new_members_sorted_by_id }); - >::mutate(|v| *v += 1); + .map_err(|e| { + log::error!(target: LOG_TARGET, "Failed to run election [{:?}].", e,); + Self::deposit_event(Event::ElectionError); + }); + + T::WeightInfo::election_phragmen(weight_candidates, weight_voters, weight_edges) } } @@ -1283,8 +1196,7 @@ impl ContainsLengthBound for Pallet { #[cfg(test)] mod tests { use super::*; - use crate as elections; - use frame_election_provider_support::{weights::SubstrateWeight, ApprovalVoting}; + use crate as elections_phragmen; use frame_support::{ assert_noop, assert_ok, dispatch::DispatchResultWithPostInfo, @@ -1296,7 +1208,7 @@ mod tests { use sp_runtime::{ testing::Header, traits::{BlakeTwo256, IdentityLookup}, - BuildStorage, Perbill, + BuildStorage, }; use substrate_test_utils::assert_eq_uvec; @@ -1395,13 +1307,13 @@ mod tests { } parameter_types! { - pub const ElectionsPalletId: LockIdentifier = *b"phrelect"; - pub const MaxVoters: u32 = 256; - pub const MaxCandidates: u32 = 64; + pub const ElectionsPhragmenPalletId: LockIdentifier = *b"phrelect"; + pub const PhragmenMaxVoters: u32 = 1000; + pub const PhragmenMaxCandidates: u32 = 100; } impl Config for Test { - type PalletId = ElectionsPalletId; + type PalletId = ElectionsPhragmenPalletId; type RuntimeEvent = RuntimeEvent; type Currency = Balances; type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote; @@ -1416,11 +1328,9 @@ mod tests { type LoserCandidate = (); type KickedMember = (); type WeightInfo = (); - type MaxVoters = MaxVoters; - type MaxCandidates = MaxCandidates; - type ElectionSolver = ApprovalVoting; - type SolverWeightInfo = SubstrateWeight; + type MaxVoters = PhragmenMaxVoters; type MaxVotesPerVoter = ConstU32<16>; + type MaxCandidates = PhragmenMaxCandidates; } pub type Block = sp_runtime::generic::Block; @@ -1435,7 +1345,7 @@ mod tests { { System: frame_system::{Pallet, Call, Event}, Balances: pallet_balances::{Pallet, Call, Event, Config}, - Elections: elections::{Pallet, Call, Event, Config}, + Elections: elections_phragmen::{Pallet, Call, Event, Config}, } ); @@ -1496,7 +1406,9 @@ mod tests { (6, 60 * self.balance_factor), ], }, - elections: elections::GenesisConfig:: { members: self.genesis_members }, + elections: elections_phragmen::GenesisConfig:: { + members: self.genesis_members, + }, } .build_storage() .unwrap() @@ -1554,7 +1466,7 @@ mod tests { .get(0) .cloned() .map(|lock| { - assert_eq!(lock.id, ElectionsPalletId::get()); + assert_eq!(lock.id, ElectionsPhragmenPalletId::get()); lock.amount }) .unwrap_or_default() @@ -1745,7 +1657,7 @@ mod tests { } #[test] - #[should_panic = "Duplicate member in elections genesis: 2"] + #[should_panic = "Duplicate member in elections-phragmen genesis: 2"] fn genesis_members_cannot_be_duplicate() { ExtBuilder::default() .desired_members(3) diff --git a/frame/elections/src/migrations/mod.rs b/frame/elections-phragmen/src/migrations/mod.rs similarity index 100% rename from frame/elections/src/migrations/mod.rs rename to frame/elections-phragmen/src/migrations/mod.rs diff --git a/frame/elections/src/migrations/v3.rs b/frame/elections-phragmen/src/migrations/v3.rs similarity index 100% rename from frame/elections/src/migrations/v3.rs rename to frame/elections-phragmen/src/migrations/v3.rs diff --git a/frame/elections/src/migrations/v4.rs b/frame/elections-phragmen/src/migrations/v4.rs similarity index 100% rename from frame/elections/src/migrations/v4.rs rename to frame/elections-phragmen/src/migrations/v4.rs diff --git a/frame/elections/src/migrations/v5.rs b/frame/elections-phragmen/src/migrations/v5.rs similarity index 100% rename from frame/elections/src/migrations/v5.rs rename to frame/elections-phragmen/src/migrations/v5.rs diff --git a/frame/elections-phragmen/src/weights.rs b/frame/elections-phragmen/src/weights.rs new file mode 100644 index 0000000000000..24ab3bc15fbcd --- /dev/null +++ b/frame/elections-phragmen/src/weights.rs @@ -0,0 +1,559 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS 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_elections_phragmen +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-02-03, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-b3zmxxc-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 + +// Executed Command: +// target/production/substrate +// benchmark +// pallet +// --steps=50 +// --repeat=20 +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/substrate/.git/.artifacts/bench.json +// --pallet=pallet_elections_phragmen +// --chain=dev +// --header=./HEADER-APACHE2 +// --output=./frame/elections-phragmen/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_elections_phragmen. +pub trait WeightInfo { + fn vote_equal(v: u32, ) -> Weight; + fn vote_more(v: u32, ) -> Weight; + fn vote_less(v: u32, ) -> Weight; + fn remove_voter() -> Weight; + fn submit_candidacy(c: u32, ) -> Weight; + fn renounce_candidacy_candidate(c: u32, ) -> Weight; + fn renounce_candidacy_members() -> Weight; + fn renounce_candidacy_runners_up() -> Weight; + fn remove_member_without_replacement() -> Weight; + fn remove_member_with_replacement() -> Weight; + fn clean_defunct_voters(v: u32, d: u32, ) -> Weight; + fn election_phragmen(c: u32, v: u32, e: u32, ) -> Weight; +} + +/// Weights for pallet_elections_phragmen using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + /// Storage: Elections Candidates (r:1 w:0) + /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Members (r:1 w:0) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections RunnersUp (r:1 w:0) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Voting (r:1 w:1) + /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// The range of component `v` is `[1, 16]`. + fn vote_equal(v: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `499 + v * (80 ±0)` + // Estimated: `9726 + v * (320 ±0)` + // Minimum execution time: 27_362 nanoseconds. + Weight::from_parts(28_497_963, 9726) + // Standard Error: 3_968 + .saturating_add(Weight::from_ref_time(176_840).saturating_mul(v.into())) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_proof_size(320).saturating_mul(v.into())) + } + /// Storage: Elections Candidates (r:1 w:0) + /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Members (r:1 w:0) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections RunnersUp (r:1 w:0) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Voting (r:1 w:1) + /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// The range of component `v` is `[2, 16]`. + fn vote_more(v: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `467 + v * (80 ±0)` + // Estimated: `9598 + v * (320 ±0)` + // Minimum execution time: 37_120 nanoseconds. + Weight::from_parts(38_455_302, 9598) + // Standard Error: 5_478 + .saturating_add(Weight::from_ref_time(219_678).saturating_mul(v.into())) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_proof_size(320).saturating_mul(v.into())) + } + /// Storage: Elections Candidates (r:1 w:0) + /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Members (r:1 w:0) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections RunnersUp (r:1 w:0) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Voting (r:1 w:1) + /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// The range of component `v` is `[2, 16]`. + fn vote_less(v: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `499 + v * (80 ±0)` + // Estimated: `9726 + v * (320 ±0)` + // Minimum execution time: 36_928 nanoseconds. + Weight::from_parts(38_334_669, 9726) + // Standard Error: 5_271 + .saturating_add(Weight::from_ref_time(232_355).saturating_mul(v.into())) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_proof_size(320).saturating_mul(v.into())) + } + /// Storage: Elections Voting (r:1 w:1) + /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + fn remove_voter() -> Weight { + // Proof Size summary in bytes: + // Measured: `989` + // Estimated: `7238` + // Minimum execution time: 34_338 nanoseconds. + Weight::from_parts(35_672_000, 7238) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: Elections Candidates (r:1 w:1) + /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Members (r:1 w:0) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections RunnersUp (r:1 w:0) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// The range of component `c` is `[1, 64]`. + fn submit_candidacy(c: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1697 + c * (48 ±0)` + // Estimated: `6576 + c * (144 ±0)` + // Minimum execution time: 31_864 nanoseconds. + Weight::from_parts(33_490_161, 6576) + // Standard Error: 2_643 + .saturating_add(Weight::from_ref_time(158_386).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + .saturating_add(Weight::from_proof_size(144).saturating_mul(c.into())) + } + /// Storage: Elections Candidates (r:1 w:1) + /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) + /// The range of component `c` is `[1, 64]`. + fn renounce_candidacy_candidate(c: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `349 + c * (48 ±0)` + // Estimated: `844 + c * (48 ±0)` + // Minimum execution time: 27_292 nanoseconds. + Weight::from_parts(28_364_955, 844) + // Standard Error: 1_335 + .saturating_add(Weight::from_ref_time(78_086).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + .saturating_add(Weight::from_proof_size(48).saturating_mul(c.into())) + } + /// Storage: Elections Members (r:1 w:1) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections RunnersUp (r:1 w:1) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Prime (r:1 w:1) + /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:0) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Members (r:0 w:1) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + fn renounce_candidacy_members() -> Weight { + // Proof Size summary in bytes: + // Measured: `2027` + // Estimated: `12115` + // Minimum execution time: 45_975 nanoseconds. + Weight::from_parts(47_103_000, 12115) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: Elections RunnersUp (r:1 w:1) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + fn renounce_candidacy_runners_up() -> Weight { + // Proof Size summary in bytes: + // Measured: `975` + // Estimated: `1470` + // Minimum execution time: 29_243 nanoseconds. + Weight::from_parts(30_582_000, 1470) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Benchmark Override (r:0 w:0) + /// Proof Skipped: Benchmark Override (max_values: None, max_size: None, mode: Measured) + fn remove_member_without_replacement() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_000_000_000 nanoseconds. + Weight::from_ref_time(2_000_000_000_000) + } + /// Storage: Elections Members (r:1 w:1) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Elections RunnersUp (r:1 w:1) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Prime (r:1 w:1) + /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:0) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Members (r:0 w:1) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + fn remove_member_with_replacement() -> Weight { + // Proof Size summary in bytes: + // Measured: `2027` + // Estimated: `14718` + // Minimum execution time: 52_527 nanoseconds. + Weight::from_parts(53_538_000, 14718) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) + } + /// Storage: Elections Voting (r:513 w:512) + /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Elections Members (r:1 w:0) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections RunnersUp (r:1 w:0) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Candidates (r:1 w:0) + /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Balances Locks (r:512 w:512) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: System Account (r:512 w:512) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// The range of component `v` is `[256, 512]`. + /// The range of component `d` is `[0, 256]`. + fn clean_defunct_voters(v: u32, _d: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1115 + v * (875 ±0)` + // Estimated: `8448 + v * (12352 ±0)` + // Minimum execution time: 14_934_185 nanoseconds. + Weight::from_parts(15_014_057_000, 8448) + // Standard Error: 245_588 + .saturating_add(Weight::from_ref_time(35_586_946).saturating_mul(v.into())) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(v.into()))) + .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(v.into()))) + .saturating_add(Weight::from_proof_size(12352).saturating_mul(v.into())) + } + /// Storage: Elections Candidates (r:1 w:1) + /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Members (r:1 w:1) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections RunnersUp (r:1 w:1) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Voting (r:513 w:0) + /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:0) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: System Account (r:44 w:44) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Elections ElectionRounds (r:1 w:1) + /// Proof Skipped: Elections ElectionRounds (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Members (r:0 w:1) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Prime (r:0 w:1) + /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) + /// The range of component `c` is `[1, 64]`. + /// The range of component `v` is `[1, 512]`. + /// The range of component `e` is `[512, 8192]`. + fn election_phragmen(c: u32, v: u32, e: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0 + v * (638 ±0) + e * (28 ±0)` + // Estimated: `330033 + v * (5229 ±6) + e * (89 ±0) + c * (2135 ±7)` + // Minimum execution time: 1_273_671 nanoseconds. + Weight::from_parts(1_279_716_000, 330033) + // Standard Error: 543_277 + .saturating_add(Weight::from_ref_time(20_613_753).saturating_mul(v.into())) + // Standard Error: 34_857 + .saturating_add(Weight::from_ref_time(688_354).saturating_mul(e.into())) + .saturating_add(T::DbWeight::get().reads(21_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(c.into()))) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) + .saturating_add(T::DbWeight::get().writes(6_u64)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(c.into()))) + .saturating_add(Weight::from_proof_size(5229).saturating_mul(v.into())) + .saturating_add(Weight::from_proof_size(89).saturating_mul(e.into())) + .saturating_add(Weight::from_proof_size(2135).saturating_mul(c.into())) + } +} + +// For backwards compatibility and tests +impl WeightInfo for () { + /// Storage: Elections Candidates (r:1 w:0) + /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Members (r:1 w:0) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections RunnersUp (r:1 w:0) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Voting (r:1 w:1) + /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// The range of component `v` is `[1, 16]`. + fn vote_equal(v: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `499 + v * (80 ±0)` + // Estimated: `9726 + v * (320 ±0)` + // Minimum execution time: 27_362 nanoseconds. + Weight::from_parts(28_497_963, 9726) + // Standard Error: 3_968 + .saturating_add(Weight::from_ref_time(176_840).saturating_mul(v.into())) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_proof_size(320).saturating_mul(v.into())) + } + /// Storage: Elections Candidates (r:1 w:0) + /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Members (r:1 w:0) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections RunnersUp (r:1 w:0) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Voting (r:1 w:1) + /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// The range of component `v` is `[2, 16]`. + fn vote_more(v: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `467 + v * (80 ±0)` + // Estimated: `9598 + v * (320 ±0)` + // Minimum execution time: 37_120 nanoseconds. + Weight::from_parts(38_455_302, 9598) + // Standard Error: 5_478 + .saturating_add(Weight::from_ref_time(219_678).saturating_mul(v.into())) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_proof_size(320).saturating_mul(v.into())) + } + /// Storage: Elections Candidates (r:1 w:0) + /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Members (r:1 w:0) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections RunnersUp (r:1 w:0) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Voting (r:1 w:1) + /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// The range of component `v` is `[2, 16]`. + fn vote_less(v: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `499 + v * (80 ±0)` + // Estimated: `9726 + v * (320 ±0)` + // Minimum execution time: 36_928 nanoseconds. + Weight::from_parts(38_334_669, 9726) + // Standard Error: 5_271 + .saturating_add(Weight::from_ref_time(232_355).saturating_mul(v.into())) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_proof_size(320).saturating_mul(v.into())) + } + /// Storage: Elections Voting (r:1 w:1) + /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + fn remove_voter() -> Weight { + // Proof Size summary in bytes: + // Measured: `989` + // Estimated: `7238` + // Minimum execution time: 34_338 nanoseconds. + Weight::from_parts(35_672_000, 7238) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: Elections Candidates (r:1 w:1) + /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Members (r:1 w:0) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections RunnersUp (r:1 w:0) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// The range of component `c` is `[1, 64]`. + fn submit_candidacy(c: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1697 + c * (48 ±0)` + // Estimated: `6576 + c * (144 ±0)` + // Minimum execution time: 31_864 nanoseconds. + Weight::from_parts(33_490_161, 6576) + // Standard Error: 2_643 + .saturating_add(Weight::from_ref_time(158_386).saturating_mul(c.into())) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + .saturating_add(Weight::from_proof_size(144).saturating_mul(c.into())) + } + /// Storage: Elections Candidates (r:1 w:1) + /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) + /// The range of component `c` is `[1, 64]`. + fn renounce_candidacy_candidate(c: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `349 + c * (48 ±0)` + // Estimated: `844 + c * (48 ±0)` + // Minimum execution time: 27_292 nanoseconds. + Weight::from_parts(28_364_955, 844) + // Standard Error: 1_335 + .saturating_add(Weight::from_ref_time(78_086).saturating_mul(c.into())) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + .saturating_add(Weight::from_proof_size(48).saturating_mul(c.into())) + } + /// Storage: Elections Members (r:1 w:1) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections RunnersUp (r:1 w:1) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Prime (r:1 w:1) + /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:0) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Members (r:0 w:1) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + fn renounce_candidacy_members() -> Weight { + // Proof Size summary in bytes: + // Measured: `2027` + // Estimated: `12115` + // Minimum execution time: 45_975 nanoseconds. + Weight::from_parts(47_103_000, 12115) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + } + /// Storage: Elections RunnersUp (r:1 w:1) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + fn renounce_candidacy_runners_up() -> Weight { + // Proof Size summary in bytes: + // Measured: `975` + // Estimated: `1470` + // Minimum execution time: 29_243 nanoseconds. + Weight::from_parts(30_582_000, 1470) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Benchmark Override (r:0 w:0) + /// Proof Skipped: Benchmark Override (max_values: None, max_size: None, mode: Measured) + fn remove_member_without_replacement() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_000_000_000 nanoseconds. + Weight::from_ref_time(2_000_000_000_000) + } + /// Storage: Elections Members (r:1 w:1) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Elections RunnersUp (r:1 w:1) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Prime (r:1 w:1) + /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:0) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Members (r:0 w:1) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + fn remove_member_with_replacement() -> Weight { + // Proof Size summary in bytes: + // Measured: `2027` + // Estimated: `14718` + // Minimum execution time: 52_527 nanoseconds. + Weight::from_parts(53_538_000, 14718) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(5_u64)) + } + /// Storage: Elections Voting (r:513 w:512) + /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Elections Members (r:1 w:0) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections RunnersUp (r:1 w:0) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Candidates (r:1 w:0) + /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Balances Locks (r:512 w:512) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: System Account (r:512 w:512) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// The range of component `v` is `[256, 512]`. + /// The range of component `d` is `[0, 256]`. + fn clean_defunct_voters(v: u32, _d: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1115 + v * (875 ±0)` + // Estimated: `8448 + v * (12352 ±0)` + // Minimum execution time: 14_934_185 nanoseconds. + Weight::from_parts(15_014_057_000, 8448) + // Standard Error: 245_588 + .saturating_add(Weight::from_ref_time(35_586_946).saturating_mul(v.into())) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(v.into()))) + .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(v.into()))) + .saturating_add(Weight::from_proof_size(12352).saturating_mul(v.into())) + } + /// Storage: Elections Candidates (r:1 w:1) + /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Members (r:1 w:1) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections RunnersUp (r:1 w:1) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Voting (r:513 w:0) + /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:0) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: System Account (r:44 w:44) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Elections ElectionRounds (r:1 w:1) + /// Proof Skipped: Elections ElectionRounds (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Members (r:0 w:1) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Prime (r:0 w:1) + /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) + /// The range of component `c` is `[1, 64]`. + /// The range of component `v` is `[1, 512]`. + /// The range of component `e` is `[512, 8192]`. + fn election_phragmen(c: u32, v: u32, e: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0 + v * (638 ±0) + e * (28 ±0)` + // Estimated: `330033 + v * (5229 ±6) + e * (89 ±0) + c * (2135 ±7)` + // Minimum execution time: 1_273_671 nanoseconds. + Weight::from_parts(1_279_716_000, 330033) + // Standard Error: 543_277 + .saturating_add(Weight::from_ref_time(20_613_753).saturating_mul(v.into())) + // Standard Error: 34_857 + .saturating_add(Weight::from_ref_time(688_354).saturating_mul(e.into())) + .saturating_add(RocksDbWeight::get().reads(21_u64)) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(c.into()))) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(v.into()))) + .saturating_add(RocksDbWeight::get().writes(6_u64)) + .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(c.into()))) + .saturating_add(Weight::from_proof_size(5229).saturating_mul(v.into())) + .saturating_add(Weight::from_proof_size(89).saturating_mul(e.into())) + .saturating_add(Weight::from_proof_size(2135).saturating_mul(c.into())) + } +} diff --git a/frame/elections/src/weights.rs b/frame/elections/src/weights.rs deleted file mode 100644 index 8caa93f0aa8cd..0000000000000 --- a/frame/elections/src/weights.rs +++ /dev/null @@ -1,397 +0,0 @@ -// 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_elections -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-11-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: -// /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_elections -// --chain=dev -// --header=./HEADER-APACHE2 -// --output=./frame/elections/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_elections. -pub trait WeightInfo { - fn vote_equal(v: u32, ) -> Weight; - fn vote_more(v: u32, ) -> Weight; - fn vote_less(v: u32, ) -> Weight; - fn remove_voter() -> Weight; - fn submit_candidacy(c: u32, ) -> Weight; - fn renounce_candidacy_candidate(c: u32, ) -> Weight; - fn renounce_candidacy_members() -> Weight; - fn renounce_candidacy_runners_up() -> Weight; - fn remove_member_without_replacement() -> Weight; - fn remove_member_with_replacement() -> Weight; - fn clean_defunct_voters(v: u32, d: u32, ) -> Weight; - fn pre_solve_election(c: u32, v: u32, e: u32, ) -> Weight; - fn post_solve_election(c: u32, v: u32, e: u32, ) -> Weight; -} - -/// Weights for pallet_elections using the Substrate node and recommended hardware. -pub struct SubstrateWeight(PhantomData); -impl WeightInfo for SubstrateWeight { - // Storage: Elections Candidates (r:1 w:0) - // Storage: Elections Members (r:1 w:0) - // 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 { - // Minimum execution time: 37_500 nanoseconds. - Weight::from_ref_time(38_575_649) - // Standard Error: 2_961 - .saturating_add(Weight::from_ref_time(154_225).saturating_mul(v.into())) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(2)) - } - // Storage: Elections Candidates (r:1 w:0) - // Storage: Elections Members (r:1 w:0) - // 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 { - // Minimum execution time: 48_836 nanoseconds. - Weight::from_ref_time(49_566_969) - // Standard Error: 3_258 - .saturating_add(Weight::from_ref_time(153_342).saturating_mul(v.into())) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(2)) - } - // Storage: Elections Candidates (r:1 w:0) - // Storage: Elections Members (r:1 w:0) - // 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 { - // Minimum execution time: 47_664 nanoseconds. - Weight::from_ref_time(48_768_157) - // Standard Error: 3_321 - .saturating_add(Weight::from_ref_time(215_112).saturating_mul(v.into())) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(2)) - } - // Storage: Elections Voting (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) - fn remove_voter() -> Weight { - // Minimum execution time: 47_146 nanoseconds. - Weight::from_ref_time(47_846_000) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - // 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 { - // Minimum execution time: 42_799 nanoseconds. - Weight::from_ref_time(46_920_164) - // Standard Error: 780 - .saturating_add(Weight::from_ref_time(81_672).saturating_mul(c.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(1)) - } - // Storage: Elections Candidates (r:1 w:1) - /// The range of component `c` is `[1, 1000]`. - fn renounce_candidacy_candidate(c: u32, ) -> Weight { - // Minimum execution time: 40_946 nanoseconds. - Weight::from_ref_time(53_109_738) - // Standard Error: 1_220 - .saturating_add(Weight::from_ref_time(60_643).saturating_mul(c.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - // Storage: Elections Members (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 renounce_candidacy_members() -> Weight { - // Minimum execution time: 53_454 nanoseconds. - Weight::from_ref_time(53_921_000) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(4)) - } - // Storage: Elections RunnersUp (r:1 w:1) - fn renounce_candidacy_runners_up() -> Weight { - // Minimum execution time: 41_275 nanoseconds. - Weight::from_ref_time(42_444_000) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - // 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) - } - // 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 { - // Minimum execution time: 62_040 nanoseconds. - Weight::from_ref_time(62_569_000) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(5)) - } - // 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:5000 w:5000) - // Storage: System Account (r:5000 w:5000) - /// The range of component `v` is `[5000, 10000]`. - /// The range of component `d` is `[0, 5000]`. - fn clean_defunct_voters(v: u32, _d: u32, ) -> Weight { - // Minimum execution time: 298_212_195 nanoseconds. - Weight::from_ref_time(298_678_889_000) - // Standard Error: 264_713 - .saturating_add(Weight::from_ref_time(38_222_955).saturating_mul(v.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(v.into()))) - .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(v.into()))) - } - // Storage: Elections Candidates (r:1 w:0) - // Storage: Elections Members (r:1 w:0) - // Storage: Elections RunnersUp (r:1 w:0) - // Storage: Elections Voting (r:10001 w:0) - /// 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 pre_solve_election(_c: u32, v: u32, _e: u32, ) -> Weight { - // Minimum execution time: 6_543_626 nanoseconds. - Weight::from_ref_time(6_627_885_000) - // Standard Error: 14_605 - .saturating_add(Weight::from_ref_time(7_613_226).saturating_mul(v.into())) - .saturating_add(T::DbWeight::get().reads(296)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) - } - // Storage: Elections Members (r:1 w:1) - // Storage: Elections RunnersUp (r:1 w:1) - // Storage: Council Proposals (r:1 w:0) - // Storage: Elections ElectionRounds (r:1 w:1) - // Storage: Elections Candidates (r:0 w:1) - // Storage: Council Members (r:0 w:1) - // Storage: Council Prime (r:0 w:1) - // 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 post_solve_election(c: u32, v: u32, _e: u32, ) -> Weight { - // Minimum execution time: 3_843_566 nanoseconds. - Weight::from_ref_time(3_854_020_000) - // Standard Error: 59_766 - .saturating_add(Weight::from_ref_time(9_622_797).saturating_mul(c.into())) - // Standard Error: 5_975 - .saturating_add(Weight::from_ref_time(541_471).saturating_mul(v.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(c.into()))) - .saturating_add(T::DbWeight::get().writes(6)) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(c.into()))) - } -} - -// For backwards compatibility and tests -impl WeightInfo for () { - // Storage: Elections Candidates (r:1 w:0) - // Storage: Elections Members (r:1 w:0) - // 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 { - // Minimum execution time: 37_500 nanoseconds. - Weight::from_ref_time(38_575_649) - // Standard Error: 2_961 - .saturating_add(Weight::from_ref_time(154_225).saturating_mul(v.into())) - .saturating_add(RocksDbWeight::get().reads(5)) - .saturating_add(RocksDbWeight::get().writes(2)) - } - // Storage: Elections Candidates (r:1 w:0) - // Storage: Elections Members (r:1 w:0) - // 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 { - // Minimum execution time: 48_836 nanoseconds. - Weight::from_ref_time(49_566_969) - // Standard Error: 3_258 - .saturating_add(Weight::from_ref_time(153_342).saturating_mul(v.into())) - .saturating_add(RocksDbWeight::get().reads(5)) - .saturating_add(RocksDbWeight::get().writes(2)) - } - // Storage: Elections Candidates (r:1 w:0) - // Storage: Elections Members (r:1 w:0) - // 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 { - // Minimum execution time: 47_664 nanoseconds. - Weight::from_ref_time(48_768_157) - // Standard Error: 3_321 - .saturating_add(Weight::from_ref_time(215_112).saturating_mul(v.into())) - .saturating_add(RocksDbWeight::get().reads(5)) - .saturating_add(RocksDbWeight::get().writes(2)) - } - // Storage: Elections Voting (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) - fn remove_voter() -> Weight { - // Minimum execution time: 47_146 nanoseconds. - Weight::from_ref_time(47_846_000) - .saturating_add(RocksDbWeight::get().reads(2)) - .saturating_add(RocksDbWeight::get().writes(2)) - } - // 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 { - // Minimum execution time: 42_799 nanoseconds. - Weight::from_ref_time(46_920_164) - // Standard Error: 780 - .saturating_add(Weight::from_ref_time(81_672).saturating_mul(c.into())) - .saturating_add(RocksDbWeight::get().reads(3)) - .saturating_add(RocksDbWeight::get().writes(1)) - } - // Storage: Elections Candidates (r:1 w:1) - /// The range of component `c` is `[1, 1000]`. - fn renounce_candidacy_candidate(c: u32, ) -> Weight { - // Minimum execution time: 40_946 nanoseconds. - Weight::from_ref_time(53_109_738) - // Standard Error: 1_220 - .saturating_add(Weight::from_ref_time(60_643).saturating_mul(c.into())) - .saturating_add(RocksDbWeight::get().reads(1)) - .saturating_add(RocksDbWeight::get().writes(1)) - } - // Storage: Elections Members (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 renounce_candidacy_members() -> Weight { - // Minimum execution time: 53_454 nanoseconds. - Weight::from_ref_time(53_921_000) - .saturating_add(RocksDbWeight::get().reads(4)) - .saturating_add(RocksDbWeight::get().writes(4)) - } - // Storage: Elections RunnersUp (r:1 w:1) - fn renounce_candidacy_runners_up() -> Weight { - // Minimum execution time: 41_275 nanoseconds. - Weight::from_ref_time(42_444_000) - .saturating_add(RocksDbWeight::get().reads(1)) - .saturating_add(RocksDbWeight::get().writes(1)) - } - // 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) - } - // 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 { - // Minimum execution time: 62_040 nanoseconds. - Weight::from_ref_time(62_569_000) - .saturating_add(RocksDbWeight::get().reads(5)) - .saturating_add(RocksDbWeight::get().writes(5)) - } - // 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:5000 w:5000) - // Storage: System Account (r:5000 w:5000) - /// The range of component `v` is `[5000, 10000]`. - /// The range of component `d` is `[0, 5000]`. - fn clean_defunct_voters(v: u32, _d: u32, ) -> Weight { - // Minimum execution time: 298_212_195 nanoseconds. - Weight::from_ref_time(298_678_889_000) - // Standard Error: 264_713 - .saturating_add(Weight::from_ref_time(38_222_955).saturating_mul(v.into())) - .saturating_add(RocksDbWeight::get().reads(4)) - .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(v.into()))) - .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(v.into()))) - } - // Storage: Elections Candidates (r:1 w:0) - // Storage: Elections Members (r:1 w:0) - // Storage: Elections RunnersUp (r:1 w:0) - // Storage: Elections Voting (r:10001 w:0) - /// 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 pre_solve_election(_c: u32, v: u32, _e: u32, ) -> Weight { - // Minimum execution time: 6_543_626 nanoseconds. - Weight::from_ref_time(6_627_885_000) - // Standard Error: 14_605 - .saturating_add(Weight::from_ref_time(7_613_226).saturating_mul(v.into())) - .saturating_add(RocksDbWeight::get().reads(296)) - .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(v.into()))) - } - // Storage: Elections Members (r:1 w:1) - // Storage: Elections RunnersUp (r:1 w:1) - // Storage: Council Proposals (r:1 w:0) - // Storage: Elections ElectionRounds (r:1 w:1) - // Storage: Elections Candidates (r:0 w:1) - // Storage: Council Members (r:0 w:1) - // Storage: Council Prime (r:0 w:1) - // 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 post_solve_election(c: u32, v: u32, _e: u32, ) -> Weight { - // Minimum execution time: 3_843_566 nanoseconds. - Weight::from_ref_time(3_854_020_000) - // Standard Error: 59_766 - .saturating_add(Weight::from_ref_time(9_622_797).saturating_mul(c.into())) - // Standard Error: 5_975 - .saturating_add(Weight::from_ref_time(541_471).saturating_mul(v.into())) - .saturating_add(RocksDbWeight::get().reads(4)) - .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(c.into()))) - .saturating_add(RocksDbWeight::get().writes(6)) - .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(c.into()))) - } -} diff --git a/primitives/npos-elections/src/approval_voting.rs b/primitives/npos-elections/src/approval_voting.rs deleted file mode 100644 index 2fcf17b60565d..0000000000000 --- a/primitives/npos-elections/src/approval_voting.rs +++ /dev/null @@ -1,79 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2023 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Implementation of the approval voting election method. -//! -//! This method allows voters to select many candidates and backing each of them with the same -//! vote weight. The candidates with the most backing are the election winners. - -use crate::{setup_inputs, ElectionResult, IdentifierT, PerThing128, VoteWeight}; -use sp_arithmetic::traits::Zero; -use sp_std::{cmp::Reverse, vec::Vec}; - -/// Execute an approvals voting election scheme. The return type is a list of winners. The weight -/// vector of all voters who contribute to the winners, which for this scheme is always 100% per -/// vote. -/// -/// - The vote assignment distribution for each vote is always 100%, since a voter backs a candidate -/// with its full stake, regardless of how many candidates are backed by the same stake. However, -/// the caller may normalize votes on site if required. -/// - Returning winners are sorted based on desirability. Voters are unsorted. -/// - The returning winners are zipped with their final backing stake. Yet, to get the exact final -/// weight distribution from the winner's point of view, one needs to build a support map. See -/// [`crate::SupportMap`] for more info. Note that this backing stake is computed in -/// ExtendedBalance and may be slightly different that what will be computed from the support map, -/// due to accuracy loss. -/// -/// 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`. -pub fn approval_voting( - to_elect: usize, - candidates: Vec, - voters: Vec<(AccountId, VoteWeight, impl IntoIterator)>, -) -> Result, crate::Error> { - let to_elect = to_elect.min(candidates.len()); - - let (mut candidates, mut voters) = setup_inputs(candidates, voters); - - candidates.sort_by_key(|c| Reverse(c.borrow().approval_stake)); - - let winners = candidates - .into_iter() - .take(to_elect) - .map(|w| { - w.borrow_mut().elected = true; - w - }) - .map(|w_ptr| (w_ptr.borrow().who.clone(), w_ptr.borrow().approval_stake)) - .collect(); - - for voter in &mut voters { - for edge in &mut voter.edges { - if edge.candidate.borrow().elected { - edge.weight = voter.budget - } else { - edge.weight = Zero::zero() - } - } - } - - let assignments = voters.into_iter().filter_map(|v| v.into_assignment()).collect::>(); - - Ok(ElectionResult { winners, assignments }) -} diff --git a/primitives/npos-elections/src/lib.rs b/primitives/npos-elections/src/lib.rs index a1a38b9b0df12..716c4b283c68e 100644 --- a/primitives/npos-elections/src/lib.rs +++ b/primitives/npos-elections/src/lib.rs @@ -25,8 +25,6 @@ //! - [`balance`](balancing::balance): Implements the star balancing algorithm. This iterative //! process can push a solution toward being more "balanced", which in turn can increase its //! score. -//! - [`approval_voting`](approval_voting::approval_voting): Implements an approval voting electoral -//! system where voters can back multiple candidates with the same stake. //! //! ### Terminology //! @@ -92,7 +90,6 @@ mod mock; #[cfg(test)] mod tests; -pub mod approval_voting; mod assignments; pub mod balancing; pub mod helpers; @@ -103,7 +100,6 @@ pub mod pjr; pub mod reduce; pub mod traits; -pub use approval_voting::*; pub use assignments::{Assignment, StakedAssignment}; pub use balancing::*; pub use helpers::*; diff --git a/primitives/npos-elections/src/phragmen.rs b/primitives/npos-elections/src/phragmen.rs index b7204ce1c34d8..c3578065f364c 100644 --- a/primitives/npos-elections/src/phragmen.rs +++ b/primitives/npos-elections/src/phragmen.rs @@ -57,7 +57,7 @@ const DEN: ExtendedBalance = ExtendedBalance::max_value(); /// - The returning weight distribution is _normalized_, meaning that it is guaranteed that the sum /// of the ratios in each voter's distribution sums up to exactly `P::one()`. /// -/// This can only fail if the normalization fails. This can happen if for any of the resulting +/// This can only fail of 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`. diff --git a/primitives/npos-elections/src/tests.rs b/primitives/npos-elections/src/tests.rs index 5fea4c2506406..72ae9a0222be1 100644 --- a/primitives/npos-elections/src/tests.rs +++ b/primitives/npos-elections/src/tests.rs @@ -18,57 +18,12 @@ //! Tests for npos-elections. use crate::{ - approval_voting::*, balancing, helpers::*, mock::*, seq_phragmen, seq_phragmen_core, - setup_inputs, to_support_map, Assignment, BalancingConfig, ElectionResult, ExtendedBalance, - StakedAssignment, Support, Voter, + balancing, helpers::*, mock::*, seq_phragmen, seq_phragmen_core, setup_inputs, to_support_map, + Assignment, BalancingConfig, ElectionResult, ExtendedBalance, StakedAssignment, Support, Voter, }; use sp_arithmetic::{PerU16, Perbill, Percent, Permill}; use substrate_test_utils::assert_eq_uvec; -#[test] -fn approval_voting_works() { - let candidates = vec![1, 2, 3, 4]; - let voters = vec![(10, vec![1, 2]), (20, vec![1, 2]), (30, vec![1, 2, 3]), (40, vec![4])]; - let stake_of = create_stake_of(&[(10, 10), (20, 20), (30, 30), (40, 40)]); - - let voters = voters - .iter() - .map(|(ref v, ref vs)| (*v, stake_of(v), vs.clone())) - .collect::>(); - - let ElectionResult::<_, Perbill> { winners, assignments } = - approval_voting(3, candidates, voters).unwrap(); - - assert_eq_uvec!(winners, vec![(1, 60), (2, 60), (4, 40)]); - assert_eq_uvec!( - assignments, - vec![ - Assignment { - who: 10u64, - distribution: vec![ - (1, Perbill::from_percent(100)), - (2, Perbill::from_percent(100)) - ] - }, - Assignment { - who: 20u64, - distribution: vec![ - (1, Perbill::from_percent(100)), - (2, Perbill::from_percent(100)) - ] - }, - Assignment { - who: 30u64, - distribution: vec![ - (1, Perbill::from_percent(100)), - (2, Perbill::from_percent(100)) - ] - }, - Assignment { who: 40u64, distribution: vec![(4, Perbill::from_percent(100))] }, - ] - ); -} - #[test] fn float_phragmen_poc_works() { let candidates = vec![1, 2, 3]; diff --git a/scripts/run_all_benchmarks.sh b/scripts/run_all_benchmarks.sh index 818a5df7f6d95..b632cb5c12f04 100755 --- a/scripts/run_all_benchmarks.sh +++ b/scripts/run_all_benchmarks.sh @@ -67,6 +67,8 @@ 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" diff --git a/utils/frame/remote-externalities/Cargo.toml b/utils/frame/remote-externalities/Cargo.toml index e55b64efbdc75..8611ae4980f12 100644 --- a/utils/frame/remote-externalities/Cargo.toml +++ b/utils/frame/remote-externalities/Cargo.toml @@ -25,7 +25,7 @@ futures = "0.3" [dev-dependencies] frame-support = { version = "4.0.0-dev", path = "../../../frame/support" } -pallet-elections = { version = "5.0.0-dev", path = "../../../frame/elections" } +pallet-elections-phragmen = { version = "5.0.0-dev", path = "../../../frame/elections-phragmen" } tracing-subscriber = { version = "0.3.16", features = ["env-filter"] } [features] From 1837f423b494254e1d27834b1c9da34b2c0c2375 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Fri, 24 Feb 2023 12:43:01 +0100 Subject: [PATCH 435/715] wasm-executor: Support growing the memory (#12520) * As always, start with something :P * Add support for max_heap_pages * Add support for wasmtime * Make it compile * Fix compilation * Copy wrongly merged code * Fix compilation * Some fixes * Fix * Get stuff working * More work * More fixes * ... * More * FIXEs * Switch wasmi to use `RuntimeBlob` like wasmtime * Removed unused stuff * Cleanup * More cleanups * Introduce `CallContext` * Fixes * More fixes * Add builder for creating the `WasmExecutor` * Adds some docs * FMT * First round of feedback. * Review feedback round 2 * More fixes * Fix try-runtime * Update client/executor/wasmtime/src/instance_wrapper.rs Co-authored-by: Koute * Update client/executor/common/src/wasm_runtime.rs Co-authored-by: Koute * Update client/executor/common/src/runtime_blob/runtime_blob.rs Co-authored-by: Koute * Update client/executor/common/src/wasm_runtime.rs Co-authored-by: Koute * Update client/allocator/src/freeing_bump.rs Co-authored-by: Koute * Update client/allocator/src/freeing_bump.rs Co-authored-by: Koute * Feedback round 3 * FMT * Review comments --------- Co-authored-by: Koute --- Cargo.lock | 14 + bin/node/executor/benches/bench.rs | 30 +- bin/node/executor/tests/common.rs | 4 +- client/allocator/src/error.rs | 2 +- client/allocator/src/freeing_bump.rs | 403 +++++++++++------- client/allocator/src/lib.rs | 32 ++ client/api/src/call_executor.rs | 2 + client/executor/Cargo.toml | 3 +- client/executor/benches/bench.rs | 9 +- client/executor/common/Cargo.toml | 2 +- .../common/src/runtime_blob/runtime_blob.rs | 26 +- client/executor/common/src/util.rs | 6 +- client/executor/common/src/wasm_runtime.rs | 26 ++ client/executor/runtime-test/src/lib.rs | 9 + .../executor/src/integration_tests/linux.rs | 49 ++- client/executor/src/integration_tests/mod.rs | 39 +- client/executor/src/native_executor.rs | 250 +++++++++-- client/executor/src/wasm_runtime.rs | 30 +- client/executor/wasmi/Cargo.toml | 2 +- client/executor/wasmi/src/lib.rs | 205 +++++---- client/executor/wasmtime/Cargo.toml | 2 +- client/executor/wasmtime/src/host.rs | 51 ++- .../executor/wasmtime/src/instance_wrapper.rs | 106 +++-- client/executor/wasmtime/src/runtime.rs | 84 +--- client/executor/wasmtime/src/tests.rs | 260 +++++------ client/finality-grandpa/src/lib.rs | 3 +- .../rpc-spec-v2/src/chain_head/chain_head.rs | 3 +- client/rpc/src/state/state_full.rs | 2 + client/service/src/client/call_executor.rs | 16 +- client/service/test/src/client/mod.rs | 8 +- primitives/core/src/traits.rs | 19 +- primitives/state-machine/src/lib.rs | 14 +- primitives/wasm-interface/Cargo.toml | 2 +- test-utils/runtime/src/lib.rs | 9 +- test-utils/runtime/src/system.rs | 20 +- .../benchmarking-cli/src/pallet/command.rs | 13 +- utils/frame/try-runtime/cli/src/lib.rs | 4 +- 37 files changed, 1092 insertions(+), 667 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7cfde057041e3..299f639219437 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7653,6 +7653,18 @@ version = "0.6.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" +[[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" @@ -8404,6 +8416,7 @@ dependencies = [ "sp-runtime", "sp-runtime-interface", "sp-state-machine", + "sp-tracing", "sp-trie", "sp-version", "sp-wasm-interface", @@ -11956,6 +11969,7 @@ dependencies = [ "memory_units", "num-rational", "num-traits", + "region", ] [[package]] diff --git a/bin/node/executor/benches/bench.rs b/bin/node/executor/benches/bench.rs index 4154d1cffcf11..19e7b158a8c81 100644 --- a/bin/node/executor/benches/bench.rs +++ b/bin/node/executor/benches/bench.rs @@ -31,7 +31,7 @@ use sc_executor::{ }; use sp_core::{ storage::well_known_keys, - traits::{CodeExecutor, RuntimeCode}, + traits::{CallContext, CodeExecutor, RuntimeCode}, }; use sp_runtime::traits::BlakeTwo256; use sp_state_machine::TestExternalities as CoreTestExternalities; @@ -112,20 +112,41 @@ fn construct_block( // execute the block to get the real header. executor - .call(ext, &runtime_code, "Core_initialize_block", &header.encode(), true) + .call( + ext, + &runtime_code, + "Core_initialize_block", + &header.encode(), + true, + CallContext::Offchain, + ) .0 .unwrap(); for i in extrinsics.iter() { executor - .call(ext, &runtime_code, "BlockBuilder_apply_extrinsic", &i.encode(), true) + .call( + ext, + &runtime_code, + "BlockBuilder_apply_extrinsic", + &i.encode(), + true, + CallContext::Offchain, + ) .0 .unwrap(); } let header = Header::decode( &mut &executor - .call(ext, &runtime_code, "BlockBuilder_finalize_block", &[0u8; 0], true) + .call( + ext, + &runtime_code, + "BlockBuilder_finalize_block", + &[0u8; 0], + true, + CallContext::Offchain, + ) .0 .unwrap()[..], ) @@ -201,6 +222,7 @@ fn bench_execute_block(c: &mut Criterion) { "Core_execute_block", &block.0, use_native, + CallContext::Offchain, ) .0 .unwrap(); diff --git a/bin/node/executor/tests/common.rs b/bin/node/executor/tests/common.rs index b428e32ea8b8d..036528f8dae1f 100644 --- a/bin/node/executor/tests/common.rs +++ b/bin/node/executor/tests/common.rs @@ -26,7 +26,7 @@ use sp_consensus_babe::{ use sp_core::{ crypto::KeyTypeId, sr25519::Signature, - traits::{CodeExecutor, RuntimeCode}, + traits::{CallContext, CodeExecutor, RuntimeCode}, }; use sp_runtime::{ traits::{BlakeTwo256, Header as HeaderT}, @@ -114,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) + executor().call(&mut t, &runtime_code, method, data, use_native, CallContext::Onchain) } pub fn new_test_ext(code: &[u8]) -> TestExternalities { diff --git a/client/allocator/src/error.rs b/client/allocator/src/error.rs index a3d91a3e2bacc..08d84317b6503 100644 --- a/client/allocator/src/error.rs +++ b/client/allocator/src/error.rs @@ -16,7 +16,7 @@ // limitations under the License. /// The error type used by the allocators. -#[derive(thiserror::Error, Debug)] +#[derive(thiserror::Error, Debug, PartialEq)] pub enum Error { /// Someone tried to allocate more memory than the allowed maximum per allocation. #[error("Requested allocation size is too large")] diff --git a/client/allocator/src/freeing_bump.rs b/client/allocator/src/freeing_bump.rs index fdd63bd66aba8..c3cb827afec08 100644 --- a/client/allocator/src/freeing_bump.rs +++ b/client/allocator/src/freeing_bump.rs @@ -67,10 +67,11 @@ //! wasted. This is more pronounced (in terms of absolute heap amounts) with larger allocation //! sizes. -use crate::Error; +use crate::{Error, Memory, MAX_WASM_PAGES, PAGE_SIZE}; pub use sp_core::MAX_POSSIBLE_ALLOCATION; use sp_wasm_interface::{Pointer, WordSize}; use std::{ + cmp::{max, min}, mem, ops::{Index, IndexMut, Range}, }; @@ -237,7 +238,7 @@ impl Header { /// /// Returns an error if the `header_ptr` is out of bounds of the linear memory or if the read /// header is corrupted (e.g. the order is incorrect). - fn read_from(memory: &M, header_ptr: u32) -> Result { + fn read_from(memory: &impl Memory, header_ptr: u32) -> Result { let raw_header = memory.read_le_u64(header_ptr)?; // Check if the header represents an occupied or free allocation and extract the header data @@ -255,7 +256,7 @@ impl Header { /// Write out this header to memory. /// /// Returns an error if the `header_ptr` is out of bounds of the linear memory. - fn write_into(&self, memory: &mut M, header_ptr: u32) -> Result<(), Error> { + fn write_into(&self, memory: &mut impl Memory, header_ptr: u32) -> Result<(), Error> { let (header_data, occupied_mask) = match *self { Self::Occupied(order) => (order.into_raw(), 0x00000001_00000000), Self::Free(link) => (link.into_raw(), 0x00000000_00000000), @@ -343,6 +344,15 @@ pub struct AllocationStats { pub address_space_used: u32, } +/// Convert the given `size` in bytes into the number of pages. +/// +/// The returned number of pages is ensured to be big enough to hold memory with the given `size`. +/// +/// Returns `None` if the number of pages to not fit into `u32`. +fn pages_from_size(size: u64) -> Option { + u32::try_from((size + PAGE_SIZE as u64 - 1) / PAGE_SIZE as u64).ok() +} + /// An implementation of freeing bump allocator. /// /// Refer to the module-level documentation for further details. @@ -351,7 +361,7 @@ pub struct FreeingBumpHeapAllocator { bumper: u32, free_lists: FreeLists, poisoned: bool, - last_observed_memory_size: u32, + last_observed_memory_size: u64, stats: AllocationStats, } @@ -395,9 +405,9 @@ impl FreeingBumpHeapAllocator { /// /// - `mem` - a slice representing the linear memory on which this allocator operates. /// - `size` - size in bytes of the allocation request - pub fn allocate( + pub fn allocate( &mut self, - mem: &mut M, + mem: &mut impl Memory, size: WordSize, ) -> Result, Error> { if self.poisoned { @@ -412,7 +422,7 @@ impl FreeingBumpHeapAllocator { let header_ptr: u32 = match self.free_lists[order] { Link::Ptr(header_ptr) => { assert!( - header_ptr + order.size() + HEADER_SIZE <= mem.size(), + u64::from(header_ptr + order.size() + HEADER_SIZE) <= mem.size(), "Pointer is looked up in list of free entries, into which only valid values are inserted; qed" ); @@ -427,7 +437,7 @@ impl FreeingBumpHeapAllocator { }, Link::Nil => { // Corresponding free list is empty. Allocate a new item. - Self::bump(&mut self.bumper, order.size() + HEADER_SIZE, mem.size())? + Self::bump(&mut self.bumper, order.size() + HEADER_SIZE, mem)? }, }; @@ -437,7 +447,7 @@ impl FreeingBumpHeapAllocator { self.stats.bytes_allocated += 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); + max(self.stats.bytes_allocated_peak, self.stats.bytes_allocated); self.stats.address_space_used = self.bumper - self.original_heap_base; log::trace!(target: LOG_TARGET, "after allocation: {:?}", self.stats); @@ -457,11 +467,7 @@ impl FreeingBumpHeapAllocator { /// /// - `mem` - a slice representing the linear memory on which this allocator operates. /// - `ptr` - pointer to the allocated chunk - pub fn deallocate( - &mut self, - mem: &mut M, - ptr: Pointer, - ) -> Result<(), Error> { + pub fn deallocate(&mut self, mem: &mut impl Memory, ptr: Pointer) -> Result<(), Error> { if self.poisoned { return Err(error("the allocator has been poisoned")) } @@ -503,15 +509,52 @@ impl FreeingBumpHeapAllocator { /// /// Returns the `bumper` from before the increase. Returns an `Error::AllocatorOutOfSpace` if /// the operation would exhaust the heap. - fn bump(bumper: &mut u32, size: u32, heap_end: u32) -> Result { - if *bumper + size > heap_end { - log::error!( - target: LOG_TARGET, - "running out of space with current bumper {}, mem size {}", - bumper, - heap_end + fn bump(bumper: &mut u32, size: u32, memory: &mut impl Memory) -> Result { + let required_size = u64::from(*bumper) + u64::from(size); + + if required_size > memory.size() { + let required_pages = + pages_from_size(required_size).ok_or_else(|| Error::AllocatorOutOfSpace)?; + + let current_pages = memory.pages(); + let max_pages = memory.max_pages().unwrap_or(MAX_WASM_PAGES); + debug_assert!( + current_pages < required_pages, + "current pages {current_pages} < required pages {required_pages}" ); - return Err(Error::AllocatorOutOfSpace) + + if current_pages >= max_pages { + log::debug!( + target: LOG_TARGET, + "Wasm pages ({current_pages}) are already at the maximum.", + ); + + return Err(Error::AllocatorOutOfSpace) + } else if required_pages > max_pages { + log::debug!( + target: LOG_TARGET, + "Failed to grow memory from {current_pages} pages to at least {required_pages}\ + pages due to the maximum limit of {max_pages} pages", + ); + return Err(Error::AllocatorOutOfSpace) + } + + // Ideally we want to double our current number of pages, + // as long as it's less than the absolute maximum we can have. + let next_pages = min(current_pages * 2, max_pages); + // ...but if even more pages are required then try to allocate that many. + let next_pages = max(next_pages, required_pages); + + if memory.grow(next_pages - current_pages).is_err() { + log::error!( + target: LOG_TARGET, + "Failed to grow memory from {current_pages} pages to {next_pages} pages", + ); + + return Err(Error::AllocatorOutOfSpace) + } + + debug_assert_eq!(memory.pages(), next_pages, "Number of pages should have increased!"); } let res = *bumper; @@ -519,9 +562,9 @@ impl FreeingBumpHeapAllocator { Ok(res) } - fn observe_memory_size( - last_observed_memory_size: &mut u32, - mem: &mut M, + fn observe_memory_size( + last_observed_memory_size: &mut u64, + mem: &mut impl Memory, ) -> Result<(), Error> { if mem.size() < *last_observed_memory_size { return Err(Error::MemoryShrinked) @@ -538,38 +581,42 @@ impl FreeingBumpHeapAllocator { /// accessible up to the reported size. /// /// The linear memory can grow in size with the wasm page granularity (64KiB), but it cannot shrink. -pub trait Memory { +trait MemoryExt: Memory { /// Read a u64 from the heap in LE form. Returns an error if any of the bytes read are out of /// bounds. - fn read_le_u64(&self, ptr: u32) -> Result; - /// Write a u64 to the heap in LE form. Returns an error if any of the bytes written are out of - /// bounds. - fn write_le_u64(&mut self, ptr: u32, val: u64) -> Result<(), Error>; - /// Returns the full size of the memory in bytes. - fn size(&self) -> u32; -} - -impl Memory for [u8] { fn read_le_u64(&self, ptr: u32) -> Result { - let range = - heap_range(ptr, 8, self.len()).ok_or_else(|| error("read out of heap bounds"))?; - let bytes = self[range] - .try_into() - .expect("[u8] slice of length 8 must be convertible to [u8; 8]"); - Ok(u64::from_le_bytes(bytes)) + self.with_access(|memory| { + let range = + heap_range(ptr, 8, memory.len()).ok_or_else(|| error("read out of heap bounds"))?; + let bytes = memory[range] + .try_into() + .expect("[u8] slice of length 8 must be convertible to [u8; 8]"); + Ok(u64::from_le_bytes(bytes)) + }) } + + /// Write a u64 to the heap in LE form. Returns an error if any of the bytes written are out of + /// bounds. fn write_le_u64(&mut self, ptr: u32, val: u64) -> Result<(), Error> { - let range = - heap_range(ptr, 8, self.len()).ok_or_else(|| error("write out of heap bounds"))?; - let bytes = val.to_le_bytes(); - self[range].copy_from_slice(&bytes[..]); - Ok(()) + self.with_access_mut(|memory| { + let range = heap_range(ptr, 8, memory.len()) + .ok_or_else(|| error("write out of heap bounds"))?; + let bytes = val.to_le_bytes(); + memory[range].copy_from_slice(&bytes[..]); + Ok(()) + }) } - fn size(&self) -> u32 { - u32::try_from(self.len()).expect("size of Wasm linear memory is <2^32; qed") + + /// Returns the full size of the memory in bytes. + fn size(&self) -> u64 { + debug_assert!(self.pages() <= MAX_WASM_PAGES); + + self.pages() as u64 * PAGE_SIZE as u64 } } +impl MemoryExt for T {} + fn heap_range(offset: u32, length: u32, heap_len: usize) -> Option> { let start = offset as usize; let end = offset.checked_add(length)? as usize; @@ -601,21 +648,72 @@ impl<'a> Drop for PoisonBomb<'a> { mod tests { use super::*; - const PAGE_SIZE: u32 = 65536; - /// Makes a pointer out of the given address. fn to_pointer(address: u32) -> Pointer { Pointer::new(address) } + #[derive(Debug)] + struct MemoryInstance { + data: Vec, + max_wasm_pages: u32, + } + + impl MemoryInstance { + fn with_pages(pages: u32) -> Self { + Self { data: vec![0; (pages * PAGE_SIZE) as usize], max_wasm_pages: MAX_WASM_PAGES } + } + + fn set_max_wasm_pages(&mut self, max_pages: u32) { + self.max_wasm_pages = max_pages; + } + } + + impl Memory for MemoryInstance { + fn with_access(&self, run: impl FnOnce(&[u8]) -> R) -> R { + run(&self.data) + } + + fn with_access_mut(&mut self, run: impl FnOnce(&mut [u8]) -> R) -> R { + run(&mut self.data) + } + + fn pages(&self) -> u32 { + pages_from_size(self.data.len() as u64).unwrap() + } + + fn max_pages(&self) -> Option { + Some(self.max_wasm_pages) + } + + fn grow(&mut self, pages: u32) -> Result<(), ()> { + if self.pages() + pages > self.max_wasm_pages { + Err(()) + } else { + self.data.resize(((self.pages() + pages) * PAGE_SIZE) as usize, 0); + Ok(()) + } + } + } + + #[test] + fn test_pages_from_size() { + assert_eq!(pages_from_size(0).unwrap(), 0); + assert_eq!(pages_from_size(1).unwrap(), 1); + assert_eq!(pages_from_size(65536).unwrap(), 1); + assert_eq!(pages_from_size(65536 + 1).unwrap(), 2); + assert_eq!(pages_from_size(2 * 65536).unwrap(), 2); + assert_eq!(pages_from_size(2 * 65536 + 1).unwrap(), 3); + } + #[test] fn should_allocate_properly() { // given - let mut mem = [0u8; PAGE_SIZE as usize]; + let mut mem = MemoryInstance::with_pages(1); let mut heap = FreeingBumpHeapAllocator::new(0); // when - let ptr = heap.allocate(&mut mem[..], 1).unwrap(); + let ptr = heap.allocate(&mut mem, 1).unwrap(); // then // returned pointer must start right after `HEADER_SIZE` @@ -625,11 +723,11 @@ mod tests { #[test] fn should_always_align_pointers_to_multiples_of_8() { // given - let mut mem = [0u8; PAGE_SIZE as usize]; + let mut mem = MemoryInstance::with_pages(1); let mut heap = FreeingBumpHeapAllocator::new(13); // when - let ptr = heap.allocate(&mut mem[..], 1).unwrap(); + let ptr = heap.allocate(&mut mem, 1).unwrap(); // then // the pointer must start at the next multiple of 8 from 13 @@ -640,13 +738,13 @@ mod tests { #[test] fn should_increment_pointers_properly() { // given - let mut mem = [0u8; PAGE_SIZE as usize]; + let mut mem = MemoryInstance::with_pages(1); let mut heap = FreeingBumpHeapAllocator::new(0); // when - let ptr1 = heap.allocate(&mut mem[..], 1).unwrap(); - let ptr2 = heap.allocate(&mut mem[..], 9).unwrap(); - let ptr3 = heap.allocate(&mut mem[..], 1).unwrap(); + let ptr1 = heap.allocate(&mut mem, 1).unwrap(); + let ptr2 = heap.allocate(&mut mem, 9).unwrap(); + let ptr3 = heap.allocate(&mut mem, 1).unwrap(); // then // a prefix of 8 bytes is prepended to each pointer @@ -663,18 +761,18 @@ mod tests { #[test] fn should_free_properly() { // given - let mut mem = [0u8; PAGE_SIZE as usize]; + let mut mem = MemoryInstance::with_pages(1); let mut heap = FreeingBumpHeapAllocator::new(0); - let ptr1 = heap.allocate(&mut mem[..], 1).unwrap(); + let ptr1 = heap.allocate(&mut mem, 1).unwrap(); // the prefix of 8 bytes is prepended to the pointer assert_eq!(ptr1, to_pointer(HEADER_SIZE)); - let ptr2 = heap.allocate(&mut mem[..], 1).unwrap(); + let ptr2 = heap.allocate(&mut mem, 1).unwrap(); // the prefix of 8 bytes + the content of ptr 1 is prepended to the pointer assert_eq!(ptr2, to_pointer(24)); // when - heap.deallocate(&mut mem[..], ptr2).unwrap(); + heap.deallocate(&mut mem, ptr2).unwrap(); // then // then the heads table should contain a pointer to the @@ -685,23 +783,23 @@ mod tests { #[test] fn should_deallocate_and_reallocate_properly() { // given - let mut mem = [0u8; PAGE_SIZE as usize]; + let mut mem = MemoryInstance::with_pages(1); let padded_offset = 16; let mut heap = FreeingBumpHeapAllocator::new(13); - let ptr1 = heap.allocate(&mut mem[..], 1).unwrap(); + let ptr1 = heap.allocate(&mut mem, 1).unwrap(); // the prefix of 8 bytes is prepended to the pointer assert_eq!(ptr1, to_pointer(padded_offset + HEADER_SIZE)); - let ptr2 = heap.allocate(&mut mem[..], 9).unwrap(); + let ptr2 = heap.allocate(&mut mem, 9).unwrap(); // the padded_offset + the previously allocated ptr (8 bytes prefix + // 8 bytes content) + the prefix of 8 bytes which is prepended to the // current pointer assert_eq!(ptr2, to_pointer(padded_offset + 16 + HEADER_SIZE)); // when - heap.deallocate(&mut mem[..], ptr2).unwrap(); - let ptr3 = heap.allocate(&mut mem[..], 9).unwrap(); + heap.deallocate(&mut mem, ptr2).unwrap(); + let ptr3 = heap.allocate(&mut mem, 9).unwrap(); // then // should have re-allocated @@ -712,22 +810,22 @@ mod tests { #[test] fn should_build_linked_list_of_free_areas_properly() { // given - let mut mem = [0u8; PAGE_SIZE as usize]; + let mut mem = MemoryInstance::with_pages(1); let mut heap = FreeingBumpHeapAllocator::new(0); - let ptr1 = heap.allocate(&mut mem[..], 8).unwrap(); - let ptr2 = heap.allocate(&mut mem[..], 8).unwrap(); - let ptr3 = heap.allocate(&mut mem[..], 8).unwrap(); + let ptr1 = heap.allocate(&mut mem, 8).unwrap(); + let ptr2 = heap.allocate(&mut mem, 8).unwrap(); + let ptr3 = heap.allocate(&mut mem, 8).unwrap(); // when - heap.deallocate(&mut mem[..], ptr1).unwrap(); - heap.deallocate(&mut mem[..], ptr2).unwrap(); - heap.deallocate(&mut mem[..], ptr3).unwrap(); + heap.deallocate(&mut mem, ptr1).unwrap(); + heap.deallocate(&mut mem, ptr2).unwrap(); + heap.deallocate(&mut mem, ptr3).unwrap(); // then assert_eq!(heap.free_lists.heads[0], Link::Ptr(u32::from(ptr3) - HEADER_SIZE)); - let ptr4 = heap.allocate(&mut mem[..], 8).unwrap(); + let ptr4 = heap.allocate(&mut mem, 8).unwrap(); assert_eq!(ptr4, ptr3); assert_eq!(heap.free_lists.heads[0], Link::Ptr(u32::from(ptr2) - HEADER_SIZE)); @@ -736,29 +834,28 @@ mod tests { #[test] fn should_not_allocate_if_too_large() { // given - let mut mem = [0u8; PAGE_SIZE as usize]; + let mut mem = MemoryInstance::with_pages(1); + mem.set_max_wasm_pages(1); let mut heap = FreeingBumpHeapAllocator::new(13); // when - let ptr = heap.allocate(&mut mem[..], PAGE_SIZE - 13); + let ptr = heap.allocate(&mut mem, PAGE_SIZE - 13); // then - match ptr.unwrap_err() { - Error::AllocatorOutOfSpace => {}, - e => panic!("Expected allocator out of space error, got: {:?}", e), - } + assert_eq!(Error::AllocatorOutOfSpace, ptr.unwrap_err()); } #[test] fn should_not_allocate_if_full() { // given - let mut mem = [0u8; PAGE_SIZE as usize]; + let mut mem = MemoryInstance::with_pages(1); + mem.set_max_wasm_pages(1); let mut heap = FreeingBumpHeapAllocator::new(0); - let ptr1 = heap.allocate(&mut mem[..], (PAGE_SIZE / 2) - HEADER_SIZE).unwrap(); + let ptr1 = heap.allocate(&mut mem, (PAGE_SIZE / 2) - HEADER_SIZE).unwrap(); assert_eq!(ptr1, to_pointer(HEADER_SIZE)); // when - let ptr2 = heap.allocate(&mut mem[..], PAGE_SIZE / 2); + let ptr2 = heap.allocate(&mut mem, PAGE_SIZE / 2); // then // there is no room for another half page incl. its 8 byte prefix @@ -771,11 +868,11 @@ mod tests { #[test] fn should_allocate_max_possible_allocation_size() { // given - let mut mem = vec![0u8; (MAX_POSSIBLE_ALLOCATION + PAGE_SIZE) as usize]; + let mut mem = MemoryInstance::with_pages(1); let mut heap = FreeingBumpHeapAllocator::new(0); // when - let ptr = heap.allocate(&mut mem[..], MAX_POSSIBLE_ALLOCATION).unwrap(); + let ptr = heap.allocate(&mut mem, MAX_POSSIBLE_ALLOCATION).unwrap(); // then assert_eq!(ptr, to_pointer(HEADER_SIZE)); @@ -784,60 +881,62 @@ mod tests { #[test] fn should_not_allocate_if_requested_size_too_large() { // given - let mut mem = [0u8; PAGE_SIZE as usize]; + let mut mem = MemoryInstance::with_pages(1); let mut heap = FreeingBumpHeapAllocator::new(0); // when - let ptr = heap.allocate(&mut mem[..], MAX_POSSIBLE_ALLOCATION + 1); + let ptr = heap.allocate(&mut mem, MAX_POSSIBLE_ALLOCATION + 1); // then - match ptr.unwrap_err() { - Error::RequestedAllocationTooLarge => {}, - e => panic!("Expected allocation size too large error, got: {:?}", e), - } + assert_eq!(Error::RequestedAllocationTooLarge, ptr.unwrap_err()); } #[test] fn should_return_error_when_bumper_greater_than_heap_size() { // given - let mut mem = [0u8; 64]; + let mut mem = MemoryInstance::with_pages(1); + mem.set_max_wasm_pages(1); let mut heap = FreeingBumpHeapAllocator::new(0); - 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.stats.bytes_allocated, 0); - assert_eq!(heap.bumper, 40); + let mut ptrs = Vec::new(); + for _ in 0..(PAGE_SIZE as usize / 40) { + ptrs.push(heap.allocate(&mut mem, 32).expect("Allocate 32 byte")); + } + + assert_eq!(heap.stats.bytes_allocated, PAGE_SIZE - 16); + assert_eq!(heap.bumper, PAGE_SIZE - 16); + + ptrs.into_iter() + .for_each(|ptr| heap.deallocate(&mut mem, ptr).expect("Deallocate 32 byte")); - 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.stats.bytes_allocated, 0); - assert_eq!(heap.bumper, 64); + assert_eq!(heap.stats.bytes_allocated_peak, PAGE_SIZE - 16); + assert_eq!(heap.bumper, PAGE_SIZE - 16); + + // Allocate another 8 byte to use the full heap. + heap.allocate(&mut mem, 8).expect("Allocate 8 byte"); // when // the `bumper` value is equal to `size` here and any // further allocation which would increment the bumper must fail. // we try to allocate 8 bytes here, which will increment the - // bumper since no 8 byte item has been allocated+freed before. - let ptr = heap.allocate(&mut mem[..], 8); + // bumper since no 8 byte item has been freed before. + assert_eq!(heap.bumper as u64, mem.size()); + let ptr = heap.allocate(&mut mem, 8); // then - match ptr.unwrap_err() { - Error::AllocatorOutOfSpace => {}, - e => panic!("Expected allocator out of space error, got: {:?}", e), - } + assert_eq!(Error::AllocatorOutOfSpace, ptr.unwrap_err()); } #[test] fn should_include_prefixes_in_total_heap_size() { // given - let mut mem = [0u8; PAGE_SIZE as usize]; + let mut mem = MemoryInstance::with_pages(1); let mut heap = FreeingBumpHeapAllocator::new(1); // when // an item size of 16 must be used then - heap.allocate(&mut mem[..], 9).unwrap(); + heap.allocate(&mut mem, 9).unwrap(); // then assert_eq!(heap.stats.bytes_allocated, HEADER_SIZE + 16); @@ -846,13 +945,13 @@ mod tests { #[test] fn should_calculate_total_heap_size_to_zero() { // given - let mut mem = [0u8; PAGE_SIZE as usize]; + let mut mem = MemoryInstance::with_pages(1); let mut heap = FreeingBumpHeapAllocator::new(13); // when - let ptr = heap.allocate(&mut mem[..], 42).unwrap(); + let ptr = heap.allocate(&mut mem, 42).unwrap(); assert_eq!(ptr, to_pointer(16 + HEADER_SIZE)); - heap.deallocate(&mut mem[..], ptr).unwrap(); + heap.deallocate(&mut mem, ptr).unwrap(); // then assert_eq!(heap.stats.bytes_allocated, 0); @@ -861,13 +960,13 @@ mod tests { #[test] fn should_calculate_total_size_of_zero() { // given - let mut mem = [0u8; PAGE_SIZE as usize]; + let mut mem = MemoryInstance::with_pages(1); let mut heap = FreeingBumpHeapAllocator::new(19); // when for _ in 1..10 { - let ptr = heap.allocate(&mut mem[..], 42).unwrap(); - heap.deallocate(&mut mem[..], ptr).unwrap(); + let ptr = heap.allocate(&mut mem, 42).unwrap(); + heap.deallocate(&mut mem, ptr).unwrap(); } // then @@ -877,13 +976,13 @@ mod tests { #[test] fn should_read_and_write_u64_correctly() { // given - let mut mem = [0u8; PAGE_SIZE as usize]; + let mut mem = MemoryInstance::with_pages(1); // when - Memory::write_le_u64(mem.as_mut(), 40, 4480113).unwrap(); + mem.write_le_u64(40, 4480113).unwrap(); // then - let value = Memory::read_le_u64(mem.as_mut(), 40).unwrap(); + let value = MemoryExt::read_le_u64(&mut mem, 40).unwrap(); assert_eq!(value, 4480113); } @@ -913,24 +1012,25 @@ mod tests { #[test] fn deallocate_needs_to_maintain_linked_list() { - let mut mem = [0u8; 8 * 2 * 4 + ALIGNMENT as usize]; + let mut mem = MemoryInstance::with_pages(1); let mut heap = FreeingBumpHeapAllocator::new(0); // Allocate and free some pointers - let ptrs = (0..4).map(|_| heap.allocate(&mut mem[..], 8).unwrap()).collect::>(); - ptrs.into_iter().for_each(|ptr| heap.deallocate(&mut mem[..], ptr).unwrap()); + let ptrs = (0..4).map(|_| heap.allocate(&mut mem, 8).unwrap()).collect::>(); + ptrs.iter().rev().for_each(|ptr| heap.deallocate(&mut mem, *ptr).unwrap()); - // Second time we should be able to allocate all of them again. - let _ = (0..4).map(|_| heap.allocate(&mut mem[..], 8).unwrap()).collect::>(); + // Second time we should be able to allocate all of them again and get the same pointers! + let new_ptrs = (0..4).map(|_| heap.allocate(&mut mem, 8).unwrap()).collect::>(); + assert_eq!(ptrs, new_ptrs); } #[test] fn header_read_write() { let roundtrip = |header: Header| { - let mut memory = [0u8; 32]; - header.write_into(memory.as_mut(), 0).unwrap(); + let mut memory = MemoryInstance::with_pages(1); + header.write_into(&mut memory, 0).unwrap(); - let read_header = Header::read_from(memory.as_mut(), 0).unwrap(); + let read_header = Header::read_from(&memory, 0).unwrap(); assert_eq!(header, read_header); }; @@ -944,18 +1044,18 @@ mod tests { #[test] fn poison_oom() { // given - // a heap of 32 bytes. Should be enough for two allocations. - let mut mem = [0u8; 32]; + let mut mem = MemoryInstance::with_pages(1); + mem.set_max_wasm_pages(1); + let mut heap = FreeingBumpHeapAllocator::new(0); // when - assert!(heap.allocate(mem.as_mut(), 8).is_ok()); - let alloc_ptr = heap.allocate(mem.as_mut(), 8).unwrap(); - assert!(heap.allocate(mem.as_mut(), 8).is_err()); + let alloc_ptr = heap.allocate(&mut mem, PAGE_SIZE / 2).unwrap(); + assert_eq!(Error::AllocatorOutOfSpace, heap.allocate(&mut mem, PAGE_SIZE).unwrap_err()); // then assert!(heap.poisoned); - assert!(heap.deallocate(mem.as_mut(), alloc_ptr).is_err()); + assert!(heap.deallocate(&mut mem, alloc_ptr).is_err()); } #[test] @@ -969,36 +1069,41 @@ mod tests { #[test] fn accepts_growing_memory() { - const ITEM_SIZE: u32 = 16; - const ITEM_ON_HEAP_SIZE: usize = 16 + HEADER_SIZE as usize; - - let mut mem = vec![0u8; ITEM_ON_HEAP_SIZE * 2]; + let mut mem = MemoryInstance::with_pages(1); let mut heap = FreeingBumpHeapAllocator::new(0); - let _ = heap.allocate(&mut mem[..], ITEM_SIZE).unwrap(); - let _ = heap.allocate(&mut mem[..], ITEM_SIZE).unwrap(); + heap.allocate(&mut mem, PAGE_SIZE / 2).unwrap(); + heap.allocate(&mut mem, PAGE_SIZE / 2).unwrap(); - mem.extend_from_slice(&[0u8; ITEM_ON_HEAP_SIZE]); + mem.grow(1).unwrap(); - let _ = heap.allocate(&mut mem[..], ITEM_SIZE).unwrap(); + heap.allocate(&mut mem, PAGE_SIZE / 2).unwrap(); } #[test] fn doesnt_accept_shrinking_memory() { - const ITEM_SIZE: u32 = 16; - const ITEM_ON_HEAP_SIZE: usize = 16 + HEADER_SIZE as usize; - - let initial_size = ITEM_ON_HEAP_SIZE * 3; - let mut mem = vec![0u8; initial_size]; + let mut mem = MemoryInstance::with_pages(2); let mut heap = FreeingBumpHeapAllocator::new(0); - let _ = heap.allocate(&mut mem[..], ITEM_SIZE).unwrap(); + heap.allocate(&mut mem, PAGE_SIZE / 2).unwrap(); - mem.truncate(initial_size - 1); + mem.data.truncate(PAGE_SIZE as usize); - match heap.allocate(&mut mem[..], ITEM_SIZE).unwrap_err() { + match heap.allocate(&mut mem, PAGE_SIZE / 2).unwrap_err() { Error::MemoryShrinked => (), _ => panic!(), } } + + #[test] + fn should_grow_memory_when_running_out_of_memory() { + let mut mem = MemoryInstance::with_pages(1); + let mut heap = FreeingBumpHeapAllocator::new(0); + + assert_eq!(1, mem.pages()); + + heap.allocate(&mut mem, PAGE_SIZE * 2).unwrap(); + + assert_eq!(3, mem.pages()); + } } diff --git a/client/allocator/src/lib.rs b/client/allocator/src/lib.rs index 31179ab5ddede..e50d7d54c8e97 100644 --- a/client/allocator/src/lib.rs +++ b/client/allocator/src/lib.rs @@ -27,3 +27,35 @@ mod freeing_bump; pub use error::Error; pub use freeing_bump::{AllocationStats, FreeingBumpHeapAllocator}; + +/// The size of one wasm page in bytes. +/// +/// The wasm memory is divided into pages, meaning the minimum size of a memory is one page. +const PAGE_SIZE: u32 = 65536; + +/// The maximum number of wasm pages that can be allocated. +/// +/// 4GiB / [`PAGE_SIZE`]. +const MAX_WASM_PAGES: u32 = (4u64 * 1024 * 1024 * 1024 / PAGE_SIZE as u64) as u32; + +/// Grants access to the memory for the allocator. +/// +/// Memory of wasm is allocated in pages. A page has a constant size of 64KiB. The maximum allowed +/// memory size as defined in the wasm specification is 4GiB (65536 pages). +pub trait Memory { + /// Run the given closure `run` and grant it write access to the raw memory. + fn with_access_mut(&mut self, run: impl FnOnce(&mut [u8]) -> R) -> R; + /// Run the given closure `run` and grant it read access to the raw memory. + fn with_access(&self, run: impl FnOnce(&[u8]) -> R) -> R; + /// Grow the memory by `additional` pages. + fn grow(&mut self, additional: u32) -> Result<(), ()>; + /// Returns the current number of pages this memory has allocated. + fn pages(&self) -> u32; + /// Returns the maximum number of pages this memory is allowed to allocate. + /// + /// The returned number needs to be smaller or equal to `65536`. The returned number needs to be + /// bigger or equal to [`Self::pages`]. + /// + /// If `None` is returned, there is no maximum (besides the maximum defined in the wasm spec). + fn max_pages(&self) -> Option; +} diff --git a/client/api/src/call_executor.rs b/client/api/src/call_executor.rs index 42d3c4e3422c4..db8e4d8495af2 100644 --- a/client/api/src/call_executor.rs +++ b/client/api/src/call_executor.rs @@ -19,6 +19,7 @@ //! A method call executor interface. use sc_executor::{RuntimeVersion, RuntimeVersionOf}; +use sp_core::traits::CallContext; use sp_runtime::traits::Block as BlockT; use sp_state_machine::{ExecutionStrategy, OverlayedChanges, StorageProof}; use std::cell::RefCell; @@ -58,6 +59,7 @@ pub trait CallExecutor: RuntimeVersionOf { method: &str, call_data: &[u8], strategy: ExecutionStrategy, + context: CallContext, ) -> Result, sp_blockchain::Error>; /// Execute a contextual call on top of state in a block of a given hash. diff --git a/client/executor/Cargo.toml b/client/executor/Cargo.toml index 46b72565afefc..21a9bd70dde65 100644 --- a/client/executor/Cargo.toml +++ b/client/executor/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] lru = "0.8.1" parking_lot = "0.12.1" tracing = "0.1.29" -wasmi = "0.13" +wasmi = "0.13.2" codec = { package = "parity-scale-codec", version = "3.2.2" } sc-executor-common = { version = "0.10.0-dev", path = "common" } @@ -43,6 +43,7 @@ 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" } +sp-tracing = { version = "6.0.0", path = "../../primitives/tracing" } tracing-subscriber = "0.2.19" paste = "1.0" regex = "1.6.0" diff --git a/client/executor/benches/bench.rs b/client/executor/benches/bench.rs index 62e8b261f4786..10425ea461c21 100644 --- a/client/executor/benches/bench.rs +++ b/client/executor/benches/bench.rs @@ -21,7 +21,7 @@ use codec::Encode; use sc_executor_common::{ runtime_blob::RuntimeBlob, - wasm_runtime::{WasmInstance, WasmModule}, + wasm_runtime::{HeapAllocStrategy, WasmInstance, WasmModule}, }; use sc_executor_wasmtime::InstantiationStrategy; use sc_runtime_test::wasm_binary_unwrap as test_runtime; @@ -51,13 +51,13 @@ fn initialize( ) -> Arc { let blob = RuntimeBlob::uncompress_if_needed(runtime).unwrap(); let host_functions = sp_io::SubstrateHostFunctions::host_functions(); - let heap_pages = 2048; + let extra_pages = 2048; let allow_missing_func_imports = true; match method { Method::Interpreted => sc_executor_wasmi::create_runtime( blob, - heap_pages, + HeapAllocStrategy::Static { extra_pages }, host_functions, allow_missing_func_imports, ) @@ -67,12 +67,11 @@ fn initialize( allow_missing_func_imports, cache_path: None, semantics: sc_executor_wasmtime::Semantics { - extra_heap_pages: heap_pages, + heap_alloc_strategy: HeapAllocStrategy::Static { extra_pages }, instantiation_strategy, deterministic_stack_limit: None, canonicalize_nans: false, parallel_compilation: true, - max_memory_size: None, }, }; diff --git a/client/executor/common/Cargo.toml b/client/executor/common/Cargo.toml index 648e937d371ff..dd74ea2cfd209 100644 --- a/client/executor/common/Cargo.toml +++ b/client/executor/common/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] thiserror = "1.0.30" wasm-instrument = "0.3" -wasmi = "0.13" +wasmi = "0.13.2" sc-allocator = { version = "4.1.0-dev", path = "../../allocator" } sp-maybe-compressed-blob = { version = "4.1.0-dev", path = "../../../primitives/maybe-compressed-blob" } sp-wasm-interface = { version = "7.0.0", path = "../../../primitives/wasm-interface" } diff --git a/client/executor/common/src/runtime_blob/runtime_blob.rs b/client/executor/common/src/runtime_blob/runtime_blob.rs index dc0cde8d26974..24dc7e393a4bc 100644 --- a/client/executor/common/src/runtime_blob/runtime_blob.rs +++ b/client/executor/common/src/runtime_blob/runtime_blob.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::WasmError; +use crate::{error::WasmError, wasm_runtime::HeapAllocStrategy}; use wasm_instrument::{ export_mutable_globals, parity_wasm::elements::{ @@ -157,18 +157,13 @@ impl RuntimeBlob { Ok(()) } - /// Increases the number of memory pages requested by the WASM blob by - /// the given amount of `extra_heap_pages`. + /// Modifies the blob's memory section according to the given `heap_alloc_strategy`. /// /// 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( + pub fn setup_memory_according_to_heap_alloc_strategy( &mut self, - extra_heap_pages: u32, + heap_alloc_strategy: HeapAllocStrategy, ) -> Result<(), WasmError> { let memory_section = self .raw_module @@ -179,8 +174,17 @@ impl RuntimeBlob { 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)); + let initial = memory_ty.limits().initial(); + let (min, max) = match heap_alloc_strategy { + HeapAllocStrategy::Dynamic { maximum_pages } => { + // Ensure `initial <= maximum_pages` + (maximum_pages.map(|m| m.min(initial)).unwrap_or(initial), maximum_pages) + }, + HeapAllocStrategy::Static { extra_pages } => { + let pages = initial.saturating_add(extra_pages); + (pages, Some(pages)) + }, + }; *memory_ty = MemoryType::new(min, max); } Ok(()) diff --git a/client/executor/common/src/util.rs b/client/executor/common/src/util.rs index e672861cb6f3c..34967f86595d6 100644 --- a/client/executor/common/src/util.rs +++ b/client/executor/common/src/util.rs @@ -26,11 +26,7 @@ use std::ops::Range; /// Returns None if the end of the range would exceed some maximum offset. pub fn checked_range(offset: usize, len: usize, max: usize) -> Option> { let end = offset.checked_add(len)?; - if end <= max { - Some(offset..end) - } else { - None - } + (end <= max).then(|| offset..end) } /// Provides safe memory access interface using an external buffer diff --git a/client/executor/common/src/wasm_runtime.rs b/client/executor/common/src/wasm_runtime.rs index 5899252068753..e3db7e52fc7e7 100644 --- a/client/executor/common/src/wasm_runtime.rs +++ b/client/executor/common/src/wasm_runtime.rs @@ -119,3 +119,29 @@ pub trait WasmInstance: Send { None } } + +/// Defines the heap pages allocation strategy the wasm runtime should use. +/// +/// A heap page is defined as 64KiB of memory. +#[derive(Debug, Copy, Clone, PartialEq, Hash, Eq)] +pub enum HeapAllocStrategy { + /// Allocate a static number of heap pages. + /// + /// The total number of allocated heap pages is the initial number of heap pages requested by + /// the wasm file plus the `extra_pages`. + Static { + /// The number of pages that will be added on top of the initial heap pages requested by + /// the wasm file. + extra_pages: u32, + }, + /// Allocate the initial heap pages as requested by the wasm file and then allow it to grow + /// dynamically. + Dynamic { + /// The absolute maximum size of the linear memory (in pages). + /// + /// When `Some(_)` the linear memory will be allowed to grow up to this limit. + /// When `None` the linear memory will be allowed to grow up to the maximum limit supported + /// by WASM (4GB). + maximum_pages: Option, + }, +} diff --git a/client/executor/runtime-test/src/lib.rs b/client/executor/runtime-test/src/lib.rs index 23584006a72c0..2bd2aeeb606eb 100644 --- a/client/executor/runtime-test/src/lib.rs +++ b/client/executor/runtime-test/src/lib.rs @@ -328,6 +328,15 @@ sp_core::wasm_export_functions! { assert_eq!(value, -66); } + fn allocate_two_gigabyte() -> u32 { + let mut data = Vec::new(); + for _ in 0..205 { + data.push(Vec::::with_capacity(10 * 1024 * 1024)); + } + + data.iter().map(|d| d.capacity() as u32).sum() + } + fn test_abort_on_panic() { sp_io::panic_handler::abort_on_panic("test_abort_on_panic called"); } diff --git a/client/executor/src/integration_tests/linux.rs b/client/executor/src/integration_tests/linux.rs index 9afe37037eb2f..38d75da4eb7e8 100644 --- a/client/executor/src/integration_tests/linux.rs +++ b/client/executor/src/integration_tests/linux.rs @@ -21,25 +21,60 @@ use super::mk_test_runtime; use crate::WasmExecutionMethod; use codec::Encode as _; +use sc_executor_common::wasm_runtime::HeapAllocStrategy; mod smaps; use self::smaps::Smaps; +#[test] +fn memory_consumption_interpreted() { + let _ = sp_tracing::try_init_simple(); + + if std::env::var("RUN_TEST").is_ok() { + memory_consumption(WasmExecutionMethod::Interpreted); + } else { + // We need to run the test in isolation, to not getting interfered by the other tests. + let executable = std::env::current_exe().unwrap(); + let output = std::process::Command::new(executable) + .env("RUN_TEST", "1") + .args(&["--nocapture", "memory_consumption_interpreted"]) + .output() + .unwrap(); + + assert!(output.status.success()); + } +} + #[test] fn memory_consumption_compiled() { + let _ = sp_tracing::try_init_simple(); + + if std::env::var("RUN_TEST").is_ok() { + memory_consumption(WasmExecutionMethod::Compiled { + instantiation_strategy: + sc_executor_wasmtime::InstantiationStrategy::LegacyInstanceReuse, + }); + } else { + // We need to run the test in isolation, to not getting interfered by the other tests. + let executable = std::env::current_exe().unwrap(); + let status = std::process::Command::new(executable) + .env("RUN_TEST", "1") + .args(&["--nocapture", "memory_consumption_compiled"]) + .status() + .unwrap(); + + assert!(status.success()); + } +} + +fn memory_consumption(wasm_method: WasmExecutionMethod) { // This aims to see if linear memory stays backed by the physical memory after a runtime call. // // For that we make a series of runtime calls, probing the RSS for the VMA matching the linear // memory. After the call we expect RSS to be equal to 0. - let runtime = mk_test_runtime( - WasmExecutionMethod::Compiled { - instantiation_strategy: - sc_executor_wasmtime::InstantiationStrategy::LegacyInstanceReuse, - }, - 1024, - ); + let runtime = mk_test_runtime(wasm_method, HeapAllocStrategy::Static { extra_pages: 1024 }); let mut instance = runtime.new_instance().unwrap(); let heap_base = instance diff --git a/client/executor/src/integration_tests/mod.rs b/client/executor/src/integration_tests/mod.rs index 324c8d515d14a..066b1497fb6ec 100644 --- a/client/executor/src/integration_tests/mod.rs +++ b/client/executor/src/integration_tests/mod.rs @@ -24,7 +24,7 @@ use codec::{Decode, Encode}; use sc_executor_common::{ error::{Error, WasmError}, runtime_blob::RuntimeBlob, - wasm_runtime::WasmModule, + wasm_runtime::{HeapAllocStrategy, WasmModule}, }; use sc_runtime_test::wasm_binary_unwrap; use sp_core::{ @@ -52,11 +52,13 @@ macro_rules! test_wasm_execution { paste::item! { #[test] fn [<$method_name _interpreted>]() { + let _ = sp_tracing::try_init_simple(); $method_name(WasmExecutionMethod::Interpreted); } #[test] fn [<$method_name _compiled_recreate_instance_cow>]() { + let _ = sp_tracing::try_init_simple(); $method_name(WasmExecutionMethod::Compiled { instantiation_strategy: sc_executor_wasmtime::InstantiationStrategy::RecreateInstanceCopyOnWrite }); @@ -64,6 +66,7 @@ macro_rules! test_wasm_execution { #[test] fn [<$method_name _compiled_recreate_instance_vanilla>]() { + let _ = sp_tracing::try_init_simple(); $method_name(WasmExecutionMethod::Compiled { instantiation_strategy: sc_executor_wasmtime::InstantiationStrategy::RecreateInstance }); @@ -71,6 +74,7 @@ macro_rules! test_wasm_execution { #[test] fn [<$method_name _compiled_pooling_cow>]() { + let _ = sp_tracing::try_init_simple(); $method_name(WasmExecutionMethod::Compiled { instantiation_strategy: sc_executor_wasmtime::InstantiationStrategy::PoolingCopyOnWrite }); @@ -78,6 +82,7 @@ macro_rules! test_wasm_execution { #[test] fn [<$method_name _compiled_pooling_vanilla>]() { + let _ = sp_tracing::try_init_simple(); $method_name(WasmExecutionMethod::Compiled { instantiation_strategy: sc_executor_wasmtime::InstantiationStrategy::Pooling }); @@ -85,6 +90,7 @@ macro_rules! test_wasm_execution { #[test] fn [<$method_name _compiled_legacy_instance_reuse>]() { + let _ = sp_tracing::try_init_simple(); $method_name(WasmExecutionMethod::Compiled { instantiation_strategy: sc_executor_wasmtime::InstantiationStrategy::LegacyInstanceReuse }); @@ -474,7 +480,10 @@ fn should_trap_when_heap_exhausted(wasm_method: WasmExecutionMethod) { } } -fn mk_test_runtime(wasm_method: WasmExecutionMethod, pages: u64) -> Arc { +fn mk_test_runtime( + wasm_method: WasmExecutionMethod, + pages: HeapAllocStrategy, +) -> Arc { let blob = RuntimeBlob::uncompress_if_needed(wasm_binary_unwrap()) .expect("failed to create a runtime blob out of test runtime"); @@ -490,7 +499,8 @@ fn mk_test_runtime(wasm_method: WasmExecutionMethod, pages: u64) -> Arc( wasm_method, - 1024, + HeapAllocStrategy::Dynamic { maximum_pages: Some(1024) }, RuntimeBlob::uncompress_if_needed(&binary[..]).unwrap(), true, None, diff --git a/client/executor/src/native_executor.rs b/client/executor/src/native_executor.rs index a2af97ae4eacd..c72cf3c9c91df 100644 --- a/client/executor/src/native_executor.rs +++ b/client/executor/src/native_executor.rs @@ -32,14 +32,15 @@ use std::{ use codec::Encode; use sc_executor_common::{ runtime_blob::RuntimeBlob, - wasm_runtime::{AllocationStats, WasmInstance, WasmModule}, + wasm_runtime::{AllocationStats, HeapAllocStrategy, WasmInstance, WasmModule}, }; -use sp_core::traits::{CodeExecutor, Externalities, RuntimeCode}; +use sp_core::traits::{CallContext, CodeExecutor, Externalities, RuntimeCode}; use sp_version::{GetNativeVersion, NativeVersion, RuntimeVersion}; use sp_wasm_interface::{ExtendedHostFunctions, HostFunctions}; -/// Default num of pages for the heap -const DEFAULT_HEAP_PAGES: u64 = 2048; +/// Default heap allocation strategy. +const DEFAULT_HEAP_ALLOC_STRATEGY: HeapAllocStrategy = + HeapAllocStrategy::Static { extra_pages: 2048 }; /// Set up the externalities and safe calling environment to execute runtime calls. /// @@ -79,13 +80,136 @@ pub trait NativeExecutionDispatch: Send + Sync { fn native_version() -> NativeVersion; } +fn unwrap_heap_pages(pages: Option) -> HeapAllocStrategy { + pages.unwrap_or_else(|| DEFAULT_HEAP_ALLOC_STRATEGY) +} + +/// Builder for creating a [`WasmExecutor`] instance. +pub struct WasmExecutorBuilder { + _phantom: PhantomData, + method: WasmExecutionMethod, + onchain_heap_alloc_strategy: Option, + offchain_heap_alloc_strategy: Option, + max_runtime_instances: usize, + cache_path: Option, + allow_missing_host_functions: bool, + runtime_cache_size: u8, +} + +impl WasmExecutorBuilder { + /// Create a new instance of `Self` + /// + /// - `method`: The wasm execution method that should be used by the executor. + pub fn new(method: WasmExecutionMethod) -> Self { + Self { + _phantom: PhantomData, + method, + onchain_heap_alloc_strategy: None, + offchain_heap_alloc_strategy: None, + max_runtime_instances: 2, + runtime_cache_size: 4, + allow_missing_host_functions: false, + cache_path: None, + } + } + + /// Create the wasm executor with the given number of `heap_alloc_strategy` for onchain runtime + /// calls. + pub fn with_onchain_heap_alloc_strategy( + mut self, + heap_alloc_strategy: HeapAllocStrategy, + ) -> Self { + self.onchain_heap_alloc_strategy = Some(heap_alloc_strategy); + self + } + + /// Create the wasm executor with the given number of `heap_alloc_strategy` for offchain runtime + /// calls. + pub fn with_offchain_heap_alloc_strategy( + mut self, + heap_alloc_strategy: HeapAllocStrategy, + ) -> Self { + self.offchain_heap_alloc_strategy = Some(heap_alloc_strategy); + self + } + + /// Create the wasm executor with the given maximum number of `instances`. + /// + /// The number of `instances` defines how many different instances of a runtime the cache is + /// storing. + /// + /// By default the maximum number of `instances` is `2`. + pub fn with_max_runtime_instances(mut self, instances: usize) -> Self { + self.max_runtime_instances = instances; + self + } + + /// Create the wasm executor with the given `cache_path`. + /// + /// The `cache_path` is 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. + /// + /// By default there is no `cache_path` given. + pub fn with_cache_path(mut self, cache_path: impl Into) -> Self { + self.cache_path = Some(cache_path.into()); + self + } + + /// Create the wasm executor and allow/forbid missing host functions. + /// + /// If missing host functions are forbidden, the instantiation of a wasm blob will fail + /// for imported host functions that the executor is not aware of. If they are allowed, + /// a stub is generated that will return an error when being called while executing the wasm. + /// + /// By default missing host functions are forbidden. + pub fn with_allow_missing_host_functions(mut self, allow: bool) -> Self { + self.allow_missing_host_functions = allow; + self + } + + /// Create the wasm executor with the given `runtime_cache_size`. + /// + /// Defines the number of different runtimes/instantiated wasm blobs the cache stores. + /// Runtimes/wasm blobs are differentiated based on the hash and the number of heap pages. + /// + /// By default this value is set to `4`. + pub fn with_runtime_cache_size(mut self, runtime_cache_size: u8) -> Self { + self.runtime_cache_size = runtime_cache_size; + self + } + + /// Build the configured [`WasmExecutor`]. + pub fn build(self) -> WasmExecutor { + WasmExecutor { + method: self.method, + default_offchain_heap_alloc_strategy: unwrap_heap_pages( + self.offchain_heap_alloc_strategy, + ), + default_onchain_heap_alloc_strategy: unwrap_heap_pages( + self.onchain_heap_alloc_strategy, + ), + cache: Arc::new(RuntimeCache::new( + self.max_runtime_instances, + self.cache_path.clone(), + self.runtime_cache_size, + )), + cache_path: self.cache_path, + allow_missing_host_functions: self.allow_missing_host_functions, + phantom: PhantomData, + } + } +} + /// An abstraction over Wasm code executor. Supports selecting execution backend and /// manages runtime cache. 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 heap allocation strategy for onchain Wasm calls. + default_onchain_heap_alloc_strategy: HeapAllocStrategy, + /// The heap allocation strategy for offchain Wasm calls. + default_offchain_heap_alloc_strategy: HeapAllocStrategy, /// WASM runtime cache. cache: Arc, /// The path to a directory which the executor can leverage for a file cache, e.g. put there @@ -100,7 +224,8 @@ impl Clone for WasmExecutor { fn clone(&self) -> Self { Self { method: self.method, - default_heap_pages: self.default_heap_pages, + default_onchain_heap_alloc_strategy: self.default_onchain_heap_alloc_strategy, + default_offchain_heap_alloc_strategy: self.default_offchain_heap_alloc_strategy, cache: self.cache.clone(), cache_path: self.cache_path.clone(), allow_missing_host_functions: self.allow_missing_host_functions, @@ -119,8 +244,10 @@ where /// /// `method` - Method used to execute Wasm code. /// - /// `default_heap_pages` - Number of 64KB pages to allocate for Wasm execution. - /// Defaults to `DEFAULT_HEAP_PAGES` if `None` is provided. + /// `default_heap_pages` - Number of 64KB pages to allocate for Wasm execution. Internally this + /// will be mapped as [`HeapAllocStrategy::Static`] where `default_heap_pages` represent the + /// static number of heap pages to allocate. Defaults to `DEFAULT_HEAP_ALLOC_STRATEGY` if `None` + /// is provided. /// /// `max_runtime_instances` - The number of runtime instances to keep in memory ready for reuse. /// @@ -138,7 +265,12 @@ where ) -> Self { WasmExecutor { method, - default_heap_pages: default_heap_pages.unwrap_or(DEFAULT_HEAP_PAGES), + default_onchain_heap_alloc_strategy: unwrap_heap_pages( + default_heap_pages.map(|h| HeapAllocStrategy::Static { extra_pages: h as _ }), + ), + default_offchain_heap_alloc_strategy: unwrap_heap_pages( + default_heap_pages.map(|h| HeapAllocStrategy::Static { extra_pages: h as _ }), + ), cache: Arc::new(RuntimeCache::new( max_runtime_instances, cache_path.clone(), @@ -150,6 +282,11 @@ where } } + /// Instantiate a builder for creating an instance of `Self`. + pub fn builder(method: WasmExecutionMethod) -> WasmExecutorBuilder { + WasmExecutorBuilder::new(method) + } + /// 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 @@ -172,6 +309,7 @@ where &self, runtime_code: &RuntimeCode, ext: &mut dyn Externalities, + heap_alloc_strategy: HeapAllocStrategy, f: F, ) -> Result where @@ -186,7 +324,7 @@ where runtime_code, ext, self.method, - self.default_heap_pages, + heap_alloc_strategy, self.allow_missing_host_functions, |module, instance, version, ext| { let module = AssertUnwindSafe(module); @@ -259,7 +397,7 @@ where ) -> std::result::Result, Error> { let module = crate::wasm_runtime::create_wasm_runtime_with_code::( self.method, - self.default_heap_pages, + self.default_onchain_heap_alloc_strategy, runtime_blob, allow_missing_host_functions, self.cache_path.as_deref(), @@ -334,6 +472,7 @@ where method: &str, data: &[u8], _use_native: bool, + context: CallContext, ) -> (Result>, bool) { tracing::trace!( target: "executor", @@ -341,10 +480,25 @@ where "Executing function", ); - let result = - self.with_instance(runtime_code, ext, |_, mut instance, _onchain_version, mut ext| { + let on_chain_heap_alloc_strategy = runtime_code + .heap_pages + .map(|h| HeapAllocStrategy::Static { extra_pages: h as _ }) + .unwrap_or_else(|| self.default_onchain_heap_alloc_strategy); + + let heap_alloc_strategy = match context { + CallContext::Offchain => self.default_offchain_heap_alloc_strategy, + CallContext::Onchain => on_chain_heap_alloc_strategy, + }; + + let result = self.with_instance( + runtime_code, + ext, + heap_alloc_strategy, + |_, mut instance, _onchain_version, mut ext| { with_externalities_safe(&mut **ext, move || instance.call_export(method, data)) - }); + }, + ); + (result, false) } } @@ -358,20 +512,25 @@ where ext: &mut dyn Externalities, runtime_code: &RuntimeCode, ) -> Result { - self.with_instance(runtime_code, ext, |_module, _instance, version, _ext| { - Ok(version.cloned().ok_or_else(|| Error::ApiError("Unknown version".into()))) - }) + let on_chain_heap_pages = runtime_code + .heap_pages + .map(|h| HeapAllocStrategy::Static { extra_pages: h as _ }) + .unwrap_or_else(|| self.default_onchain_heap_alloc_strategy); + + self.with_instance( + runtime_code, + ext, + on_chain_heap_pages, + |_module, _instance, version, _ext| { + Ok(version.cloned().ok_or_else(|| Error::ApiError("Unknown version".into()))) + }, + ) } } /// 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 -where - D: NativeExecutionDispatch, -{ - /// Dummy field to avoid the compiler complaining about us not using `D`. - _dummy: PhantomData, +pub struct NativeElseWasmExecutor { /// Native runtime version info. native_version: NativeVersion, /// Fallback wasm executor. @@ -386,8 +545,10 @@ impl NativeElseWasmExecutor { /// /// `fallback_method` - Method used to execute fallback Wasm code. /// - /// `default_heap_pages` - Number of 64KB pages to allocate for Wasm execution. - /// Defaults to `DEFAULT_HEAP_PAGES` if `None` is provided. + /// `default_heap_pages` - Number of 64KB pages to allocate for Wasm execution. Internally this + /// will be mapped as [`HeapAllocStrategy::Static`] where `default_heap_pages` represent the + /// static number of heap pages to allocate. Defaults to `DEFAULT_HEAP_ALLOC_STRATEGY` if `None` + /// is provided. /// /// `max_runtime_instances` - The number of runtime instances to keep in memory ready for reuse. /// @@ -406,11 +567,16 @@ impl NativeElseWasmExecutor { runtime_cache_size, ); - NativeElseWasmExecutor { - _dummy: Default::default(), - native_version: D::native_version(), - wasm, - } + NativeElseWasmExecutor { native_version: D::native_version(), wasm } + } + + /// Create a new instance using the given [`WasmExecutor`]. + pub fn new_with_wasm_executor( + executor: WasmExecutor< + ExtendedHostFunctions, + >, + ) -> Self { + Self { native_version: D::native_version(), wasm: executor } } /// Ignore missing function imports if set true. @@ -425,9 +591,7 @@ impl RuntimeVersionOf for NativeElseWasmExecutor ext: &mut dyn Externalities, runtime_code: &RuntimeCode, ) -> Result { - self.wasm.with_instance(runtime_code, ext, |_module, _instance, version, _ext| { - Ok(version.cloned().ok_or_else(|| Error::ApiError("Unknown version".into()))) - }) + self.wasm.runtime_version(ext, runtime_code) } } @@ -447,6 +611,7 @@ impl CodeExecutor for NativeElseWasmExecut method: &str, data: &[u8], use_native: bool, + context: CallContext, ) -> (Result>, bool) { tracing::trace!( target: "executor", @@ -454,10 +619,21 @@ impl CodeExecutor for NativeElseWasmExecut "Executing function", ); + let on_chain_heap_alloc_strategy = runtime_code + .heap_pages + .map(|h| HeapAllocStrategy::Static { extra_pages: h as _ }) + .unwrap_or_else(|| self.wasm.default_onchain_heap_alloc_strategy); + + let heap_alloc_strategy = match context { + CallContext::Offchain => self.wasm.default_offchain_heap_alloc_strategy, + CallContext::Onchain => on_chain_heap_alloc_strategy, + }; + let mut used_native = false; let result = self.wasm.with_instance( runtime_code, ext, + heap_alloc_strategy, |_, mut instance, onchain_version, mut ext| { let onchain_version = onchain_version.ok_or_else(|| Error::ApiError("Unknown version".into()))?; @@ -496,11 +672,7 @@ impl CodeExecutor for NativeElseWasmExecut impl Clone for NativeElseWasmExecutor { fn clone(&self) -> Self { - NativeElseWasmExecutor { - _dummy: Default::default(), - native_version: D::native_version(), - wasm: self.wasm.clone(), - } + NativeElseWasmExecutor { native_version: D::native_version(), wasm: self.wasm.clone() } } } diff --git a/client/executor/src/wasm_runtime.rs b/client/executor/src/wasm_runtime.rs index 4869fbae2d7db..254380dbb3693 100644 --- a/client/executor/src/wasm_runtime.rs +++ b/client/executor/src/wasm_runtime.rs @@ -27,7 +27,7 @@ use lru::LruCache; use parking_lot::Mutex; use sc_executor_common::{ runtime_blob::RuntimeBlob, - wasm_runtime::{WasmInstance, WasmModule}, + wasm_runtime::{HeapAllocStrategy, WasmInstance, WasmModule}, }; use sp_core::traits::{Externalities, FetchRuntimeCode, RuntimeCode}; use sp_version::RuntimeVersion; @@ -64,8 +64,8 @@ struct VersionedRuntimeId { code_hash: Vec, /// Wasm runtime type. wasm_method: WasmExecutionMethod, - /// The number of WebAssembly heap pages this instance was created with. - heap_pages: u64, + /// The heap allocation strategy this runtime was created with. + heap_alloc_strategy: HeapAllocStrategy, } /// A Wasm runtime object along with its cached runtime version. @@ -197,10 +197,12 @@ impl RuntimeCache { /// /// `runtime_code` - The runtime wasm code used setup the runtime. /// - /// `default_heap_pages` - Number of 64KB pages to allocate for Wasm execution. + /// `ext` - The externalities to access the state. /// /// `wasm_method` - Type of WASM backend to use. /// + /// `heap_alloc_strategy` - The heap allocation strategy to use. + /// /// `allow_missing_func_imports` - Ignore missing function imports. /// /// `f` - Function to execute. @@ -219,7 +221,7 @@ impl RuntimeCache { runtime_code: &'c RuntimeCode<'c>, ext: &mut dyn Externalities, wasm_method: WasmExecutionMethod, - default_heap_pages: u64, + heap_alloc_strategy: HeapAllocStrategy, allow_missing_func_imports: bool, f: F, ) -> Result, Error> @@ -233,10 +235,9 @@ impl RuntimeCache { ) -> Result, { 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 }; + VersionedRuntimeId { code_hash: code_hash.clone(), heap_alloc_strategy, wasm_method }; let mut runtimes = self.runtimes.lock(); // this must be released prior to calling f let versioned_runtime = if let Some(versioned_runtime) = runtimes.get(&versioned_runtime_id) @@ -251,7 +252,7 @@ impl RuntimeCache { &code, ext, wasm_method, - heap_pages, + heap_alloc_strategy, allow_missing_func_imports, self.max_runtime_instances, self.cache_path.as_deref(), @@ -289,7 +290,7 @@ impl RuntimeCache { /// Create a wasm runtime with the given `code`. pub fn create_wasm_runtime_with_code( wasm_method: WasmExecutionMethod, - heap_pages: u64, + heap_alloc_strategy: HeapAllocStrategy, blob: RuntimeBlob, allow_missing_func_imports: bool, cache_path: Option<&Path>, @@ -307,7 +308,7 @@ where sc_executor_wasmi::create_runtime( blob, - heap_pages, + heap_alloc_strategy, H::host_functions(), allow_missing_func_imports, ) @@ -320,12 +321,11 @@ where allow_missing_func_imports, cache_path: cache_path.map(ToOwned::to_owned), semantics: sc_executor_wasmtime::Semantics { - extra_heap_pages: heap_pages, + heap_alloc_strategy, instantiation_strategy, deterministic_stack_limit: None, canonicalize_nans: false, parallel_compilation: true, - max_memory_size: None, }, }, ) @@ -393,7 +393,7 @@ fn create_versioned_wasm_runtime( code: &[u8], ext: &mut dyn Externalities, wasm_method: WasmExecutionMethod, - heap_pages: u64, + heap_alloc_strategy: HeapAllocStrategy, allow_missing_func_imports: bool, max_instances: usize, cache_path: Option<&Path>, @@ -408,11 +408,11 @@ where // Use the runtime blob to scan if there is any metadata embedded into the wasm binary // pertaining to runtime version. We do it before consuming the runtime blob for creating the // runtime. - let mut version: Option<_> = read_embedded_version(&blob)?; + let mut version = read_embedded_version(&blob)?; let runtime = create_wasm_runtime_with_code::( wasm_method, - heap_pages, + heap_alloc_strategy, blob, allow_missing_func_imports, cache_path, diff --git a/client/executor/wasmi/Cargo.toml b/client/executor/wasmi/Cargo.toml index 4235440023c89..ded44f4ca77a9 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.17" -wasmi = "0.13" +wasmi = { version = "0.13.2", features = [ "virtual_memory" ] } 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" } diff --git a/client/executor/wasmi/src/lib.rs b/client/executor/wasmi/src/lib.rs index 78b32a027eaa9..c757ff8afe43d 100644 --- a/client/executor/wasmi/src/lib.rs +++ b/client/executor/wasmi/src/lib.rs @@ -20,23 +20,58 @@ use std::{cell::RefCell, str, sync::Arc}; -use log::{debug, error, trace}; +use log::{error, trace}; use wasmi::{ memory_units::Pages, - FuncInstance, ImportsBuilder, MemoryInstance, MemoryRef, Module, ModuleInstance, ModuleRef, + FuncInstance, ImportsBuilder, MemoryRef, Module, ModuleInstance, ModuleRef, RuntimeValue::{self, I32, I64}, TableRef, }; -use sc_allocator::AllocationStats; +use sc_allocator::{AllocationStats, FreeingBumpHeapAllocator}; use sc_executor_common::{ error::{Error, MessageWithBacktrace, WasmError}, runtime_blob::{DataSegmentsSnapshot, RuntimeBlob}, - wasm_runtime::{InvokeMethod, WasmInstance, WasmModule}, + wasm_runtime::{HeapAllocStrategy, InvokeMethod, WasmInstance, WasmModule}, }; use sp_runtime_interface::unpack_ptr_and_len; use sp_wasm_interface::{Function, FunctionContext, Pointer, Result as WResult, WordSize}; +/// Wrapper around [`MemorRef`] that implements [`sc_allocator::Memory`]. +struct MemoryWrapper<'a>(&'a MemoryRef); + +impl sc_allocator::Memory for MemoryWrapper<'_> { + fn with_access_mut(&mut self, run: impl FnOnce(&mut [u8]) -> R) -> R { + self.0.with_direct_access_mut(run) + } + + fn with_access(&self, run: impl FnOnce(&[u8]) -> R) -> R { + self.0.with_direct_access(run) + } + + fn pages(&self) -> u32 { + self.0.current_size().0 as _ + } + + fn max_pages(&self) -> Option { + self.0.maximum().map(|p| p.0 as _) + } + + fn grow(&mut self, additional: u32) -> Result<(), ()> { + self.0 + .grow(Pages(additional as _)) + .map_err(|e| { + log::error!( + target: "wasm-executor", + "Failed to grow memory by {} pages: {}", + additional, + e, + ) + }) + .map(drop) + } +} + struct FunctionExecutor { heap: RefCell, memory: MemoryRef, @@ -55,7 +90,7 @@ impl FunctionExecutor { missing_functions: Arc>, ) -> Result { Ok(FunctionExecutor { - heap: RefCell::new(sc_allocator::FreeingBumpHeapAllocator::new(heap_base)), + heap: RefCell::new(FreeingBumpHeapAllocator::new(heap_base)), memory: m, host_functions, allow_missing_func_imports, @@ -75,15 +110,17 @@ impl FunctionContext for FunctionExecutor { } fn allocate_memory(&mut self, size: WordSize) -> WResult> { - let heap = &mut self.heap.borrow_mut(); - self.memory - .with_direct_access_mut(|mem| heap.allocate(mem, size).map_err(|e| e.to_string())) + self.heap + .borrow_mut() + .allocate(&mut MemoryWrapper(&self.memory), size) + .map_err(|e| e.to_string()) } fn deallocate_memory(&mut self, ptr: Pointer) -> WResult<()> { - let heap = &mut self.heap.borrow_mut(); - self.memory - .with_direct_access_mut(|mem| heap.deallocate(mem, ptr).map_err(|e| e.to_string())) + self.heap + .borrow_mut() + .deallocate(&mut MemoryWrapper(&self.memory), ptr) + .map_err(|e| e.to_string()) } fn register_panic_error_message(&mut self, message: &str) { @@ -101,26 +138,17 @@ struct Resolver<'a> { allow_missing_func_imports: bool, /// All the names of functions for that we did not provide a host function. missing_functions: RefCell>, - /// Will be used as initial and maximum size of the imported memory. - heap_pages: usize, - /// By default, runtimes should import memory and this is `Some(_)` after - /// resolving. However, to be backwards compatible, we also support memory - /// exported by the WASM blob (this will be `None` after resolving). - import_memory: RefCell>, } impl<'a> Resolver<'a> { fn new( host_functions: &'a [&'static dyn Function], allow_missing_func_imports: bool, - heap_pages: usize, ) -> Resolver<'a> { Resolver { host_functions, allow_missing_func_imports, missing_functions: RefCell::new(Vec::new()), - heap_pages, - import_memory: Default::default(), } } } @@ -148,7 +176,11 @@ impl<'a> wasmi::ModuleImportResolver for Resolver<'a> { } if self.allow_missing_func_imports { - trace!(target: "wasm-executor", "Could not find function `{}`, a stub will be provided instead.", name); + trace!( + target: "wasm-executor", + "Could not find function `{}`, a stub will be provided instead.", + name, + ); let id = self.missing_functions.borrow().len() + self.host_functions.len(); self.missing_functions.borrow_mut().push(name.to_string()); @@ -160,44 +192,12 @@ impl<'a> wasmi::ModuleImportResolver for Resolver<'a> { fn resolve_memory( &self, - field_name: &str, - memory_type: &wasmi::MemoryDescriptor, + _: &str, + _: &wasmi::MemoryDescriptor, ) -> Result { - if field_name == "memory" { - match &mut *self.import_memory.borrow_mut() { - Some(_) => - Err(wasmi::Error::Instantiation("Memory can not be imported twice!".into())), - memory_ref @ None => { - if memory_type - .maximum() - .map(|m| m.saturating_sub(memory_type.initial())) - .map(|m| self.heap_pages > m as usize) - .unwrap_or(false) - { - Err(wasmi::Error::Instantiation(format!( - "Heap pages ({}) is greater than imported memory maximum ({}).", - self.heap_pages, - memory_type - .maximum() - .map(|m| m.saturating_sub(memory_type.initial())) - .expect("Maximum is set, checked above; qed"), - ))) - } else { - let memory = MemoryInstance::alloc( - Pages(memory_type.initial() as usize + self.heap_pages), - Some(Pages(memory_type.initial() as usize + self.heap_pages)), - )?; - *memory_ref = Some(memory.clone()); - Ok(memory) - } - }, - } - } else { - Err(wasmi::Error::Instantiation(format!( - "Unknown memory reference with name: {}", - field_name - ))) - } + Err(wasmi::Error::Instantiation( + "Internal error, wasmi expects that the wasm blob exports memory.".into(), + )) } } @@ -358,12 +358,11 @@ fn call_in_wasm_module( /// Prepare module instance fn instantiate_module( - heap_pages: usize, module: &Module, host_functions: &[&'static dyn Function], allow_missing_func_imports: bool, ) -> Result<(ModuleRef, Vec, MemoryRef), Error> { - let resolver = Resolver::new(host_functions, allow_missing_func_imports, heap_pages); + let resolver = Resolver::new(host_functions, allow_missing_func_imports); // start module instantiation. Don't run 'start' function yet. let intermediate_instance = ModuleInstance::new(module, &ImportsBuilder::new().with_resolver("env", &resolver))?; @@ -371,22 +370,10 @@ fn instantiate_module( // Verify that the module has the heap base global variable. let _ = get_heap_base(intermediate_instance.not_started_instance())?; - // Get the memory reference. Runtimes should import memory, but to be backwards - // compatible we also support exported memory. - let memory = match resolver.import_memory.into_inner() { - Some(memory) => memory, - None => { - debug!( - target: "wasm-executor", - "WASM blob does not imports memory, falling back to exported memory", - ); - - let memory = get_mem_instance(intermediate_instance.not_started_instance())?; - memory.grow(Pages(heap_pages)).map_err(|_| Error::Runtime)?; - - memory - }, - }; + // The `module` should export the memory with the correct properties (min, max). + // + // This is ensured by modifying the `RuntimeBlob` before initializing the `Module`. + let memory = get_mem_instance(intermediate_instance.not_started_instance())?; if intermediate_instance.has_start() { // Runtime is not allowed to have the `start` function. @@ -451,8 +438,6 @@ pub struct WasmiRuntime { /// Enable stub generation for functions that are not available in `host_functions`. /// These stubs will error when the wasm blob tries to call them. allow_missing_func_imports: bool, - /// Numer of heap pages this runtime uses. - heap_pages: u64, global_vals_snapshot: GlobalValsSnapshot, data_segments_snapshot: DataSegmentsSnapshot, @@ -461,13 +446,9 @@ pub struct WasmiRuntime { impl WasmModule for WasmiRuntime { fn new_instance(&self) -> Result, Error> { // Instantiate this module. - let (instance, missing_functions, memory) = instantiate_module( - self.heap_pages as usize, - &self.module, - &self.host_functions, - self.allow_missing_func_imports, - ) - .map_err(|e| WasmError::Instantiation(e.to_string()))?; + let (instance, missing_functions, memory) = + instantiate_module(&self.module, &self.host_functions, self.allow_missing_func_imports) + .map_err(|e| WasmError::Instantiation(e.to_string()))?; Ok(Box::new(WasmiInstance { instance, @@ -477,6 +458,7 @@ impl WasmModule for WasmiRuntime { host_functions: self.host_functions.clone(), allow_missing_func_imports: self.allow_missing_func_imports, missing_functions: Arc::new(missing_functions), + memory_zeroed: true, })) } } @@ -484,25 +466,26 @@ impl WasmModule for WasmiRuntime { /// Create a new `WasmiRuntime` given the code. This function loads the module and /// stores it in the instance. pub fn create_runtime( - blob: RuntimeBlob, - heap_pages: u64, + mut blob: RuntimeBlob, + heap_alloc_strategy: HeapAllocStrategy, host_functions: Vec<&'static dyn Function>, allow_missing_func_imports: bool, ) -> Result { let data_segments_snapshot = DataSegmentsSnapshot::take(&blob).map_err(|e| WasmError::Other(e.to_string()))?; + // Make sure we only have exported memory to simplify the code of the wasmi executor. + blob.convert_memory_import_into_export()?; + // Ensure that the memory uses the correct heap pages. + blob.setup_memory_according_to_heap_alloc_strategy(heap_alloc_strategy)?; + let module = Module::from_parity_wasm_module(blob.into_inner()).map_err(|_| WasmError::InvalidModule)?; let global_vals_snapshot = { - let (instance, _, _) = instantiate_module( - heap_pages as usize, - &module, - &host_functions, - allow_missing_func_imports, - ) - .map_err(|e| WasmError::Instantiation(e.to_string()))?; + let (instance, _, _) = + instantiate_module(&module, &host_functions, allow_missing_func_imports) + .map_err(|e| WasmError::Instantiation(e.to_string()))?; GlobalValsSnapshot::take(&instance) }; @@ -512,7 +495,6 @@ pub fn create_runtime( global_vals_snapshot, host_functions: Arc::new(host_functions), allow_missing_func_imports, - heap_pages, }) } @@ -522,6 +504,8 @@ pub struct WasmiInstance { instance: ModuleRef, /// The memory instance of used by the wasm module. memory: MemoryRef, + /// Is the memory zeroed? + memory_zeroed: bool, /// The snapshot of global variable values just after instantiation. global_vals_snapshot: GlobalValsSnapshot, /// The snapshot of data segments. @@ -549,14 +533,16 @@ impl WasmiInstance { // 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. - // First, zero initialize the linear memory. - self.memory.erase().map_err(|e| { - // Snapshot restoration failed. This is pretty unexpected since this can happen - // if some invariant is broken or if the system is under extreme memory pressure - // (so erasing fails). - error!(target: "wasm-executor", "snapshot restoration failed: {}", e); - WasmError::ErasingFailed(e.to_string()) - })?; + if !self.memory_zeroed { + // First, zero initialize the linear memory. + self.memory.erase().map_err(|e| { + // Snapshot restoration failed. This is pretty unexpected since this can happen + // if some invariant is broken or if the system is under extreme memory pressure + // (so erasing fails). + error!(target: "wasm-executor", "snapshot restoration failed: {}", e); + WasmError::ErasingFailed(e.to_string()) + })?; + } // Second, reapply data segments into the linear memory. self.data_segments_snapshot @@ -565,7 +551,7 @@ impl WasmiInstance { // Third, restore the global variables to their initial values. self.global_vals_snapshot.apply(&self.instance)?; - call_in_wasm_module( + let res = call_in_wasm_module( &self.instance, &self.memory, method, @@ -574,7 +560,12 @@ impl WasmiInstance { self.allow_missing_func_imports, self.missing_functions.clone(), allocation_stats, - ) + ); + + // If we couldn't unmap it, erase the memory. + self.memory_zeroed = self.memory.erase().is_ok(); + + res } } @@ -601,4 +592,8 @@ impl WasmInstance for WasmiInstance { None => Ok(None), } } + + fn linear_memory_base_ptr(&self) -> Option<*const u8> { + Some(self.memory.direct_access().as_ref().as_ptr()) + } } diff --git a/client/executor/wasmtime/Cargo.toml b/client/executor/wasmtime/Cargo.toml index ca7daa970207d..2e892a98a126b 100644 --- a/client/executor/wasmtime/Cargo.toml +++ b/client/executor/wasmtime/Cargo.toml @@ -13,9 +13,9 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] +log = "0.4.17" cfg-if = "1.0" libc = "0.2.121" -log = "0.4.17" # When bumping wasmtime do not forget to also bump rustix # to exactly the same version as used by wasmtime! diff --git a/client/executor/wasmtime/src/host.rs b/client/executor/wasmtime/src/host.rs index ead248385c9fe..9bd3ca3dade5e 100644 --- a/client/executor/wasmtime/src/host.rs +++ b/client/executor/wasmtime/src/host.rs @@ -24,20 +24,25 @@ use wasmtime::Caller; use sc_allocator::{AllocationStats, FreeingBumpHeapAllocator}; use sp_wasm_interface::{Pointer, WordSize}; -use crate::{runtime::StoreData, util}; +use crate::{instance_wrapper::MemoryWrapper, runtime::StoreData, util}; /// 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 { - allocator: FreeingBumpHeapAllocator, + /// The allocator instance to keep track of allocated memory. + /// + /// This is stored as an `Option` as we need to temporarly set this to `None` when we are + /// allocating/deallocating memory. The problem being that we can only mutable access `caller` + /// once. + allocator: Option, panic_message: Option, } impl HostState { /// Constructs a new `HostState`. pub fn new(allocator: FreeingBumpHeapAllocator) -> Self { - HostState { allocator, panic_message: None } + HostState { allocator: Some(allocator), panic_message: None } } /// Takes the error message out of the host state, leaving a `None` in its place. @@ -46,7 +51,9 @@ impl HostState { } pub(crate) fn allocation_stats(&self) -> AllocationStats { - self.allocator.stats() + self.allocator.as_ref() + .expect("Allocator is always set and only unavailable when doing an allocation/deallocation; qed") + .stats() } } @@ -81,22 +88,38 @@ impl<'a> sp_wasm_interface::FunctionContext for HostContext<'a> { fn allocate_memory(&mut self, size: WordSize) -> sp_wasm_interface::Result> { 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") + let mut allocator = self + .host_state_mut() .allocator - .allocate(memory, size) - .map_err(|e| e.to_string()) + .take() + .expect("allocator is not empty when calling a function in wasm; qed"); + + // We can not return on error early, as we need to store back allocator. + let res = allocator + .allocate(&mut MemoryWrapper(&memory, &mut self.caller), size) + .map_err(|e| e.to_string()); + + self.host_state_mut().allocator = Some(allocator); + + res } fn deallocate_memory(&mut self, ptr: Pointer) -> sp_wasm_interface::Result<()> { 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") + let mut allocator = self + .host_state_mut() .allocator - .deallocate(memory, ptr) - .map_err(|e| e.to_string()) + .take() + .expect("allocator is not empty when calling a function in wasm; qed"); + + // We can not return on error early, as we need to store back allocator. + let res = allocator + .deallocate(&mut MemoryWrapper(&memory, &mut self.caller), ptr) + .map_err(|e| e.to_string()); + + self.host_state_mut().allocator = Some(allocator); + + res } fn register_panic_error_message(&mut self, message: &str) { diff --git a/client/executor/wasmtime/src/instance_wrapper.rs b/client/executor/wasmtime/src/instance_wrapper.rs index 2fb27180fcc76..6d319cce509e5 100644 --- a/client/executor/wasmtime/src/instance_wrapper.rs +++ b/client/executor/wasmtime/src/instance_wrapper.rs @@ -26,8 +26,7 @@ use sc_executor_common::{ }; use sp_wasm_interface::{Pointer, Value, WordSize}; use wasmtime::{ - AsContext, AsContextMut, Engine, Extern, Func, Global, Instance, InstancePre, Memory, Table, - Val, + AsContext, AsContextMut, Engine, Extern, Instance, InstancePre, Memory, Table, Val, }; /// Invoked entrypoint format. @@ -113,66 +112,58 @@ impl EntryPoint { } } -/// Wrap the given WebAssembly Instance of a wasm module with Substrate-runtime. -/// -/// This struct is a handy wrapper around a wasmtime `Instance` that provides substrate specific -/// routines. -pub struct InstanceWrapper { - instance: Instance, - memory: Memory, - store: Store, -} +/// Wrapper around [`Memory`] that implements [`sc_allocator::Memory`]. +pub(crate) struct MemoryWrapper<'a, C>(pub &'a wasmtime::Memory, pub &'a mut C); -fn extern_memory(extern_: &Extern) -> Option<&Memory> { - match extern_ { - Extern::Memory(mem) => Some(mem), - _ => None, +impl sc_allocator::Memory for MemoryWrapper<'_, C> { + fn with_access(&self, run: impl FnOnce(&[u8]) -> R) -> R { + run(self.0.data(&self.1)) } -} -fn extern_global(extern_: &Extern) -> Option<&Global> { - match extern_ { - Extern::Global(glob) => Some(glob), - _ => None, + fn with_access_mut(&mut self, run: impl FnOnce(&mut [u8]) -> R) -> R { + run(self.0.data_mut(&mut self.1)) } -} -fn extern_table(extern_: &Extern) -> Option<&Table> { - match extern_ { - Extern::Table(table) => Some(table), - _ => None, + fn grow(&mut self, additional: u32) -> std::result::Result<(), ()> { + self.0 + .grow(&mut self.1, additional as u64) + .map_err(|e| { + log::error!( + target: "wasm-executor", + "Failed to grow memory by {} pages: {}", + additional, + e, + ) + }) + .map(drop) } -} -fn extern_func(extern_: &Extern) -> Option<&Func> { - match extern_ { - Extern::Func(func) => Some(func), - _ => None, + fn pages(&self) -> u32 { + self.0.size(&self.1) as u32 } -} -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); + fn max_pages(&self) -> Option { + self.0.ty(&self.1).maximum().map(|p| p as _) } - store +} + +/// Wrap the given WebAssembly Instance of a wasm module with Substrate-runtime. +/// +/// This struct is a handy wrapper around a wasmtime `Instance` that provides substrate specific +/// routines. +pub struct InstanceWrapper { + instance: Instance, + /// The memory instance of the `instance`. + /// + /// It is important to make sure that we don't make any copies of this to make it easier to + /// proof + memory: Memory, + store: Store, } impl InstanceWrapper { - pub(crate) fn new( - engine: &Engine, - instance_pre: &InstancePre, - max_memory_size: Option, - ) -> Result { - let mut store = create_store(engine, max_memory_size); + pub(crate) fn new(engine: &Engine, instance_pre: &InstancePre) -> Result { + let mut store = Store::new(engine, Default::default()); let instance = instance_pre.instantiate(&mut store).map_err(|error| { WasmError::Other(format!( "failed to instantiate a new WASM module instance: {:#}", @@ -201,9 +192,10 @@ impl InstanceWrapper { 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) + let func = export + .into_func() .ok_or_else(|| Error::from(format!("Export {} is not a function", method)))?; - EntryPoint::direct(*func, &self.store).map_err(|_| { + EntryPoint::direct(func, &self.store).map_err(|_| { Error::from(format!("Exported function '{}' has invalid signature.", method)) })? }, @@ -259,7 +251,8 @@ impl InstanceWrapper { .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) + let heap_base_global = heap_base_export + .into_global() .ok_or_else(|| Error::from("__heap_base is not a global"))?; let heap_base = heap_base_global @@ -277,7 +270,7 @@ impl InstanceWrapper { None => return Ok(None), }; - let global = extern_global(&global).ok_or_else(|| format!("`{}` is not a global", name))?; + let global = global.into_global().ok_or_else(|| format!("`{}` is not a global", name))?; match global.get(&mut self.store) { Val::I32(val) => Ok(Some(Value::I32(val))), @@ -300,7 +293,8 @@ fn get_linear_memory(instance: &Instance, ctx: impl AsContextMut) -> Result Option

::Public; @@ -273,23 +273,6 @@ where format!("0x{}", HexDisplay::from(&public_key.into().into_account().as_ref())) } -/// 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 = array_bytes::hex2bytes(m.as_str())?; - }, - None => { - std::io::stdin().lock().read_to_end(&mut message)?; - if should_decode { - message = array_bytes::hex2bytes(array_bytes::hex_bytes2hex_str(&message)?)?; - } - }, - } - Ok(message) -} - /// Allows for calling $method with appropriate crypto impl. #[macro_export] macro_rules! with_crypto_scheme { diff --git a/client/cli/src/commands/verify.rs b/client/cli/src/commands/verify.rs index 82554fbf268fa..183bf507bd114 100644 --- a/client/cli/src/commands/verify.rs +++ b/client/cli/src/commands/verify.rs @@ -18,9 +18,10 @@ //! implementation of the `verify` subcommand -use crate::{error, utils, with_crypto_scheme, CryptoSchemeFlag}; +use crate::{error, params::MessageParams, utils, with_crypto_scheme, CryptoSchemeFlag}; use clap::Parser; use sp_core::crypto::{ByteArray, Ss58Codec}; +use std::io::BufRead; /// The `verify` command #[derive(Debug, Clone, Parser)] @@ -37,14 +38,9 @@ pub struct VerifyCmd { /// If not given, you will be prompted for the URI. uri: Option, - /// Message to verify, if not provided you will be prompted to - /// pass the message via STDIN - #[arg(long)] - message: Option, - - /// The message on STDIN is hex-encoded data - #[arg(long)] - hex: bool, + #[allow(missing_docs)] + #[clap(flatten)] + pub message_params: MessageParams, #[allow(missing_docs)] #[clap(flatten)] @@ -54,7 +50,20 @@ pub struct VerifyCmd { impl VerifyCmd { /// Run the command pub fn run(&self) -> error::Result<()> { - let message = utils::read_message(self.message.as_ref(), self.hex)?; + self.verify(|| std::io::stdin().lock()) + } + + /// Verify a signature for a message. + /// + /// The message can either be provided as immediate argument via CLI or otherwise read from the + /// reader created by `create_reader`. The reader will only be created in case that the message + /// is not passed as immediate. + pub(crate) fn verify(&self, create_reader: F) -> error::Result<()> + where + R: BufRead, + F: FnOnce() -> R, + { + let message = self.message_params.message_from(create_reader)?; 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 }; @@ -86,3 +95,43 @@ where Ok(()) } + +#[cfg(test)] +mod test { + use super::*; + + const ALICE: &str = "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY"; + const SIG1: &str = "0x4eb25a2285a82374888880af0024eb30c3a21ce086eae3862888d345af607f0ad6fb081312f11730932564f24a9f8ebcee2d46861413ae61307eca58db2c3e81"; + const SIG2: &str = "0x026342225155056ea797118c1c8c8b3cc002aa2020c36f4217fa3c302783a572ad3dcd38c231cbaf86cadb93984d329c963ceac0685cc1ee4c1ed50fa443a68f"; + + // Verify work with `--message` argument. + #[test] + fn verify_immediate() { + let cmd = VerifyCmd::parse_from(&["verify", SIG1, ALICE, "--message", "test message"]); + assert!(cmd.run().is_ok(), "Alice' signature should verify"); + } + + // Verify work without `--message` argument. + #[test] + fn verify_stdin() { + let cmd = VerifyCmd::parse_from(&["verify", SIG1, ALICE]); + let message = "test message"; + assert!(cmd.verify(|| message.as_bytes()).is_ok(), "Alice' signature should verify"); + } + + // Verify work with `--message` argument for hex message. + #[test] + fn verify_immediate_hex() { + let cmd = VerifyCmd::parse_from(&["verify", SIG2, ALICE, "--message", "0xaabbcc", "--hex"]); + assert!(cmd.run().is_ok(), "Alice' signature should verify"); + } + + // Verify work without `--message` argument for hex message. + #[test] + fn verify_stdin_hex() { + let cmd = VerifyCmd::parse_from(&["verify", SIG2, ALICE, "--hex"]); + assert!(cmd.verify(|| "0xaabbcc".as_bytes()).is_ok()); + assert!(cmd.verify(|| "aabbcc".as_bytes()).is_ok()); + assert!(cmd.verify(|| "0xaABBcC".as_bytes()).is_ok()); + } +} diff --git a/client/cli/src/params/message_params.rs b/client/cli/src/params/message_params.rs new file mode 100644 index 0000000000000..9f88c24dcd222 --- /dev/null +++ b/client/cli/src/params/message_params.rs @@ -0,0 +1,121 @@ +// This file is part of Substrate. + +// Copyright (C) 2023 Parity Technologies (UK) Ltd. +// SPDX-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 . + +//! Params to configure how a message should be passed into a command. + +use crate::error::Error; +use array_bytes::{hex2bytes, hex_bytes2hex_str}; +use clap::Parser; +use std::io::BufRead; + +/// Params to configure how a message should be passed into a command. +#[derive(Parser, Debug, Clone)] +pub struct MessageParams { + /// Message to process. Will be read from STDIN otherwise. + /// + /// The message is assumed to be raw bytes per default. Use `--hex` for hex input. Can + /// optionally be prefixed with `0x` in the hex case. + #[arg(long)] + message: Option, + + /// The message is hex-encoded data. + #[arg(long)] + hex: bool, +} + +impl MessageParams { + /// Produces the message by either using its immediate value or reading from stdin. + /// + /// This function should only be called once and the result cached. + pub(crate) fn message_from(&self, create_reader: F) -> Result, Error> + where + R: BufRead, + F: FnOnce() -> R, + { + let raw = match &self.message { + Some(raw) => raw.as_bytes().to_vec(), + None => { + let mut raw = vec![]; + create_reader().read_to_end(&mut raw)?; + raw + }, + }; + if self.hex { + hex2bytes(hex_bytes2hex_str(&raw)?).map_err(Into::into) + } else { + Ok(raw) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + /// Test that decoding an immediate message works. + #[test] + fn message_decode_immediate() { + for (name, input, hex, output) in test_closures() { + println!("Testing: immediate_{}", name); + let params = MessageParams { message: Some(input.into()), hex }; + let message = params.message_from(|| std::io::stdin().lock()); + + match output { + Some(output) => { + let message = message.expect(&format!("{}: should decode but did not", name)); + assert_eq!(message, output, "{}: decoded a wrong message", name); + }, + None => { + message.err().expect(&format!("{}: should not decode but did", name)); + }, + } + } + } + + /// Test that decoding a message from a stream works. + #[test] + fn message_decode_stream() { + for (name, input, hex, output) in test_closures() { + println!("Testing: stream_{}", name); + let params = MessageParams { message: None, hex }; + let message = params.message_from(|| input.as_bytes()); + + match output { + Some(output) => { + let message = message.expect(&format!("{}: should decode but did not", name)); + assert_eq!(message, output, "{}: decoded a wrong message", name); + }, + None => { + message.err().expect(&format!("{}: should not decode but did", name)); + }, + } + } + } + + /// Returns (test_name, input, hex, output). + fn test_closures() -> Vec<(&'static str, &'static str, bool, Option<&'static [u8]>)> { + vec![ + ("decode_no_hex_works", "Hello this is not hex", false, Some(b"Hello this is not hex")), + ("decode_no_hex_with_hex_string_works", "0xffffffff", false, Some(b"0xffffffff")), + ("decode_hex_works", "0x00112233", true, Some(&[0, 17, 34, 51])), + ("decode_hex_without_prefix_works", "00112233", true, Some(&[0, 17, 34, 51])), + ("decode_hex_uppercase_works", "0xaAbbCCDd", true, Some(&[170, 187, 204, 221])), + ("decode_hex_wrong_len_errors", "0x0011223", true, None), + ] + } +} diff --git a/client/cli/src/params/mod.rs b/client/cli/src/params/mod.rs index 3197deb101bcc..4ec7d1d958e8f 100644 --- a/client/cli/src/params/mod.rs +++ b/client/cli/src/params/mod.rs @@ -18,6 +18,7 @@ mod database_params; mod import_params; mod keystore_params; +mod message_params; mod network_params; mod node_key_params; mod offchain_worker_params; @@ -35,7 +36,7 @@ use sp_runtime::{ use std::{fmt::Debug, str::FromStr}; pub use crate::params::{ - database_params::*, import_params::*, keystore_params::*, network_params::*, + database_params::*, import_params::*, keystore_params::*, message_params::*, network_params::*, node_key_params::*, offchain_worker_params::*, pruning_params::*, shared_params::*, transaction_pool_params::*, }; From a1d42aaa9f52531b27f882832cca9efe370ffcb6 Mon Sep 17 00:00:00 2001 From: Roman Useinov Date: Mon, 13 Feb 2023 23:22:51 +0100 Subject: [PATCH 388/715] [Feature] Introduce storage_alias for CountedStorageMap (#13366) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [Feature] Introduce storagage_alias for CountedStorageMap * bit more dry * bit more dry * address review comments * some tests and fixes * fix ui tests * Apply suggestions from code review Co-authored-by: Bastian Köcher * compare metadata --------- Co-authored-by: parity-processbot <> Co-authored-by: Bastian Köcher --- frame/support/procedural/src/lib.rs | 6 ++ .../procedural/src/pallet/expand/storage.rs | 15 ++-- frame/support/procedural/src/storage_alias.rs | 81 ++++++++++++++++++- .../support/src/storage/types/counted_map.rs | 10 +++ frame/support/test/tests/pallet.rs | 18 ++++- .../forbid_underscore_as_prefix.stderr | 2 +- 6 files changed, 119 insertions(+), 13 deletions(-) diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index 8fa46b48d005f..67e592f4ca2db 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -69,6 +69,12 @@ fn get_cargo_env_var(version_env: &str) -> std::result::Result String { + format!("CounterFor{}", prefix) +} + /// Declares strongly-typed wrappers around codec-compatible types in storage. /// /// ## Example diff --git a/frame/support/procedural/src/pallet/expand/storage.rs b/frame/support/procedural/src/pallet/expand/storage.rs index 195a62431f279..0bb19ad6c29cd 100644 --- a/frame/support/procedural/src/pallet/expand/storage.rs +++ b/frame/support/procedural/src/pallet/expand/storage.rs @@ -15,9 +15,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::pallet::{ - parse::storage::{Metadata, QueryKind, StorageDef, StorageGenerics}, - Def, +use crate::{ + counter_prefix, + pallet::{ + parse::storage::{Metadata, QueryKind, StorageDef, StorageGenerics}, + Def, + }, }; use quote::ToTokens; use std::{collections::HashMap, ops::IndexMut}; @@ -39,12 +42,6 @@ fn counter_prefix_ident(storage_ident: &syn::Ident) -> syn::Ident { ) } -/// Generate the counter_prefix related to the storage. -/// counter_prefix is used by counted storage map. -fn counter_prefix(prefix: &str) -> String { - format!("CounterFor{}", prefix) -} - /// Check for duplicated storage prefixes. This step is necessary since users can specify an /// alternative storage prefix using the #[pallet::storage_prefix] syntax, and we need to ensure /// that the prefix specified by the user is not a duplicate of an existing one. diff --git a/frame/support/procedural/src/storage_alias.rs b/frame/support/procedural/src/storage_alias.rs index e0df0123595b9..eaf8591a1d999 100644 --- a/frame/support/procedural/src/storage_alias.rs +++ b/frame/support/procedural/src/storage_alias.rs @@ -17,6 +17,7 @@ //! Implementation of the `storage_alias` attribute macro. +use crate::counter_prefix; use frame_support_procedural_tools::generate_crate_access_2018; use proc_macro2::{Span, TokenStream}; use quote::{quote, ToTokens}; @@ -136,6 +137,7 @@ impl ToTokens for SimpleGenerics { mod storage_types { syn::custom_keyword!(StorageValue); syn::custom_keyword!(StorageMap); + syn::custom_keyword!(CountedStorageMap); syn::custom_keyword!(StorageDoubleMap); syn::custom_keyword!(StorageNMap); } @@ -168,6 +170,21 @@ enum StorageType { _trailing_comma: Option, _gt_token: Token![>], }, + CountedMap { + _kw: storage_types::CountedStorageMap, + _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![<], @@ -235,12 +252,22 @@ impl StorageType { >; } }, + Self::CountedMap { + value_ty, query_type, hasher_ty, key_ty, prefix_generics, .. + } | 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)); + let map_type = Ident::new( + match self { + Self::Map { .. } => "StorageMap", + _ => "CountedStorageMap", + }, + Span::call_site(), + ); quote! { #( #attributes )* - #visibility type #storage_name #storage_generics = #crate_::storage::types::StorageMap< + #visibility type #storage_name #storage_generics = #crate_::storage::types::#map_type< #storage_instance #prefix_generics, #hasher_ty, #key_ty, @@ -296,6 +323,7 @@ impl StorageType { match self { Self::Value { prefix, .. } | Self::Map { prefix, .. } | + Self::CountedMap { prefix, .. } | Self::NMap { prefix, .. } | Self::DoubleMap { prefix, .. } => prefix, } @@ -306,6 +334,7 @@ impl StorageType { match self { Self::Value { prefix_generics, .. } | Self::Map { prefix_generics, .. } | + Self::CountedMap { prefix_generics, .. } | Self::NMap { prefix_generics, .. } | Self::DoubleMap { prefix_generics, .. } => prefix_generics.as_ref(), } @@ -363,6 +392,22 @@ impl Parse for StorageType { _trailing_comma: input.peek(Token![,]).then(|| input.parse()).transpose()?, _gt_token: input.parse()?, }) + } else if lookahead.peek(storage_types::CountedStorageMap) { + Ok(Self::CountedMap { + _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()?, @@ -476,6 +521,7 @@ pub fn storage_alias(input: TokenStream) -> Result { input.storage_type.prefix(), input.storage_type.prefix_generics(), &input.visibility, + matches!(input.storage_type, StorageType::CountedMap { .. }), )?; let definition = input.storage_type.generate_type_declaration( @@ -511,6 +557,7 @@ fn generate_storage_instance( prefix: &SimplePath, prefix_generics: Option<&TypeGenerics>, visibility: &Visibility, + is_counted_map: bool, ) -> 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`.")) @@ -546,9 +593,37 @@ fn generate_storage_instance( 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 name_str = format!("{}_Storage_Instance", storage_name); + let name = Ident::new(&name_str, Span::call_site()); let storage_name_str = storage_name.to_string(); + let counter_code = is_counted_map.then(|| { + let counter_name = Ident::new(&counter_prefix(&name_str), Span::call_site()); + let counter_storage_name_str = counter_prefix(&storage_name_str); + + quote! { + #visibility struct #counter_name< #impl_generics >( + #crate_::sp_std::marker::PhantomData<(#type_generics)> + ) #where_clause; + + impl<#impl_generics> #crate_::traits::StorageInstance + for #counter_name< #type_generics > #where_clause + { + fn pallet_prefix() -> &'static str { + #pallet_prefix + } + + const STORAGE_PREFIX: &'static str = #counter_storage_name_str; + } + + impl<#impl_generics> #crate_::storage::types::CountedStorageMapInstance + for #name< #type_generics > #where_clause + { + type CounterPrefix = #counter_name < #type_generics >; + } + } + }); + // Implement `StorageInstance` trait. let code = quote! { #visibility struct #name< #impl_generics >( @@ -564,6 +639,8 @@ fn generate_storage_instance( const STORAGE_PREFIX: &'static str = #storage_name_str; } + + #counter_code }; Ok(StorageInstance { name, code }) diff --git a/frame/support/src/storage/types/counted_map.rs b/frame/support/src/storage/types/counted_map.rs index 3361c4093dce0..7d7d9ebcf70cf 100644 --- a/frame/support/src/storage/types/counted_map.rs +++ b/frame/support/src/storage/types/counted_map.rs @@ -543,6 +543,16 @@ mod test { 97 } } + #[crate::storage_alias] + type ExampleCountedMap = CountedStorageMap; + + #[test] + fn storage_alias_works() { + TestExternalities::default().execute_with(|| { + assert_eq!(ExampleCountedMap::count(), 0); + ExampleCountedMap::insert(3, 10); + }) + } #[test] fn test_value_query() { diff --git a/frame/support/test/tests/pallet.rs b/frame/support/test/tests/pallet.rs index c0376d5aa450f..36150b28058a7 100644 --- a/frame/support/test/tests/pallet.rs +++ b/frame/support/test/tests/pallet.rs @@ -19,7 +19,7 @@ use frame_support::{ dispatch::{ DispatchClass, DispatchInfo, GetDispatchInfo, Parameter, Pays, UnfilteredDispatchable, }, - pallet_prelude::ValueQuery, + pallet_prelude::{StorageInfoTrait, ValueQuery}, storage::unhashed, traits::{ ConstU32, GetCallName, GetStorageVersion, OnFinalize, OnGenesis, OnInitialize, @@ -1906,14 +1906,30 @@ fn assert_type_all_pallets_without_system_reversed_is_correct() { #[test] fn test_storage_alias() { + use frame_support::Twox64Concat; + #[frame_support::storage_alias] type Value where ::AccountId: From + SomeAssociation1, = StorageValue, u32, ValueQuery>; + #[frame_support::storage_alias] + type SomeCountedStorageMap + where + ::AccountId: From + SomeAssociation1, + = CountedStorageMap, Twox64Concat, u8, u32>; + TestExternalities::default().execute_with(|| { pallet::Value::::put(10); assert_eq!(10, Value::::get()); + + pallet2::SomeCountedStorageMap::::insert(10, 100); + assert_eq!(Some(100), SomeCountedStorageMap::::get(10)); + assert_eq!(1, SomeCountedStorageMap::::count()); + assert_eq!( + SomeCountedStorageMap::::storage_info(), + pallet2::SomeCountedStorageMap::::storage_info() + ); }) } 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 index 3aa517ecfa314..3b5e3e9c23cca 100644 --- 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 @@ -1,4 +1,4 @@ -error: expected one of: `StorageValue`, `StorageMap`, `StorageDoubleMap`, `StorageNMap` +error: expected one of: `StorageValue`, `StorageMap`, `CountedStorageMap`, `StorageDoubleMap`, `StorageNMap` --> tests/storage_alias_ui/forbid_underscore_as_prefix.rs:2:14 | 2 | type Ident = CustomStorage; From 0ce39208841e519920b57d3ba5a3962188c4c66c Mon Sep 17 00:00:00 2001 From: Jegor Sidorenko <5252494+jsidorenko@users.noreply.github.com> Date: Tue, 14 Feb 2023 10:19:50 +0200 Subject: [PATCH 389/715] [NFTs] Offchain mint (#13158) * Allow to mint with the pre-signed signatures * Another try * WIP: test encoder * Fix the deposits * Refactoring + tests + benchmarks * Add sp-core/runtime-benchmarks * Remove sp-core from dev deps * Enable full_crypto for benchmarks * Typo * Fix * Update frame/nfts/src/mock.rs Co-authored-by: Squirrel * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_nfts * Add docs * Add attributes into the pre-signed object & track the deposit owner for attributes * Update docs * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_nfts * Add the number of attributes provided to weights * Apply suggestions * Remove dead code * Remove Copy * Fix docs * Update frame/nfts/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * Update frame/nfts/src/lib.rs Co-authored-by: Oliver Tale-Yazdi --------- Co-authored-by: Squirrel Co-authored-by: command-bot <> Co-authored-by: Oliver Tale-Yazdi --- Cargo.lock | 1 + bin/node/runtime/src/lib.rs | 4 + frame/nfts/Cargo.toml | 6 +- frame/nfts/src/benchmarking.rs | 68 +- frame/nfts/src/common_functions.rs | 2 +- frame/nfts/src/features/attributes.rs | 81 +- frame/nfts/src/features/create_delete_item.rs | 56 + frame/nfts/src/features/metadata.rs | 21 +- frame/nfts/src/features/settings.rs | 7 + frame/nfts/src/lib.rs | 66 +- frame/nfts/src/mock.rs | 23 +- frame/nfts/src/tests.rs | 1734 ++++++++++++----- frame/nfts/src/types.rs | 24 +- frame/nfts/src/weights.rs | 424 ++-- 14 files changed, 1756 insertions(+), 761 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ad3267984563a..0c2f8518473ff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6017,6 +6017,7 @@ dependencies = [ "scale-info", "sp-core", "sp-io", + "sp-keystore", "sp-runtime", "sp-std", ] diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 8f8a7ceef3cfe..2c7969ebcd6b9 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1566,6 +1566,7 @@ impl pallet_uniques::Config for Runtime { parameter_types! { pub Features: PalletFeatures = PalletFeatures::all_enabled(); + pub const MaxAttributesPerCall: u32 = 10; } impl pallet_nfts::Config for Runtime { @@ -1586,7 +1587,10 @@ impl pallet_nfts::Config for Runtime { type ItemAttributesApprovalsLimit = ItemAttributesApprovalsLimit; type MaxTips = MaxTips; type MaxDeadlineDuration = MaxDeadlineDuration; + type MaxAttributesPerCall = MaxAttributesPerCall; type Features = Features; + type OffchainSignature = Signature; + type OffchainPublic = ::Signer; type WeightInfo = pallet_nfts::weights::SubstrateWeight; #[cfg(feature = "runtime-benchmarks")] type Helper = (); diff --git a/frame/nfts/Cargo.toml b/frame/nfts/Cargo.toml index 9e010cb557958..59aa4e091fe68 100644 --- a/frame/nfts/Cargo.toml +++ b/frame/nfts/Cargo.toml @@ -21,14 +21,13 @@ 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-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-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" } +sp-keystore = { version = "0.13.0", path = "../../primitives/keystore" } [features] default = ["std"] @@ -40,6 +39,7 @@ std = [ "log/std", "scale-info/std", "sp-core/std", + "sp-io/std", "sp-runtime/std", "sp-std/std", ] diff --git a/frame/nfts/src/benchmarking.rs b/frame/nfts/src/benchmarking.rs index a4007f6b2c133..9e724a2f63111 100644 --- a/frame/nfts/src/benchmarking.rs +++ b/frame/nfts/src/benchmarking.rs @@ -31,7 +31,11 @@ use frame_support::{ BoundedVec, }; use frame_system::RawOrigin as SystemOrigin; -use sp_runtime::traits::{Bounded, One}; +use sp_io::crypto::{sr25519_generate, sr25519_sign}; +use sp_runtime::{ + traits::{Bounded, IdentifyAccount, One}, + AccountId32, MultiSignature, MultiSigner, +}; use sp_std::prelude::*; use crate::Pallet as Nfts; @@ -148,7 +152,21 @@ fn default_item_config() -> ItemConfig { ItemConfig { settings: ItemSettings::all_enabled() } } +fn make_filled_vec(value: u16, length: usize) -> Vec { + let mut vec = vec![0u8; length]; + let mut s = Vec::from(value.to_be_bytes()); + vec.truncate(length - s.len()); + vec.append(&mut s); + vec +} + benchmarks_instance_pallet! { + where_clause { + where + T::OffchainSignature: From, + T::AccountId: From, + } + create { let collection = T::Helper::collection(0); let origin = T::CreateOrigin::try_successful_origin(&collection) @@ -439,11 +457,7 @@ benchmarks_instance_pallet! { T::Currency::make_free_balance_be(&target, DepositBalanceOf::::max_value()); let value: BoundedVec<_, _> = vec![0u8; T::ValueLimit::get() as usize].try_into().unwrap(); for i in 0..n { - let mut key = vec![0u8; T::KeyLimit::get() as usize]; - let mut s = Vec::from((i as u16).to_be_bytes()); - key.truncate(s.len()); - key.append(&mut s); - + let key = make_filled_vec(i as u16, T::KeyLimit::get() as usize); Nfts::::set_attribute( SystemOrigin::Signed(target.clone()).into(), T::Helper::collection(0), @@ -717,5 +731,47 @@ benchmarks_instance_pallet! { }.into()); } + mint_pre_signed { + let n in 0 .. T::MaxAttributesPerCall::get() as u32; + let caller_public = sr25519_generate(0.into(), None); + let caller = MultiSigner::Sr25519(caller_public).into_account().into(); + T::Currency::make_free_balance_be(&caller, DepositBalanceOf::::max_value()); + let caller_lookup = T::Lookup::unlookup(caller.clone()); + + let collection = T::Helper::collection(0); + let item = T::Helper::item(0); + assert_ok!(Nfts::::force_create( + SystemOrigin::Root.into(), + caller_lookup.clone(), + default_collection_config::() + )); + + let metadata = vec![0u8; T::StringLimit::get() as usize]; + let mut attributes = vec![]; + let attribute_value = vec![0u8; T::ValueLimit::get() as usize]; + for i in 0..n { + let attribute_key = make_filled_vec(i as u16, T::KeyLimit::get() as usize); + attributes.push((attribute_key, attribute_value.clone())); + } + let mint_data = PreSignedMint { + collection, + item, + attributes, + metadata: metadata.clone(), + only_account: None, + deadline: One::one(), + }; + let message = Encode::encode(&mint_data); + let signature = MultiSignature::Sr25519(sr25519_sign(0.into(), &caller_public, &message).unwrap()); + + let target: T::AccountId = account("target", 0, SEED); + T::Currency::make_free_balance_be(&target, DepositBalanceOf::::max_value()); + frame_system::Pallet::::set_block_number(One::one()); + }: _(SystemOrigin::Signed(target.clone()), mint_data, signature.into(), caller) + verify { + let metadata: BoundedVec<_, _> = metadata.try_into().unwrap(); + assert_last_event::(Event::ItemMetadataSet { collection, item, data: metadata }.into()); + } + impl_benchmark_test_suite!(Nfts, crate::mock::new_test_ext(), crate::mock::Test); } diff --git a/frame/nfts/src/common_functions.rs b/frame/nfts/src/common_functions.rs index 9c0faeb6b7c77..31f8a96614c6b 100644 --- a/frame/nfts/src/common_functions.rs +++ b/frame/nfts/src/common_functions.rs @@ -17,7 +17,7 @@ //! Various pieces of common functionality. -use super::*; +use crate::*; impl, I: 'static> Pallet { /// Get the owner of the item, if the item exists. diff --git a/frame/nfts/src/features/attributes.rs b/frame/nfts/src/features/attributes.rs index b25f2a60cd62d..51c75233c1d0c 100644 --- a/frame/nfts/src/features/attributes.rs +++ b/frame/nfts/src/features/attributes.rs @@ -26,6 +26,7 @@ impl, I: 'static> Pallet { namespace: AttributeNamespace, key: BoundedVec, value: BoundedVec, + depositor: T::AccountId, ) -> DispatchResult { ensure!( Self::is_pallet_feature_enabled(PalletFeature::Attributes), @@ -66,7 +67,8 @@ impl, I: 'static> Pallet { } let attribute = Attribute::::get((collection, maybe_item, &namespace, &key)); - if attribute.is_none() { + let attribute_exists = attribute.is_some(); + if !attribute_exists { collection_details.attributes.saturating_inc(); } @@ -74,6 +76,7 @@ impl, I: 'static> Pallet { attribute.map_or(AttributeDeposit { account: None, amount: Zero::zero() }, |m| m.1); let mut deposit = Zero::zero(); + // disabled DepositRequired setting only affects the CollectionOwner namespace if collection_config.is_setting_enabled(CollectionSetting::DepositRequired) || namespace != AttributeNamespace::CollectionOwner { @@ -82,33 +85,50 @@ impl, I: 'static> Pallet { .saturating_add(T::AttributeDepositBase::get()); } + let is_collection_owner_namespace = namespace == AttributeNamespace::CollectionOwner; + let is_depositor_collection_owner = + is_collection_owner_namespace && collection_details.owner == depositor; + + // NOTE: in the CollectionOwner namespace if the depositor is `None` that means the deposit + // was paid by the collection's owner. + let old_depositor = + if is_collection_owner_namespace && old_deposit.account.is_none() && attribute_exists { + Some(collection_details.owner.clone()) + } else { + old_deposit.account + }; + let depositor_has_changed = old_depositor != Some(depositor.clone()); + // NOTE: when we transfer an item, we don't move attributes in the ItemOwner namespace. // When the new owner updates the same attribute, we will update the depositor record // and return the deposit to the previous owner. - if old_deposit.account.is_some() && old_deposit.account != Some(origin.clone()) { - T::Currency::unreserve(&old_deposit.account.unwrap(), old_deposit.amount); - T::Currency::reserve(&origin, deposit)?; + if depositor_has_changed { + if let Some(old_depositor) = old_depositor { + T::Currency::unreserve(&old_depositor, old_deposit.amount); + } + T::Currency::reserve(&depositor, deposit)?; } else if deposit > old_deposit.amount { - T::Currency::reserve(&origin, deposit - old_deposit.amount)?; + T::Currency::reserve(&depositor, deposit - old_deposit.amount)?; } else if deposit < old_deposit.amount { - T::Currency::unreserve(&origin, old_deposit.amount - deposit); + T::Currency::unreserve(&depositor, old_deposit.amount - deposit); } - // NOTE: we don't track the depositor in the CollectionOwner namespace as it's always a - // collection's owner. This simplifies the collection's transfer to another owner. - let deposit_owner = match namespace { - AttributeNamespace::CollectionOwner => { - collection_details.owner_deposit.saturating_accrue(deposit); + if is_depositor_collection_owner { + if !depositor_has_changed { collection_details.owner_deposit.saturating_reduce(old_deposit.amount); - None - }, - _ => Some(origin), - }; + } + collection_details.owner_deposit.saturating_accrue(deposit); + } + let new_deposit_owner = match is_depositor_collection_owner { + true => None, + false => Some(depositor), + }; Attribute::::insert( (&collection, maybe_item, &namespace, &key), - (&value, AttributeDeposit { account: deposit_owner, amount: deposit }), + (&value, AttributeDeposit { account: new_deposit_owner, amount: deposit }), ); + Collection::::insert(collection, &collection_details); Self::deposit_event(Event::AttributeSet { collection, maybe_item, key, value, namespace }); Ok(()) @@ -188,10 +208,21 @@ impl, I: 'static> Pallet { // NOTE: if the item was previously burned, the ItemConfigOf record // might not exist. In that case, we allow to clear the attribute. let maybe_is_locked = Self::get_item_config(&collection, &item) - .map_or(false, |c| { - c.has_disabled_setting(ItemSetting::UnlockedAttributes) + .map_or(None, |c| { + Some(c.has_disabled_setting(ItemSetting::UnlockedAttributes)) }); - ensure!(!maybe_is_locked, Error::::LockedItemAttributes); + match maybe_is_locked { + Some(is_locked) => { + // when item exists, then only the collection's owner can clear that + // attribute + ensure!( + check_owner == &collection_details.owner, + Error::::NoPermission + ); + ensure!(!is_locked, Error::::LockedItemAttributes); + }, + None => (), + } }, }, _ => (), @@ -199,16 +230,16 @@ impl, I: 'static> Pallet { } collection_details.attributes.saturating_dec(); - match namespace { - AttributeNamespace::CollectionOwner => { + + match deposit.account { + Some(deposit_account) => { + T::Currency::unreserve(&deposit_account, deposit.amount); + }, + None if namespace == AttributeNamespace::CollectionOwner => { collection_details.owner_deposit.saturating_reduce(deposit.amount); T::Currency::unreserve(&collection_details.owner, deposit.amount); }, _ => (), - }; - - if let Some(deposit_account) = deposit.account { - T::Currency::unreserve(&deposit_account, deposit.amount); } Collection::::insert(collection, &collection_details); diff --git a/frame/nfts/src/features/create_delete_item.rs b/frame/nfts/src/features/create_delete_item.rs index f724fe5c63b43..63d7a540c3ae6 100644 --- a/frame/nfts/src/features/create_delete_item.rs +++ b/frame/nfts/src/features/create_delete_item.rs @@ -85,6 +85,62 @@ impl, I: 'static> Pallet { Ok(()) } + pub(crate) fn do_mint_pre_signed( + mint_to: T::AccountId, + mint_data: PreSignedMintOf, + signer: T::AccountId, + ) -> DispatchResult { + let PreSignedMint { collection, item, attributes, metadata, deadline, only_account } = + mint_data; + let metadata = Self::construct_metadata(metadata)?; + + ensure!( + attributes.len() <= T::MaxAttributesPerCall::get() as usize, + Error::::MaxAttributesLimitReached + ); + if let Some(account) = only_account { + ensure!(account == mint_to, Error::::WrongOrigin); + } + + let now = frame_system::Pallet::::block_number(); + ensure!(deadline >= now, Error::::DeadlineExpired); + + let collection_details = + Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; + ensure!(collection_details.owner == signer, Error::::NoPermission); + + let item_config = ItemConfig { settings: Self::get_default_item_settings(&collection)? }; + Self::do_mint( + collection, + item, + Some(mint_to.clone()), + mint_to.clone(), + item_config, + |_, _| Ok(()), + )?; + for (key, value) in attributes { + Self::do_set_attribute( + collection_details.owner.clone(), + collection, + Some(item), + AttributeNamespace::CollectionOwner, + Self::construct_attribute_key(key)?, + Self::construct_attribute_value(value)?, + mint_to.clone(), + )?; + } + if !metadata.len().is_zero() { + Self::do_set_item_metadata( + Some(collection_details.owner.clone()), + collection, + item, + metadata, + Some(mint_to.clone()), + )?; + } + Ok(()) + } + pub fn do_burn( collection: T::CollectionId, item: T::ItemId, diff --git a/frame/nfts/src/features/metadata.rs b/frame/nfts/src/features/metadata.rs index 272b2247426d6..c4d355f1922fc 100644 --- a/frame/nfts/src/features/metadata.rs +++ b/frame/nfts/src/features/metadata.rs @@ -60,14 +60,16 @@ impl, I: 'static> Pallet { .saturating_add(T::MetadataDepositBase::get()); } - // the previous deposit was taken from the item's owner - if old_deposit.account.is_some() && maybe_depositor.is_none() { - T::Currency::unreserve(&old_deposit.account.unwrap(), old_deposit.amount); - T::Currency::reserve(&collection_details.owner, deposit)?; + let depositor = maybe_depositor.clone().unwrap_or(collection_details.owner.clone()); + let old_depositor = old_deposit.account.unwrap_or(collection_details.owner.clone()); + + if depositor != old_depositor { + T::Currency::unreserve(&old_depositor, old_deposit.amount); + T::Currency::reserve(&depositor, deposit)?; } else if deposit > old_deposit.amount { - T::Currency::reserve(&collection_details.owner, deposit - old_deposit.amount)?; + T::Currency::reserve(&depositor, deposit - old_deposit.amount)?; } else if deposit < old_deposit.amount { - T::Currency::unreserve(&collection_details.owner, old_deposit.amount - deposit); + T::Currency::unreserve(&depositor, old_deposit.amount - deposit); } if maybe_depositor.is_none() { @@ -191,4 +193,11 @@ impl, I: 'static> Pallet { Ok(()) }) } + + /// A helper method to construct metadata. + pub fn construct_metadata( + metadata: Vec, + ) -> Result, DispatchError> { + Ok(BoundedVec::try_from(metadata).map_err(|_| Error::::IncorrectMetadata)?) + } } diff --git a/frame/nfts/src/features/settings.rs b/frame/nfts/src/features/settings.rs index 5f408ed183c35..7c29711094112 100644 --- a/frame/nfts/src/features/settings.rs +++ b/frame/nfts/src/features/settings.rs @@ -96,6 +96,13 @@ impl, I: 'static> Pallet { Ok(config) } + pub(crate) fn get_default_item_settings( + collection_id: &T::CollectionId, + ) -> Result { + let collection_config = Self::get_collection_config(collection_id)?; + Ok(collection_config.mint_settings.default_item_settings) + } + pub(crate) fn is_pallet_feature_enabled(feature: PalletFeature) -> bool { let features = T::Features::get(); return features.is_enabled(feature) diff --git a/frame/nfts/src/lib.rs b/frame/nfts/src/lib.rs index 8f24c8dcd6e98..cec5ea7ffc09f 100644 --- a/frame/nfts/src/lib.rs +++ b/frame/nfts/src/lib.rs @@ -67,6 +67,7 @@ pub mod pallet { use super::*; use frame_support::{pallet_prelude::*, traits::ExistenceRequirement}; use frame_system::pallet_prelude::*; + use sp_runtime::traits::{IdentifyAccount, Verify}; #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] @@ -167,10 +168,24 @@ pub mod pallet { #[pallet::constant] type MaxDeadlineDuration: Get<::BlockNumber>; + /// The max number of attributes a user could set per call. + #[pallet::constant] + type MaxAttributesPerCall: Get; + /// Disables some of pallet's features. #[pallet::constant] type Features: Get; + /// Off-Chain signature type. + /// + /// Can verify whether an `Self::OffchainPublic` created a signature. + type OffchainSignature: Verify + Parameter; + + /// Off-Chain public key. + /// + /// Must identify as an on-chain `Self::AccountId`. + type OffchainPublic: IdentifyAccount; + #[cfg(feature = "runtime-benchmarks")] /// A set of helper functions for benchmarking. type Helper: BenchmarkHelper; @@ -591,6 +606,14 @@ pub mod pallet { AlreadyClaimed, /// The provided data is incorrect. IncorrectData, + /// The extrinsic was sent by the wrong origin. + WrongOrigin, + /// The provided signature is incorrect. + WrongSignature, + /// The provided metadata might be too long. + IncorrectMetadata, + /// Can't set more attributes per one call. + MaxAttributesLimitReached, } #[pallet::call] @@ -742,10 +765,8 @@ pub mod pallet { ) -> DispatchResult { let caller = ensure_signed(origin)?; let mint_to = T::Lookup::lookup(mint_to)?; - - let collection_config = Self::get_collection_config(&collection)?; - let item_settings = collection_config.mint_settings.default_item_settings; - let item_config = ItemConfig { settings: item_settings }; + let item_config = + ItemConfig { settings: Self::get_default_item_settings(&collection)? }; Self::do_mint( collection, @@ -1325,7 +1346,15 @@ pub mod pallet { value: BoundedVec, ) -> DispatchResult { let origin = ensure_signed(origin)?; - Self::do_set_attribute(origin, collection, maybe_item, namespace, key, value) + Self::do_set_attribute( + origin.clone(), + collection, + maybe_item, + namespace, + key, + value, + origin, + ) } /// Force-set an attribute for a collection or item. @@ -1768,6 +1797,33 @@ pub mod pallet { witness_price, ) } + + /// Mint an item by providing the pre-signed approval. + /// + /// Origin must be Signed. + /// + /// - `mint_data`: The pre-signed approval that consists of the information about the item, + /// its metadata, attributes, who can mint it (`None` for anyone) and until what block + /// number. + /// - `signature`: The signature of the `data` object. + /// - `signer`: The `data` object's signer. Should be an owner of the collection. + /// + /// Emits `Issued` on success. + /// Emits `AttributeSet` if the attributes were provided. + /// Emits `ItemMetadataSet` if the metadata was not empty. + #[pallet::call_index(37)] + #[pallet::weight(T::WeightInfo::mint_pre_signed(mint_data.attributes.len() as u32))] + pub fn mint_pre_signed( + origin: OriginFor, + mint_data: PreSignedMintOf, + signature: T::OffchainSignature, + signer: T::AccountId, + ) -> DispatchResult { + let origin = ensure_signed(origin)?; + let msg = Encode::encode(&mint_data); + ensure!(signature.verify(&*msg, &signer), Error::::WrongSignature); + Self::do_mint_pre_signed(origin, mint_data, signer) + } } } diff --git a/frame/nfts/src/mock.rs b/frame/nfts/src/mock.rs index f814b209d5f78..d0ef3cf0b12c6 100644 --- a/frame/nfts/src/mock.rs +++ b/frame/nfts/src/mock.rs @@ -25,10 +25,13 @@ use frame_support::{ traits::{AsEnsureOriginWithArg, ConstU32, ConstU64}, }; use sp_core::H256; +use sp_keystore::{testing::KeyStore, KeystoreExt}; use sp_runtime::{ testing::Header, - traits::{BlakeTwo256, IdentityLookup}, + traits::{BlakeTwo256, IdentifyAccount, IdentityLookup, Verify}, + MultiSignature, }; +use std::sync::Arc; type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; type Block = frame_system::mocking::MockBlock; @@ -45,6 +48,10 @@ construct_runtime!( } ); +pub type Signature = MultiSignature; +pub type AccountPublic = ::Signer; +pub type AccountId = ::AccountId; + impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); @@ -55,7 +62,7 @@ impl frame_system::Config for Test { type BlockNumber = u64; type Hash = H256; type Hashing = BlakeTwo256; - type AccountId = u64; + type AccountId = AccountId; type Lookup = IdentityLookup; type Header = Header; type RuntimeEvent = RuntimeEvent; @@ -93,8 +100,8 @@ impl Config for Test { type CollectionId = u32; type ItemId = u32; type Currency = Balances; - type CreateOrigin = AsEnsureOriginWithArg>; - type ForceOrigin = frame_system::EnsureRoot; + type CreateOrigin = AsEnsureOriginWithArg>; + type ForceOrigin = frame_system::EnsureRoot; type Locker = (); type CollectionDeposit = ConstU64<2>; type ItemDeposit = ConstU64<1>; @@ -108,7 +115,13 @@ impl Config for Test { type ItemAttributesApprovalsLimit = ConstU32<2>; type MaxTips = ConstU32<10>; type MaxDeadlineDuration = ConstU64<10000>; + type MaxAttributesPerCall = ConstU32<2>; type Features = Features; + /// Off-chain = signature On-chain - therefore no conversion needed. + /// It needs to be From for benchmarking. + type OffchainSignature = Signature; + /// Using `AccountPublic` here makes it trivial to convert to `AccountId` via `into_account()`. + type OffchainPublic = AccountPublic; type WeightInfo = (); #[cfg(feature = "runtime-benchmarks")] type Helper = (); @@ -117,7 +130,9 @@ impl Config for Test { pub(crate) fn new_test_ext() -> sp_io::TestExternalities { let t = frame_system::GenesisConfig::default().build_storage::().unwrap(); + let keystore = KeyStore::new(); let mut ext = sp_io::TestExternalities::new(t); + ext.register_extension(KeystoreExt(Arc::new(keystore))); ext.execute_with(|| System::set_block_number(1)); ext } diff --git a/frame/nfts/src/tests.rs b/frame/nfts/src/tests.rs index ebbba33b04fa2..fce9073af2d02 100644 --- a/frame/nfts/src/tests.rs +++ b/frame/nfts/src/tests.rs @@ -28,10 +28,17 @@ use frame_support::{ }, }; use pallet_balances::Error as BalancesError; -use sp_core::bounded::BoundedVec; +use sp_core::{bounded::BoundedVec, Pair}; +use sp_runtime::{traits::IdentifyAccount, MultiSignature, MultiSigner}; use sp_std::prelude::*; -fn items() -> Vec<(u64, u32, u32)> { +type AccountIdOf = ::AccountId; + +fn account(id: u8) -> AccountIdOf { + [id; 32].into() +} + +fn items() -> Vec<(AccountIdOf, u32, u32)> { let mut r: Vec<_> = Account::::iter().map(|x| x.0).collect(); r.sort(); let mut s: Vec<_> = Item::::iter().map(|x| (x.2.owner, x.0, x.1)).collect(); @@ -56,7 +63,7 @@ fn items() -> Vec<(u64, u32, u32)> { r } -fn collections() -> Vec<(u64, u32)> { +fn collections() -> Vec<(AccountIdOf, u32)> { let mut r: Vec<_> = CollectionAccount::::iter().map(|x| (x.0, x.1)).collect(); r.sort(); let mut s: Vec<_> = Collection::::iter().map(|x| (x.1.owner, x.0)).collect(); @@ -71,22 +78,26 @@ macro_rules! bvec { } } -fn attributes(collection: u32) -> Vec<(Option, AttributeNamespace, Vec, Vec)> { +fn attributes( + collection: u32, +) -> Vec<(Option, AttributeNamespace>, Vec, Vec)> { let mut s: Vec<_> = Attribute::::iter_prefix((collection,)) .map(|(k, v)| (k.0, k.1, k.2.into(), v.0.into())) .collect(); - s.sort_by_key(|k: &(Option, AttributeNamespace, Vec, Vec)| k.0); - s.sort_by_key(|k: &(Option, AttributeNamespace, Vec, Vec)| k.2.clone()); + s.sort_by_key(|k: &(Option, AttributeNamespace>, Vec, Vec)| k.0); + s.sort_by_key(|k: &(Option, AttributeNamespace>, Vec, Vec)| { + k.2.clone() + }); s } -fn approvals(collection_id: u32, item_id: u32) -> Vec<(u64, Option)> { +fn approvals(collection_id: u32, item_id: u32) -> Vec<(AccountIdOf, Option)> { let item = Item::::get(collection_id, item_id).unwrap(); let s: Vec<_> = item.approvals.into_iter().collect(); s } -fn item_attributes_approvals(collection_id: u32, item_id: u32) -> Vec { +fn item_attributes_approvals(collection_id: u32, item_id: u32) -> Vec> { let approvals = ItemAttributesApprovalsOf::::get(collection_id, item_id); let s: Vec<_> = approvals.into_iter().collect(); s @@ -144,60 +155,83 @@ fn basic_setup_works() { #[test] fn basic_minting_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Nfts::force_create(RuntimeOrigin::root(), 1, default_collection_config())); - assert_eq!(collections(), vec![(1, 0)]); - assert_ok!(Nfts::mint(RuntimeOrigin::signed(1), 0, 42, 1, None)); - assert_eq!(items(), vec![(1, 0, 42)]); - - assert_ok!(Nfts::force_create(RuntimeOrigin::root(), 2, default_collection_config())); - assert_eq!(collections(), vec![(1, 0), (2, 1)]); - assert_ok!(Nfts::mint(RuntimeOrigin::signed(2), 1, 69, 1, None)); - // assert_ok!(Nfts::force_mint(RuntimeOrigin::signed(2), 1, 69, 1, default_item_config())); - assert_eq!(items(), vec![(1, 0, 42), (1, 1, 69)]); + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + account(1), + default_collection_config() + )); + assert_eq!(collections(), vec![(account(1), 0)]); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 42, account(1), None)); + assert_eq!(items(), vec![(account(1), 0, 42)]); + + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + account(2), + default_collection_config() + )); + assert_eq!(collections(), vec![(account(1), 0), (account(2), 1)]); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(2)), 1, 69, account(1), None)); + assert_eq!(items(), vec![(account(1), 0, 42), (account(1), 1, 69)]); }); } #[test] fn lifecycle_should_work() { new_test_ext().execute_with(|| { - Balances::make_free_balance_be(&1, 100); - Balances::make_free_balance_be(&2, 100); + Balances::make_free_balance_be(&account(1), 100); + Balances::make_free_balance_be(&account(2), 100); assert_ok!(Nfts::create( - RuntimeOrigin::signed(1), - 1, + RuntimeOrigin::signed(account(1)), + account(1), collection_config_with_all_settings_enabled() )); - assert_eq!(Balances::reserved_balance(&1), 2); - assert_eq!(collections(), vec![(1, 0)]); - assert_ok!(Nfts::set_collection_metadata(RuntimeOrigin::signed(1), 0, bvec![0, 0])); - assert_eq!(Balances::reserved_balance(&1), 5); + assert_eq!(Balances::reserved_balance(&account(1)), 2); + assert_eq!(collections(), vec![(account(1), 0)]); + assert_ok!(Nfts::set_collection_metadata( + RuntimeOrigin::signed(account(1)), + 0, + bvec![0, 0] + )); + assert_eq!(Balances::reserved_balance(&account(1)), 5); assert!(CollectionMetadataOf::::contains_key(0)); - assert_ok!(Nfts::force_mint(RuntimeOrigin::signed(1), 0, 42, 10, default_item_config())); - assert_eq!(Balances::reserved_balance(&1), 6); - assert_ok!(Nfts::force_mint(RuntimeOrigin::signed(1), 0, 69, 20, default_item_config())); - assert_eq!(Balances::reserved_balance(&1), 7); - assert_ok!(Nfts::mint(RuntimeOrigin::signed(1), 0, 70, 1, None)); - assert_eq!(items(), vec![(1, 0, 70), (10, 0, 42), (20, 0, 69)]); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(account(1)), + 0, + 42, + account(10), + default_item_config() + )); + assert_eq!(Balances::reserved_balance(&account(1)), 6); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(account(1)), + 0, + 69, + account(20), + default_item_config() + )); + assert_eq!(Balances::reserved_balance(&account(1)), 7); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 70, account(1), None)); + assert_eq!(items(), vec![(account(1), 0, 70), (account(10), 0, 42), (account(20), 0, 69)]); assert_eq!(Collection::::get(0).unwrap().items, 3); assert_eq!(Collection::::get(0).unwrap().item_metadatas, 0); - assert_eq!(Balances::reserved_balance(&2), 0); - assert_ok!(Nfts::transfer(RuntimeOrigin::signed(1), 0, 70, 2)); - assert_eq!(Balances::reserved_balance(&2), 1); + assert_eq!(Balances::reserved_balance(&account(2)), 0); + assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(1)), 0, 70, account(2))); + assert_eq!(Balances::reserved_balance(&account(2)), 1); - assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(1), 0, 42, bvec![42, 42])); - assert_eq!(Balances::reserved_balance(&1), 10); + assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(account(1)), 0, 42, bvec![42, 42])); + assert_eq!(Balances::reserved_balance(&account(1)), 10); assert!(ItemMetadataOf::::contains_key(0, 42)); - assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(1), 0, 69, bvec![69, 69])); - assert_eq!(Balances::reserved_balance(&1), 13); + assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(account(1)), 0, 69, bvec![69, 69])); + assert_eq!(Balances::reserved_balance(&account(1)), 13); assert!(ItemMetadataOf::::contains_key(0, 69)); let w = Nfts::get_destroy_witness(&0).unwrap(); assert_eq!(w.items, 3); assert_eq!(w.item_metadatas, 2); - assert_ok!(Nfts::destroy(RuntimeOrigin::signed(1), 0, w)); - assert_eq!(Balances::reserved_balance(&1), 0); + assert_ok!(Nfts::destroy(RuntimeOrigin::signed(account(1)), 0, w)); + assert_eq!(Balances::reserved_balance(&account(1)), 0); assert!(!Collection::::contains_key(0)); assert!(!CollectionConfigOf::::contains_key(0)); @@ -214,31 +248,38 @@ 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); + Balances::make_free_balance_be(&account(1), 100); assert_ok!(Nfts::create( - RuntimeOrigin::signed(1), - 1, + RuntimeOrigin::signed(account(1)), + account(1), collection_config_with_all_settings_enabled() )); let w = Collection::::get(0).unwrap().destroy_witness(); - assert_ok!(Nfts::mint(RuntimeOrigin::signed(1), 0, 42, 1, None)); - assert_noop!(Nfts::destroy(RuntimeOrigin::signed(1), 0, w), Error::::BadWitness); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 42, account(1), None)); + assert_noop!( + Nfts::destroy(RuntimeOrigin::signed(account(1)), 0, w), + Error::::BadWitness + ); }); } #[test] fn mint_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Nfts::force_create(RuntimeOrigin::root(), 1, default_collection_config())); - assert_ok!(Nfts::mint(RuntimeOrigin::signed(1), 0, 42, 1, None)); - assert_eq!(Nfts::owner(0, 42).unwrap(), 1); - assert_eq!(collections(), vec![(1, 0)]); - assert_eq!(items(), vec![(1, 0, 42)]); + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + account(1), + default_collection_config() + )); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 42, account(1), None)); + assert_eq!(Nfts::owner(0, 42).unwrap(), account(1)); + assert_eq!(collections(), vec![(account(1), 0)]); + assert_eq!(items(), vec![(account(1), 0, 42)]); // validate minting start and end settings assert_ok!(Nfts::update_mint_settings( - RuntimeOrigin::signed(1), + RuntimeOrigin::signed(account(1)), 0, MintSettings { start_block: Some(2), @@ -250,55 +291,71 @@ fn mint_should_work() { System::set_block_number(1); assert_noop!( - Nfts::mint(RuntimeOrigin::signed(2), 0, 43, 1, None), + Nfts::mint(RuntimeOrigin::signed(account(2)), 0, 43, account(1), None), Error::::MintNotStarted ); System::set_block_number(4); assert_noop!( - Nfts::mint(RuntimeOrigin::signed(2), 0, 43, 1, None), + Nfts::mint(RuntimeOrigin::signed(account(2)), 0, 43, account(1), None), Error::::MintEnded ); // validate price assert_ok!(Nfts::update_mint_settings( - RuntimeOrigin::signed(1), + RuntimeOrigin::signed(account(1)), 0, MintSettings { mint_type: MintType::Public, price: Some(1), ..Default::default() } )); - Balances::make_free_balance_be(&2, 100); - assert_ok!(Nfts::mint(RuntimeOrigin::signed(2), 0, 43, 2, None)); - assert_eq!(Balances::total_balance(&2), 99); + Balances::make_free_balance_be(&account(2), 100); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(2)), 0, 43, account(2), None)); + assert_eq!(Balances::total_balance(&account(2)), 99); // validate types - assert_ok!(Nfts::force_create(RuntimeOrigin::root(), 1, default_collection_config())); + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + account(1), + default_collection_config() + )); assert_ok!(Nfts::update_mint_settings( - RuntimeOrigin::signed(1), + RuntimeOrigin::signed(account(1)), 1, MintSettings { mint_type: MintType::HolderOf(0), ..Default::default() } )); assert_noop!( - Nfts::mint(RuntimeOrigin::signed(3), 1, 42, 3, None), + Nfts::mint(RuntimeOrigin::signed(account(3)), 1, 42, account(3), None), Error::::BadWitness ); assert_noop!( - Nfts::mint(RuntimeOrigin::signed(2), 1, 42, 2, None), + Nfts::mint(RuntimeOrigin::signed(account(2)), 1, 42, account(2), None), Error::::BadWitness ); assert_noop!( - Nfts::mint(RuntimeOrigin::signed(2), 1, 42, 2, Some(MintWitness { owner_of_item: 42 })), + Nfts::mint( + RuntimeOrigin::signed(account(2)), + 1, + 42, + account(2), + Some(MintWitness { owner_of_item: 42 }) + ), Error::::BadWitness ); assert_ok!(Nfts::mint( - RuntimeOrigin::signed(2), + RuntimeOrigin::signed(account(2)), 1, 42, - 2, + account(2), Some(MintWitness { owner_of_item: 43 }) )); // can't mint twice assert_noop!( - Nfts::mint(RuntimeOrigin::signed(2), 1, 46, 2, Some(MintWitness { owner_of_item: 43 })), + Nfts::mint( + RuntimeOrigin::signed(account(2)), + 1, + 46, + account(2), + Some(MintWitness { owner_of_item: 43 }) + ), Error::::AlreadyClaimed ); }); @@ -307,33 +364,55 @@ fn mint_should_work() { #[test] fn transfer_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Nfts::force_create(RuntimeOrigin::root(), 1, default_collection_config())); - assert_ok!(Nfts::force_mint(RuntimeOrigin::signed(1), 0, 42, 2, default_item_config())); + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + account(1), + default_collection_config() + )); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(account(1)), + 0, + 42, + account(2), + default_item_config() + )); - assert_ok!(Nfts::transfer(RuntimeOrigin::signed(2), 0, 42, 3)); - assert_eq!(items(), vec![(3, 0, 42)]); + assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(2)), 0, 42, account(3))); + assert_eq!(items(), vec![(account(3), 0, 42)]); assert_noop!( - Nfts::transfer(RuntimeOrigin::signed(2), 0, 42, 4), + Nfts::transfer(RuntimeOrigin::signed(account(2)), 0, 42, account(4)), Error::::NoPermission ); - assert_ok!(Nfts::approve_transfer(RuntimeOrigin::signed(3), 0, 42, 2, None)); - assert_ok!(Nfts::transfer(RuntimeOrigin::signed(2), 0, 42, 4)); + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(account(3)), + 0, + 42, + account(2), + None + )); + assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(2)), 0, 42, account(4))); // validate we can't transfer non-transferable items let collection_id = 1; assert_ok!(Nfts::force_create( RuntimeOrigin::root(), - 1, + account(1), collection_config_from_disabled_settings( CollectionSetting::TransferableItems | CollectionSetting::DepositRequired ) )); - assert_ok!(Nfts::force_mint(RuntimeOrigin::signed(1), 1, 1, 42, default_item_config())); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(account(1)), + 1, + 1, + account(42), + default_item_config() + )); assert_noop!( - Nfts::transfer(RuntimeOrigin::signed(1), collection_id, 42, 3,), + Nfts::transfer(RuntimeOrigin::signed(account(1)), collection_id, 42, account(3)), Error::::ItemsNonTransferable ); }); @@ -342,19 +421,26 @@ fn transfer_should_work() { #[test] fn locking_transfer_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Nfts::force_create(RuntimeOrigin::root(), 1, default_collection_config())); - assert_ok!(Nfts::mint(RuntimeOrigin::signed(1), 0, 42, 1, None)); - assert_ok!(Nfts::lock_item_transfer(RuntimeOrigin::signed(1), 0, 42)); - assert_noop!(Nfts::transfer(RuntimeOrigin::signed(1), 0, 42, 2), Error::::ItemLocked); + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + account(1), + default_collection_config() + )); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 42, account(1), None)); + assert_ok!(Nfts::lock_item_transfer(RuntimeOrigin::signed(account(1)), 0, 42)); + assert_noop!( + Nfts::transfer(RuntimeOrigin::signed(account(1)), 0, 42, account(2)), + Error::::ItemLocked + ); - assert_ok!(Nfts::unlock_item_transfer(RuntimeOrigin::signed(1), 0, 42)); + assert_ok!(Nfts::unlock_item_transfer(RuntimeOrigin::signed(account(1)), 0, 42)); assert_ok!(Nfts::lock_collection( - RuntimeOrigin::signed(1), + RuntimeOrigin::signed(account(1)), 0, CollectionSettings::from_disabled(CollectionSetting::TransferableItems.into()) )); assert_noop!( - Nfts::transfer(RuntimeOrigin::signed(1), 0, 42, 2), + Nfts::transfer(RuntimeOrigin::signed(account(1)), 0, 42, account(2)), Error::::ItemsNonTransferable ); @@ -363,99 +449,116 @@ fn locking_transfer_should_work() { 0, collection_config_with_all_settings_enabled(), )); - assert_ok!(Nfts::transfer(RuntimeOrigin::signed(1), 0, 42, 2)); + assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(1)), 0, 42, account(2))); }); } #[test] fn origin_guards_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Nfts::force_create(RuntimeOrigin::root(), 1, default_collection_config())); - assert_ok!(Nfts::mint(RuntimeOrigin::signed(1), 0, 42, 1, None)); + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + account(1), + default_collection_config() + )); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 42, account(1), None)); - Balances::make_free_balance_be(&2, 100); - assert_ok!(Nfts::set_accept_ownership(RuntimeOrigin::signed(2), Some(0))); + Balances::make_free_balance_be(&account(2), 100); + assert_ok!(Nfts::set_accept_ownership(RuntimeOrigin::signed(account(2)), Some(0))); assert_noop!( - Nfts::transfer_ownership(RuntimeOrigin::signed(2), 0, 2), + Nfts::transfer_ownership(RuntimeOrigin::signed(account(2)), 0, account(2)), Error::::NoPermission ); assert_noop!( - Nfts::set_team(RuntimeOrigin::signed(2), 0, 2, 2, 2), + Nfts::set_team( + RuntimeOrigin::signed(account(2)), + 0, + account(2), + account(2), + account(2), + ), Error::::NoPermission ); assert_noop!( - Nfts::lock_item_transfer(RuntimeOrigin::signed(2), 0, 42), + Nfts::lock_item_transfer(RuntimeOrigin::signed(account(2)), 0, 42), Error::::NoPermission ); assert_noop!( - Nfts::unlock_item_transfer(RuntimeOrigin::signed(2), 0, 42), + Nfts::unlock_item_transfer(RuntimeOrigin::signed(account(2)), 0, 42), Error::::NoPermission ); assert_noop!( - Nfts::mint(RuntimeOrigin::signed(2), 0, 69, 2, None), + Nfts::mint(RuntimeOrigin::signed(account(2)), 0, 69, account(2), None), Error::::NoPermission ); assert_noop!( - Nfts::burn(RuntimeOrigin::signed(2), 0, 42, None), + Nfts::burn(RuntimeOrigin::signed(account(2)), 0, 42, None), Error::::NoPermission ); let w = Nfts::get_destroy_witness(&0).unwrap(); - assert_noop!(Nfts::destroy(RuntimeOrigin::signed(2), 0, w), Error::::NoPermission); + assert_noop!( + Nfts::destroy(RuntimeOrigin::signed(account(2)), 0, w), + Error::::NoPermission + ); }); } #[test] fn transfer_owner_should_work() { new_test_ext().execute_with(|| { - Balances::make_free_balance_be(&1, 100); - Balances::make_free_balance_be(&2, 100); - Balances::make_free_balance_be(&3, 100); + Balances::make_free_balance_be(&account(1), 100); + Balances::make_free_balance_be(&account(2), 100); + Balances::make_free_balance_be(&account(3), 100); assert_ok!(Nfts::create( - RuntimeOrigin::signed(1), - 1, + RuntimeOrigin::signed(account(1)), + account(1), collection_config_with_all_settings_enabled() )); - assert_eq!(collections(), vec![(1, 0)]); + assert_eq!(collections(), vec![(account(1), 0)]); assert_noop!( - Nfts::transfer_ownership(RuntimeOrigin::signed(1), 0, 2), + Nfts::transfer_ownership(RuntimeOrigin::signed(account(1)), 0, account(2)), Error::::Unaccepted ); - assert_ok!(Nfts::set_accept_ownership(RuntimeOrigin::signed(2), Some(0))); - assert_ok!(Nfts::transfer_ownership(RuntimeOrigin::signed(1), 0, 2)); + assert_ok!(Nfts::set_accept_ownership(RuntimeOrigin::signed(account(2)), Some(0))); + assert_ok!(Nfts::transfer_ownership(RuntimeOrigin::signed(account(1)), 0, account(2))); - 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); - assert_eq!(Balances::reserved_balance(&2), 2); + assert_eq!(collections(), vec![(account(2), 0)]); + assert_eq!(Balances::total_balance(&account(1)), 98); + assert_eq!(Balances::total_balance(&account(2)), 102); + assert_eq!(Balances::reserved_balance(&account(1)), 0); + assert_eq!(Balances::reserved_balance(&account(2)), 2); - assert_ok!(Nfts::set_accept_ownership(RuntimeOrigin::signed(1), Some(0))); + assert_ok!(Nfts::set_accept_ownership(RuntimeOrigin::signed(account(1)), Some(0))); assert_noop!( - Nfts::transfer_ownership(RuntimeOrigin::signed(1), 0, 1), + Nfts::transfer_ownership(RuntimeOrigin::signed(account(1)), 0, account(1)), Error::::NoPermission ); // Mint and set metadata now and make sure that deposit gets transferred back. - assert_ok!(Nfts::set_collection_metadata(RuntimeOrigin::signed(2), 0, bvec![0u8; 20])); - assert_ok!(Nfts::mint(RuntimeOrigin::signed(1), 0, 42, 1, None)); - assert_eq!(Balances::reserved_balance(&1), 1); - assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(2), 0, 42, bvec![0u8; 20])); - assert_ok!(Nfts::set_accept_ownership(RuntimeOrigin::signed(3), Some(0))); - assert_ok!(Nfts::transfer_ownership(RuntimeOrigin::signed(2), 0, 3)); - assert_eq!(collections(), vec![(3, 0)]); - assert_eq!(Balances::total_balance(&2), 58); - assert_eq!(Balances::total_balance(&3), 144); - assert_eq!(Balances::reserved_balance(&2), 0); - assert_eq!(Balances::reserved_balance(&3), 44); - - assert_ok!(Nfts::transfer(RuntimeOrigin::signed(1), 0, 42, 2)); - assert_eq!(Balances::reserved_balance(&1), 0); - assert_eq!(Balances::reserved_balance(&2), 1); + assert_ok!(Nfts::set_collection_metadata( + RuntimeOrigin::signed(account(2)), + 0, + bvec![0u8; 20], + )); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 42, account(1), None)); + assert_eq!(Balances::reserved_balance(&account(1)), 1); + assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(account(2)), 0, 42, bvec![0u8; 20])); + assert_ok!(Nfts::set_accept_ownership(RuntimeOrigin::signed(account(3)), Some(0))); + assert_ok!(Nfts::transfer_ownership(RuntimeOrigin::signed(account(2)), 0, account(3))); + assert_eq!(collections(), vec![(account(3), 0)]); + assert_eq!(Balances::total_balance(&account(2)), 58); + assert_eq!(Balances::total_balance(&account(3)), 144); + assert_eq!(Balances::reserved_balance(&account(2)), 0); + assert_eq!(Balances::reserved_balance(&account(3)), 44); + + assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(1)), 0, 42, account(2))); + assert_eq!(Balances::reserved_balance(&account(1)), 0); + assert_eq!(Balances::reserved_balance(&account(2)), 1); // 2's acceptance from before is reset when it became an owner, so it cannot be transferred // without a fresh acceptance. assert_noop!( - Nfts::transfer_ownership(RuntimeOrigin::signed(3), 0, 2), + Nfts::transfer_ownership(RuntimeOrigin::signed(account(3)), 0, account(2)), Error::::Unaccepted ); }); @@ -464,14 +567,24 @@ fn transfer_owner_should_work() { #[test] fn set_team_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Nfts::force_create(RuntimeOrigin::root(), 1, default_collection_config())); - assert_ok!(Nfts::set_team(RuntimeOrigin::signed(1), 0, 2, 3, 4)); - - assert_ok!(Nfts::mint(RuntimeOrigin::signed(2), 0, 42, 2, None)); - assert_ok!(Nfts::lock_item_transfer(RuntimeOrigin::signed(4), 0, 42)); - assert_ok!(Nfts::unlock_item_transfer(RuntimeOrigin::signed(4), 0, 42)); - assert_ok!(Nfts::transfer(RuntimeOrigin::signed(3), 0, 42, 3)); - assert_ok!(Nfts::burn(RuntimeOrigin::signed(3), 0, 42, None)); + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + account(1), + default_collection_config(), + )); + assert_ok!(Nfts::set_team( + RuntimeOrigin::signed(account(1)), + 0, + account(2), + account(3), + account(4), + )); + + assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(2)), 0, 42, account(2), None)); + assert_ok!(Nfts::lock_item_transfer(RuntimeOrigin::signed(account(4)), 0, 42)); + assert_ok!(Nfts::unlock_item_transfer(RuntimeOrigin::signed(account(4)), 0, 42)); + assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(3)), 0, 42, account(3))); + assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(3)), 0, 42, None)); }); } @@ -480,69 +593,85 @@ fn set_collection_metadata_should_work() { new_test_ext().execute_with(|| { // Cannot add metadata to unknown item assert_noop!( - Nfts::set_collection_metadata(RuntimeOrigin::signed(1), 0, bvec![0u8; 20]), + Nfts::set_collection_metadata(RuntimeOrigin::signed(account(1)), 0, bvec![0u8; 20]), Error::::NoConfig, ); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), - 1, + account(1), collection_config_with_all_settings_enabled() )); // Cannot add metadata to unowned item assert_noop!( - Nfts::set_collection_metadata(RuntimeOrigin::signed(2), 0, bvec![0u8; 20]), + Nfts::set_collection_metadata(RuntimeOrigin::signed(account(2)), 0, bvec![0u8; 20]), Error::::NoPermission, ); // Successfully add metadata and take deposit - Balances::make_free_balance_be(&1, 30); - assert_ok!(Nfts::set_collection_metadata(RuntimeOrigin::signed(1), 0, bvec![0u8; 20])); - assert_eq!(Balances::free_balance(&1), 9); + Balances::make_free_balance_be(&account(1), 30); + assert_ok!(Nfts::set_collection_metadata( + RuntimeOrigin::signed(account(1)), + 0, + bvec![0u8; 20] + )); + assert_eq!(Balances::free_balance(&account(1)), 9); assert!(CollectionMetadataOf::::contains_key(0)); // Force origin works, too. assert_ok!(Nfts::set_collection_metadata(RuntimeOrigin::root(), 0, bvec![0u8; 18])); // Update deposit - assert_ok!(Nfts::set_collection_metadata(RuntimeOrigin::signed(1), 0, bvec![0u8; 15])); - assert_eq!(Balances::free_balance(&1), 14); - assert_ok!(Nfts::set_collection_metadata(RuntimeOrigin::signed(1), 0, bvec![0u8; 25])); - assert_eq!(Balances::free_balance(&1), 4); + assert_ok!(Nfts::set_collection_metadata( + RuntimeOrigin::signed(account(1)), + 0, + bvec![0u8; 15] + )); + assert_eq!(Balances::free_balance(&account(1)), 14); + assert_ok!(Nfts::set_collection_metadata( + RuntimeOrigin::signed(account(1)), + 0, + bvec![0u8; 25] + )); + assert_eq!(Balances::free_balance(&account(1)), 4); // Cannot over-reserve assert_noop!( - Nfts::set_collection_metadata(RuntimeOrigin::signed(1), 0, bvec![0u8; 40]), + Nfts::set_collection_metadata(RuntimeOrigin::signed(account(1)), 0, bvec![0u8; 40]), BalancesError::::InsufficientBalance, ); // Can't set or clear metadata once frozen - assert_ok!(Nfts::set_collection_metadata(RuntimeOrigin::signed(1), 0, bvec![0u8; 15])); + assert_ok!(Nfts::set_collection_metadata( + RuntimeOrigin::signed(account(1)), + 0, + bvec![0u8; 15] + )); assert_ok!(Nfts::lock_collection( - RuntimeOrigin::signed(1), + RuntimeOrigin::signed(account(1)), 0, CollectionSettings::from_disabled(CollectionSetting::UnlockedMetadata.into()) )); assert_noop!( - Nfts::set_collection_metadata(RuntimeOrigin::signed(1), 0, bvec![0u8; 15]), + Nfts::set_collection_metadata(RuntimeOrigin::signed(account(1)), 0, bvec![0u8; 15]), Error::::LockedCollectionMetadata, ); assert_noop!( - Nfts::clear_collection_metadata(RuntimeOrigin::signed(1), 0), + Nfts::clear_collection_metadata(RuntimeOrigin::signed(account(1)), 0), Error::::LockedCollectionMetadata ); // Clear Metadata assert_ok!(Nfts::set_collection_metadata(RuntimeOrigin::root(), 0, bvec![0u8; 15])); assert_noop!( - Nfts::clear_collection_metadata(RuntimeOrigin::signed(2), 0), + Nfts::clear_collection_metadata(RuntimeOrigin::signed(account(2)), 0), Error::::NoPermission ); assert_noop!( - Nfts::clear_collection_metadata(RuntimeOrigin::signed(1), 1), + Nfts::clear_collection_metadata(RuntimeOrigin::signed(account(1)), 1), Error::::UnknownCollection ); assert_noop!( - Nfts::clear_collection_metadata(RuntimeOrigin::signed(1), 0), + Nfts::clear_collection_metadata(RuntimeOrigin::signed(account(1)), 0), Error::::LockedCollectionMetadata ); assert_ok!(Nfts::clear_collection_metadata(RuntimeOrigin::root(), 0)); @@ -553,61 +682,67 @@ fn set_collection_metadata_should_work() { #[test] fn set_item_metadata_should_work() { new_test_ext().execute_with(|| { - Balances::make_free_balance_be(&1, 30); + Balances::make_free_balance_be(&account(1), 30); // Cannot add metadata to unknown item assert_ok!(Nfts::force_create( RuntimeOrigin::root(), - 1, + account(1), collection_config_with_all_settings_enabled() )); - assert_ok!(Nfts::mint(RuntimeOrigin::signed(1), 0, 42, 1, None)); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 42, account(1), None)); // Cannot add metadata to unowned item assert_noop!( - Nfts::set_metadata(RuntimeOrigin::signed(2), 0, 42, bvec![0u8; 20]), + Nfts::set_metadata(RuntimeOrigin::signed(account(2)), 0, 42, bvec![0u8; 20]), Error::::NoPermission, ); // Successfully add metadata and take deposit - assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(1), 0, 42, bvec![0u8; 20])); - assert_eq!(Balances::free_balance(&1), 8); + assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(account(1)), 0, 42, bvec![0u8; 20])); + assert_eq!(Balances::free_balance(&account(1)), 8); assert!(ItemMetadataOf::::contains_key(0, 42)); // Force origin works, too. assert_ok!(Nfts::set_metadata(RuntimeOrigin::root(), 0, 42, bvec![0u8; 18])); // Update deposit - assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(1), 0, 42, bvec![0u8; 15])); - assert_eq!(Balances::free_balance(&1), 13); - assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(1), 0, 42, bvec![0u8; 25])); - assert_eq!(Balances::free_balance(&1), 3); + assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(account(1)), 0, 42, bvec![0u8; 15])); + assert_eq!(Balances::free_balance(&account(1)), 13); + assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(account(1)), 0, 42, bvec![0u8; 25])); + assert_eq!(Balances::free_balance(&account(1)), 3); // Cannot over-reserve assert_noop!( - Nfts::set_metadata(RuntimeOrigin::signed(1), 0, 42, bvec![0u8; 40]), + Nfts::set_metadata(RuntimeOrigin::signed(account(1)), 0, 42, bvec![0u8; 40]), BalancesError::::InsufficientBalance, ); // Can't set or clear metadata once frozen - assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(1), 0, 42, bvec![0u8; 15])); - assert_ok!(Nfts::lock_item_properties(RuntimeOrigin::signed(1), 0, 42, true, false)); + assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(account(1)), 0, 42, bvec![0u8; 15])); + assert_ok!(Nfts::lock_item_properties( + RuntimeOrigin::signed(account(1)), + 0, + 42, + true, + false + )); assert_noop!( - Nfts::set_metadata(RuntimeOrigin::signed(1), 0, 42, bvec![0u8; 15]), + Nfts::set_metadata(RuntimeOrigin::signed(account(1)), 0, 42, bvec![0u8; 15]), Error::::LockedItemMetadata, ); assert_noop!( - Nfts::clear_metadata(RuntimeOrigin::signed(1), 0, 42), + Nfts::clear_metadata(RuntimeOrigin::signed(account(1)), 0, 42), Error::::LockedItemMetadata, ); // Clear Metadata assert_ok!(Nfts::set_metadata(RuntimeOrigin::root(), 0, 42, bvec![0u8; 15])); assert_noop!( - Nfts::clear_metadata(RuntimeOrigin::signed(2), 0, 42), + Nfts::clear_metadata(RuntimeOrigin::signed(account(2)), 0, 42), Error::::NoPermission, ); assert_noop!( - Nfts::clear_metadata(RuntimeOrigin::signed(1), 1, 42), + Nfts::clear_metadata(RuntimeOrigin::signed(account(1)), 1, 42), Error::::MetadataNotFound, ); assert_ok!(Nfts::clear_metadata(RuntimeOrigin::root(), 0, 42)); @@ -618,17 +753,17 @@ fn set_item_metadata_should_work() { #[test] fn set_collection_owner_attributes_should_work() { new_test_ext().execute_with(|| { - Balances::make_free_balance_be(&1, 100); + Balances::make_free_balance_be(&account(1), 100); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), - 1, + account(1), collection_config_with_all_settings_enabled() )); - assert_ok!(Nfts::mint(RuntimeOrigin::signed(1), 0, 0, 1, None)); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 0, account(1), None)); assert_ok!(Nfts::set_attribute( - RuntimeOrigin::signed(1), + RuntimeOrigin::signed(account(1)), 0, None, AttributeNamespace::CollectionOwner, @@ -636,7 +771,7 @@ fn set_collection_owner_attributes_should_work() { bvec![0], )); assert_ok!(Nfts::set_attribute( - RuntimeOrigin::signed(1), + RuntimeOrigin::signed(account(1)), 0, Some(0), AttributeNamespace::CollectionOwner, @@ -644,7 +779,7 @@ fn set_collection_owner_attributes_should_work() { bvec![0], )); assert_ok!(Nfts::set_attribute( - RuntimeOrigin::signed(1), + RuntimeOrigin::signed(account(1)), 0, Some(0), AttributeNamespace::CollectionOwner, @@ -659,11 +794,11 @@ fn set_collection_owner_attributes_should_work() { (Some(0), AttributeNamespace::CollectionOwner, bvec![1], bvec![0]), ] ); - assert_eq!(Balances::reserved_balance(1), 10); + assert_eq!(Balances::reserved_balance(account(1)), 10); assert_eq!(Collection::::get(0).unwrap().owner_deposit, 9); assert_ok!(Nfts::set_attribute( - RuntimeOrigin::signed(1), + RuntimeOrigin::signed(account(1)), 0, None, AttributeNamespace::CollectionOwner, @@ -678,11 +813,11 @@ fn set_collection_owner_attributes_should_work() { (Some(0), AttributeNamespace::CollectionOwner, bvec![1], bvec![0]), ] ); - assert_eq!(Balances::reserved_balance(1), 19); + assert_eq!(Balances::reserved_balance(account(1)), 19); assert_eq!(Collection::::get(0).unwrap().owner_deposit, 18); assert_ok!(Nfts::clear_attribute( - RuntimeOrigin::signed(1), + RuntimeOrigin::signed(account(1)), 0, Some(0), AttributeNamespace::CollectionOwner, @@ -695,33 +830,39 @@ fn set_collection_owner_attributes_should_work() { (Some(0), AttributeNamespace::CollectionOwner, bvec![0], bvec![0]), ] ); - assert_eq!(Balances::reserved_balance(1), 16); + assert_eq!(Balances::reserved_balance(account(1)), 16); let w = Nfts::get_destroy_witness(&0).unwrap(); - assert_ok!(Nfts::destroy(RuntimeOrigin::signed(1), 0, w)); + assert_ok!(Nfts::destroy(RuntimeOrigin::signed(account(1)), 0, w)); assert_eq!(attributes(0), vec![]); - assert_eq!(Balances::reserved_balance(1), 0); + assert_eq!(Balances::reserved_balance(account(1)), 0); }); } #[test] fn set_item_owner_attributes_should_work() { new_test_ext().execute_with(|| { - Balances::make_free_balance_be(&1, 100); - Balances::make_free_balance_be(&2, 100); - Balances::make_free_balance_be(&3, 100); + Balances::make_free_balance_be(&account(1), 100); + Balances::make_free_balance_be(&account(2), 100); + Balances::make_free_balance_be(&account(3), 100); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), - 1, + account(1), collection_config_with_all_settings_enabled() )); - assert_ok!(Nfts::force_mint(RuntimeOrigin::signed(1), 0, 0, 2, default_item_config())); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(account(1)), + 0, + 0, + account(2), + default_item_config() + )); // can't set for the collection assert_noop!( Nfts::set_attribute( - RuntimeOrigin::signed(2), + RuntimeOrigin::signed(account(2)), 0, None, AttributeNamespace::ItemOwner, @@ -733,7 +874,7 @@ fn set_item_owner_attributes_should_work() { // can't set for the non-owned item assert_noop!( Nfts::set_attribute( - RuntimeOrigin::signed(1), + RuntimeOrigin::signed(account(1)), 0, Some(0), AttributeNamespace::ItemOwner, @@ -743,7 +884,7 @@ fn set_item_owner_attributes_should_work() { Error::::NoPermission, ); assert_ok!(Nfts::set_attribute( - RuntimeOrigin::signed(2), + RuntimeOrigin::signed(account(2)), 0, Some(0), AttributeNamespace::ItemOwner, @@ -751,7 +892,7 @@ fn set_item_owner_attributes_should_work() { bvec![0], )); assert_ok!(Nfts::set_attribute( - RuntimeOrigin::signed(2), + RuntimeOrigin::signed(account(2)), 0, Some(0), AttributeNamespace::ItemOwner, @@ -759,7 +900,7 @@ fn set_item_owner_attributes_should_work() { bvec![0], )); assert_ok!(Nfts::set_attribute( - RuntimeOrigin::signed(2), + RuntimeOrigin::signed(account(2)), 0, Some(0), AttributeNamespace::ItemOwner, @@ -774,11 +915,11 @@ fn set_item_owner_attributes_should_work() { (Some(0), AttributeNamespace::ItemOwner, bvec![2], bvec![0]), ] ); - assert_eq!(Balances::reserved_balance(2), 9); + assert_eq!(Balances::reserved_balance(account(2)), 9); // validate an attribute can be updated assert_ok!(Nfts::set_attribute( - RuntimeOrigin::signed(2), + RuntimeOrigin::signed(account(2)), 0, Some(0), AttributeNamespace::ItemOwner, @@ -793,12 +934,12 @@ fn set_item_owner_attributes_should_work() { (Some(0), AttributeNamespace::ItemOwner, bvec![2], bvec![0]), ] ); - assert_eq!(Balances::reserved_balance(2), 18); + assert_eq!(Balances::reserved_balance(account(2)), 18); // validate only item's owner (or the root) can remove an attribute assert_noop!( Nfts::clear_attribute( - RuntimeOrigin::signed(1), + RuntimeOrigin::signed(account(1)), 0, Some(0), AttributeNamespace::ItemOwner, @@ -807,7 +948,7 @@ fn set_item_owner_attributes_should_work() { Error::::NoPermission, ); assert_ok!(Nfts::clear_attribute( - RuntimeOrigin::signed(2), + RuntimeOrigin::signed(account(2)), 0, Some(0), AttributeNamespace::ItemOwner, @@ -820,10 +961,10 @@ fn set_item_owner_attributes_should_work() { (Some(0), AttributeNamespace::ItemOwner, bvec![2], bvec![0]) ] ); - assert_eq!(Balances::reserved_balance(2), 15); + assert_eq!(Balances::reserved_balance(account(2)), 15); // transfer item - assert_ok!(Nfts::transfer(RuntimeOrigin::signed(2), 0, 0, 3)); + assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(2)), 0, 0, account(3))); // validate the attribute are still here & the deposit belongs to the previous owner assert_eq!( @@ -836,12 +977,12 @@ fn set_item_owner_attributes_should_work() { let key: BoundedVec<_, _> = bvec![0]; let (_, deposit) = Attribute::::get((0, Some(0), AttributeNamespace::ItemOwner, &key)).unwrap(); - assert_eq!(deposit.account, Some(2)); + assert_eq!(deposit.account, Some(account(2))); assert_eq!(deposit.amount, 12); // on attribute update the deposit should be returned to the previous owner assert_ok!(Nfts::set_attribute( - RuntimeOrigin::signed(3), + RuntimeOrigin::signed(account(3)), 0, Some(0), AttributeNamespace::ItemOwner, @@ -850,13 +991,13 @@ fn set_item_owner_attributes_should_work() { )); let (_, deposit) = Attribute::::get((0, Some(0), AttributeNamespace::ItemOwner, &key)).unwrap(); - assert_eq!(deposit.account, Some(3)); + assert_eq!(deposit.account, Some(account(3))); assert_eq!(deposit.amount, 13); - assert_eq!(Balances::reserved_balance(2), 3); - assert_eq!(Balances::reserved_balance(3), 13); + assert_eq!(Balances::reserved_balance(account(2)), 3); + assert_eq!(Balances::reserved_balance(account(3)), 13); // validate attributes on item deletion - assert_ok!(Nfts::burn(RuntimeOrigin::signed(3), 0, 0, None)); + assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(3)), 0, 0, None)); assert_eq!( attributes(0), vec![ @@ -865,90 +1006,101 @@ fn set_item_owner_attributes_should_work() { ] ); assert_ok!(Nfts::clear_attribute( - RuntimeOrigin::signed(3), + RuntimeOrigin::signed(account(3)), 0, Some(0), AttributeNamespace::ItemOwner, bvec![0], )); assert_ok!(Nfts::clear_attribute( - RuntimeOrigin::signed(2), + RuntimeOrigin::signed(account(2)), 0, Some(0), AttributeNamespace::ItemOwner, bvec![2], )); - assert_eq!(Balances::reserved_balance(2), 0); - assert_eq!(Balances::reserved_balance(3), 0); + assert_eq!(Balances::reserved_balance(account(2)), 0); + assert_eq!(Balances::reserved_balance(account(3)), 0); }); } #[test] fn set_external_account_attributes_should_work() { new_test_ext().execute_with(|| { - Balances::make_free_balance_be(&1, 100); - Balances::make_free_balance_be(&2, 100); + Balances::make_free_balance_be(&account(1), 100); + Balances::make_free_balance_be(&account(2), 100); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), - 1, + account(1), collection_config_with_all_settings_enabled() )); - assert_ok!(Nfts::force_mint(RuntimeOrigin::signed(1), 0, 0, 1, default_item_config())); - assert_ok!(Nfts::approve_item_attributes(RuntimeOrigin::signed(1), 0, 0, 2)); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(account(1)), + 0, + 0, + account(1), + default_item_config() + )); + assert_ok!(Nfts::approve_item_attributes( + RuntimeOrigin::signed(account(1)), + 0, + 0, + account(2) + )); assert_noop!( Nfts::set_attribute( - RuntimeOrigin::signed(2), + RuntimeOrigin::signed(account(2)), 0, Some(0), - AttributeNamespace::Account(1), + AttributeNamespace::Account(account(1)), bvec![0], bvec![0], ), Error::::NoPermission, ); assert_ok!(Nfts::set_attribute( - RuntimeOrigin::signed(2), + RuntimeOrigin::signed(account(2)), 0, Some(0), - AttributeNamespace::Account(2), + AttributeNamespace::Account(account(2)), bvec![0], bvec![0], )); assert_ok!(Nfts::set_attribute( - RuntimeOrigin::signed(2), + RuntimeOrigin::signed(account(2)), 0, Some(0), - AttributeNamespace::Account(2), + AttributeNamespace::Account(account(2)), bvec![1], bvec![0], )); assert_eq!( attributes(0), vec![ - (Some(0), AttributeNamespace::Account(2), bvec![0], bvec![0]), - (Some(0), AttributeNamespace::Account(2), bvec![1], bvec![0]), + (Some(0), AttributeNamespace::Account(account(2)), bvec![0], bvec![0]), + (Some(0), AttributeNamespace::Account(account(2)), bvec![1], bvec![0]), ] ); - assert_eq!(Balances::reserved_balance(2), 6); + assert_eq!(Balances::reserved_balance(account(2)), 6); // remove permission to set attributes assert_ok!(Nfts::cancel_item_attributes_approval( - RuntimeOrigin::signed(1), + RuntimeOrigin::signed(account(1)), 0, 0, - 2, + account(2), CancelAttributesApprovalWitness { account_attributes: 2 }, )); assert_eq!(attributes(0), vec![]); - assert_eq!(Balances::reserved_balance(2), 0); + assert_eq!(Balances::reserved_balance(account(2)), 0); assert_noop!( Nfts::set_attribute( - RuntimeOrigin::signed(2), + RuntimeOrigin::signed(account(2)), 0, Some(0), - AttributeNamespace::Account(2), + AttributeNamespace::Account(account(2)), bvec![0], bvec![0], ), @@ -960,18 +1112,33 @@ fn set_external_account_attributes_should_work() { #[test] fn validate_deposit_required_setting() { new_test_ext().execute_with(|| { - Balances::make_free_balance_be(&1, 100); - Balances::make_free_balance_be(&2, 100); - Balances::make_free_balance_be(&3, 100); + Balances::make_free_balance_be(&account(1), 100); + Balances::make_free_balance_be(&account(2), 100); + Balances::make_free_balance_be(&account(3), 100); // with the disabled DepositRequired setting, only the collection's owner can set the // attributes for free. - assert_ok!(Nfts::force_create(RuntimeOrigin::root(), 1, default_collection_config())); - assert_ok!(Nfts::force_mint(RuntimeOrigin::signed(1), 0, 0, 2, default_item_config())); - assert_ok!(Nfts::approve_item_attributes(RuntimeOrigin::signed(2), 0, 0, 3)); + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + account(1), + default_collection_config() + )); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(account(1)), + 0, + 0, + account(2), + default_item_config() + )); + assert_ok!(Nfts::approve_item_attributes( + RuntimeOrigin::signed(account(2)), + 0, + 0, + account(3) + )); assert_ok!(Nfts::set_attribute( - RuntimeOrigin::signed(1), + RuntimeOrigin::signed(account(1)), 0, Some(0), AttributeNamespace::CollectionOwner, @@ -979,7 +1146,7 @@ fn validate_deposit_required_setting() { bvec![0], )); assert_ok!(Nfts::set_attribute( - RuntimeOrigin::signed(2), + RuntimeOrigin::signed(account(2)), 0, Some(0), AttributeNamespace::ItemOwner, @@ -987,10 +1154,10 @@ fn validate_deposit_required_setting() { bvec![0], )); assert_ok!(Nfts::set_attribute( - RuntimeOrigin::signed(3), + RuntimeOrigin::signed(account(3)), 0, Some(0), - AttributeNamespace::Account(3), + AttributeNamespace::Account(account(3)), bvec![2], bvec![0], )); @@ -1005,13 +1172,13 @@ fn validate_deposit_required_setting() { vec![ (Some(0), AttributeNamespace::CollectionOwner, bvec![0], bvec![0]), (Some(0), AttributeNamespace::ItemOwner, bvec![1], bvec![0]), - (Some(0), AttributeNamespace::Account(3), bvec![2], bvec![0]), + (Some(0), AttributeNamespace::Account(account(3)), bvec![2], bvec![0]), (Some(0), AttributeNamespace::Pallet, bvec![3], bvec![0]), ] ); - assert_eq!(Balances::reserved_balance(1), 0); - assert_eq!(Balances::reserved_balance(2), 3); - assert_eq!(Balances::reserved_balance(3), 3); + assert_eq!(Balances::reserved_balance(account(1)), 0); + assert_eq!(Balances::reserved_balance(account(2)), 3); + assert_eq!(Balances::reserved_balance(account(3)), 3); assert_ok!( ::AccountId, ItemConfig>>::clear_attribute( @@ -1025,7 +1192,7 @@ fn validate_deposit_required_setting() { vec![ (Some(0), AttributeNamespace::CollectionOwner, bvec![0], bvec![0]), (Some(0), AttributeNamespace::ItemOwner, bvec![1], bvec![0]), - (Some(0), AttributeNamespace::Account(3), bvec![2], bvec![0]), + (Some(0), AttributeNamespace::Account(account(3)), bvec![2], bvec![0]), ] ); }); @@ -1034,18 +1201,18 @@ fn validate_deposit_required_setting() { #[test] fn set_attribute_should_respect_lock() { new_test_ext().execute_with(|| { - Balances::make_free_balance_be(&1, 100); + Balances::make_free_balance_be(&account(1), 100); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), - 1, + account(1), collection_config_with_all_settings_enabled(), )); - assert_ok!(Nfts::mint(RuntimeOrigin::signed(1), 0, 0, 1, None)); - assert_ok!(Nfts::mint(RuntimeOrigin::signed(1), 0, 1, 1, None)); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 0, account(1), None)); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 1, account(1), None)); assert_ok!(Nfts::set_attribute( - RuntimeOrigin::signed(1), + RuntimeOrigin::signed(account(1)), 0, None, AttributeNamespace::CollectionOwner, @@ -1053,7 +1220,7 @@ fn set_attribute_should_respect_lock() { bvec![0], )); assert_ok!(Nfts::set_attribute( - RuntimeOrigin::signed(1), + RuntimeOrigin::signed(account(1)), 0, Some(0), AttributeNamespace::CollectionOwner, @@ -1061,7 +1228,7 @@ fn set_attribute_should_respect_lock() { bvec![0], )); assert_ok!(Nfts::set_attribute( - RuntimeOrigin::signed(1), + RuntimeOrigin::signed(account(1)), 0, Some(1), AttributeNamespace::CollectionOwner, @@ -1076,11 +1243,11 @@ fn set_attribute_should_respect_lock() { (Some(1), AttributeNamespace::CollectionOwner, bvec![0], bvec![0]), ] ); - assert_eq!(Balances::reserved_balance(1), 11); + assert_eq!(Balances::reserved_balance(account(1)), 11); - assert_ok!(Nfts::set_collection_metadata(RuntimeOrigin::signed(1), 0, bvec![])); + assert_ok!(Nfts::set_collection_metadata(RuntimeOrigin::signed(account(1)), 0, bvec![])); assert_ok!(Nfts::lock_collection( - RuntimeOrigin::signed(1), + RuntimeOrigin::signed(account(1)), 0, CollectionSettings::from_disabled(CollectionSetting::UnlockedAttributes.into()) )); @@ -1088,7 +1255,7 @@ fn set_attribute_should_respect_lock() { let e = Error::::LockedCollectionAttributes; assert_noop!( Nfts::set_attribute( - RuntimeOrigin::signed(1), + RuntimeOrigin::signed(account(1)), 0, None, AttributeNamespace::CollectionOwner, @@ -1098,7 +1265,7 @@ fn set_attribute_should_respect_lock() { e ); assert_ok!(Nfts::set_attribute( - RuntimeOrigin::signed(1), + RuntimeOrigin::signed(account(1)), 0, Some(0), AttributeNamespace::CollectionOwner, @@ -1106,11 +1273,17 @@ fn set_attribute_should_respect_lock() { bvec![1], )); - assert_ok!(Nfts::lock_item_properties(RuntimeOrigin::signed(1), 0, 0, false, true)); + assert_ok!(Nfts::lock_item_properties( + RuntimeOrigin::signed(account(1)), + 0, + 0, + false, + true + )); let e = Error::::LockedItemAttributes; assert_noop!( Nfts::set_attribute( - RuntimeOrigin::signed(1), + RuntimeOrigin::signed(account(1)), 0, Some(0), AttributeNamespace::CollectionOwner, @@ -1120,7 +1293,7 @@ fn set_attribute_should_respect_lock() { e ); assert_ok!(Nfts::set_attribute( - RuntimeOrigin::signed(1), + RuntimeOrigin::signed(account(1)), 0, Some(1), AttributeNamespace::CollectionOwner, @@ -1133,22 +1306,22 @@ fn set_attribute_should_respect_lock() { #[test] fn preserve_config_for_frozen_items() { new_test_ext().execute_with(|| { - Balances::make_free_balance_be(&1, 100); + Balances::make_free_balance_be(&account(1), 100); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), - 1, + account(1), collection_config_with_all_settings_enabled() )); - assert_ok!(Nfts::mint(RuntimeOrigin::signed(1), 0, 0, 1, None)); - assert_ok!(Nfts::mint(RuntimeOrigin::signed(1), 0, 1, 1, None)); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 0, account(1), None)); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 1, account(1), None)); // if the item is not locked/frozen then the config gets deleted on item burn - assert_ok!(Nfts::burn(RuntimeOrigin::signed(1), 0, 1, Some(1))); + assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(1)), 0, 1, Some(account(1)))); assert!(!ItemConfigOf::::contains_key(0, 1)); // lock the item and ensure the config stays unchanged - assert_ok!(Nfts::lock_item_properties(RuntimeOrigin::signed(1), 0, 0, true, true)); + assert_ok!(Nfts::lock_item_properties(RuntimeOrigin::signed(account(1)), 0, 0, true, true)); let expect_config = item_config_from_disabled_settings( ItemSetting::UnlockedAttributes | ItemSetting::UnlockedMetadata, @@ -1156,18 +1329,24 @@ fn preserve_config_for_frozen_items() { let config = ItemConfigOf::::get(0, 0).unwrap(); assert_eq!(config, expect_config); - assert_ok!(Nfts::burn(RuntimeOrigin::signed(1), 0, 0, Some(1))); + assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(1)), 0, 0, Some(account(1)))); let config = ItemConfigOf::::get(0, 0).unwrap(); assert_eq!(config, expect_config); // can't mint with the different config assert_noop!( - Nfts::force_mint(RuntimeOrigin::signed(1), 0, 0, 1, default_item_config()), + Nfts::force_mint( + RuntimeOrigin::signed(account(1)), + 0, + 0, + account(2), + default_item_config() + ), Error::::InconsistentItemConfig ); assert_ok!(Nfts::update_mint_settings( - RuntimeOrigin::signed(1), + RuntimeOrigin::signed(account(1)), 0, MintSettings { default_item_settings: ItemSettings::from_disabled( @@ -1176,26 +1355,36 @@ fn preserve_config_for_frozen_items() { ..Default::default() } )); - assert_ok!(Nfts::mint(RuntimeOrigin::signed(1), 0, 0, 1, None)); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 0, account(1), None)); }); } #[test] fn force_update_collection_should_work() { new_test_ext().execute_with(|| { - Balances::make_free_balance_be(&1, 100); + Balances::make_free_balance_be(&account(1), 100); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), - 1, + account(1), collection_config_with_all_settings_enabled() )); - assert_ok!(Nfts::mint(RuntimeOrigin::signed(1), 0, 42, 1, None)); - assert_ok!(Nfts::force_mint(RuntimeOrigin::signed(1), 0, 69, 2, default_item_config())); - assert_ok!(Nfts::set_collection_metadata(RuntimeOrigin::signed(1), 0, bvec![0; 20])); - assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(1), 0, 42, bvec![0; 20])); - assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(1), 0, 69, bvec![0; 20])); - assert_eq!(Balances::reserved_balance(1), 65); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 42, account(1), None)); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(account(1)), + 0, + 69, + account(2), + default_item_config(), + )); + assert_ok!(Nfts::set_collection_metadata( + RuntimeOrigin::signed(account(1)), + 0, + bvec![0; 20] + )); + assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(account(1)), 0, 42, bvec![0; 20])); + assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(account(1)), 0, 69, bvec![0; 20])); + assert_eq!(Balances::reserved_balance(account(1)), 65); // force item status to be free holding assert_ok!(Nfts::force_collection_config( @@ -1203,52 +1392,66 @@ fn force_update_collection_should_work() { 0, collection_config_from_disabled_settings(CollectionSetting::DepositRequired.into()), )); - assert_ok!(Nfts::mint(RuntimeOrigin::signed(1), 0, 142, 1, None)); - assert_ok!(Nfts::force_mint(RuntimeOrigin::signed(1), 0, 169, 2, default_item_config())); - assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(1), 0, 142, bvec![0; 20])); - assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(1), 0, 169, bvec![0; 20])); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 142, account(1), None)); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(account(1)), + 0, + 169, + account(2), + default_item_config(), + )); + assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(account(1)), 0, 142, bvec![0; 20])); + assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(account(1)), 0, 169, bvec![0; 20])); - Balances::make_free_balance_be(&5, 100); - assert_ok!(Nfts::force_collection_owner(RuntimeOrigin::root(), 0, 5)); - assert_eq!(collections(), vec![(5, 0)]); - assert_eq!(Balances::reserved_balance(1), 2); - assert_eq!(Balances::reserved_balance(5), 63); + Balances::make_free_balance_be(&account(5), 100); + assert_ok!(Nfts::force_collection_owner(RuntimeOrigin::root(), 0, account(5))); + assert_eq!(collections(), vec![(account(5), 0)]); + assert_eq!(Balances::reserved_balance(account(1)), 2); + assert_eq!(Balances::reserved_balance(account(5)), 63); - assert_ok!(Nfts::redeposit(RuntimeOrigin::signed(5), 0, bvec![0, 42, 50, 69, 100])); - assert_eq!(Balances::reserved_balance(1), 0); + assert_ok!(Nfts::redeposit( + RuntimeOrigin::signed(account(5)), + 0, + bvec![0, 42, 50, 69, 100] + )); + assert_eq!(Balances::reserved_balance(account(1)), 0); - assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(5), 0, 42, bvec![0; 20])); - assert_eq!(Balances::reserved_balance(5), 42); + assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(account(5)), 0, 42, bvec![0; 20])); + assert_eq!(Balances::reserved_balance(account(5)), 42); - assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(5), 0, 69, bvec![0; 20])); - assert_eq!(Balances::reserved_balance(5), 21); + assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(account(5)), 0, 69, bvec![0; 20])); + assert_eq!(Balances::reserved_balance(account(5)), 21); - assert_ok!(Nfts::set_collection_metadata(RuntimeOrigin::signed(5), 0, bvec![0; 20])); - assert_eq!(Balances::reserved_balance(5), 0); + assert_ok!(Nfts::set_collection_metadata( + RuntimeOrigin::signed(account(5)), + 0, + bvec![0; 20] + )); + assert_eq!(Balances::reserved_balance(account(5)), 0); // validate new roles - assert_ok!(Nfts::set_team(RuntimeOrigin::root(), 0, 2, 3, 4)); + assert_ok!(Nfts::set_team(RuntimeOrigin::root(), 0, account(2), account(3), account(4))); assert_eq!( - CollectionRoleOf::::get(0, 2).unwrap(), + CollectionRoleOf::::get(0, account(2)).unwrap(), CollectionRoles(CollectionRole::Issuer.into()) ); assert_eq!( - CollectionRoleOf::::get(0, 3).unwrap(), + CollectionRoleOf::::get(0, account(3)).unwrap(), CollectionRoles(CollectionRole::Admin.into()) ); assert_eq!( - CollectionRoleOf::::get(0, 4).unwrap(), + CollectionRoleOf::::get(0, account(4)).unwrap(), CollectionRoles(CollectionRole::Freezer.into()) ); - assert_ok!(Nfts::set_team(RuntimeOrigin::root(), 0, 3, 2, 3)); + assert_ok!(Nfts::set_team(RuntimeOrigin::root(), 0, account(3), account(2), account(3))); assert_eq!( - CollectionRoleOf::::get(0, 2).unwrap(), + CollectionRoleOf::::get(0, account(2)).unwrap(), CollectionRoles(CollectionRole::Admin.into()) ); assert_eq!( - CollectionRoleOf::::get(0, 3).unwrap(), + CollectionRoleOf::::get(0, account(3)).unwrap(), CollectionRoles(CollectionRole::Issuer | CollectionRole::Freezer) ); }); @@ -1257,68 +1460,120 @@ fn force_update_collection_should_work() { #[test] fn burn_works() { new_test_ext().execute_with(|| { - Balances::make_free_balance_be(&1, 100); + Balances::make_free_balance_be(&account(1), 100); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), - 1, + account(1), collection_config_with_all_settings_enabled() )); - assert_ok!(Nfts::set_team(RuntimeOrigin::signed(1), 0, 2, 3, 4)); + assert_ok!(Nfts::set_team( + RuntimeOrigin::signed(account(1)), + 0, + account(2), + account(3), + account(4), + )); assert_noop!( - Nfts::burn(RuntimeOrigin::signed(5), 0, 42, Some(5)), + Nfts::burn(RuntimeOrigin::signed(account(5)), 0, 42, Some(account(5))), Error::::UnknownItem ); - assert_ok!(Nfts::force_mint(RuntimeOrigin::signed(2), 0, 42, 5, default_item_config())); - assert_ok!(Nfts::force_mint(RuntimeOrigin::signed(2), 0, 69, 5, default_item_config())); - assert_eq!(Balances::reserved_balance(1), 2); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(account(2)), + 0, + 42, + account(5), + default_item_config() + )); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(account(2)), + 0, + 69, + account(5), + default_item_config() + )); + assert_eq!(Balances::reserved_balance(account(1)), 2); assert_noop!( - Nfts::burn(RuntimeOrigin::signed(0), 0, 42, None), + Nfts::burn(RuntimeOrigin::signed(account(0)), 0, 42, None), Error::::NoPermission ); assert_noop!( - Nfts::burn(RuntimeOrigin::signed(5), 0, 42, Some(6)), + Nfts::burn(RuntimeOrigin::signed(account(5)), 0, 42, Some(account(6))), Error::::WrongOwner ); - assert_ok!(Nfts::burn(RuntimeOrigin::signed(5), 0, 42, Some(5))); - assert_ok!(Nfts::burn(RuntimeOrigin::signed(3), 0, 69, Some(5))); - assert_eq!(Balances::reserved_balance(1), 0); + assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(5)), 0, 42, Some(account(5)))); + assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(3)), 0, 69, Some(account(5)))); + assert_eq!(Balances::reserved_balance(account(1)), 0); }); } #[test] fn approval_lifecycle_works() { new_test_ext().execute_with(|| { - assert_ok!(Nfts::force_create(RuntimeOrigin::root(), 1, default_collection_config())); - assert_ok!(Nfts::force_mint(RuntimeOrigin::signed(1), 0, 42, 2, default_item_config())); - assert_ok!(Nfts::approve_transfer(RuntimeOrigin::signed(2), 0, 42, 3, None)); - assert_ok!(Nfts::transfer(RuntimeOrigin::signed(3), 0, 42, 4)); + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + account(1), + default_collection_config() + )); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(account(1)), + 0, + 42, + account(2), + default_item_config() + )); + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(account(2)), + 0, + 42, + account(3), + None + )); + assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(3)), 0, 42, account(4))); assert_noop!( - Nfts::transfer(RuntimeOrigin::signed(3), 0, 42, 3), + Nfts::transfer(RuntimeOrigin::signed(account(3)), 0, 42, account(3)), Error::::NoPermission ); assert!(Item::::get(0, 42).unwrap().approvals.is_empty()); - assert_ok!(Nfts::approve_transfer(RuntimeOrigin::signed(4), 0, 42, 2, None)); - assert_ok!(Nfts::transfer(RuntimeOrigin::signed(2), 0, 42, 2)); + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(account(4)), + 0, + 42, + account(2), + None + )); + assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(2)), 0, 42, account(2))); // ensure we can't buy an item when the collection has a NonTransferableItems flag let collection_id = 1; assert_ok!(Nfts::force_create( RuntimeOrigin::root(), - 1, + account(1), collection_config_from_disabled_settings( CollectionSetting::TransferableItems | CollectionSetting::DepositRequired ) )); - assert_ok!(Nfts::mint(RuntimeOrigin::signed(1), 1, collection_id, 1, None)); + assert_ok!(Nfts::mint( + RuntimeOrigin::signed(account(1)), + 1, + collection_id, + account(1), + None, + )); assert_noop!( - Nfts::approve_transfer(RuntimeOrigin::signed(1), collection_id, 1, 2, None), + Nfts::approve_transfer( + RuntimeOrigin::signed(account(1)), + collection_id, + 1, + account(2), + None + ), Error::::ItemsNonTransferable ); }); @@ -1327,46 +1582,74 @@ fn approval_lifecycle_works() { #[test] fn cancel_approval_works() { new_test_ext().execute_with(|| { - assert_ok!(Nfts::force_create(RuntimeOrigin::root(), 1, default_collection_config())); - assert_ok!(Nfts::force_mint(RuntimeOrigin::signed(1), 0, 42, 2, default_item_config())); + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + account(1), + default_collection_config() + )); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(account(1)), + 0, + 42, + account(2), + default_item_config() + )); - assert_ok!(Nfts::approve_transfer(RuntimeOrigin::signed(2), 0, 42, 3, None)); + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(account(2)), + 0, + 42, + account(3), + None + )); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(2), 1, 42, 3), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 1, 42, account(3)), Error::::UnknownItem ); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(2), 0, 43, 3), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 43, account(3)), Error::::UnknownItem ); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(3), 0, 42, 3), + Nfts::cancel_approval(RuntimeOrigin::signed(account(3)), 0, 42, account(3)), Error::::NoPermission ); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(2), 0, 42, 4), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(4)), Error::::NotDelegate ); - assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(2), 0, 42, 3)); + assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(3))); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(2), 0, 42, 3), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(3)), Error::::NotDelegate ); let current_block = 1; System::set_block_number(current_block); - assert_ok!(Nfts::force_mint(RuntimeOrigin::signed(1), 0, 69, 2, default_item_config())); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(account(1)), + 0, + 69, + account(2), + default_item_config() + )); // approval expires after 2 blocks. - assert_ok!(Nfts::approve_transfer(RuntimeOrigin::signed(2), 0, 42, 3, Some(2))); + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(account(2)), + 0, + 42, + account(3), + Some(2) + )); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(5), 0, 42, 3), + Nfts::cancel_approval(RuntimeOrigin::signed(account(5)), 0, 42, account(3)), Error::::NoPermission ); System::set_block_number(current_block + 3); // 5 can cancel the approval since the deadline has passed. - assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(5), 0, 42, 3)); + assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(5)), 0, 42, account(3))); assert_eq!(approvals(0, 69), vec![]); }); } @@ -1374,23 +1657,54 @@ fn cancel_approval_works() { #[test] fn approving_multiple_accounts_works() { new_test_ext().execute_with(|| { - assert_ok!(Nfts::force_create(RuntimeOrigin::root(), 1, default_collection_config())); - assert_ok!(Nfts::force_mint(RuntimeOrigin::signed(1), 0, 42, 2, default_item_config())); + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + account(1), + default_collection_config() + )); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(account(1)), + 0, + 42, + account(2), + default_item_config() + )); let current_block = 1; System::set_block_number(current_block); - assert_ok!(Nfts::approve_transfer(RuntimeOrigin::signed(2), 0, 42, 3, None)); - assert_ok!(Nfts::approve_transfer(RuntimeOrigin::signed(2), 0, 42, 4, None)); - assert_ok!(Nfts::approve_transfer(RuntimeOrigin::signed(2), 0, 42, 5, Some(2))); - assert_eq!(approvals(0, 42), vec![(3, None), (4, None), (5, Some(current_block + 2))]); + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(account(2)), + 0, + 42, + account(3), + None + )); + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(account(2)), + 0, + 42, + account(4), + None + )); + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(account(2)), + 0, + 42, + account(5), + Some(2) + )); + assert_eq!( + approvals(0, 42), + vec![(account(3), None), (account(4), None), (account(5), Some(current_block + 2))] + ); - assert_ok!(Nfts::transfer(RuntimeOrigin::signed(4), 0, 42, 6)); + assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(4)), 0, 42, account(6))); assert_noop!( - Nfts::transfer(RuntimeOrigin::signed(3), 0, 42, 7), + Nfts::transfer(RuntimeOrigin::signed(account(3)), 0, 42, account(7)), Error::::NoPermission ); assert_noop!( - Nfts::transfer(RuntimeOrigin::signed(5), 0, 42, 8), + Nfts::transfer(RuntimeOrigin::signed(account(5)), 0, 42, account(8)), Error::::NoPermission ); }); @@ -1399,15 +1713,31 @@ fn approving_multiple_accounts_works() { #[test] fn approvals_limit_works() { new_test_ext().execute_with(|| { - assert_ok!(Nfts::force_create(RuntimeOrigin::root(), 1, default_collection_config())); - assert_ok!(Nfts::force_mint(RuntimeOrigin::signed(1), 0, 42, 2, default_item_config())); + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + account(1), + default_collection_config() + )); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(account(1)), + 0, + 42, + account(2), + default_item_config() + )); for i in 3..13 { - assert_ok!(Nfts::approve_transfer(RuntimeOrigin::signed(2), 0, 42, i, None)); + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(account(2)), + 0, + 42, + account(i), + None + )); } // the limit is 10 assert_noop!( - Nfts::approve_transfer(RuntimeOrigin::signed(2), 0, 42, 14, None), + Nfts::approve_transfer(RuntimeOrigin::signed(account(2)), 0, 42, account(14), None), Error::::ReachedApprovalLimit ); }); @@ -1421,55 +1751,89 @@ fn approval_deadline_works() { assert_ok!(Nfts::force_create( RuntimeOrigin::root(), - 1, + account(1), collection_config_from_disabled_settings(CollectionSetting::DepositRequired.into()) )); - assert_ok!(Nfts::force_mint(RuntimeOrigin::signed(1), 0, 42, 2, default_item_config())); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(account(1)), + 0, + 42, + account(2), + default_item_config() + )); // the approval expires after the 2nd block. - assert_ok!(Nfts::approve_transfer(RuntimeOrigin::signed(2), 0, 42, 3, Some(2))); + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(account(2)), + 0, + 42, + account(3), + Some(2) + )); System::set_block_number(3); assert_noop!( - Nfts::transfer(RuntimeOrigin::signed(3), 0, 42, 4), + Nfts::transfer(RuntimeOrigin::signed(account(3)), 0, 42, account(4)), Error::::ApprovalExpired ); System::set_block_number(1); - assert_ok!(Nfts::transfer(RuntimeOrigin::signed(3), 0, 42, 4)); + assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(3)), 0, 42, account(4))); assert_eq!(System::block_number(), 1); // make a new approval with a deadline after 4 blocks, so it will expire after the 5th // block. - assert_ok!(Nfts::approve_transfer(RuntimeOrigin::signed(4), 0, 42, 6, Some(4))); + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(account(4)), + 0, + 42, + account(6), + Some(4) + )); // this should still work. System::set_block_number(5); - assert_ok!(Nfts::transfer(RuntimeOrigin::signed(6), 0, 42, 5)); + assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(6)), 0, 42, account(5))); }); } #[test] fn cancel_approval_works_with_admin() { new_test_ext().execute_with(|| { - assert_ok!(Nfts::force_create(RuntimeOrigin::root(), 1, default_collection_config())); - assert_ok!(Nfts::force_mint(RuntimeOrigin::signed(1), 0, 42, 2, default_item_config())); + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + account(1), + default_collection_config() + )); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(account(1)), + 0, + 42, + account(2), + default_item_config() + )); - assert_ok!(Nfts::approve_transfer(RuntimeOrigin::signed(2), 0, 42, 3, None)); + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(account(2)), + 0, + 42, + account(3), + None + )); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(1), 1, 42, 1), + Nfts::cancel_approval(RuntimeOrigin::signed(account(1)), 1, 42, account(1)), Error::::UnknownItem ); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(1), 0, 43, 1), + Nfts::cancel_approval(RuntimeOrigin::signed(account(1)), 0, 43, account(1)), Error::::UnknownItem ); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(1), 0, 42, 4), + Nfts::cancel_approval(RuntimeOrigin::signed(account(1)), 0, 42, account(4)), Error::::NotDelegate ); - assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(1), 0, 42, 3)); + assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(1)), 0, 42, account(3))); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(1), 0, 42, 1), + Nfts::cancel_approval(RuntimeOrigin::signed(account(1)), 0, 42, account(1)), Error::::NotDelegate ); }); @@ -1478,26 +1842,42 @@ fn cancel_approval_works_with_admin() { #[test] fn cancel_approval_works_with_force() { new_test_ext().execute_with(|| { - assert_ok!(Nfts::force_create(RuntimeOrigin::root(), 1, default_collection_config())); - assert_ok!(Nfts::force_mint(RuntimeOrigin::signed(1), 0, 42, 2, default_item_config())); + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + account(1), + default_collection_config() + )); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(account(1)), + 0, + 42, + account(2), + default_item_config() + )); - assert_ok!(Nfts::approve_transfer(RuntimeOrigin::signed(2), 0, 42, 3, None)); + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(account(2)), + 0, + 42, + account(3), + None + )); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::root(), 1, 42, 1), + Nfts::cancel_approval(RuntimeOrigin::root(), 1, 42, account(1)), Error::::UnknownItem ); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::root(), 0, 43, 1), + Nfts::cancel_approval(RuntimeOrigin::root(), 0, 43, account(1)), Error::::UnknownItem ); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::root(), 0, 42, 4), + Nfts::cancel_approval(RuntimeOrigin::root(), 0, 42, account(4)), Error::::NotDelegate ); - assert_ok!(Nfts::cancel_approval(RuntimeOrigin::root(), 0, 42, 3)); + assert_ok!(Nfts::cancel_approval(RuntimeOrigin::root(), 0, 42, account(3))); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::root(), 0, 42, 1), + Nfts::cancel_approval(RuntimeOrigin::root(), 0, 42, account(1)), Error::::NotDelegate ); }); @@ -1506,32 +1886,54 @@ fn cancel_approval_works_with_force() { #[test] fn clear_all_transfer_approvals_works() { new_test_ext().execute_with(|| { - assert_ok!(Nfts::force_create(RuntimeOrigin::root(), 1, default_collection_config())); - assert_ok!(Nfts::force_mint(RuntimeOrigin::signed(1), 0, 42, 2, default_item_config())); + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + account(1), + default_collection_config() + )); + assert_ok!(Nfts::force_mint( + RuntimeOrigin::signed(account(1)), + 0, + 42, + account(2), + default_item_config() + )); - assert_ok!(Nfts::approve_transfer(RuntimeOrigin::signed(2), 0, 42, 3, None)); - assert_ok!(Nfts::approve_transfer(RuntimeOrigin::signed(2), 0, 42, 4, None)); + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(account(2)), + 0, + 42, + account(3), + None + )); + assert_ok!(Nfts::approve_transfer( + RuntimeOrigin::signed(account(2)), + 0, + 42, + account(4), + None + )); assert_noop!( - Nfts::clear_all_transfer_approvals(RuntimeOrigin::signed(3), 0, 42), + Nfts::clear_all_transfer_approvals(RuntimeOrigin::signed(account(3)), 0, 42), Error::::NoPermission ); - assert_ok!(Nfts::clear_all_transfer_approvals(RuntimeOrigin::signed(2), 0, 42)); + assert_ok!(Nfts::clear_all_transfer_approvals(RuntimeOrigin::signed(account(2)), 0, 42)); assert!(events().contains(&Event::::AllApprovalsCancelled { collection: 0, item: 42, - owner: 2, + owner: account(2), })); assert_eq!(approvals(0, 42), vec![]); assert_noop!( - Nfts::transfer(RuntimeOrigin::signed(3), 0, 42, 5), + Nfts::transfer(RuntimeOrigin::signed(account(3)), 0, 42, account(5)), Error::::NoPermission ); assert_noop!( - Nfts::transfer(RuntimeOrigin::signed(4), 0, 42, 5), + Nfts::transfer(RuntimeOrigin::signed(account(4)), 0, 42, account(5)), Error::::NoPermission ); }); @@ -1541,15 +1943,19 @@ fn clear_all_transfer_approvals_works() { fn max_supply_should_work() { new_test_ext().execute_with(|| { let collection_id = 0; - let user_id = 1; + let user_id = account(1); let max_supply = 1; // validate set_collection_max_supply - assert_ok!(Nfts::force_create(RuntimeOrigin::root(), user_id, default_collection_config())); + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + user_id.clone(), + default_collection_config() + )); assert_eq!(CollectionConfigOf::::get(collection_id).unwrap().max_supply, None); assert_ok!(Nfts::set_collection_max_supply( - RuntimeOrigin::signed(user_id), + RuntimeOrigin::signed(user_id.clone()), collection_id, max_supply )); @@ -1564,18 +1970,18 @@ fn max_supply_should_work() { })); assert_ok!(Nfts::set_collection_max_supply( - RuntimeOrigin::signed(user_id), + RuntimeOrigin::signed(user_id.clone()), collection_id, max_supply + 1 )); assert_ok!(Nfts::lock_collection( - RuntimeOrigin::signed(user_id), + RuntimeOrigin::signed(user_id.clone()), collection_id, CollectionSettings::from_disabled(CollectionSetting::UnlockedMaxSupply.into()) )); assert_noop!( Nfts::set_collection_max_supply( - RuntimeOrigin::signed(user_id), + RuntimeOrigin::signed(user_id.clone()), collection_id, max_supply + 2 ), @@ -1583,10 +1989,22 @@ fn max_supply_should_work() { ); // validate we can't mint more to max supply - assert_ok!(Nfts::mint(RuntimeOrigin::signed(user_id), collection_id, 0, user_id, None)); - assert_ok!(Nfts::mint(RuntimeOrigin::signed(user_id), collection_id, 1, user_id, None)); + assert_ok!(Nfts::mint( + RuntimeOrigin::signed(user_id.clone()), + collection_id, + 0, + user_id.clone(), + None + )); + assert_ok!(Nfts::mint( + RuntimeOrigin::signed(user_id.clone()), + collection_id, + 1, + user_id.clone(), + None + )); assert_noop!( - Nfts::mint(RuntimeOrigin::signed(user_id), collection_id, 2, user_id, None), + Nfts::mint(RuntimeOrigin::signed(user_id.clone()), collection_id, 2, user_id, None), Error::::MaxSupplyReached ); }); @@ -1596,15 +2014,19 @@ fn max_supply_should_work() { fn mint_settings_should_work() { new_test_ext().execute_with(|| { let collection_id = 0; - let user_id = 1; + let user_id = account(1); let item_id = 0; - assert_ok!(Nfts::force_create(RuntimeOrigin::root(), user_id, default_collection_config())); + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + user_id.clone(), + default_collection_config() + )); assert_ok!(Nfts::mint( - RuntimeOrigin::signed(user_id), + RuntimeOrigin::signed(user_id.clone()), collection_id, item_id, - user_id, + user_id.clone(), None, )); assert_eq!( @@ -1618,7 +2040,7 @@ fn mint_settings_should_work() { let collection_id = 1; assert_ok!(Nfts::force_create( RuntimeOrigin::root(), - user_id, + user_id.clone(), CollectionConfig { mint_settings: MintSettings { default_item_settings: ItemSettings::from_disabled( @@ -1630,10 +2052,10 @@ fn mint_settings_should_work() { } )); assert_ok!(Nfts::mint( - RuntimeOrigin::signed(user_id), + RuntimeOrigin::signed(user_id.clone()), collection_id, item_id, - user_id, + user_id.clone(), None, )); assert_eq!( @@ -1650,30 +2072,34 @@ fn mint_settings_should_work() { #[test] fn set_price_should_work() { new_test_ext().execute_with(|| { - let user_id = 1; + let user_id = account(1); let collection_id = 0; let item_1 = 1; let item_2 = 2; - assert_ok!(Nfts::force_create(RuntimeOrigin::root(), user_id, default_collection_config())); + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + user_id.clone(), + default_collection_config() + )); assert_ok!(Nfts::mint( - RuntimeOrigin::signed(user_id), + RuntimeOrigin::signed(user_id.clone()), collection_id, item_1, - user_id, + user_id.clone(), None, )); assert_ok!(Nfts::mint( - RuntimeOrigin::signed(user_id), + RuntimeOrigin::signed(user_id.clone()), collection_id, item_2, - user_id, + user_id.clone(), None, )); assert_ok!(Nfts::set_price( - RuntimeOrigin::signed(user_id), + RuntimeOrigin::signed(user_id.clone()), collection_id, item_1, Some(1), @@ -1681,11 +2107,11 @@ fn set_price_should_work() { )); assert_ok!(Nfts::set_price( - RuntimeOrigin::signed(user_id), + RuntimeOrigin::signed(user_id.clone()), collection_id, item_2, Some(2), - Some(3) + Some(account(3)), )); let item = ItemPriceOf::::get(collection_id, item_1).unwrap(); @@ -1694,7 +2120,7 @@ fn set_price_should_work() { let item = ItemPriceOf::::get(collection_id, item_2).unwrap(); assert_eq!(item.0, 2); - assert_eq!(item.1, Some(3)); + assert_eq!(item.1, Some(account(3))); assert!(events().contains(&Event::::ItemPriceSet { collection: collection_id, @@ -1705,7 +2131,7 @@ fn set_price_should_work() { // validate we can unset the price assert_ok!(Nfts::set_price( - RuntimeOrigin::signed(user_id), + RuntimeOrigin::signed(user_id.clone()), collection_id, item_2, None, @@ -1721,22 +2147,28 @@ fn set_price_should_work() { let collection_id = 1; assert_ok!(Nfts::force_create( RuntimeOrigin::root(), - user_id, + user_id.clone(), collection_config_from_disabled_settings( CollectionSetting::TransferableItems | CollectionSetting::DepositRequired ) )); assert_ok!(Nfts::mint( - RuntimeOrigin::signed(user_id), + RuntimeOrigin::signed(user_id.clone()), collection_id, item_1, - user_id, + user_id.clone(), None, )); assert_noop!( - Nfts::set_price(RuntimeOrigin::signed(user_id), collection_id, item_1, Some(2), None), + Nfts::set_price( + RuntimeOrigin::signed(user_id.clone()), + collection_id, + item_1, + Some(2), + None + ), Error::::ItemsNonTransferable ); }); @@ -1745,9 +2177,9 @@ fn set_price_should_work() { #[test] fn buy_item_should_work() { new_test_ext().execute_with(|| { - let user_1 = 1; - let user_2 = 2; - let user_3 = 3; + let user_1 = account(1); + let user_2 = account(2); + let user_3 = account(3); let collection_id = 0; let item_1 = 1; let item_2 = 2; @@ -1760,14 +2192,36 @@ 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!(Nfts::force_create(RuntimeOrigin::root(), user_1, default_collection_config())); + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + user_1.clone(), + default_collection_config() + )); - assert_ok!(Nfts::mint(RuntimeOrigin::signed(user_1), collection_id, item_1, user_1, None)); - assert_ok!(Nfts::mint(RuntimeOrigin::signed(user_1), collection_id, item_2, user_1, None)); - assert_ok!(Nfts::mint(RuntimeOrigin::signed(user_1), collection_id, item_3, user_1, None)); + assert_ok!(Nfts::mint( + RuntimeOrigin::signed(user_1.clone()), + collection_id, + item_1, + user_1.clone(), + None + )); + assert_ok!(Nfts::mint( + RuntimeOrigin::signed(user_1.clone()), + collection_id, + item_2, + user_1.clone(), + None + )); + assert_ok!(Nfts::mint( + RuntimeOrigin::signed(user_1.clone()), + collection_id, + item_3, + user_1.clone(), + None + )); assert_ok!(Nfts::set_price( - RuntimeOrigin::signed(user_1), + RuntimeOrigin::signed(user_1.clone()), collection_id, item_1, Some(price_1), @@ -1775,22 +2229,22 @@ fn buy_item_should_work() { )); assert_ok!(Nfts::set_price( - RuntimeOrigin::signed(user_1), + RuntimeOrigin::signed(user_1.clone()), collection_id, item_2, Some(price_2), - Some(user_3), + Some(user_3.clone()), )); // can't buy for less assert_noop!( - Nfts::buy_item(RuntimeOrigin::signed(user_2), collection_id, item_1, 1), + Nfts::buy_item(RuntimeOrigin::signed(user_2.clone()), collection_id, item_1, 1), Error::::BidTooLow ); // pass the higher price to validate it will still deduct correctly assert_ok!(Nfts::buy_item( - RuntimeOrigin::signed(user_2), + RuntimeOrigin::signed(user_2.clone()), collection_id, item_1, price_1 + 1, @@ -1798,31 +2252,36 @@ fn buy_item_should_work() { // 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); + assert_eq!(item.owner, user_2.clone()); + assert_eq!(Balances::total_balance(&user_1.clone()), initial_balance + price_1); + assert_eq!(Balances::total_balance(&user_2.clone()), initial_balance - price_1); // can't buy from yourself assert_noop!( - Nfts::buy_item(RuntimeOrigin::signed(user_1), collection_id, item_2, price_2), + Nfts::buy_item(RuntimeOrigin::signed(user_1.clone()), collection_id, item_2, price_2), Error::::NoPermission ); // can't buy when the item is listed for a specific buyer assert_noop!( - Nfts::buy_item(RuntimeOrigin::signed(user_2), collection_id, item_2, price_2), + Nfts::buy_item(RuntimeOrigin::signed(user_2.clone()), collection_id, item_2, price_2), Error::::NoPermission ); // can buy when I'm a whitelisted buyer - assert_ok!(Nfts::buy_item(RuntimeOrigin::signed(user_3), collection_id, item_2, price_2)); + assert_ok!(Nfts::buy_item( + RuntimeOrigin::signed(user_3.clone()), + 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, + seller: user_1.clone(), + buyer: user_3.clone(), })); // ensure we reset the buyer field @@ -1830,14 +2289,14 @@ fn buy_item_should_work() { // can't buy when item is not for sale assert_noop!( - Nfts::buy_item(RuntimeOrigin::signed(user_2), collection_id, item_3, price_2), + Nfts::buy_item(RuntimeOrigin::signed(user_2.clone()), collection_id, item_3, price_2), Error::::NotForSale ); // ensure we can't buy an item when the collection or an item are frozen { assert_ok!(Nfts::set_price( - RuntimeOrigin::signed(user_1), + RuntimeOrigin::signed(user_1.clone()), collection_id, item_3, Some(price_1), @@ -1846,7 +2305,7 @@ fn buy_item_should_work() { // lock the collection assert_ok!(Nfts::lock_collection( - RuntimeOrigin::signed(user_1), + RuntimeOrigin::signed(user_1.clone()), collection_id, CollectionSettings::from_disabled(CollectionSetting::TransferableItems.into()) )); @@ -1857,7 +2316,7 @@ fn buy_item_should_work() { bid_price: price_1, }); assert_noop!( - buy_item_call.dispatch(RuntimeOrigin::signed(user_2)), + buy_item_call.dispatch(RuntimeOrigin::signed(user_2.clone())), Error::::ItemsNonTransferable ); @@ -1870,7 +2329,7 @@ fn buy_item_should_work() { // lock the transfer assert_ok!(Nfts::lock_item_transfer( - RuntimeOrigin::signed(user_1), + RuntimeOrigin::signed(user_1.clone()), collection_id, item_3, )); @@ -1891,9 +2350,9 @@ fn buy_item_should_work() { #[test] fn pay_tips_should_work() { new_test_ext().execute_with(|| { - let user_1 = 1; - let user_2 = 2; - let user_3 = 3; + let user_1 = account(1); + let user_2 = account(2); + let user_3 = account(3); let collection_id = 0; let item_id = 1; let tip = 2; @@ -1904,10 +2363,20 @@ fn pay_tips_should_work() { Balances::make_free_balance_be(&user_3, initial_balance); assert_ok!(Nfts::pay_tips( - RuntimeOrigin::signed(user_1), + RuntimeOrigin::signed(user_1.clone()), bvec![ - ItemTip { collection: collection_id, item: item_id, receiver: user_2, amount: tip }, - ItemTip { collection: collection_id, item: item_id, receiver: user_3, amount: tip }, + ItemTip { + collection: collection_id, + item: item_id, + receiver: user_2.clone(), + amount: tip + }, + ItemTip { + collection: collection_id, + item: item_id, + receiver: user_3.clone(), + amount: tip + }, ] )); @@ -1919,15 +2388,15 @@ fn pay_tips_should_work() { assert!(events.contains(&Event::::TipSent { collection: collection_id, item: item_id, - sender: user_1, - receiver: user_2, + sender: user_1.clone(), + receiver: user_2.clone(), amount: tip, })); assert!(events.contains(&Event::::TipSent { collection: collection_id, item: item_id, - sender: user_1, - receiver: user_3, + sender: user_1.clone(), + receiver: user_3.clone(), amount: tip, })); }); @@ -1937,7 +2406,7 @@ fn pay_tips_should_work() { fn create_cancel_swap_should_work() { new_test_ext().execute_with(|| { System::set_block_number(1); - let user_id = 1; + let user_id = account(1); let collection_id = 0; let item_1 = 1; let item_2 = 2; @@ -1947,27 +2416,31 @@ fn create_cancel_swap_should_work() { let duration = 2; let expect_deadline = 3; - assert_ok!(Nfts::force_create(RuntimeOrigin::root(), user_id, default_collection_config())); + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + user_id.clone(), + default_collection_config() + )); assert_ok!(Nfts::mint( - RuntimeOrigin::signed(user_id), + RuntimeOrigin::signed(user_id.clone()), collection_id, item_1, - user_id, + user_id.clone(), None, )); assert_ok!(Nfts::mint( - RuntimeOrigin::signed(user_id), + RuntimeOrigin::signed(user_id.clone()), collection_id, item_2, - user_id, + user_id.clone(), None, )); // validate desired item and the collection exists assert_noop!( Nfts::create_swap( - RuntimeOrigin::signed(user_id), + RuntimeOrigin::signed(user_id.clone()), collection_id, item_1, collection_id, @@ -1979,7 +2452,7 @@ fn create_cancel_swap_should_work() { ); assert_noop!( Nfts::create_swap( - RuntimeOrigin::signed(user_id), + RuntimeOrigin::signed(user_id.clone()), collection_id, item_1, collection_id + 1, @@ -1993,7 +2466,7 @@ fn create_cancel_swap_should_work() { let max_duration: u64 = ::MaxDeadlineDuration::get(); assert_noop!( Nfts::create_swap( - RuntimeOrigin::signed(user_id), + RuntimeOrigin::signed(user_id.clone()), collection_id, item_1, collection_id, @@ -2005,7 +2478,7 @@ fn create_cancel_swap_should_work() { ); assert_ok!(Nfts::create_swap( - RuntimeOrigin::signed(user_id), + RuntimeOrigin::signed(user_id.clone()), collection_id, item_1, collection_id, @@ -2030,7 +2503,11 @@ fn create_cancel_swap_should_work() { })); // validate we can cancel the swap - assert_ok!(Nfts::cancel_swap(RuntimeOrigin::signed(user_id), collection_id, item_1)); + assert_ok!(Nfts::cancel_swap( + RuntimeOrigin::signed(user_id.clone()), + collection_id, + item_1 + )); assert!(events().contains(&Event::::SwapCancelled { offered_collection: collection_id, offered_item: item_1, @@ -2043,7 +2520,7 @@ fn create_cancel_swap_should_work() { // validate anyone can cancel the expired swap assert_ok!(Nfts::create_swap( - RuntimeOrigin::signed(user_id), + RuntimeOrigin::signed(user_id.clone()), collection_id, item_1, collection_id, @@ -2052,11 +2529,11 @@ fn create_cancel_swap_should_work() { duration, )); assert_noop!( - Nfts::cancel_swap(RuntimeOrigin::signed(user_id + 1), collection_id, item_1), + Nfts::cancel_swap(RuntimeOrigin::signed(account(2)), collection_id, item_1), Error::::NoPermission ); System::set_block_number(expect_deadline + 1); - assert_ok!(Nfts::cancel_swap(RuntimeOrigin::signed(user_id + 1), collection_id, item_1)); + assert_ok!(Nfts::cancel_swap(RuntimeOrigin::signed(account(2)), collection_id, item_1)); // validate optional desired_item param assert_ok!(Nfts::create_swap( @@ -2078,8 +2555,8 @@ fn create_cancel_swap_should_work() { fn claim_swap_should_work() { new_test_ext().execute_with(|| { System::set_block_number(1); - let user_1 = 1; - let user_2 = 2; + let user_1 = account(1); + let user_2 = account(2); let collection_id = 0; let item_1 = 1; let item_2 = 2; @@ -2097,45 +2574,46 @@ fn claim_swap_should_work() { Balances::make_free_balance_be(&user_1, initial_balance); Balances::make_free_balance_be(&user_2, initial_balance); - assert_ok!(Nfts::force_create(RuntimeOrigin::root(), user_1, default_collection_config())); + assert_ok!(Nfts::force_create(RuntimeOrigin::root(), user_1.clone(), default_collection_config())); assert_ok!(Nfts::mint( - RuntimeOrigin::signed(user_1), + RuntimeOrigin::signed(user_1.clone()), collection_id, - item_1,user_1, + item_1, + user_1.clone(), None, )); assert_ok!(Nfts::force_mint( - RuntimeOrigin::signed(user_1), + RuntimeOrigin::signed(user_1.clone()), collection_id, item_2, - user_2, + user_2.clone(), default_item_config(), )); assert_ok!(Nfts::force_mint( - RuntimeOrigin::signed(user_1), + RuntimeOrigin::signed(user_1.clone()), collection_id, item_3, - user_2, + user_2.clone(), default_item_config(), )); assert_ok!(Nfts::mint( - RuntimeOrigin::signed(user_1), + RuntimeOrigin::signed(user_1.clone()), collection_id, item_4, - user_1, + user_1.clone(), None, )); assert_ok!(Nfts::force_mint( - RuntimeOrigin::signed(user_1), + RuntimeOrigin::signed(user_1.clone()), collection_id, item_5, - user_2, + user_2.clone(), default_item_config(), )); assert_ok!(Nfts::create_swap( - RuntimeOrigin::signed(user_1), + RuntimeOrigin::signed(user_1.clone()), collection_id, item_1, collection_id, @@ -2148,7 +2626,7 @@ fn claim_swap_should_work() { System::set_block_number(5); assert_noop!( Nfts::claim_swap( - RuntimeOrigin::signed(user_2), + RuntimeOrigin::signed(user_2.clone()), collection_id, item_2, collection_id, @@ -2162,7 +2640,7 @@ fn claim_swap_should_work() { // validate edge cases assert_noop!( Nfts::claim_swap( - RuntimeOrigin::signed(user_2), + RuntimeOrigin::signed(user_2.clone()), collection_id, item_2, collection_id, @@ -2173,7 +2651,7 @@ fn claim_swap_should_work() { ); assert_noop!( Nfts::claim_swap( - RuntimeOrigin::signed(user_2), + RuntimeOrigin::signed(user_2.clone()), collection_id, item_4, // not my item collection_id, @@ -2184,7 +2662,7 @@ fn claim_swap_should_work() { ); assert_noop!( Nfts::claim_swap( - RuntimeOrigin::signed(user_2), + RuntimeOrigin::signed(user_2.clone()), collection_id, item_5, // my item, but not the one another part wants collection_id, @@ -2195,7 +2673,7 @@ fn claim_swap_should_work() { ); assert_noop!( Nfts::claim_swap( - RuntimeOrigin::signed(user_2), + RuntimeOrigin::signed(user_2.clone()), collection_id, item_2, collection_id, @@ -2206,7 +2684,7 @@ fn claim_swap_should_work() { ); assert_noop!( Nfts::claim_swap( - RuntimeOrigin::signed(user_2), + RuntimeOrigin::signed(user_2.clone()), collection_id, item_2, collection_id, @@ -2217,7 +2695,7 @@ fn claim_swap_should_work() { ); assert_ok!(Nfts::claim_swap( - RuntimeOrigin::signed(user_2), + RuntimeOrigin::signed(user_2.clone()), collection_id, item_2, collection_id, @@ -2227,9 +2705,9 @@ fn claim_swap_should_work() { // validate the new owner let item = Item::::get(collection_id, item_1).unwrap(); - assert_eq!(item.owner, user_2); + assert_eq!(item.owner, user_2.clone()); let item = Item::::get(collection_id, item_2).unwrap(); - assert_eq!(item.owner, user_1); + assert_eq!(item.owner, user_1.clone()); // validate the balances assert_eq!(Balances::total_balance(&user_1), initial_balance + price); @@ -2242,10 +2720,10 @@ fn claim_swap_should_work() { assert!(events().contains(&Event::::SwapClaimed { sent_collection: collection_id, sent_item: item_2, - sent_item_owner: user_2, + sent_item_owner: user_2.clone(), received_collection: collection_id, received_item: item_1, - received_item_owner: user_1, + received_item_owner: user_1.clone(), price: Some(price_with_direction.clone()), deadline, })); @@ -2257,7 +2735,7 @@ fn claim_swap_should_work() { Balances::make_free_balance_be(&user_2, initial_balance); assert_ok!(Nfts::create_swap( - RuntimeOrigin::signed(user_1), + RuntimeOrigin::signed(user_1.clone()), collection_id, item_4, collection_id, @@ -2266,7 +2744,7 @@ fn claim_swap_should_work() { duration, )); assert_ok!(Nfts::claim_swap( - RuntimeOrigin::signed(user_2), + RuntimeOrigin::signed(user_2.clone()), collection_id, item_1, collection_id, @@ -2289,7 +2767,7 @@ fn various_collection_settings() { // when we set only one value it's required to call .into() on it let config = collection_config_from_disabled_settings(CollectionSetting::TransferableItems.into()); - assert_ok!(Nfts::force_create(RuntimeOrigin::root(), 1, config)); + assert_ok!(Nfts::force_create(RuntimeOrigin::root(), account(1), config)); let config = CollectionConfigOf::::get(0).unwrap(); assert!(!config.is_setting_enabled(CollectionSetting::TransferableItems)); @@ -2299,25 +2777,29 @@ fn various_collection_settings() { let config = collection_config_from_disabled_settings( CollectionSetting::UnlockedMetadata | CollectionSetting::TransferableItems, ); - assert_ok!(Nfts::force_create(RuntimeOrigin::root(), 1, config)); + assert_ok!(Nfts::force_create(RuntimeOrigin::root(), account(1), config)); let config = CollectionConfigOf::::get(1).unwrap(); assert!(!config.is_setting_enabled(CollectionSetting::TransferableItems)); assert!(!config.is_setting_enabled(CollectionSetting::UnlockedMetadata)); - assert_ok!(Nfts::force_create(RuntimeOrigin::root(), 1, default_collection_config())); + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + account(1), + default_collection_config() + )); }); } #[test] fn collection_locking_should_work() { new_test_ext().execute_with(|| { - let user_id = 1; + let user_id = account(1); let collection_id = 0; assert_ok!(Nfts::force_create( RuntimeOrigin::root(), - user_id, + user_id.clone(), collection_config_with_all_settings_enabled() )); @@ -2325,7 +2807,7 @@ fn collection_locking_should_work() { collection_config_from_disabled_settings(CollectionSetting::DepositRequired.into()); assert_noop!( Nfts::lock_collection( - RuntimeOrigin::signed(user_id), + RuntimeOrigin::signed(user_id.clone()), collection_id, lock_config.settings, ), @@ -2337,7 +2819,7 @@ fn collection_locking_should_work() { CollectionSetting::TransferableItems | CollectionSetting::UnlockedAttributes, ); assert_ok!(Nfts::lock_collection( - RuntimeOrigin::signed(user_id), + RuntimeOrigin::signed(user_id.clone()), collection_id, lock_config.settings, )); @@ -2369,33 +2851,49 @@ fn pallet_level_feature_flags_should_work() { PalletFeature::Trading | PalletFeature::Approvals | PalletFeature::Attributes, )); - let user_id = 1; + let user_id = account(1); let collection_id = 0; let item_id = 1; - assert_ok!(Nfts::force_create(RuntimeOrigin::root(), user_id, default_collection_config())); + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + user_id.clone(), + default_collection_config() + )); assert_ok!(Nfts::mint( - RuntimeOrigin::signed(user_id), + RuntimeOrigin::signed(user_id.clone()), collection_id, item_id, - user_id, + user_id.clone(), None, )); // PalletFeature::Trading assert_noop!( - Nfts::set_price(RuntimeOrigin::signed(user_id), collection_id, item_id, Some(1), None), + Nfts::set_price( + RuntimeOrigin::signed(user_id.clone()), + collection_id, + item_id, + Some(1), + None + ), Error::::MethodDisabled ); assert_noop!( - Nfts::buy_item(RuntimeOrigin::signed(user_id), collection_id, item_id, 1), + Nfts::buy_item(RuntimeOrigin::signed(user_id.clone()), collection_id, item_id, 1), Error::::MethodDisabled ); // PalletFeature::Approvals assert_noop!( - Nfts::approve_transfer(RuntimeOrigin::signed(user_id), collection_id, item_id, 2, None), + Nfts::approve_transfer( + RuntimeOrigin::signed(user_id.clone()), + collection_id, + item_id, + account(2), + None + ), Error::::MethodDisabled ); @@ -2420,25 +2918,25 @@ fn group_roles_by_account_should_work() { assert_eq!(Nfts::group_roles_by_account(vec![]), vec![]); let account_to_role = Nfts::group_roles_by_account(vec![ - (3, CollectionRole::Freezer), - (1, CollectionRole::Issuer), - (2, CollectionRole::Admin), + (account(3), CollectionRole::Freezer), + (account(1), CollectionRole::Issuer), + (account(2), CollectionRole::Admin), ]); let expect = vec![ - (1, CollectionRoles(CollectionRole::Issuer.into())), - (2, CollectionRoles(CollectionRole::Admin.into())), - (3, CollectionRoles(CollectionRole::Freezer.into())), + (account(1), CollectionRoles(CollectionRole::Issuer.into())), + (account(2), CollectionRoles(CollectionRole::Admin.into())), + (account(3), CollectionRoles(CollectionRole::Freezer.into())), ]; assert_eq!(account_to_role, expect); let account_to_role = Nfts::group_roles_by_account(vec![ - (3, CollectionRole::Freezer), - (2, CollectionRole::Issuer), - (2, CollectionRole::Admin), + (account(3), CollectionRole::Freezer), + (account(2), CollectionRole::Issuer), + (account(2), CollectionRole::Admin), ]); let expect = vec![ - (2, CollectionRoles(CollectionRole::Issuer | CollectionRole::Admin)), - (3, CollectionRoles(CollectionRole::Freezer.into())), + (account(2), CollectionRoles(CollectionRole::Issuer | CollectionRole::Admin)), + (account(3), CollectionRoles(CollectionRole::Freezer.into())), ]; assert_eq!(account_to_role, expect); }) @@ -2447,40 +2945,53 @@ fn group_roles_by_account_should_work() { #[test] fn add_remove_item_attributes_approval_should_work() { new_test_ext().execute_with(|| { - let user_1 = 1; - let user_2 = 2; - let user_3 = 3; - let user_4 = 4; + let user_1 = account(1); + let user_2 = account(2); + let user_3 = account(3); + let user_4 = account(4); let collection_id = 0; let item_id = 0; - assert_ok!(Nfts::force_create(RuntimeOrigin::root(), user_1, default_collection_config())); - assert_ok!(Nfts::mint(RuntimeOrigin::signed(user_1), collection_id, item_id, user_1, None)); + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + user_1.clone(), + default_collection_config() + )); + assert_ok!(Nfts::mint( + RuntimeOrigin::signed(user_1.clone()), + collection_id, + item_id, + user_1.clone(), + None + )); assert_ok!(Nfts::approve_item_attributes( - RuntimeOrigin::signed(user_1), + RuntimeOrigin::signed(user_1.clone()), collection_id, item_id, - user_2, + user_2.clone(), )); - assert_eq!(item_attributes_approvals(collection_id, item_id), vec![user_2]); + assert_eq!(item_attributes_approvals(collection_id, item_id), vec![user_2.clone()]); assert_ok!(Nfts::approve_item_attributes( - RuntimeOrigin::signed(user_1), + RuntimeOrigin::signed(user_1.clone()), collection_id, item_id, - user_3, + user_3.clone(), )); assert_ok!(Nfts::approve_item_attributes( - RuntimeOrigin::signed(user_1), + RuntimeOrigin::signed(user_1.clone()), collection_id, item_id, - user_2, + user_2.clone(), )); - assert_eq!(item_attributes_approvals(collection_id, item_id), vec![user_2, user_3]); + assert_eq!( + item_attributes_approvals(collection_id, item_id), + vec![user_2.clone(), user_3.clone()] + ); assert_noop!( Nfts::approve_item_attributes( - RuntimeOrigin::signed(user_1), + RuntimeOrigin::signed(user_1.clone()), collection_id, item_id, user_4, @@ -2498,3 +3009,170 @@ fn add_remove_item_attributes_approval_should_work() { assert_eq!(item_attributes_approvals(collection_id, item_id), vec![user_3]); }) } + +#[test] +fn pre_signed_mints_should_work() { + new_test_ext().execute_with(|| { + let user_1_pair = sp_core::sr25519::Pair::from_string("//Alice", None).unwrap(); + let user_1_signer = MultiSigner::Sr25519(user_1_pair.public()); + let user_1 = user_1_signer.clone().into_account(); + let mint_data = PreSignedMint { + collection: 0, + item: 0, + attributes: vec![(vec![0], vec![1]), (vec![2], vec![3])], + metadata: vec![0, 1], + only_account: None, + deadline: 10000000, + }; + let message = Encode::encode(&mint_data); + let signature = MultiSignature::Sr25519(user_1_pair.sign(&message)); + let user_2 = account(2); + let user_3 = account(3); + + Balances::make_free_balance_be(&user_1, 100); + Balances::make_free_balance_be(&user_2, 100); + assert_ok!(Nfts::create( + RuntimeOrigin::signed(user_1.clone()), + user_1.clone(), + collection_config_with_all_settings_enabled(), + )); + + assert_ok!(Nfts::mint_pre_signed( + RuntimeOrigin::signed(user_2.clone()), + mint_data.clone(), + signature.clone(), + user_1.clone(), + )); + assert_eq!(items(), vec![(user_2.clone(), 0, 0)]); + let metadata = ItemMetadataOf::::get(0, 0).unwrap(); + assert_eq!( + metadata.deposit, + ItemMetadataDeposit { account: Some(user_2.clone()), amount: 3 } + ); + assert_eq!(metadata.data, vec![0, 1]); + + assert_eq!( + attributes(0), + vec![ + (Some(0), AttributeNamespace::CollectionOwner, bvec![0], bvec![1]), + (Some(0), AttributeNamespace::CollectionOwner, bvec![2], bvec![3]), + ] + ); + let attribute_key: BoundedVec<_, _> = bvec![0]; + let (_, deposit) = Attribute::::get(( + 0, + Some(0), + AttributeNamespace::CollectionOwner, + &attribute_key, + )) + .unwrap(); + assert_eq!(deposit.account, Some(user_2.clone())); + assert_eq!(deposit.amount, 3); + + assert_eq!(Balances::free_balance(&user_1), 100 - 2); // 2 - collection deposit + assert_eq!(Balances::free_balance(&user_2), 100 - 1 - 3 - 6); // 1 - item deposit, 3 - metadata, 6 - attributes + + assert_noop!( + Nfts::mint_pre_signed( + RuntimeOrigin::signed(user_2.clone()), + mint_data, + signature.clone(), + user_1.clone(), + ), + Error::::AlreadyExists + ); + + assert_ok!(Nfts::burn(RuntimeOrigin::signed(user_2.clone()), 0, 0, Some(user_2.clone()))); + assert_eq!(Balances::free_balance(&user_2), 100 - 6); + + // validate the `only_account` field + let mint_data = PreSignedMint { + collection: 0, + item: 0, + attributes: vec![], + metadata: vec![], + only_account: Some(account(2)), + deadline: 10000000, + }; + + // can't mint with the wrong signature + assert_noop!( + Nfts::mint_pre_signed( + RuntimeOrigin::signed(user_2.clone()), + mint_data.clone(), + signature.clone(), + user_1.clone(), + ), + Error::::WrongSignature + ); + + let message = Encode::encode(&mint_data); + let signature = MultiSignature::Sr25519(user_1_pair.sign(&message)); + + assert_noop!( + Nfts::mint_pre_signed( + RuntimeOrigin::signed(user_3), + mint_data.clone(), + signature.clone(), + user_1.clone(), + ), + Error::::WrongOrigin + ); + + // validate signature's expiration + System::set_block_number(10000001); + assert_noop!( + Nfts::mint_pre_signed( + RuntimeOrigin::signed(user_2.clone()), + mint_data, + signature, + user_1.clone(), + ), + Error::::DeadlineExpired + ); + System::set_block_number(1); + + // validate the collection + let mint_data = PreSignedMint { + collection: 1, + item: 0, + attributes: vec![], + metadata: vec![], + only_account: Some(account(2)), + deadline: 10000000, + }; + let message = Encode::encode(&mint_data); + let signature = MultiSignature::Sr25519(user_1_pair.sign(&message)); + + assert_noop!( + Nfts::mint_pre_signed( + RuntimeOrigin::signed(user_2.clone()), + mint_data, + signature, + user_1.clone(), + ), + Error::::UnknownCollection + ); + + // validate max attributes limit + let mint_data = PreSignedMint { + collection: 0, + item: 0, + attributes: vec![(vec![0], vec![1]), (vec![2], vec![3]), (vec![2], vec![3])], + metadata: vec![0, 1], + only_account: None, + deadline: 10000000, + }; + let message = Encode::encode(&mint_data); + let signature = MultiSignature::Sr25519(user_1_pair.sign(&message)); + assert_noop!( + Nfts::mint_pre_signed( + RuntimeOrigin::signed(user_2), + mint_data, + signature, + user_1.clone(), + ), + Error::::MaxAttributesLimitReached + ); + }) +} diff --git a/frame/nfts/src/types.rs b/frame/nfts/src/types.rs index d8938aab4377a..c2ecd61c23028 100644 --- a/frame/nfts/src/types.rs +++ b/frame/nfts/src/types.rs @@ -61,6 +61,12 @@ pub(super) type CollectionConfigFor = CollectionConfig< ::BlockNumber, >::CollectionId, >; +pub(super) type PreSignedMintOf = PreSignedMint< + >::CollectionId, + >::ItemId, + ::AccountId, + ::BlockNumber, +>; pub trait Incrementable { fn increment(&self) -> Self; @@ -187,7 +193,7 @@ pub struct PendingSwap { pub(super) desired_item: Option, /// A price for the desired `item` with the direction. pub(super) price: Option, - /// An optional deadline for the swap. + /// A deadline for the swap. pub(super) deadline: Deadline, } @@ -473,3 +479,19 @@ impl CollectionRoles { } } impl_codec_bitflags!(CollectionRoles, u8, CollectionRole); + +#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct PreSignedMint { + /// A collection of the item to be minted. + pub(super) collection: CollectionId, + /// Item's id. + pub(super) item: ItemId, + /// Additional item's key-value attributes. + pub(super) attributes: Vec<(Vec, Vec)>, + /// Additional item's metadata. + pub(super) metadata: Vec, + /// Restrict the claim to a particular account. + pub(super) only_account: Option, + /// A deadline for the signature. + pub(super) deadline: Deadline, +} diff --git a/frame/nfts/src/weights.rs b/frame/nfts/src/weights.rs index 81be145b67c88..40592c29988ed 100644 --- a/frame/nfts/src/weights.rs +++ b/frame/nfts/src/weights.rs @@ -18,25 +18,26 @@ //! Autogenerated weights for pallet_nfts //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-01-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `runner-b3zmxxc-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! 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_nfts // --extrinsic=* // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/nfts/src/weights.rs +// --json-file=/builds/parity/mirrors/substrate/.git/.artifacts/bench.json +// --pallet=pallet_nfts +// --chain=dev // --header=./HEADER-APACHE2 +// --output=./frame/nfts/src/weights.rs // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -85,6 +86,7 @@ pub trait WeightInfo { fn create_swap() -> Weight; fn cancel_swap() -> Weight; fn claim_swap() -> Weight; + fn mint_pre_signed(n: u32, ) -> Weight; } /// Weights for pallet_nfts using the Substrate node and recommended hardware. @@ -104,8 +106,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `214` // Estimated: `3054` - // Minimum execution time: 32_467 nanoseconds. - Weight::from_parts(33_236_000, 3054) + // Minimum execution time: 33_666 nanoseconds. + Weight::from_parts(34_405_000, 3054) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -123,8 +125,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `42` // Estimated: `3054` - // Minimum execution time: 22_198 nanoseconds. - Weight::from_parts(22_776_000, 3054) + // Minimum execution time: 22_028 nanoseconds. + Weight::from_parts(23_030_000, 3054) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -151,18 +153,16 @@ impl WeightInfo for SubstrateWeight { /// 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 { + fn destroy(_n: u32, m: u32, a: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `172781 + m * (127 ±0) + a * (402 ±0)` // Estimated: `3347427 + a * (2921 ±0) + m * (2615 ±0)` - // Minimum execution time: 24_021_657 nanoseconds. - Weight::from_parts(16_029_391_606, 3347427) - // Standard Error: 20_364 - .saturating_add(Weight::from_ref_time(300_580).saturating_mul(n.into())) - // Standard Error: 20_364 - .saturating_add(Weight::from_ref_time(7_748_502).saturating_mul(m.into())) - // Standard Error: 20_364 - .saturating_add(Weight::from_ref_time(9_183_566).saturating_mul(a.into())) + // Minimum execution time: 27_944_985 nanoseconds. + Weight::from_parts(19_865_318_850, 3347427) + // Standard Error: 32_345 + .saturating_add(Weight::from_ref_time(8_729_316).saturating_mul(m.into())) + // Standard Error: 32_345 + .saturating_add(Weight::from_ref_time(10_264_491).saturating_mul(a.into())) .saturating_add(T::DbWeight::get().reads(1004_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(m.into()))) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(a.into()))) @@ -188,8 +188,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `448` // Estimated: `13506` - // Minimum execution time: 42_634 nanoseconds. - Weight::from_parts(43_231_000, 13506) + // Minimum execution time: 43_925 nanoseconds. + Weight::from_parts(45_885_000, 13506) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -209,8 +209,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `448` // Estimated: `13506` - // Minimum execution time: 41_686 nanoseconds. - Weight::from_parts(41_991_000, 13506) + // Minimum execution time: 42_832 nanoseconds. + Weight::from_parts(44_621_000, 13506) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -236,8 +236,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `647` // Estimated: `13573` - // Minimum execution time: 45_192 nanoseconds. - Weight::from_parts(45_792_000, 13573) + // Minimum execution time: 47_787 nanoseconds. + Weight::from_parts(49_204_000, 13573) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } @@ -263,8 +263,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `882` // Estimated: `16109` - // Minimum execution time: 51_962 nanoseconds. - Weight::from_parts(52_367_000, 16109) + // Minimum execution time: 55_524 nanoseconds. + Weight::from_parts(56_962_000, 16109) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -279,10 +279,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `756 + i * (140 ±0)` // Estimated: `5103 + i * (3336 ±0)` - // Minimum execution time: 15_512 nanoseconds. - Weight::from_parts(15_731_000, 5103) - // Standard Error: 9_495 - .saturating_add(Weight::from_ref_time(11_462_413).saturating_mul(i.into())) + // Minimum execution time: 15_246 nanoseconds. + Weight::from_parts(15_671_000, 5103) + // Standard Error: 20_348 + .saturating_add(Weight::from_ref_time(14_692_422).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(i.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) @@ -296,8 +296,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `401` // Estimated: `5067` - // Minimum execution time: 19_273 nanoseconds. - Weight::from_parts(19_508_000, 5067) + // Minimum execution time: 19_270 nanoseconds. + Weight::from_parts(19_775_000, 5067) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -309,8 +309,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `401` // Estimated: `5067` - // Minimum execution time: 19_022 nanoseconds. - Weight::from_parts(19_430_000, 5067) + // Minimum execution time: 19_364 nanoseconds. + Weight::from_parts(20_274_000, 5067) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -322,8 +322,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `289` // Estimated: `5092` - // Minimum execution time: 17_593 nanoseconds. - Weight::from_parts(17_950_000, 5092) + // Minimum execution time: 17_036 nanoseconds. + Weight::from_parts(17_750_000, 5092) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -337,8 +337,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `381` // Estimated: `5082` - // Minimum execution time: 22_068 nanoseconds. - Weight::from_parts(22_235_000, 5082) + // Minimum execution time: 22_104 nanoseconds. + Weight::from_parts(23_022_000, 5082) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -350,8 +350,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `362` // Estimated: `2555` - // Minimum execution time: 25_056 nanoseconds. - Weight::from_parts(25_767_000, 2555) + // Minimum execution time: 24_516 nanoseconds. + Weight::from_parts(25_300_000, 2555) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -363,8 +363,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `304` // Estimated: `2555` - // Minimum execution time: 17_398 nanoseconds. - Weight::from_parts(17_684_000, 2555) + // Minimum execution time: 16_974 nanoseconds. + Weight::from_parts(17_654_000, 2555) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -376,8 +376,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `242` // Estimated: `2555` - // Minimum execution time: 14_054 nanoseconds. - Weight::from_parts(14_243_000, 2555) + // Minimum execution time: 13_190 nanoseconds. + Weight::from_parts(13_826_000, 2555) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -389,8 +389,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `445` // Estimated: `5078` - // Minimum execution time: 17_662 nanoseconds. - Weight::from_parts(18_073_000, 5078) + // Minimum execution time: 17_336 nanoseconds. + Weight::from_parts(18_242_000, 5078) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -406,8 +406,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `474` // Estimated: `10547` - // Minimum execution time: 40_098 nanoseconds. - Weight::from_parts(40_649_000, 10547) + // Minimum execution time: 40_791 nanoseconds. + Weight::from_parts(42_489_000, 10547) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -419,8 +419,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `337` // Estimated: `5476` - // Minimum execution time: 25_178 nanoseconds. - Weight::from_parts(25_473_000, 5476) + // Minimum execution time: 24_620 nanoseconds. + Weight::from_parts(25_370_000, 5476) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -434,8 +434,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `916` // Estimated: `7999` - // Minimum execution time: 35_202 nanoseconds. - Weight::from_parts(35_518_000, 7999) + // Minimum execution time: 36_411 nanoseconds. + Weight::from_parts(37_439_000, 7999) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -447,8 +447,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `379` // Estimated: `6492` - // Minimum execution time: 17_260 nanoseconds. - Weight::from_parts(17_498_000, 6492) + // Minimum execution time: 16_696 nanoseconds. + Weight::from_parts(17_411_000, 6492) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -463,12 +463,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 1000]`. fn cancel_item_attributes_approval(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `865 + n * (367 ±0)` + // Measured: `899 + n * (396 ±0)` // Estimated: `12016 + n * (2921 ±0)` - // Minimum execution time: 25_579 nanoseconds. - Weight::from_parts(25_846_000, 12016) - // Standard Error: 7_759 - .saturating_add(Weight::from_ref_time(7_159_200).saturating_mul(n.into())) + // Minimum execution time: 25_928 nanoseconds. + Weight::from_parts(26_440_000, 12016) + // Standard Error: 9_158 + .saturating_add(Weight::from_ref_time(9_271_441).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) @@ -487,8 +487,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `474` // Estimated: `10241` - // Minimum execution time: 33_285 nanoseconds. - Weight::from_parts(33_692_000, 10241) + // Minimum execution time: 34_150 nanoseconds. + Weight::from_parts(35_398_000, 10241) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -502,8 +502,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `609` // Estimated: `7693` - // Minimum execution time: 30_670 nanoseconds. - Weight::from_parts(31_282_000, 7693) + // Minimum execution time: 31_871 nanoseconds. + Weight::from_parts(33_057_000, 7693) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -517,8 +517,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `333` // Estimated: `7665` - // Minimum execution time: 28_313 nanoseconds. - Weight::from_parts(28_724_000, 7665) + // Minimum execution time: 28_843 nanoseconds. + Weight::from_parts(30_057_000, 7665) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -532,8 +532,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `476` // Estimated: `7665` - // Minimum execution time: 27_034 nanoseconds. - Weight::from_parts(27_655_000, 7665) + // Minimum execution time: 27_777 nanoseconds. + Weight::from_parts(28_471_000, 7665) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -547,8 +547,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `466` // Estimated: `8428` - // Minimum execution time: 23_408 nanoseconds. - Weight::from_parts(23_916_000, 8428) + // Minimum execution time: 23_726 nanoseconds. + Weight::from_parts(24_455_000, 8428) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -560,8 +560,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `474` // Estimated: `5880` - // Minimum execution time: 21_177 nanoseconds. - Weight::from_parts(21_492_000, 5880) + // Minimum execution time: 21_051 nanoseconds. + Weight::from_parts(21_722_000, 5880) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -573,8 +573,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `474` // Estimated: `5880` - // Minimum execution time: 20_279 nanoseconds. - Weight::from_parts(20_919_000, 5880) + // Minimum execution time: 20_095 nanoseconds. + Weight::from_parts(20_770_000, 5880) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -584,8 +584,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `42` // Estimated: `2527` - // Minimum execution time: 14_921 nanoseconds. - Weight::from_parts(15_382_000, 2527) + // Minimum execution time: 14_078 nanoseconds. + Weight::from_parts(14_582_000, 2527) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -597,8 +597,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `333` // Estimated: `5103` - // Minimum execution time: 18_201 nanoseconds. - Weight::from_parts(18_628_000, 5103) + // Minimum execution time: 17_677 nanoseconds. + Weight::from_parts(18_381_000, 5103) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -610,8 +610,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `333` // Estimated: `5103` - // Minimum execution time: 16_870 nanoseconds. - Weight::from_parts(17_318_000, 5103) + // Minimum execution time: 16_295 nanoseconds. + Weight::from_parts(17_036_000, 5103) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -627,8 +627,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `516` // Estimated: `8407` - // Minimum execution time: 22_604 nanoseconds. - Weight::from_parts(22_867_000, 8407) + // Minimum execution time: 22_847 nanoseconds. + Weight::from_parts(23_536_000, 8407) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -652,8 +652,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `934` // Estimated: `16129` - // Minimum execution time: 56_849 nanoseconds. - Weight::from_parts(57_336_000, 16129) + // Minimum execution time: 60_517 nanoseconds. + Weight::from_parts(62_528_000, 16129) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -662,10 +662,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_308 nanoseconds. - Weight::from_ref_time(4_805_401) - // Standard Error: 13_875 - .saturating_add(Weight::from_ref_time(3_167_190).saturating_mul(n.into())) + // Minimum execution time: 1_866 nanoseconds. + Weight::from_ref_time(3_949_301) + // Standard Error: 11_044 + .saturating_add(Weight::from_ref_time(3_424_466).saturating_mul(n.into())) } /// Storage: Nfts Item (r:2 w:0) /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) @@ -675,8 +675,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `524` // Estimated: `6672` - // Minimum execution time: 20_395 nanoseconds. - Weight::from_parts(20_716_000, 6672) + // Minimum execution time: 21_174 nanoseconds. + Weight::from_parts(21_619_000, 6672) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -688,8 +688,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `511` // Estimated: `5882` - // Minimum execution time: 19_936 nanoseconds. - Weight::from_parts(20_344_000, 5882) + // Minimum execution time: 20_606 nanoseconds. + Weight::from_parts(21_150_000, 5882) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -713,11 +713,42 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1097` // Estimated: `21970` - // Minimum execution time: 80_884 nanoseconds. - Weight::from_parts(81_643_000, 21970) + // Minimum execution time: 88_414 nanoseconds. + Weight::from_parts(91_830_000, 21970) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(11_u64)) } + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:0) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts Item (r:1 w:1) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:1 w:1) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Nfts Attribute (r:10 w:10) + /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) + /// Storage: Nfts ItemMetadataOf (r:1 w:1) + /// Proof: Nfts ItemMetadataOf (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) + /// Storage: Nfts Account (r:0 w:1) + /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) + /// The range of component `n` is `[0, 10]`. + fn mint_pre_signed(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `596` + // Estimated: `16180 + n * (2921 ±0)` + // Minimum execution time: 124_354 nanoseconds. + Weight::from_parts(133_779_491, 16180) + // Standard Error: 38_452 + .saturating_add(Weight::from_ref_time(25_110_697).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes(6_u64)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_proof_size(2921).saturating_mul(n.into())) + } } // For backwards compatibility and tests @@ -736,8 +767,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `214` // Estimated: `3054` - // Minimum execution time: 32_467 nanoseconds. - Weight::from_parts(33_236_000, 3054) + // Minimum execution time: 33_666 nanoseconds. + Weight::from_parts(34_405_000, 3054) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -755,8 +786,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `42` // Estimated: `3054` - // Minimum execution time: 22_198 nanoseconds. - Weight::from_parts(22_776_000, 3054) + // Minimum execution time: 22_028 nanoseconds. + Weight::from_parts(23_030_000, 3054) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -783,18 +814,16 @@ impl WeightInfo for () { /// 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 { + fn destroy(_n: u32, m: u32, a: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `172781 + m * (127 ±0) + a * (402 ±0)` // Estimated: `3347427 + a * (2921 ±0) + m * (2615 ±0)` - // Minimum execution time: 24_021_657 nanoseconds. - Weight::from_parts(16_029_391_606, 3347427) - // Standard Error: 20_364 - .saturating_add(Weight::from_ref_time(300_580).saturating_mul(n.into())) - // Standard Error: 20_364 - .saturating_add(Weight::from_ref_time(7_748_502).saturating_mul(m.into())) - // Standard Error: 20_364 - .saturating_add(Weight::from_ref_time(9_183_566).saturating_mul(a.into())) + // Minimum execution time: 27_944_985 nanoseconds. + Weight::from_parts(19_865_318_850, 3347427) + // Standard Error: 32_345 + .saturating_add(Weight::from_ref_time(8_729_316).saturating_mul(m.into())) + // Standard Error: 32_345 + .saturating_add(Weight::from_ref_time(10_264_491).saturating_mul(a.into())) .saturating_add(RocksDbWeight::get().reads(1004_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(m.into()))) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(a.into()))) @@ -820,8 +849,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `448` // Estimated: `13506` - // Minimum execution time: 42_634 nanoseconds. - Weight::from_parts(43_231_000, 13506) + // Minimum execution time: 43_925 nanoseconds. + Weight::from_parts(45_885_000, 13506) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -841,8 +870,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `448` // Estimated: `13506` - // Minimum execution time: 41_686 nanoseconds. - Weight::from_parts(41_991_000, 13506) + // Minimum execution time: 42_832 nanoseconds. + Weight::from_parts(44_621_000, 13506) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -868,8 +897,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `647` // Estimated: `13573` - // Minimum execution time: 45_192 nanoseconds. - Weight::from_parts(45_792_000, 13573) + // Minimum execution time: 47_787 nanoseconds. + Weight::from_parts(49_204_000, 13573) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } @@ -895,8 +924,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `882` // Estimated: `16109` - // Minimum execution time: 51_962 nanoseconds. - Weight::from_parts(52_367_000, 16109) + // Minimum execution time: 55_524 nanoseconds. + Weight::from_parts(56_962_000, 16109) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -911,10 +940,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `756 + i * (140 ±0)` // Estimated: `5103 + i * (3336 ±0)` - // Minimum execution time: 15_512 nanoseconds. - Weight::from_parts(15_731_000, 5103) - // Standard Error: 9_495 - .saturating_add(Weight::from_ref_time(11_462_413).saturating_mul(i.into())) + // Minimum execution time: 15_246 nanoseconds. + Weight::from_parts(15_671_000, 5103) + // Standard Error: 20_348 + .saturating_add(Weight::from_ref_time(14_692_422).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(i.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(i.into()))) @@ -928,8 +957,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `401` // Estimated: `5067` - // Minimum execution time: 19_273 nanoseconds. - Weight::from_parts(19_508_000, 5067) + // Minimum execution time: 19_270 nanoseconds. + Weight::from_parts(19_775_000, 5067) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -941,8 +970,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `401` // Estimated: `5067` - // Minimum execution time: 19_022 nanoseconds. - Weight::from_parts(19_430_000, 5067) + // Minimum execution time: 19_364 nanoseconds. + Weight::from_parts(20_274_000, 5067) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -954,8 +983,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `289` // Estimated: `5092` - // Minimum execution time: 17_593 nanoseconds. - Weight::from_parts(17_950_000, 5092) + // Minimum execution time: 17_036 nanoseconds. + Weight::from_parts(17_750_000, 5092) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -969,8 +998,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `381` // Estimated: `5082` - // Minimum execution time: 22_068 nanoseconds. - Weight::from_parts(22_235_000, 5082) + // Minimum execution time: 22_104 nanoseconds. + Weight::from_parts(23_022_000, 5082) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -982,8 +1011,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `362` // Estimated: `2555` - // Minimum execution time: 25_056 nanoseconds. - Weight::from_parts(25_767_000, 2555) + // Minimum execution time: 24_516 nanoseconds. + Weight::from_parts(25_300_000, 2555) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -995,8 +1024,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `304` // Estimated: `2555` - // Minimum execution time: 17_398 nanoseconds. - Weight::from_parts(17_684_000, 2555) + // Minimum execution time: 16_974 nanoseconds. + Weight::from_parts(17_654_000, 2555) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -1008,8 +1037,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `242` // Estimated: `2555` - // Minimum execution time: 14_054 nanoseconds. - Weight::from_parts(14_243_000, 2555) + // Minimum execution time: 13_190 nanoseconds. + Weight::from_parts(13_826_000, 2555) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1021,8 +1050,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `445` // Estimated: `5078` - // Minimum execution time: 17_662 nanoseconds. - Weight::from_parts(18_073_000, 5078) + // Minimum execution time: 17_336 nanoseconds. + Weight::from_parts(18_242_000, 5078) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1038,8 +1067,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `474` // Estimated: `10547` - // Minimum execution time: 40_098 nanoseconds. - Weight::from_parts(40_649_000, 10547) + // Minimum execution time: 40_791 nanoseconds. + Weight::from_parts(42_489_000, 10547) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1051,8 +1080,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `337` // Estimated: `5476` - // Minimum execution time: 25_178 nanoseconds. - Weight::from_parts(25_473_000, 5476) + // Minimum execution time: 24_620 nanoseconds. + Weight::from_parts(25_370_000, 5476) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1066,8 +1095,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `916` // Estimated: `7999` - // Minimum execution time: 35_202 nanoseconds. - Weight::from_parts(35_518_000, 7999) + // Minimum execution time: 36_411 nanoseconds. + Weight::from_parts(37_439_000, 7999) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1079,8 +1108,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `379` // Estimated: `6492` - // Minimum execution time: 17_260 nanoseconds. - Weight::from_parts(17_498_000, 6492) + // Minimum execution time: 16_696 nanoseconds. + Weight::from_parts(17_411_000, 6492) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1095,12 +1124,12 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 1000]`. fn cancel_item_attributes_approval(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `865 + n * (367 ±0)` + // Measured: `899 + n * (396 ±0)` // Estimated: `12016 + n * (2921 ±0)` - // Minimum execution time: 25_579 nanoseconds. - Weight::from_parts(25_846_000, 12016) - // Standard Error: 7_759 - .saturating_add(Weight::from_ref_time(7_159_200).saturating_mul(n.into())) + // Minimum execution time: 25_928 nanoseconds. + Weight::from_parts(26_440_000, 12016) + // Standard Error: 9_158 + .saturating_add(Weight::from_ref_time(9_271_441).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(2_u64)) @@ -1119,8 +1148,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `474` // Estimated: `10241` - // Minimum execution time: 33_285 nanoseconds. - Weight::from_parts(33_692_000, 10241) + // Minimum execution time: 34_150 nanoseconds. + Weight::from_parts(35_398_000, 10241) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1134,8 +1163,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `609` // Estimated: `7693` - // Minimum execution time: 30_670 nanoseconds. - Weight::from_parts(31_282_000, 7693) + // Minimum execution time: 31_871 nanoseconds. + Weight::from_parts(33_057_000, 7693) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1149,8 +1178,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `333` // Estimated: `7665` - // Minimum execution time: 28_313 nanoseconds. - Weight::from_parts(28_724_000, 7665) + // Minimum execution time: 28_843 nanoseconds. + Weight::from_parts(30_057_000, 7665) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1164,8 +1193,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `476` // Estimated: `7665` - // Minimum execution time: 27_034 nanoseconds. - Weight::from_parts(27_655_000, 7665) + // Minimum execution time: 27_777 nanoseconds. + Weight::from_parts(28_471_000, 7665) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1179,8 +1208,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `466` // Estimated: `8428` - // Minimum execution time: 23_408 nanoseconds. - Weight::from_parts(23_916_000, 8428) + // Minimum execution time: 23_726 nanoseconds. + Weight::from_parts(24_455_000, 8428) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1192,8 +1221,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `474` // Estimated: `5880` - // Minimum execution time: 21_177 nanoseconds. - Weight::from_parts(21_492_000, 5880) + // Minimum execution time: 21_051 nanoseconds. + Weight::from_parts(21_722_000, 5880) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1205,8 +1234,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `474` // Estimated: `5880` - // Minimum execution time: 20_279 nanoseconds. - Weight::from_parts(20_919_000, 5880) + // Minimum execution time: 20_095 nanoseconds. + Weight::from_parts(20_770_000, 5880) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1216,8 +1245,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `42` // Estimated: `2527` - // Minimum execution time: 14_921 nanoseconds. - Weight::from_parts(15_382_000, 2527) + // Minimum execution time: 14_078 nanoseconds. + Weight::from_parts(14_582_000, 2527) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1229,8 +1258,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `333` // Estimated: `5103` - // Minimum execution time: 18_201 nanoseconds. - Weight::from_parts(18_628_000, 5103) + // Minimum execution time: 17_677 nanoseconds. + Weight::from_parts(18_381_000, 5103) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1242,8 +1271,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `333` // Estimated: `5103` - // Minimum execution time: 16_870 nanoseconds. - Weight::from_parts(17_318_000, 5103) + // Minimum execution time: 16_295 nanoseconds. + Weight::from_parts(17_036_000, 5103) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1259,8 +1288,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `516` // Estimated: `8407` - // Minimum execution time: 22_604 nanoseconds. - Weight::from_parts(22_867_000, 8407) + // Minimum execution time: 22_847 nanoseconds. + Weight::from_parts(23_536_000, 8407) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1284,8 +1313,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `934` // Estimated: `16129` - // Minimum execution time: 56_849 nanoseconds. - Weight::from_parts(57_336_000, 16129) + // Minimum execution time: 60_517 nanoseconds. + Weight::from_parts(62_528_000, 16129) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -1294,10 +1323,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_308 nanoseconds. - Weight::from_ref_time(4_805_401) - // Standard Error: 13_875 - .saturating_add(Weight::from_ref_time(3_167_190).saturating_mul(n.into())) + // Minimum execution time: 1_866 nanoseconds. + Weight::from_ref_time(3_949_301) + // Standard Error: 11_044 + .saturating_add(Weight::from_ref_time(3_424_466).saturating_mul(n.into())) } /// Storage: Nfts Item (r:2 w:0) /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) @@ -1307,8 +1336,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `524` // Estimated: `6672` - // Minimum execution time: 20_395 nanoseconds. - Weight::from_parts(20_716_000, 6672) + // Minimum execution time: 21_174 nanoseconds. + Weight::from_parts(21_619_000, 6672) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1320,8 +1349,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `511` // Estimated: `5882` - // Minimum execution time: 19_936 nanoseconds. - Weight::from_parts(20_344_000, 5882) + // Minimum execution time: 20_606 nanoseconds. + Weight::from_parts(21_150_000, 5882) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1345,9 +1374,40 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1097` // Estimated: `21970` - // Minimum execution time: 80_884 nanoseconds. - Weight::from_parts(81_643_000, 21970) + // Minimum execution time: 88_414 nanoseconds. + Weight::from_parts(91_830_000, 21970) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(11_u64)) } + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:0) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts Item (r:1 w:1) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:1 w:1) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Nfts Attribute (r:10 w:10) + /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) + /// Storage: Nfts ItemMetadataOf (r:1 w:1) + /// Proof: Nfts ItemMetadataOf (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) + /// Storage: Nfts Account (r:0 w:1) + /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) + /// The range of component `n` is `[0, 10]`. + fn mint_pre_signed(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `596` + // Estimated: `16180 + n * (2921 ±0)` + // Minimum execution time: 124_354 nanoseconds. + Weight::from_parts(133_779_491, 16180) + // Standard Error: 38_452 + .saturating_add(Weight::from_ref_time(25_110_697).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) + .saturating_add(RocksDbWeight::get().writes(6_u64)) + .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_proof_size(2921).saturating_mul(n.into())) + } } From ef1c36114d7f0be2d9ae9b3af7e36a2014ee6e97 Mon Sep 17 00:00:00 2001 From: yjh Date: Tue, 14 Feb 2023 21:17:14 +0800 Subject: [PATCH 390/715] feat: improve FinalityProofProvider api (#13374) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: improve prove_finality api and export it * fmt * fix * improve prove_finality and kept private * Update client/finality-grandpa/src/finality_proof.rs Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> * add `prove_finality_proof` to `FinalityProofProvider` * fix some and impl Clone for FinalityProofProvider * improve by suggestions --------- Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> --- client/finality-grandpa/src/finality_proof.rs | 91 +++++++++++++------ 1 file changed, 61 insertions(+), 30 deletions(-) diff --git a/client/finality-grandpa/src/finality_proof.rs b/client/finality-grandpa/src/finality_proof.rs index 416e71478ab4d..af3ed6e14ee2d 100644 --- a/client/finality-grandpa/src/finality_proof.rs +++ b/client/finality-grandpa/src/finality_proof.rs @@ -58,6 +58,7 @@ use crate::{ const MAX_UNKNOWN_HEADERS: usize = 100_000; /// Finality proof provider for serving network requests. +#[derive(Clone)] pub struct FinalityProofProvider { backend: Arc, shared_authority_set: Option>>, @@ -99,11 +100,24 @@ where B: Backend, { /// Prove finality for the given block number by returning a Justification for the last block of - /// the authority set. + /// the authority set in bytes. pub fn prove_finality( &self, block: NumberFor, ) -> Result>, FinalityProofError> { + Ok(self.prove_finality_proof(block, true)?.map(|proof| proof.encode())) + } + + /// Prove finality for the given block number by returning a Justification for the last block of + /// the authority set. + /// + /// If `collect_unknown_headers` is true, the finality proof will include all headers from the + /// requested block until the block the justification refers to. + pub fn prove_finality_proof( + &self, + block: NumberFor, + collect_unknown_headers: bool, + ) -> Result>, FinalityProofError> { let authority_set_changes = if let Some(changes) = self .shared_authority_set .as_ref() @@ -114,7 +128,7 @@ where return Ok(None) }; - prove_finality(&*self.backend, authority_set_changes, block) + prove_finality(&*self.backend, authority_set_changes, block, collect_unknown_headers) } } @@ -146,22 +160,29 @@ pub enum FinalityProofError { Client(#[from] sp_blockchain::Error), } +/// Prove finality for the given block number by returning a justification for the last block of +/// the authority set of which the given block is part of, or a justification for the latest +/// finalized block if the given block is part of the current authority set. +/// +/// If `collect_unknown_headers` is true, the finality proof will include all headers from the +/// requested block until the block the justification refers to. fn prove_finality( backend: &B, authority_set_changes: AuthoritySetChanges>, block: NumberFor, -) -> Result>, FinalityProofError> + collect_unknown_headers: bool, +) -> Result>, FinalityProofError> where Block: BlockT, B: Backend, { // Early-return if we are sure that there are no blocks finalized that cover the requested // block. - let info = backend.blockchain().info(); - if info.finalized_number < block { + let finalized_number = backend.blockchain().info().finalized_number; + if finalized_number < block { let err = format!( "Requested finality proof for descendant of #{} while we only have finalized #{}.", - block, info.finalized_number, + block, finalized_number, ); trace!(target: LOG_TARGET, "{}", &err); return Err(FinalityProofError::BlockNotYetFinalized) @@ -214,9 +235,9 @@ where }, }; - // Collect all headers from the requested block until the last block of the set - let unknown_headers = { - let mut headers = Vec::new(); + let mut headers = Vec::new(); + if collect_unknown_headers { + // Collect all headers from the requested block until the last block of the set let mut current = block + One::one(); loop { if current > just_block || headers.len() >= MAX_UNKNOWN_HEADERS { @@ -226,17 +247,13 @@ where headers.push(backend.blockchain().expect_header(hash)?); current += One::one(); } - headers }; - Ok(Some( - FinalityProof { - block: backend.blockchain().expect_block_hash_from_id(&BlockId::Number(just_block))?, - justification, - unknown_headers, - } - .encode(), - )) + Ok(Some(FinalityProof { + block: backend.blockchain().expect_block_hash_from_id(&BlockId::Number(just_block))?, + justification, + unknown_headers: headers, + })) } #[cfg(test)] @@ -334,7 +351,7 @@ mod tests { let authority_set_changes = AuthoritySetChanges::empty(); // The last finalized block is 4, so we cannot provide further justifications. - let proof_of_5 = prove_finality(&*backend, authority_set_changes, 5); + let proof_of_5 = prove_finality(&*backend, authority_set_changes, 5, true); assert!(matches!(proof_of_5, Err(FinalityProofError::BlockNotYetFinalized))); } @@ -347,7 +364,7 @@ mod tests { // Block 4 is finalized without justification // => we can't prove finality of 3 - let proof_of_3 = prove_finality(&*backend, authority_set_changes, 3).unwrap(); + let proof_of_3 = prove_finality(&*backend, authority_set_changes, 3, true).unwrap(); assert_eq!(proof_of_3, None); } @@ -478,7 +495,7 @@ mod tests { let mut authority_set_changes = AuthoritySetChanges::empty(); authority_set_changes.append(1, 8); - let proof_of_6 = prove_finality(&*backend, authority_set_changes, 6); + let proof_of_6 = prove_finality(&*backend, authority_set_changes, 6, true); assert!(matches!(proof_of_6, Err(FinalityProofError::BlockNotInAuthoritySetChanges))); } @@ -502,10 +519,11 @@ mod tests { authority_set_changes.append(0, 5); authority_set_changes.append(1, 8); - let proof_of_6: FinalityProof = Decode::decode( - &mut &prove_finality(&*backend, authority_set_changes.clone(), 6).unwrap().unwrap()[..], - ) - .unwrap(); + let proof_of_6: FinalityProof = + prove_finality(&*backend, authority_set_changes.clone(), 6, true) + .unwrap() + .unwrap(); + assert_eq!( proof_of_6, FinalityProof { @@ -514,6 +532,20 @@ mod tests { unknown_headers: vec![block7.header().clone(), block8.header().clone()], }, ); + + let proof_of_6_without_unknown: FinalityProof = + prove_finality(&*backend, authority_set_changes.clone(), 6, false) + .unwrap() + .unwrap(); + + assert_eq!( + proof_of_6_without_unknown, + FinalityProof { + block: block8.hash(), + justification: grandpa_just8.encode(), + unknown_headers: vec![], + }, + ); } #[test] @@ -525,7 +557,7 @@ mod tests { let mut authority_set_changes = AuthoritySetChanges::empty(); authority_set_changes.append(0, 5); - assert!(matches!(prove_finality(&*backend, authority_set_changes, 6), Ok(None))); + assert!(matches!(prove_finality(&*backend, authority_set_changes, 6, true), Ok(None))); } #[test] @@ -544,10 +576,9 @@ mod tests { let mut authority_set_changes = AuthoritySetChanges::empty(); authority_set_changes.append(0, 5); - let proof_of_6: FinalityProof = Decode::decode( - &mut &prove_finality(&*backend, authority_set_changes, 6).unwrap().unwrap()[..], - ) - .unwrap(); + let proof_of_6: FinalityProof = + prove_finality(&*backend, authority_set_changes, 6, true).unwrap().unwrap(); + assert_eq!( proof_of_6, FinalityProof { From e6f6c8c0e90e512f19bc4da43234a76224a65610 Mon Sep 17 00:00:00 2001 From: Vivek Pandya Date: Tue, 14 Feb 2023 19:39:36 +0530 Subject: [PATCH 391/715] cleanup `` from docs comments (#13350) * cleanup from docs comments * Changes to address review commnets * Fix CI cargo test --docs --------- Co-authored-by: parity-processbot <> --- frame/balances/src/lib.rs | 14 +- frame/bounties/src/lib.rs | 24 ++-- frame/collective/src/lib.rs | 82 ++--------- frame/democracy/src/lib.rs | 10 +- frame/elections-phragmen/src/lib.rs | 23 ++-- frame/identity/src/lib.rs | 80 ++++------- frame/im-online/src/lib.rs | 10 +- frame/indices/src/lib.rs | 44 +----- frame/multisig/src/lib.rs | 28 +--- frame/nicks/src/lib.rs | 24 +--- frame/scheduler/src/lib.rs | 8 -- frame/session/src/lib.rs | 21 +-- frame/society/src/lib.rs | 198 +++++++-------------------- frame/staking/src/pallet/mod.rs | 73 +++------- frame/sudo/src/lib.rs | 21 +-- frame/system/src/lib.rs | 24 +--- frame/timestamp/src/lib.rs | 7 +- frame/tips/src/lib.rs | 49 +++---- frame/transaction-storage/src/lib.rs | 16 +-- frame/treasury/src/lib.rs | 36 ++--- frame/utility/src/lib.rs | 21 +-- frame/vesting/src/lib.rs | 24 +--- 22 files changed, 202 insertions(+), 635 deletions(-) diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index 99d77a3e73361..f62ea6be7d3eb 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -267,7 +267,7 @@ pub mod pallet { /// /// The dispatch origin for this call must be `Signed` by the transactor. /// - /// # + /// ## Complexity /// - Dependent on arguments but not critical, given proper implementations for input config /// types. See related functions below. /// - It contains a limited number of reads and writes internally and no complex @@ -281,9 +281,6 @@ pub mod pallet { /// - Removing enough funds from an account will trigger `T::DustRemoval::on_unbalanced`. /// - `transfer_keep_alive` works the same way as `transfer`, but has an additional check /// that the transfer will not kill the origin account. - /// --------------------------------- - /// - Origin account is already in memory, so no DB operations for them. - /// # #[pallet::call_index(0)] #[pallet::weight(T::WeightInfo::transfer())] pub fn transfer( @@ -360,10 +357,9 @@ pub mod pallet { /// Exactly as `transfer`, except the origin must be root and the source account may be /// specified. - /// # + /// ## Complexity /// - 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( @@ -417,9 +413,8 @@ pub mod pallet { /// - `keep_alive`: A boolean to determine if the `transfer_all` operation should send all /// of the funds the account has, causing the sender account to be killed (false), or /// transfer everything except at least the existential deposit, which will guarantee to - /// keep the sender account alive (true). # + /// keep the sender account alive (true). ## Complexity /// - 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( @@ -1484,10 +1479,9 @@ where // restrictions like locks and vesting balance. // Is a no-op if amount to be withdrawn is zero. // - // # + // ## Complexity // Despite iterating over a list of locks, they are limited by the number of // lock IDs, which means the number of runtime pallets that intend to use and create locks. - // # fn ensure_can_withdraw( who: &T::AccountId, amount: T::Balance, diff --git a/frame/bounties/src/lib.rs b/frame/bounties/src/lib.rs index c3c2c08d24b2a..afdcfef8279bd 100644 --- a/frame/bounties/src/lib.rs +++ b/frame/bounties/src/lib.rs @@ -349,9 +349,8 @@ pub mod pallet { /// /// May only be called from `T::SpendOrigin`. /// - /// # + /// ## Complexity /// - O(1). - /// # #[pallet::call_index(1)] #[pallet::weight(>::WeightInfo::approve_bounty())] pub fn approve_bounty( @@ -381,9 +380,8 @@ pub mod pallet { /// /// May only be called from `T::SpendOrigin`. /// - /// # + /// ## Complexity /// - O(1). - /// # #[pallet::call_index(2)] #[pallet::weight(>::WeightInfo::propose_curator())] pub fn propose_curator( @@ -431,9 +429,8 @@ pub mod pallet { /// anyone in the community to call out that a curator is not doing their due diligence, and /// we should pick a new curator. In this case the curator should also be slashed. /// - /// # + /// ## Complexity /// - O(1). - /// # #[pallet::call_index(3)] #[pallet::weight(>::WeightInfo::unassign_curator())] pub fn unassign_curator( @@ -517,9 +514,8 @@ pub mod pallet { /// /// May only be called from the curator. /// - /// # + /// ## Complexity /// - O(1). - /// # #[pallet::call_index(4)] #[pallet::weight(>::WeightInfo::accept_curator())] pub fn accept_curator( @@ -560,9 +556,8 @@ pub mod pallet { /// - `bounty_id`: Bounty ID to award. /// - `beneficiary`: The beneficiary account whom will receive the payout. /// - /// # + /// ## Complexity /// - O(1). - /// # #[pallet::call_index(5)] #[pallet::weight(>::WeightInfo::award_bounty())] pub fn award_bounty( @@ -608,9 +603,8 @@ pub mod pallet { /// /// - `bounty_id`: Bounty ID to claim. /// - /// # + /// ## Complexity /// - O(1). - /// # #[pallet::call_index(6)] #[pallet::weight(>::WeightInfo::claim_bounty())] pub fn claim_bounty( @@ -672,9 +666,8 @@ pub mod pallet { /// /// - `bounty_id`: Bounty ID to cancel. /// - /// # + /// ## Complexity /// - O(1). - /// # #[pallet::call_index(7)] #[pallet::weight(>::WeightInfo::close_bounty_proposed() .max(>::WeightInfo::close_bounty_active()))] @@ -764,9 +757,8 @@ pub mod pallet { /// - `bounty_id`: Bounty ID to extend. /// - `remark`: additional information. /// - /// # + /// ## Complexity /// - O(1). - /// # #[pallet::call_index(8)] #[pallet::weight(>::WeightInfo::extend_bounty_expiry())] pub fn extend_bounty_expiry( diff --git a/frame/collective/src/lib.rs b/frame/collective/src/lib.rs index 7d625a69a4bf7..8424527b154a4 100644 --- a/frame/collective/src/lib.rs +++ b/frame/collective/src/lib.rs @@ -364,19 +364,11 @@ pub mod pallet { /// 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 + /// ## Complexity: /// - `O(MP + N)` where: /// - `M` old-members-count (code- and governance-bounded) /// - `N` new-members-count (code- and governance-bounded) /// - `P` proposals-count (code-bounded) - /// - DB: - /// - 1 storage mutation (codec `O(M)` read, `O(N)` write) for reading and writing the - /// members - /// - 1 storage read (codec `O(P)`) for reading the proposals - /// - `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( @@ -428,13 +420,11 @@ pub mod pallet { /// /// Origin must be a member of the collective. /// - /// # - /// ## Weight - /// - `O(M + P)` where `M` members-count (code-bounded) and `P` complexity of dispatching - /// `proposal` - /// - DB: 1 read (codec `O(M)`) + DB access of `proposal` - /// - 1 event - /// # + /// ## Complexity: + /// - `O(B + M + P)` where: + /// - `B` is `proposal` size in bytes (length-fee-bounded) + /// - `M` members-count (code-bounded) + /// - `P` complexity of dispatching `proposal` #[pallet::call_index(1)] #[pallet::weight(( T::WeightInfo::execute( @@ -479,26 +469,13 @@ pub mod pallet { /// `threshold` determines whether `proposal` is executed directly (`threshold < 2`) /// or put up for voting. /// - /// # - /// ## Weight + /// ## Complexity /// - `O(B + M + P1)` or `O(B + M + P2)` where: /// - `B` is `proposal` size in bytes (length-fee-bounded) /// - `M` is members-count (code- and governance-bounded) /// - branching is influenced by `threshold` where: /// - `P1` is proposal execution complexity (`threshold < 2`) /// - `P2` is proposals-count (code-bounded) (`threshold >= 2`) - /// - DB: - /// - 1 storage read `is_member` (codec `O(M)`) - /// - 1 storage read `ProposalOf::contains_key` (codec `O(1)`) - /// - DB accesses influenced by `threshold`: - /// - EITHER storage accesses done by `proposal` (`threshold < 2`) - /// - OR proposal insertion (`threshold <= 2`) - /// - 1 storage mutation `Proposals` (codec `O(P2)`) - /// - 1 storage mutation `ProposalCount` (codec `O(1)`) - /// - 1 storage write `ProposalOf` (codec `O(B)`) - /// - 1 storage write `Voting` (codec `O(M)`) - /// - 1 event - /// # #[pallet::call_index(2)] #[pallet::weight(( if *threshold < 2 { @@ -557,14 +534,8 @@ pub mod pallet { /// Transaction fees will 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 + /// ## Complexity /// - `O(M)` where `M` is members-count (code- and governance-bounded) - /// - DB: - /// - 1 storage read `Members` (codec `O(M)`) - /// - 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( @@ -605,20 +576,12 @@ pub mod pallet { /// + `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 + /// ## Complexity /// - `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::call_index(4)] #[pallet::weight(( { @@ -657,12 +620,8 @@ pub mod pallet { /// Parameters: /// * `proposal_hash`: The hash of the proposal that should be disapproved. /// - /// # - /// Complexity: O(P) where P is the number of max proposals - /// DB Weight: - /// * Reads: Proposals - /// * Writes: Voting, Proposals, ProposalOf - /// # + /// ## Complexity + /// O(P) where P is the number of max proposals #[pallet::call_index(5)] #[pallet::weight(T::WeightInfo::disapprove_proposal(T::MaxProposals::get()))] pub fn disapprove_proposal( @@ -692,20 +651,12 @@ pub mod pallet { /// + `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 + /// ## Complexity /// - `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::call_index(6)] #[pallet::weight(( { @@ -1026,18 +977,11 @@ impl, I: 'static> ChangeMembers for 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. /// - /// # - /// ## Weight + /// ## Complexity /// - `O(MP + N)` /// - where `M` old-members-count (governance-bounded) /// - where `N` new-members-count (governance-bounded) /// - where `P` proposals-count - /// - DB: - /// - 1 storage read (codec `O(P)`) for reading the proposals - /// - `P` storage mutations for updating the votes (codec `O(M)`) - /// - 1 storage write (codec `O(N)`) for storing the new members - /// - 1 storage write (codec `O(1)`) for deleting the old prime - /// # fn change_members_sorted( _incoming: &[T::AccountId], outgoing: &[T::AccountId], diff --git a/frame/democracy/src/lib.rs b/frame/democracy/src/lib.rs index 3aa8bc0015d38..d9aae63ce6aae 100644 --- a/frame/democracy/src/lib.rs +++ b/frame/democracy/src/lib.rs @@ -1617,15 +1617,9 @@ impl Pallet { /// Current era is ending; we should finish up any proposals. /// /// - /// # + /// ## Complexity: /// 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` - /// - Db writes: `PublicProps`, `account`, `ReferendumCount`, `DepositOf`, `ReferendumInfoOf` - /// - Db reads per R: `DepositOf`, `ReferendumInfoOf` - /// # + /// empty. Otherwise, `O(R)` where `R` is the number of unbaked referenda. fn begin_block(now: T::BlockNumber) -> Weight { let max_block_weight = T::BlockWeights::get().max_block; let mut weight = Weight::zero(); diff --git a/frame/elections-phragmen/src/lib.rs b/frame/elections-phragmen/src/lib.rs index c655d4a16230b..37ee44f34dc3d 100644 --- a/frame/elections-phragmen/src/lib.rs +++ b/frame/elections-phragmen/src/lib.rs @@ -435,9 +435,9 @@ pub mod pallet { /// Even if a candidate ends up being a member, they must call [`Call::renounce_candidacy`] /// to get their deposit back. Losing the spot in an election will always lead to a slash. /// - /// # /// The number of current candidates must be provided as witness data. - /// # + /// ## Complexity + /// O(C + log(C)) where C is candidate_count. #[pallet::call_index(2)] #[pallet::weight(T::WeightInfo::submit_candidacy(*candidate_count))] pub fn submit_candidacy( @@ -479,10 +479,12 @@ pub mod pallet { /// next round. /// /// The dispatch origin of this call must be signed, and have one of the above roles. - /// - /// # /// The type of renouncing must be provided as witness data. - /// # + /// + /// ## Complexity + /// - Renouncing::Candidate(count): O(count + log(count)) + /// - Renouncing::Member: O(1) + /// - Renouncing::RunnerUp: O(1) #[pallet::call_index(3)] #[pallet::weight(match *renouncing { Renouncing::Candidate(count) => T::WeightInfo::renounce_candidacy_candidate(count), @@ -542,10 +544,8 @@ pub mod pallet { /// /// Note that this does not affect the designated block number of the next election. /// - /// # - /// 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. - /// # + /// ## Complexity + /// - Check details of remove_and_replace_member() and do_phragmen(). #[pallet::call_index(4)] #[pallet::weight(if *rerun_election { T::WeightInfo::remove_member_without_replacement() @@ -579,9 +579,8 @@ pub mod pallet { /// /// The dispatch origin of this call must be root. /// - /// # - /// The total number of voters and those that are defunct must be provided as witness data. - /// # + /// ## Complexity + /// - Check is_defunct_voter() details. #[pallet::call_index(5)] #[pallet::weight(T::WeightInfo::clean_defunct_voters(*_num_voters, *_num_defunct))] pub fn clean_defunct_voters( diff --git a/frame/identity/src/lib.rs b/frame/identity/src/lib.rs index 8eab2c67418a1..39d828ef26f83 100644 --- a/frame/identity/src/lib.rs +++ b/frame/identity/src/lib.rs @@ -279,11 +279,8 @@ pub mod pallet { /// /// Emits `RegistrarAdded` if successful. /// - /// # + /// ## Complexity /// - `O(R)` where `R` registrar-count (governance-bounded and code-bounded). - /// - 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( @@ -322,14 +319,10 @@ pub mod pallet { /// /// Emits `IdentitySet` if successful. /// - /// # + /// ## Complexity /// - `O(X + X' + R)` /// - where `X` additional-field-count (deposit-bounded and code-bounded) /// - where `R` judgements-count (registrar-count-bounded) - /// - One balance reserve operation. - /// - 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 @@ -389,17 +382,10 @@ pub mod pallet { /// /// - `subs`: The identity's (new) sub-accounts. /// - /// # + /// ## Complexity /// - `O(P + S)` /// - where `P` old-subs-count (hard- and deposit-bounded). /// - where `S` subs-count (hard- and deposit-bounded). - /// - At most one balance operations. - /// - DB: - /// - `P + S` storage mutations (codec complexity `O(1)`) - /// - One storage read (codec complexity `O(P)`). - /// - One storage write (codec complexity `O(S)`). - /// - One storage-exists (`IdentityOf::contains_key`). - /// # // TODO: This whole extrinsic screams "not optimized". For example we could // filter any overlap between new and old subs, and avoid reading/writing // to those values... We could also ideally avoid needing to write to @@ -469,15 +455,11 @@ pub mod pallet { /// /// Emits `IdentityCleared` if successful. /// - /// # + /// ## Complexity /// - `O(R + S + X)` /// - where `R` registrar-count (governance-bounded). /// - where `S` subs-count (hard- and deposit-bounded). /// - where `X` additional-field-count (deposit-bounded and code-bounded). - /// - One balance-unreserve operation. - /// - `2` storage reads and `S + 2` storage deletions. - /// - One event. - /// # #[pallet::call_index(3)] #[pallet::weight(T::WeightInfo::clear_identity( T::MaxRegistrars::get(), // R @@ -524,12 +506,10 @@ pub mod pallet { /// /// Emits `JudgementRequested` if successful. /// - /// # + /// ## Complexity /// - `O(R + X)`. - /// - One balance-reserve operation. - /// - Storage: 1 read `O(R)`, 1 mutate `O(X + R)`. - /// - One event. - /// # + /// - where `R` registrar-count (governance-bounded). + /// - where `X` additional-field-count (deposit-bounded and code-bounded). #[pallet::call_index(4)] #[pallet::weight(T::WeightInfo::request_judgement( T::MaxRegistrars::get(), // R @@ -587,12 +567,10 @@ pub mod pallet { /// /// Emits `JudgementUnrequested` if successful. /// - /// # + /// ## Complexity /// - `O(R + X)`. - /// - One balance-reserve operation. - /// - One storage mutation `O(R + X)`. - /// - One event - /// # + /// - where `R` registrar-count (governance-bounded). + /// - where `X` additional-field-count (deposit-bounded and code-bounded). #[pallet::call_index(5)] #[pallet::weight(T::WeightInfo::cancel_request( T::MaxRegistrars::get(), // R @@ -637,11 +615,9 @@ pub mod pallet { /// - `index`: the index of the registrar whose fee is to be set. /// - `fee`: the new fee. /// - /// # + /// ## Complexity /// - `O(R)`. - /// - One storage mutation `O(R)`. - /// - Benchmark: 7.315 + R * 0.329 µs (min squares analysis) - /// # + /// - where `R` registrar-count (governance-bounded). #[pallet::call_index(6)] #[pallet::weight(T::WeightInfo::set_fee(T::MaxRegistrars::get()))] // R pub fn set_fee( @@ -676,11 +652,9 @@ pub mod pallet { /// - `index`: the index of the registrar whose fee is to be set. /// - `new`: the new account ID. /// - /// # + /// ## Complexity /// - `O(R)`. - /// - One storage mutation `O(R)`. - /// - Benchmark: 8.823 + R * 0.32 µs (min squares analysis) - /// # + /// - where `R` registrar-count (governance-bounded). #[pallet::call_index(7)] #[pallet::weight(T::WeightInfo::set_account_id(T::MaxRegistrars::get()))] // R pub fn set_account_id( @@ -716,11 +690,9 @@ pub mod pallet { /// - `index`: the index of the registrar whose fee is to be set. /// - `fields`: the fields that the registrar concerns themselves with. /// - /// # + /// ## Complexity /// - `O(R)`. - /// - One storage mutation `O(R)`. - /// - Benchmark: 7.464 + R * 0.325 µs (min squares analysis) - /// # + /// - where `R` registrar-count (governance-bounded). #[pallet::call_index(8)] #[pallet::weight(T::WeightInfo::set_fields(T::MaxRegistrars::get()))] // R pub fn set_fields( @@ -763,13 +735,10 @@ pub mod pallet { /// /// Emits `JudgementGiven` if successful. /// - /// # + /// ## Complexity /// - `O(R + X)`. - /// - One balance-transfer operation. - /// - Up to one account-lookup operation. - /// - Storage: 1 read `O(R)`, 1 mutate `O(R + X)`. - /// - One event. - /// # + /// - where `R` registrar-count (governance-bounded). + /// - where `X` additional-field-count (deposit-bounded and code-bounded). #[pallet::call_index(9)] #[pallet::weight(T::WeightInfo::provide_judgement( T::MaxRegistrars::get(), // R @@ -838,12 +807,11 @@ pub mod pallet { /// /// Emits `IdentityKilled` if successful. /// - /// # - /// - `O(R + S + X)`. - /// - One balance-reserve operation. - /// - `S + 2` storage mutations. - /// - One event. - /// # + /// ## Complexity + /// - `O(R + S + X)` + /// - where `R` registrar-count (governance-bounded). + /// - where `S` subs-count (hard- and deposit-bounded). + /// - where `X` additional-field-count (deposit-bounded and code-bounded). #[pallet::call_index(10)] #[pallet::weight(T::WeightInfo::kill_identity( T::MaxRegistrars::get(), // R diff --git a/frame/im-online/src/lib.rs b/frame/im-online/src/lib.rs index 8c1f46978e8bc..3be1f53fc418d 100644 --- a/frame/im-online/src/lib.rs +++ b/frame/im-online/src/lib.rs @@ -463,15 +463,11 @@ pub mod pallet { #[pallet::call] impl Pallet { - /// # - /// - Complexity: `O(K + E)` where K is length of `Keys` (heartbeat.validators_len) and E is - /// length of `heartbeat.network_state.external_address` + /// ## Complexity: + /// - `O(K + E)` where K is length of `Keys` (heartbeat.validators_len) and E is length of + /// `heartbeat.network_state.external_address` /// - `O(K)`: decoding of length `K` /// - `O(E)`: decoding/encoding of length `E` - /// - DbReads: pallet_session `Validators`, pallet_session `CurrentIndex`, `Keys`, - /// `ReceivedHeartbeats` - /// - DbWrites: `ReceivedHeartbeats` - /// # // 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)] diff --git a/frame/indices/src/lib.rs b/frame/indices/src/lib.rs index 95d3cf4b2eed1..0eaee0f4b9eb7 100644 --- a/frame/indices/src/lib.rs +++ b/frame/indices/src/lib.rs @@ -90,14 +90,8 @@ pub mod pallet { /// /// Emits `IndexAssigned` if successful. /// - /// # + /// ## Complexity /// - `O(1)`. - /// - One storage mutation (codec `O(1)`). - /// - One reserve operation. - /// - One event. - /// ------------------- - /// - DB Weight: 1 Read/Write (Accounts) - /// # #[pallet::call_index(0)] #[pallet::weight(T::WeightInfo::claim())] pub fn claim(origin: OriginFor, index: T::AccountIndex) -> DispatchResult { @@ -122,16 +116,8 @@ pub mod pallet { /// /// Emits `IndexAssigned` if successful. /// - /// # + /// ## Complexity /// - `O(1)`. - /// - One storage mutation (codec `O(1)`). - /// - One transfer operation. - /// - One event. - /// ------------------- - /// - DB Weight: - /// - Reads: Indices Accounts, System Account (recipient) - /// - Writes: Indices Accounts, System Account (recipient) - /// # #[pallet::call_index(1)] #[pallet::weight(T::WeightInfo::transfer())] pub fn transfer( @@ -165,14 +151,8 @@ pub mod pallet { /// /// Emits `IndexFreed` if successful. /// - /// # + /// ## Complexity /// - `O(1)`. - /// - One storage mutation (codec `O(1)`). - /// - One reserve operation. - /// - One event. - /// ------------------- - /// - DB Weight: 1 Read/Write (Accounts) - /// # #[pallet::call_index(2)] #[pallet::weight(T::WeightInfo::free())] pub fn free(origin: OriginFor, index: T::AccountIndex) -> DispatchResult { @@ -200,16 +180,8 @@ pub mod pallet { /// /// Emits `IndexAssigned` if successful. /// - /// # + /// ## Complexity /// - `O(1)`. - /// - One storage mutation (codec `O(1)`). - /// - Up to one reserve operation. - /// - One event. - /// ------------------- - /// - DB Weight: - /// - 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( @@ -241,14 +213,8 @@ pub mod pallet { /// /// Emits `IndexFrozen` if successful. /// - /// # + /// ## Complexity /// - `O(1)`. - /// - One storage mutation (codec `O(1)`). - /// - Up to one slash operation. - /// - One event. - /// ------------------- - /// - DB Weight: 1 Read/Write (Accounts) - /// # #[pallet::call_index(4)] #[pallet::weight(T::WeightInfo::freeze())] pub fn freeze(origin: OriginFor, index: T::AccountIndex) -> DispatchResult { diff --git a/frame/multisig/src/lib.rs b/frame/multisig/src/lib.rs index 03d7ddec6a316..de20a9e5143d9 100644 --- a/frame/multisig/src/lib.rs +++ b/frame/multisig/src/lib.rs @@ -263,12 +263,8 @@ pub mod pallet { /// /// Result is equivalent to the dispatched result. /// - /// # + /// ## Complexity /// O(Z + C) where Z is the length of the call and C its execution weight. - /// ------------------------------- - /// - DB Weight: None - /// - Plus Call Weight - /// # #[pallet::call_index(0)] #[pallet::weight({ let dispatch_info = call.get_dispatch_info(); @@ -344,7 +340,7 @@ pub mod pallet { /// on success, result is `Ok` and the result from the interior call, if it was executed, /// may be found in the deposited `MultisigExecuted` event. /// - /// # + /// ## Complexity /// - `O(S + Z + Call)`. /// - Up to one balance-reserve or unreserve operation. /// - One passthrough operation, one insert, both `O(S)` where `S` is the number of @@ -357,12 +353,6 @@ pub mod pallet { /// - The weight of the `call`. /// - Storage: inserts one item, value size bounded by `MaxSignatories`, with a deposit /// taken for its lifetime of `DepositBase + threshold * DepositFactor`. - /// ------------------------------- - /// - DB Weight: - /// - Reads: Multisig Storage, [Caller Account] - /// - Writes: Multisig Storage, [Caller Account] - /// - Plus Call Weight - /// # #[pallet::call_index(1)] #[pallet::weight({ let s = other_signatories.len() as u32; @@ -411,7 +401,7 @@ pub mod pallet { /// /// NOTE: If this is the final approval, you will want to use `as_multi` instead. /// - /// # + /// ## Complexity /// - `O(S)`. /// - Up to one balance-reserve or unreserve operation. /// - One passthrough operation, one insert, both `O(S)` where `S` is the number of @@ -422,11 +412,6 @@ pub mod pallet { /// - One event. /// - Storage: inserts one item, value size bounded by `MaxSignatories`, with a deposit /// taken for its lifetime of `DepositBase + threshold * DepositFactor`. - /// ---------------------------------- - /// - DB Weight: - /// - Read: Multisig Storage, [Caller Account] - /// - Write: Multisig Storage, [Caller Account] - /// # #[pallet::call_index(2)] #[pallet::weight({ let s = other_signatories.len() as u32; @@ -466,7 +451,7 @@ pub mod pallet { /// transaction for this dispatch. /// - `call_hash`: The hash of the call to be executed. /// - /// # + /// ## Complexity /// - `O(S)`. /// - Up to one balance-reserve or unreserve operation. /// - One passthrough operation, one insert, both `O(S)` where `S` is the number of @@ -475,11 +460,6 @@ pub mod pallet { /// - One event. /// - I/O: 1 read `O(S)`, one remove. /// - Storage: removes one item. - /// ---------------------------------- - /// - DB Weight: - /// - 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( diff --git a/frame/nicks/src/lib.rs b/frame/nicks/src/lib.rs index 3d8307c434107..05d1a36395b94 100644 --- a/frame/nicks/src/lib.rs +++ b/frame/nicks/src/lib.rs @@ -129,12 +129,8 @@ pub mod pallet { /// /// The dispatch origin for this call must be _Signed_. /// - /// # + /// ## Complexity /// - O(1). - /// - At most one balance operation. - /// - One storage read/write. - /// - One event. - /// # #[pallet::call_index(0)] #[pallet::weight(50_000_000)] pub fn set_name(origin: OriginFor, name: Vec) -> DispatchResult { @@ -162,12 +158,8 @@ pub mod pallet { /// /// The dispatch origin for this call must be _Signed_. /// - /// # + /// ## Complexity /// - O(1). - /// - One balance operation. - /// - One storage read/write. - /// - One event. - /// # #[pallet::call_index(1)] #[pallet::weight(70_000_000)] pub fn clear_name(origin: OriginFor) -> DispatchResult { @@ -189,12 +181,8 @@ pub mod pallet { /// /// The dispatch origin for this call must match `T::ForceOrigin`. /// - /// # + /// ## Complexity /// - O(1). - /// - One unbalanced handler (probably a balance transfer) - /// - One storage read/write. - /// - One event. - /// # #[pallet::call_index(2)] #[pallet::weight(70_000_000)] pub fn kill_name(origin: OriginFor, target: AccountIdLookupOf) -> DispatchResult { @@ -217,12 +205,8 @@ pub mod pallet { /// /// The dispatch origin for this call must match `T::ForceOrigin`. /// - /// # + /// ## Complexity /// - O(1). - /// - At most one balance operation. - /// - One storage read/write. - /// - One event. - /// # #[pallet::call_index(3)] #[pallet::weight(70_000_000)] pub fn force_name( diff --git a/frame/scheduler/src/lib.rs b/frame/scheduler/src/lib.rs index dfec98d4e443a..97aaaaf0da7de 100644 --- a/frame/scheduler/src/lib.rs +++ b/frame/scheduler/src/lib.rs @@ -363,10 +363,6 @@ pub mod pallet { } /// Anonymously schedule a task after a delay. - /// - /// # - /// Same as [`schedule`]. - /// # #[pallet::call_index(4)] #[pallet::weight(::WeightInfo::schedule(T::MaxScheduledPerBlock::get()))] pub fn schedule_after( @@ -389,10 +385,6 @@ pub mod pallet { } /// Schedule a named task after a delay. - /// - /// # - /// Same as [`schedule_named`](Self::schedule_named). - /// # #[pallet::call_index(5)] #[pallet::weight(::WeightInfo::schedule_named(T::MaxScheduledPerBlock::get()))] pub fn schedule_named_after( diff --git a/frame/session/src/lib.rs b/frame/session/src/lib.rs index 4e2caf5e0874e..38a5c0f57f73c 100644 --- a/frame/session/src/lib.rs +++ b/frame/session/src/lib.rs @@ -587,14 +587,9 @@ pub mod pallet { /// /// 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. - /// - DbReads: `origin account`, `T::ValidatorIdOf`, `NextKeys` - /// - DbWrites: `origin account`, `NextKeys` - /// - DbReads per key id: `KeyOwner` - /// - DbWrites per key id: `KeyOwner` - /// # + /// ## Complexity + /// - `O(1)`. Actual cost depends on the number of length of `T::Keys::key_ids()` which is + /// fixed. #[pallet::call_index(0)] #[pallet::weight(T::WeightInfo::set_keys())] pub fn set_keys(origin: OriginFor, keys: T::Keys, proof: Vec) -> DispatchResult { @@ -614,13 +609,9 @@ pub mod pallet { /// 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 - /// of `T::Keys::key_ids()` which is fixed. - /// - DbReads: `T::ValidatorIdOf`, `NextKeys`, `origin account` - /// - DbWrites: `NextKeys`, `origin account` - /// - DbWrites per key id: `KeyOwner` - /// # + /// ## Complexity + /// - `O(1)` in number of key types. Actual cost depends on the number of length of + /// `T::Keys::key_ids()` which is fixed. #[pallet::call_index(1)] #[pallet::weight(T::WeightInfo::purge_keys())] pub fn purge_keys(origin: OriginFor) -> DispatchResult { diff --git a/frame/society/src/lib.rs b/frame/society/src/lib.rs index 18152b9e29ec4..4e83d938b2e2d 100644 --- a/frame/society/src/lib.rs +++ b/frame/society/src/lib.rs @@ -689,30 +689,12 @@ pub mod pallet { /// Parameters: /// - `value`: A one time payment the bid would like to receive when joining the society. /// - /// # - /// Key: B (len of bids), C (len of candidates), M (len of members), X (balance reserve) - /// - Storage Reads: - /// - One storage read to check for suspended candidate. O(1) - /// - One storage read to check for suspended member. O(1) - /// - One storage read to retrieve all current bids. O(B) - /// - 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) - /// - 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 Pallet Operations: - /// - One balance reserve operation. O(X) - /// - Up to one balance unreserve operation if bids.len() > MAX_BID_COUNT. - /// - Events: - /// - One event for new bid. - /// - Up to one event for AutoUnbid if bid.len() > MAX_BID_COUNT. - /// - /// Total Complexity: O(M + B + C + logM + logB + X) - /// # + /// ## Complexity + /// - O(M + B + C + logM + logB + X) + /// - B (len of bids) + /// - C (len of candidates) + /// - M (len of members) + /// - X (balance reserve) #[pallet::call_index(0)] #[pallet::weight(T::BlockWeights::get().max_block / 10)] pub fn bid(origin: OriginFor, value: BalanceOf) -> DispatchResult { @@ -745,14 +727,10 @@ pub mod pallet { /// Parameters: /// - `pos`: Position in the `Bids` vector of the bid who wants to unbid. /// - /// # - /// Key: B (len of bids), X (balance unreserve) - /// - One storage read and write to retrieve and update the bids. O(B) - /// - Either one unreserve balance action O(X) or one vouching storage removal. O(1) - /// - One event. - /// - /// Total Complexity: O(B + X) - /// # + /// ## Complexity + /// - O(B + X) + /// - B (len of bids) + /// - X (balance unreserve) #[pallet::call_index(1)] #[pallet::weight(T::BlockWeights::get().max_block / 10)] pub fn unbid(origin: OriginFor, pos: u32) -> DispatchResult { @@ -799,33 +777,12 @@ pub mod pallet { /// - `tip`: Your cut of the total `value` payout when the candidate is inducted into /// the society. Tips larger than `value` will be saturated upon payout. /// - /// # - /// Key: B (len of bids), C (len of candidates), M (len of members) - /// - Storage Reads: - /// - One storage read to retrieve all members. O(M) - /// - One storage read to check member is not already vouching. O(1) - /// - One storage read to check for suspended candidate. O(1) - /// - One storage read to check for suspended member. O(1) - /// - One storage read to retrieve all current bids. O(B) - /// - 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) - /// - 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 Pallet Operations: - /// - One balance reserve operation. O(X) - /// - Up to one balance unreserve operation if bids.len() > MAX_BID_COUNT. - /// - Events: - /// - One event for vouch. - /// - Up to one event for AutoUnbid if bid.len() > MAX_BID_COUNT. - /// - /// Total Complexity: O(M + B + C + logM + logB + X) - /// # + /// ## Complexity + /// - O(M + B + C + logM + logB + X) + /// - B (len of bids) + /// - C (len of candidates) + /// - M (len of members) + /// - X (balance reserve) #[pallet::call_index(2)] #[pallet::weight(T::BlockWeights::get().max_block / 10)] pub fn vouch( @@ -869,15 +826,9 @@ pub mod pallet { /// Parameters: /// - `pos`: Position in the `Bids` vector of the bid who should be unvouched. /// - /// # - /// Key: B (len of bids) - /// - One storage read O(1) to check the signer is a vouching member. - /// - One storage mutate to retrieve and update the bids. O(B) - /// - One vouching storage removal. O(1) - /// - One event. - /// - /// Total Complexity: O(B) - /// # + /// ## Complexity + /// - O(B) + /// - B (len of bids) #[pallet::call_index(3)] #[pallet::weight(T::BlockWeights::get().max_block / 10)] pub fn unvouch(origin: OriginFor, pos: u32) -> DispatchResult { @@ -910,16 +861,10 @@ pub mod pallet { /// - `approve`: A boolean which says if the candidate should be approved (`true`) or /// rejected (`false`). /// - /// # - /// Key: C (len of candidates), M (len of members) - /// - One storage read O(M) and O(log M) search to check user is a member. - /// - One account lookup. - /// - One storage read O(C) and O(C) search to check that user is a candidate. - /// - One storage write to add vote to votes. O(1) - /// - One event. - /// - /// Total Complexity: O(M + logM + C) - /// # + /// ## Complexity + /// - O(M + logM + C) + /// - C (len of candidates) + /// - M (len of members) #[pallet::call_index(4)] #[pallet::weight(T::BlockWeights::get().max_block / 10)] pub fn vote( @@ -949,14 +894,9 @@ pub mod pallet { /// - `approve`: A boolean which says if the candidate should be /// approved (`true`) or rejected (`false`). /// - /// # - /// - Key: M (len of members) - /// - One storage read O(M) and O(log M) search to check user is a member. - /// - One storage write to add vote to votes. O(1) - /// - One event. - /// - /// Total Complexity: O(M + logM) - /// # + /// ## Complexity + /// - O(M + logM) + /// - M (len of members) #[pallet::call_index(5)] #[pallet::weight(T::BlockWeights::get().max_block / 10)] pub fn defender_vote(origin: OriginFor, approve: bool) -> DispatchResult { @@ -982,16 +922,11 @@ pub mod pallet { /// The dispatch origin for this call must be _Signed_ and a member with /// payouts remaining. /// - /// # - /// Key: M (len of members), P (number of payouts for a particular member) - /// - One storage read O(M) and O(log M) search to check signer is a member. - /// - One storage read O(P) to get all payouts for a member. - /// - One storage read O(1) to get the current block number. - /// - One currency transfer call. O(X) - /// - One storage write or removal to update the member's payouts. O(P) - /// - /// Total Complexity: O(M + logM + P + X) - /// # + /// ## Complexity + /// - O(M + logM + P + X) + /// - M (len of members) + /// - P (number of payouts for a particular member) + /// - X (currency transfer call) #[pallet::call_index(6)] #[pallet::weight(T::BlockWeights::get().max_block / 10)] pub fn payout(origin: OriginFor) -> DispatchResult { @@ -1028,13 +963,8 @@ pub mod pallet { /// - `max_members` - The initial max number of members for the society. /// - `rules` - The rules of this society concerning membership. /// - /// # - /// - Two storage mutates to set `Head` and `Founder`. O(1) - /// - One storage write to add the first member to society. O(1) - /// - One event. - /// - /// Total Complexity: O(1) - /// # + /// ## Complexity + /// - O(1) #[pallet::call_index(7)] #[pallet::weight(T::BlockWeights::get().max_block / 10)] pub fn found( @@ -1063,13 +993,8 @@ pub mod pallet { /// the `Founder` and the `Head`. This implies that it may only be done when there is one /// member. /// - /// # - /// - Two storage reads O(1). - /// - Four storage removals O(1). - /// - One event. - /// - /// Total Complexity: O(1) - /// # + /// ## Complexity + /// - O(1) #[pallet::call_index(8)] #[pallet::weight(T::BlockWeights::get().max_block / 10)] pub fn unfound(origin: OriginFor) -> DispatchResult { @@ -1103,19 +1028,10 @@ pub mod pallet { /// - `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 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. - /// - One storage removal. O(1) - /// - One event for the judgement. - /// - /// Total Complexity: O(M + logM + B) - /// # + /// ## Complexity + /// - O(M + logM + B) + /// - B (len of bids) + /// - M (len of members) #[pallet::call_index(9)] #[pallet::weight(T::BlockWeights::get().max_block / 10)] pub fn judge_suspended_member( @@ -1171,29 +1087,11 @@ pub mod pallet { /// - `who` - The suspended candidate to be judged. /// - `judgement` - `Approve`, `Reject`, or `Rebid`. /// - /// # - /// Key: B (len of bids), M (len of members), X (balance action) - /// - One storage read to check `who` is a suspended candidate. - /// - One storage removal of the suspended candidate. - /// - Approve Logic - /// - One storage read to get the available pot to pay users with. O(1) - /// - One storage write to update the available pot. O(1) - /// - One storage read to get the current block number. O(1) - /// - One storage read to get all members. O(M) - /// - Up to one unreserve currency action. - /// - Up to two new storage writes to payouts. - /// - Up to one storage write with O(log M) binary search to add a member to society. - /// - Reject Logic - /// - Up to one repatriate reserved currency action. O(X) - /// - Up to one storage write to ban the vouching member from vouching again. - /// - Rebid Logic - /// - Storage mutate with O(log B) binary search to place the user back into bids. - /// - Up to one additional event if unvouch takes place. - /// - One storage removal. - /// - One event for the judgement. - /// - /// Total Complexity: O(M + logM + B + X) - /// # + /// ## Complexity + /// - O(M + logM + B + X) + /// - B (len of bids) + /// - M (len of members) + /// - X (balance action) #[pallet::call_index(10)] #[pallet::weight(T::BlockWeights::get().max_block / 10)] pub fn judge_suspended_candidate( @@ -1262,12 +1160,8 @@ pub mod pallet { /// Parameters: /// - `max` - The maximum number of members for the society. /// - /// # - /// - One storage write to update the max. O(1) - /// - One event. - /// - /// Total Complexity: O(1) - /// # + /// ## 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 { diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index c0c18b40cf02f..4b0e8133bc0b6 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -840,15 +840,13 @@ pub mod pallet { /// The dispatch origin for this call must be _Signed_ by the stash account. /// /// Emits `Bonded`. - /// # + /// ## Complexity /// - Independent of the arguments. Moderate complexity. /// - O(1). /// - Three extra DB entries. /// /// NOTE: Two of the storage writes (`Self::bonded`, `Self::payee`) are _never_ cleaned /// unless the `origin` falls below _existential deposit_ and gets removed as dust. - /// ------------------ - /// # #[pallet::call_index(0)] #[pallet::weight(T::WeightInfo::bond())] pub fn bond( @@ -915,10 +913,9 @@ pub mod pallet { /// /// Emits `Bonded`. /// - /// # + /// ## Complexity /// - Independent of the arguments. Insignificant complexity. /// - O(1). - /// # #[pallet::call_index(1)] #[pallet::weight(T::WeightInfo::bond_extra())] pub fn bond_extra( @@ -1076,10 +1073,9 @@ pub mod pallet { /// /// See also [`Call::unbond`]. /// - /// # - /// Complexity O(S) where S is the number of slashing spans to remove + /// ## 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( @@ -1136,11 +1132,10 @@ pub mod pallet { /// /// The dispatch origin for this call must be _Signed_ by the controller, not the stash. /// - /// # + /// ## Complexity /// - The transaction's complexity is proportional to the size of `targets` (N) /// 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( @@ -1205,11 +1200,10 @@ pub mod pallet { /// /// The dispatch origin for this call must be _Signed_ by the controller, not the stash. /// - /// # + /// ## Complexity /// - Independent of the arguments. Insignificant complexity. /// - 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 { @@ -1225,16 +1219,12 @@ pub mod pallet { /// /// The dispatch origin for this call must be _Signed_ by the controller, not the stash. /// - /// # + /// ## Complexity + /// - O(1) /// - Independent of the arguments. Insignificant complexity. /// - Contains a limited number of reads. /// - Writes are limited to the `origin` account key. /// --------- - /// - Weight: O(1) - /// - DB Weight: - /// - Read: Ledger - /// - Write: Payee - /// # #[pallet::call_index(7)] #[pallet::weight(T::WeightInfo::set_payee())] pub fn set_payee( @@ -1254,16 +1244,11 @@ pub mod pallet { /// /// The dispatch origin for this call must be _Signed_ by the stash, not the controller. /// - /// # + /// ## Complexity + /// O(1) /// - Independent of the arguments. Insignificant complexity. /// - Contains a limited number of reads. /// - Writes are limited to the `origin` account key. - /// ---------- - /// Weight: O(1) - /// DB Weight: - /// - 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( @@ -1289,10 +1274,8 @@ pub mod pallet { /// /// The dispatch origin must be Root. /// - /// # - /// Weight: O(1) - /// Write: Validator Count - /// # + /// ## Complexity + /// O(1) #[pallet::call_index(9)] #[pallet::weight(T::WeightInfo::set_validator_count())] pub fn set_validator_count( @@ -1315,9 +1298,8 @@ pub mod pallet { /// /// The dispatch origin must be Root. /// - /// # + /// ## Complexity /// Same as [`Self::set_validator_count`]. - /// # #[pallet::call_index(10)] #[pallet::weight(T::WeightInfo::set_validator_count())] pub fn increase_validator_count( @@ -1341,9 +1323,8 @@ pub mod pallet { /// /// The dispatch origin must be Root. /// - /// # + /// ## Complexity /// 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 { @@ -1370,11 +1351,9 @@ pub mod pallet { /// Thus the election process may be ongoing when this is called. In this case the /// election will continue until the next era is triggered. /// - /// # + /// ## Complexity /// - No arguments. /// - Weight: O(1) - /// - Write: ForceEra - /// # #[pallet::call_index(12)] #[pallet::weight(T::WeightInfo::force_no_eras())] pub fn force_no_eras(origin: OriginFor) -> DispatchResult { @@ -1394,11 +1373,9 @@ pub mod pallet { /// If this is called just before a new era is triggered, the election process may not /// have enough blocks to get a result. /// - /// # + /// ## Complexity /// - No arguments. /// - Weight: O(1) - /// - Write ForceEra - /// # #[pallet::call_index(13)] #[pallet::weight(T::WeightInfo::force_new_era())] pub fn force_new_era(origin: OriginFor) -> DispatchResult { @@ -1497,18 +1474,8 @@ pub mod pallet { /// The origin of this call must be _Signed_. Any account can call this function, even if /// it is not one of the stakers. /// - /// # - /// - Time complexity: at most O(MaxNominatorRewardedPerValidator). - /// - Contains a limited number of reads and writes. - /// ----------- - /// N is the Number of payouts for the validator (including the validator) - /// Weight: - /// - Reward Destination Staked: O(N) - /// - Reward Destination Controller (Creating): O(N) - /// - /// 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. - /// # + /// ## Complexity + /// - At most O(MaxNominatorRewardedPerValidator). #[pallet::call_index(18)] #[pallet::weight(T::WeightInfo::payout_stakers_alive_staked( T::MaxNominatorRewardedPerValidator::get() @@ -1526,11 +1493,9 @@ pub mod pallet { /// /// The dispatch origin must be signed by the controller. /// - /// # + /// ## Complexity /// - Time complexity: O(L), where L is unlocking chunks /// - 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( diff --git a/frame/sudo/src/lib.rs b/frame/sudo/src/lib.rs index 0867f24b1691e..3a708b6d5d6b1 100644 --- a/frame/sudo/src/lib.rs +++ b/frame/sudo/src/lib.rs @@ -142,12 +142,8 @@ pub mod pallet { /// /// The dispatch origin for this call must be _Signed_. /// - /// # + /// ## Complexity /// - O(1). - /// - Limited storage reads. - /// - One DB write (event). - /// - Weight of derivative `call` execution + 10,000. - /// # #[pallet::call_index(0)] #[pallet::weight({ let dispatch_info = call.get_dispatch_info(); @@ -173,10 +169,8 @@ pub mod pallet { /// /// The dispatch origin for this call must be _Signed_. /// - /// # + /// ## Complexity /// - 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( @@ -199,11 +193,8 @@ pub mod pallet { /// /// The dispatch origin for this call must be _Signed_. /// - /// # + /// ## Complexity /// - O(1). - /// - Limited storage reads. - /// - One DB change. - /// # #[pallet::call_index(2)] #[pallet::weight(0)] pub fn set_key( @@ -226,12 +217,8 @@ pub mod pallet { /// /// The dispatch origin for this call must be _Signed_. /// - /// # + /// ## Complexity /// - O(1). - /// - Limited storage reads. - /// - 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/system/src/lib.rs b/frame/system/src/lib.rs index c5d1706006154..c22a68296a159 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -374,9 +374,8 @@ pub mod pallet { impl Pallet { /// Make some on-chain remark. /// - /// # + /// ## Complexity /// - `O(1)` - /// # #[pallet::call_index(0)] #[pallet::weight(T::SystemWeightInfo::remark(_remark.len() as u32))] pub fn remark(origin: OriginFor, _remark: Vec) -> DispatchResultWithPostInfo { @@ -396,16 +395,8 @@ pub mod pallet { /// Set the new runtime code. /// - /// # + /// ## Complexity /// - `O(C + S)` where `C` length of `code` and `S` complexity of `can_set_code` - /// - 1 call to `can_set_code`: `O(S)` (calls `sp_io::misc::runtime_version` which is - /// expensive). - /// - 1 storage write (codec `O(C)`). - /// - 1 digest item. - /// - 1 event. - /// 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 { @@ -417,13 +408,8 @@ pub mod pallet { /// Set the new runtime code without doing any checks of the given `code`. /// - /// # + /// ## Complexity /// - `O(C)` where `C` length of `code` - /// - 1 storage write (codec `O(C)`). - /// - 1 digest item. - /// - 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( @@ -1423,10 +1409,8 @@ impl Pallet { /// Deposits a log and ensures it matches the block's log data. /// - /// # + /// ## Complexity /// - `O(1)` - /// - 1 storage write (codec `O(1)`) - /// # pub fn deposit_log(item: generic::DigestItem) { >::append(item); } diff --git a/frame/timestamp/src/lib.rs b/frame/timestamp/src/lib.rs index e859474c2cb9e..6e9c887824d17 100644 --- a/frame/timestamp/src/lib.rs +++ b/frame/timestamp/src/lib.rs @@ -171,10 +171,8 @@ pub mod pallet { T::WeightInfo::on_finalize() } - /// # + /// ## Complexity /// - `O(1)` - /// - 1 storage deletion (codec `O(1)`). - /// # fn on_finalize(_n: BlockNumberFor) { assert!(DidUpdate::::take(), "Timestamp must be updated once in the block"); } @@ -192,12 +190,11 @@ pub mod pallet { /// /// The dispatch origin for this call must be `Inherent`. /// - /// # + /// ## Complexity /// - `O(1)` (Note that implementations of `OnTimestampSet` must also be `O(1)`) /// - 1 storage read and 1 storage mutation (codec `O(1)`). (because of `DidUpdate::take` in /// `on_finalize`) /// - 1 event handler `on_timestamp_set`. Must be `O(1)`. - /// # #[pallet::call_index(0)] #[pallet::weight(( T::WeightInfo::set(), diff --git a/frame/tips/src/lib.rs b/frame/tips/src/lib.rs index 43002c7b5f196..175fc3ac39d02 100644 --- a/frame/tips/src/lib.rs +++ b/frame/tips/src/lib.rs @@ -231,12 +231,9 @@ pub mod pallet { /// /// Emits `NewTip` if successful. /// - /// # - /// - Complexity: `O(R)` where `R` length of `reason`. + /// ## Complexity + /// - `O(R)` where `R` length of `reason`. /// - encoding and hashing of 'reason' - /// - DbReads: `Reasons`, `Tips` - /// - DbWrites: `Reasons`, `Tips` - /// # #[pallet::call_index(0)] #[pallet::weight(>::WeightInfo::report_awesome(reason.len() as u32))] pub fn report_awesome( @@ -289,12 +286,9 @@ pub mod pallet { /// /// Emits `TipRetracted` if successful. /// - /// # - /// - Complexity: `O(1)` + /// ## Complexity + /// - `O(1)` /// - Depends on the length of `T::Hash` which is fixed. - /// - 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 { @@ -325,15 +319,12 @@ pub mod pallet { /// /// Emits `NewTip` if successful. /// - /// # - /// - Complexity: `O(R + T)` where `R` length of `reason`, `T` is the number of tippers. + /// ## Complexity + /// - `O(R + T)` where `R` length of `reason`, `T` is the number of tippers. /// - `O(T)`: decoding `Tipper` vec of length `T`. `T` is charged as upper bound given by /// `ContainsLengthBound`. The actual cost depends on the implementation of /// `T::Tippers`. /// - `O(R)`: hashing and encoding of reason of length `R` - /// - 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( @@ -379,16 +370,13 @@ pub mod pallet { /// Emits `TipClosing` if the threshold of tippers has been reached and the countdown period /// has started. /// - /// # - /// - Complexity: `O(T)` where `T` is the number of tippers. decoding `Tipper` vec of length - /// `T`, insert tip and check closing, `T` is charged as upper bound given by - /// `ContainsLengthBound`. The actual cost depends on the implementation of `T::Tippers`. + /// ## Complexity + /// - `O(T)` where `T` is the number of tippers. decoding `Tipper` vec of length `T`, insert + /// tip and check closing, `T` is charged as upper bound given by `ContainsLengthBound`. + /// The actual cost depends on the implementation of `T::Tippers`. /// /// Actually weight could be lower as it depends on how many tips are in `OpenTip` but it /// is weighted as if almost full i.e of length `T-1`. - /// - DbReads: `Tippers`, `Tips` - /// - DbWrites: `Tips` - /// # #[pallet::call_index(3)] #[pallet::weight(>::WeightInfo::tip(T::Tippers::max_len() as u32))] pub fn tip( @@ -416,13 +404,10 @@ pub mod pallet { /// - `hash`: The identity of the open tip for which a tip value is declared. This is formed /// as the hash of the tuple of the original tip `reason` and the beneficiary account ID. /// - /// # - /// - Complexity: `O(T)` where `T` is the number of tippers. decoding `Tipper` vec of length - /// `T`. `T` is charged as upper bound given by `ContainsLengthBound`. The actual cost - /// depends on the implementation of `T::Tippers`. - /// - DbReads: `Tips`, `Tippers`, `tip finder` - /// - DbWrites: `Reasons`, `Tips`, `Tippers`, `tip finder` - /// # + /// ## Complexity + /// - : `O(T)` where `T` is the number of tippers. decoding `Tipper` vec of length `T`. `T` + /// is charged as upper bound given by `ContainsLengthBound`. The actual cost depends on + /// the implementation of `T::Tippers`. #[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 { @@ -446,10 +431,8 @@ pub mod pallet { /// /// Emits `TipSlashed` if successful. /// - /// # - /// `T` is charged as upper bound given by `ContainsLengthBound`. - /// The actual cost depends on the implementation of `T::Tippers`. - /// # + /// ## Complexity + /// - O(1). #[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 { diff --git a/frame/transaction-storage/src/lib.rs b/frame/transaction-storage/src/lib.rs index cda7610efdf87..aaa484d58ad28 100644 --- a/frame/transaction-storage/src/lib.rs +++ b/frame/transaction-storage/src/lib.rs @@ -184,10 +184,9 @@ pub mod pallet { impl Pallet { /// 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. - /// Additionally contains a DB write. - /// # + /// is called. + /// ## Complexity + /// - O(n*log(n)) of data size, as all data is pushed to an in-memory trie. #[pallet::call_index(0)] #[pallet::weight(T::WeightInfo::store(data.len() as u32))] pub fn store(origin: OriginFor, data: Vec) -> DispatchResult { @@ -234,9 +233,8 @@ pub mod pallet { /// previous `store` or `renew` call and transaction index within that block. /// Transaction index is emitted in the `Stored` or `Renewed` event. /// Applies same fees as `store`. - /// # - /// - Constant. - /// # + /// ## Complexity + /// - O(1). #[pallet::call_index(1)] #[pallet::weight(T::WeightInfo::renew())] pub fn renew( @@ -277,12 +275,10 @@ pub mod pallet { /// Check storage proof for block number `block_number() - StoragePeriod`. /// If such block does not exist the proof is expected to be `None`. - /// # + /// ## Complexity /// - Linear w.r.t the number of indexed transactions in the proved block for random /// probing. /// 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( diff --git a/frame/treasury/src/lib.rs b/frame/treasury/src/lib.rs index 1bde1238191a4..f5ca0a984bc49 100644 --- a/frame/treasury/src/lib.rs +++ b/frame/treasury/src/lib.rs @@ -315,13 +315,8 @@ pub mod pallet { #[pallet::hooks] impl, I: 'static> Hooks> for Pallet { - /// # - /// - Complexity: `O(A)` where `A` is the number of approvals - /// - Db reads and writes: `Approvals`, `pot account data` - /// - Db reads and writes per approval: `Proposals`, `proposer account data`, `beneficiary - /// account data` - /// - The weight is overestimated if some approvals got missed. - /// # + /// ## Complexity + /// - `O(A)` where `A` is the number of approvals fn on_initialize(n: T::BlockNumber) -> Weight { let pot = Self::pot(); let deactivated = Deactivated::::get(); @@ -350,11 +345,8 @@ pub mod pallet { /// is reserved and slashed if the proposal is rejected. It is returned once the /// proposal is awarded. /// - /// # - /// - Complexity: O(1) - /// - DbReads: `ProposalCount`, `origin account` - /// - DbWrites: `ProposalCount`, `Proposals`, `origin account` - /// # + /// ## Complexity + /// - O(1) #[pallet::call_index(0)] #[pallet::weight(T::WeightInfo::propose_spend())] pub fn propose_spend( @@ -381,11 +373,8 @@ pub mod pallet { /// /// May only be called from `T::RejectOrigin`. /// - /// # - /// - Complexity: O(1) - /// - DbReads: `Proposals`, `rejected proposer account` - /// - DbWrites: `Proposals`, `rejected proposer account` - /// # + /// ## Complexity + /// - O(1) #[pallet::call_index(1)] #[pallet::weight((T::WeightInfo::reject_proposal(), DispatchClass::Operational))] pub fn reject_proposal( @@ -412,11 +401,8 @@ pub mod pallet { /// /// May only be called from `T::ApproveOrigin`. /// - /// # - /// - Complexity: O(1). - /// - DbReads: `Proposals`, `Approvals` - /// - DbWrite: `Approvals` - /// # + /// ## Complexity + /// - O(1). #[pallet::call_index(2)] #[pallet::weight((T::WeightInfo::approve_proposal(T::MaxApprovals::get()), DispatchClass::Operational))] pub fn approve_proposal( @@ -472,10 +458,8 @@ pub mod pallet { /// 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` - /// # + /// ## Complexity + /// - O(A) where `A` is the number of approvals /// /// Errors: /// - `ProposalNotApproved`: The `proposal_id` supplied was not found in the approval queue, diff --git a/frame/utility/src/lib.rs b/frame/utility/src/lib.rs index 2d60ae15679d5..a28dd4994dfa6 100644 --- a/frame/utility/src/lib.rs +++ b/frame/utility/src/lib.rs @@ -172,9 +172,8 @@ pub mod pallet { /// 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. - /// # + /// ## Complexity + /// - O(C) where C is the number of calls to be batched. /// /// This will return `Ok` in all circumstances. To determine the success of the batch, an /// event is deposited. If a call failed and the batch was interrupted, then the @@ -301,9 +300,8 @@ pub mod pallet { /// 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. - /// # + /// ## 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::>(); @@ -374,12 +372,8 @@ pub mod pallet { /// /// The dispatch origin for this call must be _Root_. /// - /// # + /// ## Complexity /// - O(1). - /// - Limited storage reads. - /// - 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(); @@ -415,9 +409,8 @@ pub mod pallet { /// 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. - /// # + /// ## 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::>(); diff --git a/frame/vesting/src/lib.rs b/frame/vesting/src/lib.rs index 3439608af3ce4..6cde546f387b4 100644 --- a/frame/vesting/src/lib.rs +++ b/frame/vesting/src/lib.rs @@ -297,12 +297,8 @@ pub mod pallet { /// /// Emits either `VestingCompleted` or `VestingUpdated`. /// - /// # + /// ## Complexity /// - `O(1)`. - /// - DbWeight: 2 Reads, 2 Writes - /// - 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)) @@ -321,12 +317,8 @@ pub mod pallet { /// /// Emits either `VestingCompleted` or `VestingUpdated`. /// - /// # + /// ## Complexity /// - `O(1)`. - /// - DbWeight: 3 Reads, 3 Writes - /// - 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)) @@ -348,12 +340,8 @@ pub mod pallet { /// /// NOTE: This will unlock all schedules through the current block. /// - /// # + /// ## Complexity /// - `O(1)`. - /// - DbWeight: 3 Reads, 3 Writes - /// - 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) @@ -380,12 +368,8 @@ pub mod pallet { /// /// NOTE: This will unlock all schedules through the current block. /// - /// # + /// ## Complexity /// - `O(1)`. - /// - DbWeight: 4 Reads, 4 Writes - /// - 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) From 3ca3f776e1d566c7f1ab46fad1252ad3cef74e98 Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Tue, 14 Feb 2023 15:17:58 +0100 Subject: [PATCH 392/715] zombienet: is up timtout increased to 30s (#13386) --- .../test-block-building-warp-sync.zndsl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/zombienet/0003-block-building-warp-sync/test-block-building-warp-sync.zndsl b/zombienet/0003-block-building-warp-sync/test-block-building-warp-sync.zndsl index 2041366a6d086..441fa45a88003 100644 --- a/zombienet/0003-block-building-warp-sync/test-block-building-warp-sync.zndsl +++ b/zombienet/0003-block-building-warp-sync/test-block-building-warp-sync.zndsl @@ -2,10 +2,10 @@ Description: Warp sync Network: ./test-block-building-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 4 bob: reports node_roles is 4 From c3ffbcdfaa88420e8aaa421a404c102cfc5c6c6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 14 Feb 2023 16:17:37 +0100 Subject: [PATCH 393/715] pallet-timestamp: Remove `ValidAtTimestamp` error variant (#13346) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * pallet-timestamp: Remove `ValidAtTimestamp` error variant The error variant wasn't that useful and it was also used wrongly in the code. In the code we returned this variant when the `timestamp < minimum`. The problem of this is that we waited on the node side some time, but then `set` function rejects the timestamp because of the same check (the timestamp in the block stays the same). We ensure that the timestamp isn't drifting too much in the future, but waiting for the timestamp to be "valid" would open some attack vector. The consensus protocols also compare the slots in the blocks to ensure that there isn't a block from the future and in the runtime we then ensure that `slot = timestamp / slot_duration`. So, we can just remove this variant and replace it with a new variant `TimeBetweenBlocksTooShort` to not even try importing a block which uses a too short delay since the last block. * Update primitives/timestamp/src/lib.rs Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> * Rename to `TooEarly` * FMT --------- Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> --- frame/timestamp/src/lib.rs | 2 +- primitives/timestamp/src/lib.rs | 44 ++++++++------------------------- 2 files changed, 11 insertions(+), 35 deletions(-) diff --git a/frame/timestamp/src/lib.rs b/frame/timestamp/src/lib.rs index 6e9c887824d17..61a46125a423b 100644 --- a/frame/timestamp/src/lib.rs +++ b/frame/timestamp/src/lib.rs @@ -255,7 +255,7 @@ pub mod pallet { if t > *(data + MAX_TIMESTAMP_DRIFT_MILLIS) { Err(InherentError::TooFarInFuture) } else if t < minimum { - Err(InherentError::ValidAtTimestamp(minimum.into())) + Err(InherentError::TooEarly) } else { Ok(()) } diff --git a/primitives/timestamp/src/lib.rs b/primitives/timestamp/src/lib.rs index 14b06779340f2..0ec079816c10a 100644 --- a/primitives/timestamp/src/lib.rs +++ b/primitives/timestamp/src/lib.rs @@ -134,10 +134,12 @@ impl From for Timestamp { #[derive(Encode, sp_runtime::RuntimeDebug)] #[cfg_attr(feature = "std", derive(Decode, thiserror::Error))] pub enum InherentError { - /// The timestamp is valid in the future. - /// This is a non-fatal-error and will not stop checking the inherents. - #[cfg_attr(feature = "std", error("Block will be valid at {0}."))] - ValidAtTimestamp(InherentType), + /// The time between the blocks is too short. + #[cfg_attr( + feature = "std", + error("The time since the last timestamp is lower than the minimum period.") + )] + TooEarly, /// The block timestamp is too far in the future #[cfg_attr(feature = "std", error("The timestamp of the block is too far in the future."))] TooFarInFuture, @@ -146,7 +148,7 @@ pub enum InherentError { impl IsFatalError for InherentError { fn is_fatal_error(&self) -> bool { match self { - InherentError::ValidAtTimestamp(_) => false, + InherentError::TooEarly => true, InherentError::TooFarInFuture => true, } } @@ -240,34 +242,8 @@ impl sp_inherents::InherentDataProvider for InherentDataProvider { identifier: &InherentIdentifier, error: &[u8], ) -> Option> { - if *identifier != INHERENT_IDENTIFIER { - return None - } - - match InherentError::try_from(&INHERENT_IDENTIFIER, error)? { - InherentError::ValidAtTimestamp(valid) => { - let max_drift = self.max_drift; - let timestamp = self.timestamp; - // halt import until timestamp is valid. - // reject when too far ahead. - if valid > timestamp + max_drift { - return Some(Err(sp_inherents::Error::Application(Box::from( - InherentError::TooFarInFuture, - )))) - } - - let diff = valid.checked_sub(timestamp).unwrap_or_default(); - log::info!( - target: "timestamp", - "halting for block {} milliseconds in the future", - diff.0, - ); - - futures_timer::Delay::new(diff.as_duration()).await; - - Some(Ok(())) - }, - o => Some(Err(sp_inherents::Error::Application(Box::from(o)))), - } + Some(Err(sp_inherents::Error::Application(Box::from(InherentError::try_from( + identifier, error, + )?)))) } } From 74ee5212765a77177ad90e542894b837be091952 Mon Sep 17 00:00:00 2001 From: Sam Elamin Date: Tue, 14 Feb 2023 17:46:51 +0000 Subject: [PATCH 394/715] add warp to target block for parachains (#12761) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add warp to target block for parachains * fix for failing tests * format using `Cargo +nightly fmt` * Remove blocking based on PR comments and create new `WarpSync` on poll * remove method from trait * add tests for wait for target * Update client/network/common/src/sync/warp.rs Co-authored-by: Bastian Köcher * Update client/network/common/src/sync/warp.rs Co-authored-by: Bastian Köcher * Update client/network/test/src/sync.rs Co-authored-by: Bastian Köcher * Update client/network/test/src/sync.rs Co-authored-by: Bastian Köcher * Update client/network/test/src/lib.rs Co-authored-by: Bastian Köcher * Update client/network/test/src/sync.rs Co-authored-by: Bastian Köcher * Update client/network/test/src/sync.rs Co-authored-by: Bastian Köcher * code refactor based on pr comments * Second round of PR comments * Third round of pr comments * add comments to explain logic * Update client/network/sync/src/lib.rs Co-authored-by: Bastian Köcher * Update client/network/sync/src/lib.rs Co-authored-by: Bastian Köcher * Update client/network/sync/src/warp.rs Co-authored-by: Bastian Köcher * Update client/network/sync/src/warp.rs Co-authored-by: Bastian Köcher * Update client/network/sync/src/warp.rs Co-authored-by: Bastian Köcher * Update client/network/sync/src/lib.rs Co-authored-by: Bastian Köcher * code refactor based on last PR comments * move warp sync polling before `process_outbound_requests` Add error message if target block fails to be retreived * Update client/network/sync/src/warp.rs Co-authored-by: Arkadiy Paronyan * Update client/network/sync/src/lib.rs Co-authored-by: Bastian Köcher * Update client/network/sync/src/warp.rs Co-authored-by: Bastian Köcher * fmt after code suggestions * rebase changes * Bring down the node if the target block fails to return * Revert "Bring down the node if the target block fails to return" This reverts commit c0ecb220d66dd8e7b1a5ee29831b776f4f18d024. * Update client/network/common/src/sync/warp.rs Co-authored-by: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> * Update client/network/common/src/sync/warp.rs Co-authored-by: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> * use matching on polling to avoid calling poll more than once * Update client/network/sync/src/warp.rs Co-authored-by: Bastian Köcher * Update client/network/sync/src/warp.rs Co-authored-by: Bastian Köcher * Update client/network/sync/src/warp.rs Co-authored-by: Bastian Köcher * fix typo on comment * update snapshot with new folder structure * Upload snapshot * Bump zombienet * bump zombienet again * Improve test * Update client/network/test/src/sync.rs Co-authored-by: Bastian Köcher * Update client/network/test/src/sync.rs Co-authored-by: Bastian Köcher * fix tests * dummy commit to restart builds * Converted the target block to an optional value that is set to `None` when an error occurs * dummy commit to restart builds --------- Co-authored-by: Bastian Köcher Co-authored-by: Arkadiy Paronyan Co-authored-by: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Co-authored-by: Sebastian Kunert --- bin/node-template/node/src/service.rs | 4 +- bin/node/cli/src/service.rs | 6 +- client/informant/src/display.rs | 5 ++ client/network/common/src/sync/warp.rs | 16 +++- client/network/sync/src/lib.rs | 28 ++++--- client/network/sync/src/warp.rs | 106 ++++++++++++++++++------- client/network/test/src/lib.rs | 20 ++++- client/network/test/src/sync.rs | 38 +++++++++ client/service/src/builder.rs | 25 +++--- client/service/src/lib.rs | 1 + 10 files changed, 189 insertions(+), 60 deletions(-) diff --git a/bin/node-template/node/src/service.rs b/bin/node-template/node/src/service.rs index ee8464688c79c..d7d075efd98ab 100644 --- a/bin/node-template/node/src/service.rs +++ b/bin/node-template/node/src/service.rs @@ -6,7 +6,7 @@ use sc_consensus_aura::{ImportQueueParams, SlotProportion, StartAuraParams}; pub use sc_executor::NativeElseWasmExecutor; use sc_finality_grandpa::SharedVoterState; use sc_keystore::LocalKeystore; -use sc_service::{error::Error as ServiceError, Configuration, TaskManager}; +use sc_service::{error::Error as ServiceError, Configuration, TaskManager, WarpSyncParams}; use sc_telemetry::{Telemetry, TelemetryWorker}; use sp_consensus_aura::sr25519::AuthorityPair as AuraPair; use std::{sync::Arc, time::Duration}; @@ -200,7 +200,7 @@ pub fn new_full(mut config: Configuration) -> Result spawn_handle: task_manager.spawn_handle(), import_queue, block_announce_validator_builder: None, - warp_sync: Some(warp_sync), + warp_sync_params: Some(WarpSyncParams::WithProvider(warp_sync)), })?; if config.offchain_worker.enabled { diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs index b1e9360b4a6c4..7ad1a9486b544 100644 --- a/bin/node/cli/src/service.rs +++ b/bin/node/cli/src/service.rs @@ -32,7 +32,9 @@ use sc_client_api::BlockBackend; use sc_consensus_babe::{self, SlotProportion}; use sc_executor::NativeElseWasmExecutor; use sc_network::NetworkService; -use sc_network_common::{protocol::event::Event, service::NetworkEventStream}; +use sc_network_common::{ + protocol::event::Event, service::NetworkEventStream, sync::warp::WarpSyncParams, +}; use sc_service::{config::Configuration, error::Error as ServiceError, RpcHandlers, TaskManager}; use sc_telemetry::{Telemetry, TelemetryWorker}; use sp_api::ProvideRuntimeApi; @@ -359,7 +361,7 @@ pub fn new_full_base( spawn_handle: task_manager.spawn_handle(), import_queue, block_announce_validator_builder: None, - warp_sync: Some(warp_sync), + warp_sync_params: Some(WarpSyncParams::WithProvider(warp_sync)), })?; if config.offchain_worker.enabled { diff --git a/client/informant/src/display.rs b/client/informant/src/display.rs index 3d585a9985134..4da46ebb65edb 100644 --- a/client/informant/src/display.rs +++ b/client/informant/src/display.rs @@ -100,6 +100,11 @@ impl InformantDisplay { _, Some(WarpSyncProgress { phase: WarpSyncPhase::DownloadingBlocks(n), .. }), ) => ("⏩", "Block history".into(), format!(", #{}", n)), + ( + _, + _, + Some(WarpSyncProgress { phase: WarpSyncPhase::AwaitingTargetBlock, .. }), + ) => ("⏩", "Waiting for pending target block".into(), "".into()), (_, _, Some(warp)) => ( "⏩", "Warping".into(), diff --git a/client/network/common/src/sync/warp.rs b/client/network/common/src/sync/warp.rs index c9b9037542388..020642fb48c82 100644 --- a/client/network/common/src/sync/warp.rs +++ b/client/network/common/src/sync/warp.rs @@ -15,9 +15,10 @@ // along with Substrate. If not, see . use codec::{Decode, Encode}; +use futures::channel::oneshot; pub use sp_finality_grandpa::{AuthorityList, SetId}; use sp_runtime::traits::{Block as BlockT, NumberFor}; -use std::fmt; +use std::{fmt, sync::Arc}; /// Scale-encoded warp sync proof response. pub struct EncodedProof(pub Vec); @@ -29,6 +30,16 @@ pub struct WarpProofRequest { pub begin: B::Hash, } +/// The different types of warp syncing. +pub enum WarpSyncParams { + /// Standard warp sync for the relay chain + WithProvider(Arc>), + /// Skip downloading proofs and wait for a header of the state that should be downloaded. + /// + /// It is expected that the header provider ensures that the header is trusted. + WaitForTarget(oneshot::Receiver<::Header>), +} + /// Proof verification result. pub enum VerificationResult { /// Proof is valid, but the target was not reached. @@ -62,6 +73,8 @@ pub trait WarpSyncProvider: Send + Sync { pub enum WarpSyncPhase { /// Waiting for peers to connect. AwaitingPeers, + /// Waiting for target block to be received. + AwaitingTargetBlock, /// Downloading and verifying grandpa warp proofs. DownloadingWarpProofs, /// Downloading target block. @@ -78,6 +91,7 @@ impl fmt::Display for WarpSyncPhase { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { Self::AwaitingPeers => write!(f, "Waiting for peers"), + Self::AwaitingTargetBlock => write!(f, "Waiting for target block to be received"), Self::DownloadingWarpProofs => write!(f, "Downloading finality proofs"), Self::DownloadingTargetBlock => write!(f, "Downloading target block"), Self::DownloadingState => write!(f, "Downloading state"), diff --git a/client/network/sync/src/lib.rs b/client/network/sync/src/lib.rs index 312fc6f5b7947..ffc0edaf31e72 100644 --- a/client/network/sync/src/lib.rs +++ b/client/network/sync/src/lib.rs @@ -71,7 +71,7 @@ use sc_network_common::{ BlockAnnounce, BlockAnnouncesHandshake, BlockAttributes, BlockData, BlockRequest, BlockResponse, Direction, FromBlock, }, - warp::{EncodedProof, WarpProofRequest, WarpSyncPhase, WarpSyncProgress, WarpSyncProvider}, + warp::{EncodedProof, WarpProofRequest, WarpSyncParams, WarpSyncPhase, WarpSyncProgress}, BadPeer, ChainSync as ChainSyncT, ImportResult, Metrics, OnBlockData, OnBlockJustification, OnStateData, OpaqueBlockRequest, OpaqueBlockResponse, OpaqueStateRequest, OpaqueStateResponse, PeerInfo, PeerRequest, PollBlockAnnounceValidation, SyncMode, @@ -318,8 +318,10 @@ pub struct ChainSync { state_sync: Option>, /// Warp sync in progress, if any. warp_sync: Option>, - /// Warp sync provider. - warp_sync_provider: Option>>, + /// Warp sync params. + /// + /// Will be `None` after `self.warp_sync` is `Some(_)`. + warp_sync_params: Option>, /// Enable importing existing blocks. This is used used after the state download to /// catch up to the latest state while re-importing blocks. import_existing: bool, @@ -565,6 +567,7 @@ where info!("💔 New peer with unknown genesis hash {} ({}).", best_hash, best_number); return Err(BadPeer(who, rep::GENESIS_MISMATCH)) } + // If there are more than `MAJOR_SYNC_BLOCKS` in the import queue then we have // enough to do in the import queue that it's not worth kicking off // an ancestor search, which is what we do in the next match case below. @@ -630,17 +633,15 @@ where }, ); - if let SyncMode::Warp = &self.mode { + 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 let Some(params) = self.warp_sync_params.take() { + self.warp_sync = Some(WarpSync::new(self.client.clone(), params)); } } } - Ok(req) }, Ok(BlockStatus::Queued) | @@ -1359,6 +1360,13 @@ where }, } } + + // Should be called before `process_outbound_requests` to ensure + // that a potential target block is directly leading to requests. + if let Some(warp_sync) = &mut self.warp_sync { + let _ = warp_sync.poll(cx); + } + self.process_outbound_requests(); while let Poll::Ready(result) = self.poll_pending_responses(cx) { @@ -1427,7 +1435,7 @@ where roles: Roles, block_announce_validator: Box + Send>, max_parallel_downloads: u32, - warp_sync_provider: Option>>, + warp_sync_params: Option>, metrics_registry: Option<&Registry>, network_service: service::network::NetworkServiceHandle, import_queue: Box>, @@ -1467,13 +1475,13 @@ where block_announce_validation_per_peer_stats: Default::default(), state_sync: None, warp_sync: None, - warp_sync_provider, import_existing: false, gap_sync: None, service_rx, network_service, block_request_protocol_name, state_request_protocol_name, + warp_sync_params, warp_sync_protocol_name, block_announce_protocol_name: block_announce_config .notifications_protocol diff --git a/client/network/sync/src/warp.rs b/client/network/sync/src/warp.rs index ab8a7c66b9856..bb64ff6a15890 100644 --- a/client/network/sync/src/warp.rs +++ b/client/network/sync/src/warp.rs @@ -19,24 +19,35 @@ //! Warp sync support. use crate::{ + oneshot, schema::v1::{StateRequest, StateResponse}, state::{ImportResult, StateSync}, }; +use futures::FutureExt; +use log::error; use sc_client_api::ProofProvider; use sc_network_common::sync::{ message::{BlockAttributes, BlockData, BlockRequest, Direction, FromBlock}, warp::{ - EncodedProof, VerificationResult, WarpProofRequest, WarpSyncPhase, WarpSyncProgress, - WarpSyncProvider, + EncodedProof, VerificationResult, WarpProofRequest, WarpSyncParams, WarpSyncPhase, + WarpSyncProgress, WarpSyncProvider, }, }; use sp_blockchain::HeaderBackend; use sp_finality_grandpa::{AuthorityList, SetId}; use sp_runtime::traits::{Block as BlockT, Header, NumberFor, Zero}; -use std::sync::Arc; +use std::{sync::Arc, task::Poll}; enum Phase { - WarpProof { set_id: SetId, authorities: AuthorityList, last_hash: B::Hash }, + WarpProof { + set_id: SetId, + authorities: AuthorityList, + last_hash: B::Hash, + warp_sync_provider: Arc>, + }, + PendingTargetBlock { + target_block: Option>, + }, TargetBlock(B::Header), State(StateSync), } @@ -61,7 +72,6 @@ pub enum TargetBlockImportResult { pub struct WarpSync { phase: Phase, client: Arc, - warp_sync_provider: Arc>, total_proof_bytes: u64, } @@ -70,21 +80,56 @@ where B: BlockT, Client: HeaderBackend + ProofProvider + 'static, { - /// Create a new instance. - pub fn new(client: Arc, warp_sync_provider: Arc>) -> Self { + /// Create a new instance. When passing a warp sync provider we will be checking for proof and + /// authorities. Alternatively we can pass a target block when we want to skip downloading + /// proofs, in this case we will continue polling until the target block is known. + pub fn new(client: Arc, warp_sync_params: WarpSyncParams) -> Self { let last_hash = client.hash(Zero::zero()).unwrap().expect("Genesis header always exists"); - let phase = Phase::WarpProof { - set_id: 0, - authorities: warp_sync_provider.current_authorities(), - last_hash, + match warp_sync_params { + WarpSyncParams::WithProvider(warp_sync_provider) => { + let phase = Phase::WarpProof { + set_id: 0, + authorities: warp_sync_provider.current_authorities(), + last_hash, + warp_sync_provider: warp_sync_provider.clone(), + }; + Self { client, phase, total_proof_bytes: 0 } + }, + WarpSyncParams::WaitForTarget(block) => Self { + client, + phase: Phase::PendingTargetBlock { target_block: Some(block) }, + total_proof_bytes: 0, + }, + } + } + + /// Poll to make progress. + /// + /// This only makes progress when `phase = Phase::PendingTargetBlock` and the pending block was + /// sent. + pub fn poll(&mut self, cx: &mut std::task::Context) { + let new_phase = if let Phase::PendingTargetBlock { target_block: Some(target_block) } = + &mut self.phase + { + match target_block.poll_unpin(cx) { + Poll::Ready(Ok(target)) => Phase::TargetBlock(target), + Poll::Ready(Err(e)) => { + error!(target: "sync", "Failed to get target block. Error: {:?}",e); + Phase::PendingTargetBlock { target_block: None } + }, + _ => return, + } + } else { + return }; - Self { client, warp_sync_provider, phase, total_proof_bytes: 0 } + + self.phase = new_phase; } /// Validate and import a state response. pub fn import_state(&mut self, response: StateResponse) -> ImportResult { match &mut self.phase { - Phase::WarpProof { .. } | Phase::TargetBlock(_) => { + Phase::WarpProof { .. } | Phase::TargetBlock(_) | Phase::PendingTargetBlock { .. } => { log::debug!(target: "sync", "Unexpected state response"); ImportResult::BadResponse }, @@ -95,12 +140,12 @@ 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::TargetBlock(_) => { + Phase::State(_) | Phase::TargetBlock(_) | Phase::PendingTargetBlock { .. } => { 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, authorities.clone()) { + Phase::WarpProof { set_id, authorities, last_hash, warp_sync_provider } => + match warp_sync_provider.verify(&response, *set_id, authorities.clone()) { Err(e) => { log::debug!(target: "sync", "Bad warp proof response: {}", e); WarpProofImportResult::BadResponse @@ -119,15 +164,14 @@ where self.phase = Phase::TargetBlock(header); WarpProofImportResult::Success }, - } - }, + }, } } /// Import the target block body. pub fn import_target_block(&mut self, block: BlockData) -> TargetBlockImportResult { match &mut self.phase { - Phase::WarpProof { .. } | Phase::State(_) => { + Phase::WarpProof { .. } | Phase::State(_) | Phase::PendingTargetBlock { .. } => { log::debug!(target: "sync", "Unexpected target block response"); TargetBlockImportResult::BadResponse }, @@ -168,8 +212,8 @@ where /// Produce next state request. pub fn next_state_request(&self) -> Option { match &self.phase { - Phase::WarpProof { .. } => None, - Phase::TargetBlock(_) => None, + Phase::WarpProof { .. } | Phase::TargetBlock(_) | Phase::PendingTargetBlock { .. } => + None, Phase::State(sync) => Some(sync.next_request()), } } @@ -178,15 +222,14 @@ where pub fn next_warp_proof_request(&self) -> Option> { match &self.phase { Phase::WarpProof { last_hash, .. } => Some(WarpProofRequest { begin: *last_hash }), - Phase::TargetBlock(_) => None, - Phase::State(_) => None, + Phase::TargetBlock(_) | Phase::State(_) | Phase::PendingTargetBlock { .. } => None, } } /// Produce next target block request. pub fn next_target_block_request(&self) -> Option<(NumberFor, BlockRequest)> { match &self.phase { - Phase::WarpProof { .. } => None, + Phase::WarpProof { .. } | Phase::State(_) | Phase::PendingTargetBlock { .. } => None, Phase::TargetBlock(header) => { let request = BlockRequest:: { id: 0, @@ -198,15 +241,14 @@ where }; 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::WarpProof { .. } => None, - Phase::TargetBlock(_) => None, + Phase::WarpProof { .. } | Phase::TargetBlock(_) | Phase::PendingTargetBlock { .. } => + None, Phase::State(s) => Some(s.target()), } } @@ -214,7 +256,7 @@ where /// Return target block number if it is known. pub fn target_block_number(&self) -> Option> { match &self.phase { - Phase::WarpProof { .. } => None, + Phase::WarpProof { .. } | Phase::PendingTargetBlock { .. } => None, Phase::TargetBlock(header) => Some(*header.number()), Phase::State(s) => Some(s.target_block_num()), } @@ -223,8 +265,8 @@ where /// Check if the state is complete. pub fn is_complete(&self) -> bool { match &self.phase { - Phase::WarpProof { .. } => false, - Phase::TargetBlock(_) => false, + Phase::WarpProof { .. } | Phase::TargetBlock(_) | Phase::PendingTargetBlock { .. } => + false, Phase::State(sync) => sync.is_complete(), } } @@ -240,6 +282,10 @@ where phase: WarpSyncPhase::DownloadingTargetBlock, total_bytes: self.total_proof_bytes, }, + Phase::PendingTargetBlock { .. } => WarpSyncProgress { + phase: WarpSyncPhase::AwaitingTargetBlock, + 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 b3653ac7c0f88..ccaebc976135b 100644 --- a/client/network/test/src/lib.rs +++ b/client/network/test/src/lib.rs @@ -31,7 +31,7 @@ use std::{ time::Duration, }; -use futures::{future::BoxFuture, prelude::*}; +use futures::{channel::oneshot, future::BoxFuture, prelude::*}; use libp2p::{build_multiaddr, PeerId}; use log::trace; use parking_lot::Mutex; @@ -56,7 +56,9 @@ use sc_network_common::{ }, protocol::{role::Roles, ProtocolName}, service::{NetworkBlock, NetworkStateInfo, NetworkSyncForkRequest}, - sync::warp::{AuthorityList, EncodedProof, SetId, VerificationResult, WarpSyncProvider}, + sync::warp::{ + AuthorityList, EncodedProof, SetId, VerificationResult, WarpSyncParams, WarpSyncProvider, + }, }; use sc_network_light::light_client_requests::handler::LightClientRequestHandler; use sc_network_sync::{ @@ -722,6 +724,8 @@ pub struct FullPeerConfig { pub extra_storage: Option, /// Enable transaction indexing. pub storage_chain: bool, + /// Optional target block header to sync to + pub target_block: Option<::Header>, } #[async_trait::async_trait] @@ -867,6 +871,15 @@ where let warp_sync = Arc::new(TestWarpSyncProvider(client.clone())); + let warp_sync_params = match config.target_block { + Some(target_block) => { + let (sender, receiver) = oneshot::channel::<::Header>(); + let _ = sender.send(target_block); + WarpSyncParams::WaitForTarget(receiver) + }, + _ => WarpSyncParams::WithProvider(warp_sync.clone()), + }; + let warp_protocol_config = { let (handler, protocol_config) = warp_request_handler::RequestHandler::new( protocol_id.clone(), @@ -887,6 +900,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, block_announce_config) = ChainSync::new( match network_config.sync_mode { SyncMode::Full => sc_network_common::sync::SyncMode::Full, @@ -903,7 +917,7 @@ where Roles::from(if config.is_authority { &Role::Authority } else { &Role::Full }), block_announce_validator, network_config.max_parallel_downloads, - Some(warp_sync), + Some(warp_sync_params), None, chain_sync_network_handle, import_queue.service(), diff --git a/client/network/test/src/sync.rs b/client/network/test/src/sync.rs index b629574fe9874..8c230640355c9 100644 --- a/client/network/test/src/sync.rs +++ b/client/network/test/src/sync.rs @@ -1249,6 +1249,44 @@ async fn warp_sync() { .await; } +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn warp_sync_to_target_block() { + 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()); + + let blocks = net.peer(0).push_blocks(64, false); + let target = blocks[63]; + net.peer(1).push_blocks(64, false); + net.peer(2).push_blocks(64, false); + + let target_block = net.peer(0).client.header(target).unwrap().unwrap(); + + net.add_full_peer_with_config(FullPeerConfig { + sync_mode: SyncMode::Warp, + target_block: Some(target_block), + ..Default::default() + }); + + net.run_until_sync().await; + assert!(net.peer(3).client().has_state_at(&BlockId::Number(64))); + + // Wait for peer 1 download block history + futures::future::poll_fn::<(), _>(|cx| { + net.poll(cx); + let peer = net.peer(3); + if blocks.iter().all(|b| peer.has_body(*b)) { + Poll::Ready(()) + } else { + Poll::Pending + } + }) + .await; +} + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn syncs_huge_blocks() { use sp_core::storage::well_known_keys::HEAP_PAGES; diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index 0b09f550ce338..a737601f71b83 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -43,7 +43,7 @@ use sc_network_bitswap::BitswapRequestHandler; use sc_network_common::{ protocol::role::Roles, service::{NetworkStateInfo, NetworkStatusProvider}, - sync::warp::WarpSyncProvider, + sync::warp::WarpSyncParams, }; use sc_network_light::light_client_requests::handler::LightClientRequestHandler; use sc_network_sync::{ @@ -759,8 +759,8 @@ pub struct BuildNetworkParams<'a, TBl: BlockT, TExPool, TImpQu, TCl> { /// A block announce validator builder. pub block_announce_validator_builder: Option) -> Box + Send> + Send>>, - /// An optional warp sync provider. - pub warp_sync: Option>>, + /// Optional warp sync params. + pub warp_sync_params: Option>, } /// Build the network service, the network status sinks and an RPC sender. pub fn build_network( @@ -795,12 +795,12 @@ where spawn_handle, import_queue, block_announce_validator_builder, - warp_sync, + warp_sync_params, } = params; let mut request_response_protocol_configs = Vec::new(); - if warp_sync.is_none() && config.network.sync_mode.is_warp() { + if warp_sync_params.is_none() && config.network.sync_mode.is_warp() { return Err("Warp sync enabled, but no warp sync provider configured.".into()) } @@ -845,8 +845,8 @@ where protocol_config }; - let (warp_sync_provider, warp_sync_protocol_config) = warp_sync - .map(|provider| { + let warp_sync_protocol_config = match warp_sync_params.as_ref() { + Some(WarpSyncParams::WithProvider(warp_with_provider)) => { // Allow both outgoing and incoming requests. let (handler, protocol_config) = WarpSyncRequestHandler::new( protocol_id.clone(), @@ -856,12 +856,13 @@ where .flatten() .expect("Genesis block exists; qed"), config.chain_spec.fork_id(), - provider.clone(), + warp_with_provider.clone(), ); spawn_handle.spawn("warp-sync-request-handler", Some("networking"), handler.run()); - (Some(provider), Some(protocol_config)) - }) - .unwrap_or_default(); + Some(protocol_config) + }, + _ => None, + }; let light_client_request_protocol_config = { // Allow both outgoing and incoming requests. @@ -888,7 +889,7 @@ where Roles::from(&config.role), block_announce_validator, config.network.max_parallel_downloads, - warp_sync_provider, + warp_sync_params, config.prometheus_config.as_ref().map(|config| config.registry.clone()).as_ref(), chain_sync_network_handle, import_queue.service(), diff --git a/client/service/src/lib.rs b/client/service/src/lib.rs index 1529b822ade32..e3dcf012892c3 100644 --- a/client/service/src/lib.rs +++ b/client/service/src/lib.rs @@ -73,6 +73,7 @@ pub use sc_chain_spec::{ pub use sc_consensus::ImportQueue; pub use sc_executor::NativeExecutionDispatch; +pub use sc_network_common::sync::warp::WarpSyncParams; #[doc(hidden)] pub use sc_network_transactions::config::{TransactionImport, TransactionImportFuture}; pub use sc_rpc::{ From 169c3f02449566638225ab73bdf75a95cb8b1da0 Mon Sep 17 00:00:00 2001 From: Sasha Gryaznov Date: Tue, 14 Feb 2023 20:28:34 +0200 Subject: [PATCH 395/715] [contracts] make `debug_message` execution outcome invariant to node debug logging setting (#13197) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * update benchmark for seal_debug_message * add seal_debug_message_per_kb benchmark * un-fallable debug buffer: silently drops excessive and wrong utf-8 encoded messages * charge debug_message per byte of the message * improved benchmark * cap debug_message * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_contracts * Apply suggestions from code review Co-authored-by: Alexander Theißen * fix applied buggy suggestion * make sure i*1024 < MaxDebugBufferLen * fix schedule for our non-batched benchmark * Switch to a `wasmtime` fork with LTO linking failure workaround * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_contracts --------- Co-authored-by: command-bot <> Co-authored-by: Alexander Theißen Co-authored-by: Jan Bujak --- Cargo.lock | 57 +- client/executor/wasmtime/Cargo.toml | 2 +- .../fixtures/debug_message_invalid_utf8.wat | 24 +- .../debug_message_logging_disabled.wat | 2 +- frame/contracts/src/benchmarking/mod.rs | 73 +- frame/contracts/src/exec.rs | 51 +- frame/contracts/src/lib.rs | 2 - frame/contracts/src/schedule.rs | 4 + frame/contracts/src/tests.rs | 3 +- frame/contracts/src/wasm/mod.rs | 9 +- frame/contracts/src/wasm/runtime.rs | 35 +- frame/contracts/src/weights.rs | 2174 ++++++++++------- primitives/wasm-interface/Cargo.toml | 2 +- 13 files changed, 1373 insertions(+), 1065 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0c2f8518473ff..ef320a85f05a6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1186,8 +1186,7 @@ checksum = "dcb25d077389e53838a8158c8e99174c5a9d902dee4904320db714f3c653ffba" [[package]] name = "cranelift-bforest" version = "0.92.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f3d54eab028f5805ae3b26fd60eca3f3a9cfb76b989d9bab173be3f61356cc3" +source = "git+https://github.com/paritytech/wasmtime.git?branch=v5.0.0_lto_fix#8a02705ad378108e43abe23c538688adf73f3b71" dependencies = [ "cranelift-entity", ] @@ -1195,8 +1194,7 @@ dependencies = [ [[package]] name = "cranelift-codegen" version = "0.92.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2be1d5f2c3cca1efb691844bc1988b89c77291f13f778499a3f3c0cf49c0ed61" +source = "git+https://github.com/paritytech/wasmtime.git?branch=v5.0.0_lto_fix#8a02705ad378108e43abe23c538688adf73f3b71" dependencies = [ "arrayvec 0.7.2", "bumpalo", @@ -1216,8 +1214,7 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" version = "0.92.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9b1b1089750ce4005893af7ee00bb08a2cf1c9779999c0f7164cbc8ad2e0d2" +source = "git+https://github.com/paritytech/wasmtime.git?branch=v5.0.0_lto_fix#8a02705ad378108e43abe23c538688adf73f3b71" dependencies = [ "cranelift-codegen-shared", ] @@ -1225,14 +1222,12 @@ dependencies = [ [[package]] name = "cranelift-codegen-shared" version = "0.92.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc5fbaec51de47297fd7304986fd53c8c0030abbe69728a60d72e1c63559318d" +source = "git+https://github.com/paritytech/wasmtime.git?branch=v5.0.0_lto_fix#8a02705ad378108e43abe23c538688adf73f3b71" [[package]] name = "cranelift-entity" version = "0.92.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dab984c94593f876090fae92e984bdcc74d9b1acf740ab5f79036001c65cba13" +source = "git+https://github.com/paritytech/wasmtime.git?branch=v5.0.0_lto_fix#8a02705ad378108e43abe23c538688adf73f3b71" dependencies = [ "serde", ] @@ -1240,8 +1235,7 @@ dependencies = [ [[package]] name = "cranelift-frontend" version = "0.92.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e0cb3102d21a2fe5f3210af608748ddd0cd09825ac12d42dc56ed5ed8725fe0" +source = "git+https://github.com/paritytech/wasmtime.git?branch=v5.0.0_lto_fix#8a02705ad378108e43abe23c538688adf73f3b71" dependencies = [ "cranelift-codegen", "log", @@ -1252,14 +1246,12 @@ dependencies = [ [[package]] name = "cranelift-isle" version = "0.92.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72101dd1f441d629735143c41e00b3428f9267738176983ef588ff43382af0a0" +source = "git+https://github.com/paritytech/wasmtime.git?branch=v5.0.0_lto_fix#8a02705ad378108e43abe23c538688adf73f3b71" [[package]] name = "cranelift-native" version = "0.92.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c22b0d9fcbe3fc5a1af9e7021b44ce42b930bcefac446ce22e02e8f9a0d67120" +source = "git+https://github.com/paritytech/wasmtime.git?branch=v5.0.0_lto_fix#8a02705ad378108e43abe23c538688adf73f3b71" dependencies = [ "cranelift-codegen", "libc", @@ -1269,8 +1261,7 @@ dependencies = [ [[package]] name = "cranelift-wasm" version = "0.92.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bddebe32fb14fbfd9efa5f130ffb8f4665795de019928dcd7247b136c46f9249" +source = "git+https://github.com/paritytech/wasmtime.git?branch=v5.0.0_lto_fix#8a02705ad378108e43abe23c538688adf73f3b71" dependencies = [ "cranelift-codegen", "cranelift-entity", @@ -11932,8 +11923,7 @@ dependencies = [ [[package]] name = "wasmtime" version = "5.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e5b183a159484980138cc05231419c536d395a7b25c1802091310ea2f74276a" +source = "git+https://github.com/paritytech/wasmtime.git?branch=v5.0.0_lto_fix#8a02705ad378108e43abe23c538688adf73f3b71" dependencies = [ "anyhow", "bincode", @@ -11960,8 +11950,7 @@ dependencies = [ [[package]] name = "wasmtime-asm-macros" version = "5.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0aeb1cb256d76cf07b20264c808351c8b525ece56de1ef4d93f87a0aaf342db" +source = "git+https://github.com/paritytech/wasmtime.git?branch=v5.0.0_lto_fix#8a02705ad378108e43abe23c538688adf73f3b71" dependencies = [ "cfg-if", ] @@ -11969,8 +11958,7 @@ dependencies = [ [[package]] name = "wasmtime-cache" version = "5.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830570847f905b8f6d2ca635c33cf42ce701dd8e4abd7d1806c631f8f06e9e4b" +source = "git+https://github.com/paritytech/wasmtime.git?branch=v5.0.0_lto_fix#8a02705ad378108e43abe23c538688adf73f3b71" dependencies = [ "anyhow", "base64 0.13.1", @@ -11989,8 +11977,7 @@ dependencies = [ [[package]] name = "wasmtime-cranelift" version = "5.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f7695d3814dcb508bf4d1c181a86ea6b97a209f6444478e95d86e2ffab8d1a3" +source = "git+https://github.com/paritytech/wasmtime.git?branch=v5.0.0_lto_fix#8a02705ad378108e43abe23c538688adf73f3b71" dependencies = [ "anyhow", "cranelift-codegen", @@ -12010,8 +11997,7 @@ dependencies = [ [[package]] name = "wasmtime-environ" version = "5.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5a2a5f0fb93aa837a727a48dd1076e8a9f882cc2fee20b433c04a18740ff63b" +source = "git+https://github.com/paritytech/wasmtime.git?branch=v5.0.0_lto_fix#8a02705ad378108e43abe23c538688adf73f3b71" dependencies = [ "anyhow", "cranelift-entity", @@ -12029,8 +12015,7 @@ dependencies = [ [[package]] name = "wasmtime-jit" version = "5.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01c78f9fb2922dbb5a95f009539d4badb44866caeeb53d156bf2cf4d683c3afd" +source = "git+https://github.com/paritytech/wasmtime.git?branch=v5.0.0_lto_fix#8a02705ad378108e43abe23c538688adf73f3b71" dependencies = [ "addr2line 0.17.0", "anyhow", @@ -12053,8 +12038,7 @@ dependencies = [ [[package]] name = "wasmtime-jit-debug" version = "5.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67cacdb52a77b8c8e744e510beeabf0bd698b1c94c59eed33c52b3fbd19639b0" +source = "git+https://github.com/paritytech/wasmtime.git?branch=v5.0.0_lto_fix#8a02705ad378108e43abe23c538688adf73f3b71" dependencies = [ "object 0.29.0", "once_cell", @@ -12064,8 +12048,7 @@ dependencies = [ [[package]] name = "wasmtime-jit-icache-coherence" version = "5.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08fcba5ebd96da2a9f0747ab6337fe9788adfb3f63fa2c180520d665562d257e" +source = "git+https://github.com/paritytech/wasmtime.git?branch=v5.0.0_lto_fix#8a02705ad378108e43abe23c538688adf73f3b71" dependencies = [ "cfg-if", "libc", @@ -12075,8 +12058,7 @@ dependencies = [ [[package]] name = "wasmtime-runtime" version = "5.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0793210acf50d4c69182c916abaee1d423dc5d172cdfde6acfea2f9446725940" +source = "git+https://github.com/paritytech/wasmtime.git?branch=v5.0.0_lto_fix#8a02705ad378108e43abe23c538688adf73f3b71" dependencies = [ "anyhow", "cc", @@ -12099,8 +12081,7 @@ dependencies = [ [[package]] name = "wasmtime-types" version = "5.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d015ba8b231248a811e323cf7a525cd3f982d4be0b9e62d27685102e5f12b1" +source = "git+https://github.com/paritytech/wasmtime.git?branch=v5.0.0_lto_fix#8a02705ad378108e43abe23c538688adf73f3b71" dependencies = [ "cranelift-entity", "serde", diff --git a/client/executor/wasmtime/Cargo.toml b/client/executor/wasmtime/Cargo.toml index acd1a5aef9391..e29a195277681 100644 --- a/client/executor/wasmtime/Cargo.toml +++ b/client/executor/wasmtime/Cargo.toml @@ -25,7 +25,7 @@ wasmtime = { version = "5.0.0", default-features = false, features = [ "jitdump", "parallel-compilation", "pooling-allocator" -] } +], git = "https://github.com/paritytech/wasmtime.git", branch = "v5.0.0_lto_fix" } anyhow = "1.0.68" sc-allocator = { version = "4.1.0-dev", path = "../../allocator" } sc-executor-common = { version = "0.10.0-dev", path = "../common" } diff --git a/frame/contracts/fixtures/debug_message_invalid_utf8.wat b/frame/contracts/fixtures/debug_message_invalid_utf8.wat index c60371076440e..e8c447b42fca5 100644 --- a/frame/contracts/fixtures/debug_message_invalid_utf8.wat +++ b/frame/contracts/fixtures/debug_message_invalid_utf8.wat @@ -1,18 +1,28 @@ -;; Emit a "Hello World!" debug message +;; Emit a debug message with an invalid utf-8 code (module (import "seal0" "seal_debug_message" (func $seal_debug_message (param i32 i32) (result i32))) (import "env" "memory" (memory 1 1)) (data (i32.const 0) "\fc") - (func (export "call") - (call $seal_debug_message - (i32.const 0) ;; Pointer to the text buffer - (i32.const 12) ;; The size of the buffer + (func $assert_eq (param i32 i32) + (block $ok + (br_if $ok + (i32.eq (get_local 0) (get_local 1)) + ) + (unreachable) ) - ;; the above call traps because we supplied invalid utf8 - unreachable ) + (func (export "call") + (call $assert_eq + (call $seal_debug_message + (i32.const 0) ;; Pointer to the text buffer + (i32.const 12) ;; The size of the buffer + ) + (i32.const 0) ;; Success return code + ) + ) + (func (export "deploy")) ) diff --git a/frame/contracts/fixtures/debug_message_logging_disabled.wat b/frame/contracts/fixtures/debug_message_logging_disabled.wat index cfe238943ad06..fc6ee72df8b08 100644 --- a/frame/contracts/fixtures/debug_message_logging_disabled.wat +++ b/frame/contracts/fixtures/debug_message_logging_disabled.wat @@ -20,7 +20,7 @@ (i32.const 0) ;; Pointer to the text buffer (i32.const 12) ;; The size of the buffer ) - (i32.const 9) ;; LoggingDisabled return code + (i32.const 0) ;; Success return code ) ) diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index 708d92766d488..e834508a0e284 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -910,13 +910,12 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); }: 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 - // when the contract is called as RPC where weights do not matter. + // Benchmark debug_message call with zero input data. + // Whereas this function is used in RPC mode only, it still should be secured + // against an excessive use. #[pov_mode = Ignored] seal_debug_message { let r in 0 .. API_BENCHMARK_BATCHES; - let max_bytes = code::max_pages::() * 64 * 1024; let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory { min_pages: 1, max_pages: 1 }), imported_functions: vec![ImportedFunction { @@ -927,15 +926,75 @@ benchmarks! { }], call_body: Some(body::repeated(r * API_BENCHMARK_BATCH_SIZE, &[ Instruction::I32Const(0), // value_ptr - Instruction::I32Const(max_bytes as i32), // value_len + Instruction::I32Const(0), // value_len 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![]) + }: { + >::bare_call( + instance.caller, + instance.account_id, + 0u32.into(), + Weight::MAX, + None, + vec![], + true, + Determinism::Deterministic, + ) + .result?; + } + + seal_debug_message_per_kb { + // Vary size of input in kilobytes up to maximum allowed contract memory + // or maximum allowed debug buffer size, whichever is less. + let i in 0 .. (T::Schedule::get().limits.memory_pages * 64).min(T::MaxDebugBufferLen::get() / 1024); + // We benchmark versus messages containing printable ASCII codes. + // About 1Kb goes to the instrumented contract code instructions, + // whereas all the space left we use for the initialization of the debug messages data. + let message = (0 .. T::MaxCodeLen::get() - 1024).zip((32..127).cycle()).map(|i| i.1).collect::>(); + let code = WasmModule::::from(ModuleDefinition { + memory: Some(ImportedMemory { + min_pages: T::Schedule::get().limits.memory_pages, + max_pages: T::Schedule::get().limits.memory_pages, + }), + imported_functions: vec![ImportedFunction { + module: "seal0", + name: "seal_debug_message", + params: vec![ValueType::I32, ValueType::I32], + return_type: Some(ValueType::I32), + }], + data_segments: vec![ + DataSegment { + offset: 0, + value: message, + }, + ], + call_body: Some(body::plain(vec![ + Instruction::I32Const(0), // value_ptr + Instruction::I32Const((i * 1024) as i32), // value_len increments by i Kb + Instruction::Call(0), + Instruction::Drop, + Instruction::End, + ])), + ..Default::default() + }); + let instance = Contract::::new(code, vec![])?; + }: { + >::bare_call( + instance.caller, + instance.account_id, + 0u32.into(), + Weight::MAX, + None, + vec![], + true, + Determinism::Deterministic, + ) + .result?; + } // Only the overhead of calling the function itself with minimal arguments. // The contract is a bit more complex because it needs to use different keys in order diff --git a/frame/contracts/src/exec.rs b/frame/contracts/src/exec.rs index 3eb59354d5c07..9b033a76cf0ff 100644 --- a/frame/contracts/src/exec.rs +++ b/frame/contracts/src/exec.rs @@ -1336,31 +1336,16 @@ where fn append_debug_buffer(&mut self, msg: &str) -> bool { if let Some(buffer) = &mut self.debug_message { - let err_msg = scale_info::prelude::format!( - "Debug message too big (size={}) for debug buffer (bound={})", - msg.len(), - DebugBufferVec::::bound(), - ); - - let mut msg = if msg.len() > DebugBufferVec::::bound() { - err_msg.bytes() - } else { - msg.bytes() - }; - - let num_drain = { - let capacity = DebugBufferVec::::bound().checked_sub(buffer.len()).expect( - " - `buffer` is of type `DebugBufferVec`, - `DebugBufferVec` is a `BoundedVec`, - `BoundedVec::len()` <= `BoundedVec::bound()`; - qed - ", - ); - msg.len().saturating_sub(capacity).min(buffer.len()) - }; - buffer.drain(0..num_drain); - buffer.try_extend(&mut msg).ok(); + buffer + .try_extend(&mut msg.bytes()) + .map_err(|_| { + log::debug!( + target: "runtime::contracts", + "Debug buffer (of {} bytes) exhausted!", + DebugBufferVec::::bound(), + ) + }) + .ok(); true } else { false @@ -2603,9 +2588,11 @@ mod tests { exec_success() }); - // Pre-fill the buffer up to its limit - let mut debug_buffer = - DebugBufferVec::::try_from(vec![0u8; DebugBufferVec::::bound()]).unwrap(); + // Pre-fill the buffer almost up to its limit, leaving not enough space to the message + let debug_buf_before = + DebugBufferVec::::try_from(vec![0u8; DebugBufferVec::::bound() - 5]) + .unwrap(); + let mut debug_buf_after = debug_buf_before.clone(); ExtBuilder::default().build().execute_with(|| { let schedule: Schedule = ::Schedule::get(); @@ -2622,15 +2609,11 @@ mod tests { &schedule, 0, vec![], - Some(&mut debug_buffer), + Some(&mut debug_buf_after), Determinism::Deterministic, ) .unwrap(); - assert_eq!( - &String::from_utf8(debug_buffer[DebugBufferVec::::bound() - 17..].to_vec()) - .unwrap(), - "overflowing bytes" - ); + assert_eq!(debug_buf_before, debug_buf_after); }); } diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index c067b264477e9..e131a2685bad9 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -912,8 +912,6 @@ pub mod pallet { /// /// This can be triggered by a call to `seal_terminate`. TerminatedInConstructor, - /// The debug message specified to `seal_debug_message` does contain invalid UTF-8. - 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. diff --git a/frame/contracts/src/schedule.rs b/frame/contracts/src/schedule.rs index 7e09d55b44c58..5e4798df147b2 100644 --- a/frame/contracts/src/schedule.rs +++ b/frame/contracts/src/schedule.rs @@ -323,6 +323,9 @@ pub struct HostFnWeights { /// Weight of calling `seal_debug_message`. pub debug_message: Weight, + /// Weight of calling `seal_debug_message` per byte of the message. + pub debug_message_per_byte: Weight, + /// Weight of calling `seal_set_storage`. pub set_storage: Weight, @@ -644,6 +647,7 @@ impl Default for HostFnWeights { 1 )), debug_message: to_weight!(cost_batched!(seal_debug_message)), + debug_message_per_byte: to_weight!(cost_byte!(seal_debug_message_per_kb)), set_storage: to_weight!(cost_batched!(seal_set_storage), 1024u64), set_code_hash: to_weight!(cost_batched!(seal_set_code_hash)), set_storage_per_new_byte: to_weight!(cost_byte_batched!(seal_set_storage_per_new_kb)), diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index 973fdefe141bf..958cbf772dba5 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -2714,7 +2714,8 @@ fn debug_message_invalid_utf8() { true, Determinism::Deterministic, ); - assert_err!(result.result, >::DebugMessageInvalidUTF8); + assert_ok!(result.result); + assert!(result.debug_message.is_empty()); }); } diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index 9bf36b47f0b06..3ca7326187a5b 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -2363,13 +2363,8 @@ mod tests { "#; let mut ext = MockExt::default(); let result = execute(CODE_DEBUG_MESSAGE_FAIL, vec![], &mut ext); - assert_eq!( - result, - Err(ExecError { - error: Error::::DebugMessageInvalidUTF8.into(), - origin: ErrorOrigin::Caller, - }) - ); + assert_ok!(result); + assert!(ext.debug_buffer.is_empty()); } const CODE_CALL_RUNTIME: &str = r#" diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index 9cdf0bf0928a9..ef0c35df73c6a 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -21,7 +21,7 @@ use crate::{ exec::{ExecError, ExecResult, Ext, FixSizedKey, TopicOf, VarSizedKey}, gas::{ChargedAmount, Token}, schedule::HostFnWeights, - BalanceOf, CodeHash, Config, Error, SENTINEL, + BalanceOf, CodeHash, Config, DebugBufferVec, Error, SENTINEL, }; use bitflags::bitflags; @@ -114,9 +114,6 @@ pub enum ReturnCode { CodeNotFound = 7, /// The contract that was called is no contract (a plain account). NotCallable = 8, - /// The call to `seal_debug_message` had no effect because debug message - /// recording was disabled. - LoggingDisabled = 9, /// The call dispatched by `seal_call_runtime` was executed but returned an error. CallRuntimeReturnedError = 10, /// ECDSA pubkey recovery failed (most probably wrong recovery id or signature), or @@ -229,8 +226,8 @@ pub enum RuntimeCosts { Random, /// Weight of calling `seal_deposit_event` with the given number of topics and event size. DepositEvent { num_topic: u32, len: u32 }, - /// Weight of calling `seal_debug_message`. - DebugMessage, + /// Weight of calling `seal_debug_message` per byte of passed message. + DebugMessage(u32), /// 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. @@ -309,7 +306,9 @@ impl RuntimeCosts { .deposit_event .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, + DebugMessage(len) => s + .debug_message + .saturating_add(s.deposit_event_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())) @@ -2054,7 +2053,7 @@ pub mod env { _delta_ptr: u32, _delta_count: u32, ) -> Result<(), TrapReason> { - ctx.charge_gas(RuntimeCosts::DebugMessage)?; + ctx.charge_gas(RuntimeCosts::DebugMessage(0))?; Ok(()) } @@ -2076,7 +2075,7 @@ pub mod env { _delta_ptr: u32, _delta_count: u32, ) -> Result<(), TrapReason> { - ctx.charge_gas(RuntimeCosts::DebugMessage)?; + ctx.charge_gas(RuntimeCosts::DebugMessage(0))?; Ok(()) } @@ -2094,7 +2093,7 @@ pub mod env { _value_ptr: u32, _value_len: u32, ) -> Result<(), TrapReason> { - ctx.charge_gas(RuntimeCosts::DebugMessage)?; + ctx.charge_gas(RuntimeCosts::DebugMessage(0))?; Ok(()) } @@ -2108,7 +2107,7 @@ pub mod env { #[prefixed_alias] #[deprecated] fn set_rent_allowance(ctx: _, _memory: _, _value_ptr: u32) -> Result<(), TrapReason> { - ctx.charge_gas(RuntimeCosts::DebugMessage)?; + ctx.charge_gas(RuntimeCosts::DebugMessage(0))?; Ok(()) } @@ -2362,7 +2361,7 @@ pub mod env { /// Emit a custom debug message. /// /// No newlines are added to the supplied message. - /// Specifying invalid UTF-8 triggers a trap. + /// Specifying invalid UTF-8 just drops the message with no 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 @@ -2383,15 +2382,15 @@ pub mod env { str_ptr: u32, str_len: u32, ) -> Result { - ctx.charge_gas(RuntimeCosts::DebugMessage)?; + let str_len = str_len.min(DebugBufferVec::::bound() as u32); + ctx.charge_gas(RuntimeCosts::DebugMessage(str_len))?; 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); - return Ok(ReturnCode::Success) + if let Some(msg) = core::str::from_utf8(&data).ok() { + ctx.ext.append_debug_buffer(msg); + } } - Ok(ReturnCode::LoggingDisabled) + Ok(ReturnCode::Success) } /// Call some dispatchable of the runtime. diff --git a/frame/contracts/src/weights.rs b/frame/contracts/src/weights.rs index d9ec1b10b2d37..50aa30e89e58b 100644 --- a/frame/contracts/src/weights.rs +++ b/frame/contracts/src/weights.rs @@ -18,25 +18,26 @@ //! Autogenerated weights for pallet_contracts //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-02-14, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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)] @@ -82,6 +83,7 @@ pub trait WeightInfo { fn seal_deposit_event(r: u32, ) -> Weight; fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight; fn seal_debug_message(r: u32, ) -> Weight; + fn seal_debug_message_per_kb(i: u32, ) -> Weight; fn seal_set_storage(r: u32, ) -> Weight; fn seal_set_storage_per_new_kb(n: u32, ) -> Weight; fn seal_set_storage_per_old_kb(n: u32, ) -> Weight; @@ -176,8 +178,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `109` // Estimated: `0` - // Minimum execution time: 2_305 nanoseconds. - Weight::from_ref_time(2_560_000) + // Minimum execution time: 2_564 nanoseconds. + Weight::from_ref_time(2_722_000) + .saturating_add(Weight::from_proof_size(0)) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: Skipped Metadata (r:0 w:0) @@ -187,10 +190,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `481 + k * (69 ±0)` // Estimated: `0` - // Minimum execution time: 9_311 nanoseconds. - Weight::from_ref_time(5_419_288) - // Standard Error: 562 - .saturating_add(Weight::from_ref_time(911_962).saturating_mul(k.into())) + // Minimum execution time: 10_292 nanoseconds. + Weight::from_ref_time(7_474_496) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 901 + .saturating_add(Weight::from_ref_time(956_864).saturating_mul(k.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(k.into()))) @@ -202,10 +206,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `281 + q * (33 ±0)` // Estimated: `0` - // Minimum execution time: 2_288 nanoseconds. - Weight::from_ref_time(9_442_437) - // Standard Error: 2_720 - .saturating_add(Weight::from_ref_time(1_076_950).saturating_mul(q.into())) + // Minimum execution time: 2_620 nanoseconds. + Weight::from_ref_time(10_288_873) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 3_073 + .saturating_add(Weight::from_ref_time(1_148_167).saturating_mul(q.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -218,10 +223,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `270 + c * (1 ±0)` // Estimated: `0` - // Minimum execution time: 27_539 nanoseconds. - Weight::from_ref_time(23_554_889) - // Standard Error: 56 - .saturating_add(Weight::from_ref_time(46_766).saturating_mul(c.into())) + // Minimum execution time: 28_004 nanoseconds. + Weight::from_ref_time(26_706_943) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 67 + .saturating_add(Weight::from_ref_time(51_603).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -240,10 +246,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `771` // Estimated: `0` - // Minimum execution time: 297_710 nanoseconds. - Weight::from_ref_time(307_327_529) - // Standard Error: 18 - .saturating_add(Weight::from_ref_time(29_849).saturating_mul(c.into())) + // Minimum execution time: 295_799 nanoseconds. + Weight::from_ref_time(308_660_753) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 20 + .saturating_add(Weight::from_ref_time(32_458).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -270,14 +277,15 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `257` // Estimated: `0` - // Minimum execution time: 3_586_223 nanoseconds. - Weight::from_ref_time(561_614_281) - // Standard Error: 274 - .saturating_add(Weight::from_ref_time(87_557).saturating_mul(c.into())) + // Minimum execution time: 3_754_887 nanoseconds. + Weight::from_ref_time(657_695_827) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 283 + .saturating_add(Weight::from_ref_time(94_808).saturating_mul(c.into())) // Standard Error: 16 - .saturating_add(Weight::from_ref_time(1_307).saturating_mul(i.into())) + .saturating_add(Weight::from_ref_time(1_357).saturating_mul(i.into())) // Standard Error: 16 - .saturating_add(Weight::from_ref_time(1_721).saturating_mul(s.into())) + .saturating_add(Weight::from_ref_time(1_756).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(9_u64)) } @@ -301,12 +309,13 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `533` // Estimated: `0` - // Minimum execution time: 1_885_437 nanoseconds. - Weight::from_ref_time(199_943_867) + // Minimum execution time: 1_961_131 nanoseconds. + Weight::from_ref_time(208_539_564) + .saturating_add(Weight::from_proof_size(0)) // Standard Error: 8 - .saturating_add(Weight::from_ref_time(1_611).saturating_mul(i.into())) + .saturating_add(Weight::from_ref_time(1_688).saturating_mul(i.into())) // Standard Error: 8 - .saturating_add(Weight::from_ref_time(1_737).saturating_mul(s.into())) + .saturating_add(Weight::from_ref_time(1_802).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } @@ -324,8 +333,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `823` // Estimated: `0` - // Minimum execution time: 150_604 nanoseconds. - Weight::from_ref_time(151_777_000) + // Minimum execution time: 148_138 nanoseconds. + Weight::from_ref_time(148_862_000) + .saturating_add(Weight::from_proof_size(0)) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -342,10 +352,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `109` // Estimated: `0` - // Minimum execution time: 295_505 nanoseconds. - Weight::from_ref_time(305_609_098) - // Standard Error: 58 - .saturating_add(Weight::from_ref_time(88_676).saturating_mul(c.into())) + // Minimum execution time: 293_444 nanoseconds. + Weight::from_ref_time(293_242_988) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 156 + .saturating_add(Weight::from_ref_time(97_476).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -361,8 +372,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `287` // Estimated: `0` - // Minimum execution time: 25_949 nanoseconds. - Weight::from_ref_time(26_316_000) + // Minimum execution time: 26_802 nanoseconds. + Weight::from_ref_time(27_121_000) + .saturating_add(Weight::from_proof_size(0)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -376,8 +388,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `634` // Estimated: `0` - // Minimum execution time: 29_005 nanoseconds. - Weight::from_ref_time(29_370_000) + // Minimum execution time: 31_079 nanoseconds. + Weight::from_ref_time(31_541_000) + .saturating_add(Weight::from_proof_size(0)) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -396,10 +409,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `845 + r * (480 ±0)` // Estimated: `0` - // Minimum execution time: 281_880 nanoseconds. - Weight::from_ref_time(289_637_700) - // Standard Error: 22_662 - .saturating_add(Weight::from_ref_time(16_866_274).saturating_mul(r.into())) + // Minimum execution time: 284_877 nanoseconds. + Weight::from_ref_time(290_043_606) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 22_094 + .saturating_add(Weight::from_ref_time(18_094_219).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -418,10 +432,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `882 + r * (19218 ±0)` // Estimated: `0` - // Minimum execution time: 285_590 nanoseconds. - Weight::from_ref_time(231_277_523) - // Standard Error: 425_084 - .saturating_add(Weight::from_ref_time(192_985_377).saturating_mul(r.into())) + // Minimum execution time: 283_956 nanoseconds. + Weight::from_ref_time(129_690_397) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 531_270 + .saturating_add(Weight::from_ref_time(264_082_418).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -441,10 +456,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `889 + r * (19539 ±0)` // Estimated: `0` - // Minimum execution time: 282_966 nanoseconds. - Weight::from_ref_time(236_127_328) - // Standard Error: 405_193 - .saturating_add(Weight::from_ref_time(235_541_377).saturating_mul(r.into())) + // Minimum execution time: 287_077 nanoseconds. + Weight::from_ref_time(148_155_166) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 466_496 + .saturating_add(Weight::from_ref_time(306_625_930).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -464,10 +480,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `852 + r * (480 ±0)` // Estimated: `0` - // Minimum execution time: 286_021 nanoseconds. - Weight::from_ref_time(290_200_599) - // Standard Error: 19_224 - .saturating_add(Weight::from_ref_time(20_692_099).saturating_mul(r.into())) + // Minimum execution time: 286_459 nanoseconds. + Weight::from_ref_time(292_826_594) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 27_808 + .saturating_add(Weight::from_ref_time(22_401_931).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -486,10 +503,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `842 + r * (240 ±0)` // Estimated: `0` - // Minimum execution time: 284_175 nanoseconds. - Weight::from_ref_time(286_665_694) - // Standard Error: 14_104 - .saturating_add(Weight::from_ref_time(11_196_944).saturating_mul(r.into())) + // Minimum execution time: 284_330 nanoseconds. + Weight::from_ref_time(289_069_701) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 13_666 + .saturating_add(Weight::from_ref_time(11_157_859).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -508,10 +526,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `846 + r * (480 ±0)` // Estimated: `0` - // Minimum execution time: 285_315 nanoseconds. - Weight::from_ref_time(289_734_189) - // Standard Error: 15_980 - .saturating_add(Weight::from_ref_time(16_940_657).saturating_mul(r.into())) + // Minimum execution time: 284_506 nanoseconds. + Weight::from_ref_time(290_155_141) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 22_944 + .saturating_add(Weight::from_ref_time(17_992_627).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -530,10 +549,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `847 + r * (480 ±0)` // Estimated: `0` - // Minimum execution time: 285_708 nanoseconds. - Weight::from_ref_time(289_872_393) - // Standard Error: 16_551 - .saturating_add(Weight::from_ref_time(16_672_944).saturating_mul(r.into())) + // Minimum execution time: 284_177 nanoseconds. + Weight::from_ref_time(289_314_787) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 24_552 + .saturating_add(Weight::from_ref_time(17_754_919).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -552,10 +572,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1017 + r * (480 ±0)` // Estimated: `0` - // Minimum execution time: 285_698 nanoseconds. - Weight::from_ref_time(295_636_093) - // Standard Error: 97_582 - .saturating_add(Weight::from_ref_time(92_891_252).saturating_mul(r.into())) + // Minimum execution time: 284_096 nanoseconds. + Weight::from_ref_time(293_655_130) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 56_379 + .saturating_add(Weight::from_ref_time(95_688_575).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -574,10 +595,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `856 + r * (480 ±0)` // Estimated: `0` - // Minimum execution time: 282_057 nanoseconds. - Weight::from_ref_time(289_304_621) - // Standard Error: 17_818 - .saturating_add(Weight::from_ref_time(16_725_632).saturating_mul(r.into())) + // Minimum execution time: 285_967 nanoseconds. + Weight::from_ref_time(288_043_137) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 83_838 + .saturating_add(Weight::from_ref_time(18_256_709).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -596,10 +618,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `854 + r * (480 ±0)` // Estimated: `0` - // Minimum execution time: 282_478 nanoseconds. - Weight::from_ref_time(289_682_366) - // Standard Error: 20_379 - .saturating_add(Weight::from_ref_time(16_517_079).saturating_mul(r.into())) + // Minimum execution time: 284_060 nanoseconds. + Weight::from_ref_time(290_577_678) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 26_131 + .saturating_add(Weight::from_ref_time(17_560_562).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -618,10 +641,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `851 + r * (480 ±0)` // Estimated: `0` - // Minimum execution time: 283_826 nanoseconds. - Weight::from_ref_time(289_935_300) - // Standard Error: 15_180 - .saturating_add(Weight::from_ref_time(16_268_515).saturating_mul(r.into())) + // Minimum execution time: 286_068 nanoseconds. + Weight::from_ref_time(290_026_137) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 34_787 + .saturating_add(Weight::from_ref_time(17_597_404).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -640,10 +664,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `842 + r * (480 ±0)` // Estimated: `0` - // Minimum execution time: 285_455 nanoseconds. - Weight::from_ref_time(289_682_526) - // Standard Error: 18_667 - .saturating_add(Weight::from_ref_time(16_502_025).saturating_mul(r.into())) + // Minimum execution time: 285_082 nanoseconds. + Weight::from_ref_time(290_487_103) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 22_743 + .saturating_add(Weight::from_ref_time(17_506_771).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -664,10 +689,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `919 + r * (800 ±0)` // Estimated: `0` - // Minimum execution time: 286_106 nanoseconds. - Weight::from_ref_time(294_493_680) - // Standard Error: 76_469 - .saturating_add(Weight::from_ref_time(87_055_837).saturating_mul(r.into())) + // Minimum execution time: 285_309 nanoseconds. + Weight::from_ref_time(296_735_365) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 49_300 + .saturating_add(Weight::from_ref_time(87_678_979).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -686,10 +712,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `809 + r * (320 ±0)` // Estimated: `0` - // Minimum execution time: 137_877 nanoseconds. - Weight::from_ref_time(141_863_027) - // Standard Error: 10_200 - .saturating_add(Weight::from_ref_time(7_925_232).saturating_mul(r.into())) + // Minimum execution time: 136_110 nanoseconds. + Weight::from_ref_time(139_800_659) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 9_674 + .saturating_add(Weight::from_ref_time(8_302_834).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -708,10 +735,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `844 + r * (480 ±0)` // Estimated: `0` - // Minimum execution time: 282_034 nanoseconds. - Weight::from_ref_time(289_388_799) - // Standard Error: 21_999 - .saturating_add(Weight::from_ref_time(15_039_420).saturating_mul(r.into())) + // Minimum execution time: 285_238 nanoseconds. + Weight::from_ref_time(289_723_839) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 19_531 + .saturating_add(Weight::from_ref_time(15_590_085).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -730,10 +758,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1324` // Estimated: `0` - // Minimum execution time: 303_229 nanoseconds. - Weight::from_ref_time(321_863_704) - // Standard Error: 2_754 - .saturating_add(Weight::from_ref_time(9_545_103).saturating_mul(n.into())) + // Minimum execution time: 303_189 nanoseconds. + Weight::from_ref_time(323_374_503) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 2_060 + .saturating_add(Weight::from_ref_time(9_799_357).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -752,10 +781,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `832 + r * (45 ±0)` // Estimated: `0` - // Minimum execution time: 278_824 nanoseconds. - Weight::from_ref_time(285_019_861) - // Standard Error: 101_646 - .saturating_add(Weight::from_ref_time(1_757_938).saturating_mul(r.into())) + // Minimum execution time: 280_736 nanoseconds. + Weight::from_ref_time(285_027_920) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 222_526 + .saturating_add(Weight::from_ref_time(1_814_579).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -774,10 +804,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `842` // Estimated: `0` - // Minimum execution time: 286_316 nanoseconds. - Weight::from_ref_time(287_206_936) - // Standard Error: 589 - .saturating_add(Weight::from_ref_time(186_684).saturating_mul(n.into())) + // Minimum execution time: 285_559 nanoseconds. + Weight::from_ref_time(290_522_234) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 2_578 + .saturating_add(Weight::from_ref_time(195_134).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -800,10 +831,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `874 + r * (280 ±0)` // Estimated: `0` - // Minimum execution time: 282_428 nanoseconds. - Weight::from_ref_time(287_101_148) - // Standard Error: 145_605 - .saturating_add(Weight::from_ref_time(58_079_551).saturating_mul(r.into())) + // Minimum execution time: 282_070 nanoseconds. + Weight::from_ref_time(286_466_489) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 238_285 + .saturating_add(Weight::from_ref_time(58_542_610).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -826,10 +858,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `889 + r * (800 ±0)` // Estimated: `0` - // Minimum execution time: 281_516 nanoseconds. - Weight::from_ref_time(292_759_183) - // Standard Error: 152_698 - .saturating_add(Weight::from_ref_time(112_729_555).saturating_mul(r.into())) + // Minimum execution time: 284_147 nanoseconds. + Weight::from_ref_time(295_373_881) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 64_682 + .saturating_add(Weight::from_ref_time(114_198_680).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -848,10 +881,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `842 + r * (800 ±0)` // Estimated: `0` - // Minimum execution time: 280_100 nanoseconds. - Weight::from_ref_time(299_862_082) - // Standard Error: 95_658 - .saturating_add(Weight::from_ref_time(234_211_246).saturating_mul(r.into())) + // Minimum execution time: 282_681 nanoseconds. + Weight::from_ref_time(290_974_649) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 77_850 + .saturating_add(Weight::from_ref_time(233_273_622).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -871,12 +905,13 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1778 + t * (2608 ±0) + n * (8 ±0)` // Estimated: `0` - // Minimum execution time: 1_197_721 nanoseconds. - Weight::from_ref_time(508_692_255) - // Standard Error: 538_596 - .saturating_add(Weight::from_ref_time(174_792_656).saturating_mul(t.into())) - // Standard Error: 147_924 - .saturating_add(Weight::from_ref_time(67_443_118).saturating_mul(n.into())) + // Minimum execution time: 1_226_868 nanoseconds. + Weight::from_ref_time(517_031_747) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 342_786 + .saturating_add(Weight::from_ref_time(183_829_556).saturating_mul(t.into())) + // Standard Error: 94_145 + .saturating_add(Weight::from_ref_time(70_675_099).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(t.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -895,12 +930,36 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_debug_message(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `841 + r * (800 ±0)` + // Measured: `841 + r * (560 ±0)` // Estimated: `0` - // Minimum execution time: 149_687 nanoseconds. - Weight::from_ref_time(153_589_818) - // Standard Error: 13_361 - .saturating_add(Weight::from_ref_time(13_379_131).saturating_mul(r.into())) + // Minimum execution time: 143_026 nanoseconds. + Weight::from_ref_time(147_158_038) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 16_662 + .saturating_add(Weight::from_ref_time(14_990_989).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: MaxEncodedLen) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: MaxEncodedLen) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) + /// The range of component `i` is `[0, 1024]`. + fn seal_debug_message_per_kb(i: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `125792` + // Estimated: `265059` + // Minimum execution time: 412_112 nanoseconds. + Weight::from_ref_time(415_624_011) + .saturating_add(Weight::from_proof_size(265059)) + // Standard Error: 1_190 + .saturating_add(Weight::from_ref_time(797_964).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -911,10 +970,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `883 + r * (23417 ±0)` // Estimated: `0` - // Minimum execution time: 281_920 nanoseconds. - Weight::from_ref_time(242_057_723) - // Standard Error: 464_911 - .saturating_add(Weight::from_ref_time(404_673_309).saturating_mul(r.into())) + // Minimum execution time: 286_118 nanoseconds. + Weight::from_ref_time(195_812_951) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 858_501 + .saturating_add(Weight::from_ref_time(485_357_331).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -927,10 +987,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `12583 + n * (11969 ±0)` // Estimated: `0` - // Minimum execution time: 423_923 nanoseconds. - Weight::from_ref_time(573_806_626) - // Standard Error: 1_371_107 - .saturating_add(Weight::from_ref_time(85_963_445).saturating_mul(n.into())) + // Minimum execution time: 433_181 nanoseconds. + Weight::from_ref_time(618_575_096) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 1_696_126 + .saturating_add(Weight::from_ref_time(96_213_633).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(52_u64)) .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(50_u64)) @@ -943,10 +1004,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `15138 + n * (175775 ±0)` // Estimated: `0` - // Minimum execution time: 424_048 nanoseconds. - Weight::from_ref_time(542_298_050) - // Standard Error: 1_092_010 - .saturating_add(Weight::from_ref_time(60_111_206).saturating_mul(n.into())) + // Minimum execution time: 433_354 nanoseconds. + Weight::from_ref_time(597_131_349) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 1_509_003 + .saturating_add(Weight::from_ref_time(64_872_907).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(51_u64)) .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(49_u64)) @@ -959,10 +1021,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `876 + r * (23098 ±0)` // Estimated: `0` - // Minimum execution time: 285_714 nanoseconds. - Weight::from_ref_time(245_068_941) - // Standard Error: 417_796 - .saturating_add(Weight::from_ref_time(394_288_572).saturating_mul(r.into())) + // Minimum execution time: 286_788 nanoseconds. + Weight::from_ref_time(207_787_332) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 778_284 + .saturating_add(Weight::from_ref_time(474_879_317).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -975,10 +1038,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `14863 + n * (175768 ±0)` // Estimated: `0` - // Minimum execution time: 385_278 nanoseconds. - Weight::from_ref_time(522_656_525) - // Standard Error: 1_259_587 - .saturating_add(Weight::from_ref_time(62_799_142).saturating_mul(n.into())) + // Minimum execution time: 397_414 nanoseconds. + Weight::from_ref_time(573_575_029) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 1_630_691 + .saturating_add(Weight::from_ref_time(67_888_226).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(51_u64)) .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(48_u64)) @@ -991,10 +1055,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `878 + r * (23740 ±0)` // Estimated: `0` - // Minimum execution time: 282_513 nanoseconds. - Weight::from_ref_time(256_242_753) - // Standard Error: 362_571 - .saturating_add(Weight::from_ref_time(317_951_687).saturating_mul(r.into())) + // Minimum execution time: 286_098 nanoseconds. + Weight::from_ref_time(223_637_903) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 669_294 + .saturating_add(Weight::from_ref_time(387_577_627).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1006,10 +1071,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `15469 + n * (175775 ±0)` // Estimated: `0` - // Minimum execution time: 370_576 nanoseconds. - Weight::from_ref_time(487_764_999) - // Standard Error: 1_073_165 - .saturating_add(Weight::from_ref_time(147_588_190).saturating_mul(n.into())) + // Minimum execution time: 373_335 nanoseconds. + Weight::from_ref_time(531_442_564) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 1_474_336 + .saturating_add(Weight::from_ref_time(154_469_598).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(51_u64)) .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1021,10 +1087,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `871 + r * (23100 ±0)` // Estimated: `0` - // Minimum execution time: 285_917 nanoseconds. - Weight::from_ref_time(259_066_807) - // Standard Error: 340_183 - .saturating_add(Weight::from_ref_time(306_291_698).saturating_mul(r.into())) + // Minimum execution time: 284_183 nanoseconds. + Weight::from_ref_time(223_325_689) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 644_587 + .saturating_add(Weight::from_ref_time(373_628_582).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1036,10 +1103,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `14814 + n * (175782 ±0)` // Estimated: `0` - // Minimum execution time: 366_225 nanoseconds. - Weight::from_ref_time(470_470_223) - // Standard Error: 953_976 - .saturating_add(Weight::from_ref_time(57_748_742).saturating_mul(n.into())) + // Minimum execution time: 368_310 nanoseconds. + Weight::from_ref_time(512_814_023) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 1_337_352 + .saturating_add(Weight::from_ref_time(62_871_539).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(51_u64)) .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1051,10 +1119,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `879 + r * (23740 ±0)` // Estimated: `0` - // Minimum execution time: 286_867 nanoseconds. - Weight::from_ref_time(244_403_664) - // Standard Error: 435_431 - .saturating_add(Weight::from_ref_time(409_282_991).saturating_mul(r.into())) + // Minimum execution time: 287_096 nanoseconds. + Weight::from_ref_time(204_878_281) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 833_763 + .saturating_add(Weight::from_ref_time(483_927_706).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1067,10 +1136,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `15470 + n * (175775 ±0)` // Estimated: `0` - // Minimum execution time: 393_392 nanoseconds. - Weight::from_ref_time(540_938_487) - // Standard Error: 1_361_411 - .saturating_add(Weight::from_ref_time(153_456_560).saturating_mul(n.into())) + // Minimum execution time: 399_318 nanoseconds. + Weight::from_ref_time(586_658_466) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 1_734_497 + .saturating_add(Weight::from_ref_time(161_047_970).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(51_u64)) .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(48_u64)) @@ -1091,10 +1161,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1393 + r * (3602 ±0)` // Estimated: `0` - // Minimum execution time: 286_766 nanoseconds. - Weight::from_ref_time(221_458_774) - // Standard Error: 714_182 - .saturating_add(Weight::from_ref_time(1_402_610_222).saturating_mul(r.into())) + // Minimum execution time: 285_460 nanoseconds. + Weight::from_ref_time(227_848_079) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 717_899 + .saturating_add(Weight::from_ref_time(1_434_112_130).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(4_u64)) @@ -1115,10 +1186,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1551 + r * (20511 ±0)` // Estimated: `0` - // Minimum execution time: 287_158 nanoseconds. - Weight::from_ref_time(288_377_000) - // Standard Error: 6_108_706 - .saturating_add(Weight::from_ref_time(21_691_098_517).saturating_mul(r.into())) + // Minimum execution time: 286_947 nanoseconds. + Weight::from_ref_time(288_518_000) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 8_492_544 + .saturating_add(Weight::from_ref_time(21_606_377_662).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().reads((160_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1139,10 +1211,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0 + r * (71670 ±0)` // Estimated: `0` - // Minimum execution time: 287_380 nanoseconds. - Weight::from_ref_time(288_241_000) - // Standard Error: 7_007_658 - .saturating_add(Weight::from_ref_time(21_428_850_764).saturating_mul(r.into())) + // Minimum execution time: 285_196 nanoseconds. + Weight::from_ref_time(287_958_000) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 10_345_109 + .saturating_add(Weight::from_ref_time(21_395_365_662).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((150_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1164,12 +1237,13 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `21611 + t * (15369 ±0)` // Estimated: `0` - // Minimum execution time: 10_644_986 nanoseconds. - Weight::from_ref_time(9_596_635_640) - // Standard Error: 6_393_384 - .saturating_add(Weight::from_ref_time(1_304_764_528).saturating_mul(t.into())) - // Standard Error: 9_586 - .saturating_add(Weight::from_ref_time(9_663_819).saturating_mul(c.into())) + // Minimum execution time: 10_540_614 nanoseconds. + Weight::from_ref_time(9_281_766_912) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 5_409_378 + .saturating_add(Weight::from_ref_time(1_449_975_070).saturating_mul(t.into())) + // Standard Error: 8_111 + .saturating_add(Weight::from_ref_time(10_275_108).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(167_u64)) .saturating_add(T::DbWeight::get().reads((81_u64).saturating_mul(t.into()))) .saturating_add(T::DbWeight::get().writes(163_u64)) @@ -1194,10 +1268,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1613 + r * (25576 ±0)` // Estimated: `0` - // Minimum execution time: 284_948 nanoseconds. - Weight::from_ref_time(289_276_000) - // Standard Error: 18_674_951 - .saturating_add(Weight::from_ref_time(27_090_355_673).saturating_mul(r.into())) + // Minimum execution time: 285_643 nanoseconds. + Weight::from_ref_time(287_472_000) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 25_921_947 + .saturating_add(Weight::from_ref_time(27_745_815_511).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().reads((400_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(5_u64)) @@ -1224,14 +1299,13 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `5666 + t * (17 ±0)` // Estimated: `0` - // Minimum execution time: 127_857_642 nanoseconds. - Weight::from_ref_time(11_399_054_049) - // Standard Error: 95_033_651 - .saturating_add(Weight::from_ref_time(434_246_236).saturating_mul(t.into())) - // Standard Error: 154_973 - .saturating_add(Weight::from_ref_time(121_130_672).saturating_mul(i.into())) - // Standard Error: 154_973 - .saturating_add(Weight::from_ref_time(121_554_853).saturating_mul(s.into())) + // Minimum execution time: 129_710_453 nanoseconds. + Weight::from_ref_time(14_347_603_160) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 194_692 + .saturating_add(Weight::from_ref_time(128_837_066).saturating_mul(i.into())) + // Standard Error: 194_692 + .saturating_add(Weight::from_ref_time(127_568_555).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(249_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(t.into()))) .saturating_add(T::DbWeight::get().writes(247_u64)) @@ -1252,10 +1326,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `839 + r * (642 ±0)` // Estimated: `0` - // Minimum execution time: 280_949 nanoseconds. - Weight::from_ref_time(286_538_475) - // Standard Error: 124_866 - .saturating_add(Weight::from_ref_time(42_531_824).saturating_mul(r.into())) + // Minimum execution time: 282_059 nanoseconds. + Weight::from_ref_time(287_215_177) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 273_484 + .saturating_add(Weight::from_ref_time(44_941_522).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1274,10 +1349,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1641` // Estimated: `0` - // Minimum execution time: 328_414 nanoseconds. - Weight::from_ref_time(329_293_000) - // Standard Error: 50_816 - .saturating_add(Weight::from_ref_time(318_312_506).saturating_mul(n.into())) + // Minimum execution time: 330_822 nanoseconds. + Weight::from_ref_time(333_012_000) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 53_200 + .saturating_add(Weight::from_ref_time(327_144_474).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1296,10 +1372,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `841 + r * (642 ±0)` // Estimated: `0` - // Minimum execution time: 282_208 nanoseconds. - Weight::from_ref_time(286_848_187) - // Standard Error: 106_214 - .saturating_add(Weight::from_ref_time(56_342_512).saturating_mul(r.into())) + // Minimum execution time: 282_859 nanoseconds. + Weight::from_ref_time(286_293_402) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 187_930 + .saturating_add(Weight::from_ref_time(57_415_297).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1318,10 +1395,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1643` // Estimated: `0` - // Minimum execution time: 342_478 nanoseconds. - Weight::from_ref_time(342_947_000) - // Standard Error: 60_809 - .saturating_add(Weight::from_ref_time(255_492_149).saturating_mul(n.into())) + // Minimum execution time: 342_221 nanoseconds. + Weight::from_ref_time(343_250_000) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 67_989 + .saturating_add(Weight::from_ref_time(261_498_077).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1340,10 +1418,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `841 + r * (642 ±0)` // Estimated: `0` - // Minimum execution time: 279_059 nanoseconds. - Weight::from_ref_time(285_413_659) - // Standard Error: 123_081 - .saturating_add(Weight::from_ref_time(33_154_840).saturating_mul(r.into())) + // Minimum execution time: 282_158 nanoseconds. + Weight::from_ref_time(285_783_279) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 200_413 + .saturating_add(Weight::from_ref_time(35_099_520).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1362,10 +1441,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1643` // Estimated: `0` - // Minimum execution time: 317_518 nanoseconds. - Weight::from_ref_time(318_178_000) - // Standard Error: 60_074 - .saturating_add(Weight::from_ref_time(99_403_819).saturating_mul(n.into())) + // Minimum execution time: 317_376 nanoseconds. + Weight::from_ref_time(319_441_000) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 61_325 + .saturating_add(Weight::from_ref_time(101_080_739).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1384,10 +1464,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `841 + r * (679 ±0)` // Estimated: `0` - // Minimum execution time: 280_145 nanoseconds. - Weight::from_ref_time(285_483_032) - // Standard Error: 106_113 - .saturating_add(Weight::from_ref_time(33_475_067).saturating_mul(r.into())) + // Minimum execution time: 280_403 nanoseconds. + Weight::from_ref_time(282_592_267) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 237_832 + .saturating_add(Weight::from_ref_time(37_056_632).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1406,10 +1487,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1643` // Estimated: `0` - // Minimum execution time: 318_141 nanoseconds. - Weight::from_ref_time(318_699_000) - // Standard Error: 55_136 - .saturating_add(Weight::from_ref_time(99_275_434).saturating_mul(n.into())) + // Minimum execution time: 315_482 nanoseconds. + Weight::from_ref_time(316_160_000) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 40_926 + .saturating_add(Weight::from_ref_time(100_317_235).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1428,10 +1510,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `885 + r * (6083 ±0)` // Estimated: `0` - // Minimum execution time: 282_474 nanoseconds. - Weight::from_ref_time(288_078_802) - // Standard Error: 302_968 - .saturating_add(Weight::from_ref_time(2_944_967_597).saturating_mul(r.into())) + // Minimum execution time: 276_155 nanoseconds. + Weight::from_ref_time(278_531_728) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 510_501 + .saturating_add(Weight::from_ref_time(3_056_236_671).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1450,10 +1533,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `854 + r * (3362 ±0)` // Estimated: `0` - // Minimum execution time: 281_514 nanoseconds. - Weight::from_ref_time(287_458_651) - // Standard Error: 146_715 - .saturating_add(Weight::from_ref_time(731_367_948).saturating_mul(r.into())) + // Minimum execution time: 276_204 nanoseconds. + Weight::from_ref_time(278_114_283) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 217_508 + .saturating_add(Weight::from_ref_time(737_577_816).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1474,10 +1558,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0 + r * (79300 ±0)` // Estimated: `0` - // Minimum execution time: 282_591 nanoseconds. - Weight::from_ref_time(286_842_000) - // Standard Error: 2_645_254 - .saturating_add(Weight::from_ref_time(1_394_535_676).saturating_mul(r.into())) + // Minimum execution time: 276_330 nanoseconds. + Weight::from_ref_time(277_573_000) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 3_652_635 + .saturating_add(Weight::from_ref_time(1_547_361_882).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((225_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1498,10 +1583,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `837 + r * (240 ±0)` // Estimated: `0` - // Minimum execution time: 286_631 nanoseconds. - Weight::from_ref_time(288_787_650) - // Standard Error: 29_802 - .saturating_add(Weight::from_ref_time(11_115_811).saturating_mul(r.into())) + // Minimum execution time: 276_228 nanoseconds. + Weight::from_ref_time(281_135_551) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 18_737 + .saturating_add(Weight::from_ref_time(10_998_953).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1520,10 +1606,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `2056 + r * (3153 ±0)` // Estimated: `0` - // Minimum execution time: 287_775 nanoseconds. - Weight::from_ref_time(319_806_123) - // Standard Error: 111_808 - .saturating_add(Weight::from_ref_time(17_641_181).saturating_mul(r.into())) + // Minimum execution time: 278_157 nanoseconds. + Weight::from_ref_time(300_739_078) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 72_695 + .saturating_add(Weight::from_ref_time(18_499_645).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1544,10 +1631,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `840 + r * (240 ±0)` // Estimated: `0` - // Minimum execution time: 285_077 nanoseconds. - Weight::from_ref_time(289_980_475) - // Standard Error: 14_535 - .saturating_add(Weight::from_ref_time(9_295_346).saturating_mul(r.into())) + // Minimum execution time: 275_532 nanoseconds. + Weight::from_ref_time(281_299_677) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 21_719 + .saturating_add(Weight::from_ref_time(9_513_444).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -1556,520 +1644,572 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 777 nanoseconds. - Weight::from_ref_time(1_014_498) - // Standard Error: 154 - .saturating_add(Weight::from_ref_time(405_551).saturating_mul(r.into())) + // Minimum execution time: 856 nanoseconds. + Weight::from_ref_time(1_054_710) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 273 + .saturating_add(Weight::from_ref_time(411_548).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64load(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 862 nanoseconds. - Weight::from_ref_time(1_345_826) - // Standard Error: 457 - .saturating_add(Weight::from_ref_time(1_033_909).saturating_mul(r.into())) + // Minimum execution time: 980 nanoseconds. + Weight::from_ref_time(1_463_182) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 415 + .saturating_add(Weight::from_ref_time(1_063_436).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64store(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 892 nanoseconds. - Weight::from_ref_time(1_233_601) - // Standard Error: 341 - .saturating_add(Weight::from_ref_time(885_275).saturating_mul(r.into())) + // Minimum execution time: 991 nanoseconds. + Weight::from_ref_time(1_521_750) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 8_499 + .saturating_add(Weight::from_ref_time(997_972).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_select(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 771 nanoseconds. - Weight::from_ref_time(1_099_906) - // Standard Error: 261 - .saturating_add(Weight::from_ref_time(1_092_031).saturating_mul(r.into())) + // Minimum execution time: 833 nanoseconds. + Weight::from_ref_time(1_152_048) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 392 + .saturating_add(Weight::from_ref_time(1_147_506).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_if(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 785 nanoseconds. - Weight::from_ref_time(929_328) - // Standard Error: 333 - .saturating_add(Weight::from_ref_time(1_374_749).saturating_mul(r.into())) + // Minimum execution time: 866 nanoseconds. + Weight::from_ref_time(1_154_637) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 5_131 + .saturating_add(Weight::from_ref_time(1_320_580).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_br(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 772 nanoseconds. - Weight::from_ref_time(979_702) - // Standard Error: 351 - .saturating_add(Weight::from_ref_time(621_385).saturating_mul(r.into())) + // Minimum execution time: 849 nanoseconds. + Weight::from_ref_time(1_073_940) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 639 + .saturating_add(Weight::from_ref_time(642_885).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_br_if(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 766 nanoseconds. - Weight::from_ref_time(1_303_783) - // Standard Error: 1_556 - .saturating_add(Weight::from_ref_time(841_842).saturating_mul(r.into())) + // Minimum execution time: 855 nanoseconds. + Weight::from_ref_time(728_631) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 1_730 + .saturating_add(Weight::from_ref_time(979_839).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_br_table(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 792 nanoseconds. - Weight::from_ref_time(1_093_901) - // Standard Error: 1_383 - .saturating_add(Weight::from_ref_time(1_145_435).saturating_mul(r.into())) + // Minimum execution time: 852 nanoseconds. + Weight::from_ref_time(658_935) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 2_373 + .saturating_add(Weight::from_ref_time(1_172_585).saturating_mul(r.into())) } /// The range of component `e` is `[1, 256]`. fn instr_br_table_per_entry(e: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_526 nanoseconds. - Weight::from_ref_time(2_872_561) - // Standard Error: 60 - .saturating_add(Weight::from_ref_time(4_365).saturating_mul(e.into())) + // Minimum execution time: 2_577 nanoseconds. + Weight::from_ref_time(2_872_555) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 70 + .saturating_add(Weight::from_ref_time(4_237).saturating_mul(e.into())) } /// The range of component `r` is `[0, 50]`. fn instr_call(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 834 nanoseconds. - Weight::from_ref_time(1_431_876) - // Standard Error: 1_448 - .saturating_add(Weight::from_ref_time(2_268_715).saturating_mul(r.into())) + // Minimum execution time: 833 nanoseconds. + Weight::from_ref_time(874_000) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 30_863 + .saturating_add(Weight::from_ref_time(2_591_963).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_call_indirect(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 920 nanoseconds. - Weight::from_ref_time(2_167_004) - // Standard Error: 2_060 - .saturating_add(Weight::from_ref_time(2_921_443).saturating_mul(r.into())) + // Minimum execution time: 992 nanoseconds. + Weight::from_ref_time(2_772_709) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 3_822 + .saturating_add(Weight::from_ref_time(3_070_825).saturating_mul(r.into())) } /// The range of component `p` is `[0, 128]`. fn instr_call_indirect_per_param(p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_624 nanoseconds. - Weight::from_ref_time(5_534_325) - // Standard Error: 326 - .saturating_add(Weight::from_ref_time(184_307).saturating_mul(p.into())) + // Minimum execution time: 4_766 nanoseconds. + Weight::from_ref_time(5_559_951) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 315 + .saturating_add(Weight::from_ref_time(227_249).saturating_mul(p.into())) } /// The range of component `l` is `[0, 1024]`. fn instr_call_per_local(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_062 nanoseconds. - Weight::from_ref_time(4_432_879) - // Standard Error: 64 - .saturating_add(Weight::from_ref_time(46_196).saturating_mul(l.into())) + // Minimum execution time: 3_215 nanoseconds. + Weight::from_ref_time(4_697_732) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 99 + .saturating_add(Weight::from_ref_time(46_431).saturating_mul(l.into())) } /// The range of component `r` is `[0, 50]`. fn instr_local_get(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_036 nanoseconds. - Weight::from_ref_time(2_318_877) - // Standard Error: 172 - .saturating_add(Weight::from_ref_time(500_498).saturating_mul(r.into())) + // Minimum execution time: 2_193 nanoseconds. + Weight::from_ref_time(2_472_277) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 374 + .saturating_add(Weight::from_ref_time(459_651).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_local_set(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_027 nanoseconds. - Weight::from_ref_time(2_355_900) - // Standard Error: 220 - .saturating_add(Weight::from_ref_time(461_393).saturating_mul(r.into())) + // Minimum execution time: 2_112 nanoseconds. + Weight::from_ref_time(2_388_132) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 380 + .saturating_add(Weight::from_ref_time(485_216).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_local_tee(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_038 nanoseconds. - Weight::from_ref_time(2_350_330) - // Standard Error: 224 - .saturating_add(Weight::from_ref_time(586_808).saturating_mul(r.into())) + // Minimum execution time: 2_219 nanoseconds. + Weight::from_ref_time(2_419_568) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 402 + .saturating_add(Weight::from_ref_time(658_484).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_global_get(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 897 nanoseconds. - Weight::from_ref_time(1_267_115) - // Standard Error: 189 - .saturating_add(Weight::from_ref_time(884_926).saturating_mul(r.into())) + // Minimum execution time: 959 nanoseconds. + Weight::from_ref_time(1_321_004) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 480 + .saturating_add(Weight::from_ref_time(898_447).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_global_set(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 892 nanoseconds. - Weight::from_ref_time(1_202_122) - // Standard Error: 286 - .saturating_add(Weight::from_ref_time(885_157).saturating_mul(r.into())) + // Minimum execution time: 934 nanoseconds. + Weight::from_ref_time(1_264_350) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 1_031 + .saturating_add(Weight::from_ref_time(922_243).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_memory_current(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 852 nanoseconds. - Weight::from_ref_time(1_132_479) - // Standard Error: 224 - .saturating_add(Weight::from_ref_time(719_603).saturating_mul(r.into())) + // Minimum execution time: 941 nanoseconds. + Weight::from_ref_time(1_229_407) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 507 + .saturating_add(Weight::from_ref_time(824_206).saturating_mul(r.into())) } /// The range of component `r` is `[0, 1]`. fn instr_memory_grow(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 786 nanoseconds. - Weight::from_ref_time(874_044) - // Standard Error: 91_309 - .saturating_add(Weight::from_ref_time(181_849_955).saturating_mul(r.into())) + // Minimum execution time: 870 nanoseconds. + Weight::from_ref_time(946_681) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 7_248 + .saturating_add(Weight::from_ref_time(179_759_218).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64clz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 763 nanoseconds. - Weight::from_ref_time(1_055_236) - // Standard Error: 207 - .saturating_add(Weight::from_ref_time(554_985).saturating_mul(r.into())) + // Minimum execution time: 843 nanoseconds. + Weight::from_ref_time(1_105_279) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 251 + .saturating_add(Weight::from_ref_time(633_218).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ctz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 756 nanoseconds. - Weight::from_ref_time(1_053_050) - // Standard Error: 165 - .saturating_add(Weight::from_ref_time(555_401).saturating_mul(r.into())) + // Minimum execution time: 843 nanoseconds. + Weight::from_ref_time(1_119_719) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 248 + .saturating_add(Weight::from_ref_time(633_064).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64popcnt(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 791 nanoseconds. - Weight::from_ref_time(1_080_240) - // Standard Error: 164 - .saturating_add(Weight::from_ref_time(554_698).saturating_mul(r.into())) + // Minimum execution time: 865 nanoseconds. + Weight::from_ref_time(1_394_651) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 9_898 + .saturating_add(Weight::from_ref_time(630_054).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64eqz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 766 nanoseconds. - Weight::from_ref_time(1_074_739) - // Standard Error: 178 - .saturating_add(Weight::from_ref_time(565_891).saturating_mul(r.into())) + // Minimum execution time: 831 nanoseconds. + Weight::from_ref_time(1_095_288) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 271 + .saturating_add(Weight::from_ref_time(650_578).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendsi32(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 781 nanoseconds. - Weight::from_ref_time(1_077_122) - // Standard Error: 177 - .saturating_add(Weight::from_ref_time(548_846).saturating_mul(r.into())) + // Minimum execution time: 835 nanoseconds. + Weight::from_ref_time(1_128_234) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 239 + .saturating_add(Weight::from_ref_time(615_970).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendui32(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 793 nanoseconds. - Weight::from_ref_time(1_086_278) - // Standard Error: 163 - .saturating_add(Weight::from_ref_time(548_765).saturating_mul(r.into())) + // Minimum execution time: 839 nanoseconds. + Weight::from_ref_time(1_111_296) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 303 + .saturating_add(Weight::from_ref_time(616_831).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i32wrapi64(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 769 nanoseconds. - Weight::from_ref_time(1_096_044) - // Standard Error: 134 - .saturating_add(Weight::from_ref_time(547_353).saturating_mul(r.into())) + // Minimum execution time: 839 nanoseconds. + Weight::from_ref_time(1_082_700) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 236 + .saturating_add(Weight::from_ref_time(617_371).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64eq(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 766 nanoseconds. - Weight::from_ref_time(1_072_610) - // Standard Error: 161 - .saturating_add(Weight::from_ref_time(774_895).saturating_mul(r.into())) + // Minimum execution time: 837 nanoseconds. + Weight::from_ref_time(1_249_666) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 836 + .saturating_add(Weight::from_ref_time(904_457).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ne(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 751 nanoseconds. - Weight::from_ref_time(1_038_676) - // Standard Error: 158 - .saturating_add(Weight::from_ref_time(775_194).saturating_mul(r.into())) + // Minimum execution time: 818 nanoseconds. + Weight::from_ref_time(1_624_057) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 5_906 + .saturating_add(Weight::from_ref_time(893_488).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64lts(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 798 nanoseconds. - Weight::from_ref_time(1_089_712) - // Standard Error: 144 - .saturating_add(Weight::from_ref_time(774_377).saturating_mul(r.into())) + // Minimum execution time: 836 nanoseconds. + Weight::from_ref_time(1_973_044) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 7_556 + .saturating_add(Weight::from_ref_time(885_369).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ltu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 758 nanoseconds. - Weight::from_ref_time(1_078_460) - // Standard Error: 180 - .saturating_add(Weight::from_ref_time(779_861).saturating_mul(r.into())) + // Minimum execution time: 846 nanoseconds. + Weight::from_ref_time(1_088_223) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 531 + .saturating_add(Weight::from_ref_time(909_313).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64gts(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 758 nanoseconds. - Weight::from_ref_time(1_089_007) - // Standard Error: 164 - .saturating_add(Weight::from_ref_time(779_372).saturating_mul(r.into())) + // Minimum execution time: 842 nanoseconds. + Weight::from_ref_time(1_435_966) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 3_824 + .saturating_add(Weight::from_ref_time(898_198).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64gtu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 772 nanoseconds. - Weight::from_ref_time(1_077_512) - // Standard Error: 165 - .saturating_add(Weight::from_ref_time(779_513).saturating_mul(r.into())) + // Minimum execution time: 846 nanoseconds. + Weight::from_ref_time(1_154_015) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 319 + .saturating_add(Weight::from_ref_time(918_083).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64les(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 760 nanoseconds. - Weight::from_ref_time(1_078_546) - // Standard Error: 168 - .saturating_add(Weight::from_ref_time(779_138).saturating_mul(r.into())) + // Minimum execution time: 848 nanoseconds. + Weight::from_ref_time(1_155_323) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 307 + .saturating_add(Weight::from_ref_time(906_516).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64leu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 757 nanoseconds. - Weight::from_ref_time(1_080_251) - // Standard Error: 168 - .saturating_add(Weight::from_ref_time(779_391).saturating_mul(r.into())) + // Minimum execution time: 877 nanoseconds. + Weight::from_ref_time(1_629_210) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 8_175 + .saturating_add(Weight::from_ref_time(906_657).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ges(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 786 nanoseconds. - Weight::from_ref_time(1_072_690) - // Standard Error: 219 - .saturating_add(Weight::from_ref_time(780_381).saturating_mul(r.into())) + // Minimum execution time: 843 nanoseconds. + Weight::from_ref_time(1_126_252) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 251 + .saturating_add(Weight::from_ref_time(907_052).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64geu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 771 nanoseconds. - Weight::from_ref_time(1_063_735) - // Standard Error: 162 - .saturating_add(Weight::from_ref_time(779_906).saturating_mul(r.into())) + // Minimum execution time: 852 nanoseconds. + Weight::from_ref_time(1_497_667) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 7_593 + .saturating_add(Weight::from_ref_time(897_474).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64add(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 785 nanoseconds. - Weight::from_ref_time(1_059_585) - // Standard Error: 155 - .saturating_add(Weight::from_ref_time(756_828).saturating_mul(r.into())) + // Minimum execution time: 856 nanoseconds. + Weight::from_ref_time(1_350_390) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 2_625 + .saturating_add(Weight::from_ref_time(889_609).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64sub(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 800 nanoseconds. - Weight::from_ref_time(1_066_659) - // Standard Error: 154 - .saturating_add(Weight::from_ref_time(754_318).saturating_mul(r.into())) + // Minimum execution time: 841 nanoseconds. + Weight::from_ref_time(2_677_235) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 11_507 + .saturating_add(Weight::from_ref_time(846_704).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64mul(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 769 nanoseconds. - Weight::from_ref_time(1_078_854) - // Standard Error: 172 - .saturating_add(Weight::from_ref_time(754_183).saturating_mul(r.into())) + // Minimum execution time: 846 nanoseconds. + Weight::from_ref_time(1_148_206) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 393 + .saturating_add(Weight::from_ref_time(884_886).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64divs(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 770 nanoseconds. - Weight::from_ref_time(1_057_476) - // Standard Error: 191 - .saturating_add(Weight::from_ref_time(1_443_902).saturating_mul(r.into())) + // Minimum execution time: 865 nanoseconds. + Weight::from_ref_time(2_862_483) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 16_413 + .saturating_add(Weight::from_ref_time(1_481_623).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64divu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 764 nanoseconds. - Weight::from_ref_time(1_063_821) - // Standard Error: 193 - .saturating_add(Weight::from_ref_time(1_324_496).saturating_mul(r.into())) + // Minimum execution time: 1_443 nanoseconds. + Weight::from_ref_time(1_086_902) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 2_245 + .saturating_add(Weight::from_ref_time(1_463_145).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64rems(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 747 nanoseconds. - Weight::from_ref_time(1_093_209) - // Standard Error: 270 - .saturating_add(Weight::from_ref_time(1_447_180).saturating_mul(r.into())) + // Minimum execution time: 878 nanoseconds. + Weight::from_ref_time(1_130_306) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 475 + .saturating_add(Weight::from_ref_time(1_522_011).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64remu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 805 nanoseconds. - Weight::from_ref_time(1_033_953) - // Standard Error: 152 - .saturating_add(Weight::from_ref_time(1_336_911).saturating_mul(r.into())) + // Minimum execution time: 827 nanoseconds. + Weight::from_ref_time(1_197_053) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 474 + .saturating_add(Weight::from_ref_time(1_449_062).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64and(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 766 nanoseconds. - Weight::from_ref_time(1_059_430) - // Standard Error: 160 - .saturating_add(Weight::from_ref_time(757_265).saturating_mul(r.into())) + // Minimum execution time: 847 nanoseconds. + Weight::from_ref_time(1_152_423) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 296 + .saturating_add(Weight::from_ref_time(895_541).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64or(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 760 nanoseconds. - Weight::from_ref_time(1_077_376) - // Standard Error: 160 - .saturating_add(Weight::from_ref_time(755_800).saturating_mul(r.into())) + // Minimum execution time: 876 nanoseconds. + Weight::from_ref_time(1_169_485) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 571 + .saturating_add(Weight::from_ref_time(932_659).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64xor(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 798 nanoseconds. - Weight::from_ref_time(1_070_570) - // Standard Error: 157 - .saturating_add(Weight::from_ref_time(756_839).saturating_mul(r.into())) + // Minimum execution time: 856 nanoseconds. + Weight::from_ref_time(1_155_127) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 256 + .saturating_add(Weight::from_ref_time(895_663).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64shl(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 761 nanoseconds. - Weight::from_ref_time(1_074_645) - // Standard Error: 169 - .saturating_add(Weight::from_ref_time(771_486).saturating_mul(r.into())) + // Minimum execution time: 871 nanoseconds. + Weight::from_ref_time(1_139_722) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 367 + .saturating_add(Weight::from_ref_time(903_115).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64shrs(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 779 nanoseconds. - Weight::from_ref_time(1_107_671) - // Standard Error: 185 - .saturating_add(Weight::from_ref_time(769_168).saturating_mul(r.into())) + // Minimum execution time: 853 nanoseconds. + Weight::from_ref_time(1_155_542) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 541 + .saturating_add(Weight::from_ref_time(901_635).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64shru(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 755 nanoseconds. - Weight::from_ref_time(1_075_769) - // Standard Error: 164 - .saturating_add(Weight::from_ref_time(770_334).saturating_mul(r.into())) + // Minimum execution time: 866 nanoseconds. + Weight::from_ref_time(2_260_588) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 12_944 + .saturating_add(Weight::from_ref_time(877_790).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotl(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 767 nanoseconds. - Weight::from_ref_time(608_749) - // Standard Error: 2_059 - .saturating_add(Weight::from_ref_time(804_228).saturating_mul(r.into())) + // Minimum execution time: 851 nanoseconds. + Weight::from_ref_time(1_627_816) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 4_004 + .saturating_add(Weight::from_ref_time(887_929).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotr(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 779 nanoseconds. - Weight::from_ref_time(1_054_998) - // Standard Error: 191 - .saturating_add(Weight::from_ref_time(770_225).saturating_mul(r.into())) + // Minimum execution time: 874 nanoseconds. + Weight::from_ref_time(2_611_817) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 10_026 + .saturating_add(Weight::from_ref_time(862_138).saturating_mul(r.into())) } } @@ -2081,8 +2221,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `109` // Estimated: `0` - // Minimum execution time: 2_305 nanoseconds. - Weight::from_ref_time(2_560_000) + // Minimum execution time: 2_564 nanoseconds. + Weight::from_ref_time(2_722_000) + .saturating_add(Weight::from_proof_size(0)) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: Skipped Metadata (r:0 w:0) @@ -2092,10 +2233,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `481 + k * (69 ±0)` // Estimated: `0` - // Minimum execution time: 9_311 nanoseconds. - Weight::from_ref_time(5_419_288) - // Standard Error: 562 - .saturating_add(Weight::from_ref_time(911_962).saturating_mul(k.into())) + // Minimum execution time: 10_292 nanoseconds. + Weight::from_ref_time(7_474_496) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 901 + .saturating_add(Weight::from_ref_time(956_864).saturating_mul(k.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(k.into()))) @@ -2107,10 +2249,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `281 + q * (33 ±0)` // Estimated: `0` - // Minimum execution time: 2_288 nanoseconds. - Weight::from_ref_time(9_442_437) - // Standard Error: 2_720 - .saturating_add(Weight::from_ref_time(1_076_950).saturating_mul(q.into())) + // Minimum execution time: 2_620 nanoseconds. + Weight::from_ref_time(10_288_873) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 3_073 + .saturating_add(Weight::from_ref_time(1_148_167).saturating_mul(q.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -2123,10 +2266,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `270 + c * (1 ±0)` // Estimated: `0` - // Minimum execution time: 27_539 nanoseconds. - Weight::from_ref_time(23_554_889) - // Standard Error: 56 - .saturating_add(Weight::from_ref_time(46_766).saturating_mul(c.into())) + // Minimum execution time: 28_004 nanoseconds. + Weight::from_ref_time(26_706_943) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 67 + .saturating_add(Weight::from_ref_time(51_603).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -2145,10 +2289,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `771` // Estimated: `0` - // Minimum execution time: 297_710 nanoseconds. - Weight::from_ref_time(307_327_529) - // Standard Error: 18 - .saturating_add(Weight::from_ref_time(29_849).saturating_mul(c.into())) + // Minimum execution time: 295_799 nanoseconds. + Weight::from_ref_time(308_660_753) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 20 + .saturating_add(Weight::from_ref_time(32_458).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -2175,14 +2320,15 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `257` // Estimated: `0` - // Minimum execution time: 3_586_223 nanoseconds. - Weight::from_ref_time(561_614_281) - // Standard Error: 274 - .saturating_add(Weight::from_ref_time(87_557).saturating_mul(c.into())) + // Minimum execution time: 3_754_887 nanoseconds. + Weight::from_ref_time(657_695_827) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 283 + .saturating_add(Weight::from_ref_time(94_808).saturating_mul(c.into())) // Standard Error: 16 - .saturating_add(Weight::from_ref_time(1_307).saturating_mul(i.into())) + .saturating_add(Weight::from_ref_time(1_357).saturating_mul(i.into())) // Standard Error: 16 - .saturating_add(Weight::from_ref_time(1_721).saturating_mul(s.into())) + .saturating_add(Weight::from_ref_time(1_756).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(9_u64)) } @@ -2206,12 +2352,13 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `533` // Estimated: `0` - // Minimum execution time: 1_885_437 nanoseconds. - Weight::from_ref_time(199_943_867) + // Minimum execution time: 1_961_131 nanoseconds. + Weight::from_ref_time(208_539_564) + .saturating_add(Weight::from_proof_size(0)) // Standard Error: 8 - .saturating_add(Weight::from_ref_time(1_611).saturating_mul(i.into())) + .saturating_add(Weight::from_ref_time(1_688).saturating_mul(i.into())) // Standard Error: 8 - .saturating_add(Weight::from_ref_time(1_737).saturating_mul(s.into())) + .saturating_add(Weight::from_ref_time(1_802).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } @@ -2229,8 +2376,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `823` // Estimated: `0` - // Minimum execution time: 150_604 nanoseconds. - Weight::from_ref_time(151_777_000) + // Minimum execution time: 148_138 nanoseconds. + Weight::from_ref_time(148_862_000) + .saturating_add(Weight::from_proof_size(0)) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -2247,10 +2395,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `109` // Estimated: `0` - // Minimum execution time: 295_505 nanoseconds. - Weight::from_ref_time(305_609_098) - // Standard Error: 58 - .saturating_add(Weight::from_ref_time(88_676).saturating_mul(c.into())) + // Minimum execution time: 293_444 nanoseconds. + Weight::from_ref_time(293_242_988) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 156 + .saturating_add(Weight::from_ref_time(97_476).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -2266,8 +2415,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `287` // Estimated: `0` - // Minimum execution time: 25_949 nanoseconds. - Weight::from_ref_time(26_316_000) + // Minimum execution time: 26_802 nanoseconds. + Weight::from_ref_time(27_121_000) + .saturating_add(Weight::from_proof_size(0)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -2281,8 +2431,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `634` // Estimated: `0` - // Minimum execution time: 29_005 nanoseconds. - Weight::from_ref_time(29_370_000) + // Minimum execution time: 31_079 nanoseconds. + Weight::from_ref_time(31_541_000) + .saturating_add(Weight::from_proof_size(0)) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -2301,10 +2452,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `845 + r * (480 ±0)` // Estimated: `0` - // Minimum execution time: 281_880 nanoseconds. - Weight::from_ref_time(289_637_700) - // Standard Error: 22_662 - .saturating_add(Weight::from_ref_time(16_866_274).saturating_mul(r.into())) + // Minimum execution time: 284_877 nanoseconds. + Weight::from_ref_time(290_043_606) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 22_094 + .saturating_add(Weight::from_ref_time(18_094_219).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -2323,10 +2475,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `882 + r * (19218 ±0)` // Estimated: `0` - // Minimum execution time: 285_590 nanoseconds. - Weight::from_ref_time(231_277_523) - // Standard Error: 425_084 - .saturating_add(Weight::from_ref_time(192_985_377).saturating_mul(r.into())) + // Minimum execution time: 283_956 nanoseconds. + Weight::from_ref_time(129_690_397) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 531_270 + .saturating_add(Weight::from_ref_time(264_082_418).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -2346,10 +2499,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `889 + r * (19539 ±0)` // Estimated: `0` - // Minimum execution time: 282_966 nanoseconds. - Weight::from_ref_time(236_127_328) - // Standard Error: 405_193 - .saturating_add(Weight::from_ref_time(235_541_377).saturating_mul(r.into())) + // Minimum execution time: 287_077 nanoseconds. + Weight::from_ref_time(148_155_166) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 466_496 + .saturating_add(Weight::from_ref_time(306_625_930).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -2369,10 +2523,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `852 + r * (480 ±0)` // Estimated: `0` - // Minimum execution time: 286_021 nanoseconds. - Weight::from_ref_time(290_200_599) - // Standard Error: 19_224 - .saturating_add(Weight::from_ref_time(20_692_099).saturating_mul(r.into())) + // Minimum execution time: 286_459 nanoseconds. + Weight::from_ref_time(292_826_594) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 27_808 + .saturating_add(Weight::from_ref_time(22_401_931).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -2391,10 +2546,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `842 + r * (240 ±0)` // Estimated: `0` - // Minimum execution time: 284_175 nanoseconds. - Weight::from_ref_time(286_665_694) - // Standard Error: 14_104 - .saturating_add(Weight::from_ref_time(11_196_944).saturating_mul(r.into())) + // Minimum execution time: 284_330 nanoseconds. + Weight::from_ref_time(289_069_701) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 13_666 + .saturating_add(Weight::from_ref_time(11_157_859).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -2413,10 +2569,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `846 + r * (480 ±0)` // Estimated: `0` - // Minimum execution time: 285_315 nanoseconds. - Weight::from_ref_time(289_734_189) - // Standard Error: 15_980 - .saturating_add(Weight::from_ref_time(16_940_657).saturating_mul(r.into())) + // Minimum execution time: 284_506 nanoseconds. + Weight::from_ref_time(290_155_141) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 22_944 + .saturating_add(Weight::from_ref_time(17_992_627).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -2435,10 +2592,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `847 + r * (480 ±0)` // Estimated: `0` - // Minimum execution time: 285_708 nanoseconds. - Weight::from_ref_time(289_872_393) - // Standard Error: 16_551 - .saturating_add(Weight::from_ref_time(16_672_944).saturating_mul(r.into())) + // Minimum execution time: 284_177 nanoseconds. + Weight::from_ref_time(289_314_787) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 24_552 + .saturating_add(Weight::from_ref_time(17_754_919).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -2457,10 +2615,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1017 + r * (480 ±0)` // Estimated: `0` - // Minimum execution time: 285_698 nanoseconds. - Weight::from_ref_time(295_636_093) - // Standard Error: 97_582 - .saturating_add(Weight::from_ref_time(92_891_252).saturating_mul(r.into())) + // Minimum execution time: 284_096 nanoseconds. + Weight::from_ref_time(293_655_130) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 56_379 + .saturating_add(Weight::from_ref_time(95_688_575).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -2479,10 +2638,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `856 + r * (480 ±0)` // Estimated: `0` - // Minimum execution time: 282_057 nanoseconds. - Weight::from_ref_time(289_304_621) - // Standard Error: 17_818 - .saturating_add(Weight::from_ref_time(16_725_632).saturating_mul(r.into())) + // Minimum execution time: 285_967 nanoseconds. + Weight::from_ref_time(288_043_137) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 83_838 + .saturating_add(Weight::from_ref_time(18_256_709).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -2501,10 +2661,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `854 + r * (480 ±0)` // Estimated: `0` - // Minimum execution time: 282_478 nanoseconds. - Weight::from_ref_time(289_682_366) - // Standard Error: 20_379 - .saturating_add(Weight::from_ref_time(16_517_079).saturating_mul(r.into())) + // Minimum execution time: 284_060 nanoseconds. + Weight::from_ref_time(290_577_678) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 26_131 + .saturating_add(Weight::from_ref_time(17_560_562).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -2523,10 +2684,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `851 + r * (480 ±0)` // Estimated: `0` - // Minimum execution time: 283_826 nanoseconds. - Weight::from_ref_time(289_935_300) - // Standard Error: 15_180 - .saturating_add(Weight::from_ref_time(16_268_515).saturating_mul(r.into())) + // Minimum execution time: 286_068 nanoseconds. + Weight::from_ref_time(290_026_137) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 34_787 + .saturating_add(Weight::from_ref_time(17_597_404).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -2545,10 +2707,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `842 + r * (480 ±0)` // Estimated: `0` - // Minimum execution time: 285_455 nanoseconds. - Weight::from_ref_time(289_682_526) - // Standard Error: 18_667 - .saturating_add(Weight::from_ref_time(16_502_025).saturating_mul(r.into())) + // Minimum execution time: 285_082 nanoseconds. + Weight::from_ref_time(290_487_103) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 22_743 + .saturating_add(Weight::from_ref_time(17_506_771).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -2569,10 +2732,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `919 + r * (800 ±0)` // Estimated: `0` - // Minimum execution time: 286_106 nanoseconds. - Weight::from_ref_time(294_493_680) - // Standard Error: 76_469 - .saturating_add(Weight::from_ref_time(87_055_837).saturating_mul(r.into())) + // Minimum execution time: 285_309 nanoseconds. + Weight::from_ref_time(296_735_365) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 49_300 + .saturating_add(Weight::from_ref_time(87_678_979).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -2591,10 +2755,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `809 + r * (320 ±0)` // Estimated: `0` - // Minimum execution time: 137_877 nanoseconds. - Weight::from_ref_time(141_863_027) - // Standard Error: 10_200 - .saturating_add(Weight::from_ref_time(7_925_232).saturating_mul(r.into())) + // Minimum execution time: 136_110 nanoseconds. + Weight::from_ref_time(139_800_659) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 9_674 + .saturating_add(Weight::from_ref_time(8_302_834).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -2613,10 +2778,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `844 + r * (480 ±0)` // Estimated: `0` - // Minimum execution time: 282_034 nanoseconds. - Weight::from_ref_time(289_388_799) - // Standard Error: 21_999 - .saturating_add(Weight::from_ref_time(15_039_420).saturating_mul(r.into())) + // Minimum execution time: 285_238 nanoseconds. + Weight::from_ref_time(289_723_839) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 19_531 + .saturating_add(Weight::from_ref_time(15_590_085).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -2635,10 +2801,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1324` // Estimated: `0` - // Minimum execution time: 303_229 nanoseconds. - Weight::from_ref_time(321_863_704) - // Standard Error: 2_754 - .saturating_add(Weight::from_ref_time(9_545_103).saturating_mul(n.into())) + // Minimum execution time: 303_189 nanoseconds. + Weight::from_ref_time(323_374_503) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 2_060 + .saturating_add(Weight::from_ref_time(9_799_357).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -2657,10 +2824,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `832 + r * (45 ±0)` // Estimated: `0` - // Minimum execution time: 278_824 nanoseconds. - Weight::from_ref_time(285_019_861) - // Standard Error: 101_646 - .saturating_add(Weight::from_ref_time(1_757_938).saturating_mul(r.into())) + // Minimum execution time: 280_736 nanoseconds. + Weight::from_ref_time(285_027_920) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 222_526 + .saturating_add(Weight::from_ref_time(1_814_579).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -2679,10 +2847,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `842` // Estimated: `0` - // Minimum execution time: 286_316 nanoseconds. - Weight::from_ref_time(287_206_936) - // Standard Error: 589 - .saturating_add(Weight::from_ref_time(186_684).saturating_mul(n.into())) + // Minimum execution time: 285_559 nanoseconds. + Weight::from_ref_time(290_522_234) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 2_578 + .saturating_add(Weight::from_ref_time(195_134).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -2705,10 +2874,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `874 + r * (280 ±0)` // Estimated: `0` - // Minimum execution time: 282_428 nanoseconds. - Weight::from_ref_time(287_101_148) - // Standard Error: 145_605 - .saturating_add(Weight::from_ref_time(58_079_551).saturating_mul(r.into())) + // Minimum execution time: 282_070 nanoseconds. + Weight::from_ref_time(286_466_489) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 238_285 + .saturating_add(Weight::from_ref_time(58_542_610).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -2731,10 +2901,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `889 + r * (800 ±0)` // Estimated: `0` - // Minimum execution time: 281_516 nanoseconds. - Weight::from_ref_time(292_759_183) - // Standard Error: 152_698 - .saturating_add(Weight::from_ref_time(112_729_555).saturating_mul(r.into())) + // Minimum execution time: 284_147 nanoseconds. + Weight::from_ref_time(295_373_881) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 64_682 + .saturating_add(Weight::from_ref_time(114_198_680).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -2753,10 +2924,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `842 + r * (800 ±0)` // Estimated: `0` - // Minimum execution time: 280_100 nanoseconds. - Weight::from_ref_time(299_862_082) - // Standard Error: 95_658 - .saturating_add(Weight::from_ref_time(234_211_246).saturating_mul(r.into())) + // Minimum execution time: 282_681 nanoseconds. + Weight::from_ref_time(290_974_649) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 77_850 + .saturating_add(Weight::from_ref_time(233_273_622).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -2776,12 +2948,13 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1778 + t * (2608 ±0) + n * (8 ±0)` // Estimated: `0` - // Minimum execution time: 1_197_721 nanoseconds. - Weight::from_ref_time(508_692_255) - // Standard Error: 538_596 - .saturating_add(Weight::from_ref_time(174_792_656).saturating_mul(t.into())) - // Standard Error: 147_924 - .saturating_add(Weight::from_ref_time(67_443_118).saturating_mul(n.into())) + // Minimum execution time: 1_226_868 nanoseconds. + Weight::from_ref_time(517_031_747) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 342_786 + .saturating_add(Weight::from_ref_time(183_829_556).saturating_mul(t.into())) + // Standard Error: 94_145 + .saturating_add(Weight::from_ref_time(70_675_099).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(t.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -2800,12 +2973,36 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_debug_message(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `841 + r * (800 ±0)` + // Measured: `841 + r * (560 ±0)` // Estimated: `0` - // Minimum execution time: 149_687 nanoseconds. - Weight::from_ref_time(153_589_818) - // Standard Error: 13_361 - .saturating_add(Weight::from_ref_time(13_379_131).saturating_mul(r.into())) + // Minimum execution time: 143_026 nanoseconds. + Weight::from_ref_time(147_158_038) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 16_662 + .saturating_add(Weight::from_ref_time(14_990_989).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: MaxEncodedLen) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: MaxEncodedLen) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) + /// The range of component `i` is `[0, 1024]`. + fn seal_debug_message_per_kb(i: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `125792` + // Estimated: `265059` + // Minimum execution time: 412_112 nanoseconds. + Weight::from_ref_time(415_624_011) + .saturating_add(Weight::from_proof_size(265059)) + // Standard Error: 1_190 + .saturating_add(Weight::from_ref_time(797_964).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -2816,10 +3013,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `883 + r * (23417 ±0)` // Estimated: `0` - // Minimum execution time: 281_920 nanoseconds. - Weight::from_ref_time(242_057_723) - // Standard Error: 464_911 - .saturating_add(Weight::from_ref_time(404_673_309).saturating_mul(r.into())) + // Minimum execution time: 286_118 nanoseconds. + Weight::from_ref_time(195_812_951) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 858_501 + .saturating_add(Weight::from_ref_time(485_357_331).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -2832,10 +3030,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `12583 + n * (11969 ±0)` // Estimated: `0` - // Minimum execution time: 423_923 nanoseconds. - Weight::from_ref_time(573_806_626) - // Standard Error: 1_371_107 - .saturating_add(Weight::from_ref_time(85_963_445).saturating_mul(n.into())) + // Minimum execution time: 433_181 nanoseconds. + Weight::from_ref_time(618_575_096) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 1_696_126 + .saturating_add(Weight::from_ref_time(96_213_633).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(52_u64)) .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(50_u64)) @@ -2848,10 +3047,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `15138 + n * (175775 ±0)` // Estimated: `0` - // Minimum execution time: 424_048 nanoseconds. - Weight::from_ref_time(542_298_050) - // Standard Error: 1_092_010 - .saturating_add(Weight::from_ref_time(60_111_206).saturating_mul(n.into())) + // Minimum execution time: 433_354 nanoseconds. + Weight::from_ref_time(597_131_349) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 1_509_003 + .saturating_add(Weight::from_ref_time(64_872_907).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(51_u64)) .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(49_u64)) @@ -2864,10 +3064,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `876 + r * (23098 ±0)` // Estimated: `0` - // Minimum execution time: 285_714 nanoseconds. - Weight::from_ref_time(245_068_941) - // Standard Error: 417_796 - .saturating_add(Weight::from_ref_time(394_288_572).saturating_mul(r.into())) + // Minimum execution time: 286_788 nanoseconds. + Weight::from_ref_time(207_787_332) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 778_284 + .saturating_add(Weight::from_ref_time(474_879_317).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -2880,10 +3081,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `14863 + n * (175768 ±0)` // Estimated: `0` - // Minimum execution time: 385_278 nanoseconds. - Weight::from_ref_time(522_656_525) - // Standard Error: 1_259_587 - .saturating_add(Weight::from_ref_time(62_799_142).saturating_mul(n.into())) + // Minimum execution time: 397_414 nanoseconds. + Weight::from_ref_time(573_575_029) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 1_630_691 + .saturating_add(Weight::from_ref_time(67_888_226).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(51_u64)) .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(48_u64)) @@ -2896,10 +3098,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `878 + r * (23740 ±0)` // Estimated: `0` - // Minimum execution time: 282_513 nanoseconds. - Weight::from_ref_time(256_242_753) - // Standard Error: 362_571 - .saturating_add(Weight::from_ref_time(317_951_687).saturating_mul(r.into())) + // Minimum execution time: 286_098 nanoseconds. + Weight::from_ref_time(223_637_903) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 669_294 + .saturating_add(Weight::from_ref_time(387_577_627).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -2911,10 +3114,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `15469 + n * (175775 ±0)` // Estimated: `0` - // Minimum execution time: 370_576 nanoseconds. - Weight::from_ref_time(487_764_999) - // Standard Error: 1_073_165 - .saturating_add(Weight::from_ref_time(147_588_190).saturating_mul(n.into())) + // Minimum execution time: 373_335 nanoseconds. + Weight::from_ref_time(531_442_564) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 1_474_336 + .saturating_add(Weight::from_ref_time(154_469_598).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(51_u64)) .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -2926,10 +3130,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `871 + r * (23100 ±0)` // Estimated: `0` - // Minimum execution time: 285_917 nanoseconds. - Weight::from_ref_time(259_066_807) - // Standard Error: 340_183 - .saturating_add(Weight::from_ref_time(306_291_698).saturating_mul(r.into())) + // Minimum execution time: 284_183 nanoseconds. + Weight::from_ref_time(223_325_689) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 644_587 + .saturating_add(Weight::from_ref_time(373_628_582).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -2941,10 +3146,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `14814 + n * (175782 ±0)` // Estimated: `0` - // Minimum execution time: 366_225 nanoseconds. - Weight::from_ref_time(470_470_223) - // Standard Error: 953_976 - .saturating_add(Weight::from_ref_time(57_748_742).saturating_mul(n.into())) + // Minimum execution time: 368_310 nanoseconds. + Weight::from_ref_time(512_814_023) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 1_337_352 + .saturating_add(Weight::from_ref_time(62_871_539).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(51_u64)) .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -2956,10 +3162,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `879 + r * (23740 ±0)` // Estimated: `0` - // Minimum execution time: 286_867 nanoseconds. - Weight::from_ref_time(244_403_664) - // Standard Error: 435_431 - .saturating_add(Weight::from_ref_time(409_282_991).saturating_mul(r.into())) + // Minimum execution time: 287_096 nanoseconds. + Weight::from_ref_time(204_878_281) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 833_763 + .saturating_add(Weight::from_ref_time(483_927_706).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -2972,10 +3179,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `15470 + n * (175775 ±0)` // Estimated: `0` - // Minimum execution time: 393_392 nanoseconds. - Weight::from_ref_time(540_938_487) - // Standard Error: 1_361_411 - .saturating_add(Weight::from_ref_time(153_456_560).saturating_mul(n.into())) + // Minimum execution time: 399_318 nanoseconds. + Weight::from_ref_time(586_658_466) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 1_734_497 + .saturating_add(Weight::from_ref_time(161_047_970).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(51_u64)) .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(48_u64)) @@ -2996,10 +3204,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1393 + r * (3602 ±0)` // Estimated: `0` - // Minimum execution time: 286_766 nanoseconds. - Weight::from_ref_time(221_458_774) - // Standard Error: 714_182 - .saturating_add(Weight::from_ref_time(1_402_610_222).saturating_mul(r.into())) + // Minimum execution time: 285_460 nanoseconds. + Weight::from_ref_time(227_848_079) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 717_899 + .saturating_add(Weight::from_ref_time(1_434_112_130).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(4_u64)) @@ -3020,10 +3229,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1551 + r * (20511 ±0)` // Estimated: `0` - // Minimum execution time: 287_158 nanoseconds. - Weight::from_ref_time(288_377_000) - // Standard Error: 6_108_706 - .saturating_add(Weight::from_ref_time(21_691_098_517).saturating_mul(r.into())) + // Minimum execution time: 286_947 nanoseconds. + Weight::from_ref_time(288_518_000) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 8_492_544 + .saturating_add(Weight::from_ref_time(21_606_377_662).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().reads((160_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3044,10 +3254,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0 + r * (71670 ±0)` // Estimated: `0` - // Minimum execution time: 287_380 nanoseconds. - Weight::from_ref_time(288_241_000) - // Standard Error: 7_007_658 - .saturating_add(Weight::from_ref_time(21_428_850_764).saturating_mul(r.into())) + // Minimum execution time: 285_196 nanoseconds. + Weight::from_ref_time(287_958_000) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 10_345_109 + .saturating_add(Weight::from_ref_time(21_395_365_662).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((150_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3069,12 +3280,13 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `21611 + t * (15369 ±0)` // Estimated: `0` - // Minimum execution time: 10_644_986 nanoseconds. - Weight::from_ref_time(9_596_635_640) - // Standard Error: 6_393_384 - .saturating_add(Weight::from_ref_time(1_304_764_528).saturating_mul(t.into())) - // Standard Error: 9_586 - .saturating_add(Weight::from_ref_time(9_663_819).saturating_mul(c.into())) + // Minimum execution time: 10_540_614 nanoseconds. + Weight::from_ref_time(9_281_766_912) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 5_409_378 + .saturating_add(Weight::from_ref_time(1_449_975_070).saturating_mul(t.into())) + // Standard Error: 8_111 + .saturating_add(Weight::from_ref_time(10_275_108).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(167_u64)) .saturating_add(RocksDbWeight::get().reads((81_u64).saturating_mul(t.into()))) .saturating_add(RocksDbWeight::get().writes(163_u64)) @@ -3099,10 +3311,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1613 + r * (25576 ±0)` // Estimated: `0` - // Minimum execution time: 284_948 nanoseconds. - Weight::from_ref_time(289_276_000) - // Standard Error: 18_674_951 - .saturating_add(Weight::from_ref_time(27_090_355_673).saturating_mul(r.into())) + // Minimum execution time: 285_643 nanoseconds. + Weight::from_ref_time(287_472_000) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 25_921_947 + .saturating_add(Weight::from_ref_time(27_745_815_511).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().reads((400_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(5_u64)) @@ -3129,14 +3342,13 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `5666 + t * (17 ±0)` // Estimated: `0` - // Minimum execution time: 127_857_642 nanoseconds. - Weight::from_ref_time(11_399_054_049) - // Standard Error: 95_033_651 - .saturating_add(Weight::from_ref_time(434_246_236).saturating_mul(t.into())) - // Standard Error: 154_973 - .saturating_add(Weight::from_ref_time(121_130_672).saturating_mul(i.into())) - // Standard Error: 154_973 - .saturating_add(Weight::from_ref_time(121_554_853).saturating_mul(s.into())) + // Minimum execution time: 129_710_453 nanoseconds. + Weight::from_ref_time(14_347_603_160) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 194_692 + .saturating_add(Weight::from_ref_time(128_837_066).saturating_mul(i.into())) + // Standard Error: 194_692 + .saturating_add(Weight::from_ref_time(127_568_555).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(249_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(t.into()))) .saturating_add(RocksDbWeight::get().writes(247_u64)) @@ -3157,10 +3369,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `839 + r * (642 ±0)` // Estimated: `0` - // Minimum execution time: 280_949 nanoseconds. - Weight::from_ref_time(286_538_475) - // Standard Error: 124_866 - .saturating_add(Weight::from_ref_time(42_531_824).saturating_mul(r.into())) + // Minimum execution time: 282_059 nanoseconds. + Weight::from_ref_time(287_215_177) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 273_484 + .saturating_add(Weight::from_ref_time(44_941_522).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3179,10 +3392,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1641` // Estimated: `0` - // Minimum execution time: 328_414 nanoseconds. - Weight::from_ref_time(329_293_000) - // Standard Error: 50_816 - .saturating_add(Weight::from_ref_time(318_312_506).saturating_mul(n.into())) + // Minimum execution time: 330_822 nanoseconds. + Weight::from_ref_time(333_012_000) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 53_200 + .saturating_add(Weight::from_ref_time(327_144_474).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3201,10 +3415,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `841 + r * (642 ±0)` // Estimated: `0` - // Minimum execution time: 282_208 nanoseconds. - Weight::from_ref_time(286_848_187) - // Standard Error: 106_214 - .saturating_add(Weight::from_ref_time(56_342_512).saturating_mul(r.into())) + // Minimum execution time: 282_859 nanoseconds. + Weight::from_ref_time(286_293_402) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 187_930 + .saturating_add(Weight::from_ref_time(57_415_297).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3223,10 +3438,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1643` // Estimated: `0` - // Minimum execution time: 342_478 nanoseconds. - Weight::from_ref_time(342_947_000) - // Standard Error: 60_809 - .saturating_add(Weight::from_ref_time(255_492_149).saturating_mul(n.into())) + // Minimum execution time: 342_221 nanoseconds. + Weight::from_ref_time(343_250_000) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 67_989 + .saturating_add(Weight::from_ref_time(261_498_077).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3245,10 +3461,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `841 + r * (642 ±0)` // Estimated: `0` - // Minimum execution time: 279_059 nanoseconds. - Weight::from_ref_time(285_413_659) - // Standard Error: 123_081 - .saturating_add(Weight::from_ref_time(33_154_840).saturating_mul(r.into())) + // Minimum execution time: 282_158 nanoseconds. + Weight::from_ref_time(285_783_279) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 200_413 + .saturating_add(Weight::from_ref_time(35_099_520).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3267,10 +3484,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1643` // Estimated: `0` - // Minimum execution time: 317_518 nanoseconds. - Weight::from_ref_time(318_178_000) - // Standard Error: 60_074 - .saturating_add(Weight::from_ref_time(99_403_819).saturating_mul(n.into())) + // Minimum execution time: 317_376 nanoseconds. + Weight::from_ref_time(319_441_000) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 61_325 + .saturating_add(Weight::from_ref_time(101_080_739).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3289,10 +3507,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `841 + r * (679 ±0)` // Estimated: `0` - // Minimum execution time: 280_145 nanoseconds. - Weight::from_ref_time(285_483_032) - // Standard Error: 106_113 - .saturating_add(Weight::from_ref_time(33_475_067).saturating_mul(r.into())) + // Minimum execution time: 280_403 nanoseconds. + Weight::from_ref_time(282_592_267) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 237_832 + .saturating_add(Weight::from_ref_time(37_056_632).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3311,10 +3530,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1643` // Estimated: `0` - // Minimum execution time: 318_141 nanoseconds. - Weight::from_ref_time(318_699_000) - // Standard Error: 55_136 - .saturating_add(Weight::from_ref_time(99_275_434).saturating_mul(n.into())) + // Minimum execution time: 315_482 nanoseconds. + Weight::from_ref_time(316_160_000) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 40_926 + .saturating_add(Weight::from_ref_time(100_317_235).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3333,10 +3553,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `885 + r * (6083 ±0)` // Estimated: `0` - // Minimum execution time: 282_474 nanoseconds. - Weight::from_ref_time(288_078_802) - // Standard Error: 302_968 - .saturating_add(Weight::from_ref_time(2_944_967_597).saturating_mul(r.into())) + // Minimum execution time: 276_155 nanoseconds. + Weight::from_ref_time(278_531_728) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 510_501 + .saturating_add(Weight::from_ref_time(3_056_236_671).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3355,10 +3576,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `854 + r * (3362 ±0)` // Estimated: `0` - // Minimum execution time: 281_514 nanoseconds. - Weight::from_ref_time(287_458_651) - // Standard Error: 146_715 - .saturating_add(Weight::from_ref_time(731_367_948).saturating_mul(r.into())) + // Minimum execution time: 276_204 nanoseconds. + Weight::from_ref_time(278_114_283) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 217_508 + .saturating_add(Weight::from_ref_time(737_577_816).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3379,10 +3601,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0 + r * (79300 ±0)` // Estimated: `0` - // Minimum execution time: 282_591 nanoseconds. - Weight::from_ref_time(286_842_000) - // Standard Error: 2_645_254 - .saturating_add(Weight::from_ref_time(1_394_535_676).saturating_mul(r.into())) + // Minimum execution time: 276_330 nanoseconds. + Weight::from_ref_time(277_573_000) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 3_652_635 + .saturating_add(Weight::from_ref_time(1_547_361_882).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((225_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3403,10 +3626,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `837 + r * (240 ±0)` // Estimated: `0` - // Minimum execution time: 286_631 nanoseconds. - Weight::from_ref_time(288_787_650) - // Standard Error: 29_802 - .saturating_add(Weight::from_ref_time(11_115_811).saturating_mul(r.into())) + // Minimum execution time: 276_228 nanoseconds. + Weight::from_ref_time(281_135_551) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 18_737 + .saturating_add(Weight::from_ref_time(10_998_953).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3425,10 +3649,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `2056 + r * (3153 ±0)` // Estimated: `0` - // Minimum execution time: 287_775 nanoseconds. - Weight::from_ref_time(319_806_123) - // Standard Error: 111_808 - .saturating_add(Weight::from_ref_time(17_641_181).saturating_mul(r.into())) + // Minimum execution time: 278_157 nanoseconds. + Weight::from_ref_time(300_739_078) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 72_695 + .saturating_add(Weight::from_ref_time(18_499_645).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3449,10 +3674,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `840 + r * (240 ±0)` // Estimated: `0` - // Minimum execution time: 285_077 nanoseconds. - Weight::from_ref_time(289_980_475) - // Standard Error: 14_535 - .saturating_add(Weight::from_ref_time(9_295_346).saturating_mul(r.into())) + // Minimum execution time: 275_532 nanoseconds. + Weight::from_ref_time(281_299_677) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 21_719 + .saturating_add(Weight::from_ref_time(9_513_444).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -3461,519 +3687,571 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 777 nanoseconds. - Weight::from_ref_time(1_014_498) - // Standard Error: 154 - .saturating_add(Weight::from_ref_time(405_551).saturating_mul(r.into())) + // Minimum execution time: 856 nanoseconds. + Weight::from_ref_time(1_054_710) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 273 + .saturating_add(Weight::from_ref_time(411_548).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64load(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 862 nanoseconds. - Weight::from_ref_time(1_345_826) - // Standard Error: 457 - .saturating_add(Weight::from_ref_time(1_033_909).saturating_mul(r.into())) + // Minimum execution time: 980 nanoseconds. + Weight::from_ref_time(1_463_182) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 415 + .saturating_add(Weight::from_ref_time(1_063_436).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64store(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 892 nanoseconds. - Weight::from_ref_time(1_233_601) - // Standard Error: 341 - .saturating_add(Weight::from_ref_time(885_275).saturating_mul(r.into())) + // Minimum execution time: 991 nanoseconds. + Weight::from_ref_time(1_521_750) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 8_499 + .saturating_add(Weight::from_ref_time(997_972).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_select(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 771 nanoseconds. - Weight::from_ref_time(1_099_906) - // Standard Error: 261 - .saturating_add(Weight::from_ref_time(1_092_031).saturating_mul(r.into())) + // Minimum execution time: 833 nanoseconds. + Weight::from_ref_time(1_152_048) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 392 + .saturating_add(Weight::from_ref_time(1_147_506).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_if(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 785 nanoseconds. - Weight::from_ref_time(929_328) - // Standard Error: 333 - .saturating_add(Weight::from_ref_time(1_374_749).saturating_mul(r.into())) + // Minimum execution time: 866 nanoseconds. + Weight::from_ref_time(1_154_637) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 5_131 + .saturating_add(Weight::from_ref_time(1_320_580).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_br(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 772 nanoseconds. - Weight::from_ref_time(979_702) - // Standard Error: 351 - .saturating_add(Weight::from_ref_time(621_385).saturating_mul(r.into())) + // Minimum execution time: 849 nanoseconds. + Weight::from_ref_time(1_073_940) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 639 + .saturating_add(Weight::from_ref_time(642_885).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_br_if(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 766 nanoseconds. - Weight::from_ref_time(1_303_783) - // Standard Error: 1_556 - .saturating_add(Weight::from_ref_time(841_842).saturating_mul(r.into())) + // Minimum execution time: 855 nanoseconds. + Weight::from_ref_time(728_631) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 1_730 + .saturating_add(Weight::from_ref_time(979_839).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_br_table(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 792 nanoseconds. - Weight::from_ref_time(1_093_901) - // Standard Error: 1_383 - .saturating_add(Weight::from_ref_time(1_145_435).saturating_mul(r.into())) + // Minimum execution time: 852 nanoseconds. + Weight::from_ref_time(658_935) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 2_373 + .saturating_add(Weight::from_ref_time(1_172_585).saturating_mul(r.into())) } /// The range of component `e` is `[1, 256]`. fn instr_br_table_per_entry(e: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_526 nanoseconds. - Weight::from_ref_time(2_872_561) - // Standard Error: 60 - .saturating_add(Weight::from_ref_time(4_365).saturating_mul(e.into())) + // Minimum execution time: 2_577 nanoseconds. + Weight::from_ref_time(2_872_555) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 70 + .saturating_add(Weight::from_ref_time(4_237).saturating_mul(e.into())) } /// The range of component `r` is `[0, 50]`. fn instr_call(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 834 nanoseconds. - Weight::from_ref_time(1_431_876) - // Standard Error: 1_448 - .saturating_add(Weight::from_ref_time(2_268_715).saturating_mul(r.into())) + // Minimum execution time: 833 nanoseconds. + Weight::from_ref_time(874_000) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 30_863 + .saturating_add(Weight::from_ref_time(2_591_963).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_call_indirect(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 920 nanoseconds. - Weight::from_ref_time(2_167_004) - // Standard Error: 2_060 - .saturating_add(Weight::from_ref_time(2_921_443).saturating_mul(r.into())) + // Minimum execution time: 992 nanoseconds. + Weight::from_ref_time(2_772_709) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 3_822 + .saturating_add(Weight::from_ref_time(3_070_825).saturating_mul(r.into())) } /// The range of component `p` is `[0, 128]`. fn instr_call_indirect_per_param(p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_624 nanoseconds. - Weight::from_ref_time(5_534_325) - // Standard Error: 326 - .saturating_add(Weight::from_ref_time(184_307).saturating_mul(p.into())) + // Minimum execution time: 4_766 nanoseconds. + Weight::from_ref_time(5_559_951) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 315 + .saturating_add(Weight::from_ref_time(227_249).saturating_mul(p.into())) } /// The range of component `l` is `[0, 1024]`. fn instr_call_per_local(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_062 nanoseconds. - Weight::from_ref_time(4_432_879) - // Standard Error: 64 - .saturating_add(Weight::from_ref_time(46_196).saturating_mul(l.into())) + // Minimum execution time: 3_215 nanoseconds. + Weight::from_ref_time(4_697_732) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 99 + .saturating_add(Weight::from_ref_time(46_431).saturating_mul(l.into())) } /// The range of component `r` is `[0, 50]`. fn instr_local_get(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_036 nanoseconds. - Weight::from_ref_time(2_318_877) - // Standard Error: 172 - .saturating_add(Weight::from_ref_time(500_498).saturating_mul(r.into())) + // Minimum execution time: 2_193 nanoseconds. + Weight::from_ref_time(2_472_277) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 374 + .saturating_add(Weight::from_ref_time(459_651).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_local_set(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_027 nanoseconds. - Weight::from_ref_time(2_355_900) - // Standard Error: 220 - .saturating_add(Weight::from_ref_time(461_393).saturating_mul(r.into())) + // Minimum execution time: 2_112 nanoseconds. + Weight::from_ref_time(2_388_132) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 380 + .saturating_add(Weight::from_ref_time(485_216).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_local_tee(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_038 nanoseconds. - Weight::from_ref_time(2_350_330) - // Standard Error: 224 - .saturating_add(Weight::from_ref_time(586_808).saturating_mul(r.into())) + // Minimum execution time: 2_219 nanoseconds. + Weight::from_ref_time(2_419_568) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 402 + .saturating_add(Weight::from_ref_time(658_484).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_global_get(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 897 nanoseconds. - Weight::from_ref_time(1_267_115) - // Standard Error: 189 - .saturating_add(Weight::from_ref_time(884_926).saturating_mul(r.into())) + // Minimum execution time: 959 nanoseconds. + Weight::from_ref_time(1_321_004) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 480 + .saturating_add(Weight::from_ref_time(898_447).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_global_set(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 892 nanoseconds. - Weight::from_ref_time(1_202_122) - // Standard Error: 286 - .saturating_add(Weight::from_ref_time(885_157).saturating_mul(r.into())) + // Minimum execution time: 934 nanoseconds. + Weight::from_ref_time(1_264_350) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 1_031 + .saturating_add(Weight::from_ref_time(922_243).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_memory_current(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 852 nanoseconds. - Weight::from_ref_time(1_132_479) - // Standard Error: 224 - .saturating_add(Weight::from_ref_time(719_603).saturating_mul(r.into())) + // Minimum execution time: 941 nanoseconds. + Weight::from_ref_time(1_229_407) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 507 + .saturating_add(Weight::from_ref_time(824_206).saturating_mul(r.into())) } /// The range of component `r` is `[0, 1]`. fn instr_memory_grow(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 786 nanoseconds. - Weight::from_ref_time(874_044) - // Standard Error: 91_309 - .saturating_add(Weight::from_ref_time(181_849_955).saturating_mul(r.into())) + // Minimum execution time: 870 nanoseconds. + Weight::from_ref_time(946_681) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 7_248 + .saturating_add(Weight::from_ref_time(179_759_218).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64clz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 763 nanoseconds. - Weight::from_ref_time(1_055_236) - // Standard Error: 207 - .saturating_add(Weight::from_ref_time(554_985).saturating_mul(r.into())) + // Minimum execution time: 843 nanoseconds. + Weight::from_ref_time(1_105_279) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 251 + .saturating_add(Weight::from_ref_time(633_218).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ctz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 756 nanoseconds. - Weight::from_ref_time(1_053_050) - // Standard Error: 165 - .saturating_add(Weight::from_ref_time(555_401).saturating_mul(r.into())) + // Minimum execution time: 843 nanoseconds. + Weight::from_ref_time(1_119_719) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 248 + .saturating_add(Weight::from_ref_time(633_064).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64popcnt(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 791 nanoseconds. - Weight::from_ref_time(1_080_240) - // Standard Error: 164 - .saturating_add(Weight::from_ref_time(554_698).saturating_mul(r.into())) + // Minimum execution time: 865 nanoseconds. + Weight::from_ref_time(1_394_651) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 9_898 + .saturating_add(Weight::from_ref_time(630_054).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64eqz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 766 nanoseconds. - Weight::from_ref_time(1_074_739) - // Standard Error: 178 - .saturating_add(Weight::from_ref_time(565_891).saturating_mul(r.into())) + // Minimum execution time: 831 nanoseconds. + Weight::from_ref_time(1_095_288) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 271 + .saturating_add(Weight::from_ref_time(650_578).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendsi32(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 781 nanoseconds. - Weight::from_ref_time(1_077_122) - // Standard Error: 177 - .saturating_add(Weight::from_ref_time(548_846).saturating_mul(r.into())) + // Minimum execution time: 835 nanoseconds. + Weight::from_ref_time(1_128_234) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 239 + .saturating_add(Weight::from_ref_time(615_970).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendui32(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 793 nanoseconds. - Weight::from_ref_time(1_086_278) - // Standard Error: 163 - .saturating_add(Weight::from_ref_time(548_765).saturating_mul(r.into())) + // Minimum execution time: 839 nanoseconds. + Weight::from_ref_time(1_111_296) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 303 + .saturating_add(Weight::from_ref_time(616_831).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i32wrapi64(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 769 nanoseconds. - Weight::from_ref_time(1_096_044) - // Standard Error: 134 - .saturating_add(Weight::from_ref_time(547_353).saturating_mul(r.into())) + // Minimum execution time: 839 nanoseconds. + Weight::from_ref_time(1_082_700) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 236 + .saturating_add(Weight::from_ref_time(617_371).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64eq(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 766 nanoseconds. - Weight::from_ref_time(1_072_610) - // Standard Error: 161 - .saturating_add(Weight::from_ref_time(774_895).saturating_mul(r.into())) + // Minimum execution time: 837 nanoseconds. + Weight::from_ref_time(1_249_666) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 836 + .saturating_add(Weight::from_ref_time(904_457).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ne(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 751 nanoseconds. - Weight::from_ref_time(1_038_676) - // Standard Error: 158 - .saturating_add(Weight::from_ref_time(775_194).saturating_mul(r.into())) + // Minimum execution time: 818 nanoseconds. + Weight::from_ref_time(1_624_057) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 5_906 + .saturating_add(Weight::from_ref_time(893_488).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64lts(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 798 nanoseconds. - Weight::from_ref_time(1_089_712) - // Standard Error: 144 - .saturating_add(Weight::from_ref_time(774_377).saturating_mul(r.into())) + // Minimum execution time: 836 nanoseconds. + Weight::from_ref_time(1_973_044) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 7_556 + .saturating_add(Weight::from_ref_time(885_369).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ltu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 758 nanoseconds. - Weight::from_ref_time(1_078_460) - // Standard Error: 180 - .saturating_add(Weight::from_ref_time(779_861).saturating_mul(r.into())) + // Minimum execution time: 846 nanoseconds. + Weight::from_ref_time(1_088_223) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 531 + .saturating_add(Weight::from_ref_time(909_313).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64gts(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 758 nanoseconds. - Weight::from_ref_time(1_089_007) - // Standard Error: 164 - .saturating_add(Weight::from_ref_time(779_372).saturating_mul(r.into())) + // Minimum execution time: 842 nanoseconds. + Weight::from_ref_time(1_435_966) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 3_824 + .saturating_add(Weight::from_ref_time(898_198).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64gtu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 772 nanoseconds. - Weight::from_ref_time(1_077_512) - // Standard Error: 165 - .saturating_add(Weight::from_ref_time(779_513).saturating_mul(r.into())) + // Minimum execution time: 846 nanoseconds. + Weight::from_ref_time(1_154_015) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 319 + .saturating_add(Weight::from_ref_time(918_083).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64les(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 760 nanoseconds. - Weight::from_ref_time(1_078_546) - // Standard Error: 168 - .saturating_add(Weight::from_ref_time(779_138).saturating_mul(r.into())) + // Minimum execution time: 848 nanoseconds. + Weight::from_ref_time(1_155_323) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 307 + .saturating_add(Weight::from_ref_time(906_516).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64leu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 757 nanoseconds. - Weight::from_ref_time(1_080_251) - // Standard Error: 168 - .saturating_add(Weight::from_ref_time(779_391).saturating_mul(r.into())) + // Minimum execution time: 877 nanoseconds. + Weight::from_ref_time(1_629_210) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 8_175 + .saturating_add(Weight::from_ref_time(906_657).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ges(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 786 nanoseconds. - Weight::from_ref_time(1_072_690) - // Standard Error: 219 - .saturating_add(Weight::from_ref_time(780_381).saturating_mul(r.into())) + // Minimum execution time: 843 nanoseconds. + Weight::from_ref_time(1_126_252) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 251 + .saturating_add(Weight::from_ref_time(907_052).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64geu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 771 nanoseconds. - Weight::from_ref_time(1_063_735) - // Standard Error: 162 - .saturating_add(Weight::from_ref_time(779_906).saturating_mul(r.into())) + // Minimum execution time: 852 nanoseconds. + Weight::from_ref_time(1_497_667) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 7_593 + .saturating_add(Weight::from_ref_time(897_474).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64add(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 785 nanoseconds. - Weight::from_ref_time(1_059_585) - // Standard Error: 155 - .saturating_add(Weight::from_ref_time(756_828).saturating_mul(r.into())) + // Minimum execution time: 856 nanoseconds. + Weight::from_ref_time(1_350_390) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 2_625 + .saturating_add(Weight::from_ref_time(889_609).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64sub(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 800 nanoseconds. - Weight::from_ref_time(1_066_659) - // Standard Error: 154 - .saturating_add(Weight::from_ref_time(754_318).saturating_mul(r.into())) + // Minimum execution time: 841 nanoseconds. + Weight::from_ref_time(2_677_235) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 11_507 + .saturating_add(Weight::from_ref_time(846_704).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64mul(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 769 nanoseconds. - Weight::from_ref_time(1_078_854) - // Standard Error: 172 - .saturating_add(Weight::from_ref_time(754_183).saturating_mul(r.into())) + // Minimum execution time: 846 nanoseconds. + Weight::from_ref_time(1_148_206) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 393 + .saturating_add(Weight::from_ref_time(884_886).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64divs(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 770 nanoseconds. - Weight::from_ref_time(1_057_476) - // Standard Error: 191 - .saturating_add(Weight::from_ref_time(1_443_902).saturating_mul(r.into())) + // Minimum execution time: 865 nanoseconds. + Weight::from_ref_time(2_862_483) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 16_413 + .saturating_add(Weight::from_ref_time(1_481_623).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64divu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 764 nanoseconds. - Weight::from_ref_time(1_063_821) - // Standard Error: 193 - .saturating_add(Weight::from_ref_time(1_324_496).saturating_mul(r.into())) + // Minimum execution time: 1_443 nanoseconds. + Weight::from_ref_time(1_086_902) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 2_245 + .saturating_add(Weight::from_ref_time(1_463_145).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64rems(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 747 nanoseconds. - Weight::from_ref_time(1_093_209) - // Standard Error: 270 - .saturating_add(Weight::from_ref_time(1_447_180).saturating_mul(r.into())) + // Minimum execution time: 878 nanoseconds. + Weight::from_ref_time(1_130_306) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 475 + .saturating_add(Weight::from_ref_time(1_522_011).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64remu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 805 nanoseconds. - Weight::from_ref_time(1_033_953) - // Standard Error: 152 - .saturating_add(Weight::from_ref_time(1_336_911).saturating_mul(r.into())) + // Minimum execution time: 827 nanoseconds. + Weight::from_ref_time(1_197_053) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 474 + .saturating_add(Weight::from_ref_time(1_449_062).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64and(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 766 nanoseconds. - Weight::from_ref_time(1_059_430) - // Standard Error: 160 - .saturating_add(Weight::from_ref_time(757_265).saturating_mul(r.into())) + // Minimum execution time: 847 nanoseconds. + Weight::from_ref_time(1_152_423) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 296 + .saturating_add(Weight::from_ref_time(895_541).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64or(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 760 nanoseconds. - Weight::from_ref_time(1_077_376) - // Standard Error: 160 - .saturating_add(Weight::from_ref_time(755_800).saturating_mul(r.into())) + // Minimum execution time: 876 nanoseconds. + Weight::from_ref_time(1_169_485) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 571 + .saturating_add(Weight::from_ref_time(932_659).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64xor(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 798 nanoseconds. - Weight::from_ref_time(1_070_570) - // Standard Error: 157 - .saturating_add(Weight::from_ref_time(756_839).saturating_mul(r.into())) + // Minimum execution time: 856 nanoseconds. + Weight::from_ref_time(1_155_127) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 256 + .saturating_add(Weight::from_ref_time(895_663).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64shl(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 761 nanoseconds. - Weight::from_ref_time(1_074_645) - // Standard Error: 169 - .saturating_add(Weight::from_ref_time(771_486).saturating_mul(r.into())) + // Minimum execution time: 871 nanoseconds. + Weight::from_ref_time(1_139_722) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 367 + .saturating_add(Weight::from_ref_time(903_115).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64shrs(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 779 nanoseconds. - Weight::from_ref_time(1_107_671) - // Standard Error: 185 - .saturating_add(Weight::from_ref_time(769_168).saturating_mul(r.into())) + // Minimum execution time: 853 nanoseconds. + Weight::from_ref_time(1_155_542) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 541 + .saturating_add(Weight::from_ref_time(901_635).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64shru(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 755 nanoseconds. - Weight::from_ref_time(1_075_769) - // Standard Error: 164 - .saturating_add(Weight::from_ref_time(770_334).saturating_mul(r.into())) + // Minimum execution time: 866 nanoseconds. + Weight::from_ref_time(2_260_588) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 12_944 + .saturating_add(Weight::from_ref_time(877_790).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotl(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 767 nanoseconds. - Weight::from_ref_time(608_749) - // Standard Error: 2_059 - .saturating_add(Weight::from_ref_time(804_228).saturating_mul(r.into())) + // Minimum execution time: 851 nanoseconds. + Weight::from_ref_time(1_627_816) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 4_004 + .saturating_add(Weight::from_ref_time(887_929).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotr(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 779 nanoseconds. - Weight::from_ref_time(1_054_998) - // Standard Error: 191 - .saturating_add(Weight::from_ref_time(770_225).saturating_mul(r.into())) + // Minimum execution time: 874 nanoseconds. + Weight::from_ref_time(2_611_817) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 10_026 + .saturating_add(Weight::from_ref_time(862_138).saturating_mul(r.into())) } } diff --git a/primitives/wasm-interface/Cargo.toml b/primitives/wasm-interface/Cargo.toml index 5f914ae3aa177..21b0bb4329ed7 100644 --- a/primitives/wasm-interface/Cargo.toml +++ b/primitives/wasm-interface/Cargo.toml @@ -18,7 +18,7 @@ codec = { package = "parity-scale-codec", version = "3.2.2", default-features = impl-trait-for-tuples = "0.2.2" log = { version = "0.4.17", optional = true } wasmi = { version = "0.13", optional = true } -wasmtime = { version = "5.0.0", default-features = false, optional = true } +wasmtime = { version = "5.0.0", default-features = false, optional = true, git = "https://github.com/paritytech/wasmtime.git", branch = "v5.0.0_lto_fix" } anyhow = { version = "1.0.68", optional = true } sp-std = { version = "5.0.0", default-features = false, path = "../std" } From a10ccb562fa2f01832283d4d854a2938037f487a Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Wed, 15 Feb 2023 11:25:26 +0100 Subject: [PATCH 396/715] Fork tree prune assumptions removal v2 (#13327) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Removed assumptions about ancestry from fork tree prune method * Tests improvement * Fork tree prune refactory * Code refactory * Correctly handle borderline, but legit, case * Apply suggestions from code review Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> * Removed duplicated test --------- Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> --- client/consensus/epochs/src/lib.rs | 4 +- utils/fork-tree/src/lib.rs | 369 +++++++++++++++++------------ 2 files changed, 225 insertions(+), 148 deletions(-) diff --git a/client/consensus/epochs/src/lib.rs b/client/consensus/epochs/src/lib.rs index 7784a99437626..0e0b9fc17336f 100644 --- a/client/consensus/epochs/src/lib.rs +++ b/client/consensus/epochs/src/lib.rs @@ -1039,7 +1039,7 @@ mod tests { 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"]); + assert_eq!(nodes, vec![b"A", b"B", b"C", 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 @@ -1050,7 +1050,7 @@ mod tests { 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"]); + assert_eq!(nodes, vec![b"B", b"C", b"G"]); } #[test] diff --git a/utils/fork-tree/src/lib.rs b/utils/fork-tree/src/lib.rs index 76c28d910f943..bbd0daca4a28d 100644 --- a/utils/fork-tree/src/lib.rs +++ b/utils/fork-tree/src/lib.rs @@ -32,7 +32,7 @@ pub enum Error { UnfinalizedAncestor, /// Imported or finalized node that is an ancestor of previously finalized node. Revert, - /// Error throw by client when checking for node ancestry. + /// Error thrown by user when checking for node ancestry. Client(E), } @@ -48,11 +48,7 @@ impl fmt::Display for Error { } } -impl std::error::Error for Error { - fn cause(&self) -> Option<&dyn std::error::Error> { - None - } -} +impl std::error::Error for Error {} impl From for Error { fn from(err: E) -> Error { @@ -83,7 +79,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 +/// finalizing nodes, which means that node is traversed, and all competing /// branches are pruned. It also guarantees that nodes in the tree are finalized /// in order. Each node is uniquely identified by its hash but can be ordered by /// its number. In order to build the tree an external function must be provided @@ -99,12 +95,14 @@ where H: PartialEq, N: Ord, { - /// Create a new empty tree. + /// Create a new empty tree instance. pub fn new() -> ForkTree { ForkTree { roots: Vec::new(), best_finalized_number: None } } - /// Rebalance the tree, i.e. sort child nodes by max branch depth (decreasing). + /// Rebalance the tree. + /// + /// For each tree level 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 @@ -120,10 +118,12 @@ where } } - /// Import a new node into the tree. The given function `is_descendent_of` - /// should return `true` if the second hash (target) is a descendent of the - /// first hash (base). This method assumes that nodes in the same branch are - /// imported in order. + /// Import a new node into the tree. + /// + /// The given function `is_descendent_of` should return `true` if the second + /// hash (target) is a descendent of the first hash (base). + /// + /// This method assumes that nodes in the same branch are 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 @@ -232,9 +232,10 @@ where } /// 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) - /// is a descendent of the first hash (base). + /// block hash and which passes the given predicate. + /// + /// 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, @@ -281,10 +282,12 @@ where /// 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. + /// from one of the roots, 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. + // // 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 @@ -351,14 +354,16 @@ where }) } - /// 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). + /// Prune the tree, removing all non-canonical nodes. /// - /// Returns all pruned node data. + /// 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 nodes data. pub fn prune( &mut self, hash: &H, @@ -371,42 +376,59 @@ where F: Fn(&H, &H) -> Result, P: Fn(&V) -> bool, { - let root_index = + let new_root_path = match self.find_node_index_where(hash, number, is_descendent_of, predicate)? { - Some(idx) => idx, + Some(path) => path, None => return Ok(RemovedIterator { stack: Vec::new() }), }; - let mut old_roots = std::mem::take(&mut self.roots); + let mut removed = std::mem::take(&mut self.roots); - let curr_children = root_index + // Find and detach the new root from the removed nodes + let root_siblings = new_root_path .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; + .take(new_root_path.len() - 1) + .fold(&mut removed, |curr, idx| &mut curr[*idx].children); + let root = root_siblings.remove(new_root_path[new_root_path.len() - 1]); + self.roots = vec![root]; - // 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; + // If, because of the `predicate`, the new root is not the deepest ancestor + // of `hash` then we can remove all the nodes that are descendants of the new + // `root` but not ancestors of `hash`. + let mut curr = &mut self.roots[0]; + loop { + let mut maybe_ancestor_idx = None; + for (idx, child) in curr.children.iter().enumerate() { + if child.number < *number && is_descendent_of(&child.hash, hash)? { + maybe_ancestor_idx = Some(idx); + break + } + } + let Some(ancestor_idx) = maybe_ancestor_idx else { + // Now we are positioned just above block identified by `hash` + break + }; + // Preserve only the ancestor node, the siblings are removed + let mut next_siblings = std::mem::take(&mut curr.children); + let next = next_siblings.remove(ancestor_idx); + curr.children = vec![next]; + removed.append(&mut next_siblings); + curr = &mut curr.children[0]; + } - for child in root_children { - if is_first && - (child.number == *number && child.hash == *hash || - child.number < *number && is_descendent_of(&child.hash, hash)?) + // Curr now points to our direct ancestor, if necessary remove any node that is + // not a descendant of `hash`. + let children = std::mem::take(&mut curr.children); + for child in children { + if child.number == *number && child.hash == *hash || + *number < child.number && is_descendent_of(hash, &child.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; + curr.children.push(child); } else { removed.push(child); } } - self.roots = vec![root]; self.rebalance(); Ok(RemovedIterator { stack: removed }) @@ -836,21 +858,21 @@ mod test { impl std::error::Error for TestError {} fn test_fork_tree<'a>( - ) -> (ForkTree<&'a str, u64, ()>, impl Fn(&&str, &&str) -> Result) { + ) -> (ForkTree<&'a str, u64, u32>, impl Fn(&&str, &&str) -> Result) { let mut tree = ForkTree::new(); #[rustfmt::skip] // - // - B - C - D - E - // / - // / - G - // / / - // A - F - H - I - // \ \ - // \ - L - M - N - // \ \ - // \ - O - // - J - K + // +---B-c-C---D---E + // | + // | +---G + // | | + // 0---A---F---H---I + // | | + // | +---L-m-M---N + // | | + // | +---O + // +---J---K // // (where N is not a part of fork tree) // @@ -859,9 +881,12 @@ mod test { // 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", "N", "O"]; - match (*base, *block) { + // This is a trick to have lowercase blocks be direct parents of their + // uppercase correspondent (A excluded) + let block = block.to_uppercase(); + match (*base, block) { ("A", b) => Ok(letters.into_iter().any(|n| n == b)), - ("B", b) => Ok(b == "C" || b == "D" || b == "E"), + ("B" | "c", b) => Ok(b == "C" || b == "D" || b == "E"), ("C", b) => Ok(b == "D" || b == "E"), ("D", b) => Ok(b == "E"), ("E", _) => Ok(false), @@ -872,7 +897,8 @@ mod test { ("I", _) => Ok(false), ("J", b) => Ok(b == "K"), ("K", _) => Ok(false), - ("L", b) => Ok(b == "M" || b == "O" || b == "N"), + ("L", b) => Ok(b == "M" || b == "N" || b == "O"), + ("m", b) => Ok(b == "M" || b == "N"), ("M", b) => Ok(b == "N"), ("O", _) => Ok(false), ("0", _) => Ok(true), @@ -880,24 +906,20 @@ mod test { } }; - tree.import("A", 1, (), &is_descendent_of).unwrap(); - - tree.import("B", 2, (), &is_descendent_of).unwrap(); - tree.import("C", 3, (), &is_descendent_of).unwrap(); - tree.import("D", 4, (), &is_descendent_of).unwrap(); - tree.import("E", 5, (), &is_descendent_of).unwrap(); - - tree.import("F", 2, (), &is_descendent_of).unwrap(); - tree.import("G", 3, (), &is_descendent_of).unwrap(); - - tree.import("H", 3, (), &is_descendent_of).unwrap(); - tree.import("I", 4, (), &is_descendent_of).unwrap(); - tree.import("L", 4, (), &is_descendent_of).unwrap(); - tree.import("M", 5, (), &is_descendent_of).unwrap(); - tree.import("O", 5, (), &is_descendent_of).unwrap(); - - tree.import("J", 2, (), &is_descendent_of).unwrap(); - tree.import("K", 3, (), &is_descendent_of).unwrap(); + tree.import("A", 10, 1, &is_descendent_of).unwrap(); + tree.import("B", 20, 2, &is_descendent_of).unwrap(); + tree.import("C", 30, 3, &is_descendent_of).unwrap(); + tree.import("D", 40, 4, &is_descendent_of).unwrap(); + tree.import("E", 50, 5, &is_descendent_of).unwrap(); + tree.import("F", 20, 2, &is_descendent_of).unwrap(); + tree.import("G", 30, 3, &is_descendent_of).unwrap(); + tree.import("H", 30, 3, &is_descendent_of).unwrap(); + tree.import("I", 40, 4, &is_descendent_of).unwrap(); + tree.import("L", 40, 4, &is_descendent_of).unwrap(); + tree.import("M", 50, 5, &is_descendent_of).unwrap(); + tree.import("O", 50, 5, &is_descendent_of).unwrap(); + tree.import("J", 20, 2, &is_descendent_of).unwrap(); + tree.import("K", 30, 3, &is_descendent_of).unwrap(); (tree, is_descendent_of) } @@ -908,22 +930,22 @@ mod test { tree.finalize_root(&"A"); - assert_eq!(tree.best_finalized_number, Some(1)); + assert_eq!(tree.best_finalized_number, Some(10)); - assert_eq!(tree.import("A", 1, (), &is_descendent_of), Err(Error::Revert)); + assert_eq!(tree.import("A", 10, 1, &is_descendent_of), Err(Error::Revert)); } #[test] fn import_doesnt_add_duplicates() { let (mut tree, is_descendent_of) = test_fork_tree(); - assert_eq!(tree.import("A", 1, (), &is_descendent_of), Err(Error::Duplicate)); + assert_eq!(tree.import("A", 10, 1, &is_descendent_of), Err(Error::Duplicate)); - assert_eq!(tree.import("I", 4, (), &is_descendent_of), Err(Error::Duplicate)); + assert_eq!(tree.import("I", 40, 4, &is_descendent_of), Err(Error::Duplicate)); - assert_eq!(tree.import("G", 3, (), &is_descendent_of), Err(Error::Duplicate)); + assert_eq!(tree.import("G", 30, 3, &is_descendent_of), Err(Error::Duplicate)); - assert_eq!(tree.import("K", 3, (), &is_descendent_of), Err(Error::Duplicate)); + assert_eq!(tree.import("K", 30, 3, &is_descendent_of), Err(Error::Duplicate)); } #[test] @@ -931,14 +953,14 @@ mod test { let finalize_a = || { let (mut tree, ..) = test_fork_tree(); - assert_eq!(tree.roots().map(|(h, n, _)| (*h, *n)).collect::>(), vec![("A", 1)]); + assert_eq!(tree.roots().map(|(h, n, _)| (*h, *n)).collect::>(), vec![("A", 10)]); // finalizing "A" opens up three possible forks tree.finalize_root(&"A"); assert_eq!( tree.roots().map(|(h, n, _)| (*h, *n)).collect::>(), - vec![("B", 2), ("F", 2), ("J", 2)], + vec![("B", 20), ("F", 20), ("J", 20)], ); tree @@ -950,7 +972,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, *n)).collect::>(), vec![("C", 3)],); + assert_eq!(tree.roots().map(|(h, n, _)| (*h, *n)).collect::>(), vec![("C", 30)],); // all the other forks have been pruned assert!(tree.roots.len() == 1); @@ -962,7 +984,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, *n)).collect::>(), vec![("K", 3)],); + assert_eq!(tree.roots().map(|(h, n, _)| (*h, *n)).collect::>(), vec![("K", 30)],); // all the other forks have been pruned assert!(tree.roots.len() == 1); @@ -982,42 +1004,42 @@ mod test { // finalizing "A" opens up three possible forks assert_eq!( - tree.finalize(&"A", 1, &is_descendent_of), - Ok(FinalizationResult::Changed(Some(()))), + tree.finalize(&"A", 10, &is_descendent_of), + Ok(FinalizationResult::Changed(Some(1))), ); assert_eq!( tree.roots().map(|(h, n, _)| (*h, *n)).collect::>(), - vec![("B", 2), ("F", 2), ("J", 2)], + vec![("B", 20), ("F", 20), ("J", 20)], ); // finalizing anything lower than what we observed will fail - assert_eq!(tree.best_finalized_number, Some(1)); + assert_eq!(tree.best_finalized_number, Some(10)); - assert_eq!(tree.finalize(&"Z", 1, &is_descendent_of), Err(Error::Revert)); + assert_eq!(tree.finalize(&"Z", 10, &is_descendent_of), Err(Error::Revert)); // trying to finalize a node without finalizing its ancestors first will fail - assert_eq!(tree.finalize(&"H", 3, &is_descendent_of), Err(Error::UnfinalizedAncestor)); + assert_eq!(tree.finalize(&"H", 30, &is_descendent_of), Err(Error::UnfinalizedAncestor)); // after finalizing "F" we can finalize "H" assert_eq!( - tree.finalize(&"F", 2, &is_descendent_of), - Ok(FinalizationResult::Changed(Some(()))), + tree.finalize(&"F", 20, &is_descendent_of), + Ok(FinalizationResult::Changed(Some(2))), ); assert_eq!( - tree.finalize(&"H", 3, &is_descendent_of), - Ok(FinalizationResult::Changed(Some(()))), + tree.finalize(&"H", 30, &is_descendent_of), + Ok(FinalizationResult::Changed(Some(3))), ); assert_eq!( tree.roots().map(|(h, n, _)| (*h, *n)).collect::>(), - vec![("L", 4), ("I", 4)], + vec![("L", 40), ("I", 40)], ); // finalizing a node from another fork that isn't part of the tree clears the tree assert_eq!( - tree.finalize(&"Z", 5, &is_descendent_of), + tree.finalize(&"Z", 50, &is_descendent_of), Ok(FinalizationResult::Changed(None)), ); @@ -1040,13 +1062,13 @@ mod test { // finalizing "A" opens up three possible forks assert_eq!( - tree.finalize_with_ancestors(&"A", 1, &is_descendent_of), - Ok(FinalizationResult::Changed(Some(()))), + tree.finalize_with_ancestors(&"A", 10, &is_descendent_of), + Ok(FinalizationResult::Changed(Some(1))), ); assert_eq!( tree.roots().map(|(h, n, _)| (*h, *n)).collect::>(), - vec![("B", 2), ("F", 2), ("J", 2)], + vec![("B", 20), ("F", 20), ("J", 20)], ); // finalizing H: @@ -1054,16 +1076,16 @@ mod test { // 2) opens root that is ancestor of H (F -> G+H) // 3) finalizes the just opened root H (H -> I + L) assert_eq!( - tree.finalize_with_ancestors(&"H", 3, &is_descendent_of), - Ok(FinalizationResult::Changed(Some(()))), + tree.finalize_with_ancestors(&"H", 30, &is_descendent_of), + Ok(FinalizationResult::Changed(Some(3))), ); assert_eq!( tree.roots().map(|(h, n, _)| (*h, *n)).collect::>(), - vec![("L", 4), ("I", 4)], + vec![("L", 40), ("I", 40)], ); - assert_eq!(tree.best_finalized_number, Some(3)); + assert_eq!(tree.best_finalized_number, Some(30)); // finalizing N (which is not a part of the tree): // 1) removes roots that are not ancestors/descendants of N (I) @@ -1071,13 +1093,13 @@ mod test { // 3) removes roots that are not ancestors/descendants of N (O) // 4) opens root that is ancestor of N (M -> {}) assert_eq!( - tree.finalize_with_ancestors(&"N", 6, &is_descendent_of), + tree.finalize_with_ancestors(&"N", 60, &is_descendent_of), Ok(FinalizationResult::Changed(None)), ); assert_eq!(tree.roots().map(|(h, n, _)| (*h, *n)).collect::>(), vec![],); - assert_eq!(tree.best_finalized_number, Some(6)); + assert_eq!(tree.best_finalized_number, Some(60)); } #[test] @@ -1209,20 +1231,20 @@ mod test { assert_eq!( tree.iter().map(|(h, n, _)| (*h, *n)).collect::>(), vec![ - ("A", 1), - ("B", 2), - ("C", 3), - ("D", 4), - ("E", 5), - ("F", 2), - ("H", 3), - ("L", 4), - ("M", 5), - ("O", 5), - ("I", 4), - ("G", 3), - ("J", 2), - ("K", 3), + ("A", 10), + ("B", 20), + ("C", 30), + ("D", 40), + ("E", 50), + ("F", 20), + ("H", 30), + ("L", 40), + ("M", 50), + ("O", 50), + ("I", 40), + ("G", 30), + ("J", 20), + ("K", 30), ], ); } @@ -1289,9 +1311,9 @@ mod test { // 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(); + let is_root = tree.import("A1", 10, 1, &is_descendent_of).unwrap(); assert!(is_root); - let is_root = tree.import("A2", 1, (), &is_descendent_of).unwrap(); + let is_root = tree.import("A2", 10, 1, &is_descendent_of).unwrap(); assert!(is_root); let old_tree = tree.clone(); @@ -1306,10 +1328,10 @@ mod test { } #[test] - fn prune_works() { + fn prune_works_for_in_tree_hashes() { let (mut tree, is_descendent_of) = test_fork_tree(); - let removed = tree.prune(&"C", &3, &is_descendent_of, &|_| true).unwrap(); + let removed = tree.prune(&"C", &30, &is_descendent_of, &|_| true).unwrap(); assert_eq!(tree.roots.iter().map(|node| node.hash).collect::>(), vec!["B"]); @@ -1323,7 +1345,7 @@ mod test { vec!["A", "F", "H", "L", "M", "O", "I", "G", "J", "K"] ); - let removed = tree.prune(&"E", &5, &is_descendent_of, &|_| true).unwrap(); + let removed = tree.prune(&"E", &50, &is_descendent_of, &|_| true).unwrap(); assert_eq!(tree.roots.iter().map(|node| node.hash).collect::>(), vec!["D"]); @@ -1332,6 +1354,61 @@ mod test { assert_eq!(removed.map(|(hash, _, _)| hash).collect::>(), vec!["B", "C"]); } + #[test] + fn prune_works_for_out_of_tree_hashes() { + let (mut tree, is_descendent_of) = test_fork_tree(); + + let removed = tree.prune(&"c", &25, &is_descendent_of, &|_| true).unwrap(); + + assert_eq!(tree.roots.iter().map(|node| node.hash).collect::>(), vec!["B"]); + + assert_eq!( + tree.iter().map(|(hash, _, _)| *hash).collect::>(), + vec!["B", "C", "D", "E"], + ); + + assert_eq!( + removed.map(|(hash, _, _)| hash).collect::>(), + vec!["A", "F", "H", "L", "M", "O", "I", "G", "J", "K"] + ); + } + + #[test] + fn prune_works_for_not_direct_ancestor() { + let (mut tree, is_descendent_of) = test_fork_tree(); + + // This is to re-root the tree not at the immediate ancestor, but the one just before. + let removed = tree.prune(&"m", &45, &is_descendent_of, &|height| *height == 3).unwrap(); + + assert_eq!(tree.roots.iter().map(|node| node.hash).collect::>(), vec!["H"]); + + assert_eq!(tree.iter().map(|(hash, _, _)| *hash).collect::>(), vec!["H", "L", "M"],); + + assert_eq!( + removed.map(|(hash, _, _)| hash).collect::>(), + vec!["O", "I", "A", "B", "C", "D", "E", "F", "G", "J", "K"] + ); + } + + #[test] + fn prune_works_for_far_away_ancestor() { + let (mut tree, is_descendent_of) = test_fork_tree(); + + let removed = tree.prune(&"m", &45, &is_descendent_of, &|height| *height == 2).unwrap(); + + assert_eq!(tree.roots.iter().map(|node| node.hash).collect::>(), vec!["F"]); + + assert_eq!( + tree.iter().map(|(hash, _, _)| *hash).collect::>(), + vec!["F", "H", "L", "M"], + ); + + assert_eq!( + removed.map(|(hash, _, _)| hash).collect::>(), + vec!["O", "I", "G", "A", "B", "C", "D", "E", "J", "K"] + ); + } + #[test] fn find_node_backtracks_after_finding_highest_descending_node() { let mut tree = ForkTree::new(); @@ -1381,7 +1458,7 @@ mod test { } }; - tree.import("P", 6, (), &is_descendent_of).unwrap(); + tree.import("P", 60, 6, &is_descendent_of).unwrap(); // this should re-order the tree, since the branch "A -> B -> C -> D -> E" is no longer tied // with 5 blocks depth. additionally "O" should be visited before "M" now, since it has one @@ -1396,7 +1473,7 @@ mod test { fn drain_filter_works() { let (mut tree, _) = test_fork_tree(); - let filter = |h: &&str, _: &u64, _: &()| match *h { + let filter = |h: &&str, _: &u64, _: &u32| match *h { "A" | "B" | "F" | "G" => FilterAction::KeepNode, "C" => FilterAction::KeepTree, "H" | "J" => FilterAction::Remove, @@ -1421,19 +1498,19 @@ mod test { let (tree, is_descendent_of) = test_fork_tree(); let path = tree - .find_node_index_where(&"D", &4, &is_descendent_of, &|_| true) + .find_node_index_where(&"D", &40, &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) + .find_node_index_where(&"O", &50, &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) + .find_node_index_where(&"N", &60, &is_descendent_of, &|_| true) .unwrap() .unwrap(); assert_eq!(path, [0, 1, 0, 0, 0]); @@ -1489,17 +1566,17 @@ 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(&"B", &20, &is_descendent_of, &|_| true).unwrap().unwrap(); + assert_eq!((node.hash, node.number), ("A", 10)); - 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(&"D", &40, &is_descendent_of, &|_| true).unwrap().unwrap(); + assert_eq!((node.hash, node.number), ("C", 30)); - 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(&"O", &50, &is_descendent_of, &|_| true).unwrap().unwrap(); + assert_eq!((node.hash, node.number), ("L", 40)); - let node = tree.find_node_where(&"N", &6, &is_descendent_of, &|_| true).unwrap().unwrap(); - assert_eq!((node.hash, node.number), ("M", 5)); + let node = tree.find_node_where(&"N", &60, &is_descendent_of, &|_| true).unwrap().unwrap(); + assert_eq!((node.hash, node.number), ("M", 50)); } #[test] @@ -1516,13 +1593,13 @@ mod test { // 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) + .find_node_index_where(&"N", &60, &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); + let res = tree.import(&"Z", 100, 10, &is_descendent_of_for_post_order); assert_eq!(res, Ok(false)); assert_eq!( tree.iter().map(|node| *node.0).collect::>(), From 725e47a4252392dd1b045e32861978c3c18e7419 Mon Sep 17 00:00:00 2001 From: Sergejs Kostjucenko <85877331+sergejparity@users.noreply.github.com> Date: Wed, 15 Feb 2023 22:35:16 +0200 Subject: [PATCH 397/715] CI add subkey docker image description and CI job to publish it to the hub.docker.com (#13392) * Add subkey docker image description and ci job to publish it * Add link to docs * fix formatting * fix ci --- scripts/ci/docker/subkey.Dockerfile.README.md | 8 +++++++ scripts/ci/gitlab/pipeline/publish.yml | 21 +++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 scripts/ci/docker/subkey.Dockerfile.README.md diff --git a/scripts/ci/docker/subkey.Dockerfile.README.md b/scripts/ci/docker/subkey.Dockerfile.README.md new file mode 100644 index 0000000000000..30a5e8212150e --- /dev/null +++ b/scripts/ci/docker/subkey.Dockerfile.README.md @@ -0,0 +1,8 @@ +# The `subkey` program is a key management utility for Substrate-based blockchains. You can use the `subkey` program to perform the following tasks: + +* Generate and inspect cryptographically-secure public and private key pairs. +* Restore keys from secret phrases and raw seeds. +* Sign and verify signatures on messages. +* Sign and verify signatures for encoded transactions. +* Derive hierarchical deterministic child key pairs. +* [Documentation](https://docs.substrate.io/reference/command-line-tools/subkey/) \ No newline at end of file diff --git a/scripts/ci/gitlab/pipeline/publish.yml b/scripts/ci/gitlab/pipeline/publish.yml index 4eafb0a055399..9f075903697a5 100644 --- a/scripts/ci/gitlab/pipeline/publish.yml +++ b/scripts/ci/gitlab/pipeline/publish.yml @@ -49,6 +49,19 @@ DOCKER_USER: $Docker_Hub_User_Parity DOCKER_PASS: $Docker_Hub_Pass_Parity +.push-docker-image-description: + stage: publish + extends: + - .kubernetes-env + - .publish-refs + variables: + CI_IMAGE: paritytech/docker-description + DOCKERHUB_REPOSITORY: parity/$PRODUCT + DOCKER_USERNAME: $Docker_Hub_User_Parity + DOCKER_PASSWORD: $Docker_Hub_Pass_Parity + README_FILEPATH: $CI_PROJECT_DIR/scripts/ci/docker/$PRODUCT.Dockerfile.README.md + script: + - echo # Dummy command to satisfy GitLab CI linter. # publish image to docker.io/paritypr, (e.g. for later use in zombienet testing) .build-push-image-temporary: @@ -90,6 +103,14 @@ publish-docker-subkey: variables: PRODUCT: subkey +publish-docker-description-subkey: + extends: .push-docker-image-description + needs: + - job: build-subkey-linux + variables: + PRODUCT: subkey + SHORT_DESCRIPTION: "The subkey program is a key management utility for Substrate-based blockchains." + publish-s3-release: stage: publish extends: From 7732f88c117ceb41b57a51402abd64f888acd013 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Wed, 15 Feb 2023 22:56:50 +0100 Subject: [PATCH 398/715] contracts: Use `proof_size` from benchmarks (#13268) * Avoid reading contract code when it is supplied in the extrinsic * Remove custom proof size injection from schedule * Set benchmarks pov_mode to Measure * Reduce overestimation of code size on re-instrument * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_contracts * Do not override proof size from benchmark * Do not charge proof size for basic block * Incrase gas limit for tests * Fix deletion queue to also use `proof_size` * Fix tests * Update frame/contracts/src/schedule.rs Co-authored-by: Cyrill Leutwiler * Fix wrong schedule macro invocations * Remove stale docs * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_contracts * Handle zero components * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_contracts * Fix instruction weight --------- Co-authored-by: command-bot <> Co-authored-by: Cyrill Leutwiler --- frame/contracts/src/benchmarking/mod.rs | 148 +- frame/contracts/src/schedule.rs | 173 +- frame/contracts/src/storage.rs | 17 +- frame/contracts/src/tests.rs | 8 +- frame/contracts/src/wasm/code_cache.rs | 104 +- frame/contracts/src/wasm/mod.rs | 4 +- frame/contracts/src/weights.rs | 3664 ++++++++++++----------- primitives/weights/src/weight_v2.rs | 76 + 8 files changed, 2173 insertions(+), 2021 deletions(-) diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index e834508a0e284..55d315d5c7be1 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -205,13 +205,13 @@ benchmarks! { } // The base weight consumed on processing contracts deletion queue. - #[pov_mode = Ignored] + #[pov_mode = Measured] on_process_deletion_queue_batch {}: { Storage::::process_deletion_queue_batch(Weight::MAX) } #[skip_meta] - #[pov_mode = Ignored] + #[pov_mode = Measured] on_initialize_per_trie_key { let k in 0..1024; let instance = Contract::::with_storage(WasmModule::dummy(), k, T::Schedule::get().limits.payload_len)?; @@ -220,7 +220,7 @@ benchmarks! { Storage::::process_deletion_queue_batch(Weight::MAX) } - #[pov_mode = Ignored] + #[pov_mode = Measured] on_initialize_per_queue_item { let q in 0..1024.min(T::DeletionQueueDepth::get()); for i in 0 .. q { @@ -235,7 +235,7 @@ 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. - #[pov_mode = Ignored] + #[pov_mode = Measured] reinstrument { let c in 0 .. Perbill::from_percent(49).mul_ceil(T::MaxCodeLen::get()); let WasmModule { code, hash, .. } = WasmModule::::sized(c, Location::Call); @@ -252,7 +252,7 @@ benchmarks! { // 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)`. - #[pov_mode = Ignored] + #[pov_mode = Measured] call_with_code_per_byte { let c in 0 .. T::MaxCodeLen::get(); let instance = Contract::::with_caller( @@ -278,7 +278,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**. - #[pov_mode = Ignored] + #[pov_mode = Measured] instantiate_with_code { let c in 0 .. Perbill::from_percent(49).mul_ceil(T::MaxCodeLen::get()); let i in 0 .. code::max_pages::() * 64 * 1024; @@ -310,7 +310,7 @@ benchmarks! { // Instantiate uses a dummy contract constructor to measure the overhead of the instantiate. // `i`: Size of the input in kilobytes. // `s`: Size of the salt in kilobytes. - #[pov_mode = Ignored] + #[pov_mode = Measured] instantiate { let i in 0 .. code::max_pages::() * 64 * 1024; let s in 0 .. code::max_pages::() * 64 * 1024; @@ -342,7 +342,7 @@ benchmarks! { // 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. - #[pov_mode = Ignored] + #[pov_mode = Measured] call { let data = vec![42u8; 1024]; let instance = Contract::::with_caller( @@ -375,7 +375,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**. - #[pov_mode = Ignored] + #[pov_mode = Measured] upload_code { let c in 0 .. Perbill::from_percent(49).mul_ceil(T::MaxCodeLen::get()); let caller = whitelisted_caller(); @@ -392,7 +392,7 @@ benchmarks! { // 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`). - #[pov_mode = Ignored] + #[pov_mode = Measured] remove_code { let caller = whitelisted_caller(); T::Currency::make_free_balance_be(&caller, caller_funding::()); @@ -409,7 +409,7 @@ benchmarks! { assert!(>::code_removed(&hash)); } - #[pov_mode = Ignored] + #[pov_mode = Measured] set_code { let instance = >::with_caller( whitelisted_caller(), WasmModule::dummy(), vec![], @@ -424,7 +424,7 @@ benchmarks! { assert_eq!(instance.info()?.code_hash, hash); } - #[pov_mode = Ignored] + #[pov_mode = Measured] seal_caller { let r in 0 .. API_BENCHMARK_BATCHES; let instance = Contract::::new(WasmModule::getter( @@ -433,7 +433,7 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) - #[pov_mode = Ignored] + #[pov_mode = Measured] seal_is_contract { let r in 0 .. API_BENCHMARK_BATCHES; let accounts = (0 .. r * API_BENCHMARK_BATCH_SIZE) @@ -471,7 +471,7 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) - #[pov_mode = Ignored] + #[pov_mode = Measured] seal_code_hash { let r in 0 .. API_BENCHMARK_BATCHES; let accounts = (0 .. r * API_BENCHMARK_BATCH_SIZE) @@ -517,7 +517,7 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) - #[pov_mode = Ignored] + #[pov_mode = Measured] seal_own_code_hash { let r in 0 .. API_BENCHMARK_BATCHES; let instance = Contract::::new(WasmModule::getter( @@ -526,7 +526,7 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) - #[pov_mode = Ignored] + #[pov_mode = Measured] seal_caller_is_origin { let r in 0 .. API_BENCHMARK_BATCHES; let code = WasmModule::::from(ModuleDefinition { @@ -547,7 +547,7 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) - #[pov_mode = Ignored] + #[pov_mode = Measured] seal_address { let r in 0 .. API_BENCHMARK_BATCHES; let instance = Contract::::new(WasmModule::getter( @@ -556,7 +556,7 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) - #[pov_mode = Ignored] + #[pov_mode = Measured] seal_gas_left { let r in 0 .. API_BENCHMARK_BATCHES; let instance = Contract::::new(WasmModule::getter( @@ -565,7 +565,7 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) - #[pov_mode = Ignored] + #[pov_mode = Measured] seal_balance { let r in 0 .. API_BENCHMARK_BATCHES; let instance = Contract::::new(WasmModule::getter( @@ -574,7 +574,7 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) - #[pov_mode = Ignored] + #[pov_mode = Measured] seal_value_transferred { let r in 0 .. API_BENCHMARK_BATCHES; let instance = Contract::::new(WasmModule::getter( @@ -583,7 +583,7 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) - #[pov_mode = Ignored] + #[pov_mode = Measured] seal_minimum_balance { let r in 0 .. API_BENCHMARK_BATCHES; let instance = Contract::::new(WasmModule::getter( @@ -592,7 +592,7 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) - #[pov_mode = Ignored] + #[pov_mode = Measured] seal_block_number { let r in 0 .. API_BENCHMARK_BATCHES; let instance = Contract::::new(WasmModule::getter( @@ -601,7 +601,7 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) - #[pov_mode = Ignored] + #[pov_mode = Measured] seal_now { let r in 0 .. API_BENCHMARK_BATCHES; let instance = Contract::::new(WasmModule::getter( @@ -610,7 +610,7 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) - #[pov_mode = Ignored] + #[pov_mode = Measured] seal_weight_to_fee { let r in 0 .. API_BENCHMARK_BATCHES; let pages = code::max_pages::(); @@ -638,7 +638,7 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) - #[pov_mode = Ignored] + #[pov_mode = Measured] seal_gas { let r in 0 .. API_BENCHMARK_BATCHES; let code = WasmModule::::from(ModuleDefinition { @@ -659,7 +659,7 @@ benchmarks! { }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) - #[pov_mode = Ignored] + #[pov_mode = Measured] seal_input { let r in 0 .. API_BENCHMARK_BATCHES; let code = WasmModule::::from(ModuleDefinition { @@ -687,7 +687,7 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) - #[pov_mode = Ignored] + #[pov_mode = Measured] seal_input_per_kb { let n in 0 .. code::max_pages::() * 64; let pages = code::max_pages::(); @@ -721,7 +721,7 @@ benchmarks! { // 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 // contract it cannot be used as an attack vector. - #[pov_mode = Ignored] + #[pov_mode = Measured] seal_return { let r in 0 .. 1; let code = WasmModule::::from(ModuleDefinition { @@ -744,7 +744,7 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) - #[pov_mode = Ignored] + #[pov_mode = Measured] seal_return_per_kb { let n in 0 .. code::max_pages::() * 64; let code = WasmModule::::from(ModuleDefinition { @@ -769,7 +769,7 @@ benchmarks! { }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) // The same argument as for `seal_return` is true here. - #[pov_mode = Ignored] + #[pov_mode = Measured] seal_terminate { let r in 0 .. 1; let beneficiary = account::("beneficiary", 0, 0); @@ -812,7 +812,7 @@ benchmarks! { // We benchmark only for the maximum subject length. We assume that this is some lowish // number (< 1 KB). Therefore we are not overcharging too much in case a smaller subject is // used. - #[pov_mode = Ignored] + #[pov_mode = Measured] seal_random { let r in 0 .. API_BENCHMARK_BATCHES; let pages = code::max_pages::(); @@ -847,7 +847,7 @@ benchmarks! { // Overhead of calling the function without any topic. // We benchmark for the worst case (largest event). - #[pov_mode = Ignored] + #[pov_mode = Measured] seal_deposit_event { let r in 0 .. API_BENCHMARK_BATCHES; let code = WasmModule::::from(ModuleDefinition { @@ -874,7 +874,7 @@ benchmarks! { // Benchmark the overhead that topics generate. // `t`: Number of topics // `n`: Size of event payload in kb - #[pov_mode = Ignored] + #[pov_mode = Measured] seal_deposit_event_per_topic_and_kb { let t in 0 .. T::Schedule::get().limits.event_topics; let n in 0 .. T::Schedule::get().limits.payload_len / 1024; @@ -913,7 +913,7 @@ benchmarks! { // Benchmark debug_message call with zero input data. // Whereas this function is used in RPC mode only, it still should be secured // against an excessive use. - #[pov_mode = Ignored] + #[pov_mode = Measured] seal_debug_message { let r in 0 .. API_BENCHMARK_BATCHES; let code = WasmModule::::from(ModuleDefinition { @@ -1003,7 +1003,7 @@ benchmarks! { // because re-writing at an existing key is always more expensive than writing // it at a virgin key. #[skip_meta] - #[pov_mode = Ignored] + #[pov_mode = Measured] seal_set_storage { let r in 0 .. API_BENCHMARK_BATCHES/2; let max_key_len = T::MaxStorageKeyLen::get(); @@ -1052,7 +1052,7 @@ benchmarks! { }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) #[skip_meta] - #[pov_mode = Ignored] + #[pov_mode = Measured] seal_set_storage_per_new_kb { 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(); @@ -1101,7 +1101,7 @@ benchmarks! { }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) #[skip_meta] - #[pov_mode = Ignored] + #[pov_mode = Measured] seal_set_storage_per_old_kb { 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(); @@ -1154,7 +1154,7 @@ benchmarks! { // 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] - #[pov_mode = Ignored] + #[pov_mode = Measured] seal_clear_storage { let r in 0 .. API_BENCHMARK_BATCHES/2; let max_key_len = T::MaxStorageKeyLen::get(); @@ -1202,7 +1202,7 @@ benchmarks! { }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) #[skip_meta] - #[pov_mode = Ignored] + #[pov_mode = Measured] seal_clear_storage_per_kb { 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(); @@ -1250,7 +1250,7 @@ benchmarks! { // We make sure that all storage accesses are to unique keys. #[skip_meta] - #[pov_mode = Ignored] + #[pov_mode = Measured] seal_get_storage { let r in 0 .. API_BENCHMARK_BATCHES/2; let max_key_len = T::MaxStorageKeyLen::get(); @@ -1305,7 +1305,7 @@ benchmarks! { }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) #[skip_meta] - #[pov_mode = Ignored] + #[pov_mode = Measured] seal_get_storage_per_kb { 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(); @@ -1361,7 +1361,7 @@ benchmarks! { // We make sure that all storage accesses are to unique keys. #[skip_meta] - #[pov_mode = Ignored] + #[pov_mode = Measured] seal_contains_storage { let r in 0 .. API_BENCHMARK_BATCHES/2; let max_key_len = T::MaxStorageKeyLen::get(); @@ -1410,7 +1410,7 @@ benchmarks! { }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) #[skip_meta] - #[pov_mode = Ignored] + #[pov_mode = Measured] seal_contains_storage_per_kb { 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(); @@ -1458,7 +1458,7 @@ benchmarks! { }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) #[skip_meta] - #[pov_mode = Ignored] + #[pov_mode = Measured] seal_take_storage { let r in 0 .. API_BENCHMARK_BATCHES/2; let max_key_len = T::MaxStorageKeyLen::get(); @@ -1513,7 +1513,7 @@ benchmarks! { }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) #[skip_meta] - #[pov_mode = Ignored] + #[pov_mode = Measured] seal_take_storage_per_kb { 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(); @@ -1568,7 +1568,7 @@ benchmarks! { }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) // We transfer to unique accounts. - #[pov_mode = Ignored] + #[pov_mode = Measured] seal_transfer { let r in 0 .. API_BENCHMARK_BATCHES; let accounts = (0..r * API_BENCHMARK_BATCH_SIZE) @@ -1622,7 +1622,7 @@ benchmarks! { } // We call unique accounts. - #[pov_mode = Ignored] + #[pov_mode = Measured] seal_call { let r in 0 .. API_BENCHMARK_BATCHES; let dummy_code = WasmModule::::dummy_with_bytes(0); @@ -1681,7 +1681,7 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) - #[pov_mode = Ignored] + #[pov_mode = Measured] seal_delegate_call { let r in 0 .. API_BENCHMARK_BATCHES; let hashes = (0..r * API_BENCHMARK_BATCH_SIZE) @@ -1734,7 +1734,7 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller); }: call(origin, callee, 0u32.into(), Weight::MAX, None, vec![]) - #[pov_mode = Ignored] + #[pov_mode = Measured] seal_call_per_transfer_clone_kb { let t in 0 .. 1; let c in 0 .. code::max_pages::() * 64; @@ -1793,7 +1793,7 @@ benchmarks! { }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, bytes) // We assume that every instantiate sends at least the minimum balance. - #[pov_mode = Ignored] + #[pov_mode = Measured] seal_instantiate { let r in 0 .. API_BENCHMARK_BATCHES; let hashes = (0..r * API_BENCHMARK_BATCH_SIZE) @@ -1907,7 +1907,7 @@ benchmarks! { } } - #[pov_mode = Ignored] + #[pov_mode = Measured] seal_instantiate_per_transfer_input_salt_kb { let t in 0 .. 1; let i in 0 .. (code::max_pages::() - 1) * 64; @@ -2002,7 +2002,7 @@ benchmarks! { }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) // Only the overhead of calling the function itself with minimal arguments. - #[pov_mode = Ignored] + #[pov_mode = Measured] seal_hash_sha2_256 { let r in 0 .. 1; let instance = Contract::::new(WasmModule::hasher( @@ -2012,7 +2012,7 @@ benchmarks! { }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) // `n`: Input to hash in kilobytes - #[pov_mode = Ignored] + #[pov_mode = Measured] seal_hash_sha2_256_per_kb { let n in 0 .. code::max_pages::() * 64; let instance = Contract::::new(WasmModule::hasher( @@ -2022,7 +2022,7 @@ benchmarks! { }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) // Only the overhead of calling the function itself with minimal arguments. - #[pov_mode = Ignored] + #[pov_mode = Measured] seal_hash_keccak_256 { let r in 0 .. 1; let instance = Contract::::new(WasmModule::hasher( @@ -2032,7 +2032,7 @@ benchmarks! { }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) // `n`: Input to hash in kilobytes - #[pov_mode = Ignored] + #[pov_mode = Measured] seal_hash_keccak_256_per_kb { let n in 0 .. code::max_pages::() * 64; let instance = Contract::::new(WasmModule::hasher( @@ -2042,7 +2042,7 @@ benchmarks! { }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) // Only the overhead of calling the function itself with minimal arguments. - #[pov_mode = Ignored] + #[pov_mode = Measured] seal_hash_blake2_256 { let r in 0 .. 1; let instance = Contract::::new(WasmModule::hasher( @@ -2052,7 +2052,7 @@ benchmarks! { }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) // `n`: Input to hash in kilobytes - #[pov_mode = Ignored] + #[pov_mode = Measured] seal_hash_blake2_256_per_kb { let n in 0 .. code::max_pages::() * 64; let instance = Contract::::new(WasmModule::hasher( @@ -2062,7 +2062,7 @@ benchmarks! { }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) // Only the overhead of calling the function itself with minimal arguments. - #[pov_mode = Ignored] + #[pov_mode = Measured] seal_hash_blake2_128 { let r in 0 .. 1; let instance = Contract::::new(WasmModule::hasher( @@ -2072,7 +2072,7 @@ benchmarks! { }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) // `n`: Input to hash in kilobytes - #[pov_mode = Ignored] + #[pov_mode = Measured] seal_hash_blake2_128_per_kb { let n in 0 .. code::max_pages::() * 64; let instance = Contract::::new(WasmModule::hasher( @@ -2083,7 +2083,7 @@ benchmarks! { // Only calling the function itself with valid arguments. // It generates different private keys and signatures for the message "Hello world". - #[pov_mode = Ignored] + #[pov_mode = Measured] seal_ecdsa_recover { let r in 0 .. 1; @@ -2132,7 +2132,7 @@ benchmarks! { // Only calling the function itself for the list of // generated different ECDSA keys. - #[pov_mode = Ignored] + #[pov_mode = Measured] seal_ecdsa_to_eth_address { let r in 0 .. 1; let key_type = sp_core::crypto::KeyTypeId(*b"code"); @@ -2168,7 +2168,7 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) - #[pov_mode = Ignored] + #[pov_mode = Measured] seal_set_code_hash { let r in 0 .. API_BENCHMARK_BATCHES; let code_hashes = (0..r * API_BENCHMARK_BATCH_SIZE) @@ -2209,7 +2209,7 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) - #[pov_mode = Ignored] + #[pov_mode = Measured] seal_reentrance_count { let r in 0 .. API_BENCHMARK_BATCHES; let code = WasmModule::::from(ModuleDefinition { @@ -2230,7 +2230,7 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) - #[pov_mode = Ignored] + #[pov_mode = Measured] seal_account_reentrance_count { let r in 0 .. API_BENCHMARK_BATCHES; let dummy_code = WasmModule::::dummy_with_bytes(0); @@ -2264,7 +2264,7 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) - #[pov_mode = Ignored] + #[pov_mode = Measured] seal_instantiation_nonce { let r in 0 .. API_BENCHMARK_BATCHES; let code = WasmModule::::from(ModuleDefinition { @@ -3103,7 +3103,7 @@ benchmarks! { // This is no benchmark. It merely exist to have an easy way to pretty print the curently // configured `Schedule` during benchmark development. // It can be outputed using the following command: - // cargo run --manifest-path=bin/node/cli/Cargo.toml --release \ + // cargo run --manifest-path=bin/node/cli/Cargo.toml \ // --features runtime-benchmarks -- benchmark pallet --extra --dev --execution=native \ // -p pallet_contracts -e print_schedule --no-median-slopes --no-min-squares #[extra] @@ -3111,17 +3111,15 @@ benchmarks! { print_schedule { #[cfg(feature = "std")] { - let weight_per_key = T::WeightInfo::on_initialize_per_trie_key(1) - - T::WeightInfo::on_initialize_per_trie_key(0); - let weight_per_queue_item = T::WeightInfo::on_initialize_per_queue_item(1) - - T::WeightInfo::on_initialize_per_queue_item(0); let weight_limit = T::DeletionWeightLimit::get(); - let queue_depth: u64 = T::DeletionQueueDepth::get().into(); + let max_queue_depth = T::DeletionQueueDepth::get() as usize; + let empty_queue_throughput = Storage::::deletion_budget(0, weight_limit); + let full_queue_throughput = Storage::::deletion_budget(max_queue_depth, weight_limit); println!("{:#?}", Schedule::::default()); println!("###############################################"); + println!("Lazy deletion weight per key: {}", empty_queue_throughput.0); println!("Lazy deletion throughput per block (empty queue, full queue): {}, {}", - weight_limit / weight_per_key.ref_time(), - (weight_limit - weight_per_queue_item * queue_depth) / weight_per_key.ref_time(), + empty_queue_throughput.1, full_queue_throughput.1, ); } #[cfg(not(feature = "std"))] @@ -3133,7 +3131,7 @@ benchmarks! { // `g` is used to enable gas instrumentation to compare the performance impact of // that instrumentation at runtime. #[extra] - #[pov_mode = Ignored] + #[pov_mode = Measured] ink_erc20_transfer { let g in 0 .. 1; let gas_metering = g != 0; @@ -3172,7 +3170,7 @@ benchmarks! { // `g` is used to enable gas instrumentation to compare the performance impact of // that instrumentation at runtime. #[extra] - #[pov_mode = Ignored] + #[pov_mode = Measured] solang_erc20_transfer { let g in 0 .. 1; let gas_metering = g != 0; diff --git a/frame/contracts/src/schedule.rs b/frame/contracts/src/schedule.rs index 5e4798df147b2..ccfba941e9817 100644 --- a/frame/contracts/src/schedule.rs +++ b/frame/contracts/src/schedule.rs @@ -447,7 +447,7 @@ macro_rules! call_zero { macro_rules! cost_args { ($name:ident, $( $arg: expr ),+) => { - (T::WeightInfo::$name($( $arg ),+).saturating_sub(call_zero!($name, $( $arg ),+))).ref_time() + (T::WeightInfo::$name($( $arg ),+).saturating_sub(call_zero!($name, $( $arg ),+))) } } @@ -459,7 +459,7 @@ macro_rules! cost_batched_args { macro_rules! cost_instr_no_params_with_batch_size { ($name:ident, $batch_size:expr) => { - (cost_args!($name, 1) / u64::from($batch_size)) as u32 + (cost_args!($name, 1).ref_time() / u64::from($batch_size)) as u32 }; } @@ -514,12 +514,6 @@ macro_rules! cost_byte_batched { }; } -macro_rules! to_weight { - ($ref_time:expr $(, $proof_size:expr )?) => { - Weight::from_ref_time($ref_time)$(.set_proof_size($proof_size))? - }; -} - impl Default for Limits { fn default() -> Self { Self { @@ -554,8 +548,8 @@ impl Default for InstructionWeights { br_table_per_entry: cost_instr!(instr_br_table_per_entry, 0), 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), + call_indirect_per_param: cost_instr!(instr_call_indirect_per_param, 0), + call_per_local: cost_instr!(instr_call_per_local, 0), local_get: cost_instr!(instr_local_get, 1), local_set: cost_instr!(instr_local_set, 1), local_tee: cost_instr!(instr_local_tee, 2), @@ -601,116 +595,91 @@ impl Default for InstructionWeights { } impl Default for HostFnWeights { - /// PoV should contain all trie nodes that are read during state transition (i.e. block - /// production). Hence we need to charge the `proof_size` weight for every host function which - /// reads storage, namely: - /// - get_storage, - /// - take_storage, - /// - contains_storage, - /// - clear_storage, - /// - set_storage. - /// - /// The last two functions write to storage, but they also do read storage in order to return - /// the size of the pre-existed value. Till we have PoV benchmarks implemented, we approximate - /// `proof_size` as being equal to the size of storage read. fn default() -> Self { Self { - caller: to_weight!(cost_batched!(seal_caller)), - is_contract: to_weight!(cost_batched!(seal_is_contract)), - code_hash: to_weight!(cost_batched!(seal_code_hash)), - own_code_hash: to_weight!(cost_batched!(seal_own_code_hash)), - caller_is_origin: to_weight!(cost_batched!(seal_caller_is_origin)), - address: to_weight!(cost_batched!(seal_address)), - gas_left: to_weight!(cost_batched!(seal_gas_left)), - balance: to_weight!(cost_batched!(seal_balance)), - value_transferred: to_weight!(cost_batched!(seal_value_transferred)), - minimum_balance: to_weight!(cost_batched!(seal_minimum_balance)), - block_number: to_weight!(cost_batched!(seal_block_number)), - now: to_weight!(cost_batched!(seal_now)), - weight_to_fee: to_weight!(cost_batched!(seal_weight_to_fee)), - gas: to_weight!(cost_batched!(seal_gas)), - input: to_weight!(cost_batched!(seal_input)), - input_per_byte: to_weight!(cost_byte_batched!(seal_input_per_kb)), - r#return: to_weight!(cost!(seal_return)), - return_per_byte: to_weight!(cost_byte!(seal_return_per_kb)), - terminate: to_weight!(cost!(seal_terminate)), - random: to_weight!(cost_batched!(seal_random)), - deposit_event: to_weight!(cost_batched!(seal_deposit_event)), - deposit_event_per_topic: to_weight!(cost_batched_args!( - seal_deposit_event_per_topic_and_kb, - 1, - 0 - )), - deposit_event_per_byte: to_weight!(cost_byte_batched_args!( + 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), + balance: cost_batched!(seal_balance), + value_transferred: cost_batched!(seal_value_transferred), + minimum_balance: cost_batched!(seal_minimum_balance), + block_number: cost_batched!(seal_block_number), + now: cost_batched!(seal_now), + weight_to_fee: cost_batched!(seal_weight_to_fee), + // Manually remove proof size from basic block cost. + // + // Due to imperfect benchmarking some host functions incur a small + // amount of proof size. Usually this is ok. However, charging a basic block is such + // a frequent operation that this would be a vast overestimation. + gas: cost_batched!(seal_gas).set_proof_size(0), + input: cost_batched!(seal_input), + input_per_byte: cost_byte_batched!(seal_input_per_kb), + r#return: cost!(seal_return), + return_per_byte: cost_byte!(seal_return_per_kb), + terminate: cost!(seal_terminate), + random: cost_batched!(seal_random), + deposit_event: cost_batched!(seal_deposit_event), + deposit_event_per_topic: cost_batched_args!(seal_deposit_event_per_topic_and_kb, 1, 0), + deposit_event_per_byte: cost_byte_batched_args!( seal_deposit_event_per_topic_and_kb, 0, 1 - )), - debug_message: to_weight!(cost_batched!(seal_debug_message)), - debug_message_per_byte: to_weight!(cost_byte!(seal_debug_message_per_kb)), - set_storage: to_weight!(cost_batched!(seal_set_storage), 1024u64), - set_code_hash: to_weight!(cost_batched!(seal_set_code_hash)), - set_storage_per_new_byte: to_weight!(cost_byte_batched!(seal_set_storage_per_new_kb)), - set_storage_per_old_byte: to_weight!( - cost_byte_batched!(seal_set_storage_per_old_kb), - 1u64 - ), - clear_storage: to_weight!(cost_batched!(seal_clear_storage), 1024u64), - clear_storage_per_byte: to_weight!(cost_byte_batched!(seal_clear_storage_per_kb), 1u64), - contains_storage: to_weight!(cost_batched!(seal_contains_storage), 1024u64), - contains_storage_per_byte: to_weight!( - cost_byte_batched!(seal_contains_storage_per_kb), - 1u64 ), - get_storage: to_weight!(cost_batched!(seal_get_storage), 1024u64), - get_storage_per_byte: to_weight!(cost_byte_batched!(seal_get_storage_per_kb), 1u64), - take_storage: to_weight!(cost_batched!(seal_take_storage), 1024u64), - take_storage_per_byte: to_weight!(cost_byte_batched!(seal_take_storage_per_kb), 1u64), - transfer: to_weight!(cost_batched!(seal_transfer)), - call: to_weight!(cost_batched!(seal_call)), - delegate_call: to_weight!(cost_batched!(seal_delegate_call)), - call_transfer_surcharge: to_weight!(cost_batched_args!( - seal_call_per_transfer_clone_kb, - 1, - 0 - )), - call_per_cloned_byte: to_weight!(cost_batched_args!( - seal_call_per_transfer_clone_kb, - 0, - 1 - )), - instantiate: to_weight!(cost_batched!(seal_instantiate)), - instantiate_transfer_surcharge: to_weight!(cost_byte_batched_args!( + debug_message: cost_batched!(seal_debug_message), + debug_message_per_byte: cost_byte!(seal_debug_message_per_kb), + 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), + 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), + 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_clone_kb, 1, 0), + call_per_cloned_byte: cost_byte_batched_args!(seal_call_per_transfer_clone_kb, 0, 1), + instantiate: cost_batched!(seal_instantiate), + instantiate_transfer_surcharge: cost_batched_args!( seal_instantiate_per_transfer_input_salt_kb, 1, 0, 0 - )), - instantiate_per_input_byte: to_weight!(cost_byte_batched_args!( + ), + instantiate_per_input_byte: cost_byte_batched_args!( seal_instantiate_per_transfer_input_salt_kb, 0, 1, 0 - )), - instantiate_per_salt_byte: to_weight!(cost_byte_batched_args!( + ), + instantiate_per_salt_byte: cost_byte_batched_args!( seal_instantiate_per_transfer_input_salt_kb, 0, 0, 1 - )), - hash_sha2_256: to_weight!(cost_batched!(seal_hash_sha2_256)), - hash_sha2_256_per_byte: to_weight!(cost_byte_batched!(seal_hash_sha2_256_per_kb)), - hash_keccak_256: to_weight!(cost_batched!(seal_hash_keccak_256)), - hash_keccak_256_per_byte: to_weight!(cost_byte_batched!(seal_hash_keccak_256_per_kb)), - hash_blake2_256: to_weight!(cost_batched!(seal_hash_blake2_256)), - hash_blake2_256_per_byte: to_weight!(cost_byte_batched!(seal_hash_blake2_256_per_kb)), - hash_blake2_128: to_weight!(cost_batched!(seal_hash_blake2_128)), - hash_blake2_128_per_byte: to_weight!(cost_byte_batched!(seal_hash_blake2_128_per_kb)), - ecdsa_recover: to_weight!(cost_batched!(seal_ecdsa_recover)), - ecdsa_to_eth_address: to_weight!(cost_batched!(seal_ecdsa_to_eth_address)), - reentrance_count: to_weight!(cost_batched!(seal_reentrance_count)), - account_reentrance_count: to_weight!(cost_batched!(seal_account_reentrance_count)), - instantiation_nonce: to_weight!(cost_batched!(seal_instantiation_nonce)), + ), + hash_sha2_256: cost_batched!(seal_hash_sha2_256), + hash_sha2_256_per_byte: cost_byte_batched!(seal_hash_sha2_256_per_kb), + hash_keccak_256: cost_batched!(seal_hash_keccak_256), + hash_keccak_256_per_byte: cost_byte_batched!(seal_hash_keccak_256_per_kb), + hash_blake2_256: cost_batched!(seal_hash_blake2_256), + hash_blake2_256_per_byte: cost_byte_batched!(seal_hash_blake2_256_per_kb), + 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), + 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/storage.rs b/frame/contracts/src/storage.rs index d40cc755c315e..bf030a2bd8c81 100644 --- a/frame/contracts/src/storage.rs +++ b/frame/contracts/src/storage.rs @@ -245,13 +245,12 @@ impl Storage { /// Calculates the weight that is necessary to remove one key from the trie and how many /// 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) { + pub fn deletion_budget(queue_len: usize, weight_limit: Weight) -> (Weight, u32) { 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)) - .ref_time(); + 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 u64); // `weight_per_key` being zero makes no sense and would constitute a failure to @@ -259,9 +258,8 @@ impl Storage { let key_budget = weight_limit .saturating_sub(base_weight) .saturating_sub(decoding_weight) - .checked_div(weight_per_key) - .unwrap_or(Weight::zero()) - .ref_time() as u32; + .checked_div_per_component(&weight_per_key) + .unwrap_or(0) as u32; (weight_per_key, key_budget) } @@ -306,10 +304,7 @@ impl Storage { } >::put(queue); - let ref_time_weight = weight_limit - .ref_time() - .saturating_sub(weight_per_key.saturating_mul(u64::from(remaining_key_budget))); - Weight::from_ref_time(ref_time_weight) + weight_limit.saturating_sub(weight_per_key.saturating_mul(u64::from(remaining_key_budget))) } /// 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 958cbf772dba5..cab426ad132cb 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -383,7 +383,7 @@ impl Contains for TestFilter { } parameter_types! { - pub const DeletionWeightLimit: Weight = Weight::from_ref_time(500_000_000_000); + pub const DeletionWeightLimit: Weight = GAS_LIMIT; pub static UnstableInterface: bool = true; } @@ -416,7 +416,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_parts(100_000_000_000, 512 * 1024); +pub const GAS_LIMIT: Weight = Weight::from_parts(100_000_000_000, 3 * 1024 * 1024); pub struct ExtBuilder { existential_deposit: u64, @@ -2322,7 +2322,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 = Weight::from_ref_time(5_000_000_000); + let weight_limit = Weight::from_parts(5_000_000_000, 100 * 1024); let mut ext = ExtBuilder::default().existential_deposit(50).build(); let (trie, vals, weight_per_key) = ext.execute_with(|| { @@ -2396,7 +2396,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::from_ref_time(weight_per_key)); + assert_eq!(weight_used, weight_limit - weight_per_key); // All the keys are removed for val in vals { diff --git a/frame/contracts/src/wasm/code_cache.rs b/frame/contracts/src/wasm/code_cache.rs index 410d26921543d..385ed54ccb410 100644 --- a/frame/contracts/src/wasm/code_cache.rs +++ b/frame/contracts/src/wasm/code_cache.rs @@ -50,53 +50,61 @@ use sp_std::vec; /// under the specified `code_hash`. pub fn store(mut module: PrefabWasmModule, instantiated: bool) -> DispatchResult { let code_hash = sp_std::mem::take(&mut module.code_hash); - >::mutate(&code_hash, |existing| match existing { - 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 => { - let orig_code = module.original_code.take().expect( - " + >::mutate(&code_hash, |owner_info| { + match owner_info { + // Instantiate existing contract. + // + // No need to update the `CodeStorage` as any re-instrumentation eagerly saves + // the re-instrumented code. + Some(owner_info) if instantiated => { + 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(()) + }, + // Re-upload existing contract without executing it. + // + // We are careful here to just overwrite the code to not include it into the PoV. + // We do this because the uploaded code was instrumented with the latest schedule + // and hence we persist those changes. Otherwise the next execution will pay again + // for the instrumentation. + Some(_) => { + >::insert(&code_hash, module); + Ok(()) + }, + // Upload a new contract. + // + // We need to write all data structures and collect the deposit. + None => { + 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. + ); + let mut new_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(vec![code_hash], Event::CodeStored { code_hash }); - Ok(()) - }, + ); + // 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(&new_owner_info.owner, new_owner_info.deposit) + .map_err(|_| >::StorageDepositNotEnoughFunds)?; + new_owner_info.refcount = if instantiated { 1 } else { 0 }; + >::insert(&code_hash, orig_code); + >::insert(&code_hash, module); + *owner_info = Some(new_owner_info); + >::deposit_event(vec![code_hash], Event::CodeStored { code_hash }); + Ok(()) + }, + } }) } @@ -162,15 +170,16 @@ pub fn load( 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)); + let instrumented_code_len = prefab_module.code.len() as u32; + gas_meter.adjust_gas(charged, CodeToken::Load(instrumented_code_len)); 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. - 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)); + let charged = gas_meter.charge(CodeToken::Reinstrument(instrumented_code_len))?; + let orig_code_len = reinstrument(&mut prefab_module, schedule)?; + gas_meter.adjust_gas(charged, CodeToken::Reinstrument(orig_code_len)); } Ok(prefab_module) @@ -224,8 +233,7 @@ impl Token for CodeToken { 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)) - .set_proof_size(len.into()), + .saturating_sub(T::WeightInfo::call_with_code_per_byte(0)), } } } diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index 3ca7326187a5b..d25499641c5d2 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -42,7 +42,7 @@ pub use crate::wasm::{ use crate::{ exec::{ExecResult, Executable, ExportedFunction, Ext}, gas::GasMeter, - AccountIdOf, BalanceOf, CodeHash, CodeStorage, CodeVec, Config, Error, RelaxedCodeVec, + AccountIdOf, BalanceOf, CodeHash, CodeVec, Config, Error, OwnerInfoOf, RelaxedCodeVec, Schedule, }; use codec::{Decode, Encode, MaxEncodedLen}; @@ -191,7 +191,7 @@ impl PrefabWasmModule { /// 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) { + if >::contains_key(&self.code_hash) { 0u32.into() } else { // Only already in-storage contracts have their `owner_info` set to `None`. diff --git a/frame/contracts/src/weights.rs b/frame/contracts/src/weights.rs index 50aa30e89e58b..057a9257d4268 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: 2023-02-14, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-02-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -173,772 +173,796 @@ pub trait WeightInfo { pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { /// Storage: Contracts DeletionQueue (r:1 w:0) - /// Proof: Contracts DeletionQueue (max_values: Some(1), max_size: Some(16642), added: 17137, mode: Ignored) + /// Proof: Contracts DeletionQueue (max_values: Some(1), max_size: Some(16642), added: 17137, mode: Measured) fn on_process_deletion_queue_batch() -> Weight { // Proof Size summary in bytes: // Measured: `109` - // Estimated: `0` - // Minimum execution time: 2_564 nanoseconds. - Weight::from_ref_time(2_722_000) - .saturating_add(Weight::from_proof_size(0)) + // Estimated: `604` + // Minimum execution time: 2_507 nanoseconds. + Weight::from_ref_time(2_650_000) + .saturating_add(Weight::from_proof_size(604)) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: Skipped Metadata (r:0 w:0) - /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `k` is `[0, 1024]`. fn on_initialize_per_trie_key(k: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `481 + k * (69 ±0)` - // Estimated: `0` - // Minimum execution time: 10_292 nanoseconds. - Weight::from_ref_time(7_474_496) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 901 - .saturating_add(Weight::from_ref_time(956_864).saturating_mul(k.into())) + // Estimated: `471 + k * (70 ±0)` + // Minimum execution time: 9_953 nanoseconds. + Weight::from_ref_time(6_467_352) + .saturating_add(Weight::from_proof_size(471)) + // Standard Error: 1_074 + .saturating_add(Weight::from_ref_time(943_946).saturating_mul(k.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(k.into()))) + .saturating_add(Weight::from_proof_size(70).saturating_mul(k.into())) } /// Storage: Contracts DeletionQueue (r:1 w:1) - /// Proof: Contracts DeletionQueue (max_values: Some(1), max_size: Some(16642), added: 17137, mode: Ignored) + /// Proof: Contracts DeletionQueue (max_values: Some(1), max_size: Some(16642), added: 17137, mode: Measured) /// The range of component `q` is `[0, 128]`. fn on_initialize_per_queue_item(q: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `281 + q * (33 ±0)` - // Estimated: `0` - // Minimum execution time: 2_620 nanoseconds. - Weight::from_ref_time(10_288_873) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 3_073 - .saturating_add(Weight::from_ref_time(1_148_167).saturating_mul(q.into())) + // Estimated: `763 + q * (33 ±0)` + // Minimum execution time: 2_545 nanoseconds. + Weight::from_ref_time(10_080_106) + .saturating_add(Weight::from_proof_size(763)) + // Standard Error: 2_929 + .saturating_add(Weight::from_ref_time(1_078_265).saturating_mul(q.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) + .saturating_add(Weight::from_proof_size(33).saturating_mul(q.into())) } /// Storage: Contracts PristineCode (r:1 w:0) - /// Proof: Contracts PristineCode (max_values: None, max_size: Some(125988), added: 128463, mode: Ignored) + /// Proof: Contracts PristineCode (max_values: None, max_size: Some(125988), added: 128463, mode: Measured) /// Storage: Contracts CodeStorage (r:0 w:1) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// The range of component `c` is `[0, 61717]`. fn reinstrument(c: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `270 + c * (1 ±0)` - // Estimated: `0` - // Minimum execution time: 28_004 nanoseconds. - Weight::from_ref_time(26_706_943) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 67 - .saturating_add(Weight::from_ref_time(51_603).saturating_mul(c.into())) + // Estimated: `3025 + c * (2 ±0)` + // Minimum execution time: 34_613 nanoseconds. + Weight::from_ref_time(27_355_774) + .saturating_add(Weight::from_proof_size(3025)) + // Standard Error: 81 + .saturating_add(Weight::from_ref_time(51_954).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) + .saturating_add(Weight::from_proof_size(2).saturating_mul(c.into())) } /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `c` is `[0, 125952]`. fn call_with_code_per_byte(c: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `771` - // Estimated: `0` - // Minimum execution time: 295_799 nanoseconds. - Weight::from_ref_time(308_660_753) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 20 - .saturating_add(Weight::from_ref_time(32_458).saturating_mul(c.into())) + // Estimated: `16780 + c * (5 ±0)` + // Minimum execution time: 386_104 nanoseconds. + Weight::from_ref_time(396_718_823) + .saturating_add(Weight::from_proof_size(16780)) + // Standard Error: 27 + .saturating_add(Weight::from_ref_time(31_370).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) + .saturating_add(Weight::from_proof_size(5).saturating_mul(c.into())) } - /// Storage: Contracts CodeStorage (r:1 w:1) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Contracts OwnerInfoOf (r:1 w:1) + /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Measured) /// Storage: Contracts Nonce (r:1 w:1) - /// Proof: Contracts Nonce (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Contracts Nonce (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: System EventTopics (r:3 w:3) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) + /// Storage: Contracts CodeStorage (r:0 w:1) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Contracts PristineCode (r:0 w:1) - /// Proof: Contracts PristineCode (max_values: None, max_size: Some(125988), added: 128463, mode: Ignored) - /// Storage: Contracts OwnerInfoOf (r:0 w:1) - /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Ignored) + /// Proof: Contracts PristineCode (max_values: None, max_size: Some(125988), added: 128463, mode: Measured) /// The range of component `c` is `[0, 61717]`. /// The range of component `i` is `[0, 1048576]`. /// The range of component `s` is `[0, 1048576]`. fn instantiate_with_code(c: u32, i: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `257` - // Estimated: `0` - // Minimum execution time: 3_754_887 nanoseconds. - Weight::from_ref_time(657_695_827) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 283 - .saturating_add(Weight::from_ref_time(94_808).saturating_mul(c.into())) + // Estimated: `17752` + // Minimum execution time: 3_786_500 nanoseconds. + Weight::from_ref_time(672_511_565) + .saturating_add(Weight::from_proof_size(17752)) + // Standard Error: 281 + .saturating_add(Weight::from_ref_time(94_538).saturating_mul(c.into())) // Standard Error: 16 - .saturating_add(Weight::from_ref_time(1_357).saturating_mul(i.into())) + .saturating_add(Weight::from_ref_time(1_364).saturating_mul(i.into())) // Standard Error: 16 - .saturating_add(Weight::from_ref_time(1_756).saturating_mul(s.into())) + .saturating_add(Weight::from_ref_time(1_768).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(9_u64)) } - /// Storage: Contracts CodeStorage (r:1 w:1) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Contracts Nonce (r:1 w:1) - /// Proof: Contracts Nonce (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Contracts Nonce (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts OwnerInfoOf (r:1 w:1) - /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Ignored) + /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `i` is `[0, 1048576]`. /// The range of component `s` is `[0, 1048576]`. fn instantiate(i: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `533` - // Estimated: `0` - // Minimum execution time: 1_961_131 nanoseconds. - Weight::from_ref_time(208_539_564) - .saturating_add(Weight::from_proof_size(0)) + // Estimated: `19543` + // Minimum execution time: 1_927_365 nanoseconds. + Weight::from_ref_time(189_843_928) + .saturating_add(Weight::from_proof_size(19543)) // Standard Error: 8 - .saturating_add(Weight::from_ref_time(1_688).saturating_mul(i.into())) + .saturating_add(Weight::from_ref_time(1_677).saturating_mul(i.into())) // Standard Error: 8 - .saturating_add(Weight::from_ref_time(1_802).saturating_mul(s.into())) + .saturating_add(Weight::from_ref_time(1_803).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) - .saturating_add(T::DbWeight::get().writes(7_u64)) + .saturating_add(T::DbWeight::get().writes(6_u64)) } /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) fn call() -> Weight { // Proof Size summary in bytes: // Measured: `823` - // Estimated: `0` - // Minimum execution time: 148_138 nanoseconds. - Weight::from_ref_time(148_862_000) - .saturating_add(Weight::from_proof_size(0)) + // Estimated: `16985` + // Minimum execution time: 146_354 nanoseconds. + Weight::from_ref_time(147_693_000) + .saturating_add(Weight::from_proof_size(16985)) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } - /// Storage: Contracts CodeStorage (r:1 w:1) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Contracts OwnerInfoOf (r:1 w:1) + /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Measured) /// Storage: System EventTopics (r:1 w:1) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) + /// Storage: Contracts CodeStorage (r:0 w:1) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Contracts PristineCode (r:0 w:1) - /// Proof: Contracts PristineCode (max_values: None, max_size: Some(125988), added: 128463, mode: Ignored) - /// Storage: Contracts OwnerInfoOf (r:0 w:1) - /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Ignored) + /// Proof: Contracts PristineCode (max_values: None, max_size: Some(125988), added: 128463, mode: Measured) /// The range of component `c` is `[0, 61717]`. fn upload_code(c: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `109` - // Estimated: `0` - // Minimum execution time: 293_444 nanoseconds. - Weight::from_ref_time(293_242_988) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 156 - .saturating_add(Weight::from_ref_time(97_476).saturating_mul(c.into())) + // Estimated: `5386` + // Minimum execution time: 388_107 nanoseconds. + Weight::from_ref_time(383_172_702) + .saturating_add(Weight::from_proof_size(5386)) + // Standard Error: 73 + .saturating_add(Weight::from_ref_time(95_037).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } /// Storage: Contracts OwnerInfoOf (r:1 w:1) - /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Ignored) + /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Measured) /// Storage: System EventTopics (r:1 w:1) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// Storage: Contracts CodeStorage (r:0 w:1) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Contracts PristineCode (r:0 w:1) - /// Proof: Contracts PristineCode (max_values: None, max_size: Some(125988), added: 128463, mode: Ignored) + /// Proof: Contracts PristineCode (max_values: None, max_size: Some(125988), added: 128463, mode: Measured) fn remove_code() -> Weight { // Proof Size summary in bytes: // Measured: `287` - // Estimated: `0` - // Minimum execution time: 26_802 nanoseconds. - Weight::from_ref_time(27_121_000) - .saturating_add(Weight::from_proof_size(0)) + // Estimated: `6098` + // Minimum execution time: 26_278 nanoseconds. + Weight::from_ref_time(26_682_000) + .saturating_add(Weight::from_proof_size(6098)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts OwnerInfoOf (r:2 w:2) - /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Ignored) + /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Measured) /// Storage: System EventTopics (r:3 w:3) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) fn set_code() -> Weight { // Proof Size summary in bytes: // Measured: `634` - // Estimated: `0` - // Minimum execution time: 31_079 nanoseconds. - Weight::from_ref_time(31_541_000) - .saturating_add(Weight::from_proof_size(0)) + // Estimated: `16752` + // Minimum execution time: 30_223 nanoseconds. + Weight::from_ref_time(30_737_000) + .saturating_add(Weight::from_proof_size(16752)) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 20]`. fn seal_caller(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `845 + r * (480 ±0)` - // Estimated: `0` - // Minimum execution time: 284_877 nanoseconds. - Weight::from_ref_time(290_043_606) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 22_094 - .saturating_add(Weight::from_ref_time(18_094_219).saturating_mul(r.into())) + // Estimated: `17120 + r * (2400 ±0)` + // Minimum execution time: 374_780 nanoseconds. + Weight::from_ref_time(379_468_453) + .saturating_add(Weight::from_proof_size(17120)) + // Standard Error: 45_809 + .saturating_add(Weight::from_ref_time(17_553_577).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(2400).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1601 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 20]`. fn seal_is_contract(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `882 + r * (19218 ±0)` - // Estimated: `0` - // Minimum execution time: 283_956 nanoseconds. - Weight::from_ref_time(129_690_397) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 531_270 - .saturating_add(Weight::from_ref_time(264_082_418).saturating_mul(r.into())) + // Estimated: `17110 + r * (294100 ±0)` + // Minimum execution time: 374_399 nanoseconds. + Weight::from_ref_time(228_569_211) + .saturating_add(Weight::from_proof_size(17110)) + // Standard Error: 492_562 + .saturating_add(Weight::from_ref_time(251_682_897).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(294100).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1601 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 20]`. fn seal_code_hash(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `889 + r * (19539 ±0)` - // Estimated: `0` - // Minimum execution time: 287_077 nanoseconds. - Weight::from_ref_time(148_155_166) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 466_496 - .saturating_add(Weight::from_ref_time(306_625_930).saturating_mul(r.into())) + // Estimated: `17170 + r * (295700 ±0)` + // Minimum execution time: 375_980 nanoseconds. + Weight::from_ref_time(232_604_331) + .saturating_add(Weight::from_proof_size(17170)) + // Standard Error: 491_912 + .saturating_add(Weight::from_ref_time(299_479_335).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(295700).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 20]`. fn seal_own_code_hash(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `852 + r * (480 ±0)` - // Estimated: `0` - // Minimum execution time: 286_459 nanoseconds. - Weight::from_ref_time(292_826_594) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 27_808 - .saturating_add(Weight::from_ref_time(22_401_931).saturating_mul(r.into())) + // Estimated: `17155 + r * (2400 ±0)` + // Minimum execution time: 375_075 nanoseconds. + Weight::from_ref_time(381_217_372) + .saturating_add(Weight::from_proof_size(17155)) + // Standard Error: 63_950 + .saturating_add(Weight::from_ref_time(21_872_316).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(2400).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 20]`. fn seal_caller_is_origin(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `842 + r * (240 ±0)` - // Estimated: `0` - // Minimum execution time: 284_330 nanoseconds. - Weight::from_ref_time(289_069_701) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 13_666 - .saturating_add(Weight::from_ref_time(11_157_859).saturating_mul(r.into())) + // Estimated: `17080 + r * (1200 ±0)` + // Minimum execution time: 373_260 nanoseconds. + Weight::from_ref_time(377_987_666) + .saturating_add(Weight::from_proof_size(17080)) + // Standard Error: 35_603 + .saturating_add(Weight::from_ref_time(11_274_165).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(1200).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 20]`. fn seal_address(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `846 + r * (480 ±0)` - // Estimated: `0` - // Minimum execution time: 284_506 nanoseconds. - Weight::from_ref_time(290_155_141) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 22_944 - .saturating_add(Weight::from_ref_time(17_992_627).saturating_mul(r.into())) + // Estimated: `17100 + r * (2400 ±0)` + // Minimum execution time: 374_605 nanoseconds. + Weight::from_ref_time(379_395_443) + .saturating_add(Weight::from_proof_size(17100)) + // Standard Error: 49_646 + .saturating_add(Weight::from_ref_time(17_487_585).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(2400).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 20]`. fn seal_gas_left(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `847 + r * (480 ±0)` - // Estimated: `0` - // Minimum execution time: 284_177 nanoseconds. - Weight::from_ref_time(289_314_787) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 24_552 - .saturating_add(Weight::from_ref_time(17_754_919).saturating_mul(r.into())) + // Estimated: `17105 + r * (2400 ±0)` + // Minimum execution time: 374_620 nanoseconds. + Weight::from_ref_time(379_623_792) + .saturating_add(Weight::from_proof_size(17105)) + // Standard Error: 49_990 + .saturating_add(Weight::from_ref_time(17_226_706).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(2400).saturating_mul(r.into())) } /// Storage: System Account (r:2 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 20]`. fn seal_balance(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `1017 + r * (480 ±0)` - // Estimated: `0` - // Minimum execution time: 284_096 nanoseconds. - Weight::from_ref_time(293_655_130) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 56_379 - .saturating_add(Weight::from_ref_time(95_688_575).saturating_mul(r.into())) + // Estimated: `19673 + r * (2456 ±4)` + // Minimum execution time: 374_002 nanoseconds. + Weight::from_ref_time(384_615_649) + .saturating_add(Weight::from_proof_size(19673)) + // Standard Error: 85_633 + .saturating_add(Weight::from_ref_time(95_227_118).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(2456).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 20]`. fn seal_value_transferred(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `856 + r * (480 ±0)` - // Estimated: `0` - // Minimum execution time: 285_967 nanoseconds. - Weight::from_ref_time(288_043_137) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 83_838 - .saturating_add(Weight::from_ref_time(18_256_709).saturating_mul(r.into())) + // Estimated: `17200 + r * (2400 ±0)` + // Minimum execution time: 375_307 nanoseconds. + Weight::from_ref_time(378_389_705) + .saturating_add(Weight::from_proof_size(17200)) + // Standard Error: 42_265 + .saturating_add(Weight::from_ref_time(17_316_680).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(2400).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 20]`. fn seal_minimum_balance(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `854 + r * (480 ±0)` - // Estimated: `0` - // Minimum execution time: 284_060 nanoseconds. - Weight::from_ref_time(290_577_678) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 26_131 - .saturating_add(Weight::from_ref_time(17_560_562).saturating_mul(r.into())) + // Estimated: `17140 + r * (2400 ±0)` + // Minimum execution time: 374_878 nanoseconds. + Weight::from_ref_time(379_364_066) + .saturating_add(Weight::from_proof_size(17140)) + // Standard Error: 49_158 + .saturating_add(Weight::from_ref_time(17_111_145).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(2400).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 20]`. fn seal_block_number(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `851 + r * (480 ±0)` - // Estimated: `0` - // Minimum execution time: 286_068 nanoseconds. - Weight::from_ref_time(290_026_137) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 34_787 - .saturating_add(Weight::from_ref_time(17_597_404).saturating_mul(r.into())) + // Estimated: `17125 + r * (2400 ±0)` + // Minimum execution time: 374_981 nanoseconds. + Weight::from_ref_time(381_539_022) + .saturating_add(Weight::from_proof_size(17125)) + // Standard Error: 61_419 + .saturating_add(Weight::from_ref_time(17_062_381).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(2400).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 20]`. fn seal_now(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `842 + r * (480 ±0)` - // Estimated: `0` - // Minimum execution time: 285_082 nanoseconds. - Weight::from_ref_time(290_487_103) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 22_743 - .saturating_add(Weight::from_ref_time(17_506_771).saturating_mul(r.into())) + // Estimated: `17100 + r * (2400 ±0)` + // Minimum execution time: 374_798 nanoseconds. + Weight::from_ref_time(372_659_915) + .saturating_add(Weight::from_proof_size(17100)) + // Standard Error: 151_499 + .saturating_add(Weight::from_ref_time(18_192_683).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(2400).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) - /// Proof: TransactionPayment NextFeeMultiplier (max_values: Some(1), max_size: Some(16), added: 511, mode: Ignored) + /// Proof: TransactionPayment NextFeeMultiplier (max_values: Some(1), max_size: Some(16), added: 511, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 20]`. fn seal_weight_to_fee(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `919 + r * (800 ±0)` - // Estimated: `0` - // Minimum execution time: 285_309 nanoseconds. - Weight::from_ref_time(296_735_365) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 49_300 - .saturating_add(Weight::from_ref_time(87_678_979).saturating_mul(r.into())) + // Estimated: `18835 + r * (4805 ±0)` + // Minimum execution time: 374_841 nanoseconds. + Weight::from_ref_time(385_475_889) + .saturating_add(Weight::from_proof_size(18835)) + // Standard Error: 106_207 + .saturating_add(Weight::from_ref_time(88_099_987).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(4805).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 20]`. fn seal_gas(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `809 + r * (320 ±0)` - // Estimated: `0` - // Minimum execution time: 136_110 nanoseconds. - Weight::from_ref_time(139_800_659) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 9_674 - .saturating_add(Weight::from_ref_time(8_302_834).saturating_mul(r.into())) + // Estimated: `16955 + r * (1600 ±0)` + // Minimum execution time: 134_436 nanoseconds. + Weight::from_ref_time(137_789_498) + .saturating_add(Weight::from_proof_size(16955)) + // Standard Error: 10_622 + .saturating_add(Weight::from_ref_time(8_144_024).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(1600).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 20]`. fn seal_input(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `844 + r * (480 ±0)` - // Estimated: `0` - // Minimum execution time: 285_238 nanoseconds. - Weight::from_ref_time(289_723_839) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 19_531 - .saturating_add(Weight::from_ref_time(15_590_085).saturating_mul(r.into())) + // Estimated: `17085 + r * (2400 ±0)` + // Minimum execution time: 374_480 nanoseconds. + Weight::from_ref_time(379_723_392) + .saturating_add(Weight::from_proof_size(17085)) + // Standard Error: 50_240 + .saturating_add(Weight::from_ref_time(15_358_041).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(2400).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `n` is `[0, 1024]`. fn seal_input_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `1324` - // Estimated: `0` - // Minimum execution time: 303_189 nanoseconds. - Weight::from_ref_time(323_374_503) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 2_060 - .saturating_add(Weight::from_ref_time(9_799_357).saturating_mul(n.into())) + // Estimated: `19490` + // Minimum execution time: 392_282 nanoseconds. + Weight::from_ref_time(418_943_323) + .saturating_add(Weight::from_proof_size(19490)) + // Standard Error: 4_673 + .saturating_add(Weight::from_ref_time(9_664_301).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 1]`. fn seal_return(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `832 + r * (45 ±0)` - // Estimated: `0` - // Minimum execution time: 280_736 nanoseconds. - Weight::from_ref_time(285_027_920) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 222_526 - .saturating_add(Weight::from_ref_time(1_814_579).saturating_mul(r.into())) + // Estimated: `17030 + r * (225 ±0)` + // Minimum execution time: 372_207 nanoseconds. + Weight::from_ref_time(376_232_444) + .saturating_add(Weight::from_proof_size(17030)) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(225).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `n` is `[0, 1024]`. fn seal_return_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `842` - // Estimated: `0` - // Minimum execution time: 285_559 nanoseconds. - Weight::from_ref_time(290_522_234) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 2_578 - .saturating_add(Weight::from_ref_time(195_134).saturating_mul(n.into())) + // Estimated: `17125` + // Minimum execution time: 374_743 nanoseconds. + Weight::from_ref_time(377_365_053) + .saturating_add(Weight::from_proof_size(17125)) + // Standard Error: 1_073 + .saturating_add(Weight::from_ref_time(231_251).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: System Account (r:3 w:3) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: Contracts DeletionQueue (r:1 w:1) - /// Proof: Contracts DeletionQueue (max_values: Some(1), max_size: Some(16642), added: 17137, mode: Ignored) + /// Proof: Contracts DeletionQueue (max_values: Some(1), max_size: Some(16642), added: 17137, mode: Measured) /// Storage: Contracts OwnerInfoOf (r:1 w:1) - /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Ignored) + /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Measured) /// Storage: System EventTopics (r:3 w:3) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 1]`. fn seal_terminate(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `874 + r * (280 ±0)` - // Estimated: `0` - // Minimum execution time: 282_070 nanoseconds. - Weight::from_ref_time(286_466_489) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 238_285 - .saturating_add(Weight::from_ref_time(58_542_610).saturating_mul(r.into())) + // Estimated: `19880 + r * (11465 ±0)` + // Minimum execution time: 374_873 nanoseconds. + Weight::from_ref_time(378_422_289) + .saturating_add(Weight::from_proof_size(19880)) + // Standard Error: 979_734 + .saturating_add(Weight::from_ref_time(57_035_310).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((6_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_proof_size(11465).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) - /// Proof: RandomnessCollectiveFlip RandomMaterial (max_values: Some(1), max_size: Some(2594), added: 3089, mode: Ignored) + /// Proof: RandomnessCollectiveFlip RandomMaterial (max_values: Some(1), max_size: Some(2594), added: 3089, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 20]`. fn seal_random(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `889 + r * (800 ±0)` - // Estimated: `0` - // Minimum execution time: 284_147 nanoseconds. - Weight::from_ref_time(295_373_881) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 64_682 - .saturating_add(Weight::from_ref_time(114_198_680).saturating_mul(r.into())) + // Estimated: `18643 + r * (4805 ±0)` + // Minimum execution time: 375_001 nanoseconds. + Weight::from_ref_time(382_558_599) + .saturating_add(Weight::from_proof_size(18643)) + // Standard Error: 94_918 + .saturating_add(Weight::from_ref_time(112_973_277).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(4805).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 20]`. fn seal_deposit_event(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `842 + r * (800 ±0)` - // Estimated: `0` - // Minimum execution time: 282_681 nanoseconds. - Weight::from_ref_time(290_974_649) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 77_850 - .saturating_add(Weight::from_ref_time(233_273_622).saturating_mul(r.into())) + // Estimated: `17075 + r * (4000 ±0)` + // Minimum execution time: 372_547 nanoseconds. + Weight::from_ref_time(383_278_916) + .saturating_add(Weight::from_proof_size(17075)) + // Standard Error: 128_339 + .saturating_add(Weight::from_ref_time(229_356_088).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(4000).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:322 w:322) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// 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 { // Proof Size summary in bytes: // Measured: `1778 + t * (2608 ±0) + n * (8 ±0)` - // Estimated: `0` - // Minimum execution time: 1_226_868 nanoseconds. - Weight::from_ref_time(517_031_747) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 342_786 - .saturating_add(Weight::from_ref_time(183_829_556).saturating_mul(t.into())) - // Standard Error: 94_145 - .saturating_add(Weight::from_ref_time(70_675_099).saturating_mul(n.into())) + // Estimated: `21675 + t * (211030 ±0) + n * (50 ±0)` + // Minimum execution time: 1_290_432 nanoseconds. + Weight::from_ref_time(595_859_216) + .saturating_add(Weight::from_proof_size(21675)) + // Standard Error: 602_943 + .saturating_add(Weight::from_ref_time(178_128_149).saturating_mul(t.into())) + // Standard Error: 165_597 + .saturating_add(Weight::from_ref_time(71_475_468).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(t.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((80_u64).saturating_mul(t.into()))) + .saturating_add(Weight::from_proof_size(211030).saturating_mul(t.into())) + .saturating_add(Weight::from_proof_size(50).saturating_mul(n.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 20]`. fn seal_debug_message(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `841 + r * (560 ±0)` - // Estimated: `0` - // Minimum execution time: 143_026 nanoseconds. - Weight::from_ref_time(147_158_038) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 16_662 - .saturating_add(Weight::from_ref_time(14_990_989).saturating_mul(r.into())) + // Estimated: `17065 + r * (2800 ±0)` + // Minimum execution time: 149_020 nanoseconds. + Weight::from_ref_time(152_893_012) + .saturating_add(Weight::from_proof_size(17065)) + // Standard Error: 31_804 + .saturating_add(Weight::from_ref_time(14_497_512).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(2800).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) @@ -955,2033 +979,2086 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `125792` // Estimated: `265059` - // Minimum execution time: 412_112 nanoseconds. - Weight::from_ref_time(415_624_011) + // Minimum execution time: 502_589 nanoseconds. + Weight::from_ref_time(506_695_307) .saturating_add(Weight::from_proof_size(265059)) - // Standard Error: 1_190 - .saturating_add(Weight::from_ref_time(797_964).saturating_mul(i.into())) + // Standard Error: 2_148 + .saturating_add(Weight::from_ref_time(814_647).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: Skipped Metadata (r:0 w:0) - /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 10]`. fn seal_set_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `883 + r * (23417 ±0)` - // Estimated: `0` - // Minimum execution time: 286_118 nanoseconds. - Weight::from_ref_time(195_812_951) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 858_501 - .saturating_add(Weight::from_ref_time(485_357_331).saturating_mul(r.into())) + // Estimated: `883 + r * (23417 ±0)` + // Minimum execution time: 375_473 nanoseconds. + Weight::from_ref_time(291_125_810) + .saturating_add(Weight::from_proof_size(883)) + // Standard Error: 824_971 + .saturating_add(Weight::from_ref_time(477_999_695).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((80_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_proof_size(23417).saturating_mul(r.into())) } /// Storage: Skipped Metadata (r:0 w:0) - /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_new_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `12583 + n * (11969 ±0)` - // Estimated: `0` - // Minimum execution time: 433_181 nanoseconds. - Weight::from_ref_time(618_575_096) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 1_696_126 - .saturating_add(Weight::from_ref_time(96_213_633).saturating_mul(n.into())) + // Estimated: `8500 + n * (12813 ±61)` + // Minimum execution time: 515_962 nanoseconds. + Weight::from_ref_time(697_904_030) + .saturating_add(Weight::from_proof_size(8500)) + // Standard Error: 1_684_000 + .saturating_add(Weight::from_ref_time(98_411_710).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(52_u64)) .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(50_u64)) .saturating_add(T::DbWeight::get().writes((7_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_proof_size(12813).saturating_mul(n.into())) } /// Storage: Skipped Metadata (r:0 w:0) - /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_old_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `15138 + n * (175775 ±0)` - // Estimated: `0` - // Minimum execution time: 433_354 nanoseconds. - Weight::from_ref_time(597_131_349) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 1_509_003 - .saturating_add(Weight::from_ref_time(64_872_907).saturating_mul(n.into())) + // Estimated: `9898 + n * (176855 ±74)` + // Minimum execution time: 515_828 nanoseconds. + Weight::from_ref_time(661_240_495) + .saturating_add(Weight::from_proof_size(9898)) + // Standard Error: 1_338_661 + .saturating_add(Weight::from_ref_time(65_767_819).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(51_u64)) .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(49_u64)) .saturating_add(T::DbWeight::get().writes((7_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_proof_size(176855).saturating_mul(n.into())) } /// Storage: Skipped Metadata (r:0 w:0) - /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 10]`. fn seal_clear_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `876 + r * (23098 ±0)` - // Estimated: `0` - // Minimum execution time: 286_788 nanoseconds. - Weight::from_ref_time(207_787_332) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 778_284 - .saturating_add(Weight::from_ref_time(474_879_317).saturating_mul(r.into())) + // Estimated: `881 + r * (23097 ±0)` + // Minimum execution time: 375_528 nanoseconds. + Weight::from_ref_time(296_453_612) + .saturating_add(Weight::from_proof_size(881)) + // Standard Error: 809_232 + .saturating_add(Weight::from_ref_time(465_365_815).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((80_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_proof_size(23097).saturating_mul(r.into())) } /// Storage: Skipped Metadata (r:0 w:0) - /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `n` is `[0, 8]`. fn seal_clear_storage_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `14863 + n * (175768 ±0)` - // Estimated: `0` - // Minimum execution time: 397_414 nanoseconds. - Weight::from_ref_time(573_575_029) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 1_630_691 - .saturating_add(Weight::from_ref_time(67_888_226).saturating_mul(n.into())) + // Estimated: `9519 + n * (176867 ±75)` + // Minimum execution time: 480_427 nanoseconds. + Weight::from_ref_time(640_337_570) + .saturating_add(Weight::from_proof_size(9519)) + // Standard Error: 1_497_141 + .saturating_add(Weight::from_ref_time(67_963_696).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(51_u64)) .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(48_u64)) .saturating_add(T::DbWeight::get().writes((7_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_proof_size(176867).saturating_mul(n.into())) } /// Storage: Skipped Metadata (r:0 w:0) - /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 10]`. fn seal_get_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `878 + r * (23740 ±0)` - // Estimated: `0` - // Minimum execution time: 286_098 nanoseconds. - Weight::from_ref_time(223_637_903) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 669_294 - .saturating_add(Weight::from_ref_time(387_577_627).saturating_mul(r.into())) + // Estimated: `880 + r * (23739 ±0)` + // Minimum execution time: 375_725 nanoseconds. + Weight::from_ref_time(307_839_394) + .saturating_add(Weight::from_proof_size(880)) + // Standard Error: 710_694 + .saturating_add(Weight::from_ref_time(381_738_407).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(23739).saturating_mul(r.into())) } /// Storage: Skipped Metadata (r:0 w:0) - /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `n` is `[0, 8]`. fn seal_get_storage_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `15469 + n * (175775 ±0)` - // Estimated: `0` - // Minimum execution time: 373_335 nanoseconds. - Weight::from_ref_time(531_442_564) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 1_474_336 - .saturating_add(Weight::from_ref_time(154_469_598).saturating_mul(n.into())) + // Estimated: `10010 + n * (176900 ±76)` + // Minimum execution time: 461_871 nanoseconds. + Weight::from_ref_time(605_755_493) + .saturating_add(Weight::from_proof_size(10010)) + // Standard Error: 1_375_044 + .saturating_add(Weight::from_ref_time(161_332_330).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(51_u64)) .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(176900).saturating_mul(n.into())) } /// Storage: Skipped Metadata (r:0 w:0) - /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 10]`. fn seal_contains_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `871 + r * (23100 ±0)` - // Estimated: `0` - // Minimum execution time: 284_183 nanoseconds. - Weight::from_ref_time(223_325_689) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 644_587 - .saturating_add(Weight::from_ref_time(373_628_582).saturating_mul(r.into())) + // Estimated: `873 + r * (23099 ±0)` + // Minimum execution time: 375_325 nanoseconds. + Weight::from_ref_time(305_508_307) + .saturating_add(Weight::from_proof_size(873)) + // Standard Error: 715_627 + .saturating_add(Weight::from_ref_time(369_985_438).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(23099).saturating_mul(r.into())) } /// Storage: Skipped Metadata (r:0 w:0) - /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `n` is `[0, 8]`. fn seal_contains_storage_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `14814 + n * (175782 ±0)` - // Estimated: `0` - // Minimum execution time: 368_310 nanoseconds. - Weight::from_ref_time(512_814_023) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 1_337_352 - .saturating_add(Weight::from_ref_time(62_871_539).saturating_mul(n.into())) + // Estimated: `9502 + n * (176872 ±75)` + // Minimum execution time: 457_128 nanoseconds. + Weight::from_ref_time(582_799_799) + .saturating_add(Weight::from_proof_size(9502)) + // Standard Error: 1_151_126 + .saturating_add(Weight::from_ref_time(63_425_277).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(51_u64)) .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(176872).saturating_mul(n.into())) } /// Storage: Skipped Metadata (r:0 w:0) - /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 10]`. fn seal_take_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `879 + r * (23740 ±0)` - // Estimated: `0` - // Minimum execution time: 287_096 nanoseconds. - Weight::from_ref_time(204_878_281) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 833_763 - .saturating_add(Weight::from_ref_time(483_927_706).saturating_mul(r.into())) + // Estimated: `881 + r * (23739 ±0)` + // Minimum execution time: 375_918 nanoseconds. + Weight::from_ref_time(293_217_646) + .saturating_add(Weight::from_proof_size(881)) + // Standard Error: 840_266 + .saturating_add(Weight::from_ref_time(478_374_701).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((80_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_proof_size(23739).saturating_mul(r.into())) } /// Storage: Skipped Metadata (r:0 w:0) - /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `n` is `[0, 8]`. fn seal_take_storage_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `15470 + n * (175775 ±0)` - // Estimated: `0` - // Minimum execution time: 399_318 nanoseconds. - Weight::from_ref_time(586_658_466) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 1_734_497 - .saturating_add(Weight::from_ref_time(161_047_970).saturating_mul(n.into())) + // Estimated: `10010 + n * (176898 ±76)` + // Minimum execution time: 484_207 nanoseconds. + Weight::from_ref_time(664_065_436) + .saturating_add(Weight::from_proof_size(10010)) + // Standard Error: 1_655_442 + .saturating_add(Weight::from_ref_time(166_258_757).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(51_u64)) .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(48_u64)) .saturating_add(T::DbWeight::get().writes((7_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_proof_size(176898).saturating_mul(n.into())) } /// Storage: System Account (r:1602 w:1601) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 20]`. fn seal_transfer(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `1393 + r * (3602 ±0)` - // Estimated: `0` - // Minimum execution time: 285_460 nanoseconds. - Weight::from_ref_time(227_848_079) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 717_899 - .saturating_add(Weight::from_ref_time(1_434_112_130).saturating_mul(r.into())) + // Estimated: `21258 + r * (216091 ±0)` + // Minimum execution time: 377_152 nanoseconds. + Weight::from_ref_time(317_470_910) + .saturating_add(Weight::from_proof_size(21258)) + // Standard Error: 994_076 + .saturating_add(Weight::from_ref_time(1_409_416_087).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(T::DbWeight::get().writes((80_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_proof_size(216091).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1601 w:1601) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:2 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:1602 w:1602) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 20]`. fn seal_call(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `1551 + r * (20511 ±0)` - // Estimated: `0` - // Minimum execution time: 286_947 nanoseconds. - Weight::from_ref_time(288_518_000) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 8_492_544 - .saturating_add(Weight::from_ref_time(21_606_377_662).saturating_mul(r.into())) + // Estimated: `21848 + r * (498651 ±1)` + // Minimum execution time: 376_257 nanoseconds. + Weight::from_ref_time(377_035_000) + .saturating_add(Weight::from_proof_size(21848)) + // Standard Error: 7_966_778 + .saturating_add(Weight::from_ref_time(28_873_495_129).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().reads((160_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((160_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_proof_size(498651).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1536 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:1537 w:1537) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 20]`. fn seal_delegate_call(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + r * (71670 ±0)` - // Estimated: `0` - // Minimum execution time: 285_196 nanoseconds. - Weight::from_ref_time(287_958_000) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 10_345_109 - .saturating_add(Weight::from_ref_time(21_395_365_662).saturating_mul(r.into())) + // Estimated: `17125 + r * (659927 ±822)` + // Minimum execution time: 376_544 nanoseconds. + Weight::from_ref_time(377_490_000) + .saturating_add(Weight::from_proof_size(17125)) + // Standard Error: 8_608_050 + .saturating_add(Weight::from_ref_time(28_568_714_410).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((150_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((75_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_proof_size(659927).saturating_mul(r.into())) } /// Storage: System Account (r:82 w:81) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:81 w:81) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:2 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:82 w:82) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// 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 { // Proof Size summary in bytes: // Measured: `21611 + t * (15369 ±0)` - // Estimated: `0` - // Minimum execution time: 10_540_614 nanoseconds. - Weight::from_ref_time(9_281_766_912) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 5_409_378 - .saturating_add(Weight::from_ref_time(1_449_975_070).saturating_mul(t.into())) - // Standard Error: 8_111 - .saturating_add(Weight::from_ref_time(10_275_108).saturating_mul(c.into())) + // Estimated: `519400 + t * (277320 ±0)` + // Minimum execution time: 10_322_052 nanoseconds. + Weight::from_ref_time(9_248_652_894) + .saturating_add(Weight::from_proof_size(519400)) + // Standard Error: 9_039_638 + .saturating_add(Weight::from_ref_time(1_393_054_441).saturating_mul(t.into())) + // Standard Error: 13_554 + .saturating_add(Weight::from_ref_time(9_819_606).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(167_u64)) .saturating_add(T::DbWeight::get().reads((81_u64).saturating_mul(t.into()))) .saturating_add(T::DbWeight::get().writes(163_u64)) .saturating_add(T::DbWeight::get().writes((81_u64).saturating_mul(t.into()))) + .saturating_add(Weight::from_proof_size(277320).saturating_mul(t.into())) } /// Storage: System Account (r:1602 w:1602) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1601 w:1601) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) - /// Storage: Contracts CodeStorage (r:1601 w:1600) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Storage: Contracts CodeStorage (r:1601 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: Contracts Nonce (r:1 w:1) - /// Proof: Contracts Nonce (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Contracts Nonce (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: Contracts OwnerInfoOf (r:1600 w:1600) - /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Ignored) + /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Measured) /// Storage: System EventTopics (r:1602 w:1602) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 20]`. fn seal_instantiate(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `1613 + r * (25576 ±0)` - // Estimated: `0` - // Minimum execution time: 285_643 nanoseconds. - Weight::from_ref_time(287_472_000) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 25_921_947 - .saturating_add(Weight::from_ref_time(27_745_815_511).saturating_mul(r.into())) + // Estimated: `25698 + r * (1169112 ±1)` + // Minimum execution time: 376_639 nanoseconds. + Weight::from_ref_time(377_892_000) + .saturating_add(Weight::from_proof_size(25698)) + // Standard Error: 21_259_255 + .saturating_add(Weight::from_ref_time(34_131_174_956).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().reads((400_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(5_u64)) - .saturating_add(T::DbWeight::get().writes((400_u64).saturating_mul(r.into()))) + .saturating_add(T::DbWeight::get().writes((320_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_proof_size(1169112).saturating_mul(r.into())) } /// Storage: System Account (r:82 w:82) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:81 w:81) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) - /// Storage: Contracts CodeStorage (r:2 w:1) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Storage: Contracts CodeStorage (r:2 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: Contracts Nonce (r:1 w:1) - /// Proof: Contracts Nonce (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Contracts Nonce (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: Contracts OwnerInfoOf (r:1 w:1) - /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Ignored) + /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Measured) /// Storage: System EventTopics (r:82 w:82) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `t` is `[0, 1]`. /// The range of component `i` is `[0, 960]`. /// The range of component `s` is `[0, 960]`. fn seal_instantiate_per_transfer_input_salt_kb(t: u32, i: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `5666 + t * (17 ±0)` - // Estimated: `0` - // Minimum execution time: 129_710_453 nanoseconds. - Weight::from_ref_time(14_347_603_160) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 194_692 - .saturating_add(Weight::from_ref_time(128_837_066).saturating_mul(i.into())) - // Standard Error: 194_692 - .saturating_add(Weight::from_ref_time(127_568_555).saturating_mul(s.into())) + // Estimated: `651914 + t * (2762 ±3)` + // Minimum execution time: 130_366_376 nanoseconds. + Weight::from_ref_time(9_844_607_874) + .saturating_add(Weight::from_proof_size(651914)) + // Standard Error: 100_211_149 + .saturating_add(Weight::from_ref_time(390_481_449).saturating_mul(t.into())) + // Standard Error: 163_416 + .saturating_add(Weight::from_ref_time(126_154_200).saturating_mul(i.into())) + // Standard Error: 163_416 + .saturating_add(Weight::from_ref_time(126_430_874).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(249_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(t.into()))) - .saturating_add(T::DbWeight::get().writes(247_u64)) + .saturating_add(T::DbWeight::get().writes(246_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(t.into()))) + .saturating_add(Weight::from_proof_size(2762).saturating_mul(t.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 1]`. fn seal_hash_sha2_256(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `839 + r * (642 ±0)` - // Estimated: `0` - // Minimum execution time: 282_059 nanoseconds. - Weight::from_ref_time(287_215_177) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 273_484 - .saturating_add(Weight::from_ref_time(44_941_522).saturating_mul(r.into())) + // Estimated: `17065 + r * (3210 ±0)` + // Minimum execution time: 373_848 nanoseconds. + Weight::from_ref_time(375_974_597) + .saturating_add(Weight::from_proof_size(17065)) + // Standard Error: 558_923 + .saturating_add(Weight::from_ref_time(42_648_202).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(3210).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `n` is `[0, 1024]`. fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `1641` - // Estimated: `0` - // Minimum execution time: 330_822 nanoseconds. - Weight::from_ref_time(333_012_000) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 53_200 - .saturating_add(Weight::from_ref_time(327_144_474).saturating_mul(n.into())) + // Estimated: `21000` + // Minimum execution time: 417_281 nanoseconds. + Weight::from_ref_time(418_086_000) + .saturating_add(Weight::from_proof_size(21000)) + // Standard Error: 43_883 + .saturating_add(Weight::from_ref_time(324_497_460).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 1]`. fn seal_hash_keccak_256(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `841 + r * (642 ±0)` - // Estimated: `0` - // Minimum execution time: 282_859 nanoseconds. - Weight::from_ref_time(286_293_402) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 187_930 - .saturating_add(Weight::from_ref_time(57_415_297).saturating_mul(r.into())) + // Estimated: `17075 + r * (3210 ±0)` + // Minimum execution time: 372_362 nanoseconds. + Weight::from_ref_time(374_975_677) + .saturating_add(Weight::from_proof_size(17075)) + // Standard Error: 307_932 + .saturating_add(Weight::from_ref_time(57_607_522).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(3210).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `n` is `[0, 1024]`. fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `1643` - // Estimated: `0` - // Minimum execution time: 342_221 nanoseconds. - Weight::from_ref_time(343_250_000) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 67_989 - .saturating_add(Weight::from_ref_time(261_498_077).saturating_mul(n.into())) + // Estimated: `21040` + // Minimum execution time: 431_034 nanoseconds. + Weight::from_ref_time(431_571_000) + .saturating_add(Weight::from_proof_size(21040)) + // Standard Error: 80_071 + .saturating_add(Weight::from_ref_time(261_645_325).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 1]`. fn seal_hash_blake2_256(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `841 + r * (642 ±0)` - // Estimated: `0` - // Minimum execution time: 282_158 nanoseconds. - Weight::from_ref_time(285_783_279) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 200_413 - .saturating_add(Weight::from_ref_time(35_099_520).saturating_mul(r.into())) + // Estimated: `17075 + r * (3210 ±0)` + // Minimum execution time: 372_069 nanoseconds. + Weight::from_ref_time(374_200_608) + .saturating_add(Weight::from_proof_size(17075)) + // Standard Error: 171_799 + .saturating_add(Weight::from_ref_time(32_843_391).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(3210).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `1643` - // Estimated: `0` - // Minimum execution time: 317_376 nanoseconds. - Weight::from_ref_time(319_441_000) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 61_325 - .saturating_add(Weight::from_ref_time(101_080_739).saturating_mul(n.into())) + // Estimated: `21010` + // Minimum execution time: 406_143 nanoseconds. + Weight::from_ref_time(406_744_000) + .saturating_add(Weight::from_proof_size(21010)) + // Standard Error: 48_038 + .saturating_add(Weight::from_ref_time(103_286_295).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 1]`. fn seal_hash_blake2_128(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `841 + r * (679 ±0)` - // Estimated: `0` - // Minimum execution time: 280_403 nanoseconds. - Weight::from_ref_time(282_592_267) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 237_832 - .saturating_add(Weight::from_ref_time(37_056_632).saturating_mul(r.into())) + // Estimated: `17075 + r * (3395 ±0)` + // Minimum execution time: 372_201 nanoseconds. + Weight::from_ref_time(374_049_708) + .saturating_add(Weight::from_proof_size(17075)) + // Standard Error: 387_179 + .saturating_add(Weight::from_ref_time(38_857_191).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(3395).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `1643` - // Estimated: `0` - // Minimum execution time: 315_482 nanoseconds. - Weight::from_ref_time(316_160_000) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 40_926 - .saturating_add(Weight::from_ref_time(100_317_235).saturating_mul(n.into())) + // Estimated: `21050` + // Minimum execution time: 405_819 nanoseconds. + Weight::from_ref_time(406_364_000) + .saturating_add(Weight::from_proof_size(21050)) + // Standard Error: 46_248 + .saturating_add(Weight::from_ref_time(103_189_157).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 1]`. fn seal_ecdsa_recover(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `885 + r * (6083 ±0)` - // Estimated: `0` - // Minimum execution time: 276_155 nanoseconds. - Weight::from_ref_time(278_531_728) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 510_501 - .saturating_add(Weight::from_ref_time(3_056_236_671).saturating_mul(r.into())) + // Estimated: `17295 + r * (30415 ±0)` + // Minimum execution time: 374_836 nanoseconds. + Weight::from_ref_time(379_385_500) + .saturating_add(Weight::from_proof_size(17295)) + // Standard Error: 1_694_427 + .saturating_add(Weight::from_ref_time(3_021_801_000).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(30415).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 1]`. fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `854 + r * (3362 ±0)` - // Estimated: `0` - // Minimum execution time: 276_204 nanoseconds. - Weight::from_ref_time(278_114_283) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 217_508 - .saturating_add(Weight::from_ref_time(737_577_816).saturating_mul(r.into())) + // Estimated: `17140 + r * (16810 ±0)` + // Minimum execution time: 374_223 nanoseconds. + Weight::from_ref_time(376_120_230) + .saturating_add(Weight::from_proof_size(17140)) + // Standard Error: 619_576 + .saturating_add(Weight::from_ref_time(754_257_969).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(16810).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1536 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: Contracts OwnerInfoOf (r:1536 w:1536) - /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Ignored) + /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Measured) /// Storage: System EventTopics (r:1538 w:1538) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 20]`. fn seal_set_code_hash(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + r * (79300 ±0)` - // Estimated: `0` - // Minimum execution time: 276_330 nanoseconds. - Weight::from_ref_time(277_573_000) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 3_652_635 - .saturating_add(Weight::from_ref_time(1_547_361_882).saturating_mul(r.into())) + // Estimated: `64652 + r * (942952 ±829)` + // Minimum execution time: 374_442 nanoseconds. + Weight::from_ref_time(375_591_000) + .saturating_add(Weight::from_proof_size(64652)) + // Standard Error: 3_764_193 + .saturating_add(Weight::from_ref_time(1_552_885_601).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((225_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((150_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_proof_size(942952).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 20]`. fn seal_reentrance_count(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `837 + r * (240 ±0)` - // Estimated: `0` - // Minimum execution time: 276_228 nanoseconds. - Weight::from_ref_time(281_135_551) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 18_737 - .saturating_add(Weight::from_ref_time(10_998_953).saturating_mul(r.into())) + // Estimated: `17055 + r * (1200 ±0)` + // Minimum execution time: 374_922 nanoseconds. + Weight::from_ref_time(376_234_094) + .saturating_add(Weight::from_proof_size(17055)) + // Standard Error: 45_995 + .saturating_add(Weight::from_ref_time(11_606_505).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(1200).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 20]`. fn seal_account_reentrance_count(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `2056 + r * (3153 ±0)` - // Estimated: `0` - // Minimum execution time: 278_157 nanoseconds. - Weight::from_ref_time(300_739_078) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 72_695 - .saturating_add(Weight::from_ref_time(18_499_645).saturating_mul(r.into())) + // Estimated: `21730 + r * (15870 ±2)` + // Minimum execution time: 376_762 nanoseconds. + Weight::from_ref_time(396_934_359) + .saturating_add(Weight::from_proof_size(21730)) + // Standard Error: 68_263 + .saturating_add(Weight::from_ref_time(18_367_270).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(15870).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: Contracts Nonce (r:1 w:1) - /// Proof: Contracts Nonce (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Contracts Nonce (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 20]`. fn seal_instantiation_nonce(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `840 + r * (240 ±0)` - // Estimated: `0` - // Minimum execution time: 275_532 nanoseconds. - Weight::from_ref_time(281_299_677) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 21_719 - .saturating_add(Weight::from_ref_time(9_513_444).saturating_mul(r.into())) + // Estimated: `18405 + r * (1440 ±0)` + // Minimum execution time: 374_257 nanoseconds. + Weight::from_ref_time(380_453_380) + .saturating_add(Weight::from_proof_size(18405)) + // Standard Error: 42_718 + .saturating_add(Weight::from_ref_time(9_355_253).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) + .saturating_add(Weight::from_proof_size(1440).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64const(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 856 nanoseconds. - Weight::from_ref_time(1_054_710) + // Minimum execution time: 788 nanoseconds. + Weight::from_ref_time(1_209_829) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 273 - .saturating_add(Weight::from_ref_time(411_548).saturating_mul(r.into())) + // Standard Error: 3_436 + .saturating_add(Weight::from_ref_time(409_858).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64load(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 980 nanoseconds. - Weight::from_ref_time(1_463_182) + // Minimum execution time: 955 nanoseconds. + Weight::from_ref_time(1_526_327) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 415 - .saturating_add(Weight::from_ref_time(1_063_436).saturating_mul(r.into())) + // Standard Error: 2_399 + .saturating_add(Weight::from_ref_time(1_084_504).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64store(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 991 nanoseconds. - Weight::from_ref_time(1_521_750) + // Minimum execution time: 967 nanoseconds. + Weight::from_ref_time(1_576_183) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 8_499 - .saturating_add(Weight::from_ref_time(997_972).saturating_mul(r.into())) + // Standard Error: 5_719 + .saturating_add(Weight::from_ref_time(1_006_742).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_select(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 833 nanoseconds. - Weight::from_ref_time(1_152_048) + // Minimum execution time: 849 nanoseconds. + Weight::from_ref_time(1_106_539) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 392 - .saturating_add(Weight::from_ref_time(1_147_506).saturating_mul(r.into())) + // Standard Error: 445 + .saturating_add(Weight::from_ref_time(1_149_752).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_if(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 866 nanoseconds. - Weight::from_ref_time(1_154_637) + // Minimum execution time: 829 nanoseconds. + Weight::from_ref_time(1_171_360) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 5_131 - .saturating_add(Weight::from_ref_time(1_320_580).saturating_mul(r.into())) + // Standard Error: 552 + .saturating_add(Weight::from_ref_time(1_309_914).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_br(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 849 nanoseconds. - Weight::from_ref_time(1_073_940) + // Minimum execution time: 835 nanoseconds. + Weight::from_ref_time(1_125_578) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 639 - .saturating_add(Weight::from_ref_time(642_885).saturating_mul(r.into())) + // Standard Error: 374 + .saturating_add(Weight::from_ref_time(641_683).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_br_if(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 855 nanoseconds. - Weight::from_ref_time(728_631) + // Minimum execution time: 816 nanoseconds. + Weight::from_ref_time(1_032_093) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 1_730 - .saturating_add(Weight::from_ref_time(979_839).saturating_mul(r.into())) + // Standard Error: 811 + .saturating_add(Weight::from_ref_time(956_228).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_br_table(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 852 nanoseconds. - Weight::from_ref_time(658_935) + // Minimum execution time: 801 nanoseconds. + Weight::from_ref_time(816_764) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 2_373 - .saturating_add(Weight::from_ref_time(1_172_585).saturating_mul(r.into())) + // Standard Error: 2_669 + .saturating_add(Weight::from_ref_time(1_166_556).saturating_mul(r.into())) } /// The range of component `e` is `[1, 256]`. fn instr_br_table_per_entry(e: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_577 nanoseconds. - Weight::from_ref_time(2_872_555) + // Minimum execution time: 2_639 nanoseconds. + Weight::from_ref_time(2_905_554) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 70 - .saturating_add(Weight::from_ref_time(4_237).saturating_mul(e.into())) + // Standard Error: 62 + .saturating_add(Weight::from_ref_time(4_438).saturating_mul(e.into())) } /// The range of component `r` is `[0, 50]`. fn instr_call(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 833 nanoseconds. - Weight::from_ref_time(874_000) + // Minimum execution time: 831 nanoseconds. + Weight::from_ref_time(1_729_584) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 30_863 - .saturating_add(Weight::from_ref_time(2_591_963).saturating_mul(r.into())) + // Standard Error: 33_753 + .saturating_add(Weight::from_ref_time(2_380_315).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_call_indirect(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 992 nanoseconds. - Weight::from_ref_time(2_772_709) + // Minimum execution time: 964 nanoseconds. + Weight::from_ref_time(2_445_291) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 3_822 - .saturating_add(Weight::from_ref_time(3_070_825).saturating_mul(r.into())) + // Standard Error: 3_285 + .saturating_add(Weight::from_ref_time(2_938_681).saturating_mul(r.into())) } /// The range of component `p` is `[0, 128]`. fn instr_call_indirect_per_param(p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_766 nanoseconds. - Weight::from_ref_time(5_559_951) + // Minimum execution time: 4_809 nanoseconds. + Weight::from_ref_time(6_763_286) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 315 - .saturating_add(Weight::from_ref_time(227_249).saturating_mul(p.into())) + // Standard Error: 3_994 + .saturating_add(Weight::from_ref_time(217_632).saturating_mul(p.into())) } /// The range of component `l` is `[0, 1024]`. fn instr_call_per_local(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_215 nanoseconds. - Weight::from_ref_time(4_697_732) + // Minimum execution time: 3_138 nanoseconds. + Weight::from_ref_time(3_894_816) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 99 - .saturating_add(Weight::from_ref_time(46_431).saturating_mul(l.into())) + // Standard Error: 131 + .saturating_add(Weight::from_ref_time(91_699).saturating_mul(l.into())) } /// The range of component `r` is `[0, 50]`. fn instr_local_get(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_193 nanoseconds. - Weight::from_ref_time(2_472_277) + // Minimum execution time: 2_959 nanoseconds. + Weight::from_ref_time(3_271_550) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 374 - .saturating_add(Weight::from_ref_time(459_651).saturating_mul(r.into())) + // Standard Error: 223 + .saturating_add(Weight::from_ref_time(460_056).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_local_set(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_112 nanoseconds. - Weight::from_ref_time(2_388_132) + // Minimum execution time: 2_970 nanoseconds. + Weight::from_ref_time(3_216_157) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 380 - .saturating_add(Weight::from_ref_time(485_216).saturating_mul(r.into())) + // Standard Error: 413 + .saturating_add(Weight::from_ref_time(485_842).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_local_tee(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_219 nanoseconds. - Weight::from_ref_time(2_419_568) + // Minimum execution time: 2_980 nanoseconds. + Weight::from_ref_time(3_323_878) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 402 - .saturating_add(Weight::from_ref_time(658_484).saturating_mul(r.into())) + // Standard Error: 2_652 + .saturating_add(Weight::from_ref_time(660_257).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_global_get(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 959 nanoseconds. - Weight::from_ref_time(1_321_004) + // Minimum execution time: 917 nanoseconds. + Weight::from_ref_time(1_445_816) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 480 - .saturating_add(Weight::from_ref_time(898_447).saturating_mul(r.into())) + // Standard Error: 5_642 + .saturating_add(Weight::from_ref_time(894_521).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_global_set(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 934 nanoseconds. - Weight::from_ref_time(1_264_350) + // Minimum execution time: 965 nanoseconds. + Weight::from_ref_time(1_373_722) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 1_031 - .saturating_add(Weight::from_ref_time(922_243).saturating_mul(r.into())) + // Standard Error: 1_157 + .saturating_add(Weight::from_ref_time(917_643).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_memory_current(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 941 nanoseconds. - Weight::from_ref_time(1_229_407) + // Minimum execution time: 982 nanoseconds. + Weight::from_ref_time(1_240_280) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 507 - .saturating_add(Weight::from_ref_time(824_206).saturating_mul(r.into())) + // Standard Error: 308 + .saturating_add(Weight::from_ref_time(817_972).saturating_mul(r.into())) } /// The range of component `r` is `[0, 1]`. fn instr_memory_grow(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 870 nanoseconds. - Weight::from_ref_time(946_681) + // Minimum execution time: 858 nanoseconds. + Weight::from_ref_time(962_183) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 7_248 - .saturating_add(Weight::from_ref_time(179_759_218).saturating_mul(r.into())) + // Standard Error: 6_701 + .saturating_add(Weight::from_ref_time(239_704_216).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64clz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 843 nanoseconds. - Weight::from_ref_time(1_105_279) + // Minimum execution time: 807 nanoseconds. + Weight::from_ref_time(1_132_872) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 251 - .saturating_add(Weight::from_ref_time(633_218).saturating_mul(r.into())) + // Standard Error: 303 + .saturating_add(Weight::from_ref_time(633_832).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ctz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 843 nanoseconds. - Weight::from_ref_time(1_119_719) + // Minimum execution time: 823 nanoseconds. + Weight::from_ref_time(1_267_518) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 248 - .saturating_add(Weight::from_ref_time(633_064).saturating_mul(r.into())) + // Standard Error: 483 + .saturating_add(Weight::from_ref_time(632_620).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64popcnt(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 865 nanoseconds. - Weight::from_ref_time(1_394_651) + // Minimum execution time: 857 nanoseconds. + Weight::from_ref_time(1_105_214) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 9_898 - .saturating_add(Weight::from_ref_time(630_054).saturating_mul(r.into())) + // Standard Error: 285 + .saturating_add(Weight::from_ref_time(635_039).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64eqz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 831 nanoseconds. - Weight::from_ref_time(1_095_288) + // Minimum execution time: 821 nanoseconds. + Weight::from_ref_time(750_223) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 271 - .saturating_add(Weight::from_ref_time(650_578).saturating_mul(r.into())) + // Standard Error: 15_923 + .saturating_add(Weight::from_ref_time(686_322).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendsi32(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 835 nanoseconds. - Weight::from_ref_time(1_128_234) + // Minimum execution time: 797 nanoseconds. + Weight::from_ref_time(1_145_072) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 239 - .saturating_add(Weight::from_ref_time(615_970).saturating_mul(r.into())) + // Standard Error: 311 + .saturating_add(Weight::from_ref_time(618_147).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendui32(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 839 nanoseconds. - Weight::from_ref_time(1_111_296) + // Minimum execution time: 803 nanoseconds. + Weight::from_ref_time(1_139_498) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 303 - .saturating_add(Weight::from_ref_time(616_831).saturating_mul(r.into())) + // Standard Error: 284 + .saturating_add(Weight::from_ref_time(617_393).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i32wrapi64(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 839 nanoseconds. - Weight::from_ref_time(1_082_700) + // Minimum execution time: 814 nanoseconds. + Weight::from_ref_time(1_099_405) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 236 - .saturating_add(Weight::from_ref_time(617_371).saturating_mul(r.into())) + // Standard Error: 663 + .saturating_add(Weight::from_ref_time(618_565).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64eq(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 837 nanoseconds. - Weight::from_ref_time(1_249_666) + // Minimum execution time: 819 nanoseconds. + Weight::from_ref_time(1_199_220) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 836 - .saturating_add(Weight::from_ref_time(904_457).saturating_mul(r.into())) + // Standard Error: 485 + .saturating_add(Weight::from_ref_time(906_878).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ne(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 818 nanoseconds. - Weight::from_ref_time(1_624_057) + // Minimum execution time: 822 nanoseconds. + Weight::from_ref_time(274_212) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 5_906 - .saturating_add(Weight::from_ref_time(893_488).saturating_mul(r.into())) + // Standard Error: 29_294 + .saturating_add(Weight::from_ref_time(971_608).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64lts(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 836 nanoseconds. - Weight::from_ref_time(1_973_044) + // Minimum execution time: 796 nanoseconds. + Weight::from_ref_time(1_396_586) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 7_556 - .saturating_add(Weight::from_ref_time(885_369).saturating_mul(r.into())) + // Standard Error: 7_205 + .saturating_add(Weight::from_ref_time(903_202).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ltu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 846 nanoseconds. - Weight::from_ref_time(1_088_223) + // Minimum execution time: 833 nanoseconds. + Weight::from_ref_time(1_115_115) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 531 - .saturating_add(Weight::from_ref_time(909_313).saturating_mul(r.into())) + // Standard Error: 310 + .saturating_add(Weight::from_ref_time(908_195).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64gts(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 842 nanoseconds. - Weight::from_ref_time(1_435_966) + // Minimum execution time: 854 nanoseconds. + Weight::from_ref_time(1_170_419) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 3_824 - .saturating_add(Weight::from_ref_time(898_198).saturating_mul(r.into())) + // Standard Error: 298 + .saturating_add(Weight::from_ref_time(907_171).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64gtu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 846 nanoseconds. - Weight::from_ref_time(1_154_015) + // Minimum execution time: 822 nanoseconds. + Weight::from_ref_time(1_186_349) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 319 - .saturating_add(Weight::from_ref_time(918_083).saturating_mul(r.into())) + // Standard Error: 302 + .saturating_add(Weight::from_ref_time(917_857).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64les(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 848 nanoseconds. - Weight::from_ref_time(1_155_323) + // Minimum execution time: 807 nanoseconds. + Weight::from_ref_time(1_127_093) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 307 - .saturating_add(Weight::from_ref_time(906_516).saturating_mul(r.into())) + // Standard Error: 1_891 + .saturating_add(Weight::from_ref_time(910_738).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64leu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 877 nanoseconds. - Weight::from_ref_time(1_629_210) + // Minimum execution time: 819 nanoseconds. + Weight::from_ref_time(1_143_022) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 8_175 - .saturating_add(Weight::from_ref_time(906_657).saturating_mul(r.into())) + // Standard Error: 309 + .saturating_add(Weight::from_ref_time(919_047).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ges(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 843 nanoseconds. - Weight::from_ref_time(1_126_252) + // Minimum execution time: 788 nanoseconds. + Weight::from_ref_time(1_116_914) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 251 - .saturating_add(Weight::from_ref_time(907_052).saturating_mul(r.into())) + // Standard Error: 643 + .saturating_add(Weight::from_ref_time(911_159).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64geu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 852 nanoseconds. - Weight::from_ref_time(1_497_667) + // Minimum execution time: 791 nanoseconds. + Weight::from_ref_time(1_123_747) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 7_593 - .saturating_add(Weight::from_ref_time(897_474).saturating_mul(r.into())) + // Standard Error: 583 + .saturating_add(Weight::from_ref_time(910_242).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64add(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 856 nanoseconds. - Weight::from_ref_time(1_350_390) + // Minimum execution time: 787 nanoseconds. + Weight::from_ref_time(1_109_471) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 2_625 - .saturating_add(Weight::from_ref_time(889_609).saturating_mul(r.into())) + // Standard Error: 305 + .saturating_add(Weight::from_ref_time(897_608).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64sub(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 841 nanoseconds. - Weight::from_ref_time(2_677_235) + // Minimum execution time: 821 nanoseconds. + Weight::from_ref_time(1_098_631) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 11_507 - .saturating_add(Weight::from_ref_time(846_704).saturating_mul(r.into())) + // Standard Error: 523 + .saturating_add(Weight::from_ref_time(887_814).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64mul(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 846 nanoseconds. - Weight::from_ref_time(1_148_206) + // Minimum execution time: 794 nanoseconds. + Weight::from_ref_time(1_166_332) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 393 - .saturating_add(Weight::from_ref_time(884_886).saturating_mul(r.into())) + // Standard Error: 384 + .saturating_add(Weight::from_ref_time(885_584).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64divs(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 865 nanoseconds. - Weight::from_ref_time(2_862_483) + // Minimum execution time: 822 nanoseconds. + Weight::from_ref_time(1_155_826) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 16_413 - .saturating_add(Weight::from_ref_time(1_481_623).saturating_mul(r.into())) + // Standard Error: 521 + .saturating_add(Weight::from_ref_time(1_520_958).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64divu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_443 nanoseconds. - Weight::from_ref_time(1_086_902) + // Minimum execution time: 881 nanoseconds. + Weight::from_ref_time(1_158_125) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 2_245 - .saturating_add(Weight::from_ref_time(1_463_145).saturating_mul(r.into())) + // Standard Error: 624 + .saturating_add(Weight::from_ref_time(1_458_378).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64rems(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 878 nanoseconds. - Weight::from_ref_time(1_130_306) + // Minimum execution time: 827 nanoseconds. + Weight::from_ref_time(1_209_535) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 475 - .saturating_add(Weight::from_ref_time(1_522_011).saturating_mul(r.into())) + // Standard Error: 399 + .saturating_add(Weight::from_ref_time(1_547_640).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64remu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 827 nanoseconds. - Weight::from_ref_time(1_197_053) + // Minimum execution time: 801 nanoseconds. + Weight::from_ref_time(1_313_872) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 474 - .saturating_add(Weight::from_ref_time(1_449_062).saturating_mul(r.into())) + // Standard Error: 2_175 + .saturating_add(Weight::from_ref_time(1_449_416).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64and(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 847 nanoseconds. - Weight::from_ref_time(1_152_423) + // Minimum execution time: 827 nanoseconds. + Weight::from_ref_time(1_093_874) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 296 - .saturating_add(Weight::from_ref_time(895_541).saturating_mul(r.into())) + // Standard Error: 708 + .saturating_add(Weight::from_ref_time(901_450).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64or(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 876 nanoseconds. - Weight::from_ref_time(1_169_485) + // Minimum execution time: 824 nanoseconds. + Weight::from_ref_time(1_164_076) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 571 - .saturating_add(Weight::from_ref_time(932_659).saturating_mul(r.into())) + // Standard Error: 623 + .saturating_add(Weight::from_ref_time(897_579).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64xor(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 856 nanoseconds. - Weight::from_ref_time(1_155_127) + // Minimum execution time: 789 nanoseconds. + Weight::from_ref_time(1_113_915) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 256 - .saturating_add(Weight::from_ref_time(895_663).saturating_mul(r.into())) + // Standard Error: 390 + .saturating_add(Weight::from_ref_time(897_354).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64shl(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 871 nanoseconds. - Weight::from_ref_time(1_139_722) + // Minimum execution time: 811 nanoseconds. + Weight::from_ref_time(1_117_366) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 367 - .saturating_add(Weight::from_ref_time(903_115).saturating_mul(r.into())) + // Standard Error: 437 + .saturating_add(Weight::from_ref_time(903_759).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64shrs(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 853 nanoseconds. - Weight::from_ref_time(1_155_542) + // Minimum execution time: 846 nanoseconds. + Weight::from_ref_time(1_103_954) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 541 - .saturating_add(Weight::from_ref_time(901_635).saturating_mul(r.into())) + // Standard Error: 414 + .saturating_add(Weight::from_ref_time(903_429).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64shru(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 866 nanoseconds. - Weight::from_ref_time(2_260_588) + // Minimum execution time: 803 nanoseconds. + Weight::from_ref_time(1_124_328) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 12_944 - .saturating_add(Weight::from_ref_time(877_790).saturating_mul(r.into())) + // Standard Error: 410 + .saturating_add(Weight::from_ref_time(903_216).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotl(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 851 nanoseconds. - Weight::from_ref_time(1_627_816) + // Minimum execution time: 810 nanoseconds. + Weight::from_ref_time(1_131_433) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 4_004 - .saturating_add(Weight::from_ref_time(887_929).saturating_mul(r.into())) + // Standard Error: 402 + .saturating_add(Weight::from_ref_time(903_381).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotr(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 874 nanoseconds. - Weight::from_ref_time(2_611_817) + // Minimum execution time: 807 nanoseconds. + Weight::from_ref_time(1_144_933) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 10_026 - .saturating_add(Weight::from_ref_time(862_138).saturating_mul(r.into())) + // Standard Error: 373 + .saturating_add(Weight::from_ref_time(902_918).saturating_mul(r.into())) } } // For backwards compatibility and tests impl WeightInfo for () { /// Storage: Contracts DeletionQueue (r:1 w:0) - /// Proof: Contracts DeletionQueue (max_values: Some(1), max_size: Some(16642), added: 17137, mode: Ignored) + /// Proof: Contracts DeletionQueue (max_values: Some(1), max_size: Some(16642), added: 17137, mode: Measured) fn on_process_deletion_queue_batch() -> Weight { // Proof Size summary in bytes: // Measured: `109` - // Estimated: `0` - // Minimum execution time: 2_564 nanoseconds. - Weight::from_ref_time(2_722_000) - .saturating_add(Weight::from_proof_size(0)) + // Estimated: `604` + // Minimum execution time: 2_507 nanoseconds. + Weight::from_ref_time(2_650_000) + .saturating_add(Weight::from_proof_size(604)) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: Skipped Metadata (r:0 w:0) - /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `k` is `[0, 1024]`. fn on_initialize_per_trie_key(k: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `481 + k * (69 ±0)` - // Estimated: `0` - // Minimum execution time: 10_292 nanoseconds. - Weight::from_ref_time(7_474_496) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 901 - .saturating_add(Weight::from_ref_time(956_864).saturating_mul(k.into())) + // Estimated: `471 + k * (70 ±0)` + // Minimum execution time: 9_953 nanoseconds. + Weight::from_ref_time(6_467_352) + .saturating_add(Weight::from_proof_size(471)) + // Standard Error: 1_074 + .saturating_add(Weight::from_ref_time(943_946).saturating_mul(k.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(k.into()))) + .saturating_add(Weight::from_proof_size(70).saturating_mul(k.into())) } /// Storage: Contracts DeletionQueue (r:1 w:1) - /// Proof: Contracts DeletionQueue (max_values: Some(1), max_size: Some(16642), added: 17137, mode: Ignored) + /// Proof: Contracts DeletionQueue (max_values: Some(1), max_size: Some(16642), added: 17137, mode: Measured) /// The range of component `q` is `[0, 128]`. fn on_initialize_per_queue_item(q: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `281 + q * (33 ±0)` - // Estimated: `0` - // Minimum execution time: 2_620 nanoseconds. - Weight::from_ref_time(10_288_873) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 3_073 - .saturating_add(Weight::from_ref_time(1_148_167).saturating_mul(q.into())) + // Estimated: `763 + q * (33 ±0)` + // Minimum execution time: 2_545 nanoseconds. + Weight::from_ref_time(10_080_106) + .saturating_add(Weight::from_proof_size(763)) + // Standard Error: 2_929 + .saturating_add(Weight::from_ref_time(1_078_265).saturating_mul(q.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) + .saturating_add(Weight::from_proof_size(33).saturating_mul(q.into())) } /// Storage: Contracts PristineCode (r:1 w:0) - /// Proof: Contracts PristineCode (max_values: None, max_size: Some(125988), added: 128463, mode: Ignored) + /// Proof: Contracts PristineCode (max_values: None, max_size: Some(125988), added: 128463, mode: Measured) /// Storage: Contracts CodeStorage (r:0 w:1) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// The range of component `c` is `[0, 61717]`. fn reinstrument(c: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `270 + c * (1 ±0)` - // Estimated: `0` - // Minimum execution time: 28_004 nanoseconds. - Weight::from_ref_time(26_706_943) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 67 - .saturating_add(Weight::from_ref_time(51_603).saturating_mul(c.into())) + // Estimated: `3025 + c * (2 ±0)` + // Minimum execution time: 34_613 nanoseconds. + Weight::from_ref_time(27_355_774) + .saturating_add(Weight::from_proof_size(3025)) + // Standard Error: 81 + .saturating_add(Weight::from_ref_time(51_954).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) + .saturating_add(Weight::from_proof_size(2).saturating_mul(c.into())) } /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `c` is `[0, 125952]`. fn call_with_code_per_byte(c: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `771` - // Estimated: `0` - // Minimum execution time: 295_799 nanoseconds. - Weight::from_ref_time(308_660_753) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 20 - .saturating_add(Weight::from_ref_time(32_458).saturating_mul(c.into())) + // Estimated: `16780 + c * (5 ±0)` + // Minimum execution time: 386_104 nanoseconds. + Weight::from_ref_time(396_718_823) + .saturating_add(Weight::from_proof_size(16780)) + // Standard Error: 27 + .saturating_add(Weight::from_ref_time(31_370).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) + .saturating_add(Weight::from_proof_size(5).saturating_mul(c.into())) } - /// Storage: Contracts CodeStorage (r:1 w:1) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Contracts OwnerInfoOf (r:1 w:1) + /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Measured) /// Storage: Contracts Nonce (r:1 w:1) - /// Proof: Contracts Nonce (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Contracts Nonce (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: System EventTopics (r:3 w:3) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) + /// Storage: Contracts CodeStorage (r:0 w:1) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Contracts PristineCode (r:0 w:1) - /// Proof: Contracts PristineCode (max_values: None, max_size: Some(125988), added: 128463, mode: Ignored) - /// Storage: Contracts OwnerInfoOf (r:0 w:1) - /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Ignored) + /// Proof: Contracts PristineCode (max_values: None, max_size: Some(125988), added: 128463, mode: Measured) /// The range of component `c` is `[0, 61717]`. /// The range of component `i` is `[0, 1048576]`. /// The range of component `s` is `[0, 1048576]`. fn instantiate_with_code(c: u32, i: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `257` - // Estimated: `0` - // Minimum execution time: 3_754_887 nanoseconds. - Weight::from_ref_time(657_695_827) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 283 - .saturating_add(Weight::from_ref_time(94_808).saturating_mul(c.into())) + // Estimated: `17752` + // Minimum execution time: 3_786_500 nanoseconds. + Weight::from_ref_time(672_511_565) + .saturating_add(Weight::from_proof_size(17752)) + // Standard Error: 281 + .saturating_add(Weight::from_ref_time(94_538).saturating_mul(c.into())) // Standard Error: 16 - .saturating_add(Weight::from_ref_time(1_357).saturating_mul(i.into())) + .saturating_add(Weight::from_ref_time(1_364).saturating_mul(i.into())) // Standard Error: 16 - .saturating_add(Weight::from_ref_time(1_756).saturating_mul(s.into())) + .saturating_add(Weight::from_ref_time(1_768).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(9_u64)) } - /// Storage: Contracts CodeStorage (r:1 w:1) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Contracts Nonce (r:1 w:1) - /// Proof: Contracts Nonce (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Contracts Nonce (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts OwnerInfoOf (r:1 w:1) - /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Ignored) + /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `i` is `[0, 1048576]`. /// The range of component `s` is `[0, 1048576]`. fn instantiate(i: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `533` - // Estimated: `0` - // Minimum execution time: 1_961_131 nanoseconds. - Weight::from_ref_time(208_539_564) - .saturating_add(Weight::from_proof_size(0)) + // Estimated: `19543` + // Minimum execution time: 1_927_365 nanoseconds. + Weight::from_ref_time(189_843_928) + .saturating_add(Weight::from_proof_size(19543)) // Standard Error: 8 - .saturating_add(Weight::from_ref_time(1_688).saturating_mul(i.into())) + .saturating_add(Weight::from_ref_time(1_677).saturating_mul(i.into())) // Standard Error: 8 - .saturating_add(Weight::from_ref_time(1_802).saturating_mul(s.into())) + .saturating_add(Weight::from_ref_time(1_803).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) - .saturating_add(RocksDbWeight::get().writes(7_u64)) + .saturating_add(RocksDbWeight::get().writes(6_u64)) } /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) fn call() -> Weight { // Proof Size summary in bytes: // Measured: `823` - // Estimated: `0` - // Minimum execution time: 148_138 nanoseconds. - Weight::from_ref_time(148_862_000) - .saturating_add(Weight::from_proof_size(0)) + // Estimated: `16985` + // Minimum execution time: 146_354 nanoseconds. + Weight::from_ref_time(147_693_000) + .saturating_add(Weight::from_proof_size(16985)) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } - /// Storage: Contracts CodeStorage (r:1 w:1) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Storage: Contracts OwnerInfoOf (r:1 w:1) + /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Measured) /// Storage: System EventTopics (r:1 w:1) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) + /// Storage: Contracts CodeStorage (r:0 w:1) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Contracts PristineCode (r:0 w:1) - /// Proof: Contracts PristineCode (max_values: None, max_size: Some(125988), added: 128463, mode: Ignored) - /// Storage: Contracts OwnerInfoOf (r:0 w:1) - /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Ignored) + /// Proof: Contracts PristineCode (max_values: None, max_size: Some(125988), added: 128463, mode: Measured) /// The range of component `c` is `[0, 61717]`. fn upload_code(c: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `109` - // Estimated: `0` - // Minimum execution time: 293_444 nanoseconds. - Weight::from_ref_time(293_242_988) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 156 - .saturating_add(Weight::from_ref_time(97_476).saturating_mul(c.into())) + // Estimated: `5386` + // Minimum execution time: 388_107 nanoseconds. + Weight::from_ref_time(383_172_702) + .saturating_add(Weight::from_proof_size(5386)) + // Standard Error: 73 + .saturating_add(Weight::from_ref_time(95_037).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } /// Storage: Contracts OwnerInfoOf (r:1 w:1) - /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Ignored) + /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Measured) /// Storage: System EventTopics (r:1 w:1) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// Storage: Contracts CodeStorage (r:0 w:1) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Contracts PristineCode (r:0 w:1) - /// Proof: Contracts PristineCode (max_values: None, max_size: Some(125988), added: 128463, mode: Ignored) + /// Proof: Contracts PristineCode (max_values: None, max_size: Some(125988), added: 128463, mode: Measured) fn remove_code() -> Weight { // Proof Size summary in bytes: // Measured: `287` - // Estimated: `0` - // Minimum execution time: 26_802 nanoseconds. - Weight::from_ref_time(27_121_000) - .saturating_add(Weight::from_proof_size(0)) + // Estimated: `6098` + // Minimum execution time: 26_278 nanoseconds. + Weight::from_ref_time(26_682_000) + .saturating_add(Weight::from_proof_size(6098)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts OwnerInfoOf (r:2 w:2) - /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Ignored) + /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Measured) /// Storage: System EventTopics (r:3 w:3) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) fn set_code() -> Weight { // Proof Size summary in bytes: // Measured: `634` - // Estimated: `0` - // Minimum execution time: 31_079 nanoseconds. - Weight::from_ref_time(31_541_000) - .saturating_add(Weight::from_proof_size(0)) + // Estimated: `16752` + // Minimum execution time: 30_223 nanoseconds. + Weight::from_ref_time(30_737_000) + .saturating_add(Weight::from_proof_size(16752)) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 20]`. fn seal_caller(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `845 + r * (480 ±0)` - // Estimated: `0` - // Minimum execution time: 284_877 nanoseconds. - Weight::from_ref_time(290_043_606) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 22_094 - .saturating_add(Weight::from_ref_time(18_094_219).saturating_mul(r.into())) + // Estimated: `17120 + r * (2400 ±0)` + // Minimum execution time: 374_780 nanoseconds. + Weight::from_ref_time(379_468_453) + .saturating_add(Weight::from_proof_size(17120)) + // Standard Error: 45_809 + .saturating_add(Weight::from_ref_time(17_553_577).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(2400).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1601 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 20]`. fn seal_is_contract(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `882 + r * (19218 ±0)` - // Estimated: `0` - // Minimum execution time: 283_956 nanoseconds. - Weight::from_ref_time(129_690_397) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 531_270 - .saturating_add(Weight::from_ref_time(264_082_418).saturating_mul(r.into())) + // Estimated: `17110 + r * (294100 ±0)` + // Minimum execution time: 374_399 nanoseconds. + Weight::from_ref_time(228_569_211) + .saturating_add(Weight::from_proof_size(17110)) + // Standard Error: 492_562 + .saturating_add(Weight::from_ref_time(251_682_897).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(294100).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1601 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 20]`. fn seal_code_hash(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `889 + r * (19539 ±0)` - // Estimated: `0` - // Minimum execution time: 287_077 nanoseconds. - Weight::from_ref_time(148_155_166) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 466_496 - .saturating_add(Weight::from_ref_time(306_625_930).saturating_mul(r.into())) + // Estimated: `17170 + r * (295700 ±0)` + // Minimum execution time: 375_980 nanoseconds. + Weight::from_ref_time(232_604_331) + .saturating_add(Weight::from_proof_size(17170)) + // Standard Error: 491_912 + .saturating_add(Weight::from_ref_time(299_479_335).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(295700).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 20]`. fn seal_own_code_hash(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `852 + r * (480 ±0)` - // Estimated: `0` - // Minimum execution time: 286_459 nanoseconds. - Weight::from_ref_time(292_826_594) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 27_808 - .saturating_add(Weight::from_ref_time(22_401_931).saturating_mul(r.into())) + // Estimated: `17155 + r * (2400 ±0)` + // Minimum execution time: 375_075 nanoseconds. + Weight::from_ref_time(381_217_372) + .saturating_add(Weight::from_proof_size(17155)) + // Standard Error: 63_950 + .saturating_add(Weight::from_ref_time(21_872_316).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(2400).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 20]`. fn seal_caller_is_origin(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `842 + r * (240 ±0)` - // Estimated: `0` - // Minimum execution time: 284_330 nanoseconds. - Weight::from_ref_time(289_069_701) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 13_666 - .saturating_add(Weight::from_ref_time(11_157_859).saturating_mul(r.into())) + // Estimated: `17080 + r * (1200 ±0)` + // Minimum execution time: 373_260 nanoseconds. + Weight::from_ref_time(377_987_666) + .saturating_add(Weight::from_proof_size(17080)) + // Standard Error: 35_603 + .saturating_add(Weight::from_ref_time(11_274_165).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(1200).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 20]`. fn seal_address(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `846 + r * (480 ±0)` - // Estimated: `0` - // Minimum execution time: 284_506 nanoseconds. - Weight::from_ref_time(290_155_141) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 22_944 - .saturating_add(Weight::from_ref_time(17_992_627).saturating_mul(r.into())) + // Estimated: `17100 + r * (2400 ±0)` + // Minimum execution time: 374_605 nanoseconds. + Weight::from_ref_time(379_395_443) + .saturating_add(Weight::from_proof_size(17100)) + // Standard Error: 49_646 + .saturating_add(Weight::from_ref_time(17_487_585).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(2400).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 20]`. fn seal_gas_left(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `847 + r * (480 ±0)` - // Estimated: `0` - // Minimum execution time: 284_177 nanoseconds. - Weight::from_ref_time(289_314_787) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 24_552 - .saturating_add(Weight::from_ref_time(17_754_919).saturating_mul(r.into())) + // Estimated: `17105 + r * (2400 ±0)` + // Minimum execution time: 374_620 nanoseconds. + Weight::from_ref_time(379_623_792) + .saturating_add(Weight::from_proof_size(17105)) + // Standard Error: 49_990 + .saturating_add(Weight::from_ref_time(17_226_706).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(2400).saturating_mul(r.into())) } /// Storage: System Account (r:2 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 20]`. fn seal_balance(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `1017 + r * (480 ±0)` - // Estimated: `0` - // Minimum execution time: 284_096 nanoseconds. - Weight::from_ref_time(293_655_130) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 56_379 - .saturating_add(Weight::from_ref_time(95_688_575).saturating_mul(r.into())) + // Estimated: `19673 + r * (2456 ±4)` + // Minimum execution time: 374_002 nanoseconds. + Weight::from_ref_time(384_615_649) + .saturating_add(Weight::from_proof_size(19673)) + // Standard Error: 85_633 + .saturating_add(Weight::from_ref_time(95_227_118).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(2456).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 20]`. fn seal_value_transferred(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `856 + r * (480 ±0)` - // Estimated: `0` - // Minimum execution time: 285_967 nanoseconds. - Weight::from_ref_time(288_043_137) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 83_838 - .saturating_add(Weight::from_ref_time(18_256_709).saturating_mul(r.into())) + // Estimated: `17200 + r * (2400 ±0)` + // Minimum execution time: 375_307 nanoseconds. + Weight::from_ref_time(378_389_705) + .saturating_add(Weight::from_proof_size(17200)) + // Standard Error: 42_265 + .saturating_add(Weight::from_ref_time(17_316_680).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(2400).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 20]`. fn seal_minimum_balance(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `854 + r * (480 ±0)` - // Estimated: `0` - // Minimum execution time: 284_060 nanoseconds. - Weight::from_ref_time(290_577_678) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 26_131 - .saturating_add(Weight::from_ref_time(17_560_562).saturating_mul(r.into())) + // Estimated: `17140 + r * (2400 ±0)` + // Minimum execution time: 374_878 nanoseconds. + Weight::from_ref_time(379_364_066) + .saturating_add(Weight::from_proof_size(17140)) + // Standard Error: 49_158 + .saturating_add(Weight::from_ref_time(17_111_145).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(2400).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 20]`. fn seal_block_number(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `851 + r * (480 ±0)` - // Estimated: `0` - // Minimum execution time: 286_068 nanoseconds. - Weight::from_ref_time(290_026_137) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 34_787 - .saturating_add(Weight::from_ref_time(17_597_404).saturating_mul(r.into())) + // Estimated: `17125 + r * (2400 ±0)` + // Minimum execution time: 374_981 nanoseconds. + Weight::from_ref_time(381_539_022) + .saturating_add(Weight::from_proof_size(17125)) + // Standard Error: 61_419 + .saturating_add(Weight::from_ref_time(17_062_381).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(2400).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 20]`. fn seal_now(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `842 + r * (480 ±0)` - // Estimated: `0` - // Minimum execution time: 285_082 nanoseconds. - Weight::from_ref_time(290_487_103) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 22_743 - .saturating_add(Weight::from_ref_time(17_506_771).saturating_mul(r.into())) + // Estimated: `17100 + r * (2400 ±0)` + // Minimum execution time: 374_798 nanoseconds. + Weight::from_ref_time(372_659_915) + .saturating_add(Weight::from_proof_size(17100)) + // Standard Error: 151_499 + .saturating_add(Weight::from_ref_time(18_192_683).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(2400).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) - /// Proof: TransactionPayment NextFeeMultiplier (max_values: Some(1), max_size: Some(16), added: 511, mode: Ignored) + /// Proof: TransactionPayment NextFeeMultiplier (max_values: Some(1), max_size: Some(16), added: 511, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 20]`. fn seal_weight_to_fee(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `919 + r * (800 ±0)` - // Estimated: `0` - // Minimum execution time: 285_309 nanoseconds. - Weight::from_ref_time(296_735_365) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 49_300 - .saturating_add(Weight::from_ref_time(87_678_979).saturating_mul(r.into())) + // Estimated: `18835 + r * (4805 ±0)` + // Minimum execution time: 374_841 nanoseconds. + Weight::from_ref_time(385_475_889) + .saturating_add(Weight::from_proof_size(18835)) + // Standard Error: 106_207 + .saturating_add(Weight::from_ref_time(88_099_987).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(4805).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 20]`. fn seal_gas(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `809 + r * (320 ±0)` - // Estimated: `0` - // Minimum execution time: 136_110 nanoseconds. - Weight::from_ref_time(139_800_659) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 9_674 - .saturating_add(Weight::from_ref_time(8_302_834).saturating_mul(r.into())) + // Estimated: `16955 + r * (1600 ±0)` + // Minimum execution time: 134_436 nanoseconds. + Weight::from_ref_time(137_789_498) + .saturating_add(Weight::from_proof_size(16955)) + // Standard Error: 10_622 + .saturating_add(Weight::from_ref_time(8_144_024).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(1600).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 20]`. fn seal_input(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `844 + r * (480 ±0)` - // Estimated: `0` - // Minimum execution time: 285_238 nanoseconds. - Weight::from_ref_time(289_723_839) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 19_531 - .saturating_add(Weight::from_ref_time(15_590_085).saturating_mul(r.into())) + // Estimated: `17085 + r * (2400 ±0)` + // Minimum execution time: 374_480 nanoseconds. + Weight::from_ref_time(379_723_392) + .saturating_add(Weight::from_proof_size(17085)) + // Standard Error: 50_240 + .saturating_add(Weight::from_ref_time(15_358_041).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(2400).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `n` is `[0, 1024]`. fn seal_input_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `1324` - // Estimated: `0` - // Minimum execution time: 303_189 nanoseconds. - Weight::from_ref_time(323_374_503) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 2_060 - .saturating_add(Weight::from_ref_time(9_799_357).saturating_mul(n.into())) + // Estimated: `19490` + // Minimum execution time: 392_282 nanoseconds. + Weight::from_ref_time(418_943_323) + .saturating_add(Weight::from_proof_size(19490)) + // Standard Error: 4_673 + .saturating_add(Weight::from_ref_time(9_664_301).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 1]`. fn seal_return(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `832 + r * (45 ±0)` - // Estimated: `0` - // Minimum execution time: 280_736 nanoseconds. - Weight::from_ref_time(285_027_920) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 222_526 - .saturating_add(Weight::from_ref_time(1_814_579).saturating_mul(r.into())) + // Estimated: `17030 + r * (225 ±0)` + // Minimum execution time: 372_207 nanoseconds. + Weight::from_ref_time(376_232_444) + .saturating_add(Weight::from_proof_size(17030)) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(225).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `n` is `[0, 1024]`. fn seal_return_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `842` - // Estimated: `0` - // Minimum execution time: 285_559 nanoseconds. - Weight::from_ref_time(290_522_234) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 2_578 - .saturating_add(Weight::from_ref_time(195_134).saturating_mul(n.into())) + // Estimated: `17125` + // Minimum execution time: 374_743 nanoseconds. + Weight::from_ref_time(377_365_053) + .saturating_add(Weight::from_proof_size(17125)) + // Standard Error: 1_073 + .saturating_add(Weight::from_ref_time(231_251).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: System Account (r:3 w:3) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: Contracts DeletionQueue (r:1 w:1) - /// Proof: Contracts DeletionQueue (max_values: Some(1), max_size: Some(16642), added: 17137, mode: Ignored) + /// Proof: Contracts DeletionQueue (max_values: Some(1), max_size: Some(16642), added: 17137, mode: Measured) /// Storage: Contracts OwnerInfoOf (r:1 w:1) - /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Ignored) + /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Measured) /// Storage: System EventTopics (r:3 w:3) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 1]`. fn seal_terminate(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `874 + r * (280 ±0)` - // Estimated: `0` - // Minimum execution time: 282_070 nanoseconds. - Weight::from_ref_time(286_466_489) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 238_285 - .saturating_add(Weight::from_ref_time(58_542_610).saturating_mul(r.into())) + // Estimated: `19880 + r * (11465 ±0)` + // Minimum execution time: 374_873 nanoseconds. + Weight::from_ref_time(378_422_289) + .saturating_add(Weight::from_proof_size(19880)) + // Standard Error: 979_734 + .saturating_add(Weight::from_ref_time(57_035_310).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((6_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_proof_size(11465).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) - /// Proof: RandomnessCollectiveFlip RandomMaterial (max_values: Some(1), max_size: Some(2594), added: 3089, mode: Ignored) + /// Proof: RandomnessCollectiveFlip RandomMaterial (max_values: Some(1), max_size: Some(2594), added: 3089, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 20]`. fn seal_random(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `889 + r * (800 ±0)` - // Estimated: `0` - // Minimum execution time: 284_147 nanoseconds. - Weight::from_ref_time(295_373_881) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 64_682 - .saturating_add(Weight::from_ref_time(114_198_680).saturating_mul(r.into())) + // Estimated: `18643 + r * (4805 ±0)` + // Minimum execution time: 375_001 nanoseconds. + Weight::from_ref_time(382_558_599) + .saturating_add(Weight::from_proof_size(18643)) + // Standard Error: 94_918 + .saturating_add(Weight::from_ref_time(112_973_277).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(4805).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 20]`. fn seal_deposit_event(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `842 + r * (800 ±0)` - // Estimated: `0` - // Minimum execution time: 282_681 nanoseconds. - Weight::from_ref_time(290_974_649) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 77_850 - .saturating_add(Weight::from_ref_time(233_273_622).saturating_mul(r.into())) + // Estimated: `17075 + r * (4000 ±0)` + // Minimum execution time: 372_547 nanoseconds. + Weight::from_ref_time(383_278_916) + .saturating_add(Weight::from_proof_size(17075)) + // Standard Error: 128_339 + .saturating_add(Weight::from_ref_time(229_356_088).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(4000).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:322 w:322) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// 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 { // Proof Size summary in bytes: // Measured: `1778 + t * (2608 ±0) + n * (8 ±0)` - // Estimated: `0` - // Minimum execution time: 1_226_868 nanoseconds. - Weight::from_ref_time(517_031_747) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 342_786 - .saturating_add(Weight::from_ref_time(183_829_556).saturating_mul(t.into())) - // Standard Error: 94_145 - .saturating_add(Weight::from_ref_time(70_675_099).saturating_mul(n.into())) + // Estimated: `21675 + t * (211030 ±0) + n * (50 ±0)` + // Minimum execution time: 1_290_432 nanoseconds. + Weight::from_ref_time(595_859_216) + .saturating_add(Weight::from_proof_size(21675)) + // Standard Error: 602_943 + .saturating_add(Weight::from_ref_time(178_128_149).saturating_mul(t.into())) + // Standard Error: 165_597 + .saturating_add(Weight::from_ref_time(71_475_468).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(t.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((80_u64).saturating_mul(t.into()))) + .saturating_add(Weight::from_proof_size(211030).saturating_mul(t.into())) + .saturating_add(Weight::from_proof_size(50).saturating_mul(n.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 20]`. fn seal_debug_message(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `841 + r * (560 ±0)` - // Estimated: `0` - // Minimum execution time: 143_026 nanoseconds. - Weight::from_ref_time(147_158_038) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 16_662 - .saturating_add(Weight::from_ref_time(14_990_989).saturating_mul(r.into())) + // Estimated: `17065 + r * (2800 ±0)` + // Minimum execution time: 149_020 nanoseconds. + Weight::from_ref_time(152_893_012) + .saturating_add(Weight::from_proof_size(17065)) + // Standard Error: 31_804 + .saturating_add(Weight::from_ref_time(14_497_512).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(2800).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) @@ -2998,1260 +3075,1289 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `125792` // Estimated: `265059` - // Minimum execution time: 412_112 nanoseconds. - Weight::from_ref_time(415_624_011) + // Minimum execution time: 502_589 nanoseconds. + Weight::from_ref_time(506_695_307) .saturating_add(Weight::from_proof_size(265059)) - // Standard Error: 1_190 - .saturating_add(Weight::from_ref_time(797_964).saturating_mul(i.into())) + // Standard Error: 2_148 + .saturating_add(Weight::from_ref_time(814_647).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: Skipped Metadata (r:0 w:0) - /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 10]`. fn seal_set_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `883 + r * (23417 ±0)` - // Estimated: `0` - // Minimum execution time: 286_118 nanoseconds. - Weight::from_ref_time(195_812_951) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 858_501 - .saturating_add(Weight::from_ref_time(485_357_331).saturating_mul(r.into())) + // Estimated: `883 + r * (23417 ±0)` + // Minimum execution time: 375_473 nanoseconds. + Weight::from_ref_time(291_125_810) + .saturating_add(Weight::from_proof_size(883)) + // Standard Error: 824_971 + .saturating_add(Weight::from_ref_time(477_999_695).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((80_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_proof_size(23417).saturating_mul(r.into())) } /// Storage: Skipped Metadata (r:0 w:0) - /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_new_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `12583 + n * (11969 ±0)` - // Estimated: `0` - // Minimum execution time: 433_181 nanoseconds. - Weight::from_ref_time(618_575_096) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 1_696_126 - .saturating_add(Weight::from_ref_time(96_213_633).saturating_mul(n.into())) + // Estimated: `8500 + n * (12813 ±61)` + // Minimum execution time: 515_962 nanoseconds. + Weight::from_ref_time(697_904_030) + .saturating_add(Weight::from_proof_size(8500)) + // Standard Error: 1_684_000 + .saturating_add(Weight::from_ref_time(98_411_710).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(52_u64)) .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(50_u64)) .saturating_add(RocksDbWeight::get().writes((7_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_proof_size(12813).saturating_mul(n.into())) } /// Storage: Skipped Metadata (r:0 w:0) - /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_old_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `15138 + n * (175775 ±0)` - // Estimated: `0` - // Minimum execution time: 433_354 nanoseconds. - Weight::from_ref_time(597_131_349) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 1_509_003 - .saturating_add(Weight::from_ref_time(64_872_907).saturating_mul(n.into())) + // Estimated: `9898 + n * (176855 ±74)` + // Minimum execution time: 515_828 nanoseconds. + Weight::from_ref_time(661_240_495) + .saturating_add(Weight::from_proof_size(9898)) + // Standard Error: 1_338_661 + .saturating_add(Weight::from_ref_time(65_767_819).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(51_u64)) .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(49_u64)) .saturating_add(RocksDbWeight::get().writes((7_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_proof_size(176855).saturating_mul(n.into())) } /// Storage: Skipped Metadata (r:0 w:0) - /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 10]`. fn seal_clear_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `876 + r * (23098 ±0)` - // Estimated: `0` - // Minimum execution time: 286_788 nanoseconds. - Weight::from_ref_time(207_787_332) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 778_284 - .saturating_add(Weight::from_ref_time(474_879_317).saturating_mul(r.into())) + // Estimated: `881 + r * (23097 ±0)` + // Minimum execution time: 375_528 nanoseconds. + Weight::from_ref_time(296_453_612) + .saturating_add(Weight::from_proof_size(881)) + // Standard Error: 809_232 + .saturating_add(Weight::from_ref_time(465_365_815).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((80_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_proof_size(23097).saturating_mul(r.into())) } /// Storage: Skipped Metadata (r:0 w:0) - /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `n` is `[0, 8]`. fn seal_clear_storage_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `14863 + n * (175768 ±0)` - // Estimated: `0` - // Minimum execution time: 397_414 nanoseconds. - Weight::from_ref_time(573_575_029) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 1_630_691 - .saturating_add(Weight::from_ref_time(67_888_226).saturating_mul(n.into())) + // Estimated: `9519 + n * (176867 ±75)` + // Minimum execution time: 480_427 nanoseconds. + Weight::from_ref_time(640_337_570) + .saturating_add(Weight::from_proof_size(9519)) + // Standard Error: 1_497_141 + .saturating_add(Weight::from_ref_time(67_963_696).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(51_u64)) .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(48_u64)) .saturating_add(RocksDbWeight::get().writes((7_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_proof_size(176867).saturating_mul(n.into())) } /// Storage: Skipped Metadata (r:0 w:0) - /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 10]`. fn seal_get_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `878 + r * (23740 ±0)` - // Estimated: `0` - // Minimum execution time: 286_098 nanoseconds. - Weight::from_ref_time(223_637_903) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 669_294 - .saturating_add(Weight::from_ref_time(387_577_627).saturating_mul(r.into())) + // Estimated: `880 + r * (23739 ±0)` + // Minimum execution time: 375_725 nanoseconds. + Weight::from_ref_time(307_839_394) + .saturating_add(Weight::from_proof_size(880)) + // Standard Error: 710_694 + .saturating_add(Weight::from_ref_time(381_738_407).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(23739).saturating_mul(r.into())) } /// Storage: Skipped Metadata (r:0 w:0) - /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `n` is `[0, 8]`. fn seal_get_storage_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `15469 + n * (175775 ±0)` - // Estimated: `0` - // Minimum execution time: 373_335 nanoseconds. - Weight::from_ref_time(531_442_564) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 1_474_336 - .saturating_add(Weight::from_ref_time(154_469_598).saturating_mul(n.into())) + // Estimated: `10010 + n * (176900 ±76)` + // Minimum execution time: 461_871 nanoseconds. + Weight::from_ref_time(605_755_493) + .saturating_add(Weight::from_proof_size(10010)) + // Standard Error: 1_375_044 + .saturating_add(Weight::from_ref_time(161_332_330).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(51_u64)) .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(176900).saturating_mul(n.into())) } /// Storage: Skipped Metadata (r:0 w:0) - /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 10]`. fn seal_contains_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `871 + r * (23100 ±0)` - // Estimated: `0` - // Minimum execution time: 284_183 nanoseconds. - Weight::from_ref_time(223_325_689) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 644_587 - .saturating_add(Weight::from_ref_time(373_628_582).saturating_mul(r.into())) + // Estimated: `873 + r * (23099 ±0)` + // Minimum execution time: 375_325 nanoseconds. + Weight::from_ref_time(305_508_307) + .saturating_add(Weight::from_proof_size(873)) + // Standard Error: 715_627 + .saturating_add(Weight::from_ref_time(369_985_438).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(23099).saturating_mul(r.into())) } /// Storage: Skipped Metadata (r:0 w:0) - /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `n` is `[0, 8]`. fn seal_contains_storage_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `14814 + n * (175782 ±0)` - // Estimated: `0` - // Minimum execution time: 368_310 nanoseconds. - Weight::from_ref_time(512_814_023) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 1_337_352 - .saturating_add(Weight::from_ref_time(62_871_539).saturating_mul(n.into())) + // Estimated: `9502 + n * (176872 ±75)` + // Minimum execution time: 457_128 nanoseconds. + Weight::from_ref_time(582_799_799) + .saturating_add(Weight::from_proof_size(9502)) + // Standard Error: 1_151_126 + .saturating_add(Weight::from_ref_time(63_425_277).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(51_u64)) .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(176872).saturating_mul(n.into())) } /// Storage: Skipped Metadata (r:0 w:0) - /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 10]`. fn seal_take_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `879 + r * (23740 ±0)` - // Estimated: `0` - // Minimum execution time: 287_096 nanoseconds. - Weight::from_ref_time(204_878_281) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 833_763 - .saturating_add(Weight::from_ref_time(483_927_706).saturating_mul(r.into())) + // Estimated: `881 + r * (23739 ±0)` + // Minimum execution time: 375_918 nanoseconds. + Weight::from_ref_time(293_217_646) + .saturating_add(Weight::from_proof_size(881)) + // Standard Error: 840_266 + .saturating_add(Weight::from_ref_time(478_374_701).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((80_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_proof_size(23739).saturating_mul(r.into())) } /// Storage: Skipped Metadata (r:0 w:0) - /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `n` is `[0, 8]`. fn seal_take_storage_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `15470 + n * (175775 ±0)` - // Estimated: `0` - // Minimum execution time: 399_318 nanoseconds. - Weight::from_ref_time(586_658_466) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 1_734_497 - .saturating_add(Weight::from_ref_time(161_047_970).saturating_mul(n.into())) + // Estimated: `10010 + n * (176898 ±76)` + // Minimum execution time: 484_207 nanoseconds. + Weight::from_ref_time(664_065_436) + .saturating_add(Weight::from_proof_size(10010)) + // Standard Error: 1_655_442 + .saturating_add(Weight::from_ref_time(166_258_757).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(51_u64)) .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(48_u64)) .saturating_add(RocksDbWeight::get().writes((7_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_proof_size(176898).saturating_mul(n.into())) } /// Storage: System Account (r:1602 w:1601) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 20]`. fn seal_transfer(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `1393 + r * (3602 ±0)` - // Estimated: `0` - // Minimum execution time: 285_460 nanoseconds. - Weight::from_ref_time(227_848_079) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 717_899 - .saturating_add(Weight::from_ref_time(1_434_112_130).saturating_mul(r.into())) + // Estimated: `21258 + r * (216091 ±0)` + // Minimum execution time: 377_152 nanoseconds. + Weight::from_ref_time(317_470_910) + .saturating_add(Weight::from_proof_size(21258)) + // Standard Error: 994_076 + .saturating_add(Weight::from_ref_time(1_409_416_087).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(RocksDbWeight::get().writes((80_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_proof_size(216091).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1601 w:1601) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:2 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:1602 w:1602) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 20]`. fn seal_call(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `1551 + r * (20511 ±0)` - // Estimated: `0` - // Minimum execution time: 286_947 nanoseconds. - Weight::from_ref_time(288_518_000) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 8_492_544 - .saturating_add(Weight::from_ref_time(21_606_377_662).saturating_mul(r.into())) + // Estimated: `21848 + r * (498651 ±1)` + // Minimum execution time: 376_257 nanoseconds. + Weight::from_ref_time(377_035_000) + .saturating_add(Weight::from_proof_size(21848)) + // Standard Error: 7_966_778 + .saturating_add(Weight::from_ref_time(28_873_495_129).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().reads((160_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((160_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_proof_size(498651).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1536 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:1537 w:1537) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 20]`. fn seal_delegate_call(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + r * (71670 ±0)` - // Estimated: `0` - // Minimum execution time: 285_196 nanoseconds. - Weight::from_ref_time(287_958_000) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 10_345_109 - .saturating_add(Weight::from_ref_time(21_395_365_662).saturating_mul(r.into())) + // Estimated: `17125 + r * (659927 ±822)` + // Minimum execution time: 376_544 nanoseconds. + Weight::from_ref_time(377_490_000) + .saturating_add(Weight::from_proof_size(17125)) + // Standard Error: 8_608_050 + .saturating_add(Weight::from_ref_time(28_568_714_410).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((150_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((75_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_proof_size(659927).saturating_mul(r.into())) } /// Storage: System Account (r:82 w:81) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:81 w:81) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:2 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:82 w:82) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// 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 { // Proof Size summary in bytes: // Measured: `21611 + t * (15369 ±0)` - // Estimated: `0` - // Minimum execution time: 10_540_614 nanoseconds. - Weight::from_ref_time(9_281_766_912) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 5_409_378 - .saturating_add(Weight::from_ref_time(1_449_975_070).saturating_mul(t.into())) - // Standard Error: 8_111 - .saturating_add(Weight::from_ref_time(10_275_108).saturating_mul(c.into())) + // Estimated: `519400 + t * (277320 ±0)` + // Minimum execution time: 10_322_052 nanoseconds. + Weight::from_ref_time(9_248_652_894) + .saturating_add(Weight::from_proof_size(519400)) + // Standard Error: 9_039_638 + .saturating_add(Weight::from_ref_time(1_393_054_441).saturating_mul(t.into())) + // Standard Error: 13_554 + .saturating_add(Weight::from_ref_time(9_819_606).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(167_u64)) .saturating_add(RocksDbWeight::get().reads((81_u64).saturating_mul(t.into()))) .saturating_add(RocksDbWeight::get().writes(163_u64)) .saturating_add(RocksDbWeight::get().writes((81_u64).saturating_mul(t.into()))) + .saturating_add(Weight::from_proof_size(277320).saturating_mul(t.into())) } /// Storage: System Account (r:1602 w:1602) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1601 w:1601) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) - /// Storage: Contracts CodeStorage (r:1601 w:1600) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Storage: Contracts CodeStorage (r:1601 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: Contracts Nonce (r:1 w:1) - /// Proof: Contracts Nonce (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Contracts Nonce (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: Contracts OwnerInfoOf (r:1600 w:1600) - /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Ignored) + /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Measured) /// Storage: System EventTopics (r:1602 w:1602) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 20]`. fn seal_instantiate(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `1613 + r * (25576 ±0)` - // Estimated: `0` - // Minimum execution time: 285_643 nanoseconds. - Weight::from_ref_time(287_472_000) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 25_921_947 - .saturating_add(Weight::from_ref_time(27_745_815_511).saturating_mul(r.into())) + // Estimated: `25698 + r * (1169112 ±1)` + // Minimum execution time: 376_639 nanoseconds. + Weight::from_ref_time(377_892_000) + .saturating_add(Weight::from_proof_size(25698)) + // Standard Error: 21_259_255 + .saturating_add(Weight::from_ref_time(34_131_174_956).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().reads((400_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(5_u64)) - .saturating_add(RocksDbWeight::get().writes((400_u64).saturating_mul(r.into()))) + .saturating_add(RocksDbWeight::get().writes((320_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_proof_size(1169112).saturating_mul(r.into())) } /// Storage: System Account (r:82 w:82) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:81 w:81) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) - /// Storage: Contracts CodeStorage (r:2 w:1) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Storage: Contracts CodeStorage (r:2 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: Contracts Nonce (r:1 w:1) - /// Proof: Contracts Nonce (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Contracts Nonce (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: Contracts OwnerInfoOf (r:1 w:1) - /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Ignored) + /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Measured) /// Storage: System EventTopics (r:82 w:82) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `t` is `[0, 1]`. /// The range of component `i` is `[0, 960]`. /// The range of component `s` is `[0, 960]`. fn seal_instantiate_per_transfer_input_salt_kb(t: u32, i: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `5666 + t * (17 ±0)` - // Estimated: `0` - // Minimum execution time: 129_710_453 nanoseconds. - Weight::from_ref_time(14_347_603_160) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 194_692 - .saturating_add(Weight::from_ref_time(128_837_066).saturating_mul(i.into())) - // Standard Error: 194_692 - .saturating_add(Weight::from_ref_time(127_568_555).saturating_mul(s.into())) + // Estimated: `651914 + t * (2762 ±3)` + // Minimum execution time: 130_366_376 nanoseconds. + Weight::from_ref_time(9_844_607_874) + .saturating_add(Weight::from_proof_size(651914)) + // Standard Error: 100_211_149 + .saturating_add(Weight::from_ref_time(390_481_449).saturating_mul(t.into())) + // Standard Error: 163_416 + .saturating_add(Weight::from_ref_time(126_154_200).saturating_mul(i.into())) + // Standard Error: 163_416 + .saturating_add(Weight::from_ref_time(126_430_874).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(249_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(t.into()))) - .saturating_add(RocksDbWeight::get().writes(247_u64)) + .saturating_add(RocksDbWeight::get().writes(246_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(t.into()))) + .saturating_add(Weight::from_proof_size(2762).saturating_mul(t.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 1]`. fn seal_hash_sha2_256(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `839 + r * (642 ±0)` - // Estimated: `0` - // Minimum execution time: 282_059 nanoseconds. - Weight::from_ref_time(287_215_177) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 273_484 - .saturating_add(Weight::from_ref_time(44_941_522).saturating_mul(r.into())) + // Estimated: `17065 + r * (3210 ±0)` + // Minimum execution time: 373_848 nanoseconds. + Weight::from_ref_time(375_974_597) + .saturating_add(Weight::from_proof_size(17065)) + // Standard Error: 558_923 + .saturating_add(Weight::from_ref_time(42_648_202).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(3210).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `n` is `[0, 1024]`. fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `1641` - // Estimated: `0` - // Minimum execution time: 330_822 nanoseconds. - Weight::from_ref_time(333_012_000) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 53_200 - .saturating_add(Weight::from_ref_time(327_144_474).saturating_mul(n.into())) + // Estimated: `21000` + // Minimum execution time: 417_281 nanoseconds. + Weight::from_ref_time(418_086_000) + .saturating_add(Weight::from_proof_size(21000)) + // Standard Error: 43_883 + .saturating_add(Weight::from_ref_time(324_497_460).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 1]`. fn seal_hash_keccak_256(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `841 + r * (642 ±0)` - // Estimated: `0` - // Minimum execution time: 282_859 nanoseconds. - Weight::from_ref_time(286_293_402) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 187_930 - .saturating_add(Weight::from_ref_time(57_415_297).saturating_mul(r.into())) + // Estimated: `17075 + r * (3210 ±0)` + // Minimum execution time: 372_362 nanoseconds. + Weight::from_ref_time(374_975_677) + .saturating_add(Weight::from_proof_size(17075)) + // Standard Error: 307_932 + .saturating_add(Weight::from_ref_time(57_607_522).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(3210).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `n` is `[0, 1024]`. fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `1643` - // Estimated: `0` - // Minimum execution time: 342_221 nanoseconds. - Weight::from_ref_time(343_250_000) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 67_989 - .saturating_add(Weight::from_ref_time(261_498_077).saturating_mul(n.into())) + // Estimated: `21040` + // Minimum execution time: 431_034 nanoseconds. + Weight::from_ref_time(431_571_000) + .saturating_add(Weight::from_proof_size(21040)) + // Standard Error: 80_071 + .saturating_add(Weight::from_ref_time(261_645_325).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 1]`. fn seal_hash_blake2_256(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `841 + r * (642 ±0)` - // Estimated: `0` - // Minimum execution time: 282_158 nanoseconds. - Weight::from_ref_time(285_783_279) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 200_413 - .saturating_add(Weight::from_ref_time(35_099_520).saturating_mul(r.into())) + // Estimated: `17075 + r * (3210 ±0)` + // Minimum execution time: 372_069 nanoseconds. + Weight::from_ref_time(374_200_608) + .saturating_add(Weight::from_proof_size(17075)) + // Standard Error: 171_799 + .saturating_add(Weight::from_ref_time(32_843_391).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(3210).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `1643` - // Estimated: `0` - // Minimum execution time: 317_376 nanoseconds. - Weight::from_ref_time(319_441_000) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 61_325 - .saturating_add(Weight::from_ref_time(101_080_739).saturating_mul(n.into())) + // Estimated: `21010` + // Minimum execution time: 406_143 nanoseconds. + Weight::from_ref_time(406_744_000) + .saturating_add(Weight::from_proof_size(21010)) + // Standard Error: 48_038 + .saturating_add(Weight::from_ref_time(103_286_295).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 1]`. fn seal_hash_blake2_128(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `841 + r * (679 ±0)` - // Estimated: `0` - // Minimum execution time: 280_403 nanoseconds. - Weight::from_ref_time(282_592_267) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 237_832 - .saturating_add(Weight::from_ref_time(37_056_632).saturating_mul(r.into())) + // Estimated: `17075 + r * (3395 ±0)` + // Minimum execution time: 372_201 nanoseconds. + Weight::from_ref_time(374_049_708) + .saturating_add(Weight::from_proof_size(17075)) + // Standard Error: 387_179 + .saturating_add(Weight::from_ref_time(38_857_191).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(3395).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `1643` - // Estimated: `0` - // Minimum execution time: 315_482 nanoseconds. - Weight::from_ref_time(316_160_000) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 40_926 - .saturating_add(Weight::from_ref_time(100_317_235).saturating_mul(n.into())) + // Estimated: `21050` + // Minimum execution time: 405_819 nanoseconds. + Weight::from_ref_time(406_364_000) + .saturating_add(Weight::from_proof_size(21050)) + // Standard Error: 46_248 + .saturating_add(Weight::from_ref_time(103_189_157).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 1]`. fn seal_ecdsa_recover(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `885 + r * (6083 ±0)` - // Estimated: `0` - // Minimum execution time: 276_155 nanoseconds. - Weight::from_ref_time(278_531_728) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 510_501 - .saturating_add(Weight::from_ref_time(3_056_236_671).saturating_mul(r.into())) + // Estimated: `17295 + r * (30415 ±0)` + // Minimum execution time: 374_836 nanoseconds. + Weight::from_ref_time(379_385_500) + .saturating_add(Weight::from_proof_size(17295)) + // Standard Error: 1_694_427 + .saturating_add(Weight::from_ref_time(3_021_801_000).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(30415).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 1]`. fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `854 + r * (3362 ±0)` - // Estimated: `0` - // Minimum execution time: 276_204 nanoseconds. - Weight::from_ref_time(278_114_283) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 217_508 - .saturating_add(Weight::from_ref_time(737_577_816).saturating_mul(r.into())) + // Estimated: `17140 + r * (16810 ±0)` + // Minimum execution time: 374_223 nanoseconds. + Weight::from_ref_time(376_120_230) + .saturating_add(Weight::from_proof_size(17140)) + // Standard Error: 619_576 + .saturating_add(Weight::from_ref_time(754_257_969).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(16810).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1536 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: Contracts OwnerInfoOf (r:1536 w:1536) - /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Ignored) + /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Measured) /// Storage: System EventTopics (r:1538 w:1538) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 20]`. fn seal_set_code_hash(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + r * (79300 ±0)` - // Estimated: `0` - // Minimum execution time: 276_330 nanoseconds. - Weight::from_ref_time(277_573_000) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 3_652_635 - .saturating_add(Weight::from_ref_time(1_547_361_882).saturating_mul(r.into())) + // Estimated: `64652 + r * (942952 ±829)` + // Minimum execution time: 374_442 nanoseconds. + Weight::from_ref_time(375_591_000) + .saturating_add(Weight::from_proof_size(64652)) + // Standard Error: 3_764_193 + .saturating_add(Weight::from_ref_time(1_552_885_601).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((225_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((150_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_proof_size(942952).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 20]`. fn seal_reentrance_count(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `837 + r * (240 ±0)` - // Estimated: `0` - // Minimum execution time: 276_228 nanoseconds. - Weight::from_ref_time(281_135_551) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 18_737 - .saturating_add(Weight::from_ref_time(10_998_953).saturating_mul(r.into())) + // Estimated: `17055 + r * (1200 ±0)` + // Minimum execution time: 374_922 nanoseconds. + Weight::from_ref_time(376_234_094) + .saturating_add(Weight::from_proof_size(17055)) + // Standard Error: 45_995 + .saturating_add(Weight::from_ref_time(11_606_505).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(1200).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 20]`. fn seal_account_reentrance_count(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `2056 + r * (3153 ±0)` - // Estimated: `0` - // Minimum execution time: 278_157 nanoseconds. - Weight::from_ref_time(300_739_078) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 72_695 - .saturating_add(Weight::from_ref_time(18_499_645).saturating_mul(r.into())) + // Estimated: `21730 + r * (15870 ±2)` + // Minimum execution time: 376_762 nanoseconds. + Weight::from_ref_time(396_934_359) + .saturating_add(Weight::from_proof_size(21730)) + // Standard Error: 68_263 + .saturating_add(Weight::from_ref_time(18_367_270).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_proof_size(15870).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Ignored) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Ignored) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) - /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Ignored) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: Contracts Nonce (r:1 w:1) - /// Proof: Contracts Nonce (max_values: Some(1), max_size: Some(8), added: 503, mode: Ignored) + /// Proof: Contracts Nonce (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) - /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Ignored) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 20]`. fn seal_instantiation_nonce(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `840 + r * (240 ±0)` - // Estimated: `0` - // Minimum execution time: 275_532 nanoseconds. - Weight::from_ref_time(281_299_677) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 21_719 - .saturating_add(Weight::from_ref_time(9_513_444).saturating_mul(r.into())) + // Estimated: `18405 + r * (1440 ±0)` + // Minimum execution time: 374_257 nanoseconds. + Weight::from_ref_time(380_453_380) + .saturating_add(Weight::from_proof_size(18405)) + // Standard Error: 42_718 + .saturating_add(Weight::from_ref_time(9_355_253).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) + .saturating_add(Weight::from_proof_size(1440).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64const(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 856 nanoseconds. - Weight::from_ref_time(1_054_710) + // Minimum execution time: 788 nanoseconds. + Weight::from_ref_time(1_209_829) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 273 - .saturating_add(Weight::from_ref_time(411_548).saturating_mul(r.into())) + // Standard Error: 3_436 + .saturating_add(Weight::from_ref_time(409_858).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64load(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 980 nanoseconds. - Weight::from_ref_time(1_463_182) + // Minimum execution time: 955 nanoseconds. + Weight::from_ref_time(1_526_327) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 415 - .saturating_add(Weight::from_ref_time(1_063_436).saturating_mul(r.into())) + // Standard Error: 2_399 + .saturating_add(Weight::from_ref_time(1_084_504).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64store(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 991 nanoseconds. - Weight::from_ref_time(1_521_750) + // Minimum execution time: 967 nanoseconds. + Weight::from_ref_time(1_576_183) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 8_499 - .saturating_add(Weight::from_ref_time(997_972).saturating_mul(r.into())) + // Standard Error: 5_719 + .saturating_add(Weight::from_ref_time(1_006_742).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_select(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 833 nanoseconds. - Weight::from_ref_time(1_152_048) + // Minimum execution time: 849 nanoseconds. + Weight::from_ref_time(1_106_539) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 392 - .saturating_add(Weight::from_ref_time(1_147_506).saturating_mul(r.into())) + // Standard Error: 445 + .saturating_add(Weight::from_ref_time(1_149_752).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_if(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 866 nanoseconds. - Weight::from_ref_time(1_154_637) + // Minimum execution time: 829 nanoseconds. + Weight::from_ref_time(1_171_360) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 5_131 - .saturating_add(Weight::from_ref_time(1_320_580).saturating_mul(r.into())) + // Standard Error: 552 + .saturating_add(Weight::from_ref_time(1_309_914).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_br(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 849 nanoseconds. - Weight::from_ref_time(1_073_940) + // Minimum execution time: 835 nanoseconds. + Weight::from_ref_time(1_125_578) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 639 - .saturating_add(Weight::from_ref_time(642_885).saturating_mul(r.into())) + // Standard Error: 374 + .saturating_add(Weight::from_ref_time(641_683).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_br_if(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 855 nanoseconds. - Weight::from_ref_time(728_631) + // Minimum execution time: 816 nanoseconds. + Weight::from_ref_time(1_032_093) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 1_730 - .saturating_add(Weight::from_ref_time(979_839).saturating_mul(r.into())) + // Standard Error: 811 + .saturating_add(Weight::from_ref_time(956_228).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_br_table(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 852 nanoseconds. - Weight::from_ref_time(658_935) + // Minimum execution time: 801 nanoseconds. + Weight::from_ref_time(816_764) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 2_373 - .saturating_add(Weight::from_ref_time(1_172_585).saturating_mul(r.into())) + // Standard Error: 2_669 + .saturating_add(Weight::from_ref_time(1_166_556).saturating_mul(r.into())) } /// The range of component `e` is `[1, 256]`. fn instr_br_table_per_entry(e: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_577 nanoseconds. - Weight::from_ref_time(2_872_555) + // Minimum execution time: 2_639 nanoseconds. + Weight::from_ref_time(2_905_554) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 70 - .saturating_add(Weight::from_ref_time(4_237).saturating_mul(e.into())) + // Standard Error: 62 + .saturating_add(Weight::from_ref_time(4_438).saturating_mul(e.into())) } /// The range of component `r` is `[0, 50]`. fn instr_call(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 833 nanoseconds. - Weight::from_ref_time(874_000) + // Minimum execution time: 831 nanoseconds. + Weight::from_ref_time(1_729_584) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 30_863 - .saturating_add(Weight::from_ref_time(2_591_963).saturating_mul(r.into())) + // Standard Error: 33_753 + .saturating_add(Weight::from_ref_time(2_380_315).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_call_indirect(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 992 nanoseconds. - Weight::from_ref_time(2_772_709) + // Minimum execution time: 964 nanoseconds. + Weight::from_ref_time(2_445_291) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 3_822 - .saturating_add(Weight::from_ref_time(3_070_825).saturating_mul(r.into())) + // Standard Error: 3_285 + .saturating_add(Weight::from_ref_time(2_938_681).saturating_mul(r.into())) } /// The range of component `p` is `[0, 128]`. fn instr_call_indirect_per_param(p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_766 nanoseconds. - Weight::from_ref_time(5_559_951) + // Minimum execution time: 4_809 nanoseconds. + Weight::from_ref_time(6_763_286) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 315 - .saturating_add(Weight::from_ref_time(227_249).saturating_mul(p.into())) + // Standard Error: 3_994 + .saturating_add(Weight::from_ref_time(217_632).saturating_mul(p.into())) } /// The range of component `l` is `[0, 1024]`. fn instr_call_per_local(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_215 nanoseconds. - Weight::from_ref_time(4_697_732) + // Minimum execution time: 3_138 nanoseconds. + Weight::from_ref_time(3_894_816) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 99 - .saturating_add(Weight::from_ref_time(46_431).saturating_mul(l.into())) + // Standard Error: 131 + .saturating_add(Weight::from_ref_time(91_699).saturating_mul(l.into())) } /// The range of component `r` is `[0, 50]`. fn instr_local_get(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_193 nanoseconds. - Weight::from_ref_time(2_472_277) + // Minimum execution time: 2_959 nanoseconds. + Weight::from_ref_time(3_271_550) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 374 - .saturating_add(Weight::from_ref_time(459_651).saturating_mul(r.into())) + // Standard Error: 223 + .saturating_add(Weight::from_ref_time(460_056).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_local_set(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_112 nanoseconds. - Weight::from_ref_time(2_388_132) + // Minimum execution time: 2_970 nanoseconds. + Weight::from_ref_time(3_216_157) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 380 - .saturating_add(Weight::from_ref_time(485_216).saturating_mul(r.into())) + // Standard Error: 413 + .saturating_add(Weight::from_ref_time(485_842).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_local_tee(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_219 nanoseconds. - Weight::from_ref_time(2_419_568) + // Minimum execution time: 2_980 nanoseconds. + Weight::from_ref_time(3_323_878) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 402 - .saturating_add(Weight::from_ref_time(658_484).saturating_mul(r.into())) + // Standard Error: 2_652 + .saturating_add(Weight::from_ref_time(660_257).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_global_get(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 959 nanoseconds. - Weight::from_ref_time(1_321_004) + // Minimum execution time: 917 nanoseconds. + Weight::from_ref_time(1_445_816) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 480 - .saturating_add(Weight::from_ref_time(898_447).saturating_mul(r.into())) + // Standard Error: 5_642 + .saturating_add(Weight::from_ref_time(894_521).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_global_set(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 934 nanoseconds. - Weight::from_ref_time(1_264_350) + // Minimum execution time: 965 nanoseconds. + Weight::from_ref_time(1_373_722) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 1_031 - .saturating_add(Weight::from_ref_time(922_243).saturating_mul(r.into())) + // Standard Error: 1_157 + .saturating_add(Weight::from_ref_time(917_643).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_memory_current(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 941 nanoseconds. - Weight::from_ref_time(1_229_407) + // Minimum execution time: 982 nanoseconds. + Weight::from_ref_time(1_240_280) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 507 - .saturating_add(Weight::from_ref_time(824_206).saturating_mul(r.into())) + // Standard Error: 308 + .saturating_add(Weight::from_ref_time(817_972).saturating_mul(r.into())) } /// The range of component `r` is `[0, 1]`. fn instr_memory_grow(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 870 nanoseconds. - Weight::from_ref_time(946_681) + // Minimum execution time: 858 nanoseconds. + Weight::from_ref_time(962_183) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 7_248 - .saturating_add(Weight::from_ref_time(179_759_218).saturating_mul(r.into())) + // Standard Error: 6_701 + .saturating_add(Weight::from_ref_time(239_704_216).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64clz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 843 nanoseconds. - Weight::from_ref_time(1_105_279) + // Minimum execution time: 807 nanoseconds. + Weight::from_ref_time(1_132_872) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 251 - .saturating_add(Weight::from_ref_time(633_218).saturating_mul(r.into())) + // Standard Error: 303 + .saturating_add(Weight::from_ref_time(633_832).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ctz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 843 nanoseconds. - Weight::from_ref_time(1_119_719) + // Minimum execution time: 823 nanoseconds. + Weight::from_ref_time(1_267_518) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 248 - .saturating_add(Weight::from_ref_time(633_064).saturating_mul(r.into())) + // Standard Error: 483 + .saturating_add(Weight::from_ref_time(632_620).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64popcnt(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 865 nanoseconds. - Weight::from_ref_time(1_394_651) + // Minimum execution time: 857 nanoseconds. + Weight::from_ref_time(1_105_214) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 9_898 - .saturating_add(Weight::from_ref_time(630_054).saturating_mul(r.into())) + // Standard Error: 285 + .saturating_add(Weight::from_ref_time(635_039).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64eqz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 831 nanoseconds. - Weight::from_ref_time(1_095_288) + // Minimum execution time: 821 nanoseconds. + Weight::from_ref_time(750_223) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 271 - .saturating_add(Weight::from_ref_time(650_578).saturating_mul(r.into())) + // Standard Error: 15_923 + .saturating_add(Weight::from_ref_time(686_322).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendsi32(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 835 nanoseconds. - Weight::from_ref_time(1_128_234) + // Minimum execution time: 797 nanoseconds. + Weight::from_ref_time(1_145_072) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 239 - .saturating_add(Weight::from_ref_time(615_970).saturating_mul(r.into())) + // Standard Error: 311 + .saturating_add(Weight::from_ref_time(618_147).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendui32(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 839 nanoseconds. - Weight::from_ref_time(1_111_296) + // Minimum execution time: 803 nanoseconds. + Weight::from_ref_time(1_139_498) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 303 - .saturating_add(Weight::from_ref_time(616_831).saturating_mul(r.into())) + // Standard Error: 284 + .saturating_add(Weight::from_ref_time(617_393).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i32wrapi64(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 839 nanoseconds. - Weight::from_ref_time(1_082_700) + // Minimum execution time: 814 nanoseconds. + Weight::from_ref_time(1_099_405) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 236 - .saturating_add(Weight::from_ref_time(617_371).saturating_mul(r.into())) + // Standard Error: 663 + .saturating_add(Weight::from_ref_time(618_565).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64eq(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 837 nanoseconds. - Weight::from_ref_time(1_249_666) + // Minimum execution time: 819 nanoseconds. + Weight::from_ref_time(1_199_220) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 836 - .saturating_add(Weight::from_ref_time(904_457).saturating_mul(r.into())) + // Standard Error: 485 + .saturating_add(Weight::from_ref_time(906_878).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ne(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 818 nanoseconds. - Weight::from_ref_time(1_624_057) + // Minimum execution time: 822 nanoseconds. + Weight::from_ref_time(274_212) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 5_906 - .saturating_add(Weight::from_ref_time(893_488).saturating_mul(r.into())) + // Standard Error: 29_294 + .saturating_add(Weight::from_ref_time(971_608).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64lts(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 836 nanoseconds. - Weight::from_ref_time(1_973_044) + // Minimum execution time: 796 nanoseconds. + Weight::from_ref_time(1_396_586) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 7_556 - .saturating_add(Weight::from_ref_time(885_369).saturating_mul(r.into())) + // Standard Error: 7_205 + .saturating_add(Weight::from_ref_time(903_202).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ltu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 846 nanoseconds. - Weight::from_ref_time(1_088_223) + // Minimum execution time: 833 nanoseconds. + Weight::from_ref_time(1_115_115) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 531 - .saturating_add(Weight::from_ref_time(909_313).saturating_mul(r.into())) + // Standard Error: 310 + .saturating_add(Weight::from_ref_time(908_195).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64gts(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 842 nanoseconds. - Weight::from_ref_time(1_435_966) + // Minimum execution time: 854 nanoseconds. + Weight::from_ref_time(1_170_419) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 3_824 - .saturating_add(Weight::from_ref_time(898_198).saturating_mul(r.into())) + // Standard Error: 298 + .saturating_add(Weight::from_ref_time(907_171).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64gtu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 846 nanoseconds. - Weight::from_ref_time(1_154_015) + // Minimum execution time: 822 nanoseconds. + Weight::from_ref_time(1_186_349) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 319 - .saturating_add(Weight::from_ref_time(918_083).saturating_mul(r.into())) + // Standard Error: 302 + .saturating_add(Weight::from_ref_time(917_857).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64les(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 848 nanoseconds. - Weight::from_ref_time(1_155_323) + // Minimum execution time: 807 nanoseconds. + Weight::from_ref_time(1_127_093) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 307 - .saturating_add(Weight::from_ref_time(906_516).saturating_mul(r.into())) + // Standard Error: 1_891 + .saturating_add(Weight::from_ref_time(910_738).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64leu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 877 nanoseconds. - Weight::from_ref_time(1_629_210) + // Minimum execution time: 819 nanoseconds. + Weight::from_ref_time(1_143_022) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 8_175 - .saturating_add(Weight::from_ref_time(906_657).saturating_mul(r.into())) + // Standard Error: 309 + .saturating_add(Weight::from_ref_time(919_047).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ges(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 843 nanoseconds. - Weight::from_ref_time(1_126_252) + // Minimum execution time: 788 nanoseconds. + Weight::from_ref_time(1_116_914) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 251 - .saturating_add(Weight::from_ref_time(907_052).saturating_mul(r.into())) + // Standard Error: 643 + .saturating_add(Weight::from_ref_time(911_159).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64geu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 852 nanoseconds. - Weight::from_ref_time(1_497_667) + // Minimum execution time: 791 nanoseconds. + Weight::from_ref_time(1_123_747) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 7_593 - .saturating_add(Weight::from_ref_time(897_474).saturating_mul(r.into())) + // Standard Error: 583 + .saturating_add(Weight::from_ref_time(910_242).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64add(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 856 nanoseconds. - Weight::from_ref_time(1_350_390) + // Minimum execution time: 787 nanoseconds. + Weight::from_ref_time(1_109_471) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 2_625 - .saturating_add(Weight::from_ref_time(889_609).saturating_mul(r.into())) + // Standard Error: 305 + .saturating_add(Weight::from_ref_time(897_608).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64sub(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 841 nanoseconds. - Weight::from_ref_time(2_677_235) + // Minimum execution time: 821 nanoseconds. + Weight::from_ref_time(1_098_631) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 11_507 - .saturating_add(Weight::from_ref_time(846_704).saturating_mul(r.into())) + // Standard Error: 523 + .saturating_add(Weight::from_ref_time(887_814).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64mul(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 846 nanoseconds. - Weight::from_ref_time(1_148_206) + // Minimum execution time: 794 nanoseconds. + Weight::from_ref_time(1_166_332) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 393 - .saturating_add(Weight::from_ref_time(884_886).saturating_mul(r.into())) + // Standard Error: 384 + .saturating_add(Weight::from_ref_time(885_584).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64divs(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 865 nanoseconds. - Weight::from_ref_time(2_862_483) + // Minimum execution time: 822 nanoseconds. + Weight::from_ref_time(1_155_826) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 16_413 - .saturating_add(Weight::from_ref_time(1_481_623).saturating_mul(r.into())) + // Standard Error: 521 + .saturating_add(Weight::from_ref_time(1_520_958).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64divu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_443 nanoseconds. - Weight::from_ref_time(1_086_902) + // Minimum execution time: 881 nanoseconds. + Weight::from_ref_time(1_158_125) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 2_245 - .saturating_add(Weight::from_ref_time(1_463_145).saturating_mul(r.into())) + // Standard Error: 624 + .saturating_add(Weight::from_ref_time(1_458_378).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64rems(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 878 nanoseconds. - Weight::from_ref_time(1_130_306) + // Minimum execution time: 827 nanoseconds. + Weight::from_ref_time(1_209_535) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 475 - .saturating_add(Weight::from_ref_time(1_522_011).saturating_mul(r.into())) + // Standard Error: 399 + .saturating_add(Weight::from_ref_time(1_547_640).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64remu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 827 nanoseconds. - Weight::from_ref_time(1_197_053) + // Minimum execution time: 801 nanoseconds. + Weight::from_ref_time(1_313_872) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 474 - .saturating_add(Weight::from_ref_time(1_449_062).saturating_mul(r.into())) + // Standard Error: 2_175 + .saturating_add(Weight::from_ref_time(1_449_416).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64and(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 847 nanoseconds. - Weight::from_ref_time(1_152_423) + // Minimum execution time: 827 nanoseconds. + Weight::from_ref_time(1_093_874) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 296 - .saturating_add(Weight::from_ref_time(895_541).saturating_mul(r.into())) + // Standard Error: 708 + .saturating_add(Weight::from_ref_time(901_450).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64or(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 876 nanoseconds. - Weight::from_ref_time(1_169_485) + // Minimum execution time: 824 nanoseconds. + Weight::from_ref_time(1_164_076) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 571 - .saturating_add(Weight::from_ref_time(932_659).saturating_mul(r.into())) + // Standard Error: 623 + .saturating_add(Weight::from_ref_time(897_579).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64xor(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 856 nanoseconds. - Weight::from_ref_time(1_155_127) + // Minimum execution time: 789 nanoseconds. + Weight::from_ref_time(1_113_915) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 256 - .saturating_add(Weight::from_ref_time(895_663).saturating_mul(r.into())) + // Standard Error: 390 + .saturating_add(Weight::from_ref_time(897_354).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64shl(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 871 nanoseconds. - Weight::from_ref_time(1_139_722) + // Minimum execution time: 811 nanoseconds. + Weight::from_ref_time(1_117_366) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 367 - .saturating_add(Weight::from_ref_time(903_115).saturating_mul(r.into())) + // Standard Error: 437 + .saturating_add(Weight::from_ref_time(903_759).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64shrs(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 853 nanoseconds. - Weight::from_ref_time(1_155_542) + // Minimum execution time: 846 nanoseconds. + Weight::from_ref_time(1_103_954) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 541 - .saturating_add(Weight::from_ref_time(901_635).saturating_mul(r.into())) + // Standard Error: 414 + .saturating_add(Weight::from_ref_time(903_429).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64shru(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 866 nanoseconds. - Weight::from_ref_time(2_260_588) + // Minimum execution time: 803 nanoseconds. + Weight::from_ref_time(1_124_328) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 12_944 - .saturating_add(Weight::from_ref_time(877_790).saturating_mul(r.into())) + // Standard Error: 410 + .saturating_add(Weight::from_ref_time(903_216).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotl(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 851 nanoseconds. - Weight::from_ref_time(1_627_816) + // Minimum execution time: 810 nanoseconds. + Weight::from_ref_time(1_131_433) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 4_004 - .saturating_add(Weight::from_ref_time(887_929).saturating_mul(r.into())) + // Standard Error: 402 + .saturating_add(Weight::from_ref_time(903_381).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotr(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 874 nanoseconds. - Weight::from_ref_time(2_611_817) + // Minimum execution time: 807 nanoseconds. + Weight::from_ref_time(1_144_933) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 10_026 - .saturating_add(Weight::from_ref_time(862_138).saturating_mul(r.into())) + // Standard Error: 373 + .saturating_add(Weight::from_ref_time(902_918).saturating_mul(r.into())) } } diff --git a/primitives/weights/src/weight_v2.rs b/primitives/weights/src/weight_v2.rs index 3a15b117955f2..52e148f30392d 100644 --- a/primitives/weights/src/weight_v2.rs +++ b/primitives/weights/src/weight_v2.rs @@ -232,6 +232,38 @@ impl Weight { Some(Self { ref_time, proof_size }) } + /// Calculates how many `other` fit into `self`. + /// + /// Divides each component of `self` against the same component of `other`. Returns the minimum + /// of all those divisions. Returns `None` in case **all** components of `other` are zero. + /// + /// This returns `Some` even if some components of `other` are zero as long as there is at least + /// one non-zero component in `other`. The devision for this particular component will then + /// yield the maximum value (e.g u64::MAX). This is because we assume not every operation and + /// hence each `Weight` will necessarily use each resource. + pub const fn checked_div_per_component(self, other: &Self) -> Option { + let mut all_zero = true; + let ref_time = match self.ref_time.checked_div(other.ref_time) { + Some(ref_time) => { + all_zero = false; + ref_time + }, + None => u64::MAX, + }; + let proof_size = match self.proof_size.checked_div(other.proof_size) { + Some(proof_size) => { + all_zero = false; + proof_size + }, + None => u64::MAX, + }; + if all_zero { + None + } else { + Some(if ref_time < proof_size { ref_time } else { proof_size }) + } + } + /// Try to increase `self` by `amount` via checked addition. pub fn checked_accrue(&mut self, amount: Self) -> Option<()> { self.checked_add(&amount).map(|new_self| *self = new_self) @@ -582,4 +614,48 @@ mod tests { assert!(weight.checked_reduce(Weight::from_parts(0, 18)).is_some()); assert!(weight.is_zero()); } + + #[test] + fn checked_div_per_component_works() { + assert_eq!( + Weight::from_parts(10, 20).checked_div_per_component(&Weight::from_parts(2, 10)), + Some(2) + ); + assert_eq!( + Weight::from_parts(10, 200).checked_div_per_component(&Weight::from_parts(2, 10)), + Some(5) + ); + assert_eq!( + Weight::from_parts(10, 200).checked_div_per_component(&Weight::from_parts(1, 10)), + Some(10) + ); + assert_eq!( + Weight::from_parts(10, 200).checked_div_per_component(&Weight::from_parts(2, 1)), + Some(5) + ); + assert_eq!( + Weight::from_parts(10, 200).checked_div_per_component(&Weight::from_parts(0, 10)), + Some(20) + ); + assert_eq!( + Weight::from_parts(10, 200).checked_div_per_component(&Weight::from_parts(1, 0)), + Some(10) + ); + assert_eq!( + Weight::from_parts(0, 200).checked_div_per_component(&Weight::from_parts(2, 3)), + Some(0) + ); + assert_eq!( + Weight::from_parts(10, 0).checked_div_per_component(&Weight::from_parts(2, 3)), + Some(0) + ); + assert_eq!( + Weight::from_parts(10, 200).checked_div_per_component(&Weight::from_parts(0, 0)), + None, + ); + assert_eq!( + Weight::from_parts(0, 0).checked_div_per_component(&Weight::from_parts(0, 0)), + None, + ); + } } From 528e71fabf4cbf329cea6377efd1f24e3e3d4da8 Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Thu, 16 Feb 2023 12:09:32 +0100 Subject: [PATCH 399/715] [ci] Move publish-crates-locally to publish stage (#13395) --- scripts/ci/gitlab/pipeline/publish.yml | 18 ++++++++++++++++++ scripts/ci/gitlab/pipeline/test.yml | 18 ------------------ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/scripts/ci/gitlab/pipeline/publish.yml b/scripts/ci/gitlab/pipeline/publish.yml index 9f075903697a5..3052658cde4e3 100644 --- a/scripts/ci/gitlab/pipeline/publish.yml +++ b/scripts/ci/gitlab/pipeline/publish.yml @@ -238,3 +238,21 @@ publish-crates-manual: extends: .publish-crates-template when: manual interruptible: false + +publish-crates-locally: + stage: publish + extends: + - .test-refs + - .crates-publishing-template + # When lots of crates are taken into account (for example on master where all crates are tested) + # the job might take a long time, as evidenced by: + # https://gitlab.parity.io/parity/mirrors/substrate/-/jobs/2269364 + timeout: 4h + script: + - rusty-cachier snapshot create + - git clone + --depth 1 + --branch "$RELENG_SCRIPTS_BRANCH" + https://github.com/paritytech/releng-scripts.git + - CRATESIO_TARGET_INSTANCE=local ./releng-scripts/publish-crates + - rusty-cachier cache upload diff --git a/scripts/ci/gitlab/pipeline/test.yml b/scripts/ci/gitlab/pipeline/test.yml index 02e05752fd01f..732b8c0fd699c 100644 --- a/scripts/ci/gitlab/pipeline/test.yml +++ b/scripts/ci/gitlab/pipeline/test.yml @@ -416,24 +416,6 @@ cargo-check-each-crate: - if [ "$CI_NODE_INDEX" == 1 ]; then rusty-cachier cache upload; fi parallel: 2 -publish-crates-locally: - stage: test - extends: - - .test-refs - - .crates-publishing-template - # When lots of crates are taken into account (for example on master where all crates are tested) - # the job might take a long time, as evidenced by: - # https://gitlab.parity.io/parity/mirrors/substrate/-/jobs/2269364 - timeout: 4h - script: - - rusty-cachier snapshot create - - git clone - --depth 1 - --branch "$RELENG_SCRIPTS_BRANCH" - https://github.com/paritytech/releng-scripts.git - - CRATESIO_TARGET_INSTANCE=local ./releng-scripts/publish-crates - - rusty-cachier cache upload - cargo-check-each-crate-macos: stage: test extends: From c24969ab6d6dcbf60564fedeeaf035792c57e53a Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Thu, 16 Feb 2023 13:10:40 +0100 Subject: [PATCH 400/715] [ci] Add dependencies for publish-crates (#13397) * [ci] Add dependencies for publishsing crates * apply review comments * fix needs --- scripts/ci/gitlab/pipeline/publish.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/scripts/ci/gitlab/pipeline/publish.yml b/scripts/ci/gitlab/pipeline/publish.yml index 3052658cde4e3..5b06711161023 100644 --- a/scripts/ci/gitlab/pipeline/publish.yml +++ b/scripts/ci/gitlab/pipeline/publish.yml @@ -233,13 +233,17 @@ publish-draft-release: publish-crates: extends: .publish-crates-template + # publish-crates should only be run if publish-crates-locally passes + needs: + - job: check-crate-publishing + artifacts: false publish-crates-manual: extends: .publish-crates-template when: manual interruptible: false -publish-crates-locally: +check-crate-publishing: stage: publish extends: - .test-refs From 6a36704c40738bc0cdb59761f871aba9918651ab Mon Sep 17 00:00:00 2001 From: Sergejs Kostjucenko <85877331+sergejparity@users.noreply.github.com> Date: Thu, 16 Feb 2023 14:37:59 +0200 Subject: [PATCH 401/715] fix image name (#13398) --- scripts/ci/gitlab/pipeline/publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/ci/gitlab/pipeline/publish.yml b/scripts/ci/gitlab/pipeline/publish.yml index 5b06711161023..557a7f2127358 100644 --- a/scripts/ci/gitlab/pipeline/publish.yml +++ b/scripts/ci/gitlab/pipeline/publish.yml @@ -55,7 +55,7 @@ - .kubernetes-env - .publish-refs variables: - CI_IMAGE: paritytech/docker-description + CI_IMAGE: paritytech/dockerhub-description DOCKERHUB_REPOSITORY: parity/$PRODUCT DOCKER_USERNAME: $Docker_Hub_User_Parity DOCKER_PASSWORD: $Docker_Hub_Pass_Parity From 46c1bd5b77f8dc7ed68fa021255985f17194fe7c Mon Sep 17 00:00:00 2001 From: dharjeezy Date: Thu, 16 Feb 2023 13:45:57 +0100 Subject: [PATCH 402/715] client/beefy: add more metrics for production visibility (#12910) * few beefy metrics * more beefy metrics * some beefy metrics * some beefy metrics * more metrics * other metrics * fix tests * merge changes * Apply suggestions from code review * client/beefy: fix metrics * client/beefy: separate metrics per component, avoid double registering * client/beefy: deduplicate metrics registration code * remove unused metric * impl review suggestions --------- Co-authored-by: Adrian Catangiu --- .../incoming_requests_handler.rs | 20 +- .../outgoing_requests_engine.rs | 11 + client/beefy/src/import.rs | 10 +- client/beefy/src/lib.rs | 30 +-- client/beefy/src/metrics.rs | 249 +++++++++++++++++- client/beefy/src/tests.rs | 3 +- client/beefy/src/worker.rs | 42 ++- 7 files changed, 316 insertions(+), 49 deletions(-) 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 d3be73dc06a43..854ece11cf93c 100644 --- a/client/beefy/src/communication/request_response/incoming_requests_handler.rs +++ b/client/beefy/src/communication/request_response/incoming_requests_handler.rs @@ -29,8 +29,13 @@ use sc_network_common::protocol::ProtocolName; use sp_runtime::traits::Block; use std::{marker::PhantomData, sync::Arc}; -use crate::communication::request_response::{ - on_demand_justifications_protocol_config, Error, JustificationRequest, BEEFY_SYNC_LOG_TARGET, +use crate::{ + communication::request_response::{ + on_demand_justifications_protocol_config, Error, JustificationRequest, + BEEFY_SYNC_LOG_TARGET, + }, + metric_inc, + metrics::{register_metrics, OnDemandIncomingRequestsMetrics}, }; /// A request coming in, including a sender for sending responses. @@ -119,6 +124,7 @@ pub struct BeefyJustifsRequestHandler { pub(crate) request_receiver: IncomingRequestReceiver, pub(crate) justif_protocol_name: ProtocolName, pub(crate) client: Arc, + pub(crate) metrics: Option, pub(crate) _block: PhantomData, } @@ -132,12 +138,16 @@ where genesis_hash: Hash, fork_id: Option<&str>, client: Arc, + prometheus_registry: Option, ) -> (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) + let metrics = register_metrics(prometheus_registry); + ( + Self { request_receiver, justif_protocol_name, client, metrics, _block: PhantomData }, + config, + ) } /// Network request-response protocol name used by this handler. @@ -180,12 +190,14 @@ where let peer = request.peer; match self.handle_request(request) { Ok(()) => { + metric_inc!(self, beefy_successful_justification_responses); debug!( target: BEEFY_SYNC_LOG_TARGET, "🥩 Handled BEEFY justification request from {:?}.", peer ) }, Err(e) => { + metric_inc!(self, beefy_failed_justification_responses); // TODO (issue #12293): apply reputation changes here based on error type. debug!( target: BEEFY_SYNC_LOG_TARGET, 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 766480f781ff5..3e0d6e47d9432 100644 --- a/client/beefy/src/communication/request_response/outgoing_requests_engine.rs +++ b/client/beefy/src/communication/request_response/outgoing_requests_engine.rs @@ -34,6 +34,8 @@ use std::{collections::VecDeque, result::Result, sync::Arc}; use crate::{ communication::request_response::{Error, JustificationRequest, BEEFY_SYNC_LOG_TARGET}, justification::{decode_and_verify_finality_proof, BeefyVersionedFinalityProof}, + metric_inc, + metrics::{register_metrics, OnDemandOutgoingRequestsMetrics}, KnownPeers, }; @@ -61,6 +63,7 @@ pub struct OnDemandJustificationsEngine { peers_cache: VecDeque, state: State, + metrics: Option, } impl OnDemandJustificationsEngine { @@ -68,13 +71,16 @@ impl OnDemandJustificationsEngine { network: Arc, protocol_name: ProtocolName, live_peers: Arc>>, + prometheus_registry: Option, ) -> Self { + let metrics = register_metrics(prometheus_registry); Self { network, protocol_name, live_peers, peers_cache: VecDeque::new(), state: State::Idle, + metrics, } } @@ -130,6 +136,7 @@ impl OnDemandJustificationsEngine { if let Some(peer) = self.try_next_peer() { self.request_from_peer(peer, RequestInfo { block, active_set }); } else { + metric_inc!(self, beefy_on_demand_justification_no_peer_to_request_from); debug!( target: BEEFY_SYNC_LOG_TARGET, "🥩 no good peers to request justif #{:?} from", block @@ -159,6 +166,7 @@ impl OnDemandJustificationsEngine { ) -> Result, Error> { response .map_err(|e| { + metric_inc!(self, beefy_on_demand_justification_peer_hang_up); debug!( target: BEEFY_SYNC_LOG_TARGET, "🥩 for on demand justification #{:?}, peer {:?} hung up: {:?}", @@ -169,6 +177,7 @@ impl OnDemandJustificationsEngine { Error::InvalidResponse })? .map_err(|e| { + metric_inc!(self, beefy_on_demand_justification_peer_error); debug!( target: BEEFY_SYNC_LOG_TARGET, "🥩 for on demand justification #{:?}, peer {:?} error: {:?}", @@ -185,6 +194,7 @@ impl OnDemandJustificationsEngine { &req_info.active_set, ) .map_err(|e| { + metric_inc!(self, beefy_on_demand_justification_invalid_proof); debug!( target: BEEFY_SYNC_LOG_TARGET, "🥩 for on demand justification #{:?}, peer {:?} responded with invalid proof: {:?}", @@ -224,6 +234,7 @@ impl OnDemandJustificationsEngine { } }) .map(|proof| { + metric_inc!(self, beefy_on_demand_justification_good_proof); debug!( target: BEEFY_SYNC_LOG_TARGET, "🥩 received valid on-demand justif #{:?} from {:?}", block, peer diff --git a/client/beefy/src/import.rs b/client/beefy/src/import.rs index f0fe3bfa024dc..1b5dda3795aae 100644 --- a/client/beefy/src/import.rs +++ b/client/beefy/src/import.rs @@ -35,6 +35,8 @@ use sc_consensus::{BlockCheckParams, BlockImport, BlockImportParams, ImportResul use crate::{ communication::notification::BeefyVersionedFinalityProofSender, justification::{decode_and_verify_finality_proof, BeefyVersionedFinalityProof}, + metric_inc, + metrics::BlockImportMetrics, LOG_TARGET, }; @@ -49,6 +51,7 @@ pub struct BeefyBlockImport { runtime: Arc, inner: I, justification_sender: BeefyVersionedFinalityProofSender, + metrics: Option, } impl Clone for BeefyBlockImport { @@ -58,6 +61,7 @@ impl Clone for BeefyBlockImport BeefyBlockImport { runtime: Arc, inner: I, justification_sender: BeefyVersionedFinalityProofSender, + metrics: Option, ) -> BeefyBlockImport { - BeefyBlockImport { backend, runtime, inner, justification_sender } + BeefyBlockImport { backend, runtime, inner, justification_sender, metrics } } } @@ -147,6 +152,8 @@ where self.justification_sender .notify(|| Ok::<_, ()>(proof)) .expect("forwards closure result; the closure always returns Ok; qed."); + + metric_inc!(self, beefy_good_justification_imports); } else { debug!( target: LOG_TARGET, @@ -154,6 +161,7 @@ where encoded, number, ); + metric_inc!(self, beefy_bad_justification_imports); } }, _ => (), diff --git a/client/beefy/src/lib.rs b/client/beefy/src/lib.rs index d7de7295a4a11..5f74b052e99fe 100644 --- a/client/beefy/src/lib.rs +++ b/client/beefy/src/lib.rs @@ -28,6 +28,7 @@ use crate::{ }, }, import::BeefyBlockImport, + metrics::register_metrics, round::Rounds, worker::PersistedState, }; @@ -36,7 +37,7 @@ use beefy_primitives::{ GENESIS_AUTHORITY_SET_ID, }; use futures::{stream::Fuse, StreamExt}; -use log::{debug, error, info}; +use log::{error, info}; use parking_lot::Mutex; use prometheus::Registry; use sc_client_api::{Backend, BlockBackend, BlockchainEvents, FinalityNotifications, Finalizer}; @@ -133,6 +134,7 @@ pub fn beefy_block_import_and_links( wrapped_block_import: I, backend: Arc, runtime: Arc, + prometheus_registry: Option, ) -> (BeefyBlockImport, BeefyVoterLinks, BeefyRPCLinks) where B: Block, @@ -152,10 +154,16 @@ where // BlockImport -> Voter links let (to_voter_justif_sender, from_block_import_justif_stream) = BeefyVersionedFinalityProofStream::::channel(); + let metrics = register_metrics(prometheus_registry); // BlockImport - let import = - BeefyBlockImport::new(backend, runtime, wrapped_block_import, to_voter_justif_sender); + let import = BeefyBlockImport::new( + backend, + runtime, + wrapped_block_import, + to_voter_justif_sender, + metrics, + ); let voter_links = BeefyVoterLinks { from_block_import_justif_stream, to_rpc_justif_sender, @@ -242,28 +250,16 @@ where gossip_validator.clone(), None, ); + let metrics = register_metrics(prometheus_registry.clone()); // The `GossipValidator` adds and removes known peers based on valid votes and network events. let on_demand_justifications = OnDemandJustificationsEngine::new( network.clone(), justifications_protocol_name, known_peers, + prometheus_registry.clone(), ); - let metrics = - prometheus_registry.as_ref().map(metrics::Metrics::register).and_then( - |result| match result { - Ok(metrics) => { - debug!(target: LOG_TARGET, "🥩 Registered metrics"); - Some(metrics) - }, - Err(err) => { - debug!(target: LOG_TARGET, "🥩 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(); diff --git a/client/beefy/src/metrics.rs b/client/beefy/src/metrics.rs index 55fdecc36d4b0..e3b48e6ec8d54 100644 --- a/client/beefy/src/metrics.rs +++ b/client/beefy/src/metrics.rs @@ -18,16 +18,22 @@ //! BEEFY Prometheus metrics definition +use log::debug; use prometheus::{register, Counter, Gauge, PrometheusError, Registry, U64}; -/// BEEFY metrics exposed through Prometheus -pub(crate) struct Metrics { +/// Helper trait for registering BEEFY metrics to Prometheus registry. +pub(crate) trait PrometheusRegister: Sized { + const DESCRIPTION: &'static str; + fn register(registry: &Registry) -> Result; +} + +/// BEEFY voting-related metrics exposed through Prometheus +#[derive(Clone, Debug)] +pub struct VoterMetrics { /// 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, /// Best block BEEFY voted on @@ -36,10 +42,31 @@ pub(crate) struct Metrics { pub beefy_should_vote_on: Gauge, /// Number of sessions with lagging signed commitment on mandatory block pub beefy_lagging_sessions: Counter, + /// Number of times no Authority public key found in store + pub beefy_no_authority_found_in_store: Counter, + /// Number of currently buffered votes + pub beefy_buffered_votes: Gauge, + /// Number of valid but stale votes received + pub beefy_stale_votes: Counter, + /// Number of votes dropped due to full buffers + pub beefy_buffered_votes_dropped: Counter, + /// Number of currently buffered justifications + pub beefy_buffered_justifications: Gauge, + /// Number of valid but stale justifications received + pub beefy_stale_justifications: Counter, + /// Number of valid justifications successfully imported + pub beefy_imported_justifications: Counter, + /// Number of justifications dropped due to full buffers + pub beefy_buffered_justifications_dropped: Counter, + /// Trying to set Best Beefy block to old block + pub beefy_best_block_set_last_failure: Gauge, + /// Number of Successful handled votes + pub beefy_successful_handled_votes: Counter, } -impl Metrics { - pub(crate) fn register(registry: &Registry) -> Result { +impl PrometheusRegister for VoterMetrics { + const DESCRIPTION: &'static str = "voter"; + fn register(registry: &Registry) -> Result { Ok(Self { beefy_validator_set_id: register( Gauge::new( @@ -52,13 +79,6 @@ impl Metrics { Counter::new("substrate_beefy_votes_sent", "Number of votes sent by this node")?, registry, )?, - beefy_round_concluded: register( - Gauge::new( - "substrate_beefy_round_concluded", - "Voting round, that has been concluded", - )?, - registry, - )?, beefy_best_block: register( Gauge::new("substrate_beefy_best_block", "Best block finalized by BEEFY")?, registry, @@ -78,10 +98,212 @@ impl Metrics { )?, registry, )?, + beefy_no_authority_found_in_store: register( + Counter::new( + "substrate_beefy_no_authority_found_in_store", + "Number of times no Authority public key found in store", + )?, + registry, + )?, + beefy_buffered_votes: register( + Gauge::new("substrate_beefy_buffered_votes", "Number of currently buffered votes")?, + registry, + )?, + beefy_stale_votes: register( + Counter::new( + "substrate_beefy_stale_votes", + "Number of valid but stale votes received", + )?, + registry, + )?, + beefy_buffered_votes_dropped: register( + Counter::new( + "substrate_beefy_buffered_votes_dropped", + "Number of votes dropped due to full buffers", + )?, + registry, + )?, + beefy_buffered_justifications: register( + Gauge::new( + "substrate_beefy_buffered_justifications", + "Number of currently buffered justifications", + )?, + registry, + )?, + beefy_stale_justifications: register( + Counter::new( + "substrate_beefy_stale_justifications", + "Number of valid but stale justifications received", + )?, + registry, + )?, + beefy_imported_justifications: register( + Counter::new( + "substrate_beefy_imported_justifications", + "Number of valid justifications successfully imported", + )?, + registry, + )?, + beefy_buffered_justifications_dropped: register( + Counter::new( + "substrate_beefy_buffered_justifications_dropped", + "Number of justifications dropped due to full buffers", + )?, + registry, + )?, + beefy_best_block_set_last_failure: register( + Gauge::new( + "substrate_beefy_best_block_to_old_block", + "Trying to set Best Beefy block to old block", + )?, + registry, + )?, + beefy_successful_handled_votes: register( + Counter::new( + "substrate_beefy_successful_handled_votes", + "Number of Successful handled votes", + )?, + registry, + )?, }) } } +/// BEEFY block-import-related metrics exposed through Prometheus +#[derive(Clone, Debug)] +pub struct BlockImportMetrics { + /// Number of Good Justification imports + pub beefy_good_justification_imports: Counter, + /// Number of Bad Justification imports + pub beefy_bad_justification_imports: Counter, +} + +impl PrometheusRegister for BlockImportMetrics { + const DESCRIPTION: &'static str = "block-import"; + fn register(registry: &Registry) -> Result { + Ok(Self { + beefy_good_justification_imports: register( + Counter::new( + "substrate_beefy_good_justification_imports", + "Number of Good Justification imports", + )?, + registry, + )?, + beefy_bad_justification_imports: register( + Counter::new( + "substrate_beefy_bad_justification_imports", + "Number of Bad Justification imports", + )?, + registry, + )?, + }) + } +} + +/// BEEFY on-demand-justifications-related metrics exposed through Prometheus +#[derive(Clone, Debug)] +pub struct OnDemandIncomingRequestsMetrics { + /// Number of Successful Justification responses + pub beefy_successful_justification_responses: Counter, + /// Number of Failed Justification responses + pub beefy_failed_justification_responses: Counter, +} + +impl PrometheusRegister for OnDemandIncomingRequestsMetrics { + const DESCRIPTION: &'static str = "on-demand incoming justification requests"; + fn register(registry: &Registry) -> Result { + Ok(Self { + beefy_successful_justification_responses: register( + Counter::new( + "substrate_beefy_successful_justification_responses", + "Number of Successful Justification responses", + )?, + registry, + )?, + beefy_failed_justification_responses: register( + Counter::new( + "substrate_beefy_failed_justification_responses", + "Number of Failed Justification responses", + )?, + registry, + )?, + }) + } +} + +/// BEEFY on-demand-justifications-related metrics exposed through Prometheus +#[derive(Clone, Debug)] +pub struct OnDemandOutgoingRequestsMetrics { + /// Number of times there was no good peer to request justification from + pub beefy_on_demand_justification_no_peer_to_request_from: Counter, + /// Number of on-demand justification peer hang up + pub beefy_on_demand_justification_peer_hang_up: Counter, + /// Number of on-demand justification peer error + pub beefy_on_demand_justification_peer_error: Counter, + /// Number of on-demand justification invalid proof + pub beefy_on_demand_justification_invalid_proof: Counter, + /// Number of on-demand justification good proof + pub beefy_on_demand_justification_good_proof: Counter, +} + +impl PrometheusRegister for OnDemandOutgoingRequestsMetrics { + const DESCRIPTION: &'static str = "on-demand outgoing justification requests"; + fn register(registry: &Registry) -> Result { + Ok(Self { + beefy_on_demand_justification_no_peer_to_request_from: register( + Counter::new( + "substrate_beefy_on_demand_justification_no_peer_to_request_from", + "Number of times there was no good peer to request justification from", + )?, + registry, + )?, + beefy_on_demand_justification_peer_hang_up: register( + Counter::new( + "substrate_beefy_on_demand_justification_peer_hang_up", + "Number of on-demand justification peer hang up", + )?, + registry, + )?, + beefy_on_demand_justification_peer_error: register( + Counter::new( + "substrate_beefy_on_demand_justification_peer_error", + "Number of on-demand justification peer error", + )?, + registry, + )?, + beefy_on_demand_justification_invalid_proof: register( + Counter::new( + "substrate_beefy_on_demand_justification_invalid_proof", + "Number of on-demand justification invalid proof", + )?, + registry, + )?, + beefy_on_demand_justification_good_proof: register( + Counter::new( + "substrate_beefy_on_demand_justification_good_proof", + "Number of on-demand justification good proof", + )?, + registry, + )?, + }) + } +} + +pub(crate) fn register_metrics( + prometheus_registry: Option, +) -> Option { + prometheus_registry.as_ref().map(T::register).and_then(|result| match result { + Ok(metrics) => { + debug!(target: "beefy", "🥩 Registered {} metrics", T::DESCRIPTION); + Some(metrics) + }, + Err(err) => { + debug!(target: "beefy", "🥩 Failed to register {} metrics: {:?}", T::DESCRIPTION, err); + None + }, + }) +} + // Note: we use the `format` macro to convert an expr into a `u64`. This will fail, // if expr does not derive `Display`. #[macro_export] @@ -104,7 +326,6 @@ macro_rules! metric_inc { }}; } -#[cfg(test)] #[macro_export] macro_rules! metric_get { ($self:ident, $m:ident) => {{ diff --git a/client/beefy/src/tests.rs b/client/beefy/src/tests.rs index 932897c775895..007c57e4269cf 100644 --- a/client/beefy/src/tests.rs +++ b/client/beefy/src/tests.rs @@ -124,6 +124,7 @@ impl BeefyTestNet { justif_protocol_name, client, _block: PhantomData, + metrics: None, }; *net.peers[i].data.beefy_justif_req_handler.lock() = Some(justif_handler); } @@ -203,7 +204,7 @@ impl TestNetFactory for BeefyTestNet { let api = Arc::new(TestApi::with_validator_set(&validator_set)); let inner = BlockImportAdapter::new(client.clone()); let (block_import, voter_links, rpc_links) = - beefy_block_import_and_links(inner, client.as_backend(), api); + beefy_block_import_and_links(inner, client.as_backend(), api, None); let peer_data = PeerData { beefy_rpc_links: Mutex::new(Some(rpc_links)), beefy_voter_links: Mutex::new(Some(voter_links)), diff --git a/client/beefy/src/worker.rs b/client/beefy/src/worker.rs index f367c8b46d037..6528aef12508a 100644 --- a/client/beefy/src/worker.rs +++ b/client/beefy/src/worker.rs @@ -24,8 +24,8 @@ use crate::{ error::Error, justification::BeefyVersionedFinalityProof, keystore::BeefyKeystore, - metric_inc, metric_set, - metrics::Metrics, + metric_get, metric_inc, metric_set, + metrics::VoterMetrics, round::{Rounds, VoteImportResult}, BeefyVoterLinks, LOG_TARGET, }; @@ -252,7 +252,7 @@ pub(crate) struct WorkerParams { pub gossip_validator: Arc>, pub on_demand_justifications: OnDemandJustificationsEngine, pub links: BeefyVoterLinks, - pub metrics: Option, + pub metrics: Option, pub persisted_state: PersistedState, } @@ -312,7 +312,7 @@ pub(crate) struct BeefyWorker { // voter state /// BEEFY client metrics. - metrics: Option, + metrics: Option, /// Buffer holding votes for future processing. pending_votes: BTreeMap< NumberFor, @@ -407,6 +407,7 @@ where if store.intersection(&active).count() == 0 { let msg = "no authority public key found in store".to_string(); debug!(target: LOG_TARGET, "🥩 for block {:?} {}", block, msg); + metric_inc!(self, beefy_no_authority_found_in_store); Err(Error::Keystore(msg)) } else { Ok(()) @@ -494,17 +495,21 @@ where debug!(target: LOG_TARGET, "🥩 Buffer vote for round: {:?}.", block_num); 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() { + if votes_vec.try_push(vote).is_ok() { + metric_inc!(self, beefy_buffered_votes); + } else { warn!( target: LOG_TARGET, "🥩 Buffer vote dropped for round: {:?}", block_num - ) + ); + metric_inc!(self, beefy_buffered_votes_dropped); } } else { warn!(target: LOG_TARGET, "🥩 Buffer vote dropped for round: {:?}.", block_num); + metric_inc!(self, beefy_buffered_votes_dropped); } }, - RoundAction::Drop => (), + RoundAction::Drop => metric_inc!(self, beefy_stale_votes), }; Ok(()) } @@ -524,20 +529,23 @@ where match self.voting_oracle().triage_round(block_num, best_grandpa)? { RoundAction::Process => { debug!(target: LOG_TARGET, "🥩 Process justification for round: {:?}.", block_num); + metric_inc!(self, beefy_imported_justifications); self.finalize(justification)? }, RoundAction::Enqueue => { debug!(target: LOG_TARGET, "🥩 Buffer justification for round: {:?}.", block_num); if self.pending_justifications.len() < MAX_BUFFERED_JUSTIFICATIONS { self.pending_justifications.entry(block_num).or_insert(justification); + metric_inc!(self, beefy_buffered_justifications); } else { + metric_inc!(self, beefy_buffered_justifications_dropped); warn!( target: LOG_TARGET, "🥩 Buffer justification dropped for round: {:?}.", block_num ); } }, - RoundAction::Drop => (), + RoundAction::Drop => metric_inc!(self, beefy_stale_justifications), }; Ok(()) } @@ -555,8 +563,6 @@ where let block_number = vote.commitment.block_number; match rounds.add_vote(vote) { VoteImportResult::RoundConcluded(signed_commitment) => { - metric_set!(self, beefy_round_concluded, block_number); - let finality_proof = VersionedFinalityProof::V1(signed_commitment); info!( target: LOG_TARGET, @@ -584,6 +590,7 @@ where }, VoteImportResult::Invalid | VoteImportResult::Stale => (), }; + metric_inc!(self, beefy_successful_handled_votes); Ok(()) } @@ -637,7 +644,8 @@ where .notify(|| Ok::<_, ()>(finality_proof)) .expect("forwards closure result; the closure always returns Ok; qed."); } else { - debug!(target: LOG_TARGET, "🥩 Can't set best beefy to older: {}", block_num); + debug!(target: LOG_TARGET, "🥩 Can't set best beefy to old: {}", block_num); + metric_set!(self, beefy_best_block_set_last_failure, block_num); } Ok(()) } @@ -669,25 +677,33 @@ where let justifs_to_handle = to_process_for(&mut self.pending_justifications, interval, _ph); for (num, justification) in justifs_to_handle.into_iter() { debug!(target: LOG_TARGET, "🥩 Handle buffered justification for: {:?}.", num); + metric_inc!(self, beefy_imported_justifications); if let Err(err) = self.finalize(justification) { error!(target: LOG_TARGET, "🥩 Error finalizing block: {}", err); } } + metric_set!(self, beefy_buffered_justifications, self.pending_justifications.len()); // Possibly new interval after processing justifications. interval = self.voting_oracle().accepted_interval(best_grandpa)?; } // Process pending votes. if !self.pending_votes.is_empty() { + let mut processed = 0u64; let votes_to_handle = to_process_for(&mut self.pending_votes, interval, _ph); for (num, votes) in votes_to_handle.into_iter() { debug!(target: LOG_TARGET, "🥩 Handle buffered votes for: {:?}.", num); + processed += votes.len() as u64; for v in votes.into_iter() { if let Err(err) = self.handle_vote(v) { error!(target: LOG_TARGET, "🥩 Error handling buffered vote: {}", err); }; } } + if let Some(previous) = metric_get!(self, beefy_buffered_votes) { + previous.sub(processed); + metric_set!(self, beefy_buffered_votes, previous.get()); + } } Ok(()) } @@ -1053,10 +1069,12 @@ pub(crate) mod tests { let gossip_validator = Arc::new(GossipValidator::new(known_peers.clone())); let gossip_engine = GossipEngine::new(network.clone(), "/beefy/1", gossip_validator.clone(), None); + let metrics = None; let on_demand_justifications = OnDemandJustificationsEngine::new( network.clone(), "/beefy/justifs/1".into(), known_peers, + None, ); let genesis_header = backend .blockchain() @@ -1077,7 +1095,7 @@ pub(crate) mod tests { links, gossip_engine, gossip_validator, - metrics: None, + metrics, network, on_demand_justifications, persisted_state, From e8178c98750f436d1ed9284f213793eae0967761 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Thu, 16 Feb 2023 16:58:28 +0100 Subject: [PATCH 403/715] contracts: Don't rely on reserved balances keeping an account alive (#13369) * Move storage deposits to their own account * Take ed for contract's account from origin * Apply suggestions from code review Co-authored-by: Cyrill Leutwiler Co-authored-by: Sasha Gryaznov * Update stale docs * Use 16 bytes prefix for address derivation * Update frame/contracts/src/address.rs Co-authored-by: Cyrill Leutwiler * Fix merge * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_contracts * Update frame/contracts/primitives/src/lib.rs Co-authored-by: Sasha Gryaznov --------- Co-authored-by: Cyrill Leutwiler Co-authored-by: Sasha Gryaznov Co-authored-by: command-bot <> --- frame/contracts/fixtures/caller_contract.wat | 55 - frame/contracts/fixtures/drain.wat | 5 +- frame/contracts/primitives/src/lib.rs | 16 +- frame/contracts/src/address.rs | 81 + frame/contracts/src/benchmarking/mod.rs | 100 +- frame/contracts/src/exec.rs | 97 +- frame/contracts/src/lib.rs | 62 +- frame/contracts/src/storage.rs | 236 +- frame/contracts/src/storage/meter.rs | 193 +- frame/contracts/src/tests.rs | 496 ++- frame/contracts/src/weights.rs | 2930 +++++++++--------- 11 files changed, 2098 insertions(+), 2173 deletions(-) create mode 100644 frame/contracts/src/address.rs diff --git a/frame/contracts/fixtures/caller_contract.wat b/frame/contracts/fixtures/caller_contract.wat index 9c7cdf62abfc9..f9caf49f29ca8 100644 --- a/frame/contracts/fixtures/caller_contract.wat +++ b/frame/contracts/fixtures/caller_contract.wat @@ -16,27 +16,11 @@ ) ) - (func $current_balance (param $sp i32) (result i64) - (i32.store - (i32.sub (get_local $sp) (i32.const 16)) - (i32.const 8) - ) - (call $seal_balance - (i32.sub (get_local $sp) (i32.const 8)) - (i32.sub (get_local $sp) (i32.const 16)) - ) - (call $assert - (i32.eq (i32.load (i32.sub (get_local $sp) (i32.const 16))) (i32.const 8)) - ) - (i64.load (i32.sub (get_local $sp) (i32.const 8))) - ) - (func (export "deploy")) (func (export "call") (local $sp i32) (local $exit_code i32) - (local $balance i64) ;; Length of the buffer (i32.store (i32.const 20) (i32.const 32)) @@ -54,9 +38,6 @@ ;; Read current balance into local variable. (set_local $sp (i32.const 1024)) - (set_local $balance - (call $current_balance (get_local $sp)) - ) ;; Fail to deploy the contract since it returns a non-zero exit status. (set_local $exit_code @@ -82,11 +63,6 @@ (i32.eq (get_local $exit_code) (i32.const 2)) ;; ReturnCode::CalleeReverted ) - ;; Check that balance has not changed. - (call $assert - (i64.eq (get_local $balance) (call $current_balance (get_local $sp))) - ) - ;; Fail to deploy the contract due to insufficient gas. (set_local $exit_code (call $seal_instantiate @@ -112,11 +88,6 @@ (i32.eq (get_local $exit_code) (i32.const 1)) ;; ReturnCode::CalleeTrapped ) - ;; Check that balance has not changed. - (call $assert - (i64.eq (get_local $balance) (call $current_balance (get_local $sp))) - ) - ;; Length of the output buffer (i32.store (i32.sub (get_local $sp) (i32.const 4)) @@ -153,14 +124,6 @@ (i32.eq (i32.load (i32.sub (get_local $sp) (i32.const 4))) (i32.const 32)) ) - ;; Check that balance has been deducted. - (set_local $balance - (i64.sub (get_local $balance) (i64.load (i32.const 0))) - ) - (call $assert - (i64.eq (get_local $balance) (call $current_balance (get_local $sp))) - ) - ;; Zero out destination buffer of output (i32.store (i32.sub (get_local $sp) (i32.const 4)) @@ -204,11 +167,6 @@ ) ) - ;; Check that balance has not changed. - (call $assert - (i64.eq (get_local $balance) (call $current_balance (get_local $sp))) - ) - ;; Fail to call the contract due to insufficient gas. (set_local $exit_code (call $seal_call @@ -229,11 +187,6 @@ (i32.eq (get_local $exit_code) (i32.const 1)) ;; ReturnCode::CalleeTrapped ) - ;; Check that balance has not changed. - (call $assert - (i64.eq (get_local $balance) (call $current_balance (get_local $sp))) - ) - ;; Zero out destination buffer of output (i32.store (i32.sub (get_local $sp) (i32.const 4)) @@ -276,14 +229,6 @@ (i32.const 0x77665544) ) ) - - ;; Check that balance has been deducted. - (set_local $balance - (i64.sub (get_local $balance) (i64.load (i32.const 0))) - ) - (call $assert - (i64.eq (get_local $balance) (call $current_balance (get_local $sp))) - ) ) (data (i32.const 0) "\00\80") ;; The value to transfer on instantiation and calls. diff --git a/frame/contracts/fixtures/drain.wat b/frame/contracts/fixtures/drain.wat index 94c6518422667..9f126898fac81 100644 --- a/frame/contracts/fixtures/drain.wat +++ b/frame/contracts/fixtures/drain.wat @@ -34,8 +34,7 @@ ) ;; 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. + ;; The call will fail because a contract transfer has a keep alive requirement (call $assert (i32.eq (call $seal_transfer @@ -44,7 +43,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 0) ;; ReturnCode::Success + (i32.const 5) ;; ReturnCode::TransferFailed ) ) ) diff --git a/frame/contracts/primitives/src/lib.rs b/frame/contracts/primitives/src/lib.rs index 1811ae09c0572..f5b8da249517e 100644 --- a/frame/contracts/primitives/src/lib.rs +++ b/frame/contracts/primitives/src/lib.rs @@ -47,10 +47,12 @@ pub struct ContractResult { /// Additionally, any `seal_call` or `seal_instantiate` makes use of pre-charging /// when a non-zero `gas_limit` argument is supplied. pub gas_required: Weight, - /// How much balance was deposited and reserved during execution in order to pay for storage. + /// How much balance was paid by the origin into the contract's deposit account 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. + /// The storage deposit is never actually charged from the origin in case of [`Self::result`] + /// is `Err`. This is because on error all storage changes are rolled back including the + /// payment of the deposit. 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. @@ -159,12 +161,12 @@ 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. + /// deposit accounts to the origin. Refund(Balance), - /// The transaction increased overall storage usage. + /// The transaction increased storage consumption. /// - /// This means that the specified amount of balance was transferred from the call origin - /// to the contracts involved. + /// This means that the specified amount of balance was transferred from the origin + /// to the involved deposit accounts. Charge(Balance), } diff --git a/frame/contracts/src/address.rs b/frame/contracts/src/address.rs new file mode 100644 index 0000000000000..4b1bb1f48b91c --- /dev/null +++ b/frame/contracts/src/address.rs @@ -0,0 +1,81 @@ +// 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. + +//! Functions that deal with address derivation. + +use crate::{CodeHash, Config}; +use codec::{Decode, Encode}; +use sp_runtime::traits::{Hash, TrailingZeroInput}; + +/// Provides the contract address generation method. +/// +/// See [`DefaultAddressGenerator`] for the default implementation. +/// +/// # 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. +pub trait AddressGenerator { + /// The address of a contract based on the given instantiate parameters. + /// + /// Changing the formular for an already deployed chain is fine as long as no collisons + /// with the old formular. Changes only affect existing contracts. + fn contract_address( + deploying_address: &T::AccountId, + code_hash: &CodeHash, + input_data: &[u8], + salt: &[u8], + ) -> T::AccountId; + + /// The address of the deposit account of `contract_addr`. + /// + /// The address is generated once on instantiation and then stored in the contracts + /// metadata. Hence changes do only affect newly created contracts. + fn deposit_address(contract_addr: &T::AccountId) -> T::AccountId; +} + +/// Default address generator. +/// +/// This is the default address generator used by contract instantiation. Its result +/// is only dependent 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("contract_addr_v1" ++ deploying_address ++ code_hash ++ input_data ++ salt)` +pub struct DefaultAddressGenerator; + +impl AddressGenerator for DefaultAddressGenerator { + /// Formula: `hash("contract_addr_v1" ++ deploying_address ++ code_hash ++ input_data ++ salt)` + fn contract_address( + deploying_address: &T::AccountId, + code_hash: &CodeHash, + input_data: &[u8], + salt: &[u8], + ) -> T::AccountId { + let entropy = (b"contract_addr_v1", deploying_address, code_hash, input_data, salt) + .using_encoded(T::Hashing::hash); + Decode::decode(&mut TrailingZeroInput::new(entropy.as_ref())) + .expect("infinite length input; no invalid inputs for type; qed") + } + + /// Formula: `hash("contract_depo_v1" ++ contract_addr)` + fn deposit_address(contract_addr: &T::AccountId) -> T::AccountId { + let entropy = (b"contract_depo_v1", contract_addr).using_encoded(T::Hashing::hash); + Decode::decode(&mut TrailingZeroInput::new(entropy.as_ref())) + .expect("infinite length input; no invalid inputs for type; qed") + } +} diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index 55d315d5c7be1..ed41cece17301 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -32,7 +32,6 @@ use self::{ use crate::{ exec::{AccountIdOf, FixSizedKey, VarSizedKey}, schedule::{API_BENCHMARK_BATCH_SIZE, INSTR_BENCHMARK_BATCH_SIZE}, - storage::Storage, wasm::CallFlags, Pallet as Contracts, *, }; @@ -133,14 +132,8 @@ where 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 as &FixSizedKey, - Some(item.1.clone()), - None, - false, - ) - .map_err(|_| "Failed to write storage to restoration dest")?; + info.write(&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(()) @@ -207,7 +200,7 @@ benchmarks! { // The base weight consumed on processing contracts deletion queue. #[pov_mode = Measured] on_process_deletion_queue_batch {}: { - Storage::::process_deletion_queue_batch(Weight::MAX) + ContractInfo::::process_deletion_queue_batch(Weight::MAX) } #[skip_meta] @@ -215,9 +208,9 @@ benchmarks! { on_initialize_per_trie_key { let k in 0..1024; let instance = Contract::::with_storage(WasmModule::dummy(), k, T::Schedule::get().limits.payload_len)?; - Storage::::queue_trie_for_deletion(&instance.info()?)?; + instance.info()?.queue_trie_for_deletion()?; }: { - Storage::::process_deletion_queue_batch(Weight::MAX) + ContractInfo::::process_deletion_queue_batch(Weight::MAX) } #[pov_mode = Measured] @@ -225,11 +218,11 @@ benchmarks! { let q in 0..1024.min(T::DeletionQueueDepth::get()); for i in 0 .. q { let instance = Contract::::with_index(i, WasmModule::dummy(), vec![])?; - Storage::::queue_trie_for_deletion(&instance.info()?)?; + instance.info()?.queue_trie_for_deletion()?; ContractInfoOf::::remove(instance.account_id); } }: { - Storage::::process_deletion_queue_batch(Weight::MAX) + ContractInfo::::process_deletion_queue_batch(Weight::MAX) } // This benchmarks the additional weight that is charged when a contract is executed the @@ -293,18 +286,16 @@ benchmarks! { let addr = Contracts::::contract_address(&caller, &hash, &input, &salt); }: _(origin, value, Weight::MAX, None, code, input, salt) verify { - // the contract itself does not trigger any reserves - let deposit = T::Currency::reserved_balance(&addr); + let deposit_account = Contract::::address_info(&addr)?.deposit_account().clone(); + let deposit = T::Currency::free_balance(&deposit_account); // 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, + caller_funding::() - value - deposit - code_deposit - Pallet::::min_balance(), ); // contract has the full value - assert_eq!(T::Currency::free_balance(&addr), value); - // instantiate should leave a contract - Contract::::address_info(&addr)?; + assert_eq!(T::Currency::free_balance(&addr), value + Pallet::::min_balance()); } // Instantiate uses a dummy contract constructor to measure the overhead of the instantiate. @@ -325,14 +316,15 @@ benchmarks! { Contracts::::store_code_raw(code, caller.clone())?; }: _(origin, value, Weight::MAX, None, hash, input, salt) verify { - // the contract itself does not trigger any reserves - let deposit = T::Currency::reserved_balance(&addr); + let deposit_account = Contract::::address_info(&addr)?.deposit_account().clone(); + let deposit = T::Currency::free_balance(&deposit_account); // value was removed from the caller - assert_eq!(T::Currency::free_balance(&caller), caller_funding::() - value - deposit); + assert_eq!( + T::Currency::free_balance(&caller), + caller_funding::() - value - deposit - Pallet::::min_balance(), + ); // contract has the full value - assert_eq!(T::Currency::free_balance(&addr), value); - // instantiate should leave a contract - Contract::::address_info(&addr)?; + assert_eq!(T::Currency::free_balance(&addr), value + Pallet::::min_balance()); } // We just call a dummy contract to measure the overhead of the call extrinsic. @@ -348,18 +340,19 @@ benchmarks! { let instance = Contract::::with_caller( whitelisted_caller(), WasmModule::dummy(), vec![], )?; + let deposit_account = instance.info()?.deposit_account().clone(); 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); + let before_deposit = T::Currency::free_balance(&deposit_account); }: _(origin, callee, value, Weight::MAX, None, data) verify { - // the contract itself does not trigger any reserves - let deposit = T::Currency::reserved_balance(&instance.account_id); + let deposit = T::Currency::free_balance(&deposit_account); // value and value transfered via call should be removed from the caller assert_eq!( T::Currency::free_balance(&instance.caller), - caller_funding::() - instance.value - value - deposit, + caller_funding::() - instance.value - value - deposit - Pallet::::min_balance(), ); // contract should have received the value assert_eq!(T::Currency::free_balance(&instance.account_id), before + value); @@ -798,14 +791,16 @@ benchmarks! { }); let instance = Contract::::new(code, vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); + let deposit_account = instance.info()?.deposit_account().clone(); assert_eq!(T::Currency::total_balance(&beneficiary), 0u32.into()); - assert_eq!(T::Currency::free_balance(&instance.account_id), Pallet::::min_balance()); - assert_ne!(T::Currency::reserved_balance(&instance.account_id), 0u32.into()); + assert_eq!(T::Currency::free_balance(&instance.account_id), Pallet::::min_balance() * 2u32.into()); + assert_ne!(T::Currency::free_balance(&deposit_account), 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), Pallet::::min_balance()); + assert_eq!(T::Currency::total_balance(&deposit_account), 0u32.into()); + assert_eq!(T::Currency::total_balance(&beneficiary), Pallet::::min_balance() * 2u32.into()); } } @@ -1039,8 +1034,7 @@ benchmarks! { let instance = Contract::::new(code, vec![])?; let info = instance.info()?; for key in keys { - Storage::::write( - &info.trie_id, + info.write( &VarSizedKey::::try_from(key).map_err(|e| "Key has wrong length")?, Some(vec![]), None, @@ -1088,8 +1082,7 @@ benchmarks! { let instance = Contract::::new(code, vec![])?; let info = instance.info()?; for key in keys { - Storage::::write( - &info.trie_id, + info.write( &VarSizedKey::::try_from(key).map_err(|e| "Key has wrong length")?, Some(vec![]), None, @@ -1137,8 +1130,7 @@ benchmarks! { let instance = Contract::::new(code, vec![])?; let info = instance.info()?; for key in keys { - Storage::::write( - &info.trie_id, + info.write( &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, @@ -1188,8 +1180,7 @@ benchmarks! { let instance = Contract::::new(code, vec![])?; let info = instance.info()?; for key in keys { - Storage::::write( - &info.trie_id, + info.write( &VarSizedKey::::try_from(key).map_err(|e| "Key has wrong length")?, Some(vec![]), None, @@ -1236,8 +1227,7 @@ benchmarks! { let instance = Contract::::new(code, vec![])?; let info = instance.info()?; for key in keys { - Storage::::write( - &info.trie_id, + info.write( &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, @@ -1291,8 +1281,7 @@ benchmarks! { let instance = Contract::::new(code, vec![])?; let info = instance.info()?; for key in keys { - Storage::::write( - &info.trie_id, + info.write( &VarSizedKey::::try_from(key).map_err(|e| "Key has wrong length")?, Some(vec![]), None, @@ -1346,8 +1335,7 @@ benchmarks! { let instance = Contract::::new(code, vec![])?; let info = instance.info()?; for key in keys { - Storage::::write( - &info.trie_id, + info.write( &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, @@ -1396,8 +1384,7 @@ benchmarks! { let instance = Contract::::new(code, vec![])?; let info = instance.info()?; for key in keys { - Storage::::write( - &info.trie_id, + info.write( &VarSizedKey::::try_from(key).map_err(|e| "Key has wrong length")?, Some(vec![]), None, @@ -1444,8 +1431,7 @@ benchmarks! { let instance = Contract::::new(code, vec![])?; let info = instance.info()?; for key in keys { - Storage::::write( - &info.trie_id, + info.write( &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, @@ -1499,8 +1485,7 @@ benchmarks! { let instance = Contract::::new(code, vec![])?; let info = instance.info()?; for key in keys { - Storage::::write( - &info.trie_id, + info.write( &VarSizedKey::::try_from(key).map_err(|e| "Key has wrong length")?, Some(vec![]), None, @@ -1554,8 +1539,7 @@ benchmarks! { let instance = Contract::::new(code, vec![])?; let info = instance.info()?; for key in keys { - Storage::::write( - &info.trie_id, + info.write( &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, @@ -1884,7 +1868,7 @@ benchmarks! { .. Default::default() }); let instance = Contract::::new(code, vec![])?; - instance.set_balance(value * (r * API_BENCHMARK_BATCH_SIZE + 1).into()); + instance.set_balance((value + Pallet::::min_balance()) * (r * API_BENCHMARK_BATCH_SIZE + 1).into()); let origin = RawOrigin::Signed(instance.caller.clone()); let callee = instance.addr.clone(); let addresses = hashes @@ -1997,7 +1981,7 @@ benchmarks! { .. Default::default() }); let instance = Contract::::new(code, vec![])?; - instance.set_balance(value * (API_BENCHMARK_BATCH_SIZE + 1).into()); + instance.set_balance((value + Pallet::::min_balance()) * (API_BENCHMARK_BATCH_SIZE + 1).into()); let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) @@ -3113,8 +3097,8 @@ benchmarks! { { let weight_limit = T::DeletionWeightLimit::get(); let max_queue_depth = T::DeletionQueueDepth::get() as usize; - let empty_queue_throughput = Storage::::deletion_budget(0, weight_limit); - let full_queue_throughput = Storage::::deletion_budget(max_queue_depth, weight_limit); + let empty_queue_throughput = ContractInfo::::deletion_budget(0, weight_limit); + let full_queue_throughput = ContractInfo::::deletion_budget(max_queue_depth, weight_limit); println!("{:#?}", Schedule::::default()); println!("###############################################"); println!("Lazy deletion weight per key: {}", empty_queue_throughput.0); diff --git a/frame/contracts/src/exec.rs b/frame/contracts/src/exec.rs index 9b033a76cf0ff..92930cc791397 100644 --- a/frame/contracts/src/exec.rs +++ b/frame/contracts/src/exec.rs @@ -17,9 +17,9 @@ use crate::{ gas::GasMeter, - storage::{self, Storage, WriteOutcome}, + storage::{self, DepositAccount, WriteOutcome}, BalanceOf, CodeHash, Config, ContractInfo, ContractInfoOf, DebugBufferVec, Determinism, Error, - Event, Nonce, Pallet as Contracts, Schedule, + Event, Nonce, Pallet as Contracts, Schedule, System, }; use frame_support::{ crypto::ecdsa::ECDSAExt, @@ -492,7 +492,7 @@ enum CachedContract { /// /// In this case a reload is neither allowed nor possible. Please note that recursive /// calls cannot remove a contract as this is checked and denied. - Terminated, + Terminated(DepositAccount), } impl CachedContract { @@ -513,6 +513,15 @@ impl CachedContract { None } } + + /// Returns `Some` iff the contract is not `Cached::Invalidated`. + fn deposit_account(&self) -> Option<&DepositAccount> { + match self { + CachedContract::Cached(contract) => Some(contract.deposit_account()), + CachedContract::Terminated(deposit_account) => Some(&deposit_account), + CachedContract::Invalidated => None, + } + } } impl Frame { @@ -591,7 +600,9 @@ impl CachedContract { /// Terminate and return the contract info. fn terminate(&mut self, account_id: &T::AccountId) -> ContractInfo { self.load(account_id); - get_cached_or_panic_after_load!(mem::replace(self, Self::Terminated)) + let contract = get_cached_or_panic_after_load!(self); + let deposit_account = contract.deposit_account().clone(); + get_cached_or_panic_after_load!(mem::replace(self, Self::Terminated(deposit_account))) } } @@ -751,9 +762,7 @@ where input_data, salt, ); - let trie_id = Storage::::generate_trie_id(&account_id, nonce); - let contract = - Storage::::new_contract(&account_id, trie_id, *executable.code_hash())?; + let contract = ContractInfo::new(&account_id, nonce, *executable.code_hash())?; ( account_id, contract, @@ -873,7 +882,7 @@ where 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) { + if matches!(frame.contract_info, CachedContract::Terminated(_)) { return Err(Error::::TerminatedInConstructor.into()) } @@ -962,11 +971,21 @@ where // 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 + // in its contract info. The load is necessary to pull it from storage in case // it was invalidated. frame.contract_info.load(account_id); + let deposit_account = frame + .contract_info + .deposit_account() + .expect( + "Is only `None` when the info is invalidated. + We just re-loaded from storage which either makes the state `Cached` or `Terminated`. + qed", + ) + .clone(); let mut contract = frame.contract_info.into_contract(); - prev.nested_storage.absorb(frame.nested_storage, account_id, contract.as_mut()); + prev.nested_storage + .absorb(frame.nested_storage, deposit_account, contract.as_mut()); // In case the contract wasn't terminated we need to persist changes made to it. if let Some(contract) = contract { @@ -1001,10 +1020,14 @@ where if !persist { return } + let deposit_account = self.first_frame.contract_info.deposit_account().expect( + "Is only `None` when the info is invalidated. The first frame can't be invalidated. + qed", + ).clone(); let mut contract = self.first_frame.contract_info.as_contract(); self.storage_meter.absorb( mem::take(&mut self.first_frame.nested_storage), - &self.first_frame.account_id, + deposit_account, contract.as_deref_mut(), ); if let Some(contract) = contract { @@ -1182,19 +1205,21 @@ where } fn terminate(&mut self, beneficiary: &AccountIdOf) -> Result<(), DispatchError> { + use frame_support::traits::fungible::Inspect; if self.is_recursive() { return Err(Error::::TerminatedWhileReentrant.into()) } let frame = self.top_frame_mut(); let info = frame.terminate(); frame.nested_storage.terminate(&info); - Storage::::queue_trie_for_deletion(&info)?; - >::transfer( - ExistenceRequirement::AllowDeath, + System::::dec_consumers(&frame.account_id); + T::Currency::transfer( &frame.account_id, beneficiary, - T::Currency::free_balance(&frame.account_id), + T::Currency::reducible_balance(&frame.account_id, false), + ExistenceRequirement::AllowDeath, )?; + info.queue_trie_for_deletion()?; ContractInfoOf::::remove(&frame.account_id); E::remove_user(info.code_hash); Contracts::::deposit_event( @@ -1212,19 +1237,19 @@ where } fn get_storage(&mut self, key: &FixSizedKey) -> Option> { - Storage::::read(&self.top_frame_mut().contract_info().trie_id, key) + self.top_frame_mut().contract_info().read(key) } fn get_storage_transparent(&mut self, key: &VarSizedKey) -> Option> { - Storage::::read(&self.top_frame_mut().contract_info().trie_id, key) + self.top_frame_mut().contract_info().read(key) } fn get_storage_size(&mut self, key: &FixSizedKey) -> Option { - Storage::::size(&self.top_frame_mut().contract_info().trie_id, key) + self.top_frame_mut().contract_info().size(key) } fn get_storage_size_transparent(&mut self, key: &VarSizedKey) -> Option { - Storage::::size(&self.top_frame_mut().contract_info().trie_id, key) + self.top_frame_mut().contract_info().size(key) } fn set_storage( @@ -1234,8 +1259,7 @@ where take_old: bool, ) -> Result { let frame = self.top_frame_mut(); - Storage::::write( - &frame.contract_info.get(&frame.account_id).trie_id, + frame.contract_info.get(&frame.account_id).write( key, value, Some(&mut frame.nested_storage), @@ -1250,8 +1274,7 @@ where take_old: bool, ) -> Result { let frame = self.top_frame_mut(); - Storage::::write( - &frame.contract_info.get(&frame.account_id).trie_id, + frame.contract_info.get(&frame.account_id).write( key, value, Some(&mut frame.nested_storage), @@ -1438,7 +1461,6 @@ mod tests { use crate::{ exec::ExportedFunction::*, gas::GasMeter, - storage::Storage, tests::{ test_utils::{get_balance, hash, place_contract, set_balance}, ExtBuilder, RuntimeCall, RuntimeEvent as MetaEvent, Test, TestFilter, ALICE, BOB, @@ -1891,9 +1913,8 @@ mod tests { let mut gas_meter = GasMeter::::new(GAS_LIMIT); let executable = MockExecutable::from_storage(input_data_ch, &schedule, &mut gas_meter).unwrap(); - set_balance(&ALICE, min_balance * 1000); - let mut storage_meter = - storage::meter::Meter::new(&ALICE, Some(min_balance * 100), min_balance).unwrap(); + set_balance(&ALICE, min_balance * 10_000); + let mut storage_meter = storage::meter::Meter::new(&ALICE, None, min_balance).unwrap(); let result = MockStack::run_instantiate( ALICE, @@ -2231,7 +2252,7 @@ mod tests { // Check that the newly created account has the expected code hash and // there are instantiation event. assert_eq!( - Storage::::code_hash(&instantiated_contract_address).unwrap(), + ContractInfo::::load_code_hash(&instantiated_contract_address).unwrap(), dummy_ch ); assert_eq!( @@ -2273,7 +2294,7 @@ mod tests { ); // Check that the account has not been created. - assert!(Storage::::code_hash(&instantiated_contract_address).is_none()); + assert!(ContractInfo::::load_code_hash(&instantiated_contract_address).is_none()); assert!(events().is_empty()); }); } @@ -2332,7 +2353,7 @@ mod tests { // Check that the newly created account has the expected code hash and // there are instantiation event. assert_eq!( - Storage::::code_hash(&instantiated_contract_address).unwrap(), + ContractInfo::::load_code_hash(&instantiated_contract_address).unwrap(), dummy_ch ); assert_eq!( @@ -2374,7 +2395,7 @@ 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(); + let mut storage_meter = storage::meter::Meter::new(&ALICE, Some(200), 0).unwrap(); assert_matches!( MockStack::run_call( @@ -2409,8 +2430,8 @@ mod tests { let mut gas_meter = GasMeter::::new(GAS_LIMIT); 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(); + set_balance(&ALICE, 10_000); + let mut storage_meter = storage::meter::Meter::new(&ALICE, None, 100).unwrap(); assert_eq!( MockStack::run_instantiate( @@ -2494,9 +2515,8 @@ mod tests { 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, min_balance * 1000); - let mut storage_meter = - storage::meter::Meter::new(&ALICE, Some(min_balance * 100), min_balance).unwrap(); + set_balance(&ALICE, min_balance * 10_000); + let mut storage_meter = storage::meter::Meter::new(&ALICE, None, min_balance).unwrap(); let result = MockStack::run_instantiate( ALICE, @@ -2902,10 +2922,9 @@ mod tests { 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); + set_balance(&ALICE, min_balance * 10_000); let mut storage_meter = - storage::meter::Meter::new(&ALICE, Some(min_balance * 500), min_balance * 100) - .unwrap(); + storage::meter::Meter::new(&ALICE, None, min_balance * 100).unwrap(); MockStack::run_instantiate( ALICE, diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index e131a2685bad9..a5f35a9cb5f3b 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -85,6 +85,7 @@ #[macro_use] mod gas; +mod address; mod benchmarking; mod exec; mod migration; @@ -101,11 +102,11 @@ mod tests; use crate::{ exec::{AccountIdOf, ExecError, Executable, Stack as ExecStack}, gas::GasMeter, - storage::{meter::Meter as StorageMeter, ContractInfo, DeletedContract, Storage}, + storage::{meter::Meter as StorageMeter, ContractInfo, DeletedContract}, wasm::{OwnerInfo, PrefabWasmModule, TryInstantiate}, weights::WeightInfo, }; -use codec::{Codec, Decode, Encode, HasCompact}; +use codec::{Codec, Encode, HasCompact}; use frame_support::{ dispatch::{Dispatchable, GetDispatchInfo, Pays, PostDispatchInfo}, ensure, @@ -124,10 +125,11 @@ use pallet_contracts_primitives::{ }; use scale_info::TypeInfo; use smallvec::Array; -use sp_runtime::traits::{Convert, Hash, Saturating, StaticLookup, TrailingZeroInput}; +use sp_runtime::traits::{Convert, Hash, Saturating, StaticLookup}; use sp_std::{fmt::Debug, marker::PhantomData, prelude::*}; pub use crate::{ + address::{AddressGenerator, DefaultAddressGenerator}, exec::{Frame, VarSizedKey as StorageKey}, migration::Migration, pallet::*, @@ -155,49 +157,6 @@ type DebugBufferVec = BoundedVec::MaxDebugBufferLen>; /// 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. -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, - input_data: &[u8], - salt: &[u8], - ) -> T::AccountId; -} - -/// Default address generator. -/// -/// This is the default address generator used by contract instantiation. Its result -/// 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("contract_addr_v1" ++ deploying_address ++ code_hash ++ input_data ++ salt)` -pub struct DefaultAddressGenerator; - -impl AddressGenerator for DefaultAddressGenerator { - fn generate_address( - deploying_address: &T::AccountId, - code_hash: &CodeHash, - input_data: &[u8], - salt: &[u8], - ) -> T::AccountId { - let entropy = (b"contract_addr_v1", deploying_address, code_hash, input_data, salt) - .using_encoded(T::Hashing::hash); - Decode::decode(&mut TrailingZeroInput::new(entropy.as_ref())) - .expect("infinite length input; no invalid inputs for type; qed") - } -} - #[frame_support::pallet] pub mod pallet { use super::*; @@ -365,7 +324,7 @@ pub mod pallet { #[pallet::hooks] impl Hooks> for Pallet { fn on_idle(_block: T::BlockNumber, remaining_weight: Weight) -> Weight { - Storage::::process_deletion_queue_batch(remaining_weight) + ContractInfo::::process_deletion_queue_batch(remaining_weight) .saturating_add(T::WeightInfo::on_process_deletion_queue_batch()) } @@ -381,7 +340,7 @@ pub mod pallet { .max_block .saturating_sub(System::::block_weight().total()) .min(T::DeletionWeightLimit::get()); - Storage::::process_deletion_queue_batch(weight_limit) + ContractInfo::::process_deletion_queue_batch(weight_limit) .saturating_add(T::WeightInfo::on_process_deletion_queue_batch()) } else { T::WeightInfo::on_process_deletion_queue_batch() @@ -1129,8 +1088,7 @@ impl Pallet { let contract_info = ContractInfoOf::::get(&address).ok_or(ContractAccessError::DoesntExist)?; - let maybe_value = Storage::::read( - &contract_info.trie_id, + let maybe_value = contract_info.read( &StorageKey::::try_from(key).map_err(|_| ContractAccessError::KeyDecodingFailed)?, ); Ok(maybe_value) @@ -1146,12 +1104,12 @@ impl Pallet { input_data: &[u8], salt: &[u8], ) -> T::AccountId { - T::AddressGenerator::generate_address(deploying_address, code_hash, input_data, salt) + T::AddressGenerator::contract_address(deploying_address, code_hash, input_data, salt) } /// Returns the code hash of the contract specified by `account` ID. pub fn code_hash(account: &AccountIdOf) -> Option> { - Storage::::code_hash(account) + ContractInfo::::load_code_hash(account) } /// Store code for benchmarks which does not check nor instrument the code. diff --git a/frame/contracts/src/storage.rs b/frame/contracts/src/storage.rs index bf030a2bd8c81..35db33c4ca0b2 100644 --- a/frame/contracts/src/storage.rs +++ b/frame/contracts/src/storage.rs @@ -22,13 +22,15 @@ pub mod meter; use crate::{ exec::{AccountIdOf, StorageKey}, weights::WeightInfo, - BalanceOf, CodeHash, Config, ContractInfoOf, DeletionQueue, Error, TrieId, SENTINEL, + AddressGenerator, BalanceOf, CodeHash, Config, ContractInfoOf, DeletionQueue, Error, Pallet, + TrieId, SENTINEL, }; use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ dispatch::{DispatchError, DispatchResult}, storage::child::{self, ChildInfo}, weights::Weight, + RuntimeDebugNoBound, }; use scale_info::TypeInfo; use sp_io::KillStorageResult; @@ -36,7 +38,7 @@ use sp_runtime::{ traits::{Hash, Saturating, Zero}, RuntimeDebug, }; -use sp_std::{marker::PhantomData, prelude::*}; +use sp_std::{ops::Deref, prelude::*}; /// Information for managing an account and its sub trie abstraction. /// This is the required info to cache for an account. @@ -45,28 +47,68 @@ use sp_std::{marker::PhantomData, prelude::*}; pub struct ContractInfo { /// Unique ID for the subtree encoded as a bytes vector. pub trie_id: TrieId, + /// The account that holds this contracts storage deposit. + /// + /// This is held in a separate account to prevent the contract from spending it. + deposit_account: DepositAccount, /// The code associated with a given account. pub code_hash: CodeHash, /// How many bytes of storage are accumulated in this contract's child trie. - pub storage_bytes: u32, + storage_bytes: u32, /// How many items of storage are accumulated in this contract's child trie. - pub storage_items: u32, + 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, + 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, + storage_base_deposit: BalanceOf, } impl ContractInfo { + /// Constructs a new contract info **without** writing it to storage. + /// + /// This returns an `Err` if an contract with the supplied `account` already exists + /// in storage. + pub fn new( + account: &AccountIdOf, + nonce: u64, + code_hash: CodeHash, + ) -> Result { + if >::contains_key(account) { + return Err(Error::::DuplicateContract.into()) + } + + let trie_id = { + let buf = (account, nonce).using_encoded(T::Hashing::hash); + buf.as_ref() + .to_vec() + .try_into() + .expect("Runtime uses a reasonable hash size. Hence sizeof(T::Hash) <= 128; qed") + }; + + let deposit_account = DepositAccount(T::AddressGenerator::deposit_address(account)); + + let contract = Self { + trie_id, + deposit_account, + code_hash, + storage_bytes: 0, + storage_items: 0, + storage_byte_deposit: Zero::zero(), + storage_item_deposit: Zero::zero(), + storage_base_deposit: Zero::zero(), + }; + + Ok(contract) + } + /// 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[..]) + ChildInfo::new_default(self.trie_id.as_ref()) } /// The deposit paying for the accumulated storage generated within the contract's child trie. @@ -76,79 +118,30 @@ impl ContractInfo { /// 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) + self.extra_deposit() + .saturating_add(self.storage_base_deposit) + .saturating_sub(Pallet::::min_balance()) } -} - -/// Associated child trie unique id is built from the hash part of the trie id. -fn child_trie_info(trie_id: &[u8]) -> ChildInfo { - ChildInfo::new_default(trie_id) -} - -#[derive(Encode, Decode, TypeInfo, MaxEncodedLen)] -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), -} - -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, - } + /// Return the account that storage deposits should be deposited into. + pub fn deposit_account(&self) -> &DepositAccount { + &self.deposit_account } - /// 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 { /// Reads a storage kv pair of a contract. /// /// 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: &K) -> Option> { - child::get_raw(&child_trie_info(trie_id), key.hash().as_slice()) + pub fn read>(&self, key: &K) -> Option> { + child::get_raw(&self.child_trie_info(), 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: &K) -> Option { - child::len(&child_trie_info(trie_id), key.hash().as_slice()) + pub fn size>(&self, key: &K) -> Option { + child::len(&self.child_trie_info(), key.hash().as_slice()) } /// Update a storage entry into a contract's kv storage. @@ -159,13 +152,13 @@ impl Storage { /// 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>( - trie_id: &TrieId, + &self, key: &K, new_value: Option>, storage_meter: Option<&mut meter::NestedMeter>, take: bool, ) -> Result { - let child_trie_info = &child_trie_info(trie_id); + let child_trie_info = &self.child_trie_info(); let hashed_key = key.hash(); let (old_len, old_value) = if take { let val = child::get_raw(child_trie_info, &hashed_key); @@ -208,37 +201,11 @@ impl Storage { }) } - /// Creates a new contract descriptor in the storage with the given code hash at the given - /// address. - /// - /// Returns `Err` if there is already a contract at the given address. - pub fn new_contract( - account: &AccountIdOf, - trie_id: TrieId, - code_hash: CodeHash, - ) -> Result, DispatchError> { - if >::contains_key(account) { - return Err(Error::::DuplicateContract.into()) - } - - 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) - } - /// Push a contract's trie to the deletion queue for lazy removal. /// /// 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 { - >::try_append(DeletedContract { trie_id: contract.trie_id.clone() }) + pub fn queue_trie_for_deletion(&self) -> DispatchResult { + >::try_append(DeletedContract { trie_id: self.trie_id.clone() }) .map_err(|_| >::DeletionQueueFull.into()) } @@ -289,7 +256,10 @@ impl Storage { // Cannot panic due to loop condition let trie = &mut queue[0]; #[allow(deprecated)] - let outcome = child::kill_storage(&child_trie_info(&trie.trie_id), Some(remaining_key_budget)); + let outcome = child::kill_storage( + &ChildInfo::new_default(&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(c) => c, @@ -307,17 +277,8 @@ impl Storage { weight_limit.saturating_sub(weight_per_key.saturating_mul(u64::from(remaining_key_budget))) } - /// Generates a unique trie id by returning `hash(account_id ++ nonce)`. - pub fn generate_trie_id(account_id: &AccountIdOf, nonce: u64) -> TrieId { - let buf = (account_id, nonce).using_encoded(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. - pub fn code_hash(account: &AccountIdOf) -> Option> { + pub fn load_code_hash(account: &AccountIdOf) -> Option> { >::get(account).map(|i| i.code_hash) } @@ -332,3 +293,62 @@ impl Storage { >::put(bounded); } } + +#[derive(Encode, Decode, TypeInfo, MaxEncodedLen)] +pub struct DeletedContract { + pub(crate) trie_id: TrieId, +} + +/// Information about what happended to the pre-existing value when calling [`ContractInfo::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), +} + +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, + } + } +} + +#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebugNoBound, TypeInfo, MaxEncodedLen)] +#[scale_info(skip_type_params(T))] +pub struct DepositAccount(AccountIdOf); + +impl Deref for DepositAccount { + type Target = AccountIdOf; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} diff --git a/frame/contracts/src/storage/meter.rs b/frame/contracts/src/storage/meter.rs index 94bca741af661..5102edb78a09f 100644 --- a/frame/contracts/src/storage/meter.rs +++ b/frame/contracts/src/storage/meter.rs @@ -17,22 +17,19 @@ //! This module contains functions to meter the storage deposit. -use crate::{storage::ContractInfo, BalanceOf, Config, Error, Inspect, Pallet}; +use crate::{ + storage::{ContractInfo, DepositAccount}, + BalanceOf, Config, Error, Inspect, Pallet, System, +}; use codec::Encode; use frame_support::{ dispatch::DispatchError, ensure, - traits::{ - tokens::{BalanceStatus, WithdrawConsequence}, - Currency, ExistenceRequirement, Get, ReservableCurrency, - }, + traits::{tokens::WithdrawConsequence, Currency, ExistenceRequirement, Get}, DefaultNoBound, RuntimeDebugNoBound, }; use pallet_contracts_primitives::StorageDeposit as Deposit; -use sp_runtime::{ - traits::{Saturating, Zero}, - FixedPointNumber, FixedU128, -}; +use sp_runtime::{traits::Saturating, FixedPointNumber, FixedU128}; use sp_std::{marker::PhantomData, vec::Vec}; /// Deposit that uses the native currency's balance type. @@ -72,14 +69,14 @@ pub trait Ext { /// 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 + /// The balance transfer can either flow from `origin` to `deposit_account` 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 + /// It is guaranteed 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, + deposit_account: &DepositAccount, amount: &DepositOf, terminated: bool, ); @@ -216,7 +213,7 @@ impl Diff { /// essentially makes the order of storage changes irrelevant with regard to the deposit system. #[derive(RuntimeDebugNoBound, Clone)] struct Charge { - contract: T::AccountId, + deposit_account: DepositAccount, amount: DepositOf, terminated: bool, } @@ -270,8 +267,8 @@ where /// 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. + /// This does the actual balance transfer from/to `origin` and `deposit_account` 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. @@ -280,12 +277,12 @@ where /// /// - `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. + /// - `deposit_account`: The contract's deposit account 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, absorbed: RawMeter, - contract: &T::AccountId, + deposit_account: DepositAccount, info: Option<&mut ContractInfo>, ) { let own_deposit = absorbed.own_contribution.update_contract(info); @@ -296,7 +293,7 @@ where if !own_deposit.is_zero() { self.charges.extend_from_slice(&absorbed.charges); self.charges.push(Charge { - contract: contract.clone(), + deposit_account, amount: own_deposit, terminated: absorbed.is_terminated(), }); @@ -345,10 +342,10 @@ where /// execution did finish. 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); + E::charge(origin, &charge.deposit_account, &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); + E::charge(origin, &charge.deposit_account, &charge.amount, charge.terminated); } self.total_deposit } @@ -360,9 +357,8 @@ where T: Config, E: Ext, { - /// Try to charge the `diff` from the meter. Fails if this would exceed the original limit. + /// Charge `diff` from the meter. 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"), @@ -379,13 +375,16 @@ where info: &mut ContractInfo, ) -> Result, DispatchError> { debug_assert!(self.is_alive()); + + let ed = Pallet::::min_balance(); 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())); + // Instantiate needs to transfer at least the minimum balance in order to pull the + // deposit account into existence. + // We also add another `ed` here which goes to the contract's own account into existence. + deposit = deposit.max(Deposit::Charge(ed)).saturating_add(&Deposit::Charge(ed)); if deposit.charge_or_zero() > self.limit { return Err(>::StorageDepositLimitExhausted.into()) } @@ -394,11 +393,22 @@ where // 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. - E::charge(origin, contract, &deposit, false); - } + + // Usually, deposit charges are deferred to be able to coalesce them with refunds. + // However, we need to charge immediately so that the account is created before + // charges possibly below the ed are collected and fail. + E::charge( + origin, + info.deposit_account(), + &deposit.saturating_sub(&Deposit::Charge(ed)), + false, + ); + System::::inc_consumers(info.deposit_account())?; + + // We also need to make sure that the contract's account itself exists. + T::Currency::transfer(origin, contract, ed, ExistenceRequirement::KeepAlive)?; + System::::inc_consumers(contract)?; + Ok(deposit) } @@ -443,7 +453,12 @@ impl Ext for ReservingExt { limit: Option>, min_leftover: BalanceOf, ) -> Result, DispatchError> { - let max = T::Currency::reducible_balance(origin, true).saturating_sub(min_leftover); + // We are sending the `min_leftover` and the `min_balance` from the origin + // account as part of a contract call. Hence origin needs to have those left over + // as free balance after accounting for all deposits. + let max = T::Currency::reducible_balance(origin, true) + .saturating_sub(min_leftover) + .saturating_sub(Pallet::::min_balance()); let limit = limit.unwrap_or(max); ensure!( limit <= max && @@ -455,67 +470,67 @@ impl Ext for ReservingExt { fn charge( origin: &T::AccountId, - contract: &T::AccountId, + deposit_account: &DepositAccount, 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. + // There is nothing we can do when this fails as this constitutes a bug in the runtime. + // We need to settle for emitting an error log in this case. + // + // # Note + // + // This is infallible because it is called in a part of the execution where we cannot + // simply roll back. It might make sense to do some refactoring to move the deposit + // collection to the fallible part of execution. 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. + // This will never fail because a deposit account is required to exist + // at all times. The pallet enforces this invariant by holding a consumer reference + // on the deposit account as long as the contract exists. + // + // The sender always has enough balance because we checked that it had enough + // balance when instantiating the storage meter. There is no way for the sender + // which is a plain account to send away this balance in the meantime. let result = T::Currency::transfer( origin, - contract, + deposit_account, *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, + "Failed to transfer storage deposit {:?} from origin {:?} to deposit account {:?}: {:?}", + amount, origin, deposit_account, 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 - // 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. + // The receiver always exists because the initial value transfer from the + // origin to the contract has a keep alive existence requirement. When taking a deposit + // we make sure to leave at least the ed in the free balance. + // + // The sender always has enough balance because we track it in the `ContractInfo` and + // never send more back than we have. Noone has access to the deposit account. Hence no + // other interaction with this account takes place. 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(Pallet::::min_balance()), - ) - }; - let result = - T::Currency::repatriate_reserved(contract, origin, amount, BalanceStatus::Free); - if matches!(result, Ok(val) if !val.is_zero()) || matches!(result, Err(_)) { + if terminated { + System::::dec_consumers(&deposit_account); + } + let result = T::Currency::transfer( + deposit_account, + origin, + *amount, + // We can safely use `AllowDeath` because our own consumer prevents an removal. + ExistenceRequirement::AllowDeath, + ); + if matches!(result, Err(_)) { log::error!( target: "runtime::contracts", - "Failed to repatriate storage deposit {:?} from contract {:?} to origin {:?}: {:?}", - amount, contract, origin, result, + "Failed to refund storage deposit {:?} from deposit account {:?} to origin {:?}: {:?}", + amount, deposit_account, origin, result, ); if cfg!(debug_assertions) { panic!("Unable to refund storage deposit. This is a bug."); @@ -558,7 +573,7 @@ mod tests { #[derive(Debug, PartialEq, Eq, Clone)] struct Charge { origin: AccountIdOf, - contract: AccountIdOf, + contract: DepositAccount, amount: DepositOf, terminated: bool, } @@ -592,7 +607,7 @@ mod tests { fn charge( origin: &AccountIdOf, - contract: &AccountIdOf, + contract: &DepositAccount, amount: &DepositOf, terminated: bool, ) { @@ -620,12 +635,10 @@ mod tests { } 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"), + trie_id: Default::default(), + deposit_account: DepositAccount([0u8; 32].into()), + code_hash: Default::default(), storage_bytes: info.bytes, storage_items: info.items, storage_byte_deposit: info.bytes_deposit, @@ -659,7 +672,7 @@ mod tests { // an empty charge does not create a `Charge` entry let mut nested0 = meter.nested(); nested0.charge(&Default::default()); - meter.absorb(nested0, &BOB, None); + meter.absorb(nested0, DepositAccount(BOB), None); assert_eq!( TestExtTestValue::get(), @@ -692,16 +705,16 @@ mod tests { 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() }); - nested0.absorb(nested1, &CHARLIE, Some(&mut nested1_info)); + nested0.absorb(nested1, DepositAccount(CHARLIE), Some(&mut nested1_info)); 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 { items_removed: 7, ..Default::default() }); - nested0.absorb(nested2, &CHARLIE, Some(&mut nested2_info)); + nested0.absorb(nested2, DepositAccount(CHARLIE), Some(&mut nested2_info)); nested0.enforce_limit(Some(&mut nested0_info)).unwrap(); - meter.absorb(nested0, &BOB, Some(&mut nested0_info)); + meter.absorb(nested0, DepositAccount(BOB), Some(&mut nested0_info)); meter.into_deposit(&ALICE); @@ -716,19 +729,19 @@ mod tests { charges: vec![ Charge { origin: ALICE, - contract: CHARLIE, + contract: DepositAccount(CHARLIE), amount: Deposit::Refund(10), terminated: false }, Charge { origin: ALICE, - contract: CHARLIE, + contract: DepositAccount(CHARLIE), amount: Deposit::Refund(20), terminated: false }, Charge { origin: ALICE, - contract: BOB, + contract: DepositAccount(BOB), amount: Deposit::Charge(2), terminated: false } @@ -760,9 +773,9 @@ mod tests { nested1.charge(&Diff { bytes_added: 20, ..Default::default() }); nested1.terminate(&nested1_info); nested0.enforce_limit(Some(&mut nested1_info)).unwrap(); - nested0.absorb(nested1, &CHARLIE, None); + nested0.absorb(nested1, DepositAccount(CHARLIE), None); - meter.absorb(nested0, &BOB, None); + meter.absorb(nested0, DepositAccount(BOB), None); meter.into_deposit(&ALICE); assert_eq!( @@ -772,13 +785,13 @@ mod tests { charges: vec![ Charge { origin: ALICE, - contract: CHARLIE, - amount: Deposit::Refund(120), + contract: DepositAccount(CHARLIE), + amount: Deposit::Refund(119), terminated: true }, Charge { origin: ALICE, - contract: BOB, + contract: DepositAccount(BOB), amount: Deposit::Charge(12), terminated: false } diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index cab426ad132cb..879268a68dca9 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -22,12 +22,11 @@ use crate::{ Result as ExtensionResult, RetVal, ReturnFlags, SysConfig, }, exec::{FixSizedKey, Frame}, - storage::Storage, tests::test_utils::{get_contract, get_contract_checked}, wasm::{Determinism, PrefabWasmModule, ReturnCode as RuntimeReturnCode}, weights::WeightInfo, - BalanceOf, Code, CodeStorage, Config, ContractInfoOf, DefaultAddressGenerator, DeletionQueue, - Error, Pallet, Schedule, + BalanceOf, Code, CodeStorage, Config, ContractInfo, ContractInfoOf, DefaultAddressGenerator, + DeletionQueue, Error, Pallet, Schedule, }; use assert_matches::assert_matches; use codec::Encode; @@ -37,8 +36,8 @@ use frame_support::{ parameter_types, storage::child, traits::{ - BalanceStatus, ConstU32, ConstU64, Contains, Currency, Get, LockableCurrency, OnIdle, - OnInitialize, ReservableCurrency, WithdrawReasons, + ConstU32, ConstU64, Contains, Currency, ExistenceRequirement, Get, LockableCurrency, + OnIdle, OnInitialize, ReservableCurrency, WithdrawReasons, }, weights::{constants::WEIGHT_REF_TIME_PER_SECOND, Weight}, }; @@ -51,7 +50,7 @@ use sp_runtime::{ traits::{BlakeTwo256, Convert, Hash, IdentityLookup}, AccountId32, }; -use std::sync::Arc; +use std::{ops::Deref, sync::Arc}; use crate as pallet_contracts; @@ -76,9 +75,7 @@ frame_support::construct_runtime!( #[macro_use] pub mod test_utils { use super::{Balances, Hash, SysConfig, Test}; - use crate::{ - exec::AccountIdOf, storage::Storage, CodeHash, Config, ContractInfo, ContractInfoOf, Nonce, - }; + use crate::{exec::AccountIdOf, CodeHash, Config, ContractInfo, ContractInfoOf, Nonce}; use codec::Encode; use frame_support::traits::Currency; @@ -87,9 +84,8 @@ pub mod test_utils { *counter += 1; *counter }); - 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(); + let contract = >::new(&address, nonce, code_hash).unwrap(); >::insert(address, contract); } pub fn set_balance(who: &AccountIdOf, amount: u64) { @@ -518,7 +514,7 @@ fn calling_plain_account_fails() { fn instantiate_and_call_and_deposit_event() { let (wasm, code_hash) = compile_module::("event_and_return_on_deploy").unwrap(); - ExtBuilder::default().existential_deposit(500).build().execute_with(|| { + ExtBuilder::default().existential_deposit(1).build().execute_with(|| { let _ = Balances::deposit_creating(&ALICE, 1_000_000); let min_balance = ::Currency::minimum_balance(); let value = 100; @@ -551,21 +547,24 @@ fn instantiate_and_call_and_deposit_event() { .account_id; assert!(ContractInfoOf::::contains_key(&addr)); + let contract = get_contract(&addr); + let deposit_account = contract.deposit_account().deref(); + assert_eq!( System::events(), vec![ EventRecord { phase: Phase::Initialization, event: RuntimeEvent::System(frame_system::Event::NewAccount { - account: addr.clone() + account: deposit_account.clone(), }), topics: vec![], }, EventRecord { phase: Phase::Initialization, event: RuntimeEvent::Balances(pallet_balances::Event::Endowed { - account: addr.clone(), - free_balance: min_balance, + account: deposit_account.clone(), + free_balance: 131, }), topics: vec![], }, @@ -573,15 +572,31 @@ fn instantiate_and_call_and_deposit_event() { phase: Phase::Initialization, event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { from: ALICE, - to: addr.clone(), - amount: min_balance, + to: deposit_account.clone(), + amount: 131, }), topics: vec![], }, EventRecord { phase: Phase::Initialization, - event: RuntimeEvent::Balances(pallet_balances::Event::Reserved { - who: addr.clone(), + event: RuntimeEvent::System(frame_system::Event::NewAccount { + account: addr.clone() + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Balances(pallet_balances::Event::Endowed { + account: addr.clone(), + free_balance: min_balance, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { + from: ALICE, + to: addr.clone(), amount: min_balance, }), topics: vec![], @@ -823,7 +838,7 @@ fn deploy_and_call_other_contract() { let (caller_wasm, _caller_code_hash) = compile_module::("caller_contract").unwrap(); let (callee_wasm, callee_code_hash) = compile_module::("return_with_data").unwrap(); - ExtBuilder::default().existential_deposit(500).build().execute_with(|| { + ExtBuilder::default().existential_deposit(1).build().execute_with(|| { let min_balance = ::Currency::minimum_balance(); // Create @@ -841,18 +856,7 @@ fn deploy_and_call_other_contract() { .result .unwrap() .account_id; - Contracts::bare_instantiate( - ALICE, - 100_000, - GAS_LIMIT, - None, - Code::Upload(callee_wasm), - 0u32.to_le_bytes().encode(), - vec![42], - false, - ) - .result - .unwrap(); + Contracts::bare_upload_code(ALICE, callee_wasm, None, Determinism::Deterministic).unwrap(); let callee_addr = Contracts::contract_address( &caller_addr, @@ -875,21 +879,24 @@ fn deploy_and_call_other_contract() { callee_code_hash.as_ref().to_vec(), )); + let callee = get_contract(&callee_addr); + let deposit_account = callee.deposit_account().deref(); + assert_eq!( System::events(), vec![ EventRecord { phase: Phase::Initialization, event: RuntimeEvent::System(frame_system::Event::NewAccount { - account: callee_addr.clone() + account: deposit_account.clone(), }), topics: vec![], }, EventRecord { phase: Phase::Initialization, event: RuntimeEvent::Balances(pallet_balances::Event::Endowed { - account: callee_addr.clone(), - free_balance: min_balance, + account: deposit_account.clone(), + free_balance: 131, }), topics: vec![], }, @@ -897,15 +904,31 @@ fn deploy_and_call_other_contract() { phase: Phase::Initialization, event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { from: ALICE, - to: callee_addr.clone(), - amount: min_balance, + to: deposit_account.clone(), + amount: 131, }), topics: vec![], }, EventRecord { phase: Phase::Initialization, - event: RuntimeEvent::Balances(pallet_balances::Event::Reserved { - who: callee_addr.clone(), + event: RuntimeEvent::System(frame_system::Event::NewAccount { + account: callee_addr.clone() + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Balances(pallet_balances::Event::Endowed { + account: callee_addr.clone(), + free_balance: min_balance, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { + from: ALICE, + to: callee_addr.clone(), amount: min_balance, }), topics: vec![], @@ -915,7 +938,7 @@ fn deploy_and_call_other_contract() { event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { from: caller_addr.clone(), to: callee_addr.clone(), - amount: 32768, // hard coded in wasm + amount: 32768 // hardcoded in wasm }), topics: vec![], }, @@ -999,8 +1022,8 @@ fn delegate_call() { } #[test] -fn cannot_self_destruct_through_draning() { - let (wasm, _code_hash) = compile_module::("drain").unwrap(); +fn transfer_allow_death_cannot_kill_account() { + let (wasm, _code_hash) = compile_module::("dummy").unwrap(); ExtBuilder::default().existential_deposit(200).build().execute_with(|| { let _ = Balances::deposit_creating(&ALICE, 1_000_000); @@ -1022,36 +1045,32 @@ fn cannot_self_destruct_through_draning() { // Check that the BOB contract has been instantiated. get_contract(&addr); - // 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( - RuntimeOrigin::signed(ALICE), - addr.clone(), - 0, - GAS_LIMIT, - None, - vec![] - )); + let total_balance = ::Currency::total_balance(&addr); - // Make sure the account wasn't remove by sending all free balance away. - assert_eq!( - ::Currency::total_balance(&addr), - ::Currency::minimum_balance(), + assert_err!( + <::Currency as Currency>::transfer( + &addr, + &ALICE, + total_balance, + ExistenceRequirement::AllowDeath, + ), + pallet_balances::Error::::KeepAlive, ); + + assert_eq!(::Currency::total_balance(&addr), total_balance); }); } #[test] -fn cannot_self_destruct_through_storage_refund_after_price_change() { - let (wasm, _code_hash) = compile_module::("store").unwrap(); +fn cannot_self_destruct_through_draning() { + let (wasm, _code_hash) = compile_module::("drain").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. let addr = Contracts::bare_instantiate( ALICE, - 0, + 1_000, GAS_LIMIT, None, Code::Upload(wasm), @@ -1063,50 +1082,36 @@ fn cannot_self_destruct_through_storage_refund_after_price_change() { .unwrap() .account_id; - // Check that the BOB contract has been instantiated and has the minimum 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 and a single storage item of price 2 - assert_ok!(Contracts::call( - RuntimeOrigin::signed(ALICE), - addr.clone(), - 0, - GAS_LIMIT, - None, - 100u32.to_le_bytes().to_vec() - )); - assert_eq!(get_contract(&addr).total_deposit(), min_balance + 102); + // Check that the BOB contract has been instantiated. + get_contract(&addr); - // 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); + // Call BOB which makes it send all funds to the zero address + // The contract code asserts that the transfer fails with the correct error code assert_ok!(Contracts::call( RuntimeOrigin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, None, - 0u32.to_le_bytes().to_vec() + vec![] )); - // Make sure the account wasn't removed by the refund + // Make sure the account wasn't remove by sending all free balance away. assert_eq!( ::Currency::total_balance(&addr), - get_contract(&addr).total_deposit(), + 1_000 + ::Currency::minimum_balance(), ); - assert_eq!(get_contract(&addr).extra_deposit(), 2,); }); } #[test] -fn cannot_self_destruct_by_refund_after_slash() { +fn cannot_self_destruct_through_storage_refund_after_price_change() { let (wasm, _code_hash) = compile_module::("store").unwrap(); - ExtBuilder::default().existential_deposit(500).build().execute_with(|| { + 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. let addr = Contracts::bare_instantiate( ALICE, 0, @@ -1121,68 +1126,40 @@ fn cannot_self_destruct_by_refund_after_slash() { .unwrap() .account_id; - // create 100 more reserved balance + // Check that the BOB contract has been instantiated and has the minimum 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 and a single storage item of price 2 assert_ok!(Contracts::call( RuntimeOrigin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, None, - 98u32.encode(), + 100u32.to_le_bytes().to_vec() )); + assert_eq!(get_contract(&addr).total_deposit(), min_balance + 102); - // 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 + // 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), addr.clone(), 0, GAS_LIMIT, None, - 48u32.encode(), + 0u32.to_le_bytes().to_vec() )); - // Make sure the account kept the minimum balance and was not destroyed - assert_eq!(::Currency::total_balance(&addr), min_balance); - + // Make sure the account wasn't removed by the refund assert_eq!( - System::events(), - vec![ - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Balances(pallet_balances::Event::Slashed { - who: addr.clone(), - amount: 90, - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Contracts(crate::Event::Called { - caller: ALICE, - contract: addr.clone(), - }), - topics: vec![hash(&ALICE), hash(&addr)], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Balances(pallet_balances::Event::ReserveRepatriated { - from: addr.clone(), - to: ALICE, - amount: 10, - destination_status: BalanceStatus::Free, - }), - topics: vec![], - }, - ] + ::Currency::total_balance(get_contract(&addr).deposit_account()), + get_contract(&addr).total_deposit(), ); + assert_eq!(get_contract(&addr).extra_deposit(), 2); }); } @@ -1252,7 +1229,7 @@ fn self_destruct_works() { .account_id; // Check that the BOB contract has been instantiated. - get_contract(&addr); + let contract = get_contract(&addr); // Drop all previous events initialize_block(2); @@ -1271,17 +1248,25 @@ fn self_destruct_works() { 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); + let ed = ::Currency::minimum_balance(); + assert_eq!(Balances::free_balance(DJANGO), 1_000_000 + 100_000 + ed); pretty_assertions::assert_eq!( System::events(), vec![ + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::System(frame_system::Event::KilledAccount { + account: addr.clone() + }), + topics: vec![], + }, EventRecord { phase: Phase::Initialization, event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { from: addr.clone(), to: DJANGO, - amount: 100_000, + amount: 100_000 + ed, }), topics: vec![], }, @@ -1304,17 +1289,16 @@ fn self_destruct_works() { EventRecord { phase: Phase::Initialization, event: RuntimeEvent::System(frame_system::Event::KilledAccount { - account: addr.clone() + account: contract.deposit_account().deref().clone(), }), topics: vec![], }, EventRecord { phase: Phase::Initialization, - event: RuntimeEvent::Balances(pallet_balances::Event::ReserveRepatriated { - from: addr.clone(), + event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { + from: contract.deposit_account().deref().clone(), to: ALICE, amount: 1_000, - destination_status: BalanceStatus::Free, }), topics: vec![], }, @@ -2055,7 +2039,7 @@ 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(); + ContractInfo::::fill_queue_with_dummies(); let queue_len_initial = >::decode_len().unwrap_or(0); @@ -2132,7 +2116,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 = Weight::from_ref_time(5_000_000_000); - let (_, max_keys) = Storage::::deletion_budget(1, weight_limit); + let (_, max_keys) = ContractInfo::::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())) .collect(); @@ -2161,14 +2145,7 @@ fn lazy_removal_partial_remove_works() { // Put value into the contracts child trie for val in &vals { - Storage::::write( - &info.trie_id, - &val.0 as &FixSizedKey, - Some(val.2.clone()), - None, - false, - ) - .unwrap(); + info.write(&val.0 as &FixSizedKey, Some(val.2.clone()), None, false).unwrap(); } >::insert(&addr, info.clone()); @@ -2201,7 +2178,7 @@ fn lazy_removal_partial_remove_works() { ext.execute_with(|| { // Run the lazy removal - let weight_used = Storage::::process_deletion_queue_batch(weight_limit); + let weight_used = ContractInfo::::process_deletion_queue_batch(weight_limit); // Weight should be exhausted because we could not even delete all keys assert_eq!(weight_used, weight_limit); @@ -2235,7 +2212,7 @@ fn lazy_removal_does_no_run_on_full_queue_and_full_block() { // Fill the deletion queue with dummy values, so that on_initialize attempts // to clear the queue - Storage::::fill_queue_with_dummies(); + ContractInfo::::fill_queue_with_dummies(); // Check that on_initialize() tries to perform lazy removal but removes nothing // as no more weight is left for that. @@ -2344,7 +2321,7 @@ fn lazy_removal_does_not_use_all_weight() { .account_id; let info = get_contract(&addr); - let (weight_per_key, max_keys) = Storage::::deletion_budget(1, weight_limit); + let (weight_per_key, max_keys) = ContractInfo::::deletion_budget(1, weight_limit); // We create a contract with one less storage item than we can remove within the limit let vals: Vec<_> = (0..max_keys - 1) @@ -2353,14 +2330,7 @@ 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 as &FixSizedKey, - Some(val.2.clone()), - None, - false, - ) - .unwrap(); + info.write(&val.0 as &FixSizedKey, Some(val.2.clone()), None, false).unwrap(); } >::insert(&addr, info.clone()); @@ -2393,7 +2363,7 @@ fn lazy_removal_does_not_use_all_weight() { ext.execute_with(|| { // Run the lazy removal - let weight_used = Storage::::process_deletion_queue_batch(weight_limit); + let weight_used = ContractInfo::::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); @@ -2427,7 +2397,7 @@ fn deletion_queue_full() { .account_id; // fill the deletion queue up until its limit - Storage::::fill_queue_with_dummies(); + ContractInfo::::fill_queue_with_dummies(); // Terminate the contract should fail assert_err_ignore_postinfo!( @@ -3196,14 +3166,12 @@ fn instantiate_with_zero_balance_works() { .account_id; // Check that the BOB contract has been instantiated. - get_contract(&addr); + let contract = get_contract(&addr); + let deposit_account = contract.deposit_account().deref(); // 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!(::Currency::free_balance(&addr), min_balance); + assert_eq!(::Currency::total_balance(&addr), min_balance,); assert_eq!( System::events(), @@ -3211,14 +3179,14 @@ fn instantiate_with_zero_balance_works() { EventRecord { phase: Phase::Initialization, event: RuntimeEvent::System(frame_system::Event::NewAccount { - account: addr.clone() + account: deposit_account.clone(), }), topics: vec![], }, EventRecord { phase: Phase::Initialization, event: RuntimeEvent::Balances(pallet_balances::Event::Endowed { - account: addr.clone(), + account: deposit_account.clone(), free_balance: min_balance, }), topics: vec![], @@ -3227,15 +3195,31 @@ fn instantiate_with_zero_balance_works() { phase: Phase::Initialization, event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { from: ALICE, - to: addr.clone(), + to: deposit_account.clone(), amount: min_balance, }), topics: vec![], }, EventRecord { phase: Phase::Initialization, - event: RuntimeEvent::Balances(pallet_balances::Event::Reserved { - who: addr.clone(), + event: RuntimeEvent::System(frame_system::Event::NewAccount { + account: addr.clone(), + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Balances(pallet_balances::Event::Endowed { + account: addr.clone(), + free_balance: min_balance, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { + from: ALICE, + to: addr.clone(), amount: min_balance, }), topics: vec![], @@ -3292,14 +3276,12 @@ fn instantiate_with_below_existential_deposit_works() { .account_id; // Check that the BOB contract has been instantiated. - get_contract(&addr); + let contract = get_contract(&addr); + let deposit_account = contract.deposit_account().deref(); - // 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, - ); + // Make sure the account exists even though not enough free balance was send + assert_eq!(::Currency::free_balance(&addr), min_balance + 50); + assert_eq!(::Currency::total_balance(&addr), min_balance + 50); assert_eq!( System::events(), @@ -3307,14 +3289,14 @@ fn instantiate_with_below_existential_deposit_works() { EventRecord { phase: Phase::Initialization, event: RuntimeEvent::System(frame_system::Event::NewAccount { - account: addr.clone() + account: deposit_account.clone(), }), topics: vec![], }, EventRecord { phase: Phase::Initialization, event: RuntimeEvent::Balances(pallet_balances::Event::Endowed { - account: addr.clone(), + account: deposit_account.clone(), free_balance: min_balance, }), topics: vec![], @@ -3323,15 +3305,31 @@ fn instantiate_with_below_existential_deposit_works() { phase: Phase::Initialization, event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { from: ALICE, - to: addr.clone(), + to: deposit_account.clone(), amount: min_balance, }), topics: vec![], }, EventRecord { phase: Phase::Initialization, - event: RuntimeEvent::Balances(pallet_balances::Event::Reserved { - who: addr.clone(), + event: RuntimeEvent::System(frame_system::Event::NewAccount { + account: addr.clone() + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Balances(pallet_balances::Event::Endowed { + account: addr.clone(), + free_balance: min_balance, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { + from: ALICE, + to: addr.clone(), amount: min_balance, }), topics: vec![], @@ -3436,6 +3434,9 @@ fn storage_deposit_works() { deposit -= refunded0; assert_eq!(get_contract(&addr).total_deposit(), deposit); + let contract = get_contract(&addr); + let deposit_account = contract.deposit_account().deref(); + assert_eq!( System::events(), vec![ @@ -3460,15 +3461,7 @@ fn storage_deposit_works() { phase: Phase::Initialization, event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { from: ALICE, - to: addr.clone(), - amount: charged0, - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Balances(pallet_balances::Event::Reserved { - who: addr.clone(), + to: deposit_account.clone(), amount: charged0, }), topics: vec![], @@ -3485,15 +3478,7 @@ fn storage_deposit_works() { phase: Phase::Initialization, event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { from: ALICE, - to: addr.clone(), - amount: charged1, - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Balances(pallet_balances::Event::Reserved { - who: addr.clone(), + to: deposit_account.clone(), amount: charged1, }), topics: vec![], @@ -3508,11 +3493,10 @@ fn storage_deposit_works() { }, EventRecord { phase: Phase::Initialization, - event: RuntimeEvent::Balances(pallet_balances::Event::ReserveRepatriated { - from: addr.clone(), + event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { + from: deposit_account.clone(), to: ALICE, amount: refunded0, - destination_status: BalanceStatus::Free, }), topics: vec![], }, @@ -3610,11 +3594,10 @@ fn set_code_extrinsic() { } #[test] -fn call_after_killed_account_needs_funding() { +fn slash_cannot_kill_account() { 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(); let addr = Contracts::bare_instantiate( ALICE, @@ -3633,107 +3616,24 @@ fn call_after_killed_account_needs_funding() { // 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 accept the destruction of the account. + // Try to destroy the account of the contract by slashing. + // The account does not get destroyed because of the consumer reference. + // Slashing can for example happen if the contract takes part in staking. 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( - RuntimeOrigin::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( - RuntimeOrigin::signed(ALICE), - addr.clone(), - 0, - GAS_LIMIT, - None, - vec![], - )); - - // Sending minimum balance should work - assert_ok!(Contracts::call( - RuntimeOrigin::signed(ALICE), - addr.clone(), - min_balance, - GAS_LIMIT, - None, - vec![], - )); - assert_eq!( System::events(), - vec![ - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::System(frame_system::Event::KilledAccount { - account: addr.clone() - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Balances(pallet_balances::Event::Slashed { - who: addr.clone(), - amount: min_balance + 700 - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Contracts(crate::Event::Called { - caller: ALICE, - contract: addr.clone(), - }), - topics: vec![hash(&ALICE), hash(&addr)], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::System(frame_system::Event::NewAccount { - account: addr.clone() - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Balances(pallet_balances::Event::Endowed { - account: addr.clone(), - free_balance: min_balance - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { - from: ALICE, - to: addr.clone(), - amount: min_balance - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Contracts(crate::Event::Called { - caller: ALICE, - contract: addr.clone(), - }), - topics: vec![hash(&ALICE), hash(&addr)], - }, - ] + vec![EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Balances(pallet_balances::Event::Slashed { + who: addr.clone(), + amount: 700, // slash didn't remove the minimum balance + }), + topics: vec![], + },] ); }); } diff --git a/frame/contracts/src/weights.rs b/frame/contracts/src/weights.rs index 057a9257d4268..d032615843656 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: 2023-02-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-02-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -178,8 +178,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `109` // Estimated: `604` - // Minimum execution time: 2_507 nanoseconds. - Weight::from_ref_time(2_650_000) + // Minimum execution time: 2_591 nanoseconds. + Weight::from_ref_time(2_817_000) .saturating_add(Weight::from_proof_size(604)) .saturating_add(T::DbWeight::get().reads(1_u64)) } @@ -190,11 +190,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `481 + k * (69 ±0)` // Estimated: `471 + k * (70 ±0)` - // Minimum execution time: 9_953 nanoseconds. - Weight::from_ref_time(6_467_352) + // Minimum execution time: 10_190 nanoseconds. + Weight::from_ref_time(6_642_117) .saturating_add(Weight::from_proof_size(471)) - // Standard Error: 1_074 - .saturating_add(Weight::from_ref_time(943_946).saturating_mul(k.into())) + // Standard Error: 992 + .saturating_add(Weight::from_ref_time(919_828).saturating_mul(k.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(k.into()))) @@ -207,11 +207,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `281 + q * (33 ±0)` // Estimated: `763 + q * (33 ±0)` - // Minimum execution time: 2_545 nanoseconds. - Weight::from_ref_time(10_080_106) + // Minimum execution time: 2_598 nanoseconds. + Weight::from_ref_time(10_288_252) .saturating_add(Weight::from_proof_size(763)) - // Standard Error: 2_929 - .saturating_add(Weight::from_ref_time(1_078_265).saturating_mul(q.into())) + // Standard Error: 2_886 + .saturating_add(Weight::from_ref_time(1_092_420).saturating_mul(q.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_proof_size(33).saturating_mul(q.into())) @@ -225,17 +225,17 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `270 + c * (1 ±0)` // Estimated: `3025 + c * (2 ±0)` - // Minimum execution time: 34_613 nanoseconds. - Weight::from_ref_time(27_355_774) + // Minimum execution time: 34_338 nanoseconds. + Weight::from_ref_time(32_159_677) .saturating_add(Weight::from_proof_size(3025)) - // Standard Error: 81 - .saturating_add(Weight::from_ref_time(51_954).saturating_mul(c.into())) + // Standard Error: 53 + .saturating_add(Weight::from_ref_time(51_034).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_proof_size(2).saturating_mul(c.into())) } /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -247,13 +247,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `c` is `[0, 125952]`. fn call_with_code_per_byte(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `771` - // Estimated: `16780 + c * (5 ±0)` - // Minimum execution time: 386_104 nanoseconds. - Weight::from_ref_time(396_718_823) - .saturating_add(Weight::from_proof_size(16780)) + // Measured: `803` + // Estimated: `16930 + c * (5 ±0)` + // Minimum execution time: 385_587 nanoseconds. + Weight::from_ref_time(395_545_811) + .saturating_add(Weight::from_proof_size(16930)) // Standard Error: 27 - .saturating_add(Weight::from_ref_time(31_370).saturating_mul(c.into())) + .saturating_add(Weight::from_ref_time(31_342).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(Weight::from_proof_size(5).saturating_mul(c.into())) @@ -263,10 +263,10 @@ impl WeightInfo for SubstrateWeight { /// Storage: Contracts Nonce (r:1 w:1) /// Proof: Contracts Nonce (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) - /// Storage: System Account (r:1 w:1) + /// Storage: System Account (r:2 w:2) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: System EventTopics (r:3 w:3) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) @@ -279,29 +279,29 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[0, 1048576]`. fn instantiate_with_code(c: u32, i: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `257` - // Estimated: `17752` - // Minimum execution time: 3_786_500 nanoseconds. - Weight::from_ref_time(672_511_565) - .saturating_add(Weight::from_proof_size(17752)) - // Standard Error: 281 - .saturating_add(Weight::from_ref_time(94_538).saturating_mul(c.into())) + // Measured: `270` + // Estimated: `20267` + // Minimum execution time: 3_799_742 nanoseconds. + Weight::from_ref_time(670_115_588) + .saturating_add(Weight::from_proof_size(20267)) + // Standard Error: 287 + .saturating_add(Weight::from_ref_time(93_885).saturating_mul(c.into())) // Standard Error: 16 - .saturating_add(Weight::from_ref_time(1_364).saturating_mul(i.into())) + .saturating_add(Weight::from_ref_time(1_367).saturating_mul(i.into())) // Standard Error: 16 - .saturating_add(Weight::from_ref_time(1_768).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(8_u64)) - .saturating_add(T::DbWeight::get().writes(9_u64)) + .saturating_add(Weight::from_ref_time(1_781).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(9_u64)) + .saturating_add(T::DbWeight::get().writes(10_u64)) } /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Contracts Nonce (r:1 w:1) /// Proof: Contracts Nonce (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) - /// Storage: System Account (r:1 w:1) + /// Storage: System Account (r:2 w:2) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts OwnerInfoOf (r:1 w:1) /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Measured) @@ -311,20 +311,20 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[0, 1048576]`. fn instantiate(i: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `533` - // Estimated: `19543` - // Minimum execution time: 1_927_365 nanoseconds. - Weight::from_ref_time(189_843_928) - .saturating_add(Weight::from_proof_size(19543)) + // Measured: `546` + // Estimated: `22039` + // Minimum execution time: 1_949_008 nanoseconds. + Weight::from_ref_time(214_033_418) + .saturating_add(Weight::from_proof_size(22039)) // Standard Error: 8 - .saturating_add(Weight::from_ref_time(1_677).saturating_mul(i.into())) + .saturating_add(Weight::from_ref_time(1_666).saturating_mul(i.into())) // Standard Error: 8 - .saturating_add(Weight::from_ref_time(1_803).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(8_u64)) - .saturating_add(T::DbWeight::get().writes(6_u64)) + .saturating_add(Weight::from_ref_time(1_801).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(9_u64)) + .saturating_add(T::DbWeight::get().writes(7_u64)) } /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -335,11 +335,11 @@ impl WeightInfo for SubstrateWeight { /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) fn call() -> Weight { // Proof Size summary in bytes: - // Measured: `823` - // Estimated: `16985` - // Minimum execution time: 146_354 nanoseconds. - Weight::from_ref_time(147_693_000) - .saturating_add(Weight::from_proof_size(16985)) + // Measured: `855` + // Estimated: `17145` + // Minimum execution time: 146_654 nanoseconds. + Weight::from_ref_time(147_528_000) + .saturating_add(Weight::from_proof_size(17145)) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -356,11 +356,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `109` // Estimated: `5386` - // Minimum execution time: 388_107 nanoseconds. - Weight::from_ref_time(383_172_702) + // Minimum execution time: 387_889 nanoseconds. + Weight::from_ref_time(391_379_335) .saturating_add(Weight::from_proof_size(5386)) - // Standard Error: 73 - .saturating_add(Weight::from_ref_time(95_037).saturating_mul(c.into())) + // Standard Error: 89 + .saturating_add(Weight::from_ref_time(94_810).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -376,32 +376,32 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `287` // Estimated: `6098` - // Minimum execution time: 26_278 nanoseconds. - Weight::from_ref_time(26_682_000) + // Minimum execution time: 26_014 nanoseconds. + Weight::from_ref_time(26_510_000) .saturating_add(Weight::from_proof_size(6098)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts OwnerInfoOf (r:2 w:2) /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Measured) /// Storage: System EventTopics (r:3 w:3) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) fn set_code() -> Weight { // Proof Size summary in bytes: - // Measured: `634` - // Estimated: `16752` - // Minimum execution time: 30_223 nanoseconds. - Weight::from_ref_time(30_737_000) - .saturating_add(Weight::from_proof_size(16752)) + // Measured: `666` + // Estimated: `16848` + // Minimum execution time: 30_177 nanoseconds. + Weight::from_ref_time(30_639_000) + .saturating_add(Weight::from_proof_size(16848)) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -411,13 +411,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_caller(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `845 + r * (480 ±0)` - // Estimated: `17120 + r * (2400 ±0)` - // Minimum execution time: 374_780 nanoseconds. - Weight::from_ref_time(379_468_453) - .saturating_add(Weight::from_proof_size(17120)) - // Standard Error: 45_809 - .saturating_add(Weight::from_ref_time(17_553_577).saturating_mul(r.into())) + // Measured: `877 + r * (480 ±0)` + // Estimated: `17295 + r * (2400 ±0)` + // Minimum execution time: 373_786 nanoseconds. + Weight::from_ref_time(377_332_691) + .saturating_add(Weight::from_proof_size(17295)) + // Standard Error: 51_211 + .saturating_add(Weight::from_ref_time(17_715_615).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_proof_size(2400).saturating_mul(r.into())) @@ -425,7 +425,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1601 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -435,22 +435,22 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_is_contract(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `882 + r * (19218 ±0)` - // Estimated: `17110 + r * (294100 ±0)` - // Minimum execution time: 374_399 nanoseconds. - Weight::from_ref_time(228_569_211) - .saturating_add(Weight::from_proof_size(17110)) - // Standard Error: 492_562 - .saturating_add(Weight::from_ref_time(251_682_897).saturating_mul(r.into())) + // Measured: `917 + r * (21778 ±0)` + // Estimated: `17295 + r * (306895 ±0)` + // Minimum execution time: 374_009 nanoseconds. + Weight::from_ref_time(238_991_986) + .saturating_add(Weight::from_proof_size(17295)) + // Standard Error: 464_711 + .saturating_add(Weight::from_ref_time(249_099_538).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(294100).saturating_mul(r.into())) + .saturating_add(Weight::from_proof_size(306895).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1601 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -460,22 +460,22 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_code_hash(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `889 + r * (19539 ±0)` - // Estimated: `17170 + r * (295700 ±0)` - // Minimum execution time: 375_980 nanoseconds. - Weight::from_ref_time(232_604_331) - .saturating_add(Weight::from_proof_size(17170)) - // Standard Error: 491_912 - .saturating_add(Weight::from_ref_time(299_479_335).saturating_mul(r.into())) + // Measured: `921 + r * (22099 ±0)` + // Estimated: `17340 + r * (308500 ±0)` + // Minimum execution time: 375_058 nanoseconds. + Weight::from_ref_time(238_765_068) + .saturating_add(Weight::from_proof_size(17340)) + // Standard Error: 662_617 + .saturating_add(Weight::from_ref_time(302_175_089).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(295700).saturating_mul(r.into())) + .saturating_add(Weight::from_proof_size(308500).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -485,13 +485,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_own_code_hash(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `852 + r * (480 ±0)` - // Estimated: `17155 + r * (2400 ±0)` - // Minimum execution time: 375_075 nanoseconds. - Weight::from_ref_time(381_217_372) - .saturating_add(Weight::from_proof_size(17155)) - // Standard Error: 63_950 - .saturating_add(Weight::from_ref_time(21_872_316).saturating_mul(r.into())) + // Measured: `884 + r * (480 ±0)` + // Estimated: `17330 + r * (2400 ±0)` + // Minimum execution time: 374_747 nanoseconds. + Weight::from_ref_time(376_482_380) + .saturating_add(Weight::from_proof_size(17330)) + // Standard Error: 61_919 + .saturating_add(Weight::from_ref_time(22_376_795).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_proof_size(2400).saturating_mul(r.into())) @@ -499,7 +499,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -509,13 +509,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_caller_is_origin(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `842 + r * (240 ±0)` - // Estimated: `17080 + r * (1200 ±0)` - // Minimum execution time: 373_260 nanoseconds. - Weight::from_ref_time(377_987_666) - .saturating_add(Weight::from_proof_size(17080)) - // Standard Error: 35_603 - .saturating_add(Weight::from_ref_time(11_274_165).saturating_mul(r.into())) + // Measured: `874 + r * (240 ±0)` + // Estimated: `17265 + r * (1200 ±0)` + // Minimum execution time: 372_287 nanoseconds. + Weight::from_ref_time(376_250_858) + .saturating_add(Weight::from_proof_size(17265)) + // Standard Error: 40_119 + .saturating_add(Weight::from_ref_time(11_359_647).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_proof_size(1200).saturating_mul(r.into())) @@ -523,7 +523,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -533,13 +533,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_address(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `846 + r * (480 ±0)` - // Estimated: `17100 + r * (2400 ±0)` - // Minimum execution time: 374_605 nanoseconds. - Weight::from_ref_time(379_395_443) - .saturating_add(Weight::from_proof_size(17100)) - // Standard Error: 49_646 - .saturating_add(Weight::from_ref_time(17_487_585).saturating_mul(r.into())) + // Measured: `878 + r * (480 ±0)` + // Estimated: `17260 + r * (2400 ±0)` + // Minimum execution time: 374_445 nanoseconds. + Weight::from_ref_time(377_243_521) + .saturating_add(Weight::from_proof_size(17260)) + // Standard Error: 53_032 + .saturating_add(Weight::from_ref_time(17_684_246).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_proof_size(2400).saturating_mul(r.into())) @@ -547,7 +547,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -557,21 +557,21 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_gas_left(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `847 + r * (480 ±0)` - // Estimated: `17105 + r * (2400 ±0)` - // Minimum execution time: 374_620 nanoseconds. - Weight::from_ref_time(379_623_792) - .saturating_add(Weight::from_proof_size(17105)) - // Standard Error: 49_990 - .saturating_add(Weight::from_ref_time(17_226_706).saturating_mul(r.into())) + // Measured: `879 + r * (480 ±0)` + // Estimated: `17250 + r * (2405 ±0)` + // Minimum execution time: 374_029 nanoseconds. + Weight::from_ref_time(380_415_186) + .saturating_add(Weight::from_proof_size(17250)) + // Standard Error: 60_562 + .saturating_add(Weight::from_ref_time(17_152_599).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(2400).saturating_mul(r.into())) + .saturating_add(Weight::from_proof_size(2405).saturating_mul(r.into())) } /// Storage: System Account (r:2 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -581,13 +581,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_balance(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1017 + r * (480 ±0)` - // Estimated: `19673 + r * (2456 ±4)` - // Minimum execution time: 374_002 nanoseconds. - Weight::from_ref_time(384_615_649) - .saturating_add(Weight::from_proof_size(19673)) - // Standard Error: 85_633 - .saturating_add(Weight::from_ref_time(95_227_118).saturating_mul(r.into())) + // Measured: `1049 + r * (480 ±0)` + // Estimated: `19849 + r * (2456 ±0)` + // Minimum execution time: 373_999 nanoseconds. + Weight::from_ref_time(381_757_033) + .saturating_add(Weight::from_proof_size(19849)) + // Standard Error: 97_983 + .saturating_add(Weight::from_ref_time(98_290_984).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_proof_size(2456).saturating_mul(r.into())) @@ -595,7 +595,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -605,13 +605,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_value_transferred(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `856 + r * (480 ±0)` - // Estimated: `17200 + r * (2400 ±0)` - // Minimum execution time: 375_307 nanoseconds. - Weight::from_ref_time(378_389_705) - .saturating_add(Weight::from_proof_size(17200)) - // Standard Error: 42_265 - .saturating_add(Weight::from_ref_time(17_316_680).saturating_mul(r.into())) + // Measured: `888 + r * (480 ±0)` + // Estimated: `17360 + r * (2400 ±0)` + // Minimum execution time: 374_197 nanoseconds. + Weight::from_ref_time(377_755_896) + .saturating_add(Weight::from_proof_size(17360)) + // Standard Error: 60_542 + .saturating_add(Weight::from_ref_time(17_442_065).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_proof_size(2400).saturating_mul(r.into())) @@ -619,7 +619,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -629,13 +629,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_minimum_balance(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `854 + r * (480 ±0)` - // Estimated: `17140 + r * (2400 ±0)` - // Minimum execution time: 374_878 nanoseconds. - Weight::from_ref_time(379_364_066) - .saturating_add(Weight::from_proof_size(17140)) - // Standard Error: 49_158 - .saturating_add(Weight::from_ref_time(17_111_145).saturating_mul(r.into())) + // Measured: `886 + r * (480 ±0)` + // Estimated: `17290 + r * (2400 ±0)` + // Minimum execution time: 373_888 nanoseconds. + Weight::from_ref_time(377_825_771) + .saturating_add(Weight::from_proof_size(17290)) + // Standard Error: 38_026 + .saturating_add(Weight::from_ref_time(17_147_903).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_proof_size(2400).saturating_mul(r.into())) @@ -643,7 +643,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -653,13 +653,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_block_number(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `851 + r * (480 ±0)` - // Estimated: `17125 + r * (2400 ±0)` - // Minimum execution time: 374_981 nanoseconds. - Weight::from_ref_time(381_539_022) - .saturating_add(Weight::from_proof_size(17125)) - // Standard Error: 61_419 - .saturating_add(Weight::from_ref_time(17_062_381).saturating_mul(r.into())) + // Measured: `883 + r * (480 ±0)` + // Estimated: `17315 + r * (2400 ±0)` + // Minimum execution time: 373_904 nanoseconds. + Weight::from_ref_time(378_652_372) + .saturating_add(Weight::from_proof_size(17315)) + // Standard Error: 43_833 + .saturating_add(Weight::from_ref_time(16_936_781).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_proof_size(2400).saturating_mul(r.into())) @@ -667,7 +667,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -677,13 +677,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_now(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `842 + r * (480 ±0)` - // Estimated: `17100 + r * (2400 ±0)` - // Minimum execution time: 374_798 nanoseconds. - Weight::from_ref_time(372_659_915) - .saturating_add(Weight::from_proof_size(17100)) - // Standard Error: 151_499 - .saturating_add(Weight::from_ref_time(18_192_683).saturating_mul(r.into())) + // Measured: `874 + r * (480 ±0)` + // Estimated: `17245 + r * (2400 ±0)` + // Minimum execution time: 373_473 nanoseconds. + Weight::from_ref_time(376_386_312) + .saturating_add(Weight::from_proof_size(17245)) + // Standard Error: 46_945 + .saturating_add(Weight::from_ref_time(17_336_462).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_proof_size(2400).saturating_mul(r.into())) @@ -691,7 +691,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -703,13 +703,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_weight_to_fee(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `919 + r * (800 ±0)` - // Estimated: `18835 + r * (4805 ±0)` - // Minimum execution time: 374_841 nanoseconds. - Weight::from_ref_time(385_475_889) - .saturating_add(Weight::from_proof_size(18835)) - // Standard Error: 106_207 - .saturating_add(Weight::from_ref_time(88_099_987).saturating_mul(r.into())) + // Measured: `951 + r * (800 ±0)` + // Estimated: `19046 + r * (4805 ±0)` + // Minimum execution time: 373_661 nanoseconds. + Weight::from_ref_time(385_824_015) + .saturating_add(Weight::from_proof_size(19046)) + // Standard Error: 75_964 + .saturating_add(Weight::from_ref_time(88_530_074).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_proof_size(4805).saturating_mul(r.into())) @@ -717,7 +717,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -727,13 +727,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_gas(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `809 + r * (320 ±0)` - // Estimated: `16955 + r * (1600 ±0)` - // Minimum execution time: 134_436 nanoseconds. - Weight::from_ref_time(137_789_498) - .saturating_add(Weight::from_proof_size(16955)) - // Standard Error: 10_622 - .saturating_add(Weight::from_ref_time(8_144_024).saturating_mul(r.into())) + // Measured: `841 + r * (320 ±0)` + // Estimated: `17120 + r * (1600 ±0)` + // Minimum execution time: 133_849 nanoseconds. + Weight::from_ref_time(137_283_391) + .saturating_add(Weight::from_proof_size(17120)) + // Standard Error: 13_312 + .saturating_add(Weight::from_ref_time(8_055_328).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_proof_size(1600).saturating_mul(r.into())) @@ -741,7 +741,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -751,13 +751,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_input(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `844 + r * (480 ±0)` - // Estimated: `17085 + r * (2400 ±0)` - // Minimum execution time: 374_480 nanoseconds. - Weight::from_ref_time(379_723_392) - .saturating_add(Weight::from_proof_size(17085)) - // Standard Error: 50_240 - .saturating_add(Weight::from_ref_time(15_358_041).saturating_mul(r.into())) + // Measured: `876 + r * (480 ±0)` + // Estimated: `17245 + r * (2400 ±0)` + // Minimum execution time: 373_468 nanoseconds. + Weight::from_ref_time(376_121_093) + .saturating_add(Weight::from_proof_size(17245)) + // Standard Error: 61_857 + .saturating_add(Weight::from_ref_time(15_868_414).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_proof_size(2400).saturating_mul(r.into())) @@ -765,7 +765,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -775,20 +775,20 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 1024]`. fn seal_input_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1324` - // Estimated: `19490` - // Minimum execution time: 392_282 nanoseconds. - Weight::from_ref_time(418_943_323) - .saturating_add(Weight::from_proof_size(19490)) - // Standard Error: 4_673 - .saturating_add(Weight::from_ref_time(9_664_301).saturating_mul(n.into())) + // Measured: `1356` + // Estimated: `19650` + // Minimum execution time: 390_668 nanoseconds. + Weight::from_ref_time(419_608_449) + .saturating_add(Weight::from_proof_size(19650)) + // Standard Error: 4_890 + .saturating_add(Weight::from_ref_time(9_672_288).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -798,11 +798,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1]`. fn seal_return(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `832 + r * (45 ±0)` - // Estimated: `17030 + r * (225 ±0)` - // Minimum execution time: 372_207 nanoseconds. - Weight::from_ref_time(376_232_444) - .saturating_add(Weight::from_proof_size(17030)) + // Measured: `864 + r * (45 ±0)` + // Estimated: `17190 + r * (225 ±0)` + // Minimum execution time: 371_309 nanoseconds. + Weight::from_ref_time(373_625_402) + .saturating_add(Weight::from_proof_size(17190)) + // Standard Error: 419_605 + .saturating_add(Weight::from_ref_time(1_737_397).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_proof_size(225).saturating_mul(r.into())) @@ -810,7 +812,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -820,20 +822,20 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 1024]`. fn seal_return_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `842` - // Estimated: `17125` - // Minimum execution time: 374_743 nanoseconds. - Weight::from_ref_time(377_365_053) - .saturating_add(Weight::from_proof_size(17125)) - // Standard Error: 1_073 - .saturating_add(Weight::from_ref_time(231_251).saturating_mul(n.into())) + // Measured: `874` + // Estimated: `17285` + // Minimum execution time: 374_094 nanoseconds. + Weight::from_ref_time(375_965_200) + .saturating_add(Weight::from_proof_size(17285)) + // Standard Error: 1_127 + .saturating_add(Weight::from_ref_time(232_645).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: System Account (r:3 w:3) + /// Storage: System Account (r:4 w:4) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -847,23 +849,23 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1]`. fn seal_terminate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `874 + r * (280 ±0)` - // Estimated: `19880 + r * (11465 ±0)` - // Minimum execution time: 374_873 nanoseconds. - Weight::from_ref_time(378_422_289) - .saturating_add(Weight::from_proof_size(19880)) - // Standard Error: 979_734 - .saturating_add(Weight::from_ref_time(57_035_310).saturating_mul(r.into())) + // Measured: `906 + r * (452 ±0)` + // Estimated: `20242 + r * (15004 ±0)` + // Minimum execution time: 373_123 nanoseconds. + Weight::from_ref_time(374_924_634) + .saturating_add(Weight::from_proof_size(20242)) + // Standard Error: 378_010 + .saturating_add(Weight::from_ref_time(70_441_665).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) - .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(r.into()))) + .saturating_add(T::DbWeight::get().reads((6_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(T::DbWeight::get().writes((6_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_proof_size(11465).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().writes((7_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_proof_size(15004).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -875,13 +877,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_random(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `889 + r * (800 ±0)` - // Estimated: `18643 + r * (4805 ±0)` - // Minimum execution time: 375_001 nanoseconds. - Weight::from_ref_time(382_558_599) - .saturating_add(Weight::from_proof_size(18643)) - // Standard Error: 94_918 - .saturating_add(Weight::from_ref_time(112_973_277).saturating_mul(r.into())) + // Measured: `921 + r * (800 ±0)` + // Estimated: `18835 + r * (4805 ±0)` + // Minimum execution time: 373_291 nanoseconds. + Weight::from_ref_time(385_684_344) + .saturating_add(Weight::from_proof_size(18835)) + // Standard Error: 99_025 + .saturating_add(Weight::from_ref_time(111_308_793).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_proof_size(4805).saturating_mul(r.into())) @@ -889,7 +891,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -899,13 +901,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_deposit_event(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `842 + r * (800 ±0)` - // Estimated: `17075 + r * (4000 ±0)` - // Minimum execution time: 372_547 nanoseconds. - Weight::from_ref_time(383_278_916) - .saturating_add(Weight::from_proof_size(17075)) - // Standard Error: 128_339 - .saturating_add(Weight::from_ref_time(229_356_088).saturating_mul(r.into())) + // Measured: `874 + r * (800 ±0)` + // Estimated: `17250 + r * (4000 ±0)` + // Minimum execution time: 371_900 nanoseconds. + Weight::from_ref_time(384_166_626) + .saturating_add(Weight::from_proof_size(17250)) + // Standard Error: 205_255 + .saturating_add(Weight::from_ref_time(229_214_157).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_proof_size(4000).saturating_mul(r.into())) @@ -913,7 +915,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -924,15 +926,15 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 16]`. fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1778 + t * (2608 ±0) + n * (8 ±0)` - // Estimated: `21675 + t * (211030 ±0) + n * (50 ±0)` - // Minimum execution time: 1_290_432 nanoseconds. - Weight::from_ref_time(595_859_216) - .saturating_add(Weight::from_proof_size(21675)) - // Standard Error: 602_943 - .saturating_add(Weight::from_ref_time(178_128_149).saturating_mul(t.into())) - // Standard Error: 165_597 - .saturating_add(Weight::from_ref_time(71_475_468).saturating_mul(n.into())) + // Measured: `1821 + t * (2608 ±0) + n * (7 ±0)` + // Estimated: `21870 + t * (211030 ±0) + n * (50 ±0)` + // Minimum execution time: 1_289_873 nanoseconds. + Weight::from_ref_time(581_702_206) + .saturating_add(Weight::from_proof_size(21870)) + // Standard Error: 665_638 + .saturating_add(Weight::from_ref_time(181_470_553).saturating_mul(t.into())) + // Standard Error: 182_816 + .saturating_add(Weight::from_ref_time(71_635_250).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(t.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -943,7 +945,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -953,13 +955,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_debug_message(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `841 + r * (560 ±0)` - // Estimated: `17065 + r * (2800 ±0)` - // Minimum execution time: 149_020 nanoseconds. - Weight::from_ref_time(152_893_012) - .saturating_add(Weight::from_proof_size(17065)) - // Standard Error: 31_804 - .saturating_add(Weight::from_ref_time(14_497_512).saturating_mul(r.into())) + // Measured: `873 + r * (560 ±0)` + // Estimated: `17240 + r * (2800 ±0)` + // Minimum execution time: 148_635 nanoseconds. + Weight::from_ref_time(154_095_712) + .saturating_add(Weight::from_proof_size(17240)) + // Standard Error: 77_790 + .saturating_add(Weight::from_ref_time(14_837_085).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_proof_size(2800).saturating_mul(r.into())) @@ -967,7 +969,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: MaxEncodedLen) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: MaxEncodedLen) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: MaxEncodedLen) /// Storage: Timestamp Now (r:1 w:0) @@ -977,13 +979,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `i` is `[0, 1024]`. fn seal_debug_message_per_kb(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `125792` - // Estimated: `265059` - // Minimum execution time: 502_589 nanoseconds. - Weight::from_ref_time(506_695_307) - .saturating_add(Weight::from_proof_size(265059)) - // Standard Error: 2_148 - .saturating_add(Weight::from_ref_time(814_647).saturating_mul(i.into())) + // Measured: `125824` + // Estimated: `265128` + // Minimum execution time: 501_014 nanoseconds. + Weight::from_ref_time(505_634_218) + .saturating_add(Weight::from_proof_size(265128)) + // Standard Error: 2_441 + .saturating_add(Weight::from_ref_time(819_257).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -992,85 +994,85 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 10]`. fn seal_set_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `883 + r * (23417 ±0)` - // Estimated: `883 + r * (23417 ±0)` - // Minimum execution time: 375_473 nanoseconds. - Weight::from_ref_time(291_125_810) - .saturating_add(Weight::from_proof_size(883)) - // Standard Error: 824_971 - .saturating_add(Weight::from_ref_time(477_999_695).saturating_mul(r.into())) + // Measured: `911 + r * (23420 ±0)` + // Estimated: `911 + r * (23418 ±0)` + // Minimum execution time: 375_301 nanoseconds. + Weight::from_ref_time(291_498_841) + .saturating_add(Weight::from_proof_size(911)) + // Standard Error: 809_989 + .saturating_add(Weight::from_ref_time(464_550_291).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((80_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_proof_size(23417).saturating_mul(r.into())) + .saturating_add(Weight::from_proof_size(23418).saturating_mul(r.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_new_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `12583 + n * (11969 ±0)` - // Estimated: `8500 + n * (12813 ±61)` - // Minimum execution time: 515_962 nanoseconds. - Weight::from_ref_time(697_904_030) - .saturating_add(Weight::from_proof_size(8500)) - // Standard Error: 1_684_000 - .saturating_add(Weight::from_ref_time(98_411_710).saturating_mul(n.into())) + // Measured: `12672 + n * (11945 ±0)` + // Estimated: `8529 + n * (12814 ±61)` + // Minimum execution time: 506_318 nanoseconds. + Weight::from_ref_time(676_935_313) + .saturating_add(Weight::from_proof_size(8529)) + // Standard Error: 1_589_291 + .saturating_add(Weight::from_ref_time(97_839_399).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(52_u64)) .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(50_u64)) .saturating_add(T::DbWeight::get().writes((7_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_proof_size(12813).saturating_mul(n.into())) + .saturating_add(Weight::from_proof_size(12814).saturating_mul(n.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_old_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `15138 + n * (175775 ±0)` - // Estimated: `9898 + n * (176855 ±74)` - // Minimum execution time: 515_828 nanoseconds. - Weight::from_ref_time(661_240_495) - .saturating_add(Weight::from_proof_size(9898)) - // Standard Error: 1_338_661 - .saturating_add(Weight::from_ref_time(65_767_819).saturating_mul(n.into())) + // Measured: `15170 + n * (175775 ±0)` + // Estimated: `9914 + n * (176858 ±74)` + // Minimum execution time: 506_148 nanoseconds. + Weight::from_ref_time(648_278_778) + .saturating_add(Weight::from_proof_size(9914)) + // Standard Error: 1_343_586 + .saturating_add(Weight::from_ref_time(65_789_595).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(51_u64)) .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(49_u64)) .saturating_add(T::DbWeight::get().writes((7_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_proof_size(176855).saturating_mul(n.into())) + .saturating_add(Weight::from_proof_size(176858).saturating_mul(n.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 10]`. fn seal_clear_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `876 + r * (23098 ±0)` - // Estimated: `881 + r * (23097 ±0)` - // Minimum execution time: 375_528 nanoseconds. - Weight::from_ref_time(296_453_612) - .saturating_add(Weight::from_proof_size(881)) - // Standard Error: 809_232 - .saturating_add(Weight::from_ref_time(465_365_815).saturating_mul(r.into())) + // Measured: `903 + r * (23099 ±0)` + // Estimated: `908 + r * (23099 ±0)` + // Minimum execution time: 374_344 nanoseconds. + Weight::from_ref_time(293_272_061) + .saturating_add(Weight::from_proof_size(908)) + // Standard Error: 810_412 + .saturating_add(Weight::from_ref_time(453_315_956).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((80_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_proof_size(23097).saturating_mul(r.into())) + .saturating_add(Weight::from_proof_size(23099).saturating_mul(r.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `n` is `[0, 8]`. fn seal_clear_storage_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `14863 + n * (175768 ±0)` - // Estimated: `9519 + n * (176867 ±75)` - // Minimum execution time: 480_427 nanoseconds. - Weight::from_ref_time(640_337_570) - .saturating_add(Weight::from_proof_size(9519)) - // Standard Error: 1_497_141 - .saturating_add(Weight::from_ref_time(67_963_696).saturating_mul(n.into())) + // Measured: `14895 + n * (175768 ±0)` + // Estimated: `9551 + n * (176867 ±75)` + // Minimum execution time: 478_564 nanoseconds. + Weight::from_ref_time(630_839_142) + .saturating_add(Weight::from_proof_size(9551)) + // Standard Error: 1_427_520 + .saturating_add(Weight::from_ref_time(66_813_592).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(51_u64)) .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(48_u64)) @@ -1082,30 +1084,30 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 10]`. fn seal_get_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `878 + r * (23740 ±0)` - // Estimated: `880 + r * (23739 ±0)` - // Minimum execution time: 375_725 nanoseconds. - Weight::from_ref_time(307_839_394) - .saturating_add(Weight::from_proof_size(880)) - // Standard Error: 710_694 - .saturating_add(Weight::from_ref_time(381_738_407).saturating_mul(r.into())) + // Measured: `896 + r * (23744 ±0)` + // Estimated: `909 + r * (23740 ±0)` + // Minimum execution time: 374_479 nanoseconds. + Weight::from_ref_time(311_839_315) + .saturating_add(Weight::from_proof_size(909)) + // Standard Error: 666_553 + .saturating_add(Weight::from_ref_time(371_213_042).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(23739).saturating_mul(r.into())) + .saturating_add(Weight::from_proof_size(23740).saturating_mul(r.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `n` is `[0, 8]`. fn seal_get_storage_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `15469 + n * (175775 ±0)` - // Estimated: `10010 + n * (176900 ±76)` - // Minimum execution time: 461_871 nanoseconds. - Weight::from_ref_time(605_755_493) - .saturating_add(Weight::from_proof_size(10010)) - // Standard Error: 1_375_044 - .saturating_add(Weight::from_ref_time(161_332_330).saturating_mul(n.into())) + // Measured: `15501 + n * (175775 ±0)` + // Estimated: `10042 + n * (176900 ±76)` + // Minimum execution time: 460_639 nanoseconds. + Weight::from_ref_time(591_187_094) + .saturating_add(Weight::from_proof_size(10042)) + // Standard Error: 1_233_792 + .saturating_add(Weight::from_ref_time(160_874_477).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(51_u64)) .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1116,47 +1118,47 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 10]`. fn seal_contains_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `871 + r * (23100 ±0)` - // Estimated: `873 + r * (23099 ±0)` - // Minimum execution time: 375_325 nanoseconds. - Weight::from_ref_time(305_508_307) - .saturating_add(Weight::from_proof_size(873)) - // Standard Error: 715_627 - .saturating_add(Weight::from_ref_time(369_985_438).saturating_mul(r.into())) + // Measured: `914 + r * (23098 ±0)` + // Estimated: `920 + r * (23098 ±0)` + // Minimum execution time: 374_272 nanoseconds. + Weight::from_ref_time(311_446_269) + .saturating_add(Weight::from_proof_size(920)) + // Standard Error: 630_307 + .saturating_add(Weight::from_ref_time(357_134_931).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(23099).saturating_mul(r.into())) + .saturating_add(Weight::from_proof_size(23098).saturating_mul(r.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `n` is `[0, 8]`. fn seal_contains_storage_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `14814 + n * (175782 ±0)` - // Estimated: `9502 + n * (176872 ±75)` - // Minimum execution time: 457_128 nanoseconds. - Weight::from_ref_time(582_799_799) - .saturating_add(Weight::from_proof_size(9502)) - // Standard Error: 1_151_126 - .saturating_add(Weight::from_ref_time(63_425_277).saturating_mul(n.into())) + // Measured: `14839 + n * (175789 ±0)` + // Estimated: `9532 + n * (176874 ±75)` + // Minimum execution time: 456_013 nanoseconds. + Weight::from_ref_time(575_116_352) + .saturating_add(Weight::from_proof_size(9532)) + // Standard Error: 1_122_298 + .saturating_add(Weight::from_ref_time(61_786_107).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(51_u64)) .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(176872).saturating_mul(n.into())) + .saturating_add(Weight::from_proof_size(176874).saturating_mul(n.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 10]`. fn seal_take_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `879 + r * (23740 ±0)` - // Estimated: `881 + r * (23739 ±0)` - // Minimum execution time: 375_918 nanoseconds. - Weight::from_ref_time(293_217_646) - .saturating_add(Weight::from_proof_size(881)) - // Standard Error: 840_266 - .saturating_add(Weight::from_ref_time(478_374_701).saturating_mul(r.into())) + // Measured: `911 + r * (23740 ±0)` + // Estimated: `913 + r * (23739 ±0)` + // Minimum execution time: 374_621 nanoseconds. + Weight::from_ref_time(299_689_489) + .saturating_add(Weight::from_proof_size(913)) + // Standard Error: 757_735 + .saturating_add(Weight::from_ref_time(465_213_246).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1168,13 +1170,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 8]`. fn seal_take_storage_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `15470 + n * (175775 ±0)` - // Estimated: `10010 + n * (176898 ±76)` - // Minimum execution time: 484_207 nanoseconds. - Weight::from_ref_time(664_065_436) - .saturating_add(Weight::from_proof_size(10010)) - // Standard Error: 1_655_442 - .saturating_add(Weight::from_ref_time(166_258_757).saturating_mul(n.into())) + // Measured: `15502 + n * (175775 ±0)` + // Estimated: `10042 + n * (176898 ±76)` + // Minimum execution time: 481_980 nanoseconds. + Weight::from_ref_time(647_289_053) + .saturating_add(Weight::from_proof_size(10042)) + // Standard Error: 1_556_155 + .saturating_add(Weight::from_ref_time(166_592_657).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(51_u64)) .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(48_u64)) @@ -1184,7 +1186,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: System Account (r:1602 w:1601) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -1194,23 +1196,23 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_transfer(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1393 + r * (3602 ±0)` - // Estimated: `21258 + r * (216091 ±0)` - // Minimum execution time: 377_152 nanoseconds. - Weight::from_ref_time(317_470_910) - .saturating_add(Weight::from_proof_size(21258)) - // Standard Error: 994_076 - .saturating_add(Weight::from_ref_time(1_409_416_087).saturating_mul(r.into())) + // Measured: `1457 + r * (3604 ±0)` + // Estimated: `21583 + r * (216101 ±0)` + // Minimum execution time: 374_962 nanoseconds. + Weight::from_ref_time(313_416_386) + .saturating_add(Weight::from_proof_size(21583)) + // Standard Error: 710_675 + .saturating_add(Weight::from_ref_time(1_396_551_156).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(T::DbWeight::get().writes((80_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_proof_size(216091).saturating_mul(r.into())) + .saturating_add(Weight::from_proof_size(216101).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1601 w:1601) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:2 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -1220,23 +1222,23 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_call(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1551 + r * (20511 ±0)` - // Estimated: `21848 + r * (498651 ±1)` - // Minimum execution time: 376_257 nanoseconds. - Weight::from_ref_time(377_035_000) - .saturating_add(Weight::from_proof_size(21848)) - // Standard Error: 7_966_778 - .saturating_add(Weight::from_ref_time(28_873_495_129).saturating_mul(r.into())) + // Measured: `1609 + r * (23073 ±0)` + // Estimated: `22098 + r * (511456 ±1)` + // Minimum execution time: 375_916 nanoseconds. + Weight::from_ref_time(376_468_000) + .saturating_add(Weight::from_proof_size(22098)) + // Standard Error: 7_246_855 + .saturating_add(Weight::from_ref_time(28_982_425_139).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().reads((160_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((160_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_proof_size(498651).saturating_mul(r.into())) + .saturating_add(Weight::from_proof_size(511456).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1536 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -1247,22 +1249,22 @@ impl WeightInfo for SubstrateWeight { fn seal_delegate_call(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + r * (71670 ±0)` - // Estimated: `17125 + r * (659927 ±822)` - // Minimum execution time: 376_544 nanoseconds. - Weight::from_ref_time(377_490_000) - .saturating_add(Weight::from_proof_size(17125)) - // Standard Error: 8_608_050 - .saturating_add(Weight::from_ref_time(28_568_714_410).saturating_mul(r.into())) + // Estimated: `17285 + r * (659930 ±563)` + // Minimum execution time: 375_412 nanoseconds. + Weight::from_ref_time(376_493_000) + .saturating_add(Weight::from_proof_size(17285)) + // Standard Error: 8_239_575 + .saturating_add(Weight::from_ref_time(28_716_347_183).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((150_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((75_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_proof_size(659927).saturating_mul(r.into())) + .saturating_add(Weight::from_proof_size(659930).saturating_mul(r.into())) } /// Storage: System Account (r:82 w:81) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:81 w:81) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:2 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -1273,25 +1275,25 @@ impl WeightInfo for SubstrateWeight { /// The range of component `c` is `[0, 1024]`. fn seal_call_per_transfer_clone_kb(t: u32, c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `21611 + t * (15369 ±0)` - // Estimated: `519400 + t * (277320 ±0)` - // Minimum execution time: 10_322_052 nanoseconds. - Weight::from_ref_time(9_248_652_894) - .saturating_add(Weight::from_proof_size(519400)) - // Standard Error: 9_039_638 - .saturating_add(Weight::from_ref_time(1_393_054_441).saturating_mul(t.into())) - // Standard Error: 13_554 - .saturating_add(Weight::from_ref_time(9_819_606).saturating_mul(c.into())) + // Measured: `24269 + t * (16910 ±0)` + // Estimated: `532690 + t * (285025 ±0)` + // Minimum execution time: 10_443_315 nanoseconds. + Weight::from_ref_time(9_342_574_069) + .saturating_add(Weight::from_proof_size(532690)) + // Standard Error: 7_237_279 + .saturating_add(Weight::from_ref_time(1_390_221_936).saturating_mul(t.into())) + // Standard Error: 10_851 + .saturating_add(Weight::from_ref_time(9_842_151).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(167_u64)) .saturating_add(T::DbWeight::get().reads((81_u64).saturating_mul(t.into()))) .saturating_add(T::DbWeight::get().writes(163_u64)) .saturating_add(T::DbWeight::get().writes((81_u64).saturating_mul(t.into()))) - .saturating_add(Weight::from_proof_size(277320).saturating_mul(t.into())) + .saturating_add(Weight::from_proof_size(285025).saturating_mul(t.into())) } - /// Storage: System Account (r:1602 w:1602) + /// Storage: System Account (r:3202 w:3202) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1601 w:1601) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1601 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -1305,23 +1307,23 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_instantiate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1613 + r * (25576 ±0)` - // Estimated: `25698 + r * (1169112 ±1)` - // Minimum execution time: 376_639 nanoseconds. - Weight::from_ref_time(377_892_000) - .saturating_add(Weight::from_proof_size(25698)) - // Standard Error: 21_259_255 - .saturating_add(Weight::from_ref_time(34_131_174_956).saturating_mul(r.into())) + // Measured: `1775 + r * (25568 ±0)` + // Estimated: `26563 + r * (1367114 ±2)` + // Minimum execution time: 376_418 nanoseconds. + Weight::from_ref_time(377_292_000) + .saturating_add(Weight::from_proof_size(26563)) + // Standard Error: 32_312_545 + .saturating_add(Weight::from_ref_time(35_904_826_312).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) - .saturating_add(T::DbWeight::get().reads((400_u64).saturating_mul(r.into()))) + .saturating_add(T::DbWeight::get().reads((480_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(5_u64)) - .saturating_add(T::DbWeight::get().writes((320_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_proof_size(1169112).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().writes((400_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_proof_size(1367114).saturating_mul(r.into())) } - /// Storage: System Account (r:82 w:82) + /// Storage: System Account (r:162 w:162) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:81 w:81) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:2 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -1337,27 +1339,27 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[0, 960]`. fn seal_instantiate_per_transfer_input_salt_kb(t: u32, i: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `5666 + t * (17 ±0)` - // Estimated: `651914 + t * (2762 ±3)` - // Minimum execution time: 130_366_376 nanoseconds. - Weight::from_ref_time(9_844_607_874) - .saturating_add(Weight::from_proof_size(651914)) - // Standard Error: 100_211_149 - .saturating_add(Weight::from_ref_time(390_481_449).saturating_mul(t.into())) - // Standard Error: 163_416 - .saturating_add(Weight::from_ref_time(126_154_200).saturating_mul(i.into())) - // Standard Error: 163_416 - .saturating_add(Weight::from_ref_time(126_430_874).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(249_u64)) + // Measured: `5785 + t * (33 ±0)` + // Estimated: `850985 + t * (2671 ±3)` + // Minimum execution time: 132_157_340 nanoseconds. + Weight::from_ref_time(11_329_968_948) + .saturating_add(Weight::from_proof_size(850985)) + // Standard Error: 99_102_968 + .saturating_add(Weight::from_ref_time(84_719_458).saturating_mul(t.into())) + // Standard Error: 161_609 + .saturating_add(Weight::from_ref_time(126_156_627).saturating_mul(i.into())) + // Standard Error: 161_609 + .saturating_add(Weight::from_ref_time(126_628_313).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(329_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(t.into()))) - .saturating_add(T::DbWeight::get().writes(246_u64)) + .saturating_add(T::DbWeight::get().writes(326_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(t.into()))) - .saturating_add(Weight::from_proof_size(2762).saturating_mul(t.into())) + .saturating_add(Weight::from_proof_size(2671).saturating_mul(t.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -1367,13 +1369,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1]`. fn seal_hash_sha2_256(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `839 + r * (642 ±0)` - // Estimated: `17065 + r * (3210 ±0)` - // Minimum execution time: 373_848 nanoseconds. - Weight::from_ref_time(375_974_597) - .saturating_add(Weight::from_proof_size(17065)) - // Standard Error: 558_923 - .saturating_add(Weight::from_ref_time(42_648_202).saturating_mul(r.into())) + // Measured: `871 + r * (642 ±0)` + // Estimated: `17225 + r * (3210 ±0)` + // Minimum execution time: 373_559 nanoseconds. + Weight::from_ref_time(375_166_904) + .saturating_add(Weight::from_proof_size(17225)) + // Standard Error: 125_024 + .saturating_add(Weight::from_ref_time(42_291_595).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_proof_size(3210).saturating_mul(r.into())) @@ -1381,7 +1383,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -1391,20 +1393,20 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 1024]`. fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1641` - // Estimated: `21000` - // Minimum execution time: 417_281 nanoseconds. - Weight::from_ref_time(418_086_000) - .saturating_add(Weight::from_proof_size(21000)) - // Standard Error: 43_883 - .saturating_add(Weight::from_ref_time(324_497_460).saturating_mul(n.into())) + // Measured: `1673` + // Estimated: `21160` + // Minimum execution time: 416_233 nanoseconds. + Weight::from_ref_time(416_785_000) + .saturating_add(Weight::from_proof_size(21160)) + // Standard Error: 56_223 + .saturating_add(Weight::from_ref_time(324_513_835).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -1414,13 +1416,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1]`. fn seal_hash_keccak_256(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `841 + r * (642 ±0)` - // Estimated: `17075 + r * (3210 ±0)` - // Minimum execution time: 372_362 nanoseconds. - Weight::from_ref_time(374_975_677) - .saturating_add(Weight::from_proof_size(17075)) - // Standard Error: 307_932 - .saturating_add(Weight::from_ref_time(57_607_522).saturating_mul(r.into())) + // Measured: `873 + r * (642 ±0)` + // Estimated: `17235 + r * (3210 ±0)` + // Minimum execution time: 371_735 nanoseconds. + Weight::from_ref_time(375_979_430) + .saturating_add(Weight::from_proof_size(17235)) + // Standard Error: 968_037 + .saturating_add(Weight::from_ref_time(57_780_769).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_proof_size(3210).saturating_mul(r.into())) @@ -1428,7 +1430,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -1438,20 +1440,20 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 1024]`. fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1643` - // Estimated: `21040` - // Minimum execution time: 431_034 nanoseconds. - Weight::from_ref_time(431_571_000) - .saturating_add(Weight::from_proof_size(21040)) - // Standard Error: 80_071 - .saturating_add(Weight::from_ref_time(261_645_325).saturating_mul(n.into())) + // Measured: `1675` + // Estimated: `21205` + // Minimum execution time: 428_196 nanoseconds. + Weight::from_ref_time(429_438_000) + .saturating_add(Weight::from_proof_size(21205)) + // Standard Error: 57_860 + .saturating_add(Weight::from_ref_time(260_917_896).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -1461,13 +1463,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1]`. fn seal_hash_blake2_256(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `841 + r * (642 ±0)` - // Estimated: `17075 + r * (3210 ±0)` - // Minimum execution time: 372_069 nanoseconds. - Weight::from_ref_time(374_200_608) - .saturating_add(Weight::from_proof_size(17075)) - // Standard Error: 171_799 - .saturating_add(Weight::from_ref_time(32_843_391).saturating_mul(r.into())) + // Measured: `873 + r * (642 ±0)` + // Estimated: `17235 + r * (3210 ±0)` + // Minimum execution time: 371_412 nanoseconds. + Weight::from_ref_time(373_635_818) + .saturating_add(Weight::from_proof_size(17235)) + // Standard Error: 222_973 + .saturating_add(Weight::from_ref_time(33_347_181).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_proof_size(3210).saturating_mul(r.into())) @@ -1475,7 +1477,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -1485,20 +1487,20 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1643` - // Estimated: `21010` - // Minimum execution time: 406_143 nanoseconds. - Weight::from_ref_time(406_744_000) - .saturating_add(Weight::from_proof_size(21010)) - // Standard Error: 48_038 - .saturating_add(Weight::from_ref_time(103_286_295).saturating_mul(n.into())) + // Measured: `1675` + // Estimated: `21180` + // Minimum execution time: 405_858 nanoseconds. + Weight::from_ref_time(406_498_000) + .saturating_add(Weight::from_proof_size(21180)) + // Standard Error: 48_388 + .saturating_add(Weight::from_ref_time(103_283_157).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -1508,13 +1510,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1]`. fn seal_hash_blake2_128(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `841 + r * (679 ±0)` - // Estimated: `17075 + r * (3395 ±0)` - // Minimum execution time: 372_201 nanoseconds. - Weight::from_ref_time(374_049_708) - .saturating_add(Weight::from_proof_size(17075)) - // Standard Error: 387_179 - .saturating_add(Weight::from_ref_time(38_857_191).saturating_mul(r.into())) + // Measured: `873 + r * (679 ±0)` + // Estimated: `17235 + r * (3395 ±0)` + // Minimum execution time: 371_746 nanoseconds. + Weight::from_ref_time(373_538_171) + .saturating_add(Weight::from_proof_size(17235)) + // Standard Error: 387_332 + .saturating_add(Weight::from_ref_time(35_933_528).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_proof_size(3395).saturating_mul(r.into())) @@ -1522,7 +1524,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -1532,20 +1534,20 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1643` - // Estimated: `21050` - // Minimum execution time: 405_819 nanoseconds. - Weight::from_ref_time(406_364_000) - .saturating_add(Weight::from_proof_size(21050)) - // Standard Error: 46_248 - .saturating_add(Weight::from_ref_time(103_189_157).saturating_mul(n.into())) + // Measured: `1675` + // Estimated: `21225` + // Minimum execution time: 405_752 nanoseconds. + Weight::from_ref_time(406_417_000) + .saturating_add(Weight::from_proof_size(21225)) + // Standard Error: 47_051 + .saturating_add(Weight::from_ref_time(103_325_027).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -1555,13 +1557,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1]`. fn seal_ecdsa_recover(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `885 + r * (6083 ±0)` - // Estimated: `17295 + r * (30415 ±0)` - // Minimum execution time: 374_836 nanoseconds. - Weight::from_ref_time(379_385_500) - .saturating_add(Weight::from_proof_size(17295)) - // Standard Error: 1_694_427 - .saturating_add(Weight::from_ref_time(3_021_801_000).saturating_mul(r.into())) + // Measured: `917 + r * (6083 ±0)` + // Estimated: `17455 + r * (30415 ±0)` + // Minimum execution time: 373_882 nanoseconds. + Weight::from_ref_time(376_553_787) + .saturating_add(Weight::from_proof_size(17455)) + // Standard Error: 912_833 + .saturating_add(Weight::from_ref_time(3_021_100_412).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_proof_size(30415).saturating_mul(r.into())) @@ -1569,7 +1571,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -1579,13 +1581,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1]`. fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `854 + r * (3362 ±0)` - // Estimated: `17140 + r * (16810 ±0)` - // Minimum execution time: 374_223 nanoseconds. - Weight::from_ref_time(376_120_230) - .saturating_add(Weight::from_proof_size(17140)) - // Standard Error: 619_576 - .saturating_add(Weight::from_ref_time(754_257_969).saturating_mul(r.into())) + // Measured: `886 + r * (3362 ±0)` + // Estimated: `17300 + r * (16810 ±0)` + // Minimum execution time: 373_673 nanoseconds. + Weight::from_ref_time(375_712_961) + .saturating_add(Weight::from_proof_size(17300)) + // Standard Error: 596_297 + .saturating_add(Weight::from_ref_time(738_257_638).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_proof_size(16810).saturating_mul(r.into())) @@ -1593,7 +1595,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1536 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -1606,12 +1608,12 @@ impl WeightInfo for SubstrateWeight { fn seal_set_code_hash(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + r * (79300 ±0)` - // Estimated: `64652 + r * (942952 ±829)` - // Minimum execution time: 374_442 nanoseconds. - Weight::from_ref_time(375_591_000) - .saturating_add(Weight::from_proof_size(64652)) - // Standard Error: 3_764_193 - .saturating_add(Weight::from_ref_time(1_552_885_601).saturating_mul(r.into())) + // Estimated: `64844 + r * (942952 ±833)` + // Minimum execution time: 374_097 nanoseconds. + Weight::from_ref_time(374_985_000) + .saturating_add(Weight::from_proof_size(64844)) + // Standard Error: 3_772_336 + .saturating_add(Weight::from_ref_time(1_546_402_854).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((225_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1621,7 +1623,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -1631,13 +1633,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_reentrance_count(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `837 + r * (240 ±0)` - // Estimated: `17055 + r * (1200 ±0)` - // Minimum execution time: 374_922 nanoseconds. - Weight::from_ref_time(376_234_094) - .saturating_add(Weight::from_proof_size(17055)) - // Standard Error: 45_995 - .saturating_add(Weight::from_ref_time(11_606_505).saturating_mul(r.into())) + // Measured: `869 + r * (240 ±0)` + // Estimated: `17215 + r * (1200 ±0)` + // Minimum execution time: 374_249 nanoseconds. + Weight::from_ref_time(377_990_998) + .saturating_add(Weight::from_proof_size(17215)) + // Standard Error: 38_133 + .saturating_add(Weight::from_ref_time(11_483_273).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_proof_size(1200).saturating_mul(r.into())) @@ -1645,7 +1647,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -1655,21 +1657,21 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_account_reentrance_count(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2056 + r * (3153 ±0)` - // Estimated: `21730 + r * (15870 ±2)` - // Minimum execution time: 376_762 nanoseconds. - Weight::from_ref_time(396_934_359) - .saturating_add(Weight::from_proof_size(21730)) - // Standard Error: 68_263 - .saturating_add(Weight::from_ref_time(18_367_270).saturating_mul(r.into())) + // Measured: `2102 + r * (3154 ±0)` + // Estimated: `21980 + r * (15875 ±2)` + // Minimum execution time: 375_552 nanoseconds. + Weight::from_ref_time(400_624_032) + .saturating_add(Weight::from_proof_size(21980)) + // Standard Error: 82_523 + .saturating_add(Weight::from_ref_time(18_057_327).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(15870).saturating_mul(r.into())) + .saturating_add(Weight::from_proof_size(15875).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -1681,13 +1683,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_instantiation_nonce(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `840 + r * (240 ±0)` - // Estimated: `18405 + r * (1440 ±0)` - // Minimum execution time: 374_257 nanoseconds. - Weight::from_ref_time(380_453_380) - .saturating_add(Weight::from_proof_size(18405)) - // Standard Error: 42_718 - .saturating_add(Weight::from_ref_time(9_355_253).saturating_mul(r.into())) + // Measured: `872 + r * (240 ±0)` + // Estimated: `18598 + r * (1440 ±0)` + // Minimum execution time: 373_899 nanoseconds. + Weight::from_ref_time(379_733_943) + .saturating_add(Weight::from_proof_size(18598)) + // Standard Error: 32_022 + .saturating_add(Weight::from_ref_time(9_381_180).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(Weight::from_proof_size(1440).saturating_mul(r.into())) @@ -1697,572 +1699,572 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 788 nanoseconds. - Weight::from_ref_time(1_209_829) + // Minimum execution time: 834 nanoseconds. + Weight::from_ref_time(1_009_646) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 3_436 - .saturating_add(Weight::from_ref_time(409_858).saturating_mul(r.into())) + // Standard Error: 388 + .saturating_add(Weight::from_ref_time(411_979).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64load(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 955 nanoseconds. - Weight::from_ref_time(1_526_327) + // Minimum execution time: 882 nanoseconds. + Weight::from_ref_time(1_416_377) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 2_399 - .saturating_add(Weight::from_ref_time(1_084_504).saturating_mul(r.into())) + // Standard Error: 1_133 + .saturating_add(Weight::from_ref_time(1_075_838).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64store(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 967 nanoseconds. - Weight::from_ref_time(1_576_183) + // Minimum execution time: 878 nanoseconds. + Weight::from_ref_time(1_343_056) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 5_719 - .saturating_add(Weight::from_ref_time(1_006_742).saturating_mul(r.into())) + // Standard Error: 426 + .saturating_add(Weight::from_ref_time(1_001_214).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_select(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 849 nanoseconds. - Weight::from_ref_time(1_106_539) + // Minimum execution time: 796 nanoseconds. + Weight::from_ref_time(1_079_086) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 445 - .saturating_add(Weight::from_ref_time(1_149_752).saturating_mul(r.into())) + // Standard Error: 409 + .saturating_add(Weight::from_ref_time(1_149_188).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_if(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 829 nanoseconds. - Weight::from_ref_time(1_171_360) + // Minimum execution time: 800 nanoseconds. + Weight::from_ref_time(1_044_184) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 552 - .saturating_add(Weight::from_ref_time(1_309_914).saturating_mul(r.into())) + // Standard Error: 707 + .saturating_add(Weight::from_ref_time(1_315_686).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_br(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 835 nanoseconds. - Weight::from_ref_time(1_125_578) + // Minimum execution time: 807 nanoseconds. + Weight::from_ref_time(1_049_633) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 374 - .saturating_add(Weight::from_ref_time(641_683).saturating_mul(r.into())) + // Standard Error: 361 + .saturating_add(Weight::from_ref_time(640_530).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_br_if(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 816 nanoseconds. - Weight::from_ref_time(1_032_093) + // Minimum execution time: 774 nanoseconds. + Weight::from_ref_time(1_124_053) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 811 - .saturating_add(Weight::from_ref_time(956_228).saturating_mul(r.into())) + // Standard Error: 784 + .saturating_add(Weight::from_ref_time(949_398).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_br_table(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 801 nanoseconds. - Weight::from_ref_time(816_764) + // Minimum execution time: 810 nanoseconds. + Weight::from_ref_time(676_581) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 2_669 - .saturating_add(Weight::from_ref_time(1_166_556).saturating_mul(r.into())) + // Standard Error: 2_356 + .saturating_add(Weight::from_ref_time(1_163_465).saturating_mul(r.into())) } /// The range of component `e` is `[1, 256]`. fn instr_br_table_per_entry(e: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_639 nanoseconds. - Weight::from_ref_time(2_905_554) + // Minimum execution time: 2_580 nanoseconds. + Weight::from_ref_time(2_835_656) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 62 - .saturating_add(Weight::from_ref_time(4_438).saturating_mul(e.into())) + // Standard Error: 71 + .saturating_add(Weight::from_ref_time(4_686).saturating_mul(e.into())) } /// The range of component `r` is `[0, 50]`. fn instr_call(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 831 nanoseconds. - Weight::from_ref_time(1_729_584) + // Minimum execution time: 826 nanoseconds. + Weight::from_ref_time(1_625_698) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 33_753 - .saturating_add(Weight::from_ref_time(2_380_315).saturating_mul(r.into())) + // Standard Error: 1_740 + .saturating_add(Weight::from_ref_time(2_332_187).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_call_indirect(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 964 nanoseconds. - Weight::from_ref_time(2_445_291) + // Minimum execution time: 901 nanoseconds. + Weight::from_ref_time(2_338_620) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 3_285 - .saturating_add(Weight::from_ref_time(2_938_681).saturating_mul(r.into())) + // Standard Error: 1_642 + .saturating_add(Weight::from_ref_time(2_924_090).saturating_mul(r.into())) } /// The range of component `p` is `[0, 128]`. fn instr_call_indirect_per_param(p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_809 nanoseconds. - Weight::from_ref_time(6_763_286) + // Minimum execution time: 4_670 nanoseconds. + Weight::from_ref_time(5_556_246) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 3_994 - .saturating_add(Weight::from_ref_time(217_632).saturating_mul(p.into())) + // Standard Error: 1_491 + .saturating_add(Weight::from_ref_time(228_965).saturating_mul(p.into())) } /// The range of component `l` is `[0, 1024]`. fn instr_call_per_local(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_138 nanoseconds. - Weight::from_ref_time(3_894_816) + // Minimum execution time: 3_099 nanoseconds. + Weight::from_ref_time(3_896_177) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 131 - .saturating_add(Weight::from_ref_time(91_699).saturating_mul(l.into())) + // Standard Error: 99 + .saturating_add(Weight::from_ref_time(91_304).saturating_mul(l.into())) } /// The range of component `r` is `[0, 50]`. fn instr_local_get(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_959 nanoseconds. - Weight::from_ref_time(3_271_550) + // Minimum execution time: 3_042 nanoseconds. + Weight::from_ref_time(3_334_621) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 223 - .saturating_add(Weight::from_ref_time(460_056).saturating_mul(r.into())) + // Standard Error: 793 + .saturating_add(Weight::from_ref_time(459_346).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_local_set(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_970 nanoseconds. - Weight::from_ref_time(3_216_157) + // Minimum execution time: 2_968 nanoseconds. + Weight::from_ref_time(3_235_286) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 413 - .saturating_add(Weight::from_ref_time(485_842).saturating_mul(r.into())) + // Standard Error: 427 + .saturating_add(Weight::from_ref_time(485_454).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_local_tee(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_980 nanoseconds. - Weight::from_ref_time(3_323_878) + // Minimum execution time: 3_012 nanoseconds. + Weight::from_ref_time(3_303_555) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 2_652 - .saturating_add(Weight::from_ref_time(660_257).saturating_mul(r.into())) + // Standard Error: 371 + .saturating_add(Weight::from_ref_time(657_811).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_global_get(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 917 nanoseconds. - Weight::from_ref_time(1_445_816) + // Minimum execution time: 865 nanoseconds. + Weight::from_ref_time(1_249_987) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 5_642 - .saturating_add(Weight::from_ref_time(894_521).saturating_mul(r.into())) + // Standard Error: 417 + .saturating_add(Weight::from_ref_time(896_704).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_global_set(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 965 nanoseconds. - Weight::from_ref_time(1_373_722) + // Minimum execution time: 866 nanoseconds. + Weight::from_ref_time(1_216_218) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 1_157 - .saturating_add(Weight::from_ref_time(917_643).saturating_mul(r.into())) + // Standard Error: 503 + .saturating_add(Weight::from_ref_time(919_719).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_memory_current(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 982 nanoseconds. - Weight::from_ref_time(1_240_280) + // Minimum execution time: 921 nanoseconds. + Weight::from_ref_time(1_228_408) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 308 - .saturating_add(Weight::from_ref_time(817_972).saturating_mul(r.into())) + // Standard Error: 309 + .saturating_add(Weight::from_ref_time(813_007).saturating_mul(r.into())) } /// The range of component `r` is `[0, 1]`. fn instr_memory_grow(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 858 nanoseconds. - Weight::from_ref_time(962_183) + // Minimum execution time: 820 nanoseconds. + Weight::from_ref_time(914_830) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 6_701 - .saturating_add(Weight::from_ref_time(239_704_216).saturating_mul(r.into())) + // Standard Error: 6_018 + .saturating_add(Weight::from_ref_time(237_062_769).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64clz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 807 nanoseconds. - Weight::from_ref_time(1_132_872) + // Minimum execution time: 812 nanoseconds. + Weight::from_ref_time(1_554_406) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 303 - .saturating_add(Weight::from_ref_time(633_832).saturating_mul(r.into())) + // Standard Error: 9_979 + .saturating_add(Weight::from_ref_time(625_434).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ctz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 823 nanoseconds. - Weight::from_ref_time(1_267_518) + // Minimum execution time: 798 nanoseconds. + Weight::from_ref_time(1_095_113) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 483 - .saturating_add(Weight::from_ref_time(632_620).saturating_mul(r.into())) + // Standard Error: 243 + .saturating_add(Weight::from_ref_time(634_204).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64popcnt(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 857 nanoseconds. - Weight::from_ref_time(1_105_214) + // Minimum execution time: 792 nanoseconds. + Weight::from_ref_time(1_109_845) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 285 - .saturating_add(Weight::from_ref_time(635_039).saturating_mul(r.into())) + // Standard Error: 14_944 + .saturating_add(Weight::from_ref_time(658_834).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64eqz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 821 nanoseconds. - Weight::from_ref_time(750_223) + // Minimum execution time: 815 nanoseconds. + Weight::from_ref_time(1_068_916) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 15_923 - .saturating_add(Weight::from_ref_time(686_322).saturating_mul(r.into())) + // Standard Error: 327 + .saturating_add(Weight::from_ref_time(652_897).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendsi32(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 797 nanoseconds. - Weight::from_ref_time(1_145_072) + // Minimum execution time: 798 nanoseconds. + Weight::from_ref_time(1_069_745) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 311 - .saturating_add(Weight::from_ref_time(618_147).saturating_mul(r.into())) + // Standard Error: 306 + .saturating_add(Weight::from_ref_time(618_481).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendui32(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 803 nanoseconds. - Weight::from_ref_time(1_139_498) + // Minimum execution time: 799 nanoseconds. + Weight::from_ref_time(1_398_001) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 284 - .saturating_add(Weight::from_ref_time(617_393).saturating_mul(r.into())) + // Standard Error: 6_234 + .saturating_add(Weight::from_ref_time(611_399).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i32wrapi64(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 814 nanoseconds. - Weight::from_ref_time(1_099_405) + // Minimum execution time: 811 nanoseconds. + Weight::from_ref_time(1_098_083) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 663 - .saturating_add(Weight::from_ref_time(618_565).saturating_mul(r.into())) + // Standard Error: 297 + .saturating_add(Weight::from_ref_time(617_692).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64eq(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 819 nanoseconds. - Weight::from_ref_time(1_199_220) + // Minimum execution time: 815 nanoseconds. + Weight::from_ref_time(1_046_922) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 485 - .saturating_add(Weight::from_ref_time(906_878).saturating_mul(r.into())) + // Standard Error: 335 + .saturating_add(Weight::from_ref_time(909_196).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ne(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 822 nanoseconds. - Weight::from_ref_time(274_212) + // Minimum execution time: 805 nanoseconds. + Weight::from_ref_time(1_093_667) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 29_294 - .saturating_add(Weight::from_ref_time(971_608).saturating_mul(r.into())) + // Standard Error: 233 + .saturating_add(Weight::from_ref_time(907_378).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64lts(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 796 nanoseconds. - Weight::from_ref_time(1_396_586) + // Minimum execution time: 805 nanoseconds. + Weight::from_ref_time(1_290_591) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 7_205 - .saturating_add(Weight::from_ref_time(903_202).saturating_mul(r.into())) + // Standard Error: 3_201 + .saturating_add(Weight::from_ref_time(902_006).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ltu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 833 nanoseconds. - Weight::from_ref_time(1_115_115) + // Minimum execution time: 783 nanoseconds. + Weight::from_ref_time(1_159_977) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 310 - .saturating_add(Weight::from_ref_time(908_195).saturating_mul(r.into())) + // Standard Error: 2_310 + .saturating_add(Weight::from_ref_time(906_489).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64gts(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 854 nanoseconds. - Weight::from_ref_time(1_170_419) + // Minimum execution time: 790 nanoseconds. + Weight::from_ref_time(1_109_719) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 298 - .saturating_add(Weight::from_ref_time(907_171).saturating_mul(r.into())) + // Standard Error: 261 + .saturating_add(Weight::from_ref_time(906_614).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64gtu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 822 nanoseconds. - Weight::from_ref_time(1_186_349) + // Minimum execution time: 776 nanoseconds. + Weight::from_ref_time(1_076_567) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 302 - .saturating_add(Weight::from_ref_time(917_857).saturating_mul(r.into())) + // Standard Error: 348 + .saturating_add(Weight::from_ref_time(919_374).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64les(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 807 nanoseconds. - Weight::from_ref_time(1_127_093) + // Minimum execution time: 780 nanoseconds. + Weight::from_ref_time(1_069_663) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 1_891 - .saturating_add(Weight::from_ref_time(910_738).saturating_mul(r.into())) + // Standard Error: 265 + .saturating_add(Weight::from_ref_time(908_037).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64leu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 819 nanoseconds. - Weight::from_ref_time(1_143_022) + // Minimum execution time: 832 nanoseconds. + Weight::from_ref_time(930_920) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 309 - .saturating_add(Weight::from_ref_time(919_047).saturating_mul(r.into())) + // Standard Error: 2_170 + .saturating_add(Weight::from_ref_time(929_811).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ges(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 788 nanoseconds. - Weight::from_ref_time(1_116_914) + // Minimum execution time: 787 nanoseconds. + Weight::from_ref_time(1_087_325) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 643 - .saturating_add(Weight::from_ref_time(911_159).saturating_mul(r.into())) + // Standard Error: 315 + .saturating_add(Weight::from_ref_time(908_321).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64geu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 791 nanoseconds. - Weight::from_ref_time(1_123_747) + // Minimum execution time: 798 nanoseconds. + Weight::from_ref_time(1_029_132) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 583 - .saturating_add(Weight::from_ref_time(910_242).saturating_mul(r.into())) + // Standard Error: 2_095 + .saturating_add(Weight::from_ref_time(913_553).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64add(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 787 nanoseconds. - Weight::from_ref_time(1_109_471) + // Minimum execution time: 791 nanoseconds. + Weight::from_ref_time(1_086_314) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 305 - .saturating_add(Weight::from_ref_time(897_608).saturating_mul(r.into())) + // Standard Error: 197 + .saturating_add(Weight::from_ref_time(896_392).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64sub(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 821 nanoseconds. - Weight::from_ref_time(1_098_631) + // Minimum execution time: 793 nanoseconds. + Weight::from_ref_time(1_078_172) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 523 - .saturating_add(Weight::from_ref_time(887_814).saturating_mul(r.into())) + // Standard Error: 404 + .saturating_add(Weight::from_ref_time(886_329).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64mul(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 794 nanoseconds. - Weight::from_ref_time(1_166_332) + // Minimum execution time: 799 nanoseconds. + Weight::from_ref_time(1_095_010) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 384 - .saturating_add(Weight::from_ref_time(885_584).saturating_mul(r.into())) + // Standard Error: 431 + .saturating_add(Weight::from_ref_time(886_513).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64divs(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 822 nanoseconds. - Weight::from_ref_time(1_155_826) + // Minimum execution time: 810 nanoseconds. + Weight::from_ref_time(1_114_325) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 521 - .saturating_add(Weight::from_ref_time(1_520_958).saturating_mul(r.into())) + // Standard Error: 452 + .saturating_add(Weight::from_ref_time(1_521_849).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64divu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 881 nanoseconds. - Weight::from_ref_time(1_158_125) + // Minimum execution time: 784 nanoseconds. + Weight::from_ref_time(1_123_153) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 624 - .saturating_add(Weight::from_ref_time(1_458_378).saturating_mul(r.into())) + // Standard Error: 475 + .saturating_add(Weight::from_ref_time(1_457_746).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64rems(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 827 nanoseconds. - Weight::from_ref_time(1_209_535) + // Minimum execution time: 809 nanoseconds. + Weight::from_ref_time(1_145_906) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 399 - .saturating_add(Weight::from_ref_time(1_547_640).saturating_mul(r.into())) + // Standard Error: 718 + .saturating_add(Weight::from_ref_time(1_549_964).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64remu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 801 nanoseconds. - Weight::from_ref_time(1_313_872) + // Minimum execution time: 803 nanoseconds. + Weight::from_ref_time(1_110_328) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 2_175 - .saturating_add(Weight::from_ref_time(1_449_416).saturating_mul(r.into())) + // Standard Error: 627 + .saturating_add(Weight::from_ref_time(1_453_013).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64and(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 827 nanoseconds. - Weight::from_ref_time(1_093_874) + // Minimum execution time: 786 nanoseconds. + Weight::from_ref_time(1_108_792) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 708 - .saturating_add(Weight::from_ref_time(901_450).saturating_mul(r.into())) + // Standard Error: 286 + .saturating_add(Weight::from_ref_time(897_035).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64or(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 824 nanoseconds. - Weight::from_ref_time(1_164_076) + // Minimum execution time: 787 nanoseconds. + Weight::from_ref_time(830_000) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 623 - .saturating_add(Weight::from_ref_time(897_579).saturating_mul(r.into())) + // Standard Error: 15_995 + .saturating_add(Weight::from_ref_time(963_344).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64xor(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 789 nanoseconds. - Weight::from_ref_time(1_113_915) + // Minimum execution time: 773 nanoseconds. + Weight::from_ref_time(1_082_459) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 390 - .saturating_add(Weight::from_ref_time(897_354).saturating_mul(r.into())) + // Standard Error: 330 + .saturating_add(Weight::from_ref_time(897_077).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64shl(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 811 nanoseconds. - Weight::from_ref_time(1_117_366) + // Minimum execution time: 810 nanoseconds. + Weight::from_ref_time(1_325_815) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 437 - .saturating_add(Weight::from_ref_time(903_759).saturating_mul(r.into())) + // Standard Error: 3_352 + .saturating_add(Weight::from_ref_time(899_555).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64shrs(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 846 nanoseconds. - Weight::from_ref_time(1_103_954) + // Minimum execution time: 808 nanoseconds. + Weight::from_ref_time(1_085_903) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 414 - .saturating_add(Weight::from_ref_time(903_429).saturating_mul(r.into())) + // Standard Error: 430 + .saturating_add(Weight::from_ref_time(903_249).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64shru(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 803 nanoseconds. - Weight::from_ref_time(1_124_328) + // Minimum execution time: 792 nanoseconds. + Weight::from_ref_time(1_091_261) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 410 - .saturating_add(Weight::from_ref_time(903_216).saturating_mul(r.into())) + // Standard Error: 312 + .saturating_add(Weight::from_ref_time(902_245).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotl(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 810 nanoseconds. - Weight::from_ref_time(1_131_433) + // Minimum execution time: 807 nanoseconds. + Weight::from_ref_time(1_121_052) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 402 - .saturating_add(Weight::from_ref_time(903_381).saturating_mul(r.into())) + // Standard Error: 506 + .saturating_add(Weight::from_ref_time(902_772).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotr(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 807 nanoseconds. - Weight::from_ref_time(1_144_933) + // Minimum execution time: 823 nanoseconds. + Weight::from_ref_time(1_317_597) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 373 - .saturating_add(Weight::from_ref_time(902_918).saturating_mul(r.into())) + // Standard Error: 6_219 + .saturating_add(Weight::from_ref_time(896_692).saturating_mul(r.into())) } } @@ -2274,8 +2276,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `109` // Estimated: `604` - // Minimum execution time: 2_507 nanoseconds. - Weight::from_ref_time(2_650_000) + // Minimum execution time: 2_591 nanoseconds. + Weight::from_ref_time(2_817_000) .saturating_add(Weight::from_proof_size(604)) .saturating_add(RocksDbWeight::get().reads(1_u64)) } @@ -2286,11 +2288,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `481 + k * (69 ±0)` // Estimated: `471 + k * (70 ±0)` - // Minimum execution time: 9_953 nanoseconds. - Weight::from_ref_time(6_467_352) + // Minimum execution time: 10_190 nanoseconds. + Weight::from_ref_time(6_642_117) .saturating_add(Weight::from_proof_size(471)) - // Standard Error: 1_074 - .saturating_add(Weight::from_ref_time(943_946).saturating_mul(k.into())) + // Standard Error: 992 + .saturating_add(Weight::from_ref_time(919_828).saturating_mul(k.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(k.into()))) @@ -2303,11 +2305,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `281 + q * (33 ±0)` // Estimated: `763 + q * (33 ±0)` - // Minimum execution time: 2_545 nanoseconds. - Weight::from_ref_time(10_080_106) + // Minimum execution time: 2_598 nanoseconds. + Weight::from_ref_time(10_288_252) .saturating_add(Weight::from_proof_size(763)) - // Standard Error: 2_929 - .saturating_add(Weight::from_ref_time(1_078_265).saturating_mul(q.into())) + // Standard Error: 2_886 + .saturating_add(Weight::from_ref_time(1_092_420).saturating_mul(q.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_proof_size(33).saturating_mul(q.into())) @@ -2321,17 +2323,17 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `270 + c * (1 ±0)` // Estimated: `3025 + c * (2 ±0)` - // Minimum execution time: 34_613 nanoseconds. - Weight::from_ref_time(27_355_774) + // Minimum execution time: 34_338 nanoseconds. + Weight::from_ref_time(32_159_677) .saturating_add(Weight::from_proof_size(3025)) - // Standard Error: 81 - .saturating_add(Weight::from_ref_time(51_954).saturating_mul(c.into())) + // Standard Error: 53 + .saturating_add(Weight::from_ref_time(51_034).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_proof_size(2).saturating_mul(c.into())) } /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -2343,13 +2345,13 @@ impl WeightInfo for () { /// The range of component `c` is `[0, 125952]`. fn call_with_code_per_byte(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `771` - // Estimated: `16780 + c * (5 ±0)` - // Minimum execution time: 386_104 nanoseconds. - Weight::from_ref_time(396_718_823) - .saturating_add(Weight::from_proof_size(16780)) + // Measured: `803` + // Estimated: `16930 + c * (5 ±0)` + // Minimum execution time: 385_587 nanoseconds. + Weight::from_ref_time(395_545_811) + .saturating_add(Weight::from_proof_size(16930)) // Standard Error: 27 - .saturating_add(Weight::from_ref_time(31_370).saturating_mul(c.into())) + .saturating_add(Weight::from_ref_time(31_342).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(Weight::from_proof_size(5).saturating_mul(c.into())) @@ -2359,10 +2361,10 @@ impl WeightInfo for () { /// Storage: Contracts Nonce (r:1 w:1) /// Proof: Contracts Nonce (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) - /// Storage: System Account (r:1 w:1) + /// Storage: System Account (r:2 w:2) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: System EventTopics (r:3 w:3) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) @@ -2375,29 +2377,29 @@ impl WeightInfo for () { /// The range of component `s` is `[0, 1048576]`. fn instantiate_with_code(c: u32, i: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `257` - // Estimated: `17752` - // Minimum execution time: 3_786_500 nanoseconds. - Weight::from_ref_time(672_511_565) - .saturating_add(Weight::from_proof_size(17752)) - // Standard Error: 281 - .saturating_add(Weight::from_ref_time(94_538).saturating_mul(c.into())) + // Measured: `270` + // Estimated: `20267` + // Minimum execution time: 3_799_742 nanoseconds. + Weight::from_ref_time(670_115_588) + .saturating_add(Weight::from_proof_size(20267)) + // Standard Error: 287 + .saturating_add(Weight::from_ref_time(93_885).saturating_mul(c.into())) // Standard Error: 16 - .saturating_add(Weight::from_ref_time(1_364).saturating_mul(i.into())) + .saturating_add(Weight::from_ref_time(1_367).saturating_mul(i.into())) // Standard Error: 16 - .saturating_add(Weight::from_ref_time(1_768).saturating_mul(s.into())) - .saturating_add(RocksDbWeight::get().reads(8_u64)) - .saturating_add(RocksDbWeight::get().writes(9_u64)) + .saturating_add(Weight::from_ref_time(1_781).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(9_u64)) + .saturating_add(RocksDbWeight::get().writes(10_u64)) } /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Contracts Nonce (r:1 w:1) /// Proof: Contracts Nonce (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) - /// Storage: System Account (r:1 w:1) + /// Storage: System Account (r:2 w:2) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts OwnerInfoOf (r:1 w:1) /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Measured) @@ -2407,20 +2409,20 @@ impl WeightInfo for () { /// The range of component `s` is `[0, 1048576]`. fn instantiate(i: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `533` - // Estimated: `19543` - // Minimum execution time: 1_927_365 nanoseconds. - Weight::from_ref_time(189_843_928) - .saturating_add(Weight::from_proof_size(19543)) + // Measured: `546` + // Estimated: `22039` + // Minimum execution time: 1_949_008 nanoseconds. + Weight::from_ref_time(214_033_418) + .saturating_add(Weight::from_proof_size(22039)) // Standard Error: 8 - .saturating_add(Weight::from_ref_time(1_677).saturating_mul(i.into())) + .saturating_add(Weight::from_ref_time(1_666).saturating_mul(i.into())) // Standard Error: 8 - .saturating_add(Weight::from_ref_time(1_803).saturating_mul(s.into())) - .saturating_add(RocksDbWeight::get().reads(8_u64)) - .saturating_add(RocksDbWeight::get().writes(6_u64)) + .saturating_add(Weight::from_ref_time(1_801).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(9_u64)) + .saturating_add(RocksDbWeight::get().writes(7_u64)) } /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -2431,11 +2433,11 @@ impl WeightInfo for () { /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) fn call() -> Weight { // Proof Size summary in bytes: - // Measured: `823` - // Estimated: `16985` - // Minimum execution time: 146_354 nanoseconds. - Weight::from_ref_time(147_693_000) - .saturating_add(Weight::from_proof_size(16985)) + // Measured: `855` + // Estimated: `17145` + // Minimum execution time: 146_654 nanoseconds. + Weight::from_ref_time(147_528_000) + .saturating_add(Weight::from_proof_size(17145)) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -2452,11 +2454,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `109` // Estimated: `5386` - // Minimum execution time: 388_107 nanoseconds. - Weight::from_ref_time(383_172_702) + // Minimum execution time: 387_889 nanoseconds. + Weight::from_ref_time(391_379_335) .saturating_add(Weight::from_proof_size(5386)) - // Standard Error: 73 - .saturating_add(Weight::from_ref_time(95_037).saturating_mul(c.into())) + // Standard Error: 89 + .saturating_add(Weight::from_ref_time(94_810).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -2472,32 +2474,32 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `287` // Estimated: `6098` - // Minimum execution time: 26_278 nanoseconds. - Weight::from_ref_time(26_682_000) + // Minimum execution time: 26_014 nanoseconds. + Weight::from_ref_time(26_510_000) .saturating_add(Weight::from_proof_size(6098)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts OwnerInfoOf (r:2 w:2) /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Measured) /// Storage: System EventTopics (r:3 w:3) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) fn set_code() -> Weight { // Proof Size summary in bytes: - // Measured: `634` - // Estimated: `16752` - // Minimum execution time: 30_223 nanoseconds. - Weight::from_ref_time(30_737_000) - .saturating_add(Weight::from_proof_size(16752)) + // Measured: `666` + // Estimated: `16848` + // Minimum execution time: 30_177 nanoseconds. + Weight::from_ref_time(30_639_000) + .saturating_add(Weight::from_proof_size(16848)) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -2507,13 +2509,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_caller(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `845 + r * (480 ±0)` - // Estimated: `17120 + r * (2400 ±0)` - // Minimum execution time: 374_780 nanoseconds. - Weight::from_ref_time(379_468_453) - .saturating_add(Weight::from_proof_size(17120)) - // Standard Error: 45_809 - .saturating_add(Weight::from_ref_time(17_553_577).saturating_mul(r.into())) + // Measured: `877 + r * (480 ±0)` + // Estimated: `17295 + r * (2400 ±0)` + // Minimum execution time: 373_786 nanoseconds. + Weight::from_ref_time(377_332_691) + .saturating_add(Weight::from_proof_size(17295)) + // Standard Error: 51_211 + .saturating_add(Weight::from_ref_time(17_715_615).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_proof_size(2400).saturating_mul(r.into())) @@ -2521,7 +2523,7 @@ impl WeightInfo for () { /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1601 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -2531,22 +2533,22 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_is_contract(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `882 + r * (19218 ±0)` - // Estimated: `17110 + r * (294100 ±0)` - // Minimum execution time: 374_399 nanoseconds. - Weight::from_ref_time(228_569_211) - .saturating_add(Weight::from_proof_size(17110)) - // Standard Error: 492_562 - .saturating_add(Weight::from_ref_time(251_682_897).saturating_mul(r.into())) + // Measured: `917 + r * (21778 ±0)` + // Estimated: `17295 + r * (306895 ±0)` + // Minimum execution time: 374_009 nanoseconds. + Weight::from_ref_time(238_991_986) + .saturating_add(Weight::from_proof_size(17295)) + // Standard Error: 464_711 + .saturating_add(Weight::from_ref_time(249_099_538).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(294100).saturating_mul(r.into())) + .saturating_add(Weight::from_proof_size(306895).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1601 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -2556,22 +2558,22 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_code_hash(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `889 + r * (19539 ±0)` - // Estimated: `17170 + r * (295700 ±0)` - // Minimum execution time: 375_980 nanoseconds. - Weight::from_ref_time(232_604_331) - .saturating_add(Weight::from_proof_size(17170)) - // Standard Error: 491_912 - .saturating_add(Weight::from_ref_time(299_479_335).saturating_mul(r.into())) + // Measured: `921 + r * (22099 ±0)` + // Estimated: `17340 + r * (308500 ±0)` + // Minimum execution time: 375_058 nanoseconds. + Weight::from_ref_time(238_765_068) + .saturating_add(Weight::from_proof_size(17340)) + // Standard Error: 662_617 + .saturating_add(Weight::from_ref_time(302_175_089).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(295700).saturating_mul(r.into())) + .saturating_add(Weight::from_proof_size(308500).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -2581,13 +2583,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_own_code_hash(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `852 + r * (480 ±0)` - // Estimated: `17155 + r * (2400 ±0)` - // Minimum execution time: 375_075 nanoseconds. - Weight::from_ref_time(381_217_372) - .saturating_add(Weight::from_proof_size(17155)) - // Standard Error: 63_950 - .saturating_add(Weight::from_ref_time(21_872_316).saturating_mul(r.into())) + // Measured: `884 + r * (480 ±0)` + // Estimated: `17330 + r * (2400 ±0)` + // Minimum execution time: 374_747 nanoseconds. + Weight::from_ref_time(376_482_380) + .saturating_add(Weight::from_proof_size(17330)) + // Standard Error: 61_919 + .saturating_add(Weight::from_ref_time(22_376_795).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_proof_size(2400).saturating_mul(r.into())) @@ -2595,7 +2597,7 @@ impl WeightInfo for () { /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -2605,13 +2607,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_caller_is_origin(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `842 + r * (240 ±0)` - // Estimated: `17080 + r * (1200 ±0)` - // Minimum execution time: 373_260 nanoseconds. - Weight::from_ref_time(377_987_666) - .saturating_add(Weight::from_proof_size(17080)) - // Standard Error: 35_603 - .saturating_add(Weight::from_ref_time(11_274_165).saturating_mul(r.into())) + // Measured: `874 + r * (240 ±0)` + // Estimated: `17265 + r * (1200 ±0)` + // Minimum execution time: 372_287 nanoseconds. + Weight::from_ref_time(376_250_858) + .saturating_add(Weight::from_proof_size(17265)) + // Standard Error: 40_119 + .saturating_add(Weight::from_ref_time(11_359_647).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_proof_size(1200).saturating_mul(r.into())) @@ -2619,7 +2621,7 @@ impl WeightInfo for () { /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -2629,13 +2631,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_address(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `846 + r * (480 ±0)` - // Estimated: `17100 + r * (2400 ±0)` - // Minimum execution time: 374_605 nanoseconds. - Weight::from_ref_time(379_395_443) - .saturating_add(Weight::from_proof_size(17100)) - // Standard Error: 49_646 - .saturating_add(Weight::from_ref_time(17_487_585).saturating_mul(r.into())) + // Measured: `878 + r * (480 ±0)` + // Estimated: `17260 + r * (2400 ±0)` + // Minimum execution time: 374_445 nanoseconds. + Weight::from_ref_time(377_243_521) + .saturating_add(Weight::from_proof_size(17260)) + // Standard Error: 53_032 + .saturating_add(Weight::from_ref_time(17_684_246).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_proof_size(2400).saturating_mul(r.into())) @@ -2643,7 +2645,7 @@ impl WeightInfo for () { /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -2653,21 +2655,21 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_gas_left(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `847 + r * (480 ±0)` - // Estimated: `17105 + r * (2400 ±0)` - // Minimum execution time: 374_620 nanoseconds. - Weight::from_ref_time(379_623_792) - .saturating_add(Weight::from_proof_size(17105)) - // Standard Error: 49_990 - .saturating_add(Weight::from_ref_time(17_226_706).saturating_mul(r.into())) + // Measured: `879 + r * (480 ±0)` + // Estimated: `17250 + r * (2405 ±0)` + // Minimum execution time: 374_029 nanoseconds. + Weight::from_ref_time(380_415_186) + .saturating_add(Weight::from_proof_size(17250)) + // Standard Error: 60_562 + .saturating_add(Weight::from_ref_time(17_152_599).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(2400).saturating_mul(r.into())) + .saturating_add(Weight::from_proof_size(2405).saturating_mul(r.into())) } /// Storage: System Account (r:2 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -2677,13 +2679,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_balance(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1017 + r * (480 ±0)` - // Estimated: `19673 + r * (2456 ±4)` - // Minimum execution time: 374_002 nanoseconds. - Weight::from_ref_time(384_615_649) - .saturating_add(Weight::from_proof_size(19673)) - // Standard Error: 85_633 - .saturating_add(Weight::from_ref_time(95_227_118).saturating_mul(r.into())) + // Measured: `1049 + r * (480 ±0)` + // Estimated: `19849 + r * (2456 ±0)` + // Minimum execution time: 373_999 nanoseconds. + Weight::from_ref_time(381_757_033) + .saturating_add(Weight::from_proof_size(19849)) + // Standard Error: 97_983 + .saturating_add(Weight::from_ref_time(98_290_984).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_proof_size(2456).saturating_mul(r.into())) @@ -2691,7 +2693,7 @@ impl WeightInfo for () { /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -2701,13 +2703,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_value_transferred(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `856 + r * (480 ±0)` - // Estimated: `17200 + r * (2400 ±0)` - // Minimum execution time: 375_307 nanoseconds. - Weight::from_ref_time(378_389_705) - .saturating_add(Weight::from_proof_size(17200)) - // Standard Error: 42_265 - .saturating_add(Weight::from_ref_time(17_316_680).saturating_mul(r.into())) + // Measured: `888 + r * (480 ±0)` + // Estimated: `17360 + r * (2400 ±0)` + // Minimum execution time: 374_197 nanoseconds. + Weight::from_ref_time(377_755_896) + .saturating_add(Weight::from_proof_size(17360)) + // Standard Error: 60_542 + .saturating_add(Weight::from_ref_time(17_442_065).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_proof_size(2400).saturating_mul(r.into())) @@ -2715,7 +2717,7 @@ impl WeightInfo for () { /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -2725,13 +2727,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_minimum_balance(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `854 + r * (480 ±0)` - // Estimated: `17140 + r * (2400 ±0)` - // Minimum execution time: 374_878 nanoseconds. - Weight::from_ref_time(379_364_066) - .saturating_add(Weight::from_proof_size(17140)) - // Standard Error: 49_158 - .saturating_add(Weight::from_ref_time(17_111_145).saturating_mul(r.into())) + // Measured: `886 + r * (480 ±0)` + // Estimated: `17290 + r * (2400 ±0)` + // Minimum execution time: 373_888 nanoseconds. + Weight::from_ref_time(377_825_771) + .saturating_add(Weight::from_proof_size(17290)) + // Standard Error: 38_026 + .saturating_add(Weight::from_ref_time(17_147_903).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_proof_size(2400).saturating_mul(r.into())) @@ -2739,7 +2741,7 @@ impl WeightInfo for () { /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -2749,13 +2751,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_block_number(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `851 + r * (480 ±0)` - // Estimated: `17125 + r * (2400 ±0)` - // Minimum execution time: 374_981 nanoseconds. - Weight::from_ref_time(381_539_022) - .saturating_add(Weight::from_proof_size(17125)) - // Standard Error: 61_419 - .saturating_add(Weight::from_ref_time(17_062_381).saturating_mul(r.into())) + // Measured: `883 + r * (480 ±0)` + // Estimated: `17315 + r * (2400 ±0)` + // Minimum execution time: 373_904 nanoseconds. + Weight::from_ref_time(378_652_372) + .saturating_add(Weight::from_proof_size(17315)) + // Standard Error: 43_833 + .saturating_add(Weight::from_ref_time(16_936_781).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_proof_size(2400).saturating_mul(r.into())) @@ -2763,7 +2765,7 @@ impl WeightInfo for () { /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -2773,13 +2775,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_now(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `842 + r * (480 ±0)` - // Estimated: `17100 + r * (2400 ±0)` - // Minimum execution time: 374_798 nanoseconds. - Weight::from_ref_time(372_659_915) - .saturating_add(Weight::from_proof_size(17100)) - // Standard Error: 151_499 - .saturating_add(Weight::from_ref_time(18_192_683).saturating_mul(r.into())) + // Measured: `874 + r * (480 ±0)` + // Estimated: `17245 + r * (2400 ±0)` + // Minimum execution time: 373_473 nanoseconds. + Weight::from_ref_time(376_386_312) + .saturating_add(Weight::from_proof_size(17245)) + // Standard Error: 46_945 + .saturating_add(Weight::from_ref_time(17_336_462).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_proof_size(2400).saturating_mul(r.into())) @@ -2787,7 +2789,7 @@ impl WeightInfo for () { /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -2799,13 +2801,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_weight_to_fee(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `919 + r * (800 ±0)` - // Estimated: `18835 + r * (4805 ±0)` - // Minimum execution time: 374_841 nanoseconds. - Weight::from_ref_time(385_475_889) - .saturating_add(Weight::from_proof_size(18835)) - // Standard Error: 106_207 - .saturating_add(Weight::from_ref_time(88_099_987).saturating_mul(r.into())) + // Measured: `951 + r * (800 ±0)` + // Estimated: `19046 + r * (4805 ±0)` + // Minimum execution time: 373_661 nanoseconds. + Weight::from_ref_time(385_824_015) + .saturating_add(Weight::from_proof_size(19046)) + // Standard Error: 75_964 + .saturating_add(Weight::from_ref_time(88_530_074).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_proof_size(4805).saturating_mul(r.into())) @@ -2813,7 +2815,7 @@ impl WeightInfo for () { /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -2823,13 +2825,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_gas(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `809 + r * (320 ±0)` - // Estimated: `16955 + r * (1600 ±0)` - // Minimum execution time: 134_436 nanoseconds. - Weight::from_ref_time(137_789_498) - .saturating_add(Weight::from_proof_size(16955)) - // Standard Error: 10_622 - .saturating_add(Weight::from_ref_time(8_144_024).saturating_mul(r.into())) + // Measured: `841 + r * (320 ±0)` + // Estimated: `17120 + r * (1600 ±0)` + // Minimum execution time: 133_849 nanoseconds. + Weight::from_ref_time(137_283_391) + .saturating_add(Weight::from_proof_size(17120)) + // Standard Error: 13_312 + .saturating_add(Weight::from_ref_time(8_055_328).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_proof_size(1600).saturating_mul(r.into())) @@ -2837,7 +2839,7 @@ impl WeightInfo for () { /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -2847,13 +2849,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_input(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `844 + r * (480 ±0)` - // Estimated: `17085 + r * (2400 ±0)` - // Minimum execution time: 374_480 nanoseconds. - Weight::from_ref_time(379_723_392) - .saturating_add(Weight::from_proof_size(17085)) - // Standard Error: 50_240 - .saturating_add(Weight::from_ref_time(15_358_041).saturating_mul(r.into())) + // Measured: `876 + r * (480 ±0)` + // Estimated: `17245 + r * (2400 ±0)` + // Minimum execution time: 373_468 nanoseconds. + Weight::from_ref_time(376_121_093) + .saturating_add(Weight::from_proof_size(17245)) + // Standard Error: 61_857 + .saturating_add(Weight::from_ref_time(15_868_414).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_proof_size(2400).saturating_mul(r.into())) @@ -2861,7 +2863,7 @@ impl WeightInfo for () { /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -2871,20 +2873,20 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 1024]`. fn seal_input_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1324` - // Estimated: `19490` - // Minimum execution time: 392_282 nanoseconds. - Weight::from_ref_time(418_943_323) - .saturating_add(Weight::from_proof_size(19490)) - // Standard Error: 4_673 - .saturating_add(Weight::from_ref_time(9_664_301).saturating_mul(n.into())) + // Measured: `1356` + // Estimated: `19650` + // Minimum execution time: 390_668 nanoseconds. + Weight::from_ref_time(419_608_449) + .saturating_add(Weight::from_proof_size(19650)) + // Standard Error: 4_890 + .saturating_add(Weight::from_ref_time(9_672_288).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -2894,11 +2896,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1]`. fn seal_return(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `832 + r * (45 ±0)` - // Estimated: `17030 + r * (225 ±0)` - // Minimum execution time: 372_207 nanoseconds. - Weight::from_ref_time(376_232_444) - .saturating_add(Weight::from_proof_size(17030)) + // Measured: `864 + r * (45 ±0)` + // Estimated: `17190 + r * (225 ±0)` + // Minimum execution time: 371_309 nanoseconds. + Weight::from_ref_time(373_625_402) + .saturating_add(Weight::from_proof_size(17190)) + // Standard Error: 419_605 + .saturating_add(Weight::from_ref_time(1_737_397).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_proof_size(225).saturating_mul(r.into())) @@ -2906,7 +2910,7 @@ impl WeightInfo for () { /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -2916,20 +2920,20 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 1024]`. fn seal_return_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `842` - // Estimated: `17125` - // Minimum execution time: 374_743 nanoseconds. - Weight::from_ref_time(377_365_053) - .saturating_add(Weight::from_proof_size(17125)) - // Standard Error: 1_073 - .saturating_add(Weight::from_ref_time(231_251).saturating_mul(n.into())) + // Measured: `874` + // Estimated: `17285` + // Minimum execution time: 374_094 nanoseconds. + Weight::from_ref_time(375_965_200) + .saturating_add(Weight::from_proof_size(17285)) + // Standard Error: 1_127 + .saturating_add(Weight::from_ref_time(232_645).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: System Account (r:3 w:3) + /// Storage: System Account (r:4 w:4) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -2943,23 +2947,23 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1]`. fn seal_terminate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `874 + r * (280 ±0)` - // Estimated: `19880 + r * (11465 ±0)` - // Minimum execution time: 374_873 nanoseconds. - Weight::from_ref_time(378_422_289) - .saturating_add(Weight::from_proof_size(19880)) - // Standard Error: 979_734 - .saturating_add(Weight::from_ref_time(57_035_310).saturating_mul(r.into())) + // Measured: `906 + r * (452 ±0)` + // Estimated: `20242 + r * (15004 ±0)` + // Minimum execution time: 373_123 nanoseconds. + Weight::from_ref_time(374_924_634) + .saturating_add(Weight::from_proof_size(20242)) + // Standard Error: 378_010 + .saturating_add(Weight::from_ref_time(70_441_665).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) - .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(r.into()))) + .saturating_add(RocksDbWeight::get().reads((6_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(RocksDbWeight::get().writes((6_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_proof_size(11465).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().writes((7_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_proof_size(15004).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -2971,13 +2975,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_random(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `889 + r * (800 ±0)` - // Estimated: `18643 + r * (4805 ±0)` - // Minimum execution time: 375_001 nanoseconds. - Weight::from_ref_time(382_558_599) - .saturating_add(Weight::from_proof_size(18643)) - // Standard Error: 94_918 - .saturating_add(Weight::from_ref_time(112_973_277).saturating_mul(r.into())) + // Measured: `921 + r * (800 ±0)` + // Estimated: `18835 + r * (4805 ±0)` + // Minimum execution time: 373_291 nanoseconds. + Weight::from_ref_time(385_684_344) + .saturating_add(Weight::from_proof_size(18835)) + // Standard Error: 99_025 + .saturating_add(Weight::from_ref_time(111_308_793).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_proof_size(4805).saturating_mul(r.into())) @@ -2985,7 +2989,7 @@ impl WeightInfo for () { /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -2995,13 +2999,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_deposit_event(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `842 + r * (800 ±0)` - // Estimated: `17075 + r * (4000 ±0)` - // Minimum execution time: 372_547 nanoseconds. - Weight::from_ref_time(383_278_916) - .saturating_add(Weight::from_proof_size(17075)) - // Standard Error: 128_339 - .saturating_add(Weight::from_ref_time(229_356_088).saturating_mul(r.into())) + // Measured: `874 + r * (800 ±0)` + // Estimated: `17250 + r * (4000 ±0)` + // Minimum execution time: 371_900 nanoseconds. + Weight::from_ref_time(384_166_626) + .saturating_add(Weight::from_proof_size(17250)) + // Standard Error: 205_255 + .saturating_add(Weight::from_ref_time(229_214_157).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_proof_size(4000).saturating_mul(r.into())) @@ -3009,7 +3013,7 @@ impl WeightInfo for () { /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -3020,15 +3024,15 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 16]`. fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1778 + t * (2608 ±0) + n * (8 ±0)` - // Estimated: `21675 + t * (211030 ±0) + n * (50 ±0)` - // Minimum execution time: 1_290_432 nanoseconds. - Weight::from_ref_time(595_859_216) - .saturating_add(Weight::from_proof_size(21675)) - // Standard Error: 602_943 - .saturating_add(Weight::from_ref_time(178_128_149).saturating_mul(t.into())) - // Standard Error: 165_597 - .saturating_add(Weight::from_ref_time(71_475_468).saturating_mul(n.into())) + // Measured: `1821 + t * (2608 ±0) + n * (7 ±0)` + // Estimated: `21870 + t * (211030 ±0) + n * (50 ±0)` + // Minimum execution time: 1_289_873 nanoseconds. + Weight::from_ref_time(581_702_206) + .saturating_add(Weight::from_proof_size(21870)) + // Standard Error: 665_638 + .saturating_add(Weight::from_ref_time(181_470_553).saturating_mul(t.into())) + // Standard Error: 182_816 + .saturating_add(Weight::from_ref_time(71_635_250).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(t.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3039,7 +3043,7 @@ impl WeightInfo for () { /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -3049,13 +3053,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_debug_message(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `841 + r * (560 ±0)` - // Estimated: `17065 + r * (2800 ±0)` - // Minimum execution time: 149_020 nanoseconds. - Weight::from_ref_time(152_893_012) - .saturating_add(Weight::from_proof_size(17065)) - // Standard Error: 31_804 - .saturating_add(Weight::from_ref_time(14_497_512).saturating_mul(r.into())) + // Measured: `873 + r * (560 ±0)` + // Estimated: `17240 + r * (2800 ±0)` + // Minimum execution time: 148_635 nanoseconds. + Weight::from_ref_time(154_095_712) + .saturating_add(Weight::from_proof_size(17240)) + // Standard Error: 77_790 + .saturating_add(Weight::from_ref_time(14_837_085).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_proof_size(2800).saturating_mul(r.into())) @@ -3063,7 +3067,7 @@ impl WeightInfo for () { /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: MaxEncodedLen) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: MaxEncodedLen) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: MaxEncodedLen) /// Storage: Timestamp Now (r:1 w:0) @@ -3073,13 +3077,13 @@ impl WeightInfo for () { /// The range of component `i` is `[0, 1024]`. fn seal_debug_message_per_kb(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `125792` - // Estimated: `265059` - // Minimum execution time: 502_589 nanoseconds. - Weight::from_ref_time(506_695_307) - .saturating_add(Weight::from_proof_size(265059)) - // Standard Error: 2_148 - .saturating_add(Weight::from_ref_time(814_647).saturating_mul(i.into())) + // Measured: `125824` + // Estimated: `265128` + // Minimum execution time: 501_014 nanoseconds. + Weight::from_ref_time(505_634_218) + .saturating_add(Weight::from_proof_size(265128)) + // Standard Error: 2_441 + .saturating_add(Weight::from_ref_time(819_257).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3088,85 +3092,85 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 10]`. fn seal_set_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `883 + r * (23417 ±0)` - // Estimated: `883 + r * (23417 ±0)` - // Minimum execution time: 375_473 nanoseconds. - Weight::from_ref_time(291_125_810) - .saturating_add(Weight::from_proof_size(883)) - // Standard Error: 824_971 - .saturating_add(Weight::from_ref_time(477_999_695).saturating_mul(r.into())) + // Measured: `911 + r * (23420 ±0)` + // Estimated: `911 + r * (23418 ±0)` + // Minimum execution time: 375_301 nanoseconds. + Weight::from_ref_time(291_498_841) + .saturating_add(Weight::from_proof_size(911)) + // Standard Error: 809_989 + .saturating_add(Weight::from_ref_time(464_550_291).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((80_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_proof_size(23417).saturating_mul(r.into())) + .saturating_add(Weight::from_proof_size(23418).saturating_mul(r.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_new_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `12583 + n * (11969 ±0)` - // Estimated: `8500 + n * (12813 ±61)` - // Minimum execution time: 515_962 nanoseconds. - Weight::from_ref_time(697_904_030) - .saturating_add(Weight::from_proof_size(8500)) - // Standard Error: 1_684_000 - .saturating_add(Weight::from_ref_time(98_411_710).saturating_mul(n.into())) + // Measured: `12672 + n * (11945 ±0)` + // Estimated: `8529 + n * (12814 ±61)` + // Minimum execution time: 506_318 nanoseconds. + Weight::from_ref_time(676_935_313) + .saturating_add(Weight::from_proof_size(8529)) + // Standard Error: 1_589_291 + .saturating_add(Weight::from_ref_time(97_839_399).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(52_u64)) .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(50_u64)) .saturating_add(RocksDbWeight::get().writes((7_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_proof_size(12813).saturating_mul(n.into())) + .saturating_add(Weight::from_proof_size(12814).saturating_mul(n.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_old_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `15138 + n * (175775 ±0)` - // Estimated: `9898 + n * (176855 ±74)` - // Minimum execution time: 515_828 nanoseconds. - Weight::from_ref_time(661_240_495) - .saturating_add(Weight::from_proof_size(9898)) - // Standard Error: 1_338_661 - .saturating_add(Weight::from_ref_time(65_767_819).saturating_mul(n.into())) + // Measured: `15170 + n * (175775 ±0)` + // Estimated: `9914 + n * (176858 ±74)` + // Minimum execution time: 506_148 nanoseconds. + Weight::from_ref_time(648_278_778) + .saturating_add(Weight::from_proof_size(9914)) + // Standard Error: 1_343_586 + .saturating_add(Weight::from_ref_time(65_789_595).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(51_u64)) .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(49_u64)) .saturating_add(RocksDbWeight::get().writes((7_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_proof_size(176855).saturating_mul(n.into())) + .saturating_add(Weight::from_proof_size(176858).saturating_mul(n.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 10]`. fn seal_clear_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `876 + r * (23098 ±0)` - // Estimated: `881 + r * (23097 ±0)` - // Minimum execution time: 375_528 nanoseconds. - Weight::from_ref_time(296_453_612) - .saturating_add(Weight::from_proof_size(881)) - // Standard Error: 809_232 - .saturating_add(Weight::from_ref_time(465_365_815).saturating_mul(r.into())) + // Measured: `903 + r * (23099 ±0)` + // Estimated: `908 + r * (23099 ±0)` + // Minimum execution time: 374_344 nanoseconds. + Weight::from_ref_time(293_272_061) + .saturating_add(Weight::from_proof_size(908)) + // Standard Error: 810_412 + .saturating_add(Weight::from_ref_time(453_315_956).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((80_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_proof_size(23097).saturating_mul(r.into())) + .saturating_add(Weight::from_proof_size(23099).saturating_mul(r.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `n` is `[0, 8]`. fn seal_clear_storage_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `14863 + n * (175768 ±0)` - // Estimated: `9519 + n * (176867 ±75)` - // Minimum execution time: 480_427 nanoseconds. - Weight::from_ref_time(640_337_570) - .saturating_add(Weight::from_proof_size(9519)) - // Standard Error: 1_497_141 - .saturating_add(Weight::from_ref_time(67_963_696).saturating_mul(n.into())) + // Measured: `14895 + n * (175768 ±0)` + // Estimated: `9551 + n * (176867 ±75)` + // Minimum execution time: 478_564 nanoseconds. + Weight::from_ref_time(630_839_142) + .saturating_add(Weight::from_proof_size(9551)) + // Standard Error: 1_427_520 + .saturating_add(Weight::from_ref_time(66_813_592).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(51_u64)) .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(48_u64)) @@ -3178,30 +3182,30 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 10]`. fn seal_get_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `878 + r * (23740 ±0)` - // Estimated: `880 + r * (23739 ±0)` - // Minimum execution time: 375_725 nanoseconds. - Weight::from_ref_time(307_839_394) - .saturating_add(Weight::from_proof_size(880)) - // Standard Error: 710_694 - .saturating_add(Weight::from_ref_time(381_738_407).saturating_mul(r.into())) + // Measured: `896 + r * (23744 ±0)` + // Estimated: `909 + r * (23740 ±0)` + // Minimum execution time: 374_479 nanoseconds. + Weight::from_ref_time(311_839_315) + .saturating_add(Weight::from_proof_size(909)) + // Standard Error: 666_553 + .saturating_add(Weight::from_ref_time(371_213_042).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(23739).saturating_mul(r.into())) + .saturating_add(Weight::from_proof_size(23740).saturating_mul(r.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `n` is `[0, 8]`. fn seal_get_storage_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `15469 + n * (175775 ±0)` - // Estimated: `10010 + n * (176900 ±76)` - // Minimum execution time: 461_871 nanoseconds. - Weight::from_ref_time(605_755_493) - .saturating_add(Weight::from_proof_size(10010)) - // Standard Error: 1_375_044 - .saturating_add(Weight::from_ref_time(161_332_330).saturating_mul(n.into())) + // Measured: `15501 + n * (175775 ±0)` + // Estimated: `10042 + n * (176900 ±76)` + // Minimum execution time: 460_639 nanoseconds. + Weight::from_ref_time(591_187_094) + .saturating_add(Weight::from_proof_size(10042)) + // Standard Error: 1_233_792 + .saturating_add(Weight::from_ref_time(160_874_477).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(51_u64)) .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3212,47 +3216,47 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 10]`. fn seal_contains_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `871 + r * (23100 ±0)` - // Estimated: `873 + r * (23099 ±0)` - // Minimum execution time: 375_325 nanoseconds. - Weight::from_ref_time(305_508_307) - .saturating_add(Weight::from_proof_size(873)) - // Standard Error: 715_627 - .saturating_add(Weight::from_ref_time(369_985_438).saturating_mul(r.into())) + // Measured: `914 + r * (23098 ±0)` + // Estimated: `920 + r * (23098 ±0)` + // Minimum execution time: 374_272 nanoseconds. + Weight::from_ref_time(311_446_269) + .saturating_add(Weight::from_proof_size(920)) + // Standard Error: 630_307 + .saturating_add(Weight::from_ref_time(357_134_931).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(23099).saturating_mul(r.into())) + .saturating_add(Weight::from_proof_size(23098).saturating_mul(r.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `n` is `[0, 8]`. fn seal_contains_storage_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `14814 + n * (175782 ±0)` - // Estimated: `9502 + n * (176872 ±75)` - // Minimum execution time: 457_128 nanoseconds. - Weight::from_ref_time(582_799_799) - .saturating_add(Weight::from_proof_size(9502)) - // Standard Error: 1_151_126 - .saturating_add(Weight::from_ref_time(63_425_277).saturating_mul(n.into())) + // Measured: `14839 + n * (175789 ±0)` + // Estimated: `9532 + n * (176874 ±75)` + // Minimum execution time: 456_013 nanoseconds. + Weight::from_ref_time(575_116_352) + .saturating_add(Weight::from_proof_size(9532)) + // Standard Error: 1_122_298 + .saturating_add(Weight::from_ref_time(61_786_107).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(51_u64)) .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(176872).saturating_mul(n.into())) + .saturating_add(Weight::from_proof_size(176874).saturating_mul(n.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 10]`. fn seal_take_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `879 + r * (23740 ±0)` - // Estimated: `881 + r * (23739 ±0)` - // Minimum execution time: 375_918 nanoseconds. - Weight::from_ref_time(293_217_646) - .saturating_add(Weight::from_proof_size(881)) - // Standard Error: 840_266 - .saturating_add(Weight::from_ref_time(478_374_701).saturating_mul(r.into())) + // Measured: `911 + r * (23740 ±0)` + // Estimated: `913 + r * (23739 ±0)` + // Minimum execution time: 374_621 nanoseconds. + Weight::from_ref_time(299_689_489) + .saturating_add(Weight::from_proof_size(913)) + // Standard Error: 757_735 + .saturating_add(Weight::from_ref_time(465_213_246).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3264,13 +3268,13 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 8]`. fn seal_take_storage_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `15470 + n * (175775 ±0)` - // Estimated: `10010 + n * (176898 ±76)` - // Minimum execution time: 484_207 nanoseconds. - Weight::from_ref_time(664_065_436) - .saturating_add(Weight::from_proof_size(10010)) - // Standard Error: 1_655_442 - .saturating_add(Weight::from_ref_time(166_258_757).saturating_mul(n.into())) + // Measured: `15502 + n * (175775 ±0)` + // Estimated: `10042 + n * (176898 ±76)` + // Minimum execution time: 481_980 nanoseconds. + Weight::from_ref_time(647_289_053) + .saturating_add(Weight::from_proof_size(10042)) + // Standard Error: 1_556_155 + .saturating_add(Weight::from_ref_time(166_592_657).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(51_u64)) .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(48_u64)) @@ -3280,7 +3284,7 @@ impl WeightInfo for () { /// Storage: System Account (r:1602 w:1601) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -3290,23 +3294,23 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_transfer(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1393 + r * (3602 ±0)` - // Estimated: `21258 + r * (216091 ±0)` - // Minimum execution time: 377_152 nanoseconds. - Weight::from_ref_time(317_470_910) - .saturating_add(Weight::from_proof_size(21258)) - // Standard Error: 994_076 - .saturating_add(Weight::from_ref_time(1_409_416_087).saturating_mul(r.into())) + // Measured: `1457 + r * (3604 ±0)` + // Estimated: `21583 + r * (216101 ±0)` + // Minimum execution time: 374_962 nanoseconds. + Weight::from_ref_time(313_416_386) + .saturating_add(Weight::from_proof_size(21583)) + // Standard Error: 710_675 + .saturating_add(Weight::from_ref_time(1_396_551_156).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(RocksDbWeight::get().writes((80_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_proof_size(216091).saturating_mul(r.into())) + .saturating_add(Weight::from_proof_size(216101).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1601 w:1601) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:2 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -3316,23 +3320,23 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_call(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1551 + r * (20511 ±0)` - // Estimated: `21848 + r * (498651 ±1)` - // Minimum execution time: 376_257 nanoseconds. - Weight::from_ref_time(377_035_000) - .saturating_add(Weight::from_proof_size(21848)) - // Standard Error: 7_966_778 - .saturating_add(Weight::from_ref_time(28_873_495_129).saturating_mul(r.into())) + // Measured: `1609 + r * (23073 ±0)` + // Estimated: `22098 + r * (511456 ±1)` + // Minimum execution time: 375_916 nanoseconds. + Weight::from_ref_time(376_468_000) + .saturating_add(Weight::from_proof_size(22098)) + // Standard Error: 7_246_855 + .saturating_add(Weight::from_ref_time(28_982_425_139).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().reads((160_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((160_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_proof_size(498651).saturating_mul(r.into())) + .saturating_add(Weight::from_proof_size(511456).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1536 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -3343,22 +3347,22 @@ impl WeightInfo for () { fn seal_delegate_call(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + r * (71670 ±0)` - // Estimated: `17125 + r * (659927 ±822)` - // Minimum execution time: 376_544 nanoseconds. - Weight::from_ref_time(377_490_000) - .saturating_add(Weight::from_proof_size(17125)) - // Standard Error: 8_608_050 - .saturating_add(Weight::from_ref_time(28_568_714_410).saturating_mul(r.into())) + // Estimated: `17285 + r * (659930 ±563)` + // Minimum execution time: 375_412 nanoseconds. + Weight::from_ref_time(376_493_000) + .saturating_add(Weight::from_proof_size(17285)) + // Standard Error: 8_239_575 + .saturating_add(Weight::from_ref_time(28_716_347_183).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((150_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((75_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_proof_size(659927).saturating_mul(r.into())) + .saturating_add(Weight::from_proof_size(659930).saturating_mul(r.into())) } /// Storage: System Account (r:82 w:81) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:81 w:81) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:2 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -3369,25 +3373,25 @@ impl WeightInfo for () { /// The range of component `c` is `[0, 1024]`. fn seal_call_per_transfer_clone_kb(t: u32, c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `21611 + t * (15369 ±0)` - // Estimated: `519400 + t * (277320 ±0)` - // Minimum execution time: 10_322_052 nanoseconds. - Weight::from_ref_time(9_248_652_894) - .saturating_add(Weight::from_proof_size(519400)) - // Standard Error: 9_039_638 - .saturating_add(Weight::from_ref_time(1_393_054_441).saturating_mul(t.into())) - // Standard Error: 13_554 - .saturating_add(Weight::from_ref_time(9_819_606).saturating_mul(c.into())) + // Measured: `24269 + t * (16910 ±0)` + // Estimated: `532690 + t * (285025 ±0)` + // Minimum execution time: 10_443_315 nanoseconds. + Weight::from_ref_time(9_342_574_069) + .saturating_add(Weight::from_proof_size(532690)) + // Standard Error: 7_237_279 + .saturating_add(Weight::from_ref_time(1_390_221_936).saturating_mul(t.into())) + // Standard Error: 10_851 + .saturating_add(Weight::from_ref_time(9_842_151).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(167_u64)) .saturating_add(RocksDbWeight::get().reads((81_u64).saturating_mul(t.into()))) .saturating_add(RocksDbWeight::get().writes(163_u64)) .saturating_add(RocksDbWeight::get().writes((81_u64).saturating_mul(t.into()))) - .saturating_add(Weight::from_proof_size(277320).saturating_mul(t.into())) + .saturating_add(Weight::from_proof_size(285025).saturating_mul(t.into())) } - /// Storage: System Account (r:1602 w:1602) + /// Storage: System Account (r:3202 w:3202) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1601 w:1601) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1601 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -3401,23 +3405,23 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_instantiate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1613 + r * (25576 ±0)` - // Estimated: `25698 + r * (1169112 ±1)` - // Minimum execution time: 376_639 nanoseconds. - Weight::from_ref_time(377_892_000) - .saturating_add(Weight::from_proof_size(25698)) - // Standard Error: 21_259_255 - .saturating_add(Weight::from_ref_time(34_131_174_956).saturating_mul(r.into())) + // Measured: `1775 + r * (25568 ±0)` + // Estimated: `26563 + r * (1367114 ±2)` + // Minimum execution time: 376_418 nanoseconds. + Weight::from_ref_time(377_292_000) + .saturating_add(Weight::from_proof_size(26563)) + // Standard Error: 32_312_545 + .saturating_add(Weight::from_ref_time(35_904_826_312).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) - .saturating_add(RocksDbWeight::get().reads((400_u64).saturating_mul(r.into()))) + .saturating_add(RocksDbWeight::get().reads((480_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(5_u64)) - .saturating_add(RocksDbWeight::get().writes((320_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_proof_size(1169112).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().writes((400_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_proof_size(1367114).saturating_mul(r.into())) } - /// Storage: System Account (r:82 w:82) + /// Storage: System Account (r:162 w:162) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:81 w:81) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:2 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -3433,27 +3437,27 @@ impl WeightInfo for () { /// The range of component `s` is `[0, 960]`. fn seal_instantiate_per_transfer_input_salt_kb(t: u32, i: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `5666 + t * (17 ±0)` - // Estimated: `651914 + t * (2762 ±3)` - // Minimum execution time: 130_366_376 nanoseconds. - Weight::from_ref_time(9_844_607_874) - .saturating_add(Weight::from_proof_size(651914)) - // Standard Error: 100_211_149 - .saturating_add(Weight::from_ref_time(390_481_449).saturating_mul(t.into())) - // Standard Error: 163_416 - .saturating_add(Weight::from_ref_time(126_154_200).saturating_mul(i.into())) - // Standard Error: 163_416 - .saturating_add(Weight::from_ref_time(126_430_874).saturating_mul(s.into())) - .saturating_add(RocksDbWeight::get().reads(249_u64)) + // Measured: `5785 + t * (33 ±0)` + // Estimated: `850985 + t * (2671 ±3)` + // Minimum execution time: 132_157_340 nanoseconds. + Weight::from_ref_time(11_329_968_948) + .saturating_add(Weight::from_proof_size(850985)) + // Standard Error: 99_102_968 + .saturating_add(Weight::from_ref_time(84_719_458).saturating_mul(t.into())) + // Standard Error: 161_609 + .saturating_add(Weight::from_ref_time(126_156_627).saturating_mul(i.into())) + // Standard Error: 161_609 + .saturating_add(Weight::from_ref_time(126_628_313).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(329_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(t.into()))) - .saturating_add(RocksDbWeight::get().writes(246_u64)) + .saturating_add(RocksDbWeight::get().writes(326_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(t.into()))) - .saturating_add(Weight::from_proof_size(2762).saturating_mul(t.into())) + .saturating_add(Weight::from_proof_size(2671).saturating_mul(t.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -3463,13 +3467,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1]`. fn seal_hash_sha2_256(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `839 + r * (642 ±0)` - // Estimated: `17065 + r * (3210 ±0)` - // Minimum execution time: 373_848 nanoseconds. - Weight::from_ref_time(375_974_597) - .saturating_add(Weight::from_proof_size(17065)) - // Standard Error: 558_923 - .saturating_add(Weight::from_ref_time(42_648_202).saturating_mul(r.into())) + // Measured: `871 + r * (642 ±0)` + // Estimated: `17225 + r * (3210 ±0)` + // Minimum execution time: 373_559 nanoseconds. + Weight::from_ref_time(375_166_904) + .saturating_add(Weight::from_proof_size(17225)) + // Standard Error: 125_024 + .saturating_add(Weight::from_ref_time(42_291_595).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_proof_size(3210).saturating_mul(r.into())) @@ -3477,7 +3481,7 @@ impl WeightInfo for () { /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -3487,20 +3491,20 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 1024]`. fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1641` - // Estimated: `21000` - // Minimum execution time: 417_281 nanoseconds. - Weight::from_ref_time(418_086_000) - .saturating_add(Weight::from_proof_size(21000)) - // Standard Error: 43_883 - .saturating_add(Weight::from_ref_time(324_497_460).saturating_mul(n.into())) + // Measured: `1673` + // Estimated: `21160` + // Minimum execution time: 416_233 nanoseconds. + Weight::from_ref_time(416_785_000) + .saturating_add(Weight::from_proof_size(21160)) + // Standard Error: 56_223 + .saturating_add(Weight::from_ref_time(324_513_835).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -3510,13 +3514,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1]`. fn seal_hash_keccak_256(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `841 + r * (642 ±0)` - // Estimated: `17075 + r * (3210 ±0)` - // Minimum execution time: 372_362 nanoseconds. - Weight::from_ref_time(374_975_677) - .saturating_add(Weight::from_proof_size(17075)) - // Standard Error: 307_932 - .saturating_add(Weight::from_ref_time(57_607_522).saturating_mul(r.into())) + // Measured: `873 + r * (642 ±0)` + // Estimated: `17235 + r * (3210 ±0)` + // Minimum execution time: 371_735 nanoseconds. + Weight::from_ref_time(375_979_430) + .saturating_add(Weight::from_proof_size(17235)) + // Standard Error: 968_037 + .saturating_add(Weight::from_ref_time(57_780_769).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_proof_size(3210).saturating_mul(r.into())) @@ -3524,7 +3528,7 @@ impl WeightInfo for () { /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -3534,20 +3538,20 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 1024]`. fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1643` - // Estimated: `21040` - // Minimum execution time: 431_034 nanoseconds. - Weight::from_ref_time(431_571_000) - .saturating_add(Weight::from_proof_size(21040)) - // Standard Error: 80_071 - .saturating_add(Weight::from_ref_time(261_645_325).saturating_mul(n.into())) + // Measured: `1675` + // Estimated: `21205` + // Minimum execution time: 428_196 nanoseconds. + Weight::from_ref_time(429_438_000) + .saturating_add(Weight::from_proof_size(21205)) + // Standard Error: 57_860 + .saturating_add(Weight::from_ref_time(260_917_896).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -3557,13 +3561,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1]`. fn seal_hash_blake2_256(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `841 + r * (642 ±0)` - // Estimated: `17075 + r * (3210 ±0)` - // Minimum execution time: 372_069 nanoseconds. - Weight::from_ref_time(374_200_608) - .saturating_add(Weight::from_proof_size(17075)) - // Standard Error: 171_799 - .saturating_add(Weight::from_ref_time(32_843_391).saturating_mul(r.into())) + // Measured: `873 + r * (642 ±0)` + // Estimated: `17235 + r * (3210 ±0)` + // Minimum execution time: 371_412 nanoseconds. + Weight::from_ref_time(373_635_818) + .saturating_add(Weight::from_proof_size(17235)) + // Standard Error: 222_973 + .saturating_add(Weight::from_ref_time(33_347_181).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_proof_size(3210).saturating_mul(r.into())) @@ -3571,7 +3575,7 @@ impl WeightInfo for () { /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -3581,20 +3585,20 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1643` - // Estimated: `21010` - // Minimum execution time: 406_143 nanoseconds. - Weight::from_ref_time(406_744_000) - .saturating_add(Weight::from_proof_size(21010)) - // Standard Error: 48_038 - .saturating_add(Weight::from_ref_time(103_286_295).saturating_mul(n.into())) + // Measured: `1675` + // Estimated: `21180` + // Minimum execution time: 405_858 nanoseconds. + Weight::from_ref_time(406_498_000) + .saturating_add(Weight::from_proof_size(21180)) + // Standard Error: 48_388 + .saturating_add(Weight::from_ref_time(103_283_157).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -3604,13 +3608,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1]`. fn seal_hash_blake2_128(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `841 + r * (679 ±0)` - // Estimated: `17075 + r * (3395 ±0)` - // Minimum execution time: 372_201 nanoseconds. - Weight::from_ref_time(374_049_708) - .saturating_add(Weight::from_proof_size(17075)) - // Standard Error: 387_179 - .saturating_add(Weight::from_ref_time(38_857_191).saturating_mul(r.into())) + // Measured: `873 + r * (679 ±0)` + // Estimated: `17235 + r * (3395 ±0)` + // Minimum execution time: 371_746 nanoseconds. + Weight::from_ref_time(373_538_171) + .saturating_add(Weight::from_proof_size(17235)) + // Standard Error: 387_332 + .saturating_add(Weight::from_ref_time(35_933_528).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_proof_size(3395).saturating_mul(r.into())) @@ -3618,7 +3622,7 @@ impl WeightInfo for () { /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -3628,20 +3632,20 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1643` - // Estimated: `21050` - // Minimum execution time: 405_819 nanoseconds. - Weight::from_ref_time(406_364_000) - .saturating_add(Weight::from_proof_size(21050)) - // Standard Error: 46_248 - .saturating_add(Weight::from_ref_time(103_189_157).saturating_mul(n.into())) + // Measured: `1675` + // Estimated: `21225` + // Minimum execution time: 405_752 nanoseconds. + Weight::from_ref_time(406_417_000) + .saturating_add(Weight::from_proof_size(21225)) + // Standard Error: 47_051 + .saturating_add(Weight::from_ref_time(103_325_027).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -3651,13 +3655,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1]`. fn seal_ecdsa_recover(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `885 + r * (6083 ±0)` - // Estimated: `17295 + r * (30415 ±0)` - // Minimum execution time: 374_836 nanoseconds. - Weight::from_ref_time(379_385_500) - .saturating_add(Weight::from_proof_size(17295)) - // Standard Error: 1_694_427 - .saturating_add(Weight::from_ref_time(3_021_801_000).saturating_mul(r.into())) + // Measured: `917 + r * (6083 ±0)` + // Estimated: `17455 + r * (30415 ±0)` + // Minimum execution time: 373_882 nanoseconds. + Weight::from_ref_time(376_553_787) + .saturating_add(Weight::from_proof_size(17455)) + // Standard Error: 912_833 + .saturating_add(Weight::from_ref_time(3_021_100_412).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_proof_size(30415).saturating_mul(r.into())) @@ -3665,7 +3669,7 @@ impl WeightInfo for () { /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -3675,13 +3679,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1]`. fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `854 + r * (3362 ±0)` - // Estimated: `17140 + r * (16810 ±0)` - // Minimum execution time: 374_223 nanoseconds. - Weight::from_ref_time(376_120_230) - .saturating_add(Weight::from_proof_size(17140)) - // Standard Error: 619_576 - .saturating_add(Weight::from_ref_time(754_257_969).saturating_mul(r.into())) + // Measured: `886 + r * (3362 ±0)` + // Estimated: `17300 + r * (16810 ±0)` + // Minimum execution time: 373_673 nanoseconds. + Weight::from_ref_time(375_712_961) + .saturating_add(Weight::from_proof_size(17300)) + // Standard Error: 596_297 + .saturating_add(Weight::from_ref_time(738_257_638).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_proof_size(16810).saturating_mul(r.into())) @@ -3689,7 +3693,7 @@ impl WeightInfo for () { /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1536 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -3702,12 +3706,12 @@ impl WeightInfo for () { fn seal_set_code_hash(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + r * (79300 ±0)` - // Estimated: `64652 + r * (942952 ±829)` - // Minimum execution time: 374_442 nanoseconds. - Weight::from_ref_time(375_591_000) - .saturating_add(Weight::from_proof_size(64652)) - // Standard Error: 3_764_193 - .saturating_add(Weight::from_ref_time(1_552_885_601).saturating_mul(r.into())) + // Estimated: `64844 + r * (942952 ±833)` + // Minimum execution time: 374_097 nanoseconds. + Weight::from_ref_time(374_985_000) + .saturating_add(Weight::from_proof_size(64844)) + // Standard Error: 3_772_336 + .saturating_add(Weight::from_ref_time(1_546_402_854).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((225_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3717,7 +3721,7 @@ impl WeightInfo for () { /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -3727,13 +3731,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_reentrance_count(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `837 + r * (240 ±0)` - // Estimated: `17055 + r * (1200 ±0)` - // Minimum execution time: 374_922 nanoseconds. - Weight::from_ref_time(376_234_094) - .saturating_add(Weight::from_proof_size(17055)) - // Standard Error: 45_995 - .saturating_add(Weight::from_ref_time(11_606_505).saturating_mul(r.into())) + // Measured: `869 + r * (240 ±0)` + // Estimated: `17215 + r * (1200 ±0)` + // Minimum execution time: 374_249 nanoseconds. + Weight::from_ref_time(377_990_998) + .saturating_add(Weight::from_proof_size(17215)) + // Standard Error: 38_133 + .saturating_add(Weight::from_ref_time(11_483_273).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_proof_size(1200).saturating_mul(r.into())) @@ -3741,7 +3745,7 @@ impl WeightInfo for () { /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -3751,21 +3755,21 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_account_reentrance_count(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2056 + r * (3153 ±0)` - // Estimated: `21730 + r * (15870 ±2)` - // Minimum execution time: 376_762 nanoseconds. - Weight::from_ref_time(396_934_359) - .saturating_add(Weight::from_proof_size(21730)) - // Standard Error: 68_263 - .saturating_add(Weight::from_ref_time(18_367_270).saturating_mul(r.into())) + // Measured: `2102 + r * (3154 ±0)` + // Estimated: `21980 + r * (15875 ±2)` + // Minimum execution time: 375_552 nanoseconds. + Weight::from_ref_time(400_624_032) + .saturating_add(Weight::from_proof_size(21980)) + // Standard Error: 82_523 + .saturating_add(Weight::from_ref_time(18_057_327).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(15870).saturating_mul(r.into())) + .saturating_add(Weight::from_proof_size(15875).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) - /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(258), added: 2733, mode: Measured) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:1 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) @@ -3777,13 +3781,13 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_instantiation_nonce(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `840 + r * (240 ±0)` - // Estimated: `18405 + r * (1440 ±0)` - // Minimum execution time: 374_257 nanoseconds. - Weight::from_ref_time(380_453_380) - .saturating_add(Weight::from_proof_size(18405)) - // Standard Error: 42_718 - .saturating_add(Weight::from_ref_time(9_355_253).saturating_mul(r.into())) + // Measured: `872 + r * (240 ±0)` + // Estimated: `18598 + r * (1440 ±0)` + // Minimum execution time: 373_899 nanoseconds. + Weight::from_ref_time(379_733_943) + .saturating_add(Weight::from_proof_size(18598)) + // Standard Error: 32_022 + .saturating_add(Weight::from_ref_time(9_381_180).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(Weight::from_proof_size(1440).saturating_mul(r.into())) @@ -3793,571 +3797,571 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 788 nanoseconds. - Weight::from_ref_time(1_209_829) + // Minimum execution time: 834 nanoseconds. + Weight::from_ref_time(1_009_646) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 3_436 - .saturating_add(Weight::from_ref_time(409_858).saturating_mul(r.into())) + // Standard Error: 388 + .saturating_add(Weight::from_ref_time(411_979).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64load(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 955 nanoseconds. - Weight::from_ref_time(1_526_327) + // Minimum execution time: 882 nanoseconds. + Weight::from_ref_time(1_416_377) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 2_399 - .saturating_add(Weight::from_ref_time(1_084_504).saturating_mul(r.into())) + // Standard Error: 1_133 + .saturating_add(Weight::from_ref_time(1_075_838).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64store(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 967 nanoseconds. - Weight::from_ref_time(1_576_183) + // Minimum execution time: 878 nanoseconds. + Weight::from_ref_time(1_343_056) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 5_719 - .saturating_add(Weight::from_ref_time(1_006_742).saturating_mul(r.into())) + // Standard Error: 426 + .saturating_add(Weight::from_ref_time(1_001_214).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_select(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 849 nanoseconds. - Weight::from_ref_time(1_106_539) + // Minimum execution time: 796 nanoseconds. + Weight::from_ref_time(1_079_086) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 445 - .saturating_add(Weight::from_ref_time(1_149_752).saturating_mul(r.into())) + // Standard Error: 409 + .saturating_add(Weight::from_ref_time(1_149_188).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_if(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 829 nanoseconds. - Weight::from_ref_time(1_171_360) + // Minimum execution time: 800 nanoseconds. + Weight::from_ref_time(1_044_184) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 552 - .saturating_add(Weight::from_ref_time(1_309_914).saturating_mul(r.into())) + // Standard Error: 707 + .saturating_add(Weight::from_ref_time(1_315_686).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_br(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 835 nanoseconds. - Weight::from_ref_time(1_125_578) + // Minimum execution time: 807 nanoseconds. + Weight::from_ref_time(1_049_633) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 374 - .saturating_add(Weight::from_ref_time(641_683).saturating_mul(r.into())) + // Standard Error: 361 + .saturating_add(Weight::from_ref_time(640_530).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_br_if(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 816 nanoseconds. - Weight::from_ref_time(1_032_093) + // Minimum execution time: 774 nanoseconds. + Weight::from_ref_time(1_124_053) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 811 - .saturating_add(Weight::from_ref_time(956_228).saturating_mul(r.into())) + // Standard Error: 784 + .saturating_add(Weight::from_ref_time(949_398).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_br_table(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 801 nanoseconds. - Weight::from_ref_time(816_764) + // Minimum execution time: 810 nanoseconds. + Weight::from_ref_time(676_581) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 2_669 - .saturating_add(Weight::from_ref_time(1_166_556).saturating_mul(r.into())) + // Standard Error: 2_356 + .saturating_add(Weight::from_ref_time(1_163_465).saturating_mul(r.into())) } /// The range of component `e` is `[1, 256]`. fn instr_br_table_per_entry(e: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_639 nanoseconds. - Weight::from_ref_time(2_905_554) + // Minimum execution time: 2_580 nanoseconds. + Weight::from_ref_time(2_835_656) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 62 - .saturating_add(Weight::from_ref_time(4_438).saturating_mul(e.into())) + // Standard Error: 71 + .saturating_add(Weight::from_ref_time(4_686).saturating_mul(e.into())) } /// The range of component `r` is `[0, 50]`. fn instr_call(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 831 nanoseconds. - Weight::from_ref_time(1_729_584) + // Minimum execution time: 826 nanoseconds. + Weight::from_ref_time(1_625_698) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 33_753 - .saturating_add(Weight::from_ref_time(2_380_315).saturating_mul(r.into())) + // Standard Error: 1_740 + .saturating_add(Weight::from_ref_time(2_332_187).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_call_indirect(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 964 nanoseconds. - Weight::from_ref_time(2_445_291) + // Minimum execution time: 901 nanoseconds. + Weight::from_ref_time(2_338_620) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 3_285 - .saturating_add(Weight::from_ref_time(2_938_681).saturating_mul(r.into())) + // Standard Error: 1_642 + .saturating_add(Weight::from_ref_time(2_924_090).saturating_mul(r.into())) } /// The range of component `p` is `[0, 128]`. fn instr_call_indirect_per_param(p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_809 nanoseconds. - Weight::from_ref_time(6_763_286) + // Minimum execution time: 4_670 nanoseconds. + Weight::from_ref_time(5_556_246) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 3_994 - .saturating_add(Weight::from_ref_time(217_632).saturating_mul(p.into())) + // Standard Error: 1_491 + .saturating_add(Weight::from_ref_time(228_965).saturating_mul(p.into())) } /// The range of component `l` is `[0, 1024]`. fn instr_call_per_local(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_138 nanoseconds. - Weight::from_ref_time(3_894_816) + // Minimum execution time: 3_099 nanoseconds. + Weight::from_ref_time(3_896_177) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 131 - .saturating_add(Weight::from_ref_time(91_699).saturating_mul(l.into())) + // Standard Error: 99 + .saturating_add(Weight::from_ref_time(91_304).saturating_mul(l.into())) } /// The range of component `r` is `[0, 50]`. fn instr_local_get(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_959 nanoseconds. - Weight::from_ref_time(3_271_550) + // Minimum execution time: 3_042 nanoseconds. + Weight::from_ref_time(3_334_621) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 223 - .saturating_add(Weight::from_ref_time(460_056).saturating_mul(r.into())) + // Standard Error: 793 + .saturating_add(Weight::from_ref_time(459_346).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_local_set(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_970 nanoseconds. - Weight::from_ref_time(3_216_157) + // Minimum execution time: 2_968 nanoseconds. + Weight::from_ref_time(3_235_286) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 413 - .saturating_add(Weight::from_ref_time(485_842).saturating_mul(r.into())) + // Standard Error: 427 + .saturating_add(Weight::from_ref_time(485_454).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_local_tee(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_980 nanoseconds. - Weight::from_ref_time(3_323_878) + // Minimum execution time: 3_012 nanoseconds. + Weight::from_ref_time(3_303_555) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 2_652 - .saturating_add(Weight::from_ref_time(660_257).saturating_mul(r.into())) + // Standard Error: 371 + .saturating_add(Weight::from_ref_time(657_811).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_global_get(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 917 nanoseconds. - Weight::from_ref_time(1_445_816) + // Minimum execution time: 865 nanoseconds. + Weight::from_ref_time(1_249_987) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 5_642 - .saturating_add(Weight::from_ref_time(894_521).saturating_mul(r.into())) + // Standard Error: 417 + .saturating_add(Weight::from_ref_time(896_704).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_global_set(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 965 nanoseconds. - Weight::from_ref_time(1_373_722) + // Minimum execution time: 866 nanoseconds. + Weight::from_ref_time(1_216_218) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 1_157 - .saturating_add(Weight::from_ref_time(917_643).saturating_mul(r.into())) + // Standard Error: 503 + .saturating_add(Weight::from_ref_time(919_719).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_memory_current(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 982 nanoseconds. - Weight::from_ref_time(1_240_280) + // Minimum execution time: 921 nanoseconds. + Weight::from_ref_time(1_228_408) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 308 - .saturating_add(Weight::from_ref_time(817_972).saturating_mul(r.into())) + // Standard Error: 309 + .saturating_add(Weight::from_ref_time(813_007).saturating_mul(r.into())) } /// The range of component `r` is `[0, 1]`. fn instr_memory_grow(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 858 nanoseconds. - Weight::from_ref_time(962_183) + // Minimum execution time: 820 nanoseconds. + Weight::from_ref_time(914_830) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 6_701 - .saturating_add(Weight::from_ref_time(239_704_216).saturating_mul(r.into())) + // Standard Error: 6_018 + .saturating_add(Weight::from_ref_time(237_062_769).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64clz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 807 nanoseconds. - Weight::from_ref_time(1_132_872) + // Minimum execution time: 812 nanoseconds. + Weight::from_ref_time(1_554_406) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 303 - .saturating_add(Weight::from_ref_time(633_832).saturating_mul(r.into())) + // Standard Error: 9_979 + .saturating_add(Weight::from_ref_time(625_434).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ctz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 823 nanoseconds. - Weight::from_ref_time(1_267_518) + // Minimum execution time: 798 nanoseconds. + Weight::from_ref_time(1_095_113) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 483 - .saturating_add(Weight::from_ref_time(632_620).saturating_mul(r.into())) + // Standard Error: 243 + .saturating_add(Weight::from_ref_time(634_204).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64popcnt(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 857 nanoseconds. - Weight::from_ref_time(1_105_214) + // Minimum execution time: 792 nanoseconds. + Weight::from_ref_time(1_109_845) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 285 - .saturating_add(Weight::from_ref_time(635_039).saturating_mul(r.into())) + // Standard Error: 14_944 + .saturating_add(Weight::from_ref_time(658_834).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64eqz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 821 nanoseconds. - Weight::from_ref_time(750_223) + // Minimum execution time: 815 nanoseconds. + Weight::from_ref_time(1_068_916) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 15_923 - .saturating_add(Weight::from_ref_time(686_322).saturating_mul(r.into())) + // Standard Error: 327 + .saturating_add(Weight::from_ref_time(652_897).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendsi32(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 797 nanoseconds. - Weight::from_ref_time(1_145_072) + // Minimum execution time: 798 nanoseconds. + Weight::from_ref_time(1_069_745) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 311 - .saturating_add(Weight::from_ref_time(618_147).saturating_mul(r.into())) + // Standard Error: 306 + .saturating_add(Weight::from_ref_time(618_481).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendui32(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 803 nanoseconds. - Weight::from_ref_time(1_139_498) + // Minimum execution time: 799 nanoseconds. + Weight::from_ref_time(1_398_001) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 284 - .saturating_add(Weight::from_ref_time(617_393).saturating_mul(r.into())) + // Standard Error: 6_234 + .saturating_add(Weight::from_ref_time(611_399).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i32wrapi64(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 814 nanoseconds. - Weight::from_ref_time(1_099_405) + // Minimum execution time: 811 nanoseconds. + Weight::from_ref_time(1_098_083) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 663 - .saturating_add(Weight::from_ref_time(618_565).saturating_mul(r.into())) + // Standard Error: 297 + .saturating_add(Weight::from_ref_time(617_692).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64eq(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 819 nanoseconds. - Weight::from_ref_time(1_199_220) + // Minimum execution time: 815 nanoseconds. + Weight::from_ref_time(1_046_922) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 485 - .saturating_add(Weight::from_ref_time(906_878).saturating_mul(r.into())) + // Standard Error: 335 + .saturating_add(Weight::from_ref_time(909_196).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ne(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 822 nanoseconds. - Weight::from_ref_time(274_212) + // Minimum execution time: 805 nanoseconds. + Weight::from_ref_time(1_093_667) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 29_294 - .saturating_add(Weight::from_ref_time(971_608).saturating_mul(r.into())) + // Standard Error: 233 + .saturating_add(Weight::from_ref_time(907_378).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64lts(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 796 nanoseconds. - Weight::from_ref_time(1_396_586) + // Minimum execution time: 805 nanoseconds. + Weight::from_ref_time(1_290_591) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 7_205 - .saturating_add(Weight::from_ref_time(903_202).saturating_mul(r.into())) + // Standard Error: 3_201 + .saturating_add(Weight::from_ref_time(902_006).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ltu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 833 nanoseconds. - Weight::from_ref_time(1_115_115) + // Minimum execution time: 783 nanoseconds. + Weight::from_ref_time(1_159_977) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 310 - .saturating_add(Weight::from_ref_time(908_195).saturating_mul(r.into())) + // Standard Error: 2_310 + .saturating_add(Weight::from_ref_time(906_489).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64gts(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 854 nanoseconds. - Weight::from_ref_time(1_170_419) + // Minimum execution time: 790 nanoseconds. + Weight::from_ref_time(1_109_719) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 298 - .saturating_add(Weight::from_ref_time(907_171).saturating_mul(r.into())) + // Standard Error: 261 + .saturating_add(Weight::from_ref_time(906_614).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64gtu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 822 nanoseconds. - Weight::from_ref_time(1_186_349) + // Minimum execution time: 776 nanoseconds. + Weight::from_ref_time(1_076_567) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 302 - .saturating_add(Weight::from_ref_time(917_857).saturating_mul(r.into())) + // Standard Error: 348 + .saturating_add(Weight::from_ref_time(919_374).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64les(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 807 nanoseconds. - Weight::from_ref_time(1_127_093) + // Minimum execution time: 780 nanoseconds. + Weight::from_ref_time(1_069_663) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 1_891 - .saturating_add(Weight::from_ref_time(910_738).saturating_mul(r.into())) + // Standard Error: 265 + .saturating_add(Weight::from_ref_time(908_037).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64leu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 819 nanoseconds. - Weight::from_ref_time(1_143_022) + // Minimum execution time: 832 nanoseconds. + Weight::from_ref_time(930_920) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 309 - .saturating_add(Weight::from_ref_time(919_047).saturating_mul(r.into())) + // Standard Error: 2_170 + .saturating_add(Weight::from_ref_time(929_811).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ges(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 788 nanoseconds. - Weight::from_ref_time(1_116_914) + // Minimum execution time: 787 nanoseconds. + Weight::from_ref_time(1_087_325) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 643 - .saturating_add(Weight::from_ref_time(911_159).saturating_mul(r.into())) + // Standard Error: 315 + .saturating_add(Weight::from_ref_time(908_321).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64geu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 791 nanoseconds. - Weight::from_ref_time(1_123_747) + // Minimum execution time: 798 nanoseconds. + Weight::from_ref_time(1_029_132) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 583 - .saturating_add(Weight::from_ref_time(910_242).saturating_mul(r.into())) + // Standard Error: 2_095 + .saturating_add(Weight::from_ref_time(913_553).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64add(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 787 nanoseconds. - Weight::from_ref_time(1_109_471) + // Minimum execution time: 791 nanoseconds. + Weight::from_ref_time(1_086_314) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 305 - .saturating_add(Weight::from_ref_time(897_608).saturating_mul(r.into())) + // Standard Error: 197 + .saturating_add(Weight::from_ref_time(896_392).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64sub(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 821 nanoseconds. - Weight::from_ref_time(1_098_631) + // Minimum execution time: 793 nanoseconds. + Weight::from_ref_time(1_078_172) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 523 - .saturating_add(Weight::from_ref_time(887_814).saturating_mul(r.into())) + // Standard Error: 404 + .saturating_add(Weight::from_ref_time(886_329).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64mul(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 794 nanoseconds. - Weight::from_ref_time(1_166_332) + // Minimum execution time: 799 nanoseconds. + Weight::from_ref_time(1_095_010) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 384 - .saturating_add(Weight::from_ref_time(885_584).saturating_mul(r.into())) + // Standard Error: 431 + .saturating_add(Weight::from_ref_time(886_513).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64divs(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 822 nanoseconds. - Weight::from_ref_time(1_155_826) + // Minimum execution time: 810 nanoseconds. + Weight::from_ref_time(1_114_325) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 521 - .saturating_add(Weight::from_ref_time(1_520_958).saturating_mul(r.into())) + // Standard Error: 452 + .saturating_add(Weight::from_ref_time(1_521_849).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64divu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 881 nanoseconds. - Weight::from_ref_time(1_158_125) + // Minimum execution time: 784 nanoseconds. + Weight::from_ref_time(1_123_153) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 624 - .saturating_add(Weight::from_ref_time(1_458_378).saturating_mul(r.into())) + // Standard Error: 475 + .saturating_add(Weight::from_ref_time(1_457_746).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64rems(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 827 nanoseconds. - Weight::from_ref_time(1_209_535) + // Minimum execution time: 809 nanoseconds. + Weight::from_ref_time(1_145_906) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 399 - .saturating_add(Weight::from_ref_time(1_547_640).saturating_mul(r.into())) + // Standard Error: 718 + .saturating_add(Weight::from_ref_time(1_549_964).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64remu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 801 nanoseconds. - Weight::from_ref_time(1_313_872) + // Minimum execution time: 803 nanoseconds. + Weight::from_ref_time(1_110_328) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 2_175 - .saturating_add(Weight::from_ref_time(1_449_416).saturating_mul(r.into())) + // Standard Error: 627 + .saturating_add(Weight::from_ref_time(1_453_013).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64and(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 827 nanoseconds. - Weight::from_ref_time(1_093_874) + // Minimum execution time: 786 nanoseconds. + Weight::from_ref_time(1_108_792) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 708 - .saturating_add(Weight::from_ref_time(901_450).saturating_mul(r.into())) + // Standard Error: 286 + .saturating_add(Weight::from_ref_time(897_035).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64or(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 824 nanoseconds. - Weight::from_ref_time(1_164_076) + // Minimum execution time: 787 nanoseconds. + Weight::from_ref_time(830_000) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 623 - .saturating_add(Weight::from_ref_time(897_579).saturating_mul(r.into())) + // Standard Error: 15_995 + .saturating_add(Weight::from_ref_time(963_344).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64xor(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 789 nanoseconds. - Weight::from_ref_time(1_113_915) + // Minimum execution time: 773 nanoseconds. + Weight::from_ref_time(1_082_459) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 390 - .saturating_add(Weight::from_ref_time(897_354).saturating_mul(r.into())) + // Standard Error: 330 + .saturating_add(Weight::from_ref_time(897_077).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64shl(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 811 nanoseconds. - Weight::from_ref_time(1_117_366) + // Minimum execution time: 810 nanoseconds. + Weight::from_ref_time(1_325_815) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 437 - .saturating_add(Weight::from_ref_time(903_759).saturating_mul(r.into())) + // Standard Error: 3_352 + .saturating_add(Weight::from_ref_time(899_555).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64shrs(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 846 nanoseconds. - Weight::from_ref_time(1_103_954) + // Minimum execution time: 808 nanoseconds. + Weight::from_ref_time(1_085_903) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 414 - .saturating_add(Weight::from_ref_time(903_429).saturating_mul(r.into())) + // Standard Error: 430 + .saturating_add(Weight::from_ref_time(903_249).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64shru(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 803 nanoseconds. - Weight::from_ref_time(1_124_328) + // Minimum execution time: 792 nanoseconds. + Weight::from_ref_time(1_091_261) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 410 - .saturating_add(Weight::from_ref_time(903_216).saturating_mul(r.into())) + // Standard Error: 312 + .saturating_add(Weight::from_ref_time(902_245).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotl(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 810 nanoseconds. - Weight::from_ref_time(1_131_433) + // Minimum execution time: 807 nanoseconds. + Weight::from_ref_time(1_121_052) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 402 - .saturating_add(Weight::from_ref_time(903_381).saturating_mul(r.into())) + // Standard Error: 506 + .saturating_add(Weight::from_ref_time(902_772).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotr(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 807 nanoseconds. - Weight::from_ref_time(1_144_933) + // Minimum execution time: 823 nanoseconds. + Weight::from_ref_time(1_317_597) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 373 - .saturating_add(Weight::from_ref_time(902_918).saturating_mul(r.into())) + // Standard Error: 6_219 + .saturating_add(Weight::from_ref_time(896_692).saturating_mul(r.into())) } } From b6c4ab862cda5dd00c16a5de89f7e23aa55e9c44 Mon Sep 17 00:00:00 2001 From: Sergejs Kostjucenko <85877331+sergejparity@users.noreply.github.com> Date: Thu, 16 Feb 2023 18:41:10 +0200 Subject: [PATCH 404/715] fix docker description publishing (#13399) --- scripts/ci/gitlab/pipeline/publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/ci/gitlab/pipeline/publish.yml b/scripts/ci/gitlab/pipeline/publish.yml index 557a7f2127358..0d2e0cac96afe 100644 --- a/scripts/ci/gitlab/pipeline/publish.yml +++ b/scripts/ci/gitlab/pipeline/publish.yml @@ -61,7 +61,7 @@ DOCKER_PASSWORD: $Docker_Hub_Pass_Parity README_FILEPATH: $CI_PROJECT_DIR/scripts/ci/docker/$PRODUCT.Dockerfile.README.md script: - - echo # Dummy command to satisfy GitLab CI linter. + - cd / && sh entrypoint.sh # publish image to docker.io/paritypr, (e.g. for later use in zombienet testing) .build-push-image-temporary: From 873fb68eeb544c436afe5edbd1625b252039653d Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Thu, 16 Feb 2023 23:21:15 +0100 Subject: [PATCH 405/715] `BlockId` removal: `CallApiAt::state_at` (#13394) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * BlockId removal: CallApiAt::state_at It changes the arguments of: - `CallApiAt::state_at`, - `Client::code_at`, - `Client::state_at` from: `BlockId` to: `Block::Hash` * Apply suggestions from code review Co-authored-by: Bastian Köcher --------- Co-authored-by: Bastian Köcher Co-authored-by: parity-processbot <> --- client/service/src/client/client.rs | 8 +++----- primitives/api/src/lib.rs | 2 +- primitives/api/test/tests/runtime_calls.rs | 4 ++-- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/client/service/src/client/client.rs b/client/service/src/client/client.rs index 6a75fad628681..4b28b39931756 100644 --- a/client/service/src/client/client.rs +++ b/client/service/src/client/client.rs @@ -481,8 +481,7 @@ where } /// 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)?; + pub fn code_at(&self, hash: Block::Hash) -> sp_blockchain::Result> { 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;\ @@ -1746,9 +1745,8 @@ where CallExecutor::runtime_version(&self.executor, hash).map_err(Into::into) } - 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) + fn state_at(&self, at: Block::Hash) -> Result { + self.state_at(at).map_err(Into::into) } } diff --git a/primitives/api/src/lib.rs b/primitives/api/src/lib.rs index 4ff4becb80f48..ad9a9b1811859 100644 --- a/primitives/api/src/lib.rs +++ b/primitives/api/src/lib.rs @@ -622,7 +622,7 @@ pub trait CallApiAt { fn runtime_version_at(&self, at: &BlockId) -> Result; /// Get the state `at` the given block. - fn state_at(&self, at: &BlockId) -> Result; + fn state_at(&self, at: Block::Hash) -> Result; } /// Auxiliary wrapper that holds an api instance and binds it to the given lifetime. diff --git a/primitives/api/test/tests/runtime_calls.rs b/primitives/api/test/tests/runtime_calls.rs index 2ac88c7e6c04f..3d355c4747736 100644 --- a/primitives/api/test/tests/runtime_calls.rs +++ b/primitives/api/test/tests/runtime_calls.rs @@ -147,13 +147,12 @@ fn record_proof_works() { .set_execution_strategy(ExecutionStrategy::Both) .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(); let runtime_code = sp_core::traits::RuntimeCode { code_fetcher: &sp_core::traits::WrappedRuntimeCode( - client.code_at(&block_id).unwrap().into(), + client.code_at(client.chain_info().best_hash).unwrap().into(), ), hash: vec![1], heap_pages: None, @@ -167,6 +166,7 @@ fn record_proof_works() { } .into_signed_tx(); + let block_id = BlockId::Hash(client.chain_info().best_hash); // Build the block and record proof let mut builder = client .new_block_at(&block_id, Default::default(), true) From d97a18851f9da0b1c299daa8fb18022794065779 Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Thu, 16 Feb 2023 23:34:00 +0100 Subject: [PATCH 406/715] `BlockId` removal: `Client::runtime_version_at` (#13393) * BlockId removal: Client::runtime_version_at It changes the arguments of `Client::runtime_version_at` from: `BlockId` to: `Block::Hash` * Apply suggestions from code review Co-authored-by: Anton --------- Co-authored-by: Anton Co-authored-by: parity-processbot <> --- bin/node/bench/src/construct.rs | 2 +- bin/node/bench/src/import.rs | 3 +-- bin/node/bench/src/txpool.rs | 2 +- bin/node/cli/src/service.rs | 6 +++--- bin/node/testing/src/bench.rs | 13 +++++-------- client/service/src/client/call_executor.rs | 2 +- client/service/src/client/client.rs | 3 +-- 7 files changed, 13 insertions(+), 18 deletions(-) diff --git a/bin/node/bench/src/construct.rs b/bin/node/bench/src/construct.rs index f994b29b5e843..529a3ba7a001e 100644 --- a/bin/node/bench/src/construct.rs +++ b/bin/node/bench/src/construct.rs @@ -120,7 +120,7 @@ impl core::Benchmark for ConstructionBenchmark { let _ = context .client - .runtime_version_at(&BlockId::Number(0)) + .runtime_version_at(context.client.chain_info().genesis_hash) .expect("Failed to get runtime version") .spec_version; diff --git a/bin/node/bench/src/import.rs b/bin/node/bench/src/import.rs index 7d59e94a44a09..db93833c83200 100644 --- a/bin/node/bench/src/import.rs +++ b/bin/node/bench/src/import.rs @@ -35,7 +35,6 @@ use std::borrow::Cow; use node_primitives::Block; use node_testing::bench::{BenchDb, BlockType, DatabaseType, KeyTypes, Profile}; use sc_client_api::backend::Backend; -use sp_runtime::generic::BlockId; use sp_state_machine::InspectState; use crate::{ @@ -115,7 +114,7 @@ impl core::Benchmark for ImportBenchmark { let _ = context .client - .runtime_version_at(&BlockId::Number(0)) + .runtime_version_at(context.client.chain_info().genesis_hash) .expect("Failed to get runtime version") .spec_version; diff --git a/bin/node/bench/src/txpool.rs b/bin/node/bench/src/txpool.rs index 322dc352e8972..5b4d5513e2b5a 100644 --- a/bin/node/bench/src/txpool.rs +++ b/bin/node/bench/src/txpool.rs @@ -61,7 +61,7 @@ impl core::Benchmark for PoolBenchmark { let _ = context .client - .runtime_version_at(&BlockId::Number(0)) + .runtime_version_at(context.client.chain_info().genesis_hash) .expect("Failed to get runtime version") .spec_version; diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs index 7ad1a9486b544..c98fe17cfc693 100644 --- a/bin/node/cli/src/service.rs +++ b/bin/node/cli/src/service.rs @@ -587,7 +587,7 @@ mod tests { use sp_keyring::AccountKeyring; use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; use sp_runtime::{ - generic::{BlockId, Digest, Era, SignedPayload}, + generic::{Digest, Era, SignedPayload}, key_types::BABE, traits::{Block as BlockT, Header as HeaderT, IdentifyAccount, Verify}, RuntimeAppPublic, @@ -754,9 +754,9 @@ mod tests { let to: Address = AccountPublic::from(bob.public()).into_account().into(); let from: Address = AccountPublic::from(charlie.public()).into_account().into(); let genesis_hash = service.client().block_hash(0).unwrap().unwrap(); - let best_block_id = BlockId::number(service.client().chain_info().best_number); + let best_hash = service.client().chain_info().best_hash; let (spec_version, transaction_version) = { - let version = service.client().runtime_version_at(&best_block_id).unwrap(); + let version = service.client().runtime_version_at(best_hash).unwrap(); (version.spec_version, version.transaction_version) }; let signer = charlie.clone(); diff --git a/bin/node/testing/src/bench.rs b/bin/node/testing/src/bench.rs index 2151a61a6ca7a..cc0a93ca27fc2 100644 --- a/bin/node/testing/src/bench.rs +++ b/bin/node/testing/src/bench.rs @@ -42,7 +42,7 @@ use node_primitives::Block; use sc_block_builder::BlockBuilderProvider; use sc_client_api::{ execution_extensions::{ExecutionExtensions, ExecutionStrategies}, - BlockBackend, ExecutionStrategy, + ExecutionStrategy, }; use sc_client_db::PruningMode; use sc_consensus::{BlockImport, BlockImportParams, ForkChoiceStrategy, ImportResult, ImportedAux}; @@ -54,7 +54,7 @@ use sp_core::{blake2_256, ed25519, sr25519, traits::SpawnNamed, ExecutionContext use sp_inherents::InherentData; use sp_runtime::{ generic::BlockId, - traits::{Block as BlockT, IdentifyAccount, Verify, Zero}, + traits::{Block as BlockT, IdentifyAccount, Verify}, OpaqueExtrinsic, }; @@ -273,15 +273,12 @@ pub struct BlockContentIterator<'a> { impl<'a> BlockContentIterator<'a> { fn new(content: BlockContent, keyring: &'a BenchKeyring, client: &Client) -> Self { + let genesis_hash = client.chain_info().genesis_hash; + let runtime_version = client - .runtime_version_at(&BlockId::number(0)) + .runtime_version_at(genesis_hash) .expect("There should be runtime version at 0"); - let genesis_hash = client - .block_hash(Zero::zero()) - .expect("Database error?") - .expect("Genesis block always exists; qed"); - BlockContentIterator { iteration: 0, content, keyring, runtime_version, genesis_hash } } } diff --git a/client/service/src/client/call_executor.rs b/client/service/src/client/call_executor.rs index 7906d62240e0b..49b969e3e71b0 100644 --- a/client/service/src/client/call_executor.rs +++ b/client/service/src/client/call_executor.rs @@ -485,7 +485,7 @@ mod tests { ) .expect("Creates a client"); - let version = client.runtime_version_at(&BlockId::Number(0)).unwrap(); + let version = client.runtime_version_at(client.chain_info().genesis_hash).unwrap(); assert_eq!(SUBSTITUTE_SPEC_NAME, &*version.spec_name); } diff --git a/client/service/src/client/client.rs b/client/service/src/client/client.rs index 4b28b39931756..d452104ce7e51 100644 --- a/client/service/src/client/client.rs +++ b/client/service/src/client/client.rs @@ -491,8 +491,7 @@ where } /// Get the RuntimeVersion at a given block. - pub fn runtime_version_at(&self, id: &BlockId) -> sp_blockchain::Result { - let hash = self.backend.blockchain().expect_block_hash_from_id(id)?; + pub fn runtime_version_at(&self, hash: Block::Hash) -> sp_blockchain::Result { CallExecutor::runtime_version(&self.executor, hash) } From 63a24581f7f4c42642e8eb5812dd222b4f680a61 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Fri, 17 Feb 2023 11:45:00 +0200 Subject: [PATCH 407/715] BEEFY: implement equivocations detection, reporting and slashing (#13121) * client/beefy: simplify self_vote logic * client/beefy: migrate to new state version * client/beefy: detect equivocated votes * fix typos * sp-beefy: add equivocation primitives * client/beefy: refactor vote processing * fix version migration for new rounds struct * client/beefy: track equivocations and create proofs * client/beefy: adjust tests for new voting logic * sp-beefy: fix commitment ordering and equality * client/beefy: simplify handle_vote() a bit * client/beefy: add simple equivocation test * client/beefy: submit equivocation proof - WIP * frame/beefy: add equivocation report runtime api - part 1 * frame/beefy: report equivocation logic - part 2 * frame/beefy: add pluggable Equivocation handler - part 3 * frame/beefy: impl ValidateUnsigned for equivocations reporting * client/beefy: submit report equivocation unsigned extrinsic * primitives/beefy: fix tests * frame/beefy: add default weights * frame/beefy: fix tests * client/beefy: fix tests * frame/beefy-mmr: fix tests * frame/beefy: cross-check session index with equivocation report * sp-beefy: make test Keyring useable in pallet * frame/beefy: add basic equivocation test * frame/beefy: test verify equivocation results in slashing * frame/beefy: test report_equivocation_old_set * frame/beefy: add more equivocation tests * sp-beefy: fix docs * beefy: simplify equivocations and fix tests * client/beefy: address review comments * frame/beefy: add ValidateUnsigned to test/mock runtime * client/beefy: fixes after merge master * fix missed merge damage * client/beefy: add test for reporting equivocations Also validated there's no unexpected equivocations reported in the other tests. Signed-off-by: acatangiu * sp-beefy: move test utils to their own file * client/beefy: add negative test for equivocation reports * sp-beefy: move back MmrRootProvider - used in polkadot-service * impl review suggestions * client/beefy: add equivocation metrics --------- Signed-off-by: acatangiu Co-authored-by: parity-processbot <> --- Cargo.lock | 8 + client/beefy/src/communication/gossip.rs | 4 +- client/beefy/src/error.rs | 18 +- client/beefy/src/justification.rs | 3 +- client/beefy/src/keystore.rs | 2 +- client/beefy/src/lib.rs | 3 +- client/beefy/src/metrics.rs | 47 +- client/beefy/src/round.rs | 52 +- client/beefy/src/tests.rs | 127 +++-- client/beefy/src/worker.rs | 157 +++++- client/consensus/babe/src/lib.rs | 2 +- frame/beefy-mmr/src/lib.rs | 4 +- frame/beefy-mmr/src/mock.rs | 13 +- frame/beefy/Cargo.toml | 12 + frame/beefy/src/default_weights.rs | 54 ++ frame/beefy/src/equivocation.rs | 385 ++++++++++++++ frame/beefy/src/lib.rs | 252 ++++++++- frame/beefy/src/mock.rs | 231 +++++++- frame/beefy/src/tests.rs | 647 ++++++++++++++++++++++- primitives/beefy/src/lib.rs | 208 +++++--- primitives/beefy/src/test_utils.rs | 110 ++++ test-utils/runtime/src/lib.rs | 14 + 22 files changed, 2140 insertions(+), 213 deletions(-) create mode 100644 frame/beefy/src/default_weights.rs create mode 100644 frame/beefy/src/equivocation.rs create mode 100644 primitives/beefy/src/test_utils.rs diff --git a/Cargo.lock b/Cargo.lock index ef320a85f05a6..b33f7627f230e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5500,9 +5500,16 @@ dependencies = [ name = "pallet-beefy" version = "4.0.0-dev" dependencies = [ + "frame-election-provider-support", "frame-support", "frame-system", + "pallet-authorship", + "pallet-balances", + "pallet-offences", "pallet-session", + "pallet-staking", + "pallet-staking-reward-curve", + "pallet-timestamp", "parity-scale-codec", "scale-info", "serde", @@ -5510,6 +5517,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", + "sp-session", "sp-staking", "sp-std", ] diff --git a/client/beefy/src/communication/gossip.rs b/client/beefy/src/communication/gossip.rs index 5d51610214610..7e60eb11ea731 100644 --- a/client/beefy/src/communication/gossip.rs +++ b/client/beefy/src/communication/gossip.rs @@ -244,8 +244,8 @@ mod tests { use crate::keystore::BeefyKeystore; use beefy_primitives::{ - crypto::Signature, keyring::Keyring, known_payloads, Commitment, MmrRootHash, Payload, - VoteMessage, KEY_TYPE, + crypto::Signature, known_payloads, Commitment, Keyring, MmrRootHash, Payload, VoteMessage, + KEY_TYPE, }; use super::*; diff --git a/client/beefy/src/error.rs b/client/beefy/src/error.rs index dd5fd649d52ce..1b44e3801e303 100644 --- a/client/beefy/src/error.rs +++ b/client/beefy/src/error.rs @@ -22,14 +22,30 @@ use std::fmt::Debug; -#[derive(Debug, thiserror::Error, PartialEq)] +#[derive(Debug, thiserror::Error)] pub enum Error { #[error("Backend: {0}")] Backend(String), #[error("Keystore error: {0}")] Keystore(String), + #[error("Runtime api error: {0}")] + RuntimeApi(sp_api::ApiError), #[error("Signature error: {0}")] Signature(String), #[error("Session uninitialized")] UninitSession, } + +#[cfg(test)] +impl PartialEq for Error { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Error::Backend(s1), Error::Backend(s2)) => s1 == s2, + (Error::Keystore(s1), Error::Keystore(s2)) => s1 == s2, + (Error::RuntimeApi(_), Error::RuntimeApi(_)) => true, + (Error::Signature(s1), Error::Signature(s2)) => s1 == s2, + (Error::UninitSession, Error::UninitSession) => true, + _ => false, + } + } +} diff --git a/client/beefy/src/justification.rs b/client/beefy/src/justification.rs index 6f869015ba763..9f433aa6ad1d7 100644 --- a/client/beefy/src/justification.rs +++ b/client/beefy/src/justification.rs @@ -81,8 +81,7 @@ fn verify_with_validator_set( #[cfg(test)] pub(crate) mod tests { use beefy_primitives::{ - keyring::Keyring, known_payloads, Commitment, Payload, SignedCommitment, - VersionedFinalityProof, + known_payloads, Commitment, Keyring, Payload, SignedCommitment, VersionedFinalityProof, }; use substrate_test_runtime_client::runtime::Block; diff --git a/client/beefy/src/keystore.rs b/client/beefy/src/keystore.rs index 73788a31b7fdc..29436e36e65bb 100644 --- a/client/beefy/src/keystore.rs +++ b/client/beefy/src/keystore.rs @@ -123,7 +123,7 @@ pub mod tests { use sc_keystore::LocalKeystore; use sp_core::{ecdsa, Pair}; - use beefy_primitives::{crypto, keyring::Keyring}; + use beefy_primitives::{crypto, Keyring}; use super::*; use crate::error::Error; diff --git a/client/beefy/src/lib.rs b/client/beefy/src/lib.rs index 5f74b052e99fe..4031b52970283 100644 --- a/client/beefy/src/lib.rs +++ b/client/beefy/src/lib.rs @@ -282,6 +282,7 @@ where let worker_params = worker::WorkerParams { backend, payload_provider, + runtime, network, key_store: key_store.into(), gossip_engine, @@ -292,7 +293,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), diff --git a/client/beefy/src/metrics.rs b/client/beefy/src/metrics.rs index e3b48e6ec8d54..c74fb420d13f4 100644 --- a/client/beefy/src/metrics.rs +++ b/client/beefy/src/metrics.rs @@ -46,10 +46,16 @@ pub struct VoterMetrics { pub beefy_no_authority_found_in_store: Counter, /// Number of currently buffered votes pub beefy_buffered_votes: Gauge, - /// Number of valid but stale votes received - pub beefy_stale_votes: Counter, /// Number of votes dropped due to full buffers pub beefy_buffered_votes_dropped: Counter, + /// Number of good votes successfully handled + pub beefy_good_votes_processed: Counter, + /// Number of equivocation votes received + pub beefy_equivocation_votes: Counter, + /// Number of invalid votes received + pub beefy_invalid_votes: Counter, + /// Number of valid but stale votes received + pub beefy_stale_votes: Counter, /// Number of currently buffered justifications pub beefy_buffered_justifications: Gauge, /// Number of valid but stale justifications received @@ -60,8 +66,6 @@ pub struct VoterMetrics { pub beefy_buffered_justifications_dropped: Counter, /// Trying to set Best Beefy block to old block pub beefy_best_block_set_last_failure: Gauge, - /// Number of Successful handled votes - pub beefy_successful_handled_votes: Counter, } impl PrometheusRegister for VoterMetrics { @@ -109,17 +113,35 @@ impl PrometheusRegister for VoterMetrics { Gauge::new("substrate_beefy_buffered_votes", "Number of currently buffered votes")?, registry, )?, - beefy_stale_votes: register( + beefy_buffered_votes_dropped: register( + Counter::new( + "substrate_beefy_buffered_votes_dropped", + "Number of votes dropped due to full buffers", + )?, + registry, + )?, + beefy_good_votes_processed: register( + Counter::new( + "substrate_beefy_successful_handled_votes", + "Number of good votes successfully handled", + )?, + registry, + )?, + beefy_equivocation_votes: register( Counter::new( "substrate_beefy_stale_votes", - "Number of valid but stale votes received", + "Number of equivocation votes received", )?, registry, )?, - beefy_buffered_votes_dropped: register( + beefy_invalid_votes: register( + Counter::new("substrate_beefy_stale_votes", "Number of invalid votes received")?, + registry, + )?, + beefy_stale_votes: register( Counter::new( - "substrate_beefy_buffered_votes_dropped", - "Number of votes dropped due to full buffers", + "substrate_beefy_stale_votes", + "Number of valid but stale votes received", )?, registry, )?, @@ -158,13 +180,6 @@ impl PrometheusRegister for VoterMetrics { )?, registry, )?, - beefy_successful_handled_votes: register( - Counter::new( - "substrate_beefy_successful_handled_votes", - "Number of Successful handled votes", - )?, - registry, - )?, }) } } diff --git a/client/beefy/src/round.rs b/client/beefy/src/round.rs index 9ad4e5d0232bf..b2c4e97a420fe 100644 --- a/client/beefy/src/round.rs +++ b/client/beefy/src/round.rs @@ -20,7 +20,7 @@ use crate::LOG_TARGET; use beefy_primitives::{ crypto::{AuthorityId, Public, Signature}, - Commitment, SignedCommitment, ValidatorSet, ValidatorSetId, VoteMessage, + Commitment, EquivocationProof, SignedCommitment, ValidatorSet, ValidatorSetId, VoteMessage, }; use codec::{Decode, Encode}; use log::debug; @@ -61,7 +61,7 @@ pub fn threshold(authorities: usize) -> usize { pub enum VoteImportResult { Ok, RoundConcluded(SignedCommitment, Signature>), - Equivocation, /* TODO: (EquivocationProof, Public, Signature>) */ + Equivocation(EquivocationProof, Public, Signature>), Invalid, Stale, } @@ -149,8 +149,10 @@ where target: LOG_TARGET, "🥩 detected equivocated vote: 1st: {:?}, 2nd: {:?}", previous_vote, vote ); - // TODO: build `EquivocationProof` and return it here. - return VoteImportResult::Equivocation + return VoteImportResult::Equivocation(EquivocationProof { + first: previous_vote.clone(), + second: vote, + }) } } else { // this is the first vote sent by `id` for `num`, all good @@ -197,8 +199,8 @@ mod tests { use sc_network_test::Block; use beefy_primitives::{ - crypto::Public, keyring::Keyring, known_payloads::MMR_ROOT_ID, Commitment, Payload, - SignedCommitment, ValidatorSet, VoteMessage, + crypto::Public, known_payloads::MMR_ROOT_ID, Commitment, EquivocationProof, Keyring, + Payload, SignedCommitment, ValidatorSet, VoteMessage, }; use super::{threshold, Block as BlockT, RoundTracker, Rounds}; @@ -452,4 +454,42 @@ mod tests { rounds.conclude(3); assert!(rounds.previous_votes.is_empty()); } + + #[test] + fn should_provide_equivocation_proof() { + sp_tracing::try_init_simple(); + + let validators = ValidatorSet::::new( + vec![Keyring::Alice.public(), Keyring::Bob.public()], + Default::default(), + ) + .unwrap(); + let validator_set_id = validators.id(); + let session_start = 1u64.into(); + let mut rounds = Rounds::::new(session_start, validators); + + let payload1 = Payload::from_single_entry(MMR_ROOT_ID, vec![1, 1, 1, 1]); + let payload2 = Payload::from_single_entry(MMR_ROOT_ID, vec![2, 2, 2, 2]); + let commitment1 = Commitment { block_number: 1, payload: payload1, validator_set_id }; + let commitment2 = Commitment { block_number: 1, payload: payload2, validator_set_id }; + + let alice_vote1 = VoteMessage { + id: Keyring::Alice.public(), + commitment: commitment1, + signature: Keyring::Alice.sign(b"I am committed"), + }; + let mut alice_vote2 = alice_vote1.clone(); + alice_vote2.commitment = commitment2; + + let expected_result = VoteImportResult::Equivocation(EquivocationProof { + first: alice_vote1.clone(), + second: alice_vote2.clone(), + }); + + // vote on one payload - ok + assert_eq!(rounds.add_vote(alice_vote1), VoteImportResult::Ok); + + // vote on _another_ commitment/payload -> expected equivocation proof + assert_eq!(rounds.add_vote(alice_vote2), expected_result); + } } diff --git a/client/beefy/src/tests.rs b/client/beefy/src/tests.rs index 007c57e4269cf..42f56226ce5af 100644 --- a/client/beefy/src/tests.rs +++ b/client/beefy/src/tests.rs @@ -31,10 +31,10 @@ use crate::{ }; use beefy_primitives::{ crypto::{AuthorityId, Signature}, - keyring::Keyring as BeefyKeyring, known_payloads, mmr::MmrRootProvider, - BeefyApi, Commitment, ConsensusLog, MmrRootHash, Payload, SignedCommitment, ValidatorSet, + BeefyApi, Commitment, ConsensusLog, EquivocationProof, Keyring as BeefyKeyring, MmrRootHash, + OpaqueKeyOwnershipProof, Payload, SignedCommitment, ValidatorSet, ValidatorSetId, VersionedFinalityProof, BEEFY_ENGINE_ID, KEY_TYPE as BeefyKeyType, }; use futures::{future, stream::FuturesUnordered, Future, StreamExt}; @@ -55,7 +55,7 @@ use sp_api::{ApiRef, ProvideRuntimeApi}; use sp_consensus::BlockOrigin; use sp_core::H256; use sp_keystore::{testing::KeyStore as TestKeystore, SyncCryptoStore, SyncCryptoStorePtr}; -use sp_mmr_primitives::{EncodableOpaqueLeaf, Error as MmrError, MmrApi, Proof}; +use sp_mmr_primitives::{Error as MmrError, MmrApi}; use sp_runtime::{ codec::Encode, generic::BlockId, @@ -73,6 +73,7 @@ fn beefy_gossip_proto_name() -> ProtocolName { const GOOD_MMR_ROOT: MmrRootHash = MmrRootHash::repeat_byte(0xbf); const BAD_MMR_ROOT: MmrRootHash = MmrRootHash::repeat_byte(0x42); +const ALTERNATE_BAD_MMR_ROOT: MmrRootHash = MmrRootHash::repeat_byte(0x13); type BeefyBlockImport = crate::BeefyBlockImport< Block, @@ -236,6 +237,8 @@ pub(crate) struct TestApi { pub beefy_genesis: u64, pub validator_set: BeefyValidatorSet, pub mmr_root_hash: MmrRootHash, + pub reported_equivocations: + Option, AuthorityId, Signature>>>>>, } impl TestApi { @@ -244,7 +247,12 @@ impl TestApi { validator_set: &BeefyValidatorSet, mmr_root_hash: MmrRootHash, ) -> Self { - TestApi { beefy_genesis, validator_set: validator_set.clone(), mmr_root_hash } + TestApi { + beefy_genesis, + validator_set: validator_set.clone(), + mmr_root_hash, + reported_equivocations: None, + } } pub fn with_validator_set(validator_set: &BeefyValidatorSet) -> Self { @@ -252,8 +260,13 @@ impl TestApi { beefy_genesis: 1, validator_set: validator_set.clone(), mmr_root_hash: GOOD_MMR_ROOT, + reported_equivocations: None, } } + + pub fn allow_equivocations(&mut self) { + self.reported_equivocations = Some(Arc::new(Mutex::new(vec![]))); + } } // compiler gets confused and warns us about unused inner @@ -277,31 +290,29 @@ sp_api::mock_impl_runtime_apis! { fn validator_set() -> Option { Some(self.inner.validator_set.clone()) } + + fn submit_report_equivocation_unsigned_extrinsic( + proof: EquivocationProof, AuthorityId, Signature>, + _dummy: OpaqueKeyOwnershipProof, + ) -> Option<()> { + if let Some(equivocations_buf) = self.inner.reported_equivocations.as_ref() { + equivocations_buf.lock().push(proof); + None + } else { + panic!("Equivocations not expected, but following proof was reported: {:?}", proof); + } + } + + fn generate_key_ownership_proof( + _dummy1: ValidatorSetId, + _dummy2: AuthorityId, + ) -> Option { Some(OpaqueKeyOwnershipProof::new(vec![])) } } impl MmrApi> for RuntimeApi { fn mmr_root() -> Result { Ok(self.inner.mmr_root_hash) } - - fn generate_proof( - _block_numbers: Vec, - _best_known_block_number: Option - ) -> Result<(Vec, Proof), MmrError> { - unimplemented!() - } - - fn verify_proof(_leaves: Vec, _proof: Proof) -> Result<(), MmrError> { - unimplemented!() - } - - fn verify_proof_stateless( - _root: MmrRootHash, - _leaves: Vec, - _proof: Proof - ) -> Result<(), MmrError> { - unimplemented!() - } } } @@ -330,7 +341,7 @@ pub(crate) fn create_beefy_keystore(authority: BeefyKeyring) -> SyncCryptoStoreP keystore } -fn voter_init_setup( +async fn voter_init_setup( net: &mut BeefyTestNet, finality: &mut futures::stream::Fuse>, api: &TestApi, @@ -345,9 +356,7 @@ fn voter_init_setup( gossip_validator, None, ); - let best_grandpa = - futures::executor::block_on(wait_for_runtime_pallet(api, &mut gossip_engine, finality)) - .unwrap(); + let best_grandpa = wait_for_runtime_pallet(api, &mut gossip_engine, finality).await.unwrap(); load_or_init_voter_state(&*backend, api, best_grandpa, 1) } @@ -980,7 +989,7 @@ async fn should_initialize_voter_at_genesis() { let api = TestApi::with_validator_set(&validator_set); // load persistent state - nothing in DB, should init at genesis - let persisted_state = voter_init_setup(&mut net, &mut finality, &api).unwrap(); + let persisted_state = voter_init_setup(&mut net, &mut finality, &api).await.unwrap(); // Test initialization at session boundary. // verify voter initialized with two sessions starting at blocks 1 and 10 @@ -1029,7 +1038,7 @@ async fn should_initialize_voter_at_custom_genesis() { net.peer(0).client().as_client().finalize_block(hashes[8], None).unwrap(); // load persistent state - nothing in DB, should init at genesis - let persisted_state = voter_init_setup(&mut net, &mut finality, &api).unwrap(); + let persisted_state = voter_init_setup(&mut net, &mut finality, &api).await.unwrap(); // Test initialization at session boundary. // verify voter initialized with single session starting at block `custom_pallet_genesis` (7) @@ -1090,7 +1099,7 @@ async fn should_initialize_voter_when_last_final_is_session_boundary() { let api = TestApi::with_validator_set(&validator_set); // load persistent state - nothing in DB, should init at session boundary - let persisted_state = voter_init_setup(&mut net, &mut finality, &api).unwrap(); + let persisted_state = voter_init_setup(&mut net, &mut finality, &api).await.unwrap(); // verify voter initialized with single session starting at block 10 assert_eq!(persisted_state.voting_oracle().sessions().len(), 1); @@ -1148,7 +1157,7 @@ async fn should_initialize_voter_at_latest_finalized() { let api = TestApi::with_validator_set(&validator_set); // load persistent state - nothing in DB, should init at last BEEFY finalized - let persisted_state = voter_init_setup(&mut net, &mut finality, &api).unwrap(); + let persisted_state = voter_init_setup(&mut net, &mut finality, &api).await.unwrap(); // verify voter initialized with single session starting at block 12 assert_eq!(persisted_state.voting_oracle().sessions().len(), 1); @@ -1205,3 +1214,59 @@ async fn beefy_finalizing_after_pallet_genesis() { // GRANDPA finalize #21 -> BEEFY finalize #20 (mandatory) and #21 finalize_block_and_wait_for_beefy(&net, peers.clone(), &[hashes[21]], &[20, 21]).await; } + +#[tokio::test] +async fn beefy_reports_equivocations() { + sp_tracing::try_init_simple(); + + let peers = [BeefyKeyring::Alice, BeefyKeyring::Bob, BeefyKeyring::Charlie]; + 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(3); + + // Alice votes on good MMR roots, equivocations are allowed/expected. + let mut api_alice = TestApi::with_validator_set(&validator_set); + api_alice.allow_equivocations(); + let api_alice = Arc::new(api_alice); + let alice = (0, &peers[0], api_alice.clone()); + tokio::spawn(initialize_beefy(&mut net, vec![alice], min_block_delta)); + + // Bob votes on bad MMR roots, equivocations are allowed/expected. + let mut api_bob = TestApi::new(1, &validator_set, BAD_MMR_ROOT); + api_bob.allow_equivocations(); + let api_bob = Arc::new(api_bob); + let bob = (1, &peers[1], api_bob.clone()); + tokio::spawn(initialize_beefy(&mut net, vec![bob], min_block_delta)); + + // We spawn another node voting with Bob key, on alternate bad MMR roots (equivocating). + // Equivocations are allowed/expected. + let mut api_bob_prime = TestApi::new(1, &validator_set, ALTERNATE_BAD_MMR_ROOT); + api_bob_prime.allow_equivocations(); + let api_bob_prime = Arc::new(api_bob_prime); + let bob_prime = (2, &BeefyKeyring::Bob, api_bob_prime.clone()); + tokio::spawn(initialize_beefy(&mut net, vec![bob_prime], min_block_delta)); + + // push 42 blocks including `AuthorityChange` digests every 10 blocks. + let hashes = net.generate_blocks_and_sync(42, session_len, &validator_set, false).await; + + let net = Arc::new(Mutex::new(net)); + + // Minimum BEEFY block delta is 4. + + let peers = peers.into_iter().enumerate(); + // finalize block #1 -> BEEFY should not finalize anything (each node votes on different MMR). + finalize_block_and_wait_for_beefy(&net, peers, &[hashes[1]], &[]).await; + + // Verify neither Bob or Bob_Prime report themselves as equivocating. + assert!(api_bob.reported_equivocations.as_ref().unwrap().lock().is_empty()); + assert!(api_bob_prime.reported_equivocations.as_ref().unwrap().lock().is_empty()); + + // Verify Alice reports Bob/Bob_Prime equivocation. + let alice_reported_equivocations = api_alice.reported_equivocations.as_ref().unwrap().lock(); + assert_eq!(alice_reported_equivocations.len(), 1); + let equivocation_proof = alice_reported_equivocations.get(0).unwrap(); + assert_eq!(equivocation_proof.first.id, BeefyKeyring::Bob.public()); + assert_eq!(equivocation_proof.first.commitment.block_number, 1); +} diff --git a/client/beefy/src/worker.rs b/client/beefy/src/worker.rs index 6528aef12508a..8783997cc6b22 100644 --- a/client/beefy/src/worker.rs +++ b/client/beefy/src/worker.rs @@ -23,16 +23,17 @@ use crate::{ }, error::Error, justification::BeefyVersionedFinalityProof, - keystore::BeefyKeystore, + keystore::{BeefyKeystore, BeefySignatureHasher}, metric_get, metric_inc, metric_set, metrics::VoterMetrics, round::{Rounds, VoteImportResult}, BeefyVoterLinks, LOG_TARGET, }; use beefy_primitives::{ + check_equivocation_proof, crypto::{AuthorityId, Signature}, - Commitment, ConsensusLog, PayloadProvider, ValidatorSet, VersionedFinalityProof, VoteMessage, - BEEFY_ENGINE_ID, + BeefyApi, Commitment, ConsensusLog, EquivocationProof, PayloadProvider, ValidatorSet, + VersionedFinalityProof, VoteMessage, BEEFY_ENGINE_ID, }; use codec::{Codec, Decode, Encode}; use futures::{stream::Fuse, FutureExt, StreamExt}; @@ -41,7 +42,7 @@ 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; +use sp_api::{BlockId, ProvideRuntimeApi}; use sp_arithmetic::traits::{AtLeast32Bit, Saturating}; use sp_consensus::SyncOracle; use sp_runtime::{ @@ -243,9 +244,10 @@ impl VoterOracle { } } -pub(crate) struct WorkerParams { +pub(crate) struct WorkerParams { pub backend: Arc, pub payload_provider: P, + pub runtime: Arc, pub network: N, pub key_store: BeefyKeystore, pub gossip_engine: GossipEngine, @@ -294,10 +296,11 @@ impl PersistedState { } /// A BEEFY worker plays the BEEFY protocol -pub(crate) struct BeefyWorker { +pub(crate) struct BeefyWorker { // utilities backend: Arc, payload_provider: P, + runtime: Arc, network: N, key_store: BeefyKeystore, @@ -327,11 +330,13 @@ pub(crate) struct BeefyWorker { persisted_state: PersistedState, } -impl BeefyWorker +impl BeefyWorker where B: Block + Codec, BE: Backend, P: PayloadProvider, + R: ProvideRuntimeApi, + R::Api: BeefyApi, N: NetworkEventStream + NetworkRequest + SyncOracle + Send + Sync + Clone + 'static, { /// Return a new BEEFY worker instance. @@ -340,10 +345,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 { backend, payload_provider, + runtime, key_store, network, gossip_engine, @@ -357,6 +363,7 @@ where BeefyWorker { backend, payload_provider, + runtime, network, key_store, gossip_engine, @@ -571,6 +578,7 @@ where // We created the `finality_proof` and know to be valid. // New state is persisted after finalization. self.finalize(finality_proof)?; + metric_inc!(self, beefy_good_votes_processed); }, VoteImportResult::Ok => { // Persist state after handling mandatory block vote. @@ -583,14 +591,15 @@ where crate::aux_schema::write_voter_state(&*self.backend, &self.persisted_state) .map_err(|e| Error::Backend(e.to_string()))?; } + metric_inc!(self, beefy_good_votes_processed); }, - VoteImportResult::Equivocation => { - // TODO: report returned `EquivocationProof` to chain through `pallet-beefy`. - () + VoteImportResult::Equivocation(proof) => { + metric_inc!(self, beefy_equivocation_votes); + self.report_equivocation(proof)?; }, - VoteImportResult::Invalid | VoteImportResult::Stale => (), + VoteImportResult::Invalid => metric_inc!(self, beefy_invalid_votes), + VoteImportResult::Stale => metric_inc!(self, beefy_stale_votes), }; - metric_inc!(self, beefy_successful_handled_votes); Ok(()) } @@ -928,6 +937,60 @@ where } } } + + /// Report the given equivocation to the BEEFY runtime module. This method + /// generates a session membership proof of the offender and then submits an + /// extrinsic to report the equivocation. In particular, the session membership + /// proof must be generated at the block at which the given set was active which + /// isn't necessarily the best block if there are pending authority set changes. + pub(crate) fn report_equivocation( + &self, + proof: EquivocationProof, AuthorityId, Signature>, + ) -> Result<(), Error> { + let rounds = + self.persisted_state.voting_oracle.active_rounds().ok_or(Error::UninitSession)?; + let (validators, validator_set_id) = (rounds.validators(), rounds.validator_set_id()); + let offender_id = proof.offender_id().clone(); + + if !check_equivocation_proof::<_, _, BeefySignatureHasher>(&proof) { + debug!(target: LOG_TARGET, "🥩 Skip report for bad equivocation {:?}", proof); + return Ok(()) + } else if let Some(local_id) = self.key_store.authority_id(validators) { + if offender_id == local_id { + debug!(target: LOG_TARGET, "🥩 Skip equivocation report for own equivocation"); + return Ok(()) + } + } + + let number = *proof.round_number(); + let runtime_api = self.runtime.runtime_api(); + // generate key ownership proof at that block + let key_owner_proof = match runtime_api + .generate_key_ownership_proof(&BlockId::Number(number), validator_set_id, offender_id) + .map_err(Error::RuntimeApi)? + { + Some(proof) => proof, + None => { + debug!( + target: LOG_TARGET, + "🥩 Equivocation offender not part of the authority set." + ); + return Ok(()) + }, + }; + + // submit equivocation report at **best** block + let best_block_hash = self.backend.blockchain().info().best_hash; + runtime_api + .submit_report_equivocation_unsigned_extrinsic( + &BlockId::Hash(best_block_hash), + proof, + key_owner_proof, + ) + .map_err(Error::RuntimeApi)?; + + Ok(()) + } } /// Scan the `header` digest log for a BEEFY validator set change. Return either the new @@ -993,7 +1056,8 @@ pub(crate) mod tests { BeefyRPCLinks, KnownPeers, }; use beefy_primitives::{ - keyring::Keyring, known_payloads, mmr::MmrRootProvider, Payload, SignedCommitment, + generate_equivocation_proof, known_payloads, known_payloads::MMR_ROOT_ID, + mmr::MmrRootProvider, Keyring, Payload, SignedCommitment, }; use futures::{future::poll_fn, task::Poll}; use parking_lot::Mutex; @@ -1041,6 +1105,7 @@ pub(crate) mod tests { Block, Backend, MmrRootProvider, + TestApi, Arc>, > { let keystore = create_beefy_keystore(*key); @@ -1091,6 +1156,7 @@ pub(crate) mod tests { let worker_params = crate::worker::WorkerParams { backend, payload_provider, + runtime: api, key_store: Some(keystore).into(), links, gossip_engine, @@ -1100,7 +1166,7 @@ pub(crate) mod tests { on_demand_justifications, persisted_state, }; - BeefyWorker::<_, _, _, _>::new(worker_params) + BeefyWorker::<_, _, _, _, _>::new(worker_params) } #[test] @@ -1546,4 +1612,65 @@ 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); } + + #[tokio::test] + async fn should_not_report_bad_old_or_self_equivocations() { + let block_num = 1; + let set_id = 1; + let keys = [Keyring::Alice]; + let validator_set = ValidatorSet::new(make_beefy_ids(&keys), set_id).unwrap(); + // Alice votes on good MMR roots, equivocations are allowed/expected + let mut api_alice = TestApi::with_validator_set(&validator_set); + api_alice.allow_equivocations(); + let api_alice = Arc::new(api_alice); + + let mut net = BeefyTestNet::new(1); + let mut worker = create_beefy_worker(&net.peer(0), &keys[0], 1, validator_set.clone()); + worker.runtime = api_alice.clone(); + + let payload1 = Payload::from_single_entry(MMR_ROOT_ID, vec![42]); + let payload2 = Payload::from_single_entry(MMR_ROOT_ID, vec![128]); + + // generate an equivocation proof, with Bob as perpetrator + let good_proof = generate_equivocation_proof( + (block_num, payload1.clone(), set_id, &Keyring::Bob), + (block_num, payload2.clone(), set_id, &Keyring::Bob), + ); + { + // expect voter (Alice) to successfully report it + assert_eq!(worker.report_equivocation(good_proof.clone()), Ok(())); + // verify Alice reports Bob equivocation to runtime + let reported = api_alice.reported_equivocations.as_ref().unwrap().lock(); + assert_eq!(reported.len(), 1); + assert_eq!(*reported.get(0).unwrap(), good_proof); + } + api_alice.reported_equivocations.as_ref().unwrap().lock().clear(); + + // now let's try with a bad proof + let mut bad_proof = good_proof.clone(); + bad_proof.first.id = Keyring::Charlie.public(); + // bad proofs are simply ignored + assert_eq!(worker.report_equivocation(bad_proof), Ok(())); + // verify nothing reported to runtime + assert!(api_alice.reported_equivocations.as_ref().unwrap().lock().is_empty()); + + // now let's try with old set it + let mut old_proof = good_proof.clone(); + old_proof.first.commitment.validator_set_id = 0; + old_proof.second.commitment.validator_set_id = 0; + // old proofs are simply ignored + assert_eq!(worker.report_equivocation(old_proof), Ok(())); + // verify nothing reported to runtime + assert!(api_alice.reported_equivocations.as_ref().unwrap().lock().is_empty()); + + // now let's try reporting a self-equivocation + let self_proof = generate_equivocation_proof( + (block_num, payload1.clone(), set_id, &Keyring::Alice), + (block_num, payload2.clone(), set_id, &Keyring::Alice), + ); + // equivocations done by 'self' are simply ignored (not reported) + assert_eq!(worker.report_equivocation(self_proof), Ok(())); + // verify nothing reported to runtime + assert!(api_alice.reported_equivocations.as_ref().unwrap().lock().is_empty()); + } } diff --git a/client/consensus/babe/src/lib.rs b/client/consensus/babe/src/lib.rs index 99b29986ec8fc..403792249e8df 100644 --- a/client/consensus/babe/src/lib.rs +++ b/client/consensus/babe/src/lib.rs @@ -1086,7 +1086,7 @@ where .map_err(|e| Error::Client(e.into()))?; // generate a key ownership proof. we start by trying to generate the - // key owernship proof at the parent of the equivocating header, this + // key ownership proof at the parent of the equivocating header, this // will make sure that proof generation is successful since it happens // during the on-going session (i.e. session keys are available in the // state to be able to generate the proof). this might fail if the diff --git a/frame/beefy-mmr/src/lib.rs b/frame/beefy-mmr/src/lib.rs index e5506ecd01d6e..eb030b71ddec6 100644 --- a/frame/beefy-mmr/src/lib.rs +++ b/frame/beefy-mmr/src/lib.rs @@ -23,8 +23,8 @@ //! 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 pallet provides a standardized MMR Leaf format that 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. diff --git a/frame/beefy-mmr/src/mock.rs b/frame/beefy-mmr/src/mock.rs index 2de71cd5b320a..de6fa135286b9 100644 --- a/frame/beefy-mmr/src/mock.rs +++ b/frame/beefy-mmr/src/mock.rs @@ -22,10 +22,10 @@ use codec::Encode; use frame_support::{ construct_runtime, parameter_types, sp_io::TestExternalities, - traits::{ConstU16, ConstU32, ConstU64, GenesisBuild}, + traits::{ConstU16, ConstU32, ConstU64, GenesisBuild, KeyOwnerProofSystem}, BasicExternalities, }; -use sp_core::{Hasher, H256}; +use sp_core::{crypto::KeyTypeId, Hasher, H256}; use sp_runtime::{ app_crypto::ecdsa::Public, impl_opaque_keys, @@ -124,8 +124,17 @@ impl pallet_mmr::Config for Test { impl pallet_beefy::Config for Test { type BeefyId = BeefyId; + type KeyOwnerProofSystem = (); + type KeyOwnerProof = + >::Proof; + type KeyOwnerIdentification = >::IdentificationTuple; + type HandleEquivocation = (); type MaxAuthorities = ConstU32<100>; type OnNewValidatorSet = BeefyMmr; + type WeightInfo = (); } parameter_types! { diff --git a/frame/beefy/Cargo.toml b/frame/beefy/Cargo.toml index 4db8c05682840..b2d6635377571 100644 --- a/frame/beefy/Cargo.toml +++ b/frame/beefy/Cargo.toml @@ -15,11 +15,20 @@ serde = { version = "1.0.136", optional = true } 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-authorship = { version = "4.0.0-dev", default-features = false, path = "../authorship" } pallet-session = { version = "4.0.0-dev", default-features = false, path = "../session" } 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 = "5.0.0", default-features = false, path = "../../primitives/std" } [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" } +pallet-timestamp = { version = "4.0.0-dev", path = "../timestamp" } 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" } @@ -31,10 +40,13 @@ std = [ "codec/std", "frame-support/std", "frame-system/std", + "pallet-authorship/std", "pallet-session/std", "scale-info/std", "serde", "sp-runtime/std", + "sp-session/std", + "sp-staking/std", "sp-std/std", ] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/beefy/src/default_weights.rs b/frame/beefy/src/default_weights.rs new file mode 100644 index 0000000000000..0b642cb45e9ce --- /dev/null +++ b/frame/beefy/src/default_weights.rs @@ -0,0 +1,54 @@ +// This file is part of Substrate. + +// Copyright (C) 2020-2023 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Default weights for the BEEFY Pallet +//! This file was not auto-generated. + +use frame_support::weights::{ + constants::{RocksDbWeight as DbWeight, WEIGHT_REF_TIME_PER_MICROS, WEIGHT_REF_TIME_PER_NANOS}, + Weight, +}; + +impl crate::WeightInfo for () { + fn report_equivocation(validator_count: u32) -> Weight { + // we take the validator set count from the membership proof to + // calculate the weight but we set a floor of 100 validators. + let validator_count = validator_count.max(100) as u64; + + // worst case we are considering is that the given offender is backed by 200 nominators + const MAX_NOMINATORS: u64 = 200; + + // checking membership proof + 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(Weight::from_ref_time(95u64 * WEIGHT_REF_TIME_PER_MICROS)) + // report offence + .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 + .saturating_add(DbWeight::get().reads(2)) + } +} diff --git a/frame/beefy/src/equivocation.rs b/frame/beefy/src/equivocation.rs new file mode 100644 index 0000000000000..ea6a9f9122351 --- /dev/null +++ b/frame/beefy/src/equivocation.rs @@ -0,0 +1,385 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2023 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! An opt-in utility module for reporting equivocations. +//! +//! This module defines an offence type for BEEFY equivocations +//! and some utility traits to wire together: +//! - a key ownership proof system (e.g. to prove that a given authority was part of a session); +//! - a system for reporting offences; +//! - a system for signing and submitting transactions; +//! - a way to get the current block author; +//! +//! These can be used in an offchain context in order to submit equivocation +//! reporting extrinsics (from the client that's running the BEEFY protocol). +//! And in a runtime context, so that the BEEFY pallet can validate the +//! equivocation proofs in the extrinsic and report the offences. +//! +//! IMPORTANT: +//! When using this module for enabling equivocation reporting it is required +//! that the `ValidateUnsigned` for the BEEFY pallet is used in the runtime +//! definition. + +use sp_std::prelude::*; + +use beefy_primitives::{EquivocationProof, ValidatorSetId}; +use codec::{self as codec, Decode, Encode}; +use frame_support::{ + log, + traits::{Get, KeyOwnerProofSystem}, +}; +use frame_system::pallet_prelude::BlockNumberFor; +use sp_runtime::{ + transaction_validity::{ + InvalidTransaction, TransactionPriority, TransactionSource, TransactionValidity, + TransactionValidityError, ValidTransaction, + }, + DispatchResult, Perbill, RuntimeAppPublic, +}; +use sp_staking::{ + offence::{Kind, Offence, OffenceError, ReportOffence}, + SessionIndex, +}; + +use super::{Call, Config, Pallet, LOG_TARGET}; + +/// A trait with utility methods for handling equivocation reports in BEEFY. +/// The offence type is generic, and the trait provides, reporting an offence +/// triggered by a valid equivocation report, and also for creating and +/// submitting equivocation report extrinsics (useful only in offchain context). +pub trait HandleEquivocation { + /// The offence type used for reporting offences on valid equivocation reports. + type Offence: BeefyOffence, T::KeyOwnerIdentification>; + + /// The longevity, in blocks, that the equivocation report is valid for. When using the staking + /// pallet this should be equal to the bonding duration (in blocks, not eras). + type ReportLongevity: Get; + + /// Report an offence proved by the given reporters. + fn report_offence( + reporters: Vec, + offence: Self::Offence, + ) -> Result<(), OffenceError>; + + /// Returns true if all of the offenders at the given time slot have already been reported. + fn is_known_offence( + offenders: &[T::KeyOwnerIdentification], + time_slot: &>::TimeSlot, + ) -> bool; + + /// Create and dispatch an equivocation report extrinsic. + fn submit_unsigned_equivocation_report( + equivocation_proof: EquivocationProof< + BlockNumberFor, + T::BeefyId, + ::Signature, + >, + key_owner_proof: T::KeyOwnerProof, + ) -> DispatchResult; + + /// Fetch the current block author id, if defined. + fn block_author() -> Option; +} + +impl HandleEquivocation for () { + type Offence = BeefyEquivocationOffence, T::KeyOwnerIdentification>; + type ReportLongevity = (); + + fn report_offence( + _reporters: Vec, + _offence: BeefyEquivocationOffence, T::KeyOwnerIdentification>, + ) -> Result<(), OffenceError> { + Ok(()) + } + + fn is_known_offence( + _offenders: &[T::KeyOwnerIdentification], + _time_slot: &BeefyTimeSlot>, + ) -> bool { + true + } + + fn submit_unsigned_equivocation_report( + _equivocation_proof: EquivocationProof< + BlockNumberFor, + T::BeefyId, + ::Signature, + >, + _key_owner_proof: T::KeyOwnerProof, + ) -> DispatchResult { + Ok(()) + } + + fn block_author() -> Option { + None + } +} + +/// Generic equivocation handler. This type implements `HandleEquivocation` +/// using existing subsystems that are part of frame (type bounds described +/// below) and will dispatch to them directly, it's only purpose is to wire all +/// subsystems together. +pub struct EquivocationHandler> { + _phantom: sp_std::marker::PhantomData<(N, I, R, L, O)>, +} + +impl Default for EquivocationHandler { + fn default() -> Self { + Self { _phantom: Default::default() } + } +} + +impl HandleEquivocation + for EquivocationHandler, T::KeyOwnerIdentification, R, L, O> +where + // We use the authorship pallet to fetch the current block author and use + // `offchain::SendTransactionTypes` for unsigned extrinsic creation and + // submission. + T: Config + pallet_authorship::Config + frame_system::offchain::SendTransactionTypes>, + // A system for reporting offences after valid equivocation reports are + // processed. + R: ReportOffence, + // The longevity (in blocks) that the equivocation report is valid for. When using the staking + // pallet this should be the bonding duration. + L: Get, + // The offence type that should be used when reporting. + O: BeefyOffence, T::KeyOwnerIdentification>, +{ + type Offence = O; + type ReportLongevity = L; + + fn report_offence(reporters: Vec, offence: O) -> Result<(), OffenceError> { + R::report_offence(reporters, offence) + } + + fn is_known_offence(offenders: &[T::KeyOwnerIdentification], time_slot: &O::TimeSlot) -> bool { + R::is_known_offence(offenders, time_slot) + } + + fn submit_unsigned_equivocation_report( + equivocation_proof: EquivocationProof< + BlockNumberFor, + T::BeefyId, + ::Signature, + >, + key_owner_proof: T::KeyOwnerProof, + ) -> DispatchResult { + use frame_system::offchain::SubmitTransaction; + + let call = Call::report_equivocation_unsigned { + equivocation_proof: Box::new(equivocation_proof), + key_owner_proof, + }; + + match SubmitTransaction::>::submit_unsigned_transaction(call.into()) { + Ok(()) => log::info!(target: LOG_TARGET, "Submitted BEEFY equivocation report.",), + Err(e) => + log::error!(target: LOG_TARGET, "Error submitting equivocation report: {:?}", e,), + } + + Ok(()) + } + + fn block_author() -> Option { + >::author() + } +} + +/// A round number and set id which point on the time of an offence. +#[derive(Copy, Clone, PartialOrd, Ord, Eq, PartialEq, Encode, Decode)] +pub struct BeefyTimeSlot { + // The order of these matters for `derive(Ord)`. + /// BEEFY Set ID. + pub set_id: ValidatorSetId, + /// Round number. + pub round: N, +} + +/// Methods for the `ValidateUnsigned` implementation: +/// It restricts calls to `report_equivocation_unsigned` to local calls (i.e. extrinsics generated +/// on this node) or that already in a block. This guarantees that only block authors can include +/// unsigned equivocation reports. +impl Pallet { + pub fn validate_unsigned(source: TransactionSource, call: &Call) -> TransactionValidity { + if let Call::report_equivocation_unsigned { equivocation_proof, key_owner_proof } = call { + // discard equivocation report not coming from the local node + match source { + TransactionSource::Local | TransactionSource::InBlock => { /* allowed */ }, + _ => { + log::warn!( + target: LOG_TARGET, + "rejecting unsigned report equivocation transaction because it is not local/in-block." + ); + return InvalidTransaction::Call.into() + }, + } + + // check report staleness + is_known_offence::(equivocation_proof, key_owner_proof)?; + + let longevity = + >::ReportLongevity::get(); + + ValidTransaction::with_tag_prefix("BeefyEquivocation") + // We assign the maximum priority for any equivocation report. + .priority(TransactionPriority::MAX) + // Only one equivocation report for the same offender at the same slot. + .and_provides(( + equivocation_proof.offender_id().clone(), + equivocation_proof.set_id(), + *equivocation_proof.round_number(), + )) + .longevity(longevity) + // We don't propagate this. This can never be included on a remote node. + .propagate(false) + .build() + } else { + InvalidTransaction::Call.into() + } + } + + pub fn pre_dispatch(call: &Call) -> Result<(), TransactionValidityError> { + if let Call::report_equivocation_unsigned { equivocation_proof, key_owner_proof } = call { + is_known_offence::(equivocation_proof, key_owner_proof) + } else { + Err(InvalidTransaction::Call.into()) + } + } +} + +fn is_known_offence( + equivocation_proof: &EquivocationProof< + BlockNumberFor, + T::BeefyId, + ::Signature, + >, + key_owner_proof: &T::KeyOwnerProof, +) -> Result<(), TransactionValidityError> { + // check the membership proof to extract the offender's id, + // equivocation validity will be fully checked during the call. + let key = (beefy_primitives::KEY_TYPE, equivocation_proof.offender_id().clone()); + + let offender = T::KeyOwnerProofSystem::check_proof(key, key_owner_proof.clone()) + .ok_or(InvalidTransaction::BadProof)?; + + // check if the offence has already been reported, + // and if so then we can discard the report. + let time_slot = >::Offence::new_time_slot( + equivocation_proof.set_id(), + *equivocation_proof.round_number(), + ); + + let is_known_offence = T::HandleEquivocation::is_known_offence(&[offender], &time_slot); + + if is_known_offence { + Err(InvalidTransaction::Stale.into()) + } else { + Ok(()) + } +} + +/// A BEEFY equivocation offence report. +pub struct BeefyEquivocationOffence +where + N: Copy + Clone + PartialOrd + Ord + Eq + PartialEq + Encode + Decode, +{ + /// Time slot at which this incident happened. + pub time_slot: BeefyTimeSlot, + /// The session index in which the incident happened. + pub session_index: SessionIndex, + /// The size of the validator set at the time of the offence. + pub validator_set_count: u32, + /// The authority which produced this equivocation. + pub offender: FullIdentification, +} + +/// An interface for types that will be used as BEEFY offences and must also +/// implement the `Offence` trait. This trait provides a constructor that is +/// provided all available data during processing of BEEFY equivocations. +pub trait BeefyOffence: Offence +where + N: Copy + Clone + PartialOrd + Ord + Eq + PartialEq + Encode + Decode, +{ + /// Create a new BEEFY offence using the given equivocation details. + fn new( + session_index: SessionIndex, + validator_set_count: u32, + offender: FullIdentification, + set_id: ValidatorSetId, + round: N, + ) -> Self; + + /// Create a new BEEFY offence time slot. + fn new_time_slot(set_id: ValidatorSetId, round: N) -> Self::TimeSlot; +} + +impl BeefyOffence + for BeefyEquivocationOffence +where + N: Copy + Clone + PartialOrd + Ord + Eq + PartialEq + Encode + Decode, +{ + fn new( + session_index: SessionIndex, + validator_set_count: u32, + offender: FullIdentification, + set_id: ValidatorSetId, + round: N, + ) -> Self { + BeefyEquivocationOffence { + session_index, + validator_set_count, + offender, + time_slot: BeefyTimeSlot { set_id, round }, + } + } + + fn new_time_slot(set_id: ValidatorSetId, round: N) -> Self::TimeSlot { + BeefyTimeSlot { set_id, round } + } +} + +impl Offence + for BeefyEquivocationOffence +where + N: Copy + Clone + PartialOrd + Ord + Eq + PartialEq + Encode + Decode, +{ + const ID: Kind = *b"beefy:equivocati"; + type TimeSlot = BeefyTimeSlot; + + fn offenders(&self) -> Vec { + vec![self.offender.clone()] + } + + fn session_index(&self) -> SessionIndex { + self.session_index + } + + fn validator_set_count(&self) -> u32 { + self.validator_set_count + } + + fn time_slot(&self) -> Self::TimeSlot { + self.time_slot + } + + fn slash_fraction(&self, offenders_count: u32) -> Perbill { + // the formula is min((3k / n)^2, 1) + let x = Perbill::from_rational(3 * offenders_count, self.validator_set_count); + // _ ^ 2 + x.square() + } +} diff --git a/frame/beefy/src/lib.rs b/frame/beefy/src/lib.rs index 86c8763a51dd3..d29440457f5bf 100644 --- a/frame/beefy/src/lib.rs +++ b/frame/beefy/src/lib.rs @@ -20,35 +20,48 @@ use codec::{Encode, MaxEncodedLen}; use frame_support::{ + dispatch::{DispatchResultWithPostInfo, Pays}, log, - traits::{Get, OneSessionHandler}, + pallet_prelude::*, + traits::{Get, KeyOwnerProofSystem, OneSessionHandler}, + weights::Weight, BoundedSlice, BoundedVec, Parameter, }; - +use frame_system::{ + ensure_none, ensure_signed, + pallet_prelude::{BlockNumberFor, OriginFor}, +}; use sp_runtime::{ generic::DigestItem, traits::{IsMember, Member}, - RuntimeAppPublic, + KeyTypeId, RuntimeAppPublic, }; +use sp_session::{GetSessionNumber, GetValidatorCount}; +use sp_staking::SessionIndex; use sp_std::prelude::*; use beefy_primitives::{ - AuthorityIndex, ConsensusLog, OnNewValidatorSet, ValidatorSet, BEEFY_ENGINE_ID, - GENESIS_AUTHORITY_SET_ID, + AuthorityIndex, BeefyAuthorityId, ConsensusLog, EquivocationProof, OnNewValidatorSet, + ValidatorSet, BEEFY_ENGINE_ID, GENESIS_AUTHORITY_SET_ID, }; +mod default_weights; +mod equivocation; #[cfg(test)] mod mock; - #[cfg(test)] mod tests; +pub use crate::equivocation::{ + BeefyEquivocationOffence, BeefyOffence, BeefyTimeSlot, EquivocationHandler, HandleEquivocation, +}; pub use pallet::*; +const LOG_TARGET: &str = "runtime::beefy"; + #[frame_support::pallet] pub mod pallet { use super::*; - use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::BlockNumberFor; #[pallet::config] @@ -56,10 +69,35 @@ pub mod pallet { /// Authority identifier type type BeefyId: Member + Parameter - + RuntimeAppPublic + // todo: use custom signature hashing type instead of hardcoded `Keccak256` + + BeefyAuthorityId + MaybeSerializeDeserialize + MaxEncodedLen; + /// A system for proving ownership of keys, i.e. that a given key was part + /// of a validator set, needed for validating equivocation reports. + type KeyOwnerProofSystem: KeyOwnerProofSystem< + (KeyTypeId, Self::BeefyId), + Proof = Self::KeyOwnerProof, + IdentificationTuple = Self::KeyOwnerIdentification, + >; + + /// The proof of key ownership, used for validating equivocation reports + /// The proof must include the session index and validator count of the + /// session at which the equivocation occurred. + type KeyOwnerProof: Parameter + GetSessionNumber + GetValidatorCount; + + /// The identification of a key owner, used when reporting equivocations. + type KeyOwnerIdentification: Parameter; + + /// The equivocation handling subsystem, defines methods to report an + /// offence (after the equivocation has been validated) and for submitting a + /// transaction to report an equivocation (from an offchain context). + /// NOTE: when enabling equivocation handling (i.e. this type isn't set to + /// `()`) you must use this pallet's `ValidateUnsigned` in the runtime + /// definition. + type HandleEquivocation: HandleEquivocation; + /// The maximum number of authorities that can be added. type MaxAuthorities: Get; @@ -69,6 +107,9 @@ pub mod pallet { /// 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>; + + /// Weights for this pallet. + type WeightInfo: WeightInfo; } #[pallet::pallet] @@ -92,6 +133,15 @@ pub mod pallet { pub(super) type NextAuthorities = StorageValue<_, BoundedVec, ValueQuery>; + /// A mapping from BEEFY set ID to the index of the *most recent* session for which its + /// members were responsible. + /// + /// TWOX-NOTE: `ValidatorSetId` is not under user control. + #[pallet::storage] + #[pallet::getter(fn session_for_set)] + pub(super) type SetIdSession = + StorageMap<_, Twox64Concat, beefy_primitives::ValidatorSetId, SessionIndex>; + /// Block number where BEEFY consensus is enabled/started. /// If changing this, make sure `Self::ValidatorSetId` is also reset to /// `GENESIS_AUTHORITY_SET_ID` in the state of the new block number configured here. @@ -124,13 +174,90 @@ pub mod pallet { #[pallet::genesis_build] impl GenesisBuild for GenesisConfig { fn build(&self) { - Pallet::::initialize_authorities(&self.authorities) + Pallet::::initialize(&self.authorities) // we panic here as runtime maintainers can simply reconfigure genesis and restart // the chain easily .expect("Authorities vec too big"); >::put(&self.genesis_block); } } + + #[pallet::error] + pub enum Error { + /// A key ownership proof provided as part of an equivocation report is invalid. + InvalidKeyOwnershipProof, + /// An equivocation proof provided as part of an equivocation report is invalid. + InvalidEquivocationProof, + /// A given equivocation report is valid but already previously reported. + DuplicateOffenceReport, + } + + #[pallet::call] + impl Pallet { + /// Report voter equivocation/misbehavior. This method will verify 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(T::WeightInfo::report_equivocation(key_owner_proof.validator_count()))] + pub fn report_equivocation( + origin: OriginFor, + equivocation_proof: Box< + EquivocationProof< + BlockNumberFor, + T::BeefyId, + ::Signature, + >, + >, + key_owner_proof: T::KeyOwnerProof, + ) -> DispatchResultWithPostInfo { + let reporter = ensure_signed(origin)?; + + Self::do_report_equivocation(Some(reporter), *equivocation_proof, key_owner_proof) + } + + /// Report voter equivocation/misbehavior. This method will verify the + /// equivocation proof and validate the given key ownership proof + /// against the extracted offender. If both are valid, the offence + /// will be reported. + /// + /// This extrinsic must be called unsigned and it is expected that only + /// 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, + equivocation_proof: Box< + EquivocationProof< + BlockNumberFor, + T::BeefyId, + ::Signature, + >, + >, + key_owner_proof: T::KeyOwnerProof, + ) -> DispatchResultWithPostInfo { + ensure_none(origin)?; + + Self::do_report_equivocation( + T::HandleEquivocation::block_author(), + *equivocation_proof, + key_owner_proof, + ) + } + } + + #[pallet::validate_unsigned] + impl ValidateUnsigned for Pallet { + type Call = Call; + fn pre_dispatch(call: &Self::Call) -> Result<(), TransactionValidityError> { + Self::pre_dispatch(call) + } + fn validate_unsigned(source: TransactionSource, call: &Self::Call) -> TransactionValidity { + Self::validate_unsigned(source, call) + } + } } impl Pallet { @@ -141,6 +268,24 @@ impl Pallet { ValidatorSet::::new(validators, id) } + /// Submits an extrinsic to report an equivocation. This method will create + /// an unsigned extrinsic with a call to `report_equivocation_unsigned` and + /// will push the transaction to the pool. Only useful in an offchain context. + pub fn submit_unsigned_equivocation_report( + equivocation_proof: EquivocationProof< + BlockNumberFor, + T::BeefyId, + ::Signature, + >, + key_owner_proof: T::KeyOwnerProof, + ) -> Option<()> { + T::HandleEquivocation::submit_unsigned_equivocation_report( + equivocation_proof, + key_owner_proof, + ) + .ok() + } + fn change_authorities( new: BoundedVec, queued: BoundedVec, @@ -169,7 +314,7 @@ impl Pallet { } } - fn initialize_authorities(authorities: &Vec) -> Result<(), ()> { + fn initialize(authorities: &Vec) -> Result<(), ()> { if authorities.is_empty() { return Ok(()) } @@ -199,15 +344,80 @@ impl Pallet { ); } } + + // NOTE: initialize first session of first set. this is necessary for + // the genesis set and session since we only update the set -> session + // mapping whenever a new session starts, i.e. through `on_new_session`. + SetIdSession::::insert(0, 0); + Ok(()) } + + fn do_report_equivocation( + reporter: Option, + equivocation_proof: EquivocationProof< + BlockNumberFor, + T::BeefyId, + ::Signature, + >, + key_owner_proof: T::KeyOwnerProof, + ) -> DispatchResultWithPostInfo { + // We check the equivocation within the context of its set id (and + // associated session) and round. We also need to know the validator + // set count at the time of the offence since it is required to calculate + // the slash amount. + let set_id = equivocation_proof.set_id(); + let round = *equivocation_proof.round_number(); + let offender_id = equivocation_proof.offender_id().clone(); + let session_index = key_owner_proof.session(); + let validator_count = key_owner_proof.validator_count(); + + // validate the key ownership proof extracting the id of the offender. + let offender = T::KeyOwnerProofSystem::check_proof( + (beefy_primitives::KEY_TYPE, offender_id), + key_owner_proof, + ) + .ok_or(Error::::InvalidKeyOwnershipProof)?; + + // validate equivocation proof (check votes are different and signatures are valid). + if !beefy_primitives::check_equivocation_proof(&equivocation_proof) { + return Err(Error::::InvalidEquivocationProof.into()) + } + + // check that the session id for the membership proof is within the + // bounds of the set id reported in the equivocation. + let set_id_session_index = + Self::session_for_set(set_id).ok_or(Error::::InvalidEquivocationProof)?; + if session_index != set_id_session_index { + return Err(Error::::InvalidEquivocationProof.into()) + } + + // report to the offences module rewarding the sender. + T::HandleEquivocation::report_offence( + reporter.into_iter().collect(), + >::Offence::new( + session_index, + validator_count, + offender, + set_id, + round, + ), + ) + .map_err(|_| Error::::DuplicateOffenceReport)?; + + // waive the fee since the report is valid and beneficial + Ok(Pays::No.into()) + } } impl sp_runtime::BoundToRuntimeAppPublic for Pallet { type Public = T::BeefyId; } -impl OneSessionHandler for Pallet { +impl OneSessionHandler for Pallet +where + T: pallet_session::Config, +{ type Key = T::BeefyId; fn on_genesis_session<'a, I: 'a>(validators: I) @@ -217,7 +427,7 @@ impl OneSessionHandler for Pallet { let authorities = validators.map(|(_, k)| k).collect::>(); // we panic here as runtime maintainers can simply reconfigure genesis and restart the // chain easily - Self::initialize_authorities(&authorities).expect("Authorities vec too big"); + Self::initialize(&authorities).expect("Authorities vec too big"); } fn on_new_session<'a, I: 'a>(_changed: bool, validators: I, queued_validators: I) @@ -227,9 +437,10 @@ impl OneSessionHandler for Pallet { let next_authorities = validators.map(|(_, k)| k).collect::>(); if next_authorities.len() as u32 > T::MaxAuthorities::get() { log::error!( - target: "runtime::beefy", + target: LOG_TARGET, "authorities list {:?} truncated to length {}", - next_authorities, T::MaxAuthorities::get(), + next_authorities, + T::MaxAuthorities::get(), ); } let bounded_next_authorities = @@ -238,9 +449,10 @@ impl OneSessionHandler for Pallet { 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", + target: LOG_TARGET, "queued authorities list {:?} truncated to length {}", - next_queued_authorities, T::MaxAuthorities::get(), + next_queued_authorities, + T::MaxAuthorities::get(), ); } let bounded_next_queued_authorities = @@ -249,6 +461,10 @@ impl OneSessionHandler for Pallet { // 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(bounded_next_authorities, bounded_next_queued_authorities); + + // Update the mapping for the new set id that corresponds to the latest session (i.e. now). + let session_index = >::current_index(); + SetIdSession::::insert(Self::validator_set_id(), &session_index); } fn on_disabled(i: u32) { @@ -266,3 +482,7 @@ impl IsMember for Pallet { Self::authorities().iter().any(|id| id == authority_id) } } + +pub trait WeightInfo { + fn report_equivocation(validator_count: u32) -> Weight; +} diff --git a/frame/beefy/src/mock.rs b/frame/beefy/src/mock.rs index ad3a672333dd5..8d8b831950d8e 100644 --- a/frame/beefy/src/mock.rs +++ b/frame/beefy/src/mock.rs @@ -17,24 +17,33 @@ use std::vec; +use frame_election_provider_support::{onchain, SequentialPhragmen}; use frame_support::{ construct_runtime, parameter_types, sp_io::TestExternalities, - traits::{ConstU16, ConstU32, ConstU64, GenesisBuild}, + traits::{ + ConstU16, ConstU32, ConstU64, GenesisBuild, KeyOwnerProofSystem, OnFinalize, OnInitialize, + }, BasicExternalities, }; -use sp_core::H256; +use pallet_session::historical as pallet_session_historical; +use sp_core::{crypto::KeyTypeId, ConstU128, H256}; use sp_runtime::{ app_crypto::ecdsa::Public, + curve::PiecewiseLinear, impl_opaque_keys, - testing::Header, - traits::{BlakeTwo256, ConvertInto, IdentityLookup, OpaqueKeys}, + testing::{Header, TestXt}, + traits::{BlakeTwo256, IdentityLookup, OpaqueKeys}, Perbill, }; +use sp_staking::{EraIndex, SessionIndex}; use crate as pallet_beefy; -pub use beefy_primitives::{crypto::AuthorityId as BeefyId, ConsensusLog, BEEFY_ENGINE_ID}; +pub use beefy_primitives::{ + crypto::{AuthorityId as BeefyId, AuthoritySignature as BeefySignature}, + ConsensusLog, EquivocationProof, BEEFY_ENGINE_ID, +}; impl_opaque_keys! { pub struct MockSessionKeys { @@ -51,9 +60,15 @@ construct_runtime!( NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic, { - System: frame_system::{Pallet, Call, Config, Storage, Event}, - Beefy: pallet_beefy::{Pallet, Config, Storage}, - Session: pallet_session::{Pallet, Call, Storage, Event, Config}, + System: frame_system, + Authorship: pallet_authorship, + Timestamp: pallet_timestamp, + Balances: pallet_balances, + Beefy: pallet_beefy, + Staking: pallet_staking, + Session: pallet_session, + Offences: pallet_offences, + Historical: pallet_session_historical, } ); @@ -75,7 +90,7 @@ impl frame_system::Config for Test { type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; - type AccountData = (); + type AccountData = pallet_balances::AccountData; type OnNewAccount = (); type OnKilledAccount = (); type SystemWeightInfo = (); @@ -84,10 +99,34 @@ impl frame_system::Config for Test { type MaxConsumers = ConstU32<16>; } +impl frame_system::offchain::SendTransactionTypes for Test +where + RuntimeCall: From, +{ + type OverarchingCall = RuntimeCall; + type Extrinsic = TestXt; +} + +parameter_types! { + pub const Period: u64 = 1; + pub const ReportLongevity: u64 = + BondingDuration::get() as u64 * SessionsPerEra::get() as u64 * Period::get(); +} + impl pallet_beefy::Config for Test { type BeefyId = BeefyId; + type KeyOwnerProofSystem = Historical; + type KeyOwnerProof = + >::Proof; + type KeyOwnerIdentification = >::IdentificationTuple; + type HandleEquivocation = + super::EquivocationHandler; type MaxAuthorities = ConstU32<100>; type OnNewValidatorSet = (); + type WeightInfo = (); } parameter_types! { @@ -97,29 +136,107 @@ parameter_types! { impl pallet_session::Config for Test { type RuntimeEvent = RuntimeEvent; type ValidatorId = u64; - type ValidatorIdOf = ConvertInto; + type ValidatorIdOf = pallet_staking::StashOf; type ShouldEndSession = pallet_session::PeriodicSessions, ConstU64<0>>; type NextSessionRotation = pallet_session::PeriodicSessions, ConstU64<0>>; - type SessionManager = MockSessionManager; + type SessionManager = pallet_session::historical::NoteHistoricalRoot; type SessionHandler = ::KeyTypeIdProviders; type Keys = MockSessionKeys; type WeightInfo = (); } -pub struct MockSessionManager; +impl pallet_session::historical::Config for Test { + type FullIdentification = pallet_staking::Exposure; + type FullIdentificationOf = pallet_staking::ExposureOf; +} -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 - } - } +impl pallet_authorship::Config for Test { + type FindAuthor = (); + type EventHandler = (); +} + +impl pallet_balances::Config for Test { + type MaxLocks = (); + type MaxReserves = (); + type ReserveIdentifier = [u8; 8]; + type Balance = u128; + type DustRemoval = (); + type RuntimeEvent = RuntimeEvent; + type ExistentialDeposit = ConstU128<1>; + type AccountStore = System; + type WeightInfo = (); +} + +impl pallet_timestamp::Config for Test { + type Moment = u64; + type OnTimestampSet = (); + type MinimumPeriod = ConstU64<3>; + 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, + ); +} + +parameter_types! { + pub const SessionsPerEra: SessionIndex = 3; + pub const BondingDuration: EraIndex = 3; + pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE; + pub const OffendingValidatorsThreshold: Perbill = Perbill::from_percent(17); +} + +pub struct OnChainSeqPhragmen; +impl onchain::Config for OnChainSeqPhragmen { + type System = Test; + 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 { + type MaxNominations = ConstU32<16>; + type RewardRemainder = (); + type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote; + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type CurrencyBalance = ::Balance; + type Slash = (); + type Reward = (); + type SessionsPerEra = SessionsPerEra; + type BondingDuration = BondingDuration; + type SlashDeferDuration = (); + type AdminOrigin = frame_system::EnsureRoot; + type SessionInterface = Self; + type UnixTime = pallet_timestamp::Pallet; + type EraPayout = pallet_staking::ConvertCurve; + type MaxNominatorRewardedPerValidator = ConstU32<64>; + type OffendingValidatorsThreshold = OffendingValidatorsThreshold; + type NextNewSession = Session; + type ElectionProvider = onchain::OnChainExecution; + type GenesisElectionProvider = Self::ElectionProvider; + 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 = (); +} + +impl pallet_offences::Config for Test { + type RuntimeEvent = RuntimeEvent; + type IdentificationTuple = pallet_session::historical::IdentificationTuple; + type OnOffenceHandler = Staking; } // Note, that we can't use `UintAuthorityId` here. Reason is that the implementation @@ -134,20 +251,27 @@ pub fn mock_beefy_id(id: u8) -> BeefyId { 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 mock_authorities(vec: Vec) -> Vec { + vec.into_iter().map(|id| 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 { +pub fn new_test_ext_raw_authorities(authorities: Vec) -> TestExternalities { let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); + let balances: Vec<_> = (0..authorities.len()).map(|i| (i as u64, 10_000_000)).collect(); + + pallet_balances::GenesisConfig:: { balances } + .assimilate_storage(&mut t) + .unwrap(); + let session_keys: Vec<_> = authorities .iter() - .map(|id| (id.0 as u64, id.0 as u64, MockSessionKeys { dummy: id.1.clone() })) + .enumerate() + .map(|(i, k)| (i as u64, i as u64, MockSessionKeys { dummy: k.clone() })) .collect(); BasicExternalities::execute_with_storage(&mut t, || { @@ -160,5 +284,56 @@ pub fn new_test_ext_raw_authorities(authorities: Vec<(u64, BeefyId)>) -> TestExt .assimilate_storage(&mut t) .unwrap(); + // controllers are the index + 1000 + let stakers: Vec<_> = (0..authorities.len()) + .map(|i| { + (i as u64, i as u64 + 1000, 10_000, pallet_staking::StakerStatus::::Validator) + }) + .collect(); + + let staking_config = pallet_staking::GenesisConfig:: { + stakers, + validator_count: 2, + force_era: pallet_staking::Forcing::ForceNew, + minimum_validator_count: 0, + invulnerables: vec![], + ..Default::default() + }; + + staking_config.assimilate_storage(&mut t).unwrap(); + t.into() } + +pub fn start_session(session_index: SessionIndex) { + for i in Session::current_index()..session_index { + System::on_finalize(System::block_number()); + Session::on_finalize(System::block_number()); + Staking::on_finalize(System::block_number()); + Beefy::on_finalize(System::block_number()); + + let parent_hash = if System::block_number() > 1 { + let hdr = System::finalize(); + hdr.hash() + } else { + System::parent_hash() + }; + + 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); + + System::on_initialize(System::block_number()); + Session::on_initialize(System::block_number()); + Staking::on_initialize(System::block_number()); + Beefy::on_initialize(System::block_number()); + } + + assert_eq!(Session::current_index(), session_index); +} + +pub fn start_era(era_index: EraIndex) { + start_session((era_index * 3).into()); + assert_eq!(Staking::current_era(), Some(era_index)); +} diff --git a/frame/beefy/src/tests.rs b/frame/beefy/src/tests.rs index 4136b0c1f1ecf..a92f90b6107bc 100644 --- a/frame/beefy/src/tests.rs +++ b/frame/beefy/src/tests.rs @@ -17,14 +17,21 @@ use std::vec; -use beefy_primitives::ValidatorSet; +use beefy_primitives::{ + check_equivocation_proof, generate_equivocation_proof, known_payloads::MMR_ROOT_ID, + Keyring as BeefyKeyring, Payload, ValidatorSet, +}; use codec::Encode; use sp_runtime::DigestItem; -use frame_support::traits::OnInitialize; +use frame_support::{ + assert_err, assert_ok, + dispatch::{GetDispatchInfo, Pays}, + traits::{Currency, KeyOwnerProofSystem, OnInitialize}, +}; -use crate::mock::*; +use crate::{mock::*, Call, Config, Error, Weight, WeightInfo}; fn init_block(block: u64) { System::set_block_number(block); @@ -37,12 +44,13 @@ pub fn beefy_log(log: ConsensusLog) -> DigestItem { #[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)]; + let authorities = mock_authorities(vec![1, 2, 3, 4]); + let want = authorities.clone(); - new_test_ext(vec![1, 2, 3, 4]).execute_with(|| { + new_test_ext_raw_authorities(authorities).execute_with(|| { let authorities = Beefy::authorities(); - assert!(authorities.len() == 2); + assert_eq!(authorities.len(), 4); assert_eq!(want[0], authorities[0]); assert_eq!(want[1], authorities[1]); @@ -50,7 +58,7 @@ fn genesis_session_initializes_authorities() { let next_authorities = Beefy::next_authorities(); - assert!(next_authorities.len() == 2); + assert_eq!(next_authorities.len(), 4); assert_eq!(want[0], next_authorities[0]); assert_eq!(want[1], next_authorities[1]); }); @@ -58,6 +66,9 @@ fn genesis_session_initializes_authorities() { #[test] fn session_change_updates_authorities() { + let authorities = mock_authorities(vec![1, 2, 3, 4]); + let want_validators = authorities.clone(); + new_test_ext(vec![1, 2, 3, 4]).execute_with(|| { assert!(0 == Beefy::validator_set_id()); @@ -66,7 +77,7 @@ fn session_change_updates_authorities() { assert!(1 == Beefy::validator_set_id()); let want = beefy_log(ConsensusLog::AuthoritiesChange( - ValidatorSet::new(vec![mock_beefy_id(1), mock_beefy_id(2)], 1).unwrap(), + ValidatorSet::new(want_validators, 1).unwrap(), )); let log = System::digest().logs[0].clone(); @@ -77,7 +88,7 @@ fn session_change_updates_authorities() { 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(), + ValidatorSet::new(vec![mock_beefy_id(2), mock_beefy_id(4)], 2).unwrap(), )); let log = System::digest().logs[1].clone(); @@ -92,16 +103,18 @@ fn session_change_updates_next_authorities() { new_test_ext(vec![1, 2, 3, 4]).execute_with(|| { let next_authorities = Beefy::next_authorities(); - assert!(next_authorities.len() == 2); + assert_eq!(next_authorities.len(), 4); assert_eq!(want[0], next_authorities[0]); assert_eq!(want[1], next_authorities[1]); + assert_eq!(want[2], next_authorities[2]); + assert_eq!(want[3], next_authorities[3]); init_block(1); let next_authorities = Beefy::next_authorities(); - assert!(next_authorities.len() == 2); - assert_eq!(want[2], next_authorities[0]); + assert_eq!(next_authorities.len(), 2); + assert_eq!(want[1], next_authorities[0]); assert_eq!(want[3], next_authorities[1]); }); } @@ -126,6 +139,10 @@ fn validator_set_updates_work() { new_test_ext(vec![1, 2, 3, 4]).execute_with(|| { 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!(want[2], vs.validators()[2]); + assert_eq!(want[3], vs.validators()[3]); init_block(1); @@ -140,7 +157,611 @@ fn validator_set_updates_work() { let vs = Beefy::validator_set().unwrap(); assert_eq!(vs.id(), 2u64); - assert_eq!(want[2], vs.validators()[0]); + assert_eq!(want[1], vs.validators()[0]); assert_eq!(want[3], vs.validators()[1]); }); } + +/// Returns a list with 3 authorities with known keys: +/// Alice, Bob and Charlie. +pub fn test_authorities() -> Vec { + let authorities = vec![BeefyKeyring::Alice, BeefyKeyring::Bob, BeefyKeyring::Charlie]; + authorities.into_iter().map(|id| id.public()).collect() +} + +#[test] +fn should_sign_and_verify() { + use sp_runtime::traits::Keccak256; + + let set_id = 3; + let payload1 = Payload::from_single_entry(MMR_ROOT_ID, vec![42]); + let payload2 = Payload::from_single_entry(MMR_ROOT_ID, vec![128]); + + // generate an equivocation proof, with two votes in the same round for + // same payload signed by the same key + let equivocation_proof = generate_equivocation_proof( + (1, payload1.clone(), set_id, &BeefyKeyring::Bob), + (1, payload1.clone(), set_id, &BeefyKeyring::Bob), + ); + // expect invalid equivocation proof + assert!(!check_equivocation_proof::<_, _, Keccak256>(&equivocation_proof)); + + // generate an equivocation proof, with two votes in different rounds for + // different payloads signed by the same key + let equivocation_proof = generate_equivocation_proof( + (1, payload1.clone(), set_id, &BeefyKeyring::Bob), + (2, payload2.clone(), set_id, &BeefyKeyring::Bob), + ); + // expect invalid equivocation proof + assert!(!check_equivocation_proof::<_, _, Keccak256>(&equivocation_proof)); + + // generate an equivocation proof, with two votes by different authorities + let equivocation_proof = generate_equivocation_proof( + (1, payload1.clone(), set_id, &BeefyKeyring::Alice), + (1, payload2.clone(), set_id, &BeefyKeyring::Bob), + ); + // expect invalid equivocation proof + assert!(!check_equivocation_proof::<_, _, Keccak256>(&equivocation_proof)); + + // generate an equivocation proof, with two votes in different set ids + let equivocation_proof = generate_equivocation_proof( + (1, payload1.clone(), set_id, &BeefyKeyring::Bob), + (1, payload2.clone(), set_id + 1, &BeefyKeyring::Bob), + ); + // expect invalid equivocation proof + assert!(!check_equivocation_proof::<_, _, Keccak256>(&equivocation_proof)); + + // generate an equivocation proof, with two votes in the same round for + // different payloads signed by the same key + let payload2 = Payload::from_single_entry(MMR_ROOT_ID, vec![128]); + let equivocation_proof = generate_equivocation_proof( + (1, payload1, set_id, &BeefyKeyring::Bob), + (1, payload2, set_id, &BeefyKeyring::Bob), + ); + // expect valid equivocation proof + assert!(check_equivocation_proof::<_, _, Keccak256>(&equivocation_proof)); +} + +#[test] +fn report_equivocation_current_set_works() { + let authorities = test_authorities(); + + new_test_ext_raw_authorities(authorities).execute_with(|| { + assert_eq!(Staking::current_era(), Some(0)); + assert_eq!(Session::current_index(), 0); + + start_era(1); + + let block_num = System::block_number(); + let validator_set = Beefy::validator_set().unwrap(); + let authorities = validator_set.validators(); + let set_id = validator_set.id(); + let validators = Session::validators(); + + // make sure that all validators have the same balance + for validator in &validators { + assert_eq!(Balances::total_balance(validator), 10_000_000); + assert_eq!(Staking::slashable_balance_of(validator), 10_000); + + assert_eq!( + Staking::eras_stakers(1, validator), + pallet_staking::Exposure { total: 10_000, own: 10_000, others: vec![] }, + ); + } + + assert_eq!(authorities.len(), 2); + let equivocation_authority_index = 1; + let equivocation_key = &authorities[equivocation_authority_index]; + let equivocation_keyring = BeefyKeyring::from_public(equivocation_key).unwrap(); + + let payload1 = Payload::from_single_entry(MMR_ROOT_ID, vec![42]); + let payload2 = Payload::from_single_entry(MMR_ROOT_ID, vec![128]); + // generate an equivocation proof, with two votes in the same round for + // different payloads signed by the same key + let equivocation_proof = generate_equivocation_proof( + (block_num, payload1, set_id, &equivocation_keyring), + (block_num, payload2, set_id, &equivocation_keyring), + ); + + // create the key ownership proof + let key_owner_proof = + Historical::prove((beefy_primitives::KEY_TYPE, &equivocation_key)).unwrap(); + + // report the equivocation and the tx should be dispatched successfully + assert_ok!(Beefy::report_equivocation_unsigned( + RuntimeOrigin::none(), + Box::new(equivocation_proof), + key_owner_proof, + ),); + + start_era(2); + + // check that the balance of 0-th validator is slashed 100%. + let equivocation_validator_id = validators[equivocation_authority_index]; + + assert_eq!(Balances::total_balance(&equivocation_validator_id), 10_000_000 - 10_000); + assert_eq!(Staking::slashable_balance_of(&equivocation_validator_id), 0); + assert_eq!( + Staking::eras_stakers(2, equivocation_validator_id), + pallet_staking::Exposure { total: 0, own: 0, others: vec![] }, + ); + + // check that the balances of all other validators are left intact. + for validator in &validators { + if *validator == equivocation_validator_id { + continue + } + + assert_eq!(Balances::total_balance(validator), 10_000_000); + assert_eq!(Staking::slashable_balance_of(validator), 10_000); + + assert_eq!( + Staking::eras_stakers(2, validator), + pallet_staking::Exposure { total: 10_000, own: 10_000, others: vec![] }, + ); + } + }); +} + +#[test] +fn report_equivocation_old_set_works() { + let authorities = test_authorities(); + + new_test_ext_raw_authorities(authorities).execute_with(|| { + start_era(1); + + let block_num = System::block_number(); + let validator_set = Beefy::validator_set().unwrap(); + let authorities = validator_set.validators(); + let validators = Session::validators(); + let old_set_id = validator_set.id(); + + assert_eq!(authorities.len(), 2); + let equivocation_authority_index = 0; + let equivocation_key = &authorities[equivocation_authority_index]; + + // create the key ownership proof in the "old" set + let key_owner_proof = + Historical::prove((beefy_primitives::KEY_TYPE, &equivocation_key)).unwrap(); + + start_era(2); + + // make sure that all authorities have the same balance + for validator in &validators { + assert_eq!(Balances::total_balance(validator), 10_000_000); + assert_eq!(Staking::slashable_balance_of(validator), 10_000); + + assert_eq!( + Staking::eras_stakers(2, validator), + pallet_staking::Exposure { total: 10_000, own: 10_000, others: vec![] }, + ); + } + + let validator_set = Beefy::validator_set().unwrap(); + let new_set_id = validator_set.id(); + assert_eq!(old_set_id + 3, new_set_id); + + let equivocation_keyring = BeefyKeyring::from_public(equivocation_key).unwrap(); + + let payload1 = Payload::from_single_entry(MMR_ROOT_ID, vec![42]); + let payload2 = Payload::from_single_entry(MMR_ROOT_ID, vec![128]); + // generate an equivocation proof for the old set, + let equivocation_proof = generate_equivocation_proof( + (block_num, payload1, old_set_id, &equivocation_keyring), + (block_num, payload2, old_set_id, &equivocation_keyring), + ); + + // report the equivocation and the tx should be dispatched successfully + assert_ok!(Beefy::report_equivocation_unsigned( + RuntimeOrigin::none(), + Box::new(equivocation_proof), + key_owner_proof, + ),); + + start_era(3); + + // check that the balance of 0-th validator is slashed 100%. + let equivocation_validator_id = validators[equivocation_authority_index]; + + assert_eq!(Balances::total_balance(&equivocation_validator_id), 10_000_000 - 10_000); + assert_eq!(Staking::slashable_balance_of(&equivocation_validator_id), 0); + assert_eq!( + Staking::eras_stakers(3, equivocation_validator_id), + pallet_staking::Exposure { total: 0, own: 0, others: vec![] }, + ); + + // check that the balances of all other validators are left intact. + for validator in &validators { + if *validator == equivocation_validator_id { + continue + } + + assert_eq!(Balances::total_balance(validator), 10_000_000); + assert_eq!(Staking::slashable_balance_of(validator), 10_000); + + assert_eq!( + Staking::eras_stakers(3, validator), + pallet_staking::Exposure { total: 10_000, own: 10_000, others: vec![] }, + ); + } + }); +} + +#[test] +fn report_equivocation_invalid_set_id() { + let authorities = test_authorities(); + + new_test_ext_raw_authorities(authorities).execute_with(|| { + start_era(1); + + let block_num = System::block_number(); + let validator_set = Beefy::validator_set().unwrap(); + let authorities = validator_set.validators(); + let set_id = validator_set.id(); + + let equivocation_authority_index = 0; + let equivocation_key = &authorities[equivocation_authority_index]; + let equivocation_keyring = BeefyKeyring::from_public(equivocation_key).unwrap(); + + let key_owner_proof = + Historical::prove((beefy_primitives::KEY_TYPE, &equivocation_key)).unwrap(); + + let payload1 = Payload::from_single_entry(MMR_ROOT_ID, vec![42]); + let payload2 = Payload::from_single_entry(MMR_ROOT_ID, vec![128]); + // generate an equivocation for a future set + let equivocation_proof = generate_equivocation_proof( + (block_num, payload1, set_id + 1, &equivocation_keyring), + (block_num, payload2, set_id + 1, &equivocation_keyring), + ); + + // the call for reporting the equivocation should error + assert_err!( + Beefy::report_equivocation_unsigned( + RuntimeOrigin::none(), + Box::new(equivocation_proof), + key_owner_proof, + ), + Error::::InvalidEquivocationProof, + ); + }); +} + +#[test] +fn report_equivocation_invalid_session() { + let authorities = test_authorities(); + + new_test_ext_raw_authorities(authorities).execute_with(|| { + start_era(1); + + let block_num = System::block_number(); + let validator_set = Beefy::validator_set().unwrap(); + let authorities = validator_set.validators(); + + let equivocation_authority_index = 0; + let equivocation_key = &authorities[equivocation_authority_index]; + let equivocation_keyring = BeefyKeyring::from_public(equivocation_key).unwrap(); + + // generate a key ownership proof at current era set id + let key_owner_proof = + Historical::prove((beefy_primitives::KEY_TYPE, &equivocation_key)).unwrap(); + + start_era(2); + + let set_id = Beefy::validator_set().unwrap().id(); + + let payload1 = Payload::from_single_entry(MMR_ROOT_ID, vec![42]); + let payload2 = Payload::from_single_entry(MMR_ROOT_ID, vec![128]); + // generate an equivocation proof at following era set id = 2 + let equivocation_proof = generate_equivocation_proof( + (block_num, payload1, set_id, &equivocation_keyring), + (block_num, payload2, set_id, &equivocation_keyring), + ); + + // report an equivocation for the current set using an key ownership + // proof from the previous set, the session should be invalid. + assert_err!( + Beefy::report_equivocation_unsigned( + RuntimeOrigin::none(), + Box::new(equivocation_proof), + key_owner_proof, + ), + Error::::InvalidEquivocationProof, + ); + }); +} + +#[test] +fn report_equivocation_invalid_key_owner_proof() { + let authorities = test_authorities(); + + new_test_ext_raw_authorities(authorities).execute_with(|| { + start_era(1); + + let block_num = System::block_number(); + let validator_set = Beefy::validator_set().unwrap(); + let authorities = validator_set.validators(); + let set_id = validator_set.id(); + + let invalid_owner_authority_index = 1; + let invalid_owner_key = &authorities[invalid_owner_authority_index]; + + // generate a key ownership proof for the authority at index 1 + let invalid_key_owner_proof = + Historical::prove((beefy_primitives::KEY_TYPE, &invalid_owner_key)).unwrap(); + + let equivocation_authority_index = 0; + let equivocation_key = &authorities[equivocation_authority_index]; + let equivocation_keyring = BeefyKeyring::from_public(equivocation_key).unwrap(); + + let payload1 = Payload::from_single_entry(MMR_ROOT_ID, vec![42]); + let payload2 = Payload::from_single_entry(MMR_ROOT_ID, vec![128]); + // generate an equivocation proof for the authority at index 0 + let equivocation_proof = generate_equivocation_proof( + (block_num, payload1, set_id + 1, &equivocation_keyring), + (block_num, payload2, set_id + 1, &equivocation_keyring), + ); + + // we need to start a new era otherwise the key ownership proof won't be + // checked since the authorities are part of the current session + start_era(2); + + // report an equivocation for the current set using a key ownership + // proof for a different key than the one in the equivocation proof. + assert_err!( + Beefy::report_equivocation_unsigned( + RuntimeOrigin::none(), + Box::new(equivocation_proof), + invalid_key_owner_proof, + ), + Error::::InvalidKeyOwnershipProof, + ); + }); +} + +#[test] +fn report_equivocation_invalid_equivocation_proof() { + let authorities = test_authorities(); + + new_test_ext_raw_authorities(authorities).execute_with(|| { + start_era(1); + + let block_num = System::block_number(); + let validator_set = Beefy::validator_set().unwrap(); + let authorities = validator_set.validators(); + let set_id = validator_set.id(); + + let equivocation_authority_index = 0; + let equivocation_key = &authorities[equivocation_authority_index]; + let equivocation_keyring = BeefyKeyring::from_public(equivocation_key).unwrap(); + + // generate a key ownership proof at set id in era 1 + let key_owner_proof = + Historical::prove((beefy_primitives::KEY_TYPE, &equivocation_key)).unwrap(); + + let assert_invalid_equivocation_proof = |equivocation_proof| { + assert_err!( + Beefy::report_equivocation_unsigned( + RuntimeOrigin::none(), + Box::new(equivocation_proof), + key_owner_proof.clone(), + ), + Error::::InvalidEquivocationProof, + ); + }; + + start_era(2); + + let payload1 = Payload::from_single_entry(MMR_ROOT_ID, vec![42]); + let payload2 = Payload::from_single_entry(MMR_ROOT_ID, vec![128]); + + // both votes target the same block number and payload, + // there is no equivocation. + assert_invalid_equivocation_proof(generate_equivocation_proof( + (block_num, payload1.clone(), set_id, &equivocation_keyring), + (block_num, payload1.clone(), set_id, &equivocation_keyring), + )); + + // votes targeting different rounds, there is no equivocation. + assert_invalid_equivocation_proof(generate_equivocation_proof( + (block_num, payload1.clone(), set_id, &equivocation_keyring), + (block_num + 1, payload2.clone(), set_id, &equivocation_keyring), + )); + + // votes signed with different authority keys + assert_invalid_equivocation_proof(generate_equivocation_proof( + (block_num, payload1.clone(), set_id, &equivocation_keyring), + (block_num, payload1.clone(), set_id, &BeefyKeyring::Charlie), + )); + + // votes signed with a key that isn't part of the authority set + assert_invalid_equivocation_proof(generate_equivocation_proof( + (block_num, payload1.clone(), set_id, &equivocation_keyring), + (block_num, payload1.clone(), set_id, &BeefyKeyring::Dave), + )); + + // votes targeting different set ids + assert_invalid_equivocation_proof(generate_equivocation_proof( + (block_num, payload1, set_id, &equivocation_keyring), + (block_num, payload2, set_id + 1, &equivocation_keyring), + )); + }); +} + +#[test] +fn report_equivocation_validate_unsigned_prevents_duplicates() { + use sp_runtime::transaction_validity::{ + InvalidTransaction, TransactionPriority, TransactionSource, TransactionValidity, + ValidTransaction, + }; + + let authorities = test_authorities(); + + new_test_ext_raw_authorities(authorities).execute_with(|| { + start_era(1); + + let block_num = System::block_number(); + let validator_set = Beefy::validator_set().unwrap(); + let authorities = validator_set.validators(); + let set_id = validator_set.id(); + + // generate and report an equivocation for the validator at index 0 + let equivocation_authority_index = 0; + let equivocation_key = &authorities[equivocation_authority_index]; + let equivocation_keyring = BeefyKeyring::from_public(equivocation_key).unwrap(); + + let payload1 = Payload::from_single_entry(MMR_ROOT_ID, vec![42]); + let payload2 = Payload::from_single_entry(MMR_ROOT_ID, vec![128]); + let equivocation_proof = generate_equivocation_proof( + (block_num, payload1, set_id, &equivocation_keyring), + (block_num, payload2, set_id, &equivocation_keyring), + ); + + let key_owner_proof = + Historical::prove((beefy_primitives::KEY_TYPE, &equivocation_key)).unwrap(); + + let call = Call::report_equivocation_unsigned { + equivocation_proof: Box::new(equivocation_proof.clone()), + key_owner_proof: key_owner_proof.clone(), + }; + + // only local/inblock reports are allowed + assert_eq!( + ::validate_unsigned( + TransactionSource::External, + &call, + ), + InvalidTransaction::Call.into(), + ); + + // the transaction is valid when passed as local + let tx_tag = (equivocation_key, set_id, 3u64); + + assert_eq!( + ::validate_unsigned( + TransactionSource::Local, + &call, + ), + TransactionValidity::Ok(ValidTransaction { + priority: TransactionPriority::max_value(), + requires: vec![], + provides: vec![("BeefyEquivocation", tx_tag).encode()], + longevity: ReportLongevity::get(), + propagate: false, + }) + ); + + // the pre dispatch checks should also pass + assert_ok!(::pre_dispatch(&call)); + + // we submit the report + Beefy::report_equivocation_unsigned( + RuntimeOrigin::none(), + Box::new(equivocation_proof), + key_owner_proof, + ) + .unwrap(); + + // the report should now be considered stale and the transaction is invalid + // the check for staleness should be done on both `validate_unsigned` and on `pre_dispatch` + assert_err!( + ::validate_unsigned( + TransactionSource::Local, + &call, + ), + InvalidTransaction::Stale, + ); + + assert_err!( + ::pre_dispatch(&call), + InvalidTransaction::Stale, + ); + }); +} + +#[test] +fn report_equivocation_has_valid_weight() { + // the weight depends on the size of the validator set, + // but there's a lower bound of 100 validators. + assert!((1..=100) + .map(::WeightInfo::report_equivocation) + .collect::>() + .windows(2) + .all(|w| w[0] == w[1])); + + // after 100 validators the weight should keep increasing + // with every extra validator. + assert!((100..=1000) + .map(::WeightInfo::report_equivocation) + .collect::>() + .windows(2) + .all(|w| w[0].ref_time() < w[1].ref_time())); +} + +#[test] +fn valid_equivocation_reports_dont_pay_fees() { + let authorities = test_authorities(); + + new_test_ext_raw_authorities(authorities).execute_with(|| { + start_era(1); + + let block_num = System::block_number(); + let validator_set = Beefy::validator_set().unwrap(); + let authorities = validator_set.validators(); + let set_id = validator_set.id(); + + let equivocation_authority_index = 0; + let equivocation_key = &authorities[equivocation_authority_index]; + let equivocation_keyring = BeefyKeyring::from_public(equivocation_key).unwrap(); + + // generate equivocation proof + let payload1 = Payload::from_single_entry(MMR_ROOT_ID, vec![42]); + let payload2 = Payload::from_single_entry(MMR_ROOT_ID, vec![128]); + let equivocation_proof = generate_equivocation_proof( + (block_num, payload1, set_id, &equivocation_keyring), + (block_num, payload2, set_id, &equivocation_keyring), + ); + + // create the key ownership proof. + let key_owner_proof = + Historical::prove((beefy_primitives::KEY_TYPE, &equivocation_key)).unwrap(); + + // check the dispatch info for the call. + let info = Call::::report_equivocation_unsigned { + equivocation_proof: Box::new(equivocation_proof.clone()), + key_owner_proof: key_owner_proof.clone(), + } + .get_dispatch_info(); + + // it should have non-zero weight and the fee has to be paid. + assert!(info.weight.any_gt(Weight::zero())); + assert_eq!(info.pays_fee, Pays::Yes); + + // report the equivocation. + let post_info = Beefy::report_equivocation_unsigned( + RuntimeOrigin::none(), + Box::new(equivocation_proof.clone()), + key_owner_proof.clone(), + ) + .unwrap(); + + // the original weight should be kept, but given that the report + // is valid the fee is waived. + assert!(post_info.actual_weight.is_none()); + assert_eq!(post_info.pays_fee, Pays::No); + + // report the equivocation again which is invalid now since it is + // duplicate. + let post_info = Beefy::report_equivocation_unsigned( + RuntimeOrigin::none(), + Box::new(equivocation_proof), + key_owner_proof, + ) + .err() + .unwrap() + .post_info; + + // the fee is not waived and the original weight is kept. + assert!(post_info.actual_weight.is_none()); + assert_eq!(post_info.pays_fee, Pays::Yes); + }) +} diff --git a/primitives/beefy/src/lib.rs b/primitives/beefy/src/lib.rs index 08467a723b704..ad9c1b8d1432a 100644 --- a/primitives/beefy/src/lib.rs +++ b/primitives/beefy/src/lib.rs @@ -34,10 +34,14 @@ mod commitment; pub mod mmr; mod payload; +#[cfg(feature = "std")] +mod test_utils; pub mod witness; pub use commitment::{Commitment, SignedCommitment, VersionedFinalityProof}; pub use payload::{known_payloads, BeefyPayloadId, Payload, PayloadProvider}; +#[cfg(feature = "std")] +pub use test_utils::*; use codec::{Codec, Decode, Encode}; use scale_info::TypeInfo; @@ -183,6 +187,83 @@ pub struct VoteMessage { pub signature: Signature, } +/// Proof of voter misbehavior on a given set id. Misbehavior/equivocation in +/// BEEFY happens when a voter votes on the same round/block for different payloads. +/// Proving is achieved by collecting the signed commitments of conflicting votes. +#[derive(Clone, Debug, Decode, Encode, PartialEq, TypeInfo)] +pub struct EquivocationProof { + /// The first vote in the equivocation. + pub first: VoteMessage, + /// The second vote in the equivocation. + pub second: VoteMessage, +} + +impl EquivocationProof { + /// Returns the authority id of the equivocator. + pub fn offender_id(&self) -> &Id { + &self.first.id + } + /// Returns the round number at which the equivocation occurred. + pub fn round_number(&self) -> &Number { + &self.first.commitment.block_number + } + /// Returns the set id at which the equivocation occurred. + pub fn set_id(&self) -> ValidatorSetId { + self.first.commitment.validator_set_id + } +} + +/// Check a commitment signature by encoding the commitment and +/// verifying the provided signature using the expected authority id. +pub fn check_commitment_signature( + commitment: &Commitment, + authority_id: &Id, + signature: &::Signature, +) -> bool +where + Id: BeefyAuthorityId, + Number: Clone + Encode + PartialEq, + MsgHash: Hash, +{ + let encoded_commitment = commitment.encode(); + BeefyAuthorityId::::verify(authority_id, signature, &encoded_commitment) +} + +/// Verifies the equivocation proof by making sure that both votes target +/// different blocks and that its signatures are valid. +pub fn check_equivocation_proof( + report: &EquivocationProof::Signature>, +) -> bool +where + Id: BeefyAuthorityId + PartialEq, + Number: Clone + Encode + PartialEq, + MsgHash: Hash, +{ + let first = &report.first; + let second = &report.second; + + // if votes + // come from different authorities, + // are for different rounds, + // have different validator set ids, + // or both votes have the same commitment, + // --> the equivocation is invalid. + if first.id != second.id || + first.commitment.block_number != second.commitment.block_number || + first.commitment.validator_set_id != second.commitment.validator_set_id || + first.commitment.payload == second.commitment.payload + { + return false + } + + // check signatures on both votes are valid + let valid_first = check_commitment_signature(&first.commitment, &first.id, &first.signature); + let valid_second = + check_commitment_signature(&second.commitment, &second.id, &second.signature); + + return valid_first && valid_second +} + /// New BEEFY validator set notification hook. pub trait OnNewValidatorSet { /// Function called by the pallet when BEEFY validator set changes. @@ -197,6 +278,28 @@ impl OnNewValidatorSet for () { fn on_new_validator_set(_: &ValidatorSet, _: &ValidatorSet) {} } +/// An opaque type used to represent the key ownership proof at the runtime API +/// boundary. The inner value is an encoded representation of the actual key +/// ownership proof which will be parameterized when defining the runtime. At +/// the runtime API boundary this type is unknown and as such we keep this +/// opaque representation, implementors of the runtime API will have to make +/// sure that all usages of `OpaqueKeyOwnershipProof` refer to the same type. +#[derive(Decode, Encode, PartialEq)] +pub struct OpaqueKeyOwnershipProof(Vec); +impl OpaqueKeyOwnershipProof { + /// Create a new `OpaqueKeyOwnershipProof` using the given encoded + /// representation. + pub fn new(inner: Vec) -> OpaqueKeyOwnershipProof { + OpaqueKeyOwnershipProof(inner) + } + + /// Try to decode this `OpaqueKeyOwnershipProof` into the given concrete key + /// ownership proof type. + pub fn decode(self) -> Option { + codec::Decode::decode(&mut &self.0[..]).ok() + } +} + sp_api::decl_runtime_apis! { /// API necessary for BEEFY voters. pub trait BeefyApi @@ -206,83 +309,36 @@ sp_api::decl_runtime_apis! { /// Return the current active BEEFY validator set fn validator_set() -> Option>; - } -} -#[cfg(feature = "std")] -/// Test accounts using [`crate::crypto`] types. -pub mod keyring { - use super::*; - use sp_core::{ecdsa, keccak_256, Pair}; - use std::collections::HashMap; - use strum::IntoEnumIterator; - - /// Set of test accounts using [`crate::crypto`] types. - #[allow(missing_docs)] - #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, strum::Display, strum::EnumIter)] - pub enum Keyring { - Alice, - Bob, - Charlie, - Dave, - Eve, - Ferdie, - One, - Two, - } - - impl Keyring { - /// Sign `msg`. - pub fn sign(self, msg: &[u8]) -> crypto::Signature { - // todo: use custom signature hashing type - 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) - } - - /// Get Keyring from public key. - pub fn from_public(who: &crypto::Public) -> Option { - Self::iter().find(|&k| &crypto::Public::from(k) == who) - } - } - - lazy_static::lazy_static! { - static ref PRIVATE_KEYS: HashMap = - Keyring::iter().map(|i| (i, i.pair())).collect(); - static ref PUBLIC_KEYS: HashMap = - PRIVATE_KEYS.iter().map(|(&name, pair)| (name, pair.public())).collect(); - } - - 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() - } - } - - impl From for crypto::Public { - fn from(k: Keyring) -> Self { - (*PUBLIC_KEYS).get(&k).cloned().unwrap() - } + /// Submits an unsigned extrinsic to report an equivocation. The caller + /// must provide the equivocation proof and a key ownership proof + /// (should be obtained using `generate_key_ownership_proof`). The + /// extrinsic will be unsigned and should only be accepted for local + /// authorship (not to be broadcast to the network). This method returns + /// `None` when creation of the extrinsic fails, e.g. if equivocation + /// reporting is disabled for the given runtime (i.e. this method is + /// hardcoded to return `None`). Only useful in an offchain context. + fn submit_report_equivocation_unsigned_extrinsic( + equivocation_proof: + EquivocationProof, crypto::AuthorityId, crypto::Signature>, + key_owner_proof: OpaqueKeyOwnershipProof, + ) -> Option<()>; + + /// Generates a proof of key ownership for the given authority in the + /// given set. An example usage of this module is coupled with the + /// session historical module to prove that a given authority key is + /// tied to a given staking identity during a specific session. Proofs + /// of key ownership are necessary for submitting equivocation reports. + /// NOTE: even though the API takes a `set_id` as parameter the current + /// implementations ignores this parameter and instead relies on this + /// method being called at the correct block height, i.e. any point at + /// which the given set id is live on-chain. Future implementations will + /// instead use indexed data through an offchain worker, not requiring + /// older states to be available. + fn generate_key_ownership_proof( + set_id: ValidatorSetId, + authority_id: crypto::AuthorityId, + ) -> Option; } } diff --git a/primitives/beefy/src/test_utils.rs b/primitives/beefy/src/test_utils.rs new file mode 100644 index 0000000000000..1a5e03be33fb4 --- /dev/null +++ b/primitives/beefy/src/test_utils.rs @@ -0,0 +1,110 @@ +// This file is part of Substrate. + +// Copyright (C) 2021-2023 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#![cfg(feature = "std")] + +use crate::{crypto, Commitment, EquivocationProof, Payload, ValidatorSetId, VoteMessage}; +use codec::Encode; +use sp_core::{ecdsa, keccak_256, Pair}; +use std::collections::HashMap; +use strum::IntoEnumIterator; + +/// Set of test accounts using [`crate::crypto`] types. +#[allow(missing_docs)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, strum::Display, strum::EnumIter)] +pub enum Keyring { + Alice, + Bob, + Charlie, + Dave, + Eve, + Ferdie, + One, + Two, +} + +impl Keyring { + /// Sign `msg`. + pub fn sign(self, msg: &[u8]) -> crypto::Signature { + // todo: use custom signature hashing type + 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) + } + + /// Get Keyring from public key. + pub fn from_public(who: &crypto::Public) -> Option { + Self::iter().find(|&k| &crypto::Public::from(k) == who) + } +} + +lazy_static::lazy_static! { + static ref PRIVATE_KEYS: HashMap = + Keyring::iter().map(|i| (i, i.pair())).collect(); + static ref PUBLIC_KEYS: HashMap = + PRIVATE_KEYS.iter().map(|(&name, pair)| (name, pair.public())).collect(); +} + +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() + } +} + +impl From for crypto::Public { + fn from(k: Keyring) -> Self { + (*PUBLIC_KEYS).get(&k).cloned().unwrap() + } +} + +/// Create a new `EquivocationProof` based on given arguments. +pub fn generate_equivocation_proof( + vote1: (u64, Payload, ValidatorSetId, &Keyring), + vote2: (u64, Payload, ValidatorSetId, &Keyring), +) -> EquivocationProof { + let signed_vote = |block_number: u64, + payload: Payload, + validator_set_id: ValidatorSetId, + keyring: &Keyring| { + let commitment = Commitment { validator_set_id, block_number, payload }; + let signature = keyring.sign(&commitment.encode()); + VoteMessage { commitment, id: keyring.public(), signature } + }; + let first = signed_vote(vote1.0, vote1.1, vote1.2, vote1.3); + let second = signed_vote(vote2.0, vote2.1, vote2.2, vote2.3); + EquivocationProof { first, second } +} diff --git a/test-utils/runtime/src/lib.rs b/test-utils/runtime/src/lib.rs index c1a66eb6acb5c..35906107015c5 100644 --- a/test-utils/runtime/src/lib.rs +++ b/test-utils/runtime/src/lib.rs @@ -980,6 +980,20 @@ cfg_if! { fn validator_set() -> Option> { None } + + fn submit_report_equivocation_unsigned_extrinsic( + _equivocation_proof: beefy_primitives::EquivocationProof< + NumberFor, + beefy_primitives::crypto::AuthorityId, + beefy_primitives::crypto::Signature + >, + _key_owner_proof: beefy_primitives::OpaqueKeyOwnershipProof, + ) -> Option<()> { None } + + fn generate_key_ownership_proof( + _set_id: beefy_primitives::ValidatorSetId, + _authority_id: beefy_primitives::crypto::AuthorityId, + ) -> Option { None } } impl pallet_beefy_mmr::BeefyMmrApi for Runtime { From dfa654d427d73850ec5095194552d5305a01a9a9 Mon Sep 17 00:00:00 2001 From: Dmitry Markin Date: Fri, 17 Feb 2023 13:08:59 +0300 Subject: [PATCH 408/715] network: Detect early that `NotificationOutSubstream` was closed by the remote (#13396) --- .../src/protocol/notifications/handler.rs | 7 +- .../notifications/upgrade/notifications.rs | 132 ++++++++++++++++-- 2 files changed, 127 insertions(+), 12 deletions(-) diff --git a/client/network/src/protocol/notifications/handler.rs b/client/network/src/protocol/notifications/handler.rs index 57561c7b9879d..ca87941cb96df 100644 --- a/client/network/src/protocol/notifications/handler.rs +++ b/client/network/src/protocol/notifications/handler.rs @@ -782,6 +782,9 @@ impl ConnectionHandler for NotifsHandler { // performed before the code paths that can produce `Ready` (with some rare exceptions). // Importantly, however, the flush is performed *after* notifications are queued with // `Sink::start_send`. + // Note that we must call `poll_flush` on all substreams and not only on those we + // have called `Sink::start_send` on, because `NotificationsOutSubstream::poll_flush` + // also reports the substream termination (even if no data was written into it). for protocol_index in 0..self.protocols.len() { match &mut self.protocols[protocol_index].state { State::Open { out_substream: out_substream @ Some(_), .. } => { @@ -824,7 +827,7 @@ impl ConnectionHandler for NotifsHandler { State::OpenDesiredByRemote { in_substream, pending_opening } => match NotificationsInSubstream::poll_process(Pin::new(in_substream), cx) { Poll::Pending => {}, - Poll::Ready(Ok(void)) => match void {}, + Poll::Ready(Ok(())) => {}, Poll::Ready(Err(_)) => { self.protocols[protocol_index].state = State::Closed { pending_opening: *pending_opening }; @@ -840,7 +843,7 @@ impl ConnectionHandler for NotifsHandler { cx, ) { Poll::Pending => {}, - Poll::Ready(Ok(void)) => match void {}, + Poll::Ready(Ok(())) => {}, Poll::Ready(Err(_)) => *in_substream = None, }, } diff --git a/client/network/src/protocol/notifications/upgrade/notifications.rs b/client/network/src/protocol/notifications/upgrade/notifications.rs index 71afc3c90e37f..3621c63497d95 100644 --- a/client/network/src/protocol/notifications/upgrade/notifications.rs +++ b/client/network/src/protocol/notifications/upgrade/notifications.rs @@ -41,7 +41,6 @@ use libp2p::core::{upgrade, InboundUpgrade, OutboundUpgrade, UpgradeInfo}; use log::{error, warn}; use sc_network_common::protocol::ProtocolName; use std::{ - convert::Infallible, io, mem, pin::Pin, task::{Context, Poll}, @@ -221,10 +220,7 @@ where /// Equivalent to `Stream::poll_next`, except that it only drives the handshake and is /// guaranteed to not generate any notification. - pub fn poll_process( - self: Pin<&mut Self>, - cx: &mut Context, - ) -> Poll> { + pub fn poll_process(self: Pin<&mut Self>, cx: &mut Context) -> Poll> { let mut this = self.project(); loop { @@ -246,8 +242,10 @@ where }, NotificationsInSubstreamHandshake::Flush => { match Sink::poll_flush(this.socket.as_mut(), cx)? { - Poll::Ready(()) => - *this.handshake = NotificationsInSubstreamHandshake::Sent, + Poll::Ready(()) => { + *this.handshake = NotificationsInSubstreamHandshake::Sent; + return Poll::Ready(Ok(())) + }, Poll::Pending => { *this.handshake = NotificationsInSubstreamHandshake::Flush; return Poll::Pending @@ -260,7 +258,7 @@ where st @ NotificationsInSubstreamHandshake::ClosingInResponseToRemote | st @ NotificationsInSubstreamHandshake::BothSidesClosed => { *this.handshake = st; - return Poll::Pending + return Poll::Ready(Ok(())) }, } } @@ -443,6 +441,21 @@ where fn poll_flush(self: Pin<&mut Self>, cx: &mut Context) -> Poll> { let mut this = self.project(); + + // `Sink::poll_flush` does not expose stream closed error until we write something into + // the stream, so the code below makes sure we detect that the substream was closed + // even if we don't write anything into it. + match Stream::poll_next(this.socket.as_mut(), cx) { + Poll::Pending => {}, + Poll::Ready(Some(_)) => { + error!( + target: "sub-libp2p", + "Unexpected incoming data in `NotificationsOutSubstream`", + ); + }, + Poll::Ready(None) => return Poll::Ready(Err(NotificationsOutError::Terminated)), + } + Sink::poll_flush(this.socket.as_mut(), cx).map_err(NotificationsOutError::Io) } @@ -492,13 +505,21 @@ pub enum NotificationsOutError { /// I/O error on the substream. #[error(transparent)] Io(#[from] io::Error), + + /// End of incoming data detected on out substream. + #[error("substream was closed/reset")] + Terminated, } #[cfg(test)] mod tests { - use super::{NotificationsIn, NotificationsInOpen, NotificationsOut, NotificationsOutOpen}; - use futures::{channel::oneshot, prelude::*}; + use super::{ + NotificationsIn, NotificationsInOpen, NotificationsOut, NotificationsOutError, + NotificationsOutOpen, + }; + use futures::{channel::oneshot, future, prelude::*}; use libp2p::core::upgrade; + use std::{pin::Pin, task::Poll}; use tokio::net::{TcpListener, TcpStream}; use tokio_util::compat::TokioAsyncReadCompatExt; @@ -691,4 +712,95 @@ mod tests { client.await.unwrap(); } + + #[tokio::test] + async fn send_handshake_without_polling_for_incoming_data() { + const PROTO_NAME: &str = "/test/proto/1"; + let (listener_addr_tx, listener_addr_rx) = oneshot::channel(); + + let client = tokio::spawn(async move { + let socket = TcpStream::connect(listener_addr_rx.await.unwrap()).await.unwrap(); + let NotificationsOutOpen { handshake, .. } = upgrade::apply_outbound( + socket.compat(), + NotificationsOut::new(PROTO_NAME, Vec::new(), &b"initial message"[..], 1024 * 1024), + upgrade::Version::V1, + ) + .await + .unwrap(); + + assert_eq!(handshake, b"hello world"); + }); + + 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.compat(), + NotificationsIn::new(PROTO_NAME, Vec::new(), 1024 * 1024), + ) + .await + .unwrap(); + + assert_eq!(handshake, b"initial message"); + substream.send_handshake(&b"hello world"[..]); + + // Actually send the handshake. + future::poll_fn(|cx| Pin::new(&mut substream).poll_process(cx)).await.unwrap(); + + client.await.unwrap(); + } + + #[tokio::test] + async fn can_detect_dropped_out_substream_without_writing_data() { + const PROTO_NAME: &str = "/test/proto/1"; + let (listener_addr_tx, listener_addr_rx) = oneshot::channel(); + + let client = tokio::spawn(async move { + let socket = TcpStream::connect(listener_addr_rx.await.unwrap()).await.unwrap(); + let NotificationsOutOpen { handshake, mut substream, .. } = upgrade::apply_outbound( + socket.compat(), + NotificationsOut::new(PROTO_NAME, Vec::new(), &b"initial message"[..], 1024 * 1024), + upgrade::Version::V1, + ) + .await + .unwrap(); + + assert_eq!(handshake, b"hello world"); + + future::poll_fn(|cx| match Pin::new(&mut substream).poll_flush(cx) { + Poll::Pending => Poll::Pending, + Poll::Ready(Ok(())) => { + cx.waker().wake_by_ref(); + Poll::Pending + }, + Poll::Ready(Err(e)) => { + assert!(matches!(e, NotificationsOutError::Terminated)); + Poll::Ready(()) + }, + }) + .await; + }); + + 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.compat(), + NotificationsIn::new(PROTO_NAME, Vec::new(), 1024 * 1024), + ) + .await + .unwrap(); + + assert_eq!(handshake, b"initial message"); + + // Send the handhsake. + substream.send_handshake(&b"hello world"[..]); + future::poll_fn(|cx| Pin::new(&mut substream).poll_process(cx)).await.unwrap(); + + drop(substream); + + client.await.unwrap(); + } } From ea4fbcb84cf3883123d1341068e1e70310ab2049 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= <123550+andresilva@users.noreply.github.com> Date: Fri, 17 Feb 2023 11:46:43 +0000 Subject: [PATCH 409/715] babe: account for skipped epochs when handling equivocations (#13335) * babe: account for skipped epochs when handling equivocations * typos * babe: enforce epoch index >= session index --- frame/babe/src/lib.rs | 90 ++++++++++++++++++++++++++++++++++++++--- frame/babe/src/tests.rs | 62 ++++++++++++++++++++++++++++ 2 files changed, 146 insertions(+), 6 deletions(-) diff --git a/frame/babe/src/lib.rs b/frame/babe/src/lib.rs index eb87d65b0549f..69c89fdcea776 100644 --- a/frame/babe/src/lib.rs +++ b/frame/babe/src/lib.rs @@ -39,6 +39,7 @@ use sp_runtime::{ ConsensusEngineId, KeyTypeId, Permill, }; use sp_session::{GetSessionNumber, GetValidatorCount}; +use sp_staking::SessionIndex; use sp_std::prelude::*; use sp_consensus_babe::{ @@ -102,7 +103,7 @@ impl EpochChangeTrigger for SameAuthoritiesForever { let authorities = >::authorities(); let next_authorities = authorities.clone(); - >::enact_epoch_change(authorities, next_authorities); + >::enact_epoch_change(authorities, next_authorities, None); } } } @@ -316,6 +317,19 @@ pub mod pallet { #[pallet::storage] pub(super) type NextEpochConfig = StorageValue<_, BabeEpochConfiguration>; + /// A list of the last 100 skipped epochs and the corresponding session index + /// when the epoch was skipped. + /// + /// This is only used for validating equivocation proofs. An equivocation proof + /// must contains a key-ownership proof for a given session, therefore we need a + /// way to tie together sessions and epoch indices, i.e. we need to validate that + /// a validator was the owner of a given key on a given session, and what the + /// active epoch index was during that session. + #[pallet::storage] + #[pallet::getter(fn skipped_epochs)] + pub(super) type SkippedEpochs = + StorageValue<_, BoundedVec<(u64, SessionIndex), ConstU32<100>>, ValueQuery>; + #[cfg_attr(feature = "std", derive(Default))] #[pallet::genesis_config] pub struct GenesisConfig { @@ -577,6 +591,7 @@ impl Pallet { pub fn enact_epoch_change( authorities: WeakBoundedVec<(AuthorityId, BabeAuthorityWeight), T::MaxAuthorities>, next_authorities: WeakBoundedVec<(AuthorityId, BabeAuthorityWeight), T::MaxAuthorities>, + session_index: Option, ) { // PRECONDITION: caller has done initialization and is guaranteed // by the session module to be called before this. @@ -602,6 +617,35 @@ impl Pallet { T::EpochDuration::get(), ); + let current_epoch_index = EpochIndex::::get(); + if current_epoch_index.saturating_add(1) != epoch_index { + // we are skipping epochs therefore we need to update the mapping + // of epochs to session + if let Some(session_index) = session_index { + SkippedEpochs::::mutate(|skipped_epochs| { + if epoch_index < session_index as u64 { + log::warn!( + target: LOG_TARGET, + "Current epoch index {} is lower than session index {}.", + epoch_index, + session_index, + ); + + return + } + + if skipped_epochs.is_full() { + // NOTE: this is O(n) but we currently don't have a bounded `VecDeque`. + // this vector is bounded to a small number of elements so performance + // shouldn't be an issue. + skipped_epochs.remove(0); + } + + skipped_epochs.force_push((epoch_index, session_index)); + }) + } + } + EpochIndex::::put(epoch_index); Authorities::::put(authorities); @@ -816,6 +860,36 @@ impl Pallet { this_randomness } + /// Returns the session index that was live when the given epoch happened, + /// taking into account any skipped epochs. + /// + /// This function is only well defined for epochs that actually existed, + /// e.g. if we skipped from epoch 10 to 20 then a call for epoch 15 (which + /// didn't exist) will return an incorrect session index. + fn session_index_for_epoch(epoch_index: u64) -> SessionIndex { + let skipped_epochs = SkippedEpochs::::get(); + match skipped_epochs.binary_search_by_key(&epoch_index, |(epoch_index, _)| *epoch_index) { + // we have an exact match so we just return the given session index + Ok(index) => skipped_epochs[index].1, + // we haven't found any skipped epoch before the given epoch, + // so the epoch index and session index should match + Err(0) => epoch_index.saturated_into::(), + // we have found a skipped epoch before the given epoch + Err(index) => { + // the element before the given index should give us the skipped epoch + // that's closest to the one we're trying to find the session index for + let closest_skipped_epoch = skipped_epochs[index - 1]; + + // calculate the number of skipped epochs at this point by checking the difference + // between the epoch and session indices. epoch index should always be greater or + // equal to session index, this is because epochs can be skipped whereas sessions + // can't (this is enforced when pushing into `SkippedEpochs`) + let skipped_epochs = closest_skipped_epoch.0 - closest_skipped_epoch.1 as u64; + epoch_index.saturating_sub(skipped_epochs).saturated_into::() + }, + } + } + fn do_report_equivocation( reporter: Option, equivocation_proof: EquivocationProof, @@ -832,12 +906,11 @@ impl Pallet { let validator_set_count = key_owner_proof.validator_count(); let session_index = key_owner_proof.session(); - let epoch_index = (*slot.saturating_sub(GenesisSlot::::get()) / T::EpochDuration::get()) - .saturated_into::(); + let epoch_index = *slot.saturating_sub(GenesisSlot::::get()) / T::EpochDuration::get(); // check that the slot number is consistent with the session index // in the key ownership proof (i.e. slot is for that epoch) - if epoch_index != session_index { + if Self::session_index_for_epoch(epoch_index) != session_index { return Err(Error::::InvalidKeyOwnershipProof.into()) } @@ -926,7 +999,10 @@ impl sp_runtime::BoundToRuntimeAppPublic for Pallet { type Public = AuthorityId; } -impl OneSessionHandler for Pallet { +impl OneSessionHandler for Pallet +where + T: pallet_session::Config, +{ type Key = AuthorityId; fn on_genesis_session<'a, I: 'a>(validators: I) @@ -959,7 +1035,9 @@ impl OneSessionHandler for Pallet { ), ); - Self::enact_epoch_change(bounded_authorities, next_bounded_authorities) + let session_index = >::current_index(); + + Self::enact_epoch_change(bounded_authorities, next_bounded_authorities, Some(session_index)) } fn on_disabled(i: u32) { diff --git a/frame/babe/src/tests.rs b/frame/babe/src/tests.rs index 0b8a02547144b..938269a6cfa62 100644 --- a/frame/babe/src/tests.rs +++ b/frame/babe/src/tests.rs @@ -826,6 +826,56 @@ fn report_equivocation_has_valid_weight() { .all(|w| w[0].ref_time() < w[1].ref_time())); } +#[test] +fn report_equivocation_after_skipped_epochs_works() { + let (pairs, mut ext) = new_test_ext_with_pairs(3); + + ext.execute_with(|| { + let epoch_duration: u64 = ::EpochDuration::get(); + + // this sets the genesis slot to 100; + let genesis_slot = 100; + go_to_block(1, genesis_slot); + assert_eq!(EpochIndex::::get(), 0); + + // skip from epoch #0 to epoch #10 + go_to_block(System::block_number() + 1, genesis_slot + epoch_duration * 10); + + assert_eq!(EpochIndex::::get(), 10); + assert_eq!(SkippedEpochs::::get(), vec![(10, 1)]); + + // generate an equivocation proof for validator at index 1 + let authorities = Babe::authorities(); + let offending_validator_index = 1; + let offending_authority_pair = pairs + .into_iter() + .find(|p| p.public() == authorities[offending_validator_index].0) + .unwrap(); + + let equivocation_proof = generate_equivocation_proof( + offending_validator_index as u32, + &offending_authority_pair, + CurrentSlot::::get(), + ); + + // create the key ownership proof + let key = (sp_consensus_babe::KEY_TYPE, &offending_authority_pair.public()); + let key_owner_proof = Historical::prove(key).unwrap(); + + // which is for session index 1 (while current epoch index is 10) + assert_eq!(key_owner_proof.session, 1); + + // report the equivocation, in order for the validation to pass the mapping + // between epoch index and session index must be checked. + assert!(Babe::report_equivocation_unsigned( + RuntimeOrigin::none(), + Box::new(equivocation_proof), + key_owner_proof + ) + .is_ok()); + }) +} + #[test] fn valid_equivocation_reports_dont_pay_fees() { let (pairs, mut ext) = new_test_ext_with_pairs(3); @@ -977,5 +1027,17 @@ fn skipping_over_epochs_works() { assert_eq!(EpochIndex::::get(), 4); assert_eq!(Randomness::::get(), randomness_for_epoch_2); + + // after skipping epochs the information is registered on-chain so that + // we can map epochs to sessions + assert_eq!(SkippedEpochs::::get(), vec![(4, 2)]); + + // before epochs are skipped the mapping should be one to one + assert_eq!(Babe::session_index_for_epoch(0), 0); + assert_eq!(Babe::session_index_for_epoch(1), 1); + + // otherwise the session index is offset by the number of skipped epochs + assert_eq!(Babe::session_index_for_epoch(4), 2); + assert_eq!(Babe::session_index_for_epoch(5), 3); }); } From a33091270e54f9e3f3488485c0a7ca3a58f5a26c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Miko=C5=82ajczyk?= Date: Fri, 17 Feb 2023 13:21:58 +0100 Subject: [PATCH 410/715] `try-runtime::fast-forward` (#12896) * try-runtime::fast-forward * Revert un`pub`ing command's fields * Handle storage change failure * Adjust Substrate node * Feature-gated imports * doc link * Feature-gated imports in node-template * Move trait, blanket implementation and auxiliary functions to a new module * Distinguish between plain babe+timestamp and substrate enhanced info * Remove uncles inherents * Missing argument * Add doc comment about `blocktime_millis` * Add licenses --- Cargo.lock | 6 + bin/node-template/node/src/command.rs | 7 +- bin/node/cli/src/command.rs | 10 +- utils/frame/try-runtime/cli/Cargo.toml | 6 + .../cli/src/block_building_info.rs | 152 ++++++++++ .../cli/src/commands/fast_forward.rs | 268 ++++++++++++++++++ .../frame/try-runtime/cli/src/commands/mod.rs | 1 + utils/frame/try-runtime/cli/src/lib.rs | 27 +- 8 files changed, 473 insertions(+), 4 deletions(-) create mode 100644 utils/frame/try-runtime/cli/src/block_building_info.rs create mode 100644 utils/frame/try-runtime/cli/src/commands/fast_forward.rs diff --git a/Cargo.lock b/Cargo.lock index b33f7627f230e..d7f48c17f8726 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11426,6 +11426,7 @@ checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" name = "try-runtime-cli" version = "0.10.0-dev" dependencies = [ + "async-trait", "clap 4.1.4", "frame-remote-externalities", "frame-try-runtime", @@ -11438,14 +11439,19 @@ dependencies = [ "serde", "serde_json", "sp-api", + "sp-consensus-aura", + "sp-consensus-babe", "sp-core", "sp-debug-derive", "sp-externalities", + "sp-inherents", "sp-io", "sp-keystore", "sp-rpc", "sp-runtime", "sp-state-machine", + "sp-timestamp", + "sp-transaction-storage-proof", "sp-version", "sp-weights", "substrate-rpc-client", diff --git a/bin/node-template/node/src/command.rs b/bin/node-template/node/src/command.rs index 15cd69b34b5b2..c3dc098cdfb3a 100644 --- a/bin/node-template/node/src/command.rs +++ b/bin/node-template/node/src/command.rs @@ -10,6 +10,9 @@ use sc_cli::{ChainSpec, RuntimeVersion, SubstrateCli}; use sc_service::PartialComponents; use sp_keyring::Sr25519Keyring; +#[cfg(feature = "try-runtime")] +use try_runtime_cli::block_building_info::timestamp_with_aura_info; + impl SubstrateCli for Cli { fn impl_name() -> String { "Substrate Node".into() @@ -184,11 +187,13 @@ pub fn run() -> sc_cli::Result<()> { let task_manager = sc_service::TaskManager::new(config.tokio_handle.clone(), registry) .map_err(|e| sc_cli::Error::Service(sc_service::Error::Prometheus(e)))?; + let info_provider = timestamp_with_aura_info(6000); + Ok(( cmd.run::::ExtendHostFunctions, - >>(), + >, _>(Some(info_provider)), task_manager, )) }) diff --git a/bin/node/cli/src/command.rs b/bin/node/cli/src/command.rs index 2ed8a2c754018..4256c7d61f4fd 100644 --- a/bin/node/cli/src/command.rs +++ b/bin/node/cli/src/command.rs @@ -32,6 +32,12 @@ use sp_keyring::Sr25519Keyring; use std::sync::Arc; +#[cfg(feature = "try-runtime")] +use { + kitchensink_runtime::constants::time::SLOT_DURATION, + try_runtime_cli::block_building_info::substrate_info, +}; + impl SubstrateCli for Cli { fn impl_name() -> String { "Substrate Node".into() @@ -236,11 +242,13 @@ pub fn run() -> Result<()> { sc_service::TaskManager::new(config.tokio_handle.clone(), registry) .map_err(|e| sc_cli::Error::Service(sc_service::Error::Prometheus(e)))?; + let info_provider = substrate_info(SLOT_DURATION); + Ok(( cmd.run::::ExtendHostFunctions, - >>(), + >, _>(Some(info_provider)), task_manager, )) }) diff --git a/utils/frame/try-runtime/cli/Cargo.toml b/utils/frame/try-runtime/cli/Cargo.toml index 8c14ddc2916b0..a220289542464 100644 --- a/utils/frame/try-runtime/cli/Cargo.toml +++ b/utils/frame/try-runtime/cli/Cargo.toml @@ -16,13 +16,18 @@ remote-externalities = { version = "0.10.0-dev", path = "../../remote-externalit 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-consensus-aura = { path = "../../../../primitives/consensus/aura" } +sp-consensus-babe = { path = "../../../../primitives/consensus/babe" } sp-core = { version = "7.0.0", path = "../../../../primitives/core" } sp-externalities = { version = "0.13.0", path = "../../../../primitives/externalities" } +sp-inherents = { path = "../../../../primitives/inherents" } 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-rpc = { version = "6.0.0", path = "../../../../primitives/rpc" } sp-state-machine = { version = "0.13.0", path = "../../../../primitives/state-machine" } +sp-timestamp = { path = "../../../../primitives/timestamp" } +sp-transaction-storage-proof = { path = "../../../../primitives/transaction-storage-proof" } sp-version = { version = "5.0.0", path = "../../../../primitives/version" } sp-debug-derive = { path = "../../../../primitives/debug-derive" } sp-api = { path = "../../../../primitives/api" } @@ -30,6 +35,7 @@ sp-weights = { version = "4.0.0", path = "../../../../primitives/weights" } frame-try-runtime = { optional = true, path = "../../../../frame/try-runtime" } substrate-rpc-client = { path = "../../rpc/client" } +async-trait = "0.1.57" clap = { version = "4.0.9", features = ["derive"] } hex = { version = "0.4.3", default-features = false } log = "0.4.17" diff --git a/utils/frame/try-runtime/cli/src/block_building_info.rs b/utils/frame/try-runtime/cli/src/block_building_info.rs new file mode 100644 index 0000000000000..b68bf081fee3e --- /dev/null +++ b/utils/frame/try-runtime/cli/src/block_building_info.rs @@ -0,0 +1,152 @@ +// 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. + +use crate::BlockT; +use parity_scale_codec::Encode; +use sc_cli::Result; +use sp_consensus_aura::{Slot, SlotDuration, AURA_ENGINE_ID}; +use sp_consensus_babe::{ + digests::{PreDigest, SecondaryPlainPreDigest}, + BABE_ENGINE_ID, +}; +use sp_inherents::{InherentData, InherentDataProvider}; +use sp_runtime::{Digest, DigestItem}; +use sp_timestamp::TimestampInherentData; + +/// Something that can create inherent data providers and pre-runtime digest. +/// +/// It is possible for the caller to provide custom arguments to the callee by setting the +/// `ExtraArgs` generic parameter. +/// +/// This module already provides some convenience implementation of this trait for closures. So, it +/// should not be required to implement it directly. +#[async_trait::async_trait] +pub trait BlockBuildingInfoProvider { + type InherentDataProviders: InherentDataProvider; + + async fn get_inherent_providers_and_pre_digest( + &self, + parent_hash: Block::Hash, + extra_args: ExtraArgs, + ) -> Result<(Self::InherentDataProviders, Vec)>; +} + +#[async_trait::async_trait] +impl BlockBuildingInfoProvider for F +where + Block: BlockT, + F: Fn(Block::Hash, ExtraArgs) -> Fut + Sync + Send, + Fut: std::future::Future)>> + Send + 'static, + IDP: InherentDataProvider + 'static, + ExtraArgs: Send + 'static, +{ + type InherentDataProviders = IDP; + + async fn get_inherent_providers_and_pre_digest( + &self, + parent: Block::Hash, + extra_args: ExtraArgs, + ) -> Result<(Self::InherentDataProviders, Vec)> { + (*self)(parent, extra_args).await + } +} + +/// Provides [`BlockBuildingInfoProvider`] implementation for chains that include timestamp inherent +/// and use Aura for a block production. +/// +/// It depends only on the expected block production frequency, i.e. `blocktime_millis`. +pub fn timestamp_with_aura_info( + blocktime_millis: u64, +) -> impl BlockBuildingInfoProvider> { + move |_, maybe_prev_info: Option<(InherentData, Digest)>| async move { + let timestamp_idp = match maybe_prev_info { + Some((inherent_data, _)) => sp_timestamp::InherentDataProvider::new( + inherent_data.timestamp_inherent_data().unwrap().unwrap() + blocktime_millis, + ), + None => sp_timestamp::InherentDataProvider::from_system_time(), + }; + + let slot = + Slot::from_timestamp(*timestamp_idp, SlotDuration::from_millis(blocktime_millis)); + let digest = vec![DigestItem::PreRuntime(AURA_ENGINE_ID, slot.encode())]; + + Ok((timestamp_idp, digest)) + } +} + +/// Provides [`BlockBuildingInfoProvider`] implementation for chains that include timestamp inherent +/// and use Babe for a block production. +/// +/// It depends only on the expected block production frequency, i.e. `blocktime_millis`. +pub fn timestamp_with_babe_info( + blocktime_millis: u64, +) -> impl BlockBuildingInfoProvider> { + move |_, maybe_prev_info: Option<(InherentData, Digest)>| async move { + let timestamp_idp = match maybe_prev_info { + Some((inherent_data, _)) => sp_timestamp::InherentDataProvider::new( + inherent_data.timestamp_inherent_data().unwrap().unwrap() + blocktime_millis, + ), + None => sp_timestamp::InherentDataProvider::from_system_time(), + }; + + let slot = + Slot::from_timestamp(*timestamp_idp, SlotDuration::from_millis(blocktime_millis)); + let slot_idp = sp_consensus_babe::inherents::InherentDataProvider::new(slot); + + let digest = vec![DigestItem::PreRuntime( + BABE_ENGINE_ID, + PreDigest::SecondaryPlain(SecondaryPlainPreDigest { slot, authority_index: 0 }) + .encode(), + )]; + + Ok(((slot_idp, timestamp_idp), digest)) + } +} + +/// Provides [`BlockBuildingInfoProvider`] implementation for chains that use: +/// - timestamp inherent, +/// - Babe for a block production (inherent + digest), +/// - uncles inherent, +/// - storage proof inherent +/// +/// It depends only on the expected block production frequency, i.e. `blocktime_millis`. +pub fn substrate_info( + blocktime_millis: u64, +) -> impl BlockBuildingInfoProvider> { + move |_, maybe_prev_info: Option<(InherentData, Digest)>| async move { + let timestamp_idp = match maybe_prev_info { + Some((inherent_data, _)) => sp_timestamp::InherentDataProvider::new( + inherent_data.timestamp_inherent_data().unwrap().unwrap() + blocktime_millis, + ), + None => sp_timestamp::InherentDataProvider::from_system_time(), + }; + + let slot = + Slot::from_timestamp(*timestamp_idp, SlotDuration::from_millis(blocktime_millis)); + let slot_idp = sp_consensus_babe::inherents::InherentDataProvider::new(slot); + + let storage_proof_idp = sp_transaction_storage_proof::InherentDataProvider::new(None); + + let digest = vec![DigestItem::PreRuntime( + BABE_ENGINE_ID, + PreDigest::SecondaryPlain(SecondaryPlainPreDigest { slot, authority_index: 0 }) + .encode(), + )]; + + Ok(((slot_idp, timestamp_idp, storage_proof_idp), digest)) + } +} diff --git a/utils/frame/try-runtime/cli/src/commands/fast_forward.rs b/utils/frame/try-runtime/cli/src/commands/fast_forward.rs new file mode 100644 index 0000000000000..ae8f9a5cf17f2 --- /dev/null +++ b/utils/frame/try-runtime/cli/src/commands/fast_forward.rs @@ -0,0 +1,268 @@ +// 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. + +use crate::{ + block_building_info::BlockBuildingInfoProvider, build_executor, full_extensions, + rpc_err_handler, state_machine_call, BlockT, LiveState, SharedParams, State, +}; +use parity_scale_codec::{Decode, Encode}; +use sc_cli::Result; +use sc_executor::{sp_wasm_interface::HostFunctions, WasmExecutor}; +use serde::de::DeserializeOwned; +use sp_core::H256; +use sp_inherents::{InherentData, InherentDataProvider}; +use sp_io::TestExternalities; +use sp_runtime::{ + traits::{Header, NumberFor, One}, + Digest, +}; +use std::{fmt::Debug, str::FromStr}; +use substrate_rpc_client::{ws_client, ChainApi}; + +/// Configurations of the [`crate::Command::FastForward`]. +#[derive(Debug, Clone, clap::Parser)] +pub struct FastForwardCmd { + /// How many blocks should be processed. If `None`, then blocks will be produced and processed + /// in a loop. + #[arg(long)] + n_blocks: Option, + + /// The state type to use. + #[command(subcommand)] + state: State, + + /// The ws uri from which to fetch the block. + /// + /// If `state` is `Live`, this is ignored. Otherwise, it must not be empty. + #[arg(long, value_parser = crate::parse::url)] + block_ws_uri: Option, + + /// 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. + #[arg(long, default_value = "all")] + try_state: frame_try_runtime::TryStateSelect, +} + +impl FastForwardCmd { + fn block_ws_uri(&self) -> &str { + match self.state { + State::Live(LiveState { ref uri, .. }) => &uri, + _ => self + .block_ws_uri + .as_ref() + .expect("Either `--block-uri` must be provided, or state must be `live`"), + } + } +} + +/// Read the block number corresponding to `hash` with an RPC call to `ws_uri`. +async fn get_block_number( + hash: Block::Hash, + ws_uri: &str, +) -> Result> +where + Block::Header: DeserializeOwned, +{ + let rpc = ws_client(ws_uri).await?; + Ok(ChainApi::<(), Block::Hash, Block::Header, ()>::header(&rpc, Some(hash)) + .await + .map_err(rpc_err_handler) + .and_then(|maybe_header| maybe_header.ok_or("header_not_found").map(|h| *h.number()))?) +} + +/// Call `method` with `data` and return the result. `externalities` will not change. +async fn dry_run( + externalities: &TestExternalities, + executor: &WasmExecutor, + method: &'static str, + data: &[u8], +) -> Result { + let (_, result) = state_machine_call::( + externalities, + executor, + method, + data, + full_extensions(), + )?; + + Ok(::decode(&mut &*result)?) +} + +/// Call `method` with `data` and actually save storage changes to `externalities`. +async fn run( + externalities: &mut TestExternalities, + executor: &WasmExecutor, + method: &'static str, + data: &[u8], +) -> Result<()> { + let (mut changes, _) = state_machine_call::( + externalities, + executor, + method, + data, + full_extensions(), + )?; + + let storage_changes = changes.drain_storage_changes( + &externalities.backend, + &mut Default::default(), + externalities.state_version, + )?; + + externalities + .backend + .apply_transaction(storage_changes.transaction_storage_root, storage_changes.transaction); + + Ok(()) +} + +/// Produce next empty block. +async fn next_empty_block< + Block: BlockT, + HostFns: HostFunctions, + BBIP: BlockBuildingInfoProvider>, +>( + externalities: &mut TestExternalities, + executor: &WasmExecutor, + parent_height: NumberFor, + parent_hash: Block::Hash, + block_building_info_provider: &Option, + previous_block_building_info: Option<(InherentData, Digest)>, +) -> Result<(Block, Option<(InherentData, Digest)>)> { + let (maybe_inherent_data, pre_digest) = match &block_building_info_provider { + None => (None, Default::default()), + Some(bbip) => { + let (inherent_data_provider, pre_digest) = bbip + .get_inherent_providers_and_pre_digest(parent_hash, previous_block_building_info) + .await?; + let inherent_data = inherent_data_provider + .create_inherent_data() + .await + .map_err(|e| sc_cli::Error::Input(format!("I don't know how to convert {e:?}")))?; + + (Some(inherent_data), Digest { logs: pre_digest }) + }, + }; + + let header = Block::Header::new( + parent_height + One::one(), + Default::default(), + Default::default(), + parent_hash, + pre_digest.clone(), + ); + let mut extrinsics = >::new(); + + run::(externalities, executor, "Core_initialize_block", &header.encode()).await?; + + if let Some(ref inherent_data) = maybe_inherent_data { + extrinsics = dry_run::, Block, _>( + externalities, + executor, + "BlockBuilder_inherent_extrinsics", + &inherent_data.encode(), + ) + .await?; + } + + for xt in &extrinsics { + run::(externalities, executor, "BlockBuilder_apply_extrinsic", &xt.encode()) + .await?; + } + + let header = dry_run::( + externalities, + executor, + "BlockBuilder_finalize_block", + &[0u8; 0], + ) + .await?; + + run::(externalities, executor, "BlockBuilder_finalize_block", &[0u8; 0]).await?; + + Ok((Block::new(header, extrinsics), (maybe_inherent_data.map(|id| (id, pre_digest))))) +} + +pub(crate) async fn fast_forward( + shared: SharedParams, + command: FastForwardCmd, + block_building_info_provider: Option, +) -> Result<()> +where + Block: BlockT + DeserializeOwned, + Block::Hash: FromStr, + Block::Header: DeserializeOwned, + ::Err: Debug, + NumberFor: FromStr, + as FromStr>::Err: Debug, + HostFns: HostFunctions, + BBIP: BlockBuildingInfoProvider>, +{ + let executor = build_executor::(&shared); + let ext = command.state.into_ext::(&shared, &executor, None, true).await?; + + let mut last_block_hash = ext.block_hash; + let mut last_block_number = + get_block_number::(last_block_hash, command.block_ws_uri()).await?; + let mut prev_block_building_info = None; + + let mut ext = ext.inner_ext; + + for _ in 1..=command.n_blocks.unwrap_or(u64::MAX) { + // We are saving state before we overwrite it while producing new block. + let backend = ext.as_backend(); + + log::info!("Producing new empty block at height {:?}", last_block_number + One::one()); + + let (next_block, new_block_building_info) = next_empty_block::( + &mut ext, + &executor, + last_block_number, + last_block_hash, + &block_building_info_provider, + prev_block_building_info, + ) + .await?; + + log::info!("Produced a new block: {:?}", next_block.header()); + + // And now we restore previous state. + ext.backend = backend; + + let state_root_check = true; + let signature_check = true; + let payload = + (next_block.clone(), state_root_check, signature_check, command.try_state.clone()) + .encode(); + run::(&mut ext, &executor, "TryRuntime_execute_block", &payload).await?; + + log::info!("Executed the new block"); + + prev_block_building_info = new_block_building_info; + last_block_hash = next_block.hash(); + last_block_number += One::one(); + } + + Ok(()) +} diff --git a/utils/frame/try-runtime/cli/src/commands/mod.rs b/utils/frame/try-runtime/cli/src/commands/mod.rs index ab0a066585f6a..81deb263163b0 100644 --- a/utils/frame/try-runtime/cli/src/commands/mod.rs +++ b/utils/frame/try-runtime/cli/src/commands/mod.rs @@ -17,6 +17,7 @@ pub mod create_snapshot; pub mod execute_block; +pub mod fast_forward; pub mod follow_chain; pub mod offchain_worker; pub mod on_runtime_upgrade; diff --git a/utils/frame/try-runtime/cli/src/lib.rs b/utils/frame/try-runtime/cli/src/lib.rs index dea20febb9c58..1a2f32de52ec1 100644 --- a/utils/frame/try-runtime/cli/src/lib.rs +++ b/utils/frame/try-runtime/cli/src/lib.rs @@ -358,6 +358,7 @@ #![cfg(feature = "try-runtime")] +use crate::block_building_info::BlockBuildingInfoProvider; use parity_scale_codec::Decode; use remote_externalities::{ Builder, Mode, OfflineConfig, OnlineConfig, RemoteExternalities, SnapshotConfig, @@ -381,15 +382,17 @@ use sp_core::{ twox_128, H256, }; use sp_externalities::Extensions; +use sp_inherents::InherentData; use sp_keystore::{testing::KeyStore, KeystoreExt}; use sp_runtime::{ traits::{BlakeTwo256, Block as BlockT, NumberFor}, - DeserializeOwned, + DeserializeOwned, Digest, }; use sp_state_machine::{CompactProof, OverlayedChanges, StateMachine, TrieBackendBuilder}; use sp_version::StateVersion; use std::{fmt::Debug, path::PathBuf, str::FromStr}; +pub mod block_building_info; pub mod commands; pub(crate) mod parse; pub(crate) const LOG_TARGET: &str = "try-runtime::cli"; @@ -445,6 +448,15 @@ pub enum Command { /// tested has remained the same, otherwise block decoding might fail. FollowChain(commands::follow_chain::FollowChainCmd), + /// Produce a series of empty, consecutive blocks and execute them one-by-one. + /// + /// To compare it with [`Command::FollowChain`]: + /// - we don't have the delay of the original blocktime (for Polkadot 6s), but instead, we + /// execute every block immediately + /// - the only data that will be put into blocks are pre-runtime digest items and inherent + /// extrinsics; both things should be defined in your node CLI handling level + FastForward(commands::fast_forward::FastForwardCmd), + /// Create a new snapshot file. CreateSnapshot(commands::create_snapshot::CreateSnapshotCmd), } @@ -719,7 +731,10 @@ impl State { } impl TryRuntimeCmd { - pub async fn run(&self) -> sc_cli::Result<()> + pub async fn run( + &self, + block_building_info_provider: Option, + ) -> sc_cli::Result<()> where Block: BlockT + DeserializeOwned, Block::Header: DeserializeOwned, @@ -729,6 +744,7 @@ impl TryRuntimeCmd { as TryInto>::Error: Debug, NumberFor: FromStr, HostFns: HostFunctions, + BBIP: BlockBuildingInfoProvider>, { match &self.command { Command::OnRuntimeUpgrade(ref cmd) => @@ -755,6 +771,13 @@ impl TryRuntimeCmd { cmd.clone(), ) .await, + Command::FastForward(cmd) => + commands::fast_forward::fast_forward::( + self.shared.clone(), + cmd.clone(), + block_building_info_provider, + ) + .await, Command::CreateSnapshot(cmd) => commands::create_snapshot::create_snapshot::( self.shared.clone(), From 30cb4d10b3118d1b3aa5b2ae7fa8429b2c4f28de Mon Sep 17 00:00:00 2001 From: Dmitry Markin Date: Fri, 17 Feb 2023 19:58:04 +0300 Subject: [PATCH 411/715] Revert "network: Detect early that `NotificationOutSubstream` was closed by the remote (#13396)" (#13409) This reverts commit dfa654d427d73850ec5095194552d5305a01a9a9. --- .../src/protocol/notifications/handler.rs | 7 +- .../notifications/upgrade/notifications.rs | 132 ++---------------- 2 files changed, 12 insertions(+), 127 deletions(-) diff --git a/client/network/src/protocol/notifications/handler.rs b/client/network/src/protocol/notifications/handler.rs index ca87941cb96df..57561c7b9879d 100644 --- a/client/network/src/protocol/notifications/handler.rs +++ b/client/network/src/protocol/notifications/handler.rs @@ -782,9 +782,6 @@ impl ConnectionHandler for NotifsHandler { // performed before the code paths that can produce `Ready` (with some rare exceptions). // Importantly, however, the flush is performed *after* notifications are queued with // `Sink::start_send`. - // Note that we must call `poll_flush` on all substreams and not only on those we - // have called `Sink::start_send` on, because `NotificationsOutSubstream::poll_flush` - // also reports the substream termination (even if no data was written into it). for protocol_index in 0..self.protocols.len() { match &mut self.protocols[protocol_index].state { State::Open { out_substream: out_substream @ Some(_), .. } => { @@ -827,7 +824,7 @@ impl ConnectionHandler for NotifsHandler { State::OpenDesiredByRemote { in_substream, pending_opening } => match NotificationsInSubstream::poll_process(Pin::new(in_substream), cx) { Poll::Pending => {}, - Poll::Ready(Ok(())) => {}, + Poll::Ready(Ok(void)) => match void {}, Poll::Ready(Err(_)) => { self.protocols[protocol_index].state = State::Closed { pending_opening: *pending_opening }; @@ -843,7 +840,7 @@ impl ConnectionHandler for NotifsHandler { cx, ) { Poll::Pending => {}, - Poll::Ready(Ok(())) => {}, + Poll::Ready(Ok(void)) => match void {}, Poll::Ready(Err(_)) => *in_substream = None, }, } diff --git a/client/network/src/protocol/notifications/upgrade/notifications.rs b/client/network/src/protocol/notifications/upgrade/notifications.rs index 3621c63497d95..71afc3c90e37f 100644 --- a/client/network/src/protocol/notifications/upgrade/notifications.rs +++ b/client/network/src/protocol/notifications/upgrade/notifications.rs @@ -41,6 +41,7 @@ use libp2p::core::{upgrade, InboundUpgrade, OutboundUpgrade, UpgradeInfo}; use log::{error, warn}; use sc_network_common::protocol::ProtocolName; use std::{ + convert::Infallible, io, mem, pin::Pin, task::{Context, Poll}, @@ -220,7 +221,10 @@ where /// Equivalent to `Stream::poll_next`, except that it only drives the handshake and is /// guaranteed to not generate any notification. - pub fn poll_process(self: Pin<&mut Self>, cx: &mut Context) -> Poll> { + pub fn poll_process( + self: Pin<&mut Self>, + cx: &mut Context, + ) -> Poll> { let mut this = self.project(); loop { @@ -242,10 +246,8 @@ where }, NotificationsInSubstreamHandshake::Flush => { match Sink::poll_flush(this.socket.as_mut(), cx)? { - Poll::Ready(()) => { - *this.handshake = NotificationsInSubstreamHandshake::Sent; - return Poll::Ready(Ok(())) - }, + Poll::Ready(()) => + *this.handshake = NotificationsInSubstreamHandshake::Sent, Poll::Pending => { *this.handshake = NotificationsInSubstreamHandshake::Flush; return Poll::Pending @@ -258,7 +260,7 @@ where st @ NotificationsInSubstreamHandshake::ClosingInResponseToRemote | st @ NotificationsInSubstreamHandshake::BothSidesClosed => { *this.handshake = st; - return Poll::Ready(Ok(())) + return Poll::Pending }, } } @@ -441,21 +443,6 @@ where fn poll_flush(self: Pin<&mut Self>, cx: &mut Context) -> Poll> { let mut this = self.project(); - - // `Sink::poll_flush` does not expose stream closed error until we write something into - // the stream, so the code below makes sure we detect that the substream was closed - // even if we don't write anything into it. - match Stream::poll_next(this.socket.as_mut(), cx) { - Poll::Pending => {}, - Poll::Ready(Some(_)) => { - error!( - target: "sub-libp2p", - "Unexpected incoming data in `NotificationsOutSubstream`", - ); - }, - Poll::Ready(None) => return Poll::Ready(Err(NotificationsOutError::Terminated)), - } - Sink::poll_flush(this.socket.as_mut(), cx).map_err(NotificationsOutError::Io) } @@ -505,21 +492,13 @@ pub enum NotificationsOutError { /// I/O error on the substream. #[error(transparent)] Io(#[from] io::Error), - - /// End of incoming data detected on out substream. - #[error("substream was closed/reset")] - Terminated, } #[cfg(test)] mod tests { - use super::{ - NotificationsIn, NotificationsInOpen, NotificationsOut, NotificationsOutError, - NotificationsOutOpen, - }; - use futures::{channel::oneshot, future, prelude::*}; + use super::{NotificationsIn, NotificationsInOpen, NotificationsOut, NotificationsOutOpen}; + use futures::{channel::oneshot, prelude::*}; use libp2p::core::upgrade; - use std::{pin::Pin, task::Poll}; use tokio::net::{TcpListener, TcpStream}; use tokio_util::compat::TokioAsyncReadCompatExt; @@ -712,95 +691,4 @@ mod tests { client.await.unwrap(); } - - #[tokio::test] - async fn send_handshake_without_polling_for_incoming_data() { - const PROTO_NAME: &str = "/test/proto/1"; - let (listener_addr_tx, listener_addr_rx) = oneshot::channel(); - - let client = tokio::spawn(async move { - let socket = TcpStream::connect(listener_addr_rx.await.unwrap()).await.unwrap(); - let NotificationsOutOpen { handshake, .. } = upgrade::apply_outbound( - socket.compat(), - NotificationsOut::new(PROTO_NAME, Vec::new(), &b"initial message"[..], 1024 * 1024), - upgrade::Version::V1, - ) - .await - .unwrap(); - - assert_eq!(handshake, b"hello world"); - }); - - 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.compat(), - NotificationsIn::new(PROTO_NAME, Vec::new(), 1024 * 1024), - ) - .await - .unwrap(); - - assert_eq!(handshake, b"initial message"); - substream.send_handshake(&b"hello world"[..]); - - // Actually send the handshake. - future::poll_fn(|cx| Pin::new(&mut substream).poll_process(cx)).await.unwrap(); - - client.await.unwrap(); - } - - #[tokio::test] - async fn can_detect_dropped_out_substream_without_writing_data() { - const PROTO_NAME: &str = "/test/proto/1"; - let (listener_addr_tx, listener_addr_rx) = oneshot::channel(); - - let client = tokio::spawn(async move { - let socket = TcpStream::connect(listener_addr_rx.await.unwrap()).await.unwrap(); - let NotificationsOutOpen { handshake, mut substream, .. } = upgrade::apply_outbound( - socket.compat(), - NotificationsOut::new(PROTO_NAME, Vec::new(), &b"initial message"[..], 1024 * 1024), - upgrade::Version::V1, - ) - .await - .unwrap(); - - assert_eq!(handshake, b"hello world"); - - future::poll_fn(|cx| match Pin::new(&mut substream).poll_flush(cx) { - Poll::Pending => Poll::Pending, - Poll::Ready(Ok(())) => { - cx.waker().wake_by_ref(); - Poll::Pending - }, - Poll::Ready(Err(e)) => { - assert!(matches!(e, NotificationsOutError::Terminated)); - Poll::Ready(()) - }, - }) - .await; - }); - - 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.compat(), - NotificationsIn::new(PROTO_NAME, Vec::new(), 1024 * 1024), - ) - .await - .unwrap(); - - assert_eq!(handshake, b"initial message"); - - // Send the handhsake. - substream.send_handshake(&b"hello world"[..]); - future::poll_fn(|cx| Pin::new(&mut substream).poll_process(cx)).await.unwrap(); - - drop(substream); - - client.await.unwrap(); - } } From 7ffae37f5c5eca019ca8c5448c97767aace0c9fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Sat, 18 Feb 2023 17:59:08 +0100 Subject: [PATCH 412/715] state-db: Print warning when using large pruning window on RocksDb (#13414) * state-db: Print warning when using large pruning window on RocksDb This pr changes state-db to print a warning when using a large pruning window and running with a database that isn't supporting ref-counting like RocksDb. This makes the user aware of potential out of memory errors because this option together with RocksDb etc puts the entire pruning window into memory. Besides that the pr introduces `LOG_TARGET` for having the target declared central! * Review comments --- client/state-db/src/lib.rs | 4 ++- client/state-db/src/noncanonical.rs | 47 ++++++++++++++++++++++------- client/state-db/src/pruning.rs | 38 +++++++++++++++++++---- 3 files changed, 71 insertions(+), 18 deletions(-) diff --git a/client/state-db/src/lib.rs b/client/state-db/src/lib.rs index 6186a45f3d646..b6106ee81e839 100644 --- a/client/state-db/src/lib.rs +++ b/client/state-db/src/lib.rs @@ -56,6 +56,8 @@ use std::{ fmt, }; +const LOG_TARGET: &str = "state-db"; +const LOG_TARGET_PIN: &str = "state-db::pin"; const PRUNING_MODE: &[u8] = b"mode"; const PRUNING_MODE_ARCHIVE: &[u8] = b"archive"; const PRUNING_MODE_ARCHIVE_CANON: &[u8] = b"archive_canonical"; @@ -309,7 +311,7 @@ impl StateDbSync { ref_counting: bool, db: D, ) -> Result, Error> { - trace!(target: "state-db", "StateDb settings: {:?}. Ref-counting: {}", mode, ref_counting); + trace!(target: LOG_TARGET, "StateDb settings: {:?}. Ref-counting: {}", mode, ref_counting); let non_canonical: NonCanonicalOverlay = NonCanonicalOverlay::new(&db)?; let pruning: Option> = match mode { diff --git a/client/state-db/src/noncanonical.rs b/client/state-db/src/noncanonical.rs index e950d245dcec9..d6cc49a3d66b3 100644 --- a/client/state-db/src/noncanonical.rs +++ b/client/state-db/src/noncanonical.rs @@ -20,6 +20,8 @@ //! Maintains trees of block overlays and allows discarding trees/roots //! The overlays are added in `insert` and removed in `canonicalize`. +use crate::{LOG_TARGET, LOG_TARGET_PIN}; + use super::{to_meta_key, ChangeSet, CommitSet, DBValue, Error, Hash, MetaDb, StateDbError}; use codec::{Decode, Encode}; use log::trace; @@ -178,7 +180,12 @@ impl NonCanonicalOverlay { let mut values = HashMap::new(); if let Some((ref hash, mut block)) = last_canonicalized { // read the journal - trace!(target: "state-db", "Reading uncanonicalized journal. Last canonicalized #{} ({:?})", block, hash); + trace!( + target: LOG_TARGET, + "Reading uncanonicalized journal. Last canonicalized #{} ({:?})", + block, + hash + ); let mut total: u64 = 0; block += 1; loop { @@ -198,7 +205,7 @@ impl NonCanonicalOverlay { }; insert_values(&mut values, record.inserted); trace!( - target: "state-db", + target: LOG_TARGET, "Uncanonicalized journal entry {}.{} ({:?}) ({} inserted, {} deleted)", block, index, @@ -217,7 +224,11 @@ impl NonCanonicalOverlay { levels.push_back(level); block += 1; } - trace!(target: "state-db", "Finished reading uncanonicalized journal, {} entries", total); + trace!( + target: LOG_TARGET, + "Finished reading uncanonicalized journal, {} entries", + total + ); } Ok(NonCanonicalOverlay { last_canonicalized, @@ -252,7 +263,9 @@ impl NonCanonicalOverlay { } else if self.last_canonicalized.is_some() { if number < front_block_number || number > front_block_number + self.levels.len() as u64 { - trace!(target: "state-db", "Failed to insert block {}, current is {} .. {})", + trace!( + target: LOG_TARGET, + "Failed to insert block {}, current is {} .. {})", number, front_block_number, front_block_number + self.levels.len() as u64, @@ -284,7 +297,7 @@ impl NonCanonicalOverlay { if level.blocks.len() >= MAX_BLOCKS_PER_LEVEL as usize { trace!( - target: "state-db", + target: LOG_TARGET, "Too many sibling blocks at #{number}: {:?}", level.blocks.iter().map(|b| &b.hash).collect::>() ); @@ -314,7 +327,15 @@ 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, hash, journal_record.inserted.len(), journal_record.deleted.len()); + trace!( + target: LOG_TARGET, + "Inserted uncanonicalized changeset {}.{} {:?} ({} inserted, {} deleted)", + number, + index, + hash, + journal_record.inserted.len(), + journal_record.deleted.len() + ); insert_values(&mut self.values, journal_record.inserted); Ok(commit) } @@ -368,7 +389,7 @@ impl NonCanonicalOverlay { hash: &BlockHash, commit: &mut CommitSet, ) -> Result { - trace!(target: "state-db", "Canonicalizing {:?}", hash); + trace!(target: LOG_TARGET, "Canonicalizing {:?}", hash); let level = match self.levels.pop_front() { Some(level) => level, None => return Err(StateDbError::InvalidBlock), @@ -432,7 +453,7 @@ impl NonCanonicalOverlay { .meta .inserted .push((to_meta_key(LAST_CANONICAL, &()), canonicalized.encode())); - trace!(target: "state-db", "Discarding {} records", commit.meta.deleted.len()); + trace!(target: LOG_TARGET, "Discarding {} records", commit.meta.deleted.len()); let num = canonicalized.1; self.last_canonicalized = Some(canonicalized); @@ -479,7 +500,7 @@ impl NonCanonicalOverlay { }; // Check that it does not have any children if (level_index != level_count - 1) && self.parents.values().any(|h| h == hash) { - log::debug!(target: "state-db", "Trying to remove block {:?} with children", hash); + log::debug!(target: LOG_TARGET, "Trying to remove block {:?} with children", hash); return None } let overlay = level.remove(index); @@ -502,7 +523,7 @@ impl NonCanonicalOverlay { pub fn pin(&mut self, hash: &BlockHash) { let refs = self.pinned.entry(hash.clone()).or_default(); if *refs == 0 { - trace!(target: "state-db-pin", "Pinned non-canon block: {:?}", hash); + trace!(target: LOG_TARGET_PIN, "Pinned non-canon block: {:?}", hash); } *refs += 1; } @@ -531,7 +552,11 @@ impl NonCanonicalOverlay { entry.get_mut().1 -= 1; if entry.get().1 == 0 { let (inserted, _) = entry.remove(); - trace!(target: "state-db-pin", "Discarding unpinned non-canon block: {:?}", hash); + trace!( + target: LOG_TARGET_PIN, + "Discarding unpinned non-canon block: {:?}", + hash + ); discard_values(&mut self.values, inserted); self.parents.remove(&hash); } diff --git a/client/state-db/src/pruning.rs b/client/state-db/src/pruning.rs index d942fb2428b6a..16561bbe0ffd5 100644 --- a/client/state-db/src/pruning.rs +++ b/client/state-db/src/pruning.rs @@ -26,7 +26,7 @@ use crate::{ noncanonical::LAST_CANONICAL, to_meta_key, CommitSet, Error, Hash, MetaDb, StateDbError, - DEFAULT_MAX_BLOCK_CONSTRAINT, + DEFAULT_MAX_BLOCK_CONSTRAINT, LOG_TARGET, }; use codec::{Decode, Encode}; use log::trace; @@ -79,14 +79,24 @@ impl DeathRowQueue { death_index: HashMap::new(), }; // read the journal - trace!(target: "state-db", "Reading pruning journal for the memory queue. Pending #{}", base); + trace!( + target: LOG_TARGET, + "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)? { Some(record) => { 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()); + trace!( + target: LOG_TARGET, + "Pruning journal entry {} ({} inserted, {} deleted)", + block, + record.inserted.len(), + record.deleted.len(), + ); queue.import(base, block, record); }, None => break, @@ -107,7 +117,11 @@ impl DeathRowQueue { // 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); + trace!( + target: LOG_TARGET, + "Reading pruning journal for the database-backed queue. Pending #{}", + base + ); DeathRowQueue::load_batch_from_db(&db, &mut cache, base, cache_capacity)?; Ok(DeathRowQueue::DbBacked { db, cache, cache_capacity, last }) } @@ -115,13 +129,13 @@ impl DeathRowQueue { /// import a new block to the back of the queue 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); + trace!(target: LOG_TARGET, "Importing {}, base={}", num, base); match self { 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); + trace!(target: LOG_TARGET, "Adding to DB backed cache {:?} (#{})", hash, num); cache.push_back(DeathRow { hash, deleted: deleted.into_iter().collect() }); } *last = Some(num); @@ -306,6 +320,18 @@ impl RefWindow { }; let queue = if count_insertions { + // Highly scientific crafted number for deciding when to print the warning! + // + // Rocksdb doesn't support refcounting and requires that we load the entire pruning + // window into the memory. + if window_size > 1000 { + log::warn!( + target: LOG_TARGET, + "Large pruning window of {window_size} detected! THIS CAN LEAD TO HIGH MEMORY USAGE AND CRASHES. \ + Reduce the pruning window or switch your database to paritydb." + ); + } + DeathRowQueue::new_mem(&db, base)? } else { let last = match last_canonicalized_number { From 76208c89d77705b608776df069c200c36feba02f Mon Sep 17 00:00:00 2001 From: Dmitry Markin Date: Mon, 20 Feb 2023 15:08:02 +0300 Subject: [PATCH 413/715] Use async/await instead of manual polling of `NetworkWorker` (#13219) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Convert `NetworkWorker::poll()` into async `next_action()` * Use `NetworkWorker::next_action` instead of `poll` in `sc-network-test` * Revert "Use `NetworkWorker::next_action` instead of `poll` in `sc-network-test`" This reverts commit 4b5d851ec864f78f9d083a18a618fbe117c896d2. * Fix `sc-network-test` to poll `NetworkWorker::next_action` * Fix `sc_network::service` tests to poll `NetworkWorker::next_action` * Fix docs * kick CI * Factor out `next_worker_message()` & `next_swarm_event()` * Error handling: replace `futures::pending!()` with `expect()` * Simplify stream polling in `select!` * Replace `NetworkWorker::next_action()` with `run()` * Apply suggestions from code review Co-authored-by: Bastian Köcher * minor: comment * Apply suggestions from code review Co-authored-by: Bastian Köcher * Print debug log when network future is shut down * Evaluate `NetworkWorker::run()` future once before the loop * Fix client code to match new `NetworkService` interfaces * Make clippy happy * Apply suggestions from code review Co-authored-by: Bastian Köcher * Apply suggestions from code review Co-authored-by: Bastian Köcher * Revert "Apply suggestions from code review" This reverts commit 9fa646d0ed613e5f8623d3d37d1d59ec0a535850. * Make `NetworkWorker::run()` consume `self` * Terminate system RPC future if RPC rx stream has terminated. * Rewrite with let-else * Fix comments * Get `best_seen_block` and call `on_block_finalized` via `ChainSync` instead of `NetworkService` * rustfmt * make clippy happy * Tests: schedule wake if `next_action()` returned true * minor: comment * minor: fix `NetworkWorker` rustdoc * minor: amend the rustdoc * Fix bug that caused `on_demand_beefy_justification_sync` test to hang * rustfmt * Apply review suggestions --------- Co-authored-by: Bastian Köcher --- .../authority-discovery/src/worker/tests.rs | 4 + client/network/common/src/service.rs | 11 +- client/network/src/service.rs | 1190 +++++++++-------- .../network/src/service/tests/chain_sync.rs | 36 +- client/network/src/service/tests/mod.rs | 5 +- client/network/sync/src/lib.rs | 6 + client/network/sync/src/service/chain_sync.rs | 22 +- client/network/test/src/lib.rs | 17 +- client/offchain/src/api.rs | 4 + client/offchain/src/lib.rs | 4 + client/service/src/builder.rs | 30 +- client/service/src/lib.rs | 263 ++-- 12 files changed, 853 insertions(+), 739 deletions(-) diff --git a/client/authority-discovery/src/worker/tests.rs b/client/authority-discovery/src/worker/tests.rs index ce55728a1bfa6..7f3d113a83448 100644 --- a/client/authority-discovery/src/worker/tests.rs +++ b/client/authority-discovery/src/worker/tests.rs @@ -184,6 +184,10 @@ impl NetworkStateInfo for TestNetwork { fn external_addresses(&self) -> Vec { self.external_addresses.clone() } + + fn listen_addresses(&self) -> Vec { + self.external_addresses.clone() + } } struct TestSigner<'a> { diff --git a/client/network/common/src/service.rs b/client/network/common/src/service.rs index 54d254eac384f..f0f307800202f 100644 --- a/client/network/common/src/service.rs +++ b/client/network/common/src/service.rs @@ -180,13 +180,13 @@ pub trait NetworkPeers { /// purposes. fn deny_unreserved_peers(&self); - /// Adds a `PeerId` and its `Multiaddr` as reserved. + /// Adds a `PeerId` and its `Multiaddr` as reserved for a sync protocol (default peer set). /// /// 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: MultiaddrWithPeerId) -> Result<(), String>; - /// Removes a `PeerId` from the list of reserved peers. + /// Removes a `PeerId` from the list of reserved peers for a sync protocol (default peer set). fn remove_reserved_peer(&self, peer_id: PeerId); /// Sets the reserved set of a protocol to the given set of peers. @@ -359,6 +359,9 @@ pub trait NetworkStateInfo { /// Returns the local external addresses. fn external_addresses(&self) -> Vec; + /// Returns the listening addresses (without trailing `/p2p/` with our `PeerId`). + fn listen_addresses(&self) -> Vec; + /// Returns the local Peer ID. fn local_peer_id(&self) -> PeerId; } @@ -372,6 +375,10 @@ where T::external_addresses(self) } + fn listen_addresses(&self) -> Vec { + T::listen_addresses(self) + } + fn local_peer_id(&self) -> PeerId { T::local_peer_id(self) } diff --git a/client/network/src/service.rs b/client/network/src/service.rs index dbe148c899395..3c8856eaf8eff 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -19,13 +19,13 @@ //! Main entry point of the sc-network crate. //! //! There are two main structs in this module: [`NetworkWorker`] and [`NetworkService`]. -//! The [`NetworkWorker`] *is* the network and implements the `Future` trait. It must be polled in -//! order for the network to advance. +//! The [`NetworkWorker`] *is* the network. Network is driven by [`NetworkWorker::run`] future that +//! terminates only when all instances of the control handles [`NetworkService`] were dropped. //! The [`NetworkService`] is merely a shared version of the [`NetworkWorker`]. You can obtain an //! `Arc` by calling [`NetworkWorker::service`]. //! //! The methods of the [`NetworkService`] are implemented by sending a message over a channel, -//! which is then processed by [`NetworkWorker::poll`]. +//! which is then processed by [`NetworkWorker::next_action`]. use crate::{ behaviour::{self, Behaviour, BehaviourOut}, @@ -46,8 +46,9 @@ use libp2p::{ multiaddr, ping::Failure as PingFailure, swarm::{ - AddressScore, ConnectionError, ConnectionLimits, DialError, Executor, NetworkBehaviour, - PendingConnectionError, Swarm, SwarmBuilder, SwarmEvent, + AddressScore, ConnectionError, ConnectionHandler, ConnectionLimits, DialError, Executor, + IntoConnectionHandler, NetworkBehaviour, PendingConnectionError, Swarm, SwarmBuilder, + SwarmEvent, }, Multiaddr, PeerId, }; @@ -87,7 +88,6 @@ use std::{ atomic::{AtomicBool, AtomicUsize, Ordering}, Arc, }, - task::Poll, }; pub use behaviour::{InboundFailure, OutboundFailure, ResponseFailure}; @@ -100,12 +100,20 @@ mod tests; pub use libp2p::identity::{error::DecodingError, Keypair, PublicKey}; use sc_network_common::service::{NetworkBlock, NetworkRequest}; +/// Custom error that can be produced by the [`ConnectionHandler`] of the [`NetworkBehaviour`]. +/// Used as a template parameter of [`SwarmEvent`] below. +type ConnectionHandlerErr = + <<::ConnectionHandler as IntoConnectionHandler> + ::Handler as ConnectionHandler>::Error; + /// Substrate network service. Handles network IO and manages connectivity. pub struct NetworkService { /// Number of peers we're connected to. num_connected: Arc, /// The local external addresses. external_addresses: Arc>>, + /// Listen addresses. Do **NOT** include a trailing `/p2p/` with our `PeerId`. + listen_addresses: Arc>>, /// Are we actively catching up with the chain? is_major_syncing: Arc, /// Local copy of the `PeerId` of the local node. @@ -434,11 +442,13 @@ where } let external_addresses = Arc::new(Mutex::new(Vec::new())); + let listen_addresses = Arc::new(Mutex::new(Vec::new())); let peers_notifications_sinks = Arc::new(Mutex::new(HashMap::new())); let service = Arc::new(NetworkService { bandwidth, external_addresses: external_addresses.clone(), + listen_addresses: listen_addresses.clone(), num_connected: num_connected.clone(), is_major_syncing: is_major_syncing.clone(), peerset: peerset_handle, @@ -455,6 +465,7 @@ where Ok(NetworkWorker { external_addresses, + listen_addresses, num_connected, is_major_syncing, network_service: swarm, @@ -711,6 +722,34 @@ impl NetworkService { } } + /// Get connected peers debug information. + /// + /// Returns an error if the `NetworkWorker` is no longer running. + pub async fn peers_debug_info(&self) -> Result)>, ()> { + let (tx, rx) = oneshot::channel(); + + let _ = self + .to_worker + .unbounded_send(ServiceToWorkerMsg::PeersDebugInfo { pending_response: tx }); + + // The channel can only be closed if the network worker no longer exists. + rx.await.map_err(|_| ()) + } + + /// Get the list of reserved peers. + /// + /// Returns an error if the `NetworkWorker` is no longer running. + pub async fn reserved_peers(&self) -> Result, ()> { + let (tx, rx) = oneshot::channel(); + + let _ = self + .to_worker + .unbounded_send(ServiceToWorkerMsg::ReservedPeers { pending_response: tx }); + + // The channel can only be closed if the network worker no longer exists. + rx.await.map_err(|_| ()) + } + /// 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 @@ -774,6 +813,11 @@ where self.external_addresses.lock().clone() } + /// Returns the listener addresses (without trailing `/p2p/` with our `PeerId`). + fn listen_addresses(&self) -> Vec { + self.listen_addresses.lock().clone() + } + /// Returns the local Peer ID. fn local_peer_id(&self) -> PeerId { self.local_peer_id @@ -1243,6 +1287,12 @@ enum ServiceToWorkerMsg { }, DisconnectPeer(PeerId, ProtocolName), NewBestBlockImported(B::Hash, NumberFor), + PeersDebugInfo { + pending_response: oneshot::Sender)>>, + }, + ReservedPeers { + pending_response: oneshot::Sender>, + }, } /// Main network worker. Must be polled in order for the network to advance. @@ -1258,6 +1308,8 @@ where /// Updated by the `NetworkWorker` and loaded by the `NetworkService`. external_addresses: Arc>>, /// Updated by the `NetworkWorker` and loaded by the `NetworkService`. + listen_addresses: Arc>>, + /// Updated by the `NetworkWorker` and loaded by the `NetworkService`. num_connected: Arc, /// Updated by the `NetworkWorker` and loaded by the `NetworkService`. is_major_syncing: Arc, @@ -1281,637 +1333,595 @@ where _marker: PhantomData, } -impl Future for NetworkWorker +impl NetworkWorker where B: BlockT + 'static, H: ExHashT, Client: HeaderBackend + 'static, { - type Output = (); - - fn poll(mut self: Pin<&mut Self>, cx: &mut std::task::Context) -> Poll { - let this = &mut *self; - - // 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 - // freeze, a limit to the number of iterations is enforced below. If the limit is reached, - // the task is interrupted then scheduled again. - // - // This allows for a more even distribution in the time taken by each sub-part of the - // polling. - let mut num_iterations = 0; - loop { - num_iterations += 1; - if num_iterations >= 100 { - cx.waker().wake_by_ref(); - break - } + /// Run the network. + pub async fn run(mut self) { + while self.next_action().await {} + } - // Process the next message coming from the `NetworkService`. - let msg = match this.from_service.poll_next_unpin(cx) { - Poll::Ready(Some(msg)) => msg, - Poll::Ready(None) => return Poll::Ready(()), - Poll::Pending => break, - }; - match msg { - ServiceToWorkerMsg::AnnounceBlock(hash, data) => this - .network_service - .behaviour_mut() - .user_protocol_mut() - .announce_block(hash, data), - ServiceToWorkerMsg::GetValue(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 - .network_service - .behaviour_mut() - .user_protocol_mut() - .set_reserved_only(reserved_only), - ServiceToWorkerMsg::SetReserved(peers) => this - .network_service - .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() - .user_protocol_mut() - .add_reserved_peer(peer_id), - ServiceToWorkerMsg::RemoveReserved(peer_id) => this - .network_service - .behaviour_mut() - .user_protocol_mut() - .remove_reserved_peer(peer_id), - ServiceToWorkerMsg::AddSetReserved(protocol, peer_id) => this - .network_service - .behaviour_mut() - .user_protocol_mut() - .add_set_reserved_peer(protocol, peer_id), - ServiceToWorkerMsg::RemoveSetReserved(protocol, peer_id) => this - .network_service - .behaviour_mut() - .user_protocol_mut() - .remove_set_reserved_peer(protocol, peer_id), - ServiceToWorkerMsg::AddKnownAddress(peer_id, addr) => - this.network_service.behaviour_mut().add_known_address(peer_id, addr), - ServiceToWorkerMsg::AddToPeersSet(protocol, peer_id) => this - .network_service - .behaviour_mut() - .user_protocol_mut() - .add_to_peers_set(protocol, peer_id), - ServiceToWorkerMsg::RemoveFromPeersSet(protocol, peer_id) => this - .network_service - .behaviour_mut() - .user_protocol_mut() - .remove_from_peers_set(protocol, peer_id), - ServiceToWorkerMsg::EventStream(sender) => this.event_streams.push(sender), - ServiceToWorkerMsg::Request { - target, - protocol, - request, - pending_response, - connect, - } => { - this.network_service.behaviour_mut().send_request( - &target, - &protocol, - request, - pending_response, - connect, - ); - }, - ServiceToWorkerMsg::NetworkStatus { pending_response } => { - let _ = pending_response.send(Ok(this.status())); - }, - ServiceToWorkerMsg::NetworkState { pending_response } => { - let _ = pending_response.send(Ok(this.network_state())); - }, - ServiceToWorkerMsg::DisconnectPeer(who, protocol_name) => this - .network_service - .behaviour_mut() - .user_protocol_mut() - .disconnect_peer(&who, protocol_name), - ServiceToWorkerMsg::NewBestBlockImported(hash, number) => this - .network_service - .behaviour_mut() - .user_protocol_mut() - .new_best_block_imported(hash, number), - } + /// Perform one action on the network. + /// + /// Returns `false` when the worker should be shutdown. + /// Use in tests only. + pub async fn next_action(&mut self) -> bool { + futures::select! { + // Next message from the service. + msg = self.from_service.next() => { + if let Some(msg) = msg { + self.handle_worker_message(msg); + } else { + return false + } + }, + // Next event from `Swarm` (the stream guaranteed to never terminate). + event = self.network_service.select_next_some() => { + self.handle_swarm_event(event); + }, + }; + + let num_connected_peers = + self.network_service.behaviour_mut().user_protocol_mut().num_connected_peers(); + + // Update the variables shared with the `NetworkService`. + self.num_connected.store(num_connected_peers, Ordering::Relaxed); + { + let external_addresses = + self.network_service.external_addresses().map(|r| &r.addr).cloned().collect(); + *self.external_addresses.lock() = external_addresses; + + let listen_addresses = + self.network_service.listeners().map(ToOwned::to_owned).collect(); + *self.listen_addresses.lock() = listen_addresses; } - // `num_iterations` serves the same purpose as in the previous loop. - // See the previous loop for explanations. - let mut num_iterations = 0; - loop { - num_iterations += 1; - if num_iterations >= 1000 { - cx.waker().wake_by_ref(); - break + let is_major_syncing = self + .network_service + .behaviour_mut() + .user_protocol_mut() + .sync_state() + .state + .is_major_syncing(); + + self.is_major_syncing.store(is_major_syncing, Ordering::Relaxed); + + if let Some(metrics) = self.metrics.as_ref() { + if let Some(buckets) = self.network_service.behaviour_mut().num_entries_per_kbucket() { + for (lower_ilog2_bucket_bound, num_entries) in buckets { + metrics + .kbuckets_num_nodes + .with_label_values(&[&lower_ilog2_bucket_bound.to_string()]) + .set(num_entries as u64); + } + } + if let Some(num_entries) = self.network_service.behaviour_mut().num_kademlia_records() { + metrics.kademlia_records_count.set(num_entries as u64); + } + if let Some(num_entries) = + self.network_service.behaviour_mut().kademlia_records_total_size() + { + metrics.kademlia_records_sizes_total.set(num_entries as u64); } + metrics + .peerset_num_discovered + .set(self.network_service.behaviour_mut().user_protocol().num_discovered_peers() + as u64); + metrics.pending_connections.set( + Swarm::network_info(&self.network_service).connection_counters().num_pending() + as u64, + ); + } - // Process the next action coming from the network. - let next_event = this.network_service.select_next_some(); - futures::pin_mut!(next_event); - let poll_value = next_event.poll_unpin(cx); + true + } - match poll_value { - Poll::Pending => break, - Poll::Ready(SwarmEvent::Behaviour(BehaviourOut::InboundRequest { - protocol, - result, - .. - })) => { - if let Some(metrics) = this.metrics.as_ref() { - match result { - Ok(serve_time) => { - metrics - .requests_in_success_total - .with_label_values(&[&protocol]) - .observe(serve_time.as_secs_f64()); - }, - Err(err) => { - let reason = match err { - ResponseFailure::Network(InboundFailure::Timeout) => "timeout", - ResponseFailure::Network( - InboundFailure::UnsupportedProtocols, - ) => - // `UnsupportedProtocols` is reported for every single - // inbound request whenever a request with an unsupported - // protocol is received. This is not reported in order to - // avoid confusions. - continue, - ResponseFailure::Network(InboundFailure::ResponseOmission) => - "busy-omitted", - ResponseFailure::Network(InboundFailure::ConnectionClosed) => - "connection-closed", - }; + /// Process the next message coming from the `NetworkService`. + fn handle_worker_message(&mut self, msg: ServiceToWorkerMsg) { + match msg { + ServiceToWorkerMsg::AnnounceBlock(hash, data) => self + .network_service + .behaviour_mut() + .user_protocol_mut() + .announce_block(hash, data), + ServiceToWorkerMsg::GetValue(key) => + self.network_service.behaviour_mut().get_value(key), + ServiceToWorkerMsg::PutValue(key, value) => + self.network_service.behaviour_mut().put_value(key, value), + ServiceToWorkerMsg::SetReservedOnly(reserved_only) => self + .network_service + .behaviour_mut() + .user_protocol_mut() + .set_reserved_only(reserved_only), + ServiceToWorkerMsg::SetReserved(peers) => self + .network_service + .behaviour_mut() + .user_protocol_mut() + .set_reserved_peers(peers), + ServiceToWorkerMsg::SetPeersetReserved(protocol, peers) => self + .network_service + .behaviour_mut() + .user_protocol_mut() + .set_reserved_peerset_peers(protocol, peers), + ServiceToWorkerMsg::AddReserved(peer_id) => self + .network_service + .behaviour_mut() + .user_protocol_mut() + .add_reserved_peer(peer_id), + ServiceToWorkerMsg::RemoveReserved(peer_id) => self + .network_service + .behaviour_mut() + .user_protocol_mut() + .remove_reserved_peer(peer_id), + ServiceToWorkerMsg::AddSetReserved(protocol, peer_id) => self + .network_service + .behaviour_mut() + .user_protocol_mut() + .add_set_reserved_peer(protocol, peer_id), + ServiceToWorkerMsg::RemoveSetReserved(protocol, peer_id) => self + .network_service + .behaviour_mut() + .user_protocol_mut() + .remove_set_reserved_peer(protocol, peer_id), + ServiceToWorkerMsg::AddKnownAddress(peer_id, addr) => + self.network_service.behaviour_mut().add_known_address(peer_id, addr), + ServiceToWorkerMsg::AddToPeersSet(protocol, peer_id) => self + .network_service + .behaviour_mut() + .user_protocol_mut() + .add_to_peers_set(protocol, peer_id), + ServiceToWorkerMsg::RemoveFromPeersSet(protocol, peer_id) => self + .network_service + .behaviour_mut() + .user_protocol_mut() + .remove_from_peers_set(protocol, peer_id), + ServiceToWorkerMsg::EventStream(sender) => self.event_streams.push(sender), + ServiceToWorkerMsg::Request { + target, + protocol, + request, + pending_response, + connect, + } => { + self.network_service.behaviour_mut().send_request( + &target, + &protocol, + request, + pending_response, + connect, + ); + }, + ServiceToWorkerMsg::NetworkStatus { pending_response } => { + let _ = pending_response.send(Ok(self.status())); + }, + ServiceToWorkerMsg::NetworkState { pending_response } => { + let _ = pending_response.send(Ok(self.network_state())); + }, + ServiceToWorkerMsg::DisconnectPeer(who, protocol_name) => self + .network_service + .behaviour_mut() + .user_protocol_mut() + .disconnect_peer(&who, protocol_name), + ServiceToWorkerMsg::NewBestBlockImported(hash, number) => self + .network_service + .behaviour_mut() + .user_protocol_mut() + .new_best_block_imported(hash, number), + ServiceToWorkerMsg::PeersDebugInfo { pending_response } => { + let _ = pending_response.send(self.peers_debug_info()); + }, + ServiceToWorkerMsg::ReservedPeers { pending_response } => { + let _ = + pending_response.send(self.reserved_peers().map(ToOwned::to_owned).collect()); + }, + } + } + /// Process the next event coming from `Swarm`. + fn handle_swarm_event( + &mut self, + event: SwarmEvent>>, + ) { + match event { + SwarmEvent::Behaviour(BehaviourOut::InboundRequest { protocol, result, .. }) => { + if let Some(metrics) = self.metrics.as_ref() { + match result { + Ok(serve_time) => { + metrics + .requests_in_success_total + .with_label_values(&[&protocol]) + .observe(serve_time.as_secs_f64()); + }, + Err(err) => { + let reason = match err { + ResponseFailure::Network(InboundFailure::Timeout) => + Some("timeout"), + ResponseFailure::Network(InboundFailure::UnsupportedProtocols) => + // `UnsupportedProtocols` is reported for every single + // inbound request whenever a request with an unsupported + // protocol is received. This is not reported in order to + // avoid confusions. + None, + ResponseFailure::Network(InboundFailure::ResponseOmission) => + Some("busy-omitted"), + ResponseFailure::Network(InboundFailure::ConnectionClosed) => + Some("connection-closed"), + }; + + if let Some(reason) = reason { metrics .requests_in_failure_total .with_label_values(&[&protocol, reason]) .inc(); - }, - } + } + }, } - }, - Poll::Ready(SwarmEvent::Behaviour(BehaviourOut::RequestFinished { - protocol, - duration, - result, - .. - })) => - if let Some(metrics) = this.metrics.as_ref() { - match result { - Ok(_) => { - metrics - .requests_out_success_total - .with_label_values(&[&protocol]) - .observe(duration.as_secs_f64()); - }, - Err(err) => { - let reason = match err { - RequestFailure::NotConnected => "not-connected", - RequestFailure::UnknownProtocol => "unknown-protocol", - RequestFailure::Refused => "refused", - RequestFailure::Obsolete => "obsolete", - RequestFailure::Network(OutboundFailure::DialFailure) => - "dial-failure", - RequestFailure::Network(OutboundFailure::Timeout) => "timeout", - RequestFailure::Network(OutboundFailure::ConnectionClosed) => - "connection-closed", - RequestFailure::Network( - OutboundFailure::UnsupportedProtocols, - ) => "unsupported", - }; + } + }, + SwarmEvent::Behaviour(BehaviourOut::RequestFinished { + protocol, + duration, + result, + .. + }) => + if let Some(metrics) = self.metrics.as_ref() { + match result { + Ok(_) => { + metrics + .requests_out_success_total + .with_label_values(&[&protocol]) + .observe(duration.as_secs_f64()); + }, + Err(err) => { + let reason = match err { + RequestFailure::NotConnected => "not-connected", + RequestFailure::UnknownProtocol => "unknown-protocol", + RequestFailure::Refused => "refused", + RequestFailure::Obsolete => "obsolete", + RequestFailure::Network(OutboundFailure::DialFailure) => + "dial-failure", + RequestFailure::Network(OutboundFailure::Timeout) => "timeout", + RequestFailure::Network(OutboundFailure::ConnectionClosed) => + "connection-closed", + RequestFailure::Network(OutboundFailure::UnsupportedProtocols) => + "unsupported", + }; - metrics - .requests_out_failure_total - .with_label_values(&[&protocol, reason]) - .inc(); - }, - } - }, - 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, - .. + metrics + .requests_out_failure_total + .with_label_values(&[&protocol, reason]) + .inc(); }, - })) => { - 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)); + SwarmEvent::Behaviour(BehaviourOut::ReputationChanges { peer, changes }) => + for change in changes { + self.network_service.behaviour().user_protocol().report_peer(peer, change); }, - Poll::Ready(SwarmEvent::Behaviour(BehaviourOut::RandomKademliaStarted)) => - if let Some(metrics) = this.metrics.as_ref() { - metrics.kademlia_random_queries_total.inc(); + SwarmEvent::Behaviour(BehaviourOut::PeerIdentify { + peer_id, + info: + IdentifyInfo { + protocol_version, agent_version, mut listen_addrs, protocols, .. }, - Poll::Ready(SwarmEvent::Behaviour(BehaviourOut::NotificationStreamOpened { + }) => { + 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.network_service + .behaviour_mut() + .add_self_reported_address_to_dht(&peer_id, &protocols, addr); + } + self.network_service + .behaviour_mut() + .user_protocol_mut() + .add_default_set_discovered_nodes(iter::once(peer_id)); + }, + SwarmEvent::Behaviour(BehaviourOut::Discovered(peer_id)) => { + self.network_service + .behaviour_mut() + .user_protocol_mut() + .add_default_set_discovered_nodes(iter::once(peer_id)); + }, + SwarmEvent::Behaviour(BehaviourOut::RandomKademliaStarted) => + if let Some(metrics) = self.metrics.as_ref() { + metrics.kademlia_random_queries_total.inc(); + }, + SwarmEvent::Behaviour(BehaviourOut::NotificationStreamOpened { + remote, + protocol, + negotiated_fallback, + notifications_sink, + role, + }) => { + if let Some(metrics) = self.metrics.as_ref() { + metrics + .notifications_streams_opened_total + .with_label_values(&[&protocol]) + .inc(); + } + { + let mut peers_notifications_sinks = self.peers_notifications_sinks.lock(); + let _previous_value = peers_notifications_sinks + .insert((remote, protocol.clone()), notifications_sink); + debug_assert!(_previous_value.is_none()); + } + self.event_streams.send(Event::NotificationStreamOpened { remote, protocol, negotiated_fallback, - notifications_sink, role, - })) => { - if let Some(metrics) = this.metrics.as_ref() { - metrics - .notifications_streams_opened_total - .with_label_values(&[&protocol]) - .inc(); - } - { - let mut peers_notifications_sinks = this.peers_notifications_sinks.lock(); - let _previous_value = peers_notifications_sinks - .insert((remote, protocol.clone()), notifications_sink); - debug_assert!(_previous_value.is_none()); - } - this.event_streams.send(Event::NotificationStreamOpened { - remote, - protocol, - negotiated_fallback, - role, - }); - }, - Poll::Ready(SwarmEvent::Behaviour(BehaviourOut::NotificationStreamReplaced { - remote, - protocol, - notifications_sink, - })) => { - let mut peers_notifications_sinks = this.peers_notifications_sinks.lock(); - if let Some(s) = peers_notifications_sinks.get_mut(&(remote, protocol)) { - *s = notifications_sink; - } else { - error!( - target: "sub-libp2p", - "NotificationStreamReplaced for non-existing substream" - ); - debug_assert!(false); - } + }); + }, + SwarmEvent::Behaviour(BehaviourOut::NotificationStreamReplaced { + remote, + protocol, + notifications_sink, + }) => { + let mut peers_notifications_sinks = self.peers_notifications_sinks.lock(); + if let Some(s) = peers_notifications_sinks.get_mut(&(remote, protocol)) { + *s = notifications_sink; + } else { + error!( + target: "sub-libp2p", + "NotificationStreamReplaced for non-existing substream" + ); + debug_assert!(false); + } - // TODO: Notifications might have been lost as a result of the previous - // connection being dropped, and as a result it would be preferable to notify - // the users of this fact by simulating the substream being closed then - // reopened. - // The code below doesn't compile because `role` is unknown. Propagating the - // handshake of the secondary connections is quite an invasive change and - // would conflict with https://github.com/paritytech/substrate/issues/6403. - // Considering that dropping notifications is generally regarded as - // acceptable, this bug is at the moment intentionally left there and is - // intended to be fixed at the same time as - // https://github.com/paritytech/substrate/issues/6403. - // this.event_streams.send(Event::NotificationStreamClosed { - // remote, - // protocol, - // }); - // this.event_streams.send(Event::NotificationStreamOpened { - // remote, - // protocol, - // role, - // }); - }, - Poll::Ready(SwarmEvent::Behaviour(BehaviourOut::NotificationStreamClosed { - remote, - protocol, - })) => { - if let Some(metrics) = this.metrics.as_ref() { - metrics - .notifications_streams_closed_total - .with_label_values(&[&protocol[..]]) - .inc(); - } - this.event_streams.send(Event::NotificationStreamClosed { - remote, - protocol: protocol.clone(), - }); - { - let mut peers_notifications_sinks = this.peers_notifications_sinks.lock(); - let _previous_value = peers_notifications_sinks.remove(&(remote, protocol)); - debug_assert!(_previous_value.is_some()); - } - }, - Poll::Ready(SwarmEvent::Behaviour(BehaviourOut::NotificationsReceived { - remote, - messages, - })) => { - if let Some(metrics) = this.metrics.as_ref() { - for (protocol, message) in &messages { - metrics - .notifications_sizes - .with_label_values(&["in", protocol]) - .observe(message.len() as f64); - } - } - this.event_streams.send(Event::NotificationsReceived { remote, messages }); - }, - Poll::Ready(SwarmEvent::Behaviour(BehaviourOut::SyncConnected(remote))) => { - this.event_streams.send(Event::SyncConnected { remote }); - }, - Poll::Ready(SwarmEvent::Behaviour(BehaviourOut::SyncDisconnected(remote))) => { - this.event_streams.send(Event::SyncDisconnected { remote }); - }, - Poll::Ready(SwarmEvent::Behaviour(BehaviourOut::Dht(event, duration))) => { - if let Some(metrics) = this.metrics.as_ref() { - let query_type = match event { - DhtEvent::ValueFound(_) => "value-found", - DhtEvent::ValueNotFound(_) => "value-not-found", - DhtEvent::ValuePut(_) => "value-put", - DhtEvent::ValuePutFailed(_) => "value-put-failed", - }; + // TODO: Notifications might have been lost as a result of the previous + // connection being dropped, and as a result it would be preferable to notify + // the users of this fact by simulating the substream being closed then + // reopened. + // The code below doesn't compile because `role` is unknown. Propagating the + // handshake of the secondary connections is quite an invasive change and + // would conflict with https://github.com/paritytech/substrate/issues/6403. + // Considering that dropping notifications is generally regarded as + // acceptable, this bug is at the moment intentionally left there and is + // intended to be fixed at the same time as + // https://github.com/paritytech/substrate/issues/6403. + // self.event_streams.send(Event::NotificationStreamClosed { + // remote, + // protocol, + // }); + // self.event_streams.send(Event::NotificationStreamOpened { + // remote, + // protocol, + // role, + // }); + }, + SwarmEvent::Behaviour(BehaviourOut::NotificationStreamClosed { remote, protocol }) => { + if let Some(metrics) = self.metrics.as_ref() { + metrics + .notifications_streams_closed_total + .with_label_values(&[&protocol[..]]) + .inc(); + } + self.event_streams + .send(Event::NotificationStreamClosed { remote, protocol: protocol.clone() }); + { + let mut peers_notifications_sinks = self.peers_notifications_sinks.lock(); + let _previous_value = peers_notifications_sinks.remove(&(remote, protocol)); + debug_assert!(_previous_value.is_some()); + } + }, + SwarmEvent::Behaviour(BehaviourOut::NotificationsReceived { remote, messages }) => { + if let Some(metrics) = self.metrics.as_ref() { + for (protocol, message) in &messages { metrics - .kademlia_query_duration - .with_label_values(&[query_type]) - .observe(duration.as_secs_f64()); + .notifications_sizes + .with_label_values(&["in", protocol]) + .observe(message.len() as f64); } + } + self.event_streams.send(Event::NotificationsReceived { remote, messages }); + }, + SwarmEvent::Behaviour(BehaviourOut::SyncConnected(remote)) => { + self.event_streams.send(Event::SyncConnected { remote }); + }, + SwarmEvent::Behaviour(BehaviourOut::SyncDisconnected(remote)) => { + self.event_streams.send(Event::SyncDisconnected { remote }); + }, + SwarmEvent::Behaviour(BehaviourOut::Dht(event, duration)) => { + if let Some(metrics) = self.metrics.as_ref() { + let query_type = match event { + DhtEvent::ValueFound(_) => "value-found", + DhtEvent::ValueNotFound(_) => "value-not-found", + DhtEvent::ValuePut(_) => "value-put", + DhtEvent::ValuePutFailed(_) => "value-put-failed", + }; + metrics + .kademlia_query_duration + .with_label_values(&[query_type]) + .observe(duration.as_secs_f64()); + } - 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, - num_established, - concurrent_dial_errors, - }) => { - 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); - } + self.event_streams.send(Event::Dht(event)); + }, + SwarmEvent::Behaviour(BehaviourOut::None) => { + // Ignored event from lower layers. + }, + SwarmEvent::ConnectionEstablished { + peer_id, + endpoint, + num_established, + concurrent_dial_errors, + } => { + 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 { - ConnectedPoint::Dialer { .. } => "out", - ConnectedPoint::Listener { .. } => "in", - }; - metrics.connections_opened_total.with_label_values(&[direction]).inc(); + if let Some(metrics) = self.metrics.as_ref() { + let direction = match endpoint { + ConnectedPoint::Dialer { .. } => "out", + ConnectedPoint::Listener { .. } => "in", + }; + metrics.connections_opened_total.with_label_values(&[direction]).inc(); - if num_established.get() == 1 { - metrics.distinct_peers_connections_opened_total.inc(); - } + if num_established.get() == 1 { + metrics.distinct_peers_connections_opened_total.inc(); } - }, - Poll::Ready(SwarmEvent::ConnectionClosed { - peer_id, - cause, - endpoint, - num_established, - }) => { - debug!(target: "sub-libp2p", "Libp2p => Disconnected({:?}, {:?})", peer_id, cause); - if let Some(metrics) = this.metrics.as_ref() { - let direction = match endpoint { - ConnectedPoint::Dialer { .. } => "out", - ConnectedPoint::Listener { .. } => "in", - }; - let reason = match cause { - Some(ConnectionError::IO(_)) => "transport-error", - Some(ConnectionError::Handler(EitherError::A(EitherError::A( - EitherError::B(EitherError::A(PingFailure::Timeout)), - )))) => "ping-timeout", - Some(ConnectionError::Handler(EitherError::A(EitherError::A( - EitherError::A(NotifsHandlerError::SyncNotificationsClogged), - )))) => "sync-notifications-clogged", - Some(ConnectionError::Handler(_)) => "protocol-error", - Some(ConnectionError::KeepAliveTimeout) => "keep-alive-timeout", - None => "actively-closed", - }; - metrics - .connections_closed_total - .with_label_values(&[direction, reason]) - .inc(); + } + }, + SwarmEvent::ConnectionClosed { peer_id, cause, endpoint, num_established } => { + debug!(target: "sub-libp2p", "Libp2p => Disconnected({:?}, {:?})", peer_id, cause); + if let Some(metrics) = self.metrics.as_ref() { + let direction = match endpoint { + ConnectedPoint::Dialer { .. } => "out", + ConnectedPoint::Listener { .. } => "in", + }; + let reason = match cause { + Some(ConnectionError::IO(_)) => "transport-error", + Some(ConnectionError::Handler(EitherError::A(EitherError::A( + EitherError::B(EitherError::A(PingFailure::Timeout)), + )))) => "ping-timeout", + Some(ConnectionError::Handler(EitherError::A(EitherError::A( + EitherError::A(NotifsHandlerError::SyncNotificationsClogged), + )))) => "sync-notifications-clogged", + Some(ConnectionError::Handler(_)) => "protocol-error", + Some(ConnectionError::KeepAliveTimeout) => "keep-alive-timeout", + None => "actively-closed", + }; + metrics.connections_closed_total.with_label_values(&[direction, reason]).inc(); - // `num_established` represents the number of *remaining* connections. - if num_established == 0 { - metrics.distinct_peers_connections_closed_total.inc(); - } - } - }, - Poll::Ready(SwarmEvent::NewListenAddr { address, .. }) => { - trace!(target: "sub-libp2p", "Libp2p => NewListenAddr({})", address); - if let Some(metrics) = this.metrics.as_ref() { - metrics.listeners_local_addresses.inc(); - } - }, - Poll::Ready(SwarmEvent::ExpiredListenAddr { address, .. }) => { - info!(target: "sub-libp2p", "📪 No longer listening on {}", address); - if let Some(metrics) = this.metrics.as_ref() { - metrics.listeners_local_addresses.dec(); + // `num_established` represents the number of *remaining* connections. + if num_established == 0 { + metrics.distinct_peers_connections_closed_total.inc(); } - }, - 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 DialError::WrongPeerId { obtained, endpoint } = &error { - if let ConnectedPoint::Dialer { address, role_override: _ } = - endpoint - { - warn!( - "💔 The bootnode you want to connect to at `{}` provided a different peer ID `{}` than the one you expect `{}`.", - address, - obtained, - peer_id, - ); - } + } + }, + SwarmEvent::NewListenAddr { address, .. } => { + trace!(target: "sub-libp2p", "Libp2p => NewListenAddr({})", address); + if let Some(metrics) = self.metrics.as_ref() { + metrics.listeners_local_addresses.inc(); + } + }, + SwarmEvent::ExpiredListenAddr { address, .. } => { + info!(target: "sub-libp2p", "📪 No longer listening on {}", address); + if let Some(metrics) = self.metrics.as_ref() { + metrics.listeners_local_addresses.dec(); + } + }, + SwarmEvent::OutgoingConnectionError { peer_id, error } => { + if let Some(peer_id) = peer_id { + trace!( + target: "sub-libp2p", + "Libp2p => Failed to reach {:?}: {}", + peer_id, error, + ); + + if self.boot_node_ids.contains(&peer_id) { + if let DialError::WrongPeerId { obtained, endpoint } = &error { + if let ConnectedPoint::Dialer { address, role_override: _ } = endpoint { + warn!( + "💔 The bootnode you want to connect to at `{}` provided a different peer ID `{}` than the one you expect `{}`.", + address, + obtained, + peer_id, + ); } } } + } - if let Some(metrics) = this.metrics.as_ref() { - 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::WrongPeerId { .. } | - DialError::Aborted => None, // ignore them - }; - if let Some(reason) = reason { - metrics - .pending_connections_errors_total - .with_label_values(&[reason]) - .inc(); - } - } - }, - Poll::Ready(SwarmEvent::Dialing(peer_id)) => { - trace!(target: "sub-libp2p", "Libp2p => Dialing({:?})", peer_id) - }, - Poll::Ready(SwarmEvent::IncomingConnection { local_addr, send_back_addr }) => { - trace!(target: "sub-libp2p", "Libp2p => IncomingConnection({},{}))", - local_addr, send_back_addr); - if let Some(metrics) = this.metrics.as_ref() { - metrics.incoming_connections_total.inc(); - } - }, - Poll::Ready(SwarmEvent::IncomingConnectionError { - local_addr, - send_back_addr, - error, - }) => { - debug!( - target: "sub-libp2p", - "Libp2p => IncomingConnectionError({},{}): {}", - local_addr, send_back_addr, error, - ); - if let Some(metrics) = this.metrics.as_ref() { - let reason = match error { - PendingConnectionError::ConnectionLimit(_) => Some("limit-reached"), - PendingConnectionError::WrongPeerId { .. } => Some("invalid-peer-id"), - PendingConnectionError::Transport(_) | - PendingConnectionError::IO(_) => Some("transport-error"), - PendingConnectionError::Aborted => None, // ignore it - }; - - if let Some(reason) = reason { - metrics - .incoming_connections_errors_total - .with_label_values(&[reason]) - .inc(); - } + if let Some(metrics) = self.metrics.as_ref() { + 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::WrongPeerId { .. } | + DialError::Aborted => None, // ignore them + }; + if let Some(reason) = reason { + metrics.pending_connections_errors_total.with_label_values(&[reason]).inc(); } - }, - Poll::Ready(SwarmEvent::BannedPeer { peer_id, endpoint }) => { - debug!( - target: "sub-libp2p", - "Libp2p => BannedPeer({}). Connected via {:?}.", - peer_id, endpoint, - ); - if let Some(metrics) = this.metrics.as_ref() { + } + }, + SwarmEvent::Dialing(peer_id) => { + trace!(target: "sub-libp2p", "Libp2p => Dialing({:?})", peer_id) + }, + SwarmEvent::IncomingConnection { local_addr, send_back_addr } => { + trace!(target: "sub-libp2p", "Libp2p => IncomingConnection({},{}))", + local_addr, send_back_addr); + if let Some(metrics) = self.metrics.as_ref() { + metrics.incoming_connections_total.inc(); + } + }, + SwarmEvent::IncomingConnectionError { local_addr, send_back_addr, error } => { + debug!( + target: "sub-libp2p", + "Libp2p => IncomingConnectionError({},{}): {}", + local_addr, send_back_addr, error, + ); + if let Some(metrics) = self.metrics.as_ref() { + let reason = match error { + PendingConnectionError::ConnectionLimit(_) => Some("limit-reached"), + PendingConnectionError::WrongPeerId { .. } => Some("invalid-peer-id"), + PendingConnectionError::Transport(_) | PendingConnectionError::IO(_) => + Some("transport-error"), + PendingConnectionError::Aborted => None, // ignore it + }; + + if let Some(reason) = reason { metrics .incoming_connections_errors_total - .with_label_values(&["banned"]) + .with_label_values(&[reason]) .inc(); } - }, - Poll::Ready(SwarmEvent::ListenerClosed { reason, addresses, .. }) => { - if let Some(metrics) = this.metrics.as_ref() { - metrics.listeners_local_addresses.sub(addresses.len() as u64); - } - let addrs = - addresses.into_iter().map(|a| a.to_string()).collect::>().join(", "); - match reason { - Ok(()) => error!( - target: "sub-libp2p", - "📪 Libp2p listener ({}) closed gracefully", - addrs - ), - Err(e) => error!( - target: "sub-libp2p", - "📪 Libp2p listener ({}) closed: {}", - addrs, e - ), - } - }, - Poll::Ready(SwarmEvent::ListenerError { error, .. }) => { - debug!(target: "sub-libp2p", "Libp2p => ListenerError: {}", error); - if let Some(metrics) = this.metrics.as_ref() { - metrics.listeners_errors_total.inc(); - } - }, - }; - } - - let num_connected_peers = - this.network_service.behaviour_mut().user_protocol_mut().num_connected_peers(); - - // 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(); - *this.external_addresses.lock() = external_addresses; - } - - 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); - - if let Some(metrics) = this.metrics.as_ref() { - 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(&[&lower_ilog2_bucket_bound.to_string()]) - .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); - } - if let Some(num_entries) = - this.network_service.behaviour_mut().kademlia_records_total_size() - { - metrics.kademlia_records_sizes_total.set(num_entries as u64); - } - metrics - .peerset_num_discovered - .set(this.network_service.behaviour_mut().user_protocol().num_discovered_peers() - as u64); - metrics.pending_connections.set( - Swarm::network_info(&this.network_service).connection_counters().num_pending() - as u64, - ); + }, + SwarmEvent::BannedPeer { peer_id, endpoint } => { + debug!( + target: "sub-libp2p", + "Libp2p => BannedPeer({}). Connected via {:?}.", + peer_id, endpoint, + ); + if let Some(metrics) = self.metrics.as_ref() { + metrics.incoming_connections_errors_total.with_label_values(&["banned"]).inc(); + } + }, + SwarmEvent::ListenerClosed { reason, addresses, .. } => { + if let Some(metrics) = self.metrics.as_ref() { + metrics.listeners_local_addresses.sub(addresses.len() as u64); + } + let addrs = + addresses.into_iter().map(|a| a.to_string()).collect::>().join(", "); + match reason { + Ok(()) => error!( + target: "sub-libp2p", + "📪 Libp2p listener ({}) closed gracefully", + addrs + ), + Err(e) => error!( + target: "sub-libp2p", + "📪 Libp2p listener ({}) closed: {}", + addrs, e + ), + } + }, + SwarmEvent::ListenerError { error, .. } => { + debug!(target: "sub-libp2p", "Libp2p => ListenerError: {}", error); + if let Some(metrics) = self.metrics.as_ref() { + metrics.listeners_errors_total.inc(); + } + }, } - - Poll::Pending } } diff --git a/client/network/src/service/tests/chain_sync.rs b/client/network/src/service/tests/chain_sync.rs index 9d8463ff190a8..1ae432fd4c235 100644 --- a/client/network/src/service/tests/chain_sync.rs +++ b/client/network/src/service/tests/chain_sync.rs @@ -75,12 +75,8 @@ async fn normal_network_poll_no_peers() { .with_chain_sync((chain_sync, chain_sync_service)) .build(); - // poll the network once - futures::future::poll_fn(|cx| { - let _ = network.network().poll_unpin(cx); - Poll::Ready(()) - }) - .await; + // perform one action on network + let _ = network.network().next_action().await; } #[tokio::test] @@ -110,11 +106,8 @@ async fn request_justification() { // send "request justifiction" message and poll the network network.service().request_justification(&hash, number); - futures::future::poll_fn(|cx| { - let _ = network.network().poll_unpin(cx); - Poll::Ready(()) - }) - .await; + // perform one action on network + let _ = network.network().next_action().await; } #[tokio::test] @@ -141,11 +134,8 @@ async fn clear_justification_requests() { // send "request justifiction" message and poll the network network.service().clear_justification_requests(); - futures::future::poll_fn(|cx| { - let _ = network.network().poll_unpin(cx); - Poll::Ready(()) - }) - .await; + // perform one action on network + let _ = network.network().next_action().await; } #[tokio::test] @@ -180,11 +170,8 @@ async fn set_sync_fork_request() { // 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.network().poll_unpin(cx); - Poll::Ready(()) - }) - .await; + // perform one action on network + let _ = network.network().next_action().await; } #[tokio::test] @@ -225,11 +212,8 @@ async fn on_block_finalized() { // send "set sync fork request" message and poll the network network.network().on_block_finalized(hash, header); - futures::future::poll_fn(|cx| { - let _ = network.network().poll_unpin(cx); - Poll::Ready(()) - }) - .await; + // perform one action on network + let _ = network.network().next_action().await; } // report from mock import queue that importing a justification was not successful diff --git a/client/network/src/service/tests/mod.rs b/client/network/src/service/tests/mod.rs index 9c97a7f73837d..3ce139ff03a33 100644 --- a/client/network/src/service/tests/mod.rs +++ b/client/network/src/service/tests/mod.rs @@ -80,10 +80,7 @@ impl TestNetwork { let service = worker.service().clone(); let event_stream = service.event_stream("test"); - tokio::spawn(async move { - futures::pin_mut!(worker); - let _ = worker.await; - }); + tokio::spawn(worker.run()); (service, event_stream) } diff --git a/client/network/sync/src/lib.rs b/client/network/sync/src/lib.rs index ffc0edaf31e72..f56ef13fc9065 100644 --- a/client/network/sync/src/lib.rs +++ b/client/network/sync/src/lib.rs @@ -1358,6 +1358,12 @@ where ); } }, + ToServiceCommand::BlockFinalized(hash, number) => { + self.on_block_finalized(&hash, number); + }, + ToServiceCommand::Status { pending_response } => { + let _ = pending_response.send(self.status()); + }, } } diff --git a/client/network/sync/src/service/chain_sync.rs b/client/network/sync/src/service/chain_sync.rs index 50ded5b643dea..824303ec09d70 100644 --- a/client/network/sync/src/service/chain_sync.rs +++ b/client/network/sync/src/service/chain_sync.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 futures::channel::oneshot; use libp2p::PeerId; use sc_consensus::{BlockImportError, BlockImportStatus, JustificationSyncLink, Link}; -use sc_network_common::service::NetworkSyncForkRequest; +use sc_network_common::{service::NetworkSyncForkRequest, sync::SyncStatus}; use sc_utils::mpsc::TracingUnboundedSender; use sp_runtime::traits::{Block as BlockT, NumberFor}; @@ -34,6 +35,10 @@ pub enum ToServiceCommand { Vec<(Result>, BlockImportError>, B::Hash)>, ), JustificationImported(PeerId, B::Hash, NumberFor, bool), + BlockFinalized(B::Hash, NumberFor), + Status { + pending_response: oneshot::Sender>, + }, } /// Handle for communicating with `ChainSync` asynchronously @@ -47,6 +52,21 @@ impl ChainSyncInterfaceHandle { pub fn new(tx: TracingUnboundedSender>) -> Self { Self { tx } } + + /// Notify ChainSync about finalized block + pub fn on_block_finalized(&self, hash: B::Hash, number: NumberFor) { + let _ = self.tx.unbounded_send(ToServiceCommand::BlockFinalized(hash, number)); + } + + /// Get sync status + /// + /// Returns an error if `ChainSync` has terminated. + pub async fn status(&self) -> Result, ()> { + let (tx, rx) = oneshot::channel(); + let _ = self.tx.unbounded_send(ToServiceCommand::Status { pending_response: tx }); + + rx.await.map_err(|_| ()) + } } impl NetworkSyncForkRequest> diff --git a/client/network/test/src/lib.rs b/client/network/test/src/lib.rs index ccaebc976135b..c47e3c86f5c0e 100644 --- a/client/network/test/src/lib.rs +++ b/client/network/test/src/lib.rs @@ -31,7 +31,7 @@ use std::{ time::Duration, }; -use futures::{channel::oneshot, future::BoxFuture, prelude::*}; +use futures::{channel::oneshot, future::BoxFuture, pin_mut, prelude::*}; use libp2p::{build_multiaddr, PeerId}; use log::trace; use parking_lot::Mutex; @@ -83,7 +83,7 @@ use sp_runtime::{ }; use substrate_test_runtime_client::AccountKeyring; pub use substrate_test_runtime_client::{ - runtime::{Block, Extrinsic, Hash, Transfer}, + runtime::{Block, Extrinsic, Hash, Header, Transfer}, TestClient, TestClientBuilder, TestClientBuilderExt, }; use tokio::time::timeout; @@ -1078,8 +1078,17 @@ where self.mut_peers(|peers| { 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.") + loop { + // The code below is not quite correct, because we are polling a different + // instance of the future every time. But as long as + // `NetworkWorker::next_action()` contains just streams polling not interleaved + // with other `.await`s, dropping the future and recreating it works the same as + // polling a single instance. + let net_poll_future = peer.network.next_action(); + pin_mut!(net_poll_future); + if let Poll::Pending = net_poll_future.poll(cx) { + break + } } trace!(target: "sync", "-- Polling complete {}: {}", i, peer.id()); diff --git a/client/offchain/src/api.rs b/client/offchain/src/api.rs index 1301ce9fd9627..cd9f5c8f6feb9 100644 --- a/client/offchain/src/api.rs +++ b/client/offchain/src/api.rs @@ -419,6 +419,10 @@ mod tests { fn local_peer_id(&self) -> PeerId { PeerId::random() } + + fn listen_addresses(&self) -> Vec { + Vec::new() + } } fn offchain_api() -> (Api, AsyncApi) { diff --git a/client/offchain/src/lib.rs b/client/offchain/src/lib.rs index 6b28d3f8a48e9..6cf5838a46bed 100644 --- a/client/offchain/src/lib.rs +++ b/client/offchain/src/lib.rs @@ -270,6 +270,10 @@ mod tests { fn local_peer_id(&self) -> PeerId { PeerId::random() } + + fn listen_addresses(&self) -> Vec { + Vec::new() + } } impl NetworkPeers for TestNetwork { diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index a737601f71b83..fb80753b4cbf6 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -17,7 +17,7 @@ // along with this program. If not, see . use crate::{ - build_network_future, + build_network_future, build_system_rpc_future, client::{Client, ClientConfig}, config::{Configuration, KeystoreConfig, PrometheusConfig}, error::Error, @@ -963,19 +963,29 @@ where Some("networking"), chain_sync_network_provider.run(network.clone()), ); - spawn_handle.spawn("import-queue", None, import_queue.run(Box::new(chain_sync_service))); + spawn_handle.spawn( + "import-queue", + None, + import_queue.run(Box::new(chain_sync_service.clone())), + ); let (system_rpc_tx, system_rpc_rx) = tracing_unbounded("mpsc_system_rpc", 10_000); - - let future = build_network_future( - config.role.clone(), - network_mut, - client, - system_rpc_rx, - has_bootnodes, - config.announce_block, + spawn_handle.spawn( + "system-rpc-handler", + Some("networking"), + build_system_rpc_future( + config.role.clone(), + network_mut.service().clone(), + chain_sync_service.clone(), + client.clone(), + system_rpc_rx, + has_bootnodes, + ), ); + let future = + build_network_future(network_mut, client, chain_sync_service, config.announce_block); + // TODO: Normally, one is supposed to pass a list of notifications protocols supported by the // node through the `NetworkConfiguration` struct. But because this function doesn't know in // advance which components, such as GrandPa or Polkadot, will be plugged on top of the diff --git a/client/service/src/lib.rs b/client/service/src/lib.rs index e3dcf012892c3..253479abc3bca 100644 --- a/client/service/src/lib.rs +++ b/client/service/src/lib.rs @@ -37,12 +37,16 @@ mod task_manager; use std::{collections::HashMap, net::SocketAddr}; use codec::{Decode, Encode}; -use futures::{channel::mpsc, FutureExt, StreamExt}; +use futures::{channel::mpsc, pin_mut, FutureExt, StreamExt}; 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::{config::MultiaddrWithPeerId, service::NetworkBlock}; +use sc_network::{NetworkStateInfo, PeerId}; +use sc_network_common::{ + config::MultiaddrWithPeerId, + service::{NetworkBlock, NetworkPeers}, +}; +use sc_network_sync::service::chain_sync::ChainSyncInterfaceHandle; use sc_utils::mpsc::TracingUnboundedReceiver; use sp_blockchain::HeaderMetadata; use sp_consensus::SyncOracle; @@ -138,9 +142,7 @@ pub struct PartialComponents @@ -153,21 +155,21 @@ async fn build_network_future< + 'static, H: sc_network_common::ExHashT, >( - role: Role, - mut network: sc_network::NetworkWorker, + network: sc_network::NetworkWorker, client: Arc, - mut rpc_rx: TracingUnboundedReceiver>, - should_have_peers: bool, + chain_sync_service: ChainSyncInterfaceHandle, announce_imported_blocks: bool, ) { let mut imported_blocks_stream = client.import_notification_stream().fuse(); - // Current best block at initialization, to report to the RPC layer. - let starting_block = client.info().best_number; - // Stream of finalized blocks reported by the client. let mut finality_notification_stream = client.finality_notification_stream().fuse(); + let network_service = network.service().clone(); + + let network_run = network.run().fuse(); + pin_mut!(network_run); + loop { futures::select! { // List of blocks that the client has imported. @@ -176,15 +178,18 @@ async fn build_network_future< Some(n) => n, // If this stream is shut down, that means the client has shut down, and the // most appropriate thing to do for the network future is to shut down too. - None => return, + None => { + debug!("Block import stream has terminated, shutting down the network future."); + return + }, }; if announce_imported_blocks { - network.service().announce_block(notification.hash, None); + network_service.announce_block(notification.hash, None); } if notification.is_new_best { - network.service().new_best_block_imported( + network_service.new_best_block_imported( notification.hash, *notification.header.number(), ); @@ -193,106 +198,160 @@ async fn build_network_future< // List of blocks that the client has finalized. notification = finality_notification_stream.select_next_some() => { - network.on_block_finalized(notification.hash, notification.header); + chain_sync_service.on_block_finalized(notification.hash, *notification.header.number()); } - // Answer incoming RPC requests. - request = rpc_rx.select_next_some() => { - match request { - sc_rpc::system::Request::Health(sender) => { - let _ = sender.send(sc_rpc::system::Health { - peers: network.peers_debug_info().len(), - is_syncing: network.service().is_major_syncing(), - should_have_peers, - }); - }, - sc_rpc::system::Request::LocalPeerId(sender) => { - let _ = sender.send(network.local_peer_id().to_base58()); - }, - sc_rpc::system::Request::LocalListenAddresses(sender) => { - 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()) - .collect(); - let _ = sender.send(addresses); - }, - sc_rpc::system::Request::Peers(sender) => { - let _ = sender.send(network.peers_debug_info().into_iter().map(|(peer_id, p)| - sc_rpc::system::PeerInfo { + // Drive the network. Shut down the network future if `NetworkWorker` has terminated. + _ = network_run => { + debug!("`NetworkWorker` has terminated, shutting down the network future."); + return + } + } + } +} + +/// Builds a future that processes system RPC requests. +async fn build_system_rpc_future< + B: BlockT, + C: BlockchainEvents + + HeaderBackend + + BlockBackend + + HeaderMetadata + + ProofProvider + + Send + + Sync + + 'static, + H: sc_network_common::ExHashT, +>( + role: Role, + network_service: Arc>, + chain_sync_service: ChainSyncInterfaceHandle, + client: Arc, + mut rpc_rx: TracingUnboundedReceiver>, + should_have_peers: bool, +) { + // Current best block at initialization, to report to the RPC layer. + let starting_block = client.info().best_number; + + loop { + // Answer incoming RPC requests. + let Some(req) = rpc_rx.next().await else { + debug!("RPC requests stream has terminated, shutting down the system RPC future."); + return; + }; + + match req { + sc_rpc::system::Request::Health(sender) => { + let peers = network_service.peers_debug_info().await; + if let Ok(peers) = peers { + let _ = sender.send(sc_rpc::system::Health { + peers: peers.len(), + is_syncing: network_service.is_major_syncing(), + should_have_peers, + }); + } else { + break + } + }, + sc_rpc::system::Request::LocalPeerId(sender) => { + let _ = sender.send(network_service.local_peer_id().to_base58()); + }, + sc_rpc::system::Request::LocalListenAddresses(sender) => { + let peer_id = network_service.local_peer_id().into(); + let p2p_proto_suffix = sc_network::multiaddr::Protocol::P2p(peer_id); + let addresses = network_service + .listen_addresses() + .iter() + .map(|addr| addr.clone().with(p2p_proto_suffix.clone()).to_string()) + .collect(); + let _ = sender.send(addresses); + }, + sc_rpc::system::Request::Peers(sender) => { + let peers = network_service.peers_debug_info().await; + if let Ok(peers) = peers { + let _ = sender.send( + peers + .into_iter() + .map(|(peer_id, p)| sc_rpc::system::PeerInfo { peer_id: peer_id.to_base58(), roles: format!("{:?}", p.roles), best_hash: p.best_hash, best_number: p.best_number, - } - ).collect()); - } - sc_rpc::system::Request::NetworkState(sender) => { - if let Ok(network_state) = serde_json::to_value(&network.network_state()) { - let _ = sender.send(network_state); - } - } - sc_rpc::system::Request::NetworkAddReservedPeer(peer_addr, sender) => { - 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) => { - let _ = match peer_id.parse::() { - Ok(peer_id) => { - network.remove_reserved_peer(peer_id); - sender.send(Ok(())) - } - Err(e) => sender.send(Err(sc_rpc::system::error::Error::MalformattedPeerArg( - e.to_string(), - ))), - }; - } - sc_rpc::system::Request::NetworkReservedPeers(sender) => { - let reserved_peers = network.reserved_peers(); - let reserved_peers = reserved_peers - .map(|peer_id| peer_id.to_base58()) - .collect(); - - let _ = sender.send(reserved_peers); + }) + .collect(), + ); + } else { + break + } + }, + sc_rpc::system::Request::NetworkState(sender) => { + let network_state = network_service.network_state().await; + if let Ok(network_state) = network_state { + if let Ok(network_state) = serde_json::to_value(network_state) { + let _ = sender.send(network_state); } - sc_rpc::system::Request::NodeRoles(sender) => { - use sc_rpc::system::NodeRole; + } else { + break + } + }, + sc_rpc::system::Request::NetworkAddReservedPeer(peer_addr, sender) => { + let result = match MultiaddrWithPeerId::try_from(peer_addr) { + Ok(peer) => network_service.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) => { + let _ = match peer_id.parse::() { + Ok(peer_id) => { + network_service.remove_reserved_peer(peer_id); + sender.send(Ok(())) + }, + Err(e) => sender.send(Err(sc_rpc::system::error::Error::MalformattedPeerArg( + e.to_string(), + ))), + }; + }, + sc_rpc::system::Request::NetworkReservedPeers(sender) => { + let reserved_peers = network_service.reserved_peers().await; + if let Ok(reserved_peers) = reserved_peers { + let reserved_peers = + reserved_peers.iter().map(|peer_id| peer_id.to_base58()).collect(); + let _ = sender.send(reserved_peers); + } else { + break + } + }, + sc_rpc::system::Request::NodeRoles(sender) => { + use sc_rpc::system::NodeRole; - let node_role = match role { - Role::Authority { .. } => NodeRole::Authority, - Role::Full => NodeRole::Full, - }; + let node_role = match role { + Role::Authority { .. } => NodeRole::Authority, + Role::Full => NodeRole::Full, + }; - let _ = sender.send(vec![node_role]); - } - sc_rpc::system::Request::SyncState(sender) => { - use sc_rpc::system::SyncState; + let _ = sender.send(vec![node_role]); + }, + sc_rpc::system::Request::SyncState(sender) => { + use sc_rpc::system::SyncState; - let best_number = client.info().best_number; + let best_number = client.info().best_number; - let _ = sender.send(SyncState { - starting_block, - current_block: best_number, - highest_block: network.best_seen_block().unwrap_or(best_number), - }); - } - } - } + let Ok(status) = chain_sync_service.status().await else { + debug!("`ChainSync` has terminated, shutting down the system RPC future."); + return + }; - // The network worker has done something. Nothing special to do, but could be - // used in the future to perform actions in response of things that happened on - // the network. - _ = (&mut network).fuse() => {} + let _ = sender.send(SyncState { + starting_block, + current_block: best_number, + highest_block: status.best_seen_block.unwrap_or(best_number), + }); + }, } } + debug!("`NetworkWorker` has terminated, shutting down the system RPC future."); } // Wrapper for HTTP and WS servers that makes sure they are properly shut down. From abfa341754d8f8fbe2a580b2e3a1fde6428db182 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Mon, 20 Feb 2023 16:58:37 +0200 Subject: [PATCH 414/715] client/beefy: drop justification on import if pallet not enabled (#13422) BEEFY pallet allows setting on-chain BEEFY genesis to some future block. Disregard any BEEFY justifications attached to imported blocks that predate configured BEEFY genesis. Signed-off-by: acatangiu --- client/beefy/src/import.rs | 56 +++++++++++++--------- client/beefy/src/tests.rs | 98 +++++++++++++++++++++----------------- 2 files changed, 89 insertions(+), 65 deletions(-) diff --git a/client/beefy/src/import.rs b/client/beefy/src/import.rs index 1b5dda3795aae..15554dc53966c 100644 --- a/client/beefy/src/import.rs +++ b/client/beefy/src/import.rs @@ -92,13 +92,23 @@ where number: NumberFor, hash: ::Hash, ) -> Result, ConsensusError> { + use ConsensusError::ClientImport as ImportError; let block_id = BlockId::hash(hash); + let beefy_genesis = self + .runtime + .runtime_api() + .beefy_genesis(&block_id) + .map_err(|e| ImportError(e.to_string()))? + .ok_or_else(|| ImportError("Unknown BEEFY genesis".to_string()))?; + if number < beefy_genesis { + return Err(ImportError("BEEFY genesis is set for future block".to_string())) + } 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()))?; + .map_err(|e| ImportError(e.to_string()))? + .ok_or_else(|| ImportError("Unknown validator set".to_string()))?; decode_and_verify_finality_proof::(&encoded[..], number, &validator_set) } @@ -142,26 +152,28 @@ where 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. - debug!( - target: LOG_TARGET, - "🥩 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."); - - metric_inc!(self, beefy_good_justification_imports); - } else { - debug!( - target: LOG_TARGET, - "🥩 error decoding justification: {:?} for imported block {:?}", - encoded, - number, - ); - metric_inc!(self, beefy_bad_justification_imports); + match self.decode_and_verify(&encoded, number, hash) { + Ok(proof) => { + // The proof is valid and the block is imported and final, we can import. + debug!( + target: LOG_TARGET, + "🥩 import justif {:?} for block number {:?}.", proof, number + ); + // Send the justification to the BEEFY voter for processing. + self.justification_sender + .notify(|| Ok::<_, ()>(proof)) + .expect("the closure always returns Ok; qed."); + metric_inc!(self, beefy_good_justification_imports); + }, + Err(err) => { + debug!( + target: LOG_TARGET, + "🥩 error importing BEEFY justification for block {:?}: {:?}", + number, + err, + ); + metric_inc!(self, beefy_bad_justification_imports); + }, } }, _ => (), diff --git a/client/beefy/src/tests.rs b/client/beefy/src/tests.rs index 42f56226ce5af..f17a42f2045a5 100644 --- a/client/beefy/src/tests.rs +++ b/client/beefy/src/tests.rs @@ -60,7 +60,7 @@ use sp_runtime::{ codec::Encode, generic::BlockId, traits::{Header as HeaderT, NumberFor}, - BuildStorage, DigestItem, Justifications, Storage, + BuildStorage, DigestItem, EncodedJustification, Justifications, Storage, }; use std::{collections::HashMap, marker::PhantomData, sync::Arc, task::Poll}; use substrate_test_runtime_client::{runtime::Header, ClientExt}; @@ -107,11 +107,13 @@ pub(crate) struct PeerData { #[derive(Default)] pub(crate) struct BeefyTestNet { peers: Vec, + pub beefy_genesis: NumberFor, } impl BeefyTestNet { pub(crate) fn new(n_authority: usize) -> Self { - let mut net = BeefyTestNet { peers: Vec::with_capacity(n_authority) }; + let beefy_genesis = 1; + let mut net = BeefyTestNet { peers: Vec::with_capacity(n_authority), beefy_genesis }; for i in 0..n_authority { let (rx, cfg) = on_demand_justifications_protocol_config(GENESIS_HASH, None); @@ -202,7 +204,7 @@ impl TestNetFactory for BeefyTestNet { ) { let keys = &[BeefyKeyring::Alice, BeefyKeyring::Bob]; let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); - let api = Arc::new(TestApi::with_validator_set(&validator_set)); + let api = Arc::new(TestApi::new(self.beefy_genesis, &validator_set, GOOD_MMR_ROOT)); let inner = BlockImportAdapter::new(client.clone()); let (block_import, voter_links, rpc_links) = beefy_block_import_and_links(inner, client.as_backend(), api, None); @@ -716,7 +718,7 @@ async fn correct_beefy_payload() { } #[tokio::test] -async fn beefy_importing_blocks() { +async fn beefy_importing_justifications() { use futures::{future::poll_fn, task::Poll}; use sc_block_builder::BlockBuilderProvider; use sc_client_api::BlockBackend; @@ -726,11 +728,15 @@ async fn beefy_importing_blocks() { let mut net = BeefyTestNet::new(2); let keys = &[BeefyKeyring::Alice, BeefyKeyring::Bob]; let good_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); + // Set BEEFY genesis to block 3. + net.beefy_genesis = 3; let client = net.peer(0).client().clone(); + let full_client = client.as_client(); let (mut block_import, _, peer_data) = net.make_block_import(client.clone()); let PeerData { beefy_voter_links, .. } = peer_data; let justif_stream = beefy_voter_links.lock().take().unwrap().from_block_import_justif_stream; + let mut justif_recv = justif_stream.subscribe(100_000); let params = |block: Block, justifications: Option| { let mut import = BlockImportParams::new(BlockOrigin::File, block.header); @@ -740,15 +746,19 @@ async fn beefy_importing_blocks() { import.fork_choice = Some(ForkChoiceStrategy::LongestChain); import }; + let backend_justif_for = |block_hash: H256| -> Option { + full_client + .justifications(block_hash) + .unwrap() + .and_then(|j| j.get(BEEFY_ENGINE_ID).cloned()) + }; - let full_client = client.as_client(); let parent_id = BlockId::Number(0); 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(100_000); + // Import block 1 without justifications. assert_eq!( block_import .import_block(params(block.clone(), None), HashMap::new()) @@ -760,16 +770,32 @@ async fn beefy_importing_blocks() { block_import.import_block(params(block, None), HashMap::new()).await.unwrap(), ImportResult::AlreadyInChain, ); - // Verify no BEEFY justifications present: + + // Import block 2 with "valid" justification (beefy pallet genesis block not yet reached). + let parent_id = BlockId::Number(1); + let block_num = 2; + 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 proof = crate::justification::tests::new_finality_proof(block_num, &good_set, keys); + let versioned_proof: VersionedFinalityProof, Signature> = proof.into(); + let encoded = versioned_proof.encode(); + let justif = Some(Justifications::from((BEEFY_ENGINE_ID, encoded))); + assert_eq!( + block_import.import_block(params(block, justif), HashMap::new()).await.unwrap(), + ImportResult::Imported(ImportedAux { + bad_justification: false, + is_new_best: true, + ..Default::default() + }), + ); + + // Verify no BEEFY justifications present (for either block 1 or 2): { // none in backend, - assert_eq!( - full_client - .justifications(hashof1) - .unwrap() - .and_then(|j| j.get(BEEFY_ENGINE_ID).cloned()), - None - ); + assert_eq!(backend_justif_for(hashof1), None); + assert_eq!(backend_justif_for(hashof2), None); // and none sent to BEEFY worker. poll_fn(move |cx| { assert_eq!(justif_recv.poll_next_unpin(cx), Poll::Pending); @@ -778,17 +804,16 @@ async fn beefy_importing_blocks() { .await; } - // Import with valid justification. - let parent_id = BlockId::Number(1); - let block_num = 2; + // Import block 3 with valid justification. + let parent_id = BlockId::Number(2); + let block_num = 3; + 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 proof = crate::justification::tests::new_finality_proof(block_num, &good_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 hashof2 = block.header.hash(); let mut justif_recv = justif_stream.subscribe(100_000); assert_eq!( block_import.import_block(params(block, justif), HashMap::new()).await.unwrap(), @@ -801,13 +826,7 @@ async fn beefy_importing_blocks() { // Verify BEEFY justification successfully imported: { // still not in backend (worker is responsible for appending to backend), - assert_eq!( - full_client - .justifications(hashof2) - .unwrap() - .and_then(|j| j.get(BEEFY_ENGINE_ID).cloned()), - None - ); + assert_eq!(backend_justif_for(hashof3), None); // but sent to BEEFY worker // (worker will append it to backend when all previous mandatory justifs are there as well). poll_fn(move |cx| { @@ -820,19 +839,18 @@ async fn beefy_importing_blocks() { .await; } - // Import with invalid justification (incorrect validator set). - let parent_id = BlockId::Number(2); - let block_num = 3; + // Import block 4 with invalid justification (incorrect validator set). + let parent_id = BlockId::Number(3); + let block_num = 4; + let builder = full_client.new_block_at(&parent_id, Default::default(), false).unwrap(); + let block = builder.build().unwrap().block; + let hashof4 = block.header.hash(); let keys = &[BeefyKeyring::Alice]; let bad_set = ValidatorSet::new(make_beefy_ids(keys), 1).unwrap(); let proof = crate::justification::tests::new_finality_proof(block_num, &bad_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 hashof3 = block.header.hash(); let mut justif_recv = justif_stream.subscribe(100_000); assert_eq!( block_import.import_block(params(block, justif), HashMap::new()).await.unwrap(), @@ -846,13 +864,7 @@ async fn beefy_importing_blocks() { // Verify bad BEEFY justifications was not imported: { // none in backend, - assert_eq!( - full_client - .justifications(hashof3) - .unwrap() - .and_then(|j| j.get(BEEFY_ENGINE_ID).cloned()), - None - ); + assert_eq!(backend_justif_for(hashof4), None); // and none sent to BEEFY worker. poll_fn(move |cx| { assert_eq!(justif_recv.poll_next_unpin(cx), Poll::Pending); From 1eff8873407ea0df01a701010086008eb06e1907 Mon Sep 17 00:00:00 2001 From: Sasha Gryaznov Date: Mon, 20 Feb 2023 17:45:54 +0200 Subject: [PATCH 415/715] rename call_runtime() returned error (#13412) --- frame/contracts/src/wasm/runtime.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index ef0c35df73c6a..eba20e9596786 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -115,7 +115,7 @@ pub enum ReturnCode { /// The contract that was called is no contract (a plain account). NotCallable = 8, /// The call dispatched by `seal_call_runtime` was executed but returned an error. - CallRuntimeReturnedError = 10, + CallRuntimeFailed = 10, /// ECDSA pubkey recovery failed (most probably wrong recovery id or signature), or /// ECDSA compressed pubkey conversion into Ethereum address failed (most probably /// wrong pubkey provided). @@ -2404,21 +2404,21 @@ pub mod env { /// /// # 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. + /// - `call_ptr`: the pointer into the linear memory where the input data is placed. + /// - `call_len`: the length of the input data in bytes. /// /// # Return Value /// /// Returns `ReturnCode::Success` when the dispatchable was succesfully executed and /// returned `Ok`. When the dispatchable was exeuted but returned an error - /// `ReturnCode::CallRuntimeReturnedError` is returned. The full error is not + /// `ReturnCode::CallRuntimeFailed` is returned. The full error is not /// provided because it is not guaranteed to be stable. /// /// # Comparison with `ChainExtension` /// /// Just as a chain extension this API allows the runtime to extend the functionality - /// of contracts. While making use of this function is generelly easier it cannot be - /// used in call cases. Consider writing a chain extension if you need to do perform + /// of contracts. While making use of this function is generally easier it cannot be + /// used in all cases. Consider writing a chain extension if you need to do perform /// one of the following tasks: /// /// - Return data. @@ -2444,7 +2444,7 @@ pub mod env { ctx.adjust_gas(charged, RuntimeCosts::CallRuntime(actual_weight)); match result { Ok(_) => Ok(ReturnCode::Success), - Err(_) => Ok(ReturnCode::CallRuntimeReturnedError), + Err(_) => Ok(ReturnCode::CallRuntimeFailed), } } From 5b6519a7ff4a2d3cc424d78bc4830688f3b184c0 Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Mon, 20 Feb 2023 23:47:21 +0100 Subject: [PATCH 416/715] `BlockId` removal: `runtime-api` refactor (#13255) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * BlockId removal: refactor of runtime API It changes the arguments of: - `ApiExt` methods: `has_api`, `has_api_with`, `api_version` - `CallApiAt` method: `runtime_version_at` from: `BlockId` to: `Block::Hash` It also changes the first argument of all generated runtime API calls from: `BlockId` to: `Block::Hash` This PR is part of BlockId::Number refactoring analysis (paritytech/substrate#11292) * BlockId removal: refactor of runtime API - tests - tests adjusted to new runtime API, - some tests migrated from block number to block hash * benchmarking-cli: BlockId(0) migrated to info().genesis_hash `runtime_api.call()` now requires the block hash instead of BlockId::Number. To access the genesis hash widely used in benchmarking engine the Client was constrained to satisfy `sp_blockchain::HeaderBackend` trait which provides `info().genesis_hash`. * trivial: api.call(BlockId) -> api.call(Hash) - Migrated all `runtime_api.calls` to use Hash - Noteworthy (?): -- `validate_transaction_blocking` in transaction pool, * CallApiAtParams::at changed to Block::Hash * missed doc updated * Apply suggestions from code review Co-authored-by: Bastian Köcher * ".git/.scripts/commands/fmt/fmt.sh" * BlockId removal: Benchmark::consumed_weight Little refactor around `Benchmark::consumed_weight`: `BlockId` removed. * at_hash renamed * wrong merge fixed * beefy worker: merged with master * beefy: tests: missing block problem fixed * Apply review suggestion * fix --------- Co-authored-by: Bastian Köcher Co-authored-by: command-bot <> --- bin/node/cli/src/service.rs | 2 +- bin/node/testing/src/bench.rs | 4 +- client/authority-discovery/src/worker.rs | 4 +- .../basic-authorship/src/basic_authorship.rs | 2 +- client/beefy/src/import.rs | 6 +-- client/beefy/src/lib.rs | 36 ++++++-------- client/beefy/src/worker.rs | 22 ++++++--- client/block-builder/src/lib.rs | 24 +++++----- client/consensus/aura/src/import_queue.rs | 12 ++--- client/consensus/aura/src/lib.rs | 11 +++-- client/consensus/babe/rpc/src/lib.rs | 4 +- client/consensus/babe/src/lib.rs | 41 ++++++++-------- client/consensus/babe/src/tests.rs | 2 +- client/consensus/pow/src/lib.rs | 6 +-- client/finality-grandpa/src/environment.rs | 9 ++-- client/finality-grandpa/src/import.rs | 9 ++-- client/merkle-mountain-range/rpc/src/lib.rs | 19 +++----- client/merkle-mountain-range/src/lib.rs | 16 +++---- client/offchain/src/lib.rs | 24 +++++----- .../rpc-spec-v2/src/chain_head/chain_head.rs | 28 ++++------- client/rpc/src/author/mod.rs | 4 +- client/rpc/src/dev/mod.rs | 4 +- client/rpc/src/state/state_full.rs | 17 +++---- client/service/src/client/client.rs | 9 ++-- client/service/test/src/client/mod.rs | 29 +++--------- client/tracing/src/block/mod.rs | 5 +- client/transaction-pool/src/api.rs | 18 +++---- frame/transaction-payment/rpc/src/lib.rs | 17 +++---- .../api/proc-macro/src/decl_runtime_apis.rs | 12 ++--- .../api/proc-macro/src/impl_runtime_apis.rs | 11 ++--- .../proc-macro/src/mock_impl_runtime_apis.rs | 47 +++++++++---------- primitives/api/proc-macro/src/utils.rs | 6 +-- primitives/api/src/lib.rs | 36 +++++++------- primitives/api/test/benches/bench.rs | 25 +++++----- primitives/api/test/tests/decl_and_impl.rs | 32 ++++++------- primitives/api/test/tests/runtime_calls.rs | 47 ++++++++++--------- ....rs => mock_advanced_hash_by_reference.rs} | 2 +- ...=> mock_advanced_hash_by_reference.stderr} | 6 +-- ...ockid.rs => mock_advanced_missing_hash.rs} | 0 ...derr => mock_advanced_missing_hash.stderr} | 4 +- .../application-crypto/test/src/ecdsa.rs | 3 +- .../application-crypto/test/src/ed25519.rs | 3 +- .../application-crypto/test/src/sr25519.rs | 3 +- primitives/beefy/src/mmr.rs | 7 +-- primitives/runtime/src/runtime_logger.rs | 7 +-- primitives/session/src/lib.rs | 4 +- test-utils/runtime/src/lib.rs | 19 ++++---- .../frame/benchmarking-cli/src/block/bench.rs | 14 +++--- .../benchmarking-cli/src/extrinsic/bench.rs | 14 +++--- .../benchmarking-cli/src/extrinsic/cmd.rs | 4 +- .../benchmarking-cli/src/overhead/cmd.rs | 4 +- utils/frame/rpc/system/src/lib.rs | 18 +++---- 52 files changed, 321 insertions(+), 391 deletions(-) rename primitives/api/test/tests/ui/{mock_advanced_block_id_by_value.rs => mock_advanced_hash_by_reference.rs} (81%) rename primitives/api/test/tests/ui/{mock_advanced_block_id_by_value.stderr => mock_advanced_hash_by_reference.stderr} (60%) rename primitives/api/test/tests/ui/{mock_advanced_missing_blockid.rs => mock_advanced_missing_hash.rs} (100%) rename primitives/api/test/tests/ui/{mock_advanced_missing_blockid.stderr => mock_advanced_missing_hash.stderr} (56%) diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs index c98fe17cfc693..e0247079db4bc 100644 --- a/bin/node/cli/src/service.rs +++ b/bin/node/cli/src/service.rs @@ -60,7 +60,7 @@ 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()) + .account_nonce(best_hash, account.public().into()) .expect("Fetching account nonce works; qed") } diff --git a/bin/node/testing/src/bench.rs b/bin/node/testing/src/bench.rs index cc0a93ca27fc2..f9bad2a561367 100644 --- a/bin/node/testing/src/bench.rs +++ b/bin/node/testing/src/bench.rs @@ -53,7 +53,6 @@ use sp_consensus::BlockOrigin; use sp_core::{blake2_256, ed25519, sr25519, traits::SpawnNamed, ExecutionContext, Pair, Public}; use sp_inherents::InherentData; use sp_runtime::{ - generic::BlockId, traits::{Block as BlockT, IdentifyAccount, Verify}, OpaqueExtrinsic, }; @@ -274,7 +273,6 @@ pub struct BlockContentIterator<'a> { impl<'a> BlockContentIterator<'a> { fn new(content: BlockContent, keyring: &'a BenchKeyring, client: &Client) -> Self { let genesis_hash = client.chain_info().genesis_hash; - let runtime_version = client .runtime_version_at(genesis_hash) .expect("There should be runtime version at 0"); @@ -442,7 +440,7 @@ impl BenchDb { client .runtime_api() .inherent_extrinsics_with_context( - &BlockId::number(0), + client.chain_info().genesis_hash, ExecutionContext::BlockConstruction, inherent_data, ) diff --git a/client/authority-discovery/src/worker.rs b/client/authority-discovery/src/worker.rs index 4121b64e00b9b..72a371cb6abe4 100644 --- a/client/authority-discovery/src/worker.rs +++ b/client/authority-discovery/src/worker.rs @@ -55,7 +55,7 @@ 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}; +use sp_runtime::traits::Block as BlockT; mod addr_cache; /// Dht payload schemas generated from Protobuf definitions via Prost crate in build.rs. @@ -171,7 +171,7 @@ where &self, at: Block::Hash, ) -> std::result::Result, ApiError> { - self.runtime_api().authorities(&BlockId::Hash(at)) + self.runtime_api().authorities(at) } } diff --git a/client/basic-authorship/src/basic_authorship.rs b/client/basic-authorship/src/basic_authorship.rs index c39d07a14f0f1..9ab7ef55fb03a 100644 --- a/client/basic-authorship/src/basic_authorship.rs +++ b/client/basic-authorship/src/basic_authorship.rs @@ -731,7 +731,7 @@ mod tests { assert_eq!(proposal.block.extrinsics().len(), 1); let api = client.runtime_api(); - api.execute_block(&BlockId::Hash(genesis_hash), proposal.block).unwrap(); + api.execute_block(genesis_hash, proposal.block).unwrap(); let state = backend.state_at(genesis_hash).unwrap(); diff --git a/client/beefy/src/import.rs b/client/beefy/src/import.rs index 15554dc53966c..66421e227476c 100644 --- a/client/beefy/src/import.rs +++ b/client/beefy/src/import.rs @@ -24,7 +24,6 @@ use sp_api::{ProvideRuntimeApi, TransactionFor}; use sp_blockchain::well_known_cache_keys; use sp_consensus::Error as ConsensusError; use sp_runtime::{ - generic::BlockId, traits::{Block as BlockT, Header as HeaderT, NumberFor}, EncodedJustification, }; @@ -93,11 +92,10 @@ where hash: ::Hash, ) -> Result, ConsensusError> { use ConsensusError::ClientImport as ImportError; - let block_id = BlockId::hash(hash); let beefy_genesis = self .runtime .runtime_api() - .beefy_genesis(&block_id) + .beefy_genesis(hash) .map_err(|e| ImportError(e.to_string()))? .ok_or_else(|| ImportError("Unknown BEEFY genesis".to_string()))?; if number < beefy_genesis { @@ -106,7 +104,7 @@ where let validator_set = self .runtime .runtime_api() - .validator_set(&block_id) + .validator_set(hash) .map_err(|e| ImportError(e.to_string()))? .ok_or_else(|| ImportError("Unknown validator set".to_string()))?; diff --git a/client/beefy/src/lib.rs b/client/beefy/src/lib.rs index 4031b52970283..04345912f1d78 100644 --- a/client/beefy/src/lib.rs +++ b/client/beefy/src/lib.rs @@ -52,10 +52,7 @@ use sp_blockchain::{ use sp_consensus::{Error as ConsensusError, SyncOracle}; use sp_keystore::SyncCryptoStorePtr; use sp_mmr_primitives::MmrApi; -use sp_runtime::{ - generic::BlockId, - traits::{Block, Zero}, -}; +use sp_runtime::traits::{Block, Zero}; use std::{collections::VecDeque, marker::PhantomData, sync::Arc}; mod aux_schema; @@ -345,7 +342,7 @@ where { let beefy_genesis = runtime .runtime_api() - .beefy_genesis(&BlockId::hash(best_grandpa.hash())) + .beefy_genesis(best_grandpa.hash()) .ok() .flatten() .ok_or_else(|| ClientError::Backend("BEEFY pallet expected to be active.".into()))?; @@ -369,7 +366,7 @@ where let best_beefy = *header.number(); // If no session boundaries detected so far, just initialize new rounds here. if sessions.is_empty() { - let active_set = expect_validator_set(runtime, BlockId::hash(header.hash()))?; + let active_set = expect_validator_set(runtime, header.hash())?; let mut rounds = Rounds::new(best_beefy, active_set); // Mark the round as already finalized. rounds.conclude(best_beefy); @@ -383,8 +380,8 @@ where if *header.number() == beefy_genesis { // We've reached BEEFY genesis, initialize voter here. - let genesis_set = expect_validator_set(runtime, BlockId::hash(header.hash())) - .and_then(genesis_set_sanity_check)?; + let genesis_set = + expect_validator_set(runtime, header.hash()).and_then(genesis_set_sanity_check)?; info!( target: LOG_TARGET, "🥩 Loading BEEFY voter state from genesis on what appears to be first startup. \ @@ -409,16 +406,11 @@ where // 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: LOG_TARGET, "🥩 {}", msg); - ClientError::Consensus(sp_consensus::Error::StateUnavailable(msg)) - })?; + runtime.runtime_api().validator_set(parent_hash).ok().flatten().ok_or_else(|| { + let msg = format!("{}. Could not initialize BEEFY voter.", parent_hash); + error!(target: LOG_TARGET, "🥩 {}", msg); + ClientError::Consensus(sp_consensus::Error::StateUnavailable(msg)) + })?; // Move up the chain. header = blockchain.expect_header(parent_hash)?; @@ -449,8 +441,8 @@ where Some(notif) => notif, None => break }; - let at = BlockId::hash(notif.header.hash()); - if let Some(start) = runtime.runtime_api().beefy_genesis(&at).ok().flatten() { + let at = notif.header.hash(); + if let Some(start) = runtime.runtime_api().beefy_genesis(at).ok().flatten() { if *notif.header.number() >= start { // Beefy pallet available, return header for best grandpa at the time. info!( @@ -485,7 +477,7 @@ fn genesis_set_sanity_check( fn expect_validator_set( runtime: &R, - at: BlockId, + at_hash: B::Hash, ) -> ClientResult> where B: Block, @@ -494,7 +486,7 @@ where { runtime .runtime_api() - .validator_set(&at) + .validator_set(at_hash) .ok() .flatten() .ok_or_else(|| ClientError::Backend("BEEFY pallet expected to be active.".into())) diff --git a/client/beefy/src/worker.rs b/client/beefy/src/worker.rs index 8783997cc6b22..f67ec17fc23a5 100644 --- a/client/beefy/src/worker.rs +++ b/client/beefy/src/worker.rs @@ -963,10 +963,21 @@ where } let number = *proof.round_number(); + let hash = self + .backend + .blockchain() + .expect_block_hash_from_id(&BlockId::Number(number)) + .map_err(|err| { + let err_msg = format!( + "Couldn't get hash for block #{:?} (error: {:?}), skipping report for equivocation", + number, err + ); + Error::Backend(err_msg) + })?; let runtime_api = self.runtime.runtime_api(); // generate key ownership proof at that block let key_owner_proof = match runtime_api - .generate_key_ownership_proof(&BlockId::Number(number), validator_set_id, offender_id) + .generate_key_ownership_proof(hash, validator_set_id, offender_id) .map_err(Error::RuntimeApi)? { Some(proof) => proof, @@ -982,11 +993,7 @@ where // submit equivocation report at **best** block let best_block_hash = self.backend.blockchain().info().best_hash; runtime_api - .submit_report_equivocation_unsigned_extrinsic( - &BlockId::Hash(best_block_hash), - proof, - key_owner_proof, - ) + .submit_report_equivocation_unsigned_extrinsic(best_block_hash, proof, key_owner_proof) .map_err(Error::RuntimeApi)?; Ok(()) @@ -1628,6 +1635,9 @@ pub(crate) mod tests { let mut worker = create_beefy_worker(&net.peer(0), &keys[0], 1, validator_set.clone()); worker.runtime = api_alice.clone(); + // let there be a block with num = 1: + let _ = net.peer(0).push_blocks(1, false); + let payload1 = Payload::from_single_entry(MMR_ROOT_ID, vec![42]); let payload2 = Payload::from_single_entry(MMR_ROOT_ID, vec![128]); diff --git a/client/block-builder/src/lib.rs b/client/block-builder/src/lib.rs index b6c2ac3ba5d68..d302a834fd723 100644 --- a/client/block-builder/src/lib.rs +++ b/client/block-builder/src/lib.rs @@ -137,7 +137,6 @@ 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, /// The estimated size of the block header. @@ -181,12 +180,14 @@ where api.record_proof(); } - let block_id = BlockId::Hash(parent_hash); - - api.initialize_block_with_context(&block_id, ExecutionContext::BlockConstruction, &header)?; + api.initialize_block_with_context( + parent_hash, + ExecutionContext::BlockConstruction, + &header, + )?; let version = api - .api_version::>(&block_id)? + .api_version::>(parent_hash)? .ok_or_else(|| Error::VersionInvalid("BlockBuilderApi".to_string()))?; Ok(Self { @@ -194,7 +195,6 @@ where extrinsics: Vec::new(), api, version, - block_id, backend, estimated_header_size, }) @@ -204,7 +204,7 @@ where /// /// This will ensure the extrinsic can be validly executed (by executing it). pub fn push(&mut self, xt: ::Extrinsic) -> Result<(), Error> { - let block_id = &self.block_id; + let parent_hash = self.parent_hash; let extrinsics = &mut self.extrinsics; let version = self.version; @@ -212,14 +212,14 @@ where let res = if version < 6 { #[allow(deprecated)] api.apply_extrinsic_before_version_6_with_context( - block_id, + parent_hash, ExecutionContext::BlockConstruction, xt.clone(), ) .map(legacy::byte_sized_error::convert_to_latest) } else { api.apply_extrinsic_with_context( - block_id, + parent_hash, ExecutionContext::BlockConstruction, xt.clone(), ) @@ -246,7 +246,7 @@ where pub fn build(mut self) -> Result>, Error> { let header = self .api - .finalize_block_with_context(&self.block_id, ExecutionContext::BlockConstruction)?; + .finalize_block_with_context(self.parent_hash, ExecutionContext::BlockConstruction)?; debug_assert_eq!( header.extrinsics_root().clone(), @@ -279,13 +279,13 @@ where &mut self, inherent_data: sp_inherents::InherentData, ) -> Result, Error> { - let block_id = self.block_id; + let parent_hash = self.parent_hash; self.api .execute_in_transaction(move |api| { // `create_inherents` should not change any state, to ensure this we always rollback // the transaction. TransactionOutcome::Rollback(api.inherent_extrinsics_with_context( - &block_id, + parent_hash, ExecutionContext::BlockConstruction, inherent_data, )) diff --git a/client/consensus/aura/src/import_queue.rs b/client/consensus/aura/src/import_queue.rs index 4c8722c31f206..be52bffe0c02c 100644 --- a/client/consensus/aura/src/import_queue.rs +++ b/client/consensus/aura/src/import_queue.rs @@ -41,7 +41,6 @@ use sp_consensus_slots::Slot; use sp_core::{crypto::Pair, ExecutionContext}; use sp_inherents::{CreateInherentDataProviders, InherentDataProvider as _}; use sp_runtime::{ - generic::BlockId, traits::{Block as BlockT, Header, NumberFor}, DigestItem, }; @@ -142,7 +141,7 @@ where async fn check_inherents( &self, block: B, - block_id: BlockId, + at_hash: B::Hash, inherent_data: sp_inherents::InherentData, create_inherent_data_providers: CIDP::InherentDataProviders, execution_context: ExecutionContext, @@ -155,7 +154,7 @@ where let inherent_res = self .client .runtime_api() - .check_inherents_with_context(&block_id, execution_context, block, inherent_data) + .check_inherents_with_context(at_hash, execution_context, block, inherent_data) .map_err(|e| Error::Client(e.into()))?; if !inherent_res.ok() { @@ -248,15 +247,12 @@ where if self .client .runtime_api() - .has_api_with::, _>( - &BlockId::Hash(parent_hash), - |v| v >= 2, - ) + .has_api_with::, _>(parent_hash, |v| v >= 2) .map_err(|e| e.to_string())? { self.check_inherents( new_block.clone(), - BlockId::Hash(parent_hash), + parent_hash, inherent_data, create_inherent_data_providers, block.origin.into(), diff --git a/client/consensus/aura/src/lib.rs b/client/consensus/aura/src/lib.rs index 6ef6bdc2ed1ff..0345eaa397bf5 100644 --- a/client/consensus/aura/src/lib.rs +++ b/client/consensus/aura/src/lib.rs @@ -53,7 +53,6 @@ use sp_core::crypto::{ByteArray, Pair, Public}; use sp_inherents::CreateInherentDataProviders; use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; use sp_runtime::{ - generic::BlockId, traits::{Block as BlockT, Header, Member, NumberFor, Zero}, DigestItem, }; @@ -121,8 +120,10 @@ where C: AuxStore + ProvideRuntimeApi + UsageProvider, C::Api: AuraApi, { - let best_block_id = BlockId::Hash(client.usage_info().chain.best_hash); - client.runtime_api().slot_duration(&best_block_id).map_err(|err| err.into()) + client + .runtime_api() + .slot_duration(client.usage_info().chain.best_hash) + .map_err(|err| err.into()) } /// Get slot author for given block along with authorities. @@ -613,7 +614,7 @@ where if *until > context_block_number { runtime_api .initialize_block( - &BlockId::Hash(parent_hash), + parent_hash, &B::Header::new( context_block_number, Default::default(), @@ -627,7 +628,7 @@ where } runtime_api - .authorities(&BlockId::Hash(parent_hash)) + .authorities(parent_hash) .ok() .ok_or(sp_consensus::Error::InvalidAuthoritiesSet) } diff --git a/client/consensus/babe/rpc/src/lib.rs b/client/consensus/babe/rpc/src/lib.rs index 288f852a5c989..2d6d95b8dc862 100644 --- a/client/consensus/babe/rpc/src/lib.rs +++ b/client/consensus/babe/rpc/src/lib.rs @@ -29,7 +29,7 @@ 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}; -use sp_api::{BlockId, ProvideRuntimeApi}; +use sp_api::ProvideRuntimeApi; use sp_application_crypto::AppKey; use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata}; use sp_consensus::{Error as ConsensusError, SelectChain}; @@ -97,7 +97,7 @@ where let epoch_start = self .client .runtime_api() - .current_epoch_start(&BlockId::Hash(header.hash())) + .current_epoch_start(header.hash()) .map_err(|err| Error::StringError(format!("{:?}", err)))?; let epoch = epoch_data( diff --git a/client/consensus/babe/src/lib.rs b/client/consensus/babe/src/lib.rs index 403792249e8df..a305403405e27 100644 --- a/client/consensus/babe/src/lib.rs +++ b/client/consensus/babe/src/lib.rs @@ -123,7 +123,7 @@ use sp_core::{crypto::ByteArray, ExecutionContext}; use sp_inherents::{CreateInherentDataProviders, InherentData, InherentDataProvider}; use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; use sp_runtime::{ - generic::{BlockId, OpaqueDigestItemId}, + generic::OpaqueDigestItemId, traits::{Block as BlockT, Header, NumberFor, SaturatedConversion, Zero}, DigestItem, }; @@ -377,24 +377,24 @@ 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) + let at_hash = if client.usage_info().chain.finalized_state.is_some() { + client.usage_info().chain.best_hash } else { debug!(target: LOG_TARGET, "No finalized state is available. Reading config from genesis"); - BlockId::Hash(client.usage_info().chain.genesis_hash) + client.usage_info().chain.genesis_hash }; let runtime_api = client.runtime_api(); - let version = runtime_api.api_version::>(&block_id)?; + let version = runtime_api.api_version::>(at_hash)?; let config = match version { Some(1) => { #[allow(deprecated)] { - runtime_api.configuration_before_version_2(&block_id)?.into() + runtime_api.configuration_before_version_2(at_hash)?.into() } }, - Some(2) => runtime_api.configuration(&block_id)?, + Some(2) => runtime_api.configuration(at_hash)?, _ => return Err(sp_blockchain::Error::VersionInvalid( "Unsupported or invalid BabeApi version".to_string(), @@ -1023,7 +1023,7 @@ where async fn check_inherents( &self, block: Block, - block_id: BlockId, + at_hash: Block::Hash, inherent_data: InherentData, create_inherent_data_providers: CIDP::InherentDataProviders, execution_context: ExecutionContext, @@ -1031,7 +1031,7 @@ where let inherent_res = self .client .runtime_api() - .check_inherents_with_context(&block_id, execution_context, block, inherent_data) + .check_inherents_with_context(at_hash, execution_context, block, inherent_data) .map_err(Error::RuntimeApi)?; if !inherent_res.ok() { @@ -1078,11 +1078,11 @@ where ); // get the best block on which we will build and send the equivocation report. - let best_id = self + let best_hash = self .select_chain .best_chain() .await - .map(|h| BlockId::Hash(h.hash())) + .map(|h| h.hash()) .map_err(|e| Error::Client(e.into()))?; // generate a key ownership proof. we start by trying to generate the @@ -1093,17 +1093,17 @@ where // equivocation happens on the first block of the session, in which case // its parent would be on the previous session. if generation on the // parent header fails we try with best block as well. - let generate_key_owner_proof = |block_id: &BlockId| { + let generate_key_owner_proof = |at_hash: Block::Hash| { self.client .runtime_api() - .generate_key_ownership_proof(block_id, slot, equivocation_proof.offender.clone()) + .generate_key_ownership_proof(at_hash, slot, equivocation_proof.offender.clone()) .map_err(Error::RuntimeApi) }; - let parent_id = BlockId::Hash(*header.parent_hash()); - let key_owner_proof = match generate_key_owner_proof(&parent_id)? { + let parent_hash = *header.parent_hash(); + let key_owner_proof = match generate_key_owner_proof(parent_hash)? { Some(proof) => proof, - None => match generate_key_owner_proof(&best_id)? { + None => match generate_key_owner_proof(best_hash)? { Some(proof) => proof, None => { debug!( @@ -1119,7 +1119,7 @@ where self.client .runtime_api() .submit_report_equivocation_unsigned_extrinsic( - &best_id, + best_hash, equivocation_proof, key_owner_proof, ) @@ -1268,7 +1268,7 @@ where self.check_inherents( new_block.clone(), - BlockId::Hash(parent_hash), + parent_hash, inherent_data, create_inherent_data_providers, block.origin.into(), @@ -1395,11 +1395,10 @@ where }; // Read epoch info from the imported state. - let block_id = BlockId::hash(hash); - let current_epoch = self.client.runtime_api().current_epoch(&block_id).map_err(|e| { + let current_epoch = self.client.runtime_api().current_epoch(hash).map_err(|e| { ConsensusError::ClientImport(babe_err::(Error::RuntimeApi(e)).into()) })?; - let next_epoch = self.client.runtime_api().next_epoch(&block_id).map_err(|e| { + let next_epoch = self.client.runtime_api().next_epoch(hash).map_err(|e| { ConsensusError::ClientImport(babe_err::(Error::RuntimeApi(e)).into()) })?; diff --git a/client/consensus/babe/src/tests.rs b/client/consensus/babe/src/tests.rs index 0dd0b59dd69c0..ad2e95df033f4 100644 --- a/client/consensus/babe/src/tests.rs +++ b/client/consensus/babe/src/tests.rs @@ -45,7 +45,7 @@ use sp_keystore::{ SyncCryptoStore, }; use sp_runtime::{ - generic::{Digest, DigestItem}, + generic::{BlockId, Digest, DigestItem}, traits::Block as BlockT, }; use sp_timestamp::Timestamp; diff --git a/client/consensus/pow/src/lib.rs b/client/consensus/pow/src/lib.rs index ace00a34459af..a81ad8ebea6f2 100644 --- a/client/consensus/pow/src/lib.rs +++ b/client/consensus/pow/src/lib.rs @@ -267,7 +267,7 @@ where async fn check_inherents( &self, block: B, - block_id: BlockId, + at_hash: B::Hash, inherent_data_providers: CIDP::InherentDataProviders, execution_context: ExecutionContext, ) -> Result<(), Error> { @@ -283,7 +283,7 @@ where let inherent_res = self .client .runtime_api() - .check_inherents_with_context(&block_id, execution_context, block, inherent_data) + .check_inherents_with_context(at_hash, execution_context, block, inherent_data) .map_err(|e| Error::Client(e.into()))?; if !inherent_res.ok() { @@ -344,7 +344,7 @@ where if !block.state_action.skip_execution_checks() { self.check_inherents( check_block.clone(), - BlockId::Hash(parent_hash), + parent_hash, self.create_inherent_data_providers .create_inherent_data_providers(parent_hash, ()) .await?, diff --git a/client/finality-grandpa/src/environment.rs b/client/finality-grandpa/src/environment.rs index a9aa204f12e2d..9ee7e486c709e 100644 --- a/client/finality-grandpa/src/environment.rs +++ b/client/finality-grandpa/src/environment.rs @@ -46,10 +46,7 @@ use sp_finality_grandpa::{ AuthorityId, AuthoritySignature, Equivocation, EquivocationProof, GrandpaApi, RoundNumber, SetId, GRANDPA_ENGINE_ID, }; -use sp_runtime::{ - generic::BlockId, - traits::{Block as BlockT, Header as HeaderT, NumberFor, Zero}, -}; +use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor, Zero}; use crate::{ authorities::{AuthoritySet, SharedAuthoritySet}, @@ -543,7 +540,7 @@ where .client .runtime_api() .generate_key_ownership_proof( - &BlockId::Hash(current_set_latest_hash), + current_set_latest_hash, authority_set.set_id, equivocation.offender().clone(), ) @@ -565,7 +562,7 @@ where self.client .runtime_api() .submit_report_equivocation_unsigned_extrinsic( - &BlockId::Hash(best_block_hash), + best_block_hash, equivocation_proof, key_owner_proof, ) diff --git a/client/finality-grandpa/src/import.rs b/client/finality-grandpa/src/import.rs index ed6e4a0fa2e9f..f5e2f96432327 100644 --- a/client/finality-grandpa/src/import.rs +++ b/client/finality-grandpa/src/import.rs @@ -34,7 +34,7 @@ use sp_consensus::{BlockOrigin, Error as ConsensusError, SelectChain}; use sp_core::hashing::twox_128; use sp_finality_grandpa::{ConsensusLog, GrandpaApi, ScheduledChange, SetId, GRANDPA_ENGINE_ID}; use sp_runtime::{ - generic::{BlockId, OpaqueDigestItemId}, + generic::OpaqueDigestItemId, traits::{Block as BlockT, Header as HeaderT, NumberFor, Zero}, Justification, }; @@ -424,8 +424,7 @@ where /// Read current set id form a given state. 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| { + let runtime_version = self.inner.runtime_api().version(hash).map_err(|e| { ConsensusError::ClientImport(format!( "Unable to retrieve current runtime version. {}", e @@ -452,7 +451,7 @@ where } else { self.inner .runtime_api() - .current_set_id(id) + .current_set_id(hash) .map_err(|e| ConsensusError::ClientImport(e.to_string())) } } @@ -477,7 +476,7 @@ where let authorities = self .inner .runtime_api() - .grandpa_authorities(&BlockId::hash(hash)) + .grandpa_authorities(hash) .map_err(|e| ConsensusError::ClientImport(e.to_string()))?; let set_id = self.current_set_id(hash)?; let authority_set = AuthoritySet::new( diff --git a/client/merkle-mountain-range/rpc/src/lib.rs b/client/merkle-mountain-range/rpc/src/lib.rs index 6e520b3bf130e..5c65be57ee509 100644 --- a/client/merkle-mountain-range/rpc/src/lib.rs +++ b/client/merkle-mountain-range/rpc/src/lib.rs @@ -34,7 +34,7 @@ use sp_api::{NumberFor, ProvideRuntimeApi}; use sp_blockchain::HeaderBackend; use sp_core::Bytes; use sp_mmr_primitives::{Error as MmrError, Proof}; -use sp_runtime::{generic::BlockId, traits::Block as BlockT}; +use sp_runtime::traits::Block as BlockT; pub use sp_mmr_primitives::MmrApi as MmrRuntimeApi; @@ -154,7 +154,7 @@ where self.client.info().best_hash); let api = self.client.runtime_api(); let mmr_root = api - .mmr_root(&BlockId::Hash(block_hash)) + .mmr_root(block_hash) .map_err(runtime_error_into_rpc_error)? .map_err(mmr_error_into_rpc_error)?; Ok(mmr_root) @@ -173,7 +173,7 @@ where let (leaves, proof) = api .generate_proof_with_context( - &BlockId::hash(block_hash), + block_hash, sp_core::ExecutionContext::OffchainCall(None), block_numbers, best_known_block_number, @@ -194,7 +194,7 @@ where .map_err(|e| CallError::InvalidParams(anyhow::Error::new(e)))?; api.verify_proof_with_context( - &BlockId::hash(proof.block_hash), + proof.block_hash, sp_core::ExecutionContext::OffchainCall(None), leaves, decoded_proof, @@ -218,14 +218,9 @@ where 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)?; + api.verify_proof_stateless(proof.block_hash, mmr_root, leaves, decoded_proof) + .map_err(runtime_error_into_rpc_error)? + .map_err(mmr_error_into_rpc_error)?; Ok(true) } diff --git a/client/merkle-mountain-range/src/lib.rs b/client/merkle-mountain-range/src/lib.rs index 568c4b94c1e08..ce7223525eae1 100644 --- a/client/merkle-mountain-range/src/lib.rs +++ b/client/merkle-mountain-range/src/lib.rs @@ -51,10 +51,7 @@ 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 sp_runtime::traits::{Block, Header, NumberFor}; use std::{marker::PhantomData, sync::Arc}; /// Logging target for the mmr gadget. @@ -71,15 +68,16 @@ where { /// Get the block number where the mmr pallet was added to the runtime. fn first_mmr_block_num(&self, notification: &FinalityNotification) -> Option> { - let best_block = *notification.header.number(); - match self.runtime_api().mmr_leaf_count(&BlockId::number(best_block)) { + let best_block_hash = notification.header.hash(); + let best_block_number = *notification.header.number(); + match self.runtime_api().mmr_leaf_count(best_block_hash) { Ok(Ok(mmr_leaf_count)) => { - match utils::first_mmr_block_num::(best_block, mmr_leaf_count) { + match utils::first_mmr_block_num::(best_block_number, mmr_leaf_count) { Ok(first_mmr_block) => { debug!( target: LOG_TARGET, "pallet-mmr detected at block {:?} with genesis at block {:?}", - best_block, + best_block_number, first_mmr_block ); Some(first_mmr_block) @@ -97,7 +95,7 @@ where trace!( target: LOG_TARGET, "pallet-mmr not detected at block {:?} ... (best finalized {:?})", - best_block, + best_block_number, notification.header.number() ); None diff --git a/client/offchain/src/lib.rs b/client/offchain/src/lib.rs index 6cf5838a46bed..904d127e1abdb 100644 --- a/client/offchain/src/lib.rs +++ b/client/offchain/src/lib.rs @@ -45,10 +45,7 @@ use parking_lot::Mutex; use sc_network_common::service::{NetworkPeers, NetworkStateInfo}; use sp_api::{ApiExt, ProvideRuntimeApi}; use sp_core::{offchain, traits::SpawnNamed, ExecutionContext}; -use sp_runtime::{ - generic::BlockId, - traits::{self, Header}, -}; +use sp_runtime::traits::{self, Header}; use threadpool::ThreadPool; mod api; @@ -123,9 +120,9 @@ where is_validator: bool, ) -> impl Future { let runtime = self.client.runtime_api(); - let at = BlockId::hash(header.hash()); - let has_api_v1 = runtime.has_api_with::, _>(&at, |v| v == 1); - let has_api_v2 = runtime.has_api_with::, _>(&at, |v| v == 2); + let hash = header.hash(); + let has_api_v1 = runtime.has_api_with::, _>(hash, |v| v == 1); + let has_api_v2 = runtime.has_api_with::, _>(hash, |v| v == 2); let version = match (has_api_v1, has_api_v2) { (_, Ok(true)) => 2, (Ok(true), _) => 1, @@ -144,13 +141,13 @@ where tracing::debug!( target: LOG_TARGET, "Checking offchain workers at {:?}: version:{}", - at, + hash, version ); let process = (version > 0).then(|| { let (api, runner) = api::AsyncApi::new(network_provider, is_validator, self.shared_http_client.clone()); - tracing::debug!(target: LOG_TARGET, "Spawning offchain workers at {:?}", at); + tracing::debug!(target: LOG_TARGET, "Spawning offchain workers at {:?}", hash); let header = header.clone(); let client = self.client.clone(); @@ -160,15 +157,15 @@ where self.spawn_worker(move || { let runtime = client.runtime_api(); let api = Box::new(api); - tracing::debug!(target: LOG_TARGET, "Running offchain workers at {:?}", at); + tracing::debug!(target: LOG_TARGET, "Running offchain workers at {:?}", hash); let context = ExecutionContext::OffchainCall(Some((api, capabilities))); let run = if version == 2 { - runtime.offchain_worker_with_context(&at, context, &header) + runtime.offchain_worker_with_context(hash, context, &header) } else { #[allow(deprecated)] runtime.offchain_worker_before_version_2_with_context( - &at, + hash, context, *header.number(), ) @@ -177,7 +174,7 @@ where tracing::error!( target: LOG_TARGET, "Error running offchain workers at {:?}: {}", - at, + hash, e ); } @@ -254,6 +251,7 @@ mod tests { use sc_transaction_pool::{BasicPool, FullChainApi}; use sc_transaction_pool_api::{InPoolTransaction, TransactionPool}; use sp_consensus::BlockOrigin; + use sp_runtime::generic::BlockId; use std::{collections::HashSet, sync::Arc}; use substrate_test_runtime_client::{ runtime::Block, ClientBlockImportExt, DefaultTestClientBuilderExt, TestClient, diff --git a/client/rpc-spec-v2/src/chain_head/chain_head.rs b/client/rpc-spec-v2/src/chain_head/chain_head.rs index 2a9cabaf2b310..76963d81edc38 100644 --- a/client/rpc-spec-v2/src/chain_head/chain_head.rs +++ b/client/rpc-spec-v2/src/chain_head/chain_head.rs @@ -53,10 +53,7 @@ use sp_blockchain::{ Backend as BlockChainBackend, Error as BlockChainError, HeaderBackend, HeaderMetadata, }; use sp_core::{hexdisplay::HexDisplay, storage::well_known_keys, Bytes}; -use sp_runtime::{ - generic::BlockId, - traits::{Block as BlockT, Header}, -}; +use sp_runtime::traits::{Block as BlockT, Header}; use std::{marker::PhantomData, sync::Arc}; /// An API for chain head RPC calls. @@ -142,12 +139,8 @@ where let finalized_block_hash = client.info().finalized_hash; handle.pin_block(finalized_block_hash)?; - let finalized_block_runtime = generate_runtime_event( - &client, - runtime_updates, - &BlockId::Hash(finalized_block_hash), - None, - ); + let finalized_block_runtime = + generate_runtime_event(&client, runtime_updates, finalized_block_hash, None); let initialized_event = FollowEvent::Initialized(Initialized { finalized_block_hash, @@ -162,12 +155,7 @@ where for (child, parent) in initial_blocks.into_iter() { handle.pin_block(child)?; - let new_runtime = generate_runtime_event( - &client, - runtime_updates, - &BlockId::Hash(child), - Some(&BlockId::Hash(parent)), - ); + let new_runtime = generate_runtime_event(&client, runtime_updates, child, Some(parent)); let event = FollowEvent::NewBlock(NewBlock { block_hash: child, @@ -214,8 +202,8 @@ fn parse_hex_param( fn generate_runtime_event( client: &Arc, runtime_updates: bool, - block: &BlockId, - parent: Option<&BlockId>, + block: Block::Hash, + parent: Option, ) -> Option where Block: BlockT + 'static, @@ -329,8 +317,8 @@ where let new_runtime = generate_runtime_event( &client, runtime_updates, - &BlockId::Hash(notification.hash), - Some(&BlockId::Hash(*notification.header.parent_hash())), + notification.hash, + Some(*notification.header.parent_hash()), ); // Note: `Block::Hash` will serialize to hexadecimal encoded string. diff --git a/client/rpc/src/author/mod.rs b/client/rpc/src/author/mod.rs index 7d0ffdc62e080..cf47e9faf6114 100644 --- a/client/rpc/src/author/mod.rs +++ b/client/rpc/src/author/mod.rs @@ -123,7 +123,7 @@ where let best_block_hash = self.client.info().best_hash; self.client .runtime_api() - .generate_session_keys(&generic::BlockId::Hash(best_block_hash), None) + .generate_session_keys(best_block_hash, None) .map(Into::into) .map_err(|api_err| Error::Client(Box::new(api_err)).into()) } @@ -135,7 +135,7 @@ where let keys = self .client .runtime_api() - .decode_session_keys(&generic::BlockId::Hash(best_block_hash), session_keys.to_vec()) + .decode_session_keys(best_block_hash, session_keys.to_vec()) .map_err(|e| Error::Client(Box::new(e)))? .ok_or(Error::InvalidSessionKeys)?; diff --git a/client/rpc/src/dev/mod.rs b/client/rpc/src/dev/mod.rs index e48a8ee4e7d5c..fa5d358b087bd 100644 --- a/client/rpc/src/dev/mod.rs +++ b/client/rpc/src/dev/mod.rs @@ -28,7 +28,7 @@ use sc_rpc_api::{dev::error::Error, DenyUnsafe}; use sp_api::{ApiExt, Core, ProvideRuntimeApi}; use sp_core::Encode; use sp_runtime::{ - generic::{BlockId, DigestItem}, + generic::DigestItem, traits::{Block as BlockT, Header}, }; use std::{ @@ -98,7 +98,7 @@ where let mut runtime_api = self.client.runtime_api(); runtime_api.record_proof(); runtime_api - .execute_block(&BlockId::Hash(parent_header.hash()), block) + .execute_block(parent_header.hash(), block) .map_err(|_| Error::BlockExecutionFailed)?; let witness = runtime_api .extract_proof() diff --git a/client/rpc/src/state/state_full.rs b/client/rpc/src/state/state_full.rs index 58dfd9ea876a1..b0c0922c6ceea 100644 --- a/client/rpc/src/state/state_full.rs +++ b/client/rpc/src/state/state_full.rs @@ -48,7 +48,7 @@ use sp_core::{ }, Bytes, }; -use sp_runtime::{generic::BlockId, traits::Block as BlockT}; +use sp_runtime::traits::Block as BlockT; use sp_version::RuntimeVersion; /// The maximum time allowed for an RPC call when running without unsafe RPC enabled. @@ -321,7 +321,7 @@ where self.block_or_best(block).map_err(client_err).and_then(|block| { self.client .runtime_api() - .metadata(&BlockId::Hash(block)) + .metadata(block) .map(Into::into) .map_err(|e| Error::Client(Box::new(e))) }) @@ -332,9 +332,7 @@ where 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))) + self.client.runtime_version_at(block).map_err(|e| Error::Client(Box::new(e))) }) } @@ -383,9 +381,7 @@ where let initial = match self .block_or_best(None) - .and_then(|block| { - self.client.runtime_version_at(&BlockId::Hash(block)).map_err(Into::into) - }) + .and_then(|block| self.client.runtime_version_at(block).map_err(Into::into)) .map_err(|e| Error::Client(Box::new(e))) { Ok(initial) => initial, @@ -402,9 +398,8 @@ where .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))); + let version = + client.runtime_version_at(n.hash).map_err(|e| Error::Client(Box::new(e))); match version { Ok(version) if version != previous_version => { diff --git a/client/service/src/client/client.rs b/client/service/src/client/client.rs index d452104ce7e51..7bd37b5163664 100644 --- a/client/service/src/client/client.rs +++ b/client/service/src/client/client.rs @@ -838,7 +838,6 @@ where CoreApi + ApiExt, { let parent_hash = import_block.header.parent_hash(); - let at = BlockId::Hash(*parent_hash); let state_action = std::mem::replace(&mut import_block.state_action, StateAction::Skip); let (enact_state, storage_changes) = match (self.block_status(*parent_hash)?, state_action) { @@ -870,7 +869,7 @@ where let execution_context = import_block.origin.into(); runtime_api.execute_block_with_context( - &at, + *parent_hash, execution_context, Block::new(import_block.header.clone(), body.clone()), )?; @@ -1725,10 +1724,9 @@ where &self, params: CallApiAtParams, ) -> Result, sp_api::ApiError> { - let at_hash = self.expect_block_hash_from_id(params.at)?; self.executor .contextual_call( - at_hash, + params.at, params.function, ¶ms.arguments, params.overlayed_changes, @@ -1739,8 +1737,7 @@ where .map_err(Into::into) } - fn runtime_version_at(&self, at: &BlockId) -> Result { - let hash = self.backend.blockchain().expect_block_hash_from_id(at)?; + fn runtime_version_at(&self, hash: Block::Hash) -> Result { CallExecutor::runtime_version(&self.executor, hash).map_err(Into::into) } diff --git a/client/service/test/src/client/mod.rs b/client/service/test/src/client/mod.rs index 12b92afc458b4..53af18c6b8604 100644 --- a/client/service/test/src/client/mod.rs +++ b/client/service/test/src/client/mod.rs @@ -291,20 +291,14 @@ fn client_initializes_from_genesis_ok() { assert_eq!( client .runtime_api() - .balance_of( - &BlockId::Number(client.chain_info().best_number), - AccountKeyring::Alice.into(), - ) + .balance_of(client.chain_info().best_hash, AccountKeyring::Alice.into()) .unwrap(), 1000 ); assert_eq!( client .runtime_api() - .balance_of( - &BlockId::Number(client.chain_info().best_number), - AccountKeyring::Ferdie.into(), - ) + .balance_of(client.chain_info().best_hash, AccountKeyring::Ferdie.into()) .unwrap(), 0 ); @@ -351,20 +345,14 @@ fn block_builder_works_with_transactions() { assert_eq!( client .runtime_api() - .balance_of( - &BlockId::Number(client.chain_info().best_number), - AccountKeyring::Alice.into(), - ) + .balance_of(client.chain_info().best_hash, AccountKeyring::Alice.into()) .unwrap(), 958 ); assert_eq!( client .runtime_api() - .balance_of( - &BlockId::Number(client.chain_info().best_number), - AccountKeyring::Ferdie.into(), - ) + .balance_of(client.chain_info().best_hash, AccountKeyring::Ferdie.into()) .unwrap(), 42 ); @@ -1256,10 +1244,7 @@ fn state_reverted_on_reorg() { let current_balance = |client: &substrate_test_runtime_client::TestClient| { client .runtime_api() - .balance_of( - &BlockId::number(client.chain_info().best_number), - AccountKeyring::Alice.into(), - ) + .balance_of(client.chain_info().best_hash, AccountKeyring::Alice.into()) .unwrap() }; @@ -1996,10 +1981,10 @@ fn use_dalek_ext_works() { // 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![]) + .verify_ed25519(client.chain_info().genesis_hash, zero_ed_sig(), zero_ed_pub(), vec![]) .unwrap()); assert!(client .runtime_api() - .verify_ed25519(&BlockId::Number(1), zero_ed_sig(), zero_ed_pub(), vec![]) + .verify_ed25519(a1.hash(), zero_ed_sig(), zero_ed_pub(), vec![]) .unwrap()); } diff --git a/client/tracing/src/block/mod.rs b/client/tracing/src/block/mod.rs index 89c0945e0eb03..465767781eb1f 100644 --- a/client/tracing/src/block/mod.rs +++ b/client/tracing/src/block/mod.rs @@ -229,7 +229,6 @@ where .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(); - let parent_id = BlockId::Hash(parent_hash); // Remove all `Seal`s as they are added by the consensus engines after building the block. // On import they are normally removed by the consensus engine. header.digest_mut().logs.retain(|d| d.as_seal().is_none()); @@ -249,7 +248,7 @@ where if let Err(e) = dispatcher::with_default(&dispatch, || { let span = tracing::info_span!(target: TRACE_TARGET, "trace_block"); let _enter = span.enter(); - self.client.runtime_api().execute_block(&parent_id, block) + self.client.runtime_api().execute_block(parent_hash, block) }) { return Err(Error::Dispatch(format!( "Failed to collect traces and execute block: {}", @@ -298,7 +297,7 @@ where } else { TraceBlockResponse::BlockTrace(BlockTrace { block_hash: block_id_as_string(BlockId::::Hash(self.block)), - parent_hash: block_id_as_string(parent_id), + parent_hash: block_id_as_string(BlockId::::Hash(parent_hash)), tracing_targets: targets.to_string(), storage_keys: self.storage_keys.clone().unwrap_or_default(), methods: self.methods.clone().unwrap_or_default(), diff --git a/client/transaction-pool/src/api.rs b/client/transaction-pool/src/api.rs index 0166dfaced208..9e20915dbacf6 100644 --- a/client/transaction-pool/src/api.rs +++ b/client/transaction-pool/src/api.rs @@ -225,27 +225,27 @@ where { sp_tracing::within_span!(sp_tracing::Level::TRACE, "validate_transaction"; { + let block_hash = client.to_hash(at) + .map_err(|e| Error::RuntimeApi(e.to_string()))? + .ok_or_else(|| Error::RuntimeApi(format!("Could not get hash for block `{:?}`.", at)))?; + let runtime_api = client.runtime_api(); let api_version = sp_tracing::within_span! { sp_tracing::Level::TRACE, "check_version"; runtime_api - .api_version::>(at) + .api_version::>(block_hash) .map_err(|e| Error::RuntimeApi(e.to_string()))? .ok_or_else(|| Error::RuntimeApi( format!("Could not find `TaggedTransactionQueue` api for block `{:?}`.", at) )) }?; - let block_hash = client.to_hash(at) - .map_err(|e| Error::RuntimeApi(e.to_string()))? - .ok_or_else(|| Error::RuntimeApi(format!("Could not get hash for block `{:?}`.", at)))?; - use sp_api::Core; sp_tracing::within_span!( sp_tracing::Level::TRACE, "runtime::validate_transaction"; { if api_version >= 3 { - runtime_api.validate_transaction(at, source, uxt, block_hash) + runtime_api.validate_transaction(block_hash, source, uxt, block_hash) .map_err(|e| Error::RuntimeApi(e.to_string())) } else { let block_number = client.to_number(at) @@ -255,7 +255,7 @@ where )?; // The old versions require us to call `initialize_block` before. - runtime_api.initialize_block(at, &sp_runtime::traits::Header::new( + runtime_api.initialize_block(block_hash, &sp_runtime::traits::Header::new( block_number + sp_runtime::traits::One::one(), Default::default(), Default::default(), @@ -265,11 +265,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(block_hash, 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(block_hash, uxt) .map_err(|e| Error::RuntimeApi(e.to_string())) } } diff --git a/frame/transaction-payment/rpc/src/lib.rs b/frame/transaction-payment/rpc/src/lib.rs index 19007d37963ec..46ad5dbc0f5fb 100644 --- a/frame/transaction-payment/rpc/src/lib.rs +++ b/frame/transaction-payment/rpc/src/lib.rs @@ -30,10 +30,7 @@ use sp_api::{ApiExt, ProvideRuntimeApi}; use sp_blockchain::HeaderBackend; use sp_core::Bytes; use sp_rpc::number::NumberOrHex; -use sp_runtime::{ - generic::BlockId, - traits::{Block as BlockT, MaybeDisplay}, -}; +use sp_runtime::traits::{Block as BlockT, MaybeDisplay}; pub use pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi as TransactionPaymentRuntimeApi; @@ -98,7 +95,7 @@ where at: Option, ) -> RpcResult> { let api = self.client.runtime_api(); - let at = BlockId::hash(at.unwrap_or_else(|| self.client.info().best_hash)); + let at_hash = at.unwrap_or_else(|| self.client.info().best_hash); let encoded_len = encoded_xt.len() as u32; @@ -119,7 +116,7 @@ where } let api_version = api - .api_version::>(&at) + .api_version::>(at_hash) .map_err(|e| map_err(e, "Failed to get transaction payment runtime api version"))? .ok_or_else(|| { CallError::Custom(ErrorObject::owned( @@ -131,11 +128,11 @@ where if api_version < 2 { #[allow(deprecated)] - api.query_info_before_version_2(&at, uxt, encoded_len) + api.query_info_before_version_2(at_hash, 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) + .query_info(at_hash, uxt, encoded_len) .map_err(|e| map_err(e, "Unable to query dispatch info."))?; Ok(RuntimeDispatchInfo { @@ -152,7 +149,7 @@ where at: Option, ) -> RpcResult> { let api = self.client.runtime_api(); - let at = BlockId::hash(at.unwrap_or_else(|| self.client.info().best_hash)); + let at_hash = at.unwrap_or_else(|| self.client.info().best_hash); let encoded_len = encoded_xt.len() as u32; @@ -163,7 +160,7 @@ where Some(format!("{:?}", e)), )) })?; - let fee_details = api.query_fee_details(&at, uxt, encoded_len).map_err(|e| { + let fee_details = api.query_fee_details(at_hash, uxt, encoded_len).map_err(|e| { CallError::Custom(ErrorObject::owned( Error::RuntimeError.into(), "Unable to query fee details.", diff --git a/primitives/api/proc-macro/src/decl_runtime_apis.rs b/primitives/api/proc-macro/src/decl_runtime_apis.rs index 8d46047dbda5a..c254237cc6688 100644 --- a/primitives/api/proc-macro/src/decl_runtime_apis.rs +++ b/primitives/api/proc-macro/src/decl_runtime_apis.rs @@ -316,7 +316,7 @@ fn generate_runtime_decls(decls: &[ItemTrait]) -> Result { /// Modify the given runtime api declaration to be usable on the client side. struct ToClientSideDecl<'a> { - block_id: &'a TokenStream, + block_hash: &'a TokenStream, crate_: &'a TokenStream, found_attributes: &'a mut HashMap<&'static str, Attribute>, /// Any error that we found while converting this declaration. @@ -329,7 +329,7 @@ impl<'a> ToClientSideDecl<'a> { fn process(mut self, decl: ItemTrait) -> ItemTrait { let mut decl = self.fold_item_trait(decl); - let block_id = self.block_id; + let block_hash = self.block_hash; let crate_ = self.crate_; // Add the special method that will be implemented by the `impl_runtime_apis!` macro @@ -339,7 +339,7 @@ impl<'a> ToClientSideDecl<'a> { #[doc(hidden)] fn __runtime_api_internal_call_api_at( &self, - at: &#block_id, + at: #block_hash, context: #crate_::ExecutionContext, params: std::vec::Vec, fn_name: &dyn Fn(#crate_::RuntimeVersion) -> &'static str, @@ -420,7 +420,7 @@ impl<'a> ToClientSideDecl<'a> { }; 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_hash, self.crate_); let crate_ = self.crate_; @@ -621,14 +621,14 @@ fn generate_client_side_decls(decls: &[ItemTrait]) -> Result { let decl = decl.clone(); let crate_ = generate_crate_access(HIDDEN_INCLUDES_ID); - let block_id = quote!( #crate_::BlockId ); + let block_hash = quote!( ::Hash ); let mut found_attributes = HashMap::new(); let mut errors = Vec::new(); let trait_ = decl.ident.clone(); let decl = ToClientSideDecl { crate_: &crate_, - block_id: &block_id, + block_hash: &block_hash, found_attributes: &mut found_attributes, errors: &mut errors, trait_: &trait_, diff --git a/primitives/api/proc-macro/src/impl_runtime_apis.rs b/primitives/api/proc-macro/src/impl_runtime_apis.rs index c3f4e36655d22..76c9e1164217f 100644 --- a/primitives/api/proc-macro/src/impl_runtime_apis.rs +++ b/primitives/api/proc-macro/src/impl_runtime_apis.rs @@ -233,7 +233,7 @@ fn generate_runtime_api_base_structures() -> Result { fn has_api( &self, - at: &#crate_::BlockId, + at: ::Hash, ) -> std::result::Result where Self: Sized { #crate_::CallApiAt::::runtime_version_at(self.call, at) .map(|v| #crate_::RuntimeVersion::has_api_with(&v, &A::ID, |v| v == A::VERSION)) @@ -241,7 +241,7 @@ fn generate_runtime_api_base_structures() -> Result { fn has_api_with bool>( &self, - at: &#crate_::BlockId, + at: ::Hash, pred: P, ) -> std::result::Result where Self: Sized { #crate_::CallApiAt::::runtime_version_at(self.call, at) @@ -250,7 +250,7 @@ fn generate_runtime_api_base_structures() -> Result { fn api_version( &self, - at: &#crate_::BlockId, + at: ::Hash, ) -> std::result::Result, #crate_::ApiError> where Self: Sized { #crate_::CallApiAt::::runtime_version_at(self.call, at) .map(|v| #crate_::RuntimeVersion::api_version(&v, &A::ID)) @@ -281,8 +281,7 @@ fn generate_runtime_api_base_structures() -> Result { #crate_::StorageChanges, String > where Self: Sized { - let at = #crate_::BlockId::Hash(std::clone::Clone::clone(&parent_hash)); - let state_version = #crate_::CallApiAt::::runtime_version_at(self.call, &at) + let state_version = #crate_::CallApiAt::::runtime_version_at(self.call, std::clone::Clone::clone(&parent_hash)) .map(|v| #crate_::RuntimeVersion::state_version(&v)) .map_err(|e| format!("Failed to get state version: {}", e))?; @@ -424,7 +423,7 @@ impl<'a> ApiRuntimeImplToApiRuntimeApiImpl<'a> { input.items.push(parse_quote! { fn __runtime_api_internal_call_api_at( &self, - at: &#crate_::BlockId<__SR_API_BLOCK__>, + at: <__SR_API_BLOCK__ as #crate_::BlockT>::Hash, context: #crate_::ExecutionContext, params: std::vec::Vec, fn_name: &dyn Fn(#crate_::RuntimeVersion) -> &'static str, 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 e43a302e18923..493111e4f6158 100644 --- a/primitives/api/proc-macro/src/mock_impl_runtime_apis.rs +++ b/primitives/api/proc-macro/src/mock_impl_runtime_apis.rs @@ -38,7 +38,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 +/// If this attribute is given to a function, the function gets access to the `Hash` as first /// parameter and needs to return a `Result` with the appropriate error type. const ADVANCED_ATTRIBUTE: &str = "advanced"; @@ -80,14 +80,14 @@ fn implement_common_api_traits(block_type: TypePath, self_ty: Type) -> Result( &self, - _: &#crate_::BlockId<#block_type>, + _: ::Hash, ) -> std::result::Result where Self: Sized { Ok(true) } fn has_api_with bool>( &self, - _: &#crate_::BlockId<#block_type>, + _: ::Hash, pred: P, ) -> std::result::Result where Self: Sized { Ok(pred(A::VERSION)) @@ -95,7 +95,7 @@ fn implement_common_api_traits(block_type: TypePath, self_ty: Type) -> Result( &self, - _: &#crate_::BlockId<#block_type>, + _: ::Hash, ) -> std::result::Result, #crate_::ApiError> where Self: Sized { Ok(Some(A::VERSION)) } @@ -129,7 +129,7 @@ fn implement_common_api_traits(block_type: TypePath, self_ty: Type) -> Result for #self_ty { fn __runtime_api_internal_call_api_at( &self, - _: &#crate_::BlockId<#block_type>, + _: <#block_type as #crate_::BlockT>::Hash, _: #crate_::ExecutionContext, _: std::vec::Vec, _: &dyn Fn(#crate_::RuntimeVersion) -> &'static str, @@ -139,14 +139,14 @@ fn implement_common_api_traits(block_type: TypePath, self_ty: Type) -> Result, + _: <#block_type as #crate_::BlockT>::Hash, ) -> 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>, + _: <#block_type as #crate_::BlockT>::Hash, _: #crate_::ExecutionContext, ) -> std::result::Result<#crate_::RuntimeVersion, #crate_::ApiError> { unimplemented!("`Core::version` not implemented for runtime api mocks") @@ -154,7 +154,7 @@ fn implement_common_api_traits(block_type: TypePath, self_ty: Type) -> Result, + _: <#block_type as #crate_::BlockT>::Hash, _: #block_type, ) -> std::result::Result<(), #crate_::ApiError> { unimplemented!("`Core::execute_block` not implemented for runtime api mocks") @@ -162,7 +162,7 @@ fn implement_common_api_traits(block_type: TypePath, self_ty: Type) -> Result, + _: <#block_type as #crate_::BlockT>::Hash, _: #crate_::ExecutionContext, _: #block_type, ) -> std::result::Result<(), #crate_::ApiError> { @@ -171,7 +171,7 @@ fn implement_common_api_traits(block_type: TypePath, self_ty: Type) -> Result, + _: <#block_type as #crate_::BlockT>::Hash, _: &<#block_type as #crate_::BlockT>::Header, ) -> std::result::Result<(), #crate_::ApiError> { unimplemented!("`Core::initialize_block` not implemented for runtime api mocks") @@ -179,7 +179,7 @@ fn implement_common_api_traits(block_type: TypePath, self_ty: Type) -> Result, + _: <#block_type as #crate_::BlockT>::Hash, _: #crate_::ExecutionContext, _: &<#block_type as #crate_::BlockT>::Header, ) -> std::result::Result<(), #crate_::ApiError> { @@ -214,7 +214,7 @@ fn get_at_param_name( param_names: &mut Vec, param_types_and_borrows: &mut Vec<(TokenStream, bool)>, function_span: Span, - default_block_id_type: &TokenStream, + default_hash_type: &TokenStream, ) -> Result<(TokenStream, TokenStream)> { if is_advanced { if param_names.is_empty() { @@ -222,7 +222,7 @@ fn get_at_param_name( function_span, format!( "If using the `{}` attribute, it is required that the function \ - takes at least one argument, the `BlockId`.", + takes at least one argument, the `Hash`.", ADVANCED_ATTRIBUTE, ), )) @@ -232,17 +232,14 @@ fn get_at_param_name( // `param_types` can not be empty as well. let ptype_and_borrows = param_types_and_borrows.remove(0); let span = ptype_and_borrows.1.span(); - if !ptype_and_borrows.1 { - return Err(Error::new( - span, - "`BlockId` needs to be taken by reference and not by value!", - )) + if ptype_and_borrows.1 { + return Err(Error::new(span, "`Hash` needs to be taken by value and not by reference!")) } let name = param_names.remove(0); Ok((quote!( #name ), ptype_and_borrows.0)) } else { - Ok((quote!(_), default_block_id_type.clone())) + Ok((quote!(_), default_hash_type.clone())) } } @@ -279,7 +276,7 @@ impl<'a> FoldRuntimeApiImpl<'a> { impl_item.items.push(parse_quote! { fn __runtime_api_internal_call_api_at( &self, - _: &#crate_::BlockId<#block_type>, + _: <#block_type as #crate_::BlockT>::Hash, _: #crate_::ExecutionContext, _: std::vec::Vec, _: &dyn Fn(#crate_::RuntimeVersion) -> &'static str, @@ -325,19 +322,19 @@ impl<'a> Fold for FoldRuntimeApiImpl<'a> { }; let block_type = &self.block_type; - let block_id_type = quote!( &#crate_::BlockId<#block_type> ); + let hash_type = quote!( <#block_type as #crate_::BlockT>::Hash ); - let (at_param_name, block_id_type) = match get_at_param_name( + let (at_param_name, hash_type) = match get_at_param_name( is_advanced, &mut param_names, &mut param_types_and_borrows, input.span(), - &block_id_type, + &hash_type, ) { Ok(res) => res, Err(e) => { errors.push(e.to_compile_error()); - (quote!(_), block_id_type) + (quote!(_), hash_type) }, }; @@ -345,7 +342,7 @@ impl<'a> Fold for FoldRuntimeApiImpl<'a> { // Rewrite the input parameters. input.sig.inputs = parse_quote! { &self, - #at_param_name: #block_id_type, + #at_param_name: #hash_type, #( #param_names: #param_types ),* }; diff --git a/primitives/api/proc-macro/src/utils.rs b/primitives/api/proc-macro/src/utils.rs index 2ccd050cfb151..6f2a766e9c01f 100644 --- a/primitives/api/proc-macro/src/utils.rs +++ b/primitives/api/proc-macro/src/utils.rs @@ -94,13 +94,13 @@ pub fn replace_wild_card_parameter_names(input: &mut Signature) { /// Fold the given `Signature` to make it usable on the client side. pub fn fold_fn_decl_for_client_side( input: &mut Signature, - block_id: &TokenStream, + block_hash: &TokenStream, crate_: &TokenStream, ) { replace_wild_card_parameter_names(input); - // Add `&self, at:& BlockId` as parameters to each function at the beginning. - input.inputs.insert(0, parse_quote!( __runtime_api_at_param__: &#block_id )); + // Add `&self, at:& Block::Hash` as parameters to each function at the beginning. + input.inputs.insert(0, parse_quote!( __runtime_api_at_param__: #block_hash )); input.inputs.insert(0, parse_quote!(&self)); // Wrap the output in a `Result` diff --git a/primitives/api/src/lib.rs b/primitives/api/src/lib.rs index ad9a9b1811859..c9605b8111cc5 100644 --- a/primitives/api/src/lib.rs +++ b/primitives/api/src/lib.rs @@ -115,7 +115,7 @@ pub const MAX_EXTRINSIC_DEPTH: u32 = 256; /// The macro will create two declarations, one for using on the client side and one for using /// on the runtime side. The declaration for the runtime side is hidden in its own module. /// The client side declaration gets two extra parameters per function, -/// `&self` and `at: &BlockId`. The runtime side declaration will match the given trait +/// `&self` and `at: Block::Hash`. The runtime side declaration will match the given trait /// declaration. Besides one exception, the macro adds an extra generic parameter `Block: /// BlockT` to the client side and the runtime side. This generic parameter is usable by the /// user. @@ -182,7 +182,7 @@ 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)` +/// function `has_api()`. Also the `ApiExt` provides a function `has_api(at: Hash)` /// to check if the runtime at the given block id implements the requested runtime api trait. /// /// # Declaring multiple api versions @@ -400,16 +400,16 @@ pub use sp_api_proc_macro::impl_runtime_apis; /// /// This attribute can be placed above individual function in the mock implementation to /// request more control over the function declaration. From the client side each runtime api -/// function is called with the `at` parameter that is a [`BlockId`](sp_api::BlockId). When -/// 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`]`<, Error>` while `ReturnValue` being the return -/// value that is specified in the trait declaration. +/// function is called with the `at` parameter that is a [`Hash`](sp_runtime::traits::Hash). +/// When 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`]`<, 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_runtime::traits::Block as BlockT; /// # use sp_test_primitives::Block; /// # use codec; /// # @@ -429,16 +429,14 @@ 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 { +/// fn get_balance(&self, at: ::Hash) -> Result { /// println!("Being called at: {}", at); /// /// Ok(self.balance.into()) /// } /// #[advanced] -/// 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); -/// } +/// fn set_balance(at: ::Hash, val: u64) -> Result<(), sp_api::ApiError> { +/// println!("Being called at: {}", at); /// /// Ok(().into()) /// } @@ -539,14 +537,14 @@ pub trait ApiExt { Self: Sized; /// Checks if the given api is implemented and versions match. - fn has_api(&self, at: &BlockId) -> Result + fn has_api(&self, at_hash: Block::Hash) -> Result where Self: Sized; /// Check if the given api is implemented and the version passes a predicate. fn has_api_with bool>( &self, - at: &BlockId, + at_hash: Block::Hash, pred: P, ) -> Result where @@ -555,7 +553,7 @@ pub trait ApiExt { /// Returns the version of the given api. fn api_version( &self, - at: &BlockId, + at_hash: Block::Hash, ) -> Result, ApiError> where Self: Sized; @@ -590,7 +588,7 @@ pub trait ApiExt { #[cfg(feature = "std")] 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, + pub at: Block::Hash, /// The name of the function that should be called. pub function: &'static str, /// The encoded arguments of the function. @@ -619,7 +617,7 @@ pub trait CallApiAt { ) -> Result, ApiError>; /// Returns the runtime version at the given block. - fn runtime_version_at(&self, at: &BlockId) -> Result; + fn runtime_version_at(&self, at_hash: Block::Hash) -> Result; /// Get the state `at` the given block. fn state_at(&self, at: Block::Hash) -> Result; diff --git a/primitives/api/test/benches/bench.rs b/primitives/api/test/benches/bench.rs index 2445a5c07f09e..0d47d3038a8b8 100644 --- a/primitives/api/test/benches/bench.rs +++ b/primitives/api/test/benches/bench.rs @@ -17,7 +17,6 @@ use criterion::{criterion_group, criterion_main, Criterion}; use sp_api::ProvideRuntimeApi; -use sp_runtime::generic::BlockId; use sp_state_machine::ExecutionStrategy; use substrate_test_runtime_client::{ runtime::TestAPI, DefaultTestClientBuilderExt, TestClientBuilder, TestClientBuilderExt, @@ -27,49 +26,49 @@ 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::Hash(client.chain_info().best_hash); + let best_hash = client.chain_info().best_hash; - b.iter(|| runtime_api.benchmark_add_one(&block_id, &1)) + b.iter(|| runtime_api.benchmark_add_one(best_hash, &1)) }); c.bench_function("add one with recreating runtime api", |b| { let client = substrate_test_runtime_client::new(); - let block_id = BlockId::Hash(client.chain_info().best_hash); + let best_hash = client.chain_info().best_hash; - b.iter(|| client.runtime_api().benchmark_add_one(&block_id, &1)) + b.iter(|| client.runtime_api().benchmark_add_one(best_hash, &1)) }); 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::Hash(client.chain_info().best_hash); + let best_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)) + b.iter_with_large_drop(|| runtime_api.benchmark_vector_add_one(best_hash, &data)) }); c.bench_function("vector add one with recreating runtime api", |b| { let client = substrate_test_runtime_client::new(); - let block_id = BlockId::Hash(client.chain_info().best_hash); + let best_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)) + b.iter_with_large_drop(|| client.runtime_api().benchmark_vector_add_one(best_hash, &data)) }); c.bench_function("calling function by function pointer in wasm", |b| { let client = TestClientBuilder::new() .set_execution_strategy(ExecutionStrategy::AlwaysWasm) .build(); - let block_id = BlockId::Hash(client.chain_info().best_hash); - b.iter(|| client.runtime_api().benchmark_indirect_call(&block_id).unwrap()) + let best_hash = client.chain_info().best_hash; + b.iter(|| client.runtime_api().benchmark_indirect_call(best_hash).unwrap()) }); c.bench_function("calling function in wasm", |b| { let client = TestClientBuilder::new() .set_execution_strategy(ExecutionStrategy::AlwaysWasm) .build(); - let block_id = BlockId::Hash(client.chain_info().best_hash); - b.iter(|| client.runtime_api().benchmark_direct_call(&block_id).unwrap()) + let best_hash = client.chain_info().best_hash; + b.iter(|| client.runtime_api().benchmark_direct_call(best_hash).unwrap()) }); } diff --git a/primitives/api/test/tests/decl_and_impl.rs b/primitives/api/test/tests/decl_and_impl.rs index 42628830cc7fa..47e33d81d43f7 100644 --- a/primitives/api/test/tests/decl_and_impl.rs +++ b/primitives/api/test/tests/decl_and_impl.rs @@ -18,11 +18,9 @@ use sp_api::{ decl_runtime_apis, impl_runtime_apis, mock_impl_runtime_apis, ApiError, ApiExt, RuntimeApiInfo, }; -use sp_runtime::{ - generic::BlockId, - traits::{Block as BlockT, GetNodeBlockType}, -}; -use substrate_test_runtime_client::runtime::Block; +use sp_runtime::traits::{Block as BlockT, GetNodeBlockType}; + +use substrate_test_runtime_client::runtime::{Block, Hash}; /// The declaration of the `Runtime` type and the implementation of the `GetNodeBlockType` /// trait are done by the `construct_runtime!` macro in a real runtime. @@ -119,13 +117,13 @@ mock_impl_runtime_apis! { } #[advanced] - fn same_name(_: &BlockId) -> Result<(), ApiError> { + fn same_name(_: ::Hash) -> Result<(), ApiError> { Ok(().into()) } #[advanced] - fn wild_card(at: &BlockId, _: u32) -> Result<(), ApiError> { - if let BlockId::Number(1337) = at { + fn wild_card(at: ::Hash, _: u32) -> Result<(), ApiError> { + if Hash::repeat_byte(0x0f) == at { // yeah Ok(().into()) } else { @@ -150,19 +148,19 @@ type TestClient = substrate_test_runtime_client::client::Client< fn test_client_side_function_signature() { let _test: fn( &RuntimeApiImpl, - &BlockId, + ::Hash, u64, ) -> Result<(), ApiError> = RuntimeApiImpl::::test; let _something_with_block: fn( &RuntimeApiImpl, - &BlockId, + ::Hash, Block, ) -> Result = RuntimeApiImpl::::something_with_block; #[allow(deprecated)] let _same_name_before_version_2: fn( &RuntimeApiImpl, - &BlockId, + ::Hash, ) -> Result = RuntimeApiImpl::::same_name_before_version_2; } @@ -204,8 +202,8 @@ fn check_runtime_api_versions() { fn mock_runtime_api_has_api() { let mock = MockApi { block: None }; - assert!(mock.has_api::>(&BlockId::Number(0)).unwrap()); - assert!(mock.has_api::>(&BlockId::Number(0)).unwrap()); + assert!(mock.has_api::>(Hash::default()).unwrap()); + assert!(mock.has_api::>(Hash::default()).unwrap()); } #[test] @@ -214,17 +212,17 @@ fn mock_runtime_api_panics_on_calling_old_version() { let mock = MockApi { block: None }; #[allow(deprecated)] - let _ = mock.same_name_before_version_2(&BlockId::Number(0)); + let _ = mock.same_name_before_version_2(Hash::default()); } #[test] fn mock_runtime_api_works_with_advanced() { let mock = MockApi { block: None }; - Api::::same_name(&mock, &BlockId::Number(0)).unwrap(); - mock.wild_card(&BlockId::Number(1337), 1).unwrap(); + Api::::same_name(&mock, Hash::default()).unwrap(); + mock.wild_card(Hash::repeat_byte(0x0f), 1).unwrap(); assert_eq!( "Test error".to_string(), - mock.wild_card(&BlockId::Number(1336), 1).unwrap_err().to_string(), + mock.wild_card(Hash::repeat_byte(0x01), 1).unwrap_err().to_string(), ); } diff --git a/primitives/api/test/tests/runtime_calls.rs b/primitives/api/test/tests/runtime_calls.rs index 3d355c4747736..4f88d887c8c55 100644 --- a/primitives/api/test/tests/runtime_calls.rs +++ b/primitives/api/test/tests/runtime_calls.rs @@ -36,9 +36,9 @@ use sp_consensus::SelectChain; fn calling_function_with_strat(strat: ExecutionStrategy) { let client = TestClientBuilder::new().set_execution_strategy(strat).build(); let runtime_api = client.runtime_api(); - let block_id = BlockId::Number(client.chain_info().best_number); + let best_hash = client.chain_info().best_hash; - assert_eq!(runtime_api.benchmark_add_one(&block_id, &1).unwrap(), 2); + assert_eq!(runtime_api.benchmark_add_one(best_hash, &1).unwrap(), 2); } #[test] @@ -57,9 +57,9 @@ fn calling_native_runtime_signature_changed_function() { .set_execution_strategy(ExecutionStrategy::NativeWhenPossible) .build(); let runtime_api = client.runtime_api(); - let block_id = BlockId::Number(client.chain_info().best_number); + let best_hash = client.chain_info().best_hash; - assert_eq!(runtime_api.function_signature_changed(&block_id).unwrap(), 1); + assert_eq!(runtime_api.function_signature_changed(best_hash).unwrap(), 1); } #[test] @@ -68,10 +68,10 @@ fn calling_wasm_runtime_signature_changed_old_function() { .set_execution_strategy(ExecutionStrategy::AlwaysWasm) .build(); let runtime_api = client.runtime_api(); - let block_id = BlockId::Number(client.chain_info().best_number); + let best_hash = client.chain_info().best_hash; #[allow(deprecated)] - let res = runtime_api.function_signature_changed_before_version_2(&block_id).unwrap(); + let res = runtime_api.function_signature_changed_before_version_2(best_hash).unwrap(); assert_eq!(&res, &[1, 2]); } @@ -79,16 +79,16 @@ fn calling_wasm_runtime_signature_changed_old_function() { fn calling_with_both_strategy_and_fail_on_wasm_should_return_error() { 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); - assert!(runtime_api.fail_on_wasm(&block_id).is_err()); + let best_hash = client.chain_info().best_hash; + assert!(runtime_api.fail_on_wasm(best_hash).is_err()); } #[test] fn calling_with_both_strategy_and_fail_on_native_should_work() { 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); - assert_eq!(runtime_api.fail_on_native(&block_id).unwrap(), 1); + let best_hash = client.chain_info().best_hash; + assert_eq!(runtime_api.fail_on_native(best_hash).unwrap(), 1); } #[test] @@ -97,8 +97,8 @@ fn calling_with_native_else_wasm_and_fail_on_wasm_should_work() { .set_execution_strategy(ExecutionStrategy::NativeElseWasm) .build(); let runtime_api = client.runtime_api(); - let block_id = BlockId::Number(client.chain_info().best_number); - assert_eq!(runtime_api.fail_on_wasm(&block_id).unwrap(), 1); + let best_hash = client.chain_info().best_hash; + assert_eq!(runtime_api.fail_on_wasm(best_hash).unwrap(), 1); } #[test] @@ -107,8 +107,8 @@ fn calling_with_native_else_wasm_and_fail_on_native_should_work() { .set_execution_strategy(ExecutionStrategy::NativeElseWasm) .build(); let runtime_api = client.runtime_api(); - let block_id = BlockId::Number(client.chain_info().best_number); - assert_eq!(runtime_api.fail_on_native(&block_id).unwrap(), 1); + let best_hash = client.chain_info().best_hash; + assert_eq!(runtime_api.fail_on_native(best_hash).unwrap(), 1); } #[test] @@ -117,18 +117,18 @@ fn use_trie_function() { .set_execution_strategy(ExecutionStrategy::AlwaysWasm) .build(); let runtime_api = client.runtime_api(); - let block_id = BlockId::Number(client.chain_info().best_number); - assert_eq!(runtime_api.use_trie(&block_id).unwrap(), 2); + let best_hash = client.chain_info().best_hash; + assert_eq!(runtime_api.use_trie(best_hash).unwrap(), 2); } #[test] fn initialize_block_works() { 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 best_hash = client.chain_info().best_hash; runtime_api .initialize_block( - &block_id, + best_hash, &Header::new( 1, Default::default(), @@ -138,7 +138,7 @@ fn initialize_block_works() { ), ) .unwrap(); - assert_eq!(runtime_api.get_block_number(&block_id).unwrap(), 1); + assert_eq!(runtime_api.get_block_number(best_hash).unwrap(), 1); } #[test] @@ -205,10 +205,10 @@ fn call_runtime_api_with_multiple_arguments() { let client = TestClientBuilder::new().set_execution_strategy(ExecutionStrategy::Both).build(); let data = vec![1, 2, 4, 5, 6, 7, 8, 8, 10, 12]; - let block_id = BlockId::Number(client.chain_info().best_number); + let best_hash = client.chain_info().best_hash; client .runtime_api() - .test_multiple_arguments(&block_id, data.clone(), data.clone(), data.len() as u32) + .test_multiple_arguments(best_hash, data.clone(), data.clone(), data.len() as u32) .unwrap(); } @@ -225,8 +225,9 @@ fn disable_logging_works() { let client = builder.build(); let runtime_api = client.runtime_api(); - let block_id = BlockId::Number(0); - runtime_api.do_trace_log(&block_id).expect("Logging should not fail"); + runtime_api + .do_trace_log(client.chain_info().genesis_hash) + .expect("Logging should not fail"); log::error!("Logging from native works"); } else { let executable = std::env::current_exe().unwrap(); diff --git a/primitives/api/test/tests/ui/mock_advanced_block_id_by_value.rs b/primitives/api/test/tests/ui/mock_advanced_hash_by_reference.rs similarity index 81% rename from primitives/api/test/tests/ui/mock_advanced_block_id_by_value.rs rename to primitives/api/test/tests/ui/mock_advanced_hash_by_reference.rs index aeef40f4c77d6..45e6adb2fcf94 100644 --- a/primitives/api/test/tests/ui/mock_advanced_block_id_by_value.rs +++ b/primitives/api/test/tests/ui/mock_advanced_hash_by_reference.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, _: &Hash) -> 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_hash_by_reference.stderr similarity index 60% rename from primitives/api/test/tests/ui/mock_advanced_block_id_by_value.stderr rename to primitives/api/test/tests/ui/mock_advanced_hash_by_reference.stderr index 3b3c4e94c3121..234331c9749bb 100644 --- a/primitives/api/test/tests/ui/mock_advanced_block_id_by_value.stderr +++ b/primitives/api/test/tests/ui/mock_advanced_hash_by_reference.stderr @@ -1,10 +1,10 @@ -error: `BlockId` needs to be taken by reference and not by value! - --> tests/ui/mock_advanced_block_id_by_value.rs:12:1 +error: `Hash` needs to be taken by value and not by reference! + --> tests/ui/mock_advanced_hash_by_reference.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, _: &Hash) -> 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_hash.rs similarity index 100% rename from primitives/api/test/tests/ui/mock_advanced_missing_blockid.rs rename to primitives/api/test/tests/ui/mock_advanced_missing_hash.rs diff --git a/primitives/api/test/tests/ui/mock_advanced_missing_blockid.stderr b/primitives/api/test/tests/ui/mock_advanced_missing_hash.stderr similarity index 56% rename from primitives/api/test/tests/ui/mock_advanced_missing_blockid.stderr rename to primitives/api/test/tests/ui/mock_advanced_missing_hash.stderr index b9ce7324b5caa..48a94a00beae7 100644 --- a/primitives/api/test/tests/ui/mock_advanced_missing_blockid.stderr +++ b/primitives/api/test/tests/ui/mock_advanced_missing_hash.stderr @@ -1,5 +1,5 @@ -error: If using the `advanced` attribute, it is required that the function takes at least one argument, the `BlockId`. - --> tests/ui/mock_advanced_missing_blockid.rs:15:3 +error: If using the `advanced` attribute, it is required that the function takes at least one argument, the `Hash`. + --> tests/ui/mock_advanced_missing_hash.rs:15:3 | 15 | fn test(&self) -> Result<(), ApiError> { | ^^ diff --git a/primitives/application-crypto/test/src/ecdsa.rs b/primitives/application-crypto/test/src/ecdsa.rs index e45a3d5f8f86c..4fe77db30fc66 100644 --- a/primitives/application-crypto/test/src/ecdsa.rs +++ b/primitives/application-crypto/test/src/ecdsa.rs @@ -20,7 +20,6 @@ use sp_api::ProvideRuntimeApi; use sp_application_crypto::ecdsa::{AppPair, AppPublic}; use sp_core::{crypto::Pair, testing::ECDSA}; use sp_keystore::{testing::KeyStore, SyncCryptoStore}; -use sp_runtime::generic::BlockId; use std::sync::Arc; use substrate_test_runtime_client::{ runtime::TestAPI, DefaultTestClientBuilderExt, TestClientBuilder, TestClientBuilderExt, @@ -32,7 +31,7 @@ fn ecdsa_works_in_runtime() { let test_client = TestClientBuilder::new().set_keystore(keystore.clone()).build(); let (signature, public) = test_client .runtime_api() - .test_ecdsa_crypto(&BlockId::Number(0)) + .test_ecdsa_crypto(test_client.chain_info().genesis_hash) .expect("Tests `ecdsa` crypto."); let supported_keys = SyncCryptoStore::keys(&*keystore, ECDSA).unwrap(); diff --git a/primitives/application-crypto/test/src/ed25519.rs b/primitives/application-crypto/test/src/ed25519.rs index ef2df9fe9196e..7f37744ec88ee 100644 --- a/primitives/application-crypto/test/src/ed25519.rs +++ b/primitives/application-crypto/test/src/ed25519.rs @@ -21,7 +21,6 @@ use sp_api::ProvideRuntimeApi; use sp_application_crypto::ed25519::{AppPair, AppPublic}; use sp_core::{crypto::Pair, testing::ED25519}; use sp_keystore::{testing::KeyStore, SyncCryptoStore}; -use sp_runtime::generic::BlockId; use std::sync::Arc; use substrate_test_runtime_client::{ runtime::TestAPI, DefaultTestClientBuilderExt, TestClientBuilder, TestClientBuilderExt, @@ -33,7 +32,7 @@ fn ed25519_works_in_runtime() { let test_client = TestClientBuilder::new().set_keystore(keystore.clone()).build(); let (signature, public) = test_client .runtime_api() - .test_ed25519_crypto(&BlockId::Number(0)) + .test_ed25519_crypto(test_client.chain_info().genesis_hash) .expect("Tests `ed25519` crypto."); let supported_keys = SyncCryptoStore::keys(&*keystore, ED25519).unwrap(); diff --git a/primitives/application-crypto/test/src/sr25519.rs b/primitives/application-crypto/test/src/sr25519.rs index e15ffe82a1c35..aa6734bf61d23 100644 --- a/primitives/application-crypto/test/src/sr25519.rs +++ b/primitives/application-crypto/test/src/sr25519.rs @@ -21,7 +21,6 @@ use sp_api::ProvideRuntimeApi; use sp_application_crypto::sr25519::{AppPair, AppPublic}; use sp_core::{crypto::Pair, testing::SR25519}; use sp_keystore::{testing::KeyStore, SyncCryptoStore}; -use sp_runtime::generic::BlockId; use std::sync::Arc; use substrate_test_runtime_client::{ runtime::TestAPI, DefaultTestClientBuilderExt, TestClientBuilder, TestClientBuilderExt, @@ -33,7 +32,7 @@ fn sr25519_works_in_runtime() { let test_client = TestClientBuilder::new().set_keystore(keystore.clone()).build(); let (signature, public) = test_client .runtime_api() - .test_sr25519_crypto(&BlockId::Number(0)) + .test_sr25519_crypto(test_client.chain_info().genesis_hash) .expect("Tests `sr25519` crypto."); let supported_keys = SyncCryptoStore::keys(&*keystore, SR25519).unwrap(); diff --git a/primitives/beefy/src/mmr.rs b/primitives/beefy/src/mmr.rs index 549d2edbdf287..ca60f2a918bac 100644 --- a/primitives/beefy/src/mmr.rs +++ b/primitives/beefy/src/mmr.rs @@ -145,7 +145,6 @@ mod mmr_root_provider { use crate::{known_payloads, payload::PayloadProvider, Payload}; use sp_api::{NumberFor, 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. @@ -170,11 +169,7 @@ mod mmr_root_provider { /// 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()) + self.runtime.runtime_api().mmr_root(header.hash()).ok().and_then(|r| r.ok()) }) } } diff --git a/primitives/runtime/src/runtime_logger.rs b/primitives/runtime/src/runtime_logger.rs index 8b5a15762e1f3..fa866f8342a1f 100644 --- a/primitives/runtime/src/runtime_logger.rs +++ b/primitives/runtime/src/runtime_logger.rs @@ -65,7 +65,7 @@ impl log::Log for RuntimeLogger { #[cfg(test)] mod tests { - use sp_api::{BlockId, ProvideRuntimeApi}; + use sp_api::ProvideRuntimeApi; use std::{env, str::FromStr}; use substrate_test_runtime_client::{ runtime::TestAPI, DefaultTestClientBuilderExt, ExecutionStrategy, TestClientBuilder, @@ -82,8 +82,9 @@ mod tests { .set_execution_strategy(ExecutionStrategy::AlwaysWasm) .build(); let runtime_api = client.runtime_api(); - let block_id = BlockId::Number(0); - runtime_api.do_trace_log(&block_id).expect("Logging should not fail"); + runtime_api + .do_trace_log(client.chain_info().genesis_hash) + .expect("Logging should not fail"); } else { for (level, should_print) in &[("trace", true), ("info", false)] { let executable = std::env::current_exe().unwrap(); diff --git a/primitives/session/src/lib.rs b/primitives/session/src/lib.rs index 9b403409c9151..9688547db42a3 100644 --- a/primitives/session/src/lib.rs +++ b/primitives/session/src/lib.rs @@ -24,7 +24,7 @@ use codec::{Decode, Encode}; #[cfg(feature = "std")] use sp_api::ProvideRuntimeApi; #[cfg(feature = "std")] -use sp_runtime::{generic::BlockId, traits::Block as BlockT}; +use sp_runtime::traits::Block as BlockT; use sp_core::{crypto::KeyTypeId, RuntimeDebug}; use sp_staking::SessionIndex; @@ -125,7 +125,7 @@ where let runtime_api = client.runtime_api(); for seed in seeds { - runtime_api.generate_session_keys(&BlockId::Hash(at), Some(seed.as_bytes().to_vec()))?; + runtime_api.generate_session_keys(at, Some(seed.as_bytes().to_vec()))?; } Ok(()) diff --git a/test-utils/runtime/src/lib.rs b/test-utils/runtime/src/lib.rs index 35906107015c5..b979a961ae9de 100644 --- a/test-utils/runtime/src/lib.rs +++ b/test-utils/runtime/src/lib.rs @@ -1353,7 +1353,6 @@ mod tests { use sp_api::ProvideRuntimeApi; use sp_consensus::BlockOrigin; use sp_core::storage::well_known_keys::HEAP_PAGES; - use sp_runtime::generic::BlockId; use sp_state_machine::ExecutionStrategy; use substrate_test_runtime_client::{ prelude::*, runtime::TestAPI, DefaultTestClientBuilderExt, TestClientBuilder, @@ -1368,27 +1367,27 @@ mod tests { .set_execution_strategy(ExecutionStrategy::AlwaysWasm) .set_heap_pages(8) .build(); - let block_id = BlockId::Hash(client.chain_info().best_hash); + let best_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. - let ret = client.runtime_api().vec_with_capacity(&block_id, 1048576); + let ret = client.runtime_api().vec_with_capacity(best_hash, 1048576); assert!(ret.is_err()); // Create a block that sets the `:heap_pages` to 32 pages of memory which corresponds to // ~2048k of heap memory. - let (new_block_id, block) = { + let (new_at_hash, block) = { let mut builder = client.new_block(Default::default()).unwrap(); builder.push_storage_change(HEAP_PAGES.to_vec(), Some(32u64.encode())).unwrap(); let block = builder.build().unwrap().block; let hash = block.header.hash(); - (BlockId::Hash(hash), block) + (hash, block) }; futures::executor::block_on(client.import(BlockOrigin::Own, block)).unwrap(); // Allocation of 1024k while having ~2048k should succeed. - let ret = client.runtime_api().vec_with_capacity(&new_block_id, 1048576); + let ret = client.runtime_api().vec_with_capacity(new_at_hash, 1048576); assert!(ret.is_ok()); } @@ -1397,9 +1396,9 @@ mod tests { let client = TestClientBuilder::new().set_execution_strategy(ExecutionStrategy::Both).build(); let runtime_api = client.runtime_api(); - let block_id = BlockId::Hash(client.chain_info().best_hash); + let best_hash = client.chain_info().best_hash; - runtime_api.test_storage(&block_id).unwrap(); + runtime_api.test_storage(best_hash).unwrap(); } fn witness_backend() -> (sp_trie::MemoryDB, crate::Hash) { @@ -1424,8 +1423,8 @@ mod tests { let client = TestClientBuilder::new().set_execution_strategy(ExecutionStrategy::Both).build(); let runtime_api = client.runtime_api(); - let block_id = BlockId::Hash(client.chain_info().best_hash); + let best_hash = client.chain_info().best_hash; - runtime_api.test_witness(&block_id, proof, root).unwrap(); + runtime_api.test_witness(best_hash, proof, root).unwrap(); } } diff --git a/utils/frame/benchmarking-cli/src/block/bench.rs b/utils/frame/benchmarking-cli/src/block/bench.rs index c69d95725eb14..2ceac787ffb53 100644 --- a/utils/frame/benchmarking-cli/src/block/bench.rs +++ b/utils/frame/benchmarking-cli/src/block/bench.rs @@ -92,13 +92,12 @@ where 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 hash = self.client.expect_block_hash_from_id(&block_num)?; + let consumed = self.consumed_weight(hash)?; let block = self.client.block(hash)?.ok_or(format!("Block {} not found", block_num))?; let block = self.unsealed(block.block); - let took = self.measure_block(&block, &parent_num)?; + let took = self.measure_block(&block, *block.header().parent_hash())?; self.log_weight(i, block.extrinsics().len(), consumed, took); } @@ -107,7 +106,7 @@ where } /// Return the average *execution* aka. *import* time of the block. - fn measure_block(&self, block: &Block, parent_num: &BlockId) -> Result { + fn measure_block(&self, block: &Block, parent_hash: Block::Hash) -> Result { let mut record = Vec::::default(); // Interesting part here: // Execute the block multiple times and collect stats about its execution time. @@ -117,7 +116,7 @@ where let start = Instant::now(); runtime_api - .execute_block(&parent_num, block) + .execute_block(parent_hash, block) .map_err(|e| Error::Client(RuntimeApiError(e)))?; record.push(start.elapsed().as_nanos() as NanoSeconds); @@ -131,7 +130,7 @@ where /// /// This is the post-dispatch corrected weight and is only available /// after executing the block. - fn consumed_weight(&self, block: &BlockId) -> Result { + fn consumed_weight(&self, block_hash: Block::Hash) -> 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 = array_bytes::hex2bytes( @@ -139,11 +138,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_hash, &key)? - .ok_or(format!("Could not find System::BlockWeight for block: {}", block))? + .ok_or(format!("Could not find System::BlockWeight for block: {}", block_hash))? .0[..]; let weight = ConsumedWeight::decode_all(&mut raw_weight)?; diff --git a/utils/frame/benchmarking-cli/src/extrinsic/bench.rs b/utils/frame/benchmarking-cli/src/extrinsic/bench.rs index 2a86c10e7ad27..948f648377d55 100644 --- a/utils/frame/benchmarking-cli/src/extrinsic/bench.rs +++ b/utils/frame/benchmarking-cli/src/extrinsic/bench.rs @@ -20,13 +20,13 @@ 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_api::{ApiExt, Core, ProvideRuntimeApi}; use sp_blockchain::{ ApplyExtrinsicFailed::Validity, Error::{ApplyExtrinsicFailed, RuntimeApiError}, }; use sp_runtime::{ - traits::{Block as BlockT, Zero}, + traits::Block as BlockT, transaction_validity::{InvalidTransaction, TransactionValidityError}, Digest, DigestItem, OpaqueExtrinsic, }; @@ -73,7 +73,9 @@ impl Benchmark where Block: BlockT, BA: ClientBackend, - C: BlockBuilderProvider + ProvideRuntimeApi, + C: BlockBuilderProvider + + ProvideRuntimeApi + + sp_blockchain::HeaderBackend, C::Api: ApiExt + BlockBuilderApi, { /// Create a new [`Self`] from the arguments. @@ -167,13 +169,13 @@ where /// Measures the time that it take to execute a block or an extrinsic. fn measure_block(&self, block: &Block) -> Result { let mut record = BenchRecord::new(); - let genesis = BlockId::Number(Zero::zero()); + let genesis = self.client.info().genesis_hash; info!("Running {} warmups...", self.params.warmup); for _ in 0..self.params.warmup { self.client .runtime_api() - .execute_block(&genesis, block.clone()) + .execute_block(genesis, block.clone()) .map_err(|e| Error::Client(RuntimeApiError(e)))?; } @@ -186,7 +188,7 @@ where let start = Instant::now(); runtime_api - .execute_block(&genesis, block) + .execute_block(genesis, block) .map_err(|e| Error::Client(RuntimeApiError(e)))?; let elapsed = start.elapsed().as_nanos(); diff --git a/utils/frame/benchmarking-cli/src/extrinsic/cmd.rs b/utils/frame/benchmarking-cli/src/extrinsic/cmd.rs index b95cd6b5c2e42..dc8aa8b7c4200 100644 --- a/utils/frame/benchmarking-cli/src/extrinsic/cmd.rs +++ b/utils/frame/benchmarking-cli/src/extrinsic/cmd.rs @@ -94,7 +94,9 @@ impl ExtrinsicCmd { where Block: BlockT, BA: ClientBackend, - C: BlockBuilderProvider + ProvideRuntimeApi, + C: BlockBuilderProvider + + ProvideRuntimeApi + + sp_blockchain::HeaderBackend, C::Api: ApiExt + BlockBuilderApi, { // Short circuit if --list was specified. diff --git a/utils/frame/benchmarking-cli/src/overhead/cmd.rs b/utils/frame/benchmarking-cli/src/overhead/cmd.rs index 74c1e7efc24d4..bca63f7cae938 100644 --- a/utils/frame/benchmarking-cli/src/overhead/cmd.rs +++ b/utils/frame/benchmarking-cli/src/overhead/cmd.rs @@ -108,7 +108,9 @@ impl OverheadCmd { where Block: BlockT, BA: ClientBackend, - C: BlockBuilderProvider + ProvideRuntimeApi, + C: BlockBuilderProvider + + ProvideRuntimeApi + + sp_blockchain::HeaderBackend, C::Api: ApiExt + BlockBuilderApi, { if ext_builder.pallet() != "system" || ext_builder.extrinsic() != "remark" { diff --git a/utils/frame/rpc/system/src/lib.rs b/utils/frame/rpc/system/src/lib.rs index 72ad99e435f72..965a7b44d3ff4 100644 --- a/utils/frame/rpc/system/src/lib.rs +++ b/utils/frame/rpc/system/src/lib.rs @@ -32,7 +32,7 @@ use sp_api::ApiExt; use sp_block_builder::BlockBuilder; use sp_blockchain::HeaderBackend; use sp_core::{hexdisplay::HexDisplay, Bytes}; -use sp_runtime::{generic::BlockId, legacy, traits}; +use sp_runtime::{legacy, traits}; pub use frame_system_rpc_runtime_api::AccountNonceApi; @@ -101,9 +101,8 @@ where 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| { + let nonce = api.account_nonce(best, account.clone()).map_err(|e| { CallError::Custom(ErrorObject::owned( Error::RuntimeError.into(), "Unable to query nonce.", @@ -120,9 +119,9 @@ where ) -> RpcResult { self.deny_unsafe.check_if_safe()?; let api = self.client.runtime_api(); - let at = BlockId::::hash(at.unwrap_or_else(|| + let best_hash = at.unwrap_or_else(|| // If the block hash is not supplied assume the best block. - self.client.info().best_hash)); + self.client.info().best_hash); let uxt: ::Extrinsic = Decode::decode(&mut &*extrinsic).map_err(|e| { @@ -134,7 +133,7 @@ where })?; let api_version = api - .api_version::>(&at) + .api_version::>(best_hash) .map_err(|e| { CallError::Custom(ErrorObject::owned( Error::RuntimeError.into(), @@ -146,13 +145,13 @@ where CallError::Custom(ErrorObject::owned( Error::RuntimeError.into(), "Unable to dry run extrinsic.", - Some(format!("Could not find `BlockBuilder` api for block `{:?}`.", at)), + Some(format!("Could not find `BlockBuilder` api for block `{:?}`.", best_hash)), )) })?; let result = if api_version < 6 { #[allow(deprecated)] - api.apply_extrinsic_before_version_6(&at, uxt) + api.apply_extrinsic_before_version_6(best_hash, uxt) .map(legacy::byte_sized_error::convert_to_latest) .map_err(|e| { CallError::Custom(ErrorObject::owned( @@ -162,7 +161,7 @@ where )) })? } else { - api.apply_extrinsic(&at, uxt).map_err(|e| { + api.apply_extrinsic(best_hash, uxt).map_err(|e| { CallError::Custom(ErrorObject::owned( Error::RuntimeError.into(), "Unable to dry run extrinsic.", @@ -220,6 +219,7 @@ mod tests { use jsonrpsee::{core::Error as JsonRpseeError, types::error::CallError}; use sc_transaction_pool::BasicPool; use sp_runtime::{ + generic::BlockId, transaction_validity::{InvalidTransaction, TransactionValidityError}, ApplyExtrinsicResult, }; From 49fa611204650467ebce59c912999e1b28953978 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Tue, 21 Feb 2023 12:50:41 +0200 Subject: [PATCH 417/715] frame/beefy: prune entries in set id session mapping (#13411) Add limit for the number of entries in the `SetIdSession` mapping. For example, it can be set to the bonding duration (in sessions). Signed-off-by: acatangiu --- frame/beefy-mmr/src/mock.rs | 1 + frame/beefy/src/lib.rs | 24 +++++++++++++++++++++++- frame/beefy/src/mock.rs | 2 ++ frame/beefy/src/tests.rs | 33 +++++++++++++++++++++++++++++++++ 4 files changed, 59 insertions(+), 1 deletion(-) diff --git a/frame/beefy-mmr/src/mock.rs b/frame/beefy-mmr/src/mock.rs index de6fa135286b9..8f3bdd619568c 100644 --- a/frame/beefy-mmr/src/mock.rs +++ b/frame/beefy-mmr/src/mock.rs @@ -133,6 +133,7 @@ impl pallet_beefy::Config for Test { )>>::IdentificationTuple; type HandleEquivocation = (); type MaxAuthorities = ConstU32<100>; + type MaxSetIdSessionEntries = ConstU64<100>; type OnNewValidatorSet = BeefyMmr; type WeightInfo = (); } diff --git a/frame/beefy/src/lib.rs b/frame/beefy/src/lib.rs index d29440457f5bf..cccfdbb8131c6 100644 --- a/frame/beefy/src/lib.rs +++ b/frame/beefy/src/lib.rs @@ -99,8 +99,18 @@ pub mod pallet { type HandleEquivocation: HandleEquivocation; /// The maximum number of authorities that can be added. + #[pallet::constant] type MaxAuthorities: Get; + /// The maximum number of entries to keep in the set id to session index mapping. + /// + /// Since the `SetIdSession` map is only used for validating equivocations this + /// value should relate to the bonding duration of whatever staking system is + /// being used (if any). If equivocation handling is not enabled then this value + /// can be zero. + #[pallet::constant] + type MaxSetIdSessionEntries: 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 @@ -136,6 +146,12 @@ pub mod pallet { /// A mapping from BEEFY set ID to the index of the *most recent* session for which its /// members were responsible. /// + /// This is only used for validating equivocation proofs. An equivocation proof must + /// contains a key-ownership proof for a given session, therefore we need a way to tie + /// together sessions and BEEFY set ids, i.e. we need to validate that a validator + /// was the owner of a given key on a given session, and what the active set ID was + /// during that session. + /// /// TWOX-NOTE: `ValidatorSetId` is not under user control. #[pallet::storage] #[pallet::getter(fn session_for_set)] @@ -462,9 +478,15 @@ where // We want to have at least one BEEFY mandatory block per session. Self::change_authorities(bounded_next_authorities, bounded_next_queued_authorities); + let validator_set_id = Self::validator_set_id(); // Update the mapping for the new set id that corresponds to the latest session (i.e. now). let session_index = >::current_index(); - SetIdSession::::insert(Self::validator_set_id(), &session_index); + SetIdSession::::insert(validator_set_id, &session_index); + // Prune old entry if limit reached. + let max_set_id_session_entries = T::MaxSetIdSessionEntries::get().max(1); + if validator_set_id >= max_set_id_session_entries { + SetIdSession::::remove(validator_set_id - max_set_id_session_entries); + } } fn on_disabled(i: u32) { diff --git a/frame/beefy/src/mock.rs b/frame/beefy/src/mock.rs index 8d8b831950d8e..c6cde5332b4fc 100644 --- a/frame/beefy/src/mock.rs +++ b/frame/beefy/src/mock.rs @@ -111,6 +111,7 @@ parameter_types! { pub const Period: u64 = 1; pub const ReportLongevity: u64 = BondingDuration::get() as u64 * SessionsPerEra::get() as u64 * Period::get(); + pub const MaxSetIdSessionEntries: u32 = BondingDuration::get() * SessionsPerEra::get(); } impl pallet_beefy::Config for Test { @@ -125,6 +126,7 @@ impl pallet_beefy::Config for Test { type HandleEquivocation = super::EquivocationHandler; type MaxAuthorities = ConstU32<100>; + type MaxSetIdSessionEntries = MaxSetIdSessionEntries; type OnNewValidatorSet = (); type WeightInfo = (); } diff --git a/frame/beefy/src/tests.rs b/frame/beefy/src/tests.rs index a92f90b6107bc..b2e1b67691d9b 100644 --- a/frame/beefy/src/tests.rs +++ b/frame/beefy/src/tests.rs @@ -162,6 +162,39 @@ fn validator_set_updates_work() { }); } +#[test] +fn cleans_up_old_set_id_session_mappings() { + new_test_ext(vec![1, 2, 3, 4]).execute_with(|| { + let max_set_id_session_entries = MaxSetIdSessionEntries::get(); + + // we have 3 sessions per era + let era_limit = max_set_id_session_entries / 3; + // sanity check against division precision loss + assert_eq!(0, max_set_id_session_entries % 3); + // go through `max_set_id_session_entries` sessions + start_era(era_limit); + + // we should have a session id mapping for all the set ids from + // `max_set_id_session_entries` eras we have observed + for i in 1..=max_set_id_session_entries { + assert!(Beefy::session_for_set(i as u64).is_some()); + } + + // go through another `max_set_id_session_entries` sessions + start_era(era_limit * 2); + + // we should keep tracking the new mappings for new sessions + for i in max_set_id_session_entries + 1..=max_set_id_session_entries * 2 { + assert!(Beefy::session_for_set(i as u64).is_some()); + } + + // but the old ones should have been pruned by now + for i in 1..=max_set_id_session_entries { + assert!(Beefy::session_for_set(i as u64).is_none()); + } + }); +} + /// Returns a list with 3 authorities with known keys: /// Alice, Bob and Charlie. pub fn test_authorities() -> Vec { From 425bf6b440242fa39fd7d64e9987418fba8f29f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 21 Feb 2023 11:17:01 +0000 Subject: [PATCH 418/715] Staking and nomination pools runtime API improvements (#13119) * Adds StakingAPI_nominations_quota and NominationPoolsApi_balanceToPoint and NominationPoolsApi_pointsToBalance runtime APIs * Adds balance param to api_nominations_quota * Update frame/nomination-pools/src/lib.rs Co-authored-by: Anton * Update frame/nomination-pools/src/lib.rs Co-authored-by: Anton * Addresses comments - returns zero instead of error in runtime api * Update frame/staking/runtime-api/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update frame/staking/runtime-api/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Addresses PR comments * Update frame/nomination-pools/runtime-api/Cargo.toml Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Fixes points_to_balance logic; adds tests * test comment fix * Update frame/nomination-pools/runtime-api/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update frame/nomination-pools/runtime-api/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Fix block pruning (#13323) * Referendum proposal's metadata (#12568) * referenda metadata * todo comment * remove TODO, update rustdocs * referenda clear_metadata origin signed or root * referenda metadata unit tests * drop schema type for referenda metadata * remove metadata type * referenda metadata benches * note different preimages * metadata for democracy pallet * metadata democracy pallet tests and benches * fix cargo clippy * update docs * ".git/.scripts/bench-bot.sh" pallet dev pallet_democracy * ".git/.scripts/bench-bot.sh" pallet dev pallet_referenda * Update the doc frame/democracy/src/lib.rs Co-authored-by: Roman Useinov * Update the doc frame/democracy/src/lib.rs Co-authored-by: Anthony Alaribe * reference instead clone for take Co-authored-by: Anthony Alaribe * error rename BadMetadata to PreimageNotExist * clear metadata within internal_cancel_referendum fn * remove redundant clone * collapse metadata api into one set_metadata method * fmt * review fixes * not request preimage on set_metadata * rename events and update docs * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_democracy * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_referenda * rename reset_metadata to transfer_metadata --------- Co-authored-by: command-bot <> Co-authored-by: Roman Useinov Co-authored-by: Anthony Alaribe * Improve test coverage of the `Notifications` protocol (#13033) * Add handler and upgrade tests * Add tests for `behaviour.rs` * Apply review comments * Update dependencies * Apply suggestions from code review Co-authored-by: Dmitry Markin * Apply review comments * Fix clippy * Update mockall * Apply review comment --------- Co-authored-by: Dmitry Markin * refactors runtime API logic to own pallet impl block * removes unrelated changes * Fixes cargo doc comments lint * fixes node cargo * fixes comment * restart ci * restart ci * restart ci --------- Co-authored-by: Anton Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: parity-processbot <> Co-authored-by: Arkadiy Paronyan Co-authored-by: Muharem Ismailov Co-authored-by: Roman Useinov Co-authored-by: Anthony Alaribe Co-authored-by: Aaro Altonen <48052676+altonen@users.noreply.github.com> Co-authored-by: Dmitry Markin --- Cargo.lock | 10 +++ Cargo.toml | 1 + bin/node/runtime/Cargo.toml | 2 + bin/node/runtime/src/lib.rs | 18 +++- frame/nomination-pools/runtime-api/Cargo.toml | 2 + frame/nomination-pools/runtime-api/src/lib.rs | 13 ++- frame/nomination-pools/src/lib.rs | 62 +++++++++---- frame/nomination-pools/src/tests.rs | 86 ++++++++++++++----- frame/staking/runtime-api/Cargo.toml | 24 ++++++ frame/staking/runtime-api/README.md | 3 + frame/staking/runtime-api/src/lib.rs | 32 +++++++ frame/staking/src/pallet/impls.rs | 14 +++ 12 files changed, 222 insertions(+), 45 deletions(-) create mode 100644 frame/staking/runtime-api/Cargo.toml create mode 100644 frame/staking/runtime-api/README.md create mode 100644 frame/staking/runtime-api/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index d7f48c17f8726..bed09f135de32 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3568,6 +3568,7 @@ dependencies = [ "pallet-society", "pallet-staking", "pallet-staking-reward-curve", + "pallet-staking-runtime-api", "pallet-state-trie-migration", "pallet-sudo", "pallet-timestamp", @@ -6129,6 +6130,7 @@ dependencies = [ name = "pallet-nomination-pools-runtime-api" version = "1.0.0-dev" dependencies = [ + "pallet-nomination-pools", "parity-scale-codec", "sp-api", "sp-std", @@ -6486,6 +6488,14 @@ dependencies = [ "sp-arithmetic", ] +[[package]] +name = "pallet-staking-runtime-api" +version = "4.0.0-dev" +dependencies = [ + "parity-scale-codec", + "sp-api", +] + [[package]] name = "pallet-state-trie-migration" version = "4.0.0-dev" diff --git a/Cargo.toml b/Cargo.toml index aaa1c2a211183..a86ec3146832b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -141,6 +141,7 @@ members = [ "frame/staking", "frame/staking/reward-curve", "frame/staking/reward-fn", + "frame/staking/runtime-api", "frame/state-trie-migration", "frame/sudo", "frame/root-offences", diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index 1d2e6f057d517..e27e4f7f8a545 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -97,6 +97,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-staking-runtime-api = { version = "4.0.0-dev", default-features = false, path = "../../../frame/staking/runtime-api" } 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" } @@ -175,6 +176,7 @@ std = [ "sp-runtime/std", "sp-staking/std", "pallet-staking/std", + "pallet-staking-runtime-api/std", "pallet-state-trie-migration/std", "sp-session/std", "pallet-sudo/std", diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 2c7969ebcd6b9..0b887ff7d7a9f 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1986,8 +1986,22 @@ impl_runtime_apis! { } impl pallet_nomination_pools_runtime_api::NominationPoolsApi for Runtime { - fn pending_rewards(member_account: AccountId) -> Balance { - NominationPools::pending_rewards(member_account).unwrap_or_default() + fn pending_rewards(who: AccountId) -> Balance { + NominationPools::api_pending_rewards(who).unwrap_or_default() + } + + fn points_to_balance(pool_id: pallet_nomination_pools::PoolId, points: Balance) -> Balance { + NominationPools::api_points_to_balance(pool_id, points) + } + + fn balance_to_points(pool_id: pallet_nomination_pools::PoolId, new_funds: Balance) -> Balance { + NominationPools::api_balance_to_points(pool_id, new_funds) + } + } + + impl pallet_staking_runtime_api::StakingApi for Runtime { + fn nominations_quota(balance: Balance) -> u32 { + Staking::api_nominations_quota(balance) } } diff --git a/frame/nomination-pools/runtime-api/Cargo.toml b/frame/nomination-pools/runtime-api/Cargo.toml index d1e4fbb30df52..5e290232a115e 100644 --- a/frame/nomination-pools/runtime-api/Cargo.toml +++ b/frame/nomination-pools/runtime-api/Cargo.toml @@ -16,6 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/api" } sp-std = { version = "5.0.0", default-features = false, path = "../../../primitives/std" } +pallet-nomination-pools = { version = "1.0.0", default-features = false, path = "../" } [features] default = ["std"] @@ -23,4 +24,5 @@ std = [ "codec/std", "sp-api/std", "sp-std/std", + "pallet-nomination-pools/std", ] diff --git a/frame/nomination-pools/runtime-api/src/lib.rs b/frame/nomination-pools/runtime-api/src/lib.rs index aa3ca57ca5b8b..94573bfdb2e33 100644 --- a/frame/nomination-pools/runtime-api/src/lib.rs +++ b/frame/nomination-pools/runtime-api/src/lib.rs @@ -21,13 +21,22 @@ #![cfg_attr(not(feature = "std"), no_std)] use codec::Codec; +use pallet_nomination_pools::PoolId; sp_api::decl_runtime_apis! { /// Runtime api for accessing information about nomination pools. pub trait NominationPoolsApi - where AccountId: Codec, Balance: Codec + where + AccountId: Codec, + Balance: Codec, { /// Returns the pending rewards for the member that the AccountId was given for. - fn pending_rewards(member: AccountId) -> Balance; + fn pending_rewards(who: AccountId) -> Balance; + + /// Returns the equivalent balance of `points` for a given pool. + fn points_to_balance(pool_id: PoolId, points: Balance) -> Balance; + + /// Returns the equivalent points of `new_funds` for a given pool. + fn balance_to_points(pool_id: PoolId, new_funds: Balance) -> Balance; } } diff --git a/frame/nomination-pools/src/lib.rs b/frame/nomination-pools/src/lib.rs index 3cb8abedda2fb..9c52cf71c6b30 100644 --- a/frame/nomination-pools/src/lib.rs +++ b/frame/nomination-pools/src/lib.rs @@ -2142,24 +2142,6 @@ pub mod pallet { } impl Pallet { - /// Returns the pending rewards for the specified `member_account`. - /// - /// 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, 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() - } - } - - None - } - /// 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 @@ -2579,6 +2561,50 @@ impl Pallet { } } +impl Pallet { + /// Returns the pending rewards for the specified `who` account. + /// + /// In the case of error, `None` is returned. Used by runtime API. + pub fn api_pending_rewards(who: T::AccountId) -> Option> { + if let Some(pool_member) = PoolMembers::::get(who) { + 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() + } + } + + None + } + + /// Returns the points to balance conversion for a specified pool. + /// + /// If the pool ID does not exist, it returns 0 ratio points to balance. Used by runtime API. + pub fn api_points_to_balance(pool_id: PoolId, points: BalanceOf) -> BalanceOf { + if let Some(pool) = BondedPool::::get(pool_id) { + pool.points_to_balance(points) + } else { + Zero::zero() + } + } + + /// Returns the equivalent `new_funds` balance to point conversion for a specified pool. + /// + /// If the pool ID does not exist, returns 0 ratio balance to points. Used by runtime API. + pub fn api_balance_to_points(pool_id: PoolId, new_funds: BalanceOf) -> BalanceOf { + if let Some(pool) = BondedPool::::get(pool_id) { + let bonded_balance = + T::Staking::active_stake(&pool.bonded_account()).unwrap_or(Zero::zero()); + Pallet::::balance_to_point(bonded_balance, pool.points, new_funds) + } else { + Zero::zero() + } + } +} + impl OnStakerSlash> for Pallet { fn on_slash( pool_account: &T::AccountId, diff --git a/frame/nomination-pools/src/tests.rs b/frame/nomination-pools/src/tests.rs index 7d5d418bbf2c8..be52996a587f7 100644 --- a/frame/nomination-pools/src/tests.rs +++ b/frame/nomination-pools/src/tests.rs @@ -195,6 +195,46 @@ mod bonded_pool { }) } + #[test] + fn api_points_to_balance_works() { + ExtBuilder::default().build_and_execute(|| { + assert!(BondedPool::::get(1).is_some()); + assert_eq!(Pallet::::api_points_to_balance(1, 10), 10); + + // slash half of the pool's balance. expected result of `fn api_points_to_balance` + // to be 1/2 of the pool's balance. + StakingMock::set_bonded_balance( + default_bonded_account(), + Pools::depositor_min_bond() / 2, + ); + assert_eq!(Pallet::::api_points_to_balance(1, 10), 5); + + // if pool does not exist, points to balance ratio is 0. + assert_eq!(BondedPool::::get(2), None); + assert_eq!(Pallet::::api_points_to_balance(2, 10), 0); + }) + } + + #[test] + fn api_balance_to_points_works() { + ExtBuilder::default().build_and_execute(|| { + assert_eq!(Pallet::::api_balance_to_points(1, 0), 0); + assert_eq!(Pallet::::api_balance_to_points(1, 10), 10); + + // slash half of the pool's balance. expect result of `fn api_balance_to_points` + // to be 2 * of the balance to add to the pool. + StakingMock::set_bonded_balance( + default_bonded_account(), + Pools::depositor_min_bond() / 2, + ); + assert_eq!(Pallet::::api_balance_to_points(1, 10), 20); + + // if pool does not exist, balance to points ratio is 0. + assert_eq!(BondedPool::::get(2), None); + assert_eq!(Pallet::::api_points_to_balance(2, 10), 0); + }) + } + #[test] fn ok_to_join_with_works() { ExtBuilder::default().build_and_execute(|| { @@ -1305,51 +1345,51 @@ mod claim_payout { ExtBuilder::default().build_and_execute(|| { let ed = Balances::minimum_balance(); - assert_eq!(Pools::pending_rewards(10), Some(0)); + assert_eq!(Pools::api_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); + assert_eq!(Pools::api_pending_rewards(10), Some(30)); + assert_eq!(Pools::api_pending_rewards(20), None); Balances::make_free_balance_be(&20, ed + 10); 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)); + assert_eq!(Pools::api_pending_rewards(10), Some(30)); + assert_eq!(Pools::api_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); + assert_eq!(Pools::api_pending_rewards(10), Some(30 + 50)); + assert_eq!(Pools::api_pending_rewards(20), Some(50)); + assert_eq!(Pools::api_pending_rewards(30), None); Balances::make_free_balance_be(&30, ed + 10); 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)); - assert_eq!(Pools::pending_rewards(30), Some(0)); + assert_eq!(Pools::api_pending_rewards(10), Some(30 + 50)); + assert_eq!(Pools::api_pending_rewards(20), Some(50)); + assert_eq!(Pools::api_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)); + assert_eq!(Pools::api_pending_rewards(10), Some(30 + 50 + 20)); + assert_eq!(Pools::api_pending_rewards(20), Some(50 + 20)); + assert_eq!(Pools::api_pending_rewards(30), Some(20)); // 10 should claim 10, 20 should claim nothing. 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_eq!(Pools::api_pending_rewards(10), Some(0)); + assert_eq!(Pools::api_pending_rewards(20), Some(50 + 20)); + assert_eq!(Pools::api_pending_rewards(30), Some(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_eq!(Pools::api_pending_rewards(10), Some(0)); + assert_eq!(Pools::api_pending_rewards(20), Some(0)); + assert_eq!(Pools::api_pending_rewards(30), Some(20)); 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)); + assert_eq!(Pools::api_pending_rewards(10), Some(0)); + assert_eq!(Pools::api_pending_rewards(20), Some(0)); + assert_eq!(Pools::api_pending_rewards(30), Some(0)); }); } diff --git a/frame/staking/runtime-api/Cargo.toml b/frame/staking/runtime-api/Cargo.toml new file mode 100644 index 0000000000000..9923b881c38d8 --- /dev/null +++ b/frame/staking/runtime-api/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "pallet-staking-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 = "RPC runtime API for transaction payment 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" } + +[features] +default = ["std"] +std = [ + "codec/std", + "sp-api/std", +] diff --git a/frame/staking/runtime-api/README.md b/frame/staking/runtime-api/README.md new file mode 100644 index 0000000000000..a999e519f8cbf --- /dev/null +++ b/frame/staking/runtime-api/README.md @@ -0,0 +1,3 @@ +Runtime API definition for the staking pallet. + +License: Apache-2.0 diff --git a/frame/staking/runtime-api/src/lib.rs b/frame/staking/runtime-api/src/lib.rs new file mode 100644 index 0000000000000..378599c665506 --- /dev/null +++ b/frame/staking/runtime-api/src/lib.rs @@ -0,0 +1,32 @@ +// This file is part of Substrate. + +// Copyright (C) 2023 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Runtime API definition for the staking pallet. + +#![cfg_attr(not(feature = "std"), no_std)] + +use codec::Codec; + +sp_api::decl_runtime_apis! { + pub trait StakingApi + where + Balance: Codec, + { + /// Returns the nominations quota for a nominator with a given balance. + fn nominations_quota(balance: Balance) -> u32; + } +} diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 6a35e2b861565..fc0bf082c7caf 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -972,6 +972,20 @@ impl Pallet { } } +impl Pallet { + /// Returns the current nominations quota for nominators. + /// + /// Used by the runtime API. + /// Note: for now, this api runtime will always return value of `T::MaxNominations` and thus it + /// is redundant. However, with the upcoming changes in + /// , the nominations quota will change + /// depending on the nominators balance. We're introducing this runtime API now to prepare the + /// community to use it before rolling out PR#12970. + pub fn api_nominations_quota(_balance: BalanceOf) -> u32 { + T::MaxNominations::get() + } +} + impl ElectionDataProvider for Pallet { type AccountId = T::AccountId; type BlockNumber = BlockNumberFor; From 088a7fc5e66cc08b1a5ac2fbe53e19baf7349489 Mon Sep 17 00:00:00 2001 From: Ross Bulat Date: Tue, 21 Feb 2023 19:39:52 +0800 Subject: [PATCH 419/715] Nomination Pools: Rename state-toggler to bouncer (#13421) * rename state-toggler to bouncer * add migration * fmt * bump storage version * rm migration * revert version * ".git/.scripts/commands/fmt/fmt.sh" --------- Co-authored-by: command-bot <> --- .../nomination-pools/benchmarking/src/lib.rs | 6 +- frame/nomination-pools/fuzzer/src/call.rs | 4 +- frame/nomination-pools/src/lib.rs | 63 ++++++++-------- frame/nomination-pools/src/migration.rs | 4 +- frame/nomination-pools/src/tests.rs | 73 ++++++------------- 5 files changed, 60 insertions(+), 90 deletions(-) diff --git a/frame/nomination-pools/benchmarking/src/lib.rs b/frame/nomination-pools/benchmarking/src/lib.rs index 32708ff53e01c..675a4a8324f43 100644 --- a/frame/nomination-pools/benchmarking/src/lib.rs +++ b/frame/nomination-pools/benchmarking/src/lib.rs @@ -518,7 +518,7 @@ frame_benchmarking::benchmarks! { depositor: depositor.clone(), root: Some(depositor.clone()), nominator: Some(depositor.clone()), - state_toggler: Some(depositor.clone()), + bouncer: Some(depositor.clone()), }, } ); @@ -557,7 +557,7 @@ frame_benchmarking::benchmarks! { depositor: depositor.clone(), root: Some(depositor.clone()), nominator: Some(depositor.clone()), - state_toggler: Some(depositor.clone()), + bouncer: Some(depositor.clone()), } } ); @@ -630,7 +630,7 @@ frame_benchmarking::benchmarks! { pallet_nomination_pools::PoolRoles { depositor: root, nominator: Some(random.clone()), - state_toggler: Some(random.clone()), + bouncer: Some(random.clone()), root: Some(random), }, ) diff --git a/frame/nomination-pools/fuzzer/src/call.rs b/frame/nomination-pools/fuzzer/src/call.rs index b07903609e8ab..805cc265d96e0 100644 --- a/frame/nomination-pools/fuzzer/src/call.rs +++ b/frame/nomination-pools/fuzzer/src/call.rs @@ -143,9 +143,9 @@ fn random_call(mut rng: &mut R) -> (pools::Call, RuntimeOrigin) { let amount = random_ed_multiple(&mut rng); fund_account(&mut rng, &who); let root = who; - let state_toggler = who; + let bouncer = who; let nominator = who; - (PoolsCall::::create { amount, root, state_toggler, nominator }, origin) + (PoolsCall::::create { amount, root, bouncer, nominator }, origin) }, 7 => { // nominate diff --git a/frame/nomination-pools/src/lib.rs b/frame/nomination-pools/src/lib.rs index 9c52cf71c6b30..4a80168469570 100644 --- a/frame/nomination-pools/src/lib.rs +++ b/frame/nomination-pools/src/lib.rs @@ -120,9 +120,9 @@ //! * Depositor: creates the pool and is the initial member. They can only leave the pool once all //! 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. +//! * Bouncer: can change the pools state and kick members if the pool is blocked. +//! * Root: can change the nominator, bouncer, or itself and can perform any of the actions the +//! nominator or bouncer can. //! //! ### Dismantling //! @@ -573,13 +573,13 @@ 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. + /// Can change the nominator, bouncer, or itself and can perform any of the actions the + /// nominator or bouncer can. pub root: Option, /// Can select which validators the pool nominates. pub nominator: Option, /// Can change the pools state and kick members if the pool is blocked. - pub state_toggler: Option, + pub bouncer: Option, } /// Pool permissions and state @@ -734,11 +734,8 @@ impl BondedPool { 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 is_bouncer(&self, who: &T::AccountId) -> bool { + self.roles.bouncer.as_ref().map_or(false, |bouncer| bouncer == who) } fn can_update_roles(&self, who: &T::AccountId) -> bool { @@ -751,15 +748,15 @@ impl BondedPool { } fn can_kick(&self, who: &T::AccountId) -> bool { - self.state == PoolState::Blocked && (self.is_root(who) || self.is_state_toggler(who)) + self.state == PoolState::Blocked && (self.is_root(who) || self.is_bouncer(who)) } fn can_toggle_state(&self, who: &T::AccountId) -> bool { - (self.is_root(who) || self.is_state_toggler(who)) && !self.is_destroying() + (self.is_root(who) || self.is_bouncer(who)) && !self.is_destroying() } fn can_set_metadata(&self, who: &T::AccountId) -> bool { - self.is_root(who) || self.is_state_toggler(who) + self.is_root(who) || self.is_bouncer(who) } fn is_destroying(&self) -> bool { @@ -1407,7 +1404,7 @@ pub mod pallet { /// can never change. RolesUpdated { root: Option, - state_toggler: Option, + bouncer: Option, nominator: Option, }, /// The active balance of pool `pool_id` has been slashed to `balance`. @@ -1630,8 +1627,8 @@ pub mod pallet { /// /// # 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 blocked and the caller is either the root or bouncer. 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. @@ -1754,7 +1751,7 @@ pub mod pallet { /// /// * 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. + /// * The pool is blocked and the caller is either the root or bouncer. /// /// # Conditions for permissioned dispatch /// @@ -1879,7 +1876,7 @@ pub mod pallet { /// 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`]. + /// * `bouncer` - The account to set as the [`PoolRoles::bouncer`]. /// /// # Note /// @@ -1892,7 +1889,7 @@ pub mod pallet { #[pallet::compact] amount: BalanceOf, root: AccountIdLookupOf, nominator: AccountIdLookupOf, - state_toggler: AccountIdLookupOf, + bouncer: AccountIdLookupOf, ) -> DispatchResult { let depositor = ensure_signed(origin)?; @@ -1901,7 +1898,7 @@ pub mod pallet { Ok(*id) })?; - Self::do_create(depositor, amount, root, nominator, state_toggler, pool_id) + Self::do_create(depositor, amount, root, nominator, bouncer, pool_id) } /// Create a new delegation pool with a previously used pool id @@ -1917,7 +1914,7 @@ pub mod pallet { #[pallet::compact] amount: BalanceOf, root: AccountIdLookupOf, nominator: AccountIdLookupOf, - state_toggler: AccountIdLookupOf, + bouncer: AccountIdLookupOf, pool_id: PoolId, ) -> DispatchResult { let depositor = ensure_signed(origin)?; @@ -1925,7 +1922,7 @@ pub mod pallet { ensure!(!BondedPools::::contains_key(pool_id), Error::::PoolIdInUse); ensure!(pool_id < LastPoolId::::get(), Error::::InvalidPoolId); - Self::do_create(depositor, amount, root, nominator, state_toggler, pool_id) + Self::do_create(depositor, amount, root, nominator, bouncer, pool_id) } /// Nominate on behalf of the pool. @@ -1955,7 +1952,7 @@ pub mod pallet { /// /// The dispatch origin of this call must be either: /// - /// 1. signed by the state toggler, or the root role of the pool, + /// 1. signed by the bouncer, 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)] @@ -1985,7 +1982,7 @@ pub mod pallet { /// Set a new metadata for the pool. /// - /// The dispatch origin of this call must be signed by the state toggler, or the root role + /// The dispatch origin of this call must be signed by the bouncer, or the root role /// of the pool. #[pallet::call_index(10)] #[pallet::weight(T::WeightInfo::set_metadata(metadata.len() as u32))] @@ -2063,7 +2060,7 @@ pub mod pallet { pool_id: PoolId, new_root: ConfigOp, new_nominator: ConfigOp, - new_state_toggler: ConfigOp, + new_bouncer: ConfigOp, ) -> DispatchResult { let mut bonded_pool = match ensure_root(origin.clone()) { Ok(()) => BondedPool::::get(pool_id).ok_or(Error::::PoolNotFound)?, @@ -2086,16 +2083,16 @@ pub mod pallet { ConfigOp::Remove => bonded_pool.roles.nominator = None, ConfigOp::Set(v) => bonded_pool.roles.nominator = Some(v), }; - match new_state_toggler { + match new_bouncer { ConfigOp::Noop => (), - ConfigOp::Remove => bonded_pool.roles.state_toggler = None, - ConfigOp::Set(v) => bonded_pool.roles.state_toggler = Some(v), + ConfigOp::Remove => bonded_pool.roles.bouncer = None, + ConfigOp::Set(v) => bonded_pool.roles.bouncer = Some(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(), + bouncer: bonded_pool.roles.bouncer.clone(), }); bonded_pool.put(); @@ -2336,12 +2333,12 @@ impl Pallet { amount: BalanceOf, root: AccountIdLookupOf, nominator: AccountIdLookupOf, - state_toggler: AccountIdLookupOf, + bouncer: 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)?; + let bouncer = T::Lookup::lookup(bouncer)?; ensure!(amount >= Pallet::::depositor_min_bond(), Error::::MinimumBondNotMet); ensure!( @@ -2354,7 +2351,7 @@ impl Pallet { PoolRoles { root: Some(root), nominator: Some(nominator), - state_toggler: Some(state_toggler), + bouncer: Some(bouncer), depositor: who.clone(), }, ); diff --git a/frame/nomination-pools/src/migration.rs b/frame/nomination-pools/src/migration.rs index 4a9b6ca0fe117..53087e763b99c 100644 --- a/frame/nomination-pools/src/migration.rs +++ b/frame/nomination-pools/src/migration.rs @@ -28,7 +28,7 @@ pub mod v1 { pub depositor: AccountId, pub root: AccountId, pub nominator: AccountId, - pub state_toggler: AccountId, + pub bouncer: AccountId, } impl OldPoolRoles { @@ -37,7 +37,7 @@ pub mod v1 { depositor: self.depositor, root: Some(self.root), nominator: Some(self.nominator), - state_toggler: Some(self.state_toggler), + bouncer: Some(self.bouncer), } } } diff --git a/frame/nomination-pools/src/tests.rs b/frame/nomination-pools/src/tests.rs index be52996a587f7..46330051b7f4c 100644 --- a/frame/nomination-pools/src/tests.rs +++ b/frame/nomination-pools/src/tests.rs @@ -37,7 +37,7 @@ macro_rules! member_unbonding_eras { } pub const DEFAULT_ROLES: PoolRoles = - PoolRoles { depositor: 10, root: Some(900), nominator: Some(901), state_toggler: Some(902) }; + PoolRoles { depositor: 10, root: Some(900), nominator: Some(901), bouncer: Some(902) }; #[test] fn test_setup_works() { @@ -2148,7 +2148,7 @@ mod unbond { .add_members(vec![(20, 20)]) .build_and_execute(|| { unsafe_set_state(1, PoolState::Blocked); - let kicker = DEFAULT_ROLES.state_toggler.unwrap(); + let kicker = DEFAULT_ROLES.bouncer.unwrap(); // cannot be kicked to above the limit. assert_noop!( @@ -2251,7 +2251,7 @@ mod unbond { // set the stage unsafe_set_state(1, PoolState::Blocked); - let kicker = DEFAULT_ROLES.state_toggler.unwrap(); + let kicker = DEFAULT_ROLES.bouncer.unwrap(); // cannot be kicked to above limit. assert_noop!( @@ -2590,7 +2590,7 @@ mod unbond { #[test] fn unbond_kick_works() { - // Kick: the pool is blocked and the caller is either the root or state-toggler. + // Kick: the pool is blocked and the caller is either the root or bouncer. ExtBuilder::default() .add_members(vec![(100, 100), (200, 200)]) .build_and_execute(|| { @@ -2599,7 +2599,7 @@ mod unbond { let bonded_pool = BondedPool::::get(1).unwrap(); 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); + assert_eq!(bonded_pool.roles.bouncer.unwrap(), 902); // When the nominator tries to kick, then its a noop assert_noop!( @@ -2627,7 +2627,7 @@ mod unbond { ] ); - // When the state toggler kicks then its ok + // When the bouncer kicks then its ok assert_ok!(Pools::fully_unbond(RuntimeOrigin::signed(902), 200)); assert_eq!( @@ -3558,7 +3558,7 @@ mod withdraw_unbonded { // Can kick as root assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(900), 100, 0)); - // Can kick as state toggler + // Can kick as bouncer assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(900), 200, 0)); assert_eq!(Balances::free_balance(100), 100 + 100); @@ -4148,7 +4148,7 @@ mod create { depositor: 11, root: Some(123), nominator: Some(456), - state_toggler: Some(789) + bouncer: Some(789) } } } @@ -4232,7 +4232,7 @@ mod create { amount: 20, root: 11, nominator: 11, - state_toggler: 11, + bouncer: 11, }); assert_noop!( create.dispatch(RuntimeOrigin::signed(11)), @@ -4292,7 +4292,7 @@ mod nominate { Error::::NotNominator ); - // State toggler can't nominate + // bouncer can't nominate assert_noop!( Pools::nominate(RuntimeOrigin::signed(902), 1, vec![21]), Error::::NotNominator @@ -4324,7 +4324,7 @@ mod set_state { // Given 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. + // Only the root and bouncer can change the state when the pool is ok to be open. assert_noop!( Pools::set_state(RuntimeOrigin::signed(10), 1, PoolState::Blocked), Error::::CanNotChangeState @@ -4348,7 +4348,7 @@ mod set_state { assert_eq!(BondedPool::::get(1).unwrap().state, PoolState::Blocked); - // State toggler can change state + // bouncer can change state assert_ok!(Pools::set_state(RuntimeOrigin::signed(902), 1, PoolState::Destroying)); assert_eq!(BondedPool::::get(1).unwrap().state, PoolState::Destroying); @@ -4412,7 +4412,7 @@ mod set_metadata { 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 + // bouncer can set metadata assert_ok!(Pools::set_metadata(RuntimeOrigin::signed(902), 1, vec![2, 2])); assert_eq!(Metadata::::get(1), vec![2, 2]); @@ -4637,7 +4637,7 @@ mod update_roles { depositor: 10, root: Some(900), nominator: Some(901), - state_toggler: Some(902) + bouncer: Some(902) }, ); @@ -4676,7 +4676,7 @@ mod update_roles { ), Error::::DoesNotHavePermission, ); - // state-toggler + // bouncer assert_noop!( Pools::update_roles( RuntimeOrigin::signed(902), @@ -4702,21 +4702,12 @@ mod update_roles { vec![ Event::Created { depositor: 10, pool_id: 1 }, Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, - Event::RolesUpdated { - root: Some(5), - state_toggler: Some(7), - nominator: Some(6) - } + Event::RolesUpdated { root: Some(5), bouncer: Some(7), nominator: Some(6) } ] ); assert_eq!( BondedPools::::get(1).unwrap().roles, - PoolRoles { - depositor: 10, - root: Some(5), - nominator: Some(6), - state_toggler: Some(7) - }, + PoolRoles { depositor: 10, root: Some(5), nominator: Some(6), bouncer: Some(7) }, ); // also root origin can @@ -4730,20 +4721,11 @@ mod update_roles { assert_eq!( pool_events_since_last_call(), - vec![Event::RolesUpdated { - root: Some(1), - state_toggler: Some(3), - nominator: Some(2) - }] + vec![Event::RolesUpdated { root: Some(1), bouncer: 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) - }, + PoolRoles { depositor: 10, root: Some(1), nominator: Some(2), bouncer: Some(3) }, ); // Noop works @@ -4757,21 +4739,12 @@ mod update_roles { assert_eq!( pool_events_since_last_call(), - vec![Event::RolesUpdated { - root: Some(11), - state_toggler: Some(3), - nominator: Some(2) - }] + vec![Event::RolesUpdated { root: Some(11), bouncer: Some(3), nominator: Some(2) }] ); assert_eq!( BondedPools::::get(1).unwrap().roles, - PoolRoles { - depositor: 10, - root: Some(11), - nominator: Some(2), - state_toggler: Some(3) - }, + PoolRoles { depositor: 10, root: Some(11), nominator: Some(2), bouncer: Some(3) }, ); // Remove works @@ -4785,12 +4758,12 @@ mod update_roles { assert_eq!( pool_events_since_last_call(), - vec![Event::RolesUpdated { root: Some(69), state_toggler: None, nominator: None }] + vec![Event::RolesUpdated { root: Some(69), bouncer: None, nominator: None }] ); assert_eq!( BondedPools::::get(1).unwrap().roles, - PoolRoles { depositor: 10, root: Some(69), nominator: None, state_toggler: None }, + PoolRoles { depositor: 10, root: Some(69), nominator: None, bouncer: None }, ); }) } From 0e8daf091fd801c26022d0da1876d63852334ec3 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Tue, 21 Feb 2023 18:03:17 +0100 Subject: [PATCH 420/715] Add `defensive_assert!` macro (#13423) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add defensive_assert macro Signed-off-by: Oliver Tale-Yazdi * Apply review suggestions Co-authored-by: Bastian Köcher Signed-off-by: Oliver Tale-Yazdi --------- Signed-off-by: Oliver Tale-Yazdi --- frame/support/src/traits/misc.rs | 44 ++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/frame/support/src/traits/misc.rs b/frame/support/src/traits/misc.rs index 734b84ebd9d85..5a13fc4ab6509 100644 --- a/frame/support/src/traits/misc.rs +++ b/frame/support/src/traits/misc.rs @@ -49,7 +49,7 @@ macro_rules! defensive { ); debug_assert!(false, "{}", $crate::traits::DEFENSIVE_OP_INTERNAL_ERROR); }; - ($error:tt) => { + ($error:expr $(,)?) => { frame_support::log::error!( target: "runtime", "{}: {:?}", @@ -58,7 +58,7 @@ macro_rules! defensive { ); debug_assert!(false, "{}: {:?}", $crate::traits::DEFENSIVE_OP_INTERNAL_ERROR, $error); }; - ($error:tt, $proof:tt) => { + ($error:expr, $proof:expr $(,)?) => { frame_support::log::error!( target: "runtime", "{}: {:?}: {:?}", @@ -70,6 +70,25 @@ macro_rules! defensive { } } +/// Trigger a defensive failure if a condition is not met. +/// +/// Similar to [`assert!`] but will print an error without `debug_assertions` instead of silently +/// ignoring it. Only accepts one instead of variable formatting arguments. +/// +/// # Example +/// +/// ```should_panic +/// frame_support::defensive_assert!(1 == 0, "Must fail") +/// ``` +#[macro_export] +macro_rules! defensive_assert { + ($cond:expr $(, $proof:expr )? $(,)?) => { + if !($cond) { + $crate::defensive!(::core::stringify!($cond) $(, $proof )?); + } + }; +} + /// Prelude module for all defensive traits to be imported at once. pub mod defensive_prelude { pub use super::{Defensive, DefensiveOption, DefensiveResult}; @@ -1141,6 +1160,27 @@ mod test { use sp_core::bounded::{BoundedSlice, BoundedVec}; use sp_std::marker::PhantomData; + #[test] + fn defensive_assert_works() { + defensive_assert!(true); + defensive_assert!(true,); + defensive_assert!(true, "must work"); + defensive_assert!(true, "must work",); + } + + #[test] + #[cfg(debug_assertions)] + #[should_panic(expected = "Defensive failure has been triggered!: \"1 == 0\": \"Must fail\"")] + fn defensive_assert_panics() { + defensive_assert!(1 == 0, "Must fail"); + } + + #[test] + #[cfg(not(debug_assertions))] + fn defensive_assert_does_not_panic() { + defensive_assert!(1 == 0, "Must fail"); + } + #[test] #[cfg(not(debug_assertions))] fn defensive_saturating_accrue_works() { From 2d6e5556bbf47581b5f86b1c2f6bd7eb9add4cd9 Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Tue, 21 Feb 2023 19:36:00 +0100 Subject: [PATCH 421/715] `BlockId` removal: `BlockBuilderProvider::new_block_at` (#13401) * `BlockId` removal: `BlockBuilderProvider::new_block_at` It changes the arguments of `BlockBuilderProvider::new_block_at` from: `BlockId` to: `Block::Hash` * fmt * fix * more fixes --- bin/node/cli/benches/block_production.rs | 7 +- .../basic-authorship/src/basic_authorship.rs | 11 +- client/beefy/src/tests.rs | 15 +- client/block-builder/src/lib.rs | 3 +- client/consensus/babe/src/tests.rs | 9 +- client/finality-grandpa/src/tests.rs | 6 +- .../merkle-mountain-range/src/test_utils.rs | 3 +- .../network/src/service/tests/chain_sync.rs | 7 +- client/network/sync/src/lib.rs | 7 +- client/network/test/src/lib.rs | 3 +- client/rpc-spec-v2/src/chain_head/tests.rs | 10 +- client/service/src/client/client.rs | 6 +- client/service/test/src/client/mod.rs | 202 ++++++++++-------- primitives/api/test/tests/runtime_calls.rs | 8 +- test-utils/runtime/client/src/trait_tests.rs | 74 +++---- 15 files changed, 175 insertions(+), 196 deletions(-) diff --git a/bin/node/cli/benches/block_production.rs b/bin/node/cli/benches/block_production.rs index 4fcebb123d9e3..64ea03f58289a 100644 --- a/bin/node/cli/benches/block_production.rs +++ b/bin/node/cli/benches/block_production.rs @@ -37,7 +37,6 @@ 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, }; @@ -206,14 +205,14 @@ fn block_production(c: &mut Criterion) { group.sample_size(10); group.throughput(Throughput::Elements(max_transfer_count as u64)); - let block_id = BlockId::Hash(client.chain_info().best_hash); + let best_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(); + client.new_block_at(best_hash, Default::default(), RecordProof::No).unwrap(); for extrinsic in extrinsics { block_builder.push(extrinsic).unwrap(); } @@ -228,7 +227,7 @@ fn block_production(c: &mut Criterion) { || extrinsics.clone(), |extrinsics| { let mut block_builder = - client.new_block_at(&block_id, Default::default(), RecordProof::Yes).unwrap(); + client.new_block_at(best_hash, Default::default(), RecordProof::Yes).unwrap(); for extrinsic in extrinsics { block_builder.push(extrinsic).unwrap(); } diff --git a/client/basic-authorship/src/basic_authorship.rs b/client/basic-authorship/src/basic_authorship.rs index 9ab7ef55fb03a..f68a86ef12a39 100644 --- a/client/basic-authorship/src/basic_authorship.rs +++ b/client/basic-authorship/src/basic_authorship.rs @@ -38,7 +38,6 @@ use sp_consensus::{DisableProofRecording, EnableProofRecording, ProofRecording, use sp_core::traits::SpawnNamed; use sp_inherents::InherentData; use sp_runtime::{ - generic::BlockId, traits::{BlakeTwo256, Block as BlockT, Hash as HashT, Header as HeaderT}, Digest, Percent, SaturatedConversion, }; @@ -196,14 +195,12 @@ where ) -> Proposer { let parent_hash = parent_header.hash(); - let id = BlockId::hash(parent_hash); - info!("🙌 Starting consensus session on top of parent {:?}", parent_hash); let proposer = Proposer::<_, _, _, _, PR> { spawn_handle: self.spawn_handle.clone(), client: self.client.clone(), - parent_id: id, + parent_hash, parent_number: *parent_header.number(), transaction_pool: self.transaction_pool.clone(), now, @@ -247,7 +244,7 @@ where pub struct Proposer { spawn_handle: Box, client: Arc, - parent_id: BlockId, + parent_hash: Block::Hash, parent_number: <::Header as HeaderT>::Number, transaction_pool: Arc, now: Box time::Instant + Send + Sync>, @@ -344,7 +341,7 @@ where { let propose_with_start = time::Instant::now(); let mut block_builder = - self.client.new_block_at(&self.parent_id, inherent_digests, PR::ENABLED)?; + self.client.new_block_at(self.parent_hash, inherent_digests, PR::ENABLED)?; let create_inherents_start = time::Instant::now(); let inherents = block_builder.create_inherents(inherent_data)?; @@ -559,7 +556,7 @@ mod tests { use sp_blockchain::HeaderBackend; use sp_consensus::{BlockOrigin, Environment, Proposer}; use sp_core::Pair; - use sp_runtime::traits::NumberFor; + use sp_runtime::{generic::BlockId, traits::NumberFor}; use substrate_test_runtime_client::{ prelude::*, runtime::{Extrinsic, Transfer}, diff --git a/client/beefy/src/tests.rs b/client/beefy/src/tests.rs index f17a42f2045a5..d8afc5465eaad 100644 --- a/client/beefy/src/tests.rs +++ b/client/beefy/src/tests.rs @@ -58,7 +58,6 @@ use sp_keystore::{testing::KeyStore as TestKeystore, SyncCryptoStore, SyncCrypto use sp_mmr_primitives::{Error as MmrError, MmrApi}; use sp_runtime::{ codec::Encode, - generic::BlockId, traits::{Header as HeaderT, NumberFor}, BuildStorage, DigestItem, EncodedJustification, Justifications, Storage, }; @@ -753,8 +752,9 @@ async fn beefy_importing_justifications() { .and_then(|j| j.get(BEEFY_ENGINE_ID).cloned()) }; - let parent_id = BlockId::Number(0); - let builder = full_client.new_block_at(&parent_id, Default::default(), false).unwrap(); + let builder = full_client + .new_block_at(full_client.chain_info().genesis_hash, Default::default(), false) + .unwrap(); let block = builder.build().unwrap().block; let hashof1 = block.header.hash(); @@ -772,9 +772,8 @@ async fn beefy_importing_justifications() { ); // Import block 2 with "valid" justification (beefy pallet genesis block not yet reached). - let parent_id = BlockId::Number(1); let block_num = 2; - let builder = full_client.new_block_at(&parent_id, Default::default(), false).unwrap(); + let builder = full_client.new_block_at(hashof1, Default::default(), false).unwrap(); let block = builder.build().unwrap().block; let hashof2 = block.header.hash(); @@ -805,9 +804,8 @@ async fn beefy_importing_justifications() { } // Import block 3 with valid justification. - let parent_id = BlockId::Number(2); let block_num = 3; - let builder = full_client.new_block_at(&parent_id, Default::default(), false).unwrap(); + let builder = full_client.new_block_at(hashof2, Default::default(), false).unwrap(); let block = builder.build().unwrap().block; let hashof3 = block.header.hash(); let proof = crate::justification::tests::new_finality_proof(block_num, &good_set, keys); @@ -840,9 +838,8 @@ async fn beefy_importing_justifications() { } // Import block 4 with invalid justification (incorrect validator set). - let parent_id = BlockId::Number(3); let block_num = 4; - let builder = full_client.new_block_at(&parent_id, Default::default(), false).unwrap(); + let builder = full_client.new_block_at(hashof3, Default::default(), false).unwrap(); let block = builder.build().unwrap().block; let hashof4 = block.header.hash(); let keys = &[BeefyKeyring::Alice]; diff --git a/client/block-builder/src/lib.rs b/client/block-builder/src/lib.rs index d302a834fd723..437e43a71d634 100644 --- a/client/block-builder/src/lib.rs +++ b/client/block-builder/src/lib.rs @@ -34,7 +34,6 @@ use sp_api::{ 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, @@ -120,7 +119,7 @@ where /// output of this block builder without having access to the full storage. fn new_block_at>( &self, - parent: &BlockId, + parent: Block::Hash, inherent_digests: Digest, record_proof: R, ) -> sp_blockchain::Result>; diff --git a/client/consensus/babe/src/tests.rs b/client/consensus/babe/src/tests.rs index ad2e95df033f4..d1ad91a1ce760 100644 --- a/client/consensus/babe/src/tests.rs +++ b/client/consensus/babe/src/tests.rs @@ -45,7 +45,7 @@ use sp_keystore::{ SyncCryptoStore, }; use sp_runtime::{ - generic::{BlockId, Digest, DigestItem}, + generic::{Digest, DigestItem}, traits::Block as BlockT, }; use sp_timestamp::Timestamp; @@ -123,11 +123,8 @@ impl DummyProposer { Error, >, > { - let block_builder = self - .factory - .client - .new_block_at(&BlockId::Hash(self.parent_hash), pre_digests, false) - .unwrap(); + let block_builder = + self.factory.client.new_block_at(self.parent_hash, pre_digests, false).unwrap(); let mut block = match block_builder.build().map_err(|e| e.into()) { Ok(b) => b.block, diff --git a/client/finality-grandpa/src/tests.rs b/client/finality-grandpa/src/tests.rs index d132abd940ba3..fee3b13ba0be9 100644 --- a/client/finality-grandpa/src/tests.rs +++ b/client/finality-grandpa/src/tests.rs @@ -875,7 +875,7 @@ async fn allows_reimporting_change_blocks() { let full_client = client.as_client(); let builder = full_client - .new_block_at(&BlockId::Number(0), Default::default(), false) + .new_block_at(full_client.chain_info().genesis_hash, Default::default(), false) .unwrap(); let mut block = builder.build().unwrap().block; add_scheduled_change( @@ -922,7 +922,7 @@ async fn test_bad_justification() { let full_client = client.as_client(); let builder = full_client - .new_block_at(&BlockId::Number(0), Default::default(), false) + .new_block_at(full_client.chain_info().genesis_hash, Default::default(), false) .unwrap(); let mut block = builder.build().unwrap().block; @@ -1854,7 +1854,7 @@ async fn imports_justification_for_regular_blocks_on_import() { let full_client = client.as_client(); let builder = full_client - .new_block_at(&BlockId::Number(0), Default::default(), false) + .new_block_at(full_client.chain_info().genesis_hash, Default::default(), false) .unwrap(); let block = builder.build().unwrap().block; diff --git a/client/merkle-mountain-range/src/test_utils.rs b/client/merkle-mountain-range/src/test_utils.rs index e5a6673483dbb..9decaa3c243ff 100644 --- a/client/merkle-mountain-range/src/test_utils.rs +++ b/client/merkle-mountain-range/src/test_utils.rs @@ -124,7 +124,8 @@ impl MockClient { ) -> MmrBlock { let mut client = self.client.lock(); - let mut block_builder = client.new_block_at(at, Default::default(), false).unwrap(); + let hash = client.expect_block_hash_from_id(&at).unwrap(); + let mut block_builder = client.new_block_at(hash, 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())) diff --git a/client/network/src/service/tests/chain_sync.rs b/client/network/src/service/tests/chain_sync.rs index 1ae432fd4c235..98884024ac7e1 100644 --- a/client/network/src/service/tests/chain_sync.rs +++ b/client/network/src/service/tests/chain_sync.rs @@ -34,10 +34,7 @@ use sc_network_common::{ }; 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 sp_runtime::traits::{Block as BlockT, Header as _}; use std::{ sync::{Arc, RwLock}, task::Poll, @@ -188,7 +185,7 @@ async fn on_block_finalized() { let at = client.header(client.info().best_hash).unwrap().unwrap().hash(); let block = client - .new_block_at(&BlockId::Hash(at), Default::default(), false) + .new_block_at(at, Default::default(), false) .unwrap() .build() .unwrap() diff --git a/client/network/sync/src/lib.rs b/client/network/sync/src/lib.rs index f56ef13fc9065..1f4f6a04ebd77 100644 --- a/client/network/sync/src/lib.rs +++ b/client/network/sync/src/lib.rs @@ -3212,7 +3212,6 @@ mod test { }; use sp_blockchain::HeaderBackend; use sp_consensus::block_validation::DefaultBlockAnnounceValidator; - use sp_runtime::generic::BlockId; use substrate_test_runtime_client::{ runtime::{Block, Hash, Header}, BlockBuilderExt, ClientBlockImportExt, ClientExt, DefaultTestClientBuilderExt, TestClient, @@ -3449,8 +3448,7 @@ mod test { fn build_block(client: &mut Arc, at: Option, fork: bool) -> Block { let at = at.unwrap_or_else(|| client.info().best_hash); - let mut block_builder = - client.new_block_at(&BlockId::Hash(at), Default::default(), false).unwrap(); + let mut block_builder = client.new_block_at(at, Default::default(), false).unwrap(); if fork { block_builder.push_storage_change(vec![1, 2, 3], Some(vec![4, 5, 6])).unwrap(); @@ -3503,8 +3501,7 @@ mod test { let mut client2 = client.clone(); let mut build_block_at = |at, import| { - let mut block_builder = - client2.new_block_at(&BlockId::Hash(at), Default::default(), false).unwrap(); + let mut block_builder = client2.new_block_at(at, Default::default(), false).unwrap(); // Make sure we generate a different block as fork block_builder.push_storage_change(vec![1, 2, 3], Some(vec![4, 5, 6])).unwrap(); diff --git a/client/network/test/src/lib.rs b/client/network/test/src/lib.rs index c47e3c86f5c0e..3cd508103c41a 100644 --- a/client/network/test/src/lib.rs +++ b/client/network/test/src/lib.rs @@ -377,8 +377,7 @@ where let full_client = self.client.as_client(); let mut at = full_client.block_hash_from_id(&at).unwrap().unwrap(); for _ in 0..count { - let builder = - full_client.new_block_at(&BlockId::Hash(at), Default::default(), false).unwrap(); + let builder = full_client.new_block_at(at, Default::default(), false).unwrap(); let block = edit_block(builder); let hash = block.header.hash(); trace!( diff --git a/client/rpc-spec-v2/src/chain_head/tests.rs b/client/rpc-spec-v2/src/chain_head/tests.rs index 4084075f0b321..79be391368f71 100644 --- a/client/rpc-spec-v2/src/chain_head/tests.rs +++ b/client/rpc-spec-v2/src/chain_head/tests.rs @@ -8,7 +8,6 @@ use jsonrpsee::{ }; use sc_block_builder::BlockBuilderProvider; use sc_client_api::ChildInfo; -use sp_api::BlockId; use sp_blockchain::HeaderBackend; use sp_consensus::BlockOrigin; use sp_core::{ @@ -639,9 +638,8 @@ async fn follow_generates_initial_blocks() { let block_2_hash = block_2.header.hash(); client.import(BlockOrigin::Own, block_2.clone()).await.unwrap(); - let mut block_builder = client - .new_block_at(&BlockId::Hash(block_1.header.hash()), Default::default(), false) - .unwrap(); + let mut block_builder = + client.new_block_at(block_1.header.hash(), Default::default(), false).unwrap(); // This push is required as otherwise block 3 has the same hash as block 2 and won't get // imported block_builder @@ -921,9 +919,7 @@ async fn follow_prune_best_block() { client.import(BlockOrigin::Own, block_4.clone()).await.unwrap(); // Import block 2 as best on the fork. - let mut block_builder = client - .new_block_at(&BlockId::Hash(block_1.header.hash()), Default::default(), false) - .unwrap(); + let mut block_builder = client.new_block_at(block_1_hash, Default::default(), false).unwrap(); // This push is required as otherwise block 3 has the same hash as block 2 and won't get // imported block_builder diff --git a/client/service/src/client/client.rs b/client/service/src/client/client.rs index 7bd37b5163664..615817cc32517 100644 --- a/client/service/src/client/client.rs +++ b/client/service/src/client/client.rs @@ -1408,14 +1408,14 @@ where { fn new_block_at>( &self, - parent: &BlockId, + parent: Block::Hash, inherent_digests: Digest, record_proof: R, ) -> sp_blockchain::Result> { sc_block_builder::BlockBuilder::new( self, - self.expect_block_hash_from_id(parent)?, - self.expect_block_number_from_id(parent)?, + parent, + self.expect_block_number_from_id(&BlockId::Hash(parent))?, record_proof.into(), inherent_digests, &self.backend, diff --git a/client/service/test/src/client/mod.rs b/client/service/test/src/client/mod.rs index 53af18c6b8604..0fe4760fcb93e 100644 --- a/client/service/test/src/client/mod.rs +++ b/client/service/test/src/client/mod.rs @@ -447,7 +447,7 @@ fn uncles_with_multiple_forks() { // A1 -> A2 let a2 = client - .new_block_at(&BlockId::Hash(a1.hash()), Default::default(), false) + .new_block_at(a1.hash(), Default::default(), false) .unwrap() .build() .unwrap() @@ -456,7 +456,7 @@ fn uncles_with_multiple_forks() { // A2 -> A3 let a3 = client - .new_block_at(&BlockId::Hash(a2.hash()), Default::default(), false) + .new_block_at(a2.hash(), Default::default(), false) .unwrap() .build() .unwrap() @@ -465,7 +465,7 @@ fn uncles_with_multiple_forks() { // A3 -> A4 let a4 = client - .new_block_at(&BlockId::Hash(a3.hash()), Default::default(), false) + .new_block_at(a3.hash(), Default::default(), false) .unwrap() .build() .unwrap() @@ -474,7 +474,7 @@ fn uncles_with_multiple_forks() { // A4 -> A5 let a5 = client - .new_block_at(&BlockId::Hash(a4.hash()), Default::default(), false) + .new_block_at(a4.hash(), Default::default(), false) .unwrap() .build() .unwrap() @@ -482,9 +482,7 @@ fn uncles_with_multiple_forks() { block_on(client.import(BlockOrigin::Own, a5.clone())).unwrap(); // A1 -> B2 - let mut builder = client - .new_block_at(&BlockId::Hash(a1.hash()), Default::default(), false) - .unwrap(); + let mut builder = client.new_block_at(a1.hash(), Default::default(), false).unwrap(); // this push is required as otherwise B2 has the same hash as A2 and won't get imported builder .push_transfer(Transfer { @@ -499,7 +497,7 @@ fn uncles_with_multiple_forks() { // B2 -> B3 let b3 = client - .new_block_at(&BlockId::Hash(b2.hash()), Default::default(), false) + .new_block_at(b2.hash(), Default::default(), false) .unwrap() .build() .unwrap() @@ -508,7 +506,7 @@ fn uncles_with_multiple_forks() { // B3 -> B4 let b4 = client - .new_block_at(&BlockId::Hash(b3.hash()), Default::default(), false) + .new_block_at(b3.hash(), Default::default(), false) .unwrap() .build() .unwrap() @@ -516,9 +514,7 @@ fn uncles_with_multiple_forks() { block_on(client.import(BlockOrigin::Own, b4.clone())).unwrap(); // // B2 -> C3 - let mut builder = client - .new_block_at(&BlockId::Hash(b2.hash()), Default::default(), false) - .unwrap(); + let mut builder = client.new_block_at(b2.hash(), Default::default(), false).unwrap(); // this push is required as otherwise C3 has the same hash as B3 and won't get imported builder .push_transfer(Transfer { @@ -532,9 +528,7 @@ fn uncles_with_multiple_forks() { block_on(client.import(BlockOrigin::Own, c3.clone())).unwrap(); // A1 -> D2 - let mut builder = client - .new_block_at(&BlockId::Hash(a1.hash()), Default::default(), false) - .unwrap(); + let mut builder = client.new_block_at(a1.hash(), Default::default(), false).unwrap(); // this push is required as otherwise D2 has the same hash as B2 and won't get imported builder .push_transfer(Transfer { @@ -608,7 +602,7 @@ fn finality_target_on_longest_chain_with_multiple_forks() { // A1 -> A2 let a2 = client - .new_block_at(&BlockId::Hash(a1.hash()), Default::default(), false) + .new_block_at(a1.hash(), Default::default(), false) .unwrap() .build() .unwrap() @@ -617,7 +611,7 @@ fn finality_target_on_longest_chain_with_multiple_forks() { // A2 -> A3 let a3 = client - .new_block_at(&BlockId::Hash(a2.hash()), Default::default(), false) + .new_block_at(a2.hash(), Default::default(), false) .unwrap() .build() .unwrap() @@ -626,7 +620,7 @@ fn finality_target_on_longest_chain_with_multiple_forks() { // A3 -> A4 let a4 = client - .new_block_at(&BlockId::Hash(a3.hash()), Default::default(), false) + .new_block_at(a3.hash(), Default::default(), false) .unwrap() .build() .unwrap() @@ -635,7 +629,7 @@ fn finality_target_on_longest_chain_with_multiple_forks() { // A4 -> A5 let a5 = client - .new_block_at(&BlockId::Hash(a4.hash()), Default::default(), false) + .new_block_at(a4.hash(), Default::default(), false) .unwrap() .build() .unwrap() @@ -643,9 +637,7 @@ fn finality_target_on_longest_chain_with_multiple_forks() { block_on(client.import(BlockOrigin::Own, a5.clone())).unwrap(); // A1 -> B2 - let mut builder = client - .new_block_at(&BlockId::Hash(a1.hash()), Default::default(), false) - .unwrap(); + let mut builder = client.new_block_at(a1.hash(), Default::default(), false).unwrap(); // this push is required as otherwise B2 has the same hash as A2 and won't get imported builder .push_transfer(Transfer { @@ -660,7 +652,7 @@ fn finality_target_on_longest_chain_with_multiple_forks() { // B2 -> B3 let b3 = client - .new_block_at(&BlockId::Hash(b2.hash()), Default::default(), false) + .new_block_at(b2.hash(), Default::default(), false) .unwrap() .build() .unwrap() @@ -669,7 +661,7 @@ fn finality_target_on_longest_chain_with_multiple_forks() { // B3 -> B4 let b4 = client - .new_block_at(&BlockId::Hash(b3.hash()), Default::default(), false) + .new_block_at(b3.hash(), Default::default(), false) .unwrap() .build() .unwrap() @@ -677,9 +669,7 @@ fn finality_target_on_longest_chain_with_multiple_forks() { block_on(client.import(BlockOrigin::Own, b4.clone())).unwrap(); // B2 -> C3 - let mut builder = client - .new_block_at(&BlockId::Hash(b2.hash()), Default::default(), false) - .unwrap(); + let mut builder = client.new_block_at(b2.hash(), Default::default(), false).unwrap(); // this push is required as otherwise C3 has the same hash as B3 and won't get imported builder .push_transfer(Transfer { @@ -693,9 +683,7 @@ fn finality_target_on_longest_chain_with_multiple_forks() { block_on(client.import(BlockOrigin::Own, c3.clone())).unwrap(); // A1 -> D2 - let mut builder = client - .new_block_at(&BlockId::Hash(a1.hash()), Default::default(), false) - .unwrap(); + let mut builder = client.new_block_at(a1.hash(), Default::default(), false).unwrap(); // this push is required as otherwise D2 has the same hash as B2 and won't get imported builder .push_transfer(Transfer { @@ -871,9 +859,7 @@ fn finality_target_with_best_not_on_longest_chain() { block_on(client.import(BlockOrigin::Own, a5.clone())).unwrap(); // A1 -> B2 - let mut builder = client - .new_block_at(&BlockId::Hash(a1.hash()), Default::default(), false) - .unwrap(); + let mut builder = client.new_block_at(a1.hash(), Default::default(), false).unwrap(); // this push is required as otherwise B2 has the same hash as A2 and won't get imported builder .push_transfer(Transfer { @@ -895,7 +881,7 @@ fn finality_target_with_best_not_on_longest_chain() { // B2 -> B3 let b3 = client - .new_block_at(&BlockId::Hash(b2.hash()), Default::default(), false) + .new_block_at(b2.hash(), Default::default(), false) .unwrap() .build() .unwrap() @@ -904,7 +890,7 @@ fn finality_target_with_best_not_on_longest_chain() { // B3 -> B4 let b4 = client - .new_block_at(&BlockId::Hash(b3.hash()), Default::default(), false) + .new_block_at(b3.hash(), Default::default(), false) .unwrap() .build() .unwrap() @@ -940,7 +926,7 @@ fn import_with_justification() { // A1 -> A2 let a2 = client - .new_block_at(&BlockId::Hash(a1.hash()), Default::default(), false) + .new_block_at(a1.hash(), Default::default(), false) .unwrap() .build() .unwrap() @@ -951,7 +937,7 @@ fn import_with_justification() { // A2 -> A3 let justification = Justifications::from((TEST_ENGINE_ID, vec![1, 2, 3])); let a3 = client - .new_block_at(&BlockId::Hash(a2.hash()), Default::default(), false) + .new_block_at(a2.hash(), Default::default(), false) .unwrap() .build() .unwrap() @@ -982,7 +968,7 @@ fn importing_diverged_finalized_block_should_trigger_reorg() { let mut finality_notifications = client.finality_notification_stream(); let a1 = client - .new_block_at(&BlockId::Number(0), Default::default(), false) + .new_block_at(client.chain_info().genesis_hash, Default::default(), false) .unwrap() .build() .unwrap() @@ -990,14 +976,16 @@ fn importing_diverged_finalized_block_should_trigger_reorg() { block_on(client.import(BlockOrigin::Own, a1.clone())).unwrap(); let a2 = client - .new_block_at(&BlockId::Hash(a1.hash()), Default::default(), false) + .new_block_at(a1.hash(), Default::default(), false) .unwrap() .build() .unwrap() .block; block_on(client.import(BlockOrigin::Own, a2.clone())).unwrap(); - let mut b1 = client.new_block_at(&BlockId::Number(0), Default::default(), false).unwrap(); + let mut b1 = client + .new_block_at(client.chain_info().genesis_hash, Default::default(), false) + .unwrap(); // needed to make sure B1 gets a different hash from A1 b1.push_transfer(Transfer { from: AccountKeyring::Alice.into(), @@ -1035,7 +1023,7 @@ fn finalizing_diverged_block_should_trigger_reorg() { let mut finality_notifications = client.finality_notification_stream(); let a1 = client - .new_block_at(&BlockId::Number(0), Default::default(), false) + .new_block_at(client.chain_info().genesis_hash, Default::default(), false) .unwrap() .build() .unwrap() @@ -1043,14 +1031,16 @@ fn finalizing_diverged_block_should_trigger_reorg() { block_on(client.import(BlockOrigin::Own, a1.clone())).unwrap(); let a2 = client - .new_block_at(&BlockId::Hash(a1.hash()), Default::default(), false) + .new_block_at(a1.hash(), Default::default(), false) .unwrap() .build() .unwrap() .block; block_on(client.import(BlockOrigin::Own, a2.clone())).unwrap(); - let mut b1 = client.new_block_at(&BlockId::Number(0), Default::default(), false).unwrap(); + let mut b1 = client + .new_block_at(client.chain_info().genesis_hash, Default::default(), false) + .unwrap(); // needed to make sure B1 gets a different hash from A1 b1.push_transfer(Transfer { from: AccountKeyring::Alice.into(), @@ -1063,7 +1053,7 @@ fn finalizing_diverged_block_should_trigger_reorg() { block_on(client.import(BlockOrigin::Own, b1.clone())).unwrap(); let b2 = client - .new_block_at(&BlockId::Hash(b1.hash()), Default::default(), false) + .new_block_at(b1.hash(), Default::default(), false) .unwrap() .build() .unwrap() @@ -1089,7 +1079,7 @@ fn finalizing_diverged_block_should_trigger_reorg() { // after we build B3 on top of B2 and import it, it should be the new best block let b3 = client - .new_block_at(&BlockId::Hash(b2.hash()), Default::default(), false) + .new_block_at(b2.hash(), Default::default(), false) .unwrap() .build() .unwrap() @@ -1121,7 +1111,7 @@ fn finality_notifications_content() { let mut finality_notifications = client.finality_notification_stream(); let a1 = client - .new_block_at(&BlockId::Number(0), Default::default(), false) + .new_block_at(client.chain_info().genesis_hash, Default::default(), false) .unwrap() .build() .unwrap() @@ -1129,7 +1119,7 @@ fn finality_notifications_content() { block_on(client.import(BlockOrigin::Own, a1.clone())).unwrap(); let a2 = client - .new_block_at(&BlockId::Hash(a1.hash()), Default::default(), false) + .new_block_at(a1.hash(), Default::default(), false) .unwrap() .build() .unwrap() @@ -1137,14 +1127,16 @@ fn finality_notifications_content() { block_on(client.import(BlockOrigin::Own, a2.clone())).unwrap(); let a3 = client - .new_block_at(&BlockId::Hash(a2.hash()), Default::default(), false) + .new_block_at(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(); + let mut b1 = client + .new_block_at(client.chain_info().genesis_hash, Default::default(), false) + .unwrap(); // needed to make sure B1 gets a different hash from A1 b1.push_transfer(Transfer { from: AccountKeyring::Alice.into(), @@ -1157,14 +1149,16 @@ fn finality_notifications_content() { block_on(client.import(BlockOrigin::Own, b1.clone())).unwrap(); let b2 = client - .new_block_at(&BlockId::Hash(b1.hash()), Default::default(), false) + .new_block_at(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(); + let mut c1 = client + .new_block_at(client.chain_info().genesis_hash, Default::default(), false) + .unwrap(); // needed to make sure B1 gets a different hash from A1 c1.push_transfer(Transfer { from: AccountKeyring::Alice.into(), @@ -1176,9 +1170,7 @@ fn finality_notifications_content() { let c1 = c1.build().unwrap().block; block_on(client.import(BlockOrigin::Own, c1.clone())).unwrap(); - let mut d3 = client - .new_block_at(&BlockId::Hash(a2.hash()), Default::default(), false) - .unwrap(); + let mut d3 = client.new_block_at(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(), @@ -1191,7 +1183,7 @@ fn finality_notifications_content() { block_on(client.import(BlockOrigin::Own, d3.clone())).unwrap(); let d4 = client - .new_block_at(&BlockId::Hash(d3.hash()), Default::default(), false) + .new_block_at(d3.hash(), Default::default(), false) .unwrap() .build() .unwrap() @@ -1251,7 +1243,9 @@ fn state_reverted_on_reorg() { // G -> A1 -> A2 // \ // -> B1 - let mut a1 = client.new_block_at(&BlockId::Number(0), Default::default(), false).unwrap(); + let mut a1 = client + .new_block_at(client.chain_info().genesis_hash, Default::default(), false) + .unwrap(); a1.push_transfer(Transfer { from: AccountKeyring::Alice.into(), to: AccountKeyring::Bob.into(), @@ -1262,7 +1256,9 @@ fn state_reverted_on_reorg() { let a1 = a1.build().unwrap().block; block_on(client.import(BlockOrigin::Own, a1.clone())).unwrap(); - let mut b1 = client.new_block_at(&BlockId::Number(0), Default::default(), false).unwrap(); + let mut b1 = client + .new_block_at(client.chain_info().genesis_hash, Default::default(), false) + .unwrap(); b1.push_transfer(Transfer { from: AccountKeyring::Alice.into(), to: AccountKeyring::Ferdie.into(), @@ -1275,9 +1271,7 @@ fn state_reverted_on_reorg() { block_on(client.import_as_best(BlockOrigin::Own, b1.clone())).unwrap(); assert_eq!(950, current_balance(&client)); - let mut a2 = client - .new_block_at(&BlockId::Hash(a1.hash()), Default::default(), false) - .unwrap(); + let mut a2 = client.new_block_at(a1.hash(), Default::default(), false).unwrap(); a2.push_transfer(Transfer { from: AccountKeyring::Alice.into(), to: AccountKeyring::Charlie.into(), @@ -1322,7 +1316,7 @@ fn doesnt_import_blocks_that_revert_finality() { // -> B1 -> B2 -> B3 let a1 = client - .new_block_at(&BlockId::Number(0), Default::default(), false) + .new_block_at(client.chain_info().genesis_hash, Default::default(), false) .unwrap() .build() .unwrap() @@ -1330,14 +1324,16 @@ fn doesnt_import_blocks_that_revert_finality() { block_on(client.import(BlockOrigin::Own, a1.clone())).unwrap(); let a2 = client - .new_block_at(&BlockId::Hash(a1.hash()), Default::default(), false) + .new_block_at(a1.hash(), Default::default(), false) .unwrap() .build() .unwrap() .block; block_on(client.import(BlockOrigin::Own, a2.clone())).unwrap(); - let mut b1 = client.new_block_at(&BlockId::Number(0), Default::default(), false).unwrap(); + let mut b1 = client + .new_block_at(client.chain_info().genesis_hash, Default::default(), false) + .unwrap(); // needed to make sure B1 gets a different hash from A1 b1.push_transfer(Transfer { @@ -1351,7 +1347,7 @@ fn doesnt_import_blocks_that_revert_finality() { block_on(client.import(BlockOrigin::Own, b1.clone())).unwrap(); let b2 = client - .new_block_at(&BlockId::Hash(b1.hash()), Default::default(), false) + .new_block_at(b1.hash(), Default::default(), false) .unwrap() .build() .unwrap() @@ -1361,7 +1357,7 @@ fn doesnt_import_blocks_that_revert_finality() { // prepare B3 before we finalize A2, because otherwise we won't be able to // read changes trie configuration after A2 is finalized let b3 = client - .new_block_at(&BlockId::Hash(b2.hash()), Default::default(), false) + .new_block_at(b2.hash(), Default::default(), false) .unwrap() .build() .unwrap() @@ -1379,7 +1375,9 @@ fn doesnt_import_blocks_that_revert_finality() { // adding a C1 block which is lower than the last finalized should also // fail (with a cheaper check that doesn't require checking ancestry). - let mut c1 = client.new_block_at(&BlockId::Number(0), Default::default(), false).unwrap(); + let mut c1 = client + .new_block_at(client.chain_info().genesis_hash, Default::default(), false) + .unwrap(); // needed to make sure C1 gets a different hash from A1 and B1 c1.push_transfer(Transfer { @@ -1398,7 +1396,7 @@ fn doesnt_import_blocks_that_revert_finality() { assert_eq!(import_err.to_string(), expected_err.to_string()); let a3 = client - .new_block_at(&BlockId::Hash(a2.hash()), Default::default(), false) + .new_block_at(a2.hash(), Default::default(), false) .unwrap() .build() .unwrap() @@ -1428,16 +1426,34 @@ fn respects_block_rules() { .build() }; + // test modus operandi: + // + // B[2] + // / + // G[0]--B[1] + // \ \ + // \ B'[2] + // \ + // B'[1] + // + // B[1] - block ok + // B'[1] - block not ok, added to block_rules::bad + // + // B[2] - block ok, correct fork for block height==2, added to block_rules::forks + // B'[2] - block not ok, (incorrect fork) + + // build B[1] let block_ok = client - .new_block_at(&BlockId::Number(0), Default::default(), false) + .new_block_at(client.chain_info().genesis_hash, Default::default(), false) .unwrap() .build() .unwrap() .block; + let block_ok_1_hash = block_ok.hash(); let params = BlockCheckParams { hash: block_ok.hash(), - number: 0, + number: 1, parent_hash: *block_ok.header().parent_hash(), allow_missing_state: false, allow_missing_parent: false, @@ -1445,15 +1461,16 @@ fn respects_block_rules() { }; assert_eq!(block_on(client.check_block(params)).unwrap(), ImportResult::imported(false)); - // this is 0x0d6d6612a10485370d9e085aeea7ec427fb3f34d961c6a816cdbe5cde2278864 - let mut block_not_ok = - client.new_block_at(&BlockId::Number(0), Default::default(), false).unwrap(); + // build B'[1] + let mut block_not_ok = client + .new_block_at(client.chain_info().genesis_hash, Default::default(), false) + .unwrap(); block_not_ok.push_storage_change(vec![0], Some(vec![1])).unwrap(); let block_not_ok = block_not_ok.build().unwrap().block; let params = BlockCheckParams { hash: block_not_ok.hash(), - number: 0, + number: 1, parent_hash: *block_not_ok.header().parent_hash(), allow_missing_state: false, allow_missing_parent: false, @@ -1468,34 +1485,35 @@ fn respects_block_rules() { // Now going to the fork block_on(client.import_as_final(BlockOrigin::Own, block_ok)).unwrap(); - // And check good fork - let mut block_ok = - client.new_block_at(&BlockId::Number(1), Default::default(), false).unwrap(); + // And check good fork (build B[2]) + let mut block_ok = client.new_block_at(block_ok_1_hash, Default::default(), false).unwrap(); block_ok.push_storage_change(vec![0], Some(vec![2])).unwrap(); let block_ok = block_ok.build().unwrap().block; + assert_eq!(*block_ok.header().number(), 2); let params = BlockCheckParams { hash: block_ok.hash(), - number: 1, + number: 2, 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())); + fork_rules.push((2, block_ok.hash())); } assert_eq!(block_on(client.check_block(params)).unwrap(), ImportResult::imported(false)); - // And now try bad fork + // And now try bad fork (build B'[2]) let mut block_not_ok = - client.new_block_at(&BlockId::Number(1), Default::default(), false).unwrap(); + client.new_block_at(block_ok_1_hash, Default::default(), false).unwrap(); block_not_ok.push_storage_change(vec![0], Some(vec![3])).unwrap(); let block_not_ok = block_not_ok.build().unwrap().block; + assert_eq!(*block_not_ok.header().number(), 2); let params = BlockCheckParams { hash: block_not_ok.hash(), - number: 1, + number: 2, parent_hash: *block_not_ok.header().parent_hash(), allow_missing_state: false, allow_missing_parent: false, @@ -1540,13 +1558,15 @@ fn returns_status_for_pruned_blocks() { let mut client = TestClientBuilder::with_backend(backend).build(); let a1 = client - .new_block_at(&BlockId::Number(0), Default::default(), false) + .new_block_at(client.chain_info().genesis_hash, Default::default(), false) .unwrap() .build() .unwrap() .block; - let mut b1 = client.new_block_at(&BlockId::Number(0), Default::default(), false).unwrap(); + let mut b1 = client + .new_block_at(client.chain_info().genesis_hash, Default::default(), false) + .unwrap(); // b1 is created, but not imported b1.push_transfer(Transfer { @@ -1582,7 +1602,7 @@ fn returns_status_for_pruned_blocks() { assert_eq!(client.block_status(check_block_a1.hash).unwrap(), BlockStatus::InChainWithState); let a2 = client - .new_block_at(&BlockId::Hash(a1.hash()), Default::default(), false) + .new_block_at(a1.hash(), Default::default(), false) .unwrap() .build() .unwrap() @@ -1610,7 +1630,7 @@ fn returns_status_for_pruned_blocks() { assert_eq!(client.block_status(check_block_a2.hash).unwrap(), BlockStatus::InChainWithState); let a3 = client - .new_block_at(&BlockId::Hash(a2.hash()), Default::default(), false) + .new_block_at(a2.hash(), Default::default(), false) .unwrap() .build() .unwrap() @@ -1907,7 +1927,7 @@ fn reorg_triggers_a_notification_even_for_sources_that_should_not_trigger_notifi futures::executor::block_on_stream(client.import_notification_stream()); let a1 = client - .new_block_at(&BlockId::Number(0), Default::default(), false) + .new_block_at(client.chain_info().genesis_hash, Default::default(), false) .unwrap() .build() .unwrap() @@ -1915,14 +1935,16 @@ fn reorg_triggers_a_notification_even_for_sources_that_should_not_trigger_notifi block_on(client.import(BlockOrigin::NetworkInitialSync, a1.clone())).unwrap(); let a2 = client - .new_block_at(&BlockId::Hash(a1.hash()), Default::default(), false) + .new_block_at(a1.hash(), Default::default(), false) .unwrap() .build() .unwrap() .block; block_on(client.import(BlockOrigin::NetworkInitialSync, a2.clone())).unwrap(); - let mut b1 = client.new_block_at(&BlockId::Number(0), Default::default(), false).unwrap(); + let mut b1 = client + .new_block_at(client.chain_info().genesis_hash, Default::default(), false) + .unwrap(); // needed to make sure B1 gets a different hash from A1 b1.push_transfer(Transfer { from: AccountKeyring::Alice.into(), @@ -1935,7 +1957,7 @@ fn reorg_triggers_a_notification_even_for_sources_that_should_not_trigger_notifi block_on(client.import(BlockOrigin::NetworkInitialSync, b1.clone())).unwrap(); let b2 = client - .new_block_at(&BlockId::Hash(b1.hash()), Default::default(), false) + .new_block_at(b1.hash(), Default::default(), false) .unwrap() .build() .unwrap() @@ -1971,7 +1993,7 @@ fn use_dalek_ext_works() { ); let a1 = client - .new_block_at(&BlockId::Number(0), Default::default(), false) + .new_block_at(client.chain_info().genesis_hash, Default::default(), false) .unwrap() .build() .unwrap() diff --git a/primitives/api/test/tests/runtime_calls.rs b/primitives/api/test/tests/runtime_calls.rs index 4f88d887c8c55..feb3e1a6ef48c 100644 --- a/primitives/api/test/tests/runtime_calls.rs +++ b/primitives/api/test/tests/runtime_calls.rs @@ -16,10 +16,7 @@ // limitations under the License. use sp_api::{Core, ProvideRuntimeApi}; -use sp_runtime::{ - generic::BlockId, - traits::{HashFor, Header as HeaderT}, -}; +use sp_runtime::traits::{HashFor, Header as HeaderT}; use sp_state_machine::{ create_proof_check_backend, execution_proof_check_on_trie_backend, ExecutionStrategy, }; @@ -166,10 +163,9 @@ fn record_proof_works() { } .into_signed_tx(); - let block_id = BlockId::Hash(client.chain_info().best_hash); // Build the block and record proof let mut builder = client - .new_block_at(&block_id, Default::default(), true) + .new_block_at(client.chain_info().best_hash, Default::default(), true) .expect("Creates block builder"); builder.push(transaction.clone()).unwrap(); let (block, _, proof) = builder.build().expect("Bake block").into_inner(); diff --git a/test-utils/runtime/client/src/trait_tests.rs b/test-utils/runtime/client/src/trait_tests.rs index 19772c8c94067..7ec56635e2d03 100644 --- a/test-utils/runtime/client/src/trait_tests.rs +++ b/test-utils/runtime/client/src/trait_tests.rs @@ -32,7 +32,7 @@ use sc_client_api::{ blockchain::{Backend as BlockChainBackendT, HeaderBackend}, }; use sp_consensus::BlockOrigin; -use sp_runtime::{generic::BlockId, traits::Block as BlockT}; +use sp_runtime::traits::Block as BlockT; use substrate_test_runtime::{self, Transfer}; /// helper to test the `leaves` implementation for various backends @@ -60,7 +60,7 @@ where // A1 -> A2 let a2 = client - .new_block_at(&BlockId::Hash(a1.hash()), Default::default(), false) + .new_block_at(a1.hash(), Default::default(), false) .unwrap() .build() .unwrap() @@ -71,7 +71,7 @@ where // A2 -> A3 let a3 = client - .new_block_at(&BlockId::Hash(a2.hash()), Default::default(), false) + .new_block_at(a2.hash(), Default::default(), false) .unwrap() .build() .unwrap() @@ -82,7 +82,7 @@ where // A3 -> A4 let a4 = client - .new_block_at(&BlockId::Hash(a3.hash()), Default::default(), false) + .new_block_at(a3.hash(), Default::default(), false) .unwrap() .build() .unwrap() @@ -92,7 +92,7 @@ where // A4 -> A5 let a5 = client - .new_block_at(&BlockId::Hash(a4.hash()), Default::default(), false) + .new_block_at(a4.hash(), Default::default(), false) .unwrap() .build() .unwrap() @@ -102,9 +102,7 @@ where assert_eq!(blockchain.leaves().unwrap(), vec![a5.hash()]); // A1 -> B2 - let mut builder = client - .new_block_at(&BlockId::Hash(a1.hash()), Default::default(), false) - .unwrap(); + let mut builder = client.new_block_at(a1.hash(), Default::default(), false).unwrap(); // this push is required as otherwise B2 has the same hash as A2 and won't get imported builder @@ -121,7 +119,7 @@ where // B2 -> B3 let b3 = client - .new_block_at(&BlockId::Hash(b2.hash()), Default::default(), false) + .new_block_at(b2.hash(), Default::default(), false) .unwrap() .build() .unwrap() @@ -132,7 +130,7 @@ where // B3 -> B4 let b4 = client - .new_block_at(&BlockId::Hash(b3.hash()), Default::default(), false) + .new_block_at(b3.hash(), Default::default(), false) .unwrap() .build() .unwrap() @@ -141,9 +139,7 @@ where assert_eq!(blockchain.leaves().unwrap(), vec![a5.hash(), b4.hash()]); // // B2 -> C3 - let mut builder = client - .new_block_at(&BlockId::Hash(b2.hash()), Default::default(), false) - .unwrap(); + let mut builder = client.new_block_at(b2.hash(), Default::default(), false).unwrap(); // this push is required as otherwise C3 has the same hash as B3 and won't get imported builder .push_transfer(Transfer { @@ -158,9 +154,7 @@ where assert_eq!(blockchain.leaves().unwrap(), vec![a5.hash(), b4.hash(), c3.hash()]); // A1 -> D2 - let mut builder = client - .new_block_at(&BlockId::Hash(a1.hash()), Default::default(), false) - .unwrap(); + let mut builder = client.new_block_at(a1.hash(), Default::default(), false).unwrap(); // this push is required as otherwise D2 has the same hash as B2 and won't get imported builder .push_transfer(Transfer { @@ -195,7 +189,7 @@ where // A1 -> A2 let a2 = client - .new_block_at(&BlockId::Hash(a1.hash()), Default::default(), false) + .new_block_at(a1.hash(), Default::default(), false) .unwrap() .build() .unwrap() @@ -204,7 +198,7 @@ where // A2 -> A3 let a3 = client - .new_block_at(&BlockId::Hash(a2.hash()), Default::default(), false) + .new_block_at(a2.hash(), Default::default(), false) .unwrap() .build() .unwrap() @@ -213,7 +207,7 @@ where // A3 -> A4 let a4 = client - .new_block_at(&BlockId::Hash(a3.hash()), Default::default(), false) + .new_block_at(a3.hash(), Default::default(), false) .unwrap() .build() .unwrap() @@ -222,7 +216,7 @@ where // A4 -> A5 let a5 = client - .new_block_at(&BlockId::Hash(a4.hash()), Default::default(), false) + .new_block_at(a4.hash(), Default::default(), false) .unwrap() .build() .unwrap() @@ -230,9 +224,7 @@ where block_on(client.import(BlockOrigin::Own, a5.clone())).unwrap(); // A1 -> B2 - let mut builder = client - .new_block_at(&BlockId::Hash(a1.hash()), Default::default(), false) - .unwrap(); + let mut builder = client.new_block_at(a1.hash(), Default::default(), false).unwrap(); // this push is required as otherwise B2 has the same hash as A2 and won't get imported builder .push_transfer(Transfer { @@ -247,7 +239,7 @@ where // B2 -> B3 let b3 = client - .new_block_at(&BlockId::Hash(b2.hash()), Default::default(), false) + .new_block_at(b2.hash(), Default::default(), false) .unwrap() .build() .unwrap() @@ -256,7 +248,7 @@ where // B3 -> B4 let b4 = client - .new_block_at(&BlockId::Hash(b3.hash()), Default::default(), false) + .new_block_at(b3.hash(), Default::default(), false) .unwrap() .build() .unwrap() @@ -264,9 +256,7 @@ where block_on(client.import(BlockOrigin::Own, b4)).unwrap(); // // B2 -> C3 - let mut builder = client - .new_block_at(&BlockId::Hash(b2.hash()), Default::default(), false) - .unwrap(); + let mut builder = client.new_block_at(b2.hash(), Default::default(), false).unwrap(); // this push is required as otherwise C3 has the same hash as B3 and won't get imported builder .push_transfer(Transfer { @@ -280,9 +270,7 @@ where block_on(client.import(BlockOrigin::Own, c3.clone())).unwrap(); // A1 -> D2 - let mut builder = client - .new_block_at(&BlockId::Hash(a1.hash()), Default::default(), false) - .unwrap(); + let mut builder = client.new_block_at(a1.hash(), Default::default(), false).unwrap(); // this push is required as otherwise D2 has the same hash as B2 and won't get imported builder .push_transfer(Transfer { @@ -328,7 +316,7 @@ where // A1 -> A2 let a2 = client - .new_block_at(&BlockId::Hash(a1.hash()), Default::default(), false) + .new_block_at(a1.hash(), Default::default(), false) .unwrap() .build() .unwrap() @@ -337,7 +325,7 @@ where // A2 -> A3 let a3 = client - .new_block_at(&BlockId::Hash(a2.hash()), Default::default(), false) + .new_block_at(a2.hash(), Default::default(), false) .unwrap() .build() .unwrap() @@ -346,7 +334,7 @@ where // A3 -> A4 let a4 = client - .new_block_at(&BlockId::Hash(a3.hash()), Default::default(), false) + .new_block_at(a3.hash(), Default::default(), false) .unwrap() .build() .unwrap() @@ -355,7 +343,7 @@ where // A4 -> A5 let a5 = client - .new_block_at(&BlockId::Hash(a4.hash()), Default::default(), false) + .new_block_at(a4.hash(), Default::default(), false) .unwrap() .build() .unwrap() @@ -363,9 +351,7 @@ where block_on(client.import(BlockOrigin::Own, a5.clone())).unwrap(); // A1 -> B2 - let mut builder = client - .new_block_at(&BlockId::Hash(a1.hash()), Default::default(), false) - .unwrap(); + let mut builder = client.new_block_at(a1.hash(), Default::default(), false).unwrap(); // this push is required as otherwise B2 has the same hash as A2 and won't get imported builder .push_transfer(Transfer { @@ -380,7 +366,7 @@ where // B2 -> B3 let b3 = client - .new_block_at(&BlockId::Hash(b2.hash()), Default::default(), false) + .new_block_at(b2.hash(), Default::default(), false) .unwrap() .build() .unwrap() @@ -389,7 +375,7 @@ where // B3 -> B4 let b4 = client - .new_block_at(&BlockId::Hash(b3.hash()), Default::default(), false) + .new_block_at(b3.hash(), Default::default(), false) .unwrap() .build() .unwrap() @@ -397,9 +383,7 @@ where block_on(client.import(BlockOrigin::Own, b4)).unwrap(); // // B2 -> C3 - let mut builder = client - .new_block_at(&BlockId::Hash(b2.hash()), Default::default(), false) - .unwrap(); + let mut builder = client.new_block_at(b2.hash(), Default::default(), false).unwrap(); // this push is required as otherwise C3 has the same hash as B3 and won't get imported builder .push_transfer(Transfer { @@ -413,9 +397,7 @@ where block_on(client.import(BlockOrigin::Own, c3)).unwrap(); // A1 -> D2 - let mut builder = client - .new_block_at(&BlockId::Hash(a1.hash()), Default::default(), false) - .unwrap(); + let mut builder = client.new_block_at(a1.hash(), Default::default(), false).unwrap(); // this push is required as otherwise D2 has the same hash as B2 and won't get imported builder .push_transfer(Transfer { From e374a33fe1d99d59eb24a08981090bdb4503e81b Mon Sep 17 00:00:00 2001 From: Vivek Pandya Date: Wed, 22 Feb 2023 00:16:41 +0530 Subject: [PATCH 422/715] Remove years from copyright notes. (#13415) * Change copyright year to 2023 from 2022 * Fix incorrect update of copyright year * Remove years from copy right header * Fix remaining files * Fix typo in a header and remove update-copyright.sh --- .maintain/update-copyright.sh | 14 -------------- 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/benchmarking.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/benchmark_block_works.rs | 2 +- bin/node/cli/tests/benchmark_extrinsic_works.rs | 2 +- bin/node/cli/tests/benchmark_machine_works.rs | 2 +- bin/node/cli/tests/benchmark_overhead_works.rs | 2 +- bin/node/cli/tests/benchmark_pallet_works.rs | 2 +- bin/node/cli/tests/benchmark_storage_works.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/remember_state_pruning_works.rs | 2 +- .../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/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/notifications/registry.rs | 2 +- client/api/src/notifications/tests.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 +- .../authority-discovery/src/worker/addr_cache.rs | 2 +- .../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/aux_schema.rs | 2 +- client/beefy/src/communication/gossip.rs | 2 +- client/beefy/src/communication/mod.rs | 2 +- client/beefy/src/communication/notification.rs | 2 +- client/beefy/src/communication/peers.rs | 2 +- .../request_response/incoming_requests_handler.rs | 2 +- .../src/communication/request_response/mod.rs | 2 +- .../request_response/outgoing_requests_engine.rs | 2 +- client/beefy/src/error.rs | 2 +- client/beefy/src/import.rs | 2 +- client/beefy/src/justification.rs | 2 +- client/beefy/src/keystore.rs | 2 +- client/beefy/src/lib.rs | 2 +- client/beefy/src/metrics.rs | 2 +- client/beefy/src/round.rs | 2 +- client/beefy/src/tests.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/chain_info_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/test/mod.rs | 2 +- client/cli/src/commands/test/sig_verify.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/message_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 +- .../common/src/import_queue/basic_queue.rs | 2 +- .../common/src/import_queue/buffered_link.rs | 2 +- client/consensus/common/src/import_queue/mock.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/aura.rs | 2 +- client/consensus/manual-seal/src/consensus/babe.rs | 2 +- .../manual-seal/src/consensus/timestamp.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/db/benches/state_access.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/pinned_blocks_cache.rs | 2 +- client/db/src/record_stats_state.rs | 2 +- client/db/src/stats.rs | 2 +- client/db/src/upgrade.rs | 2 +- client/db/src/utils.rs | 2 +- client/executor/benches/bench.rs | 2 +- client/executor/common/src/error.rs | 2 +- client/executor/common/src/lib.rs | 2 +- .../src/runtime_blob/data_segments_snapshot.rs | 2 +- .../common/src/runtime_blob/globals_snapshot.rs | 2 +- client/executor/common/src/runtime_blob/mod.rs | 2 +- .../common/src/runtime_blob/runtime_blob.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 +- .../executor/src/integration_tests/linux/smaps.rs | 2 +- client/executor/src/integration_tests/mod.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 +- .../finality-grandpa/src/communication/gossip.rs | 2 +- client/finality-grandpa/src/communication/mod.rs | 2 +- .../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/finality-grandpa/src/warp_proof.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/merkle-mountain-range/rpc/src/lib.rs | 2 +- client/merkle-mountain-range/src/aux_schema.rs | 2 +- client/merkle-mountain-range/src/lib.rs | 2 +- client/merkle-mountain-range/src/offchain_mmr.rs | 2 +- client/merkle-mountain-range/src/test_utils.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/bitswap/src/lib.rs | 2 +- client/network/bitswap/src/schema.rs | 2 +- client/network/common/src/config.rs | 2 +- client/network/common/src/error.rs | 2 +- client/network/common/src/lib.rs | 2 +- client/network/common/src/message.rs | 2 +- client/network/common/src/protocol.rs | 2 +- client/network/common/src/protocol/event.rs | 2 +- client/network/common/src/protocol/role.rs | 2 +- client/network/common/src/request_responses.rs | 2 +- client/network/common/src/service.rs | 2 +- client/network/common/src/service/signature.rs | 2 +- client/network/common/src/sync.rs | 2 +- client/network/common/src/sync/message.rs | 2 +- client/network/common/src/sync/metrics.rs | 2 +- client/network/common/src/sync/warp.rs | 2 +- client/network/common/src/utils.rs | 2 +- client/network/light/src/lib.rs | 2 +- client/network/light/src/light_client_requests.rs | 2 +- .../light/src/light_client_requests/handler.rs | 2 +- client/network/light/src/schema.rs | 2 +- client/network/src/behaviour.rs | 2 +- client/network/src/config.rs | 2 +- client/network/src/discovery.rs | 2 +- client/network/src/lib.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/message.rs | 2 +- client/network/src/protocol/notifications.rs | 2 +- .../src/protocol/notifications/behaviour.rs | 2 +- .../network/src/protocol/notifications/handler.rs | 2 +- client/network/src/protocol/notifications/tests.rs | 2 +- .../network/src/protocol/notifications/upgrade.rs | 2 +- .../src/protocol/notifications/upgrade/collec.rs | 2 +- .../notifications/upgrade/notifications.rs | 2 +- client/network/src/request_responses.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/tests/chain_sync.rs | 2 +- client/network/src/service/tests/mod.rs | 2 +- client/network/src/service/tests/service.rs | 2 +- client/network/src/transport.rs | 2 +- client/network/sync/src/block_request_handler.rs | 2 +- client/network/sync/src/blocks.rs | 2 +- client/network/sync/src/extra_requests.rs | 2 +- client/network/sync/src/lib.rs | 2 +- client/network/sync/src/mock.rs | 2 +- client/network/sync/src/schema.rs | 2 +- client/network/sync/src/service/chain_sync.rs | 2 +- client/network/sync/src/service/mock.rs | 2 +- client/network/sync/src/service/mod.rs | 2 +- client/network/sync/src/service/network.rs | 2 +- client/network/sync/src/state.rs | 2 +- client/network/sync/src/state_request_handler.rs | 2 +- client/network/sync/src/tests.rs | 2 +- client/network/sync/src/warp.rs | 2 +- client/network/sync/src/warp_request_handler.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/network/transactions/src/config.rs | 2 +- client/network/transactions/src/lib.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/dev/error.rs | 2 +- client/rpc-api/src/dev/mod.rs | 2 +- client/rpc-api/src/lib.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-spec-v2/src/chain_head/api.rs | 2 +- client/rpc-spec-v2/src/chain_head/chain_head.rs | 2 +- client/rpc-spec-v2/src/chain_head/error.rs | 2 +- client/rpc-spec-v2/src/chain_head/event.rs | 2 +- client/rpc-spec-v2/src/chain_head/mod.rs | 2 +- client/rpc-spec-v2/src/chain_head/subscription.rs | 2 +- client/rpc-spec-v2/src/chain_spec/api.rs | 2 +- client/rpc-spec-v2/src/chain_spec/chain_spec.rs | 2 +- client/rpc-spec-v2/src/chain_spec/mod.rs | 2 +- client/rpc-spec-v2/src/chain_spec/tests.rs | 2 +- client/rpc-spec-v2/src/lib.rs | 2 +- client/rpc-spec-v2/src/transaction/api.rs | 2 +- client/rpc-spec-v2/src/transaction/error.rs | 2 +- client/rpc-spec-v2/src/transaction/event.rs | 2 +- client/rpc-spec-v2/src/transaction/mod.rs | 2 +- client/rpc-spec-v2/src/transaction/transaction.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/dev/mod.rs | 2 +- client/rpc/src/dev/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/state/utils.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 +- .../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/storage-monitor/src/lib.rs | 2 +- client/sync-state-rpc/src/lib.rs | 2 +- client/sysinfo/build.rs | 2 +- client/sysinfo/src/lib.rs | 2 +- client/sysinfo/src/sysinfo.rs | 2 +- client/sysinfo/src/sysinfo_linux.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/block/mod.rs | 2 +- client/tracing/src/lib.rs | 2 +- client/tracing/src/logging/directives.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/enactment_state.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 +- .../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/src/tests.rs | 2 +- client/transaction-pool/tests/pool.rs | 2 +- client/utils/src/id_sequence.rs | 2 +- client/utils/src/lib.rs | 2 +- client/utils/src/metrics.rs | 2 +- client/utils/src/mpsc.rs | 2 +- client/utils/src/notification.rs | 2 +- client/utils/src/notification/registry.rs | 2 +- client/utils/src/notification/tests.rs | 2 +- client/utils/src/pubsub.rs | 2 +- client/utils/src/pubsub/tests.rs | 2 +- client/utils/src/pubsub/tests/normal_operation.rs | 2 +- .../utils/src/pubsub/tests/panicking_registry.rs | 2 +- client/utils/src/status_sinks.rs | 2 +- frame/alliance/src/benchmarking.rs | 2 +- frame/alliance/src/lib.rs | 2 +- frame/alliance/src/migration.rs | 2 +- frame/alliance/src/mock.rs | 2 +- frame/alliance/src/tests.rs | 2 +- frame/alliance/src/types.rs | 2 +- frame/alliance/src/weights.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/migration.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/remote-tests/src/migration.rs | 2 +- frame/bags-list/remote-tests/src/snapshot.rs | 2 +- frame/bags-list/remote-tests/src/try_state.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/migration.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/src/lib.rs | 2 +- frame/beefy-mmr/src/mock.rs | 2 +- frame/beefy-mmr/src/tests.rs | 2 +- frame/beefy/src/default_weights.rs | 2 +- frame/beefy/src/equivocation.rs | 2 +- frame/beefy/src/lib.rs | 2 +- frame/beefy/src/mock.rs | 2 +- frame/beefy/src/tests.rs | 2 +- frame/benchmarking/pov/src/benchmarking.rs | 2 +- frame/benchmarking/pov/src/lib.rs | 2 +- frame/benchmarking/pov/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/v1.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/primitives/src/lib.rs | 2 +- frame/contracts/proc-macro/src/lib.rs | 2 +- frame/contracts/src/address.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/mod.rs | 2 +- frame/contracts/src/wasm/prepare.rs | 2 +- frame/contracts/src/wasm/runtime.rs | 2 +- frame/contracts/src/weights.rs | 2 +- frame/conviction-voting/src/benchmarking.rs | 2 +- frame/conviction-voting/src/conviction.rs | 2 +- frame/conviction-voting/src/lib.rs | 2 +- frame/conviction-voting/src/tests.rs | 2 +- frame/conviction-voting/src/types.rs | 2 +- frame/conviction-voting/src/vote.rs | 2 +- frame/conviction-voting/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/migrations.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/metadata.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 +- .../src/benchmarking.rs | 2 +- frame/election-provider-multi-phase/src/helpers.rs | 2 +- frame/election-provider-multi-phase/src/lib.rs | 2 +- .../src/migrations.rs | 2 +- frame/election-provider-multi-phase/src/mock.rs | 2 +- frame/election-provider-multi-phase/src/signed.rs | 2 +- .../election-provider-multi-phase/src/unsigned.rs | 2 +- frame/election-provider-multi-phase/src/weights.rs | 2 +- .../benchmarking/src/lib.rs | 2 +- .../solution-type/src/codec.rs | 2 +- .../solution-type/src/from_assignment_helpers.rs | 2 +- .../solution-type/src/index_assignment.rs | 2 +- .../solution-type/src/lib.rs | 2 +- .../solution-type/src/single_page.rs | 2 +- frame/election-provider-support/src/lib.rs | 2 +- frame/election-provider-support/src/mock.rs | 2 +- frame/election-provider-support/src/onchain.rs | 2 +- frame/election-provider-support/src/tests.rs | 2 +- frame/election-provider-support/src/traits.rs | 2 +- frame/election-provider-support/src/weights.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/executive/src/lib.rs | 2 +- frame/fast-unstake/src/benchmarking.rs | 2 +- frame/fast-unstake/src/lib.rs | 2 +- frame/fast-unstake/src/migrations.rs | 2 +- frame/fast-unstake/src/mock.rs | 2 +- frame/fast-unstake/src/tests.rs | 2 +- frame/fast-unstake/src/types.rs | 2 +- frame/fast-unstake/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 +- .../insecure-randomness-collective-flip/src/lib.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/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/mock.rs | 2 +- frame/merkle-mountain-range/src/tests.rs | 2 +- frame/message-queue/src/benchmarking.rs | 2 +- frame/message-queue/src/integration_test.rs | 2 +- frame/message-queue/src/lib.rs | 2 +- frame/message-queue/src/mock.rs | 2 +- frame/message-queue/src/mock_helpers.rs | 2 +- frame/message-queue/src/tests.rs | 2 +- frame/message-queue/src/weights.rs | 2 +- frame/multisig/src/benchmarking.rs | 2 +- frame/multisig/src/lib.rs | 2 +- frame/multisig/src/migrations.rs | 2 +- frame/multisig/src/tests.rs | 2 +- frame/multisig/src/weights.rs | 2 +- frame/nfts/src/benchmarking.rs | 2 +- frame/nfts/src/common_functions.rs | 2 +- frame/nfts/src/features/approvals.rs | 2 +- frame/nfts/src/features/atomic_swap.rs | 2 +- frame/nfts/src/features/attributes.rs | 2 +- frame/nfts/src/features/buy_sell.rs | 2 +- .../nfts/src/features/create_delete_collection.rs | 2 +- frame/nfts/src/features/create_delete_item.rs | 2 +- frame/nfts/src/features/lock.rs | 2 +- frame/nfts/src/features/metadata.rs | 2 +- frame/nfts/src/features/mod.rs | 2 +- frame/nfts/src/features/roles.rs | 2 +- frame/nfts/src/features/settings.rs | 2 +- frame/nfts/src/features/transfer.rs | 2 +- frame/nfts/src/impl_nonfungibles.rs | 2 +- frame/nfts/src/lib.rs | 2 +- frame/nfts/src/macros.rs | 2 +- frame/nfts/src/mock.rs | 2 +- frame/nfts/src/tests.rs | 2 +- frame/nfts/src/types.rs | 2 +- frame/nfts/src/weights.rs | 2 +- frame/nicks/src/lib.rs | 2 +- frame/nis/src/benchmarking.rs | 2 +- frame/nis/src/lib.rs | 2 +- frame/nis/src/mock.rs | 2 +- frame/nis/src/tests.rs | 2 +- frame/nis/src/weights.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/nomination-pools/benchmarking/src/lib.rs | 2 +- frame/nomination-pools/benchmarking/src/mock.rs | 2 +- frame/nomination-pools/fuzzer/src/call.rs | 2 +- frame/nomination-pools/runtime-api/src/lib.rs | 2 +- frame/nomination-pools/src/lib.rs | 2 +- frame/nomination-pools/src/migration.rs | 2 +- frame/nomination-pools/src/tests.rs | 2 +- frame/nomination-pools/src/weights.rs | 2 +- frame/nomination-pools/test-staking/src/lib.rs | 2 +- frame/nomination-pools/test-staking/src/mock.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/migration.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/ranked-collective/src/benchmarking.rs | 2 +- frame/ranked-collective/src/lib.rs | 2 +- frame/ranked-collective/src/tests.rs | 2 +- frame/ranked-collective/src/weights.rs | 2 +- frame/recovery/src/benchmarking.rs | 2 +- frame/recovery/src/lib.rs | 2 +- frame/recovery/src/mock.rs | 2 +- frame/recovery/src/tests.rs | 2 +- frame/recovery/src/weights.rs | 2 +- frame/referenda/src/benchmarking.rs | 2 +- frame/referenda/src/branch.rs | 2 +- frame/referenda/src/lib.rs | 2 +- frame/referenda/src/migration.rs | 2 +- frame/referenda/src/mock.rs | 2 +- frame/referenda/src/tests.rs | 2 +- frame/referenda/src/types.rs | 2 +- frame/referenda/src/weights.rs | 2 +- frame/remark/src/benchmarking.rs | 2 +- frame/remark/src/lib.rs | 2 +- frame/remark/src/mock.rs | 2 +- frame/remark/src/tests.rs | 2 +- frame/remark/src/weights.rs | 2 +- frame/root-offences/src/lib.rs | 2 +- frame/root-offences/src/mock.rs | 2 +- frame/root-offences/src/tests.rs | 2 +- frame/root-testing/src/lib.rs | 2 +- frame/scheduler/src/benchmarking.rs | 2 +- frame/scheduler/src/lib.rs | 2 +- frame/scheduler/src/migration.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/state-trie-migration/src/lib.rs | 2 +- frame/state-trie-migration/src/weights.rs | 2 +- frame/sudo/src/extension.rs | 2 +- frame/sudo/src/lib.rs | 2 +- frame/sudo/src/mock.rs | 2 +- frame/sudo/src/tests.rs | 2 +- frame/support/procedural/src/benchmark.rs | 2 +- frame/support/procedural/src/clone_no_bound.rs | 2 +- .../src/construct_runtime/expand/call.rs | 2 +- .../src/construct_runtime/expand/config.rs | 2 +- .../src/construct_runtime/expand/event.rs | 2 +- .../src/construct_runtime/expand/inherent.rs | 2 +- .../src/construct_runtime/expand/metadata.rs | 2 +- .../procedural/src/construct_runtime/expand/mod.rs | 2 +- .../src/construct_runtime/expand/origin.rs | 2 +- .../src/construct_runtime/expand/unsigned.rs | 2 +- .../procedural/src/construct_runtime/mod.rs | 2 +- .../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 +- .../support/procedural/src/pallet/expand/config.rs | 2 +- .../procedural/src/pallet/expand/constants.rs | 2 +- .../support/procedural/src/pallet/expand/error.rs | 2 +- .../support/procedural/src/pallet/expand/event.rs | 2 +- .../procedural/src/pallet/expand/genesis_build.rs | 2 +- .../procedural/src/pallet/expand/genesis_config.rs | 2 +- .../support/procedural/src/pallet/expand/hooks.rs | 2 +- .../procedural/src/pallet/expand/inherent.rs | 2 +- .../procedural/src/pallet/expand/instances.rs | 2 +- frame/support/procedural/src/pallet/expand/mod.rs | 2 +- .../support/procedural/src/pallet/expand/origin.rs | 2 +- .../procedural/src/pallet/expand/pallet_struct.rs | 2 +- .../procedural/src/pallet/expand/storage.rs | 2 +- .../procedural/src/pallet/expand/store_trait.rs | 2 +- .../src/pallet/expand/tt_default_parts.rs | 2 +- .../procedural/src/pallet/expand/type_value.rs | 2 +- .../src/pallet/expand/validate_unsigned.rs | 2 +- frame/support/procedural/src/pallet/mod.rs | 2 +- frame/support/procedural/src/pallet/parse/call.rs | 2 +- .../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 +- .../procedural/src/pallet/parse/extra_constants.rs | 2 +- .../procedural/src/pallet/parse/genesis_build.rs | 2 +- .../procedural/src/pallet/parse/genesis_config.rs | 2 +- .../support/procedural/src/pallet/parse/helper.rs | 2 +- frame/support/procedural/src/pallet/parse/hooks.rs | 2 +- .../procedural/src/pallet/parse/inherent.rs | 2 +- frame/support/procedural/src/pallet/parse/mod.rs | 2 +- .../support/procedural/src/pallet/parse/origin.rs | 2 +- .../procedural/src/pallet/parse/pallet_struct.rs | 2 +- .../support/procedural/src/pallet/parse/storage.rs | 2 +- .../procedural/src/pallet/parse/type_value.rs | 2 +- .../src/pallet/parse/validate_unsigned.rs | 2 +- frame/support/procedural/src/pallet_error.rs | 2 +- .../support/procedural/src/partial_eq_no_bound.rs | 2 +- .../src/storage/genesis_config/builder_def.rs | 2 +- .../storage/genesis_config/genesis_config_def.rs | 2 +- .../procedural/src/storage/genesis_config/mod.rs | 2 +- frame/support/procedural/src/storage/getters.rs | 2 +- .../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 +- .../support/procedural/src/storage/storage_info.rs | 2 +- .../procedural/src/storage/storage_struct.rs | 2 +- .../support/procedural/src/storage/store_trait.rs | 2 +- frame/support/procedural/src/storage_alias.rs | 2 +- frame/support/procedural/src/transactional.rs | 2 +- frame/support/procedural/src/tt_macro.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/crypto.rs | 2 +- frame/support/src/crypto/ecdsa.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/storage_noop_guard.rs | 2 +- frame/support/src/storage/stream_iter.rs | 2 +- frame/support/src/storage/transactional.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/error.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/messages.rs | 2 +- frame/support/src/traits/metadata.rs | 2 +- frame/support/src/traits/misc.rs | 2 +- frame/support/src/traits/preimages.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 +- .../support/src/traits/tokens/currency/lockable.rs | 2 +- .../src/traits/tokens/currency/reservable.rs | 2 +- frame/support/src/traits/tokens/fungible.rs | 2 +- .../support/src/traits/tokens/fungible/balanced.rs | 2 +- .../src/traits/tokens/fungible/imbalance.rs | 2 +- frame/support/src/traits/tokens/fungibles.rs | 2 +- .../src/traits/tokens/fungibles/approvals.rs | 2 +- .../src/traits/tokens/fungibles/balanced.rs | 2 +- .../src/traits/tokens/fungibles/enumerable.rs | 2 +- .../src/traits/tokens/fungibles/imbalance.rs | 2 +- .../src/traits/tokens/fungibles/metadata.rs | 2 +- frame/support/src/traits/tokens/fungibles/roles.rs | 2 +- frame/support/src/traits/tokens/imbalance.rs | 2 +- .../src/traits/tokens/imbalance/on_unbalanced.rs | 2 +- .../traits/tokens/imbalance/signed_imbalance.rs | 2 +- .../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/nonfungible_v2.rs | 2 +- frame/support/src/traits/tokens/nonfungibles.rs | 2 +- frame/support/src/traits/tokens/nonfungibles_v2.rs | 2 +- frame/support/src/traits/try_runtime.rs | 2 +- frame/support/src/traits/validation.rs | 2 +- frame/support/src/traits/voting.rs | 2 +- frame/support/src/weights.rs | 2 +- frame/support/src/weights/block_weights.rs | 2 +- frame/support/src/weights/extrinsic_weights.rs | 2 +- frame/support/src/weights/paritydb_weights.rs | 2 +- frame/support/src/weights/rocksdb_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/benchmark_ui.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 +- .../test/tests/decl_storage_ui/config_duplicate.rs | 2 +- .../tests/decl_storage_ui/config_get_duplicate.rs | 2 +- .../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/origin.rs | 2 +- frame/support/test/tests/pallet.rs | 2 +- frame/support/test/tests/pallet_compatibility.rs | 2 +- .../test/tests/pallet_compatibility_instance.rs | 2 +- frame/support/test/tests/pallet_instance.rs | 2 +- frame/support/test/tests/pallet_ui.rs | 2 +- .../test/tests/pallet_with_name_trait_is_valid.rs | 2 +- frame/support/test/tests/storage_alias_ui.rs | 2 +- frame/support/test/tests/storage_layers.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 +- .../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/mock.rs | 2 +- frame/timestamp/src/tests.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 +- .../asset-tx-payment/src/lib.rs | 2 +- .../asset-tx-payment/src/mock.rs | 2 +- .../asset-tx-payment/src/payment.rs | 2 +- .../asset-tx-payment/src/tests.rs | 2 +- .../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/mock.rs | 2 +- frame/transaction-payment/src/tests.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 +- frame/whitelist/src/benchmarking.rs | 2 +- frame/whitelist/src/lib.rs | 2 +- frame/whitelist/src/mock.rs | 2 +- frame/whitelist/src/tests.rs | 2 +- frame/whitelist/src/weights.rs | 2 +- primitives/api/proc-macro/src/common.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 +- .../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 +- .../src/multiply_by_rational_with_rounding.rs | 2 +- primitives/arithmetic/fuzzer/src/normalize.rs | 2 +- .../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/beefy/src/commitment.rs | 2 +- primitives/beefy/src/lib.rs | 2 +- primitives/beefy/src/mmr.rs | 2 +- primitives/beefy/src/payload.rs | 2 +- primitives/beefy/src/test_utils.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 +- .../consensus/common/src/block_validation.rs | 2 +- primitives/consensus/common/src/error.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/benches/bench.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/bounded.rs | 2 +- primitives/core/src/crypto.rs | 2 +- primitives/core/src/defer.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/sr25519.rs | 2 +- primitives/core/src/testing.rs | 2 +- primitives/core/src/traits.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/merkle-mountain-range/src/lib.rs | 2 +- primitives/merkle-mountain-range/src/utils.rs | 2 +- primitives/npos-elections/fuzzer/src/common.rs | 2 +- .../fuzzer/src/phragmen_balancing.rs | 2 +- .../npos-elections/fuzzer/src/phragmen_pjr.rs | 2 +- .../fuzzer/src/phragmms_balancing.rs | 2 +- primitives/npos-elections/fuzzer/src/reduce.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 | 3 ++- 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 +- .../proc-macro/src/pass_by/codec.rs | 2 +- .../proc-macro/src/pass_by/enum_.rs | 2 +- .../proc-macro/src/pass_by/inner.rs | 2 +- .../proc-macro/src/pass_by/mod.rs | 2 +- .../runtime_interface/bare_function_interface.rs | 2 +- .../runtime_interface/host_function_interface.rs | 2 +- .../proc-macro/src/runtime_interface/mod.rs | 2 +- .../src/runtime_interface/trait_decl_impl.rs | 2 +- .../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 +- .../test-wasm-deprecated/build.rs | 2 +- .../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 +- .../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 +- .../runtime/src/generic/unchecked_extrinsic.rs | 2 +- primitives/runtime/src/legacy.rs | 2 +- primitives/runtime/src/legacy/byte_sized_error.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/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 +- .../src/overlayed_changes/changeset.rs | 2 +- .../state-machine/src/overlayed_changes/mod.rs | 2 +- .../src/overlayed_changes/offchain.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 +- .../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/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/cache/mod.rs | 2 +- primitives/trie/src/cache/shared_cache.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/recorder.rs | 2 +- primitives/trie/src/storage_proof.rs | 2 +- primitives/trie/src/trie_codec.rs | 2 +- primitives/trie/src/trie_stream.rs | 2 +- .../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 +- primitives/weights/src/lib.rs | 2 +- primitives/weights/src/weight_meter.rs | 2 +- primitives/weights/src/weight_v2.rs | 2 +- scripts/run_all_benchmarks.sh | 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/tests/basic.rs | 2 +- test-utils/tests/ui.rs | 2 +- test-utils/tests/ui/too-many-func-parameters.rs | 2 +- utils/binary-merkle-tree/src/lib.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/build.rs | 2 +- utils/frame/benchmarking-cli/src/block/bench.rs | 2 +- utils/frame/benchmarking-cli/src/block/cmd.rs | 2 +- utils/frame/benchmarking-cli/src/block/mod.rs | 2 +- .../frame/benchmarking-cli/src/extrinsic/bench.rs | 2 +- utils/frame/benchmarking-cli/src/extrinsic/cmd.rs | 2 +- .../src/extrinsic/extrinsic_factory.rs | 2 +- utils/frame/benchmarking-cli/src/extrinsic/mod.rs | 2 +- utils/frame/benchmarking-cli/src/lib.rs | 2 +- .../frame/benchmarking-cli/src/machine/hardware.rs | 2 +- utils/frame/benchmarking-cli/src/machine/mod.rs | 2 +- utils/frame/benchmarking-cli/src/overhead/cmd.rs | 2 +- utils/frame/benchmarking-cli/src/overhead/mod.rs | 2 +- .../benchmarking-cli/src/overhead/template.rs | 2 +- utils/frame/benchmarking-cli/src/pallet/command.rs | 2 +- utils/frame/benchmarking-cli/src/pallet/mod.rs | 2 +- utils/frame/benchmarking-cli/src/pallet/writer.rs | 2 +- utils/frame/benchmarking-cli/src/shared/mod.rs | 2 +- utils/frame/benchmarking-cli/src/shared/record.rs | 2 +- utils/frame/benchmarking-cli/src/shared/stats.rs | 2 +- .../benchmarking-cli/src/shared/weight_params.rs | 2 +- utils/frame/benchmarking-cli/src/storage/cmd.rs | 2 +- utils/frame/benchmarking-cli/src/storage/mod.rs | 2 +- utils/frame/benchmarking-cli/src/storage/read.rs | 2 +- .../frame/benchmarking-cli/src/storage/template.rs | 2 +- utils/frame/benchmarking-cli/src/storage/write.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/rpc/client/src/lib.rs | 2 +- .../frame/rpc/state-trie-migration-rpc/src/lib.rs | 2 +- utils/frame/rpc/support/src/lib.rs | 2 +- utils/frame/rpc/system/src/lib.rs | 2 +- .../try-runtime/cli/src/block_building_info.rs | 2 +- .../cli/src/commands/create_snapshot.rs | 2 +- .../try-runtime/cli/src/commands/execute_block.rs | 2 +- .../try-runtime/cli/src/commands/fast_forward.rs | 2 +- .../try-runtime/cli/src/commands/follow_chain.rs | 2 +- utils/frame/try-runtime/cli/src/commands/mod.rs | 2 +- .../cli/src/commands/offchain_worker.rs | 2 +- .../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/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 +- 1374 files changed, 1374 insertions(+), 1387 deletions(-) delete mode 100755 .maintain/update-copyright.sh diff --git a/.maintain/update-copyright.sh b/.maintain/update-copyright.sh deleted file mode 100755 index d67cab7c1e152..0000000000000 --- a/.maintain/update-copyright.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env bash - -SINGLE_DATES=$(grep -lr "// Copyright (C) [0-9]* Parity Technologies (UK) Ltd.") -YEAR=$(date +%Y) - -for file in $SINGLE_DATES; do - FILE_YEAR=$(cat $file | sed -n "s|// Copyright (C) \([[:digit:]][[:digit:]][[:digit:]][[:digit:]]\) Parity Technologies (UK) Ltd.|\1|p") - if [ $YEAR -ne $FILE_YEAR ]; then - sed -i -e "s|// Copyright (C) \([[:digit:]][[:digit:]][[:digit:]][[:digit:]]\) Parity Technologies (UK) Ltd.|// Copyright (C) \1-$YEAR Parity Technologies (UK) Ltd.|g" $file - fi -done - -grep -lr "// Copyright (C) [0-9]*-[0-9]* Parity Technologies (UK) Ltd." | - xargs sed -i -e "s|// Copyright (C) \([[:digit:]][[:digit:]][[:digit:]][[:digit:]]\)-[[:digit:]][[:digit:]][[:digit:]][[:digit:]] Parity Technologies (UK) Ltd.|// Copyright (C) \1-$YEAR Parity Technologies (UK) Ltd.|g" diff --git a/HEADER-APACHE2 b/HEADER-APACHE2 index 403497a86907f..ecd364a6d62e0 100644 --- a/HEADER-APACHE2 +++ b/HEADER-APACHE2 @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/HEADER-GPL3 b/HEADER-GPL3 index ed7daba723272..b46a8f75295fe 100644 --- a/HEADER-GPL3 +++ b/HEADER-GPL3 @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-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 839e26f9f6d13..46c9d0417fece 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/bench/src/construct.rs b/bin/node/bench/src/construct.rs index 529a3ba7a001e..ec2a829f692a6 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/bench/src/core.rs b/bin/node/bench/src/core.rs index b6ad3ecd80068..29cda70990aa0 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/bench/src/generator.rs b/bin/node/bench/src/generator.rs index 76bd3a3240c51..0fe0826028f5f 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/bench/src/import.rs b/bin/node/bench/src/import.rs index db93833c83200..167377ea9a220 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/bench/src/main.rs b/bin/node/bench/src/main.rs index 8a5d99640eb1b..051d8ddb9bf55 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/bench/src/simple_trie.rs b/bin/node/bench/src/simple_trie.rs index aa9c96a1cbd3f..6d5072358d239 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/bench/src/state_sizes.rs b/bin/node/bench/src/state_sizes.rs index 5387850666b6e..12e0f6eae1916 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/bench/src/tempdb.rs b/bin/node/bench/src/tempdb.rs index 82895ddfab69d..2aafd013a586a 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/bench/src/trie.rs b/bin/node/bench/src/trie.rs index de49a6fe7b6da..09ab405c03b23 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/bench/src/txpool.rs b/bin/node/bench/src/txpool.rs index 5b4d5513e2b5a..4e8e5c0d9a4fd 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/cli/benches/block_production.rs b/bin/node/cli/benches/block_production.rs index 64ea03f58289a..e4b48497e0f88 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/cli/benches/transaction_pool.rs b/bin/node/cli/benches/transaction_pool.rs index a8839642ddc26..165c67f602777 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/cli/bin/main.rs b/bin/node/cli/bin/main.rs index 3ae295754561c..4b434a3e6dad5 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/cli/build.rs b/bin/node/cli/build.rs index e8142b297f1b2..18860a1afafb7 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/cli/src/benchmarking.rs b/bin/node/cli/src/benchmarking.rs index 16ea9109d0c1f..333f855f2d7bb 100644 --- a/bin/node/cli/src/benchmarking.rs +++ b/bin/node/cli/src/benchmarking.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-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 1e4e806fd2736..178b97823fb2e 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/cli/src/cli.rs b/bin/node/cli/src/cli.rs index 7bea336c8e41a..35b949831141d 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/cli/src/command.rs b/bin/node/cli/src/command.rs index 4256c7d61f4fd..b38b25d8fb3ad 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/cli/src/lib.rs b/bin/node/cli/src/lib.rs index 13c074268e50f..2fe238ef316e6 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs index e0247079db4bc..7b1ab2c1ebc44 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/cli/tests/benchmark_block_works.rs b/bin/node/cli/tests/benchmark_block_works.rs index 65cb474ea88d6..369e1b3e52d87 100644 --- a/bin/node/cli/tests/benchmark_block_works.rs +++ b/bin/node/cli/tests/benchmark_block_works.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-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/benchmark_extrinsic_works.rs b/bin/node/cli/tests/benchmark_extrinsic_works.rs index 69800ad3c6c13..9cdb971def522 100644 --- a/bin/node/cli/tests/benchmark_extrinsic_works.rs +++ b/bin/node/cli/tests/benchmark_extrinsic_works.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-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/benchmark_machine_works.rs b/bin/node/cli/tests/benchmark_machine_works.rs index 193e6b701ec94..2cdadb64603ec 100644 --- a/bin/node/cli/tests/benchmark_machine_works.rs +++ b/bin/node/cli/tests/benchmark_machine_works.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-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/benchmark_overhead_works.rs b/bin/node/cli/tests/benchmark_overhead_works.rs index 44dcebfbc0c35..92ab93b7f6f26 100644 --- a/bin/node/cli/tests/benchmark_overhead_works.rs +++ b/bin/node/cli/tests/benchmark_overhead_works.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-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/benchmark_pallet_works.rs b/bin/node/cli/tests/benchmark_pallet_works.rs index bf29c0e308bcb..1a278f985da4f 100644 --- a/bin/node/cli/tests/benchmark_pallet_works.rs +++ b/bin/node/cli/tests/benchmark_pallet_works.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-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/benchmark_storage_works.rs b/bin/node/cli/tests/benchmark_storage_works.rs index 82d1c943ae7aa..1f1181218db03 100644 --- a/bin/node/cli/tests/benchmark_storage_works.rs +++ b/bin/node/cli/tests/benchmark_storage_works.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-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 aecabed60c849..dc5d36184f0c6 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/cli/tests/check_block_works.rs b/bin/node/cli/tests/check_block_works.rs index d4afc530bbcb3..019d97aa8228e 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/cli/tests/common.rs b/bin/node/cli/tests/common.rs index c8f9e2b3d3c82..a0de7300fca90 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/cli/tests/export_import_flow.rs b/bin/node/cli/tests/export_import_flow.rs index 750b4f7acc121..afee9ef70c15a 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/cli/tests/inspect_works.rs b/bin/node/cli/tests/inspect_works.rs index 849fb913a18d0..56569248befc0 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/cli/tests/purge_chain_works.rs b/bin/node/cli/tests/purge_chain_works.rs index 811762a714a9d..470c0a7e48fba 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/cli/tests/remember_state_pruning_works.rs b/bin/node/cli/tests/remember_state_pruning_works.rs index 5b8e34cc7a00d..b8c5ddf4a4864 100644 --- a/bin/node/cli/tests/remember_state_pruning_works.rs +++ b/bin/node/cli/tests/remember_state_pruning_works.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-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 6d4a4b40425c4..fc0bf69a099ba 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/cli/tests/telemetry.rs b/bin/node/cli/tests/telemetry.rs index 98cf0b3af32b2..633cc996ca615 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/cli/tests/temp_base_path_works.rs b/bin/node/cli/tests/temp_base_path_works.rs index 98422a21f5308..4e743f2d3abd4 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/cli/tests/version.rs b/bin/node/cli/tests/version.rs index f5a6f3a53d598..e239277c9b0ed 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/cli/tests/websocket_server.rs b/bin/node/cli/tests/websocket_server.rs index 1e7450995230c..432a4871cd378 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/executor/benches/bench.rs b/bin/node/executor/benches/bench.rs index 4cbd95471b86b..4154d1cffcf11 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/bin/node/executor/src/lib.rs b/bin/node/executor/src/lib.rs index c4edf5ad22f47..4e3ec9a0b34d5 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/bin/node/executor/tests/basic.rs b/bin/node/executor/tests/basic.rs index 02b2a8787b5d5..c19db5af50ee4 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/bin/node/executor/tests/common.rs b/bin/node/executor/tests/common.rs index 803ec78329eea..b428e32ea8b8d 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/bin/node/executor/tests/fees.rs b/bin/node/executor/tests/fees.rs index 3c696d595040b..cbf0fdce9476b 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/bin/node/executor/tests/submit_transaction.rs b/bin/node/executor/tests/submit_transaction.rs index be43f3c78674f..ab5df62a2e714 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/bin/node/inspect/src/cli.rs b/bin/node/inspect/src/cli.rs index fa6344ac346e9..c02a9c61d1ef6 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/inspect/src/command.rs b/bin/node/inspect/src/command.rs index ce164e0768fbc..3dca979eb9e4a 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/inspect/src/lib.rs b/bin/node/inspect/src/lib.rs index 3b9d7b2b1ff98..5764e0f05c172 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/primitives/src/lib.rs b/bin/node/primitives/src/lib.rs index feb9ee60d311b..e2fa5c3108149 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/bin/node/rpc/src/lib.rs b/bin/node/rpc/src/lib.rs index 0dc5ba4039b00..40e4de6b9dd62 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/bin/node/runtime/build.rs b/bin/node/runtime/build.rs index 70f84bc00a817..b7676a70dfe84 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/bin/node/runtime/src/constants.rs b/bin/node/runtime/src/constants.rs index 23fb13cfb0492..e4fafbf0fa479 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/bin/node/runtime/src/impls.rs b/bin/node/runtime/src/impls.rs index b3f58ea5d24ab..9c606ff075f39 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 0b887ff7d7a9f..8e924a9c52e3c 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/runtime/src/voter_bags.rs b/bin/node/runtime/src/voter_bags.rs index eb540c27abcc7..bf18097ddf53b 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) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/bin/node/testing/src/bench.rs b/bin/node/testing/src/bench.rs index f9bad2a561367..ccce6dc23cfeb 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/testing/src/client.rs b/bin/node/testing/src/client.rs index 590304bdd52a5..8594a4a2e2d32 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/testing/src/genesis.rs b/bin/node/testing/src/genesis.rs index b207fc7f98ab4..b8c80aeb116a9 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/testing/src/keyring.rs b/bin/node/testing/src/keyring.rs index 88d9dc56b0532..e16502bf17554 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/node/testing/src/lib.rs b/bin/node/testing/src/lib.rs index ce3471e5b1f83..14e540906fc91 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/utils/chain-spec-builder/build.rs b/bin/utils/chain-spec-builder/build.rs index b700b28e322ca..a68cb706e8fbd 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/utils/chain-spec-builder/src/main.rs b/bin/utils/chain-spec-builder/src/main.rs index 7dfcaed773f40..b3f28b269fddd 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/utils/subkey/src/lib.rs b/bin/utils/subkey/src/lib.rs index 280b90848fbf5..201d4d25f84ab 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/bin/utils/subkey/src/main.rs b/bin/utils/subkey/src/main.rs index 271388549bcf9..d836a9b8f8cc4 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/allocator/src/error.rs b/client/allocator/src/error.rs index d9fc483224adf..a3d91a3e2bacc 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/client/allocator/src/freeing_bump.rs b/client/allocator/src/freeing_bump.rs index e81d1b79e74ed..fdd63bd66aba8 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/client/allocator/src/lib.rs b/client/allocator/src/lib.rs index 2fe63a1ec392c..31179ab5ddede 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/client/api/src/backend.rs b/client/api/src/backend.rs index 4ef609bdd4525..bc799a418d5dc 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/api/src/call_executor.rs b/client/api/src/call_executor.rs index 74a2b8b8557c6..42d3c4e3422c4 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/api/src/client.rs b/client/api/src/client.rs index 8e7ceb68704b2..aeb119e0ef77a 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/api/src/execution_extensions.rs b/client/api/src/execution_extensions.rs index 58c085a29a945..b491d7672e8f0 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/api/src/in_mem.rs b/client/api/src/in_mem.rs index 5e82757e7d9cd..7096910e10b93 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/api/src/leaves.rs b/client/api/src/leaves.rs index cdcb80a110b74..a8a988771e2fd 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/api/src/lib.rs b/client/api/src/lib.rs index 3d21f12f6940b..0faddc10fe016 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/api/src/notifications.rs b/client/api/src/notifications.rs index 4dd23581d2622..c16cefe21da02 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/api/src/notifications/registry.rs b/client/api/src/notifications/registry.rs index 882d6ed40be67..10c6673110ad4 100644 --- a/client/api/src/notifications/registry.rs +++ b/client/api/src/notifications/registry.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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/tests.rs b/client/api/src/notifications/tests.rs index 2c728de7428dd..fba829b1cf902 100644 --- a/client/api/src/notifications/tests.rs +++ b/client/api/src/notifications/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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 01e35df1dec1c..7f60f856ae809 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/authority-discovery/src/error.rs b/client/authority-discovery/src/error.rs index 285a2714b81f5..89c05b71b9ea6 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/authority-discovery/src/interval.rs b/client/authority-discovery/src/interval.rs index 5ddf81fbccc34..23c7ce266e3bf 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/authority-discovery/src/lib.rs b/client/authority-discovery/src/lib.rs index db3802b168fe5..579b9d8b15051 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/authority-discovery/src/service.rs b/client/authority-discovery/src/service.rs index df09b6ea43216..89ae058d17f7a 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/authority-discovery/src/tests.rs b/client/authority-discovery/src/tests.rs index 208440b7ab1ea..982c3fc04c590 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/authority-discovery/src/worker.rs b/client/authority-discovery/src/worker.rs index 72a371cb6abe4..bc5fe2848d5a1 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/authority-discovery/src/worker/addr_cache.rs b/client/authority-discovery/src/worker/addr_cache.rs index 4859413a8cefd..8084b7f0a6dff 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/authority-discovery/src/worker/schema/tests.rs b/client/authority-discovery/src/worker/schema/tests.rs index 60147d6762e50..89c921e0c9fda 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/authority-discovery/src/worker/tests.rs b/client/authority-discovery/src/worker/tests.rs index 7f3d113a83448..22f984d9718ee 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/basic-authorship/src/basic_authorship.rs b/client/basic-authorship/src/basic_authorship.rs index f68a86ef12a39..376278fa1b6db 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/basic-authorship/src/lib.rs b/client/basic-authorship/src/lib.rs index e7f0d4496edeb..23a2120ac6204 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/beefy/rpc/src/lib.rs b/client/beefy/rpc/src/lib.rs index 4fea98c6eb24e..0a7a4de14cbcc 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/beefy/rpc/src/notification.rs b/client/beefy/rpc/src/notification.rs index a815425644d52..286385187c342 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/beefy/src/aux_schema.rs b/client/beefy/src/aux_schema.rs index 6e87956dac2db..2e99b4cc40638 100644 --- a/client/beefy/src/aux_schema.rs +++ b/client/beefy/src/aux_schema.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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/communication/gossip.rs b/client/beefy/src/communication/gossip.rs index 7e60eb11ea731..a1fb6fa26e5d4 100644 --- a/client/beefy/src/communication/gossip.rs +++ b/client/beefy/src/communication/gossip.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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/communication/mod.rs b/client/beefy/src/communication/mod.rs index 91798d4ae0d33..f91b08bbc97ec 100644 --- a/client/beefy/src/communication/mod.rs +++ b/client/beefy/src/communication/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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/communication/notification.rs b/client/beefy/src/communication/notification.rs index c673115e487f3..a4486e523c301 100644 --- a/client/beefy/src/communication/notification.rs +++ b/client/beefy/src/communication/notification.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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/communication/peers.rs b/client/beefy/src/communication/peers.rs index 50158126a0a07..c2fb06faddf0c 100644 --- a/client/beefy/src/communication/peers.rs +++ b/client/beefy/src/communication/peers.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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/communication/request_response/incoming_requests_handler.rs b/client/beefy/src/communication/request_response/incoming_requests_handler.rs index 854ece11cf93c..3266f6dba3989 100644 --- a/client/beefy/src/communication/request_response/incoming_requests_handler.rs +++ b/client/beefy/src/communication/request_response/incoming_requests_handler.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/client/beefy/src/communication/request_response/mod.rs b/client/beefy/src/communication/request_response/mod.rs index 22a20c247086d..c528d06bbe0c5 100644 --- a/client/beefy/src/communication/request_response/mod.rs +++ b/client/beefy/src/communication/request_response/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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/communication/request_response/outgoing_requests_engine.rs b/client/beefy/src/communication/request_response/outgoing_requests_engine.rs index 3e0d6e47d9432..0f4f07835ca82 100644 --- a/client/beefy/src/communication/request_response/outgoing_requests_engine.rs +++ b/client/beefy/src/communication/request_response/outgoing_requests_engine.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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 1b44e3801e303..16afbf2185780 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/beefy/src/import.rs b/client/beefy/src/import.rs index 66421e227476c..44d30d5d7df03 100644 --- a/client/beefy/src/import.rs +++ b/client/beefy/src/import.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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/justification.rs b/client/beefy/src/justification.rs index 9f433aa6ad1d7..6ceb3d2f5b369 100644 --- a/client/beefy/src/justification.rs +++ b/client/beefy/src/justification.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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 29436e36e65bb..3f0d8a5f316af 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/beefy/src/lib.rs b/client/beefy/src/lib.rs index 04345912f1d78..4f5f8b44329bf 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/beefy/src/metrics.rs b/client/beefy/src/metrics.rs index c74fb420d13f4..85438f1ca7cd6 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/beefy/src/round.rs b/client/beefy/src/round.rs index b2c4e97a420fe..142e138f599d5 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/beefy/src/tests.rs b/client/beefy/src/tests.rs index d8afc5465eaad..419033efe367f 100644 --- a/client/beefy/src/tests.rs +++ b/client/beefy/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/beefy/src/worker.rs b/client/beefy/src/worker.rs index f67ec17fc23a5..439da213818df 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/block-builder/src/lib.rs b/client/block-builder/src/lib.rs index 437e43a71d634..d7ef3b1da5123 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/chain-spec/derive/src/impls.rs b/client/chain-spec/derive/src/impls.rs index 7af403d46ad10..e54c1895e4a4b 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/chain-spec/derive/src/lib.rs b/client/chain-spec/derive/src/lib.rs index 75356a2250465..7607c6fdcff42 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/chain-spec/src/chain_spec.rs b/client/chain-spec/src/chain_spec.rs index 0b951200b069a..9eed5bbbc4e69 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/chain-spec/src/extension.rs b/client/chain-spec/src/extension.rs index c0b3e15a2df4c..25ab011a05b32 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/chain-spec/src/lib.rs b/client/chain-spec/src/lib.rs index 9d2cc728b8288..414df1fe1296f 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/cli/src/arg_enums.rs b/client/cli/src/arg_enums.rs index 372e8645e30cc..c3399a89680d1 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/cli/src/commands/build_spec_cmd.rs b/client/cli/src/commands/build_spec_cmd.rs index 5ab3ce9e88a09..a2cbfedb764fc 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/cli/src/commands/chain_info_cmd.rs b/client/cli/src/commands/chain_info_cmd.rs index cbc22cc4d52d9..002d7893d9f35 100644 --- a/client/cli/src/commands/chain_info_cmd.rs +++ b/client/cli/src/commands/chain_info_cmd.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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 3e25eab2c4350..897b61c8e0386 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/cli/src/commands/export_blocks_cmd.rs b/client/cli/src/commands/export_blocks_cmd.rs index 76fedff4d3ad7..7e8a295f99618 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/cli/src/commands/export_state_cmd.rs b/client/cli/src/commands/export_state_cmd.rs index 04bce0c1d707a..45196c1192c84 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/cli/src/commands/generate.rs b/client/cli/src/commands/generate.rs index 461cb98bc2e51..93b83fcbef51e 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/client/cli/src/commands/generate_node_key.rs b/client/cli/src/commands/generate_node_key.rs index e84b4a71d6d72..2288cd4037773 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/client/cli/src/commands/import_blocks_cmd.rs b/client/cli/src/commands/import_blocks_cmd.rs index debc697242ddd..f76c72924ddb6 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/cli/src/commands/insert_key.rs b/client/cli/src/commands/insert_key.rs index 7d66a680df8c0..77d0f57780a94 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/client/cli/src/commands/inspect_key.rs b/client/cli/src/commands/inspect_key.rs index 369fd10926dce..de82fe71e2445 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/client/cli/src/commands/inspect_node_key.rs b/client/cli/src/commands/inspect_node_key.rs index 9300007cb6bf2..2370f4a0989ba 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/client/cli/src/commands/key.rs b/client/cli/src/commands/key.rs index 59cca554bfa37..d49b7e4072c8e 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/client/cli/src/commands/mod.rs b/client/cli/src/commands/mod.rs index eeb9f3be3eb14..d004fc1beb097 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/cli/src/commands/purge_chain_cmd.rs b/client/cli/src/commands/purge_chain_cmd.rs index 9a3aeee50e944..2ff3d4b9a04c0 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/cli/src/commands/revert_cmd.rs b/client/cli/src/commands/revert_cmd.rs index 8477630cf9404..df5d93a7e944e 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/cli/src/commands/run_cmd.rs b/client/cli/src/commands/run_cmd.rs index 35181d83f805f..9441acecc4dfc 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/cli/src/commands/sign.rs b/client/cli/src/commands/sign.rs index b3da31e56658b..91b0651f0521f 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/cli/src/commands/test/mod.rs b/client/cli/src/commands/test/mod.rs index 762918f70ff0c..9b5d0ee897a93 100644 --- a/client/cli/src/commands/test/mod.rs +++ b/client/cli/src/commands/test/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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/test/sig_verify.rs b/client/cli/src/commands/test/sig_verify.rs index 8d7247480be87..bffd7dbc9fc03 100644 --- a/client/cli/src/commands/test/sig_verify.rs +++ b/client/cli/src/commands/test/sig_verify.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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 8ced185d7f3bc..ff159909b879c 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/cli/src/commands/vanity.rs b/client/cli/src/commands/vanity.rs index ae0007ac7964d..ce75161329893 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/cli/src/commands/verify.rs b/client/cli/src/commands/verify.rs index 183bf507bd114..c6d280de3fcfd 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/cli/src/config.rs b/client/cli/src/config.rs index 77689708a231f..5fedcf99a12ef 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/cli/src/error.rs b/client/cli/src/error.rs index a0f843e73bf53..3b30ccb3ed6b0 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/cli/src/lib.rs b/client/cli/src/lib.rs index b6d0d47e52c1f..adbb299317ac9 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/cli/src/params/database_params.rs b/client/cli/src/params/database_params.rs index 06a154fd60867..cbc602cb877b4 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/cli/src/params/import_params.rs b/client/cli/src/params/import_params.rs index b7ccbf1c8ed55..e36fbb5ffd91c 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/cli/src/params/keystore_params.rs b/client/cli/src/params/keystore_params.rs index d6c3c35d82418..e6e6fd9eb47ed 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/cli/src/params/message_params.rs b/client/cli/src/params/message_params.rs index 9f88c24dcd222..a935bbb25bddd 100644 --- a/client/cli/src/params/message_params.rs +++ b/client/cli/src/params/message_params.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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 4ec7d1d958e8f..f9c840d2d4865 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/cli/src/params/network_params.rs b/client/cli/src/params/network_params.rs index 984789da752d1..2402b5d68f998 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/cli/src/params/node_key_params.rs b/client/cli/src/params/node_key_params.rs index 2346455c26a37..074b95bea0f3a 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/cli/src/params/offchain_worker_params.rs b/client/cli/src/params/offchain_worker_params.rs index b18e036c06de5..33fd8d609b605 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/cli/src/params/pruning_params.rs b/client/cli/src/params/pruning_params.rs index 66282fd08848c..59eeb13cd0379 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/cli/src/params/shared_params.rs b/client/cli/src/params/shared_params.rs index 5cbb6dbad54a3..46f5390039d46 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/cli/src/params/transaction_pool_params.rs b/client/cli/src/params/transaction_pool_params.rs index 6b3a2d8a97a01..b2bf0b9b364c8 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/cli/src/runner.rs b/client/cli/src/runner.rs index c7a6f1f3c0f99..8917a37c499c0 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/aura/src/import_queue.rs b/client/consensus/aura/src/import_queue.rs index be52bffe0c02c..99b5af0818dc9 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/aura/src/lib.rs b/client/consensus/aura/src/lib.rs index 0345eaa397bf5..f5f70857c0ff8 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/babe/rpc/src/lib.rs b/client/consensus/babe/rpc/src/lib.rs index 2d6d95b8dc862..677a4ad92c9e1 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/babe/src/authorship.rs b/client/consensus/babe/src/authorship.rs index 3a92aa5c6b224..195a19b3d0f61 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/babe/src/aux_schema.rs b/client/consensus/babe/src/aux_schema.rs index 2a09aa738f4ec..a87b7c9a0d030 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/babe/src/lib.rs b/client/consensus/babe/src/lib.rs index a305403405e27..271e3f648c261 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/babe/src/migration.rs b/client/consensus/babe/src/migration.rs index 23413aa6a7b1b..ec864b8e5510f 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/babe/src/tests.rs b/client/consensus/babe/src/tests.rs index d1ad91a1ce760..42b8730cdd9ca 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/babe/src/verification.rs b/client/consensus/babe/src/verification.rs index 8e8f5d998f884..96d3961d44571 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/common/src/block_import.rs b/client/consensus/common/src/block_import.rs index f888176addd2d..98accc1d2f8c4 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/common/src/import_queue.rs b/client/consensus/common/src/import_queue.rs index 02309cc6a365e..66ff5e6d5e12f 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/common/src/import_queue/basic_queue.rs b/client/consensus/common/src/import_queue/basic_queue.rs index a96b0a47e57c7..06122491eedce 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/common/src/import_queue/buffered_link.rs b/client/consensus/common/src/import_queue/buffered_link.rs index 71adcf2dc2ea9..5c95cbc4260e1 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/common/src/import_queue/mock.rs b/client/consensus/common/src/import_queue/mock.rs index 67deee9514a1c..64ac532ded854 100644 --- a/client/consensus/common/src/import_queue/mock.rs +++ b/client/consensus/common/src/import_queue/mock.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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 f291cc2704818..6bf1ed0b48b4d 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/common/src/longest_chain.rs b/client/consensus/common/src/longest_chain.rs index ece2486209ff3..f27cde4982def 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/common/src/metrics.rs b/client/consensus/common/src/metrics.rs index 8314049238b88..e807189d46165 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/common/src/shared_data.rs b/client/consensus/common/src/shared_data.rs index fb04966b5db61..efd41d0985454 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/epochs/src/lib.rs b/client/consensus/epochs/src/lib.rs index 0e0b9fc17336f..29bb18e147c2b 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/epochs/src/migration.rs b/client/consensus/epochs/src/migration.rs index 052d0b7be4a53..8838dbb4605b7 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/manual-seal/src/consensus.rs b/client/consensus/manual-seal/src/consensus.rs index a812bb028c7f2..b54ec5e41b750 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/manual-seal/src/consensus/aura.rs b/client/consensus/manual-seal/src/consensus/aura.rs index 065b78732cdc3..92203f91826f0 100644 --- a/client/consensus/manual-seal/src/consensus/aura.rs +++ b/client/consensus/manual-seal/src/consensus/aura.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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 c5bb3b78fce35..476d2f0f4094d 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/manual-seal/src/consensus/timestamp.rs b/client/consensus/manual-seal/src/consensus/timestamp.rs index b3c2d780c35d9..dbffb2fbba824 100644 --- a/client/consensus/manual-seal/src/consensus/timestamp.rs +++ b/client/consensus/manual-seal/src/consensus/timestamp.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/manual-seal/src/error.rs b/client/consensus/manual-seal/src/error.rs index a056c541c3cef..eeae1d153e81b 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/manual-seal/src/finalize_block.rs b/client/consensus/manual-seal/src/finalize_block.rs index cee4d59b6d6e5..06883b2291bd2 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/manual-seal/src/lib.rs b/client/consensus/manual-seal/src/lib.rs index 5c86382a3ab7b..41f1f44335525 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/manual-seal/src/rpc.rs b/client/consensus/manual-seal/src/rpc.rs index b9bb06551f818..db92b9fd2981a 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/manual-seal/src/seal_block.rs b/client/consensus/manual-seal/src/seal_block.rs index 2cafdae503dce..eda3d91c9782b 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/pow/src/lib.rs b/client/consensus/pow/src/lib.rs index a81ad8ebea6f2..44eaccd2a40ac 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/pow/src/worker.rs b/client/consensus/pow/src/worker.rs index b53227bb3ca50..1a423895770fb 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/slots/build.rs b/client/consensus/slots/build.rs index b700b28e322ca..a68cb706e8fbd 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/slots/src/aux_schema.rs b/client/consensus/slots/src/aux_schema.rs index c1d01500ffe47..9c6bc0ad0cdc4 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/slots/src/lib.rs b/client/consensus/slots/src/lib.rs index 30d2c1761c712..ec6481a87f6d4 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/consensus/slots/src/slots.rs b/client/consensus/slots/src/slots.rs index 7bb263b2bdba7..203764310601a 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/db/benches/state_access.rs b/client/db/benches/state_access.rs index bab79fe7c90db..e47559e710df1 100644 --- a/client/db/benches/state_access.rs +++ b/client/db/benches/state_access.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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 a744762876440..b8fb3b6cec223 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/db/src/children.rs b/client/db/src/children.rs index 538e51851f081..0671376537182 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index 03de383f2c7f4..24c66fd7796e3 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/db/src/offchain.rs b/client/db/src/offchain.rs index 030a410981b26..dc7202ff6d290 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/db/src/parity_db.rs b/client/db/src/parity_db.rs index 4adacbf6f041c..01562081a8f4f 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/db/src/pinned_blocks_cache.rs b/client/db/src/pinned_blocks_cache.rs index 39ff1c5277871..f50a7081df6a8 100644 --- a/client/db/src/pinned_blocks_cache.rs +++ b/client/db/src/pinned_blocks_cache.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/db/src/record_stats_state.rs b/client/db/src/record_stats_state.rs index 0b51d3fef2127..91d6c2fe5bfad 100644 --- a/client/db/src/record_stats_state.rs +++ b/client/db/src/record_stats_state.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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 f6c14568236e9..1609ef9d5dad8 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/db/src/upgrade.rs b/client/db/src/upgrade.rs index 98517acad6e0b..f1e503867dfc3 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/db/src/utils.rs b/client/db/src/utils.rs index e998511016a67..abf9c4629cee4 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/executor/benches/bench.rs b/client/executor/benches/bench.rs index a282cdfbdd334..62e8b261f4786 100644 --- a/client/executor/benches/bench.rs +++ b/client/executor/benches/bench.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/client/executor/common/src/error.rs b/client/executor/common/src/error.rs index c35a874b7796d..c47164a60655f 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/executor/common/src/lib.rs b/client/executor/common/src/lib.rs index 79bb74b62a41e..751801fb30da1 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/executor/common/src/runtime_blob/data_segments_snapshot.rs b/client/executor/common/src/runtime_blob/data_segments_snapshot.rs index e65fc32f637a6..3fd546ce4457b 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/executor/common/src/runtime_blob/globals_snapshot.rs b/client/executor/common/src/runtime_blob/globals_snapshot.rs index 207fa751bc408..9ba6fc55e49c2 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/executor/common/src/runtime_blob/mod.rs b/client/executor/common/src/runtime_blob/mod.rs index 4b163bbaaf329..58278493af51b 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/executor/common/src/runtime_blob/runtime_blob.rs b/client/executor/common/src/runtime_blob/runtime_blob.rs index 08df4b32d59eb..dc0cde8d26974 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/executor/common/src/util.rs b/client/executor/common/src/util.rs index fbae01b556fb1..e672861cb6f3c 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/executor/common/src/wasm_runtime.rs b/client/executor/common/src/wasm_runtime.rs index d0cc8926144be..5899252068753 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/executor/runtime-test/build.rs b/client/executor/runtime-test/build.rs index d3aceedf9ed95..745742123a8f6 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/executor/src/integration_tests/linux.rs b/client/executor/src/integration_tests/linux.rs index efac4e74bb8e2..9afe37037eb2f 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/executor/src/integration_tests/linux/smaps.rs b/client/executor/src/integration_tests/linux/smaps.rs index 665155ff81ea8..1ac570dd8d5f2 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/executor/src/integration_tests/mod.rs b/client/executor/src/integration_tests/mod.rs index bb2930803841b..324c8d515d14a 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/executor/src/lib.rs b/client/executor/src/lib.rs index 0670b840949d7..e5bae474e9e25 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/executor/src/native_executor.rs b/client/executor/src/native_executor.rs index 0eabffb8c87df..a2af97ae4eacd 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/executor/src/wasm_runtime.rs b/client/executor/src/wasm_runtime.rs index 5576fff186bb2..4869fbae2d7db 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/executor/wasmi/src/lib.rs b/client/executor/wasmi/src/lib.rs index 6eb38146946b8..78b32a027eaa9 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/executor/wasmtime/build.rs b/client/executor/wasmtime/build.rs index c514b0041bc34..a68cb706e8fbd 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/executor/wasmtime/src/host.rs b/client/executor/wasmtime/src/host.rs index 0d9eac875170b..ead248385c9fe 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/executor/wasmtime/src/imports.rs b/client/executor/wasmtime/src/imports.rs index fad3195de93dc..fccc121fa0887 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/executor/wasmtime/src/instance_wrapper.rs b/client/executor/wasmtime/src/instance_wrapper.rs index 2117f1ebf2e91..f80c7b70d1f28 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/executor/wasmtime/src/lib.rs b/client/executor/wasmtime/src/lib.rs index 4d0e4c37c947e..c45478ec46a37 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/executor/wasmtime/src/runtime.rs b/client/executor/wasmtime/src/runtime.rs index e54070065274b..1728feeee5a87 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/executor/wasmtime/src/tests.rs b/client/executor/wasmtime/src/tests.rs index 3c6a25a186129..57540b35d05cf 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/executor/wasmtime/src/util.rs b/client/executor/wasmtime/src/util.rs index 15f62e475033a..5c64fc01c13a8 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/finality-grandpa/rpc/src/error.rs b/client/finality-grandpa/rpc/src/error.rs index 197c0b8a72102..885408d8f1d3b 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/finality-grandpa/rpc/src/finality.rs b/client/finality-grandpa/rpc/src/finality.rs index f2be6d674b2f1..dd1f0af8606c6 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/finality-grandpa/rpc/src/lib.rs b/client/finality-grandpa/rpc/src/lib.rs index 70ff7ed176869..8f06531be5f41 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/finality-grandpa/rpc/src/notification.rs b/client/finality-grandpa/rpc/src/notification.rs index 6fb1383579359..45e7d34889b3f 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/finality-grandpa/rpc/src/report.rs b/client/finality-grandpa/rpc/src/report.rs index 8c04ca28ef870..58e59d8aec606 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/finality-grandpa/src/authorities.rs b/client/finality-grandpa/src/authorities.rs index a61c66979bb5c..245c6bfe3c300 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/finality-grandpa/src/aux_schema.rs b/client/finality-grandpa/src/aux_schema.rs index a7357a7fa5e40..fbb0ab8a8bb06 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/finality-grandpa/src/communication/gossip.rs b/client/finality-grandpa/src/communication/gossip.rs index cbcafc727d436..65e765a4cb244 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/finality-grandpa/src/communication/mod.rs b/client/finality-grandpa/src/communication/mod.rs index e7e3c12989c96..3c1de1f4699d8 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/finality-grandpa/src/communication/periodic.rs b/client/finality-grandpa/src/communication/periodic.rs index c00fed1296512..f3f7572864e5c 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/finality-grandpa/src/communication/tests.rs b/client/finality-grandpa/src/communication/tests.rs index 839b2d52be651..19c2e4fef45e4 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/finality-grandpa/src/environment.rs b/client/finality-grandpa/src/environment.rs index 9ee7e486c709e..cdc98fc2206a8 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/finality-grandpa/src/finality_proof.rs b/client/finality-grandpa/src/finality_proof.rs index af3ed6e14ee2d..b042d6fce9f7a 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/finality-grandpa/src/import.rs b/client/finality-grandpa/src/import.rs index f5e2f96432327..19c42463715fb 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/finality-grandpa/src/justification.rs b/client/finality-grandpa/src/justification.rs index 96c31d4c0cc29..1534ca752cb6e 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/finality-grandpa/src/lib.rs b/client/finality-grandpa/src/lib.rs index 15d689e917d20..fca1a8a83b269 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/finality-grandpa/src/notification.rs b/client/finality-grandpa/src/notification.rs index 1d6e25e55dc65..de1fba09ea3d4 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/finality-grandpa/src/observer.rs b/client/finality-grandpa/src/observer.rs index 96101a8eda0ab..af56f2ac341a4 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/finality-grandpa/src/tests.rs b/client/finality-grandpa/src/tests.rs index fee3b13ba0be9..1a1f20797852a 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/finality-grandpa/src/until_imported.rs b/client/finality-grandpa/src/until_imported.rs index 3bca77ae8393f..f9ecb7df34e06 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/finality-grandpa/src/voting_rule.rs b/client/finality-grandpa/src/voting_rule.rs index 6f15a9cdd349e..27a91d5478370 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/finality-grandpa/src/warp_proof.rs b/client/finality-grandpa/src/warp_proof.rs index 1169083ea1d51..f73a0a323e593 100644 --- a/client/finality-grandpa/src/warp_proof.rs +++ b/client/finality-grandpa/src/warp_proof.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate 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 4da46ebb65edb..85be926d99b21 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/informant/src/lib.rs b/client/informant/src/lib.rs index b03b92686e2aa..cb30d08c45227 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/keystore/src/lib.rs b/client/keystore/src/lib.rs index cf94a16f08d86..4151f8c4dc1a4 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/keystore/src/local.rs b/client/keystore/src/local.rs index 54ff6a5b164a8..cd55739a9fac3 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/client/merkle-mountain-range/rpc/src/lib.rs b/client/merkle-mountain-range/rpc/src/lib.rs index 5c65be57ee509..daf2cd1ec298b 100644 --- a/client/merkle-mountain-range/rpc/src/lib.rs +++ b/client/merkle-mountain-range/rpc/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/client/merkle-mountain-range/src/aux_schema.rs b/client/merkle-mountain-range/src/aux_schema.rs index e6c53d4067988..436252267f107 100644 --- a/client/merkle-mountain-range/src/aux_schema.rs +++ b/client/merkle-mountain-range/src/aux_schema.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/merkle-mountain-range/src/lib.rs b/client/merkle-mountain-range/src/lib.rs index ce7223525eae1..de21b9b4967fb 100644 --- a/client/merkle-mountain-range/src/lib.rs +++ b/client/merkle-mountain-range/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/merkle-mountain-range/src/offchain_mmr.rs b/client/merkle-mountain-range/src/offchain_mmr.rs index bbb53cf3a9347..33d85f0cb14e3 100644 --- a/client/merkle-mountain-range/src/offchain_mmr.rs +++ b/client/merkle-mountain-range/src/offchain_mmr.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/merkle-mountain-range/src/test_utils.rs b/client/merkle-mountain-range/src/test_utils.rs index 9decaa3c243ff..9e00d620a115c 100644 --- a/client/merkle-mountain-range/src/test_utils.rs +++ b/client/merkle-mountain-range/src/test_utils.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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/bridge.rs b/client/network-gossip/src/bridge.rs index 5d7fd96c13e57..129e18d8a58df 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network-gossip/src/lib.rs b/client/network-gossip/src/lib.rs index 1c8fb8ba05ce7..859ec3d528d96 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network-gossip/src/state_machine.rs b/client/network-gossip/src/state_machine.rs index 001f2c6136a00..48a1a2e53352b 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network-gossip/src/validator.rs b/client/network-gossip/src/validator.rs index 77dcc3bdc8791..26835a5ae6687 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/bitswap/src/lib.rs b/client/network/bitswap/src/lib.rs index 62a18b18c839d..dd5fc46f6ca71 100644 --- a/client/network/bitswap/src/lib.rs +++ b/client/network/bitswap/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/client/network/bitswap/src/schema.rs b/client/network/bitswap/src/schema.rs index 362e59aca68f9..1d62847c21d08 100644 --- a/client/network/bitswap/src/schema.rs +++ b/client/network/bitswap/src/schema.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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/common/src/config.rs b/client/network/common/src/config.rs index c35d8a42a8c0c..782b5a9651384 100644 --- a/client/network/common/src/config.rs +++ b/client/network/common/src/config.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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/common/src/error.rs b/client/network/common/src/error.rs index 4326b1af52836..712b8c5de3f66 100644 --- a/client/network/common/src/error.rs +++ b/client/network/common/src/error.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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/common/src/lib.rs b/client/network/common/src/lib.rs index 36e67f11e5cff..10d2449388bb9 100644 --- a/client/network/common/src/lib.rs +++ b/client/network/common/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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/common/src/message.rs b/client/network/common/src/message.rs index 930fe5ca52847..12d2a6800490f 100644 --- a/client/network/common/src/message.rs +++ b/client/network/common/src/message.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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/common/src/protocol.rs b/client/network/common/src/protocol.rs index 04bfaedbcac71..bfeb1daf5d53b 100644 --- a/client/network/common/src/protocol.rs +++ b/client/network/common/src/protocol.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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/common/src/protocol/event.rs b/client/network/common/src/protocol/event.rs index 236913df1b120..7a14a2801319a 100644 --- a/client/network/common/src/protocol/event.rs +++ b/client/network/common/src/protocol/event.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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/common/src/protocol/role.rs b/client/network/common/src/protocol/role.rs index ed22830fd7170..cd43f6655b72c 100644 --- a/client/network/common/src/protocol/role.rs +++ b/client/network/common/src/protocol/role.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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/common/src/request_responses.rs b/client/network/common/src/request_responses.rs index 1a8d48e11be53..4fa53a736ac33 100644 --- a/client/network/common/src/request_responses.rs +++ b/client/network/common/src/request_responses.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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/common/src/service.rs b/client/network/common/src/service.rs index f0f307800202f..e96a00c40c123 100644 --- a/client/network/common/src/service.rs +++ b/client/network/common/src/service.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. // -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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/common/src/service/signature.rs b/client/network/common/src/service/signature.rs index 602ef3d82979a..14addafc6bba2 100644 --- a/client/network/common/src/service/signature.rs +++ b/client/network/common/src/service/signature.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. // -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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/common/src/sync.rs b/client/network/common/src/sync.rs index 802cf75fc4709..6a98543d42065 100644 --- a/client/network/common/src/sync.rs +++ b/client/network/common/src/sync.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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/common/src/sync/message.rs b/client/network/common/src/sync/message.rs index 346f1dbce9bcc..7b8be18bda5cc 100644 --- a/client/network/common/src/sync/message.rs +++ b/client/network/common/src/sync/message.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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/common/src/sync/metrics.rs b/client/network/common/src/sync/metrics.rs index 15ff090a8ccac..455f57ec39339 100644 --- a/client/network/common/src/sync/metrics.rs +++ b/client/network/common/src/sync/metrics.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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/common/src/sync/warp.rs b/client/network/common/src/sync/warp.rs index 020642fb48c82..a906091ff2a7b 100644 --- a/client/network/common/src/sync/warp.rs +++ b/client/network/common/src/sync/warp.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/client/network/common/src/utils.rs b/client/network/common/src/utils.rs index d0e61a0d0475d..c32d264a943e7 100644 --- a/client/network/common/src/utils.rs +++ b/client/network/common/src/utils.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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/light/src/lib.rs b/client/network/light/src/lib.rs index 2b7cf226f90dd..656f658d4c92f 100644 --- a/client/network/light/src/lib.rs +++ b/client/network/light/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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/light/src/light_client_requests.rs b/client/network/light/src/light_client_requests.rs index 61b549d0f0984..5b6daf174cce6 100644 --- a/client/network/light/src/light_client_requests.rs +++ b/client/network/light/src/light_client_requests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/light/src/light_client_requests/handler.rs b/client/network/light/src/light_client_requests/handler.rs index abf012b82f9db..0a1215a1dc6a9 100644 --- a/client/network/light/src/light_client_requests/handler.rs +++ b/client/network/light/src/light_client_requests/handler.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/light/src/schema.rs b/client/network/light/src/schema.rs index 1fc91659a5bbb..0ef9bac4df976 100644 --- a/client/network/light/src/schema.rs +++ b/client/network/light/src/schema.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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 eac74f7e6e37d..1ed8efbcdf949 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/src/config.rs b/client/network/src/config.rs index 8ca8d75f1681c..fc5304779dbfc 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/src/discovery.rs b/client/network/src/discovery.rs index b8805d1b1229d..6a8c777cac9c6 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/src/lib.rs b/client/network/src/lib.rs index f185458e0dace..8ecb3e54902af 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/src/network_state.rs b/client/network/src/network_state.rs index 57073c57afa69..cf8b8b55a7ff8 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/src/peer_info.rs b/client/network/src/peer_info.rs index f3402c0af110c..1cf0c928a4067 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/src/protocol.rs b/client/network/src/protocol.rs index cd232334e3b6a..2443fce815676 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/src/protocol/message.rs b/client/network/src/protocol/message.rs index ef652387d2c7d..f7981f1714951 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/src/protocol/notifications.rs b/client/network/src/protocol/notifications.rs index bf183abf160cb..aa49cfcf9d44e 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/src/protocol/notifications/behaviour.rs b/client/network/src/protocol/notifications/behaviour.rs index c546f6b6f2c44..ebfb95afaea2d 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/src/protocol/notifications/handler.rs b/client/network/src/protocol/notifications/handler.rs index 57561c7b9879d..70157386ef32e 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/src/protocol/notifications/tests.rs b/client/network/src/protocol/notifications/tests.rs index 6e858697486ea..9ca6974e4cdde 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/src/protocol/notifications/upgrade.rs b/client/network/src/protocol/notifications/upgrade.rs index 89fede25f6ae7..70c6023623f51 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/src/protocol/notifications/upgrade/collec.rs b/client/network/src/protocol/notifications/upgrade/collec.rs index 288b8bfd4849c..89999ff0c7534 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/src/protocol/notifications/upgrade/notifications.rs b/client/network/src/protocol/notifications/upgrade/notifications.rs index 71afc3c90e37f..bfdd9ccfa7eb9 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/src/request_responses.rs b/client/network/src/request_responses.rs index 45f1030400908..37c97e8282b4c 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/src/service.rs b/client/network/src/service.rs index 3c8856eaf8eff..fd0b965b77372 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/src/service/metrics.rs b/client/network/src/service/metrics.rs index a099bba716eb9..ccb440b2c3e1a 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/src/service/out_events.rs b/client/network/src/service/out_events.rs index 5e0c8ac6a1a40..57a5092ae62ea 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/src/service/tests/chain_sync.rs b/client/network/src/service/tests/chain_sync.rs index 98884024ac7e1..a369b71748974 100644 --- a/client/network/src/service/tests/chain_sync.rs +++ b/client/network/src/service/tests/chain_sync.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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/mod.rs b/client/network/src/service/tests/mod.rs index 3ce139ff03a33..3233b15840a2a 100644 --- a/client/network/src/service/tests/mod.rs +++ b/client/network/src/service/tests/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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/service.rs b/client/network/src/service/tests/service.rs index bdf30096356f2..1c7b32ff0dd17 100644 --- a/client/network/src/service/tests/service.rs +++ b/client/network/src/service/tests/service.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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 51a8483e0e4e6..3aa0bb48dec53 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/sync/src/block_request_handler.rs b/client/network/sync/src/block_request_handler.rs index 84755453fbea0..38aca2cde3fd2 100644 --- a/client/network/sync/src/block_request_handler.rs +++ b/client/network/sync/src/block_request_handler.rs @@ -1,4 +1,4 @@ -// Copyright 2020 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/client/network/sync/src/blocks.rs b/client/network/sync/src/blocks.rs index b8acd61a2009f..4cc1ca080d177 100644 --- a/client/network/sync/src/blocks.rs +++ b/client/network/sync/src/blocks.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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/sync/src/extra_requests.rs b/client/network/sync/src/extra_requests.rs index 0506bd542ff3b..09e6bdb57399f 100644 --- a/client/network/sync/src/extra_requests.rs +++ b/client/network/sync/src/extra_requests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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/sync/src/lib.rs b/client/network/sync/src/lib.rs index 1f4f6a04ebd77..5c1496e751dad 100644 --- a/client/network/sync/src/lib.rs +++ b/client/network/sync/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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/sync/src/mock.rs b/client/network/sync/src/mock.rs index b59ea7e4fea70..5300638ce89b0 100644 --- a/client/network/sync/src/mock.rs +++ b/client/network/sync/src/mock.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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/sync/src/schema.rs b/client/network/sync/src/schema.rs index b31005360d023..22b7ee592778e 100644 --- a/client/network/sync/src/schema.rs +++ b/client/network/sync/src/schema.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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/sync/src/service/chain_sync.rs b/client/network/sync/src/service/chain_sync.rs index 824303ec09d70..4d47899a31727 100644 --- a/client/network/sync/src/service/chain_sync.rs +++ b/client/network/sync/src/service/chain_sync.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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/sync/src/service/mock.rs b/client/network/sync/src/service/mock.rs index d8aad2fa7bac1..e66a9e5611f09 100644 --- a/client/network/sync/src/service/mock.rs +++ b/client/network/sync/src/service/mock.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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/sync/src/service/mod.rs b/client/network/sync/src/service/mod.rs index 692aa26985458..18331d63ed29f 100644 --- a/client/network/sync/src/service/mod.rs +++ b/client/network/sync/src/service/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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/sync/src/service/network.rs b/client/network/sync/src/service/network.rs index b81a65ae731cf..de7e255f5a895 100644 --- a/client/network/sync/src/service/network.rs +++ b/client/network/sync/src/service/network.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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/sync/src/state.rs b/client/network/sync/src/state.rs index 9f64b52334c8a..0fcf17158179e 100644 --- a/client/network/sync/src/state.rs +++ b/client/network/sync/src/state.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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/sync/src/state_request_handler.rs b/client/network/sync/src/state_request_handler.rs index 98f1ed34d0581..2f615f4ead753 100644 --- a/client/network/sync/src/state_request_handler.rs +++ b/client/network/sync/src/state_request_handler.rs @@ -1,4 +1,4 @@ -// Copyright 2020 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify diff --git a/client/network/sync/src/tests.rs b/client/network/sync/src/tests.rs index 61de08443a6c2..d56e84093ad71 100644 --- a/client/network/sync/src/tests.rs +++ b/client/network/sync/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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/sync/src/warp.rs b/client/network/sync/src/warp.rs index bb64ff6a15890..21af507877449 100644 --- a/client/network/sync/src/warp.rs +++ b/client/network/sync/src/warp.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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/sync/src/warp_request_handler.rs b/client/network/sync/src/warp_request_handler.rs index e675bf45cad91..fcb0d116bcdac 100644 --- a/client/network/sync/src/warp_request_handler.rs +++ b/client/network/sync/src/warp_request_handler.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate 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 250f5f5fd102c..25e3b9bee87f1 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/test/src/lib.rs b/client/network/test/src/lib.rs index 3cd508103c41a..544f4c5f62d18 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/test/src/sync.rs b/client/network/test/src/sync.rs index 8c230640355c9..490ec134c7ab9 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/network/transactions/src/config.rs b/client/network/transactions/src/config.rs index abb8cccd301ac..fdf81fcd9ff47 100644 --- a/client/network/transactions/src/config.rs +++ b/client/network/transactions/src/config.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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/transactions/src/lib.rs b/client/network/transactions/src/lib.rs index a5adb274d29de..d4d08d2ab7545 100644 --- a/client/network/transactions/src/lib.rs +++ b/client/network/transactions/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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 cd9f5c8f6feb9..6fdd91cda2390 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/offchain/src/api/http.rs b/client/offchain/src/api/http.rs index a47adb3e8026e..e3872614eae4d 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/offchain/src/api/timestamp.rs b/client/offchain/src/api/timestamp.rs index 4b3f5efddf275..0087ff592e1fc 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/offchain/src/lib.rs b/client/offchain/src/lib.rs index 904d127e1abdb..c69f01de19bf6 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/peerset/src/lib.rs b/client/peerset/src/lib.rs index 9b1dc6a2d0276..e5393acbaa32f 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/peerset/src/peersstate.rs b/client/peerset/src/peersstate.rs index c9af5b8e2ccd0..84907ac914b45 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/peerset/tests/fuzz.rs b/client/peerset/tests/fuzz.rs index 48c5cb341c35a..1f4bd053b553a 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/proposer-metrics/src/lib.rs b/client/proposer-metrics/src/lib.rs index c27d16ea04d7d..012e8ca769a96 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc-api/src/author/error.rs b/client/rpc-api/src/author/error.rs index 57a27d48de3ad..7ca96bbab7f19 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc-api/src/author/hash.rs b/client/rpc-api/src/author/hash.rs index 453947dd21f26..5c9542ffedcd0 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc-api/src/author/mod.rs b/client/rpc-api/src/author/mod.rs index feba7640e3b9f..55881e62152e3 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc-api/src/chain/error.rs b/client/rpc-api/src/chain/error.rs index 670e221cf1cde..cfb429bcffd12 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc-api/src/chain/mod.rs b/client/rpc-api/src/chain/mod.rs index c7cc97463983d..2ed767c370a65 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc-api/src/child_state/mod.rs b/client/rpc-api/src/child_state/mod.rs index be279a97463b0..a184677a721b5 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc-api/src/dev/error.rs b/client/rpc-api/src/dev/error.rs index 43fd3325fa598..2896e66bc0a35 100644 --- a/client/rpc-api/src/dev/error.rs +++ b/client/rpc-api/src/dev/error.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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/dev/mod.rs b/client/rpc-api/src/dev/mod.rs index afd83272a0127..bc7216199dd74 100644 --- a/client/rpc-api/src/dev/mod.rs +++ b/client/rpc-api/src/dev/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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 a0cbbcee80e3e..bc76d029ab6bb 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc-api/src/offchain/error.rs b/client/rpc-api/src/offchain/error.rs index be72e05fc4460..5ca0476087a5c 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc-api/src/offchain/mod.rs b/client/rpc-api/src/offchain/mod.rs index d9435d9a875fe..cd42d6db35081 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc-api/src/policy.rs b/client/rpc-api/src/policy.rs index 69ca8958520a6..799898fb7cf53 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc-api/src/state/error.rs b/client/rpc-api/src/state/error.rs index b1df64b4789ab..c69b3d9199ce6 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc-api/src/state/helpers.rs b/client/rpc-api/src/state/helpers.rs index 25f07be1c97c8..de20ee6f1bdfc 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc-api/src/state/mod.rs b/client/rpc-api/src/state/mod.rs index 323e6ad1d41a3..ebc1eb9b4ff52 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc-api/src/system/error.rs b/client/rpc-api/src/system/error.rs index 777f8c6c6df0b..4ad0f1b690a19 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc-api/src/system/helpers.rs b/client/rpc-api/src/system/helpers.rs index 7ddb3f813c249..ad56dc3850093 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc-api/src/system/mod.rs b/client/rpc-api/src/system/mod.rs index 1e12d5be87ee8..bf2e92bc27a01 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc-servers/src/lib.rs b/client/rpc-servers/src/lib.rs index 1fa2ba81d8672..62a9b4fc4a0ea 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc-servers/src/middleware.rs b/client/rpc-servers/src/middleware.rs index 1c25ac1dfd1b3..c3e17c7852f10 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc-spec-v2/src/chain_head/api.rs b/client/rpc-spec-v2/src/chain_head/api.rs index 7e72d6d774b1b..ad1e58500d51b 100644 --- a/client/rpc-spec-v2/src/chain_head/api.rs +++ b/client/rpc-spec-v2/src/chain_head/api.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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-spec-v2/src/chain_head/chain_head.rs b/client/rpc-spec-v2/src/chain_head/chain_head.rs index 76963d81edc38..4dbdf277e1732 100644 --- a/client/rpc-spec-v2/src/chain_head/chain_head.rs +++ b/client/rpc-spec-v2/src/chain_head/chain_head.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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-spec-v2/src/chain_head/error.rs b/client/rpc-spec-v2/src/chain_head/error.rs index 92f336ed4f4e3..3f31d985de0ff 100644 --- a/client/rpc-spec-v2/src/chain_head/error.rs +++ b/client/rpc-spec-v2/src/chain_head/error.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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-spec-v2/src/chain_head/event.rs b/client/rpc-spec-v2/src/chain_head/event.rs index 25930cb6f9950..2e070c7ce6ae7 100644 --- a/client/rpc-spec-v2/src/chain_head/event.rs +++ b/client/rpc-spec-v2/src/chain_head/event.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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-spec-v2/src/chain_head/mod.rs b/client/rpc-spec-v2/src/chain_head/mod.rs index a25933b40f07d..3d6d5a916aa75 100644 --- a/client/rpc-spec-v2/src/chain_head/mod.rs +++ b/client/rpc-spec-v2/src/chain_head/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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-spec-v2/src/chain_head/subscription.rs b/client/rpc-spec-v2/src/chain_head/subscription.rs index 033db45ca755c..e52336097086d 100644 --- a/client/rpc-spec-v2/src/chain_head/subscription.rs +++ b/client/rpc-spec-v2/src/chain_head/subscription.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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-spec-v2/src/chain_spec/api.rs b/client/rpc-spec-v2/src/chain_spec/api.rs index dfe2d76de6501..66c9f868047ce 100644 --- a/client/rpc-spec-v2/src/chain_spec/api.rs +++ b/client/rpc-spec-v2/src/chain_spec/api.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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-spec-v2/src/chain_spec/chain_spec.rs b/client/rpc-spec-v2/src/chain_spec/chain_spec.rs index 90d05f1d9d41d..99ea34521f586 100644 --- a/client/rpc-spec-v2/src/chain_spec/chain_spec.rs +++ b/client/rpc-spec-v2/src/chain_spec/chain_spec.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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-spec-v2/src/chain_spec/mod.rs b/client/rpc-spec-v2/src/chain_spec/mod.rs index cd4fcf246f603..0dfbdf1b10cc3 100644 --- a/client/rpc-spec-v2/src/chain_spec/mod.rs +++ b/client/rpc-spec-v2/src/chain_spec/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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-spec-v2/src/chain_spec/tests.rs b/client/rpc-spec-v2/src/chain_spec/tests.rs index 6f662ba422bc4..74aec01a2113e 100644 --- a/client/rpc-spec-v2/src/chain_spec/tests.rs +++ b/client/rpc-spec-v2/src/chain_spec/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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-spec-v2/src/lib.rs b/client/rpc-spec-v2/src/lib.rs index 5af7e3be264dc..7c22ef5d52318 100644 --- a/client/rpc-spec-v2/src/lib.rs +++ b/client/rpc-spec-v2/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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-spec-v2/src/transaction/api.rs b/client/rpc-spec-v2/src/transaction/api.rs index 2f0c799f1cc19..c226ab86787e9 100644 --- a/client/rpc-spec-v2/src/transaction/api.rs +++ b/client/rpc-spec-v2/src/transaction/api.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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-spec-v2/src/transaction/error.rs b/client/rpc-spec-v2/src/transaction/error.rs index 901d7c58b1417..d2de07afd5955 100644 --- a/client/rpc-spec-v2/src/transaction/error.rs +++ b/client/rpc-spec-v2/src/transaction/error.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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-spec-v2/src/transaction/event.rs b/client/rpc-spec-v2/src/transaction/event.rs index 3c75eaff10fd4..bdc126366fb92 100644 --- a/client/rpc-spec-v2/src/transaction/event.rs +++ b/client/rpc-spec-v2/src/transaction/event.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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-spec-v2/src/transaction/mod.rs b/client/rpc-spec-v2/src/transaction/mod.rs index bb983894a428c..212912ba1c728 100644 --- a/client/rpc-spec-v2/src/transaction/mod.rs +++ b/client/rpc-spec-v2/src/transaction/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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-spec-v2/src/transaction/transaction.rs b/client/rpc-spec-v2/src/transaction/transaction.rs index e2cf736dff17a..44f4bd36c8b8b 100644 --- a/client/rpc-spec-v2/src/transaction/transaction.rs +++ b/client/rpc-spec-v2/src/transaction/transaction.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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 cf47e9faf6114..2bb88352eb2e5 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc/src/author/tests.rs b/client/rpc/src/author/tests.rs index 573d01630de32..bf880cfbcfe9b 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc/src/chain/chain_full.rs b/client/rpc/src/chain/chain_full.rs index 6ff544b0deacd..a88291eb7bd35 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc/src/chain/mod.rs b/client/rpc/src/chain/mod.rs index 16e69c0f6324f..d54811320e749 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc/src/chain/tests.rs b/client/rpc/src/chain/tests.rs index 224d021f9409e..75211a43bd9f1 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc/src/dev/mod.rs b/client/rpc/src/dev/mod.rs index fa5d358b087bd..4d2e8618d553a 100644 --- a/client/rpc/src/dev/mod.rs +++ b/client/rpc/src/dev/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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/dev/tests.rs b/client/rpc/src/dev/tests.rs index 816f3cdfe6025..9beb01182585a 100644 --- a/client/rpc/src/dev/tests.rs +++ b/client/rpc/src/dev/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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 a0e810eafbb62..6230ef6648e20 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc/src/offchain/mod.rs b/client/rpc/src/offchain/mod.rs index 6896b82619166..de711accdcc12 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc/src/offchain/tests.rs b/client/rpc/src/offchain/tests.rs index 28a7b6115b657..62a846d0887cd 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc/src/state/mod.rs b/client/rpc/src/state/mod.rs index 9ba4c8218dd79..12d59ad3b382d 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc/src/state/state_full.rs b/client/rpc/src/state/state_full.rs index b0c0922c6ceea..ffc97487a8155 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc/src/state/tests.rs b/client/rpc/src/state/tests.rs index fe8bdf0ac2da8..53f8f1d48bc95 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc/src/state/utils.rs b/client/rpc/src/state/utils.rs index 81476cdd34262..9fc21b72b81e7 100644 --- a/client/rpc/src/state/utils.rs +++ b/client/rpc/src/state/utils.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc/src/system/mod.rs b/client/rpc/src/system/mod.rs index ea24524cd2ea9..0da4f8d0e211c 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc/src/system/tests.rs b/client/rpc/src/system/tests.rs index 4da49cdd1a0c5..c0ee1e8f88005 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/rpc/src/testing.rs b/client/rpc/src/testing.rs index 584e4a9901eab..6b6e1906d44d1 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index fb80753b4cbf6..2c690dcd2f8ac 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/service/src/chain_ops/check_block.rs b/client/service/src/chain_ops/check_block.rs index c3380e5476ab6..a14f535b9b367 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/service/src/chain_ops/export_blocks.rs b/client/service/src/chain_ops/export_blocks.rs index 9638722ef6b21..8d66f1f96baf3 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/service/src/chain_ops/export_raw_state.rs b/client/service/src/chain_ops/export_raw_state.rs index ca7a070086f45..f5e154795b9b7 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/service/src/chain_ops/import_blocks.rs b/client/service/src/chain_ops/import_blocks.rs index ca09c1658d72f..34f7669d0106e 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/service/src/chain_ops/mod.rs b/client/service/src/chain_ops/mod.rs index 98245eeb98d08..9ee6848ad4b1f 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/service/src/chain_ops/revert_chain.rs b/client/service/src/chain_ops/revert_chain.rs index 3ee4399d063b3..f3c344a75c5b0 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/service/src/client/block_rules.rs b/client/service/src/client/block_rules.rs index 2ed27b8fe1b63..532cde1ae78f0 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/service/src/client/call_executor.rs b/client/service/src/client/call_executor.rs index 49b969e3e71b0..8942b20bd91dc 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/service/src/client/client.rs b/client/service/src/client/client.rs index 615817cc32517..968044ba5cf97 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/service/src/client/genesis.rs b/client/service/src/client/genesis.rs index 54ef1182b7e7d..b3ed46c1550c7 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/service/src/client/mod.rs b/client/service/src/client/mod.rs index dafeb68831885..38d818c498a6a 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/service/src/client/wasm_override.rs b/client/service/src/client/wasm_override.rs index 03a5704adf8bf..3a56e5c595829 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/service/src/client/wasm_substitutes.rs b/client/service/src/client/wasm_substitutes.rs index ed931d3dae213..a792ab87e771b 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/service/src/config.rs b/client/service/src/config.rs index efadb8433f63d..7f3a2e3c0bb25 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/service/src/error.rs b/client/service/src/error.rs index ec2951193964c..c61c5164043c4 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/service/src/lib.rs b/client/service/src/lib.rs index 253479abc3bca..af0b11f2092c4 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/service/src/metrics.rs b/client/service/src/metrics.rs index c83b3988f9fa3..19c64e953667d 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/service/src/task_manager/mod.rs b/client/service/src/task_manager/mod.rs index f2987e684d9dc..8dc4748b089ee 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/service/src/task_manager/prometheus_future.rs b/client/service/src/task_manager/prometheus_future.rs index 88296a67336fe..51bf7fea496a7 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/service/src/task_manager/tests.rs b/client/service/src/task_manager/tests.rs index 323110a4e1b0c..27be4f9a8a26e 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/service/test/src/client/db.rs b/client/service/test/src/client/db.rs index 5c1315fc870cd..def1a41e62bb5 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/service/test/src/client/mod.rs b/client/service/test/src/client/mod.rs index 0fe4760fcb93e..9d021be5b7cad 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/service/test/src/lib.rs b/client/service/test/src/lib.rs index 6533fe13961b5..655aff2423094 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/state-db/src/lib.rs b/client/state-db/src/lib.rs index b6106ee81e839..14b4622ac0670 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/state-db/src/noncanonical.rs b/client/state-db/src/noncanonical.rs index d6cc49a3d66b3..bdbe8318371ce 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/state-db/src/pruning.rs b/client/state-db/src/pruning.rs index 16561bbe0ffd5..7bee2b1d99a34 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/state-db/src/test.rs b/client/state-db/src/test.rs index 314ec2902452a..74571145b52a3 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/storage-monitor/src/lib.rs b/client/storage-monitor/src/lib.rs index 162fcfe34a52b..e65b13ff65e11 100644 --- a/client/storage-monitor/src/lib.rs +++ b/client/storage-monitor/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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 9edc2ceecb78f..94bf53c5ab456 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/sysinfo/build.rs b/client/sysinfo/build.rs index 6d288107445aa..d267f3670608c 100644 --- a/client/sysinfo/build.rs +++ b/client/sysinfo/build.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/sysinfo/src/lib.rs b/client/sysinfo/src/lib.rs index f623bdae53e66..7065c9b997e72 100644 --- a/client/sysinfo/src/lib.rs +++ b/client/sysinfo/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/sysinfo/src/sysinfo.rs b/client/sysinfo/src/sysinfo.rs index 1fbca7d37efb7..41161fc685d31 100644 --- a/client/sysinfo/src/sysinfo.rs +++ b/client/sysinfo/src/sysinfo.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/sysinfo/src/sysinfo_linux.rs b/client/sysinfo/src/sysinfo_linux.rs index 41ab6014cbef0..ae678e07661ef 100644 --- a/client/sysinfo/src/sysinfo_linux.rs +++ b/client/sysinfo/src/sysinfo_linux.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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 fba3822a90676..a4f0d0f83d617 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/telemetry/src/error.rs b/client/telemetry/src/error.rs index 4d9cdc05c51b9..b8e3d28751d98 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/telemetry/src/lib.rs b/client/telemetry/src/lib.rs index aa6b841b79164..113d8303a20f6 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/telemetry/src/node.rs b/client/telemetry/src/node.rs index 71eed04128c7c..0bbdbfb622ef1 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/telemetry/src/transport.rs b/client/telemetry/src/transport.rs index 5e940bbe54eb5..a82626caac2d3 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/tracing/benches/bench.rs b/client/tracing/benches/bench.rs index a939a26797396..1379023ddfa6c 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/client/tracing/proc-macro/src/lib.rs b/client/tracing/proc-macro/src/lib.rs index ba757619fb5a0..8fb01de403686 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/tracing/src/block/mod.rs b/client/tracing/src/block/mod.rs index 465767781eb1f..f5efadc34fb92 100644 --- a/client/tracing/src/block/mod.rs +++ b/client/tracing/src/block/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate 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 acbde8b75da25..bd5045fed7f11 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/tracing/src/logging/directives.rs b/client/tracing/src/logging/directives.rs index b5fb373674ace..3985bf2d88c64 100644 --- a/client/tracing/src/logging/directives.rs +++ b/client/tracing/src/logging/directives.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate 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 aec6b76843daf..f4579f006c25d 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/tracing/src/logging/fast_local_time.rs b/client/tracing/src/logging/fast_local_time.rs index 47fc23340482a..7be7bec8364aa 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/tracing/src/logging/layers/mod.rs b/client/tracing/src/logging/layers/mod.rs index 382b79bc85d73..b39320975f86f 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/tracing/src/logging/layers/prefix_layer.rs b/client/tracing/src/logging/layers/prefix_layer.rs index 836ffd2adda8e..fc444257bde04 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/tracing/src/logging/mod.rs b/client/tracing/src/logging/mod.rs index 77307ad999daf..a3cf277fbd501 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/tracing/src/logging/stderr_writer.rs b/client/tracing/src/logging/stderr_writer.rs index de78a61af41a2..80df2f1fe7cdf 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/transaction-pool/api/src/error.rs b/client/transaction-pool/api/src/error.rs index aada44734d053..e521502f66fb1 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/transaction-pool/api/src/lib.rs b/client/transaction-pool/api/src/lib.rs index 870760962a520..428d0aed62efe 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/transaction-pool/benches/basics.rs b/client/transaction-pool/benches/basics.rs index 97d8edddffdbc..f7739ef73a971 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/transaction-pool/src/api.rs b/client/transaction-pool/src/api.rs index 9e20915dbacf6..f9d79ee429e6c 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/transaction-pool/src/enactment_state.rs b/client/transaction-pool/src/enactment_state.rs index 7252c0dec7f2a..ed6b3d186694f 100644 --- a/client/transaction-pool/src/enactment_state.rs +++ b/client/transaction-pool/src/enactment_state.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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 a4cf756481dc3..d93872d6c6762 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/transaction-pool/src/graph/base_pool.rs b/client/transaction-pool/src/graph/base_pool.rs index 44371be62c621..a9d2d6c825f61 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/transaction-pool/src/graph/future.rs b/client/transaction-pool/src/graph/future.rs index d23b5f2b6e1f1..bad4663184854 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/transaction-pool/src/graph/listener.rs b/client/transaction-pool/src/graph/listener.rs index c603a542c2767..46b7957e0b31b 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/transaction-pool/src/graph/mod.rs b/client/transaction-pool/src/graph/mod.rs index 42812897a954b..5afdddb7402d1 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/transaction-pool/src/graph/pool.rs b/client/transaction-pool/src/graph/pool.rs index 14217d56aaa57..54534df820227 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/transaction-pool/src/graph/ready.rs b/client/transaction-pool/src/graph/ready.rs index 9040c81b3c434..b4a5d9e3ba719 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/transaction-pool/src/graph/rotator.rs b/client/transaction-pool/src/graph/rotator.rs index 47e00a1292155..61a26fb4138ca 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/transaction-pool/src/graph/tracked_map.rs b/client/transaction-pool/src/graph/tracked_map.rs index 7292293258f57..47ad22603e469 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/transaction-pool/src/graph/validated_pool.rs b/client/transaction-pool/src/graph/validated_pool.rs index bf8a059af2ff1..ed76d439ae71d 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/transaction-pool/src/graph/watcher.rs b/client/transaction-pool/src/graph/watcher.rs index df5bb94edfe6d..fc440771d7bbc 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/transaction-pool/src/lib.rs b/client/transaction-pool/src/lib.rs index 44bda82da38a1..c3a85a373ba31 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/transaction-pool/src/metrics.rs b/client/transaction-pool/src/metrics.rs index 8bcefe246bff5..170bface96477 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/transaction-pool/src/revalidation.rs b/client/transaction-pool/src/revalidation.rs index 99602b50a2269..bd8f3dd6498f3 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/transaction-pool/src/tests.rs b/client/transaction-pool/src/tests.rs index d399367eae818..3945c88d49c0a 100644 --- a/client/transaction-pool/src/tests.rs +++ b/client/transaction-pool/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/transaction-pool/tests/pool.rs b/client/transaction-pool/tests/pool.rs index 511f6d9e24b5f..284c777a683db 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/utils/src/id_sequence.rs b/client/utils/src/id_sequence.rs index 2ccb4fc3f32ee..abb1271c72a00 100644 --- a/client/utils/src/id_sequence.rs +++ b/client/utils/src/id_sequence.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/utils/src/lib.rs b/client/utils/src/lib.rs index 0e47330335c27..f0cc1efe6111c 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/utils/src/metrics.rs b/client/utils/src/metrics.rs index 457ef23e41ab1..c2b10100f229f 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/utils/src/mpsc.rs b/client/utils/src/mpsc.rs index d74703c4abd08..df45e33ff8ee5 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/utils/src/notification.rs b/client/utils/src/notification.rs index 4917a43265df4..7d866ffc8c019 100644 --- a/client/utils/src/notification.rs +++ b/client/utils/src/notification.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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/notification/registry.rs b/client/utils/src/notification/registry.rs index ebe41452a567e..6f0960ea918be 100644 --- a/client/utils/src/notification/registry.rs +++ b/client/utils/src/notification/registry.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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/notification/tests.rs b/client/utils/src/notification/tests.rs index f813f37d29ddb..1afc2307e7b30 100644 --- a/client/utils/src/notification/tests.rs +++ b/client/utils/src/notification/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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/pubsub.rs b/client/utils/src/pubsub.rs index f85f44b498841..8136aa0692c26 100644 --- a/client/utils/src/pubsub.rs +++ b/client/utils/src/pubsub.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.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/pubsub/tests.rs b/client/utils/src/pubsub/tests.rs index 12945c0d886b8..0d832c7dbd872 100644 --- a/client/utils/src/pubsub/tests.rs +++ b/client/utils/src/pubsub/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/utils/src/pubsub/tests/normal_operation.rs b/client/utils/src/pubsub/tests/normal_operation.rs index 830388de32e46..d4b614d7a8889 100644 --- a/client/utils/src/pubsub/tests/normal_operation.rs +++ b/client/utils/src/pubsub/tests/normal_operation.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/utils/src/pubsub/tests/panicking_registry.rs b/client/utils/src/pubsub/tests/panicking_registry.rs index cfe8168d80229..9f7579e79f479 100644 --- a/client/utils/src/pubsub/tests/panicking_registry.rs +++ b/client/utils/src/pubsub/tests/panicking_registry.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/client/utils/src/status_sinks.rs b/client/utils/src/status_sinks.rs index c536e2c18c6a1..51d78aa497752 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/frame/alliance/src/benchmarking.rs b/frame/alliance/src/benchmarking.rs index 01b81ed66e999..a30b5adcee3ed 100644 --- a/frame/alliance/src/benchmarking.rs +++ b/frame/alliance/src/benchmarking.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/alliance/src/lib.rs b/frame/alliance/src/lib.rs index 790c3c384e701..c9232a1f2fb8e 100644 --- a/frame/alliance/src/lib.rs +++ b/frame/alliance/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/alliance/src/migration.rs b/frame/alliance/src/migration.rs index ea07f8c1279b1..e3a44a7887e97 100644 --- a/frame/alliance/src/migration.rs +++ b/frame/alliance/src/migration.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/alliance/src/mock.rs b/frame/alliance/src/mock.rs index 0f774dc4853fa..0925a82fdbfa3 100644 --- a/frame/alliance/src/mock.rs +++ b/frame/alliance/src/mock.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/alliance/src/tests.rs b/frame/alliance/src/tests.rs index 363b19429b80f..5942595469d5f 100644 --- a/frame/alliance/src/tests.rs +++ b/frame/alliance/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/alliance/src/types.rs b/frame/alliance/src/types.rs index c155b9fa90f95..784993b2bc133 100644 --- a/frame/alliance/src/types.rs +++ b/frame/alliance/src/types.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/alliance/src/weights.rs b/frame/alliance/src/weights.rs index 9ff6ce612f36e..6ccf6bed3a5d2 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) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/assets/src/benchmarking.rs b/frame/assets/src/benchmarking.rs index cf0ec353f6350..4fe951f56edf3 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/assets/src/extra_mutator.rs b/frame/assets/src/extra_mutator.rs index b72bfa86df5b8..96fb765cb0382 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/assets/src/functions.rs b/frame/assets/src/functions.rs index b540f02b87c82..f970ce6cf5640 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/assets/src/impl_fungibles.rs b/frame/assets/src/impl_fungibles.rs index b10b8c6b10755..f420ea02c31e9 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/assets/src/impl_stored_map.rs b/frame/assets/src/impl_stored_map.rs index a4669c776ed41..5ead708469a94 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/assets/src/lib.rs b/frame/assets/src/lib.rs index c2480a20636b0..894f8f3a4ab93 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/assets/src/migration.rs b/frame/assets/src/migration.rs index 9f8905ceff6c4..71da8823e92ef 100644 --- a/frame/assets/src/migration.rs +++ b/frame/assets/src/migration.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/assets/src/mock.rs b/frame/assets/src/mock.rs index 93a87ee6714c6..14795b10a7e15 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/assets/src/tests.rs b/frame/assets/src/tests.rs index f7007ff3ccf17..6a3fd672a759c 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/assets/src/types.rs b/frame/assets/src/types.rs index 557af6bd3f488..d50461ba59898 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/assets/src/weights.rs b/frame/assets/src/weights.rs index c2028105cd4b7..9ebba62237091 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) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/atomic-swap/src/lib.rs b/frame/atomic-swap/src/lib.rs index 66628e8e6f242..68d2544204b83 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/aura/src/lib.rs b/frame/aura/src/lib.rs index b19fbd57c5030..108b9303b3071 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/aura/src/migrations.rs b/frame/aura/src/migrations.rs index d9b7cb8872a83..b45e4eb7cb5c8 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/aura/src/mock.rs b/frame/aura/src/mock.rs index 7a07fe99ae25d..72d11a0749933 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/aura/src/tests.rs b/frame/aura/src/tests.rs index ce09f85678c00..1ed937a7745fe 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/authority-discovery/src/lib.rs b/frame/authority-discovery/src/lib.rs index 39e01dba43b2b..e93deabeb5318 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/authorship/src/lib.rs b/frame/authorship/src/lib.rs index b5568a6acf77c..cb1d777fa56c3 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/babe/src/benchmarking.rs b/frame/babe/src/benchmarking.rs index 70605e4cff34c..92f55665913e2 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/babe/src/default_weights.rs b/frame/babe/src/default_weights.rs index f864fd18d86a6..e875bc83522c2 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/babe/src/equivocation.rs b/frame/babe/src/equivocation.rs index 70f087fd461f9..2a2e2b47605d1 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/babe/src/lib.rs b/frame/babe/src/lib.rs index 69c89fdcea776..bb07037ee0a12 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/babe/src/mock.rs b/frame/babe/src/mock.rs index b09dc29f6d60a..b130677897883 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/babe/src/randomness.rs b/frame/babe/src/randomness.rs index 28b2ea7cd665e..b223df6804c0b 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/babe/src/tests.rs b/frame/babe/src/tests.rs index 938269a6cfa62..68426d0a8636e 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/bags-list/fuzzer/src/main.rs b/frame/bags-list/fuzzer/src/main.rs index c78e2a13076d5..18391bbb3c9a5 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/bags-list/remote-tests/src/lib.rs b/frame/bags-list/remote-tests/src/lib.rs index fc25e3b65ddb1..9f7c22d99dad1 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/bags-list/remote-tests/src/migration.rs b/frame/bags-list/remote-tests/src/migration.rs index 759906a4ef479..7847fdc7591c0 100644 --- a/frame/bags-list/remote-tests/src/migration.rs +++ b/frame/bags-list/remote-tests/src/migration.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot is free software: you can redistribute it and/or modify diff --git a/frame/bags-list/remote-tests/src/snapshot.rs b/frame/bags-list/remote-tests/src/snapshot.rs index 0163ca200a15d..0c6e194d32478 100644 --- a/frame/bags-list/remote-tests/src/snapshot.rs +++ b/frame/bags-list/remote-tests/src/snapshot.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot is free software: you can redistribute it and/or modify diff --git a/frame/bags-list/remote-tests/src/try_state.rs b/frame/bags-list/remote-tests/src/try_state.rs index 9ed877a43afe1..5bbac00bc75ab 100644 --- a/frame/bags-list/remote-tests/src/try_state.rs +++ b/frame/bags-list/remote-tests/src/try_state.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot is free software: you can redistribute it and/or modify diff --git a/frame/bags-list/src/benchmarks.rs b/frame/bags-list/src/benchmarks.rs index 74ae5f31ac81f..0c3955c0d7b79 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/bags-list/src/lib.rs b/frame/bags-list/src/lib.rs index f04c685ae386c..b65b65c39223d 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/bags-list/src/list/mod.rs b/frame/bags-list/src/list/mod.rs index 4082a5324091b..f667f4c101ef8 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/bags-list/src/list/tests.rs b/frame/bags-list/src/list/tests.rs index 3c4aa7c86634d..f5afdc24f2608 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/bags-list/src/migrations.rs b/frame/bags-list/src/migrations.rs index e1dc9f777e537..5f9bb8f73ac60 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/bags-list/src/mock.rs b/frame/bags-list/src/mock.rs index 32f6bb09e4772..2ccc3c438af37 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/bags-list/src/tests.rs b/frame/bags-list/src/tests.rs index 63a395ed0d65a..74f1491835a32 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/bags-list/src/weights.rs b/frame/bags-list/src/weights.rs index d06f7b0db603c..65d27c5aea4bb 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) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/balances/src/benchmarking.rs b/frame/balances/src/benchmarking.rs index d80aa3ec8e57e..c2ed0ace54100 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-2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index f62ea6be7d3eb..f02c7f9c0c579 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/balances/src/migration.rs b/frame/balances/src/migration.rs index 80d1bcd35ba9e..6a272a611c3f9 100644 --- a/frame/balances/src/migration.rs +++ b/frame/balances/src/migration.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2020 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot is free software: you can redistribute it and/or modify diff --git a/frame/balances/src/tests.rs b/frame/balances/src/tests.rs index 83944caf9f7ff..82a6ee5f6d33b 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/balances/src/tests_composite.rs b/frame/balances/src/tests_composite.rs index f8a8fdd1851d4..6f371f1e23010 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/balances/src/tests_local.rs b/frame/balances/src/tests_local.rs index 152a5da37410f..0d57a33200147 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/balances/src/tests_reentrancy.rs b/frame/balances/src/tests_reentrancy.rs index 90363140000e8..1699a879638e2 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/balances/src/weights.rs b/frame/balances/src/weights.rs index 3266fcbcd4805..6bd7d7548c637 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) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/beefy-mmr/src/lib.rs b/frame/beefy-mmr/src/lib.rs index eb030b71ddec6..8bb3aaa7e69b8 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/beefy-mmr/src/mock.rs b/frame/beefy-mmr/src/mock.rs index 8f3bdd619568c..922f882e1f1df 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/beefy-mmr/src/tests.rs b/frame/beefy-mmr/src/tests.rs index 0f7804e544aa4..af10d1127ebd7 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/beefy/src/default_weights.rs b/frame/beefy/src/default_weights.rs index 0b642cb45e9ce..7743edf25ec6c 100644 --- a/frame/beefy/src/default_weights.rs +++ b/frame/beefy/src/default_weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/beefy/src/equivocation.rs b/frame/beefy/src/equivocation.rs index ea6a9f9122351..19c41cbfacea5 100644 --- a/frame/beefy/src/equivocation.rs +++ b/frame/beefy/src/equivocation.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: 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 cccfdbb8131c6..bcb7fc126520b 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/beefy/src/mock.rs b/frame/beefy/src/mock.rs index c6cde5332b4fc..74dba2a01b81d 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/beefy/src/tests.rs b/frame/beefy/src/tests.rs index b2e1b67691d9b..767b1e5657502 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/benchmarking/pov/src/benchmarking.rs b/frame/benchmarking/pov/src/benchmarking.rs index 608077e2df806..331570ad28fce 100644 --- a/frame/benchmarking/pov/src/benchmarking.rs +++ b/frame/benchmarking/pov/src/benchmarking.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/benchmarking/pov/src/lib.rs b/frame/benchmarking/pov/src/lib.rs index 6618ce60d8ec8..7dee5c37c1288 100644 --- a/frame/benchmarking/pov/src/lib.rs +++ b/frame/benchmarking/pov/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/benchmarking/pov/src/tests.rs b/frame/benchmarking/pov/src/tests.rs index 1100fdc46f813..19156b93060bc 100644 --- a/frame/benchmarking/pov/src/tests.rs +++ b/frame/benchmarking/pov/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/benchmarking/src/analysis.rs b/frame/benchmarking/src/analysis.rs index e5afe8103f29c..5fc3abb5a27f0 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/benchmarking/src/baseline.rs b/frame/benchmarking/src/baseline.rs index 0d511cbff4b86..11d4ba5011a2f 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/benchmarking/src/lib.rs b/frame/benchmarking/src/lib.rs index a3bf809f6b9ba..f5dc513650e21 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/benchmarking/src/tests.rs b/frame/benchmarking/src/tests.rs index 1499f9c182fce..a3e19cde3642e 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/benchmarking/src/tests_instance.rs b/frame/benchmarking/src/tests_instance.rs index ecc0a78a199b9..49f9786d77ea1 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/benchmarking/src/utils.rs b/frame/benchmarking/src/utils.rs index 74e44fbf91103..59e5192b427b0 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/benchmarking/src/v1.rs b/frame/benchmarking/src/v1.rs index 089083f85b982..be6dc393cbce3 100644 --- a/frame/benchmarking/src/v1.rs +++ b/frame/benchmarking/src/v1.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/benchmarking/src/weights.rs b/frame/benchmarking/src/weights.rs index dea95947122af..85dbb18c7e024 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) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/bounties/src/benchmarking.rs b/frame/bounties/src/benchmarking.rs index 881f1c912e38b..04465a25eb891 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/bounties/src/lib.rs b/frame/bounties/src/lib.rs index afdcfef8279bd..325347502a918 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/bounties/src/migrations/mod.rs b/frame/bounties/src/migrations/mod.rs index 235d0f1c7cf15..2487ed1d5da52 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/bounties/src/migrations/v4.rs b/frame/bounties/src/migrations/v4.rs index 2f81c97127bcd..936bac1170089 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/bounties/src/tests.rs b/frame/bounties/src/tests.rs index bc59e3a70fd82..27aa0858523ec 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/bounties/src/weights.rs b/frame/bounties/src/weights.rs index 1ae8ab2983704..174891f9589d3 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) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/child-bounties/src/benchmarking.rs b/frame/child-bounties/src/benchmarking.rs index e7f18c1645823..0a83f7c394905 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/child-bounties/src/lib.rs b/frame/child-bounties/src/lib.rs index 9eb784eaccd23..3046d97007cae 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/child-bounties/src/tests.rs b/frame/child-bounties/src/tests.rs index f3415c69df611..b4b24eb910293 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/child-bounties/src/weights.rs b/frame/child-bounties/src/weights.rs index 77ab24488e1b2..e27393de9d350 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) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/collective/src/benchmarking.rs b/frame/collective/src/benchmarking.rs index 5c9e55862d1a4..d4b5af1bc1937 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/collective/src/lib.rs b/frame/collective/src/lib.rs index 8424527b154a4..ae5b22559d7c8 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/collective/src/migrations/mod.rs b/frame/collective/src/migrations/mod.rs index 235d0f1c7cf15..2487ed1d5da52 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/collective/src/migrations/v4.rs b/frame/collective/src/migrations/v4.rs index 2756b3fd15a6b..b3326b4251c9b 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/collective/src/tests.rs b/frame/collective/src/tests.rs index b7cdeb3383375..bfc6a0249b76c 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/collective/src/weights.rs b/frame/collective/src/weights.rs index fe6a222017919..d8a7131186424 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) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/contracts/primitives/src/lib.rs b/frame/contracts/primitives/src/lib.rs index f5b8da249517e..ee415cb822257 100644 --- a/frame/contracts/primitives/src/lib.rs +++ b/frame/contracts/primitives/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/contracts/proc-macro/src/lib.rs b/frame/contracts/proc-macro/src/lib.rs index c5f52f43a7d87..1b530a409b933 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/contracts/src/address.rs b/frame/contracts/src/address.rs index 4b1bb1f48b91c..1c25af21e8cb7 100644 --- a/frame/contracts/src/address.rs +++ b/frame/contracts/src/address.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/contracts/src/benchmarking/code.rs b/frame/contracts/src/benchmarking/code.rs index 156b9e2f99945..aa44cc3976a2c 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index ed41cece17301..c18d9ffb4b584 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/contracts/src/benchmarking/sandbox.rs b/frame/contracts/src/benchmarking/sandbox.rs index a6a97d11acbe3..7e28840981008 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/contracts/src/chain_extension.rs b/frame/contracts/src/chain_extension.rs index 3974bdba30d14..9b94542547ea8 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/contracts/src/exec.rs b/frame/contracts/src/exec.rs index 92930cc791397..37be12d50d689 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/contracts/src/gas.rs b/frame/contracts/src/gas.rs index c8383f307c0ea..c6f7d44be686e 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index a5f35a9cb5f3b..a115cf119ceef 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/contracts/src/migration.rs b/frame/contracts/src/migration.rs index 56d688abc7309..cd8f1dd1c9cd4 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/contracts/src/schedule.rs b/frame/contracts/src/schedule.rs index ccfba941e9817..71faf08c23d6a 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/contracts/src/storage.rs b/frame/contracts/src/storage.rs index 35db33c4ca0b2..26162b55ca393 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/contracts/src/storage/meter.rs b/frame/contracts/src/storage/meter.rs index 5102edb78a09f..ef6fb3277c11b 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index 879268a68dca9..bf1bd4f65442f 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/contracts/src/wasm/code_cache.rs b/frame/contracts/src/wasm/code_cache.rs index 385ed54ccb410..7dbce367ca96b 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index d25499641c5d2..f8c5a6ed96c57 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/contracts/src/wasm/prepare.rs b/frame/contracts/src/wasm/prepare.rs index 787b97d31acce..3c69fc2a7940f 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index eba20e9596786..ab873331cbbc6 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/contracts/src/weights.rs b/frame/contracts/src/weights.rs index d032615843656..880b7305f3bc1 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) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/conviction-voting/src/benchmarking.rs b/frame/conviction-voting/src/benchmarking.rs index 8c168a34a739d..27f46507d6078 100644 --- a/frame/conviction-voting/src/benchmarking.rs +++ b/frame/conviction-voting/src/benchmarking.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/conviction-voting/src/conviction.rs b/frame/conviction-voting/src/conviction.rs index 1feff35b19fcc..b5c9a3a705f6b 100644 --- a/frame/conviction-voting/src/conviction.rs +++ b/frame/conviction-voting/src/conviction.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/conviction-voting/src/lib.rs b/frame/conviction-voting/src/lib.rs index 141e9690fa29d..6c15c6cf25b13 100644 --- a/frame/conviction-voting/src/lib.rs +++ b/frame/conviction-voting/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/conviction-voting/src/tests.rs b/frame/conviction-voting/src/tests.rs index 9caa451e0dae8..e01931d7ad24a 100644 --- a/frame/conviction-voting/src/tests.rs +++ b/frame/conviction-voting/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/conviction-voting/src/types.rs b/frame/conviction-voting/src/types.rs index aa2406eef7110..2c45b54485bd9 100644 --- a/frame/conviction-voting/src/types.rs +++ b/frame/conviction-voting/src/types.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/conviction-voting/src/vote.rs b/frame/conviction-voting/src/vote.rs index 1fed70536d246..5ae08f0de65f2 100644 --- a/frame/conviction-voting/src/vote.rs +++ b/frame/conviction-voting/src/vote.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/conviction-voting/src/weights.rs b/frame/conviction-voting/src/weights.rs index c5c7123837755..a2f992b1f3a29 100644 --- a/frame/conviction-voting/src/weights.rs +++ b/frame/conviction-voting/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/democracy/src/benchmarking.rs b/frame/democracy/src/benchmarking.rs index f376b733aba6b..9a67ba698a662 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/democracy/src/conviction.rs b/frame/democracy/src/conviction.rs index a938d8a4e6852..d2f685f7d99ef 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/democracy/src/lib.rs b/frame/democracy/src/lib.rs index d9aae63ce6aae..b3ac3dfe78674 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/democracy/src/migrations.rs b/frame/democracy/src/migrations.rs index 3ec249c1d981c..fe2e445bd02a6 100644 --- a/frame/democracy/src/migrations.rs +++ b/frame/democracy/src/migrations.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/democracy/src/tests.rs b/frame/democracy/src/tests.rs index 9c7ec2906c677..eb1d2650afc45 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/democracy/src/tests/cancellation.rs b/frame/democracy/src/tests/cancellation.rs index ff046d612c026..4384fe6a1641a 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/democracy/src/tests/decoders.rs b/frame/democracy/src/tests/decoders.rs index 1c8b9c3d980f9..9cd725d97f64b 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/democracy/src/tests/delegation.rs b/frame/democracy/src/tests/delegation.rs index bca7cb9524112..710faf9192386 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/democracy/src/tests/external_proposing.rs b/frame/democracy/src/tests/external_proposing.rs index 4cfdd2aa74a3d..08b497ab4b90e 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/democracy/src/tests/fast_tracking.rs b/frame/democracy/src/tests/fast_tracking.rs index 09af3dbf3b5dd..85e7792a4c2ed 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/democracy/src/tests/lock_voting.rs b/frame/democracy/src/tests/lock_voting.rs index 540198ecf33a1..9b9172ff02b45 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/democracy/src/tests/metadata.rs b/frame/democracy/src/tests/metadata.rs index 95b617e37b199..59229abfe4aab 100644 --- a/frame/democracy/src/tests/metadata.rs +++ b/frame/democracy/src/tests/metadata.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/democracy/src/tests/public_proposals.rs b/frame/democracy/src/tests/public_proposals.rs index f9471442c6336..69a2d3e25686f 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/democracy/src/tests/scheduling.rs b/frame/democracy/src/tests/scheduling.rs index 5e133f38945d6..fdbc8fdb34947 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/democracy/src/tests/voting.rs b/frame/democracy/src/tests/voting.rs index 482cd430e0e7f..f096b633ee6d4 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/democracy/src/types.rs b/frame/democracy/src/types.rs index 25954e05498a6..ee6e2e0aa2537 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/democracy/src/vote.rs b/frame/democracy/src/vote.rs index 122f54febd8cf..c1b626fd9b7b9 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/democracy/src/vote_threshold.rs b/frame/democracy/src/vote_threshold.rs index e8ef91def9820..e8efa179ed8bf 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/democracy/src/weights.rs b/frame/democracy/src/weights.rs index 10d0744eac029..a2cdeead6f400 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) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/election-provider-multi-phase/src/benchmarking.rs b/frame/election-provider-multi-phase/src/benchmarking.rs index 16263d97da586..4d48f17909c0e 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/election-provider-multi-phase/src/helpers.rs b/frame/election-provider-multi-phase/src/helpers.rs index 0a7240c5d27af..57d580e93016c 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index 6c1b1d163d0fb..3ba90f4112a35 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/election-provider-multi-phase/src/migrations.rs b/frame/election-provider-multi-phase/src/migrations.rs index 77efe0d0c5e92..50b821e6db6ae 100644 --- a/frame/election-provider-multi-phase/src/migrations.rs +++ b/frame/election-provider-multi-phase/src/migrations.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/election-provider-multi-phase/src/mock.rs b/frame/election-provider-multi-phase/src/mock.rs index 347a4f19185f9..2ceaa6c23b70f 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/election-provider-multi-phase/src/signed.rs b/frame/election-provider-multi-phase/src/signed.rs index 895f3670a7f0d..d5d17e26b3051 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/election-provider-multi-phase/src/unsigned.rs b/frame/election-provider-multi-phase/src/unsigned.rs index cdc71f7bf5bf0..cff1e01d9e0be 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/election-provider-multi-phase/src/weights.rs b/frame/election-provider-multi-phase/src/weights.rs index 51bb7b0f10eba..f3ea218e451c5 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) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/election-provider-support/benchmarking/src/lib.rs b/frame/election-provider-support/benchmarking/src/lib.rs index 5323513da98d5..774b7036fd413 100644 --- a/frame/election-provider-support/benchmarking/src/lib.rs +++ b/frame/election-provider-support/benchmarking/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/election-provider-support/solution-type/src/codec.rs b/frame/election-provider-support/solution-type/src/codec.rs index 05d753d3d8456..3e91fc1ea92f6 100644 --- a/frame/election-provider-support/solution-type/src/codec.rs +++ b/frame/election-provider-support/solution-type/src/codec.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/election-provider-support/solution-type/src/from_assignment_helpers.rs b/frame/election-provider-support/solution-type/src/from_assignment_helpers.rs index e0613afc0d392..e8429b7f91cb5 100644 --- a/frame/election-provider-support/solution-type/src/from_assignment_helpers.rs +++ b/frame/election-provider-support/solution-type/src/from_assignment_helpers.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/election-provider-support/solution-type/src/index_assignment.rs b/frame/election-provider-support/solution-type/src/index_assignment.rs index ccdcb4ba25cdb..2518393038580 100644 --- a/frame/election-provider-support/solution-type/src/index_assignment.rs +++ b/frame/election-provider-support/solution-type/src/index_assignment.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/election-provider-support/solution-type/src/lib.rs b/frame/election-provider-support/solution-type/src/lib.rs index 0a5c11e76dedb..f79554321d54e 100644 --- a/frame/election-provider-support/solution-type/src/lib.rs +++ b/frame/election-provider-support/solution-type/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/election-provider-support/solution-type/src/single_page.rs b/frame/election-provider-support/solution-type/src/single_page.rs index a7ccf5085d2b1..688fee70a323b 100644 --- a/frame/election-provider-support/solution-type/src/single_page.rs +++ b/frame/election-provider-support/solution-type/src/single_page.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/election-provider-support/src/lib.rs b/frame/election-provider-support/src/lib.rs index 9e60eb3be1a6f..750ccca46213f 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/election-provider-support/src/mock.rs b/frame/election-provider-support/src/mock.rs index 0789ee90e6662..5cbe305eb522d 100644 --- a/frame/election-provider-support/src/mock.rs +++ b/frame/election-provider-support/src/mock.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/election-provider-support/src/onchain.rs b/frame/election-provider-support/src/onchain.rs index 483c402fe249c..296ac976d59f3 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/election-provider-support/src/tests.rs b/frame/election-provider-support/src/tests.rs index c38444f011dfe..73ce1427cf2f0 100644 --- a/frame/election-provider-support/src/tests.rs +++ b/frame/election-provider-support/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/election-provider-support/src/traits.rs b/frame/election-provider-support/src/traits.rs index ed812e2e0f2c4..43d183b338e29 100644 --- a/frame/election-provider-support/src/traits.rs +++ b/frame/election-provider-support/src/traits.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/election-provider-support/src/weights.rs b/frame/election-provider-support/src/weights.rs index 44075ba871228..fd4db1374ac4a 100644 --- a/frame/election-provider-support/src/weights.rs +++ b/frame/election-provider-support/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/elections-phragmen/src/benchmarking.rs b/frame/elections-phragmen/src/benchmarking.rs index b7c04bad318b0..56ea19578c8f5 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/elections-phragmen/src/lib.rs b/frame/elections-phragmen/src/lib.rs index 37ee44f34dc3d..fa63762c5e09a 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/elections-phragmen/src/migrations/mod.rs b/frame/elections-phragmen/src/migrations/mod.rs index 7c62e8fa93067..3c40c51b1456c 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/elections-phragmen/src/migrations/v3.rs b/frame/elections-phragmen/src/migrations/v3.rs index e48cd6c1a8056..204614a5b46cb 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/elections-phragmen/src/migrations/v4.rs b/frame/elections-phragmen/src/migrations/v4.rs index 535a9fb8201d7..7e946371f5ca6 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/elections-phragmen/src/weights.rs b/frame/elections-phragmen/src/weights.rs index a13dadf210ec0..24ab3bc15fbcd 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) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/examples/basic/src/benchmarking.rs b/frame/examples/basic/src/benchmarking.rs index a9e2013b0446c..0d2e9c5b3b1b3 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/examples/basic/src/lib.rs b/frame/examples/basic/src/lib.rs index d5045157dade7..a2b55bff1654e 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/examples/basic/src/tests.rs b/frame/examples/basic/src/tests.rs index 891c7c78628a1..2e6a03bdd857c 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/examples/basic/src/weights.rs b/frame/examples/basic/src/weights.rs index a69f0824eac11..4ea1e01d74bb0 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) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/examples/offchain-worker/src/lib.rs b/frame/examples/offchain-worker/src/lib.rs index 203ea2f27bacb..c9c72f8e82514 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/examples/offchain-worker/src/tests.rs b/frame/examples/offchain-worker/src/tests.rs index 2050d76a241ff..75a42e872ae52 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index b454d1e276cc8..573332294cb7f 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/fast-unstake/src/benchmarking.rs b/frame/fast-unstake/src/benchmarking.rs index e0e4186d78014..5ec997e8eaa2a 100644 --- a/frame/fast-unstake/src/benchmarking.rs +++ b/frame/fast-unstake/src/benchmarking.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/fast-unstake/src/lib.rs b/frame/fast-unstake/src/lib.rs index 82454a4b8ac7d..81eb3087b998e 100644 --- a/frame/fast-unstake/src/lib.rs +++ b/frame/fast-unstake/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/fast-unstake/src/migrations.rs b/frame/fast-unstake/src/migrations.rs index d2778d48b1b6e..e5ef919298a4f 100644 --- a/frame/fast-unstake/src/migrations.rs +++ b/frame/fast-unstake/src/migrations.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/fast-unstake/src/mock.rs b/frame/fast-unstake/src/mock.rs index 38cf41fdebe8b..b20ba43ab3758 100644 --- a/frame/fast-unstake/src/mock.rs +++ b/frame/fast-unstake/src/mock.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/fast-unstake/src/tests.rs b/frame/fast-unstake/src/tests.rs index 3e62146ae299f..1bb6fc100c94c 100644 --- a/frame/fast-unstake/src/tests.rs +++ b/frame/fast-unstake/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/fast-unstake/src/types.rs b/frame/fast-unstake/src/types.rs index 34ca6517f3168..3ec4b3a9b4d6e 100644 --- a/frame/fast-unstake/src/types.rs +++ b/frame/fast-unstake/src/types.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/fast-unstake/src/weights.rs b/frame/fast-unstake/src/weights.rs index f7d0cacba0bcf..d1c6595964ee0 100644 --- a/frame/fast-unstake/src/weights.rs +++ b/frame/fast-unstake/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/grandpa/src/benchmarking.rs b/frame/grandpa/src/benchmarking.rs index 6eee12ad98dbf..7a3849766d5ec 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/grandpa/src/default_weights.rs b/frame/grandpa/src/default_weights.rs index ba343cabac622..6b203783e2fd9 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/grandpa/src/equivocation.rs b/frame/grandpa/src/equivocation.rs index 23801a4982a82..8de8d7ae68380 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/grandpa/src/lib.rs b/frame/grandpa/src/lib.rs index ea534947ddd37..86751e23a31d3 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/grandpa/src/migrations.rs b/frame/grandpa/src/migrations.rs index f4a28fff13974..6307cbdd3b056 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/grandpa/src/migrations/v4.rs b/frame/grandpa/src/migrations/v4.rs index 33e200b728336..8604296b6e57b 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/grandpa/src/mock.rs b/frame/grandpa/src/mock.rs index 7d54966a498a6..0948be0080889 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/grandpa/src/tests.rs b/frame/grandpa/src/tests.rs index e090dcebb60bf..4fd5727d54ab2 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/identity/src/benchmarking.rs b/frame/identity/src/benchmarking.rs index 2d485af0f698b..4b51d23f6b34f 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/identity/src/lib.rs b/frame/identity/src/lib.rs index 39d828ef26f83..d1b764591dc79 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/identity/src/tests.rs b/frame/identity/src/tests.rs index baca70e2795fc..0e15f08ddd7e6 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/identity/src/types.rs b/frame/identity/src/types.rs index b1f15da3b1117..4d59a528021a0 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/identity/src/weights.rs b/frame/identity/src/weights.rs index 7bcbf539d617a..6475880528534 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) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/im-online/src/benchmarking.rs b/frame/im-online/src/benchmarking.rs index e4d1a64651408..f90dcd53b3ef9 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/im-online/src/lib.rs b/frame/im-online/src/lib.rs index 3be1f53fc418d..cdac51c9459c2 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/im-online/src/mock.rs b/frame/im-online/src/mock.rs index 783e68dfede9f..97b411e8719de 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/im-online/src/tests.rs b/frame/im-online/src/tests.rs index 2c026f7176b65..8cc7f38eb7b82 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/im-online/src/weights.rs b/frame/im-online/src/weights.rs index 4ea275a33f792..ee7cabf8ae2ee 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) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/indices/src/benchmarking.rs b/frame/indices/src/benchmarking.rs index ce1ea9f4d39f3..bd173815cb347 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/indices/src/lib.rs b/frame/indices/src/lib.rs index 0eaee0f4b9eb7..82dc48f7bce5b 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/indices/src/mock.rs b/frame/indices/src/mock.rs index 6b5373bb43b5a..6cf1f9d9740c9 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/indices/src/tests.rs b/frame/indices/src/tests.rs index bed6cfffaa825..56b1019000389 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/indices/src/weights.rs b/frame/indices/src/weights.rs index 36dd79ece4c9e..fcb71177a5951 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) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/insecure-randomness-collective-flip/src/lib.rs b/frame/insecure-randomness-collective-flip/src/lib.rs index 1d7ddc371173c..c73419efe87fe 100644 --- a/frame/insecure-randomness-collective-flip/src/lib.rs +++ b/frame/insecure-randomness-collective-flip/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/lottery/src/benchmarking.rs b/frame/lottery/src/benchmarking.rs index 0db7fabb365ef..9216464b07d35 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/lottery/src/lib.rs b/frame/lottery/src/lib.rs index 3255062e3fe7f..bd7ca40fb4556 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/lottery/src/mock.rs b/frame/lottery/src/mock.rs index 1977da5959d39..9b1a933d0a4ac 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/lottery/src/tests.rs b/frame/lottery/src/tests.rs index 0eaf080564008..09386c7e348d8 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/lottery/src/weights.rs b/frame/lottery/src/weights.rs index e2cf9ea2b74cc..e7857b230cd44 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) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/membership/src/lib.rs b/frame/membership/src/lib.rs index 8b39a08ce6699..04263b93e1a89 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/membership/src/migrations/mod.rs b/frame/membership/src/migrations/mod.rs index 235d0f1c7cf15..2487ed1d5da52 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/membership/src/migrations/v4.rs b/frame/membership/src/migrations/v4.rs index cbc58cd6ae917..38e97af51a09d 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/membership/src/weights.rs b/frame/membership/src/weights.rs index 1be50afc5254d..17f4b2f84ec6d 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) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/merkle-mountain-range/src/benchmarking.rs b/frame/merkle-mountain-range/src/benchmarking.rs index 7731c0e505c97..9eb676a4ee44b 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/merkle-mountain-range/src/default_weights.rs b/frame/merkle-mountain-range/src/default_weights.rs index e4f9750fbcba5..5d2e37cddce8b 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/merkle-mountain-range/src/lib.rs b/frame/merkle-mountain-range/src/lib.rs index 170c1d724f3a2..0b4c2f8d97a8b 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/merkle-mountain-range/src/mmr/mmr.rs b/frame/merkle-mountain-range/src/mmr/mmr.rs index cdb189a14b66d..beb4ac977c3be 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/merkle-mountain-range/src/mmr/mod.rs b/frame/merkle-mountain-range/src/mmr/mod.rs index 51de294753151..536faa68e4e9f 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/merkle-mountain-range/src/mmr/storage.rs b/frame/merkle-mountain-range/src/mmr/storage.rs index 2e3b174f3943a..d7466784e4ab8 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/merkle-mountain-range/src/mock.rs b/frame/merkle-mountain-range/src/mock.rs index 3fd44275857c1..292c80a483325 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/merkle-mountain-range/src/tests.rs b/frame/merkle-mountain-range/src/tests.rs index b5f9a78ede010..b628b51d2938b 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/message-queue/src/benchmarking.rs b/frame/message-queue/src/benchmarking.rs index 97ca71ce9d7d2..b53527048ac61 100644 --- a/frame/message-queue/src/benchmarking.rs +++ b/frame/message-queue/src/benchmarking.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/message-queue/src/integration_test.rs b/frame/message-queue/src/integration_test.rs index c9e3b2e870fd8..b89c7808613dd 100644 --- a/frame/message-queue/src/integration_test.rs +++ b/frame/message-queue/src/integration_test.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/message-queue/src/lib.rs b/frame/message-queue/src/lib.rs index 8d9faebe0517f..2b64e3fc9b174 100644 --- a/frame/message-queue/src/lib.rs +++ b/frame/message-queue/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/message-queue/src/mock.rs b/frame/message-queue/src/mock.rs index 37e504ac50033..8817ebc3531ed 100644 --- a/frame/message-queue/src/mock.rs +++ b/frame/message-queue/src/mock.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/message-queue/src/mock_helpers.rs b/frame/message-queue/src/mock_helpers.rs index f12cf4cc41073..64fc70057cca4 100644 --- a/frame/message-queue/src/mock_helpers.rs +++ b/frame/message-queue/src/mock_helpers.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/message-queue/src/tests.rs b/frame/message-queue/src/tests.rs index 103fb690ddba7..f4cbd81ac6667 100644 --- a/frame/message-queue/src/tests.rs +++ b/frame/message-queue/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/message-queue/src/weights.rs b/frame/message-queue/src/weights.rs index 325fc208301de..be2f801f195a9 100644 --- a/frame/message-queue/src/weights.rs +++ b/frame/message-queue/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/multisig/src/benchmarking.rs b/frame/multisig/src/benchmarking.rs index 8993908b25acf..ebe19df5dc436 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/multisig/src/lib.rs b/frame/multisig/src/lib.rs index de20a9e5143d9..fb10838cedc44 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/multisig/src/migrations.rs b/frame/multisig/src/migrations.rs index 5085297cde433..2a9c858a5552f 100644 --- a/frame/multisig/src/migrations.rs +++ b/frame/multisig/src/migrations.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/multisig/src/tests.rs b/frame/multisig/src/tests.rs index 13493587caa2b..c5517195d149f 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/multisig/src/weights.rs b/frame/multisig/src/weights.rs index 46bf911f273d6..eff6a29803e04 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) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/nfts/src/benchmarking.rs b/frame/nfts/src/benchmarking.rs index 9e724a2f63111..efa0a7412ce16 100644 --- a/frame/nfts/src/benchmarking.rs +++ b/frame/nfts/src/benchmarking.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/nfts/src/common_functions.rs b/frame/nfts/src/common_functions.rs index 31f8a96614c6b..1ef6591db02b4 100644 --- a/frame/nfts/src/common_functions.rs +++ b/frame/nfts/src/common_functions.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/nfts/src/features/approvals.rs b/frame/nfts/src/features/approvals.rs index cb5279fd949db..408c441290fb4 100644 --- a/frame/nfts/src/features/approvals.rs +++ b/frame/nfts/src/features/approvals.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/nfts/src/features/atomic_swap.rs b/frame/nfts/src/features/atomic_swap.rs index bacaccdaedcbf..505056be95353 100644 --- a/frame/nfts/src/features/atomic_swap.rs +++ b/frame/nfts/src/features/atomic_swap.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/nfts/src/features/attributes.rs b/frame/nfts/src/features/attributes.rs index 51c75233c1d0c..e310a5e2e432f 100644 --- a/frame/nfts/src/features/attributes.rs +++ b/frame/nfts/src/features/attributes.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/nfts/src/features/buy_sell.rs b/frame/nfts/src/features/buy_sell.rs index 8ba5171f8d822..ad721e0748ad0 100644 --- a/frame/nfts/src/features/buy_sell.rs +++ b/frame/nfts/src/features/buy_sell.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/nfts/src/features/create_delete_collection.rs b/frame/nfts/src/features/create_delete_collection.rs index a2caa04bc8dc3..8187fff7fca77 100644 --- a/frame/nfts/src/features/create_delete_collection.rs +++ b/frame/nfts/src/features/create_delete_collection.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/nfts/src/features/create_delete_item.rs b/frame/nfts/src/features/create_delete_item.rs index 63d7a540c3ae6..0319f2c8a0f18 100644 --- a/frame/nfts/src/features/create_delete_item.rs +++ b/frame/nfts/src/features/create_delete_item.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/nfts/src/features/lock.rs b/frame/nfts/src/features/lock.rs index e96a30dfd2c7c..c28fdda983774 100644 --- a/frame/nfts/src/features/lock.rs +++ b/frame/nfts/src/features/lock.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/nfts/src/features/metadata.rs b/frame/nfts/src/features/metadata.rs index c4d355f1922fc..232262bdbb8fc 100644 --- a/frame/nfts/src/features/metadata.rs +++ b/frame/nfts/src/features/metadata.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/nfts/src/features/mod.rs b/frame/nfts/src/features/mod.rs index b77ee9bf2491b..752feaf5db858 100644 --- a/frame/nfts/src/features/mod.rs +++ b/frame/nfts/src/features/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/nfts/src/features/roles.rs b/frame/nfts/src/features/roles.rs index d6be9965a5e74..f3fa277b15617 100644 --- a/frame/nfts/src/features/roles.rs +++ b/frame/nfts/src/features/roles.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/nfts/src/features/settings.rs b/frame/nfts/src/features/settings.rs index 7c29711094112..91bff9dc683f8 100644 --- a/frame/nfts/src/features/settings.rs +++ b/frame/nfts/src/features/settings.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/nfts/src/features/transfer.rs b/frame/nfts/src/features/transfer.rs index 3a34f0b8c9fe9..998df81cd1fe1 100644 --- a/frame/nfts/src/features/transfer.rs +++ b/frame/nfts/src/features/transfer.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/nfts/src/impl_nonfungibles.rs b/frame/nfts/src/impl_nonfungibles.rs index 86d82b4021517..ac02355ba29ac 100644 --- a/frame/nfts/src/impl_nonfungibles.rs +++ b/frame/nfts/src/impl_nonfungibles.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/nfts/src/lib.rs b/frame/nfts/src/lib.rs index cec5ea7ffc09f..41313e6518867 100644 --- a/frame/nfts/src/lib.rs +++ b/frame/nfts/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/nfts/src/macros.rs b/frame/nfts/src/macros.rs index 07a8f3b9f9556..8b0b8358dd7ff 100644 --- a/frame/nfts/src/macros.rs +++ b/frame/nfts/src/macros.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/nfts/src/mock.rs b/frame/nfts/src/mock.rs index d0ef3cf0b12c6..a9db1a62c9d67 100644 --- a/frame/nfts/src/mock.rs +++ b/frame/nfts/src/mock.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/nfts/src/tests.rs b/frame/nfts/src/tests.rs index fce9073af2d02..fb8265007a261 100644 --- a/frame/nfts/src/tests.rs +++ b/frame/nfts/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/nfts/src/types.rs b/frame/nfts/src/types.rs index c2ecd61c23028..860f937aafc05 100644 --- a/frame/nfts/src/types.rs +++ b/frame/nfts/src/types.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/nfts/src/weights.rs b/frame/nfts/src/weights.rs index 40592c29988ed..dc59330f3e674 100644 --- a/frame/nfts/src/weights.rs +++ b/frame/nfts/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/nicks/src/lib.rs b/frame/nicks/src/lib.rs index 05d1a36395b94..b457cc2996dbf 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/nis/src/benchmarking.rs b/frame/nis/src/benchmarking.rs index 10d3a238a3f5e..6fc9fbc2bffa2 100644 --- a/frame/nis/src/benchmarking.rs +++ b/frame/nis/src/benchmarking.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/nis/src/lib.rs b/frame/nis/src/lib.rs index fa0163fb60bfe..9cae5e2aae5c1 100644 --- a/frame/nis/src/lib.rs +++ b/frame/nis/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/nis/src/mock.rs b/frame/nis/src/mock.rs index 585ed2d8b278f..8df9f89c16926 100644 --- a/frame/nis/src/mock.rs +++ b/frame/nis/src/mock.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/nis/src/tests.rs b/frame/nis/src/tests.rs index b5feb4df16aab..d0808367ee08c 100644 --- a/frame/nis/src/tests.rs +++ b/frame/nis/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/nis/src/weights.rs b/frame/nis/src/weights.rs index 07221f358cab6..36a169f16c52e 100644 --- a/frame/nis/src/weights.rs +++ b/frame/nis/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/node-authorization/src/lib.rs b/frame/node-authorization/src/lib.rs index 543ba24500ebc..d91a769b36ba0 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/node-authorization/src/mock.rs b/frame/node-authorization/src/mock.rs index fcf7ff0189332..b7c5957e15dee 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/node-authorization/src/tests.rs b/frame/node-authorization/src/tests.rs index d9db09db4f46f..4704b5adf2690 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/node-authorization/src/weights.rs b/frame/node-authorization/src/weights.rs index 63728c21b65c4..f1ff9580d5a43 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/nomination-pools/benchmarking/src/lib.rs b/frame/nomination-pools/benchmarking/src/lib.rs index 675a4a8324f43..3b6df669af8a3 100644 --- a/frame/nomination-pools/benchmarking/src/lib.rs +++ b/frame/nomination-pools/benchmarking/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/nomination-pools/benchmarking/src/mock.rs b/frame/nomination-pools/benchmarking/src/mock.rs index 06a66838594c7..4e188ea7ef189 100644 --- a/frame/nomination-pools/benchmarking/src/mock.rs +++ b/frame/nomination-pools/benchmarking/src/mock.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/nomination-pools/fuzzer/src/call.rs b/frame/nomination-pools/fuzzer/src/call.rs index 805cc265d96e0..5e82471201546 100644 --- a/frame/nomination-pools/fuzzer/src/call.rs +++ b/frame/nomination-pools/fuzzer/src/call.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/nomination-pools/runtime-api/src/lib.rs b/frame/nomination-pools/runtime-api/src/lib.rs index 94573bfdb2e33..881c3c36331b6 100644 --- a/frame/nomination-pools/runtime-api/src/lib.rs +++ b/frame/nomination-pools/runtime-api/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/nomination-pools/src/lib.rs b/frame/nomination-pools/src/lib.rs index 4a80168469570..f61a376443944 100644 --- a/frame/nomination-pools/src/lib.rs +++ b/frame/nomination-pools/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/nomination-pools/src/migration.rs b/frame/nomination-pools/src/migration.rs index 53087e763b99c..a1696326989e3 100644 --- a/frame/nomination-pools/src/migration.rs +++ b/frame/nomination-pools/src/migration.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/nomination-pools/src/tests.rs b/frame/nomination-pools/src/tests.rs index 46330051b7f4c..59fd17be51434 100644 --- a/frame/nomination-pools/src/tests.rs +++ b/frame/nomination-pools/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/nomination-pools/src/weights.rs b/frame/nomination-pools/src/weights.rs index ae73015940f80..c24689558edf3 100644 --- a/frame/nomination-pools/src/weights.rs +++ b/frame/nomination-pools/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/nomination-pools/test-staking/src/lib.rs b/frame/nomination-pools/test-staking/src/lib.rs index 933e42578d1a6..1587492582143 100644 --- a/frame/nomination-pools/test-staking/src/lib.rs +++ b/frame/nomination-pools/test-staking/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/nomination-pools/test-staking/src/mock.rs b/frame/nomination-pools/test-staking/src/mock.rs index c67aec0134b07..3d0ab2c6f35f3 100644 --- a/frame/nomination-pools/test-staking/src/mock.rs +++ b/frame/nomination-pools/test-staking/src/mock.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/offences/benchmarking/src/lib.rs b/frame/offences/benchmarking/src/lib.rs index b71321906cbdd..16d77335e1a82 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/offences/benchmarking/src/mock.rs b/frame/offences/benchmarking/src/mock.rs index 592e821a81d8c..233aa449d391c 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/offences/src/lib.rs b/frame/offences/src/lib.rs index 7858b02719c4c..6ba16161b320c 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/offences/src/migration.rs b/frame/offences/src/migration.rs index e8fab1c0babc7..95b94ba87cc9c 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/offences/src/mock.rs b/frame/offences/src/mock.rs index 63d2b0de34780..5fc987ebdafca 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/offences/src/tests.rs b/frame/offences/src/tests.rs index 266e05debf050..a5c18020bcaa3 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/preimage/src/benchmarking.rs b/frame/preimage/src/benchmarking.rs index 56361b88c2583..b719c28be641b 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/preimage/src/lib.rs b/frame/preimage/src/lib.rs index bf7d602057cac..74a3176b1144a 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/preimage/src/migration.rs b/frame/preimage/src/migration.rs index a5d15c23c758a..be352201da6cd 100644 --- a/frame/preimage/src/migration.rs +++ b/frame/preimage/src/migration.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/preimage/src/mock.rs b/frame/preimage/src/mock.rs index d81f5a9c3232c..23875ccb0ef7a 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/preimage/src/tests.rs b/frame/preimage/src/tests.rs index f480b9c36b670..63a178c408a3f 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/preimage/src/weights.rs b/frame/preimage/src/weights.rs index 394c76956db87..7d181be01b742 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) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/proxy/src/benchmarking.rs b/frame/proxy/src/benchmarking.rs index ef3df02dcc776..7244dd5f17472 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/proxy/src/lib.rs b/frame/proxy/src/lib.rs index dfe8c86ca5097..c26a53d1a0c40 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/proxy/src/tests.rs b/frame/proxy/src/tests.rs index 0e7db3512f15b..c49c344aca107 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/proxy/src/weights.rs b/frame/proxy/src/weights.rs index 53e368acae3f7..5e85e148a0397 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) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/ranked-collective/src/benchmarking.rs b/frame/ranked-collective/src/benchmarking.rs index ad81325becb5e..b610d10009a08 100644 --- a/frame/ranked-collective/src/benchmarking.rs +++ b/frame/ranked-collective/src/benchmarking.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/ranked-collective/src/lib.rs b/frame/ranked-collective/src/lib.rs index a65d184d6bf06..30bb280a1a4f8 100644 --- a/frame/ranked-collective/src/lib.rs +++ b/frame/ranked-collective/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/ranked-collective/src/tests.rs b/frame/ranked-collective/src/tests.rs index c11d4877d3577..91244a90b0b6a 100644 --- a/frame/ranked-collective/src/tests.rs +++ b/frame/ranked-collective/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/ranked-collective/src/weights.rs b/frame/ranked-collective/src/weights.rs index 2d5ed3afdb1e2..1f50441aabe36 100644 --- a/frame/ranked-collective/src/weights.rs +++ b/frame/ranked-collective/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/recovery/src/benchmarking.rs b/frame/recovery/src/benchmarking.rs index 48ca7dad766bb..2deb55bb69f24 100644 --- a/frame/recovery/src/benchmarking.rs +++ b/frame/recovery/src/benchmarking.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/recovery/src/lib.rs b/frame/recovery/src/lib.rs index 9c57ca79d2e47..b32d19d5dda1d 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/recovery/src/mock.rs b/frame/recovery/src/mock.rs index 05ca8e6a30a0e..1d21be801c85c 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/recovery/src/tests.rs b/frame/recovery/src/tests.rs index b037a8110147d..9381d6a881ef1 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/recovery/src/weights.rs b/frame/recovery/src/weights.rs index 73f61654a619a..7a67c716fafc6 100644 --- a/frame/recovery/src/weights.rs +++ b/frame/recovery/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/referenda/src/benchmarking.rs b/frame/referenda/src/benchmarking.rs index ea44beeb3994f..288c65feae567 100644 --- a/frame/referenda/src/benchmarking.rs +++ b/frame/referenda/src/benchmarking.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/referenda/src/branch.rs b/frame/referenda/src/branch.rs index d3744979fc547..499e623878317 100644 --- a/frame/referenda/src/branch.rs +++ b/frame/referenda/src/branch.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/referenda/src/lib.rs b/frame/referenda/src/lib.rs index 4491c1b40d197..dccc40112867d 100644 --- a/frame/referenda/src/lib.rs +++ b/frame/referenda/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/referenda/src/migration.rs b/frame/referenda/src/migration.rs index 39575556e4096..e15eb499b42fc 100644 --- a/frame/referenda/src/migration.rs +++ b/frame/referenda/src/migration.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/referenda/src/mock.rs b/frame/referenda/src/mock.rs index f6e19d06ed5f3..ade2a09a9f9a4 100644 --- a/frame/referenda/src/mock.rs +++ b/frame/referenda/src/mock.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/referenda/src/tests.rs b/frame/referenda/src/tests.rs index 034454cfcc265..f728350c37e6f 100644 --- a/frame/referenda/src/tests.rs +++ b/frame/referenda/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/referenda/src/types.rs b/frame/referenda/src/types.rs index 0763a71a95ba3..d61b8955443c2 100644 --- a/frame/referenda/src/types.rs +++ b/frame/referenda/src/types.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/referenda/src/weights.rs b/frame/referenda/src/weights.rs index ab49759516bd9..817e0d88d329d 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) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/remark/src/benchmarking.rs b/frame/remark/src/benchmarking.rs index ee93cb24a3f34..831946834963f 100644 --- a/frame/remark/src/benchmarking.rs +++ b/frame/remark/src/benchmarking.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/remark/src/lib.rs b/frame/remark/src/lib.rs index 80fe393c20f4a..8ca3cd395afb5 100644 --- a/frame/remark/src/lib.rs +++ b/frame/remark/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/remark/src/mock.rs b/frame/remark/src/mock.rs index 22467796cf37b..39f5d50ed28fd 100644 --- a/frame/remark/src/mock.rs +++ b/frame/remark/src/mock.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/remark/src/tests.rs b/frame/remark/src/tests.rs index 2278e3817b48a..51fb32b60fc1f 100644 --- a/frame/remark/src/tests.rs +++ b/frame/remark/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/remark/src/weights.rs b/frame/remark/src/weights.rs index 9142ed04c5108..0e18e10c69561 100644 --- a/frame/remark/src/weights.rs +++ b/frame/remark/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/root-offences/src/lib.rs b/frame/root-offences/src/lib.rs index ed039f46becc8..92f3e17b5e17e 100644 --- a/frame/root-offences/src/lib.rs +++ b/frame/root-offences/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/root-offences/src/mock.rs b/frame/root-offences/src/mock.rs index 273fbf614169d..0937c43d6e519 100644 --- a/frame/root-offences/src/mock.rs +++ b/frame/root-offences/src/mock.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/root-offences/src/tests.rs b/frame/root-offences/src/tests.rs index b0df4fcee5314..f96884d750da8 100644 --- a/frame/root-offences/src/tests.rs +++ b/frame/root-offences/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/root-testing/src/lib.rs b/frame/root-testing/src/lib.rs index da67904967853..ad0e4cfea7373 100644 --- a/frame/root-testing/src/lib.rs +++ b/frame/root-testing/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/scheduler/src/benchmarking.rs b/frame/scheduler/src/benchmarking.rs index 94a833bd98e0a..d56e007ec9a2a 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/scheduler/src/lib.rs b/frame/scheduler/src/lib.rs index 97aaaaf0da7de..95bfe8411f381 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/scheduler/src/migration.rs b/frame/scheduler/src/migration.rs index f71b9457f5166..e641d2895aa0c 100644 --- a/frame/scheduler/src/migration.rs +++ b/frame/scheduler/src/migration.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/scheduler/src/mock.rs b/frame/scheduler/src/mock.rs index 0aaac56667dcb..5a2328971964f 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/scheduler/src/tests.rs b/frame/scheduler/src/tests.rs index a261c6718616d..258e6a281dfa9 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/scheduler/src/weights.rs b/frame/scheduler/src/weights.rs index 9be3bfaef5723..6b786ef8b24dd 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) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/scored-pool/src/lib.rs b/frame/scored-pool/src/lib.rs index 5db9c6506d770..16d59b6609000 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/scored-pool/src/mock.rs b/frame/scored-pool/src/mock.rs index 951871dd83c5c..a91b1a60f4974 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/scored-pool/src/tests.rs b/frame/scored-pool/src/tests.rs index 8f4daff47cc44..96c94a6c1c652 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/session/benchmarking/src/lib.rs b/frame/session/benchmarking/src/lib.rs index a6c25f5e10549..7f64dc70f35d5 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/session/benchmarking/src/mock.rs b/frame/session/benchmarking/src/mock.rs index 0699640bc092a..4c4accbbfac8f 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/session/src/historical/mod.rs b/frame/session/src/historical/mod.rs index 45b4ba3c0a799..d9827679400b8 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/session/src/historical/offchain.rs b/frame/session/src/historical/offchain.rs index ececb8af5ad58..4185788cbbed0 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/session/src/historical/onchain.rs b/frame/session/src/historical/onchain.rs index c7160e2fcf531..97a7f02bd096e 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/session/src/historical/shared.rs b/frame/session/src/historical/shared.rs index faa91f7919860..297385dfb426e 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/session/src/lib.rs b/frame/session/src/lib.rs index 38a5c0f57f73c..7d5dd632493f3 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/session/src/migrations/mod.rs b/frame/session/src/migrations/mod.rs index 5981e87b677cc..3b15d0ac4646a 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/session/src/migrations/v1.rs b/frame/session/src/migrations/v1.rs index 6689ca7299f1e..394a1f4a5227c 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/session/src/mock.rs b/frame/session/src/mock.rs index 1138bd9543989..d6b8d9e207e02 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/session/src/tests.rs b/frame/session/src/tests.rs index 43809cc3a9de0..69337e016ea8a 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/session/src/weights.rs b/frame/session/src/weights.rs index aea9d9dbf526d..c01799ce53050 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) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/society/src/lib.rs b/frame/society/src/lib.rs index 4e83d938b2e2d..f3207dabdaf8f 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/society/src/mock.rs b/frame/society/src/mock.rs index 24544bf9e82dd..73565dedc7cd1 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/society/src/tests.rs b/frame/society/src/tests.rs index 0b42f77035776..8a5c626dea5b7 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/staking/reward-curve/src/lib.rs b/frame/staking/reward-curve/src/lib.rs index e1ea8aa7b15d5..ecf3af5537914 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/staking/reward-curve/tests/test.rs b/frame/staking/reward-curve/tests/test.rs index aa19b1782453d..339e003222492 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/staking/reward-fn/src/lib.rs b/frame/staking/reward-fn/src/lib.rs index cc9919c28cce3..2c7f4613b466e 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/staking/reward-fn/tests/test.rs b/frame/staking/reward-fn/tests/test.rs index a79137716fd28..d76d2ce5e8c09 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index a4366bbd8aa9a..ad7aab984bdca 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/staking/src/inflation.rs b/frame/staking/src/inflation.rs index c7519683c75d1..8b4a85b6c2d81 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 3672056534b75..d6345c2161f73 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/staking/src/migrations.rs b/frame/staking/src/migrations.rs index a8d360c098137..3c33ae2a35d62 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index 30db036d00056..e876940cb92d3 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index fc0bf082c7caf..99c2f6043ee2c 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 4b0e8133bc0b6..a030538878241 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/staking/src/slashing.rs b/frame/staking/src/slashing.rs index aeea0a1a58c63..f73e3a6f818a2 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/staking/src/testing_utils.rs b/frame/staking/src/testing_utils.rs index 0e0ac76523471..9bd231cce6c73 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index e200f621b3742..16bafae01e3c3 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/staking/src/weights.rs b/frame/staking/src/weights.rs index af2afa2b538d6..2c9e1b2669c8b 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) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/state-trie-migration/src/lib.rs b/frame/state-trie-migration/src/lib.rs index 23f73bb56b173..0ebb8122d4618 100644 --- a/frame/state-trie-migration/src/lib.rs +++ b/frame/state-trie-migration/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/state-trie-migration/src/weights.rs b/frame/state-trie-migration/src/weights.rs index 29b7f7ad47ca9..a833d816cd13a 100644 --- a/frame/state-trie-migration/src/weights.rs +++ b/frame/state-trie-migration/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/sudo/src/extension.rs b/frame/sudo/src/extension.rs index 068fa2ed928d5..c717ff3567268 100644 --- a/frame/sudo/src/extension.rs +++ b/frame/sudo/src/extension.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/sudo/src/lib.rs b/frame/sudo/src/lib.rs index 3a708b6d5d6b1..4d5149926ac29 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/sudo/src/mock.rs b/frame/sudo/src/mock.rs index f8a03836f8f0f..59a5cb6cc1a15 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/sudo/src/tests.rs b/frame/sudo/src/tests.rs index ae8f198736004..e924bc77cf69e 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/benchmark.rs b/frame/support/procedural/src/benchmark.rs index fa7fd44928659..6cf1d7ecc23af 100644 --- a/frame/support/procedural/src/benchmark.rs +++ b/frame/support/procedural/src/benchmark.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/clone_no_bound.rs b/frame/support/procedural/src/clone_no_bound.rs index bd2741c0d47ab..bbea2feffa96f 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/construct_runtime/expand/call.rs b/frame/support/procedural/src/construct_runtime/expand/call.rs index 8f07448f5785e..5ec665682ddaa 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/construct_runtime/expand/config.rs b/frame/support/procedural/src/construct_runtime/expand/config.rs index 9b731a5825a3c..4d73ebb11774a 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/construct_runtime/expand/event.rs b/frame/support/procedural/src/construct_runtime/expand/event.rs index b11fcef1bfd53..fcd9b32141ab5 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/construct_runtime/expand/inherent.rs b/frame/support/procedural/src/construct_runtime/expand/inherent.rs index 599b34ba87241..52586bd691d4e 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/construct_runtime/expand/metadata.rs b/frame/support/procedural/src/construct_runtime/expand/metadata.rs index ec90a0d30f98b..e9996121757d7 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/construct_runtime/expand/mod.rs b/frame/support/procedural/src/construct_runtime/expand/mod.rs index 6c92d2c3444ec..ace0b23bd7f85 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/construct_runtime/expand/origin.rs b/frame/support/procedural/src/construct_runtime/expand/origin.rs index 1551d85ea4c96..e48a70a9df973 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/construct_runtime/expand/unsigned.rs b/frame/support/procedural/src/construct_runtime/expand/unsigned.rs index 1d528779423a7..33aadba0d1f1c 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/construct_runtime/mod.rs b/frame/support/procedural/src/construct_runtime/mod.rs index 18b66ddff5ffa..37f23efed36c1 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/construct_runtime/parse.rs b/frame/support/procedural/src/construct_runtime/parse.rs index 7a5acf43b92b0..b0bebcd9e0f21 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/crate_version.rs b/frame/support/procedural/src/crate_version.rs index e2be6dd889db4..3f728abdb0b03 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/debug_no_bound.rs b/frame/support/procedural/src/debug_no_bound.rs index 56168edb87e83..ae182829a49eb 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/default_no_bound.rs b/frame/support/procedural/src/default_no_bound.rs index b174a49e91741..127b490878d07 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/key_prefix.rs b/frame/support/procedural/src/key_prefix.rs index 05582f1297eed..6f793d0e37bde 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index 67e592f4ca2db..fec824107f123 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/match_and_insert.rs b/frame/support/procedural/src/match_and_insert.rs index 79d1da7549c1d..aa9cc56d769d0 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/expand/call.rs b/frame/support/procedural/src/pallet/expand/call.rs index 30ef1a8fca31d..72367dc3957d9 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/expand/config.rs b/frame/support/procedural/src/pallet/expand/config.rs index 8ad34361d684a..c70f6eb80422a 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/expand/constants.rs b/frame/support/procedural/src/pallet/expand/constants.rs index 1f9526f9cebe0..21ac1de3642d5 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/expand/error.rs b/frame/support/procedural/src/pallet/expand/error.rs index 5a8487b09de5c..70f9fdfc71112 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/expand/event.rs b/frame/support/procedural/src/pallet/expand/event.rs index abed680eb245e..2f0cefb8b9fc3 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/expand/genesis_build.rs b/frame/support/procedural/src/pallet/expand/genesis_build.rs index d19476779011b..9447154f386dd 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/expand/genesis_config.rs b/frame/support/procedural/src/pallet/expand/genesis_config.rs index 739e85e0d1ced..85ad20dd45c9e 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/expand/hooks.rs b/frame/support/procedural/src/pallet/expand/hooks.rs index 987d0691b1ecc..711b78e642d9f 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/expand/inherent.rs b/frame/support/procedural/src/pallet/expand/inherent.rs index 71d95f958fcd2..182d79f5b0a9e 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/expand/instances.rs b/frame/support/procedural/src/pallet/expand/instances.rs index 52dc887635503..b6dfa7e6d9e9c 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/expand/mod.rs b/frame/support/procedural/src/pallet/expand/mod.rs index c33d2386700b2..3ccbf91b4f130 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/expand/origin.rs b/frame/support/procedural/src/pallet/expand/origin.rs index 721fc781a907c..55865b42491a3 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/expand/pallet_struct.rs b/frame/support/procedural/src/pallet/expand/pallet_struct.rs index e5941a33fee13..27fe9d3401ea2 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/expand/storage.rs b/frame/support/procedural/src/pallet/expand/storage.rs index 0bb19ad6c29cd..05d61bb522180 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/expand/store_trait.rs b/frame/support/procedural/src/pallet/expand/store_trait.rs index 4fb4f46143a14..15a6a223e9708 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/expand/tt_default_parts.rs b/frame/support/procedural/src/pallet/expand/tt_default_parts.rs index 173dcc0e2ac3f..564b526e93536 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/expand/type_value.rs b/frame/support/procedural/src/pallet/expand/type_value.rs index abe52459a791d..5dc6309c074a6 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/expand/validate_unsigned.rs b/frame/support/procedural/src/pallet/expand/validate_unsigned.rs index b49ba2b5b02ea..8769955851712 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/mod.rs b/frame/support/procedural/src/pallet/mod.rs index 3f85be81c1f7d..31048841c64e7 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/parse/call.rs b/frame/support/procedural/src/pallet/parse/call.rs index 3af3225484fae..5b90c2d98b85e 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/parse/config.rs b/frame/support/procedural/src/pallet/parse/config.rs index 0f3aa69b170ce..4d22e50ef2bbf 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/parse/error.rs b/frame/support/procedural/src/pallet/parse/error.rs index c6ce9b37c75a2..f344c5d27a877 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/parse/event.rs b/frame/support/procedural/src/pallet/parse/event.rs index e046cacac88e8..64c3afd557335 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/parse/extra_constants.rs b/frame/support/procedural/src/pallet/parse/extra_constants.rs index d8622da08461b..8e85d2c2622d5 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/parse/genesis_build.rs b/frame/support/procedural/src/pallet/parse/genesis_build.rs index 9815b8d2203c4..6d356b2ee3844 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/parse/genesis_config.rs b/frame/support/procedural/src/pallet/parse/genesis_config.rs index 45e765c018aae..62da6ba13b3be 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/parse/helper.rs b/frame/support/procedural/src/pallet/parse/helper.rs index 8244079173581..4814dce5a3dfa 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/parse/hooks.rs b/frame/support/procedural/src/pallet/parse/hooks.rs index 2dc8f4da47c5f..f941df5f29272 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/parse/inherent.rs b/frame/support/procedural/src/pallet/parse/inherent.rs index a485eed4c40d9..d8641691a40e3 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/parse/mod.rs b/frame/support/procedural/src/pallet/parse/mod.rs index f91159248281c..94e6f7a7c2f7d 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/parse/origin.rs b/frame/support/procedural/src/pallet/parse/origin.rs index 89929e3e8dbfc..76e2a8841196b 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/parse/pallet_struct.rs b/frame/support/procedural/src/pallet/parse/pallet_struct.rs index a96c310b6f1ca..571298d5a12ec 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/parse/storage.rs b/frame/support/procedural/src/pallet/parse/storage.rs index 8b551ab31d6c3..3ed7ce54ebd64 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/parse/type_value.rs b/frame/support/procedural/src/pallet/parse/type_value.rs index a3d004cd8a532..4b80506889dfd 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet/parse/validate_unsigned.rs b/frame/support/procedural/src/pallet/parse/validate_unsigned.rs index 18d5a2dc4443f..2bf0a1b6c1886 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/pallet_error.rs b/frame/support/procedural/src/pallet_error.rs index 216168131e43d..fb0bf52f69094 100644 --- a/frame/support/procedural/src/pallet_error.rs +++ b/frame/support/procedural/src/pallet_error.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/partial_eq_no_bound.rs b/frame/support/procedural/src/partial_eq_no_bound.rs index 31930c0c3dae3..27f5e98810ec3 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/storage/genesis_config/builder_def.rs b/frame/support/procedural/src/storage/genesis_config/builder_def.rs index 29e2560bc16e4..5b8e4eb7603fc 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/storage/genesis_config/genesis_config_def.rs b/frame/support/procedural/src/storage/genesis_config/genesis_config_def.rs index d24e50096f25e..491db59184fd9 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/storage/genesis_config/mod.rs b/frame/support/procedural/src/storage/genesis_config/mod.rs index d4348ee19171c..57c938368bc90 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/storage/getters.rs b/frame/support/procedural/src/storage/getters.rs index 9fe3734e6889c..428b2ec453407 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/storage/instance_trait.rs b/frame/support/procedural/src/storage/instance_trait.rs index e9df02e3dc132..8b5aa500550ef 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/storage/metadata.rs b/frame/support/procedural/src/storage/metadata.rs index d1879d1509f8d..3e3e0576f63b5 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/storage/mod.rs b/frame/support/procedural/src/storage/mod.rs index e8e2d7529cb3f..1e48a1fbb06d1 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/storage/parse.rs b/frame/support/procedural/src/storage/parse.rs index 54026b7d78b19..f9f62e0ff3123 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/storage/storage_info.rs b/frame/support/procedural/src/storage/storage_info.rs index 77515fa739b2b..3e851b04231ac 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/storage/storage_struct.rs b/frame/support/procedural/src/storage/storage_struct.rs index 649a41bab5ece..373e722122235 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/storage/store_trait.rs b/frame/support/procedural/src/storage/store_trait.rs index daf933b3b770c..5dca502518a33 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/storage_alias.rs b/frame/support/procedural/src/storage_alias.rs index eaf8591a1d999..7699568721788 100644 --- a/frame/support/procedural/src/storage_alias.rs +++ b/frame/support/procedural/src/storage_alias.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/transactional.rs b/frame/support/procedural/src/transactional.rs index eb77a320a509f..23117ffa39c4e 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/src/tt_macro.rs b/frame/support/procedural/src/tt_macro.rs index 0a270a7173cfc..69b5eb3d5521a 100644 --- a/frame/support/procedural/src/tt_macro.rs +++ b/frame/support/procedural/src/tt_macro.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/tools/derive/src/lib.rs b/frame/support/procedural/tools/derive/src/lib.rs index 392a438342017..f7c57c08674fc 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/tools/src/lib.rs b/frame/support/procedural/tools/src/lib.rs index 3abde59574119..385b20ad05dc8 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/procedural/tools/src/syn_ext.rs b/frame/support/procedural/tools/src/syn_ext.rs index 1a2d7c1d372ad..833cd17dfacb4 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/crypto.rs b/frame/support/src/crypto.rs index 182a784649d02..1957a7bc97cea 100644 --- a/frame/support/src/crypto.rs +++ b/frame/support/src/crypto.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/crypto/ecdsa.rs b/frame/support/src/crypto/ecdsa.rs index a4a04acabe1df..afa45e296d3fd 100644 --- a/frame/support/src/crypto/ecdsa.rs +++ b/frame/support/src/crypto/ecdsa.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/dispatch.rs b/frame/support/src/dispatch.rs index 291abdd12893f..c26a3d8e71a36 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/error.rs b/frame/support/src/error.rs index 337bd75895c2c..72d13dfcef164 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/event.rs b/frame/support/src/event.rs index dc45f2bf69d94..ce9e0dbb70a46 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/hash.rs b/frame/support/src/hash.rs index 9bdad6d9d59de..bf9eb2f88b0b1 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/inherent.rs b/frame/support/src/inherent.rs index 0aa6b9d3f75a9..dce61378de8b8 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/instances.rs b/frame/support/src/instances.rs index 81139f8671818..482051c1f36d0 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 77ca89dc6f800..c11c902d64dd2 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/migrations.rs b/frame/support/src/migrations.rs index 63679fd56d667..645316042b38c 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/storage/bounded_btree_map.rs b/frame/support/src/storage/bounded_btree_map.rs index d567faa38fdc1..f2f32d890b87b 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/storage/bounded_btree_set.rs b/frame/support/src/storage/bounded_btree_set.rs index 9ed129e67c46c..52be1bb99f101 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/storage/bounded_vec.rs b/frame/support/src/storage/bounded_vec.rs index 1fa01b44ae6c4..59b716b3ae5c6 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/storage/child.rs b/frame/support/src/storage/child.rs index 397daaa82a677..76b9c554d65f9 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/storage/generator/double_map.rs b/frame/support/src/storage/generator/double_map.rs index b60bb79566d51..5763a472cd570 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/storage/generator/map.rs b/frame/support/src/storage/generator/map.rs index f6c8eaa270bb3..fb499384f1506 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/storage/generator/mod.rs b/frame/support/src/storage/generator/mod.rs index 334e9b9e24e86..2da612b24de8f 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/storage/generator/nmap.rs b/frame/support/src/storage/generator/nmap.rs index 8cf1459431171..21fe7b41eda99 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/storage/generator/value.rs b/frame/support/src/storage/generator/value.rs index 4a1fd5c551d3f..4ffe40bac53ca 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/storage/hashed.rs b/frame/support/src/storage/hashed.rs index 19c9d73be868d..6633adce8ff65 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/storage/migration.rs b/frame/support/src/storage/migration.rs index 67001fc4e1f42..8e945afdb6441 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/storage/mod.rs b/frame/support/src/storage/mod.rs index dd91d8cc2a335..4c6ea943c6920 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/storage/storage_noop_guard.rs b/frame/support/src/storage/storage_noop_guard.rs index 7186c3eaf467a..f2fb60027ec37 100644 --- a/frame/support/src/storage/storage_noop_guard.rs +++ b/frame/support/src/storage/storage_noop_guard.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/storage/stream_iter.rs b/frame/support/src/storage/stream_iter.rs index 4e25ca6ca1f6c..e784ebd14c52a 100644 --- a/frame/support/src/storage/stream_iter.rs +++ b/frame/support/src/storage/stream_iter.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/storage/transactional.rs b/frame/support/src/storage/transactional.rs index b7ae22d86727c..d42e1809e9129 100644 --- a/frame/support/src/storage/transactional.rs +++ b/frame/support/src/storage/transactional.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/storage/types/counted_map.rs b/frame/support/src/storage/types/counted_map.rs index 7d7d9ebcf70cf..24b00be485e49 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/storage/types/double_map.rs b/frame/support/src/storage/types/double_map.rs index 9ba4cf052e82a..6a4bdc1e68d72 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/storage/types/key.rs b/frame/support/src/storage/types/key.rs index 182ddbedd9b8e..901bdb8b0514c 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/storage/types/map.rs b/frame/support/src/storage/types/map.rs index 3e2b744d72f89..53cf74d26f17c 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/storage/types/mod.rs b/frame/support/src/storage/types/mod.rs index f87da5de12274..9a6f15d1ee820 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/storage/types/nmap.rs b/frame/support/src/storage/types/nmap.rs index dcbdac761fe15..d971035968ff2 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/storage/types/value.rs b/frame/support/src/storage/types/value.rs index 15290f1b1e085..64fb432b2dab1 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/storage/unhashed.rs b/frame/support/src/storage/unhashed.rs index 8388c5f885c51..aae83034ab71a 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/storage/weak_bounded_vec.rs b/frame/support/src/storage/weak_bounded_vec.rs index 72ba8d775a1d3..41d27b51a12fd 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index f7b57f446fee8..a649dad40078d 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/dispatch.rs b/frame/support/src/traits/dispatch.rs index 50c6c22791944..6961e69ba5750 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/error.rs b/frame/support/src/traits/error.rs index 8e26891669e65..0f30e266da2df 100644 --- a/frame/support/src/traits/error.rs +++ b/frame/support/src/traits/error.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/filter.rs b/frame/support/src/traits/filter.rs index cdd82a3124e63..36420b46f0315 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/hooks.rs b/frame/support/src/traits/hooks.rs index 3f7db1fa046bd..fe67e33d1832c 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/members.rs b/frame/support/src/traits/members.rs index daf2d3aa6517d..f336b460c8f1e 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/messages.rs b/frame/support/src/traits/messages.rs index 9b86c421ad9e0..637aa7fdc045b 100644 --- a/frame/support/src/traits/messages.rs +++ b/frame/support/src/traits/messages.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/metadata.rs b/frame/support/src/traits/metadata.rs index 42f2d759a597d..f3e4b955da4a9 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/misc.rs b/frame/support/src/traits/misc.rs index 5a13fc4ab6509..a320b85eac557 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/preimages.rs b/frame/support/src/traits/preimages.rs index ce3537c792c08..db8abdbdc79bb 100644 --- a/frame/support/src/traits/preimages.rs +++ b/frame/support/src/traits/preimages.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/randomness.rs b/frame/support/src/traits/randomness.rs index d68b95b1dfcf5..3666a486465f9 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/schedule.rs b/frame/support/src/traits/schedule.rs index b8e6a7f807904..4e17092ae329b 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/storage.rs b/frame/support/src/traits/storage.rs index 8285ab988d5b1..c3394185a7743 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/stored_map.rs b/frame/support/src/traits/stored_map.rs index 2aae88096ec74..a073b268252ad 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/tokens.rs b/frame/support/src/traits/tokens.rs index 03a24bd3ba9c8..6055fde2180f0 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/tokens/currency.rs b/frame/support/src/traits/tokens/currency.rs index 48247b6021798..3f6f6b8e7384b 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/tokens/currency/lockable.rs b/frame/support/src/traits/tokens/currency/lockable.rs index a10edd6e3e874..955814f5aa9de 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/tokens/currency/reservable.rs b/frame/support/src/traits/tokens/currency/reservable.rs index 53f6764c3a1ac..aa097a756d4df 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/tokens/fungible.rs b/frame/support/src/traits/tokens/fungible.rs index a36e63e717f94..12bac29727dd4 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/tokens/fungible/balanced.rs b/frame/support/src/traits/tokens/fungible/balanced.rs index 0e75ccc22d050..437d2c82defee 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/tokens/fungible/imbalance.rs b/frame/support/src/traits/tokens/fungible/imbalance.rs index ca911cf12d44c..1b3d16c62ddf4 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/tokens/fungibles.rs b/frame/support/src/traits/tokens/fungibles.rs index a29cb974fe450..d146832f3b649 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/tokens/fungibles/approvals.rs b/frame/support/src/traits/tokens/fungibles/approvals.rs index 48929955d9497..7a80279b01981 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/tokens/fungibles/balanced.rs b/frame/support/src/traits/tokens/fungibles/balanced.rs index 9e50ff834a874..598ba250ee806 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/tokens/fungibles/enumerable.rs b/frame/support/src/traits/tokens/fungibles/enumerable.rs index 151d15b3684a5..5d7266d9f2c16 100644 --- a/frame/support/src/traits/tokens/fungibles/enumerable.rs +++ b/frame/support/src/traits/tokens/fungibles/enumerable.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/tokens/fungibles/imbalance.rs b/frame/support/src/traits/tokens/fungibles/imbalance.rs index 61bd4a43064e6..87445859cb5c7 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/tokens/fungibles/metadata.rs b/frame/support/src/traits/tokens/fungibles/metadata.rs index b736ab1489f58..64f8bf094fb0e 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/tokens/fungibles/roles.rs b/frame/support/src/traits/tokens/fungibles/roles.rs index 18fd1cc801210..5cd1228afbce7 100644 --- a/frame/support/src/traits/tokens/fungibles/roles.rs +++ b/frame/support/src/traits/tokens/fungibles/roles.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/tokens/imbalance.rs b/frame/support/src/traits/tokens/imbalance.rs index d721beb41494c..403321725042c 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/tokens/imbalance/on_unbalanced.rs b/frame/support/src/traits/tokens/imbalance/on_unbalanced.rs index 0125254cefc85..27bfe46e181e2 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/tokens/imbalance/signed_imbalance.rs b/frame/support/src/traits/tokens/imbalance/signed_imbalance.rs index f969a4363405a..03e821b161b69 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/tokens/imbalance/split_two_ways.rs b/frame/support/src/traits/tokens/imbalance/split_two_ways.rs index b963895af0de5..c1afac35fc93c 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/tokens/misc.rs b/frame/support/src/traits/tokens/misc.rs index f9876ef477b81..b4bd4640116a7 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/tokens/nonfungible.rs b/frame/support/src/traits/tokens/nonfungible.rs index 46ca573131127..e3fc84f1d57b2 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/tokens/nonfungible_v2.rs b/frame/support/src/traits/tokens/nonfungible_v2.rs index e1899020bb336..36ef9ab0aa63f 100644 --- a/frame/support/src/traits/tokens/nonfungible_v2.rs +++ b/frame/support/src/traits/tokens/nonfungible_v2.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/tokens/nonfungibles.rs b/frame/support/src/traits/tokens/nonfungibles.rs index ac007b5a67f1d..e9538d14f5471 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/tokens/nonfungibles_v2.rs b/frame/support/src/traits/tokens/nonfungibles_v2.rs index 17c5d887defc0..9331f966822a6 100644 --- a/frame/support/src/traits/tokens/nonfungibles_v2.rs +++ b/frame/support/src/traits/tokens/nonfungibles_v2.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/try_runtime.rs b/frame/support/src/traits/try_runtime.rs index cb4902201f1e8..6103f07a73c78 100644 --- a/frame/support/src/traits/try_runtime.rs +++ b/frame/support/src/traits/try_runtime.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/validation.rs b/frame/support/src/traits/validation.rs index 135dd927acbb2..84430901b9783 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/traits/voting.rs b/frame/support/src/traits/voting.rs index 49ae3163d0cd1..caec472785782 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/weights.rs b/frame/support/src/weights.rs index d52380b832fc4..75eba8fbe9883 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/weights/block_weights.rs b/frame/support/src/weights/block_weights.rs index dc01107cec01f..a208c77aa28c1 100644 --- a/frame/support/src/weights/block_weights.rs +++ b/frame/support/src/weights/block_weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/weights/extrinsic_weights.rs b/frame/support/src/weights/extrinsic_weights.rs index 3d25d5a4025c9..4e3a0fda8d2f5 100644 --- a/frame/support/src/weights/extrinsic_weights.rs +++ b/frame/support/src/weights/extrinsic_weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/weights/paritydb_weights.rs b/frame/support/src/weights/paritydb_weights.rs index 6fd1112ee2947..f69fc0cd93c62 100644 --- a/frame/support/src/weights/paritydb_weights.rs +++ b/frame/support/src/weights/paritydb_weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/weights/rocksdb_weights.rs b/frame/support/src/weights/rocksdb_weights.rs index b18b387de9957..25d2ac1cdec04 100644 --- a/frame/support/src/weights/rocksdb_weights.rs +++ b/frame/support/src/weights/rocksdb_weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/test/compile_pass/src/lib.rs b/frame/support/test/compile_pass/src/lib.rs index b46f6c48a6d99..1ff72bea5dd13 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/frame/support/test/pallet/src/lib.rs b/frame/support/test/pallet/src/lib.rs index 37678e056f3e1..82f12ea954614 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/test/src/lib.rs b/frame/support/test/src/lib.rs index 0ceeed42ff982..c0b025380dd45 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/test/src/pallet_version.rs b/frame/support/test/src/pallet_version.rs index 096289116c419..b015699685a44 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/test/tests/benchmark_ui.rs b/frame/support/test/tests/benchmark_ui.rs index 243030bd07fcd..aa5fadd0e27bf 100644 --- a/frame/support/test/tests/benchmark_ui.rs +++ b/frame/support/test/tests/benchmark_ui.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/test/tests/construct_runtime.rs b/frame/support/test/tests/construct_runtime.rs index 18e4af1ac3739..0965577149d17 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/test/tests/construct_runtime_ui.rs b/frame/support/test/tests/construct_runtime_ui.rs index 42fd87ca95c0e..ec6758f4b295f 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/test/tests/decl_module_ui.rs b/frame/support/test/tests/decl_module_ui.rs index 292451335e7ea..296ae3e586f54 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/test/tests/decl_storage.rs b/frame/support/test/tests/decl_storage.rs index a4e420eb454b6..c2ee7742426bb 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/test/tests/decl_storage_ui.rs b/frame/support/test/tests/decl_storage_ui.rs index 34dfea8601ab9..1414c8a994520 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/test/tests/decl_storage_ui/config_duplicate.rs b/frame/support/test/tests/decl_storage_ui/config_duplicate.rs index af74823f64ca6..a6e1bfad5836b 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/test/tests/decl_storage_ui/config_get_duplicate.rs b/frame/support/test/tests/decl_storage_ui/config_get_duplicate.rs index 8805effd9e725..c40dd0e44f11b 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/test/tests/decl_storage_ui/get_duplicate.rs b/frame/support/test/tests/decl_storage_ui/get_duplicate.rs index 5e05887110537..23c89d276ef39 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/test/tests/derive_no_bound.rs b/frame/support/test/tests/derive_no_bound.rs index 9162b5013bcdc..8b1394fcd590b 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/test/tests/derive_no_bound_ui.rs b/frame/support/test/tests/derive_no_bound_ui.rs index d714e1113625a..b1c9283c0925a 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/test/tests/final_keys.rs b/frame/support/test/tests/final_keys.rs index a7ad88c801001..9e1d6c0876740 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/test/tests/genesisconfig.rs b/frame/support/test/tests/genesisconfig.rs index f0094b3188ae1..869641df87060 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/test/tests/instance.rs b/frame/support/test/tests/instance.rs index 043959b67ee6e..28bd5c8c57ddc 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/test/tests/issue2219.rs b/frame/support/test/tests/issue2219.rs index 5d24d54165c1f..da3226d624916 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/test/tests/origin.rs b/frame/support/test/tests/origin.rs index f794cd8be1ce0..996b996c8c49c 100644 --- a/frame/support/test/tests/origin.rs +++ b/frame/support/test/tests/origin.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/test/tests/pallet.rs b/frame/support/test/tests/pallet.rs index 36150b28058a7..7dd9aa0ddaf66 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/test/tests/pallet_compatibility.rs b/frame/support/test/tests/pallet_compatibility.rs index 300fb9a40cf4e..8b0573398bd1d 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/test/tests/pallet_compatibility_instance.rs b/frame/support/test/tests/pallet_compatibility_instance.rs index 79370d911b943..5cc1c1f4478e7 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/test/tests/pallet_instance.rs b/frame/support/test/tests/pallet_instance.rs index 7fec0aa9d0e07..ea1e27fe9f348 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/test/tests/pallet_ui.rs b/frame/support/test/tests/pallet_ui.rs index 26d016c5a7796..466957c9faa63 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/test/tests/pallet_with_name_trait_is_valid.rs b/frame/support/test/tests/pallet_with_name_trait_is_valid.rs index 0066420566fe8..43330dbe25b41 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/test/tests/storage_alias_ui.rs b/frame/support/test/tests/storage_alias_ui.rs index d45d071578dab..b82acd8f3be43 100644 --- a/frame/support/test/tests/storage_alias_ui.rs +++ b/frame/support/test/tests/storage_alias_ui.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/test/tests/storage_layers.rs b/frame/support/test/tests/storage_layers.rs index cff81c0bea2ed..c5bbbae02e111 100644 --- a/frame/support/test/tests/storage_layers.rs +++ b/frame/support/test/tests/storage_layers.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/test/tests/storage_transaction.rs b/frame/support/test/tests/storage_transaction.rs index 6fedd75019e37..769ecb29a8db2 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/test/tests/system.rs b/frame/support/test/tests/system.rs index eff41242917a0..1a938ad4e80db 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/system/benches/bench.rs b/frame/system/benches/bench.rs index f2acc319d3f5d..51652727c4766 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/system/benchmarking/src/lib.rs b/frame/system/benchmarking/src/lib.rs index 87d3c7fc7044b..ef06729749422 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/system/benchmarking/src/mock.rs b/frame/system/benchmarking/src/mock.rs index a7f28ca30fe87..8da623a3abbb5 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/system/rpc/runtime-api/src/lib.rs b/frame/system/rpc/runtime-api/src/lib.rs index 6e01bdae2d150..2ea9f2f62e11c 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/system/src/extensions/check_genesis.rs b/frame/system/src/extensions/check_genesis.rs index f5811f306cfe3..5964ec452842f 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/system/src/extensions/check_mortality.rs b/frame/system/src/extensions/check_mortality.rs index 635ab4ef1d9a9..739a27a2ae139 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/system/src/extensions/check_non_zero_sender.rs b/frame/system/src/extensions/check_non_zero_sender.rs index 036f70c2fdd48..b0b6704fe78ee 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/system/src/extensions/check_nonce.rs b/frame/system/src/extensions/check_nonce.rs index 1616a2d8a119e..57ebd7701ef6a 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/system/src/extensions/check_spec_version.rs b/frame/system/src/extensions/check_spec_version.rs index ef5f40402692c..24d5ef9cafb17 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/system/src/extensions/check_tx_version.rs b/frame/system/src/extensions/check_tx_version.rs index be0b8fe2354aa..3f9d6a1903fe1 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/system/src/extensions/check_weight.rs b/frame/system/src/extensions/check_weight.rs index 590d05474f91a..ca5f7a82c0e8b 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/system/src/extensions/mod.rs b/frame/system/src/extensions/mod.rs index 9ba73c5f4d4e5..a88c9fbf96ebd 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index c22a68296a159..5e921ab854df1 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/system/src/limits.rs b/frame/system/src/limits.rs index 54d27c5b9e86d..5fd7a5af87571 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/system/src/migrations/mod.rs b/frame/system/src/migrations/mod.rs index 90b88de1ab11c..f8ebfab33b891 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/system/src/mock.rs b/frame/system/src/mock.rs index fb230f66a94f7..a3807512dedcb 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/system/src/mocking.rs b/frame/system/src/mocking.rs index d8cfcb9baf268..8f76c1b8e08ba 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/system/src/offchain.rs b/frame/system/src/offchain.rs index 99a4c1541d30f..742146d1642c8 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/system/src/tests.rs b/frame/system/src/tests.rs index f441e785599eb..3e24d8f3c2fe4 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/system/src/weights.rs b/frame/system/src/weights.rs index d189afd4a549f..fa77db90d0c96 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) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/timestamp/src/benchmarking.rs b/frame/timestamp/src/benchmarking.rs index 3a9297fda805e..8a7febed4d12f 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/timestamp/src/lib.rs b/frame/timestamp/src/lib.rs index 61a46125a423b..93af4447d9612 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/timestamp/src/mock.rs b/frame/timestamp/src/mock.rs index e1ba5cd11e615..6f681788236c3 100644 --- a/frame/timestamp/src/mock.rs +++ b/frame/timestamp/src/mock.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/timestamp/src/tests.rs b/frame/timestamp/src/tests.rs index 6a76fbc4820e6..317631eeb7048 100644 --- a/frame/timestamp/src/tests.rs +++ b/frame/timestamp/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/timestamp/src/weights.rs b/frame/timestamp/src/weights.rs index 4c7dfd5ed17a5..8c7ef0d1f1afe 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) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/tips/src/benchmarking.rs b/frame/tips/src/benchmarking.rs index 5b1a102b8eb30..613f684afdf56 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/tips/src/lib.rs b/frame/tips/src/lib.rs index 175fc3ac39d02..d82906563fb8e 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/tips/src/migrations/mod.rs b/frame/tips/src/migrations/mod.rs index 719bb2f86fddd..f7f144adcdb6e 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/tips/src/migrations/v4.rs b/frame/tips/src/migrations/v4.rs index 0107e96a41168..35569633d1bb8 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/tips/src/tests.rs b/frame/tips/src/tests.rs index cb0b4458c7fba..fa4ec15014292 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/tips/src/weights.rs b/frame/tips/src/weights.rs index a568aaa870f0f..41fdf4928833c 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) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/transaction-payment/asset-tx-payment/src/lib.rs b/frame/transaction-payment/asset-tx-payment/src/lib.rs index 645ebb1e123be..ec0bfcd4f4028 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/transaction-payment/asset-tx-payment/src/mock.rs b/frame/transaction-payment/asset-tx-payment/src/mock.rs index 60fb2e6c5e03e..ada4777cfe719 100644 --- a/frame/transaction-payment/asset-tx-payment/src/mock.rs +++ b/frame/transaction-payment/asset-tx-payment/src/mock.rs @@ -1,4 +1,4 @@ -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/transaction-payment/asset-tx-payment/src/payment.rs b/frame/transaction-payment/asset-tx-payment/src/payment.rs index ae8253b6e7d3e..e273ffcfc565c 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/transaction-payment/asset-tx-payment/src/tests.rs b/frame/transaction-payment/asset-tx-payment/src/tests.rs index f76293f456497..08699fef032e8 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/transaction-payment/rpc/runtime-api/src/lib.rs b/frame/transaction-payment/rpc/runtime-api/src/lib.rs index 760f9e3693417..ae4a25bf1711d 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/transaction-payment/rpc/src/lib.rs b/frame/transaction-payment/rpc/src/lib.rs index 46ad5dbc0f5fb..1207a8cbf747a 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/transaction-payment/src/lib.rs b/frame/transaction-payment/src/lib.rs index fb4381c5242c6..6ed3e9789c35a 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/transaction-payment/src/mock.rs b/frame/transaction-payment/src/mock.rs index e214458b3766e..b4b8a784a6f22 100644 --- a/frame/transaction-payment/src/mock.rs +++ b/frame/transaction-payment/src/mock.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/transaction-payment/src/tests.rs b/frame/transaction-payment/src/tests.rs index ee54c1130e699..2748b80b1cdac 100644 --- a/frame/transaction-payment/src/tests.rs +++ b/frame/transaction-payment/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/transaction-payment/src/types.rs b/frame/transaction-payment/src/types.rs index d9677861f434e..b8bc17918ab36 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/transaction-storage/src/benchmarking.rs b/frame/transaction-storage/src/benchmarking.rs index 736d2c40d0b39..dfea3331569f9 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/transaction-storage/src/lib.rs b/frame/transaction-storage/src/lib.rs index aaa484d58ad28..c4b1a622fc5f3 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/transaction-storage/src/mock.rs b/frame/transaction-storage/src/mock.rs index 8764b16c31d8d..f54c134d74a0e 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/transaction-storage/src/tests.rs b/frame/transaction-storage/src/tests.rs index 01b71a7851ac3..43dfed81f88bb 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/transaction-storage/src/weights.rs b/frame/transaction-storage/src/weights.rs index 9ee7b37b3dc48..d9659a925ab24 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) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/treasury/src/benchmarking.rs b/frame/treasury/src/benchmarking.rs index 0947618a2b02f..a3761083e4faa 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/treasury/src/lib.rs b/frame/treasury/src/lib.rs index f5ca0a984bc49..2e22063eb3ea3 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/treasury/src/tests.rs b/frame/treasury/src/tests.rs index e6a1ea0f543fe..c9305dfd15037 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/treasury/src/weights.rs b/frame/treasury/src/weights.rs index aff593d88a0f9..10bab00836836 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) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/try-runtime/src/lib.rs b/frame/try-runtime/src/lib.rs index d8b117d1ff059..43292efe21042 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/uniques/src/benchmarking.rs b/frame/uniques/src/benchmarking.rs index 2656582f0e073..6d17951428bf9 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/uniques/src/functions.rs b/frame/uniques/src/functions.rs index f73e5c479de67..1aa79134dd575 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/uniques/src/impl_nonfungibles.rs b/frame/uniques/src/impl_nonfungibles.rs index 75d193ad19605..e8bef4e3f5c74 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/uniques/src/lib.rs b/frame/uniques/src/lib.rs index da0f0e0560674..587f1ae4b7d84 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/uniques/src/migration.rs b/frame/uniques/src/migration.rs index fd98c030d7f1b..6c92b753b4ac2 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/uniques/src/mock.rs b/frame/uniques/src/mock.rs index d6ed5cc5cc23e..67d994d7933c2 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/uniques/src/tests.rs b/frame/uniques/src/tests.rs index 7af54ddbb188c..993552c3a2aaa 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/uniques/src/types.rs b/frame/uniques/src/types.rs index 98e056163d28d..5b13998153e03 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/uniques/src/weights.rs b/frame/uniques/src/weights.rs index 3c1b102ba066a..144a384f0a6d7 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) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/utility/src/benchmarking.rs b/frame/utility/src/benchmarking.rs index f381b1e5f9e61..78911fd310e85 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/utility/src/lib.rs b/frame/utility/src/lib.rs index a28dd4994dfa6..6cfa8b7e36e9a 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/utility/src/tests.rs b/frame/utility/src/tests.rs index c63ed24c6aafb..938a5392b963d 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/utility/src/weights.rs b/frame/utility/src/weights.rs index 7b8c261d1db8b..8c7a14715989e 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) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/vesting/src/benchmarking.rs b/frame/vesting/src/benchmarking.rs index eb0d596b8a38b..35a094a9f4f19 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/vesting/src/lib.rs b/frame/vesting/src/lib.rs index 6cde546f387b4..dbc018796a3c6 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/vesting/src/migrations.rs b/frame/vesting/src/migrations.rs index 15668425b4b20..69bbc97296500 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/vesting/src/mock.rs b/frame/vesting/src/mock.rs index da9490bea66c0..f2ad6a70025e5 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/vesting/src/tests.rs b/frame/vesting/src/tests.rs index cbc2e09c83199..efc134cab7279 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/vesting/src/vesting_info.rs b/frame/vesting/src/vesting_info.rs index 9069b69482769..5d5ae31fc3247 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/vesting/src/weights.rs b/frame/vesting/src/weights.rs index a6a70fb56f45a..350e6a86e24e4 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) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/whitelist/src/benchmarking.rs b/frame/whitelist/src/benchmarking.rs index 582f4a7997c67..1982f5eb8738e 100644 --- a/frame/whitelist/src/benchmarking.rs +++ b/frame/whitelist/src/benchmarking.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/whitelist/src/lib.rs b/frame/whitelist/src/lib.rs index 8a5666331c7e9..bfbadd073a8f8 100644 --- a/frame/whitelist/src/lib.rs +++ b/frame/whitelist/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/whitelist/src/mock.rs b/frame/whitelist/src/mock.rs index e08c2875aec51..b16286863d71c 100644 --- a/frame/whitelist/src/mock.rs +++ b/frame/whitelist/src/mock.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/whitelist/src/tests.rs b/frame/whitelist/src/tests.rs index d04bb48c1ec40..986a09b8e03de 100644 --- a/frame/whitelist/src/tests.rs +++ b/frame/whitelist/src/tests.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/whitelist/src/weights.rs b/frame/whitelist/src/weights.rs index d5bc37c5759c8..2b25e81941540 100644 --- a/frame/whitelist/src/weights.rs +++ b/frame/whitelist/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/api/proc-macro/src/common.rs b/primitives/api/proc-macro/src/common.rs index 10887be613278..d29057723b8a4 100644 --- a/primitives/api/proc-macro/src/common.rs +++ b/primitives/api/proc-macro/src/common.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2018-2024 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/api/proc-macro/src/decl_runtime_apis.rs b/primitives/api/proc-macro/src/decl_runtime_apis.rs index c254237cc6688..d9a72adadec98 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/api/proc-macro/src/impl_runtime_apis.rs b/primitives/api/proc-macro/src/impl_runtime_apis.rs index 76c9e1164217f..f32961f892bba 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/api/proc-macro/src/lib.rs b/primitives/api/proc-macro/src/lib.rs index 31636b8e2d545..cea958426879e 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/api/proc-macro/src/mock_impl_runtime_apis.rs b/primitives/api/proc-macro/src/mock_impl_runtime_apis.rs index 493111e4f6158..4c79787a1e8df 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/api/proc-macro/src/utils.rs b/primitives/api/proc-macro/src/utils.rs index 6f2a766e9c01f..dee29b1a52c49 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/api/src/lib.rs b/primitives/api/src/lib.rs index c9605b8111cc5..7542ca3f20ccd 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/api/test/benches/bench.rs b/primitives/api/test/benches/bench.rs index 0d47d3038a8b8..88ebdbc6134aa 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/api/test/tests/decl_and_impl.rs b/primitives/api/test/tests/decl_and_impl.rs index 47e33d81d43f7..78990d5467d0e 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/api/test/tests/runtime_calls.rs b/primitives/api/test/tests/runtime_calls.rs index feb3e1a6ef48c..69f9a88ffadb3 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/api/test/tests/trybuild.rs b/primitives/api/test/tests/trybuild.rs index 13af1ded7dc6b..b0a334eb7a224 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/application-crypto/src/ecdsa.rs b/primitives/application-crypto/src/ecdsa.rs index 6356f54a0b085..011456df08fae 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/application-crypto/src/ed25519.rs b/primitives/application-crypto/src/ed25519.rs index 199e55383b881..822dd3fa5c422 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/application-crypto/src/lib.rs b/primitives/application-crypto/src/lib.rs index 05f89c40ef99f..992ecd1d05621 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/application-crypto/src/sr25519.rs b/primitives/application-crypto/src/sr25519.rs index c96e7382eb191..a961f5cf3edf0 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/application-crypto/src/traits.rs b/primitives/application-crypto/src/traits.rs index 853208bc20cbf..e3586ccecd0d8 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/application-crypto/test/src/ecdsa.rs b/primitives/application-crypto/test/src/ecdsa.rs index 4fe77db30fc66..df3be6f934304 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/application-crypto/test/src/ed25519.rs b/primitives/application-crypto/test/src/ed25519.rs index 7f37744ec88ee..8ce08717a8947 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/application-crypto/test/src/lib.rs b/primitives/application-crypto/test/src/lib.rs index 7cc3f8b0780e6..90856ee1e596f 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/application-crypto/test/src/sr25519.rs b/primitives/application-crypto/test/src/sr25519.rs index aa6734bf61d23..4c1d0f1ef7a97 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/arithmetic/benches/bench.rs b/primitives/arithmetic/benches/bench.rs index 5551d209098cf..6a8abca14e526 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/arithmetic/fuzzer/src/biguint.rs b/primitives/arithmetic/fuzzer/src/biguint.rs index f49743a4b8a69..2f9f54c810001 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/arithmetic/fuzzer/src/fixed_point.rs b/primitives/arithmetic/fuzzer/src/fixed_point.rs index c1b93f8c63a11..e76dd1503e39f 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/arithmetic/fuzzer/src/multiply_by_rational_with_rounding.rs b/primitives/arithmetic/fuzzer/src/multiply_by_rational_with_rounding.rs index 474b2d363eccd..13c9d022be6bd 100644 --- a/primitives/arithmetic/fuzzer/src/multiply_by_rational_with_rounding.rs +++ b/primitives/arithmetic/fuzzer/src/multiply_by_rational_with_rounding.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/arithmetic/fuzzer/src/normalize.rs b/primitives/arithmetic/fuzzer/src/normalize.rs index 3d2d6eb9acfcc..7211819017a87 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/arithmetic/fuzzer/src/per_thing_rational.rs b/primitives/arithmetic/fuzzer/src/per_thing_rational.rs index 7021c54c0ba04..c9c5146565cc7 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/arithmetic/src/biguint.rs b/primitives/arithmetic/src/biguint.rs index 33f0960ee378c..d92b08c8eca96 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/arithmetic/src/fixed_point.rs b/primitives/arithmetic/src/fixed_point.rs index bf3c93cdad605..67fbd5bc79c88 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/arithmetic/src/helpers_128bit.rs b/primitives/arithmetic/src/helpers_128bit.rs index 7938c31d1eaa6..56432d15a7260 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // Some code is based upon Derek Dreery's IntegerSquareRoot impl, used under license. // SPDX-License-Identifier: Apache-2.0 diff --git a/primitives/arithmetic/src/lib.rs b/primitives/arithmetic/src/lib.rs index 590aaa3166448..581206b6d4460 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/arithmetic/src/per_things.rs b/primitives/arithmetic/src/per_things.rs index fc3767761175c..068bdb4e17b0d 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/arithmetic/src/rational.rs b/primitives/arithmetic/src/rational.rs index 447b37551bb1f..0fcb7d4d9462a 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/arithmetic/src/traits.rs b/primitives/arithmetic/src/traits.rs index dfba046754373..91e13a832ea08 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/authority-discovery/src/lib.rs b/primitives/authority-discovery/src/lib.rs index 95bb458b1be8c..3b25e39d4045e 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/beefy/src/commitment.rs b/primitives/beefy/src/commitment.rs index 8642a83aae4be..f824c90e27c46 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/beefy/src/lib.rs b/primitives/beefy/src/lib.rs index ad9c1b8d1432a..2e3ec2ef801c5 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/beefy/src/mmr.rs b/primitives/beefy/src/mmr.rs index ca60f2a918bac..465008dc22499 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/beefy/src/payload.rs b/primitives/beefy/src/payload.rs index 0f23c3f381f19..d520de445c95a 100644 --- a/primitives/beefy/src/payload.rs +++ b/primitives/beefy/src/payload.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/beefy/src/test_utils.rs b/primitives/beefy/src/test_utils.rs index 1a5e03be33fb4..9e0758cdeb150 100644 --- a/primitives/beefy/src/test_utils.rs +++ b/primitives/beefy/src/test_utils.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021-2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/beefy/src/witness.rs b/primitives/beefy/src/witness.rs index 2c45e0ade90c4..9cc31d54b4c1d 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/block-builder/src/lib.rs b/primitives/block-builder/src/lib.rs index cf1bfa256084d..29e04857f463e 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/blockchain/src/backend.rs b/primitives/blockchain/src/backend.rs index 7339d4c1a6804..227559239d011 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/blockchain/src/error.rs b/primitives/blockchain/src/error.rs index 6585cc54f1582..41e5cda9c11c5 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/blockchain/src/header_metadata.rs b/primitives/blockchain/src/header_metadata.rs index 87ac44459987e..1d406dd0f4ed4 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/blockchain/src/lib.rs b/primitives/blockchain/src/lib.rs index 2fdef6cba9e5f..eabbbcf50d9f2 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/consensus/aura/src/digests.rs b/primitives/consensus/aura/src/digests.rs index b71930b6c6b80..13484da2a2955 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/primitives/consensus/aura/src/inherents.rs b/primitives/consensus/aura/src/inherents.rs index 135ae2660b32f..1ef25feb0ad62 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/consensus/aura/src/lib.rs b/primitives/consensus/aura/src/lib.rs index 2c6a97b934137..78409e84e93a3 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/consensus/babe/src/digests.rs b/primitives/consensus/babe/src/digests.rs index 1e4c820379d7a..4364057a4b478 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/consensus/babe/src/inherents.rs b/primitives/consensus/babe/src/inherents.rs index 2634507968f8e..b01bd1c9221f2 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/consensus/babe/src/lib.rs b/primitives/consensus/babe/src/lib.rs index 10d027bd9162d..e7747ac4c204a 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/consensus/common/src/block_validation.rs b/primitives/consensus/common/src/block_validation.rs index 1dc42104913cb..91e5330bbb06a 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/consensus/common/src/error.rs b/primitives/consensus/common/src/error.rs index 0656b5761fb38..33c1afa63fe70 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/consensus/common/src/lib.rs b/primitives/consensus/common/src/lib.rs index 458a5eee259a9..e02564654bd52 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/consensus/common/src/select_chain.rs b/primitives/consensus/common/src/select_chain.rs index 5beab6705046d..d387cc1ade097 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/consensus/pow/src/lib.rs b/primitives/consensus/pow/src/lib.rs index fe10ee808db98..f37aae1c5c012 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/consensus/slots/src/lib.rs b/primitives/consensus/slots/src/lib.rs index 21b3cad1e7167..d723785278da9 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/consensus/vrf/src/lib.rs b/primitives/consensus/vrf/src/lib.rs index 07e3f2c319706..84040c18590e0 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/consensus/vrf/src/schnorrkel.rs b/primitives/consensus/vrf/src/schnorrkel.rs index 8666de6c4bc0c..be145c5b12096 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/core/benches/bench.rs b/primitives/core/benches/bench.rs index 77e5bb63fef7a..e91c1758c3cbb 100644 --- a/primitives/core/benches/bench.rs +++ b/primitives/core/benches/bench.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2020 Parity Technologies +// Copyright Parity Technologies (UK) Ltd. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/primitives/core/hashing/proc-macro/src/impls.rs b/primitives/core/hashing/proc-macro/src/impls.rs index 3058cf019b143..714852ae3594a 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/core/hashing/proc-macro/src/lib.rs b/primitives/core/hashing/proc-macro/src/lib.rs index 2db292d8dc0cb..69668cadb4e26 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/core/hashing/src/lib.rs b/primitives/core/hashing/src/lib.rs index e6ccd5aaa8fb9..5bb68586a1340 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/core/src/bounded.rs b/primitives/core/src/bounded.rs index 45b4a9ca623d4..c78f1f85a4c23 100644 --- a/primitives/core/src/bounded.rs +++ b/primitives/core/src/bounded.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/core/src/crypto.rs b/primitives/core/src/crypto.rs index 52c805bb6119f..16af3d06963ab 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/core/src/defer.rs b/primitives/core/src/defer.rs index d14b26d59e4dd..c5ff502593692 100644 --- a/primitives/core/src/defer.rs +++ b/primitives/core/src/defer.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/core/src/ecdsa.rs b/primitives/core/src/ecdsa.rs index ca6b800625bc2..d68ba39a0fb79 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/core/src/ed25519.rs b/primitives/core/src/ed25519.rs index e85eb87c9fd83..4eb9401a9bde2 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/core/src/hash.rs b/primitives/core/src/hash.rs index f2974e9372ad5..ec7da98296bf3 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/core/src/hasher.rs b/primitives/core/src/hasher.rs index 173bd560ad1e3..5c4c40cba8e2d 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/core/src/hashing.rs b/primitives/core/src/hashing.rs index 1c439355a33c0..e71d0b5433803 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/core/src/hexdisplay.rs b/primitives/core/src/hexdisplay.rs index 26c04c433b49f..9f35e5ec7725f 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/core/src/lib.rs b/primitives/core/src/lib.rs index 13dbad66be9ff..efccd0378e95a 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/core/src/offchain/mod.rs b/primitives/core/src/offchain/mod.rs index 3f0eed87a3a64..5a77e19a3e522 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/core/src/offchain/storage.rs b/primitives/core/src/offchain/storage.rs index cf2c93641f245..3a114de5bfa3c 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/core/src/offchain/testing.rs b/primitives/core/src/offchain/testing.rs index a2065eb17717f..ee3620e701965 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/core/src/sr25519.rs b/primitives/core/src/sr25519.rs index 9064fb7427393..1206cf5f431fa 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/core/src/testing.rs b/primitives/core/src/testing.rs index d3fa3fc86fce5..756275aed6f41 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/core/src/traits.rs b/primitives/core/src/traits.rs index c4b7f20f7e9a0..3fe2a2ed3c394 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/core/src/uint.rs b/primitives/core/src/uint.rs index 4bf914bde2ee1..df49511e84943 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/database/src/error.rs b/primitives/database/src/error.rs index 78646427a2b5d..0cc1159b21e7d 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/database/src/kvdb.rs b/primitives/database/src/kvdb.rs index 5fe5fda307a1e..735813c368570 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/database/src/lib.rs b/primitives/database/src/lib.rs index 3ec62a2b78148..012f699552d74 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/database/src/mem.rs b/primitives/database/src/mem.rs index 6ecd44c6005b9..71ba7a9927636 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/debug-derive/src/impls.rs b/primitives/debug-derive/src/impls.rs index 51a4d876c79b6..76ef8367277b9 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/debug-derive/src/lib.rs b/primitives/debug-derive/src/lib.rs index c98610ce47808..639dbb6df189c 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/debug-derive/tests/tests.rs b/primitives/debug-derive/tests/tests.rs index 39414da86bf45..da521068e0dcd 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/externalities/src/extensions.rs b/primitives/externalities/src/extensions.rs index ecb489e5ec829..84155227a713e 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/externalities/src/lib.rs b/primitives/externalities/src/lib.rs index b343b8c393e00..411ec97a6b824 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/externalities/src/scope_limited.rs b/primitives/externalities/src/scope_limited.rs index 1d2e6863c9e58..2167db7c15280 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/finality-grandpa/src/lib.rs b/primitives/finality-grandpa/src/lib.rs index f5307ab06bde7..b466dcf374ccf 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/inherents/src/client_side.rs b/primitives/inherents/src/client_side.rs index 1ece7e1e4dea3..27479de136f2d 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/inherents/src/lib.rs b/primitives/inherents/src/lib.rs index f05c9a9ad552b..dd7c294f1e245 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/io/src/batch_verifier.rs b/primitives/io/src/batch_verifier.rs index 501d986758bf2..e6d8c6131f778 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/io/src/lib.rs b/primitives/io/src/lib.rs index bb06c00ee2c6f..8c3cdc668cba3 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/keyring/src/ed25519.rs b/primitives/keyring/src/ed25519.rs index 404e4121e71a3..c3ad86409e905 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/keyring/src/lib.rs b/primitives/keyring/src/lib.rs index 170a4c3d01b23..7432aff12544a 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/keyring/src/sr25519.rs b/primitives/keyring/src/sr25519.rs index 115a7fce70122..c738cfdc59d9e 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/keystore/src/lib.rs b/primitives/keystore/src/lib.rs index 6540e71bc3fe0..17c435483bae5 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/keystore/src/testing.rs b/primitives/keystore/src/testing.rs index a9ec6709d912a..5058a06508eac 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/keystore/src/vrf.rs b/primitives/keystore/src/vrf.rs index 7409353afe9f4..e089336c1485b 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/maybe-compressed-blob/src/lib.rs b/primitives/maybe-compressed-blob/src/lib.rs index 99c12ed39bc04..add620d4a1a17 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/merkle-mountain-range/src/lib.rs b/primitives/merkle-mountain-range/src/lib.rs index df0a7f75a73fb..1c319c4e3934c 100644 --- a/primitives/merkle-mountain-range/src/lib.rs +++ b/primitives/merkle-mountain-range/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/merkle-mountain-range/src/utils.rs b/primitives/merkle-mountain-range/src/utils.rs index 619ca7e98160f..b9171c96a6201 100644 --- a/primitives/merkle-mountain-range/src/utils.rs +++ b/primitives/merkle-mountain-range/src/utils.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/npos-elections/fuzzer/src/common.rs b/primitives/npos-elections/fuzzer/src/common.rs index ad9bd43f9bce0..ebf103401a629 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/npos-elections/fuzzer/src/phragmen_balancing.rs b/primitives/npos-elections/fuzzer/src/phragmen_balancing.rs index e053f9aa0cddd..c7aaf6ceed2a8 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/npos-elections/fuzzer/src/phragmen_pjr.rs b/primitives/npos-elections/fuzzer/src/phragmen_pjr.rs index 0401249a3df1d..94e697d9c4d8a 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/npos-elections/fuzzer/src/phragmms_balancing.rs b/primitives/npos-elections/fuzzer/src/phragmms_balancing.rs index 3f114674e29d9..067b788f01cb4 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/npos-elections/fuzzer/src/reduce.rs b/primitives/npos-elections/fuzzer/src/reduce.rs index 602467a343884..9ac34189d2e86 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/npos-elections/src/assignments.rs b/primitives/npos-elections/src/assignments.rs index fc88ef40010b7..9390cd1f4f9fc 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/npos-elections/src/balancing.rs b/primitives/npos-elections/src/balancing.rs index 4a713658ad38f..234326ee94dd2 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/npos-elections/src/helpers.rs b/primitives/npos-elections/src/helpers.rs index 598eb3b2ecc2c..082491ea04281 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/npos-elections/src/lib.rs b/primitives/npos-elections/src/lib.rs index d0c9ed18caddc..716c4b283c68e 100644 --- a/primitives/npos-elections/src/lib.rs +++ b/primitives/npos-elections/src/lib.rs @@ -1,6 +1,7 @@ // This file is part of Substrate. -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. SPDX-License-Identifier: Apache-2.0 +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at diff --git a/primitives/npos-elections/src/mock.rs b/primitives/npos-elections/src/mock.rs index 5a06e3f3c88ca..2fc49fd72cd03 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/npos-elections/src/node.rs b/primitives/npos-elections/src/node.rs index 6642a9ae39736..caca9561d8397 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/npos-elections/src/phragmen.rs b/primitives/npos-elections/src/phragmen.rs index ca32780ed84b4..c3578065f364c 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/npos-elections/src/phragmms.rs b/primitives/npos-elections/src/phragmms.rs index 3fbbad75e2f8f..df6becf47472f 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/npos-elections/src/pjr.rs b/primitives/npos-elections/src/pjr.rs index fd7c8ef539241..f0e59a25d440b 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/npos-elections/src/reduce.rs b/primitives/npos-elections/src/reduce.rs index c802a29504709..6a5a0159e4efb 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/npos-elections/src/tests.rs b/primitives/npos-elections/src/tests.rs index 6f2e4fca77115..72ae9a0222be1 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/npos-elections/src/traits.rs b/primitives/npos-elections/src/traits.rs index 91026f9de4b6b..d49970873b707 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/offchain/src/lib.rs b/primitives/offchain/src/lib.rs index 3e967f16d2a84..56de4f1589f83 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/panic-handler/src/lib.rs b/primitives/panic-handler/src/lib.rs index e06fe90ad6f3b..e2a9bfa195a66 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/rpc/src/lib.rs b/primitives/rpc/src/lib.rs index 915482e5fca70..4dbc629bb967a 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/rpc/src/list.rs b/primitives/rpc/src/list.rs index 7ec4d3491c7ea..860e5161b97c1 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/rpc/src/number.rs b/primitives/rpc/src/number.rs index 81084a09d4ac8..28caa243eb700 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/rpc/src/tracing.rs b/primitives/rpc/src/tracing.rs index a923ffcb69e0d..eb3fd47843357 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime-interface/proc-macro/src/lib.rs b/primitives/runtime-interface/proc-macro/src/lib.rs index afba38993fe76..e6f060c219e01 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime-interface/proc-macro/src/pass_by/codec.rs b/primitives/runtime-interface/proc-macro/src/pass_by/codec.rs index 4259b137d67cb..a1b7bccd3acc0 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime-interface/proc-macro/src/pass_by/enum_.rs b/primitives/runtime-interface/proc-macro/src/pass_by/enum_.rs index e25295fdca5cb..0d05dd9aa51e2 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime-interface/proc-macro/src/pass_by/inner.rs b/primitives/runtime-interface/proc-macro/src/pass_by/inner.rs index 7c9bd63aba11d..cc51fe44f912f 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime-interface/proc-macro/src/pass_by/mod.rs b/primitives/runtime-interface/proc-macro/src/pass_by/mod.rs index e32c2beb8b72a..f3d51d36248dd 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/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 b5745e25deb4c..16c1cffb78158 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/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 280c13667fde3..fb751c69bc86d 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime-interface/proc-macro/src/runtime_interface/mod.rs b/primitives/runtime-interface/proc-macro/src/runtime_interface/mod.rs index d14c1f67ecff5..008d69b321008 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/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 0ae0f5260286c..4a3a688e5c3bd 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime-interface/proc-macro/src/utils.rs b/primitives/runtime-interface/proc-macro/src/utils.rs index 386eef153f45c..07f9b5ce09802 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime-interface/src/host.rs b/primitives/runtime-interface/src/host.rs index 36492430266a7..914e575539d2f 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime-interface/src/impls.rs b/primitives/runtime-interface/src/impls.rs index e311b01dbefcf..3530b62662a53 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime-interface/src/lib.rs b/primitives/runtime-interface/src/lib.rs index 975d7158b8dcd..058801522a4f0 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime-interface/src/pass_by.rs b/primitives/runtime-interface/src/pass_by.rs index ac6f0def9cad0..8d145669adc3c 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime-interface/src/util.rs b/primitives/runtime-interface/src/util.rs index fe8afe99508a8..8db32271a0e7e 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime-interface/src/wasm.rs b/primitives/runtime-interface/src/wasm.rs index 4ed27687a10a5..91205addf21a0 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime-interface/test-wasm-deprecated/build.rs b/primitives/runtime-interface/test-wasm-deprecated/build.rs index 70f84bc00a817..b7676a70dfe84 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime-interface/test-wasm-deprecated/src/lib.rs b/primitives/runtime-interface/test-wasm-deprecated/src/lib.rs index 512d52214c12b..2f42e60504eb7 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime-interface/test-wasm/build.rs b/primitives/runtime-interface/test-wasm/build.rs index 70f84bc00a817..b7676a70dfe84 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime-interface/test-wasm/src/lib.rs b/primitives/runtime-interface/test-wasm/src/lib.rs index 3720735ac773b..cf1ff3bca088f 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime-interface/test/src/lib.rs b/primitives/runtime-interface/test/src/lib.rs index d1db3e064295e..d691d4846c330 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime-interface/tests/ui.rs b/primitives/runtime-interface/tests/ui.rs index f3d6aa59a0336..821d0b73f268b 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime/src/curve.rs b/primitives/runtime/src/curve.rs index c040b7cf517e0..7cea92293b4a0 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime/src/generic/block.rs b/primitives/runtime/src/generic/block.rs index b03fab2904db5..85d0b7ca1fd2d 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime/src/generic/checked_extrinsic.rs b/primitives/runtime/src/generic/checked_extrinsic.rs index fd7745c6031ff..4b0e017f4517b 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime/src/generic/digest.rs b/primitives/runtime/src/generic/digest.rs index 1d1173057ea8d..73741ba5d1dae 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime/src/generic/era.rs b/primitives/runtime/src/generic/era.rs index b26545fb8404e..79dea7258c9e1 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime/src/generic/header.rs b/primitives/runtime/src/generic/header.rs index 04d09f6b15541..e8b99efd42c75 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime/src/generic/mod.rs b/primitives/runtime/src/generic/mod.rs index 049b0e1624e7e..d9eee7fee8b20 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime/src/generic/tests.rs b/primitives/runtime/src/generic/tests.rs index d0536a5673125..b63efeb522124 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime/src/generic/unchecked_extrinsic.rs b/primitives/runtime/src/generic/unchecked_extrinsic.rs index bab4411167a7f..d147e7b6c1505 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime/src/legacy.rs b/primitives/runtime/src/legacy.rs index 7bc7c88a7e10d..b134038a12869 100644 --- a/primitives/runtime/src/legacy.rs +++ b/primitives/runtime/src/legacy.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime/src/legacy/byte_sized_error.rs b/primitives/runtime/src/legacy/byte_sized_error.rs index 049abff69ff1a..b552d6af3066e 100644 --- a/primitives/runtime/src/legacy/byte_sized_error.rs +++ b/primitives/runtime/src/legacy/byte_sized_error.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime/src/lib.rs b/primitives/runtime/src/lib.rs index 8a32d0b9b4221..dc03e074f9e89 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime/src/multiaddress.rs b/primitives/runtime/src/multiaddress.rs index b2d46fb106cbc..89b0a3bcf8ccc 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime/src/offchain/http.rs b/primitives/runtime/src/offchain/http.rs index dede4db5dd3de..0229203c1de5f 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime/src/offchain/mod.rs b/primitives/runtime/src/offchain/mod.rs index bbff693dea038..07abef7c4efad 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime/src/offchain/storage.rs b/primitives/runtime/src/offchain/storage.rs index 38ad268e58945..23ab7433e66a5 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime/src/offchain/storage_lock.rs b/primitives/runtime/src/offchain/storage_lock.rs index 47325743bd2f3..1b795978447df 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime/src/runtime_logger.rs b/primitives/runtime/src/runtime_logger.rs index fa866f8342a1f..63e96a52a527f 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime/src/runtime_string.rs b/primitives/runtime/src/runtime_string.rs index 762af0acd9250..f8f183ec785c4 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime/src/testing.rs b/primitives/runtime/src/testing.rs index 81762b3fc4f9f..7e2ee5403f3ea 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime/src/traits.rs b/primitives/runtime/src/traits.rs index 6eb19683b4439..e853cad61d81e 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/runtime/src/transaction_validity.rs b/primitives/runtime/src/transaction_validity.rs index f47459f3eed16..072609c667b41 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/serializer/src/lib.rs b/primitives/serializer/src/lib.rs index d1e364a133ba1..3d42707143d5e 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/session/src/lib.rs b/primitives/session/src/lib.rs index 9688547db42a3..642aa2a21143e 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/staking/src/lib.rs b/primitives/staking/src/lib.rs index 9eb4a4890cdf8..a8d8e6a602c94 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/staking/src/offence.rs b/primitives/staking/src/offence.rs index f6517b9e9028b..dec9756687979 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/state-machine/src/backend.rs b/primitives/state-machine/src/backend.rs index 791183c4d7e4d..eeb264aedd53d 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/state-machine/src/basic.rs b/primitives/state-machine/src/basic.rs index fdc50e3f8f207..a7adbc8a0daee 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/state-machine/src/error.rs b/primitives/state-machine/src/error.rs index a12b3eae71bd7..4e8e02a26025c 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/state-machine/src/ext.rs b/primitives/state-machine/src/ext.rs index 1db0ec517015b..548bab56aa918 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/state-machine/src/in_memory_backend.rs b/primitives/state-machine/src/in_memory_backend.rs index 06714fb41405a..2c3ed7441501c 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/state-machine/src/lib.rs b/primitives/state-machine/src/lib.rs index 188fb2f4b8d99..94fede96ffa55 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/state-machine/src/overlayed_changes/changeset.rs b/primitives/state-machine/src/overlayed_changes/changeset.rs index e5dad7157c731..8f2d02fd6840e 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/state-machine/src/overlayed_changes/mod.rs b/primitives/state-machine/src/overlayed_changes/mod.rs index 9eb26d52f79f8..b32df635b177c 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/state-machine/src/overlayed_changes/offchain.rs b/primitives/state-machine/src/overlayed_changes/offchain.rs index a9643c265e755..66e7ab5864c06 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/state-machine/src/read_only.rs b/primitives/state-machine/src/read_only.rs index e58fb760f4d7e..2056bf9866358 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/state-machine/src/stats.rs b/primitives/state-machine/src/stats.rs index 863ea5cfed7ec..7c5510961a373 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/state-machine/src/testing.rs b/primitives/state-machine/src/testing.rs index e94d34b5560cd..23e0ed2b5bb38 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/state-machine/src/trie_backend.rs b/primitives/state-machine/src/trie_backend.rs index ff5cce24c5124..a42976fb593a6 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/state-machine/src/trie_backend_essence.rs b/primitives/state-machine/src/trie_backend_essence.rs index cdd1bb0bba055..d92caeb84ff62 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/std/src/lib.rs b/primitives/std/src/lib.rs index 6653c3d7eadec..c5873b3698de1 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/std/with_std.rs b/primitives/std/with_std.rs index b5fa3f85ed702..b838de07a309a 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/std/without_std.rs b/primitives/std/without_std.rs index 7a6d5851dface..80baeae44cc9e 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/storage/src/lib.rs b/primitives/storage/src/lib.rs index 68d7b90639886..77aa260c9dd7d 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/test-primitives/src/lib.rs b/primitives/test-primitives/src/lib.rs index 9779fe2393c35..3a5f3dac40d68 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/timestamp/src/lib.rs b/primitives/timestamp/src/lib.rs index 0ec079816c10a..eeec73efbc8be 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/tracing/src/lib.rs b/primitives/tracing/src/lib.rs index 1efae226a546f..cc65183684667 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/tracing/src/types.rs b/primitives/tracing/src/types.rs index e7d5abfb27d9a..003787f310d8c 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/transaction-pool/src/lib.rs b/primitives/transaction-pool/src/lib.rs index 143958f06d165..431f429e29f9f 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/transaction-pool/src/runtime_api.rs b/primitives/transaction-pool/src/runtime_api.rs index 87a0c82e9133e..5d321ede40fcb 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/transaction-storage-proof/src/lib.rs b/primitives/transaction-storage-proof/src/lib.rs index 43928c83f21ed..9d540ae68d163 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/trie/benches/bench.rs b/primitives/trie/benches/bench.rs index f1670b0c2fa42..35aa0b808930b 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/trie/src/cache/mod.rs b/primitives/trie/src/cache/mod.rs index 3c1e5b8d0ff0b..e55a56971827b 100644 --- a/primitives/trie/src/cache/mod.rs +++ b/primitives/trie/src/cache/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/trie/src/cache/shared_cache.rs b/primitives/trie/src/cache/shared_cache.rs index 8c60d5043d062..28b3274fde11e 100644 --- a/primitives/trie/src/cache/shared_cache.rs +++ b/primitives/trie/src/cache/shared_cache.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/trie/src/error.rs b/primitives/trie/src/error.rs index a781d408e994f..17be556d3489a 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/trie/src/lib.rs b/primitives/trie/src/lib.rs index 01650e9a376be..34517d6aa6bcc 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/trie/src/node_codec.rs b/primitives/trie/src/node_codec.rs index f632320dd296d..46acde77c0543 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/trie/src/node_header.rs b/primitives/trie/src/node_header.rs index f3544be65b2e9..c118ee07b8cbd 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/trie/src/recorder.rs b/primitives/trie/src/recorder.rs index bc67cfc287942..d496408b21170 100644 --- a/primitives/trie/src/recorder.rs +++ b/primitives/trie/src/recorder.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/trie/src/storage_proof.rs b/primitives/trie/src/storage_proof.rs index 5351e8de6fd82..6c871d73b043a 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/trie/src/trie_codec.rs b/primitives/trie/src/trie_codec.rs index d5ae9a43fb1eb..f29e009c4761e 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/trie/src/trie_stream.rs b/primitives/trie/src/trie_stream.rs index 435e6a986722e..f57b80f978ffb 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/version/proc-macro/src/decl_runtime_version.rs b/primitives/version/proc-macro/src/decl_runtime_version.rs index 9a25adfa5fca2..7ca2d9b71f60a 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/version/proc-macro/src/lib.rs b/primitives/version/proc-macro/src/lib.rs index 8be18b15868f9..4f9179f3196a1 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/version/src/embed.rs b/primitives/version/src/embed.rs index c71849238fe33..096a7009a4fc5 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/version/src/lib.rs b/primitives/version/src/lib.rs index 37bb15afb29e6..214606acc534a 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/wasm-interface/src/lib.rs b/primitives/wasm-interface/src/lib.rs index c06eb43c7268b..b096d236c01eb 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/wasm-interface/src/wasmi_impl.rs b/primitives/wasm-interface/src/wasmi_impl.rs index 977b4fc606fa7..7394e34551305 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/weights/src/lib.rs b/primitives/weights/src/lib.rs index 59852815d7aef..acfcae1dfcd15 100644 --- a/primitives/weights/src/lib.rs +++ b/primitives/weights/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/weights/src/weight_meter.rs b/primitives/weights/src/weight_meter.rs index 17c5da1502e9e..ab7b6c63ed383 100644 --- a/primitives/weights/src/weight_meter.rs +++ b/primitives/weights/src/weight_meter.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/primitives/weights/src/weight_v2.rs b/primitives/weights/src/weight_v2.rs index 52e148f30392d..f6e6164b5fe4b 100644 --- a/primitives/weights/src/weight_v2.rs +++ b/primitives/weights/src/weight_v2.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/scripts/run_all_benchmarks.sh b/scripts/run_all_benchmarks.sh index f122be577c52d..b632cb5c12f04 100755 --- a/scripts/run_all_benchmarks.sh +++ b/scripts/run_all_benchmarks.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash # This file is part of Substrate. -# Copyright (C) 2022 Parity Technologies (UK) Ltd. +# Copyright (C) Parity Technologies (UK) Ltd. # SPDX-License-Identifier: Apache-2.0 # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/test-utils/client/src/client_ext.rs b/test-utils/client/src/client_ext.rs index 881c50d434264..c73ea76a3a244 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/test-utils/client/src/lib.rs b/test-utils/client/src/lib.rs index ff744b80cbff4..a27178792579a 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/test-utils/derive/src/lib.rs b/test-utils/derive/src/lib.rs index 06b7d2463cbd8..0291d825e768c 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/test-utils/runtime/build.rs b/test-utils/runtime/build.rs index 870d8ac43825b..dd79ce2c5ae84 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/test-utils/runtime/client/src/block_builder_ext.rs b/test-utils/runtime/client/src/block_builder_ext.rs index 66b0b4c3b881b..3c5e1122f0613 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/test-utils/runtime/client/src/lib.rs b/test-utils/runtime/client/src/lib.rs index 99d4e1163e272..97ee525f6eb9a 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/test-utils/runtime/client/src/trait_tests.rs b/test-utils/runtime/client/src/trait_tests.rs index 7ec56635e2d03..5fce7a2860b75 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/test-utils/runtime/src/genesismap.rs b/test-utils/runtime/src/genesismap.rs index 42706730eb9ac..77fdf59ea8cb4 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/test-utils/runtime/src/lib.rs b/test-utils/runtime/src/lib.rs index b979a961ae9de..1fa3c7a00b9c5 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/test-utils/runtime/src/system.rs b/test-utils/runtime/src/system.rs index 6e33d5c25fe6f..76ddf11a85196 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/test-utils/runtime/transaction-pool/src/lib.rs b/test-utils/runtime/transaction-pool/src/lib.rs index 8a648cd003152..8a39b8295041a 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/test-utils/src/lib.rs b/test-utils/src/lib.rs index 643985940792e..1ad702893683f 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/test-utils/test-crate/src/main.rs b/test-utils/test-crate/src/main.rs index 4696e71779c12..cab4cc6e924d7 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/test-utils/tests/basic.rs b/test-utils/tests/basic.rs index 4daca836c7fd9..e8c46b1e837d2 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/test-utils/tests/ui.rs b/test-utils/tests/ui.rs index be3b9c111b3e9..baf822bb87a49 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/test-utils/tests/ui/too-many-func-parameters.rs b/test-utils/tests/ui/too-many-func-parameters.rs index 51059f37ab629..0eece5f9e6130 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify diff --git a/utils/binary-merkle-tree/src/lib.rs b/utils/binary-merkle-tree/src/lib.rs index 42f4e8a5bbf26..43c07cb60a045 100644 --- a/utils/binary-merkle-tree/src/lib.rs +++ b/utils/binary-merkle-tree/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/build-script-utils/src/git.rs b/utils/build-script-utils/src/git.rs index db9a4b291ffdb..057ee0af15f76 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/build-script-utils/src/lib.rs b/utils/build-script-utils/src/lib.rs index 7e69f2ac85d4f..7bab35c9879ec 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/build-script-utils/src/version.rs b/utils/build-script-utils/src/version.rs index 19b507ba261e0..4ee5376ed322d 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/fork-tree/src/lib.rs b/utils/fork-tree/src/lib.rs index bbd0daca4a28d..cd175166b9cdf 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/benchmarking-cli/build.rs b/utils/frame/benchmarking-cli/build.rs index 4347804156815..1545d1e0c21e9 100644 --- a/utils/frame/benchmarking-cli/build.rs +++ b/utils/frame/benchmarking-cli/build.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/benchmarking-cli/src/block/bench.rs b/utils/frame/benchmarking-cli/src/block/bench.rs index 2ceac787ffb53..960056991a190 100644 --- a/utils/frame/benchmarking-cli/src/block/bench.rs +++ b/utils/frame/benchmarking-cli/src/block/bench.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/benchmarking-cli/src/block/cmd.rs b/utils/frame/benchmarking-cli/src/block/cmd.rs index 8bac04110f7ab..0192372fa33a7 100644 --- a/utils/frame/benchmarking-cli/src/block/cmd.rs +++ b/utils/frame/benchmarking-cli/src/block/cmd.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/benchmarking-cli/src/block/mod.rs b/utils/frame/benchmarking-cli/src/block/mod.rs index 97fdb6ad2c20c..9fbd4ea708013 100644 --- a/utils/frame/benchmarking-cli/src/block/mod.rs +++ b/utils/frame/benchmarking-cli/src/block/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/benchmarking-cli/src/extrinsic/bench.rs b/utils/frame/benchmarking-cli/src/extrinsic/bench.rs index 948f648377d55..facde14adab59 100644 --- a/utils/frame/benchmarking-cli/src/extrinsic/bench.rs +++ b/utils/frame/benchmarking-cli/src/extrinsic/bench.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/benchmarking-cli/src/extrinsic/cmd.rs b/utils/frame/benchmarking-cli/src/extrinsic/cmd.rs index dc8aa8b7c4200..1001958fe0d28 100644 --- a/utils/frame/benchmarking-cli/src/extrinsic/cmd.rs +++ b/utils/frame/benchmarking-cli/src/extrinsic/cmd.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/benchmarking-cli/src/extrinsic/extrinsic_factory.rs b/utils/frame/benchmarking-cli/src/extrinsic/extrinsic_factory.rs index 7e1a22ccd1419..9a209e9c56cff 100644 --- a/utils/frame/benchmarking-cli/src/extrinsic/extrinsic_factory.rs +++ b/utils/frame/benchmarking-cli/src/extrinsic/extrinsic_factory.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/benchmarking-cli/src/extrinsic/mod.rs b/utils/frame/benchmarking-cli/src/extrinsic/mod.rs index 12a09c3b1af63..4e8a66c0286a1 100644 --- a/utils/frame/benchmarking-cli/src/extrinsic/mod.rs +++ b/utils/frame/benchmarking-cli/src/extrinsic/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/benchmarking-cli/src/lib.rs b/utils/frame/benchmarking-cli/src/lib.rs index 5723a8038fdbb..0ef2c299de63e 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/benchmarking-cli/src/machine/hardware.rs b/utils/frame/benchmarking-cli/src/machine/hardware.rs index 318c193d7c08c..b3cbc0053c3f5 100644 --- a/utils/frame/benchmarking-cli/src/machine/hardware.rs +++ b/utils/frame/benchmarking-cli/src/machine/hardware.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/benchmarking-cli/src/machine/mod.rs b/utils/frame/benchmarking-cli/src/machine/mod.rs index bcffef255e5b5..fb9f14c9a4af1 100644 --- a/utils/frame/benchmarking-cli/src/machine/mod.rs +++ b/utils/frame/benchmarking-cli/src/machine/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/benchmarking-cli/src/overhead/cmd.rs b/utils/frame/benchmarking-cli/src/overhead/cmd.rs index bca63f7cae938..70e64cc2b66ad 100644 --- a/utils/frame/benchmarking-cli/src/overhead/cmd.rs +++ b/utils/frame/benchmarking-cli/src/overhead/cmd.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/benchmarking-cli/src/overhead/mod.rs b/utils/frame/benchmarking-cli/src/overhead/mod.rs index fc3db912f7a30..00cde66fd7221 100644 --- a/utils/frame/benchmarking-cli/src/overhead/mod.rs +++ b/utils/frame/benchmarking-cli/src/overhead/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/benchmarking-cli/src/overhead/template.rs b/utils/frame/benchmarking-cli/src/overhead/template.rs index ceed34d1981f9..7c8c92b07d747 100644 --- a/utils/frame/benchmarking-cli/src/overhead/template.rs +++ b/utils/frame/benchmarking-cli/src/overhead/template.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/benchmarking-cli/src/pallet/command.rs b/utils/frame/benchmarking-cli/src/pallet/command.rs index ec1be27614cc9..3f0e9298c7713 100644 --- a/utils/frame/benchmarking-cli/src/pallet/command.rs +++ b/utils/frame/benchmarking-cli/src/pallet/command.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/benchmarking-cli/src/pallet/mod.rs b/utils/frame/benchmarking-cli/src/pallet/mod.rs index 1fcf0cc1151dd..9ae9846745918 100644 --- a/utils/frame/benchmarking-cli/src/pallet/mod.rs +++ b/utils/frame/benchmarking-cli/src/pallet/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/benchmarking-cli/src/pallet/writer.rs b/utils/frame/benchmarking-cli/src/pallet/writer.rs index 9359b272551f0..a609f9e38c0ce 100644 --- a/utils/frame/benchmarking-cli/src/pallet/writer.rs +++ b/utils/frame/benchmarking-cli/src/pallet/writer.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/benchmarking-cli/src/shared/mod.rs b/utils/frame/benchmarking-cli/src/shared/mod.rs index ea5415f33f020..f8aa49b867f7d 100644 --- a/utils/frame/benchmarking-cli/src/shared/mod.rs +++ b/utils/frame/benchmarking-cli/src/shared/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/benchmarking-cli/src/shared/record.rs b/utils/frame/benchmarking-cli/src/shared/record.rs index 79ab37f651528..d82caa172d07d 100644 --- a/utils/frame/benchmarking-cli/src/shared/record.rs +++ b/utils/frame/benchmarking-cli/src/shared/record.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/benchmarking-cli/src/shared/stats.rs b/utils/frame/benchmarking-cli/src/shared/stats.rs index ffae4a17724f8..5c724456ddb9a 100644 --- a/utils/frame/benchmarking-cli/src/shared/stats.rs +++ b/utils/frame/benchmarking-cli/src/shared/stats.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/benchmarking-cli/src/shared/weight_params.rs b/utils/frame/benchmarking-cli/src/shared/weight_params.rs index 030bbfa00d468..10230ba305f48 100644 --- a/utils/frame/benchmarking-cli/src/shared/weight_params.rs +++ b/utils/frame/benchmarking-cli/src/shared/weight_params.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/benchmarking-cli/src/storage/cmd.rs b/utils/frame/benchmarking-cli/src/storage/cmd.rs index ce2d52e57d641..10ea8caaee9a4 100644 --- a/utils/frame/benchmarking-cli/src/storage/cmd.rs +++ b/utils/frame/benchmarking-cli/src/storage/cmd.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/benchmarking-cli/src/storage/mod.rs b/utils/frame/benchmarking-cli/src/storage/mod.rs index 0c722fdd47029..188cc5e3d4e41 100644 --- a/utils/frame/benchmarking-cli/src/storage/mod.rs +++ b/utils/frame/benchmarking-cli/src/storage/mod.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/benchmarking-cli/src/storage/read.rs b/utils/frame/benchmarking-cli/src/storage/read.rs index 20c41e4a5196b..c2aef1c794a90 100644 --- a/utils/frame/benchmarking-cli/src/storage/read.rs +++ b/utils/frame/benchmarking-cli/src/storage/read.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/benchmarking-cli/src/storage/template.rs b/utils/frame/benchmarking-cli/src/storage/template.rs index ebc415ccb8189..43aea75b47711 100644 --- a/utils/frame/benchmarking-cli/src/storage/template.rs +++ b/utils/frame/benchmarking-cli/src/storage/template.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/benchmarking-cli/src/storage/write.rs b/utils/frame/benchmarking-cli/src/storage/write.rs index 1917bc5f8fd07..66d5a30ead912 100644 --- a/utils/frame/benchmarking-cli/src/storage/write.rs +++ b/utils/frame/benchmarking-cli/src/storage/write.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/frame-utilities-cli/src/lib.rs b/utils/frame/frame-utilities-cli/src/lib.rs index 9a18d39263c98..97129e36f7e9c 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/frame-utilities-cli/src/pallet_id.rs b/utils/frame/frame-utilities-cli/src/pallet_id.rs index 2a80e3a3d312d..abc0cdb3ff52b 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/generate-bags/node-runtime/src/main.rs b/utils/frame/generate-bags/node-runtime/src/main.rs index 27e51b205f8ce..b8d233814752c 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/generate-bags/src/lib.rs b/utils/frame/generate-bags/src/lib.rs index 23da131a668d8..509ae5530eae1 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/remote-externalities/src/lib.rs b/utils/frame/remote-externalities/src/lib.rs index fb63b4275172d..ee342408828de 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/rpc/client/src/lib.rs b/utils/frame/rpc/client/src/lib.rs index a6f73ba6784b2..a6a667bef5681 100644 --- a/utils/frame/rpc/client/src/lib.rs +++ b/utils/frame/rpc/client/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/rpc/state-trie-migration-rpc/src/lib.rs b/utils/frame/rpc/state-trie-migration-rpc/src/lib.rs index 2140ee8845625..d1175fdea907a 100644 --- a/utils/frame/rpc/state-trie-migration-rpc/src/lib.rs +++ b/utils/frame/rpc/state-trie-migration-rpc/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/rpc/support/src/lib.rs b/utils/frame/rpc/support/src/lib.rs index a13d4f707797d..c0ec8befc4bee 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/rpc/system/src/lib.rs b/utils/frame/rpc/system/src/lib.rs index 965a7b44d3ff4..46d8472b27f6b 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/try-runtime/cli/src/block_building_info.rs b/utils/frame/try-runtime/cli/src/block_building_info.rs index b68bf081fee3e..db24d06ef0a15 100644 --- a/utils/frame/try-runtime/cli/src/block_building_info.rs +++ b/utils/frame/try-runtime/cli/src/block_building_info.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/try-runtime/cli/src/commands/create_snapshot.rs b/utils/frame/try-runtime/cli/src/commands/create_snapshot.rs index 8d6144f84c1e8..87855c1d6bf0d 100644 --- a/utils/frame/try-runtime/cli/src/commands/create_snapshot.rs +++ b/utils/frame/try-runtime/cli/src/commands/create_snapshot.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/try-runtime/cli/src/commands/execute_block.rs b/utils/frame/try-runtime/cli/src/commands/execute_block.rs index e054c8ab87932..561bc57c70c5a 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/try-runtime/cli/src/commands/fast_forward.rs b/utils/frame/try-runtime/cli/src/commands/fast_forward.rs index ae8f9a5cf17f2..75c48c3c402f3 100644 --- a/utils/frame/try-runtime/cli/src/commands/fast_forward.rs +++ b/utils/frame/try-runtime/cli/src/commands/fast_forward.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/try-runtime/cli/src/commands/follow_chain.rs b/utils/frame/try-runtime/cli/src/commands/follow_chain.rs index d887757b1646e..2a67d269c87f1 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/try-runtime/cli/src/commands/mod.rs b/utils/frame/try-runtime/cli/src/commands/mod.rs index 81deb263163b0..37902e676e3db 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs b/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs index 985b04bfb1cac..352d552a3f358 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/try-runtime/cli/src/commands/on_runtime_upgrade.rs b/utils/frame/try-runtime/cli/src/commands/on_runtime_upgrade.rs index 61b5847ed8ffc..c8582ea4d2a60 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/try-runtime/cli/src/lib.rs b/utils/frame/try-runtime/cli/src/lib.rs index 1a2f32de52ec1..04459ab5920d1 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/frame/try-runtime/cli/src/parse.rs b/utils/frame/try-runtime/cli/src/parse.rs index 257a99566979f..336a36baf2416 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/prometheus/src/lib.rs b/utils/prometheus/src/lib.rs index 3ea9d45d48b11..581666635ab54 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/prometheus/src/sourced.rs b/utils/prometheus/src/sourced.rs index 9f52d1eff47cd..8adaefa09d28f 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/wasm-builder/src/builder.rs b/utils/wasm-builder/src/builder.rs index 81a8693968188..72d32445e8da5 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/wasm-builder/src/lib.rs b/utils/wasm-builder/src/lib.rs index fc86a06170a50..659b955256af7 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/wasm-builder/src/prerequisites.rs b/utils/wasm-builder/src/prerequisites.rs index fb04dc3c98fb2..ca07a029281a8 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/wasm-builder/src/wasm_project.rs b/utils/wasm-builder/src/wasm_project.rs index d17997360deef..a3038c4e934c9 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-2022 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); From 59fd2ac6b1e2909aa9d4bddcdf7d445a6bffcbe4 Mon Sep 17 00:00:00 2001 From: Dan Shields <35669742+NukeManDan@users.noreply.github.com> Date: Tue, 21 Feb 2023 15:24:23 -0700 Subject: [PATCH 423/715] Update Template README (#12741) * update README remove matrix links remove playground references (service reported as sunsetting) OSPL rule per Docs style guide * Apply suggestions from code review Co-authored-by: Sacha Lansky * Update README.md * Apply suggestions from code review Co-authored-by: lisa-parity <92225469+lisa-parity@users.noreply.github.com> * (fix) chmod +x script --------- Co-authored-by: Sacha Lansky Co-authored-by: lisa-parity <92225469+lisa-parity@users.noreply.github.com> Co-authored-by: parity-processbot <> --- bin/node-template/README.md | 219 +++++++++--------------- bin/node-template/scripts/docker_run.sh | 0 2 files changed, 85 insertions(+), 134 deletions(-) mode change 100644 => 100755 bin/node-template/scripts/docker_run.sh diff --git a/bin/node-template/README.md b/bin/node-template/README.md index 0f6fd9450aeee..c42b58449565d 100644 --- a/bin/node-template/README.md +++ b/bin/node-template/README.md @@ -1,38 +1,22 @@ # Substrate Node Template -[![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 [Substrate](https://substrate.io/) node, ready for hacking :rocket: -A fresh FRAME-based [Substrate](https://www.substrate.io/) node, ready for hacking :rocket: +A standalone version of this template is available for each release of Polkadot in the [Substrate Developer Hub Parachain Template](https://github.com/substrate-developer-hub/substrate-parachain-template/) repository. +The parachain template is generated directly at each Polkadot release branch form the [Node Template in Substreate](https://github.com/paritytech/substrate/tree/master/bin/node-template) upstream -## 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 -the [Substrate Playground](https://docs.substrate.io/playground/) :hammer_and_wrench: - -### Using Nix - -Install [nix](https://nixos.org/) and optionally [direnv](https://github.com/direnv/direnv) 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 +It is usually best to to use the stand-alone version to start a new project. +All bugs, suggestions, and feature requests should be made upstream in the [Substrate](https://github.com/paritytech/substrate/tree/master/bin/node-template) repository. -First, complete the [basic Rust setup instructions](./docs/rust-setup.md). - -### Run +## Getting Started -Use Rust's native `cargo` command to build and launch the template node: - -```sh -cargo run --release -- --dev -``` +Depending on your operating system and Rust version, there might be additional packages required to compile this template. +Check the [Install](https://docs.substrate.io/install/) instructions for your platform for the most common dependencies. +Alternatively, you can use one of the [alternative installation](#alternatives-installations) options. ### Build -The `cargo run` command will perform an initial build. Use the following command to build the node -without launching it: +Use the following command to build the node without launching it: ```sh cargo build --release @@ -40,54 +24,49 @@ cargo build --release ### Embedded Docs -Once the project has been built, the following command can be used to explore all parameters and -subcommands: +After you build the project, you can use the following command to explore its parameters and subcommands: ```sh ./target/release/node-template -h ``` -## Run +You can generate and view the [Rust Docs](https://doc.rust-lang.org/cargo/commands/cargo-doc.html) for this template with this command: -The provided `cargo run` command will launch a temporary node and its state will be discarded after -you terminate the process. After the project has been built, there are other ways to launch the -node. +```sh +cargo +nightly doc --open +``` ### Single-Node Development Chain -This command will start the single-node development chain with non-persistent state: +The following command starts a single-node development chain that doesn't persist state: -```bash +```sh ./target/release/node-template --dev ``` -Purge the development chain's state: +To purge the development chain's state, run the following command: -```bash +```sh ./target/release/node-template purge-chain --dev ``` -Start the development chain with detailed logging: +To start the development chain with detailed logging, run the following command: -```bash +```sh 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 pre-funded: -> - Alice -> - 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 -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 +Development chains: + +- Maintain state in a `tmp` folder while the node is running. +- Use the **Alice** and **Bob** accounts as default validator authorities. +- Use the **Alice** account as the default `sudo` account. +- Are preconfigured with a genesis state (`/node/src/chain_spec.rs`) that includes several prefunded development accounts. + + +To persist chain state between runs, specify a base path by running a command similar to the following: + +```sh // Create a folder to use as the db base path $ mkdir my-chain-state @@ -103,23 +82,19 @@ $ ls ./my-chain-state/chains/dev db keystore network ``` +### Connect with Polkadot-JS Apps Front-End -### 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. +After you start the node template locally, you can interact with it using the hosted version of the [Polkadot/Substrate Portal](https://polkadot.js.org/apps/#/explorer?rpc=ws://localhost:9944) front-end by connecting to the local node endpoint. +A hosted version is also available on [IPFS (redirect) here](https://dotapps.io/) or [IPNS (direct) here](ipns://dotapps.io/?rpc=ws%3A%2F%2F127.0.0.1%3A9944#/explorer). +You can also find the source code and instructions for hosting your own instance on the [polkadot-js/apps](https://github.com/polkadot-js/apps) repository. ### Multi-Node Local Testnet -If you want to see the multi-node consensus algorithm in action, refer to our -[Simulate a network tutorial](https://docs.substrate.io/tutorials/get-started/simulate-network/). +If you want to see the multi-node consensus algorithm in action, see [Simulate a network](https://docs.substrate.io/tutorials/get-started/simulate-network/). ## Template Structure -A Substrate project such as this consists of a number of components that are spread across a few -directories. +A Substrate project such as this consists of a number of components that are spread across a few directories. ### Node @@ -128,98 +103,74 @@ 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/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). +- Consensus: Blockchains must have a way to come to [consensus](https://docs.substrate.io/fundamentals/consensus/) on the state of the network. + Substrate makes it possible to supply custom consensus engines and also ships with several consensus mechanisms that have been built on top of [Web3 Foundation research](https://research.web3.foundation/en/latest/polkadot/NPoS/index.html). - RPC Server: A remote procedure call (RPC) server is used to interact with Substrate nodes. -There are several files in the `node` directory - take special note of the following: - -- [`chain_spec.rs`](./node/src/chain_spec.rs): A - [chain specification](https://docs.substrate.io/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/reference/command-line-tools/subkey/) - and use them to configure the blockchain's initial state. -- [`service.rs`](./node/src/service.rs): This file defines the node implementation. Take note of - the libraries that this file imports and the names of the functions it invokes. In particular, - there are references to consensus-related topics, such as the - [block finalization and forks](https://docs.substrate.io/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: - -```shell -./target/release/node-template --help -``` +There are several files in the `node` directory. +Take special note of the following: + +- [`chain_spec.rs`](./node/src/chain_spec.rs): A [chain specification](https://docs.substrate.io/build/chain-spec/) is a source code file that defines a Substrate chain's initial (genesis) state. + Chain specifications are useful for development and testing, and critical when architecting the launch of a production chain. + Take note of the `development_config` and `testnet_genesis` functions,. + These functions are used to define the genesis state for the local development chain configuration. + These functions identify some [well-known accounts](https://docs.substrate.io/reference/command-line-tools/subkey/) and use them to configure the blockchain's initial state. +- [`service.rs`](./node/src/service.rs): This file defines the node implementation. + Take note of the libraries that this file imports and the names of the functions it invokes. + In particular, there are references to consensus-related topics, such as the [block finalization and forks](https://docs.substrate.io/fundamentals/consensus/#finalization-and-forks) and other [consensus mechanisms](https://docs.substrate.io/fundamentals/consensus/#default-consensus-models) such as Aura for block authoring and GRANDPA for finality. + + ### Runtime -In Substrate, the terms -"runtime" and "state transition function" -are analogous - 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 -[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/reference/frame-macros/) that makes it easy to -create pallets and flexibly compose them to create blockchains that can address -[a variety of needs](https://substrate.io/ecosystem/projects/). - -Review the [FRAME runtime implementation](./runtime/src/lib.rs) included in this template and note -the following: - -- This file configures several pallets to include in the runtime. Each pallet configuration is - defined by a code block that begins with `impl $PALLET_NAME::Config for Runtime`. -- The pallets are composed into a single runtime by way of the - [`construct_runtime!`](https://crates.parity.io/frame_support/macro.construct_runtime.html) - macro, which is part of the core - FRAME Support [system](https://docs.substrate.io/reference/frame-pallets/#system-pallets) library. +In Substrate, the terms "runtime" and "state transition function" are analogous. +Both terms refer to the core logic of the blockchain that is responsible for validating blocks and executing the state changes they define. +The Substrate project in this repository uses [FRAME](https://docs.substrate.io/fundamentals/runtime-development/#frame) to construct a blockchain runtime. +FRAME allows runtime developers to declare domain-specific logic in modules called "pallets". +At the heart of FRAME is a helpful [macro language](https://docs.substrate.io/reference/frame-macros/) that makes it easy to create pallets and flexibly compose them to create blockchains that can address [a variety of needs](https://substrate.io/ecosystem/projects/). + +Review the [FRAME runtime implementation](./runtime/src/lib.rs) included in this template and note the following: + +- This file configures several pallets to include in the runtime. + Each pallet configuration is defined by a code block that begins with `impl $PALLET_NAME::Config for Runtime`. +- The pallets are composed into a single runtime by way of the [`construct_runtime!`](https://crates.parity.io/frame_support/macro.construct_runtime.html) macro, which is part of the core FRAME Support [system](https://docs.substrate.io/reference/frame-pallets/#system-pallets) library. ### Pallets -The runtime in this project is constructed using many FRAME pallets that ship with the -[core Substrate repository](https://github.com/paritytech/substrate/tree/master/frame) and a -template pallet that is [defined in the `pallets`](./pallets/template/src/lib.rs) directory. +The runtime in this project is constructed using many FRAME pallets that ship with the [core Substrate repository](https://github.com/paritytech/substrate/tree/master/frame) and a template pallet that is [defined in the `pallets`](./pallets/template/src/lib.rs) directory. A FRAME pallet is compromised of a number of blockchain primitives: -- Storage: FRAME defines a rich set of powerful - [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/main-docs/build/events-errors/) - to notify users of important changes in the runtime. +- Storage: FRAME defines a rich set of powerful [storage abstractions](https://docs.substrate.io/build/runtime-storage/) that makes it easy to use Substrate's efficient key-value database to manage the evolving state of a blockchain. +- Dispatchables: FRAME pallets define special types of functions that can be invoked (dispatched) from outside of the runtime in order to update its state. +- Events: Substrate uses [events and errors](https://docs.substrate.io/build/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. +- Config: The `Config` configuration interface is used to define the types and parameters upon which a FRAME pallet depends. + +## Alternatives Installations + +Instead of installing dependencies and building this source directly, consider the following alternatives. -### Run in Docker +### Nix -First, install [Docker](https://docs.docker.com/get-docker/) and -[Docker Compose](https://docs.docker.com/compose/install/). +Install [nix](https://nixos.org/), and optionally [direnv](https://github.com/direnv/direnv) 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`. + +### Docker + +First, install [Docker](https://docs.docker.com/get-docker/) and [Docker Compose](https://docs.docker.com/compose/install/). Then run the following command to start a single node development chain. -```bash +```sh ./scripts/docker_run.sh ``` -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`) -by appending your own. A few useful ones are as follow. +This command compiles the code and starts a local development network. +You can also replace the default command (`cargo build --release && ./target/release/node-template --dev --ws-external`) by appending your own. +For example: -```bash +```sh # Run Substrate node without re-compiling ./scripts/docker_run.sh ./target/release/node-template --dev --ws-external diff --git a/bin/node-template/scripts/docker_run.sh b/bin/node-template/scripts/docker_run.sh old mode 100644 new mode 100755 From ea182669e111d819b2f4539749b86edee4944168 Mon Sep 17 00:00:00 2001 From: Sergej Sakac <73715684+Szegoo@users.noreply.github.com> Date: Tue, 21 Feb 2023 23:39:27 +0100 Subject: [PATCH 424/715] Glutton pallet (#12833) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Pov-Limit pallet * use Perbill & fixes * fixes * reads & writes * update docs * tests * calculate weight * fmt * benchmark * logic fix * naming fix * caclulate computation weight limit * make the Hasher generic * make the code compile * generate weight * fix on_idle * fix * fix * make reading generic * fix? * fixes * remove warning * fix * hasher fix :D * change value * test * actual weight and expected weight are the same * update * fix * add events * remove useless line * using actual hashing algorithm * better readability * fix nits * Update Signed-off-by: Oliver Tale-Yazdi * add migration * hardcode proof_size in weights.rs * format * fixes * Fix weight * docs * fix * Update frame/pov-limit/src/lib.rs Co-authored-by: Bastian Köcher * Update frame/pov-limit/src/lib.rs Co-authored-by: Bastian Köcher * empty on_ilde & update weight.rs * remove migration & fix benchmark * remove migration from migrations * initialize_pallet * use blake2 * Update frame/pov-limit/Cargo.toml Co-authored-by: Bastian Köcher * Update frame/pov-limit/src/lib.rs Co-authored-by: Bastian Köcher * Update frame/pov-limit/Cargo.toml Co-authored-by: Bastian Köcher * rename pallet * make the wasters non-generic * rename to glutton * fix * small fixes & run benchmark * increase left over ref-time in tests * Update frame/glutton/src/lib.rs Co-authored-by: Bastian Köcher * or values * fix * generate weight * Update frame/glutton/Cargo.toml Co-authored-by: Oliver Tale-Yazdi * fix nits * Adjustments Signed-off-by: Oliver Tale-Yazdi * Fixes Signed-off-by: Oliver Tale-Yazdi * fix * Update weights Signed-off-by: Oliver Tale-Yazdi * Tweak constants Signed-off-by: Oliver Tale-Yazdi * Update weights Signed-off-by: Oliver Tale-Yazdi * remove genesis config * passing tests * More precise results Signed-off-by: Oliver Tale-Yazdi * update node-executor test * Calculate number of iterations in advance Signed-off-by: Oliver Tale-Yazdi * increase criteria * Final fixes Signed-off-by: Oliver Tale-Yazdi * Update frame/glutton/src/tests.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update frame/glutton/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update frame/glutton/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * fix typos * Update frame/glutton/src/lib.rs Co-authored-by: Bastian Köcher * Update frame/glutton/src/lib.rs Co-authored-by: Bastian Köcher * expand/shrink * fmt * Revert "Update frame/glutton/src/lib.rs" This reverts commit 98a237afd27de3deb15ba381871e12f71a9d71b1. Signed-off-by: Oliver Tale-Yazdi * Use CountedStorageMap Signed-off-by: Oliver Tale-Yazdi * Add benchmark Signed-off-by: Oliver Tale-Yazdi * Use manual map counter Something with the R/W count in the benchmarking result did not add up. Need to investigate but for now just using a manual counter. Signed-off-by: Oliver Tale-Yazdi * Use new template Signed-off-by: Oliver Tale-Yazdi * Doc+typos Signed-off-by: Oliver Tale-Yazdi * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_glutton * Apply suggestions from code review Co-authored-by: Koute * Add minimal README Signed-off-by: Oliver Tale-Yazdi * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_glutton --------- Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Oliver Tale-Yazdi Co-authored-by: Bastian Köcher Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: command-bot <> Co-authored-by: Koute --- Cargo.lock | 20 ++ Cargo.toml | 1 + bin/node/executor/Cargo.toml | 1 + bin/node/runtime/Cargo.toml | 4 + bin/node/runtime/src/lib.rs | 7 + frame/glutton/Cargo.toml | 51 +++++ frame/glutton/README.md | 9 + frame/glutton/src/benchmarking.rs | 98 +++++++++ frame/glutton/src/lib.rs | 292 +++++++++++++++++++++++++++ frame/glutton/src/mock.rs | 80 ++++++++ frame/glutton/src/tests.rs | 226 +++++++++++++++++++++ frame/glutton/src/weights.rs | 324 ++++++++++++++++++++++++++++++ 12 files changed, 1113 insertions(+) create mode 100644 frame/glutton/Cargo.toml create mode 100644 frame/glutton/README.md create mode 100644 frame/glutton/src/benchmarking.rs create mode 100644 frame/glutton/src/lib.rs create mode 100644 frame/glutton/src/mock.rs create mode 100644 frame/glutton/src/tests.rs create mode 100644 frame/glutton/src/weights.rs diff --git a/Cargo.lock b/Cargo.lock index bed09f135de32..7c0b40cd99da9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3538,6 +3538,7 @@ dependencies = [ "pallet-election-provider-support-benchmarking", "pallet-elections-phragmen", "pallet-fast-unstake", + "pallet-glutton", "pallet-grandpa", "pallet-identity", "pallet-im-online", @@ -4850,6 +4851,7 @@ dependencies = [ "node-testing", "pallet-balances", "pallet-contracts", + "pallet-glutton", "pallet-im-online", "pallet-root-testing", "pallet-sudo", @@ -5813,6 +5815,24 @@ dependencies = [ "substrate-test-utils", ] +[[package]] +name = "pallet-glutton" +version = "4.0.0-dev" +dependencies = [ + "blake2", + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "pallet-balances", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-grandpa" version = "4.0.0-dev" diff --git a/Cargo.toml b/Cargo.toml index a86ec3146832b..89a52fd16cde8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -167,6 +167,7 @@ members = [ "frame/uniques", "frame/utility", "frame/vesting", + "frame/glutton", "frame/whitelist", "primitives/api", "primitives/api/proc-macro", diff --git a/bin/node/executor/Cargo.toml b/bin/node/executor/Cargo.toml index ffa8d38ee4b34..cb661f536f7b7 100644 --- a/bin/node/executor/Cargo.toml +++ b/bin/node/executor/Cargo.toml @@ -35,6 +35,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-glutton = { version = "4.0.0-dev", path = "../../../frame/glutton" } 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" } diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index e27e4f7f8a545..37a99414b5dce 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -85,6 +85,7 @@ pallet-nomination-pools-benchmarking = { version = "1.0.0", default-features = f 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-glutton = { version = "4.0.0-dev", default-features = false, path = "../../../frame/glutton" } 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-insecure-randomness-collective-flip = { version = "4.0.0-dev", default-features = false, path = "../../../frame/insecure-randomness-collective-flip" } @@ -165,6 +166,7 @@ std = [ "node-primitives/std", "sp-offchain/std", "pallet-offences/std", + "pallet-glutton/std", "pallet-preimage/std", "pallet-proxy/std", "sp-core/std", @@ -244,6 +246,7 @@ runtime-benchmarks = [ "pallet-multisig/runtime-benchmarks", "pallet-nomination-pools-benchmarking/runtime-benchmarks", "pallet-offences-benchmarking/runtime-benchmarks", + "pallet-glutton/runtime-benchmarks", "pallet-preimage/runtime-benchmarks", "pallet-proxy/runtime-benchmarks", "pallet-scheduler/runtime-benchmarks", @@ -300,6 +303,7 @@ try-runtime = [ "pallet-multisig/try-runtime", "pallet-nomination-pools/try-runtime", "pallet-offences/try-runtime", + "pallet-glutton/try-runtime", "pallet-preimage/try-runtime", "pallet-proxy/try-runtime", "pallet-insecure-randomness-collective-flip/try-runtime", diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 8e924a9c52e3c..3e3a0d75366ac 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -362,6 +362,11 @@ impl pallet_scheduler::Config for Runtime { type Preimages = Preimage; } +impl pallet_glutton::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = pallet_glutton::weights::SubstrateWeight; +} + parameter_types! { pub const PreimageMaxSize: u32 = 4096 * 1024; pub const PreimageBaseDeposit: Balance = 1 * DOLLARS; @@ -1747,6 +1752,7 @@ construct_runtime!( Recovery: pallet_recovery, Vesting: pallet_vesting, Scheduler: pallet_scheduler, + Glutton: pallet_glutton, Preimage: pallet_preimage, Proxy: pallet_proxy, Multisig: pallet_multisig, @@ -1878,6 +1884,7 @@ mod benches { [pallet_recovery, Recovery] [pallet_remark, Remark] [pallet_scheduler, Scheduler] + [pallet_glutton, Glutton] [pallet_session, SessionBench::] [pallet_staking, Staking] [pallet_state_trie_migration, StateTrieMigration] diff --git a/frame/glutton/Cargo.toml b/frame/glutton/Cargo.toml new file mode 100644 index 0000000000000..c0f0312464ee6 --- /dev/null +++ b/frame/glutton/Cargo.toml @@ -0,0 +1,51 @@ +[package] +name = "pallet-glutton" +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 pushing a chain to its weight limits" +readme = "README.md" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +blake2 = { version = "0.10.4", default-features = false } +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"] } +log = { version = "0.4.14", default-features = false } +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 = "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" } + +[features] +default = ["std"] +std = [ + "blake2/std", + "codec/std", + "frame-benchmarking?/std", + "frame-support/std", + "frame-system/std", + "scale-info/std", + "sp-core/std", + "sp-io/std", + "sp-runtime/std", + "sp-std/std", +] +try-runtime = ["frame-support/try-runtime"] + +runtime-benchmarks = [ + "frame-benchmarking/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", +] diff --git a/frame/glutton/README.md b/frame/glutton/README.md new file mode 100644 index 0000000000000..bcd6c51a6fced --- /dev/null +++ b/frame/glutton/README.md @@ -0,0 +1,9 @@ +# WARNING + +Do not use on value-bearing chains. This pallet is **only** intended for usage on test-chains. + +# Glutton Pallet + +The `Glutton` pallet gets the name from its property to consume vast amounts of resources. It can be used to push para-chains and their relay-chains to the limits. This is good for testing out theoretical limits in a practical way. + +The `Glutton` can be set to consume a fraction of the available unused weight of a chain. It accomplishes this by utilizing the `on_idle` hook and consuming a specific ration of the remaining weight. The rations can be set via `set_compute` and `set_storage`. Initially the `Glutton` needs to be initialized once with `initialize_pallet`. diff --git a/frame/glutton/src/benchmarking.rs b/frame/glutton/src/benchmarking.rs new file mode 100644 index 0000000000000..13576ae2f3d98 --- /dev/null +++ b/frame/glutton/src/benchmarking.rs @@ -0,0 +1,98 @@ +// 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. + +//! Glutton pallet benchmarking. +//! +//! Has to be compiled and run twice to calibrate on new hardware. + +#[cfg(feature = "runtime-benchmarks")] +use super::*; + +use frame_benchmarking::benchmarks; +use frame_support::{pallet_prelude::*, weights::constants::*}; +use frame_system::RawOrigin as SystemOrigin; + +use crate::Pallet as Glutton; +use frame_system::Pallet as System; + +benchmarks! { + initialize_pallet_grow { + let n in 0 .. 1_000; + }: { + Glutton::::initialize_pallet(SystemOrigin::Root.into(), n, None).unwrap() + } verify { + assert_eq!(TrashDataCount::::get(), n); + } + + initialize_pallet_shrink { + let n in 0 .. 1_000; + + Glutton::::initialize_pallet(SystemOrigin::Root.into(), n, None).unwrap(); + }: { + Glutton::::initialize_pallet(SystemOrigin::Root.into(), 0, Some(n)).unwrap() + } verify { + assert_eq!(TrashDataCount::::get(), 0); + } + + waste_ref_time_iter { + let i in 0..100_000; + }: { + Glutton::::waste_ref_time_iter(vec![0u8; 64], i); + } + + waste_proof_size_some { + let i in 0..5_000; + + (0..5000).for_each(|i| TrashData::::insert(i, [i as u8; 1024])); + }: { + (0..i).for_each(|i| { + TrashData::::get(i); + }) + } + + // For manual verification only. + on_idle_high_proof_waste { + (0..5000).for_each(|i| TrashData::::insert(i, [i as u8; 1024])); + let _ = Glutton::::set_compute(SystemOrigin::Root.into(), Perbill::from_percent(100)); + let _ = Glutton::::set_storage(SystemOrigin::Root.into(), Perbill::from_percent(100)); + }: { + let weight = Glutton::::on_idle(System::::block_number(), Weight::from_parts(WEIGHT_REF_TIME_PER_MILLIS * 100, WEIGHT_PROOF_SIZE_PER_MB * 5)); + } + + // For manual verification only. + on_idle_low_proof_waste { + (0..5000).for_each(|i| TrashData::::insert(i, [i as u8; 1024])); + let _ = Glutton::::set_compute(SystemOrigin::Root.into(), Perbill::from_percent(100)); + let _ = Glutton::::set_storage(SystemOrigin::Root.into(), Perbill::from_percent(100)); + }: { + let weight = Glutton::::on_idle(System::::block_number(), Weight::from_parts(WEIGHT_REF_TIME_PER_MILLIS * 100, WEIGHT_PROOF_SIZE_PER_KB * 20)); + } + + empty_on_idle { + }: { + // Enough weight do do nothing. + Glutton::::on_idle(System::::block_number(), T::WeightInfo::empty_on_idle()); + } + + set_compute { + }: _(SystemOrigin::Root, Perbill::from_percent(50)) + + set_storage { + }: _(SystemOrigin::Root, Perbill::from_percent(50)) + + impl_benchmark_test_suite!(Glutton, crate::mock::new_test_ext(), crate::mock::Test); +} diff --git a/frame/glutton/src/lib.rs b/frame/glutton/src/lib.rs new file mode 100644 index 0000000000000..e9a46374a5ade --- /dev/null +++ b/frame/glutton/src/lib.rs @@ -0,0 +1,292 @@ +// 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. + +//! # Glutton Pallet +//! +//! Pallet that consumes `ref_time` and `proof_size` of a block. Based on the +//! `Compute` and `Storage` parameters the pallet consumes the adequate amount +//! of weight. + +#![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 blake2::{Blake2b512, Digest}; +use frame_support::{pallet_prelude::*, weights::WeightMeter}; +use frame_system::pallet_prelude::*; +use sp_runtime::{traits::Zero, Perbill}; +use sp_std::{vec, vec::Vec}; + +pub use pallet::*; +pub use weights::WeightInfo; + +#[frame_support::pallet] +pub mod pallet { + use super::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeEvent: From + IsType<::RuntimeEvent>; + + /// Weight information for this pallet. + type WeightInfo: WeightInfo; + } + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// The pallet has been (re)initialized by root. + PalletInitialized { reinit: bool }, + /// The computation limit has been updated by root. + ComputationLimitSet { compute: Perbill }, + /// The storage limit has been updated by root. + StorageLimitSet { storage: Perbill }, + } + + #[pallet::error] + pub enum Error { + /// The pallet was already initialized. + /// + /// Set `witness_count` to `Some` to bypass this error. + AlreadyInitialized, + } + + /// Storage value used to specify what percentage of the left over `ref_time` + /// to consume during `on_idle`. + #[pallet::storage] + pub(crate) type Compute = StorageValue<_, Perbill, ValueQuery>; + + /// Storage value used the specify what percentage of left over `proof_size` + /// to consume during `on_idle`. + #[pallet::storage] + pub(crate) type Storage = StorageValue<_, Perbill, ValueQuery>; + + /// Storage map used for wasting proof size. + /// + /// It contains no meaningful data - hence the name "Trash". The maximal number of entries is + /// set to 65k, which is just below the next jump at 16^4. This is important to reduce the proof + /// size benchmarking overestimate. The assumption here is that we won't have more than 65k * + /// 1KiB = 65MiB of proof size wasting in practice. However, this limit is not enforced, so the + /// pallet would also work out of the box with more entries, but its benchmarked proof weight + /// would possibly be underestimated in that case. + #[pallet::storage] + pub(super) type TrashData = StorageMap< + Hasher = Twox64Concat, + Key = u32, + Value = [u8; 1024], + QueryKind = OptionQuery, + MaxValues = ConstU32<65_000>, + >; + + /// The current number of entries in `TrashData`. + #[pallet::storage] + pub(crate) type TrashDataCount = StorageValue<_, u32, ValueQuery>; + + #[pallet::hooks] + impl Hooks> for Pallet { + fn integrity_test() { + assert!( + !T::WeightInfo::waste_ref_time_iter(1).ref_time().is_zero(), + "Weight zero; would get stuck in an infinite loop" + ); + assert!( + !T::WeightInfo::waste_proof_size_some(1).proof_size().is_zero(), + "Weight zero; would get stuck in an infinite loop" + ); + } + + fn on_idle(_: BlockNumberFor, remaining_weight: Weight) -> Weight { + let mut meter = WeightMeter::from_limit(remaining_weight); + if !meter.check_accrue(T::WeightInfo::empty_on_idle()) { + return T::WeightInfo::empty_on_idle() + } + + let proof_size_limit = Storage::::get().mul_floor(meter.remaining().proof_size()); + let computation_weight_limit = + Compute::::get().mul_floor(meter.remaining().ref_time()); + let mut meter = WeightMeter::from_limit(Weight::from_parts( + computation_weight_limit, + proof_size_limit, + )); + + Self::waste_at_most_proof_size(&mut meter); + Self::waste_at_most_ref_time(&mut meter); + + meter.consumed + } + } + + #[pallet::call] + impl Pallet { + /// Initializes the pallet by writing into `TrashData`. + /// + /// Only callable by Root. A good default for `trash_count` is `5_000`. + #[pallet::call_index(0)] + #[pallet::weight( + T::WeightInfo::initialize_pallet_grow(witness_count.unwrap_or_default()) + .max(T::WeightInfo::initialize_pallet_shrink(witness_count.unwrap_or_default())) + )] + pub fn initialize_pallet( + origin: OriginFor, + new_count: u32, + witness_count: Option, + ) -> DispatchResult { + ensure_root(origin)?; + + let current_count = TrashDataCount::::get(); + ensure!( + current_count == witness_count.unwrap_or_default(), + Error::::AlreadyInitialized + ); + + if new_count > current_count { + (current_count..new_count).for_each(|i| TrashData::::insert(i, [i as u8; 1024])); + } else { + (new_count..current_count).for_each(TrashData::::remove); + } + + Self::deposit_event(Event::PalletInitialized { reinit: witness_count.is_some() }); + TrashDataCount::::set(new_count); + Ok(()) + } + + /// Set the `Compute` storage value that determines how much of the + /// block's weight `ref_time` to use during `on_idle`. + /// + /// Only callable by Root. + #[pallet::call_index(1)] + #[pallet::weight(T::WeightInfo::set_compute())] + pub fn set_compute(origin: OriginFor, compute: Perbill) -> DispatchResult { + ensure_root(origin)?; + Compute::::set(compute); + + Self::deposit_event(Event::ComputationLimitSet { compute }); + Ok(()) + } + + /// Set the `Storage` storage value that determines the PoV size usage + /// for each block. + /// + /// Only callable by Root. + #[pallet::call_index(2)] + #[pallet::weight(T::WeightInfo::set_storage())] + pub fn set_storage(origin: OriginFor, storage: Perbill) -> DispatchResult { + ensure_root(origin)?; + Storage::::set(storage); + + Self::deposit_event(Event::StorageLimitSet { storage }); + Ok(()) + } + } + + impl Pallet { + /// Waste at most the remaining proof size of `meter`. + /// + /// Tries to come as close to the limit as possible. + pub(crate) fn waste_at_most_proof_size(meter: &mut WeightMeter) { + let Ok(n) = Self::calculate_proof_size_iters(&meter) else { + return; + }; + + meter.defensive_saturating_accrue(T::WeightInfo::waste_proof_size_some(n)); + + (0..n).for_each(|i| { + TrashData::::get(i); + }); + } + + /// Calculate how many times `waste_proof_size_some` should be called to fill up `meter`. + fn calculate_proof_size_iters(meter: &WeightMeter) -> Result { + let base = T::WeightInfo::waste_proof_size_some(0); + let slope = T::WeightInfo::waste_proof_size_some(1).saturating_sub(base); + + let remaining = meter.remaining().saturating_sub(base); + let iter_by_proof_size = + remaining.proof_size().checked_div(slope.proof_size()).ok_or(())?; + let iter_by_ref_time = remaining.ref_time().checked_div(slope.ref_time()).ok_or(())?; + + if iter_by_proof_size > 0 && iter_by_proof_size <= iter_by_ref_time { + Ok(iter_by_proof_size as u32) + } else { + Err(()) + } + } + + /// Waste at most the remaining ref time weight of `meter`. + /// + /// Tries to come as close to the limit as possible. + pub(crate) fn waste_at_most_ref_time(meter: &mut WeightMeter) { + let Ok(n) = Self::calculate_ref_time_iters(&meter) else { + return; + }; + meter.defensive_saturating_accrue(T::WeightInfo::waste_ref_time_iter(n)); + + let clobber = Self::waste_ref_time_iter(vec![0u8; 64], n); + + // By casting it into a vec we can hopefully prevent the compiler from optimizing it + // out. Note that `Blake2b512` produces 64 bytes, this is therefore impossible - but the + // compiler does not know that (hopefully). + debug_assert!(clobber.len() == 64); + if clobber.len() == 65 { + TrashData::::insert(0, [clobber[0] as u8; 1024]); + } + } + + /// Wastes some `ref_time`. Receives the previous result as an argument. + /// + /// The ref_time of one iteration should be in the order of 1-10 ms. + pub(crate) fn waste_ref_time_iter(clobber: Vec, i: u32) -> Vec { + let mut hasher = Blake2b512::new(); + + // Blake2 has a very high speed of hashing so we make multiple hashes with it to + // waste more `ref_time` at once. + (0..i).for_each(|_| { + hasher.update(clobber.as_slice()); + }); + + hasher.finalize().to_vec() + } + + /// Calculate how many times `waste_ref_time_iter` should be called to fill up `meter`. + fn calculate_ref_time_iters(meter: &WeightMeter) -> Result { + let base = T::WeightInfo::waste_ref_time_iter(0); + let slope = T::WeightInfo::waste_ref_time_iter(1).saturating_sub(base); + if !slope.proof_size().is_zero() || !base.proof_size().is_zero() { + return Err(()) + } + + match meter + .remaining() + .ref_time() + .saturating_sub(base.ref_time()) + .checked_div(slope.ref_time()) + { + Some(0) | None => Err(()), + Some(i) => Ok(i as u32), + } + } + } +} diff --git a/frame/glutton/src/mock.rs b/frame/glutton/src/mock.rs new file mode 100644 index 0000000000000..c8be354f48e28 --- /dev/null +++ b/frame/glutton/src/mock.rs @@ -0,0 +1,80 @@ +// 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 pallet_glutton; + +use frame_support::traits::{ConstU32, ConstU64}; +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}, + Glutton: pallet_glutton::{Pallet, Event}, + } +); + +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 Config for Test { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); +} + +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 +} diff --git a/frame/glutton/src/tests.rs b/frame/glutton/src/tests.rs new file mode 100644 index 0000000000000..d2d2d4edec421 --- /dev/null +++ b/frame/glutton/src/tests.rs @@ -0,0 +1,226 @@ +// This file is part of Substrate. + +// Copyright (C) 2023 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Tests for the glutton pallet. + +use super::*; +use mock::{new_test_ext, Glutton, RuntimeOrigin, System, Test}; + +use frame_support::{assert_err, assert_noop, assert_ok, weights::constants::*}; + +#[test] +fn initialize_pallet_works() { + new_test_ext().execute_with(|| { + assert_eq!(TrashData::::get(0), None); + + assert_noop!( + Glutton::initialize_pallet(RuntimeOrigin::signed(1), 3, None), + DispatchError::BadOrigin + ); + assert_noop!( + Glutton::initialize_pallet(RuntimeOrigin::none(), 3, None), + DispatchError::BadOrigin + ); + + assert_ok!(Glutton::initialize_pallet(RuntimeOrigin::root(), 2, None)); + System::assert_last_event(Event::PalletInitialized { reinit: false }.into()); + assert_err!( + Glutton::initialize_pallet(RuntimeOrigin::root(), 2, None), + Error::::AlreadyInitialized + ); + + assert_eq!(TrashData::::get(0), Some([0; 1024])); + assert_eq!(TrashData::::get(1), Some([1; 1024])); + assert_eq!(TrashData::::get(2), None); + + assert_eq!(TrashDataCount::::get(), 2); + + assert_ok!(Glutton::initialize_pallet(RuntimeOrigin::root(), 20, Some(2))); + + assert_eq!(TrashDataCount::::get(), 20); + assert_eq!(TrashData::::iter_keys().count(), 20); + }); +} + +#[test] +fn expand_and_shrink_trash_data_works() { + new_test_ext().execute_with(|| { + assert_eq!(TrashDataCount::::get(), 0); + + assert_ok!(Glutton::initialize_pallet(RuntimeOrigin::root(), 5000, None)); + assert_eq!(TrashDataCount::::get(), 5000); + assert_eq!(TrashData::::iter_keys().count(), 5000); + + assert_ok!(Glutton::initialize_pallet(RuntimeOrigin::root(), 8000, Some(5000))); + assert_eq!(TrashDataCount::::get(), 8000); + assert_eq!(TrashData::::iter_keys().count(), 8000); + + assert_ok!(Glutton::initialize_pallet(RuntimeOrigin::root(), 6000, Some(8000))); + assert_eq!(TrashDataCount::::get(), 6000); + assert_eq!(TrashData::::iter_keys().count(), 6000); + + assert_noop!( + Glutton::initialize_pallet(RuntimeOrigin::root(), 0, None), + Error::::AlreadyInitialized + ); + assert_ok!(Glutton::initialize_pallet(RuntimeOrigin::root(), 0, Some(6000))); + assert_eq!(TrashDataCount::::get(), 0); + assert_eq!(TrashData::::iter_keys().count(), 0); + }); +} + +#[test] +fn setting_compute_works() { + new_test_ext().execute_with(|| { + assert_eq!(Compute::::get(), Perbill::from_percent(0)); + + assert_ok!(Glutton::set_compute(RuntimeOrigin::root(), Perbill::from_percent(70))); + assert_eq!(Compute::::get(), Perbill::from_percent(70)); + System::assert_last_event( + Event::ComputationLimitSet { compute: Perbill::from_percent(70) }.into(), + ); + + assert_noop!( + Glutton::set_compute(RuntimeOrigin::signed(1), Perbill::from_percent(30)), + DispatchError::BadOrigin + ); + assert_noop!( + Glutton::set_compute(RuntimeOrigin::none(), Perbill::from_percent(30)), + DispatchError::BadOrigin + ); + }); +} + +#[test] +fn setting_storage_works() { + new_test_ext().execute_with(|| { + assert_eq!(Storage::::get(), Perbill::from_percent(0)); + + assert_ok!(Glutton::set_storage(RuntimeOrigin::root(), Perbill::from_percent(30))); + assert_eq!(Storage::::get(), Perbill::from_percent(30)); + System::assert_last_event( + Event::StorageLimitSet { storage: Perbill::from_percent(30) }.into(), + ); + + assert_noop!( + Glutton::set_storage(RuntimeOrigin::signed(1), Perbill::from_percent(90)), + DispatchError::BadOrigin + ); + assert_noop!( + Glutton::set_storage(RuntimeOrigin::none(), Perbill::from_percent(90)), + DispatchError::BadOrigin + ); + }); +} + +#[test] +fn on_idle_works() { + new_test_ext().execute_with(|| { + assert_ok!(Glutton::set_compute(RuntimeOrigin::root(), Perbill::from_percent(100))); + assert_ok!(Glutton::set_storage(RuntimeOrigin::root(), Perbill::from_percent(100))); + + Glutton::on_idle(1, Weight::from_ref_time(20_000_000)); + }); +} + +/// Check that the expected is close enough to the consumed weight. +#[test] +fn on_idle_weight_high_proof_is_close_enough_works() { + new_test_ext().execute_with(|| { + assert_ok!(Glutton::set_compute(RuntimeOrigin::root(), Perbill::from_percent(100))); + assert_ok!(Glutton::set_storage(RuntimeOrigin::root(), Perbill::from_percent(100))); + + let should = Weight::from_parts(WEIGHT_REF_TIME_PER_SECOND, WEIGHT_PROOF_SIZE_PER_MB * 5); + let got = Glutton::on_idle(1, should); + assert!(got.all_lte(should), "Consumed too much weight"); + + let ratio = Perbill::from_rational(got.proof_size(), should.proof_size()); + assert!( + ratio >= Perbill::from_percent(99), + "Too few proof size consumed, was only {:?} of expected", + ratio + ); + + let ratio = Perbill::from_rational(got.ref_time(), should.ref_time()); + assert!( + ratio >= Perbill::from_percent(99), + "Too few ref time consumed, was only {:?} of expected", + ratio + ); + }); +} + +#[test] +fn on_idle_weight_low_proof_is_close_enough_works() { + new_test_ext().execute_with(|| { + assert_ok!(Glutton::set_compute(RuntimeOrigin::root(), Perbill::from_percent(100))); + assert_ok!(Glutton::set_storage(RuntimeOrigin::root(), Perbill::from_percent(100))); + + let should = Weight::from_parts(WEIGHT_REF_TIME_PER_SECOND, WEIGHT_PROOF_SIZE_PER_KB * 20); + let got = Glutton::on_idle(1, should); + assert!(got.all_lte(should), "Consumed too much weight"); + + let ratio = Perbill::from_rational(got.proof_size(), should.proof_size()); + // Just a sanity check here. + assert!( + ratio >= Perbill::from_percent(80), + "Too few proof size consumed, was only {:?} of expected", + ratio + ); + + let ratio = Perbill::from_rational(got.ref_time(), should.ref_time()); + assert!( + ratio >= Perbill::from_percent(99), + "Too few ref time consumed, was only {:?} of expected", + ratio + ); + }); +} + +#[test] +fn waste_at_most_ref_time_weight_close_enough() { + new_test_ext().execute_with(|| { + let mut meter = + WeightMeter::from_limit(Weight::from_parts(WEIGHT_REF_TIME_PER_SECOND, u64::MAX)); + // Over-spending fails defensively. + Glutton::waste_at_most_ref_time(&mut meter); + + // We require it to be under-spend by at most 1%. + assert!( + meter.consumed_ratio() >= Perbill::from_percent(99), + "Consumed too few: {:?}", + meter.consumed_ratio() + ); + }); +} + +#[test] +fn waste_at_most_proof_size_weight_close_enough() { + new_test_ext().execute_with(|| { + let mut meter = + WeightMeter::from_limit(Weight::from_parts(u64::MAX, WEIGHT_PROOF_SIZE_PER_MB * 5)); + // Over-spending fails defensively. + Glutton::waste_at_most_proof_size(&mut meter); + + // We require it to be under-spend by at most 1%. + assert!( + meter.consumed_ratio() >= Perbill::from_percent(99), + "Consumed too few: {:?}", + meter.consumed_ratio() + ); + }); +} diff --git a/frame/glutton/src/weights.rs b/frame/glutton/src/weights.rs new file mode 100644 index 0000000000000..1e09d02c69d1c --- /dev/null +++ b/frame/glutton/src/weights.rs @@ -0,0 +1,324 @@ +// This file is part of Substrate. + +// Copyright (C) 2023 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for pallet_glutton +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-02-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-ehxwxxsd-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 + +// Executed Command: +// target/production/substrate +// benchmark +// pallet +// --steps=50 +// --repeat=20 +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/substrate/.git/.artifacts/bench.json +// --pallet=pallet_glutton +// --chain=dev +// --header=./HEADER-APACHE2 +// --output=./frame/glutton/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_glutton. +pub trait WeightInfo { + fn initialize_pallet_grow(n: u32, ) -> Weight; + fn initialize_pallet_shrink(n: u32, ) -> Weight; + fn waste_ref_time_iter(i: u32, ) -> Weight; + fn waste_proof_size_some(i: u32, ) -> Weight; + fn on_idle_high_proof_waste() -> Weight; + fn on_idle_low_proof_waste() -> Weight; + fn empty_on_idle() -> Weight; + fn set_compute() -> Weight; + fn set_storage() -> Weight; +} + +/// Weights for pallet_glutton using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + /// Storage: Glutton TrashDataCount (r:1 w:1) + /// Proof: Glutton TrashDataCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Glutton TrashData (r:0 w:1000) + /// Proof: Glutton TrashData (max_values: Some(65000), max_size: Some(1036), added: 3016, mode: MaxEncodedLen) + /// The range of component `n` is `[0, 1000]`. + fn initialize_pallet_grow(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `4` + // Estimated: `499` + // Minimum execution time: 9_248 nanoseconds. + Weight::from_ref_time(9_582_000) + .saturating_add(Weight::from_proof_size(499)) + // Standard Error: 1_144 + .saturating_add(Weight::from_ref_time(1_624_225).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) + } + /// Storage: Glutton TrashDataCount (r:1 w:1) + /// Proof: Glutton TrashDataCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Glutton TrashData (r:0 w:1000) + /// Proof: Glutton TrashData (max_values: Some(65000), max_size: Some(1036), added: 3016, mode: MaxEncodedLen) + /// The range of component `n` is `[0, 1000]`. + fn initialize_pallet_shrink(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `65` + // Estimated: `499` + // Minimum execution time: 10_210 nanoseconds. + Weight::from_ref_time(7_260_854) + .saturating_add(Weight::from_proof_size(499)) + // Standard Error: 1_459 + .saturating_add(Weight::from_ref_time(1_053_844).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) + } + /// The range of component `i` is `[0, 100000]`. + fn waste_ref_time_iter(i: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 605 nanoseconds. + Weight::from_ref_time(1_102_112) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 28 + .saturating_add(Weight::from_ref_time(120_597).saturating_mul(i.into())) + } + /// Storage: Glutton TrashData (r:5000 w:0) + /// Proof: Glutton TrashData (max_values: Some(65000), max_size: Some(1036), added: 3016, mode: MaxEncodedLen) + /// The range of component `i` is `[0, 5000]`. + fn waste_proof_size_some(i: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `119036 + i * (1053 ±0)` + // Estimated: `0 + i * (3016 ±0)` + // Minimum execution time: 464 nanoseconds. + Weight::from_ref_time(552_000) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 1_962 + .saturating_add(Weight::from_ref_time(5_780_304).saturating_mul(i.into())) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(i.into()))) + .saturating_add(Weight::from_proof_size(3016).saturating_mul(i.into())) + } + /// Storage: Glutton Storage (r:1 w:0) + /// Proof: Glutton Storage (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Glutton Compute (r:1 w:0) + /// Proof: Glutton Compute (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Glutton TrashData (r:1738 w:0) + /// Proof: Glutton TrashData (max_values: Some(65000), max_size: Some(1036), added: 3016, mode: MaxEncodedLen) + fn on_idle_high_proof_waste() -> Weight { + // Proof Size summary in bytes: + // Measured: `1955391` + // Estimated: `5242806` + // Minimum execution time: 55_398_405 nanoseconds. + Weight::from_ref_time(55_594_848_000) + .saturating_add(Weight::from_proof_size(5242806)) + .saturating_add(T::DbWeight::get().reads(1740_u64)) + } + /// Storage: Glutton Storage (r:1 w:0) + /// Proof: Glutton Storage (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Glutton Compute (r:1 w:0) + /// Proof: Glutton Compute (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Glutton TrashData (r:6 w:0) + /// Proof: Glutton TrashData (max_values: Some(65000), max_size: Some(1036), added: 3016, mode: MaxEncodedLen) + fn on_idle_low_proof_waste() -> Weight { + // Proof Size summary in bytes: + // Measured: `11717` + // Estimated: `19094` + // Minimum execution time: 98_888_667 nanoseconds. + Weight::from_ref_time(99_157_239_000) + .saturating_add(Weight::from_proof_size(19094)) + .saturating_add(T::DbWeight::get().reads(8_u64)) + } + /// Storage: Glutton Storage (r:1 w:0) + /// Proof: Glutton Storage (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Glutton Compute (r:1 w:0) + /// Proof: Glutton Compute (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + fn empty_on_idle() -> Weight { + // Proof Size summary in bytes: + // Measured: `4` + // Estimated: `998` + // Minimum execution time: 3_967 nanoseconds. + Weight::from_ref_time(4_121_000) + .saturating_add(Weight::from_proof_size(998)) + .saturating_add(T::DbWeight::get().reads(2_u64)) + } + /// Storage: Glutton Compute (r:0 w:1) + /// Proof: Glutton Compute (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + fn set_compute() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 7_112 nanoseconds. + Weight::from_ref_time(7_484_000) + .saturating_add(Weight::from_proof_size(0)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Glutton Storage (r:0 w:1) + /// Proof: Glutton Storage (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + fn set_storage() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 7_056 nanoseconds. + Weight::from_ref_time(7_414_000) + .saturating_add(Weight::from_proof_size(0)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } +} + +// For backwards compatibility and tests +impl WeightInfo for () { + /// Storage: Glutton TrashDataCount (r:1 w:1) + /// Proof: Glutton TrashDataCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Glutton TrashData (r:0 w:1000) + /// Proof: Glutton TrashData (max_values: Some(65000), max_size: Some(1036), added: 3016, mode: MaxEncodedLen) + /// The range of component `n` is `[0, 1000]`. + fn initialize_pallet_grow(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `4` + // Estimated: `499` + // Minimum execution time: 9_248 nanoseconds. + Weight::from_ref_time(9_582_000) + .saturating_add(Weight::from_proof_size(499)) + // Standard Error: 1_144 + .saturating_add(Weight::from_ref_time(1_624_225).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) + } + /// Storage: Glutton TrashDataCount (r:1 w:1) + /// Proof: Glutton TrashDataCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Glutton TrashData (r:0 w:1000) + /// Proof: Glutton TrashData (max_values: Some(65000), max_size: Some(1036), added: 3016, mode: MaxEncodedLen) + /// The range of component `n` is `[0, 1000]`. + fn initialize_pallet_shrink(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `65` + // Estimated: `499` + // Minimum execution time: 10_210 nanoseconds. + Weight::from_ref_time(7_260_854) + .saturating_add(Weight::from_proof_size(499)) + // Standard Error: 1_459 + .saturating_add(Weight::from_ref_time(1_053_844).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) + } + /// The range of component `i` is `[0, 100000]`. + fn waste_ref_time_iter(i: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 605 nanoseconds. + Weight::from_ref_time(1_102_112) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 28 + .saturating_add(Weight::from_ref_time(120_597).saturating_mul(i.into())) + } + /// Storage: Glutton TrashData (r:5000 w:0) + /// Proof: Glutton TrashData (max_values: Some(65000), max_size: Some(1036), added: 3016, mode: MaxEncodedLen) + /// The range of component `i` is `[0, 5000]`. + fn waste_proof_size_some(i: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `119036 + i * (1053 ±0)` + // Estimated: `0 + i * (3016 ±0)` + // Minimum execution time: 464 nanoseconds. + Weight::from_ref_time(552_000) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 1_962 + .saturating_add(Weight::from_ref_time(5_780_304).saturating_mul(i.into())) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(i.into()))) + .saturating_add(Weight::from_proof_size(3016).saturating_mul(i.into())) + } + /// Storage: Glutton Storage (r:1 w:0) + /// Proof: Glutton Storage (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Glutton Compute (r:1 w:0) + /// Proof: Glutton Compute (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Glutton TrashData (r:1738 w:0) + /// Proof: Glutton TrashData (max_values: Some(65000), max_size: Some(1036), added: 3016, mode: MaxEncodedLen) + fn on_idle_high_proof_waste() -> Weight { + // Proof Size summary in bytes: + // Measured: `1955391` + // Estimated: `5242806` + // Minimum execution time: 55_398_405 nanoseconds. + Weight::from_ref_time(55_594_848_000) + .saturating_add(Weight::from_proof_size(5242806)) + .saturating_add(RocksDbWeight::get().reads(1740_u64)) + } + /// Storage: Glutton Storage (r:1 w:0) + /// Proof: Glutton Storage (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Glutton Compute (r:1 w:0) + /// Proof: Glutton Compute (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Glutton TrashData (r:6 w:0) + /// Proof: Glutton TrashData (max_values: Some(65000), max_size: Some(1036), added: 3016, mode: MaxEncodedLen) + fn on_idle_low_proof_waste() -> Weight { + // Proof Size summary in bytes: + // Measured: `11717` + // Estimated: `19094` + // Minimum execution time: 98_888_667 nanoseconds. + Weight::from_ref_time(99_157_239_000) + .saturating_add(Weight::from_proof_size(19094)) + .saturating_add(RocksDbWeight::get().reads(8_u64)) + } + /// Storage: Glutton Storage (r:1 w:0) + /// Proof: Glutton Storage (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Glutton Compute (r:1 w:0) + /// Proof: Glutton Compute (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + fn empty_on_idle() -> Weight { + // Proof Size summary in bytes: + // Measured: `4` + // Estimated: `998` + // Minimum execution time: 3_967 nanoseconds. + Weight::from_ref_time(4_121_000) + .saturating_add(Weight::from_proof_size(998)) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + } + /// Storage: Glutton Compute (r:0 w:1) + /// Proof: Glutton Compute (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + fn set_compute() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 7_112 nanoseconds. + Weight::from_ref_time(7_484_000) + .saturating_add(Weight::from_proof_size(0)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Glutton Storage (r:0 w:1) + /// Proof: Glutton Storage (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + fn set_storage() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 7_056 nanoseconds. + Weight::from_ref_time(7_414_000) + .saturating_add(Weight::from_proof_size(0)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } +} From b77175df6b7c73e0f56bb38aca875f8096b25379 Mon Sep 17 00:00:00 2001 From: Daniel Shiposha Date: Tue, 21 Feb 2023 22:56:07 +0000 Subject: [PATCH 425/715] Introduce EnsureOrigin to democracy.propose (#13410) * feat: add submitorigin to democracy * fix: democracy tests * fix: SubmitOrigin doc comment Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --------- Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- bin/node/runtime/src/lib.rs | 1 + frame/democracy/src/lib.rs | 7 ++++++- frame/democracy/src/tests.rs | 3 ++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 3e3a0d75366ac..e02792b95275a 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -948,6 +948,7 @@ impl pallet_democracy::Config for Runtime { /// (NTB) vote. type ExternalDefaultOrigin = pallet_collective::EnsureProportionAtLeast; + type SubmitOrigin = EnsureSigned; /// Two thirds of the technical committee can have an ExternalMajority/ExternalDefault vote /// be tabled immediately and with a shorter voting/enactment period. type FastTrackOrigin = diff --git a/frame/democracy/src/lib.rs b/frame/democracy/src/lib.rs index b3ac3dfe78674..e1e111e96313f 100644 --- a/frame/democracy/src/lib.rs +++ b/frame/democracy/src/lib.rs @@ -308,6 +308,11 @@ pub mod pallet { /// of a negative-turnout-bias (default-carries) referendum. type ExternalDefaultOrigin: EnsureOrigin; + /// Origin from which the new proposal can be made. + /// + /// The success variant is the account id of the depositor. + type SubmitOrigin: 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. @@ -590,7 +595,7 @@ pub mod pallet { proposal: BoundedCallOf, #[pallet::compact] value: BalanceOf, ) -> DispatchResult { - let who = ensure_signed(origin)?; + let who = T::SubmitOrigin::ensure_origin(origin)?; ensure!(value >= T::MinimumDeposit::get(), Error::::ValueLow); let index = Self::public_prop_count(); diff --git a/frame/democracy/src/tests.rs b/frame/democracy/src/tests.rs index eb1d2650afc45..9e735765905d6 100644 --- a/frame/democracy/src/tests.rs +++ b/frame/democracy/src/tests.rs @@ -27,7 +27,7 @@ use frame_support::{ }, weights::Weight, }; -use frame_system::{EnsureRoot, EnsureSignedBy}; +use frame_system::{EnsureRoot, EnsureSigned, EnsureSignedBy}; use pallet_balances::{BalanceLock, Error as BalancesError}; use sp_core::H256; use sp_runtime::{ @@ -177,6 +177,7 @@ impl Config for Test { type MinimumDeposit = ConstU64<1>; type MaxDeposits = ConstU32<1000>; type MaxBlacklisted = ConstU32<5>; + type SubmitOrigin = EnsureSigned; type ExternalOrigin = EnsureSignedBy; type ExternalMajorityOrigin = EnsureSignedBy; type ExternalDefaultOrigin = EnsureSignedBy; From 86c6bb9614c437b63f3dbd2afddef52f32af7866 Mon Sep 17 00:00:00 2001 From: Koute Date: Wed, 22 Feb 2023 16:49:25 +0900 Subject: [PATCH 426/715] Rework storage iterators (#13284) * Rework storage iterators * Make sure storage iteration is also accounted for when benchmarking * Use `trie-db` from crates.io * Appease clippy * Bump `trie-bench` to 0.35.0 * Fix tests' compilation * Update comment to clarify how `IterArgs::start_at` works * Add extra tests * Fix iterators on `Client` so that they behave as before * Add extra `unwrap`s in tests * More clippy fixes * Come on clippy, give me a break already * Rename `allow_missing` to `stop_on_incomplete_database` * Add `#[inline]` to `with_recorder_and_cache` * Use `with_recorder_and_cache` in `with_trie_db`; add doc comment * Simplify code: use `with_trie_db` in `next_storage_key_from_root` * Remove `expect`s in the benchmarking CLI * Add extra doc comments * Move `RawIter` before `TrieBackendEssence` (no code changes; just cut-paste) * Remove a TODO in tests * Update comment for `StorageIterator::was_complete` * Update `trie-db` to 0.25.1 --- Cargo.lock | 14 +- client/api/src/backend.rs | 186 +++++--- client/db/Cargo.toml | 1 + client/db/src/bench.rs | 228 ++++++---- client/db/src/lib.rs | 82 ++-- client/db/src/record_stats_state.rs | 86 ++-- client/rpc/src/state/state_full.rs | 22 +- .../service/src/chain_ops/export_raw_state.rs | 46 +- client/service/src/client/client.rs | 62 +-- client/service/test/src/client/mod.rs | 102 ++++- primitives/state-machine/Cargo.toml | 6 +- primitives/state-machine/src/backend.rs | 236 +++++++++- primitives/state-machine/src/ext.rs | 55 ++- primitives/state-machine/src/lib.rs | 2 +- primitives/state-machine/src/testing.rs | 7 +- primitives/state-machine/src/trie_backend.rs | 236 +++++++--- .../state-machine/src/trie_backend_essence.rs | 413 +++++++----------- primitives/storage/src/lib.rs | 1 + primitives/trie/Cargo.toml | 4 +- primitives/trie/src/cache/mod.rs | 4 +- primitives/trie/src/lib.rs | 3 +- primitives/trie/src/recorder.rs | 3 +- test-utils/runtime/Cargo.toml | 2 +- .../frame/benchmarking-cli/src/storage/cmd.rs | 4 +- .../benchmarking-cli/src/storage/read.rs | 7 +- .../benchmarking-cli/src/storage/write.rs | 7 +- .../rpc/state-trie-migration-rpc/Cargo.toml | 2 +- 27 files changed, 1088 insertions(+), 733 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7c0b40cd99da9..0f271f807a753 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2902,6 +2902,9 @@ name = "hashbrown" version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash 0.8.3", +] [[package]] name = "heck" @@ -8090,6 +8093,7 @@ dependencies = [ name = "sc-client-db" version = "0.10.0-dev" dependencies = [ + "array-bytes", "criterion", "hash-db", "kitchensink-runtime", @@ -11354,9 +11358,9 @@ dependencies = [ [[package]] name = "trie-bench" -version = "0.34.0" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fbb0a830db7c42ae97ce4e21b30e2cf9dbcc1b4f7853bd1aedad3d806c281d0" +checksum = "22c1d18c423077531e693e87ace54ed9e4af1e4ce0a3ea8c9aa6608741074e2b" dependencies = [ "criterion", "hash-db", @@ -11370,12 +11374,12 @@ dependencies = [ [[package]] name = "trie-db" -version = "0.24.0" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "004e1e8f92535694b4cb1444dc5a8073ecf0815e3357f729638b9f8fc4062908" +checksum = "3390c0409daaa6027d6681393316f4ccd3ff82e1590a1e4725014e3ae2bf1920" dependencies = [ "hash-db", - "hashbrown 0.12.3", + "hashbrown 0.13.2", "log", "rustc-hex", "smallvec", diff --git a/client/api/src/backend.rs b/client/api/src/backend.rs index bc799a418d5dc..486ac50611e35 100644 --- a/client/api/src/backend.rs +++ b/client/api/src/backend.rs @@ -31,14 +31,13 @@ use sp_runtime::{ Justification, Justifications, StateVersion, Storage, }; use sp_state_machine::{ - backend::AsTrieBackend, ChildStorageCollection, IndexOperation, OffchainChangesCollection, - StorageCollection, + backend::AsTrieBackend, ChildStorageCollection, IndexOperation, IterArgs, + OffchainChangesCollection, StorageCollection, StorageIterator, }; use sp_storage::{ChildInfo, StorageData, StorageKey}; use std::collections::{HashMap, HashSet}; pub use sp_state_machine::{Backend as StateBackend, KeyValueStates}; -use std::marker::PhantomData; /// Extracts the state backend type for the given backend. pub type StateBackendFor = >::State; @@ -303,32 +302,61 @@ pub trait AuxStore { } /// An `Iterator` that iterates keys in a given block under a prefix. -pub struct KeyIterator { +pub struct KeysIter +where + State: StateBackend>, + Block: BlockT, +{ + inner: >>::RawIter, state: State, - child_storage: Option, - prefix: Option, - current_key: Vec, - _phantom: PhantomData, + skip_if_first: Option, } -impl KeyIterator { - /// create a KeyIterator instance - pub fn new(state: State, prefix: Option, current_key: Vec) -> Self { - Self { state, child_storage: None, prefix, current_key, _phantom: PhantomData } +impl KeysIter +where + State: StateBackend>, + Block: BlockT, +{ + /// Create a new iterator over storage keys. + pub fn new( + state: State, + prefix: Option<&StorageKey>, + start_at: Option<&StorageKey>, + ) -> Result { + let mut args = IterArgs::default(); + args.prefix = prefix.as_ref().map(|prefix| prefix.0.as_slice()); + args.start_at = start_at.as_ref().map(|start_at| start_at.0.as_slice()); + + let start_at = args.start_at; + Ok(Self { + inner: state.raw_iter(args)?, + state, + skip_if_first: start_at.map(|key| StorageKey(key.to_vec())), + }) } - /// Create a `KeyIterator` instance for a child storage. + /// Create a new iterator over a child storage's keys. pub fn new_child( state: State, child_info: ChildInfo, - prefix: Option, - current_key: Vec, - ) -> Self { - Self { state, child_storage: Some(child_info), prefix, current_key, _phantom: PhantomData } + prefix: Option<&StorageKey>, + start_at: Option<&StorageKey>, + ) -> Result { + let mut args = IterArgs::default(); + args.prefix = prefix.as_ref().map(|prefix| prefix.0.as_slice()); + args.start_at = start_at.as_ref().map(|start_at| start_at.0.as_slice()); + args.child_info = Some(child_info); + + let start_at = args.start_at; + Ok(Self { + inner: state.raw_iter(args)?, + state, + skip_if_first: start_at.map(|key| StorageKey(key.to_vec())), + }) } } -impl Iterator for KeyIterator +impl Iterator for KeysIter where Block: BlockT, State: StateBackend>, @@ -336,25 +364,78 @@ where type Item = StorageKey; fn next(&mut self) -> Option { - let next_key = if let Some(child_info) = self.child_storage.as_ref() { - self.state.next_child_storage_key(child_info, &self.current_key) - } else { - self.state.next_storage_key(&self.current_key) + let key = self.inner.next_key(&self.state)?.ok().map(StorageKey)?; + + if let Some(skipped_key) = self.skip_if_first.take() { + if key == skipped_key { + return self.next() + } } - .ok() - .flatten()?; - // this terminates the iterator the first time it fails. - if let Some(ref prefix) = self.prefix { - if !next_key.starts_with(&prefix.0[..]) { - return None + + Some(key) + } +} + +/// An `Iterator` that iterates keys and values in a given block under a prefix. +pub struct PairsIter +where + State: StateBackend>, + Block: BlockT, +{ + inner: >>::RawIter, + state: State, + skip_if_first: Option, +} + +impl Iterator for PairsIter +where + Block: BlockT, + State: StateBackend>, +{ + type Item = (StorageKey, StorageData); + + fn next(&mut self) -> Option { + let (key, value) = self + .inner + .next_pair(&self.state)? + .ok() + .map(|(key, value)| (StorageKey(key), StorageData(value)))?; + + if let Some(skipped_key) = self.skip_if_first.take() { + if key == skipped_key { + return self.next() } } - self.current_key = next_key.clone(); - Some(StorageKey(next_key)) + + Some((key, value)) } } -/// Provides acess to storage primitives +impl PairsIter +where + State: StateBackend>, + Block: BlockT, +{ + /// Create a new iterator over storage key and value pairs. + pub fn new( + state: State, + prefix: Option<&StorageKey>, + start_at: Option<&StorageKey>, + ) -> Result { + let mut args = IterArgs::default(); + args.prefix = prefix.as_ref().map(|prefix| prefix.0.as_slice()); + args.start_at = start_at.as_ref().map(|start_at| start_at.0.as_slice()); + + let start_at = args.start_at; + Ok(Self { + inner: state.raw_iter(args)?, + state, + skip_if_first: start_at.map(|key| StorageKey(key.to_vec())), + }) + } +} + +/// Provides access to storage primitives pub trait StorageProvider> { /// Given a block's `Hash` and a key, return the value under the key in that block. fn storage( @@ -363,13 +444,6 @@ pub trait StorageProvider> { 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, - 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, @@ -377,22 +451,23 @@ pub trait StorageProvider> { key: &StorageKey, ) -> sp_blockchain::Result>; - /// Given a block's `Hash` and a key prefix, return the matching child storage keys and values - /// in that block. - fn storage_pairs( + /// Given a block's `Hash` and a key prefix, returns a `KeysIter` iterates matching storage + /// keys in that block. + fn storage_keys( &self, hash: Block::Hash, - key_prefix: &StorageKey, - ) -> sp_blockchain::Result>; + prefix: Option<&StorageKey>, + start_key: Option<&StorageKey>, + ) -> sp_blockchain::Result>; - /// Given a block's `Hash` and a key prefix, return a `KeyIterator` iterates matching storage - /// keys in that block. - fn storage_keys_iter( + /// Given a block's `Hash` and a key prefix, returns an iterator over the storage keys and + /// values in that block. + fn storage_pairs( &self, - hash: Block::Hash, + hash: ::Hash, prefix: Option<&StorageKey>, start_key: Option<&StorageKey>, - ) -> sp_blockchain::Result>; + ) -> sp_blockchain::Result>; /// Given a block's `Hash`, a key and a child storage key, return the value under the key in /// that block. @@ -403,24 +478,15 @@ pub trait StorageProvider> { key: &StorageKey, ) -> sp_blockchain::Result>; - /// Given a block's `Hash`, a key prefix, and a child storage key, return the matching child - /// storage keys. - fn child_storage_keys( - &self, - hash: Block::Hash, - child_info: &ChildInfo, - key_prefix: &StorageKey, - ) -> sp_blockchain::Result>; - /// 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( + /// returns a `KeysIter` that iterates matching storage keys in that block. + fn child_storage_keys( &self, hash: Block::Hash, child_info: ChildInfo, prefix: Option<&StorageKey>, start_key: Option<&StorageKey>, - ) -> sp_blockchain::Result>; + ) -> sp_blockchain::Result>; /// Given a block's `Hash`, a key and a child storage key, return the hash under the key in that /// block. diff --git a/client/db/Cargo.toml b/client/db/Cargo.toml index 7a62cb1ea0f53..73eca1dff708a 100644 --- a/client/db/Cargo.toml +++ b/client/db/Cargo.toml @@ -44,6 +44,7 @@ quickcheck = { version = "1.0.3", default-features = false } kitchensink-runtime = { path = "../../bin/node/runtime" } sp-tracing = { version = "6.0.0", path = "../../primitives/tracing" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } +array-bytes = "4.1" [features] default = [] diff --git a/client/db/src/bench.rs b/client/db/src/bench.rs index b8fb3b6cec223..b1fe3f206f58b 100644 --- a/client/db/src/bench.rs +++ b/client/db/src/bench.rs @@ -22,6 +22,7 @@ use crate::{DbState, DbStateBuilder}; use hash_db::{Hasher, Prefix}; use kvdb::{DBTransaction, KeyValueDB}; use linked_hash_map::LinkedHashMap; +use parking_lot::Mutex; use sp_core::{ hexdisplay::HexDisplay, storage::{ChildInfo, TrackedStorageKey}, @@ -31,7 +32,8 @@ use sp_runtime::{ StateVersion, Storage, }; use sp_state_machine::{ - backend::Backend as StateBackend, ChildStorageCollection, DBValue, StorageCollection, + backend::Backend as StateBackend, ChildStorageCollection, DBValue, IterArgs, StorageCollection, + StorageIterator, StorageKey, StorageValue, }; use sp_trie::{ cache::{CacheSize, SharedTrieCache}, @@ -59,6 +61,19 @@ impl sp_state_machine::Storage> for StorageDb, TrackedStorageKey>, + /// Key tracker for keys in a child trie. + /// Child trie are identified by their storage key (i.e. `ChildInfo::storage_key()`) + /// We track the total number of reads and writes to these keys, + /// not de-duplicated for repeats. + child_keys: LinkedHashMap, LinkedHashMap, TrackedStorageKey>>, +} + /// State that manages the backend database reference. Allows runtime to control the database. pub struct BenchmarkingState { root: Cell, @@ -67,22 +82,52 @@ pub struct BenchmarkingState { db: Cell>>, genesis: HashMap, (Vec, i32)>, record: Cell>>, - /// 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. - main_key_tracker: RefCell, TrackedStorageKey>>, - /// Key tracker for keys in a child trie. - /// Child trie are identified by their storage key (i.e. `ChildInfo::storage_key()`) - /// We track the total number of reads and writes to these keys, - /// not de-duplicated for repeats. - child_key_tracker: RefCell, LinkedHashMap, TrackedStorageKey>>>, + key_tracker: Arc>, whitelist: RefCell>, proof_recorder: Option>>, proof_recorder_root: Cell, - enable_tracking: bool, shared_trie_cache: SharedTrieCache>, } +/// A raw iterator over the `BenchmarkingState`. +pub struct RawIter { + inner: as StateBackend>>::RawIter, + child_trie: Option>, + key_tracker: Arc>, +} + +impl StorageIterator> for RawIter { + type Backend = BenchmarkingState; + type Error = String; + + fn next_key(&mut self, backend: &Self::Backend) -> Option> { + match self.inner.next_key(backend.state.borrow().as_ref()?) { + Some(Ok(key)) => { + self.key_tracker.lock().add_read_key(self.child_trie.as_deref(), &key); + Some(Ok(key)) + }, + result => result, + } + } + + fn next_pair( + &mut self, + backend: &Self::Backend, + ) -> Option> { + match self.inner.next_pair(backend.state.borrow().as_ref()?) { + Some(Ok((key, value))) => { + self.key_tracker.lock().add_read_key(self.child_trie.as_deref(), &key); + Some(Ok((key, value))) + }, + result => result, + } + } + + fn was_complete(&self) -> bool { + self.inner.was_complete() + } +} + impl BenchmarkingState { /// Create a new instance that creates a database in a temporary dir. pub fn new( @@ -103,12 +148,14 @@ impl BenchmarkingState { genesis: Default::default(), genesis_root: Default::default(), record: Default::default(), - main_key_tracker: Default::default(), - child_key_tracker: Default::default(), + key_tracker: Arc::new(Mutex::new(KeyTracker { + main_keys: Default::default(), + child_keys: Default::default(), + enable_tracking, + })), 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::new(0)), }; @@ -123,7 +170,7 @@ impl BenchmarkingState { ) }); let (root, transaction): (B::Hash, _) = - state.state.borrow_mut().as_mut().unwrap().full_storage_root( + state.state.borrow().as_ref().unwrap().full_storage_root( genesis.top.iter().map(|(k, v)| (k.as_ref(), Some(v.as_ref()))), child_delta, state_version, @@ -157,36 +204,51 @@ impl BenchmarkingState { } fn add_whitelist_to_tracker(&self) { - let mut main_key_tracker = self.main_key_tracker.borrow_mut(); + self.key_tracker.lock().add_whitelist(&self.whitelist.borrow()); + } + + fn wipe_tracker(&self) { + let mut key_tracker = self.key_tracker.lock(); + key_tracker.main_keys = LinkedHashMap::new(); + key_tracker.child_keys = LinkedHashMap::new(); + key_tracker.add_whitelist(&self.whitelist.borrow()); + } + + fn add_read_key(&self, childtrie: Option<&[u8]>, key: &[u8]) { + self.key_tracker.lock().add_read_key(childtrie, key); + } + + fn add_write_key(&self, childtrie: Option<&[u8]>, key: &[u8]) { + self.key_tracker.lock().add_write_key(childtrie, key); + } - let whitelist = self.whitelist.borrow(); + fn all_trackers(&self) -> Vec { + self.key_tracker.lock().all_trackers() + } +} +impl KeyTracker { + fn add_whitelist(&mut self, whitelist: &[TrackedStorageKey]) { whitelist.iter().for_each(|key| { let mut whitelisted = TrackedStorageKey::new(key.key.clone()); whitelisted.whitelist(); - main_key_tracker.insert(key.key.clone(), whitelisted); + self.main_keys.insert(key.key.clone(), whitelisted); }); } - fn wipe_tracker(&self) { - *self.main_key_tracker.borrow_mut() = LinkedHashMap::new(); - *self.child_key_tracker.borrow_mut() = LinkedHashMap::new(); - self.add_whitelist_to_tracker(); - } - // Childtrie is identified by its storage key (i.e. `ChildInfo::storage_key`) - fn add_read_key(&self, childtrie: Option<&[u8]>, key: &[u8]) { + fn add_read_key(&mut self, childtrie: Option<&[u8]>, key: &[u8]) { if !self.enable_tracking { return } - let mut child_key_tracker = self.child_key_tracker.borrow_mut(); - let mut main_key_tracker = self.main_key_tracker.borrow_mut(); + let child_key_tracker = &mut self.child_keys; + let main_key_tracker = &mut self.main_keys; let key_tracker = if let Some(childtrie) = childtrie { child_key_tracker.entry(childtrie.to_vec()).or_insert_with(LinkedHashMap::new) } else { - &mut main_key_tracker + main_key_tracker }; let should_log = match key_tracker.get_mut(key) { @@ -216,18 +278,18 @@ impl BenchmarkingState { } // Childtrie is identified by its storage key (i.e. `ChildInfo::storage_key`) - fn add_write_key(&self, childtrie: Option<&[u8]>, key: &[u8]) { + fn add_write_key(&mut self, childtrie: Option<&[u8]>, key: &[u8]) { if !self.enable_tracking { return } - let mut child_key_tracker = self.child_key_tracker.borrow_mut(); - let mut main_key_tracker = self.main_key_tracker.borrow_mut(); + let child_key_tracker = &mut self.child_keys; + let main_key_tracker = &mut self.main_keys; let key_tracker = if let Some(childtrie) = childtrie { child_key_tracker.entry(childtrie.to_vec()).or_insert_with(LinkedHashMap::new) } else { - &mut main_key_tracker + main_key_tracker }; // If we have written to the key, we also consider that we have read from it. @@ -261,11 +323,11 @@ impl BenchmarkingState { fn all_trackers(&self) -> Vec { let mut all_trackers = Vec::new(); - self.main_key_tracker.borrow().iter().for_each(|(_, tracker)| { + self.main_keys.iter().for_each(|(_, tracker)| { all_trackers.push(tracker.clone()); }); - self.child_key_tracker.borrow().iter().for_each(|(_, child_tracker)| { + self.child_keys.iter().for_each(|(_, child_tracker)| { child_tracker.iter().for_each(|(_, tracker)| { all_trackers.push(tracker.clone()); }); @@ -283,6 +345,7 @@ impl StateBackend> for BenchmarkingState { type Error = as StateBackend>>::Error; type Transaction = as StateBackend>>::Transaction; type TrieBackendStorage = as StateBackend>>::TrieBackendStorage; + type RawIter = RawIter; fn storage(&self, key: &[u8]) -> Result>, Self::Error> { self.add_read_key(None, key); @@ -356,58 +419,6 @@ impl StateBackend> for BenchmarkingState { .next_child_storage_key(child_info, key) } - fn for_keys_with_prefix(&self, prefix: &[u8], f: F) { - if let Some(ref state) = *self.state.borrow() { - state.for_keys_with_prefix(prefix, f) - } - } - - fn for_key_values_with_prefix(&self, prefix: &[u8], f: F) { - if let Some(ref state) = *self.state.borrow() { - state.for_key_values_with_prefix(prefix, f) - } - } - - 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.borrow().as_ref().ok_or_else(state_err)?.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, - ) { - if let Some(ref state) = *self.state.borrow() { - state.apply_to_keys_while(child_info, prefix, start_at, f) - } - } - - fn for_child_keys_with_prefix( - &self, - child_info: &ChildInfo, - prefix: &[u8], - f: F, - ) { - if let Some(ref state) = *self.state.borrow() { - state.for_child_keys_with_prefix(child_info, prefix, f) - } - } - fn storage_root<'a>( &self, delta: impl Iterator)>, @@ -437,19 +448,19 @@ impl StateBackend> for BenchmarkingState { .map_or(Default::default(), |s| s.child_storage_root(child_info, delta, state_version)) } - fn pairs(&self) -> Vec<(Vec, Vec)> { - self.state.borrow().as_ref().map_or(Default::default(), |s| s.pairs()) - } - - fn keys(&self, prefix: &[u8]) -> Vec> { - self.state.borrow().as_ref().map_or(Default::default(), |s| s.keys(prefix)) - } - - fn child_keys(&self, child_info: &ChildInfo, prefix: &[u8]) -> Vec> { + fn raw_iter(&self, args: IterArgs) -> Result { + let child_trie = + args.child_info.as_ref().map(|child_info| child_info.storage_key().to_vec()); self.state .borrow() .as_ref() - .map_or(Default::default(), |s| s.child_keys(child_info, prefix)) + .map(|s| s.raw_iter(args)) + .unwrap_or(Ok(Default::default())) + .map(|raw_iter| RawIter { + inner: raw_iter, + key_tracker: self.key_tracker.clone(), + child_trie, + }) } fn commit( @@ -587,7 +598,7 @@ impl StateBackend> for BenchmarkingState { } fn register_overlay_stats(&self, stats: &sp_state_machine::StateMachineStats) { - self.state.borrow_mut().as_mut().map(|s| s.register_overlay_stats(stats)); + self.state.borrow().as_ref().map(|s| s.register_overlay_stats(stats)); } fn usage_info(&self) -> sp_state_machine::UsageInfo { @@ -639,6 +650,29 @@ mod test { use crate::bench::BenchmarkingState; use sp_state_machine::backend::Backend as _; + fn hex(hex: &str) -> Vec { + array_bytes::hex2bytes(hex).unwrap() + } + + #[test] + fn iteration_is_also_counted_in_rw_counts() { + let storage = sp_runtime::Storage { + top: vec![( + hex("ce6e1397e668c7fcf47744350dc59688455a2c2dbd2e2a649df4e55d93cd7158"), + hex("0102030405060708"), + )] + .into_iter() + .collect(), + ..sp_runtime::Storage::default() + }; + let bench_state = + BenchmarkingState::::new(storage, None, false, true).unwrap(); + + assert_eq!(bench_state.read_write_count(), (0, 0, 0, 0)); + assert_eq!(bench_state.keys(Default::default()).unwrap().count(), 1); + assert_eq!(bench_state.read_write_count(), (1, 0, 0, 0)); + } + #[test] fn read_to_main_and_child_tries() { let bench_state = diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index 24c66fd7796e3..b78c66228390d 100644 --- a/client/db/src/lib.rs +++ b/client/db/src/lib.rs @@ -86,8 +86,9 @@ use sp_runtime::{ }; use sp_state_machine::{ backend::{AsTrieBackend, Backend as StateBackend}, - ChildStorageCollection, DBValue, IndexOperation, OffchainChangesCollection, StateMachineStats, - StorageCollection, UsageInfo as StateUsageInfo, + ChildStorageCollection, DBValue, IndexOperation, IterArgs, OffchainChangesCollection, + StateMachineStats, StorageCollection, StorageIterator, StorageKey, StorageValue, + UsageInfo as StateUsageInfo, }; use sp_trie::{cache::SharedTrieCache, prefixed_key, MemoryDB, PrefixedMemoryDB}; @@ -159,10 +160,36 @@ impl std::fmt::Debug for RefTrackingState { } } +/// A raw iterator over the `RefTrackingState`. +pub struct RawIter { + inner: as StateBackend>>::RawIter, +} + +impl StorageIterator> for RawIter { + type Backend = RefTrackingState; + type Error = as StateBackend>>::Error; + + fn next_key(&mut self, backend: &Self::Backend) -> Option> { + self.inner.next_key(&backend.state) + } + + fn next_pair( + &mut self, + backend: &Self::Backend, + ) -> Option> { + self.inner.next_pair(&backend.state) + } + + fn was_complete(&self) -> bool { + self.inner.was_complete() + } +} + impl StateBackend> for RefTrackingState { type Error = as StateBackend>>::Error; type Transaction = as StateBackend>>::Transaction; type TrieBackendStorage = as StateBackend>>::TrieBackendStorage; + type RawIter = RawIter; fn storage(&self, key: &[u8]) -> Result>, Self::Error> { self.state.storage(key) @@ -212,45 +239,6 @@ impl StateBackend> for RefTrackingState { 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 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 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)>, @@ -274,16 +262,8 @@ impl StateBackend> for RefTrackingState { 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 raw_iter(&self, args: IterArgs) -> Result { + self.state.raw_iter(args).map(|inner| RawIter { inner }) } fn register_overlay_stats(&self, stats: &StateMachineStats) { diff --git a/client/db/src/record_stats_state.rs b/client/db/src/record_stats_state.rs index 91d6c2fe5bfad..2776802dde04e 100644 --- a/client/db/src/record_stats_state.rs +++ b/client/db/src/record_stats_state.rs @@ -26,7 +26,7 @@ use sp_runtime::{ }; use sp_state_machine::{ backend::{AsTrieBackend, Backend as StateBackend}, - TrieBackend, + IterArgs, StorageIterator, StorageKey, StorageValue, TrieBackend, }; use std::sync::Arc; @@ -73,10 +73,43 @@ impl>, B: BlockT> RecordStatsState { } } +pub struct RawIter +where + S: StateBackend>, + B: BlockT, +{ + inner: >>::RawIter, +} + +impl StorageIterator> for RawIter +where + S: StateBackend>, + B: BlockT, +{ + type Backend = RecordStatsState; + type Error = S::Error; + + fn next_key(&mut self, backend: &Self::Backend) -> Option> { + self.inner.next_key(&backend.state) + } + + fn next_pair( + &mut self, + backend: &Self::Backend, + ) -> Option> { + self.inner.next_pair(&backend.state) + } + + fn was_complete(&self) -> bool { + self.inner.was_complete() + } +} + impl>, B: BlockT> StateBackend> for RecordStatsState { type Error = S::Error; type Transaction = S::Transaction; type TrieBackendStorage = S::TrieBackendStorage; + type RawIter = RawIter; fn storage(&self, key: &[u8]) -> Result>, Self::Error> { let value = self.state.storage(key)?; @@ -122,28 +155,6 @@ impl>, B: BlockT> StateBackend> for Record 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) } @@ -156,23 +167,6 @@ impl>, B: BlockT> StateBackend> for Record 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)>, @@ -196,16 +190,8 @@ impl>, B: BlockT> StateBackend> for Record 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 raw_iter(&self, args: IterArgs) -> Result { + self.state.raw_iter(args).map(|inner| RawIter { inner }) } fn register_overlay_stats(&self, stats: &sp_state_machine::StateMachineStats) { diff --git a/client/rpc/src/state/state_full.rs b/client/rpc/src/state/state_full.rs index ffc97487a8155..efd2085398238 100644 --- a/client/rpc/src/state/state_full.rs +++ b/client/rpc/src/state/state_full.rs @@ -213,23 +213,29 @@ where .map_err(client_err) } + // TODO: This is horribly broken; either remove it, or make it streaming. fn storage_keys( &self, block: Option, prefix: StorageKey, ) -> std::result::Result, Error> { + // TODO: Remove the `.collect`. self.block_or_best(block) - .and_then(|block| self.client.storage_keys(block, &prefix)) + .and_then(|block| self.client.storage_keys(block, Some(&prefix), None)) + .map(|iter| iter.collect()) .map_err(client_err) } + // TODO: This is horribly broken; either remove it, or make it streaming. fn storage_pairs( &self, block: Option, prefix: StorageKey, ) -> std::result::Result, Error> { + // TODO: Remove the `.collect`. self.block_or_best(block) - .and_then(|block| self.client.storage_pairs(block, &prefix)) + .and_then(|block| self.client.storage_pairs(block, Some(&prefix), None)) + .map(|iter| iter.collect()) .map_err(client_err) } @@ -241,9 +247,7 @@ where start_key: Option, ) -> 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()) - }) + .and_then(|block| self.client.storage_keys(block, prefix.as_ref(), start_key.as_ref())) .map(|iter| iter.take(count as usize).collect()) .map_err(client_err) } @@ -284,7 +288,7 @@ where } // The key doesn't point to anything, so it's probably a prefix. - let iter = match client.storage_keys_iter(block, Some(&key), None).map_err(client_err) { + let iter = match client.storage_keys(block, Some(&key), None).map_err(client_err) { Ok(iter) => iter, Err(e) => return Ok(Err(e)), }; @@ -531,6 +535,7 @@ where storage_key: PrefixedStorageKey, prefix: StorageKey, ) -> std::result::Result, Error> { + // TODO: Remove the `.collect`. self.block_or_best(block) .and_then(|block| { let child_info = match ChildType::from_prefixed_key(&storage_key) { @@ -538,8 +543,9 @@ 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, Some(&prefix), None) }) + .map(|iter| iter.collect()) .map_err(client_err) } @@ -558,7 +564,7 @@ where ChildInfo::new_default(storage_key), None => return Err(sp_blockchain::Error::InvalidChildStorageKey), }; - self.client.child_storage_keys_iter( + self.client.child_storage_keys( block, child_info, prefix.as_ref(), diff --git a/client/service/src/chain_ops/export_raw_state.rs b/client/service/src/chain_ops/export_raw_state.rs index f5e154795b9b7..fde2c5617cb41 100644 --- a/client/service/src/chain_ops/export_raw_state.rs +++ b/client/service/src/chain_ops/export_raw_state.rs @@ -21,7 +21,10 @@ use sc_client_api::{StorageProvider, UsageProvider}; use sp_core::storage::{well_known_keys, ChildInfo, Storage, StorageChild, StorageKey, StorageMap}; use sp_runtime::traits::Block as BlockT; -use std::{collections::HashMap, sync::Arc}; +use std::{ + collections::{BTreeMap, HashMap}, + sync::Arc, +}; /// Export the raw state at the given `block`. If `block` is `None`, the /// best block will be used. @@ -31,35 +34,30 @@ where B: BlockT, BA: sc_client_api::backend::Backend, { - let empty_key = StorageKey(Vec::new()); - let mut top_storage = client.storage_pairs(hash, &empty_key)?; + let mut top = BTreeMap::new(); let mut children_default = HashMap::new(); - // Remove all default child storage roots from the top storage and collect the child storage - // pairs. - while let Some(pos) = top_storage - .iter() - .position(|(k, _)| k.0.starts_with(well_known_keys::DEFAULT_CHILD_STORAGE_KEY_PREFIX)) - { - let (key, _) = top_storage.swap_remove(pos); - - let key = - 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(hash, &child_info, &empty_key)?; - let mut pairs = StorageMap::new(); - keys.into_iter().try_for_each(|k| { - if let Some(value) = client.child_storage(hash, &child_info, &k)? { - pairs.insert(k.0, value.0); + for (key, value) in client.storage_pairs(hash, None, None)? { + // Remove all default child storage roots from the top storage and collect the child storage + // pairs. + if key.0.starts_with(well_known_keys::DEFAULT_CHILD_STORAGE_KEY_PREFIX) { + let child_root_key = StorageKey( + key.0[well_known_keys::DEFAULT_CHILD_STORAGE_KEY_PREFIX.len()..].to_vec(), + ); + let child_info = ChildInfo::new_default(&child_root_key.0); + let mut pairs = StorageMap::new(); + for child_key in client.child_storage_keys(hash, child_info.clone(), None, None)? { + if let Some(child_value) = client.child_storage(hash, &child_info, &child_key)? { + pairs.insert(child_key.0, child_value.0); + } } - Ok::<_, Error>(()) - })?; + children_default.insert(child_root_key.0, StorageChild { child_info, data: pairs }); + continue + } - children_default.insert(key.0, StorageChild { child_info, data: pairs }); + top.insert(key.0, value.0); } - let top = top_storage.into_iter().map(|(k, v)| (k.0, v.0)).collect(); Ok(Storage { top, children_default }) } diff --git a/client/service/src/client/client.rs b/client/service/src/client/client.rs index 968044ba5cf97..ddeec5c73e63e 100644 --- a/client/service/src/client/client.rs +++ b/client/service/src/client/client.rs @@ -40,8 +40,8 @@ use sc_client_api::{ }, execution_extensions::ExecutionExtensions, notifications::{StorageEventStream, StorageNotifications}, - CallExecutor, ExecutorProvider, KeyIterator, OnFinalityAction, OnImportAction, ProofProvider, - UsageProvider, + CallExecutor, ExecutorProvider, KeysIter, OnFinalityAction, OnImportAction, PairsIter, + ProofProvider, UsageProvider, }; use sc_consensus::{ BlockCheckParams, BlockImportParams, ForkChoiceStrategy, ImportResult, StateAction, @@ -1462,52 +1462,37 @@ where Block: BlockT, { fn storage_keys( - &self, - hash: Block::Hash, - key_prefix: &StorageKey, - ) -> sp_blockchain::Result> { - let keys = self.state_at(hash)?.keys(&key_prefix.0).into_iter().map(StorageKey).collect(); - Ok(keys) - } - - fn storage_pairs( &self, hash: ::Hash, - key_prefix: &StorageKey, - ) -> sp_blockchain::Result> { + prefix: Option<&StorageKey>, + start_key: Option<&StorageKey>, + ) -> sp_blockchain::Result> { let state = self.state_at(hash)?; - let keys = state - .keys(&key_prefix.0) - .into_iter() - .map(|k| { - let d = state.storage(&k).ok().flatten().unwrap_or_default(); - (StorageKey(k), StorageData(d)) - }) - .collect(); - Ok(keys) + KeysIter::new(state, prefix, start_key) + .map_err(|e| sp_blockchain::Error::from_state(Box::new(e))) } - fn storage_keys_iter( + fn child_storage_keys( &self, hash: ::Hash, + child_info: ChildInfo, prefix: Option<&StorageKey>, start_key: Option<&StorageKey>, - ) -> sp_blockchain::Result> { + ) -> sp_blockchain::Result> { 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.cloned(), start_key)) + KeysIter::new_child(state, child_info, prefix, start_key) + .map_err(|e| sp_blockchain::Error::from_state(Box::new(e))) } - fn child_storage_keys_iter( + fn storage_pairs( &self, hash: ::Hash, - child_info: ChildInfo, prefix: Option<&StorageKey>, start_key: Option<&StorageKey>, - ) -> sp_blockchain::Result> { + ) -> sp_blockchain::Result> { 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.cloned(), start_key)) + PairsIter::new(state, prefix, start_key) + .map_err(|e| sp_blockchain::Error::from_state(Box::new(e))) } fn storage( @@ -1532,21 +1517,6 @@ where .map_err(|e| sp_blockchain::Error::from_state(Box::new(e))) } - fn child_storage_keys( - &self, - hash: ::Hash, - child_info: &ChildInfo, - key_prefix: &StorageKey, - ) -> sp_blockchain::Result> { - let keys = self - .state_at(hash)? - .child_keys(child_info, &key_prefix.0) - .into_iter() - .map(StorageKey) - .collect(); - Ok(keys) - } - fn child_storage( &self, hash: ::Hash, diff --git a/client/service/test/src/client/mod.rs b/client/service/test/src/client/mod.rs index 9d021be5b7cad..b2b029f226140 100644 --- a/client/service/test/src/client/mod.rs +++ b/client/service/test/src/client/mod.rs @@ -341,7 +341,20 @@ 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(Default::default()) + .unwrap() + .collect::>(), + client + .state_at(hash0) + .unwrap() + .pairs(Default::default()) + .unwrap() + .collect::>() + ); assert_eq!( client .runtime_api() @@ -394,8 +407,18 @@ 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(Default::default()) + .unwrap() + .collect::>(), + client + .state_at(hashof0) + .unwrap() + .pairs(Default::default()) + .unwrap() + .collect::>() ); assert_eq!(client.body(hashof1).unwrap().unwrap().len(), 1) } @@ -1688,7 +1711,7 @@ fn returns_status_for_pruned_blocks() { } #[test] -fn storage_keys_iter_prefix_and_start_key_works() { +fn storage_keys_prefix_and_start_key_works() { let child_info = ChildInfo::new_default(b"child"); let client = TestClientBuilder::new() .add_extra_child_storage(&child_info, b"first".to_vec(), vec![0u8; 32]) @@ -1703,7 +1726,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(block_hash, Some(&prefix), None) .unwrap() .map(|x| x.0) .collect(); @@ -1717,7 +1740,7 @@ fn storage_keys_iter_prefix_and_start_key_works() { ); let res: Vec<_> = client - .storage_keys_iter( + .storage_keys( block_hash, Some(&prefix), Some(&StorageKey(array_bytes::hex2bytes_unchecked("3a636f6465"))), @@ -1728,7 +1751,7 @@ fn storage_keys_iter_prefix_and_start_key_works() { assert_eq!(res, [array_bytes::hex2bytes_unchecked("3a686561707061676573")]); let res: Vec<_> = client - .storage_keys_iter( + .storage_keys( block_hash, Some(&prefix), Some(&StorageKey(array_bytes::hex2bytes_unchecked("3a686561707061676573"))), @@ -1739,19 +1762,14 @@ 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(block_hash, child_info.clone(), Some(&child_prefix), None) .unwrap() .map(|x| x.0) .collect(); assert_eq!(res, [b"second".to_vec()]); let res: Vec<_> = client - .child_storage_keys_iter( - block_hash, - child_info, - None, - Some(&StorageKey(b"second".to_vec())), - ) + .child_storage_keys(block_hash, child_info, None, Some(&StorageKey(b"second".to_vec()))) .unwrap() .map(|x| x.0) .collect(); @@ -1759,7 +1777,7 @@ fn storage_keys_iter_prefix_and_start_key_works() { } #[test] -fn storage_keys_iter_works() { +fn storage_keys_works() { let client = substrate_test_runtime_client::new(); let block_hash = client.info().best_hash; @@ -1767,7 +1785,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(block_hash, Some(&prefix), None) .unwrap() .take(9) .map(|x| array_bytes::bytes2hex("", &x.0)) @@ -1787,8 +1805,56 @@ fn storage_keys_iter_works() { ] ); + // Starting at an empty key nothing gets skipped. + let res: Vec<_> = client + .storage_keys(block_hash, Some(&prefix), Some(&StorageKey("".into()))) + .unwrap() + .take(9) + .map(|x| array_bytes::bytes2hex("", &x.0)) + .collect(); + assert_eq!( + res, + [ + "00c232cf4e70a5e343317016dc805bf80a6a8cd8ad39958d56f99891b07851e0", + "085b2407916e53a86efeb8b72dbe338c4b341dab135252f96b6ed8022209b6cb", + "0befda6e1ca4ef40219d588a727f1271", + "1a560ecfd2a62c2b8521ef149d0804eb621050e3988ed97dca55f0d7c3e6aa34", + "1d66850d32002979d67dd29dc583af5b2ae2a1f71c1f35ad90fff122be7a3824", + "237498b98d8803334286e9f0483ef513098dd3c1c22ca21c4dc155b4ef6cc204", + "26aa394eea5630e07c48ae0c9558cef75e0621c4869aa60c02be9adcc98a0d1d", + "29b9db10ec5bf7907d8f74b5e60aa8140c4fbdd8127a1ee5600cb98e5ec01729", + "3a636f6465", + ] + ); + + // Starting at an incomplete key nothing gets skipped. + let res: Vec<_> = client + .storage_keys( + block_hash, + Some(&prefix), + Some(&StorageKey(array_bytes::hex2bytes_unchecked("3a636f64"))), + ) + .unwrap() + .take(8) + .map(|x| array_bytes::bytes2hex("", &x.0)) + .collect(); + assert_eq!( + res, + [ + "3a636f6465", + "3a686561707061676573", + "52008686cc27f6e5ed83a216929942f8bcd32a396f09664a5698f81371934b56", + "5348d72ac6cc66e5d8cbecc27b0e0677503b845fe2382d819f83001781788fd5", + "5c2d5fda66373dabf970e4fb13d277ce91c5233473321129d32b5a8085fa8133", + "6644b9b8bc315888ac8e41a7968dc2b4141a5403c58acdf70b7e8f7e07bf5081", + "66484000ed3f75c95fc7b03f39c20ca1e1011e5999278247d3b2f5e3c3273808", + "7d5007603a7f5dd729d51d93cf695d6465789443bb967c0d1fe270e388c96eaa", + ] + ); + + // Starting at a complete key the first key is skipped. let res: Vec<_> = client - .storage_keys_iter( + .storage_keys( block_hash, Some(&prefix), Some(&StorageKey(array_bytes::hex2bytes_unchecked("3a636f6465"))), @@ -1811,7 +1877,7 @@ fn storage_keys_iter_works() { ); let res: Vec<_> = client - .storage_keys_iter( + .storage_keys( block_hash, Some(&prefix), Some(&StorageKey(array_bytes::hex2bytes_unchecked( diff --git a/primitives/state-machine/Cargo.toml b/primitives/state-machine/Cargo.toml index 595dfe286d225..2969a51c4eba0 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.2.2", default-features = false } hash-db = { version = "0.15.2", default-features = false } -log = { version = "0.4.17", optional = true } +log = { version = "0.4.17", default-features = false } parking_lot = { version = "0.12.1", optional = true } rand = { version = "0.8.5", optional = true } smallvec = "1.8.0" @@ -33,7 +33,7 @@ array-bytes = "4.1" pretty_assertions = "1.2.1" rand = "0.8.5" sp-runtime = { version = "7.0.0", path = "../runtime" } -trie-db = "0.24.0" +trie-db = "0.25.1" assert_matches = "1.5" [features] @@ -41,7 +41,7 @@ default = ["std"] std = [ "codec/std", "hash-db/std", - "log", + "log/std", "parking_lot", "rand", "sp-core/std", diff --git a/primitives/state-machine/src/backend.rs b/primitives/state-machine/src/backend.rs index eeb264aedd53d..a8e742d1d2a1d 100644 --- a/primitives/state-machine/src/backend.rs +++ b/primitives/state-machine/src/backend.rs @@ -24,12 +24,135 @@ use crate::{ StorageKey, StorageValue, UsageInfo, }; use codec::Encode; +use core::marker::PhantomData; use hash_db::Hasher; use sp_core::storage::{ChildInfo, StateVersion, TrackedStorageKey}; #[cfg(feature = "std")] use sp_core::traits::RuntimeCode; use sp_std::vec::Vec; +/// A struct containing arguments for iterating over the storage. +#[derive(Default)] +#[non_exhaustive] +pub struct IterArgs<'a> { + /// The prefix of the keys over which to iterate. + pub prefix: Option<&'a [u8]>, + + /// The prefix from which to start the iteration from. + /// + /// This is inclusive and the iteration will include the key which is specified here. + pub start_at: Option<&'a [u8]>, + + /// The info of the child trie over which to iterate over. + pub child_info: Option, + + /// Whether to stop iteration when a missing trie node is reached. + /// + /// When a missing trie node is reached the iterator will: + /// - return an error if this is set to `false` (default) + /// - return `None` if this is set to `true` + pub stop_on_incomplete_database: bool, +} + +/// A trait for a raw storage iterator. +pub trait StorageIterator +where + H: Hasher, +{ + /// The state backend over which the iterator is iterating. + type Backend; + + /// The error type. + type Error; + + /// Fetches the next key from the storage. + fn next_key( + &mut self, + backend: &Self::Backend, + ) -> Option>; + + /// Fetches the next key and value from the storage. + fn next_pair( + &mut self, + backend: &Self::Backend, + ) -> Option>; + + /// Returns whether the end of iteration was reached without an error. + fn was_complete(&self) -> bool; +} + +/// An iterator over storage keys and values. +pub struct PairsIter<'a, H, I> +where + H: Hasher, + I: StorageIterator, +{ + backend: Option<&'a I::Backend>, + raw_iter: I, + _phantom: PhantomData, +} + +impl<'a, H, I> Iterator for PairsIter<'a, H, I> +where + H: Hasher, + I: StorageIterator, +{ + type Item = Result<(Vec, Vec), >::Error>; + fn next(&mut self) -> Option { + self.raw_iter.next_pair(self.backend.as_ref()?) + } +} + +impl<'a, H, I> Default for PairsIter<'a, H, I> +where + H: Hasher, + I: StorageIterator + Default, +{ + fn default() -> Self { + Self { + backend: Default::default(), + raw_iter: Default::default(), + _phantom: Default::default(), + } + } +} + +/// An iterator over storage keys. +pub struct KeysIter<'a, H, I> +where + H: Hasher, + I: StorageIterator, +{ + backend: Option<&'a I::Backend>, + raw_iter: I, + _phantom: PhantomData, +} + +impl<'a, H, I> Iterator for KeysIter<'a, H, I> +where + H: Hasher, + I: StorageIterator, +{ + type Item = Result, >::Error>; + fn next(&mut self) -> Option { + self.raw_iter.next_key(self.backend.as_ref()?) + } +} + +impl<'a, H, I> Default for KeysIter<'a, H, I> +where + H: Hasher, + I: StorageIterator + Default, +{ + fn default() -> Self { + Self { + backend: Default::default(), + raw_iter: Default::default(), + _phantom: Default::default(), + } + } +} + /// A state backend is used to read state data and can have changes committed /// to it. /// @@ -44,6 +167,9 @@ pub trait Backend: sp_std::fmt::Debug { /// Type of trie backend storage. type TrieBackendStorage: TrieBackendStorage; + /// Type of the raw storage iterator. + type RawIter: StorageIterator; + /// Get keyed storage or None if there is nothing associated. fn storage(&self, key: &[u8]) -> Result, Self::Error>; @@ -95,43 +221,103 @@ pub trait Backend: sp_std::fmt::Debug { /// Otherwise an error is produced. /// /// Returns `true` if trie end is reached. + // TODO: Remove this. fn apply_to_key_values_while, Vec) -> bool>( &self, child_info: Option<&ChildInfo>, prefix: Option<&[u8]>, start_at: Option<&[u8]>, - f: F, + mut f: F, allow_missing: bool, - ) -> Result; + ) -> Result { + let args = IterArgs { + child_info: child_info.cloned(), + prefix, + start_at, + stop_on_incomplete_database: allow_missing, + ..IterArgs::default() + }; + let mut iter = self.pairs(args)?; + while let Some(key_value) = iter.next() { + let (key, value) = key_value?; + if !f(key, value) { + return Ok(false) + } + } + Ok(iter.raw_iter.was_complete()) + } /// Retrieve all entries keys of storage and call `f` for each of those keys. /// Aborts as soon as `f` returns false. + // TODO: Remove this. fn apply_to_keys_while bool>( &self, child_info: Option<&ChildInfo>, prefix: Option<&[u8]>, start_at: Option<&[u8]>, - f: F, - ); + mut f: F, + ) -> Result<(), Self::Error> { + let args = + IterArgs { child_info: child_info.cloned(), prefix, start_at, ..IterArgs::default() }; + + for key in self.keys(args)? { + if !f(&key?) { + return Ok(()) + } + } + Ok(()) + } /// Retrieve all entries keys which start with the given prefix and /// call `f` for each of those keys. - fn for_keys_with_prefix(&self, prefix: &[u8], mut f: F) { - self.for_key_values_with_prefix(prefix, |k, _v| f(k)) + // TODO: Remove this. + fn for_keys_with_prefix( + &self, + prefix: &[u8], + mut f: F, + ) -> Result<(), Self::Error> { + let args = IterArgs { prefix: Some(prefix), ..IterArgs::default() }; + self.keys(args)?.try_for_each(|key| { + f(&key?); + Ok(()) + }) } /// Retrieve all entries keys and values of which start with the given prefix and /// call `f` for each of those keys. - fn for_key_values_with_prefix(&self, prefix: &[u8], f: F); + // TODO: Remove this. + fn for_key_values_with_prefix( + &self, + prefix: &[u8], + mut f: F, + ) -> Result<(), Self::Error> { + let args = IterArgs { prefix: Some(prefix), ..IterArgs::default() }; + self.pairs(args)?.try_for_each(|key_value| { + let (key, value) = key_value?; + f(&key, &value); + Ok(()) + }) + } /// Retrieve all child entries keys which start with the given prefix and /// call `f` for each of those keys. + // TODO: Remove this. fn for_child_keys_with_prefix( &self, child_info: &ChildInfo, prefix: &[u8], - f: F, - ); + mut f: F, + ) -> Result<(), Self::Error> { + let args = IterArgs { + child_info: Some(child_info.clone()), + prefix: Some(prefix), + ..IterArgs::default() + }; + self.keys(args)?.try_for_each(|key| { + f(&key?); + Ok(()) + }) + } /// 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. @@ -156,21 +342,25 @@ pub trait Backend: sp_std::fmt::Debug { where H::Out: Ord; - /// Get all key/value pairs into a Vec. - fn pairs(&self) -> Vec<(StorageKey, StorageValue)>; + /// Returns a lifetimeless raw storage iterator. + fn raw_iter(&self, args: IterArgs) -> Result; - /// Get all keys with given prefix - fn keys(&self, prefix: &[u8]) -> Vec { - let mut all = Vec::new(); - self.for_keys_with_prefix(prefix, |k| all.push(k.to_vec())); - all + /// Get an iterator over key/value pairs. + fn pairs<'a>(&'a self, args: IterArgs) -> Result, Self::Error> { + Ok(PairsIter { + backend: Some(self), + raw_iter: self.raw_iter(args)?, + _phantom: Default::default(), + }) } - /// Get all keys of child storage with given prefix - fn child_keys(&self, child_info: &ChildInfo, prefix: &[u8]) -> Vec { - let mut all = Vec::new(); - self.for_child_keys_with_prefix(child_info, prefix, |k| all.push(k.to_vec())); - all + /// Get an iterator over keys. + fn keys<'a>(&'a self, args: IterArgs) -> Result, Self::Error> { + Ok(KeysIter { + backend: Some(self), + raw_iter: self.raw_iter(args)?, + _phantom: Default::default(), + }) } /// Calculate the storage root, with given delta over what is already stored @@ -309,7 +499,7 @@ where #[cfg(feature = "std")] pub struct BackendRuntimeCode<'a, B, H> { backend: &'a B, - _marker: std::marker::PhantomData, + _marker: PhantomData, } #[cfg(feature = "std")] @@ -332,7 +522,7 @@ where { /// Create a new instance. pub fn new(backend: &'a B) -> Self { - Self { backend, _marker: std::marker::PhantomData } + Self { backend, _marker: PhantomData } } /// Return the [`RuntimeCode`] build from the wrapped `backend`. diff --git a/primitives/state-machine/src/ext.rs b/primitives/state-machine/src/ext.rs index 548bab56aa918..695868c96caf9 100644 --- a/primitives/state-machine/src/ext.rs +++ b/primitives/state-machine/src/ext.rs @@ -159,9 +159,10 @@ where use std::collections::HashMap; self.backend - .pairs() - .iter() - .map(|&(ref k, ref v)| (k.to_vec(), Some(v.to_vec()))) + .pairs(Default::default()) + .expect("never fails in tests; qed.") + .map(|key_value| key_value.expect("never fails in tests; qed.")) + .map(|(k, v)| (k, Some(v))) .chain(self.overlay.changes().map(|(k, v)| (k.clone(), v.value().cloned()))) .collect::>() .into_iter() @@ -757,28 +758,34 @@ where 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 - } - 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); + let result = + 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 } - delete_count = delete_count.saturating_add(1); - } - loop_count = loop_count.saturating_add(1); - true - }); + 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 + }); + + if let Err(error) = result { + log::debug!(target: "trie", "Error while iterating the storage: {}", error); + } + (maybe_next_key, delete_count, loop_count) } } diff --git a/primitives/state-machine/src/lib.rs b/primitives/state-machine/src/lib.rs index 94fede96ffa55..538c63837920c 100644 --- a/primitives/state-machine/src/lib.rs +++ b/primitives/state-machine/src/lib.rs @@ -123,7 +123,7 @@ impl sp_std::fmt::Display for DefaultError { } pub use crate::{ - backend::Backend, + backend::{Backend, IterArgs, KeysIter, PairsIter, StorageIterator}, error::{Error, ExecutionError}, ext::Ext, overlayed_changes::{ diff --git a/primitives/state-machine/src/testing.rs b/primitives/state-machine/src/testing.rs index 23e0ed2b5bb38..a9f6399a9a1b5 100644 --- a/primitives/state-machine/src/testing.rs +++ b/primitives/state-machine/src/testing.rs @@ -241,7 +241,12 @@ where H::Out: Ord + codec::Codec, { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "overlay: {:?}\nbackend: {:?}", self.overlay, self.backend.pairs()) + let pairs: Vec<_> = self + .backend + .pairs(Default::default()) + .expect("creating an iterator over all of the pairs doesn't fail in tests") + .collect(); + write!(f, "overlay: {:?}\nbackend: {:?}", self.overlay, pairs) } } diff --git a/primitives/state-machine/src/trie_backend.rs b/primitives/state-machine/src/trie_backend.rs index a42976fb593a6..ec6db9be3346b 100644 --- a/primitives/state-machine/src/trie_backend.rs +++ b/primitives/state-machine/src/trie_backend.rs @@ -20,6 +20,7 @@ #[cfg(feature = "std")] use crate::backend::AsTrieBackend; use crate::{ + backend::IterArgs, trie_backend_essence::{TrieBackendEssence, TrieBackendStorage}, Backend, StorageKey, StorageValue, }; @@ -28,7 +29,6 @@ use codec::Codec; 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")] @@ -51,6 +51,7 @@ pub trait AsLocalTrieCache: sealed::Sealed { impl AsLocalTrieCache for LocalTrieCache { #[cfg(feature = "std")] + #[inline] fn as_local_trie_cache(&self) -> &LocalTrieCache { self } @@ -58,6 +59,7 @@ impl AsLocalTrieCache for LocalTrieCache { #[cfg(feature = "std")] impl AsLocalTrieCache for &LocalTrieCache { + #[inline] fn as_local_trie_cache(&self) -> &LocalTrieCache { self } @@ -236,6 +238,7 @@ where type Error = crate::DefaultError; type Transaction = S::Overlay; type TrieBackendStorage = S; + type RawIter = crate::trie_backend_essence::RawIter; fn storage_hash(&self, key: &[u8]) -> Result, Self::Error> { self.essence.storage_hash(key) @@ -273,51 +276,8 @@ where self.essence.next_child_storage_key(child_info, key) } - fn for_keys_with_prefix(&self, prefix: &[u8], f: F) { - self.essence.for_keys_with_prefix(prefix, f) - } - - fn for_key_values_with_prefix(&self, prefix: &[u8], f: F) { - self.essence.for_key_values_with_prefix(prefix, f) - } - - 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.essence - .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.essence.apply_to_keys_while(child_info, prefix, start_at, f) - } - - fn for_child_keys_with_prefix( - &self, - child_info: &ChildInfo, - prefix: &[u8], - f: F, - ) { - self.essence.for_child_keys_with_prefix(child_info, prefix, f) - } - - fn pairs(&self) -> Vec<(StorageKey, StorageValue)> { - self.essence.pairs() - } - - fn keys(&self, prefix: &[u8]) -> Vec { - self.essence.keys(prefix) + fn raw_iter(&self, args: IterArgs) -> Result { + self.essence.raw_iter(args) } fn storage_root<'a>( @@ -579,7 +539,11 @@ pub mod tests { cache: Option, recorder: Option, ) { - assert!(!test_trie(state_version, cache, recorder).pairs().is_empty()); + assert!(!test_trie(state_version, cache, recorder) + .pairs(Default::default()) + .unwrap() + .next() + .is_none()); } #[test] @@ -589,8 +553,163 @@ pub mod tests { Default::default(), ) .build() - .pairs() - .is_empty()); + .pairs(Default::default()) + .unwrap() + .next() + .is_none()); + } + + parameterized_test!(storage_iteration_works, storage_iteration_works_inner); + fn storage_iteration_works_inner( + state_version: StateVersion, + cache: Option, + recorder: Option, + ) { + let trie = test_trie(state_version, cache, recorder); + + // Fetch everything. + assert_eq!( + trie.keys(Default::default()) + .unwrap() + .map(|result| result.unwrap()) + .take(5) + .collect::>(), + vec![ + b":child_storage:default:sub1".to_vec(), + b":code".to_vec(), + b"key".to_vec(), + b"value1".to_vec(), + b"value2".to_vec(), + ] + ); + + // Fetch starting at a given key (full key). + assert_eq!( + trie.keys(IterArgs { start_at: Some(b"key"), ..IterArgs::default() }) + .unwrap() + .map(|result| result.unwrap()) + .take(3) + .collect::>(), + vec![b"key".to_vec(), b"value1".to_vec(), b"value2".to_vec(),] + ); + + // Fetch starting at a given key (partial key). + assert_eq!( + trie.keys(IterArgs { start_at: Some(b"ke"), ..IterArgs::default() }) + .unwrap() + .map(|result| result.unwrap()) + .take(3) + .collect::>(), + vec![b"key".to_vec(), b"value1".to_vec(), b"value2".to_vec(),] + ); + + // Fetch starting at a given key (empty key). + assert_eq!( + trie.keys(IterArgs { start_at: Some(b""), ..IterArgs::default() }) + .unwrap() + .map(|result| result.unwrap()) + .take(5) + .collect::>(), + vec![ + b":child_storage:default:sub1".to_vec(), + b":code".to_vec(), + b"key".to_vec(), + b"value1".to_vec(), + b"value2".to_vec(), + ] + ); + + // Fetch starting at a given key and with prefix which doesn't match that key. + assert!(trie + .keys(IterArgs { + prefix: Some(b"value"), + start_at: Some(b"key"), + ..IterArgs::default() + }) + .unwrap() + .map(|result| result.unwrap()) + .next() + .is_none()); + + // Fetch starting at a given key and with prefix which does match that key. + assert_eq!( + trie.keys(IterArgs { + prefix: Some(b"value"), + start_at: Some(b"value"), + ..IterArgs::default() + }) + .unwrap() + .map(|result| result.unwrap()) + .collect::>(), + vec![b"value1".to_vec(), b"value2".to_vec(),] + ); + + // Also test out the wrapper methods. + // TODO: Remove this once these methods are gone. + + let mut list = Vec::new(); + assert!(trie + .apply_to_key_values_while( + None, + None, + Some(b"key"), + |key, _| { + list.push(key); + true + }, + false + ) + .unwrap()); + assert_eq!(list[0..3], vec![b"key".to_vec(), b"value1".to_vec(), b"value2".to_vec(),]); + + let mut list = Vec::new(); + trie.apply_to_keys_while(None, None, Some(b"key"), |key| { + list.push(key.to_vec()); + true + }) + .unwrap(); + assert_eq!(list[0..3], vec![b"key".to_vec(), b"value1".to_vec(), b"value2".to_vec(),]); + + let mut list = Vec::new(); + trie.apply_to_keys_while(None, None, Some(b"k"), |key| { + list.push(key.to_vec()); + true + }) + .unwrap(); + assert_eq!(list[0..3], vec![b"key".to_vec(), b"value1".to_vec(), b"value2".to_vec(),]); + + let mut list = Vec::new(); + trie.apply_to_keys_while(None, None, Some(b""), |key| { + list.push(key.to_vec()); + true + }) + .unwrap(); + assert_eq!( + list[0..5], + vec![ + b":child_storage:default:sub1".to_vec(), + b":code".to_vec(), + b"key".to_vec(), + b"value1".to_vec(), + b"value2".to_vec(), + ] + ); + + let mut list = Vec::new(); + trie.apply_to_keys_while(None, Some(b"value"), Some(b"key"), |key| { + list.push(key.to_vec()); + true + }) + .unwrap(); + assert!(list.is_empty()); + + let mut list = Vec::new(); + trie.apply_to_keys_while(None, Some(b"value"), Some(b"value"), |key| { + list.push(key.to_vec()); + true + }) + .unwrap(); + assert_eq!(list, vec![b"value1".to_vec(), b"value2".to_vec(),]); } parameterized_test!(storage_root_is_non_default, storage_root_is_non_default_inner); @@ -638,7 +757,8 @@ pub mod tests { trie.for_keys_with_prefix(b"value", |key| { let for_first_time = seen.insert(key.to_vec()); assert!(for_first_time, "Seen key '{:?}' more than once", key); - }); + }) + .unwrap(); let mut expected = HashSet::new(); expected.insert(b"value1".to_vec()); @@ -664,7 +784,8 @@ pub mod tests { .collect::>(); let trie = test_trie(state_version, cache, recorder); - let keys = trie.keys(&[]); + let keys: Vec<_> = + trie.keys(Default::default()).unwrap().map(|result| result.unwrap()).collect(); assert_eq!(expected, keys); } @@ -724,7 +845,18 @@ pub mod tests { .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()); + assert_eq!( + trie_backend + .pairs(Default::default()) + .unwrap() + .map(|result| result.unwrap()) + .collect::>(), + proving_backend + .pairs(Default::default()) + .unwrap() + .map(|result| result.unwrap()) + .collect::>() + ); let (trie_root, mut trie_mdb) = trie_backend.storage_root(std::iter::empty(), state_version); diff --git a/primitives/state-machine/src/trie_backend_essence.rs b/primitives/state-machine/src/trie_backend_essence.rs index d92caeb84ff62..81a627a657c3e 100644 --- a/primitives/state-machine/src/trie_backend_essence.rs +++ b/primitives/state-machine/src/trie_backend_essence.rs @@ -19,24 +19,23 @@ //! from storage. use crate::{ - backend::Consolidate, debug, trie_backend::AsLocalTrieCache, warn, StorageKey, StorageValue, + backend::{Consolidate, IterArgs, StorageIterator}, + 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}; +use sp_std::{boxed::Box, marker::PhantomData, vec::Vec}; #[cfg(feature = "std")] use sp_trie::recorder::Recorder; use sp_trie::{ child_delta_trie_root, delta_trie_root, empty_child_trie_root, read_child_trie_hash, read_child_trie_value, read_trie_value, trie_types::{TrieDBBuilder, TrieError}, - DBValue, KeySpacedDB, NodeCodec, Trie, TrieCache, TrieDBIterator, TrieDBKeyIterator, - TrieRecorder, + DBValue, KeySpacedDB, NodeCodec, Trie, TrieCache, TrieDBRawIterator, TrieRecorder, }; #[cfg(feature = "std")] use std::{collections::HashMap, sync::Arc}; @@ -76,6 +75,109 @@ impl Cache { } } +enum IterState { + Pending, + FinishedComplete, + FinishedIncomplete, +} + +/// A raw iterator over the storage. +pub struct RawIter +where + H: Hasher, +{ + stop_on_incomplete_database: bool, + root: H::Out, + child_info: Option, + trie_iter: TrieDBRawIterator>, + state: IterState, + _phantom: PhantomData<(S, C)>, +} + +impl RawIter +where + H: Hasher, + S: TrieBackendStorage, + H::Out: Codec + Ord, + C: AsLocalTrieCache + Send + Sync, +{ + #[inline] + fn prepare( + &mut self, + backend: &TrieBackendEssence, + callback: impl FnOnce( + &sp_trie::TrieDB>, + &mut TrieDBRawIterator>, + ) -> Option::Out>>>>, + ) -> Option> { + if !matches!(self.state, IterState::Pending) { + return None + } + + let result = backend.with_trie_db(self.root, self.child_info.as_ref(), |db| { + callback(&db, &mut self.trie_iter) + }); + match result { + Some(Ok(key_value)) => Some(Ok(key_value)), + None => { + self.state = IterState::FinishedComplete; + None + }, + Some(Err(error)) => { + self.state = IterState::FinishedIncomplete; + if matches!(*error, TrieError::IncompleteDatabase(_)) && + self.stop_on_incomplete_database + { + None + } else { + Some(Err(format!("TrieDB iteration error: {}", error))) + } + }, + } + } +} + +impl Default for RawIter +where + H: Hasher, +{ + fn default() -> Self { + Self { + stop_on_incomplete_database: false, + child_info: None, + root: Default::default(), + trie_iter: TrieDBRawIterator::empty(), + state: IterState::FinishedComplete, + _phantom: Default::default(), + } + } +} + +impl StorageIterator for RawIter +where + H: Hasher, + S: TrieBackendStorage, + H::Out: Codec + Ord, + C: AsLocalTrieCache + Send + Sync, +{ + type Backend = crate::TrieBackend; + type Error = crate::DefaultError; + + #[inline] + fn next_key(&mut self, backend: &Self::Backend) -> Option> { + self.prepare(&backend.essence, |trie, trie_iter| trie_iter.next_key(&trie)) + } + + #[inline] + fn next_pair(&mut self, backend: &Self::Backend) -> Option> { + self.prepare(&backend.essence, |trie, trie_iter| trie_iter.next_item(&trie)) + } + + fn was_complete(&self) -> bool { + matches!(self.state, IterState::FinishedComplete) + } +} + /// Patricia trie-based pairs storage essence. pub struct TrieBackendEssence, H: Hasher, C> { storage: S, @@ -168,6 +270,7 @@ impl, H: Hasher, C: AsLocalTrieCache> TrieBackendEss /// /// If the given `storage_root` is `None`, `self.root` will be used. #[cfg(feature = "std")] + #[inline] fn with_recorder_and_cache( &self, storage_root: Option, @@ -193,6 +296,7 @@ impl, H: Hasher, C: AsLocalTrieCache> TrieBackendEss } #[cfg(not(feature = "std"))] + #[inline] fn with_recorder_and_cache( &self, _: Option, @@ -262,6 +366,31 @@ impl, H: Hasher, C: AsLocalTrieCache + Send + Sync> where H::Out: Codec + Ord, { + /// Calls the given closure with a [`TrieDb`] constructed for the given + /// storage root and (optionally) child trie. + #[inline] + fn with_trie_db( + &self, + root: H::Out, + child_info: Option<&ChildInfo>, + callback: impl FnOnce(&sp_trie::TrieDB>) -> R, + ) -> R { + let backend = self as &dyn HashDBRef>; + let db = child_info + .as_ref() + .map(|child_info| KeySpacedDB::new(backend, child_info.keyspace())); + let db = db.as_ref().map(|db| db as &dyn HashDBRef>).unwrap_or(backend); + + self.with_recorder_and_cache(Some(root), |recorder, cache| { + let trie = TrieDBBuilder::::new(db, &root) + .with_optional_recorder(recorder) + .with_optional_cache(cache) + .build(); + + callback(&trie) + }) + } + /// 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> { @@ -316,21 +445,7 @@ where child_info: Option<&ChildInfo>, key: &[u8], ) -> Result> { - 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()); - dyn_eph = &keyspace_eph; - } else { - dyn_eph = self; - } - - 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(); - + self.with_trie_db(*root, child_info, |trie| { 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`. @@ -429,246 +544,42 @@ where }) } - /// Retrieve all entries keys of storage and call `f` for each of those keys. - /// Aborts as soon as `f` returns false. - /// - /// Returns `true` when all keys were iterated. - pub fn apply_to_key_values_while( - &self, - child_info: Option<&ChildInfo>, - prefix: Option<&[u8]>, - start_at: Option<&[u8]>, - f: impl FnMut(Vec, Vec) -> bool, - allow_missing_nodes: bool, - ) -> Result { - let root = if let Some(child_info) = child_info.as_ref() { - match self.child_root(child_info)? { - Some(child_root) => child_root, - None => return Ok(true), - } - } else { - self.root - }; - - self.trie_iter_inner(&root, prefix, f, child_info, start_at, allow_missing_nodes) - } - - /// Retrieve all entries keys of a storage and call `f` for each of those keys. - /// Aborts as soon as `f` returns false. - pub fn apply_to_keys_while bool>( - &self, - child_info: Option<&ChildInfo>, - prefix: Option<&[u8]>, - start_at: Option<&[u8]>, - f: F, - ) { - let root = if let Some(child_info) = child_info.as_ref() { - 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 - }, - } + /// Create a raw iterator over the storage. + pub fn raw_iter(&self, args: IterArgs) -> Result> { + let root = if let Some(child_info) = args.child_info.as_ref() { + let root = match self.child_root(&child_info)? { + Some(root) => root, + None => return Ok(Default::default()), + }; + root } else { self.root }; - self.trie_iter_key_inner(&root, prefix, f, child_info, start_at) - } - - /// Execute given closure for all keys starting with prefix. - pub fn for_child_keys_with_prefix( - &self, - child_info: &ChildInfo, - prefix: &[u8], - mut f: impl FnMut(&[u8]), - ) { - 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 - }, - }; - - self.trie_iter_key_inner( - &root, - Some(prefix), - |k| { - f(k); - true - }, - Some(child_info), - None, - ) - } - - /// Execute given closure for all keys starting with prefix. - pub fn for_keys_with_prefix(&self, prefix: &[u8], mut f: F) { - self.trie_iter_key_inner( - &self.root, - Some(prefix), - |k| { - f(k); - true - }, - None, - None, - ) - } - - fn trie_iter_key_inner bool>( - &self, - root: &H::Out, - 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>> { - 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(()) - }) - }; - - 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); + if self.root == Default::default() { + // A special-case for an empty storage root. + return Ok(Default::default()) } - } - fn trie_iter_inner, Vec) -> bool>( - &self, - root: &H::Out, - prefix: Option<&[u8]>, - mut f: F, - child_info: Option<&ChildInfo>, - start_at: Option<&[u8]>, - allow_missing_nodes: bool, - ) -> Result { - let mut iter = move |db| -> sp_std::result::Result>> { - 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)? + let trie_iter = self + .with_trie_db(root, args.child_info.as_ref(), |db| { + let prefix = args.prefix.as_deref().unwrap_or(&[]); + if let Some(start_at) = args.start_at { + TrieDBRawIterator::new_prefixed_then_seek(db, 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) - }) - }; - - let result = if let Some(child_info) = child_info { - let db = KeySpacedDB::new(self, child_info.keyspace()); - iter(&db) - } else { - iter(self) - }; - match result { - Ok(completed) => Ok(completed), - Err(e) if matches!(*e, TrieError::IncompleteDatabase(_)) && allow_missing_nodes => - Ok(false), - Err(e) => Err(format!("TrieDB iteration error: {}", e)), - } - } - - /// Execute given closure for all key and values starting with prefix. - pub fn for_key_values_with_prefix(&self, prefix: &[u8], mut f: F) { - let _ = self.trie_iter_inner( - &self.root, - Some(prefix), - |k, v| { - f(&k, &v); - true - }, - None, - None, - false, - ); - } - - /// Returns all `(key, value)` pairs in the trie. - pub fn pairs(&self) -> Vec<(StorageKey, StorageValue)> { - let collect_all = || -> sp_std::result::Result<_, Box>> { - 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())); + TrieDBRawIterator::new_prefixed(db, prefix) } - - Ok(v) }) - }; - - match collect_all() { - Ok(v) => v, - Err(e) => { - debug!(target: "trie", "Error extracting trie values: {}", e); - Vec::new() - }, - } - } + .map_err(|e| format!("TrieDB iteration error: {}", e))?; - /// Returns all keys that start with the given `prefix`. - pub fn keys(&self, prefix: &[u8]) -> Vec { - let mut keys = Vec::new(); - self.for_keys_with_prefix(prefix, |k| keys.push(k.to_vec())); - keys + Ok(RawIter { + stop_on_incomplete_database: args.stop_on_incomplete_database, + child_info: args.child_info, + root, + trie_iter, + state: IterState::Pending, + _phantom: Default::default(), + }) } /// Return the storage root after applying the given `delta`. diff --git a/primitives/storage/src/lib.rs b/primitives/storage/src/lib.rs index 77aa260c9dd7d..06995005d9f56 100644 --- a/primitives/storage/src/lib.rs +++ b/primitives/storage/src/lib.rs @@ -273,6 +273,7 @@ impl ChildInfo { /// Returns byte sequence (keyspace) that can be use by underlying db to isolate keys. /// This is a unique id of the child trie. The collision resistance of this value /// depends on the type of child info use. For `ChildInfo::Default` it is and need to be. + #[inline] pub fn keyspace(&self) -> &[u8] { match self { ChildInfo::ParentKeyId(..) => self.storage_key(), diff --git a/primitives/trie/Cargo.toml b/primitives/trie/Cargo.toml index 1e83a5d6dfec5..33a62cdd94084 100644 --- a/primitives/trie/Cargo.toml +++ b/primitives/trie/Cargo.toml @@ -29,7 +29,7 @@ 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 } -trie-db = { version = "0.24.0", default-features = false } +trie-db = { version = "0.25.0", default-features = false } trie-root = { version = "0.17.0", default-features = false } sp-core = { version = "7.0.0", default-features = false, path = "../core" } sp-std = { version = "5.0.0", default-features = false, path = "../std" } @@ -38,7 +38,7 @@ schnellru = { version = "0.2.1", optional = true } [dev-dependencies] array-bytes = "4.1" criterion = "0.4.0" -trie-bench = "0.34.0" +trie-bench = "0.35.0" trie-standardmap = "0.15.2" sp-runtime = { version = "7.0.0", path = "../runtime" } diff --git a/primitives/trie/src/cache/mod.rs b/primitives/trie/src/cache/mod.rs index e55a56971827b..0100e2876e9a9 100644 --- a/primitives/trie/src/cache/mod.rs +++ b/primitives/trie/src/cache/mod.rs @@ -438,8 +438,8 @@ enum ValueCache<'a, H: Hasher> { impl ValueCache<'_, H> { /// Get the value for the given `key`. - fn get<'a>( - &'a mut self, + fn get( + &mut self, key: &[u8], shared_cache: &SharedTrieCache, stats: &HitStats, diff --git a/primitives/trie/src/lib.rs b/primitives/trie/src/lib.rs index 34517d6aa6bcc..175fb32d4e851 100644 --- a/primitives/trie/src/lib.rs +++ b/primitives/trie/src/lib.rs @@ -51,7 +51,7 @@ pub use trie_db::{ nibble_ops, node::{NodePlan, ValuePlan}, CError, DBValue, Query, Recorder, Trie, TrieCache, TrieConfiguration, TrieDBIterator, - TrieDBKeyIterator, TrieLayout, TrieMut, TrieRecorder, + TrieDBKeyIterator, TrieDBRawIterator, TrieLayout, TrieMut, TrieRecorder, }; /// The Substrate format implementation of `TrieStream`. pub use trie_stream::TrieStream; @@ -442,6 +442,7 @@ fn keyspace_as_prefix_alloc(ks: &[u8], prefix: Prefix) -> (Vec, Option) impl<'a, DB: ?Sized, H> KeySpacedDB<'a, DB, H> { /// instantiate new keyspaced db + #[inline] pub fn new(db: &'a DB, ks: &'a [u8]) -> Self { KeySpacedDB(db, ks, PhantomData) } diff --git a/primitives/trie/src/recorder.rs b/primitives/trie/src/recorder.rs index d496408b21170..3bdfda01532cc 100644 --- a/primitives/trie/src/recorder.rs +++ b/primitives/trie/src/recorder.rs @@ -83,6 +83,7 @@ impl Recorder { /// /// - `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). + #[inline] pub fn as_trie_recorder( &self, storage_root: H::Out, @@ -147,7 +148,7 @@ struct TrieRecorder { impl>> trie_db::TrieRecorder for TrieRecorder { - fn record<'b>(&mut self, access: TrieAccess<'b, H::Out>) { + fn record(&mut self, access: TrieAccess) { let mut encoded_size_update = 0; match access { diff --git a/test-utils/runtime/Cargo.toml b/test-utils/runtime/Cargo.toml index 0852003a6808f..33dbfce680d75 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 = "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 } +trie-db = { version = "0.25.1", default-features = false } 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" } diff --git a/utils/frame/benchmarking-cli/src/storage/cmd.rs b/utils/frame/benchmarking-cli/src/storage/cmd.rs index 10ea8caaee9a4..99cadbe8ec34e 100644 --- a/utils/frame/benchmarking-cli/src/storage/cmd.rs +++ b/utils/frame/benchmarking-cli/src/storage/cmd.rs @@ -20,7 +20,6 @@ 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; @@ -192,8 +191,7 @@ impl StorageCmd { BA: ClientBackend, { 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: Vec<_> = client.storage_keys(hash, None, None)?.collect(); let (mut rng, _) = new_rng(None); keys.shuffle(&mut rng); diff --git a/utils/frame/benchmarking-cli/src/storage/read.rs b/utils/frame/benchmarking-cli/src/storage/read.rs index c2aef1c794a90..fe72364269d50 100644 --- a/utils/frame/benchmarking-cli/src/storage/read.rs +++ b/utils/frame/benchmarking-cli/src/storage/read.rs @@ -17,7 +17,6 @@ use sc_cli::Result; use sc_client_api::{Backend as ClientBackend, StorageProvider, UsageProvider}; -use sp_core::storage::StorageKey; use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; use log::info; @@ -42,8 +41,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: Vec<_> = client.storage_keys(best_hash, None, None)?.collect(); let (mut rng, _) = new_rng(None); keys.shuffle(&mut rng); @@ -55,8 +53,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)?; - for ck in child_keys { + for ck in client.child_storage_keys(best_hash, info.clone(), None, None)? { child_nodes.push((ck.clone(), info.clone())); } }, diff --git a/utils/frame/benchmarking-cli/src/storage/write.rs b/utils/frame/benchmarking-cli/src/storage/write.rs index 66d5a30ead912..faca3b536b22e 100644 --- a/utils/frame/benchmarking-cli/src/storage/write.rs +++ b/utils/frame/benchmarking-cli/src/storage/write.rs @@ -61,7 +61,7 @@ impl StorageCmd { info!("Preparing keys from block {}", best_hash); // Load all KV pairs and randomly shuffle them. - let mut kvs = trie.pairs(); + let mut kvs: Vec<_> = trie.pairs(Default::default())?.collect(); let (mut rng, _) = new_rng(None); kvs.shuffle(&mut rng); info!("Writing {} keys", kvs.len()); @@ -70,11 +70,12 @@ impl StorageCmd { // 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 { + for key_value in kvs { + let (k, original_v) = key_value?; 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(best_hash, info.clone(), None, None)?; for ck in child_keys { child_nodes.push((ck.clone(), info.clone())); } diff --git a/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml b/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml index 17a68e2f4cbe8..1dd9da9a56fee 100644 --- a/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml +++ b/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml @@ -21,7 +21,7 @@ log = { version = "0.4.17", default-features = false } sp-core = { path = "../../../../primitives/core" } sp-state-machine = { path = "../../../../primitives/state-machine" } sp-trie = { path = "../../../../primitives/trie" } -trie-db = "0.24.0" +trie-db = "0.25.1" jsonrpsee = { version = "0.16.2", features = ["client-core", "server", "macros"] } From 473b5d06354c5b82e8f6df904c5f50d95c6fcc22 Mon Sep 17 00:00:00 2001 From: Doordashcon Date: Wed, 22 Feb 2023 13:17:11 +0100 Subject: [PATCH 427/715] permissionless `bond_extra` in nomination pools (#12608) * create enum * logic check * add benchmarks * -enum * update * bond extra other * update * update * update * cargo fmt * Permissioned * update * cargo fmt * update * update index * doc update Co-authored-by: Ankan <10196091+Ank4n@users.noreply.github.com> * doc update Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * cargo fmt * bond_extra auto compound * bond_extra_other * Apply suggestions from code review * Fixes from kian * updates docs & test * Update frame/nomination-pools/src/lib.rs * Update frame/nomination-pools/src/lib.rs * Update frame/nomination-pools/src/lib.rs * Update frame/nomination-pools/src/lib.rs * Update frame/nomination-pools/src/lib.rs * Update frame/nomination-pools/src/tests.rs * Update frame/nomination-pools/src/lib.rs * Update frame/nomination-pools/src/tests.rs * Update frame/nomination-pools/src/tests.rs * Update frame/nomination-pools/src/tests.rs * Update frame/nomination-pools/src/tests.rs * Update frame/nomination-pools/src/tests.rs * Update frame/nomination-pools/src/lib.rs * Update frame/nomination-pools/src/tests.rs * fixes + fmt * expand ClaimPermissions + add benchmarks * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_nomination_pools * tidy up claim payout benches * fix * + test: claim_payout_other_works * comments, rename to set_claim_permission * fix comment * remove ClaimPermission on leave pool * fix test * ".git/.scripts/commands/fmt/fmt.sh" * + test for ClaimPermissions::remove() * impl can_bond_extra & can_claim_payout --------- Co-authored-by: Ankan <10196091+Ank4n@users.noreply.github.com> Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: kianenigma Co-authored-by: parity-processbot <> Co-authored-by: Ross Bulat --- .../nomination-pools/benchmarking/src/lib.rs | 46 ++- frame/nomination-pools/src/lib.rs | 214 +++++++++++--- frame/nomination-pools/src/tests.rs | 179 ++++++++++++ frame/nomination-pools/src/weights.rs | 270 +++++++++++------- 4 files changed, 567 insertions(+), 142 deletions(-) diff --git a/frame/nomination-pools/benchmarking/src/lib.rs b/frame/nomination-pools/benchmarking/src/lib.rs index 3b6df669af8a3..094289ee03265 100644 --- a/frame/nomination-pools/benchmarking/src/lib.rs +++ b/frame/nomination-pools/benchmarking/src/lib.rs @@ -30,9 +30,9 @@ use frame_election_provider_support::SortedListProvider; use frame_support::{assert_ok, ensure, traits::Get}; use frame_system::RawOrigin as RuntimeOrigin; use pallet_nomination_pools::{ - BalanceOf, BondExtra, BondedPoolInner, BondedPools, ConfigOp, MaxPoolMembers, - MaxPoolMembersPerPool, MaxPools, Metadata, MinCreateBond, MinJoinBond, Pallet as Pools, - PoolMembers, PoolRoles, PoolState, RewardPools, SubPoolsStorage, + BalanceOf, BondExtra, BondedPoolInner, BondedPools, ClaimPermission, ClaimPermissions, + ConfigOp, MaxPoolMembers, MaxPoolMembersPerPool, MaxPools, Metadata, MinCreateBond, + MinJoinBond, Pallet as Pools, PoolMembers, PoolRoles, PoolState, RewardPools, SubPoolsStorage, }; use sp_runtime::traits::{Bounded, StaticLookup, Zero}; use sp_staking::{EraIndex, StakingInterface}; @@ -252,17 +252,22 @@ frame_benchmarking::benchmarks! { ); } - bond_extra_reward { + bond_extra_other { + let claimer: T::AccountId = account("claimer", USER_SEED + 4, 0); + let origin_weight = Pools::::depositor_min_bond() * 2u32.into(); let scenario = ListScenario::::new(origin_weight, true)?; let extra = (scenario.dest_weight - origin_weight).max(CurrencyOf::::minimum_balance()); + // set claim preferences to `PermissionlessAll` to any account to bond extra on member's behalf. + let _ = Pools::::set_claim_permission(RuntimeOrigin::Signed(scenario.creator1.clone()).into(), ClaimPermission::PermissionlessAll); + // transfer exactly `extra` to the depositor of the src pool (1), let reward_account1 = Pools::::create_reward_account(1); assert!(extra >= CurrencyOf::::minimum_balance()); CurrencyOf::::deposit_creating(&reward_account1, extra); - }: bond_extra(RuntimeOrigin::Signed(scenario.creator1.clone()), BondExtra::Rewards) + }: _(RuntimeOrigin::Signed(claimer), T::Lookup::unlookup(scenario.creator1.clone()), BondExtra::Rewards) verify { assert!( T::Staking::active_stake(&scenario.origin1).unwrap() >= @@ -271,6 +276,8 @@ frame_benchmarking::benchmarks! { } claim_payout { + let claimer: T::AccountId = account("claimer", USER_SEED + 4, 0); + let origin_weight = Pools::::depositor_min_bond() * 2u32.into(); let ed = CurrencyOf::::minimum_balance(); let (depositor, pool_account) = create_pool_account::(0, origin_weight); @@ -279,6 +286,10 @@ frame_benchmarking::benchmarks! { // Send funds to the reward account of the pool CurrencyOf::::make_free_balance_be(&reward_account, ed + origin_weight); + // set claim preferences to `PermissionlessAll` so any account can claim rewards on member's + // behalf. + let _ = Pools::::set_claim_permission(RuntimeOrigin::Signed(depositor.clone()).into(), ClaimPermission::PermissionlessAll); + // Sanity check assert_eq!( CurrencyOf::::free_balance(&depositor), @@ -286,7 +297,7 @@ frame_benchmarking::benchmarks! { ); whitelist_account!(depositor); - }:_(RuntimeOrigin::Signed(depositor.clone())) + }:claim_payout_other(RuntimeOrigin::Signed(claimer), depositor.clone()) verify { assert_eq!( CurrencyOf::::free_balance(&depositor), @@ -298,6 +309,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). @@ -654,6 +666,28 @@ frame_benchmarking::benchmarks! { assert!(T::Staking::nominations(Pools::::create_bonded_account(1)).is_none()); } + set_claim_permission { + // Create a pool + let min_create_bond = Pools::::depositor_min_bond(); + let (depositor, pool_account) = create_pool_account::(0, min_create_bond); + + // Join pool + let min_join_bond = MinJoinBond::::get().max(CurrencyOf::::minimum_balance()); + let joiner = create_funded_user_with_balance::("joiner", 0, min_join_bond * 4u32.into()); + let joiner_lookup = T::Lookup::unlookup(joiner.clone()); + Pools::::join(RuntimeOrigin::Signed(joiner.clone()).into(), min_join_bond, 1) + .unwrap(); + + // Sanity check join worked + assert_eq!( + T::Staking::active_stake(&pool_account).unwrap(), + min_create_bond + min_join_bond + ); + }:_(RuntimeOrigin::Signed(joiner.clone()), ClaimPermission::PermissionlessAll) + verify { + assert_eq!(ClaimPermissions::::get(joiner), ClaimPermission::PermissionlessAll); + } + 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 f61a376443944..b296eb048562a 100644 --- a/frame/nomination-pools/src/lib.rs +++ b/frame/nomination-pools/src/lib.rs @@ -61,6 +61,10 @@ //! //! After joining a pool, a member can claim rewards by calling [`Call::claim_payout`]. //! +//! A pool member can also set a `ClaimPermission` with [`Call::set_claim_permission`], to allow +//! other members to permissionlessly bond or withdraw their rewards by calling +//! [`Call::bond_extra_other`] or [`Call::claim_payout_other`] respectively. +//! //! For design docs see the [reward pool](#reward-pool) section. //! //! ### Leave @@ -411,6 +415,43 @@ enum AccountType { Reward, } +/// The permission a pool member can set for other accounts to claim rewards on their behalf. +#[derive(Encode, Decode, MaxEncodedLen, Clone, Copy, Debug, PartialEq, Eq, TypeInfo)] +pub enum ClaimPermission { + /// Only the pool member themself can claim their rewards. + Permissioned, + /// Anyone can compound rewards on a pool member's behalf. + PermissionlessCompound, + /// Anyone can withdraw rewards on a pool member's behalf. + PermissionlessWithdraw, + /// Anyone can withdraw and compound rewards on a member's behalf. + PermissionlessAll, +} + +impl ClaimPermission { + fn can_bond_extra(&self) -> bool { + match self { + ClaimPermission::PermissionlessAll => true, + ClaimPermission::PermissionlessCompound => true, + _ => false, + } + } + + fn can_claim_payout(&self) -> bool { + match self { + ClaimPermission::PermissionlessAll => true, + ClaimPermission::PermissionlessWithdraw => true, + _ => false, + } + } +} + +impl Default for ClaimPermission { + fn default() -> Self { + Self::Permissioned + } +} + /// A member in a pool. #[derive(Encode, Decode, MaxEncodedLen, TypeInfo, RuntimeDebugNoBound, CloneNoBound)] #[cfg_attr(feature = "std", derive(frame_support::PartialEqNoBound, DefaultNoBound))] @@ -1313,6 +1354,11 @@ pub mod pallet { pub type ReversePoolIdLookup = CountedStorageMap<_, Twox64Concat, T::AccountId, PoolId, OptionQuery>; + /// Map from a pool member account to their opted claim permission. + #[pallet::storage] + pub type ClaimPermissions = + StorageMap<_, Twox64Concat, T::AccountId, ClaimPermission, ValueQuery>; + #[pallet::genesis_config] pub struct GenesisConfig { pub min_join_bond: BalanceOf, @@ -1470,6 +1516,8 @@ pub mod pallet { PoolIdInUse, /// Pool id provided is not correct/usable. InvalidPoolId, + /// Bonding extra is restricted to the exact pending reward amount. + BondExtraRestricted, } #[derive(Encode, Decode, PartialEq, TypeInfo, frame_support::PalletError, RuntimeDebug)] @@ -1560,44 +1608,18 @@ pub mod pallet { /// accumulated rewards, see [`BondExtra`]. /// /// Bonding extra funds implies an automatic payout of all pending rewards as well. + /// See `bond_extra_other` to bond pending rewards of `other` members. // 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()) + .max(T::WeightInfo::bond_extra_other()) )] 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)?; - - // 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)?; - 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 => - (bonded_pool.try_bond_funds(&who, claimed, BondType::Later)?, claimed), - }; - - 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(), - pool_id: member.pool_id, - bonded, - joined: false, - }); - Self::put_member_with_pools(&who, member, bonded_pool, reward_pool); - - Ok(()) + Self::do_bond_extra(who.clone(), who, extra) } /// A bonded member can use this to claim their payout based on the rewards that the pool @@ -1606,16 +1628,13 @@ 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". + /// + /// See `claim_payout_other` to caim rewards on bahalf of some `other` pool member. #[pallet::call_index(2)] #[pallet::weight(T::WeightInfo::claim_payout())] 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(()) + let signer = ensure_signed(origin)?; + Self::do_claim_payout(signer.clone(), signer) } /// Unbond up to `unbonding_points` of the `member_account`'s funds from the pool. It @@ -1715,7 +1734,6 @@ pub mod pallet { // 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(()) } @@ -1840,6 +1858,9 @@ pub mod pallet { }); let post_info_weight = if member.total_points().is_zero() { + // remove any `ClaimPermission` associated with the member. + ClaimPermissions::::remove(&member_account); + // member being reaped. PoolMembers::::remove(&member_account); Self::deposit_event(Event::::MemberRemoved { @@ -2114,6 +2135,67 @@ pub mod pallet { ensure!(bonded_pool.can_nominate(&who), Error::::NotNominator); T::Staking::chill(&bonded_pool.bonded_account()) } + + /// `origin` bonds funds from `extra` for some pool member `member` into their respective + /// pools. + /// + /// `origin` can bond extra funds from free balance or pending rewards when `origin == + /// other`. + /// + /// In the case of `origin != other`, `origin` can only bond extra pending rewards of + /// `other` members assuming set_claim_permission for the given member is + /// `PermissionlessAll` or `PermissionlessCompound`. + #[pallet::call_index(14)] + #[pallet::weight( + T::WeightInfo::bond_extra_transfer() + .max(T::WeightInfo::bond_extra_other()) + )] + pub fn bond_extra_other( + origin: OriginFor, + member: AccountIdLookupOf, + extra: BondExtra>, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + Self::do_bond_extra(who, T::Lookup::lookup(member)?, extra) + } + + /// Allows a pool member to set a claim permission to allow or disallow permissionless + /// bonding and withdrawing. + /// + /// By default, this is `Permissioned`, which implies only the pool member themselves can + /// claim their pending rewards. If a pool member wishes so, they can set this to + /// `PermissionlessAll` to allow any account to claim their rewards and bond extra to the + /// pool. + /// + /// # Arguments + /// + /// * `origin` - Member of a pool. + /// * `actor` - Account to claim reward. // improve this + #[pallet::call_index(15)] + #[pallet::weight(T::DbWeight::get().reads_writes(1, 1))] + pub fn set_claim_permission( + origin: OriginFor, + permission: ClaimPermission, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + + ensure!(PoolMembers::::contains_key(&who), Error::::PoolMemberNotFound); + ClaimPermissions::::mutate(who, |source| { + *source = permission; + }); + Ok(()) + } + + /// `origin` can claim payouts on some pool member `other`'s behalf. + /// + /// Pool member `other` must have a `PermissionlessAll` or `PermissionlessWithdraw` in order + /// for this call to be successful. + #[pallet::call_index(16)] + #[pallet::weight(T::WeightInfo::claim_payout())] + pub fn claim_payout_other(origin: OriginFor, other: T::AccountId) -> DispatchResult { + let signer = ensure_signed(origin)?; + Self::do_claim_payout(signer, other) + } } #[pallet::hooks] @@ -2398,6 +2480,64 @@ impl Pallet { Ok(()) } + fn do_bond_extra( + signer: T::AccountId, + who: T::AccountId, + extra: BondExtra>, + ) -> DispatchResult { + if signer != who { + ensure!( + ClaimPermissions::::get(&who).can_bond_extra(), + Error::::DoesNotHavePermission + ); + ensure!(extra == BondExtra::Rewards, Error::::BondExtraRestricted); + } + + 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)?; + 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 => + (bonded_pool.try_bond_funds(&who, claimed, BondType::Later)?, claimed), + }; + + 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(), + pool_id: member.pool_id, + bonded, + joined: false, + }); + Self::put_member_with_pools(&who, member, bonded_pool, reward_pool); + + Ok(()) + } + + fn do_claim_payout(signer: T::AccountId, who: T::AccountId) -> DispatchResult { + if signer != who { + ensure!( + ClaimPermissions::::get(&who).can_claim_payout(), + Error::::DoesNotHavePermission + ); + } + 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(()) + } + /// 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 59fd17be51434..33eee01948d1f 100644 --- a/frame/nomination-pools/src/tests.rs +++ b/frame/nomination-pools/src/tests.rs @@ -2104,6 +2104,36 @@ mod claim_payout { ); }) } + + #[test] + fn claim_payout_other_works() { + ExtBuilder::default().add_members(vec![(20, 20)]).build_and_execute(|| { + Balances::make_free_balance_be(&default_reward_account(), 8); + // ... of which only 3 are claimable to make sure the reward account does not die. + let claimable_reward = 8 - ExistentialDeposit::get(); + // NOTE: easier to read if we use 3, so let's use the number instead of variable. + assert_eq!(claimable_reward, 3, "test is correct if rewards are divisible by 3"); + + // given + assert_eq!(Balances::free_balance(10), 35); + + // Permissioned by default + assert_noop!( + Pools::claim_payout_other(RuntimeOrigin::signed(80), 10), + Error::::DoesNotHavePermission + ); + + assert_ok!(Pools::set_claim_permission( + RuntimeOrigin::signed(10), + ClaimPermission::PermissionlessWithdraw + )); + assert_ok!(Pools::claim_payout_other(RuntimeOrigin::signed(80), 10)); + + // then + assert_eq!(Balances::free_balance(10), 36); + assert_eq!(Balances::free_balance(&default_reward_account()), 7); + }) + } } mod unbond { @@ -2130,10 +2160,21 @@ mod unbond { Error::::MinimumBondNotMet ); + // Make permissionless + assert_eq!(ClaimPermissions::::get(10), ClaimPermission::Permissioned); + assert_ok!(Pools::set_claim_permission( + RuntimeOrigin::signed(20), + ClaimPermission::PermissionlessAll + )); + // but can go to 0 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); + assert_eq!( + ClaimPermissions::::get(20), + ClaimPermission::PermissionlessAll + ); }) } @@ -4098,6 +4139,49 @@ mod withdraw_unbonded { assert!(!Metadata::::contains_key(1)); }) } + + #[test] + fn withdraw_unbonded_removes_claim_permissions_on_leave() { + ExtBuilder::default().add_members(vec![(20, 20)]).build_and_execute(|| { + // Given + CurrentEra::set(1); + assert_eq!(PoolMembers::::get(20).unwrap().points, 20); + + assert_ok!(Pools::set_claim_permission( + RuntimeOrigin::signed(20), + ClaimPermission::PermissionlessAll + )); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 20)); + assert_eq!(ClaimPermissions::::get(20), ClaimPermission::PermissionlessAll); + + 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::Unbonded { member: 20, pool_id: 1, balance: 20, points: 20, era: 4 }, + ] + ); + + CurrentEra::set(5); + + // When + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(20), 20, 0)); + + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Withdrawn { member: 20, pool_id: 1, balance: 20, points: 20 }, + Event::MemberRemoved { pool_id: 1, member: 20 } + ] + ); + + // Then + assert_eq!(PoolMembers::::get(20), None); + assert_eq!(ClaimPermissions::::contains_key(20), false); + }); + } } mod create { @@ -4280,6 +4364,45 @@ mod create { } } +#[test] +fn set_claimable_actor_works() { + 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(RuntimeOrigin::signed(11), 2, 1)); + + // Then + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Created { depositor: 10, pool_id: 1 }, + Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, + Event::Bonded { member: 11, pool_id: 1, bonded: 2, joined: true }, + ] + ); + + // Make permissionless + assert_eq!(ClaimPermissions::::get(11), ClaimPermission::Permissioned); + assert_noop!( + Pools::set_claim_permission( + RuntimeOrigin::signed(12), + ClaimPermission::PermissionlessAll + ), + Error::::PoolMemberNotFound + ); + assert_ok!(Pools::set_claim_permission( + RuntimeOrigin::signed(11), + ClaimPermission::PermissionlessAll + )); + + // then + assert_eq!(ClaimPermissions::::get(11), ClaimPermission::PermissionlessAll); + }); +} + mod nominate { use super::*; @@ -4592,6 +4715,7 @@ mod bond_extra { // when assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(10), BondExtra::Rewards)); + assert_eq!(Balances::free_balance(&default_reward_account()), 7); // then assert_eq!(Balances::free_balance(10), 35); @@ -4623,6 +4747,61 @@ mod bond_extra { ); }) } + + #[test] + fn bond_extra_other() { + ExtBuilder::default().add_members(vec![(20, 20)]).build_and_execute(|| { + Balances::make_free_balance_be(&default_reward_account(), 8); + // ... of which only 3 are claimable to make sure the reward account does not die. + let claimable_reward = 8 - ExistentialDeposit::get(); + // NOTE: easier to read if we use 3, so let's use the number instead of variable. + assert_eq!(claimable_reward, 3, "test is correct if rewards are divisible by 3"); + + // given + assert_eq!(PoolMembers::::get(10).unwrap().points, 10); + assert_eq!(PoolMembers::::get(20).unwrap().points, 20); + assert_eq!(BondedPools::::get(1).unwrap().points, 30); + assert_eq!(Balances::free_balance(10), 35); + assert_eq!(Balances::free_balance(20), 20); + + // Permissioned by default + assert_noop!( + Pools::bond_extra_other(RuntimeOrigin::signed(80), 20, BondExtra::Rewards), + Error::::DoesNotHavePermission + ); + + assert_ok!(Pools::set_claim_permission( + RuntimeOrigin::signed(10), + ClaimPermission::PermissionlessAll + )); + assert_ok!(Pools::bond_extra_other(RuntimeOrigin::signed(50), 10, BondExtra::Rewards)); + assert_eq!(Balances::free_balance(&default_reward_account()), 7); + + // then + assert_eq!(Balances::free_balance(10), 35); + assert_eq!(PoolMembers::::get(10).unwrap().points, 10 + 1); + assert_eq!(BondedPools::::get(1).unwrap().points, 30 + 1); + + // when + assert_noop!( + Pools::bond_extra_other(RuntimeOrigin::signed(40), 40, BondExtra::Rewards), + Error::::PoolMemberNotFound + ); + + // when + assert_ok!(Pools::bond_extra_other( + RuntimeOrigin::signed(20), + 20, + BondExtra::FreeBalance(10) + )); + + // then + assert_eq!(Balances::free_balance(20), 12); + assert_eq!(Balances::free_balance(&default_reward_account()), 5); + assert_eq!(PoolMembers::::get(20).unwrap().points, 30); + assert_eq!(BondedPools::::get(1).unwrap().points, 41); + }) + } } mod update_roles { diff --git a/frame/nomination-pools/src/weights.rs b/frame/nomination-pools/src/weights.rs index c24689558edf3..1c3d1c6339e8d 100644 --- a/frame/nomination-pools/src/weights.rs +++ b/frame/nomination-pools/src/weights.rs @@ -18,25 +18,26 @@ //! Autogenerated weights for pallet_nomination_pools //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-02-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `runner-ehxwxxsd-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! 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_nomination_pools // --extrinsic=* // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/nomination-pools/src/weights.rs +// --json-file=/builds/parity/mirrors/substrate/.git/.artifacts/bench.json +// --pallet=pallet_nomination_pools +// --chain=dev // --header=./HEADER-APACHE2 +// --output=./frame/nomination-pools/src/weights.rs // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -50,7 +51,7 @@ use sp_std::marker::PhantomData; pub trait WeightInfo { fn join() -> Weight; fn bond_extra_transfer() -> Weight; - fn bond_extra_reward() -> Weight; + fn bond_extra_other() -> Weight; fn claim_payout() -> Weight; fn unbond() -> Weight; fn pool_withdraw_unbonded(s: u32, ) -> Weight; @@ -63,6 +64,7 @@ pub trait WeightInfo { fn set_configs() -> Weight; fn update_roles() -> Weight; fn chill() -> Weight; + fn set_claim_permission() -> Weight; } /// Weights for pallet_nomination_pools using the Substrate node and recommended hardware. @@ -98,8 +100,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `3573` // Estimated: `37988` - // Minimum execution time: 140_155 nanoseconds. - Weight::from_parts(141_098_000, 37988) + // Minimum execution time: 169_857 nanoseconds. + Weight::from_ref_time(173_895_000) + .saturating_add(Weight::from_proof_size(37988)) .saturating_add(T::DbWeight::get().reads(17_u64)) .saturating_add(T::DbWeight::get().writes(12_u64)) } @@ -125,11 +128,14 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `3615` // Estimated: `38583` - // Minimum execution time: 136_048 nanoseconds. - Weight::from_parts(136_767_000, 38583) + // Minimum execution time: 167_372 nanoseconds. + Weight::from_ref_time(168_776_000) + .saturating_add(Weight::from_proof_size(38583)) .saturating_add(T::DbWeight::get().reads(14_u64)) .saturating_add(T::DbWeight::get().writes(12_u64)) } + /// Storage: NominationPools ClaimPermissions (r:1 w:0) + /// Proof: NominationPools ClaimPermissions (max_values: None, max_size: Some(41), added: 2516, mode: MaxEncodedLen) /// Storage: NominationPools PoolMembers (r:1 w:1) /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(237), added: 2712, mode: MaxEncodedLen) /// Storage: NominationPools BondedPools (r:1 w:1) @@ -148,15 +154,18 @@ impl WeightInfo for SubstrateWeight { /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) /// Storage: VoterList ListBags (r:2 w:2) /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - fn bond_extra_reward() -> Weight { + fn bond_extra_other() -> Weight { // Proof Size summary in bytes: - // Measured: `3615` - // Estimated: `38583` - // Minimum execution time: 151_473 nanoseconds. - Weight::from_parts(152_375_000, 38583) - .saturating_add(T::DbWeight::get().reads(14_u64)) + // Measured: `3680` + // Estimated: `41099` + // Minimum execution time: 186_346 nanoseconds. + Weight::from_ref_time(191_308_000) + .saturating_add(Weight::from_proof_size(41099)) + .saturating_add(T::DbWeight::get().reads(15_u64)) .saturating_add(T::DbWeight::get().writes(13_u64)) } + /// Storage: NominationPools ClaimPermissions (r:1 w:0) + /// Proof: NominationPools ClaimPermissions (max_values: None, max_size: Some(41), added: 2516, mode: MaxEncodedLen) /// Storage: NominationPools PoolMembers (r:1 w:1) /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(237), added: 2712, mode: MaxEncodedLen) /// Storage: NominationPools BondedPools (r:1 w:1) @@ -167,11 +176,12 @@ impl WeightInfo for SubstrateWeight { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn claim_payout() -> Weight { // Proof Size summary in bytes: - // Measured: `1189` - // Estimated: `10489` - // Minimum execution time: 51_146 nanoseconds. - Weight::from_parts(51_570_000, 10489) - .saturating_add(T::DbWeight::get().reads(4_u64)) + // Measured: `1254` + // Estimated: `13005` + // Minimum execution time: 61_423 nanoseconds. + Weight::from_ref_time(63_219_000) + .saturating_add(Weight::from_proof_size(13005)) + .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } /// Storage: NominationPools PoolMembers (r:1 w:1) @@ -202,14 +212,17 @@ impl WeightInfo for SubstrateWeight { /// Proof: NominationPools SubPoolsStorage (max_values: None, max_size: Some(24382), added: 26857, mode: MaxEncodedLen) /// Storage: NominationPools CounterForSubPoolsStorage (r:1 w:1) /// Proof: NominationPools CounterForSubPoolsStorage (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: NominationPools ClaimPermissions (r:0 w:1) + /// Proof: NominationPools ClaimPermissions (max_values: None, max_size: Some(41), added: 2516, mode: MaxEncodedLen) fn unbond() -> Weight { // Proof Size summary in bytes: // Measured: `3858` // Estimated: `67379` - // Minimum execution time: 141_400 nanoseconds. - Weight::from_parts(141_822_000, 67379) + // Minimum execution time: 174_532 nanoseconds. + Weight::from_ref_time(180_032_000) + .saturating_add(Weight::from_proof_size(67379)) .saturating_add(T::DbWeight::get().reads(18_u64)) - .saturating_add(T::DbWeight::get().writes(13_u64)) + .saturating_add(T::DbWeight::get().writes(14_u64)) } /// Storage: NominationPools BondedPools (r:1 w:0) /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) @@ -226,10 +239,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1779` // Estimated: `13025` - // Minimum execution time: 49_021 nanoseconds. - Weight::from_parts(49_954_282, 13025) - // Standard Error: 378 - .saturating_add(Weight::from_ref_time(5_165).saturating_mul(s.into())) + // Minimum execution time: 55_327 nanoseconds. + Weight::from_ref_time(58_947_746) + .saturating_add(Weight::from_proof_size(13025)) + // Standard Error: 1_589 + .saturating_add(Weight::from_ref_time(40_696).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -256,10 +270,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `2303` // Estimated: `45696` - // Minimum execution time: 92_473 nanoseconds. - Weight::from_parts(93_901_972, 45696) - // Standard Error: 618 - .saturating_add(Weight::from_ref_time(12_032).saturating_mul(s.into())) + // Minimum execution time: 105_923 nanoseconds. + Weight::from_ref_time(110_572_476) + .saturating_add(Weight::from_proof_size(45696)) + // Standard Error: 2_438 + .saturating_add(Weight::from_ref_time(69_045).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } @@ -308,8 +323,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `2690` // Estimated: `68812` - // Minimum execution time: 150_063 nanoseconds. - Weight::from_parts(152_321_387, 68812) + // Minimum execution time: 169_700 nanoseconds. + Weight::from_ref_time(178_693_541) + .saturating_add(Weight::from_proof_size(68812)) .saturating_add(T::DbWeight::get().reads(20_u64)) .saturating_add(T::DbWeight::get().writes(17_u64)) } @@ -359,8 +375,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1321` // Estimated: `31522` - // Minimum execution time: 131_430 nanoseconds. - Weight::from_parts(132_214_000, 31522) + // Minimum execution time: 145_976 nanoseconds. + Weight::from_ref_time(150_664_000) + .saturating_add(Weight::from_proof_size(31522)) .saturating_add(T::DbWeight::get().reads(21_u64)) .saturating_add(T::DbWeight::get().writes(15_u64)) } @@ -393,10 +410,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1909` // Estimated: `21998 + n * (2520 ±0)` - // Minimum execution time: 61_798 nanoseconds. - Weight::from_parts(61_504_758, 21998) - // Standard Error: 4_046 - .saturating_add(Weight::from_ref_time(1_159_175).saturating_mul(n.into())) + // Minimum execution time: 69_288 nanoseconds. + Weight::from_ref_time(71_075_293) + .saturating_add(Weight::from_proof_size(21998)) + // Standard Error: 10_508 + .saturating_add(Weight::from_ref_time(1_384_674).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(5_u64)) @@ -412,8 +430,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1498` // Estimated: `8752` - // Minimum execution time: 32_433 nanoseconds. - Weight::from_parts(32_894_000, 8752) + // Minimum execution time: 36_410 nanoseconds. + Weight::from_ref_time(37_585_000) + .saturating_add(Weight::from_proof_size(8752)) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -428,10 +447,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `559` // Estimated: `5883` - // Minimum execution time: 13_608 nanoseconds. - Weight::from_parts(13_966_346, 5883) - // Standard Error: 44 - .saturating_add(Weight::from_ref_time(1_511).saturating_mul(n.into())) + // Minimum execution time: 14_322 nanoseconds. + Weight::from_ref_time(15_328_204) + .saturating_add(Weight::from_proof_size(5883)) + // Standard Error: 161 + .saturating_add(Weight::from_ref_time(1_406).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -449,8 +469,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_832 nanoseconds. - Weight::from_ref_time(6_117_000) + // Minimum execution time: 5_968 nanoseconds. + Weight::from_ref_time(6_245_000) + .saturating_add(Weight::from_proof_size(0)) .saturating_add(T::DbWeight::get().writes(5_u64)) } /// Storage: NominationPools BondedPools (r:1 w:1) @@ -459,8 +480,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `559` // Estimated: `2639` - // Minimum execution time: 18_160 nanoseconds. - Weight::from_parts(18_567_000, 2639) + // Minimum execution time: 18_979 nanoseconds. + Weight::from_ref_time(19_795_000) + .saturating_add(Weight::from_proof_size(2639)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -486,11 +508,26 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `2136` // Estimated: `20489` - // Minimum execution time: 58_991 nanoseconds. - Weight::from_parts(59_528_000, 20489) + // Minimum execution time: 68_145 nanoseconds. + Weight::from_ref_time(70_444_000) + .saturating_add(Weight::from_proof_size(20489)) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } + /// Storage: NominationPools PoolMembers (r:1 w:0) + /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(237), added: 2712, mode: MaxEncodedLen) + /// Storage: NominationPools ClaimPermissions (r:1 w:1) + /// Proof: NominationPools ClaimPermissions (max_values: None, max_size: Some(41), added: 2516, mode: MaxEncodedLen) + fn set_claim_permission() -> Weight { + // Proof Size summary in bytes: + // Measured: `542` + // Estimated: `5228` + // Minimum execution time: 15_112 nanoseconds. + Weight::from_ref_time(15_897_000) + .saturating_add(Weight::from_proof_size(5228)) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } } // For backwards compatibility and tests @@ -525,8 +562,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `3573` // Estimated: `37988` - // Minimum execution time: 140_155 nanoseconds. - Weight::from_parts(141_098_000, 37988) + // Minimum execution time: 169_857 nanoseconds. + Weight::from_ref_time(173_895_000) + .saturating_add(Weight::from_proof_size(37988)) .saturating_add(RocksDbWeight::get().reads(17_u64)) .saturating_add(RocksDbWeight::get().writes(12_u64)) } @@ -552,11 +590,14 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `3615` // Estimated: `38583` - // Minimum execution time: 136_048 nanoseconds. - Weight::from_parts(136_767_000, 38583) + // Minimum execution time: 167_372 nanoseconds. + Weight::from_ref_time(168_776_000) + .saturating_add(Weight::from_proof_size(38583)) .saturating_add(RocksDbWeight::get().reads(14_u64)) .saturating_add(RocksDbWeight::get().writes(12_u64)) } + /// Storage: NominationPools ClaimPermissions (r:1 w:0) + /// Proof: NominationPools ClaimPermissions (max_values: None, max_size: Some(41), added: 2516, mode: MaxEncodedLen) /// Storage: NominationPools PoolMembers (r:1 w:1) /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(237), added: 2712, mode: MaxEncodedLen) /// Storage: NominationPools BondedPools (r:1 w:1) @@ -575,15 +616,18 @@ impl WeightInfo for () { /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) /// Storage: VoterList ListBags (r:2 w:2) /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - fn bond_extra_reward() -> Weight { + fn bond_extra_other() -> Weight { // Proof Size summary in bytes: - // Measured: `3615` - // Estimated: `38583` - // Minimum execution time: 151_473 nanoseconds. - Weight::from_parts(152_375_000, 38583) - .saturating_add(RocksDbWeight::get().reads(14_u64)) + // Measured: `3680` + // Estimated: `41099` + // Minimum execution time: 186_346 nanoseconds. + Weight::from_ref_time(191_308_000) + .saturating_add(Weight::from_proof_size(41099)) + .saturating_add(RocksDbWeight::get().reads(15_u64)) .saturating_add(RocksDbWeight::get().writes(13_u64)) } + /// Storage: NominationPools ClaimPermissions (r:1 w:0) + /// Proof: NominationPools ClaimPermissions (max_values: None, max_size: Some(41), added: 2516, mode: MaxEncodedLen) /// Storage: NominationPools PoolMembers (r:1 w:1) /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(237), added: 2712, mode: MaxEncodedLen) /// Storage: NominationPools BondedPools (r:1 w:1) @@ -594,11 +638,12 @@ impl WeightInfo for () { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn claim_payout() -> Weight { // Proof Size summary in bytes: - // Measured: `1189` - // Estimated: `10489` - // Minimum execution time: 51_146 nanoseconds. - Weight::from_parts(51_570_000, 10489) - .saturating_add(RocksDbWeight::get().reads(4_u64)) + // Measured: `1254` + // Estimated: `13005` + // Minimum execution time: 61_423 nanoseconds. + Weight::from_ref_time(63_219_000) + .saturating_add(Weight::from_proof_size(13005)) + .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } /// Storage: NominationPools PoolMembers (r:1 w:1) @@ -629,14 +674,17 @@ impl WeightInfo for () { /// Proof: NominationPools SubPoolsStorage (max_values: None, max_size: Some(24382), added: 26857, mode: MaxEncodedLen) /// Storage: NominationPools CounterForSubPoolsStorage (r:1 w:1) /// Proof: NominationPools CounterForSubPoolsStorage (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: NominationPools ClaimPermissions (r:0 w:1) + /// Proof: NominationPools ClaimPermissions (max_values: None, max_size: Some(41), added: 2516, mode: MaxEncodedLen) fn unbond() -> Weight { // Proof Size summary in bytes: // Measured: `3858` // Estimated: `67379` - // Minimum execution time: 141_400 nanoseconds. - Weight::from_parts(141_822_000, 67379) + // Minimum execution time: 174_532 nanoseconds. + Weight::from_ref_time(180_032_000) + .saturating_add(Weight::from_proof_size(67379)) .saturating_add(RocksDbWeight::get().reads(18_u64)) - .saturating_add(RocksDbWeight::get().writes(13_u64)) + .saturating_add(RocksDbWeight::get().writes(14_u64)) } /// Storage: NominationPools BondedPools (r:1 w:0) /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) @@ -653,10 +701,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1779` // Estimated: `13025` - // Minimum execution time: 49_021 nanoseconds. - Weight::from_parts(49_954_282, 13025) - // Standard Error: 378 - .saturating_add(Weight::from_ref_time(5_165).saturating_mul(s.into())) + // Minimum execution time: 55_327 nanoseconds. + Weight::from_ref_time(58_947_746) + .saturating_add(Weight::from_proof_size(13025)) + // Standard Error: 1_589 + .saturating_add(Weight::from_ref_time(40_696).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -683,10 +732,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `2303` // Estimated: `45696` - // Minimum execution time: 92_473 nanoseconds. - Weight::from_parts(93_901_972, 45696) - // Standard Error: 618 - .saturating_add(Weight::from_ref_time(12_032).saturating_mul(s.into())) + // Minimum execution time: 105_923 nanoseconds. + Weight::from_ref_time(110_572_476) + .saturating_add(Weight::from_proof_size(45696)) + // Standard Error: 2_438 + .saturating_add(Weight::from_ref_time(69_045).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } @@ -735,8 +785,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `2690` // Estimated: `68812` - // Minimum execution time: 150_063 nanoseconds. - Weight::from_parts(152_321_387, 68812) + // Minimum execution time: 169_700 nanoseconds. + Weight::from_ref_time(178_693_541) + .saturating_add(Weight::from_proof_size(68812)) .saturating_add(RocksDbWeight::get().reads(20_u64)) .saturating_add(RocksDbWeight::get().writes(17_u64)) } @@ -786,8 +837,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1321` // Estimated: `31522` - // Minimum execution time: 131_430 nanoseconds. - Weight::from_parts(132_214_000, 31522) + // Minimum execution time: 145_976 nanoseconds. + Weight::from_ref_time(150_664_000) + .saturating_add(Weight::from_proof_size(31522)) .saturating_add(RocksDbWeight::get().reads(21_u64)) .saturating_add(RocksDbWeight::get().writes(15_u64)) } @@ -820,10 +872,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1909` // Estimated: `21998 + n * (2520 ±0)` - // Minimum execution time: 61_798 nanoseconds. - Weight::from_parts(61_504_758, 21998) - // Standard Error: 4_046 - .saturating_add(Weight::from_ref_time(1_159_175).saturating_mul(n.into())) + // Minimum execution time: 69_288 nanoseconds. + Weight::from_ref_time(71_075_293) + .saturating_add(Weight::from_proof_size(21998)) + // Standard Error: 10_508 + .saturating_add(Weight::from_ref_time(1_384_674).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(5_u64)) @@ -839,8 +892,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1498` // Estimated: `8752` - // Minimum execution time: 32_433 nanoseconds. - Weight::from_parts(32_894_000, 8752) + // Minimum execution time: 36_410 nanoseconds. + Weight::from_ref_time(37_585_000) + .saturating_add(Weight::from_proof_size(8752)) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -855,10 +909,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `559` // Estimated: `5883` - // Minimum execution time: 13_608 nanoseconds. - Weight::from_parts(13_966_346, 5883) - // Standard Error: 44 - .saturating_add(Weight::from_ref_time(1_511).saturating_mul(n.into())) + // Minimum execution time: 14_322 nanoseconds. + Weight::from_ref_time(15_328_204) + .saturating_add(Weight::from_proof_size(5883)) + // Standard Error: 161 + .saturating_add(Weight::from_ref_time(1_406).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -876,8 +931,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_832 nanoseconds. - Weight::from_ref_time(6_117_000) + // Minimum execution time: 5_968 nanoseconds. + Weight::from_ref_time(6_245_000) + .saturating_add(Weight::from_proof_size(0)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } /// Storage: NominationPools BondedPools (r:1 w:1) @@ -886,8 +942,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `559` // Estimated: `2639` - // Minimum execution time: 18_160 nanoseconds. - Weight::from_parts(18_567_000, 2639) + // Minimum execution time: 18_979 nanoseconds. + Weight::from_ref_time(19_795_000) + .saturating_add(Weight::from_proof_size(2639)) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -913,9 +970,24 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `2136` // Estimated: `20489` - // Minimum execution time: 58_991 nanoseconds. - Weight::from_parts(59_528_000, 20489) + // Minimum execution time: 68_145 nanoseconds. + Weight::from_ref_time(70_444_000) + .saturating_add(Weight::from_proof_size(20489)) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } + /// Storage: NominationPools PoolMembers (r:1 w:0) + /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(237), added: 2712, mode: MaxEncodedLen) + /// Storage: NominationPools ClaimPermissions (r:1 w:1) + /// Proof: NominationPools ClaimPermissions (max_values: None, max_size: Some(41), added: 2516, mode: MaxEncodedLen) + fn set_claim_permission() -> Weight { + // Proof Size summary in bytes: + // Measured: `542` + // Estimated: `5228` + // Minimum execution time: 15_112 nanoseconds. + Weight::from_ref_time(15_897_000) + .saturating_add(Weight::from_proof_size(5228)) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } } From b0ed48e2295861b79ca7399323d6d64157fa2303 Mon Sep 17 00:00:00 2001 From: Jegor Sidorenko <5252494+jsidorenko@users.noreply.github.com> Date: Wed, 22 Feb 2023 15:50:40 +0200 Subject: [PATCH 428/715] [NFTs] Update attributes with offchain signature (#13390) * Allow to mint with the pre-signed signatures * Another try * WIP: test encoder * Fix the deposits * Refactoring + tests + benchmarks * Add sp-core/runtime-benchmarks * Remove sp-core from dev deps * Enable full_crypto for benchmarks * Typo * Fix * Update frame/nfts/src/mock.rs Co-authored-by: Squirrel * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_nfts * Add docs * Add attributes into the pre-signed object & track the deposit owner for attributes * Update docs * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_nfts * Add the number of attributes provided to weights * Support pre-signed attributes * Update docs * Fix merge artifacts * Update docs * Add more tests * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_nfts * Update frame/nfts/src/types.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Update types.rs --------- Co-authored-by: Squirrel Co-authored-by: command-bot <> Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> --- frame/nfts/src/benchmarking.rs | 50 +++ frame/nfts/src/features/attributes.rs | 53 +++ frame/nfts/src/lib.rs | 35 ++ frame/nfts/src/tests.rs | 308 ++++++++++++++++ frame/nfts/src/types.rs | 22 +- frame/nfts/src/weights.rs | 497 ++++++++++++++++---------- 6 files changed, 782 insertions(+), 183 deletions(-) diff --git a/frame/nfts/src/benchmarking.rs b/frame/nfts/src/benchmarking.rs index efa0a7412ce16..ae628fbefcce6 100644 --- a/frame/nfts/src/benchmarking.rs +++ b/frame/nfts/src/benchmarking.rs @@ -773,5 +773,55 @@ benchmarks_instance_pallet! { assert_last_event::(Event::ItemMetadataSet { collection, item, data: metadata }.into()); } + set_attributes_pre_signed { + let n in 0 .. T::MaxAttributesPerCall::get() as u32; + let (collection, _, _) = create_collection::(); + + let item_owner: T::AccountId = account("item_owner", 0, SEED); + let item_owner_lookup = T::Lookup::unlookup(item_owner.clone()); + + let signer_public = sr25519_generate(0.into(), None); + let signer: T::AccountId = MultiSigner::Sr25519(signer_public).into_account().into(); + + T::Currency::make_free_balance_be(&item_owner, DepositBalanceOf::::max_value()); + + let item = T::Helper::item(0); + assert_ok!(Nfts::::force_mint( + SystemOrigin::Root.into(), + collection, + item, + item_owner_lookup.clone(), + default_item_config(), + )); + + let mut attributes = vec![]; + let attribute_value = vec![0u8; T::ValueLimit::get() as usize]; + for i in 0..n { + let attribute_key = make_filled_vec(i as u16, T::KeyLimit::get() as usize); + attributes.push((attribute_key, attribute_value.clone())); + } + let pre_signed_data = PreSignedAttributes { + collection, + item, + attributes, + namespace: AttributeNamespace::Account(signer.clone()), + deadline: One::one(), + }; + let message = Encode::encode(&pre_signed_data); + let signature = MultiSignature::Sr25519(sr25519_sign(0.into(), &signer_public, &message).unwrap()); + + frame_system::Pallet::::set_block_number(One::one()); + }: _(SystemOrigin::Signed(item_owner.clone()), pre_signed_data, signature.into(), signer.clone()) + verify { + assert_last_event::( + Event::PreSignedAttributesSet { + collection, + item, + namespace: AttributeNamespace::Account(signer.clone()), + } + .into(), + ); + } + impl_benchmark_test_suite!(Nfts, crate::mock::new_test_ext(), crate::mock::Test); } diff --git a/frame/nfts/src/features/attributes.rs b/frame/nfts/src/features/attributes.rs index e310a5e2e432f..fbd1c93247a52 100644 --- a/frame/nfts/src/features/attributes.rs +++ b/frame/nfts/src/features/attributes.rs @@ -165,6 +165,59 @@ impl, I: 'static> Pallet { Ok(()) } + pub(crate) fn do_set_attributes_pre_signed( + origin: T::AccountId, + data: PreSignedAttributesOf, + signer: T::AccountId, + ) -> DispatchResult { + let PreSignedAttributes { collection, item, attributes, namespace, deadline } = data; + + ensure!( + attributes.len() <= T::MaxAttributesPerCall::get() as usize, + Error::::MaxAttributesLimitReached + ); + + let now = frame_system::Pallet::::block_number(); + ensure!(deadline >= now, Error::::DeadlineExpired); + + let item_details = + Item::::get(&collection, &item).ok_or(Error::::UnknownItem)?; + ensure!(item_details.owner == origin, Error::::NoPermission); + + // Only the CollectionOwner and Account() namespaces could be updated in this way. + // For the Account() namespace we check and set the approval if it wasn't set before. + match &namespace { + AttributeNamespace::CollectionOwner => {}, + AttributeNamespace::Account(account) => { + ensure!(account == &signer, Error::::NoPermission); + let approvals = ItemAttributesApprovalsOf::::get(&collection, &item); + if !approvals.contains(account) { + Self::do_approve_item_attributes( + origin.clone(), + collection, + item, + account.clone(), + )?; + } + }, + _ => return Err(Error::::WrongNamespace.into()), + } + + for (key, value) in attributes { + Self::do_set_attribute( + signer.clone(), + collection, + Some(item), + namespace.clone(), + Self::construct_attribute_key(key)?, + Self::construct_attribute_value(value)?, + origin.clone(), + )?; + } + Self::deposit_event(Event::PreSignedAttributesSet { collection, item, namespace }); + Ok(()) + } + pub(crate) fn do_clear_attribute( maybe_check_owner: Option, collection: T::CollectionId, diff --git a/frame/nfts/src/lib.rs b/frame/nfts/src/lib.rs index 41313e6518867..2c3ab290cf569 100644 --- a/frame/nfts/src/lib.rs +++ b/frame/nfts/src/lib.rs @@ -526,6 +526,12 @@ pub mod pallet { price: Option>>, deadline: ::BlockNumber, }, + /// New attributes have been set for an `item` of the `collection`. + PreSignedAttributesSet { + collection: T::CollectionId, + item: T::ItemId, + namespace: AttributeNamespace, + }, } #[pallet::error] @@ -614,6 +620,8 @@ pub mod pallet { IncorrectMetadata, /// Can't set more attributes per one call. MaxAttributesLimitReached, + /// The provided namespace isn't supported in this call. + WrongNamespace, } #[pallet::call] @@ -1824,6 +1832,33 @@ pub mod pallet { ensure!(signature.verify(&*msg, &signer), Error::::WrongSignature); Self::do_mint_pre_signed(origin, mint_data, signer) } + + /// Set attributes for an item by providing the pre-signed approval. + /// + /// Origin must be Signed and must be an owner of the `data.item`. + /// + /// - `data`: The pre-signed approval that consists of the information about the item, + /// attributes to update and until what block number. + /// - `signature`: The signature of the `data` object. + /// - `signer`: The `data` object's signer. Should be an owner of the collection for the + /// `CollectionOwner` namespace. + /// + /// Emits `AttributeSet` for each provided attribute. + /// Emits `ItemAttributesApprovalAdded` if the approval wasn't set before. + /// Emits `PreSignedAttributesSet` on success. + #[pallet::call_index(38)] + #[pallet::weight(T::WeightInfo::set_attributes_pre_signed(data.attributes.len() as u32))] + pub fn set_attributes_pre_signed( + origin: OriginFor, + data: PreSignedAttributesOf, + signature: T::OffchainSignature, + signer: T::AccountId, + ) -> DispatchResult { + let origin = ensure_signed(origin)?; + let msg = Encode::encode(&data); + ensure!(signature.verify(&*msg, &signer), Error::::WrongSignature); + Self::do_set_attributes_pre_signed(origin, data, signer) + } } } diff --git a/frame/nfts/src/tests.rs b/frame/nfts/src/tests.rs index fb8265007a261..8d937b0f7fe68 100644 --- a/frame/nfts/src/tests.rs +++ b/frame/nfts/src/tests.rs @@ -3176,3 +3176,311 @@ fn pre_signed_mints_should_work() { ); }) } + +#[test] +fn pre_signed_attributes_should_work() { + new_test_ext().execute_with(|| { + let user_1_pair = sp_core::sr25519::Pair::from_string("//Alice", None).unwrap(); + let user_1_signer = MultiSigner::Sr25519(user_1_pair.public()); + let user_1 = user_1_signer.clone().into_account(); + let user_2 = account(2); + let user_3_pair = sp_core::sr25519::Pair::from_string("//Bob", None).unwrap(); + let user_3_signer = MultiSigner::Sr25519(user_3_pair.public()); + let user_3 = user_3_signer.clone().into_account(); + let collection_id = 0; + let item_id = 0; + + Balances::make_free_balance_be(&user_1, 100); + Balances::make_free_balance_be(&user_2, 100); + Balances::make_free_balance_be(&user_3, 100); + assert_ok!(Nfts::create( + RuntimeOrigin::signed(user_1.clone()), + user_1.clone(), + collection_config_with_all_settings_enabled(), + )); + assert_ok!(Nfts::mint( + RuntimeOrigin::signed(user_1.clone()), + collection_id, + item_id, + user_2.clone(), + None, + )); + + // validate the CollectionOwner namespace + let pre_signed_data = PreSignedAttributes { + collection: 0, + item: 0, + attributes: vec![(vec![0], vec![1]), (vec![2], vec![3])], + namespace: AttributeNamespace::CollectionOwner, + deadline: 10000000, + }; + let message = Encode::encode(&pre_signed_data); + let signature = MultiSignature::Sr25519(user_1_pair.sign(&message)); + + assert_ok!(Nfts::set_attributes_pre_signed( + RuntimeOrigin::signed(user_2.clone()), + pre_signed_data.clone(), + signature.clone(), + user_1.clone(), + )); + + assert_eq!( + attributes(0), + vec![ + (Some(0), AttributeNamespace::CollectionOwner, bvec![0], bvec![1]), + (Some(0), AttributeNamespace::CollectionOwner, bvec![2], bvec![3]), + ] + ); + let attribute_key: BoundedVec<_, _> = bvec![0]; + let (_, deposit) = Attribute::::get(( + 0, + Some(0), + AttributeNamespace::CollectionOwner, + &attribute_key, + )) + .unwrap(); + assert_eq!(deposit.account, Some(user_2.clone())); + assert_eq!(deposit.amount, 3); + + assert_eq!(Balances::free_balance(&user_1), 100 - 2 - 1); // 2 - collection deposit, 1 - item deposit + assert_eq!(Balances::free_balance(&user_2), 100 - 6); // 6 - attributes + + // validate the deposit gets returned on attribute update from collection's owner + assert_ok!(Nfts::set_attribute( + RuntimeOrigin::signed(user_1.clone()), + collection_id, + Some(item_id), + AttributeNamespace::CollectionOwner, + bvec![0], + bvec![1], + )); + let (_, deposit) = Attribute::::get(( + 0, + Some(0), + AttributeNamespace::CollectionOwner, + &attribute_key, + )) + .unwrap(); + assert_eq!(deposit.account, None); + assert_eq!(deposit.amount, 3); + + // validate we don't partially modify the state + assert_eq!(item_attributes_approvals(collection_id, item_id), vec![]); + let pre_signed_data = PreSignedAttributes { + collection: 0, + item: 0, + attributes: vec![(vec![0], vec![1]), (vec![2; 51], vec![3])], + namespace: AttributeNamespace::Account(user_3.clone()), + deadline: 10000000, + }; + let message = Encode::encode(&pre_signed_data); + let signature = MultiSignature::Sr25519(user_3_pair.sign(&message)); + + assert_noop!( + Nfts::set_attributes_pre_signed( + RuntimeOrigin::signed(user_2.clone()), + pre_signed_data.clone(), + signature.clone(), + user_3.clone(), + ), + Error::::IncorrectData + ); + + // no new approval was set + assert_eq!(item_attributes_approvals(collection_id, item_id), vec![]); + + // no new attributes were added + assert_eq!( + attributes(0), + vec![ + (Some(0), AttributeNamespace::CollectionOwner, bvec![0], bvec![1]), + (Some(0), AttributeNamespace::CollectionOwner, bvec![2], bvec![3]), + ] + ); + + // validate the Account namespace + let pre_signed_data = PreSignedAttributes { + collection: 0, + item: 0, + attributes: vec![(vec![0], vec![1]), (vec![2], vec![3])], + namespace: AttributeNamespace::Account(user_3.clone()), + deadline: 10000000, + }; + let message = Encode::encode(&pre_signed_data); + let signature = MultiSignature::Sr25519(user_3_pair.sign(&message)); + + assert_ok!(Nfts::set_attributes_pre_signed( + RuntimeOrigin::signed(user_2.clone()), + pre_signed_data.clone(), + signature.clone(), + user_3.clone(), + )); + + assert_eq!( + attributes(0), + vec![ + (Some(0), AttributeNamespace::CollectionOwner, bvec![0], bvec![1]), + (Some(0), AttributeNamespace::Account(user_3.clone()), bvec![0], bvec![1]), + (Some(0), AttributeNamespace::CollectionOwner, bvec![2], bvec![3]), + (Some(0), AttributeNamespace::Account(user_3.clone()), bvec![2], bvec![3]), + ] + ); + assert_eq!(item_attributes_approvals(collection_id, item_id), vec![user_3.clone()]); + + let attribute_key: BoundedVec<_, _> = bvec![0]; + let (_, deposit) = Attribute::::get(( + 0, + Some(0), + AttributeNamespace::Account(user_3.clone()), + &attribute_key, + )) + .unwrap(); + assert_eq!(deposit.account, Some(user_2.clone())); + assert_eq!(deposit.amount, 3); + + assert_eq!(Balances::free_balance(&user_2), 100 - 9); + assert_eq!(Balances::free_balance(&user_3), 100); + + // validate the deposit gets returned on attribute update from user_3 + assert_ok!(Nfts::set_attribute( + RuntimeOrigin::signed(user_3.clone()), + collection_id, + Some(item_id), + AttributeNamespace::Account(user_3.clone()), + bvec![0], + bvec![1], + )); + let (_, deposit) = Attribute::::get(( + 0, + Some(0), + AttributeNamespace::Account(user_3.clone()), + &attribute_key, + )) + .unwrap(); + assert_eq!(deposit.account, Some(user_3.clone())); + assert_eq!(deposit.amount, 3); + + assert_eq!(Balances::free_balance(&user_2), 100 - 6); + assert_eq!(Balances::free_balance(&user_3), 100 - 3); + + // can't update with the wrong signature + assert_noop!( + Nfts::set_attributes_pre_signed( + RuntimeOrigin::signed(user_2.clone()), + pre_signed_data.clone(), + signature.clone(), + user_1.clone(), + ), + Error::::WrongSignature + ); + + // can't update if I don't own that item + assert_noop!( + Nfts::set_attributes_pre_signed( + RuntimeOrigin::signed(user_3.clone()), + pre_signed_data.clone(), + signature.clone(), + user_3.clone(), + ), + Error::::NoPermission + ); + + // can't update the CollectionOwner namespace if the signer is not an owner of that + // collection + let pre_signed_data = PreSignedAttributes { + collection: 0, + item: 0, + attributes: vec![(vec![0], vec![1]), (vec![2], vec![3])], + namespace: AttributeNamespace::CollectionOwner, + deadline: 10000000, + }; + let message = Encode::encode(&pre_signed_data); + let signature = MultiSignature::Sr25519(user_3_pair.sign(&message)); + + assert_noop!( + Nfts::set_attributes_pre_signed( + RuntimeOrigin::signed(user_2.clone()), + pre_signed_data.clone(), + signature.clone(), + user_3.clone(), + ), + Error::::NoPermission + ); + + // validate signature's expiration + System::set_block_number(10000001); + assert_noop!( + Nfts::set_attributes_pre_signed( + RuntimeOrigin::signed(user_2.clone()), + pre_signed_data.clone(), + signature.clone(), + user_3.clone(), + ), + Error::::DeadlineExpired + ); + System::set_block_number(1); + + // validate item & collection + let pre_signed_data = PreSignedAttributes { + collection: 1, + item: 1, + attributes: vec![(vec![0], vec![1]), (vec![2], vec![3])], + namespace: AttributeNamespace::CollectionOwner, + deadline: 10000000, + }; + let message = Encode::encode(&pre_signed_data); + let signature = MultiSignature::Sr25519(user_1_pair.sign(&message)); + + assert_noop!( + Nfts::set_attributes_pre_signed( + RuntimeOrigin::signed(user_2.clone()), + pre_signed_data.clone(), + signature.clone(), + user_1.clone(), + ), + Error::::UnknownItem + ); + + // validate max attributes limit + let pre_signed_data = PreSignedAttributes { + collection: 1, + item: 1, + attributes: vec![(vec![0], vec![1]), (vec![2], vec![3]), (vec![2], vec![3])], + namespace: AttributeNamespace::CollectionOwner, + deadline: 10000000, + }; + let message = Encode::encode(&pre_signed_data); + let signature = MultiSignature::Sr25519(user_1_pair.sign(&message)); + + assert_noop!( + Nfts::set_attributes_pre_signed( + RuntimeOrigin::signed(user_2.clone()), + pre_signed_data.clone(), + signature.clone(), + user_1.clone(), + ), + Error::::MaxAttributesLimitReached + ); + + // validate the attribute's value length + let pre_signed_data = PreSignedAttributes { + collection: 0, + item: 0, + attributes: vec![(vec![0], vec![1]), (vec![2], vec![3; 51])], + namespace: AttributeNamespace::CollectionOwner, + deadline: 10000000, + }; + let message = Encode::encode(&pre_signed_data); + let signature = MultiSignature::Sr25519(user_1_pair.sign(&message)); + + assert_noop!( + Nfts::set_attributes_pre_signed( + RuntimeOrigin::signed(user_2.clone()), + pre_signed_data.clone(), + signature.clone(), + user_1.clone(), + ), + Error::::IncorrectData + ); + }) +} diff --git a/frame/nfts/src/types.rs b/frame/nfts/src/types.rs index 860f937aafc05..8c43024cdaceb 100644 --- a/frame/nfts/src/types.rs +++ b/frame/nfts/src/types.rs @@ -67,6 +67,12 @@ pub(super) type PreSignedMintOf = PreSignedMint< ::AccountId, ::BlockNumber, >; +pub(super) type PreSignedAttributesOf = PreSignedAttributes< + >::CollectionId, + >::ItemId, + ::AccountId, + ::BlockNumber, +>; pub trait Incrementable { fn increment(&self) -> Self; @@ -484,7 +490,7 @@ impl_codec_bitflags!(CollectionRoles, u8, CollectionRole); pub struct PreSignedMint { /// A collection of the item to be minted. pub(super) collection: CollectionId, - /// Item's id. + /// Item's ID. pub(super) item: ItemId, /// Additional item's key-value attributes. pub(super) attributes: Vec<(Vec, Vec)>, @@ -495,3 +501,17 @@ pub struct PreSignedMint { /// A deadline for the signature. pub(super) deadline: Deadline, } + +#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct PreSignedAttributes { + /// Collection's ID. + pub(super) collection: CollectionId, + /// Item's ID. + pub(super) item: ItemId, + /// Key-value attributes. + pub(super) attributes: Vec<(Vec, Vec)>, + /// Attributes' namespace. + pub(super) namespace: AttributeNamespace, + /// A deadline for the signature. + pub(super) deadline: Deadline, +} diff --git a/frame/nfts/src/weights.rs b/frame/nfts/src/weights.rs index dc59330f3e674..9eedea958ae83 100644 --- a/frame/nfts/src/weights.rs +++ b/frame/nfts/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_nfts //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-01-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-02-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-b3zmxxc-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-osnnfcqu-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -87,6 +87,7 @@ pub trait WeightInfo { fn cancel_swap() -> Weight; fn claim_swap() -> Weight; fn mint_pre_signed(n: u32, ) -> Weight; + fn set_attributes_pre_signed(n: u32, ) -> Weight; } /// Weights for pallet_nfts using the Substrate node and recommended hardware. @@ -106,8 +107,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `214` // Estimated: `3054` - // Minimum execution time: 33_666 nanoseconds. - Weight::from_parts(34_405_000, 3054) + // Minimum execution time: 33_769 nanoseconds. + Weight::from_ref_time(36_031_000) + .saturating_add(Weight::from_proof_size(3054)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -125,8 +127,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `42` // Estimated: `3054` - // Minimum execution time: 22_028 nanoseconds. - Weight::from_parts(23_030_000, 3054) + // Minimum execution time: 21_767 nanoseconds. + Weight::from_ref_time(22_565_000) + .saturating_add(Weight::from_proof_size(3054)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -156,21 +159,22 @@ impl WeightInfo for SubstrateWeight { fn destroy(_n: u32, m: u32, a: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `172781 + m * (127 ±0) + a * (402 ±0)` - // Estimated: `3347427 + a * (2921 ±0) + m * (2615 ±0)` - // Minimum execution time: 27_944_985 nanoseconds. - Weight::from_parts(19_865_318_850, 3347427) - // Standard Error: 32_345 - .saturating_add(Weight::from_ref_time(8_729_316).saturating_mul(m.into())) - // Standard Error: 32_345 - .saturating_add(Weight::from_ref_time(10_264_491).saturating_mul(a.into())) + // Estimated: `3347427 + m * (2615 ±0) + a * (2921 ±0)` + // Minimum execution time: 26_973_627 nanoseconds. + Weight::from_ref_time(19_692_361_714) + .saturating_add(Weight::from_proof_size(3347427)) + // Standard Error: 17_036 + .saturating_add(Weight::from_ref_time(7_797_219).saturating_mul(m.into())) + // Standard Error: 17_036 + .saturating_add(Weight::from_ref_time(9_504_128).saturating_mul(a.into())) .saturating_add(T::DbWeight::get().reads(1004_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(m.into()))) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(a.into()))) .saturating_add(T::DbWeight::get().writes(3005_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(m.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(a.into()))) - .saturating_add(Weight::from_proof_size(2921).saturating_mul(a.into())) .saturating_add(Weight::from_proof_size(2615).saturating_mul(m.into())) + .saturating_add(Weight::from_proof_size(2921).saturating_mul(a.into())) } /// Storage: Nfts CollectionConfigOf (r:1 w:0) /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) @@ -188,8 +192,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `448` // Estimated: `13506` - // Minimum execution time: 43_925 nanoseconds. - Weight::from_parts(45_885_000, 13506) + // Minimum execution time: 44_837 nanoseconds. + Weight::from_ref_time(46_794_000) + .saturating_add(Weight::from_proof_size(13506)) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -209,8 +214,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `448` // Estimated: `13506` - // Minimum execution time: 42_832 nanoseconds. - Weight::from_parts(44_621_000, 13506) + // Minimum execution time: 43_976 nanoseconds. + Weight::from_ref_time(44_831_000) + .saturating_add(Weight::from_proof_size(13506)) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -236,8 +242,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `647` // Estimated: `13573` - // Minimum execution time: 47_787 nanoseconds. - Weight::from_parts(49_204_000, 13573) + // Minimum execution time: 48_233 nanoseconds. + Weight::from_ref_time(50_113_000) + .saturating_add(Weight::from_proof_size(13573)) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } @@ -263,8 +270,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `882` // Estimated: `16109` - // Minimum execution time: 55_524 nanoseconds. - Weight::from_parts(56_962_000, 16109) + // Minimum execution time: 55_452 nanoseconds. + Weight::from_ref_time(57_642_000) + .saturating_add(Weight::from_proof_size(16109)) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -279,10 +287,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `756 + i * (140 ±0)` // Estimated: `5103 + i * (3336 ±0)` - // Minimum execution time: 15_246 nanoseconds. - Weight::from_parts(15_671_000, 5103) - // Standard Error: 20_348 - .saturating_add(Weight::from_ref_time(14_692_422).saturating_mul(i.into())) + // Minimum execution time: 15_598 nanoseconds. + Weight::from_ref_time(15_926_000) + .saturating_add(Weight::from_proof_size(5103)) + // Standard Error: 13_692 + .saturating_add(Weight::from_ref_time(14_040_741).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(i.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) @@ -296,8 +305,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `401` // Estimated: `5067` - // Minimum execution time: 19_270 nanoseconds. - Weight::from_parts(19_775_000, 5067) + // Minimum execution time: 19_686 nanoseconds. + Weight::from_ref_time(20_404_000) + .saturating_add(Weight::from_proof_size(5067)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -309,8 +319,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `401` // Estimated: `5067` - // Minimum execution time: 19_364 nanoseconds. - Weight::from_parts(20_274_000, 5067) + // Minimum execution time: 19_172 nanoseconds. + Weight::from_ref_time(20_151_000) + .saturating_add(Weight::from_proof_size(5067)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -322,8 +333,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `289` // Estimated: `5092` - // Minimum execution time: 17_036 nanoseconds. - Weight::from_parts(17_750_000, 5092) + // Minimum execution time: 17_063 nanoseconds. + Weight::from_ref_time(17_482_000) + .saturating_add(Weight::from_proof_size(5092)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -337,8 +349,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `381` // Estimated: `5082` - // Minimum execution time: 22_104 nanoseconds. - Weight::from_parts(23_022_000, 5082) + // Minimum execution time: 21_974 nanoseconds. + Weight::from_ref_time(22_770_000) + .saturating_add(Weight::from_proof_size(5082)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -350,8 +363,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `362` // Estimated: `2555` - // Minimum execution time: 24_516 nanoseconds. - Weight::from_parts(25_300_000, 2555) + // Minimum execution time: 24_341 nanoseconds. + Weight::from_ref_time(25_059_000) + .saturating_add(Weight::from_proof_size(2555)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -363,8 +377,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `304` // Estimated: `2555` - // Minimum execution time: 16_974 nanoseconds. - Weight::from_parts(17_654_000, 2555) + // Minimum execution time: 16_897 nanoseconds. + Weight::from_ref_time(17_560_000) + .saturating_add(Weight::from_proof_size(2555)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -376,8 +391,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `242` // Estimated: `2555` - // Minimum execution time: 13_190 nanoseconds. - Weight::from_parts(13_826_000, 2555) + // Minimum execution time: 13_239 nanoseconds. + Weight::from_ref_time(13_963_000) + .saturating_add(Weight::from_proof_size(2555)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -389,8 +405,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `445` // Estimated: `5078` - // Minimum execution time: 17_336 nanoseconds. - Weight::from_parts(18_242_000, 5078) + // Minimum execution time: 17_187 nanoseconds. + Weight::from_ref_time(17_942_000) + .saturating_add(Weight::from_proof_size(5078)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -406,8 +423,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `474` // Estimated: `10547` - // Minimum execution time: 40_791 nanoseconds. - Weight::from_parts(42_489_000, 10547) + // Minimum execution time: 40_925 nanoseconds. + Weight::from_ref_time(42_733_000) + .saturating_add(Weight::from_proof_size(10547)) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -419,8 +437,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `337` // Estimated: `5476` - // Minimum execution time: 24_620 nanoseconds. - Weight::from_parts(25_370_000, 5476) + // Minimum execution time: 24_486 nanoseconds. + Weight::from_ref_time(25_409_000) + .saturating_add(Weight::from_proof_size(5476)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -434,8 +453,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `916` // Estimated: `7999` - // Minimum execution time: 36_411 nanoseconds. - Weight::from_parts(37_439_000, 7999) + // Minimum execution time: 36_643 nanoseconds. + Weight::from_ref_time(37_805_000) + .saturating_add(Weight::from_proof_size(7999)) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -447,8 +467,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `379` // Estimated: `6492` - // Minimum execution time: 16_696 nanoseconds. - Weight::from_parts(17_411_000, 6492) + // Minimum execution time: 16_798 nanoseconds. + Weight::from_ref_time(17_326_000) + .saturating_add(Weight::from_proof_size(6492)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -465,10 +486,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `899 + n * (396 ±0)` // Estimated: `12016 + n * (2921 ±0)` - // Minimum execution time: 25_928 nanoseconds. - Weight::from_parts(26_440_000, 12016) - // Standard Error: 9_158 - .saturating_add(Weight::from_ref_time(9_271_441).saturating_mul(n.into())) + // Minimum execution time: 25_524 nanoseconds. + Weight::from_ref_time(26_107_000) + .saturating_add(Weight::from_proof_size(12016)) + // Standard Error: 5_460 + .saturating_add(Weight::from_ref_time(9_030_830).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) @@ -487,8 +509,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `474` // Estimated: `10241` - // Minimum execution time: 34_150 nanoseconds. - Weight::from_parts(35_398_000, 10241) + // Minimum execution time: 34_400 nanoseconds. + Weight::from_ref_time(35_469_000) + .saturating_add(Weight::from_proof_size(10241)) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -502,8 +525,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `609` // Estimated: `7693` - // Minimum execution time: 31_871 nanoseconds. - Weight::from_parts(33_057_000, 7693) + // Minimum execution time: 31_560 nanoseconds. + Weight::from_ref_time(33_081_000) + .saturating_add(Weight::from_proof_size(7693)) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -517,8 +541,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `333` // Estimated: `7665` - // Minimum execution time: 28_843 nanoseconds. - Weight::from_parts(30_057_000, 7665) + // Minimum execution time: 28_821 nanoseconds. + Weight::from_ref_time(30_010_000) + .saturating_add(Weight::from_proof_size(7665)) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -532,8 +557,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `476` // Estimated: `7665` - // Minimum execution time: 27_777 nanoseconds. - Weight::from_parts(28_471_000, 7665) + // Minimum execution time: 27_608 nanoseconds. + Weight::from_ref_time(28_766_000) + .saturating_add(Weight::from_proof_size(7665)) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -547,8 +573,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `466` // Estimated: `8428` - // Minimum execution time: 23_726 nanoseconds. - Weight::from_parts(24_455_000, 8428) + // Minimum execution time: 23_987 nanoseconds. + Weight::from_ref_time(24_819_000) + .saturating_add(Weight::from_proof_size(8428)) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -560,8 +587,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `474` // Estimated: `5880` - // Minimum execution time: 21_051 nanoseconds. - Weight::from_parts(21_722_000, 5880) + // Minimum execution time: 21_254 nanoseconds. + Weight::from_ref_time(21_826_000) + .saturating_add(Weight::from_proof_size(5880)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -573,8 +601,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `474` // Estimated: `5880` - // Minimum execution time: 20_095 nanoseconds. - Weight::from_parts(20_770_000, 5880) + // Minimum execution time: 20_272 nanoseconds. + Weight::from_ref_time(20_922_000) + .saturating_add(Weight::from_proof_size(5880)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -584,8 +613,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `42` // Estimated: `2527` - // Minimum execution time: 14_078 nanoseconds. - Weight::from_parts(14_582_000, 2527) + // Minimum execution time: 14_287 nanoseconds. + Weight::from_ref_time(14_960_000) + .saturating_add(Weight::from_proof_size(2527)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -597,8 +627,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `333` // Estimated: `5103` - // Minimum execution time: 17_677 nanoseconds. - Weight::from_parts(18_381_000, 5103) + // Minimum execution time: 17_948 nanoseconds. + Weight::from_ref_time(18_780_000) + .saturating_add(Weight::from_proof_size(5103)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -610,8 +641,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `333` // Estimated: `5103` - // Minimum execution time: 16_295 nanoseconds. - Weight::from_parts(17_036_000, 5103) + // Minimum execution time: 16_616 nanoseconds. + Weight::from_ref_time(17_155_000) + .saturating_add(Weight::from_proof_size(5103)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -627,8 +659,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `516` // Estimated: `8407` - // Minimum execution time: 22_847 nanoseconds. - Weight::from_parts(23_536_000, 8407) + // Minimum execution time: 22_777 nanoseconds. + Weight::from_ref_time(23_955_000) + .saturating_add(Weight::from_proof_size(8407)) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -652,8 +685,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `934` // Estimated: `16129` - // Minimum execution time: 60_517 nanoseconds. - Weight::from_parts(62_528_000, 16129) + // Minimum execution time: 61_131 nanoseconds. + Weight::from_ref_time(62_791_000) + .saturating_add(Weight::from_proof_size(16129)) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -662,10 +696,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_866 nanoseconds. - Weight::from_ref_time(3_949_301) - // Standard Error: 11_044 - .saturating_add(Weight::from_ref_time(3_424_466).saturating_mul(n.into())) + // Minimum execution time: 1_952 nanoseconds. + Weight::from_ref_time(3_975_700) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 11_254 + .saturating_add(Weight::from_ref_time(3_501_698).saturating_mul(n.into())) } /// Storage: Nfts Item (r:2 w:0) /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) @@ -675,8 +710,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `524` // Estimated: `6672` - // Minimum execution time: 21_174 nanoseconds. - Weight::from_parts(21_619_000, 6672) + // Minimum execution time: 20_327 nanoseconds. + Weight::from_ref_time(21_714_000) + .saturating_add(Weight::from_proof_size(6672)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -688,8 +724,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `511` // Estimated: `5882` - // Minimum execution time: 20_606 nanoseconds. - Weight::from_parts(21_150_000, 5882) + // Minimum execution time: 20_668 nanoseconds. + Weight::from_ref_time(21_416_000) + .saturating_add(Weight::from_proof_size(5882)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -713,8 +750,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1097` // Estimated: `21970` - // Minimum execution time: 88_414 nanoseconds. - Weight::from_parts(91_830_000, 21970) + // Minimum execution time: 88_006 nanoseconds. + Weight::from_ref_time(90_390_000) + .saturating_add(Weight::from_proof_size(21970)) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(11_u64)) } @@ -739,16 +777,45 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `596` // Estimated: `16180 + n * (2921 ±0)` - // Minimum execution time: 124_354 nanoseconds. - Weight::from_parts(133_779_491, 16180) - // Standard Error: 38_452 - .saturating_add(Weight::from_ref_time(25_110_697).saturating_mul(n.into())) + // Minimum execution time: 124_967 nanoseconds. + Weight::from_ref_time(131_602_642) + .saturating_add(Weight::from_proof_size(16180)) + // Standard Error: 36_480 + .saturating_add(Weight::from_ref_time(25_811_394).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(6_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) .saturating_add(Weight::from_proof_size(2921).saturating_mul(n.into())) } + /// Storage: Nfts Item (r:1 w:0) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts ItemAttributesApprovalsOf (r:1 w:1) + /// Proof: Nfts ItemAttributesApprovalsOf (max_values: None, max_size: Some(681), added: 3156, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:0) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts Attribute (r:10 w:10) + /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// The range of component `n` is `[0, 10]`. + fn set_attributes_pre_signed(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `716` + // Estimated: `14198 + n * (2921 ±0)` + // Minimum execution time: 84_153 nanoseconds. + Weight::from_ref_time(96_401_623) + .saturating_add(Weight::from_proof_size(14198)) + // Standard Error: 70_244 + .saturating_add(Weight::from_ref_time(26_866_222).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_proof_size(2921).saturating_mul(n.into())) + } } // For backwards compatibility and tests @@ -767,8 +834,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `214` // Estimated: `3054` - // Minimum execution time: 33_666 nanoseconds. - Weight::from_parts(34_405_000, 3054) + // Minimum execution time: 33_769 nanoseconds. + Weight::from_ref_time(36_031_000) + .saturating_add(Weight::from_proof_size(3054)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -786,8 +854,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `42` // Estimated: `3054` - // Minimum execution time: 22_028 nanoseconds. - Weight::from_parts(23_030_000, 3054) + // Minimum execution time: 21_767 nanoseconds. + Weight::from_ref_time(22_565_000) + .saturating_add(Weight::from_proof_size(3054)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -817,21 +886,22 @@ impl WeightInfo for () { fn destroy(_n: u32, m: u32, a: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `172781 + m * (127 ±0) + a * (402 ±0)` - // Estimated: `3347427 + a * (2921 ±0) + m * (2615 ±0)` - // Minimum execution time: 27_944_985 nanoseconds. - Weight::from_parts(19_865_318_850, 3347427) - // Standard Error: 32_345 - .saturating_add(Weight::from_ref_time(8_729_316).saturating_mul(m.into())) - // Standard Error: 32_345 - .saturating_add(Weight::from_ref_time(10_264_491).saturating_mul(a.into())) + // Estimated: `3347427 + m * (2615 ±0) + a * (2921 ±0)` + // Minimum execution time: 26_973_627 nanoseconds. + Weight::from_ref_time(19_692_361_714) + .saturating_add(Weight::from_proof_size(3347427)) + // Standard Error: 17_036 + .saturating_add(Weight::from_ref_time(7_797_219).saturating_mul(m.into())) + // Standard Error: 17_036 + .saturating_add(Weight::from_ref_time(9_504_128).saturating_mul(a.into())) .saturating_add(RocksDbWeight::get().reads(1004_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(m.into()))) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(a.into()))) .saturating_add(RocksDbWeight::get().writes(3005_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(m.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(a.into()))) - .saturating_add(Weight::from_proof_size(2921).saturating_mul(a.into())) .saturating_add(Weight::from_proof_size(2615).saturating_mul(m.into())) + .saturating_add(Weight::from_proof_size(2921).saturating_mul(a.into())) } /// Storage: Nfts CollectionConfigOf (r:1 w:0) /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) @@ -849,8 +919,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `448` // Estimated: `13506` - // Minimum execution time: 43_925 nanoseconds. - Weight::from_parts(45_885_000, 13506) + // Minimum execution time: 44_837 nanoseconds. + Weight::from_ref_time(46_794_000) + .saturating_add(Weight::from_proof_size(13506)) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -870,8 +941,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `448` // Estimated: `13506` - // Minimum execution time: 42_832 nanoseconds. - Weight::from_parts(44_621_000, 13506) + // Minimum execution time: 43_976 nanoseconds. + Weight::from_ref_time(44_831_000) + .saturating_add(Weight::from_proof_size(13506)) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -897,8 +969,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `647` // Estimated: `13573` - // Minimum execution time: 47_787 nanoseconds. - Weight::from_parts(49_204_000, 13573) + // Minimum execution time: 48_233 nanoseconds. + Weight::from_ref_time(50_113_000) + .saturating_add(Weight::from_proof_size(13573)) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } @@ -924,8 +997,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `882` // Estimated: `16109` - // Minimum execution time: 55_524 nanoseconds. - Weight::from_parts(56_962_000, 16109) + // Minimum execution time: 55_452 nanoseconds. + Weight::from_ref_time(57_642_000) + .saturating_add(Weight::from_proof_size(16109)) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -940,10 +1014,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `756 + i * (140 ±0)` // Estimated: `5103 + i * (3336 ±0)` - // Minimum execution time: 15_246 nanoseconds. - Weight::from_parts(15_671_000, 5103) - // Standard Error: 20_348 - .saturating_add(Weight::from_ref_time(14_692_422).saturating_mul(i.into())) + // Minimum execution time: 15_598 nanoseconds. + Weight::from_ref_time(15_926_000) + .saturating_add(Weight::from_proof_size(5103)) + // Standard Error: 13_692 + .saturating_add(Weight::from_ref_time(14_040_741).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(i.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(i.into()))) @@ -957,8 +1032,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `401` // Estimated: `5067` - // Minimum execution time: 19_270 nanoseconds. - Weight::from_parts(19_775_000, 5067) + // Minimum execution time: 19_686 nanoseconds. + Weight::from_ref_time(20_404_000) + .saturating_add(Weight::from_proof_size(5067)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -970,8 +1046,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `401` // Estimated: `5067` - // Minimum execution time: 19_364 nanoseconds. - Weight::from_parts(20_274_000, 5067) + // Minimum execution time: 19_172 nanoseconds. + Weight::from_ref_time(20_151_000) + .saturating_add(Weight::from_proof_size(5067)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -983,8 +1060,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `289` // Estimated: `5092` - // Minimum execution time: 17_036 nanoseconds. - Weight::from_parts(17_750_000, 5092) + // Minimum execution time: 17_063 nanoseconds. + Weight::from_ref_time(17_482_000) + .saturating_add(Weight::from_proof_size(5092)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -998,8 +1076,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `381` // Estimated: `5082` - // Minimum execution time: 22_104 nanoseconds. - Weight::from_parts(23_022_000, 5082) + // Minimum execution time: 21_974 nanoseconds. + Weight::from_ref_time(22_770_000) + .saturating_add(Weight::from_proof_size(5082)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -1011,8 +1090,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `362` // Estimated: `2555` - // Minimum execution time: 24_516 nanoseconds. - Weight::from_parts(25_300_000, 2555) + // Minimum execution time: 24_341 nanoseconds. + Weight::from_ref_time(25_059_000) + .saturating_add(Weight::from_proof_size(2555)) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -1024,8 +1104,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `304` // Estimated: `2555` - // Minimum execution time: 16_974 nanoseconds. - Weight::from_parts(17_654_000, 2555) + // Minimum execution time: 16_897 nanoseconds. + Weight::from_ref_time(17_560_000) + .saturating_add(Weight::from_proof_size(2555)) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -1037,8 +1118,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `242` // Estimated: `2555` - // Minimum execution time: 13_190 nanoseconds. - Weight::from_parts(13_826_000, 2555) + // Minimum execution time: 13_239 nanoseconds. + Weight::from_ref_time(13_963_000) + .saturating_add(Weight::from_proof_size(2555)) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1050,8 +1132,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `445` // Estimated: `5078` - // Minimum execution time: 17_336 nanoseconds. - Weight::from_parts(18_242_000, 5078) + // Minimum execution time: 17_187 nanoseconds. + Weight::from_ref_time(17_942_000) + .saturating_add(Weight::from_proof_size(5078)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1067,8 +1150,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `474` // Estimated: `10547` - // Minimum execution time: 40_791 nanoseconds. - Weight::from_parts(42_489_000, 10547) + // Minimum execution time: 40_925 nanoseconds. + Weight::from_ref_time(42_733_000) + .saturating_add(Weight::from_proof_size(10547)) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1080,8 +1164,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `337` // Estimated: `5476` - // Minimum execution time: 24_620 nanoseconds. - Weight::from_parts(25_370_000, 5476) + // Minimum execution time: 24_486 nanoseconds. + Weight::from_ref_time(25_409_000) + .saturating_add(Weight::from_proof_size(5476)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1095,8 +1180,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `916` // Estimated: `7999` - // Minimum execution time: 36_411 nanoseconds. - Weight::from_parts(37_439_000, 7999) + // Minimum execution time: 36_643 nanoseconds. + Weight::from_ref_time(37_805_000) + .saturating_add(Weight::from_proof_size(7999)) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1108,8 +1194,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `379` // Estimated: `6492` - // Minimum execution time: 16_696 nanoseconds. - Weight::from_parts(17_411_000, 6492) + // Minimum execution time: 16_798 nanoseconds. + Weight::from_ref_time(17_326_000) + .saturating_add(Weight::from_proof_size(6492)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1126,10 +1213,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `899 + n * (396 ±0)` // Estimated: `12016 + n * (2921 ±0)` - // Minimum execution time: 25_928 nanoseconds. - Weight::from_parts(26_440_000, 12016) - // Standard Error: 9_158 - .saturating_add(Weight::from_ref_time(9_271_441).saturating_mul(n.into())) + // Minimum execution time: 25_524 nanoseconds. + Weight::from_ref_time(26_107_000) + .saturating_add(Weight::from_proof_size(12016)) + // Standard Error: 5_460 + .saturating_add(Weight::from_ref_time(9_030_830).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(2_u64)) @@ -1148,8 +1236,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `474` // Estimated: `10241` - // Minimum execution time: 34_150 nanoseconds. - Weight::from_parts(35_398_000, 10241) + // Minimum execution time: 34_400 nanoseconds. + Weight::from_ref_time(35_469_000) + .saturating_add(Weight::from_proof_size(10241)) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1163,8 +1252,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `609` // Estimated: `7693` - // Minimum execution time: 31_871 nanoseconds. - Weight::from_parts(33_057_000, 7693) + // Minimum execution time: 31_560 nanoseconds. + Weight::from_ref_time(33_081_000) + .saturating_add(Weight::from_proof_size(7693)) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1178,8 +1268,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `333` // Estimated: `7665` - // Minimum execution time: 28_843 nanoseconds. - Weight::from_parts(30_057_000, 7665) + // Minimum execution time: 28_821 nanoseconds. + Weight::from_ref_time(30_010_000) + .saturating_add(Weight::from_proof_size(7665)) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1193,8 +1284,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `476` // Estimated: `7665` - // Minimum execution time: 27_777 nanoseconds. - Weight::from_parts(28_471_000, 7665) + // Minimum execution time: 27_608 nanoseconds. + Weight::from_ref_time(28_766_000) + .saturating_add(Weight::from_proof_size(7665)) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1208,8 +1300,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `466` // Estimated: `8428` - // Minimum execution time: 23_726 nanoseconds. - Weight::from_parts(24_455_000, 8428) + // Minimum execution time: 23_987 nanoseconds. + Weight::from_ref_time(24_819_000) + .saturating_add(Weight::from_proof_size(8428)) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1221,8 +1314,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `474` // Estimated: `5880` - // Minimum execution time: 21_051 nanoseconds. - Weight::from_parts(21_722_000, 5880) + // Minimum execution time: 21_254 nanoseconds. + Weight::from_ref_time(21_826_000) + .saturating_add(Weight::from_proof_size(5880)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1234,8 +1328,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `474` // Estimated: `5880` - // Minimum execution time: 20_095 nanoseconds. - Weight::from_parts(20_770_000, 5880) + // Minimum execution time: 20_272 nanoseconds. + Weight::from_ref_time(20_922_000) + .saturating_add(Weight::from_proof_size(5880)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1245,8 +1340,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `42` // Estimated: `2527` - // Minimum execution time: 14_078 nanoseconds. - Weight::from_parts(14_582_000, 2527) + // Minimum execution time: 14_287 nanoseconds. + Weight::from_ref_time(14_960_000) + .saturating_add(Weight::from_proof_size(2527)) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1258,8 +1354,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `333` // Estimated: `5103` - // Minimum execution time: 17_677 nanoseconds. - Weight::from_parts(18_381_000, 5103) + // Minimum execution time: 17_948 nanoseconds. + Weight::from_ref_time(18_780_000) + .saturating_add(Weight::from_proof_size(5103)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1271,8 +1368,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `333` // Estimated: `5103` - // Minimum execution time: 16_295 nanoseconds. - Weight::from_parts(17_036_000, 5103) + // Minimum execution time: 16_616 nanoseconds. + Weight::from_ref_time(17_155_000) + .saturating_add(Weight::from_proof_size(5103)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1288,8 +1386,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `516` // Estimated: `8407` - // Minimum execution time: 22_847 nanoseconds. - Weight::from_parts(23_536_000, 8407) + // Minimum execution time: 22_777 nanoseconds. + Weight::from_ref_time(23_955_000) + .saturating_add(Weight::from_proof_size(8407)) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1313,8 +1412,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `934` // Estimated: `16129` - // Minimum execution time: 60_517 nanoseconds. - Weight::from_parts(62_528_000, 16129) + // Minimum execution time: 61_131 nanoseconds. + Weight::from_ref_time(62_791_000) + .saturating_add(Weight::from_proof_size(16129)) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -1323,10 +1423,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_866 nanoseconds. - Weight::from_ref_time(3_949_301) - // Standard Error: 11_044 - .saturating_add(Weight::from_ref_time(3_424_466).saturating_mul(n.into())) + // Minimum execution time: 1_952 nanoseconds. + Weight::from_ref_time(3_975_700) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 11_254 + .saturating_add(Weight::from_ref_time(3_501_698).saturating_mul(n.into())) } /// Storage: Nfts Item (r:2 w:0) /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) @@ -1336,8 +1437,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `524` // Estimated: `6672` - // Minimum execution time: 21_174 nanoseconds. - Weight::from_parts(21_619_000, 6672) + // Minimum execution time: 20_327 nanoseconds. + Weight::from_ref_time(21_714_000) + .saturating_add(Weight::from_proof_size(6672)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1349,8 +1451,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `511` // Estimated: `5882` - // Minimum execution time: 20_606 nanoseconds. - Weight::from_parts(21_150_000, 5882) + // Minimum execution time: 20_668 nanoseconds. + Weight::from_ref_time(21_416_000) + .saturating_add(Weight::from_proof_size(5882)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1374,8 +1477,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1097` // Estimated: `21970` - // Minimum execution time: 88_414 nanoseconds. - Weight::from_parts(91_830_000, 21970) + // Minimum execution time: 88_006 nanoseconds. + Weight::from_ref_time(90_390_000) + .saturating_add(Weight::from_proof_size(21970)) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(11_u64)) } @@ -1400,14 +1504,43 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `596` // Estimated: `16180 + n * (2921 ±0)` - // Minimum execution time: 124_354 nanoseconds. - Weight::from_parts(133_779_491, 16180) - // Standard Error: 38_452 - .saturating_add(Weight::from_ref_time(25_110_697).saturating_mul(n.into())) + // Minimum execution time: 124_967 nanoseconds. + Weight::from_ref_time(131_602_642) + .saturating_add(Weight::from_proof_size(16180)) + // Standard Error: 36_480 + .saturating_add(Weight::from_ref_time(25_811_394).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(6_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) .saturating_add(Weight::from_proof_size(2921).saturating_mul(n.into())) } + /// Storage: Nfts Item (r:1 w:0) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts ItemAttributesApprovalsOf (r:1 w:1) + /// Proof: Nfts ItemAttributesApprovalsOf (max_values: None, max_size: Some(681), added: 3156, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:0) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts Attribute (r:10 w:10) + /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// The range of component `n` is `[0, 10]`. + fn set_attributes_pre_signed(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `716` + // Estimated: `14198 + n * (2921 ±0)` + // Minimum execution time: 84_153 nanoseconds. + Weight::from_ref_time(96_401_623) + .saturating_add(Weight::from_proof_size(14198)) + // Standard Error: 70_244 + .saturating_add(Weight::from_ref_time(26_866_222).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_proof_size(2921).saturating_mul(n.into())) + } } From 56de870f943679fede8443d06d3aa96a9f7321d6 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 22 Feb 2023 09:09:11 -0500 Subject: [PATCH 429/715] generation of real benchmark functions for benchmarking v2 (#13224) * function generation with _name working, need to modify signature * WIP * support custom BenchmarkResult type * full support for BenchmarkResult on benchmark function defs * support () return type for benchmark function defs that don't use ? * uncomment * fix where clause handling * fix benchmark function call bodies * proper parsing of return type * add UI tests for bad return type * fix detection of missing last_stmt with defined return type * UI tests covering missing last_stmt * properly detect and complain about empty benchmark function defs * fix missing Comma in Result parsing + test * add additional UI test * allow complex path for BenchmarkResult and BenchmarkError in fn defs * add UI tests covering complex path for BenchmarkResult, BenchmarkError * retain doc comments and attributes * also add attributes to struct * add docs for benchmark function definition support * fix imports on benchmark example * fix issue with unused variables in extrinsic call fn def * fix up docs * remove support for v2::BenchmarkResult because it was confusing * fix typo * remove ability to use custom T for Result in v2 * use missing call error instead of empty_fn() * remove unneeded match statement * Add a proper QED Co-authored-by: Keith Yeung * fix other QED Co-authored-by: Keith Yeung * cargo fmt * add an explicit error for non TypePath as return type * tweak error warning and add a UI test for non TypePath return * remove comment * add docs about T and I generic params * improve docs referring to section "below" * pull out return type checking logic into its own function * pull out params parsing into its own function * pull out call_def parsing into its own function * add doc comment for missing_call() * replace spaces with tabs * add a result-based example to the benchmarking examples --------- Co-authored-by: Keith Yeung --- frame/balances/src/benchmarking.rs | 4 +- frame/benchmarking/src/lib.rs | 108 ++++++- frame/examples/basic/src/benchmarking.rs | 20 +- frame/support/procedural/src/benchmark.rs | 297 ++++++++++++++---- .../bad_return_non_benchmark_err.rs | 19 ++ .../bad_return_non_benchmark_err.stderr | 5 + .../benchmark_ui/bad_return_non_type_path.rs | 17 + .../bad_return_non_type_path.stderr | 5 + .../benchmark_ui/bad_return_non_unit_t.rs | 15 + .../benchmark_ui/bad_return_non_unit_t.stderr | 5 + .../bad_return_type_blank_with_question.rs | 22 ++ ...bad_return_type_blank_with_question.stderr | 10 + .../bad_return_type_no_last_stmt.rs | 16 + .../bad_return_type_no_last_stmt.stderr | 9 + .../bad_return_type_non_result.rs | 19 ++ .../bad_return_type_non_result.stderr | 5 + .../benchmark_ui/bad_return_type_option.rs | 18 ++ .../bad_return_type_option.stderr | 5 + .../test/tests/benchmark_ui/empty_function.rs | 13 + .../tests/benchmark_ui/empty_function.stderr | 5 + .../test/tests/benchmark_ui/missing_call.rs | 4 +- .../tests/benchmark_ui/missing_call.stderr | 7 +- .../valid_complex_path_benchmark_result.rs | 17 + .../benchmark_ui/pass/valid_no_last_stmt.rs | 16 + .../pass/valid_path_result_benchmark_error.rs | 17 + .../tests/benchmark_ui/pass/valid_result.rs | 18 ++ 26 files changed, 601 insertions(+), 95 deletions(-) create mode 100644 frame/support/test/tests/benchmark_ui/bad_return_non_benchmark_err.rs create mode 100644 frame/support/test/tests/benchmark_ui/bad_return_non_benchmark_err.stderr create mode 100644 frame/support/test/tests/benchmark_ui/bad_return_non_type_path.rs create mode 100644 frame/support/test/tests/benchmark_ui/bad_return_non_type_path.stderr create mode 100644 frame/support/test/tests/benchmark_ui/bad_return_non_unit_t.rs create mode 100644 frame/support/test/tests/benchmark_ui/bad_return_non_unit_t.stderr create mode 100644 frame/support/test/tests/benchmark_ui/bad_return_type_blank_with_question.rs create mode 100644 frame/support/test/tests/benchmark_ui/bad_return_type_blank_with_question.stderr create mode 100644 frame/support/test/tests/benchmark_ui/bad_return_type_no_last_stmt.rs create mode 100644 frame/support/test/tests/benchmark_ui/bad_return_type_no_last_stmt.stderr create mode 100644 frame/support/test/tests/benchmark_ui/bad_return_type_non_result.rs create mode 100644 frame/support/test/tests/benchmark_ui/bad_return_type_non_result.stderr create mode 100644 frame/support/test/tests/benchmark_ui/bad_return_type_option.rs create mode 100644 frame/support/test/tests/benchmark_ui/bad_return_type_option.stderr create mode 100644 frame/support/test/tests/benchmark_ui/empty_function.rs create mode 100644 frame/support/test/tests/benchmark_ui/empty_function.stderr create mode 100644 frame/support/test/tests/benchmark_ui/pass/valid_complex_path_benchmark_result.rs create mode 100644 frame/support/test/tests/benchmark_ui/pass/valid_no_last_stmt.rs create mode 100644 frame/support/test/tests/benchmark_ui/pass/valid_path_result_benchmark_error.rs create mode 100644 frame/support/test/tests/benchmark_ui/pass/valid_result.rs diff --git a/frame/balances/src/benchmarking.rs b/frame/balances/src/benchmarking.rs index c2ed0ace54100..b36fe1e341de3 100644 --- a/frame/balances/src/benchmarking.rs +++ b/frame/balances/src/benchmarking.rs @@ -225,7 +225,7 @@ mod benchmarks { } #[benchmark] - fn force_unreserve() { + fn force_unreserve() -> Result<(), BenchmarkError> { let user: T::AccountId = account("user", 0, SEED); let user_lookup = T::Lookup::unlookup(user.clone()); @@ -244,6 +244,8 @@ mod benchmarks { assert!(Balances::::reserved_balance(&user).is_zero()); assert_eq!(Balances::::free_balance(&user), balance); + + Ok(()) } impl_benchmark_test_suite! { diff --git a/frame/benchmarking/src/lib.rs b/frame/benchmarking/src/lib.rs index f5dc513650e21..7110c378d581e 100644 --- a/frame/benchmarking/src/lib.rs +++ b/frame/benchmarking/src/lib.rs @@ -114,21 +114,22 @@ pub use v1::*; /// Within a `#[benchmarks]` or `#[instance_benchmarks]` module, you can define individual /// benchmarks using the `#[benchmark]` attribute, as shown in the example above. /// -/// The `#[benchmark]` attribute expects a function definition with a blank return type and -/// zero or more arguments whose names are valid -/// [BenchmarkParameter](`crate::BenchmarkParameter`) parameters, such as `x`, `y`, `a`, `b`, -/// etc., and whose param types must implement [ParamRange](`v2::ParamRange`). At the moment -/// the only valid type that implements [ParamRange](`v2::ParamRange`) is -/// [Linear](`v2::Linear`). -/// -/// The valid syntax for defining a [Linear](`v2::Linear`)is `Linear` where `A`, and `B` +/// The `#[benchmark]` attribute expects a function definition with a blank return type (or a +/// return type compatible with `Result<(), BenchmarkError>`, as discussed below) and zero or +/// more arguments whose names are valid [BenchmarkParameter](`crate::BenchmarkParameter`) +/// parameters, such as `x`, `y`, `a`, `b`, etc., and whose param types must implement +/// [ParamRange](`v2::ParamRange`). At the moment the only valid type that implements +/// [ParamRange](`v2::ParamRange`) is [Linear](`v2::Linear`). +/// +/// The valid syntax for defining a [Linear](`v2::Linear`) is `Linear` where `A`, and `B` /// are valid integer literals (that fit in a `u32`), such that `B` >= `A`. /// -/// Note that the benchmark function definition does not actually expand as a function -/// definition, but rather is used to automatically create a number of impls and structs -/// required by the benchmarking engine. For this reason, the visibility of the function -/// definition as well as the return type are not used for any purpose and are discarded by the -/// expansion code. +/// Anywhere within a benchmark function you may use the generic `T: Config` parameter as well +/// as `I` in the case of an `#[instance_benchmarks]` module. You should not add these to the +/// function signature as this will be handled automatically for you based on whether this is a +/// `#[benchmarks]` or `#[instance_benchmarks]` module and whatever [where clause](#where-clause) +/// you have defined for the the module. You should not manually add any generics to the +/// signature of your benchmark function. /// /// Also note that the `// setup code` and `// verification code` comments shown above are not /// required and are included simply for demonstration purposes. @@ -189,10 +190,10 @@ pub use v1::*; /// /// #### `skip_meta` /// -/// Specifies that the benchmarking framework should not analyze the storage keys that +/// Specifies that the benchmarking framework should not analyze the storage keys that the /// benchmarked code read or wrote. This useful to suppress the prints in the form of unknown -/// 0x… in case a storage key that does not have metadata. Note that this skips the analysis -/// of all accesses, not just ones without metadata. +/// 0x… in case a storage key that does not have metadata. Note that this skips the analysis of +/// all accesses, not just ones without metadata. /// /// ## Where Clause /// @@ -231,6 +232,79 @@ pub use v1::*; /// ); /// } /// ``` +/// +/// ## Benchmark Function Generation +/// +/// The benchmark function definition that you provide is used to automatically create a number +/// of impls and structs required by the benchmarking engine. Additionally, a benchmark +/// function is also generated that resembles the function definition you provide, with a few +/// modifications: +/// 1. The function name is transformed from i.e. `original_name` to `_original_name` so as not +/// to collide with the struct `original_name` that is created for some of the benchmarking +/// engine impls. +/// 2. Appropriate `T: Config` and `I` (if this is an instance benchmark) generics are added to +/// the function automatically during expansion, so you should not add these manually on +/// your function definition (but you may make use of `T` and `I` anywhere within your +/// benchmark function, in any of the three sections (setup, call, verification). +/// 3. Arguments such as `u: Linear<10, 100>` are converted to `u: u32` to make the function +/// directly callable. +/// 4. A `verify: bool` param is added as the last argument. Specifying `true` will result in +/// the verification section of your function executing, while a value of `false` will skip +/// verification. +/// 5. If you specify a return type on the function definition, it must conform to the [rules +/// below](#support-for-result-benchmarkerror-and-the--operator), and the last statement of +/// the function definition must resolve to something compatible with `Result<(), +/// BenchmarkError>`. +/// +/// The reason we generate an actual function as part of the expansion is to allow the compiler +/// to enforce several constraints that would otherwise be difficult to enforce and to reduce +/// developer confusion (especially regarding the use of the `?` operator, as covered below). +/// +/// Note that any attributes, comments, and doc comments attached to your benchmark function +/// definition are also carried over onto the resulting benchmark function and the struct for +/// that benchmark. As a result you should be careful about what attributes you attach here as +/// they will be replicated in multiple places. +/// +/// ### Support for `Result<(), BenchmarkError>` and the `?` operator +/// +/// You may optionally specify `Result<(), BenchmarkError>` as the return type of your +/// benchmark function definition. If you do so, you must return a compatible `Result<(), +/// BenchmarkError>` as the *last statement* of your benchmark function definition. You may +/// also use the `?` operator throughout your benchmark function definition if you choose to +/// follow this route. See the example below: +/// +/// ```ignore +/// #![cfg(feature = "runtime-benchmarks")] +/// +/// use super::{mock_helpers::*, Pallet as MyPallet}; +/// use frame_benchmarking::v2::*; +/// +/// #[benchmarks] +/// mod benchmarks { +/// use super::*; +/// +/// #[benchmark] +/// fn bench_name(x: Linear<5, 25>) -> Result<(), BenchmarkError> { +/// // setup code +/// let z = x + 4; +/// let caller = whitelisted_caller(); +/// +/// // note we can make use of the ? operator here because of the return type +/// something(z)?; +/// +/// #[extrinsic_call] +/// extrinsic_name(SystemOrigin::Signed(caller), other, arguments); +/// +/// // verification code +/// assert_eq!(MyPallet::::my_var(), z); +/// +/// // we must return a valid `Result<(), BenchmarkError>` as the last line of our benchmark +/// // function definition. This line is not included as part of the verification code that +/// // appears above it. +/// Ok(()) +/// } +/// } +/// ``` pub mod v2 { pub use super::*; pub use frame_support_procedural::{ @@ -240,7 +314,7 @@ pub mod v2 { // Used in #[benchmark] implementation to ensure that benchmark function arguments // implement [`ParamRange`]. #[doc(hidden)] - pub use static_assertions::assert_impl_all; + pub use static_assertions::{assert_impl_all, assert_type_eq_all}; /// Used by the new benchmarking code to specify that a benchmarking variable is linear /// over some specified range, i.e. `Linear<0, 1_000>` means that the corresponding variable diff --git a/frame/examples/basic/src/benchmarking.rs b/frame/examples/basic/src/benchmarking.rs index 0d2e9c5b3b1b3..4b2ebb41fbda1 100644 --- a/frame/examples/basic/src/benchmarking.rs +++ b/frame/examples/basic/src/benchmarking.rs @@ -21,11 +21,7 @@ #![cfg(feature = "runtime-benchmarks")] use crate::*; -use frame_benchmarking::v1::{ - impl_benchmark_test_suite, - v2::{benchmarks, Linear}, - whitelisted_caller, -}; +use frame_benchmarking::v2::*; use frame_system::RawOrigin; // To actually run this benchmark on pallet-example-basic, we need to put this pallet into the @@ -55,19 +51,31 @@ mod benchmarks { assert_eq!(Pallet::::dummy(), Some(value)) } + // An example method that returns a Result that can be called within a benchmark + fn example_result_method() -> Result<(), BenchmarkError> { + Ok(()) + } + // 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. #[benchmark] - fn accumulate_dummy() { + fn accumulate_dummy() -> Result<(), BenchmarkError> { let value = 1000u32.into(); // The caller account is whitelisted for DB reads/write by the benchmarking macro. let caller: T::AccountId = whitelisted_caller(); + // an example of calling something result-based within a benchmark using the ? operator + // this necessitates specifying the `Result<(), BenchmarkError>` return type + example_result_method()?; + // You can use `_` if the name of the Call matches the benchmark name. #[extrinsic_call] _(RawOrigin::Signed(caller), value); + + // need this to be compatible with the return type + Ok(()) } /// You can write helper functions in here since its a normal Rust module. diff --git a/frame/support/procedural/src/benchmark.rs b/frame/support/procedural/src/benchmark.rs index 6cf1d7ecc23af..1aca2f87b1d1d 100644 --- a/frame/support/procedural/src/benchmark.rs +++ b/frame/support/procedural/src/benchmark.rs @@ -25,11 +25,13 @@ use quote::{quote, quote_spanned, ToTokens}; use syn::{ parenthesized, parse::{Nothing, ParseStream}, + parse_quote, punctuated::Punctuated, spanned::Spanned, token::{Colon2, Comma, Gt, Lt, Paren}, Attribute, Error, Expr, ExprBlock, ExprCall, ExprPath, FnArg, Item, ItemFn, ItemMod, LitInt, - Pat, Path, PathArguments, PathSegment, Result, Stmt, Token, Type, WhereClause, + Pat, Path, PathArguments, PathSegment, Result, ReturnType, Signature, Stmt, Token, Type, + TypePath, Visibility, WhereClause, }; mod keywords { @@ -41,6 +43,8 @@ mod keywords { custom_keyword!(extra); custom_keyword!(extrinsic_call); custom_keyword!(skip_meta); + custom_keyword!(BenchmarkError); + custom_keyword!(Result); } /// This represents the raw parsed data for a param definition such as `x: Linear<10, 20>`. @@ -145,62 +149,121 @@ struct BenchmarkDef { setup_stmts: Vec, call_def: BenchmarkCallDef, verify_stmts: Vec, + last_stmt: Option, extra: bool, skip_meta: bool, + fn_sig: Signature, + fn_vis: Visibility, + fn_attrs: Vec, } -impl BenchmarkDef { - /// Constructs a [`BenchmarkDef`] by traversing an existing [`ItemFn`] node. - pub fn from(item_fn: &ItemFn, extra: bool, skip_meta: bool) -> Result { - let mut params: Vec = Vec::new(); +/// used to parse something compatible with `Result` +#[derive(Parse)] +struct ResultDef { + _result_kw: keywords::Result, + _lt: Token![<], + unit: Type, + _comma: Comma, + e_type: TypePath, + _gt: Token![>], +} - // parse params such as "x: Linear<0, 1>" - for arg in &item_fn.sig.inputs { - let invalid_param = |span| { - return Err(Error::new(span, "Invalid benchmark function param. A valid example would be `x: Linear<5, 10>`.", )) +/// Ensures that `ReturnType` is a `Result<(), BenchmarkError>`, if specified +fn ensure_valid_return_type(item_fn: &ItemFn) -> Result<()> { + if let ReturnType::Type(_, typ) = &item_fn.sig.output { + let non_unit = |span| return Err(Error::new(span, "expected `()`")); + let Type::Path(TypePath { path, qself: _ }) = &**typ else { + return Err(Error::new( + typ.span(), + "Only `Result<(), BenchmarkError>` or a blank return type is allowed on benchmark function definitions", + )) }; + let seg = path + .segments + .last() + .expect("to be parsed as a TypePath, it must have at least one segment; qed"); + let res: ResultDef = syn::parse2(seg.to_token_stream())?; + // ensure T in Result is () + let Type::Tuple(tup) = res.unit else { return non_unit(res.unit.span()) }; + if !tup.elems.is_empty() { + return non_unit(tup.span()) + } + let TypePath { path, qself: _ } = res.e_type; + let seg = path + .segments + .last() + .expect("to be parsed as a TypePath, it must have at least one segment; qed"); + syn::parse2::(seg.to_token_stream())?; + } + Ok(()) +} - let FnArg::Typed(arg) = arg else { return invalid_param(arg.span()) }; - let Pat::Ident(ident) = &*arg.pat else { return invalid_param(arg.span()) }; +/// Parses params such as `x: Linear<0, 1>` +fn parse_params(item_fn: &ItemFn) -> Result> { + let mut params: Vec = Vec::new(); + for arg in &item_fn.sig.inputs { + let invalid_param = |span| { + return Err(Error::new( + span, + "Invalid benchmark function param. A valid example would be `x: Linear<5, 10>`.", + )) + }; - // check param name - let var_span = ident.span(); - let invalid_param_name = || { - return Err(Error::new( + let FnArg::Typed(arg) = arg else { return invalid_param(arg.span()) }; + let Pat::Ident(ident) = &*arg.pat else { return invalid_param(arg.span()) }; + + // check param name + let var_span = ident.span(); + let invalid_param_name = || { + return Err(Error::new( var_span, "Benchmark parameter names must consist of a single lowercase letter (a-z) and no other characters.", )) - }; - let name = ident.ident.to_token_stream().to_string(); - if name.len() > 1 { - return invalid_param_name() - }; - let Some(name_char) = name.chars().next() else { return invalid_param_name() }; - if !name_char.is_alphabetic() || !name_char.is_lowercase() { - return invalid_param_name() - } + }; + let name = ident.ident.to_token_stream().to_string(); + if name.len() > 1 { + return invalid_param_name() + }; + let Some(name_char) = name.chars().next() else { return invalid_param_name() }; + if !name_char.is_alphabetic() || !name_char.is_lowercase() { + return invalid_param_name() + } - // parse type - let typ = &*arg.ty; - let Type::Path(tpath) = typ else { return invalid_param(typ.span()) }; - let Some(segment) = tpath.path.segments.last() else { return invalid_param(typ.span()) }; - let args = segment.arguments.to_token_stream().into(); - let Ok(args) = syn::parse::(args) else { return invalid_param(typ.span()) }; - let Ok(start) = args.start.base10_parse::() else { return invalid_param(args.start.span()) }; - let Ok(end) = args.end.base10_parse::() else { return invalid_param(args.end.span()) }; + // parse type + let typ = &*arg.ty; + let Type::Path(tpath) = typ else { return invalid_param(typ.span()) }; + let Some(segment) = tpath.path.segments.last() else { return invalid_param(typ.span()) }; + let args = segment.arguments.to_token_stream().into(); + let Ok(args) = syn::parse::(args) else { return invalid_param(typ.span()) }; + let Ok(start) = args.start.base10_parse::() else { return invalid_param(args.start.span()) }; + let Ok(end) = args.end.base10_parse::() else { return invalid_param(args.end.span()) }; + + if end < start { + return Err(Error::new( + args.start.span(), + "The start of a `ParamRange` must be less than or equal to the end", + )) + } - if end < start { - return Err(Error::new( - args.start.span(), - "The start of a `ParamRange` must be less than or equal to the end", - )) - } + params.push(ParamDef { name, typ: typ.clone(), start, end }); + } + Ok(params) +} - params.push(ParamDef { name, typ: typ.clone(), start, end }); - } +/// Used in several places where the `#[extrinsic_call]` or `#[body]` annotation is missing +fn missing_call(item_fn: &ItemFn) -> Result { + return Err(Error::new( + item_fn.block.brace_token.span, + "No valid #[extrinsic_call] or #[block] annotation could be found in benchmark function body." + )) +} - // #[extrinsic_call] / #[block] handling - let call_defs = item_fn.block.stmts.iter().enumerate().filter_map(|(i, child)| { +/// Finds the `BenchmarkCallDef` and its index (within the list of stmts for the fn) and +/// returns them. Also handles parsing errors for invalid / extra call defs. AKA this is +/// general handling for `#[extrinsic_call]` and `#[block]` +fn parse_call_def(item_fn: &ItemFn) -> Result<(usize, BenchmarkCallDef)> { + // #[extrinsic_call] / #[block] handling + let call_defs = item_fn.block.stmts.iter().enumerate().filter_map(|(i, child)| { if let Stmt::Semi(Expr::Call(expr_call), _semi) = child { // #[extrinsic_call] case expr_call.attrs.iter().enumerate().find_map(|(k, attr)| { @@ -234,25 +297,60 @@ impl BenchmarkDef { None } }).collect::>>()?; - let (i, call_def) = match &call_defs[..] { - [(i, call_def)] => (*i, call_def.clone()), // = 1 - [] => return Err(Error::new( // = 0 - item_fn.block.brace_token.span, - "No valid #[extrinsic_call] or #[block] annotation could be found in benchmark function body." - )), - _ => return Err(Error::new( // > 1 + Ok(match &call_defs[..] { + [(i, call_def)] => (*i, call_def.clone()), // = 1 + [] => return missing_call(item_fn), + _ => + return Err(Error::new( call_defs[1].1.attr_span(), - "Only one #[extrinsic_call] or #[block] attribute is allowed per benchmark." + "Only one #[extrinsic_call] or #[block] attribute is allowed per benchmark.", )), + }) +} + +impl BenchmarkDef { + /// Constructs a [`BenchmarkDef`] by traversing an existing [`ItemFn`] node. + pub fn from(item_fn: &ItemFn, extra: bool, skip_meta: bool) -> Result { + let params = parse_params(item_fn)?; + ensure_valid_return_type(item_fn)?; + let (i, call_def) = parse_call_def(&item_fn)?; + + let (verify_stmts, last_stmt) = match item_fn.sig.output { + ReturnType::Default => + // no return type, last_stmt should be None + (Vec::from(&item_fn.block.stmts[(i + 1)..item_fn.block.stmts.len()]), None), + ReturnType::Type(_, _) => { + // defined return type, last_stmt should be Result<(), BenchmarkError> + // compatible and should not be included in verify_stmts + if i + 1 >= item_fn.block.stmts.len() { + return Err(Error::new( + item_fn.block.span(), + "Benchmark `#[block]` or `#[extrinsic_call]` item cannot be the \ + last statement of your benchmark function definition if you have \ + defined a return type. You should return something compatible \ + with Result<(), BenchmarkError> (i.e. `Ok(())`) as the last statement \ + or change your signature to a blank return type.", + )) + } + let Some(stmt) = item_fn.block.stmts.last() else { return missing_call(item_fn) }; + ( + Vec::from(&item_fn.block.stmts[(i + 1)..item_fn.block.stmts.len() - 1]), + Some(stmt.clone()), + ) + }, }; Ok(BenchmarkDef { params, setup_stmts: Vec::from(&item_fn.block.stmts[0..i]), call_def, - verify_stmts: Vec::from(&item_fn.block.stmts[(i + 1)..item_fn.block.stmts.len()]), + verify_stmts, + last_stmt, extra, skip_meta, + fn_sig: item_fn.sig.clone(), + fn_vis: item_fn.vis.clone(), + fn_attrs: item_fn.attrs.clone(), }) } } @@ -643,6 +741,7 @@ fn expand_benchmark( let traits = quote!(#krate::frame_support::traits); let setup_stmts = benchmark_def.setup_stmts; let verify_stmts = benchmark_def.verify_stmts; + let last_stmt = benchmark_def.last_stmt; let test_ident = Ident::new(format!("test_{}", name.to_string()).as_str(), Span::call_site()); // unroll params (prepare for quoting) @@ -661,7 +760,8 @@ fn expand_benchmark( true => quote!(T: Config, I: 'static), }; - let (pre_call, post_call) = match benchmark_def.call_def { + // used in the benchmarking impls + let (pre_call, post_call, fn_call_body) = match &benchmark_def.call_def { BenchmarkCallDef::ExtrinsicCall { origin, expr_call, attr_span: _ } => { let mut expr_call = expr_call.clone(); @@ -705,36 +805,97 @@ fn expand_benchmark( qself: None, path: Path { leading_colon: None, segments: punct }, }); - + let pre_call = quote! { + let __call = Call::<#type_use_generics>::#expr_call; + let __benchmarked_call_encoded = #codec::Encode::encode(&__call); + }; + let post_call = quote! { + let __call_decoded = as #codec::Decode> + ::decode(&mut &__benchmarked_call_encoded[..]) + .expect("call is encoded above, encoding must be correct"); + let __origin = #origin.into(); + as #traits::UnfilteredDispatchable>::dispatch_bypass_filter( + __call_decoded, + __origin, + ) + }; ( - // (pre_call, post_call): - quote! { - let __call = Call::<#type_use_generics>::#expr_call; - let __benchmarked_call_encoded = #codec::Encode::encode(&__call); - }, + // (pre_call, post_call, fn_call_body): + pre_call.clone(), + quote!(#post_call?;), quote! { - let __call_decoded = as #codec::Decode> - ::decode(&mut &__benchmarked_call_encoded[..]) - .expect("call is encoded above, encoding must be correct"); - let __origin = #origin.into(); - as #traits::UnfilteredDispatchable>::dispatch_bypass_filter( - __call_decoded, - __origin, - )?; + #pre_call + #post_call.unwrap(); }, ) }, - BenchmarkCallDef::Block { block, attr_span: _ } => (quote!(), quote!(#block)), + BenchmarkCallDef::Block { block, attr_span: _ } => + (quote!(), quote!(#block), quote!(#block)), + }; + + let vis = benchmark_def.fn_vis; + + // remove #[benchmark] attribute + let fn_attrs: Vec<&Attribute> = benchmark_def + .fn_attrs + .iter() + .filter(|attr| !syn::parse2::(attr.path.to_token_stream()).is_ok()) + .collect(); + + // modify signature generics, ident, and inputs, e.g: + // before: `fn bench(u: Linear<1, 100>) -> Result<(), BenchmarkError>` + // after: `fn _bench , I: 'static>(u: u32, verify: bool) -> Result<(), + // BenchmarkError>` + let mut sig = benchmark_def.fn_sig; + sig.generics = parse_quote!(<#type_impl_generics>); + if !where_clause.is_empty() { + sig.generics.where_clause = parse_quote!(where #where_clause); + } + sig.ident = + Ident::new(format!("_{}", name.to_token_stream().to_string()).as_str(), Span::call_site()); + let mut fn_param_inputs: Vec = + param_names.iter().map(|name| quote!(#name: u32)).collect(); + fn_param_inputs.push(quote!(verify: bool)); + sig.inputs = parse_quote!(#(#fn_param_inputs),*); + + // used in instance() impl + let impl_last_stmt = match &last_stmt { + Some(stmt) => quote!(#stmt), + None => quote!(Ok(())), + }; + + let fn_def = quote! { + #( + #fn_attrs + )* + #vis #sig { + #( + #setup_stmts + )* + #fn_call_body + if verify { + #( + #verify_stmts + )* + } + #last_stmt + } }; // generate final quoted tokens let res = quote! { + // benchmark function definition + #fn_def + // compile-time assertions that each referenced param type implements ParamRange #( #home::assert_impl_all!(#param_types: #home::ParamRange); )* #[allow(non_camel_case_types)] + #( + #fn_attrs + )* struct #name; #[allow(unused_variables)] @@ -773,7 +934,7 @@ fn expand_benchmark( #verify_stmts )* } - Ok(()) + #impl_last_stmt })) } } diff --git a/frame/support/test/tests/benchmark_ui/bad_return_non_benchmark_err.rs b/frame/support/test/tests/benchmark_ui/bad_return_non_benchmark_err.rs new file mode 100644 index 0000000000000..5e332801df830 --- /dev/null +++ b/frame/support/test/tests/benchmark_ui/bad_return_non_benchmark_err.rs @@ -0,0 +1,19 @@ +use frame_benchmarking::v2::*; +#[allow(unused_imports)] +use frame_support_test::Config; + +#[benchmarks] +mod benches { + use super::*; + + #[benchmark] + fn bench() -> Result<(), BenchmarkException> { + let a = 2 + 2; + #[block] + {} + assert_eq!(a, 4); + Ok(()) + } +} + +fn main() {} diff --git a/frame/support/test/tests/benchmark_ui/bad_return_non_benchmark_err.stderr b/frame/support/test/tests/benchmark_ui/bad_return_non_benchmark_err.stderr new file mode 100644 index 0000000000000..ab0bff54a8a03 --- /dev/null +++ b/frame/support/test/tests/benchmark_ui/bad_return_non_benchmark_err.stderr @@ -0,0 +1,5 @@ +error: expected `BenchmarkError` + --> tests/benchmark_ui/bad_return_non_benchmark_err.rs:10:27 + | +10 | fn bench() -> Result<(), BenchmarkException> { + | ^^^^^^^^^^^^^^^^^^ diff --git a/frame/support/test/tests/benchmark_ui/bad_return_non_type_path.rs b/frame/support/test/tests/benchmark_ui/bad_return_non_type_path.rs new file mode 100644 index 0000000000000..a4b0d007eeecb --- /dev/null +++ b/frame/support/test/tests/benchmark_ui/bad_return_non_type_path.rs @@ -0,0 +1,17 @@ +use frame_benchmarking::v2::*; +#[allow(unused_imports)] +use frame_support_test::Config; + +#[benchmarks] +mod benchmarks { + use super::*; + + #[benchmark] + fn bench() -> (String, u32) { + #[block] + {} + (String::from("hey"), 23) + } +} + +fn main() {} diff --git a/frame/support/test/tests/benchmark_ui/bad_return_non_type_path.stderr b/frame/support/test/tests/benchmark_ui/bad_return_non_type_path.stderr new file mode 100644 index 0000000000000..69d61b4229155 --- /dev/null +++ b/frame/support/test/tests/benchmark_ui/bad_return_non_type_path.stderr @@ -0,0 +1,5 @@ +error: Only `Result<(), BenchmarkError>` or a blank return type is allowed on benchmark function definitions + --> tests/benchmark_ui/bad_return_non_type_path.rs:10:16 + | +10 | fn bench() -> (String, u32) { + | ^^^^^^^^^^^^^ diff --git a/frame/support/test/tests/benchmark_ui/bad_return_non_unit_t.rs b/frame/support/test/tests/benchmark_ui/bad_return_non_unit_t.rs new file mode 100644 index 0000000000000..15289c298aec1 --- /dev/null +++ b/frame/support/test/tests/benchmark_ui/bad_return_non_unit_t.rs @@ -0,0 +1,15 @@ +use frame_benchmarking::v2::*; +#[allow(unused_imports)] +use frame_support_test::Config; + +#[benchmarks] +mod benchmarks { + #[benchmark] + fn bench() -> Result { + #[block] + {} + Ok(10) + } +} + +fn main() {} diff --git a/frame/support/test/tests/benchmark_ui/bad_return_non_unit_t.stderr b/frame/support/test/tests/benchmark_ui/bad_return_non_unit_t.stderr new file mode 100644 index 0000000000000..4181ea099a14f --- /dev/null +++ b/frame/support/test/tests/benchmark_ui/bad_return_non_unit_t.stderr @@ -0,0 +1,5 @@ +error: expected `()` + --> tests/benchmark_ui/bad_return_non_unit_t.rs:8:23 + | +8 | fn bench() -> Result { + | ^^^ diff --git a/frame/support/test/tests/benchmark_ui/bad_return_type_blank_with_question.rs b/frame/support/test/tests/benchmark_ui/bad_return_type_blank_with_question.rs new file mode 100644 index 0000000000000..a6a2c61127fa2 --- /dev/null +++ b/frame/support/test/tests/benchmark_ui/bad_return_type_blank_with_question.rs @@ -0,0 +1,22 @@ +use frame_benchmarking::v2::*; +#[allow(unused_imports)] +use frame_support_test::Config; + +#[benchmarks] +mod benches { + use super::*; + + fn something() -> Result<(), BenchmarkError> { + Ok(()) + } + + #[benchmark] + fn bench() { + something()?; + #[block] + {} + assert_eq!(2 + 2, 4); + } +} + +fn main() {} diff --git a/frame/support/test/tests/benchmark_ui/bad_return_type_blank_with_question.stderr b/frame/support/test/tests/benchmark_ui/bad_return_type_blank_with_question.stderr new file mode 100644 index 0000000000000..1f8c9f1e171eb --- /dev/null +++ b/frame/support/test/tests/benchmark_ui/bad_return_type_blank_with_question.stderr @@ -0,0 +1,10 @@ +error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) + --> tests/benchmark_ui/bad_return_type_blank_with_question.rs:15:14 + | +5 | #[benchmarks] + | ------------- this function should return `Result` or `Option` to accept `?` +... +15 | something()?; + | ^ cannot use the `?` operator in a function that returns `()` + | + = help: the trait `FromResidual>` is not implemented for `()` diff --git a/frame/support/test/tests/benchmark_ui/bad_return_type_no_last_stmt.rs b/frame/support/test/tests/benchmark_ui/bad_return_type_no_last_stmt.rs new file mode 100644 index 0000000000000..76f1299005309 --- /dev/null +++ b/frame/support/test/tests/benchmark_ui/bad_return_type_no_last_stmt.rs @@ -0,0 +1,16 @@ +use frame_benchmarking::v2::*; +#[allow(unused_imports)] +use frame_support_test::Config; + +#[benchmarks] +mod benches { + use super::*; + + #[benchmark] + fn bench() -> Result<(), BenchmarkError> { + #[block] + {} + } +} + +fn main() {} diff --git a/frame/support/test/tests/benchmark_ui/bad_return_type_no_last_stmt.stderr b/frame/support/test/tests/benchmark_ui/bad_return_type_no_last_stmt.stderr new file mode 100644 index 0000000000000..ff501a620fe33 --- /dev/null +++ b/frame/support/test/tests/benchmark_ui/bad_return_type_no_last_stmt.stderr @@ -0,0 +1,9 @@ +error: Benchmark `#[block]` or `#[extrinsic_call]` item cannot be the last statement of your benchmark function definition if you have defined a return type. You should return something compatible with Result<(), BenchmarkError> (i.e. `Ok(())`) as the last statement or change your signature to a blank return type. + --> tests/benchmark_ui/bad_return_type_no_last_stmt.rs:10:43 + | +10 | fn bench() -> Result<(), BenchmarkError> { + | ______________________________________________^ +11 | | #[block] +12 | | {} +13 | | } + | |_____^ diff --git a/frame/support/test/tests/benchmark_ui/bad_return_type_non_result.rs b/frame/support/test/tests/benchmark_ui/bad_return_type_non_result.rs new file mode 100644 index 0000000000000..c206ec36a151e --- /dev/null +++ b/frame/support/test/tests/benchmark_ui/bad_return_type_non_result.rs @@ -0,0 +1,19 @@ +use frame_benchmarking::v2::*; +#[allow(unused_imports)] +use frame_support_test::Config; + +#[benchmarks] +mod benches { + use super::*; + + #[benchmark] + fn bench(y: Linear<1, 2>) -> String { + let a = 2 + 2; + #[block] + {} + assert_eq!(a, 4); + String::from("test") + } +} + +fn main() {} diff --git a/frame/support/test/tests/benchmark_ui/bad_return_type_non_result.stderr b/frame/support/test/tests/benchmark_ui/bad_return_type_non_result.stderr new file mode 100644 index 0000000000000..b830b8eb59c63 --- /dev/null +++ b/frame/support/test/tests/benchmark_ui/bad_return_type_non_result.stderr @@ -0,0 +1,5 @@ +error: expected `Result` + --> tests/benchmark_ui/bad_return_type_non_result.rs:10:31 + | +10 | fn bench(y: Linear<1, 2>) -> String { + | ^^^^^^ diff --git a/frame/support/test/tests/benchmark_ui/bad_return_type_option.rs b/frame/support/test/tests/benchmark_ui/bad_return_type_option.rs new file mode 100644 index 0000000000000..4b55885939747 --- /dev/null +++ b/frame/support/test/tests/benchmark_ui/bad_return_type_option.rs @@ -0,0 +1,18 @@ +use frame_benchmarking::v2::*; +#[allow(unused_imports)] +use frame_support_test::Config; + +#[benchmarks] +mod benches { + use super::*; + + #[benchmark] + fn bench() -> Option { + #[block] + {} + assert_eq!(2 + 2, 4); + None + } +} + +fn main() {} diff --git a/frame/support/test/tests/benchmark_ui/bad_return_type_option.stderr b/frame/support/test/tests/benchmark_ui/bad_return_type_option.stderr new file mode 100644 index 0000000000000..050da1676735a --- /dev/null +++ b/frame/support/test/tests/benchmark_ui/bad_return_type_option.stderr @@ -0,0 +1,5 @@ +error: expected `Result` + --> tests/benchmark_ui/bad_return_type_option.rs:10:16 + | +10 | fn bench() -> Option { + | ^^^^^^ diff --git a/frame/support/test/tests/benchmark_ui/empty_function.rs b/frame/support/test/tests/benchmark_ui/empty_function.rs new file mode 100644 index 0000000000000..bc04101dd384a --- /dev/null +++ b/frame/support/test/tests/benchmark_ui/empty_function.rs @@ -0,0 +1,13 @@ +use frame_benchmarking::v2::*; +#[allow(unused_imports)] +use frame_support_test::Config; + +#[benchmarks] +mod benches { + use super::*; + + #[benchmark] + fn bench() {} +} + +fn main() {} diff --git a/frame/support/test/tests/benchmark_ui/empty_function.stderr b/frame/support/test/tests/benchmark_ui/empty_function.stderr new file mode 100644 index 0000000000000..69d75303613d9 --- /dev/null +++ b/frame/support/test/tests/benchmark_ui/empty_function.stderr @@ -0,0 +1,5 @@ +error: No valid #[extrinsic_call] or #[block] annotation could be found in benchmark function body. + --> tests/benchmark_ui/empty_function.rs:10:13 + | +10 | fn bench() {} + | ^^ diff --git a/frame/support/test/tests/benchmark_ui/missing_call.rs b/frame/support/test/tests/benchmark_ui/missing_call.rs index bc04101dd384a..f39e74286b5cb 100644 --- a/frame/support/test/tests/benchmark_ui/missing_call.rs +++ b/frame/support/test/tests/benchmark_ui/missing_call.rs @@ -7,7 +7,9 @@ mod benches { use super::*; #[benchmark] - fn bench() {} + fn bench() { + assert_eq!(2 + 2, 4); + } } fn main() {} diff --git a/frame/support/test/tests/benchmark_ui/missing_call.stderr b/frame/support/test/tests/benchmark_ui/missing_call.stderr index 3b55f77d42562..908d970439227 100644 --- a/frame/support/test/tests/benchmark_ui/missing_call.stderr +++ b/frame/support/test/tests/benchmark_ui/missing_call.stderr @@ -1,5 +1,8 @@ error: No valid #[extrinsic_call] or #[block] annotation could be found in benchmark function body. --> tests/benchmark_ui/missing_call.rs:10:13 | -10 | fn bench() {} - | ^^ +10 | fn bench() { + | ________________^ +11 | | assert_eq!(2 + 2, 4); +12 | | } + | |_____^ diff --git a/frame/support/test/tests/benchmark_ui/pass/valid_complex_path_benchmark_result.rs b/frame/support/test/tests/benchmark_ui/pass/valid_complex_path_benchmark_result.rs new file mode 100644 index 0000000000000..4930aedd6011e --- /dev/null +++ b/frame/support/test/tests/benchmark_ui/pass/valid_complex_path_benchmark_result.rs @@ -0,0 +1,17 @@ +use frame_benchmarking::v2::*; +#[allow(unused_imports)] +use frame_support_test::Config; + +#[benchmarks] +mod benches { + use super::*; + + #[benchmark] + fn bench() -> Result<(), frame_benchmarking::v2::BenchmarkError> { + #[block] + {} + Ok(()) + } +} + +fn main() {} diff --git a/frame/support/test/tests/benchmark_ui/pass/valid_no_last_stmt.rs b/frame/support/test/tests/benchmark_ui/pass/valid_no_last_stmt.rs new file mode 100644 index 0000000000000..ce09b437a83bd --- /dev/null +++ b/frame/support/test/tests/benchmark_ui/pass/valid_no_last_stmt.rs @@ -0,0 +1,16 @@ +use frame_benchmarking::v2::*; +#[allow(unused_imports)] +use frame_support_test::Config; + +#[benchmarks] +mod benches { + use super::*; + + #[benchmark] + fn bench() { + #[block] + {} + } +} + +fn main() {} diff --git a/frame/support/test/tests/benchmark_ui/pass/valid_path_result_benchmark_error.rs b/frame/support/test/tests/benchmark_ui/pass/valid_path_result_benchmark_error.rs new file mode 100644 index 0000000000000..4930aedd6011e --- /dev/null +++ b/frame/support/test/tests/benchmark_ui/pass/valid_path_result_benchmark_error.rs @@ -0,0 +1,17 @@ +use frame_benchmarking::v2::*; +#[allow(unused_imports)] +use frame_support_test::Config; + +#[benchmarks] +mod benches { + use super::*; + + #[benchmark] + fn bench() -> Result<(), frame_benchmarking::v2::BenchmarkError> { + #[block] + {} + Ok(()) + } +} + +fn main() {} diff --git a/frame/support/test/tests/benchmark_ui/pass/valid_result.rs b/frame/support/test/tests/benchmark_ui/pass/valid_result.rs new file mode 100644 index 0000000000000..33d71ece4a018 --- /dev/null +++ b/frame/support/test/tests/benchmark_ui/pass/valid_result.rs @@ -0,0 +1,18 @@ +use frame_benchmarking::v2::*; +use frame_support_test::Config; + +#[benchmarks] +mod benches { + use super::*; + + #[benchmark] + fn bench() -> Result<(), BenchmarkError> { + let a = 2 + 2; + #[block] + {} + assert_eq!(a, 4); + Ok(()) + } +} + +fn main() {} From 5a1d521f88ec338e46d60023ee048c72af1fe616 Mon Sep 17 00:00:00 2001 From: Koute Date: Thu, 23 Feb 2023 19:56:11 +0900 Subject: [PATCH 430/715] Bump `wasmtime` to 6.0.0 (#13429) * Bump `wasmtime` to 6.0.0 * Disable cranelift egraphs --- Cargo.lock | 99 +++++++++++-------- client/executor/wasmtime/Cargo.toml | 6 +- .../executor/wasmtime/src/instance_wrapper.rs | 3 +- client/executor/wasmtime/src/runtime.rs | 11 ++- primitives/wasm-interface/Cargo.toml | 2 +- 5 files changed, 71 insertions(+), 50 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0f271f807a753..6326d1ffdf60c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1185,16 +1185,18 @@ checksum = "dcb25d077389e53838a8158c8e99174c5a9d902dee4904320db714f3c653ffba" [[package]] name = "cranelift-bforest" -version = "0.92.0" -source = "git+https://github.com/paritytech/wasmtime.git?branch=v5.0.0_lto_fix#8a02705ad378108e43abe23c538688adf73f3b71" +version = "0.93.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91b18cf92869a6ae85cde3af4bc4beb6154efa8adef03b18db2ad413d5bce3a2" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-codegen" -version = "0.92.0" -source = "git+https://github.com/paritytech/wasmtime.git?branch=v5.0.0_lto_fix#8a02705ad378108e43abe23c538688adf73f3b71" +version = "0.93.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567d9f6e919bac076f39b902a072686eaf9e6d015baa34d10a61b85105b7af59" dependencies = [ "arrayvec 0.7.2", "bumpalo", @@ -1213,29 +1215,33 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.92.0" -source = "git+https://github.com/paritytech/wasmtime.git?branch=v5.0.0_lto_fix#8a02705ad378108e43abe23c538688adf73f3b71" +version = "0.93.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e72b2d5ec8917b2971fe83850187373d0a186db4748a7c23a5f48691b8d92bb" dependencies = [ "cranelift-codegen-shared", ] [[package]] name = "cranelift-codegen-shared" -version = "0.92.0" -source = "git+https://github.com/paritytech/wasmtime.git?branch=v5.0.0_lto_fix#8a02705ad378108e43abe23c538688adf73f3b71" +version = "0.93.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3461c0e0c2ebbeb92533aacb27e219289f60dc84134ef34fbf2d77c9eddf07ef" [[package]] name = "cranelift-entity" -version = "0.92.0" -source = "git+https://github.com/paritytech/wasmtime.git?branch=v5.0.0_lto_fix#8a02705ad378108e43abe23c538688adf73f3b71" +version = "0.93.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af684f7f7b01427b1942c7102673322a51b9d6f261e9663dc5e5595786775531" dependencies = [ "serde", ] [[package]] name = "cranelift-frontend" -version = "0.92.0" -source = "git+https://github.com/paritytech/wasmtime.git?branch=v5.0.0_lto_fix#8a02705ad378108e43abe23c538688adf73f3b71" +version = "0.93.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d361ed0373cf5f086b49c499aa72227b646a64f899f32e34312f97c0fadff75" dependencies = [ "cranelift-codegen", "log", @@ -1245,13 +1251,15 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.92.0" -source = "git+https://github.com/paritytech/wasmtime.git?branch=v5.0.0_lto_fix#8a02705ad378108e43abe23c538688adf73f3b71" +version = "0.93.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cef4f8f3984d772c199a48896d2fb766f96301bf71b371e03a2b99f4f3b7b931" [[package]] name = "cranelift-native" -version = "0.92.0" -source = "git+https://github.com/paritytech/wasmtime.git?branch=v5.0.0_lto_fix#8a02705ad378108e43abe23c538688adf73f3b71" +version = "0.93.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f98e4e99a353703475d5acb402b9c13482d41d8a4008b352559bd560afb90363" dependencies = [ "cranelift-codegen", "libc", @@ -1260,8 +1268,9 @@ dependencies = [ [[package]] name = "cranelift-wasm" -version = "0.92.0" -source = "git+https://github.com/paritytech/wasmtime.git?branch=v5.0.0_lto_fix#8a02705ad378108e43abe23c538688adf73f3b71" +version = "0.93.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1e3f4f0779a1b0f286a6ef19835d8665f88326e656a6d7d84fa9a39fa38ca32" dependencies = [ "cranelift-codegen", "cranelift-entity", @@ -11951,9 +11960,9 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.96.0" +version = "0.100.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adde01ade41ab9a5d10ec8ed0bb954238cf8625b5cd5a13093d6de2ad9c2be1a" +checksum = "64b20236ab624147dfbb62cf12a19aaf66af0e41b8398838b66e997d07d269d4" dependencies = [ "indexmap", "url", @@ -11970,8 +11979,9 @@ dependencies = [ [[package]] name = "wasmtime" -version = "5.0.0" -source = "git+https://github.com/paritytech/wasmtime.git?branch=v5.0.0_lto_fix#8a02705ad378108e43abe23c538688adf73f3b71" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9010891d0b8e367c3be94ca35d7bc25c1de3240463bb1d61bcfc8c2233c4e0d0" dependencies = [ "anyhow", "bincode", @@ -11997,16 +12007,18 @@ dependencies = [ [[package]] name = "wasmtime-asm-macros" -version = "5.0.0" -source = "git+https://github.com/paritytech/wasmtime.git?branch=v5.0.0_lto_fix#8a02705ad378108e43abe23c538688adf73f3b71" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65805c663eaa8257b910666f6d4b056b5c7329750da754ba5df54f3af7dbf35c" dependencies = [ "cfg-if", ] [[package]] name = "wasmtime-cache" -version = "5.0.0" -source = "git+https://github.com/paritytech/wasmtime.git?branch=v5.0.0_lto_fix#8a02705ad378108e43abe23c538688adf73f3b71" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2049ddfc1b10efc3c5591d0e84b9570ca50478f8818f3bfabb1a467918f53fb4" dependencies = [ "anyhow", "base64 0.13.1", @@ -12024,8 +12036,9 @@ dependencies = [ [[package]] name = "wasmtime-cranelift" -version = "5.0.0" -source = "git+https://github.com/paritytech/wasmtime.git?branch=v5.0.0_lto_fix#8a02705ad378108e43abe23c538688adf73f3b71" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9065cad6a724fa838ec8497567e0b23acc26417bb2449f8d9d2021925c72f2" dependencies = [ "anyhow", "cranelift-codegen", @@ -12044,8 +12057,9 @@ dependencies = [ [[package]] name = "wasmtime-environ" -version = "5.0.0" -source = "git+https://github.com/paritytech/wasmtime.git?branch=v5.0.0_lto_fix#8a02705ad378108e43abe23c538688adf73f3b71" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f964bb0b91fa021b8d1b488c62cc77b346c1dae6e3ebd010050b57c1f2ca657" dependencies = [ "anyhow", "cranelift-entity", @@ -12062,8 +12076,9 @@ dependencies = [ [[package]] name = "wasmtime-jit" -version = "5.0.0" -source = "git+https://github.com/paritytech/wasmtime.git?branch=v5.0.0_lto_fix#8a02705ad378108e43abe23c538688adf73f3b71" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7a1d06f5d109539e0168fc74fa65e3948ac8dac3bb8cdbd08b62b36a0ae27b8" dependencies = [ "addr2line 0.17.0", "anyhow", @@ -12085,8 +12100,9 @@ dependencies = [ [[package]] name = "wasmtime-jit-debug" -version = "5.0.0" -source = "git+https://github.com/paritytech/wasmtime.git?branch=v5.0.0_lto_fix#8a02705ad378108e43abe23c538688adf73f3b71" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f76ef2e410329aaf8555ac6571d6fe07711be0646dcdf7ff3ab750a42ed2e583" dependencies = [ "object 0.29.0", "once_cell", @@ -12095,8 +12111,9 @@ dependencies = [ [[package]] name = "wasmtime-jit-icache-coherence" -version = "5.0.0" -source = "git+https://github.com/paritytech/wasmtime.git?branch=v5.0.0_lto_fix#8a02705ad378108e43abe23c538688adf73f3b71" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec1fd0f0dd79e7cc0f55b102e320d7c77ab76cd272008a8fd98e25b5777e2636" dependencies = [ "cfg-if", "libc", @@ -12105,8 +12122,9 @@ dependencies = [ [[package]] name = "wasmtime-runtime" -version = "5.0.0" -source = "git+https://github.com/paritytech/wasmtime.git?branch=v5.0.0_lto_fix#8a02705ad378108e43abe23c538688adf73f3b71" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271aef9b4ca2e953a866293683f2db33cda46f6933c5e431e68d8373723d4ab6" dependencies = [ "anyhow", "cc", @@ -12128,8 +12146,9 @@ dependencies = [ [[package]] name = "wasmtime-types" -version = "5.0.0" -source = "git+https://github.com/paritytech/wasmtime.git?branch=v5.0.0_lto_fix#8a02705ad378108e43abe23c538688adf73f3b71" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b18144b0e45479a830ac9fcebfc71a16d90dc72d8ebd5679700eb3bfe974d7df" dependencies = [ "cranelift-entity", "serde", diff --git a/client/executor/wasmtime/Cargo.toml b/client/executor/wasmtime/Cargo.toml index e29a195277681..ca7daa970207d 100644 --- a/client/executor/wasmtime/Cargo.toml +++ b/client/executor/wasmtime/Cargo.toml @@ -19,13 +19,13 @@ log = "0.4.17" # When bumping wasmtime do not forget to also bump rustix # to exactly the same version as used by wasmtime! -wasmtime = { version = "5.0.0", default-features = false, features = [ +wasmtime = { version = "6.0.0", default-features = false, features = [ "cache", "cranelift", "jitdump", "parallel-compilation", "pooling-allocator" -], git = "https://github.com/paritytech/wasmtime.git", branch = "v5.0.0_lto_fix" } +] } anyhow = "1.0.68" sc-allocator = { version = "4.1.0-dev", path = "../../allocator" } sc-executor-common = { version = "0.10.0-dev", path = "../common" } @@ -38,7 +38,7 @@ sp-wasm-interface = { version = "7.0.0", path = "../../../primitives/wasm-interf # By default rustix directly calls the appropriate syscalls completely bypassing libc; # this doesn't have any actual benefits for us besides making it harder to debug memory # problems (since then `mmap` etc. cannot be easily hooked into). -rustix = { version = "0.36.0", default-features = false, features = ["std", "mm", "fs", "param", "use-libc"] } +rustix = { version = "0.36.7", default-features = false, features = ["std", "mm", "fs", "param", "use-libc"] } once_cell = "1.12.0" [dev-dependencies] diff --git a/client/executor/wasmtime/src/instance_wrapper.rs b/client/executor/wasmtime/src/instance_wrapper.rs index f80c7b70d1f28..2fb27180fcc76 100644 --- a/client/executor/wasmtime/src/instance_wrapper.rs +++ b/client/executor/wasmtime/src/instance_wrapper.rs @@ -402,8 +402,7 @@ fn decommit_works() { let code = wat::parse_str("(module (memory (export \"memory\") 1 4))").unwrap(); let module = wasmtime::Module::new(&engine, code).unwrap(); let linker = wasmtime::Linker::new(&engine); - let mut store = create_store(&engine, None); - let instance_pre = linker.instantiate_pre(&mut store, &module).unwrap(); + let instance_pre = linker.instantiate_pre(&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); diff --git a/client/executor/wasmtime/src/runtime.rs b/client/executor/wasmtime/src/runtime.rs index 1728feeee5a87..ce3f889fc9a75 100644 --- a/client/executor/wasmtime/src/runtime.rs +++ b/client/executor/wasmtime/src/runtime.rs @@ -298,6 +298,11 @@ fn common_config(semantics: &Semantics) -> std::result::Result wasmtime::ProfilingStrategy::JitDump, None => wasmtime::ProfilingStrategy::None, @@ -368,7 +373,7 @@ fn common_config(semantics: &Semantics) -> std::result::Result(&mut linker, &module, config.allow_missing_func_imports)?; - let mut store = - crate::instance_wrapper::create_store(module.engine(), config.semantics.max_memory_size); let instance_pre = linker - .instantiate_pre(&mut store, &module) + .instantiate_pre(&module) .map_err(|e| WasmError::Other(format!("cannot preinstantiate module: {:#}", e)))?; Ok(WasmtimeRuntime { diff --git a/primitives/wasm-interface/Cargo.toml b/primitives/wasm-interface/Cargo.toml index 21b0bb4329ed7..65c4ae42f044e 100644 --- a/primitives/wasm-interface/Cargo.toml +++ b/primitives/wasm-interface/Cargo.toml @@ -18,7 +18,7 @@ codec = { package = "parity-scale-codec", version = "3.2.2", default-features = impl-trait-for-tuples = "0.2.2" log = { version = "0.4.17", optional = true } wasmi = { version = "0.13", optional = true } -wasmtime = { version = "5.0.0", default-features = false, optional = true, git = "https://github.com/paritytech/wasmtime.git", branch = "v5.0.0_lto_fix" } +wasmtime = { version = "6.0.0", default-features = false, optional = true } anyhow = { version = "1.0.68", optional = true } sp-std = { version = "5.0.0", default-features = false, path = "../std" } From 4be5dd2937ab9fffd4f13772b547450a95a59018 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 23 Feb 2023 11:21:00 +0000 Subject: [PATCH 431/715] Abstracts elections-phragmen pallet to use NposSolver (#12588) * Abstracts elections-phragmen pallet to use NposSolver * Update frame/elections-phragmen/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update frame/elections-phragmen/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * changes the name of the pallet; adds changelog * update changelog * Adds weight testing * Adds log macro_rules * renames elections-phragment dir to elections * weights rename * fixes typo in cargo toml * pre/post solve weight scafolding * refactor do_post_election * refactors into pre and post election solve for independent benchmarking * deconstructs PreElectionResults struct * updates benchmarking pre and post election solve; mock weights * Update frame/elections/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update frame/elections/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * addresses PR comments * adds pre_solve and post_sove weights * Adds comments on election pallet id param name change * ".git/.scripts/bench-bot.sh" pallet dev pallet_elections * Finishes pre-post solve weights * Update frame/elections/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update frame/elections/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Addresses PR comments: no panic in on_init path; nits * Fixes node build * Implements approval voting to use as a `NposSolver` (#13367) * Implements the approval voting methods in sp_npos_elections * fmt * remove unecessary file * comment clarification * re-run weights * fix typo * updates MaxVoters in tests for integrity_tests to pass * Refactors election provider support benchmarks outside its own crate (#13431) * Refactors election provider support benchmarks outside its own crate --------- Co-authored-by: command-bot <> --------- Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: parity-processbot <> Co-authored-by: Ross Bulat --- Cargo.lock | 265 ++++----- Cargo.toml | 3 +- bin/node/runtime/Cargo.toml | 12 +- bin/node/runtime/src/lib.rs | 30 +- .../election-provider-multi-phase/Cargo.toml | 2 - frame/election-provider-support/Cargo.toml | 8 +- .../benchmarking/Cargo.toml | 37 -- .../src/lib.rs => src/benchmarking.rs} | 18 +- frame/election-provider-support/src/lib.rs | 26 + .../election-provider-support/src/onchain.rs | 30 +- .../election-provider-support/src/weights.rs | 147 +++-- frame/elections-phragmen/src/weights.rs | 559 ------------------ .../CHANGELOG.md | 11 + .../Cargo.toml | 5 +- .../README.md | 6 +- .../src/benchmarking.rs | 57 +- .../src/lib.rs | 482 +++++++++------ .../src/migrations/mod.rs | 0 .../src/migrations/v3.rs | 0 .../src/migrations/v4.rs | 0 .../src/migrations/v5.rs | 0 frame/elections/src/weights.rs | 397 +++++++++++++ .../npos-elections/src/approval_voting.rs | 79 +++ primitives/npos-elections/src/lib.rs | 4 + primitives/npos-elections/src/phragmen.rs | 2 +- primitives/npos-elections/src/tests.rs | 49 +- scripts/run_all_benchmarks.sh | 2 - utils/frame/remote-externalities/Cargo.toml | 2 +- 28 files changed, 1206 insertions(+), 1027 deletions(-) delete mode 100644 frame/election-provider-support/benchmarking/Cargo.toml rename frame/election-provider-support/{benchmarking/src/lib.rs => src/benchmarking.rs} (86%) delete mode 100644 frame/elections-phragmen/src/weights.rs rename frame/{elections-phragmen => elections}/CHANGELOG.md (80%) rename frame/{elections-phragmen => elections}/Cargo.toml (90%) rename frame/{elections-phragmen => elections}/README.md (94%) rename frame/{elections-phragmen => elections}/src/benchmarking.rs (85%) rename frame/{elections-phragmen => elections}/src/lib.rs (90%) rename frame/{elections-phragmen => elections}/src/migrations/mod.rs (100%) rename frame/{elections-phragmen => elections}/src/migrations/v3.rs (100%) rename frame/{elections-phragmen => elections}/src/migrations/v4.rs (100%) rename frame/{elections-phragmen => elections}/src/migrations/v5.rs (100%) create mode 100644 frame/elections/src/weights.rs create mode 100644 primitives/npos-elections/src/approval_voting.rs diff --git a/Cargo.lock b/Cargo.lock index 6326d1ffdf60c..e485a6512250e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -27,7 +27,7 @@ version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" dependencies = [ - "gimli 0.27.1", + "gimli 0.27.2", ] [[package]] @@ -246,7 +246,7 @@ dependencies = [ "num-traits", "rusticata-macros", "thiserror", - "time 0.3.17", + "time 0.3.19", ] [[package]] @@ -262,7 +262,7 @@ dependencies = [ "num-traits", "rusticata-macros", "thiserror", - "time 0.3.17", + "time 0.3.19", ] [[package]] @@ -358,19 +358,20 @@ dependencies = [ [[package]] name = "async-stream" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dad5c83079eae9969be7fadefe640a1c566901f05ff91ab221de4b6f68d9507e" +checksum = "ad445822218ce64be7a341abfb0b1ea43b5c23aa83902542a4542e78309d8e5e" dependencies = [ "async-stream-impl", "futures-core", + "pin-project-lite 0.2.9", ] [[package]] name = "async-stream-impl" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10f203db73a71dfa2fb6dd22763990fa26f3d2625a6da2da900d23b87d26be27" +checksum = "e4655ae1a7b0cdf149156f780c5bf3f1352bc53cbd9e0a361a7ef7b22947e965" dependencies = [ "proc-macro2", "quote", @@ -579,9 +580,9 @@ dependencies = [ [[package]] name = "bindgen" -version = "0.60.1" +version = "0.64.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "062dddbc1ba4aca46de6338e2bf87771414c335f7b2f2036e8f3e9befebf88e6" +checksum = "c4243e6031260db77ede97ad86c27e501d646a27ab57b59a574f725d98ab1fb4" dependencies = [ "bitflags", "cexpr", @@ -594,6 +595,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", + "syn", ] [[package]] @@ -625,24 +627,24 @@ dependencies = [ [[package]] name = "blake2b_simd" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72936ee4afc7f8f736d1c38383b56480b5497b4617b4a77bdbf1d2ababc76127" +checksum = "3c2f0dc9a68c6317d884f97cc36cf5a3d20ba14ce404227df55e1af708ab04bc" dependencies = [ "arrayref", "arrayvec 0.7.2", - "constant_time_eq 0.1.5", + "constant_time_eq", ] [[package]] name = "blake2s_simd" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db539cc2b5f6003621f1cd9ef92d7ded8ea5232c7de0f9faa2de251cd98730d4" +checksum = "6637f448b9e61dfadbdcbae9a885fadee1f3eaffb1f8d3c1965d3ade8bdfd44f" dependencies = [ "arrayref", "arrayvec 0.7.2", - "constant_time_eq 0.1.5", + "constant_time_eq", ] [[package]] @@ -655,7 +657,7 @@ dependencies = [ "arrayvec 0.7.2", "cc", "cfg-if", - "constant_time_eq 0.2.4", + "constant_time_eq", ] [[package]] @@ -715,9 +717,9 @@ checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" [[package]] name = "bounded-collections" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de2aff4807e40f478132150d80b031f2461d88f061851afcab537d7600c24120" +checksum = "a071c348a5ef6da1d3a87166b408170b46002382b1dda83992b5c2208cefb370" dependencies = [ "log", "parity-scale-codec", @@ -733,9 +735,9 @@ checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" [[package]] name = "bstr" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7f0778972c64420fdedc63f09919c8a88bda7b25135357fd25a5d9f3257e832" +checksum = "5ffdb39cb703212f3c11973452c2861b972f757b021158f3516ba10f2fa8b2c1" dependencies = [ "memchr", "once_cell", @@ -917,7 +919,7 @@ name = "chain-spec-builder" version = "2.0.0" dependencies = [ "ansi_term", - "clap 4.1.4", + "clap 4.1.6", "node-cli", "rand 0.8.5", "sc-chain-spec", @@ -1010,9 +1012,9 @@ dependencies = [ [[package]] name = "clang-sys" -version = "1.4.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa2e27ae6ab525c3d369ded447057bca5438d86dc3a68f6faafb8269ba82ebf3" +checksum = "77ed9a53e5d4d9c573ae844bfac6872b159cb1d1585a83b29e7a64b7eef7332a" dependencies = [ "glob", "libc", @@ -1033,9 +1035,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.1.4" +version = "4.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f13b9c79b5d1dd500d20ef541215a6423c75829ef43117e1b4d17fd8af0b5d76" +checksum = "ec0b0588d44d4d63a87dbd75c136c166bbfd9a86a31cb89e09906521c7d3f5e3" dependencies = [ "bitflags", "clap_derive", @@ -1048,11 +1050,11 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.1.1" +version = "4.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6540eedc41f8a5a76cf3d8d458057dcdf817be4158a55b5f861f7a5483de75" +checksum = "bd125be87bf4c255ebc50de0b7f4d2a6201e8ac3dc86e39c0ad081dc5e7236fe" dependencies = [ - "clap 4.1.4", + "clap 4.1.6", ] [[package]] @@ -1122,12 +1124,6 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cec318a675afcb6a1ea1d4340e2d377e56e47c266f28043ceccbf4412ddfdd3b" -[[package]] -name = "constant_time_eq" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" - [[package]] name = "constant_time_eq" version = "0.2.4" @@ -1515,9 +1511,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.89" +version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc831ee6a32dd495436e317595e639a587aa9907bef96fe6e6abc290ab6204e9" +checksum = "86d3488e7665a7a483b57e25bdd90d0aeb2bc7608c8d0346acf2ad3f1caf1d62" dependencies = [ "cc", "cxxbridge-flags", @@ -1527,9 +1523,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.89" +version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94331d54f1b1a8895cd81049f7eaaaef9d05a7dcb4d1fd08bf3ff0806246789d" +checksum = "48fcaf066a053a41a81dfb14d57d99738b767febb8b735c3016e469fac5da690" dependencies = [ "cc", "codespan-reporting", @@ -1542,15 +1538,15 @@ dependencies = [ [[package]] name = "cxxbridge-flags" -version = "1.0.89" +version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48dcd35ba14ca9b40d6e4b4b39961f23d835dbb8eed74565ded361d93e1feb8a" +checksum = "a2ef98b8b717a829ca5603af80e1f9e2e48013ab227b68ef37872ef84ee479bf" [[package]] name = "cxxbridge-macro" -version = "1.0.89" +version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81bbeb29798b407ccd82a3324ade1a7286e0d29851475990b612670f6f5124d2" +checksum = "086c685979a698443656e5cf7856c95c642295a38599f12fb1ff76fb28d19892" dependencies = [ "proc-macro2", "quote", @@ -2051,9 +2047,9 @@ checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" [[package]] name = "fastrand" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" dependencies = [ "instant", ] @@ -2095,14 +2091,14 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.19" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e884668cd0c7480504233e951174ddc3b382f7c2666e3b7310b5c4e7b0c37f9" +checksum = "8a3de6e8d11b22ff9edc6d916f890800597d60f8b2da1caf2955c274638d6412" dependencies = [ "cfg-if", "libc", "redox_syscall", - "windows-sys 0.42.0", + "windows-sys 0.45.0", ] [[package]] @@ -2222,7 +2218,7 @@ dependencies = [ "Inflector", "array-bytes", "chrono", - "clap 4.1.4", + "clap 4.1.6", "comfy-table", "frame-benchmarking", "frame-support", @@ -2295,6 +2291,7 @@ dependencies = [ name = "frame-election-provider-support" version = "4.0.0-dev" dependencies = [ + "frame-benchmarking", "frame-election-provider-solution-type", "frame-support", "frame-system", @@ -2313,7 +2310,7 @@ dependencies = [ name = "frame-election-solution-type-fuzzer" version = "2.0.0-alpha.5" dependencies = [ - "clap 4.1.4", + "clap 4.1.6", "frame-election-provider-solution-type", "frame-election-provider-support", "frame-support", @@ -2366,7 +2363,7 @@ dependencies = [ "frame-support", "futures", "log", - "pallet-elections-phragmen", + "pallet-elections", "parity-scale-codec", "serde", "sp-core", @@ -2796,9 +2793,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.27.1" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "221996f774192f0f718773def8201c4ae31f02616a54ccfc2d358bb0e5cefdec" +checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" [[package]] name = "git2" @@ -2941,9 +2938,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "856b5cb0902c2b6d65d5fd97dfa30f9b70c7538e770b98eab5ed52d8db923e01" +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" [[package]] name = "hex" @@ -3035,9 +3032,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" +checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" dependencies = [ "bytes", "fnv", @@ -3321,7 +3318,7 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22e18b0a45d56fe973d6db23972bf5bc46f988a4a2385deac9cc29572f09daef" dependencies = [ - "hermit-abi 0.3.0", + "hermit-abi 0.3.1", "io-lifetimes", "rustix", "windows-sys 0.45.0", @@ -3547,8 +3544,7 @@ dependencies = [ "pallet-conviction-voting", "pallet-democracy", "pallet-election-provider-multi-phase", - "pallet-election-provider-support-benchmarking", - "pallet-elections-phragmen", + "pallet-elections", "pallet-fast-unstake", "pallet-glutton", "pallet-grandpa", @@ -4113,9 +4109,9 @@ dependencies = [ [[package]] name = "librocksdb-sys" -version = "0.8.0+7.4.4" +version = "0.8.3+7.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "611804e4666a25136fcc5f8cf425ab4d26c7f74ea245ffe92ea23b85b6420b5d" +checksum = "557b255ff04123fcc176162f56ed0c9cd42d8f357cf55b3fabeb60f7413741b3" dependencies = [ "bindgen", "bzip2-sys", @@ -4374,9 +4370,9 @@ dependencies = [ [[package]] name = "memmap2" -version = "0.5.8" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b182332558b18d807c4ce1ca8ca983b34c3ee32765e47b3f0f69b90355cc1dc" +checksum = "2af2c65375e552a67fe3829ca63e8a7c27a378a62824594f43b2851d682b5ec2" dependencies = [ "libc", ] @@ -4444,14 +4440,14 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" +checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" dependencies = [ "libc", "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.42.0", + "windows-sys 0.45.0", ] [[package]] @@ -4733,7 +4729,7 @@ name = "node-bench" version = "0.9.0-dev" dependencies = [ "array-bytes", - "clap 4.1.4", + "clap 4.1.6", "derive_more", "fs_extra", "futures", @@ -4770,7 +4766,7 @@ version = "3.0.0-dev" dependencies = [ "array-bytes", "assert_cmd", - "clap 4.1.4", + "clap 4.1.6", "clap_complete", "criterion", "frame-benchmarking-cli", @@ -4890,7 +4886,7 @@ dependencies = [ name = "node-inspect" version = "0.9.0-dev" dependencies = [ - "clap 4.1.4", + "clap 4.1.6", "parity-scale-codec", "sc-cli", "sc-client-api", @@ -4949,7 +4945,7 @@ dependencies = [ name = "node-runtime-generate-bags" version = "3.0.0" dependencies = [ - "clap 4.1.4", + "clap 4.1.6", "generate-bags", "kitchensink-runtime", ] @@ -4958,7 +4954,7 @@ dependencies = [ name = "node-template" version = "4.0.0-dev" dependencies = [ - "clap 4.1.4", + "clap 4.1.6", "frame-benchmarking", "frame-benchmarking-cli", "frame-system", @@ -5214,9 +5210,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.17.0" +version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" [[package]] name = "oorandom" @@ -5722,7 +5718,6 @@ dependencies = [ "frame-system", "log", "pallet-balances", - "pallet-election-provider-support-benchmarking", "parity-scale-codec", "parking_lot 0.12.1", "rand 0.8.5", @@ -5738,22 +5733,11 @@ dependencies = [ ] [[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" +name = "pallet-elections" version = "5.0.0-dev" dependencies = [ "frame-benchmarking", + "frame-election-provider-support", "frame-support", "frame-system", "log", @@ -6793,9 +6777,9 @@ dependencies = [ [[package]] name = "parity-scale-codec" -version = "3.3.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3840933452adf7b3b9145e27086a5a3376c619dca1a21b1e5a5af0d54979bed" +checksum = "637935964ff85a605d114591d4d2c13c5d1ba2806dae97cea6bf180238a749ac" dependencies = [ "arrayvec 0.7.2", "bitvec", @@ -6940,9 +6924,9 @@ checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" [[package]] name = "pest" -version = "2.5.4" +version = "2.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ab62d2fa33726dbe6321cc97ef96d8cde531e3eeaf858a058de53a8a6d40d8f" +checksum = "028accff104c4e513bad663bbcd2ad7cfd5304144404c31ed0a77ac103d00660" dependencies = [ "thiserror", "ucd-trie", @@ -6950,9 +6934,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.5.4" +version = "2.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bf026e2d0581559db66d837fe5242320f525d85c76283c61f4d51a1238d65ea" +checksum = "2ac3922aac69a40733080f53c1ce7f91dcf57e1a5f6c52f421fadec7fbdc4b69" dependencies = [ "pest", "pest_generator", @@ -6960,9 +6944,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.5.4" +version = "2.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b27bd18aa01d91c8ed2b61ea23406a676b42d82609c6e2581fba42f0c15f17f" +checksum = "d06646e185566b5961b4058dd107e0a7f56e77c3f484549fb119867773c0f202" dependencies = [ "pest", "pest_meta", @@ -6973,9 +6957,9 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.5.4" +version = "2.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f02b677c1859756359fc9983c2e56a0237f18624a3789528804406b7e915e5d" +checksum = "e6f60b2ba541577e2a0c307c8f39d1439108120eb7903adeb6497fa880c59616" dependencies = [ "once_cell", "pest", @@ -7547,7 +7531,7 @@ checksum = "6413f3de1edee53342e6138e75b56d32e7bc6e332b3bd62d497b1929d4cfbcdd" dependencies = [ "pem", "ring", - "time 0.3.17", + "time 0.3.19", "x509-parser 0.13.2", "yasna", ] @@ -7560,7 +7544,7 @@ checksum = "ffbe84efe2f38dea12e9bfc1f65377fdf03e53a18cb3b995faedf7934c7e785b" dependencies = [ "pem", "ring", - "time 0.3.17", + "time 0.3.19", "yasna", ] @@ -8034,7 +8018,7 @@ version = "0.10.0-dev" dependencies = [ "array-bytes", "chrono", - "clap 4.1.4", + "clap 4.1.6", "fdlimit", "futures", "futures-timer", @@ -9069,7 +9053,7 @@ dependencies = [ name = "sc-storage-monitor" version = "0.1.0" dependencies = [ - "clap 4.1.4", + "clap 4.1.6", "futures", "log", "nix 0.26.2", @@ -9465,9 +9449,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.92" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7434af0dc1cbd59268aa98b4c22c131c0584d2232f6fb166efb993e2832e896a" +checksum = "cad406b69c91885b5107daf2c29572f6c8cdb3c66826821e286c533490c0bc76" dependencies = [ "itoa", "ryu", @@ -9550,9 +9534,9 @@ checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" [[package]] name = "signal-hook-registry" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" dependencies = [ "libc", ] @@ -9582,9 +9566,9 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" dependencies = [ "autocfg", ] @@ -10128,7 +10112,7 @@ dependencies = [ name = "sp-npos-elections-fuzzer" version = "2.0.0-alpha.5" dependencies = [ - "clap 4.1.4", + "clap 4.1.6", "honggfuzz", "parity-scale-codec", "rand 0.8.5", @@ -10485,9 +10469,9 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" [[package]] name = "spin" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f6002a767bff9e83f8eeecf883ecb8011875a21ae8da43bffb817a57e78cc09" +checksum = "7dccf47db1b41fa1573ed27ccf5e08e3ca771cb994f776668c5ebda893b248fc" [[package]] name = "spki" @@ -10605,7 +10589,7 @@ dependencies = [ name = "subkey" version = "3.0.0" dependencies = [ - "clap 4.1.4", + "clap 4.1.6", "sc-cli", ] @@ -10633,7 +10617,7 @@ dependencies = [ name = "substrate-frame-cli" version = "4.0.0-dev" dependencies = [ - "clap 4.1.4", + "clap 4.1.6", "frame-support", "frame-system", "sc-cli", @@ -10943,9 +10927,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "target-lexicon" -version = "0.12.5" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9410d0f6853b1d94f0e519fb95df60f29d2c1eff2d921ffdf01a4c8a3b54f12d" +checksum = "8ae9980cab1db3fceee2f6c6f643d5d8de2997c58ee8d25fb0cc8a9e9e7348e5" [[package]] name = "tempfile" @@ -11010,10 +10994,11 @@ checksum = "3bf63baf9f5039dadc247375c29eb13706706cfde997d0330d05aa63a77d8820" [[package]] name = "thread_local" -version = "1.1.4" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" dependencies = [ + "cfg-if", "once_cell", ] @@ -11049,9 +11034,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.17" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376" +checksum = "53250a3b3fed8ff8fd988587d8925d26a83ac3845d9e03b220b37f34c2b8d6c2" dependencies = [ "itoa", "serde", @@ -11067,9 +11052,9 @@ checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" [[package]] name = "time-macros" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d967f99f534ca7e495c575c62638eebc2898a8c84c119b89e250477bc4ba16b2" +checksum = "a460aeb8de6dcb0f381e1ee05f1cd56fcf5a5f6eb8187ff3d8f0b11078d38b7c" dependencies = [ "time-core", ] @@ -11171,9 +11156,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.11" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d660770404473ccd7bc9f8b28494a811bc18542b915c0855c51e8f419d5223ce" +checksum = "8fb52b74f05dbf495a8fba459fdc331812b96aa086d9eb78101fa0d4569c3313" dependencies = [ "futures-core", "pin-project-lite 0.2.9", @@ -11196,9 +11181,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.4" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bb2e075f03b3d66d8d8785356224ba688d2906a371015e225beeb65ca92c740" +checksum = "5427d89453009325de0d8f342c9490009f76e999cb7672d77e46267448f7e6b2" dependencies = [ "bytes", "futures-core", @@ -11470,7 +11455,7 @@ name = "try-runtime-cli" version = "0.10.0-dev" dependencies = [ "async-trait", - "clap 4.1.4", + "clap 4.1.6", "frame-remote-externalities", "frame-try-runtime", "hex", @@ -11815,9 +11800,9 @@ checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" [[package]] name = "wasm-encoder" -version = "0.22.1" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a584273ccc2d9311f1dd19dc3fb26054661fa3e373d53ede5d1144ba07a9acd" +checksum = "704553b4d614a47080b4a457a976b3c16174b19ce95b931b847561b590dd09ba" dependencies = [ "leb128", ] @@ -11913,7 +11898,7 @@ version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01bf50edb2ea9d922aa75a7bf3c15e26a6c9e2d18c56e862b49737a582901729" dependencies = [ - "spin 0.9.4", + "spin 0.9.5", "wasmi_arena", "wasmi_core 0.5.0", "wasmparser-nostd", @@ -12158,9 +12143,9 @@ dependencies = [ [[package]] name = "wast" -version = "52.0.3" +version = "54.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15942180f265280eede7bc38b239e9770031d1821c02d905284216c645316430" +checksum = "f0d3df4a63b10958fe98ab9d7e9a57a7bc900209d2b4edd10535bfb0703e6516" dependencies = [ "leb128", "memchr", @@ -12170,9 +12155,9 @@ dependencies = [ [[package]] name = "wat" -version = "1.0.57" +version = "1.0.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37212100d4cbe6f0f6ff6e707f1e5a5b5b675f0451231ed9e4235e234e127ed3" +checksum = "3e9a7c7d177696d0548178c36e377d49eba54170e885801d4270e2d44e82ac84" dependencies = [ "wast", ] @@ -12242,7 +12227,7 @@ dependencies = [ "sha2 0.10.6", "stun", "thiserror", - "time 0.3.17", + "time 0.3.19", "tokio", "turn", "url", @@ -12315,9 +12300,9 @@ dependencies = [ [[package]] name = "webrtc-ice" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "494483fbb2f5492620871fdc78b084aed8807377f6e3fe88b2e49f0a9c9c41d7" +checksum = "465a03cc11e9a7d7b4f9f99870558fe37a102b65b93f8045392fef7c67b39e80" dependencies = [ "arc-swap", "async-trait", @@ -12675,7 +12660,7 @@ dependencies = [ "ring", "rusticata-macros", "thiserror", - "time 0.3.17", + "time 0.3.19", ] [[package]] @@ -12693,7 +12678,7 @@ dependencies = [ "oid-registry 0.6.1", "rusticata-macros", "thiserror", - "time 0.3.17", + "time 0.3.19", ] [[package]] @@ -12722,7 +12707,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aed2e7a52e3744ab4d0c05c20aa065258e84c49fd4226f5191b2ed29712710b4" dependencies = [ - "time 0.3.17", + "time 0.3.19", ] [[package]] @@ -12767,9 +12752,9 @@ dependencies = [ [[package]] name = "zstd-sys" -version = "2.0.6+zstd.1.5.2" +version = "2.0.7+zstd.1.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68a3f9792c0c3dc6c165840a75f47ae1f4da402c2d006881129579f6597e801b" +checksum = "94509c3ba2fe55294d752b79842c530ccfab760192521df74a081a78d2b3c7f5" dependencies = [ "cc", "libc", diff --git a/Cargo.toml b/Cargo.toml index 89a52fd16cde8..2ae924bf6e1eb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -97,10 +97,9 @@ members = [ "frame/democracy", "frame/fast-unstake", "frame/try-runtime", - "frame/elections-phragmen", + "frame/elections", "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 37a99414b5dce..d7b42efd4d2d6 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -66,8 +66,7 @@ pallet-contracts-primitives = { version = "7.0.0", default-features = false, pat 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-elections = { version = "5.0.0-dev", default-features = false, path = "../../../frame/elections" } pallet-fast-unstake = { version = "4.0.0-dev", default-features = false, path = "../../../frame/fast-unstake" } 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" } @@ -124,7 +123,6 @@ with-tracing = ["frame-executive/with-tracing"] 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", @@ -145,7 +143,7 @@ std = [ "pallet-contracts-primitives/std", "pallet-conviction-voting/std", "pallet-democracy/std", - "pallet-elections-phragmen/std", + "pallet-elections/std", "pallet-fast-unstake/std", "frame-executive/std", "pallet-nis/std", @@ -218,6 +216,7 @@ runtime-benchmarks = [ "frame-benchmarking-pallet-pov/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", + "frame-election-provider-support/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "pallet-alliance/runtime-benchmarks", "pallet-assets/runtime-benchmarks", @@ -231,8 +230,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-elections/runtime-benchmarks", "pallet-fast-unstake/runtime-benchmarks", "pallet-nis/runtime-benchmarks", "pallet-grandpa/runtime-benchmarks", @@ -289,7 +287,7 @@ try-runtime = [ "pallet-conviction-voting/try-runtime", "pallet-democracy/try-runtime", "pallet-election-provider-multi-phase/try-runtime", - "pallet-elections-phragmen/try-runtime", + "pallet-elections/try-runtime", "pallet-fast-unstake/try-runtime", "pallet-nis/try-runtime", "pallet-grandpa/try-runtime", diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index e02792b95275a..1ed43c211f8a1 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -24,7 +24,8 @@ use codec::{Decode, Encode, MaxEncodedLen}; use frame_election_provider_support::{ - onchain, BalancingConfig, ElectionDataProvider, SequentialPhragmen, VoteWeight, + onchain, weights::SubstrateWeight, ApprovalVoting, BalancingConfig, ElectionDataProvider, + SequentialPhragmen, VoteWeight, }; use frame_support::{ construct_runtime, @@ -1010,18 +1011,21 @@ parameter_types! { pub const TermDuration: BlockNumber = 7 * DAYS; pub const DesiredMembers: u32 = 13; pub const DesiredRunnersUp: u32 = 7; - pub const MaxVotesPerVoter: u32 = 16; pub const MaxVoters: u32 = 512; pub const MaxCandidates: u32 = 64; - pub const ElectionsPhragmenPalletId: LockIdentifier = *b"phrelect"; + pub const MaxVotesPerVoter: u32 = 16; + // The ElectionsPalletId parameter name was changed along with the renaming of the elections + // pallet, but we keep the same lock ID to prevent a migration from current runtimes. + // Related to https://github.com/paritytech/substrate/issues/8250 + pub const ElectionsPalletId: LockIdentifier = *b"phrelect"; } // Make sure that there are no more than `MaxMembers` members elected via elections-phragmen. const_assert!(DesiredMembers::get() <= CouncilMaxMembers::get()); -impl pallet_elections_phragmen::Config for Runtime { +impl pallet_elections::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type PalletId = ElectionsPhragmenPalletId; + type PalletId = ElectionsPalletId; type Currency = Balances; type ChangeMembers = Council; // NOTE: this implies that council's genesis members cannot be set directly and must come from @@ -1039,7 +1043,9 @@ impl pallet_elections_phragmen::Config for Runtime { type MaxVoters = MaxVoters; type MaxVotesPerVoter = MaxVotesPerVoter; type MaxCandidates = MaxCandidates; - type WeightInfo = pallet_elections_phragmen::weights::SubstrateWeight; + type ElectionSolver = ApprovalVoting; + type SolverWeightInfo = SubstrateWeight; + type WeightInfo = pallet_elections::weights::SubstrateWeight; } parameter_types! { @@ -1737,7 +1743,7 @@ construct_runtime!( Democracy: pallet_democracy, Council: pallet_collective::, TechnicalCommittee: pallet_collective::, - Elections: pallet_elections_phragmen, + Elections: pallet_elections, TechnicalMembership: pallet_membership::, Grandpa: pallet_grandpa, Treasury: pallet_treasury, @@ -1851,6 +1857,7 @@ mod benches { frame_benchmarking::define_benchmarks!( [frame_benchmarking, BaselineBench::] [frame_benchmarking_pallet_pov, Pov] + [frame_election_provider_support, EPSBench::] [pallet_alliance, Alliance] [pallet_assets, Assets] [pallet_babe, Babe] @@ -1863,8 +1870,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_elections, Elections] [pallet_fast_unstake, FastUnstake] [pallet_nis, Nis] [pallet_grandpa, Grandpa] @@ -2279,7 +2285,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_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; @@ -2302,14 +2308,14 @@ 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_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_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 {} diff --git a/frame/election-provider-multi-phase/Cargo.toml b/frame/election-provider-multi-phase/Cargo.toml index aa734850aae43..996f40febdeba 100644 --- a/frame/election-provider-multi-phase/Cargo.toml +++ b/frame/election-provider-multi-phase/Cargo.toml @@ -33,7 +33,6 @@ 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.8.5", default-features = false, features = ["alloc", "small_rng"], optional = true } strum = { version = "0.24.1", default-features = false, features = ["derive"], optional = true } @@ -50,7 +49,6 @@ 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", diff --git a/frame/election-provider-support/Cargo.toml b/frame/election-provider-support/Cargo.toml index 114caee793f1a..f9cb5233ced22 100644 --- a/frame/election-provider-support/Cargo.toml +++ b/frame/election-provider-support/Cargo.toml @@ -23,6 +23,8 @@ sp-runtime = { version = "7.0.0", default-features = false, path = "../../primit sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } sp-core = { version = "7.0.0", default-features = false, path = "../../primitives/core" } +frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } + [dev-dependencies] rand = { version = "0.8.5", features = ["small_rng"] } sp-io = { version = "7.0.0", path = "../../primitives/io" } @@ -41,6 +43,10 @@ std = [ "sp-core/std", "sp-runtime/std", "sp-std/std", + + "frame-benchmarking?/std", +] +runtime-benchmarks = [ + "frame-benchmarking/runtime-benchmarks", ] -runtime-benchmarks = [] try-runtime = [] diff --git a/frame/election-provider-support/benchmarking/Cargo.toml b/frame/election-provider-support/benchmarking/Cargo.toml deleted file mode 100644 index bef371ec5efbf..0000000000000 --- a/frame/election-provider-support/benchmarking/Cargo.toml +++ /dev/null @@ -1,37 +0,0 @@ -[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.2.2", 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 = "7.0.0", default-features = false, path = "../../../primitives/runtime" } - -[features] -default = ["std"] -std = [ - "codec/std", - "frame-benchmarking?/std", - "frame-election-provider-support/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/election-provider-support/benchmarking/src/lib.rs b/frame/election-provider-support/src/benchmarking.rs similarity index 86% rename from frame/election-provider-support/benchmarking/src/lib.rs rename to frame/election-provider-support/src/benchmarking.rs index 774b7036fd413..5c5b952b6dcc9 100644 --- a/frame/election-provider-support/benchmarking/src/lib.rs +++ b/frame/election-provider-support/src/benchmarking.rs @@ -18,12 +18,9 @@ //! 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 crate::{ApprovalVoting, NposSolver, PhragMMS, SequentialPhragmen}; use codec::Decode; use frame_benchmarking::v1::{benchmarks, Vec}; -use frame_election_provider_support::{NposSolver, PhragMMS, SequentialPhragmen}; pub struct Pallet(frame_system::Pallet); pub trait Config: frame_system::Config {} @@ -88,4 +85,17 @@ benchmarks! { ::solve(d as usize, targets, voters).is_ok() ); } + + approval_voting { + let v in (VOTERS[0]) .. VOTERS[1]; + let t in (TARGETS[0]) .. TARGETS[1]; + let d in (VOTES_PER_VOTER[0]) .. VOTES_PER_VOTER[1]; + + let (voters, targets) = set_up_voters_targets::(v, t, d as usize); + }: { + assert!( + ApprovalVoting:: + ::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 750ccca46213f..423ce3d67e8cb 100644 --- a/frame/election-provider-support/src/lib.rs +++ b/frame/election-provider-support/src/lib.rs @@ -199,6 +199,9 @@ pub use sp_arithmetic; #[doc(hidden)] pub use sp_std; +#[cfg(feature = "runtime-benchmarks")] +pub mod benchmarking; + pub mod weights; pub use weights::WeightInfo; @@ -660,6 +663,29 @@ impl(sp_std::marker::PhantomData<(AccountId, Accuracy)>); + +impl NposSolver + for ApprovalVoting +{ + type AccountId = AccountId; + type Accuracy = Accuracy; + type Error = sp_npos_elections::Error; + fn solve( + winners: usize, + targets: Vec, + voters: Vec<(Self::AccountId, VoteWeight, impl IntoIterator)>, + ) -> Result, Self::Error> { + sp_npos_elections::approval_voting(winners, targets, voters) + } + + fn weight(voters: u32, targets: u32, vote_degree: u32) -> Weight { + T::approval_voting(voters, targets, vote_degree) + } +} + /// A voter, at the level of abstraction of this crate. pub type Voter = (AccountId, VoteWeight, BoundedVec); diff --git a/frame/election-provider-support/src/onchain.rs b/frame/election-provider-support/src/onchain.rs index 296ac976d59f3..60c7853c794dc 100644 --- a/frame/election-provider-support/src/onchain.rs +++ b/frame/election-provider-support/src/onchain.rs @@ -185,7 +185,7 @@ impl ElectionProvider for OnChainExecution { #[cfg(test)] mod tests { use super::*; - use crate::{ElectionProvider, PhragMMS, SequentialPhragmen}; + use crate::{ApprovalVoting, ElectionProvider, PhragMMS, SequentialPhragmen}; use frame_support::{assert_noop, parameter_types, traits::ConstU32}; use sp_npos_elections::Support; use sp_runtime::Perbill; @@ -235,6 +235,7 @@ mod tests { struct PhragmenParams; struct PhragMMSParams; + struct ApprovalVotingParams; parameter_types! { pub static MaxWinners: u32 = 10; @@ -261,6 +262,16 @@ mod tests { type TargetsBound = ConstU32<400>; } + impl Config for ApprovalVotingParams { + type System = Runtime; + type Solver = ApprovalVoting; + type DataProvider = mock_data_provider::DataProvider; + type WeightInfo = (); + type MaxWinners = MaxWinners; + type VotersBound = ConstU32<600>; + type TargetsBound = ConstU32<400>; + } + mod mock_data_provider { use frame_support::{bounded_vec, traits::ConstU32}; @@ -333,4 +344,21 @@ mod tests { ); }) } + + #[test] + fn onchain_approval_voting_works() { + sp_io::TestExternalities::new_empty().execute_with(|| { + DesiredTargets::set(3); + + // note that the `OnChainExecution::elect` implementation normalizes the vote weights. + assert_eq!( + as ElectionProvider>::elect().unwrap(), + vec![ + (10, Support { total: 20, voters: vec![(1, 5), (3, 15)] }), + (20, Support { total: 15, voters: vec![(1, 5), (2, 10)] }), + (30, Support { total: 25, voters: vec![(2, 10), (3, 15)] }) + ] + ) + }) + } } diff --git a/frame/election-provider-support/src/weights.rs b/frame/election-provider-support/src/weights.rs index fd4db1374ac4a..c28794267c640 100644 --- a/frame/election-provider-support/src/weights.rs +++ b/frame/election-provider-support/src/weights.rs @@ -1,13 +1,13 @@ // This file is part of Substrate. -// Copyright (C) Parity Technologies (UK) Ltd. +// Copyright (C) 2023 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -15,25 +15,29 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for pallet_election_provider_support_benchmarking +//! Autogenerated weights for frame_election_provider_support //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-04-23, STEPS: `1`, REPEAT: 1, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-02-22, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-ehxwxxsd-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! 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=1 -// --repeat=1 -// --pallet=pallet_election_provider_support_benchmarking +// --steps=50 +// --repeat=20 // --extrinsic=* // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=frame/election-provider-support/src/weights.rs +// --json-file=/builds/parity/mirrors/substrate/.git/.artifacts/bench.json +// --pallet=frame_election_provider_support +// --chain=dev +// --header=./HEADER-APACHE2 +// --output=./frame/election-provider-support/src/weights.rs // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -43,53 +47,108 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; -/// Weight functions needed for pallet_election_provider_support_benchmarking. +/// Weight functions needed for frame_election_provider_support. pub trait WeightInfo { fn phragmen(v: u32, t: u32, d: u32, ) -> Weight; fn phragmms(v: u32, t: u32, d: u32, ) -> Weight; + fn approval_voting(v: u32, t: u32, d: u32, ) -> Weight; } -/// Weights for pallet_election_provider_support_benchmarking using the Substrate node and recommended hardware. +/// Weights for frame_election_provider_support using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - fn phragmen(v: u32, t: u32, d: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 667_000 - .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 u64).saturating_mul(t as u64)) - // Standard Error: 60_644_000 - .saturating_add(Weight::from_ref_time(2_636_364_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 `d` is `[5, 16]`. + fn phragmen(v: u32, _t: u32, d: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 5_789_174 nanoseconds. + Weight::from_ref_time(5_826_449_000) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 130_342 + .saturating_add(Weight::from_ref_time(5_332_741).saturating_mul(v.into())) + // Standard Error: 13_325_769 + .saturating_add(Weight::from_ref_time(1_416_874_101).saturating_mul(d.into())) } - fn phragmms(v: u32, t: u32, d: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 73_000 - .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 u64).saturating_mul(t as u64)) - // Standard Error: 6_649_000 - .saturating_add(Weight::from_ref_time(1_711_424_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 `d` is `[5, 16]`. + fn phragmms(v: u32, _t: u32, d: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 4_151_790 nanoseconds. + Weight::from_ref_time(4_215_936_000) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 125_135 + .saturating_add(Weight::from_ref_time(4_730_609).saturating_mul(v.into())) + // Standard Error: 12_793_390 + .saturating_add(Weight::from_ref_time(1_474_383_961).saturating_mul(d.into())) + } + /// The range of component `v` is `[1000, 2000]`. + /// The range of component `t` is `[500, 1000]`. + /// The range of component `d` is `[5, 16]`. + fn approval_voting(v: u32, _t: u32, d: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_800_445 nanoseconds. + Weight::from_ref_time(1_824_645_000) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 26_266 + .saturating_add(Weight::from_ref_time(1_229_576).saturating_mul(v.into())) + // Standard Error: 2_685_343 + .saturating_add(Weight::from_ref_time(213_080_804).saturating_mul(d.into())) } } // For backwards compatibility and tests impl WeightInfo for () { - fn phragmen(v: u32, t: u32, d: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 667_000 - .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 u64).saturating_mul(t as u64)) - // Standard Error: 60_644_000 - .saturating_add(Weight::from_ref_time(2_636_364_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 `d` is `[5, 16]`. + fn phragmen(v: u32, _t: u32, d: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 5_789_174 nanoseconds. + Weight::from_ref_time(5_826_449_000) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 130_342 + .saturating_add(Weight::from_ref_time(5_332_741).saturating_mul(v.into())) + // Standard Error: 13_325_769 + .saturating_add(Weight::from_ref_time(1_416_874_101).saturating_mul(d.into())) + } + /// The range of component `v` is `[1000, 2000]`. + /// The range of component `t` is `[500, 1000]`. + /// The range of component `d` is `[5, 16]`. + fn phragmms(v: u32, _t: u32, d: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 4_151_790 nanoseconds. + Weight::from_ref_time(4_215_936_000) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 125_135 + .saturating_add(Weight::from_ref_time(4_730_609).saturating_mul(v.into())) + // Standard Error: 12_793_390 + .saturating_add(Weight::from_ref_time(1_474_383_961).saturating_mul(d.into())) } - fn phragmms(v: u32, t: u32, d: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 73_000 - .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 u64).saturating_mul(t as u64)) - // Standard Error: 6_649_000 - .saturating_add(Weight::from_ref_time(1_711_424_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 `d` is `[5, 16]`. + fn approval_voting(v: u32, _t: u32, d: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_800_445 nanoseconds. + Weight::from_ref_time(1_824_645_000) + .saturating_add(Weight::from_proof_size(0)) + // Standard Error: 26_266 + .saturating_add(Weight::from_ref_time(1_229_576).saturating_mul(v.into())) + // Standard Error: 2_685_343 + .saturating_add(Weight::from_ref_time(213_080_804).saturating_mul(d.into())) } } diff --git a/frame/elections-phragmen/src/weights.rs b/frame/elections-phragmen/src/weights.rs deleted file mode 100644 index 24ab3bc15fbcd..0000000000000 --- a/frame/elections-phragmen/src/weights.rs +++ /dev/null @@ -1,559 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Autogenerated weights for pallet_elections_phragmen -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-03, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-b3zmxxc-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 - -// Executed Command: -// target/production/substrate -// benchmark -// pallet -// --steps=50 -// --repeat=20 -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --heap-pages=4096 -// --json-file=/builds/parity/mirrors/substrate/.git/.artifacts/bench.json -// --pallet=pallet_elections_phragmen -// --chain=dev -// --header=./HEADER-APACHE2 -// --output=./frame/elections-phragmen/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_elections_phragmen. -pub trait WeightInfo { - fn vote_equal(v: u32, ) -> Weight; - fn vote_more(v: u32, ) -> Weight; - fn vote_less(v: u32, ) -> Weight; - fn remove_voter() -> Weight; - fn submit_candidacy(c: u32, ) -> Weight; - fn renounce_candidacy_candidate(c: u32, ) -> Weight; - fn renounce_candidacy_members() -> Weight; - fn renounce_candidacy_runners_up() -> Weight; - fn remove_member_without_replacement() -> Weight; - fn remove_member_with_replacement() -> Weight; - fn clean_defunct_voters(v: u32, d: u32, ) -> Weight; - fn election_phragmen(c: u32, v: u32, e: u32, ) -> Weight; -} - -/// Weights for pallet_elections_phragmen using the Substrate node and recommended hardware. -pub struct SubstrateWeight(PhantomData); -impl WeightInfo for SubstrateWeight { - /// Storage: Elections Candidates (r:1 w:0) - /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections Members (r:1 w:0) - /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections RunnersUp (r:1 w:0) - /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections Voting (r:1 w:1) - /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// The range of component `v` is `[1, 16]`. - fn vote_equal(v: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `499 + v * (80 ±0)` - // Estimated: `9726 + v * (320 ±0)` - // Minimum execution time: 27_362 nanoseconds. - Weight::from_parts(28_497_963, 9726) - // Standard Error: 3_968 - .saturating_add(Weight::from_ref_time(176_840).saturating_mul(v.into())) - .saturating_add(T::DbWeight::get().reads(5_u64)) - .saturating_add(T::DbWeight::get().writes(2_u64)) - .saturating_add(Weight::from_proof_size(320).saturating_mul(v.into())) - } - /// Storage: Elections Candidates (r:1 w:0) - /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections Members (r:1 w:0) - /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections RunnersUp (r:1 w:0) - /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections Voting (r:1 w:1) - /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// The range of component `v` is `[2, 16]`. - fn vote_more(v: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `467 + v * (80 ±0)` - // Estimated: `9598 + v * (320 ±0)` - // Minimum execution time: 37_120 nanoseconds. - Weight::from_parts(38_455_302, 9598) - // Standard Error: 5_478 - .saturating_add(Weight::from_ref_time(219_678).saturating_mul(v.into())) - .saturating_add(T::DbWeight::get().reads(5_u64)) - .saturating_add(T::DbWeight::get().writes(2_u64)) - .saturating_add(Weight::from_proof_size(320).saturating_mul(v.into())) - } - /// Storage: Elections Candidates (r:1 w:0) - /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections Members (r:1 w:0) - /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections RunnersUp (r:1 w:0) - /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections Voting (r:1 w:1) - /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// The range of component `v` is `[2, 16]`. - fn vote_less(v: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `499 + v * (80 ±0)` - // Estimated: `9726 + v * (320 ±0)` - // Minimum execution time: 36_928 nanoseconds. - Weight::from_parts(38_334_669, 9726) - // Standard Error: 5_271 - .saturating_add(Weight::from_ref_time(232_355).saturating_mul(v.into())) - .saturating_add(T::DbWeight::get().reads(5_u64)) - .saturating_add(T::DbWeight::get().writes(2_u64)) - .saturating_add(Weight::from_proof_size(320).saturating_mul(v.into())) - } - /// Storage: Elections Voting (r:1 w:1) - /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - fn remove_voter() -> Weight { - // Proof Size summary in bytes: - // Measured: `989` - // Estimated: `7238` - // Minimum execution time: 34_338 nanoseconds. - Weight::from_parts(35_672_000, 7238) - .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(T::DbWeight::get().writes(2_u64)) - } - /// Storage: Elections Candidates (r:1 w:1) - /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections Members (r:1 w:0) - /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections RunnersUp (r:1 w:0) - /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `c` is `[1, 64]`. - fn submit_candidacy(c: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `1697 + c * (48 ±0)` - // Estimated: `6576 + c * (144 ±0)` - // Minimum execution time: 31_864 nanoseconds. - Weight::from_parts(33_490_161, 6576) - // Standard Error: 2_643 - .saturating_add(Weight::from_ref_time(158_386).saturating_mul(c.into())) - .saturating_add(T::DbWeight::get().reads(3_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) - .saturating_add(Weight::from_proof_size(144).saturating_mul(c.into())) - } - /// Storage: Elections Candidates (r:1 w:1) - /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `c` is `[1, 64]`. - fn renounce_candidacy_candidate(c: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `349 + c * (48 ±0)` - // Estimated: `844 + c * (48 ±0)` - // Minimum execution time: 27_292 nanoseconds. - Weight::from_parts(28_364_955, 844) - // Standard Error: 1_335 - .saturating_add(Weight::from_ref_time(78_086).saturating_mul(c.into())) - .saturating_add(T::DbWeight::get().reads(1_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) - .saturating_add(Weight::from_proof_size(48).saturating_mul(c.into())) - } - /// Storage: Elections Members (r:1 w:1) - /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections RunnersUp (r:1 w:1) - /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Prime (r:1 w:1) - /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Proposals (r:1 w:0) - /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Members (r:0 w:1) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - fn renounce_candidacy_members() -> Weight { - // Proof Size summary in bytes: - // Measured: `2027` - // Estimated: `12115` - // Minimum execution time: 45_975 nanoseconds. - Weight::from_parts(47_103_000, 12115) - .saturating_add(T::DbWeight::get().reads(4_u64)) - .saturating_add(T::DbWeight::get().writes(4_u64)) - } - /// Storage: Elections RunnersUp (r:1 w:1) - /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - fn renounce_candidacy_runners_up() -> Weight { - // Proof Size summary in bytes: - // Measured: `975` - // Estimated: `1470` - // Minimum execution time: 29_243 nanoseconds. - Weight::from_parts(30_582_000, 1470) - .saturating_add(T::DbWeight::get().reads(1_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) - } - /// Storage: Benchmark Override (r:0 w:0) - /// Proof Skipped: Benchmark Override (max_values: None, max_size: None, mode: Measured) - fn remove_member_without_replacement() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_000_000_000 nanoseconds. - Weight::from_ref_time(2_000_000_000_000) - } - /// Storage: Elections Members (r:1 w:1) - /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Elections RunnersUp (r:1 w:1) - /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Prime (r:1 w:1) - /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Proposals (r:1 w:0) - /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Members (r:0 w:1) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - fn remove_member_with_replacement() -> Weight { - // Proof Size summary in bytes: - // Measured: `2027` - // Estimated: `14718` - // Minimum execution time: 52_527 nanoseconds. - Weight::from_parts(53_538_000, 14718) - .saturating_add(T::DbWeight::get().reads(5_u64)) - .saturating_add(T::DbWeight::get().writes(5_u64)) - } - /// Storage: Elections Voting (r:513 w:512) - /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Elections Members (r:1 w:0) - /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections RunnersUp (r:1 w:0) - /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections Candidates (r:1 w:0) - /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Balances Locks (r:512 w:512) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: System Account (r:512 w:512) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// The range of component `v` is `[256, 512]`. - /// The range of component `d` is `[0, 256]`. - fn clean_defunct_voters(v: u32, _d: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `1115 + v * (875 ±0)` - // Estimated: `8448 + v * (12352 ±0)` - // Minimum execution time: 14_934_185 nanoseconds. - Weight::from_parts(15_014_057_000, 8448) - // Standard Error: 245_588 - .saturating_add(Weight::from_ref_time(35_586_946).saturating_mul(v.into())) - .saturating_add(T::DbWeight::get().reads(4_u64)) - .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(v.into()))) - .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(v.into()))) - .saturating_add(Weight::from_proof_size(12352).saturating_mul(v.into())) - } - /// Storage: Elections Candidates (r:1 w:1) - /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections Members (r:1 w:1) - /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections RunnersUp (r:1 w:1) - /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections Voting (r:513 w:0) - /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Council Proposals (r:1 w:0) - /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: System Account (r:44 w:44) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Elections ElectionRounds (r:1 w:1) - /// Proof Skipped: Elections ElectionRounds (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Members (r:0 w:1) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Prime (r:0 w:1) - /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `c` is `[1, 64]`. - /// The range of component `v` is `[1, 512]`. - /// The range of component `e` is `[512, 8192]`. - fn election_phragmen(c: u32, v: u32, e: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0 + v * (638 ±0) + e * (28 ±0)` - // Estimated: `330033 + v * (5229 ±6) + e * (89 ±0) + c * (2135 ±7)` - // Minimum execution time: 1_273_671 nanoseconds. - Weight::from_parts(1_279_716_000, 330033) - // Standard Error: 543_277 - .saturating_add(Weight::from_ref_time(20_613_753).saturating_mul(v.into())) - // Standard Error: 34_857 - .saturating_add(Weight::from_ref_time(688_354).saturating_mul(e.into())) - .saturating_add(T::DbWeight::get().reads(21_u64)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(c.into()))) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) - .saturating_add(T::DbWeight::get().writes(6_u64)) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(c.into()))) - .saturating_add(Weight::from_proof_size(5229).saturating_mul(v.into())) - .saturating_add(Weight::from_proof_size(89).saturating_mul(e.into())) - .saturating_add(Weight::from_proof_size(2135).saturating_mul(c.into())) - } -} - -// For backwards compatibility and tests -impl WeightInfo for () { - /// Storage: Elections Candidates (r:1 w:0) - /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections Members (r:1 w:0) - /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections RunnersUp (r:1 w:0) - /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections Voting (r:1 w:1) - /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// The range of component `v` is `[1, 16]`. - fn vote_equal(v: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `499 + v * (80 ±0)` - // Estimated: `9726 + v * (320 ±0)` - // Minimum execution time: 27_362 nanoseconds. - Weight::from_parts(28_497_963, 9726) - // Standard Error: 3_968 - .saturating_add(Weight::from_ref_time(176_840).saturating_mul(v.into())) - .saturating_add(RocksDbWeight::get().reads(5_u64)) - .saturating_add(RocksDbWeight::get().writes(2_u64)) - .saturating_add(Weight::from_proof_size(320).saturating_mul(v.into())) - } - /// Storage: Elections Candidates (r:1 w:0) - /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections Members (r:1 w:0) - /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections RunnersUp (r:1 w:0) - /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections Voting (r:1 w:1) - /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// The range of component `v` is `[2, 16]`. - fn vote_more(v: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `467 + v * (80 ±0)` - // Estimated: `9598 + v * (320 ±0)` - // Minimum execution time: 37_120 nanoseconds. - Weight::from_parts(38_455_302, 9598) - // Standard Error: 5_478 - .saturating_add(Weight::from_ref_time(219_678).saturating_mul(v.into())) - .saturating_add(RocksDbWeight::get().reads(5_u64)) - .saturating_add(RocksDbWeight::get().writes(2_u64)) - .saturating_add(Weight::from_proof_size(320).saturating_mul(v.into())) - } - /// Storage: Elections Candidates (r:1 w:0) - /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections Members (r:1 w:0) - /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections RunnersUp (r:1 w:0) - /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections Voting (r:1 w:1) - /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// The range of component `v` is `[2, 16]`. - fn vote_less(v: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `499 + v * (80 ±0)` - // Estimated: `9726 + v * (320 ±0)` - // Minimum execution time: 36_928 nanoseconds. - Weight::from_parts(38_334_669, 9726) - // Standard Error: 5_271 - .saturating_add(Weight::from_ref_time(232_355).saturating_mul(v.into())) - .saturating_add(RocksDbWeight::get().reads(5_u64)) - .saturating_add(RocksDbWeight::get().writes(2_u64)) - .saturating_add(Weight::from_proof_size(320).saturating_mul(v.into())) - } - /// Storage: Elections Voting (r:1 w:1) - /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - fn remove_voter() -> Weight { - // Proof Size summary in bytes: - // Measured: `989` - // Estimated: `7238` - // Minimum execution time: 34_338 nanoseconds. - Weight::from_parts(35_672_000, 7238) - .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(RocksDbWeight::get().writes(2_u64)) - } - /// Storage: Elections Candidates (r:1 w:1) - /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections Members (r:1 w:0) - /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections RunnersUp (r:1 w:0) - /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `c` is `[1, 64]`. - fn submit_candidacy(c: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `1697 + c * (48 ±0)` - // Estimated: `6576 + c * (144 ±0)` - // Minimum execution time: 31_864 nanoseconds. - Weight::from_parts(33_490_161, 6576) - // Standard Error: 2_643 - .saturating_add(Weight::from_ref_time(158_386).saturating_mul(c.into())) - .saturating_add(RocksDbWeight::get().reads(3_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) - .saturating_add(Weight::from_proof_size(144).saturating_mul(c.into())) - } - /// Storage: Elections Candidates (r:1 w:1) - /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `c` is `[1, 64]`. - fn renounce_candidacy_candidate(c: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `349 + c * (48 ±0)` - // Estimated: `844 + c * (48 ±0)` - // Minimum execution time: 27_292 nanoseconds. - Weight::from_parts(28_364_955, 844) - // Standard Error: 1_335 - .saturating_add(Weight::from_ref_time(78_086).saturating_mul(c.into())) - .saturating_add(RocksDbWeight::get().reads(1_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) - .saturating_add(Weight::from_proof_size(48).saturating_mul(c.into())) - } - /// Storage: Elections Members (r:1 w:1) - /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections RunnersUp (r:1 w:1) - /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Prime (r:1 w:1) - /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Proposals (r:1 w:0) - /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Members (r:0 w:1) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - fn renounce_candidacy_members() -> Weight { - // Proof Size summary in bytes: - // Measured: `2027` - // Estimated: `12115` - // Minimum execution time: 45_975 nanoseconds. - Weight::from_parts(47_103_000, 12115) - .saturating_add(RocksDbWeight::get().reads(4_u64)) - .saturating_add(RocksDbWeight::get().writes(4_u64)) - } - /// Storage: Elections RunnersUp (r:1 w:1) - /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - fn renounce_candidacy_runners_up() -> Weight { - // Proof Size summary in bytes: - // Measured: `975` - // Estimated: `1470` - // Minimum execution time: 29_243 nanoseconds. - Weight::from_parts(30_582_000, 1470) - .saturating_add(RocksDbWeight::get().reads(1_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) - } - /// Storage: Benchmark Override (r:0 w:0) - /// Proof Skipped: Benchmark Override (max_values: None, max_size: None, mode: Measured) - fn remove_member_without_replacement() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_000_000_000 nanoseconds. - Weight::from_ref_time(2_000_000_000_000) - } - /// Storage: Elections Members (r:1 w:1) - /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Elections RunnersUp (r:1 w:1) - /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Prime (r:1 w:1) - /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Proposals (r:1 w:0) - /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Members (r:0 w:1) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - fn remove_member_with_replacement() -> Weight { - // Proof Size summary in bytes: - // Measured: `2027` - // Estimated: `14718` - // Minimum execution time: 52_527 nanoseconds. - Weight::from_parts(53_538_000, 14718) - .saturating_add(RocksDbWeight::get().reads(5_u64)) - .saturating_add(RocksDbWeight::get().writes(5_u64)) - } - /// Storage: Elections Voting (r:513 w:512) - /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Elections Members (r:1 w:0) - /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections RunnersUp (r:1 w:0) - /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections Candidates (r:1 w:0) - /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Balances Locks (r:512 w:512) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: System Account (r:512 w:512) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// The range of component `v` is `[256, 512]`. - /// The range of component `d` is `[0, 256]`. - fn clean_defunct_voters(v: u32, _d: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `1115 + v * (875 ±0)` - // Estimated: `8448 + v * (12352 ±0)` - // Minimum execution time: 14_934_185 nanoseconds. - Weight::from_parts(15_014_057_000, 8448) - // Standard Error: 245_588 - .saturating_add(Weight::from_ref_time(35_586_946).saturating_mul(v.into())) - .saturating_add(RocksDbWeight::get().reads(4_u64)) - .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(v.into()))) - .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(v.into()))) - .saturating_add(Weight::from_proof_size(12352).saturating_mul(v.into())) - } - /// Storage: Elections Candidates (r:1 w:1) - /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections Members (r:1 w:1) - /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections RunnersUp (r:1 w:1) - /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections Voting (r:513 w:0) - /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) - /// Storage: Council Proposals (r:1 w:0) - /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: System Account (r:44 w:44) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Elections ElectionRounds (r:1 w:1) - /// Proof Skipped: Elections ElectionRounds (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Members (r:0 w:1) - /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Council Prime (r:0 w:1) - /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `c` is `[1, 64]`. - /// The range of component `v` is `[1, 512]`. - /// The range of component `e` is `[512, 8192]`. - fn election_phragmen(c: u32, v: u32, e: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0 + v * (638 ±0) + e * (28 ±0)` - // Estimated: `330033 + v * (5229 ±6) + e * (89 ±0) + c * (2135 ±7)` - // Minimum execution time: 1_273_671 nanoseconds. - Weight::from_parts(1_279_716_000, 330033) - // Standard Error: 543_277 - .saturating_add(Weight::from_ref_time(20_613_753).saturating_mul(v.into())) - // Standard Error: 34_857 - .saturating_add(Weight::from_ref_time(688_354).saturating_mul(e.into())) - .saturating_add(RocksDbWeight::get().reads(21_u64)) - .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(c.into()))) - .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(v.into()))) - .saturating_add(RocksDbWeight::get().writes(6_u64)) - .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(c.into()))) - .saturating_add(Weight::from_proof_size(5229).saturating_mul(v.into())) - .saturating_add(Weight::from_proof_size(89).saturating_mul(e.into())) - .saturating_add(Weight::from_proof_size(2135).saturating_mul(c.into())) - } -} diff --git a/frame/elections-phragmen/CHANGELOG.md b/frame/elections/CHANGELOG.md similarity index 80% rename from frame/elections-phragmen/CHANGELOG.md rename to frame/elections/CHANGELOG.md index 231de1d2e475e..b173557be6feb 100644 --- a/frame/elections-phragmen/CHANGELOG.md +++ b/frame/elections/CHANGELOG.md @@ -4,6 +4,17 @@ All notable changes to this crate will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this crate adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [5.0.0] - UNRELEASED + +### Added + +### Changed +Generalized the pallet to use `NposSolver` instead of hard coding the phragmen algorithm; Changed the name of the pallet from `pallet-elections-phragmen` to `pallet-elections` + +### Fixed + +### Security + ## [4.0.0] - UNRELEASED ### Added diff --git a/frame/elections-phragmen/Cargo.toml b/frame/elections/Cargo.toml similarity index 90% rename from frame/elections-phragmen/Cargo.toml rename to frame/elections/Cargo.toml index ce39e42b8eeb5..14d07eca7dde7 100644 --- a/frame/elections-phragmen/Cargo.toml +++ b/frame/elections/Cargo.toml @@ -1,12 +1,12 @@ [package] -name = "pallet-elections-phragmen" +name = "pallet-elections" version = "5.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 based on seq-Phragmén election method." +description = "FRAME pallet for generic elections." readme = "README.md" [package.metadata.docs.rs] @@ -24,6 +24,7 @@ frame-system = { version = "4.0.0-dev", default-features = false, path = "../sys 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" } +frame-election-provider-support = { version = "4.0.0-dev", default-features = false, path = "../election-provider-support" } 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/frame/elections-phragmen/README.md b/frame/elections/README.md similarity index 94% rename from frame/elections-phragmen/README.md rename to frame/elections/README.md index 26b3f260da563..0f27bdd189110 100644 --- a/frame/elections-phragmen/README.md +++ b/frame/elections/README.md @@ -1,6 +1,6 @@ -# Phragmén Election Module. +# Generic Elections Module. -An election module based on sequential phragmen. +A generic elections module. ### Term and Round @@ -60,7 +60,7 @@ being re-elected at the end of each round. ### Module Information -- [`election_sp_phragmen::Config`](https://docs.rs/pallet-elections-phragmen/latest/pallet_elections_phragmen/trait.Config.html) +- [`elections::Config`](https://docs.rs/pallet-elections-phragmen/latest/pallet_elections_phragmen/trait.Config.html) - [`Call`](https://docs.rs/pallet-elections-phragmen/latest/pallet_elections_phragmen/enum.Call.html) - [`Module`](https://docs.rs/pallet-elections-phragmen/latest/pallet_elections_phragmen/struct.Module.html) diff --git a/frame/elections-phragmen/src/benchmarking.rs b/frame/elections/src/benchmarking.rs similarity index 85% rename from frame/elections-phragmen/src/benchmarking.rs rename to frame/elections/src/benchmarking.rs index 56ea19578c8f5..da755fe9b56c4 100644 --- a/frame/elections-phragmen/src/benchmarking.rs +++ b/frame/elections/src/benchmarking.rs @@ -15,14 +15,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Elections-Phragmen pallet benchmarking. +//! Elections pallet benchmarking. #![cfg(feature = "runtime-benchmarks")] use super::*; use frame_benchmarking::v1::{account, benchmarks, whitelist, BenchmarkError, BenchmarkResult}; -use frame_support::{dispatch::DispatchResultWithPostInfo, traits::OnInitialize}; +use frame_support::dispatch::DispatchResultWithPostInfo; use frame_system::RawOrigin; use crate::Pallet as Elections; @@ -37,7 +37,7 @@ fn endowed_account(name: &'static str, index: u32) -> T::AccountId { 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. + // the election to work. T::Currency::issue(amount); account @@ -122,7 +122,7 @@ fn distribute_voters( fn fill_seats_up_to(m: u32) -> Result, &'static str> { let _ = submit_candidates_with_self_vote::(m, "fill_seats_up_to")?; assert_eq!(>::candidates().len() as u32, m, "wrong number of candidates."); - >::do_phragmen(); + >::do_election(); assert_eq!(>::candidates().len(), 0, "some candidates remaining."); assert_eq!( >::members().len() + >::runners_up().len(), @@ -382,11 +382,11 @@ benchmarks! { assert_eq!(>::iter().count() as u32, 0); } - election_phragmen { - // This is just to focus on phragmen in the context of this module. We always select 20 - // 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. + pre_solve_election { + // We always select 20 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 .. T::MaxCandidates::get(); let v in 1 .. T::MaxVoters::get(); let e in (T::MaxVoters::get()) .. T::MaxVoters::get() * T::MaxVotesPerVoter::get(); @@ -404,7 +404,44 @@ benchmarks! { let all_candidates = submit_candidates_with_self_vote::(c, "candidates")?; let _ = distribute_voters::(all_candidates, v.saturating_sub(c), votes_per_voter as usize)?; }: { - >::on_initialize(T::TermDuration::get()); + >::do_pre_solve_election().unwrap(); + } + + post_solve_election { + // We always select 20 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 .. T::MaxCandidates::get(); + let v in 1 .. T::MaxVoters::get(); + let e in (T::MaxVoters::get()) .. T::MaxVoters::get() as u32 * T::MaxVotesPerVoter::get() as u32; + clean::(); + + // so we have a situation with v and e. we want e to basically always be in the range of `e + // -> e * T::MaxVotesPerVoter`, but we cannot express that now with the benchmarks. So what we do + // is: when c is being iterated, v, and e are max and fine. when v is being iterated, e is + // being set to max and this is a problem. In these cases, we cap e to a lower value, namely + // v * `T::MaxVotesPerVoter`. when e is being iterated, v is at max, and again fine. all in all, + // votes_per_voter can never be more than `T::MaxVotesPerVoter`. Note that this might cause `v` to be + // an overestimate. + let votes_per_voter = (e / v).min(T::MaxVotesPerVoter::get() as u32); + + let all_candidates = submit_candidates_with_self_vote::(c, "candidates")?; + let _ = distribute_voters::(all_candidates, v.saturating_sub(c), votes_per_voter as usize)?; + + let pre_election_result = >::do_pre_solve_election().unwrap(); + let election_result = T::ElectionSolver::solve( + pre_election_result.num_to_elect, + pre_election_result.candidate_ids, + pre_election_result.voters_and_votes, + ).unwrap(); + + }: { + >::do_post_solve_election( + election_result.winners, + pre_election_result.candidates_and_deposit, + pre_election_result.voters_and_stakes, + ); } verify { assert_eq!(>::members().len() as u32, T::DesiredMembers::get().min(c)); diff --git a/frame/elections-phragmen/src/lib.rs b/frame/elections/src/lib.rs similarity index 90% rename from frame/elections-phragmen/src/lib.rs rename to frame/elections/src/lib.rs index fa63762c5e09a..bdf0161ba8ea0 100644 --- a/frame/elections-phragmen/src/lib.rs +++ b/frame/elections/src/lib.rs @@ -15,9 +15,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! # Phragmén Election Module. +//! # Generic Election Module. //! -//! An election module based on sequential phragmen. +//! An election module based on a generic election algorithm. //! //! ### Term and Round //! @@ -99,6 +99,7 @@ #![cfg_attr(not(feature = "std"), no_std)] use codec::{Decode, Encode}; +use frame_election_provider_support::NposSolver; use frame_support::{ traits::{ defensive_prelude::*, ChangeMembers, Contains, ContainsLengthBound, Currency, @@ -108,12 +109,12 @@ use frame_support::{ weights::Weight, }; use scale_info::TypeInfo; -use sp_npos_elections::{ElectionResult, ExtendedBalance}; +use sp_npos_elections::{ElectionResult, ExtendedBalance, VoteWeight}; use sp_runtime::{ traits::{Saturating, StaticLookup, Zero}, - DispatchError, Perbill, RuntimeDebug, + DispatchError, RuntimeDebug, }; -use sp_std::{cmp::Ordering, prelude::*}; +use sp_std::{cmp::Ordering, iter::IntoIterator, prelude::*}; mod benchmarking; pub mod weights; @@ -122,7 +123,17 @@ pub use weights::WeightInfo; /// All migrations. pub mod migrations; -const LOG_TARGET: &str = "runtime::elections-phragmen"; +pub(crate) const LOG_TARGET: &str = "runtime::elections"; + +// logging helper. +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; @@ -173,6 +184,17 @@ pub struct SeatHolder { pub deposit: Balance, } +/// The results of running the pre-election step. +#[derive(Debug, Clone)] +struct PreElectionResults { + pub num_to_elect: usize, + pub candidate_ids: Vec, + pub candidates_and_deposit: Vec<(T::AccountId, BalanceOf)>, + pub voters_and_stakes: Vec<(T::AccountId, BalanceOf, Vec)>, + pub voters_and_votes: Vec<(T::AccountId, VoteWeight, Vec)>, + pub num_edges: u32, +} + pub use pallet::*; type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; @@ -196,7 +218,7 @@ pub mod pallet { pub trait Config: frame_system::Config { type RuntimeEvent: From> + IsType<::RuntimeEvent>; - /// Identifier for the elections-phragmen pallet's lock + /// Identifier for the elections pallet's lock #[pallet::constant] type PalletId: Get; @@ -249,7 +271,7 @@ pub mod pallet { #[pallet::constant] type TermDuration: Get; - /// The maximum number of candidates in a phragmen election. + /// The maximum number of candidates in an election. /// /// Warning: This impacts the size of the election which is run onchain. Chose wisely, and /// consider how it will impact `T::WeightInfo::election_phragmen`. @@ -258,7 +280,7 @@ pub mod pallet { #[pallet::constant] type MaxCandidates: Get; - /// The maximum number of voters to allow in a phragmen election. + /// The maximum number of voters to allow in an election. /// /// Warning: This impacts the size of the election which is run onchain. Chose wisely, and /// consider how it will impact `T::WeightInfo::election_phragmen`. @@ -267,6 +289,12 @@ pub mod pallet { #[pallet::constant] type MaxVoters: Get; + /// Something that will calculate the result of elections. + type ElectionSolver: NposSolver; + + /// Weight information for the [`Config::ElectionSolver`]. + type SolverWeightInfo: frame_election_provider_support::WeightInfo; + /// Maximum numbers of votes per voter. /// /// Warning: This impacts the size of the election which is run onchain. Chose wisely, and @@ -286,7 +314,7 @@ pub mod pallet { fn on_initialize(n: T::BlockNumber) -> Weight { let term_duration = T::TermDuration::get(); if !term_duration.is_zero() && (n % term_duration).is_zero() { - Self::do_phragmen() + Self::do_election() } else { Weight::zero() } @@ -295,11 +323,26 @@ pub mod pallet { fn integrity_test() { let block_weight = T::BlockWeights::get().max_block; // mind the order. - let election_weight = T::WeightInfo::election_phragmen( + let pre_solve_weight = T::WeightInfo::pre_solve_election( T::MaxCandidates::get(), T::MaxVoters::get(), T::MaxVotesPerVoter::get() * T::MaxVoters::get(), ); + // mind the order. + let post_solve_weight = T::WeightInfo::post_solve_election( + T::MaxCandidates::get(), + T::MaxVoters::get(), + T::MaxVotesPerVoter::get() * T::MaxVoters::get(), + ); + // mind the order. + let election_weight = T::ElectionSolver::weight::( + T::MaxCandidates::get(), + T::MaxVoters::get(), + T::MaxVotesPerVoter::get() * T::MaxVoters::get(), + ); + let election_weight = pre_solve_weight + .saturating_sub(post_solve_weight) + .saturating_add(election_weight); let to_seconds = |w: &Weight| { w.ref_time() as f32 / @@ -534,8 +577,8 @@ 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, if `rerun_election` is `true`, a new phragmen election is - /// started, else, nothing happens. + /// outgoing member. Otherwise, if `rerun_election` is `true`, a new 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. @@ -565,7 +608,7 @@ pub mod pallet { Self::deposit_event(Event::MemberKicked { member: who }); if rerun_election { - Self::do_phragmen(); + Self::do_election(); } // no refund needed. @@ -664,6 +707,8 @@ pub mod pallet { InvalidRenouncing, /// Prediction regarding replacement after member removal is wrong. InvalidReplacement, + /// No candidates for the next term. + EmptyTerm, } /// The current elected members. @@ -742,7 +787,7 @@ pub mod pallet { Members::::mutate(|members| { match members.binary_search_by(|m| m.who.cmp(member)) { Ok(_) => { - panic!("Duplicate member in elections-phragmen genesis: {}", member) + panic!("Duplicate member in elections genesis: {}", member) }, Err(pos) => members.insert( pos, @@ -934,11 +979,77 @@ impl Pallet { debug_assert!(_remainder.is_zero()); } - /// Run the phragmen election with all required side processes and state updates, if election - /// succeeds. Else, it will emit an `ElectionError` event. + /// Run an election with all required side processes and state updates, if election + /// succeeds. Else, it will emit an `ElectionError` event. The election algorithm is defined + /// by the implementor of `Self::ElectionSolver`. /// /// Calls the appropriate [`ChangeMembers`] function variant internally. - fn do_phragmen() -> Weight { + fn do_election() -> Weight { + let PreElectionResults { + num_to_elect, + candidate_ids, + candidates_and_deposit, + voters_and_stakes, + voters_and_votes, + num_edges, + } = match Self::do_pre_solve_election() { + Ok(results) => results, + Err(err) => match err { + Error::EmptyTerm => { + Self::deposit_event(Event::EmptyTerm); + return T::DbWeight::get().reads(3) + }, + Error::TooManyVotes => { + Self::deposit_event(Event::ElectionError); + log!(error, "Failed to run election. Number of voters exceeded",); + let max_voters = ::MaxVoters::get() as usize; + return T::DbWeight::get().reads(3 + max_voters as u64) + }, + _ => { + log!(error, "Unexpected pre-election error",); + let max_voters = ::MaxVoters::get() as usize; + return T::DbWeight::get().reads(3 + max_voters as u64) + }, + }, + }; + + let num_candidates = candidates_and_deposit.len() as u32; + let num_voters = voters_and_votes.len() as u32; + let num_edges = num_edges; + + let election_winners = + T::ElectionSolver::solve(num_to_elect, candidate_ids, voters_and_votes) + .map( + |ElectionResult::< + T::AccountId, + ::Accuracy, + > { + winners, + assignments: _, + }| winners, + ) + .map_err(|e| { + log!(warn, "Failed to run election [{:?}].", e); + Self::deposit_event(Event::ElectionError); + }); + + let post_election_weight = if let Ok(winners) = election_winners { + Self::do_post_solve_election(winners, candidates_and_deposit, voters_and_stakes); + T::WeightInfo::post_solve_election(num_candidates, num_voters, num_edges) + } else { + Weight::zero() + }; + + T::ElectionSolver::weight::(num_candidates, num_voters, num_edges) + .saturating_add(T::WeightInfo::pre_solve_election( + num_candidates, + num_voters, + num_edges, + )) + .saturating_add(post_election_weight) + } + + fn do_pre_solve_election() -> Result, Error> { let desired_seats = T::DesiredMembers::get() as usize; let desired_runners_up = T::DesiredRunnersUp::get() as usize; let num_to_elect = desired_runners_up + desired_seats; @@ -948,44 +1059,33 @@ impl Pallet { candidates_and_deposit.append(&mut Self::implicit_candidates_with_deposit()); if candidates_and_deposit.len().is_zero() { - Self::deposit_event(Event::EmptyTerm); - return T::DbWeight::get().reads(3) + return Err(Error::EmptyTerm) } - // All of the new winners that come out of phragmen will thus have a deposit recorded. + // All of the new winners that come out of the election will thus have a deposit recorded. let candidate_ids = candidates_and_deposit.iter().map(|(x, _)| x).cloned().collect::>(); // helper closures to deal with balance/stake. let total_issuance = T::Currency::total_issuance(); let to_votes = |b: BalanceOf| T::CurrencyToVote::to_vote(b, total_issuance); - let to_balance = |e: ExtendedBalance| T::CurrencyToVote::to_currency(e, total_issuance); 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, .. })| { + + Voting::::iter().try_for_each(|(voter, Voter { stake, votes, .. })| { if voters_and_stakes.len() < max_voters { voters_and_stakes.push((voter, stake, votes)); Ok(()) } else { - Err(()) + Err(Error::TooManyVotes) } - }) { - Ok(_) => (), - Err(_) => { - log::error!( - target: LOG_TARGET, - "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. + // used for elections. let voters_and_votes = voters_and_stakes .iter() .cloned() @@ -995,157 +1095,144 @@ impl Pallet { }) .collect::>(); - 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, 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 `T::MaxVotesPerVoter` = 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)| { - ((T::MaxVotesPerVoter::get() as usize - 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, - }); - } - }); + Ok(PreElectionResults { + num_to_elect, + candidate_ids, + candidates_and_deposit, + voters_and_stakes, + voters_and_votes, + num_edges, + }) + } - // 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::>(), - ); + fn do_post_solve_election( + winners: Vec<(T::AccountId, u128)>, + candidates_and_deposit: Vec<(T::AccountId, BalanceOf)>, + voters_and_stakes: Vec<(T::AccountId, BalanceOf, Vec)>, + ) { + let desired_seats = T::DesiredMembers::get() as usize; + let total_issuance = T::Currency::total_issuance(); + let to_balance = |e: ExtendedBalance| T::CurrencyToVote::to_currency(e, total_issuance); - // clean candidates. - >::kill(); + // this is already sorted by id. + let old_members_ids_sorted = + >::take().into_iter().map(|m| m.who).collect::>(); + // this one needs sorted by id. + let mut old_runners_up_ids_sorted = + >::take().into_iter().map(|r| r.who).collect::>(); + old_runners_up_ids_sorted.sort(); - Self::deposit_event(Event::NewTerm { new_members: new_members_sorted_by_id }); - >::mutate(|v| *v += 1); - }) - .map_err(|e| { - log::error!(target: LOG_TARGET, "Failed to run election [{:?}].", e,); - Self::deposit_event(Event::ElectionError); - }); + // 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 `T::MaxVotesPerVoter` = 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)| { + ((T::MaxVotesPerVoter::get() as usize - 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()); - T::WeightInfo::election_phragmen(weight_candidates, weight_voters, weight_edges) + // 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 election 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(); + + log!(info, "New term election successful."); + Self::deposit_event(Event::NewTerm { new_members: new_members_sorted_by_id }); + >::mutate(|v| *v += 1); } } @@ -1196,7 +1283,8 @@ impl ContainsLengthBound for Pallet { #[cfg(test)] mod tests { use super::*; - use crate as elections_phragmen; + use crate as elections; + use frame_election_provider_support::{weights::SubstrateWeight, ApprovalVoting}; use frame_support::{ assert_noop, assert_ok, dispatch::DispatchResultWithPostInfo, @@ -1208,7 +1296,7 @@ mod tests { use sp_runtime::{ testing::Header, traits::{BlakeTwo256, IdentityLookup}, - BuildStorage, + BuildStorage, Perbill, }; use substrate_test_utils::assert_eq_uvec; @@ -1307,13 +1395,13 @@ mod tests { } parameter_types! { - pub const ElectionsPhragmenPalletId: LockIdentifier = *b"phrelect"; - pub const PhragmenMaxVoters: u32 = 1000; - pub const PhragmenMaxCandidates: u32 = 100; + pub const ElectionsPalletId: LockIdentifier = *b"phrelect"; + pub const MaxVoters: u32 = 256; + pub const MaxCandidates: u32 = 64; } impl Config for Test { - type PalletId = ElectionsPhragmenPalletId; + type PalletId = ElectionsPalletId; type RuntimeEvent = RuntimeEvent; type Currency = Balances; type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote; @@ -1328,9 +1416,11 @@ mod tests { type LoserCandidate = (); type KickedMember = (); type WeightInfo = (); - type MaxVoters = PhragmenMaxVoters; + type MaxVoters = MaxVoters; + type MaxCandidates = MaxCandidates; + type ElectionSolver = ApprovalVoting; + type SolverWeightInfo = SubstrateWeight; type MaxVotesPerVoter = ConstU32<16>; - type MaxCandidates = PhragmenMaxCandidates; } pub type Block = sp_runtime::generic::Block; @@ -1345,7 +1435,7 @@ mod tests { { System: frame_system::{Pallet, Call, Event}, Balances: pallet_balances::{Pallet, Call, Event, Config}, - Elections: elections_phragmen::{Pallet, Call, Event, Config}, + Elections: elections::{Pallet, Call, Event, Config}, } ); @@ -1406,9 +1496,7 @@ mod tests { (6, 60 * self.balance_factor), ], }, - elections: elections_phragmen::GenesisConfig:: { - members: self.genesis_members, - }, + elections: elections::GenesisConfig:: { members: self.genesis_members }, } .build_storage() .unwrap() @@ -1466,7 +1554,7 @@ mod tests { .get(0) .cloned() .map(|lock| { - assert_eq!(lock.id, ElectionsPhragmenPalletId::get()); + assert_eq!(lock.id, ElectionsPalletId::get()); lock.amount }) .unwrap_or_default() @@ -1657,7 +1745,7 @@ mod tests { } #[test] - #[should_panic = "Duplicate member in elections-phragmen genesis: 2"] + #[should_panic = "Duplicate member in elections genesis: 2"] fn genesis_members_cannot_be_duplicate() { ExtBuilder::default() .desired_members(3) diff --git a/frame/elections-phragmen/src/migrations/mod.rs b/frame/elections/src/migrations/mod.rs similarity index 100% rename from frame/elections-phragmen/src/migrations/mod.rs rename to frame/elections/src/migrations/mod.rs diff --git a/frame/elections-phragmen/src/migrations/v3.rs b/frame/elections/src/migrations/v3.rs similarity index 100% rename from frame/elections-phragmen/src/migrations/v3.rs rename to frame/elections/src/migrations/v3.rs diff --git a/frame/elections-phragmen/src/migrations/v4.rs b/frame/elections/src/migrations/v4.rs similarity index 100% rename from frame/elections-phragmen/src/migrations/v4.rs rename to frame/elections/src/migrations/v4.rs diff --git a/frame/elections-phragmen/src/migrations/v5.rs b/frame/elections/src/migrations/v5.rs similarity index 100% rename from frame/elections-phragmen/src/migrations/v5.rs rename to frame/elections/src/migrations/v5.rs diff --git a/frame/elections/src/weights.rs b/frame/elections/src/weights.rs new file mode 100644 index 0000000000000..8caa93f0aa8cd --- /dev/null +++ b/frame/elections/src/weights.rs @@ -0,0 +1,397 @@ +// 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_elections +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2022-11-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: +// /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_elections +// --chain=dev +// --header=./HEADER-APACHE2 +// --output=./frame/elections/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_elections. +pub trait WeightInfo { + fn vote_equal(v: u32, ) -> Weight; + fn vote_more(v: u32, ) -> Weight; + fn vote_less(v: u32, ) -> Weight; + fn remove_voter() -> Weight; + fn submit_candidacy(c: u32, ) -> Weight; + fn renounce_candidacy_candidate(c: u32, ) -> Weight; + fn renounce_candidacy_members() -> Weight; + fn renounce_candidacy_runners_up() -> Weight; + fn remove_member_without_replacement() -> Weight; + fn remove_member_with_replacement() -> Weight; + fn clean_defunct_voters(v: u32, d: u32, ) -> Weight; + fn pre_solve_election(c: u32, v: u32, e: u32, ) -> Weight; + fn post_solve_election(c: u32, v: u32, e: u32, ) -> Weight; +} + +/// Weights for pallet_elections using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + // Storage: Elections Candidates (r:1 w:0) + // Storage: Elections Members (r:1 w:0) + // 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 { + // Minimum execution time: 37_500 nanoseconds. + Weight::from_ref_time(38_575_649) + // Standard Error: 2_961 + .saturating_add(Weight::from_ref_time(154_225).saturating_mul(v.into())) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(2)) + } + // Storage: Elections Candidates (r:1 w:0) + // Storage: Elections Members (r:1 w:0) + // 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 { + // Minimum execution time: 48_836 nanoseconds. + Weight::from_ref_time(49_566_969) + // Standard Error: 3_258 + .saturating_add(Weight::from_ref_time(153_342).saturating_mul(v.into())) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(2)) + } + // Storage: Elections Candidates (r:1 w:0) + // Storage: Elections Members (r:1 w:0) + // 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 { + // Minimum execution time: 47_664 nanoseconds. + Weight::from_ref_time(48_768_157) + // Standard Error: 3_321 + .saturating_add(Weight::from_ref_time(215_112).saturating_mul(v.into())) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(2)) + } + // Storage: Elections Voting (r:1 w:1) + // Storage: Balances Locks (r:1 w:1) + fn remove_voter() -> Weight { + // Minimum execution time: 47_146 nanoseconds. + Weight::from_ref_time(47_846_000) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + // 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 { + // Minimum execution time: 42_799 nanoseconds. + Weight::from_ref_time(46_920_164) + // Standard Error: 780 + .saturating_add(Weight::from_ref_time(81_672).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(1)) + } + // Storage: Elections Candidates (r:1 w:1) + /// The range of component `c` is `[1, 1000]`. + fn renounce_candidacy_candidate(c: u32, ) -> Weight { + // Minimum execution time: 40_946 nanoseconds. + Weight::from_ref_time(53_109_738) + // Standard Error: 1_220 + .saturating_add(Weight::from_ref_time(60_643).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + // Storage: Elections Members (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 renounce_candidacy_members() -> Weight { + // Minimum execution time: 53_454 nanoseconds. + Weight::from_ref_time(53_921_000) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) + } + // Storage: Elections RunnersUp (r:1 w:1) + fn renounce_candidacy_runners_up() -> Weight { + // Minimum execution time: 41_275 nanoseconds. + Weight::from_ref_time(42_444_000) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + // 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) + } + // 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 { + // Minimum execution time: 62_040 nanoseconds. + Weight::from_ref_time(62_569_000) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(5)) + } + // 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:5000 w:5000) + // Storage: System Account (r:5000 w:5000) + /// The range of component `v` is `[5000, 10000]`. + /// The range of component `d` is `[0, 5000]`. + fn clean_defunct_voters(v: u32, _d: u32, ) -> Weight { + // Minimum execution time: 298_212_195 nanoseconds. + Weight::from_ref_time(298_678_889_000) + // Standard Error: 264_713 + .saturating_add(Weight::from_ref_time(38_222_955).saturating_mul(v.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(v.into()))) + .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(v.into()))) + } + // Storage: Elections Candidates (r:1 w:0) + // Storage: Elections Members (r:1 w:0) + // Storage: Elections RunnersUp (r:1 w:0) + // Storage: Elections Voting (r:10001 w:0) + /// 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 pre_solve_election(_c: u32, v: u32, _e: u32, ) -> Weight { + // Minimum execution time: 6_543_626 nanoseconds. + Weight::from_ref_time(6_627_885_000) + // Standard Error: 14_605 + .saturating_add(Weight::from_ref_time(7_613_226).saturating_mul(v.into())) + .saturating_add(T::DbWeight::get().reads(296)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) + } + // Storage: Elections Members (r:1 w:1) + // Storage: Elections RunnersUp (r:1 w:1) + // Storage: Council Proposals (r:1 w:0) + // Storage: Elections ElectionRounds (r:1 w:1) + // Storage: Elections Candidates (r:0 w:1) + // Storage: Council Members (r:0 w:1) + // Storage: Council Prime (r:0 w:1) + // 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 post_solve_election(c: u32, v: u32, _e: u32, ) -> Weight { + // Minimum execution time: 3_843_566 nanoseconds. + Weight::from_ref_time(3_854_020_000) + // Standard Error: 59_766 + .saturating_add(Weight::from_ref_time(9_622_797).saturating_mul(c.into())) + // Standard Error: 5_975 + .saturating_add(Weight::from_ref_time(541_471).saturating_mul(v.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(c.into()))) + .saturating_add(T::DbWeight::get().writes(6)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(c.into()))) + } +} + +// For backwards compatibility and tests +impl WeightInfo for () { + // Storage: Elections Candidates (r:1 w:0) + // Storage: Elections Members (r:1 w:0) + // 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 { + // Minimum execution time: 37_500 nanoseconds. + Weight::from_ref_time(38_575_649) + // Standard Error: 2_961 + .saturating_add(Weight::from_ref_time(154_225).saturating_mul(v.into())) + .saturating_add(RocksDbWeight::get().reads(5)) + .saturating_add(RocksDbWeight::get().writes(2)) + } + // Storage: Elections Candidates (r:1 w:0) + // Storage: Elections Members (r:1 w:0) + // 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 { + // Minimum execution time: 48_836 nanoseconds. + Weight::from_ref_time(49_566_969) + // Standard Error: 3_258 + .saturating_add(Weight::from_ref_time(153_342).saturating_mul(v.into())) + .saturating_add(RocksDbWeight::get().reads(5)) + .saturating_add(RocksDbWeight::get().writes(2)) + } + // Storage: Elections Candidates (r:1 w:0) + // Storage: Elections Members (r:1 w:0) + // 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 { + // Minimum execution time: 47_664 nanoseconds. + Weight::from_ref_time(48_768_157) + // Standard Error: 3_321 + .saturating_add(Weight::from_ref_time(215_112).saturating_mul(v.into())) + .saturating_add(RocksDbWeight::get().reads(5)) + .saturating_add(RocksDbWeight::get().writes(2)) + } + // Storage: Elections Voting (r:1 w:1) + // Storage: Balances Locks (r:1 w:1) + fn remove_voter() -> Weight { + // Minimum execution time: 47_146 nanoseconds. + Weight::from_ref_time(47_846_000) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(2)) + } + // 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 { + // Minimum execution time: 42_799 nanoseconds. + Weight::from_ref_time(46_920_164) + // Standard Error: 780 + .saturating_add(Weight::from_ref_time(81_672).saturating_mul(c.into())) + .saturating_add(RocksDbWeight::get().reads(3)) + .saturating_add(RocksDbWeight::get().writes(1)) + } + // Storage: Elections Candidates (r:1 w:1) + /// The range of component `c` is `[1, 1000]`. + fn renounce_candidacy_candidate(c: u32, ) -> Weight { + // Minimum execution time: 40_946 nanoseconds. + Weight::from_ref_time(53_109_738) + // Standard Error: 1_220 + .saturating_add(Weight::from_ref_time(60_643).saturating_mul(c.into())) + .saturating_add(RocksDbWeight::get().reads(1)) + .saturating_add(RocksDbWeight::get().writes(1)) + } + // Storage: Elections Members (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 renounce_candidacy_members() -> Weight { + // Minimum execution time: 53_454 nanoseconds. + Weight::from_ref_time(53_921_000) + .saturating_add(RocksDbWeight::get().reads(4)) + .saturating_add(RocksDbWeight::get().writes(4)) + } + // Storage: Elections RunnersUp (r:1 w:1) + fn renounce_candidacy_runners_up() -> Weight { + // Minimum execution time: 41_275 nanoseconds. + Weight::from_ref_time(42_444_000) + .saturating_add(RocksDbWeight::get().reads(1)) + .saturating_add(RocksDbWeight::get().writes(1)) + } + // 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) + } + // 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 { + // Minimum execution time: 62_040 nanoseconds. + Weight::from_ref_time(62_569_000) + .saturating_add(RocksDbWeight::get().reads(5)) + .saturating_add(RocksDbWeight::get().writes(5)) + } + // 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:5000 w:5000) + // Storage: System Account (r:5000 w:5000) + /// The range of component `v` is `[5000, 10000]`. + /// The range of component `d` is `[0, 5000]`. + fn clean_defunct_voters(v: u32, _d: u32, ) -> Weight { + // Minimum execution time: 298_212_195 nanoseconds. + Weight::from_ref_time(298_678_889_000) + // Standard Error: 264_713 + .saturating_add(Weight::from_ref_time(38_222_955).saturating_mul(v.into())) + .saturating_add(RocksDbWeight::get().reads(4)) + .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(v.into()))) + .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(v.into()))) + } + // Storage: Elections Candidates (r:1 w:0) + // Storage: Elections Members (r:1 w:0) + // Storage: Elections RunnersUp (r:1 w:0) + // Storage: Elections Voting (r:10001 w:0) + /// 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 pre_solve_election(_c: u32, v: u32, _e: u32, ) -> Weight { + // Minimum execution time: 6_543_626 nanoseconds. + Weight::from_ref_time(6_627_885_000) + // Standard Error: 14_605 + .saturating_add(Weight::from_ref_time(7_613_226).saturating_mul(v.into())) + .saturating_add(RocksDbWeight::get().reads(296)) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(v.into()))) + } + // Storage: Elections Members (r:1 w:1) + // Storage: Elections RunnersUp (r:1 w:1) + // Storage: Council Proposals (r:1 w:0) + // Storage: Elections ElectionRounds (r:1 w:1) + // Storage: Elections Candidates (r:0 w:1) + // Storage: Council Members (r:0 w:1) + // Storage: Council Prime (r:0 w:1) + // 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 post_solve_election(c: u32, v: u32, _e: u32, ) -> Weight { + // Minimum execution time: 3_843_566 nanoseconds. + Weight::from_ref_time(3_854_020_000) + // Standard Error: 59_766 + .saturating_add(Weight::from_ref_time(9_622_797).saturating_mul(c.into())) + // Standard Error: 5_975 + .saturating_add(Weight::from_ref_time(541_471).saturating_mul(v.into())) + .saturating_add(RocksDbWeight::get().reads(4)) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(c.into()))) + .saturating_add(RocksDbWeight::get().writes(6)) + .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(c.into()))) + } +} diff --git a/primitives/npos-elections/src/approval_voting.rs b/primitives/npos-elections/src/approval_voting.rs new file mode 100644 index 0000000000000..2fcf17b60565d --- /dev/null +++ b/primitives/npos-elections/src/approval_voting.rs @@ -0,0 +1,79 @@ +// This file is part of Substrate. + +// Copyright (C) 2023 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Implementation of the approval voting election method. +//! +//! This method allows voters to select many candidates and backing each of them with the same +//! vote weight. The candidates with the most backing are the election winners. + +use crate::{setup_inputs, ElectionResult, IdentifierT, PerThing128, VoteWeight}; +use sp_arithmetic::traits::Zero; +use sp_std::{cmp::Reverse, vec::Vec}; + +/// Execute an approvals voting election scheme. The return type is a list of winners. The weight +/// vector of all voters who contribute to the winners, which for this scheme is always 100% per +/// vote. +/// +/// - The vote assignment distribution for each vote is always 100%, since a voter backs a candidate +/// with its full stake, regardless of how many candidates are backed by the same stake. However, +/// the caller may normalize votes on site if required. +/// - Returning winners are sorted based on desirability. Voters are unsorted. +/// - The returning winners are zipped with their final backing stake. Yet, to get the exact final +/// weight distribution from the winner's point of view, one needs to build a support map. See +/// [`crate::SupportMap`] for more info. Note that this backing stake is computed in +/// ExtendedBalance and may be slightly different that what will be computed from the support map, +/// due to accuracy loss. +/// +/// 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

{ instance .get_export(ctx, "__indirect_function_table") .as_ref() - .and_then(extern_table) .cloned() + .and_then(Extern::into_table) } /// Functions related to memory. @@ -403,7 +397,7 @@ fn decommit_works() { let module = wasmtime::Module::new(&engine, code).unwrap(); let linker = wasmtime::Linker::new(&engine); let instance_pre = linker.instantiate_pre(&module).unwrap(); - let mut wrapper = InstanceWrapper::new(&engine, &instance_pre, None).unwrap(); + let mut wrapper = InstanceWrapper::new(&engine, &instance_pre).unwrap(); unsafe { *wrapper.memory.data_ptr(&wrapper.store) = 42 }; assert_eq!(unsafe { *wrapper.memory.data_ptr(&wrapper.store) }, 42); wrapper.decommit(); diff --git a/client/executor/wasmtime/src/runtime.rs b/client/executor/wasmtime/src/runtime.rs index ce3f889fc9a75..de7a2ea0e73df 100644 --- a/client/executor/wasmtime/src/runtime.rs +++ b/client/executor/wasmtime/src/runtime.rs @@ -20,7 +20,7 @@ use crate::{ host::HostState, - instance_wrapper::{EntryPoint, InstanceWrapper}, + instance_wrapper::{EntryPoint, InstanceWrapper, MemoryWrapper}, util::{self, replace_strategy_if_broken}, }; @@ -31,7 +31,7 @@ use sc_executor_common::{ self, DataSegmentsSnapshot, ExposedMutableGlobalsSet, GlobalsSnapshot, RuntimeBlob, }, util::checked_range, - wasm_runtime::{InvokeMethod, WasmInstance, WasmModule}, + wasm_runtime::{HeapAllocStrategy, InvokeMethod, WasmInstance, WasmModule}, }; use sp_runtime_interface::unpack_ptr_and_len; use sp_wasm_interface::{HostFunctions, Pointer, Value, WordSize}; @@ -42,12 +42,10 @@ use std::{ Arc, }, }; -use wasmtime::{AsContext, Engine, Memory, StoreLimits, Table}; +use wasmtime::{AsContext, Engine, Memory, Table}; +#[derive(Default)] pub(crate) struct StoreData { - /// 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. - pub(crate) limits: StoreLimits, /// This will only be set when we call into the runtime. pub(crate) host_state: Option, /// This will be always set once the store is initialized. @@ -83,12 +81,11 @@ enum Strategy { struct InstanceCreator { engine: wasmtime::Engine, instance_pre: Arc>, - max_memory_size: Option, } impl InstanceCreator { fn instantiate(&mut self) -> Result { - InstanceWrapper::new(&self.engine, &self.instance_pre, self.max_memory_size) + InstanceWrapper::new(&self.engine, &self.instance_pre) } } @@ -128,18 +125,13 @@ pub struct WasmtimeRuntime { engine: wasmtime::Engine, instance_pre: Arc>, instantiation_strategy: InternalInstantiationStrategy, - config: Config, } impl WasmModule for WasmtimeRuntime { fn new_instance(&self) -> Result> { let strategy = match self.instantiation_strategy { InternalInstantiationStrategy::LegacyInstanceReuse(ref snapshot_data) => { - let mut instance_wrapper = InstanceWrapper::new( - &self.engine, - &self.instance_pre, - self.config.semantics.max_memory_size, - )?; + let mut instance_wrapper = InstanceWrapper::new(&self.engine, &self.instance_pre)?; let heap_base = instance_wrapper.extract_heap_base()?; // This function panics if the instance was created from a runtime blob different @@ -161,7 +153,6 @@ impl WasmModule for WasmtimeRuntime { InternalInstantiationStrategy::Builtin => Strategy::RecreateInstance(InstanceCreator { engine: self.engine.clone(), instance_pre: self.instance_pre.clone(), - max_memory_size: self.config.semantics.max_memory_size, }), }; @@ -350,25 +341,22 @@ fn common_config(semantics: &Semantics) -> std::result::Result (false, false), }; + const WASM_PAGE_SIZE: u64 = 65536; + 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), - ); + config.memory_guaranteed_dense_image_size(match semantics.heap_alloc_strategy { + HeapAllocStrategy::Dynamic { maximum_pages } => + maximum_pages.map(|p| p as u64 * WASM_PAGE_SIZE).unwrap_or(u64::MAX), + HeapAllocStrategy::Static { .. } => u64::MAX, + }); if use_pooling { - const WASM_PAGE_SIZE: u64 = 65536; const MAX_WASM_PAGES: u64 = 0x10000; - let memory_pages = if let Some(max_memory_size) = semantics.max_memory_size { - let max_memory_size = max_memory_size as u64; - let mut pages = max_memory_size / WASM_PAGE_SIZE; - if max_memory_size % WASM_PAGE_SIZE != 0 { - pages += 1; - } - - std::cmp::min(MAX_WASM_PAGES, pages) - } else { - MAX_WASM_PAGES + let memory_pages = match semantics.heap_alloc_strategy { + HeapAllocStrategy::Dynamic { maximum_pages } => + maximum_pages.map(|p| p as u64).unwrap_or(MAX_WASM_PAGES), + HeapAllocStrategy::Static { .. } => MAX_WASM_PAGES, }; let mut pooling_config = wasmtime::PoolingAllocationConfig::default(); @@ -514,25 +502,8 @@ 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, - - /// 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 [`Semantics::extra_heap_pages`] is accounted - /// for. - /// - /// That means that the initial number of pages of a linear memory plus the - /// [`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`. - /// - /// The default is `None`. - pub max_memory_size: Option, + /// The heap allocation strategy to use. + pub heap_alloc_strategy: HeapAllocStrategy, } #[derive(Clone)] @@ -689,12 +660,7 @@ where .instantiate_pre(&module) .map_err(|e| WasmError::Other(format!("cannot preinstantiate module: {:#}", e)))?; - Ok(WasmtimeRuntime { - engine, - instance_pre: Arc::new(instance_pre), - instantiation_strategy, - config, - }) + Ok(WasmtimeRuntime { engine, instance_pre: Arc::new(instance_pre), instantiation_strategy }) } fn prepare_blob_for_compilation( @@ -717,12 +683,7 @@ fn prepare_blob_for_compilation( // 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 - .extra_heap_pages - .try_into() - .map_err(|e| WasmError::Other(format!("invalid `extra_heap_pages`: {}", e)))?, - )?; + blob.setup_memory_according_to_heap_alloc_strategy(semantics.heap_alloc_strategy)?; Ok(blob) } @@ -783,9 +744,8 @@ fn inject_input_data( ) -> 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 = allocator.allocate(memory, data_len)?; + let data_ptr = allocator.allocate(&mut MemoryWrapper(&memory, &mut ctx), data_len)?; util::write_memory_from(instance.store_mut(), data_ptr, data)?; Ok((data_ptr, data_len)) } diff --git a/client/executor/wasmtime/src/tests.rs b/client/executor/wasmtime/src/tests.rs index 57540b35d05cf..7f222b6cf7c05 100644 --- a/client/executor/wasmtime/src/tests.rs +++ b/client/executor/wasmtime/src/tests.rs @@ -17,7 +17,11 @@ // along with this program. If not, see . use codec::{Decode as _, Encode as _}; -use sc_executor_common::{error::Error, runtime_blob::RuntimeBlob, wasm_runtime::WasmModule}; +use sc_executor_common::{ + error::Error, + runtime_blob::RuntimeBlob, + wasm_runtime::{HeapAllocStrategy, WasmModule}, +}; use sc_runtime_test::wasm_binary_unwrap; use crate::InstantiationStrategy; @@ -77,8 +81,7 @@ struct RuntimeBuilder { instantiation_strategy: InstantiationStrategy, canonicalize_nans: bool, deterministic_stack: bool, - extra_heap_pages: u64, - max_memory_size: Option, + heap_pages: HeapAllocStrategy, precompile_runtime: bool, tmpdir: Option, } @@ -90,8 +93,7 @@ impl RuntimeBuilder { instantiation_strategy, canonicalize_nans: false, deterministic_stack: false, - extra_heap_pages: 1024, - max_memory_size: None, + heap_pages: HeapAllocStrategy::Static { extra_pages: 1024 }, precompile_runtime: false, tmpdir: None, } @@ -117,8 +119,8 @@ impl RuntimeBuilder { self } - fn max_memory_size(mut self, max_memory_size: Option) -> Self { - self.max_memory_size = max_memory_size; + fn heap_alloc_strategy(mut self, heap_pages: HeapAllocStrategy) -> Self { + self.heap_pages = heap_pages; self } @@ -152,8 +154,7 @@ impl RuntimeBuilder { }, canonicalize_nans: self.canonicalize_nans, parallel_compilation: true, - extra_heap_pages: self.extra_heap_pages, - max_memory_size: self.max_memory_size, + heap_alloc_strategy: self.heap_pages, }, }; @@ -227,7 +228,7 @@ fn deep_call_stack_wat(depth: usize) -> String { // 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 = 65455; -const CALL_DEPTH_UPPER_LIMIT: usize = 65503; +const CALL_DEPTH_UPPER_LIMIT: usize = 65509; 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) { @@ -344,29 +345,25 @@ fn test_max_memory_pages( import_memory: bool, precompile_runtime: bool, ) { - fn try_instantiate( - max_memory_size: Option, + fn call( + heap_alloc_strategy: HeapAllocStrategy, wat: String, instantiation_strategy: InstantiationStrategy, precompile_runtime: bool, ) -> Result<(), Box> { let mut builder = RuntimeBuilder::new(instantiation_strategy) .use_wat(wat) - .max_memory_size(max_memory_size) + .heap_alloc_strategy(heap_alloc_strategy) .precompile_runtime(precompile_runtime); let runtime = builder.build(); - let mut instance = runtime.new_instance()?; + let mut instance = runtime.new_instance().unwrap(); let _ = instance.call_export("main", &[])?; 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) - }; + fn memory(initial: u32, maximum: u32, import: bool) -> String { + let memory = format!("(memory $0 {} {})", initial, maximum); if import { format!("(import \"env\" \"memory\" {})", memory) @@ -375,152 +372,90 @@ fn test_max_memory_pages( } } - 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, - 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) - ), - instantiation_strategy, - precompile_runtime, - ) - .unwrap(); - - // max is not specified, therefore it's implied to be 65536 pages (4 GiB). - // - // max_memory_size = (1 (initial) + 1024 (heap_pages)) * WASM_PAGE_SIZE - try_instantiate( - Some((1 + 1024) * WASM_PAGE_SIZE), - 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) - ), - instantiation_strategy, - precompile_runtime, - ) - .unwrap(); - - // max is specified explicitly to 2048 pages. - try_instantiate( - Some((1 + 1024) * WASM_PAGE_SIZE), - 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) - ), - instantiation_strategy, - precompile_runtime, - ) - .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), - 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) + let assert_grow_ok = |alloc_strategy: HeapAllocStrategy, initial_pages: u32, max_pages: u32| { + eprintln!("assert_grow_ok({alloc_strategy:?}, {initial_pages}, {max_pages})"); + + call( + alloc_strategy, + 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 1) + ) + (i32.const -1) + ) + (unreachable) ) - (i32.const -1) + + (i64.const 0) ) - (unreachable) ) - - (i64.const 0) - ) - ) "#, - // Zero starting pages. - memory(0, None, import_memory) - ), - instantiation_strategy, - precompile_runtime, - ) - .unwrap(); + memory(initial_pages, max_pages, import_memory) + ), + instantiation_strategy, + precompile_runtime, + ) + .unwrap() + }; - // We start with 1025 pages and try to grow at least one. - try_instantiate( - Some((1 + 1024) * WASM_PAGE_SIZE), - 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) + let assert_grow_fail = + |alloc_strategy: HeapAllocStrategy, initial_pages: u32, max_pages: u32| { + eprintln!("assert_grow_fail({alloc_strategy:?}, {initial_pages}, {max_pages})"); + + call( + alloc_strategy, + 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) + ) + (unreachable) + ) + + (i64.const 0) ) - (i32.const -1) ) - (unreachable) - ) - - (i64.const 0) - ) + "#, + memory(initial_pages, max_pages, import_memory) + ), + instantiation_strategy, + precompile_runtime, ) - "#, - // Initial=1, meaning after heap pages mount the total will be already 1025. - memory(1, None, import_memory) - ), - instantiation_strategy, - precompile_runtime, - ) - .unwrap(); + .unwrap() + }; + + assert_grow_ok(HeapAllocStrategy::Dynamic { maximum_pages: Some(10) }, 1, 10); + assert_grow_ok(HeapAllocStrategy::Dynamic { maximum_pages: Some(10) }, 9, 10); + assert_grow_fail(HeapAllocStrategy::Dynamic { maximum_pages: Some(10) }, 10, 10); + + assert_grow_ok(HeapAllocStrategy::Dynamic { maximum_pages: None }, 1, 10); + assert_grow_ok(HeapAllocStrategy::Dynamic { maximum_pages: None }, 9, 10); + assert_grow_ok(HeapAllocStrategy::Dynamic { maximum_pages: None }, 10, 10); + + assert_grow_fail(HeapAllocStrategy::Static { extra_pages: 10 }, 1, 10); + assert_grow_fail(HeapAllocStrategy::Static { extra_pages: 10 }, 9, 10); + assert_grow_fail(HeapAllocStrategy::Static { extra_pages: 10 }, 10, 10); } // This test takes quite a while to execute in a debug build (over 6 minutes on a TR 3970x) @@ -538,8 +473,7 @@ fn test_instances_without_reuse_are_not_leaked() { deterministic_stack_limit: None, canonicalize_nans: false, parallel_compilation: true, - extra_heap_pages: 2048, - max_memory_size: None, + heap_alloc_strategy: HeapAllocStrategy::Static { extra_pages: 2048 }, }, }, ) @@ -583,6 +517,10 @@ fn test_rustix_version_matches_with_wasmtime() { .unwrap(); if wasmtime_rustix.req != our_rustix.req { - panic!("our version of rustix ({0}) doesn't match wasmtime's ({1}); bump the version in `sc-executor-wasmtime`'s `Cargo.toml' to '{1}' and try again", our_rustix.req, wasmtime_rustix.req); + panic!( + "our version of rustix ({0}) doesn't match wasmtime's ({1}); \ + bump the version in `sc-executor-wasmtime`'s `Cargo.toml' to '{1}' and try again", + our_rustix.req, wasmtime_rustix.req, + ); } } diff --git a/client/finality-grandpa/src/lib.rs b/client/finality-grandpa/src/lib.rs index fca1a8a83b269..4f72bb0521554 100644 --- a/client/finality-grandpa/src/lib.rs +++ b/client/finality-grandpa/src/lib.rs @@ -75,7 +75,7 @@ use sp_api::ProvideRuntimeApi; use sp_application_crypto::AppKey; use sp_blockchain::{Error as ClientError, HeaderBackend, HeaderMetadata, Result as ClientResult}; use sp_consensus::SelectChain; -use sp_core::crypto::ByteArray; +use sp_core::{crypto::ByteArray, traits::CallContext}; use sp_finality_grandpa::{ AuthorityList, AuthoritySignature, SetId, CLIENT_LOG_TARGET as LOG_TARGET, }; @@ -479,6 +479,7 @@ where "GrandpaApi_grandpa_authorities", &[], ExecutionStrategy::NativeElseWasm, + CallContext::Offchain, ) .and_then(|call_result| { Decode::decode(&mut &call_result[..]).map_err(|err| { diff --git a/client/rpc-spec-v2/src/chain_head/chain_head.rs b/client/rpc-spec-v2/src/chain_head/chain_head.rs index 4dbdf277e1732..4fa47dc403cc9 100644 --- a/client/rpc-spec-v2/src/chain_head/chain_head.rs +++ b/client/rpc-spec-v2/src/chain_head/chain_head.rs @@ -52,7 +52,7 @@ use sp_api::CallApiAt; use sp_blockchain::{ Backend as BlockChainBackend, Error as BlockChainError, HeaderBackend, HeaderMetadata, }; -use sp_core::{hexdisplay::HexDisplay, storage::well_known_keys, Bytes}; +use sp_core::{hexdisplay::HexDisplay, storage::well_known_keys, traits::CallContext, Bytes}; use sp_runtime::traits::{Block as BlockT, Header}; use std::{marker::PhantomData, sync::Arc}; @@ -736,6 +736,7 @@ where &function, &call_parameters, client.execution_extensions().strategies().other, + CallContext::Offchain, ) .map(|result| { let result = format!("0x{:?}", HexDisplay::from(&result)); diff --git a/client/rpc/src/state/state_full.rs b/client/rpc/src/state/state_full.rs index efd2085398238..f26d42484f24f 100644 --- a/client/rpc/src/state/state_full.rs +++ b/client/rpc/src/state/state_full.rs @@ -46,6 +46,7 @@ use sp_core::{ storage::{ ChildInfo, ChildType, PrefixedStorageKey, StorageChangeSet, StorageData, StorageKey, }, + traits::CallContext, Bytes, }; use sp_runtime::traits::Block as BlockT; @@ -207,6 +208,7 @@ where &method, &call_data, self.client.execution_extensions().strategies().other, + CallContext::Offchain, ) .map(Into::into) }) diff --git a/client/service/src/client/call_executor.rs b/client/service/src/client/call_executor.rs index 8942b20bd91dc..82d3e36ac80ea 100644 --- a/client/service/src/client/call_executor.rs +++ b/client/service/src/client/call_executor.rs @@ -21,8 +21,11 @@ use sc_client_api::{ backend, call_executor::CallExecutor, execution_extensions::ExecutionExtensions, HeaderBackend, }; use sc_executor::{RuntimeVersion, RuntimeVersionOf}; -use sp_api::{ExecutionContext, ProofRecorder, StorageTransactionCache}; -use sp_core::traits::{CodeExecutor, RuntimeCode, SpawnNamed}; +use sp_api::{ProofRecorder, StorageTransactionCache}; +use sp_core::{ + traits::{CallContext, CodeExecutor, RuntimeCode, SpawnNamed}, + ExecutionContext, +}; use sp_runtime::{generic::BlockId, traits::Block as BlockT}; use sp_state_machine::{ backend::AsTrieBackend, ExecutionStrategy, Ext, OverlayedChanges, StateMachine, StorageProof, @@ -166,6 +169,7 @@ where method: &str, call_data: &[u8], strategy: ExecutionStrategy, + context: CallContext, ) -> sp_blockchain::Result> { let mut changes = OverlayedChanges::default(); let at_number = @@ -193,6 +197,7 @@ where extensions, &runtime_code, self.spawn_handle.clone(), + context, ) .set_parent_hash(at_hash); @@ -216,6 +221,11 @@ where self.backend.blockchain().expect_block_number_from_id(&BlockId::Hash(at_hash))?; let state = self.backend.state_at(at_hash)?; + let call_context = match context { + ExecutionContext::OffchainCall(_) => CallContext::Offchain, + _ => CallContext::Onchain, + }; + let (execution_manager, extensions) = self.execution_extensions.manager_and_extensions(at_hash, at_number, context); @@ -247,6 +257,7 @@ where extensions, &runtime_code, self.spawn_handle.clone(), + call_context, ) .with_storage_transaction_cache(storage_transaction_cache.as_deref_mut()) .set_parent_hash(at_hash); @@ -262,6 +273,7 @@ where extensions, &runtime_code, self.spawn_handle.clone(), + call_context, ) .with_storage_transaction_cache(storage_transaction_cache.as_deref_mut()) .set_parent_hash(at_hash); diff --git a/client/service/test/src/client/mod.rs b/client/service/test/src/client/mod.rs index b2b029f226140..f8988c5a454c3 100644 --- a/client/service/test/src/client/mod.rs +++ b/client/service/test/src/client/mod.rs @@ -30,7 +30,7 @@ use sc_consensus::{ 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::{testing::TaskExecutor, H256}; +use sp_core::{testing::TaskExecutor, traits::CallContext, H256}; use sp_runtime::{ generic::BlockId, traits::{BlakeTwo256, Block as BlockT, Header as HeaderT}, @@ -114,6 +114,7 @@ fn construct_block( Default::default(), &runtime_code, task_executor.clone() as Box<_>, + CallContext::Onchain, ) .execute(ExecutionStrategy::NativeElseWasm) .unwrap(); @@ -128,6 +129,7 @@ fn construct_block( Default::default(), &runtime_code, task_executor.clone() as Box<_>, + CallContext::Onchain, ) .execute(ExecutionStrategy::NativeElseWasm) .unwrap(); @@ -142,6 +144,7 @@ fn construct_block( Default::default(), &runtime_code, task_executor.clone() as Box<_>, + CallContext::Onchain, ) .execute(ExecutionStrategy::NativeElseWasm) .unwrap(); @@ -213,6 +216,7 @@ fn construct_genesis_should_work_with_native() { Default::default(), &runtime_code, TaskExecutor::new(), + CallContext::Onchain, ) .execute(ExecutionStrategy::NativeElseWasm) .unwrap(); @@ -246,6 +250,7 @@ fn construct_genesis_should_work_with_wasm() { Default::default(), &runtime_code, TaskExecutor::new(), + CallContext::Onchain, ) .execute(ExecutionStrategy::AlwaysWasm) .unwrap(); @@ -279,6 +284,7 @@ fn construct_genesis_with_bad_transaction_should_panic() { Default::default(), &runtime_code, TaskExecutor::new(), + CallContext::Onchain, ) .execute(ExecutionStrategy::NativeElseWasm); assert!(r.is_err()); diff --git a/primitives/core/src/traits.rs b/primitives/core/src/traits.rs index 3fe2a2ed3c394..0e42ee3ad4b12 100644 --- a/primitives/core/src/traits.rs +++ b/primitives/core/src/traits.rs @@ -24,13 +24,27 @@ use std::{ pub use sp_externalities::{Externalities, ExternalitiesExt}; +/// The context in which a call is done. +/// +/// Depending on the context the executor may chooses different kind of heap sizes for the runtime +/// instance. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Ord, PartialOrd)] +pub enum CallContext { + /// The call is happening in some offchain context. + Offchain, + /// The call is happening in some on-chain context like building or importing a block. + Onchain, +} + /// Code execution engine. pub trait CodeExecutor: Sized + Send + Sync + ReadRuntimeVersion + Clone + 'static { /// Externalities error type. type Error: Display + Debug + Send + Sync + 'static; - /// 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. + /// 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( &self, ext: &mut dyn Externalities, @@ -38,6 +52,7 @@ pub trait CodeExecutor: Sized + Send + Sync + ReadRuntimeVersion + Clone + 'stat method: &str, data: &[u8], use_native: bool, + context: CallContext, ) -> (Result, Self::Error>, bool); } diff --git a/primitives/state-machine/src/lib.rs b/primitives/state-machine/src/lib.rs index 538c63837920c..5fb300e12bae7 100644 --- a/primitives/state-machine/src/lib.rs +++ b/primitives/state-machine/src/lib.rs @@ -163,7 +163,7 @@ mod execution { use sp_core::{ hexdisplay::HexDisplay, storage::{ChildInfo, ChildType, PrefixedStorageKey}, - traits::{CodeExecutor, ReadRuntimeVersionExt, RuntimeCode, SpawnNamed}, + traits::{CallContext, CodeExecutor, ReadRuntimeVersionExt, RuntimeCode, SpawnNamed}, }; use sp_externalities::Extensions; use std::{ @@ -295,6 +295,7 @@ mod execution { /// /// Used for logging. parent_hash: Option, + context: CallContext, } impl<'a, B, H, Exec> Drop for StateMachine<'a, B, H, Exec> @@ -324,6 +325,7 @@ mod execution { mut extensions: Extensions, runtime_code: &'a RuntimeCode, spawn_handle: impl SpawnNamed + Send + 'static, + context: CallContext, ) -> Self { extensions.register(ReadRuntimeVersionExt::new(exec.clone())); extensions.register(sp_core::traits::TaskExecutorExt::new(spawn_handle)); @@ -339,6 +341,7 @@ mod execution { runtime_code, stats: StateMachineStats::default(), parent_hash: None, + context, } } @@ -408,6 +411,7 @@ mod execution { self.method, self.call_data, use_native, + self.context, ); self.overlay @@ -574,6 +578,7 @@ mod execution { extensions, runtime_code, spawn_handle, + CallContext::Offchain, ) .execute_using_consensus_failure_handler::<_>(always_wasm())?; @@ -638,6 +643,7 @@ mod execution { Extensions::default(), runtime_code, spawn_handle, + CallContext::Offchain, ) .execute_using_consensus_failure_handler(always_untrusted_wasm()) } @@ -1318,7 +1324,7 @@ mod tests { map, storage::{ChildInfo, StateVersion}, testing::TaskExecutor, - traits::{CodeExecutor, Externalities, RuntimeCode}, + traits::{CallContext, CodeExecutor, Externalities, RuntimeCode}, }; use sp_runtime::traits::BlakeTwo256; use sp_trie::trie_types::{TrieDBMutBuilderV0, TrieDBMutBuilderV1}; @@ -1341,6 +1347,7 @@ mod tests { _method: &str, _data: &[u8], use_native: bool, + _: CallContext, ) -> (CallResult, bool) { let using_native = use_native && self.native_available; match (using_native, self.native_succeeds, self.fallback_succeeds) { @@ -1388,6 +1395,7 @@ mod tests { Default::default(), &wasm_code, TaskExecutor::new(), + CallContext::Offchain, ); assert_eq!(state_machine.execute(ExecutionStrategy::NativeWhenPossible).unwrap(), vec![66]); @@ -1416,6 +1424,7 @@ mod tests { Default::default(), &wasm_code, TaskExecutor::new(), + CallContext::Offchain, ); assert_eq!(state_machine.execute(ExecutionStrategy::NativeElseWasm).unwrap(), vec![66]); @@ -1445,6 +1454,7 @@ mod tests { Default::default(), &wasm_code, TaskExecutor::new(), + CallContext::Offchain, ); assert!(state_machine diff --git a/primitives/wasm-interface/Cargo.toml b/primitives/wasm-interface/Cargo.toml index 65c4ae42f044e..306a47e6dc1b7 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.2.2", default-features = false, features = ["derive"] } impl-trait-for-tuples = "0.2.2" log = { version = "0.4.17", optional = true } -wasmi = { version = "0.13", optional = true } +wasmi = { version = "0.13.2", optional = true } wasmtime = { version = "6.0.0", default-features = false, optional = true } anyhow = { version = "1.0.68", optional = true } sp-std = { version = "5.0.0", default-features = false, path = "../std" } diff --git a/test-utils/runtime/src/lib.rs b/test-utils/runtime/src/lib.rs index 1fa3c7a00b9c5..720b0a1e06f07 100644 --- a/test-utils/runtime/src/lib.rs +++ b/test-utils/runtime/src/lib.rs @@ -1352,7 +1352,7 @@ mod tests { use sc_block_builder::BlockBuilderProvider; use sp_api::ProvideRuntimeApi; use sp_consensus::BlockOrigin; - use sp_core::storage::well_known_keys::HEAP_PAGES; + use sp_core::{storage::well_known_keys::HEAP_PAGES, ExecutionContext}; use sp_state_machine::ExecutionStrategy; use substrate_test_runtime_client::{ prelude::*, runtime::TestAPI, DefaultTestClientBuilderExt, TestClientBuilder, @@ -1371,7 +1371,12 @@ mod tests { // Try to allocate 1024k of memory on heap. This is going to fail since it is twice larger // than the heap. - let ret = client.runtime_api().vec_with_capacity(best_hash, 1048576); + let ret = client.runtime_api().vec_with_capacity_with_context( + best_hash, + // Use `BlockImport` to ensure we use the on chain heap pages as configured above. + ExecutionContext::Importing, + 1048576, + ); assert!(ret.is_err()); // Create a block that sets the `:heap_pages` to 32 pages of memory which corresponds to diff --git a/test-utils/runtime/src/system.rs b/test-utils/runtime/src/system.rs index 76ddf11a85196..657e3c90fa6d3 100644 --- a/test-utils/runtime/src/system.rs +++ b/test-utils/runtime/src/system.rs @@ -354,7 +354,7 @@ mod tests { use sc_executor::{NativeElseWasmExecutor, WasmExecutionMethod}; use sp_core::{ map, - traits::{CodeExecutor, RuntimeCode}, + traits::{CallContext, CodeExecutor, RuntimeCode}, }; use sp_io::{hashing::twox_128, TestExternalities}; use substrate_test_runtime_client::{AccountKeyring, Sr25519Keyring}; @@ -438,7 +438,14 @@ mod tests { }; executor() - .call(&mut ext, &runtime_code, "Core_execute_block", &b.encode(), false) + .call( + &mut ext, + &runtime_code, + "Core_execute_block", + &b.encode(), + false, + CallContext::Offchain, + ) .0 .unwrap(); }) @@ -540,7 +547,14 @@ mod tests { }; executor() - .call(&mut ext, &runtime_code, "Core_execute_block", &b.encode(), false) + .call( + &mut ext, + &runtime_code, + "Core_execute_block", + &b.encode(), + false, + CallContext::Offchain, + ) .0 .unwrap(); }) diff --git a/utils/frame/benchmarking-cli/src/pallet/command.rs b/utils/frame/benchmarking-cli/src/pallet/command.rs index 3f0e9298c7713..60f078142e17f 100644 --- a/utils/frame/benchmarking-cli/src/pallet/command.rs +++ b/utils/frame/benchmarking-cli/src/pallet/command.rs @@ -30,9 +30,12 @@ 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, +use sp_core::{ + offchain::{ + testing::{TestOffchainExt, TestTransactionPoolExt}, + OffchainDbExt, OffchainWorkerExt, TransactionPoolExt, + }, + traits::CallContext, }; use sp_externalities::Extensions; use sp_keystore::{testing::KeyStore, KeystoreExt, SyncCryptoStorePtr}; @@ -235,6 +238,7 @@ impl PalletCmd { extensions(), &sp_state_machine::backend::BackendRuntimeCode::new(state).runtime_code()?, sp_core::testing::TaskExecutor::new(), + CallContext::Offchain, ) .execute(strategy.into()) .map_err(|e| format!("{}: {}", ERROR_METADATA_NOT_FOUND, e))?; @@ -372,6 +376,7 @@ impl PalletCmd { &sp_state_machine::backend::BackendRuntimeCode::new(state) .runtime_code()?, sp_core::testing::TaskExecutor::new(), + CallContext::Offchain, ) .execute(strategy.into()) .map_err(|e| { @@ -412,6 +417,7 @@ impl PalletCmd { &sp_state_machine::backend::BackendRuntimeCode::new(state) .runtime_code()?, sp_core::testing::TaskExecutor::new(), + CallContext::Offchain, ) .execute(strategy.into()) .map_err(|e| format!("Error executing runtime benchmark: {}", e))?; @@ -444,6 +450,7 @@ impl PalletCmd { &sp_state_machine::backend::BackendRuntimeCode::new(state) .runtime_code()?, sp_core::testing::TaskExecutor::new(), + CallContext::Offchain, ) .execute(strategy.into()) .map_err(|e| format!("Error executing runtime benchmark: {}", e))?; diff --git a/utils/frame/try-runtime/cli/src/lib.rs b/utils/frame/try-runtime/cli/src/lib.rs index 04459ab5920d1..6fb4b44392546 100644 --- a/utils/frame/try-runtime/cli/src/lib.rs +++ b/utils/frame/try-runtime/cli/src/lib.rs @@ -378,7 +378,7 @@ use sp_core::{ }, storage::well_known_keys, testing::TaskExecutor, - traits::{ReadRuntimeVersion, TaskExecutorExt}, + traits::{CallContext, ReadRuntimeVersion, TaskExecutorExt}, twox_128, H256, }; use sp_externalities::Extensions; @@ -877,6 +877,7 @@ pub(crate) fn state_machine_call( extensions, &sp_state_machine::backend::BackendRuntimeCode::new(&ext.backend).runtime_code()?, sp_core::testing::TaskExecutor::new(), + CallContext::Offchain, ) .execute(sp_state_machine::ExecutionStrategy::AlwaysWasm) .map_err(|e| format!("failed to execute '{}': {}", method, e)) @@ -916,6 +917,7 @@ pub(crate) fn state_machine_call_with_proof Date: Fri, 24 Feb 2023 16:02:30 +0100 Subject: [PATCH 436/715] Automatically format ci pipeline specs with prettier (#13441) * [ci] Deduplicate variables: sections in pipeline specs The prettier yaml parser doesn't like these. * [ci] provide git clean filter to format pipeline specs * [ci] Reformat pipeline specs with prettier --- .gitattributes | 2 + .gitlab-ci.yml | 214 ++++++++++----------- scripts/ci/gitlab/pipeline/build.yml | 88 ++++----- scripts/ci/gitlab/pipeline/check.yml | 38 ++-- scripts/ci/gitlab/pipeline/publish.yml | 181 +++++++++--------- scripts/ci/gitlab/pipeline/test.yml | 230 +++++++++++------------ scripts/ci/gitlab/pipeline/zombienet.yml | 33 ++-- scripts/ci/gitlab/prettier.sh | 6 + 8 files changed, 396 insertions(+), 396 deletions(-) create mode 100755 scripts/ci/gitlab/prettier.sh diff --git a/.gitattributes b/.gitattributes index 9bd26362b0e87..1762f1a04d802 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,3 @@ Cargo.lock linguist-generated=true +/.gitlab-ci.yml filter=ci-prettier +/scripts/ci/gitlab/pipeline/*.yml filter=ci-prettier diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ab3fd84d6e9ee..12a1ff825d162 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -43,57 +43,57 @@ workflow: - if: $CI_COMMIT_BRANCH variables: - GIT_STRATEGY: fetch - GIT_DEPTH: 100 - CARGO_INCREMENTAL: 0 - 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 + GIT_STRATEGY: fetch + GIT_DEPTH: 100 + CARGO_INCREMENTAL: 0 + 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" RUSTY_CACHIER_COMPRESSION_METHOD: zstd - NEXTEST_FAILURE_OUTPUT: immediate-final - NEXTEST_SUCCESS_OUTPUT: final - ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.3.34" + NEXTEST_FAILURE_OUTPUT: immediate-final + NEXTEST_SUCCESS_OUTPUT: final + ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.3.34" -.shared-default: &shared-default +.shared-default: &shared-default retry: max: 2 when: - runner_system_failure - unknown_failure - api_failure - cache: {} + cache: {} .default-pipeline-definitions: default: - <<: *shared-default - interruptible: true + <<: *shared-default + interruptible: true .crate-publishing-pipeline-definitions: default: - <<: *shared-default + <<: *shared-default # The crate-publishing pipeline defaults to `interruptible: false` so that we'll be able to # reach and run the publishing jobs despite the "Auto-cancel redundant pipelines" CI setting. # The setting is relevant because the crate-publishing pipeline runs on `master`, thus future # pipelines on `master` (e.g. created for new commits or other schedules) might unintendedly # cancel the publishing jobs or its dependencies before we get to actually publish the crates. - interruptible: false + interruptible: false .collect-artifacts: artifacts: - name: "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}" - when: on_success - expire_in: 7 days + name: "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}" + when: on_success + expire_in: 7 days paths: - artifacts/ .collect-artifacts-short: artifacts: - name: "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}" - when: on_success - expire_in: 3 hours + name: "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}" + when: on_success + expire_in: 3 hours paths: - artifacts/ @@ -111,7 +111,7 @@ variables: - if echo "$CI_DISABLED_JOBS" | grep -xF "$CI_JOB_NAME"; then echo "The job has been cancelled in CI settings"; exit 0; fi .kubernetes-env: - image: "${CI_IMAGE}" + image: "${CI_IMAGE}" before_script: - !reference [.job-switcher, before_script] - !reference [.prepare-env, before_script] @@ -139,7 +139,7 @@ variables: dotenv: pipeline-stopper.env .docker-env: - image: "${CI_IMAGE}" + image: "${CI_IMAGE}" before_script: - !reference [.job-switcher, before_script] - !reference [.prepare-env, before_script] @@ -167,8 +167,8 @@ variables: - 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 =~ /^[0-9]+$/ # PRs + - if: $CI_COMMIT_REF_NAME =~ /^v[0-9]+\.[0-9]+.*$/ # i.e. v1.0, v2.1rc1 # handle the specific case where benches could store incorrect bench data because of the downstream staging runs # exclude cargo-check-benches from such runs @@ -179,8 +179,8 @@ variables: - 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 =~ /^[0-9]+$/ # PRs + - if: $CI_COMMIT_REF_NAME =~ /^v[0-9]+\.[0-9]+.*$/ # i.e. v1.0, v2.1rc1 .test-refs-no-trigger: rules: @@ -189,8 +189,8 @@ variables: - 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 =~ /^[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: @@ -199,7 +199,7 @@ variables: when: never - if: $CI_PIPELINE_SOURCE == "web" - if: $CI_PIPELINE_SOURCE == "schedule" - - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs + - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs .publish-refs: rules: @@ -208,7 +208,7 @@ variables: - if: $CI_PIPELINE_SOURCE == "web" - if: $CI_PIPELINE_SOURCE == "schedule" - if: $CI_COMMIT_REF_NAME == "master" - - if: $CI_COMMIT_REF_NAME =~ /^v[0-9]+\.[0-9]+.*$/ # i.e. v1.0, v2.1rc1 + - if: $CI_COMMIT_REF_NAME =~ /^v[0-9]+\.[0-9]+.*$/ # i.e. v1.0, v2.1rc1 .build-refs: # publish-refs + PRs @@ -218,8 +218,8 @@ variables: - if: $CI_PIPELINE_SOURCE == "web" - if: $CI_PIPELINE_SOURCE == "schedule" - if: $CI_COMMIT_REF_NAME == "master" - - if: $CI_COMMIT_REF_NAME =~ /^v[0-9]+\.[0-9]+.*$/ # i.e. v1.0, v2.1rc1 - - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs + - 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 @@ -231,12 +231,12 @@ variables: .crates-publishing-variables: variables: - CRATESIO_CRATES_OWNER: parity-crate-owner - REPO: substrate - REPO_OWNER: paritytech + CRATESIO_CRATES_OWNER: parity-crate-owner + REPO: substrate + REPO_OWNER: paritytech .crates-publishing-pipeline: - extends: .crates-publishing-variables + extends: .crates-publishing-variables rules: - if: $CI_PIPELINE_SOURCE == "schedule" && $CI_COMMIT_REF_NAME == "master" && $PIPELINE == "automatic-crate-publishing" @@ -247,40 +247,40 @@ variables: # collect artifacts even on failure so that we know how the crates were generated (they'll be # generated to the artifacts folder according to SPUB_TMP further down) artifacts: - name: "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}" - when: always - expire_in: 7 days + name: "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}" + when: always + expire_in: 7 days paths: - artifacts/ variables: - SPUB_TMP: artifacts + SPUB_TMP: artifacts #### stage: .pre skip-if-draft: - extends: .kubernetes-env + extends: .kubernetes-env variables: - CI_IMAGE: "paritytech/tools:latest" - stage: .pre + CI_IMAGE: "paritytech/tools:latest" + stage: .pre rules: - - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs + - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs script: - - echo "Commit message is ${CI_COMMIT_MESSAGE}" - - echo "Ref is ${CI_COMMIT_REF_NAME}" - - echo "pipeline source is ${CI_PIPELINE_SOURCE}" - - ./scripts/ci/gitlab/skip_if_draft.sh - allow_failure: true + - echo "Commit message is ${CI_COMMIT_MESSAGE}" + - echo "Ref is ${CI_COMMIT_REF_NAME}" + - echo "pipeline source is ${CI_PIPELINE_SOURCE}" + - ./scripts/ci/gitlab/skip_if_draft.sh + allow_failure: true check-crates-publishing-pipeline: - stage: .pre + stage: .pre extends: - .kubernetes-env - .crates-publishing-pipeline script: - git clone - --depth 1 - --branch "$RELENG_SCRIPTS_BRANCH" - https://github.com/paritytech/releng-scripts.git + --depth 1 + --branch "$RELENG_SCRIPTS_BRANCH" + https://github.com/paritytech/releng-scripts.git - ONLY_CHECK_PIPELINE=true ./releng-scripts/publish-crates include: @@ -314,17 +314,17 @@ include: #### stage: deploy deploy-prometheus-alerting-rules: - stage: deploy + stage: deploy needs: - - job: test-prometheus-alerting-rules - artifacts: false - allow_failure: true + - job: test-prometheus-alerting-rules + artifacts: false + allow_failure: true trigger: - project: parity/infrastructure/cloud-infra + project: parity/infrastructure/cloud-infra variables: - SUBSTRATE_CI_COMMIT_NAME: "${CI_COMMIT_REF_NAME}" - SUBSTRATE_CI_COMMIT_REF: "${CI_COMMIT_SHORT_SHA}" - UPSTREAM_TRIGGER_PROJECT: "${CI_PROJECT_PATH}" + SUBSTRATE_CI_COMMIT_NAME: "${CI_COMMIT_REF_NAME}" + SUBSTRATE_CI_COMMIT_REF: "${CI_COMMIT_SHORT_SHA}" + UPSTREAM_TRIGGER_PROJECT: "${CI_PROJECT_PATH}" rules: - if: $CI_PIPELINE_SOURCE == "pipeline" when: never @@ -339,12 +339,12 @@ deploy-prometheus-alerting-rules: # This info is later used for the cache distribution and an overlay creation. # Note that we don't use any .rusty-cachier references as we assume that a pipeline has reached this stage with working rusty-cachier. rusty-cachier-notify: - stage: notify - extends: .kubernetes-env + stage: notify + extends: .kubernetes-env variables: - CI_IMAGE: paritytech/rusty-cachier-env:latest - GIT_STRATEGY: none - dependencies: [] + 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 @@ -355,83 +355,83 @@ rusty-cachier-notify: # In a DAG, every jobs chain is executed independently of others. The `fail_fast` principle suggests # to fail the pipeline as soon as possible to shorten the feedback loop. .cancel-pipeline-template: - stage: .post + stage: .post rules: - - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs + - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs when: on_failure variables: - PROJECT_ID: "${CI_PROJECT_ID}" - PROJECT_NAME: "${CI_PROJECT_NAME}" - PIPELINE_ID: "${CI_PIPELINE_ID}" - FAILED_JOB_URL: "${FAILED_JOB_URL}" - FAILED_JOB_NAME: "${FAILED_JOB_NAME}" - PR_NUM: "${PR_NUM}" + PROJECT_ID: "${CI_PROJECT_ID}" + PROJECT_NAME: "${CI_PROJECT_NAME}" + PIPELINE_ID: "${CI_PIPELINE_ID}" + FAILED_JOB_URL: "${FAILED_JOB_URL}" + FAILED_JOB_NAME: "${FAILED_JOB_NAME}" + PR_NUM: "${PR_NUM}" trigger: - project: "parity/infrastructure/ci_cd/pipeline-stopper" + project: "parity/infrastructure/ci_cd/pipeline-stopper" remove-cancel-pipeline-message: stage: .post rules: - - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs + - 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}" + 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" + project: "parity/infrastructure/ci_cd/pipeline-stopper" + branch: "as-improve" # need to copy jobs this way because otherwise gitlab will wait # for all 3 jobs to finish instead of cancelling if one fails cancel-pipeline-test-linux-stable1: - extends: .cancel-pipeline-template + extends: .cancel-pipeline-template needs: - - job: "test-linux-stable 1/3" + - job: "test-linux-stable 1/3" cancel-pipeline-test-linux-stable2: - extends: .cancel-pipeline-template + extends: .cancel-pipeline-template needs: - - job: "test-linux-stable 2/3" + - job: "test-linux-stable 2/3" cancel-pipeline-test-linux-stable3: - extends: .cancel-pipeline-template + extends: .cancel-pipeline-template needs: - - job: "test-linux-stable 3/3" + - job: "test-linux-stable 3/3" cancel-pipeline-cargo-check-benches1: - extends: .cancel-pipeline-template + extends: .cancel-pipeline-template needs: - - job: "cargo-check-benches 1/2" + - job: "cargo-check-benches 1/2" cancel-pipeline-cargo-check-benches2: - extends: .cancel-pipeline-template + extends: .cancel-pipeline-template needs: - - job: "cargo-check-benches 2/2" + - job: "cargo-check-benches 2/2" cancel-pipeline-test-linux-stable-int: - extends: .cancel-pipeline-template + extends: .cancel-pipeline-template needs: - - job: test-linux-stable-int + - job: test-linux-stable-int cancel-pipeline-cargo-check-each-crate-1: - extends: .cancel-pipeline-template + extends: .cancel-pipeline-template needs: - - job: "cargo-check-each-crate 1/2" + - job: "cargo-check-each-crate 1/2" cancel-pipeline-cargo-check-each-crate-2: - extends: .cancel-pipeline-template + extends: .cancel-pipeline-template needs: - - job: "cargo-check-each-crate 2/2" + - job: "cargo-check-each-crate 2/2" cancel-pipeline-cargo-check-each-crate-macos: - extends: .cancel-pipeline-template + extends: .cancel-pipeline-template needs: - - job: cargo-check-each-crate-macos + - job: cargo-check-each-crate-macos cancel-pipeline-check-tracing: - extends: .cancel-pipeline-template + extends: .cancel-pipeline-template needs: - - job: check-tracing + - job: check-tracing diff --git a/scripts/ci/gitlab/pipeline/build.yml b/scripts/ci/gitlab/pipeline/build.yml index ba529569d0fc1..02f25a02a2c22 100644 --- a/scripts/ci/gitlab/pipeline/build.yml +++ b/scripts/ci/gitlab/pipeline/build.yml @@ -4,63 +4,63 @@ # PIPELINE_SCRIPTS_TAG can be found in the project variables .check-dependent-project: - stage: build + stage: build # DAG: this is artificial dependency needs: - - job: cargo-clippy - artifacts: false + - job: cargo-clippy + artifacts: false extends: - .docker-env - .test-refs-no-trigger-prs-only script: - git clone - --depth=1 - --branch="$PIPELINE_SCRIPTS_TAG" - https://github.com/paritytech/pipeline-scripts + --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" + --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 + extends: .check-dependent-project variables: - DEPENDENT_REPO: polkadot + DEPENDENT_REPO: polkadot COMPANION_OVERRIDES: | substrate: polkadot-v* polkadot: release-v* rules: - - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ #PRs + - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ #PRs check-dependent-cumulus: - extends: .check-dependent-project + extends: .check-dependent-project variables: - DEPENDENT_REPO: cumulus - EXTRA_DEPENDENCIES: polkadot + DEPENDENT_REPO: cumulus + EXTRA_DEPENDENCIES: polkadot COMPANION_OVERRIDES: | substrate: polkadot-v* polkadot: release-v* rules: - - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ #PRs + - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ #PRs build-linux-substrate: - stage: build + stage: build extends: - .collect-artifacts - .docker-env - .build-refs variables: # this variable gets overriden by "rusty-cachier environment inject", use the value as default - CARGO_TARGET_DIR: "$CI_PROJECT_DIR/target" + CARGO_TARGET_DIR: "$CI_PROJECT_DIR/target" needs: - - job: test-linux-stable - artifacts: false + - job: test-linux-stable + artifacts: false before_script: - !reference [.job-switcher, before_script] - mkdir -p ./artifacts/substrate/ @@ -74,10 +74,10 @@ build-linux-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; + echo "${CI_COMMIT_TAG}" | tee ./artifacts/substrate/VERSION; else - ./artifacts/substrate/substrate --version | - cut -d ' ' -f 2 | tee ./artifacts/substrate/VERSION; + ./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/ @@ -86,14 +86,14 @@ build-linux-substrate: - rusty-cachier cache upload .build-subkey: - stage: build + stage: build extends: - .collect-artifacts - .docker-env - .publish-refs variables: # this variable gets overriden by "rusty-cachier environment inject", use the value as default - CARGO_TARGET_DIR: "$CI_PROJECT_DIR/target" + CARGO_TARGET_DIR: "$CI_PROJECT_DIR/target" before_script: - !reference [.job-switcher, before_script] - mkdir -p ./artifacts/subkey @@ -106,17 +106,17 @@ build-linux-substrate: - 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; + 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 + extends: .build-subkey build-subkey-macos: - extends: .build-subkey + 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: @@ -129,8 +129,8 @@ build-subkey-macos: - 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; + sed -n -E 's/^subkey ([0-9.]+.*)/\1/p' | + tee ./artifacts/subkey/VERSION; - sha256sum ./artifacts/subkey/subkey | tee ./artifacts/subkey/subkey.sha256 - cp -r ./scripts/ci/docker/subkey.Dockerfile ./artifacts/subkey/ after_script: [""] @@ -138,26 +138,26 @@ build-subkey-macos: - osx build-rustdoc: - stage: build + stage: build extends: - .docker-env - .test-refs variables: - SKIP_WASM_BUILD: 1 - DOC_INDEX_PAGE: "sc_service/index.html" # default redirected page - RUSTY_CACHIER_TOOLCHAIN: nightly + 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: "$CI_PROJECT_DIR/target" + CARGO_TARGET_DIR: "$CI_PROJECT_DIR/target" artifacts: - name: "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}-doc" - when: on_success - expire_in: 7 days + name: "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}-doc" + when: on_success + expire_in: 7 days paths: - - ./crate-docs/ + - ./crate-docs/ # DAG: this is artificial dependency needs: - - job: cargo-clippy - artifacts: false + - 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/check.yml b/scripts/ci/gitlab/pipeline/check.yml index 55f0061501076..a29f31d4aa3ba 100644 --- a/scripts/ci/gitlab/pipeline/check.yml +++ b/scripts/ci/gitlab/pipeline/check.yml @@ -2,56 +2,56 @@ # Here are all jobs that are executed during "check" stage check-runtime: - stage: check + 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" + 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 + allow_failure: true check-signed-tag: - stage: check - extends: .kubernetes-env + stage: check + extends: .kubernetes-env variables: - CI_IMAGE: "paritytech/tools:latest" + 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 + - 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 + stage: check extends: - .kubernetes-env - .test-refs-no-trigger-prs-only variables: - CI_IMAGE: "paritytech/tools:latest" + CI_IMAGE: "paritytech/tools:latest" script: - ./scripts/ci/gitlab/ensure-deps.sh test-rust-features: - stage: check + stage: check extends: - .kubernetes-env - .test-refs-no-trigger-prs-only script: - git clone - --depth=1 - --branch="$PIPELINE_SCRIPTS_TAG" - https://github.com/paritytech/pipeline-scripts + --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 + stage: check + extends: .kubernetes-env variables: - CI_IMAGE: "paritytech/tools:latest" + CI_IMAGE: "paritytech/tools:latest" rules: - if: $CI_PIPELINE_SOURCE == "pipeline" when: never @@ -62,4 +62,4 @@ test-prometheus-alerting-rules: 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 + 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 index 3c280dec7325c..188a093864cc0 100644 --- a/scripts/ci/gitlab/pipeline/publish.yml +++ b/scripts/ci/gitlab/pipeline/publish.yml @@ -1,16 +1,15 @@ - # This file is part of .gitlab-ci.yml # Here are all jobs that are executed during "publish" stage .build-push-docker-image-common: extends: - .kubernetes-env - stage: publish + stage: publish variables: - CI_IMAGE: $BUILDAH_IMAGE - GIT_STRATEGY: none - DOCKERFILE: $PRODUCT.Dockerfile - IMAGE_NAME: docker.io/$IMAGE_PATH + CI_IMAGE: $BUILDAH_IMAGE + GIT_STRATEGY: none + DOCKERFILE: $PRODUCT.Dockerfile + IMAGE_NAME: docker.io/$IMAGE_PATH before_script: - !reference [.kubernetes-env, before_script] - cd ./artifacts/$PRODUCT/ @@ -19,17 +18,17 @@ - test -z "${VERSION}" && exit 1 script: - test "$DOCKER_USER" -a "$DOCKER_PASS" || - ( echo "no docker credentials provided"; exit 1 ) + ( 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" . + --format=docker + --build-arg VCS_REF="${CI_COMMIT_SHA}" + --build-arg BUILD_DATE="$(date -u '+%Y-%m-%dT%H:%M:%SZ')" + --build-arg IMAGE_NAME="${IMAGE_PATH}" + --tag "$IMAGE_NAME:$VERSION" + --tag "$IMAGE_NAME:latest" + --file "$DOCKERFILE" . - echo "$DOCKER_PASS" | - buildah login --username "$DOCKER_USER" --password-stdin docker.io + buildah login --username "$DOCKER_USER" --password-stdin docker.io - buildah info - buildah push --format=v2s2 "$IMAGE_NAME:$VERSION" - buildah push --format=v2s2 "$IMAGE_NAME:latest" @@ -45,25 +44,25 @@ - .publish-refs - .build-push-docker-image-common variables: - IMAGE_PATH: parity/$PRODUCT - DOCKER_USER: $Docker_Hub_User_Parity - DOCKER_PASS: $Docker_Hub_Pass_Parity + IMAGE_PATH: parity/$PRODUCT + DOCKER_USER: $Docker_Hub_User_Parity + DOCKER_PASS: $Docker_Hub_Pass_Parity .push-docker-image-description: - stage: publish + stage: publish extends: - .kubernetes-env - .publish-refs variables: - CI_IMAGE: paritytech/dockerhub-description - DOCKERHUB_REPOSITORY: parity/$PRODUCT - DOCKER_USERNAME: $Docker_Hub_User_Parity - DOCKER_PASSWORD: $Docker_Hub_Pass_Parity - README_FILEPATH: $CI_PROJECT_DIR/scripts/ci/docker/$PRODUCT.Dockerfile.README.md + CI_IMAGE: paritytech/dockerhub-description + DOCKERHUB_REPOSITORY: parity/$PRODUCT + DOCKER_USERNAME: $Docker_Hub_User_Parity + DOCKER_PASSWORD: $Docker_Hub_Pass_Parity + README_FILEPATH: $CI_PROJECT_DIR/scripts/ci/docker/$PRODUCT.Dockerfile.README.md rules: - - if: $CI_COMMIT_REF_NAME == "master" - changes: - - scripts/ci/docker/$PRODUCT.Dockerfile.README.md + - if: $CI_COMMIT_REF_NAME == "master" + changes: + - scripts/ci/docker/$PRODUCT.Dockerfile.README.md script: - cd / && sh entrypoint.sh @@ -73,94 +72,94 @@ - .build-refs - .build-push-docker-image-common variables: - IMAGE_PATH: paritypr/$PRODUCT - DOCKER_USER: $PARITYPR_USER - DOCKER_PASS: $PARITYPR_PASS + IMAGE_PATH: paritypr/$PRODUCT + DOCKER_USER: $PARITYPR_USER + DOCKER_PASS: $PARITYPR_PASS publish-docker-substrate: - extends: .build-push-docker-image + extends: .build-push-docker-image needs: - - job: build-linux-substrate - artifacts: true + - job: build-linux-substrate + artifacts: true variables: - PRODUCT: substrate + PRODUCT: substrate publish-docker-description-substrate: - extends: .push-docker-image-description + extends: .push-docker-image-description variables: - PRODUCT: substrate - SHORT_DESCRIPTION: "Substrate Docker Image." + PRODUCT: substrate + SHORT_DESCRIPTION: "Substrate Docker Image." publish-docker-substrate-temporary: - extends: .build-push-image-temporary + extends: .build-push-image-temporary needs: - - job: build-linux-substrate - artifacts: true + - job: build-linux-substrate + artifacts: true variables: - PRODUCT: substrate + 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 + expire_in: 24h publish-docker-subkey: - extends: .build-push-docker-image + extends: .build-push-docker-image needs: - - job: build-subkey-linux - artifacts: true + - job: build-subkey-linux + artifacts: true variables: - PRODUCT: subkey + PRODUCT: subkey publish-docker-description-subkey: - extends: .push-docker-image-description + extends: .push-docker-image-description variables: - PRODUCT: subkey - SHORT_DESCRIPTION: "The subkey program is a key management utility for Substrate-based blockchains." + PRODUCT: subkey + SHORT_DESCRIPTION: "The subkey program is a key management utility for Substrate-based blockchains." publish-s3-release: - stage: publish + stage: publish extends: - .publish-refs - .kubernetes-env needs: - - job: build-linux-substrate - artifacts: true - - job: build-subkey-linux - artifacts: true - image: paritytech/awscli:latest + - 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}" + 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 + --recursive --human-readable --summarize publish-rustdoc: - stage: publish - extends: .kubernetes-env + stage: publish + extends: .kubernetes-env variables: - CI_IMAGE: node:16 - GIT_DEPTH: 100 - RUSTDOCS_DEPLOY_REFS: "master" + 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 + - 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 + - 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. @@ -196,75 +195,75 @@ publish-rustdoc: # 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___" + echo "___Nothing to commit___" - git push origin gh-pages --force after_script: - rm -rf .git/ ./* publish-draft-release: - stage: publish - image: paritytech/tools:latest + 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 + - 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 + allow_failure: true .publish-crates-template: - stage: publish + stage: publish extends: - .crates-publishing-template - .crates-publishing-pipeline # We don't want multiple jobs racing to publish crates as it's redundant and they might overwrite # the releases of one another. Use resource_group to ensure that at most one instance of this job # is running at any given time. - resource_group: crates-publishing + resource_group: crates-publishing # crates.io currently rate limits crate publishing at 1 per minute: # https://github.com/paritytech/release-engineering/issues/123#issuecomment-1335509748 # Taking into account the 202 (as of Dec 07, 2022) publishable Substrate crates, in the worst # case, due to the rate limits alone, we'd have to wait through at least 202 minutes of delay. # Taking into account also the verification steps and extra synchronization delays after # publishing the crate, the job needs to have a much higher timeout than average. - timeout: 9h + timeout: 9h # A custom publishing environment is used for us to be able to set up protected secrets # specifically for it - environment: publish-crates + environment: publish-crates script: - rusty-cachier snapshot create - git clone - --depth 1 - --branch "$RELENG_SCRIPTS_BRANCH" - https://github.com/paritytech/releng-scripts.git + --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 + extends: .publish-crates-template # publish-crates should only be run if publish-crates-locally passes needs: - - job: check-crate-publishing - artifacts: false + - job: check-crate-publishing + artifacts: false publish-crates-manual: - extends: .publish-crates-template - when: manual - interruptible: false + extends: .publish-crates-template + when: manual + interruptible: false check-crate-publishing: - stage: publish + stage: publish extends: - .test-refs - .crates-publishing-template # When lots of crates are taken into account (for example on master where all crates are tested) # the job might take a long time, as evidenced by: # https://gitlab.parity.io/parity/mirrors/substrate/-/jobs/2269364 - timeout: 4h + timeout: 4h script: - rusty-cachier snapshot create - git clone - --depth 1 - --branch "$RELENG_SCRIPTS_BRANCH" - https://github.com/paritytech/releng-scripts.git + --depth 1 + --branch "$RELENG_SCRIPTS_BRANCH" + https://github.com/paritytech/releng-scripts.git - CRATESIO_TARGET_INSTANCE=local ./releng-scripts/publish-crates - rusty-cachier cache upload diff --git a/scripts/ci/gitlab/pipeline/test.yml b/scripts/ci/gitlab/pipeline/test.yml index 732b8c0fd699c..49dbb194fb651 100644 --- a/scripts/ci/gitlab/pipeline/test.yml +++ b/scripts/ci/gitlab/pipeline/test.yml @@ -1,29 +1,28 @@ # This file is part of .gitlab-ci.yml # Here are all jobs that are executed during "test" stage - # It's more like a check and it belongs to the previous stage, but we want to run this job with real tests in parallel find-fail-ci-phrase: - stage: test + stage: test variables: - CI_IMAGE: "paritytech/tools:latest" - ASSERT_REGEX: "FAIL-CI" - GIT_DEPTH: 1 + CI_IMAGE: "paritytech/tools:latest" + ASSERT_REGEX: "FAIL-CI" + GIT_DEPTH: 1 extends: - .kubernetes-env script: - set +e - rg --line-number --hidden --type rust --glob '!{.git,target}' "$ASSERT_REGEX" .; exit_status=$? - if [ $exit_status -eq 0 ]; then - echo "$ASSERT_REGEX was found, exiting with 1"; - exit 1; + echo "$ASSERT_REGEX was found, exiting with 1"; + exit 1; else - echo "No $ASSERT_REGEX was found, exiting with 0"; - exit 0; + echo "No $ASSERT_REGEX was found, exiting with 0"; + exit 0; fi cargo-deny: - stage: test + stage: test extends: - .docker-env - .nightly-pipeline @@ -36,16 +35,16 @@ cargo-deny: - 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 + name: $CI_COMMIT_SHORT_SHA + expire_in: 3 days + when: always paths: - deny.log # FIXME: Temporarily allow to fail. - allow_failure: true + allow_failure: true cargo-fmt: - stage: test + stage: test variables: RUSTY_CACHIER_TOOLCHAIN: nightly extends: @@ -57,11 +56,11 @@ cargo-fmt: - rusty-cachier cache upload cargo-clippy: - stage: test + stage: test # this is an artificial job dependency, for pipeline optimization using GitLab's DAGs needs: - - job: cargo-fmt - artifacts: false + - job: cargo-fmt + artifacts: false variables: RUSTY_CACHIER_TOOLCHAIN: nightly extends: @@ -73,11 +72,11 @@ cargo-clippy: - rusty-cachier cache upload cargo-check-benches: - stage: test + stage: test variables: # Override to use nightly toolchain - RUSTY_CACHIER_TOOLCHAIN: "nightly" - CI_JOB_NAME: "cargo-check-benches" + RUSTY_CACHIER_TOOLCHAIN: "nightly" + CI_JOB_NAME: "cargo-check-benches" extends: - .docker-env - .test-refs-check-benches @@ -93,11 +92,11 @@ cargo-check-benches: - | 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 +${BASE}:${BASE}; - git fetch origin +$CI_COMMIT_REF_NAME:$CI_COMMIT_REF_NAME; - git checkout ${BASE}; - git config user.email "ci@gitlab.parity.io"; - git merge $CI_COMMIT_REF_NAME --verbose --no-edit; + git fetch origin +${BASE}:${BASE}; + git fetch origin +$CI_COMMIT_REF_NAME:$CI_COMMIT_REF_NAME; + git checkout ${BASE}; + git config user.email "ci@gitlab.parity.io"; + git merge $CI_COMMIT_REF_NAME --verbose --no-edit; fi parallel: 2 script: @@ -106,18 +105,18 @@ cargo-check-benches: # 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 --locked --benches --all; - cargo run --locked --release -p node-bench -- ::trie::read::small --json - | tee ./artifacts/benches/$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA/::trie::read::small.json; - echo "___Uploading cache for rusty-cachier___"; - rusty-cachier cache upload - ;; - 2) - cargo run --locked --release -p node-bench -- ::node::import::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 + 1) + 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 --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 tags: - linux-docker-benches @@ -125,38 +124,38 @@ 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 + stage: build extends: - .docker-env - .test-refs-no-trigger-prs-only needs: # this is a DAG - - job: cargo-check-benches - artifacts: true + - job: cargo-check-benches + artifacts: true # polls artifact from master to compare with current result # need to specify both parallel jobs from master because of the bug # https://gitlab.com/gitlab-org/gitlab/-/issues/39063 - - project: $CI_PROJECT_PATH - job: "cargo-check-benches 1/2" - ref: master - artifacts: true - - project: $CI_PROJECT_PATH - job: "cargo-check-benches 2/2" - ref: master - artifacts: true + - project: $CI_PROJECT_PATH + job: "cargo-check-benches 1/2" + ref: master + artifacts: true + - project: $CI_PROJECT_PATH + job: "cargo-check-benches 2/2" + ref: master + artifacts: true variables: - CI_IMAGE: "paritytech/node-bench-regression-guard:latest" + 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' + - "node-bench-regression-guard --reference artifacts/benches/master-* + --compare-with artifacts/benches/$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA" after_script: [""] cargo-check-try-runtime: - stage: test + stage: test extends: - .docker-env - .test-refs @@ -166,18 +165,18 @@ cargo-check-try-runtime: - rusty-cachier cache upload test-deterministic-wasm: - stage: test + stage: test # this is an artificial job dependency, for pipeline optimization using GitLab's DAGs needs: - - job: cargo-check-try-runtime - artifacts: false + - job: cargo-check-try-runtime + artifacts: false extends: - .docker-env - .test-refs variables: - WASM_BUILD_NO_COLOR: 1 + WASM_BUILD_NO_COLOR: 1 # this variable gets overriden by "rusty-cachier environment inject", use the value as default - CARGO_TARGET_DIR: "$CI_PROJECT_DIR/target" + CARGO_TARGET_DIR: "$CI_PROJECT_DIR/target" script: - rusty-cachier snapshot create # build runtime @@ -195,7 +194,7 @@ test-deterministic-wasm: - rusty-cachier cache upload test-linux-stable: - stage: test + stage: test extends: - .docker-env - .test-refs @@ -203,14 +202,14 @@ test-linux-stable: 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" + 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 + 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" + CI_JOB_NAME: "test-linux-stable" parallel: 3 script: - rusty-cachier snapshot create @@ -219,30 +218,30 @@ test-linux-stable: # node-cli is excluded until https://github.com/paritytech/substrate/issues/11321 fixed - 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} + --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 + 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" + 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 + RUN_UI_TESTS: 1 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 @@ -252,19 +251,19 @@ test-frame-support: # This job runs tests that don't work with cargo-nextest in test-linux-stable test-linux-stable-extra: - stage: test + 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" + 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 + RUN_UI_TESTS: 1 script: - rusty-cachier snapshot create # Run node-cli tests @@ -277,17 +276,17 @@ test-linux-stable-extra: # This job runs all benchmarks defined in the `/bin/node/runtime` once to check that there are no errors. quick-benchmarks: - stage: test + 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" + 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 --locked --release --features runtime-benchmarks -- benchmark pallet --execution wasm --wasm-execution compiled --chain dev --pallet "*" --extrinsic "*" --steps 2 --repeat 1 @@ -295,16 +294,15 @@ quick-benchmarks: test-frame-examples-compile-to-wasm: # into one job - stage: test - variables: - RUSTY_CACHIER_TOOLCHAIN: nightly + stage: test extends: - .docker-env - .test-refs variables: + RUSTY_CACHIER_TOOLCHAIN: nightly # Enable debug assertions since we are running optimized builds for testing # but still want to have debug assertions. - RUSTFLAGS: "-Cdebug-assertions=y" + RUSTFLAGS: "-Cdebug-assertions=y" RUST_BACKTRACE: 1 script: - rusty-cachier snapshot create @@ -315,7 +313,7 @@ test-frame-examples-compile-to-wasm: - rusty-cachier cache upload test-linux-stable-int: - stage: test + stage: test extends: - .docker-env - .test-refs @@ -323,27 +321,27 @@ test-linux-stable-int: 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" + 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 + RUN_UI_TESTS: 1 script: - rusty-cachier snapshot create - WASM_BUILD_NO_COLOR=1 RUST_LOG=sync=trace,consensus=trace,client=trace,state-db=trace,db=trace,forks=trace,state_db=trace,storage_cache=trace - time cargo test -p node-cli --release --verbose --locked -- --ignored + 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 + stage: test # this is an artificial job dependency, for pipeline optimization using GitLab's DAGs needs: - - job: test-linux-stable-int - artifacts: false + - job: test-linux-stable-int + artifacts: false variables: RUSTY_CACHIER_TOOLCHAIN: nightly extends: @@ -360,20 +358,19 @@ check-tracing: # more information about this job can be found here: # https://github.com/paritytech/substrate/pull/3778 test-full-crypto-feature: - stage: test + stage: test # this is an artificial job dependency, for pipeline optimization using GitLab's DAGs needs: - - job: check-tracing - artifacts: false - variables: - RUSTY_CACHIER_TOOLCHAIN: nightly + - job: check-tracing + artifacts: false extends: - .docker-env - .test-refs variables: + RUSTY_CACHIER_TOOLCHAIN: nightly # Enable debug assertions since we are running optimized builds for testing # but still want to have debug assertions. - RUSTFLAGS: "-Cdebug-assertions=y" + RUSTFLAGS: "-Cdebug-assertions=y" RUST_BACKTRACE: 1 script: - rusty-cachier snapshot create @@ -384,22 +381,21 @@ test-full-crypto-feature: - rusty-cachier cache upload check-rustdoc: - stage: test - variables: - RUSTY_CACHIER_TOOLCHAIN: nightly + stage: test extends: - .docker-env - .test-refs variables: - SKIP_WASM_BUILD: 1 - RUSTDOCFLAGS: "-Dwarnings" + RUSTY_CACHIER_TOOLCHAIN: nightly + SKIP_WASM_BUILD: 1 + RUSTDOCFLAGS: "-Dwarnings" script: - 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 + stage: test extends: - .docker-env - .test-refs @@ -408,7 +404,7 @@ cargo-check-each-crate: 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 + CI_JOB_NAME: cargo-check-each-crate script: - rusty-cachier snapshot create - PYTHONUNBUFFERED=x time ./scripts/ci/gitlab/check-each-crate.py "$CI_NODE_INDEX" "$CI_NODE_TOTAL" @@ -427,7 +423,7 @@ cargo-check-each-crate-macos: - !reference [.rust-info-script, script] - !reference [.pipeline-stopper-vars, script] variables: - SKIP_WASM_BUILD: 1 + 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 diff --git a/scripts/ci/gitlab/pipeline/zombienet.yml b/scripts/ci/gitlab/pipeline/zombienet.yml index 3429621e4fe22..31ee510343278 100644 --- a/scripts/ci/gitlab/pipeline/zombienet.yml +++ b/scripts/ci/gitlab/pipeline/zombienet.yml @@ -11,20 +11,20 @@ - 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}" + stage: zombienet + image: "${ZOMBIENET_IMAGE}" needs: - - job: publish-docker-substrate-temporary + - job: publish-docker-substrate-temporary extends: - .kubernetes-env - .zombienet-refs variables: - GH_DIR: "https://github.com/paritytech/substrate/tree/${CI_COMMIT_SHA}/zombienet" + 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 + name: "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}" + when: always + expire_in: 2 days paths: - ./zombienet-logs after_script: @@ -39,32 +39,29 @@ zombienet-0000-block-building: - .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" - + --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" - + --github-remote-dir="${GH_DIR}/0001-basic-warp-sync" + --test="test-warp-sync.zndsl" zombienet-0002-validators-warp-sync: extends: - .zombienet-common script: - /home/nonroot/zombie-net/scripts/ci/run-test-env-manager.sh - --github-remote-dir="${GH_DIR}/0002-validators-warp-sync" - --test="test-validators-warp-sync.zndsl" - + --github-remote-dir="${GH_DIR}/0002-validators-warp-sync" + --test="test-validators-warp-sync.zndsl" zombienet-0003-block-building-warp-sync: extends: - .zombienet-common script: - /home/nonroot/zombie-net/scripts/ci/run-test-env-manager.sh - --github-remote-dir="${GH_DIR}/0003-block-building-warp-sync" - --test="test-block-building-warp-sync.zndsl" + --github-remote-dir="${GH_DIR}/0003-block-building-warp-sync" + --test="test-block-building-warp-sync.zndsl" diff --git a/scripts/ci/gitlab/prettier.sh b/scripts/ci/gitlab/prettier.sh new file mode 100755 index 0000000000000..299bbee179dca --- /dev/null +++ b/scripts/ci/gitlab/prettier.sh @@ -0,0 +1,6 @@ +#!/bin/sh + +# meant to be installed via +# git config filter.ci-prettier.clean "scripts/ci/gitlab/prettier.sh" + +prettier --parser yaml From 9526f040b487aa8642ba21450cddfbbcace9e1f2 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Sat, 25 Feb 2023 17:13:20 +0100 Subject: [PATCH 437/715] Yieldable queues for pallet `MessageQueue` (#13424) * Add Yield message processing error Signed-off-by: Oliver Tale-Yazdi * Add NoopServiceQueues Signed-off-by: Oliver Tale-Yazdi * Implement temporary error aka Yield Signed-off-by: Oliver Tale-Yazdi * Make NoopMessageProcessor generic Signed-off-by: Oliver Tale-Yazdi * Mock pausable message processor Signed-off-by: Oliver Tale-Yazdi * Test paused queues Signed-off-by: Oliver Tale-Yazdi * Integration test paused queues Signed-off-by: Oliver Tale-Yazdi * Use WeightMeter instead of weight return Signed-off-by: Oliver Tale-Yazdi * fix Signed-off-by: Oliver Tale-Yazdi * Make compile Signed-off-by: Oliver Tale-Yazdi * Add tests Signed-off-by: Oliver Tale-Yazdi * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_message_queue * Fix test Signed-off-by: Oliver Tale-Yazdi --------- Signed-off-by: Oliver Tale-Yazdi Co-authored-by: command-bot <> --- bin/node/runtime/src/lib.rs | 2 +- frame/message-queue/src/integration_test.rs | 129 ++++++++++- frame/message-queue/src/lib.rs | 55 +++-- frame/message-queue/src/mock.rs | 49 ++-- frame/message-queue/src/mock_helpers.rs | 26 ++- frame/message-queue/src/tests.rs | 119 +++++++++- frame/message-queue/src/weights.rs | 241 +++++++++++--------- frame/support/src/traits.rs | 4 +- frame/support/src/traits/messages.rs | 27 ++- 9 files changed, 479 insertions(+), 173 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index a869d309fa479..14b74425f094b 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1155,7 +1155,7 @@ 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 MessageProcessor = pallet_message_queue::mock_helpers::NoopMessageProcessor; type Size = u32; type QueueChangeHandler = (); type HeapSize = ConstU32<{ 64 * 1024 }>; diff --git a/frame/message-queue/src/integration_test.rs b/frame/message-queue/src/integration_test.rs index b89c7808613dd..255098b3b1415 100644 --- a/frame/message-queue/src/integration_test.rs +++ b/frame/message-queue/src/integration_test.rs @@ -23,7 +23,9 @@ use crate::{ mock::{ new_test_ext, CountingMessageProcessor, IntoWeight, MockedWeightInfo, NumMessagesProcessed, + SuspendedQueues, }, + mock_helpers::MessageOrigin, *, }; @@ -39,6 +41,7 @@ use sp_runtime::{ testing::Header, traits::{BlakeTwo256, IdentityLookup}, }; +use std::collections::{BTreeMap, BTreeSet}; type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; type Block = frame_system::mocking::MockBlock; @@ -100,7 +103,8 @@ impl Config for Test { /// Simulates heavy usage by enqueueing and processing large amounts of messages. /// -/// Best to run with `-r`, `RUST_LOG=info` and `RUSTFLAGS='-Cdebug-assertions=y'`. +/// Best to run with `RUST_LOG=info RUSTFLAGS='-Cdebug-assertions=y' cargo test -r -p +/// pallet-message-queue -- --ignored`. /// /// # Example output /// @@ -130,29 +134,131 @@ fn stress_test_enqueue_and_service() { let mut msgs_remaining = 0; for _ in 0..blocks { // Start by enqueuing a large number of messages. - let (enqueued, _) = + 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. + process_some_messages(processed); // This also advances the block. msgs_remaining -= processed; } log::info!("Processing all remaining {} messages", msgs_remaining); - process_messages(msgs_remaining); + process_all_messages(msgs_remaining); post_conditions(); }); } +/// Simulates heavy usage of the suspension logic via `Yield`. +/// +/// Best to run with `RUST_LOG=info RUSTFLAGS='-Cdebug-assertions=y' cargo test -r -p +/// pallet-message-queue -- --ignored`. +/// +/// # Example output +/// +/// ```pre +/// Enqueued 11776 messages across 2526 queues. Payload 173.94 KiB +/// Suspended 63 and resumed 7 queues of 2526 in total +/// Processing 593 messages. Resumed msgs: 11599, All msgs: 11776 +/// Enqueued 30104 messages across 5533 queues. Payload 416.62 KiB +/// Suspended 24 and resumed 15 queues of 5533 in total +/// Processing 12841 messages. Resumed msgs: 40857, All msgs: 41287 +/// Processing all 28016 remaining resumed messages +/// Resumed all 64 suspended queues +/// Processing all remaining 430 messages +/// ``` +#[test] +#[ignore] // Only run in the CI. +fn stress_test_queue_suspension() { + let blocks = 20; + let max_queues = 10_000; + let max_messages_per_queue = 10_000; + let (max_suspend_per_block, max_resume_per_block) = (100, 50); + let max_msg_len = MaxMessageLenOf::::get(); + let mut rng = StdRng::seed_from_u64(41); + + new_test_ext::().execute_with(|| { + let mut suspended = BTreeSet::::new(); + 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; + let per_queue = msgs_per_queue(); + + // Suspend a random subset of queues. + let to_suspend = rng.gen_range(0..max_suspend_per_block).min(per_queue.len()); + for _ in 0..to_suspend { + let q = rng.gen_range(0..per_queue.len()); + suspended.insert(*per_queue.iter().nth(q).map(|(q, _)| q).unwrap()); + } + // Resume a random subst of suspended queues. + let to_resume = rng.gen_range(0..max_resume_per_block).min(suspended.len()); + for _ in 0..to_resume { + let q = rng.gen_range(0..suspended.len()); + suspended.remove(&suspended.iter().nth(q).unwrap().clone()); + } + log::info!( + "Suspended {} and resumed {} queues of {} in total", + to_suspend, + to_resume, + per_queue.len() + ); + SuspendedQueues::set(suspended.iter().map(|q| MessageOrigin::Everywhere(*q)).collect()); + + // Pick a fraction of all messages currently in queue and process them. + let resumed_messages = + per_queue.iter().filter(|(q, _)| !suspended.contains(q)).map(|(_, n)| n).sum(); + let processed = rng.gen_range(1..=resumed_messages); + log::info!( + "Processing {} messages. Resumed msgs: {}, All msgs: {}", + processed, + resumed_messages, + msgs_remaining + ); + process_some_messages(processed); // This also advances the block. + msgs_remaining -= processed; + } + let per_queue = msgs_per_queue(); + let resumed_messages = + per_queue.iter().filter(|(q, _)| !suspended.contains(q)).map(|(_, n)| n).sum(); + log::info!("Processing all {} remaining resumed messages", resumed_messages); + process_all_messages(resumed_messages); + msgs_remaining -= resumed_messages; + + let resumed = SuspendedQueues::take(); + log::info!("Resumed all {} suspended queues", resumed.len()); + log::info!("Processing all remaining {} messages", msgs_remaining); + process_all_messages(msgs_remaining); + post_conditions(); + }); +} + +/// How many messages are in each queue. +fn msgs_per_queue() -> BTreeMap { + let mut per_queue = BTreeMap::new(); + for (o, q) in BookStateFor::::iter() { + let MessageOrigin::Everywhere(o) = o else { + unreachable!(); + }; + per_queue.insert(o, q.message_count as u32); + } + per_queue +} + /// Enqueue a random number of random messages into a random number of queues. +/// +/// Returns the total number of enqueued messages, their combined length and the number of messages +/// per queue. fn enqueue_messages( max_queues: u32, max_per_queue: u32, max_msg_len: u32, rng: &mut StdRng, -) -> (u32, usize) { +) -> u32 { let num_queues = rng.gen_range(1..max_queues); let mut num_messages = 0; let mut total_msg_len = 0; @@ -179,11 +285,11 @@ fn enqueue_messages( num_queues, total_msg_len as f64 / 1024.0 ); - (num_messages, total_msg_len as usize) + num_messages } /// Process the number of messages. -fn process_messages(num_msgs: u32) { +fn process_some_messages(num_msgs: u32) { let weight = (num_msgs as u64).into_weight(); ServiceWeight::set(Some(weight)); let consumed = next_block(); @@ -192,6 +298,15 @@ fn process_messages(num_msgs: u32) { assert_eq!(NumMessagesProcessed::take(), num_msgs as usize); } +/// Process all remaining messages and assert their number. +fn process_all_messages(expected: u32) { + ServiceWeight::set(Some(Weight::MAX)); + let consumed = next_block(); + + assert_eq!(consumed, Weight::from_all(expected as u64)); + assert_eq!(NumMessagesProcessed::take(), expected as usize); +} + /// Returns the weight consumed by `MessageQueue::on_initialize()`. fn next_block() -> Weight { MessageQueue::on_finalize(System::block_number()); diff --git a/frame/message-queue/src/lib.rs b/frame/message-queue/src/lib.rs index 2b64e3fc9b174..6c264be3c834e 100644 --- a/frame/message-queue/src/lib.rs +++ b/frame/message-queue/src/lib.rs @@ -533,6 +533,11 @@ pub mod pallet { Queued, /// There is temporarily not enough weight to continue servicing messages. InsufficientWeight, + /// This message is temporarily unprocessable. + /// + /// Such errors are expected, but not guaranteed, to resolve themselves eventually through + /// retrying. + TemporarilyUnprocessable, } /// The index of the first and last (non-empty) pages. @@ -588,6 +593,9 @@ pub mod pallet { /// Execute an overweight message. /// + /// Temporary processing errors will be propagated whereas permanent errors are treated + /// as success condition. + /// /// - `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. @@ -621,6 +629,10 @@ pub mod pallet { enum PageExecutionStatus { /// The execution bailed because there was not enough weight remaining. Bailed, + /// The page did not make any progress on its execution. + /// + /// This is a transient condition and can be handled by retrying - exactly like [Bailed]. + NoProgress, /// No more messages could be loaded. This does _not_ imply `page.is_complete()`. /// /// The reasons for this status are: @@ -634,6 +646,10 @@ enum PageExecutionStatus { enum ItemExecutionStatus { /// The execution bailed because there was not enough weight remaining. Bailed, + /// The item did not make any progress on its execution. + /// + /// This is a transient condition and can be handled by retrying - exactly like [Bailed]. + NoProgress, /// The item was not found. NoItem, /// Whether the execution of an item resulted in it being processed. @@ -651,8 +667,8 @@ enum MessageExecutionStatus { Overweight, /// The message was processed successfully. Processed, - /// The message was processed and resulted in a permanent error. - Unprocessable, + /// The message was processed and resulted in a, possibly permanent, error. + Unprocessable { permanent: bool }, } impl Pallet { @@ -814,7 +830,8 @@ impl Pallet { // additional overweight event being deposited. ) { Overweight | InsufficientWeight => Err(Error::::InsufficientWeight), - Unprocessable | Processed => { + Unprocessable { permanent: false } => Err(Error::::TemporarilyUnprocessable), + Unprocessable { permanent: true } | Processed => { page.note_processed_at_pos(pos); book_state.message_count.saturating_dec(); book_state.size.saturating_reduce(payload_len); @@ -921,6 +938,7 @@ impl Pallet { weight: &mut WeightMeter, overweight_limit: Weight, ) -> (bool, Option>) { + use PageExecutionStatus::*; if !weight.check_accrue( T::WeightInfo::service_queue_base().saturating_add(T::WeightInfo::ready_ring_unknit()), ) { @@ -936,9 +954,9 @@ impl Pallet { total_processed.saturating_accrue(processed); match status { // Store the page progress and do not go to the next one. - PageExecutionStatus::Bailed => break, + Bailed | NoProgress => break, // Go to the next page if this one is at the end. - PageExecutionStatus::NoMore => (), + NoMore => (), }; book_state.begin.saturating_inc(); } @@ -1003,6 +1021,7 @@ impl Pallet { ) { Bailed => break PageExecutionStatus::Bailed, NoItem => break PageExecutionStatus::NoMore, + NoProgress => break PageExecutionStatus::NoProgress, // Keep going as long as we make progress... Executed(true) => total_processed.saturating_inc(), Executed(false) => (), @@ -1053,7 +1072,8 @@ impl Pallet { overweight_limit, ) { InsufficientWeight => return ItemExecutionStatus::Bailed, - Processed | Unprocessable => true, + Unprocessable { permanent: false } => return ItemExecutionStatus::NoProgress, + Processed | Unprocessable { permanent: true } => true, Overweight => false, }; @@ -1125,12 +1145,14 @@ impl Pallet { page_index: PageIndex, message_index: T::Size, message: &[u8], - weight: &mut WeightMeter, + meter: &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()) { + use ProcessMessageError::*; + let prev_consumed = meter.consumed; + + match T::MessageProcessor::process_message(message, origin.clone(), meter) { Err(Overweight(w)) if w.any_gt(overweight_limit) => { // Permanently overweight. Self::deposit_event(Event::::OverweightEnqueued { @@ -1146,16 +1168,19 @@ impl Pallet { // queue. MessageExecutionStatus::InsufficientWeight }, - Err(error) => { + Err(Yield) => { + // Processing should be reattempted later. + MessageExecutionStatus::Unprocessable { permanent: false } + }, + Err(error @ BadFormat | error @ Corrupt | error @ Unsupported) => { // Permanent error - drop Self::deposit_event(Event::::ProcessingFailed { hash, origin, error }); - MessageExecutionStatus::Unprocessable + MessageExecutionStatus::Unprocessable { permanent: true } }, - Ok((success, weight_used)) => { + Ok(success) => { // Success - weight.defensive_saturating_accrue(weight_used); - let event = Event::::Processed { hash, origin, weight_used, success }; - Self::deposit_event(event); + let weight_used = meter.consumed.saturating_sub(prev_consumed); + Self::deposit_event(Event::::Processed { hash, origin, weight_used, success }); MessageExecutionStatus::Processed }, } diff --git a/frame/message-queue/src/mock.rs b/frame/message-queue/src/mock.rs index 8817ebc3531ed..28a599bcf83c6 100644 --- a/frame/message-queue/src/mock.rs +++ b/frame/message-queue/src/mock.rs @@ -154,6 +154,7 @@ impl crate::weights::WeightInfo for MockedWeightInfo { parameter_types! { pub static MessagesProcessed: Vec<(Vec, MessageOrigin)> = vec![]; + pub static SuspendedQueues: Vec = vec![]; } /// A message processor which records all processed messages into [`MessagesProcessed`]. @@ -170,9 +171,9 @@ impl ProcessMessage for RecordingMessageProcessor { fn process_message( message: &[u8], origin: Self::Origin, - weight_limit: Weight, - ) -> Result<(bool, Weight), ProcessMessageError> { - processing_message(message)?; + meter: &mut WeightMeter, + ) -> Result { + processing_message(message, &origin)?; let weight = if message.starts_with(&b"weight="[..]) { let mut w: u64 = 0; @@ -187,22 +188,26 @@ impl ProcessMessage for RecordingMessageProcessor { } else { 1 }; - let weight = Weight::from_parts(weight, weight); + let required = Weight::from_parts(weight, weight); - if weight.all_lte(weight_limit) { + if meter.check_accrue(required) { let mut m = MessagesProcessed::get(); m.push((message.to_vec(), origin)); MessagesProcessed::set(m); - Ok((true, weight)) + Ok(true) } else { - Err(ProcessMessageError::Overweight(weight)) + Err(ProcessMessageError::Overweight(required)) } } } -/// 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> { +/// Processed a mocked message. Messages that end with `badformat`, `corrupt`, `unsupported` or +/// `yield` will fail with an error respectively. +fn processing_message(msg: &[u8], origin: &MessageOrigin) -> Result<(), ProcessMessageError> { + if SuspendedQueues::get().contains(&origin) { + return Err(ProcessMessageError::Yield) + } + let msg = String::from_utf8_lossy(msg); if msg.ends_with("badformat") { Err(ProcessMessageError::BadFormat) @@ -210,6 +215,8 @@ fn processing_message(msg: &[u8]) -> Result<(), ProcessMessageError> { Err(ProcessMessageError::Corrupt) } else if msg.ends_with("unsupported") { Err(ProcessMessageError::Unsupported) + } else if msg.ends_with("yield") { + Err(ProcessMessageError::Yield) } else { Ok(()) } @@ -230,20 +237,20 @@ impl ProcessMessage for CountingMessageProcessor { fn process_message( message: &[u8], - _origin: Self::Origin, - weight_limit: Weight, - ) -> Result<(bool, Weight), ProcessMessageError> { - if let Err(e) = processing_message(message) { + origin: Self::Origin, + meter: &mut WeightMeter, + ) -> Result { + if let Err(e) = processing_message(message, &origin) { NumMessagesErrored::set(NumMessagesErrored::get() + 1); return Err(e) } - let weight = Weight::from_parts(1, 1); + let required = Weight::from_parts(1, 1); - if weight.all_lte(weight_limit) { + if meter.check_accrue(required) { NumMessagesProcessed::set(NumMessagesProcessed::get() + 1); - Ok((true, weight)) + Ok(true) } else { - Err(ProcessMessageError::Overweight(weight)) + Err(ProcessMessageError::Overweight(required)) } } } @@ -285,7 +292,11 @@ pub fn set_weight(name: &str, w: Weight) { /// Assert that exactly these pages are present. Assumes `Here` origin. pub fn assert_pages(indices: &[u32]) { - assert_eq!(Pages::::iter().count(), indices.len()); + assert_eq!( + Pages::::iter_keys().count(), + indices.len(), + "Wrong number of pages in the queue" + ); for i in indices { assert!(Pages::::contains_key(MessageOrigin::Here, i)); } diff --git a/frame/message-queue/src/mock_helpers.rs b/frame/message-queue/src/mock_helpers.rs index 64fc70057cca4..716a60782ec7f 100644 --- a/frame/message-queue/src/mock_helpers.rs +++ b/frame/message-queue/src/mock_helpers.rs @@ -47,22 +47,28 @@ impl From for MessageOrigin { } } -/// Processes any message and consumes (1, 1) weight per message. -pub struct NoopMessageProcessor; -impl ProcessMessage for NoopMessageProcessor { - type Origin = MessageOrigin; +/// Processes any message and consumes `(REQUIRED_WEIGHT, REQUIRED_WEIGHT)` weight. +/// +/// Returns [ProcessMessageError::Overweight] error if the weight limit is not sufficient. +pub struct NoopMessageProcessor(PhantomData); +impl ProcessMessage + for NoopMessageProcessor +where + Origin: codec::FullCodec + MaxEncodedLen + Clone + Eq + PartialEq + TypeInfo + Debug, +{ + type Origin = Origin; fn process_message( _message: &[u8], _origin: Self::Origin, - weight_limit: Weight, - ) -> Result<(bool, Weight), ProcessMessageError> { - let weight = Weight::from_parts(1, 1); + meter: &mut WeightMeter, + ) -> Result { + let required = Weight::from_parts(REQUIRED_WEIGHT, REQUIRED_WEIGHT); - if weight.all_lte(weight_limit) { - Ok((true, weight)) + if meter.check_accrue(required) { + Ok(true) } else { - Err(ProcessMessageError::Overweight(weight)) + Err(ProcessMessageError::Overweight(required)) } } } diff --git a/frame/message-queue/src/tests.rs b/frame/message-queue/src/tests.rs index f4cbd81ac6667..d3b0555f281f7 100644 --- a/frame/message-queue/src/tests.rs +++ b/frame/message-queue/src/tests.rs @@ -171,8 +171,9 @@ fn service_queues_failing_messages_works() { 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]); + MessageQueue::enqueue_message(msg("yield"), Here); + // Starts with four pages. + assert_pages(&[0, 1, 2, 3]); assert_eq!(MessageQueue::service_queues(1.into_weight()), 1.into_weight()); assert_last_event::( @@ -201,8 +202,65 @@ fn service_queues_failing_messages_works() { } .into(), ); - // All pages removed. - assert_pages(&[]); + assert_eq!(MessageQueue::service_queues(1.into_weight()), 1.into_weight()); + assert_eq!(System::events().len(), 3); + // Last page with the `yield` stays in. + assert_pages(&[3]); + }); +} + +#[test] +fn service_queues_suspension_works() { + use MessageOrigin::*; + new_test_ext::().execute_with(|| { + MessageQueue::enqueue_messages(vec![msg("a"), msg("b"), msg("c")].into_iter(), Here); + MessageQueue::enqueue_messages(vec![msg("x"), msg("y"), msg("z")].into_iter(), There); + MessageQueue::enqueue_messages( + vec![msg("m"), msg("n"), msg("o")].into_iter(), + Everywhere(0), + ); + assert_eq!(QueueChanges::take(), vec![(Here, 3, 3), (There, 3, 3), (Everywhere(0), 3, 3)]); + + // 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, 2)]); + + // Pause queue `Here` and `Everywhere(0)`. + SuspendedQueues::set(vec![Here, Everywhere(0)]); + + // Service one message from `There`. + 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, 2)]); + + // Now it would normally swap to `Everywhere(0)` and `Here`, but they are paused so we + // expect `There` again. + assert_eq!(MessageQueue::service_queues(2.into_weight()), 2.into_weight()); + assert_eq!(MessagesProcessed::take(), vec![(vmsg("y"), There), (vmsg("z"), There)]); + + // Processing with max-weight won't do anything. + assert_eq!(MessageQueue::service_queues(Weight::MAX), Weight::zero()); + assert_eq!(MessageQueue::service_queues(Weight::MAX), Weight::zero()); + + // ... until we resume `Here`: + SuspendedQueues::set(vec![Everywhere(0)]); + assert_eq!(MessageQueue::service_queues(Weight::MAX), 2.into_weight()); + assert_eq!(MessagesProcessed::take(), vec![(vmsg("b"), Here), (vmsg("c"), Here)]); + + // Everywhere still won't move. + assert_eq!(MessageQueue::service_queues(Weight::MAX), Weight::zero()); + SuspendedQueues::take(); + // Resume `Everywhere(0)` makes it work. + assert_eq!(MessageQueue::service_queues(Weight::MAX), 3.into_weight()); + assert_eq!( + MessagesProcessed::take(), + vec![ + (vmsg("m"), Everywhere(0)), + (vmsg("n"), Everywhere(0)), + (vmsg("o"), Everywhere(0)) + ] + ); }); } @@ -379,7 +437,7 @@ fn service_page_works() { assert_eq!(status, Bailed); } } - assert!(!Pages::::contains_key(Here, 0), "The page got removed"); + assert_pages(&[]); }); } @@ -445,6 +503,57 @@ fn service_page_item_bails() { }); } +#[test] +fn service_page_suspension_works() { + use super::integration_test::Test; // Run with larger page size. + use MessageOrigin::*; + use PageExecutionStatus::*; + + new_test_ext::().execute_with(|| { + 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); + + // First we process 5 messages from this page. + let mut meter = WeightMeter::from_limit(5.into_weight()); + let (_, status) = + crate::Pallet::::service_page(&Here, &mut book, &mut meter, Weight::MAX); + + assert_eq!(NumMessagesProcessed::take(), 5); + assert!(meter.remaining().is_zero()); + assert_eq!(status, Bailed); // It bailed since weight is missing. + msgs -= 5; + + // Then we pause the queue. + SuspendedQueues::set(vec![Here]); + // Noting happens... + for _ in 0..5 { + let (_, status) = crate::Pallet::::service_page( + &Here, + &mut book, + &mut WeightMeter::max_limit(), + Weight::MAX, + ); + assert_eq!(status, NoProgress); + assert!(NumMessagesProcessed::take().is_zero()); + } + + // Resume and process all remaining. + SuspendedQueues::take(); + let (_, status) = crate::Pallet::::service_page( + &Here, + &mut book, + &mut WeightMeter::max_limit(), + Weight::MAX, + ); + assert_eq!(status, NoMore); + assert_eq!(NumMessagesProcessed::take(), msgs); + + assert!(Pages::::iter_keys().count().is_zero()); + }); +} + #[test] fn bump_service_head_works() { use MessageOrigin::*; diff --git a/frame/message-queue/src/weights.rs b/frame/message-queue/src/weights.rs index be2f801f195a9..b48cf811a17ef 100644 --- a/frame/message-queue/src/weights.rs +++ b/frame/message-queue/src/weights.rs @@ -18,25 +18,26 @@ //! Autogenerated weights for pallet_message_queue //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-02-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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 // --steps=50 // --repeat=20 -// --pallet=pallet_message_queue // --extrinsic=* // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/message-queue/src/weights.rs +// --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)] @@ -64,61 +65,66 @@ pub trait WeightInfo { pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { /// Storage: MessageQueue ServiceHead (r:1 w:0) - /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: MessageQueue BookStateFor (r:2 w:2) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) fn ready_ring_knit() -> Weight { // Proof Size summary in bytes: - // Measured: `837` - // Estimated: `5554` - // Minimum execution time: 12_676 nanoseconds. - Weight::from_parts(13_113_000, 5554) + // Measured: `829` + // Estimated: `5547` + // Minimum execution time: 15_241 nanoseconds. + Weight::from_ref_time(15_603_000) + .saturating_add(Weight::from_proof_size(5547)) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: MessageQueue BookStateFor (r:2 w:2) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: MessageQueue ServiceHead (r:1 w:1) - /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn ready_ring_unknit() -> Weight { // Proof Size summary in bytes: - // Measured: `837` - // Estimated: `5554` - // Minimum execution time: 12_654 nanoseconds. - Weight::from_parts(12_969_000, 5554) + // Measured: `829` + // Estimated: `5547` + // Minimum execution time: 14_652 nanoseconds. + Weight::from_ref_time(14_983_000) + .saturating_add(Weight::from_proof_size(5547)) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) fn service_queue_base() -> Weight { // Proof Size summary in bytes: // Measured: `576` - // Estimated: `2527` - // Minimum execution time: 5_096 nanoseconds. - Weight::from_parts(5_280_000, 2527) + // Estimated: `2524` + // Minimum execution time: 5_750 nanoseconds. + Weight::from_ref_time(6_003_000) + .saturating_add(Weight::from_proof_size(2524)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65584), added: 68059, mode: MaxEncodedLen) fn service_page_base_completion() -> Weight { // Proof Size summary in bytes: - // Measured: `648` - // Estimated: `68060` - // Minimum execution time: 7_291 nanoseconds. - Weight::from_parts(7_564_000, 68060) + // Measured: `647` + // Estimated: `68059` + // Minimum execution time: 8_257 nanoseconds. + Weight::from_ref_time(8_506_000) + .saturating_add(Weight::from_proof_size(68059)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65584), added: 68059, mode: MaxEncodedLen) fn service_page_base_no_completion() -> Weight { // Proof Size summary in bytes: - // Measured: `648` - // Estimated: `68060` - // Minimum execution time: 7_401 nanoseconds. - Weight::from_parts(7_681_000, 68060) + // Measured: `647` + // Estimated: `68059` + // Minimum execution time: 8_422 nanoseconds. + Weight::from_ref_time(8_589_000) + .saturating_add(Weight::from_proof_size(68059)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -126,58 +132,63 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `972` // Estimated: `0` - // Minimum execution time: 79_412 nanoseconds. - Weight::from_ref_time(79_816_000) + // Minimum execution time: 81_929 nanoseconds. + Weight::from_ref_time(82_375_000) + .saturating_add(Weight::from_proof_size(0)) } /// Storage: MessageQueue ServiceHead (r:1 w:1) - /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: MessageQueue BookStateFor (r:1 w:0) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) fn bump_service_head() -> Weight { // Proof Size summary in bytes: - // Measured: `712` - // Estimated: `3027` - // Minimum execution time: 8_258 nanoseconds. - Weight::from_parts(8_438_000, 3027) + // Measured: `706` + // Estimated: `3023` + // Minimum execution time: 8_992 nanoseconds. + Weight::from_ref_time(9_200_000) + .saturating_add(Weight::from_proof_size(3023)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65584), added: 68059, mode: MaxEncodedLen) fn reap_page() -> Weight { // Proof Size summary in bytes: - // Measured: `66827` - // Estimated: `70587` - // Minimum execution time: 61_361 nanoseconds. - Weight::from_parts(62_103_000, 70587) + // Measured: `66825` + // Estimated: `70583` + // Minimum execution time: 68_292 nanoseconds. + Weight::from_ref_time(69_108_000) + .saturating_add(Weight::from_proof_size(70583)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65584), added: 68059, mode: MaxEncodedLen) fn execute_overweight_page_removed() -> Weight { // Proof Size summary in bytes: - // Measured: `66827` - // Estimated: `70587` - // Minimum execution time: 75_153 nanoseconds. - Weight::from_parts(76_093_000, 70587) + // Measured: `66825` + // Estimated: `70583` + // Minimum execution time: 83_855 nanoseconds. + Weight::from_ref_time(84_946_000) + .saturating_add(Weight::from_proof_size(70583)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65584), added: 68059, mode: MaxEncodedLen) fn execute_overweight_page_updated() -> Weight { // Proof Size summary in bytes: - // Measured: `66827` - // Estimated: `70587` - // Minimum execution time: 88_272 nanoseconds. - Weight::from_parts(89_373_000, 70587) + // Measured: `66825` + // Estimated: `70583` + // Minimum execution time: 96_997 nanoseconds. + Weight::from_ref_time(98_668_000) + .saturating_add(Weight::from_proof_size(70583)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -186,61 +197,66 @@ impl WeightInfo for SubstrateWeight { // For backwards compatibility and tests impl WeightInfo for () { /// Storage: MessageQueue ServiceHead (r:1 w:0) - /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: MessageQueue BookStateFor (r:2 w:2) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) fn ready_ring_knit() -> Weight { // Proof Size summary in bytes: - // Measured: `837` - // Estimated: `5554` - // Minimum execution time: 12_676 nanoseconds. - Weight::from_parts(13_113_000, 5554) + // Measured: `829` + // Estimated: `5547` + // Minimum execution time: 15_241 nanoseconds. + Weight::from_ref_time(15_603_000) + .saturating_add(Weight::from_proof_size(5547)) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: MessageQueue BookStateFor (r:2 w:2) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: MessageQueue ServiceHead (r:1 w:1) - /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn ready_ring_unknit() -> Weight { // Proof Size summary in bytes: - // Measured: `837` - // Estimated: `5554` - // Minimum execution time: 12_654 nanoseconds. - Weight::from_parts(12_969_000, 5554) + // Measured: `829` + // Estimated: `5547` + // Minimum execution time: 14_652 nanoseconds. + Weight::from_ref_time(14_983_000) + .saturating_add(Weight::from_proof_size(5547)) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) fn service_queue_base() -> Weight { // Proof Size summary in bytes: // Measured: `576` - // Estimated: `2527` - // Minimum execution time: 5_096 nanoseconds. - Weight::from_parts(5_280_000, 2527) + // Estimated: `2524` + // Minimum execution time: 5_750 nanoseconds. + Weight::from_ref_time(6_003_000) + .saturating_add(Weight::from_proof_size(2524)) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65584), added: 68059, mode: MaxEncodedLen) fn service_page_base_completion() -> Weight { // Proof Size summary in bytes: - // Measured: `648` - // Estimated: `68060` - // Minimum execution time: 7_291 nanoseconds. - Weight::from_parts(7_564_000, 68060) + // Measured: `647` + // Estimated: `68059` + // Minimum execution time: 8_257 nanoseconds. + Weight::from_ref_time(8_506_000) + .saturating_add(Weight::from_proof_size(68059)) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65584), added: 68059, mode: MaxEncodedLen) fn service_page_base_no_completion() -> Weight { // Proof Size summary in bytes: - // Measured: `648` - // Estimated: `68060` - // Minimum execution time: 7_401 nanoseconds. - Weight::from_parts(7_681_000, 68060) + // Measured: `647` + // Estimated: `68059` + // Minimum execution time: 8_422 nanoseconds. + Weight::from_ref_time(8_589_000) + .saturating_add(Weight::from_proof_size(68059)) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -248,58 +264,63 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `972` // Estimated: `0` - // Minimum execution time: 79_412 nanoseconds. - Weight::from_ref_time(79_816_000) + // Minimum execution time: 81_929 nanoseconds. + Weight::from_ref_time(82_375_000) + .saturating_add(Weight::from_proof_size(0)) } /// Storage: MessageQueue ServiceHead (r:1 w:1) - /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: MessageQueue BookStateFor (r:1 w:0) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) fn bump_service_head() -> Weight { // Proof Size summary in bytes: - // Measured: `712` - // Estimated: `3027` - // Minimum execution time: 8_258 nanoseconds. - Weight::from_parts(8_438_000, 3027) + // Measured: `706` + // Estimated: `3023` + // Minimum execution time: 8_992 nanoseconds. + Weight::from_ref_time(9_200_000) + .saturating_add(Weight::from_proof_size(3023)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65584), added: 68059, mode: MaxEncodedLen) fn reap_page() -> Weight { // Proof Size summary in bytes: - // Measured: `66827` - // Estimated: `70587` - // Minimum execution time: 61_361 nanoseconds. - Weight::from_parts(62_103_000, 70587) + // Measured: `66825` + // Estimated: `70583` + // Minimum execution time: 68_292 nanoseconds. + Weight::from_ref_time(69_108_000) + .saturating_add(Weight::from_proof_size(70583)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65584), added: 68059, mode: MaxEncodedLen) fn execute_overweight_page_removed() -> Weight { // Proof Size summary in bytes: - // Measured: `66827` - // Estimated: `70587` - // Minimum execution time: 75_153 nanoseconds. - Weight::from_parts(76_093_000, 70587) + // Measured: `66825` + // Estimated: `70583` + // Minimum execution time: 83_855 nanoseconds. + Weight::from_ref_time(84_946_000) + .saturating_add(Weight::from_proof_size(70583)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65584), added: 68059, mode: MaxEncodedLen) fn execute_overweight_page_updated() -> Weight { // Proof Size summary in bytes: - // Measured: `66827` - // Estimated: `70587` - // Minimum execution time: 88_272 nanoseconds. - Weight::from_parts(89_373_000, 70587) + // Measured: `66825` + // Estimated: `70583` + // Minimum execution time: 96_997 nanoseconds. + Weight::from_ref_time(98_668_000) + .saturating_add(Weight::from_proof_size(70583)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index a649dad40078d..da8efe6afc483 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -114,8 +114,8 @@ pub use preimages::{Bounded, BoundedInline, FetchResult, Hash, QueryPreimage, St mod messages; pub use messages::{ - EnqueueMessage, ExecuteOverweightError, Footprint, ProcessMessage, ProcessMessageError, - ServiceQueues, + EnqueueMessage, ExecuteOverweightError, Footprint, NoopServiceQueues, ProcessMessage, + ProcessMessageError, ServiceQueues, TransformOrigin, }; #[cfg(feature = "try-runtime")] diff --git a/frame/support/src/traits/messages.rs b/frame/support/src/traits/messages.rs index 637aa7fdc045b..781da3ed6c704 100644 --- a/frame/support/src/traits/messages.rs +++ b/frame/support/src/traits/messages.rs @@ -22,7 +22,7 @@ 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; +use sp_weights::{Weight, WeightMeter}; /// Errors that can happen when attempting to process a message with /// [`ProcessMessage::process_message()`]. @@ -38,6 +38,13 @@ pub enum ProcessMessageError { /// would be respected. The parameter gives the maximum weight which the message could take /// to process. Overweight(Weight), + /// The queue wants to give up its current processing slot. + /// + /// Hints the message processor to cease servicing this queue and proceed to the next + /// one. This is seen as a *hint*, not an instruction. Implementations must therefore handle + /// the case that a queue is re-serviced within the same block after *yielding*. A queue is + /// not required to *yield* again when it is being re-serviced withing the same block. + Yield, } /// Can process messages from a specific origin. @@ -45,12 +52,14 @@ 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. + /// Process the given message, using no more than the remaining `meter` weight to do so. + /// + /// Returns whether the message was processed. fn process_message( message: &[u8], origin: Self::Origin, - weight_limit: Weight, - ) -> Result<(bool, Weight), ProcessMessageError>; + meter: &mut WeightMeter, + ) -> Result; } /// Errors that can happen when attempting to execute an overweight message with @@ -85,6 +94,16 @@ pub trait ServiceQueues { } } +/// Services queues by doing nothing. +pub struct NoopServiceQueues(PhantomData); +impl ServiceQueues for NoopServiceQueues { + type OverweightMessageAddress = OverweightAddr; + + fn service_queues(_: Weight) -> Weight { + Weight::zero() + } +} + /// The resource footprint of a queue. #[derive(Default, Copy, Clone, Eq, PartialEq, RuntimeDebug)] pub struct Footprint { From 3d8a0255994d0094342d88b9ce87cd97a15f647e Mon Sep 17 00:00:00 2001 From: Liu-Cheng Xu Date: Mon, 27 Feb 2023 17:02:54 +0800 Subject: [PATCH 438/715] Support the subscription of every imported block (#13372) * Support the subscription of every import block Close #13315 * Clean up any closed block import notification sinks * Apply review suggestions * Nit * `every_block_import_notification_sinks` -> `every_import_notification_sinks` * Apply review suggestions --- client/api/src/backend.rs | 15 +++ client/api/src/client.rs | 10 +- .../merkle-mountain-range/src/test_utils.rs | 4 + client/service/src/client/client.rs | 122 +++++++++++++----- 4 files changed, 120 insertions(+), 31 deletions(-) diff --git a/client/api/src/backend.rs b/client/api/src/backend.rs index 486ac50611e35..f991bea8821e0 100644 --- a/client/api/src/backend.rs +++ b/client/api/src/backend.rs @@ -48,6 +48,19 @@ pub type TransactionForSB = >>::Trans /// Extracts the transaction for the given backend. pub type TransactionFor = TransactionForSB, Block>; +/// Describes which block import notification stream should be notified. +#[derive(Debug, Clone, Copy)] +pub enum ImportNotificationAction { + /// Notify only when the node has synced to the tip or there is a re-org. + RecentBlock, + /// Notify for every single block no matter what the sync state is. + EveryBlock, + /// Both block import notifications above should be fired. + Both, + /// No block import notification should be fired. + None, +} + /// Import operation summary. /// /// Contains information about the block that just got imported, @@ -67,6 +80,8 @@ pub struct ImportSummary { /// /// If `None`, there was no re-org while importing. pub tree_route: Option>, + /// What notify action to take for this import. + pub import_notification_action: ImportNotificationAction, } /// Finalization operation summary. diff --git a/client/api/src/client.rs b/client/api/src/client.rs index aeb119e0ef77a..e334f2f9fb4f6 100644 --- a/client/api/src/client.rs +++ b/client/api/src/client.rs @@ -59,10 +59,16 @@ pub trait BlockOf { /// A source of blockchain events. pub trait BlockchainEvents { - /// Get block import event stream. Not guaranteed to be fired for every - /// imported block. + /// Get block import event stream. + /// + /// Not guaranteed to be fired for every imported block, only fired when the node + /// has synced to the tip or there is a re-org. Use `every_import_notification_stream()` + /// if you want a notification of every imported block regardless. fn import_notification_stream(&self) -> ImportNotifications; + /// Get a stream of every imported block. + fn every_import_notification_stream(&self) -> ImportNotifications; + /// Get a stream of finality notifications. Not guaranteed to be fired for every /// finalized block. fn finality_notification_stream(&self) -> FinalityNotifications; diff --git a/client/merkle-mountain-range/src/test_utils.rs b/client/merkle-mountain-range/src/test_utils.rs index 9e00d620a115c..010b48bb3d7da 100644 --- a/client/merkle-mountain-range/src/test_utils.rs +++ b/client/merkle-mountain-range/src/test_utils.rs @@ -265,6 +265,10 @@ impl BlockchainEvents for MockClient { unimplemented!() } + fn every_import_notification_stream(&self) -> ImportNotifications { + unimplemented!() + } + fn finality_notification_stream(&self) -> FinalityNotifications { self.client.lock().finality_notification_stream() } diff --git a/client/service/src/client/client.rs b/client/service/src/client/client.rs index ddeec5c73e63e..4b5822ae0e017 100644 --- a/client/service/src/client/client.rs +++ b/client/service/src/client/client.rs @@ -31,7 +31,7 @@ use sc_block_builder::{BlockBuilderApi, BlockBuilderProvider, RecordProof}; use sc_client_api::{ backend::{ self, apply_aux, BlockImportOperation, ClientImportOperation, FinalizeSummary, Finalizer, - ImportSummary, LockImportRun, NewBlockState, StorageProvider, + ImportNotificationAction, ImportSummary, LockImportRun, NewBlockState, StorageProvider, }, client::{ BadBlocks, BlockBackend, BlockImportNotification, BlockOf, BlockchainEvents, ClientInfo, @@ -106,6 +106,7 @@ where executor: E, storage_notifications: StorageNotifications, import_notification_sinks: NotificationSinks>, + every_import_notification_sinks: NotificationSinks>, finality_notification_sinks: NotificationSinks>, // Collects auxiliary operations to be performed atomically together with // block import operations. @@ -304,19 +305,22 @@ where FinalityNotification::from_summary(summary, self.unpin_worker_sender.clone()) }); - let (import_notification, storage_changes) = match notify_imported { - Some(mut summary) => { - let storage_changes = summary.storage_changes.take(); - ( - Some(BlockImportNotification::from_summary( - summary, - self.unpin_worker_sender.clone(), - )), - storage_changes, - ) - }, - None => (None, None), - }; + let (import_notification, storage_changes, import_notification_action) = + match notify_imported { + Some(mut summary) => { + let import_notification_action = summary.import_notification_action; + let storage_changes = summary.storage_changes.take(); + ( + Some(BlockImportNotification::from_summary( + summary, + self.unpin_worker_sender.clone(), + )), + storage_changes, + import_notification_action, + ) + }, + None => (None, None, ImportNotificationAction::None), + }; if let Some(ref notification) = finality_notification { for action in self.finality_actions.lock().iter_mut() { @@ -353,7 +357,7 @@ where } self.notify_finalized(finality_notification)?; - self.notify_imported(import_notification, storage_changes)?; + self.notify_imported(import_notification, import_notification_action, storage_changes)?; Ok(r) }; @@ -451,6 +455,7 @@ where executor, storage_notifications: StorageNotifications::new(prometheus_registry), import_notification_sinks: Default::default(), + every_import_notification_sinks: Default::default(), finality_notification_sinks: Default::default(), import_actions: Default::default(), finality_actions: Default::default(), @@ -769,11 +774,15 @@ where operation.op.insert_aux(aux)?; - // We only notify when we are already synced to the tip of the chain + let should_notify_every_block = !self.every_import_notification_sinks.lock().is_empty(); + + // 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 should_notify_recent_block = make_notifications || tree_route.is_some(); + + if should_notify_every_block || should_notify_recent_block { let header = import_headers.into_post(); - if finalized { + if finalized && should_notify_recent_block { let mut summary = match operation.notify_finalized.take() { Some(mut summary) => { summary.header = header.clone(); @@ -810,6 +819,16 @@ where operation.notify_finalized = Some(summary); } + let import_notification_action = if should_notify_every_block { + if should_notify_recent_block { + ImportNotificationAction::Both + } else { + ImportNotificationAction::EveryBlock + } + } else { + ImportNotificationAction::RecentBlock + }; + operation.notify_imported = Some(ImportSummary { hash, origin, @@ -817,6 +836,7 @@ where is_new_best, storage_changes, tree_route, + import_notification_action, }) } @@ -1012,6 +1032,7 @@ where fn notify_imported( &self, notification: Option>, + import_notification_action: ImportNotificationAction, storage_changes: Option<(StorageCollection, ChildStorageCollection)>, ) -> sp_blockchain::Result<()> { let notification = match notification { @@ -1024,22 +1045,59 @@ where // temporary leak of closed/discarded notification sinks (e.g. // from consensus code). self.import_notification_sinks.lock().retain(|sink| !sink.is_closed()); + + self.every_import_notification_sinks.lock().retain(|sink| !sink.is_closed()); + return Ok(()) }, }; - if let Some(storage_changes) = storage_changes { - // TODO [ToDr] How to handle re-orgs? Should we re-emit all storage changes? - self.storage_notifications.trigger( - ¬ification.hash, - storage_changes.0.into_iter(), - storage_changes.1.into_iter().map(|(sk, v)| (sk, v.into_iter())), - ); - } + let trigger_storage_changes_notification = || { + if let Some(storage_changes) = storage_changes { + // TODO [ToDr] How to handle re-orgs? Should we re-emit all storage changes? + self.storage_notifications.trigger( + ¬ification.hash, + storage_changes.0.into_iter(), + storage_changes.1.into_iter().map(|(sk, v)| (sk, v.into_iter())), + ); + } + }; + + match import_notification_action { + ImportNotificationAction::Both => { + trigger_storage_changes_notification(); + self.import_notification_sinks + .lock() + .retain(|sink| sink.unbounded_send(notification.clone()).is_ok()); + + self.every_import_notification_sinks + .lock() + .retain(|sink| sink.unbounded_send(notification.clone()).is_ok()); + }, + ImportNotificationAction::RecentBlock => { + trigger_storage_changes_notification(); + self.import_notification_sinks + .lock() + .retain(|sink| sink.unbounded_send(notification.clone()).is_ok()); + + self.every_import_notification_sinks.lock().retain(|sink| !sink.is_closed()); + }, + ImportNotificationAction::EveryBlock => { + self.every_import_notification_sinks + .lock() + .retain(|sink| sink.unbounded_send(notification.clone()).is_ok()); + + self.import_notification_sinks.lock().retain(|sink| !sink.is_closed()); + }, + ImportNotificationAction::None => { + // This branch is unreachable in fact because the block import notification must be + // Some(_) instead of None (it's already handled at the beginning of this function) + // at this point. + self.import_notification_sinks.lock().retain(|sink| !sink.is_closed()); - self.import_notification_sinks - .lock() - .retain(|sink| sink.unbounded_send(notification.clone()).is_ok()); + self.every_import_notification_sinks.lock().retain(|sink| !sink.is_closed()); + }, + } Ok(()) } @@ -1944,6 +2002,12 @@ where stream } + fn every_import_notification_stream(&self) -> ImportNotifications { + let (sink, stream) = tracing_unbounded("mpsc_every_import_notification_stream", 100_000); + self.every_import_notification_sinks.lock().push(sink); + stream + } + fn finality_notification_stream(&self) -> FinalityNotifications { let (sink, stream) = tracing_unbounded("mpsc_finality_notification_stream", 100_000); self.finality_notification_sinks.lock().push(sink); From 4ad96cfe44cca7fceac437de232a8c887d70f6ea Mon Sep 17 00:00:00 2001 From: Anton Date: Mon, 27 Feb 2023 14:43:15 +0400 Subject: [PATCH 439/715] [client/network] Remove unused argument (#13444) * improve error message * removed unused argument * docs: disconnect_peer_inner no longer accepts `ban` * remove redundant trace message ``` sync: Too many full nodes, rejecting 12D3KooWSQAP2fh4qBkLXBW4mvCtbAiK8sqMnExWHHTZtVAxZ8bQ sync: 12D3KooWSQAP2fh4qBkLXBW4mvCtbAiK8sqMnExWHHTZtVAxZ8bQ disconnected ``` is enough to understand that we've refused to connect to the given peer * Revert "removed unused argument" This reverts commit c87f755b1fd03494fb446b604fe25c2418da7c87. * ban peer for 10s after disconnect * do not accept incoming conns if peer was banned * Revert "do not accept incoming conns if peer was banned" This reverts commit 7e59d05975765f2547468e9dcfd1361516c41e06. * Revert "ban peer for 10s after disconnect" This reverts commit 3859201ced42a5b2d18c0600e29efd20962a7289. * Revert "Revert "removed unused argument"" This reverts commit f1dc623646dc5a69e1822c35f428e90dffe34d95. * format code * Revert "remove redundant trace message" This reverts commit a87e65f08553dbe69027e9aa4f7ca4779ccaa7f2. --- .../src/protocol/notifications/behaviour.rs | 30 ++++--------------- client/network/sync/src/lib.rs | 2 +- 2 files changed, 7 insertions(+), 25 deletions(-) diff --git a/client/network/src/protocol/notifications/behaviour.rs b/client/network/src/protocol/notifications/behaviour.rs index ebfb95afaea2d..027ea0ab53136 100644 --- a/client/network/src/protocol/notifications/behaviour.rs +++ b/client/network/src/protocol/notifications/behaviour.rs @@ -415,17 +415,11 @@ impl Notifications { /// Disconnects the given peer if we are connected to it. pub fn disconnect_peer(&mut self, peer_id: &PeerId, set_id: sc_peerset::SetId) { trace!(target: "sub-libp2p", "External API => Disconnect({}, {:?})", peer_id, set_id); - self.disconnect_peer_inner(peer_id, set_id, None); + self.disconnect_peer_inner(peer_id, set_id); } - /// Inner implementation of `disconnect_peer`. If `ban` is `Some`, we ban the peer - /// for the specific duration. - fn disconnect_peer_inner( - &mut self, - peer_id: &PeerId, - set_id: sc_peerset::SetId, - ban: Option, - ) { + /// Inner implementation of `disconnect_peer`. + fn disconnect_peer_inner(&mut self, peer_id: &PeerId, set_id: sc_peerset::SetId) { let mut entry = if let Entry::Occupied(entry) = self.peers.entry((*peer_id, set_id)) { entry } else { @@ -443,12 +437,8 @@ impl Notifications { PeerState::DisabledPendingEnable { connections, timer_deadline, timer: _ } => { trace!(target: "sub-libp2p", "PSM <= Dropped({}, {:?})", peer_id, set_id); self.peerset.dropped(set_id, *peer_id, DropReason::Unknown); - let backoff_until = Some(if let Some(ban) = ban { - cmp::max(timer_deadline, Instant::now() + ban) - } else { - timer_deadline - }); - *entry.into_mut() = PeerState::Disabled { connections, backoff_until } + *entry.into_mut() = + PeerState::Disabled { connections, backoff_until: Some(timer_deadline) } }, // Enabled => Disabled. @@ -496,8 +486,7 @@ impl Notifications { .iter() .any(|(_, s)| matches!(s, ConnectionState::Opening))); - let backoff_until = ban.map(|dur| Instant::now() + dur); - *entry.into_mut() = PeerState::Disabled { connections, backoff_until } + *entry.into_mut() = PeerState::Disabled { connections, backoff_until: None } }, // Incoming => Disabled. @@ -532,13 +521,6 @@ impl Notifications { *connec_state = ConnectionState::Closing; } - let backoff_until = match (backoff_until, ban) { - (Some(a), Some(b)) => Some(cmp::max(a, Instant::now() + b)), - (Some(a), None) => Some(a), - (None, Some(b)) => Some(Instant::now() + b), - (None, None) => None, - }; - debug_assert!(!connections .iter() .any(|(_, s)| matches!(s, ConnectionState::OpenDesiredByRemote))); diff --git a/client/network/sync/src/lib.rs b/client/network/sync/src/lib.rs index 5c1496e751dad..f710215e74177 100644 --- a/client/network/sync/src/lib.rs +++ b/client/network/sync/src/lib.rs @@ -1015,7 +1015,7 @@ where 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"); + error!(target: "sync", "💔 Called on_block_justification with a peer ID of an unknown peer"); return Ok(OnBlockJustification::Nothing) }; From 7d767195cb60b00309c4c95e362df67244f63ad5 Mon Sep 17 00:00:00 2001 From: Koute Date: Mon, 27 Feb 2023 19:45:42 +0900 Subject: [PATCH 440/715] Further storage iterator refactoring (#13445) * Remove `Backend::apply_to_key_values_while` * Add `IterArgs::start_at_exclusive` * Use `start_at_exclusive` in functions which used `Backend::apply_to_key_values_while` * Remove `Backend::apply_to_keys_while` * Remove `for_keys_with_prefix`, `for_key_values_with_prefix` and `for_child_keys_with_prefix` * Remove unnecessary `to_vec` calls * Fix unused method warning in no_std * Remove unnecessary import * Also check proof sizes in the test * Iterate over both keys and values in `prove_range_read_with_size` and add a test --- client/api/src/backend.rs | 49 +--- primitives/state-machine/src/backend.rs | 120 ++------- primitives/state-machine/src/ext.rs | 74 +++--- primitives/state-machine/src/lib.rs | 230 ++++++++++-------- primitives/state-machine/src/trie_backend.rs | 90 +------ .../state-machine/src/trie_backend_essence.rs | 33 ++- 6 files changed, 226 insertions(+), 370 deletions(-) diff --git a/client/api/src/backend.rs b/client/api/src/backend.rs index f991bea8821e0..26a0cf0351998 100644 --- a/client/api/src/backend.rs +++ b/client/api/src/backend.rs @@ -324,7 +324,6 @@ where { inner: >>::RawIter, state: State, - skip_if_first: Option, } impl KeysIter @@ -341,13 +340,9 @@ where let mut args = IterArgs::default(); args.prefix = prefix.as_ref().map(|prefix| prefix.0.as_slice()); args.start_at = start_at.as_ref().map(|start_at| start_at.0.as_slice()); + args.start_at_exclusive = true; - let start_at = args.start_at; - Ok(Self { - inner: state.raw_iter(args)?, - state, - skip_if_first: start_at.map(|key| StorageKey(key.to_vec())), - }) + Ok(Self { inner: state.raw_iter(args)?, state }) } /// Create a new iterator over a child storage's keys. @@ -361,13 +356,9 @@ where args.prefix = prefix.as_ref().map(|prefix| prefix.0.as_slice()); args.start_at = start_at.as_ref().map(|start_at| start_at.0.as_slice()); args.child_info = Some(child_info); + args.start_at_exclusive = true; - let start_at = args.start_at; - Ok(Self { - inner: state.raw_iter(args)?, - state, - skip_if_first: start_at.map(|key| StorageKey(key.to_vec())), - }) + Ok(Self { inner: state.raw_iter(args)?, state }) } } @@ -379,15 +370,7 @@ where type Item = StorageKey; fn next(&mut self) -> Option { - let key = self.inner.next_key(&self.state)?.ok().map(StorageKey)?; - - if let Some(skipped_key) = self.skip_if_first.take() { - if key == skipped_key { - return self.next() - } - } - - Some(key) + self.inner.next_key(&self.state)?.ok().map(StorageKey) } } @@ -399,7 +382,6 @@ where { inner: >>::RawIter, state: State, - skip_if_first: Option, } impl Iterator for PairsIter @@ -410,19 +392,10 @@ where type Item = (StorageKey, StorageData); fn next(&mut self) -> Option { - let (key, value) = self - .inner + self.inner .next_pair(&self.state)? .ok() - .map(|(key, value)| (StorageKey(key), StorageData(value)))?; - - if let Some(skipped_key) = self.skip_if_first.take() { - if key == skipped_key { - return self.next() - } - } - - Some((key, value)) + .map(|(key, value)| (StorageKey(key), StorageData(value))) } } @@ -440,13 +413,9 @@ where let mut args = IterArgs::default(); args.prefix = prefix.as_ref().map(|prefix| prefix.0.as_slice()); args.start_at = start_at.as_ref().map(|start_at| start_at.0.as_slice()); + args.start_at_exclusive = true; - let start_at = args.start_at; - Ok(Self { - inner: state.raw_iter(args)?, - state, - skip_if_first: start_at.map(|key| StorageKey(key.to_vec())), - }) + Ok(Self { inner: state.raw_iter(args)?, state }) } } diff --git a/primitives/state-machine/src/backend.rs b/primitives/state-machine/src/backend.rs index a8e742d1d2a1d..f3244308a54cf 100644 --- a/primitives/state-machine/src/backend.rs +++ b/primitives/state-machine/src/backend.rs @@ -43,6 +43,10 @@ pub struct IterArgs<'a> { /// This is inclusive and the iteration will include the key which is specified here. pub start_at: Option<&'a [u8]>, + /// If this is `true` then the iteration will *not* include + /// the key specified in `start_at`, if there is such a key. + pub start_at_exclusive: bool, + /// The info of the child trie over which to iterate over. pub child_info: Option, @@ -117,6 +121,17 @@ where } } +impl<'a, H, I> PairsIter<'a, H, I> +where + H: Hasher, + I: StorageIterator + Default, +{ + #[cfg(feature = "std")] + pub(crate) fn was_complete(&self) -> bool { + self.raw_iter.was_complete() + } +} + /// An iterator over storage keys. pub struct KeysIter<'a, H, I> where @@ -214,111 +229,6 @@ pub trait Backend: sp_std::fmt::Debug { key: &[u8], ) -> Result, Self::Error>; - /// Iterate over storage starting at key, for a given prefix and child trie. - /// Aborts as soon as `f` returns false. - /// Warning, this fails at first error when usual iteration skips errors. - /// If `allow_missing` is true, iteration stops when it reaches a missing trie node. - /// Otherwise an error is produced. - /// - /// Returns `true` if trie end is reached. - // TODO: Remove this. - fn apply_to_key_values_while, Vec) -> bool>( - &self, - child_info: Option<&ChildInfo>, - prefix: Option<&[u8]>, - start_at: Option<&[u8]>, - mut f: F, - allow_missing: bool, - ) -> Result { - let args = IterArgs { - child_info: child_info.cloned(), - prefix, - start_at, - stop_on_incomplete_database: allow_missing, - ..IterArgs::default() - }; - let mut iter = self.pairs(args)?; - while let Some(key_value) = iter.next() { - let (key, value) = key_value?; - if !f(key, value) { - return Ok(false) - } - } - Ok(iter.raw_iter.was_complete()) - } - - /// Retrieve all entries keys of storage and call `f` for each of those keys. - /// Aborts as soon as `f` returns false. - // TODO: Remove this. - fn apply_to_keys_while bool>( - &self, - child_info: Option<&ChildInfo>, - prefix: Option<&[u8]>, - start_at: Option<&[u8]>, - mut f: F, - ) -> Result<(), Self::Error> { - let args = - IterArgs { child_info: child_info.cloned(), prefix, start_at, ..IterArgs::default() }; - - for key in self.keys(args)? { - if !f(&key?) { - return Ok(()) - } - } - Ok(()) - } - - /// Retrieve all entries keys which start with the given prefix and - /// call `f` for each of those keys. - // TODO: Remove this. - fn for_keys_with_prefix( - &self, - prefix: &[u8], - mut f: F, - ) -> Result<(), Self::Error> { - let args = IterArgs { prefix: Some(prefix), ..IterArgs::default() }; - self.keys(args)?.try_for_each(|key| { - f(&key?); - Ok(()) - }) - } - - /// Retrieve all entries keys and values of which start with the given prefix and - /// call `f` for each of those keys. - // TODO: Remove this. - fn for_key_values_with_prefix( - &self, - prefix: &[u8], - mut f: F, - ) -> Result<(), Self::Error> { - let args = IterArgs { prefix: Some(prefix), ..IterArgs::default() }; - self.pairs(args)?.try_for_each(|key_value| { - let (key, value) = key_value?; - f(&key, &value); - Ok(()) - }) - } - - /// Retrieve all child entries keys which start with the given prefix and - /// call `f` for each of those keys. - // TODO: Remove this. - fn for_child_keys_with_prefix( - &self, - child_info: &ChildInfo, - prefix: &[u8], - mut f: F, - ) -> Result<(), Self::Error> { - let args = IterArgs { - child_info: Some(child_info.clone()), - prefix: Some(prefix), - ..IterArgs::default() - }; - self.keys(args)?.try_for_each(|key| { - f(&key?); - Ok(()) - }) - } - /// 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 not include child storage updates. diff --git a/primitives/state-machine/src/ext.rs b/primitives/state-machine/src/ext.rs index 695868c96caf9..3c088a2176582 100644 --- a/primitives/state-machine/src/ext.rs +++ b/primitives/state-machine/src/ext.rs @@ -19,7 +19,9 @@ #[cfg(feature = "std")] use crate::overlayed_changes::OverlayedExtensions; -use crate::{backend::Backend, IndexOperation, OverlayedChanges, StorageKey, StorageValue}; +use crate::{ + backend::Backend, IndexOperation, IterArgs, OverlayedChanges, StorageKey, StorageValue, +}; use codec::{Decode, Encode, EncodeAppend}; use hash_db::Hasher; #[cfg(feature = "std")] @@ -750,40 +752,54 @@ where { fn limit_remove_from_backend( &mut self, - maybe_child: Option<&ChildInfo>, - maybe_prefix: Option<&[u8]>, + child_info: Option<&ChildInfo>, + prefix: Option<&[u8]>, maybe_limit: Option, - maybe_cursor: Option<&[u8]>, + start_at: Option<&[u8]>, ) -> (Option>, u32, u32) { + let iter = match self.backend.keys(IterArgs { + child_info: child_info.cloned(), + prefix, + start_at, + ..IterArgs::default() + }) { + Ok(iter) => iter, + Err(error) => { + log::debug!(target: "trie", "Error while iterating the storage: {}", error); + return (None, 0, 0) + }, + }; + let mut delete_count: u32 = 0; let mut loop_count: u32 = 0; let mut maybe_next_key = None; - let result = - 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 - } - 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 - }); + for key in iter { + let key = match key { + Ok(key) => key, + Err(error) => { + log::debug!(target: "trie", "Error while iterating the storage: {}", error); + break + }, + }; - if let Err(error) = result { - log::debug!(target: "trie", "Error while iterating the storage: {}", error); + if maybe_limit.map_or(false, |limit| loop_count == limit) { + maybe_next_key = Some(key); + break + } + let overlay = match child_info { + 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) = child_info { + self.overlay.set_child_storage(child_info, key, None); + } else { + self.overlay.set_storage(key, None); + } + delete_count = delete_count.saturating_add(1); + } + loop_count = loop_count.saturating_add(1); } (maybe_next_key, delete_count, loop_count) diff --git a/primitives/state-machine/src/lib.rs b/primitives/state-machine/src/lib.rs index 5fb300e12bae7..90ee962dafa9e 100644 --- a/primitives/state-machine/src/lib.rs +++ b/primitives/state-machine/src/lib.rs @@ -849,48 +849,37 @@ mod execution { 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 && - 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 recorder.estimate_encoded_size() <= size_limit { - count += 1; - true - } else { - false - } - }, - false, - ) + let mut iter = proving_backend + .pairs(IterArgs { + child_info, + start_at: start_at_ref, + start_at_exclusive: true, + ..IterArgs::default() + }) .map_err(|e| Box::new(e) as Box)?; + while let Some(item) = iter.next() { + let (key, value) = item.map_err(|e| Box::new(e) as Box)?; + + if depth < MAX_NESTED_TRIE_DEPTH && + sp_core::storage::well_known_keys::is_child_storage_key(key.as_slice()) + { + count += 1; + // do not add two child trie with same root + if !child_roots.contains(value.as_slice()) { + child_roots.insert(value); + switch_child_key = Some(key); + break + } + } else if recorder.estimate_encoded_size() <= size_limit { + count += 1; + } else { + break + } + } + + let completed = iter.was_complete(); + if switch_child_key.is_none() { if depth == 1 { break @@ -951,23 +940,27 @@ mod execution { let proving_backend = TrieBackendBuilder::wrap(trie_backend).with_recorder(recorder.clone()).build(); let mut count = 0; - proving_backend - .apply_to_key_values_while( - child_info, + let iter = proving_backend + // NOTE: Even though the loop below doesn't use these values + // this *must* fetch both the keys and the values so that + // the proof is correct. + .pairs(IterArgs { + child_info: child_info.cloned(), prefix, start_at, - |_key, _value| { - if count == 0 || recorder.estimate_encoded_size() <= size_limit { - count += 1; - true - } else { - false - } - }, - false, - ) + ..IterArgs::default() + }) .map_err(|e| Box::new(e) as Box)?; + for item in iter { + item.map_err(|e| Box::new(e) as Box)?; + if count == 0 || recorder.estimate_encoded_size() <= size_limit { + count += 1; + } else { + break + } + } + let proof = proving_backend .extract_proof() .expect("A recorder was set and thus, a storage proof can be extracted; qed"); @@ -1173,20 +1166,25 @@ mod execution { H::Out: Ord + Codec, { let mut values = Vec::new(); - let result = proving_backend.apply_to_key_values_while( - child_info, - prefix, - start_at, - |key, value| { - values.push((key.to_vec(), value.to_vec())); - count.as_ref().map_or(true, |c| (values.len() as u32) < *c) - }, - true, - ); - match result { - Ok(completed) => Ok((values, completed)), - Err(e) => Err(Box::new(e) as Box), + let mut iter = proving_backend + .pairs(IterArgs { + child_info: child_info.cloned(), + prefix, + start_at, + stop_on_incomplete_database: true, + ..IterArgs::default() + }) + .map_err(|e| Box::new(e) as Box)?; + + while let Some(item) = iter.next() { + let (key, value) = item.map_err(|e| Box::new(e) as Box)?; + values.push((key, value)); + if !count.as_ref().map_or(true, |c| (values.len() as u32) < *c) { + break + } } + + Ok((values, iter.was_complete())) } /// Check storage range proof on pre-created proving backend. @@ -1255,47 +1253,35 @@ mod execution { }; 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 && - 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, - ) + let mut iter = proving_backend + .pairs(IterArgs { + child_info, + start_at: start_at_ref, + start_at_exclusive: true, + stop_on_incomplete_database: true, + ..IterArgs::default() + }) .map_err(|e| Box::new(e) as Box)?; + while let Some(item) = iter.next() { + let (key, value) = item.map_err(|e| Box::new(e) as Box)?; + values.push((key.to_vec(), value.to_vec())); + + if depth < MAX_NESTED_TRIE_DEPTH && + sp_core::storage::well_known_keys::is_child_storage_key(key.as_slice()) + { + // Do not add two chid trie with same root. + if !child_roots.contains(value.as_slice()) { + child_roots.insert(value.clone()); + switch_child_key = Some((key, value)); + break + } + } + } + + let completed = iter.was_complete(); + if switch_child_key.is_none() { if !completed { break depth @@ -1325,9 +1311,13 @@ mod tests { storage::{ChildInfo, StateVersion}, testing::TaskExecutor, traits::{CallContext, CodeExecutor, Externalities, RuntimeCode}, + H256, }; use sp_runtime::traits::BlakeTwo256; - use sp_trie::trie_types::{TrieDBMutBuilderV0, TrieDBMutBuilderV1}; + use sp_trie::{ + trie_types::{TrieDBMutBuilderV0, TrieDBMutBuilderV1}, + KeySpacedDBMut, PrefixedMemoryDB, + }; use std::collections::{BTreeMap, HashMap}; #[derive(Clone)] @@ -1953,12 +1943,14 @@ mod tests { // Always contains at least some nodes. assert_eq!(proof.to_memory_db::().drain().len(), 3); assert_eq!(count, 1); + assert_eq!(proof.encoded_size(), 443); 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.to_memory_db::().drain().len(), 9); assert_eq!(count, 85); + assert_eq!(proof.encoded_size(), 857); let (results, completed) = read_range_proof_check::( remote_root, proof.clone(), @@ -1982,6 +1974,8 @@ mod tests { prove_range_read_with_size(remote_backend, None, None, 50000, Some(&[])).unwrap(); assert_eq!(proof.to_memory_db::().drain().len(), 11); assert_eq!(count, 132); + assert_eq!(proof.encoded_size(), 990); + let (results, completed) = read_range_proof_check::(remote_root, proof, None, None, None, None) .unwrap(); @@ -1989,6 +1983,32 @@ mod tests { assert_eq!(completed, true); } + #[test] + fn prove_read_with_size_limit_proof_size() { + let mut root = H256::default(); + let mut mdb = PrefixedMemoryDB::::default(); + { + let mut mdb = KeySpacedDBMut::new(&mut mdb, b""); + let mut trie = TrieDBMutBuilderV1::new(&mut mdb, &mut root).build(); + trie.insert(b"value1", &[123; 1]).unwrap(); + trie.insert(b"value2", &[123; 10]).unwrap(); + trie.insert(b"value3", &[123; 100]).unwrap(); + trie.insert(b"value4", &[123; 1000]).unwrap(); + } + + let remote_backend: TrieBackend, BlakeTwo256> = + TrieBackendBuilder::new(mdb, root) + .with_optional_cache(None) + .with_optional_recorder(None) + .build(); + + let (proof, count) = + prove_range_read_with_size(remote_backend, None, None, 1000, None).unwrap(); + + assert_eq!(proof.encoded_size(), 1267); + assert_eq!(count, 3); + } + #[test] fn inner_state_versioning_switch_proofs() { let mut state_version = StateVersion::V0; diff --git a/primitives/state-machine/src/trie_backend.rs b/primitives/state-machine/src/trie_backend.rs index ec6db9be3346b..3e8d0a7a3bf0a 100644 --- a/primitives/state-machine/src/trie_backend.rs +++ b/primitives/state-machine/src/trie_backend.rs @@ -357,7 +357,7 @@ pub mod tests { trie_types::{TrieDBBuilder, TrieDBMutBuilderV0, TrieDBMutBuilderV1}, KeySpacedDBMut, PrefixedKey, PrefixedMemoryDB, Trie, TrieCache, TrieMut, }; - use std::{collections::HashSet, iter}; + use std::iter; use trie_db::NodeCodec; const CHILD_KEY_1: &[u8] = b"sub1"; @@ -643,73 +643,6 @@ pub mod tests { .collect::>(), vec![b"value1".to_vec(), b"value2".to_vec(),] ); - - // Also test out the wrapper methods. - // TODO: Remove this once these methods are gone. - - let mut list = Vec::new(); - assert!(trie - .apply_to_key_values_while( - None, - None, - Some(b"key"), - |key, _| { - list.push(key); - true - }, - false - ) - .unwrap()); - assert_eq!(list[0..3], vec![b"key".to_vec(), b"value1".to_vec(), b"value2".to_vec(),]); - - let mut list = Vec::new(); - trie.apply_to_keys_while(None, None, Some(b"key"), |key| { - list.push(key.to_vec()); - true - }) - .unwrap(); - assert_eq!(list[0..3], vec![b"key".to_vec(), b"value1".to_vec(), b"value2".to_vec(),]); - - let mut list = Vec::new(); - trie.apply_to_keys_while(None, None, Some(b"k"), |key| { - list.push(key.to_vec()); - true - }) - .unwrap(); - assert_eq!(list[0..3], vec![b"key".to_vec(), b"value1".to_vec(), b"value2".to_vec(),]); - - let mut list = Vec::new(); - trie.apply_to_keys_while(None, None, Some(b""), |key| { - list.push(key.to_vec()); - true - }) - .unwrap(); - assert_eq!( - list[0..5], - vec![ - b":child_storage:default:sub1".to_vec(), - b":code".to_vec(), - b"key".to_vec(), - b"value1".to_vec(), - b"value2".to_vec(), - ] - ); - - let mut list = Vec::new(); - trie.apply_to_keys_while(None, Some(b"value"), Some(b"key"), |key| { - list.push(key.to_vec()); - true - }) - .unwrap(); - assert!(list.is_empty()); - - let mut list = Vec::new(); - trie.apply_to_keys_while(None, Some(b"value"), Some(b"value"), |key| { - list.push(key.to_vec()); - true - }) - .unwrap(); - assert_eq!(list, vec![b"value1".to_vec(), b"value2".to_vec(),]); } parameterized_test!(storage_root_is_non_default, storage_root_is_non_default_inner); @@ -745,27 +678,6 @@ pub mod tests { ); } - 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| { - let for_first_time = seen.insert(key.to_vec()); - assert!(for_first_time, "Seen key '{:?}' more than once", key); - }) - .unwrap(); - - let mut expected = HashSet::new(); - expected.insert(b"value1".to_vec()); - expected.insert(b"value2".to_vec()); - assert_eq!(seen, expected); - } - parameterized_test!( keys_with_empty_prefix_returns_all_keys, keys_with_empty_prefix_returns_all_keys_inner diff --git a/primitives/state-machine/src/trie_backend_essence.rs b/primitives/state-machine/src/trie_backend_essence.rs index 81a627a657c3e..f071a32cede89 100644 --- a/primitives/state-machine/src/trie_backend_essence.rs +++ b/primitives/state-machine/src/trie_backend_essence.rs @@ -87,6 +87,7 @@ where H: Hasher, { stop_on_incomplete_database: bool, + skip_if_first: Option, root: H::Out, child_info: Option, trie_iter: TrieDBRawIterator>, @@ -144,6 +145,7 @@ where fn default() -> Self { Self { stop_on_incomplete_database: false, + skip_if_first: None, child_info: None, root: Default::default(), trie_iter: TrieDBRawIterator::empty(), @@ -165,12 +167,34 @@ where #[inline] fn next_key(&mut self, backend: &Self::Backend) -> Option> { - self.prepare(&backend.essence, |trie, trie_iter| trie_iter.next_key(&trie)) + let skip_if_first = self.skip_if_first.take(); + self.prepare(&backend.essence, |trie, trie_iter| { + let mut result = trie_iter.next_key(&trie); + if let Some(skipped_key) = skip_if_first { + if let Some(Ok(ref key)) = result { + if *key == skipped_key { + result = trie_iter.next_key(&trie); + } + } + } + result + }) } #[inline] fn next_pair(&mut self, backend: &Self::Backend) -> Option> { - self.prepare(&backend.essence, |trie, trie_iter| trie_iter.next_item(&trie)) + let skip_if_first = self.skip_if_first.take(); + self.prepare(&backend.essence, |trie, trie_iter| { + let mut result = trie_iter.next_item(&trie); + if let Some(skipped_key) = skip_if_first { + if let Some(Ok((ref key, _))) = result { + if *key == skipped_key { + result = trie_iter.next_item(&trie); + } + } + } + result + }) } fn was_complete(&self) -> bool { @@ -574,6 +598,11 @@ where Ok(RawIter { stop_on_incomplete_database: args.stop_on_incomplete_database, + skip_if_first: if args.start_at_exclusive { + args.start_at.map(|key| key.to_vec()) + } else { + None + }, child_info: args.child_info, root, trie_iter, From 7c8b89b3a6b603902709fc33fdb10a864b8b4204 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Mon, 27 Feb 2023 17:15:08 +0100 Subject: [PATCH 441/715] Move grandpa crates to consensus folder (#13458) * Move grandpa under consensus dir * Rename grandpa folder * Finish grandpa renaming * Minor tweaks * Cargo fmt * Adjust path to chain spec --- Cargo.lock | 200 +++++++++--------- Cargo.toml | 6 +- bin/node-template/node/Cargo.toml | 4 +- bin/node-template/node/src/chain_spec.rs | 2 +- bin/node-template/node/src/command.rs | 2 +- bin/node-template/node/src/service.rs | 22 +- bin/node-template/runtime/Cargo.toml | 2 + bin/node-template/runtime/src/lib.rs | 18 +- bin/node/cli/Cargo.toml | 4 +- bin/node/rpc/Cargo.toml | 4 +- bin/node/rpc/src/lib.rs | 4 +- bin/node/runtime/Cargo.toml | 2 + bin/node/runtime/src/lib.rs | 22 +- client/beefy/Cargo.toml | 2 +- client/consensus/grandpa/Cargo.toml | 60 ++++++ .../grandpa}/README.md | 0 client/consensus/grandpa/rpc/Cargo.toml | 34 +++ .../grandpa}/rpc/README.md | 0 .../grandpa}/rpc/src/error.rs | 2 +- .../grandpa}/rpc/src/finality.rs | 6 +- .../grandpa}/rpc/src/lib.rs | 14 +- .../grandpa}/rpc/src/notification.rs | 2 +- .../grandpa}/rpc/src/report.rs | 2 +- .../grandpa}/src/authorities.rs | 2 +- .../grandpa}/src/aux_schema.rs | 4 +- .../grandpa}/src/communication/gossip.rs | 4 +- .../grandpa}/src/communication/mod.rs | 8 +- .../grandpa}/src/communication/periodic.rs | 0 .../grandpa}/src/communication/tests.rs | 14 +- .../grandpa}/src/environment.rs | 2 +- .../grandpa}/src/finality_proof.rs | 10 +- .../grandpa}/src/import.rs | 2 +- .../grandpa}/src/justification.rs | 16 +- .../grandpa}/src/lib.rs | 8 +- .../grandpa}/src/notification.rs | 0 .../grandpa}/src/observer.rs | 2 +- .../grandpa}/src/tests.rs | 16 +- .../grandpa}/src/until_imported.rs | 2 +- .../grandpa}/src/voting_rule.rs | 0 .../grandpa}/src/warp_proof.rs | 12 +- client/finality-grandpa/Cargo.toml | 60 ------ client/finality-grandpa/rpc/Cargo.toml | 36 ---- client/network/README.md | 2 +- client/network/common/Cargo.toml | 2 +- client/network/common/src/sync/warp.rs | 2 +- client/network/src/lib.rs | 2 +- client/network/sync/Cargo.toml | 2 +- client/network/sync/src/warp.rs | 2 +- client/sync-state-rpc/Cargo.toml | 2 +- client/sync-state-rpc/src/lib.rs | 4 +- docs/CODEOWNERS | 2 +- frame/grandpa/Cargo.toml | 4 +- frame/grandpa/src/benchmarking.rs | 6 +- frame/grandpa/src/equivocation.rs | 4 +- frame/grandpa/src/lib.rs | 4 +- frame/grandpa/src/mock.rs | 10 +- frame/grandpa/src/tests.rs | 16 +- .../grandpa}/Cargo.toml | 16 +- .../grandpa}/README.md | 0 .../grandpa}/src/lib.rs | 0 test-utils/runtime/Cargo.toml | 4 +- test-utils/runtime/src/lib.rs | 16 +- 62 files changed, 356 insertions(+), 356 deletions(-) create mode 100644 client/consensus/grandpa/Cargo.toml rename client/{finality-grandpa => consensus/grandpa}/README.md (100%) create mode 100644 client/consensus/grandpa/rpc/Cargo.toml rename client/{finality-grandpa => consensus/grandpa}/rpc/README.md (100%) rename client/{finality-grandpa => consensus/grandpa}/rpc/src/error.rs (97%) rename client/{finality-grandpa => consensus/grandpa}/rpc/src/finality.rs (88%) rename client/{finality-grandpa => consensus/grandpa}/rpc/src/lib.rs (96%) rename client/{finality-grandpa => consensus/grandpa}/rpc/src/notification.rs (96%) rename client/{finality-grandpa => consensus/grandpa}/rpc/src/report.rs (97%) rename client/{finality-grandpa => consensus/grandpa}/src/authorities.rs (99%) rename client/{finality-grandpa => consensus/grandpa}/src/aux_schema.rs (99%) rename client/{finality-grandpa => consensus/grandpa}/src/communication/gossip.rs (99%) rename client/{finality-grandpa => consensus/grandpa}/src/communication/mod.rs (99%) rename client/{finality-grandpa => consensus/grandpa}/src/communication/periodic.rs (100%) rename client/{finality-grandpa => consensus/grandpa}/src/communication/tests.rs (97%) rename client/{finality-grandpa => consensus/grandpa}/src/environment.rs (99%) rename client/{finality-grandpa => consensus/grandpa}/src/finality_proof.rs (98%) rename client/{finality-grandpa => consensus/grandpa}/src/import.rs (99%) rename client/{finality-grandpa => consensus/grandpa}/src/justification.rs (93%) rename client/{finality-grandpa => consensus/grandpa}/src/lib.rs (99%) rename client/{finality-grandpa => consensus/grandpa}/src/notification.rs (100%) rename client/{finality-grandpa => consensus/grandpa}/src/observer.rs (99%) rename client/{finality-grandpa => consensus/grandpa}/src/tests.rs (99%) rename client/{finality-grandpa => consensus/grandpa}/src/until_imported.rs (99%) rename client/{finality-grandpa => consensus/grandpa}/src/voting_rule.rs (100%) rename client/{finality-grandpa => consensus/grandpa}/src/warp_proof.rs (97%) delete mode 100644 client/finality-grandpa/Cargo.toml delete mode 100644 client/finality-grandpa/rpc/Cargo.toml rename primitives/{finality-grandpa => consensus/grandpa}/Cargo.toml (86%) rename primitives/{finality-grandpa => consensus/grandpa}/README.md (100%) rename primitives/{finality-grandpa => consensus/grandpa}/src/lib.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index 299f639219437..92db97a36c943 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -520,8 +520,8 @@ dependencies = [ "sp-beefy", "sp-blockchain", "sp-consensus", + "sp-consensus-grandpa", "sp-core", - "sp-finality-grandpa", "sp-keyring", "sp-keystore", "sp-mmr-primitives", @@ -3601,6 +3601,7 @@ dependencies = [ "sp-authority-discovery", "sp-block-builder", "sp-consensus-babe", + "sp-consensus-grandpa", "sp-core", "sp-inherents", "sp-io", @@ -4806,9 +4807,9 @@ dependencies = [ "sc-consensus", "sc-consensus-babe", "sc-consensus-epochs", + "sc-consensus-grandpa", "sc-consensus-slots", "sc-executor", - "sc-finality-grandpa", "sc-keystore", "sc-network", "sc-network-common", @@ -4829,8 +4830,8 @@ dependencies = [ "sp-blockchain", "sp-consensus", "sp-consensus-babe", + "sp-consensus-grandpa", "sp-core", - "sp-finality-grandpa", "sp-inherents", "sp-io", "sp-keyring", @@ -4928,8 +4929,8 @@ dependencies = [ "sc-consensus-babe", "sc-consensus-babe-rpc", "sc-consensus-epochs", - "sc-finality-grandpa", - "sc-finality-grandpa-rpc", + "sc-consensus-grandpa", + "sc-consensus-grandpa-rpc", "sc-rpc", "sc-rpc-api", "sc-rpc-spec-v2", @@ -4973,8 +4974,8 @@ dependencies = [ "sc-client-api", "sc-consensus", "sc-consensus-aura", + "sc-consensus-grandpa", "sc-executor", - "sc-finality-grandpa", "sc-keystore", "sc-rpc", "sc-rpc-api", @@ -4987,8 +4988,8 @@ dependencies = [ "sp-blockchain", "sp-consensus", "sp-consensus-aura", + "sp-consensus-grandpa", "sp-core", - "sp-finality-grandpa", "sp-inherents", "sp-io", "sp-keyring", @@ -5024,6 +5025,7 @@ dependencies = [ "sp-api", "sp-block-builder", "sp-consensus-aura", + "sp-consensus-grandpa", "sp-core", "sp-inherents", "sp-offchain", @@ -5866,8 +5868,8 @@ dependencies = [ "parity-scale-codec", "scale-info", "sp-application-crypto", + "sp-consensus-grandpa", "sp-core", - "sp-finality-grandpa", "sp-io", "sp-keyring", "sp-runtime", @@ -8304,6 +8306,76 @@ dependencies = [ "sp-runtime", ] +[[package]] +name = "sc-consensus-grandpa" +version = "0.10.0-dev" +dependencies = [ + "ahash 0.8.3", + "array-bytes", + "assert_matches", + "async-trait", + "dyn-clone", + "finality-grandpa", + "fork-tree", + "futures", + "futures-timer", + "log", + "parity-scale-codec", + "parking_lot 0.12.1", + "rand 0.8.5", + "sc-block-builder", + "sc-chain-spec", + "sc-client-api", + "sc-consensus", + "sc-network", + "sc-network-common", + "sc-network-gossip", + "sc-network-test", + "sc-telemetry", + "sc-utils", + "serde", + "serde_json", + "sp-api", + "sp-application-crypto", + "sp-arithmetic", + "sp-blockchain", + "sp-consensus", + "sp-consensus-grandpa", + "sp-core", + "sp-keyring", + "sp-keystore", + "sp-runtime", + "sp-tracing", + "substrate-prometheus-endpoint", + "substrate-test-runtime-client", + "thiserror", + "tokio", +] + +[[package]] +name = "sc-consensus-grandpa-rpc" +version = "0.10.0-dev" +dependencies = [ + "finality-grandpa", + "futures", + "jsonrpsee", + "log", + "parity-scale-codec", + "sc-block-builder", + "sc-client-api", + "sc-consensus-grandpa", + "sc-rpc", + "serde", + "sp-blockchain", + "sp-consensus-grandpa", + "sp-core", + "sp-keyring", + "sp-runtime", + "substrate-test-runtime-client", + "thiserror", + "tokio", +] + [[package]] name = "sc-consensus-manual-seal" version = "0.10.0-dev" @@ -8476,76 +8548,6 @@ dependencies = [ "wat", ] -[[package]] -name = "sc-finality-grandpa" -version = "0.10.0-dev" -dependencies = [ - "ahash 0.8.3", - "array-bytes", - "assert_matches", - "async-trait", - "dyn-clone", - "finality-grandpa", - "fork-tree", - "futures", - "futures-timer", - "log", - "parity-scale-codec", - "parking_lot 0.12.1", - "rand 0.8.5", - "sc-block-builder", - "sc-chain-spec", - "sc-client-api", - "sc-consensus", - "sc-network", - "sc-network-common", - "sc-network-gossip", - "sc-network-test", - "sc-telemetry", - "sc-utils", - "serde", - "serde_json", - "sp-api", - "sp-application-crypto", - "sp-arithmetic", - "sp-blockchain", - "sp-consensus", - "sp-core", - "sp-finality-grandpa", - "sp-keyring", - "sp-keystore", - "sp-runtime", - "sp-tracing", - "substrate-prometheus-endpoint", - "substrate-test-runtime-client", - "thiserror", - "tokio", -] - -[[package]] -name = "sc-finality-grandpa-rpc" -version = "0.10.0-dev" -dependencies = [ - "finality-grandpa", - "futures", - "jsonrpsee", - "log", - "parity-scale-codec", - "sc-block-builder", - "sc-client-api", - "sc-finality-grandpa", - "sc-rpc", - "serde", - "sp-blockchain", - "sp-core", - "sp-finality-grandpa", - "sp-keyring", - "sp-runtime", - "substrate-test-runtime-client", - "thiserror", - "tokio", -] - [[package]] name = "sc-informant" version = "0.10.0-dev" @@ -8673,7 +8675,7 @@ dependencies = [ "smallvec", "sp-blockchain", "sp-consensus", - "sp-finality-grandpa", + "sp-consensus-grandpa", "sp-runtime", "substrate-prometheus-endpoint", "thiserror", @@ -8745,8 +8747,8 @@ dependencies = [ "sp-arithmetic", "sp-blockchain", "sp-consensus", + "sp-consensus-grandpa", "sp-core", - "sp-finality-grandpa", "sp-runtime", "sp-test-primitives", "sp-tracing", @@ -9114,7 +9116,7 @@ dependencies = [ "sc-client-api", "sc-consensus-babe", "sc-consensus-epochs", - "sc-finality-grandpa", + "sc-consensus-grandpa", "serde", "serde_json", "sp-blockchain", @@ -9893,6 +9895,23 @@ dependencies = [ "sp-timestamp", ] +[[package]] +name = "sp-consensus-grandpa" +version = "4.0.0-dev" +dependencies = [ + "finality-grandpa", + "log", + "parity-scale-codec", + "scale-info", + "serde", + "sp-api", + "sp-application-crypto", + "sp-core", + "sp-keystore", + "sp-runtime", + "sp-std", +] + [[package]] name = "sp-consensus-pow" version = "0.10.0-dev" @@ -10023,23 +10042,6 @@ dependencies = [ "sp-storage", ] -[[package]] -name = "sp-finality-grandpa" -version = "4.0.0-dev" -dependencies = [ - "finality-grandpa", - "log", - "parity-scale-codec", - "scale-info", - "serde", - "sp-api", - "sp-application-crypto", - "sp-core", - "sp-keystore", - "sp-runtime", - "sp-std", -] - [[package]] name = "sp-inherents" version = "4.0.0-dev" @@ -10801,9 +10803,9 @@ dependencies = [ "sp-consensus", "sp-consensus-aura", "sp-consensus-babe", + "sp-consensus-grandpa", "sp-core", "sp-externalities", - "sp-finality-grandpa", "sp-inherents", "sp-io", "sp-keyring", diff --git a/Cargo.toml b/Cargo.toml index 80dd2b90f85c2..88c9c1998f415 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,8 @@ members = [ "client/consensus/babe/rpc", "client/consensus/common", "client/consensus/epochs", + "client/consensus/grandpa", + "client/consensus/grandpa/rpc", "client/consensus/manual-seal", "client/consensus/pow", "client/consensus/slots", @@ -38,8 +40,6 @@ members = [ "client/executor/runtime-test", "client/executor/wasmi", "client/executor/wasmtime", - "client/finality-grandpa", - "client/finality-grandpa/rpc", "client/informant", "client/keystore", "client/merkle-mountain-range", @@ -184,6 +184,7 @@ members = [ "primitives/consensus/aura", "primitives/consensus/babe", "primitives/consensus/common", + "primitives/consensus/grandpa", "primitives/consensus/pow", "primitives/consensus/slots", "primitives/consensus/vrf", @@ -193,7 +194,6 @@ members = [ "primitives/database", "primitives/debug-derive", "primitives/externalities", - "primitives/finality-grandpa", "primitives/inherents", "primitives/io", "primitives/keyring", diff --git a/bin/node-template/node/Cargo.toml b/bin/node-template/node/Cargo.toml index 364cfa25d3c6b..979c00120ddb7 100644 --- a/bin/node-template/node/Cargo.toml +++ b/bin/node-template/node/Cargo.toml @@ -32,8 +32,8 @@ sc-consensus-aura = { version = "0.10.0-dev", path = "../../../client/consensus/ sp-consensus-aura = { version = "0.10.0-dev", path = "../../../primitives/consensus/aura" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/common" } -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-consensus-grandpa = { version = "0.10.0-dev", path = "../../../client/consensus/grandpa" } +sp-consensus-grandpa = { version = "4.0.0-dev", path = "../../../primitives/consensus/grandpa" } sc-client-api = { version = "4.0.0-dev", path = "../../../client/api" } sp-runtime = { version = "7.0.0", path = "../../../primitives/runtime" } sp-io = { version = "7.0.0", path = "../../../primitives/io" } diff --git a/bin/node-template/node/src/chain_spec.rs b/bin/node-template/node/src/chain_spec.rs index ef34ec369a77f..e978596beb7b1 100644 --- a/bin/node-template/node/src/chain_spec.rs +++ b/bin/node-template/node/src/chain_spec.rs @@ -4,8 +4,8 @@ use node_template_runtime::{ }; use sc_service::ChainType; use sp_consensus_aura::sr25519::AuthorityId as AuraId; +use sp_consensus_grandpa::AuthorityId as GrandpaId; use sp_core::{sr25519, Pair, Public}; -use sp_finality_grandpa::AuthorityId as GrandpaId; use sp_runtime::traits::{IdentifyAccount, Verify}; // The URL for the telemetry server. diff --git a/bin/node-template/node/src/command.rs b/bin/node-template/node/src/command.rs index c3dc098cdfb3a..e121db820f2a3 100644 --- a/bin/node-template/node/src/command.rs +++ b/bin/node-template/node/src/command.rs @@ -102,7 +102,7 @@ pub fn run() -> sc_cli::Result<()> { let PartialComponents { client, task_manager, backend, .. } = service::new_partial(&config)?; let aux_revert = Box::new(|client, _, blocks| { - sc_finality_grandpa::revert(client, blocks)?; + sc_consensus_grandpa::revert(client, blocks)?; Ok(()) }); Ok((cmd.run(client, backend, Some(aux_revert)), task_manager)) diff --git a/bin/node-template/node/src/service.rs b/bin/node-template/node/src/service.rs index d7d075efd98ab..98485a7ad674c 100644 --- a/bin/node-template/node/src/service.rs +++ b/bin/node-template/node/src/service.rs @@ -3,8 +3,8 @@ use node_template_runtime::{self, opaque::Block, RuntimeApi}; use sc_client_api::BlockBackend; use sc_consensus_aura::{ImportQueueParams, SlotProportion, StartAuraParams}; +use sc_consensus_grandpa::SharedVoterState; pub use sc_executor::NativeElseWasmExecutor; -use sc_finality_grandpa::SharedVoterState; use sc_keystore::LocalKeystore; use sc_service::{error::Error as ServiceError, Configuration, TaskManager, WarpSyncParams}; use sc_telemetry::{Telemetry, TelemetryWorker}; @@ -46,13 +46,13 @@ pub fn new_partial( sc_consensus::DefaultImportQueue, sc_transaction_pool::FullPool, ( - sc_finality_grandpa::GrandpaBlockImport< + sc_consensus_grandpa::GrandpaBlockImport< FullBackend, Block, FullClient, FullSelectChain, >, - sc_finality_grandpa::LinkHalf, + sc_consensus_grandpa::LinkHalf, Option, ), >, @@ -103,7 +103,7 @@ pub fn new_partial( client.clone(), ); - let (grandpa_block_import, grandpa_link) = sc_finality_grandpa::block_import( + let (grandpa_block_import, grandpa_link) = sc_consensus_grandpa::block_import( client.clone(), &(client.clone() as Arc<_>), select_chain.clone(), @@ -177,7 +177,7 @@ pub fn new_full(mut config: Configuration) -> Result ))), }; } - let grandpa_protocol_name = sc_finality_grandpa::protocol_standard_name( + let grandpa_protocol_name = sc_consensus_grandpa::protocol_standard_name( &client.block_hash(0).ok().flatten().expect("Genesis block exists; qed"), &config.chain_spec, ); @@ -185,8 +185,8 @@ pub fn new_full(mut config: Configuration) -> Result 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( + .push(sc_consensus_grandpa::grandpa_peers_set_config(grandpa_protocol_name.clone())); + let warp_sync = Arc::new(sc_consensus_grandpa::warp_proof::NetworkProvider::new( backend.clone(), grandpa_link.shared_authority_set().clone(), Vec::default(), @@ -298,7 +298,7 @@ pub fn new_full(mut config: Configuration) -> Result let keystore = if role.is_authority() { Some(keystore_container.sync_keystore()) } else { None }; - let grandpa_config = sc_finality_grandpa::Config { + let grandpa_config = sc_consensus_grandpa::Config { // FIXME #1578 make this available through chainspec gossip_duration: Duration::from_millis(333), justification_period: 512, @@ -316,11 +316,11 @@ pub fn new_full(mut config: Configuration) -> Result // and vote data availability than the observer. The observer has not // been tested extensively yet and having most nodes in a network run it // could lead to finality stalls. - let grandpa_config = sc_finality_grandpa::GrandpaParams { + let grandpa_config = sc_consensus_grandpa::GrandpaParams { config: grandpa_config, link: grandpa_link, network, - voting_rule: sc_finality_grandpa::VotingRulesBuilder::default().build(), + voting_rule: sc_consensus_grandpa::VotingRulesBuilder::default().build(), prometheus_registry, shared_voter_state: SharedVoterState::empty(), telemetry: telemetry.as_ref().map(|x| x.handle()), @@ -331,7 +331,7 @@ pub fn new_full(mut config: Configuration) -> Result task_manager.spawn_essential_handle().spawn_blocking( "grandpa-voter", None, - sc_finality_grandpa::run_grandpa_voter(grandpa_config)?, + sc_consensus_grandpa::run_grandpa_voter(grandpa_config)?, ); } diff --git a/bin/node-template/runtime/Cargo.toml b/bin/node-template/runtime/Cargo.toml index dd453d9f1ec79..55fdea7f59031 100644 --- a/bin/node-template/runtime/Cargo.toml +++ b/bin/node-template/runtime/Cargo.toml @@ -30,6 +30,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 = { 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-consensus-grandpa = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/consensus/grandpa" } 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" } @@ -78,6 +79,7 @@ std = [ "sp-api/std", "sp-block-builder/std", "sp-consensus-aura/std", + "sp-consensus-grandpa/std", "sp-core/std", "sp-inherents/std", "sp-offchain/std", diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs index ff9ac66d6afec..57e4470c762ac 100644 --- a/bin/node-template/runtime/src/lib.rs +++ b/bin/node-template/runtime/src/lib.rs @@ -6,9 +6,7 @@ #[cfg(feature = "std")] include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); -use pallet_grandpa::{ - fg_primitives, AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList, -}; +use pallet_grandpa::AuthorityId as GrandpaId; use sp_api::impl_runtime_apis; use sp_consensus_aura::sr25519::AuthorityId as AuraId; use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; @@ -429,29 +427,29 @@ impl_runtime_apis! { } } - impl fg_primitives::GrandpaApi for Runtime { - fn grandpa_authorities() -> GrandpaAuthorityList { + impl sp_consensus_grandpa::GrandpaApi for Runtime { + fn grandpa_authorities() -> sp_consensus_grandpa::AuthorityList { Grandpa::grandpa_authorities() } - fn current_set_id() -> fg_primitives::SetId { + fn current_set_id() -> sp_consensus_grandpa::SetId { Grandpa::current_set_id() } fn submit_report_equivocation_unsigned_extrinsic( - _equivocation_proof: fg_primitives::EquivocationProof< + _equivocation_proof: sp_consensus_grandpa::EquivocationProof< ::Hash, NumberFor, >, - _key_owner_proof: fg_primitives::OpaqueKeyOwnershipProof, + _key_owner_proof: sp_consensus_grandpa::OpaqueKeyOwnershipProof, ) -> Option<()> { None } fn generate_key_ownership_proof( - _set_id: fg_primitives::SetId, + _set_id: sp_consensus_grandpa::SetId, _authority_id: GrandpaId, - ) -> Option { + ) -> Option { // NOTE: this is the only implementation possible since we've // defined our key owner proof type as a bottom type (i.e. a type // with no values). diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index 9ec06d9d9cab1..b93019b7cc219 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -47,7 +47,7 @@ rand = "0.8" # primitives 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" } +grandpa-primitives = { version = "4.0.0-dev", package = "sp-consensus-grandpa", path = "../../../primitives/consensus/grandpa" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-core = { version = "7.0.0", path = "../../../primitives/core" } sp-runtime = { version = "7.0.0", path = "../../../primitives/runtime" } @@ -70,7 +70,7 @@ 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" } -grandpa = { version = "0.10.0-dev", package = "sc-finality-grandpa", path = "../../../client/finality-grandpa" } +grandpa = { version = "0.10.0-dev", package = "sc-consensus-grandpa", path = "../../../client/consensus/grandpa" } sc-rpc = { version = "4.0.0-dev", path = "../../../client/rpc" } sc-basic-authorship = { version = "0.10.0-dev", path = "../../../client/basic-authorship" } sc-service = { version = "0.10.0-dev", default-features = false, path = "../../../client/service" } diff --git a/bin/node/rpc/Cargo.toml b/bin/node/rpc/Cargo.toml index f34922a287dfe..0ea6f49bd6094 100644 --- a/bin/node/rpc/Cargo.toml +++ b/bin/node/rpc/Cargo.toml @@ -22,8 +22,8 @@ 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-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-consensus-grandpa = { version = "0.10.0-dev", path = "../../../client/consensus/grandpa" } +sc-consensus-grandpa-rpc = { version = "0.10.0-dev", path = "../../../client/consensus/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" } diff --git a/bin/node/rpc/src/lib.rs b/bin/node/rpc/src/lib.rs index 40e4de6b9dd62..7c2f7c15e05c8 100644 --- a/bin/node/rpc/src/lib.rs +++ b/bin/node/rpc/src/lib.rs @@ -38,7 +38,7 @@ use node_primitives::{AccountId, Balance, Block, BlockNumber, Hash, Index}; use sc_client_api::AuxStore; use sc_consensus_babe::{BabeConfiguration, Epoch}; use sc_consensus_epochs::SharedEpochChanges; -use sc_finality_grandpa::{ +use sc_consensus_grandpa::{ FinalityProofProvider, GrandpaJustificationStream, SharedAuthoritySet, SharedVoterState, }; use sc_rpc::SubscriptionTaskExecutor; @@ -120,7 +120,7 @@ where 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}; + use sc_consensus_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}; diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index 3df4596aaad90..993108bf732b1 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -27,6 +27,7 @@ log = { version = "0.4.17", default-features = false } # primitives sp-authority-discovery = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/authority-discovery" } sp-consensus-babe = { version = "0.10.0-dev", default-features = false, path = "../../../primitives/consensus/babe" } +sp-consensus-grandpa = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/consensus/grandpa" } sp-block-builder = { path = "../../../primitives/block-builder", default-features = false, version = "4.0.0-dev" } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/inherents" } node-primitives = { version = "2.0.0", default-features = false, path = "../primitives" } @@ -134,6 +135,7 @@ std = [ "pallet-authority-discovery/std", "pallet-authorship/std", "sp-consensus-babe/std", + "sp-consensus-grandpa/std", "pallet-babe/std", "pallet-bags-list/std", "pallet-balances/std", diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 14b74425f094b..f8589036f7853 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -52,9 +52,6 @@ use frame_system::{ pub use node_primitives::{AccountId, Signature}; use node_primitives::{AccountIndex, Balance, BlockNumber, Hash, Index, Moment}; 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_nfts::PalletFeatures; use pallet_nis::WithMaximumOf; @@ -63,6 +60,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_consensus_grandpa::AuthorityId as GrandpaId; use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; use sp_inherents::{CheckInherentsResult, InherentData}; use sp_runtime::{ @@ -1957,21 +1955,21 @@ impl_runtime_apis! { } } - impl fg_primitives::GrandpaApi for Runtime { - fn grandpa_authorities() -> GrandpaAuthorityList { + impl sp_consensus_grandpa::GrandpaApi for Runtime { + fn grandpa_authorities() -> sp_consensus_grandpa::AuthorityList { Grandpa::grandpa_authorities() } - fn current_set_id() -> fg_primitives::SetId { + fn current_set_id() -> sp_consensus_grandpa::SetId { Grandpa::current_set_id() } fn submit_report_equivocation_unsigned_extrinsic( - equivocation_proof: fg_primitives::EquivocationProof< + equivocation_proof: sp_consensus_grandpa::EquivocationProof< ::Hash, NumberFor, >, - key_owner_proof: fg_primitives::OpaqueKeyOwnershipProof, + key_owner_proof: sp_consensus_grandpa::OpaqueKeyOwnershipProof, ) -> Option<()> { let key_owner_proof = key_owner_proof.decode()?; @@ -1982,14 +1980,14 @@ impl_runtime_apis! { } fn generate_key_ownership_proof( - _set_id: fg_primitives::SetId, + _set_id: sp_consensus_grandpa::SetId, authority_id: GrandpaId, - ) -> Option { + ) -> Option { use codec::Encode; - Historical::prove((fg_primitives::KEY_TYPE, authority_id)) + Historical::prove((sp_consensus_grandpa::KEY_TYPE, authority_id)) .map(|p| p.encode()) - .map(fg_primitives::OpaqueKeyOwnershipProof::new) + .map(sp_consensus_grandpa::OpaqueKeyOwnershipProof::new) } } diff --git a/client/beefy/Cargo.toml b/client/beefy/Cargo.toml index 2976d1474012a..eb616823680aa 100644 --- a/client/beefy/Cargo.toml +++ b/client/beefy/Cargo.toml @@ -43,7 +43,7 @@ tempfile = "3.1.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" } +sp-consensus-grandpa = { version = "4.0.0-dev", path = "../../primitives/consensus/grandpa" } 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/consensus/grandpa/Cargo.toml b/client/consensus/grandpa/Cargo.toml new file mode 100644 index 0000000000000..511e546aa7256 --- /dev/null +++ b/client/consensus/grandpa/Cargo.toml @@ -0,0 +1,60 @@ +[package] +name = "sc-consensus-grandpa" +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 = "Integration of the GRANDPA finality gadget into substrate." +documentation = "https://docs.rs/sc-consensus-grandpa" +readme = "README.md" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +ahash = "0.8.2" +array-bytes = "4.1" +async-trait = "0.1.57" +dyn-clone = "1.0" +finality-grandpa = { version = "0.16.1", features = ["derive-codec"] } +futures = "0.3.21" +futures-timer = "3.0.1" +log = "0.4.17" +parity-scale-codec = { version = "3.2.2", features = ["derive"] } +parking_lot = "0.12.1" +rand = "0.8.5" +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" } +sc-block-builder = { version = "0.10.0-dev", path = "../../block-builder" } +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 = "../common" } +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" } +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 = "7.0.0", path = "../../../primitives/core" } +sp-consensus-grandpa = { version = "4.0.0-dev", path = "../../../primitives/consensus/grandpa" } +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" +finality-grandpa = { version = "0.16.1", features = ["derive-codec", "test-helpers"] } +serde = "1.0.136" +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" } +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/README.md b/client/consensus/grandpa/README.md similarity index 100% rename from client/finality-grandpa/README.md rename to client/consensus/grandpa/README.md diff --git a/client/consensus/grandpa/rpc/Cargo.toml b/client/consensus/grandpa/rpc/Cargo.toml new file mode 100644 index 0000000000000..4880b50d30630 --- /dev/null +++ b/client/consensus/grandpa/rpc/Cargo.toml @@ -0,0 +1,34 @@ +[package] +name = "sc-consensus-grandpa-rpc" +version = "0.10.0-dev" +authors = ["Parity Technologies "] +description = "RPC extensions for the GRANDPA finality gadget" +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] +finality-grandpa = { version = "0.16.1", features = ["derive-codec"] } +futures = "0.3.16" +jsonrpsee = { version = "0.16.2", features = ["client-core", "server", "macros"] } +log = "0.4.8" +parity-scale-codec = { version = "3.2.2", features = ["derive"] } +serde = { version = "1.0.105", features = ["derive"] } +thiserror = "1.0" +sc-client-api = { version = "4.0.0-dev", path = "../../../api" } +sc-consensus-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 = "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 = "7.0.0", path = "../../../../primitives/core" } +sp-consensus-grandpa = { version = "4.0.0-dev", path = "../../../../primitives/consensus/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.22.0", features = ["macros"] } diff --git a/client/finality-grandpa/rpc/README.md b/client/consensus/grandpa/rpc/README.md similarity index 100% rename from client/finality-grandpa/rpc/README.md rename to client/consensus/grandpa/rpc/README.md diff --git a/client/finality-grandpa/rpc/src/error.rs b/client/consensus/grandpa/rpc/src/error.rs similarity index 97% rename from client/finality-grandpa/rpc/src/error.rs rename to client/consensus/grandpa/rpc/src/error.rs index 885408d8f1d3b..4884380cd22d0 100644 --- a/client/finality-grandpa/rpc/src/error.rs +++ b/client/consensus/grandpa/rpc/src/error.rs @@ -35,7 +35,7 @@ pub enum Error { VoterStateReportsUnreasonablyLargeNumbers, /// GRANDPA prove finality failed. #[error("GRANDPA prove finality rpc failed: {0}")] - ProveFinalityFailed(#[from] sc_finality_grandpa::FinalityProofError), + ProveFinalityFailed(#[from] sc_consensus_grandpa::FinalityProofError), } /// The error codes returned by jsonrpc. diff --git a/client/finality-grandpa/rpc/src/finality.rs b/client/consensus/grandpa/rpc/src/finality.rs similarity index 88% rename from client/finality-grandpa/rpc/src/finality.rs rename to client/consensus/grandpa/rpc/src/finality.rs index dd1f0af8606c6..f8ec01781ac6b 100644 --- a/client/finality-grandpa/rpc/src/finality.rs +++ b/client/consensus/grandpa/rpc/src/finality.rs @@ -18,7 +18,7 @@ use serde::{Deserialize, Serialize}; -use sc_finality_grandpa::FinalityProofProvider; +use sc_consensus_grandpa::FinalityProofProvider; use sp_runtime::traits::{Block as BlockT, NumberFor}; #[derive(Serialize, Deserialize)] @@ -31,7 +31,7 @@ pub trait RpcFinalityProofProvider { fn rpc_prove_finality( &self, block: NumberFor, - ) -> Result, sc_finality_grandpa::FinalityProofError>; + ) -> Result, sc_consensus_grandpa::FinalityProofError>; } impl RpcFinalityProofProvider for FinalityProofProvider @@ -43,7 +43,7 @@ where fn rpc_prove_finality( &self, block: NumberFor, - ) -> Result, sc_finality_grandpa::FinalityProofError> { + ) -> Result, sc_consensus_grandpa::FinalityProofError> { self.prove_finality(block).map(|x| x.map(|y| EncodedFinalityProof(y.into()))) } } diff --git a/client/finality-grandpa/rpc/src/lib.rs b/client/consensus/grandpa/rpc/src/lib.rs similarity index 96% rename from client/finality-grandpa/rpc/src/lib.rs rename to client/consensus/grandpa/rpc/src/lib.rs index 8f06531be5f41..c6298bff969bd 100644 --- a/client/finality-grandpa/rpc/src/lib.rs +++ b/client/consensus/grandpa/rpc/src/lib.rs @@ -35,7 +35,7 @@ mod finality; mod notification; mod report; -use sc_finality_grandpa::GrandpaJustificationStream; +use sc_consensus_grandpa::GrandpaJustificationStream; use sc_rpc::SubscriptionTaskExecutor; use sp_runtime::traits::{Block as BlockT, NumberFor}; @@ -105,7 +105,7 @@ where fn subscribe_justifications(&self, mut sink: SubscriptionSink) -> SubscriptionResult { let stream = self.justification_stream.subscribe(100_000).map( - |x: sc_finality_grandpa::GrandpaJustification| { + |x: sc_consensus_grandpa::GrandpaJustification| { JustificationNotification::from(x) }, ); @@ -143,7 +143,7 @@ mod tests { }; use parity_scale_codec::{Decode, Encode}; use sc_block_builder::{BlockBuilder, RecordProof}; - use sc_finality_grandpa::{ + use sc_consensus_grandpa::{ report, AuthorityId, FinalityProof, GrandpaJustification, GrandpaJustificationSender, }; use sp_blockchain::HeaderBackend; @@ -200,7 +200,7 @@ mod tests { fn rpc_prove_finality( &self, _block: NumberFor, - ) -> Result, sc_finality_grandpa::FinalityProofError> { + ) -> Result, sc_consensus_grandpa::FinalityProofError> { Ok(Some(EncodedFinalityProof( self.finality_proof .as_ref() @@ -216,7 +216,7 @@ mod tests { 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 { + let best_round_state = sc_consensus_grandpa::report::RoundState { total_weight: 100_u64.try_into().unwrap(), threshold_weight: 67_u64.try_into().unwrap(), prevote_current_weight: 50.into(), @@ -225,7 +225,7 @@ mod tests { precommit_ids: HashSet::new(), }; - let past_round_state = sc_finality_grandpa::report::RoundState { + let past_round_state = sc_consensus_grandpa::report::RoundState { total_weight: 100_u64.try_into().unwrap(), threshold_weight: 67_u64.try_into().unwrap(), prevote_current_weight: 100.into(), @@ -364,7 +364,7 @@ mod tests { }; let msg = finality_grandpa::Message::Precommit(precommit.clone()); - let encoded = sp_finality_grandpa::localized_payload(round, set_id, &msg); + let encoded = sp_consensus_grandpa::localized_payload(round, set_id, &msg); let signature = peers[0].sign(&encoded[..]).into(); let precommit = finality_grandpa::SignedPrecommit { diff --git a/client/finality-grandpa/rpc/src/notification.rs b/client/consensus/grandpa/rpc/src/notification.rs similarity index 96% rename from client/finality-grandpa/rpc/src/notification.rs rename to client/consensus/grandpa/rpc/src/notification.rs index 45e7d34889b3f..42b9123ed8c14 100644 --- a/client/finality-grandpa/rpc/src/notification.rs +++ b/client/consensus/grandpa/rpc/src/notification.rs @@ -17,7 +17,7 @@ // along with this program. If not, see . use parity_scale_codec::Encode; -use sc_finality_grandpa::GrandpaJustification; +use sc_consensus_grandpa::GrandpaJustification; use serde::{Deserialize, Serialize}; use sp_runtime::traits::Block as BlockT; diff --git a/client/finality-grandpa/rpc/src/report.rs b/client/consensus/grandpa/rpc/src/report.rs similarity index 97% rename from client/finality-grandpa/rpc/src/report.rs rename to client/consensus/grandpa/rpc/src/report.rs index 58e59d8aec606..ae4fd76d2857a 100644 --- a/client/finality-grandpa/rpc/src/report.rs +++ b/client/consensus/grandpa/rpc/src/report.rs @@ -24,7 +24,7 @@ use std::{ use serde::{Deserialize, Serialize}; -use sc_finality_grandpa::{report, AuthorityId, SharedAuthoritySet, SharedVoterState}; +use sc_consensus_grandpa::{report, AuthorityId, SharedAuthoritySet, SharedVoterState}; use crate::error::Error; diff --git a/client/finality-grandpa/src/authorities.rs b/client/consensus/grandpa/src/authorities.rs similarity index 99% rename from client/finality-grandpa/src/authorities.rs rename to client/consensus/grandpa/src/authorities.rs index 245c6bfe3c300..623223e41eb82 100644 --- a/client/finality-grandpa/src/authorities.rs +++ b/client/consensus/grandpa/src/authorities.rs @@ -27,7 +27,7 @@ use parity_scale_codec::{Decode, Encode}; use parking_lot::MappedMutexGuard; use sc_consensus::shared_data::{SharedData, SharedDataLocked}; use sc_telemetry::{telemetry, TelemetryHandle, CONSENSUS_INFO}; -use sp_finality_grandpa::{AuthorityId, AuthorityList}; +use sp_consensus_grandpa::{AuthorityId, AuthorityList}; use crate::{SetId, LOG_TARGET}; diff --git a/client/finality-grandpa/src/aux_schema.rs b/client/consensus/grandpa/src/aux_schema.rs similarity index 99% rename from client/finality-grandpa/src/aux_schema.rs rename to client/consensus/grandpa/src/aux_schema.rs index fbb0ab8a8bb06..97a8bc660317a 100644 --- a/client/finality-grandpa/src/aux_schema.rs +++ b/client/consensus/grandpa/src/aux_schema.rs @@ -27,7 +27,7 @@ use parity_scale_codec::{Decode, Encode}; use fork_tree::ForkTree; use sc_client_api::backend::AuxStore; use sp_blockchain::{Error as ClientError, Result as ClientResult}; -use sp_finality_grandpa::{AuthorityList, RoundNumber, SetId}; +use sp_consensus_grandpa::{AuthorityList, RoundNumber, SetId}; use sp_runtime::traits::{Block as BlockT, NumberFor}; use crate::{ @@ -501,8 +501,8 @@ pub(crate) fn load_authorities( #[cfg(test)] mod test { use super::*; + use sp_consensus_grandpa::AuthorityId; use sp_core::{crypto::UncheckedFrom, H256}; - use sp_finality_grandpa::AuthorityId; use substrate_test_runtime_client::{self, runtime::Block}; fn dummy_id() -> AuthorityId { diff --git a/client/finality-grandpa/src/communication/gossip.rs b/client/consensus/grandpa/src/communication/gossip.rs similarity index 99% rename from client/finality-grandpa/src/communication/gossip.rs rename to client/consensus/grandpa/src/communication/gossip.rs index 65e765a4cb244..cf476f8e32222 100644 --- a/client/finality-grandpa/src/communication/gossip.rs +++ b/client/consensus/grandpa/src/communication/gossip.rs @@ -95,7 +95,7 @@ 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}; -use sp_finality_grandpa::AuthorityId; +use sp_consensus_grandpa::AuthorityId; use sp_runtime::traits::{Block as BlockT, NumberFor, Zero}; use super::{benefit, cost, Round, SetId, NEIGHBOR_REBROADCAST_PERIOD}; @@ -931,7 +931,7 @@ impl Inner { return Action::Discard(cost::UNKNOWN_VOTER) } - if !sp_finality_grandpa::check_message_signature( + if !sp_consensus_grandpa::check_message_signature( &full.message.message, &full.message.id, &full.message.signature, diff --git a/client/finality-grandpa/src/communication/mod.rs b/client/consensus/grandpa/src/communication/mod.rs similarity index 99% rename from client/finality-grandpa/src/communication/mod.rs rename to client/consensus/grandpa/src/communication/mod.rs index 3c1de1f4699d8..d3ade4bf3d49d 100644 --- a/client/finality-grandpa/src/communication/mod.rs +++ b/client/consensus/grandpa/src/communication/mod.rs @@ -61,7 +61,7 @@ use gossip::{ }; use sc_network_common::service::{NetworkBlock, NetworkSyncForkRequest}; use sc_utils::mpsc::TracingUnboundedReceiver; -use sp_finality_grandpa::{AuthorityId, AuthoritySignature, RoundNumber, SetId as SetIdNumber}; +use sp_consensus_grandpa::{AuthorityId, AuthoritySignature, RoundNumber, SetId as SetIdNumber}; pub mod gossip; mod periodic; @@ -739,7 +739,7 @@ impl Sink> for OutgoingMessages { // when locals exist, sign messages on import if let Some(ref keystore) = self.keystore { let target_hash = *(msg.target().0); - let signed = sp_finality_grandpa::sign_message( + let signed = sp_consensus_grandpa::sign_message( keystore.keystore(), msg, keystore.local_id().clone(), @@ -842,7 +842,7 @@ fn check_compact_commit( use crate::communication::gossip::Misbehavior; use finality_grandpa::Message as GrandpaMessage; - if !sp_finality_grandpa::check_message_signature_with_buffer( + if !sp_consensus_grandpa::check_message_signature_with_buffer( &GrandpaMessage::Precommit(precommit.clone()), id, sig, @@ -934,7 +934,7 @@ fn check_catch_up( for (msg, id, sig) in messages { signatures_checked += 1; - if !sp_finality_grandpa::check_message_signature_with_buffer( + if !sp_consensus_grandpa::check_message_signature_with_buffer( &msg, id, sig, round, set_id, buf, ) { debug!(target: LOG_TARGET, "Bad catch up message signature {}", id); diff --git a/client/finality-grandpa/src/communication/periodic.rs b/client/consensus/grandpa/src/communication/periodic.rs similarity index 100% rename from client/finality-grandpa/src/communication/periodic.rs rename to client/consensus/grandpa/src/communication/periodic.rs diff --git a/client/finality-grandpa/src/communication/tests.rs b/client/consensus/grandpa/src/communication/tests.rs similarity index 97% rename from client/finality-grandpa/src/communication/tests.rs rename to client/consensus/grandpa/src/communication/tests.rs index 19c2e4fef45e4..21e2e978c8767 100644 --- a/client/finality-grandpa/src/communication/tests.rs +++ b/client/consensus/grandpa/src/communication/tests.rs @@ -37,7 +37,7 @@ use sc_network_common::{ use sc_network_gossip::Validator; use sc_network_test::{Block, Hash}; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; -use sp_finality_grandpa::AuthorityList; +use sp_consensus_grandpa::AuthorityList; use sp_keyring::Ed25519Keyring; use sp_runtime::traits::NumberFor; use std::{ @@ -237,8 +237,8 @@ fn config() -> crate::Config { fn voter_set_state() -> SharedVoterSetState { use crate::{authorities::AuthoritySet, environment::VoterSetState}; use finality_grandpa::round::State as RoundState; + use sp_consensus_grandpa::AuthorityId; use sp_core::{crypto::ByteArray, H256}; - use sp_finality_grandpa::AuthorityId; let state = RoundState::genesis((H256::zero(), 0)); let base = state.prevote_ghost.unwrap(); @@ -306,7 +306,7 @@ fn good_commit_leads_to_relay() { let target_number = 500; let precommit = finality_grandpa::Precommit { target_hash, target_number }; - let payload = sp_finality_grandpa::localized_payload( + let payload = sp_consensus_grandpa::localized_payload( round, set_id, &finality_grandpa::Message::Precommit(precommit.clone()), @@ -318,7 +318,7 @@ fn good_commit_leads_to_relay() { for (i, key) in private.iter().enumerate() { precommits.push(precommit.clone()); - let signature = sp_finality_grandpa::AuthoritySignature::from(key.sign(&payload[..])); + let signature = sp_consensus_grandpa::AuthoritySignature::from(key.sign(&payload[..])); auth_data.push((signature, public[i].0.clone())) } @@ -456,7 +456,7 @@ fn bad_commit_leads_to_report() { let target_number = 500; let precommit = finality_grandpa::Precommit { target_hash, target_number }; - let payload = sp_finality_grandpa::localized_payload( + let payload = sp_consensus_grandpa::localized_payload( round, set_id, &finality_grandpa::Message::Precommit(precommit.clone()), @@ -468,7 +468,7 @@ fn bad_commit_leads_to_report() { for (i, key) in private.iter().enumerate() { precommits.push(precommit.clone()); - let signature = sp_finality_grandpa::AuthoritySignature::from(key.sign(&payload[..])); + let signature = sp_consensus_grandpa::AuthoritySignature::from(key.sign(&payload[..])); auth_data.push((signature, public[i].0.clone())) } @@ -631,7 +631,7 @@ fn local_chain_spec() -> Box { } } let chain_spec = GenericChainSpec::::from_json_bytes( - &include_bytes!("../../../chain-spec/res/chain_spec.json")[..], + &include_bytes!("../../../../chain-spec/res/chain_spec.json")[..], ) .unwrap(); chain_spec.cloned_box() diff --git a/client/finality-grandpa/src/environment.rs b/client/consensus/grandpa/src/environment.rs similarity index 99% rename from client/finality-grandpa/src/environment.rs rename to client/consensus/grandpa/src/environment.rs index cdc98fc2206a8..3425426617115 100644 --- a/client/finality-grandpa/src/environment.rs +++ b/client/consensus/grandpa/src/environment.rs @@ -42,7 +42,7 @@ use sc_client_api::{ use sc_telemetry::{telemetry, TelemetryHandle, CONSENSUS_DEBUG, CONSENSUS_INFO}; use sp_blockchain::HeaderMetadata; use sp_consensus::SelectChain as SelectChainT; -use sp_finality_grandpa::{ +use sp_consensus_grandpa::{ AuthorityId, AuthoritySignature, Equivocation, EquivocationProof, GrandpaApi, RoundNumber, SetId, GRANDPA_ENGINE_ID, }; diff --git a/client/finality-grandpa/src/finality_proof.rs b/client/consensus/grandpa/src/finality_proof.rs similarity index 98% rename from client/finality-grandpa/src/finality_proof.rs rename to client/consensus/grandpa/src/finality_proof.rs index b042d6fce9f7a..8a8a688583e34 100644 --- a/client/finality-grandpa/src/finality_proof.rs +++ b/client/consensus/grandpa/src/finality_proof.rs @@ -42,7 +42,7 @@ use std::sync::Arc; use parity_scale_codec::{Decode, Encode}; use sc_client_api::backend::Backend; use sp_blockchain::{Backend as BlockchainBackend, HeaderBackend}; -use sp_finality_grandpa::GRANDPA_ENGINE_ID; +use sp_consensus_grandpa::GRANDPA_ENGINE_ID; use sp_runtime::{ generic::BlockId, traits::{Block as BlockT, Header as HeaderT, NumberFor, One}, @@ -264,8 +264,8 @@ mod tests { use sc_block_builder::BlockBuilderProvider; use sc_client_api::{apply_aux, LockImportRun}; use sp_consensus::BlockOrigin; + use sp_consensus_grandpa::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}, @@ -279,7 +279,7 @@ mod tests { /// AND if at least one of those headers is invalid, all other MUST be considered invalid. fn check_finality_proof( current_set_id: SetId, - current_authorities: sp_finality_grandpa::AuthorityList, + current_authorities: sp_consensus_grandpa::AuthorityList, remote_proof: Vec, ) -> sp_blockchain::Result> where @@ -402,7 +402,7 @@ mod tests { }; let grandpa_just: GrandpaJustification = - sp_finality_grandpa::GrandpaJustification::
{ + sp_consensus_grandpa::GrandpaJustification::
{ round: 8, votes_ancestries: Vec::new(), commit, @@ -442,7 +442,7 @@ mod tests { }; let msg = finality_grandpa::Message::Precommit(precommit.clone()); - let encoded = sp_finality_grandpa::localized_payload(round, set_id, &msg); + let encoded = sp_consensus_grandpa::localized_payload(round, set_id, &msg); let signature = voter.sign(&encoded[..]).into(); let signed_precommit = finality_grandpa::SignedPrecommit { diff --git a/client/finality-grandpa/src/import.rs b/client/consensus/grandpa/src/import.rs similarity index 99% rename from client/finality-grandpa/src/import.rs rename to client/consensus/grandpa/src/import.rs index 19c42463715fb..c1f6cb566dae9 100644 --- a/client/finality-grandpa/src/import.rs +++ b/client/consensus/grandpa/src/import.rs @@ -31,8 +31,8 @@ use sc_utils::mpsc::TracingUnboundedSender; use sp_api::{Core, RuntimeApiInfo, TransactionFor}; use sp_blockchain::{well_known_cache_keys, BlockStatus}; use sp_consensus::{BlockOrigin, Error as ConsensusError, SelectChain}; +use sp_consensus_grandpa::{ConsensusLog, GrandpaApi, ScheduledChange, SetId, GRANDPA_ENGINE_ID}; use sp_core::hashing::twox_128; -use sp_finality_grandpa::{ConsensusLog, GrandpaApi, ScheduledChange, SetId, GRANDPA_ENGINE_ID}; use sp_runtime::{ generic::OpaqueDigestItemId, traits::{Block as BlockT, Header as HeaderT, NumberFor, Zero}, diff --git a/client/finality-grandpa/src/justification.rs b/client/consensus/grandpa/src/justification.rs similarity index 93% rename from client/finality-grandpa/src/justification.rs rename to client/consensus/grandpa/src/justification.rs index 1534ca752cb6e..c300a3d7ac43c 100644 --- a/client/finality-grandpa/src/justification.rs +++ b/client/consensus/grandpa/src/justification.rs @@ -25,7 +25,7 @@ use std::{ use finality_grandpa::{voter_set::VoterSet, Error as GrandpaError}; use parity_scale_codec::{Decode, Encode}; use sp_blockchain::{Error as ClientError, HeaderBackend}; -use sp_finality_grandpa::AuthorityId; +use sp_consensus_grandpa::AuthorityId; use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor}; use crate::{AuthorityList, Commit, Error}; @@ -41,22 +41,22 @@ use crate::{AuthorityList, Commit, Error}; #[derive(Clone, Encode, Decode, PartialEq, Eq, Debug)] pub struct GrandpaJustification { /// The GRANDPA justification for block finality. - pub justification: sp_finality_grandpa::GrandpaJustification, + pub justification: sp_consensus_grandpa::GrandpaJustification, _block: PhantomData, } -impl From> +impl From> for GrandpaJustification { - fn from(justification: sp_finality_grandpa::GrandpaJustification) -> Self { + fn from(justification: sp_consensus_grandpa::GrandpaJustification) -> Self { Self { justification, _block: Default::default() } } } -impl Into> +impl Into> for GrandpaJustification { - fn into(self) -> sp_finality_grandpa::GrandpaJustification { + fn into(self) -> sp_consensus_grandpa::GrandpaJustification { self.justification } } @@ -122,7 +122,7 @@ impl GrandpaJustification { } } - Ok(sp_finality_grandpa::GrandpaJustification { round, commit, votes_ancestries }.into()) + Ok(sp_consensus_grandpa::GrandpaJustification { round, commit, votes_ancestries }.into()) } /// Decode a GRANDPA justification and validate the commit and the votes' @@ -205,7 +205,7 @@ impl GrandpaJustification { let mut buf = Vec::new(); let mut visited_hashes = HashSet::new(); for signed in self.justification.commit.precommits.iter() { - if !sp_finality_grandpa::check_message_signature_with_buffer( + if !sp_consensus_grandpa::check_message_signature_with_buffer( &finality_grandpa::Message::Precommit(signed.precommit.clone()), &signed.id, &signed.signature, diff --git a/client/finality-grandpa/src/lib.rs b/client/consensus/grandpa/src/lib.rs similarity index 99% rename from client/finality-grandpa/src/lib.rs rename to client/consensus/grandpa/src/lib.rs index 4f72bb0521554..ef4beb51b4fff 100644 --- a/client/finality-grandpa/src/lib.rs +++ b/client/consensus/grandpa/src/lib.rs @@ -75,10 +75,10 @@ use sp_api::ProvideRuntimeApi; use sp_application_crypto::AppKey; use sp_blockchain::{Error as ClientError, HeaderBackend, HeaderMetadata, Result as ClientResult}; use sp_consensus::SelectChain; -use sp_core::{crypto::ByteArray, traits::CallContext}; -use sp_finality_grandpa::{ +use sp_consensus_grandpa::{ AuthorityList, AuthoritySignature, SetId, CLIENT_LOG_TARGET as LOG_TARGET, }; +use sp_core::{crypto::ByteArray, traits::CallContext}; use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; use sp_runtime::{ generic::BlockId, @@ -146,7 +146,7 @@ use environment::{Environment, VoterSetState}; use until_imported::UntilGlobalMessageBlocksImported; // Re-export these two because it's just so damn convenient. -pub use sp_finality_grandpa::{ +pub use sp_consensus_grandpa::{ AuthorityId, AuthorityPair, CatchUp, Commit, CompactCommit, GrandpaApi, Message, Precommit, Prevote, PrimaryPropose, ScheduledChange, SignedMessage, }; @@ -1091,7 +1091,7 @@ where Poll::Ready(Ok(())) => { // voters don't conclude naturally return Poll::Ready(Err(Error::Safety( - "finality-grandpa inner voter has concluded.".into(), + "consensus-grandpa inner voter has concluded.".into(), ))) }, Poll::Ready(Err(CommandOrError::Error(e))) => { diff --git a/client/finality-grandpa/src/notification.rs b/client/consensus/grandpa/src/notification.rs similarity index 100% rename from client/finality-grandpa/src/notification.rs rename to client/consensus/grandpa/src/notification.rs diff --git a/client/finality-grandpa/src/observer.rs b/client/consensus/grandpa/src/observer.rs similarity index 99% rename from client/finality-grandpa/src/observer.rs rename to client/consensus/grandpa/src/observer.rs index af56f2ac341a4..b382430ef3d4c 100644 --- a/client/finality-grandpa/src/observer.rs +++ b/client/consensus/grandpa/src/observer.rs @@ -32,7 +32,7 @@ use sc_telemetry::TelemetryHandle; use sc_utils::mpsc::TracingUnboundedReceiver; use sp_blockchain::HeaderMetadata; use sp_consensus::SelectChain; -use sp_finality_grandpa::AuthorityId; +use sp_consensus_grandpa::AuthorityId; use sp_keystore::SyncCryptoStorePtr; use sp_runtime::traits::{Block as BlockT, NumberFor}; diff --git a/client/finality-grandpa/src/tests.rs b/client/consensus/grandpa/src/tests.rs similarity index 99% rename from client/finality-grandpa/src/tests.rs rename to client/consensus/grandpa/src/tests.rs index 1a1f20797852a..7cc5e75fa148c 100644 --- a/client/finality-grandpa/src/tests.rs +++ b/client/consensus/grandpa/src/tests.rs @@ -35,10 +35,10 @@ use sc_network_test::{ }; use sp_api::{ApiRef, ProvideRuntimeApi}; use sp_consensus::{BlockOrigin, Error as ConsensusError, SelectChain}; -use sp_core::H256; -use sp_finality_grandpa::{ +use sp_consensus_grandpa::{ AuthorityList, EquivocationProof, GrandpaApi, OpaqueKeyOwnershipProof, GRANDPA_ENGINE_ID, }; +use sp_core::H256; use sp_keyring::Ed25519Keyring; use sp_keystore::{testing::KeyStore as TestKeyStore, SyncCryptoStore, SyncCryptoStorePtr}; use sp_runtime::{ @@ -398,7 +398,7 @@ async fn run_to_completion( fn add_scheduled_change(block: &mut Block, change: ScheduledChange) { block.header.digest_mut().push(DigestItem::Consensus( GRANDPA_ENGINE_ID, - sp_finality_grandpa::ConsensusLog::ScheduledChange(change).encode(), + sp_consensus_grandpa::ConsensusLog::ScheduledChange(change).encode(), )); } @@ -409,7 +409,7 @@ fn add_forced_change( ) { block.header.digest_mut().push(DigestItem::Consensus( GRANDPA_ENGINE_ID, - sp_finality_grandpa::ConsensusLog::ForcedChange(median_last_finalized, change).encode(), + sp_consensus_grandpa::ConsensusLog::ForcedChange(median_last_finalized, change).encode(), )); } @@ -1798,7 +1798,7 @@ async fn justification_with_equivocation() { 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 encoded = sp_consensus_grandpa::localized_payload(round, set_id, &msg); let precommit = finality_grandpa::SignedPrecommit { precommit: precommit.clone(), @@ -1871,7 +1871,7 @@ async fn imports_justification_for_regular_blocks_on_import() { }; let msg = finality_grandpa::Message::Precommit(precommit.clone()); - let encoded = sp_finality_grandpa::localized_payload(round, set_id, &msg); + let encoded = sp_consensus_grandpa::localized_payload(round, set_id, &msg); let signature = peers[0].sign(&encoded[..]).into(); let precommit = finality_grandpa::SignedPrecommit { @@ -1946,13 +1946,13 @@ async fn grandpa_environment_doesnt_send_equivocation_reports_for_itself() { // reporting the equivocation should fail since the offender is a local // authority (i.e. we have keys in our keystore for the given id) - let equivocation_proof = sp_finality_grandpa::Equivocation::Prevote(equivocation.clone()); + let equivocation_proof = sp_consensus_grandpa::Equivocation::Prevote(equivocation.clone()); assert!(matches!(environment.report_equivocation(equivocation_proof), Err(Error::Safety(_)))); // if we set the equivocation offender to another id for which we don't have // keys it should work equivocation.identity = TryFrom::try_from(&[1; 32][..]).unwrap(); - let equivocation_proof = sp_finality_grandpa::Equivocation::Prevote(equivocation); + let equivocation_proof = sp_consensus_grandpa::Equivocation::Prevote(equivocation); assert!(environment.report_equivocation(equivocation_proof).is_ok()); } diff --git a/client/finality-grandpa/src/until_imported.rs b/client/consensus/grandpa/src/until_imported.rs similarity index 99% rename from client/finality-grandpa/src/until_imported.rs rename to client/consensus/grandpa/src/until_imported.rs index f9ecb7df34e06..14f32ecc88366 100644 --- a/client/finality-grandpa/src/until_imported.rs +++ b/client/consensus/grandpa/src/until_imported.rs @@ -38,7 +38,7 @@ use parking_lot::Mutex; use prometheus_endpoint::{register, Gauge, PrometheusError, Registry, U64}; use sc_client_api::{BlockImportNotification, ImportNotifications}; use sc_utils::mpsc::TracingUnboundedReceiver; -use sp_finality_grandpa::AuthorityId; +use sp_consensus_grandpa::AuthorityId; use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor}; use std::{ diff --git a/client/finality-grandpa/src/voting_rule.rs b/client/consensus/grandpa/src/voting_rule.rs similarity index 100% rename from client/finality-grandpa/src/voting_rule.rs rename to client/consensus/grandpa/src/voting_rule.rs diff --git a/client/finality-grandpa/src/warp_proof.rs b/client/consensus/grandpa/src/warp_proof.rs similarity index 97% rename from client/finality-grandpa/src/warp_proof.rs rename to client/consensus/grandpa/src/warp_proof.rs index f73a0a323e593..cd4fedf96b4c4 100644 --- a/client/finality-grandpa/src/warp_proof.rs +++ b/client/consensus/grandpa/src/warp_proof.rs @@ -25,7 +25,7 @@ use crate::{ use sc_client_api::Backend as ClientBackend; 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_consensus_grandpa::{AuthorityList, SetId, GRANDPA_ENGINE_ID}; use sp_runtime::{ generic::BlockId, traits::{Block as BlockT, Header as HeaderT, NumberFor, One}, @@ -324,7 +324,7 @@ mod tests { use sc_block_builder::BlockBuilderProvider; use sp_blockchain::HeaderBackend; use sp_consensus::BlockOrigin; - use sp_finality_grandpa::GRANDPA_ENGINE_ID; + use sp_consensus_grandpa::GRANDPA_ENGINE_ID; use sp_keyring::Ed25519Keyring; use sp_runtime::traits::Header as _; use std::sync::Arc; @@ -369,9 +369,9 @@ mod tests { .collect::>(); let digest = sp_runtime::generic::DigestItem::Consensus( - sp_finality_grandpa::GRANDPA_ENGINE_ID, - sp_finality_grandpa::ConsensusLog::ScheduledChange( - sp_finality_grandpa::ScheduledChange { delay: 0u64, next_authorities }, + sp_consensus_grandpa::GRANDPA_ENGINE_ID, + sp_consensus_grandpa::ConsensusLog::ScheduledChange( + sp_consensus_grandpa::ScheduledChange { delay: 0u64, next_authorities }, ) .encode(), ); @@ -394,7 +394,7 @@ mod tests { let precommit = finality_grandpa::Precommit { target_hash, target_number }; let msg = finality_grandpa::Message::Precommit(precommit.clone()); - let encoded = sp_finality_grandpa::localized_payload(42, current_set_id, &msg); + let encoded = sp_consensus_grandpa::localized_payload(42, current_set_id, &msg); let signature = keyring.sign(&encoded[..]).into(); let precommit = finality_grandpa::SignedPrecommit { diff --git a/client/finality-grandpa/Cargo.toml b/client/finality-grandpa/Cargo.toml deleted file mode 100644 index 8a4e0449f2d1c..0000000000000 --- a/client/finality-grandpa/Cargo.toml +++ /dev/null @@ -1,60 +0,0 @@ -[package] -name = "sc-finality-grandpa" -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 = "Integration of the GRANDPA finality gadget into substrate." -documentation = "https://docs.rs/sc-finality-grandpa" -readme = "README.md" - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] - -[dependencies] -ahash = "0.8.2" -array-bytes = "4.1" -async-trait = "0.1.57" -dyn-clone = "1.0" -finality-grandpa = { version = "0.16.1", features = ["derive-codec"] } -futures = "0.3.21" -futures-timer = "3.0.1" -log = "0.4.17" -parity-scale-codec = { version = "3.2.2", features = ["derive"] } -parking_lot = "0.12.1" -rand = "0.8.5" -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" } -sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" } -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-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" } -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 = "7.0.0", path = "../../primitives/core" } -sp-finality-grandpa = { version = "4.0.0-dev", path = "../../primitives/finality-grandpa" } -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" -finality-grandpa = { version = "0.16.1", features = ["derive-codec", "test-helpers"] } -serde = "1.0.136" -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" } -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 deleted file mode 100644 index e20ff174d41c5..0000000000000 --- a/client/finality-grandpa/rpc/Cargo.toml +++ /dev/null @@ -1,36 +0,0 @@ -[package] -name = "sc-finality-grandpa-rpc" -version = "0.10.0-dev" -authors = ["Parity Technologies "] -description = "RPC extensions for the GRANDPA finality gadget" -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] -finality-grandpa = { version = "0.16.1", features = ["derive-codec"] } -futures = "0.3.16" -jsonrpsee = { version = "0.16.2", features = ["client-core", "server", "macros"] } -log = "0.4.8" -parity-scale-codec = { version = "3.2.2", features = ["derive"] } -serde = { version = "1.0.105", features = ["derive"] } -thiserror = "1.0" -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 = "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 = "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.22.0", features = ["macros"] } diff --git a/client/network/README.md b/client/network/README.md index c361bc9249f71..d396747241ab1 100644 --- a/client/network/README.md +++ b/client/network/README.md @@ -190,7 +190,7 @@ The API of `sc-network` allows one to register user-defined notification protoco `sc-network` automatically tries to open a substream towards each node for which the legacy Substream substream is open. The handshake is then performed automatically. -For example, the `sc-finality-grandpa` crate registers the `/paritytech/grandpa/1` +For example, the `sc-consensus-grandpa` crate registers the `/paritytech/grandpa/1` notifications protocol. At the moment, for backwards-compatibility, notification protocols are tied to the legacy diff --git a/client/network/common/Cargo.toml b/client/network/common/Cargo.toml index 2aaada021f0fa..06ff00ef77dbc 100644 --- a/client/network/common/Cargo.toml +++ b/client/network/common/Cargo.toml @@ -32,7 +32,7 @@ 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-consensus-grandpa = { version = "4.0.0-dev", path = "../../../primitives/consensus/grandpa" } 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/common/src/sync/warp.rs b/client/network/common/src/sync/warp.rs index a906091ff2a7b..5f2cacd2eeae5 100644 --- a/client/network/common/src/sync/warp.rs +++ b/client/network/common/src/sync/warp.rs @@ -16,7 +16,7 @@ use codec::{Decode, Encode}; use futures::channel::oneshot; -pub use sp_finality_grandpa::{AuthorityList, SetId}; +pub use sp_consensus_grandpa::{AuthorityList, SetId}; use sp_runtime::traits::{Block as BlockT, NumberFor}; use std::{fmt, sync::Arc}; diff --git a/client/network/src/lib.rs b/client/network/src/lib.rs index 8ecb3e54902af..8714d66f1332d 100644 --- a/client/network/src/lib.rs +++ b/client/network/src/lib.rs @@ -212,7 +212,7 @@ //! `sc-network` automatically tries to open a substream towards each node for which the legacy //! Substream substream is open. The handshake is then performed automatically. //! -//! For example, the `sc-finality-grandpa` crate registers the `/paritytech/grandpa/1` +//! For example, the `sc-consensus-grandpa` crate registers the `/paritytech/grandpa/1` //! notifications protocol. //! //! At the moment, for backwards-compatibility, notification protocols are tied to the legacy diff --git a/client/network/sync/Cargo.toml b/client/network/sync/Cargo.toml index 532e873836204..bd51776d6f898 100644 --- a/client/network/sync/Cargo.toml +++ b/client/network/sync/Cargo.toml @@ -38,7 +38,7 @@ 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 = "7.0.0", path = "../../../primitives/core" } -sp-finality-grandpa = { version = "4.0.0-dev", path = "../../../primitives/finality-grandpa" } +sp-consensus-grandpa = { version = "4.0.0-dev", path = "../../../primitives/consensus/grandpa" } sp-runtime = { version = "7.0.0", path = "../../../primitives/runtime" } [dev-dependencies] diff --git a/client/network/sync/src/warp.rs b/client/network/sync/src/warp.rs index 21af507877449..912ad78dfdd08 100644 --- a/client/network/sync/src/warp.rs +++ b/client/network/sync/src/warp.rs @@ -34,7 +34,7 @@ use sc_network_common::sync::{ }, }; use sp_blockchain::HeaderBackend; -use sp_finality_grandpa::{AuthorityList, SetId}; +use sp_consensus_grandpa::{AuthorityList, SetId}; use sp_runtime::traits::{Block as BlockT, Header, NumberFor, Zero}; use std::{sync::Arc, task::Poll}; diff --git a/client/sync-state-rpc/Cargo.toml b/client/sync-state-rpc/Cargo.toml index 3a964521c505b..5447c809c0795 100644 --- a/client/sync-state-rpc/Cargo.toml +++ b/client/sync-state-rpc/Cargo.toml @@ -21,6 +21,6 @@ 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" } +sc-consensus-grandpa = { version = "0.10.0-dev", path = "../consensus/grandpa" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-runtime = { version = "7.0.0", path = "../../primitives/runtime" } diff --git a/client/sync-state-rpc/src/lib.rs b/client/sync-state-rpc/src/lib.rs index 94bf53c5ab456..78d5cafa31e26 100644 --- a/client/sync-state-rpc/src/lib.rs +++ b/client/sync-state-rpc/src/lib.rs @@ -52,7 +52,7 @@ use sp_runtime::traits::{Block as BlockT, NumberFor}; use std::sync::Arc; type SharedAuthoritySet = - sc_finality_grandpa::SharedAuthoritySet<::Hash, NumberFor>; + sc_consensus_grandpa::SharedAuthoritySet<::Hash, NumberFor>; type SharedEpochChanges = sc_consensus_epochs::SharedEpochChanges; @@ -117,7 +117,7 @@ pub struct LightSyncState { /// The authority set for grandpa. #[serde(serialize_with = "serialize_encoded")] pub grandpa_authority_set: - sc_finality_grandpa::AuthoritySet<::Hash, NumberFor>, + sc_consensus_grandpa::AuthoritySet<::Hash, NumberFor>, } /// An api for sync state RPC calls. diff --git a/docs/CODEOWNERS b/docs/CODEOWNERS index 133ba7b094d43..4377e7ff049dc 100644 --- a/docs/CODEOWNERS +++ b/docs/CODEOWNERS @@ -41,7 +41,7 @@ # GRANDPA, BABE, consensus stuff /frame/babe/ @andresilva /frame/grandpa/ @andresilva -/client/finality-grandpa/ @andresilva +/client/consensus/grandpa/ @andresilva /client/consensus/babe/ @andresilva /client/consensus/slots/ @andresilva /client/consensus/pow/ @sorpaas diff --git a/frame/grandpa/Cargo.toml b/frame/grandpa/Cargo.toml index fa63b8427523a..3ffb516423906 100644 --- a/frame/grandpa/Cargo.toml +++ b/frame/grandpa/Cargo.toml @@ -23,7 +23,7 @@ pallet-authorship = { version = "4.0.0-dev", default-features = false, path = ". pallet-session = { version = "4.0.0-dev", default-features = false, path = "../session" } 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-consensus-grandpa = { version = "4.0.0-dev", default-features = false, path = "../../primitives/consensus/grandpa" } 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" } @@ -54,7 +54,7 @@ std = [ "scale-info/std", "sp-application-crypto/std", "sp-core/std", - "sp-finality-grandpa/std", + "sp-consensus-grandpa/std", "sp-io/std", "sp-runtime/std", "sp-session/std", diff --git a/frame/grandpa/src/benchmarking.rs b/frame/grandpa/src/benchmarking.rs index 7a3849766d5ec..7a87f0c4b0788 100644 --- a/frame/grandpa/src/benchmarking.rs +++ b/frame/grandpa/src/benchmarking.rs @@ -50,14 +50,14 @@ benchmarks! { 251, 129, 29, 45, 32, 29, 6 ]; - let equivocation_proof1: sp_finality_grandpa::EquivocationProof = + let equivocation_proof1: sp_consensus_grandpa::EquivocationProof = Decode::decode(&mut &EQUIVOCATION_PROOF_BLOB[..]).unwrap(); let equivocation_proof2 = equivocation_proof1.clone(); }: { - sp_finality_grandpa::check_equivocation_proof(equivocation_proof1); + sp_consensus_grandpa::check_equivocation_proof(equivocation_proof1); } verify { - assert!(sp_finality_grandpa::check_equivocation_proof(equivocation_proof2)); + assert!(sp_consensus_grandpa::check_equivocation_proof(equivocation_proof2)); } note_stalled { diff --git a/frame/grandpa/src/equivocation.rs b/frame/grandpa/src/equivocation.rs index 8de8d7ae68380..7d8eb6774097c 100644 --- a/frame/grandpa/src/equivocation.rs +++ b/frame/grandpa/src/equivocation.rs @@ -39,7 +39,7 @@ use sp_std::prelude::*; use codec::{self as codec, Decode, Encode}; use frame_support::traits::{Get, KeyOwnerProofSystem}; -use sp_finality_grandpa::{EquivocationProof, RoundNumber, SetId}; +use sp_consensus_grandpa::{EquivocationProof, RoundNumber, SetId}; use sp_runtime::{ transaction_validity::{ InvalidTransaction, TransactionPriority, TransactionSource, TransactionValidity, @@ -251,7 +251,7 @@ fn is_known_offence( key_owner_proof: &T::KeyOwnerProof, ) -> Result<(), TransactionValidityError> { // check the membership proof to extract the offender's id - let key = (sp_finality_grandpa::KEY_TYPE, equivocation_proof.offender().clone()); + let key = (sp_consensus_grandpa::KEY_TYPE, equivocation_proof.offender().clone()); let offender = T::KeyOwnerProofSystem::check_proof(key, key_owner_proof.clone()) .ok_or(InvalidTransaction::BadProof)?; diff --git a/frame/grandpa/src/lib.rs b/frame/grandpa/src/lib.rs index 86751e23a31d3..85d116ee7d7e7 100644 --- a/frame/grandpa/src/lib.rs +++ b/frame/grandpa/src/lib.rs @@ -29,7 +29,7 @@ #![cfg_attr(not(feature = "std"), no_std)] // re-export since this is necessary for `impl_apis` in runtime. -pub use sp_finality_grandpa as fg_primitives; +pub use sp_consensus_grandpa as fg_primitives; use sp_std::prelude::*; @@ -555,7 +555,7 @@ impl Pallet { // validate equivocation proof (check votes are different and // signatures are valid). - if !sp_finality_grandpa::check_equivocation_proof(equivocation_proof) { + if !sp_consensus_grandpa::check_equivocation_proof(equivocation_proof) { return Err(Error::::InvalidEquivocationProof.into()) } diff --git a/frame/grandpa/src/mock.rs b/frame/grandpa/src/mock.rs index 0948be0080889..a33fbb22d6ff8 100644 --- a/frame/grandpa/src/mock.rs +++ b/frame/grandpa/src/mock.rs @@ -30,8 +30,8 @@ use frame_support::{ }, }; use pallet_session::historical as pallet_session_historical; +use sp_consensus_grandpa::{RoundNumber, SetId, GRANDPA_ENGINE_ID}; use sp_core::{crypto::KeyTypeId, H256}; -use sp_finality_grandpa::{RoundNumber, SetId, GRANDPA_ENGINE_ID}; use sp_keyring::Ed25519Keyring; use sp_runtime::{ curve::PiecewiseLinear, @@ -354,12 +354,12 @@ pub fn generate_equivocation_proof( set_id: SetId, vote1: (RoundNumber, H256, u64, &Ed25519Keyring), vote2: (RoundNumber, H256, u64, &Ed25519Keyring), -) -> sp_finality_grandpa::EquivocationProof { +) -> sp_consensus_grandpa::EquivocationProof { let signed_prevote = |round, hash, number, keyring: &Ed25519Keyring| { let prevote = finality_grandpa::Prevote { target_hash: hash, target_number: number }; let prevote_msg = finality_grandpa::Message::Prevote(prevote.clone()); - let payload = sp_finality_grandpa::localized_payload(round, set_id, &prevote_msg); + let payload = sp_consensus_grandpa::localized_payload(round, set_id, &prevote_msg); let signed = keyring.sign(&payload).into(); (prevote, signed) }; @@ -367,9 +367,9 @@ pub fn generate_equivocation_proof( let (prevote1, signed1) = signed_prevote(vote1.0, vote1.1, vote1.2, vote1.3); let (prevote2, signed2) = signed_prevote(vote2.0, vote2.1, vote2.2, vote2.3); - sp_finality_grandpa::EquivocationProof::new( + sp_consensus_grandpa::EquivocationProof::new( set_id, - sp_finality_grandpa::Equivocation::Prevote(finality_grandpa::Equivocation { + sp_consensus_grandpa::Equivocation::Prevote(finality_grandpa::Equivocation { round_number: vote1.0, identity: vote1.3.public().into(), first: (prevote1, signed1), diff --git a/frame/grandpa/src/tests.rs b/frame/grandpa/src/tests.rs index 4fd5727d54ab2..0bf3c8ddf63dc 100644 --- a/frame/grandpa/src/tests.rs +++ b/frame/grandpa/src/tests.rs @@ -355,7 +355,7 @@ fn report_equivocation_current_set_works() { // create the key ownership proof let key_owner_proof = - Historical::prove((sp_finality_grandpa::KEY_TYPE, &equivocation_key)).unwrap(); + Historical::prove((sp_consensus_grandpa::KEY_TYPE, &equivocation_key)).unwrap(); // report the equivocation and the tx should be dispatched successfully assert_ok!(Grandpa::report_equivocation_unsigned( @@ -408,7 +408,7 @@ fn report_equivocation_old_set_works() { // create the key ownership proof in the "old" set let key_owner_proof = - Historical::prove((sp_finality_grandpa::KEY_TYPE, &equivocation_key)).unwrap(); + Historical::prove((sp_consensus_grandpa::KEY_TYPE, &equivocation_key)).unwrap(); start_era(2); @@ -486,7 +486,7 @@ fn report_equivocation_invalid_set_id() { let equivocation_keyring = extract_keyring(equivocation_key); let key_owner_proof = - Historical::prove((sp_finality_grandpa::KEY_TYPE, &equivocation_key)).unwrap(); + Historical::prove((sp_consensus_grandpa::KEY_TYPE, &equivocation_key)).unwrap(); let set_id = Grandpa::current_set_id(); @@ -524,7 +524,7 @@ fn report_equivocation_invalid_session() { // generate a key ownership proof at set id = 1 let key_owner_proof = - Historical::prove((sp_finality_grandpa::KEY_TYPE, &equivocation_key)).unwrap(); + Historical::prove((sp_consensus_grandpa::KEY_TYPE, &equivocation_key)).unwrap(); start_era(2); @@ -563,7 +563,7 @@ fn report_equivocation_invalid_key_owner_proof() { // generate a key ownership proof for the authority at index 1 let invalid_key_owner_proof = - Historical::prove((sp_finality_grandpa::KEY_TYPE, &invalid_owner_key)).unwrap(); + Historical::prove((sp_consensus_grandpa::KEY_TYPE, &invalid_owner_key)).unwrap(); let equivocation_authority_index = 0; let equivocation_key = &authorities[equivocation_authority_index].0; @@ -610,7 +610,7 @@ fn report_equivocation_invalid_equivocation_proof() { // generate a key ownership proof at set id = 1 let key_owner_proof = - Historical::prove((sp_finality_grandpa::KEY_TYPE, &equivocation_key)).unwrap(); + Historical::prove((sp_consensus_grandpa::KEY_TYPE, &equivocation_key)).unwrap(); let set_id = Grandpa::current_set_id(); @@ -685,7 +685,7 @@ fn report_equivocation_validate_unsigned_prevents_duplicates() { ); let key_owner_proof = - Historical::prove((sp_finality_grandpa::KEY_TYPE, &equivocation_key)).unwrap(); + Historical::prove((sp_consensus_grandpa::KEY_TYPE, &equivocation_key)).unwrap(); let call = Call::report_equivocation_unsigned { equivocation_proof: Box::new(equivocation_proof.clone()), @@ -873,7 +873,7 @@ fn valid_equivocation_reports_dont_pay_fees() { // create the key ownership proof. let key_owner_proof = - Historical::prove((sp_finality_grandpa::KEY_TYPE, &equivocation_key)).unwrap(); + Historical::prove((sp_consensus_grandpa::KEY_TYPE, &equivocation_key)).unwrap(); // check the dispatch info for the call. let info = Call::::report_equivocation_unsigned { diff --git a/primitives/finality-grandpa/Cargo.toml b/primitives/consensus/grandpa/Cargo.toml similarity index 86% rename from primitives/finality-grandpa/Cargo.toml rename to primitives/consensus/grandpa/Cargo.toml index 39bb6713a2394..7146873e0a751 100644 --- a/primitives/finality-grandpa/Cargo.toml +++ b/primitives/consensus/grandpa/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "sp-finality-grandpa" +name = "sp-consensus-grandpa" version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2021" @@ -7,7 +7,7 @@ license = "Apache-2.0" 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" +documentation = "https://docs.rs/sp-consensus-grandpa" readme = "README.md" [package.metadata.docs.rs] @@ -19,12 +19,12 @@ grandpa = { package = "finality-grandpa", version = "0.16.1", default-features = 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 } -sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } -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" } +sp-api = { version = "4.0.0-dev", default-features = false, path = "../../api" } +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/finality-grandpa/README.md b/primitives/consensus/grandpa/README.md similarity index 100% rename from primitives/finality-grandpa/README.md rename to primitives/consensus/grandpa/README.md diff --git a/primitives/finality-grandpa/src/lib.rs b/primitives/consensus/grandpa/src/lib.rs similarity index 100% rename from primitives/finality-grandpa/src/lib.rs rename to primitives/consensus/grandpa/src/lib.rs diff --git a/test-utils/runtime/Cargo.toml b/test-utils/runtime/Cargo.toml index 33dbfce680d75..f3222dc15c280 100644 --- a/test-utils/runtime/Cargo.toml +++ b/test-utils/runtime/Cargo.toml @@ -38,7 +38,7 @@ pallet-babe = { version = "4.0.0-dev", default-features = false, path = "../../f 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-consensus-grandpa = { version = "4.0.0-dev", default-features = false, path = "../../primitives/consensus/grandpa" } 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.25.1", default-features = false } @@ -97,7 +97,7 @@ std = [ "frame-system/std", "pallet-timestamp/std", "sc-service", - "sp-finality-grandpa/std", + "sp-consensus-grandpa/std", "sp-trie/std", "sp-transaction-pool/std", "trie-db/std", diff --git a/test-utils/runtime/src/lib.rs b/test-utils/runtime/src/lib.rs index 720b0a1e06f07..9e8a4e119b293 100644 --- a/test-utils/runtime/src/lib.rs +++ b/test-utils/runtime/src/lib.rs @@ -945,29 +945,29 @@ cfg_if! { } } - impl sp_finality_grandpa::GrandpaApi for Runtime { - fn grandpa_authorities() -> sp_finality_grandpa::AuthorityList { + impl sp_consensus_grandpa::GrandpaApi for Runtime { + fn grandpa_authorities() -> sp_consensus_grandpa::AuthorityList { Vec::new() } - fn current_set_id() -> sp_finality_grandpa::SetId { + fn current_set_id() -> sp_consensus_grandpa::SetId { 0 } fn submit_report_equivocation_unsigned_extrinsic( - _equivocation_proof: sp_finality_grandpa::EquivocationProof< + _equivocation_proof: sp_consensus_grandpa::EquivocationProof< ::Hash, NumberFor, >, - _key_owner_proof: sp_finality_grandpa::OpaqueKeyOwnershipProof, + _key_owner_proof: sp_consensus_grandpa::OpaqueKeyOwnershipProof, ) -> Option<()> { None } fn generate_key_ownership_proof( - _set_id: sp_finality_grandpa::SetId, - _authority_id: sp_finality_grandpa::AuthorityId, - ) -> Option { + _set_id: sp_consensus_grandpa::SetId, + _authority_id: sp_consensus_grandpa::AuthorityId, + ) -> Option { None } } From 1cbb2ef4f2bc7486a60a5ece409525ae46bce3b6 Mon Sep 17 00:00:00 2001 From: Muharem Ismailov Date: Mon, 27 Feb 2023 17:41:23 +0100 Subject: [PATCH 442/715] constructor for MemberRecord (#13473) --- frame/ranked-collective/src/lib.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/frame/ranked-collective/src/lib.rs b/frame/ranked-collective/src/lib.rs index 30bb280a1a4f8..66af9bf6e0a5e 100644 --- a/frame/ranked-collective/src/lib.rs +++ b/frame/ranked-collective/src/lib.rs @@ -170,6 +170,13 @@ pub struct MemberRecord { rank: Rank, } +impl MemberRecord { + // Constructs a new instance of [`MemberRecord`]. + pub fn new(rank: Rank) -> Self { + Self { rank } + } +} + /// Record needed for every vote. #[derive(PartialEq, Eq, Clone, Copy, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub enum VoteRecord { From 295712018a10703362967376bfc7013d63fe37f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Mon, 27 Feb 2023 18:49:16 +0100 Subject: [PATCH 443/715] `pallet-treasury`: Ensure we respect `max_amount` for spend across batch calls (#13468) * `pallet-treasury`: Ensure we respect `max_amount` for spend across batch calls When calling `spend` the origin defines the `max_amount` of tokens it is allowed to spend. The problem is that someone can send a `batch(spend, spend)` to circumvent this restriction as we don't check across different calls that the `max_amount` is respected. This pull request fixes this behavior by introducing a so-called dispatch context. This dispatch context is created once per outer most `dispatch` call. For more information see the docs in this pr. The treasury then uses this dispatch context to attach information about already spent funds per `max_amount` (we assume that each origin has a different `max_amount` configured). So, a `batch(spend, spend)` is now checked to stay inside the allowed spending bounds. Fixes: https://github.com/paritytech/substrate/issues/13167 * Import `Box` for wasm * FMT --- Cargo.lock | 2 + frame/support/Cargo.toml | 2 + .../procedural/src/pallet/expand/call.rs | 32 +-- frame/support/src/dispatch_context.rs | 232 ++++++++++++++++++ frame/support/src/lib.rs | 1 + frame/support/test/tests/pallet.rs | 32 ++- frame/treasury/Cargo.toml | 1 + frame/treasury/src/lib.rs | 35 ++- frame/treasury/src/tests.rs | 40 ++- 9 files changed, 353 insertions(+), 24 deletions(-) create mode 100644 frame/support/src/dispatch_context.rs diff --git a/Cargo.lock b/Cargo.lock index 92db97a36c943..df6843364331a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2383,6 +2383,7 @@ version = "4.0.0-dev" dependencies = [ "assert_matches", "bitflags", + "environmental", "frame-metadata", "frame-support-procedural", "frame-system", @@ -6705,6 +6706,7 @@ dependencies = [ "frame-system", "impl-trait-for-tuples", "pallet-balances", + "pallet-utility", "parity-scale-codec", "scale-info", "serde", diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index 4f62ae42ef78f..008d4b3f26015 100644 --- a/frame/support/Cargo.toml +++ b/frame/support/Cargo.toml @@ -38,6 +38,7 @@ 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.11.5", default-features = false, features = ["ecdsa"] } +environmental = { version = "1.1.4", default-features = false } [dev-dependencies] serde_json = "1.0.85" @@ -67,6 +68,7 @@ std = [ "sp-weights/std", "frame-support-procedural/std", "log/std", + "environmental/std", ] runtime-benchmarks = [] try-runtime = [] diff --git a/frame/support/procedural/src/pallet/expand/call.rs b/frame/support/procedural/src/pallet/expand/call.rs index 72367dc3957d9..3db454eb6211b 100644 --- a/frame/support/procedural/src/pallet/expand/call.rs +++ b/frame/support/procedural/src/pallet/expand/call.rs @@ -333,22 +333,24 @@ pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream { self, origin: Self::RuntimeOrigin ) -> #frame_support::dispatch::DispatchResultWithPostInfo { - match self { - #( - Self::#fn_name { #( #args_name_pattern, )* } => { - #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) + #frame_support::dispatch_context::run_in_context(|| { + match self { + #( + Self::#fn_name { #( #args_name_pattern, )* } => { + #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) + }, + )* + Self::__Ignore(_, _) => { + let _ = origin; // Use origin for empty Call enum + unreachable!("__PhantomItem cannot be used."); }, - )* - Self::__Ignore(_, _) => { - let _ = origin; // Use origin for empty Call enum - unreachable!("__PhantomItem cannot be used."); - }, - } + } + }) } } diff --git a/frame/support/src/dispatch_context.rs b/frame/support/src/dispatch_context.rs new file mode 100644 index 0000000000000..31278ea9f8194 --- /dev/null +++ b/frame/support/src/dispatch_context.rs @@ -0,0 +1,232 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT 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 functions to interact with the dispatch context. +//! +//! A Dispatch context is created by calling [`run_in_context`] and then the given closure will be +//! executed in this dispatch context. Everyting run in this `closure` will have access to the same +//! dispatch context. This also applies to nested calls of [`run_in_context`]. The dispatch context +//! can be used to store and retrieve information locally in this context. The dispatch context can +//! be accessed by using [`with_context`]. This function will execute the given closure and give it +//! access to the value stored in the dispatch context. +//! +//! # FRAME integration +//! +//! The FRAME macros implement [`UnfilteredDispatchable`](crate::traits::UnfilteredDispatchable) for +//! each pallet `Call` enum. Part of this implementation is the call to [`run_in_context`], so that +//! each call to +//! [`UnfilteredDispatchable::dispatch_bypass_filter`](crate::traits::UnfilteredDispatchable::dispatch_bypass_filter) +//! or [`Dispatchable::dispatch`](crate::dispatch::Dispatchable::dispatch) will run in a dispatch +//! context. +//! +//! # Example +//! +//! ``` +//! use frame_support::dispatch_context::{with_context, run_in_context}; +//! +//! // Not executed in a dispatch context, so it should return `None`. +//! assert!(with_context::<(), _>(|_| println!("Hello")).is_none()); +//! +//! // Run it in a dispatch context and `with_context` returns `Some(_)`. +//! run_in_context(|| { +//! assert!(with_context::<(), _>(|_| println!("Hello")).is_some()); +//! }); +//! +//! #[derive(Default)] +//! struct CustomContext(i32); +//! +//! run_in_context(|| { +//! with_context::(|v| { +//! // Intitialize the value to the default value. +//! assert_eq!(0, v.or_default().0); +//! v.or_default().0 = 10; +//! }); +//! +//! with_context::(|v| { +//! // We are still in the same context and can still access the set value. +//! assert_eq!(10, v.or_default().0); +//! }); +//! +//! run_in_context(|| { +//! with_context::(|v| { +//! // A nested call of `run_in_context` stays in the same dispatch context +//! assert_eq!(10, v.or_default().0); +//! }) +//! }) +//! }); +//! +//! run_in_context(|| { +//! with_context::(|v| { +//! // We left the other context and created a new one, so we should be back +//! // to our default value. +//! assert_eq!(0, v.or_default().0); +//! }); +//! }); +//! ``` +//! +//! In your pallet you will only have to use [`with_context`], because as described above +//! [`run_in_context`] will be handled by FRAME for you. + +use sp_std::{ + any::{Any, TypeId}, + boxed::Box, + collections::btree_map::{BTreeMap, Entry}, +}; + +environmental::environmental!(DISPATCH_CONTEXT: BTreeMap>); + +/// Abstraction over some optional value `T` that is stored in the dispatch context. +pub struct Value<'a, T> { + value: Option<&'a mut T>, + new_value: Option, +} + +impl Value<'_, T> { + /// Get the value as reference. + pub fn get(&self) -> Option<&T> { + self.new_value.as_ref().or_else(|| self.value.as_ref().map(|v| *v as &T)) + } + + /// Get the value as mutable reference. + pub fn get_mut(&mut self) -> Option<&mut T> { + self.new_value.as_mut().or_else(|| self.value.as_mut().map(|v| *v as &mut T)) + } + + /// Set to the given value. + /// + /// [`Self::get`] and [`Self::get_mut`] will return `new_value` afterwards. + pub fn set(&mut self, new_value: T) { + self.value = None; + self.new_value = Some(new_value); + } + + /// Returns a mutable reference to the value. + /// + /// If the internal value isn't initialized, this will set it to [`Default::default()`] before + /// returning the mutable reference. + pub fn or_default(&mut self) -> &mut T + where + T: Default, + { + if let Some(v) = &mut self.value { + return v + } + + self.new_value.get_or_insert_with(|| Default::default()) + } + + /// Clear the internal value. + /// + /// [`Self::get`] and [`Self::get_mut`] will return `None` afterwards. + pub fn clear(&mut self) { + self.new_value = None; + self.value = None; + } +} + +/// Runs the given `callback` in the dispatch context and gives access to some user defined value. +/// +/// Passes the a mutable reference of [`Value`] to the callback. The value will be of type `T` and +/// is identified using the [`TypeId`] of `T`. This means that `T` should be some unique type to +/// make the value unique. If no value is set yet [`Value::get()`] and [`Value::get_mut()`] will +/// return `None`. It is totally valid to have some `T` that is shared between different callers to +/// have access to the same value. +/// +/// Returns `None` if the current context is not a dispatch context. To create a context it is +/// required to call [`run_in_context`] with the closure to execute in this context. So, for example +/// in tests it could be that there isn't any dispatch context or when calling a dispatchable like a +/// normal Rust function from some FRAME hook. +pub fn with_context(callback: impl FnOnce(&mut Value) -> R) -> Option { + DISPATCH_CONTEXT::with(|c| match c.entry(TypeId::of::()) { + Entry::Occupied(mut o) => { + let value = o.get_mut().downcast_mut::(); + + if value.is_none() { + log::error!( + "Failed to downcast value for type {} in dispatch context!", + sp_std::any::type_name::(), + ); + } + + let mut value = Value { value, new_value: None }; + let res = callback(&mut value); + + if value.value.is_none() && value.new_value.is_none() { + o.remove(); + } else if let Some(new_value) = value.new_value { + o.insert(Box::new(new_value) as Box<_>); + } + + res + }, + Entry::Vacant(v) => { + let mut value = Value { value: None, new_value: None }; + + let res = callback(&mut value); + + if let Some(new_value) = value.new_value { + v.insert(Box::new(new_value) as Box<_>); + } + + res + }, + }) +} + +/// Run the given closure `run` in a dispatch context. +/// +/// Nested calls to this function will execute `run` in the same dispatch context as the initial +/// call to this function. In other words, all nested calls of this function will be done in the +/// same dispatch context. +pub fn run_in_context(run: impl FnOnce() -> R) -> R { + DISPATCH_CONTEXT::using_once(&mut Default::default(), run) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn dispatch_context_works() { + // No context, so we don't execute + assert!(with_context::<(), _>(|_| ()).is_none()); + + let ret = run_in_context(|| with_context::<(), _>(|_| 1).unwrap()); + assert_eq!(1, ret); + + #[derive(Default)] + struct Context(i32); + + let res = run_in_context(|| { + with_context::(|v| { + assert_eq!(0, v.or_default().0); + + v.or_default().0 = 100; + }); + + run_in_context(|| { + run_in_context(|| { + run_in_context(|| with_context::(|v| v.or_default().0).unwrap()) + }) + }) + }); + + // Ensure that the initial value set in the context is also accessible after nesting the + // `run_in_context` calls. + assert_eq!(100, res); + } +} diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index c11c902d64dd2..4e9bc32b0043b 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -78,6 +78,7 @@ pub mod inherent; #[macro_use] pub mod error; pub mod crypto; +pub mod dispatch_context; pub mod instances; pub mod migrations; pub mod traits; diff --git a/frame/support/test/tests/pallet.rs b/frame/support/test/tests/pallet.rs index 7dd9aa0ddaf66..8ce85fa506348 100644 --- a/frame/support/test/tests/pallet.rs +++ b/frame/support/test/tests/pallet.rs @@ -16,9 +16,12 @@ // limitations under the License. use frame_support::{ + assert_ok, dispatch::{ - DispatchClass, DispatchInfo, GetDispatchInfo, Parameter, Pays, UnfilteredDispatchable, + DispatchClass, DispatchInfo, Dispatchable, GetDispatchInfo, Parameter, Pays, + UnfilteredDispatchable, }, + dispatch_context::with_context, pallet_prelude::{StorageInfoTrait, ValueQuery}, storage::unhashed, traits::{ @@ -102,6 +105,7 @@ pub mod pallet { use super::*; use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; + use sp_runtime::DispatchResult; type BalanceOf = ::Balance; @@ -227,6 +231,12 @@ pub mod pallet { pub fn foo_no_post_info(_origin: OriginFor) -> DispatchResult { Ok(()) } + + #[pallet::call_index(3)] + #[pallet::weight(1)] + pub fn check_for_dispatch_context(_origin: OriginFor) -> DispatchResult { + with_context::<(), _>(|_| ()).ok_or_else(|| DispatchError::Unavailable) + } } #[pallet::error] @@ -713,7 +723,7 @@ fn call_expand() { assert_eq!(call_foo.get_call_name(), "foo"); assert_eq!( pallet::Call::::get_call_names(), - &["foo", "foo_storage_layer", "foo_no_post_info"], + &["foo", "foo_storage_layer", "foo_no_post_info", "check_for_dispatch_context"], ); } @@ -1933,3 +1943,21 @@ fn test_storage_alias() { ); }) } + +#[test] +fn test_dispatch_context() { + TestExternalities::default().execute_with(|| { + // By default there is no context + assert!(with_context::<(), _>(|_| ()).is_none()); + + // When not using `dispatch`, there should be no dispatch context + assert_eq!( + DispatchError::Unavailable, + Example::check_for_dispatch_context(RuntimeOrigin::root()).unwrap_err(), + ); + + // When using `dispatch`, there should be a dispatch context + assert_ok!(RuntimeCall::from(pallet::Call::::check_for_dispatch_context {}) + .dispatch(RuntimeOrigin::root())); + }); +} diff --git a/frame/treasury/Cargo.toml b/frame/treasury/Cargo.toml index 1fd1d7b3d4620..23fcb7944bfb7 100644 --- a/frame/treasury/Cargo.toml +++ b/frame/treasury/Cargo.toml @@ -30,6 +30,7 @@ sp-std = { version = "5.0.0", default-features = false, path = "../../primitives [dev-dependencies] sp-core = { version = "7.0.0", path = "../../primitives/core" } sp-io = { version = "7.0.0", path = "../../primitives/io" } +pallet-utility = { version = "4.0.0-dev", path = "../utility" } [features] default = ["std"] diff --git a/frame/treasury/src/lib.rs b/frame/treasury/src/lib.rs index 2e22063eb3ea3..04e989373c8cd 100644 --- a/frame/treasury/src/lib.rs +++ b/frame/treasury/src/lib.rs @@ -67,10 +67,10 @@ use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; use sp_runtime::{ - traits::{AccountIdConversion, Saturating, StaticLookup, Zero}, + traits::{AccountIdConversion, CheckedAdd, Saturating, StaticLookup, Zero}, Permill, RuntimeDebug, }; -use sp_std::prelude::*; +use sp_std::{collections::btree_map::BTreeMap, prelude::*}; use frame_support::{ print, @@ -136,7 +136,7 @@ pub struct Proposal { #[frame_support::pallet] pub mod pallet { use super::*; - use frame_support::pallet_prelude::*; + use frame_support::{dispatch_context::with_context, pallet_prelude::*}; use frame_system::pallet_prelude::*; #[pallet::pallet] @@ -339,6 +339,11 @@ pub mod pallet { } } + #[derive(Default)] + struct SpendContext { + spend_in_context: BTreeMap, + } + #[pallet::call] impl, I: 'static> Pallet { /// Put forward a suggestion for spending. A deposit proportional to the value @@ -433,9 +438,29 @@ pub mod pallet { beneficiary: AccountIdLookupOf, ) -> DispatchResult { let max_amount = T::SpendOrigin::ensure_origin(origin)?; - let beneficiary = T::Lookup::lookup(beneficiary)?; - ensure!(amount <= max_amount, Error::::InsufficientPermission); + + with_context::>, _>(|v| { + let context = v.or_default(); + + // We group based on `max_amount`, to dinstinguish between different kind of + // origins. (assumes that all origins have different `max_amount`) + // + // Worst case is that we reject some "valid" request. + let spend = context.spend_in_context.entry(max_amount).or_default(); + + // Ensure that we don't overflow nor use more than `max_amount` + if spend.checked_add(&amount).map(|s| s > max_amount).unwrap_or(true) { + Err(Error::::InsufficientPermission) + } else { + *spend = spend.saturating_add(amount); + + Ok(()) + } + }) + .unwrap_or(Ok(()))?; + + let beneficiary = T::Lookup::lookup(beneficiary)?; let proposal_index = Self::proposal_count(); Approvals::::try_append(proposal_index) .map_err(|_| Error::::TooManyApprovals)?; diff --git a/frame/treasury/src/tests.rs b/frame/treasury/src/tests.rs index c9305dfd15037..24d2d01f92f8a 100644 --- a/frame/treasury/src/tests.rs +++ b/frame/treasury/src/tests.rs @@ -22,11 +22,11 @@ use sp_core::H256; use sp_runtime::{ testing::Header, - traits::{BadOrigin, BlakeTwo256, IdentityLookup}, + traits::{BadOrigin, BlakeTwo256, Dispatchable, IdentityLookup}, }; use frame_support::{ - assert_noop, assert_ok, + assert_err_ignore_postinfo, assert_noop, assert_ok, pallet_prelude::GenesisBuild, parameter_types, traits::{ConstU32, ConstU64, OnInitialize}, @@ -38,6 +38,8 @@ use crate as treasury; type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; type Block = frame_system::mocking::MockBlock; +type UtilityCall = pallet_utility::Call; +type TreasuryCall = crate::Call; frame_support::construct_runtime!( pub enum Test where @@ -48,6 +50,7 @@ frame_support::construct_runtime!( System: frame_system::{Pallet, Call, Config, Storage, Event}, Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, Treasury: treasury::{Pallet, Call, Storage, Config, Event}, + Utility: pallet_utility, } ); @@ -88,6 +91,14 @@ impl pallet_balances::Config for Test { type AccountStore = System; type WeightInfo = (); } + +impl pallet_utility::Config for Test { + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type PalletsOrigin = OriginCaller; + type WeightInfo = (); +} + parameter_types! { pub const ProposalBond: Permill = Permill::from_percent(5); pub const Burn: Permill = Permill::from_percent(50); @@ -470,3 +481,28 @@ fn remove_already_removed_approval_fails() { ); }); } + +#[test] +fn spending_in_batch_respects_max_total() { + new_test_ext().execute_with(|| { + // Respect the `max_total` for the given origin. + assert_ok!(RuntimeCall::from(UtilityCall::batch_all { + calls: vec![ + RuntimeCall::from(TreasuryCall::spend { amount: 2, beneficiary: 100 }), + RuntimeCall::from(TreasuryCall::spend { amount: 2, beneficiary: 101 }) + ] + }) + .dispatch(RuntimeOrigin::signed(10))); + + assert_err_ignore_postinfo!( + RuntimeCall::from(UtilityCall::batch_all { + calls: vec![ + RuntimeCall::from(TreasuryCall::spend { amount: 2, beneficiary: 100 }), + RuntimeCall::from(TreasuryCall::spend { amount: 4, beneficiary: 101 }) + ] + }) + .dispatch(RuntimeOrigin::signed(10)), + Error::::InsufficientPermission + ); + }) +} From 3d40b175fc7c93dbd7fec7871ec34b98d15e05a9 Mon Sep 17 00:00:00 2001 From: Arsenii Lyashenko Date: Mon, 27 Feb 2023 23:26:38 +0300 Subject: [PATCH 444/715] Add Windows support for storage monitor (#13466) * Add Windows support for storage monitor * Apply suggested changes --- Cargo.lock | 57 +++++++++++++++++++++++++------ client/storage-monitor/Cargo.toml | 2 +- client/storage-monitor/src/lib.rs | 11 ++---- 3 files changed, 51 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index df6843364331a..91ae9ab422c3e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2557,6 +2557,17 @@ dependencies = [ "winapi", ] +[[package]] +name = "fs4" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea55201cc351fdb478217c0fb641b59813da9b4efe4c414a9d8f989a657d149" +dependencies = [ + "libc", + "rustix 0.35.13", + "winapi", +] + [[package]] name = "fs_extra" version = "1.3.0" @@ -3282,6 +3293,12 @@ dependencies = [ "webrtc-util", ] +[[package]] +name = "io-lifetimes" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ce5ef949d49ee85593fc4d3f3f95ad61657076395cbbce23e2121fc5542074" + [[package]] name = "io-lifetimes" version = "1.0.5" @@ -3323,8 +3340,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22e18b0a45d56fe973d6db23972bf5bc46f988a4a2385deac9cc29572f09daef" dependencies = [ "hermit-abi 0.3.0", - "io-lifetimes", - "rustix", + "io-lifetimes 1.0.5", + "rustix 0.36.8", "windows-sys 0.45.0", ] @@ -4222,6 +4239,12 @@ dependencies = [ "nalgebra", ] +[[package]] +name = "linux-raw-sys" +version = "0.0.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4d2456c373231a208ad294c33dc5bff30051eafd954cd4caae83a712b12854d" + [[package]] name = "linux-raw-sys" version = "0.1.4" @@ -4372,7 +4395,7 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b20a59d985586e4a5aef64564ac77299f8586d8be6cf9106a5a40207e8908efb" dependencies = [ - "rustix", + "rustix 0.36.8", ] [[package]] @@ -7830,6 +7853,20 @@ dependencies = [ "nom", ] +[[package]] +name = "rustix" +version = "0.35.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "727a1a6d65f786ec22df8a81ca3121107f235970dc1705ed681d3e6e8b9cd5f9" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes 0.7.5", + "libc", + "linux-raw-sys 0.0.46", + "windows-sys 0.42.0", +] + [[package]] name = "rustix" version = "0.36.8" @@ -7838,9 +7875,9 @@ checksum = "f43abb88211988493c1abb44a70efa56ff0ce98f233b7b276146f1f3f7ba9644" dependencies = [ "bitflags", "errno", - "io-lifetimes", + "io-lifetimes 1.0.5", "libc", - "linux-raw-sys", + "linux-raw-sys 0.1.4", "windows-sys 0.45.0", ] @@ -8538,7 +8575,7 @@ dependencies = [ "once_cell", "parity-scale-codec", "paste", - "rustix", + "rustix 0.36.8", "sc-allocator", "sc-executor-common", "sc-runtime-test", @@ -9098,9 +9135,9 @@ name = "sc-storage-monitor" version = "0.1.0" dependencies = [ "clap 4.1.4", + "fs4", "futures", "log", - "nix 0.26.2", "sc-client-db", "sc-utils", "sp-core", @@ -12055,7 +12092,7 @@ dependencies = [ "directories-next", "file-per-thread-logger", "log", - "rustix", + "rustix 0.36.8", "serde", "sha2 0.10.6", "toml", @@ -12135,7 +12172,7 @@ checksum = "f76ef2e410329aaf8555ac6571d6fe07711be0646dcdf7ff3ab750a42ed2e583" dependencies = [ "object 0.29.0", "once_cell", - "rustix", + "rustix 0.36.8", ] [[package]] @@ -12166,7 +12203,7 @@ dependencies = [ "memoffset 0.6.5", "paste", "rand 0.8.5", - "rustix", + "rustix 0.36.8", "wasmtime-asm-macros", "wasmtime-environ", "wasmtime-jit-debug", diff --git a/client/storage-monitor/Cargo.toml b/client/storage-monitor/Cargo.toml index 2ba24f9e2e718..52f34a2967654 100644 --- a/client/storage-monitor/Cargo.toml +++ b/client/storage-monitor/Cargo.toml @@ -12,7 +12,7 @@ homepage = "https://substrate.io" clap = { version = "4.0.9", features = ["derive", "string"] } futures = "0.3.21" log = "0.4.17" -nix = { version = "0.26.1", features = ["fs"] } +fs4 = "0.6.3" sc-client-db = { version = "0.10.0-dev", default-features = false, path = "../db" } sc-utils = { version = "4.0.0-dev", path = "../utils" } sp-core = { version = "7.0.0", path = "../../primitives/core" } diff --git a/client/storage-monitor/src/lib.rs b/client/storage-monitor/src/lib.rs index e65b13ff65e11..277a74de08baf 100644 --- a/client/storage-monitor/src/lib.rs +++ b/client/storage-monitor/src/lib.rs @@ -17,10 +17,10 @@ // along with this program. If not, see . use clap::Args; -use nix::{errno::Errno, sys::statvfs::statvfs}; use sc_client_db::DatabaseSource; use sp_core::traits::SpawnEssentialNamed; use std::{ + io, path::{Path, PathBuf}, time::Duration, }; @@ -31,7 +31,7 @@ const LOG_TARGET: &str = "storage-monitor"; #[derive(Debug, thiserror::Error)] pub enum Error { #[error("IO Error")] - IOError(#[from] Errno), + IOError(#[from] io::Error), #[error("Out of storage space: available {0}MB, required {1}MB")] StorageOutOfSpace(u64, u64), } @@ -117,12 +117,7 @@ impl StorageMonitorService { /// Returns free space in MB, or error if statvfs failed. fn free_space(path: &Path) -> Result { - statvfs(path) - .map(|stats| { - u64::from(stats.blocks_available()).saturating_mul(u64::from(stats.block_size())) / - 1_000_000 - }) - .map_err(Error::from) + Ok(fs4::available_space(path).map(|s| s / 1_000_000)?) } /// Checks if the amount of free space for given `path` is above given `threshold`. From 0d36e75bde372b297d9a4c3deb4dd9a42b756bc2 Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Tue, 28 Feb 2023 00:10:34 +0100 Subject: [PATCH 445/715] Service::Error: Storage variant removed (#13481) --- bin/node/cli/src/service.rs | 3 ++- client/service/src/error.rs | 3 --- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs index 7b1ab2c1ebc44..268a170a82199 100644 --- a/bin/node/cli/src/service.rs +++ b/bin/node/cli/src/service.rs @@ -560,7 +560,8 @@ pub fn new_full(config: Configuration, cli: Cli) -> Result Date: Tue, 28 Feb 2023 09:52:11 +0200 Subject: [PATCH 446/715] Adjust the ratio of the `in-peers`/`out-peers` (#13477) Establish fewer outbound connections in an attempt to allow publicly available nodes to accept more full nodes. Maintain the overall number of connections node should establish. --- client/cli/src/params/network_params.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/cli/src/params/network_params.rs b/client/cli/src/params/network_params.rs index 2402b5d68f998..3aebee778d3f9 100644 --- a/client/cli/src/params/network_params.rs +++ b/client/cli/src/params/network_params.rs @@ -82,11 +82,11 @@ pub struct NetworkParams { pub allow_private_ip: bool, /// Specify the number of outgoing connections we're trying to maintain. - #[arg(long, value_name = "COUNT", default_value_t = 15)] + #[arg(long, value_name = "COUNT", default_value_t = 8)] pub out_peers: u32, /// Maximum number of inbound full nodes peers. - #[arg(long, value_name = "COUNT", default_value_t = 25)] + #[arg(long, value_name = "COUNT", default_value_t = 32)] pub in_peers: u32, /// Maximum number of inbound light nodes peers. From 2a7887e37569872919144c60afbd92cd36763f39 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Tue, 28 Feb 2023 14:47:36 +0100 Subject: [PATCH 447/715] Fix V2 PoV benchmarking (#13485) * Bump default 'additional_trie_layers' to two The default here only works for extremely small runtimes, which have no more than 16 storage prefices. This is changed to a "sane" default of 2, which is save for runtimes with up to 4096 storage prefices (eg StorageValue). Signed-off-by: Oliver Tale-Yazdi * Update tests and test weights Signed-off-by: Oliver Tale-Yazdi * Fix PoV weights Signed-off-by: Oliver Tale-Yazdi * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_balances * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_message_queue * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_glutton * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_glutton * Fix sanity check >0 would also do as a check, but let's try this. Signed-off-by: Oliver Tale-Yazdi --------- Signed-off-by: Oliver Tale-Yazdi Co-authored-by: command-bot <> --- frame/balances/src/weights.rs | 139 ++--- frame/benchmarking/pov/src/benchmarking.rs | 11 + frame/benchmarking/pov/src/weights.rs | 508 ++++++++++-------- frame/glutton/src/tests.rs | 2 +- frame/glutton/src/weights.rs | 184 +++---- frame/message-queue/src/weights.rs | 194 +++---- frame/support/procedural/src/benchmark.rs | 13 +- .../frame/benchmarking-cli/src/pallet/mod.rs | 2 +- 8 files changed, 576 insertions(+), 477 deletions(-) diff --git a/frame/balances/src/weights.rs b/frame/balances/src/weights.rs index 6bd7d7548c637..8c307ff90924d 100644 --- a/frame/balances/src/weights.rs +++ b/frame/balances/src/weights.rs @@ -18,25 +18,26 @@ //! Autogenerated weights for pallet_balances //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-02-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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 // --steps=50 // --repeat=20 -// --pallet=pallet_balances // --extrinsic=* // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/balances/src/weights.rs +// --json-file=/var/lib/gitlab-runner/builds/zyw4fam_/0/parity/mirrors/substrate/.git/.artifacts/bench.json +// --pallet=pallet_balances +// --chain=dev // --header=./HEADER-APACHE2 +// --output=./frame/balances/src/weights.rs // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -64,10 +65,11 @@ impl WeightInfo for SubstrateWeight { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `1723` - // Estimated: `2603` - // Minimum execution time: 47_557 nanoseconds. - Weight::from_parts(48_314_000, 2603) + // Measured: `0` + // Estimated: `3593` + // Minimum execution time: 37_815 nanoseconds. + Weight::from_ref_time(38_109_000) + .saturating_add(Weight::from_proof_size(3593)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -75,10 +77,11 @@ impl WeightInfo for SubstrateWeight { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer_keep_alive() -> Weight { // Proof Size summary in bytes: - // Measured: `1607` - // Estimated: `2603` - // Minimum execution time: 36_372 nanoseconds. - Weight::from_parts(37_432_000, 2603) + // Measured: `0` + // Estimated: `3593` + // Minimum execution time: 28_184 nanoseconds. + Weight::from_ref_time(49_250_000) + .saturating_add(Weight::from_proof_size(3593)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -86,10 +89,11 @@ impl WeightInfo for SubstrateWeight { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn set_balance_creating() -> Weight { // Proof Size summary in bytes: - // Measured: `1757` - // Estimated: `2603` - // Minimum execution time: 26_671 nanoseconds. - Weight::from_parts(28_287_000, 2603) + // Measured: `206` + // Estimated: `3593` + // Minimum execution time: 17_474 nanoseconds. + Weight::from_ref_time(17_777_000) + .saturating_add(Weight::from_proof_size(3593)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -97,10 +101,11 @@ impl WeightInfo for SubstrateWeight { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn set_balance_killing() -> Weight { // Proof Size summary in bytes: - // Measured: `1757` - // Estimated: `2603` - // Minimum execution time: 30_122 nanoseconds. - Weight::from_parts(30_615_000, 2603) + // Measured: `206` + // Estimated: `3593` + // Minimum execution time: 20_962 nanoseconds. + Weight::from_ref_time(21_419_000) + .saturating_add(Weight::from_proof_size(3593)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -108,10 +113,11 @@ impl WeightInfo for SubstrateWeight { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn force_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `1719` - // Estimated: `5206` - // Minimum execution time: 47_891 nanoseconds. - Weight::from_parts(48_496_000, 5206) + // Measured: `135` + // Estimated: `6196` + // Minimum execution time: 39_713 nanoseconds. + Weight::from_ref_time(40_360_000) + .saturating_add(Weight::from_proof_size(6196)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -119,10 +125,11 @@ impl WeightInfo for SubstrateWeight { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer_all() -> Weight { // Proof Size summary in bytes: - // Measured: `1607` - // Estimated: `2603` - // Minimum execution time: 42_470 nanoseconds. - Weight::from_parts(42_950_000, 2603) + // Measured: `0` + // Estimated: `3593` + // Minimum execution time: 34_878 nanoseconds. + Weight::from_ref_time(35_121_000) + .saturating_add(Weight::from_proof_size(3593)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -130,10 +137,11 @@ impl WeightInfo for SubstrateWeight { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn force_unreserve() -> Weight { // Proof Size summary in bytes: - // Measured: `1641` - // Estimated: `2603` - // Minimum execution time: 23_230 nanoseconds. - Weight::from_parts(23_951_000, 2603) + // Measured: `206` + // Estimated: `3593` + // Minimum execution time: 16_790 nanoseconds. + Weight::from_ref_time(17_029_000) + .saturating_add(Weight::from_proof_size(3593)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -145,10 +153,11 @@ impl WeightInfo for () { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `1723` - // Estimated: `2603` - // Minimum execution time: 47_557 nanoseconds. - Weight::from_parts(48_314_000, 2603) + // Measured: `0` + // Estimated: `3593` + // Minimum execution time: 37_815 nanoseconds. + Weight::from_ref_time(38_109_000) + .saturating_add(Weight::from_proof_size(3593)) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -156,10 +165,11 @@ impl WeightInfo for () { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer_keep_alive() -> Weight { // Proof Size summary in bytes: - // Measured: `1607` - // Estimated: `2603` - // Minimum execution time: 36_372 nanoseconds. - Weight::from_parts(37_432_000, 2603) + // Measured: `0` + // Estimated: `3593` + // Minimum execution time: 28_184 nanoseconds. + Weight::from_ref_time(49_250_000) + .saturating_add(Weight::from_proof_size(3593)) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -167,10 +177,11 @@ impl WeightInfo for () { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn set_balance_creating() -> Weight { // Proof Size summary in bytes: - // Measured: `1757` - // Estimated: `2603` - // Minimum execution time: 26_671 nanoseconds. - Weight::from_parts(28_287_000, 2603) + // Measured: `206` + // Estimated: `3593` + // Minimum execution time: 17_474 nanoseconds. + Weight::from_ref_time(17_777_000) + .saturating_add(Weight::from_proof_size(3593)) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -178,10 +189,11 @@ impl WeightInfo for () { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn set_balance_killing() -> Weight { // Proof Size summary in bytes: - // Measured: `1757` - // Estimated: `2603` - // Minimum execution time: 30_122 nanoseconds. - Weight::from_parts(30_615_000, 2603) + // Measured: `206` + // Estimated: `3593` + // Minimum execution time: 20_962 nanoseconds. + Weight::from_ref_time(21_419_000) + .saturating_add(Weight::from_proof_size(3593)) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -189,10 +201,11 @@ impl WeightInfo for () { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn force_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `1719` - // Estimated: `5206` - // Minimum execution time: 47_891 nanoseconds. - Weight::from_parts(48_496_000, 5206) + // Measured: `135` + // Estimated: `6196` + // Minimum execution time: 39_713 nanoseconds. + Weight::from_ref_time(40_360_000) + .saturating_add(Weight::from_proof_size(6196)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -200,10 +213,11 @@ impl WeightInfo for () { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer_all() -> Weight { // Proof Size summary in bytes: - // Measured: `1607` - // Estimated: `2603` - // Minimum execution time: 42_470 nanoseconds. - Weight::from_parts(42_950_000, 2603) + // Measured: `0` + // Estimated: `3593` + // Minimum execution time: 34_878 nanoseconds. + Weight::from_ref_time(35_121_000) + .saturating_add(Weight::from_proof_size(3593)) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -211,10 +225,11 @@ impl WeightInfo for () { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn force_unreserve() -> Weight { // Proof Size summary in bytes: - // Measured: `1641` - // Estimated: `2603` - // Minimum execution time: 23_230 nanoseconds. - Weight::from_parts(23_951_000, 2603) + // Measured: `206` + // Estimated: `3593` + // Minimum execution time: 16_790 nanoseconds. + Weight::from_ref_time(17_029_000) + .saturating_add(Weight::from_proof_size(3593)) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/frame/benchmarking/pov/src/benchmarking.rs b/frame/benchmarking/pov/src/benchmarking.rs index 331570ad28fce..ebe9b241416ad 100644 --- a/frame/benchmarking/pov/src/benchmarking.rs +++ b/frame/benchmarking/pov/src/benchmarking.rs @@ -39,6 +39,17 @@ frame_benchmarking::benchmarks! { assert_eq!(Value::::get(), Some(123)); } + #[pov_mode = MaxEncodedLen { + Pov::Value2: Ignored + }] + storage_single_value_ignored_some_read { + Value::::put(123); + Value2::::put(123); + }: { + assert_eq!(Value::::get(), Some(123)); + assert_eq!(Value2::::get(), Some(123)); + } + storage_single_value_read_twice { Value::::put(123); }: { diff --git a/frame/benchmarking/pov/src/weights.rs b/frame/benchmarking/pov/src/weights.rs index e890e9b2ef88a..948d268cf7a4b 100644 --- a/frame/benchmarking/pov/src/weights.rs +++ b/frame/benchmarking/pov/src/weights.rs @@ -2,9 +2,9 @@ //! Autogenerated weights for frame_benchmarking_pallet_pov //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-01-23, STEPS: `50`, REPEAT: `1`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-02-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `oty-parity`, CPU: `11th Gen Intel(R) Core(TM) i7-1165G7 @ 2.80GHz` +//! HOSTNAME: `i9`, CPU: `13th Gen Intel(R) Core(TM) i9-13900K` //! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 1024 // Executed Command: @@ -19,7 +19,7 @@ // --steps // 50 // --repeat -// 1 +// 20 // --template=.maintain/frame-weight-template.hbs // --output=frame/benchmarking/pov/src/weights.rs @@ -71,9 +71,10 @@ impl WeightInfo for SubstrateWeight { fn storage_single_value_read() -> Weight { // Proof Size summary in bytes: // Measured: `136` - // Estimated: `499` - // Minimum execution time: 3_291 nanoseconds. - Weight::from_parts(3_291_000, 499) + // Estimated: `1489` + // Minimum execution time: 1_968 nanoseconds. + Weight::from_ref_time(2_060_000) + .saturating_add(Weight::from_proof_size(1489)) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: Pov Value (r:1 w:0) @@ -82,8 +83,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `136` // Estimated: `0` - // Minimum execution time: 2_918 nanoseconds. - Weight::from_ref_time(2_918_000) + // Minimum execution time: 1_934 nanoseconds. + Weight::from_ref_time(2_092_000) + .saturating_add(Weight::from_proof_size(0)) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: Pov Value (r:1 w:0) @@ -93,9 +95,10 @@ impl WeightInfo for SubstrateWeight { fn storage_single_value_ignored_some_read() -> Weight { // Proof Size summary in bytes: // Measured: `160` - // Estimated: `659` - // Minimum execution time: 4_056 nanoseconds. - Weight::from_parts(4_056_000, 659) + // Estimated: `1649` + // Minimum execution time: 2_605 nanoseconds. + Weight::from_ref_time(2_786_000) + .saturating_add(Weight::from_proof_size(1649)) .saturating_add(T::DbWeight::get().reads(2_u64)) } /// Storage: Pov Value (r:1 w:0) @@ -103,9 +106,10 @@ impl WeightInfo for SubstrateWeight { fn storage_single_value_read_twice() -> Weight { // Proof Size summary in bytes: // Measured: `136` - // Estimated: `499` - // Minimum execution time: 3_552 nanoseconds. - Weight::from_parts(3_552_000, 499) + // Estimated: `1489` + // Minimum execution time: 2_019 nanoseconds. + Weight::from_ref_time(2_214_000) + .saturating_add(Weight::from_proof_size(1489)) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: Pov Value (r:0 w:1) @@ -114,8 +118,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 795 nanoseconds. - Weight::from_ref_time(795_000) + // Minimum execution time: 279 nanoseconds. + Weight::from_ref_time(357_000) + .saturating_add(Weight::from_proof_size(0)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Pov Value (r:0 w:1) @@ -124,8 +129,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 865 nanoseconds. - Weight::from_ref_time(865_000) + // Minimum execution time: 291 nanoseconds. + Weight::from_ref_time(378_000) + .saturating_add(Weight::from_proof_size(0)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Pov Map1M (r:1 w:0) @@ -133,9 +139,10 @@ impl WeightInfo for SubstrateWeight { fn storage_1m_map_read_one_value_two_additional_layers() -> Weight { // Proof Size summary in bytes: // Measured: `1275` - // Estimated: `3750` - // Minimum execution time: 9_571 nanoseconds. - Weight::from_parts(9_571_000, 3750) + // Estimated: `4740` + // Minimum execution time: 5_077 nanoseconds. + Weight::from_ref_time(5_400_000) + .saturating_add(Weight::from_proof_size(4740)) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: Pov Map1M (r:1 w:0) @@ -143,9 +150,10 @@ impl WeightInfo for SubstrateWeight { fn storage_1m_map_read_one_value_three_additional_layers() -> Weight { // Proof Size summary in bytes: // Measured: `1544` - // Estimated: `4019` - // Minimum execution time: 14_597 nanoseconds. - Weight::from_parts(14_597_000, 4019) + // Estimated: `5009` + // Minimum execution time: 5_878 nanoseconds. + Weight::from_ref_time(6_239_000) + .saturating_add(Weight::from_proof_size(5009)) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: Pov Map1M (r:1 w:0) @@ -153,9 +161,10 @@ impl WeightInfo for SubstrateWeight { fn storage_1m_map_read_one_value_four_additional_layers() -> Weight { // Proof Size summary in bytes: // Measured: `2044` - // Estimated: `4519` - // Minimum execution time: 19_793 nanoseconds. - Weight::from_parts(19_793_000, 4519) + // Estimated: `5509` + // Minimum execution time: 7_282 nanoseconds. + Weight::from_ref_time(8_022_000) + .saturating_add(Weight::from_proof_size(5509)) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: Pov Map1M (r:100 w:0) @@ -167,13 +176,14 @@ impl WeightInfo for SubstrateWeight { fn storage_map_read_per_component(n: u32, m: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `515 + n * (188 ±0) + m * (188 ±0)` - // Estimated: `0 + n * (3006 ±0) + m * (2511 ±0)` - // Minimum execution time: 266_160 nanoseconds. - Weight::from_ref_time(190_477_747) - // Standard Error: 96_405 - .saturating_add(Weight::from_ref_time(1_049_993).saturating_mul(n.into())) - // Standard Error: 96_405 - .saturating_add(Weight::from_ref_time(1_202_546).saturating_mul(m.into())) + // Estimated: `1980 + n * (3006 ±0) + m * (2511 ±0)` + // Minimum execution time: 195_406 nanoseconds. + Weight::from_ref_time(129_093_464) + .saturating_add(Weight::from_proof_size(1980)) + // Standard Error: 12_134 + .saturating_add(Weight::from_ref_time(855_330).saturating_mul(n.into())) + // Standard Error: 12_134 + .saturating_add(Weight::from_ref_time(870_523).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(m.into()))) .saturating_add(Weight::from_proof_size(3006).saturating_mul(n.into())) @@ -188,13 +198,14 @@ impl WeightInfo for SubstrateWeight { fn storage_map_read_per_component_one_ignored(n: u32, m: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `515 + n * (188 ±0) + m * (188 ±0)` - // Estimated: `695 + n * (3195 ±2) + m * (189 ±2)` - // Minimum execution time: 265_113 nanoseconds. - Weight::from_parts(215_943_973, 695) - // Standard Error: 199_907 - .saturating_add(Weight::from_ref_time(988_371).saturating_mul(n.into())) - // Standard Error: 199_907 - .saturating_add(Weight::from_ref_time(1_145_693).saturating_mul(m.into())) + // Estimated: `1685 + n * (3195 ±0) + m * (189 ±0)` + // Minimum execution time: 195_053 nanoseconds. + Weight::from_ref_time(131_322_479) + .saturating_add(Weight::from_proof_size(1685)) + // Standard Error: 12_161 + .saturating_add(Weight::from_ref_time(843_047).saturating_mul(n.into())) + // Standard Error: 12_161 + .saturating_add(Weight::from_ref_time(858_668).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(m.into()))) .saturating_add(Weight::from_proof_size(3195).saturating_mul(n.into())) @@ -206,11 +217,12 @@ impl WeightInfo for SubstrateWeight { fn storage_1m_map_one_entry_repeated_read(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `170` - // Estimated: `2511` - // Minimum execution time: 119 nanoseconds. - Weight::from_parts(3_649_405, 2511) - // Standard Error: 4_472 - .saturating_add(Weight::from_ref_time(432_147).saturating_mul(n.into())) + // Estimated: `3501` + // Minimum execution time: 22 nanoseconds. + Weight::from_ref_time(2_334_945) + .saturating_add(Weight::from_proof_size(3501)) + // Standard Error: 624 + .saturating_add(Weight::from_ref_time(282_046).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: Pov Map1M (r:100 w:0) @@ -219,11 +231,12 @@ impl WeightInfo for SubstrateWeight { fn storage_1m_map_multiple_entry_repeated_read(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `147 + n * (40 ±0)` - // Estimated: `0 + n * (2511 ±0)` - // Minimum execution time: 106 nanoseconds. - Weight::from_ref_time(59_892_609) - // Standard Error: 418_004 - .saturating_add(Weight::from_ref_time(5_919_793).saturating_mul(n.into())) + // Estimated: `990 + n * (2511 ±0)` + // Minimum execution time: 20 nanoseconds. + Weight::from_ref_time(525_027) + .saturating_add(Weight::from_proof_size(990)) + // Standard Error: 2_767 + .saturating_add(Weight::from_ref_time(3_887_350).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(Weight::from_proof_size(2511).saturating_mul(n.into())) } @@ -233,11 +246,12 @@ impl WeightInfo for SubstrateWeight { fn storage_1m_double_map_read_per_component(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `21938 + n * (57 ±0)` - // Estimated: `0 + n * (2543 ±0)` - // Minimum execution time: 550 nanoseconds. - Weight::from_ref_time(65_431_603) - // Standard Error: 66_935 - .saturating_add(Weight::from_ref_time(2_825_371).saturating_mul(n.into())) + // Estimated: `990 + n * (2543 ±0)` + // Minimum execution time: 34 nanoseconds. + Weight::from_ref_time(18_341_393) + .saturating_add(Weight::from_proof_size(990)) + // Standard Error: 1_312 + .saturating_add(Weight::from_ref_time(2_053_135).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(Weight::from_proof_size(2543).saturating_mul(n.into())) } @@ -246,9 +260,10 @@ impl WeightInfo for SubstrateWeight { fn storage_value_bounded_read() -> Weight { // Proof Size summary in bytes: // Measured: `109` - // Estimated: `528` - // Minimum execution time: 2_541 nanoseconds. - Weight::from_parts(2_541_000, 528) + // Estimated: `1518` + // Minimum execution time: 1_163 nanoseconds. + Weight::from_ref_time(1_274_000) + .saturating_add(Weight::from_proof_size(1518)) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: Pov UnboundedValue (r:1 w:0) @@ -256,9 +271,10 @@ impl WeightInfo for SubstrateWeight { fn storage_value_unbounded_read() -> Weight { // Proof Size summary in bytes: // Measured: `109` - // Estimated: `604` - // Minimum execution time: 2_226 nanoseconds. - Weight::from_parts(2_226_000, 604) + // Estimated: `1594` + // Minimum execution time: 1_167 nanoseconds. + Weight::from_ref_time(1_367_000) + .saturating_add(Weight::from_proof_size(1594)) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: Pov UnboundedValue (r:1 w:0) @@ -267,8 +283,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `109` // Estimated: `0` - // Minimum execution time: 2_100 nanoseconds. - Weight::from_ref_time(2_100_000) + // Minimum execution time: 1_155 nanoseconds. + Weight::from_ref_time(1_248_000) + .saturating_add(Weight::from_proof_size(0)) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: Pov UnboundedValue (r:1 w:0) @@ -278,9 +295,10 @@ impl WeightInfo for SubstrateWeight { fn storage_value_bounded_and_unbounded_read() -> Weight { // Proof Size summary in bytes: // Measured: `109` - // Estimated: `1132` - // Minimum execution time: 2_808 nanoseconds. - Weight::from_parts(2_808_000, 1132) + // Estimated: `3112` + // Minimum execution time: 1_424 nanoseconds. + Weight::from_ref_time(1_601_000) + .saturating_add(Weight::from_proof_size(3112)) .saturating_add(T::DbWeight::get().reads(2_u64)) } /// Storage: Pov LargeValue (r:1 w:0) @@ -289,11 +307,12 @@ impl WeightInfo for SubstrateWeight { fn measured_storage_value_read_linear_size(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `174 + l * (1 ±0)` - // Estimated: `666 + l * (1 ±0)` - // Minimum execution time: 3_385 nanoseconds. - Weight::from_parts(3_385_000, 666) - // Standard Error: 10 - .saturating_add(Weight::from_ref_time(356).saturating_mul(l.into())) + // Estimated: `1656 + l * (1 ±0)` + // Minimum execution time: 1_744 nanoseconds. + Weight::from_ref_time(1_800_000) + .saturating_add(Weight::from_proof_size(1656)) + // Standard Error: 4 + .saturating_add(Weight::from_ref_time(443).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(Weight::from_proof_size(1).saturating_mul(l.into())) } @@ -303,11 +322,12 @@ impl WeightInfo for SubstrateWeight { fn mel_storage_value_read_linear_size(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `174 + l * (1 ±0)` - // Estimated: `4194803` - // Minimum execution time: 3_342 nanoseconds. - Weight::from_parts(3_342_000, 4194803) + // Estimated: `4195793` + // Minimum execution time: 1_770 nanoseconds. + Weight::from_ref_time(1_813_000) + .saturating_add(Weight::from_proof_size(4195793)) // Standard Error: 6 - .saturating_add(Weight::from_ref_time(345).saturating_mul(l.into())) + .saturating_add(Weight::from_ref_time(495).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: Pov LargeValue (r:1 w:0) @@ -318,11 +338,12 @@ impl WeightInfo for SubstrateWeight { fn measured_storage_double_value_read_linear_size(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `235 + l * (2 ±0)` - // Estimated: `1448 + l * (4 ±0)` - // Minimum execution time: 4_519 nanoseconds. - Weight::from_parts(4_519_000, 1448) - // Standard Error: 9 - .saturating_add(Weight::from_ref_time(560).saturating_mul(l.into())) + // Estimated: `3428 + l * (4 ±0)` + // Minimum execution time: 2_349 nanoseconds. + Weight::from_ref_time(2_423_000) + .saturating_add(Weight::from_proof_size(3428)) + // Standard Error: 11 + .saturating_add(Weight::from_ref_time(950).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(Weight::from_proof_size(4).saturating_mul(l.into())) } @@ -334,11 +355,12 @@ impl WeightInfo for SubstrateWeight { fn mel_storage_double_value_read_linear_size(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `235 + l * (2 ±0)` - // Estimated: `8389606` - // Minimum execution time: 4_462 nanoseconds. - Weight::from_parts(4_462_000, 8389606) - // Standard Error: 7 - .saturating_add(Weight::from_ref_time(538).saturating_mul(l.into())) + // Estimated: `8391586` + // Minimum execution time: 2_315 nanoseconds. + Weight::from_ref_time(2_409_000) + .saturating_add(Weight::from_proof_size(8391586)) + // Standard Error: 12 + .saturating_add(Weight::from_ref_time(984).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) } /// Storage: Pov LargeValue (r:1 w:0) @@ -349,11 +371,12 @@ impl WeightInfo for SubstrateWeight { fn mel_mixed_storage_double_value_read_linear_size(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `235 + l * (2 ±0)` - // Estimated: `4195527 + l * (2 ±0)` - // Minimum execution time: 4_552 nanoseconds. - Weight::from_parts(4_552_000, 4195527) - // Standard Error: 6 - .saturating_add(Weight::from_ref_time(507).saturating_mul(l.into())) + // Estimated: `4197507 + l * (2 ±0)` + // Minimum execution time: 2_370 nanoseconds. + Weight::from_ref_time(2_474_000) + .saturating_add(Weight::from_proof_size(4197507)) + // Standard Error: 11 + .saturating_add(Weight::from_ref_time(956).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(Weight::from_proof_size(2).saturating_mul(l.into())) } @@ -365,11 +388,12 @@ impl WeightInfo for SubstrateWeight { fn measured_mixed_storage_double_value_read_linear_size(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `235 + l * (2 ±0)` - // Estimated: `4195527 + l * (2 ±0)` - // Minimum execution time: 4_236 nanoseconds. - Weight::from_parts(4_236_000, 4195527) - // Standard Error: 8 - .saturating_add(Weight::from_ref_time(517).saturating_mul(l.into())) + // Estimated: `4197507 + l * (2 ±0)` + // Minimum execution time: 2_375 nanoseconds. + Weight::from_ref_time(2_420_000) + .saturating_add(Weight::from_proof_size(4197507)) + // Standard Error: 9 + .saturating_add(Weight::from_ref_time(914).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(Weight::from_proof_size(2).saturating_mul(l.into())) } @@ -381,11 +405,12 @@ impl WeightInfo for SubstrateWeight { fn storage_map_unbounded_both_measured_read(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `293 + i * (8 ±0)` - // Estimated: `5524 + i * (16 ±0)` - // Minimum execution time: 5_649 nanoseconds. - Weight::from_parts(6_111_237, 5524) - // Standard Error: 1_060 - .saturating_add(Weight::from_ref_time(2_693).saturating_mul(i.into())) + // Estimated: `7504 + i * (16 ±0)` + // Minimum execution time: 3_305 nanoseconds. + Weight::from_ref_time(3_689_335) + .saturating_add(Weight::from_proof_size(7504)) + // Standard Error: 29 + .saturating_add(Weight::from_ref_time(638).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(Weight::from_proof_size(16).saturating_mul(i.into())) } @@ -397,9 +422,12 @@ impl WeightInfo for SubstrateWeight { fn storage_map_partial_unbounded_read(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `260 + i * (4 ±0)` - // Estimated: `5243 + i * (4 ±0)` - // Minimum execution time: 5_997 nanoseconds. - Weight::from_parts(7_996_508, 5243) + // Estimated: `7223 + i * (4 ±0)` + // Minimum execution time: 3_469 nanoseconds. + Weight::from_ref_time(3_878_896) + .saturating_add(Weight::from_proof_size(7223)) + // Standard Error: 33 + .saturating_add(Weight::from_ref_time(356).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(Weight::from_proof_size(4).saturating_mul(i.into())) } @@ -411,11 +439,12 @@ impl WeightInfo for SubstrateWeight { fn storage_map_partial_unbounded_ignored_read(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `260 + i * (4 ±0)` - // Estimated: `2768 + i * (4 ±0)` - // Minimum execution time: 5_679 nanoseconds. - Weight::from_parts(6_496_804, 2768) - // Standard Error: 611 - .saturating_add(Weight::from_ref_time(930).saturating_mul(i.into())) + // Estimated: `3758 + i * (4 ±0)` + // Minimum execution time: 3_442 nanoseconds. + Weight::from_ref_time(3_881_051) + .saturating_add(Weight::from_proof_size(3758)) + // Standard Error: 35 + .saturating_add(Weight::from_ref_time(384).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(Weight::from_proof_size(4).saturating_mul(i.into())) } @@ -423,15 +452,17 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_087 nanoseconds. - Weight::from_ref_time(7_087_000) + // Minimum execution time: 1_619 nanoseconds. + Weight::from_ref_time(1_728_000) + .saturating_add(Weight::from_proof_size(0)) } fn noop() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_719 nanoseconds. - Weight::from_ref_time(2_719_000) + // Minimum execution time: 546 nanoseconds. + Weight::from_ref_time(640_000) + .saturating_add(Weight::from_proof_size(0)) } } @@ -442,9 +473,10 @@ impl WeightInfo for () { fn storage_single_value_read() -> Weight { // Proof Size summary in bytes: // Measured: `136` - // Estimated: `499` - // Minimum execution time: 3_291 nanoseconds. - Weight::from_parts(3_291_000, 499) + // Estimated: `1489` + // Minimum execution time: 1_968 nanoseconds. + Weight::from_ref_time(2_060_000) + .saturating_add(Weight::from_proof_size(1489)) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: Pov Value (r:1 w:0) @@ -453,8 +485,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `136` // Estimated: `0` - // Minimum execution time: 2_918 nanoseconds. - Weight::from_ref_time(2_918_000) + // Minimum execution time: 1_934 nanoseconds. + Weight::from_ref_time(2_092_000) + .saturating_add(Weight::from_proof_size(0)) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: Pov Value (r:1 w:0) @@ -464,9 +497,10 @@ impl WeightInfo for () { fn storage_single_value_ignored_some_read() -> Weight { // Proof Size summary in bytes: // Measured: `160` - // Estimated: `659` - // Minimum execution time: 4_056 nanoseconds. - Weight::from_parts(4_056_000, 659) + // Estimated: `1649` + // Minimum execution time: 2_605 nanoseconds. + Weight::from_ref_time(2_786_000) + .saturating_add(Weight::from_proof_size(1649)) .saturating_add(RocksDbWeight::get().reads(2_u64)) } /// Storage: Pov Value (r:1 w:0) @@ -474,9 +508,10 @@ impl WeightInfo for () { fn storage_single_value_read_twice() -> Weight { // Proof Size summary in bytes: // Measured: `136` - // Estimated: `499` - // Minimum execution time: 3_552 nanoseconds. - Weight::from_parts(3_552_000, 499) + // Estimated: `1489` + // Minimum execution time: 2_019 nanoseconds. + Weight::from_ref_time(2_214_000) + .saturating_add(Weight::from_proof_size(1489)) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: Pov Value (r:0 w:1) @@ -485,8 +520,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 795 nanoseconds. - Weight::from_ref_time(795_000) + // Minimum execution time: 279 nanoseconds. + Weight::from_ref_time(357_000) + .saturating_add(Weight::from_proof_size(0)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Pov Value (r:0 w:1) @@ -495,8 +531,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 865 nanoseconds. - Weight::from_ref_time(865_000) + // Minimum execution time: 291 nanoseconds. + Weight::from_ref_time(378_000) + .saturating_add(Weight::from_proof_size(0)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Pov Map1M (r:1 w:0) @@ -504,9 +541,10 @@ impl WeightInfo for () { fn storage_1m_map_read_one_value_two_additional_layers() -> Weight { // Proof Size summary in bytes: // Measured: `1275` - // Estimated: `3750` - // Minimum execution time: 9_571 nanoseconds. - Weight::from_parts(9_571_000, 3750) + // Estimated: `4740` + // Minimum execution time: 5_077 nanoseconds. + Weight::from_ref_time(5_400_000) + .saturating_add(Weight::from_proof_size(4740)) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: Pov Map1M (r:1 w:0) @@ -514,9 +552,10 @@ impl WeightInfo for () { fn storage_1m_map_read_one_value_three_additional_layers() -> Weight { // Proof Size summary in bytes: // Measured: `1544` - // Estimated: `4019` - // Minimum execution time: 14_597 nanoseconds. - Weight::from_parts(14_597_000, 4019) + // Estimated: `5009` + // Minimum execution time: 5_878 nanoseconds. + Weight::from_ref_time(6_239_000) + .saturating_add(Weight::from_proof_size(5009)) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: Pov Map1M (r:1 w:0) @@ -524,9 +563,10 @@ impl WeightInfo for () { fn storage_1m_map_read_one_value_four_additional_layers() -> Weight { // Proof Size summary in bytes: // Measured: `2044` - // Estimated: `4519` - // Minimum execution time: 19_793 nanoseconds. - Weight::from_parts(19_793_000, 4519) + // Estimated: `5509` + // Minimum execution time: 7_282 nanoseconds. + Weight::from_ref_time(8_022_000) + .saturating_add(Weight::from_proof_size(5509)) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: Pov Map1M (r:100 w:0) @@ -538,13 +578,14 @@ impl WeightInfo for () { fn storage_map_read_per_component(n: u32, m: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `515 + n * (188 ±0) + m * (188 ±0)` - // Estimated: `0 + n * (3006 ±0) + m * (2511 ±0)` - // Minimum execution time: 266_160 nanoseconds. - Weight::from_ref_time(190_477_747) - // Standard Error: 96_405 - .saturating_add(Weight::from_ref_time(1_049_993).saturating_mul(n.into())) - // Standard Error: 96_405 - .saturating_add(Weight::from_ref_time(1_202_546).saturating_mul(m.into())) + // Estimated: `1980 + n * (3006 ±0) + m * (2511 ±0)` + // Minimum execution time: 195_406 nanoseconds. + Weight::from_ref_time(129_093_464) + .saturating_add(Weight::from_proof_size(1980)) + // Standard Error: 12_134 + .saturating_add(Weight::from_ref_time(855_330).saturating_mul(n.into())) + // Standard Error: 12_134 + .saturating_add(Weight::from_ref_time(870_523).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(m.into()))) .saturating_add(Weight::from_proof_size(3006).saturating_mul(n.into())) @@ -559,13 +600,14 @@ impl WeightInfo for () { fn storage_map_read_per_component_one_ignored(n: u32, m: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `515 + n * (188 ±0) + m * (188 ±0)` - // Estimated: `695 + n * (3195 ±2) + m * (189 ±2)` - // Minimum execution time: 265_113 nanoseconds. - Weight::from_parts(215_943_973, 695) - // Standard Error: 199_907 - .saturating_add(Weight::from_ref_time(988_371).saturating_mul(n.into())) - // Standard Error: 199_907 - .saturating_add(Weight::from_ref_time(1_145_693).saturating_mul(m.into())) + // Estimated: `1685 + n * (3195 ±0) + m * (189 ±0)` + // Minimum execution time: 195_053 nanoseconds. + Weight::from_ref_time(131_322_479) + .saturating_add(Weight::from_proof_size(1685)) + // Standard Error: 12_161 + .saturating_add(Weight::from_ref_time(843_047).saturating_mul(n.into())) + // Standard Error: 12_161 + .saturating_add(Weight::from_ref_time(858_668).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(m.into()))) .saturating_add(Weight::from_proof_size(3195).saturating_mul(n.into())) @@ -577,11 +619,12 @@ impl WeightInfo for () { fn storage_1m_map_one_entry_repeated_read(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `170` - // Estimated: `2511` - // Minimum execution time: 119 nanoseconds. - Weight::from_parts(3_649_405, 2511) - // Standard Error: 4_472 - .saturating_add(Weight::from_ref_time(432_147).saturating_mul(n.into())) + // Estimated: `3501` + // Minimum execution time: 22 nanoseconds. + Weight::from_ref_time(2_334_945) + .saturating_add(Weight::from_proof_size(3501)) + // Standard Error: 624 + .saturating_add(Weight::from_ref_time(282_046).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: Pov Map1M (r:100 w:0) @@ -590,11 +633,12 @@ impl WeightInfo for () { fn storage_1m_map_multiple_entry_repeated_read(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `147 + n * (40 ±0)` - // Estimated: `0 + n * (2511 ±0)` - // Minimum execution time: 106 nanoseconds. - Weight::from_ref_time(59_892_609) - // Standard Error: 418_004 - .saturating_add(Weight::from_ref_time(5_919_793).saturating_mul(n.into())) + // Estimated: `990 + n * (2511 ±0)` + // Minimum execution time: 20 nanoseconds. + Weight::from_ref_time(525_027) + .saturating_add(Weight::from_proof_size(990)) + // Standard Error: 2_767 + .saturating_add(Weight::from_ref_time(3_887_350).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(Weight::from_proof_size(2511).saturating_mul(n.into())) } @@ -604,11 +648,12 @@ impl WeightInfo for () { fn storage_1m_double_map_read_per_component(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `21938 + n * (57 ±0)` - // Estimated: `0 + n * (2543 ±0)` - // Minimum execution time: 550 nanoseconds. - Weight::from_ref_time(65_431_603) - // Standard Error: 66_935 - .saturating_add(Weight::from_ref_time(2_825_371).saturating_mul(n.into())) + // Estimated: `990 + n * (2543 ±0)` + // Minimum execution time: 34 nanoseconds. + Weight::from_ref_time(18_341_393) + .saturating_add(Weight::from_proof_size(990)) + // Standard Error: 1_312 + .saturating_add(Weight::from_ref_time(2_053_135).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(Weight::from_proof_size(2543).saturating_mul(n.into())) } @@ -617,9 +662,10 @@ impl WeightInfo for () { fn storage_value_bounded_read() -> Weight { // Proof Size summary in bytes: // Measured: `109` - // Estimated: `528` - // Minimum execution time: 2_541 nanoseconds. - Weight::from_parts(2_541_000, 528) + // Estimated: `1518` + // Minimum execution time: 1_163 nanoseconds. + Weight::from_ref_time(1_274_000) + .saturating_add(Weight::from_proof_size(1518)) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: Pov UnboundedValue (r:1 w:0) @@ -627,9 +673,10 @@ impl WeightInfo for () { fn storage_value_unbounded_read() -> Weight { // Proof Size summary in bytes: // Measured: `109` - // Estimated: `604` - // Minimum execution time: 2_226 nanoseconds. - Weight::from_parts(2_226_000, 604) + // Estimated: `1594` + // Minimum execution time: 1_167 nanoseconds. + Weight::from_ref_time(1_367_000) + .saturating_add(Weight::from_proof_size(1594)) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: Pov UnboundedValue (r:1 w:0) @@ -638,8 +685,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `109` // Estimated: `0` - // Minimum execution time: 2_100 nanoseconds. - Weight::from_ref_time(2_100_000) + // Minimum execution time: 1_155 nanoseconds. + Weight::from_ref_time(1_248_000) + .saturating_add(Weight::from_proof_size(0)) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: Pov UnboundedValue (r:1 w:0) @@ -649,9 +697,10 @@ impl WeightInfo for () { fn storage_value_bounded_and_unbounded_read() -> Weight { // Proof Size summary in bytes: // Measured: `109` - // Estimated: `1132` - // Minimum execution time: 2_808 nanoseconds. - Weight::from_parts(2_808_000, 1132) + // Estimated: `3112` + // Minimum execution time: 1_424 nanoseconds. + Weight::from_ref_time(1_601_000) + .saturating_add(Weight::from_proof_size(3112)) .saturating_add(RocksDbWeight::get().reads(2_u64)) } /// Storage: Pov LargeValue (r:1 w:0) @@ -660,11 +709,12 @@ impl WeightInfo for () { fn measured_storage_value_read_linear_size(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `174 + l * (1 ±0)` - // Estimated: `666 + l * (1 ±0)` - // Minimum execution time: 3_385 nanoseconds. - Weight::from_parts(3_385_000, 666) - // Standard Error: 10 - .saturating_add(Weight::from_ref_time(356).saturating_mul(l.into())) + // Estimated: `1656 + l * (1 ±0)` + // Minimum execution time: 1_744 nanoseconds. + Weight::from_ref_time(1_800_000) + .saturating_add(Weight::from_proof_size(1656)) + // Standard Error: 4 + .saturating_add(Weight::from_ref_time(443).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(Weight::from_proof_size(1).saturating_mul(l.into())) } @@ -674,11 +724,12 @@ impl WeightInfo for () { fn mel_storage_value_read_linear_size(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `174 + l * (1 ±0)` - // Estimated: `4194803` - // Minimum execution time: 3_342 nanoseconds. - Weight::from_parts(3_342_000, 4194803) + // Estimated: `4195793` + // Minimum execution time: 1_770 nanoseconds. + Weight::from_ref_time(1_813_000) + .saturating_add(Weight::from_proof_size(4195793)) // Standard Error: 6 - .saturating_add(Weight::from_ref_time(345).saturating_mul(l.into())) + .saturating_add(Weight::from_ref_time(495).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: Pov LargeValue (r:1 w:0) @@ -689,11 +740,12 @@ impl WeightInfo for () { fn measured_storage_double_value_read_linear_size(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `235 + l * (2 ±0)` - // Estimated: `1448 + l * (4 ±0)` - // Minimum execution time: 4_519 nanoseconds. - Weight::from_parts(4_519_000, 1448) - // Standard Error: 9 - .saturating_add(Weight::from_ref_time(560).saturating_mul(l.into())) + // Estimated: `3428 + l * (4 ±0)` + // Minimum execution time: 2_349 nanoseconds. + Weight::from_ref_time(2_423_000) + .saturating_add(Weight::from_proof_size(3428)) + // Standard Error: 11 + .saturating_add(Weight::from_ref_time(950).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(Weight::from_proof_size(4).saturating_mul(l.into())) } @@ -705,11 +757,12 @@ impl WeightInfo for () { fn mel_storage_double_value_read_linear_size(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `235 + l * (2 ±0)` - // Estimated: `8389606` - // Minimum execution time: 4_462 nanoseconds. - Weight::from_parts(4_462_000, 8389606) - // Standard Error: 7 - .saturating_add(Weight::from_ref_time(538).saturating_mul(l.into())) + // Estimated: `8391586` + // Minimum execution time: 2_315 nanoseconds. + Weight::from_ref_time(2_409_000) + .saturating_add(Weight::from_proof_size(8391586)) + // Standard Error: 12 + .saturating_add(Weight::from_ref_time(984).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) } /// Storage: Pov LargeValue (r:1 w:0) @@ -720,11 +773,12 @@ impl WeightInfo for () { fn mel_mixed_storage_double_value_read_linear_size(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `235 + l * (2 ±0)` - // Estimated: `4195527 + l * (2 ±0)` - // Minimum execution time: 4_552 nanoseconds. - Weight::from_parts(4_552_000, 4195527) - // Standard Error: 6 - .saturating_add(Weight::from_ref_time(507).saturating_mul(l.into())) + // Estimated: `4197507 + l * (2 ±0)` + // Minimum execution time: 2_370 nanoseconds. + Weight::from_ref_time(2_474_000) + .saturating_add(Weight::from_proof_size(4197507)) + // Standard Error: 11 + .saturating_add(Weight::from_ref_time(956).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(Weight::from_proof_size(2).saturating_mul(l.into())) } @@ -736,11 +790,12 @@ impl WeightInfo for () { fn measured_mixed_storage_double_value_read_linear_size(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `235 + l * (2 ±0)` - // Estimated: `4195527 + l * (2 ±0)` - // Minimum execution time: 4_236 nanoseconds. - Weight::from_parts(4_236_000, 4195527) - // Standard Error: 8 - .saturating_add(Weight::from_ref_time(517).saturating_mul(l.into())) + // Estimated: `4197507 + l * (2 ±0)` + // Minimum execution time: 2_375 nanoseconds. + Weight::from_ref_time(2_420_000) + .saturating_add(Weight::from_proof_size(4197507)) + // Standard Error: 9 + .saturating_add(Weight::from_ref_time(914).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(Weight::from_proof_size(2).saturating_mul(l.into())) } @@ -752,11 +807,12 @@ impl WeightInfo for () { fn storage_map_unbounded_both_measured_read(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `293 + i * (8 ±0)` - // Estimated: `5524 + i * (16 ±0)` - // Minimum execution time: 5_649 nanoseconds. - Weight::from_parts(6_111_237, 5524) - // Standard Error: 1_060 - .saturating_add(Weight::from_ref_time(2_693).saturating_mul(i.into())) + // Estimated: `7504 + i * (16 ±0)` + // Minimum execution time: 3_305 nanoseconds. + Weight::from_ref_time(3_689_335) + .saturating_add(Weight::from_proof_size(7504)) + // Standard Error: 29 + .saturating_add(Weight::from_ref_time(638).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(Weight::from_proof_size(16).saturating_mul(i.into())) } @@ -768,9 +824,12 @@ impl WeightInfo for () { fn storage_map_partial_unbounded_read(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `260 + i * (4 ±0)` - // Estimated: `5243 + i * (4 ±0)` - // Minimum execution time: 5_997 nanoseconds. - Weight::from_parts(7_996_508, 5243) + // Estimated: `7223 + i * (4 ±0)` + // Minimum execution time: 3_469 nanoseconds. + Weight::from_ref_time(3_878_896) + .saturating_add(Weight::from_proof_size(7223)) + // Standard Error: 33 + .saturating_add(Weight::from_ref_time(356).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(Weight::from_proof_size(4).saturating_mul(i.into())) } @@ -782,11 +841,12 @@ impl WeightInfo for () { fn storage_map_partial_unbounded_ignored_read(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `260 + i * (4 ±0)` - // Estimated: `2768 + i * (4 ±0)` - // Minimum execution time: 5_679 nanoseconds. - Weight::from_parts(6_496_804, 2768) - // Standard Error: 611 - .saturating_add(Weight::from_ref_time(930).saturating_mul(i.into())) + // Estimated: `3758 + i * (4 ±0)` + // Minimum execution time: 3_442 nanoseconds. + Weight::from_ref_time(3_881_051) + .saturating_add(Weight::from_proof_size(3758)) + // Standard Error: 35 + .saturating_add(Weight::from_ref_time(384).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(Weight::from_proof_size(4).saturating_mul(i.into())) } @@ -794,14 +854,16 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_087 nanoseconds. - Weight::from_ref_time(7_087_000) + // Minimum execution time: 1_619 nanoseconds. + Weight::from_ref_time(1_728_000) + .saturating_add(Weight::from_proof_size(0)) } fn noop() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_719 nanoseconds. - Weight::from_ref_time(2_719_000) + // Minimum execution time: 546 nanoseconds. + Weight::from_ref_time(640_000) + .saturating_add(Weight::from_proof_size(0)) } } diff --git a/frame/glutton/src/tests.rs b/frame/glutton/src/tests.rs index d2d2d4edec421..8d2c86ed45471 100644 --- a/frame/glutton/src/tests.rs +++ b/frame/glutton/src/tests.rs @@ -177,7 +177,7 @@ fn on_idle_weight_low_proof_is_close_enough_works() { let ratio = Perbill::from_rational(got.proof_size(), should.proof_size()); // Just a sanity check here. assert!( - ratio >= Perbill::from_percent(80), + ratio >= Perbill::from_percent(50), "Too few proof size consumed, was only {:?} of expected", ratio ); diff --git a/frame/glutton/src/weights.rs b/frame/glutton/src/weights.rs index 1e09d02c69d1c..9c8e161c825f2 100644 --- a/frame/glutton/src/weights.rs +++ b/frame/glutton/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2023 Parity Technologies (UK) Ltd. +// Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_glutton //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-02-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-ehxwxxsd-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! 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: @@ -33,7 +33,7 @@ // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --json-file=/builds/parity/mirrors/substrate/.git/.artifacts/bench.json +// --json-file=/var/lib/gitlab-runner/builds/zyw4fam_/0/parity/mirrors/substrate/.git/.artifacts/bench.json // --pallet=pallet_glutton // --chain=dev // --header=./HEADER-APACHE2 @@ -71,12 +71,12 @@ impl WeightInfo for SubstrateWeight { fn initialize_pallet_grow(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `4` - // Estimated: `499` - // Minimum execution time: 9_248 nanoseconds. - Weight::from_ref_time(9_582_000) - .saturating_add(Weight::from_proof_size(499)) - // Standard Error: 1_144 - .saturating_add(Weight::from_ref_time(1_624_225).saturating_mul(n.into())) + // Estimated: `1489` + // Minimum execution time: 10_218 nanoseconds. + Weight::from_ref_time(10_510_000) + .saturating_add(Weight::from_proof_size(1489)) + // Standard Error: 1_582 + .saturating_add(Weight::from_ref_time(1_577_660).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) @@ -89,12 +89,12 @@ impl WeightInfo for SubstrateWeight { fn initialize_pallet_shrink(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `65` - // Estimated: `499` - // Minimum execution time: 10_210 nanoseconds. - Weight::from_ref_time(7_260_854) - .saturating_add(Weight::from_proof_size(499)) - // Standard Error: 1_459 - .saturating_add(Weight::from_ref_time(1_053_844).saturating_mul(n.into())) + // Estimated: `1489` + // Minimum execution time: 10_993 nanoseconds. + Weight::from_ref_time(11_208_000) + .saturating_add(Weight::from_proof_size(1489)) + // Standard Error: 1_386 + .saturating_add(Weight::from_ref_time(1_072_330).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) @@ -104,11 +104,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 605 nanoseconds. - Weight::from_ref_time(1_102_112) + // Minimum execution time: 740 nanoseconds. + Weight::from_ref_time(770_000) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 28 - .saturating_add(Weight::from_ref_time(120_597).saturating_mul(i.into())) + // Standard Error: 24 + .saturating_add(Weight::from_ref_time(96_434).saturating_mul(i.into())) } /// Storage: Glutton TrashData (r:5000 w:0) /// Proof: Glutton TrashData (max_values: Some(65000), max_size: Some(1036), added: 3016, mode: MaxEncodedLen) @@ -116,12 +116,12 @@ impl WeightInfo for SubstrateWeight { fn waste_proof_size_some(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `119036 + i * (1053 ±0)` - // Estimated: `0 + i * (3016 ±0)` - // Minimum execution time: 464 nanoseconds. - Weight::from_ref_time(552_000) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 1_962 - .saturating_add(Weight::from_ref_time(5_780_304).saturating_mul(i.into())) + // Estimated: `990 + i * (3016 ±0)` + // Minimum execution time: 630 nanoseconds. + Weight::from_ref_time(712_000) + .saturating_add(Weight::from_proof_size(990)) + // Standard Error: 4_326 + .saturating_add(Weight::from_ref_time(5_500_880).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(i.into()))) .saturating_add(Weight::from_proof_size(3016).saturating_mul(i.into())) } @@ -129,31 +129,31 @@ impl WeightInfo for SubstrateWeight { /// Proof: Glutton Storage (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: Glutton Compute (r:1 w:0) /// Proof: Glutton Compute (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Glutton TrashData (r:1738 w:0) + /// Storage: Glutton TrashData (r:1737 w:0) /// Proof: Glutton TrashData (max_values: Some(65000), max_size: Some(1036), added: 3016, mode: MaxEncodedLen) fn on_idle_high_proof_waste() -> Weight { // Proof Size summary in bytes: - // Measured: `1955391` - // Estimated: `5242806` - // Minimum execution time: 55_398_405 nanoseconds. - Weight::from_ref_time(55_594_848_000) - .saturating_add(Weight::from_proof_size(5242806)) - .saturating_add(T::DbWeight::get().reads(1740_u64)) + // Measured: `1954313` + // Estimated: `5242760` + // Minimum execution time: 56_743_236 nanoseconds. + Weight::from_ref_time(57_088_040_000) + .saturating_add(Weight::from_proof_size(5242760)) + .saturating_add(T::DbWeight::get().reads(1739_u64)) } /// Storage: Glutton Storage (r:1 w:0) /// Proof: Glutton Storage (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: Glutton Compute (r:1 w:0) /// Proof: Glutton Compute (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Glutton TrashData (r:6 w:0) + /// Storage: Glutton TrashData (r:5 w:0) /// Proof: Glutton TrashData (max_values: Some(65000), max_size: Some(1036), added: 3016, mode: MaxEncodedLen) fn on_idle_low_proof_waste() -> Weight { // Proof Size summary in bytes: - // Measured: `11717` - // Estimated: `19094` - // Minimum execution time: 98_888_667 nanoseconds. - Weight::from_ref_time(99_157_239_000) - .saturating_add(Weight::from_proof_size(19094)) - .saturating_add(T::DbWeight::get().reads(8_u64)) + // Measured: `9671` + // Estimated: `19048` + // Minimum execution time: 100_387_042 nanoseconds. + Weight::from_ref_time(100_987_577_000) + .saturating_add(Weight::from_proof_size(19048)) + .saturating_add(T::DbWeight::get().reads(7_u64)) } /// Storage: Glutton Storage (r:1 w:0) /// Proof: Glutton Storage (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -162,10 +162,10 @@ impl WeightInfo for SubstrateWeight { fn empty_on_idle() -> Weight { // Proof Size summary in bytes: // Measured: `4` - // Estimated: `998` - // Minimum execution time: 3_967 nanoseconds. - Weight::from_ref_time(4_121_000) - .saturating_add(Weight::from_proof_size(998)) + // Estimated: `2978` + // Minimum execution time: 4_256 nanoseconds. + Weight::from_ref_time(4_447_000) + .saturating_add(Weight::from_proof_size(2978)) .saturating_add(T::DbWeight::get().reads(2_u64)) } /// Storage: Glutton Compute (r:0 w:1) @@ -174,8 +174,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_112 nanoseconds. - Weight::from_ref_time(7_484_000) + // Minimum execution time: 8_663 nanoseconds. + Weight::from_ref_time(8_864_000) .saturating_add(Weight::from_proof_size(0)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -185,8 +185,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_056 nanoseconds. - Weight::from_ref_time(7_414_000) + // Minimum execution time: 8_653 nanoseconds. + Weight::from_ref_time(8_998_000) .saturating_add(Weight::from_proof_size(0)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -202,12 +202,12 @@ impl WeightInfo for () { fn initialize_pallet_grow(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `4` - // Estimated: `499` - // Minimum execution time: 9_248 nanoseconds. - Weight::from_ref_time(9_582_000) - .saturating_add(Weight::from_proof_size(499)) - // Standard Error: 1_144 - .saturating_add(Weight::from_ref_time(1_624_225).saturating_mul(n.into())) + // Estimated: `1489` + // Minimum execution time: 10_218 nanoseconds. + Weight::from_ref_time(10_510_000) + .saturating_add(Weight::from_proof_size(1489)) + // Standard Error: 1_582 + .saturating_add(Weight::from_ref_time(1_577_660).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) @@ -220,12 +220,12 @@ impl WeightInfo for () { fn initialize_pallet_shrink(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `65` - // Estimated: `499` - // Minimum execution time: 10_210 nanoseconds. - Weight::from_ref_time(7_260_854) - .saturating_add(Weight::from_proof_size(499)) - // Standard Error: 1_459 - .saturating_add(Weight::from_ref_time(1_053_844).saturating_mul(n.into())) + // Estimated: `1489` + // Minimum execution time: 10_993 nanoseconds. + Weight::from_ref_time(11_208_000) + .saturating_add(Weight::from_proof_size(1489)) + // Standard Error: 1_386 + .saturating_add(Weight::from_ref_time(1_072_330).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) @@ -235,11 +235,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 605 nanoseconds. - Weight::from_ref_time(1_102_112) + // Minimum execution time: 740 nanoseconds. + Weight::from_ref_time(770_000) .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 28 - .saturating_add(Weight::from_ref_time(120_597).saturating_mul(i.into())) + // Standard Error: 24 + .saturating_add(Weight::from_ref_time(96_434).saturating_mul(i.into())) } /// Storage: Glutton TrashData (r:5000 w:0) /// Proof: Glutton TrashData (max_values: Some(65000), max_size: Some(1036), added: 3016, mode: MaxEncodedLen) @@ -247,12 +247,12 @@ impl WeightInfo for () { fn waste_proof_size_some(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `119036 + i * (1053 ±0)` - // Estimated: `0 + i * (3016 ±0)` - // Minimum execution time: 464 nanoseconds. - Weight::from_ref_time(552_000) - .saturating_add(Weight::from_proof_size(0)) - // Standard Error: 1_962 - .saturating_add(Weight::from_ref_time(5_780_304).saturating_mul(i.into())) + // Estimated: `990 + i * (3016 ±0)` + // Minimum execution time: 630 nanoseconds. + Weight::from_ref_time(712_000) + .saturating_add(Weight::from_proof_size(990)) + // Standard Error: 4_326 + .saturating_add(Weight::from_ref_time(5_500_880).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(i.into()))) .saturating_add(Weight::from_proof_size(3016).saturating_mul(i.into())) } @@ -260,31 +260,31 @@ impl WeightInfo for () { /// Proof: Glutton Storage (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: Glutton Compute (r:1 w:0) /// Proof: Glutton Compute (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Glutton TrashData (r:1738 w:0) + /// Storage: Glutton TrashData (r:1737 w:0) /// Proof: Glutton TrashData (max_values: Some(65000), max_size: Some(1036), added: 3016, mode: MaxEncodedLen) fn on_idle_high_proof_waste() -> Weight { // Proof Size summary in bytes: - // Measured: `1955391` - // Estimated: `5242806` - // Minimum execution time: 55_398_405 nanoseconds. - Weight::from_ref_time(55_594_848_000) - .saturating_add(Weight::from_proof_size(5242806)) - .saturating_add(RocksDbWeight::get().reads(1740_u64)) + // Measured: `1954313` + // Estimated: `5242760` + // Minimum execution time: 56_743_236 nanoseconds. + Weight::from_ref_time(57_088_040_000) + .saturating_add(Weight::from_proof_size(5242760)) + .saturating_add(RocksDbWeight::get().reads(1739_u64)) } /// Storage: Glutton Storage (r:1 w:0) /// Proof: Glutton Storage (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: Glutton Compute (r:1 w:0) /// Proof: Glutton Compute (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Glutton TrashData (r:6 w:0) + /// Storage: Glutton TrashData (r:5 w:0) /// Proof: Glutton TrashData (max_values: Some(65000), max_size: Some(1036), added: 3016, mode: MaxEncodedLen) fn on_idle_low_proof_waste() -> Weight { // Proof Size summary in bytes: - // Measured: `11717` - // Estimated: `19094` - // Minimum execution time: 98_888_667 nanoseconds. - Weight::from_ref_time(99_157_239_000) - .saturating_add(Weight::from_proof_size(19094)) - .saturating_add(RocksDbWeight::get().reads(8_u64)) + // Measured: `9671` + // Estimated: `19048` + // Minimum execution time: 100_387_042 nanoseconds. + Weight::from_ref_time(100_987_577_000) + .saturating_add(Weight::from_proof_size(19048)) + .saturating_add(RocksDbWeight::get().reads(7_u64)) } /// Storage: Glutton Storage (r:1 w:0) /// Proof: Glutton Storage (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -293,10 +293,10 @@ impl WeightInfo for () { fn empty_on_idle() -> Weight { // Proof Size summary in bytes: // Measured: `4` - // Estimated: `998` - // Minimum execution time: 3_967 nanoseconds. - Weight::from_ref_time(4_121_000) - .saturating_add(Weight::from_proof_size(998)) + // Estimated: `2978` + // Minimum execution time: 4_256 nanoseconds. + Weight::from_ref_time(4_447_000) + .saturating_add(Weight::from_proof_size(2978)) .saturating_add(RocksDbWeight::get().reads(2_u64)) } /// Storage: Glutton Compute (r:0 w:1) @@ -305,8 +305,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_112 nanoseconds. - Weight::from_ref_time(7_484_000) + // Minimum execution time: 8_663 nanoseconds. + Weight::from_ref_time(8_864_000) .saturating_add(Weight::from_proof_size(0)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -316,8 +316,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_056 nanoseconds. - Weight::from_ref_time(7_414_000) + // Minimum execution time: 8_653 nanoseconds. + Weight::from_ref_time(8_998_000) .saturating_add(Weight::from_proof_size(0)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/frame/message-queue/src/weights.rs b/frame/message-queue/src/weights.rs index b48cf811a17ef..3421c2f2f59af 100644 --- a/frame/message-queue/src/weights.rs +++ b/frame/message-queue/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_message_queue //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-02-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -70,11 +70,11 @@ impl WeightInfo for SubstrateWeight { /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) fn ready_ring_knit() -> Weight { // Proof Size summary in bytes: - // Measured: `829` - // Estimated: `5547` - // Minimum execution time: 15_241 nanoseconds. - Weight::from_ref_time(15_603_000) - .saturating_add(Weight::from_proof_size(5547)) + // Measured: `295` + // Estimated: `7527` + // Minimum execution time: 12_538 nanoseconds. + Weight::from_ref_time(12_799_000) + .saturating_add(Weight::from_proof_size(7527)) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -84,11 +84,11 @@ impl WeightInfo for SubstrateWeight { /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn ready_ring_unknit() -> Weight { // Proof Size summary in bytes: - // Measured: `829` - // Estimated: `5547` - // Minimum execution time: 14_652 nanoseconds. - Weight::from_ref_time(14_983_000) - .saturating_add(Weight::from_proof_size(5547)) + // Measured: `295` + // Estimated: `7527` + // Minimum execution time: 11_727 nanoseconds. + Weight::from_ref_time(12_177_000) + .saturating_add(Weight::from_proof_size(7527)) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -96,11 +96,11 @@ impl WeightInfo for SubstrateWeight { /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) fn service_queue_base() -> Weight { // Proof Size summary in bytes: - // Measured: `576` - // Estimated: `2524` - // Minimum execution time: 5_750 nanoseconds. - Weight::from_ref_time(6_003_000) - .saturating_add(Weight::from_proof_size(2524)) + // Measured: `42` + // Estimated: `3514` + // Minimum execution time: 4_983 nanoseconds. + Weight::from_ref_time(5_174_000) + .saturating_add(Weight::from_proof_size(3514)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -108,11 +108,11 @@ impl WeightInfo for SubstrateWeight { /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65584), added: 68059, mode: MaxEncodedLen) fn service_page_base_completion() -> Weight { // Proof Size summary in bytes: - // Measured: `647` - // Estimated: `68059` - // Minimum execution time: 8_257 nanoseconds. - Weight::from_ref_time(8_506_000) - .saturating_add(Weight::from_proof_size(68059)) + // Measured: `113` + // Estimated: `69049` + // Minimum execution time: 6_299 nanoseconds. + Weight::from_ref_time(6_670_000) + .saturating_add(Weight::from_proof_size(69049)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -120,20 +120,20 @@ impl WeightInfo for SubstrateWeight { /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65584), added: 68059, mode: MaxEncodedLen) fn service_page_base_no_completion() -> Weight { // Proof Size summary in bytes: - // Measured: `647` - // Estimated: `68059` - // Minimum execution time: 8_422 nanoseconds. - Weight::from_ref_time(8_589_000) - .saturating_add(Weight::from_proof_size(68059)) + // Measured: `113` + // Estimated: `69049` + // Minimum execution time: 6_762 nanoseconds. + Weight::from_ref_time(7_059_000) + .saturating_add(Weight::from_proof_size(69049)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } fn service_page_item() -> Weight { // Proof Size summary in bytes: - // Measured: `972` + // Measured: `0` // Estimated: `0` - // Minimum execution time: 81_929 nanoseconds. - Weight::from_ref_time(82_375_000) + // Minimum execution time: 72_681 nanoseconds. + Weight::from_ref_time(73_147_000) .saturating_add(Weight::from_proof_size(0)) } /// Storage: MessageQueue ServiceHead (r:1 w:1) @@ -142,11 +142,11 @@ impl WeightInfo for SubstrateWeight { /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) fn bump_service_head() -> Weight { // Proof Size summary in bytes: - // Measured: `706` - // Estimated: `3023` - // Minimum execution time: 8_992 nanoseconds. - Weight::from_ref_time(9_200_000) - .saturating_add(Weight::from_proof_size(3023)) + // Measured: `172` + // Estimated: `5003` + // Minimum execution time: 7_066 nanoseconds. + Weight::from_ref_time(7_214_000) + .saturating_add(Weight::from_proof_size(5003)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -156,11 +156,11 @@ impl WeightInfo for SubstrateWeight { /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65584), added: 68059, mode: MaxEncodedLen) fn reap_page() -> Weight { // Proof Size summary in bytes: - // Measured: `66825` - // Estimated: `70583` - // Minimum execution time: 68_292 nanoseconds. - Weight::from_ref_time(69_108_000) - .saturating_add(Weight::from_proof_size(70583)) + // Measured: `65742` + // Estimated: `72563` + // Minimum execution time: 57_778 nanoseconds. + Weight::from_ref_time(58_778_000) + .saturating_add(Weight::from_proof_size(72563)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -170,11 +170,11 @@ impl WeightInfo for SubstrateWeight { /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65584), added: 68059, mode: MaxEncodedLen) fn execute_overweight_page_removed() -> Weight { // Proof Size summary in bytes: - // Measured: `66825` - // Estimated: `70583` - // Minimum execution time: 83_855 nanoseconds. - Weight::from_ref_time(84_946_000) - .saturating_add(Weight::from_proof_size(70583)) + // Measured: `65742` + // Estimated: `72563` + // Minimum execution time: 72_144 nanoseconds. + Weight::from_ref_time(72_942_000) + .saturating_add(Weight::from_proof_size(72563)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -184,11 +184,11 @@ impl WeightInfo for SubstrateWeight { /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65584), added: 68059, mode: MaxEncodedLen) fn execute_overweight_page_updated() -> Weight { // Proof Size summary in bytes: - // Measured: `66825` - // Estimated: `70583` - // Minimum execution time: 96_997 nanoseconds. - Weight::from_ref_time(98_668_000) - .saturating_add(Weight::from_proof_size(70583)) + // Measured: `65742` + // Estimated: `72563` + // Minimum execution time: 84_890 nanoseconds. + Weight::from_ref_time(86_073_000) + .saturating_add(Weight::from_proof_size(72563)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -202,11 +202,11 @@ impl WeightInfo for () { /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) fn ready_ring_knit() -> Weight { // Proof Size summary in bytes: - // Measured: `829` - // Estimated: `5547` - // Minimum execution time: 15_241 nanoseconds. - Weight::from_ref_time(15_603_000) - .saturating_add(Weight::from_proof_size(5547)) + // Measured: `295` + // Estimated: `7527` + // Minimum execution time: 12_538 nanoseconds. + Weight::from_ref_time(12_799_000) + .saturating_add(Weight::from_proof_size(7527)) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -216,11 +216,11 @@ impl WeightInfo for () { /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn ready_ring_unknit() -> Weight { // Proof Size summary in bytes: - // Measured: `829` - // Estimated: `5547` - // Minimum execution time: 14_652 nanoseconds. - Weight::from_ref_time(14_983_000) - .saturating_add(Weight::from_proof_size(5547)) + // Measured: `295` + // Estimated: `7527` + // Minimum execution time: 11_727 nanoseconds. + Weight::from_ref_time(12_177_000) + .saturating_add(Weight::from_proof_size(7527)) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -228,11 +228,11 @@ impl WeightInfo for () { /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) fn service_queue_base() -> Weight { // Proof Size summary in bytes: - // Measured: `576` - // Estimated: `2524` - // Minimum execution time: 5_750 nanoseconds. - Weight::from_ref_time(6_003_000) - .saturating_add(Weight::from_proof_size(2524)) + // Measured: `42` + // Estimated: `3514` + // Minimum execution time: 4_983 nanoseconds. + Weight::from_ref_time(5_174_000) + .saturating_add(Weight::from_proof_size(3514)) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -240,11 +240,11 @@ impl WeightInfo for () { /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65584), added: 68059, mode: MaxEncodedLen) fn service_page_base_completion() -> Weight { // Proof Size summary in bytes: - // Measured: `647` - // Estimated: `68059` - // Minimum execution time: 8_257 nanoseconds. - Weight::from_ref_time(8_506_000) - .saturating_add(Weight::from_proof_size(68059)) + // Measured: `113` + // Estimated: `69049` + // Minimum execution time: 6_299 nanoseconds. + Weight::from_ref_time(6_670_000) + .saturating_add(Weight::from_proof_size(69049)) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -252,20 +252,20 @@ impl WeightInfo for () { /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65584), added: 68059, mode: MaxEncodedLen) fn service_page_base_no_completion() -> Weight { // Proof Size summary in bytes: - // Measured: `647` - // Estimated: `68059` - // Minimum execution time: 8_422 nanoseconds. - Weight::from_ref_time(8_589_000) - .saturating_add(Weight::from_proof_size(68059)) + // Measured: `113` + // Estimated: `69049` + // Minimum execution time: 6_762 nanoseconds. + Weight::from_ref_time(7_059_000) + .saturating_add(Weight::from_proof_size(69049)) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } fn service_page_item() -> Weight { // Proof Size summary in bytes: - // Measured: `972` + // Measured: `0` // Estimated: `0` - // Minimum execution time: 81_929 nanoseconds. - Weight::from_ref_time(82_375_000) + // Minimum execution time: 72_681 nanoseconds. + Weight::from_ref_time(73_147_000) .saturating_add(Weight::from_proof_size(0)) } /// Storage: MessageQueue ServiceHead (r:1 w:1) @@ -274,11 +274,11 @@ impl WeightInfo for () { /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) fn bump_service_head() -> Weight { // Proof Size summary in bytes: - // Measured: `706` - // Estimated: `3023` - // Minimum execution time: 8_992 nanoseconds. - Weight::from_ref_time(9_200_000) - .saturating_add(Weight::from_proof_size(3023)) + // Measured: `172` + // Estimated: `5003` + // Minimum execution time: 7_066 nanoseconds. + Weight::from_ref_time(7_214_000) + .saturating_add(Weight::from_proof_size(5003)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -288,11 +288,11 @@ impl WeightInfo for () { /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65584), added: 68059, mode: MaxEncodedLen) fn reap_page() -> Weight { // Proof Size summary in bytes: - // Measured: `66825` - // Estimated: `70583` - // Minimum execution time: 68_292 nanoseconds. - Weight::from_ref_time(69_108_000) - .saturating_add(Weight::from_proof_size(70583)) + // Measured: `65742` + // Estimated: `72563` + // Minimum execution time: 57_778 nanoseconds. + Weight::from_ref_time(58_778_000) + .saturating_add(Weight::from_proof_size(72563)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -302,11 +302,11 @@ impl WeightInfo for () { /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65584), added: 68059, mode: MaxEncodedLen) fn execute_overweight_page_removed() -> Weight { // Proof Size summary in bytes: - // Measured: `66825` - // Estimated: `70583` - // Minimum execution time: 83_855 nanoseconds. - Weight::from_ref_time(84_946_000) - .saturating_add(Weight::from_proof_size(70583)) + // Measured: `65742` + // Estimated: `72563` + // Minimum execution time: 72_144 nanoseconds. + Weight::from_ref_time(72_942_000) + .saturating_add(Weight::from_proof_size(72563)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -316,11 +316,11 @@ impl WeightInfo for () { /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65584), added: 68059, mode: MaxEncodedLen) fn execute_overweight_page_updated() -> Weight { // Proof Size summary in bytes: - // Measured: `66825` - // Estimated: `70583` - // Minimum execution time: 96_997 nanoseconds. - Weight::from_ref_time(98_668_000) - .saturating_add(Weight::from_proof_size(70583)) + // Measured: `65742` + // Estimated: `72563` + // Minimum execution time: 84_890 nanoseconds. + Weight::from_ref_time(86_073_000) + .saturating_add(Weight::from_proof_size(72563)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } diff --git a/frame/support/procedural/src/benchmark.rs b/frame/support/procedural/src/benchmark.rs index 1aca2f87b1d1d..4f9994b6cd073 100644 --- a/frame/support/procedural/src/benchmark.rs +++ b/frame/support/procedural/src/benchmark.rs @@ -567,7 +567,12 @@ pub fn benchmarks( #support::storage::transactional::TRANSACTION_LEVEL_KEY.into(), ); whitelist.push(transactional_layer_key); - #krate::benchmarking::set_whitelist(whitelist); + // Whitelist the `:extrinsic_index`. + let extrinsic_index = #krate::TrackedStorageKey::new( + #krate::well_known_keys::EXTRINSIC_INDEX.into() + ); + whitelist.push(extrinsic_index); + #krate::benchmarking::set_whitelist(whitelist.clone()); let mut results: #krate::Vec<#krate::BenchmarkResult> = #krate::Vec::new(); // Always do at least one internal repeat... @@ -590,6 +595,12 @@ pub fn benchmarks( // This will enable worst case scenario for reading from the database. #krate::benchmarking::commit_db(); + // Access all whitelisted keys to get them into the proof recorder since the + // recorder does now have a whitelist. + for key in &whitelist { + #krate::frame_support::storage::unhashed::get_raw(&key.key); + } + // Reset the read/write counter so we don't count operations in the setup process. #krate::benchmarking::reset_read_write_count(); diff --git a/utils/frame/benchmarking-cli/src/pallet/mod.rs b/utils/frame/benchmarking-cli/src/pallet/mod.rs index 9ae9846745918..f214569051d45 100644 --- a/utils/frame/benchmarking-cli/src/pallet/mod.rs +++ b/utils/frame/benchmarking-cli/src/pallet/mod.rs @@ -187,7 +187,7 @@ pub struct PalletCmd { /// Each layer will result in an additional 495 bytes PoV per distinct top-level access. /// Therefore multiple `StorageMap` accesses only suffer from this increase once. The exact /// number of storage items depends on the runtime and the deployed pallets. - #[clap(long, default_value = "0")] + #[clap(long, default_value = "2")] pub additional_trie_layers: u8, /// A path to a `.json` file with existing benchmark results generated with `--json` or From b7e0518966b145f22c16137da5c9796fcdb43b73 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Tue, 28 Feb 2023 15:56:22 +0100 Subject: [PATCH 448/715] Move BEEFY code to consensus (#13484) * Move beefy primitives to consensus dir * Move beefy gadget to client consensus folder * Rename beefy crates --- Cargo.lock | 174 +++++++++--------- Cargo.toml | 6 +- client/beefy/Cargo.toml | 49 ----- client/consensus/beefy/Cargo.toml | 49 +++++ client/{ => consensus}/beefy/README.md | 0 client/{ => consensus}/beefy/rpc/Cargo.toml | 18 +- client/{ => consensus}/beefy/rpc/src/lib.rs | 12 +- .../beefy/rpc/src/notification.rs | 4 +- .../{ => consensus}/beefy/src/aux_schema.rs | 0 .../beefy/src/communication/gossip.rs | 4 +- .../beefy/src/communication/mod.rs | 0 .../beefy/src/communication/notification.rs | 0 .../beefy/src/communication/peers.rs | 0 .../incoming_requests_handler.rs | 2 +- .../src/communication/request_response/mod.rs | 0 .../outgoing_requests_engine.rs | 2 +- client/{ => consensus}/beefy/src/error.rs | 0 client/{ => consensus}/beefy/src/import.rs | 2 +- .../beefy/src/justification.rs | 10 +- client/{ => consensus}/beefy/src/keystore.rs | 8 +- client/{ => consensus}/beefy/src/lib.rs | 8 +- client/{ => consensus}/beefy/src/metrics.rs | 0 client/{ => consensus}/beefy/src/round.rs | 8 +- client/{ => consensus}/beefy/src/tests.rs | 18 +- client/{ => consensus}/beefy/src/worker.rs | 20 +- client/merkle-mountain-range/Cargo.toml | 4 +- client/merkle-mountain-range/src/lib.rs | 2 +- .../merkle-mountain-range/src/offchain_mmr.rs | 2 +- frame/beefy-mmr/Cargo.toml | 4 +- frame/beefy-mmr/src/lib.rs | 18 +- frame/beefy-mmr/src/mock.rs | 6 +- frame/beefy-mmr/src/tests.rs | 4 +- frame/beefy/Cargo.toml | 4 +- frame/beefy/src/equivocation.rs | 4 +- frame/beefy/src/lib.rs | 12 +- frame/beefy/src/mock.rs | 2 +- frame/beefy/src/tests.rs | 20 +- primitives/{ => consensus}/beefy/Cargo.toml | 18 +- .../{ => consensus}/beefy/src/commitment.rs | 0 primitives/{ => consensus}/beefy/src/lib.rs | 0 primitives/{ => consensus}/beefy/src/mmr.rs | 0 .../{ => consensus}/beefy/src/payload.rs | 0 .../{ => consensus}/beefy/src/test_utils.rs | 0 .../{ => consensus}/beefy/src/witness.rs | 0 .../beefy/test-res/large-raw-commitment | Bin test-utils/runtime/Cargo.toml | 4 +- test-utils/runtime/src/lib.rs | 24 +-- 47 files changed, 260 insertions(+), 262 deletions(-) delete mode 100644 client/beefy/Cargo.toml create mode 100644 client/consensus/beefy/Cargo.toml rename client/{ => consensus}/beefy/README.md (100%) rename client/{ => consensus}/beefy/rpc/Cargo.toml (60%) rename client/{ => consensus}/beefy/rpc/src/lib.rs (97%) rename client/{ => consensus}/beefy/rpc/src/notification.rs (90%) rename client/{ => consensus}/beefy/src/aux_schema.rs (100%) rename client/{ => consensus}/beefy/src/communication/gossip.rs (99%) rename client/{ => consensus}/beefy/src/communication/mod.rs (100%) rename client/{ => consensus}/beefy/src/communication/notification.rs (100%) rename client/{ => consensus}/beefy/src/communication/peers.rs (100%) rename client/{ => consensus}/beefy/src/communication/request_response/incoming_requests_handler.rs (99%) rename client/{ => consensus}/beefy/src/communication/request_response/mod.rs (100%) rename client/{ => consensus}/beefy/src/communication/request_response/outgoing_requests_engine.rs (99%) rename client/{ => consensus}/beefy/src/error.rs (100%) rename client/{ => consensus}/beefy/src/import.rs (99%) rename client/{ => consensus}/beefy/src/justification.rs (98%) rename client/{ => consensus}/beefy/src/keystore.rs (97%) rename client/{ => consensus}/beefy/src/lib.rs (99%) rename client/{ => consensus}/beefy/src/metrics.rs (100%) rename client/{ => consensus}/beefy/src/round.rs (99%) rename client/{ => consensus}/beefy/src/tests.rs (99%) rename client/{ => consensus}/beefy/src/worker.rs (99%) rename primitives/{ => consensus}/beefy/Cargo.toml (84%) rename primitives/{ => consensus}/beefy/src/commitment.rs (100%) rename primitives/{ => consensus}/beefy/src/lib.rs (100%) rename primitives/{ => consensus}/beefy/src/mmr.rs (100%) rename primitives/{ => consensus}/beefy/src/payload.rs (100%) rename primitives/{ => consensus}/beefy/src/test_utils.rs (100%) rename primitives/{ => consensus}/beefy/src/witness.rs (100%) rename primitives/{ => consensus}/beefy/test-res/large-raw-commitment (100%) diff --git a/Cargo.lock b/Cargo.lock index 91ae9ab422c3e..a29213b45b545 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -493,69 +493,6 @@ dependencies = [ "serde", ] -[[package]] -name = "beefy-gadget" -version = "4.0.0-dev" -dependencies = [ - "array-bytes", - "async-trait", - "fnv", - "futures", - "log", - "parity-scale-codec", - "parking_lot 0.12.1", - "sc-block-builder", - "sc-client-api", - "sc-consensus", - "sc-keystore", - "sc-network", - "sc-network-common", - "sc-network-gossip", - "sc-network-test", - "sc-utils", - "serde", - "sp-api", - "sp-application-crypto", - "sp-arithmetic", - "sp-beefy", - "sp-blockchain", - "sp-consensus", - "sp-consensus-grandpa", - "sp-core", - "sp-keyring", - "sp-keystore", - "sp-mmr-primitives", - "sp-runtime", - "sp-tracing", - "substrate-prometheus-endpoint", - "substrate-test-runtime-client", - "tempfile", - "thiserror", - "tokio", - "wasm-timer", -] - -[[package]] -name = "beefy-gadget-rpc" -version = "4.0.0-dev" -dependencies = [ - "beefy-gadget", - "futures", - "jsonrpsee", - "log", - "parity-scale-codec", - "parking_lot 0.12.1", - "sc-rpc", - "serde", - "serde_json", - "sp-beefy", - "sp-core", - "sp-runtime", - "substrate-test-runtime-client", - "thiserror", - "tokio", -] - [[package]] name = "binary-merkle-tree" version = "4.0.0-dev" @@ -4492,9 +4429,9 @@ dependencies = [ "sc-client-api", "sc-offchain", "sp-api", - "sp-beefy", "sp-blockchain", "sp-consensus", + "sp-consensus-beefy", "sp-core", "sp-mmr-primitives", "sp-runtime", @@ -5555,7 +5492,7 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", - "sp-beefy", + "sp-consensus-beefy", "sp-core", "sp-io", "sp-runtime", @@ -5580,7 +5517,7 @@ dependencies = [ "scale-info", "serde", "sp-api", - "sp-beefy", + "sp-consensus-beefy", "sp-core", "sp-io", "sp-runtime", @@ -8333,6 +8270,69 @@ dependencies = [ "tokio", ] +[[package]] +name = "sc-consensus-beefy" +version = "4.0.0-dev" +dependencies = [ + "array-bytes", + "async-trait", + "fnv", + "futures", + "log", + "parity-scale-codec", + "parking_lot 0.12.1", + "sc-block-builder", + "sc-client-api", + "sc-consensus", + "sc-keystore", + "sc-network", + "sc-network-common", + "sc-network-gossip", + "sc-network-test", + "sc-utils", + "serde", + "sp-api", + "sp-application-crypto", + "sp-arithmetic", + "sp-blockchain", + "sp-consensus", + "sp-consensus-beefy", + "sp-consensus-grandpa", + "sp-core", + "sp-keyring", + "sp-keystore", + "sp-mmr-primitives", + "sp-runtime", + "sp-tracing", + "substrate-prometheus-endpoint", + "substrate-test-runtime-client", + "tempfile", + "thiserror", + "tokio", + "wasm-timer", +] + +[[package]] +name = "sc-consensus-beefy-rpc" +version = "4.0.0-dev" +dependencies = [ + "futures", + "jsonrpsee", + "log", + "parity-scale-codec", + "parking_lot 0.12.1", + "sc-consensus-beefy", + "sc-rpc", + "serde", + "serde_json", + "sp-consensus-beefy", + "sp-core", + "sp-runtime", + "substrate-test-runtime-client", + "thiserror", + "tokio", +] + [[package]] name = "sc-consensus-epochs" version = "0.10.0-dev" @@ -9829,26 +9829,6 @@ dependencies = [ "sp-std", ] -[[package]] -name = "sp-beefy" -version = "4.0.0-dev" -dependencies = [ - "array-bytes", - "lazy_static", - "parity-scale-codec", - "scale-info", - "serde", - "sp-api", - "sp-application-crypto", - "sp-core", - "sp-io", - "sp-keystore", - "sp-mmr-primitives", - "sp-runtime", - "sp-std", - "strum", -] - [[package]] name = "sp-block-builder" version = "4.0.0-dev" @@ -9934,6 +9914,26 @@ dependencies = [ "sp-timestamp", ] +[[package]] +name = "sp-consensus-beefy" +version = "4.0.0-dev" +dependencies = [ + "array-bytes", + "lazy_static", + "parity-scale-codec", + "scale-info", + "serde", + "sp-api", + "sp-application-crypto", + "sp-core", + "sp-io", + "sp-keystore", + "sp-mmr-primitives", + "sp-runtime", + "sp-std", + "strum", +] + [[package]] name = "sp-consensus-grandpa" version = "4.0.0-dev" @@ -10837,11 +10837,11 @@ dependencies = [ "serde", "sp-api", "sp-application-crypto", - "sp-beefy", "sp-block-builder", "sp-consensus", "sp-consensus-aura", "sp-consensus-babe", + "sp-consensus-beefy", "sp-consensus-grandpa", "sp-core", "sp-externalities", diff --git a/Cargo.toml b/Cargo.toml index 88c9c1998f415..af2d8f9066fa1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,8 +18,6 @@ members = [ "client/api", "client/authority-discovery", "client/basic-authorship", - "client/beefy", - "client/beefy/rpc", "client/block-builder", "client/chain-spec", "client/chain-spec/derive", @@ -27,6 +25,8 @@ members = [ "client/consensus/aura", "client/consensus/babe", "client/consensus/babe/rpc", + "client/consensus/beefy", + "client/consensus/beefy/rpc", "client/consensus/common", "client/consensus/epochs", "client/consensus/grandpa", @@ -178,11 +178,11 @@ members = [ "primitives/arithmetic", "primitives/arithmetic/fuzzer", "primitives/authority-discovery", - "primitives/beefy", "primitives/block-builder", "primitives/blockchain", "primitives/consensus/aura", "primitives/consensus/babe", + "primitives/consensus/beefy", "primitives/consensus/common", "primitives/consensus/grandpa", "primitives/consensus/pow", diff --git a/client/beefy/Cargo.toml b/client/beefy/Cargo.toml deleted file mode 100644 index eb616823680aa..0000000000000 --- a/client/beefy/Cargo.toml +++ /dev/null @@ -1,49 +0,0 @@ -[package] -name = "beefy-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 = "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.2.2", features = ["derive"] } -fnv = "1.0.6" -futures = "0.3" -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", package = "sp-beefy" } -prometheus = { 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-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" } -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 = "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 = "7.0.0", path = "../../primitives/runtime" } - -[dev-dependencies] -serde = "1.0.136" -tempfile = "3.1.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-consensus-grandpa = { version = "4.0.0-dev", path = "../../primitives/consensus/grandpa" } -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/consensus/beefy/Cargo.toml b/client/consensus/beefy/Cargo.toml new file mode 100644 index 0000000000000..d88c07df2612f --- /dev/null +++ b/client/consensus/beefy/Cargo.toml @@ -0,0 +1,49 @@ +[package] +name = "sc-consensus-beefy" +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" +homepage = "https://substrate.io" + +[dependencies] +array-bytes = "4.1" +async-trait = "0.1.57" +codec = { package = "parity-scale-codec", version = "3.2.2", features = ["derive"] } +fnv = "1.0.6" +futures = "0.3" +log = "0.4" +parking_lot = "0.12.1" +thiserror = "1.0" +wasm-timer = "0.2.5" +prometheus = { 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-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" } +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-consensus-beefy = { version = "4.0.0-dev", path = "../../../primitives/consensus/beefy" } +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 = "7.0.0", path = "../../../primitives/runtime" } + +[dev-dependencies] +serde = "1.0.136" +tempfile = "3.1.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-consensus-grandpa = { version = "4.0.0-dev", path = "../../../primitives/consensus/grandpa" } +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/beefy/README.md b/client/consensus/beefy/README.md similarity index 100% rename from client/beefy/README.md rename to client/consensus/beefy/README.md diff --git a/client/beefy/rpc/Cargo.toml b/client/consensus/beefy/rpc/Cargo.toml similarity index 60% rename from client/beefy/rpc/Cargo.toml rename to client/consensus/beefy/rpc/Cargo.toml index ab3e6921f3cfe..d6dfa8731a3be 100644 --- a/client/beefy/rpc/Cargo.toml +++ b/client/consensus/beefy/rpc/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "beefy-gadget-rpc" +name = "sc-consensus-beefy-rpc" version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2021" @@ -16,16 +16,14 @@ log = "0.4" 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", package = "sp-beefy" } -sc-rpc = { version = "4.0.0-dev", path = "../../rpc" } -sp-core = { version = "7.0.0", path = "../../../primitives/core" } -sp-runtime = { version = "7.0.0", path = "../../../primitives/runtime" } +sc-consensus-beefy = { version = "4.0.0-dev", path = "../" } +sp-consensus-beefy = { version = "4.0.0-dev", path = "../../../../primitives/consensus/beefy" } +sc-rpc = { version = "4.0.0-dev", path = "../../../rpc" } +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" -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" } +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.22.0", features = ["macros"] } diff --git a/client/beefy/rpc/src/lib.rs b/client/consensus/beefy/rpc/src/lib.rs similarity index 97% rename from client/beefy/rpc/src/lib.rs rename to client/consensus/beefy/rpc/src/lib.rs index 0a7a4de14cbcc..f5c0ff32627d5 100644 --- a/client/beefy/rpc/src/lib.rs +++ b/client/consensus/beefy/rpc/src/lib.rs @@ -35,7 +35,7 @@ use jsonrpsee::{ }; use log::warn; -use beefy_gadget::communication::notification::{ +use sc_consensus_beefy::communication::notification::{ BeefyBestBlockStream, BeefyVersionedFinalityProofStream, }; @@ -166,13 +166,13 @@ where mod tests { use super::*; - use beefy_gadget::{ + use codec::{Decode, Encode}; + use jsonrpsee::{types::EmptyServerParams as EmptyParams, RpcModule}; + use sc_consensus_beefy::{ communication::notification::BeefyVersionedFinalityProofSender, justification::BeefyVersionedFinalityProof, }; - use beefy_primitives::{known_payloads, Payload, SignedCommitment}; - use codec::{Decode, Encode}; - use jsonrpsee::{types::EmptyServerParams as EmptyParams, RpcModule}; + use sp_consensus_beefy::{known_payloads, Payload, SignedCommitment}; use sp_runtime::traits::{BlakeTwo256, Hash}; use substrate_test_runtime_client::runtime::Block; @@ -269,7 +269,7 @@ mod tests { let payload = Payload::from_single_entry(known_payloads::MMR_ROOT_ID, "Hello World!".encode()); BeefyVersionedFinalityProof::::V1(SignedCommitment { - commitment: beefy_primitives::Commitment { + commitment: sp_consensus_beefy::Commitment { payload, block_number: 5, validator_set_id: 0, diff --git a/client/beefy/rpc/src/notification.rs b/client/consensus/beefy/rpc/src/notification.rs similarity index 90% rename from client/beefy/rpc/src/notification.rs rename to client/consensus/beefy/rpc/src/notification.rs index 286385187c342..690c511b999ac 100644 --- a/client/beefy/rpc/src/notification.rs +++ b/client/consensus/beefy/rpc/src/notification.rs @@ -23,13 +23,13 @@ use sp_runtime::traits::Block as BlockT; /// 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::VersionedFinalityProof`. +/// `sp_consensus_beefy::VersionedFinalityProof`. #[derive(Clone, Serialize, Deserialize)] pub struct EncodedVersionedFinalityProof(sp_core::Bytes); impl EncodedVersionedFinalityProof { pub fn new( - finality_proof: beefy_gadget::justification::BeefyVersionedFinalityProof, + finality_proof: sc_consensus_beefy::justification::BeefyVersionedFinalityProof, ) -> Self where Block: BlockT, diff --git a/client/beefy/src/aux_schema.rs b/client/consensus/beefy/src/aux_schema.rs similarity index 100% rename from client/beefy/src/aux_schema.rs rename to client/consensus/beefy/src/aux_schema.rs diff --git a/client/beefy/src/communication/gossip.rs b/client/consensus/beefy/src/communication/gossip.rs similarity index 99% rename from client/beefy/src/communication/gossip.rs rename to client/consensus/beefy/src/communication/gossip.rs index a1fb6fa26e5d4..219203ee4e173 100644 --- a/client/beefy/src/communication/gossip.rs +++ b/client/consensus/beefy/src/communication/gossip.rs @@ -29,7 +29,7 @@ use parking_lot::{Mutex, RwLock}; use wasm_timer::Instant; use crate::{communication::peers::KnownPeers, keystore::BeefyKeystore, LOG_TARGET}; -use beefy_primitives::{ +use sp_consensus_beefy::{ crypto::{Public, Signature}, VoteMessage, }; @@ -243,7 +243,7 @@ mod tests { use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; use crate::keystore::BeefyKeystore; - use beefy_primitives::{ + use sp_consensus_beefy::{ crypto::Signature, known_payloads, Commitment, Keyring, MmrRootHash, Payload, VoteMessage, KEY_TYPE, }; diff --git a/client/beefy/src/communication/mod.rs b/client/consensus/beefy/src/communication/mod.rs similarity index 100% rename from client/beefy/src/communication/mod.rs rename to client/consensus/beefy/src/communication/mod.rs diff --git a/client/beefy/src/communication/notification.rs b/client/consensus/beefy/src/communication/notification.rs similarity index 100% rename from client/beefy/src/communication/notification.rs rename to client/consensus/beefy/src/communication/notification.rs diff --git a/client/beefy/src/communication/peers.rs b/client/consensus/beefy/src/communication/peers.rs similarity index 100% rename from client/beefy/src/communication/peers.rs rename to client/consensus/beefy/src/communication/peers.rs diff --git a/client/beefy/src/communication/request_response/incoming_requests_handler.rs b/client/consensus/beefy/src/communication/request_response/incoming_requests_handler.rs similarity index 99% rename from client/beefy/src/communication/request_response/incoming_requests_handler.rs rename to client/consensus/beefy/src/communication/request_response/incoming_requests_handler.rs index 3266f6dba3989..ab6c21a187c95 100644 --- a/client/beefy/src/communication/request_response/incoming_requests_handler.rs +++ b/client/consensus/beefy/src/communication/request_response/incoming_requests_handler.rs @@ -16,7 +16,6 @@ //! 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}, @@ -26,6 +25,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_consensus_beefy::BEEFY_ENGINE_ID; use sp_runtime::traits::Block; use std::{marker::PhantomData, sync::Arc}; diff --git a/client/beefy/src/communication/request_response/mod.rs b/client/consensus/beefy/src/communication/request_response/mod.rs similarity index 100% rename from client/beefy/src/communication/request_response/mod.rs rename to client/consensus/beefy/src/communication/request_response/mod.rs diff --git a/client/beefy/src/communication/request_response/outgoing_requests_engine.rs b/client/consensus/beefy/src/communication/request_response/outgoing_requests_engine.rs similarity index 99% rename from client/beefy/src/communication/request_response/outgoing_requests_engine.rs rename to client/consensus/beefy/src/communication/request_response/outgoing_requests_engine.rs index 0f4f07835ca82..7450d4b3239f1 100644 --- a/client/beefy/src/communication/request_response/outgoing_requests_engine.rs +++ b/client/consensus/beefy/src/communication/request_response/outgoing_requests_engine.rs @@ -18,7 +18,6 @@ //! Generating request logic for request/response protocol for syncing BEEFY justifications. -use beefy_primitives::{crypto::AuthorityId, ValidatorSet}; use codec::Encode; use futures::channel::{oneshot, oneshot::Canceled}; use log::{debug, warn}; @@ -28,6 +27,7 @@ use sc_network_common::{ request_responses::{IfDisconnected, RequestFailure}, service::NetworkRequest, }; +use sp_consensus_beefy::{crypto::AuthorityId, ValidatorSet}; use sp_runtime::traits::{Block, NumberFor}; use std::{collections::VecDeque, result::Result, sync::Arc}; diff --git a/client/beefy/src/error.rs b/client/consensus/beefy/src/error.rs similarity index 100% rename from client/beefy/src/error.rs rename to client/consensus/beefy/src/error.rs diff --git a/client/beefy/src/import.rs b/client/consensus/beefy/src/import.rs similarity index 99% rename from client/beefy/src/import.rs rename to client/consensus/beefy/src/import.rs index 44d30d5d7df03..177a99b1066b2 100644 --- a/client/beefy/src/import.rs +++ b/client/consensus/beefy/src/import.rs @@ -16,8 +16,8 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use beefy_primitives::{BeefyApi, BEEFY_ENGINE_ID}; use log::debug; +use sp_consensus_beefy::{BeefyApi, BEEFY_ENGINE_ID}; use std::{collections::HashMap, sync::Arc}; use sp_api::{ProvideRuntimeApi, TransactionFor}; diff --git a/client/beefy/src/justification.rs b/client/consensus/beefy/src/justification.rs similarity index 98% rename from client/beefy/src/justification.rs rename to client/consensus/beefy/src/justification.rs index 6ceb3d2f5b369..1bd250b2a25f3 100644 --- a/client/beefy/src/justification.rs +++ b/client/consensus/beefy/src/justification.rs @@ -17,17 +17,17 @@ // along with this program. If not, see . use crate::keystore::BeefyKeystore; -use beefy_primitives::{ +use codec::{Decode, Encode}; +use sp_consensus::Error as ConsensusError; +use sp_consensus_beefy::{ crypto::{AuthorityId, Signature}, ValidatorSet, VersionedFinalityProof, }; -use codec::{Decode, Encode}; -use sp_consensus::Error as ConsensusError; use sp_runtime::traits::{Block as BlockT, NumberFor}; /// A finality proof with matching BEEFY authorities' signatures. pub type BeefyVersionedFinalityProof = - beefy_primitives::VersionedFinalityProof, Signature>; + sp_consensus_beefy::VersionedFinalityProof, Signature>; /// Decode and verify a Beefy FinalityProof. pub(crate) fn decode_and_verify_finality_proof( @@ -80,7 +80,7 @@ fn verify_with_validator_set( #[cfg(test)] pub(crate) mod tests { - use beefy_primitives::{ + use sp_consensus_beefy::{ known_payloads, Commitment, Keyring, Payload, SignedCommitment, VersionedFinalityProof, }; use substrate_test_runtime_client::runtime::Block; diff --git a/client/beefy/src/keystore.rs b/client/consensus/beefy/src/keystore.rs similarity index 97% rename from client/beefy/src/keystore.rs rename to client/consensus/beefy/src/keystore.rs index 3f0d8a5f316af..421f7149018c8 100644 --- a/client/beefy/src/keystore.rs +++ b/client/consensus/beefy/src/keystore.rs @@ -22,7 +22,7 @@ use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; use log::warn; -use beefy_primitives::{ +use sp_consensus_beefy::{ crypto::{Public, Signature}, BeefyAuthorityId, KEY_TYPE, }; @@ -89,8 +89,8 @@ impl BeefyKeystore { Ok(sig) } - /// Returns a vector of [`beefy_primitives::crypto::Public`] keys which are currently supported - /// (i.e. found in the keystore). + /// Returns a vector of [`sp_consensus_beefy::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()))?; @@ -123,7 +123,7 @@ pub mod tests { use sc_keystore::LocalKeystore; use sp_core::{ecdsa, Pair}; - use beefy_primitives::{crypto, Keyring}; + use sp_consensus_beefy::{crypto, Keyring}; use super::*; use crate::error::Error; diff --git a/client/beefy/src/lib.rs b/client/consensus/beefy/src/lib.rs similarity index 99% rename from client/beefy/src/lib.rs rename to client/consensus/beefy/src/lib.rs index 4f5f8b44329bf..9b627e3ff8fef 100644 --- a/client/beefy/src/lib.rs +++ b/client/consensus/beefy/src/lib.rs @@ -32,10 +32,6 @@ use crate::{ 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::{error, info}; use parking_lot::Mutex; @@ -50,6 +46,10 @@ use sp_blockchain::{ Backend as BlockchainBackend, Error as ClientError, HeaderBackend, Result as ClientResult, }; use sp_consensus::{Error as ConsensusError, SyncOracle}; +use sp_consensus_beefy::{ + crypto::AuthorityId, BeefyApi, MmrRootHash, PayloadProvider, ValidatorSet, BEEFY_ENGINE_ID, + GENESIS_AUTHORITY_SET_ID, +}; use sp_keystore::SyncCryptoStorePtr; use sp_mmr_primitives::MmrApi; use sp_runtime::traits::{Block, Zero}; diff --git a/client/beefy/src/metrics.rs b/client/consensus/beefy/src/metrics.rs similarity index 100% rename from client/beefy/src/metrics.rs rename to client/consensus/beefy/src/metrics.rs diff --git a/client/beefy/src/round.rs b/client/consensus/beefy/src/round.rs similarity index 99% rename from client/beefy/src/round.rs rename to client/consensus/beefy/src/round.rs index 142e138f599d5..64d03beeee854 100644 --- a/client/beefy/src/round.rs +++ b/client/consensus/beefy/src/round.rs @@ -18,12 +18,12 @@ use crate::LOG_TARGET; -use beefy_primitives::{ +use codec::{Decode, Encode}; +use log::debug; +use sp_consensus_beefy::{ crypto::{AuthorityId, Public, Signature}, Commitment, EquivocationProof, SignedCommitment, ValidatorSet, ValidatorSetId, VoteMessage, }; -use codec::{Decode, Encode}; -use log::debug; use sp_runtime::traits::{Block, NumberFor}; use std::collections::BTreeMap; @@ -198,7 +198,7 @@ where mod tests { use sc_network_test::Block; - use beefy_primitives::{ + use sp_consensus_beefy::{ crypto::Public, known_payloads::MMR_ROOT_ID, Commitment, EquivocationProof, Keyring, Payload, SignedCommitment, ValidatorSet, VoteMessage, }; diff --git a/client/beefy/src/tests.rs b/client/consensus/beefy/src/tests.rs similarity index 99% rename from client/beefy/src/tests.rs rename to client/consensus/beefy/src/tests.rs index 419033efe367f..e4fe16a2acfd3 100644 --- a/client/beefy/src/tests.rs +++ b/client/consensus/beefy/src/tests.rs @@ -29,14 +29,6 @@ use crate::{ 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, EquivocationProof, Keyring as BeefyKeyring, MmrRootHash, - OpaqueKeyOwnershipProof, Payload, SignedCommitment, ValidatorSet, ValidatorSetId, - VersionedFinalityProof, BEEFY_ENGINE_ID, KEY_TYPE as BeefyKeyType, -}; use futures::{future, stream::FuturesUnordered, Future, StreamExt}; use parking_lot::Mutex; use sc_client_api::{Backend as BackendT, BlockchainEvents, FinalityNotifications, HeaderBackend}; @@ -53,6 +45,14 @@ use sc_utils::notification::NotificationReceiver; use serde::{Deserialize, Serialize}; use sp_api::{ApiRef, ProvideRuntimeApi}; use sp_consensus::BlockOrigin; +use sp_consensus_beefy::{ + crypto::{AuthorityId, Signature}, + known_payloads, + mmr::MmrRootProvider, + BeefyApi, Commitment, ConsensusLog, EquivocationProof, Keyring as BeefyKeyring, MmrRootHash, + OpaqueKeyOwnershipProof, Payload, SignedCommitment, ValidatorSet, ValidatorSetId, + VersionedFinalityProof, BEEFY_ENGINE_ID, KEY_TYPE as BeefyKeyType, +}; use sp_core::H256; use sp_keystore::{testing::KeyStore as TestKeystore, SyncCryptoStore, SyncCryptoStorePtr}; use sp_mmr_primitives::{Error as MmrError, MmrApi}; @@ -484,7 +484,7 @@ async fn wait_for_beefy_signed_commitments( let expected = expected.next(); async move { let signed_commitment = match versioned_finality_proof { - beefy_primitives::VersionedFinalityProof::V1(sc) => sc, + sp_consensus_beefy::VersionedFinalityProof::V1(sc) => sc, }; let commitment_block_num = signed_commitment.commitment.block_number; assert_eq!(expected, Some(commitment_block_num).as_ref()); diff --git a/client/beefy/src/worker.rs b/client/consensus/beefy/src/worker.rs similarity index 99% rename from client/beefy/src/worker.rs rename to client/consensus/beefy/src/worker.rs index 439da213818df..7f3114958647f 100644 --- a/client/beefy/src/worker.rs +++ b/client/consensus/beefy/src/worker.rs @@ -29,12 +29,6 @@ use crate::{ round::{Rounds, VoteImportResult}, BeefyVoterLinks, LOG_TARGET, }; -use beefy_primitives::{ - check_equivocation_proof, - crypto::{AuthorityId, Signature}, - BeefyApi, Commitment, ConsensusLog, EquivocationProof, PayloadProvider, 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}; @@ -45,6 +39,12 @@ use sc_utils::notification::NotificationReceiver; use sp_api::{BlockId, ProvideRuntimeApi}; use sp_arithmetic::traits::{AtLeast32Bit, Saturating}; use sp_consensus::SyncOracle; +use sp_consensus_beefy::{ + check_equivocation_proof, + crypto::{AuthorityId, Signature}, + BeefyApi, Commitment, ConsensusLog, EquivocationProof, PayloadProvider, ValidatorSet, + VersionedFinalityProof, VoteMessage, BEEFY_ENGINE_ID, +}; use sp_runtime::{ generic::OpaqueDigestItemId, traits::{Block, ConstU32, Header, NumberFor, Zero}, @@ -1062,10 +1062,6 @@ pub(crate) mod tests { }, BeefyRPCLinks, KnownPeers, }; - use beefy_primitives::{ - generate_equivocation_proof, known_payloads, known_payloads::MMR_ROOT_ID, - mmr::MmrRootProvider, Keyring, Payload, SignedCommitment, - }; use futures::{future::poll_fn, task::Poll}; use parking_lot::Mutex; use sc_client_api::{Backend as BackendT, HeaderBackend}; @@ -1073,6 +1069,10 @@ pub(crate) mod tests { use sc_network_test::TestNetFactory; use sp_api::HeaderT; use sp_blockchain::Backend as BlockchainBackendT; + use sp_consensus_beefy::{ + generate_equivocation_proof, known_payloads, known_payloads::MMR_ROOT_ID, + mmr::MmrRootProvider, Keyring, Payload, SignedCommitment, + }; use sp_runtime::traits::One; use substrate_test_runtime_client::{ runtime::{Block, Digest, DigestItem, Header, H256}, diff --git a/client/merkle-mountain-range/Cargo.toml b/client/merkle-mountain-range/Cargo.toml index 90fb65453ba12..899f4cc2e08da 100644 --- a/client/merkle-mountain-range/Cargo.toml +++ b/client/merkle-mountain-range/Cargo.toml @@ -14,10 +14,10 @@ homepage = "https://substrate.io" codec = { package = "parity-scale-codec", version = "3.2.2" } futures = "0.3" log = "0.4" -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" } +sc-client-api = { version = "4.0.0-dev", path = "../api" } +sp-consensus-beefy = { version = "4.0.0-dev", path = "../../primitives/consensus/beefy" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } sp-core = { version = "7.0.0", path = "../../primitives/core" } sp-mmr-primitives = { version = "4.0.0-dev", path = "../../primitives/merkle-mountain-range" } diff --git a/client/merkle-mountain-range/src/lib.rs b/client/merkle-mountain-range/src/lib.rs index de21b9b4967fb..e174af7068abb 100644 --- a/client/merkle-mountain-range/src/lib.rs +++ b/client/merkle-mountain-range/src/lib.rs @@ -43,13 +43,13 @@ mod offchain_mmr; pub mod test_utils; use crate::offchain_mmr::OffchainMmr; -use beefy_primitives::MmrRootHash; use futures::StreamExt; use log::{debug, error, trace, warn}; use sc_client_api::{Backend, BlockchainEvents, FinalityNotification, FinalityNotifications}; use sc_offchain::OffchainDb; use sp_api::ProvideRuntimeApi; use sp_blockchain::{HeaderBackend, HeaderMetadata}; +use sp_consensus_beefy::MmrRootHash; use sp_mmr_primitives::{utils, LeafIndex, MmrApi}; use sp_runtime::traits::{Block, Header, NumberFor}; use std::{marker::PhantomData, sync::Arc}; diff --git a/client/merkle-mountain-range/src/offchain_mmr.rs b/client/merkle-mountain-range/src/offchain_mmr.rs index 33d85f0cb14e3..3c3f0beb6c6a9 100644 --- a/client/merkle-mountain-range/src/offchain_mmr.rs +++ b/client/merkle-mountain-range/src/offchain_mmr.rs @@ -22,11 +22,11 @@ #![warn(missing_docs)] use crate::{aux_schema, MmrClient, LOG_TARGET}; -use beefy_primitives::MmrRootHash; use log::{debug, error, info, warn}; use sc_client_api::{Backend, FinalityNotification}; use sc_offchain::OffchainDb; use sp_blockchain::{CachedHeaderMetadata, ForkBackend}; +use sp_consensus_beefy::MmrRootHash; use sp_core::offchain::{DbExternalities, StorageKind}; use sp_mmr_primitives::{utils, utils::NodesUtils, MmrApi, NodeIndex}; use sp_runtime::{ diff --git a/frame/beefy-mmr/Cargo.toml b/frame/beefy-mmr/Cargo.toml index 1d24e821c5012..721e24282c45b 100644 --- a/frame/beefy-mmr/Cargo.toml +++ b/frame/beefy-mmr/Cargo.toml @@ -15,12 +15,12 @@ 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 } binary-merkle-tree = { version = "4.0.0-dev", default-features = false, path = "../../utils/binary-merkle-tree" } -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" } 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-consensus-beefy = { version = "4.0.0-dev", default-features = false, path = "../../primitives/consensus/beefy" } 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" } @@ -36,7 +36,6 @@ default = ["std"] std = [ "array-bytes", "binary-merkle-tree/std", - "beefy-primitives/std", "codec/std", "frame-support/std", "frame-system/std", @@ -46,6 +45,7 @@ std = [ "pallet-session/std", "scale-info/std", "serde", + "sp-consensus-beefy/std", "sp-core/std", "sp-io/std", "sp-runtime/std", diff --git a/frame/beefy-mmr/src/lib.rs b/frame/beefy-mmr/src/lib.rs index 8bb3aaa7e69b8..ba52be4f883f0 100644 --- a/frame/beefy-mmr/src/lib.rs +++ b/frame/beefy-mmr/src/lib.rs @@ -36,11 +36,11 @@ use sp_runtime::traits::{Convert, Member}; use sp_std::prelude::*; -use beefy_primitives::{ +use pallet_mmr::{LeafDataProvider, ParentNumberAndHash}; +use sp_consensus_beefy::{ mmr::{BeefyAuthoritySet, BeefyDataProvider, BeefyNextAuthoritySet, MmrLeaf, MmrLeafVersion}, ValidatorSet as BeefyValidatorSet, }; -use pallet_mmr::{LeafDataProvider, ParentNumberAndHash}; use frame_support::{crypto::ecdsa::ECDSAExt, traits::Get}; @@ -54,15 +54,15 @@ 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 +impl pallet_mmr::primitives::OnNewRoot for DepositBeefyDigest where - T: pallet_mmr::Config, + 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::< + sp_consensus_beefy::BEEFY_ENGINE_ID, + codec::Encode::encode(&sp_consensus_beefy::ConsensusLog::< ::BeefyId, >::MmrRoot(*root)), ); @@ -72,8 +72,8 @@ where /// Convert BEEFY secp256k1 public keys into Ethereum addresses pub struct BeefyEcdsaToEthereum; -impl Convert> for BeefyEcdsaToEthereum { - fn convert(beefy_id: beefy_primitives::crypto::AuthorityId) -> Vec { +impl Convert> for BeefyEcdsaToEthereum { + fn convert(beefy_id: sp_consensus_beefy::crypto::AuthorityId) -> Vec { sp_core::ecdsa::Public::from(beefy_id) .to_eth_address() .map(|v| v.to_vec()) @@ -156,7 +156,7 @@ impl LeafDataProvider for Pallet { } } -impl beefy_primitives::OnNewValidatorSet<::BeefyId> for Pallet +impl sp_consensus_beefy::OnNewValidatorSet<::BeefyId> for Pallet where T: pallet::Config, { diff --git a/frame/beefy-mmr/src/mock.rs b/frame/beefy-mmr/src/mock.rs index 922f882e1f1df..d31effc9ab577 100644 --- a/frame/beefy-mmr/src/mock.rs +++ b/frame/beefy-mmr/src/mock.rs @@ -17,7 +17,6 @@ use std::vec; -use beefy_primitives::mmr::MmrLeafVersion; use codec::Encode; use frame_support::{ construct_runtime, parameter_types, @@ -25,6 +24,7 @@ use frame_support::{ traits::{ConstU16, ConstU32, ConstU64, GenesisBuild, KeyOwnerProofSystem}, BasicExternalities, }; +use sp_consensus_beefy::mmr::MmrLeafVersion; use sp_core::{crypto::KeyTypeId, Hasher, H256}; use sp_runtime::{ app_crypto::ecdsa::Public, @@ -35,7 +35,7 @@ use sp_runtime::{ use crate as pallet_beefy_mmr; -pub use beefy_primitives::{ +pub use sp_consensus_beefy::{ crypto::AuthorityId as BeefyId, mmr::BeefyDataProvider, ConsensusLog, BEEFY_ENGINE_ID, }; @@ -101,7 +101,7 @@ impl pallet_session::Config for Test { type WeightInfo = (); } -pub type MmrLeaf = beefy_primitives::mmr::MmrLeaf< +pub type MmrLeaf = sp_consensus_beefy::mmr::MmrLeaf< ::BlockNumber, ::Hash, ::Hash, diff --git a/frame/beefy-mmr/src/tests.rs b/frame/beefy-mmr/src/tests.rs index af10d1127ebd7..dc2e46f31fe64 100644 --- a/frame/beefy-mmr/src/tests.rs +++ b/frame/beefy-mmr/src/tests.rs @@ -17,11 +17,11 @@ use std::vec; -use beefy_primitives::{ +use codec::{Decode, Encode}; +use sp_consensus_beefy::{ mmr::{BeefyNextAuthoritySet, MmrLeafVersion}, ValidatorSet, }; -use codec::{Decode, Encode}; use sp_core::H256; use sp_io::TestExternalities; diff --git a/frame/beefy/Cargo.toml b/frame/beefy/Cargo.toml index b2d6635377571..3778ca5f37a56 100644 --- a/frame/beefy/Cargo.toml +++ b/frame/beefy/Cargo.toml @@ -12,11 +12,11 @@ homepage = "https://substrate.io" codec = { package = "parity-scale-codec", version = "3.2.2", 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", 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-authorship = { version = "4.0.0-dev", default-features = false, path = "../authorship" } pallet-session = { version = "4.0.0-dev", default-features = false, path = "../session" } +sp-consensus-beefy = { version = "4.0.0-dev", default-features = false, path = "../../primitives/consensus/beefy" } 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" } @@ -36,7 +36,6 @@ sp-staking = { version = "4.0.0-dev", path = "../../primitives/staking" } [features] default = ["std"] std = [ - "beefy-primitives/std", "codec/std", "frame-support/std", "frame-system/std", @@ -44,6 +43,7 @@ std = [ "pallet-session/std", "scale-info/std", "serde", + "sp-consensus-beefy/std", "sp-runtime/std", "sp-session/std", "sp-staking/std", diff --git a/frame/beefy/src/equivocation.rs b/frame/beefy/src/equivocation.rs index 19c41cbfacea5..cc04f316c3638 100644 --- a/frame/beefy/src/equivocation.rs +++ b/frame/beefy/src/equivocation.rs @@ -36,13 +36,13 @@ use sp_std::prelude::*; -use beefy_primitives::{EquivocationProof, ValidatorSetId}; use codec::{self as codec, Decode, Encode}; use frame_support::{ log, traits::{Get, KeyOwnerProofSystem}, }; use frame_system::pallet_prelude::BlockNumberFor; +use sp_consensus_beefy::{EquivocationProof, ValidatorSetId}; use sp_runtime::{ transaction_validity::{ InvalidTransaction, TransactionPriority, TransactionSource, TransactionValidity, @@ -271,7 +271,7 @@ fn is_known_offence( ) -> Result<(), TransactionValidityError> { // check the membership proof to extract the offender's id, // equivocation validity will be fully checked during the call. - let key = (beefy_primitives::KEY_TYPE, equivocation_proof.offender_id().clone()); + let key = (sp_consensus_beefy::KEY_TYPE, equivocation_proof.offender_id().clone()); let offender = T::KeyOwnerProofSystem::check_proof(key, key_owner_proof.clone()) .ok_or(InvalidTransaction::BadProof)?; diff --git a/frame/beefy/src/lib.rs b/frame/beefy/src/lib.rs index bcb7fc126520b..698e6e73312f1 100644 --- a/frame/beefy/src/lib.rs +++ b/frame/beefy/src/lib.rs @@ -40,7 +40,7 @@ use sp_session::{GetSessionNumber, GetValidatorCount}; use sp_staking::SessionIndex; use sp_std::prelude::*; -use beefy_primitives::{ +use sp_consensus_beefy::{ AuthorityIndex, BeefyAuthorityId, ConsensusLog, EquivocationProof, OnNewValidatorSet, ValidatorSet, BEEFY_ENGINE_ID, GENESIS_AUTHORITY_SET_ID, }; @@ -135,7 +135,7 @@ pub mod pallet { #[pallet::storage] #[pallet::getter(fn validator_set_id)] pub(super) type ValidatorSetId = - StorageValue<_, beefy_primitives::ValidatorSetId, ValueQuery>; + StorageValue<_, sp_consensus_beefy::ValidatorSetId, ValueQuery>; /// Authorities set scheduled to be used with the next session #[pallet::storage] @@ -156,7 +156,7 @@ pub mod pallet { #[pallet::storage] #[pallet::getter(fn session_for_set)] pub(super) type SetIdSession = - StorageMap<_, Twox64Concat, beefy_primitives::ValidatorSetId, SessionIndex>; + StorageMap<_, Twox64Concat, sp_consensus_beefy::ValidatorSetId, SessionIndex>; /// Block number where BEEFY consensus is enabled/started. /// If changing this, make sure `Self::ValidatorSetId` is also reset to @@ -280,7 +280,7 @@ impl Pallet { /// Return the current active BEEFY validator set. pub fn validator_set() -> Option> { let validators: BoundedVec = Self::authorities(); - let id: beefy_primitives::ValidatorSetId = Self::validator_set_id(); + let id: sp_consensus_beefy::ValidatorSetId = Self::validator_set_id(); ValidatorSet::::new(validators, id) } @@ -390,13 +390,13 @@ impl Pallet { // validate the key ownership proof extracting the id of the offender. let offender = T::KeyOwnerProofSystem::check_proof( - (beefy_primitives::KEY_TYPE, offender_id), + (sp_consensus_beefy::KEY_TYPE, offender_id), key_owner_proof, ) .ok_or(Error::::InvalidKeyOwnershipProof)?; // validate equivocation proof (check votes are different and signatures are valid). - if !beefy_primitives::check_equivocation_proof(&equivocation_proof) { + if !sp_consensus_beefy::check_equivocation_proof(&equivocation_proof) { return Err(Error::::InvalidEquivocationProof.into()) } diff --git a/frame/beefy/src/mock.rs b/frame/beefy/src/mock.rs index 74dba2a01b81d..72e3f83dff91c 100644 --- a/frame/beefy/src/mock.rs +++ b/frame/beefy/src/mock.rs @@ -40,7 +40,7 @@ use sp_staking::{EraIndex, SessionIndex}; use crate as pallet_beefy; -pub use beefy_primitives::{ +pub use sp_consensus_beefy::{ crypto::{AuthorityId as BeefyId, AuthoritySignature as BeefySignature}, ConsensusLog, EquivocationProof, BEEFY_ENGINE_ID, }; diff --git a/frame/beefy/src/tests.rs b/frame/beefy/src/tests.rs index 767b1e5657502..f9da20e90dc74 100644 --- a/frame/beefy/src/tests.rs +++ b/frame/beefy/src/tests.rs @@ -17,11 +17,11 @@ use std::vec; -use beefy_primitives::{ +use codec::Encode; +use sp_consensus_beefy::{ check_equivocation_proof, generate_equivocation_proof, known_payloads::MMR_ROOT_ID, Keyring as BeefyKeyring, Payload, ValidatorSet, }; -use codec::Encode; use sp_runtime::DigestItem; @@ -298,7 +298,7 @@ fn report_equivocation_current_set_works() { // create the key ownership proof let key_owner_proof = - Historical::prove((beefy_primitives::KEY_TYPE, &equivocation_key)).unwrap(); + Historical::prove((sp_consensus_beefy::KEY_TYPE, &equivocation_key)).unwrap(); // report the equivocation and the tx should be dispatched successfully assert_ok!(Beefy::report_equivocation_unsigned( @@ -355,7 +355,7 @@ fn report_equivocation_old_set_works() { // create the key ownership proof in the "old" set let key_owner_proof = - Historical::prove((beefy_primitives::KEY_TYPE, &equivocation_key)).unwrap(); + Historical::prove((sp_consensus_beefy::KEY_TYPE, &equivocation_key)).unwrap(); start_era(2); @@ -437,7 +437,7 @@ fn report_equivocation_invalid_set_id() { let equivocation_keyring = BeefyKeyring::from_public(equivocation_key).unwrap(); let key_owner_proof = - Historical::prove((beefy_primitives::KEY_TYPE, &equivocation_key)).unwrap(); + Historical::prove((sp_consensus_beefy::KEY_TYPE, &equivocation_key)).unwrap(); let payload1 = Payload::from_single_entry(MMR_ROOT_ID, vec![42]); let payload2 = Payload::from_single_entry(MMR_ROOT_ID, vec![128]); @@ -476,7 +476,7 @@ fn report_equivocation_invalid_session() { // generate a key ownership proof at current era set id let key_owner_proof = - Historical::prove((beefy_primitives::KEY_TYPE, &equivocation_key)).unwrap(); + Historical::prove((sp_consensus_beefy::KEY_TYPE, &equivocation_key)).unwrap(); start_era(2); @@ -520,7 +520,7 @@ fn report_equivocation_invalid_key_owner_proof() { // generate a key ownership proof for the authority at index 1 let invalid_key_owner_proof = - Historical::prove((beefy_primitives::KEY_TYPE, &invalid_owner_key)).unwrap(); + Historical::prove((sp_consensus_beefy::KEY_TYPE, &invalid_owner_key)).unwrap(); let equivocation_authority_index = 0; let equivocation_key = &authorities[equivocation_authority_index]; @@ -569,7 +569,7 @@ fn report_equivocation_invalid_equivocation_proof() { // generate a key ownership proof at set id in era 1 let key_owner_proof = - Historical::prove((beefy_primitives::KEY_TYPE, &equivocation_key)).unwrap(); + Historical::prove((sp_consensus_beefy::KEY_TYPE, &equivocation_key)).unwrap(); let assert_invalid_equivocation_proof = |equivocation_proof| { assert_err!( @@ -650,7 +650,7 @@ fn report_equivocation_validate_unsigned_prevents_duplicates() { ); let key_owner_proof = - Historical::prove((beefy_primitives::KEY_TYPE, &equivocation_key)).unwrap(); + Historical::prove((sp_consensus_beefy::KEY_TYPE, &equivocation_key)).unwrap(); let call = Call::report_equivocation_unsigned { equivocation_proof: Box::new(equivocation_proof.clone()), @@ -756,7 +756,7 @@ fn valid_equivocation_reports_dont_pay_fees() { // create the key ownership proof. let key_owner_proof = - Historical::prove((beefy_primitives::KEY_TYPE, &equivocation_key)).unwrap(); + Historical::prove((sp_consensus_beefy::KEY_TYPE, &equivocation_key)).unwrap(); // check the dispatch info for the call. let info = Call::::report_equivocation_unsigned { diff --git a/primitives/beefy/Cargo.toml b/primitives/consensus/beefy/Cargo.toml similarity index 84% rename from primitives/beefy/Cargo.toml rename to primitives/consensus/beefy/Cargo.toml index 5dfda3e378fab..657569d122b05 100644 --- a/primitives/beefy/Cargo.toml +++ b/primitives/consensus/beefy/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "sp-beefy" +name = "sp-consensus-beefy" version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2021" @@ -15,19 +15,19 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.2.2", 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 = "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 = "7.0.0", default-features = false, path = "../runtime" } -sp-std = { version = "5.0.0", default-features = false, path = "../std" } +sp-api = { version = "4.0.0-dev", default-features = false, path = "../../api" } +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 = "7.0.0", default-features = false, path = "../../runtime" } +sp-std = { version = "5.0.0", default-features = false, path = "../../std" } strum = { version = "0.24.1", features = ["derive"], default-features = false } lazy_static = "1.4.0" [dev-dependencies] array-bytes = "4.1" -sp-keystore = { version = "0.13.0", path = "../keystore" } +sp-keystore = { version = "0.13.0", path = "../../keystore" } [features] default = ["std"] diff --git a/primitives/beefy/src/commitment.rs b/primitives/consensus/beefy/src/commitment.rs similarity index 100% rename from primitives/beefy/src/commitment.rs rename to primitives/consensus/beefy/src/commitment.rs diff --git a/primitives/beefy/src/lib.rs b/primitives/consensus/beefy/src/lib.rs similarity index 100% rename from primitives/beefy/src/lib.rs rename to primitives/consensus/beefy/src/lib.rs diff --git a/primitives/beefy/src/mmr.rs b/primitives/consensus/beefy/src/mmr.rs similarity index 100% rename from primitives/beefy/src/mmr.rs rename to primitives/consensus/beefy/src/mmr.rs diff --git a/primitives/beefy/src/payload.rs b/primitives/consensus/beefy/src/payload.rs similarity index 100% rename from primitives/beefy/src/payload.rs rename to primitives/consensus/beefy/src/payload.rs diff --git a/primitives/beefy/src/test_utils.rs b/primitives/consensus/beefy/src/test_utils.rs similarity index 100% rename from primitives/beefy/src/test_utils.rs rename to primitives/consensus/beefy/src/test_utils.rs diff --git a/primitives/beefy/src/witness.rs b/primitives/consensus/beefy/src/witness.rs similarity index 100% rename from primitives/beefy/src/witness.rs rename to primitives/consensus/beefy/src/witness.rs diff --git a/primitives/beefy/test-res/large-raw-commitment b/primitives/consensus/beefy/test-res/large-raw-commitment similarity index 100% rename from primitives/beefy/test-res/large-raw-commitment rename to primitives/consensus/beefy/test-res/large-raw-commitment diff --git a/test-utils/runtime/Cargo.toml b/test-utils/runtime/Cargo.toml index f3222dc15c280..339a435ef2a04 100644 --- a/test-utils/runtime/Cargo.toml +++ b/test-utils/runtime/Cargo.toml @@ -13,11 +13,11 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -beefy-primitives = { version = "4.0.0-dev", default-features = false, path = "../../primitives/beefy", package = "sp-beefy" } pallet-beefy-mmr = { version = "4.0.0-dev", default-features = false, path = "../../frame/beefy-mmr" } 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-consensus-beefy = { version = "4.0.0-dev", default-features = false, path = "../../primitives/consensus/beefy" } sp-block-builder = { version = "4.0.0-dev", default-features = false, path = "../../primitives/block-builder" } codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } @@ -66,11 +66,11 @@ default = [ "std", ] std = [ - "beefy-primitives/std", "pallet-beefy-mmr/std", "sp-application-crypto/std", "sp-consensus-aura/std", "sp-consensus-babe/std", + "sp-consensus-beefy/std", "sp-block-builder/std", "codec/std", "scale-info/std", diff --git a/test-utils/runtime/src/lib.rs b/test-utils/runtime/src/lib.rs index 9e8a4e119b293..87a60acfc87ce 100644 --- a/test-utils/runtime/src/lib.rs +++ b/test-utils/runtime/src/lib.rs @@ -972,36 +972,36 @@ cfg_if! { } } - impl beefy_primitives::BeefyApi for Runtime { + impl sp_consensus_beefy::BeefyApi for Runtime { fn beefy_genesis() -> Option { None } - fn validator_set() -> Option> { + fn validator_set() -> Option> { None } fn submit_report_equivocation_unsigned_extrinsic( - _equivocation_proof: beefy_primitives::EquivocationProof< + _equivocation_proof: sp_consensus_beefy::EquivocationProof< NumberFor, - beefy_primitives::crypto::AuthorityId, - beefy_primitives::crypto::Signature + sp_consensus_beefy::crypto::AuthorityId, + sp_consensus_beefy::crypto::Signature >, - _key_owner_proof: beefy_primitives::OpaqueKeyOwnershipProof, + _key_owner_proof: sp_consensus_beefy::OpaqueKeyOwnershipProof, ) -> Option<()> { None } fn generate_key_ownership_proof( - _set_id: beefy_primitives::ValidatorSetId, - _authority_id: beefy_primitives::crypto::AuthorityId, - ) -> Option { None } + _set_id: sp_consensus_beefy::ValidatorSetId, + _authority_id: sp_consensus_beefy::crypto::AuthorityId, + ) -> Option { None } } - impl pallet_beefy_mmr::BeefyMmrApi for Runtime { - fn authority_set_proof() -> beefy_primitives::mmr::BeefyAuthoritySet { + impl pallet_beefy_mmr::BeefyMmrApi for Runtime { + fn authority_set_proof() -> sp_consensus_beefy::mmr::BeefyAuthoritySet { Default::default() } - fn next_authority_set_proof() -> beefy_primitives::mmr::BeefyNextAuthoritySet { + fn next_authority_set_proof() -> sp_consensus_beefy::mmr::BeefyNextAuthoritySet { Default::default() } } From ad5399644aebc54e32a107ac37ae08e6cd1f0cfb Mon Sep 17 00:00:00 2001 From: yjh Date: Wed, 1 Mar 2023 03:50:57 +0800 Subject: [PATCH 449/715] chore: move genesis block builder to chain-spec crate. (#13427) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: move genesis block builder to block builder crate. * add missing file * chore: move genesis block builder to sc-chain-spec * Update client/chain-spec/src/genesis.rs Co-authored-by: Bastian Köcher * Update test-utils/runtime/src/genesismap.rs Co-authored-by: Bastian Köcher * Update test-utils/runtime/client/src/lib.rs * fix warnings * fix warnings --------- Co-authored-by: Bastian Köcher --- Cargo.lock | 5 ++ client/block-builder/Cargo.toml | 2 +- client/block-builder/src/lib.rs | 3 +- client/chain-spec/Cargo.toml | 4 ++ .../src/client => chain-spec/src}/genesis.rs | 49 +++++++++++++++--- client/chain-spec/src/lib.rs | 11 ++-- client/service/src/client/client.rs | 50 +++---------------- client/service/src/client/mod.rs | 3 +- client/service/src/lib.rs | 11 ++-- test-utils/runtime/client/Cargo.toml | 1 + test-utils/runtime/client/src/lib.rs | 17 +++---- test-utils/runtime/src/genesismap.rs | 6 +-- 12 files changed, 88 insertions(+), 74 deletions(-) rename client/{service/src/client => chain-spec/src}/genesis.rs (68%) diff --git a/Cargo.lock b/Cargo.lock index a29213b45b545..a412347bde5c0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8011,12 +8011,16 @@ version = "4.0.0-dev" dependencies = [ "memmap2", "sc-chain-spec-derive", + "sc-client-api", + "sc-executor", "sc-network-common", "sc-telemetry", "serde", "serde_json", + "sp-blockchain", "sp-core", "sp-runtime", + "sp-state-machine", ] [[package]] @@ -10869,6 +10873,7 @@ dependencies = [ "futures", "parity-scale-codec", "sc-block-builder", + "sc-chain-spec", "sc-client-api", "sc-consensus", "sp-api", diff --git a/client/block-builder/Cargo.toml b/client/block-builder/Cargo.toml index 3b4bea9818c9e..d009826b2fae4 100644 --- a/client/block-builder/Cargo.toml +++ b/client/block-builder/Cargo.toml @@ -23,7 +23,7 @@ sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-core = { version = "7.0.0", path = "../../primitives/core" } sp-inherents = { version = "4.0.0-dev", path = "../../primitives/inherents" } sp-runtime = { version = "7.0.0", path = "../../primitives/runtime" } -sp-state-machine = { version = "0.13.0", path = "../../primitives/state-machine" } [dev-dependencies] +sp-state-machine = { version = "0.13.0", path = "../../primitives/state-machine" } substrate-test-runtime-client = { path = "../../test-utils/runtime/client" } diff --git a/client/block-builder/src/lib.rs b/client/block-builder/src/lib.rs index d7ef3b1da5123..d97afadd40156 100644 --- a/client/block-builder/src/lib.rs +++ b/client/block-builder/src/lib.rs @@ -39,9 +39,8 @@ use sp_runtime::{ Digest, }; -pub use sp_block_builder::BlockBuilder as BlockBuilderApi; - use sc_client_api::backend; +pub use sp_block_builder::BlockBuilder as BlockBuilderApi; /// Used as parameter to [`BlockBuilderProvider`] to express if proof recording should be enabled. /// diff --git a/client/chain-spec/Cargo.toml b/client/chain-spec/Cargo.toml index 0a4e54e8d6a67..6168a897c962c 100644 --- a/client/chain-spec/Cargo.toml +++ b/client/chain-spec/Cargo.toml @@ -16,8 +16,12 @@ targets = ["x86_64-unknown-linux-gnu"] memmap2 = "0.5.0" serde = { version = "1.0.136", features = ["derive"] } serde_json = "1.0.85" +sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-chain-spec-derive = { version = "4.0.0-dev", path = "./derive" } +sc-executor = { version = "0.10.0-dev", path = "../executor" } sc-network-common = { version = "0.10.0-dev", path = "../network/common" } sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" } +sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } 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" } diff --git a/client/service/src/client/genesis.rs b/client/chain-spec/src/genesis.rs similarity index 68% rename from client/service/src/client/genesis.rs rename to client/chain-spec/src/genesis.rs index b3ed46c1550c7..6aa156a620a79 100644 --- a/client/service/src/client/genesis.rs +++ b/client/chain-spec/src/genesis.rs @@ -18,20 +18,56 @@ //! Tool for creating the genesis block. +use std::{collections::hash_map::DefaultHasher, marker::PhantomData, sync::Arc}; + use sc_client_api::{backend::Backend, BlockImportOperation}; use sc_executor::RuntimeVersionOf; -use sp_core::storage::Storage; +use sp_core::storage::{well_known_keys, StateVersion, Storage}; use sp_runtime::{ traits::{Block as BlockT, Hash as HashT, Header as HeaderT, Zero}, BuildStorage, }; -use std::{marker::PhantomData, sync::Arc}; + +/// Return the state version given the genesis storage and executor. +pub fn resolve_state_version_from_wasm( + storage: &Storage, + executor: &E, +) -> sp_blockchain::Result +where + E: RuntimeVersionOf, +{ + 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(e.to_string()))?; + Ok(runtime_version.state_version()) + } else { + Err(sp_blockchain::Error::VersionInvalid( + "Runtime missing from initial storage, could not read state version.".to_string(), + )) + } +} /// Create a genesis block, given the initial storage. -pub fn construct_genesis_block(state_root: Block::Hash) -> Block { +pub fn construct_genesis_block( + state_root: Block::Hash, + state_version: StateVersion, +) -> Block { let extrinsics_root = <<::Header as HeaderT>::Hashing as HashT>::trie_root( Vec::new(), - sp_runtime::StateVersion::V0, + state_version, ); Block::new( @@ -93,12 +129,11 @@ impl, E: RuntimeVersionOf> BuildGenesisBlock sp_blockchain::Result<(Block, Self::BlockImportOperation)> { let Self { genesis_storage, commit_genesis_state, backend, executor, _phantom } = self; - let genesis_state_version = - crate::resolve_state_version_from_wasm(&genesis_storage, &executor)?; + let genesis_state_version = resolve_state_version_from_wasm(&genesis_storage, &executor)?; let mut op = backend.begin_operation()?; let state_root = op.set_genesis_state(genesis_storage, commit_genesis_state, genesis_state_version)?; - let genesis_block = construct_genesis_block::(state_root); + let genesis_block = construct_genesis_block::(state_root, genesis_state_version); Ok((genesis_block, op)) } diff --git a/client/chain-spec/src/lib.rs b/client/chain-spec/src/lib.rs index 414df1fe1296f..e43a247961f02 100644 --- a/client/chain-spec/src/lib.rs +++ b/client/chain-spec/src/lib.rs @@ -177,10 +177,15 @@ mod chain_spec; mod extension; +mod genesis; -pub use chain_spec::{ChainSpec as GenericChainSpec, NoExtension}; -pub use extension::{ - get_extension, get_extension_mut, Extension, Fork, Forks, GetExtension, Group, +pub use self::{ + chain_spec::{ChainSpec as GenericChainSpec, NoExtension}, + extension::{get_extension, get_extension_mut, Extension, Fork, Forks, GetExtension, Group}, + genesis::{ + construct_genesis_block, resolve_state_version_from_wasm, BuildGenesisBlock, + GenesisBlockBuilder, + }, }; pub use sc_chain_spec_derive::{ChainSpecExtension, ChainSpecGroup}; diff --git a/client/service/src/client/client.rs b/client/service/src/client/client.rs index 4b5822ae0e017..9a2a376ebc19f 100644 --- a/client/service/src/client/client.rs +++ b/client/service/src/client/client.rs @@ -18,16 +18,14 @@ //! Substrate Client -use super::{ - block_rules::{BlockRules, LookupResult as BlockLookupResult}, - genesis::BuildGenesisBlock, -}; +use super::block_rules::{BlockRules, LookupResult as BlockLookupResult}; use futures::{FutureExt, StreamExt}; use log::{error, info, trace, warn}; use parking_lot::{Mutex, RwLock}; use prometheus_endpoint::Registry; use rand::Rng; use sc_block_builder::{BlockBuilderApi, BlockBuilderProvider, RecordProof}; +use sc_chain_spec::{resolve_state_version_from_wasm, BuildGenesisBlock}; use sc_client_api::{ backend::{ self, apply_aux, BlockImportOperation, ClientImportOperation, FinalizeSummary, Finalizer, @@ -46,7 +44,7 @@ use sc_client_api::{ use sc_consensus::{ BlockCheckParams, BlockImportParams, ForkChoiceStrategy, ImportResult, StateAction, }; -use sc_executor::{RuntimeVersion, RuntimeVersionOf}; +use sc_executor::RuntimeVersion; use sc_telemetry::{telemetry, TelemetryHandle, SUBSTRATE_INFO}; use sp_api::{ ApiExt, ApiRef, CallApiAt, CallApiAtParams, ConstructRuntimeApi, Core as CoreApi, @@ -61,8 +59,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, Storage, StorageChild, - StorageData, StorageKey, + well_known_keys, ChildInfo, ChildType, PrefixedStorageKey, StorageChild, StorageData, + StorageKey, }, traits::SpawnNamed, }; @@ -84,7 +82,7 @@ use sp_state_machine::{ }; use sp_trie::{CompactProof, StorageProof}; use std::{ - collections::{hash_map::DefaultHasher, HashMap, HashSet}, + collections::{HashMap, HashSet}, marker::PhantomData, path::PathBuf, sync::Arc, @@ -172,7 +170,7 @@ pub fn new_in_mem( Client, LocalCallExecutor, E>, Block, RA>, > where - E: CodeExecutor + RuntimeVersionOf, + E: CodeExecutor + sc_executor::RuntimeVersionOf, Block: BlockT, G: BuildGenesisBlock< Block, @@ -233,7 +231,7 @@ pub fn new_with_backend( config: ClientConfig, ) -> sp_blockchain::Result, Block, RA>> where - E: CodeExecutor + RuntimeVersionOf, + E: CodeExecutor + sc_executor::RuntimeVersionOf, G: BuildGenesisBlock< Block, BlockImportOperation = >::BlockImportOperation, @@ -1222,38 +1220,6 @@ where } } -/// Return the genesis state version given the genesis storage and executor. -pub fn resolve_state_version_from_wasm( - storage: &Storage, - executor: &E, -) -> sp_blockchain::Result -where - E: RuntimeVersionOf, -{ - 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(e.to_string()))?; - 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 where B: backend::Backend, diff --git a/client/service/src/client/mod.rs b/client/service/src/client/mod.rs index 38d818c498a6a..a13fd4317e155 100644 --- a/client/service/src/client/mod.rs +++ b/client/service/src/client/mod.rs @@ -47,13 +47,12 @@ mod block_rules; mod call_executor; mod client; -pub mod genesis; mod wasm_override; mod wasm_substitutes; pub use self::{ call_executor::LocalCallExecutor, - client::{resolve_state_version_from_wasm, Client, ClientConfig}, + client::{Client, ClientConfig}, }; #[cfg(feature = "test-helpers")] diff --git a/client/service/src/lib.rs b/client/service/src/lib.rs index af0b11f2092c4..6bafa9936c0bf 100644 --- a/client/service/src/lib.rs +++ b/client/service/src/lib.rs @@ -61,12 +61,15 @@ pub use self::{ new_full_parts, spawn_tasks, BuildNetworkParams, KeystoreContainer, NetworkStarter, SpawnTasksParams, TFullBackend, TFullCallExecutor, TFullClient, }, - client::{ - genesis::{BuildGenesisBlock, GenesisBlockBuilder}, - resolve_state_version_from_wasm, ClientConfig, LocalCallExecutor, - }, + client::{ClientConfig, LocalCallExecutor}, error::Error, }; + +pub use sc_chain_spec::{ + construct_genesis_block, resolve_state_version_from_wasm, BuildGenesisBlock, + GenesisBlockBuilder, +}; + pub use config::{ BasePath, BlocksPruning, Configuration, DatabaseSource, PruningMode, Role, RpcMethods, TaskType, }; diff --git a/test-utils/runtime/client/Cargo.toml b/test-utils/runtime/client/Cargo.toml index 7d5c9673f6e21..986db0ba60283 100644 --- a/test-utils/runtime/client/Cargo.toml +++ b/test-utils/runtime/client/Cargo.toml @@ -15,6 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.2.2" } futures = "0.3.21" sc-block-builder = { version = "0.10.0-dev", path = "../../../client/block-builder" } +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 = { version = "0.10.0-dev", path = "../../../client/consensus/common" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } diff --git a/test-utils/runtime/client/src/lib.rs b/test-utils/runtime/client/src/lib.rs index 97ee525f6eb9a..099aeab11f768 100644 --- a/test-utils/runtime/client/src/lib.rs +++ b/test-utils/runtime/client/src/lib.rs @@ -30,6 +30,8 @@ pub use substrate_test_runtime as runtime; pub use self::block_builder_ext::BlockBuilderExt; +use sc_chain_spec::construct_genesis_block; +use sp_api::StateVersion; use sp_core::{ sr25519, storage::{ChildInfo, Storage, StorageChild}, @@ -122,7 +124,7 @@ impl GenesisParameters { } } -impl substrate_test_client::GenesisInit for GenesisParameters { +impl GenesisInit for GenesisParameters { fn genesis_storage(&self) -> Storage { use codec::Encode; @@ -148,7 +150,7 @@ impl substrate_test_client::GenesisInit for GenesisParameters { storage.top.clone().into_iter().chain(child_roots).collect(), sp_runtime::StateVersion::V1, ); - let block: runtime::Block = client::genesis::construct_genesis_block(state_root); + let block: runtime::Block = construct_genesis_block(state_root, StateVersion::V1); storage.top.extend(additional_storage_with_genesis(&block)); storage @@ -260,7 +262,7 @@ impl TestClientBuilderExt client::LocalCallExecutor< substrate_test_runtime::Block, B, - sc_executor::NativeElseWasmExecutor, + NativeElseWasmExecutor, >, B, > where @@ -288,11 +290,6 @@ 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, - 2, - ) +pub fn new_native_executor() -> NativeElseWasmExecutor { + NativeElseWasmExecutor::new(sc_executor::WasmExecutionMethod::Interpreted, None, 8, 2) } diff --git a/test-utils/runtime/src/genesismap.rs b/test-utils/runtime/src/genesismap.rs index 77fdf59ea8cb4..9e00dd29999f8 100644 --- a/test-utils/runtime/src/genesismap.rs +++ b/test-utils/runtime/src/genesismap.rs @@ -20,10 +20,10 @@ 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 sc_service::construct_genesis_block; use sp_core::{ map, - storage::{well_known_keys, Storage}, + storage::{well_known_keys, StateVersion, Storage}, }; use sp_io::hashing::{blake2_256, twox_128}; use sp_runtime::traits::{Block as BlockT, Hash as HashT, Header as HeaderT}; @@ -106,7 +106,7 @@ pub fn insert_genesis_block(storage: &mut Storage) -> sp_core::hash::H256 { storage.top.clone().into_iter().collect(), sp_runtime::StateVersion::V1, ); - let block: crate::Block = genesis::construct_genesis_block(state_root); + let block: crate::Block = construct_genesis_block(state_root, StateVersion::V1); let genesis_hash = block.header.hash(); storage.top.extend(additional_storage_with_genesis(&block)); genesis_hash From aa31d1b1ca12197c2d8b07e78d6c6c3a8bd34f98 Mon Sep 17 00:00:00 2001 From: Koute Date: Wed, 1 Mar 2023 17:58:18 +0900 Subject: [PATCH 450/715] Speed up storage iteration from within the runtime (#13479) * Speed up storage iteration from within the runtime * Move the cached iterator into an `Option` * Use `RefCell` in no_std * Simplify the code slightly * Use `Option::replace` * Update doc comment for `next_storage_key_slow` --- Cargo.lock | 8 +- frame/benchmarking/pov/src/benchmarking.rs | 13 +++ frame/benchmarking/pov/src/lib.rs | 5 ++ primitives/state-machine/Cargo.toml | 2 +- primitives/state-machine/src/trie_backend.rs | 85 ++++++++++++++++++- .../state-machine/src/trie_backend_essence.rs | 13 ++- primitives/trie/Cargo.toml | 4 +- test-utils/runtime/Cargo.toml | 2 +- .../rpc/state-trie-migration-rpc/Cargo.toml | 2 +- 9 files changed, 118 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a412347bde5c0..a8f596c0684ef 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11437,9 +11437,9 @@ dependencies = [ [[package]] name = "trie-bench" -version = "0.35.0" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22c1d18c423077531e693e87ace54ed9e4af1e4ce0a3ea8c9aa6608741074e2b" +checksum = "ac2b7695feb8041efc0adaa09ed3a692ca7b7c997395954fdc838b5b078346f6" dependencies = [ "criterion", "hash-db", @@ -11453,9 +11453,9 @@ dependencies = [ [[package]] name = "trie-db" -version = "0.25.1" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3390c0409daaa6027d6681393316f4ccd3ff82e1590a1e4725014e3ae2bf1920" +checksum = "879380c0061b165ba1f036325b7f3478bc1a947814d9fc36d22c5d8e960b11bd" dependencies = [ "hash-db", "hashbrown 0.13.2", diff --git a/frame/benchmarking/pov/src/benchmarking.rs b/frame/benchmarking/pov/src/benchmarking.rs index ebe9b241416ad..46a98ae3ff183 100644 --- a/frame/benchmarking/pov/src/benchmarking.rs +++ b/frame/benchmarking/pov/src/benchmarking.rs @@ -316,6 +316,19 @@ frame_benchmarking::benchmarks! { call.dispatch_bypass_filter(RawOrigin::Root.into()).unwrap(); } + storage_iteration { + for i in 0..65000 { + UnboundedMapTwox::::insert(i, sp_std::vec![0; 64]); + } + }: { + for (key, value) in UnboundedMapTwox::::iter() { + unsafe { + core::ptr::read_volatile(&key); + core::ptr::read_volatile(value.as_ptr()); + } + } + } + impl_benchmark_test_suite!( Pallet, mock::new_test_ext(), diff --git a/frame/benchmarking/pov/src/lib.rs b/frame/benchmarking/pov/src/lib.rs index 7dee5c37c1288..b66b5e417817a 100644 --- a/frame/benchmarking/pov/src/lib.rs +++ b/frame/benchmarking/pov/src/lib.rs @@ -107,6 +107,11 @@ pub mod pallet { pub(crate) type UnboundedMap2 = StorageMap, QueryKind = OptionQuery>; + #[pallet::storage] + #[pallet::unbounded] + pub(crate) type UnboundedMapTwox = + StorageMap, QueryKind = OptionQuery>; + #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { diff --git a/primitives/state-machine/Cargo.toml b/primitives/state-machine/Cargo.toml index 2969a51c4eba0..56fbe0726b82e 100644 --- a/primitives/state-machine/Cargo.toml +++ b/primitives/state-machine/Cargo.toml @@ -33,7 +33,7 @@ array-bytes = "4.1" pretty_assertions = "1.2.1" rand = "0.8.5" sp-runtime = { version = "7.0.0", path = "../runtime" } -trie-db = "0.25.1" +trie-db = "0.26.0" assert_matches = "1.5" [features] diff --git a/primitives/state-machine/src/trie_backend.rs b/primitives/state-machine/src/trie_backend.rs index 3e8d0a7a3bf0a..10e2dfd16d66a 100644 --- a/primitives/state-machine/src/trie_backend.rs +++ b/primitives/state-machine/src/trie_backend.rs @@ -20,8 +20,8 @@ #[cfg(feature = "std")] use crate::backend::AsTrieBackend; use crate::{ - backend::IterArgs, - trie_backend_essence::{TrieBackendEssence, TrieBackendStorage}, + backend::{IterArgs, StorageIterator}, + trie_backend_essence::{RawIter, TrieBackendEssence, TrieBackendStorage}, Backend, StorageKey, StorageValue, }; use codec::Codec; @@ -172,6 +172,7 @@ where self.cache, self.recorder, ), + next_storage_key_cache: Default::default(), } } @@ -180,19 +181,62 @@ where pub fn build(self) -> TrieBackend { let _ = self.cache; - TrieBackend { essence: TrieBackendEssence::new(self.storage, self.root) } + TrieBackend { + essence: TrieBackendEssence::new(self.storage, self.root), + next_storage_key_cache: Default::default(), + } + } +} + +/// A cached iterator. +struct CachedIter +where + H: Hasher, +{ + last_key: sp_std::vec::Vec, + iter: RawIter, +} + +impl Default for CachedIter +where + H: Hasher, +{ + fn default() -> Self { + Self { last_key: Default::default(), iter: Default::default() } } } +#[cfg(feature = "std")] +type CacheCell = parking_lot::Mutex; + +#[cfg(not(feature = "std"))] +type CacheCell = core::cell::RefCell; + +#[cfg(feature = "std")] +fn access_cache(cell: &CacheCell, callback: impl FnOnce(&mut T) -> R) -> R { + callback(&mut *cell.lock()) +} + +#[cfg(not(feature = "std"))] +fn access_cache(cell: &CacheCell, callback: impl FnOnce(&mut T) -> R) -> R { + callback(&mut *cell.borrow_mut()) +} + /// Patricia trie-based backend. Transaction type is an overlay of changes to commit. pub struct TrieBackend, H: Hasher, C = LocalTrieCache> { pub(crate) essence: TrieBackendEssence, + next_storage_key_cache: CacheCell>>, } impl, H: Hasher, C: AsLocalTrieCache + Send + Sync> TrieBackend where H::Out: Codec, { + #[cfg(test)] + pub(crate) fn from_essence(essence: TrieBackendEssence) -> Self { + Self { essence, next_storage_key_cache: Default::default() } + } + /// Get backend essence reference. pub fn essence(&self) -> &TrieBackendEssence { &self.essence @@ -265,7 +309,40 @@ where } fn next_storage_key(&self, key: &[u8]) -> Result, Self::Error> { - self.essence.next_storage_key(key) + let (is_cached, mut cache) = access_cache(&self.next_storage_key_cache, Option::take) + .map(|cache| (cache.last_key == key, cache)) + .unwrap_or_default(); + + if !is_cached { + cache.iter = self.raw_iter(IterArgs { + start_at: Some(key), + start_at_exclusive: true, + ..IterArgs::default() + })? + }; + + let next_key = match cache.iter.next_key(self) { + None => return Ok(None), + Some(Err(error)) => return Err(error), + Some(Ok(next_key)) => next_key, + }; + + cache.last_key.clear(); + cache.last_key.extend_from_slice(&next_key); + access_cache(&self.next_storage_key_cache, |cache_cell| cache_cell.replace(cache)); + + #[cfg(debug_assertions)] + debug_assert_eq!( + self.essence + .next_storage_key_slow(key) + .expect( + "fetching the next key through iterator didn't fail so this shouldn't either" + ) + .as_ref(), + Some(&next_key) + ); + + Ok(Some(next_key)) } fn next_child_storage_key( diff --git a/primitives/state-machine/src/trie_backend_essence.rs b/primitives/state-machine/src/trie_backend_essence.rs index f071a32cede89..1f6d71b2dce80 100644 --- a/primitives/state-machine/src/trie_backend_essence.rs +++ b/primitives/state-machine/src/trie_backend_essence.rs @@ -415,9 +415,14 @@ where }) } - /// Return the next key in the trie i.e. the minimum key that is strictly superior to `key` in + /// Returns 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> { + /// + /// Will always traverse the trie from scratch in search of the key, which is slow. + /// Used only when debug assertions are enabled to crosscheck the results of finding + /// the next key through an iterator. + #[cfg(debug_assertions)] + pub fn next_storage_key_slow(&self, key: &[u8]) -> Result> { self.next_storage_key_from_root(&self.root, None, key) } @@ -859,6 +864,7 @@ impl, H: Hasher, C: AsLocalTrieCache + Send + Sync> #[cfg(test)] mod test { use super::*; + use crate::{Backend, TrieBackend}; use sp_core::{Blake2Hasher, H256}; use sp_trie::{ cache::LocalTrieCache, trie_types::TrieDBMutBuilderV1 as TrieDBMutBuilder, KeySpacedDBMut, @@ -897,6 +903,8 @@ mod test { }; let essence_1 = TrieBackendEssence::<_, _, LocalTrieCache<_>>::new(mdb, root_1); + let mdb = essence_1.backend_storage().clone(); + let essence_1 = TrieBackend::from_essence(essence_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()))); @@ -904,7 +912,6 @@ 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.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()))); diff --git a/primitives/trie/Cargo.toml b/primitives/trie/Cargo.toml index 33a62cdd94084..fae39ec34c0ea 100644 --- a/primitives/trie/Cargo.toml +++ b/primitives/trie/Cargo.toml @@ -29,7 +29,7 @@ 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 } -trie-db = { version = "0.25.0", default-features = false } +trie-db = { version = "0.26.0", default-features = false } trie-root = { version = "0.17.0", default-features = false } sp-core = { version = "7.0.0", default-features = false, path = "../core" } sp-std = { version = "5.0.0", default-features = false, path = "../std" } @@ -38,7 +38,7 @@ schnellru = { version = "0.2.1", optional = true } [dev-dependencies] array-bytes = "4.1" criterion = "0.4.0" -trie-bench = "0.35.0" +trie-bench = "0.36.0" trie-standardmap = "0.15.2" sp-runtime = { version = "7.0.0", path = "../runtime" } diff --git a/test-utils/runtime/Cargo.toml b/test-utils/runtime/Cargo.toml index 339a435ef2a04..e0f414b161cf5 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-consensus-grandpa = { version = "4.0.0-dev", default-features = false, path = "../../primitives/consensus/grandpa" } 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.25.1", default-features = false } +trie-db = { version = "0.26.0", default-features = false } 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" } diff --git a/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml b/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml index 1dd9da9a56fee..e6eccc6ff62e0 100644 --- a/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml +++ b/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml @@ -21,7 +21,7 @@ log = { version = "0.4.17", default-features = false } sp-core = { path = "../../../../primitives/core" } sp-state-machine = { path = "../../../../primitives/state-machine" } sp-trie = { path = "../../../../primitives/trie" } -trie-db = "0.25.1" +trie-db = "0.26.0" jsonrpsee = { version = "0.16.2", features = ["client-core", "server", "macros"] } From 5cd48479c5766161729666ac99091e60d7b8fef5 Mon Sep 17 00:00:00 2001 From: Dmitry Markin Date: Wed, 1 Mar 2023 12:54:31 +0300 Subject: [PATCH 451/715] Make unbounded channels size warning exact (part 1) (#13490) * Replace `futures-channel` with `async-channel` in `out_events` * Apply suggestions from code review Co-authored-by: Koute * Also print the backtrace of `send()` call * Switch from `backtrace` crate to `std::backtrace` * Remove outdated `backtrace` dependency * Remove `backtrace` from `Cargo.lock` --------- Co-authored-by: Koute --- Cargo.lock | 13 ++++++- client/network/Cargo.toml | 2 +- client/network/src/service/out_events.rs | 48 ++++++++++-------------- 3 files changed, 32 insertions(+), 31 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a8f596c0684ef..f37a3b41f2f0b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -326,6 +326,17 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" +[[package]] +name = "async-channel" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf46fee83e5ccffc220104713af3292ff9bc7c64c7de289f66dae8e38d826833" +dependencies = [ + "concurrent-queue", + "event-listener", + "futures-core", +] + [[package]] name = "async-io" version = "1.12.0" @@ -8626,9 +8637,9 @@ version = "0.10.0-dev" dependencies = [ "array-bytes", "assert_matches", + "async-channel", "async-trait", "asynchronous-codec", - "backtrace", "bytes", "either", "fnv", diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index b6b21247128d7..5a918bebd626e 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -15,9 +15,9 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] array-bytes = "4.1" +async-channel = "1.8.0" async-trait = "0.1" asynchronous-codec = "0.6" -backtrace = "0.3.67" bytes = "1" codec = { package = "parity-scale-codec", version = "3.2.2", features = ["derive"] } either = "1.5.3" diff --git a/client/network/src/service/out_events.rs b/client/network/src/service/out_events.rs index 57a5092ae62ea..99ac022c2d8b6 100644 --- a/client/network/src/service/out_events.rs +++ b/client/network/src/service/out_events.rs @@ -31,20 +31,17 @@ //! - Send events by calling [`OutChannels::send`]. Events are cloned for each sender in the //! collection. -use backtrace::Backtrace; -use futures::{channel::mpsc, prelude::*, ready, stream::FusedStream}; +use futures::{prelude::*, ready, stream::FusedStream}; use log::error; use parking_lot::Mutex; use prometheus_endpoint::{register, CounterVec, GaugeVec, Opts, PrometheusError, Registry, U64}; use sc_network_common::protocol::event::Event; use std::{ + backtrace::Backtrace, cell::RefCell, fmt, pin::Pin, - sync::{ - atomic::{AtomicI64, Ordering}, - Arc, - }, + sync::Arc, task::{Context, Poll}, }; @@ -52,20 +49,18 @@ use std::{ /// /// The name is used in Prometheus reports, the queue size threshold is used /// to warn if there are too many unprocessed events in the channel. -pub fn channel(name: &'static str, queue_size_warning: i64) -> (Sender, Receiver) { - let (tx, rx) = mpsc::unbounded(); +pub fn channel(name: &'static str, queue_size_warning: usize) -> (Sender, Receiver) { + let (tx, rx) = async_channel::unbounded(); let metrics = Arc::new(Mutex::new(None)); - let queue_size = Arc::new(AtomicI64::new(0)); let tx = Sender { inner: tx, name, - queue_size: queue_size.clone(), queue_size_warning, warning_fired: false, - creation_backtrace: Backtrace::new_unresolved(), + creation_backtrace: Backtrace::force_capture(), metrics: metrics.clone(), }; - let rx = Receiver { inner: rx, name, queue_size, metrics }; + let rx = Receiver { inner: rx, name, metrics }; (tx, rx) } @@ -77,16 +72,11 @@ pub fn channel(name: &'static str, queue_size_warning: i64) -> (Sender, Receiver /// implement the `Clone` trait e.g. in Order to not complicate the logic keeping the metrics in /// sync on drop. If someone adds a `#[derive(Clone)]` below, it is **wrong**. pub struct Sender { - inner: mpsc::UnboundedSender, + inner: async_channel::Sender, /// Name to identify the channel (e.g., in Prometheus and logs). name: &'static str, - /// Number of events in the queue. Clone of [`Receiver::in_transit`]. - // To not bother with ordering and possible underflow errors of the unsigned counter - // we just use `i64` and `Ordering::Relaxed`, and perceive `queue_size` as approximate. - // It can turn < 0 though. - queue_size: Arc, /// Threshold queue size to generate an error message in the logs. - queue_size_warning: i64, + queue_size_warning: usize, /// We generate the error message only once to not spam the logs. warning_fired: bool, /// Backtrace of a place where the channel was created. @@ -113,9 +103,8 @@ impl Drop for Sender { /// Receiving side of a channel. pub struct Receiver { - inner: mpsc::UnboundedReceiver, + inner: async_channel::Receiver, name: &'static str, - queue_size: Arc, /// Initially contains `None`, and will be set to a value once the corresponding [`Sender`] /// is assigned to an instance of [`OutChannels`]. metrics: Arc>>>>, @@ -126,7 +115,6 @@ impl Stream for Receiver { fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll> { if let Some(ev) = ready!(Pin::new(&mut self.inner).poll_next(cx)) { - let _ = self.queue_size.fetch_sub(1, Ordering::Relaxed); let metrics = self.metrics.lock().clone(); match metrics.as_ref().map(|m| m.as_ref()) { Some(Some(metrics)) => metrics.event_out(&ev, self.name), @@ -191,17 +179,19 @@ impl OutChannels { /// Sends an event. pub fn send(&mut self, event: Event) { self.event_streams.retain_mut(|sender| { - let queue_size = sender.queue_size.fetch_add(1, Ordering::Relaxed); - if queue_size == sender.queue_size_warning && !sender.warning_fired { + if sender.inner.len() >= sender.queue_size_warning && !sender.warning_fired { sender.warning_fired = true; - sender.creation_backtrace.resolve(); error!( - "The number of unprocessed events in channel `{}` reached {}.\n\ - The channel was created at:\n{:?}", - sender.name, sender.queue_size_warning, sender.creation_backtrace, + "The number of unprocessed events in channel `{}` exceeded {}.\n\ + The channel was created at:\n{:}\n + The last event was sent from:\n{:}", + sender.name, + sender.queue_size_warning, + sender.creation_backtrace, + Backtrace::force_capture(), ); } - sender.inner.unbounded_send(event.clone()).is_ok() + sender.inner.try_send(event.clone()).is_ok() }); if let Some(metrics) = &*self.metrics { From 8ae4738bd7ee57556ea42c33600dc95488b58db6 Mon Sep 17 00:00:00 2001 From: Anthony Lazam Date: Wed, 1 Mar 2023 19:15:18 +0800 Subject: [PATCH 452/715] Removal of Prometheus alerting rules deployment in cloud-infra (#13499) --- .gitlab-ci.yml | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 12a1ff825d162..336e97cdd4433 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -311,28 +311,6 @@ include: rules: - if: $PIPELINE != "automatic-crate-publishing" -#### stage: deploy - -deploy-prometheus-alerting-rules: - stage: deploy - needs: - - job: test-prometheus-alerting-rules - artifacts: false - allow_failure: true - trigger: - project: parity/infrastructure/cloud-infra - variables: - SUBSTRATE_CI_COMMIT_NAME: "${CI_COMMIT_REF_NAME}" - SUBSTRATE_CI_COMMIT_REF: "${CI_COMMIT_SHORT_SHA}" - UPSTREAM_TRIGGER_PROJECT: "${CI_PROJECT_PATH}" - rules: - - if: $CI_PIPELINE_SOURCE == "pipeline" - when: never - - if: $CI_COMMIT_REF_NAME == "master" - changes: - - .gitlab-ci.yml - - ./scripts/ci/monitoring/**/* - #### stage: notify # This job notifies rusty-cachier about the latest commit with the cache. From 39865603b6ff020395177becc32fc6744c364779 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= <123550+andresilva@users.noreply.github.com> Date: Wed, 1 Mar 2023 13:04:57 +0000 Subject: [PATCH 453/715] sp-consensus: remove unused error variants (#13495) --- Cargo.lock | 3 -- client/consensus/pow/src/lib.rs | 3 +- primitives/consensus/common/Cargo.toml | 5 -- primitives/consensus/common/src/error.rs | 69 +++++------------------- 4 files changed, 15 insertions(+), 65 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f37a3b41f2f0b..b7c7a813fede1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9879,14 +9879,11 @@ dependencies = [ "async-trait", "futures", "log", - "parity-scale-codec", "sp-core", "sp-inherents", "sp-runtime", "sp-state-machine", - "sp-std", "sp-test-primitives", - "sp-version", "thiserror", ] diff --git a/client/consensus/pow/src/lib.rs b/client/consensus/pow/src/lib.rs index 44eaccd2a40ac..513386fb22ac0 100644 --- a/client/consensus/pow/src/lib.rs +++ b/client/consensus/pow/src/lib.rs @@ -331,7 +331,8 @@ 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)) + .map_err(ConsensusError::ChainLookup)?; let best_hash = best_header.hash(); let parent_hash = *block.header.parent_hash(); diff --git a/primitives/consensus/common/Cargo.toml b/primitives/consensus/common/Cargo.toml index 83b09f9eb47e2..1179261340f6e 100644 --- a/primitives/consensus/common/Cargo.toml +++ b/primitives/consensus/common/Cargo.toml @@ -15,9 +15,6 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-trait = "0.1.57" -codec = { package = "parity-scale-codec", version = "3.2.2", features = [ - "derive", -] } futures = { version = "0.3.21", features = ["thread-pool"] } log = "0.4.17" thiserror = "1.0.30" @@ -25,8 +22,6 @@ sp-core = { version = "7.0.0", path = "../../core" } sp-inherents = { version = "4.0.0-dev", path = "../../inherents" } 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] futures = "0.3.21" diff --git a/primitives/consensus/common/src/error.rs b/primitives/consensus/common/src/error.rs index 33c1afa63fe70..e881259da11e4 100644 --- a/primitives/consensus/common/src/error.rs +++ b/primitives/consensus/common/src/error.rs @@ -15,85 +15,42 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Error types in Consensus -use sp_core::ed25519::Public; -use sp_version::RuntimeVersion; -use std::error; +//! Error types for consensus modules. /// Result type alias. pub type Result = std::result::Result; -/// Error type. +/// The error type for consensus-related operations. #[derive(Debug, thiserror::Error)] -#[non_exhaustive] pub enum Error { /// Missing state at block with given descriptor. #[error("State unavailable at block {0}")] StateUnavailable(String), - /// I/O terminated unexpectedly - #[error("I/O terminated unexpectedly.")] - IoTerminated, /// Intermediate missing. - #[error("Missing intermediate.")] + #[error("Missing intermediate")] NoIntermediate, /// Intermediate is of wrong type. - #[error("Invalid intermediate.")] + #[error("Invalid intermediate")] InvalidIntermediate, - /// Unable to schedule wake-up. - #[error("Timer error: {0}")] - FaultyTimer(#[from] std::io::Error), - /// Error while working with inherent data. - #[error("InherentData error: {0}")] - InherentData(#[from] sp_inherents::Error), - /// Unable to propose a block. - #[error("Unable to create block proposal.")] - CannotPropose, - /// Error checking signature - #[error("Message signature {0:?} by {1:?} is invalid.")] + /// Error checking signature. + #[error("Message signature {0:?} by {1:?} is invalid")] InvalidSignature(Vec, Vec), /// Invalid authorities set received from the runtime. #[error("Current state of blockchain has invalid authorities set")] InvalidAuthoritiesSet, - /// Account is not an authority. - #[error("Message sender {0:?} is not a valid authority")] - InvalidAuthority(Public), - /// Authoring interface does not match the runtime. - #[error( - "Authoring for current \ - runtime is not supported. Native ({native}) cannot author for on-chain ({on_chain})." - )] - IncompatibleAuthoringRuntime { native: RuntimeVersion, on_chain: RuntimeVersion }, - /// Authoring interface does not match the runtime. - #[error("Authoring for current runtime is not supported since it has no version.")] - RuntimeVersionMissing, - /// Authoring interface does not match the runtime. - #[error("Authoring in current build is not supported since it has no runtime.")] - NativeRuntimeMissing, /// Justification requirements not met. - #[error("Invalid justification.")] + #[error("Invalid justification")] InvalidJustification, - /// Some other error. - #[error(transparent)] - Other(#[from] Box), - /// Error from the client while importing + /// Error from the client while importing. #[error("Import failed: {0}")] ClientImport(String), - /// Error from the client while importing + /// Error from the client while fetching some data from the chain. #[error("Chain lookup failed: {0}")] ChainLookup(String), - /// Signing failed + /// Signing failed. #[error("Failed to sign using key: {0:?}. Reason: {1}")] CannotSign(Vec, String), -} - -impl From for Error { - fn from(p: Public) -> Self { - Self::InvalidAuthority(p) - } -} - -impl From for Error { - fn from(s: String) -> Self { - Self::StateUnavailable(s) - } + /// Some other error. + #[error(transparent)] + Other(#[from] Box), } From 376ada82d77503d099a61fd198a3089caf7920c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Miko=C5=82ajczyk?= Date: Wed, 1 Mar 2023 14:35:32 +0100 Subject: [PATCH 454/715] Expose `ChargedAmount` (#13488) * Expose `ChargedAmount` * Fix imports --- frame/contracts/src/chain_extension.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/frame/contracts/src/chain_extension.rs b/frame/contracts/src/chain_extension.rs index 9b94542547ea8..56d41a759391b 100644 --- a/frame/contracts/src/chain_extension.rs +++ b/frame/contracts/src/chain_extension.rs @@ -71,7 +71,6 @@ //! on how to use a chain extension in order to provide new features to ink! contracts. use crate::{ - gas::ChargedAmount, wasm::{Runtime, RuntimeCosts}, Error, }; @@ -80,7 +79,7 @@ use frame_support::weights::Weight; use sp_runtime::DispatchError; use sp_std::{marker::PhantomData, vec::Vec}; -pub use crate::{exec::Ext, Config}; +pub use crate::{exec::Ext, gas::ChargedAmount, Config}; pub use frame_system::Config as SysConfig; pub use pallet_contracts_primitives::ReturnFlags; From 024bfcedb15c8421a90f0834f73a7b529c502c0b Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Wed, 1 Mar 2023 18:04:09 +0200 Subject: [PATCH 455/715] sc-consensus-beefy: fix metrics: use correct names (#13494) Signed-off-by: acatangiu --- client/consensus/beefy/src/metrics.rs | 34 +++++++++++++++++++++------ 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/client/consensus/beefy/src/metrics.rs b/client/consensus/beefy/src/metrics.rs index 85438f1ca7cd6..0ce48e60ebc84 100644 --- a/client/consensus/beefy/src/metrics.rs +++ b/client/consensus/beefy/src/metrics.rs @@ -18,7 +18,8 @@ //! BEEFY Prometheus metrics definition -use log::debug; +use crate::LOG_TARGET; +use log::{debug, error}; use prometheus::{register, Counter, Gauge, PrometheusError, Registry, U64}; /// Helper trait for registering BEEFY metrics to Prometheus registry. @@ -129,13 +130,13 @@ impl PrometheusRegister for VoterMetrics { )?, beefy_equivocation_votes: register( Counter::new( - "substrate_beefy_stale_votes", + "substrate_beefy_equivocation_votes", "Number of equivocation votes received", )?, registry, )?, beefy_invalid_votes: register( - Counter::new("substrate_beefy_stale_votes", "Number of invalid votes received")?, + Counter::new("substrate_beefy_invalid_votes", "Number of invalid votes received")?, registry, )?, beefy_stale_votes: register( @@ -200,14 +201,14 @@ impl PrometheusRegister for BlockImportMetrics { beefy_good_justification_imports: register( Counter::new( "substrate_beefy_good_justification_imports", - "Number of Good Justification imports", + "Number of good justifications on block-import", )?, registry, )?, beefy_bad_justification_imports: register( Counter::new( "substrate_beefy_bad_justification_imports", - "Number of Bad Justification imports", + "Number of bad justifications on block-import", )?, registry, )?, @@ -309,11 +310,16 @@ pub(crate) fn register_metrics( ) -> Option { prometheus_registry.as_ref().map(T::register).and_then(|result| match result { Ok(metrics) => { - debug!(target: "beefy", "🥩 Registered {} metrics", T::DESCRIPTION); + debug!(target: LOG_TARGET, "🥩 Registered {} metrics", T::DESCRIPTION); Some(metrics) }, Err(err) => { - debug!(target: "beefy", "🥩 Failed to register {} metrics: {:?}", T::DESCRIPTION, err); + error!( + target: LOG_TARGET, + "🥩 Failed to register {} metrics: {:?}", + T::DESCRIPTION, + err + ); None }, }) @@ -347,3 +353,17 @@ macro_rules! metric_get { $self.metrics.as_ref().map(|metrics| metrics.$m.clone()) }}; } + +#[cfg(test)] +pub(crate) mod tests { + use super::*; + + #[test] + fn should_register_metrics() { + let registry = Some(Registry::new()); + assert!(register_metrics::(registry.clone()).is_some()); + assert!(register_metrics::(registry.clone()).is_some()); + assert!(register_metrics::(registry.clone()).is_some()); + assert!(register_metrics::(registry.clone()).is_some()); + } +} From 4aa213ce1aef94f97836e7ceec753e2a131c849a Mon Sep 17 00:00:00 2001 From: Sergej Sakac <73715684+Szegoo@users.noreply.github.com> Date: Thu, 2 Mar 2023 11:16:47 +0100 Subject: [PATCH 456/715] Assets pallet: Giving the asset owner the ability to set minimum balance (#13486) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * set_min_balance * allow when new_min_balance < old_min_balance * add more specific event * Update frame/assets/src/lib.rs Co-authored-by: Bastian Köcher * Update frame/assets/src/lib.rs Co-authored-by: Bastian Köcher * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_assets * use actual weight --------- Co-authored-by: Bastian Köcher Co-authored-by: command-bot <> --- frame/assets/src/benchmarking.rs | 7 + frame/assets/src/lib.rs | 45 ++++ frame/assets/src/tests.rs | 29 ++ frame/assets/src/weights.rs | 442 ++++++++++++++++++------------- 4 files changed, 337 insertions(+), 186 deletions(-) diff --git a/frame/assets/src/benchmarking.rs b/frame/assets/src/benchmarking.rs index 4fe951f56edf3..0538e955b2c09 100644 --- a/frame/assets/src/benchmarking.rs +++ b/frame/assets/src/benchmarking.rs @@ -471,5 +471,12 @@ benchmarks_instance_pallet! { assert_last_event::(Event::ApprovalCancelled { asset_id: asset_id.into(), owner: caller, delegate }.into()); } + set_min_balance { + let (asset_id, caller, caller_lookup) = create_default_asset::(true); + }: _(SystemOrigin::Signed(caller.clone()), asset_id, 50u32.into()) + verify { + assert_last_event::(Event::AssetMinBalanceChanged { asset_id: asset_id.into(), new_min_balance: 50u32.into() }.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 894f8f3a4ab93..96da078065839 100644 --- a/frame/assets/src/lib.rs +++ b/frame/assets/src/lib.rs @@ -514,6 +514,8 @@ pub mod pallet { }, /// An asset has had its attributes changed by the `Force` origin. AssetStatusChanged { asset_id: T::AssetId }, + /// The min_balance of an asset has been updated by the asset owner. + AssetMinBalanceChanged { asset_id: T::AssetId, new_min_balance: T::Balance }, } #[pallet::error] @@ -1511,6 +1513,49 @@ pub mod pallet { let id: T::AssetId = id.into(); Self::do_refund(id, ensure_signed(origin)?, allow_burn) } + + /// Sets the minimum balance of an asset. + /// + /// Only works if there aren't any accounts that are holding the asset or if + /// the new value of `min_balance` is less than the old one. + /// + /// Origin must be Signed and the sender has to be the Owner of the + /// asset `id`. + /// + /// - `id`: The identifier of the asset. + /// - `min_balance`: The new value of `min_balance`. + /// + /// Emits `AssetMinBalanceChanged` event when successful. + #[pallet::call_index(28)] + #[pallet::weight(T::WeightInfo::set_min_balance())] + pub fn set_min_balance( + origin: OriginFor, + id: T::AssetIdParameter, + min_balance: T::Balance, + ) -> DispatchResult { + let origin = ensure_signed(origin)?; + let id: T::AssetId = id.into(); + + let mut details = Asset::::get(id).ok_or(Error::::Unknown)?; + ensure!(origin == details.owner, Error::::NoPermission); + + let old_min_balance = details.min_balance; + // Ensure that either the new min_balance is less than old min_balance or there aren't + // any accounts holding the asset. + ensure!( + min_balance < old_min_balance || details.accounts == 0, + Error::::NoPermission + ); + + details.min_balance = min_balance; + Asset::::insert(&id, details); + + Self::deposit_event(Event::AssetMinBalanceChanged { + asset_id: id, + new_min_balance: min_balance, + }); + Ok(()) + } } } diff --git a/frame/assets/src/tests.rs b/frame/assets/src/tests.rs index 6a3fd672a759c..e76e989ef8932 100644 --- a/frame/assets/src/tests.rs +++ b/frame/assets/src/tests.rs @@ -1091,6 +1091,35 @@ fn force_asset_status_should_work() { }); } +#[test] +fn set_min_balance_should_work() { + new_test_ext().execute_with(|| { + let id = 42; + Balances::make_free_balance_be(&1, 10); + assert_ok!(Assets::create(RuntimeOrigin::signed(1), id, 1, 30)); + + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), id, 1, 50)); + // won't execute because there is an asset holder. + assert_noop!( + Assets::set_min_balance(RuntimeOrigin::signed(1), id, 50), + Error::::NoPermission + ); + + // will execute because the new value of min_balance is less than the + // old value. 10 < 30 + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), id, 1, 10)); + + assert_ok!(Assets::burn(RuntimeOrigin::signed(1), id, 1, 50)); + assert_noop!( + Assets::set_min_balance(RuntimeOrigin::signed(2), id, 50), + Error::::NoPermission + ); + + assert_ok!(Assets::set_min_balance(RuntimeOrigin::signed(1), id, 50)); + assert_eq!(Asset::::get(id).unwrap().min_balance, 50); + }); +} + #[test] fn balance_conversion_should_work() { new_test_ext().execute_with(|| { diff --git a/frame/assets/src/weights.rs b/frame/assets/src/weights.rs index 9ebba62237091..27de4fa333687 100644 --- a/frame/assets/src/weights.rs +++ b/frame/assets/src/weights.rs @@ -18,25 +18,26 @@ //! Autogenerated weights for pallet_assets //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-02-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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 // --steps=50 // --repeat=20 -// --pallet=pallet_assets // --extrinsic=* // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/assets/src/weights.rs +// --json-file=/var/lib/gitlab-runner/builds/zyw4fam_/0/parity/mirrors/substrate/.git/.artifacts/bench.json +// --pallet=pallet_assets +// --chain=dev // --header=./HEADER-APACHE2 +// --output=./frame/assets/src/weights.rs // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -74,6 +75,7 @@ pub trait WeightInfo { fn transfer_approved() -> Weight; fn cancel_approval() -> Weight; fn force_cancel_approval() -> Weight; + fn set_min_balance() -> Weight; } /// Weights for pallet_assets using the Substrate node and recommended hardware. @@ -86,9 +88,10 @@ impl WeightInfo for SubstrateWeight { fn create() -> Weight { // Proof Size summary in bytes: // Measured: `325` - // Estimated: `5288` - // Minimum execution time: 23_623 nanoseconds. - Weight::from_parts(24_072_000, 5288) + // Estimated: `7268` + // Minimum execution time: 27_887 nanoseconds. + Weight::from_ref_time(28_190_000) + .saturating_add(Weight::from_proof_size(7268)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -97,9 +100,10 @@ impl WeightInfo for SubstrateWeight { fn force_create() -> Weight { // Proof Size summary in bytes: // Measured: `153` - // Estimated: `2685` - // Minimum execution time: 13_145 nanoseconds. - Weight::from_parts(13_572_000, 2685) + // Estimated: `3675` + // Minimum execution time: 15_059 nanoseconds. + Weight::from_ref_time(15_600_000) + .saturating_add(Weight::from_proof_size(3675)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -108,9 +112,10 @@ impl WeightInfo for SubstrateWeight { fn start_destroy() -> Weight { // Proof Size summary in bytes: // Measured: `417` - // Estimated: `2685` - // Minimum execution time: 13_420 nanoseconds. - Weight::from_parts(13_649_000, 2685) + // Estimated: `3675` + // Minimum execution time: 15_581 nanoseconds. + Weight::from_ref_time(15_868_000) + .saturating_add(Weight::from_proof_size(3675)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -124,11 +129,12 @@ impl WeightInfo for SubstrateWeight { fn destroy_accounts(c: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `25 + c * (240 ±0)` - // Estimated: `5262 + c * (5180 ±0)` - // Minimum execution time: 17_565 nanoseconds. - Weight::from_parts(17_757_000, 5262) - // Standard Error: 15_192 - .saturating_add(Weight::from_ref_time(13_799_167).saturating_mul(c.into())) + // Estimated: `8232 + c * (5180 ±0)` + // Minimum execution time: 20_167 nanoseconds. + Weight::from_ref_time(20_436_000) + .saturating_add(Weight::from_proof_size(8232)) + // Standard Error: 12_761 + .saturating_add(Weight::from_ref_time(15_535_268).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(c.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) @@ -143,11 +149,12 @@ impl WeightInfo for SubstrateWeight { fn destroy_approvals(a: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `554 + a * (86 ±0)` - // Estimated: `5308 + a * (2623 ±0)` - // Minimum execution time: 18_251 nanoseconds. - Weight::from_parts(18_359_000, 5308) - // Standard Error: 10_051 - .saturating_add(Weight::from_ref_time(13_613_342).saturating_mul(a.into())) + // Estimated: `7288 + a * (2623 ±0)` + // Minimum execution time: 20_349 nanoseconds. + Weight::from_ref_time(20_482_000) + .saturating_add(Weight::from_proof_size(7288)) + // Standard Error: 9_831 + .saturating_add(Weight::from_ref_time(15_771_918).saturating_mul(a.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(a.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) @@ -161,9 +168,10 @@ impl WeightInfo for SubstrateWeight { fn finish_destroy() -> Weight { // Proof Size summary in bytes: // Measured: `383` - // Estimated: `5300` - // Minimum execution time: 14_344 nanoseconds. - Weight::from_parts(14_619_000, 5300) + // Estimated: `7280` + // Minimum execution time: 15_647 nanoseconds. + Weight::from_ref_time(15_975_000) + .saturating_add(Weight::from_proof_size(7280)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -174,9 +182,10 @@ impl WeightInfo for SubstrateWeight { fn mint() -> Weight { // Proof Size summary in bytes: // Measured: `383` - // Estimated: `5262` - // Minimum execution time: 24_992 nanoseconds. - Weight::from_parts(25_784_000, 5262) + // Estimated: `7242` + // Minimum execution time: 28_383 nanoseconds. + Weight::from_ref_time(29_055_000) + .saturating_add(Weight::from_proof_size(7242)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -187,9 +196,10 @@ impl WeightInfo for SubstrateWeight { fn burn() -> Weight { // Proof Size summary in bytes: // Measured: `491` - // Estimated: `5262` - // Minimum execution time: 31_233 nanoseconds. - Weight::from_parts(31_511_000, 5262) + // Estimated: `7242` + // Minimum execution time: 34_950 nanoseconds. + Weight::from_ref_time(35_296_000) + .saturating_add(Weight::from_proof_size(7242)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -202,9 +212,10 @@ impl WeightInfo for SubstrateWeight { fn transfer() -> Weight { // Proof Size summary in bytes: // Measured: `530` - // Estimated: `10442` - // Minimum execution time: 43_002 nanoseconds. - Weight::from_parts(43_533_000, 10442) + // Estimated: `13412` + // Minimum execution time: 50_129 nanoseconds. + Weight::from_ref_time(50_820_000) + .saturating_add(Weight::from_proof_size(13412)) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -217,9 +228,10 @@ impl WeightInfo for SubstrateWeight { fn transfer_keep_alive() -> Weight { // Proof Size summary in bytes: // Measured: `530` - // Estimated: `10442` - // Minimum execution time: 38_220 nanoseconds. - Weight::from_parts(38_639_000, 10442) + // Estimated: `13412` + // Minimum execution time: 43_424 nanoseconds. + Weight::from_ref_time(44_080_000) + .saturating_add(Weight::from_proof_size(13412)) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -232,9 +244,10 @@ impl WeightInfo for SubstrateWeight { fn force_transfer() -> Weight { // Proof Size summary in bytes: // Measured: `530` - // Estimated: `10442` - // Minimum execution time: 43_171 nanoseconds. - Weight::from_parts(43_543_000, 10442) + // Estimated: `13412` + // Minimum execution time: 48_919 nanoseconds. + Weight::from_ref_time(50_720_000) + .saturating_add(Weight::from_proof_size(13412)) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -245,9 +258,10 @@ impl WeightInfo for SubstrateWeight { fn freeze() -> Weight { // Proof Size summary in bytes: // Measured: `491` - // Estimated: `5262` - // Minimum execution time: 16_972 nanoseconds. - Weight::from_parts(17_498_000, 5262) + // Estimated: `7242` + // Minimum execution time: 19_750 nanoseconds. + Weight::from_ref_time(20_053_000) + .saturating_add(Weight::from_proof_size(7242)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -258,9 +272,10 @@ impl WeightInfo for SubstrateWeight { fn thaw() -> Weight { // Proof Size summary in bytes: // Measured: `491` - // Estimated: `5262` - // Minimum execution time: 17_471 nanoseconds. - Weight::from_parts(17_842_000, 5262) + // Estimated: `7242` + // Minimum execution time: 19_672 nanoseconds. + Weight::from_ref_time(19_928_000) + .saturating_add(Weight::from_proof_size(7242)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -269,9 +284,10 @@ impl WeightInfo for SubstrateWeight { fn freeze_asset() -> Weight { // Proof Size summary in bytes: // Measured: `417` - // Estimated: `2685` - // Minimum execution time: 13_497 nanoseconds. - Weight::from_parts(13_719_000, 2685) + // Estimated: `3675` + // Minimum execution time: 15_367 nanoseconds. + Weight::from_ref_time(15_726_000) + .saturating_add(Weight::from_proof_size(3675)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -280,9 +296,10 @@ impl WeightInfo for SubstrateWeight { fn thaw_asset() -> Weight { // Proof Size summary in bytes: // Measured: `417` - // Estimated: `2685` - // Minimum execution time: 13_424 nanoseconds. - Weight::from_parts(13_764_000, 2685) + // Estimated: `3675` + // Minimum execution time: 14_814 nanoseconds. + Weight::from_ref_time(15_301_000) + .saturating_add(Weight::from_proof_size(3675)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -293,9 +310,10 @@ impl WeightInfo for SubstrateWeight { fn transfer_ownership() -> Weight { // Proof Size summary in bytes: // Measured: `383` - // Estimated: `5300` - // Minimum execution time: 15_028 nanoseconds. - Weight::from_parts(15_366_000, 5300) + // Estimated: `7280` + // Minimum execution time: 17_426 nanoseconds. + Weight::from_ref_time(17_804_000) + .saturating_add(Weight::from_proof_size(7280)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -304,9 +322,10 @@ impl WeightInfo for SubstrateWeight { fn set_team() -> Weight { // Proof Size summary in bytes: // Measured: `383` - // Estimated: `2685` - // Minimum execution time: 14_197 nanoseconds. - Weight::from_parts(14_437_000, 2685) + // Estimated: `3675` + // Minimum execution time: 15_935 nanoseconds. + Weight::from_ref_time(16_165_000) + .saturating_add(Weight::from_proof_size(3675)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -316,16 +335,15 @@ impl WeightInfo for SubstrateWeight { /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) /// The range of component `n` is `[0, 50]`. /// The range of component `s` is `[0, 50]`. - fn set_metadata(n: u32, s: u32, ) -> Weight { + fn set_metadata(n: u32, _s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `383` - // Estimated: `5300` - // Minimum execution time: 23_707 nanoseconds. - Weight::from_parts(24_466_834, 5300) - // Standard Error: 635 - .saturating_add(Weight::from_ref_time(730).saturating_mul(n.into())) - // Standard Error: 635 - .saturating_add(Weight::from_ref_time(3_975).saturating_mul(s.into())) + // Estimated: `7280` + // Minimum execution time: 26_890 nanoseconds. + Weight::from_ref_time(28_766_510) + .saturating_add(Weight::from_proof_size(7280)) + // Standard Error: 7_444 + .saturating_add(Weight::from_ref_time(3_619).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -336,9 +354,10 @@ impl WeightInfo for SubstrateWeight { fn clear_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `579` - // Estimated: `5300` - // Minimum execution time: 23_997 nanoseconds. - Weight::from_parts(24_812_000, 5300) + // Estimated: `7280` + // Minimum execution time: 27_146 nanoseconds. + Weight::from_ref_time(27_692_000) + .saturating_add(Weight::from_proof_size(7280)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -348,14 +367,13 @@ impl WeightInfo for SubstrateWeight { /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) /// The range of component `n` is `[0, 50]`. /// The range of component `s` is `[0, 50]`. - fn force_set_metadata(_n: u32, s: u32, ) -> Weight { + fn force_set_metadata(_n: u32, _s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `190` - // Estimated: `5300` - // Minimum execution time: 14_028 nanoseconds. - Weight::from_parts(15_217_669, 5300) - // Standard Error: 2_266 - .saturating_add(Weight::from_ref_time(2_045).saturating_mul(s.into())) + // Estimated: `7280` + // Minimum execution time: 16_181 nanoseconds. + Weight::from_ref_time(18_317_178) + .saturating_add(Weight::from_proof_size(7280)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -366,9 +384,10 @@ impl WeightInfo for SubstrateWeight { fn force_clear_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `579` - // Estimated: `5300` - // Minimum execution time: 23_754 nanoseconds. - Weight::from_parts(24_154_000, 5300) + // Estimated: `7280` + // Minimum execution time: 26_962 nanoseconds. + Weight::from_ref_time(27_896_000) + .saturating_add(Weight::from_proof_size(7280)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -377,9 +396,10 @@ impl WeightInfo for SubstrateWeight { fn force_asset_status() -> Weight { // Proof Size summary in bytes: // Measured: `383` - // Estimated: `2685` - // Minimum execution time: 13_128 nanoseconds. - Weight::from_parts(13_428_000, 2685) + // Estimated: `3675` + // Minimum execution time: 14_394 nanoseconds. + Weight::from_ref_time(14_917_000) + .saturating_add(Weight::from_proof_size(3675)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -390,9 +410,10 @@ impl WeightInfo for SubstrateWeight { fn approve_transfer() -> Weight { // Proof Size summary in bytes: // Measured: `417` - // Estimated: `5308` - // Minimum execution time: 27_224 nanoseconds. - Weight::from_parts(27_665_000, 5308) + // Estimated: `7288` + // Minimum execution time: 30_861 nanoseconds. + Weight::from_ref_time(31_356_000) + .saturating_add(Weight::from_proof_size(7288)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -407,9 +428,10 @@ impl WeightInfo for SubstrateWeight { fn transfer_approved() -> Weight { // Proof Size summary in bytes: // Measured: `700` - // Estimated: `13065` - // Minimum execution time: 55_837 nanoseconds. - Weight::from_parts(56_636_000, 13065) + // Estimated: `17025` + // Minimum execution time: 64_510 nanoseconds. + Weight::from_ref_time(65_676_000) + .saturating_add(Weight::from_proof_size(17025)) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -420,9 +442,10 @@ impl WeightInfo for SubstrateWeight { fn cancel_approval() -> Weight { // Proof Size summary in bytes: // Measured: `587` - // Estimated: `5308` - // Minimum execution time: 28_915 nanoseconds. - Weight::from_parts(29_325_000, 5308) + // Estimated: `7288` + // Minimum execution time: 32_620 nanoseconds. + Weight::from_ref_time(33_183_000) + .saturating_add(Weight::from_proof_size(7288)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -433,12 +456,25 @@ impl WeightInfo for SubstrateWeight { fn force_cancel_approval() -> Weight { // Proof Size summary in bytes: // Measured: `587` - // Estimated: `5308` - // Minimum execution time: 29_103 nanoseconds. - Weight::from_parts(29_599_000, 5308) + // Estimated: `7288` + // Minimum execution time: 33_277 nanoseconds. + Weight::from_ref_time(34_438_000) + .saturating_add(Weight::from_proof_size(7288)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + fn set_min_balance() -> Weight { + // Proof Size summary in bytes: + // Measured: `383` + // Estimated: `3675` + // Minimum execution time: 16_213 nanoseconds. + Weight::from_ref_time(16_575_000) + .saturating_add(Weight::from_proof_size(3675)) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } } // For backwards compatibility and tests @@ -450,9 +486,10 @@ impl WeightInfo for () { fn create() -> Weight { // Proof Size summary in bytes: // Measured: `325` - // Estimated: `5288` - // Minimum execution time: 23_623 nanoseconds. - Weight::from_parts(24_072_000, 5288) + // Estimated: `7268` + // Minimum execution time: 27_887 nanoseconds. + Weight::from_ref_time(28_190_000) + .saturating_add(Weight::from_proof_size(7268)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -461,9 +498,10 @@ impl WeightInfo for () { fn force_create() -> Weight { // Proof Size summary in bytes: // Measured: `153` - // Estimated: `2685` - // Minimum execution time: 13_145 nanoseconds. - Weight::from_parts(13_572_000, 2685) + // Estimated: `3675` + // Minimum execution time: 15_059 nanoseconds. + Weight::from_ref_time(15_600_000) + .saturating_add(Weight::from_proof_size(3675)) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -472,9 +510,10 @@ impl WeightInfo for () { fn start_destroy() -> Weight { // Proof Size summary in bytes: // Measured: `417` - // Estimated: `2685` - // Minimum execution time: 13_420 nanoseconds. - Weight::from_parts(13_649_000, 2685) + // Estimated: `3675` + // Minimum execution time: 15_581 nanoseconds. + Weight::from_ref_time(15_868_000) + .saturating_add(Weight::from_proof_size(3675)) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -488,11 +527,12 @@ impl WeightInfo for () { fn destroy_accounts(c: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `25 + c * (240 ±0)` - // Estimated: `5262 + c * (5180 ±0)` - // Minimum execution time: 17_565 nanoseconds. - Weight::from_parts(17_757_000, 5262) - // Standard Error: 15_192 - .saturating_add(Weight::from_ref_time(13_799_167).saturating_mul(c.into())) + // Estimated: `8232 + c * (5180 ±0)` + // Minimum execution time: 20_167 nanoseconds. + Weight::from_ref_time(20_436_000) + .saturating_add(Weight::from_proof_size(8232)) + // Standard Error: 12_761 + .saturating_add(Weight::from_ref_time(15_535_268).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(c.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) @@ -507,11 +547,12 @@ impl WeightInfo for () { fn destroy_approvals(a: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `554 + a * (86 ±0)` - // Estimated: `5308 + a * (2623 ±0)` - // Minimum execution time: 18_251 nanoseconds. - Weight::from_parts(18_359_000, 5308) - // Standard Error: 10_051 - .saturating_add(Weight::from_ref_time(13_613_342).saturating_mul(a.into())) + // Estimated: `7288 + a * (2623 ±0)` + // Minimum execution time: 20_349 nanoseconds. + Weight::from_ref_time(20_482_000) + .saturating_add(Weight::from_proof_size(7288)) + // Standard Error: 9_831 + .saturating_add(Weight::from_ref_time(15_771_918).saturating_mul(a.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(a.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) @@ -525,9 +566,10 @@ impl WeightInfo for () { fn finish_destroy() -> Weight { // Proof Size summary in bytes: // Measured: `383` - // Estimated: `5300` - // Minimum execution time: 14_344 nanoseconds. - Weight::from_parts(14_619_000, 5300) + // Estimated: `7280` + // Minimum execution time: 15_647 nanoseconds. + Weight::from_ref_time(15_975_000) + .saturating_add(Weight::from_proof_size(7280)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -538,9 +580,10 @@ impl WeightInfo for () { fn mint() -> Weight { // Proof Size summary in bytes: // Measured: `383` - // Estimated: `5262` - // Minimum execution time: 24_992 nanoseconds. - Weight::from_parts(25_784_000, 5262) + // Estimated: `7242` + // Minimum execution time: 28_383 nanoseconds. + Weight::from_ref_time(29_055_000) + .saturating_add(Weight::from_proof_size(7242)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -551,9 +594,10 @@ impl WeightInfo for () { fn burn() -> Weight { // Proof Size summary in bytes: // Measured: `491` - // Estimated: `5262` - // Minimum execution time: 31_233 nanoseconds. - Weight::from_parts(31_511_000, 5262) + // Estimated: `7242` + // Minimum execution time: 34_950 nanoseconds. + Weight::from_ref_time(35_296_000) + .saturating_add(Weight::from_proof_size(7242)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -566,9 +610,10 @@ impl WeightInfo for () { fn transfer() -> Weight { // Proof Size summary in bytes: // Measured: `530` - // Estimated: `10442` - // Minimum execution time: 43_002 nanoseconds. - Weight::from_parts(43_533_000, 10442) + // Estimated: `13412` + // Minimum execution time: 50_129 nanoseconds. + Weight::from_ref_time(50_820_000) + .saturating_add(Weight::from_proof_size(13412)) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -581,9 +626,10 @@ impl WeightInfo for () { fn transfer_keep_alive() -> Weight { // Proof Size summary in bytes: // Measured: `530` - // Estimated: `10442` - // Minimum execution time: 38_220 nanoseconds. - Weight::from_parts(38_639_000, 10442) + // Estimated: `13412` + // Minimum execution time: 43_424 nanoseconds. + Weight::from_ref_time(44_080_000) + .saturating_add(Weight::from_proof_size(13412)) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -596,9 +642,10 @@ impl WeightInfo for () { fn force_transfer() -> Weight { // Proof Size summary in bytes: // Measured: `530` - // Estimated: `10442` - // Minimum execution time: 43_171 nanoseconds. - Weight::from_parts(43_543_000, 10442) + // Estimated: `13412` + // Minimum execution time: 48_919 nanoseconds. + Weight::from_ref_time(50_720_000) + .saturating_add(Weight::from_proof_size(13412)) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -609,9 +656,10 @@ impl WeightInfo for () { fn freeze() -> Weight { // Proof Size summary in bytes: // Measured: `491` - // Estimated: `5262` - // Minimum execution time: 16_972 nanoseconds. - Weight::from_parts(17_498_000, 5262) + // Estimated: `7242` + // Minimum execution time: 19_750 nanoseconds. + Weight::from_ref_time(20_053_000) + .saturating_add(Weight::from_proof_size(7242)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -622,9 +670,10 @@ impl WeightInfo for () { fn thaw() -> Weight { // Proof Size summary in bytes: // Measured: `491` - // Estimated: `5262` - // Minimum execution time: 17_471 nanoseconds. - Weight::from_parts(17_842_000, 5262) + // Estimated: `7242` + // Minimum execution time: 19_672 nanoseconds. + Weight::from_ref_time(19_928_000) + .saturating_add(Weight::from_proof_size(7242)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -633,9 +682,10 @@ impl WeightInfo for () { fn freeze_asset() -> Weight { // Proof Size summary in bytes: // Measured: `417` - // Estimated: `2685` - // Minimum execution time: 13_497 nanoseconds. - Weight::from_parts(13_719_000, 2685) + // Estimated: `3675` + // Minimum execution time: 15_367 nanoseconds. + Weight::from_ref_time(15_726_000) + .saturating_add(Weight::from_proof_size(3675)) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -644,9 +694,10 @@ impl WeightInfo for () { fn thaw_asset() -> Weight { // Proof Size summary in bytes: // Measured: `417` - // Estimated: `2685` - // Minimum execution time: 13_424 nanoseconds. - Weight::from_parts(13_764_000, 2685) + // Estimated: `3675` + // Minimum execution time: 14_814 nanoseconds. + Weight::from_ref_time(15_301_000) + .saturating_add(Weight::from_proof_size(3675)) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -657,9 +708,10 @@ impl WeightInfo for () { fn transfer_ownership() -> Weight { // Proof Size summary in bytes: // Measured: `383` - // Estimated: `5300` - // Minimum execution time: 15_028 nanoseconds. - Weight::from_parts(15_366_000, 5300) + // Estimated: `7280` + // Minimum execution time: 17_426 nanoseconds. + Weight::from_ref_time(17_804_000) + .saturating_add(Weight::from_proof_size(7280)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -668,9 +720,10 @@ impl WeightInfo for () { fn set_team() -> Weight { // Proof Size summary in bytes: // Measured: `383` - // Estimated: `2685` - // Minimum execution time: 14_197 nanoseconds. - Weight::from_parts(14_437_000, 2685) + // Estimated: `3675` + // Minimum execution time: 15_935 nanoseconds. + Weight::from_ref_time(16_165_000) + .saturating_add(Weight::from_proof_size(3675)) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -680,16 +733,15 @@ impl WeightInfo for () { /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) /// The range of component `n` is `[0, 50]`. /// The range of component `s` is `[0, 50]`. - fn set_metadata(n: u32, s: u32, ) -> Weight { + fn set_metadata(n: u32, _s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `383` - // Estimated: `5300` - // Minimum execution time: 23_707 nanoseconds. - Weight::from_parts(24_466_834, 5300) - // Standard Error: 635 - .saturating_add(Weight::from_ref_time(730).saturating_mul(n.into())) - // Standard Error: 635 - .saturating_add(Weight::from_ref_time(3_975).saturating_mul(s.into())) + // Estimated: `7280` + // Minimum execution time: 26_890 nanoseconds. + Weight::from_ref_time(28_766_510) + .saturating_add(Weight::from_proof_size(7280)) + // Standard Error: 7_444 + .saturating_add(Weight::from_ref_time(3_619).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -700,9 +752,10 @@ impl WeightInfo for () { fn clear_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `579` - // Estimated: `5300` - // Minimum execution time: 23_997 nanoseconds. - Weight::from_parts(24_812_000, 5300) + // Estimated: `7280` + // Minimum execution time: 27_146 nanoseconds. + Weight::from_ref_time(27_692_000) + .saturating_add(Weight::from_proof_size(7280)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -712,14 +765,13 @@ impl WeightInfo for () { /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) /// The range of component `n` is `[0, 50]`. /// The range of component `s` is `[0, 50]`. - fn force_set_metadata(_n: u32, s: u32, ) -> Weight { + fn force_set_metadata(_n: u32, _s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `190` - // Estimated: `5300` - // Minimum execution time: 14_028 nanoseconds. - Weight::from_parts(15_217_669, 5300) - // Standard Error: 2_266 - .saturating_add(Weight::from_ref_time(2_045).saturating_mul(s.into())) + // Estimated: `7280` + // Minimum execution time: 16_181 nanoseconds. + Weight::from_ref_time(18_317_178) + .saturating_add(Weight::from_proof_size(7280)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -730,9 +782,10 @@ impl WeightInfo for () { fn force_clear_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `579` - // Estimated: `5300` - // Minimum execution time: 23_754 nanoseconds. - Weight::from_parts(24_154_000, 5300) + // Estimated: `7280` + // Minimum execution time: 26_962 nanoseconds. + Weight::from_ref_time(27_896_000) + .saturating_add(Weight::from_proof_size(7280)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -741,9 +794,10 @@ impl WeightInfo for () { fn force_asset_status() -> Weight { // Proof Size summary in bytes: // Measured: `383` - // Estimated: `2685` - // Minimum execution time: 13_128 nanoseconds. - Weight::from_parts(13_428_000, 2685) + // Estimated: `3675` + // Minimum execution time: 14_394 nanoseconds. + Weight::from_ref_time(14_917_000) + .saturating_add(Weight::from_proof_size(3675)) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -754,9 +808,10 @@ impl WeightInfo for () { fn approve_transfer() -> Weight { // Proof Size summary in bytes: // Measured: `417` - // Estimated: `5308` - // Minimum execution time: 27_224 nanoseconds. - Weight::from_parts(27_665_000, 5308) + // Estimated: `7288` + // Minimum execution time: 30_861 nanoseconds. + Weight::from_ref_time(31_356_000) + .saturating_add(Weight::from_proof_size(7288)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -771,9 +826,10 @@ impl WeightInfo for () { fn transfer_approved() -> Weight { // Proof Size summary in bytes: // Measured: `700` - // Estimated: `13065` - // Minimum execution time: 55_837 nanoseconds. - Weight::from_parts(56_636_000, 13065) + // Estimated: `17025` + // Minimum execution time: 64_510 nanoseconds. + Weight::from_ref_time(65_676_000) + .saturating_add(Weight::from_proof_size(17025)) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -784,9 +840,10 @@ impl WeightInfo for () { fn cancel_approval() -> Weight { // Proof Size summary in bytes: // Measured: `587` - // Estimated: `5308` - // Minimum execution time: 28_915 nanoseconds. - Weight::from_parts(29_325_000, 5308) + // Estimated: `7288` + // Minimum execution time: 32_620 nanoseconds. + Weight::from_ref_time(33_183_000) + .saturating_add(Weight::from_proof_size(7288)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -797,10 +854,23 @@ impl WeightInfo for () { fn force_cancel_approval() -> Weight { // Proof Size summary in bytes: // Measured: `587` - // Estimated: `5308` - // Minimum execution time: 29_103 nanoseconds. - Weight::from_parts(29_599_000, 5308) + // Estimated: `7288` + // Minimum execution time: 33_277 nanoseconds. + Weight::from_ref_time(34_438_000) + .saturating_add(Weight::from_proof_size(7288)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + fn set_min_balance() -> Weight { + // Proof Size summary in bytes: + // Measured: `383` + // Estimated: `3675` + // Minimum execution time: 16_213 nanoseconds. + Weight::from_ref_time(16_575_000) + .saturating_add(Weight::from_proof_size(3675)) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } } From 7d00033cbec0e2e3b50f7a42dd253ae55972371b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Thu, 2 Mar 2023 12:06:46 +0100 Subject: [PATCH 457/715] network-gossip: Do not report peer on duplicate message if its the first time (#13508) Two peers can send us the same gossip message. Before this pr we would have reported the second peer for sending a duplicate message. However, this isn't correct if we haven't seen the message from this peer yet. So, we should not report them as they can not be aware of our internal state. --- client/network-gossip/src/state_machine.rs | 36 +++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/client/network-gossip/src/state_machine.rs b/client/network-gossip/src/state_machine.rs index 48a1a2e53352b..7cd5b5613b073 100644 --- a/client/network-gossip/src/state_machine.rs +++ b/client/network-gossip/src/state_machine.rs @@ -354,7 +354,15 @@ impl ConsensusGossip { protocol = %self.protocol, "Ignored already known message", ); - network.report_peer(who, rep::DUPLICATE_GOSSIP); + + // If the peer already send us the message once, let's report them. + if self + .peers + .get_mut(&who) + .map_or(false, |p| !p.known_messages.insert(message_hash)) + { + network.report_peer(who, rep::DUPLICATE_GOSSIP); + } continue } @@ -814,4 +822,30 @@ mod tests { to_forward, ); } + + // Two peers can send us the same gossip message. We should not report the second peer + // sending the gossip message as long as its the first time the peer send us this message. + #[test] + fn do_not_report_peer_for_first_time_duplicate_gossip_message() { + let mut consensus = ConsensusGossip::::new(Arc::new(AllowAll), "/foo".into(), None); + + let mut network = NoOpNetwork::default(); + + let peer_id = PeerId::random(); + consensus.new_peer(&mut network, peer_id, ObservedRole::Full); + assert!(consensus.peers.contains_key(&peer_id)); + + let peer_id2 = PeerId::random(); + consensus.new_peer(&mut network, peer_id2, ObservedRole::Full); + assert!(consensus.peers.contains_key(&peer_id2)); + + let message = vec![vec![1, 2, 3]]; + consensus.on_incoming(&mut network, peer_id, message.clone()); + consensus.on_incoming(&mut network, peer_id2, message.clone()); + + assert_eq!( + vec![(peer_id, rep::GOSSIP_SUCCESS)], + network.inner.lock().unwrap().peer_reports + ); + } } From df93a0d673a786063f2c9e4b110b9a6194a76adf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= <123550+andresilva@users.noreply.github.com> Date: Thu, 2 Mar 2023 12:38:12 +0000 Subject: [PATCH 458/715] im-online: don't disable offending validators (#13493) --- frame/im-online/src/lib.rs | 6 +++++- frame/im-online/src/tests.rs | 3 +++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/frame/im-online/src/lib.rs b/frame/im-online/src/lib.rs index cdac51c9459c2..39762945ca70e 100644 --- a/frame/im-online/src/lib.rs +++ b/frame/im-online/src/lib.rs @@ -101,7 +101,7 @@ use sp_runtime::{ PerThing, Perbill, Permill, RuntimeDebug, SaturatedConversion, }; use sp_staking::{ - offence::{Kind, Offence, ReportOffence}, + offence::{DisableStrategy, Kind, Offence, ReportOffence}, SessionIndex, }; use sp_std::prelude::*; @@ -951,6 +951,10 @@ impl Offence for UnresponsivenessOffence { self.session_index } + fn disable_strategy(&self) -> DisableStrategy { + DisableStrategy::Never + } + fn slash_fraction(&self, offenders: u32) -> Perbill { // the formula is min((3 * (k - (n / 10 + 1))) / n, 1) * 0.07 // basically, 10% can be offline with no slash, but after that, it linearly climbs up to 7% diff --git a/frame/im-online/src/tests.rs b/frame/im-online/src/tests.rs index 8cc7f38eb7b82..80320959c53bd 100644 --- a/frame/im-online/src/tests.rs +++ b/frame/im-online/src/tests.rs @@ -56,6 +56,9 @@ fn test_unresponsiveness_slash_fraction() { dummy_offence.slash_fraction(17), Perbill::from_parts(46200000), // 4.62% ); + + // Offline offences should never lead to being disabled. + assert_eq!(dummy_offence.disable_strategy(), DisableStrategy::Never); } #[test] From d1d67cddf577ef275a2ca339312805c6d25ef9e5 Mon Sep 17 00:00:00 2001 From: Jegor Sidorenko <5252494+jsidorenko@users.noreply.github.com> Date: Thu, 2 Mar 2023 15:58:41 +0200 Subject: [PATCH 459/715] Return account's asset balances (#13352) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Runtime method to get user's assets balances * Fix test (typo) * Update frame/assets/src/functions.rs * Remove instance param * Update frame/assets/src/functions.rs Co-authored-by: Bastian Köcher * Remove instance param * Refactor * Chore * Update doc --------- Co-authored-by: Bastian Köcher Co-authored-by: parity-processbot <> --- bin/node/runtime/src/assets_api.rs | 34 ++++++++++++++++++++++++++++++ bin/node/runtime/src/lib.rs | 15 +++++++++++++ frame/assets/src/functions.rs | 7 ++++++ frame/assets/src/tests.rs | 5 ++++- 4 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 bin/node/runtime/src/assets_api.rs diff --git a/bin/node/runtime/src/assets_api.rs b/bin/node/runtime/src/assets_api.rs new file mode 100644 index 0000000000000..cf1a663d70300 --- /dev/null +++ b/bin/node/runtime/src/assets_api.rs @@ -0,0 +1,34 @@ +// 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 . + +//! Runtime API definition for assets. + +use codec::Codec; +use sp_std::vec::Vec; + +sp_api::decl_runtime_apis! { + pub trait AssetsApi + where + AccountId: Codec, + AssetBalance: Codec, + AssetId: Codec, + { + /// Returns the list of `AssetId`s and corresponding balance that an `AccountId` has. + fn account_balances(account: AccountId) -> Vec<(AssetId, AssetBalance)>; + } +} diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index f8589036f7853..9b317926a5a99 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -105,6 +105,9 @@ use sp_runtime::generic::Era; /// Generated voter bag information. mod voter_bags; +/// Runtime API definition for assets. +pub mod assets_api; + // Make the WASM binary available. #[cfg(feature = "std")] include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); @@ -2072,6 +2075,18 @@ impl_runtime_apis! { } } + impl assets_api::AssetsApi< + Block, + AccountId, + Balance, + u32, + > for Runtime + { + fn account_balances(account: AccountId) -> Vec<(u32, Balance)> { + Assets::account_balances(account) + } + } + impl pallet_contracts::ContractsApi for Runtime { fn call( diff --git a/frame/assets/src/functions.rs b/frame/assets/src/functions.rs index f970ce6cf5640..f6e027472f159 100644 --- a/frame/assets/src/functions.rs +++ b/frame/assets/src/functions.rs @@ -924,4 +924,11 @@ impl, I: 'static> Pallet { Ok(()) }) } + + /// Returns all the non-zero balances for all assets of the given `account`. + pub fn account_balances(account: T::AccountId) -> Vec<(T::AssetId, T::Balance)> { + Asset::::iter_keys() + .filter_map(|id| Self::maybe_balance(id, account.clone()).map(|balance| (id, balance))) + .collect::>() + } } diff --git a/frame/assets/src/tests.rs b/frame/assets/src/tests.rs index e76e989ef8932..e0f612e5cd781 100644 --- a/frame/assets/src/tests.rs +++ b/frame/assets/src/tests.rs @@ -37,11 +37,14 @@ fn asset_ids() -> Vec { fn basic_minting_should_work() { new_test_ext().execute_with(|| { assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 1, 1, true, 1)); assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); 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]); + assert_eq!(asset_ids(), vec![0, 1, 999]); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 1, 1, 100)); + assert_eq!(Assets::account_balances(1), vec![(0, 100), (999, 100), (1, 100)]); }); } From 6e81199eac74ce9a7bf3b1c720989031dd9b18a1 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Thu, 2 Mar 2023 22:28:17 +0100 Subject: [PATCH 460/715] Deprecate `Weight::from_{ref_time, proof_size}` (#13475) * Deprecate Weight::from_{ref_time, proof_size} Signed-off-by: Oliver Tale-Yazdi * Update templates Signed-off-by: Oliver Tale-Yazdi * Use from_parts Signed-off-by: Oliver Tale-Yazdi * Use from_parts Signed-off-by: Oliver Tale-Yazdi * Dont revert comment :facepalm: Signed-off-by: Oliver Tale-Yazdi * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_balances * Update weight files Signed-off-by: Oliver Tale-Yazdi * More fixes Signed-off-by: Oliver Tale-Yazdi * Adapt to Master changes Signed-off-by: Oliver Tale-Yazdi --------- Signed-off-by: Oliver Tale-Yazdi Co-authored-by: command-bot <> --- .maintain/frame-weight-template.hbs | 18 +- bin/node/executor/tests/basic.rs | 4 +- bin/node/runtime/src/impls.rs | 20 +- frame/alliance/src/weights.rs | 152 +- frame/assets/src/weights.rs | 236 +-- frame/babe/src/default_weights.rs | 11 +- 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 | 56 +- frame/beefy/src/default_weights.rs | 11 +- frame/benchmarking/pov/src/weights.rs | 348 ++-- frame/benchmarking/src/weights.rs | 28 +- frame/bounties/src/weights.rs | 12 +- frame/child-bounties/src/tests.rs | 2 +- frame/child-bounties/src/weights.rs | 4 +- frame/collective/src/tests.rs | 6 +- frame/collective/src/weights.rs | 156 +- frame/contracts/src/gas.rs | 12 +- frame/contracts/src/tests.rs | 6 +- frame/contracts/src/wasm/runtime.rs | 8 +- frame/contracts/src/weights.rs | 1640 ++++++++--------- frame/conviction-voting/src/weights.rs | 16 +- frame/democracy/src/weights.rs | 60 +- .../election-provider-multi-phase/src/mock.rs | 5 +- .../src/signed.rs | 8 +- .../src/unsigned.rs | 260 +-- .../src/weights.rs | 56 +- .../election-provider-support/src/weights.rs | 32 +- frame/elections-phragmen/src/weights.rs | 72 +- frame/examples/basic/src/lib.rs | 2 +- frame/examples/basic/src/weights.rs | 16 +- frame/executive/src/lib.rs | 24 +- frame/fast-unstake/src/lib.rs | 4 +- frame/fast-unstake/src/tests.rs | 8 +- frame/fast-unstake/src/weights.rs | 32 +- frame/glutton/src/tests.rs | 2 +- frame/glutton/src/weights.rs | 92 +- frame/grandpa/src/default_weights.rs | 13 +- frame/identity/src/weights.rs | 100 +- frame/im-online/src/weights.rs | 16 +- frame/lottery/src/weights.rs | 8 +- frame/membership/src/weights.rs | 56 +- .../src/default_weights.rs | 2 +- frame/message-queue/src/weights.rs | 80 +- frame/multisig/src/weights.rs | 44 +- frame/nfts/src/weights.rs | 364 ++-- frame/nis/src/mock.rs | 2 +- frame/nis/src/weights.rs | 12 +- frame/node-authorization/src/weights.rs | 18 +- frame/nomination-pools/src/weights.rs | 148 +- frame/preimage/src/weights.rs | 12 +- frame/proxy/src/weights.rs | 56 +- frame/ranked-collective/src/weights.rs | 20 +- frame/recovery/src/weights.rs | 24 +- frame/remark/src/weights.rs | 8 +- frame/scheduler/src/mock.rs | 26 +- frame/scheduler/src/tests.rs | 134 +- frame/scheduler/src/weights.rs | 48 +- frame/staking/src/pallet/impls.rs | 2 +- frame/staking/src/weights.rs | 144 +- frame/state-trie-migration/src/lib.rs | 14 +- frame/state-trie-migration/src/weights.rs | 16 +- frame/sudo/src/tests.rs | 32 +- frame/support/src/dispatch.rs | 80 +- frame/support/src/traits/hooks.rs | 8 +- frame/support/src/weights/block_weights.rs | 2 +- .../support/src/weights/extrinsic_weights.rs | 2 +- frame/support/test/tests/construct_runtime.rs | 4 +- frame/support/test/tests/pallet.rs | 18 +- .../test/tests/pallet_compatibility.rs | 4 +- .../tests/pallet_compatibility_instance.rs | 4 +- frame/support/test/tests/pallet_instance.rs | 18 +- .../system/src/extensions/check_mortality.rs | 2 +- frame/system/src/extensions/check_weight.rs | 76 +- frame/system/src/mock.rs | 8 +- frame/system/src/tests.rs | 34 +- frame/system/src/weights.rs | 40 +- frame/timestamp/src/weights.rs | 4 +- frame/tips/src/weights.rs | 36 +- .../asset-tx-payment/src/mock.rs | 2 +- .../asset-tx-payment/src/tests.rs | 60 +- frame/transaction-payment/src/lib.rs | 2 +- frame/transaction-payment/src/mock.rs | 2 +- frame/transaction-payment/src/tests.rs | 98 +- frame/transaction-payment/src/types.rs | 4 +- frame/transaction-storage/src/weights.rs | 4 +- frame/treasury/src/weights.rs | 12 +- frame/uniques/src/weights.rs | 24 +- frame/utility/src/tests.rs | 14 +- frame/utility/src/weights.rs | 32 +- frame/vesting/src/weights.rs | 64 +- frame/whitelist/src/tests.rs | 2 +- frame/whitelist/src/weights.rs | 12 +- primitives/weights/src/lib.rs | 24 +- primitives/weights/src/weight_v2.rs | 6 +- test-utils/runtime/src/lib.rs | 2 +- .../benchmarking-cli/src/overhead/README.md | 4 +- .../benchmarking-cli/src/overhead/weights.hbs | 2 +- .../benchmarking-cli/src/pallet/template.hbs | 10 +- 101 files changed, 2695 insertions(+), 2857 deletions(-) diff --git a/.maintain/frame-weight-template.hbs b/.maintain/frame-weight-template.hbs index 186e3cb23b333..ba9ac0798844d 100644 --- a/.maintain/frame-weight-template.hbs +++ b/.maintain/frame-weight-template.hbs @@ -52,12 +52,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `{{benchmark.base_recorded_proof_size}}{{#each benchmark.component_recorded_proof_size as |cp|}} + {{cp.name}} * ({{cp.slope}} ±{{underscore cp.error}}){{/each}}` // Estimated: `{{benchmark.base_calculated_proof_size}}{{#each benchmark.component_calculated_proof_size as |cp|}} + {{cp.name}} * ({{cp.slope}} ±{{underscore cp.error}}){{/each}}` - // Minimum execution time: {{underscore benchmark.min_execution_time}} nanoseconds. - Weight::from_ref_time({{underscore benchmark.base_weight}}) - .saturating_add(Weight::from_proof_size({{benchmark.base_calculated_proof_size}})) + // Minimum execution time: {{underscore benchmark.min_execution_time}}_000 picoseconds. + Weight::from_parts({{underscore benchmark.base_weight}}, {{benchmark.base_calculated_proof_size}}) {{#each benchmark.component_weight as |cw|}} // Standard Error: {{underscore cw.error}} - .saturating_add(Weight::from_ref_time({{underscore cw.slope}}).saturating_mul({{cw.name}}.into())) + .saturating_add(Weight::from_parts({{underscore cw.slope}}, 0).saturating_mul({{cw.name}}.into())) {{/each}} {{#if (ne benchmark.base_reads "0")}} .saturating_add(T::DbWeight::get().reads({{benchmark.base_reads}}_u64)) @@ -72,7 +71,7 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().writes(({{cw.slope}}_u64).saturating_mul({{cw.name}}.into()))) {{/each}} {{#each benchmark.component_calculated_proof_size as |cp|}} - .saturating_add(Weight::from_proof_size({{cp.slope}}).saturating_mul({{cp.name}}.into())) + .saturating_add(Weight::from_parts(0, {{cp.slope}}).saturating_mul({{cp.name}}.into())) {{/each}} } {{/each}} @@ -95,12 +94,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `{{benchmark.base_recorded_proof_size}}{{#each benchmark.component_recorded_proof_size as |cp|}} + {{cp.name}} * ({{cp.slope}} ±{{underscore cp.error}}){{/each}}` // Estimated: `{{benchmark.base_calculated_proof_size}}{{#each benchmark.component_calculated_proof_size as |cp|}} + {{cp.name}} * ({{cp.slope}} ±{{underscore cp.error}}){{/each}}` - // Minimum execution time: {{underscore benchmark.min_execution_time}} nanoseconds. - Weight::from_ref_time({{underscore benchmark.base_weight}}) - .saturating_add(Weight::from_proof_size({{benchmark.base_calculated_proof_size}})) + // Minimum execution time: {{underscore benchmark.min_execution_time}}_000 picoseconds. + Weight::from_parts({{underscore benchmark.base_weight}}, {{benchmark.base_calculated_proof_size}}) {{#each benchmark.component_weight as |cw|}} // Standard Error: {{underscore cw.error}} - .saturating_add(Weight::from_ref_time({{underscore cw.slope}}).saturating_mul({{cw.name}}.into())) + .saturating_add(Weight::from_parts({{underscore cw.slope}}, 0).saturating_mul({{cw.name}}.into())) {{/each}} {{#if (ne benchmark.base_reads "0")}} .saturating_add(RocksDbWeight::get().reads({{benchmark.base_reads}}_u64)) @@ -115,7 +113,7 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().writes(({{cw.slope}}_u64).saturating_mul({{cw.name}}.into()))) {{/each}} {{#each benchmark.component_calculated_proof_size as |cp|}} - .saturating_add(Weight::from_proof_size({{cp.slope}}).saturating_mul({{cp.name}}.into())) + .saturating_add(Weight::from_parts(0, {{cp.slope}}).saturating_mul({{cp.name}}.into())) {{/each}} } {{/each}} diff --git a/bin/node/executor/tests/basic.rs b/bin/node/executor/tests/basic.rs index c19db5af50ee4..ecfe02aa41596 100644 --- a/bin/node/executor/tests/basic.rs +++ b/bin/node/executor/tests/basic.rs @@ -682,7 +682,7 @@ fn deploying_wasm_contract_should_work() { Runtime, > { value: 0, - gas_limit: Weight::from_ref_time(500_000_000), + gas_limit: Weight::from_parts(500_000_000, 0), storage_deposit_limit: None, code: transfer_code, data: Vec::new(), @@ -694,7 +694,7 @@ fn deploying_wasm_contract_should_work() { 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), + gas_limit: Weight::from_parts(500_000_000, 0), storage_deposit_limit: None, data: vec![0x00, 0x01, 0x02, 0x03], }), diff --git a/bin/node/runtime/src/impls.rs b/bin/node/runtime/src/impls.rs index 9c606ff075f39..09f7b6a29e0b6 100644 --- a/bin/node/runtime/src/impls.rs +++ b/bin/node/runtime/src/impls.rs @@ -199,8 +199,8 @@ mod multiplier_tests { let fm = Multiplier::saturating_from_rational(1, 2); let test_set = vec![ (Weight::zero(), fm), - (Weight::from_ref_time(100), fm), - (Weight::from_ref_time(1000), fm), + (Weight::from_parts(100, 0), fm), + (Weight::from_parts(1000, 0), fm), (target(), fm), (max_normal() / 2, fm), (max_normal(), fm), @@ -285,7 +285,7 @@ mod multiplier_tests { // almost full. The entire quota of normal transactions is taken. let block_weight = BlockWeights::get().get(DispatchClass::Normal).max_total.unwrap() - - Weight::from_ref_time(100); + Weight::from_parts(100, 0); // Default substrate weight. let tx_weight = frame_support::weights::constants::ExtrinsicBaseWeight::get(); @@ -409,23 +409,23 @@ mod multiplier_tests { #[test] fn weight_to_fee_should_not_overflow_on_large_weights() { - let kb = Weight::from_ref_time(1024); + let kb = Weight::from_parts(1024, 0); 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::from_ref_time(1), - Weight::from_ref_time(10), - Weight::from_ref_time(1000), + Weight::from_parts(1, 0), + Weight::from_parts(10, 0), + Weight::from_parts(1000, 0), kb, 10u64 * kb, 100u64 * kb, mb, 10u64 * mb, - Weight::from_ref_time(2147483647), - Weight::from_ref_time(4294967295), + Weight::from_parts(2147483647, 0), + Weight::from_parts(4294967295, 0), BlockWeights::get().max_block / 2, BlockWeights::get().max_block, Weight::MAX / 2, @@ -442,7 +442,7 @@ mod multiplier_tests { // Some values that are all above the target and will cause an increase. let t = target(); - vec![t + Weight::from_ref_time(100), t * 2, t * 4].into_iter().for_each(|i| { + vec![t + Weight::from_parts(100, 0), 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/frame/alliance/src/weights.rs b/frame/alliance/src/weights.rs index 6ccf6bed3a5d2..8ff4bad31313c 100644 --- a/frame/alliance/src/weights.rs +++ b/frame/alliance/src/weights.rs @@ -93,15 +93,15 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 28_849 nanoseconds. Weight::from_parts(29_823_933, 11659) // Standard Error: 74 - .saturating_add(Weight::from_ref_time(830).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(830, 0).saturating_mul(b.into())) // Standard Error: 775 - .saturating_add(Weight::from_ref_time(22_980).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(22_980, 0).saturating_mul(m.into())) // Standard Error: 765 - .saturating_add(Weight::from_ref_time(90_520).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(90_520, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) - .saturating_add(Weight::from_proof_size(132).saturating_mul(m.into())) - .saturating_add(Weight::from_proof_size(144).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 132).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 144).saturating_mul(p.into())) } /// Storage: Alliance Members (r:1 w:0) /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) @@ -115,10 +115,10 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 23_570 nanoseconds. Weight::from_parts(25_473_196, 9337) // Standard Error: 824 - .saturating_add(Weight::from_ref_time(54_603).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(54_603, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) - .saturating_add(Weight::from_proof_size(64).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) } /// Storage: Alliance Members (r:1 w:0) /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) @@ -139,13 +139,13 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 35_373 nanoseconds. Weight::from_parts(32_763_656, 11979) // Standard Error: 2_041 - .saturating_add(Weight::from_ref_time(52_915).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(52_915, 0).saturating_mul(m.into())) // Standard Error: 1_991 - .saturating_add(Weight::from_ref_time(78_594).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(78_594, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(388).saturating_mul(m.into())) - .saturating_add(Weight::from_proof_size(148).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 388).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 148).saturating_mul(p.into())) } /// Storage: Alliance Members (r:1 w:0) /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) @@ -167,15 +167,15 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 44_590 nanoseconds. Weight::from_parts(43_367_913, 15730) // Standard Error: 71 - .saturating_add(Weight::from_ref_time(819).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(819, 0).saturating_mul(b.into())) // Standard Error: 751 - .saturating_add(Weight::from_ref_time(39_124).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(39_124, 0).saturating_mul(m.into())) // Standard Error: 732 - .saturating_add(Weight::from_ref_time(90_469).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(90_469, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(388).saturating_mul(m.into())) - .saturating_add(Weight::from_proof_size(164).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 388).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 164).saturating_mul(p.into())) } /// Storage: Alliance Members (r:1 w:0) /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) @@ -198,13 +198,13 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 36_796 nanoseconds. Weight::from_parts(34_578_765, 13201) // Standard Error: 1_037 - .saturating_add(Weight::from_ref_time(43_508).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(43_508, 0).saturating_mul(m.into())) // Standard Error: 1_024 - .saturating_add(Weight::from_ref_time(77_084).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(77_084, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(485).saturating_mul(m.into())) - .saturating_add(Weight::from_proof_size(185).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 485).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 185).saturating_mul(p.into())) } /// Storage: Alliance Members (r:1 w:0) /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) @@ -228,15 +228,15 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 36_897 nanoseconds. Weight::from_parts(34_169_666, 13146) // Standard Error: 47 - .saturating_add(Weight::from_ref_time(972).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(972, 0).saturating_mul(b.into())) // Standard Error: 510 - .saturating_add(Weight::from_ref_time(38_084).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(38_084, 0).saturating_mul(m.into())) // Standard Error: 492 - .saturating_add(Weight::from_ref_time(78_576).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(78_576, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(480).saturating_mul(m.into())) - .saturating_add(Weight::from_proof_size(185).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 480).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 185).saturating_mul(p.into())) } /// Storage: Alliance Members (r:2 w:2) /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) @@ -251,9 +251,9 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 29_313 nanoseconds. Weight::from_parts(20_502_244, 12084) // Standard Error: 304 - .saturating_add(Weight::from_ref_time(107_994).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(107_994, 0).saturating_mul(m.into())) // Standard Error: 300 - .saturating_add(Weight::from_ref_time(92_645).saturating_mul(z.into())) + .saturating_add(Weight::from_parts(92_645, 0).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -279,20 +279,20 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 232_895 nanoseconds. Weight::from_parts(233_860_000, 32201) // Standard Error: 19_092 - .saturating_add(Weight::from_ref_time(445_664).saturating_mul(x.into())) + .saturating_add(Weight::from_parts(445_664, 0).saturating_mul(x.into())) // Standard Error: 19_000 - .saturating_add(Weight::from_ref_time(432_571).saturating_mul(y.into())) + .saturating_add(Weight::from_parts(432_571, 0).saturating_mul(y.into())) // Standard Error: 37_965 - .saturating_add(Weight::from_ref_time(9_386_151).saturating_mul(z.into())) + .saturating_add(Weight::from_parts(9_386_151, 0).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(x.into()))) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(y.into()))) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(z.into()))) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(z.into()))) - .saturating_add(Weight::from_proof_size(2587).saturating_mul(x.into())) - .saturating_add(Weight::from_proof_size(2590).saturating_mul(y.into())) - .saturating_add(Weight::from_proof_size(3209).saturating_mul(z.into())) + .saturating_add(Weight::from_parts(0, 2587).saturating_mul(x.into())) + .saturating_add(Weight::from_parts(0, 2590).saturating_mul(y.into())) + .saturating_add(Weight::from_parts(0, 3209).saturating_mul(z.into())) } /// Storage: Alliance Rule (r:0 w:1) /// Proof: Alliance Rule (max_values: Some(1), max_size: Some(87), added: 582, mode: MaxEncodedLen) @@ -301,7 +301,7 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 9_156 nanoseconds. - Weight::from_ref_time(9_376_000) + Weight::from_parts(9_376_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Alliance Announcements (r:1 w:1) @@ -443,9 +443,9 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 7_709 nanoseconds. Weight::from_parts(7_773_000, 29894) // Standard Error: 2_645 - .saturating_add(Weight::from_ref_time(1_266_755).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(1_266_755, 0).saturating_mul(n.into())) // Standard Error: 1_036 - .saturating_add(Weight::from_ref_time(67_359).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(67_359, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -462,9 +462,9 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 7_438 nanoseconds. Weight::from_parts(7_570_000, 29894) // Standard Error: 165_072 - .saturating_add(Weight::from_ref_time(13_026_975).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(13_026_975, 0).saturating_mul(n.into())) // Standard Error: 64_649 - .saturating_add(Weight::from_ref_time(485_565).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(485_565, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -509,15 +509,15 @@ impl WeightInfo for () { // Minimum execution time: 28_849 nanoseconds. Weight::from_parts(29_823_933, 11659) // Standard Error: 74 - .saturating_add(Weight::from_ref_time(830).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(830, 0).saturating_mul(b.into())) // Standard Error: 775 - .saturating_add(Weight::from_ref_time(22_980).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(22_980, 0).saturating_mul(m.into())) // Standard Error: 765 - .saturating_add(Weight::from_ref_time(90_520).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(90_520, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) - .saturating_add(Weight::from_proof_size(132).saturating_mul(m.into())) - .saturating_add(Weight::from_proof_size(144).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 132).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 144).saturating_mul(p.into())) } /// Storage: Alliance Members (r:1 w:0) /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) @@ -531,10 +531,10 @@ impl WeightInfo for () { // Minimum execution time: 23_570 nanoseconds. Weight::from_parts(25_473_196, 9337) // Standard Error: 824 - .saturating_add(Weight::from_ref_time(54_603).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(54_603, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) - .saturating_add(Weight::from_proof_size(64).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) } /// Storage: Alliance Members (r:1 w:0) /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) @@ -555,13 +555,13 @@ impl WeightInfo for () { // Minimum execution time: 35_373 nanoseconds. Weight::from_parts(32_763_656, 11979) // Standard Error: 2_041 - .saturating_add(Weight::from_ref_time(52_915).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(52_915, 0).saturating_mul(m.into())) // Standard Error: 1_991 - .saturating_add(Weight::from_ref_time(78_594).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(78_594, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(388).saturating_mul(m.into())) - .saturating_add(Weight::from_proof_size(148).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 388).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 148).saturating_mul(p.into())) } /// Storage: Alliance Members (r:1 w:0) /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) @@ -583,15 +583,15 @@ impl WeightInfo for () { // Minimum execution time: 44_590 nanoseconds. Weight::from_parts(43_367_913, 15730) // Standard Error: 71 - .saturating_add(Weight::from_ref_time(819).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(819, 0).saturating_mul(b.into())) // Standard Error: 751 - .saturating_add(Weight::from_ref_time(39_124).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(39_124, 0).saturating_mul(m.into())) // Standard Error: 732 - .saturating_add(Weight::from_ref_time(90_469).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(90_469, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(388).saturating_mul(m.into())) - .saturating_add(Weight::from_proof_size(164).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 388).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 164).saturating_mul(p.into())) } /// Storage: Alliance Members (r:1 w:0) /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) @@ -614,13 +614,13 @@ impl WeightInfo for () { // Minimum execution time: 36_796 nanoseconds. Weight::from_parts(34_578_765, 13201) // Standard Error: 1_037 - .saturating_add(Weight::from_ref_time(43_508).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(43_508, 0).saturating_mul(m.into())) // Standard Error: 1_024 - .saturating_add(Weight::from_ref_time(77_084).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(77_084, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(485).saturating_mul(m.into())) - .saturating_add(Weight::from_proof_size(185).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 485).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 185).saturating_mul(p.into())) } /// Storage: Alliance Members (r:1 w:0) /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) @@ -644,15 +644,15 @@ impl WeightInfo for () { // Minimum execution time: 36_897 nanoseconds. Weight::from_parts(34_169_666, 13146) // Standard Error: 47 - .saturating_add(Weight::from_ref_time(972).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(972, 0).saturating_mul(b.into())) // Standard Error: 510 - .saturating_add(Weight::from_ref_time(38_084).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(38_084, 0).saturating_mul(m.into())) // Standard Error: 492 - .saturating_add(Weight::from_ref_time(78_576).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(78_576, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(480).saturating_mul(m.into())) - .saturating_add(Weight::from_proof_size(185).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 480).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 185).saturating_mul(p.into())) } /// Storage: Alliance Members (r:2 w:2) /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) @@ -667,9 +667,9 @@ impl WeightInfo for () { // Minimum execution time: 29_313 nanoseconds. Weight::from_parts(20_502_244, 12084) // Standard Error: 304 - .saturating_add(Weight::from_ref_time(107_994).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(107_994, 0).saturating_mul(m.into())) // Standard Error: 300 - .saturating_add(Weight::from_ref_time(92_645).saturating_mul(z.into())) + .saturating_add(Weight::from_parts(92_645, 0).saturating_mul(z.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -695,20 +695,20 @@ impl WeightInfo for () { // Minimum execution time: 232_895 nanoseconds. Weight::from_parts(233_860_000, 32201) // Standard Error: 19_092 - .saturating_add(Weight::from_ref_time(445_664).saturating_mul(x.into())) + .saturating_add(Weight::from_parts(445_664, 0).saturating_mul(x.into())) // Standard Error: 19_000 - .saturating_add(Weight::from_ref_time(432_571).saturating_mul(y.into())) + .saturating_add(Weight::from_parts(432_571, 0).saturating_mul(y.into())) // Standard Error: 37_965 - .saturating_add(Weight::from_ref_time(9_386_151).saturating_mul(z.into())) + .saturating_add(Weight::from_parts(9_386_151, 0).saturating_mul(z.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(x.into()))) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(y.into()))) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(z.into()))) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(RocksDbWeight::get().writes((2_u64).saturating_mul(z.into()))) - .saturating_add(Weight::from_proof_size(2587).saturating_mul(x.into())) - .saturating_add(Weight::from_proof_size(2590).saturating_mul(y.into())) - .saturating_add(Weight::from_proof_size(3209).saturating_mul(z.into())) + .saturating_add(Weight::from_parts(0, 2587).saturating_mul(x.into())) + .saturating_add(Weight::from_parts(0, 2590).saturating_mul(y.into())) + .saturating_add(Weight::from_parts(0, 3209).saturating_mul(z.into())) } /// Storage: Alliance Rule (r:0 w:1) /// Proof: Alliance Rule (max_values: Some(1), max_size: Some(87), added: 582, mode: MaxEncodedLen) @@ -717,7 +717,7 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 9_156 nanoseconds. - Weight::from_ref_time(9_376_000) + Weight::from_parts(9_376_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Alliance Announcements (r:1 w:1) @@ -859,9 +859,9 @@ impl WeightInfo for () { // Minimum execution time: 7_709 nanoseconds. Weight::from_parts(7_773_000, 29894) // Standard Error: 2_645 - .saturating_add(Weight::from_ref_time(1_266_755).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(1_266_755, 0).saturating_mul(n.into())) // Standard Error: 1_036 - .saturating_add(Weight::from_ref_time(67_359).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(67_359, 0).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -878,9 +878,9 @@ impl WeightInfo for () { // Minimum execution time: 7_438 nanoseconds. Weight::from_parts(7_570_000, 29894) // Standard Error: 165_072 - .saturating_add(Weight::from_ref_time(13_026_975).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(13_026_975, 0).saturating_mul(n.into())) // Standard Error: 64_649 - .saturating_add(Weight::from_ref_time(485_565).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(485_565, 0).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } diff --git a/frame/assets/src/weights.rs b/frame/assets/src/weights.rs index 27de4fa333687..080800daa6c6b 100644 --- a/frame/assets/src/weights.rs +++ b/frame/assets/src/weights.rs @@ -90,8 +90,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `325` // Estimated: `7268` // Minimum execution time: 27_887 nanoseconds. - Weight::from_ref_time(28_190_000) - .saturating_add(Weight::from_proof_size(7268)) + Weight::from_parts(28_190_000, 0) + .saturating_add(Weight::from_parts(0, 7268)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -102,8 +102,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `153` // Estimated: `3675` // Minimum execution time: 15_059 nanoseconds. - Weight::from_ref_time(15_600_000) - .saturating_add(Weight::from_proof_size(3675)) + Weight::from_parts(15_600_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -114,8 +114,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `417` // Estimated: `3675` // Minimum execution time: 15_581 nanoseconds. - Weight::from_ref_time(15_868_000) - .saturating_add(Weight::from_proof_size(3675)) + Weight::from_parts(15_868_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -131,15 +131,15 @@ impl WeightInfo for SubstrateWeight { // Measured: `25 + c * (240 ±0)` // Estimated: `8232 + c * (5180 ±0)` // Minimum execution time: 20_167 nanoseconds. - Weight::from_ref_time(20_436_000) - .saturating_add(Weight::from_proof_size(8232)) + Weight::from_parts(20_436_000, 0) + .saturating_add(Weight::from_parts(0, 8232)) // Standard Error: 12_761 - .saturating_add(Weight::from_ref_time(15_535_268).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(15_535_268, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(c.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(c.into()))) - .saturating_add(Weight::from_proof_size(5180).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(0, 5180).saturating_mul(c.into())) } /// Storage: Assets Asset (r:1 w:1) /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) @@ -151,15 +151,15 @@ impl WeightInfo for SubstrateWeight { // Measured: `554 + a * (86 ±0)` // Estimated: `7288 + a * (2623 ±0)` // Minimum execution time: 20_349 nanoseconds. - Weight::from_ref_time(20_482_000) - .saturating_add(Weight::from_proof_size(7288)) + Weight::from_parts(20_482_000, 0) + .saturating_add(Weight::from_parts(0, 7288)) // Standard Error: 9_831 - .saturating_add(Weight::from_ref_time(15_771_918).saturating_mul(a.into())) + .saturating_add(Weight::from_parts(15_771_918, 0).saturating_mul(a.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(a.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(a.into()))) - .saturating_add(Weight::from_proof_size(2623).saturating_mul(a.into())) + .saturating_add(Weight::from_parts(0, 2623).saturating_mul(a.into())) } /// Storage: Assets Asset (r:1 w:1) /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) @@ -170,8 +170,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `383` // Estimated: `7280` // Minimum execution time: 15_647 nanoseconds. - Weight::from_ref_time(15_975_000) - .saturating_add(Weight::from_proof_size(7280)) + Weight::from_parts(15_975_000, 0) + .saturating_add(Weight::from_parts(0, 7280)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -184,8 +184,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `383` // Estimated: `7242` // Minimum execution time: 28_383 nanoseconds. - Weight::from_ref_time(29_055_000) - .saturating_add(Weight::from_proof_size(7242)) + Weight::from_parts(29_055_000, 0) + .saturating_add(Weight::from_parts(0, 7242)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -198,8 +198,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `491` // Estimated: `7242` // Minimum execution time: 34_950 nanoseconds. - Weight::from_ref_time(35_296_000) - .saturating_add(Weight::from_proof_size(7242)) + Weight::from_parts(35_296_000, 0) + .saturating_add(Weight::from_parts(0, 7242)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -214,8 +214,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `530` // Estimated: `13412` // Minimum execution time: 50_129 nanoseconds. - Weight::from_ref_time(50_820_000) - .saturating_add(Weight::from_proof_size(13412)) + Weight::from_parts(50_820_000, 0) + .saturating_add(Weight::from_parts(0, 13412)) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -230,8 +230,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `530` // Estimated: `13412` // Minimum execution time: 43_424 nanoseconds. - Weight::from_ref_time(44_080_000) - .saturating_add(Weight::from_proof_size(13412)) + Weight::from_parts(44_080_000, 0) + .saturating_add(Weight::from_parts(0, 13412)) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -246,8 +246,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `530` // Estimated: `13412` // Minimum execution time: 48_919 nanoseconds. - Weight::from_ref_time(50_720_000) - .saturating_add(Weight::from_proof_size(13412)) + Weight::from_parts(50_720_000, 0) + .saturating_add(Weight::from_parts(0, 13412)) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -260,8 +260,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `491` // Estimated: `7242` // Minimum execution time: 19_750 nanoseconds. - Weight::from_ref_time(20_053_000) - .saturating_add(Weight::from_proof_size(7242)) + Weight::from_parts(20_053_000, 0) + .saturating_add(Weight::from_parts(0, 7242)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -274,8 +274,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `491` // Estimated: `7242` // Minimum execution time: 19_672 nanoseconds. - Weight::from_ref_time(19_928_000) - .saturating_add(Weight::from_proof_size(7242)) + Weight::from_parts(19_928_000, 0) + .saturating_add(Weight::from_parts(0, 7242)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -286,8 +286,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `417` // Estimated: `3675` // Minimum execution time: 15_367 nanoseconds. - Weight::from_ref_time(15_726_000) - .saturating_add(Weight::from_proof_size(3675)) + Weight::from_parts(15_726_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -298,8 +298,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `417` // Estimated: `3675` // Minimum execution time: 14_814 nanoseconds. - Weight::from_ref_time(15_301_000) - .saturating_add(Weight::from_proof_size(3675)) + Weight::from_parts(15_301_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -312,8 +312,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `383` // Estimated: `7280` // Minimum execution time: 17_426 nanoseconds. - Weight::from_ref_time(17_804_000) - .saturating_add(Weight::from_proof_size(7280)) + Weight::from_parts(17_804_000, 0) + .saturating_add(Weight::from_parts(0, 7280)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -324,8 +324,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `383` // Estimated: `3675` // Minimum execution time: 15_935 nanoseconds. - Weight::from_ref_time(16_165_000) - .saturating_add(Weight::from_proof_size(3675)) + Weight::from_parts(16_165_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -340,10 +340,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `383` // Estimated: `7280` // Minimum execution time: 26_890 nanoseconds. - Weight::from_ref_time(28_766_510) - .saturating_add(Weight::from_proof_size(7280)) + Weight::from_parts(28_766_510, 0) + .saturating_add(Weight::from_parts(0, 7280)) // Standard Error: 7_444 - .saturating_add(Weight::from_ref_time(3_619).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(3_619, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -356,8 +356,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `579` // Estimated: `7280` // Minimum execution time: 27_146 nanoseconds. - Weight::from_ref_time(27_692_000) - .saturating_add(Weight::from_proof_size(7280)) + Weight::from_parts(27_692_000, 0) + .saturating_add(Weight::from_parts(0, 7280)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -372,8 +372,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `190` // Estimated: `7280` // Minimum execution time: 16_181 nanoseconds. - Weight::from_ref_time(18_317_178) - .saturating_add(Weight::from_proof_size(7280)) + Weight::from_parts(18_317_178, 0) + .saturating_add(Weight::from_parts(0, 7280)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -386,8 +386,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `579` // Estimated: `7280` // Minimum execution time: 26_962 nanoseconds. - Weight::from_ref_time(27_896_000) - .saturating_add(Weight::from_proof_size(7280)) + Weight::from_parts(27_896_000, 0) + .saturating_add(Weight::from_parts(0, 7280)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -398,8 +398,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `383` // Estimated: `3675` // Minimum execution time: 14_394 nanoseconds. - Weight::from_ref_time(14_917_000) - .saturating_add(Weight::from_proof_size(3675)) + Weight::from_parts(14_917_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -412,8 +412,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `417` // Estimated: `7288` // Minimum execution time: 30_861 nanoseconds. - Weight::from_ref_time(31_356_000) - .saturating_add(Weight::from_proof_size(7288)) + Weight::from_parts(31_356_000, 0) + .saturating_add(Weight::from_parts(0, 7288)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -430,8 +430,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `700` // Estimated: `17025` // Minimum execution time: 64_510 nanoseconds. - Weight::from_ref_time(65_676_000) - .saturating_add(Weight::from_proof_size(17025)) + Weight::from_parts(65_676_000, 0) + .saturating_add(Weight::from_parts(0, 17025)) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -444,8 +444,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `587` // Estimated: `7288` // Minimum execution time: 32_620 nanoseconds. - Weight::from_ref_time(33_183_000) - .saturating_add(Weight::from_proof_size(7288)) + Weight::from_parts(33_183_000, 0) + .saturating_add(Weight::from_parts(0, 7288)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -458,8 +458,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `587` // Estimated: `7288` // Minimum execution time: 33_277 nanoseconds. - Weight::from_ref_time(34_438_000) - .saturating_add(Weight::from_proof_size(7288)) + Weight::from_parts(34_438_000, 0) + .saturating_add(Weight::from_parts(0, 7288)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -470,8 +470,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `383` // Estimated: `3675` // Minimum execution time: 16_213 nanoseconds. - Weight::from_ref_time(16_575_000) - .saturating_add(Weight::from_proof_size(3675)) + Weight::from_parts(16_575_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -488,8 +488,8 @@ impl WeightInfo for () { // Measured: `325` // Estimated: `7268` // Minimum execution time: 27_887 nanoseconds. - Weight::from_ref_time(28_190_000) - .saturating_add(Weight::from_proof_size(7268)) + Weight::from_parts(28_190_000, 0) + .saturating_add(Weight::from_parts(0, 7268)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -500,8 +500,8 @@ impl WeightInfo for () { // Measured: `153` // Estimated: `3675` // Minimum execution time: 15_059 nanoseconds. - Weight::from_ref_time(15_600_000) - .saturating_add(Weight::from_proof_size(3675)) + Weight::from_parts(15_600_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -512,8 +512,8 @@ impl WeightInfo for () { // Measured: `417` // Estimated: `3675` // Minimum execution time: 15_581 nanoseconds. - Weight::from_ref_time(15_868_000) - .saturating_add(Weight::from_proof_size(3675)) + Weight::from_parts(15_868_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -529,15 +529,15 @@ impl WeightInfo for () { // Measured: `25 + c * (240 ±0)` // Estimated: `8232 + c * (5180 ±0)` // Minimum execution time: 20_167 nanoseconds. - Weight::from_ref_time(20_436_000) - .saturating_add(Weight::from_proof_size(8232)) + Weight::from_parts(20_436_000, 0) + .saturating_add(Weight::from_parts(0, 8232)) // Standard Error: 12_761 - .saturating_add(Weight::from_ref_time(15_535_268).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(15_535_268, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(c.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(RocksDbWeight::get().writes((2_u64).saturating_mul(c.into()))) - .saturating_add(Weight::from_proof_size(5180).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(0, 5180).saturating_mul(c.into())) } /// Storage: Assets Asset (r:1 w:1) /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) @@ -549,15 +549,15 @@ impl WeightInfo for () { // Measured: `554 + a * (86 ±0)` // Estimated: `7288 + a * (2623 ±0)` // Minimum execution time: 20_349 nanoseconds. - Weight::from_ref_time(20_482_000) - .saturating_add(Weight::from_proof_size(7288)) + Weight::from_parts(20_482_000, 0) + .saturating_add(Weight::from_parts(0, 7288)) // Standard Error: 9_831 - .saturating_add(Weight::from_ref_time(15_771_918).saturating_mul(a.into())) + .saturating_add(Weight::from_parts(15_771_918, 0).saturating_mul(a.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(a.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(a.into()))) - .saturating_add(Weight::from_proof_size(2623).saturating_mul(a.into())) + .saturating_add(Weight::from_parts(0, 2623).saturating_mul(a.into())) } /// Storage: Assets Asset (r:1 w:1) /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) @@ -568,8 +568,8 @@ impl WeightInfo for () { // Measured: `383` // Estimated: `7280` // Minimum execution time: 15_647 nanoseconds. - Weight::from_ref_time(15_975_000) - .saturating_add(Weight::from_proof_size(7280)) + Weight::from_parts(15_975_000, 0) + .saturating_add(Weight::from_parts(0, 7280)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -582,8 +582,8 @@ impl WeightInfo for () { // Measured: `383` // Estimated: `7242` // Minimum execution time: 28_383 nanoseconds. - Weight::from_ref_time(29_055_000) - .saturating_add(Weight::from_proof_size(7242)) + Weight::from_parts(29_055_000, 0) + .saturating_add(Weight::from_parts(0, 7242)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -596,8 +596,8 @@ impl WeightInfo for () { // Measured: `491` // Estimated: `7242` // Minimum execution time: 34_950 nanoseconds. - Weight::from_ref_time(35_296_000) - .saturating_add(Weight::from_proof_size(7242)) + Weight::from_parts(35_296_000, 0) + .saturating_add(Weight::from_parts(0, 7242)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -612,8 +612,8 @@ impl WeightInfo for () { // Measured: `530` // Estimated: `13412` // Minimum execution time: 50_129 nanoseconds. - Weight::from_ref_time(50_820_000) - .saturating_add(Weight::from_proof_size(13412)) + Weight::from_parts(50_820_000, 0) + .saturating_add(Weight::from_parts(0, 13412)) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -628,8 +628,8 @@ impl WeightInfo for () { // Measured: `530` // Estimated: `13412` // Minimum execution time: 43_424 nanoseconds. - Weight::from_ref_time(44_080_000) - .saturating_add(Weight::from_proof_size(13412)) + Weight::from_parts(44_080_000, 0) + .saturating_add(Weight::from_parts(0, 13412)) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -644,8 +644,8 @@ impl WeightInfo for () { // Measured: `530` // Estimated: `13412` // Minimum execution time: 48_919 nanoseconds. - Weight::from_ref_time(50_720_000) - .saturating_add(Weight::from_proof_size(13412)) + Weight::from_parts(50_720_000, 0) + .saturating_add(Weight::from_parts(0, 13412)) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -658,8 +658,8 @@ impl WeightInfo for () { // Measured: `491` // Estimated: `7242` // Minimum execution time: 19_750 nanoseconds. - Weight::from_ref_time(20_053_000) - .saturating_add(Weight::from_proof_size(7242)) + Weight::from_parts(20_053_000, 0) + .saturating_add(Weight::from_parts(0, 7242)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -672,8 +672,8 @@ impl WeightInfo for () { // Measured: `491` // Estimated: `7242` // Minimum execution time: 19_672 nanoseconds. - Weight::from_ref_time(19_928_000) - .saturating_add(Weight::from_proof_size(7242)) + Weight::from_parts(19_928_000, 0) + .saturating_add(Weight::from_parts(0, 7242)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -684,8 +684,8 @@ impl WeightInfo for () { // Measured: `417` // Estimated: `3675` // Minimum execution time: 15_367 nanoseconds. - Weight::from_ref_time(15_726_000) - .saturating_add(Weight::from_proof_size(3675)) + Weight::from_parts(15_726_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -696,8 +696,8 @@ impl WeightInfo for () { // Measured: `417` // Estimated: `3675` // Minimum execution time: 14_814 nanoseconds. - Weight::from_ref_time(15_301_000) - .saturating_add(Weight::from_proof_size(3675)) + Weight::from_parts(15_301_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -710,8 +710,8 @@ impl WeightInfo for () { // Measured: `383` // Estimated: `7280` // Minimum execution time: 17_426 nanoseconds. - Weight::from_ref_time(17_804_000) - .saturating_add(Weight::from_proof_size(7280)) + Weight::from_parts(17_804_000, 0) + .saturating_add(Weight::from_parts(0, 7280)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -722,8 +722,8 @@ impl WeightInfo for () { // Measured: `383` // Estimated: `3675` // Minimum execution time: 15_935 nanoseconds. - Weight::from_ref_time(16_165_000) - .saturating_add(Weight::from_proof_size(3675)) + Weight::from_parts(16_165_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -738,10 +738,10 @@ impl WeightInfo for () { // Measured: `383` // Estimated: `7280` // Minimum execution time: 26_890 nanoseconds. - Weight::from_ref_time(28_766_510) - .saturating_add(Weight::from_proof_size(7280)) + Weight::from_parts(28_766_510, 0) + .saturating_add(Weight::from_parts(0, 7280)) // Standard Error: 7_444 - .saturating_add(Weight::from_ref_time(3_619).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(3_619, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -754,8 +754,8 @@ impl WeightInfo for () { // Measured: `579` // Estimated: `7280` // Minimum execution time: 27_146 nanoseconds. - Weight::from_ref_time(27_692_000) - .saturating_add(Weight::from_proof_size(7280)) + Weight::from_parts(27_692_000, 0) + .saturating_add(Weight::from_parts(0, 7280)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -770,8 +770,8 @@ impl WeightInfo for () { // Measured: `190` // Estimated: `7280` // Minimum execution time: 16_181 nanoseconds. - Weight::from_ref_time(18_317_178) - .saturating_add(Weight::from_proof_size(7280)) + Weight::from_parts(18_317_178, 0) + .saturating_add(Weight::from_parts(0, 7280)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -784,8 +784,8 @@ impl WeightInfo for () { // Measured: `579` // Estimated: `7280` // Minimum execution time: 26_962 nanoseconds. - Weight::from_ref_time(27_896_000) - .saturating_add(Weight::from_proof_size(7280)) + Weight::from_parts(27_896_000, 0) + .saturating_add(Weight::from_parts(0, 7280)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -796,8 +796,8 @@ impl WeightInfo for () { // Measured: `383` // Estimated: `3675` // Minimum execution time: 14_394 nanoseconds. - Weight::from_ref_time(14_917_000) - .saturating_add(Weight::from_proof_size(3675)) + Weight::from_parts(14_917_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -810,8 +810,8 @@ impl WeightInfo for () { // Measured: `417` // Estimated: `7288` // Minimum execution time: 30_861 nanoseconds. - Weight::from_ref_time(31_356_000) - .saturating_add(Weight::from_proof_size(7288)) + Weight::from_parts(31_356_000, 0) + .saturating_add(Weight::from_parts(0, 7288)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -828,8 +828,8 @@ impl WeightInfo for () { // Measured: `700` // Estimated: `17025` // Minimum execution time: 64_510 nanoseconds. - Weight::from_ref_time(65_676_000) - .saturating_add(Weight::from_proof_size(17025)) + Weight::from_parts(65_676_000, 0) + .saturating_add(Weight::from_parts(0, 17025)) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -842,8 +842,8 @@ impl WeightInfo for () { // Measured: `587` // Estimated: `7288` // Minimum execution time: 32_620 nanoseconds. - Weight::from_ref_time(33_183_000) - .saturating_add(Weight::from_proof_size(7288)) + Weight::from_parts(33_183_000, 0) + .saturating_add(Weight::from_parts(0, 7288)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -856,8 +856,8 @@ impl WeightInfo for () { // Measured: `587` // Estimated: `7288` // Minimum execution time: 33_277 nanoseconds. - Weight::from_ref_time(34_438_000) - .saturating_add(Weight::from_proof_size(7288)) + Weight::from_parts(34_438_000, 0) + .saturating_add(Weight::from_parts(0, 7288)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -868,8 +868,8 @@ impl WeightInfo for () { // Measured: `383` // Estimated: `3675` // Minimum execution time: 16_213 nanoseconds. - Weight::from_ref_time(16_575_000) - .saturating_add(Weight::from_proof_size(3675)) + Weight::from_parts(16_575_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/frame/babe/src/default_weights.rs b/frame/babe/src/default_weights.rs index e875bc83522c2..2e880fd67cc22 100644 --- a/frame/babe/src/default_weights.rs +++ b/frame/babe/src/default_weights.rs @@ -38,18 +38,19 @@ impl crate::WeightInfo for () { const MAX_NOMINATORS: u64 = 200; // checking membership proof - Weight::from_ref_time(35u64 * WEIGHT_REF_TIME_PER_MICROS) + Weight::from_parts(35u64 * WEIGHT_REF_TIME_PER_MICROS, 0) .saturating_add( - Weight::from_ref_time(175u64 * WEIGHT_REF_TIME_PER_NANOS) + Weight::from_parts(175u64 * WEIGHT_REF_TIME_PER_NANOS, 0) .saturating_mul(validator_count), ) .saturating_add(DbWeight::get().reads(5)) // check equivocation proof - .saturating_add(Weight::from_ref_time(110u64 * WEIGHT_REF_TIME_PER_MICROS)) + .saturating_add(Weight::from_parts(110u64 * WEIGHT_REF_TIME_PER_MICROS, 0)) // report offence - .saturating_add(Weight::from_ref_time(110u64 * WEIGHT_REF_TIME_PER_MICROS)) - .saturating_add(Weight::from_ref_time( + .saturating_add(Weight::from_parts(110u64 * WEIGHT_REF_TIME_PER_MICROS, 0)) + .saturating_add(Weight::from_parts( 25u64 * WEIGHT_REF_TIME_PER_MICROS * MAX_NOMINATORS, + 0, )) .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 82a6ee5f6d33b..b4233a6c3a85c 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::from_ref_time(1)), + &info_from_weight(Weight::from_parts(1, 0)), 1, ).is_err()); assert_ok!( as SignedExtension>::pre_dispatch( ChargeTransactionPayment::from(0), &1, CALL, - &info_from_weight(Weight::from_ref_time(1)), + &info_from_weight(Weight::from_parts(1, 0)), 1, )); @@ -206,14 +206,14 @@ macro_rules! decl_tests { ChargeTransactionPayment::from(1), &1, CALL, - &info_from_weight(Weight::from_ref_time(1)), + &info_from_weight(Weight::from_parts(1, 0)), 1, ).is_err()); assert!( as SignedExtension>::pre_dispatch( ChargeTransactionPayment::from(0), &1, CALL, - &info_from_weight(Weight::from_ref_time(1)), + &info_from_weight(Weight::from_parts(1, 0)), 1, ).is_err()); }); diff --git a/frame/balances/src/tests_composite.rs b/frame/balances/src/tests_composite.rs index 6f371f1e23010..765ab194d2011 100644 --- a/frame/balances/src/tests_composite.rs +++ b/frame/balances/src/tests_composite.rs @@ -48,7 +48,7 @@ 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).set_proof_size(u64::MAX), + frame_support::weights::Weight::from_parts(1024, u64::MAX), ); pub static ExistentialDeposit: u64 = 0; } diff --git a/frame/balances/src/tests_local.rs b/frame/balances/src/tests_local.rs index 0d57a33200147..929f77b540fe1 100644 --- a/frame/balances/src/tests_local.rs +++ b/frame/balances/src/tests_local.rs @@ -49,7 +49,7 @@ 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).set_proof_size(u64::MAX), + frame_support::weights::Weight::from_parts(1024, u64::MAX), ); pub static ExistentialDeposit: u64 = 0; } diff --git a/frame/balances/src/tests_reentrancy.rs b/frame/balances/src/tests_reentrancy.rs index 1699a879638e2..828dfa23707d0 100644 --- a/frame/balances/src/tests_reentrancy.rs +++ b/frame/balances/src/tests_reentrancy.rs @@ -52,7 +52,7 @@ 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).set_proof_size(u64::MAX), + frame_support::weights::Weight::from_parts(1024, u64::MAX), ); pub static ExistentialDeposit: u64 = 0; } diff --git a/frame/balances/src/weights.rs b/frame/balances/src/weights.rs index 8c307ff90924d..cdc657ce1656c 100644 --- a/frame/balances/src/weights.rs +++ b/frame/balances/src/weights.rs @@ -68,8 +68,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `3593` // Minimum execution time: 37_815 nanoseconds. - Weight::from_ref_time(38_109_000) - .saturating_add(Weight::from_proof_size(3593)) + Weight::from_parts(38_109_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -80,8 +80,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `3593` // Minimum execution time: 28_184 nanoseconds. - Weight::from_ref_time(49_250_000) - .saturating_add(Weight::from_proof_size(3593)) + Weight::from_parts(49_250_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -92,8 +92,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `206` // Estimated: `3593` // Minimum execution time: 17_474 nanoseconds. - Weight::from_ref_time(17_777_000) - .saturating_add(Weight::from_proof_size(3593)) + Weight::from_parts(17_777_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -104,8 +104,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `206` // Estimated: `3593` // Minimum execution time: 20_962 nanoseconds. - Weight::from_ref_time(21_419_000) - .saturating_add(Weight::from_proof_size(3593)) + Weight::from_parts(21_419_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -116,8 +116,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `135` // Estimated: `6196` // Minimum execution time: 39_713 nanoseconds. - Weight::from_ref_time(40_360_000) - .saturating_add(Weight::from_proof_size(6196)) + Weight::from_parts(40_360_000, 0) + .saturating_add(Weight::from_parts(0, 6196)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -128,8 +128,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `3593` // Minimum execution time: 34_878 nanoseconds. - Weight::from_ref_time(35_121_000) - .saturating_add(Weight::from_proof_size(3593)) + Weight::from_parts(35_121_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -140,8 +140,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `206` // Estimated: `3593` // Minimum execution time: 16_790 nanoseconds. - Weight::from_ref_time(17_029_000) - .saturating_add(Weight::from_proof_size(3593)) + Weight::from_parts(17_029_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -156,8 +156,8 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `3593` // Minimum execution time: 37_815 nanoseconds. - Weight::from_ref_time(38_109_000) - .saturating_add(Weight::from_proof_size(3593)) + Weight::from_parts(38_109_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -168,8 +168,8 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `3593` // Minimum execution time: 28_184 nanoseconds. - Weight::from_ref_time(49_250_000) - .saturating_add(Weight::from_proof_size(3593)) + Weight::from_parts(49_250_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -180,8 +180,8 @@ impl WeightInfo for () { // Measured: `206` // Estimated: `3593` // Minimum execution time: 17_474 nanoseconds. - Weight::from_ref_time(17_777_000) - .saturating_add(Weight::from_proof_size(3593)) + Weight::from_parts(17_777_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -192,8 +192,8 @@ impl WeightInfo for () { // Measured: `206` // Estimated: `3593` // Minimum execution time: 20_962 nanoseconds. - Weight::from_ref_time(21_419_000) - .saturating_add(Weight::from_proof_size(3593)) + Weight::from_parts(21_419_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -204,8 +204,8 @@ impl WeightInfo for () { // Measured: `135` // Estimated: `6196` // Minimum execution time: 39_713 nanoseconds. - Weight::from_ref_time(40_360_000) - .saturating_add(Weight::from_proof_size(6196)) + Weight::from_parts(40_360_000, 0) + .saturating_add(Weight::from_parts(0, 6196)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -216,8 +216,8 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `3593` // Minimum execution time: 34_878 nanoseconds. - Weight::from_ref_time(35_121_000) - .saturating_add(Weight::from_proof_size(3593)) + Weight::from_parts(35_121_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -228,8 +228,8 @@ impl WeightInfo for () { // Measured: `206` // Estimated: `3593` // Minimum execution time: 16_790 nanoseconds. - Weight::from_ref_time(17_029_000) - .saturating_add(Weight::from_proof_size(3593)) + Weight::from_parts(17_029_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/frame/beefy/src/default_weights.rs b/frame/beefy/src/default_weights.rs index 7743edf25ec6c..b15f1c88f9611 100644 --- a/frame/beefy/src/default_weights.rs +++ b/frame/beefy/src/default_weights.rs @@ -33,18 +33,19 @@ impl crate::WeightInfo for () { const MAX_NOMINATORS: u64 = 200; // checking membership proof - Weight::from_ref_time(35u64 * WEIGHT_REF_TIME_PER_MICROS) + Weight::from_parts(35u64 * WEIGHT_REF_TIME_PER_MICROS, 0) .saturating_add( - Weight::from_ref_time(175u64 * WEIGHT_REF_TIME_PER_NANOS) + Weight::from_parts(175u64 * WEIGHT_REF_TIME_PER_NANOS, 0) .saturating_mul(validator_count), ) .saturating_add(DbWeight::get().reads(5)) // check equivocation proof - .saturating_add(Weight::from_ref_time(95u64 * WEIGHT_REF_TIME_PER_MICROS)) + .saturating_add(Weight::from_parts(95u64 * WEIGHT_REF_TIME_PER_MICROS, 0)) // report offence - .saturating_add(Weight::from_ref_time(110u64 * WEIGHT_REF_TIME_PER_MICROS)) - .saturating_add(Weight::from_ref_time( + .saturating_add(Weight::from_parts(110u64 * WEIGHT_REF_TIME_PER_MICROS, 0)) + .saturating_add(Weight::from_parts( 25u64 * WEIGHT_REF_TIME_PER_MICROS * MAX_NOMINATORS, + 0, )) .saturating_add(DbWeight::get().reads(14 + 3 * MAX_NOMINATORS)) .saturating_add(DbWeight::get().writes(10 + 3 * MAX_NOMINATORS)) diff --git a/frame/benchmarking/pov/src/weights.rs b/frame/benchmarking/pov/src/weights.rs index 948d268cf7a4b..df6dba33b2dd3 100644 --- a/frame/benchmarking/pov/src/weights.rs +++ b/frame/benchmarking/pov/src/weights.rs @@ -73,8 +73,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `136` // Estimated: `1489` // Minimum execution time: 1_968 nanoseconds. - Weight::from_ref_time(2_060_000) - .saturating_add(Weight::from_proof_size(1489)) + Weight::from_parts(2_060_000, 0) + .saturating_add(Weight::from_parts(0, 1489)) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: Pov Value (r:1 w:0) @@ -84,8 +84,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `136` // Estimated: `0` // Minimum execution time: 1_934 nanoseconds. - Weight::from_ref_time(2_092_000) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(2_092_000, 0) + .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: Pov Value (r:1 w:0) @@ -97,8 +97,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `160` // Estimated: `1649` // Minimum execution time: 2_605 nanoseconds. - Weight::from_ref_time(2_786_000) - .saturating_add(Weight::from_proof_size(1649)) + Weight::from_parts(2_786_000, 0) + .saturating_add(Weight::from_parts(0, 1649)) .saturating_add(T::DbWeight::get().reads(2_u64)) } /// Storage: Pov Value (r:1 w:0) @@ -108,8 +108,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `136` // Estimated: `1489` // Minimum execution time: 2_019 nanoseconds. - Weight::from_ref_time(2_214_000) - .saturating_add(Weight::from_proof_size(1489)) + Weight::from_parts(2_214_000, 0) + .saturating_add(Weight::from_parts(0, 1489)) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: Pov Value (r:0 w:1) @@ -119,8 +119,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 279 nanoseconds. - Weight::from_ref_time(357_000) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(357_000, 0) + .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Pov Value (r:0 w:1) @@ -130,8 +130,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 291 nanoseconds. - Weight::from_ref_time(378_000) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(378_000, 0) + .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Pov Map1M (r:1 w:0) @@ -141,8 +141,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `1275` // Estimated: `4740` // Minimum execution time: 5_077 nanoseconds. - Weight::from_ref_time(5_400_000) - .saturating_add(Weight::from_proof_size(4740)) + Weight::from_parts(5_400_000, 0) + .saturating_add(Weight::from_parts(0, 4740)) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: Pov Map1M (r:1 w:0) @@ -152,8 +152,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `1544` // Estimated: `5009` // Minimum execution time: 5_878 nanoseconds. - Weight::from_ref_time(6_239_000) - .saturating_add(Weight::from_proof_size(5009)) + Weight::from_parts(6_239_000, 0) + .saturating_add(Weight::from_parts(0, 5009)) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: Pov Map1M (r:1 w:0) @@ -163,8 +163,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `2044` // Estimated: `5509` // Minimum execution time: 7_282 nanoseconds. - Weight::from_ref_time(8_022_000) - .saturating_add(Weight::from_proof_size(5509)) + Weight::from_parts(8_022_000, 0) + .saturating_add(Weight::from_parts(0, 5509)) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: Pov Map1M (r:100 w:0) @@ -178,16 +178,16 @@ impl WeightInfo for SubstrateWeight { // Measured: `515 + n * (188 ±0) + m * (188 ±0)` // Estimated: `1980 + n * (3006 ±0) + m * (2511 ±0)` // Minimum execution time: 195_406 nanoseconds. - Weight::from_ref_time(129_093_464) - .saturating_add(Weight::from_proof_size(1980)) + Weight::from_parts(129_093_464, 0) + .saturating_add(Weight::from_parts(0, 1980)) // Standard Error: 12_134 - .saturating_add(Weight::from_ref_time(855_330).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(855_330, 0).saturating_mul(n.into())) // Standard Error: 12_134 - .saturating_add(Weight::from_ref_time(870_523).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(870_523, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(m.into()))) - .saturating_add(Weight::from_proof_size(3006).saturating_mul(n.into())) - .saturating_add(Weight::from_proof_size(2511).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 3006).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 2511).saturating_mul(m.into())) } /// Storage: Pov Map1M (r:100 w:0) /// Proof: Pov Map1M (max_values: Some(1000000), max_size: Some(36), added: 2511, mode: Ignored) @@ -200,16 +200,16 @@ impl WeightInfo for SubstrateWeight { // Measured: `515 + n * (188 ±0) + m * (188 ±0)` // Estimated: `1685 + n * (3195 ±0) + m * (189 ±0)` // Minimum execution time: 195_053 nanoseconds. - Weight::from_ref_time(131_322_479) - .saturating_add(Weight::from_proof_size(1685)) + Weight::from_parts(131_322_479, 0) + .saturating_add(Weight::from_parts(0, 1685)) // Standard Error: 12_161 - .saturating_add(Weight::from_ref_time(843_047).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(843_047, 0).saturating_mul(n.into())) // Standard Error: 12_161 - .saturating_add(Weight::from_ref_time(858_668).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(858_668, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(m.into()))) - .saturating_add(Weight::from_proof_size(3195).saturating_mul(n.into())) - .saturating_add(Weight::from_proof_size(189).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 3195).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 189).saturating_mul(m.into())) } /// Storage: Pov Map1M (r:1 w:0) /// Proof: Pov Map1M (max_values: Some(1000000), max_size: Some(36), added: 2511, mode: MaxEncodedLen) @@ -219,10 +219,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `170` // Estimated: `3501` // Minimum execution time: 22 nanoseconds. - Weight::from_ref_time(2_334_945) - .saturating_add(Weight::from_proof_size(3501)) + Weight::from_parts(2_334_945, 0) + .saturating_add(Weight::from_parts(0, 3501)) // Standard Error: 624 - .saturating_add(Weight::from_ref_time(282_046).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(282_046, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: Pov Map1M (r:100 w:0) @@ -233,12 +233,12 @@ impl WeightInfo for SubstrateWeight { // Measured: `147 + n * (40 ±0)` // Estimated: `990 + n * (2511 ±0)` // Minimum execution time: 20 nanoseconds. - Weight::from_ref_time(525_027) - .saturating_add(Weight::from_proof_size(990)) + Weight::from_parts(525_027, 0) + .saturating_add(Weight::from_parts(0, 990)) // Standard Error: 2_767 - .saturating_add(Weight::from_ref_time(3_887_350).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(3_887_350, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_proof_size(2511).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 2511).saturating_mul(n.into())) } /// Storage: Pov DoubleMap1M (r:1024 w:0) /// Proof: Pov DoubleMap1M (max_values: Some(1000000), max_size: Some(68), added: 2543, mode: MaxEncodedLen) @@ -248,12 +248,12 @@ impl WeightInfo for SubstrateWeight { // Measured: `21938 + n * (57 ±0)` // Estimated: `990 + n * (2543 ±0)` // Minimum execution time: 34 nanoseconds. - Weight::from_ref_time(18_341_393) - .saturating_add(Weight::from_proof_size(990)) + Weight::from_parts(18_341_393, 0) + .saturating_add(Weight::from_parts(0, 990)) // Standard Error: 1_312 - .saturating_add(Weight::from_ref_time(2_053_135).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(2_053_135, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_proof_size(2543).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 2543).saturating_mul(n.into())) } /// Storage: Pov BoundedValue (r:1 w:0) /// Proof: Pov BoundedValue (max_values: Some(1), max_size: Some(33), added: 528, mode: MaxEncodedLen) @@ -262,8 +262,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `109` // Estimated: `1518` // Minimum execution time: 1_163 nanoseconds. - Weight::from_ref_time(1_274_000) - .saturating_add(Weight::from_proof_size(1518)) + Weight::from_parts(1_274_000, 0) + .saturating_add(Weight::from_parts(0, 1518)) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: Pov UnboundedValue (r:1 w:0) @@ -273,8 +273,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `109` // Estimated: `1594` // Minimum execution time: 1_167 nanoseconds. - Weight::from_ref_time(1_367_000) - .saturating_add(Weight::from_proof_size(1594)) + Weight::from_parts(1_367_000, 0) + .saturating_add(Weight::from_parts(0, 1594)) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: Pov UnboundedValue (r:1 w:0) @@ -284,8 +284,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `109` // Estimated: `0` // Minimum execution time: 1_155 nanoseconds. - Weight::from_ref_time(1_248_000) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_248_000, 0) + .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: Pov UnboundedValue (r:1 w:0) @@ -297,8 +297,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `109` // Estimated: `3112` // Minimum execution time: 1_424 nanoseconds. - Weight::from_ref_time(1_601_000) - .saturating_add(Weight::from_proof_size(3112)) + Weight::from_parts(1_601_000, 0) + .saturating_add(Weight::from_parts(0, 3112)) .saturating_add(T::DbWeight::get().reads(2_u64)) } /// Storage: Pov LargeValue (r:1 w:0) @@ -309,12 +309,12 @@ impl WeightInfo for SubstrateWeight { // Measured: `174 + l * (1 ±0)` // Estimated: `1656 + l * (1 ±0)` // Minimum execution time: 1_744 nanoseconds. - Weight::from_ref_time(1_800_000) - .saturating_add(Weight::from_proof_size(1656)) + Weight::from_parts(1_800_000, 0) + .saturating_add(Weight::from_parts(0, 1656)) // Standard Error: 4 - .saturating_add(Weight::from_ref_time(443).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(443, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) - .saturating_add(Weight::from_proof_size(1).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(0, 1).saturating_mul(l.into())) } /// Storage: Pov LargeValue (r:1 w:0) /// Proof: Pov LargeValue (max_values: Some(1), max_size: Some(4194308), added: 4194803, mode: MaxEncodedLen) @@ -324,10 +324,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `174 + l * (1 ±0)` // Estimated: `4195793` // Minimum execution time: 1_770 nanoseconds. - Weight::from_ref_time(1_813_000) - .saturating_add(Weight::from_proof_size(4195793)) + Weight::from_parts(1_813_000, 0) + .saturating_add(Weight::from_parts(0, 4195793)) // Standard Error: 6 - .saturating_add(Weight::from_ref_time(495).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(495, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: Pov LargeValue (r:1 w:0) @@ -340,12 +340,12 @@ impl WeightInfo for SubstrateWeight { // Measured: `235 + l * (2 ±0)` // Estimated: `3428 + l * (4 ±0)` // Minimum execution time: 2_349 nanoseconds. - Weight::from_ref_time(2_423_000) - .saturating_add(Weight::from_proof_size(3428)) + Weight::from_parts(2_423_000, 0) + .saturating_add(Weight::from_parts(0, 3428)) // Standard Error: 11 - .saturating_add(Weight::from_ref_time(950).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(950, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(Weight::from_proof_size(4).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(0, 4).saturating_mul(l.into())) } /// Storage: Pov LargeValue (r:1 w:0) /// Proof: Pov LargeValue (max_values: Some(1), max_size: Some(4194308), added: 4194803, mode: MaxEncodedLen) @@ -357,10 +357,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `235 + l * (2 ±0)` // Estimated: `8391586` // Minimum execution time: 2_315 nanoseconds. - Weight::from_ref_time(2_409_000) - .saturating_add(Weight::from_proof_size(8391586)) + Weight::from_parts(2_409_000, 0) + .saturating_add(Weight::from_parts(0, 8391586)) // Standard Error: 12 - .saturating_add(Weight::from_ref_time(984).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(984, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) } /// Storage: Pov LargeValue (r:1 w:0) @@ -373,12 +373,12 @@ impl WeightInfo for SubstrateWeight { // Measured: `235 + l * (2 ±0)` // Estimated: `4197507 + l * (2 ±0)` // Minimum execution time: 2_370 nanoseconds. - Weight::from_ref_time(2_474_000) - .saturating_add(Weight::from_proof_size(4197507)) + Weight::from_parts(2_474_000, 0) + .saturating_add(Weight::from_parts(0, 4197507)) // Standard Error: 11 - .saturating_add(Weight::from_ref_time(956).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(956, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(Weight::from_proof_size(2).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(0, 2).saturating_mul(l.into())) } /// Storage: Pov LargeValue (r:1 w:0) /// Proof: Pov LargeValue (max_values: Some(1), max_size: Some(4194308), added: 4194803, mode: Measured) @@ -390,12 +390,12 @@ impl WeightInfo for SubstrateWeight { // Measured: `235 + l * (2 ±0)` // Estimated: `4197507 + l * (2 ±0)` // Minimum execution time: 2_375 nanoseconds. - Weight::from_ref_time(2_420_000) - .saturating_add(Weight::from_proof_size(4197507)) + Weight::from_parts(2_420_000, 0) + .saturating_add(Weight::from_parts(0, 4197507)) // Standard Error: 9 - .saturating_add(Weight::from_ref_time(914).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(914, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(Weight::from_proof_size(2).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(0, 2).saturating_mul(l.into())) } /// Storage: Pov UnboundedMap (r:1 w:0) /// Proof Skipped: Pov UnboundedMap (max_values: None, max_size: None, mode: Measured) @@ -407,12 +407,12 @@ impl WeightInfo for SubstrateWeight { // Measured: `293 + i * (8 ±0)` // Estimated: `7504 + i * (16 ±0)` // Minimum execution time: 3_305 nanoseconds. - Weight::from_ref_time(3_689_335) - .saturating_add(Weight::from_proof_size(7504)) + Weight::from_parts(3_689_335, 0) + .saturating_add(Weight::from_parts(0, 7504)) // Standard Error: 29 - .saturating_add(Weight::from_ref_time(638).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(638, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(Weight::from_proof_size(16).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(0, 16).saturating_mul(i.into())) } /// Storage: Pov Map1M (r:1 w:0) /// Proof: Pov Map1M (max_values: Some(1000000), max_size: Some(36), added: 2511, mode: MaxEncodedLen) @@ -424,12 +424,12 @@ impl WeightInfo for SubstrateWeight { // Measured: `260 + i * (4 ±0)` // Estimated: `7223 + i * (4 ±0)` // Minimum execution time: 3_469 nanoseconds. - Weight::from_ref_time(3_878_896) - .saturating_add(Weight::from_proof_size(7223)) + Weight::from_parts(3_878_896, 0) + .saturating_add(Weight::from_parts(0, 7223)) // Standard Error: 33 - .saturating_add(Weight::from_ref_time(356).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(356, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(Weight::from_proof_size(4).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(0, 4).saturating_mul(i.into())) } /// Storage: Pov Map1M (r:1 w:0) /// Proof: Pov Map1M (max_values: Some(1000000), max_size: Some(36), added: 2511, mode: MaxEncodedLen) @@ -441,28 +441,28 @@ impl WeightInfo for SubstrateWeight { // Measured: `260 + i * (4 ±0)` // Estimated: `3758 + i * (4 ±0)` // Minimum execution time: 3_442 nanoseconds. - Weight::from_ref_time(3_881_051) - .saturating_add(Weight::from_proof_size(3758)) + Weight::from_parts(3_881_051, 0) + .saturating_add(Weight::from_parts(0, 3758)) // Standard Error: 35 - .saturating_add(Weight::from_ref_time(384).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(384, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(Weight::from_proof_size(4).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(0, 4).saturating_mul(i.into())) } fn emit_event() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` // Minimum execution time: 1_619 nanoseconds. - Weight::from_ref_time(1_728_000) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_728_000, 0) + .saturating_add(Weight::from_parts(0, 0)) } fn noop() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` // Minimum execution time: 546 nanoseconds. - Weight::from_ref_time(640_000) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(640_000, 0) + .saturating_add(Weight::from_parts(0, 0)) } } @@ -475,8 +475,8 @@ impl WeightInfo for () { // Measured: `136` // Estimated: `1489` // Minimum execution time: 1_968 nanoseconds. - Weight::from_ref_time(2_060_000) - .saturating_add(Weight::from_proof_size(1489)) + Weight::from_parts(2_060_000, 0) + .saturating_add(Weight::from_parts(0, 1489)) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: Pov Value (r:1 w:0) @@ -486,8 +486,8 @@ impl WeightInfo for () { // Measured: `136` // Estimated: `0` // Minimum execution time: 1_934 nanoseconds. - Weight::from_ref_time(2_092_000) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(2_092_000, 0) + .saturating_add(Weight::from_parts(0, 0)) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: Pov Value (r:1 w:0) @@ -499,8 +499,8 @@ impl WeightInfo for () { // Measured: `160` // Estimated: `1649` // Minimum execution time: 2_605 nanoseconds. - Weight::from_ref_time(2_786_000) - .saturating_add(Weight::from_proof_size(1649)) + Weight::from_parts(2_786_000, 0) + .saturating_add(Weight::from_parts(0, 1649)) .saturating_add(RocksDbWeight::get().reads(2_u64)) } /// Storage: Pov Value (r:1 w:0) @@ -510,8 +510,8 @@ impl WeightInfo for () { // Measured: `136` // Estimated: `1489` // Minimum execution time: 2_019 nanoseconds. - Weight::from_ref_time(2_214_000) - .saturating_add(Weight::from_proof_size(1489)) + Weight::from_parts(2_214_000, 0) + .saturating_add(Weight::from_parts(0, 1489)) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: Pov Value (r:0 w:1) @@ -521,8 +521,8 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 279 nanoseconds. - Weight::from_ref_time(357_000) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(357_000, 0) + .saturating_add(Weight::from_parts(0, 0)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Pov Value (r:0 w:1) @@ -532,8 +532,8 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 291 nanoseconds. - Weight::from_ref_time(378_000) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(378_000, 0) + .saturating_add(Weight::from_parts(0, 0)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Pov Map1M (r:1 w:0) @@ -543,8 +543,8 @@ impl WeightInfo for () { // Measured: `1275` // Estimated: `4740` // Minimum execution time: 5_077 nanoseconds. - Weight::from_ref_time(5_400_000) - .saturating_add(Weight::from_proof_size(4740)) + Weight::from_parts(5_400_000, 0) + .saturating_add(Weight::from_parts(0, 4740)) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: Pov Map1M (r:1 w:0) @@ -554,8 +554,8 @@ impl WeightInfo for () { // Measured: `1544` // Estimated: `5009` // Minimum execution time: 5_878 nanoseconds. - Weight::from_ref_time(6_239_000) - .saturating_add(Weight::from_proof_size(5009)) + Weight::from_parts(6_239_000, 0) + .saturating_add(Weight::from_parts(0, 5009)) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: Pov Map1M (r:1 w:0) @@ -565,8 +565,8 @@ impl WeightInfo for () { // Measured: `2044` // Estimated: `5509` // Minimum execution time: 7_282 nanoseconds. - Weight::from_ref_time(8_022_000) - .saturating_add(Weight::from_proof_size(5509)) + Weight::from_parts(8_022_000, 0) + .saturating_add(Weight::from_parts(0, 5509)) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: Pov Map1M (r:100 w:0) @@ -580,16 +580,16 @@ impl WeightInfo for () { // Measured: `515 + n * (188 ±0) + m * (188 ±0)` // Estimated: `1980 + n * (3006 ±0) + m * (2511 ±0)` // Minimum execution time: 195_406 nanoseconds. - Weight::from_ref_time(129_093_464) - .saturating_add(Weight::from_proof_size(1980)) + Weight::from_parts(129_093_464, 0) + .saturating_add(Weight::from_parts(0, 1980)) // Standard Error: 12_134 - .saturating_add(Weight::from_ref_time(855_330).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(855_330, 0).saturating_mul(n.into())) // Standard Error: 12_134 - .saturating_add(Weight::from_ref_time(870_523).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(870_523, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(m.into()))) - .saturating_add(Weight::from_proof_size(3006).saturating_mul(n.into())) - .saturating_add(Weight::from_proof_size(2511).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 3006).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 2511).saturating_mul(m.into())) } /// Storage: Pov Map1M (r:100 w:0) /// Proof: Pov Map1M (max_values: Some(1000000), max_size: Some(36), added: 2511, mode: Ignored) @@ -602,16 +602,16 @@ impl WeightInfo for () { // Measured: `515 + n * (188 ±0) + m * (188 ±0)` // Estimated: `1685 + n * (3195 ±0) + m * (189 ±0)` // Minimum execution time: 195_053 nanoseconds. - Weight::from_ref_time(131_322_479) - .saturating_add(Weight::from_proof_size(1685)) + Weight::from_parts(131_322_479, 0) + .saturating_add(Weight::from_parts(0, 1685)) // Standard Error: 12_161 - .saturating_add(Weight::from_ref_time(843_047).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(843_047, 0).saturating_mul(n.into())) // Standard Error: 12_161 - .saturating_add(Weight::from_ref_time(858_668).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(858_668, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(m.into()))) - .saturating_add(Weight::from_proof_size(3195).saturating_mul(n.into())) - .saturating_add(Weight::from_proof_size(189).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 3195).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 189).saturating_mul(m.into())) } /// Storage: Pov Map1M (r:1 w:0) /// Proof: Pov Map1M (max_values: Some(1000000), max_size: Some(36), added: 2511, mode: MaxEncodedLen) @@ -621,10 +621,10 @@ impl WeightInfo for () { // Measured: `170` // Estimated: `3501` // Minimum execution time: 22 nanoseconds. - Weight::from_ref_time(2_334_945) - .saturating_add(Weight::from_proof_size(3501)) + Weight::from_parts(2_334_945, 0) + .saturating_add(Weight::from_parts(0, 3501)) // Standard Error: 624 - .saturating_add(Weight::from_ref_time(282_046).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(282_046, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: Pov Map1M (r:100 w:0) @@ -635,12 +635,12 @@ impl WeightInfo for () { // Measured: `147 + n * (40 ±0)` // Estimated: `990 + n * (2511 ±0)` // Minimum execution time: 20 nanoseconds. - Weight::from_ref_time(525_027) - .saturating_add(Weight::from_proof_size(990)) + Weight::from_parts(525_027, 0) + .saturating_add(Weight::from_parts(0, 990)) // Standard Error: 2_767 - .saturating_add(Weight::from_ref_time(3_887_350).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(3_887_350, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_proof_size(2511).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 2511).saturating_mul(n.into())) } /// Storage: Pov DoubleMap1M (r:1024 w:0) /// Proof: Pov DoubleMap1M (max_values: Some(1000000), max_size: Some(68), added: 2543, mode: MaxEncodedLen) @@ -650,12 +650,12 @@ impl WeightInfo for () { // Measured: `21938 + n * (57 ±0)` // Estimated: `990 + n * (2543 ±0)` // Minimum execution time: 34 nanoseconds. - Weight::from_ref_time(18_341_393) - .saturating_add(Weight::from_proof_size(990)) + Weight::from_parts(18_341_393, 0) + .saturating_add(Weight::from_parts(0, 990)) // Standard Error: 1_312 - .saturating_add(Weight::from_ref_time(2_053_135).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(2_053_135, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_proof_size(2543).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 2543).saturating_mul(n.into())) } /// Storage: Pov BoundedValue (r:1 w:0) /// Proof: Pov BoundedValue (max_values: Some(1), max_size: Some(33), added: 528, mode: MaxEncodedLen) @@ -664,8 +664,8 @@ impl WeightInfo for () { // Measured: `109` // Estimated: `1518` // Minimum execution time: 1_163 nanoseconds. - Weight::from_ref_time(1_274_000) - .saturating_add(Weight::from_proof_size(1518)) + Weight::from_parts(1_274_000, 0) + .saturating_add(Weight::from_parts(0, 1518)) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: Pov UnboundedValue (r:1 w:0) @@ -675,8 +675,8 @@ impl WeightInfo for () { // Measured: `109` // Estimated: `1594` // Minimum execution time: 1_167 nanoseconds. - Weight::from_ref_time(1_367_000) - .saturating_add(Weight::from_proof_size(1594)) + Weight::from_parts(1_367_000, 0) + .saturating_add(Weight::from_parts(0, 1594)) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: Pov UnboundedValue (r:1 w:0) @@ -686,8 +686,8 @@ impl WeightInfo for () { // Measured: `109` // Estimated: `0` // Minimum execution time: 1_155 nanoseconds. - Weight::from_ref_time(1_248_000) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_248_000, 0) + .saturating_add(Weight::from_parts(0, 0)) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: Pov UnboundedValue (r:1 w:0) @@ -699,8 +699,8 @@ impl WeightInfo for () { // Measured: `109` // Estimated: `3112` // Minimum execution time: 1_424 nanoseconds. - Weight::from_ref_time(1_601_000) - .saturating_add(Weight::from_proof_size(3112)) + Weight::from_parts(1_601_000, 0) + .saturating_add(Weight::from_parts(0, 3112)) .saturating_add(RocksDbWeight::get().reads(2_u64)) } /// Storage: Pov LargeValue (r:1 w:0) @@ -711,12 +711,12 @@ impl WeightInfo for () { // Measured: `174 + l * (1 ±0)` // Estimated: `1656 + l * (1 ±0)` // Minimum execution time: 1_744 nanoseconds. - Weight::from_ref_time(1_800_000) - .saturating_add(Weight::from_proof_size(1656)) + Weight::from_parts(1_800_000, 0) + .saturating_add(Weight::from_parts(0, 1656)) // Standard Error: 4 - .saturating_add(Weight::from_ref_time(443).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(443, 0).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) - .saturating_add(Weight::from_proof_size(1).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(0, 1).saturating_mul(l.into())) } /// Storage: Pov LargeValue (r:1 w:0) /// Proof: Pov LargeValue (max_values: Some(1), max_size: Some(4194308), added: 4194803, mode: MaxEncodedLen) @@ -726,10 +726,10 @@ impl WeightInfo for () { // Measured: `174 + l * (1 ±0)` // Estimated: `4195793` // Minimum execution time: 1_770 nanoseconds. - Weight::from_ref_time(1_813_000) - .saturating_add(Weight::from_proof_size(4195793)) + Weight::from_parts(1_813_000, 0) + .saturating_add(Weight::from_parts(0, 4195793)) // Standard Error: 6 - .saturating_add(Weight::from_ref_time(495).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(495, 0).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: Pov LargeValue (r:1 w:0) @@ -742,12 +742,12 @@ impl WeightInfo for () { // Measured: `235 + l * (2 ±0)` // Estimated: `3428 + l * (4 ±0)` // Minimum execution time: 2_349 nanoseconds. - Weight::from_ref_time(2_423_000) - .saturating_add(Weight::from_proof_size(3428)) + Weight::from_parts(2_423_000, 0) + .saturating_add(Weight::from_parts(0, 3428)) // Standard Error: 11 - .saturating_add(Weight::from_ref_time(950).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(950, 0).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(Weight::from_proof_size(4).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(0, 4).saturating_mul(l.into())) } /// Storage: Pov LargeValue (r:1 w:0) /// Proof: Pov LargeValue (max_values: Some(1), max_size: Some(4194308), added: 4194803, mode: MaxEncodedLen) @@ -759,10 +759,10 @@ impl WeightInfo for () { // Measured: `235 + l * (2 ±0)` // Estimated: `8391586` // Minimum execution time: 2_315 nanoseconds. - Weight::from_ref_time(2_409_000) - .saturating_add(Weight::from_proof_size(8391586)) + Weight::from_parts(2_409_000, 0) + .saturating_add(Weight::from_parts(0, 8391586)) // Standard Error: 12 - .saturating_add(Weight::from_ref_time(984).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(984, 0).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) } /// Storage: Pov LargeValue (r:1 w:0) @@ -775,12 +775,12 @@ impl WeightInfo for () { // Measured: `235 + l * (2 ±0)` // Estimated: `4197507 + l * (2 ±0)` // Minimum execution time: 2_370 nanoseconds. - Weight::from_ref_time(2_474_000) - .saturating_add(Weight::from_proof_size(4197507)) + Weight::from_parts(2_474_000, 0) + .saturating_add(Weight::from_parts(0, 4197507)) // Standard Error: 11 - .saturating_add(Weight::from_ref_time(956).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(956, 0).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(Weight::from_proof_size(2).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(0, 2).saturating_mul(l.into())) } /// Storage: Pov LargeValue (r:1 w:0) /// Proof: Pov LargeValue (max_values: Some(1), max_size: Some(4194308), added: 4194803, mode: Measured) @@ -792,12 +792,12 @@ impl WeightInfo for () { // Measured: `235 + l * (2 ±0)` // Estimated: `4197507 + l * (2 ±0)` // Minimum execution time: 2_375 nanoseconds. - Weight::from_ref_time(2_420_000) - .saturating_add(Weight::from_proof_size(4197507)) + Weight::from_parts(2_420_000, 0) + .saturating_add(Weight::from_parts(0, 4197507)) // Standard Error: 9 - .saturating_add(Weight::from_ref_time(914).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(914, 0).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(Weight::from_proof_size(2).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(0, 2).saturating_mul(l.into())) } /// Storage: Pov UnboundedMap (r:1 w:0) /// Proof Skipped: Pov UnboundedMap (max_values: None, max_size: None, mode: Measured) @@ -809,12 +809,12 @@ impl WeightInfo for () { // Measured: `293 + i * (8 ±0)` // Estimated: `7504 + i * (16 ±0)` // Minimum execution time: 3_305 nanoseconds. - Weight::from_ref_time(3_689_335) - .saturating_add(Weight::from_proof_size(7504)) + Weight::from_parts(3_689_335, 0) + .saturating_add(Weight::from_parts(0, 7504)) // Standard Error: 29 - .saturating_add(Weight::from_ref_time(638).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(638, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(Weight::from_proof_size(16).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(0, 16).saturating_mul(i.into())) } /// Storage: Pov Map1M (r:1 w:0) /// Proof: Pov Map1M (max_values: Some(1000000), max_size: Some(36), added: 2511, mode: MaxEncodedLen) @@ -826,12 +826,12 @@ impl WeightInfo for () { // Measured: `260 + i * (4 ±0)` // Estimated: `7223 + i * (4 ±0)` // Minimum execution time: 3_469 nanoseconds. - Weight::from_ref_time(3_878_896) - .saturating_add(Weight::from_proof_size(7223)) + Weight::from_parts(3_878_896, 0) + .saturating_add(Weight::from_parts(0, 7223)) // Standard Error: 33 - .saturating_add(Weight::from_ref_time(356).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(356, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(Weight::from_proof_size(4).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(0, 4).saturating_mul(i.into())) } /// Storage: Pov Map1M (r:1 w:0) /// Proof: Pov Map1M (max_values: Some(1000000), max_size: Some(36), added: 2511, mode: MaxEncodedLen) @@ -843,27 +843,27 @@ impl WeightInfo for () { // Measured: `260 + i * (4 ±0)` // Estimated: `3758 + i * (4 ±0)` // Minimum execution time: 3_442 nanoseconds. - Weight::from_ref_time(3_881_051) - .saturating_add(Weight::from_proof_size(3758)) + Weight::from_parts(3_881_051, 0) + .saturating_add(Weight::from_parts(0, 3758)) // Standard Error: 35 - .saturating_add(Weight::from_ref_time(384).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(384, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(Weight::from_proof_size(4).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(0, 4).saturating_mul(i.into())) } fn emit_event() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` // Minimum execution time: 1_619 nanoseconds. - Weight::from_ref_time(1_728_000) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_728_000, 0) + .saturating_add(Weight::from_parts(0, 0)) } fn noop() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` // Minimum execution time: 546 nanoseconds. - Weight::from_ref_time(640_000) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(640_000, 0) + .saturating_add(Weight::from_parts(0, 0)) } } diff --git a/frame/benchmarking/src/weights.rs b/frame/benchmarking/src/weights.rs index 85dbb18c7e024..fdd4429f2039b 100644 --- a/frame/benchmarking/src/weights.rs +++ b/frame/benchmarking/src/weights.rs @@ -65,7 +65,7 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 138 nanoseconds. - Weight::from_ref_time(199_805) + Weight::from_parts(199_805, 0) } /// The range of component `i` is `[0, 1000000]`. fn subtraction(_i: u32, ) -> Weight { @@ -73,7 +73,7 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 142 nanoseconds. - Weight::from_ref_time(201_435) + Weight::from_parts(201_435, 0) } /// The range of component `i` is `[0, 1000000]`. fn multiplication(_i: u32, ) -> Weight { @@ -81,7 +81,7 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 138 nanoseconds. - Weight::from_ref_time(207_037) + Weight::from_parts(207_037, 0) } /// The range of component `i` is `[0, 1000000]`. fn division(_i: u32, ) -> Weight { @@ -89,14 +89,14 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 151 nanoseconds. - Weight::from_ref_time(205_150) + Weight::from_parts(205_150, 0) } fn hashing() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` // Minimum execution time: 21_950_884 nanoseconds. - Weight::from_ref_time(21_994_001_000) + Weight::from_parts(21_994_001_000, 0) } /// The range of component `i` is `[0, 100]`. fn sr25519_verification(i: u32, ) -> Weight { @@ -104,9 +104,9 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 168 nanoseconds. - Weight::from_ref_time(1_680_898) + Weight::from_parts(1_680_898, 0) // Standard Error: 10_291 - .saturating_add(Weight::from_ref_time(46_867_301).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(46_867_301, 0).saturating_mul(i.into())) } } @@ -118,7 +118,7 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 138 nanoseconds. - Weight::from_ref_time(199_805) + Weight::from_parts(199_805, 0) } /// The range of component `i` is `[0, 1000000]`. fn subtraction(_i: u32, ) -> Weight { @@ -126,7 +126,7 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 142 nanoseconds. - Weight::from_ref_time(201_435) + Weight::from_parts(201_435, 0) } /// The range of component `i` is `[0, 1000000]`. fn multiplication(_i: u32, ) -> Weight { @@ -134,7 +134,7 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 138 nanoseconds. - Weight::from_ref_time(207_037) + Weight::from_parts(207_037, 0) } /// The range of component `i` is `[0, 1000000]`. fn division(_i: u32, ) -> Weight { @@ -142,14 +142,14 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 151 nanoseconds. - Weight::from_ref_time(205_150) + Weight::from_parts(205_150, 0) } fn hashing() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` // Minimum execution time: 21_950_884 nanoseconds. - Weight::from_ref_time(21_994_001_000) + Weight::from_parts(21_994_001_000, 0) } /// The range of component `i` is `[0, 100]`. fn sr25519_verification(i: u32, ) -> Weight { @@ -157,8 +157,8 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 168 nanoseconds. - Weight::from_ref_time(1_680_898) + Weight::from_parts(1_680_898, 0) // Standard Error: 10_291 - .saturating_add(Weight::from_ref_time(46_867_301).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(46_867_301, 0).saturating_mul(i.into())) } } diff --git a/frame/bounties/src/weights.rs b/frame/bounties/src/weights.rs index 174891f9589d3..f0ea78b5f1e8d 100644 --- a/frame/bounties/src/weights.rs +++ b/frame/bounties/src/weights.rs @@ -80,7 +80,7 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 22_787 nanoseconds. Weight::from_parts(23_898_632, 3102) // Standard Error: 141 - .saturating_add(Weight::from_ref_time(568).saturating_mul(d.into())) + .saturating_add(Weight::from_parts(568, 0).saturating_mul(d.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -223,12 +223,12 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 4_685 nanoseconds. Weight::from_parts(9_932_840, 897) // Standard Error: 14_301 - .saturating_add(Weight::from_ref_time(27_178_347).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(27_178_347, 0).saturating_mul(b.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(b.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(b.into()))) - .saturating_add(Weight::from_proof_size(7858).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(0, 7858).saturating_mul(b.into())) } } @@ -250,7 +250,7 @@ impl WeightInfo for () { // Minimum execution time: 22_787 nanoseconds. Weight::from_parts(23_898_632, 3102) // Standard Error: 141 - .saturating_add(Weight::from_ref_time(568).saturating_mul(d.into())) + .saturating_add(Weight::from_parts(568, 0).saturating_mul(d.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -393,11 +393,11 @@ impl WeightInfo for () { // Minimum execution time: 4_685 nanoseconds. Weight::from_parts(9_932_840, 897) // Standard Error: 14_301 - .saturating_add(Weight::from_ref_time(27_178_347).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(27_178_347, 0).saturating_mul(b.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(b.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(b.into()))) - .saturating_add(Weight::from_proof_size(7858).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(0, 7858).saturating_mul(b.into())) } } diff --git a/frame/child-bounties/src/tests.rs b/frame/child-bounties/src/tests.rs index b4b24eb910293..0172468ec55d6 100644 --- a/frame/child-bounties/src/tests.rs +++ b/frame/child-bounties/src/tests.rs @@ -59,7 +59,7 @@ frame_support::construct_runtime!( ); parameter_types! { - pub const MaximumBlockWeight: Weight = Weight::from_ref_time(1024); + pub const MaximumBlockWeight: Weight = Weight::from_parts(1024, 0); 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 e27393de9d350..eeb14419678d7 100644 --- a/frame/child-bounties/src/weights.rs +++ b/frame/child-bounties/src/weights.rs @@ -81,7 +81,7 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 46_743 nanoseconds. Weight::from_parts(47_762_924, 10848) // Standard Error: 135 - .saturating_add(Weight::from_ref_time(599).saturating_mul(d.into())) + .saturating_add(Weight::from_parts(599, 0).saturating_mul(d.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -226,7 +226,7 @@ impl WeightInfo for () { // Minimum execution time: 46_743 nanoseconds. Weight::from_parts(47_762_924, 10848) // Standard Error: 135 - .saturating_add(Weight::from_ref_time(599).saturating_mul(d.into())) + .saturating_add(Weight::from_parts(599, 0).saturating_mul(d.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } diff --git a/frame/collective/src/tests.rs b/frame/collective/src/tests.rs index bfc6a0249b76c..2d9b31a539d59 100644 --- a/frame/collective/src/tests.rs +++ b/frame/collective/src/tests.rs @@ -288,7 +288,7 @@ fn proposal_weight_limit_works_on_approve() { RuntimeOrigin::signed(4), hash, 0, - proposal_weight - Weight::from_ref_time(100), + proposal_weight - Weight::from_parts(100, 0), proposal_len ), Error::::WrongProposalWeight @@ -327,7 +327,7 @@ fn proposal_weight_limit_ignored_on_disapprove() { RuntimeOrigin::signed(4), hash, 0, - proposal_weight - Weight::from_ref_time(100), + proposal_weight - Weight::from_parts(100, 0), proposal_len )); }) @@ -750,7 +750,7 @@ fn correct_validate_and_get_proposal() { Collective::validate_and_get_proposal( &hash, length, - weight - Weight::from_ref_time(10) + weight - Weight::from_parts(10, 0) ), Error::::WrongProposalWeight ); diff --git a/frame/collective/src/weights.rs b/frame/collective/src/weights.rs index d8a7131186424..df233fc248e3d 100644 --- a/frame/collective/src/weights.rs +++ b/frame/collective/src/weights.rs @@ -81,15 +81,15 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 17_093 nanoseconds. Weight::from_parts(17_284_000, 16586) // Standard Error: 64_700 - .saturating_add(Weight::from_ref_time(5_143_145).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(5_143_145, 0).saturating_mul(m.into())) // Standard Error: 64_700 - .saturating_add(Weight::from_ref_time(7_480_941).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(7_480_941, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(p.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(p.into()))) - .saturating_add(Weight::from_proof_size(7809).saturating_mul(m.into())) - .saturating_add(Weight::from_proof_size(10238).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 7809).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 10238).saturating_mul(p.into())) } /// Storage: Council Members (r:1 w:0) /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) @@ -102,11 +102,11 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 15_972 nanoseconds. Weight::from_parts(14_971_445, 730) // Standard Error: 32 - .saturating_add(Weight::from_ref_time(1_775).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(1_775, 0).saturating_mul(b.into())) // Standard Error: 334 - .saturating_add(Weight::from_ref_time(17_052).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(17_052, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) - .saturating_add(Weight::from_proof_size(32).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 32).saturating_mul(m.into())) } /// Storage: Council Members (r:1 w:0) /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) @@ -121,11 +121,11 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 17_950 nanoseconds. Weight::from_parts(17_019_558, 3440) // Standard Error: 41 - .saturating_add(Weight::from_ref_time(1_807).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(1_807, 0).saturating_mul(b.into())) // Standard Error: 432 - .saturating_add(Weight::from_ref_time(27_986).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(27_986, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(Weight::from_proof_size(64).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) } /// Storage: Council Members (r:1 w:0) /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) @@ -147,15 +147,15 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 24_817 nanoseconds. Weight::from_parts(24_778_955, 6355) // Standard Error: 73 - .saturating_add(Weight::from_ref_time(2_355).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(2_355, 0).saturating_mul(b.into())) // Standard Error: 765 - .saturating_add(Weight::from_ref_time(20_518).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(20_518, 0).saturating_mul(m.into())) // Standard Error: 755 - .saturating_add(Weight::from_ref_time(85_670).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(85_670, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) - .saturating_add(Weight::from_proof_size(165).saturating_mul(m.into())) - .saturating_add(Weight::from_proof_size(180).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 165).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 180).saturating_mul(p.into())) } /// Storage: Council Members (r:1 w:0) /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) @@ -169,10 +169,10 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 19_790 nanoseconds. Weight::from_parts(20_528_275, 4980) // Standard Error: 651 - .saturating_add(Weight::from_ref_time(48_856).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(48_856, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) - .saturating_add(Weight::from_proof_size(128).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 128).saturating_mul(m.into())) } /// Storage: Council Voting (r:1 w:1) /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) @@ -191,13 +191,13 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 25_564 nanoseconds. Weight::from_parts(25_535_497, 5893) // Standard Error: 610 - .saturating_add(Weight::from_ref_time(27_956).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(27_956, 0).saturating_mul(m.into())) // Standard Error: 595 - .saturating_add(Weight::from_ref_time(84_835).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(84_835, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(260).saturating_mul(m.into())) - .saturating_add(Weight::from_proof_size(144).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 260).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 144).saturating_mul(p.into())) } /// Storage: Council Voting (r:1 w:1) /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) @@ -217,16 +217,16 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 36_515 nanoseconds. Weight::from_parts(36_626_648, 9164) // Standard Error: 98 - .saturating_add(Weight::from_ref_time(2_295).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(2_295, 0).saturating_mul(b.into())) // Standard Error: 1_036 - .saturating_add(Weight::from_ref_time(22_182).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(22_182, 0).saturating_mul(m.into())) // Standard Error: 1_010 - .saturating_add(Weight::from_ref_time(100_034).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(100_034, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(4).saturating_mul(b.into())) - .saturating_add(Weight::from_proof_size(264).saturating_mul(m.into())) - .saturating_add(Weight::from_proof_size(160).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 4).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(0, 264).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 160).saturating_mul(p.into())) } /// Storage: Council Voting (r:1 w:1) /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) @@ -247,13 +247,13 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 28_858 nanoseconds. Weight::from_parts(28_050_047, 7095) // Standard Error: 614 - .saturating_add(Weight::from_ref_time(34_031).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(34_031, 0).saturating_mul(m.into())) // Standard Error: 599 - .saturating_add(Weight::from_ref_time(85_744).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(85_744, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(325).saturating_mul(m.into())) - .saturating_add(Weight::from_proof_size(180).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 325).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 180).saturating_mul(p.into())) } /// Storage: Council Voting (r:1 w:1) /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) @@ -275,16 +275,16 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 38_608 nanoseconds. Weight::from_parts(39_948_329, 10565) // Standard Error: 84 - .saturating_add(Weight::from_ref_time(2_045).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(2_045, 0).saturating_mul(b.into())) // Standard Error: 895 - .saturating_add(Weight::from_ref_time(22_669).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(22_669, 0).saturating_mul(m.into())) // Standard Error: 872 - .saturating_add(Weight::from_ref_time(95_525).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(95_525, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(5).saturating_mul(b.into())) - .saturating_add(Weight::from_proof_size(330).saturating_mul(m.into())) - .saturating_add(Weight::from_proof_size(200).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 5).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(0, 330).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 200).saturating_mul(p.into())) } /// Storage: Council Proposals (r:1 w:1) /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) @@ -300,10 +300,10 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 14_785 nanoseconds. Weight::from_parts(16_393_818, 1668) // Standard Error: 612 - .saturating_add(Weight::from_ref_time(76_786).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(76_786, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(96).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 96).saturating_mul(p.into())) } } @@ -327,15 +327,15 @@ impl WeightInfo for () { // Minimum execution time: 17_093 nanoseconds. Weight::from_parts(17_284_000, 16586) // Standard Error: 64_700 - .saturating_add(Weight::from_ref_time(5_143_145).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(5_143_145, 0).saturating_mul(m.into())) // Standard Error: 64_700 - .saturating_add(Weight::from_ref_time(7_480_941).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(7_480_941, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(p.into()))) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(p.into()))) - .saturating_add(Weight::from_proof_size(7809).saturating_mul(m.into())) - .saturating_add(Weight::from_proof_size(10238).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 7809).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 10238).saturating_mul(p.into())) } /// Storage: Council Members (r:1 w:0) /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) @@ -348,11 +348,11 @@ impl WeightInfo for () { // Minimum execution time: 15_972 nanoseconds. Weight::from_parts(14_971_445, 730) // Standard Error: 32 - .saturating_add(Weight::from_ref_time(1_775).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(1_775, 0).saturating_mul(b.into())) // Standard Error: 334 - .saturating_add(Weight::from_ref_time(17_052).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(17_052, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) - .saturating_add(Weight::from_proof_size(32).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 32).saturating_mul(m.into())) } /// Storage: Council Members (r:1 w:0) /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) @@ -367,11 +367,11 @@ impl WeightInfo for () { // Minimum execution time: 17_950 nanoseconds. Weight::from_parts(17_019_558, 3440) // Standard Error: 41 - .saturating_add(Weight::from_ref_time(1_807).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(1_807, 0).saturating_mul(b.into())) // Standard Error: 432 - .saturating_add(Weight::from_ref_time(27_986).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(27_986, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(Weight::from_proof_size(64).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) } /// Storage: Council Members (r:1 w:0) /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) @@ -393,15 +393,15 @@ impl WeightInfo for () { // Minimum execution time: 24_817 nanoseconds. Weight::from_parts(24_778_955, 6355) // Standard Error: 73 - .saturating_add(Weight::from_ref_time(2_355).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(2_355, 0).saturating_mul(b.into())) // Standard Error: 765 - .saturating_add(Weight::from_ref_time(20_518).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(20_518, 0).saturating_mul(m.into())) // Standard Error: 755 - .saturating_add(Weight::from_ref_time(85_670).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(85_670, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) - .saturating_add(Weight::from_proof_size(165).saturating_mul(m.into())) - .saturating_add(Weight::from_proof_size(180).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 165).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 180).saturating_mul(p.into())) } /// Storage: Council Members (r:1 w:0) /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) @@ -415,10 +415,10 @@ impl WeightInfo for () { // Minimum execution time: 19_790 nanoseconds. Weight::from_parts(20_528_275, 4980) // Standard Error: 651 - .saturating_add(Weight::from_ref_time(48_856).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(48_856, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) - .saturating_add(Weight::from_proof_size(128).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 128).saturating_mul(m.into())) } /// Storage: Council Voting (r:1 w:1) /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) @@ -437,13 +437,13 @@ impl WeightInfo for () { // Minimum execution time: 25_564 nanoseconds. Weight::from_parts(25_535_497, 5893) // Standard Error: 610 - .saturating_add(Weight::from_ref_time(27_956).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(27_956, 0).saturating_mul(m.into())) // Standard Error: 595 - .saturating_add(Weight::from_ref_time(84_835).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(84_835, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(260).saturating_mul(m.into())) - .saturating_add(Weight::from_proof_size(144).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 260).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 144).saturating_mul(p.into())) } /// Storage: Council Voting (r:1 w:1) /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) @@ -463,16 +463,16 @@ impl WeightInfo for () { // Minimum execution time: 36_515 nanoseconds. Weight::from_parts(36_626_648, 9164) // Standard Error: 98 - .saturating_add(Weight::from_ref_time(2_295).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(2_295, 0).saturating_mul(b.into())) // Standard Error: 1_036 - .saturating_add(Weight::from_ref_time(22_182).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(22_182, 0).saturating_mul(m.into())) // Standard Error: 1_010 - .saturating_add(Weight::from_ref_time(100_034).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(100_034, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(4).saturating_mul(b.into())) - .saturating_add(Weight::from_proof_size(264).saturating_mul(m.into())) - .saturating_add(Weight::from_proof_size(160).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 4).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(0, 264).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 160).saturating_mul(p.into())) } /// Storage: Council Voting (r:1 w:1) /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) @@ -493,13 +493,13 @@ impl WeightInfo for () { // Minimum execution time: 28_858 nanoseconds. Weight::from_parts(28_050_047, 7095) // Standard Error: 614 - .saturating_add(Weight::from_ref_time(34_031).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(34_031, 0).saturating_mul(m.into())) // Standard Error: 599 - .saturating_add(Weight::from_ref_time(85_744).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(85_744, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(325).saturating_mul(m.into())) - .saturating_add(Weight::from_proof_size(180).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 325).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 180).saturating_mul(p.into())) } /// Storage: Council Voting (r:1 w:1) /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) @@ -521,16 +521,16 @@ impl WeightInfo for () { // Minimum execution time: 38_608 nanoseconds. Weight::from_parts(39_948_329, 10565) // Standard Error: 84 - .saturating_add(Weight::from_ref_time(2_045).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(2_045, 0).saturating_mul(b.into())) // Standard Error: 895 - .saturating_add(Weight::from_ref_time(22_669).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(22_669, 0).saturating_mul(m.into())) // Standard Error: 872 - .saturating_add(Weight::from_ref_time(95_525).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(95_525, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(5).saturating_mul(b.into())) - .saturating_add(Weight::from_proof_size(330).saturating_mul(m.into())) - .saturating_add(Weight::from_proof_size(200).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 5).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(0, 330).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 200).saturating_mul(p.into())) } /// Storage: Council Proposals (r:1 w:1) /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) @@ -546,9 +546,9 @@ impl WeightInfo for () { // Minimum execution time: 14_785 nanoseconds. Weight::from_parts(16_393_818, 1668) // Standard Error: 612 - .saturating_add(Weight::from_ref_time(76_786).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(76_786, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(96).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 96).saturating_mul(p.into())) } } diff --git a/frame/contracts/src/gas.rs b/frame/contracts/src/gas.rs index c6f7d44be686e..f6484fbcf4630 100644 --- a/frame/contracts/src/gas.rs +++ b/frame/contracts/src/gas.rs @@ -275,19 +275,19 @@ mod tests { struct SimpleToken(u64); impl Token for SimpleToken { fn weight(&self) -> Weight { - Weight::from_ref_time(self.0) + Weight::from_parts(self.0, 0) } } #[test] fn it_works() { - let gas_meter = GasMeter::::new(Weight::from_ref_time(50000)); - assert_eq!(gas_meter.gas_left(), Weight::from_ref_time(50000)); + let gas_meter = GasMeter::::new(Weight::from_parts(50000, 0)); + assert_eq!(gas_meter.gas_left(), Weight::from_parts(50000, 0)); } #[test] fn tracing() { - let mut gas_meter = GasMeter::::new(Weight::from_ref_time(50000)); + let mut gas_meter = GasMeter::::new(Weight::from_parts(50000, 0)); assert!(!gas_meter.charge(SimpleToken(1)).is_err()); let mut tokens = gas_meter.tokens().iter(); @@ -304,7 +304,7 @@ mod tests { // Make sure that the gas meter does not charge in case of overcharger #[test] fn overcharge_does_not_charge() { - let mut gas_meter = GasMeter::::new(Weight::from_ref_time(200)); + let mut gas_meter = GasMeter::::new(Weight::from_parts(200, 0)); // The first charge is should lead to OOG. assert!(gas_meter.charge(SimpleToken(300)).is_err()); @@ -317,7 +317,7 @@ mod tests { // possible. #[test] fn charge_exact_amount() { - let mut gas_meter = GasMeter::::new(Weight::from_ref_time(25)); + let mut gas_meter = GasMeter::::new(Weight::from_parts(25, 0)); assert!(!gas_meter.charge(SimpleToken(25)).is_err()); } } diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index bf1bd4f65442f..cecac03388d1b 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -190,7 +190,7 @@ impl ChainExtension for TestExtension { }, 2 => { let mut env = env.buf_in_buf_out(); - let weight = Weight::from_ref_time(env.read(5)?[4].into()); + let weight = Weight::from_parts(env.read(5)?[4].into(), 0); env.charge_weight(weight)?; Ok(RetVal::Converging(id)) }, @@ -705,7 +705,7 @@ fn run_out_of_gas() { RuntimeOrigin::signed(ALICE), addr, // newly created account 0, - Weight::from_ref_time(1_000_000_000_000).set_proof_size(u64::MAX), + Weight::from_parts(1_000_000_000_000, u64::MAX), None, vec![], ), @@ -2115,7 +2115,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 = Weight::from_ref_time(5_000_000_000); + let weight_limit = Weight::from_parts(5_000_000_000, 0); let (_, max_keys) = ContractInfo::::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())) diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index ab873331cbbc6..e80e2cde302fe 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -282,7 +282,7 @@ impl RuntimeCosts { fn token(&self, s: &HostFnWeights) -> RuntimeToken { use self::RuntimeCosts::*; let weight = match *self { - MeteringBlock(amount) => s.gas.saturating_add(Weight::from_ref_time(amount)), + MeteringBlock(amount) => s.gas.saturating_add(Weight::from_parts(amount, 0)), CopyFromContract(len) => s.return_per_byte.saturating_mul(len.into()), CopyToContract(len) => s.input_per_byte.saturating_mul(len.into()), Caller => s.caller, @@ -903,7 +903,7 @@ impl<'a, E: Ext + 'a> Runtime<'a, E> { self.charge_gas(RuntimeCosts::CallSurchargeTransfer)?; } self.ext.call( - Weight::from_ref_time(gas), + Weight::from_parts(gas, 0), callee, value, input_data, @@ -958,7 +958,7 @@ impl<'a, E: Ext + 'a> Runtime<'a, E> { salt_ptr: u32, salt_len: u32, ) -> Result { - let gas = Weight::from_ref_time(gas); + let gas = Weight::from_parts(gas, 0); self.charge_gas(RuntimeCosts::InstantiateBase { input_data_len, salt_len })?; let value: BalanceOf<::T> = self.read_sandbox_memory_as(memory, value_ptr)?; if value > 0u32.into() { @@ -1802,7 +1802,7 @@ pub mod env { out_ptr: u32, out_len_ptr: u32, ) -> Result<(), TrapReason> { - let gas = Weight::from_ref_time(gas); + let gas = Weight::from_parts(gas, 0); ctx.charge_gas(RuntimeCosts::WeightToFee)?; Ok(ctx.write_sandbox_output( memory, diff --git a/frame/contracts/src/weights.rs b/frame/contracts/src/weights.rs index 880b7305f3bc1..14e680fb6a0ed 100644 --- a/frame/contracts/src/weights.rs +++ b/frame/contracts/src/weights.rs @@ -179,8 +179,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `109` // Estimated: `604` // Minimum execution time: 2_591 nanoseconds. - Weight::from_ref_time(2_817_000) - .saturating_add(Weight::from_proof_size(604)) + Weight::from_parts(2_817_000, 0) + .saturating_add(Weight::from_parts(0, 604)) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: Skipped Metadata (r:0 w:0) @@ -191,14 +191,14 @@ impl WeightInfo for SubstrateWeight { // Measured: `481 + k * (69 ±0)` // Estimated: `471 + k * (70 ±0)` // Minimum execution time: 10_190 nanoseconds. - Weight::from_ref_time(6_642_117) - .saturating_add(Weight::from_proof_size(471)) + Weight::from_parts(6_642_117, 0) + .saturating_add(Weight::from_parts(0, 471)) // Standard Error: 992 - .saturating_add(Weight::from_ref_time(919_828).saturating_mul(k.into())) + .saturating_add(Weight::from_parts(919_828, 0).saturating_mul(k.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(k.into()))) - .saturating_add(Weight::from_proof_size(70).saturating_mul(k.into())) + .saturating_add(Weight::from_parts(0, 70).saturating_mul(k.into())) } /// Storage: Contracts DeletionQueue (r:1 w:1) /// Proof: Contracts DeletionQueue (max_values: Some(1), max_size: Some(16642), added: 17137, mode: Measured) @@ -208,13 +208,13 @@ impl WeightInfo for SubstrateWeight { // Measured: `281 + q * (33 ±0)` // Estimated: `763 + q * (33 ±0)` // Minimum execution time: 2_598 nanoseconds. - Weight::from_ref_time(10_288_252) - .saturating_add(Weight::from_proof_size(763)) + Weight::from_parts(10_288_252, 0) + .saturating_add(Weight::from_parts(0, 763)) // Standard Error: 2_886 - .saturating_add(Weight::from_ref_time(1_092_420).saturating_mul(q.into())) + .saturating_add(Weight::from_parts(1_092_420, 0).saturating_mul(q.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) - .saturating_add(Weight::from_proof_size(33).saturating_mul(q.into())) + .saturating_add(Weight::from_parts(0, 33).saturating_mul(q.into())) } /// Storage: Contracts PristineCode (r:1 w:0) /// Proof: Contracts PristineCode (max_values: None, max_size: Some(125988), added: 128463, mode: Measured) @@ -226,13 +226,13 @@ impl WeightInfo for SubstrateWeight { // Measured: `270 + c * (1 ±0)` // Estimated: `3025 + c * (2 ±0)` // Minimum execution time: 34_338 nanoseconds. - Weight::from_ref_time(32_159_677) - .saturating_add(Weight::from_proof_size(3025)) + Weight::from_parts(32_159_677, 0) + .saturating_add(Weight::from_parts(0, 3025)) // Standard Error: 53 - .saturating_add(Weight::from_ref_time(51_034).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(51_034, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) - .saturating_add(Weight::from_proof_size(2).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(0, 2).saturating_mul(c.into())) } /// Storage: Contracts ContractInfoOf (r:1 w:1) /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) @@ -250,13 +250,13 @@ impl WeightInfo for SubstrateWeight { // Measured: `803` // Estimated: `16930 + c * (5 ±0)` // Minimum execution time: 385_587 nanoseconds. - Weight::from_ref_time(395_545_811) - .saturating_add(Weight::from_proof_size(16930)) + Weight::from_parts(395_545_811, 0) + .saturating_add(Weight::from_parts(0, 16930)) // Standard Error: 27 - .saturating_add(Weight::from_ref_time(31_342).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(31_342, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) - .saturating_add(Weight::from_proof_size(5).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(0, 5).saturating_mul(c.into())) } /// Storage: Contracts OwnerInfoOf (r:1 w:1) /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Measured) @@ -282,14 +282,14 @@ impl WeightInfo for SubstrateWeight { // Measured: `270` // Estimated: `20267` // Minimum execution time: 3_799_742 nanoseconds. - Weight::from_ref_time(670_115_588) - .saturating_add(Weight::from_proof_size(20267)) + Weight::from_parts(670_115_588, 0) + .saturating_add(Weight::from_parts(0, 20267)) // Standard Error: 287 - .saturating_add(Weight::from_ref_time(93_885).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(93_885, 0).saturating_mul(c.into())) // Standard Error: 16 - .saturating_add(Weight::from_ref_time(1_367).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(1_367, 0).saturating_mul(i.into())) // Standard Error: 16 - .saturating_add(Weight::from_ref_time(1_781).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_781, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(10_u64)) } @@ -314,12 +314,12 @@ impl WeightInfo for SubstrateWeight { // Measured: `546` // Estimated: `22039` // Minimum execution time: 1_949_008 nanoseconds. - Weight::from_ref_time(214_033_418) - .saturating_add(Weight::from_proof_size(22039)) + Weight::from_parts(214_033_418, 0) + .saturating_add(Weight::from_parts(0, 22039)) // Standard Error: 8 - .saturating_add(Weight::from_ref_time(1_666).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(1_666, 0).saturating_mul(i.into())) // Standard Error: 8 - .saturating_add(Weight::from_ref_time(1_801).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_801, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } @@ -338,8 +338,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `855` // Estimated: `17145` // Minimum execution time: 146_654 nanoseconds. - Weight::from_ref_time(147_528_000) - .saturating_add(Weight::from_proof_size(17145)) + Weight::from_parts(147_528_000, 0) + .saturating_add(Weight::from_parts(0, 17145)) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -357,10 +357,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `109` // Estimated: `5386` // Minimum execution time: 387_889 nanoseconds. - Weight::from_ref_time(391_379_335) - .saturating_add(Weight::from_proof_size(5386)) + Weight::from_parts(391_379_335, 0) + .saturating_add(Weight::from_parts(0, 5386)) // Standard Error: 89 - .saturating_add(Weight::from_ref_time(94_810).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(94_810, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -377,8 +377,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `287` // Estimated: `6098` // Minimum execution time: 26_014 nanoseconds. - Weight::from_ref_time(26_510_000) - .saturating_add(Weight::from_proof_size(6098)) + Weight::from_parts(26_510_000, 0) + .saturating_add(Weight::from_parts(0, 6098)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -393,8 +393,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `666` // Estimated: `16848` // Minimum execution time: 30_177 nanoseconds. - Weight::from_ref_time(30_639_000) - .saturating_add(Weight::from_proof_size(16848)) + Weight::from_parts(30_639_000, 0) + .saturating_add(Weight::from_parts(0, 16848)) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -414,13 +414,13 @@ impl WeightInfo for SubstrateWeight { // Measured: `877 + r * (480 ±0)` // Estimated: `17295 + r * (2400 ±0)` // Minimum execution time: 373_786 nanoseconds. - Weight::from_ref_time(377_332_691) - .saturating_add(Weight::from_proof_size(17295)) + Weight::from_parts(377_332_691, 0) + .saturating_add(Weight::from_parts(0, 17295)) // Standard Error: 51_211 - .saturating_add(Weight::from_ref_time(17_715_615).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(17_715_615, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(2400).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 2400).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -438,14 +438,14 @@ impl WeightInfo for SubstrateWeight { // Measured: `917 + r * (21778 ±0)` // Estimated: `17295 + r * (306895 ±0)` // Minimum execution time: 374_009 nanoseconds. - Weight::from_ref_time(238_991_986) - .saturating_add(Weight::from_proof_size(17295)) + Weight::from_parts(238_991_986, 0) + .saturating_add(Weight::from_parts(0, 17295)) // Standard Error: 464_711 - .saturating_add(Weight::from_ref_time(249_099_538).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(249_099_538, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(306895).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 306895).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -463,14 +463,14 @@ impl WeightInfo for SubstrateWeight { // Measured: `921 + r * (22099 ±0)` // Estimated: `17340 + r * (308500 ±0)` // Minimum execution time: 375_058 nanoseconds. - Weight::from_ref_time(238_765_068) - .saturating_add(Weight::from_proof_size(17340)) + Weight::from_parts(238_765_068, 0) + .saturating_add(Weight::from_parts(0, 17340)) // Standard Error: 662_617 - .saturating_add(Weight::from_ref_time(302_175_089).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(302_175_089, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(308500).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 308500).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -488,13 +488,13 @@ impl WeightInfo for SubstrateWeight { // Measured: `884 + r * (480 ±0)` // Estimated: `17330 + r * (2400 ±0)` // Minimum execution time: 374_747 nanoseconds. - Weight::from_ref_time(376_482_380) - .saturating_add(Weight::from_proof_size(17330)) + Weight::from_parts(376_482_380, 0) + .saturating_add(Weight::from_parts(0, 17330)) // Standard Error: 61_919 - .saturating_add(Weight::from_ref_time(22_376_795).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(22_376_795, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(2400).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 2400).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -512,13 +512,13 @@ impl WeightInfo for SubstrateWeight { // Measured: `874 + r * (240 ±0)` // Estimated: `17265 + r * (1200 ±0)` // Minimum execution time: 372_287 nanoseconds. - Weight::from_ref_time(376_250_858) - .saturating_add(Weight::from_proof_size(17265)) + Weight::from_parts(376_250_858, 0) + .saturating_add(Weight::from_parts(0, 17265)) // Standard Error: 40_119 - .saturating_add(Weight::from_ref_time(11_359_647).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(11_359_647, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(1200).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 1200).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -536,13 +536,13 @@ impl WeightInfo for SubstrateWeight { // Measured: `878 + r * (480 ±0)` // Estimated: `17260 + r * (2400 ±0)` // Minimum execution time: 374_445 nanoseconds. - Weight::from_ref_time(377_243_521) - .saturating_add(Weight::from_proof_size(17260)) + Weight::from_parts(377_243_521, 0) + .saturating_add(Weight::from_parts(0, 17260)) // Standard Error: 53_032 - .saturating_add(Weight::from_ref_time(17_684_246).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(17_684_246, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(2400).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 2400).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -560,13 +560,13 @@ impl WeightInfo for SubstrateWeight { // Measured: `879 + r * (480 ±0)` // Estimated: `17250 + r * (2405 ±0)` // Minimum execution time: 374_029 nanoseconds. - Weight::from_ref_time(380_415_186) - .saturating_add(Weight::from_proof_size(17250)) + Weight::from_parts(380_415_186, 0) + .saturating_add(Weight::from_parts(0, 17250)) // Standard Error: 60_562 - .saturating_add(Weight::from_ref_time(17_152_599).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(17_152_599, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(2405).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 2405).saturating_mul(r.into())) } /// Storage: System Account (r:2 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -584,13 +584,13 @@ impl WeightInfo for SubstrateWeight { // Measured: `1049 + r * (480 ±0)` // Estimated: `19849 + r * (2456 ±0)` // Minimum execution time: 373_999 nanoseconds. - Weight::from_ref_time(381_757_033) - .saturating_add(Weight::from_proof_size(19849)) + Weight::from_parts(381_757_033, 0) + .saturating_add(Weight::from_parts(0, 19849)) // Standard Error: 97_983 - .saturating_add(Weight::from_ref_time(98_290_984).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(98_290_984, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(2456).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 2456).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -608,13 +608,13 @@ impl WeightInfo for SubstrateWeight { // Measured: `888 + r * (480 ±0)` // Estimated: `17360 + r * (2400 ±0)` // Minimum execution time: 374_197 nanoseconds. - Weight::from_ref_time(377_755_896) - .saturating_add(Weight::from_proof_size(17360)) + Weight::from_parts(377_755_896, 0) + .saturating_add(Weight::from_parts(0, 17360)) // Standard Error: 60_542 - .saturating_add(Weight::from_ref_time(17_442_065).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(17_442_065, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(2400).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 2400).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -632,13 +632,13 @@ impl WeightInfo for SubstrateWeight { // Measured: `886 + r * (480 ±0)` // Estimated: `17290 + r * (2400 ±0)` // Minimum execution time: 373_888 nanoseconds. - Weight::from_ref_time(377_825_771) - .saturating_add(Weight::from_proof_size(17290)) + Weight::from_parts(377_825_771, 0) + .saturating_add(Weight::from_parts(0, 17290)) // Standard Error: 38_026 - .saturating_add(Weight::from_ref_time(17_147_903).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(17_147_903, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(2400).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 2400).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -656,13 +656,13 @@ impl WeightInfo for SubstrateWeight { // Measured: `883 + r * (480 ±0)` // Estimated: `17315 + r * (2400 ±0)` // Minimum execution time: 373_904 nanoseconds. - Weight::from_ref_time(378_652_372) - .saturating_add(Weight::from_proof_size(17315)) + Weight::from_parts(378_652_372, 0) + .saturating_add(Weight::from_parts(0, 17315)) // Standard Error: 43_833 - .saturating_add(Weight::from_ref_time(16_936_781).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(16_936_781, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(2400).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 2400).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -680,13 +680,13 @@ impl WeightInfo for SubstrateWeight { // Measured: `874 + r * (480 ±0)` // Estimated: `17245 + r * (2400 ±0)` // Minimum execution time: 373_473 nanoseconds. - Weight::from_ref_time(376_386_312) - .saturating_add(Weight::from_proof_size(17245)) + Weight::from_parts(376_386_312, 0) + .saturating_add(Weight::from_parts(0, 17245)) // Standard Error: 46_945 - .saturating_add(Weight::from_ref_time(17_336_462).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(17_336_462, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(2400).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 2400).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -706,13 +706,13 @@ impl WeightInfo for SubstrateWeight { // Measured: `951 + r * (800 ±0)` // Estimated: `19046 + r * (4805 ±0)` // Minimum execution time: 373_661 nanoseconds. - Weight::from_ref_time(385_824_015) - .saturating_add(Weight::from_proof_size(19046)) + Weight::from_parts(385_824_015, 0) + .saturating_add(Weight::from_parts(0, 19046)) // Standard Error: 75_964 - .saturating_add(Weight::from_ref_time(88_530_074).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(88_530_074, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(4805).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 4805).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -730,13 +730,13 @@ impl WeightInfo for SubstrateWeight { // Measured: `841 + r * (320 ±0)` // Estimated: `17120 + r * (1600 ±0)` // Minimum execution time: 133_849 nanoseconds. - Weight::from_ref_time(137_283_391) - .saturating_add(Weight::from_proof_size(17120)) + Weight::from_parts(137_283_391, 0) + .saturating_add(Weight::from_parts(0, 17120)) // Standard Error: 13_312 - .saturating_add(Weight::from_ref_time(8_055_328).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(8_055_328, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(1600).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 1600).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -754,13 +754,13 @@ impl WeightInfo for SubstrateWeight { // Measured: `876 + r * (480 ±0)` // Estimated: `17245 + r * (2400 ±0)` // Minimum execution time: 373_468 nanoseconds. - Weight::from_ref_time(376_121_093) - .saturating_add(Weight::from_proof_size(17245)) + Weight::from_parts(376_121_093, 0) + .saturating_add(Weight::from_parts(0, 17245)) // Standard Error: 61_857 - .saturating_add(Weight::from_ref_time(15_868_414).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(15_868_414, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(2400).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 2400).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -778,10 +778,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `1356` // Estimated: `19650` // Minimum execution time: 390_668 nanoseconds. - Weight::from_ref_time(419_608_449) - .saturating_add(Weight::from_proof_size(19650)) + Weight::from_parts(419_608_449, 0) + .saturating_add(Weight::from_parts(0, 19650)) // Standard Error: 4_890 - .saturating_add(Weight::from_ref_time(9_672_288).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(9_672_288, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -801,13 +801,13 @@ impl WeightInfo for SubstrateWeight { // Measured: `864 + r * (45 ±0)` // Estimated: `17190 + r * (225 ±0)` // Minimum execution time: 371_309 nanoseconds. - Weight::from_ref_time(373_625_402) - .saturating_add(Weight::from_proof_size(17190)) + Weight::from_parts(373_625_402, 0) + .saturating_add(Weight::from_parts(0, 17190)) // Standard Error: 419_605 - .saturating_add(Weight::from_ref_time(1_737_397).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(1_737_397, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(225).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 225).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -825,10 +825,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `874` // Estimated: `17285` // Minimum execution time: 374_094 nanoseconds. - Weight::from_ref_time(375_965_200) - .saturating_add(Weight::from_proof_size(17285)) + Weight::from_parts(375_965_200, 0) + .saturating_add(Weight::from_parts(0, 17285)) // Standard Error: 1_127 - .saturating_add(Weight::from_ref_time(232_645).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(232_645, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -852,15 +852,15 @@ impl WeightInfo for SubstrateWeight { // Measured: `906 + r * (452 ±0)` // Estimated: `20242 + r * (15004 ±0)` // Minimum execution time: 373_123 nanoseconds. - Weight::from_ref_time(374_924_634) - .saturating_add(Weight::from_proof_size(20242)) + Weight::from_parts(374_924_634, 0) + .saturating_add(Weight::from_parts(0, 20242)) // Standard Error: 378_010 - .saturating_add(Weight::from_ref_time(70_441_665).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(70_441_665, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((6_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((7_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_proof_size(15004).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 15004).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -880,13 +880,13 @@ impl WeightInfo for SubstrateWeight { // Measured: `921 + r * (800 ±0)` // Estimated: `18835 + r * (4805 ±0)` // Minimum execution time: 373_291 nanoseconds. - Weight::from_ref_time(385_684_344) - .saturating_add(Weight::from_proof_size(18835)) + Weight::from_parts(385_684_344, 0) + .saturating_add(Weight::from_parts(0, 18835)) // Standard Error: 99_025 - .saturating_add(Weight::from_ref_time(111_308_793).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(111_308_793, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(4805).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 4805).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -904,13 +904,13 @@ impl WeightInfo for SubstrateWeight { // Measured: `874 + r * (800 ±0)` // Estimated: `17250 + r * (4000 ±0)` // Minimum execution time: 371_900 nanoseconds. - Weight::from_ref_time(384_166_626) - .saturating_add(Weight::from_proof_size(17250)) + Weight::from_parts(384_166_626, 0) + .saturating_add(Weight::from_parts(0, 17250)) // Standard Error: 205_255 - .saturating_add(Weight::from_ref_time(229_214_157).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(229_214_157, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(4000).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 4000).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -929,18 +929,18 @@ impl WeightInfo for SubstrateWeight { // Measured: `1821 + t * (2608 ±0) + n * (7 ±0)` // Estimated: `21870 + t * (211030 ±0) + n * (50 ±0)` // Minimum execution time: 1_289_873 nanoseconds. - Weight::from_ref_time(581_702_206) - .saturating_add(Weight::from_proof_size(21870)) + Weight::from_parts(581_702_206, 0) + .saturating_add(Weight::from_parts(0, 21870)) // Standard Error: 665_638 - .saturating_add(Weight::from_ref_time(181_470_553).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(181_470_553, 0).saturating_mul(t.into())) // Standard Error: 182_816 - .saturating_add(Weight::from_ref_time(71_635_250).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(71_635_250, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(t.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((80_u64).saturating_mul(t.into()))) - .saturating_add(Weight::from_proof_size(211030).saturating_mul(t.into())) - .saturating_add(Weight::from_proof_size(50).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 211030).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(0, 50).saturating_mul(n.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -958,13 +958,13 @@ impl WeightInfo for SubstrateWeight { // Measured: `873 + r * (560 ±0)` // Estimated: `17240 + r * (2800 ±0)` // Minimum execution time: 148_635 nanoseconds. - Weight::from_ref_time(154_095_712) - .saturating_add(Weight::from_proof_size(17240)) + Weight::from_parts(154_095_712, 0) + .saturating_add(Weight::from_parts(0, 17240)) // Standard Error: 77_790 - .saturating_add(Weight::from_ref_time(14_837_085).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(14_837_085, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(2800).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 2800).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) @@ -982,10 +982,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `125824` // Estimated: `265128` // Minimum execution time: 501_014 nanoseconds. - Weight::from_ref_time(505_634_218) - .saturating_add(Weight::from_proof_size(265128)) + Weight::from_parts(505_634_218, 0) + .saturating_add(Weight::from_parts(0, 265128)) // Standard Error: 2_441 - .saturating_add(Weight::from_ref_time(819_257).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(819_257, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -997,15 +997,15 @@ impl WeightInfo for SubstrateWeight { // Measured: `911 + r * (23420 ±0)` // Estimated: `911 + r * (23418 ±0)` // Minimum execution time: 375_301 nanoseconds. - Weight::from_ref_time(291_498_841) - .saturating_add(Weight::from_proof_size(911)) + Weight::from_parts(291_498_841, 0) + .saturating_add(Weight::from_parts(0, 911)) // Standard Error: 809_989 - .saturating_add(Weight::from_ref_time(464_550_291).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(464_550_291, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((80_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_proof_size(23418).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 23418).saturating_mul(r.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) @@ -1015,15 +1015,15 @@ impl WeightInfo for SubstrateWeight { // Measured: `12672 + n * (11945 ±0)` // Estimated: `8529 + n * (12814 ±61)` // Minimum execution time: 506_318 nanoseconds. - Weight::from_ref_time(676_935_313) - .saturating_add(Weight::from_proof_size(8529)) + Weight::from_parts(676_935_313, 0) + .saturating_add(Weight::from_parts(0, 8529)) // Standard Error: 1_589_291 - .saturating_add(Weight::from_ref_time(97_839_399).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(97_839_399, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(52_u64)) .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(50_u64)) .saturating_add(T::DbWeight::get().writes((7_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_proof_size(12814).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 12814).saturating_mul(n.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) @@ -1033,15 +1033,15 @@ impl WeightInfo for SubstrateWeight { // Measured: `15170 + n * (175775 ±0)` // Estimated: `9914 + n * (176858 ±74)` // Minimum execution time: 506_148 nanoseconds. - Weight::from_ref_time(648_278_778) - .saturating_add(Weight::from_proof_size(9914)) + Weight::from_parts(648_278_778, 0) + .saturating_add(Weight::from_parts(0, 9914)) // Standard Error: 1_343_586 - .saturating_add(Weight::from_ref_time(65_789_595).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(65_789_595, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(51_u64)) .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(49_u64)) .saturating_add(T::DbWeight::get().writes((7_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_proof_size(176858).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 176858).saturating_mul(n.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) @@ -1051,15 +1051,15 @@ impl WeightInfo for SubstrateWeight { // Measured: `903 + r * (23099 ±0)` // Estimated: `908 + r * (23099 ±0)` // Minimum execution time: 374_344 nanoseconds. - Weight::from_ref_time(293_272_061) - .saturating_add(Weight::from_proof_size(908)) + Weight::from_parts(293_272_061, 0) + .saturating_add(Weight::from_parts(0, 908)) // Standard Error: 810_412 - .saturating_add(Weight::from_ref_time(453_315_956).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(453_315_956, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((80_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_proof_size(23099).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 23099).saturating_mul(r.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) @@ -1069,15 +1069,15 @@ impl WeightInfo for SubstrateWeight { // Measured: `14895 + n * (175768 ±0)` // Estimated: `9551 + n * (176867 ±75)` // Minimum execution time: 478_564 nanoseconds. - Weight::from_ref_time(630_839_142) - .saturating_add(Weight::from_proof_size(9551)) + Weight::from_parts(630_839_142, 0) + .saturating_add(Weight::from_parts(0, 9551)) // Standard Error: 1_427_520 - .saturating_add(Weight::from_ref_time(66_813_592).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(66_813_592, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(51_u64)) .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(48_u64)) .saturating_add(T::DbWeight::get().writes((7_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_proof_size(176867).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 176867).saturating_mul(n.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) @@ -1087,14 +1087,14 @@ impl WeightInfo for SubstrateWeight { // Measured: `896 + r * (23744 ±0)` // Estimated: `909 + r * (23740 ±0)` // Minimum execution time: 374_479 nanoseconds. - Weight::from_ref_time(311_839_315) - .saturating_add(Weight::from_proof_size(909)) + Weight::from_parts(311_839_315, 0) + .saturating_add(Weight::from_parts(0, 909)) // Standard Error: 666_553 - .saturating_add(Weight::from_ref_time(371_213_042).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(371_213_042, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(23740).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 23740).saturating_mul(r.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) @@ -1104,14 +1104,14 @@ impl WeightInfo for SubstrateWeight { // Measured: `15501 + n * (175775 ±0)` // Estimated: `10042 + n * (176900 ±76)` // Minimum execution time: 460_639 nanoseconds. - Weight::from_ref_time(591_187_094) - .saturating_add(Weight::from_proof_size(10042)) + Weight::from_parts(591_187_094, 0) + .saturating_add(Weight::from_parts(0, 10042)) // Standard Error: 1_233_792 - .saturating_add(Weight::from_ref_time(160_874_477).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(160_874_477, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(51_u64)) .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(176900).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 176900).saturating_mul(n.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) @@ -1121,14 +1121,14 @@ impl WeightInfo for SubstrateWeight { // Measured: `914 + r * (23098 ±0)` // Estimated: `920 + r * (23098 ±0)` // Minimum execution time: 374_272 nanoseconds. - Weight::from_ref_time(311_446_269) - .saturating_add(Weight::from_proof_size(920)) + Weight::from_parts(311_446_269, 0) + .saturating_add(Weight::from_parts(0, 920)) // Standard Error: 630_307 - .saturating_add(Weight::from_ref_time(357_134_931).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(357_134_931, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(23098).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 23098).saturating_mul(r.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) @@ -1138,14 +1138,14 @@ impl WeightInfo for SubstrateWeight { // Measured: `14839 + n * (175789 ±0)` // Estimated: `9532 + n * (176874 ±75)` // Minimum execution time: 456_013 nanoseconds. - Weight::from_ref_time(575_116_352) - .saturating_add(Weight::from_proof_size(9532)) + Weight::from_parts(575_116_352, 0) + .saturating_add(Weight::from_parts(0, 9532)) // Standard Error: 1_122_298 - .saturating_add(Weight::from_ref_time(61_786_107).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(61_786_107, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(51_u64)) .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(176874).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 176874).saturating_mul(n.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) @@ -1155,15 +1155,15 @@ impl WeightInfo for SubstrateWeight { // Measured: `911 + r * (23740 ±0)` // Estimated: `913 + r * (23739 ±0)` // Minimum execution time: 374_621 nanoseconds. - Weight::from_ref_time(299_689_489) - .saturating_add(Weight::from_proof_size(913)) + Weight::from_parts(299_689_489, 0) + .saturating_add(Weight::from_parts(0, 913)) // Standard Error: 757_735 - .saturating_add(Weight::from_ref_time(465_213_246).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(465_213_246, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((80_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_proof_size(23739).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 23739).saturating_mul(r.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) @@ -1173,15 +1173,15 @@ impl WeightInfo for SubstrateWeight { // Measured: `15502 + n * (175775 ±0)` // Estimated: `10042 + n * (176898 ±76)` // Minimum execution time: 481_980 nanoseconds. - Weight::from_ref_time(647_289_053) - .saturating_add(Weight::from_proof_size(10042)) + Weight::from_parts(647_289_053, 0) + .saturating_add(Weight::from_parts(0, 10042)) // Standard Error: 1_556_155 - .saturating_add(Weight::from_ref_time(166_592_657).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(166_592_657, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(51_u64)) .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(48_u64)) .saturating_add(T::DbWeight::get().writes((7_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_proof_size(176898).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 176898).saturating_mul(n.into())) } /// Storage: System Account (r:1602 w:1601) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1199,15 +1199,15 @@ impl WeightInfo for SubstrateWeight { // Measured: `1457 + r * (3604 ±0)` // Estimated: `21583 + r * (216101 ±0)` // Minimum execution time: 374_962 nanoseconds. - Weight::from_ref_time(313_416_386) - .saturating_add(Weight::from_proof_size(21583)) + Weight::from_parts(313_416_386, 0) + .saturating_add(Weight::from_parts(0, 21583)) // Standard Error: 710_675 - .saturating_add(Weight::from_ref_time(1_396_551_156).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(1_396_551_156, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(T::DbWeight::get().writes((80_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_proof_size(216101).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 216101).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1225,15 +1225,15 @@ impl WeightInfo for SubstrateWeight { // Measured: `1609 + r * (23073 ±0)` // Estimated: `22098 + r * (511456 ±1)` // Minimum execution time: 375_916 nanoseconds. - Weight::from_ref_time(376_468_000) - .saturating_add(Weight::from_proof_size(22098)) + Weight::from_parts(376_468_000, 0) + .saturating_add(Weight::from_parts(0, 22098)) // Standard Error: 7_246_855 - .saturating_add(Weight::from_ref_time(28_982_425_139).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(28_982_425_139, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().reads((160_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((160_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_proof_size(511456).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 511456).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1251,15 +1251,15 @@ impl WeightInfo for SubstrateWeight { // Measured: `0 + r * (71670 ±0)` // Estimated: `17285 + r * (659930 ±563)` // Minimum execution time: 375_412 nanoseconds. - Weight::from_ref_time(376_493_000) - .saturating_add(Weight::from_proof_size(17285)) + Weight::from_parts(376_493_000, 0) + .saturating_add(Weight::from_parts(0, 17285)) // Standard Error: 8_239_575 - .saturating_add(Weight::from_ref_time(28_716_347_183).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(28_716_347_183, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((150_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((75_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_proof_size(659930).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 659930).saturating_mul(r.into())) } /// Storage: System Account (r:82 w:81) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1278,17 +1278,17 @@ impl WeightInfo for SubstrateWeight { // Measured: `24269 + t * (16910 ±0)` // Estimated: `532690 + t * (285025 ±0)` // Minimum execution time: 10_443_315 nanoseconds. - Weight::from_ref_time(9_342_574_069) - .saturating_add(Weight::from_proof_size(532690)) + Weight::from_parts(9_342_574_069, 0) + .saturating_add(Weight::from_parts(0, 532690)) // Standard Error: 7_237_279 - .saturating_add(Weight::from_ref_time(1_390_221_936).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(1_390_221_936, 0).saturating_mul(t.into())) // Standard Error: 10_851 - .saturating_add(Weight::from_ref_time(9_842_151).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(9_842_151, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(167_u64)) .saturating_add(T::DbWeight::get().reads((81_u64).saturating_mul(t.into()))) .saturating_add(T::DbWeight::get().writes(163_u64)) .saturating_add(T::DbWeight::get().writes((81_u64).saturating_mul(t.into()))) - .saturating_add(Weight::from_proof_size(285025).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(0, 285025).saturating_mul(t.into())) } /// Storage: System Account (r:3202 w:3202) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1310,15 +1310,15 @@ impl WeightInfo for SubstrateWeight { // Measured: `1775 + r * (25568 ±0)` // Estimated: `26563 + r * (1367114 ±2)` // Minimum execution time: 376_418 nanoseconds. - Weight::from_ref_time(377_292_000) - .saturating_add(Weight::from_proof_size(26563)) + Weight::from_parts(377_292_000, 0) + .saturating_add(Weight::from_parts(0, 26563)) // Standard Error: 32_312_545 - .saturating_add(Weight::from_ref_time(35_904_826_312).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(35_904_826_312, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().reads((480_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(5_u64)) .saturating_add(T::DbWeight::get().writes((400_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_proof_size(1367114).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 1367114).saturating_mul(r.into())) } /// Storage: System Account (r:162 w:162) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1342,19 +1342,19 @@ impl WeightInfo for SubstrateWeight { // Measured: `5785 + t * (33 ±0)` // Estimated: `850985 + t * (2671 ±3)` // Minimum execution time: 132_157_340 nanoseconds. - Weight::from_ref_time(11_329_968_948) - .saturating_add(Weight::from_proof_size(850985)) + Weight::from_parts(11_329_968_948, 0) + .saturating_add(Weight::from_parts(0, 850985)) // Standard Error: 99_102_968 - .saturating_add(Weight::from_ref_time(84_719_458).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(84_719_458, 0).saturating_mul(t.into())) // Standard Error: 161_609 - .saturating_add(Weight::from_ref_time(126_156_627).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(126_156_627, 0).saturating_mul(i.into())) // Standard Error: 161_609 - .saturating_add(Weight::from_ref_time(126_628_313).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(126_628_313, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(329_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(t.into()))) .saturating_add(T::DbWeight::get().writes(326_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(t.into()))) - .saturating_add(Weight::from_proof_size(2671).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(0, 2671).saturating_mul(t.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1372,13 +1372,13 @@ impl WeightInfo for SubstrateWeight { // Measured: `871 + r * (642 ±0)` // Estimated: `17225 + r * (3210 ±0)` // Minimum execution time: 373_559 nanoseconds. - Weight::from_ref_time(375_166_904) - .saturating_add(Weight::from_proof_size(17225)) + Weight::from_parts(375_166_904, 0) + .saturating_add(Weight::from_parts(0, 17225)) // Standard Error: 125_024 - .saturating_add(Weight::from_ref_time(42_291_595).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(42_291_595, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(3210).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 3210).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1396,10 +1396,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `1673` // Estimated: `21160` // Minimum execution time: 416_233 nanoseconds. - Weight::from_ref_time(416_785_000) - .saturating_add(Weight::from_proof_size(21160)) + Weight::from_parts(416_785_000, 0) + .saturating_add(Weight::from_parts(0, 21160)) // Standard Error: 56_223 - .saturating_add(Weight::from_ref_time(324_513_835).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(324_513_835, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1419,13 +1419,13 @@ impl WeightInfo for SubstrateWeight { // Measured: `873 + r * (642 ±0)` // Estimated: `17235 + r * (3210 ±0)` // Minimum execution time: 371_735 nanoseconds. - Weight::from_ref_time(375_979_430) - .saturating_add(Weight::from_proof_size(17235)) + Weight::from_parts(375_979_430, 0) + .saturating_add(Weight::from_parts(0, 17235)) // Standard Error: 968_037 - .saturating_add(Weight::from_ref_time(57_780_769).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(57_780_769, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(3210).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 3210).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1443,10 +1443,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `1675` // Estimated: `21205` // Minimum execution time: 428_196 nanoseconds. - Weight::from_ref_time(429_438_000) - .saturating_add(Weight::from_proof_size(21205)) + Weight::from_parts(429_438_000, 0) + .saturating_add(Weight::from_parts(0, 21205)) // Standard Error: 57_860 - .saturating_add(Weight::from_ref_time(260_917_896).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(260_917_896, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1466,13 +1466,13 @@ impl WeightInfo for SubstrateWeight { // Measured: `873 + r * (642 ±0)` // Estimated: `17235 + r * (3210 ±0)` // Minimum execution time: 371_412 nanoseconds. - Weight::from_ref_time(373_635_818) - .saturating_add(Weight::from_proof_size(17235)) + Weight::from_parts(373_635_818, 0) + .saturating_add(Weight::from_parts(0, 17235)) // Standard Error: 222_973 - .saturating_add(Weight::from_ref_time(33_347_181).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(33_347_181, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(3210).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 3210).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1490,10 +1490,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `1675` // Estimated: `21180` // Minimum execution time: 405_858 nanoseconds. - Weight::from_ref_time(406_498_000) - .saturating_add(Weight::from_proof_size(21180)) + Weight::from_parts(406_498_000, 0) + .saturating_add(Weight::from_parts(0, 21180)) // Standard Error: 48_388 - .saturating_add(Weight::from_ref_time(103_283_157).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(103_283_157, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1513,13 +1513,13 @@ impl WeightInfo for SubstrateWeight { // Measured: `873 + r * (679 ±0)` // Estimated: `17235 + r * (3395 ±0)` // Minimum execution time: 371_746 nanoseconds. - Weight::from_ref_time(373_538_171) - .saturating_add(Weight::from_proof_size(17235)) + Weight::from_parts(373_538_171, 0) + .saturating_add(Weight::from_parts(0, 17235)) // Standard Error: 387_332 - .saturating_add(Weight::from_ref_time(35_933_528).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(35_933_528, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(3395).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 3395).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1537,10 +1537,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `1675` // Estimated: `21225` // Minimum execution time: 405_752 nanoseconds. - Weight::from_ref_time(406_417_000) - .saturating_add(Weight::from_proof_size(21225)) + Weight::from_parts(406_417_000, 0) + .saturating_add(Weight::from_parts(0, 21225)) // Standard Error: 47_051 - .saturating_add(Weight::from_ref_time(103_325_027).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(103_325_027, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1560,13 +1560,13 @@ impl WeightInfo for SubstrateWeight { // Measured: `917 + r * (6083 ±0)` // Estimated: `17455 + r * (30415 ±0)` // Minimum execution time: 373_882 nanoseconds. - Weight::from_ref_time(376_553_787) - .saturating_add(Weight::from_proof_size(17455)) + Weight::from_parts(376_553_787, 0) + .saturating_add(Weight::from_parts(0, 17455)) // Standard Error: 912_833 - .saturating_add(Weight::from_ref_time(3_021_100_412).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_021_100_412, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(30415).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 30415).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1584,13 +1584,13 @@ impl WeightInfo for SubstrateWeight { // Measured: `886 + r * (3362 ±0)` // Estimated: `17300 + r * (16810 ±0)` // Minimum execution time: 373_673 nanoseconds. - Weight::from_ref_time(375_712_961) - .saturating_add(Weight::from_proof_size(17300)) + Weight::from_parts(375_712_961, 0) + .saturating_add(Weight::from_parts(0, 17300)) // Standard Error: 596_297 - .saturating_add(Weight::from_ref_time(738_257_638).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(738_257_638, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(16810).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 16810).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1610,15 +1610,15 @@ impl WeightInfo for SubstrateWeight { // Measured: `0 + r * (79300 ±0)` // Estimated: `64844 + r * (942952 ±833)` // Minimum execution time: 374_097 nanoseconds. - Weight::from_ref_time(374_985_000) - .saturating_add(Weight::from_proof_size(64844)) + Weight::from_parts(374_985_000, 0) + .saturating_add(Weight::from_parts(0, 64844)) // Standard Error: 3_772_336 - .saturating_add(Weight::from_ref_time(1_546_402_854).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(1_546_402_854, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((225_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((150_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_proof_size(942952).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 942952).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1636,13 +1636,13 @@ impl WeightInfo for SubstrateWeight { // Measured: `869 + r * (240 ±0)` // Estimated: `17215 + r * (1200 ±0)` // Minimum execution time: 374_249 nanoseconds. - Weight::from_ref_time(377_990_998) - .saturating_add(Weight::from_proof_size(17215)) + Weight::from_parts(377_990_998, 0) + .saturating_add(Weight::from_parts(0, 17215)) // Standard Error: 38_133 - .saturating_add(Weight::from_ref_time(11_483_273).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(11_483_273, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(1200).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 1200).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1660,13 +1660,13 @@ impl WeightInfo for SubstrateWeight { // Measured: `2102 + r * (3154 ±0)` // Estimated: `21980 + r * (15875 ±2)` // Minimum execution time: 375_552 nanoseconds. - Weight::from_ref_time(400_624_032) - .saturating_add(Weight::from_proof_size(21980)) + Weight::from_parts(400_624_032, 0) + .saturating_add(Weight::from_parts(0, 21980)) // Standard Error: 82_523 - .saturating_add(Weight::from_ref_time(18_057_327).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(18_057_327, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(15875).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 15875).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1686,13 +1686,13 @@ impl WeightInfo for SubstrateWeight { // Measured: `872 + r * (240 ±0)` // Estimated: `18598 + r * (1440 ±0)` // Minimum execution time: 373_899 nanoseconds. - Weight::from_ref_time(379_733_943) - .saturating_add(Weight::from_proof_size(18598)) + Weight::from_parts(379_733_943, 0) + .saturating_add(Weight::from_parts(0, 18598)) // Standard Error: 32_022 - .saturating_add(Weight::from_ref_time(9_381_180).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(9_381_180, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) - .saturating_add(Weight::from_proof_size(1440).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 1440).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64const(r: u32, ) -> Weight { @@ -1700,10 +1700,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 834 nanoseconds. - Weight::from_ref_time(1_009_646) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_009_646, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 388 - .saturating_add(Weight::from_ref_time(411_979).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(411_979, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64load(r: u32, ) -> Weight { @@ -1711,10 +1711,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 882 nanoseconds. - Weight::from_ref_time(1_416_377) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_416_377, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 1_133 - .saturating_add(Weight::from_ref_time(1_075_838).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(1_075_838, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64store(r: u32, ) -> Weight { @@ -1722,10 +1722,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 878 nanoseconds. - Weight::from_ref_time(1_343_056) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_343_056, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 426 - .saturating_add(Weight::from_ref_time(1_001_214).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(1_001_214, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_select(r: u32, ) -> Weight { @@ -1733,10 +1733,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 796 nanoseconds. - Weight::from_ref_time(1_079_086) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_079_086, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 409 - .saturating_add(Weight::from_ref_time(1_149_188).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(1_149_188, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_if(r: u32, ) -> Weight { @@ -1744,10 +1744,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 800 nanoseconds. - Weight::from_ref_time(1_044_184) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_044_184, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 707 - .saturating_add(Weight::from_ref_time(1_315_686).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(1_315_686, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_br(r: u32, ) -> Weight { @@ -1755,10 +1755,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 807 nanoseconds. - Weight::from_ref_time(1_049_633) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_049_633, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 361 - .saturating_add(Weight::from_ref_time(640_530).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(640_530, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_br_if(r: u32, ) -> Weight { @@ -1766,10 +1766,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 774 nanoseconds. - Weight::from_ref_time(1_124_053) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_124_053, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 784 - .saturating_add(Weight::from_ref_time(949_398).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(949_398, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_br_table(r: u32, ) -> Weight { @@ -1777,10 +1777,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 810 nanoseconds. - Weight::from_ref_time(676_581) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(676_581, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 2_356 - .saturating_add(Weight::from_ref_time(1_163_465).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(1_163_465, 0).saturating_mul(r.into())) } /// The range of component `e` is `[1, 256]`. fn instr_br_table_per_entry(e: u32, ) -> Weight { @@ -1788,10 +1788,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 2_580 nanoseconds. - Weight::from_ref_time(2_835_656) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(2_835_656, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 71 - .saturating_add(Weight::from_ref_time(4_686).saturating_mul(e.into())) + .saturating_add(Weight::from_parts(4_686, 0).saturating_mul(e.into())) } /// The range of component `r` is `[0, 50]`. fn instr_call(r: u32, ) -> Weight { @@ -1799,10 +1799,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 826 nanoseconds. - Weight::from_ref_time(1_625_698) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_625_698, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 1_740 - .saturating_add(Weight::from_ref_time(2_332_187).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(2_332_187, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_call_indirect(r: u32, ) -> Weight { @@ -1810,10 +1810,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 901 nanoseconds. - Weight::from_ref_time(2_338_620) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(2_338_620, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 1_642 - .saturating_add(Weight::from_ref_time(2_924_090).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(2_924_090, 0).saturating_mul(r.into())) } /// The range of component `p` is `[0, 128]`. fn instr_call_indirect_per_param(p: u32, ) -> Weight { @@ -1821,10 +1821,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 4_670 nanoseconds. - Weight::from_ref_time(5_556_246) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(5_556_246, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 1_491 - .saturating_add(Weight::from_ref_time(228_965).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(228_965, 0).saturating_mul(p.into())) } /// The range of component `l` is `[0, 1024]`. fn instr_call_per_local(l: u32, ) -> Weight { @@ -1832,10 +1832,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 3_099 nanoseconds. - Weight::from_ref_time(3_896_177) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(3_896_177, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 99 - .saturating_add(Weight::from_ref_time(91_304).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(91_304, 0).saturating_mul(l.into())) } /// The range of component `r` is `[0, 50]`. fn instr_local_get(r: u32, ) -> Weight { @@ -1843,10 +1843,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 3_042 nanoseconds. - Weight::from_ref_time(3_334_621) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(3_334_621, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 793 - .saturating_add(Weight::from_ref_time(459_346).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(459_346, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_local_set(r: u32, ) -> Weight { @@ -1854,10 +1854,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 2_968 nanoseconds. - Weight::from_ref_time(3_235_286) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(3_235_286, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 427 - .saturating_add(Weight::from_ref_time(485_454).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(485_454, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_local_tee(r: u32, ) -> Weight { @@ -1865,10 +1865,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 3_012 nanoseconds. - Weight::from_ref_time(3_303_555) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(3_303_555, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 371 - .saturating_add(Weight::from_ref_time(657_811).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(657_811, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_global_get(r: u32, ) -> Weight { @@ -1876,10 +1876,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 865 nanoseconds. - Weight::from_ref_time(1_249_987) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_249_987, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 417 - .saturating_add(Weight::from_ref_time(896_704).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(896_704, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_global_set(r: u32, ) -> Weight { @@ -1887,10 +1887,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 866 nanoseconds. - Weight::from_ref_time(1_216_218) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_216_218, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 503 - .saturating_add(Weight::from_ref_time(919_719).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(919_719, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_memory_current(r: u32, ) -> Weight { @@ -1898,10 +1898,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 921 nanoseconds. - Weight::from_ref_time(1_228_408) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_228_408, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 309 - .saturating_add(Weight::from_ref_time(813_007).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(813_007, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 1]`. fn instr_memory_grow(r: u32, ) -> Weight { @@ -1909,10 +1909,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 820 nanoseconds. - Weight::from_ref_time(914_830) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(914_830, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 6_018 - .saturating_add(Weight::from_ref_time(237_062_769).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(237_062_769, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64clz(r: u32, ) -> Weight { @@ -1920,10 +1920,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 812 nanoseconds. - Weight::from_ref_time(1_554_406) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_554_406, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 9_979 - .saturating_add(Weight::from_ref_time(625_434).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(625_434, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ctz(r: u32, ) -> Weight { @@ -1931,10 +1931,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 798 nanoseconds. - Weight::from_ref_time(1_095_113) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_095_113, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 243 - .saturating_add(Weight::from_ref_time(634_204).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(634_204, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64popcnt(r: u32, ) -> Weight { @@ -1942,10 +1942,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 792 nanoseconds. - Weight::from_ref_time(1_109_845) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_109_845, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 14_944 - .saturating_add(Weight::from_ref_time(658_834).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(658_834, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64eqz(r: u32, ) -> Weight { @@ -1953,10 +1953,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 815 nanoseconds. - Weight::from_ref_time(1_068_916) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_068_916, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 327 - .saturating_add(Weight::from_ref_time(652_897).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(652_897, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendsi32(r: u32, ) -> Weight { @@ -1964,10 +1964,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 798 nanoseconds. - Weight::from_ref_time(1_069_745) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_069_745, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 306 - .saturating_add(Weight::from_ref_time(618_481).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(618_481, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendui32(r: u32, ) -> Weight { @@ -1975,10 +1975,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 799 nanoseconds. - Weight::from_ref_time(1_398_001) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_398_001, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 6_234 - .saturating_add(Weight::from_ref_time(611_399).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(611_399, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i32wrapi64(r: u32, ) -> Weight { @@ -1986,10 +1986,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 811 nanoseconds. - Weight::from_ref_time(1_098_083) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_098_083, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 297 - .saturating_add(Weight::from_ref_time(617_692).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(617_692, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64eq(r: u32, ) -> Weight { @@ -1997,10 +1997,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 815 nanoseconds. - Weight::from_ref_time(1_046_922) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_046_922, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 335 - .saturating_add(Weight::from_ref_time(909_196).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(909_196, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ne(r: u32, ) -> Weight { @@ -2008,10 +2008,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 805 nanoseconds. - Weight::from_ref_time(1_093_667) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_093_667, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 233 - .saturating_add(Weight::from_ref_time(907_378).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(907_378, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64lts(r: u32, ) -> Weight { @@ -2019,10 +2019,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 805 nanoseconds. - Weight::from_ref_time(1_290_591) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_290_591, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 3_201 - .saturating_add(Weight::from_ref_time(902_006).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(902_006, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ltu(r: u32, ) -> Weight { @@ -2030,10 +2030,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 783 nanoseconds. - Weight::from_ref_time(1_159_977) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_159_977, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 2_310 - .saturating_add(Weight::from_ref_time(906_489).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(906_489, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64gts(r: u32, ) -> Weight { @@ -2041,10 +2041,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 790 nanoseconds. - Weight::from_ref_time(1_109_719) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_109_719, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 261 - .saturating_add(Weight::from_ref_time(906_614).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(906_614, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64gtu(r: u32, ) -> Weight { @@ -2052,10 +2052,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 776 nanoseconds. - Weight::from_ref_time(1_076_567) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_076_567, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 348 - .saturating_add(Weight::from_ref_time(919_374).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(919_374, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64les(r: u32, ) -> Weight { @@ -2063,10 +2063,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 780 nanoseconds. - Weight::from_ref_time(1_069_663) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_069_663, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 265 - .saturating_add(Weight::from_ref_time(908_037).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(908_037, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64leu(r: u32, ) -> Weight { @@ -2074,10 +2074,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 832 nanoseconds. - Weight::from_ref_time(930_920) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(930_920, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 2_170 - .saturating_add(Weight::from_ref_time(929_811).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(929_811, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ges(r: u32, ) -> Weight { @@ -2085,10 +2085,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 787 nanoseconds. - Weight::from_ref_time(1_087_325) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_087_325, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 315 - .saturating_add(Weight::from_ref_time(908_321).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(908_321, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64geu(r: u32, ) -> Weight { @@ -2096,10 +2096,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 798 nanoseconds. - Weight::from_ref_time(1_029_132) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_029_132, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 2_095 - .saturating_add(Weight::from_ref_time(913_553).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(913_553, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64add(r: u32, ) -> Weight { @@ -2107,10 +2107,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 791 nanoseconds. - Weight::from_ref_time(1_086_314) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_086_314, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 197 - .saturating_add(Weight::from_ref_time(896_392).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(896_392, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64sub(r: u32, ) -> Weight { @@ -2118,10 +2118,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 793 nanoseconds. - Weight::from_ref_time(1_078_172) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_078_172, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 404 - .saturating_add(Weight::from_ref_time(886_329).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(886_329, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64mul(r: u32, ) -> Weight { @@ -2129,10 +2129,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 799 nanoseconds. - Weight::from_ref_time(1_095_010) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_095_010, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 431 - .saturating_add(Weight::from_ref_time(886_513).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(886_513, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64divs(r: u32, ) -> Weight { @@ -2140,10 +2140,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 810 nanoseconds. - Weight::from_ref_time(1_114_325) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_114_325, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 452 - .saturating_add(Weight::from_ref_time(1_521_849).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(1_521_849, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64divu(r: u32, ) -> Weight { @@ -2151,10 +2151,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 784 nanoseconds. - Weight::from_ref_time(1_123_153) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_123_153, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 475 - .saturating_add(Weight::from_ref_time(1_457_746).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(1_457_746, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64rems(r: u32, ) -> Weight { @@ -2162,10 +2162,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 809 nanoseconds. - Weight::from_ref_time(1_145_906) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_145_906, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 718 - .saturating_add(Weight::from_ref_time(1_549_964).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(1_549_964, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64remu(r: u32, ) -> Weight { @@ -2173,10 +2173,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 803 nanoseconds. - Weight::from_ref_time(1_110_328) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_110_328, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 627 - .saturating_add(Weight::from_ref_time(1_453_013).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(1_453_013, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64and(r: u32, ) -> Weight { @@ -2184,10 +2184,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 786 nanoseconds. - Weight::from_ref_time(1_108_792) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_108_792, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 286 - .saturating_add(Weight::from_ref_time(897_035).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(897_035, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64or(r: u32, ) -> Weight { @@ -2195,10 +2195,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 787 nanoseconds. - Weight::from_ref_time(830_000) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(830_000, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 15_995 - .saturating_add(Weight::from_ref_time(963_344).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(963_344, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64xor(r: u32, ) -> Weight { @@ -2206,10 +2206,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 773 nanoseconds. - Weight::from_ref_time(1_082_459) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_082_459, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 330 - .saturating_add(Weight::from_ref_time(897_077).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(897_077, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64shl(r: u32, ) -> Weight { @@ -2217,10 +2217,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 810 nanoseconds. - Weight::from_ref_time(1_325_815) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_325_815, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 3_352 - .saturating_add(Weight::from_ref_time(899_555).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(899_555, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64shrs(r: u32, ) -> Weight { @@ -2228,10 +2228,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 808 nanoseconds. - Weight::from_ref_time(1_085_903) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_085_903, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 430 - .saturating_add(Weight::from_ref_time(903_249).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(903_249, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64shru(r: u32, ) -> Weight { @@ -2239,10 +2239,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 792 nanoseconds. - Weight::from_ref_time(1_091_261) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_091_261, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 312 - .saturating_add(Weight::from_ref_time(902_245).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(902_245, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotl(r: u32, ) -> Weight { @@ -2250,10 +2250,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 807 nanoseconds. - Weight::from_ref_time(1_121_052) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_121_052, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 506 - .saturating_add(Weight::from_ref_time(902_772).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(902_772, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotr(r: u32, ) -> Weight { @@ -2261,10 +2261,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 823 nanoseconds. - Weight::from_ref_time(1_317_597) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_317_597, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 6_219 - .saturating_add(Weight::from_ref_time(896_692).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(896_692, 0).saturating_mul(r.into())) } } @@ -2277,8 +2277,8 @@ impl WeightInfo for () { // Measured: `109` // Estimated: `604` // Minimum execution time: 2_591 nanoseconds. - Weight::from_ref_time(2_817_000) - .saturating_add(Weight::from_proof_size(604)) + Weight::from_parts(2_817_000, 0) + .saturating_add(Weight::from_parts(0, 604)) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: Skipped Metadata (r:0 w:0) @@ -2289,14 +2289,14 @@ impl WeightInfo for () { // Measured: `481 + k * (69 ±0)` // Estimated: `471 + k * (70 ±0)` // Minimum execution time: 10_190 nanoseconds. - Weight::from_ref_time(6_642_117) - .saturating_add(Weight::from_proof_size(471)) + Weight::from_parts(6_642_117, 0) + .saturating_add(Weight::from_parts(0, 471)) // Standard Error: 992 - .saturating_add(Weight::from_ref_time(919_828).saturating_mul(k.into())) + .saturating_add(Weight::from_parts(919_828, 0).saturating_mul(k.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(k.into()))) - .saturating_add(Weight::from_proof_size(70).saturating_mul(k.into())) + .saturating_add(Weight::from_parts(0, 70).saturating_mul(k.into())) } /// Storage: Contracts DeletionQueue (r:1 w:1) /// Proof: Contracts DeletionQueue (max_values: Some(1), max_size: Some(16642), added: 17137, mode: Measured) @@ -2306,13 +2306,13 @@ impl WeightInfo for () { // Measured: `281 + q * (33 ±0)` // Estimated: `763 + q * (33 ±0)` // Minimum execution time: 2_598 nanoseconds. - Weight::from_ref_time(10_288_252) - .saturating_add(Weight::from_proof_size(763)) + Weight::from_parts(10_288_252, 0) + .saturating_add(Weight::from_parts(0, 763)) // Standard Error: 2_886 - .saturating_add(Weight::from_ref_time(1_092_420).saturating_mul(q.into())) + .saturating_add(Weight::from_parts(1_092_420, 0).saturating_mul(q.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) - .saturating_add(Weight::from_proof_size(33).saturating_mul(q.into())) + .saturating_add(Weight::from_parts(0, 33).saturating_mul(q.into())) } /// Storage: Contracts PristineCode (r:1 w:0) /// Proof: Contracts PristineCode (max_values: None, max_size: Some(125988), added: 128463, mode: Measured) @@ -2324,13 +2324,13 @@ impl WeightInfo for () { // Measured: `270 + c * (1 ±0)` // Estimated: `3025 + c * (2 ±0)` // Minimum execution time: 34_338 nanoseconds. - Weight::from_ref_time(32_159_677) - .saturating_add(Weight::from_proof_size(3025)) + Weight::from_parts(32_159_677, 0) + .saturating_add(Weight::from_parts(0, 3025)) // Standard Error: 53 - .saturating_add(Weight::from_ref_time(51_034).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(51_034, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) - .saturating_add(Weight::from_proof_size(2).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(0, 2).saturating_mul(c.into())) } /// Storage: Contracts ContractInfoOf (r:1 w:1) /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) @@ -2348,13 +2348,13 @@ impl WeightInfo for () { // Measured: `803` // Estimated: `16930 + c * (5 ±0)` // Minimum execution time: 385_587 nanoseconds. - Weight::from_ref_time(395_545_811) - .saturating_add(Weight::from_proof_size(16930)) + Weight::from_parts(395_545_811, 0) + .saturating_add(Weight::from_parts(0, 16930)) // Standard Error: 27 - .saturating_add(Weight::from_ref_time(31_342).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(31_342, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) - .saturating_add(Weight::from_proof_size(5).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(0, 5).saturating_mul(c.into())) } /// Storage: Contracts OwnerInfoOf (r:1 w:1) /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Measured) @@ -2380,14 +2380,14 @@ impl WeightInfo for () { // Measured: `270` // Estimated: `20267` // Minimum execution time: 3_799_742 nanoseconds. - Weight::from_ref_time(670_115_588) - .saturating_add(Weight::from_proof_size(20267)) + Weight::from_parts(670_115_588, 0) + .saturating_add(Weight::from_parts(0, 20267)) // Standard Error: 287 - .saturating_add(Weight::from_ref_time(93_885).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(93_885, 0).saturating_mul(c.into())) // Standard Error: 16 - .saturating_add(Weight::from_ref_time(1_367).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(1_367, 0).saturating_mul(i.into())) // Standard Error: 16 - .saturating_add(Weight::from_ref_time(1_781).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_781, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(10_u64)) } @@ -2412,12 +2412,12 @@ impl WeightInfo for () { // Measured: `546` // Estimated: `22039` // Minimum execution time: 1_949_008 nanoseconds. - Weight::from_ref_time(214_033_418) - .saturating_add(Weight::from_proof_size(22039)) + Weight::from_parts(214_033_418, 0) + .saturating_add(Weight::from_parts(0, 22039)) // Standard Error: 8 - .saturating_add(Weight::from_ref_time(1_666).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(1_666, 0).saturating_mul(i.into())) // Standard Error: 8 - .saturating_add(Weight::from_ref_time(1_801).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_801, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } @@ -2436,8 +2436,8 @@ impl WeightInfo for () { // Measured: `855` // Estimated: `17145` // Minimum execution time: 146_654 nanoseconds. - Weight::from_ref_time(147_528_000) - .saturating_add(Weight::from_proof_size(17145)) + Weight::from_parts(147_528_000, 0) + .saturating_add(Weight::from_parts(0, 17145)) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -2455,10 +2455,10 @@ impl WeightInfo for () { // Measured: `109` // Estimated: `5386` // Minimum execution time: 387_889 nanoseconds. - Weight::from_ref_time(391_379_335) - .saturating_add(Weight::from_proof_size(5386)) + Weight::from_parts(391_379_335, 0) + .saturating_add(Weight::from_parts(0, 5386)) // Standard Error: 89 - .saturating_add(Weight::from_ref_time(94_810).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(94_810, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -2475,8 +2475,8 @@ impl WeightInfo for () { // Measured: `287` // Estimated: `6098` // Minimum execution time: 26_014 nanoseconds. - Weight::from_ref_time(26_510_000) - .saturating_add(Weight::from_proof_size(6098)) + Weight::from_parts(26_510_000, 0) + .saturating_add(Weight::from_parts(0, 6098)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -2491,8 +2491,8 @@ impl WeightInfo for () { // Measured: `666` // Estimated: `16848` // Minimum execution time: 30_177 nanoseconds. - Weight::from_ref_time(30_639_000) - .saturating_add(Weight::from_proof_size(16848)) + Weight::from_parts(30_639_000, 0) + .saturating_add(Weight::from_parts(0, 16848)) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -2512,13 +2512,13 @@ impl WeightInfo for () { // Measured: `877 + r * (480 ±0)` // Estimated: `17295 + r * (2400 ±0)` // Minimum execution time: 373_786 nanoseconds. - Weight::from_ref_time(377_332_691) - .saturating_add(Weight::from_proof_size(17295)) + Weight::from_parts(377_332_691, 0) + .saturating_add(Weight::from_parts(0, 17295)) // Standard Error: 51_211 - .saturating_add(Weight::from_ref_time(17_715_615).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(17_715_615, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(2400).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 2400).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2536,14 +2536,14 @@ impl WeightInfo for () { // Measured: `917 + r * (21778 ±0)` // Estimated: `17295 + r * (306895 ±0)` // Minimum execution time: 374_009 nanoseconds. - Weight::from_ref_time(238_991_986) - .saturating_add(Weight::from_proof_size(17295)) + Weight::from_parts(238_991_986, 0) + .saturating_add(Weight::from_parts(0, 17295)) // Standard Error: 464_711 - .saturating_add(Weight::from_ref_time(249_099_538).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(249_099_538, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(306895).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 306895).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2561,14 +2561,14 @@ impl WeightInfo for () { // Measured: `921 + r * (22099 ±0)` // Estimated: `17340 + r * (308500 ±0)` // Minimum execution time: 375_058 nanoseconds. - Weight::from_ref_time(238_765_068) - .saturating_add(Weight::from_proof_size(17340)) + Weight::from_parts(238_765_068, 0) + .saturating_add(Weight::from_parts(0, 17340)) // Standard Error: 662_617 - .saturating_add(Weight::from_ref_time(302_175_089).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(302_175_089, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(308500).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 308500).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2586,13 +2586,13 @@ impl WeightInfo for () { // Measured: `884 + r * (480 ±0)` // Estimated: `17330 + r * (2400 ±0)` // Minimum execution time: 374_747 nanoseconds. - Weight::from_ref_time(376_482_380) - .saturating_add(Weight::from_proof_size(17330)) + Weight::from_parts(376_482_380, 0) + .saturating_add(Weight::from_parts(0, 17330)) // Standard Error: 61_919 - .saturating_add(Weight::from_ref_time(22_376_795).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(22_376_795, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(2400).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 2400).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2610,13 +2610,13 @@ impl WeightInfo for () { // Measured: `874 + r * (240 ±0)` // Estimated: `17265 + r * (1200 ±0)` // Minimum execution time: 372_287 nanoseconds. - Weight::from_ref_time(376_250_858) - .saturating_add(Weight::from_proof_size(17265)) + Weight::from_parts(376_250_858, 0) + .saturating_add(Weight::from_parts(0, 17265)) // Standard Error: 40_119 - .saturating_add(Weight::from_ref_time(11_359_647).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(11_359_647, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(1200).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 1200).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2634,13 +2634,13 @@ impl WeightInfo for () { // Measured: `878 + r * (480 ±0)` // Estimated: `17260 + r * (2400 ±0)` // Minimum execution time: 374_445 nanoseconds. - Weight::from_ref_time(377_243_521) - .saturating_add(Weight::from_proof_size(17260)) + Weight::from_parts(377_243_521, 0) + .saturating_add(Weight::from_parts(0, 17260)) // Standard Error: 53_032 - .saturating_add(Weight::from_ref_time(17_684_246).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(17_684_246, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(2400).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 2400).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2658,13 +2658,13 @@ impl WeightInfo for () { // Measured: `879 + r * (480 ±0)` // Estimated: `17250 + r * (2405 ±0)` // Minimum execution time: 374_029 nanoseconds. - Weight::from_ref_time(380_415_186) - .saturating_add(Weight::from_proof_size(17250)) + Weight::from_parts(380_415_186, 0) + .saturating_add(Weight::from_parts(0, 17250)) // Standard Error: 60_562 - .saturating_add(Weight::from_ref_time(17_152_599).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(17_152_599, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(2405).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 2405).saturating_mul(r.into())) } /// Storage: System Account (r:2 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2682,13 +2682,13 @@ impl WeightInfo for () { // Measured: `1049 + r * (480 ±0)` // Estimated: `19849 + r * (2456 ±0)` // Minimum execution time: 373_999 nanoseconds. - Weight::from_ref_time(381_757_033) - .saturating_add(Weight::from_proof_size(19849)) + Weight::from_parts(381_757_033, 0) + .saturating_add(Weight::from_parts(0, 19849)) // Standard Error: 97_983 - .saturating_add(Weight::from_ref_time(98_290_984).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(98_290_984, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(2456).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 2456).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2706,13 +2706,13 @@ impl WeightInfo for () { // Measured: `888 + r * (480 ±0)` // Estimated: `17360 + r * (2400 ±0)` // Minimum execution time: 374_197 nanoseconds. - Weight::from_ref_time(377_755_896) - .saturating_add(Weight::from_proof_size(17360)) + Weight::from_parts(377_755_896, 0) + .saturating_add(Weight::from_parts(0, 17360)) // Standard Error: 60_542 - .saturating_add(Weight::from_ref_time(17_442_065).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(17_442_065, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(2400).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 2400).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2730,13 +2730,13 @@ impl WeightInfo for () { // Measured: `886 + r * (480 ±0)` // Estimated: `17290 + r * (2400 ±0)` // Minimum execution time: 373_888 nanoseconds. - Weight::from_ref_time(377_825_771) - .saturating_add(Weight::from_proof_size(17290)) + Weight::from_parts(377_825_771, 0) + .saturating_add(Weight::from_parts(0, 17290)) // Standard Error: 38_026 - .saturating_add(Weight::from_ref_time(17_147_903).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(17_147_903, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(2400).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 2400).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2754,13 +2754,13 @@ impl WeightInfo for () { // Measured: `883 + r * (480 ±0)` // Estimated: `17315 + r * (2400 ±0)` // Minimum execution time: 373_904 nanoseconds. - Weight::from_ref_time(378_652_372) - .saturating_add(Weight::from_proof_size(17315)) + Weight::from_parts(378_652_372, 0) + .saturating_add(Weight::from_parts(0, 17315)) // Standard Error: 43_833 - .saturating_add(Weight::from_ref_time(16_936_781).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(16_936_781, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(2400).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 2400).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2778,13 +2778,13 @@ impl WeightInfo for () { // Measured: `874 + r * (480 ±0)` // Estimated: `17245 + r * (2400 ±0)` // Minimum execution time: 373_473 nanoseconds. - Weight::from_ref_time(376_386_312) - .saturating_add(Weight::from_proof_size(17245)) + Weight::from_parts(376_386_312, 0) + .saturating_add(Weight::from_parts(0, 17245)) // Standard Error: 46_945 - .saturating_add(Weight::from_ref_time(17_336_462).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(17_336_462, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(2400).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 2400).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2804,13 +2804,13 @@ impl WeightInfo for () { // Measured: `951 + r * (800 ±0)` // Estimated: `19046 + r * (4805 ±0)` // Minimum execution time: 373_661 nanoseconds. - Weight::from_ref_time(385_824_015) - .saturating_add(Weight::from_proof_size(19046)) + Weight::from_parts(385_824_015, 0) + .saturating_add(Weight::from_parts(0, 19046)) // Standard Error: 75_964 - .saturating_add(Weight::from_ref_time(88_530_074).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(88_530_074, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(4805).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 4805).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2828,13 +2828,13 @@ impl WeightInfo for () { // Measured: `841 + r * (320 ±0)` // Estimated: `17120 + r * (1600 ±0)` // Minimum execution time: 133_849 nanoseconds. - Weight::from_ref_time(137_283_391) - .saturating_add(Weight::from_proof_size(17120)) + Weight::from_parts(137_283_391, 0) + .saturating_add(Weight::from_parts(0, 17120)) // Standard Error: 13_312 - .saturating_add(Weight::from_ref_time(8_055_328).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(8_055_328, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(1600).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 1600).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2852,13 +2852,13 @@ impl WeightInfo for () { // Measured: `876 + r * (480 ±0)` // Estimated: `17245 + r * (2400 ±0)` // Minimum execution time: 373_468 nanoseconds. - Weight::from_ref_time(376_121_093) - .saturating_add(Weight::from_proof_size(17245)) + Weight::from_parts(376_121_093, 0) + .saturating_add(Weight::from_parts(0, 17245)) // Standard Error: 61_857 - .saturating_add(Weight::from_ref_time(15_868_414).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(15_868_414, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(2400).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 2400).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2876,10 +2876,10 @@ impl WeightInfo for () { // Measured: `1356` // Estimated: `19650` // Minimum execution time: 390_668 nanoseconds. - Weight::from_ref_time(419_608_449) - .saturating_add(Weight::from_proof_size(19650)) + Weight::from_parts(419_608_449, 0) + .saturating_add(Weight::from_parts(0, 19650)) // Standard Error: 4_890 - .saturating_add(Weight::from_ref_time(9_672_288).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(9_672_288, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -2899,13 +2899,13 @@ impl WeightInfo for () { // Measured: `864 + r * (45 ±0)` // Estimated: `17190 + r * (225 ±0)` // Minimum execution time: 371_309 nanoseconds. - Weight::from_ref_time(373_625_402) - .saturating_add(Weight::from_proof_size(17190)) + Weight::from_parts(373_625_402, 0) + .saturating_add(Weight::from_parts(0, 17190)) // Standard Error: 419_605 - .saturating_add(Weight::from_ref_time(1_737_397).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(1_737_397, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(225).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 225).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2923,10 +2923,10 @@ impl WeightInfo for () { // Measured: `874` // Estimated: `17285` // Minimum execution time: 374_094 nanoseconds. - Weight::from_ref_time(375_965_200) - .saturating_add(Weight::from_proof_size(17285)) + Weight::from_parts(375_965_200, 0) + .saturating_add(Weight::from_parts(0, 17285)) // Standard Error: 1_127 - .saturating_add(Weight::from_ref_time(232_645).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(232_645, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -2950,15 +2950,15 @@ impl WeightInfo for () { // Measured: `906 + r * (452 ±0)` // Estimated: `20242 + r * (15004 ±0)` // Minimum execution time: 373_123 nanoseconds. - Weight::from_ref_time(374_924_634) - .saturating_add(Weight::from_proof_size(20242)) + Weight::from_parts(374_924_634, 0) + .saturating_add(Weight::from_parts(0, 20242)) // Standard Error: 378_010 - .saturating_add(Weight::from_ref_time(70_441_665).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(70_441_665, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((6_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((7_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_proof_size(15004).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 15004).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2978,13 +2978,13 @@ impl WeightInfo for () { // Measured: `921 + r * (800 ±0)` // Estimated: `18835 + r * (4805 ±0)` // Minimum execution time: 373_291 nanoseconds. - Weight::from_ref_time(385_684_344) - .saturating_add(Weight::from_proof_size(18835)) + Weight::from_parts(385_684_344, 0) + .saturating_add(Weight::from_parts(0, 18835)) // Standard Error: 99_025 - .saturating_add(Weight::from_ref_time(111_308_793).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(111_308_793, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(4805).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 4805).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3002,13 +3002,13 @@ impl WeightInfo for () { // Measured: `874 + r * (800 ±0)` // Estimated: `17250 + r * (4000 ±0)` // Minimum execution time: 371_900 nanoseconds. - Weight::from_ref_time(384_166_626) - .saturating_add(Weight::from_proof_size(17250)) + Weight::from_parts(384_166_626, 0) + .saturating_add(Weight::from_parts(0, 17250)) // Standard Error: 205_255 - .saturating_add(Weight::from_ref_time(229_214_157).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(229_214_157, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(4000).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 4000).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3027,18 +3027,18 @@ impl WeightInfo for () { // Measured: `1821 + t * (2608 ±0) + n * (7 ±0)` // Estimated: `21870 + t * (211030 ±0) + n * (50 ±0)` // Minimum execution time: 1_289_873 nanoseconds. - Weight::from_ref_time(581_702_206) - .saturating_add(Weight::from_proof_size(21870)) + Weight::from_parts(581_702_206, 0) + .saturating_add(Weight::from_parts(0, 21870)) // Standard Error: 665_638 - .saturating_add(Weight::from_ref_time(181_470_553).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(181_470_553, 0).saturating_mul(t.into())) // Standard Error: 182_816 - .saturating_add(Weight::from_ref_time(71_635_250).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(71_635_250, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(t.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((80_u64).saturating_mul(t.into()))) - .saturating_add(Weight::from_proof_size(211030).saturating_mul(t.into())) - .saturating_add(Weight::from_proof_size(50).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 211030).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(0, 50).saturating_mul(n.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3056,13 +3056,13 @@ impl WeightInfo for () { // Measured: `873 + r * (560 ±0)` // Estimated: `17240 + r * (2800 ±0)` // Minimum execution time: 148_635 nanoseconds. - Weight::from_ref_time(154_095_712) - .saturating_add(Weight::from_proof_size(17240)) + Weight::from_parts(154_095_712, 0) + .saturating_add(Weight::from_parts(0, 17240)) // Standard Error: 77_790 - .saturating_add(Weight::from_ref_time(14_837_085).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(14_837_085, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(2800).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 2800).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) @@ -3080,10 +3080,10 @@ impl WeightInfo for () { // Measured: `125824` // Estimated: `265128` // Minimum execution time: 501_014 nanoseconds. - Weight::from_ref_time(505_634_218) - .saturating_add(Weight::from_proof_size(265128)) + Weight::from_parts(505_634_218, 0) + .saturating_add(Weight::from_parts(0, 265128)) // Standard Error: 2_441 - .saturating_add(Weight::from_ref_time(819_257).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(819_257, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3095,15 +3095,15 @@ impl WeightInfo for () { // Measured: `911 + r * (23420 ±0)` // Estimated: `911 + r * (23418 ±0)` // Minimum execution time: 375_301 nanoseconds. - Weight::from_ref_time(291_498_841) - .saturating_add(Weight::from_proof_size(911)) + Weight::from_parts(291_498_841, 0) + .saturating_add(Weight::from_parts(0, 911)) // Standard Error: 809_989 - .saturating_add(Weight::from_ref_time(464_550_291).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(464_550_291, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((80_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_proof_size(23418).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 23418).saturating_mul(r.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) @@ -3113,15 +3113,15 @@ impl WeightInfo for () { // Measured: `12672 + n * (11945 ±0)` // Estimated: `8529 + n * (12814 ±61)` // Minimum execution time: 506_318 nanoseconds. - Weight::from_ref_time(676_935_313) - .saturating_add(Weight::from_proof_size(8529)) + Weight::from_parts(676_935_313, 0) + .saturating_add(Weight::from_parts(0, 8529)) // Standard Error: 1_589_291 - .saturating_add(Weight::from_ref_time(97_839_399).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(97_839_399, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(52_u64)) .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(50_u64)) .saturating_add(RocksDbWeight::get().writes((7_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_proof_size(12814).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 12814).saturating_mul(n.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) @@ -3131,15 +3131,15 @@ impl WeightInfo for () { // Measured: `15170 + n * (175775 ±0)` // Estimated: `9914 + n * (176858 ±74)` // Minimum execution time: 506_148 nanoseconds. - Weight::from_ref_time(648_278_778) - .saturating_add(Weight::from_proof_size(9914)) + Weight::from_parts(648_278_778, 0) + .saturating_add(Weight::from_parts(0, 9914)) // Standard Error: 1_343_586 - .saturating_add(Weight::from_ref_time(65_789_595).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(65_789_595, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(51_u64)) .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(49_u64)) .saturating_add(RocksDbWeight::get().writes((7_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_proof_size(176858).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 176858).saturating_mul(n.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) @@ -3149,15 +3149,15 @@ impl WeightInfo for () { // Measured: `903 + r * (23099 ±0)` // Estimated: `908 + r * (23099 ±0)` // Minimum execution time: 374_344 nanoseconds. - Weight::from_ref_time(293_272_061) - .saturating_add(Weight::from_proof_size(908)) + Weight::from_parts(293_272_061, 0) + .saturating_add(Weight::from_parts(0, 908)) // Standard Error: 810_412 - .saturating_add(Weight::from_ref_time(453_315_956).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(453_315_956, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((80_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_proof_size(23099).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 23099).saturating_mul(r.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) @@ -3167,15 +3167,15 @@ impl WeightInfo for () { // Measured: `14895 + n * (175768 ±0)` // Estimated: `9551 + n * (176867 ±75)` // Minimum execution time: 478_564 nanoseconds. - Weight::from_ref_time(630_839_142) - .saturating_add(Weight::from_proof_size(9551)) + Weight::from_parts(630_839_142, 0) + .saturating_add(Weight::from_parts(0, 9551)) // Standard Error: 1_427_520 - .saturating_add(Weight::from_ref_time(66_813_592).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(66_813_592, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(51_u64)) .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(48_u64)) .saturating_add(RocksDbWeight::get().writes((7_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_proof_size(176867).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 176867).saturating_mul(n.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) @@ -3185,14 +3185,14 @@ impl WeightInfo for () { // Measured: `896 + r * (23744 ±0)` // Estimated: `909 + r * (23740 ±0)` // Minimum execution time: 374_479 nanoseconds. - Weight::from_ref_time(311_839_315) - .saturating_add(Weight::from_proof_size(909)) + Weight::from_parts(311_839_315, 0) + .saturating_add(Weight::from_parts(0, 909)) // Standard Error: 666_553 - .saturating_add(Weight::from_ref_time(371_213_042).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(371_213_042, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(23740).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 23740).saturating_mul(r.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) @@ -3202,14 +3202,14 @@ impl WeightInfo for () { // Measured: `15501 + n * (175775 ±0)` // Estimated: `10042 + n * (176900 ±76)` // Minimum execution time: 460_639 nanoseconds. - Weight::from_ref_time(591_187_094) - .saturating_add(Weight::from_proof_size(10042)) + Weight::from_parts(591_187_094, 0) + .saturating_add(Weight::from_parts(0, 10042)) // Standard Error: 1_233_792 - .saturating_add(Weight::from_ref_time(160_874_477).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(160_874_477, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(51_u64)) .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(176900).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 176900).saturating_mul(n.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) @@ -3219,14 +3219,14 @@ impl WeightInfo for () { // Measured: `914 + r * (23098 ±0)` // Estimated: `920 + r * (23098 ±0)` // Minimum execution time: 374_272 nanoseconds. - Weight::from_ref_time(311_446_269) - .saturating_add(Weight::from_proof_size(920)) + Weight::from_parts(311_446_269, 0) + .saturating_add(Weight::from_parts(0, 920)) // Standard Error: 630_307 - .saturating_add(Weight::from_ref_time(357_134_931).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(357_134_931, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(23098).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 23098).saturating_mul(r.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) @@ -3236,14 +3236,14 @@ impl WeightInfo for () { // Measured: `14839 + n * (175789 ±0)` // Estimated: `9532 + n * (176874 ±75)` // Minimum execution time: 456_013 nanoseconds. - Weight::from_ref_time(575_116_352) - .saturating_add(Weight::from_proof_size(9532)) + Weight::from_parts(575_116_352, 0) + .saturating_add(Weight::from_parts(0, 9532)) // Standard Error: 1_122_298 - .saturating_add(Weight::from_ref_time(61_786_107).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(61_786_107, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(51_u64)) .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(176874).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 176874).saturating_mul(n.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) @@ -3253,15 +3253,15 @@ impl WeightInfo for () { // Measured: `911 + r * (23740 ±0)` // Estimated: `913 + r * (23739 ±0)` // Minimum execution time: 374_621 nanoseconds. - Weight::from_ref_time(299_689_489) - .saturating_add(Weight::from_proof_size(913)) + Weight::from_parts(299_689_489, 0) + .saturating_add(Weight::from_parts(0, 913)) // Standard Error: 757_735 - .saturating_add(Weight::from_ref_time(465_213_246).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(465_213_246, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((80_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_proof_size(23739).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 23739).saturating_mul(r.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) @@ -3271,15 +3271,15 @@ impl WeightInfo for () { // Measured: `15502 + n * (175775 ±0)` // Estimated: `10042 + n * (176898 ±76)` // Minimum execution time: 481_980 nanoseconds. - Weight::from_ref_time(647_289_053) - .saturating_add(Weight::from_proof_size(10042)) + Weight::from_parts(647_289_053, 0) + .saturating_add(Weight::from_parts(0, 10042)) // Standard Error: 1_556_155 - .saturating_add(Weight::from_ref_time(166_592_657).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(166_592_657, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(51_u64)) .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(48_u64)) .saturating_add(RocksDbWeight::get().writes((7_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_proof_size(176898).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 176898).saturating_mul(n.into())) } /// Storage: System Account (r:1602 w:1601) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3297,15 +3297,15 @@ impl WeightInfo for () { // Measured: `1457 + r * (3604 ±0)` // Estimated: `21583 + r * (216101 ±0)` // Minimum execution time: 374_962 nanoseconds. - Weight::from_ref_time(313_416_386) - .saturating_add(Weight::from_proof_size(21583)) + Weight::from_parts(313_416_386, 0) + .saturating_add(Weight::from_parts(0, 21583)) // Standard Error: 710_675 - .saturating_add(Weight::from_ref_time(1_396_551_156).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(1_396_551_156, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(RocksDbWeight::get().writes((80_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_proof_size(216101).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 216101).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3323,15 +3323,15 @@ impl WeightInfo for () { // Measured: `1609 + r * (23073 ±0)` // Estimated: `22098 + r * (511456 ±1)` // Minimum execution time: 375_916 nanoseconds. - Weight::from_ref_time(376_468_000) - .saturating_add(Weight::from_proof_size(22098)) + Weight::from_parts(376_468_000, 0) + .saturating_add(Weight::from_parts(0, 22098)) // Standard Error: 7_246_855 - .saturating_add(Weight::from_ref_time(28_982_425_139).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(28_982_425_139, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().reads((160_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((160_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_proof_size(511456).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 511456).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3349,15 +3349,15 @@ impl WeightInfo for () { // Measured: `0 + r * (71670 ±0)` // Estimated: `17285 + r * (659930 ±563)` // Minimum execution time: 375_412 nanoseconds. - Weight::from_ref_time(376_493_000) - .saturating_add(Weight::from_proof_size(17285)) + Weight::from_parts(376_493_000, 0) + .saturating_add(Weight::from_parts(0, 17285)) // Standard Error: 8_239_575 - .saturating_add(Weight::from_ref_time(28_716_347_183).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(28_716_347_183, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((150_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((75_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_proof_size(659930).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 659930).saturating_mul(r.into())) } /// Storage: System Account (r:82 w:81) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3376,17 +3376,17 @@ impl WeightInfo for () { // Measured: `24269 + t * (16910 ±0)` // Estimated: `532690 + t * (285025 ±0)` // Minimum execution time: 10_443_315 nanoseconds. - Weight::from_ref_time(9_342_574_069) - .saturating_add(Weight::from_proof_size(532690)) + Weight::from_parts(9_342_574_069, 0) + .saturating_add(Weight::from_parts(0, 532690)) // Standard Error: 7_237_279 - .saturating_add(Weight::from_ref_time(1_390_221_936).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(1_390_221_936, 0).saturating_mul(t.into())) // Standard Error: 10_851 - .saturating_add(Weight::from_ref_time(9_842_151).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(9_842_151, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(167_u64)) .saturating_add(RocksDbWeight::get().reads((81_u64).saturating_mul(t.into()))) .saturating_add(RocksDbWeight::get().writes(163_u64)) .saturating_add(RocksDbWeight::get().writes((81_u64).saturating_mul(t.into()))) - .saturating_add(Weight::from_proof_size(285025).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(0, 285025).saturating_mul(t.into())) } /// Storage: System Account (r:3202 w:3202) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3408,15 +3408,15 @@ impl WeightInfo for () { // Measured: `1775 + r * (25568 ±0)` // Estimated: `26563 + r * (1367114 ±2)` // Minimum execution time: 376_418 nanoseconds. - Weight::from_ref_time(377_292_000) - .saturating_add(Weight::from_proof_size(26563)) + Weight::from_parts(377_292_000, 0) + .saturating_add(Weight::from_parts(0, 26563)) // Standard Error: 32_312_545 - .saturating_add(Weight::from_ref_time(35_904_826_312).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(35_904_826_312, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().reads((480_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(5_u64)) .saturating_add(RocksDbWeight::get().writes((400_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_proof_size(1367114).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 1367114).saturating_mul(r.into())) } /// Storage: System Account (r:162 w:162) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3440,19 +3440,19 @@ impl WeightInfo for () { // Measured: `5785 + t * (33 ±0)` // Estimated: `850985 + t * (2671 ±3)` // Minimum execution time: 132_157_340 nanoseconds. - Weight::from_ref_time(11_329_968_948) - .saturating_add(Weight::from_proof_size(850985)) + Weight::from_parts(11_329_968_948, 0) + .saturating_add(Weight::from_parts(0, 850985)) // Standard Error: 99_102_968 - .saturating_add(Weight::from_ref_time(84_719_458).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(84_719_458, 0).saturating_mul(t.into())) // Standard Error: 161_609 - .saturating_add(Weight::from_ref_time(126_156_627).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(126_156_627, 0).saturating_mul(i.into())) // Standard Error: 161_609 - .saturating_add(Weight::from_ref_time(126_628_313).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(126_628_313, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(329_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(t.into()))) .saturating_add(RocksDbWeight::get().writes(326_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(t.into()))) - .saturating_add(Weight::from_proof_size(2671).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(0, 2671).saturating_mul(t.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3470,13 +3470,13 @@ impl WeightInfo for () { // Measured: `871 + r * (642 ±0)` // Estimated: `17225 + r * (3210 ±0)` // Minimum execution time: 373_559 nanoseconds. - Weight::from_ref_time(375_166_904) - .saturating_add(Weight::from_proof_size(17225)) + Weight::from_parts(375_166_904, 0) + .saturating_add(Weight::from_parts(0, 17225)) // Standard Error: 125_024 - .saturating_add(Weight::from_ref_time(42_291_595).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(42_291_595, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(3210).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 3210).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3494,10 +3494,10 @@ impl WeightInfo for () { // Measured: `1673` // Estimated: `21160` // Minimum execution time: 416_233 nanoseconds. - Weight::from_ref_time(416_785_000) - .saturating_add(Weight::from_proof_size(21160)) + Weight::from_parts(416_785_000, 0) + .saturating_add(Weight::from_parts(0, 21160)) // Standard Error: 56_223 - .saturating_add(Weight::from_ref_time(324_513_835).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(324_513_835, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3517,13 +3517,13 @@ impl WeightInfo for () { // Measured: `873 + r * (642 ±0)` // Estimated: `17235 + r * (3210 ±0)` // Minimum execution time: 371_735 nanoseconds. - Weight::from_ref_time(375_979_430) - .saturating_add(Weight::from_proof_size(17235)) + Weight::from_parts(375_979_430, 0) + .saturating_add(Weight::from_parts(0, 17235)) // Standard Error: 968_037 - .saturating_add(Weight::from_ref_time(57_780_769).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(57_780_769, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(3210).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 3210).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3541,10 +3541,10 @@ impl WeightInfo for () { // Measured: `1675` // Estimated: `21205` // Minimum execution time: 428_196 nanoseconds. - Weight::from_ref_time(429_438_000) - .saturating_add(Weight::from_proof_size(21205)) + Weight::from_parts(429_438_000, 0) + .saturating_add(Weight::from_parts(0, 21205)) // Standard Error: 57_860 - .saturating_add(Weight::from_ref_time(260_917_896).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(260_917_896, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3564,13 +3564,13 @@ impl WeightInfo for () { // Measured: `873 + r * (642 ±0)` // Estimated: `17235 + r * (3210 ±0)` // Minimum execution time: 371_412 nanoseconds. - Weight::from_ref_time(373_635_818) - .saturating_add(Weight::from_proof_size(17235)) + Weight::from_parts(373_635_818, 0) + .saturating_add(Weight::from_parts(0, 17235)) // Standard Error: 222_973 - .saturating_add(Weight::from_ref_time(33_347_181).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(33_347_181, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(3210).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 3210).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3588,10 +3588,10 @@ impl WeightInfo for () { // Measured: `1675` // Estimated: `21180` // Minimum execution time: 405_858 nanoseconds. - Weight::from_ref_time(406_498_000) - .saturating_add(Weight::from_proof_size(21180)) + Weight::from_parts(406_498_000, 0) + .saturating_add(Weight::from_parts(0, 21180)) // Standard Error: 48_388 - .saturating_add(Weight::from_ref_time(103_283_157).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(103_283_157, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3611,13 +3611,13 @@ impl WeightInfo for () { // Measured: `873 + r * (679 ±0)` // Estimated: `17235 + r * (3395 ±0)` // Minimum execution time: 371_746 nanoseconds. - Weight::from_ref_time(373_538_171) - .saturating_add(Weight::from_proof_size(17235)) + Weight::from_parts(373_538_171, 0) + .saturating_add(Weight::from_parts(0, 17235)) // Standard Error: 387_332 - .saturating_add(Weight::from_ref_time(35_933_528).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(35_933_528, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(3395).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 3395).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3635,10 +3635,10 @@ impl WeightInfo for () { // Measured: `1675` // Estimated: `21225` // Minimum execution time: 405_752 nanoseconds. - Weight::from_ref_time(406_417_000) - .saturating_add(Weight::from_proof_size(21225)) + Weight::from_parts(406_417_000, 0) + .saturating_add(Weight::from_parts(0, 21225)) // Standard Error: 47_051 - .saturating_add(Weight::from_ref_time(103_325_027).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(103_325_027, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3658,13 +3658,13 @@ impl WeightInfo for () { // Measured: `917 + r * (6083 ±0)` // Estimated: `17455 + r * (30415 ±0)` // Minimum execution time: 373_882 nanoseconds. - Weight::from_ref_time(376_553_787) - .saturating_add(Weight::from_proof_size(17455)) + Weight::from_parts(376_553_787, 0) + .saturating_add(Weight::from_parts(0, 17455)) // Standard Error: 912_833 - .saturating_add(Weight::from_ref_time(3_021_100_412).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_021_100_412, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(30415).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 30415).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3682,13 +3682,13 @@ impl WeightInfo for () { // Measured: `886 + r * (3362 ±0)` // Estimated: `17300 + r * (16810 ±0)` // Minimum execution time: 373_673 nanoseconds. - Weight::from_ref_time(375_712_961) - .saturating_add(Weight::from_proof_size(17300)) + Weight::from_parts(375_712_961, 0) + .saturating_add(Weight::from_parts(0, 17300)) // Standard Error: 596_297 - .saturating_add(Weight::from_ref_time(738_257_638).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(738_257_638, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(16810).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 16810).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3708,15 +3708,15 @@ impl WeightInfo for () { // Measured: `0 + r * (79300 ±0)` // Estimated: `64844 + r * (942952 ±833)` // Minimum execution time: 374_097 nanoseconds. - Weight::from_ref_time(374_985_000) - .saturating_add(Weight::from_proof_size(64844)) + Weight::from_parts(374_985_000, 0) + .saturating_add(Weight::from_parts(0, 64844)) // Standard Error: 3_772_336 - .saturating_add(Weight::from_ref_time(1_546_402_854).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(1_546_402_854, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((225_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((150_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_proof_size(942952).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 942952).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3734,13 +3734,13 @@ impl WeightInfo for () { // Measured: `869 + r * (240 ±0)` // Estimated: `17215 + r * (1200 ±0)` // Minimum execution time: 374_249 nanoseconds. - Weight::from_ref_time(377_990_998) - .saturating_add(Weight::from_proof_size(17215)) + Weight::from_parts(377_990_998, 0) + .saturating_add(Weight::from_parts(0, 17215)) // Standard Error: 38_133 - .saturating_add(Weight::from_ref_time(11_483_273).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(11_483_273, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(1200).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 1200).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3758,13 +3758,13 @@ impl WeightInfo for () { // Measured: `2102 + r * (3154 ±0)` // Estimated: `21980 + r * (15875 ±2)` // Minimum execution time: 375_552 nanoseconds. - Weight::from_ref_time(400_624_032) - .saturating_add(Weight::from_proof_size(21980)) + Weight::from_parts(400_624_032, 0) + .saturating_add(Weight::from_parts(0, 21980)) // Standard Error: 82_523 - .saturating_add(Weight::from_ref_time(18_057_327).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(18_057_327, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(15875).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 15875).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3784,13 +3784,13 @@ impl WeightInfo for () { // Measured: `872 + r * (240 ±0)` // Estimated: `18598 + r * (1440 ±0)` // Minimum execution time: 373_899 nanoseconds. - Weight::from_ref_time(379_733_943) - .saturating_add(Weight::from_proof_size(18598)) + Weight::from_parts(379_733_943, 0) + .saturating_add(Weight::from_parts(0, 18598)) // Standard Error: 32_022 - .saturating_add(Weight::from_ref_time(9_381_180).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(9_381_180, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) - .saturating_add(Weight::from_proof_size(1440).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 1440).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64const(r: u32, ) -> Weight { @@ -3798,10 +3798,10 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 834 nanoseconds. - Weight::from_ref_time(1_009_646) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_009_646, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 388 - .saturating_add(Weight::from_ref_time(411_979).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(411_979, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64load(r: u32, ) -> Weight { @@ -3809,10 +3809,10 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 882 nanoseconds. - Weight::from_ref_time(1_416_377) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_416_377, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 1_133 - .saturating_add(Weight::from_ref_time(1_075_838).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(1_075_838, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64store(r: u32, ) -> Weight { @@ -3820,10 +3820,10 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 878 nanoseconds. - Weight::from_ref_time(1_343_056) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_343_056, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 426 - .saturating_add(Weight::from_ref_time(1_001_214).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(1_001_214, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_select(r: u32, ) -> Weight { @@ -3831,10 +3831,10 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 796 nanoseconds. - Weight::from_ref_time(1_079_086) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_079_086, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 409 - .saturating_add(Weight::from_ref_time(1_149_188).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(1_149_188, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_if(r: u32, ) -> Weight { @@ -3842,10 +3842,10 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 800 nanoseconds. - Weight::from_ref_time(1_044_184) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_044_184, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 707 - .saturating_add(Weight::from_ref_time(1_315_686).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(1_315_686, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_br(r: u32, ) -> Weight { @@ -3853,10 +3853,10 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 807 nanoseconds. - Weight::from_ref_time(1_049_633) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_049_633, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 361 - .saturating_add(Weight::from_ref_time(640_530).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(640_530, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_br_if(r: u32, ) -> Weight { @@ -3864,10 +3864,10 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 774 nanoseconds. - Weight::from_ref_time(1_124_053) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_124_053, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 784 - .saturating_add(Weight::from_ref_time(949_398).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(949_398, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_br_table(r: u32, ) -> Weight { @@ -3875,10 +3875,10 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 810 nanoseconds. - Weight::from_ref_time(676_581) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(676_581, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 2_356 - .saturating_add(Weight::from_ref_time(1_163_465).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(1_163_465, 0).saturating_mul(r.into())) } /// The range of component `e` is `[1, 256]`. fn instr_br_table_per_entry(e: u32, ) -> Weight { @@ -3886,10 +3886,10 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 2_580 nanoseconds. - Weight::from_ref_time(2_835_656) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(2_835_656, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 71 - .saturating_add(Weight::from_ref_time(4_686).saturating_mul(e.into())) + .saturating_add(Weight::from_parts(4_686, 0).saturating_mul(e.into())) } /// The range of component `r` is `[0, 50]`. fn instr_call(r: u32, ) -> Weight { @@ -3897,10 +3897,10 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 826 nanoseconds. - Weight::from_ref_time(1_625_698) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_625_698, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 1_740 - .saturating_add(Weight::from_ref_time(2_332_187).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(2_332_187, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_call_indirect(r: u32, ) -> Weight { @@ -3908,10 +3908,10 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 901 nanoseconds. - Weight::from_ref_time(2_338_620) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(2_338_620, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 1_642 - .saturating_add(Weight::from_ref_time(2_924_090).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(2_924_090, 0).saturating_mul(r.into())) } /// The range of component `p` is `[0, 128]`. fn instr_call_indirect_per_param(p: u32, ) -> Weight { @@ -3919,10 +3919,10 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 4_670 nanoseconds. - Weight::from_ref_time(5_556_246) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(5_556_246, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 1_491 - .saturating_add(Weight::from_ref_time(228_965).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(228_965, 0).saturating_mul(p.into())) } /// The range of component `l` is `[0, 1024]`. fn instr_call_per_local(l: u32, ) -> Weight { @@ -3930,10 +3930,10 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 3_099 nanoseconds. - Weight::from_ref_time(3_896_177) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(3_896_177, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 99 - .saturating_add(Weight::from_ref_time(91_304).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(91_304, 0).saturating_mul(l.into())) } /// The range of component `r` is `[0, 50]`. fn instr_local_get(r: u32, ) -> Weight { @@ -3941,10 +3941,10 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 3_042 nanoseconds. - Weight::from_ref_time(3_334_621) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(3_334_621, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 793 - .saturating_add(Weight::from_ref_time(459_346).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(459_346, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_local_set(r: u32, ) -> Weight { @@ -3952,10 +3952,10 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 2_968 nanoseconds. - Weight::from_ref_time(3_235_286) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(3_235_286, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 427 - .saturating_add(Weight::from_ref_time(485_454).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(485_454, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_local_tee(r: u32, ) -> Weight { @@ -3963,10 +3963,10 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 3_012 nanoseconds. - Weight::from_ref_time(3_303_555) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(3_303_555, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 371 - .saturating_add(Weight::from_ref_time(657_811).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(657_811, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_global_get(r: u32, ) -> Weight { @@ -3974,10 +3974,10 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 865 nanoseconds. - Weight::from_ref_time(1_249_987) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_249_987, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 417 - .saturating_add(Weight::from_ref_time(896_704).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(896_704, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_global_set(r: u32, ) -> Weight { @@ -3985,10 +3985,10 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 866 nanoseconds. - Weight::from_ref_time(1_216_218) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_216_218, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 503 - .saturating_add(Weight::from_ref_time(919_719).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(919_719, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_memory_current(r: u32, ) -> Weight { @@ -3996,10 +3996,10 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 921 nanoseconds. - Weight::from_ref_time(1_228_408) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_228_408, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 309 - .saturating_add(Weight::from_ref_time(813_007).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(813_007, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 1]`. fn instr_memory_grow(r: u32, ) -> Weight { @@ -4007,10 +4007,10 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 820 nanoseconds. - Weight::from_ref_time(914_830) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(914_830, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 6_018 - .saturating_add(Weight::from_ref_time(237_062_769).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(237_062_769, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64clz(r: u32, ) -> Weight { @@ -4018,10 +4018,10 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 812 nanoseconds. - Weight::from_ref_time(1_554_406) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_554_406, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 9_979 - .saturating_add(Weight::from_ref_time(625_434).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(625_434, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ctz(r: u32, ) -> Weight { @@ -4029,10 +4029,10 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 798 nanoseconds. - Weight::from_ref_time(1_095_113) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_095_113, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 243 - .saturating_add(Weight::from_ref_time(634_204).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(634_204, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64popcnt(r: u32, ) -> Weight { @@ -4040,10 +4040,10 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 792 nanoseconds. - Weight::from_ref_time(1_109_845) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_109_845, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 14_944 - .saturating_add(Weight::from_ref_time(658_834).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(658_834, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64eqz(r: u32, ) -> Weight { @@ -4051,10 +4051,10 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 815 nanoseconds. - Weight::from_ref_time(1_068_916) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_068_916, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 327 - .saturating_add(Weight::from_ref_time(652_897).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(652_897, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendsi32(r: u32, ) -> Weight { @@ -4062,10 +4062,10 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 798 nanoseconds. - Weight::from_ref_time(1_069_745) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_069_745, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 306 - .saturating_add(Weight::from_ref_time(618_481).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(618_481, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendui32(r: u32, ) -> Weight { @@ -4073,10 +4073,10 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 799 nanoseconds. - Weight::from_ref_time(1_398_001) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_398_001, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 6_234 - .saturating_add(Weight::from_ref_time(611_399).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(611_399, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i32wrapi64(r: u32, ) -> Weight { @@ -4084,10 +4084,10 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 811 nanoseconds. - Weight::from_ref_time(1_098_083) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_098_083, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 297 - .saturating_add(Weight::from_ref_time(617_692).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(617_692, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64eq(r: u32, ) -> Weight { @@ -4095,10 +4095,10 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 815 nanoseconds. - Weight::from_ref_time(1_046_922) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_046_922, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 335 - .saturating_add(Weight::from_ref_time(909_196).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(909_196, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ne(r: u32, ) -> Weight { @@ -4106,10 +4106,10 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 805 nanoseconds. - Weight::from_ref_time(1_093_667) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_093_667, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 233 - .saturating_add(Weight::from_ref_time(907_378).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(907_378, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64lts(r: u32, ) -> Weight { @@ -4117,10 +4117,10 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 805 nanoseconds. - Weight::from_ref_time(1_290_591) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_290_591, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 3_201 - .saturating_add(Weight::from_ref_time(902_006).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(902_006, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ltu(r: u32, ) -> Weight { @@ -4128,10 +4128,10 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 783 nanoseconds. - Weight::from_ref_time(1_159_977) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_159_977, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 2_310 - .saturating_add(Weight::from_ref_time(906_489).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(906_489, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64gts(r: u32, ) -> Weight { @@ -4139,10 +4139,10 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 790 nanoseconds. - Weight::from_ref_time(1_109_719) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_109_719, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 261 - .saturating_add(Weight::from_ref_time(906_614).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(906_614, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64gtu(r: u32, ) -> Weight { @@ -4150,10 +4150,10 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 776 nanoseconds. - Weight::from_ref_time(1_076_567) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_076_567, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 348 - .saturating_add(Weight::from_ref_time(919_374).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(919_374, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64les(r: u32, ) -> Weight { @@ -4161,10 +4161,10 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 780 nanoseconds. - Weight::from_ref_time(1_069_663) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_069_663, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 265 - .saturating_add(Weight::from_ref_time(908_037).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(908_037, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64leu(r: u32, ) -> Weight { @@ -4172,10 +4172,10 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 832 nanoseconds. - Weight::from_ref_time(930_920) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(930_920, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 2_170 - .saturating_add(Weight::from_ref_time(929_811).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(929_811, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ges(r: u32, ) -> Weight { @@ -4183,10 +4183,10 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 787 nanoseconds. - Weight::from_ref_time(1_087_325) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_087_325, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 315 - .saturating_add(Weight::from_ref_time(908_321).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(908_321, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64geu(r: u32, ) -> Weight { @@ -4194,10 +4194,10 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 798 nanoseconds. - Weight::from_ref_time(1_029_132) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_029_132, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 2_095 - .saturating_add(Weight::from_ref_time(913_553).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(913_553, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64add(r: u32, ) -> Weight { @@ -4205,10 +4205,10 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 791 nanoseconds. - Weight::from_ref_time(1_086_314) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_086_314, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 197 - .saturating_add(Weight::from_ref_time(896_392).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(896_392, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64sub(r: u32, ) -> Weight { @@ -4216,10 +4216,10 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 793 nanoseconds. - Weight::from_ref_time(1_078_172) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_078_172, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 404 - .saturating_add(Weight::from_ref_time(886_329).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(886_329, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64mul(r: u32, ) -> Weight { @@ -4227,10 +4227,10 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 799 nanoseconds. - Weight::from_ref_time(1_095_010) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_095_010, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 431 - .saturating_add(Weight::from_ref_time(886_513).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(886_513, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64divs(r: u32, ) -> Weight { @@ -4238,10 +4238,10 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 810 nanoseconds. - Weight::from_ref_time(1_114_325) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_114_325, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 452 - .saturating_add(Weight::from_ref_time(1_521_849).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(1_521_849, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64divu(r: u32, ) -> Weight { @@ -4249,10 +4249,10 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 784 nanoseconds. - Weight::from_ref_time(1_123_153) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_123_153, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 475 - .saturating_add(Weight::from_ref_time(1_457_746).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(1_457_746, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64rems(r: u32, ) -> Weight { @@ -4260,10 +4260,10 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 809 nanoseconds. - Weight::from_ref_time(1_145_906) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_145_906, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 718 - .saturating_add(Weight::from_ref_time(1_549_964).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(1_549_964, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64remu(r: u32, ) -> Weight { @@ -4271,10 +4271,10 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 803 nanoseconds. - Weight::from_ref_time(1_110_328) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_110_328, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 627 - .saturating_add(Weight::from_ref_time(1_453_013).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(1_453_013, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64and(r: u32, ) -> Weight { @@ -4282,10 +4282,10 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 786 nanoseconds. - Weight::from_ref_time(1_108_792) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_108_792, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 286 - .saturating_add(Weight::from_ref_time(897_035).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(897_035, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64or(r: u32, ) -> Weight { @@ -4293,10 +4293,10 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 787 nanoseconds. - Weight::from_ref_time(830_000) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(830_000, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 15_995 - .saturating_add(Weight::from_ref_time(963_344).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(963_344, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64xor(r: u32, ) -> Weight { @@ -4304,10 +4304,10 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 773 nanoseconds. - Weight::from_ref_time(1_082_459) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_082_459, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 330 - .saturating_add(Weight::from_ref_time(897_077).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(897_077, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64shl(r: u32, ) -> Weight { @@ -4315,10 +4315,10 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 810 nanoseconds. - Weight::from_ref_time(1_325_815) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_325_815, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 3_352 - .saturating_add(Weight::from_ref_time(899_555).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(899_555, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64shrs(r: u32, ) -> Weight { @@ -4326,10 +4326,10 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 808 nanoseconds. - Weight::from_ref_time(1_085_903) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_085_903, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 430 - .saturating_add(Weight::from_ref_time(903_249).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(903_249, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64shru(r: u32, ) -> Weight { @@ -4337,10 +4337,10 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 792 nanoseconds. - Weight::from_ref_time(1_091_261) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_091_261, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 312 - .saturating_add(Weight::from_ref_time(902_245).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(902_245, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotl(r: u32, ) -> Weight { @@ -4348,10 +4348,10 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 807 nanoseconds. - Weight::from_ref_time(1_121_052) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_121_052, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 506 - .saturating_add(Weight::from_ref_time(902_772).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(902_772, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotr(r: u32, ) -> Weight { @@ -4359,9 +4359,9 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 823 nanoseconds. - Weight::from_ref_time(1_317_597) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(1_317_597, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 6_219 - .saturating_add(Weight::from_ref_time(896_692).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(896_692, 0).saturating_mul(r.into())) } } diff --git a/frame/conviction-voting/src/weights.rs b/frame/conviction-voting/src/weights.rs index a2f992b1f3a29..91c4c013051db 100644 --- a/frame/conviction-voting/src/weights.rs +++ b/frame/conviction-voting/src/weights.rs @@ -144,12 +144,12 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 33_246 nanoseconds. Weight::from_parts(34_560_391, 176657) // Standard Error: 63_925 - .saturating_add(Weight::from_ref_time(34_500_408).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(34_500_408, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_proof_size(110917).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 110917).saturating_mul(r.into())) } /// Storage: ConvictionVoting VotingFor (r:2 w:2) /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) @@ -165,12 +165,12 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 20_508 nanoseconds. Weight::from_parts(21_240_024, 170349) // Standard Error: 37_314 - .saturating_add(Weight::from_ref_time(30_890_875).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(30_890_875, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_proof_size(110917).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 110917).saturating_mul(r.into())) } /// Storage: ConvictionVoting VotingFor (r:1 w:1) /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) @@ -275,12 +275,12 @@ impl WeightInfo for () { // Minimum execution time: 33_246 nanoseconds. Weight::from_parts(34_560_391, 176657) // Standard Error: 63_925 - .saturating_add(Weight::from_ref_time(34_500_408).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(34_500_408, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_proof_size(110917).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 110917).saturating_mul(r.into())) } /// Storage: ConvictionVoting VotingFor (r:2 w:2) /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) @@ -296,12 +296,12 @@ impl WeightInfo for () { // Minimum execution time: 20_508 nanoseconds. Weight::from_parts(21_240_024, 170349) // Standard Error: 37_314 - .saturating_add(Weight::from_ref_time(30_890_875).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(30_890_875, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_proof_size(110917).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 110917).saturating_mul(r.into())) } /// Storage: ConvictionVoting VotingFor (r:1 w:1) /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) diff --git a/frame/democracy/src/weights.rs b/frame/democracy/src/weights.rs index a2cdeead6f400..9241b27bbe1fb 100644 --- a/frame/democracy/src/weights.rs +++ b/frame/democracy/src/weights.rs @@ -198,7 +198,7 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 2_961 nanoseconds. - Weight::from_ref_time(3_139_000) + Weight::from_parts(3_139_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Democracy NextExternal (r:0 w:1) @@ -208,7 +208,7 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 3_040 nanoseconds. - Weight::from_ref_time(3_261_000) + Weight::from_parts(3_261_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Democracy NextExternal (r:1 w:1) @@ -287,11 +287,11 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 7_093 nanoseconds. Weight::from_parts(8_792_955, 998) // Standard Error: 6_630 - .saturating_add(Weight::from_ref_time(3_091_565).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_091_565, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) - .saturating_add(Weight::from_proof_size(2676).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 2676).saturating_mul(r.into())) } /// Storage: Democracy LowestUnbaked (r:1 w:1) /// Proof: Democracy LowestUnbaked (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -313,11 +313,11 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 10_372 nanoseconds. Weight::from_parts(10_961_165, 19318) // Standard Error: 7_284 - .saturating_add(Weight::from_ref_time(3_112_573).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_112_573, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) - .saturating_add(Weight::from_proof_size(2676).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 2676).saturating_mul(r.into())) } /// Storage: Democracy VotingOf (r:3 w:3) /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) @@ -333,12 +333,12 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 36_618 nanoseconds. Weight::from_parts(42_803_184, 22584) // Standard Error: 7_268 - .saturating_add(Weight::from_ref_time(4_537_902).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(4_537_902, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_proof_size(2676).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 2676).saturating_mul(r.into())) } /// Storage: Democracy VotingOf (r:2 w:2) /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) @@ -352,12 +352,12 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 19_758 nanoseconds. Weight::from_parts(21_641_793, 12540) // Standard Error: 6_889 - .saturating_add(Weight::from_ref_time(4_478_884).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(4_478_884, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_proof_size(2676).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 2676).saturating_mul(r.into())) } /// Storage: Democracy PublicProps (r:0 w:1) /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) @@ -366,7 +366,7 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 2_844 nanoseconds. - Weight::from_ref_time(3_017_000) + Weight::from_parts(3_017_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Democracy VotingOf (r:1 w:1) @@ -383,7 +383,7 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 20_380 nanoseconds. Weight::from_parts(28_295_875, 12647) // Standard Error: 2_331 - .saturating_add(Weight::from_ref_time(67_348).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(67_348, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -401,7 +401,7 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 24_475 nanoseconds. Weight::from_parts(27_102_576, 12647) // Standard Error: 1_464 - .saturating_add(Weight::from_ref_time(128_921).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(128_921, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -417,7 +417,7 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 15_039 nanoseconds. Weight::from_parts(19_252_498, 8946) // Standard Error: 1_798 - .saturating_add(Weight::from_ref_time(131_855).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(131_855, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -433,7 +433,7 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 14_837 nanoseconds. Weight::from_parts(19_144_929, 8946) // Standard Error: 1_875 - .saturating_add(Weight::from_ref_time(136_819).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(136_819, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -639,7 +639,7 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 2_961 nanoseconds. - Weight::from_ref_time(3_139_000) + Weight::from_parts(3_139_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Democracy NextExternal (r:0 w:1) @@ -649,7 +649,7 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 3_040 nanoseconds. - Weight::from_ref_time(3_261_000) + Weight::from_parts(3_261_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Democracy NextExternal (r:1 w:1) @@ -728,11 +728,11 @@ impl WeightInfo for () { // Minimum execution time: 7_093 nanoseconds. Weight::from_parts(8_792_955, 998) // Standard Error: 6_630 - .saturating_add(Weight::from_ref_time(3_091_565).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_091_565, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) - .saturating_add(Weight::from_proof_size(2676).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 2676).saturating_mul(r.into())) } /// Storage: Democracy LowestUnbaked (r:1 w:1) /// Proof: Democracy LowestUnbaked (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -754,11 +754,11 @@ impl WeightInfo for () { // Minimum execution time: 10_372 nanoseconds. Weight::from_parts(10_961_165, 19318) // Standard Error: 7_284 - .saturating_add(Weight::from_ref_time(3_112_573).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_112_573, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) - .saturating_add(Weight::from_proof_size(2676).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 2676).saturating_mul(r.into())) } /// Storage: Democracy VotingOf (r:3 w:3) /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) @@ -774,12 +774,12 @@ impl WeightInfo for () { // Minimum execution time: 36_618 nanoseconds. Weight::from_parts(42_803_184, 22584) // Standard Error: 7_268 - .saturating_add(Weight::from_ref_time(4_537_902).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(4_537_902, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_proof_size(2676).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 2676).saturating_mul(r.into())) } /// Storage: Democracy VotingOf (r:2 w:2) /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) @@ -793,12 +793,12 @@ impl WeightInfo for () { // Minimum execution time: 19_758 nanoseconds. Weight::from_parts(21_641_793, 12540) // Standard Error: 6_889 - .saturating_add(Weight::from_ref_time(4_478_884).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(4_478_884, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_proof_size(2676).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 2676).saturating_mul(r.into())) } /// Storage: Democracy PublicProps (r:0 w:1) /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) @@ -807,7 +807,7 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 2_844 nanoseconds. - Weight::from_ref_time(3_017_000) + Weight::from_parts(3_017_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Democracy VotingOf (r:1 w:1) @@ -824,7 +824,7 @@ impl WeightInfo for () { // Minimum execution time: 20_380 nanoseconds. Weight::from_parts(28_295_875, 12647) // Standard Error: 2_331 - .saturating_add(Weight::from_ref_time(67_348).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(67_348, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -842,7 +842,7 @@ impl WeightInfo for () { // Minimum execution time: 24_475 nanoseconds. Weight::from_parts(27_102_576, 12647) // Standard Error: 1_464 - .saturating_add(Weight::from_ref_time(128_921).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(128_921, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -858,7 +858,7 @@ impl WeightInfo for () { // Minimum execution time: 15_039 nanoseconds. Weight::from_parts(19_252_498, 8946) // Standard Error: 1_798 - .saturating_add(Weight::from_ref_time(131_855).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(131_855, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -874,7 +874,7 @@ impl WeightInfo for () { // Minimum execution time: 14_837 nanoseconds. Weight::from_parts(19_144_929, 8946) // Standard Error: 1_875 - .saturating_add(Weight::from_ref_time(136_819).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(136_819, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } diff --git a/frame/election-provider-multi-phase/src/mock.rs b/frame/election-provider-multi-phase/src/mock.rs index 2ceaa6c23b70f..a46aa861ecf86 100644 --- a/frame/election-provider-multi-phase/src/mock.rs +++ b/frame/election-provider-multi-phase/src/mock.rs @@ -363,11 +363,12 @@ impl MinerConfig for Runtime { fn solution_weight(v: u32, t: u32, a: u32, d: u32) -> Weight { match MockWeightInfo::get() { - MockedWeightInfo::Basic => Weight::from_ref_time( + MockedWeightInfo::Basic => Weight::from_parts( (10 as u64).saturating_add((5 as u64).saturating_mul(a as u64)), + 0, ), MockedWeightInfo::Complex => - Weight::from_ref_time((0 * v + 0 * t + 1000 * a + 0 * d) as u64), + Weight::from_parts((0 * v + 0 * t + 1000 * a + 0 * d) as u64, 0), 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 d5d17e26b3051..75bbcfcf9e537 100644 --- a/frame/election-provider-multi-phase/src/signed.rs +++ b/frame/election-provider-multi-phase/src/signed.rs @@ -1254,7 +1254,7 @@ mod tests { #[test] fn cannot_consume_too_much_future_weight() { ExtBuilder::default() - .signed_weight(Weight::from_ref_time(40).set_proof_size(u64::MAX)) + .signed_weight(Weight::from_parts(40, u64::MAX)) .mock_weight_info(MockedWeightInfo::Basic) .build_and_execute(|| { roll_to_signed(); @@ -1268,16 +1268,16 @@ mod tests { raw.solution.unique_targets().len() as u32, ); // default solution will have 5 edges (5 * 5 + 10) - assert_eq!(solution_weight, Weight::from_ref_time(35)); + assert_eq!(solution_weight, Weight::from_parts(35, 0)); assert_eq!(raw.solution.voter_count(), 5); assert_eq!( ::SignedMaxWeight::get(), - Weight::from_ref_time(40).set_proof_size(u64::MAX) + Weight::from_parts(40, u64::MAX) ); assert_ok!(MultiPhase::submit(RuntimeOrigin::signed(99), Box::new(raw.clone()))); - ::set(Weight::from_ref_time(30).set_proof_size(u64::MAX)); + ::set(Weight::from_parts(30, 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 cff1e01d9e0be..3d80f8f4d9315 100644 --- a/frame/election-provider-multi-phase/src/unsigned.rs +++ b/frame/election-provider-multi-phase/src/unsigned.rs @@ -701,345 +701,177 @@ mod max_weight { let w = SolutionOrSnapshotSize { voters: 10, targets: 0 }; MockWeightInfo::set(crate::mock::MockedWeightInfo::Complex); assert_eq!( - Miner::::maximum_voter_for_weight( - 0, - w, - Weight::zero().set_proof_size(u64::MAX) - ), + Miner::::maximum_voter_for_weight(0, w, Weight::from_parts(0, u64::MAX)), 0 ); assert_eq!( - Miner::::maximum_voter_for_weight( - 0, - w, - Weight::from_ref_time(1).set_proof_size(u64::MAX) - ), + Miner::::maximum_voter_for_weight(0, w, Weight::from_parts(1, u64::MAX)), 0 ); assert_eq!( - Miner::::maximum_voter_for_weight( - 0, - w, - Weight::from_ref_time(999).set_proof_size(u64::MAX) - ), + Miner::::maximum_voter_for_weight(0, w, Weight::from_parts(999, u64::MAX)), 0 ); assert_eq!( - Miner::::maximum_voter_for_weight( - 0, - w, - Weight::from_ref_time(1000).set_proof_size(u64::MAX) - ), + Miner::::maximum_voter_for_weight(0, w, Weight::from_parts(1000, u64::MAX)), 1 ); assert_eq!( - Miner::::maximum_voter_for_weight( - 0, - w, - Weight::from_ref_time(1001).set_proof_size(u64::MAX) - ), + Miner::::maximum_voter_for_weight(0, w, Weight::from_parts(1001, u64::MAX)), 1 ); assert_eq!( - Miner::::maximum_voter_for_weight( - 0, - w, - Weight::from_ref_time(1990).set_proof_size(u64::MAX) - ), + Miner::::maximum_voter_for_weight(0, w, Weight::from_parts(1990, u64::MAX)), 1 ); assert_eq!( - Miner::::maximum_voter_for_weight( - 0, - w, - Weight::from_ref_time(1999).set_proof_size(u64::MAX) - ), + Miner::::maximum_voter_for_weight(0, w, Weight::from_parts(1999, u64::MAX)), 1 ); assert_eq!( - Miner::::maximum_voter_for_weight( - 0, - w, - Weight::from_ref_time(2000).set_proof_size(u64::MAX) - ), + Miner::::maximum_voter_for_weight(0, w, Weight::from_parts(2000, u64::MAX)), 2 ); assert_eq!( - Miner::::maximum_voter_for_weight( - 0, - w, - Weight::from_ref_time(2001).set_proof_size(u64::MAX) - ), + Miner::::maximum_voter_for_weight(0, w, Weight::from_parts(2001, u64::MAX)), 2 ); assert_eq!( - Miner::::maximum_voter_for_weight( - 0, - w, - Weight::from_ref_time(2010).set_proof_size(u64::MAX) - ), + Miner::::maximum_voter_for_weight(0, w, Weight::from_parts(2010, u64::MAX)), 2 ); assert_eq!( - Miner::::maximum_voter_for_weight( - 0, - w, - Weight::from_ref_time(2990).set_proof_size(u64::MAX) - ), + Miner::::maximum_voter_for_weight(0, w, Weight::from_parts(2990, u64::MAX)), 2 ); assert_eq!( - Miner::::maximum_voter_for_weight( - 0, - w, - Weight::from_ref_time(2999).set_proof_size(u64::MAX) - ), + Miner::::maximum_voter_for_weight(0, w, Weight::from_parts(2999, u64::MAX)), 2 ); assert_eq!( - Miner::::maximum_voter_for_weight( - 0, - w, - Weight::from_ref_time(3000).set_proof_size(u64::MAX) - ), + Miner::::maximum_voter_for_weight(0, w, Weight::from_parts(3000, u64::MAX)), 3 ); assert_eq!( - Miner::::maximum_voter_for_weight( - 0, - w, - Weight::from_ref_time(3333).set_proof_size(u64::MAX) - ), + Miner::::maximum_voter_for_weight(0, w, Weight::from_parts(3333, u64::MAX)), 3 ); assert_eq!( - Miner::::maximum_voter_for_weight( - 0, - w, - Weight::from_ref_time(5500).set_proof_size(u64::MAX) - ), + Miner::::maximum_voter_for_weight(0, w, Weight::from_parts(5500, u64::MAX)), 5 ); assert_eq!( - Miner::::maximum_voter_for_weight( - 0, - w, - Weight::from_ref_time(7777).set_proof_size(u64::MAX) - ), + Miner::::maximum_voter_for_weight(0, w, Weight::from_parts(7777, u64::MAX)), 7 ); assert_eq!( - Miner::::maximum_voter_for_weight( - 0, - w, - Weight::from_ref_time(9999).set_proof_size(u64::MAX) - ), + Miner::::maximum_voter_for_weight(0, w, Weight::from_parts(9999, u64::MAX)), 9 ); assert_eq!( - Miner::::maximum_voter_for_weight( - 0, - w, - Weight::from_ref_time(10_000).set_proof_size(u64::MAX) - ), + Miner::::maximum_voter_for_weight(0, w, Weight::from_parts(10_000, u64::MAX)), 10 ); assert_eq!( - Miner::::maximum_voter_for_weight( - 0, - w, - Weight::from_ref_time(10_999).set_proof_size(u64::MAX) - ), + Miner::::maximum_voter_for_weight(0, w, Weight::from_parts(10_999, u64::MAX)), 10 ); assert_eq!( - Miner::::maximum_voter_for_weight( - 0, - w, - Weight::from_ref_time(11_000).set_proof_size(u64::MAX) - ), + Miner::::maximum_voter_for_weight(0, w, Weight::from_parts(11_000, u64::MAX)), 10 ); assert_eq!( - Miner::::maximum_voter_for_weight( - 0, - w, - Weight::from_ref_time(22_000).set_proof_size(u64::MAX) - ), + Miner::::maximum_voter_for_weight(0, w, Weight::from_parts(22_000, u64::MAX)), 10 ); let w = SolutionOrSnapshotSize { voters: 1, targets: 0 }; assert_eq!( - Miner::::maximum_voter_for_weight( - 0, - w, - Weight::from_ref_time(0).set_proof_size(u64::MAX) - ), + Miner::::maximum_voter_for_weight(0, w, Weight::from_parts(0, u64::MAX)), 0 ); assert_eq!( - Miner::::maximum_voter_for_weight( - 0, - w, - Weight::from_ref_time(1).set_proof_size(u64::MAX) - ), + Miner::::maximum_voter_for_weight(0, w, Weight::from_parts(1, u64::MAX)), 0 ); assert_eq!( - Miner::::maximum_voter_for_weight( - 0, - w, - Weight::from_ref_time(999).set_proof_size(u64::MAX) - ), + Miner::::maximum_voter_for_weight(0, w, Weight::from_parts(999, u64::MAX)), 0 ); assert_eq!( - Miner::::maximum_voter_for_weight( - 0, - w, - Weight::from_ref_time(1000).set_proof_size(u64::MAX) - ), + Miner::::maximum_voter_for_weight(0, w, Weight::from_parts(1000, u64::MAX)), 1 ); assert_eq!( - Miner::::maximum_voter_for_weight( - 0, - w, - Weight::from_ref_time(1001).set_proof_size(u64::MAX) - ), + Miner::::maximum_voter_for_weight(0, w, Weight::from_parts(1001, u64::MAX)), 1 ); assert_eq!( - Miner::::maximum_voter_for_weight( - 0, - w, - Weight::from_ref_time(1990).set_proof_size(u64::MAX) - ), + Miner::::maximum_voter_for_weight(0, w, Weight::from_parts(1990, u64::MAX)), 1 ); assert_eq!( - Miner::::maximum_voter_for_weight( - 0, - w, - Weight::from_ref_time(1999).set_proof_size(u64::MAX) - ), + Miner::::maximum_voter_for_weight(0, w, Weight::from_parts(1999, u64::MAX)), 1 ); assert_eq!( - Miner::::maximum_voter_for_weight( - 0, - w, - Weight::from_ref_time(2000).set_proof_size(u64::MAX) - ), + Miner::::maximum_voter_for_weight(0, w, Weight::from_parts(2000, u64::MAX)), 1 ); assert_eq!( - Miner::::maximum_voter_for_weight( - 0, - w, - Weight::from_ref_time(2001).set_proof_size(u64::MAX) - ), + Miner::::maximum_voter_for_weight(0, w, Weight::from_parts(2001, u64::MAX)), 1 ); assert_eq!( - Miner::::maximum_voter_for_weight( - 0, - w, - Weight::from_ref_time(2010).set_proof_size(u64::MAX) - ), + Miner::::maximum_voter_for_weight(0, w, Weight::from_parts(2010, u64::MAX)), 1 ); assert_eq!( - Miner::::maximum_voter_for_weight( - 0, - w, - Weight::from_ref_time(3333).set_proof_size(u64::MAX) - ), + Miner::::maximum_voter_for_weight(0, w, Weight::from_parts(3333, u64::MAX)), 1 ); let w = SolutionOrSnapshotSize { voters: 2, targets: 0 }; assert_eq!( - Miner::::maximum_voter_for_weight( - 0, - w, - Weight::from_ref_time(0).set_proof_size(u64::MAX) - ), + Miner::::maximum_voter_for_weight(0, w, Weight::from_parts(0, u64::MAX)), 0 ); assert_eq!( - Miner::::maximum_voter_for_weight( - 0, - w, - Weight::from_ref_time(1).set_proof_size(u64::MAX) - ), + Miner::::maximum_voter_for_weight(0, w, Weight::from_parts(1, u64::MAX)), 0 ); assert_eq!( - Miner::::maximum_voter_for_weight( - 0, - w, - Weight::from_ref_time(999).set_proof_size(u64::MAX) - ), + Miner::::maximum_voter_for_weight(0, w, Weight::from_parts(999, u64::MAX)), 0 ); assert_eq!( - Miner::::maximum_voter_for_weight( - 0, - w, - Weight::from_ref_time(1000).set_proof_size(u64::MAX) - ), + Miner::::maximum_voter_for_weight(0, w, Weight::from_parts(1000, u64::MAX)), 1 ); assert_eq!( - Miner::::maximum_voter_for_weight( - 0, - w, - Weight::from_ref_time(1001).set_proof_size(u64::MAX) - ), + Miner::::maximum_voter_for_weight(0, w, Weight::from_parts(1001, u64::MAX)), 1 ); assert_eq!( - Miner::::maximum_voter_for_weight( - 0, - w, - Weight::from_ref_time(1999).set_proof_size(u64::MAX) - ), + Miner::::maximum_voter_for_weight(0, w, Weight::from_parts(1999, u64::MAX)), 1 ); assert_eq!( - Miner::::maximum_voter_for_weight( - 0, - w, - Weight::from_ref_time(2000).set_proof_size(u64::MAX) - ), + Miner::::maximum_voter_for_weight(0, w, Weight::from_parts(2000, u64::MAX)), 2 ); assert_eq!( - Miner::::maximum_voter_for_weight( - 0, - w, - Weight::from_ref_time(2001).set_proof_size(u64::MAX) - ), + Miner::::maximum_voter_for_weight(0, w, Weight::from_parts(2001, u64::MAX)), 2 ); assert_eq!( - Miner::::maximum_voter_for_weight( - 0, - w, - Weight::from_ref_time(2010).set_proof_size(u64::MAX) - ), + Miner::::maximum_voter_for_weight(0, w, Weight::from_parts(2010, u64::MAX)), 2 ); assert_eq!( - Miner::::maximum_voter_for_weight( - 0, - w, - Weight::from_ref_time(3333).set_proof_size(u64::MAX) - ), + Miner::::maximum_voter_for_weight(0, w, Weight::from_parts(3333, u64::MAX)), 2 ); } @@ -1340,7 +1172,7 @@ mod tests { #[test] fn miner_trims_weight() { ExtBuilder::default() - .miner_weight(Weight::from_ref_time(100).set_proof_size(u64::MAX)) + .miner_weight(Weight::from_parts(100, u64::MAX)) .mock_weight_info(crate::mock::MockedWeightInfo::Basic) .build_and_execute(|| { roll_to_unsigned(); @@ -1354,11 +1186,11 @@ mod tests { raw.solution.unique_targets().len() as u32, ); // default solution will have 5 edges (5 * 5 + 10) - assert_eq!(solution_weight, Weight::from_ref_time(35)); + assert_eq!(solution_weight, Weight::from_parts(35, 0)); assert_eq!(raw.solution.voter_count(), 5); // now reduce the max weight - ::set(Weight::from_ref_time(25).set_proof_size(u64::MAX)); + ::set(Weight::from_parts(25, u64::MAX)); let (raw, witness) = MultiPhase::mine_solution().unwrap(); let solution_weight = ::solution_weight( @@ -1368,7 +1200,7 @@ mod tests { raw.solution.unique_targets().len() as u32, ); // default solution will have 5 edges (5 * 5 + 10) - assert_eq!(solution_weight, Weight::from_ref_time(25)); + assert_eq!(solution_weight, Weight::from_parts(25, 0)); 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 f3ea218e451c5..90be98ece489a 100644 --- a/frame/election-provider-multi-phase/src/weights.rs +++ b/frame/election-provider-multi-phase/src/weights.rs @@ -150,9 +150,9 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 215_168 nanoseconds. - Weight::from_ref_time(219_887_000) + Weight::from_parts(219_887_000, 0) // Standard Error: 1_444 - .saturating_add(Weight::from_ref_time(146_388).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(146_388, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: ElectionProviderMultiPhase SignedSubmissionIndices (r:1 w:1) @@ -182,13 +182,13 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 268_021 nanoseconds. Weight::from_parts(72_491_937, 9540) // Standard Error: 2_910 - .saturating_add(Weight::from_ref_time(303_955).saturating_mul(a.into())) + .saturating_add(Weight::from_parts(303_955, 0).saturating_mul(a.into())) // Standard Error: 4_363 - .saturating_add(Weight::from_ref_time(167_369).saturating_mul(d.into())) + .saturating_add(Weight::from_parts(167_369, 0).saturating_mul(d.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(8_u64)) - .saturating_add(Weight::from_proof_size(6912).saturating_mul(a.into())) - .saturating_add(Weight::from_proof_size(441).saturating_mul(d.into())) + .saturating_add(Weight::from_parts(0, 6912).saturating_mul(a.into())) + .saturating_add(Weight::from_parts(0, 441).saturating_mul(d.into())) } /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) @@ -236,13 +236,13 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 4_425_457 nanoseconds. Weight::from_parts(4_445_889_000, 5222) // Standard Error: 13_250 - .saturating_add(Weight::from_ref_time(48_844).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(48_844, 0).saturating_mul(v.into())) // Standard Error: 39_266 - .saturating_add(Weight::from_ref_time(4_144_034).saturating_mul(a.into())) + .saturating_add(Weight::from_parts(4_144_034, 0).saturating_mul(a.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) - .saturating_add(Weight::from_proof_size(3871).saturating_mul(v.into())) - .saturating_add(Weight::from_proof_size(224).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(0, 3871).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(0, 224).saturating_mul(t.into())) } /// Storage: ElectionProviderMultiPhase Round (r:1 w:0) /// Proof Skipped: ElectionProviderMultiPhase Round (max_values: Some(1), max_size: None, mode: Measured) @@ -263,12 +263,12 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 3_812_071 nanoseconds. Weight::from_parts(3_826_375_000, 2884) // Standard Error: 11_601 - .saturating_add(Weight::from_ref_time(145_309).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(145_309, 0).saturating_mul(v.into())) // Standard Error: 34_378 - .saturating_add(Weight::from_ref_time(3_223_977).saturating_mul(a.into())) + .saturating_add(Weight::from_parts(3_223_977, 0).saturating_mul(a.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) - .saturating_add(Weight::from_proof_size(2212).saturating_mul(v.into())) - .saturating_add(Weight::from_proof_size(128).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(0, 2212).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(0, 128).saturating_mul(t.into())) } } @@ -361,9 +361,9 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 215_168 nanoseconds. - Weight::from_ref_time(219_887_000) + Weight::from_parts(219_887_000, 0) // Standard Error: 1_444 - .saturating_add(Weight::from_ref_time(146_388).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(146_388, 0).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: ElectionProviderMultiPhase SignedSubmissionIndices (r:1 w:1) @@ -393,13 +393,13 @@ impl WeightInfo for () { // Minimum execution time: 268_021 nanoseconds. Weight::from_parts(72_491_937, 9540) // Standard Error: 2_910 - .saturating_add(Weight::from_ref_time(303_955).saturating_mul(a.into())) + .saturating_add(Weight::from_parts(303_955, 0).saturating_mul(a.into())) // Standard Error: 4_363 - .saturating_add(Weight::from_ref_time(167_369).saturating_mul(d.into())) + .saturating_add(Weight::from_parts(167_369, 0).saturating_mul(d.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(8_u64)) - .saturating_add(Weight::from_proof_size(6912).saturating_mul(a.into())) - .saturating_add(Weight::from_proof_size(441).saturating_mul(d.into())) + .saturating_add(Weight::from_parts(0, 6912).saturating_mul(a.into())) + .saturating_add(Weight::from_parts(0, 441).saturating_mul(d.into())) } /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) @@ -447,13 +447,13 @@ impl WeightInfo for () { // Minimum execution time: 4_425_457 nanoseconds. Weight::from_parts(4_445_889_000, 5222) // Standard Error: 13_250 - .saturating_add(Weight::from_ref_time(48_844).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(48_844, 0).saturating_mul(v.into())) // Standard Error: 39_266 - .saturating_add(Weight::from_ref_time(4_144_034).saturating_mul(a.into())) + .saturating_add(Weight::from_parts(4_144_034, 0).saturating_mul(a.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) - .saturating_add(Weight::from_proof_size(3871).saturating_mul(v.into())) - .saturating_add(Weight::from_proof_size(224).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(0, 3871).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(0, 224).saturating_mul(t.into())) } /// Storage: ElectionProviderMultiPhase Round (r:1 w:0) /// Proof Skipped: ElectionProviderMultiPhase Round (max_values: Some(1), max_size: None, mode: Measured) @@ -474,11 +474,11 @@ impl WeightInfo for () { // Minimum execution time: 3_812_071 nanoseconds. Weight::from_parts(3_826_375_000, 2884) // Standard Error: 11_601 - .saturating_add(Weight::from_ref_time(145_309).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(145_309, 0).saturating_mul(v.into())) // Standard Error: 34_378 - .saturating_add(Weight::from_ref_time(3_223_977).saturating_mul(a.into())) + .saturating_add(Weight::from_parts(3_223_977, 0).saturating_mul(a.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) - .saturating_add(Weight::from_proof_size(2212).saturating_mul(v.into())) - .saturating_add(Weight::from_proof_size(128).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(0, 2212).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(0, 128).saturating_mul(t.into())) } } diff --git a/frame/election-provider-support/src/weights.rs b/frame/election-provider-support/src/weights.rs index fd4db1374ac4a..addb6ad8d0306 100644 --- a/frame/election-provider-support/src/weights.rs +++ b/frame/election-provider-support/src/weights.rs @@ -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 u64) + Weight::from_parts(0 as u64, 0) // Standard Error: 667_000 - .saturating_add(Weight::from_ref_time(32_973_000 as u64).saturating_mul(v as u64)) + .saturating_add(Weight::from_parts(32_973_000 as u64, 0).saturating_mul(v as u64)) // Standard Error: 1_334_000 - .saturating_add(Weight::from_ref_time(1_334_000 as u64).saturating_mul(t as u64)) + .saturating_add(Weight::from_parts(1_334_000 as u64, 0).saturating_mul(t as u64)) // Standard Error: 60_644_000 - .saturating_add(Weight::from_ref_time(2_636_364_000 as u64).saturating_mul(d as u64)) + .saturating_add(Weight::from_parts(2_636_364_000 as u64, 0).saturating_mul(d as u64)) } fn phragmms(v: u32, t: u32, d: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) + Weight::from_parts(0 as u64, 0) // Standard Error: 73_000 - .saturating_add(Weight::from_ref_time(21_073_000 as u64).saturating_mul(v as u64)) + .saturating_add(Weight::from_parts(21_073_000 as u64, 0).saturating_mul(v as u64)) // Standard Error: 146_000 - .saturating_add(Weight::from_ref_time(65_000 as u64).saturating_mul(t as u64)) + .saturating_add(Weight::from_parts(65_000 as u64, 0).saturating_mul(t as u64)) // Standard Error: 6_649_000 - .saturating_add(Weight::from_ref_time(1_711_424_000 as u64).saturating_mul(d as u64)) + .saturating_add(Weight::from_parts(1_711_424_000 as u64, 0).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 u64) + Weight::from_parts(0 as u64, 0) // Standard Error: 667_000 - .saturating_add(Weight::from_ref_time(32_973_000 as u64).saturating_mul(v as u64)) + .saturating_add(Weight::from_parts(32_973_000 as u64, 0).saturating_mul(v as u64)) // Standard Error: 1_334_000 - .saturating_add(Weight::from_ref_time(1_334_000 as u64).saturating_mul(t as u64)) + .saturating_add(Weight::from_parts(1_334_000 as u64, 0).saturating_mul(t as u64)) // Standard Error: 60_644_000 - .saturating_add(Weight::from_ref_time(2_636_364_000 as u64).saturating_mul(d as u64)) + .saturating_add(Weight::from_parts(2_636_364_000 as u64, 0).saturating_mul(d as u64)) } fn phragmms(v: u32, t: u32, d: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) + Weight::from_parts(0 as u64, 0) // Standard Error: 73_000 - .saturating_add(Weight::from_ref_time(21_073_000 as u64).saturating_mul(v as u64)) + .saturating_add(Weight::from_parts(21_073_000 as u64, 0).saturating_mul(v as u64)) // Standard Error: 146_000 - .saturating_add(Weight::from_ref_time(65_000 as u64).saturating_mul(t as u64)) + .saturating_add(Weight::from_parts(65_000 as u64, 0).saturating_mul(t as u64)) // Standard Error: 6_649_000 - .saturating_add(Weight::from_ref_time(1_711_424_000 as u64).saturating_mul(d as u64)) + .saturating_add(Weight::from_parts(1_711_424_000 as u64, 0).saturating_mul(d as u64)) } } diff --git a/frame/elections-phragmen/src/weights.rs b/frame/elections-phragmen/src/weights.rs index 24ab3bc15fbcd..bbe66d52981c5 100644 --- a/frame/elections-phragmen/src/weights.rs +++ b/frame/elections-phragmen/src/weights.rs @@ -84,10 +84,10 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 27_362 nanoseconds. Weight::from_parts(28_497_963, 9726) // Standard Error: 3_968 - .saturating_add(Weight::from_ref_time(176_840).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(176_840, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) - .saturating_add(Weight::from_proof_size(320).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(0, 320).saturating_mul(v.into())) } /// Storage: Elections Candidates (r:1 w:0) /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) @@ -107,10 +107,10 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 37_120 nanoseconds. Weight::from_parts(38_455_302, 9598) // Standard Error: 5_478 - .saturating_add(Weight::from_ref_time(219_678).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(219_678, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) - .saturating_add(Weight::from_proof_size(320).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(0, 320).saturating_mul(v.into())) } /// Storage: Elections Candidates (r:1 w:0) /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) @@ -130,10 +130,10 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 36_928 nanoseconds. Weight::from_parts(38_334_669, 9726) // Standard Error: 5_271 - .saturating_add(Weight::from_ref_time(232_355).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(232_355, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) - .saturating_add(Weight::from_proof_size(320).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(0, 320).saturating_mul(v.into())) } /// Storage: Elections Voting (r:1 w:1) /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) @@ -162,10 +162,10 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 31_864 nanoseconds. Weight::from_parts(33_490_161, 6576) // Standard Error: 2_643 - .saturating_add(Weight::from_ref_time(158_386).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(158_386, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) - .saturating_add(Weight::from_proof_size(144).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(0, 144).saturating_mul(c.into())) } /// Storage: Elections Candidates (r:1 w:1) /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) @@ -177,10 +177,10 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 27_292 nanoseconds. Weight::from_parts(28_364_955, 844) // Standard Error: 1_335 - .saturating_add(Weight::from_ref_time(78_086).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(78_086, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) - .saturating_add(Weight::from_proof_size(48).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(0, 48).saturating_mul(c.into())) } /// Storage: Elections Members (r:1 w:1) /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) @@ -219,7 +219,7 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 2_000_000_000 nanoseconds. - Weight::from_ref_time(2_000_000_000_000) + Weight::from_parts(2_000_000_000_000, 0) } /// Storage: Elections Members (r:1 w:1) /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) @@ -263,11 +263,11 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 14_934_185 nanoseconds. Weight::from_parts(15_014_057_000, 8448) // Standard Error: 245_588 - .saturating_add(Weight::from_ref_time(35_586_946).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(35_586_946, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(v.into()))) - .saturating_add(Weight::from_proof_size(12352).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(0, 12352).saturating_mul(v.into())) } /// Storage: Elections Candidates (r:1 w:1) /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) @@ -297,17 +297,17 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 1_273_671 nanoseconds. Weight::from_parts(1_279_716_000, 330033) // Standard Error: 543_277 - .saturating_add(Weight::from_ref_time(20_613_753).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(20_613_753, 0).saturating_mul(v.into())) // Standard Error: 34_857 - .saturating_add(Weight::from_ref_time(688_354).saturating_mul(e.into())) + .saturating_add(Weight::from_parts(688_354, 0).saturating_mul(e.into())) .saturating_add(T::DbWeight::get().reads(21_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(c.into()))) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().writes(6_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(c.into()))) - .saturating_add(Weight::from_proof_size(5229).saturating_mul(v.into())) - .saturating_add(Weight::from_proof_size(89).saturating_mul(e.into())) - .saturating_add(Weight::from_proof_size(2135).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(0, 5229).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(0, 89).saturating_mul(e.into())) + .saturating_add(Weight::from_parts(0, 2135).saturating_mul(c.into())) } } @@ -331,10 +331,10 @@ impl WeightInfo for () { // Minimum execution time: 27_362 nanoseconds. Weight::from_parts(28_497_963, 9726) // Standard Error: 3_968 - .saturating_add(Weight::from_ref_time(176_840).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(176_840, 0).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) - .saturating_add(Weight::from_proof_size(320).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(0, 320).saturating_mul(v.into())) } /// Storage: Elections Candidates (r:1 w:0) /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) @@ -354,10 +354,10 @@ impl WeightInfo for () { // Minimum execution time: 37_120 nanoseconds. Weight::from_parts(38_455_302, 9598) // Standard Error: 5_478 - .saturating_add(Weight::from_ref_time(219_678).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(219_678, 0).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) - .saturating_add(Weight::from_proof_size(320).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(0, 320).saturating_mul(v.into())) } /// Storage: Elections Candidates (r:1 w:0) /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) @@ -377,10 +377,10 @@ impl WeightInfo for () { // Minimum execution time: 36_928 nanoseconds. Weight::from_parts(38_334_669, 9726) // Standard Error: 5_271 - .saturating_add(Weight::from_ref_time(232_355).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(232_355, 0).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) - .saturating_add(Weight::from_proof_size(320).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(0, 320).saturating_mul(v.into())) } /// Storage: Elections Voting (r:1 w:1) /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) @@ -409,10 +409,10 @@ impl WeightInfo for () { // Minimum execution time: 31_864 nanoseconds. Weight::from_parts(33_490_161, 6576) // Standard Error: 2_643 - .saturating_add(Weight::from_ref_time(158_386).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(158_386, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) - .saturating_add(Weight::from_proof_size(144).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(0, 144).saturating_mul(c.into())) } /// Storage: Elections Candidates (r:1 w:1) /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) @@ -424,10 +424,10 @@ impl WeightInfo for () { // Minimum execution time: 27_292 nanoseconds. Weight::from_parts(28_364_955, 844) // Standard Error: 1_335 - .saturating_add(Weight::from_ref_time(78_086).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(78_086, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) - .saturating_add(Weight::from_proof_size(48).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(0, 48).saturating_mul(c.into())) } /// Storage: Elections Members (r:1 w:1) /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) @@ -466,7 +466,7 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 2_000_000_000 nanoseconds. - Weight::from_ref_time(2_000_000_000_000) + Weight::from_parts(2_000_000_000_000, 0) } /// Storage: Elections Members (r:1 w:1) /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) @@ -510,11 +510,11 @@ impl WeightInfo for () { // Minimum execution time: 14_934_185 nanoseconds. Weight::from_parts(15_014_057_000, 8448) // Standard Error: 245_588 - .saturating_add(Weight::from_ref_time(35_586_946).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(35_586_946, 0).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(v.into()))) .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(v.into()))) - .saturating_add(Weight::from_proof_size(12352).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(0, 12352).saturating_mul(v.into())) } /// Storage: Elections Candidates (r:1 w:1) /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) @@ -544,16 +544,16 @@ impl WeightInfo for () { // Minimum execution time: 1_273_671 nanoseconds. Weight::from_parts(1_279_716_000, 330033) // Standard Error: 543_277 - .saturating_add(Weight::from_ref_time(20_613_753).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(20_613_753, 0).saturating_mul(v.into())) // Standard Error: 34_857 - .saturating_add(Weight::from_ref_time(688_354).saturating_mul(e.into())) + .saturating_add(Weight::from_parts(688_354, 0).saturating_mul(e.into())) .saturating_add(RocksDbWeight::get().reads(21_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(c.into()))) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(v.into()))) .saturating_add(RocksDbWeight::get().writes(6_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(c.into()))) - .saturating_add(Weight::from_proof_size(5229).saturating_mul(v.into())) - .saturating_add(Weight::from_proof_size(89).saturating_mul(e.into())) - .saturating_add(Weight::from_proof_size(2135).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(0, 5229).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(0, 89).saturating_mul(e.into())) + .saturating_add(Weight::from_parts(0, 2135).saturating_mul(c.into())) } } diff --git a/frame/examples/basic/src/lib.rs b/frame/examples/basic/src/lib.rs index a2b55bff1654e..a75a0e17cceba 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); - Weight::from_ref_time((cents * multiplier).saturated_into::()) + Weight::from_parts((cents * multiplier).saturated_into::(), 0) } } diff --git a/frame/examples/basic/src/weights.rs b/frame/examples/basic/src/weights.rs index 4ea1e01d74bb0..def944054cce8 100644 --- a/frame/examples/basic/src/weights.rs +++ b/frame/examples/basic/src/weights.rs @@ -56,20 +56,20 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: BasicExample Dummy (r:0 w:1) fn set_dummy_benchmark() -> Weight { - Weight::from_ref_time(19_000_000 as u64) + Weight::from_parts(19_000_000 as u64, 0) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: BasicExample Dummy (r:1 w:1) fn accumulate_dummy() -> Weight { - Weight::from_ref_time(18_000_000 as u64) + Weight::from_parts(18_000_000 as u64, 0) .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(0 as u64) + Weight::from_parts(0 as u64, 0) // Standard Error: 2 - .saturating_add(Weight::from_ref_time(520 as u64).saturating_mul(x as u64)) + .saturating_add(Weight::from_parts(520 as u64, 0).saturating_mul(x as u64)) } } @@ -77,19 +77,19 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: BasicExample Dummy (r:0 w:1) fn set_dummy_benchmark() -> Weight { - Weight::from_ref_time(19_000_000 as u64) + Weight::from_parts(19_000_000 as u64, 0) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: BasicExample Dummy (r:1 w:1) fn accumulate_dummy() -> Weight { - Weight::from_ref_time(18_000_000 as u64) + Weight::from_parts(18_000_000 as u64, 0) .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(0 as u64) + Weight::from_parts(0 as u64, 0) // Standard Error: 2 - .saturating_add(Weight::from_ref_time(520 as u64).saturating_mul(x as u64)) + .saturating_add(Weight::from_parts(520 as u64, 0).saturating_mul(x as u64)) } } diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index 573332294cb7f..05f3ee4f53588 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -718,12 +718,12 @@ mod tests { // one with block number arg and one without fn on_initialize(n: T::BlockNumber) -> Weight { println!("on_initialize({})", n); - Weight::from_ref_time(175) + Weight::from_parts(175, 0) } fn on_idle(n: T::BlockNumber, remaining_weight: Weight) -> Weight { println!("on_idle{}, {})", n, remaining_weight); - Weight::from_ref_time(175) + Weight::from_parts(175, 0) } fn on_finalize(n: T::BlockNumber) { @@ -732,7 +732,7 @@ mod tests { fn on_runtime_upgrade() -> Weight { sp_io::storage::set(super::TEST_KEY, "module".as_bytes()); - Weight::from_ref_time(200) + Weight::from_parts(200, 0) } fn offchain_worker(n: T::BlockNumber) { @@ -853,9 +853,9 @@ mod tests { parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = 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).set_proof_size(u64::MAX).into()) + .base_block(Weight::from_parts(10, 0)) + .for_class(DispatchClass::all(), |weights| weights.base_extrinsic = Weight::from_parts(5, 0)) + .for_class(DispatchClass::non_mandatory(), |weights| weights.max_total = Weight::from_parts(1024, u64::MAX).into()) .build_or_panic(); pub const DbWeight: RuntimeDbWeight = RuntimeDbWeight { read: 10, @@ -946,7 +946,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); - Weight::from_ref_time(100) + Weight::from_parts(100, 0) } } @@ -1124,7 +1124,7 @@ mod tests { let encoded_len = encoded.len() as u64; // on_initialize weight + base block execution weight let block_weights = ::BlockWeights::get(); - let base_block_weight = Weight::from_ref_time(175) + block_weights.base_block; + let base_block_weight = Weight::from_parts(175, 0) + block_weights.base_block; let limit = block_weights.get(DispatchClass::Normal).max_total.unwrap() - base_block_weight; let num_to_exhaust_block = limit.ref_time() / (encoded_len + 5); t.execute_with(|| { @@ -1149,7 +1149,7 @@ mod tests { assert_eq!( >::block_weight().total(), //--------------------- on_initialize + block_execution + extrinsic_base weight - Weight::from_ref_time((encoded_len + 5) * (nonce + 1)) + base_block_weight, + Weight::from_parts((encoded_len + 5) * (nonce + 1), 0) + base_block_weight, ); assert_eq!( >::extrinsic_index(), @@ -1180,7 +1180,7 @@ 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 = Weight::from_ref_time(175) + + let base_block_weight = Weight::from_parts(175, 0) + ::BlockWeights::get().base_block; Executive::initialize_block(&Header::new( @@ -1199,7 +1199,7 @@ mod tests { assert!(Executive::apply_extrinsic(x2.clone()).unwrap().is_ok()); // default weight for `TestXt` == encoded length. - let extrinsic_weight = Weight::from_ref_time(len as u64) + + let extrinsic_weight = Weight::from_parts(len as u64, 0) + ::BlockWeights::get() .get(DispatchClass::Normal) .base_extrinsic; @@ -1315,7 +1315,7 @@ mod tests { // the `on_initialize` weight defined in the custom test module. assert_eq!( >::block_weight().total(), - Weight::from_ref_time(175 + 175 + 10) + Weight::from_parts(175 + 175 + 10, 0) ); }) } diff --git a/frame/fast-unstake/src/lib.rs b/frame/fast-unstake/src/lib.rs index 81eb3087b998e..3e79bf4077d20 100644 --- a/frame/fast-unstake/src/lib.rs +++ b/frame/fast-unstake/src/lib.rs @@ -208,7 +208,7 @@ pub mod pallet { 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) + return Weight::from_parts(0, 0) } Self::do_on_idle(remaining_weight) @@ -356,7 +356,7 @@ pub mod pallet { /// checked, we don't finish the process. pub(crate) fn do_on_idle(remaining_weight: Weight) -> Weight { // any weight that is unaccounted for - let mut unaccounted_weight = Weight::from_ref_time(0); + let mut unaccounted_weight = Weight::from_parts(0, 0); let eras_to_check_per_block = ErasToCheckPerBlock::::get(); if eras_to_check_per_block.is_zero() { diff --git a/frame/fast-unstake/src/tests.rs b/frame/fast-unstake/src/tests.rs index 1bb6fc100c94c..b4bf1f1cb994a 100644 --- a/frame/fast-unstake/src/tests.rs +++ b/frame/fast-unstake/src/tests.rs @@ -228,7 +228,7 @@ mod on_idle { 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)); + FastUnstake::on_idle(System::block_number(), Weight::from_parts(0, 0)); // assert nothing changed in Queue and Head assert_eq!(Head::::get(), None); @@ -1091,8 +1091,9 @@ mod batched { #[test] fn kusama_estimate() { use crate::WeightInfo; - let block_time = frame_support::weights::Weight::from_ref_time( + let block_time = frame_support::weights::Weight::from_parts( frame_support::weights::constants::WEIGHT_REF_TIME_PER_SECOND * 2, + 0, ) .ref_time() as f32; let on_idle = crate::weights::SubstrateWeight::::on_idle_check(1000, 64).ref_time() as f32; @@ -1102,8 +1103,9 @@ fn kusama_estimate() { #[test] fn polkadot_estimate() { use crate::WeightInfo; - let block_time = frame_support::weights::Weight::from_ref_time( + let block_time = frame_support::weights::Weight::from_parts( frame_support::weights::constants::WEIGHT_REF_TIME_PER_SECOND * 2, + 0, ) .ref_time() as f32; let on_idle = crate::weights::SubstrateWeight::::on_idle_check(300, 64).ref_time() as f32; diff --git a/frame/fast-unstake/src/weights.rs b/frame/fast-unstake/src/weights.rs index d1c6595964ee0..ced7acb951229 100644 --- a/frame/fast-unstake/src/weights.rs +++ b/frame/fast-unstake/src/weights.rs @@ -75,9 +75,9 @@ impl WeightInfo for SubstrateWeight { /// The range of component `b` is `[1, 64]`. fn on_idle_unstake(b: u32, ) -> Weight { // Minimum execution time: 92_833 nanoseconds. - Weight::from_ref_time(62_136_346) + Weight::from_parts(62_136_346, 0) // Standard Error: 25_541 - .saturating_add(Weight::from_ref_time(42_904_859).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(42_904_859, 0).saturating_mul(b.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().reads((6_u64).saturating_mul(b.into()))) .saturating_add(T::DbWeight::get().writes(1)) @@ -94,11 +94,11 @@ impl WeightInfo for SubstrateWeight { /// The range of component `b` is `[1, 64]`. fn on_idle_check(v: u32, b: u32, ) -> Weight { // Minimum execution time: 1_775_293 nanoseconds. - Weight::from_ref_time(1_787_133_000) + Weight::from_parts(1_787_133_000, 0) // Standard Error: 17_109_142 - .saturating_add(Weight::from_ref_time(546_766_552).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(546_766_552, 0).saturating_mul(v.into())) // Standard Error: 68_455_625 - .saturating_add(Weight::from_ref_time(2_135_980_830).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(2_135_980_830, 0).saturating_mul(b.into())) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().writes(1)) @@ -119,7 +119,7 @@ impl WeightInfo for SubstrateWeight { // Storage: FastUnstake CounterForQueue (r:1 w:1) fn register_fast_unstake() -> Weight { // Minimum execution time: 124_849 nanoseconds. - Weight::from_ref_time(128_176_000) + Weight::from_parts(128_176_000, 0) .saturating_add(T::DbWeight::get().reads(14)) .saturating_add(T::DbWeight::get().writes(9)) } @@ -130,14 +130,14 @@ impl WeightInfo for SubstrateWeight { // Storage: FastUnstake CounterForQueue (r:1 w:1) fn deregister() -> Weight { // Minimum execution time: 48_246 nanoseconds. - Weight::from_ref_time(49_720_000) + Weight::from_parts(49_720_000, 0) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } // Storage: FastUnstake ErasToCheckPerBlock (r:0 w:1) fn control() -> Weight { // Minimum execution time: 4_611 nanoseconds. - Weight::from_ref_time(4_844_000) + Weight::from_parts(4_844_000, 0) .saturating_add(T::DbWeight::get().writes(1)) } } @@ -161,9 +161,9 @@ impl WeightInfo for () { /// The range of component `b` is `[1, 64]`. fn on_idle_unstake(b: u32, ) -> Weight { // Minimum execution time: 92_833 nanoseconds. - Weight::from_ref_time(62_136_346) + Weight::from_parts(62_136_346, 0) // Standard Error: 25_541 - .saturating_add(Weight::from_ref_time(42_904_859).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(42_904_859, 0).saturating_mul(b.into())) .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().reads((6_u64).saturating_mul(b.into()))) .saturating_add(RocksDbWeight::get().writes(1)) @@ -180,11 +180,11 @@ impl WeightInfo for () { /// The range of component `b` is `[1, 64]`. fn on_idle_check(v: u32, b: u32, ) -> Weight { // Minimum execution time: 1_775_293 nanoseconds. - Weight::from_ref_time(1_787_133_000) + Weight::from_parts(1_787_133_000, 0) // Standard Error: 17_109_142 - .saturating_add(Weight::from_ref_time(546_766_552).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(546_766_552, 0).saturating_mul(v.into())) // Standard Error: 68_455_625 - .saturating_add(Weight::from_ref_time(2_135_980_830).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(2_135_980_830, 0).saturating_mul(b.into())) .saturating_add(RocksDbWeight::get().reads(7)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(v.into()))) .saturating_add(RocksDbWeight::get().writes(1)) @@ -205,7 +205,7 @@ impl WeightInfo for () { // Storage: FastUnstake CounterForQueue (r:1 w:1) fn register_fast_unstake() -> Weight { // Minimum execution time: 124_849 nanoseconds. - Weight::from_ref_time(128_176_000) + Weight::from_parts(128_176_000, 0) .saturating_add(RocksDbWeight::get().reads(14)) .saturating_add(RocksDbWeight::get().writes(9)) } @@ -216,14 +216,14 @@ impl WeightInfo for () { // Storage: FastUnstake CounterForQueue (r:1 w:1) fn deregister() -> Weight { // Minimum execution time: 48_246 nanoseconds. - Weight::from_ref_time(49_720_000) + Weight::from_parts(49_720_000, 0) .saturating_add(RocksDbWeight::get().reads(5)) .saturating_add(RocksDbWeight::get().writes(2)) } // Storage: FastUnstake ErasToCheckPerBlock (r:0 w:1) fn control() -> Weight { // Minimum execution time: 4_611 nanoseconds. - Weight::from_ref_time(4_844_000) + Weight::from_parts(4_844_000, 0) .saturating_add(RocksDbWeight::get().writes(1)) } } diff --git a/frame/glutton/src/tests.rs b/frame/glutton/src/tests.rs index 8d2c86ed45471..d75f2da5cb7ee 100644 --- a/frame/glutton/src/tests.rs +++ b/frame/glutton/src/tests.rs @@ -133,7 +133,7 @@ fn on_idle_works() { assert_ok!(Glutton::set_compute(RuntimeOrigin::root(), Perbill::from_percent(100))); assert_ok!(Glutton::set_storage(RuntimeOrigin::root(), Perbill::from_percent(100))); - Glutton::on_idle(1, Weight::from_ref_time(20_000_000)); + Glutton::on_idle(1, Weight::from_parts(20_000_000, 0)); }); } diff --git a/frame/glutton/src/weights.rs b/frame/glutton/src/weights.rs index 9c8e161c825f2..1a7020c17a9ab 100644 --- a/frame/glutton/src/weights.rs +++ b/frame/glutton/src/weights.rs @@ -73,10 +73,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `4` // Estimated: `1489` // Minimum execution time: 10_218 nanoseconds. - Weight::from_ref_time(10_510_000) - .saturating_add(Weight::from_proof_size(1489)) + Weight::from_parts(10_510_000, 0) + .saturating_add(Weight::from_parts(0, 1489)) // Standard Error: 1_582 - .saturating_add(Weight::from_ref_time(1_577_660).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(1_577_660, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) @@ -91,10 +91,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `65` // Estimated: `1489` // Minimum execution time: 10_993 nanoseconds. - Weight::from_ref_time(11_208_000) - .saturating_add(Weight::from_proof_size(1489)) + Weight::from_parts(11_208_000, 0) + .saturating_add(Weight::from_parts(0, 1489)) // Standard Error: 1_386 - .saturating_add(Weight::from_ref_time(1_072_330).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(1_072_330, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) @@ -105,10 +105,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 740 nanoseconds. - Weight::from_ref_time(770_000) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(770_000, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 24 - .saturating_add(Weight::from_ref_time(96_434).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(96_434, 0).saturating_mul(i.into())) } /// Storage: Glutton TrashData (r:5000 w:0) /// Proof: Glutton TrashData (max_values: Some(65000), max_size: Some(1036), added: 3016, mode: MaxEncodedLen) @@ -118,12 +118,12 @@ impl WeightInfo for SubstrateWeight { // Measured: `119036 + i * (1053 ±0)` // Estimated: `990 + i * (3016 ±0)` // Minimum execution time: 630 nanoseconds. - Weight::from_ref_time(712_000) - .saturating_add(Weight::from_proof_size(990)) + Weight::from_parts(712_000, 0) + .saturating_add(Weight::from_parts(0, 990)) // Standard Error: 4_326 - .saturating_add(Weight::from_ref_time(5_500_880).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(5_500_880, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(i.into()))) - .saturating_add(Weight::from_proof_size(3016).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(0, 3016).saturating_mul(i.into())) } /// Storage: Glutton Storage (r:1 w:0) /// Proof: Glutton Storage (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -136,8 +136,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `1954313` // Estimated: `5242760` // Minimum execution time: 56_743_236 nanoseconds. - Weight::from_ref_time(57_088_040_000) - .saturating_add(Weight::from_proof_size(5242760)) + Weight::from_parts(57_088_040_000, 0) + .saturating_add(Weight::from_parts(0, 5242760)) .saturating_add(T::DbWeight::get().reads(1739_u64)) } /// Storage: Glutton Storage (r:1 w:0) @@ -151,8 +151,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `9671` // Estimated: `19048` // Minimum execution time: 100_387_042 nanoseconds. - Weight::from_ref_time(100_987_577_000) - .saturating_add(Weight::from_proof_size(19048)) + Weight::from_parts(100_987_577_000, 0) + .saturating_add(Weight::from_parts(0, 19048)) .saturating_add(T::DbWeight::get().reads(7_u64)) } /// Storage: Glutton Storage (r:1 w:0) @@ -164,8 +164,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `4` // Estimated: `2978` // Minimum execution time: 4_256 nanoseconds. - Weight::from_ref_time(4_447_000) - .saturating_add(Weight::from_proof_size(2978)) + Weight::from_parts(4_447_000, 0) + .saturating_add(Weight::from_parts(0, 2978)) .saturating_add(T::DbWeight::get().reads(2_u64)) } /// Storage: Glutton Compute (r:0 w:1) @@ -175,8 +175,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 8_663 nanoseconds. - Weight::from_ref_time(8_864_000) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(8_864_000, 0) + .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Glutton Storage (r:0 w:1) @@ -186,8 +186,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 8_653 nanoseconds. - Weight::from_ref_time(8_998_000) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(8_998_000, 0) + .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1_u64)) } } @@ -204,10 +204,10 @@ impl WeightInfo for () { // Measured: `4` // Estimated: `1489` // Minimum execution time: 10_218 nanoseconds. - Weight::from_ref_time(10_510_000) - .saturating_add(Weight::from_proof_size(1489)) + Weight::from_parts(10_510_000, 0) + .saturating_add(Weight::from_parts(0, 1489)) // Standard Error: 1_582 - .saturating_add(Weight::from_ref_time(1_577_660).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(1_577_660, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) @@ -222,10 +222,10 @@ impl WeightInfo for () { // Measured: `65` // Estimated: `1489` // Minimum execution time: 10_993 nanoseconds. - Weight::from_ref_time(11_208_000) - .saturating_add(Weight::from_proof_size(1489)) + Weight::from_parts(11_208_000, 0) + .saturating_add(Weight::from_parts(0, 1489)) // Standard Error: 1_386 - .saturating_add(Weight::from_ref_time(1_072_330).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(1_072_330, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) @@ -236,10 +236,10 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 740 nanoseconds. - Weight::from_ref_time(770_000) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(770_000, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 24 - .saturating_add(Weight::from_ref_time(96_434).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(96_434, 0).saturating_mul(i.into())) } /// Storage: Glutton TrashData (r:5000 w:0) /// Proof: Glutton TrashData (max_values: Some(65000), max_size: Some(1036), added: 3016, mode: MaxEncodedLen) @@ -249,12 +249,12 @@ impl WeightInfo for () { // Measured: `119036 + i * (1053 ±0)` // Estimated: `990 + i * (3016 ±0)` // Minimum execution time: 630 nanoseconds. - Weight::from_ref_time(712_000) - .saturating_add(Weight::from_proof_size(990)) + Weight::from_parts(712_000, 0) + .saturating_add(Weight::from_parts(0, 990)) // Standard Error: 4_326 - .saturating_add(Weight::from_ref_time(5_500_880).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(5_500_880, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(i.into()))) - .saturating_add(Weight::from_proof_size(3016).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(0, 3016).saturating_mul(i.into())) } /// Storage: Glutton Storage (r:1 w:0) /// Proof: Glutton Storage (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -267,8 +267,8 @@ impl WeightInfo for () { // Measured: `1954313` // Estimated: `5242760` // Minimum execution time: 56_743_236 nanoseconds. - Weight::from_ref_time(57_088_040_000) - .saturating_add(Weight::from_proof_size(5242760)) + Weight::from_parts(57_088_040_000, 0) + .saturating_add(Weight::from_parts(0, 5242760)) .saturating_add(RocksDbWeight::get().reads(1739_u64)) } /// Storage: Glutton Storage (r:1 w:0) @@ -282,8 +282,8 @@ impl WeightInfo for () { // Measured: `9671` // Estimated: `19048` // Minimum execution time: 100_387_042 nanoseconds. - Weight::from_ref_time(100_987_577_000) - .saturating_add(Weight::from_proof_size(19048)) + Weight::from_parts(100_987_577_000, 0) + .saturating_add(Weight::from_parts(0, 19048)) .saturating_add(RocksDbWeight::get().reads(7_u64)) } /// Storage: Glutton Storage (r:1 w:0) @@ -295,8 +295,8 @@ impl WeightInfo for () { // Measured: `4` // Estimated: `2978` // Minimum execution time: 4_256 nanoseconds. - Weight::from_ref_time(4_447_000) - .saturating_add(Weight::from_proof_size(2978)) + Weight::from_parts(4_447_000, 0) + .saturating_add(Weight::from_parts(0, 2978)) .saturating_add(RocksDbWeight::get().reads(2_u64)) } /// Storage: Glutton Compute (r:0 w:1) @@ -306,8 +306,8 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 8_663 nanoseconds. - Weight::from_ref_time(8_864_000) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(8_864_000, 0) + .saturating_add(Weight::from_parts(0, 0)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Glutton Storage (r:0 w:1) @@ -317,8 +317,8 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 8_653 nanoseconds. - Weight::from_ref_time(8_998_000) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(8_998_000, 0) + .saturating_add(Weight::from_parts(0, 0)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } } diff --git a/frame/grandpa/src/default_weights.rs b/frame/grandpa/src/default_weights.rs index 6b203783e2fd9..3afd714f47e57 100644 --- a/frame/grandpa/src/default_weights.rs +++ b/frame/grandpa/src/default_weights.rs @@ -34,18 +34,19 @@ impl crate::WeightInfo for () { const MAX_NOMINATORS: u64 = 200; // checking membership proof - Weight::from_ref_time(35u64 * WEIGHT_REF_TIME_PER_MICROS) + Weight::from_parts(35u64 * WEIGHT_REF_TIME_PER_MICROS, 0) .saturating_add( - Weight::from_ref_time(175u64 * WEIGHT_REF_TIME_PER_NANOS) + Weight::from_parts(175u64 * WEIGHT_REF_TIME_PER_NANOS, 0) .saturating_mul(validator_count), ) .saturating_add(DbWeight::get().reads(5)) // check equivocation proof - .saturating_add(Weight::from_ref_time(95u64 * WEIGHT_REF_TIME_PER_MICROS)) + .saturating_add(Weight::from_parts(95u64 * WEIGHT_REF_TIME_PER_MICROS, 0)) // report offence - .saturating_add(Weight::from_ref_time(110u64 * WEIGHT_REF_TIME_PER_MICROS)) - .saturating_add(Weight::from_ref_time( + .saturating_add(Weight::from_parts(110u64 * WEIGHT_REF_TIME_PER_MICROS, 0)) + .saturating_add(Weight::from_parts( 25u64 * WEIGHT_REF_TIME_PER_MICROS * MAX_NOMINATORS, + 0, )) .saturating_add(DbWeight::get().reads(14 + 3 * MAX_NOMINATORS)) .saturating_add(DbWeight::get().writes(10 + 3 * MAX_NOMINATORS)) @@ -54,7 +55,7 @@ impl crate::WeightInfo for () { } fn note_stalled() -> Weight { - Weight::from_ref_time(3u64 * WEIGHT_REF_TIME_PER_MICROS) + Weight::from_parts(3u64 * WEIGHT_REF_TIME_PER_MICROS, 0) .saturating_add(DbWeight::get().writes(1)) } } diff --git a/frame/identity/src/weights.rs b/frame/identity/src/weights.rs index 6475880528534..65fe2b17ba527 100644 --- a/frame/identity/src/weights.rs +++ b/frame/identity/src/weights.rs @@ -79,7 +79,7 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 10_964 nanoseconds. Weight::from_parts(11_800_935, 1636) // Standard Error: 1_334 - .saturating_add(Weight::from_ref_time(96_038).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(96_038, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -94,9 +94,9 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 26_400 nanoseconds. Weight::from_parts(26_060_549, 10013) // Standard Error: 1_561 - .saturating_add(Weight::from_ref_time(72_083).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(72_083, 0).saturating_mul(r.into())) // Standard Error: 304 - .saturating_add(Weight::from_ref_time(306_994).saturating_mul(x.into())) + .saturating_add(Weight::from_parts(306_994, 0).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -114,12 +114,12 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 8_492 nanoseconds. Weight::from_parts(21_645_924, 15746) // Standard Error: 3_452 - .saturating_add(Weight::from_ref_time(2_442_604).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(2_442_604, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(s.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) - .saturating_add(Weight::from_proof_size(2589).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(0, 2589).saturating_mul(s.into())) } /// Storage: Identity IdentityOf (r:1 w:0) /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) @@ -135,7 +135,7 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 8_488 nanoseconds. Weight::from_parts(20_202_601, 15746) // Standard Error: 2_834 - .saturating_add(Weight::from_ref_time(1_082_941).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(1_082_941, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(p.into()))) @@ -156,11 +156,11 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 41_319 nanoseconds. Weight::from_parts(25_850_055, 15746) // Standard Error: 4_144 - .saturating_add(Weight::from_ref_time(59_619).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(59_619, 0).saturating_mul(r.into())) // Standard Error: 809 - .saturating_add(Weight::from_ref_time(1_076_550).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_076_550, 0).saturating_mul(s.into())) // Standard Error: 809 - .saturating_add(Weight::from_ref_time(163_191).saturating_mul(x.into())) + .saturating_add(Weight::from_parts(163_191, 0).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -178,9 +178,9 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 28_118 nanoseconds. Weight::from_parts(27_359_471, 11649) // Standard Error: 2_707 - .saturating_add(Weight::from_ref_time(107_279).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(107_279, 0).saturating_mul(r.into())) // Standard Error: 528 - .saturating_add(Weight::from_ref_time(325_165).saturating_mul(x.into())) + .saturating_add(Weight::from_parts(325_165, 0).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -195,9 +195,9 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 24_817 nanoseconds. Weight::from_parts(24_749_808, 10013) // Standard Error: 1_938 - .saturating_add(Weight::from_ref_time(63_396).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(63_396, 0).saturating_mul(r.into())) // Standard Error: 378 - .saturating_add(Weight::from_ref_time(327_083).saturating_mul(x.into())) + .saturating_add(Weight::from_parts(327_083, 0).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -211,7 +211,7 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 6_664 nanoseconds. Weight::from_parts(7_286_307, 1636) // Standard Error: 1_560 - .saturating_add(Weight::from_ref_time(96_416).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(96_416, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -225,7 +225,7 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 7_054 nanoseconds. Weight::from_parts(7_382_954, 1636) // Standard Error: 1_621 - .saturating_add(Weight::from_ref_time(101_595).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(101_595, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -239,7 +239,7 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 6_659 nanoseconds. Weight::from_parts(7_188_883, 1636) // Standard Error: 1_377 - .saturating_add(Weight::from_ref_time(98_965).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(98_965, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -256,9 +256,9 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 21_567 nanoseconds. Weight::from_parts(21_015_310, 11649) // Standard Error: 2_516 - .saturating_add(Weight::from_ref_time(123_992).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(123_992, 0).saturating_mul(r.into())) // Standard Error: 465 - .saturating_add(Weight::from_ref_time(552_116).saturating_mul(x.into())) + .saturating_add(Weight::from_parts(552_116, 0).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -280,11 +280,11 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 52_881 nanoseconds. Weight::from_parts(38_504_388, 18349) // Standard Error: 3_909 - .saturating_add(Weight::from_ref_time(51_452).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(51_452, 0).saturating_mul(r.into())) // Standard Error: 763 - .saturating_add(Weight::from_ref_time(1_069_924).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_069_924, 0).saturating_mul(s.into())) // Standard Error: 763 - .saturating_add(Weight::from_ref_time(164_906).saturating_mul(x.into())) + .saturating_add(Weight::from_parts(164_906, 0).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -303,7 +303,7 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 24_556 nanoseconds. Weight::from_parts(28_641_160, 18335) // Standard Error: 1_327 - .saturating_add(Weight::from_ref_time(66_150).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(66_150, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -319,7 +319,7 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 11_347 nanoseconds. Weight::from_parts(13_299_367, 12602) // Standard Error: 525 - .saturating_add(Weight::from_ref_time(16_472).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(16_472, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -337,7 +337,7 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 27_810 nanoseconds. Weight::from_parts(30_347_763, 18335) // Standard Error: 928 - .saturating_add(Weight::from_ref_time(55_342).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(55_342, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -353,7 +353,7 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 17_601 nanoseconds. Weight::from_parts(19_794_971, 8322) // Standard Error: 934 - .saturating_add(Weight::from_ref_time(59_289).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(59_289, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -371,7 +371,7 @@ impl WeightInfo for () { // Minimum execution time: 10_964 nanoseconds. Weight::from_parts(11_800_935, 1636) // Standard Error: 1_334 - .saturating_add(Weight::from_ref_time(96_038).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(96_038, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -386,9 +386,9 @@ impl WeightInfo for () { // Minimum execution time: 26_400 nanoseconds. Weight::from_parts(26_060_549, 10013) // Standard Error: 1_561 - .saturating_add(Weight::from_ref_time(72_083).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(72_083, 0).saturating_mul(r.into())) // Standard Error: 304 - .saturating_add(Weight::from_ref_time(306_994).saturating_mul(x.into())) + .saturating_add(Weight::from_parts(306_994, 0).saturating_mul(x.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -406,12 +406,12 @@ impl WeightInfo for () { // Minimum execution time: 8_492 nanoseconds. Weight::from_parts(21_645_924, 15746) // Standard Error: 3_452 - .saturating_add(Weight::from_ref_time(2_442_604).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(2_442_604, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(s.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) - .saturating_add(Weight::from_proof_size(2589).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(0, 2589).saturating_mul(s.into())) } /// Storage: Identity IdentityOf (r:1 w:0) /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) @@ -427,7 +427,7 @@ impl WeightInfo for () { // Minimum execution time: 8_488 nanoseconds. Weight::from_parts(20_202_601, 15746) // Standard Error: 2_834 - .saturating_add(Weight::from_ref_time(1_082_941).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(1_082_941, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(p.into()))) @@ -448,11 +448,11 @@ impl WeightInfo for () { // Minimum execution time: 41_319 nanoseconds. Weight::from_parts(25_850_055, 15746) // Standard Error: 4_144 - .saturating_add(Weight::from_ref_time(59_619).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(59_619, 0).saturating_mul(r.into())) // Standard Error: 809 - .saturating_add(Weight::from_ref_time(1_076_550).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_076_550, 0).saturating_mul(s.into())) // Standard Error: 809 - .saturating_add(Weight::from_ref_time(163_191).saturating_mul(x.into())) + .saturating_add(Weight::from_parts(163_191, 0).saturating_mul(x.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -470,9 +470,9 @@ impl WeightInfo for () { // Minimum execution time: 28_118 nanoseconds. Weight::from_parts(27_359_471, 11649) // Standard Error: 2_707 - .saturating_add(Weight::from_ref_time(107_279).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(107_279, 0).saturating_mul(r.into())) // Standard Error: 528 - .saturating_add(Weight::from_ref_time(325_165).saturating_mul(x.into())) + .saturating_add(Weight::from_parts(325_165, 0).saturating_mul(x.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -487,9 +487,9 @@ impl WeightInfo for () { // Minimum execution time: 24_817 nanoseconds. Weight::from_parts(24_749_808, 10013) // Standard Error: 1_938 - .saturating_add(Weight::from_ref_time(63_396).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(63_396, 0).saturating_mul(r.into())) // Standard Error: 378 - .saturating_add(Weight::from_ref_time(327_083).saturating_mul(x.into())) + .saturating_add(Weight::from_parts(327_083, 0).saturating_mul(x.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -503,7 +503,7 @@ impl WeightInfo for () { // Minimum execution time: 6_664 nanoseconds. Weight::from_parts(7_286_307, 1636) // Standard Error: 1_560 - .saturating_add(Weight::from_ref_time(96_416).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(96_416, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -517,7 +517,7 @@ impl WeightInfo for () { // Minimum execution time: 7_054 nanoseconds. Weight::from_parts(7_382_954, 1636) // Standard Error: 1_621 - .saturating_add(Weight::from_ref_time(101_595).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(101_595, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -531,7 +531,7 @@ impl WeightInfo for () { // Minimum execution time: 6_659 nanoseconds. Weight::from_parts(7_188_883, 1636) // Standard Error: 1_377 - .saturating_add(Weight::from_ref_time(98_965).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(98_965, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -548,9 +548,9 @@ impl WeightInfo for () { // Minimum execution time: 21_567 nanoseconds. Weight::from_parts(21_015_310, 11649) // Standard Error: 2_516 - .saturating_add(Weight::from_ref_time(123_992).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(123_992, 0).saturating_mul(r.into())) // Standard Error: 465 - .saturating_add(Weight::from_ref_time(552_116).saturating_mul(x.into())) + .saturating_add(Weight::from_parts(552_116, 0).saturating_mul(x.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -572,11 +572,11 @@ impl WeightInfo for () { // Minimum execution time: 52_881 nanoseconds. Weight::from_parts(38_504_388, 18349) // Standard Error: 3_909 - .saturating_add(Weight::from_ref_time(51_452).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(51_452, 0).saturating_mul(r.into())) // Standard Error: 763 - .saturating_add(Weight::from_ref_time(1_069_924).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_069_924, 0).saturating_mul(s.into())) // Standard Error: 763 - .saturating_add(Weight::from_ref_time(164_906).saturating_mul(x.into())) + .saturating_add(Weight::from_parts(164_906, 0).saturating_mul(x.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -595,7 +595,7 @@ impl WeightInfo for () { // Minimum execution time: 24_556 nanoseconds. Weight::from_parts(28_641_160, 18335) // Standard Error: 1_327 - .saturating_add(Weight::from_ref_time(66_150).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(66_150, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -611,7 +611,7 @@ impl WeightInfo for () { // Minimum execution time: 11_347 nanoseconds. Weight::from_parts(13_299_367, 12602) // Standard Error: 525 - .saturating_add(Weight::from_ref_time(16_472).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(16_472, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -629,7 +629,7 @@ impl WeightInfo for () { // Minimum execution time: 27_810 nanoseconds. Weight::from_parts(30_347_763, 18335) // Standard Error: 928 - .saturating_add(Weight::from_ref_time(55_342).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(55_342, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -645,7 +645,7 @@ impl WeightInfo for () { // Minimum execution time: 17_601 nanoseconds. Weight::from_parts(19_794_971, 8322) // Standard Error: 934 - .saturating_add(Weight::from_ref_time(59_289).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(59_289, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } diff --git a/frame/im-online/src/weights.rs b/frame/im-online/src/weights.rs index ee7cabf8ae2ee..675feb075473f 100644 --- a/frame/im-online/src/weights.rs +++ b/frame/im-online/src/weights.rs @@ -73,13 +73,13 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 91_116 nanoseconds. Weight::from_parts(72_526_877, 10345712) // Standard Error: 95 - .saturating_add(Weight::from_ref_time(20_461).saturating_mul(k.into())) + .saturating_add(Weight::from_parts(20_461, 0).saturating_mul(k.into())) // Standard Error: 967 - .saturating_add(Weight::from_ref_time(307_869).saturating_mul(e.into())) + .saturating_add(Weight::from_parts(307_869, 0).saturating_mul(e.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) - .saturating_add(Weight::from_proof_size(25).saturating_mul(e.into())) - .saturating_add(Weight::from_proof_size(64).saturating_mul(k.into())) + .saturating_add(Weight::from_parts(0, 25).saturating_mul(e.into())) + .saturating_add(Weight::from_parts(0, 64).saturating_mul(k.into())) } } @@ -104,12 +104,12 @@ impl WeightInfo for () { // Minimum execution time: 91_116 nanoseconds. Weight::from_parts(72_526_877, 10345712) // Standard Error: 95 - .saturating_add(Weight::from_ref_time(20_461).saturating_mul(k.into())) + .saturating_add(Weight::from_parts(20_461, 0).saturating_mul(k.into())) // Standard Error: 967 - .saturating_add(Weight::from_ref_time(307_869).saturating_mul(e.into())) + .saturating_add(Weight::from_parts(307_869, 0).saturating_mul(e.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) - .saturating_add(Weight::from_proof_size(25).saturating_mul(e.into())) - .saturating_add(Weight::from_proof_size(64).saturating_mul(k.into())) + .saturating_add(Weight::from_parts(0, 25).saturating_mul(e.into())) + .saturating_add(Weight::from_parts(0, 64).saturating_mul(k.into())) } } diff --git a/frame/lottery/src/weights.rs b/frame/lottery/src/weights.rs index e7857b230cd44..0038db6210d2b 100644 --- a/frame/lottery/src/weights.rs +++ b/frame/lottery/src/weights.rs @@ -90,9 +90,9 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 7_650 nanoseconds. - Weight::from_ref_time(8_344_960) + Weight::from_parts(8_344_960, 0) // Standard Error: 2_629 - .saturating_add(Weight::from_ref_time(268_557).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(268_557, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Lottery Lottery (r:1 w:1) @@ -196,9 +196,9 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 7_650 nanoseconds. - Weight::from_ref_time(8_344_960) + Weight::from_parts(8_344_960, 0) // Standard Error: 2_629 - .saturating_add(Weight::from_ref_time(268_557).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(268_557, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Lottery Lottery (r:1 w:1) diff --git a/frame/membership/src/weights.rs b/frame/membership/src/weights.rs index 17f4b2f84ec6d..f080f842c54b4 100644 --- a/frame/membership/src/weights.rs +++ b/frame/membership/src/weights.rs @@ -76,10 +76,10 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 15_673 nanoseconds. Weight::from_parts(16_830_288, 4903) // Standard Error: 570 - .saturating_add(Weight::from_ref_time(41_959).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(41_959, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(192).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 192).saturating_mul(m.into())) } /// Storage: TechnicalMembership Members (r:1 w:1) /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) @@ -99,10 +99,10 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 18_231 nanoseconds. Weight::from_parts(19_081_297, 5742) // Standard Error: 571 - .saturating_add(Weight::from_ref_time(41_331).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(41_331, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(192).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 192).saturating_mul(m.into())) } /// Storage: TechnicalMembership Members (r:1 w:1) /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) @@ -122,10 +122,10 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 18_517 nanoseconds. Weight::from_parts(19_388_310, 5742) // Standard Error: 625 - .saturating_add(Weight::from_ref_time(51_422).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(51_422, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(192).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 192).saturating_mul(m.into())) } /// Storage: TechnicalMembership Members (r:1 w:1) /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) @@ -145,10 +145,10 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 17_628 nanoseconds. Weight::from_parts(19_258_882, 5742) // Standard Error: 820 - .saturating_add(Weight::from_ref_time(153_956).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(153_956, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(192).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 192).saturating_mul(m.into())) } /// Storage: TechnicalMembership Members (r:1 w:1) /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) @@ -168,10 +168,10 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 19_031 nanoseconds. Weight::from_parts(20_264_948, 5742) // Standard Error: 707 - .saturating_add(Weight::from_ref_time(51_060).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(51_060, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) - .saturating_add(Weight::from_proof_size(192).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 192).saturating_mul(m.into())) } /// Storage: TechnicalMembership Members (r:1 w:0) /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) @@ -187,10 +187,10 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 6_897 nanoseconds. Weight::from_parts(7_455_387, 3761) // Standard Error: 326 - .saturating_add(Weight::from_ref_time(16_653).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(16_653, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) - .saturating_add(Weight::from_proof_size(32).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 32).saturating_mul(m.into())) } /// Storage: TechnicalMembership Prime (r:0 w:1) /// Proof: TechnicalMembership Prime (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) @@ -202,9 +202,9 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 3_400 nanoseconds. - Weight::from_ref_time(3_703_421) + Weight::from_parts(3_703_421, 0) // Standard Error: 119 - .saturating_add(Weight::from_ref_time(915).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(915, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().writes(2_u64)) } } @@ -227,10 +227,10 @@ impl WeightInfo for () { // Minimum execution time: 15_673 nanoseconds. Weight::from_parts(16_830_288, 4903) // Standard Error: 570 - .saturating_add(Weight::from_ref_time(41_959).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(41_959, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(192).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 192).saturating_mul(m.into())) } /// Storage: TechnicalMembership Members (r:1 w:1) /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) @@ -250,10 +250,10 @@ impl WeightInfo for () { // Minimum execution time: 18_231 nanoseconds. Weight::from_parts(19_081_297, 5742) // Standard Error: 571 - .saturating_add(Weight::from_ref_time(41_331).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(41_331, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(192).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 192).saturating_mul(m.into())) } /// Storage: TechnicalMembership Members (r:1 w:1) /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) @@ -273,10 +273,10 @@ impl WeightInfo for () { // Minimum execution time: 18_517 nanoseconds. Weight::from_parts(19_388_310, 5742) // Standard Error: 625 - .saturating_add(Weight::from_ref_time(51_422).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(51_422, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(192).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 192).saturating_mul(m.into())) } /// Storage: TechnicalMembership Members (r:1 w:1) /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) @@ -296,10 +296,10 @@ impl WeightInfo for () { // Minimum execution time: 17_628 nanoseconds. Weight::from_parts(19_258_882, 5742) // Standard Error: 820 - .saturating_add(Weight::from_ref_time(153_956).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(153_956, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(192).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 192).saturating_mul(m.into())) } /// Storage: TechnicalMembership Members (r:1 w:1) /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) @@ -319,10 +319,10 @@ impl WeightInfo for () { // Minimum execution time: 19_031 nanoseconds. Weight::from_parts(20_264_948, 5742) // Standard Error: 707 - .saturating_add(Weight::from_ref_time(51_060).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(51_060, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) - .saturating_add(Weight::from_proof_size(192).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 192).saturating_mul(m.into())) } /// Storage: TechnicalMembership Members (r:1 w:0) /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) @@ -338,10 +338,10 @@ impl WeightInfo for () { // Minimum execution time: 6_897 nanoseconds. Weight::from_parts(7_455_387, 3761) // Standard Error: 326 - .saturating_add(Weight::from_ref_time(16_653).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(16_653, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) - .saturating_add(Weight::from_proof_size(32).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 32).saturating_mul(m.into())) } /// Storage: TechnicalMembership Prime (r:0 w:1) /// Proof: TechnicalMembership Prime (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) @@ -353,9 +353,9 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 3_400 nanoseconds. - Weight::from_ref_time(3_703_421) + Weight::from_parts(3_703_421, 0) // Standard Error: 119 - .saturating_add(Weight::from_ref_time(915).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(915, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().writes(2_u64)) } } diff --git a/frame/merkle-mountain-range/src/default_weights.rs b/frame/merkle-mountain-range/src/default_weights.rs index 5d2e37cddce8b..52e3f130383fd 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 = Weight::from_ref_time(2u64 * WEIGHT_REF_TIME_PER_NANOS); + let hash_weight = Weight::from_parts(2u64 * WEIGHT_REF_TIME_PER_NANOS, 0); // No-op hook. let hook_weight = Weight::zero(); diff --git a/frame/message-queue/src/weights.rs b/frame/message-queue/src/weights.rs index 3421c2f2f59af..d1ccb338e66c3 100644 --- a/frame/message-queue/src/weights.rs +++ b/frame/message-queue/src/weights.rs @@ -73,8 +73,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `295` // Estimated: `7527` // Minimum execution time: 12_538 nanoseconds. - Weight::from_ref_time(12_799_000) - .saturating_add(Weight::from_proof_size(7527)) + Weight::from_parts(12_799_000, 0) + .saturating_add(Weight::from_parts(0, 7527)) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -87,8 +87,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `295` // Estimated: `7527` // Minimum execution time: 11_727 nanoseconds. - Weight::from_ref_time(12_177_000) - .saturating_add(Weight::from_proof_size(7527)) + Weight::from_parts(12_177_000, 0) + .saturating_add(Weight::from_parts(0, 7527)) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -99,8 +99,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `42` // Estimated: `3514` // Minimum execution time: 4_983 nanoseconds. - Weight::from_ref_time(5_174_000) - .saturating_add(Weight::from_proof_size(3514)) + Weight::from_parts(5_174_000, 0) + .saturating_add(Weight::from_parts(0, 3514)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -111,8 +111,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `113` // Estimated: `69049` // Minimum execution time: 6_299 nanoseconds. - Weight::from_ref_time(6_670_000) - .saturating_add(Weight::from_proof_size(69049)) + Weight::from_parts(6_670_000, 0) + .saturating_add(Weight::from_parts(0, 69049)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -123,8 +123,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `113` // Estimated: `69049` // Minimum execution time: 6_762 nanoseconds. - Weight::from_ref_time(7_059_000) - .saturating_add(Weight::from_proof_size(69049)) + Weight::from_parts(7_059_000, 0) + .saturating_add(Weight::from_parts(0, 69049)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -133,8 +133,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 72_681 nanoseconds. - Weight::from_ref_time(73_147_000) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(73_147_000, 0) + .saturating_add(Weight::from_parts(0, 0)) } /// Storage: MessageQueue ServiceHead (r:1 w:1) /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -145,8 +145,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `172` // Estimated: `5003` // Minimum execution time: 7_066 nanoseconds. - Weight::from_ref_time(7_214_000) - .saturating_add(Weight::from_proof_size(5003)) + Weight::from_parts(7_214_000, 0) + .saturating_add(Weight::from_parts(0, 5003)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -159,8 +159,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `65742` // Estimated: `72563` // Minimum execution time: 57_778 nanoseconds. - Weight::from_ref_time(58_778_000) - .saturating_add(Weight::from_proof_size(72563)) + Weight::from_parts(58_778_000, 0) + .saturating_add(Weight::from_parts(0, 72563)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -173,8 +173,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `65742` // Estimated: `72563` // Minimum execution time: 72_144 nanoseconds. - Weight::from_ref_time(72_942_000) - .saturating_add(Weight::from_proof_size(72563)) + Weight::from_parts(72_942_000, 0) + .saturating_add(Weight::from_parts(0, 72563)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -187,8 +187,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `65742` // Estimated: `72563` // Minimum execution time: 84_890 nanoseconds. - Weight::from_ref_time(86_073_000) - .saturating_add(Weight::from_proof_size(72563)) + Weight::from_parts(86_073_000, 0) + .saturating_add(Weight::from_parts(0, 72563)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -205,8 +205,8 @@ impl WeightInfo for () { // Measured: `295` // Estimated: `7527` // Minimum execution time: 12_538 nanoseconds. - Weight::from_ref_time(12_799_000) - .saturating_add(Weight::from_proof_size(7527)) + Weight::from_parts(12_799_000, 0) + .saturating_add(Weight::from_parts(0, 7527)) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -219,8 +219,8 @@ impl WeightInfo for () { // Measured: `295` // Estimated: `7527` // Minimum execution time: 11_727 nanoseconds. - Weight::from_ref_time(12_177_000) - .saturating_add(Weight::from_proof_size(7527)) + Weight::from_parts(12_177_000, 0) + .saturating_add(Weight::from_parts(0, 7527)) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -231,8 +231,8 @@ impl WeightInfo for () { // Measured: `42` // Estimated: `3514` // Minimum execution time: 4_983 nanoseconds. - Weight::from_ref_time(5_174_000) - .saturating_add(Weight::from_proof_size(3514)) + Weight::from_parts(5_174_000, 0) + .saturating_add(Weight::from_parts(0, 3514)) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -243,8 +243,8 @@ impl WeightInfo for () { // Measured: `113` // Estimated: `69049` // Minimum execution time: 6_299 nanoseconds. - Weight::from_ref_time(6_670_000) - .saturating_add(Weight::from_proof_size(69049)) + Weight::from_parts(6_670_000, 0) + .saturating_add(Weight::from_parts(0, 69049)) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -255,8 +255,8 @@ impl WeightInfo for () { // Measured: `113` // Estimated: `69049` // Minimum execution time: 6_762 nanoseconds. - Weight::from_ref_time(7_059_000) - .saturating_add(Weight::from_proof_size(69049)) + Weight::from_parts(7_059_000, 0) + .saturating_add(Weight::from_parts(0, 69049)) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -265,8 +265,8 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 72_681 nanoseconds. - Weight::from_ref_time(73_147_000) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(73_147_000, 0) + .saturating_add(Weight::from_parts(0, 0)) } /// Storage: MessageQueue ServiceHead (r:1 w:1) /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -277,8 +277,8 @@ impl WeightInfo for () { // Measured: `172` // Estimated: `5003` // Minimum execution time: 7_066 nanoseconds. - Weight::from_ref_time(7_214_000) - .saturating_add(Weight::from_proof_size(5003)) + Weight::from_parts(7_214_000, 0) + .saturating_add(Weight::from_parts(0, 5003)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -291,8 +291,8 @@ impl WeightInfo for () { // Measured: `65742` // Estimated: `72563` // Minimum execution time: 57_778 nanoseconds. - Weight::from_ref_time(58_778_000) - .saturating_add(Weight::from_proof_size(72563)) + Weight::from_parts(58_778_000, 0) + .saturating_add(Weight::from_parts(0, 72563)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -305,8 +305,8 @@ impl WeightInfo for () { // Measured: `65742` // Estimated: `72563` // Minimum execution time: 72_144 nanoseconds. - Weight::from_ref_time(72_942_000) - .saturating_add(Weight::from_proof_size(72563)) + Weight::from_parts(72_942_000, 0) + .saturating_add(Weight::from_parts(0, 72563)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -319,8 +319,8 @@ impl WeightInfo for () { // Measured: `65742` // Estimated: `72563` // Minimum execution time: 84_890 nanoseconds. - Weight::from_ref_time(86_073_000) - .saturating_add(Weight::from_proof_size(72563)) + Weight::from_parts(86_073_000, 0) + .saturating_add(Weight::from_parts(0, 72563)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } diff --git a/frame/multisig/src/weights.rs b/frame/multisig/src/weights.rs index eff6a29803e04..fb155c97f2def 100644 --- a/frame/multisig/src/weights.rs +++ b/frame/multisig/src/weights.rs @@ -66,9 +66,9 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 12_086 nanoseconds. - Weight::from_ref_time(12_464_828) + Weight::from_parts(12_464_828, 0) // Standard Error: 1 - .saturating_add(Weight::from_ref_time(494).saturating_mul(z.into())) + .saturating_add(Weight::from_parts(494, 0).saturating_mul(z.into())) } /// Storage: Multisig Multisigs (r:1 w:1) /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) @@ -81,9 +81,9 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 35_377 nanoseconds. Weight::from_parts(29_088_956, 5821) // Standard Error: 335 - .saturating_add(Weight::from_ref_time(67_846).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(67_846, 0).saturating_mul(s.into())) // Standard Error: 3 - .saturating_add(Weight::from_ref_time(1_523).saturating_mul(z.into())) + .saturating_add(Weight::from_parts(1_523, 0).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -98,9 +98,9 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 26_138 nanoseconds. Weight::from_parts(20_479_380, 5821) // Standard Error: 259 - .saturating_add(Weight::from_ref_time(64_116).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(64_116, 0).saturating_mul(s.into())) // Standard Error: 2 - .saturating_add(Weight::from_ref_time(1_520).saturating_mul(z.into())) + .saturating_add(Weight::from_parts(1_520, 0).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -117,9 +117,9 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 40_323 nanoseconds. Weight::from_parts(32_311_615, 8424) // Standard Error: 401 - .saturating_add(Weight::from_ref_time(85_999).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(85_999, 0).saturating_mul(s.into())) // Standard Error: 3 - .saturating_add(Weight::from_ref_time(1_534).saturating_mul(z.into())) + .saturating_add(Weight::from_parts(1_534, 0).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -133,7 +133,7 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 26_938 nanoseconds. Weight::from_parts(27_802_216, 5821) // Standard Error: 342 - .saturating_add(Weight::from_ref_time(69_282).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(69_282, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -147,7 +147,7 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 18_050 nanoseconds. Weight::from_parts(19_095_404, 5821) // Standard Error: 419 - .saturating_add(Weight::from_ref_time(66_914).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(66_914, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -161,7 +161,7 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 27_508 nanoseconds. Weight::from_parts(28_702_686, 5821) // Standard Error: 466 - .saturating_add(Weight::from_ref_time(69_419).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(69_419, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -175,9 +175,9 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 12_086 nanoseconds. - Weight::from_ref_time(12_464_828) + Weight::from_parts(12_464_828, 0) // Standard Error: 1 - .saturating_add(Weight::from_ref_time(494).saturating_mul(z.into())) + .saturating_add(Weight::from_parts(494, 0).saturating_mul(z.into())) } /// Storage: Multisig Multisigs (r:1 w:1) /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) @@ -190,9 +190,9 @@ impl WeightInfo for () { // Minimum execution time: 35_377 nanoseconds. Weight::from_parts(29_088_956, 5821) // Standard Error: 335 - .saturating_add(Weight::from_ref_time(67_846).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(67_846, 0).saturating_mul(s.into())) // Standard Error: 3 - .saturating_add(Weight::from_ref_time(1_523).saturating_mul(z.into())) + .saturating_add(Weight::from_parts(1_523, 0).saturating_mul(z.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -207,9 +207,9 @@ impl WeightInfo for () { // Minimum execution time: 26_138 nanoseconds. Weight::from_parts(20_479_380, 5821) // Standard Error: 259 - .saturating_add(Weight::from_ref_time(64_116).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(64_116, 0).saturating_mul(s.into())) // Standard Error: 2 - .saturating_add(Weight::from_ref_time(1_520).saturating_mul(z.into())) + .saturating_add(Weight::from_parts(1_520, 0).saturating_mul(z.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -226,9 +226,9 @@ impl WeightInfo for () { // Minimum execution time: 40_323 nanoseconds. Weight::from_parts(32_311_615, 8424) // Standard Error: 401 - .saturating_add(Weight::from_ref_time(85_999).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(85_999, 0).saturating_mul(s.into())) // Standard Error: 3 - .saturating_add(Weight::from_ref_time(1_534).saturating_mul(z.into())) + .saturating_add(Weight::from_parts(1_534, 0).saturating_mul(z.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -242,7 +242,7 @@ impl WeightInfo for () { // Minimum execution time: 26_938 nanoseconds. Weight::from_parts(27_802_216, 5821) // Standard Error: 342 - .saturating_add(Weight::from_ref_time(69_282).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(69_282, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -256,7 +256,7 @@ impl WeightInfo for () { // Minimum execution time: 18_050 nanoseconds. Weight::from_parts(19_095_404, 5821) // Standard Error: 419 - .saturating_add(Weight::from_ref_time(66_914).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(66_914, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -270,7 +270,7 @@ impl WeightInfo for () { // Minimum execution time: 27_508 nanoseconds. Weight::from_parts(28_702_686, 5821) // Standard Error: 466 - .saturating_add(Weight::from_ref_time(69_419).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(69_419, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/frame/nfts/src/weights.rs b/frame/nfts/src/weights.rs index 9eedea958ae83..858ae2fec9226 100644 --- a/frame/nfts/src/weights.rs +++ b/frame/nfts/src/weights.rs @@ -108,8 +108,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `214` // Estimated: `3054` // Minimum execution time: 33_769 nanoseconds. - Weight::from_ref_time(36_031_000) - .saturating_add(Weight::from_proof_size(3054)) + Weight::from_parts(36_031_000, 0) + .saturating_add(Weight::from_parts(0, 3054)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -128,8 +128,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `42` // Estimated: `3054` // Minimum execution time: 21_767 nanoseconds. - Weight::from_ref_time(22_565_000) - .saturating_add(Weight::from_proof_size(3054)) + Weight::from_parts(22_565_000, 0) + .saturating_add(Weight::from_parts(0, 3054)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -161,20 +161,20 @@ impl WeightInfo for SubstrateWeight { // Measured: `172781 + m * (127 ±0) + a * (402 ±0)` // Estimated: `3347427 + m * (2615 ±0) + a * (2921 ±0)` // Minimum execution time: 26_973_627 nanoseconds. - Weight::from_ref_time(19_692_361_714) - .saturating_add(Weight::from_proof_size(3347427)) + Weight::from_parts(19_692_361_714, 0) + .saturating_add(Weight::from_parts(0, 3347427)) // Standard Error: 17_036 - .saturating_add(Weight::from_ref_time(7_797_219).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(7_797_219, 0).saturating_mul(m.into())) // Standard Error: 17_036 - .saturating_add(Weight::from_ref_time(9_504_128).saturating_mul(a.into())) + .saturating_add(Weight::from_parts(9_504_128, 0).saturating_mul(a.into())) .saturating_add(T::DbWeight::get().reads(1004_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(m.into()))) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(a.into()))) .saturating_add(T::DbWeight::get().writes(3005_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(m.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(a.into()))) - .saturating_add(Weight::from_proof_size(2615).saturating_mul(m.into())) - .saturating_add(Weight::from_proof_size(2921).saturating_mul(a.into())) + .saturating_add(Weight::from_parts(0, 2615).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 2921).saturating_mul(a.into())) } /// Storage: Nfts CollectionConfigOf (r:1 w:0) /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) @@ -193,8 +193,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `448` // Estimated: `13506` // Minimum execution time: 44_837 nanoseconds. - Weight::from_ref_time(46_794_000) - .saturating_add(Weight::from_proof_size(13506)) + Weight::from_parts(46_794_000, 0) + .saturating_add(Weight::from_parts(0, 13506)) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -215,8 +215,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `448` // Estimated: `13506` // Minimum execution time: 43_976 nanoseconds. - Weight::from_ref_time(44_831_000) - .saturating_add(Weight::from_proof_size(13506)) + Weight::from_parts(44_831_000, 0) + .saturating_add(Weight::from_parts(0, 13506)) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -243,8 +243,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `647` // Estimated: `13573` // Minimum execution time: 48_233 nanoseconds. - Weight::from_ref_time(50_113_000) - .saturating_add(Weight::from_proof_size(13573)) + Weight::from_parts(50_113_000, 0) + .saturating_add(Weight::from_parts(0, 13573)) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } @@ -271,8 +271,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `882` // Estimated: `16109` // Minimum execution time: 55_452 nanoseconds. - Weight::from_ref_time(57_642_000) - .saturating_add(Weight::from_proof_size(16109)) + Weight::from_parts(57_642_000, 0) + .saturating_add(Weight::from_parts(0, 16109)) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -288,14 +288,14 @@ impl WeightInfo for SubstrateWeight { // Measured: `756 + i * (140 ±0)` // Estimated: `5103 + i * (3336 ±0)` // Minimum execution time: 15_598 nanoseconds. - Weight::from_ref_time(15_926_000) - .saturating_add(Weight::from_proof_size(5103)) + Weight::from_parts(15_926_000, 0) + .saturating_add(Weight::from_parts(0, 5103)) // Standard Error: 13_692 - .saturating_add(Weight::from_ref_time(14_040_741).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(14_040_741, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(i.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) - .saturating_add(Weight::from_proof_size(3336).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(0, 3336).saturating_mul(i.into())) } /// Storage: Nfts CollectionRoleOf (r:1 w:0) /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) @@ -306,8 +306,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `401` // Estimated: `5067` // Minimum execution time: 19_686 nanoseconds. - Weight::from_ref_time(20_404_000) - .saturating_add(Weight::from_proof_size(5067)) + Weight::from_parts(20_404_000, 0) + .saturating_add(Weight::from_parts(0, 5067)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -320,8 +320,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `401` // Estimated: `5067` // Minimum execution time: 19_172 nanoseconds. - Weight::from_ref_time(20_151_000) - .saturating_add(Weight::from_proof_size(5067)) + Weight::from_parts(20_151_000, 0) + .saturating_add(Weight::from_parts(0, 5067)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -334,8 +334,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `289` // Estimated: `5092` // Minimum execution time: 17_063 nanoseconds. - Weight::from_ref_time(17_482_000) - .saturating_add(Weight::from_proof_size(5092)) + Weight::from_parts(17_482_000, 0) + .saturating_add(Weight::from_parts(0, 5092)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -350,8 +350,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `381` // Estimated: `5082` // Minimum execution time: 21_974 nanoseconds. - Weight::from_ref_time(22_770_000) - .saturating_add(Weight::from_proof_size(5082)) + Weight::from_parts(22_770_000, 0) + .saturating_add(Weight::from_parts(0, 5082)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -364,8 +364,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `362` // Estimated: `2555` // Minimum execution time: 24_341 nanoseconds. - Weight::from_ref_time(25_059_000) - .saturating_add(Weight::from_proof_size(2555)) + Weight::from_parts(25_059_000, 0) + .saturating_add(Weight::from_parts(0, 2555)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -378,8 +378,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `304` // Estimated: `2555` // Minimum execution time: 16_897 nanoseconds. - Weight::from_ref_time(17_560_000) - .saturating_add(Weight::from_proof_size(2555)) + Weight::from_parts(17_560_000, 0) + .saturating_add(Weight::from_parts(0, 2555)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -392,8 +392,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `242` // Estimated: `2555` // Minimum execution time: 13_239 nanoseconds. - Weight::from_ref_time(13_963_000) - .saturating_add(Weight::from_proof_size(2555)) + Weight::from_parts(13_963_000, 0) + .saturating_add(Weight::from_parts(0, 2555)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -406,8 +406,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `445` // Estimated: `5078` // Minimum execution time: 17_187 nanoseconds. - Weight::from_ref_time(17_942_000) - .saturating_add(Weight::from_proof_size(5078)) + Weight::from_parts(17_942_000, 0) + .saturating_add(Weight::from_parts(0, 5078)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -424,8 +424,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `474` // Estimated: `10547` // Minimum execution time: 40_925 nanoseconds. - Weight::from_ref_time(42_733_000) - .saturating_add(Weight::from_proof_size(10547)) + Weight::from_parts(42_733_000, 0) + .saturating_add(Weight::from_parts(0, 10547)) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -438,8 +438,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `337` // Estimated: `5476` // Minimum execution time: 24_486 nanoseconds. - Weight::from_ref_time(25_409_000) - .saturating_add(Weight::from_proof_size(5476)) + Weight::from_parts(25_409_000, 0) + .saturating_add(Weight::from_parts(0, 5476)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -454,8 +454,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `916` // Estimated: `7999` // Minimum execution time: 36_643 nanoseconds. - Weight::from_ref_time(37_805_000) - .saturating_add(Weight::from_proof_size(7999)) + Weight::from_parts(37_805_000, 0) + .saturating_add(Weight::from_parts(0, 7999)) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -468,8 +468,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `379` // Estimated: `6492` // Minimum execution time: 16_798 nanoseconds. - Weight::from_ref_time(17_326_000) - .saturating_add(Weight::from_proof_size(6492)) + Weight::from_parts(17_326_000, 0) + .saturating_add(Weight::from_parts(0, 6492)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -487,15 +487,15 @@ impl WeightInfo for SubstrateWeight { // Measured: `899 + n * (396 ±0)` // Estimated: `12016 + n * (2921 ±0)` // Minimum execution time: 25_524 nanoseconds. - Weight::from_ref_time(26_107_000) - .saturating_add(Weight::from_proof_size(12016)) + Weight::from_parts(26_107_000, 0) + .saturating_add(Weight::from_parts(0, 12016)) // Standard Error: 5_460 - .saturating_add(Weight::from_ref_time(9_030_830).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(9_030_830, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_proof_size(2921).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 2921).saturating_mul(n.into())) } /// Storage: Nfts Collection (r:1 w:1) /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) @@ -510,8 +510,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `474` // Estimated: `10241` // Minimum execution time: 34_400 nanoseconds. - Weight::from_ref_time(35_469_000) - .saturating_add(Weight::from_proof_size(10241)) + Weight::from_parts(35_469_000, 0) + .saturating_add(Weight::from_parts(0, 10241)) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -526,8 +526,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `609` // Estimated: `7693` // Minimum execution time: 31_560 nanoseconds. - Weight::from_ref_time(33_081_000) - .saturating_add(Weight::from_proof_size(7693)) + Weight::from_parts(33_081_000, 0) + .saturating_add(Weight::from_parts(0, 7693)) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -542,8 +542,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `333` // Estimated: `7665` // Minimum execution time: 28_821 nanoseconds. - Weight::from_ref_time(30_010_000) - .saturating_add(Weight::from_proof_size(7665)) + Weight::from_parts(30_010_000, 0) + .saturating_add(Weight::from_parts(0, 7665)) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -558,8 +558,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `476` // Estimated: `7665` // Minimum execution time: 27_608 nanoseconds. - Weight::from_ref_time(28_766_000) - .saturating_add(Weight::from_proof_size(7665)) + Weight::from_parts(28_766_000, 0) + .saturating_add(Weight::from_parts(0, 7665)) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -574,8 +574,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `466` // Estimated: `8428` // Minimum execution time: 23_987 nanoseconds. - Weight::from_ref_time(24_819_000) - .saturating_add(Weight::from_proof_size(8428)) + Weight::from_parts(24_819_000, 0) + .saturating_add(Weight::from_parts(0, 8428)) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -588,8 +588,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `474` // Estimated: `5880` // Minimum execution time: 21_254 nanoseconds. - Weight::from_ref_time(21_826_000) - .saturating_add(Weight::from_proof_size(5880)) + Weight::from_parts(21_826_000, 0) + .saturating_add(Weight::from_parts(0, 5880)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -602,8 +602,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `474` // Estimated: `5880` // Minimum execution time: 20_272 nanoseconds. - Weight::from_ref_time(20_922_000) - .saturating_add(Weight::from_proof_size(5880)) + Weight::from_parts(20_922_000, 0) + .saturating_add(Weight::from_parts(0, 5880)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -614,8 +614,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `42` // Estimated: `2527` // Minimum execution time: 14_287 nanoseconds. - Weight::from_ref_time(14_960_000) - .saturating_add(Weight::from_proof_size(2527)) + Weight::from_parts(14_960_000, 0) + .saturating_add(Weight::from_parts(0, 2527)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -628,8 +628,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `333` // Estimated: `5103` // Minimum execution time: 17_948 nanoseconds. - Weight::from_ref_time(18_780_000) - .saturating_add(Weight::from_proof_size(5103)) + Weight::from_parts(18_780_000, 0) + .saturating_add(Weight::from_parts(0, 5103)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -642,8 +642,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `333` // Estimated: `5103` // Minimum execution time: 16_616 nanoseconds. - Weight::from_ref_time(17_155_000) - .saturating_add(Weight::from_proof_size(5103)) + Weight::from_parts(17_155_000, 0) + .saturating_add(Weight::from_parts(0, 5103)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -660,8 +660,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `516` // Estimated: `8407` // Minimum execution time: 22_777 nanoseconds. - Weight::from_ref_time(23_955_000) - .saturating_add(Weight::from_proof_size(8407)) + Weight::from_parts(23_955_000, 0) + .saturating_add(Weight::from_parts(0, 8407)) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -686,8 +686,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `934` // Estimated: `16129` // Minimum execution time: 61_131 nanoseconds. - Weight::from_ref_time(62_791_000) - .saturating_add(Weight::from_proof_size(16129)) + Weight::from_parts(62_791_000, 0) + .saturating_add(Weight::from_parts(0, 16129)) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -697,10 +697,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 1_952 nanoseconds. - Weight::from_ref_time(3_975_700) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(3_975_700, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 11_254 - .saturating_add(Weight::from_ref_time(3_501_698).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(3_501_698, 0).saturating_mul(n.into())) } /// Storage: Nfts Item (r:2 w:0) /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) @@ -711,8 +711,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `524` // Estimated: `6672` // Minimum execution time: 20_327 nanoseconds. - Weight::from_ref_time(21_714_000) - .saturating_add(Weight::from_proof_size(6672)) + Weight::from_parts(21_714_000, 0) + .saturating_add(Weight::from_parts(0, 6672)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -725,8 +725,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `511` // Estimated: `5882` // Minimum execution time: 20_668 nanoseconds. - Weight::from_ref_time(21_416_000) - .saturating_add(Weight::from_proof_size(5882)) + Weight::from_parts(21_416_000, 0) + .saturating_add(Weight::from_parts(0, 5882)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -751,8 +751,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `1097` // Estimated: `21970` // Minimum execution time: 88_006 nanoseconds. - Weight::from_ref_time(90_390_000) - .saturating_add(Weight::from_proof_size(21970)) + Weight::from_parts(90_390_000, 0) + .saturating_add(Weight::from_parts(0, 21970)) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(11_u64)) } @@ -778,15 +778,15 @@ impl WeightInfo for SubstrateWeight { // Measured: `596` // Estimated: `16180 + n * (2921 ±0)` // Minimum execution time: 124_967 nanoseconds. - Weight::from_ref_time(131_602_642) - .saturating_add(Weight::from_proof_size(16180)) + Weight::from_parts(131_602_642, 0) + .saturating_add(Weight::from_parts(0, 16180)) // Standard Error: 36_480 - .saturating_add(Weight::from_ref_time(25_811_394).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(25_811_394, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(6_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_proof_size(2921).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 2921).saturating_mul(n.into())) } /// Storage: Nfts Item (r:1 w:0) /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) @@ -806,15 +806,15 @@ impl WeightInfo for SubstrateWeight { // Measured: `716` // Estimated: `14198 + n * (2921 ±0)` // Minimum execution time: 84_153 nanoseconds. - Weight::from_ref_time(96_401_623) - .saturating_add(Weight::from_proof_size(14198)) + Weight::from_parts(96_401_623, 0) + .saturating_add(Weight::from_parts(0, 14198)) // Standard Error: 70_244 - .saturating_add(Weight::from_ref_time(26_866_222).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(26_866_222, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_proof_size(2921).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 2921).saturating_mul(n.into())) } } @@ -835,8 +835,8 @@ impl WeightInfo for () { // Measured: `214` // Estimated: `3054` // Minimum execution time: 33_769 nanoseconds. - Weight::from_ref_time(36_031_000) - .saturating_add(Weight::from_proof_size(3054)) + Weight::from_parts(36_031_000, 0) + .saturating_add(Weight::from_parts(0, 3054)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -855,8 +855,8 @@ impl WeightInfo for () { // Measured: `42` // Estimated: `3054` // Minimum execution time: 21_767 nanoseconds. - Weight::from_ref_time(22_565_000) - .saturating_add(Weight::from_proof_size(3054)) + Weight::from_parts(22_565_000, 0) + .saturating_add(Weight::from_parts(0, 3054)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -888,20 +888,20 @@ impl WeightInfo for () { // Measured: `172781 + m * (127 ±0) + a * (402 ±0)` // Estimated: `3347427 + m * (2615 ±0) + a * (2921 ±0)` // Minimum execution time: 26_973_627 nanoseconds. - Weight::from_ref_time(19_692_361_714) - .saturating_add(Weight::from_proof_size(3347427)) + Weight::from_parts(19_692_361_714, 0) + .saturating_add(Weight::from_parts(0, 3347427)) // Standard Error: 17_036 - .saturating_add(Weight::from_ref_time(7_797_219).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(7_797_219, 0).saturating_mul(m.into())) // Standard Error: 17_036 - .saturating_add(Weight::from_ref_time(9_504_128).saturating_mul(a.into())) + .saturating_add(Weight::from_parts(9_504_128, 0).saturating_mul(a.into())) .saturating_add(RocksDbWeight::get().reads(1004_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(m.into()))) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(a.into()))) .saturating_add(RocksDbWeight::get().writes(3005_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(m.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(a.into()))) - .saturating_add(Weight::from_proof_size(2615).saturating_mul(m.into())) - .saturating_add(Weight::from_proof_size(2921).saturating_mul(a.into())) + .saturating_add(Weight::from_parts(0, 2615).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 2921).saturating_mul(a.into())) } /// Storage: Nfts CollectionConfigOf (r:1 w:0) /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) @@ -920,8 +920,8 @@ impl WeightInfo for () { // Measured: `448` // Estimated: `13506` // Minimum execution time: 44_837 nanoseconds. - Weight::from_ref_time(46_794_000) - .saturating_add(Weight::from_proof_size(13506)) + Weight::from_parts(46_794_000, 0) + .saturating_add(Weight::from_parts(0, 13506)) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -942,8 +942,8 @@ impl WeightInfo for () { // Measured: `448` // Estimated: `13506` // Minimum execution time: 43_976 nanoseconds. - Weight::from_ref_time(44_831_000) - .saturating_add(Weight::from_proof_size(13506)) + Weight::from_parts(44_831_000, 0) + .saturating_add(Weight::from_parts(0, 13506)) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -970,8 +970,8 @@ impl WeightInfo for () { // Measured: `647` // Estimated: `13573` // Minimum execution time: 48_233 nanoseconds. - Weight::from_ref_time(50_113_000) - .saturating_add(Weight::from_proof_size(13573)) + Weight::from_parts(50_113_000, 0) + .saturating_add(Weight::from_parts(0, 13573)) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } @@ -998,8 +998,8 @@ impl WeightInfo for () { // Measured: `882` // Estimated: `16109` // Minimum execution time: 55_452 nanoseconds. - Weight::from_ref_time(57_642_000) - .saturating_add(Weight::from_proof_size(16109)) + Weight::from_parts(57_642_000, 0) + .saturating_add(Weight::from_parts(0, 16109)) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -1015,14 +1015,14 @@ impl WeightInfo for () { // Measured: `756 + i * (140 ±0)` // Estimated: `5103 + i * (3336 ±0)` // Minimum execution time: 15_598 nanoseconds. - Weight::from_ref_time(15_926_000) - .saturating_add(Weight::from_proof_size(5103)) + Weight::from_parts(15_926_000, 0) + .saturating_add(Weight::from_parts(0, 5103)) // Standard Error: 13_692 - .saturating_add(Weight::from_ref_time(14_040_741).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(14_040_741, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(i.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(i.into()))) - .saturating_add(Weight::from_proof_size(3336).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(0, 3336).saturating_mul(i.into())) } /// Storage: Nfts CollectionRoleOf (r:1 w:0) /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) @@ -1033,8 +1033,8 @@ impl WeightInfo for () { // Measured: `401` // Estimated: `5067` // Minimum execution time: 19_686 nanoseconds. - Weight::from_ref_time(20_404_000) - .saturating_add(Weight::from_proof_size(5067)) + Weight::from_parts(20_404_000, 0) + .saturating_add(Weight::from_parts(0, 5067)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1047,8 +1047,8 @@ impl WeightInfo for () { // Measured: `401` // Estimated: `5067` // Minimum execution time: 19_172 nanoseconds. - Weight::from_ref_time(20_151_000) - .saturating_add(Weight::from_proof_size(5067)) + Weight::from_parts(20_151_000, 0) + .saturating_add(Weight::from_parts(0, 5067)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1061,8 +1061,8 @@ impl WeightInfo for () { // Measured: `289` // Estimated: `5092` // Minimum execution time: 17_063 nanoseconds. - Weight::from_ref_time(17_482_000) - .saturating_add(Weight::from_proof_size(5092)) + Weight::from_parts(17_482_000, 0) + .saturating_add(Weight::from_parts(0, 5092)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1077,8 +1077,8 @@ impl WeightInfo for () { // Measured: `381` // Estimated: `5082` // Minimum execution time: 21_974 nanoseconds. - Weight::from_ref_time(22_770_000) - .saturating_add(Weight::from_proof_size(5082)) + Weight::from_parts(22_770_000, 0) + .saturating_add(Weight::from_parts(0, 5082)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -1091,8 +1091,8 @@ impl WeightInfo for () { // Measured: `362` // Estimated: `2555` // Minimum execution time: 24_341 nanoseconds. - Weight::from_ref_time(25_059_000) - .saturating_add(Weight::from_proof_size(2555)) + Weight::from_parts(25_059_000, 0) + .saturating_add(Weight::from_parts(0, 2555)) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -1105,8 +1105,8 @@ impl WeightInfo for () { // Measured: `304` // Estimated: `2555` // Minimum execution time: 16_897 nanoseconds. - Weight::from_ref_time(17_560_000) - .saturating_add(Weight::from_proof_size(2555)) + Weight::from_parts(17_560_000, 0) + .saturating_add(Weight::from_parts(0, 2555)) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -1119,8 +1119,8 @@ impl WeightInfo for () { // Measured: `242` // Estimated: `2555` // Minimum execution time: 13_239 nanoseconds. - Weight::from_ref_time(13_963_000) - .saturating_add(Weight::from_proof_size(2555)) + Weight::from_parts(13_963_000, 0) + .saturating_add(Weight::from_parts(0, 2555)) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1133,8 +1133,8 @@ impl WeightInfo for () { // Measured: `445` // Estimated: `5078` // Minimum execution time: 17_187 nanoseconds. - Weight::from_ref_time(17_942_000) - .saturating_add(Weight::from_proof_size(5078)) + Weight::from_parts(17_942_000, 0) + .saturating_add(Weight::from_parts(0, 5078)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1151,8 +1151,8 @@ impl WeightInfo for () { // Measured: `474` // Estimated: `10547` // Minimum execution time: 40_925 nanoseconds. - Weight::from_ref_time(42_733_000) - .saturating_add(Weight::from_proof_size(10547)) + Weight::from_parts(42_733_000, 0) + .saturating_add(Weight::from_parts(0, 10547)) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1165,8 +1165,8 @@ impl WeightInfo for () { // Measured: `337` // Estimated: `5476` // Minimum execution time: 24_486 nanoseconds. - Weight::from_ref_time(25_409_000) - .saturating_add(Weight::from_proof_size(5476)) + Weight::from_parts(25_409_000, 0) + .saturating_add(Weight::from_parts(0, 5476)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1181,8 +1181,8 @@ impl WeightInfo for () { // Measured: `916` // Estimated: `7999` // Minimum execution time: 36_643 nanoseconds. - Weight::from_ref_time(37_805_000) - .saturating_add(Weight::from_proof_size(7999)) + Weight::from_parts(37_805_000, 0) + .saturating_add(Weight::from_parts(0, 7999)) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1195,8 +1195,8 @@ impl WeightInfo for () { // Measured: `379` // Estimated: `6492` // Minimum execution time: 16_798 nanoseconds. - Weight::from_ref_time(17_326_000) - .saturating_add(Weight::from_proof_size(6492)) + Weight::from_parts(17_326_000, 0) + .saturating_add(Weight::from_parts(0, 6492)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1214,15 +1214,15 @@ impl WeightInfo for () { // Measured: `899 + n * (396 ±0)` // Estimated: `12016 + n * (2921 ±0)` // Minimum execution time: 25_524 nanoseconds. - Weight::from_ref_time(26_107_000) - .saturating_add(Weight::from_proof_size(12016)) + Weight::from_parts(26_107_000, 0) + .saturating_add(Weight::from_parts(0, 12016)) // Standard Error: 5_460 - .saturating_add(Weight::from_ref_time(9_030_830).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(9_030_830, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_proof_size(2921).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 2921).saturating_mul(n.into())) } /// Storage: Nfts Collection (r:1 w:1) /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) @@ -1237,8 +1237,8 @@ impl WeightInfo for () { // Measured: `474` // Estimated: `10241` // Minimum execution time: 34_400 nanoseconds. - Weight::from_ref_time(35_469_000) - .saturating_add(Weight::from_proof_size(10241)) + Weight::from_parts(35_469_000, 0) + .saturating_add(Weight::from_parts(0, 10241)) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1253,8 +1253,8 @@ impl WeightInfo for () { // Measured: `609` // Estimated: `7693` // Minimum execution time: 31_560 nanoseconds. - Weight::from_ref_time(33_081_000) - .saturating_add(Weight::from_proof_size(7693)) + Weight::from_parts(33_081_000, 0) + .saturating_add(Weight::from_parts(0, 7693)) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1269,8 +1269,8 @@ impl WeightInfo for () { // Measured: `333` // Estimated: `7665` // Minimum execution time: 28_821 nanoseconds. - Weight::from_ref_time(30_010_000) - .saturating_add(Weight::from_proof_size(7665)) + Weight::from_parts(30_010_000, 0) + .saturating_add(Weight::from_parts(0, 7665)) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1285,8 +1285,8 @@ impl WeightInfo for () { // Measured: `476` // Estimated: `7665` // Minimum execution time: 27_608 nanoseconds. - Weight::from_ref_time(28_766_000) - .saturating_add(Weight::from_proof_size(7665)) + Weight::from_parts(28_766_000, 0) + .saturating_add(Weight::from_parts(0, 7665)) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1301,8 +1301,8 @@ impl WeightInfo for () { // Measured: `466` // Estimated: `8428` // Minimum execution time: 23_987 nanoseconds. - Weight::from_ref_time(24_819_000) - .saturating_add(Weight::from_proof_size(8428)) + Weight::from_parts(24_819_000, 0) + .saturating_add(Weight::from_parts(0, 8428)) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1315,8 +1315,8 @@ impl WeightInfo for () { // Measured: `474` // Estimated: `5880` // Minimum execution time: 21_254 nanoseconds. - Weight::from_ref_time(21_826_000) - .saturating_add(Weight::from_proof_size(5880)) + Weight::from_parts(21_826_000, 0) + .saturating_add(Weight::from_parts(0, 5880)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1329,8 +1329,8 @@ impl WeightInfo for () { // Measured: `474` // Estimated: `5880` // Minimum execution time: 20_272 nanoseconds. - Weight::from_ref_time(20_922_000) - .saturating_add(Weight::from_proof_size(5880)) + Weight::from_parts(20_922_000, 0) + .saturating_add(Weight::from_parts(0, 5880)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1341,8 +1341,8 @@ impl WeightInfo for () { // Measured: `42` // Estimated: `2527` // Minimum execution time: 14_287 nanoseconds. - Weight::from_ref_time(14_960_000) - .saturating_add(Weight::from_proof_size(2527)) + Weight::from_parts(14_960_000, 0) + .saturating_add(Weight::from_parts(0, 2527)) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1355,8 +1355,8 @@ impl WeightInfo for () { // Measured: `333` // Estimated: `5103` // Minimum execution time: 17_948 nanoseconds. - Weight::from_ref_time(18_780_000) - .saturating_add(Weight::from_proof_size(5103)) + Weight::from_parts(18_780_000, 0) + .saturating_add(Weight::from_parts(0, 5103)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1369,8 +1369,8 @@ impl WeightInfo for () { // Measured: `333` // Estimated: `5103` // Minimum execution time: 16_616 nanoseconds. - Weight::from_ref_time(17_155_000) - .saturating_add(Weight::from_proof_size(5103)) + Weight::from_parts(17_155_000, 0) + .saturating_add(Weight::from_parts(0, 5103)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1387,8 +1387,8 @@ impl WeightInfo for () { // Measured: `516` // Estimated: `8407` // Minimum execution time: 22_777 nanoseconds. - Weight::from_ref_time(23_955_000) - .saturating_add(Weight::from_proof_size(8407)) + Weight::from_parts(23_955_000, 0) + .saturating_add(Weight::from_parts(0, 8407)) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1413,8 +1413,8 @@ impl WeightInfo for () { // Measured: `934` // Estimated: `16129` // Minimum execution time: 61_131 nanoseconds. - Weight::from_ref_time(62_791_000) - .saturating_add(Weight::from_proof_size(16129)) + Weight::from_parts(62_791_000, 0) + .saturating_add(Weight::from_parts(0, 16129)) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -1424,10 +1424,10 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 1_952 nanoseconds. - Weight::from_ref_time(3_975_700) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(3_975_700, 0) + .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 11_254 - .saturating_add(Weight::from_ref_time(3_501_698).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(3_501_698, 0).saturating_mul(n.into())) } /// Storage: Nfts Item (r:2 w:0) /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) @@ -1438,8 +1438,8 @@ impl WeightInfo for () { // Measured: `524` // Estimated: `6672` // Minimum execution time: 20_327 nanoseconds. - Weight::from_ref_time(21_714_000) - .saturating_add(Weight::from_proof_size(6672)) + Weight::from_parts(21_714_000, 0) + .saturating_add(Weight::from_parts(0, 6672)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1452,8 +1452,8 @@ impl WeightInfo for () { // Measured: `511` // Estimated: `5882` // Minimum execution time: 20_668 nanoseconds. - Weight::from_ref_time(21_416_000) - .saturating_add(Weight::from_proof_size(5882)) + Weight::from_parts(21_416_000, 0) + .saturating_add(Weight::from_parts(0, 5882)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1478,8 +1478,8 @@ impl WeightInfo for () { // Measured: `1097` // Estimated: `21970` // Minimum execution time: 88_006 nanoseconds. - Weight::from_ref_time(90_390_000) - .saturating_add(Weight::from_proof_size(21970)) + Weight::from_parts(90_390_000, 0) + .saturating_add(Weight::from_parts(0, 21970)) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(11_u64)) } @@ -1505,15 +1505,15 @@ impl WeightInfo for () { // Measured: `596` // Estimated: `16180 + n * (2921 ±0)` // Minimum execution time: 124_967 nanoseconds. - Weight::from_ref_time(131_602_642) - .saturating_add(Weight::from_proof_size(16180)) + Weight::from_parts(131_602_642, 0) + .saturating_add(Weight::from_parts(0, 16180)) // Standard Error: 36_480 - .saturating_add(Weight::from_ref_time(25_811_394).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(25_811_394, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(6_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_proof_size(2921).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 2921).saturating_mul(n.into())) } /// Storage: Nfts Item (r:1 w:0) /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) @@ -1533,14 +1533,14 @@ impl WeightInfo for () { // Measured: `716` // Estimated: `14198 + n * (2921 ±0)` // Minimum execution time: 84_153 nanoseconds. - Weight::from_ref_time(96_401_623) - .saturating_add(Weight::from_proof_size(14198)) + Weight::from_parts(96_401_623, 0) + .saturating_add(Weight::from_parts(0, 14198)) // Standard Error: 70_244 - .saturating_add(Weight::from_ref_time(26_866_222).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(26_866_222, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_proof_size(2921).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 2921).saturating_mul(n.into())) } } diff --git a/frame/nis/src/mock.rs b/frame/nis/src/mock.rs index 8df9f89c16926..8594c88a5927d 100644 --- a/frame/nis/src/mock.rs +++ b/frame/nis/src/mock.rs @@ -111,7 +111,7 @@ parameter_types! { 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); + pub static MaxIntakeWeight: Weight = Weight::from_parts(2_000_000_000_000, 0); pub const ReserveId: [u8; 8] = *b"py/nis "; } diff --git a/frame/nis/src/weights.rs b/frame/nis/src/weights.rs index 36a169f16c52e..27c2f23e0e9ec 100644 --- a/frame/nis/src/weights.rs +++ b/frame/nis/src/weights.rs @@ -78,7 +78,7 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 28_814 nanoseconds. Weight::from_parts(35_245_917, 60718) // Standard Error: 189 - .saturating_add(Weight::from_ref_time(45_322).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(45_322, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -111,7 +111,7 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 34_426 nanoseconds. Weight::from_parts(36_434_166, 60718) // Standard Error: 135 - .saturating_add(Weight::from_ref_time(33_923).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(33_923, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -239,7 +239,7 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 6_758 nanoseconds. - Weight::from_ref_time(6_911_000) + Weight::from_parts(6_911_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } } @@ -260,7 +260,7 @@ impl WeightInfo for () { // Minimum execution time: 28_814 nanoseconds. Weight::from_parts(35_245_917, 60718) // Standard Error: 189 - .saturating_add(Weight::from_ref_time(45_322).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(45_322, 0).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -293,7 +293,7 @@ impl WeightInfo for () { // Minimum execution time: 34_426 nanoseconds. Weight::from_parts(36_434_166, 60718) // Standard Error: 135 - .saturating_add(Weight::from_ref_time(33_923).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(33_923, 0).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -421,7 +421,7 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 6_758 nanoseconds. - Weight::from_ref_time(6_911_000) + Weight::from_parts(6_911_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } } diff --git a/frame/node-authorization/src/weights.rs b/frame/node-authorization/src/weights.rs index f1ff9580d5a43..a4529c845c7c0 100644 --- a/frame/node-authorization/src/weights.rs +++ b/frame/node-authorization/src/weights.rs @@ -37,13 +37,13 @@ pub trait WeightInfo { } impl WeightInfo for () { - 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) } + fn add_well_known_node() -> Weight { Weight::from_parts(50_000_000, 0) } + fn remove_well_known_node() -> Weight { Weight::from_parts(50_000_000, 0) } + fn swap_well_known_node() -> Weight { Weight::from_parts(50_000_000, 0) } + fn reset_well_known_nodes() -> Weight { Weight::from_parts(50_000_000, 0) } + fn claim_node() -> Weight { Weight::from_parts(50_000_000, 0) } + fn remove_claim() -> Weight { Weight::from_parts(50_000_000, 0) } + fn transfer_node() -> Weight { Weight::from_parts(50_000_000, 0) } + fn add_connections() -> Weight { Weight::from_parts(50_000_000, 0) } + fn remove_connections() -> Weight { Weight::from_parts(50_000_000, 0) } } diff --git a/frame/nomination-pools/src/weights.rs b/frame/nomination-pools/src/weights.rs index 1c3d1c6339e8d..ca7de7be6e7c6 100644 --- a/frame/nomination-pools/src/weights.rs +++ b/frame/nomination-pools/src/weights.rs @@ -101,8 +101,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `3573` // Estimated: `37988` // Minimum execution time: 169_857 nanoseconds. - Weight::from_ref_time(173_895_000) - .saturating_add(Weight::from_proof_size(37988)) + Weight::from_parts(173_895_000, 0) + .saturating_add(Weight::from_parts(0, 37988)) .saturating_add(T::DbWeight::get().reads(17_u64)) .saturating_add(T::DbWeight::get().writes(12_u64)) } @@ -129,8 +129,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `3615` // Estimated: `38583` // Minimum execution time: 167_372 nanoseconds. - Weight::from_ref_time(168_776_000) - .saturating_add(Weight::from_proof_size(38583)) + Weight::from_parts(168_776_000, 0) + .saturating_add(Weight::from_parts(0, 38583)) .saturating_add(T::DbWeight::get().reads(14_u64)) .saturating_add(T::DbWeight::get().writes(12_u64)) } @@ -159,8 +159,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `3680` // Estimated: `41099` // Minimum execution time: 186_346 nanoseconds. - Weight::from_ref_time(191_308_000) - .saturating_add(Weight::from_proof_size(41099)) + Weight::from_parts(191_308_000, 0) + .saturating_add(Weight::from_parts(0, 41099)) .saturating_add(T::DbWeight::get().reads(15_u64)) .saturating_add(T::DbWeight::get().writes(13_u64)) } @@ -179,8 +179,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `1254` // Estimated: `13005` // Minimum execution time: 61_423 nanoseconds. - Weight::from_ref_time(63_219_000) - .saturating_add(Weight::from_proof_size(13005)) + Weight::from_parts(63_219_000, 0) + .saturating_add(Weight::from_parts(0, 13005)) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -219,8 +219,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `3858` // Estimated: `67379` // Minimum execution time: 174_532 nanoseconds. - Weight::from_ref_time(180_032_000) - .saturating_add(Weight::from_proof_size(67379)) + Weight::from_parts(180_032_000, 0) + .saturating_add(Weight::from_parts(0, 67379)) .saturating_add(T::DbWeight::get().reads(18_u64)) .saturating_add(T::DbWeight::get().writes(14_u64)) } @@ -240,10 +240,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `1779` // Estimated: `13025` // Minimum execution time: 55_327 nanoseconds. - Weight::from_ref_time(58_947_746) - .saturating_add(Weight::from_proof_size(13025)) + Weight::from_parts(58_947_746, 0) + .saturating_add(Weight::from_parts(0, 13025)) // Standard Error: 1_589 - .saturating_add(Weight::from_ref_time(40_696).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(40_696, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -271,10 +271,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `2303` // Estimated: `45696` // Minimum execution time: 105_923 nanoseconds. - Weight::from_ref_time(110_572_476) - .saturating_add(Weight::from_proof_size(45696)) + Weight::from_parts(110_572_476, 0) + .saturating_add(Weight::from_parts(0, 45696)) // Standard Error: 2_438 - .saturating_add(Weight::from_ref_time(69_045).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(69_045, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } @@ -324,8 +324,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `2690` // Estimated: `68812` // Minimum execution time: 169_700 nanoseconds. - Weight::from_ref_time(178_693_541) - .saturating_add(Weight::from_proof_size(68812)) + Weight::from_parts(178_693_541, 0) + .saturating_add(Weight::from_parts(0, 68812)) .saturating_add(T::DbWeight::get().reads(20_u64)) .saturating_add(T::DbWeight::get().writes(17_u64)) } @@ -376,8 +376,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `1321` // Estimated: `31522` // Minimum execution time: 145_976 nanoseconds. - Weight::from_ref_time(150_664_000) - .saturating_add(Weight::from_proof_size(31522)) + Weight::from_parts(150_664_000, 0) + .saturating_add(Weight::from_parts(0, 31522)) .saturating_add(T::DbWeight::get().reads(21_u64)) .saturating_add(T::DbWeight::get().writes(15_u64)) } @@ -411,14 +411,14 @@ impl WeightInfo for SubstrateWeight { // Measured: `1909` // Estimated: `21998 + n * (2520 ±0)` // Minimum execution time: 69_288 nanoseconds. - Weight::from_ref_time(71_075_293) - .saturating_add(Weight::from_proof_size(21998)) + Weight::from_parts(71_075_293, 0) + .saturating_add(Weight::from_parts(0, 21998)) // Standard Error: 10_508 - .saturating_add(Weight::from_ref_time(1_384_674).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(1_384_674, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(5_u64)) - .saturating_add(Weight::from_proof_size(2520).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 2520).saturating_mul(n.into())) } /// Storage: NominationPools BondedPools (r:1 w:1) /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) @@ -431,8 +431,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `1498` // Estimated: `8752` // Minimum execution time: 36_410 nanoseconds. - Weight::from_ref_time(37_585_000) - .saturating_add(Weight::from_proof_size(8752)) + Weight::from_parts(37_585_000, 0) + .saturating_add(Weight::from_parts(0, 8752)) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -448,10 +448,10 @@ impl WeightInfo for SubstrateWeight { // Measured: `559` // Estimated: `5883` // Minimum execution time: 14_322 nanoseconds. - Weight::from_ref_time(15_328_204) - .saturating_add(Weight::from_proof_size(5883)) + Weight::from_parts(15_328_204, 0) + .saturating_add(Weight::from_parts(0, 5883)) // Standard Error: 161 - .saturating_add(Weight::from_ref_time(1_406).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(1_406, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -470,8 +470,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 5_968 nanoseconds. - Weight::from_ref_time(6_245_000) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(6_245_000, 0) + .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(5_u64)) } /// Storage: NominationPools BondedPools (r:1 w:1) @@ -481,8 +481,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `559` // Estimated: `2639` // Minimum execution time: 18_979 nanoseconds. - Weight::from_ref_time(19_795_000) - .saturating_add(Weight::from_proof_size(2639)) + Weight::from_parts(19_795_000, 0) + .saturating_add(Weight::from_parts(0, 2639)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -509,8 +509,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `2136` // Estimated: `20489` // Minimum execution time: 68_145 nanoseconds. - Weight::from_ref_time(70_444_000) - .saturating_add(Weight::from_proof_size(20489)) + Weight::from_parts(70_444_000, 0) + .saturating_add(Weight::from_parts(0, 20489)) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -523,8 +523,8 @@ impl WeightInfo for SubstrateWeight { // Measured: `542` // Estimated: `5228` // Minimum execution time: 15_112 nanoseconds. - Weight::from_ref_time(15_897_000) - .saturating_add(Weight::from_proof_size(5228)) + Weight::from_parts(15_897_000, 0) + .saturating_add(Weight::from_parts(0, 5228)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -563,8 +563,8 @@ impl WeightInfo for () { // Measured: `3573` // Estimated: `37988` // Minimum execution time: 169_857 nanoseconds. - Weight::from_ref_time(173_895_000) - .saturating_add(Weight::from_proof_size(37988)) + Weight::from_parts(173_895_000, 0) + .saturating_add(Weight::from_parts(0, 37988)) .saturating_add(RocksDbWeight::get().reads(17_u64)) .saturating_add(RocksDbWeight::get().writes(12_u64)) } @@ -591,8 +591,8 @@ impl WeightInfo for () { // Measured: `3615` // Estimated: `38583` // Minimum execution time: 167_372 nanoseconds. - Weight::from_ref_time(168_776_000) - .saturating_add(Weight::from_proof_size(38583)) + Weight::from_parts(168_776_000, 0) + .saturating_add(Weight::from_parts(0, 38583)) .saturating_add(RocksDbWeight::get().reads(14_u64)) .saturating_add(RocksDbWeight::get().writes(12_u64)) } @@ -621,8 +621,8 @@ impl WeightInfo for () { // Measured: `3680` // Estimated: `41099` // Minimum execution time: 186_346 nanoseconds. - Weight::from_ref_time(191_308_000) - .saturating_add(Weight::from_proof_size(41099)) + Weight::from_parts(191_308_000, 0) + .saturating_add(Weight::from_parts(0, 41099)) .saturating_add(RocksDbWeight::get().reads(15_u64)) .saturating_add(RocksDbWeight::get().writes(13_u64)) } @@ -641,8 +641,8 @@ impl WeightInfo for () { // Measured: `1254` // Estimated: `13005` // Minimum execution time: 61_423 nanoseconds. - Weight::from_ref_time(63_219_000) - .saturating_add(Weight::from_proof_size(13005)) + Weight::from_parts(63_219_000, 0) + .saturating_add(Weight::from_parts(0, 13005)) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -681,8 +681,8 @@ impl WeightInfo for () { // Measured: `3858` // Estimated: `67379` // Minimum execution time: 174_532 nanoseconds. - Weight::from_ref_time(180_032_000) - .saturating_add(Weight::from_proof_size(67379)) + Weight::from_parts(180_032_000, 0) + .saturating_add(Weight::from_parts(0, 67379)) .saturating_add(RocksDbWeight::get().reads(18_u64)) .saturating_add(RocksDbWeight::get().writes(14_u64)) } @@ -702,10 +702,10 @@ impl WeightInfo for () { // Measured: `1779` // Estimated: `13025` // Minimum execution time: 55_327 nanoseconds. - Weight::from_ref_time(58_947_746) - .saturating_add(Weight::from_proof_size(13025)) + Weight::from_parts(58_947_746, 0) + .saturating_add(Weight::from_parts(0, 13025)) // Standard Error: 1_589 - .saturating_add(Weight::from_ref_time(40_696).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(40_696, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -733,10 +733,10 @@ impl WeightInfo for () { // Measured: `2303` // Estimated: `45696` // Minimum execution time: 105_923 nanoseconds. - Weight::from_ref_time(110_572_476) - .saturating_add(Weight::from_proof_size(45696)) + Weight::from_parts(110_572_476, 0) + .saturating_add(Weight::from_parts(0, 45696)) // Standard Error: 2_438 - .saturating_add(Weight::from_ref_time(69_045).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(69_045, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } @@ -786,8 +786,8 @@ impl WeightInfo for () { // Measured: `2690` // Estimated: `68812` // Minimum execution time: 169_700 nanoseconds. - Weight::from_ref_time(178_693_541) - .saturating_add(Weight::from_proof_size(68812)) + Weight::from_parts(178_693_541, 0) + .saturating_add(Weight::from_parts(0, 68812)) .saturating_add(RocksDbWeight::get().reads(20_u64)) .saturating_add(RocksDbWeight::get().writes(17_u64)) } @@ -838,8 +838,8 @@ impl WeightInfo for () { // Measured: `1321` // Estimated: `31522` // Minimum execution time: 145_976 nanoseconds. - Weight::from_ref_time(150_664_000) - .saturating_add(Weight::from_proof_size(31522)) + Weight::from_parts(150_664_000, 0) + .saturating_add(Weight::from_parts(0, 31522)) .saturating_add(RocksDbWeight::get().reads(21_u64)) .saturating_add(RocksDbWeight::get().writes(15_u64)) } @@ -873,14 +873,14 @@ impl WeightInfo for () { // Measured: `1909` // Estimated: `21998 + n * (2520 ±0)` // Minimum execution time: 69_288 nanoseconds. - Weight::from_ref_time(71_075_293) - .saturating_add(Weight::from_proof_size(21998)) + Weight::from_parts(71_075_293, 0) + .saturating_add(Weight::from_parts(0, 21998)) // Standard Error: 10_508 - .saturating_add(Weight::from_ref_time(1_384_674).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(1_384_674, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(5_u64)) - .saturating_add(Weight::from_proof_size(2520).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 2520).saturating_mul(n.into())) } /// Storage: NominationPools BondedPools (r:1 w:1) /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) @@ -893,8 +893,8 @@ impl WeightInfo for () { // Measured: `1498` // Estimated: `8752` // Minimum execution time: 36_410 nanoseconds. - Weight::from_ref_time(37_585_000) - .saturating_add(Weight::from_proof_size(8752)) + Weight::from_parts(37_585_000, 0) + .saturating_add(Weight::from_parts(0, 8752)) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -910,10 +910,10 @@ impl WeightInfo for () { // Measured: `559` // Estimated: `5883` // Minimum execution time: 14_322 nanoseconds. - Weight::from_ref_time(15_328_204) - .saturating_add(Weight::from_proof_size(5883)) + Weight::from_parts(15_328_204, 0) + .saturating_add(Weight::from_parts(0, 5883)) // Standard Error: 161 - .saturating_add(Weight::from_ref_time(1_406).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(1_406, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -932,8 +932,8 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 5_968 nanoseconds. - Weight::from_ref_time(6_245_000) - .saturating_add(Weight::from_proof_size(0)) + Weight::from_parts(6_245_000, 0) + .saturating_add(Weight::from_parts(0, 0)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } /// Storage: NominationPools BondedPools (r:1 w:1) @@ -943,8 +943,8 @@ impl WeightInfo for () { // Measured: `559` // Estimated: `2639` // Minimum execution time: 18_979 nanoseconds. - Weight::from_ref_time(19_795_000) - .saturating_add(Weight::from_proof_size(2639)) + Weight::from_parts(19_795_000, 0) + .saturating_add(Weight::from_parts(0, 2639)) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -971,8 +971,8 @@ impl WeightInfo for () { // Measured: `2136` // Estimated: `20489` // Minimum execution time: 68_145 nanoseconds. - Weight::from_ref_time(70_444_000) - .saturating_add(Weight::from_proof_size(20489)) + Weight::from_parts(70_444_000, 0) + .saturating_add(Weight::from_parts(0, 20489)) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -985,8 +985,8 @@ impl WeightInfo for () { // Measured: `542` // Estimated: `5228` // Minimum execution time: 15_112 nanoseconds. - Weight::from_ref_time(15_897_000) - .saturating_add(Weight::from_proof_size(5228)) + Weight::from_parts(15_897_000, 0) + .saturating_add(Weight::from_parts(0, 5228)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/frame/preimage/src/weights.rs b/frame/preimage/src/weights.rs index 7d181be01b742..fa6bdc972fa47 100644 --- a/frame/preimage/src/weights.rs +++ b/frame/preimage/src/weights.rs @@ -77,7 +77,7 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 23_484 nanoseconds. Weight::from_parts(23_828_000, 2566) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_705).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_705, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -93,7 +93,7 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 14_812 nanoseconds. Weight::from_parts(14_949_000, 2566) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_707).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_707, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -109,7 +109,7 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 14_185 nanoseconds. Weight::from_parts(14_398_000, 2566) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_709).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_709, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -234,7 +234,7 @@ impl WeightInfo for () { // Minimum execution time: 23_484 nanoseconds. Weight::from_parts(23_828_000, 2566) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_705).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_705, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -250,7 +250,7 @@ impl WeightInfo for () { // Minimum execution time: 14_812 nanoseconds. Weight::from_parts(14_949_000, 2566) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_707).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_707, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -266,7 +266,7 @@ impl WeightInfo for () { // Minimum execution time: 14_185 nanoseconds. Weight::from_parts(14_398_000, 2566) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_709).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_709, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } diff --git a/frame/proxy/src/weights.rs b/frame/proxy/src/weights.rs index 5e85e148a0397..5b70b61e569b4 100644 --- a/frame/proxy/src/weights.rs +++ b/frame/proxy/src/weights.rs @@ -73,7 +73,7 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 14_461 nanoseconds. Weight::from_parts(14_913_927, 3716) // Standard Error: 1_174 - .saturating_add(Weight::from_ref_time(36_087).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(36_087, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: Proxy Proxies (r:1 w:0) @@ -91,9 +91,9 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 31_523 nanoseconds. Weight::from_parts(31_116_270, 11027) // Standard Error: 1_789 - .saturating_add(Weight::from_ref_time(135_656).saturating_mul(a.into())) + .saturating_add(Weight::from_parts(135_656, 0).saturating_mul(a.into())) // Standard Error: 1_849 - .saturating_add(Weight::from_ref_time(53_893).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(53_893, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -110,9 +110,9 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 19_363 nanoseconds. Weight::from_parts(20_282_191, 7311) // Standard Error: 1_084 - .saturating_add(Weight::from_ref_time(133_825).saturating_mul(a.into())) + .saturating_add(Weight::from_parts(133_825, 0).saturating_mul(a.into())) // Standard Error: 1_120 - .saturating_add(Weight::from_ref_time(3_434).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(3_434, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -129,9 +129,9 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 19_363 nanoseconds. Weight::from_parts(20_211_584, 7311) // Standard Error: 1_171 - .saturating_add(Weight::from_ref_time(136_984).saturating_mul(a.into())) + .saturating_add(Weight::from_parts(136_984, 0).saturating_mul(a.into())) // Standard Error: 1_210 - .saturating_add(Weight::from_ref_time(3_686).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(3_686, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -150,9 +150,9 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 27_811 nanoseconds. Weight::from_parts(27_965_813, 11027) // Standard Error: 1_987 - .saturating_add(Weight::from_ref_time(124_133).saturating_mul(a.into())) + .saturating_add(Weight::from_parts(124_133, 0).saturating_mul(a.into())) // Standard Error: 2_053 - .saturating_add(Weight::from_ref_time(54_692).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(54_692, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -166,7 +166,7 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 20_922 nanoseconds. Weight::from_parts(21_551_797, 3716) // Standard Error: 1_425 - .saturating_add(Weight::from_ref_time(58_434).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(58_434, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -180,7 +180,7 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 20_812 nanoseconds. Weight::from_parts(21_660_732, 3716) // Standard Error: 1_438 - .saturating_add(Weight::from_ref_time(68_740).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(68_740, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -194,7 +194,7 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 16_786 nanoseconds. Weight::from_parts(17_249_958, 3716) // Standard Error: 1_007 - .saturating_add(Weight::from_ref_time(37_546).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(37_546, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -208,7 +208,7 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 22_764 nanoseconds. Weight::from_parts(23_539_039, 3716) // Standard Error: 814 - .saturating_add(Weight::from_ref_time(144).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(144, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -222,7 +222,7 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 17_720 nanoseconds. Weight::from_parts(18_428_849, 3716) // Standard Error: 1_093 - .saturating_add(Weight::from_ref_time(34_600).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(34_600, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -240,7 +240,7 @@ impl WeightInfo for () { // Minimum execution time: 14_461 nanoseconds. Weight::from_parts(14_913_927, 3716) // Standard Error: 1_174 - .saturating_add(Weight::from_ref_time(36_087).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(36_087, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: Proxy Proxies (r:1 w:0) @@ -258,9 +258,9 @@ impl WeightInfo for () { // Minimum execution time: 31_523 nanoseconds. Weight::from_parts(31_116_270, 11027) // Standard Error: 1_789 - .saturating_add(Weight::from_ref_time(135_656).saturating_mul(a.into())) + .saturating_add(Weight::from_parts(135_656, 0).saturating_mul(a.into())) // Standard Error: 1_849 - .saturating_add(Weight::from_ref_time(53_893).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(53_893, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -277,9 +277,9 @@ impl WeightInfo for () { // Minimum execution time: 19_363 nanoseconds. Weight::from_parts(20_282_191, 7311) // Standard Error: 1_084 - .saturating_add(Weight::from_ref_time(133_825).saturating_mul(a.into())) + .saturating_add(Weight::from_parts(133_825, 0).saturating_mul(a.into())) // Standard Error: 1_120 - .saturating_add(Weight::from_ref_time(3_434).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(3_434, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -296,9 +296,9 @@ impl WeightInfo for () { // Minimum execution time: 19_363 nanoseconds. Weight::from_parts(20_211_584, 7311) // Standard Error: 1_171 - .saturating_add(Weight::from_ref_time(136_984).saturating_mul(a.into())) + .saturating_add(Weight::from_parts(136_984, 0).saturating_mul(a.into())) // Standard Error: 1_210 - .saturating_add(Weight::from_ref_time(3_686).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(3_686, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -317,9 +317,9 @@ impl WeightInfo for () { // Minimum execution time: 27_811 nanoseconds. Weight::from_parts(27_965_813, 11027) // Standard Error: 1_987 - .saturating_add(Weight::from_ref_time(124_133).saturating_mul(a.into())) + .saturating_add(Weight::from_parts(124_133, 0).saturating_mul(a.into())) // Standard Error: 2_053 - .saturating_add(Weight::from_ref_time(54_692).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(54_692, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -333,7 +333,7 @@ impl WeightInfo for () { // Minimum execution time: 20_922 nanoseconds. Weight::from_parts(21_551_797, 3716) // Standard Error: 1_425 - .saturating_add(Weight::from_ref_time(58_434).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(58_434, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -347,7 +347,7 @@ impl WeightInfo for () { // Minimum execution time: 20_812 nanoseconds. Weight::from_parts(21_660_732, 3716) // Standard Error: 1_438 - .saturating_add(Weight::from_ref_time(68_740).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(68_740, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -361,7 +361,7 @@ impl WeightInfo for () { // Minimum execution time: 16_786 nanoseconds. Weight::from_parts(17_249_958, 3716) // Standard Error: 1_007 - .saturating_add(Weight::from_ref_time(37_546).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(37_546, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -375,7 +375,7 @@ impl WeightInfo for () { // Minimum execution time: 22_764 nanoseconds. Weight::from_parts(23_539_039, 3716) // Standard Error: 814 - .saturating_add(Weight::from_ref_time(144).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(144, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -389,7 +389,7 @@ impl WeightInfo for () { // Minimum execution time: 17_720 nanoseconds. Weight::from_parts(18_428_849, 3716) // Standard Error: 1_093 - .saturating_add(Weight::from_ref_time(34_600).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(34_600, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/frame/ranked-collective/src/weights.rs b/frame/ranked-collective/src/weights.rs index 1f50441aabe36..8d6c1620d81f8 100644 --- a/frame/ranked-collective/src/weights.rs +++ b/frame/ranked-collective/src/weights.rs @@ -92,12 +92,12 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 26_177 nanoseconds. Weight::from_parts(29_245_248, 10064) // Standard Error: 18_611 - .saturating_add(Weight::from_ref_time(10_916_516).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(10_916_516, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_proof_size(7547).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 7547).saturating_mul(r.into())) } /// Storage: RankedCollective Members (r:1 w:1) /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) @@ -115,7 +115,7 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 18_953 nanoseconds. Weight::from_parts(19_570_567, 5006) // Standard Error: 4_156 - .saturating_add(Weight::from_ref_time(263_843).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(263_843, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -135,7 +135,7 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 26_243 nanoseconds. Weight::from_parts(28_532_816, 10064) // Standard Error: 22_689 - .saturating_add(Weight::from_ref_time(614_464).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(614_464, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -170,7 +170,7 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 13_245 nanoseconds. Weight::from_parts(17_420_271, 5394) // Standard Error: 1_503 - .saturating_add(Weight::from_ref_time(952_500).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(952_500, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) } @@ -211,12 +211,12 @@ impl WeightInfo for () { // Minimum execution time: 26_177 nanoseconds. Weight::from_parts(29_245_248, 10064) // Standard Error: 18_611 - .saturating_add(Weight::from_ref_time(10_916_516).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(10_916_516, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_proof_size(7547).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 7547).saturating_mul(r.into())) } /// Storage: RankedCollective Members (r:1 w:1) /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) @@ -234,7 +234,7 @@ impl WeightInfo for () { // Minimum execution time: 18_953 nanoseconds. Weight::from_parts(19_570_567, 5006) // Standard Error: 4_156 - .saturating_add(Weight::from_ref_time(263_843).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(263_843, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -254,7 +254,7 @@ impl WeightInfo for () { // Minimum execution time: 26_243 nanoseconds. Weight::from_parts(28_532_816, 10064) // Standard Error: 22_689 - .saturating_add(Weight::from_ref_time(614_464).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(614_464, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -289,7 +289,7 @@ impl WeightInfo for () { // Minimum execution time: 13_245 nanoseconds. Weight::from_parts(17_420_271, 5394) // Standard Error: 1_503 - .saturating_add(Weight::from_ref_time(952_500).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(952_500, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) } diff --git a/frame/recovery/src/weights.rs b/frame/recovery/src/weights.rs index 7a67c716fafc6..6f8818f819bad 100644 --- a/frame/recovery/src/weights.rs +++ b/frame/recovery/src/weights.rs @@ -79,7 +79,7 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 8_893 nanoseconds. - Weight::from_ref_time(9_177_000) + Weight::from_parts(9_177_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Recovery Recoverable (r:1 w:1) @@ -92,7 +92,7 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 20_662 nanoseconds. Weight::from_parts(21_378_064, 2826) // Standard Error: 3_350 - .saturating_add(Weight::from_ref_time(83_738).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(83_738, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -121,7 +121,7 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 17_837 nanoseconds. Weight::from_parts(18_429_664, 5690) // Standard Error: 3_187 - .saturating_add(Weight::from_ref_time(143_648).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(143_648, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -139,7 +139,7 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 21_960 nanoseconds. Weight::from_parts(22_529_644, 8245) // Standard Error: 2_945 - .saturating_add(Weight::from_ref_time(85_604).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(85_604, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -155,7 +155,7 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 26_054 nanoseconds. Weight::from_parts(26_724_866, 5467) // Standard Error: 2_645 - .saturating_add(Weight::from_ref_time(104_301).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(104_301, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -171,7 +171,7 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 25_110 nanoseconds. Weight::from_parts(25_805_837, 5690) // Standard Error: 2_732 - .saturating_add(Weight::from_ref_time(73_458).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(73_458, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -207,7 +207,7 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 8_893 nanoseconds. - Weight::from_ref_time(9_177_000) + Weight::from_parts(9_177_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Recovery Recoverable (r:1 w:1) @@ -220,7 +220,7 @@ impl WeightInfo for () { // Minimum execution time: 20_662 nanoseconds. Weight::from_parts(21_378_064, 2826) // Standard Error: 3_350 - .saturating_add(Weight::from_ref_time(83_738).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(83_738, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -249,7 +249,7 @@ impl WeightInfo for () { // Minimum execution time: 17_837 nanoseconds. Weight::from_parts(18_429_664, 5690) // Standard Error: 3_187 - .saturating_add(Weight::from_ref_time(143_648).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(143_648, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -267,7 +267,7 @@ impl WeightInfo for () { // Minimum execution time: 21_960 nanoseconds. Weight::from_parts(22_529_644, 8245) // Standard Error: 2_945 - .saturating_add(Weight::from_ref_time(85_604).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(85_604, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -283,7 +283,7 @@ impl WeightInfo for () { // Minimum execution time: 26_054 nanoseconds. Weight::from_parts(26_724_866, 5467) // Standard Error: 2_645 - .saturating_add(Weight::from_ref_time(104_301).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(104_301, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -299,7 +299,7 @@ impl WeightInfo for () { // Minimum execution time: 25_110 nanoseconds. Weight::from_parts(25_805_837, 5690) // Standard Error: 2_732 - .saturating_add(Weight::from_ref_time(73_458).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(73_458, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/frame/remark/src/weights.rs b/frame/remark/src/weights.rs index 0e18e10c69561..f9fcb73803716 100644 --- a/frame/remark/src/weights.rs +++ b/frame/remark/src/weights.rs @@ -60,9 +60,9 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 8_404 nanoseconds. - Weight::from_ref_time(343_031) + Weight::from_parts(343_031, 0) // Standard Error: 1 - .saturating_add(Weight::from_ref_time(1_404).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(1_404, 0).saturating_mul(l.into())) } } @@ -74,8 +74,8 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 8_404 nanoseconds. - Weight::from_ref_time(343_031) + Weight::from_parts(343_031, 0) // Standard Error: 1 - .saturating_add(Weight::from_ref_time(1_404).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(1_404, 0).saturating_mul(l.into())) } } diff --git a/frame/scheduler/src/mock.rs b/frame/scheduler/src/mock.rs index 5a2328971964f..914a97ab9d5d7 100644 --- a/frame/scheduler/src/mock.rs +++ b/frame/scheduler/src/mock.rs @@ -121,7 +121,7 @@ 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).set_proof_size(u64::MAX), + Weight::from_parts(2_000_000_000_000, u64::MAX), ); } impl system::Config for Test { @@ -169,40 +169,40 @@ impl pallet_preimage::Config for Test { pub struct TestWeightInfo; impl WeightInfo for TestWeightInfo { fn service_agendas_base() -> Weight { - Weight::from_ref_time(0b0000_0001) + Weight::from_parts(0b0000_0001, 0) } fn service_agenda_base(i: u32) -> Weight { - Weight::from_ref_time((i << 8) as u64 + 0b0000_0010) + Weight::from_parts((i << 8) as u64 + 0b0000_0010, 0) } fn service_task_base() -> Weight { - Weight::from_ref_time(0b0000_0100) + Weight::from_parts(0b0000_0100, 0) } fn service_task_periodic() -> Weight { - Weight::from_ref_time(0b0000_1100) + Weight::from_parts(0b0000_1100, 0) } fn service_task_named() -> Weight { - Weight::from_ref_time(0b0001_0100) + Weight::from_parts(0b0001_0100, 0) } fn service_task_fetched(s: u32) -> Weight { - Weight::from_ref_time((s << 8) as u64 + 0b0010_0100) + Weight::from_parts((s << 8) as u64 + 0b0010_0100, 0) } fn execute_dispatch_signed() -> Weight { - Weight::from_ref_time(0b0100_0000) + Weight::from_parts(0b0100_0000, 0) } fn execute_dispatch_unsigned() -> Weight { - Weight::from_ref_time(0b1000_0000) + Weight::from_parts(0b1000_0000, 0) } fn schedule(_s: u32) -> Weight { - Weight::from_ref_time(50) + Weight::from_parts(50, 0) } fn cancel(_s: u32) -> Weight { - Weight::from_ref_time(50) + Weight::from_parts(50, 0) } fn schedule_named(_s: u32) -> Weight { - Weight::from_ref_time(50) + Weight::from_parts(50, 0) } fn cancel_named(_s: u32) -> Weight { - Weight::from_ref_time(50) + Weight::from_parts(50, 0) } } parameter_types! { diff --git a/frame/scheduler/src/tests.rs b/frame/scheduler/src/tests.rs index 258e6a281dfa9..a0cac897d43df 100644 --- a/frame/scheduler/src/tests.rs +++ b/frame/scheduler/src/tests.rs @@ -33,7 +33,7 @@ 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(10) }); + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_parts(10, 0) }); assert!(!::BaseCallFilter::contains(&call)); assert_ok!(Scheduler::do_schedule( DispatchTime::At(4), @@ -55,7 +55,7 @@ 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(10) }); + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_parts(10, 0) }); let hash = ::Hashing::hash_of(&call); let len = call.using_encoded(|x| x.len()) as u32; // Important to use here `Bounded::Lookup` to ensure that we request the hash. @@ -79,7 +79,7 @@ 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(10) }); + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_parts(10, 0) }); 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( @@ -103,7 +103,7 @@ 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(10) }); + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_parts(10, 0) }); assert!(!::BaseCallFilter::contains(&call)); assert_ok!(Scheduler::do_schedule( DispatchTime::After(0), @@ -131,7 +131,7 @@ fn periodic_scheduling_works() { root(), Preimage::bound(RuntimeCall::Logger(logger::Call::log { i: 42, - weight: Weight::from_ref_time(10) + weight: Weight::from_parts(10, 0) })) .unwrap() )); @@ -156,7 +156,7 @@ 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(10) }); + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_parts(10, 0) }); assert!(!::BaseCallFilter::contains(&call)); assert_eq!( Scheduler::do_schedule( @@ -195,7 +195,7 @@ 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(10) }); + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_parts(10, 0) }); assert!(!::BaseCallFilter::contains(&call)); assert_eq!( Scheduler::do_schedule_named( @@ -235,7 +235,7 @@ 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(10) }); + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_parts(10, 0) }); assert!(!::BaseCallFilter::contains(&call)); assert_eq!( Scheduler::do_schedule_named( @@ -293,7 +293,7 @@ fn cancel_named_scheduling_works_with_normal_cancel() { root(), Preimage::bound(RuntimeCall::Logger(LoggerCall::log { i: 69, - weight: Weight::from_ref_time(10), + weight: Weight::from_parts(10, 0), })) .unwrap(), ) @@ -305,7 +305,7 @@ fn cancel_named_scheduling_works_with_normal_cancel() { root(), Preimage::bound(RuntimeCall::Logger(LoggerCall::log { i: 42, - weight: Weight::from_ref_time(10), + weight: Weight::from_parts(10, 0), })) .unwrap(), ) @@ -331,7 +331,7 @@ fn cancel_named_periodic_scheduling_works() { root(), Preimage::bound(RuntimeCall::Logger(LoggerCall::log { i: 42, - weight: Weight::from_ref_time(10), + weight: Weight::from_parts(10, 0), })) .unwrap(), ) @@ -345,7 +345,7 @@ fn cancel_named_periodic_scheduling_works() { root(), Preimage::bound(RuntimeCall::Logger(LoggerCall::log { i: 69, - weight: Weight::from_ref_time(10) + weight: Weight::from_parts(10, 0) })) .unwrap(), ) @@ -359,7 +359,7 @@ fn cancel_named_periodic_scheduling_works() { root(), Preimage::bound(RuntimeCall::Logger(LoggerCall::log { i: 69, - weight: Weight::from_ref_time(10), + weight: Weight::from_parts(10, 0), })) .unwrap(), ) @@ -581,12 +581,12 @@ fn scheduler_respects_priority_ordering_with_soft_deadlines() { #[test] fn on_initialize_weight_is_correct() { new_test_ext().execute_with(|| { - let call_weight = Weight::from_ref_time(25); + let call_weight = Weight::from_parts(25, 0); // Named let call = RuntimeCall::Logger(LoggerCall::log { i: 3, - weight: call_weight + Weight::from_ref_time(1), + weight: call_weight + Weight::from_parts(1, 0), }); assert_ok!(Scheduler::do_schedule_named( [1u8; 32], @@ -598,7 +598,7 @@ fn on_initialize_weight_is_correct() { )); let call = RuntimeCall::Logger(LoggerCall::log { i: 42, - weight: call_weight + Weight::from_ref_time(2), + weight: call_weight + Weight::from_parts(2, 0), }); // Anon Periodic assert_ok!(Scheduler::do_schedule( @@ -610,7 +610,7 @@ fn on_initialize_weight_is_correct() { )); let call = RuntimeCall::Logger(LoggerCall::log { i: 69, - weight: call_weight + Weight::from_ref_time(3), + weight: call_weight + Weight::from_parts(3, 0), }); // Anon assert_ok!(Scheduler::do_schedule( @@ -623,7 +623,7 @@ fn on_initialize_weight_is_correct() { // Named Periodic let call = RuntimeCall::Logger(LoggerCall::log { i: 2600, - weight: call_weight + Weight::from_ref_time(4), + weight: call_weight + Weight::from_parts(4, 0), }); assert_ok!(Scheduler::do_schedule_named( [2u8; 32], @@ -641,7 +641,7 @@ fn on_initialize_weight_is_correct() { TestWeightInfo::service_agenda_base(1) + ::service_task(None, true, true) + TestWeightInfo::execute_dispatch_unsigned() + - call_weight + Weight::from_ref_time(4) + call_weight + Weight::from_parts(4, 0) ); assert_eq!(IncompleteSince::::get(), None); assert_eq!(logger::log(), vec![(root(), 2600u32)]); @@ -653,10 +653,10 @@ fn on_initialize_weight_is_correct() { TestWeightInfo::service_agenda_base(2) + ::service_task(None, false, true) + TestWeightInfo::execute_dispatch_unsigned() + - call_weight + Weight::from_ref_time(3) + + call_weight + Weight::from_parts(3, 0) + ::service_task(None, false, false) + TestWeightInfo::execute_dispatch_unsigned() + - call_weight + Weight::from_ref_time(2) + call_weight + Weight::from_parts(2, 0) ); assert_eq!(IncompleteSince::::get(), None); assert_eq!(logger::log(), vec![(root(), 2600u32), (root(), 69u32), (root(), 42u32)]); @@ -668,7 +668,7 @@ fn on_initialize_weight_is_correct() { TestWeightInfo::service_agenda_base(1) + ::service_task(None, true, false) + TestWeightInfo::execute_dispatch_unsigned() + - call_weight + Weight::from_ref_time(1) + call_weight + Weight::from_parts(1, 0) ); assert_eq!(IncompleteSince::::get(), None); assert_eq!( @@ -690,11 +690,11 @@ fn root_calls_works() { new_test_ext().execute_with(|| { let call = Box::new(RuntimeCall::Logger(LoggerCall::log { i: 69, - weight: Weight::from_ref_time(10), + weight: Weight::from_parts(10, 0), })); let call2 = Box::new(RuntimeCall::Logger(LoggerCall::log { i: 42, - weight: Weight::from_ref_time(10), + weight: Weight::from_parts(10, 0), })); assert_ok!( Scheduler::schedule_named(RuntimeOrigin::root(), [1u8; 32], 4, None, 127, call,) @@ -719,15 +719,15 @@ fn fails_to_schedule_task_in_the_past() { let call1 = Box::new(RuntimeCall::Logger(LoggerCall::log { i: 69, - weight: Weight::from_ref_time(10), + weight: Weight::from_parts(10, 0), })); let call2 = Box::new(RuntimeCall::Logger(LoggerCall::log { i: 42, - weight: Weight::from_ref_time(10), + weight: Weight::from_parts(10, 0), })); let call3 = Box::new(RuntimeCall::Logger(LoggerCall::log { i: 42, - weight: Weight::from_ref_time(10), + weight: Weight::from_parts(10, 0), })); assert_noop!( @@ -752,11 +752,11 @@ fn should_use_origin() { new_test_ext().execute_with(|| { let call = Box::new(RuntimeCall::Logger(LoggerCall::log { i: 69, - weight: Weight::from_ref_time(10), + weight: Weight::from_parts(10, 0), })); let call2 = Box::new(RuntimeCall::Logger(LoggerCall::log { i: 42, - weight: Weight::from_ref_time(10), + weight: Weight::from_parts(10, 0), })); assert_ok!(Scheduler::schedule_named( system::RawOrigin::Signed(1).into(), @@ -784,11 +784,11 @@ fn should_check_origin() { new_test_ext().execute_with(|| { let call = Box::new(RuntimeCall::Logger(LoggerCall::log { i: 69, - weight: Weight::from_ref_time(10), + weight: Weight::from_parts(10, 0), })); let call2 = Box::new(RuntimeCall::Logger(LoggerCall::log { i: 42, - weight: Weight::from_ref_time(10), + weight: Weight::from_parts(10, 0), })); assert_noop!( Scheduler::schedule_named( @@ -813,11 +813,11 @@ 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(10), + weight: Weight::from_parts(10, 0), })); let call2 = Box::new(RuntimeCall::Logger(LoggerCall::log_without_filter { i: 42, - weight: Weight::from_ref_time(10), + weight: Weight::from_parts(10, 0), })); assert_ok!(Scheduler::schedule_named( system::RawOrigin::Signed(1).into(), @@ -861,7 +861,7 @@ fn migration_to_v4_works() { priority: i as u8 + 10, call: RuntimeCall::Logger(LoggerCall::log { i: 96, - weight: Weight::from_ref_time(100), + weight: Weight::from_parts(100, 0), }), maybe_periodic: None, }), @@ -871,7 +871,7 @@ fn migration_to_v4_works() { priority: 123, call: RuntimeCall::Logger(LoggerCall::log { i: 69, - weight: Weight::from_ref_time(10), + weight: Weight::from_parts(10, 0), }), maybe_periodic: Some((456u64, 10)), }), @@ -892,7 +892,7 @@ fn migration_to_v4_works() { priority: 10, call: Preimage::bound(RuntimeCall::Logger(LoggerCall::log { i: 96, - weight: Weight::from_ref_time(100), + weight: Weight::from_parts(100, 0), })) .unwrap(), maybe_periodic: None, @@ -905,7 +905,7 @@ fn migration_to_v4_works() { priority: 123, call: Preimage::bound(RuntimeCall::Logger(LoggerCall::log { i: 69, - weight: Weight::from_ref_time(10), + weight: Weight::from_parts(10, 0), })) .unwrap(), maybe_periodic: Some((456u64, 10)), @@ -922,7 +922,7 @@ fn migration_to_v4_works() { priority: 11, call: Preimage::bound(RuntimeCall::Logger(LoggerCall::log { i: 96, - weight: Weight::from_ref_time(100), + weight: Weight::from_parts(100, 0), })) .unwrap(), maybe_periodic: None, @@ -935,7 +935,7 @@ fn migration_to_v4_works() { priority: 123, call: Preimage::bound(RuntimeCall::Logger(LoggerCall::log { i: 69, - weight: Weight::from_ref_time(10), + weight: Weight::from_parts(10, 0), })) .unwrap(), maybe_periodic: Some((456u64, 10)), @@ -952,7 +952,7 @@ fn migration_to_v4_works() { priority: 12, call: Preimage::bound(RuntimeCall::Logger(LoggerCall::log { i: 96, - weight: Weight::from_ref_time(100), + weight: Weight::from_parts(100, 0), })) .unwrap(), maybe_periodic: None, @@ -965,7 +965,7 @@ fn migration_to_v4_works() { priority: 123, call: Preimage::bound(RuntimeCall::Logger(LoggerCall::log { i: 69, - weight: Weight::from_ref_time(10), + weight: Weight::from_parts(10, 0), })) .unwrap(), maybe_periodic: Some((456u64, 10)), @@ -998,7 +998,7 @@ fn test_migrate_origin() { priority: i as u8 + 10, call: Preimage::bound(RuntimeCall::Logger(LoggerCall::log { i: 96, - weight: Weight::from_ref_time(100), + weight: Weight::from_parts(100, 0), })) .unwrap(), origin: 3u32, @@ -1012,7 +1012,7 @@ fn test_migrate_origin() { origin: 2u32, call: Preimage::bound(RuntimeCall::Logger(LoggerCall::log { i: 69, - weight: Weight::from_ref_time(10), + weight: Weight::from_parts(10, 0), })) .unwrap(), maybe_periodic: Some((456u64, 10)), @@ -1045,7 +1045,7 @@ fn test_migrate_origin() { priority: 10, call: Preimage::bound(RuntimeCall::Logger(LoggerCall::log { i: 96, - weight: Weight::from_ref_time(100) + weight: Weight::from_parts(100, 0) })) .unwrap(), maybe_periodic: None, @@ -1058,7 +1058,7 @@ fn test_migrate_origin() { priority: 123, call: Preimage::bound(RuntimeCall::Logger(LoggerCall::log { i: 69, - weight: Weight::from_ref_time(10) + weight: Weight::from_parts(10, 0) })) .unwrap(), maybe_periodic: Some((456u64, 10)), @@ -1075,7 +1075,7 @@ fn test_migrate_origin() { priority: 11, call: Preimage::bound(RuntimeCall::Logger(LoggerCall::log { i: 96, - weight: Weight::from_ref_time(100) + weight: Weight::from_parts(100, 0) })) .unwrap(), maybe_periodic: None, @@ -1088,7 +1088,7 @@ fn test_migrate_origin() { priority: 123, call: Preimage::bound(RuntimeCall::Logger(LoggerCall::log { i: 69, - weight: Weight::from_ref_time(10) + weight: Weight::from_parts(10, 0) })) .unwrap(), maybe_periodic: Some((456u64, 10)), @@ -1105,7 +1105,7 @@ fn test_migrate_origin() { priority: 12, call: Preimage::bound(RuntimeCall::Logger(LoggerCall::log { i: 96, - weight: Weight::from_ref_time(100) + weight: Weight::from_parts(100, 0) })) .unwrap(), maybe_periodic: None, @@ -1118,7 +1118,7 @@ fn test_migrate_origin() { priority: 123, call: Preimage::bound(RuntimeCall::Logger(LoggerCall::log { i: 69, - weight: Weight::from_ref_time(10) + weight: Weight::from_parts(10, 0) })) .unwrap(), maybe_periodic: Some((456u64, 10)), @@ -1136,7 +1136,7 @@ fn test_migrate_origin() { 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) }); + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_parts(1000, 0) }); let hash = ::Hashing::hash_of(&call); let len = call.using_encoded(|x| x.len()) as u32; // Important to use here `Bounded::Lookup` to ensure that we request the hash. @@ -1204,7 +1204,7 @@ 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) }); + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_parts(10, 0) }); // Schedule a call. let _address = >::schedule( @@ -1233,7 +1233,7 @@ 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) }); + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_parts(10, 0) }); let bound = Preimage::bound(call).unwrap(); // Schedule a call. @@ -1260,7 +1260,7 @@ 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) }); + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_parts(10, 0) }); // Schedule a call. let address = >::schedule( @@ -1307,7 +1307,7 @@ 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) }); + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_parts(10, 0) }); let bound = Preimage::bound(call).unwrap(); // Schedule a call. @@ -1344,7 +1344,7 @@ 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) }); + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_parts(10, 0) }); let bound = Preimage::bound(call).unwrap(); // Schedule a call. @@ -1386,7 +1386,7 @@ fn scheduler_v3_anon_schedule_agenda_overflows() { new_test_ext().execute_with(|| { let call = - RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) }); + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_parts(10, 0) }); let bound = Preimage::bound(call).unwrap(); // Schedule the maximal number allowed per block. @@ -1422,7 +1422,7 @@ fn scheduler_v3_anon_cancel_and_schedule_fills_holes() { new_test_ext().execute_with(|| { let call = - RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) }); + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_parts(10, 0) }); let bound = Preimage::bound(call).unwrap(); let mut addrs = Vec::<_>::default(); @@ -1471,7 +1471,7 @@ fn scheduler_v3_anon_reschedule_fills_holes() { new_test_ext().execute_with(|| { let call = - RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) }); + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_parts(10, 0) }); let bound = Preimage::bound(call).unwrap(); let mut addrs = Vec::<_>::default(); @@ -1515,7 +1515,7 @@ fn scheduler_v3_named_basic_works() { new_test_ext().execute_with(|| { let call = - RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) }); + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_parts(10, 0) }); let name = [1u8; 32]; // Schedule a call. @@ -1547,7 +1547,7 @@ 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) }); + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_parts(10, 0) }); let bound = Preimage::bound(call).unwrap(); let name = [1u8; 32]; @@ -1577,7 +1577,7 @@ 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) }); + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_parts(10, 0) }); let bound = Preimage::bound(call).unwrap(); let name = [1u8; 32]; @@ -1607,7 +1607,7 @@ 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) }); + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_parts(10, 0) }); let name = [1u8; 32]; // Schedule a call. @@ -1666,7 +1666,7 @@ 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) }); + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_parts(10, 0) }); let bound = Preimage::bound(call).unwrap(); let name = [1u8; 32]; @@ -1711,7 +1711,7 @@ fn cancel_last_task_removes_agenda() { new_test_ext().execute_with(|| { let when = 4; let call = - RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) }); + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_parts(10, 0) }); let address = Scheduler::do_schedule( DispatchTime::At(when), None, @@ -1745,7 +1745,7 @@ fn cancel_named_last_task_removes_agenda() { new_test_ext().execute_with(|| { let when = 4; let call = - RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) }); + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_parts(10, 0) }); Scheduler::do_schedule_named( [1u8; 32], DispatchTime::At(when), @@ -1781,7 +1781,7 @@ fn reschedule_last_task_removes_agenda() { new_test_ext().execute_with(|| { let when = 4; let call = - RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) }); + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_parts(10, 0) }); let address = Scheduler::do_schedule( DispatchTime::At(when), None, @@ -1818,7 +1818,7 @@ fn reschedule_named_last_task_removes_agenda() { new_test_ext().execute_with(|| { let when = 4; let call = - RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) }); + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_parts(10, 0) }); Scheduler::do_schedule_named( [1u8; 32], DispatchTime::At(when), diff --git a/frame/scheduler/src/weights.rs b/frame/scheduler/src/weights.rs index 6b786ef8b24dd..577e5b0bc4b2d 100644 --- a/frame/scheduler/src/weights.rs +++ b/frame/scheduler/src/weights.rs @@ -86,7 +86,7 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 3_079 nanoseconds. Weight::from_parts(7_087_647, 109497) // Standard Error: 658 - .saturating_add(Weight::from_ref_time(279_320).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(279_320, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -95,7 +95,7 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 5_192 nanoseconds. - Weight::from_ref_time(5_528_000) + Weight::from_parts(5_528_000, 0) } /// Storage: Preimage PreimageFor (r:1 w:1) /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: Measured) @@ -109,10 +109,10 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 17_284 nanoseconds. Weight::from_parts(17_574_000, 5252) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_126).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_126, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) - .saturating_add(Weight::from_proof_size(1).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(0, 1).saturating_mul(s.into())) } /// Storage: Scheduler Lookup (r:0 w:1) /// Proof: Scheduler Lookup (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) @@ -121,7 +121,7 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 7_020 nanoseconds. - Weight::from_ref_time(7_262_000) + Weight::from_parts(7_262_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } fn service_task_periodic() -> Weight { @@ -129,21 +129,21 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 5_187 nanoseconds. - Weight::from_ref_time(5_368_000) + Weight::from_parts(5_368_000, 0) } fn execute_dispatch_signed() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` // Minimum execution time: 2_313 nanoseconds. - Weight::from_ref_time(2_404_000) + Weight::from_parts(2_404_000, 0) } fn execute_dispatch_unsigned() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` // Minimum execution time: 2_187 nanoseconds. - Weight::from_ref_time(2_362_000) + Weight::from_parts(2_362_000, 0) } /// Storage: Scheduler Agenda (r:1 w:1) /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) @@ -155,7 +155,7 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 11_971 nanoseconds. Weight::from_parts(16_060_361, 109497) // Standard Error: 665 - .saturating_add(Weight::from_ref_time(286_324).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(286_324, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -171,7 +171,7 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 15_594 nanoseconds. Weight::from_parts(17_191_501, 109497) // Standard Error: 626 - .saturating_add(Weight::from_ref_time(425_572).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(425_572, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -187,7 +187,7 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 15_127 nanoseconds. Weight::from_parts(20_932_642, 112020) // Standard Error: 692 - .saturating_add(Weight::from_ref_time(288_344).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(288_344, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -203,7 +203,7 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 16_859 nanoseconds. Weight::from_parts(19_736_937, 112020) // Standard Error: 676 - .saturating_add(Weight::from_ref_time(429_770).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(429_770, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -232,7 +232,7 @@ impl WeightInfo for () { // Minimum execution time: 3_079 nanoseconds. Weight::from_parts(7_087_647, 109497) // Standard Error: 658 - .saturating_add(Weight::from_ref_time(279_320).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(279_320, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -241,7 +241,7 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 5_192 nanoseconds. - Weight::from_ref_time(5_528_000) + Weight::from_parts(5_528_000, 0) } /// Storage: Preimage PreimageFor (r:1 w:1) /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: Measured) @@ -255,10 +255,10 @@ impl WeightInfo for () { // Minimum execution time: 17_284 nanoseconds. Weight::from_parts(17_574_000, 5252) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_126).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_126, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) - .saturating_add(Weight::from_proof_size(1).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(0, 1).saturating_mul(s.into())) } /// Storage: Scheduler Lookup (r:0 w:1) /// Proof: Scheduler Lookup (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) @@ -267,7 +267,7 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 7_020 nanoseconds. - Weight::from_ref_time(7_262_000) + Weight::from_parts(7_262_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } fn service_task_periodic() -> Weight { @@ -275,21 +275,21 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 5_187 nanoseconds. - Weight::from_ref_time(5_368_000) + Weight::from_parts(5_368_000, 0) } fn execute_dispatch_signed() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` // Minimum execution time: 2_313 nanoseconds. - Weight::from_ref_time(2_404_000) + Weight::from_parts(2_404_000, 0) } fn execute_dispatch_unsigned() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` // Minimum execution time: 2_187 nanoseconds. - Weight::from_ref_time(2_362_000) + Weight::from_parts(2_362_000, 0) } /// Storage: Scheduler Agenda (r:1 w:1) /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) @@ -301,7 +301,7 @@ impl WeightInfo for () { // Minimum execution time: 11_971 nanoseconds. Weight::from_parts(16_060_361, 109497) // Standard Error: 665 - .saturating_add(Weight::from_ref_time(286_324).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(286_324, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -317,7 +317,7 @@ impl WeightInfo for () { // Minimum execution time: 15_594 nanoseconds. Weight::from_parts(17_191_501, 109497) // Standard Error: 626 - .saturating_add(Weight::from_ref_time(425_572).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(425_572, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -333,7 +333,7 @@ impl WeightInfo for () { // Minimum execution time: 15_127 nanoseconds. Weight::from_parts(20_932_642, 112020) // Standard Error: 692 - .saturating_add(Weight::from_ref_time(288_344).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(288_344, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -349,7 +349,7 @@ impl WeightInfo for () { // Minimum execution time: 16_859 nanoseconds. Weight::from_parts(19_736_937, 112020) // Standard Error: 676 - .saturating_add(Weight::from_ref_time(429_770).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(429_770, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 99c2f6043ee2c..78c9a51bc829c 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -1267,7 +1267,7 @@ where disable_strategy: DisableStrategy, ) -> Weight { let reward_proportion = SlashRewardFraction::::get(); - let mut consumed_weight = Weight::from_ref_time(0); + let mut consumed_weight = Weight::from_parts(0, 0); let mut add_db_reads_writes = |reads, writes| { consumed_weight += T::DbWeight::get().reads_writes(reads, writes); }; diff --git a/frame/staking/src/weights.rs b/frame/staking/src/weights.rs index 2c9e1b2669c8b..d1814d89d4d89 100644 --- a/frame/staking/src/weights.rs +++ b/frame/staking/src/weights.rs @@ -164,7 +164,7 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 31_479 nanoseconds. Weight::from_parts(32_410_035, 10442) // Standard Error: 313 - .saturating_add(Weight::from_ref_time(9_090).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(9_090, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -204,11 +204,11 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 71_968 nanoseconds. Weight::from_parts(76_631_804, 32303) // Standard Error: 1_613 - .saturating_add(Weight::from_ref_time(1_058_968).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_058_968, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(13_u64)) .saturating_add(T::DbWeight::get().writes(12_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) - .saturating_add(Weight::from_proof_size(4).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into())) } /// Storage: Staking Ledger (r:1 w:0) /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) @@ -253,11 +253,11 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 25_685 nanoseconds. Weight::from_parts(25_290_286, 3566) // Standard Error: 5_164 - .saturating_add(Weight::from_ref_time(6_445_608).saturating_mul(k.into())) + .saturating_add(Weight::from_parts(6_445_608, 0).saturating_mul(k.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(k.into()))) - .saturating_add(Weight::from_proof_size(3033).saturating_mul(k.into())) + .saturating_add(Weight::from_parts(0, 3033).saturating_mul(k.into())) } /// Storage: Staking Ledger (r:1 w:0) /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) @@ -289,11 +289,11 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 59_542 nanoseconds. Weight::from_parts(57_558_678, 21988) // Standard Error: 10_364 - .saturating_add(Weight::from_ref_time(2_759_713).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(2_759_713, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(6_u64)) - .saturating_add(Weight::from_proof_size(2520).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 2520).saturating_mul(n.into())) } /// Storage: Staking Ledger (r:1 w:0) /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) @@ -351,7 +351,7 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 3_069 nanoseconds. - Weight::from_ref_time(3_176_000) + Weight::from_parts(3_176_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Staking ForceEra (r:0 w:1) @@ -361,7 +361,7 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 11_386 nanoseconds. - Weight::from_ref_time(11_672_000) + Weight::from_parts(11_672_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Staking ForceEra (r:0 w:1) @@ -371,7 +371,7 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 11_591 nanoseconds. - Weight::from_ref_time(11_799_000) + Weight::from_parts(11_799_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Staking ForceEra (r:0 w:1) @@ -381,7 +381,7 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 11_553 nanoseconds. - Weight::from_ref_time(11_871_000) + Weight::from_parts(11_871_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Staking Invulnerables (r:0 w:1) @@ -392,9 +392,9 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 3_292 nanoseconds. - Weight::from_ref_time(3_754_352) + Weight::from_parts(3_754_352, 0) // Standard Error: 40 - .saturating_add(Weight::from_ref_time(9_838).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(9_838, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Staking Bonded (r:1 w:1) @@ -431,11 +431,11 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 65_307 nanoseconds. Weight::from_parts(70_227_980, 27930) // Standard Error: 2_113 - .saturating_add(Weight::from_ref_time(1_059_856).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_059_856, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(12_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) - .saturating_add(Weight::from_proof_size(4).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into())) } /// Storage: Staking UnappliedSlashes (r:1 w:1) /// Proof Skipped: Staking UnappliedSlashes (max_values: None, max_size: None, mode: Measured) @@ -447,7 +447,7 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 89_123 nanoseconds. Weight::from_parts(890_989_741, 69146) // Standard Error: 58_282 - .saturating_add(Weight::from_ref_time(4_920_413).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(4_920_413, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -477,12 +477,12 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 73_652 nanoseconds. Weight::from_parts(127_839_483, 54756) // Standard Error: 14_195 - .saturating_add(Weight::from_ref_time(21_932_079).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(21_932_079, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_proof_size(8024).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 8024).saturating_mul(n.into())) } /// Storage: Staking CurrentEra (r:1 w:0) /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -512,12 +512,12 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 94_560 nanoseconds. Weight::from_parts(154_033_219, 83594) // Standard Error: 26_663 - .saturating_add(Weight::from_ref_time(31_269_223).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(31_269_223, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(10_u64)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_proof_size(16026).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 16026).saturating_mul(n.into())) } /// Storage: Staking Ledger (r:1 w:1) /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) @@ -539,7 +539,7 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 74_764 nanoseconds. Weight::from_parts(75_814_067, 25491) // Standard Error: 1_217 - .saturating_add(Weight::from_ref_time(64_725).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(64_725, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(8_u64)) } @@ -577,11 +577,11 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 77_611 nanoseconds. Weight::from_parts(79_760_034, 31810) // Standard Error: 1_597 - .saturating_add(Weight::from_ref_time(1_039_268).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_039_268, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(12_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) - .saturating_add(Weight::from_proof_size(4).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into())) } /// Storage: VoterList CounterForListNodes (r:1 w:0) /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -626,16 +626,16 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 489_824 nanoseconds. Weight::from_parts(491_687_000, 528203) // Standard Error: 1_787_577 - .saturating_add(Weight::from_ref_time(58_719_498).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(58_719_498, 0).saturating_mul(v.into())) // Standard Error: 178_122 - .saturating_add(Weight::from_ref_time(13_273_555).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(13_273_555, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(206_u64)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(v.into()))) - .saturating_add(Weight::from_proof_size(16743).saturating_mul(v.into())) - .saturating_add(Weight::from_proof_size(12947).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 16743).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(0, 12947).saturating_mul(n.into())) } /// Storage: VoterList CounterForListNodes (r:1 w:0) /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -662,15 +662,15 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 23_373_467 nanoseconds. Weight::from_parts(23_497_257_000, 511899) // Standard Error: 299_205 - .saturating_add(Weight::from_ref_time(3_434_000).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(3_434_000, 0).saturating_mul(v.into())) // Standard Error: 299_205 - .saturating_add(Weight::from_ref_time(2_568_954).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(2_568_954, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(201_u64)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) - .saturating_add(Weight::from_proof_size(14295).saturating_mul(v.into())) - .saturating_add(Weight::from_proof_size(11775).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 14295).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(0, 11775).saturating_mul(n.into())) } /// Storage: Staking CounterForValidators (r:1 w:0) /// Proof: Staking CounterForValidators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -684,10 +684,10 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 3_882_120 nanoseconds. Weight::from_parts(3_951_993_000, 3019) // Standard Error: 46_729 - .saturating_add(Weight::from_ref_time(2_856_043).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(2_856_043, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) - .saturating_add(Weight::from_proof_size(2520).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(0, 2520).saturating_mul(v.into())) } /// Storage: Staking MinCommission (r:0 w:1) /// Proof: Staking MinCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -706,7 +706,7 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 8_427 nanoseconds. - Weight::from_ref_time(8_794_000) + Weight::from_parts(8_794_000, 0) .saturating_add(T::DbWeight::get().writes(6_u64)) } /// Storage: Staking MinCommission (r:0 w:1) @@ -726,7 +726,7 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 7_620 nanoseconds. - Weight::from_ref_time(7_901_000) + Weight::from_parts(7_901_000, 0) .saturating_add(T::DbWeight::get().writes(6_u64)) } /// Storage: Staking Ledger (r:1 w:0) @@ -778,7 +778,7 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 4_518 nanoseconds. - Weight::from_ref_time(4_656_000) + Weight::from_parts(4_656_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } } @@ -866,7 +866,7 @@ impl WeightInfo for () { // Minimum execution time: 31_479 nanoseconds. Weight::from_parts(32_410_035, 10442) // Standard Error: 313 - .saturating_add(Weight::from_ref_time(9_090).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(9_090, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -906,11 +906,11 @@ impl WeightInfo for () { // Minimum execution time: 71_968 nanoseconds. Weight::from_parts(76_631_804, 32303) // Standard Error: 1_613 - .saturating_add(Weight::from_ref_time(1_058_968).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_058_968, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(13_u64)) .saturating_add(RocksDbWeight::get().writes(12_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) - .saturating_add(Weight::from_proof_size(4).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into())) } /// Storage: Staking Ledger (r:1 w:0) /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) @@ -955,11 +955,11 @@ impl WeightInfo for () { // Minimum execution time: 25_685 nanoseconds. Weight::from_parts(25_290_286, 3566) // Standard Error: 5_164 - .saturating_add(Weight::from_ref_time(6_445_608).saturating_mul(k.into())) + .saturating_add(Weight::from_parts(6_445_608, 0).saturating_mul(k.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(k.into()))) - .saturating_add(Weight::from_proof_size(3033).saturating_mul(k.into())) + .saturating_add(Weight::from_parts(0, 3033).saturating_mul(k.into())) } /// Storage: Staking Ledger (r:1 w:0) /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) @@ -991,11 +991,11 @@ impl WeightInfo for () { // Minimum execution time: 59_542 nanoseconds. Weight::from_parts(57_558_678, 21988) // Standard Error: 10_364 - .saturating_add(Weight::from_ref_time(2_759_713).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(2_759_713, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(6_u64)) - .saturating_add(Weight::from_proof_size(2520).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 2520).saturating_mul(n.into())) } /// Storage: Staking Ledger (r:1 w:0) /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) @@ -1053,7 +1053,7 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 3_069 nanoseconds. - Weight::from_ref_time(3_176_000) + Weight::from_parts(3_176_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Staking ForceEra (r:0 w:1) @@ -1063,7 +1063,7 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 11_386 nanoseconds. - Weight::from_ref_time(11_672_000) + Weight::from_parts(11_672_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Staking ForceEra (r:0 w:1) @@ -1073,7 +1073,7 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 11_591 nanoseconds. - Weight::from_ref_time(11_799_000) + Weight::from_parts(11_799_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Staking ForceEra (r:0 w:1) @@ -1083,7 +1083,7 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 11_553 nanoseconds. - Weight::from_ref_time(11_871_000) + Weight::from_parts(11_871_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Staking Invulnerables (r:0 w:1) @@ -1094,9 +1094,9 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 3_292 nanoseconds. - Weight::from_ref_time(3_754_352) + Weight::from_parts(3_754_352, 0) // Standard Error: 40 - .saturating_add(Weight::from_ref_time(9_838).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(9_838, 0).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Staking Bonded (r:1 w:1) @@ -1133,11 +1133,11 @@ impl WeightInfo for () { // Minimum execution time: 65_307 nanoseconds. Weight::from_parts(70_227_980, 27930) // Standard Error: 2_113 - .saturating_add(Weight::from_ref_time(1_059_856).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_059_856, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(12_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) - .saturating_add(Weight::from_proof_size(4).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into())) } /// Storage: Staking UnappliedSlashes (r:1 w:1) /// Proof Skipped: Staking UnappliedSlashes (max_values: None, max_size: None, mode: Measured) @@ -1149,7 +1149,7 @@ impl WeightInfo for () { // Minimum execution time: 89_123 nanoseconds. Weight::from_parts(890_989_741, 69146) // Standard Error: 58_282 - .saturating_add(Weight::from_ref_time(4_920_413).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(4_920_413, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1179,12 +1179,12 @@ impl WeightInfo for () { // Minimum execution time: 73_652 nanoseconds. Weight::from_parts(127_839_483, 54756) // Standard Error: 14_195 - .saturating_add(Weight::from_ref_time(21_932_079).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(21_932_079, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_proof_size(8024).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 8024).saturating_mul(n.into())) } /// Storage: Staking CurrentEra (r:1 w:0) /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -1214,12 +1214,12 @@ impl WeightInfo for () { // Minimum execution time: 94_560 nanoseconds. Weight::from_parts(154_033_219, 83594) // Standard Error: 26_663 - .saturating_add(Weight::from_ref_time(31_269_223).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(31_269_223, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(10_u64)) .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_proof_size(16026).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 16026).saturating_mul(n.into())) } /// Storage: Staking Ledger (r:1 w:1) /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) @@ -1241,7 +1241,7 @@ impl WeightInfo for () { // Minimum execution time: 74_764 nanoseconds. Weight::from_parts(75_814_067, 25491) // Standard Error: 1_217 - .saturating_add(Weight::from_ref_time(64_725).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(64_725, 0).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(8_u64)) } @@ -1279,11 +1279,11 @@ impl WeightInfo for () { // Minimum execution time: 77_611 nanoseconds. Weight::from_parts(79_760_034, 31810) // Standard Error: 1_597 - .saturating_add(Weight::from_ref_time(1_039_268).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_039_268, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().writes(12_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) - .saturating_add(Weight::from_proof_size(4).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into())) } /// Storage: VoterList CounterForListNodes (r:1 w:0) /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -1328,16 +1328,16 @@ impl WeightInfo for () { // Minimum execution time: 489_824 nanoseconds. Weight::from_parts(491_687_000, 528203) // Standard Error: 1_787_577 - .saturating_add(Weight::from_ref_time(58_719_498).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(58_719_498, 0).saturating_mul(v.into())) // Standard Error: 178_122 - .saturating_add(Weight::from_ref_time(13_273_555).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(13_273_555, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(206_u64)) .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(v.into()))) - .saturating_add(Weight::from_proof_size(16743).saturating_mul(v.into())) - .saturating_add(Weight::from_proof_size(12947).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 16743).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(0, 12947).saturating_mul(n.into())) } /// Storage: VoterList CounterForListNodes (r:1 w:0) /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -1364,15 +1364,15 @@ impl WeightInfo for () { // Minimum execution time: 23_373_467 nanoseconds. Weight::from_parts(23_497_257_000, 511899) // Standard Error: 299_205 - .saturating_add(Weight::from_ref_time(3_434_000).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(3_434_000, 0).saturating_mul(v.into())) // Standard Error: 299_205 - .saturating_add(Weight::from_ref_time(2_568_954).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(2_568_954, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(201_u64)) .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) - .saturating_add(Weight::from_proof_size(14295).saturating_mul(v.into())) - .saturating_add(Weight::from_proof_size(11775).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 14295).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(0, 11775).saturating_mul(n.into())) } /// Storage: Staking CounterForValidators (r:1 w:0) /// Proof: Staking CounterForValidators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -1386,10 +1386,10 @@ impl WeightInfo for () { // Minimum execution time: 3_882_120 nanoseconds. Weight::from_parts(3_951_993_000, 3019) // Standard Error: 46_729 - .saturating_add(Weight::from_ref_time(2_856_043).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(2_856_043, 0).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(v.into()))) - .saturating_add(Weight::from_proof_size(2520).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(0, 2520).saturating_mul(v.into())) } /// Storage: Staking MinCommission (r:0 w:1) /// Proof: Staking MinCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -1408,7 +1408,7 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 8_427 nanoseconds. - Weight::from_ref_time(8_794_000) + Weight::from_parts(8_794_000, 0) .saturating_add(RocksDbWeight::get().writes(6_u64)) } /// Storage: Staking MinCommission (r:0 w:1) @@ -1428,7 +1428,7 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 7_620 nanoseconds. - Weight::from_ref_time(7_901_000) + Weight::from_parts(7_901_000, 0) .saturating_add(RocksDbWeight::get().writes(6_u64)) } /// Storage: Staking Ledger (r:1 w:0) @@ -1480,7 +1480,7 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 4_518 nanoseconds. - Weight::from_ref_time(4_656_000) + Weight::from_parts(4_656_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } } diff --git a/frame/state-trie-migration/src/lib.rs b/frame/state-trie-migration/src/lib.rs index 0ebb8122d4618..547dfa5cda9c8 100644 --- a/frame/state-trie-migration/src/lib.rs +++ b/frame/state-trie-migration/src/lib.rs @@ -1136,25 +1136,25 @@ mod mock { impl WeightInfo for StateMigrationTestWeight { fn process_top_key(_: u32) -> Weight { - Weight::from_ref_time(1000000) + Weight::from_parts(1000000, 0) } fn continue_migrate() -> Weight { - Weight::from_ref_time(1000000) + Weight::from_parts(1000000, 0) } fn continue_migrate_wrong_witness() -> Weight { - Weight::from_ref_time(1000000) + Weight::from_parts(1000000, 0) } fn migrate_custom_top_fail() -> Weight { - Weight::from_ref_time(1000000) + Weight::from_parts(1000000, 0) } fn migrate_custom_top_success() -> Weight { - Weight::from_ref_time(1000000) + Weight::from_parts(1000000, 0) } fn migrate_custom_child_fail() -> Weight { - Weight::from_ref_time(1000000) + Weight::from_parts(1000000, 0) } fn migrate_custom_child_success() -> Weight { - Weight::from_ref_time(1000000) + Weight::from_parts(1000000, 0) } } diff --git a/frame/state-trie-migration/src/weights.rs b/frame/state-trie-migration/src/weights.rs index a833d816cd13a..e087ba185994f 100644 --- a/frame/state-trie-migration/src/weights.rs +++ b/frame/state-trie-migration/src/weights.rs @@ -88,7 +88,7 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 8_817 nanoseconds. - Weight::from_ref_time(9_027_000) + Weight::from_parts(9_027_000, 0) } /// Storage: unknown `0x666f6f` (r:1 w:1) /// Proof Skipped: unknown `0x666f6f` (r:1 w:1) @@ -106,7 +106,7 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 9_020 nanoseconds. - Weight::from_ref_time(9_234_000) + Weight::from_parts(9_234_000, 0) } /// Storage: unknown `0x666f6f` (r:1 w:1) /// Proof Skipped: unknown `0x666f6f` (r:1 w:1) @@ -129,10 +129,10 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 5_279 nanoseconds. Weight::from_parts(5_517_000, 2700) // Standard Error: 1 - .saturating_add(Weight::from_ref_time(1_230).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(1_230, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) - .saturating_add(Weight::from_proof_size(1).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(0, 1).saturating_mul(v.into())) } } @@ -166,7 +166,7 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 8_817 nanoseconds. - Weight::from_ref_time(9_027_000) + Weight::from_parts(9_027_000, 0) } /// Storage: unknown `0x666f6f` (r:1 w:1) /// Proof Skipped: unknown `0x666f6f` (r:1 w:1) @@ -184,7 +184,7 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 9_020 nanoseconds. - Weight::from_ref_time(9_234_000) + Weight::from_parts(9_234_000, 0) } /// Storage: unknown `0x666f6f` (r:1 w:1) /// Proof Skipped: unknown `0x666f6f` (r:1 w:1) @@ -207,9 +207,9 @@ impl WeightInfo for () { // Minimum execution time: 5_279 nanoseconds. Weight::from_parts(5_517_000, 2700) // Standard Error: 1 - .saturating_add(Weight::from_ref_time(1_230).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(1_230, 0).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) - .saturating_add(Weight::from_proof_size(1).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(0, 1).saturating_mul(v.into())) } } diff --git a/frame/sudo/src/tests.rs b/frame/sudo/src/tests.rs index e924bc77cf69e..c854fed8f0736 100644 --- a/frame/sudo/src/tests.rs +++ b/frame/sudo/src/tests.rs @@ -41,7 +41,7 @@ fn sudo_basics() { // A privileged function should work when `sudo` is passed the root `key` as `origin`. let call = Box::new(RuntimeCall::Logger(LoggerCall::privileged_i32_log { i: 42, - weight: Weight::from_ref_time(1_000), + weight: Weight::from_parts(1_000, 0), })); assert_ok!(Sudo::sudo(RuntimeOrigin::signed(1), call)); assert_eq!(Logger::i32_log(), vec![42i32]); @@ -49,7 +49,7 @@ fn sudo_basics() { // A privileged function should not work when `sudo` is passed a non-root `key` as `origin`. let call = Box::new(RuntimeCall::Logger(LoggerCall::privileged_i32_log { i: 42, - weight: Weight::from_ref_time(1_000), + weight: Weight::from_parts(1_000, 0), })); assert_noop!(Sudo::sudo(RuntimeOrigin::signed(2), call), Error::::RequireSudo); }); @@ -64,7 +64,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(RuntimeCall::Logger(LoggerCall::privileged_i32_log { i: 42, - weight: Weight::from_ref_time(1), + weight: Weight::from_parts(1, 0), })); assert_ok!(Sudo::sudo(RuntimeOrigin::signed(1), call)); System::assert_has_event(TestEvent::Sudo(Event::Sudid { sudo_result: Ok(()) })); @@ -77,25 +77,25 @@ fn sudo_unchecked_weight_basics() { // A privileged function should work when `sudo` is passed the root `key` as origin. let call = Box::new(RuntimeCall::Logger(LoggerCall::privileged_i32_log { i: 42, - weight: Weight::from_ref_time(1_000), + weight: Weight::from_parts(1_000, 0), })); assert_ok!(Sudo::sudo_unchecked_weight( RuntimeOrigin::signed(1), call, - Weight::from_ref_time(1_000) + Weight::from_parts(1_000, 0) )); assert_eq!(Logger::i32_log(), vec![42i32]); // A privileged function should not work when called with a non-root `key`. let call = Box::new(RuntimeCall::Logger(LoggerCall::privileged_i32_log { i: 42, - weight: Weight::from_ref_time(1_000), + weight: Weight::from_parts(1_000, 0), })); assert_noop!( Sudo::sudo_unchecked_weight( RuntimeOrigin::signed(2), call, - Weight::from_ref_time(1_000) + Weight::from_parts(1_000, 0) ), Error::::RequireSudo, ); @@ -105,12 +105,12 @@ fn sudo_unchecked_weight_basics() { // Controls the dispatched weight. let call = Box::new(RuntimeCall::Logger(LoggerCall::privileged_i32_log { i: 42, - weight: Weight::from_ref_time(1), + weight: Weight::from_parts(1, 0), })); let sudo_unchecked_weight_call = - SudoCall::sudo_unchecked_weight { call, weight: Weight::from_ref_time(1_000) }; + SudoCall::sudo_unchecked_weight { call, weight: Weight::from_parts(1_000, 0) }; let info = sudo_unchecked_weight_call.get_dispatch_info(); - assert_eq!(info.weight, Weight::from_ref_time(1_000)); + assert_eq!(info.weight, Weight::from_parts(1_000, 0)); }); } @@ -123,12 +123,12 @@ 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(RuntimeCall::Logger(LoggerCall::privileged_i32_log { i: 42, - weight: Weight::from_ref_time(1), + weight: Weight::from_parts(1, 0), })); assert_ok!(Sudo::sudo_unchecked_weight( RuntimeOrigin::signed(1), call, - Weight::from_ref_time(1_000) + Weight::from_parts(1_000, 0) )); System::assert_has_event(TestEvent::Sudo(Event::Sudid { sudo_result: Ok(()) })); }) @@ -170,7 +170,7 @@ fn sudo_as_basics() { // A privileged function will not work when passed to `sudo_as`. let call = Box::new(RuntimeCall::Logger(LoggerCall::privileged_i32_log { i: 42, - weight: Weight::from_ref_time(1_000), + weight: Weight::from_parts(1_000, 0), })); assert_ok!(Sudo::sudo_as(RuntimeOrigin::signed(1), 2, call)); assert!(Logger::i32_log().is_empty()); @@ -179,14 +179,14 @@ fn sudo_as_basics() { // A non-privileged function should not work when called with a non-root `key`. let call = Box::new(RuntimeCall::Logger(LoggerCall::non_privileged_log { i: 42, - weight: Weight::from_ref_time(1), + weight: Weight::from_parts(1, 0), })); 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), + weight: Weight::from_parts(1, 0), })); assert_ok!(Sudo::sudo_as(RuntimeOrigin::signed(1), 2, call)); assert_eq!(Logger::i32_log(), vec![42i32]); @@ -204,7 +204,7 @@ 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(RuntimeCall::Logger(LoggerCall::non_privileged_log { i: 42, - weight: Weight::from_ref_time(1), + weight: Weight::from_parts(1, 0), })); 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/src/dispatch.rs b/frame/support/src/dispatch.rs index c26a3d8e71a36..e2798763df437 100644 --- a/frame/support/src/dispatch.rs +++ b/frame/support/src/dispatch.rs @@ -314,7 +314,7 @@ pub trait WithPostDispatchInfo { /// # Example /// /// ```ignore - /// let who = ensure_signed(origin).map_err(|e| e.with_weight(Weight::from_ref_time(100)))?; + /// let who = ensure_signed(origin).map_err(|e| e.with_weight(Weight::from_parts(100, 0)))?; /// ensure!(who == me, Error::::NotMe.with_weight(200_000)); /// ``` fn with_weight(self, actual_weight: Weight) -> DispatchErrorWithPostInfo; @@ -365,7 +365,7 @@ impl GetDispatchInfo fn get_dispatch_info(&self) -> DispatchInfo { // for testing: weight == size. DispatchInfo { - weight: Weight::from_ref_time(self.encode().len() as _), + weight: Weight::from_parts(self.encode().len() as _, 0), pays_fee: Pays::Yes, class: self.call.get_dispatch_info().class, } @@ -552,7 +552,7 @@ impl ClassifyDispatch for (Weight, DispatchClass, Pays) { 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)), + Some(actual_computation) => Some(Weight::from_parts(actual_computation, 0)), None => None, }; Self { actual_weight, pays_fee: Default::default() } @@ -563,7 +563,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::zero().set_ref_time(actual_time)), + Some(actual_time) => Some(Weight::from_parts(actual_time, 0)), None => None, }; Self { actual_weight, pays_fee } @@ -584,7 +584,7 @@ impl PaysFee for u64 { impl WeighData for u64 { fn weigh_data(&self, _: T) -> Weight { - return Weight::zero().set_ref_time(*self) + return Weight::from_parts(*self, 0) } } @@ -735,7 +735,7 @@ impl PaysFee for (u64, Pays) { /// 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)))?; +/// ensure_signed(origin).map_err(|e| e.with_weight(Weight::from_parts(100_000, 0)))?; /// if do_expensive_calc { /// // do the expensive calculation /// // ... @@ -3239,13 +3239,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") } Weight::from_ref_time(7) } + fn on_initialize(n: T::BlockNumber,) -> Weight { if n.into() == 42 { panic!("on_initialize") } Weight::from_parts(7, 0) } fn on_idle(n: T::BlockNumber, remaining_weight: Weight,) -> Weight { - if n.into() == 42 || remaining_weight == Weight::from_ref_time(42) { panic!("on_idle") } - Weight::from_ref_time(7) + if n.into() == 42 || remaining_weight == Weight::from_parts(42, 0) { panic!("on_idle") } + Weight::from_parts(7, 0) } fn on_finalize(n: T::BlockNumber,) { if n.into() == 42 { panic!("on_finalize") } } - fn on_runtime_upgrade() -> Weight { Weight::from_ref_time(10) } + fn on_runtime_upgrade() -> Weight { Weight::from_parts(10, 0) } fn offchain_worker() {} /// Some doc fn integrity_test() { panic!("integrity_test") } @@ -3423,27 +3423,27 @@ mod tests { fn on_initialize_should_work_2() { assert_eq!( as OnInitialize>::on_initialize(10), - Weight::from_ref_time(7) + Weight::from_parts(7, 0) ); } #[test] #[should_panic(expected = "on_idle")] fn on_idle_should_work_1() { - as OnIdle>::on_idle(42, Weight::from_ref_time(9)); + as OnIdle>::on_idle(42, Weight::from_parts(9, 0)); } #[test] #[should_panic(expected = "on_idle")] fn on_idle_should_work_2() { - as OnIdle>::on_idle(9, Weight::from_ref_time(42)); + as OnIdle>::on_idle(9, Weight::from_parts(42, 0)); } #[test] fn on_idle_should_work_3() { assert_eq!( - as OnIdle>::on_idle(10, Weight::from_ref_time(11)), - Weight::from_ref_time(7) + as OnIdle>::on_idle(10, Weight::from_parts(11, 0)), + Weight::from_parts(7, 0) ); } @@ -3458,7 +3458,7 @@ mod tests { sp_io::TestExternalities::default().execute_with(|| { assert_eq!( as OnRuntimeUpgrade>::on_runtime_upgrade(), - Weight::from_ref_time(10) + Weight::from_parts(10, 0) ) }); } @@ -3469,7 +3469,7 @@ mod tests { assert_eq!( Call::::operational {}.get_dispatch_info(), DispatchInfo { - weight: Weight::from_ref_time(5), + weight: Weight::from_parts(5, 0), class: DispatchClass::Operational, pays_fee: Pays::Yes }, @@ -3478,7 +3478,7 @@ mod tests { assert_eq!( Call::::aux_3 {}.get_dispatch_info(), DispatchInfo { - weight: Weight::from_ref_time(3), + weight: Weight::from_parts(3, 0), class: DispatchClass::Normal, pays_fee: Pays::Yes }, @@ -3567,10 +3567,10 @@ mod weight_tests { #[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)] + #[weight = T::DbWeight::get().reads(3) + T::DbWeight::get().writes(2) + Weight::from_parts(10_000, 0)] fn f20(_origin) { unimplemented!(); } - #[weight = T::DbWeight::get().reads_writes(6, 5) + Weight::from_ref_time(40_000)] + #[weight = T::DbWeight::get().reads_writes(6, 5) + Weight::from_parts(40_000, 0)] fn f21(_origin) { unimplemented!(); } } @@ -3580,96 +3580,96 @@ mod weight_tests { 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.weight, Weight::from_parts(1000, 0)); 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.weight, Weight::from_parts(1000, 0)); 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.weight, Weight::from_parts(1000, 0)); 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.weight, Weight::from_parts(1000, 0)); 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.weight, Weight::from_parts(150, 0)); // 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.weight, Weight::from_parts(0, 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.weight, Weight::from_parts(12300, 0)); // 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.weight, Weight::from_parts(45600, 0)); // 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)); + let pre = DispatchInfo { weight: Weight::from_parts(1000, 0), ..Default::default() }; + assert_eq!(extract_actual_weight(&Ok(Some(7).into()), &pre), Weight::from_parts(7, 0)); assert_eq!( extract_actual_weight(&Ok(Some(1000).into()), &pre), - Weight::from_ref_time(1000) + Weight::from_parts(1000, 0) ); assert_eq!( extract_actual_weight( - &Err(DispatchError::BadOrigin.with_weight(Weight::from_ref_time(9))), + &Err(DispatchError::BadOrigin.with_weight(Weight::from_parts(9, 0))), &pre ), - Weight::from_ref_time(9) + Weight::from_parts(9, 0) ); } #[test] fn extract_actual_weight_caps_at_pre_weight() { - let pre = DispatchInfo { weight: Weight::from_ref_time(1000), ..Default::default() }; + let pre = DispatchInfo { weight: Weight::from_parts(1000, 0), ..Default::default() }; assert_eq!( extract_actual_weight(&Ok(Some(1250).into()), &pre), - Weight::from_ref_time(1000) + Weight::from_parts(1000, 0) ); assert_eq!( extract_actual_weight( - &Err(DispatchError::BadOrigin.with_weight(Weight::from_ref_time(1300))), + &Err(DispatchError::BadOrigin.with_weight(Weight::from_parts(1300, 0))), &pre ), - Weight::from_ref_time(1000), + Weight::from_parts(1000, 0), ); } #[test] fn extract_actual_pays_fee_works() { - let pre = DispatchInfo { weight: Weight::from_ref_time(1000), ..Default::default() }; + let pre = DispatchInfo { weight: Weight::from_parts(1000, 0), ..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))), + &Err(DispatchError::BadOrigin.with_weight(Weight::from_parts(9, 0))), &pre ), Pays::Yes @@ -3686,7 +3686,7 @@ mod weight_tests { ); let pre = DispatchInfo { - weight: Weight::from_ref_time(1000), + weight: Weight::from_parts(1000, 0), pays_fee: Pays::No, ..Default::default() }; diff --git a/frame/support/src/traits/hooks.rs b/frame/support/src/traits/hooks.rs index fe67e33d1832c..a3374d0bf537f 100644 --- a/frame/support/src/traits/hooks.rs +++ b/frame/support/src/traits/hooks.rs @@ -367,18 +367,18 @@ mod tests { impl OnInitialize for Test { fn on_initialize(_n: u8) -> Weight { - Weight::from_ref_time(10) + Weight::from_parts(10, 0) } } impl OnRuntimeUpgrade for Test { fn on_runtime_upgrade() -> Weight { - Weight::from_ref_time(20) + Weight::from_parts(20, 0) } } 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)); + assert_eq!(<(Test, Test)>::on_initialize(0), Weight::from_parts(20, 0)); + assert_eq!(<(Test, Test)>::on_runtime_upgrade(), Weight::from_parts(40, 0)); }); } diff --git a/frame/support/src/weights/block_weights.rs b/frame/support/src/weights/block_weights.rs index a208c77aa28c1..2389c51d9de9c 100644 --- a/frame/support/src/weights/block_weights.rs +++ b/frame/support/src/weights/block_weights.rs @@ -54,7 +54,7 @@ parameter_types! { /// 95th: 384_876 /// 75th: 380_642 pub const BlockExecutionWeight: Weight = - Weight::from_ref_time(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(381_015)); + Weight::from_parts(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(381_015), 0); } #[cfg(test)] diff --git a/frame/support/src/weights/extrinsic_weights.rs b/frame/support/src/weights/extrinsic_weights.rs index 4e3a0fda8d2f5..78798d2e3a277 100644 --- a/frame/support/src/weights/extrinsic_weights.rs +++ b/frame/support/src/weights/extrinsic_weights.rs @@ -54,7 +54,7 @@ parameter_types! { /// 95th: 100_051 /// 75th: 99_916 pub const ExtrinsicBaseWeight: Weight = - Weight::from_ref_time(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(99_840)); + Weight::from_parts(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(99_840), 0); } #[cfg(test)] diff --git a/frame/support/test/tests/construct_runtime.rs b/frame/support/test/tests/construct_runtime.rs index 0965577149d17..24f8a278b3539 100644 --- a/frame/support/test/tests/construct_runtime.rs +++ b/frame/support/test/tests/construct_runtime.rs @@ -508,7 +508,7 @@ fn call_weight_should_attach_to_call_enum() { assert_eq!( module3::Call::::operational {}.get_dispatch_info(), DispatchInfo { - weight: Weight::from_ref_time(5), + weight: Weight::from_parts(5, 0), class: DispatchClass::Operational, pays_fee: Pays::Yes }, @@ -517,7 +517,7 @@ fn call_weight_should_attach_to_call_enum() { assert_eq!( module3::Call::::aux_4 {}.get_dispatch_info(), DispatchInfo { - weight: Weight::from_ref_time(3), + weight: Weight::from_parts(3, 0), class: DispatchClass::Normal, pays_fee: Pays::Yes }, diff --git a/frame/support/test/tests/pallet.rs b/frame/support/test/tests/pallet.rs index 8ce85fa506348..2a4732d0222d2 100644 --- a/frame/support/test/tests/pallet.rs +++ b/frame/support/test/tests/pallet.rs @@ -171,7 +171,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)); - Weight::from_ref_time(10) + Weight::from_parts(10, 0) } fn on_finalize(_: BlockNumberFor) { let _ = T::AccountId::from(SomeType1); // Test for where clause @@ -182,7 +182,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)); - Weight::from_ref_time(30) + Weight::from_parts(30, 0) } fn integrity_test() { let _ = T::AccountId::from(SomeType1); // Test for where clause @@ -197,7 +197,7 @@ pub mod pallet { { /// Doc comment put in metadata #[pallet::call_index(0)] - #[pallet::weight(Weight::from_ref_time(*_foo as u64))] + #[pallet::weight(Weight::from_parts(*_foo as u64, 0))] pub fn foo( origin: OriginFor, #[pallet::compact] _foo: u32, @@ -715,7 +715,7 @@ fn call_expand() { assert_eq!( call_foo.get_dispatch_info(), DispatchInfo { - weight: frame_support::weights::Weight::from_ref_time(3), + weight: frame_support::weights::Weight::from_parts(3, 0), class: DispatchClass::Normal, pays_fee: Pays::Yes } @@ -1096,10 +1096,10 @@ fn pallet_hooks_expand() { TestExternalities::default().execute_with(|| { frame_system::Pallet::::set_block_number(1); - assert_eq!(AllPalletsWithoutSystem::on_initialize(1), Weight::from_ref_time(10)); + assert_eq!(AllPalletsWithoutSystem::on_initialize(1), Weight::from_parts(10, 0)); AllPalletsWithoutSystem::on_finalize(1); - assert_eq!(AllPalletsWithoutSystem::on_runtime_upgrade(), Weight::from_ref_time(30)); + assert_eq!(AllPalletsWithoutSystem::on_runtime_upgrade(), Weight::from_parts(30, 0)); assert_eq!( frame_system::Pallet::::events()[0].event, @@ -1137,13 +1137,13 @@ fn all_pallets_type_reversed_order_is_correct() { { assert_eq!( AllPalletsWithoutSystemReversed::on_initialize(1), - Weight::from_ref_time(10) + Weight::from_parts(10, 0) ); AllPalletsWithoutSystemReversed::on_finalize(1); assert_eq!( AllPalletsWithoutSystemReversed::on_runtime_upgrade(), - Weight::from_ref_time(30) + Weight::from_parts(30, 0) ); } @@ -1219,7 +1219,7 @@ fn migrate_from_pallet_version_to_storage_version() { }; // `pallet_num` pallets, 2 writes and every write costs 5 weight. - assert_eq!(Weight::from_ref_time(pallet_num * 2 * 5), weight); + assert_eq!(Weight::from_parts(pallet_num * 2 * 5, 0), 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 8b0573398bd1d..bd11d0da3ca65 100644 --- a/frame/support/test/tests/pallet_compatibility.rs +++ b/frame/support/test/tests/pallet_compatibility.rs @@ -85,7 +85,7 @@ mod pallet_old { fn on_initialize(_n: T::BlockNumber) -> Weight { >::put(T::Balance::from(10)); - Weight::from_ref_time(10) + Weight::from_parts(10, 0) } fn on_finalize(_n: T::BlockNumber) { @@ -131,7 +131,7 @@ pub mod pallet { impl Hooks for Pallet { fn on_initialize(_n: T::BlockNumber) -> Weight { >::put(T::Balance::from(10)); - Weight::from_ref_time(10) + Weight::from_parts(10, 0) } fn on_finalize(_n: T::BlockNumber) { diff --git a/frame/support/test/tests/pallet_compatibility_instance.rs b/frame/support/test/tests/pallet_compatibility_instance.rs index 5cc1c1f4478e7..1d2705b12ff31 100644 --- a/frame/support/test/tests/pallet_compatibility_instance.rs +++ b/frame/support/test/tests/pallet_compatibility_instance.rs @@ -72,7 +72,7 @@ mod pallet_old { fn on_initialize(_n: T::BlockNumber) -> Weight { >::put(T::Balance::from(10)); - Weight::from_ref_time(10) + Weight::from_parts(10, 0) } fn on_finalize(_n: T::BlockNumber) { @@ -117,7 +117,7 @@ pub mod pallet { impl, I: 'static> Hooks for Pallet { fn on_initialize(_n: T::BlockNumber) -> Weight { >::put(T::Balance::from(10)); - Weight::from_ref_time(10) + Weight::from_parts(10, 0) } fn on_finalize(_n: T::BlockNumber) { diff --git a/frame/support/test/tests/pallet_instance.rs b/frame/support/test/tests/pallet_instance.rs index ea1e27fe9f348..6dc73a6d4230f 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)); - Weight::from_ref_time(10) + Weight::from_parts(10, 0) } else { Self::deposit_event(Event::Something(11)); - Weight::from_ref_time(11) + Weight::from_parts(11, 0) } } 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)); - Weight::from_ref_time(30) + Weight::from_parts(30, 0) } else { Self::deposit_event(Event::Something(31)); - Weight::from_ref_time(31) + Weight::from_parts(31, 0) } } fn integrity_test() {} @@ -83,7 +83,7 @@ pub mod pallet { impl, I: 'static> Pallet { /// Doc comment put in metadata #[pallet::call_index(0)] - #[pallet::weight(Weight::from_ref_time(*_foo as u64))] + #[pallet::weight(Weight::from_parts(*_foo as u64, 0))] pub fn foo( origin: OriginFor, #[pallet::compact] _foo: u32, @@ -356,7 +356,7 @@ fn call_expand() { assert_eq!( call_foo.get_dispatch_info(), DispatchInfo { - weight: Weight::from_ref_time(3), + weight: Weight::from_parts(3, 0), class: DispatchClass::Normal, pays_fee: Pays::Yes } @@ -368,7 +368,7 @@ fn call_expand() { assert_eq!( call_foo.get_dispatch_info(), DispatchInfo { - weight: Weight::from_ref_time(3), + weight: Weight::from_parts(3, 0), class: DispatchClass::Normal, pays_fee: Pays::Yes } @@ -649,10 +649,10 @@ fn pallet_hooks_expand() { TestExternalities::default().execute_with(|| { frame_system::Pallet::::set_block_number(1); - assert_eq!(AllPalletsWithoutSystem::on_initialize(1), Weight::from_ref_time(21)); + assert_eq!(AllPalletsWithoutSystem::on_initialize(1), Weight::from_parts(21, 0)); AllPalletsWithoutSystem::on_finalize(1); - assert_eq!(AllPalletsWithoutSystem::on_runtime_upgrade(), Weight::from_ref_time(61)); + assert_eq!(AllPalletsWithoutSystem::on_runtime_upgrade(), Weight::from_parts(61, 0)); assert_eq!( frame_system::Pallet::::events()[0].event, diff --git a/frame/system/src/extensions/check_mortality.rs b/frame/system/src/extensions/check_mortality.rs index 739a27a2ae139..23c357d481350 100644 --- a/frame/system/src/extensions/check_mortality.rs +++ b/frame/system/src/extensions/check_mortality.rs @@ -130,7 +130,7 @@ mod tests { fn signed_ext_check_era_should_change_longevity() { new_test_ext().execute_with(|| { let normal = DispatchInfo { - weight: Weight::from_ref_time(100), + weight: Weight::from_parts(100, 0), class: DispatchClass::Normal, pays_fee: Pays::Yes, }; diff --git a/frame/system/src/extensions/check_weight.rs b/frame/system/src/extensions/check_weight.rs index ca5f7a82c0e8b..1030c8daf7b04 100644 --- a/frame/system/src/extensions/check_weight.rs +++ b/frame/system/src/extensions/check_weight.rs @@ -308,7 +308,7 @@ mod tests { new_test_ext().execute_with(|| { let max = DispatchInfo { weight: block_weights().get(DispatchClass::Normal).max_extrinsic.unwrap() + - Weight::from_ref_time(1), + Weight::from_parts(1, 0), class: DispatchClass::Normal, ..Default::default() }; @@ -334,7 +334,7 @@ mod tests { let okay = DispatchInfo { weight, class: DispatchClass::Operational, ..Default::default() }; let max = DispatchInfo { - weight: weight + Weight::from_ref_time(1), + weight: weight + Weight::from_parts(1, 0), class: DispatchClass::Operational, ..Default::default() }; @@ -366,9 +366,9 @@ mod tests { // So normal extrinsic can be 758 weight (-5 for base extrinsic weight) // 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() }; + DispatchInfo { weight: Weight::from_parts(753, 0), ..Default::default() }; let rest_operational = DispatchInfo { - weight: Weight::from_ref_time(246), + weight: Weight::from_parts(246, 0), class: DispatchClass::Operational, ..Default::default() }; @@ -376,9 +376,9 @@ mod tests { let len = 0_usize; assert_ok!(CheckWeight::::do_pre_dispatch(&max_normal, len)); - assert_eq!(System::block_weight().total(), Weight::from_ref_time(768)); + assert_eq!(System::block_weight().total(), Weight::from_parts(768, 0)); assert_ok!(CheckWeight::::do_pre_dispatch(&rest_operational, len)); - assert_eq!(block_weight_limit(), Weight::from_ref_time(1024).set_proof_size(u64::MAX)); + assert_eq!(block_weight_limit(), Weight::from_parts(1024, 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(())); @@ -390,9 +390,9 @@ mod tests { new_test_ext().execute_with(|| { // We switch the order of `full_block_with_normal_and_operational` let max_normal = - DispatchInfo { weight: Weight::from_ref_time(753), ..Default::default() }; + DispatchInfo { weight: Weight::from_parts(753, 0), ..Default::default() }; let rest_operational = DispatchInfo { - weight: Weight::from_ref_time(246), + weight: Weight::from_parts(246, 0), class: DispatchClass::Operational, ..Default::default() }; @@ -401,9 +401,9 @@ mod tests { assert_ok!(CheckWeight::::do_pre_dispatch(&rest_operational, len)); // Extra 20 here from block execution + base extrinsic weight - assert_eq!(System::block_weight().total(), Weight::from_ref_time(266)); + assert_eq!(System::block_weight().total(), Weight::from_parts(266, 0)); assert_ok!(CheckWeight::::do_pre_dispatch(&max_normal, len)); - assert_eq!(block_weight_limit(), Weight::from_ref_time(1024).set_proof_size(u64::MAX)); + assert_eq!(block_weight_limit(), Weight::from_parts(1024, u64::MAX)); assert_eq!(System::block_weight().total(), block_weight_limit().set_proof_size(0)); }); } @@ -414,12 +414,12 @@ mod tests { // An on_initialize takes up the whole block! (Every time!) System::register_extra_weight_unchecked(Weight::MAX, DispatchClass::Mandatory); let dispatch_normal = DispatchInfo { - weight: Weight::from_ref_time(251), + weight: Weight::from_parts(251, 0), class: DispatchClass::Normal, ..Default::default() }; let dispatch_operational = DispatchInfo { - weight: Weight::from_ref_time(246), + weight: Weight::from_parts(246, 0), class: DispatchClass::Operational, ..Default::default() }; @@ -445,9 +445,9 @@ mod tests { #[test] fn signed_ext_check_weight_works_operational_tx() { new_test_ext().execute_with(|| { - let normal = DispatchInfo { weight: Weight::from_ref_time(100), ..Default::default() }; + let normal = DispatchInfo { weight: Weight::from_parts(100, 0), ..Default::default() }; let op = DispatchInfo { - weight: Weight::from_ref_time(100), + weight: Weight::from_parts(100, 0), class: DispatchClass::Operational, pays_fee: Pays::Yes, }; @@ -513,12 +513,12 @@ 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: Weight::from_ref_time(100), ..Default::default() }; + let small = DispatchInfo { weight: Weight::from_parts(100, 0), ..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 + Weight::from_ref_time(1), + weight: normal_limit - base_extrinsic + Weight::from_parts(1, 0), ..Default::default() }; let len = 0_usize; @@ -537,7 +537,7 @@ mod tests { reset_check_weight(&small, false, Weight::zero()); reset_check_weight(&medium, false, Weight::zero()); - reset_check_weight(&big, true, Weight::from_ref_time(1)); + reset_check_weight(&big, true, Weight::from_parts(1, 0)); }) } @@ -545,9 +545,9 @@ 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: Weight::from_ref_time(512), ..Default::default() }; + let info = DispatchInfo { weight: Weight::from_parts(512, 0), ..Default::default() }; let post_info = PostDispatchInfo { - actual_weight: Some(Weight::from_ref_time(128)), + actual_weight: Some(Weight::from_parts(128, 0)), pays_fee: Default::default(), }; let len = 0_usize; @@ -557,13 +557,13 @@ mod tests { BlockWeight::::mutate(|current_weight| { current_weight.set(Weight::zero(), DispatchClass::Mandatory); current_weight - .set(Weight::from_ref_time(256) - base_extrinsic, DispatchClass::Normal); + .set(Weight::from_parts(256, 0) - base_extrinsic, DispatchClass::Normal); }); let pre = CheckWeight::(PhantomData).pre_dispatch(&1, CALL, &info, len).unwrap(); assert_eq!( BlockWeight::::get().total(), - info.weight + Weight::from_ref_time(256) + info.weight + Weight::from_parts(256, 0) ); assert_ok!(CheckWeight::::post_dispatch( @@ -575,7 +575,7 @@ mod tests { )); assert_eq!( BlockWeight::::get().total(), - post_info.actual_weight.unwrap() + Weight::from_ref_time(256) + post_info.actual_weight.unwrap() + Weight::from_parts(256, 0) ); }) } @@ -583,23 +583,23 @@ mod tests { #[test] fn signed_ext_check_weight_actual_weight_higher_than_max_is_capped() { new_test_ext().execute_with(|| { - let info = DispatchInfo { weight: Weight::from_ref_time(512), ..Default::default() }; + let info = DispatchInfo { weight: Weight::from_parts(512, 0), ..Default::default() }; let post_info = PostDispatchInfo { - actual_weight: Some(Weight::from_ref_time(700)), + actual_weight: Some(Weight::from_parts(700, 0)), pays_fee: Default::default(), }; let len = 0_usize; BlockWeight::::mutate(|current_weight| { current_weight.set(Weight::zero(), DispatchClass::Mandatory); - current_weight.set(Weight::from_ref_time(128), DispatchClass::Normal); + current_weight.set(Weight::from_parts(128, 0), DispatchClass::Normal); }); let pre = CheckWeight::(PhantomData).pre_dispatch(&1, CALL, &info, len).unwrap(); assert_eq!( BlockWeight::::get().total(), info.weight + - Weight::from_ref_time(128) + + Weight::from_parts(128, 0) + block_weights().get(DispatchClass::Normal).base_extrinsic, ); @@ -613,7 +613,7 @@ mod tests { assert_eq!( BlockWeight::::get().total(), info.weight + - Weight::from_ref_time(128) + + Weight::from_parts(128, 0) + block_weights().get(DispatchClass::Normal).base_extrinsic, ); }) @@ -643,9 +643,9 @@ mod tests { // Max normal is 768 (75%) // Max mandatory is unlimited let max_normal = - DispatchInfo { weight: Weight::from_ref_time(753), ..Default::default() }; + DispatchInfo { weight: Weight::from_parts(753, 0), ..Default::default() }; let mandatory = DispatchInfo { - weight: Weight::from_ref_time(1019), + weight: Weight::from_parts(1019, 0), class: DispatchClass::Mandatory, ..Default::default() }; @@ -653,10 +653,10 @@ mod tests { let len = 0_usize; assert_ok!(CheckWeight::::do_pre_dispatch(&max_normal, len)); - assert_eq!(System::block_weight().total(), Weight::from_ref_time(768)); + assert_eq!(System::block_weight().total(), Weight::from_parts(768, 0)); assert_ok!(CheckWeight::::do_pre_dispatch(&mandatory, len)); - 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!(block_weight_limit(), Weight::from_parts(1024, u64::MAX)); + assert_eq!(System::block_weight().total(), Weight::from_parts(1024 + 768, 0)); assert_eq!(CheckWeight::::check_extrinsic_weight(&mandatory), Ok(())); }); } @@ -668,30 +668,30 @@ 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).set_proof_size(u64::MAX)); + w.max_total = Some(Weight::from_parts(20, u64::MAX)); }) .for_class(DispatchClass::Mandatory, |w| { w.base_extrinsic = Weight::zero(); - w.reserved = Some(Weight::from_ref_time(5).set_proof_size(u64::MAX)); + w.reserved = Some(Weight::from_parts(5, u64::MAX)); w.max_total = None; }) .build_or_panic(); let all_weight = crate::ConsumedWeight::new(|class| match class { - DispatchClass::Normal => Weight::from_ref_time(10), - DispatchClass::Operational => Weight::from_ref_time(10), + DispatchClass::Normal => Weight::from_parts(10, 0), + DispatchClass::Operational => Weight::from_parts(10, 0), DispatchClass::Mandatory => Weight::zero(), }); assert_eq!(maximum_weight.max_block, all_weight.total().set_proof_size(u64::MAX)); // fits into reserved let mandatory1 = DispatchInfo { - weight: Weight::from_ref_time(5), + weight: Weight::from_parts(5, 0), class: DispatchClass::Mandatory, ..Default::default() }; // does not fit into reserved and the block is full. let mandatory2 = DispatchInfo { - weight: Weight::from_ref_time(6), + weight: Weight::from_parts(6, 0), class: DispatchClass::Mandatory, ..Default::default() }; diff --git a/frame/system/src/mock.rs b/frame/system/src/mock.rs index a3807512dedcb..83e12dccaa165 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).set_proof_size(u64::MAX); +const MAX_BLOCK_WEIGHT: Weight = Weight::from_parts(1024, u64::MAX); parameter_types! { pub Version: RuntimeVersion = RuntimeVersion { @@ -59,15 +59,15 @@ parameter_types! { write: 100, }; pub RuntimeBlockWeights: limits::BlockWeights = limits::BlockWeights::builder() - .base_block(Weight::from_ref_time(10)) + .base_block(Weight::from_parts(10, 0)) .for_class(DispatchClass::all(), |weights| { - weights.base_extrinsic = Weight::from_ref_time(5); + weights.base_extrinsic = Weight::from_parts(5, 0); }) .for_class(DispatchClass::Normal, |weights| { weights.max_total = Some(NORMAL_DISPATCH_RATIO * MAX_BLOCK_WEIGHT); }) .for_class(DispatchClass::Operational, |weights| { - weights.base_extrinsic = Weight::from_ref_time(10); + weights.base_extrinsic = Weight::from_parts(10, 0); 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 3e24d8f3c2fe4..ebb28ca87bbd8 100644 --- a/frame/system/src/tests.rs +++ b/frame/system/src/tests.rs @@ -233,7 +233,7 @@ fn deposit_event_uses_actual_weight_and_pays_fee() { let normal_base = ::BlockWeights::get() .get(DispatchClass::Normal) .base_extrinsic; - let pre_info = DispatchInfo { weight: Weight::from_ref_time(1000), ..Default::default() }; + let pre_info = DispatchInfo { weight: Weight::from_parts(1000, 0), ..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( @@ -246,7 +246,7 @@ fn deposit_event_uses_actual_weight_and_pays_fee() { 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(Weight::from_ref_time(999))), + &Err(DispatchError::BadOrigin.with_weight(Weight::from_parts(999, 0))), pre_info, ); @@ -260,7 +260,7 @@ fn deposit_event_uses_actual_weight_and_pays_fee() { System::note_applied_extrinsic( &Err(DispatchErrorWithPostInfo { post_info: PostDispatchInfo { - actual_weight: Some(Weight::from_ref_time(800)), + actual_weight: Some(Weight::from_parts(800, 0)), pays_fee: Pays::Yes, }, error: DispatchError::BadOrigin, @@ -270,7 +270,7 @@ fn deposit_event_uses_actual_weight_and_pays_fee() { System::note_applied_extrinsic( &Err(DispatchErrorWithPostInfo { post_info: PostDispatchInfo { - actual_weight: Some(Weight::from_ref_time(800)), + actual_weight: Some(Weight::from_parts(800, 0)), pays_fee: Pays::No, }, error: DispatchError::BadOrigin, @@ -283,7 +283,7 @@ fn deposit_event_uses_actual_weight_and_pays_fee() { .base_extrinsic; assert!(normal_base != operational_base, "Test pre-condition violated"); let pre_info = DispatchInfo { - weight: Weight::from_ref_time(1000), + weight: Weight::from_parts(1000, 0), class: DispatchClass::Operational, ..Default::default() }; @@ -295,7 +295,7 @@ fn deposit_event_uses_actual_weight_and_pays_fee() { phase: Phase::ApplyExtrinsic(0), event: SysEvent::ExtrinsicSuccess { dispatch_info: DispatchInfo { - weight: Weight::from_ref_time(300).saturating_add(normal_base), + weight: Weight::from_parts(300, 0).saturating_add(normal_base), ..Default::default() }, } @@ -306,7 +306,7 @@ fn deposit_event_uses_actual_weight_and_pays_fee() { phase: Phase::ApplyExtrinsic(1), event: SysEvent::ExtrinsicSuccess { dispatch_info: DispatchInfo { - weight: Weight::from_ref_time(1000).saturating_add(normal_base), + weight: Weight::from_parts(1000, 0).saturating_add(normal_base), ..Default::default() }, } @@ -317,7 +317,7 @@ fn deposit_event_uses_actual_weight_and_pays_fee() { phase: Phase::ApplyExtrinsic(2), event: SysEvent::ExtrinsicSuccess { dispatch_info: DispatchInfo { - weight: Weight::from_ref_time(1000).saturating_add(normal_base), + weight: Weight::from_parts(1000, 0).saturating_add(normal_base), ..Default::default() }, } @@ -328,7 +328,7 @@ fn deposit_event_uses_actual_weight_and_pays_fee() { phase: Phase::ApplyExtrinsic(3), event: SysEvent::ExtrinsicSuccess { dispatch_info: DispatchInfo { - weight: Weight::from_ref_time(1000).saturating_add(normal_base), + weight: Weight::from_parts(1000, 0).saturating_add(normal_base), pays_fee: Pays::Yes, ..Default::default() }, @@ -340,7 +340,7 @@ fn deposit_event_uses_actual_weight_and_pays_fee() { phase: Phase::ApplyExtrinsic(4), event: SysEvent::ExtrinsicSuccess { dispatch_info: DispatchInfo { - weight: Weight::from_ref_time(1000).saturating_add(normal_base), + weight: Weight::from_parts(1000, 0).saturating_add(normal_base), pays_fee: Pays::No, ..Default::default() }, @@ -352,7 +352,7 @@ fn deposit_event_uses_actual_weight_and_pays_fee() { phase: Phase::ApplyExtrinsic(5), event: SysEvent::ExtrinsicSuccess { dispatch_info: DispatchInfo { - weight: Weight::from_ref_time(1000).saturating_add(normal_base), + weight: Weight::from_parts(1000, 0).saturating_add(normal_base), pays_fee: Pays::No, ..Default::default() }, @@ -364,7 +364,7 @@ fn deposit_event_uses_actual_weight_and_pays_fee() { phase: Phase::ApplyExtrinsic(6), event: SysEvent::ExtrinsicSuccess { dispatch_info: DispatchInfo { - weight: Weight::from_ref_time(500).saturating_add(normal_base), + weight: Weight::from_parts(500, 0).saturating_add(normal_base), pays_fee: Pays::No, ..Default::default() }, @@ -377,7 +377,7 @@ fn deposit_event_uses_actual_weight_and_pays_fee() { event: SysEvent::ExtrinsicFailed { dispatch_error: DispatchError::BadOrigin.into(), dispatch_info: DispatchInfo { - weight: Weight::from_ref_time(999).saturating_add(normal_base), + weight: Weight::from_parts(999, 0).saturating_add(normal_base), ..Default::default() }, } @@ -389,7 +389,7 @@ fn deposit_event_uses_actual_weight_and_pays_fee() { event: SysEvent::ExtrinsicFailed { dispatch_error: DispatchError::BadOrigin.into(), dispatch_info: DispatchInfo { - weight: Weight::from_ref_time(1000).saturating_add(normal_base), + weight: Weight::from_parts(1000, 0).saturating_add(normal_base), pays_fee: Pays::Yes, ..Default::default() }, @@ -402,7 +402,7 @@ fn deposit_event_uses_actual_weight_and_pays_fee() { event: SysEvent::ExtrinsicFailed { dispatch_error: DispatchError::BadOrigin.into(), dispatch_info: DispatchInfo { - weight: Weight::from_ref_time(800).saturating_add(normal_base), + weight: Weight::from_parts(800, 0).saturating_add(normal_base), pays_fee: Pays::Yes, ..Default::default() }, @@ -415,7 +415,7 @@ fn deposit_event_uses_actual_weight_and_pays_fee() { event: SysEvent::ExtrinsicFailed { dispatch_error: DispatchError::BadOrigin.into(), dispatch_info: DispatchInfo { - weight: Weight::from_ref_time(800).saturating_add(normal_base), + weight: Weight::from_parts(800, 0).saturating_add(normal_base), pays_fee: Pays::No, ..Default::default() }, @@ -427,7 +427,7 @@ fn deposit_event_uses_actual_weight_and_pays_fee() { phase: Phase::ApplyExtrinsic(11), event: SysEvent::ExtrinsicSuccess { dispatch_info: DispatchInfo { - weight: Weight::from_ref_time(300).saturating_add(operational_base), + weight: Weight::from_parts(300, 0).saturating_add(operational_base), class: DispatchClass::Operational, ..Default::default() }, diff --git a/frame/system/src/weights.rs b/frame/system/src/weights.rs index fa77db90d0c96..812f2d091fcfe 100644 --- a/frame/system/src/weights.rs +++ b/frame/system/src/weights.rs @@ -65,9 +65,9 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 2_018 nanoseconds. - Weight::from_ref_time(2_091_000) + Weight::from_parts(2_091_000, 0) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(362).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(362, 0).saturating_mul(b.into())) } /// The range of component `b` is `[0, 3932160]`. fn remark_with_event(b: u32, ) -> Weight { @@ -75,9 +75,9 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 7_449 nanoseconds. - Weight::from_ref_time(7_748_000) + Weight::from_parts(7_748_000, 0) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_423).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(1_423, 0).saturating_mul(b.into())) } /// Storage: System Digest (r:1 w:1) /// Proof Skipped: System Digest (max_values: Some(1), max_size: None, mode: Measured) @@ -100,9 +100,9 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 1_981 nanoseconds. - Weight::from_ref_time(2_114_000) + Weight::from_parts(2_114_000, 0) // Standard Error: 804 - .saturating_add(Weight::from_ref_time(631_438).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(631_438, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) } /// Storage: Skipped Metadata (r:0 w:0) @@ -113,9 +113,9 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 2_061 nanoseconds. - Weight::from_ref_time(2_153_000) + Weight::from_parts(2_153_000, 0) // Standard Error: 952 - .saturating_add(Weight::from_ref_time(502_629).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(502_629, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) } /// Storage: Skipped Metadata (r:0 w:0) @@ -128,9 +128,9 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 4_026 nanoseconds. Weight::from_parts(4_174_000, 121) // Standard Error: 1_148 - .saturating_add(Weight::from_ref_time(1_093_099).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(1_093_099, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(p.into()))) - .saturating_add(Weight::from_proof_size(70).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 70).saturating_mul(p.into())) } } @@ -142,9 +142,9 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 2_018 nanoseconds. - Weight::from_ref_time(2_091_000) + Weight::from_parts(2_091_000, 0) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(362).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(362, 0).saturating_mul(b.into())) } /// The range of component `b` is `[0, 3932160]`. fn remark_with_event(b: u32, ) -> Weight { @@ -152,9 +152,9 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 7_449 nanoseconds. - Weight::from_ref_time(7_748_000) + Weight::from_parts(7_748_000, 0) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_423).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(1_423, 0).saturating_mul(b.into())) } /// Storage: System Digest (r:1 w:1) /// Proof Skipped: System Digest (max_values: Some(1), max_size: None, mode: Measured) @@ -177,9 +177,9 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 1_981 nanoseconds. - Weight::from_ref_time(2_114_000) + Weight::from_parts(2_114_000, 0) // Standard Error: 804 - .saturating_add(Weight::from_ref_time(631_438).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(631_438, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(i.into()))) } /// Storage: Skipped Metadata (r:0 w:0) @@ -190,9 +190,9 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 2_061 nanoseconds. - Weight::from_ref_time(2_153_000) + Weight::from_parts(2_153_000, 0) // Standard Error: 952 - .saturating_add(Weight::from_ref_time(502_629).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(502_629, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(i.into()))) } /// Storage: Skipped Metadata (r:0 w:0) @@ -205,8 +205,8 @@ impl WeightInfo for () { // Minimum execution time: 4_026 nanoseconds. Weight::from_parts(4_174_000, 121) // Standard Error: 1_148 - .saturating_add(Weight::from_ref_time(1_093_099).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(1_093_099, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(p.into()))) - .saturating_add(Weight::from_proof_size(70).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 70).saturating_mul(p.into())) } } diff --git a/frame/timestamp/src/weights.rs b/frame/timestamp/src/weights.rs index 8c7ef0d1f1afe..943f941d55305 100644 --- a/frame/timestamp/src/weights.rs +++ b/frame/timestamp/src/weights.rs @@ -73,7 +73,7 @@ impl WeightInfo for SubstrateWeight { // Measured: `161` // Estimated: `0` // Minimum execution time: 3_927 nanoseconds. - Weight::from_ref_time(4_078_000) + Weight::from_parts(4_078_000, 0) } } @@ -97,6 +97,6 @@ impl WeightInfo for () { // Measured: `161` // Estimated: `0` // Minimum execution time: 3_927 nanoseconds. - Weight::from_ref_time(4_078_000) + Weight::from_parts(4_078_000, 0) } } diff --git a/frame/tips/src/weights.rs b/frame/tips/src/weights.rs index 41fdf4928833c..2b265d7879712 100644 --- a/frame/tips/src/weights.rs +++ b/frame/tips/src/weights.rs @@ -71,7 +71,7 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 23_262 nanoseconds. Weight::from_parts(24_104_224, 4958) // Standard Error: 148 - .saturating_add(Weight::from_ref_time(1_963).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(1_963, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -103,12 +103,12 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 18_382 nanoseconds. Weight::from_parts(18_195_288, 4644) // Standard Error: 103 - .saturating_add(Weight::from_ref_time(2_096).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(2_096, 0).saturating_mul(r.into())) // Standard Error: 2_469 - .saturating_add(Weight::from_ref_time(97_092).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(97_092, 0).saturating_mul(t.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) - .saturating_add(Weight::from_proof_size(192).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(0, 192).saturating_mul(t.into())) } /// Storage: Elections Members (r:1 w:0) /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) @@ -122,10 +122,10 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 13_564 nanoseconds. Weight::from_parts(13_867_280, 4592) // Standard Error: 4_245 - .saturating_add(Weight::from_ref_time(206_587).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(206_587, 0).saturating_mul(t.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) - .saturating_add(Weight::from_proof_size(224).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(0, 224).saturating_mul(t.into())) } /// Storage: Tips Tips (r:1 w:1) /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) @@ -143,10 +143,10 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 39_902 nanoseconds. Weight::from_parts(40_747_650, 8096) // Standard Error: 5_322 - .saturating_add(Weight::from_ref_time(144_298).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(144_298, 0).saturating_mul(t.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(336).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(0, 336).saturating_mul(t.into())) } /// Storage: Tips Tips (r:1 w:1) /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) @@ -160,7 +160,7 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 13_511 nanoseconds. Weight::from_parts(14_114_101, 3077) // Standard Error: 1_815 - .saturating_add(Weight::from_ref_time(7_825).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(7_825, 0).saturating_mul(t.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -180,7 +180,7 @@ impl WeightInfo for () { // Minimum execution time: 23_262 nanoseconds. Weight::from_parts(24_104_224, 4958) // Standard Error: 148 - .saturating_add(Weight::from_ref_time(1_963).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(1_963, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -212,12 +212,12 @@ impl WeightInfo for () { // Minimum execution time: 18_382 nanoseconds. Weight::from_parts(18_195_288, 4644) // Standard Error: 103 - .saturating_add(Weight::from_ref_time(2_096).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(2_096, 0).saturating_mul(r.into())) // Standard Error: 2_469 - .saturating_add(Weight::from_ref_time(97_092).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(97_092, 0).saturating_mul(t.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) - .saturating_add(Weight::from_proof_size(192).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(0, 192).saturating_mul(t.into())) } /// Storage: Elections Members (r:1 w:0) /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) @@ -231,10 +231,10 @@ impl WeightInfo for () { // Minimum execution time: 13_564 nanoseconds. Weight::from_parts(13_867_280, 4592) // Standard Error: 4_245 - .saturating_add(Weight::from_ref_time(206_587).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(206_587, 0).saturating_mul(t.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) - .saturating_add(Weight::from_proof_size(224).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(0, 224).saturating_mul(t.into())) } /// Storage: Tips Tips (r:1 w:1) /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) @@ -252,10 +252,10 @@ impl WeightInfo for () { // Minimum execution time: 39_902 nanoseconds. Weight::from_parts(40_747_650, 8096) // Standard Error: 5_322 - .saturating_add(Weight::from_ref_time(144_298).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(144_298, 0).saturating_mul(t.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(336).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(0, 336).saturating_mul(t.into())) } /// Storage: Tips Tips (r:1 w:1) /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) @@ -269,7 +269,7 @@ impl WeightInfo for () { // Minimum execution time: 13_511 nanoseconds. Weight::from_parts(14_114_101, 3077) // Standard Error: 1_815 - .saturating_add(Weight::from_ref_time(7_825).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(7_825, 0).saturating_mul(t.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } diff --git a/frame/transaction-payment/asset-tx-payment/src/mock.rs b/frame/transaction-payment/asset-tx-payment/src/mock.rs index ada4777cfe719..bc994b4dce2cb 100644 --- a/frame/transaction-payment/asset-tx-payment/src/mock.rs +++ b/frame/transaction-payment/asset-tx-payment/src/mock.rs @@ -67,7 +67,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).set_proof_size(u64::MAX).into(); + weights.max_total = Weight::from_parts(1024, u64::MAX).into(); }) .build_or_panic() } diff --git a/frame/transaction-payment/asset-tx-payment/src/tests.rs b/frame/transaction-payment/asset-tx-payment/src/tests.rs index 08699fef032e8..cd9891825db32 100644 --- a/frame/transaction-payment/asset-tx-payment/src/tests.rs +++ b/frame/transaction-payment/asset-tx-payment/src/tests.rs @@ -41,7 +41,7 @@ impl Default for ExtBuilder { fn default() -> Self { Self { balance_factor: 1, - base_weight: Weight::from_ref_time(0), + base_weight: Weight::from_parts(0, 0), byte_fee: 1, weight_to_fee: 1, } @@ -112,19 +112,19 @@ fn transaction_payment_in_native_possible() { let balance_factor = 100; ExtBuilder::default() .balance_factor(balance_factor) - .base_weight(Weight::from_ref_time(5)) + .base_weight(Weight::from_parts(5, 0)) .build() .execute_with(|| { let len = 10; let pre = ChargeAssetTxPayment::::from(0, None) - .pre_dispatch(&1, CALL, &info_from_weight(Weight::from_ref_time(5)), len) + .pre_dispatch(&1, CALL, &info_from_weight(Weight::from_parts(5, 0)), 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(Weight::from_ref_time(5)), + &info_from_weight(Weight::from_parts(5, 0)), &default_post_info(), len, &Ok(()) @@ -132,15 +132,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(Weight::from_ref_time(100)), len) + .pre_dispatch(&2, CALL, &info_from_weight(Weight::from_parts(100, 0)), 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(Weight::from_ref_time(100)), - &post_info_from_weight(Weight::from_ref_time(50)), + &info_from_weight(Weight::from_parts(100, 0)), + &post_info_from_weight(Weight::from_parts(50, 0)), len, &Ok(()) )); @@ -154,7 +154,7 @@ fn transaction_payment_in_asset_possible() { let balance_factor = 100; ExtBuilder::default() .balance_factor(balance_factor) - .base_weight(Weight::from_ref_time(base_weight)) + .base_weight(Weight::from_parts(base_weight, 0)) .build() .execute_with(|| { // create the asset @@ -180,7 +180,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::from_ref_time(weight)), len) + .pre_dispatch(&caller, CALL, &info_from_weight(Weight::from_parts(weight, 0)), len) .unwrap(); // assert that native balance is not used assert_eq!(Balances::free_balance(caller), 10 * balance_factor); @@ -190,7 +190,7 @@ fn transaction_payment_in_asset_possible() { assert_ok!(ChargeAssetTxPayment::::post_dispatch( Some(pre), - &info_from_weight(Weight::from_ref_time(weight)), + &info_from_weight(Weight::from_parts(weight, 0)), &default_post_info(), len, &Ok(()) @@ -207,7 +207,7 @@ fn transaction_payment_without_fee() { let balance_factor = 100; ExtBuilder::default() .balance_factor(balance_factor) - .base_weight(Weight::from_ref_time(base_weight)) + .base_weight(Weight::from_parts(base_weight, 0)) .build() .execute_with(|| { // create the asset @@ -233,7 +233,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::from_ref_time(weight)), len) + .pre_dispatch(&caller, CALL, &info_from_weight(Weight::from_parts(weight, 0)), len) .unwrap(); // assert that native balance is not used assert_eq!(Balances::free_balance(caller), 10 * balance_factor); @@ -243,7 +243,7 @@ fn transaction_payment_without_fee() { assert_ok!(ChargeAssetTxPayment::::post_dispatch( Some(pre), - &info_from_weight(Weight::from_ref_time(weight)), + &info_from_weight(Weight::from_parts(weight, 0)), &post_info_from_pays(Pays::No), len, &Ok(()) @@ -260,7 +260,7 @@ fn asset_transaction_payment_with_tip_and_refund() { let base_weight = 5; ExtBuilder::default() .balance_factor(100) - .base_weight(Weight::from_ref_time(base_weight)) + .base_weight(Weight::from_parts(base_weight, 0)) .build() .execute_with(|| { // create the asset @@ -288,15 +288,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::from_ref_time(weight)), len) + .pre_dispatch(&caller, CALL, &info_from_weight(Weight::from_parts(weight, 0)), 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::from_ref_time(weight)), - &post_info_from_weight(Weight::from_ref_time(final_weight)), + &info_from_weight(Weight::from_parts(weight, 0)), + &post_info_from_weight(Weight::from_parts(final_weight, 0)), len, &Ok(()) )); @@ -312,7 +312,7 @@ fn payment_from_account_with_only_assets() { let base_weight = 5; ExtBuilder::default() .balance_factor(100) - .base_weight(Weight::from_ref_time(base_weight)) + .base_weight(Weight::from_parts(base_weight, 0)) .build() .execute_with(|| { // create the asset @@ -340,7 +340,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::from_ref_time(weight)), len) + .pre_dispatch(&caller, CALL, &info_from_weight(Weight::from_parts(weight, 0)), len) .unwrap(); assert_eq!(Balances::free_balance(caller), 0); // check that fee was charged in the given asset @@ -348,7 +348,7 @@ fn payment_from_account_with_only_assets() { assert_ok!(ChargeAssetTxPayment::::post_dispatch( Some(pre), - &info_from_weight(Weight::from_ref_time(weight)), + &info_from_weight(Weight::from_parts(weight, 0)), &default_post_info(), len, &Ok(()) @@ -363,7 +363,7 @@ fn payment_only_with_existing_sufficient_asset() { let base_weight = 5; ExtBuilder::default() .balance_factor(100) - .base_weight(Weight::from_ref_time(base_weight)) + .base_weight(Weight::from_parts(base_weight, 0)) .build() .execute_with(|| { let asset_id = 1; @@ -372,7 +372,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::from_ref_time(weight)), len) + .pre_dispatch(&caller, CALL, &info_from_weight(Weight::from_parts(weight, 0)), len) .is_err()); // create the non-sufficient asset @@ -386,7 +386,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::from_ref_time(weight)), len) + .pre_dispatch(&caller, CALL, &info_from_weight(Weight::from_parts(weight, 0)), len) .is_err()); }); } @@ -396,7 +396,7 @@ fn converted_fee_is_never_zero_if_input_fee_is_not() { let base_weight = 1; ExtBuilder::default() .balance_factor(100) - .base_weight(Weight::from_ref_time(base_weight)) + .base_weight(Weight::from_parts(base_weight, 0)) .build() .execute_with(|| { // create the asset @@ -440,14 +440,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::from_ref_time(weight)), len) + .pre_dispatch(&caller, CALL, &info_from_weight(Weight::from_parts(weight, 0)), 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::from_ref_time(weight)), + &info_from_weight(Weight::from_parts(weight, 0)), &default_post_info(), len, &Ok(()) @@ -461,7 +461,7 @@ fn post_dispatch_fee_is_zero_if_pre_dispatch_fee_is_zero() { let base_weight = 1; ExtBuilder::default() .balance_factor(100) - .base_weight(Weight::from_ref_time(base_weight)) + .base_weight(Weight::from_parts(base_weight, 0)) .build() .execute_with(|| { // create the asset @@ -518,7 +518,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(Weight::from_ref_time(base_weight)) + .base_weight(Weight::from_parts(base_weight, 0)) .build() .execute_with(|| { // create the asset @@ -542,7 +542,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::from_ref_time(weight)), + &info_from_weight(Weight::from_parts(weight, 0)), len, ) .unwrap(); @@ -553,7 +553,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::from_ref_time(weight)), + &info_from_weight(Weight::from_parts(weight, 0)), &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 6ed3e9789c35a..42798c62f4012 100644 --- a/frame/transaction-payment/src/lib.rs +++ b/frame/transaction-payment/src/lib.rs @@ -614,7 +614,7 @@ where /// Compute the length portion of a fee by invoking the configured `LengthToFee` impl. pub fn length_to_fee(length: u32) -> BalanceOf { - T::LengthToFee::weight_to_fee(&Weight::from_ref_time(length as u64)) + T::LengthToFee::weight_to_fee(&Weight::from_parts(length as u64, 0)) } /// Compute the unadjusted portion of the weight fee by invoking the configured `WeightToFee` diff --git a/frame/transaction-payment/src/mock.rs b/frame/transaction-payment/src/mock.rs index b4b8a784a6f22..92799bf5b0237 100644 --- a/frame/transaction-payment/src/mock.rs +++ b/frame/transaction-payment/src/mock.rs @@ -64,7 +64,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).set_proof_size(u64::MAX).into(); + weights.max_total = Weight::from_parts(1024, u64::MAX).into(); }) .build_or_panic() } diff --git a/frame/transaction-payment/src/tests.rs b/frame/transaction-payment/src/tests.rs index 2748b80b1cdac..218f50e1cc95f 100644 --- a/frame/transaction-payment/src/tests.rs +++ b/frame/transaction-payment/src/tests.rs @@ -129,18 +129,18 @@ fn default_post_info() -> PostDispatchInfo { fn signed_extension_transaction_payment_work() { ExtBuilder::default() .balance_factor(10) - .base_weight(Weight::from_ref_time(5)) + .base_weight(Weight::from_parts(5, 0)) .build() .execute_with(|| { let len = 10; let pre = ChargeTransactionPayment::::from(0) - .pre_dispatch(&1, CALL, &info_from_weight(Weight::from_ref_time(5)), len) + .pre_dispatch(&1, CALL, &info_from_weight(Weight::from_parts(5, 0)), len) .unwrap(); assert_eq!(Balances::free_balance(1), 100 - 5 - 5 - 10); assert_ok!(ChargeTransactionPayment::::post_dispatch( Some(pre), - &info_from_weight(Weight::from_ref_time(5)), + &info_from_weight(Weight::from_parts(5, 0)), &default_post_info(), len, &Ok(()) @@ -152,14 +152,14 @@ fn signed_extension_transaction_payment_work() { FeeUnbalancedAmount::mutate(|a| *a = 0); let pre = ChargeTransactionPayment::::from(5 /* tipped */) - .pre_dispatch(&2, CALL, &info_from_weight(Weight::from_ref_time(100)), len) + .pre_dispatch(&2, CALL, &info_from_weight(Weight::from_parts(100, 0)), len) .unwrap(); assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 100 - 5); assert_ok!(ChargeTransactionPayment::::post_dispatch( Some(pre), - &info_from_weight(Weight::from_ref_time(100)), - &post_info_from_weight(Weight::from_ref_time(50)), + &info_from_weight(Weight::from_parts(100, 0)), + &post_info_from_weight(Weight::from_parts(50, 0)), len, &Ok(()) )); @@ -173,22 +173,22 @@ fn signed_extension_transaction_payment_work() { fn signed_extension_transaction_payment_multiplied_refund_works() { ExtBuilder::default() .balance_factor(10) - .base_weight(Weight::from_ref_time(5)) + .base_weight(Weight::from_parts(5, 0)) .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(Weight::from_ref_time(100)), len) + .pre_dispatch(&2, CALL, &info_from_weight(Weight::from_parts(100, 0)), 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(Weight::from_ref_time(100)), - &post_info_from_weight(Weight::from_ref_time(50)), + &info_from_weight(Weight::from_parts(100, 0)), + &post_info_from_weight(Weight::from_parts(50, 0)), len, &Ok(()) )); @@ -219,7 +219,7 @@ fn signed_extension_transaction_payment_is_bounded() { #[test] fn signed_extension_allows_free_transactions() { ExtBuilder::default() - .base_weight(Weight::from_ref_time(100)) + .base_weight(Weight::from_parts(100, 0)) .balance_factor(0) .build() .execute_with(|| { @@ -230,7 +230,7 @@ fn signed_extension_allows_free_transactions() { // This is a completely free (and thus wholly insecure/DoS-ridden) transaction. let operational_transaction = DispatchInfo { - weight: Weight::from_ref_time(0), + weight: Weight::from_parts(0, 0), class: DispatchClass::Operational, pays_fee: Pays::No, }; @@ -243,7 +243,7 @@ fn signed_extension_allows_free_transactions() { // like a InsecureFreeNormal let free_transaction = DispatchInfo { - weight: Weight::from_ref_time(0), + weight: Weight::from_parts(0, 0), class: DispatchClass::Normal, pays_fee: Pays::Yes, }; @@ -262,7 +262,7 @@ fn signed_extension_allows_free_transactions() { #[test] fn signed_ext_length_fee_is_also_updated_per_congestion() { ExtBuilder::default() - .base_weight(Weight::from_ref_time(5)) + .base_weight(Weight::from_parts(5, 0)) .balance_factor(10) .build() .execute_with(|| { @@ -271,7 +271,7 @@ fn signed_ext_length_fee_is_also_updated_per_congestion() { let len = 10; assert_ok!(ChargeTransactionPayment::::from(10) // tipped - .pre_dispatch(&1, CALL, &info_from_weight(Weight::from_ref_time(3)), len)); + .pre_dispatch(&1, CALL, &info_from_weight(Weight::from_parts(3, 0)), len)); assert_eq!( Balances::free_balance(1), 100 // original @@ -297,7 +297,7 @@ fn query_info_and_fee_details_works() { let unsigned_xt_info = unsigned_xt.get_dispatch_info(); ExtBuilder::default() - .base_weight(Weight::from_ref_time(5)) + .base_weight(Weight::from_parts(5, 0)) .weight_fee(2) .build() .execute_with(|| { @@ -354,7 +354,7 @@ fn query_call_info_and_fee_details_works() { let len = encoded_call.len() as u32; ExtBuilder::default() - .base_weight(Weight::from_ref_time(5)) + .base_weight(Weight::from_parts(5, 0)) .weight_fee(2) .build() .execute_with(|| { @@ -392,7 +392,7 @@ fn query_call_info_and_fee_details_works() { #[test] fn compute_fee_works_without_multiplier() { ExtBuilder::default() - .base_weight(Weight::from_ref_time(100)) + .base_weight(Weight::from_parts(100, 0)) .byte_fee(10) .balance_factor(0) .build() @@ -402,14 +402,14 @@ fn compute_fee_works_without_multiplier() { // Tip only, no fees works let dispatch_info = DispatchInfo { - weight: Weight::from_ref_time(0), + weight: Weight::from_parts(0, 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: Weight::from_ref_time(0), + weight: Weight::from_parts(0, 0), class: DispatchClass::Operational, pays_fee: Pays::Yes, }; @@ -420,7 +420,7 @@ fn compute_fee_works_without_multiplier() { assert_eq!(Pallet::::compute_fee(42, &dispatch_info, 0), 520); // Weight fee + base fee works let dispatch_info = DispatchInfo { - weight: Weight::from_ref_time(1000), + weight: Weight::from_parts(1000, 0), class: DispatchClass::Operational, pays_fee: Pays::Yes, }; @@ -431,7 +431,7 @@ fn compute_fee_works_without_multiplier() { #[test] fn compute_fee_works_with_multiplier() { ExtBuilder::default() - .base_weight(Weight::from_ref_time(100)) + .base_weight(Weight::from_parts(100, 0)) .byte_fee(10) .balance_factor(0) .build() @@ -440,7 +440,7 @@ fn compute_fee_works_with_multiplier() { >::put(Multiplier::saturating_from_rational(3, 2)); // Base fee is unaffected by multiplier let dispatch_info = DispatchInfo { - weight: Weight::from_ref_time(0), + weight: Weight::from_parts(0, 0), class: DispatchClass::Operational, pays_fee: Pays::Yes, }; @@ -448,7 +448,7 @@ fn compute_fee_works_with_multiplier() { // Everything works together :) let dispatch_info = DispatchInfo { - weight: Weight::from_ref_time(123), + weight: Weight::from_parts(123, 0), class: DispatchClass::Operational, pays_fee: Pays::Yes, }; @@ -463,7 +463,7 @@ fn compute_fee_works_with_multiplier() { #[test] fn compute_fee_works_with_negative_multiplier() { ExtBuilder::default() - .base_weight(Weight::from_ref_time(100)) + .base_weight(Weight::from_parts(100, 0)) .byte_fee(10) .balance_factor(0) .build() @@ -473,7 +473,7 @@ fn compute_fee_works_with_negative_multiplier() { // Base fee is unaffected by multiplier. let dispatch_info = DispatchInfo { - weight: Weight::from_ref_time(0), + weight: Weight::from_parts(0, 0), class: DispatchClass::Operational, pays_fee: Pays::Yes, }; @@ -481,7 +481,7 @@ fn compute_fee_works_with_negative_multiplier() { // Everything works together. let dispatch_info = DispatchInfo { - weight: Weight::from_ref_time(123), + weight: Weight::from_parts(123, 0), class: DispatchClass::Operational, pays_fee: Pays::Yes, }; @@ -496,7 +496,7 @@ fn compute_fee_works_with_negative_multiplier() { #[test] fn compute_fee_does_not_overflow() { ExtBuilder::default() - .base_weight(Weight::from_ref_time(100)) + .base_weight(Weight::from_parts(100, 0)) .byte_fee(10) .balance_factor(0) .build() @@ -518,14 +518,14 @@ fn compute_fee_does_not_overflow() { fn refund_does_not_recreate_account() { ExtBuilder::default() .balance_factor(10) - .base_weight(Weight::from_ref_time(5)) + .base_weight(Weight::from_parts(5, 0)) .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(Weight::from_ref_time(100)), len) + .pre_dispatch(&2, CALL, &info_from_weight(Weight::from_parts(100, 0)), len) .unwrap(); assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 100 - 5); @@ -535,8 +535,8 @@ fn refund_does_not_recreate_account() { assert_ok!(ChargeTransactionPayment::::post_dispatch( Some(pre), - &info_from_weight(Weight::from_ref_time(100)), - &post_info_from_weight(Weight::from_ref_time(50)), + &info_from_weight(Weight::from_parts(100, 0)), + &post_info_from_weight(Weight::from_parts(50, 0)), len, &Ok(()) )); @@ -558,19 +558,19 @@ fn refund_does_not_recreate_account() { fn actual_weight_higher_than_max_refunds_nothing() { ExtBuilder::default() .balance_factor(10) - .base_weight(Weight::from_ref_time(5)) + .base_weight(Weight::from_parts(5, 0)) .build() .execute_with(|| { let len = 10; let pre = ChargeTransactionPayment::::from(5 /* tipped */) - .pre_dispatch(&2, CALL, &info_from_weight(Weight::from_ref_time(100)), len) + .pre_dispatch(&2, CALL, &info_from_weight(Weight::from_parts(100, 0)), len) .unwrap(); assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 100 - 5); assert_ok!(ChargeTransactionPayment::::post_dispatch( Some(pre), - &info_from_weight(Weight::from_ref_time(100)), - &post_info_from_weight(Weight::from_ref_time(101)), + &info_from_weight(Weight::from_parts(100, 0)), + &post_info_from_weight(Weight::from_parts(101, 0)), len, &Ok(()) )); @@ -582,14 +582,14 @@ fn actual_weight_higher_than_max_refunds_nothing() { fn zero_transfer_on_free_transaction() { ExtBuilder::default() .balance_factor(10) - .base_weight(Weight::from_ref_time(5)) + .base_weight(Weight::from_parts(5, 0)) .build() .execute_with(|| { // So events are emitted System::set_block_number(10); let len = 10; let dispatch_info = DispatchInfo { - weight: Weight::from_ref_time(100), + weight: Weight::from_parts(100, 0), pays_fee: Pays::No, class: DispatchClass::Normal, }; @@ -621,11 +621,11 @@ fn zero_transfer_on_free_transaction() { fn refund_consistent_with_actual_weight() { ExtBuilder::default() .balance_factor(10) - .base_weight(Weight::from_ref_time(7)) + .base_weight(Weight::from_parts(7, 0)) .build() .execute_with(|| { - let info = info_from_weight(Weight::from_ref_time(100)); - let post_info = post_info_from_weight(Weight::from_ref_time(33)); + let info = info_from_weight(Weight::from_parts(100, 0)); + let post_info = post_info_from_weight(Weight::from_parts(33, 0)); let prev_balance = Balances::free_balance(2); let len = 10; let tip = 5; @@ -662,7 +662,7 @@ fn should_alter_operational_priority() { ExtBuilder::default().balance_factor(100).build().execute_with(|| { let normal = DispatchInfo { - weight: Weight::from_ref_time(100), + weight: Weight::from_parts(100, 0), class: DispatchClass::Normal, pays_fee: Pays::Yes, }; @@ -683,7 +683,7 @@ fn should_alter_operational_priority() { ExtBuilder::default().balance_factor(100).build().execute_with(|| { let op = DispatchInfo { - weight: Weight::from_ref_time(100), + weight: Weight::from_parts(100, 0), class: DispatchClass::Operational, pays_fee: Pays::Yes, }; @@ -708,7 +708,7 @@ fn no_tip_has_some_priority() { ExtBuilder::default().balance_factor(100).build().execute_with(|| { let normal = DispatchInfo { - weight: Weight::from_ref_time(100), + weight: Weight::from_parts(100, 0), class: DispatchClass::Normal, pays_fee: Pays::Yes, }; @@ -722,7 +722,7 @@ fn no_tip_has_some_priority() { ExtBuilder::default().balance_factor(100).build().execute_with(|| { let op = DispatchInfo { - weight: Weight::from_ref_time(100), + weight: Weight::from_parts(100, 0), class: DispatchClass::Operational, pays_fee: Pays::Yes, }; @@ -742,7 +742,7 @@ fn higher_tip_have_higher_priority() { let len = 10; ExtBuilder::default().balance_factor(100).build().execute_with(|| { let normal = DispatchInfo { - weight: Weight::from_ref_time(100), + weight: Weight::from_parts(100, 0), class: DispatchClass::Normal, pays_fee: Pays::Yes, }; @@ -754,7 +754,7 @@ fn higher_tip_have_higher_priority() { ExtBuilder::default().balance_factor(100).build().execute_with(|| { let op = DispatchInfo { - weight: Weight::from_ref_time(100), + weight: Weight::from_parts(100, 0), class: DispatchClass::Operational, pays_fee: Pays::Yes, }; @@ -781,10 +781,10 @@ fn higher_tip_have_higher_priority() { fn post_info_can_change_pays_fee() { ExtBuilder::default() .balance_factor(10) - .base_weight(Weight::from_ref_time(7)) + .base_weight(Weight::from_parts(7, 0)) .build() .execute_with(|| { - let info = info_from_weight(Weight::from_ref_time(100)); + let info = info_from_weight(Weight::from_parts(100, 0)); 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 b8bc17918ab36..cbe85309b856a 100644 --- a/frame/transaction-payment/src/types.rs +++ b/frame/transaction-payment/src/types.rs @@ -144,7 +144,7 @@ mod tests { #[test] fn should_serialize_and_deserialize_properly_with_string() { let info = RuntimeDispatchInfo { - weight: Weight::from_ref_time(5), + weight: Weight::from_parts(5, 0), class: DispatchClass::Normal, partial_fee: 1_000_000_u64, }; @@ -162,7 +162,7 @@ mod tests { #[test] fn should_serialize_and_deserialize_properly_large_value() { let info = RuntimeDispatchInfo { - weight: Weight::from_ref_time(5), + weight: Weight::from_parts(5, 0), class: DispatchClass::Normal, partial_fee: u128::max_value(), }; diff --git a/frame/transaction-storage/src/weights.rs b/frame/transaction-storage/src/weights.rs index d9659a925ab24..896e1ebab43aa 100644 --- a/frame/transaction-storage/src/weights.rs +++ b/frame/transaction-storage/src/weights.rs @@ -70,7 +70,7 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 28_702 nanoseconds. Weight::from_parts(29_164_000, 38383) // Standard Error: 2 - .saturating_add(Weight::from_ref_time(5_601).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(5_601, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -128,7 +128,7 @@ impl WeightInfo for () { // Minimum execution time: 28_702 nanoseconds. Weight::from_parts(29_164_000, 38383) // Standard Error: 2 - .saturating_add(Weight::from_ref_time(5_601).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(5_601, 0).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/frame/treasury/src/weights.rs b/frame/treasury/src/weights.rs index 10bab00836836..abf461c622a0f 100644 --- a/frame/treasury/src/weights.rs +++ b/frame/treasury/src/weights.rs @@ -112,7 +112,7 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 9_366 nanoseconds. Weight::from_parts(11_731_455, 3480) // Standard Error: 761 - .saturating_add(Weight::from_ref_time(21_665).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(21_665, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -145,12 +145,12 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 37_834 nanoseconds. Weight::from_parts(47_496_917, 2305) // Standard Error: 12_505 - .saturating_add(Weight::from_ref_time(26_902_474).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(26_902_474, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(p.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(p.into()))) - .saturating_add(Weight::from_proof_size(7789).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 7789).saturating_mul(p.into())) } } @@ -209,7 +209,7 @@ impl WeightInfo for () { // Minimum execution time: 9_366 nanoseconds. Weight::from_parts(11_731_455, 3480) // Standard Error: 761 - .saturating_add(Weight::from_ref_time(21_665).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(21_665, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -242,11 +242,11 @@ impl WeightInfo for () { // Minimum execution time: 37_834 nanoseconds. Weight::from_parts(47_496_917, 2305) // Standard Error: 12_505 - .saturating_add(Weight::from_ref_time(26_902_474).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(26_902_474, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(p.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(p.into()))) - .saturating_add(Weight::from_proof_size(7789).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 7789).saturating_mul(p.into())) } } diff --git a/frame/uniques/src/weights.rs b/frame/uniques/src/weights.rs index 144a384f0a6d7..edf3bd35dcef0 100644 --- a/frame/uniques/src/weights.rs +++ b/frame/uniques/src/weights.rs @@ -131,18 +131,18 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 2_404_081 nanoseconds. Weight::from_parts(2_419_004_000, 5250) // Standard Error: 27_175 - .saturating_add(Weight::from_ref_time(8_616_904).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(8_616_904, 0).saturating_mul(n.into())) // Standard Error: 27_175 - .saturating_add(Weight::from_ref_time(334_249).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(334_249, 0).saturating_mul(m.into())) // Standard Error: 27_175 - .saturating_add(Weight::from_ref_time(213_038).saturating_mul(a.into())) + .saturating_add(Weight::from_parts(213_038, 0).saturating_mul(a.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(m.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(a.into()))) - .saturating_add(Weight::from_proof_size(2597).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 2597).saturating_mul(n.into())) } /// Storage: Uniques Asset (r:1 w:1) /// Proof: Uniques Asset (max_values: None, max_size: Some(122), added: 2597, mode: MaxEncodedLen) @@ -207,12 +207,12 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 13_633 nanoseconds. Weight::from_parts(13_797_000, 2653) // Standard Error: 9_293 - .saturating_add(Weight::from_ref_time(11_163_914).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(11_163_914, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(i.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) - .saturating_add(Weight::from_proof_size(2597).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(0, 2597).saturating_mul(i.into())) } /// Storage: Uniques Asset (r:1 w:1) /// Proof: Uniques Asset (max_values: None, max_size: Some(122), added: 2597, mode: MaxEncodedLen) @@ -519,18 +519,18 @@ impl WeightInfo for () { // Minimum execution time: 2_404_081 nanoseconds. Weight::from_parts(2_419_004_000, 5250) // Standard Error: 27_175 - .saturating_add(Weight::from_ref_time(8_616_904).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(8_616_904, 0).saturating_mul(n.into())) // Standard Error: 27_175 - .saturating_add(Weight::from_ref_time(334_249).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(334_249, 0).saturating_mul(m.into())) // Standard Error: 27_175 - .saturating_add(Weight::from_ref_time(213_038).saturating_mul(a.into())) + .saturating_add(Weight::from_parts(213_038, 0).saturating_mul(a.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(RocksDbWeight::get().writes((2_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(m.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(a.into()))) - .saturating_add(Weight::from_proof_size(2597).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 2597).saturating_mul(n.into())) } /// Storage: Uniques Asset (r:1 w:1) /// Proof: Uniques Asset (max_values: None, max_size: Some(122), added: 2597, mode: MaxEncodedLen) @@ -595,12 +595,12 @@ impl WeightInfo for () { // Minimum execution time: 13_633 nanoseconds. Weight::from_parts(13_797_000, 2653) // Standard Error: 9_293 - .saturating_add(Weight::from_ref_time(11_163_914).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(11_163_914, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(i.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(i.into()))) - .saturating_add(Weight::from_proof_size(2597).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(0, 2597).saturating_mul(i.into())) } /// Storage: Uniques Asset (r:1 w:1) /// Proof: Uniques Asset (max_values: None, max_size: Some(122), added: 2597, mode: MaxEncodedLen) diff --git a/frame/utility/src/tests.rs b/frame/utility/src/tests.rs index 938a5392b963d..413315a25eb44 100644 --- a/frame/utility/src/tests.rs +++ b/frame/utility/src/tests.rs @@ -308,8 +308,8 @@ fn as_derivative_works() { #[test] fn as_derivative_handles_weight_refund() { new_test_ext().execute_with(|| { - let start_weight = Weight::from_ref_time(100); - let end_weight = Weight::from_ref_time(75); + let start_weight = Weight::from_parts(100, 0); + let end_weight = Weight::from_parts(75, 0); let diff = start_weight - end_weight; // Full weight when ok @@ -495,8 +495,8 @@ fn batch_weight_calculation_doesnt_overflow() { #[test] fn batch_handles_weight_refund() { new_test_ext().execute_with(|| { - let start_weight = Weight::from_ref_time(100); - let end_weight = Weight::from_ref_time(75); + let start_weight = Weight::from_parts(100, 0); + let end_weight = Weight::from_parts(75, 0); let diff = start_weight - end_weight; let batch_len = 4; @@ -611,8 +611,8 @@ fn batch_all_revert() { #[test] fn batch_all_handles_weight_refund() { new_test_ext().execute_with(|| { - let start_weight = Weight::from_ref_time(100); - let end_weight = Weight::from_ref_time(75); + let start_weight = Weight::from_parts(100, 0); + let end_weight = Weight::from_parts(75, 0); let diff = start_weight - end_weight; let batch_len = 4; @@ -739,7 +739,7 @@ fn force_batch_works() { RuntimeOrigin::signed(1), vec![ call_transfer(2, 5), - call_foobar(true, Weight::from_ref_time(75), None), + call_foobar(true, Weight::from_parts(75, 0), None), call_transfer(2, 10), call_transfer(2, 5), ] diff --git a/frame/utility/src/weights.rs b/frame/utility/src/weights.rs index 8c7a14715989e..c680c9ff00f9f 100644 --- a/frame/utility/src/weights.rs +++ b/frame/utility/src/weights.rs @@ -64,16 +64,16 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 6_742 nanoseconds. - Weight::from_ref_time(16_087_635) + Weight::from_parts(16_087_635, 0) // Standard Error: 2_411 - .saturating_add(Weight::from_ref_time(3_665_506).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(3_665_506, 0).saturating_mul(c.into())) } fn as_derivative() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` // Minimum execution time: 4_802 nanoseconds. - Weight::from_ref_time(5_269_000) + Weight::from_parts(5_269_000, 0) } /// The range of component `c` is `[0, 1000]`. fn batch_all(c: u32, ) -> Weight { @@ -81,16 +81,16 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 7_100 nanoseconds. - Weight::from_ref_time(14_090_381) + Weight::from_parts(14_090_381, 0) // Standard Error: 1_917 - .saturating_add(Weight::from_ref_time(3_744_891).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(3_744_891, 0).saturating_mul(c.into())) } fn dispatch_as() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` // Minimum execution time: 8_840 nanoseconds. - Weight::from_ref_time(9_280_000) + Weight::from_parts(9_280_000, 0) } /// The range of component `c` is `[0, 1000]`. fn force_batch(c: u32, ) -> Weight { @@ -98,9 +98,9 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 7_245 nanoseconds. - Weight::from_ref_time(14_292_923) + Weight::from_parts(14_292_923, 0) // Standard Error: 1_803 - .saturating_add(Weight::from_ref_time(3_645_950).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(3_645_950, 0).saturating_mul(c.into())) } } @@ -112,16 +112,16 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 6_742 nanoseconds. - Weight::from_ref_time(16_087_635) + Weight::from_parts(16_087_635, 0) // Standard Error: 2_411 - .saturating_add(Weight::from_ref_time(3_665_506).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(3_665_506, 0).saturating_mul(c.into())) } fn as_derivative() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` // Minimum execution time: 4_802 nanoseconds. - Weight::from_ref_time(5_269_000) + Weight::from_parts(5_269_000, 0) } /// The range of component `c` is `[0, 1000]`. fn batch_all(c: u32, ) -> Weight { @@ -129,16 +129,16 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 7_100 nanoseconds. - Weight::from_ref_time(14_090_381) + Weight::from_parts(14_090_381, 0) // Standard Error: 1_917 - .saturating_add(Weight::from_ref_time(3_744_891).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(3_744_891, 0).saturating_mul(c.into())) } fn dispatch_as() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` // Minimum execution time: 8_840 nanoseconds. - Weight::from_ref_time(9_280_000) + Weight::from_parts(9_280_000, 0) } /// The range of component `c` is `[0, 1000]`. fn force_batch(c: u32, ) -> Weight { @@ -146,8 +146,8 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 7_245 nanoseconds. - Weight::from_ref_time(14_292_923) + Weight::from_parts(14_292_923, 0) // Standard Error: 1_803 - .saturating_add(Weight::from_ref_time(3_645_950).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(3_645_950, 0).saturating_mul(c.into())) } } diff --git a/frame/vesting/src/weights.rs b/frame/vesting/src/weights.rs index 350e6a86e24e4..de3260fa1e6a6 100644 --- a/frame/vesting/src/weights.rs +++ b/frame/vesting/src/weights.rs @@ -74,9 +74,9 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 28_062 nanoseconds. Weight::from_parts(26_857_563, 7306) // Standard Error: 623 - .saturating_add(Weight::from_ref_time(55_988).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(55_988, 0).saturating_mul(l.into())) // Standard Error: 1_109 - .saturating_add(Weight::from_ref_time(59_714).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(59_714, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -93,9 +93,9 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 27_027 nanoseconds. Weight::from_parts(26_509_364, 7306) // Standard Error: 815 - .saturating_add(Weight::from_ref_time(54_711).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(54_711, 0).saturating_mul(l.into())) // Standard Error: 1_451 - .saturating_add(Weight::from_ref_time(32_792).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(32_792, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -114,9 +114,9 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 29_554 nanoseconds. Weight::from_parts(28_269_203, 9909) // Standard Error: 623 - .saturating_add(Weight::from_ref_time(59_058).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(59_058, 0).saturating_mul(l.into())) // Standard Error: 1_108 - .saturating_add(Weight::from_ref_time(63_429).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(63_429, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -135,9 +135,9 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 28_546 nanoseconds. Weight::from_parts(28_299_251, 9909) // Standard Error: 786 - .saturating_add(Weight::from_ref_time(53_401).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(53_401, 0).saturating_mul(l.into())) // Standard Error: 1_399 - .saturating_add(Weight::from_ref_time(29_713).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(29_713, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -156,9 +156,9 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 43_436 nanoseconds. Weight::from_parts(44_885_707, 9909) // Standard Error: 1_516 - .saturating_add(Weight::from_ref_time(59_066).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(59_066, 0).saturating_mul(l.into())) // Standard Error: 2_698 - .saturating_add(Weight::from_ref_time(32_053).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(32_053, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -177,9 +177,9 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 45_805 nanoseconds. Weight::from_parts(46_869_490, 12512) // Standard Error: 1_445 - .saturating_add(Weight::from_ref_time(52_654).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(52_654, 0).saturating_mul(l.into())) // Standard Error: 2_571 - .saturating_add(Weight::from_ref_time(34_202).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(34_202, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -198,9 +198,9 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 30_460 nanoseconds. Weight::from_parts(29_407_637, 9909) // Standard Error: 794 - .saturating_add(Weight::from_ref_time(63_757).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(63_757, 0).saturating_mul(l.into())) // Standard Error: 1_466 - .saturating_add(Weight::from_ref_time(56_032).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(56_032, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -219,9 +219,9 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 30_413 nanoseconds. Weight::from_parts(29_350_467, 9909) // Standard Error: 724 - .saturating_add(Weight::from_ref_time(65_366).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(65_366, 0).saturating_mul(l.into())) // Standard Error: 1_337 - .saturating_add(Weight::from_ref_time(53_799).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(53_799, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -242,9 +242,9 @@ impl WeightInfo for () { // Minimum execution time: 28_062 nanoseconds. Weight::from_parts(26_857_563, 7306) // Standard Error: 623 - .saturating_add(Weight::from_ref_time(55_988).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(55_988, 0).saturating_mul(l.into())) // Standard Error: 1_109 - .saturating_add(Weight::from_ref_time(59_714).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(59_714, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -261,9 +261,9 @@ impl WeightInfo for () { // Minimum execution time: 27_027 nanoseconds. Weight::from_parts(26_509_364, 7306) // Standard Error: 815 - .saturating_add(Weight::from_ref_time(54_711).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(54_711, 0).saturating_mul(l.into())) // Standard Error: 1_451 - .saturating_add(Weight::from_ref_time(32_792).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(32_792, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -282,9 +282,9 @@ impl WeightInfo for () { // Minimum execution time: 29_554 nanoseconds. Weight::from_parts(28_269_203, 9909) // Standard Error: 623 - .saturating_add(Weight::from_ref_time(59_058).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(59_058, 0).saturating_mul(l.into())) // Standard Error: 1_108 - .saturating_add(Weight::from_ref_time(63_429).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(63_429, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -303,9 +303,9 @@ impl WeightInfo for () { // Minimum execution time: 28_546 nanoseconds. Weight::from_parts(28_299_251, 9909) // Standard Error: 786 - .saturating_add(Weight::from_ref_time(53_401).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(53_401, 0).saturating_mul(l.into())) // Standard Error: 1_399 - .saturating_add(Weight::from_ref_time(29_713).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(29_713, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -324,9 +324,9 @@ impl WeightInfo for () { // Minimum execution time: 43_436 nanoseconds. Weight::from_parts(44_885_707, 9909) // Standard Error: 1_516 - .saturating_add(Weight::from_ref_time(59_066).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(59_066, 0).saturating_mul(l.into())) // Standard Error: 2_698 - .saturating_add(Weight::from_ref_time(32_053).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(32_053, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -345,9 +345,9 @@ impl WeightInfo for () { // Minimum execution time: 45_805 nanoseconds. Weight::from_parts(46_869_490, 12512) // Standard Error: 1_445 - .saturating_add(Weight::from_ref_time(52_654).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(52_654, 0).saturating_mul(l.into())) // Standard Error: 2_571 - .saturating_add(Weight::from_ref_time(34_202).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(34_202, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -366,9 +366,9 @@ impl WeightInfo for () { // Minimum execution time: 30_460 nanoseconds. Weight::from_parts(29_407_637, 9909) // Standard Error: 794 - .saturating_add(Weight::from_ref_time(63_757).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(63_757, 0).saturating_mul(l.into())) // Standard Error: 1_466 - .saturating_add(Weight::from_ref_time(56_032).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(56_032, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -387,9 +387,9 @@ impl WeightInfo for () { // Minimum execution time: 30_413 nanoseconds. Weight::from_parts(29_350_467, 9909) // Standard Error: 724 - .saturating_add(Weight::from_ref_time(65_366).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(65_366, 0).saturating_mul(l.into())) // Standard Error: 1_337 - .saturating_add(Weight::from_ref_time(53_799).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(53_799, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } diff --git a/frame/whitelist/src/tests.rs b/frame/whitelist/src/tests.rs index 986a09b8e03de..3a60adbcfbedc 100644 --- a/frame/whitelist/src/tests.rs +++ b/frame/whitelist/src/tests.rs @@ -119,7 +119,7 @@ fn test_whitelist_call_and_execute() { RuntimeOrigin::root(), call_hash, call_encoded_len, - call_weight - Weight::from_ref_time(1) + call_weight - Weight::from_parts(1, 0) ), crate::Error::::InvalidCallWeightWitness, ); diff --git a/frame/whitelist/src/weights.rs b/frame/whitelist/src/weights.rs index 2b25e81941540..667d602a3c0ba 100644 --- a/frame/whitelist/src/weights.rs +++ b/frame/whitelist/src/weights.rs @@ -97,10 +97,10 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 27_539 nanoseconds. Weight::from_parts(27_950_000, 8007) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_134).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(1_134, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(1).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } /// Storage: Whitelist WhitelistedCall (r:1 w:1) /// Proof: Whitelist WhitelistedCall (max_values: None, max_size: Some(40), added: 2515, mode: MaxEncodedLen) @@ -114,7 +114,7 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 20_581 nanoseconds. Weight::from_parts(21_762_318, 5081) // Standard Error: 4 - .saturating_add(Weight::from_ref_time(1_480).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(1_480, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -162,10 +162,10 @@ impl WeightInfo for () { // Minimum execution time: 27_539 nanoseconds. Weight::from_parts(27_950_000, 8007) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_134).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(1_134, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_proof_size(1).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } /// Storage: Whitelist WhitelistedCall (r:1 w:1) /// Proof: Whitelist WhitelistedCall (max_values: None, max_size: Some(40), added: 2515, mode: MaxEncodedLen) @@ -179,7 +179,7 @@ impl WeightInfo for () { // Minimum execution time: 20_581 nanoseconds. Weight::from_parts(21_762_318, 5081) // Standard Error: 4 - .saturating_add(Weight::from_ref_time(1_480).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(1_480, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } diff --git a/primitives/weights/src/lib.rs b/primitives/weights/src/lib.rs index acfcae1dfcd15..8a842307355bf 100644 --- a/primitives/weights/src/lib.rs +++ b/primitives/weights/src/lib.rs @@ -82,17 +82,17 @@ pub struct RuntimeDbWeight { impl RuntimeDbWeight { pub fn reads(self, r: u64) -> Weight { - Weight::from_ref_time(self.read.saturating_mul(r)) + Weight::from_parts(self.read.saturating_mul(r), 0) } pub fn writes(self, w: u64) -> Weight { - Weight::from_ref_time(self.write.saturating_mul(w)) + Weight::from_parts(self.write.saturating_mul(w), 0) } 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)) + Weight::from_parts(read_weight.saturating_add(write_weight), 0) } } @@ -264,15 +264,15 @@ mod tests { #[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); + assert_eq!(Poly::weight_to_fee(&Weight::from_parts(100, 0)), 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); + assert_eq!(Poly::weight_to_fee(&Weight::from_parts(10_123, 0)), 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); + assert_eq!(Poly::weight_to_fee(&Weight::from_parts(10, 0)), 0); } #[test] @@ -283,7 +283,7 @@ mod tests { #[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::from_parts(50, 0)), 50); assert_eq!(IdentityFee::::weight_to_fee(&Weight::MAX), Balance::max_value()); } @@ -295,20 +295,20 @@ mod tests { 0 ); assert_eq!( - ConstantMultiplier::>::weight_to_fee(&Weight::from_ref_time( - 50 + ConstantMultiplier::>::weight_to_fee(&Weight::from_parts( + 50, 0 )), 500 ); assert_eq!( - ConstantMultiplier::>::weight_to_fee(&Weight::from_ref_time( - 16 + ConstantMultiplier::>::weight_to_fee(&Weight::from_parts( + 16, 0 )), 16384 ); assert_eq!( ConstantMultiplier::>::weight_to_fee( - &Weight::from_ref_time(2) + &Weight::from_parts(2, 0) ), u128::MAX ); diff --git a/primitives/weights/src/weight_v2.rs b/primitives/weights/src/weight_v2.rs index f6e6164b5fe4b..ca137145920bb 100644 --- a/primitives/weights/src/weight_v2.rs +++ b/primitives/weights/src/weight_v2.rs @@ -37,7 +37,7 @@ pub struct Weight { impl From for Weight { fn from(old: OldWeight) -> Self { - Weight::from_ref_time(old.0) + Weight::from_parts(old.0, 0) } } @@ -103,11 +103,13 @@ impl Weight { } /// Construct [`Weight`] with reference time weight and 0 storage size weight. + #[deprecated = "Will be removed soon; use `from_parts` instead."] pub const fn from_ref_time(ref_time: u64) -> Self { Self { ref_time, proof_size: 0 } } /// Construct [`Weight`] with storage size weight and 0 reference time weight. + #[deprecated = "Will be removed soon; use `from_parts` instead."] pub const fn from_proof_size(proof_size: u64) -> Self { Self { ref_time: 0, proof_size } } @@ -238,7 +240,7 @@ impl Weight { /// of all those divisions. Returns `None` in case **all** components of `other` are zero. /// /// This returns `Some` even if some components of `other` are zero as long as there is at least - /// one non-zero component in `other`. The devision for this particular component will then + /// one non-zero component in `other`. The division for this particular component will then /// yield the maximum value (e.g u64::MAX). This is because we assume not every operation and /// hence each `Weight` will necessarily use each resource. pub const fn checked_div_per_component(self, other: &Self) -> Option { diff --git a/test-utils/runtime/src/lib.rs b/test-utils/runtime/src/lib.rs index 87a60acfc87ce..1ea8b866367dd 100644 --- a/test-utils/runtime/src/lib.rs +++ b/test-utils/runtime/src/lib.rs @@ -601,7 +601,7 @@ parameter_types! { pub RuntimeBlockLength: BlockLength = BlockLength::max(4 * 1024 * 1024); pub RuntimeBlockWeights: BlockWeights = - BlockWeights::with_sensible_defaults(Weight::from_ref_time(4 * 1024 * 1024), Perbill::from_percent(75)); + BlockWeights::with_sensible_defaults(Weight::from_parts(4 * 1024 * 1024, 0), Perbill::from_percent(75)); } impl From> for Extrinsic { diff --git a/utils/frame/benchmarking-cli/src/overhead/README.md b/utils/frame/benchmarking-cli/src/overhead/README.md index 1584c2affe0a3..85bcc7fa36f2d 100644 --- a/utils/frame/benchmarking-cli/src/overhead/README.md +++ b/utils/frame/benchmarking-cli/src/overhead/README.md @@ -31,7 +31,7 @@ The file will contain the concrete weight value and various statistics about the /// 95th: 3_595_674 /// 75th: 3_526_435 pub const BlockExecutionWeight: Weight = - Weight::from_ref_time(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(3_532_484)); + Weight::from_parts(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(3_532_484), 0); ``` In this example it takes 3.5 ms to execute an empty block. That means that it always takes at least 3.5 ms to execute *any* block. @@ -61,7 +61,7 @@ The relevant section in the output file looks like this: /// 95th: 67_843 /// 75th: 67_749 pub const ExtrinsicBaseWeight: Weight = - Weight::from_ref_time(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(67_745)); + Weight::from_parts(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(67_745), 0); ``` In this example it takes 67.7 µs to execute a NO-OP extrinsic. That means that it always takes at least 67.7 µs to execute *any* extrinsic. diff --git a/utils/frame/benchmarking-cli/src/overhead/weights.hbs b/utils/frame/benchmarking-cli/src/overhead/weights.hbs index c54393d200bd3..6e364facc12f4 100644 --- a/utils/frame/benchmarking-cli/src/overhead/weights.hbs +++ b/utils/frame/benchmarking-cli/src/overhead/weights.hbs @@ -35,7 +35,7 @@ parameter_types! { /// 95th: {{underscore stats.p95}} /// 75th: {{underscore stats.p75}} pub const {{long_name}}Weight: Weight = - Weight::from_ref_time(WEIGHT_REF_TIME_PER_NANOS.saturating_mul({{underscore weight}})); + Weight::from_parts(WEIGHT_REF_TIME_PER_NANOS.saturating_mul({{underscore weight}}), 0); } #[cfg(test)] diff --git a/utils/frame/benchmarking-cli/src/pallet/template.hbs b/utils/frame/benchmarking-cli/src/pallet/template.hbs index 0bec34eaae774..88d6b69a6c339 100644 --- a/utils/frame/benchmarking-cli/src/pallet/template.hbs +++ b/utils/frame/benchmarking-cli/src/pallet/template.hbs @@ -37,12 +37,12 @@ impl {{pallet}}::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `{{benchmark.base_recorded_proof_size}}{{#each benchmark.component_recorded_proof_size as |cp|}} + {{cp.name}} * ({{cp.slope}} ±{{underscore cp.error}}){{/each}}` // Estimated: `{{benchmark.base_calculated_proof_size}}{{#each benchmark.component_calculated_proof_size as |cp|}} + {{cp.name}} * ({{cp.slope}} ±{{underscore cp.error}}){{/each}}` - // Minimum execution time: {{underscore benchmark.min_execution_time}} nanoseconds. - Weight::from_ref_time({{underscore benchmark.base_weight}}) - .saturating_add(Weight::from_proof_size({{benchmark.base_calculated_proof_size}})) + // Minimum execution time: {{underscore benchmark.min_execution_time}}_000 picoseconds. + Weight::from_parts({{underscore benchmark.base_weight}}, 0) + .saturating_add(Weight::from_parts(0, {{benchmark.base_calculated_proof_size}})) {{#each benchmark.component_weight as |cw|}} // Standard Error: {{underscore cw.error}} - .saturating_add(Weight::from_ref_time({{underscore cw.slope}}).saturating_mul({{cw.name}}.into())) + .saturating_add(Weight::from_parts({{underscore cw.slope}}, 0).saturating_mul({{cw.name}}.into())) {{/each}} {{#if (ne benchmark.base_reads "0")}} .saturating_add(T::DbWeight::get().reads({{benchmark.base_reads}})) @@ -57,7 +57,7 @@ impl {{pallet}}::WeightInfo for WeightInfo { .saturating_add(T::DbWeight::get().writes(({{cw.slope}}_u64).saturating_mul({{cw.name}}.into()))) {{/each}} {{#each benchmark.component_calculated_proof_size as |cp|}} - .saturating_add(Weight::from_proof_size({{cp.slope}}).saturating_mul({{cp.name}}.into())) + .saturating_add(Weight::from_parts(0, {{cp.slope}}).saturating_mul({{cp.name}}.into())) {{/each}} } {{/each}} From 6f923eedcac0fba4fd6b73e8792520f69722e527 Mon Sep 17 00:00:00 2001 From: Robert Hambrock Date: Fri, 3 Mar 2023 11:23:15 +0100 Subject: [PATCH 461/715] bump API versions of {Beefy,Mmr}Api (#13509) --- primitives/consensus/beefy/src/lib.rs | 1 + primitives/merkle-mountain-range/src/lib.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/primitives/consensus/beefy/src/lib.rs b/primitives/consensus/beefy/src/lib.rs index 2e3ec2ef801c5..cc5d1e8cb9a3b 100644 --- a/primitives/consensus/beefy/src/lib.rs +++ b/primitives/consensus/beefy/src/lib.rs @@ -302,6 +302,7 @@ impl OpaqueKeyOwnershipProof { sp_api::decl_runtime_apis! { /// API necessary for BEEFY voters. + #[api_version(2)] pub trait BeefyApi { /// Return the block number where BEEFY consensus is enabled/started diff --git a/primitives/merkle-mountain-range/src/lib.rs b/primitives/merkle-mountain-range/src/lib.rs index 1c319c4e3934c..436755c032908 100644 --- a/primitives/merkle-mountain-range/src/lib.rs +++ b/primitives/merkle-mountain-range/src/lib.rs @@ -422,6 +422,7 @@ impl Error { sp_api::decl_runtime_apis! { /// API to interact with MMR pallet. + #[api_version(2)] pub trait MmrApi { /// Return the on-chain MMR root hash. fn mmr_root() -> Result; From e8f5bc176ca33bc5a2fd375e64c67b91ce16bbc9 Mon Sep 17 00:00:00 2001 From: Jegor Sidorenko <5252494+jsidorenko@users.noreply.github.com> Date: Fri, 3 Mar 2023 14:17:55 +0200 Subject: [PATCH 462/715] [NFTs] Emit new PalletAttributeSet event (#13525) * Emit new PalletAttributeSet event * Chore --- frame/nfts/src/lib.rs | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/frame/nfts/src/lib.rs b/frame/nfts/src/lib.rs index 2c3ab290cf569..681d908423da6 100644 --- a/frame/nfts/src/lib.rs +++ b/frame/nfts/src/lib.rs @@ -532,6 +532,14 @@ pub mod pallet { item: T::ItemId, namespace: AttributeNamespace, }, + /// A new attribute in the `Pallet` namespace was set for the `collection` or an `item` + /// within that `collection`. + PalletAttributeSet { + collection: T::CollectionId, + item: Option, + attribute: PalletAttributes, + value: BoundedVec, + }, } #[pallet::error] @@ -804,32 +812,39 @@ pub mod pallet { let MintWitness { owner_of_item } = witness_data.ok_or(Error::::BadWitness)?; - let has_item = Account::::contains_key(( + let owns_item = Account::::contains_key(( &caller, &collection_id, &owner_of_item, )); - ensure!(has_item, Error::::BadWitness); + ensure!(owns_item, Error::::BadWitness); - let attribute_key = Self::construct_attribute_key( - PalletAttributes::::UsedToClaim(collection) - .encode(), - )?; + let pallet_attribute = + PalletAttributes::::UsedToClaim(collection); let key = ( &collection_id, Some(owner_of_item), AttributeNamespace::Pallet, - &attribute_key, + &Self::construct_attribute_key(pallet_attribute.encode())?, ); let already_claimed = Attribute::::contains_key(key.clone()); ensure!(!already_claimed, Error::::AlreadyClaimed); - let value = Self::construct_attribute_value(vec![0])?; + let attribute_value = Self::construct_attribute_value(vec![])?; Attribute::::insert( key, - (value, AttributeDeposit { account: None, amount: Zero::zero() }), + ( + attribute_value.clone(), + AttributeDeposit { account: None, amount: Zero::zero() }, + ), ); + Self::deposit_event(Event::PalletAttributeSet { + collection, + item: Some(item), + attribute: pallet_attribute, + value: attribute_value, + }); }, _ => {}, } From 96a6cd36d526439cea9bddebcd3286d0070fb7d7 Mon Sep 17 00:00:00 2001 From: abebeos <110243666+abebeos@users.noreply.github.com> Date: Fri, 3 Mar 2023 16:53:22 +0200 Subject: [PATCH 463/715] fix feature/enhancement issue template (#13522) --- .github/ISSUE_TEMPLATE/feature.yaml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/feature.yaml b/.github/ISSUE_TEMPLATE/feature.yaml index 92b2fea3e88da..6a59522ab4b48 100644 --- a/.github/ISSUE_TEMPLATE/feature.yaml +++ b/.github/ISSUE_TEMPLATE/feature.yaml @@ -1,7 +1,9 @@ name: Feature Request description: Submit your requests and suggestions to improve! +labels: ["J0-enhancement"] body: - type: checkboxes + id: existing 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. @@ -9,6 +11,7 @@ body: - label: I have searched the existing issues required: true - type: checkboxes + id: stackexchange 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. @@ -16,7 +19,7 @@ body: - label: This is not a support question. required: true - type: textarea - id: content + id: motivation attributes: label: Motivation description: Please give precedence as to what lead you to file this issue. @@ -24,7 +27,7 @@ body: validations: required: false - type: textarea - id: content + id: request attributes: label: Request description: Please describe what is needed. @@ -32,7 +35,7 @@ body: validations: required: true - type: textarea - id: content + id: solution attributes: label: Solution description: If possible, please describe what a solution could be. From 2cb4825ea0d196d6e23e8e908bc4986413bd5b9f Mon Sep 17 00:00:00 2001 From: Arkadiy Paronyan Date: Fri, 3 Mar 2023 18:16:59 +0100 Subject: [PATCH 464/715] Bump parity-db (#13521) --- Cargo.lock | 21 ++++++++++++++------- bin/node/bench/Cargo.toml | 2 +- client/db/Cargo.toml | 2 +- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b7c7a813fede1..79e528b60b149 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3310,9 +3310,9 @@ checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" [[package]] name = "jobserver" -version = "0.1.25" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "068b1ee6743e4d11fb9c6a1e6064b3693a1b600e7f5f5988047d98b3dc9fb90b" +checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2" dependencies = [ "libc", ] @@ -4348,9 +4348,9 @@ dependencies = [ [[package]] name = "memmap2" -version = "0.5.8" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b182332558b18d807c4ce1ca8ca983b34c3ee32765e47b3f0f69b90355cc1dc" +checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" dependencies = [ "libc", ] @@ -6760,9 +6760,9 @@ dependencies = [ [[package]] name = "parity-db" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd684a725651d9588ef21f140a328b6b4f64e646b2e931f3e6f14f75eedf9980" +checksum = "df89dd8311063c54ae4e03d9aeb597b04212a57e82c339344130a9cad9b3e2d9" dependencies = [ "blake2", "crc32fast", @@ -6774,6 +6774,7 @@ dependencies = [ "memmap2", "parking_lot 0.12.1", "rand 0.8.5", + "siphasher", "snap", ] @@ -9660,6 +9661,12 @@ dependencies = [ "wide", ] +[[package]] +name = "siphasher" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" + [[package]] name = "slab" version = "0.4.7" @@ -11629,7 +11636,7 @@ checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" dependencies = [ "cfg-if", "digest 0.10.6", - "rand 0.8.5", + "rand 0.7.3", "static_assertions", ] diff --git a/bin/node/bench/Cargo.toml b/bin/node/bench/Cargo.toml index 0097b51ab008e..dfff4db43a53b 100644 --- a/bin/node/bench/Cargo.toml +++ b/bin/node/bench/Cargo.toml @@ -38,7 +38,7 @@ tempfile = "3.1.0" fs_extra = "1" rand = { version = "0.8.5", features = ["small_rng"] } lazy_static = "1.4.0" -parity-db = "0.4.3" +parity-db = "0.4.4" 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 73eca1dff708a..ed26f373733e4 100644 --- a/client/db/Cargo.toml +++ b/client/db/Cargo.toml @@ -22,7 +22,7 @@ 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.3" +parity-db = "0.4.4" 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 48c9de8902d9d7e240fe6b3d29f8adcf522d605c Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Fri, 3 Mar 2023 19:05:01 +0000 Subject: [PATCH 465/715] Salary pallet (#13378) * More drafting * Paymaster pallet * Fix build * More tests * Rename * Rename * Renaming * Revert old changes * Multi-phase payouts to avoid bank-runs * Tests * Tests * Allow payment to be targeted elsewhere * Proper ssync payment failure handling * Test for repayment * Docs * Impl RankedMembers for RankedCollective * Implement Pay for Pot (i.e. basic account). * Benchmarks * Weights * Introduce Salary benchmark into node * Fix warning * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_salary * Update primitives/arithmetic/src/traits.rs Co-authored-by: Jegor Sidorenko <5252494+jsidorenko@users.noreply.github.com> * Update frame/salary/src/lib.rs Co-authored-by: Jegor Sidorenko <5252494+jsidorenko@users.noreply.github.com> * Update lib.rs * Update frame/salary/src/lib.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Docs * Update frame/salary/src/lib.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Update frame/salary/src/lib.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Fix * Fixes * Fixes * Move some salary traits stuff to a shared location * Fix * Update frame/salary/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * Update frame/salary/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * Mul floor * Fix warnings * Fix test * Docs --------- Co-authored-by: command-bot <> Co-authored-by: Jegor Sidorenko <5252494+jsidorenko@users.noreply.github.com> Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> Co-authored-by: Oliver Tale-Yazdi --- .gitignore | 1 + Cargo.lock | 18 + Cargo.toml | 1 + bin/node/runtime/Cargo.toml | 4 + bin/node/runtime/src/lib.rs | 34 +- frame/ranked-collective/src/lib.rs | 75 ++- frame/salary/Cargo.toml | 49 ++ frame/salary/README.md | 3 + frame/salary/src/benchmarking.rs | 183 +++++++ frame/salary/src/lib.rs | 514 +++++++++++++++++++ frame/salary/src/tests.rs | 641 ++++++++++++++++++++++++ frame/salary/src/weights.rs | 276 ++++++++++ frame/support/src/traits.rs | 2 +- frame/support/src/traits/members.rs | 24 + frame/support/src/traits/tokens.rs | 5 +- frame/support/src/traits/tokens/misc.rs | 17 +- primitives/arithmetic/src/traits.rs | 14 + 17 files changed, 1833 insertions(+), 28 deletions(-) create mode 100644 frame/salary/Cargo.toml create mode 100644 frame/salary/README.md create mode 100644 frame/salary/src/benchmarking.rs create mode 100644 frame/salary/src/lib.rs create mode 100644 frame/salary/src/tests.rs create mode 100644 frame/salary/src/weights.rs diff --git a/.gitignore b/.gitignore index 5cd013e054e4f..efb63520e1e1b 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,4 @@ rls*.log *.bin *.iml scripts/ci/node-template-release/Cargo.lock +substrate.code-workspace diff --git a/Cargo.lock b/Cargo.lock index 79e528b60b149..d67aeda9f03f2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3542,6 +3542,7 @@ dependencies = [ "pallet-referenda", "pallet-remark", "pallet-root-testing", + "pallet-salary", "pallet-scheduler", "pallet-session", "pallet-session-benchmarking", @@ -6362,6 +6363,23 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-salary" +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-scheduler" version = "4.0.0-dev" diff --git a/Cargo.toml b/Cargo.toml index af2d8f9066fa1..0b490bd17c82b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -134,6 +134,7 @@ members = [ "frame/recovery", "frame/referenda", "frame/remark", + "frame/salary", "frame/scheduler", "frame/scored-pool", "frame/session", diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index 993108bf732b1..a610bbe5d8113 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -96,6 +96,7 @@ pallet-recovery = { version = "4.0.0-dev", default-features = false, path = "../ 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-salary = { version = "4.0.0-dev", default-features = false, path = "../../../frame/salary" } 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" } @@ -183,6 +184,7 @@ std = [ "pallet-staking/std", "pallet-staking-runtime-api/std", "pallet-state-trie-migration/std", + "pallet-salary/std", "sp-session/std", "pallet-sudo/std", "frame-support/std", @@ -258,6 +260,7 @@ runtime-benchmarks = [ "pallet-referenda/runtime-benchmarks", "pallet-recovery/runtime-benchmarks", "pallet-remark/runtime-benchmarks", + "pallet-salary/runtime-benchmarks", "pallet-session-benchmarking/runtime-benchmarks", "pallet-society/runtime-benchmarks", "pallet-staking/runtime-benchmarks", @@ -316,6 +319,7 @@ try-runtime = [ "pallet-referenda/try-runtime", "pallet-remark/try-runtime", "pallet-root-testing/try-runtime", + "pallet-salary/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 9b317926a5a99..0c21fcc904fa1 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -32,10 +32,11 @@ use frame_support::{ pallet_prelude::Get, parameter_types, traits::{ - fungible::ItemOf, tokens::nonfungibles_v2::Inspect, AsEnsureOriginWithArg, ConstBool, - ConstU128, ConstU16, ConstU32, Currency, EitherOfDiverse, EqualPrivilegeOnly, Everything, - Imbalance, InstanceFilter, KeyOwnerProofSystem, LockIdentifier, Nothing, OnUnbalanced, - U128CurrencyToVote, WithdrawReasons, + fungible::ItemOf, + tokens::{nonfungibles_v2::Inspect, GetSalary}, + AsEnsureOriginWithArg, ConstBool, ConstU128, ConstU16, ConstU32, Currency, EitherOfDiverse, + EqualPrivilegeOnly, Everything, Imbalance, InstanceFilter, KeyOwnerProofSystem, + LockIdentifier, Nothing, OnUnbalanced, U128CurrencyToVote, WithdrawReasons, }, weights::{ constants::{ @@ -1571,6 +1572,29 @@ impl pallet_uniques::Config for Runtime { type Locker = (); } +parameter_types! { + pub const Budget: Balance = 10_000 * DOLLARS; + pub TreasuryAccount: AccountId = Treasury::account_id(); +} + +pub struct SalaryForRank; +impl GetSalary for SalaryForRank { + fn get_salary(a: u16, _: &AccountId) -> Balance { + Balance::from(a) * 1000 * DOLLARS + } +} + +impl pallet_salary::Config for Runtime { + type WeightInfo = (); + type RuntimeEvent = RuntimeEvent; + type Paymaster = pallet_salary::PayFromAccount; + type Members = RankedCollective; + type Salary = SalaryForRank; + type RegistrationPeriod = ConstU32<200>; + type PayoutPeriod = ConstU32<200>; + type Budget = Budget; +} + parameter_types! { pub Features: PalletFeatures = PalletFeatures::all_enabled(); pub const MaxAttributesPerCall: u32 = 10; @@ -1766,6 +1790,7 @@ construct_runtime!( Nis: pallet_nis, Uniques: pallet_uniques, Nfts: pallet_nfts, + Salary: pallet_salary, TransactionStorage: pallet_transaction_storage, VoterList: pallet_bags_list::, StateTrieMigration: pallet_state_trie_migration, @@ -1885,6 +1910,7 @@ mod benches { [pallet_referenda, Referenda] [pallet_recovery, Recovery] [pallet_remark, Remark] + [pallet_salary, Salary] [pallet_scheduler, Scheduler] [pallet_glutton, Glutton] [pallet_session, SessionBench::] diff --git a/frame/ranked-collective/src/lib.rs b/frame/ranked-collective/src/lib.rs index 66af9bf6e0a5e..8ed1bbd2e01d6 100644 --- a/frame/ranked-collective/src/lib.rs +++ b/frame/ranked-collective/src/lib.rs @@ -54,7 +54,7 @@ use frame_support::{ codec::{Decode, Encode, MaxEncodedLen}, dispatch::{DispatchError, DispatchResultWithPostInfo, PostDispatchInfo}, ensure, - traits::{EnsureOrigin, PollStatus, Polling, VoteTally}, + traits::{EnsureOrigin, PollStatus, Polling, RankedMembers, VoteTally}, CloneNoBound, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound, }; @@ -472,24 +472,7 @@ pub mod pallet { 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); - - 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(()) + Self::do_demote_member(who, Some(max_rank)) } /// Remove the member entirely. @@ -659,7 +642,7 @@ pub mod pallet { Ok(()) } - /// Promotes a member in the ranked collective into the next role. + /// Promotes a member in the ranked collective into the next higher rank. /// /// 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. @@ -681,6 +664,33 @@ pub mod pallet { Ok(()) } + /// Demotes a member in the ranked collective into the next lower rank. + /// + /// A `maybe_max_rank` may be provided to check that the member does not get demoted from + /// a certain rank. Is `None` is provided, then the rank will be decremented without checks. + fn do_demote_member(who: T::AccountId, maybe_max_rank: Option) -> DispatchResult { + let mut record = Self::ensure_member(&who)?; + let rank = record.rank; + if let Some(max_rank) = maybe_max_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(()) + } + /// 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 { @@ -691,4 +701,29 @@ pub mod pallet { Ok(()) } } + + impl, I: 'static> RankedMembers for Pallet { + type AccountId = T::AccountId; + type Rank = Rank; + + fn min_rank() -> Self::Rank { + 0 + } + + fn rank_of(who: &Self::AccountId) -> Option { + Some(Self::ensure_member(&who).ok()?.rank) + } + + fn induct(who: &Self::AccountId) -> DispatchResult { + Self::do_add_member(who.clone()) + } + + fn promote(who: &Self::AccountId) -> DispatchResult { + Self::do_promote_member(who.clone(), None) + } + + fn demote(who: &Self::AccountId) -> DispatchResult { + Self::do_demote_member(who.clone(), None) + } + } } diff --git a/frame/salary/Cargo.toml b/frame/salary/Cargo.toml new file mode 100644 index 0000000000000..86cae16bb28b7 --- /dev/null +++ b/frame/salary/Cargo.toml @@ -0,0 +1,49 @@ +[package] +name = "pallet-salary" +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 = "Paymaster" +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 = "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"] +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/salary/README.md b/frame/salary/README.md new file mode 100644 index 0000000000000..25c1be0e805d7 --- /dev/null +++ b/frame/salary/README.md @@ -0,0 +1,3 @@ +# Salary + +Make periodic payment to members of a ranked collective according to rank. \ No newline at end of file diff --git a/frame/salary/src/benchmarking.rs b/frame/salary/src/benchmarking.rs new file mode 100644 index 0000000000000..339185b37cb7b --- /dev/null +++ b/frame/salary/src/benchmarking.rs @@ -0,0 +1,183 @@ +// 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. + +//! Salary pallet benchmarking. + +#![cfg(feature = "runtime-benchmarks")] + +use super::*; +use crate::Pallet as Salary; + +use frame_benchmarking::v2::*; +use frame_system::{Pallet as System, RawOrigin}; +use sp_core::Get; + +const SEED: u32 = 0; + +fn ensure_member_with_salary, I: 'static>(who: &T::AccountId) { + // induct if not a member. + if T::Members::rank_of(who).is_none() { + T::Members::induct(who).unwrap(); + } + // promote until they have a salary. + for _ in 0..255 { + let r = T::Members::rank_of(who).expect("prior guard ensures `who` is a member; qed"); + if !T::Salary::get_salary(r, &who).is_zero() { + break + } + T::Members::promote(who).unwrap(); + } +} + +#[instance_benchmarks] +mod benchmarks { + use super::*; + + #[benchmark] + fn init() { + let caller: T::AccountId = whitelisted_caller(); + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone())); + + assert!(Salary::::status().is_some()); + } + + #[benchmark] + fn bump() { + let caller: T::AccountId = whitelisted_caller(); + Salary::::init(RawOrigin::Signed(caller.clone()).into()).unwrap(); + System::::set_block_number(System::::block_number() + Salary::::cycle_period()); + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone())); + + assert_eq!(Salary::::status().unwrap().cycle_index, 1u32.into()); + } + + #[benchmark] + fn induct() { + let caller = whitelisted_caller(); + ensure_member_with_salary::(&caller); + Salary::::init(RawOrigin::Signed(caller.clone()).into()).unwrap(); + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone())); + + assert!(Salary::::last_active(&caller).is_ok()); + } + + #[benchmark] + fn register() { + let caller = whitelisted_caller(); + ensure_member_with_salary::(&caller); + Salary::::init(RawOrigin::Signed(caller.clone()).into()).unwrap(); + Salary::::induct(RawOrigin::Signed(caller.clone()).into()).unwrap(); + System::::set_block_number(System::::block_number() + Salary::::cycle_period()); + Salary::::bump(RawOrigin::Signed(caller.clone()).into()).unwrap(); + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone())); + + assert_eq!(Salary::::last_active(&caller).unwrap(), 1u32.into()); + } + + #[benchmark] + fn payout() { + let caller = whitelisted_caller(); + ensure_member_with_salary::(&caller); + Salary::::init(RawOrigin::Signed(caller.clone()).into()).unwrap(); + Salary::::induct(RawOrigin::Signed(caller.clone()).into()).unwrap(); + System::::set_block_number(System::::block_number() + Salary::::cycle_period()); + Salary::::bump(RawOrigin::Signed(caller.clone()).into()).unwrap(); + System::::set_block_number(System::::block_number() + T::RegistrationPeriod::get()); + + let salary = T::Salary::get_salary(T::Members::rank_of(&caller).unwrap(), &caller); + T::Paymaster::ensure_successful(&caller, salary); + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone())); + + match Claimant::::get(&caller) { + Some(ClaimantStatus { last_active, status: Attempted { id, .. } }) => { + assert_eq!(last_active, 1u32.into()); + assert_ne!(T::Paymaster::check_payment(id), PaymentStatus::Failure); + }, + _ => panic!("No claim made"), + } + assert!(Salary::::payout(RawOrigin::Signed(caller.clone()).into()).is_err()); + } + + #[benchmark] + fn payout_other() { + let caller = whitelisted_caller(); + ensure_member_with_salary::(&caller); + Salary::::init(RawOrigin::Signed(caller.clone()).into()).unwrap(); + Salary::::induct(RawOrigin::Signed(caller.clone()).into()).unwrap(); + System::::set_block_number(System::::block_number() + Salary::::cycle_period()); + Salary::::bump(RawOrigin::Signed(caller.clone()).into()).unwrap(); + System::::set_block_number(System::::block_number() + T::RegistrationPeriod::get()); + + let salary = T::Salary::get_salary(T::Members::rank_of(&caller).unwrap(), &caller); + let recipient: T::AccountId = account("recipient", 0, SEED); + T::Paymaster::ensure_successful(&recipient, salary); + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone()), recipient.clone()); + + match Claimant::::get(&caller) { + Some(ClaimantStatus { last_active, status: Attempted { id, .. } }) => { + assert_eq!(last_active, 1u32.into()); + assert_ne!(T::Paymaster::check_payment(id), PaymentStatus::Failure); + }, + _ => panic!("No claim made"), + } + assert!(Salary::::payout(RawOrigin::Signed(caller.clone()).into()).is_err()); + } + + #[benchmark] + fn check_payment() { + let caller = whitelisted_caller(); + ensure_member_with_salary::(&caller); + Salary::::init(RawOrigin::Signed(caller.clone()).into()).unwrap(); + Salary::::induct(RawOrigin::Signed(caller.clone()).into()).unwrap(); + System::::set_block_number(System::::block_number() + Salary::::cycle_period()); + Salary::::bump(RawOrigin::Signed(caller.clone()).into()).unwrap(); + System::::set_block_number(System::::block_number() + T::RegistrationPeriod::get()); + + let salary = T::Salary::get_salary(T::Members::rank_of(&caller).unwrap(), &caller); + let recipient: T::AccountId = account("recipient", 0, SEED); + T::Paymaster::ensure_successful(&recipient, salary); + Salary::::payout(RawOrigin::Signed(caller.clone()).into()).unwrap(); + let id = match Claimant::::get(&caller).unwrap().status { + Attempted { id, .. } => id, + _ => panic!("No claim made"), + }; + T::Paymaster::ensure_concluded(id); + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone())); + + assert!(!matches!(Claimant::::get(&caller).unwrap().status, Attempted { .. })); + } + + impl_benchmark_test_suite! { + Salary, + crate::tests::new_test_ext(), + crate::tests::Test, + } +} diff --git a/frame/salary/src/lib.rs b/frame/salary/src/lib.rs new file mode 100644 index 0000000000000..2169952f1a7f3 --- /dev/null +++ b/frame/salary/src/lib.rs @@ -0,0 +1,514 @@ +// 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. + +//! Make periodic payment to members of a ranked collective according to rank. + +#![cfg_attr(not(feature = "std"), no_std)] +#![recursion_limit = "128"] + +use codec::{Decode, Encode, FullCodec, MaxEncodedLen}; +use scale_info::TypeInfo; +use sp_arithmetic::traits::{Saturating, Zero}; +use sp_core::TypedGet; +use sp_runtime::Perbill; +use sp_std::{fmt::Debug, marker::PhantomData, prelude::*}; + +use frame_support::{ + dispatch::DispatchResultWithPostInfo, + ensure, + traits::{ + tokens::{fungible, Balance, GetSalary}, + RankedMembers, + }, + RuntimeDebug, +}; + +#[cfg(test)] +mod tests; + +#[cfg(feature = "runtime-benchmarks")] +mod benchmarking; +pub mod weights; + +pub use pallet::*; +pub use weights::WeightInfo; + +/// Payroll cycle. +pub type Cycle = u32; + +/// Status for making a payment via the `Pay::pay` trait function. +#[derive(Encode, Decode, Eq, PartialEq, Clone, TypeInfo, MaxEncodedLen, RuntimeDebug)] +pub enum PaymentStatus { + /// Payment is in progress. Nothing to report yet. + InProgress, + /// Payment status is unknowable. It will never be reported successful or failed. + Unknown, + /// Payment happened successfully. + Success, + /// Payment failed. It may safely be retried. + Failure, +} + +/// Can be implemented by `PayFromAccount` using a `fungible` impl, but can also be implemented with +/// XCM/MultiAsset and made generic over assets. +pub trait Pay { + /// The type by which we measure units of the currency in which we make payments. + type Balance: Balance; + /// The type by which we identify the individuals to whom a payment may be made. + type AccountId; + /// An identifier given to an individual payment. + type Id: FullCodec + MaxEncodedLen + TypeInfo + Clone + Eq + PartialEq + Debug + Copy; + /// Make a payment and return an identifier for later evaluation of success in some off-chain + /// mechanism (likely an event, but possibly not on this chain). + fn pay(who: &Self::AccountId, amount: Self::Balance) -> Result; + /// Check how a payment has proceeded. `id` must have been a previously returned by `pay` for + /// the result of this call to be meaningful. + fn check_payment(id: Self::Id) -> PaymentStatus; + /// Ensure that a call to pay with the given parameters will be successful if done immediately + /// after this call. Used in benchmarking code. + #[cfg(feature = "runtime-benchmarks")] + fn ensure_successful(who: &Self::AccountId, amount: Self::Balance); + /// Ensure that a call to check_payment with the given parameters will return either Success + /// or Failure. + #[cfg(feature = "runtime-benchmarks")] + fn ensure_concluded(id: Self::Id); +} + +/// Simple implementation of `Pay` which makes a payment from a "pot" - i.e. a single account. +pub struct PayFromAccount(sp_std::marker::PhantomData<(F, A)>); +impl + fungible::Mutate> Pay + for PayFromAccount +{ + type Balance = F::Balance; + type AccountId = A::Type; + type Id = (); + fn pay(who: &Self::AccountId, amount: Self::Balance) -> Result { + >::transfer(&A::get(), who, amount, false).map_err(|_| ())?; + Ok(()) + } + fn check_payment(_: ()) -> PaymentStatus { + PaymentStatus::Success + } + #[cfg(feature = "runtime-benchmarks")] + fn ensure_successful(_: &Self::AccountId, amount: Self::Balance) { + >::mint_into(&A::get(), amount).unwrap(); + } + #[cfg(feature = "runtime-benchmarks")] + fn ensure_concluded(_: Self::Id) {} +} + +/// The status of the pallet instance. +#[derive(Encode, Decode, Eq, PartialEq, Clone, TypeInfo, MaxEncodedLen, RuntimeDebug)] +pub struct StatusType { + /// The index of the "current cycle" (i.e. the last cycle being processed). + cycle_index: CycleIndex, + /// The first block of the "current cycle" (i.e. the last cycle being processed). + cycle_start: BlockNumber, + /// The total budget available for all payments in the current cycle. + budget: Balance, + /// The total amount of the payments registered in the current cycle. + total_registrations: Balance, + /// The total amount of unregistered payments which have been made in the current cycle. + total_unregistered_paid: Balance, +} + +/// The state of a specific payment claim. +#[derive(Encode, Decode, Eq, PartialEq, Clone, TypeInfo, MaxEncodedLen, RuntimeDebug)] +pub enum ClaimState { + /// No claim recorded. + Nothing, + /// Amount reserved when last active. + Registered(Balance), + /// Amount attempted to be paid when last active as well as the identity of the payment. + Attempted { registered: Option, id: Id, amount: Balance }, +} + +use ClaimState::*; + +/// The status of a single payee/claimant. +#[derive(Encode, Decode, Eq, PartialEq, Clone, TypeInfo, MaxEncodedLen, RuntimeDebug)] +pub struct ClaimantStatus { + /// The most recent cycle in which the claimant was active. + last_active: CycleIndex, + /// The state of the payment/claim with in the above cycle. + status: ClaimState, +} + +#[frame_support::pallet] +pub mod pallet { + use super::*; + use frame_support::{dispatch::Pays, pallet_prelude::*}; + use frame_system::pallet_prelude::*; + + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + 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 runtime event type. + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; + + /// Means by which we can make payments to accounts. This also defines the currency and the + /// balance which we use to denote that currency. + type Paymaster: Pay::AccountId>; + + /// The current membership of payees. + type Members: RankedMembers::AccountId>; + + /// The maximum payout to be made for a single period to an active member of the given rank. + /// + /// The benchmarks require that this be non-zero for some rank at most 255. + type Salary: GetSalary< + ::Rank, + Self::AccountId, + ::Balance, + >; + + /// The number of blocks within a cycle which accounts have to register their intent to + /// claim. + /// + /// The number of blocks between sequential payout cycles is the sum of this and + /// `PayoutPeriod`. + #[pallet::constant] + type RegistrationPeriod: Get; + + /// The number of blocks within a cycle which accounts have to claim the payout. + /// + /// The number of blocks between sequential payout cycles is the sum of this and + /// `RegistrationPeriod`. + #[pallet::constant] + type PayoutPeriod: Get; + + /// The total budget per cycle. + /// + /// This may change over the course of a cycle without any problem. + #[pallet::constant] + type Budget: Get>; + } + + pub type CycleIndexOf = ::BlockNumber; + pub type BalanceOf = <>::Paymaster as Pay>::Balance; + pub type IdOf = <>::Paymaster as Pay>::Id; + pub type StatusOf = + StatusType, ::BlockNumber, BalanceOf>; + pub type ClaimantStatusOf = ClaimantStatus, BalanceOf, IdOf>; + + /// The overall status of the system. + #[pallet::storage] + pub(super) type Status, I: 'static = ()> = + StorageValue<_, StatusOf, OptionQuery>; + + /// The status of a claimant. + #[pallet::storage] + pub(super) type Claimant, I: 'static = ()> = + StorageMap<_, Twox64Concat, T::AccountId, ClaimantStatusOf, OptionQuery>; + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event, I: 'static = ()> { + /// A member is inducted into the payroll. + Inducted { who: T::AccountId }, + /// A member registered for a payout. + Registered { who: T::AccountId, amount: BalanceOf }, + /// A payment happened. + Paid { + who: T::AccountId, + beneficiary: T::AccountId, + amount: BalanceOf, + id: ::Id, + }, + /// The next cycle begins. + CycleStarted { index: CycleIndexOf }, + } + + #[pallet::error] + pub enum Error { + /// The salary system has already been started. + AlreadyStarted, + /// The account is not a ranked member. + NotMember, + /// The account is already inducted. + AlreadyInducted, + // The account is not yet inducted into the system. + NotInducted, + /// The member does not have a current valid claim. + NoClaim, + /// The member's claim is zero. + ClaimZero, + /// Current cycle's registration period is over. + TooLate, + /// Current cycle's payment period is not yet begun. + TooEarly, + /// Cycle is not yet over. + NotYet, + /// The payout cycles have not yet started. + NotStarted, + /// There is no budget left for the payout. + Bankrupt, + /// There was some issue with the mechanism of payment. + PayError, + /// The payment has neither failed nor succeeded yet. + Inconclusive, + /// The cycle is after that in which the payment was made. + NotCurrent, + } + + #[pallet::call] + impl, I: 'static> Pallet { + /// Start the first payout cycle. + /// + /// - `origin`: A `Signed` origin of an account. + #[pallet::weight(T::WeightInfo::init())] + #[pallet::call_index(0)] + pub fn init(origin: OriginFor) -> DispatchResultWithPostInfo { + let _ = ensure_signed(origin)?; + let now = frame_system::Pallet::::block_number(); + ensure!(!Status::::exists(), Error::::AlreadyStarted); + let status = StatusType { + cycle_index: Zero::zero(), + cycle_start: now, + budget: T::Budget::get(), + total_registrations: Zero::zero(), + total_unregistered_paid: Zero::zero(), + }; + Status::::put(&status); + + Self::deposit_event(Event::::CycleStarted { index: status.cycle_index }); + Ok(Pays::No.into()) + } + + /// Move to next payout cycle, assuming that the present block is now within that cycle. + /// + /// - `origin`: A `Signed` origin of an account. + #[pallet::weight(T::WeightInfo::bump())] + #[pallet::call_index(1)] + pub fn bump(origin: OriginFor) -> DispatchResultWithPostInfo { + let _ = ensure_signed(origin)?; + let now = frame_system::Pallet::::block_number(); + let cycle_period = Self::cycle_period(); + let mut status = Status::::get().ok_or(Error::::NotStarted)?; + status.cycle_start.saturating_accrue(cycle_period); + ensure!(now >= status.cycle_start, Error::::NotYet); + status.cycle_index.saturating_inc(); + status.budget = T::Budget::get(); + status.total_registrations = Zero::zero(); + status.total_unregistered_paid = Zero::zero(); + Status::::put(&status); + + Self::deposit_event(Event::::CycleStarted { index: status.cycle_index }); + Ok(Pays::No.into()) + } + + /// Induct oneself into the payout system. + #[pallet::weight(T::WeightInfo::induct())] + #[pallet::call_index(2)] + pub fn induct(origin: OriginFor) -> DispatchResultWithPostInfo { + let who = ensure_signed(origin)?; + let cycle_index = Status::::get().ok_or(Error::::NotStarted)?.cycle_index; + let _ = T::Members::rank_of(&who).ok_or(Error::::NotMember)?; + ensure!(!Claimant::::contains_key(&who), Error::::AlreadyInducted); + + Claimant::::insert( + &who, + ClaimantStatus { last_active: cycle_index, status: Nothing }, + ); + + Self::deposit_event(Event::::Inducted { who }); + Ok(Pays::No.into()) + } + + /// Register for a payout. + /// + /// Will only work if we are in the first `RegistrationPeriod` blocks since the cycle + /// started. + /// + /// - `origin`: A `Signed` origin of an account which is a member of `Members`. + #[pallet::weight(T::WeightInfo::register())] + #[pallet::call_index(3)] + pub fn register(origin: OriginFor) -> DispatchResultWithPostInfo { + let who = ensure_signed(origin)?; + let rank = T::Members::rank_of(&who).ok_or(Error::::NotMember)?; + let mut status = Status::::get().ok_or(Error::::NotStarted)?; + let mut claimant = Claimant::::get(&who).ok_or(Error::::NotInducted)?; + let now = frame_system::Pallet::::block_number(); + ensure!( + now < status.cycle_start + T::RegistrationPeriod::get(), + Error::::TooLate + ); + ensure!(claimant.last_active < status.cycle_index, Error::::NoClaim); + let payout = T::Salary::get_salary(rank, &who); + ensure!(!payout.is_zero(), Error::::ClaimZero); + claimant.last_active = status.cycle_index; + claimant.status = Registered(payout); + status.total_registrations.saturating_accrue(payout); + + Claimant::::insert(&who, &claimant); + Status::::put(&status); + + Self::deposit_event(Event::::Registered { who, amount: payout }); + Ok(Pays::No.into()) + } + + /// Request a payout. + /// + /// Will only work if we are after the first `RegistrationPeriod` blocks since the cycle + /// started but by no more than `PayoutPeriod` blocks. + /// + /// - `origin`: A `Signed` origin of an account which is a member of `Members`. + #[pallet::weight(T::WeightInfo::payout())] + #[pallet::call_index(4)] + pub fn payout(origin: OriginFor) -> DispatchResultWithPostInfo { + let who = ensure_signed(origin)?; + Self::do_payout(who.clone(), who)?; + Ok(Pays::No.into()) + } + + /// Request a payout to a secondary account. + /// + /// Will only work if we are after the first `RegistrationPeriod` blocks since the cycle + /// started but by no more than `PayoutPeriod` blocks. + /// + /// - `origin`: A `Signed` origin of an account which is a member of `Members`. + /// - `beneficiary`: The account to receive payment. + #[pallet::weight(T::WeightInfo::payout_other())] + #[pallet::call_index(5)] + pub fn payout_other( + origin: OriginFor, + beneficiary: T::AccountId, + ) -> DispatchResultWithPostInfo { + let who = ensure_signed(origin)?; + Self::do_payout(who, beneficiary)?; + Ok(Pays::No.into()) + } + + /// Update a payment's status; if it failed, alter the state so the payment can be retried. + /// + /// This must be called within the same cycle as the failed payment. It will fail with + /// `Event::NotCurrent` otherwise. + /// + /// - `origin`: A `Signed` origin of an account which is a member of `Members` who has + /// received a payment this cycle. + #[pallet::weight(T::WeightInfo::check_payment())] + #[pallet::call_index(6)] + pub fn check_payment(origin: OriginFor) -> DispatchResultWithPostInfo { + let who = ensure_signed(origin)?; + + let mut status = Status::::get().ok_or(Error::::NotStarted)?; + let mut claimant = Claimant::::get(&who).ok_or(Error::::NotInducted)?; + ensure!(claimant.last_active == status.cycle_index, Error::::NotCurrent); + let (id, registered, amount) = match claimant.status { + Attempted { id, registered, amount } => (id, registered, amount), + _ => return Err(Error::::NoClaim.into()), + }; + match T::Paymaster::check_payment(id) { + PaymentStatus::Failure => { + // Payment failed: we reset back to the status prior to payment. + if let Some(amount) = registered { + // Account registered; this makes it simple to roll back and allow retry. + claimant.status = ClaimState::Registered(amount); + } else { + // Account didn't register; we set it to `Nothing` but must decrement + // the `last_active` also to ensure a retry works. + claimant.last_active.saturating_reduce(1u32.into()); + claimant.status = ClaimState::Nothing; + // Since it is not registered, we must walk back our counter for what has + // been paid. + status.total_unregistered_paid.saturating_reduce(amount); + } + }, + PaymentStatus::Success => claimant.status = ClaimState::Nothing, + _ => return Err(Error::::Inconclusive.into()), + } + Claimant::::insert(&who, &claimant); + Status::::put(&status); + + Ok(Pays::No.into()) + } + } + + impl, I: 'static> Pallet { + pub fn status() -> Option> { + Status::::get() + } + pub fn last_active(who: &T::AccountId) -> Result, DispatchError> { + Ok(Claimant::::get(&who).ok_or(Error::::NotInducted)?.last_active) + } + pub fn cycle_period() -> T::BlockNumber { + T::RegistrationPeriod::get() + T::PayoutPeriod::get() + } + fn do_payout(who: T::AccountId, beneficiary: T::AccountId) -> DispatchResult { + let mut status = Status::::get().ok_or(Error::::NotStarted)?; + let mut claimant = Claimant::::get(&who).ok_or(Error::::NotInducted)?; + + let now = frame_system::Pallet::::block_number(); + ensure!( + now >= status.cycle_start + T::RegistrationPeriod::get(), + Error::::TooEarly, + ); + + let (payout, registered) = match claimant.status { + Registered(unpaid) if claimant.last_active == status.cycle_index => { + // Registered for this cycle. Pay accordingly. + let payout = if status.total_registrations <= status.budget { + // Can pay in full. + unpaid + } else { + // Must be reduced pro-rata + Perbill::from_rational(status.budget, status.total_registrations) + .mul_floor(unpaid) + }; + (payout, Some(unpaid)) + }, + Nothing | Attempted { .. } if claimant.last_active < status.cycle_index => { + // Not registered for this cycle. Pay from whatever is left. + let rank = T::Members::rank_of(&who).ok_or(Error::::NotMember)?; + let ideal_payout = T::Salary::get_salary(rank, &who); + + let pot = status + .budget + .saturating_sub(status.total_registrations) + .saturating_sub(status.total_unregistered_paid); + + let payout = ideal_payout.min(pot); + ensure!(!payout.is_zero(), Error::::ClaimZero); + + status.total_unregistered_paid.saturating_accrue(payout); + (payout, None) + }, + _ => return Err(Error::::NoClaim.into()), + }; + + claimant.last_active = status.cycle_index; + + let id = + T::Paymaster::pay(&beneficiary, payout).map_err(|()| Error::::PayError)?; + + claimant.status = Attempted { registered, id, amount: payout }; + + Claimant::::insert(&who, &claimant); + Status::::put(&status); + + Self::deposit_event(Event::::Paid { who, beneficiary, amount: payout, id }); + Ok(()) + } + } +} diff --git a/frame/salary/src/tests.rs b/frame/salary/src/tests.rs new file mode 100644 index 0000000000000..8649291225bc3 --- /dev/null +++ b/frame/salary/src/tests.rs @@ -0,0 +1,641 @@ +// 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, + pallet_prelude::Weight, + parameter_types, + traits::{tokens::ConvertRank, ConstU32, ConstU64, Everything}, +}; +use sp_core::H256; +use sp_runtime::{ + testing::Header, + traits::{BlakeTwo256, Identity, IdentityLookup}, + DispatchResult, +}; +use sp_std::cell::RefCell; + +use super::*; +use crate as pallet_salary; + +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}, + Salary: pallet_salary::{Pallet, Call, Storage, Event}, + } +); + +parameter_types! { + pub BlockWeights: frame_system::limits::BlockWeights = + frame_system::limits::BlockWeights::simple_max(Weight::from_ref_time(1_000_000)); +} +impl frame_system::Config for Test { + type BaseCallFilter = Everything; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type RuntimeOrigin = RuntimeOrigin; + type Index = u64; + type BlockNumber = u64; + type RuntimeCall = RuntimeCall; + type Hash = H256; + 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>; +} + +thread_local! { + pub static PAID: RefCell> = RefCell::new(BTreeMap::new()); + pub static STATUS: RefCell> = RefCell::new(BTreeMap::new()); + pub static LAST_ID: RefCell = RefCell::new(0u64); +} + +fn paid(who: u64) -> u64 { + PAID.with(|p| p.borrow().get(&who).cloned().unwrap_or(0)) +} +fn unpay(who: u64, amount: u64) { + PAID.with(|p| p.borrow_mut().entry(who).or_default().saturating_reduce(amount)) +} +fn set_status(id: u64, s: PaymentStatus) { + STATUS.with(|m| m.borrow_mut().insert(id, s)); +} + +pub struct TestPay; +impl Pay for TestPay { + type AccountId = u64; + type Balance = u64; + type Id = u64; + + fn pay(who: &Self::AccountId, amount: Self::Balance) -> Result { + PAID.with(|paid| *paid.borrow_mut().entry(*who).or_default() += amount); + Ok(LAST_ID.with(|lid| { + let x = *lid.borrow(); + lid.replace(x + 1); + x + })) + } + fn check_payment(id: Self::Id) -> PaymentStatus { + STATUS.with(|s| s.borrow().get(&id).cloned().unwrap_or(PaymentStatus::Unknown)) + } + #[cfg(feature = "runtime-benchmarks")] + fn ensure_successful(_: &Self::AccountId, _: Self::Balance) {} + #[cfg(feature = "runtime-benchmarks")] + fn ensure_concluded(id: Self::Id) { + set_status(id, PaymentStatus::Failure) + } +} + +thread_local! { + pub static CLUB: RefCell> = RefCell::new(BTreeMap::new()); +} + +pub struct TestClub; +impl RankedMembers for TestClub { + type AccountId = u64; + type Rank = u64; + fn min_rank() -> Self::Rank { + 0 + } + fn rank_of(who: &Self::AccountId) -> Option { + CLUB.with(|club| club.borrow().get(who).cloned()) + } + fn induct(who: &Self::AccountId) -> DispatchResult { + CLUB.with(|club| club.borrow_mut().insert(*who, 0)); + Ok(()) + } + fn promote(who: &Self::AccountId) -> DispatchResult { + CLUB.with(|club| { + club.borrow_mut().entry(*who).and_modify(|r| *r += 1); + }); + Ok(()) + } + fn demote(who: &Self::AccountId) -> DispatchResult { + CLUB.with(|club| match club.borrow().get(who) { + None => Err(sp_runtime::DispatchError::Unavailable), + Some(&0) => { + club.borrow_mut().remove(&who); + Ok(()) + }, + Some(_) => { + club.borrow_mut().entry(*who).and_modify(|x| *x -= 1); + Ok(()) + }, + }) + } +} + +fn set_rank(who: u64, rank: u64) { + CLUB.with(|club| club.borrow_mut().insert(who, rank)); +} + +parameter_types! { + pub static Budget: u64 = 10; +} + +impl Config for Test { + type WeightInfo = (); + type RuntimeEvent = RuntimeEvent; + type Paymaster = TestPay; + type Members = TestClub; + type Salary = ConvertRank; + type RegistrationPeriod = ConstU64<2>; + type PayoutPeriod = ConstU64<2>; + type Budget = Budget; +} + +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); +} + +#[allow(dead_code)] +fn run_to(n: u64) { + while System::block_number() < n { + next_block(); + } +} + +#[test] +fn basic_stuff() { + new_test_ext().execute_with(|| { + assert!(Salary::last_active(&0).is_err()); + assert_eq!(Salary::status(), None); + }); +} + +#[test] +fn can_start() { + new_test_ext().execute_with(|| { + assert_ok!(Salary::init(RuntimeOrigin::signed(1))); + assert_eq!( + Salary::status(), + Some(StatusType { + cycle_index: 0, + cycle_start: 1, + budget: 10, + total_registrations: 0, + total_unregistered_paid: 0, + }) + ); + }); +} + +#[test] +fn bump_works() { + new_test_ext().execute_with(|| { + assert_ok!(Salary::init(RuntimeOrigin::signed(1))); + run_to(4); + assert_noop!(Salary::bump(RuntimeOrigin::signed(1)), Error::::NotYet); + + run_to(5); + assert_ok!(Salary::bump(RuntimeOrigin::signed(1))); + assert_eq!( + Salary::status(), + Some(StatusType { + cycle_index: 1, + cycle_start: 5, + budget: 10, + total_registrations: 0, + total_unregistered_paid: 0 + }) + ); + + run_to(8); + assert_noop!(Salary::bump(RuntimeOrigin::signed(1)), Error::::NotYet); + + BUDGET.with(|b| b.replace(5)); + run_to(9); + assert_ok!(Salary::bump(RuntimeOrigin::signed(1))); + assert_eq!( + Salary::status(), + Some(StatusType { + cycle_index: 2, + cycle_start: 9, + budget: 5, + total_registrations: 0, + total_unregistered_paid: 0 + }) + ); + }); +} + +#[test] +fn induct_works() { + new_test_ext().execute_with(|| { + assert_ok!(Salary::init(RuntimeOrigin::signed(1))); + + assert_noop!(Salary::induct(RuntimeOrigin::signed(1)), Error::::NotMember); + set_rank(1, 1); + assert!(Salary::last_active(&1).is_err()); + assert_ok!(Salary::induct(RuntimeOrigin::signed(1))); + assert_eq!(Salary::last_active(&1).unwrap(), 0); + assert_noop!(Salary::induct(RuntimeOrigin::signed(1)), Error::::AlreadyInducted); + }); +} + +#[test] +fn unregistered_payment_works() { + new_test_ext().execute_with(|| { + set_rank(1, 1); + assert_noop!(Salary::induct(RuntimeOrigin::signed(1)), Error::::NotStarted); + assert_ok!(Salary::init(RuntimeOrigin::signed(1))); + assert_noop!(Salary::payout(RuntimeOrigin::signed(1)), Error::::NotInducted); + assert_ok!(Salary::induct(RuntimeOrigin::signed(1))); + // No claim on the cycle active during induction. + assert_noop!(Salary::payout(RuntimeOrigin::signed(1)), Error::::TooEarly); + run_to(3); + assert_noop!(Salary::payout(RuntimeOrigin::signed(1)), Error::::NoClaim); + + run_to(6); + assert_ok!(Salary::bump(RuntimeOrigin::signed(1))); + assert_noop!(Salary::payout(RuntimeOrigin::signed(1)), Error::::TooEarly); + run_to(7); + assert_ok!(Salary::payout(RuntimeOrigin::signed(1))); + assert_eq!(paid(1), 1); + assert_eq!(Salary::status().unwrap().total_unregistered_paid, 1); + assert_noop!(Salary::payout(RuntimeOrigin::signed(1)), Error::::NoClaim); + run_to(8); + assert_noop!(Salary::bump(RuntimeOrigin::signed(1)), Error::::NotYet); + run_to(9); + assert_ok!(Salary::bump(RuntimeOrigin::signed(1))); + run_to(11); + assert_ok!(Salary::payout_other(RuntimeOrigin::signed(1), 10)); + assert_eq!(paid(1), 1); + assert_eq!(paid(10), 1); + assert_eq!(Salary::status().unwrap().total_unregistered_paid, 1); + }); +} + +#[test] +fn retry_payment_works() { + new_test_ext().execute_with(|| { + set_rank(1, 1); + assert_ok!(Salary::init(RuntimeOrigin::signed(1))); + assert_ok!(Salary::induct(RuntimeOrigin::signed(1))); + run_to(6); + assert_ok!(Salary::bump(RuntimeOrigin::signed(1))); + run_to(7); + assert_ok!(Salary::payout(RuntimeOrigin::signed(1))); + + // Payment failed. + unpay(1, 1); + set_status(0, PaymentStatus::Failure); + + assert_eq!(paid(1), 0); + assert_eq!(Salary::status().unwrap().total_unregistered_paid, 1); + + // Can't just retry. + assert_noop!(Salary::payout(RuntimeOrigin::signed(1)), Error::::NoClaim); + // Check status. + assert_ok!(Salary::check_payment(RuntimeOrigin::signed(1))); + // Allowed to try again. + assert_ok!(Salary::payout(RuntimeOrigin::signed(1))); + + assert_eq!(paid(1), 1); + assert_eq!(Salary::status().unwrap().total_unregistered_paid, 1); + + assert_noop!(Salary::payout(RuntimeOrigin::signed(1)), Error::::NoClaim); + run_to(8); + assert_noop!(Salary::bump(RuntimeOrigin::signed(1)), Error::::NotYet); + run_to(9); + assert_ok!(Salary::bump(RuntimeOrigin::signed(1))); + run_to(11); + assert_ok!(Salary::payout_other(RuntimeOrigin::signed(1), 10)); + assert_eq!(paid(1), 1); + assert_eq!(paid(10), 1); + assert_eq!(Salary::status().unwrap().total_unregistered_paid, 1); + }); +} + +#[test] +fn retry_registered_payment_works() { + new_test_ext().execute_with(|| { + set_rank(1, 1); + assert_ok!(Salary::init(RuntimeOrigin::signed(1))); + assert_ok!(Salary::induct(RuntimeOrigin::signed(1))); + run_to(6); + assert_ok!(Salary::bump(RuntimeOrigin::signed(1))); + assert_ok!(Salary::register(RuntimeOrigin::signed(1))); + run_to(7); + assert_ok!(Salary::payout(RuntimeOrigin::signed(1))); + + // Payment failed. + unpay(1, 1); + set_status(0, PaymentStatus::Failure); + + assert_eq!(paid(1), 0); + assert_eq!(Salary::status().unwrap().total_unregistered_paid, 0); + + assert_noop!(Salary::payout(RuntimeOrigin::signed(1)), Error::::NoClaim); + // Check status. + assert_ok!(Salary::check_payment(RuntimeOrigin::signed(1))); + // Allowed to try again. + assert_ok!(Salary::payout(RuntimeOrigin::signed(1))); + + assert_eq!(paid(1), 1); + assert_eq!(Salary::status().unwrap().total_unregistered_paid, 0); + }); +} + +#[test] +fn retry_payment_later_is_not_allowed() { + new_test_ext().execute_with(|| { + set_rank(1, 1); + assert_ok!(Salary::init(RuntimeOrigin::signed(1))); + assert_ok!(Salary::induct(RuntimeOrigin::signed(1))); + run_to(6); + assert_ok!(Salary::bump(RuntimeOrigin::signed(1))); + run_to(7); + assert_ok!(Salary::payout(RuntimeOrigin::signed(1))); + + // Payment failed. + unpay(1, 1); + set_status(0, PaymentStatus::Failure); + + assert_eq!(paid(1), 0); + assert_eq!(Salary::status().unwrap().total_unregistered_paid, 1); + + // Can't just retry. + assert_noop!(Salary::payout(RuntimeOrigin::signed(1)), Error::::NoClaim); + + // Next cycle. + run_to(9); + assert_ok!(Salary::bump(RuntimeOrigin::signed(1))); + + // Payment did fail but now too late to retry. + assert_noop!(Salary::check_payment(RuntimeOrigin::signed(1)), Error::::NotCurrent); + + // We do get this cycle's payout, but we must wait for the payout period to start. + assert_noop!(Salary::payout(RuntimeOrigin::signed(1)), Error::::TooEarly); + + run_to(11); + assert_ok!(Salary::payout(RuntimeOrigin::signed(1))); + assert_eq!(paid(1), 1); + assert_eq!(Salary::status().unwrap().total_unregistered_paid, 1); + assert_noop!(Salary::payout(RuntimeOrigin::signed(1)), Error::::NoClaim); + }); +} + +#[test] +fn retry_payment_later_without_bump_is_allowed() { + new_test_ext().execute_with(|| { + set_rank(1, 1); + assert_ok!(Salary::init(RuntimeOrigin::signed(1))); + assert_ok!(Salary::induct(RuntimeOrigin::signed(1))); + run_to(6); + assert_ok!(Salary::bump(RuntimeOrigin::signed(1))); + run_to(7); + assert_ok!(Salary::payout(RuntimeOrigin::signed(1))); + + // Payment failed. + unpay(1, 1); + set_status(0, PaymentStatus::Failure); + + // Next cycle. + run_to(9); + + // Payment did fail but we can still retry as long as we don't `bump`. + assert_ok!(Salary::check_payment(RuntimeOrigin::signed(1))); + assert_ok!(Salary::payout(RuntimeOrigin::signed(1))); + + assert_eq!(paid(1), 1); + assert_eq!(Salary::status().unwrap().total_unregistered_paid, 1); + }); +} + +#[test] +fn retry_payment_to_other_works() { + new_test_ext().execute_with(|| { + set_rank(1, 1); + assert_ok!(Salary::init(RuntimeOrigin::signed(1))); + assert_ok!(Salary::induct(RuntimeOrigin::signed(1))); + run_to(6); + assert_ok!(Salary::bump(RuntimeOrigin::signed(1))); + run_to(7); + assert_ok!(Salary::payout_other(RuntimeOrigin::signed(1), 10)); + + // Payment failed. + unpay(10, 1); + set_status(0, PaymentStatus::Failure); + + // Can't just retry. + assert_noop!(Salary::payout_other(RuntimeOrigin::signed(1), 10), Error::::NoClaim); + // Check status. + assert_ok!(Salary::check_payment(RuntimeOrigin::signed(1))); + // Allowed to try again. + assert_ok!(Salary::payout_other(RuntimeOrigin::signed(1), 10)); + + assert_eq!(paid(10), 1); + assert_eq!(Salary::status().unwrap().total_unregistered_paid, 1); + + assert_noop!(Salary::payout_other(RuntimeOrigin::signed(1), 10), Error::::NoClaim); + run_to(8); + assert_noop!(Salary::bump(RuntimeOrigin::signed(1)), Error::::NotYet); + run_to(9); + assert_ok!(Salary::bump(RuntimeOrigin::signed(1))); + run_to(11); + assert_ok!(Salary::payout(RuntimeOrigin::signed(1))); + assert_eq!(paid(1), 1); + assert_eq!(paid(10), 1); + assert_eq!(Salary::status().unwrap().total_unregistered_paid, 1); + }); +} + +#[test] +fn registered_payment_works() { + new_test_ext().execute_with(|| { + set_rank(1, 1); + assert_noop!(Salary::induct(RuntimeOrigin::signed(1)), Error::::NotStarted); + assert_ok!(Salary::init(RuntimeOrigin::signed(1))); + assert_noop!(Salary::payout(RuntimeOrigin::signed(1)), Error::::NotInducted); + assert_ok!(Salary::induct(RuntimeOrigin::signed(1))); + // No claim on the cycle active during induction. + assert_noop!(Salary::register(RuntimeOrigin::signed(1)), Error::::NoClaim); + run_to(3); + assert_noop!(Salary::payout(RuntimeOrigin::signed(1)), Error::::NoClaim); + + run_to(5); + assert_ok!(Salary::bump(RuntimeOrigin::signed(1))); + assert_ok!(Salary::register(RuntimeOrigin::signed(1))); + assert_eq!(Salary::status().unwrap().total_registrations, 1); + run_to(7); + assert_ok!(Salary::payout(RuntimeOrigin::signed(1))); + assert_eq!(paid(1), 1); + assert_eq!(Salary::status().unwrap().total_unregistered_paid, 0); + assert_noop!(Salary::payout(RuntimeOrigin::signed(1)), Error::::NoClaim); + + run_to(9); + assert_ok!(Salary::bump(RuntimeOrigin::signed(1))); + assert_eq!(Salary::status().unwrap().total_registrations, 0); + assert_ok!(Salary::register(RuntimeOrigin::signed(1))); + assert_eq!(Salary::status().unwrap().total_registrations, 1); + run_to(11); + assert_ok!(Salary::payout(RuntimeOrigin::signed(1))); + assert_eq!(paid(1), 2); + assert_eq!(Salary::status().unwrap().total_unregistered_paid, 0); + }); +} + +#[test] +fn zero_payment_fails() { + new_test_ext().execute_with(|| { + assert_ok!(Salary::init(RuntimeOrigin::signed(1))); + set_rank(1, 0); + assert_ok!(Salary::induct(RuntimeOrigin::signed(1))); + run_to(7); + assert_ok!(Salary::bump(RuntimeOrigin::signed(1))); + assert_noop!(Salary::payout(RuntimeOrigin::signed(1)), Error::::ClaimZero); + }); +} + +#[test] +fn unregistered_bankrupcy_fails_gracefully() { + new_test_ext().execute_with(|| { + assert_ok!(Salary::init(RuntimeOrigin::signed(1))); + set_rank(1, 2); + set_rank(2, 6); + set_rank(3, 12); + + assert_ok!(Salary::induct(RuntimeOrigin::signed(1))); + assert_ok!(Salary::induct(RuntimeOrigin::signed(2))); + assert_ok!(Salary::induct(RuntimeOrigin::signed(3))); + + run_to(7); + assert_ok!(Salary::bump(RuntimeOrigin::signed(1))); + assert_ok!(Salary::payout(RuntimeOrigin::signed(1))); + assert_ok!(Salary::payout(RuntimeOrigin::signed(2))); + assert_ok!(Salary::payout(RuntimeOrigin::signed(3))); + + assert_eq!(paid(1), 2); + assert_eq!(paid(2), 6); + assert_eq!(paid(3), 2); + }); +} + +#[test] +fn registered_bankrupcy_fails_gracefully() { + new_test_ext().execute_with(|| { + assert_ok!(Salary::init(RuntimeOrigin::signed(1))); + set_rank(1, 2); + set_rank(2, 6); + set_rank(3, 12); + + assert_ok!(Salary::induct(RuntimeOrigin::signed(1))); + assert_ok!(Salary::induct(RuntimeOrigin::signed(2))); + assert_ok!(Salary::induct(RuntimeOrigin::signed(3))); + + run_to(5); + assert_ok!(Salary::bump(RuntimeOrigin::signed(1))); + assert_ok!(Salary::register(RuntimeOrigin::signed(1))); + assert_ok!(Salary::register(RuntimeOrigin::signed(2))); + assert_ok!(Salary::register(RuntimeOrigin::signed(3))); + + run_to(7); + assert_ok!(Salary::payout(RuntimeOrigin::signed(1))); + assert_ok!(Salary::payout(RuntimeOrigin::signed(2))); + assert_ok!(Salary::payout(RuntimeOrigin::signed(3))); + + assert_eq!(paid(1), 1); + assert_eq!(paid(2), 3); + assert_eq!(paid(3), 6); + }); +} + +#[test] +fn mixed_bankrupcy_fails_gracefully() { + new_test_ext().execute_with(|| { + assert_ok!(Salary::init(RuntimeOrigin::signed(1))); + set_rank(1, 2); + set_rank(2, 6); + set_rank(3, 12); + + assert_ok!(Salary::induct(RuntimeOrigin::signed(1))); + assert_ok!(Salary::induct(RuntimeOrigin::signed(2))); + assert_ok!(Salary::induct(RuntimeOrigin::signed(3))); + + run_to(5); + assert_ok!(Salary::bump(RuntimeOrigin::signed(1))); + assert_ok!(Salary::register(RuntimeOrigin::signed(1))); + assert_ok!(Salary::register(RuntimeOrigin::signed(2))); + + run_to(7); + assert_ok!(Salary::payout(RuntimeOrigin::signed(3))); + assert_ok!(Salary::payout(RuntimeOrigin::signed(2))); + assert_ok!(Salary::payout(RuntimeOrigin::signed(1))); + + assert_eq!(paid(1), 2); + assert_eq!(paid(2), 6); + assert_eq!(paid(3), 2); + }); +} + +#[test] +fn other_mixed_bankrupcy_fails_gracefully() { + new_test_ext().execute_with(|| { + assert_ok!(Salary::init(RuntimeOrigin::signed(1))); + set_rank(1, 2); + set_rank(2, 6); + set_rank(3, 12); + + assert_ok!(Salary::induct(RuntimeOrigin::signed(1))); + assert_ok!(Salary::induct(RuntimeOrigin::signed(2))); + assert_ok!(Salary::induct(RuntimeOrigin::signed(3))); + + run_to(5); + assert_ok!(Salary::bump(RuntimeOrigin::signed(1))); + assert_ok!(Salary::register(RuntimeOrigin::signed(2))); + assert_ok!(Salary::register(RuntimeOrigin::signed(3))); + + run_to(7); + assert_noop!(Salary::payout(RuntimeOrigin::signed(1)), Error::::ClaimZero); + assert_ok!(Salary::payout(RuntimeOrigin::signed(2))); + assert_ok!(Salary::payout(RuntimeOrigin::signed(3))); + + assert_eq!(paid(1), 0); + assert_eq!(paid(2), 3); + assert_eq!(paid(3), 6); + }); +} diff --git a/frame/salary/src/weights.rs b/frame/salary/src/weights.rs new file mode 100644 index 0000000000000..f678d086dfcd9 --- /dev/null +++ b/frame/salary/src/weights.rs @@ -0,0 +1,276 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for pallet_salary +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-02-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 + +// Executed Command: +// target/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_salary +// --chain=dev +// --header=./HEADER-APACHE2 +// --output=./frame/salary/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_salary. +pub trait WeightInfo { + fn init() -> Weight; + fn bump() -> Weight; + fn induct() -> Weight; + fn register() -> Weight; + fn payout() -> Weight; + fn payout_other() -> Weight; + fn check_payment() -> Weight; +} + +/// Weights for pallet_salary using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + /// Storage: Salary Status (r:1 w:1) + /// Proof: Salary Status (max_values: Some(1), max_size: Some(56), added: 551, mode: MaxEncodedLen) + fn init() -> Weight { + // Proof Size summary in bytes: + // Measured: `1120` + // Estimated: `551` + // Minimum execution time: 21_058 nanoseconds. + Weight::from_ref_time(21_381_000) + .saturating_add(Weight::from_proof_size(551)) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Salary Status (r:1 w:1) + /// Proof: Salary Status (max_values: Some(1), max_size: Some(56), added: 551, mode: MaxEncodedLen) + fn bump() -> Weight { + // Proof Size summary in bytes: + // Measured: `1234` + // Estimated: `551` + // Minimum execution time: 22_272 nanoseconds. + Weight::from_ref_time(22_923_000) + .saturating_add(Weight::from_proof_size(551)) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Salary Status (r:1 w:0) + /// Proof: Salary Status (max_values: Some(1), max_size: Some(56), added: 551, mode: MaxEncodedLen) + /// Storage: RankedCollective Members (r:1 w:0) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: Salary Claimant (r:1 w:1) + /// Proof: Salary Claimant (max_values: None, max_size: Some(78), added: 2553, mode: MaxEncodedLen) + fn induct() -> Weight { + // Proof Size summary in bytes: + // Measured: `1510` + // Estimated: `5621` + // Minimum execution time: 32_223 nanoseconds. + Weight::from_ref_time(32_663_000) + .saturating_add(Weight::from_proof_size(5621)) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: RankedCollective Members (r:1 w:0) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: Salary Status (r:1 w:1) + /// Proof: Salary Status (max_values: Some(1), max_size: Some(56), added: 551, mode: MaxEncodedLen) + /// Storage: Salary Claimant (r:1 w:1) + /// Proof: Salary Claimant (max_values: None, max_size: Some(78), added: 2553, mode: MaxEncodedLen) + fn register() -> Weight { + // Proof Size summary in bytes: + // Measured: `1616` + // Estimated: `5621` + // Minimum execution time: 38_279 nanoseconds. + Weight::from_ref_time(38_996_000) + .saturating_add(Weight::from_proof_size(5621)) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: Salary Status (r:1 w:1) + /// Proof: Salary Status (max_values: Some(1), max_size: Some(56), added: 551, mode: MaxEncodedLen) + /// Storage: Salary Claimant (r:1 w:1) + /// Proof: Salary Claimant (max_values: None, max_size: Some(78), added: 2553, mode: MaxEncodedLen) + /// Storage: RankedCollective Members (r:1 w:0) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + fn payout() -> Weight { + // Proof Size summary in bytes: + // Measured: `2241` + // Estimated: `5621` + // Minimum execution time: 68_868 nanoseconds. + Weight::from_ref_time(70_160_000) + .saturating_add(Weight::from_proof_size(5621)) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: Salary Status (r:1 w:1) + /// Proof: Salary Status (max_values: Some(1), max_size: Some(56), added: 551, mode: MaxEncodedLen) + /// Storage: Salary Claimant (r:1 w:1) + /// Proof: Salary Claimant (max_values: None, max_size: Some(78), added: 2553, mode: MaxEncodedLen) + /// Storage: RankedCollective Members (r:1 w:0) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + fn payout_other() -> Weight { + // Proof Size summary in bytes: + // Measured: `2189` + // Estimated: `8224` + // Minimum execution time: 68_804 nanoseconds. + Weight::from_ref_time(69_223_000) + .saturating_add(Weight::from_proof_size(8224)) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: Salary Status (r:1 w:1) + /// Proof: Salary Status (max_values: Some(1), max_size: Some(56), added: 551, mode: MaxEncodedLen) + /// Storage: Salary Claimant (r:1 w:1) + /// Proof: Salary Claimant (max_values: None, max_size: Some(78), added: 2553, mode: MaxEncodedLen) + fn check_payment() -> Weight { + // Proof Size summary in bytes: + // Measured: `880` + // Estimated: `3104` + // Minimum execution time: 19_027 nanoseconds. + Weight::from_ref_time(19_360_000) + .saturating_add(Weight::from_proof_size(3104)) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } +} + +// For backwards compatibility and tests +impl WeightInfo for () { + /// Storage: Salary Status (r:1 w:1) + /// Proof: Salary Status (max_values: Some(1), max_size: Some(56), added: 551, mode: MaxEncodedLen) + fn init() -> Weight { + // Proof Size summary in bytes: + // Measured: `1120` + // Estimated: `551` + // Minimum execution time: 21_058 nanoseconds. + Weight::from_ref_time(21_381_000) + .saturating_add(Weight::from_proof_size(551)) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Salary Status (r:1 w:1) + /// Proof: Salary Status (max_values: Some(1), max_size: Some(56), added: 551, mode: MaxEncodedLen) + fn bump() -> Weight { + // Proof Size summary in bytes: + // Measured: `1234` + // Estimated: `551` + // Minimum execution time: 22_272 nanoseconds. + Weight::from_ref_time(22_923_000) + .saturating_add(Weight::from_proof_size(551)) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Salary Status (r:1 w:0) + /// Proof: Salary Status (max_values: Some(1), max_size: Some(56), added: 551, mode: MaxEncodedLen) + /// Storage: RankedCollective Members (r:1 w:0) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: Salary Claimant (r:1 w:1) + /// Proof: Salary Claimant (max_values: None, max_size: Some(78), added: 2553, mode: MaxEncodedLen) + fn induct() -> Weight { + // Proof Size summary in bytes: + // Measured: `1510` + // Estimated: `5621` + // Minimum execution time: 32_223 nanoseconds. + Weight::from_ref_time(32_663_000) + .saturating_add(Weight::from_proof_size(5621)) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: RankedCollective Members (r:1 w:0) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: Salary Status (r:1 w:1) + /// Proof: Salary Status (max_values: Some(1), max_size: Some(56), added: 551, mode: MaxEncodedLen) + /// Storage: Salary Claimant (r:1 w:1) + /// Proof: Salary Claimant (max_values: None, max_size: Some(78), added: 2553, mode: MaxEncodedLen) + fn register() -> Weight { + // Proof Size summary in bytes: + // Measured: `1616` + // Estimated: `5621` + // Minimum execution time: 38_279 nanoseconds. + Weight::from_ref_time(38_996_000) + .saturating_add(Weight::from_proof_size(5621)) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: Salary Status (r:1 w:1) + /// Proof: Salary Status (max_values: Some(1), max_size: Some(56), added: 551, mode: MaxEncodedLen) + /// Storage: Salary Claimant (r:1 w:1) + /// Proof: Salary Claimant (max_values: None, max_size: Some(78), added: 2553, mode: MaxEncodedLen) + /// Storage: RankedCollective Members (r:1 w:0) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + fn payout() -> Weight { + // Proof Size summary in bytes: + // Measured: `2241` + // Estimated: `5621` + // Minimum execution time: 68_868 nanoseconds. + Weight::from_ref_time(70_160_000) + .saturating_add(Weight::from_proof_size(5621)) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: Salary Status (r:1 w:1) + /// Proof: Salary Status (max_values: Some(1), max_size: Some(56), added: 551, mode: MaxEncodedLen) + /// Storage: Salary Claimant (r:1 w:1) + /// Proof: Salary Claimant (max_values: None, max_size: Some(78), added: 2553, mode: MaxEncodedLen) + /// Storage: RankedCollective Members (r:1 w:0) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + fn payout_other() -> Weight { + // Proof Size summary in bytes: + // Measured: `2189` + // Estimated: `8224` + // Minimum execution time: 68_804 nanoseconds. + Weight::from_ref_time(69_223_000) + .saturating_add(Weight::from_proof_size(8224)) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: Salary Status (r:1 w:1) + /// Proof: Salary Status (max_values: Some(1), max_size: Some(56), added: 551, mode: MaxEncodedLen) + /// Storage: Salary Claimant (r:1 w:1) + /// Proof: Salary Claimant (max_values: None, max_size: Some(78), added: 2553, mode: MaxEncodedLen) + fn check_payment() -> Weight { + // Proof Size summary in bytes: + // Measured: `880` + // Estimated: `3104` + // Minimum execution time: 19_027 nanoseconds. + Weight::from_ref_time(19_360_000) + .saturating_add(Weight::from_proof_size(3104)) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } +} diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index da8efe6afc483..4b92cfbaee69c 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -36,7 +36,7 @@ pub use members::{AllowAll, DenyAll, Filter}; pub use members::{ AsContains, ChangeMembers, Contains, ContainsLengthBound, ContainsPair, Everything, EverythingBut, FromContainsPair, InitializeMembers, InsideBoth, IsInVec, Nothing, - SortedMembers, TheseExcept, + RankedMembers, SortedMembers, TheseExcept, }; mod validation; diff --git a/frame/support/src/traits/members.rs b/frame/support/src/traits/members.rs index f336b460c8f1e..fbba742ebeb43 100644 --- a/frame/support/src/traits/members.rs +++ b/frame/support/src/traits/members.rs @@ -18,6 +18,8 @@ //! Traits for dealing with the idea of membership. use impl_trait_for_tuples::impl_for_tuples; +use sp_arithmetic::traits::AtLeast16BitUnsigned; +use sp_runtime::DispatchResult; use sp_std::{marker::PhantomData, prelude::*}; /// A trait for querying whether a type can be said to "contain" a value. @@ -265,6 +267,28 @@ pub trait ContainsLengthBound { fn max_len() -> usize; } +/// Ranked membership data structure. +pub trait RankedMembers { + type AccountId; + type Rank: AtLeast16BitUnsigned; + + /// The lowest rank possible in this membership organisation. + fn min_rank() -> Self::Rank; + + /// Return the rank of the given ID, or `None` if they are not a member. + fn rank_of(who: &Self::AccountId) -> Option; + + /// Add a member to the group at the `min_rank()`. + fn induct(who: &Self::AccountId) -> DispatchResult; + + /// Promote a member to the next higher rank. + fn promote(who: &Self::AccountId) -> DispatchResult; + + /// Demote a member to the next lower rank; demoting beyond the `min_rank` removes the + /// member entirely. + fn demote(who: &Self::AccountId) -> DispatchResult; +} + /// Trait for type that can handle the initialization of account IDs at genesis. pub trait InitializeMembers { /// Initialize the members to the given `members`. diff --git a/frame/support/src/traits/tokens.rs b/frame/support/src/traits/tokens.rs index 6055fde2180f0..f8dcf68159f1a 100644 --- a/frame/support/src/traits/tokens.rs +++ b/frame/support/src/traits/tokens.rs @@ -28,6 +28,7 @@ pub mod nonfungibles; pub mod nonfungibles_v2; pub use imbalance::Imbalance; pub use misc::{ - AssetId, AttributeNamespace, Balance, BalanceConversion, BalanceStatus, DepositConsequence, - ExistenceRequirement, Locker, WithdrawConsequence, WithdrawReasons, + AssetId, AttributeNamespace, Balance, BalanceConversion, BalanceStatus, ConvertRank, + DepositConsequence, ExistenceRequirement, GetSalary, Locker, WithdrawConsequence, + WithdrawReasons, }; diff --git a/frame/support/src/traits/tokens/misc.rs b/frame/support/src/traits/tokens/misc.rs index b4bd4640116a7..eff65f3620a32 100644 --- a/frame/support/src/traits/tokens/misc.rs +++ b/frame/support/src/traits/tokens/misc.rs @@ -20,7 +20,7 @@ use codec::{Decode, Encode, FullCodec, MaxEncodedLen}; use sp_arithmetic::traits::{AtLeast32BitUnsigned, Zero}; use sp_core::RuntimeDebug; -use sp_runtime::{ArithmeticError, DispatchError, TokenError}; +use sp_runtime::{traits::Convert, ArithmeticError, DispatchError, TokenError}; use sp_std::fmt::Debug; /// One of a number of consequences of withdrawing a fungible from an account. @@ -225,3 +225,18 @@ impl Locker for () { false } } + +/// Retrieve the salary for a member of a particular rank. +pub trait GetSalary { + /// Retrieve the salary for a given rank. The account ID is also supplied in case this changes + /// things. + fn get_salary(rank: Rank, who: &AccountId) -> Balance; +} + +/// Adapter for a rank-to-salary `Convert` implementation into a `GetSalary` implementation. +pub struct ConvertRank(sp_std::marker::PhantomData); +impl> GetSalary for ConvertRank { + fn get_salary(rank: R, _: &A) -> B { + C::convert(rank) + } +} diff --git a/primitives/arithmetic/src/traits.rs b/primitives/arithmetic/src/traits.rs index 91e13a832ea08..84e3f60aa6a7d 100644 --- a/primitives/arithmetic/src/traits.rs +++ b/primitives/arithmetic/src/traits.rs @@ -148,6 +148,20 @@ impl< { } +/// A meta trait for arithmetic. +/// +/// Arithmetic types do all the usual stuff you'd expect numbers to do. They are guaranteed to +/// be able to represent at least `u16` values without loss, hence the trait implies `From` +/// and smaller integers. All other conversions are fallible. +pub trait AtLeast16Bit: BaseArithmetic + From {} + +impl> AtLeast16Bit for T {} + +/// A meta trait for arithmetic. Same as [`AtLeast16Bit `], but also bounded to be unsigned. +pub trait AtLeast16BitUnsigned: AtLeast16Bit + Unsigned {} + +impl AtLeast16BitUnsigned for T {} + /// A meta trait for arithmetic. /// /// Arithmetic types do all the usual stuff you'd expect numbers to do. They are guaranteed to From e923511e15ec5000acb2a44d3764020ea71b109d Mon Sep 17 00:00:00 2001 From: Sergej Sakac <73715684+Szegoo@users.noreply.github.com> Date: Fri, 3 Mar 2023 21:39:45 +0100 Subject: [PATCH 466/715] Assets pallet: Don't allow `set_min_balance` when sufficient (#13510) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Assets pallet: Don't allow set_min_balance when sufficient * fix * fix benchmark * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_assets * Update frame/assets/src/lib.rs * fix * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_assets --------- Co-authored-by: command-bot <> Co-authored-by: Bastian Köcher --- frame/assets/src/benchmarking.rs | 2 +- frame/assets/src/lib.rs | 8 +- frame/assets/src/tests.rs | 44 ++++- frame/assets/src/weights.rs | 304 +++++++++++++------------------ 4 files changed, 169 insertions(+), 189 deletions(-) diff --git a/frame/assets/src/benchmarking.rs b/frame/assets/src/benchmarking.rs index 0538e955b2c09..5b4f1489df5db 100644 --- a/frame/assets/src/benchmarking.rs +++ b/frame/assets/src/benchmarking.rs @@ -472,7 +472,7 @@ benchmarks_instance_pallet! { } set_min_balance { - let (asset_id, caller, caller_lookup) = create_default_asset::(true); + let (asset_id, caller, caller_lookup) = create_default_asset::(false); }: _(SystemOrigin::Signed(caller.clone()), asset_id, 50u32.into()) verify { assert_last_event::(Event::AssetMinBalanceChanged { asset_id: asset_id.into(), new_min_balance: 50u32.into() }.into()); diff --git a/frame/assets/src/lib.rs b/frame/assets/src/lib.rs index 96da078065839..662c20e00fb1a 100644 --- a/frame/assets/src/lib.rs +++ b/frame/assets/src/lib.rs @@ -1540,8 +1540,12 @@ pub mod pallet { ensure!(origin == details.owner, Error::::NoPermission); let old_min_balance = details.min_balance; - // Ensure that either the new min_balance is less than old min_balance or there aren't - // any accounts holding the asset. + // If the asset is marked as sufficient it won't be allowed to + // change the min_balance. + ensure!(!details.is_sufficient, Error::::NoPermission); + + // Ensure that either the new min_balance is less than old + // min_balance or there aren't any accounts holding the asset. ensure!( min_balance < old_min_balance || details.accounts == 0, Error::::NoPermission diff --git a/frame/assets/src/tests.rs b/frame/assets/src/tests.rs index e0f612e5cd781..a2788f7f4a9aa 100644 --- a/frame/assets/src/tests.rs +++ b/frame/assets/src/tests.rs @@ -1101,23 +1101,53 @@ fn set_min_balance_should_work() { Balances::make_free_balance_be(&1, 10); assert_ok!(Assets::create(RuntimeOrigin::signed(1), id, 1, 30)); - assert_ok!(Assets::mint(RuntimeOrigin::signed(1), id, 1, 50)); - // won't execute because there is an asset holder. + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), id, 1, 100)); + // Won't execute because there is an asset holder. assert_noop!( Assets::set_min_balance(RuntimeOrigin::signed(1), id, 50), Error::::NoPermission ); - // will execute because the new value of min_balance is less than the - // old value. 10 < 30 - assert_ok!(Assets::mint(RuntimeOrigin::signed(1), id, 1, 10)); + // Force asset status to make this a sufficient asset. + assert_ok!(Assets::force_asset_status( + RuntimeOrigin::root(), + id, + 1, + 1, + 1, + 1, + 30, + true, + false + )); - assert_ok!(Assets::burn(RuntimeOrigin::signed(1), id, 1, 50)); + // Won't execute because there is an account holding the asset and the asset is marked as + // sufficient. assert_noop!( - Assets::set_min_balance(RuntimeOrigin::signed(2), id, 50), + Assets::set_min_balance(RuntimeOrigin::signed(1), id, 10), Error::::NoPermission ); + // Make the asset not sufficient. + assert_ok!(Assets::force_asset_status( + RuntimeOrigin::root(), + id, + 1, + 1, + 1, + 1, + 60, + false, + false + )); + + // Will execute because the new value of min_balance is less than the + // old value. 10 < 30 + assert_ok!(Assets::set_min_balance(RuntimeOrigin::signed(1), id, 10)); + assert_eq!(Asset::::get(id).unwrap().min_balance, 10); + + assert_ok!(Assets::burn(RuntimeOrigin::signed(1), id, 1, 100)); + assert_ok!(Assets::set_min_balance(RuntimeOrigin::signed(1), id, 50)); assert_eq!(Asset::::get(id).unwrap().min_balance, 50); }); diff --git a/frame/assets/src/weights.rs b/frame/assets/src/weights.rs index 080800daa6c6b..b9c3ab21d8a33 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: 2023-02-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-03, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -89,9 +89,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `325` // Estimated: `7268` - // Minimum execution time: 27_887 nanoseconds. - Weight::from_parts(28_190_000, 0) - .saturating_add(Weight::from_parts(0, 7268)) + // Minimum execution time: 28_265_000 picoseconds. + Weight::from_parts(28_764_000, 7268) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -101,9 +100,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `153` // Estimated: `3675` - // Minimum execution time: 15_059 nanoseconds. - Weight::from_parts(15_600_000, 0) - .saturating_add(Weight::from_parts(0, 3675)) + // Minimum execution time: 15_125_000 picoseconds. + Weight::from_parts(15_468_000, 3675) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -113,9 +111,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `417` // Estimated: `3675` - // Minimum execution time: 15_581 nanoseconds. - Weight::from_parts(15_868_000, 0) - .saturating_add(Weight::from_parts(0, 3675)) + // Minimum execution time: 15_368_000 picoseconds. + Weight::from_parts(15_625_000, 3675) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -130,11 +127,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `25 + c * (240 ±0)` // Estimated: `8232 + c * (5180 ±0)` - // Minimum execution time: 20_167 nanoseconds. - Weight::from_parts(20_436_000, 0) - .saturating_add(Weight::from_parts(0, 8232)) - // Standard Error: 12_761 - .saturating_add(Weight::from_parts(15_535_268, 0).saturating_mul(c.into())) + // Minimum execution time: 20_816_000 picoseconds. + Weight::from_parts(21_045_000, 8232) + // Standard Error: 7_118 + .saturating_add(Weight::from_parts(12_723_454, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(c.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) @@ -150,11 +146,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `554 + a * (86 ±0)` // Estimated: `7288 + a * (2623 ±0)` - // Minimum execution time: 20_349 nanoseconds. - Weight::from_parts(20_482_000, 0) - .saturating_add(Weight::from_parts(0, 7288)) - // Standard Error: 9_831 - .saturating_add(Weight::from_parts(15_771_918, 0).saturating_mul(a.into())) + // Minimum execution time: 20_923_000 picoseconds. + Weight::from_parts(21_229_000, 7288) + // Standard Error: 7_215 + .saturating_add(Weight::from_parts(12_915_292, 0).saturating_mul(a.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(a.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) @@ -169,9 +164,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `383` // Estimated: `7280` - // Minimum execution time: 15_647 nanoseconds. - Weight::from_parts(15_975_000, 0) - .saturating_add(Weight::from_parts(0, 7280)) + // Minimum execution time: 15_764_000 picoseconds. + Weight::from_parts(16_245_000, 7280) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -183,9 +177,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `383` // Estimated: `7242` - // Minimum execution time: 28_383 nanoseconds. - Weight::from_parts(29_055_000, 0) - .saturating_add(Weight::from_parts(0, 7242)) + // Minimum execution time: 28_814_000 picoseconds. + Weight::from_parts(29_407_000, 7242) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -197,9 +190,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `491` // Estimated: `7242` - // Minimum execution time: 34_950 nanoseconds. - Weight::from_parts(35_296_000, 0) - .saturating_add(Weight::from_parts(0, 7242)) + // Minimum execution time: 34_784_000 picoseconds. + Weight::from_parts(35_402_000, 7242) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -213,9 +205,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `530` // Estimated: `13412` - // Minimum execution time: 50_129 nanoseconds. - Weight::from_parts(50_820_000, 0) - .saturating_add(Weight::from_parts(0, 13412)) + // Minimum execution time: 49_110_000 picoseconds. + Weight::from_parts(50_483_000, 13412) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -229,9 +220,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `530` // Estimated: `13412` - // Minimum execution time: 43_424 nanoseconds. - Weight::from_parts(44_080_000, 0) - .saturating_add(Weight::from_parts(0, 13412)) + // Minimum execution time: 43_585_000 picoseconds. + Weight::from_parts(44_207_000, 13412) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -245,9 +235,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `530` // Estimated: `13412` - // Minimum execution time: 48_919 nanoseconds. - Weight::from_parts(50_720_000, 0) - .saturating_add(Weight::from_parts(0, 13412)) + // Minimum execution time: 49_238_000 picoseconds. + Weight::from_parts(77_664_000, 13412) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -259,9 +248,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `491` // Estimated: `7242` - // Minimum execution time: 19_750 nanoseconds. - Weight::from_parts(20_053_000, 0) - .saturating_add(Weight::from_parts(0, 7242)) + // Minimum execution time: 19_198_000 picoseconds. + Weight::from_parts(19_585_000, 7242) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -273,9 +261,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `491` // Estimated: `7242` - // Minimum execution time: 19_672 nanoseconds. - Weight::from_parts(19_928_000, 0) - .saturating_add(Weight::from_parts(0, 7242)) + // Minimum execution time: 19_659_000 picoseconds. + Weight::from_parts(20_079_000, 7242) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -285,9 +272,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `417` // Estimated: `3675` - // Minimum execution time: 15_367 nanoseconds. - Weight::from_parts(15_726_000, 0) - .saturating_add(Weight::from_parts(0, 3675)) + // Minimum execution time: 15_035_000 picoseconds. + Weight::from_parts(15_594_000, 3675) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -297,9 +283,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `417` // Estimated: `3675` - // Minimum execution time: 14_814 nanoseconds. - Weight::from_parts(15_301_000, 0) - .saturating_add(Weight::from_parts(0, 3675)) + // Minimum execution time: 15_073_000 picoseconds. + Weight::from_parts(15_862_000, 3675) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -311,9 +296,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `383` // Estimated: `7280` - // Minimum execution time: 17_426 nanoseconds. - Weight::from_parts(17_804_000, 0) - .saturating_add(Weight::from_parts(0, 7280)) + // Minimum execution time: 17_343_000 picoseconds. + Weight::from_parts(17_656_000, 7280) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -323,9 +307,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `383` // Estimated: `3675` - // Minimum execution time: 15_935 nanoseconds. - Weight::from_parts(16_165_000, 0) - .saturating_add(Weight::from_parts(0, 3675)) + // Minimum execution time: 15_902_000 picoseconds. + Weight::from_parts(16_439_000, 3675) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -335,15 +318,12 @@ impl WeightInfo for SubstrateWeight { /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) /// The range of component `n` is `[0, 50]`. /// The range of component `s` is `[0, 50]`. - fn set_metadata(n: u32, _s: u32, ) -> Weight { + fn set_metadata(_n: u32, _s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `383` // Estimated: `7280` - // Minimum execution time: 26_890 nanoseconds. - Weight::from_parts(28_766_510, 0) - .saturating_add(Weight::from_parts(0, 7280)) - // Standard Error: 7_444 - .saturating_add(Weight::from_parts(3_619, 0).saturating_mul(n.into())) + // Minimum execution time: 27_222_000 picoseconds. + Weight::from_parts(29_151_657, 7280) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -355,9 +335,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `579` // Estimated: `7280` - // Minimum execution time: 27_146 nanoseconds. - Weight::from_parts(27_692_000, 0) - .saturating_add(Weight::from_parts(0, 7280)) + // Minimum execution time: 27_976_000 picoseconds. + Weight::from_parts(28_289_000, 7280) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -367,13 +346,14 @@ impl WeightInfo for SubstrateWeight { /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) /// The range of component `n` is `[0, 50]`. /// The range of component `s` is `[0, 50]`. - fn force_set_metadata(_n: u32, _s: u32, ) -> Weight { + fn force_set_metadata(_n: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `190` // Estimated: `7280` - // Minimum execution time: 16_181 nanoseconds. - Weight::from_parts(18_317_178, 0) - .saturating_add(Weight::from_parts(0, 7280)) + // Minimum execution time: 16_162_000 picoseconds. + Weight::from_parts(17_137_043, 7280) + // Standard Error: 982 + .saturating_add(Weight::from_parts(4_180, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -385,9 +365,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `579` // Estimated: `7280` - // Minimum execution time: 26_962 nanoseconds. - Weight::from_parts(27_896_000, 0) - .saturating_add(Weight::from_parts(0, 7280)) + // Minimum execution time: 27_219_000 picoseconds. + Weight::from_parts(27_931_000, 7280) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -397,9 +376,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `383` // Estimated: `3675` - // Minimum execution time: 14_394 nanoseconds. - Weight::from_parts(14_917_000, 0) - .saturating_add(Weight::from_parts(0, 3675)) + // Minimum execution time: 15_313_000 picoseconds. + Weight::from_parts(15_775_000, 3675) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -411,9 +389,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `417` // Estimated: `7288` - // Minimum execution time: 30_861 nanoseconds. - Weight::from_parts(31_356_000, 0) - .saturating_add(Weight::from_parts(0, 7288)) + // Minimum execution time: 31_865_000 picoseconds. + Weight::from_parts(32_316_000, 7288) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -429,9 +406,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `700` // Estimated: `17025` - // Minimum execution time: 64_510 nanoseconds. - Weight::from_parts(65_676_000, 0) - .saturating_add(Weight::from_parts(0, 17025)) + // Minimum execution time: 67_203_000 picoseconds. + Weight::from_parts(109_742_000, 17025) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -443,9 +419,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `587` // Estimated: `7288` - // Minimum execution time: 32_620 nanoseconds. - Weight::from_parts(33_183_000, 0) - .saturating_add(Weight::from_parts(0, 7288)) + // Minimum execution time: 33_430_000 picoseconds. + Weight::from_parts(33_824_000, 7288) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -457,9 +432,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `587` // Estimated: `7288` - // Minimum execution time: 33_277 nanoseconds. - Weight::from_parts(34_438_000, 0) - .saturating_add(Weight::from_parts(0, 7288)) + // Minimum execution time: 33_596_000 picoseconds. + Weight::from_parts(34_226_000, 7288) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -469,9 +443,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `383` // Estimated: `3675` - // Minimum execution time: 16_213 nanoseconds. - Weight::from_parts(16_575_000, 0) - .saturating_add(Weight::from_parts(0, 3675)) + // Minimum execution time: 16_367_000 picoseconds. + Weight::from_parts(16_703_000, 3675) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -487,9 +460,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `325` // Estimated: `7268` - // Minimum execution time: 27_887 nanoseconds. - Weight::from_parts(28_190_000, 0) - .saturating_add(Weight::from_parts(0, 7268)) + // Minimum execution time: 28_265_000 picoseconds. + Weight::from_parts(28_764_000, 7268) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -499,9 +471,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `153` // Estimated: `3675` - // Minimum execution time: 15_059 nanoseconds. - Weight::from_parts(15_600_000, 0) - .saturating_add(Weight::from_parts(0, 3675)) + // Minimum execution time: 15_125_000 picoseconds. + Weight::from_parts(15_468_000, 3675) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -511,9 +482,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `417` // Estimated: `3675` - // Minimum execution time: 15_581 nanoseconds. - Weight::from_parts(15_868_000, 0) - .saturating_add(Weight::from_parts(0, 3675)) + // Minimum execution time: 15_368_000 picoseconds. + Weight::from_parts(15_625_000, 3675) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -528,11 +498,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `25 + c * (240 ±0)` // Estimated: `8232 + c * (5180 ±0)` - // Minimum execution time: 20_167 nanoseconds. - Weight::from_parts(20_436_000, 0) - .saturating_add(Weight::from_parts(0, 8232)) - // Standard Error: 12_761 - .saturating_add(Weight::from_parts(15_535_268, 0).saturating_mul(c.into())) + // Minimum execution time: 20_816_000 picoseconds. + Weight::from_parts(21_045_000, 8232) + // Standard Error: 7_118 + .saturating_add(Weight::from_parts(12_723_454, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(c.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) @@ -548,11 +517,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `554 + a * (86 ±0)` // Estimated: `7288 + a * (2623 ±0)` - // Minimum execution time: 20_349 nanoseconds. - Weight::from_parts(20_482_000, 0) - .saturating_add(Weight::from_parts(0, 7288)) - // Standard Error: 9_831 - .saturating_add(Weight::from_parts(15_771_918, 0).saturating_mul(a.into())) + // Minimum execution time: 20_923_000 picoseconds. + Weight::from_parts(21_229_000, 7288) + // Standard Error: 7_215 + .saturating_add(Weight::from_parts(12_915_292, 0).saturating_mul(a.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(a.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) @@ -567,9 +535,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `383` // Estimated: `7280` - // Minimum execution time: 15_647 nanoseconds. - Weight::from_parts(15_975_000, 0) - .saturating_add(Weight::from_parts(0, 7280)) + // Minimum execution time: 15_764_000 picoseconds. + Weight::from_parts(16_245_000, 7280) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -581,9 +548,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `383` // Estimated: `7242` - // Minimum execution time: 28_383 nanoseconds. - Weight::from_parts(29_055_000, 0) - .saturating_add(Weight::from_parts(0, 7242)) + // Minimum execution time: 28_814_000 picoseconds. + Weight::from_parts(29_407_000, 7242) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -595,9 +561,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `491` // Estimated: `7242` - // Minimum execution time: 34_950 nanoseconds. - Weight::from_parts(35_296_000, 0) - .saturating_add(Weight::from_parts(0, 7242)) + // Minimum execution time: 34_784_000 picoseconds. + Weight::from_parts(35_402_000, 7242) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -611,9 +576,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `530` // Estimated: `13412` - // Minimum execution time: 50_129 nanoseconds. - Weight::from_parts(50_820_000, 0) - .saturating_add(Weight::from_parts(0, 13412)) + // Minimum execution time: 49_110_000 picoseconds. + Weight::from_parts(50_483_000, 13412) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -627,9 +591,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `530` // Estimated: `13412` - // Minimum execution time: 43_424 nanoseconds. - Weight::from_parts(44_080_000, 0) - .saturating_add(Weight::from_parts(0, 13412)) + // Minimum execution time: 43_585_000 picoseconds. + Weight::from_parts(44_207_000, 13412) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -643,9 +606,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `530` // Estimated: `13412` - // Minimum execution time: 48_919 nanoseconds. - Weight::from_parts(50_720_000, 0) - .saturating_add(Weight::from_parts(0, 13412)) + // Minimum execution time: 49_238_000 picoseconds. + Weight::from_parts(77_664_000, 13412) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -657,9 +619,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `491` // Estimated: `7242` - // Minimum execution time: 19_750 nanoseconds. - Weight::from_parts(20_053_000, 0) - .saturating_add(Weight::from_parts(0, 7242)) + // Minimum execution time: 19_198_000 picoseconds. + Weight::from_parts(19_585_000, 7242) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -671,9 +632,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `491` // Estimated: `7242` - // Minimum execution time: 19_672 nanoseconds. - Weight::from_parts(19_928_000, 0) - .saturating_add(Weight::from_parts(0, 7242)) + // Minimum execution time: 19_659_000 picoseconds. + Weight::from_parts(20_079_000, 7242) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -683,9 +643,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `417` // Estimated: `3675` - // Minimum execution time: 15_367 nanoseconds. - Weight::from_parts(15_726_000, 0) - .saturating_add(Weight::from_parts(0, 3675)) + // Minimum execution time: 15_035_000 picoseconds. + Weight::from_parts(15_594_000, 3675) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -695,9 +654,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `417` // Estimated: `3675` - // Minimum execution time: 14_814 nanoseconds. - Weight::from_parts(15_301_000, 0) - .saturating_add(Weight::from_parts(0, 3675)) + // Minimum execution time: 15_073_000 picoseconds. + Weight::from_parts(15_862_000, 3675) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -709,9 +667,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `383` // Estimated: `7280` - // Minimum execution time: 17_426 nanoseconds. - Weight::from_parts(17_804_000, 0) - .saturating_add(Weight::from_parts(0, 7280)) + // Minimum execution time: 17_343_000 picoseconds. + Weight::from_parts(17_656_000, 7280) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -721,9 +678,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `383` // Estimated: `3675` - // Minimum execution time: 15_935 nanoseconds. - Weight::from_parts(16_165_000, 0) - .saturating_add(Weight::from_parts(0, 3675)) + // Minimum execution time: 15_902_000 picoseconds. + Weight::from_parts(16_439_000, 3675) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -733,15 +689,12 @@ impl WeightInfo for () { /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) /// The range of component `n` is `[0, 50]`. /// The range of component `s` is `[0, 50]`. - fn set_metadata(n: u32, _s: u32, ) -> Weight { + fn set_metadata(_n: u32, _s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `383` // Estimated: `7280` - // Minimum execution time: 26_890 nanoseconds. - Weight::from_parts(28_766_510, 0) - .saturating_add(Weight::from_parts(0, 7280)) - // Standard Error: 7_444 - .saturating_add(Weight::from_parts(3_619, 0).saturating_mul(n.into())) + // Minimum execution time: 27_222_000 picoseconds. + Weight::from_parts(29_151_657, 7280) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -753,9 +706,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `579` // Estimated: `7280` - // Minimum execution time: 27_146 nanoseconds. - Weight::from_parts(27_692_000, 0) - .saturating_add(Weight::from_parts(0, 7280)) + // Minimum execution time: 27_976_000 picoseconds. + Weight::from_parts(28_289_000, 7280) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -765,13 +717,14 @@ impl WeightInfo for () { /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) /// The range of component `n` is `[0, 50]`. /// The range of component `s` is `[0, 50]`. - fn force_set_metadata(_n: u32, _s: u32, ) -> Weight { + fn force_set_metadata(_n: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `190` // Estimated: `7280` - // Minimum execution time: 16_181 nanoseconds. - Weight::from_parts(18_317_178, 0) - .saturating_add(Weight::from_parts(0, 7280)) + // Minimum execution time: 16_162_000 picoseconds. + Weight::from_parts(17_137_043, 7280) + // Standard Error: 982 + .saturating_add(Weight::from_parts(4_180, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -783,9 +736,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `579` // Estimated: `7280` - // Minimum execution time: 26_962 nanoseconds. - Weight::from_parts(27_896_000, 0) - .saturating_add(Weight::from_parts(0, 7280)) + // Minimum execution time: 27_219_000 picoseconds. + Weight::from_parts(27_931_000, 7280) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -795,9 +747,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `383` // Estimated: `3675` - // Minimum execution time: 14_394 nanoseconds. - Weight::from_parts(14_917_000, 0) - .saturating_add(Weight::from_parts(0, 3675)) + // Minimum execution time: 15_313_000 picoseconds. + Weight::from_parts(15_775_000, 3675) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -809,9 +760,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `417` // Estimated: `7288` - // Minimum execution time: 30_861 nanoseconds. - Weight::from_parts(31_356_000, 0) - .saturating_add(Weight::from_parts(0, 7288)) + // Minimum execution time: 31_865_000 picoseconds. + Weight::from_parts(32_316_000, 7288) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -827,9 +777,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `700` // Estimated: `17025` - // Minimum execution time: 64_510 nanoseconds. - Weight::from_parts(65_676_000, 0) - .saturating_add(Weight::from_parts(0, 17025)) + // Minimum execution time: 67_203_000 picoseconds. + Weight::from_parts(109_742_000, 17025) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -841,9 +790,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `587` // Estimated: `7288` - // Minimum execution time: 32_620 nanoseconds. - Weight::from_parts(33_183_000, 0) - .saturating_add(Weight::from_parts(0, 7288)) + // Minimum execution time: 33_430_000 picoseconds. + Weight::from_parts(33_824_000, 7288) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -855,9 +803,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `587` // Estimated: `7288` - // Minimum execution time: 33_277 nanoseconds. - Weight::from_parts(34_438_000, 0) - .saturating_add(Weight::from_parts(0, 7288)) + // Minimum execution time: 33_596_000 picoseconds. + Weight::from_parts(34_226_000, 7288) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -867,9 +814,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `383` // Estimated: `3675` - // Minimum execution time: 16_213 nanoseconds. - Weight::from_parts(16_575_000, 0) - .saturating_add(Weight::from_parts(0, 3675)) + // Minimum execution time: 16_367_000 picoseconds. + Weight::from_parts(16_703_000, 3675) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } From 2520dedb5521a7fe32ee494ce608b2f0da6179b3 Mon Sep 17 00:00:00 2001 From: Javier Viola Date: Fri, 3 Mar 2023 17:46:02 -0300 Subject: [PATCH 467/715] bump `zombienet` version to v1.3.37 (#13447) * bump zombienet version to v1.3.35 * remove checks, since now is checked by zn * Update .gitlab-ci.yml --------- Co-authored-by: Anton --- .gitlab-ci.yml | 2 +- zombienet/0000-block-building/block-building.zndsl | 3 --- zombienet/0001-basic-warp-sync/test-warp-sync.zndsl | 5 ----- .../test-validators-warp-sync.zndsl | 6 ------ .../test-block-building-warp-sync.zndsl | 5 ----- 5 files changed, 1 insertion(+), 20 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 336e97cdd4433..94fb3c608b771 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -55,7 +55,7 @@ variables: RUSTY_CACHIER_COMPRESSION_METHOD: zstd NEXTEST_FAILURE_OUTPUT: immediate-final NEXTEST_SUCCESS_OUTPUT: final - ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.3.34" + ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.3.37" .shared-default: &shared-default retry: diff --git a/zombienet/0000-block-building/block-building.zndsl b/zombienet/0000-block-building/block-building.zndsl index 86a54773484b3..6ad5f3d89fda5 100644 --- a/zombienet/0000-block-building/block-building.zndsl +++ b/zombienet/0000-block-building/block-building.zndsl @@ -2,9 +2,6 @@ Description: Block building Network: ./block-building.toml Creds: config -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 8ceb61c8b039d..dc84804b70b02 100644 --- a/zombienet/0001-basic-warp-sync/test-warp-sync.zndsl +++ b/zombienet/0001-basic-warp-sync/test-warp-sync.zndsl @@ -2,11 +2,6 @@ Description: Warp sync Network: ./test-warp-sync.toml Creds: config -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 charlie: reports node_roles is 1 diff --git a/zombienet/0002-validators-warp-sync/test-validators-warp-sync.zndsl b/zombienet/0002-validators-warp-sync/test-validators-warp-sync.zndsl index 2110d6373fa2c..05c458fbf4b79 100644 --- a/zombienet/0002-validators-warp-sync/test-validators-warp-sync.zndsl +++ b/zombienet/0002-validators-warp-sync/test-validators-warp-sync.zndsl @@ -2,12 +2,6 @@ Description: Warp sync Network: ./test-validators-warp-sync.toml Creds: config -alice: is up within 30 seconds -bob: is up within 30 seconds -charlie: is up within 30 seconds -dave: is up within 30 seconds -eve: is up within 30 seconds - alice: reports node_roles is 4 bob: reports node_roles is 4 charlie: reports node_roles is 1 diff --git a/zombienet/0003-block-building-warp-sync/test-block-building-warp-sync.zndsl b/zombienet/0003-block-building-warp-sync/test-block-building-warp-sync.zndsl index 441fa45a88003..a4ba46017a3f7 100644 --- a/zombienet/0003-block-building-warp-sync/test-block-building-warp-sync.zndsl +++ b/zombienet/0003-block-building-warp-sync/test-block-building-warp-sync.zndsl @@ -2,11 +2,6 @@ Description: Warp sync Network: ./test-block-building-warp-sync.toml Creds: config -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 4 bob: reports node_roles is 4 charlie: reports node_roles is 1 From c2034a822bdb423bfee5f077a4c40f1c2c797f85 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Sat, 4 Mar 2023 11:38:22 +0000 Subject: [PATCH 468/715] Just a typo (#13533) * Typo * Update Salary weight Signed-off-by: Oliver Tale-Yazdi * Fix test Signed-off-by: Oliver Tale-Yazdi --------- Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Oliver Tale-Yazdi --- frame/message-queue/src/lib.rs | 2 +- frame/salary/src/tests.rs | 2 +- frame/salary/src/weights.rs | 141 +++++++++++++++------------------ 3 files changed, 65 insertions(+), 80 deletions(-) diff --git a/frame/message-queue/src/lib.rs b/frame/message-queue/src/lib.rs index 6c264be3c834e..409503d31725a 100644 --- a/frame/message-queue/src/lib.rs +++ b/frame/message-queue/src/lib.rs @@ -56,7 +56,7 @@ //! **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 +//! in a lot of complexity when implementing the pallet but is completely necessary to achieve 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 diff --git a/frame/salary/src/tests.rs b/frame/salary/src/tests.rs index 8649291225bc3..e54b9612b152c 100644 --- a/frame/salary/src/tests.rs +++ b/frame/salary/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(Weight::from_ref_time(1_000_000)); + frame_system::limits::BlockWeights::simple_max(Weight::from_parts(1_000_000, 0)); } impl frame_system::Config for Test { type BaseCallFilter = Everything; diff --git a/frame/salary/src/weights.rs b/frame/salary/src/weights.rs index f678d086dfcd9..6b43c58b6038c 100644 --- a/frame/salary/src/weights.rs +++ b/frame/salary/src/weights.rs @@ -18,27 +18,26 @@ //! Autogenerated weights for pallet_salary //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-03, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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 // --steps=50 // --repeat=20 // --extrinsic=* +// --pallet=pallet_salary // --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_salary // --chain=dev -// --header=./HEADER-APACHE2 -// --output=./frame/salary/src/weights.rs -// --template=./.maintain/frame-weight-template.hbs +// --header=HEADER-APACHE2 +// --output=frame/salary/src/weights.rs +// --template=.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -65,11 +64,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Salary Status (max_values: Some(1), max_size: Some(56), added: 551, mode: MaxEncodedLen) fn init() -> Weight { // Proof Size summary in bytes: - // Measured: `1120` - // Estimated: `551` - // Minimum execution time: 21_058 nanoseconds. - Weight::from_ref_time(21_381_000) - .saturating_add(Weight::from_proof_size(551)) + // Measured: `4` + // Estimated: `1541` + // Minimum execution time: 11_793_000 picoseconds. + Weight::from_parts(12_080_000, 1541) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -77,11 +75,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Salary Status (max_values: Some(1), max_size: Some(56), added: 551, mode: MaxEncodedLen) fn bump() -> Weight { // Proof Size summary in bytes: - // Measured: `1234` - // Estimated: `551` - // Minimum execution time: 22_272 nanoseconds. - Weight::from_ref_time(22_923_000) - .saturating_add(Weight::from_proof_size(551)) + // Measured: `118` + // Estimated: `1541` + // Minimum execution time: 12_799_000 picoseconds. + Weight::from_parts(13_343_000, 1541) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -93,11 +90,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Salary Claimant (max_values: None, max_size: Some(78), added: 2553, mode: MaxEncodedLen) fn induct() -> Weight { // Proof Size summary in bytes: - // Measured: `1510` - // Estimated: `5621` - // Minimum execution time: 32_223 nanoseconds. - Weight::from_ref_time(32_663_000) - .saturating_add(Weight::from_proof_size(5621)) + // Measured: `394` + // Estimated: `8591` + // Minimum execution time: 20_299_000 picoseconds. + Weight::from_parts(20_664_000, 8591) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -109,11 +105,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Salary Claimant (max_values: None, max_size: Some(78), added: 2553, mode: MaxEncodedLen) fn register() -> Weight { // Proof Size summary in bytes: - // Measured: `1616` - // Estimated: `5621` - // Minimum execution time: 38_279 nanoseconds. - Weight::from_ref_time(38_996_000) - .saturating_add(Weight::from_proof_size(5621)) + // Measured: `461` + // Estimated: `8591` + // Minimum execution time: 24_195_000 picoseconds. + Weight::from_parts(24_528_000, 8591) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -125,11 +120,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) fn payout() -> Weight { // Proof Size summary in bytes: - // Measured: `2241` - // Estimated: `5621` - // Minimum execution time: 68_868 nanoseconds. - Weight::from_ref_time(70_160_000) - .saturating_add(Weight::from_proof_size(5621)) + // Measured: `461` + // Estimated: `8591` + // Minimum execution time: 47_609_000 picoseconds. + Weight::from_parts(48_462_000, 8591) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -143,11 +137,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn payout_other() -> Weight { // Proof Size summary in bytes: - // Measured: `2189` - // Estimated: `8224` - // Minimum execution time: 68_804 nanoseconds. - Weight::from_ref_time(69_223_000) - .saturating_add(Weight::from_proof_size(8224)) + // Measured: `461` + // Estimated: `12184` + // Minimum execution time: 48_513_000 picoseconds. + Weight::from_parts(49_053_000, 12184) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -157,11 +150,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Salary Claimant (max_values: None, max_size: Some(78), added: 2553, mode: MaxEncodedLen) fn check_payment() -> Weight { // Proof Size summary in bytes: - // Measured: `880` - // Estimated: `3104` - // Minimum execution time: 19_027 nanoseconds. - Weight::from_ref_time(19_360_000) - .saturating_add(Weight::from_proof_size(3104)) + // Measured: `202` + // Estimated: `5084` + // Minimum execution time: 12_663_000 picoseconds. + Weight::from_parts(12_858_000, 5084) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -173,11 +165,10 @@ impl WeightInfo for () { /// Proof: Salary Status (max_values: Some(1), max_size: Some(56), added: 551, mode: MaxEncodedLen) fn init() -> Weight { // Proof Size summary in bytes: - // Measured: `1120` - // Estimated: `551` - // Minimum execution time: 21_058 nanoseconds. - Weight::from_ref_time(21_381_000) - .saturating_add(Weight::from_proof_size(551)) + // Measured: `4` + // Estimated: `1541` + // Minimum execution time: 11_793_000 picoseconds. + Weight::from_parts(12_080_000, 1541) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -185,11 +176,10 @@ impl WeightInfo for () { /// Proof: Salary Status (max_values: Some(1), max_size: Some(56), added: 551, mode: MaxEncodedLen) fn bump() -> Weight { // Proof Size summary in bytes: - // Measured: `1234` - // Estimated: `551` - // Minimum execution time: 22_272 nanoseconds. - Weight::from_ref_time(22_923_000) - .saturating_add(Weight::from_proof_size(551)) + // Measured: `118` + // Estimated: `1541` + // Minimum execution time: 12_799_000 picoseconds. + Weight::from_parts(13_343_000, 1541) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -201,11 +191,10 @@ impl WeightInfo for () { /// Proof: Salary Claimant (max_values: None, max_size: Some(78), added: 2553, mode: MaxEncodedLen) fn induct() -> Weight { // Proof Size summary in bytes: - // Measured: `1510` - // Estimated: `5621` - // Minimum execution time: 32_223 nanoseconds. - Weight::from_ref_time(32_663_000) - .saturating_add(Weight::from_proof_size(5621)) + // Measured: `394` + // Estimated: `8591` + // Minimum execution time: 20_299_000 picoseconds. + Weight::from_parts(20_664_000, 8591) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -217,11 +206,10 @@ impl WeightInfo for () { /// Proof: Salary Claimant (max_values: None, max_size: Some(78), added: 2553, mode: MaxEncodedLen) fn register() -> Weight { // Proof Size summary in bytes: - // Measured: `1616` - // Estimated: `5621` - // Minimum execution time: 38_279 nanoseconds. - Weight::from_ref_time(38_996_000) - .saturating_add(Weight::from_proof_size(5621)) + // Measured: `461` + // Estimated: `8591` + // Minimum execution time: 24_195_000 picoseconds. + Weight::from_parts(24_528_000, 8591) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -233,11 +221,10 @@ impl WeightInfo for () { /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) fn payout() -> Weight { // Proof Size summary in bytes: - // Measured: `2241` - // Estimated: `5621` - // Minimum execution time: 68_868 nanoseconds. - Weight::from_ref_time(70_160_000) - .saturating_add(Weight::from_proof_size(5621)) + // Measured: `461` + // Estimated: `8591` + // Minimum execution time: 47_609_000 picoseconds. + Weight::from_parts(48_462_000, 8591) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -251,11 +238,10 @@ impl WeightInfo for () { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn payout_other() -> Weight { // Proof Size summary in bytes: - // Measured: `2189` - // Estimated: `8224` - // Minimum execution time: 68_804 nanoseconds. - Weight::from_ref_time(69_223_000) - .saturating_add(Weight::from_proof_size(8224)) + // Measured: `461` + // Estimated: `12184` + // Minimum execution time: 48_513_000 picoseconds. + Weight::from_parts(49_053_000, 12184) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -265,11 +251,10 @@ impl WeightInfo for () { /// Proof: Salary Claimant (max_values: None, max_size: Some(78), added: 2553, mode: MaxEncodedLen) fn check_payment() -> Weight { // Proof Size summary in bytes: - // Measured: `880` - // Estimated: `3104` - // Minimum execution time: 19_027 nanoseconds. - Weight::from_ref_time(19_360_000) - .saturating_add(Weight::from_proof_size(3104)) + // Measured: `202` + // Estimated: `5084` + // Minimum execution time: 12_663_000 picoseconds. + Weight::from_parts(12_858_000, 5084) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } From f57ff377c13599696772e3c98ddd473717b8f8c2 Mon Sep 17 00:00:00 2001 From: abebeos <110243666+abebeos@users.noreply.github.com> Date: Sat, 4 Mar 2023 15:01:04 +0200 Subject: [PATCH 469/715] FRAME: add a basic readme (#13520) --- frame/README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 frame/README.md diff --git a/frame/README.md b/frame/README.md new file mode 100644 index 0000000000000..47a7892c2c8d0 --- /dev/null +++ b/frame/README.md @@ -0,0 +1,11 @@ +# FRAME + +The FRAME development environment provides modules (called "pallets") and support libraries that you can use, modify, and extend to build the runtime logic to suit the needs of your blockchain. + +### Documentation + +https://docs.substrate.io/reference/frame-pallets/ + +### Issues + +https://github.com/orgs/paritytech/projects/40 From 7d8aa669e32a544e80ddf807211186b30fedd343 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Sun, 5 Mar 2023 15:38:49 -0600 Subject: [PATCH 470/715] Update staking related code-owners (#13462) --- docs/CODEOWNERS | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/CODEOWNERS b/docs/CODEOWNERS index 4377e7ff049dc..95ee8cc66fa0a 100644 --- a/docs/CODEOWNERS +++ b/docs/CODEOWNERS @@ -59,10 +59,11 @@ /frame/contracts/ @athei # NPoS and election -/frame/staking/ @kianenigma -/frame/elections/ @kianenigma -/frame/elections-phragmen/ @kianenigma -/primitives/npos-elections/ @kianenigma +/frame/election-provider-support/ @paritytech/staking-core +/frame/staking/ @paritytech/staking-core +/frame/nomination-pools/ @paritytech/staking-core +/frame/elections-phragmen/ @paritytech/staking-core +/primitives/npos-elections/ @paritytech/staking-core # Fixed point arithmetic /primitives/sp-arithmetic/ @kianenigma From 1d9a139dd96bf5d1583c725bae6fcac5a0805372 Mon Sep 17 00:00:00 2001 From: Sasha Gryaznov Date: Mon, 6 Mar 2023 10:40:03 +0200 Subject: [PATCH 471/715] [contracts] Forbid calling back to contracts after switching to runtime (#13443) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * save: compiles and tests pass * save: added global * done + test * cleanup * changelog update * cleanup * address feedback, step 1 * address feedback, step 2 * address feedback, step 3 * returned updated gas_estimation_call_runtime test * clippy fix * address feedback, step 4 * address feedback, step 5 * move data from context to inputs * docs fix * Apply suggestions from code review Co-authored-by: Alexander Theißen * address feedback, step 6 --------- Co-authored-by: Alexander Theißen --- Cargo.lock | 1 + frame/contracts/CHANGELOG.md | 3 + frame/contracts/Cargo.toml | 2 + frame/contracts/src/lib.rs | 359 +++++++++++++++++++++-------------- frame/contracts/src/tests.rs | 72 ++++++- 5 files changed, 287 insertions(+), 150 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d67aeda9f03f2..5a215553d15c5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5598,6 +5598,7 @@ dependencies = [ "assert_matches", "bitflags", "env_logger 0.9.3", + "environmental", "frame-benchmarking", "frame-support", "frame-system", diff --git a/frame/contracts/CHANGELOG.md b/frame/contracts/CHANGELOG.md index ab3998e6dc4f7..dcb9d6d4d2b20 100644 --- a/frame/contracts/CHANGELOG.md +++ b/frame/contracts/CHANGELOG.md @@ -20,6 +20,9 @@ In other words: Upgrading this pallet will not break pre-existing contracts. ### Added +- Forbid calling back to contracts after switching to runtime +[#13443](https://github.com/paritytech/substrate/pull/13443) + - Allow contracts to dispatch calls into the runtime (**unstable**) [#9276](https://github.com/paritytech/substrate/pull/9276) diff --git a/frame/contracts/Cargo.toml b/frame/contracts/Cargo.toml index cd41ae2e39b55..e19326b785b2b 100644 --- a/frame/contracts/Cargo.toml +++ b/frame/contracts/Cargo.toml @@ -35,6 +35,7 @@ rand = { version = "0.8", optional = true, default-features = false } rand_pcg = { version = "0.3", optional = true } # Substrate Dependencies +environmental = { version = "1.1.4", default-features = false } 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" } @@ -80,6 +81,7 @@ std = [ "log/std", "rand/std", "wasmparser/std", + "environmental/std", ] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index a115cf119ceef..4f5d7ba305fc1 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -100,13 +100,14 @@ pub mod weights; mod tests; use crate::{ - exec::{AccountIdOf, ExecError, Executable, Stack as ExecStack}, + exec::{AccountIdOf, ErrorOrigin, ExecError, Executable, Stack as ExecStack}, gas::GasMeter, storage::{meter::Meter as StorageMeter, ContractInfo, DeletedContract}, wasm::{OwnerInfo, PrefabWasmModule, TryInstantiate}, weights::WeightInfo, }; use codec::{Codec, Encode, HasCompact}; +use environmental::*; use frame_support::{ dispatch::{Dispatchable, GetDispatchInfo, Pays, PostDispatchInfo}, ensure, @@ -616,16 +617,16 @@ pub mod pallet { let gas_limit: Weight = gas_limit.into(); let origin = ensure_signed(origin)?; let dest = T::Lookup::lookup(dest)?; - let mut output = Self::internal_call( + let common = CommonInput { origin, - dest, value, - gas_limit, - storage_deposit_limit.map(Into::into), data, - None, - Determinism::Deterministic, - ); + gas_limit, + storage_deposit_limit: storage_deposit_limit.map(Into::into), + debug_message: None, + }; + let mut output = CallInput:: { dest, determinism: Determinism::Deterministic } + .run_guarded(common); if let Ok(retval) = &output.result { if retval.did_revert() { output.result = Err(>::ContractReverted.into()); @@ -678,16 +679,16 @@ pub mod pallet { let code_len = code.len() as u32; let data_len = data.len() as u32; let salt_len = salt.len() as u32; - let mut output = Self::internal_instantiate( + let common = CommonInput { origin, value, - gas_limit, - storage_deposit_limit.map(Into::into), - Code::Upload(code), data, - salt, - None, - ); + gas_limit, + storage_deposit_limit: storage_deposit_limit.map(Into::into), + debug_message: None, + }; + let mut output = + InstantiateInput:: { code: Code::Upload(code), salt }.run_guarded(common); if let Ok(retval) = &output.result { if retval.1.did_revert() { output.result = Err(>::ContractReverted.into()); @@ -720,16 +721,16 @@ pub mod pallet { let origin = ensure_signed(origin)?; let data_len = data.len() as u32; let salt_len = salt.len() as u32; - let mut output = Self::internal_instantiate( + let common = CommonInput { origin, value, - gas_limit, - storage_deposit_limit.map(Into::into), - Code::Existing(code_hash), data, - salt, - None, - ); + gas_limit, + storage_deposit_limit: storage_deposit_limit.map(Into::into), + debug_message: None, + }; + let mut output = + InstantiateInput:: { code: Code::Existing(code_hash), salt }.run_guarded(common); if let Ok(retval) = &output.result { if retval.1.did_revert() { output.result = Err(>::ContractReverted.into()); @@ -872,6 +873,9 @@ pub mod pallet { /// This can be triggered by a call to `seal_terminate`. TerminatedInConstructor, /// A call tried to invoke a contract that is flagged as non-reentrant. + /// The only other cause is that a call from a contract into the runtime tried to call back + /// into `pallet-contracts`. This would make the whole pallet reentrant with regard to + /// contract code execution which is not supported. ReentranceDenied, /// Origin doesn't have enough balance to pay the required storage deposits. StorageDepositNotEnoughFunds, @@ -951,11 +955,27 @@ pub mod pallet { StorageValue<_, BoundedVec, ValueQuery>; } -/// Return type of the private [`Pallet::internal_call`] function. -type InternalCallOutput = InternalOutput; +/// Context of a contract invocation. +struct CommonInput<'a, T: Config> { + origin: T::AccountId, + value: BalanceOf, + data: Vec, + gas_limit: Weight, + storage_deposit_limit: Option>, + debug_message: Option<&'a mut DebugBufferVec>, +} -/// Return type of the private [`Pallet::internal_instantiate`] function. -type InternalInstantiateOutput = InternalOutput, ExecReturnValue)>; +/// Input specific to a call into contract. +struct CallInput { + dest: T::AccountId, + determinism: Determinism, +} + +/// Input specific to a contract instantiation invocation. +struct InstantiateInput { + code: Code>, + salt: Vec, +} /// Return type of private helper functions. struct InternalOutput { @@ -967,6 +987,164 @@ struct InternalOutput { result: Result, } +/// Helper trait to wrap contract execution entry points into a signle function +/// [`Invokable::run_guarded`]. +trait Invokable { + /// What is returned as a result of a successful invocation. + type Output; + + /// Single entry point to contract execution. + /// Downstream execution flow is branched by implementations of [`Invokable`] trait: + /// + /// - [`InstantiateInput::run`] runs contract instantiation, + /// - [`CallInput::run`] runs contract call. + /// + /// We enforce a re-entrancy guard here by initializing and checking a boolean flag through a + /// global reference. + fn run_guarded(&self, common: CommonInput) -> InternalOutput { + // Set up a global reference to the boolean flag used for the re-entrancy guard. + environmental!(executing_contract: bool); + + let gas_limit = common.gas_limit; + executing_contract::using_once(&mut false, || { + executing_contract::with(|f| { + // Fail if already entered contract execution + if *f { + return Err(()) + } + // We are entering contract execution + *f = true; + Ok(()) + }) + .expect("Returns `Ok` if called within `using_once`. It is syntactically obvious that this is the case; qed") + .map_or_else( + |_| InternalOutput { + gas_meter: GasMeter::new(gas_limit), + storage_deposit: Default::default(), + result: Err(ExecError { + error: >::ReentranceDenied.into(), + origin: ErrorOrigin::Caller, + }), + }, + // Enter contract call. + |_| self.run(common, GasMeter::new(gas_limit)), + ) + }) + } + + /// Method that does the actual call to a contract. It can be either a call to a deployed + /// contract or a instantiation of a new one. + /// + /// Called by dispatchables and public functions through the [`Invokable::run_guarded`]. + fn run( + &self, + common: CommonInput, + gas_meter: GasMeter, + ) -> InternalOutput; +} + +impl Invokable for CallInput { + type Output = ExecReturnValue; + + fn run( + &self, + common: CommonInput, + mut gas_meter: GasMeter, + ) -> InternalOutput { + let mut storage_meter = + match StorageMeter::new(&common.origin, common.storage_deposit_limit, common.value) { + Ok(meter) => meter, + Err(err) => + return InternalOutput { + result: Err(err.into()), + gas_meter, + storage_deposit: Default::default(), + }, + }; + let schedule = T::Schedule::get(); + let CallInput { dest, determinism } = self; + let CommonInput { origin, value, data, debug_message, .. } = common; + let result = ExecStack::>::run_call( + origin.clone(), + dest.clone(), + &mut gas_meter, + &mut storage_meter, + &schedule, + value, + data.clone(), + debug_message, + *determinism, + ); + InternalOutput { gas_meter, storage_deposit: storage_meter.into_deposit(&origin), result } + } +} + +impl Invokable for InstantiateInput { + type Output = (AccountIdOf, ExecReturnValue); + + fn run( + &self, + mut common: CommonInput, + mut gas_meter: GasMeter, + ) -> InternalOutput { + let mut storage_deposit = Default::default(); + let try_exec = || { + let schedule = T::Schedule::get(); + let (extra_deposit, executable) = match &self.code { + Code::Upload(binary) => { + let executable = PrefabWasmModule::from_code( + binary.clone(), + &schedule, + common.origin.clone(), + Determinism::Deterministic, + TryInstantiate::Skip, + ) + .map_err(|(err, msg)| { + common + .debug_message + .as_mut() + .map(|buffer| buffer.try_extend(&mut msg.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 + // reserved on the uploading account. + (executable.open_deposit(), executable) + }, + Code::Existing(hash) => ( + Default::default(), + PrefabWasmModule::from_storage(*hash, &schedule, &mut gas_meter)?, + ), + }; + let mut storage_meter = StorageMeter::new( + &common.origin, + common.storage_deposit_limit, + common.value.saturating_add(extra_deposit), + )?; + + let InstantiateInput { salt, .. } = self; + let CommonInput { origin, value, data, debug_message, .. } = common; + let result = ExecStack::>::run_instantiate( + origin.clone(), + executable, + &mut gas_meter, + &mut storage_meter, + &schedule, + value, + data.clone(), + &salt, + debug_message, + ); + storage_deposit = storage_meter + .into_deposit(&origin) + .saturating_add(&StorageDeposit::Charge(extra_deposit)); + result + }; + InternalOutput { result: try_exec(), gas_meter, storage_deposit } + } +} + impl Pallet { /// Perform a call to a specified contract. /// @@ -991,16 +1169,15 @@ impl Pallet { determinism: Determinism, ) -> ContractExecResult> { let mut debug_message = if debug { Some(DebugBufferVec::::default()) } else { None }; - let output = Self::internal_call( + let common = CommonInput { origin, - dest, value, + data, gas_limit, storage_deposit_limit, - data, - debug_message.as_mut(), - determinism, - ); + debug_message: debug_message.as_mut(), + }; + let output = CallInput:: { dest, determinism }.run_guarded(common); ContractExecResult { result: output.result.map_err(|r| r.error), gas_consumed: output.gas_meter.gas_consumed(), @@ -1033,16 +1210,15 @@ impl Pallet { debug: bool, ) -> ContractInstantiateResult> { let mut debug_message = if debug { Some(DebugBufferVec::::default()) } else { None }; - let output = Self::internal_instantiate( + let common = CommonInput { origin, value, + data, gas_limit, storage_deposit_limit, - code, - data, - salt, - debug_message.as_mut(), - ); + debug_message: debug_message.as_mut(), + }; + let output = InstantiateInput:: { code, salt }.run_guarded(common); ContractInstantiateResult { result: output .result @@ -1132,113 +1308,6 @@ impl Pallet { self::wasm::reinstrument(module, schedule).map(|_| ()) } - /// 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, - storage_deposit_limit: Option>, - data: Vec, - debug_message: Option<&mut DebugBufferVec>, - determinism: Determinism, - ) -> 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.clone(), - dest, - &mut gas_meter, - &mut storage_meter, - &schedule, - value, - data, - debug_message, - determinism, - ); - InternalCallOutput { - result, - gas_meter, - storage_deposit: storage_meter.into_deposit(&origin), - } - } - - /// Internal function that does the actual instantiation. - /// - /// Called by dispatchables and public functions. - fn internal_instantiate( - origin: T::AccountId, - value: BalanceOf, - gas_limit: Weight, - storage_deposit_limit: Option>, - code: Code>, - data: Vec, - salt: Vec, - mut debug_message: Option<&mut DebugBufferVec>, - ) -> InternalInstantiateOutput { - let mut storage_deposit = Default::default(); - let mut gas_meter = GasMeter::new(gas_limit); - let try_exec = || { - let schedule = T::Schedule::get(); - let (extra_deposit, executable) = match code { - Code::Upload(binary) => { - let executable = PrefabWasmModule::from_code( - binary, - &schedule, - origin.clone(), - Determinism::Deterministic, - TryInstantiate::Skip, - ) - .map_err(|(err, msg)| { - debug_message.as_mut().map(|buffer| buffer.try_extend(&mut msg.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 - // reserved on the uploading account. - (executable.open_deposit(), executable) - }, - Code::Existing(hash) => ( - Default::default(), - PrefabWasmModule::from_storage(hash, &schedule, &mut gas_meter)?, - ), - }; - let mut storage_meter = StorageMeter::new( - &origin, - storage_deposit_limit, - value.saturating_add(extra_deposit), - )?; - let result = ExecStack::>::run_instantiate( - origin.clone(), - executable, - &mut gas_meter, - &mut storage_meter, - &schedule, - value, - data, - &salt, - debug_message, - ); - storage_deposit = storage_meter - .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( diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index cecac03388d1b..d74b08243df4b 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -2805,12 +2805,9 @@ 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 = RuntimeCall::Contracts(crate::Call::call { + let call = RuntimeCall::Balances(pallet_balances::Call::transfer { dest: addr_callee, - value: 0, - gas_limit: GAS_LIMIT / 3, - storage_deposit_limit: None, - data: vec![], + value: min_balance * 10, }); let result = Contracts::bare_call( ALICE, @@ -2844,6 +2841,71 @@ fn gas_estimation_call_runtime() { }); } +#[test] +fn gas_call_runtime_reentrancy_guarded() { + 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 min_balance = ::Currency::minimum_balance(); + let _ = Balances::deposit_creating(&ALICE, 1000 * min_balance); + let _ = Balances::deposit_creating(&CHARLIE, 1000 * min_balance); + + let addr_caller = Contracts::bare_instantiate( + ALICE, + min_balance * 100, + GAS_LIMIT, + None, + Code::Upload(caller_code), + vec![], + vec![0], + false, + ) + .result + .unwrap() + .account_id; + + let addr_callee = Contracts::bare_instantiate( + ALICE, + min_balance * 100, + GAS_LIMIT, + None, + Code::Upload(callee_code), + vec![], + vec![1], + false, + ) + .result + .unwrap() + .account_id; + + // Call pallet_contracts call() dispatchable + let call = RuntimeCall::Contracts(crate::Call::call { + dest: addr_callee, + value: 0, + gas_limit: GAS_LIMIT / 3, + storage_deposit_limit: None, + data: vec![], + }); + + // Call runtime to re-enter back to contracts engine by + // calling dummy contract + let result = Contracts::bare_call( + ALICE, + addr_caller.clone(), + 0, + GAS_LIMIT, + None, + call.encode(), + false, + Determinism::Deterministic, + ) + .result + .unwrap(); + // Call to runtime should fail because of the re-entrancy guard + assert_return_code!(result, RuntimeReturnCode::CallRuntimeFailed); + }); +} + #[test] fn ecdsa_recover() { let (wasm, _code_hash) = compile_module::("ecdsa_recover").unwrap(); From 435446fe0ba4063aa9cedbef8cfb10ef0724a9ce Mon Sep 17 00:00:00 2001 From: yjh Date: Mon, 6 Mar 2023 22:09:07 +0800 Subject: [PATCH 472/715] chore: reduce copy times for bytes in core-hashing (#13519) * chore: reduce copy bytes for core-hashing * improve by suggestions and remove unused `xx_into` * chore: replace sha2 crate by `sp_core::hashing` for pallet-alliance * fix features * use sp-core-hashing directly * add to dev-dep --- Cargo.lock | 2 +- frame/alliance/Cargo.toml | 7 +++-- frame/alliance/src/benchmarking.rs | 7 ++--- frame/alliance/src/mock.rs | 7 ++--- primitives/core/hashing/src/lib.rs | 46 +++++------------------------- 5 files changed, 16 insertions(+), 53 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5a215553d15c5..e9e33471a1588 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5285,8 +5285,8 @@ dependencies = [ "pallet-identity", "parity-scale-codec", "scale-info", - "sha2 0.10.6", "sp-core", + "sp-core-hashing", "sp-io", "sp-runtime", "sp-std", diff --git a/frame/alliance/Cargo.toml b/frame/alliance/Cargo.toml index d6a16e2c32e36..d70dfd6d752eb 100644 --- a/frame/alliance/Cargo.toml +++ b/frame/alliance/Cargo.toml @@ -14,7 +14,6 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] 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 } codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } @@ -22,6 +21,7 @@ scale-info = { version = "2.0.1", default-features = false, features = ["derive" 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-core-hashing = { version = "5.0.0", default-features = false, path = "../../primitives/core/hashing", optional = true } sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } @@ -34,13 +34,14 @@ pallet-collective = { version = "4.0.0-dev", path = "../collective", default-fea [dev-dependencies] array-bytes = "4.1" -sha2 = "0.10.1" +sp-core-hashing = { version = "5.0.0", default-features = false, path = "../../primitives/core/hashing" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } pallet-collective = { version = "4.0.0-dev", path = "../collective" } [features] default = ["std"] std = [ + "sp-core-hashing?/std", "pallet-collective?/std", "frame-benchmarking?/std", "log/std", @@ -56,7 +57,7 @@ std = [ ] runtime-benchmarks = [ "array-bytes", - "sha2", + "sp-core-hashing", "frame-benchmarking/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "frame-support/runtime-benchmarks", diff --git a/frame/alliance/src/benchmarking.rs b/frame/alliance/src/benchmarking.rs index a30b5adcee3ed..92bf1ae4468df 100644 --- a/frame/alliance/src/benchmarking.rs +++ b/frame/alliance/src/benchmarking.rs @@ -40,11 +40,8 @@ fn assert_last_event, I: 'static>(generic_event: >:: } 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) + let result = sp_core_hashing::sha2_256(input.as_ref()); + Cid::new_v0(result) } fn rule(input: impl AsRef<[u8]>) -> Cid { diff --git a/frame/alliance/src/mock.rs b/frame/alliance/src/mock.rs index 0925a82fdbfa3..b8fd998eb20a0 100644 --- a/frame/alliance/src/mock.rs +++ b/frame/alliance/src/mock.rs @@ -368,11 +368,8 @@ pub fn new_bench_ext() -> sp_io::TestExternalities { } 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) + let result = sp_core_hashing::sha2_256(b"hello world"); + Cid::new_v0(result) } pub fn make_remark_proposal(value: u64) -> (RuntimeCall, u32, H256) { diff --git a/primitives/core/hashing/src/lib.rs b/primitives/core/hashing/src/lib.rs index 5bb68586a1340..26941bb60fa51 100644 --- a/primitives/core/hashing/src/lib.rs +++ b/primitives/core/hashing/src/lib.rs @@ -35,48 +35,22 @@ pub fn blake2_512_into(data: &[u8], dest: &mut [u8; 64]) { /// 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]) { - type Blake2b256 = blake2::Blake2b; - dest.copy_from_slice(Blake2b256::digest(data).as_slice()); + blake2::Blake2b512::digest(data).into() } /// 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]) { - type Blake2b128 = blake2::Blake2b; - dest.copy_from_slice(Blake2b128::digest(data).as_slice()); + blake2::Blake2b::::digest(data).into() } /// 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]) { - type Blake2b64 = blake2::Blake2b; - dest.copy_from_slice(Blake2b64::digest(data).as_slice()); + blake2::Blake2b::::digest(data).into() } /// 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 + blake2::Blake2b::::digest(data).into() } /// Do a XX 64-bit hash and place result in `dest`. @@ -128,21 +102,15 @@ 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 output = [0u8; 32]; - output.copy_from_slice(sha3::Keccak256::digest(data).as_slice()); - output + sha3::Keccak256::digest(data).into() } /// Do a keccak 512-bit hash and return result. pub fn keccak_512(data: &[u8]) -> [u8; 64] { - let mut output = [0u8; 64]; - output.copy_from_slice(sha3::Keccak512::digest(data).as_slice()); - output + sha3::Keccak512::digest(data).into() } /// Do a sha2 256-bit hash and return result. pub fn sha2_256(data: &[u8]) -> [u8; 32] { - let mut output = [0u8; 32]; - output.copy_from_slice(sha2::Sha256::digest(data).as_slice()); - output + sha2::Sha256::digest(data).into() } From c4081230565220dff6a7f3a383f81c8eaa27da1b Mon Sep 17 00:00:00 2001 From: Martin Pugh Date: Mon, 6 Mar 2023 15:07:59 +0000 Subject: [PATCH 473/715] [CI] Remove redundant trigger-review-pipeline job (#13547) This job is now redundant since pipelines are run for each commit, so it can be safely removed. Cheers --- .github/workflows/trigger-review-pipeline.yml | 20 ------------------- 1 file changed, 20 deletions(-) delete mode 100644 .github/workflows/trigger-review-pipeline.yml diff --git a/.github/workflows/trigger-review-pipeline.yml b/.github/workflows/trigger-review-pipeline.yml deleted file mode 100644 index af54ec4358b43..0000000000000 --- a/.github/workflows/trigger-review-pipeline.yml +++ /dev/null @@ -1,20 +0,0 @@ -name: Trigger pipeline for review - -on: - pull_request: - types: [ready_for_review] - -jobs: - trigger: - runs-on: ubuntu-latest - - steps: - - name: Trigger pipeline - run: | - curl -X POST \ - -F token="$TOKEN" \ - -F ref="$REF" \ - https://gitlab.parity.io/api/v4/projects/145/trigger/pipeline - env: - REF: ${{ github.event.number }} - TOKEN: ${{ secrets.GITLAB_TRIGGER_TOKEN }} From e7aa37ec9601fac11f48d227fc06da84b0a5c521 Mon Sep 17 00:00:00 2001 From: Aaro Altonen <48052676+altonen@users.noreply.github.com> Date: Mon, 6 Mar 2023 18:33:38 +0200 Subject: [PATCH 474/715] Extract syncing protocol from `sc-network` (#12828) * 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. * Move stuff to SyncingEngine * Move `ChainSync` instanation to `SyncingEngine` Some of the tests have to be rewritten * Move peer hashmap to `SyncingEngine` * Let `SyncingEngine` to implement `ChainSyncInterface` * Introduce `SyncStatusProvider` * Move `sync_peer_(connected|disconnected)` to `SyncingEngine` * Implement `SyncEventStream` Remove `SyncConnected`/`SyncDisconnected` events from `NetworkEvenStream` and provide those events through `ChainSyncInterface` instead. Modify BEEFY/GRANDPA/transactions protocol and `NetworkGossip` to take `SyncEventStream` object which they listen to for incoming sync peer events. * Introduce `ChainSyncInterface` This interface provides a set of miscellaneous functions that other subsystems can use to query, for example, the syncing status. * Move event stream polling to `SyncingEngine` Subscribe to `NetworkStreamEvent` and poll the incoming notifications and substream events from `SyncingEngine`. The code needs refactoring. * Make `SyncingEngine` into an asynchronous runner This commits removes the last hard dependency of syncing from `sc-network` meaning the protocol now lives completely outside of `sc-network`, ignoring the hardcoded peerset entry which will be addressed in the future. Code needs a lot of refactoring. * Fix warnings * Code refactoring * Use `SyncingService` for BEEFY * Use `SyncingService` for GRANDPA * Remove call delegation from `NetworkService` * Remove `ChainSyncService` * Remove `ChainSync` service tests They were written for the sole purpose of verifying that `NetworWorker` continues to function while the calls are being dispatched to `ChainSync`. * Refactor code * Refactor code * Update client/finality-grandpa/src/communication/tests.rs Co-authored-by: Anton * Fix warnings * Apply review comments * Fix docs * Fix test * cargo-fmt * Update client/network/sync/src/engine.rs Co-authored-by: Anton * Update client/network/sync/src/engine.rs Co-authored-by: Anton * Add missing docs * Refactor code --------- Co-authored-by: Anton --- Cargo.lock | 666 ++++++++----- bin/node-template/node/src/service.rs | 8 +- bin/node/cli/Cargo.toml | 1 + bin/node/cli/src/chain_spec.rs | 3 +- bin/node/cli/src/service.rs | 26 +- client/cli/src/arg_enums.rs | 20 +- client/cli/src/params/network_params.rs | 7 +- client/cli/src/params/node_key_params.rs | 14 +- client/consensus/aura/src/lib.rs | 5 + client/consensus/babe/src/tests.rs | 5 + client/consensus/beefy/Cargo.toml | 1 + client/consensus/beefy/src/lib.rs | 30 +- client/consensus/beefy/src/tests.rs | 8 +- client/consensus/beefy/src/worker.rs | 39 +- .../grandpa/src/communication/mod.rs | 45 +- .../grandpa/src/communication/tests.rs | 40 +- client/consensus/grandpa/src/environment.rs | 31 +- client/consensus/grandpa/src/lib.rs | 35 +- client/consensus/grandpa/src/observer.rs | 19 +- client/consensus/grandpa/src/tests.rs | 71 +- client/informant/src/display.rs | 11 +- client/informant/src/lib.rs | 20 +- client/network-gossip/src/bridge.rs | 123 ++- client/network-gossip/src/lib.rs | 18 +- client/network-gossip/src/state_machine.rs | 4 + client/network/common/Cargo.toml | 6 + client/network/common/src/config.rs | 375 ++++++- client/network/common/src/protocol/event.rs | 14 +- client/network/common/src/service.rs | 35 +- client/network/common/src/sync.rs | 61 +- client/network/src/behaviour.rs | 39 +- client/network/src/config.rs | 384 +------- client/network/src/lib.rs | 20 +- client/network/src/protocol.rs | 766 ++------------- .../src/protocol/notifications/behaviour.rs | 50 +- client/network/src/service.rs | 266 +---- client/network/src/service/metrics.rs | 35 +- client/network/src/service/out_events.rs | 14 - .../network/src/service/tests/chain_sync.rs | 420 -------- client/network/src/service/tests/mod.rs | 138 +-- client/network/src/service/tests/service.rs | 68 +- client/network/sync/Cargo.toml | 1 + client/network/sync/src/engine.rs | 924 ++++++++++++++++++ client/network/sync/src/lib.rs | 71 +- client/network/sync/src/service/chain_sync.rs | 169 +++- client/network/sync/src/service/mock.rs | 15 +- client/network/sync/src/service/network.rs | 30 +- client/network/sync/src/tests.rs | 78 -- client/network/test/src/lib.rs | 215 ++-- client/network/test/src/sync.rs | 27 +- client/network/transactions/src/lib.rs | 76 +- client/service/src/builder.rs | 78 +- client/service/src/config.rs | 9 +- client/service/src/lib.rs | 69 +- client/service/src/metrics.rs | 23 +- client/service/test/Cargo.toml | 1 + client/service/test/src/lib.rs | 18 +- 57 files changed, 2886 insertions(+), 2859 deletions(-) delete mode 100644 client/network/src/service/tests/chain_sync.rs create mode 100644 client/network/sync/src/engine.rs delete mode 100644 client/network/sync/src/tests.rs diff --git a/Cargo.lock b/Cargo.lock index e9e33471a1588..72b5943d48b3f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -27,7 +27,7 @@ version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" dependencies = [ - "gimli 0.27.1", + "gimli 0.27.2", ] [[package]] @@ -55,6 +55,16 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "aead" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c192eb8f11fc081b0fe4259ba5af04217d4e0faddd02417310a927911abd7c8" +dependencies = [ + "crypto-common", + "generic-array 0.14.6", +] + [[package]] name = "aes" version = "0.6.0" @@ -79,17 +89,14 @@ dependencies = [ ] [[package]] -name = "aes-gcm" -version = "0.8.0" +name = "aes" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5278b5fabbb9bd46e24aa69b2fdea62c99088e0a950a9be40e3e0101298f88da" +checksum = "433cfd6710c9986c576a25ca913c39d66a6474107b406f34f91d4a8923395241" dependencies = [ - "aead 0.3.2", - "aes 0.6.0", - "cipher 0.2.5", - "ctr 0.6.0", - "ghash 0.3.1", - "subtle", + "cfg-if", + "cipher 0.4.3", + "cpufeatures", ] [[package]] @@ -106,6 +113,20 @@ dependencies = [ "subtle", ] +[[package]] +name = "aes-gcm" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82e1366e0c69c9f927b1fa5ce2c7bf9eafc8f9268c0b9800729e8b267612447c" +dependencies = [ + "aead 0.5.1", + "aes 0.8.2", + "cipher 0.4.3", + "ctr 0.9.2", + "ghash 0.5.0", + "subtle", +] + [[package]] name = "aes-soft" version = "0.6.4" @@ -246,7 +267,7 @@ dependencies = [ "num-traits", "rusticata-macros", "thiserror", - "time 0.3.17", + "time 0.3.20", ] [[package]] @@ -262,7 +283,7 @@ dependencies = [ "num-traits", "rusticata-macros", "thiserror", - "time 0.3.17", + "time 0.3.20", ] [[package]] @@ -369,19 +390,20 @@ dependencies = [ [[package]] name = "async-stream" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dad5c83079eae9969be7fadefe640a1c566901f05ff91ab221de4b6f68d9507e" +checksum = "ad445822218ce64be7a341abfb0b1ea43b5c23aa83902542a4542e78309d8e5e" dependencies = [ "async-stream-impl", "futures-core", + "pin-project-lite 0.2.9", ] [[package]] name = "async-stream-impl" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10f203db73a71dfa2fb6dd22763990fa26f3d2625a6da2da900d23b87d26be27" +checksum = "e4655ae1a7b0cdf149156f780c5bf3f1352bc53cbd9e0a361a7ef7b22947e965" dependencies = [ "proc-macro2", "quote", @@ -482,9 +504,9 @@ checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" [[package]] name = "base64ct" -version = "1.5.3" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b645a089122eccb6111b4f81cbc1a49f5900ac4666bb93ac027feaecf15607bf" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" [[package]] name = "basic-toml" @@ -527,9 +549,9 @@ dependencies = [ [[package]] name = "bindgen" -version = "0.60.1" +version = "0.64.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "062dddbc1ba4aca46de6338e2bf87771414c335f7b2f2036e8f3e9befebf88e6" +checksum = "c4243e6031260db77ede97ad86c27e501d646a27ab57b59a574f725d98ab1fb4" dependencies = [ "bitflags", "cexpr", @@ -542,6 +564,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", + "syn", ] [[package]] @@ -573,24 +596,24 @@ dependencies = [ [[package]] name = "blake2b_simd" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72936ee4afc7f8f736d1c38383b56480b5497b4617b4a77bdbf1d2ababc76127" +checksum = "3c2f0dc9a68c6317d884f97cc36cf5a3d20ba14ce404227df55e1af708ab04bc" dependencies = [ "arrayref", "arrayvec 0.7.2", - "constant_time_eq 0.1.5", + "constant_time_eq", ] [[package]] name = "blake2s_simd" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db539cc2b5f6003621f1cd9ef92d7ded8ea5232c7de0f9faa2de251cd98730d4" +checksum = "6637f448b9e61dfadbdcbae9a885fadee1f3eaffb1f8d3c1965d3ade8bdfd44f" dependencies = [ "arrayref", "arrayvec 0.7.2", - "constant_time_eq 0.1.5", + "constant_time_eq", ] [[package]] @@ -603,7 +626,7 @@ dependencies = [ "arrayvec 0.7.2", "cc", "cfg-if", - "constant_time_eq 0.2.4", + "constant_time_eq", ] [[package]] @@ -663,9 +686,9 @@ checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" [[package]] name = "bounded-collections" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de2aff4807e40f478132150d80b031f2461d88f061851afcab537d7600c24120" +checksum = "a071c348a5ef6da1d3a87166b408170b46002382b1dda83992b5c2208cefb370" dependencies = [ "log", "parity-scale-codec", @@ -681,9 +704,9 @@ checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" [[package]] name = "bstr" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7f0778972c64420fdedc63f09919c8a88bda7b25135357fd25a5d9f3257e832" +checksum = "5ffdb39cb703212f3c11973452c2861b972f757b021158f3516ba10f2fa8b2c1" dependencies = [ "memchr", "once_cell", @@ -749,9 +772,9 @@ dependencies = [ [[package]] name = "camino" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c77df041dc383319cc661b428b6961a005db4d6808d5e12536931b1ca9556055" +checksum = "6031a462f977dd38968b6f23378356512feeace69cef817e1a4475108093cec3" dependencies = [ "serde", ] @@ -865,7 +888,7 @@ name = "chain-spec-builder" version = "2.0.0" dependencies = [ "ansi_term", - "clap 4.1.4", + "clap 4.1.8", "node-cli", "rand 0.8.5", "sc-chain-spec", @@ -924,7 +947,7 @@ checksum = "f6ed9c8b2d17acb8110c46f1da5bf4a696d745e1474a16db0cd2b49cd0249bf2" dependencies = [ "core2", "multibase", - "multihash", + "multihash 0.16.3", "serde", "unsigned-varint", ] @@ -947,6 +970,16 @@ dependencies = [ "generic-array 0.14.6", ] +[[package]] +name = "cipher" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1873270f8f7942c191139cb8a40fd228da6c3fd2fc376d7e92d47aa14aeb59e" +dependencies = [ + "crypto-common", + "inout", +] + [[package]] name = "ckb-merkle-mountain-range" version = "0.5.2" @@ -958,9 +991,9 @@ dependencies = [ [[package]] name = "clang-sys" -version = "1.4.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa2e27ae6ab525c3d369ded447057bca5438d86dc3a68f6faafb8269ba82ebf3" +checksum = "77ed9a53e5d4d9c573ae844bfac6872b159cb1d1585a83b29e7a64b7eef7332a" dependencies = [ "glob", "libc", @@ -981,13 +1014,13 @@ dependencies = [ [[package]] name = "clap" -version = "4.1.4" +version = "4.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f13b9c79b5d1dd500d20ef541215a6423c75829ef43117e1b4d17fd8af0b5d76" +checksum = "c3d7ae14b20b94cb02149ed21a86c423859cbe18dc7ed69845cace50e52b40a5" dependencies = [ "bitflags", "clap_derive", - "clap_lex 0.3.1", + "clap_lex 0.3.2", "is-terminal", "once_cell", "strsim", @@ -996,18 +1029,18 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.1.1" +version = "4.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6540eedc41f8a5a76cf3d8d458057dcdf817be4158a55b5f861f7a5483de75" +checksum = "501ff0a401473ea1d4c3b125ff95506b62c5bc5768d818634195fbb7c4ad5ff4" dependencies = [ - "clap 4.1.4", + "clap 4.1.8", ] [[package]] name = "clap_derive" -version = "4.1.0" +version = "4.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "684a277d672e91966334af371f1a7b5833f9aa00b07c84e92fbce95e00208ce8" +checksum = "44bec8e5c9d09e439c4335b1af0abaab56dcf3b94999a936e1bb47b9134288f0" dependencies = [ "heck", "proc-macro-error", @@ -1027,9 +1060,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "783fe232adfca04f90f56201b26d79682d4cd2625e0bc7290b95123afe558ade" +checksum = "350b9cf31731f9957399229e9b2adc51eeabdfbe9d71d9a0552275fd12710d09" dependencies = [ "os_str_bytes", ] @@ -1066,15 +1099,9 @@ dependencies = [ [[package]] name = "const-oid" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cec318a675afcb6a1ea1d4340e2d377e56e47c266f28043ceccbf4412ddfdd3b" - -[[package]] -name = "constant_time_eq" -version = "0.1.5" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" +checksum = "520fbf3c07483f94e3e3ca9d0cfd913d7718ef2483d2cfd91c0d9e91474ab913" [[package]] name = "constant_time_eq" @@ -1125,12 +1152,6 @@ dependencies = [ "libc", ] -[[package]] -name = "cpuid-bool" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcb25d077389e53838a8158c8e99174c5a9d902dee4904320db714f3c653ffba" - [[package]] name = "cranelift-bforest" version = "0.93.0" @@ -1294,9 +1315,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.6" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" +checksum = "cf2b3e8478797446514c91ef04bafcb59faba183e621ad488df88983cc14128c" dependencies = [ "cfg-if", "crossbeam-utils", @@ -1304,9 +1325,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" dependencies = [ "cfg-if", "crossbeam-epoch", @@ -1315,22 +1336,22 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.13" +version = "0.9.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a" +checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695" dependencies = [ "autocfg", "cfg-if", "crossbeam-utils", - "memoffset 0.7.1", + "memoffset 0.8.0", "scopeguard", ] [[package]] name = "crossbeam-utils" -version = "0.8.14" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f" +checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" dependencies = [ "cfg-if", ] @@ -1360,6 +1381,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array 0.14.6", + "rand_core 0.6.4", "typenum", ] @@ -1373,16 +1395,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "crypto-mac" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bff07008ec701e8028e2ceb8f83f0e4274ee62bd2dbdc4fefff2e9a91824081a" -dependencies = [ - "generic-array 0.14.6", - "subtle", -] - [[package]] name = "crypto-mac" version = "0.11.1" @@ -1405,20 +1417,20 @@ dependencies = [ [[package]] name = "ctr" -version = "0.6.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb4a30d54f7443bf3d6191dcd486aca19e67cb3c49fa7a06a319966346707e7f" +checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea" dependencies = [ - "cipher 0.2.5", + "cipher 0.3.0", ] [[package]] name = "ctr" -version = "0.8.0" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" dependencies = [ - "cipher 0.3.0", + "cipher 0.4.3", ] [[package]] @@ -1463,9 +1475,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.89" +version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc831ee6a32dd495436e317595e639a587aa9907bef96fe6e6abc290ab6204e9" +checksum = "86d3488e7665a7a483b57e25bdd90d0aeb2bc7608c8d0346acf2ad3f1caf1d62" dependencies = [ "cc", "cxxbridge-flags", @@ -1475,9 +1487,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.89" +version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94331d54f1b1a8895cd81049f7eaaaef9d05a7dcb4d1fd08bf3ff0806246789d" +checksum = "48fcaf066a053a41a81dfb14d57d99738b767febb8b735c3016e469fac5da690" dependencies = [ "cc", "codespan-reporting", @@ -1490,15 +1502,15 @@ dependencies = [ [[package]] name = "cxxbridge-flags" -version = "1.0.89" +version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48dcd35ba14ca9b40d6e4b4b39961f23d835dbb8eed74565ded361d93e1feb8a" +checksum = "a2ef98b8b717a829ca5603af80e1f9e2e48013ab227b68ef37872ef84ee479bf" [[package]] name = "cxxbridge-macro" -version = "1.0.89" +version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81bbeb29798b407ccd82a3324ade1a7286e0d29851475990b612670f6f5124d2" +checksum = "086c685979a698443656e5cf7856c95c642295a38599f12fb1ff76fb28d19892" dependencies = [ "proc-macro2", "quote", @@ -1804,9 +1816,9 @@ dependencies = [ [[package]] name = "dyn-clone" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9b0705efd4599c15a38151f4721f7bc388306f61084d3bfd50bd07fbca5cb60" +checksum = "68b0cf012f1230e43cd00ebb729c6bb58707ecfa8ad08b52ef3a4ccd2697fc30" [[package]] name = "ecdsa" @@ -1999,9 +2011,9 @@ checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" [[package]] name = "fastrand" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" dependencies = [ "instant", ] @@ -2043,14 +2055,14 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.19" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e884668cd0c7480504233e951174ddc3b382f7c2666e3b7310b5c4e7b0c37f9" +checksum = "8a3de6e8d11b22ff9edc6d916f890800597d60f8b2da1caf2955c274638d6412" dependencies = [ "cfg-if", "libc", "redox_syscall", - "windows-sys 0.42.0", + "windows-sys 0.45.0", ] [[package]] @@ -2170,7 +2182,7 @@ dependencies = [ "Inflector", "array-bytes", "chrono", - "clap 4.1.4", + "clap 4.1.8", "comfy-table", "frame-benchmarking", "frame-support", @@ -2261,7 +2273,7 @@ dependencies = [ name = "frame-election-solution-type-fuzzer" version = "2.0.0-alpha.5" dependencies = [ - "clap 4.1.4", + "clap 4.1.8", "frame-election-provider-solution-type", "frame-election-provider-support", "frame-support", @@ -2725,22 +2737,22 @@ dependencies = [ [[package]] name = "ghash" -version = "0.3.1" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97304e4cd182c3846f7575ced3890c53012ce534ad9114046b0a9e00bb30a375" +checksum = "1583cc1656d7839fd3732b80cf4f38850336cdb9b8ded1cd399ca62958de3c99" dependencies = [ "opaque-debug 0.3.0", - "polyval 0.4.5", + "polyval 0.5.3", ] [[package]] name = "ghash" -version = "0.4.4" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1583cc1656d7839fd3732b80cf4f38850336cdb9b8ded1cd399ca62958de3c99" +checksum = "d930750de5717d2dd0b8c0d42c076c0e884c81a73e6cab859bbd2339c71e3e40" dependencies = [ "opaque-debug 0.3.0", - "polyval 0.5.3", + "polyval 0.6.0", ] [[package]] @@ -2756,9 +2768,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.27.1" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "221996f774192f0f718773def8201c4ae31f02616a54ccfc2d358bb0e5cefdec" +checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" [[package]] name = "git2" @@ -2805,9 +2817,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.15" +version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f9f29bc9dda355256b2916cf526ab02ce0aeaaaf2bad60d65ef3f12f11dd0f4" +checksum = "5be7b54589b581f624f566bf5d8eb2bab1db736c51528720b6bd36b96b55924d" dependencies = [ "bytes", "fnv", @@ -2901,9 +2913,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "856b5cb0902c2b6d65d5fd97dfa30f9b70c7538e770b98eab5ed52d8db923e01" +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" [[package]] name = "hex" @@ -2930,16 +2942,6 @@ dependencies = [ "digest 0.9.0", ] -[[package]] -name = "hmac" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1441c6b1e930e2817404b5046f1f989899143a12bf92de603b69f4e0aee1e15" -dependencies = [ - "crypto-mac 0.10.1", - "digest 0.9.0", -] - [[package]] name = "hmac" version = "0.11.0" @@ -2995,9 +2997,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" +checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" dependencies = [ "bytes", "fnv", @@ -3204,6 +3206,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e04e2fd2b8188ea827b32ef11de88377086d690286ab35747ef7f9bf3ccb590" +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array 0.14.6", +] + [[package]] name = "instant" version = "0.1.12" @@ -3283,11 +3294,11 @@ checksum = "30e22bd8629359895450b59ea7a776c850561b96a3b1d31321c1949d9e6c9146" [[package]] name = "is-terminal" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22e18b0a45d56fe973d6db23972bf5bc46f988a4a2385deac9cc29572f09daef" +checksum = "21b6b32576413a8e69b90e952e4a026476040d81017b80445deda5f2d3921857" dependencies = [ - "hermit-abi 0.3.0", + "hermit-abi 0.3.1", "io-lifetimes 1.0.5", "rustix 0.36.8", "windows-sys 0.45.0", @@ -3685,14 +3696,14 @@ dependencies = [ "futures-timer", "getrandom 0.2.8", "instant", - "libp2p-core", + "libp2p-core 0.38.0", "libp2p-dns", "libp2p-identify", "libp2p-kad", "libp2p-mdns", "libp2p-metrics", "libp2p-mplex", - "libp2p-noise", + "libp2p-noise 0.41.0", "libp2p-ping", "libp2p-quic", "libp2p-request-response", @@ -3702,7 +3713,7 @@ dependencies = [ "libp2p-webrtc", "libp2p-websocket", "libp2p-yamux", - "multiaddr", + "multiaddr 0.16.0", "parking_lot 0.12.1", "pin-project", "smallvec", @@ -3723,8 +3734,42 @@ dependencies = [ "futures-timer", "instant", "log", - "multiaddr", - "multihash", + "multiaddr 0.16.0", + "multihash 0.16.3", + "multistream-select", + "once_cell", + "parking_lot 0.12.1", + "pin-project", + "prost", + "prost-build", + "rand 0.8.5", + "rw-stream-sink", + "sec1", + "sha2 0.10.6", + "smallvec", + "thiserror", + "unsigned-varint", + "void", + "zeroize", +] + +[[package]] +name = "libp2p-core" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "881d9a54e97d97cdaa4125d48269d97ca8c40e5fefec6b85b30440dc60cc551f" +dependencies = [ + "asn1_der", + "bs58", + "ed25519-dalek", + "either", + "fnv", + "futures", + "futures-timer", + "instant", + "log", + "multiaddr 0.17.0", + "multihash 0.17.0", "multistream-select", "once_cell", "parking_lot 0.12.1", @@ -3749,7 +3794,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e42a271c1b49f789b92f7fc87749fa79ce5c7bdc88cbdfacb818a4bca47fec5" dependencies = [ "futures", - "libp2p-core", + "libp2p-core 0.38.0", "log", "parking_lot 0.12.1", "smallvec", @@ -3765,7 +3810,7 @@ dependencies = [ "asynchronous-codec", "futures", "futures-timer", - "libp2p-core", + "libp2p-core 0.38.0", "libp2p-swarm", "log", "lru", @@ -3791,7 +3836,7 @@ dependencies = [ "futures", "futures-timer", "instant", - "libp2p-core", + "libp2p-core 0.38.0", "libp2p-swarm", "log", "prost", @@ -3814,7 +3859,7 @@ dependencies = [ "data-encoding", "futures", "if-watch", - "libp2p-core", + "libp2p-core 0.38.0", "libp2p-swarm", "log", "rand 0.8.5", @@ -3831,7 +3876,7 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ad8a64f29da86005c86a4d2728b8a0719e9b192f4092b609fd8790acb9dec55" dependencies = [ - "libp2p-core", + "libp2p-core 0.38.0", "libp2p-identify", "libp2p-kad", "libp2p-ping", @@ -3848,7 +3893,7 @@ dependencies = [ "asynchronous-codec", "bytes", "futures", - "libp2p-core", + "libp2p-core 0.38.0", "log", "nohash-hasher", "parking_lot 0.12.1", @@ -3866,7 +3911,30 @@ dependencies = [ "bytes", "curve25519-dalek 3.2.0", "futures", - "libp2p-core", + "libp2p-core 0.38.0", + "log", + "once_cell", + "prost", + "prost-build", + "rand 0.8.5", + "sha2 0.10.6", + "snow", + "static_assertions", + "thiserror", + "x25519-dalek 1.1.1", + "zeroize", +] + +[[package]] +name = "libp2p-noise" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1216f9ec823ac7a2289b954674c54cbce81c9e45920b4fcf173018ede4295246" +dependencies = [ + "bytes", + "curve25519-dalek 3.2.0", + "futures", + "libp2p-core 0.39.0", "log", "once_cell", "prost", @@ -3889,7 +3957,7 @@ dependencies = [ "futures", "futures-timer", "instant", - "libp2p-core", + "libp2p-core 0.38.0", "libp2p-swarm", "log", "rand 0.8.5", @@ -3898,15 +3966,15 @@ dependencies = [ [[package]] name = "libp2p-quic" -version = "0.7.0-alpha" +version = "0.7.0-alpha.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01e7c867e95c8130667b24409d236d37598270e6da69b3baf54213ba31ffca59" +checksum = "5971f629ff7519f4d4889a7c981f0dc09c6ad493423cd8a13ee442de241bc8c8" dependencies = [ "bytes", "futures", "futures-timer", "if-watch", - "libp2p-core", + "libp2p-core 0.39.0", "libp2p-tls", "log", "parking_lot 0.12.1", @@ -3927,7 +3995,7 @@ dependencies = [ "bytes", "futures", "instant", - "libp2p-core", + "libp2p-core 0.38.0", "libp2p-swarm", "log", "rand 0.8.5", @@ -3946,7 +4014,7 @@ dependencies = [ "futures", "futures-timer", "instant", - "libp2p-core", + "libp2p-core 0.38.0", "libp2p-swarm-derive", "log", "pin-project", @@ -3978,7 +4046,7 @@ dependencies = [ "futures-timer", "if-watch", "libc", - "libp2p-core", + "libp2p-core 0.38.0", "log", "socket2", "tokio", @@ -3986,13 +4054,13 @@ dependencies = [ [[package]] name = "libp2p-tls" -version = "0.1.0-alpha" +version = "0.1.0-alpha.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7905ce0d040576634e8a3229a7587cc8beab83f79db6023800f1792895defa8" +checksum = "e9baf6f6292149e124ee737d9a79dbee783f29473fc368c7faad9d157841078a" dependencies = [ "futures", "futures-rustls", - "libp2p-core", + "libp2p-core 0.39.0", "rcgen 0.10.0", "ring", "rustls 0.20.8", @@ -4010,7 +4078,7 @@ checksum = "1bb1a35299860e0d4b3c02a3e74e3b293ad35ae0cee8a056363b0c862d082069" dependencies = [ "futures", "js-sys", - "libp2p-core", + "libp2p-core 0.38.0", "parity-send-wrapper", "wasm-bindgen", "wasm-bindgen-futures", @@ -4018,9 +4086,9 @@ dependencies = [ [[package]] name = "libp2p-webrtc" -version = "0.4.0-alpha" +version = "0.4.0-alpha.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb6cd86dd68cba72308ea05de1cebf3ba0ae6e187c40548167955d4e3970f6a" +checksum = "db4401ec550d36f413310ba5d4bf564bb21f89fb1601cadb32b2300f8bc1eb5b" dependencies = [ "async-trait", "asynchronous-codec", @@ -4029,10 +4097,10 @@ dependencies = [ "futures-timer", "hex", "if-watch", - "libp2p-core", - "libp2p-noise", + "libp2p-core 0.39.0", + "libp2p-noise 0.42.0", "log", - "multihash", + "multihash 0.17.0", "prost", "prost-build", "prost-codec", @@ -4056,7 +4124,7 @@ dependencies = [ "either", "futures", "futures-rustls", - "libp2p-core", + "libp2p-core 0.38.0", "log", "parking_lot 0.12.1", "quicksink", @@ -4073,7 +4141,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4f63594a0aa818642d9d4915c791945053877253f08a3626f13416b5cd928a29" dependencies = [ "futures", - "libp2p-core", + "libp2p-core 0.38.0", "log", "parking_lot 0.12.1", "thiserror", @@ -4082,9 +4150,9 @@ dependencies = [ [[package]] name = "librocksdb-sys" -version = "0.8.0+7.4.4" +version = "0.8.3+7.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "611804e4666a25136fcc5f8cf425ab4d26c7f74ea245ffe92ea23b85b6420b5d" +checksum = "557b255ff04123fcc176162f56ed0c9cd42d8f357cf55b3fabeb60f7413741b3" dependencies = [ "bindgen", "bzip2-sys", @@ -4374,6 +4442,15 @@ dependencies = [ "autocfg", ] +[[package]] +name = "memoffset" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" +dependencies = [ + "autocfg", +] + [[package]] name = "memory-db" version = "0.31.0" @@ -4419,14 +4496,14 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" +checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" dependencies = [ "libc", "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.42.0", + "windows-sys 0.45.0", ] [[package]] @@ -4505,7 +4582,25 @@ dependencies = [ "byteorder", "data-encoding", "multibase", - "multihash", + "multihash 0.16.3", + "percent-encoding", + "serde", + "static_assertions", + "unsigned-varint", + "url", +] + +[[package]] +name = "multiaddr" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b53e0cc5907a5c216ba6584bf74be8ab47d6d6289f72793b2dddbf15dc3bf8c" +dependencies = [ + "arrayref", + "byteorder", + "data-encoding", + "multibase", + "multihash 0.17.0", "percent-encoding", "serde", "static_assertions", @@ -4541,6 +4636,19 @@ dependencies = [ "unsigned-varint", ] +[[package]] +name = "multihash" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835d6ff01d610179fbce3de1694d007e500bf33a7f29689838941d6bf783ae40" +dependencies = [ + "core2", + "digest 0.10.6", + "multihash-derive", + "sha2 0.10.6", + "unsigned-varint", +] + [[package]] name = "multihash-derive" version = "0.8.1" @@ -4708,7 +4816,7 @@ name = "node-bench" version = "0.9.0-dev" dependencies = [ "array-bytes", - "clap 4.1.4", + "clap 4.1.8", "derive_more", "fs_extra", "futures", @@ -4745,7 +4853,7 @@ version = "3.0.0-dev" dependencies = [ "array-bytes", "assert_cmd", - "clap 4.1.4", + "clap 4.1.8", "clap_complete", "criterion", "frame-benchmarking-cli", @@ -4786,6 +4894,7 @@ dependencies = [ "sc-keystore", "sc-network", "sc-network-common", + "sc-network-sync", "sc-rpc", "sc-service", "sc-service-test", @@ -4865,7 +4974,7 @@ dependencies = [ name = "node-inspect" version = "0.9.0-dev" dependencies = [ - "clap 4.1.4", + "clap 4.1.8", "parity-scale-codec", "sc-cli", "sc-client-api", @@ -4924,7 +5033,7 @@ dependencies = [ name = "node-runtime-generate-bags" version = "3.0.0" dependencies = [ - "clap 4.1.4", + "clap 4.1.8", "generate-bags", "kitchensink-runtime", ] @@ -4933,7 +5042,7 @@ dependencies = [ name = "node-template" version = "4.0.0-dev" dependencies = [ - "clap 4.1.4", + "clap 4.1.8", "frame-benchmarking", "frame-benchmarking-cli", "frame-system", @@ -5190,9 +5299,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.17.0" +version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" [[package]] name = "oorandom" @@ -6799,9 +6908,9 @@ dependencies = [ [[package]] name = "parity-scale-codec" -version = "3.3.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3840933452adf7b3b9145e27086a5a3376c619dca1a21b1e5a5af0d54979bed" +checksum = "637935964ff85a605d114591d4d2c13c5d1ba2806dae97cea6bf180238a749ac" dependencies = [ "arrayvec 0.7.2", "bitvec", @@ -6946,9 +7055,9 @@ checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" [[package]] name = "pest" -version = "2.5.4" +version = "2.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ab62d2fa33726dbe6321cc97ef96d8cde531e3eeaf858a058de53a8a6d40d8f" +checksum = "028accff104c4e513bad663bbcd2ad7cfd5304144404c31ed0a77ac103d00660" dependencies = [ "thiserror", "ucd-trie", @@ -6956,9 +7065,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.5.4" +version = "2.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bf026e2d0581559db66d837fe5242320f525d85c76283c61f4d51a1238d65ea" +checksum = "2ac3922aac69a40733080f53c1ce7f91dcf57e1a5f6c52f421fadec7fbdc4b69" dependencies = [ "pest", "pest_generator", @@ -6966,9 +7075,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.5.4" +version = "2.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b27bd18aa01d91c8ed2b61ea23406a676b42d82609c6e2581fba42f0c15f17f" +checksum = "d06646e185566b5961b4058dd107e0a7f56e77c3f484549fb119867773c0f202" dependencies = [ "pest", "pest_meta", @@ -6979,9 +7088,9 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.5.4" +version = "2.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f02b677c1859756359fc9983c2e56a0237f18624a3789528804406b7e915e5d" +checksum = "e6f60b2ba541577e2a0c307c8f39d1439108120eb7903adeb6497fa880c59616" dependencies = [ "once_cell", "pest", @@ -7114,30 +7223,31 @@ checksum = "048aeb476be11a4b6ca432ca569e375810de9294ae78f4774e78ea98a9246ede" dependencies = [ "cpufeatures", "opaque-debug 0.3.0", - "universal-hash", + "universal-hash 0.4.1", ] [[package]] name = "polyval" -version = "0.4.5" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eebcc4aa140b9abd2bc40d9c3f7ccec842679cd79045ac3a7ac698c1a064b7cd" +checksum = "8419d2b623c7c0896ff2d5d96e2cb4ede590fed28fcc34934f4c33c036e620a1" dependencies = [ - "cpuid-bool", + "cfg-if", + "cpufeatures", "opaque-debug 0.3.0", - "universal-hash", + "universal-hash 0.4.1", ] [[package]] name = "polyval" -version = "0.5.3" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8419d2b623c7c0896ff2d5d96e2cb4ede590fed28fcc34934f4c33c036e620a1" +checksum = "7ef234e08c11dfcb2e56f79fd70f6f2eb7f025c0ce2333e82f4f0518ecad30c6" dependencies = [ "cfg-if", "cpufeatures", "opaque-debug 0.3.0", - "universal-hash", + "universal-hash 0.5.0", ] [[package]] @@ -7293,9 +7403,9 @@ dependencies = [ [[package]] name = "prost" -version = "0.11.6" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21dc42e00223fc37204bd4aa177e69420c604ca4a183209a8f9de30c6d934698" +checksum = "e48e50df39172a3e7eb17e14642445da64996989bc212b583015435d39a58537" dependencies = [ "bytes", "prost-derive", @@ -7303,9 +7413,9 @@ dependencies = [ [[package]] name = "prost-build" -version = "0.11.6" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3f8ad728fb08fe212df3c05169e940fbb6d9d16a877ddde14644a983ba2012e" +checksum = "2c828f93f5ca4826f97fedcbd3f9a536c16b12cff3dbbb4a007f932bbad95b12" dependencies = [ "bytes", "heck", @@ -7338,9 +7448,9 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.11.6" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bda8c0881ea9f722eb9629376db3d0b903b462477c1aafcb0566610ac28ac5d" +checksum = "4ea9b0f8cbe5e15a8a042d030bd96668db28ecb567ec37d691971ff5731d2b1b" dependencies = [ "anyhow", "itertools", @@ -7351,11 +7461,10 @@ dependencies = [ [[package]] name = "prost-types" -version = "0.11.6" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e0526209433e96d83d750dd81a99118edbc55739e7e61a46764fd2ad537788" +checksum = "379119666929a1afd7a043aa6cf96fa67a6dce9af60c88095a4686dbce4c9c88" dependencies = [ - "bytes", "prost", ] @@ -7553,7 +7662,7 @@ checksum = "6413f3de1edee53342e6138e75b56d32e7bc6e332b3bd62d497b1929d4cfbcdd" dependencies = [ "pem", "ring", - "time 0.3.17", + "time 0.3.20", "x509-parser 0.13.2", "yasna", ] @@ -7566,7 +7675,7 @@ checksum = "ffbe84efe2f38dea12e9bfc1f65377fdf03e53a18cb3b995faedf7934c7e785b" dependencies = [ "pem", "ring", - "time 0.3.17", + "time 0.3.20", "yasna", ] @@ -7660,15 +7769,6 @@ dependencies = [ "winapi", ] -[[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 = "resolv-conf" version = "0.7.0" @@ -8070,7 +8170,7 @@ version = "0.10.0-dev" dependencies = [ "array-bytes", "chrono", - "clap 4.1.4", + "clap 4.1.8", "fdlimit", "futures", "futures-timer", @@ -8323,6 +8423,7 @@ dependencies = [ "sc-network", "sc-network-common", "sc-network-gossip", + "sc-network-sync", "sc-network-test", "sc-utils", "serde", @@ -8734,6 +8835,7 @@ dependencies = [ name = "sc-network-common" version = "0.10.0-dev" dependencies = [ + "array-bytes", "async-trait", "bitflags", "bytes", @@ -8745,6 +8847,7 @@ dependencies = [ "prost-build", "sc-consensus", "sc-peerset", + "sc-utils", "serde", "smallvec", "sp-blockchain", @@ -8752,7 +8855,9 @@ dependencies = [ "sp-consensus-grandpa", "sp-runtime", "substrate-prometheus-endpoint", + "tempfile", "thiserror", + "zeroize", ] [[package]] @@ -8803,6 +8908,7 @@ dependencies = [ "async-trait", "fork-tree", "futures", + "futures-timer", "libp2p", "log", "lru", @@ -9137,6 +9243,7 @@ dependencies = [ "sc-executor", "sc-network", "sc-network-common", + "sc-network-sync", "sc-service", "sc-transaction-pool-api", "sp-api", @@ -9169,7 +9276,7 @@ dependencies = [ name = "sc-storage-monitor" version = "0.1.0" dependencies = [ - "clap 4.1.4", + "clap 4.1.8", "fs4", "futures", "log", @@ -9565,9 +9672,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.92" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7434af0dc1cbd59268aa98b4c22c131c0584d2232f6fb166efb993e2832e896a" +checksum = "cad406b69c91885b5107daf2c29572f6c8cdb3c66826821e286c533490c0bc76" dependencies = [ "itoa", "ryu", @@ -9587,6 +9694,17 @@ dependencies = [ "opaque-debug 0.3.0", ] +[[package]] +name = "sha1" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.6", +] + [[package]] name = "sha2" version = "0.8.2" @@ -9650,9 +9768,9 @@ checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" [[package]] name = "signal-hook-registry" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" dependencies = [ "libc", ] @@ -9688,9 +9806,9 @@ checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" [[package]] name = "slab" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" dependencies = [ "autocfg", ] @@ -10231,7 +10349,7 @@ dependencies = [ name = "sp-npos-elections-fuzzer" version = "2.0.0-alpha.5" dependencies = [ - "clap 4.1.4", + "clap 4.1.8", "honggfuzz", "parity-scale-codec", "rand 0.8.5", @@ -10588,9 +10706,9 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" [[package]] name = "spin" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f6002a767bff9e83f8eeecf883ecb8011875a21ae8da43bffb817a57e78cc09" +checksum = "7dccf47db1b41fa1573ed27ccf5e08e3ca771cb994f776668c5ebda893b248fc" [[package]] name = "spki" @@ -10604,9 +10722,9 @@ dependencies = [ [[package]] name = "ss58-registry" -version = "1.38.0" +version = "1.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e40c020d72bc0a9c5660bb71e4a6fdef081493583062c474740a7d59f55f0e7b" +checksum = "ecf0bd63593ef78eca595a7fc25e9a443ca46fe69fd472f8f09f5245cdcd769d" dependencies = [ "Inflector", "num-format", @@ -10708,7 +10826,7 @@ dependencies = [ name = "subkey" version = "3.0.0" dependencies = [ - "clap 4.1.4", + "clap 4.1.8", "sc-cli", ] @@ -10736,7 +10854,7 @@ dependencies = [ name = "substrate-frame-cli" version = "4.0.0-dev" dependencies = [ - "clap 4.1.4", + "clap 4.1.8", "frame-support", "frame-system", "sc-cli", @@ -10997,9 +11115,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" -version = "1.0.107" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", "quote", @@ -11047,22 +11165,21 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "target-lexicon" -version = "0.12.5" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9410d0f6853b1d94f0e519fb95df60f29d2c1eff2d921ffdf01a4c8a3b54f12d" +checksum = "8ae9980cab1db3fceee2f6c6f643d5d8de2997c58ee8d25fb0cc8a9e9e7348e5" [[package]] name = "tempfile" -version = "3.3.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +checksum = "af18f7ae1acd354b992402e9ec5864359d693cd8a79dcbef59f76891701c1e95" dependencies = [ "cfg-if", "fastrand", - "libc", "redox_syscall", - "remove_dir_all", - "winapi", + "rustix 0.36.8", + "windows-sys 0.42.0", ] [[package]] @@ -11114,10 +11231,11 @@ checksum = "3bf63baf9f5039dadc247375c29eb13706706cfde997d0330d05aa63a77d8820" [[package]] name = "thread_local" -version = "1.1.4" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" dependencies = [ + "cfg-if", "once_cell", ] @@ -11153,9 +11271,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.17" +version = "0.3.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376" +checksum = "cd0cbfecb4d19b5ea75bb31ad904eb5b9fa13f21079c3b92017ebdf4999a5890" dependencies = [ "itoa", "serde", @@ -11171,9 +11289,9 @@ checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" [[package]] name = "time-macros" -version = "0.2.6" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d967f99f534ca7e495c575c62638eebc2898a8c84c119b89e250477bc4ba16b2" +checksum = "fd80a657e71da814b8e5d60d3374fc6d35045062245d80224748ae522dd76f36" dependencies = [ "time-core", ] @@ -11275,9 +11393,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.11" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d660770404473ccd7bc9f8b28494a811bc18542b915c0855c51e8f419d5223ce" +checksum = "8fb52b74f05dbf495a8fba459fdc331812b96aa086d9eb78101fa0d4569c3313" dependencies = [ "futures-core", "pin-project-lite 0.2.9", @@ -11300,9 +11418,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.4" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bb2e075f03b3d66d8d8785356224ba688d2906a371015e225beeb65ca92c740" +checksum = "5427d89453009325de0d8f342c9490009f76e999cb7672d77e46267448f7e6b2" dependencies = [ "bytes", "futures-core", @@ -11574,7 +11692,7 @@ name = "try-runtime-cli" version = "0.10.0-dev" dependencies = [ "async-trait", - "clap 4.1.4", + "clap 4.1.8", "frame-remote-externalities", "frame-try-runtime", "hex", @@ -11726,6 +11844,16 @@ dependencies = [ "subtle", ] +[[package]] +name = "universal-hash" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d3160b73c9a19f7e2939a2fdad446c57c1bbbbf4d919d3213ff1267a580d8b5" +dependencies = [ + "crypto-common", + "subtle", +] + [[package]] name = "unsigned-varint" version = "0.7.1" @@ -11919,9 +12047,9 @@ checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" [[package]] name = "wasm-encoder" -version = "0.22.1" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a584273ccc2d9311f1dd19dc3fb26054661fa3e373d53ede5d1144ba07a9acd" +checksum = "68f7d56227d910901ce12dfd19acc40c12687994dfb3f57c90690f80be946ec5" dependencies = [ "leb128", ] @@ -12017,7 +12145,7 @@ version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01bf50edb2ea9d922aa75a7bf3c15e26a6c9e2d18c56e862b49737a582901729" dependencies = [ - "spin 0.9.4", + "spin 0.9.5", "wasmi_arena", "wasmi_core 0.5.0", "wasmparser-nostd", @@ -12263,9 +12391,9 @@ dependencies = [ [[package]] name = "wast" -version = "52.0.3" +version = "54.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15942180f265280eede7bc38b239e9770031d1821c02d905284216c645316430" +checksum = "3d48d9d731d835f4f8dacbb8de7d47be068812cb9877f5c60d408858778d8d2a" dependencies = [ "leb128", "memchr", @@ -12275,9 +12403,9 @@ dependencies = [ [[package]] name = "wat" -version = "1.0.57" +version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37212100d4cbe6f0f6ff6e707f1e5a5b5b675f0451231ed9e4235e234e127ed3" +checksum = "d1db2e3ed05ea31243761439194bec3af6efbbaf87c4c8667fb879e4f23791a0" dependencies = [ "wast", ] @@ -12347,7 +12475,7 @@ dependencies = [ "sha2 0.10.6", "stun", "thiserror", - "time 0.3.17", + "time 0.3.20", "tokio", "turn", "url", @@ -12379,12 +12507,12 @@ dependencies = [ [[package]] name = "webrtc-dtls" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7021987ae0a2ed6c8cd33f68e98e49bb6e74ffe9543310267b48a1bbe3900e5f" +checksum = "942be5bd85f072c3128396f6e5a9bfb93ca8c1939ded735d177b7bcba9a13d05" dependencies = [ "aes 0.6.0", - "aes-gcm 0.8.0", + "aes-gcm 0.10.1", "async-trait", "bincode", "block-modes", @@ -12394,7 +12522,7 @@ dependencies = [ "der-parser 8.1.0", "elliptic-curve", "hkdf", - "hmac 0.10.1", + "hmac 0.12.1", "log", "oid-registry 0.6.1", "p256", @@ -12406,8 +12534,8 @@ dependencies = [ "rustls 0.19.1", "sec1", "serde", - "sha-1", - "sha2 0.9.9", + "sha1", + "sha2 0.10.6", "signature", "subtle", "thiserror", @@ -12420,9 +12548,9 @@ dependencies = [ [[package]] name = "webrtc-ice" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "494483fbb2f5492620871fdc78b084aed8807377f6e3fe88b2e49f0a9c9c41d7" +checksum = "465a03cc11e9a7d7b4f9f99870558fe37a102b65b93f8045392fef7c67b39e80" dependencies = [ "arc-swap", "async-trait", @@ -12555,9 +12683,9 @@ dependencies = [ [[package]] name = "wide" -version = "0.7.6" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "feff0a412894d67223777b6cc8d68c0dab06d52d95e9890d5f2d47f10dd9366c" +checksum = "b689b6c49d6549434bf944e6b0f39238cf63693cb7a147e9d887507fffa3b223" dependencies = [ "bytemuck", "safe_arch", @@ -12780,7 +12908,7 @@ dependencies = [ "ring", "rusticata-macros", "thiserror", - "time 0.3.17", + "time 0.3.20", ] [[package]] @@ -12798,7 +12926,7 @@ dependencies = [ "oid-registry 0.6.1", "rusticata-macros", "thiserror", - "time 0.3.17", + "time 0.3.20", ] [[package]] @@ -12827,7 +12955,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aed2e7a52e3744ab4d0c05c20aa065258e84c49fd4226f5191b2ed29712710b4" dependencies = [ - "time 0.3.17", + "time 0.3.20", ] [[package]] @@ -12872,9 +13000,9 @@ dependencies = [ [[package]] name = "zstd-sys" -version = "2.0.6+zstd.1.5.2" +version = "2.0.7+zstd.1.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68a3f9792c0c3dc6c165840a75f47ae1f4da402c2d006881129579f6597e801b" +checksum = "94509c3ba2fe55294d752b79842c530ccfab760192521df74a081a78d2b3c7f5" dependencies = [ "cc", "libc", diff --git a/bin/node-template/node/src/service.rs b/bin/node-template/node/src/service.rs index 98485a7ad674c..34e4e566d92fc 100644 --- a/bin/node-template/node/src/service.rs +++ b/bin/node-template/node/src/service.rs @@ -192,7 +192,7 @@ pub fn new_full(mut config: Configuration) -> Result Vec::default(), )); - let (network, system_rpc_tx, tx_handler_controller, network_starter) = + let (network, system_rpc_tx, tx_handler_controller, network_starter, sync_service) = sc_service::build_network(sc_service::BuildNetworkParams { config: &config, client: client.clone(), @@ -240,6 +240,7 @@ pub fn new_full(mut config: Configuration) -> Result backend, system_rpc_tx, tx_handler_controller, + sync_service: sync_service.clone(), config, telemetry: telemetry.as_mut(), })?; @@ -276,8 +277,8 @@ pub fn new_full(mut config: Configuration) -> Result force_authoring, backoff_authoring_blocks, keystore: keystore_container.sync_keystore(), - sync_oracle: network.clone(), - justification_sync_link: network.clone(), + sync_oracle: sync_service.clone(), + justification_sync_link: sync_service.clone(), block_proposal_slot_portion: SlotProportion::new(2f32 / 3f32), max_block_proposal_slot_portion: None, telemetry: telemetry.as_ref().map(|x| x.handle()), @@ -320,6 +321,7 @@ pub fn new_full(mut config: Configuration) -> Result config: grandpa_config, link: grandpa_link, network, + sync: Arc::new(sync_service), voting_rule: sc_consensus_grandpa::VotingRulesBuilder::default().build(), prometheus_registry, shared_voter_state: SharedVoterState::empty(), diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index b93019b7cc219..4451935c36035 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -68,6 +68,7 @@ sc-transaction-pool = { version = "4.0.0-dev", path = "../../../client/transacti 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-network-sync = { version = "0.10.0-dev", path = "../../../client/network/sync" } sc-consensus-slots = { version = "0.10.0-dev", path = "../../../client/consensus/slots" } sc-consensus-babe = { version = "0.10.0-dev", path = "../../../client/consensus/babe" } grandpa = { version = "0.10.0-dev", package = "sc-consensus-grandpa", path = "../../../client/consensus/grandpa" } diff --git a/bin/node/cli/src/chain_spec.rs b/bin/node/cli/src/chain_spec.rs index 178b97823fb2e..4732e12f9c76e 100644 --- a/bin/node/cli/src/chain_spec.rs +++ b/bin/node/cli/src/chain_spec.rs @@ -479,12 +479,13 @@ pub(crate) mod tests { sp_tracing::try_init_simple(); sc_service_test::connectivity(integration_test_config_with_two_authorities(), |config| { - let NewFullBase { task_manager, client, network, transaction_pool, .. } = + let NewFullBase { task_manager, client, network, sync, transaction_pool, .. } = new_full_base(config, false, |_, _| ())?; Ok(sc_service_test::TestNetComponents::new( task_manager, client, network, + sync, transaction_pool, )) }); diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs index 268a170a82199..6e000a4755ecf 100644 --- a/bin/node/cli/src/service.rs +++ b/bin/node/cli/src/service.rs @@ -35,6 +35,7 @@ use sc_network::NetworkService; use sc_network_common::{ protocol::event::Event, service::NetworkEventStream, sync::warp::WarpSyncParams, }; +use sc_network_sync::SyncingService; use sc_service::{config::Configuration, error::Error as ServiceError, RpcHandlers, TaskManager}; use sc_telemetry::{Telemetry, TelemetryWorker}; use sp_api::ProvideRuntimeApi; @@ -303,6 +304,8 @@ pub struct NewFullBase { pub client: Arc, /// The networking service of the node. pub network: Arc::Hash>>, + /// The syncing service of the node. + pub sync: Arc>, /// The transaction pool of the node. pub transaction_pool: Arc, /// The rpc handlers of the node. @@ -353,7 +356,7 @@ pub fn new_full_base( Vec::default(), )); - let (network, system_rpc_tx, tx_handler_controller, network_starter) = + let (network, system_rpc_tx, tx_handler_controller, network_starter, sync_service) = sc_service::build_network(sc_service::BuildNetworkParams { config: &config, client: client.clone(), @@ -392,6 +395,7 @@ pub fn new_full_base( task_manager: &mut task_manager, system_rpc_tx, tx_handler_controller, + sync_service: sync_service.clone(), telemetry: telemetry.as_mut(), })?; @@ -434,8 +438,8 @@ pub fn new_full_base( select_chain, env: proposer, block_import, - sync_oracle: network.clone(), - justification_sync_link: network.clone(), + sync_oracle: sync_service.clone(), + justification_sync_link: sync_service.clone(), create_inherent_data_providers: move |parent, ()| { let client_clone = client_clone.clone(); async move { @@ -531,6 +535,7 @@ pub fn new_full_base( config, link: grandpa_link, network: network.clone(), + sync: Arc::new(sync_service.clone()), telemetry: telemetry.as_ref().map(|x| x.handle()), voting_rule: grandpa::VotingRulesBuilder::default().build(), prometheus_registry, @@ -547,7 +552,14 @@ pub fn new_full_base( } network_starter.start_network(); - Ok(NewFullBase { task_manager, client, network, transaction_pool, rpc_handlers }) + Ok(NewFullBase { + task_manager, + client, + network, + sync: sync_service, + transaction_pool, + rpc_handlers, + }) } /// Builds a new service for a full client. @@ -627,7 +639,7 @@ mod tests { chain_spec, |config| { let mut setup_handles = None; - let NewFullBase { task_manager, client, network, transaction_pool, .. } = + let NewFullBase { task_manager, client, network, sync, transaction_pool, .. } = new_full_base( config, false, @@ -641,6 +653,7 @@ mod tests { task_manager, client, network, + sync, transaction_pool, ); Ok((node, setup_handles.unwrap())) @@ -807,12 +820,13 @@ mod tests { sc_service_test::consensus( crate::chain_spec::tests::integration_test_config_with_two_authorities(), |config| { - let NewFullBase { task_manager, client, network, transaction_pool, .. } = + let NewFullBase { task_manager, client, network, sync, transaction_pool, .. } = new_full_base(config, false, |_, _| ())?; Ok(sc_service_test::TestNetComponents::new( task_manager, client, network, + sync, transaction_pool, )) }, diff --git a/client/cli/src/arg_enums.rs b/client/cli/src/arg_enums.rs index c3399a89680d1..472c1722f9ed8 100644 --- a/client/cli/src/arg_enums.rs +++ b/client/cli/src/arg_enums.rs @@ -251,15 +251,19 @@ pub enum SyncMode { Warp, } -impl Into for SyncMode { - fn into(self) -> sc_network::config::SyncMode { +impl Into for SyncMode { + fn into(self) -> sc_network_common::config::SyncMode { match self { - SyncMode::Full => sc_network::config::SyncMode::Full, - SyncMode::Fast => - sc_network::config::SyncMode::Fast { skip_proofs: false, storage_chain_mode: false }, - SyncMode::FastUnsafe => - sc_network::config::SyncMode::Fast { skip_proofs: true, storage_chain_mode: false }, - SyncMode::Warp => sc_network::config::SyncMode::Warp, + SyncMode::Full => sc_network_common::config::SyncMode::Full, + SyncMode::Fast => sc_network_common::config::SyncMode::Fast { + skip_proofs: false, + storage_chain_mode: false, + }, + SyncMode::FastUnsafe => sc_network_common::config::SyncMode::Fast { + skip_proofs: true, + storage_chain_mode: false, + }, + SyncMode::Warp => sc_network_common::config::SyncMode::Warp, } } } diff --git a/client/cli/src/params/network_params.rs b/client/cli/src/params/network_params.rs index 3aebee778d3f9..31b761938df84 100644 --- a/client/cli/src/params/network_params.rs +++ b/client/cli/src/params/network_params.rs @@ -18,11 +18,8 @@ use crate::{arg_enums::SyncMode, params::node_key_params::NodeKeyParams}; use clap::Args; -use sc_network::{ - config::{NetworkConfiguration, NodeKeyConfig}, - multiaddr::Protocol, -}; -use sc_network_common::config::{NonReservedPeerMode, SetConfig, TransportConfig}; +use sc_network::{config::NetworkConfiguration, multiaddr::Protocol}; +use sc_network_common::config::{NodeKeyConfig, NonReservedPeerMode, SetConfig, TransportConfig}; use sc_service::{ config::{Multiaddr, MultiaddrWithPeerId}, ChainSpec, ChainType, diff --git a/client/cli/src/params/node_key_params.rs b/client/cli/src/params/node_key_params.rs index 074b95bea0f3a..d470ef1fad12a 100644 --- a/client/cli/src/params/node_key_params.rs +++ b/client/cli/src/params/node_key_params.rs @@ -17,7 +17,7 @@ // along with this program. If not, see . use clap::Args; -use sc_network::config::{identity::ed25519, NodeKeyConfig}; +use sc_network_common::config::{identity::ed25519, NodeKeyConfig}; use sp_core::H256; use std::{path::PathBuf, str::FromStr}; @@ -92,7 +92,7 @@ impl NodeKeyParams { let secret = if let Some(node_key) = self.node_key.as_ref() { parse_ed25519_secret(node_key)? } else { - sc_network::config::Secret::File( + sc_network_common::config::Secret::File( self.node_key_file .clone() .unwrap_or_else(|| net_config_dir.join(NODE_KEY_ED25519_FILE)), @@ -111,10 +111,10 @@ 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 { +fn parse_ed25519_secret(hex: &str) -> error::Result { H256::from_str(hex).map_err(invalid_node_key).and_then(|bytes| { ed25519::SecretKey::from_bytes(bytes) - .map(sc_network::config::Secret::Input) + .map(sc_network_common::config::Secret::Input) .map_err(invalid_node_key) }) } @@ -123,7 +123,7 @@ fn parse_ed25519_secret(hex: &str) -> error::Result Ok(()), _ => Err(error::Error::Input("Unexpected node key config".into())), @@ -200,7 +200,7 @@ mod tests { let dir = PathBuf::from(net_config_dir.clone()); let typ = params.node_key_type; params.node_key(net_config_dir).and_then(move |c| match c { - NodeKeyConfig::Ed25519(sc_network::config::Secret::File(ref f)) + NodeKeyConfig::Ed25519(sc_network_common::config::Secret::File(ref f)) if typ == NodeKeyType::Ed25519 && f == &dir.join(NODE_KEY_ED25519_FILE) => Ok(()), _ => Err(error::Error::Input("Unexpected node key config".into())), diff --git a/client/consensus/aura/src/lib.rs b/client/consensus/aura/src/lib.rs index f5f70857c0ff8..e90494ddfc177 100644 --- a/client/consensus/aura/src/lib.rs +++ b/client/consensus/aura/src/lib.rs @@ -766,6 +766,11 @@ mod tests { fn peers(&self) -> &Vec { &self.peers } + + fn peers_mut(&mut self) -> &mut Vec { + &mut self.peers + } + fn mut_peers)>(&mut self, closure: F) { closure(&mut self.peers); } diff --git a/client/consensus/babe/src/tests.rs b/client/consensus/babe/src/tests.rs index 42b8730cdd9ca..fcdada94c4538 100644 --- a/client/consensus/babe/src/tests.rs +++ b/client/consensus/babe/src/tests.rs @@ -349,6 +349,11 @@ impl TestNetFactory for BabeTestNet { &self.peers } + fn peers_mut(&mut self) -> &mut Vec { + trace!(target: "babe", "Retrieving peers, mutable"); + &mut self.peers + } + fn mut_peers)>(&mut self, closure: F) { closure(&mut self.peers); } diff --git a/client/consensus/beefy/Cargo.toml b/client/consensus/beefy/Cargo.toml index d88c07df2612f..161d53777ebc1 100644 --- a/client/consensus/beefy/Cargo.toml +++ b/client/consensus/beefy/Cargo.toml @@ -25,6 +25,7 @@ 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-network-sync = { version = "0.10.0-dev", path = "../../network/sync" } sc-utils = { version = "4.0.0-dev", path = "../../utils" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-application-crypto = { version = "7.0.0", path = "../../../primitives/application-crypto" } diff --git a/client/consensus/beefy/src/lib.rs b/client/consensus/beefy/src/lib.rs index 9b627e3ff8fef..67758a4979b19 100644 --- a/client/consensus/beefy/src/lib.rs +++ b/client/consensus/beefy/src/lib.rs @@ -40,7 +40,7 @@ use sc_client_api::{Backend, BlockBackend, BlockchainEvents, FinalityNotificatio use sc_consensus::BlockImport; use sc_network::ProtocolName; use sc_network_common::service::NetworkRequest; -use sc_network_gossip::{GossipEngine, Network as GossipNetwork}; +use sc_network_gossip::{GossipEngine, Network as GossipNetwork, Syncing as GossipSyncing}; use sp_api::{HeaderT, NumberFor, ProvideRuntimeApi}; use sp_blockchain::{ Backend as BlockchainBackend, Error as ClientError, HeaderBackend, Result as ClientResult, @@ -172,9 +172,11 @@ where } /// BEEFY gadget network parameters. -pub struct BeefyNetworkParams { +pub struct BeefyNetworkParams { /// Network implementing gossip, requests and sync-oracle. pub network: Arc, + /// Syncing service implementing a sync oracle and an event stream for peers. + pub sync: Arc, /// Chain specific BEEFY gossip protocol name. See /// [`communication::beefy_protocol_name::gossip_protocol_name`]. pub gossip_protocol_name: ProtocolName, @@ -186,7 +188,7 @@ pub struct BeefyNetworkParams { } /// BEEFY gadget initialization parameters. -pub struct BeefyParams { +pub struct BeefyParams { /// BEEFY client pub client: Arc, /// Client Backend @@ -198,7 +200,7 @@ pub struct BeefyParams { /// Local key store pub key_store: Option, /// BEEFY voter network params - pub network_params: BeefyNetworkParams, + pub network_params: BeefyNetworkParams, /// Minimal delta between blocks, BEEFY should vote for pub min_block_delta: u32, /// Prometheus metric registry @@ -212,15 +214,17 @@ 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) -where +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, + N: GossipNetwork + NetworkRequest + Send + Sync + 'static, + S: GossipSyncing + SyncOracle + 'static, { let BeefyParams { client, @@ -235,14 +239,20 @@ where on_demand_justifications_handler, } = beefy_params; - let BeefyNetworkParams { network, gossip_protocol_name, justifications_protocol_name, .. } = - network_params; + let BeefyNetworkParams { + network, + sync, + 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 mut gossip_engine = sc_network_gossip::GossipEngine::new( network.clone(), + sync.clone(), gossip_protocol_name, gossip_validator.clone(), None, @@ -280,7 +290,7 @@ where backend, payload_provider, runtime, - network, + sync, key_store: key_store.into(), gossip_engine, gossip_validator, diff --git a/client/consensus/beefy/src/tests.rs b/client/consensus/beefy/src/tests.rs index e4fe16a2acfd3..fb1c45b90a83a 100644 --- a/client/consensus/beefy/src/tests.rs +++ b/client/consensus/beefy/src/tests.rs @@ -223,6 +223,10 @@ impl TestNetFactory for BeefyTestNet { &self.peers } + fn peers_mut(&mut self) -> &mut Vec { + &mut self.peers + } + fn mut_peers)>(&mut self, closure: F) { closure(&mut self.peers); } @@ -353,6 +357,7 @@ async fn voter_init_setup( Arc::new(crate::communication::gossip::GossipValidator::new(known_peers)); let mut gossip_engine = sc_network_gossip::GossipEngine::new( net.peer(0).network_service().clone(), + net.peer(0).sync_service().clone(), "/beefy/whatever", gossip_validator, None, @@ -389,6 +394,7 @@ where let network_params = crate::BeefyNetworkParams { network: peer.network_service().clone(), + sync: peer.sync_service().clone(), gossip_protocol_name: beefy_gossip_proto_name(), justifications_protocol_name: on_demand_justif_handler.protocol_name(), _phantom: PhantomData, @@ -407,7 +413,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/consensus/beefy/src/worker.rs b/client/consensus/beefy/src/worker.rs index 7f3114958647f..3f29dc7abee5c 100644 --- a/client/consensus/beefy/src/worker.rs +++ b/client/consensus/beefy/src/worker.rs @@ -33,7 +33,6 @@ use codec::{Codec, Decode, Encode}; use futures::{stream::Fuse, FutureExt, StreamExt}; use log::{debug, error, info, log_enabled, trace, warn}; use sc_client_api::{Backend, FinalityNotification, FinalityNotifications, HeaderBackend}; -use sc_network_common::service::{NetworkEventStream, NetworkRequest}; use sc_network_gossip::GossipEngine; use sc_utils::notification::NotificationReceiver; use sp_api::{BlockId, ProvideRuntimeApi}; @@ -244,11 +243,11 @@ impl VoterOracle { } } -pub(crate) struct WorkerParams { +pub(crate) struct WorkerParams { pub backend: Arc, pub payload_provider: P, pub runtime: Arc, - pub network: N, + pub sync: Arc, pub key_store: BeefyKeystore, pub gossip_engine: GossipEngine, pub gossip_validator: Arc>, @@ -296,12 +295,12 @@ impl PersistedState { } /// A BEEFY worker plays the BEEFY protocol -pub(crate) struct BeefyWorker { +pub(crate) struct BeefyWorker { // utilities backend: Arc, payload_provider: P, runtime: Arc, - network: N, + sync: Arc, key_store: BeefyKeystore, // communication @@ -330,14 +329,14 @@ pub(crate) struct BeefyWorker { persisted_state: PersistedState, } -impl BeefyWorker +impl BeefyWorker where B: Block + Codec, BE: Backend, P: PayloadProvider, + S: SyncOracle, R: ProvideRuntimeApi, R::Api: BeefyApi, - N: NetworkEventStream + NetworkRequest + SyncOracle + Send + Sync + Clone + 'static, { /// Return a new BEEFY worker instance. /// @@ -345,13 +344,13 @@ 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, runtime, key_store, - network, + sync, gossip_engine, gossip_validator, on_demand_justifications, @@ -364,7 +363,7 @@ where backend, payload_provider, runtime, - network, + sync, key_store, gossip_engine, gossip_validator, @@ -836,7 +835,7 @@ where } // Don't bother voting or requesting justifications during major sync. - if !self.network.is_major_syncing() { + if !self.sync.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: LOG_TARGET, "🥩 {}", err); @@ -1065,7 +1064,7 @@ pub(crate) mod tests { use futures::{future::poll_fn, task::Poll}; use parking_lot::Mutex; use sc_client_api::{Backend as BackendT, HeaderBackend}; - use sc_network::NetworkService; + use sc_network_sync::SyncingService; use sc_network_test::TestNetFactory; use sp_api::HeaderT; use sp_blockchain::Backend as BlockchainBackendT; @@ -1075,7 +1074,7 @@ pub(crate) mod tests { }; use sp_runtime::traits::One; use substrate_test_runtime_client::{ - runtime::{Block, Digest, DigestItem, Header, H256}, + runtime::{Block, Digest, DigestItem, Header}, Backend, }; @@ -1113,7 +1112,7 @@ pub(crate) mod tests { Backend, MmrRootProvider, TestApi, - Arc>, + Arc>, > { let keystore = create_beefy_keystore(*key); @@ -1137,10 +1136,16 @@ pub(crate) mod tests { let backend = peer.client().as_backend(); let api = Arc::new(TestApi::with_validator_set(&genesis_validator_set)); let network = peer.network_service().clone(); + let sync = peer.sync_service().clone(); 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.clone(), "/beefy/1", gossip_validator.clone(), None); + let gossip_engine = GossipEngine::new( + network.clone(), + sync.clone(), + "/beefy/1", + gossip_validator.clone(), + None, + ); let metrics = None; let on_demand_justifications = OnDemandJustificationsEngine::new( network.clone(), @@ -1169,7 +1174,7 @@ pub(crate) mod tests { gossip_engine, gossip_validator, metrics, - network, + sync: Arc::new(sync), on_demand_justifications, persisted_state, }; diff --git a/client/consensus/grandpa/src/communication/mod.rs b/client/consensus/grandpa/src/communication/mod.rs index d3ade4bf3d49d..6c7e3ea46511e 100644 --- a/client/consensus/grandpa/src/communication/mod.rs +++ b/client/consensus/grandpa/src/communication/mod.rs @@ -59,7 +59,10 @@ use crate::{ use gossip::{ FullCatchUpMessage, FullCommitMessage, GossipMessage, GossipValidator, PeerReport, VoteMessage, }; -use sc_network_common::service::{NetworkBlock, NetworkSyncForkRequest}; +use sc_network_common::{ + service::{NetworkBlock, NetworkSyncForkRequest}, + sync::SyncEventStream, +}; use sc_utils::mpsc::TracingUnboundedReceiver; use sp_consensus_grandpa::{AuthorityId, AuthoritySignature, RoundNumber, SetId as SetIdNumber}; @@ -163,24 +166,35 @@ const TELEMETRY_VOTERS_LIMIT: usize = 10; /// A handle to the network. /// -/// 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: +/// Something that provides the capabilities needed for the `gossip_network::Network` trait. +pub trait Network: GossipNetwork + Clone + Send + 'static {} + +impl Network for T +where + Block: BlockT, + T: GossipNetwork + Clone + Send + 'static, +{ +} + +/// A handle to syncing-related services. +/// +/// Something that provides the ability to set a fork sync request for a particular block. +pub trait Syncing: NetworkSyncForkRequest> + NetworkBlock> - + GossipNetwork + + SyncEventStream + Clone + Send + 'static { } -impl Network for T +impl Syncing for T where Block: BlockT, T: NetworkSyncForkRequest> + NetworkBlock> - + GossipNetwork + + SyncEventStream + Clone + Send + 'static, @@ -198,8 +212,9 @@ pub(crate) fn global_topic(set_id: SetIdNumber) -> B::Hash { } /// Bridge between the underlying network service, gossiping consensus messages and Grandpa -pub(crate) struct NetworkBridge> { +pub(crate) struct NetworkBridge, S: Syncing> { service: N, + sync: S, gossip_engine: Arc>>, validator: Arc>, @@ -225,15 +240,16 @@ pub(crate) struct NetworkBridge> { telemetry: Option, } -impl> Unpin for NetworkBridge {} +impl, S: Syncing> Unpin for NetworkBridge {} -impl> NetworkBridge { +impl, S: Syncing> NetworkBridge { /// Create a new NetworkBridge to the given NetworkService. Returns the service /// handle. /// On creation it will register previous rounds' votes with the gossip /// service taken from the VoterSetState. pub(crate) fn new( service: N, + sync: S, config: crate::Config, set_state: crate::environment::SharedVoterSetState, prometheus_registry: Option<&Registry>, @@ -246,6 +262,7 @@ impl> NetworkBridge { let validator = Arc::new(validator); let gossip_engine = Arc::new(Mutex::new(GossipEngine::new( service.clone(), + sync.clone(), protocol, validator.clone(), prometheus_registry, @@ -290,6 +307,7 @@ impl> NetworkBridge { NetworkBridge { service, + sync, gossip_engine, validator, neighbor_sender: neighbor_packet_sender, @@ -475,11 +493,11 @@ impl> NetworkBridge { hash: B::Hash, number: NumberFor, ) { - self.service.set_sync_fork_request(peers, hash, number) + self.sync.set_sync_fork_request(peers, hash, number) } } -impl> Future for NetworkBridge { +impl, S: Syncing> Future for NetworkBridge { type Output = Result<(), Error>; fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll { @@ -661,10 +679,11 @@ fn incoming_global( }) } -impl> Clone for NetworkBridge { +impl, S: Syncing> Clone for NetworkBridge { fn clone(&self) -> Self { NetworkBridge { service: self.service.clone(), + sync: self.sync.clone(), gossip_engine: self.gossip_engine.clone(), validator: Arc::clone(&self.validator), neighbor_sender: self.neighbor_sender.clone(), diff --git a/client/consensus/grandpa/src/communication/tests.rs b/client/consensus/grandpa/src/communication/tests.rs index 21e2e978c8767..843e5467910e8 100644 --- a/client/consensus/grandpa/src/communication/tests.rs +++ b/client/consensus/grandpa/src/communication/tests.rs @@ -33,6 +33,7 @@ use sc_network_common::{ NetworkBlock, NetworkEventStream, NetworkNotification, NetworkPeers, NetworkSyncForkRequest, NotificationSender, NotificationSenderError, }, + sync::{SyncEvent as SyncStreamEvent, SyncEventStream}, }; use sc_network_gossip::Validator; use sc_network_test::{Block, Hash}; @@ -153,6 +154,10 @@ impl NetworkNotification for TestNetwork { ) -> Result, NotificationSenderError> { unimplemented!(); } + + fn set_notification_handshake(&self, _protocol: ProtocolName, _handshake: Vec) { + unimplemented!(); + } } impl NetworkBlock> for TestNetwork { @@ -186,8 +191,34 @@ impl sc_network_gossip::ValidatorContext for TestNetwork { fn send_topic(&mut self, _: &PeerId, _: Hash, _: bool) {} } +#[derive(Clone)] +pub(crate) struct TestSync; + +impl SyncEventStream for TestSync { + fn event_stream( + &self, + _name: &'static str, + ) -> Pin + Send>> { + Box::pin(futures::stream::pending()) + } +} + +impl NetworkBlock> for TestSync { + fn announce_block(&self, _hash: Hash, _data: Option>) { + unimplemented!(); + } + + fn new_best_block_imported(&self, _hash: Hash, _number: NumberFor) { + unimplemented!(); + } +} + +impl NetworkSyncForkRequest> for TestSync { + fn set_sync_fork_request(&self, _peers: Vec, _hash: Hash, _number: NumberFor) {} +} + pub(crate) struct Tester { - pub(crate) net_handle: super::NetworkBridge, + pub(crate) net_handle: super::NetworkBridge, gossip_validator: Arc>, pub(crate) events: TracingUnboundedReceiver, } @@ -255,6 +286,7 @@ fn voter_set_state() -> SharedVoterSetState { pub(crate) fn make_test_network() -> (impl Future, TestNetwork) { let (tx, rx) = tracing_unbounded("test", 100_000); let net = TestNetwork { sender: tx }; + let sync = TestSync {}; #[derive(Clone)] struct Exit; @@ -267,7 +299,8 @@ pub(crate) fn make_test_network() -> (impl Future, TestNetwork) } } - let bridge = super::NetworkBridge::new(net.clone(), config(), voter_set_state(), None, None); + let bridge = + super::NetworkBridge::new(net.clone(), sync, config(), voter_set_state(), None, None); ( futures::future::ready(Tester { @@ -370,6 +403,7 @@ fn good_commit_leads_to_relay() { protocol: grandpa_protocol_name::NAME.into(), negotiated_fallback: None, role: ObservedRole::Full, + received_handshake: vec![], }); let _ = sender.unbounded_send(NetworkEvent::NotificationsReceived { @@ -387,6 +421,7 @@ fn good_commit_leads_to_relay() { protocol: grandpa_protocol_name::NAME.into(), negotiated_fallback: None, role: ObservedRole::Full, + received_handshake: vec![], }); // Announce its local set has being on the current set id through a neighbor @@ -519,6 +554,7 @@ fn bad_commit_leads_to_report() { protocol: grandpa_protocol_name::NAME.into(), negotiated_fallback: None, role: ObservedRole::Full, + received_handshake: vec![], }); let _ = sender.unbounded_send(NetworkEvent::NotificationsReceived { remote: sender_id, diff --git a/client/consensus/grandpa/src/environment.rs b/client/consensus/grandpa/src/environment.rs index 3425426617115..67820a59cc943 100644 --- a/client/consensus/grandpa/src/environment.rs +++ b/client/consensus/grandpa/src/environment.rs @@ -50,7 +50,7 @@ use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor, Zero}; use crate::{ authorities::{AuthoritySet, SharedAuthoritySet}, - communication::Network as NetworkT, + communication::{Network as NetworkT, Syncing as SyncingT}, justification::GrandpaJustification, local_authority_id, notification::GrandpaJustificationSender, @@ -423,13 +423,21 @@ impl Metrics { } /// The environment we run GRANDPA in. -pub(crate) struct Environment, SC, VR> { +pub(crate) struct Environment< + Backend, + Block: BlockT, + C, + N: NetworkT, + S: SyncingT, + SC, + VR, +> { pub(crate) client: Arc, pub(crate) select_chain: SC, pub(crate) voters: Arc>, pub(crate) config: Config, pub(crate) authority_set: SharedAuthoritySet>, - pub(crate) network: crate::communication::NetworkBridge, + pub(crate) network: crate::communication::NetworkBridge, pub(crate) set_id: SetId, pub(crate) voter_set_state: SharedVoterSetState, pub(crate) voting_rule: VR, @@ -439,7 +447,9 @@ pub(crate) struct Environment, SC, pub(crate) _phantom: PhantomData, } -impl, SC, VR> Environment { +impl, S: SyncingT, SC, VR> + Environment +{ /// Updates the voter set state using the given closure. The write lock is /// held during evaluation of the closure and the environment's voter set /// state is set to its result if successful. @@ -469,13 +479,14 @@ impl, SC, VR> Environment Environment +impl Environment where Block: BlockT, BE: BackendT, C: ClientForGrandpa, C::Api: GrandpaApi, N: NetworkT, + S: SyncingT, SC: SelectChainT, { /// Report the given equivocation to the GRANDPA runtime module. This method @@ -572,13 +583,14 @@ where } } -impl finality_grandpa::Chain> - for Environment +impl finality_grandpa::Chain> + for Environment where Block: BlockT, BE: BackendT, C: ClientForGrandpa, N: NetworkT, + S: SyncingT, SC: SelectChainT, VR: VotingRuleT, NumberFor: BlockNumberOps, @@ -630,14 +642,15 @@ where Ok(tree_route.retracted().iter().skip(1).map(|e| e.hash).collect()) } -impl voter::Environment> - for Environment +impl voter::Environment> + for Environment where Block: BlockT, B: BackendT, C: ClientForGrandpa + 'static, C::Api: GrandpaApi, N: NetworkT, + S: SyncingT, SC: SelectChainT + 'static, VR: VotingRuleT + Clone + 'static, NumberFor: BlockNumberOps, diff --git a/client/consensus/grandpa/src/lib.rs b/client/consensus/grandpa/src/lib.rs index ef4beb51b4fff..7bf48a498fabb 100644 --- a/client/consensus/grandpa/src/lib.rs +++ b/client/consensus/grandpa/src/lib.rs @@ -141,7 +141,7 @@ pub use voting_rule::{ }; use aux_schema::PersistentData; -use communication::{Network as NetworkT, NetworkBridge}; +use communication::{Network as NetworkT, NetworkBridge, Syncing as SyncingT}; use environment::{Environment, VoterSetState}; use until_imported::UntilGlobalMessageBlocksImported; @@ -349,10 +349,11 @@ pub(crate) trait BlockSyncRequester { ); } -impl BlockSyncRequester for NetworkBridge +impl BlockSyncRequester for NetworkBridge where Block: BlockT, Network: NetworkT, + Syncing: SyncingT, { fn set_sync_fork_request( &self, @@ -617,11 +618,11 @@ where )) } -fn global_communication( +fn global_communication( set_id: SetId, voters: &Arc>, client: Arc, - network: &NetworkBridge, + network: &NetworkBridge, keystore: Option<&SyncCryptoStorePtr>, metrics: Option, ) -> ( @@ -640,6 +641,7 @@ where BE: Backend + 'static, C: ClientForGrandpa + 'static, N: NetworkT, + S: SyncingT, NumberFor: BlockNumberOps, { let is_voter = local_authority_id(voters, keystore).is_some(); @@ -665,7 +667,7 @@ where } /// Parameters used to run Grandpa. -pub struct GrandpaParams { +pub struct GrandpaParams { /// Configuration for the GRANDPA service. pub config: Config, /// A link to the block import worker. @@ -676,6 +678,8 @@ pub struct GrandpaParams { /// `sc_network` crate, it is assumed that the Grandpa notifications protocol has been passed /// to the configuration of the networking. See [`grandpa_peers_set_config`]. pub network: N, + /// Event stream for syncing-related events. + pub sync: S, /// A voting rule used to potentially restrict target votes. pub voting_rule: VR, /// The prometheus metrics registry. @@ -710,13 +714,14 @@ pub fn grandpa_peers_set_config( /// Run a GRANDPA voter as a task. Provide configuration and a link to a /// block import worker that has already been instantiated with `block_import`. -pub fn run_grandpa_voter( - grandpa_params: GrandpaParams, +pub fn run_grandpa_voter( + grandpa_params: GrandpaParams, ) -> sp_blockchain::Result + Send> where Block::Hash: Ord, BE: Backend + 'static, N: NetworkT + Sync + 'static, + S: SyncingT + Sync + 'static, SC: SelectChain + 'static, VR: VotingRule + Clone + 'static, NumberFor: BlockNumberOps, @@ -727,6 +732,7 @@ where mut config, link, network, + sync, voting_rule, prometheus_registry, shared_voter_state, @@ -751,6 +757,7 @@ where let network = NetworkBridge::new( network, + sync, config.clone(), persistent_data.set_state.clone(), prometheus_registry.as_ref(), @@ -836,26 +843,27 @@ impl Metrics { /// Future that powers the voter. #[must_use] -struct VoterWork, SC, VR> { +struct VoterWork, S: SyncingT, SC, VR> { voter: Pin< Box>>> + Send>, >, shared_voter_state: SharedVoterState, - env: Arc>, + env: Arc>, voter_commands_rx: TracingUnboundedReceiver>>, - network: NetworkBridge, + network: NetworkBridge, telemetry: Option, /// Prometheus metrics. metrics: Option, } -impl VoterWork +impl VoterWork where Block: BlockT, B: Backend + 'static, C: ClientForGrandpa + 'static, C::Api: GrandpaApi, N: NetworkT + Sync, + S: SyncingT + Sync, NumberFor: BlockNumberOps, SC: SelectChain + 'static, VR: VotingRule + Clone + 'static, @@ -863,7 +871,7 @@ where fn new( client: Arc, config: Config, - network: NetworkBridge, + network: NetworkBridge, select_chain: SC, voting_rule: VR, persistent_data: PersistentData, @@ -1072,11 +1080,12 @@ where } } -impl Future for VoterWork +impl Future for VoterWork where Block: BlockT, B: Backend + 'static, N: NetworkT + Sync, + S: SyncingT + Sync, NumberFor: BlockNumberOps, SC: SelectChain + 'static, C: ClientForGrandpa + 'static, diff --git a/client/consensus/grandpa/src/observer.rs b/client/consensus/grandpa/src/observer.rs index b382430ef3d4c..53672c1f02225 100644 --- a/client/consensus/grandpa/src/observer.rs +++ b/client/consensus/grandpa/src/observer.rs @@ -39,7 +39,7 @@ use sp_runtime::traits::{Block as BlockT, NumberFor}; use crate::{ authorities::SharedAuthoritySet, aux_schema::PersistentData, - communication::{Network as NetworkT, NetworkBridge}, + communication::{Network as NetworkT, NetworkBridge, Syncing as SyncingT}, environment, global_communication, notification::GrandpaJustificationSender, ClientForGrandpa, CommandOrError, CommunicationIn, Config, Error, LinkHalf, VoterCommand, @@ -163,14 +163,16 @@ where /// already been instantiated with `block_import`. /// NOTE: this is currently not part of the crate's public API since we don't consider /// it stable enough to use on a live network. -pub fn run_grandpa_observer( +pub fn run_grandpa_observer( config: Config, link: LinkHalf, network: N, + sync: S, ) -> sp_blockchain::Result + Send> where BE: Backend + Unpin + 'static, N: NetworkT, + S: SyncingT, SC: SelectChain, NumberFor: BlockNumberOps, Client: ClientForGrandpa + 'static, @@ -186,6 +188,7 @@ where let network = NetworkBridge::new( network, + sync, config.clone(), persistent_data.set_state.clone(), None, @@ -211,11 +214,11 @@ where /// Future that powers the observer. #[must_use] -struct ObserverWork> { +struct ObserverWork, S: SyncingT> { observer: Pin>>> + Send>>, client: Arc, - network: NetworkBridge, + network: NetworkBridge, persistent_data: PersistentData, keystore: Option, voter_commands_rx: TracingUnboundedReceiver>>, @@ -224,17 +227,18 @@ struct ObserverWork> { _phantom: PhantomData, } -impl ObserverWork +impl ObserverWork where B: BlockT, BE: Backend + 'static, Client: ClientForGrandpa + 'static, Network: NetworkT, + Syncing: SyncingT, NumberFor: BlockNumberOps, { fn new( client: Arc, - network: NetworkBridge, + network: NetworkBridge, persistent_data: PersistentData, keystore: Option, voter_commands_rx: TracingUnboundedReceiver>>, @@ -347,12 +351,13 @@ where } } -impl Future for ObserverWork +impl Future for ObserverWork where B: BlockT, BE: Backend + Unpin + 'static, C: ClientForGrandpa + 'static, N: NetworkT, + S: SyncingT, NumberFor: BlockNumberOps, { type Output = Result<(), Error>; diff --git a/client/consensus/grandpa/src/tests.rs b/client/consensus/grandpa/src/tests.rs index 7cc5e75fa148c..f7747a20301f5 100644 --- a/client/consensus/grandpa/src/tests.rs +++ b/client/consensus/grandpa/src/tests.rs @@ -145,6 +145,10 @@ impl TestNetFactory for GrandpaTestNet { &self.peers } + fn peers_mut(&mut self) -> &mut Vec { + &mut self.peers + } + fn mut_peers)>(&mut self, closure: F) { closure(&mut self.peers); } @@ -310,6 +314,7 @@ fn initialize_grandpa( net.peers[peer_id].data.lock().take().expect("link initialized at startup; qed"); (net.peers[peer_id].network_service().clone(), link) }; + let sync = net.peers[peer_id].sync_service().clone(); let grandpa_params = GrandpaParams { config: Config { @@ -324,6 +329,7 @@ fn initialize_grandpa( }, link, network: net_service, + sync, voting_rule: (), prometheus_registry: None, shared_voter_state: SharedVoterState::empty(), @@ -451,6 +457,7 @@ async fn finalize_3_voters_1_full_observer() { tokio::spawn({ let peer_id = 3; let net_service = net.peers[peer_id].network_service().clone(); + let sync = net.peers[peer_id].sync_service().clone(); let link = net.peers[peer_id].data.lock().take().expect("link initialized at startup; qed"); let grandpa_params = GrandpaParams { @@ -466,6 +473,7 @@ async fn finalize_3_voters_1_full_observer() { }, link, network: net_service, + sync, voting_rule: (), prometheus_registry: None, shared_voter_state: SharedVoterState::empty(), @@ -533,11 +541,15 @@ async fn transition_3_voters_twice_1_full_observer() { for (peer_id, local_key) in all_peers.clone().into_iter().enumerate() { let keystore = create_keystore(local_key); - let (net_service, link) = { + let (net_service, link, sync) = { let net = net.lock(); let link = net.peers[peer_id].data.lock().take().expect("link initialized at startup; qed"); - (net.peers[peer_id].network_service().clone(), link) + ( + net.peers[peer_id].network_service().clone(), + link, + net.peers[peer_id].sync_service().clone(), + ) }; let grandpa_params = GrandpaParams { @@ -553,6 +565,7 @@ async fn transition_3_voters_twice_1_full_observer() { }, link, network: net_service, + sync, voting_rule: (), prometheus_registry: None, shared_voter_state: SharedVoterState::empty(), @@ -999,6 +1012,7 @@ async fn voter_persists_its_votes() { communication::NetworkBridge::new( net.peers[1].network_service().clone(), + net.peers[1].sync_service().clone(), config.clone(), set_state, None, @@ -1016,6 +1030,7 @@ async fn voter_persists_its_votes() { let link = net.peers[0].data.lock().take().expect("link initialized at startup; qed"); (net.peers[0].network_service().clone(), link) }; + let sync = net.peers[0].sync_service().clone(); let grandpa_params = GrandpaParams { config: Config { @@ -1030,6 +1045,7 @@ async fn voter_persists_its_votes() { }, link, network: net_service, + sync, voting_rule: VotingRulesBuilder::default().build(), prometheus_registry: None, shared_voter_state: SharedVoterState::empty(), @@ -1050,6 +1066,7 @@ async fn voter_persists_its_votes() { // the network service of this new peer net.add_authority_peer(); let net_service = net.peers[2].network_service().clone(); + let sync = net.peers[2].sync_service().clone(); // but we'll reuse the client from the first peer (alice_voter1) // since we want to share the same database, so that we can // read the persisted state after aborting alice_voter1. @@ -1071,6 +1088,7 @@ async fn voter_persists_its_votes() { }, link, network: net_service, + sync, voting_rule: VotingRulesBuilder::default().build(), prometheus_registry: None, shared_voter_state: SharedVoterState::empty(), @@ -1232,6 +1250,7 @@ async fn finalize_3_voters_1_light_observer() { }, net.peers[3].data.lock().take().expect("link initialized at startup; qed"), net.peers[3].network_service().clone(), + net.peers[3].sync_service().clone(), ) .unwrap(); net.peer(0).push_blocks(20, false); @@ -1265,6 +1284,7 @@ async fn voter_catches_up_to_latest_round_when_behind() { link, net: Arc>| -> Pin + Send>> { + let mut net = net.lock(); let grandpa_params = GrandpaParams { config: Config { gossip_duration: TEST_GOSSIP_DURATION, @@ -1277,7 +1297,8 @@ async fn voter_catches_up_to_latest_round_when_behind() { protocol_name: grandpa_protocol_name::NAME.into(), }, link, - network: net.lock().peer(peer_id).network_service().clone(), + network: net.peer(peer_id).network_service().clone(), + sync: net.peer(peer_id).sync_service().clone(), voting_rule: (), prometheus_registry: None, shared_voter_state: SharedVoterState::empty(), @@ -1359,18 +1380,20 @@ async fn voter_catches_up_to_latest_round_when_behind() { future::select(test, drive_to_completion).await; } -type TestEnvironment = - Environment; +type TestEnvironment = + Environment; -fn test_environment_with_select_chain( +fn test_environment_with_select_chain( link: &TestLinkHalf, keystore: Option, network_service: N, + sync_service: S, select_chain: SC, voting_rule: VR, -) -> TestEnvironment +) -> TestEnvironment where N: NetworkT, + S: SyncingT, VR: VotingRule, { let PersistentData { ref authority_set, ref set_state, .. } = link.persistent_data; @@ -1386,8 +1409,14 @@ where protocol_name: grandpa_protocol_name::NAME.into(), }; - let network = - NetworkBridge::new(network_service.clone(), config.clone(), set_state.clone(), None, None); + let network = NetworkBridge::new( + network_service.clone(), + sync_service, + config.clone(), + set_state.clone(), + None, + None, + ); Environment { authority_set: authority_set.clone(), @@ -1406,20 +1435,23 @@ where } } -fn test_environment( +fn test_environment( link: &TestLinkHalf, keystore: Option, network_service: N, + sync_service: S, voting_rule: VR, -) -> TestEnvironment, VR> +) -> TestEnvironment, VR> where N: NetworkT, + S: SyncingT, VR: VotingRule, { test_environment_with_select_chain( link, keystore, network_service, + sync_service, link.select_chain.clone(), voting_rule, ) @@ -1435,19 +1467,22 @@ async fn grandpa_environment_respects_voting_rules() { let mut net = GrandpaTestNet::new(TestApi::new(voters), 1, 0); let peer = net.peer(0); let network_service = peer.network_service().clone(); + let sync_service = peer.sync_service().clone(); let link = peer.data.lock().take().unwrap(); // add 21 blocks let hashes = peer.push_blocks(21, false); // create an environment with no voting rule restrictions - let unrestricted_env = test_environment(&link, None, network_service.clone(), ()); + let unrestricted_env = + test_environment(&link, None, network_service.clone(), sync_service.clone(), ()); // another with 3/4 unfinalized chain voting rule restriction let three_quarters_env = test_environment( &link, None, network_service.clone(), + sync_service.clone(), voting_rule::ThreeQuartersOfTheUnfinalizedChain, ); @@ -1457,6 +1492,7 @@ async fn grandpa_environment_respects_voting_rules() { &link, None, network_service.clone(), + sync_service, VotingRulesBuilder::default().build(), ); @@ -1549,6 +1585,7 @@ async fn grandpa_environment_passes_actual_best_block_to_voting_rules() { let mut net = GrandpaTestNet::new(TestApi::new(voters), 1, 0); let peer = net.peer(0); let network_service = peer.network_service().clone(); + let sync_service = peer.sync_service().clone(); let link = peer.data.lock().take().unwrap(); let client = peer.client().as_client().clone(); let select_chain = MockSelectChain::default(); @@ -1562,6 +1599,7 @@ async fn grandpa_environment_passes_actual_best_block_to_voting_rules() { &link, None, network_service.clone(), + sync_service, select_chain.clone(), voting_rule::BeforeBestBlockBy(5), ); @@ -1607,6 +1645,7 @@ async fn grandpa_environment_checks_if_best_block_is_descendent_of_finality_targ let mut net = GrandpaTestNet::new(TestApi::new(voters), 1, 0); let peer = net.peer(0); let network_service = peer.network_service().clone(); + let sync_service = peer.sync_service().clone(); let link = peer.data.lock().take().unwrap(); let client = peer.client().as_client().clone(); let select_chain = MockSelectChain::default(); @@ -1615,6 +1654,7 @@ async fn grandpa_environment_checks_if_best_block_is_descendent_of_finality_targ &link, None, network_service.clone(), + sync_service.clone(), select_chain.clone(), voting_rule.clone(), ); @@ -1717,10 +1757,12 @@ async fn grandpa_environment_never_overwrites_round_voter_state() { let mut net = GrandpaTestNet::new(TestApi::new(voters), 1, 0); let peer = net.peer(0); let network_service = peer.network_service().clone(); + let sync_service = peer.sync_service().clone(); let link = peer.data.lock().take().unwrap(); let keystore = create_keystore(peers[0]); - let environment = test_environment(&link, Some(keystore), network_service.clone(), ()); + let environment = + test_environment(&link, Some(keystore), network_service.clone(), sync_service, ()); let round_state = || finality_grandpa::round::State::genesis(Default::default()); let base = || Default::default(); @@ -1921,9 +1963,10 @@ async fn grandpa_environment_doesnt_send_equivocation_reports_for_itself() { let mut net = GrandpaTestNet::new(TestApi::new(voters), 1, 0); let peer = net.peer(0); let network_service = peer.network_service().clone(); + let sync_service = peer.sync_service().clone(); let link = peer.data.lock().take().unwrap(); let keystore = create_keystore(alice); - test_environment(&link, Some(keystore), network_service.clone(), ()) + test_environment(&link, Some(keystore), network_service.clone(), sync_service, ()) }; let signed_prevote = { diff --git a/client/informant/src/display.rs b/client/informant/src/display.rs index 85be926d99b21..fc68e5603c134 100644 --- a/client/informant/src/display.rs +++ b/client/informant/src/display.rs @@ -24,7 +24,7 @@ use sc_network_common::{ service::NetworkStatus, sync::{ warp::{WarpSyncPhase, WarpSyncProgress}, - SyncState, + SyncState, SyncStatus, }, }; use sp_runtime::traits::{Block as BlockT, CheckedDiv, NumberFor, Saturating, Zero}; @@ -69,7 +69,12 @@ impl InformantDisplay { } /// Displays the informant by calling `info!`. - pub fn display(&mut self, info: &ClientInfo, net_status: NetworkStatus) { + pub fn display( + &mut self, + info: &ClientInfo, + net_status: NetworkStatus, + sync_status: SyncStatus, + ) { let best_number = info.chain.best_number; let best_hash = info.chain.best_hash; let finalized_number = info.chain.finalized_number; @@ -94,7 +99,7 @@ impl InformantDisplay { }; let (level, status, target) = - match (net_status.sync_state, net_status.state_sync, net_status.warp_sync) { + match (sync_status.state, sync_status.state_sync, sync_status.warp_sync) { ( _, _, diff --git a/client/informant/src/lib.rs b/client/informant/src/lib.rs index cb30d08c45227..dc6aebc2ed658 100644 --- a/client/informant/src/lib.rs +++ b/client/informant/src/lib.rs @@ -23,7 +23,7 @@ use futures::prelude::*; use futures_timer::Delay; use log::{debug, info, trace}; use sc_client_api::{BlockchainEvents, UsageProvider}; -use sc_network_common::service::NetworkStatusProvider; +use sc_network_common::{service::NetworkStatusProvider, sync::SyncStatusProvider}; use sp_blockchain::HeaderMetadata; use sp_runtime::traits::{Block as BlockT, Header}; use std::{collections::VecDeque, fmt::Display, sync::Arc, time::Duration}; @@ -51,9 +51,10 @@ impl Default for OutputFormat { } /// Builds the informant and returns a `Future` that drives the informant. -pub async fn build(client: Arc, network: N, format: OutputFormat) +pub async fn build(client: Arc, network: N, syncing: S, format: OutputFormat) where - N: NetworkStatusProvider, + N: NetworkStatusProvider, + S: SyncStatusProvider, C: UsageProvider + HeaderMetadata + BlockchainEvents, >::Error: Display, { @@ -63,10 +64,15 @@ where let display_notifications = interval(Duration::from_millis(5000)) .filter_map(|_| async { - let status = network.status().await; - status.ok() + let net_status = network.status().await; + let sync_status = syncing.status().await; + + match (net_status.ok(), sync_status.ok()) { + (Some(net), Some(sync)) => Some((net, sync)), + _ => None, + } }) - .for_each(move |net_status| { + .for_each(move |(net_status, sync_status)| { let info = client_1.usage_info(); if let Some(ref usage) = info.usage { trace!(target: "usage", "Usage statistics: {}", usage); @@ -76,7 +82,7 @@ where "Usage statistics not displayed as backend does not provide it", ) } - display.display(&info, net_status); + display.display(&info, net_status, sync_status); future::ready(()) }); diff --git a/client/network-gossip/src/bridge.rs b/client/network-gossip/src/bridge.rs index 129e18d8a58df..7368cc770306e 100644 --- a/client/network-gossip/src/bridge.rs +++ b/client/network-gossip/src/bridge.rs @@ -18,10 +18,13 @@ use crate::{ state_machine::{ConsensusGossip, TopicNotification, PERIODIC_MAINTENANCE_INTERVAL}, - Network, Validator, + Network, Syncing, Validator, }; -use sc_network_common::protocol::{event::Event, ProtocolName}; +use sc_network_common::{ + protocol::{event::Event, ProtocolName}, + sync::SyncEvent, +}; use sc_peerset::ReputationChange; use futures::{ @@ -44,11 +47,14 @@ use std::{ pub struct GossipEngine { state_machine: ConsensusGossip, network: Box + Send>, + sync: Box>, periodic_maintenance_interval: futures_timer::Delay, protocol: ProtocolName, /// Incoming events from the network. network_event_stream: Pin + Send>>, + /// Incoming events from the syncing service. + sync_event_stream: Pin + Send>>, /// Outgoing events to the consumer. message_sinks: HashMap>>, /// Buffered messages (see [`ForwardingState`]). @@ -75,25 +81,31 @@ impl Unpin for GossipEngine {} impl GossipEngine { /// Create a new instance. - pub fn new + Send + Clone + 'static>( + pub fn new( network: N, + sync: S, protocol: impl Into, validator: Arc>, metrics_registry: Option<&Registry>, ) -> Self where B: 'static, + N: Network + Send + Clone + 'static, + S: Syncing + Send + Clone + 'static, { let protocol = protocol.into(); let network_event_stream = network.event_stream("network-gossip"); + let sync_event_stream = sync.event_stream("network-gossip"); GossipEngine { state_machine: ConsensusGossip::new(validator, protocol.clone(), metrics_registry), network: Box::new(network), + sync: Box::new(sync), periodic_maintenance_interval: futures_timer::Delay::new(PERIODIC_MAINTENANCE_INTERVAL), protocol, network_event_stream, + sync_event_stream, message_sinks: HashMap::new(), forwarding_state: ForwardingState::Idle, @@ -162,7 +174,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(block, associated_data); + self.sync.announce_block(block, associated_data); } } @@ -175,28 +187,24 @@ impl Future for GossipEngine { 'outer: loop { match &mut this.forwarding_state { ForwardingState::Idle => { - match this.network_event_stream.poll_next_unpin(cx) { + let net_event_stream = this.network_event_stream.poll_next_unpin(cx); + let sync_event_stream = this.sync_event_stream.poll_next_unpin(cx); + + if net_event_stream.is_pending() && sync_event_stream.is_pending() { + break + } + + match net_event_stream { Poll::Ready(Some(event)) => match event { - Event::SyncConnected { remote } => { - this.network.add_set_reserved(remote, this.protocol.clone()); - }, - Event::SyncDisconnected { remote } => { - this.network.remove_peers_from_reserved_set( - this.protocol.clone(), - vec![remote], - ); - }, - Event::NotificationStreamOpened { remote, protocol, role, .. } => { - if protocol != this.protocol { - continue - } - this.state_machine.new_peer(&mut *this.network, remote, role); - }, + Event::NotificationStreamOpened { remote, protocol, role, .. } => + if protocol == this.protocol { + this.state_machine.new_peer(&mut *this.network, remote, role); + }, Event::NotificationStreamClosed { remote, protocol } => { - if protocol != this.protocol { - continue + if protocol == this.protocol { + this.state_machine + .peer_disconnected(&mut *this.network, remote); } - this.state_machine.peer_disconnected(&mut *this.network, remote); }, Event::NotificationsReceived { remote, messages } => { let messages = messages @@ -225,7 +233,25 @@ impl Future for GossipEngine { self.is_terminated = true; return Poll::Ready(()) }, - Poll::Pending => break, + Poll::Pending => {}, + } + + match sync_event_stream { + Poll::Ready(Some(event)) => match event { + SyncEvent::PeerConnected(remote) => + this.network.add_set_reserved(remote, this.protocol.clone()), + SyncEvent::PeerDisconnected(remote) => + this.network.remove_peers_from_reserved_set( + this.protocol.clone(), + vec![remote], + ), + }, + // The sync event stream closed. Do the same for [`GossipValidator`]. + Poll::Ready(None) => { + self.is_terminated = true; + return Poll::Ready(()) + }, + Poll::Pending => {}, } }, ForwardingState::Busy(to_forward) => { @@ -321,6 +347,7 @@ mod tests { NetworkBlock, NetworkEventStream, NetworkNotification, NetworkPeers, NotificationSender, NotificationSenderError, }, + sync::SyncEventStream, }; use sp_runtime::{ testing::H256, @@ -433,6 +460,10 @@ mod tests { ) -> Result, NotificationSenderError> { unimplemented!(); } + + fn set_notification_handshake(&self, _protocol: ProtocolName, _handshake: Vec) { + unimplemented!(); + } } impl NetworkBlock<::Hash, NumberFor> for TestNetwork { @@ -449,6 +480,42 @@ mod tests { } } + #[derive(Clone, Default)] + struct TestSync { + inner: Arc>, + } + + #[derive(Clone, Default)] + struct TestSyncInner { + event_senders: Vec>, + } + + impl SyncEventStream for TestSync { + fn event_stream( + &self, + _name: &'static str, + ) -> Pin + Send>> { + let (tx, rx) = unbounded(); + self.inner.lock().unwrap().event_senders.push(tx); + + Box::pin(rx) + } + } + + impl NetworkBlock<::Hash, NumberFor> for TestSync { + fn announce_block(&self, _hash: ::Hash, _data: Option>) { + unimplemented!(); + } + + fn new_best_block_imported( + &self, + _hash: ::Hash, + _number: NumberFor, + ) { + unimplemented!(); + } + } + struct AllowAll; impl Validator for AllowAll { fn validate( @@ -468,8 +535,10 @@ mod tests { #[test] fn returns_when_network_event_stream_closes() { let network = TestNetwork::default(); + let sync = Arc::new(TestSync::default()); let mut gossip_engine = GossipEngine::::new( network.clone(), + sync, "/my_protocol", Arc::new(AllowAll {}), None, @@ -495,9 +564,11 @@ mod tests { let protocol = ProtocolName::from("/my_protocol"); let remote_peer = PeerId::random(); let network = TestNetwork::default(); + let sync = Arc::new(TestSync::default()); let mut gossip_engine = GossipEngine::::new( network.clone(), + sync.clone(), protocol.clone(), Arc::new(AllowAll {}), None, @@ -512,6 +583,7 @@ mod tests { protocol: protocol.clone(), negotiated_fallback: None, role: ObservedRole::Authority, + received_handshake: vec![], }) .expect("Event stream is unbounded; qed."); @@ -614,6 +686,7 @@ mod tests { let protocol = ProtocolName::from("/my_protocol"); let remote_peer = PeerId::random(); let network = TestNetwork::default(); + let sync = Arc::new(TestSync::default()); let num_channels_per_topic = channels.iter().fold( HashMap::new(), @@ -640,6 +713,7 @@ mod tests { let mut gossip_engine = GossipEngine::::new( network.clone(), + sync.clone(), protocol.clone(), Arc::new(TestValidator {}), None, @@ -674,6 +748,7 @@ mod tests { protocol: protocol.clone(), negotiated_fallback: None, role: ObservedRole::Authority, + received_handshake: vec![], }) .expect("Event stream is unbounded; qed."); diff --git a/client/network-gossip/src/lib.rs b/client/network-gossip/src/lib.rs index 859ec3d528d96..e3448ba01c373 100644 --- a/client/network-gossip/src/lib.rs +++ b/client/network-gossip/src/lib.rs @@ -71,6 +71,7 @@ use libp2p::{multiaddr, PeerId}; use sc_network_common::{ protocol::ProtocolName, service::{NetworkBlock, NetworkEventStream, NetworkNotification, NetworkPeers}, + sync::SyncEventStream, }; use sp_runtime::traits::{Block as BlockT, NumberFor}; use std::iter; @@ -80,9 +81,7 @@ mod state_machine; mod validator; /// Abstraction over a network. -pub trait Network: - NetworkPeers + NetworkEventStream + NetworkNotification + NetworkBlock> -{ +pub trait Network: NetworkPeers + NetworkEventStream + NetworkNotification { fn add_set_reserved(&self, who: PeerId, protocol: ProtocolName) { let addr = iter::once(multiaddr::Protocol::P2p(who.into())).collect::(); @@ -93,10 +92,9 @@ pub trait Network: } } -impl Network for T where - T: NetworkPeers - + NetworkEventStream - + NetworkNotification - + NetworkBlock> -{ -} +impl Network for T where T: NetworkPeers + NetworkEventStream + NetworkNotification {} + +/// Abstraction over the syncing subsystem. +pub trait Syncing: SyncEventStream + NetworkBlock> {} + +impl Syncing for T where T: SyncEventStream + NetworkBlock> {} diff --git a/client/network-gossip/src/state_machine.rs b/client/network-gossip/src/state_machine.rs index 7cd5b5613b073..3a0d5fc0de173 100644 --- a/client/network-gossip/src/state_machine.rs +++ b/client/network-gossip/src/state_machine.rs @@ -683,6 +683,10 @@ mod tests { ) -> Result, NotificationSenderError> { unimplemented!(); } + + fn set_notification_handshake(&self, _protocol: ProtocolName, _handshake: Vec) { + unimplemented!(); + } } impl NetworkBlock<::Hash, NumberFor> for NoOpNetwork { diff --git a/client/network/common/Cargo.toml b/client/network/common/Cargo.toml index 06ff00ef77dbc..c5f9d6d4cb027 100644 --- a/client/network/common/Cargo.toml +++ b/client/network/common/Cargo.toml @@ -16,6 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] prost-build = "0.11" [dependencies] +array-bytes = "4.1" async-trait = "0.1.57" bitflags = "1.3.2" bytes = "1" @@ -30,9 +31,14 @@ prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0. smallvec = "1.8.0" sc-consensus = { version = "0.10.0-dev", path = "../../consensus/common" } sc-peerset = { version = "4.0.0-dev", path = "../../peerset" } +sc-utils = { version = "4.0.0-dev", path = "../../utils" } serde = { version = "1.0.136", features = ["derive"] } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } sp-consensus-grandpa = { version = "4.0.0-dev", path = "../../../primitives/consensus/grandpa" } sp-runtime = { version = "7.0.0", path = "../../../primitives/runtime" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } thiserror = "1.0" +zeroize = "1.4.3" + +[dev-dependencies] +tempfile = "3.1.0" diff --git a/client/network/common/src/config.rs b/client/network/common/src/config.rs index 782b5a9651384..6a02129fcfe06 100644 --- a/client/network/common/src/config.rs +++ b/client/network/common/src/config.rs @@ -18,11 +18,33 @@ //! Configuration of the networking layer. -use crate::protocol; +pub use crate::{ + protocol::{self, role::Role}, + request_responses::{ + IncomingRequest, OutgoingResponse, ProtocolConfig as RequestResponseConfig, + }, + sync::warp::WarpSyncProvider, + ExHashT, +}; +pub use libp2p::{build_multiaddr, core::PublicKey, identity}; use codec::Encode; -use libp2p::{multiaddr, Multiaddr, PeerId}; -use std::{fmt, str, str::FromStr}; +use libp2p::{ + identity::{ed25519, Keypair}, + multiaddr, Multiaddr, PeerId, +}; +use zeroize::Zeroize; + +use std::{ + error::Error, + fmt, fs, + io::{self, Write}, + iter, + net::Ipv4Addr, + path::{Path, PathBuf}, + str, + str::FromStr, +}; /// 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. @@ -331,3 +353,350 @@ impl NonReservedPeerMode { } } } + +/// Sync operation mode. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum SyncMode { + /// Full block download and verification. + Full, + /// Download blocks and the latest state. + Fast { + /// Skip state proof download and verification. + skip_proofs: bool, + /// Download indexed transactions for recent blocks. + storage_chain_mode: bool, + }, + /// Warp sync - verify authority set transitions and the latest state. + 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 + } +} + +/// Network service configuration. +#[derive(Clone, Debug)] +pub struct NetworkConfiguration { + /// Directory path to store network-specific configuration. None means nothing will be saved. + pub net_config_path: Option, + /// Multiaddresses to listen for incoming connections. + pub listen_addresses: Vec, + /// Multiaddresses to advertise. Detected automatically if empty. + pub public_addresses: Vec, + /// List of initial node addresses + pub boot_nodes: Vec, + /// The node key configuration, which determines the node's network identity keypair. + pub node_key: NodeKeyConfig, + /// List of request-response protocols that the node supports. + 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. + pub client_version: String, + /// Name of the node. Sent over the wire for debugging purposes. + pub node_name: String, + /// Configuration for the transport layer. + pub transport: TransportConfig, + /// Maximum number of peers to ask the same blocks in parallel. + pub max_parallel_downloads: u32, + /// Initial syncing mode. + pub sync_mode: SyncMode, + + /// True if Kademlia random discovery should be enabled. + /// + /// If true, the node will automatically randomly walk the DHT in order to find new peers. + pub enable_dht_random_walk: bool, + + /// Should we insert non-global addresses into the DHT? + pub allow_non_globals_in_dht: bool, + + /// Require iterative Kademlia DHT queries to use disjoint paths for increased resiliency in + /// the presence of potentially adversarial nodes. + pub kademlia_disjoint_query_paths: bool, + /// Enable serving block data over IPFS bitswap. + pub ipfs_server: bool, + + /// Size of Yamux receive window of all substreams. `None` for the default (256kiB). + /// Any value less than 256kiB is invalid. + /// + /// # Context + /// + /// By design, notifications substreams on top of Yamux connections only allow up to `N` bytes + /// to be transferred at a time, where `N` is the Yamux receive window size configurable here. + /// This means, in practice, that every `N` bytes must be acknowledged by the receiver before + /// the sender can send more data. The maximum bandwidth of each notifications substream is + /// therefore `N / round_trip_time`. + /// + /// It is recommended to leave this to `None`, and use a request-response protocol instead if + /// a large amount of data must be transferred. The reason why the value is configurable is + /// that some Substrate users mis-use notification protocols to send large amounts of data. + /// As such, this option isn't designed to stay and will likely get removed in the future. + /// + /// Note that configuring a value here isn't a modification of the Yamux protocol, but rather + /// a modification of the way the implementation works. Different nodes with different + /// configured values remain compatible with each other. + pub yamux_window_size: Option, +} + +impl NetworkConfiguration { + /// Create new default configuration + pub fn new, SV: Into>( + node_name: SN, + client_version: SV, + node_key: NodeKeyConfig, + net_config_path: Option, + ) -> Self { + let default_peers_set = SetConfig::default(); + Self { + net_config_path, + listen_addresses: Vec::new(), + public_addresses: Vec::new(), + boot_nodes: Vec::new(), + node_key, + request_response_protocols: Vec::new(), + 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(), + transport: TransportConfig::Normal { enable_mdns: false, allow_private_ip: true }, + max_parallel_downloads: 5, + sync_mode: SyncMode::Full, + enable_dht_random_walk: true, + allow_non_globals_in_dht: false, + kademlia_disjoint_query_paths: false, + yamux_window_size: None, + ipfs_server: false, + } + } + + /// Create new default configuration for localhost-only connection with random port (useful for + /// testing) + pub fn new_local() -> NetworkConfiguration { + let mut config = + NetworkConfiguration::new("test-node", "test-client", Default::default(), None); + + config.listen_addresses = + vec![iter::once(multiaddr::Protocol::Ip4(Ipv4Addr::new(127, 0, 0, 1))) + .chain(iter::once(multiaddr::Protocol::Tcp(0))) + .collect()]; + + config.allow_non_globals_in_dht = true; + config + } + + /// Create new default configuration for localhost-only connection with random port (useful for + /// testing) + pub fn new_memory() -> NetworkConfiguration { + let mut config = + NetworkConfiguration::new("test-node", "test-client", Default::default(), None); + + config.listen_addresses = + vec![iter::once(multiaddr::Protocol::Ip4(Ipv4Addr::new(127, 0, 0, 1))) + .chain(iter::once(multiaddr::Protocol::Tcp(0))) + .collect()]; + + config.allow_non_globals_in_dht = true; + config + } +} + +/// 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. +#[derive(Clone, Debug)] +pub enum NodeKeyConfig { + /// A Ed25519 secret key configuration. + Ed25519(Secret), +} + +impl Default for NodeKeyConfig { + fn default() -> NodeKeyConfig { + Self::Ed25519(Secret::New) + } +} + +/// The options for obtaining a Ed25519 secret key. +pub type Ed25519Secret = Secret; + +/// The configuration options for obtaining a secret key `K`. +#[derive(Clone)] +pub enum Secret { + /// Use the given secret key `K`. + Input(K), + /// Read the secret key from a file. If the file does not exist, + /// it is created with a newly generated secret key `K`. The format + /// of the file is determined by `K`: + /// + /// * `ed25519::SecretKey`: An unencoded 32 bytes Ed25519 secret key. + File(PathBuf), + /// Always generate a new secret key `K`. + New, +} + +impl fmt::Debug for Secret { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::Input(_) => f.debug_tuple("Secret::Input").finish(), + Self::File(path) => f.debug_tuple("Secret::File").field(path).finish(), + Self::New => f.debug_tuple("Secret::New").finish(), + } + } +} + +impl NodeKeyConfig { + /// Evaluate a `NodeKeyConfig` to obtain an identity `Keypair`: + /// + /// * If the secret is configured as input, the corresponding keypair is returned. + /// + /// * If the secret is configured as a file, it is read from that file, if it exists. Otherwise + /// a new secret is generated and stored. In either case, the keypair obtained from the + /// secret is returned. + /// + /// * If the secret is configured to be new, it is generated and the corresponding keypair is + /// returned. + pub fn into_keypair(self) -> io::Result { + use NodeKeyConfig::*; + match self { + Ed25519(Secret::New) => Ok(Keypair::generate_ed25519()), + + Ed25519(Secret::Input(k)) => Ok(Keypair::Ed25519(k.into())), + + Ed25519(Secret::File(f)) => get_secret( + f, + |mut b| match String::from_utf8(b.to_vec()).ok().and_then(|s| { + if s.len() == 64 { + array_bytes::hex2bytes(&s).ok() + } else { + None + } + }) { + Some(s) => ed25519::SecretKey::from_bytes(s), + _ => ed25519::SecretKey::from_bytes(&mut b), + }, + ed25519::SecretKey::generate, + |b| b.as_ref().to_vec(), + ) + .map(ed25519::Keypair::from) + .map(Keypair::Ed25519), + } + } +} + +/// Load a secret key from a file, if it exists, or generate a +/// new secret key and write it to that file. In either case, +/// the secret key is returned. +fn get_secret(file: P, parse: F, generate: G, serialize: W) -> io::Result +where + P: AsRef, + F: for<'r> FnOnce(&'r mut [u8]) -> Result, + G: FnOnce() -> K, + E: Error + Send + Sync + 'static, + W: Fn(&K) -> Vec, +{ + std::fs::read(&file) + .and_then(|mut sk_bytes| { + parse(&mut sk_bytes).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) + }) + .or_else(|e| { + if e.kind() == io::ErrorKind::NotFound { + file.as_ref().parent().map_or(Ok(()), fs::create_dir_all)?; + let sk = generate(); + let mut sk_vec = serialize(&sk); + write_secret_file(file, &sk_vec)?; + sk_vec.zeroize(); + Ok(sk) + } else { + Err(e) + } + }) +} + +/// Write secret bytes to a file. +fn write_secret_file

(path: P, sk_bytes: &[u8]) -> io::Result<()> +where + P: AsRef, +{ + let mut file = open_secret_file(&path)?; + file.write_all(sk_bytes) +} + +/// Opens a file containing a secret key in write mode. +#[cfg(unix)] +fn open_secret_file

(path: P) -> io::Result +where + P: AsRef, +{ + use std::os::unix::fs::OpenOptionsExt; + fs::OpenOptions::new().write(true).create_new(true).mode(0o600).open(path) +} + +/// Opens a file containing a secret key in write mode. +#[cfg(not(unix))] +fn open_secret_file

(path: P) -> Result +where + P: AsRef, +{ + fs::OpenOptions::new().write(true).create_new(true).open(path) +} + +#[cfg(test)] +mod tests { + use super::*; + use tempfile::TempDir; + + fn tempdir_with_prefix(prefix: &str) -> TempDir { + tempfile::Builder::new().prefix(prefix).tempdir().unwrap() + } + + fn secret_bytes(kp: &Keypair) -> Vec { + let Keypair::Ed25519(p) = kp; + p.secret().as_ref().iter().cloned().collect() + } + + #[test] + fn test_secret_file() { + let tmp = tempdir_with_prefix("x"); + std::fs::remove_dir(tmp.path()).unwrap(); // should be recreated + let file = tmp.path().join("x").to_path_buf(); + let kp1 = NodeKeyConfig::Ed25519(Secret::File(file.clone())).into_keypair().unwrap(); + let kp2 = NodeKeyConfig::Ed25519(Secret::File(file.clone())).into_keypair().unwrap(); + assert!(file.is_file() && secret_bytes(&kp1) == secret_bytes(&kp2)) + } + + #[test] + fn test_secret_input() { + let sk = ed25519::SecretKey::generate(); + let kp1 = NodeKeyConfig::Ed25519(Secret::Input(sk.clone())).into_keypair().unwrap(); + let kp2 = NodeKeyConfig::Ed25519(Secret::Input(sk)).into_keypair().unwrap(); + assert!(secret_bytes(&kp1) == secret_bytes(&kp2)); + } + + #[test] + fn test_secret_new() { + let kp1 = NodeKeyConfig::Ed25519(Secret::New).into_keypair().unwrap(); + let kp2 = NodeKeyConfig::Ed25519(Secret::New).into_keypair().unwrap(); + assert!(secret_bytes(&kp1) != secret_bytes(&kp2)); + } +} diff --git a/client/network/common/src/protocol/event.rs b/client/network/common/src/protocol/event.rs index 7a14a2801319a..90c38b48c320f 100644 --- a/client/network/common/src/protocol/event.rs +++ b/client/network/common/src/protocol/event.rs @@ -48,18 +48,6 @@ pub enum Event { /// Event generated by a DHT. Dht(DhtEvent), - /// Now connected to a new peer for syncing purposes. - SyncConnected { - /// Node we are now syncing from. - remote: PeerId, - }, - - /// Now disconnected from a peer for syncing purposes. - SyncDisconnected { - /// Node we are no longer syncing from. - remote: PeerId, - }, - /// 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. @@ -79,6 +67,8 @@ pub enum Event { negotiated_fallback: Option, /// Role of the remote. role: ObservedRole, + /// Received handshake. + received_handshake: Vec, }, /// Closed a substream with the given node. Always matches a corresponding previous diff --git a/client/network/common/src/service.rs b/client/network/common/src/service.rs index e96a00c40c123..d3c5c2f439450 100644 --- a/client/network/common/src/service.rs +++ b/client/network/common/src/service.rs @@ -22,14 +22,12 @@ use crate::{ config::MultiaddrWithPeerId, protocol::{event::Event, ProtocolName}, 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::{collections::HashSet, future::Future, pin::Pin, sync::Arc}; mod signature; @@ -96,45 +94,33 @@ where /// 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 struct NetworkStatus { + /// 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 { +pub trait NetworkStatusProvider { /// High-level network status information. /// /// Returns an error if the `NetworkWorker` is no longer running. - async fn status(&self) -> Result, ()>; + async fn status(&self) -> Result; } // Manual implementation to avoid extra boxing here -impl NetworkStatusProvider for Arc +impl NetworkStatusProvider for Arc where T: ?Sized, - T: NetworkStatusProvider, + T: NetworkStatusProvider, { fn status<'life0, 'async_trait>( &'life0 self, - ) -> Pin, ()>> + Send + 'async_trait>> + ) -> Pin> + Send + 'async_trait>> where 'life0: 'async_trait, Self: 'async_trait, @@ -511,6 +497,9 @@ pub trait NetworkNotification { target: PeerId, protocol: ProtocolName, ) -> Result, NotificationSenderError>; + + /// Set handshake for the notification protocol. + fn set_notification_handshake(&self, protocol: ProtocolName, handshake: Vec); } impl NetworkNotification for Arc @@ -529,6 +518,10 @@ where ) -> Result, NotificationSenderError> { T::notification_sender(self, target, protocol) } + + fn set_notification_handshake(&self, protocol: ProtocolName, handshake: Vec) { + T::set_notification_handshake(self, protocol, handshake) + } } /// Provides ability to send network requests. diff --git a/client/network/common/src/sync.rs b/client/network/common/src/sync.rs index 6a98543d42065..262da6c202aa3 100644 --- a/client/network/common/src/sync.rs +++ b/client/network/common/src/sync.rs @@ -22,7 +22,11 @@ pub mod message; pub mod metrics; pub mod warp; +use crate::protocol::role::Roles; +use futures::Stream; + use libp2p::PeerId; + use message::{BlockAnnounce, BlockData, BlockRequest, BlockResponse}; use sc_consensus::{import_queue::RuntimeOrigin, IncomingBlock}; use sp_consensus::BlockOrigin; @@ -30,9 +34,10 @@ use sp_runtime::{ traits::{Block as BlockT, NumberFor}, Justifications, }; -use std::{any::Any, fmt, fmt::Formatter, task::Poll}; use warp::WarpSyncProgress; +use std::{any::Any, fmt, fmt::Formatter, pin::Pin, sync::Arc, task::Poll}; + /// The sync status of a peer we are trying to sync with #[derive(Debug)] pub struct PeerInfo { @@ -42,6 +47,17 @@ pub struct PeerInfo { pub best_number: NumberFor, } +/// Info about a peer's known state (both full and light). +#[derive(Clone, Debug)] +pub struct ExtendedPeerInfo { + /// Roles + pub roles: Roles, + /// Peer best block hash + pub best_hash: B::Hash, + /// Peer best block number + pub best_number: NumberFor, +} + /// Reported sync state. #[derive(Clone, Eq, PartialEq, Debug)] pub enum SyncState { @@ -251,6 +267,49 @@ impl fmt::Debug for OpaqueBlockResponse { } } +/// Provides high-level status of syncing. +#[async_trait::async_trait] +pub trait SyncStatusProvider: Send + Sync { + /// Get high-level view of the syncing status. + async fn status(&self) -> Result, ()>; +} + +#[async_trait::async_trait] +impl SyncStatusProvider for Arc +where + T: ?Sized, + T: SyncStatusProvider, + Block: BlockT, +{ + async fn status(&self) -> Result, ()> { + T::status(self).await + } +} + +/// Syncing-related events that other protocols can subscribe to. +pub enum SyncEvent { + /// Peer that the syncing implementation is tracking connected. + PeerConnected(PeerId), + + /// Peer that the syncing implementation was tracking disconnected. + PeerDisconnected(PeerId), +} + +pub trait SyncEventStream: Send + Sync { + /// Subscribe to syncing-related events. + fn event_stream(&self, name: &'static str) -> Pin + Send>>; +} + +impl SyncEventStream for Arc +where + T: ?Sized, + T: SyncEventStream, +{ + fn event_stream(&self, name: &'static str) -> Pin + Send>> { + T::event_stream(self, name) + } +} + /// Something that represents the syncing strategy to download past and future blocks of the chain. pub trait ChainSync: Send { /// Returns the state of the sync of the given peer. diff --git a/client/network/src/behaviour.rs b/client/network/src/behaviour.rs index 1ed8efbcdf949..5591290200361 100644 --- a/client/network/src/behaviour.rs +++ b/client/network/src/behaviour.rs @@ -41,7 +41,6 @@ use sc_network_common::{ request_responses::{IfDisconnected, ProtocolConfig, RequestFailure}, }; use sc_peerset::{PeersetHandle, ReputationChange}; -use sp_blockchain::HeaderBackend; use sp_runtime::traits::Block as BlockT; use std::{collections::HashSet, time::Duration}; @@ -50,13 +49,9 @@ pub use crate::request_responses::{InboundFailure, OutboundFailure, RequestId, R /// General behaviour of the network. Combines all protocols together. #[derive(NetworkBehaviour)] #[behaviour(out_event = "BehaviourOut")] -pub struct Behaviour -where - B: BlockT, - Client: HeaderBackend + 'static, -{ +pub struct Behaviour { /// 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, @@ -118,6 +113,8 @@ pub enum BehaviourOut { notifications_sink: NotificationsSink, /// Role of the remote. role: ObservedRole, + /// Received handshake. + received_handshake: Vec, }, /// The [`NotificationsSink`] object used to send notifications with the given peer must be @@ -151,12 +148,6 @@ pub enum BehaviourOut { messages: Vec<(ProtocolName, Bytes)>, }, - /// 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 { @@ -177,14 +168,10 @@ pub enum BehaviourOut { None, } -impl Behaviour -where - B: BlockT, - Client: HeaderBackend + 'static, -{ +impl Behaviour { /// Builds a new `Behaviour`. pub fn new( - substrate: Protocol, + substrate: Protocol, user_agent: String, local_public_key: PublicKey, disco_config: DiscoveryConfig, @@ -252,12 +239,12 @@ where } /// 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 } @@ -295,20 +282,22 @@ fn reported_roles_to_observed_role(roles: Roles) -> ObservedRole { } } -impl From> for BehaviourOut { - fn from(event: CustomMessageOutcome) -> Self { +impl From for BehaviourOut { + fn from(event: CustomMessageOutcome) -> Self { match event { CustomMessageOutcome::NotificationStreamOpened { remote, protocol, negotiated_fallback, roles, + received_handshake, notifications_sink, } => BehaviourOut::NotificationStreamOpened { remote, protocol, negotiated_fallback, role: reported_roles_to_observed_role(roles), + received_handshake, notifications_sink, }, CustomMessageOutcome::NotificationStreamReplaced { @@ -320,10 +309,6 @@ impl From> for BehaviourOut { 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) => - BehaviourOut::SyncDisconnected(peer_id), CustomMessageOutcome::None => BehaviourOut::None, } } diff --git a/client/network/src/config.rs b/client/network/src/config.rs index fc5304779dbfc..90d02af848bf4 100644 --- a/client/network/src/config.rs +++ b/client/network/src/config.rs @@ -22,7 +22,7 @@ //! See the documentation of [`Params`]. pub use sc_network_common::{ - config::ProtocolId, + config::{NetworkConfiguration, ProtocolId}, protocol::role::Role, request_responses::{ IncomingRequest, OutgoingResponse, ProtocolConfig as RequestResponseConfig, @@ -33,35 +33,12 @@ 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}, - multiaddr, Multiaddr, -}; use prometheus_endpoint::Registry; -use sc_network_common::{ - config::{MultiaddrWithPeerId, NonDefaultSetConfig, SetConfig, TransportConfig}, - sync::ChainSync, -}; -use sp_runtime::traits::Block as BlockT; -use std::{ - error::Error, - fs, - future::Future, - io::{self, Write}, - net::Ipv4Addr, - path::{Path, PathBuf}, - pin::Pin, - sync::Arc, -}; -use zeroize::Zeroize; +use sc_network_common::config::NonDefaultSetConfig; +use std::{future::Future, pin::Pin, sync::Arc}; /// Network initialization parameters. -pub struct Params -where - B: BlockT + 'static, -{ +pub struct Params { /// Assigned role for our node (full, light, ...). pub role: Role, @@ -81,12 +58,6 @@ where /// name on the wire. pub fork_id: Option, - /// 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, @@ -96,350 +67,3 @@ where /// Request response protocol configurations pub request_response_protocol_configs: Vec, } - -/// Sync operation mode. -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub enum SyncMode { - /// Full block download and verification. - Full, - /// Download blocks and the latest state. - Fast { - /// Skip state proof download and verification. - skip_proofs: bool, - /// Download indexed transactions for recent blocks. - storage_chain_mode: bool, - }, - /// Warp sync - verify authority set transitions and the latest state. - 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 - } -} - -/// Network service configuration. -#[derive(Clone, Debug)] -pub struct NetworkConfiguration { - /// Directory path to store network-specific configuration. None means nothing will be saved. - pub net_config_path: Option, - /// Multiaddresses to listen for incoming connections. - pub listen_addresses: Vec, - /// Multiaddresses to advertise. Detected automatically if empty. - pub public_addresses: Vec, - /// List of initial node addresses - pub boot_nodes: Vec, - /// The node key configuration, which determines the node's network identity keypair. - pub node_key: NodeKeyConfig, - /// List of request-response protocols that the node supports. - 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. - pub client_version: String, - /// Name of the node. Sent over the wire for debugging purposes. - pub node_name: String, - /// Configuration for the transport layer. - pub transport: TransportConfig, - /// Maximum number of peers to ask the same blocks in parallel. - pub max_parallel_downloads: u32, - /// Initial syncing mode. - pub sync_mode: SyncMode, - - /// True if Kademlia random discovery should be enabled. - /// - /// If true, the node will automatically randomly walk the DHT in order to find new peers. - pub enable_dht_random_walk: bool, - - /// Should we insert non-global addresses into the DHT? - pub allow_non_globals_in_dht: bool, - - /// Require iterative Kademlia DHT queries to use disjoint paths for increased resiliency in - /// the presence of potentially adversarial nodes. - pub kademlia_disjoint_query_paths: bool, - /// Enable serving block data over IPFS bitswap. - pub ipfs_server: bool, - - /// Size of Yamux receive window of all substreams. `None` for the default (256kiB). - /// Any value less than 256kiB is invalid. - /// - /// # Context - /// - /// By design, notifications substreams on top of Yamux connections only allow up to `N` bytes - /// to be transferred at a time, where `N` is the Yamux receive window size configurable here. - /// This means, in practice, that every `N` bytes must be acknowledged by the receiver before - /// the sender can send more data. The maximum bandwidth of each notifications substream is - /// therefore `N / round_trip_time`. - /// - /// It is recommended to leave this to `None`, and use a request-response protocol instead if - /// a large amount of data must be transferred. The reason why the value is configurable is - /// that some Substrate users mis-use notification protocols to send large amounts of data. - /// As such, this option isn't designed to stay and will likely get removed in the future. - /// - /// Note that configuring a value here isn't a modification of the Yamux protocol, but rather - /// a modification of the way the implementation works. Different nodes with different - /// configured values remain compatible with each other. - pub yamux_window_size: Option, -} - -impl NetworkConfiguration { - /// Create new default configuration - pub fn new, SV: Into>( - node_name: SN, - client_version: SV, - node_key: NodeKeyConfig, - net_config_path: Option, - ) -> Self { - let default_peers_set = SetConfig::default(); - Self { - net_config_path, - listen_addresses: Vec::new(), - public_addresses: Vec::new(), - boot_nodes: Vec::new(), - node_key, - request_response_protocols: Vec::new(), - 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(), - transport: TransportConfig::Normal { enable_mdns: false, allow_private_ip: true }, - max_parallel_downloads: 5, - sync_mode: SyncMode::Full, - enable_dht_random_walk: true, - allow_non_globals_in_dht: false, - kademlia_disjoint_query_paths: false, - yamux_window_size: None, - ipfs_server: false, - } - } - - /// Create new default configuration for localhost-only connection with random port (useful for - /// testing) - pub fn new_local() -> NetworkConfiguration { - let mut config = - NetworkConfiguration::new("test-node", "test-client", Default::default(), None); - - config.listen_addresses = - vec![iter::once(multiaddr::Protocol::Ip4(Ipv4Addr::new(127, 0, 0, 1))) - .chain(iter::once(multiaddr::Protocol::Tcp(0))) - .collect()]; - - config.allow_non_globals_in_dht = true; - config - } - - /// Create new default configuration for localhost-only connection with random port (useful for - /// testing) - pub fn new_memory() -> NetworkConfiguration { - let mut config = - NetworkConfiguration::new("test-node", "test-client", Default::default(), None); - - config.listen_addresses = - vec![iter::once(multiaddr::Protocol::Ip4(Ipv4Addr::new(127, 0, 0, 1))) - .chain(iter::once(multiaddr::Protocol::Tcp(0))) - .collect()]; - - config.allow_non_globals_in_dht = true; - config - } -} - -/// 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. -#[derive(Clone, Debug)] -pub enum NodeKeyConfig { - /// A Ed25519 secret key configuration. - Ed25519(Secret), -} - -impl Default for NodeKeyConfig { - fn default() -> NodeKeyConfig { - Self::Ed25519(Secret::New) - } -} - -/// The options for obtaining a Ed25519 secret key. -pub type Ed25519Secret = Secret; - -/// The configuration options for obtaining a secret key `K`. -#[derive(Clone)] -pub enum Secret { - /// Use the given secret key `K`. - Input(K), - /// Read the secret key from a file. If the file does not exist, - /// it is created with a newly generated secret key `K`. The format - /// of the file is determined by `K`: - /// - /// * `ed25519::SecretKey`: An unencoded 32 bytes Ed25519 secret key. - File(PathBuf), - /// Always generate a new secret key `K`. - New, -} - -impl fmt::Debug for Secret { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Self::Input(_) => f.debug_tuple("Secret::Input").finish(), - Self::File(path) => f.debug_tuple("Secret::File").field(path).finish(), - Self::New => f.debug_tuple("Secret::New").finish(), - } - } -} - -impl NodeKeyConfig { - /// Evaluate a `NodeKeyConfig` to obtain an identity `Keypair`: - /// - /// * If the secret is configured as input, the corresponding keypair is returned. - /// - /// * If the secret is configured as a file, it is read from that file, if it exists. Otherwise - /// a new secret is generated and stored. In either case, the keypair obtained from the - /// secret is returned. - /// - /// * If the secret is configured to be new, it is generated and the corresponding keypair is - /// returned. - pub fn into_keypair(self) -> io::Result { - use NodeKeyConfig::*; - match self { - Ed25519(Secret::New) => Ok(Keypair::generate_ed25519()), - - Ed25519(Secret::Input(k)) => Ok(Keypair::Ed25519(k.into())), - - Ed25519(Secret::File(f)) => get_secret( - f, - |mut b| match String::from_utf8(b.to_vec()).ok().and_then(|s| { - if s.len() == 64 { - array_bytes::hex2bytes(&s).ok() - } else { - None - } - }) { - Some(s) => ed25519::SecretKey::from_bytes(s), - _ => ed25519::SecretKey::from_bytes(&mut b), - }, - ed25519::SecretKey::generate, - |b| b.as_ref().to_vec(), - ) - .map(ed25519::Keypair::from) - .map(Keypair::Ed25519), - } - } -} - -/// Load a secret key from a file, if it exists, or generate a -/// new secret key and write it to that file. In either case, -/// the secret key is returned. -fn get_secret(file: P, parse: F, generate: G, serialize: W) -> io::Result -where - P: AsRef, - F: for<'r> FnOnce(&'r mut [u8]) -> Result, - G: FnOnce() -> K, - E: Error + Send + Sync + 'static, - W: Fn(&K) -> Vec, -{ - std::fs::read(&file) - .and_then(|mut sk_bytes| { - parse(&mut sk_bytes).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) - }) - .or_else(|e| { - if e.kind() == io::ErrorKind::NotFound { - file.as_ref().parent().map_or(Ok(()), fs::create_dir_all)?; - let sk = generate(); - let mut sk_vec = serialize(&sk); - write_secret_file(file, &sk_vec)?; - sk_vec.zeroize(); - Ok(sk) - } else { - Err(e) - } - }) -} - -/// Write secret bytes to a file. -fn write_secret_file

(path: P, sk_bytes: &[u8]) -> io::Result<()> -where - P: AsRef, -{ - let mut file = open_secret_file(&path)?; - file.write_all(sk_bytes) -} - -/// Opens a file containing a secret key in write mode. -#[cfg(unix)] -fn open_secret_file

(path: P) -> io::Result -where - P: AsRef, -{ - use std::os::unix::fs::OpenOptionsExt; - fs::OpenOptions::new().write(true).create_new(true).mode(0o600).open(path) -} - -/// Opens a file containing a secret key in write mode. -#[cfg(not(unix))] -fn open_secret_file

(path: P, sk_bytes: &[u8]) -> io::Result<()> -where - P: AsRef, -{ - let mut file = open_secret_file(&path)?; - file.write_all(sk_bytes) -} - -/// Opens a file containing a secret key in write mode. -#[cfg(unix)] -fn open_secret_file

(path: P) -> io::Result -where - P: AsRef, -{ - use std::os::unix::fs::OpenOptionsExt; - fs::OpenOptions::new().write(true).create_new(true).mode(0o600).open(path) -} - -/// Opens a file containing a secret key in write mode. -#[cfg(not(unix))] -fn open_secret_file

(path: P) -> Result -where - P: AsRef, -{ - fs::OpenOptions::new().write(true).create_new(true).open(path) -} - -#[cfg(test)] -mod tests { - use super::*; - use tempfile::TempDir; - - fn tempdir_with_prefix(prefix: &str) -> TempDir { - tempfile::Builder::new().prefix(prefix).tempdir().unwrap() - } - - fn secret_bytes(kp: &Keypair) -> Vec { - let Keypair::Ed25519(p) = kp; - p.secret().as_ref().iter().cloned().collect() - } - - #[test] - fn test_secret_file() { - let tmp = tempdir_with_prefix("x"); - std::fs::remove_dir(tmp.path()).unwrap(); // should be recreated - let file = tmp.path().join("x").to_path_buf(); - let kp1 = NodeKeyConfig::Ed25519(Secret::File(file.clone())).into_keypair().unwrap(); - let kp2 = NodeKeyConfig::Ed25519(Secret::File(file.clone())).into_keypair().unwrap(); - assert!(file.is_file() && secret_bytes(&kp1) == secret_bytes(&kp2)) - } - - #[test] - fn test_secret_input() { - let sk = ed25519::SecretKey::generate(); - let kp1 = NodeKeyConfig::Ed25519(Secret::Input(sk.clone())).into_keypair().unwrap(); - let kp2 = NodeKeyConfig::Ed25519(Secret::Input(sk)).into_keypair().unwrap(); - assert!(secret_bytes(&kp1) == secret_bytes(&kp2)); - } - - #[test] - fn test_secret_new() { - let kp1 = NodeKeyConfig::Ed25519(Secret::New).into_keypair().unwrap(); - let kp2 = NodeKeyConfig::Ed25519(Secret::New).into_keypair().unwrap(); - assert!(secret_bytes(&kp1) != secret_bytes(&kp2)); - } -} diff --git a/client/network/common/src/lib.rs b/client/network/common/src/lib.rs index 10d2449388bb9..f53590efd4c84 100644 --- a/client/network/common/src/lib.rs +++ b/client/network/common/src/lib.rs @@ -18,14 +18,9 @@ //! 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 role; 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 {} diff --git a/client/network/common/src/request_responses.rs b/client/network/common/src/request_responses.rs deleted file mode 100644 index 4fa53a736ac33..0000000000000 --- a/client/network/common/src/request_responses.rs +++ /dev/null @@ -1,155 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -//! 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::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: ProtocolName, - - /// 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 - /// 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>, -} - -/// 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/protocol/role.rs b/client/network/common/src/role.rs similarity index 100% rename from client/network/common/src/protocol/role.rs rename to client/network/common/src/role.rs diff --git a/client/network/common/src/sync.rs b/client/network/common/src/sync.rs index 262da6c202aa3..130f354b70050 100644 --- a/client/network/common/src/sync.rs +++ b/client/network/common/src/sync.rs @@ -22,7 +22,7 @@ pub mod message; pub mod metrics; pub mod warp; -use crate::protocol::role::Roles; +use crate::role::Roles; use futures::Stream; use libp2p::PeerId; diff --git a/client/network/common/src/sync/message.rs b/client/network/common/src/sync/message.rs index 7b8be18bda5cc..c651660c89c8d 100644 --- a/client/network/common/src/sync/message.rs +++ b/client/network/common/src/sync/message.rs @@ -19,7 +19,7 @@ //! Network packet message types. These get serialized and put into the lower level protocol //! payload. -use crate::protocol::role::Roles; +use crate::role::Roles; use bitflags::bitflags; use codec::{Decode, Encode, Error, Input, Output}; diff --git a/client/network/light/Cargo.toml b/client/network/light/Cargo.toml index f3e94790df61e..ed2a5d6cb4ec6 100644 --- a/client/network/light/Cargo.toml +++ b/client/network/light/Cargo.toml @@ -26,6 +26,7 @@ log = "0.4.16" 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 = { version = "0.10.0-dev", path = "../" } sc-network-common = { version = "0.10.0-dev", path = "../common" } sc-peerset = { version = "4.0.0-dev", path = "../../peerset" } sp-core = { version = "7.0.0", path = "../../../primitives/core" } diff --git a/client/network/light/src/light_client_requests.rs b/client/network/light/src/light_client_requests.rs index 5b6daf174cce6..4d2a301c00e6b 100644 --- a/client/network/light/src/light_client_requests.rs +++ b/client/network/light/src/light_client_requests.rs @@ -18,13 +18,13 @@ //! Helpers for outgoing and incoming light client requests. -/// For incoming light client requests. -pub mod handler; - -use sc_network_common::{config::ProtocolId, request_responses::ProtocolConfig}; +use sc_network::{config::ProtocolId, request_responses::ProtocolConfig}; use std::time::Duration; +/// For incoming light client requests. +pub mod handler; + /// 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(); diff --git a/client/network/light/src/light_client_requests/handler.rs b/client/network/light/src/light_client_requests/handler.rs index 0a1215a1dc6a9..db2630b79f498 100644 --- a/client/network/light/src/light_client_requests/handler.rs +++ b/client/network/light/src/light_client_requests/handler.rs @@ -29,7 +29,7 @@ use libp2p::PeerId; use log::{debug, trace}; use prost::Message; use sc_client_api::{BlockBackend, ProofProvider}; -use sc_network_common::{ +use sc_network::{ config::ProtocolId, request_responses::{IncomingRequest, OutgoingResponse, ProtocolConfig}, }; diff --git a/client/network/src/behaviour.rs b/client/network/src/behaviour.rs index 5591290200361..f068099928efc 100644 --- a/client/network/src/behaviour.rs +++ b/client/network/src/behaviour.rs @@ -18,9 +18,11 @@ use crate::{ discovery::{DiscoveryBehaviour, DiscoveryConfig, DiscoveryOut}, + event::DhtEvent, peer_info, protocol::{CustomMessageOutcome, NotificationsSink, Protocol}, - request_responses, + request_responses::{self, IfDisconnected, ProtocolConfig, RequestFailure}, + types::ProtocolName, }; use bytes::Bytes; @@ -32,14 +34,7 @@ use libp2p::{ swarm::NetworkBehaviour, }; -use sc_network_common::{ - protocol::{ - event::DhtEvent, - role::{ObservedRole, Roles}, - ProtocolName, - }, - request_responses::{IfDisconnected, ProtocolConfig, RequestFailure}, -}; +use sc_network_common::role::{ObservedRole, Roles}; use sc_peerset::{PeersetHandle, ReputationChange}; use sp_runtime::traits::Block as BlockT; use std::{collections::HashSet, time::Duration}; diff --git a/client/network/src/config.rs b/client/network/src/config.rs index 90d02af848bf4..925a7795d290f 100644 --- a/client/network/src/config.rs +++ b/client/network/src/config.rs @@ -21,21 +21,671 @@ //! The [`Params`] struct is the struct that must be passed in order to initialize the networking. //! See the documentation of [`Params`]. -pub use sc_network_common::{ - config::{NetworkConfiguration, ProtocolId}, - protocol::role::Role, +pub use crate::{ request_responses::{ IncomingRequest, OutgoingResponse, ProtocolConfig as RequestResponseConfig, }, - sync::warp::WarpSyncProvider, - ExHashT, + types::ProtocolName, }; -pub use libp2p::{build_multiaddr, core::PublicKey, identity}; - +use codec::Encode; +use libp2p::{identity::Keypair, multiaddr, Multiaddr, PeerId}; use prometheus_endpoint::Registry; -use sc_network_common::config::NonDefaultSetConfig; -use std::{future::Future, pin::Pin, sync::Arc}; +pub use sc_network_common::{role::Role, sync::warp::WarpSyncProvider, ExHashT}; +use zeroize::Zeroize; + +use std::{ + error::Error, + fmt, fs, + future::Future, + io::{self, Write}, + iter, + net::Ipv4Addr, + path::{Path, PathBuf}, + pin::Pin, + str::{self, FromStr}, + sync::Arc, +}; + +pub use libp2p::{ + build_multiaddr, + identity::{self, ed25519}, +}; + +/// Protocol name prefix, transmitted on the wire for legacy protocol names. +/// I.e., `dot` in `/dot/sync/2`. Should be unique for each chain. Always UTF-8. +/// Deprecated in favour of genesis hash & fork ID based protocol names. +#[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. +/// +/// # Example +/// +/// ``` +/// # use libp2p::{Multiaddr, PeerId}; +/// use sc_network::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::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) + } +} + +/// 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 + } +} + +/// 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/IPv6 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_ip: 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, + } + } +} + +/// Sync operation mode. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum SyncMode { + /// Full block download and verification. + Full, + /// Download blocks and the latest state. + Fast { + /// Skip state proof download and verification. + skip_proofs: bool, + /// Download indexed transactions for recent blocks. + storage_chain_mode: bool, + }, + /// Warp sync - verify authority set transitions and the latest state. + 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 + } +} + +/// 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. +#[derive(Clone, Debug)] +pub enum NodeKeyConfig { + /// A Ed25519 secret key configuration. + Ed25519(Secret), +} + +impl Default for NodeKeyConfig { + fn default() -> NodeKeyConfig { + Self::Ed25519(Secret::New) + } +} + +/// The options for obtaining a Ed25519 secret key. +pub type Ed25519Secret = Secret; + +/// The configuration options for obtaining a secret key `K`. +#[derive(Clone)] +pub enum Secret { + /// Use the given secret key `K`. + Input(K), + /// Read the secret key from a file. If the file does not exist, + /// it is created with a newly generated secret key `K`. The format + /// of the file is determined by `K`: + /// + /// * `ed25519::SecretKey`: An unencoded 32 bytes Ed25519 secret key. + File(PathBuf), + /// Always generate a new secret key `K`. + New, +} + +impl fmt::Debug for Secret { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::Input(_) => f.debug_tuple("Secret::Input").finish(), + Self::File(path) => f.debug_tuple("Secret::File").field(path).finish(), + Self::New => f.debug_tuple("Secret::New").finish(), + } + } +} + +impl NodeKeyConfig { + /// Evaluate a `NodeKeyConfig` to obtain an identity `Keypair`: + /// + /// * If the secret is configured as input, the corresponding keypair is returned. + /// + /// * If the secret is configured as a file, it is read from that file, if it exists. Otherwise + /// a new secret is generated and stored. In either case, the keypair obtained from the + /// secret is returned. + /// + /// * If the secret is configured to be new, it is generated and the corresponding keypair is + /// returned. + pub fn into_keypair(self) -> io::Result { + use NodeKeyConfig::*; + match self { + Ed25519(Secret::New) => Ok(Keypair::generate_ed25519()), + + Ed25519(Secret::Input(k)) => Ok(Keypair::Ed25519(k.into())), + + Ed25519(Secret::File(f)) => get_secret( + f, + |mut b| match String::from_utf8(b.to_vec()).ok().and_then(|s| { + if s.len() == 64 { + array_bytes::hex2bytes(&s).ok() + } else { + None + } + }) { + Some(s) => ed25519::SecretKey::from_bytes(s), + _ => ed25519::SecretKey::from_bytes(&mut b), + }, + ed25519::SecretKey::generate, + |b| b.as_ref().to_vec(), + ) + .map(ed25519::Keypair::from) + .map(Keypair::Ed25519), + } + } +} + +/// Load a secret key from a file, if it exists, or generate a +/// new secret key and write it to that file. In either case, +/// the secret key is returned. +fn get_secret(file: P, parse: F, generate: G, serialize: W) -> io::Result +where + P: AsRef, + F: for<'r> FnOnce(&'r mut [u8]) -> Result, + G: FnOnce() -> K, + E: Error + Send + Sync + 'static, + W: Fn(&K) -> Vec, +{ + std::fs::read(&file) + .and_then(|mut sk_bytes| { + parse(&mut sk_bytes).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) + }) + .or_else(|e| { + if e.kind() == io::ErrorKind::NotFound { + file.as_ref().parent().map_or(Ok(()), fs::create_dir_all)?; + let sk = generate(); + let mut sk_vec = serialize(&sk); + write_secret_file(file, &sk_vec)?; + sk_vec.zeroize(); + Ok(sk) + } else { + Err(e) + } + }) +} + +/// Write secret bytes to a file. +fn write_secret_file

(path: P, sk_bytes: &[u8]) -> io::Result<()> +where + P: AsRef, +{ + let mut file = open_secret_file(&path)?; + file.write_all(sk_bytes) +} + +/// Opens a file containing a secret key in write mode. +#[cfg(unix)] +fn open_secret_file

(path: P) -> io::Result +where + P: AsRef, +{ + use std::os::unix::fs::OpenOptionsExt; + fs::OpenOptions::new().write(true).create_new(true).mode(0o600).open(path) +} + +/// Opens a file containing a secret key in write mode. +#[cfg(not(unix))] +fn open_secret_file

(path: P) -> Result +where + P: AsRef, +{ + fs::OpenOptions::new().write(true).create_new(true).open(path) +} + +/// 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 + /// `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, + + /// 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(), + handshake: None, + 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); + } +} + +/// Network service configuration. +#[derive(Clone, Debug)] +pub struct NetworkConfiguration { + /// Directory path to store network-specific configuration. None means nothing will be saved. + pub net_config_path: Option, + + /// Multiaddresses to listen for incoming connections. + pub listen_addresses: Vec, + + /// Multiaddresses to advertise. Detected automatically if empty. + pub public_addresses: Vec, + + /// List of initial node addresses + pub boot_nodes: Vec, + + /// The node key configuration, which determines the node's network identity keypair. + pub node_key: NodeKeyConfig, + + /// List of request-response protocols that the node supports. + 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. + pub client_version: String, + + /// Name of the node. Sent over the wire for debugging purposes. + pub node_name: String, + + /// Configuration for the transport layer. + pub transport: TransportConfig, + + /// Maximum number of peers to ask the same blocks in parallel. + pub max_parallel_downloads: u32, + + /// Initial syncing mode. + pub sync_mode: SyncMode, + + /// True if Kademlia random discovery should be enabled. + /// + /// If true, the node will automatically randomly walk the DHT in order to find new peers. + pub enable_dht_random_walk: bool, + + /// Should we insert non-global addresses into the DHT? + pub allow_non_globals_in_dht: bool, + + /// Require iterative Kademlia DHT queries to use disjoint paths for increased resiliency in + /// the presence of potentially adversarial nodes. + pub kademlia_disjoint_query_paths: bool, + + /// Enable serving block data over IPFS bitswap. + pub ipfs_server: bool, + + /// Size of Yamux receive window of all substreams. `None` for the default (256kiB). + /// Any value less than 256kiB is invalid. + /// + /// # Context + /// + /// By design, notifications substreams on top of Yamux connections only allow up to `N` bytes + /// to be transferred at a time, where `N` is the Yamux receive window size configurable here. + /// This means, in practice, that every `N` bytes must be acknowledged by the receiver before + /// the sender can send more data. The maximum bandwidth of each notifications substream is + /// therefore `N / round_trip_time`. + /// + /// It is recommended to leave this to `None`, and use a request-response protocol instead if + /// a large amount of data must be transferred. The reason why the value is configurable is + /// that some Substrate users mis-use notification protocols to send large amounts of data. + /// As such, this option isn't designed to stay and will likely get removed in the future. + /// + /// Note that configuring a value here isn't a modification of the Yamux protocol, but rather + /// a modification of the way the implementation works. Different nodes with different + /// configured values remain compatible with each other. + pub yamux_window_size: Option, +} + +impl NetworkConfiguration { + /// Create new default configuration + pub fn new, SV: Into>( + node_name: SN, + client_version: SV, + node_key: NodeKeyConfig, + net_config_path: Option, + ) -> Self { + let default_peers_set = SetConfig::default(); + Self { + net_config_path, + listen_addresses: Vec::new(), + public_addresses: Vec::new(), + boot_nodes: Vec::new(), + node_key, + request_response_protocols: Vec::new(), + 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(), + transport: TransportConfig::Normal { enable_mdns: false, allow_private_ip: true }, + max_parallel_downloads: 5, + sync_mode: SyncMode::Full, + enable_dht_random_walk: true, + allow_non_globals_in_dht: false, + kademlia_disjoint_query_paths: false, + yamux_window_size: None, + ipfs_server: false, + } + } + + /// Create new default configuration for localhost-only connection with random port (useful for + /// testing) + pub fn new_local() -> NetworkConfiguration { + let mut config = + NetworkConfiguration::new("test-node", "test-client", Default::default(), None); + + config.listen_addresses = + vec![iter::once(multiaddr::Protocol::Ip4(Ipv4Addr::new(127, 0, 0, 1))) + .chain(iter::once(multiaddr::Protocol::Tcp(0))) + .collect()]; + + config.allow_non_globals_in_dht = true; + config + } + + /// Create new default configuration for localhost-only connection with random port (useful for + /// testing) + pub fn new_memory() -> NetworkConfiguration { + let mut config = + NetworkConfiguration::new("test-node", "test-client", Default::default(), None); + + config.listen_addresses = + vec![iter::once(multiaddr::Protocol::Ip4(Ipv4Addr::new(127, 0, 0, 1))) + .chain(iter::once(multiaddr::Protocol::Tcp(0))) + .collect()]; + + config.allow_non_globals_in_dht = true; + config + } +} /// Network initialization parameters. pub struct Params { @@ -67,3 +717,43 @@ pub struct Params { /// Request response protocol configurations pub request_response_protocol_configs: Vec, } + +#[cfg(test)] +mod tests { + use super::*; + use tempfile::TempDir; + + fn tempdir_with_prefix(prefix: &str) -> TempDir { + tempfile::Builder::new().prefix(prefix).tempdir().unwrap() + } + + fn secret_bytes(kp: &Keypair) -> Vec { + let Keypair::Ed25519(p) = kp; + p.secret().as_ref().iter().cloned().collect() + } + + #[test] + fn test_secret_file() { + let tmp = tempdir_with_prefix("x"); + std::fs::remove_dir(tmp.path()).unwrap(); // should be recreated + let file = tmp.path().join("x").to_path_buf(); + let kp1 = NodeKeyConfig::Ed25519(Secret::File(file.clone())).into_keypair().unwrap(); + let kp2 = NodeKeyConfig::Ed25519(Secret::File(file.clone())).into_keypair().unwrap(); + assert!(file.is_file() && secret_bytes(&kp1) == secret_bytes(&kp2)) + } + + #[test] + fn test_secret_input() { + let sk = ed25519::SecretKey::generate(); + let kp1 = NodeKeyConfig::Ed25519(Secret::Input(sk.clone())).into_keypair().unwrap(); + let kp2 = NodeKeyConfig::Ed25519(Secret::Input(sk)).into_keypair().unwrap(); + assert!(secret_bytes(&kp1) == secret_bytes(&kp2)); + } + + #[test] + fn test_secret_new() { + let kp1 = NodeKeyConfig::Ed25519(Secret::New).into_keypair().unwrap(); + let kp2 = NodeKeyConfig::Ed25519(Secret::New).into_keypair().unwrap(); + assert!(secret_bytes(&kp1) != secret_bytes(&kp2)); + } +} diff --git a/client/network/src/discovery.rs b/client/network/src/discovery.rs index 6a8c777cac9c6..7100c0c70d525 100644 --- a/client/network/src/discovery.rs +++ b/client/network/src/discovery.rs @@ -46,6 +46,8 @@ //! 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 array_bytes::bytes2hex; use futures::prelude::*; use futures_timer::Delay; @@ -73,7 +75,6 @@ use libp2p::{ }, }; use log::{debug, info, trace, warn}; -use sc_network_common::{config::ProtocolId, utils::LruHashSet}; use sp_core::hexdisplay::HexDisplay; use std::{ cmp, @@ -904,6 +905,7 @@ mod tests { use super::{ kademlia_protocol_name, legacy_kademlia_protocol_name, DiscoveryConfig, DiscoveryOut, }; + use crate::config::ProtocolId; use futures::prelude::*; use libp2p::{ core::{ @@ -915,7 +917,6 @@ mod tests { swarm::{Executor, Swarm, SwarmEvent}, yamux, Multiaddr, }; - use sc_network_common::config::ProtocolId; use sp_core::hash::H256; use std::{collections::HashSet, pin::Pin, task::Poll}; diff --git a/client/network/common/src/error.rs b/client/network/src/error.rs similarity index 97% rename from client/network/common/src/error.rs rename to client/network/src/error.rs index 712b8c5de3f66..f0828fb821f35 100644 --- a/client/network/common/src/error.rs +++ b/client/network/src/error.rs @@ -18,7 +18,8 @@ //! Substrate network possible errors. -use crate::{config::TransportConfig, protocol::ProtocolName}; +use crate::{config::TransportConfig, types::ProtocolName}; + use libp2p::{Multiaddr, PeerId}; use std::fmt; diff --git a/client/network/common/src/protocol/event.rs b/client/network/src/event.rs similarity index 97% rename from client/network/common/src/protocol/event.rs rename to client/network/src/event.rs index 90c38b48c320f..3ecd8f9311429 100644 --- a/client/network/common/src/protocol/event.rs +++ b/client/network/src/event.rs @@ -19,11 +19,13 @@ //! 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 crate::protocol::role::ObservedRole; +use crate::types::ProtocolName; + use bytes::Bytes; use libp2p::{core::PeerId, kad::record::Key}; +use sc_network_common::role::ObservedRole; + /// Events generated by DHT as a response to get_value and put_value requests. #[derive(Debug, Clone)] #[must_use] diff --git a/client/network/src/lib.rs b/client/network/src/lib.rs index f94a71681cd3d..c290f4b94db53 100644 --- a/client/network/src/lib.rs +++ b/client/network/src/lib.rs @@ -248,36 +248,40 @@ mod behaviour; mod discovery; mod peer_info; mod protocol; -mod request_responses; mod service; mod transport; pub mod config; +pub mod error; +pub mod event; pub mod network_state; +pub mod request_responses; +pub mod types; +pub mod utils; +pub use event::{DhtEvent, Event}; #[doc(inline)] pub use libp2p::{multiaddr, Multiaddr, PeerId}; +pub use request_responses::{IfDisconnected, RequestFailure, RequestResponseConfig}; pub use sc_network_common::{ - protocol::{ - event::{DhtEvent, Event}, - role::ObservedRole, - ProtocolName, - }, - request_responses::{IfDisconnected, RequestFailure}, - service::{ - KademliaKey, NetworkBlock, NetworkDHTProvider, NetworkRequest, NetworkSigner, - NetworkStateInfo, NetworkStatus, NetworkStatusProvider, NetworkSyncForkRequest, Signature, - SigningError, - }, + role::ObservedRole, sync::{ warp::{WarpSyncPhase, WarpSyncProgress}, ExtendedPeerInfo, StateDownloadProgress, SyncEventStream, SyncState, SyncStatusProvider, }, }; pub use service::{ - DecodingError, Keypair, NetworkService, NetworkWorker, NotificationSender, - NotificationSenderReady, OutboundFailure, PublicKey, + signature::Signature, + traits::{ + KademliaKey, NetworkBlock, NetworkDHTProvider, NetworkEventStream, NetworkNotification, + NetworkPeers, NetworkRequest, NetworkSigner, NetworkStateInfo, NetworkStatus, + NetworkStatusProvider, NetworkSyncForkRequest, NotificationSender as NotificationSenderT, + NotificationSenderError, NotificationSenderReady, + }, + DecodingError, Keypair, NetworkService, NetworkWorker, NotificationSender, OutboundFailure, + PublicKey, }; +pub use types::ProtocolName; pub use sc_peerset::ReputationChange; diff --git a/client/network/src/peer_info.rs b/client/network/src/peer_info.rs index 1cf0c928a4067..3f769736ff10e 100644 --- a/client/network/src/peer_info.rs +++ b/client/network/src/peer_info.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 crate::utils::interval; + use fnv::FnvHashMap; use futures::prelude::*; use libp2p::{ @@ -36,8 +38,8 @@ use libp2p::{ Multiaddr, }; use log::{debug, error, trace}; -use sc_network_common::utils::interval; use smallvec::SmallVec; + use std::{ collections::hash_map::Entry, pin::Pin, diff --git a/client/network/src/protocol.rs b/client/network/src/protocol.rs index 8d604124233a0..06ca02c0ca8d5 100644 --- a/client/network/src/protocol.rs +++ b/client/network/src/protocol.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::config; +use crate::{ + config::{self, NonReservedPeerMode}, + error, + types::ProtocolName, +}; use bytes::Bytes; use codec::{DecodeAll, Encode}; @@ -29,27 +33,25 @@ use libp2p::{ Multiaddr, PeerId, }; use log::{debug, error, warn}; -use message::{generic::Message as GenericMessage, Message}; -use notifications::{Notifications, NotificationsOut}; -use sc_network_common::{ - config::NonReservedPeerMode, - error, - protocol::{role::Roles, ProtocolName}, - sync::message::BlockAnnouncesHandshake, -}; + +use sc_network_common::{role::Roles, sync::message::BlockAnnouncesHandshake}; use sp_runtime::traits::Block as BlockT; + use std::{ collections::{HashMap, HashSet, VecDeque}, iter, task::Poll, }; +use message::{generic::Message as GenericMessage, Message}; +use notifications::{Notifications, NotificationsOut}; + +pub use notifications::{NotificationsSink, NotifsHandlerError, Ready}; + mod notifications; pub mod message; -pub use notifications::{NotificationsSink, NotifsHandlerError, Ready}; - /// Maximum size used for notifications in the block announce and transaction protocols. // Must be equal to `max(MAX_BLOCK_ANNOUNCE_SIZE, MAX_TRANSACTIONS_SIZE)`. pub(crate) const BLOCK_ANNOUNCES_TRANSACTIONS_SUBSTREAM_SIZE: u64 = 16 * 1024 * 1024; @@ -93,7 +95,7 @@ impl Protocol { pub fn new( roles: Roles, network_config: &config::NetworkConfiguration, - block_announces_protocol: sc_network_common::config::NonDefaultSetConfig, + block_announces_protocol: config::NonDefaultSetConfig, ) -> error::Result<(Self, sc_peerset::PeersetHandle, Vec<(PeerId, Multiaddr)>)> { let mut known_addresses = Vec::new(); diff --git a/client/network/src/protocol/message.rs b/client/network/src/protocol/message.rs index f7981f1714951..66dca2975375f 100644 --- a/client/network/src/protocol/message.rs +++ b/client/network/src/protocol/message.rs @@ -61,7 +61,7 @@ pub mod generic { use sc_client_api::StorageProof; use sc_network_common::{ message::RequestId, - protocol::role::Roles, + role::Roles, sync::message::{ generic::{BlockRequest, BlockResponse}, BlockAnnounce, diff --git a/client/network/src/protocol/notifications/behaviour.rs b/client/network/src/protocol/notifications/behaviour.rs index 093d5846db7de..74e27fa17c602 100644 --- a/client/network/src/protocol/notifications/behaviour.rs +++ b/client/network/src/protocol/notifications/behaviour.rs @@ -16,8 +16,11 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use crate::protocol::notifications::handler::{ - self, NotificationsSink, NotifsHandlerIn, NotifsHandlerOut, NotifsHandlerProto, +use crate::{ + protocol::notifications::handler::{ + self, NotificationsSink, NotifsHandlerIn, NotifsHandlerOut, NotifsHandlerProto, + }, + types::ProtocolName, }; use bytes::BytesMut; @@ -35,7 +38,6 @@ 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::{ diff --git a/client/network/src/protocol/notifications/handler.rs b/client/network/src/protocol/notifications/handler.rs index 70157386ef32e..9d8d98fd8cf27 100644 --- a/client/network/src/protocol/notifications/handler.rs +++ b/client/network/src/protocol/notifications/handler.rs @@ -57,9 +57,12 @@ //! It is illegal to send a [`NotifsHandlerIn::Open`] before a previously-emitted //! [`NotifsHandlerIn::Open`] has gotten an answer. -use crate::protocol::notifications::upgrade::{ - NotificationsIn, NotificationsInSubstream, NotificationsOut, NotificationsOutSubstream, - UpgradeCollec, +use crate::{ + protocol::notifications::upgrade::{ + NotificationsIn, NotificationsInSubstream, NotificationsOut, NotificationsOutSubstream, + UpgradeCollec, + }, + types::ProtocolName, }; use bytes::BytesMut; @@ -77,7 +80,6 @@ use libp2p::{ }; use log::error; use parking_lot::{Mutex, RwLock}; -use sc_network_common::protocol::ProtocolName; use std::{ collections::VecDeque, mem, @@ -945,8 +947,9 @@ pub mod tests { Poll::Ready(Some(NotificationsSinkMessage::Notification { message })) => Poll::Ready(Some(message)), Poll::Pending => Poll::Ready(None), - Poll::Ready(Some(NotificationsSinkMessage::ForceClose)) | Poll::Ready(None) => - panic!("sink closed"), + Poll::Ready(Some(NotificationsSinkMessage::ForceClose)) | Poll::Ready(None) => { + panic!("sink closed") + }, }) .await } diff --git a/client/network/src/protocol/notifications/upgrade/collec.rs b/client/network/src/protocol/notifications/upgrade/collec.rs index 89999ff0c7534..791821b3f75da 100644 --- a/client/network/src/protocol/notifications/upgrade/collec.rs +++ b/client/network/src/protocol/notifications/upgrade/collec.rs @@ -103,8 +103,8 @@ impl>, O, E> Future for FutWithUsize { #[cfg(test)] mod tests { use super::*; + use crate::types::ProtocolName as ProtoName; use libp2p::core::upgrade::{ProtocolName, UpgradeInfo}; - use sc_network_common::protocol::ProtocolName as ProtoName; // TODO: move to mocks mockall::mock! { diff --git a/client/network/src/protocol/notifications/upgrade/notifications.rs b/client/network/src/protocol/notifications/upgrade/notifications.rs index bfdd9ccfa7eb9..4e1c033f33b68 100644 --- a/client/network/src/protocol/notifications/upgrade/notifications.rs +++ b/client/network/src/protocol/notifications/upgrade/notifications.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 asynchronous_codec::Framed; /// Notifications protocol. /// /// The Substrate notifications protocol consists in the following: @@ -35,11 +34,15 @@ use asynchronous_codec::Framed; /// /// Notification substreams are unidirectional. If A opens a substream with B, then B is /// encouraged but not required to open a substream to A as well. +use crate::types::ProtocolName; + +use asynchronous_codec::Framed; use bytes::BytesMut; use futures::prelude::*; use libp2p::core::{upgrade, InboundUpgrade, OutboundUpgrade, UpgradeInfo}; use log::{error, warn}; -use sc_network_common::protocol::ProtocolName; +use unsigned_varint::codec::UviBytes; + use std::{ convert::Infallible, io, mem, @@ -47,7 +50,6 @@ use std::{ task::{Context, Poll}, vec, }; -use unsigned_varint::codec::UviBytes; /// Maximum allowed size of the two handshake messages, in bytes. const MAX_HANDSHAKE_SIZE: usize = 1024; diff --git a/client/network/src/request_responses.rs b/client/network/src/request_responses.rs index 37c97e8282b4c..4628b0191a2e8 100644 --- a/client/network/src/request_responses.rs +++ b/client/network/src/request_responses.rs @@ -34,7 +34,8 @@ //! - If provided, a ["requests processing"](ProtocolConfig::inbound_queue) channel //! is used to handle incoming requests. -use crate::ReputationChange; +use crate::{types::ProtocolName, ReputationChange}; + use futures::{ channel::{mpsc, oneshot}, prelude::*, @@ -43,7 +44,7 @@ use libp2p::{ core::{connection::ConnectionId, Multiaddr, PeerId}, request_response::{ handler::RequestResponseHandler, ProtocolSupport, RequestResponse, RequestResponseCodec, - RequestResponseConfig, RequestResponseEvent, RequestResponseMessage, ResponseChannel, + RequestResponseEvent, RequestResponseMessage, ResponseChannel, }, swarm::{ behaviour::{ConnectionClosed, DialFailure, FromSwarm, ListenFailure}, @@ -52,12 +53,9 @@ use libp2p::{ PollParameters, }, }; -use sc_network_common::{ - protocol::ProtocolName, - request_responses::{ - IfDisconnected, IncomingRequest, OutgoingResponse, ProtocolConfig, RequestFailure, - }, -}; + +use sc_peerset::{PeersetHandle, BANNED_THRESHOLD}; + use std::{ collections::{hash_map::Entry, HashMap}, io, iter, @@ -66,8 +64,138 @@ use std::{ time::{Duration, Instant}, }; -pub use libp2p::request_response::{InboundFailure, OutboundFailure, RequestId}; -use sc_peerset::{PeersetHandle, BANNED_THRESHOLD}; +pub use libp2p::request_response::{ + InboundFailure, OutboundFailure, RequestId, RequestResponseConfig, +}; + +/// 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, + #[error("Problem on the network: {0}")] + Network(OutboundFailure), +} + +/// 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: ProtocolName, + + /// 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 + /// 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>, +} + +/// 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, + } + } +} /// Event generated by the [`RequestResponsesBehaviour`]. #[derive(Debug)] @@ -103,7 +231,12 @@ pub enum Event { }, /// A request protocol handler issued reputation changes for the given peer. - ReputationChanges { peer: PeerId, changes: Vec }, + ReputationChanges { + /// Peer whose reputation needs to be adjust. + peer: PeerId, + /// Reputation changes. + changes: Vec, + }, } /// Combination of a protocol name and a request id. @@ -344,7 +477,7 @@ impl NetworkBehaviour for RequestResponsesBehaviour { ) } }, - FromSwarm::DialFailure(DialFailure { peer_id, error, handler }) => + FromSwarm::DialFailure(DialFailure { peer_id, error, handler }) => { for (p_name, p_handler) in handler.into_iter() { if let Some((proto, _)) = self.protocols.get_mut(p_name.as_str()) { proto.on_swarm_event(FromSwarm::DialFailure(DialFailure { @@ -359,7 +492,8 @@ impl NetworkBehaviour for RequestResponsesBehaviour { p_name, ) } - }, + } + }, FromSwarm::ListenerClosed(e) => for (p, _) in self.protocols.values_mut() { NetworkBehaviour::on_swarm_event(p, FromSwarm::ListenerClosed(e)); diff --git a/client/network/src/service.rs b/client/network/src/service.rs index 4a05393618cfb..6dc00b36ceb53 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -29,13 +29,27 @@ use crate::{ behaviour::{self, Behaviour, BehaviourOut}, - config::Params, + config::{MultiaddrWithPeerId, Params, TransportConfig}, discovery::DiscoveryConfig, + error::Error, + event::{DhtEvent, Event}, network_state::{ NetworkState, NotConnectedPeer as NetworkStateNotConnectedPeer, Peer as NetworkStatePeer, }, protocol::{self, NotificationsSink, NotifsHandlerError, Protocol, Ready}, - transport, ReputationChange, + request_responses::{IfDisconnected, RequestFailure}, + service::{ + signature::{Signature, SigningError}, + traits::{ + NetworkDHTProvider, NetworkEventStream, NetworkNotification, NetworkPeers, + NetworkRequest, NetworkSigner, NetworkStateInfo, NetworkStatus, NetworkStatusProvider, + NotificationSender as NotificationSenderT, NotificationSenderError, + NotificationSenderReady as NotificationSenderReadyT, + }, + }, + transport, + types::ProtocolName, + ReputationChange, }; use futures::{channel::oneshot, prelude::*}; @@ -55,26 +69,13 @@ use libp2p::{ use log::{debug, error, info, trace, warn}; use metrics::{Histogram, HistogramVec, MetricSources, Metrics}; use parking_lot::Mutex; -use sc_network_common::{ - config::{MultiaddrWithPeerId, TransportConfig}, - error::Error, - protocol::{ - event::{DhtEvent, Event}, - ProtocolName, - }, - request_responses::{IfDisconnected, RequestFailure}, - service::{ - NetworkDHTProvider, NetworkEventStream, NetworkNotification, NetworkPeers, NetworkSigner, - NetworkStateInfo, NetworkStatus, NetworkStatusProvider, - NotificationSender as NotificationSenderT, NotificationSenderError, - NotificationSenderReady as NotificationSenderReadyT, Signature, SigningError, - }, - ExHashT, -}; + +use sc_network_common::ExHashT; use sc_peerset::PeersetHandle; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; use sp_blockchain::HeaderBackend; use sp_runtime::traits::{Block as BlockT, Zero}; + use std::{ cmp, collections::{HashMap, HashSet}, @@ -90,14 +91,13 @@ use std::{ }; pub use behaviour::{InboundFailure, OutboundFailure, ResponseFailure}; +pub use libp2p::identity::{error::DecodingError, Keypair, PublicKey}; mod metrics; mod out_events; -#[cfg(test)] -mod tests; -pub use libp2p::identity::{error::DecodingError, Keypair, PublicKey}; -use sc_network_common::service::NetworkRequest; +pub mod signature; +pub mod traits; /// Custom error that can be produced by the [`ConnectionHandler`] of the [`NetworkBehaviour`]. /// Used as a template parameter of [`SwarmEvent`] below. @@ -1432,10 +1432,11 @@ where }, } }, - SwarmEvent::Behaviour(BehaviourOut::ReputationChanges { peer, changes }) => + SwarmEvent::Behaviour(BehaviourOut::ReputationChanges { peer, changes }) => { for change in changes { self.network_service.behaviour().user_protocol().report_peer(peer, change); - }, + } + }, SwarmEvent::Behaviour(BehaviourOut::PeerIdentify { peer_id, info: @@ -1467,10 +1468,11 @@ where .user_protocol_mut() .add_default_set_discovered_nodes(iter::once(peer_id)); }, - SwarmEvent::Behaviour(BehaviourOut::RandomKademliaStarted) => + SwarmEvent::Behaviour(BehaviourOut::RandomKademliaStarted) => { if let Some(metrics) = self.metrics.as_ref() { metrics.kademlia_random_queries_total.inc(); - }, + } + }, SwarmEvent::Behaviour(BehaviourOut::NotificationStreamOpened { remote, protocol, diff --git a/client/network/src/service/out_events.rs b/client/network/src/service/out_events.rs index 3771ea1643aec..398c26793fd41 100644 --- a/client/network/src/service/out_events.rs +++ b/client/network/src/service/out_events.rs @@ -31,11 +31,12 @@ //! - Send events by calling [`OutChannels::send`]. Events are cloned for each sender in the //! collection. +use crate::event::Event; + use futures::{prelude::*, ready, stream::FusedStream}; use log::error; use parking_lot::Mutex; use prometheus_endpoint::{register, CounterVec, GaugeVec, Opts, PrometheusError, Registry, U64}; -use sc_network_common::protocol::event::Event; use std::{ backtrace::Backtrace, cell::RefCell, diff --git a/client/network/common/src/service/signature.rs b/client/network/src/service/signature.rs similarity index 96% rename from client/network/common/src/service/signature.rs rename to client/network/src/service/signature.rs index 14addafc6bba2..e52dd6b1d2a29 100644 --- a/client/network/common/src/service/signature.rs +++ b/client/network/src/service/signature.rs @@ -19,10 +19,12 @@ // If you read this, you are very thorough, congratulations. use libp2p::{ - identity::{error::SigningError, Keypair, PublicKey}, + identity::{Keypair, PublicKey}, PeerId, }; +pub use libp2p::identity::error::SigningError; + /// 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`. diff --git a/client/network/src/service/tests/mod.rs b/client/network/src/service/tests/mod.rs deleted file mode 100644 index f29e43e6ce366..0000000000000 --- a/client/network/src/service/tests/mod.rs +++ /dev/null @@ -1,240 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use crate::{config, NetworkService, NetworkWorker}; - -use futures::prelude::*; -use libp2p::Multiaddr; -use sc_consensus::{ImportQueue, Link}; -use sc_network_common::{ - config::{NonDefaultSetConfig, ProtocolId, SetConfig, TransportConfig}, - protocol::{event::Event, role::Roles}, - service::NetworkEventStream, -}; -use sc_network_light::light_client_requests::handler::LightClientRequestHandler; -use sc_network_sync::{ - block_request_handler::BlockRequestHandler, - engine::SyncingEngine, - service::network::{NetworkServiceHandle, NetworkServiceProvider}, - state_request_handler::StateRequestHandler, -}; -use sp_runtime::traits::Block as BlockT; -use std::sync::Arc; -use substrate_test_runtime_client::{ - runtime::{Block as TestBlock, Hash as TestHash}, - TestClientBuilder, TestClientBuilderExt as _, -}; - -#[cfg(test)] -mod service; - -type TestNetworkWorker = NetworkWorker; -type TestNetworkService = NetworkService; - -const PROTOCOL_NAME: &str = "/foo"; - -struct TestNetwork { - network: TestNetworkWorker, -} - -impl TestNetwork { - pub fn new(network: TestNetworkWorker) -> Self { - 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"); - - tokio::spawn(worker.run()); - - (service, event_stream) - } -} - -struct TestNetworkBuilder { - import_queue: Option>>, - link: Option>>, - client: Option>, - listen_addresses: Vec, - set_config: Option, - chain_sync_network: Option<(NetworkServiceProvider, NetworkServiceHandle)>, - config: Option, -} - -impl TestNetworkBuilder { - pub fn new() -> Self { - Self { - import_queue: None, - link: None, - client: None, - listen_addresses: Vec::new(), - set_config: None, - chain_sync_network: None, - config: None, - } - } - - 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 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, String> { - block.finalized = self.0; - block.fork_choice = Some(sc_consensus::ForkChoiceStrategy::LongestChain); - Ok(block) - } - } - - 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")); - - let block_request_protocol_config = { - let (handler, protocol_config) = - BlockRequestHandler::new(&protocol_id, None, client.clone(), 50); - tokio::spawn(handler.run().boxed()); - protocol_config - }; - - let state_request_protocol_config = { - let (handler, protocol_config) = - StateRequestHandler::new(&protocol_id, None, client.clone(), 50); - tokio::spawn(handler.run().boxed()); - protocol_config - }; - - let light_client_request_protocol_config = { - let (handler, protocol_config) = - LightClientRequestHandler::new(&protocol_id, None, client.clone()); - tokio::spawn(handler.run().boxed()); - protocol_config - }; - - let (chain_sync_network_provider, chain_sync_network_handle) = - self.chain_sync_network.unwrap_or(NetworkServiceProvider::new()); - - let (engine, chain_sync_service, block_announce_config) = SyncingEngine::new( - Roles::from(&config::Role::Full), - client.clone(), - None, - &network_config, - protocol_id.clone(), - &None, - Box::new(sp_consensus::block_validation::DefaultBlockAnnounceValidator), - None, - chain_sync_network_handle, - import_queue.service(), - block_request_protocol_config.name.clone(), - state_request_protocol_config.name.clone(), - None, - ) - .unwrap(); - let mut link = self.link.unwrap_or(Box::new(chain_sync_service.clone())); - let worker = NetworkWorker::< - substrate_test_runtime_client::runtime::Block, - substrate_test_runtime_client::runtime::Hash, - >::new(config::Params { - block_announce_config, - role: config::Role::Full, - executor: Box::new(|f| { - tokio::spawn(f); - }), - network_config, - chain: client.clone(), - protocol_id, - fork_id, - metrics_registry: None, - request_response_protocol_configs: [ - block_request_protocol_config, - state_request_protocol_config, - light_client_request_protocol_config, - ] - .to_vec(), - }) - .unwrap(); - - let service = worker.service().clone(); - tokio::spawn(async move { - let _ = chain_sync_network_provider.run(service).await; - }); - tokio::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; - } - }); - let stream = worker.service().event_stream("syncing"); - tokio::spawn(engine.run(stream)); - - TestNetwork::new(worker) - } -} diff --git a/client/network/common/src/service.rs b/client/network/src/service/traits.rs similarity index 99% rename from client/network/common/src/service.rs rename to client/network/src/service/traits.rs index d3c5c2f439450..3f9b7e552027b 100644 --- a/client/network/common/src/service.rs +++ b/client/network/src/service/traits.rs @@ -20,17 +20,20 @@ use crate::{ config::MultiaddrWithPeerId, - protocol::{event::Event, ProtocolName}, + event::Event, request_responses::{IfDisconnected, RequestFailure}, + service::signature::Signature, + types::ProtocolName, }; + 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 std::{collections::HashSet, future::Future, pin::Pin, sync::Arc}; -mod signature; +pub use libp2p::{identity::error::SigningError, kad::record::Key as KademliaKey}; /// Signer with network identity pub trait NetworkSigner { diff --git a/client/network/common/src/protocol.rs b/client/network/src/types.rs similarity index 99% rename from client/network/common/src/protocol.rs rename to client/network/src/types.rs index bfeb1daf5d53b..b0e32ae109149 100644 --- a/client/network/common/src/protocol.rs +++ b/client/network/src/types.rs @@ -16,6 +16,10 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +//! `sc-network` type definitions + +use libp2p::core::upgrade; + use std::{ borrow::Borrow, fmt, @@ -24,11 +28,6 @@ use std::{ sync::Arc, }; -use libp2p::core::upgrade; - -pub mod event; -pub mod role; - /// The protocol name transmitted on the wire. #[derive(Debug, Clone)] pub enum ProtocolName { diff --git a/client/network/common/src/utils.rs b/client/network/src/utils.rs similarity index 98% rename from client/network/common/src/utils.rs rename to client/network/src/utils.rs index c32d264a943e7..8db2cf4e7920d 100644 --- a/client/network/common/src/utils.rs +++ b/client/network/src/utils.rs @@ -16,9 +16,12 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +//! `sc-network` utilities + use futures::{stream::unfold, FutureExt, Stream, StreamExt}; use futures_timer::Delay; use linked_hash_set::LinkedHashSet; + use std::{hash::Hash, num::NonZeroUsize, time::Duration}; /// Creates a stream that returns a new value every `duration`. diff --git a/client/network/sync/Cargo.toml b/client/network/sync/Cargo.toml index 52ab0d15e1670..298cbf1801f2e 100644 --- a/client/network/sync/Cargo.toml +++ b/client/network/sync/Cargo.toml @@ -32,6 +32,7 @@ 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 = { version = "0.10.0-dev", path = "../" } 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" } diff --git a/client/network/sync/src/block_request_handler.rs b/client/network/sync/src/block_request_handler.rs index 38aca2cde3fd2..921efd7def622 100644 --- a/client/network/sync/src/block_request_handler.rs +++ b/client/network/sync/src/block_request_handler.rs @@ -18,6 +18,7 @@ //! `crate::request_responses::RequestResponsesBehaviour`. use crate::schema::v1::{block_request::FromBlock, BlockResponse, Direction}; + use codec::{Decode, Encode}; use futures::{ channel::{mpsc, oneshot}, @@ -27,17 +28,19 @@ use libp2p::PeerId; use log::debug; use lru::LruCache; use prost::Message; + use sc_client_api::BlockBackend; -use sc_network_common::{ +use sc_network::{ config::ProtocolId, request_responses::{IncomingRequest, OutgoingResponse, ProtocolConfig}, - sync::message::BlockAttributes, }; +use sc_network_common::sync::message::BlockAttributes; use sp_blockchain::HeaderBackend; use sp_runtime::{ generic::BlockId, traits::{Block as BlockT, Header, One, Zero}, }; + use std::{ cmp::min, hash::{Hash, Hasher}, diff --git a/client/network/sync/src/engine.rs b/client/network/sync/src/engine.rs index 25cd3968c2924..e6e62101ffcd0 100644 --- a/client/network/sync/src/engine.rs +++ b/client/network/sync/src/engine.rs @@ -24,22 +24,27 @@ use crate::{ ChainSync, ClientError, SyncingService, }; +use codec::{Decode, DecodeAll, Encode}; use futures::{FutureExt, Stream, StreamExt}; +use futures_timer::Delay; use libp2p::PeerId; use lru::LruCache; use prometheus_endpoint::{ register, Gauge, GaugeVec, MetricSource, Opts, PrometheusError, Registry, SourcedGauge, U64, }; -use codec::{Decode, DecodeAll, Encode}; -use futures_timer::Delay; use sc_client_api::{BlockBackend, HeaderBackend, ProofProvider}; use sc_consensus::import_queue::ImportQueueService; -use sc_network_common::{ +use sc_network::{ config::{ NetworkConfiguration, NonDefaultSetConfig, ProtocolId, SyncMode as SyncOperationMode, }, - protocol::{event::Event, role::Roles, ProtocolName}, + event::Event, + utils::LruHashSet, + ProtocolName, +}; +use sc_network_common::{ + role::Roles, sync::{ message::{ generic::{BlockData, BlockResponse}, @@ -49,7 +54,6 @@ use sc_network_common::{ BadPeer, ChainSync as ChainSyncT, ExtendedPeerInfo, PollBlockAnnounceValidation, SyncEvent, SyncMode, }, - utils::LruHashSet, }; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; use sp_blockchain::HeaderMetadata; diff --git a/client/network/sync/src/lib.rs b/client/network/sync/src/lib.rs index 23269b02bd128..45d14ffa7bb37 100644 --- a/client/network/sync/src/lib.rs +++ b/client/network/sync/src/lib.rs @@ -28,23 +28,13 @@ //! 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 engine; -pub mod mock; -mod schema; -pub mod service; -pub mod state; -pub mod state_request_handler; -pub mod warp; -pub mod warp_request_handler; - use crate::{ blocks::BlockCollection, schema::v1::{StateRequest, StateResponse}, state::StateSync, warp::{WarpProofImportResult, WarpSync}, }; + use codec::{Decode, DecodeAll, Encode}; use extra_requests::ExtraRequests; use futures::{ @@ -52,18 +42,22 @@ 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 prometheus_endpoint::{register, Counter, PrometheusError, Registry, U64}; use sc_client_api::{BlockBackend, ProofProvider}; use sc_consensus::{ import_queue::ImportQueueService, BlockImportError, BlockImportStatus, IncomingBlock, }; -use sc_network_common::{ +use sc_network::{ config::{ NonDefaultSetConfig, NonReservedPeerMode, NotificationHandshake, ProtocolId, SetConfig, }, - protocol::{role::Roles, ProtocolName}, request_responses::{IfDisconnected, RequestFailure}, + types::ProtocolName, +}; +use sc_network_common::{ + role::Roles, sync::{ message::{ BlockAnnounce, BlockAnnouncesHandshake, BlockAttributes, BlockData, BlockRequest, @@ -76,7 +70,6 @@ use sc_network_common::{ SyncState, SyncStatus, }, }; -pub use service::chain_sync::SyncingService; use sp_arithmetic::traits::Saturating; use sp_blockchain::{Error as ClientError, HeaderBackend, HeaderMetadata}; use sp_consensus::{ @@ -90,6 +83,7 @@ use sp_runtime::{ }, EncodedJustification, Justifications, }; + use std::{ collections::{hash_map::Entry, HashMap, HashSet}, iter, @@ -97,9 +91,21 @@ use std::{ pin::Pin, sync::Arc, }; -use warp::TargetBlockImportResult; + +pub use service::chain_sync::SyncingService; mod extra_requests; +mod schema; + +pub mod block_request_handler; +pub mod blocks; +pub mod engine; +pub mod mock; +pub mod service; +pub mod state; +pub mod state_request_handler; +pub mod warp; +pub mod warp_request_handler; /// Maximum blocks to request in a single packet. const MAX_BLOCKS_TO_REQUEST: usize = 64; @@ -927,9 +933,9 @@ where match warp_sync.import_target_block( blocks.pop().expect("`blocks` len checked above."), ) { - TargetBlockImportResult::Success => + warp::TargetBlockImportResult::Success => return Ok(OnBlockData::Continue), - TargetBlockImportResult::BadResponse => + warp::TargetBlockImportResult::BadResponse => return Err(BadPeer(*who, rep::VERIFICATION_FAIL)), } } else if blocks.is_empty() { @@ -3160,7 +3166,7 @@ mod test { use futures::{executor::block_on, future::poll_fn}; use sc_block_builder::BlockBuilderProvider; use sc_network_common::{ - protocol::role::Role, + role::Role, sync::message::{BlockData, BlockState, FromBlock}, }; use sp_blockchain::HeaderBackend; diff --git a/client/network/sync/src/service/chain_sync.rs b/client/network/sync/src/service/chain_sync.rs index 99b4197740eda..f9e0e401fdf8f 100644 --- a/client/network/sync/src/service/chain_sync.rs +++ b/client/network/sync/src/service/chain_sync.rs @@ -20,9 +20,9 @@ use futures::{channel::oneshot, Stream}; use libp2p::PeerId; use sc_consensus::{BlockImportError, BlockImportStatus, JustificationSyncLink, Link}; -use sc_network_common::{ - service::{NetworkBlock, NetworkSyncForkRequest}, - sync::{ExtendedPeerInfo, SyncEvent, SyncEventStream, SyncStatus, SyncStatusProvider}, +use sc_network::{NetworkBlock, NetworkSyncForkRequest}; +use sc_network_common::sync::{ + ExtendedPeerInfo, SyncEvent, SyncEventStream, SyncStatus, SyncStatusProvider, }; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedSender}; use sp_runtime::traits::{Block as BlockT, NumberFor}; diff --git a/client/network/sync/src/service/mock.rs b/client/network/sync/src/service/mock.rs index 2853616adfb4d..c882633993c8b 100644 --- a/client/network/sync/src/service/mock.rs +++ b/client/network/sync/src/service/mock.rs @@ -18,18 +18,18 @@ use futures::channel::oneshot; use libp2p::{Multiaddr, PeerId}; + use sc_consensus::{BlockImportError, BlockImportStatus}; -use sc_network_common::{ +use sc_network::{ config::MultiaddrWithPeerId, - protocol::ProtocolName, request_responses::{IfDisconnected, RequestFailure}, - service::{ - NetworkNotification, NetworkPeers, NetworkRequest, NetworkSyncForkRequest, - NotificationSender, NotificationSenderError, - }, + types::ProtocolName, + NetworkNotification, NetworkPeers, NetworkRequest, NetworkSyncForkRequest, + NotificationSenderError, NotificationSenderT, }; use sc_peerset::ReputationChange; use sp_runtime::traits::{Block as BlockT, NumberFor}; + use std::collections::HashSet; mockall::mock! { @@ -135,7 +135,7 @@ mockall::mock! { &self, target: PeerId, protocol: ProtocolName, - ) -> Result, NotificationSenderError>; + ) -> Result, NotificationSenderError>; fn set_notification_handshake(&self, protocol: ProtocolName, handshake: Vec); } } diff --git a/client/network/sync/src/service/network.rs b/client/network/sync/src/service/network.rs index a1f4f27bbbd99..f87de1c4c3ecc 100644 --- a/client/network/sync/src/service/network.rs +++ b/client/network/sync/src/service/network.rs @@ -18,13 +18,15 @@ use futures::{channel::oneshot, StreamExt}; use libp2p::PeerId; -use sc_network_common::{ - protocol::ProtocolName, + +use sc_network::{ request_responses::{IfDisconnected, RequestFailure}, - service::{NetworkNotification, NetworkPeers, NetworkRequest}, + types::ProtocolName, + NetworkNotification, 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` diff --git a/client/network/sync/src/state_request_handler.rs b/client/network/sync/src/state_request_handler.rs index 2f615f4ead753..0ce2c541bf92e 100644 --- a/client/network/sync/src/state_request_handler.rs +++ b/client/network/sync/src/state_request_handler.rs @@ -18,6 +18,7 @@ //! `crate::request_responses::RequestResponsesBehaviour`. use crate::schema::v1::{KeyValueStateEntry, StateEntry, StateRequest, StateResponse}; + use codec::{Decode, Encode}; use futures::{ channel::{mpsc, oneshot}, @@ -27,12 +28,14 @@ use libp2p::PeerId; use log::{debug, trace}; use lru::LruCache; use prost::Message; + use sc_client_api::{BlockBackend, ProofProvider}; -use sc_network_common::{ +use sc_network::{ config::ProtocolId, request_responses::{IncomingRequest, OutgoingResponse, ProtocolConfig}, }; use sp_runtime::traits::Block as BlockT; + use std::{ hash::{Hash, Hasher}, num::NonZeroUsize, diff --git a/client/network/sync/src/warp_request_handler.rs b/client/network/sync/src/warp_request_handler.rs index fcb0d116bcdac..7061d6485d092 100644 --- a/client/network/sync/src/warp_request_handler.rs +++ b/client/network/sync/src/warp_request_handler.rs @@ -22,14 +22,16 @@ use futures::{ stream::StreamExt, }; use log::debug; -use sc_network_common::{ + +use sc_network::{ config::ProtocolId, request_responses::{ IncomingRequest, OutgoingResponse, ProtocolConfig as RequestResponseConfig, }, - sync::warp::{EncodedProof, WarpProofRequest, WarpSyncProvider}, }; +use sc_network_common::sync::warp::{EncodedProof, WarpProofRequest, WarpSyncProvider}; use sp_runtime::traits::Block as BlockT; + use std::{sync::Arc, time::Duration}; const MAX_RESPONSE_SIZE: u64 = 16 * 1024 * 1024; diff --git a/client/network/test/src/lib.rs b/client/network/test/src/lib.rs index a79e17e2fb6d1..75b8287b08dcf 100644 --- a/client/network/test/src/lib.rs +++ b/client/network/test/src/lib.rs @@ -20,6 +20,8 @@ #[cfg(test)] mod block_import; #[cfg(test)] +mod service; +#[cfg(test)] mod sync; use std::{ @@ -46,14 +48,18 @@ use sc_consensus::{ ForkChoiceStrategy, ImportQueue, ImportResult, JustificationImport, JustificationSyncLink, LongestChain, Verifier, }; -use sc_network::{Multiaddr, NetworkService, NetworkWorker}; -use sc_network_common::{ +use sc_network::{ config::{ MultiaddrWithPeerId, NetworkConfiguration, NonDefaultSetConfig, NonReservedPeerMode, - ProtocolId, RequestResponseConfig, Role, SyncMode, TransportConfig, + ProtocolId, Role, SyncMode, TransportConfig, }, - protocol::{role::Roles, ProtocolName}, - service::{NetworkBlock, NetworkEventStream, NetworkStateInfo, NetworkSyncForkRequest}, + request_responses::ProtocolConfig as RequestResponseConfig, + types::ProtocolName, + Multiaddr, NetworkBlock, NetworkEventStream, NetworkService, NetworkStateInfo, + NetworkSyncForkRequest, NetworkWorker, +}; +use sc_network_common::{ + role::Roles, sync::warp::{ AuthorityList, EncodedProof, SetId, VerificationResult, WarpSyncParams, WarpSyncProvider, }, diff --git a/client/network/src/service/tests/service.rs b/client/network/test/src/service.rs similarity index 72% rename from client/network/src/service/tests/service.rs rename to client/network/test/src/service.rs index 9c4c0ad6e0cd9..b1de2a91ebcc9 100644 --- a/client/network/src/service/tests/service.rs +++ b/client/network/test/src/service.rs @@ -16,24 +16,228 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use crate::{config, service::tests::TestNetworkBuilder, NetworkService}; - use futures::prelude::*; -use libp2p::PeerId; -use sc_network_common::{ - config::{MultiaddrWithPeerId, NonDefaultSetConfig, SetConfig, TransportConfig}, - protocol::event::Event, - service::{NetworkNotification, NetworkPeers, NetworkStateInfo}, +use libp2p::{Multiaddr, PeerId}; + +use sc_consensus::{ImportQueue, Link}; +use sc_network::{ + config::{self, MultiaddrWithPeerId, ProtocolId, TransportConfig}, + event::Event, + NetworkEventStream, NetworkNotification, NetworkPeers, NetworkService, NetworkStateInfo, + NetworkWorker, +}; +use sc_network_common::role::Roles; +use sc_network_light::light_client_requests::handler::LightClientRequestHandler; +use sc_network_sync::{ + block_request_handler::BlockRequestHandler, + engine::SyncingEngine, + service::network::{NetworkServiceHandle, NetworkServiceProvider}, + state_request_handler::StateRequestHandler, }; +use sp_runtime::traits::Block as BlockT; +use substrate_test_runtime_client::{ + runtime::{Block as TestBlock, Hash as TestHash}, + TestClientBuilder, TestClientBuilderExt as _, +}; + use std::{sync::Arc, time::Duration}; -type TestNetworkService = NetworkService< - substrate_test_runtime_client::runtime::Block, - substrate_test_runtime_client::runtime::Hash, ->; +type TestNetworkWorker = NetworkWorker; +type TestNetworkService = NetworkService; const PROTOCOL_NAME: &str = "/foo"; +struct TestNetwork { + network: TestNetworkWorker, +} + +impl TestNetwork { + pub fn new(network: TestNetworkWorker) -> Self { + 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"); + + tokio::spawn(worker.run()); + + (service, event_stream) + } +} + +struct TestNetworkBuilder { + import_queue: Option>>, + link: Option>>, + client: Option>, + listen_addresses: Vec, + set_config: Option, + chain_sync_network: Option<(NetworkServiceProvider, NetworkServiceHandle)>, + config: Option, +} + +impl TestNetworkBuilder { + pub fn new() -> Self { + Self { + import_queue: None, + link: None, + client: None, + listen_addresses: Vec::new(), + set_config: None, + chain_sync_network: None, + config: None, + } + } + + 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: config::SetConfig) -> Self { + self.set_config = Some(set_config); + 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![config::NonDefaultSetConfig { + notifications_protocol: PROTOCOL_NAME.into(), + fallback_names: Vec::new(), + max_notification_size: 1024 * 1024, + handshake: None, + set_config: self.set_config.unwrap_or_default(), + }], + 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, String> { + block.finalized = self.0; + block.fork_choice = Some(sc_consensus::ForkChoiceStrategy::LongestChain); + Ok(block) + } + } + + 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")); + + let block_request_protocol_config = { + let (handler, protocol_config) = + BlockRequestHandler::new(&protocol_id, None, client.clone(), 50); + tokio::spawn(handler.run().boxed()); + protocol_config + }; + + let state_request_protocol_config = { + let (handler, protocol_config) = + StateRequestHandler::new(&protocol_id, None, client.clone(), 50); + tokio::spawn(handler.run().boxed()); + protocol_config + }; + + let light_client_request_protocol_config = { + let (handler, protocol_config) = + LightClientRequestHandler::new(&protocol_id, None, client.clone()); + tokio::spawn(handler.run().boxed()); + protocol_config + }; + + let (chain_sync_network_provider, chain_sync_network_handle) = + self.chain_sync_network.unwrap_or(NetworkServiceProvider::new()); + + let (engine, chain_sync_service, block_announce_config) = SyncingEngine::new( + Roles::from(&config::Role::Full), + client.clone(), + None, + &network_config, + protocol_id.clone(), + &None, + Box::new(sp_consensus::block_validation::DefaultBlockAnnounceValidator), + None, + chain_sync_network_handle, + import_queue.service(), + block_request_protocol_config.name.clone(), + state_request_protocol_config.name.clone(), + None, + ) + .unwrap(); + let mut link = self.link.unwrap_or(Box::new(chain_sync_service.clone())); + let worker = NetworkWorker::< + substrate_test_runtime_client::runtime::Block, + substrate_test_runtime_client::runtime::Hash, + >::new(config::Params { + block_announce_config, + role: config::Role::Full, + executor: Box::new(|f| { + tokio::spawn(f); + }), + network_config, + chain: client.clone(), + protocol_id, + fork_id, + metrics_registry: None, + request_response_protocol_configs: [ + block_request_protocol_config, + state_request_protocol_config, + light_client_request_protocol_config, + ] + .to_vec(), + }) + .unwrap(); + + let service = worker.service().clone(); + tokio::spawn(async move { + let _ = chain_sync_network_provider.run(service).await; + }); + tokio::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; + } + }); + let stream = worker.service().event_stream("syncing"); + tokio::spawn(engine.run(stream)); + + TestNetwork::new(worker) + } +} + /// 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() -> ( @@ -50,7 +254,7 @@ fn build_nodes_one_proto() -> ( .start_network(); let (node2, events_stream2) = TestNetworkBuilder::new() - .with_set_config(SetConfig { + .with_set_config(config::SetConfig { reserved_nodes: vec![MultiaddrWithPeerId { multiaddr: listen_addr, peer_id: node1.local_peer_id(), @@ -208,7 +412,7 @@ async fn lots_of_incoming_peers_works() { let (main_node, _) = TestNetworkBuilder::new() .with_listen_addresses(vec![listen_addr.clone()]) - .with_set_config(SetConfig { in_peers: u32::MAX, ..Default::default() }) + .with_set_config(config::SetConfig { in_peers: u32::MAX, ..Default::default() }) .build() .start_network(); @@ -220,7 +424,7 @@ async fn lots_of_incoming_peers_works() { for _ in 0..32 { let (_dialing_node, event_stream) = TestNetworkBuilder::new() - .with_set_config(SetConfig { + .with_set_config(config::SetConfig { reserved_nodes: vec![MultiaddrWithPeerId { multiaddr: listen_addr.clone(), peer_id: main_node_peer_id, @@ -289,10 +493,11 @@ async fn notifications_back_pressure() { while received_notifications < TOTAL_NOTIFS { match events_stream2.next().await.unwrap() { - Event::NotificationStreamOpened { protocol, .. } => + Event::NotificationStreamOpened { protocol, .. } => { if let None = sync_protocol_name { sync_protocol_name = Some(protocol); - }, + } + }, Event::NotificationStreamClosed { protocol, .. } => { if Some(&protocol) != sync_protocol_name.as_ref() { panic!() @@ -344,7 +549,7 @@ async fn fallback_name_working() { let listen_addr = config::build_multiaddr![Memory(rand::random::())]; let (node1, mut events_stream1) = TestNetworkBuilder::new() .with_config(config::NetworkConfiguration { - extra_sets: vec![NonDefaultSetConfig { + extra_sets: vec![config::NonDefaultSetConfig { notifications_protocol: NEW_PROTOCOL_NAME.into(), fallback_names: vec![PROTOCOL_NAME.into()], max_notification_size: 1024 * 1024, @@ -359,7 +564,7 @@ async fn fallback_name_working() { .start_network(); let (_, mut events_stream2) = TestNetworkBuilder::new() - .with_set_config(SetConfig { + .with_set_config(config::SetConfig { reserved_nodes: vec![MultiaddrWithPeerId { multiaddr: listen_addr, peer_id: node1.local_peer_id(), @@ -500,7 +705,7 @@ async fn ensure_reserved_node_addresses_consistent_with_transport_memory() { .with_config(config::NetworkConfiguration { listen_addresses: vec![listen_addr.clone()], transport: TransportConfig::MemoryOnly, - default_peers_set: SetConfig { + default_peers_set: config::SetConfig { reserved_nodes: vec![reserved_node], ..Default::default() }, @@ -527,7 +732,7 @@ async fn ensure_reserved_node_addresses_consistent_with_transport_not_memory() { let _ = TestNetworkBuilder::new() .with_config(config::NetworkConfiguration { listen_addresses: vec![listen_addr.clone()], - default_peers_set: SetConfig { + default_peers_set: config::SetConfig { reserved_nodes: vec![reserved_node], ..Default::default() }, diff --git a/client/network/transactions/Cargo.toml b/client/network/transactions/Cargo.toml index cab702fbd7a6c..3616473d3baed 100644 --- a/client/network/transactions/Cargo.toml +++ b/client/network/transactions/Cargo.toml @@ -20,6 +20,7 @@ libp2p = "0.50.0" log = "0.4.17" pin-project = "1.0.12" prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../../utils/prometheus" } +sc-network = { version = "0.10.0-dev", path = "../" } 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" } diff --git a/client/network/transactions/src/lib.rs b/client/network/transactions/src/lib.rs index 48bb394946671..381dd654b600b 100644 --- a/client/network/transactions/src/lib.rs +++ b/client/network/transactions/src/lib.rs @@ -27,22 +27,29 @@ //! `Future` that processes transactions. use crate::config::*; + use codec::{Decode, Encode}; use futures::{prelude::*, stream::FuturesUnordered}; use libp2p::{multiaddr, PeerId}; use log::{debug, trace, warn}; + use prometheus_endpoint::{register, Counter, PrometheusError, Registry, U64}; -use sc_network_common::{ +use sc_network::{ config::{NonDefaultSetConfig, NonReservedPeerMode, ProtocolId, SetConfig}, error, - protocol::{event::Event, role::ObservedRole, ProtocolName}, - service::{NetworkEventStream, NetworkNotification, NetworkPeers}, - sync::{SyncEvent, SyncEventStream}, + event::Event, + types::ProtocolName, utils::{interval, LruHashSet}, + NetworkEventStream, NetworkNotification, NetworkPeers, +}; +use sc_network_common::{ + role::ObservedRole, + sync::{SyncEvent, SyncEventStream}, ExHashT, }; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; use sp_runtime::traits::Block as BlockT; + use std::{ collections::{hash_map::Entry, HashMap}, iter, diff --git a/client/offchain/Cargo.toml b/client/offchain/Cargo.toml index dd6e2e44caf55..0307e3125f3ee 100644 --- a/client/offchain/Cargo.toml +++ b/client/offchain/Cargo.toml @@ -29,6 +29,7 @@ rand = "0.8.5" 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" } diff --git a/client/offchain/src/api.rs b/client/offchain/src/api.rs index 6fdd91cda2390..a15f03bab6f84 100644 --- a/client/offchain/src/api.rs +++ b/client/offchain/src/api.rs @@ -326,10 +326,8 @@ mod tests { use super::*; use libp2p::PeerId; use sc_client_db::offchain::LocalStorage; - use sc_network_common::{ - config::MultiaddrWithPeerId, - protocol::ProtocolName, - service::{NetworkPeers, NetworkStateInfo}, + use sc_network::{ + config::MultiaddrWithPeerId, types::ProtocolName, NetworkPeers, NetworkStateInfo, }; use sc_peerset::ReputationChange; use sp_core::offchain::{DbExternalities, Externalities}; diff --git a/client/offchain/src/lib.rs b/client/offchain/src/lib.rs index c69f01de19bf6..677d89267e3a6 100644 --- a/client/offchain/src/lib.rs +++ b/client/offchain/src/lib.rs @@ -42,7 +42,7 @@ use futures::{ prelude::*, }; use parking_lot::Mutex; -use sc_network_common::service::{NetworkPeers, NetworkStateInfo}; +use sc_network::{NetworkPeers, NetworkStateInfo}; use sp_api::{ApiExt, ProvideRuntimeApi}; use sp_core::{offchain, traits::SpawnNamed, ExecutionContext}; use sp_runtime::traits::{self, Header}; @@ -246,7 +246,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, protocol::ProtocolName}; + use sc_network::{config::MultiaddrWithPeerId, types::ProtocolName}; use sc_peerset::ReputationChange; use sc_transaction_pool::{BasicPool, FullChainApi}; use sc_transaction_pool_api::{InPoolTransaction, TransactionPool}; diff --git a/client/rpc/src/system/tests.rs b/client/rpc/src/system/tests.rs index c0ee1e8f88005..b6bfec7736b08 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_common::config::parse_str_addr(&peer) { + let _ = match sc_network::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/builder.rs b/client/service/src/builder.rs index ea4b630003123..91ef65cf134e4 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -38,14 +38,11 @@ use sc_client_db::{Backend, DatabaseSettings}; use sc_consensus::import_queue::ImportQueue; use sc_executor::RuntimeVersionOf; use sc_keystore::LocalKeystore; -use sc_network::NetworkService; -use sc_network_bitswap::BitswapRequestHandler; -use sc_network_common::{ - config::SyncMode, - protocol::role::Roles, - service::{NetworkEventStream, NetworkStateInfo, NetworkStatusProvider}, - sync::warp::WarpSyncParams, +use sc_network::{ + config::SyncMode, NetworkEventStream, NetworkService, NetworkStateInfo, NetworkStatusProvider, }; +use sc_network_bitswap::BitswapRequestHandler; +use sc_network_common::{role::Roles, sync::warp::WarpSyncParams}; use sc_network_light::light_client_requests::handler::LightClientRequestHandler; use sc_network_sync::{ block_request_handler::BlockRequestHandler, engine::SyncingEngine, diff --git a/client/service/src/config.rs b/client/service/src/config.rs index 8e843b58f285e..c7d98a4533436 100644 --- a/client/service/src/config.rs +++ b/client/service/src/config.rs @@ -22,22 +22,18 @@ pub use sc_client_api::execution_extensions::{ExecutionStrategies, ExecutionStra pub use sc_client_db::{BlocksPruning, Database, DatabaseSource, PruningMode}; pub use sc_executor::{WasmExecutionMethod, WasmtimeInstantiationStrategy}; pub use sc_network::{ - config::{NetworkConfiguration, Role}, - Multiaddr, -}; -pub use sc_network_common::{ config::{ - MultiaddrWithPeerId, NodeKeyConfig, NonDefaultSetConfig, ProtocolId, SetConfig, - TransportConfig, + MultiaddrWithPeerId, NetworkConfiguration, NodeKeyConfig, NonDefaultSetConfig, ProtocolId, + Role, SetConfig, SyncMode, TransportConfig, }, request_responses::{ IncomingRequest, OutgoingResponse, ProtocolConfig as RequestResponseConfig, }, + Multiaddr, }; use prometheus_endpoint::Registry; use sc_chain_spec::ChainSpec; -use sc_network_common::config::SyncMode; pub use sc_telemetry::TelemetryEndpoints; pub use sc_transaction_pool::Options as TransactionPoolOptions; use sp_core::crypto::SecretString; diff --git a/client/service/src/error.rs b/client/service/src/error.rs index 6b71e46b4e0ef..c871342c771eb 100644 --- a/client/service/src/error.rs +++ b/client/service/src/error.rs @@ -40,7 +40,7 @@ pub enum Error { Consensus(#[from] sp_consensus::Error), #[error(transparent)] - Network(#[from] sc_network_common::error::Error), + Network(#[from] sc_network::error::Error), #[error(transparent)] Keystore(#[from] sc_keystore::Error), diff --git a/client/service/src/lib.rs b/client/service/src/lib.rs index 9dab81a5b4ed9..54f11ec25a02a 100644 --- a/client/service/src/lib.rs +++ b/client/service/src/lib.rs @@ -41,10 +41,8 @@ use futures::{channel::mpsc, pin_mut, FutureExt, StreamExt}; use jsonrpsee::{core::Error as JsonRpseeError, RpcModule}; use log::{debug, error, warn}; use sc_client_api::{blockchain::HeaderBackend, BlockBackend, BlockchainEvents, ProofProvider}; -use sc_network::{NetworkStateInfo, PeerId}; -use sc_network_common::{ - config::MultiaddrWithPeerId, - service::{NetworkBlock, NetworkPeers}, +use sc_network::{ + config::MultiaddrWithPeerId, NetworkBlock, NetworkPeers, NetworkStateInfo, PeerId, }; use sc_network_sync::SyncingService; use sc_utils::mpsc::TracingUnboundedReceiver; diff --git a/client/service/src/metrics.rs b/client/service/src/metrics.rs index 967e3133dbea9..ece5758be7718 100644 --- a/client/service/src/metrics.rs +++ b/client/service/src/metrics.rs @@ -22,11 +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; -use sc_network_common::{ - service::{NetworkStatus, NetworkStatusProvider}, - sync::{SyncStatus, SyncStatusProvider}, -}; +use sc_network::{config::Role, NetworkStatus, NetworkStatusProvider}; +use sc_network_common::sync::{SyncStatus, SyncStatusProvider}; use sc_telemetry::{telemetry, TelemetryHandle, SUBSTRATE_INFO}; use sc_transaction_pool_api::{MaintainedTransactionPool, PoolStatus}; use sc_utils::metrics::register_globals; diff --git a/client/service/test/src/lib.rs b/client/service/test/src/lib.rs index b1a09a0620fcd..f80446a4d43eb 100644 --- a/client/service/test/src/lib.rs +++ b/client/service/test/src/lib.rs @@ -22,10 +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, multiaddr}; -use sc_network_common::{ - config::{MultiaddrWithPeerId, TransportConfig}, - service::{NetworkBlock, NetworkPeers, NetworkStateInfo}, +use sc_network::{ + config::{MultiaddrWithPeerId, NetworkConfiguration, TransportConfig}, + multiaddr, NetworkBlock, NetworkPeers, NetworkStateInfo, }; use sc_network_sync::SyncingService; use sc_service::{ From 39510ecaa82f07f8671ec4d6d05ef572974ec9fe Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Tue, 14 Mar 2023 16:52:53 +0200 Subject: [PATCH 505/715] sc-consensus-beefy: fix on-demand async state machine (#13599) `futures_util::pending!()` macro only yields to the event loop once, resulting in many calls to the `OnDemandJustificationsEngine::next()` made by the tokio reactor even though the on-demand-engine is idle. Replace it with the correct `futures::future::pending::<()>()` function which forever yields to the event loop, which is what we want when the engine is idle. Signed-off-by: Adrian Catangiu --- .../outgoing_requests_engine.rs | 2 +- client/consensus/beefy/src/tests.rs | 23 ++++++++++++------- client/consensus/beefy/src/worker.rs | 10 ++++---- 3 files changed, 21 insertions(+), 14 deletions(-) diff --git a/client/consensus/beefy/src/communication/request_response/outgoing_requests_engine.rs b/client/consensus/beefy/src/communication/request_response/outgoing_requests_engine.rs index c642e3dfe581c..fbf464bd639d9 100644 --- a/client/consensus/beefy/src/communication/request_response/outgoing_requests_engine.rs +++ b/client/consensus/beefy/src/communication/request_response/outgoing_requests_engine.rs @@ -207,7 +207,7 @@ impl OnDemandJustificationsEngine { pub async fn next(&mut self) -> Option> { let (peer, req_info, resp) = match &mut self.state { State::Idle => { - futures::pending!(); + futures::future::pending::<()>().await; return None }, State::AwaitingResponse(peer, req_info, receiver) => { diff --git a/client/consensus/beefy/src/tests.rs b/client/consensus/beefy/src/tests.rs index 44920aaa6faa9..27dc8d81915aa 100644 --- a/client/consensus/beefy/src/tests.rs +++ b/client/consensus/beefy/src/tests.rs @@ -934,7 +934,7 @@ async fn on_demand_beefy_justification_sync() { let dave_index = 3; // push 30 blocks - let hashes = net.generate_blocks_and_sync(35, session_len, &validator_set, false).await; + let mut hashes = net.generate_blocks_and_sync(30, session_len, &validator_set, false).await; let fast_peers = fast_peers.into_iter().enumerate(); let net = Arc::new(Mutex::new(net)); @@ -951,8 +951,16 @@ async fn on_demand_beefy_justification_sync() { // Spawn Dave, they are now way behind voting and can only catch up through on-demand justif // sync. tokio::spawn(dave_task); - // give Dave a chance to spawn and init. - run_for(Duration::from_millis(400), &net).await; + // Dave pushes and syncs 4 more blocks just to make sure he gets included in gossip. + { + let mut net_guard = net.lock(); + let built_hashes = + net_guard + .peer(dave_index) + .generate_blocks(4, BlockOrigin::File, |builder| builder.build().unwrap().block); + hashes.extend(built_hashes); + net_guard.run_until_sync().await; + } let (dave_best_blocks, _) = get_beefy_streams(&mut net.lock(), [(dave_index, BeefyKeyring::Dave)].into_iter()); @@ -965,7 +973,10 @@ async fn on_demand_beefy_justification_sync() { // Have the other peers do some gossip so Dave finds out about their progress. finalize_block_and_wait_for_beefy(&net, fast_peers, &[hashes[25], hashes[29]], &[25, 29]).await; - // Now verify Dave successfully finalized #1 (through on-demand justification request). + // Kick Dave's async loop by finalizing another block. + client.finalize_block(hashes[2], None).unwrap(); + + // And verify Dave successfully finalized #1 (through on-demand justification request). wait_for_best_beefy_blocks(dave_best_blocks, &net, &[1]).await; // Give all tasks some cpu cycles to burn through their events queues, @@ -978,10 +989,6 @@ async fn on_demand_beefy_justification_sync() { &[5, 10, 15, 20, 25], ) .await; - - 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, &[hashes[30], hashes[34]], &[30]).await; } #[tokio::test] diff --git a/client/consensus/beefy/src/worker.rs b/client/consensus/beefy/src/worker.rs index 3f29dc7abee5c..0abb38d022ef6 100644 --- a/client/consensus/beefy/src/worker.rs +++ b/client/consensus/beefy/src/worker.rs @@ -887,11 +887,6 @@ where // 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: LOG_TARGET, "🥩 Gossip engine has terminated, closing worker."); - return; - }, // Process finality notifications first since these drive the voter. notification = finality_notifications.next() => { if let Some(notification) = notification { @@ -901,6 +896,11 @@ where return; } }, + // Make sure to pump gossip engine. + _ = gossip_engine => { + error!(target: LOG_TARGET, "🥩 Gossip engine has terminated, closing worker."); + return; + }, // Process incoming justifications as these can make some in-flight votes obsolete. justif = self.on_demand_justifications.next().fuse() => { if let Some(justif) = justif { From 03ea99e4b57d17d3029da87a3b196eb9d5178f5d Mon Sep 17 00:00:00 2001 From: cheme Date: Tue, 14 Mar 2023 22:03:50 +0100 Subject: [PATCH 506/715] update trie deps (#13601) --- Cargo.lock | 29 +++++++++---------- bin/node/bench/Cargo.toml | 2 +- client/db/Cargo.toml | 2 +- primitives/api/Cargo.toml | 2 +- primitives/core/Cargo.toml | 2 +- primitives/state-machine/Cargo.toml | 4 +-- primitives/trie/Cargo.toml | 12 ++++---- test-utils/runtime/Cargo.toml | 4 +-- utils/binary-merkle-tree/Cargo.toml | 2 +- .../rpc/state-trie-migration-rpc/Cargo.toml | 2 +- 10 files changed, 30 insertions(+), 31 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4aac7f3c7ed99..0d048a99de668 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2856,9 +2856,9 @@ dependencies = [ [[package]] name = "hash-db" -version = "0.15.2" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d23bd4e7b5eda0d0f3a307e8b381fdc8ba9000f26fbe912250c0a4cc3956364a" +checksum = "8e7d7786361d7425ae2fe4f9e407eb0efaa0840f5212d109cc018c40c35c6ab4" [[package]] name = "hash256-std-hasher" @@ -3484,9 +3484,9 @@ dependencies = [ [[package]] name = "keccak-hasher" -version = "0.15.3" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711adba9940a039f4374fc5724c0a5eaca84a2d558cce62256bfe26f0dbef05e" +checksum = "19ea4653859ca2266a86419d3f592d3f22e7a854b482f99180d2498507902048" dependencies = [ "hash-db", "hash256-std-hasher", @@ -4454,12 +4454,11 @@ dependencies = [ [[package]] name = "memory-db" -version = "0.31.0" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e0c7cba9ce19ac7ffd2053ac9f49843bbd3f4318feedfd74e85c19d5fb0ba66" +checksum = "808b50db46293432a45e63bc15ea51e0ab4c0a1647b8eb114e31a3e698dd6fbe" dependencies = [ "hash-db", - "hashbrown 0.12.3", ] [[package]] @@ -11618,9 +11617,9 @@ dependencies = [ [[package]] name = "trie-bench" -version = "0.36.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac2b7695feb8041efc0adaa09ed3a692ca7b7c997395954fdc838b5b078346f6" +checksum = "4f54b4f9d51d368e62cf7e0730c7c1e18fc658cc84333656bab5b328f44aa964" dependencies = [ "criterion", "hash-db", @@ -11634,9 +11633,9 @@ dependencies = [ [[package]] name = "trie-db" -version = "0.26.0" +version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879380c0061b165ba1f036325b7f3478bc1a947814d9fc36d22c5d8e960b11bd" +checksum = "634d75c77ea43f2ad8ea9d9c58de49dfc9c3995bdef32b503df7883ff054e7f1" dependencies = [ "hash-db", "hashbrown 0.13.2", @@ -11647,18 +11646,18 @@ dependencies = [ [[package]] name = "trie-root" -version = "0.17.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a36c5ca3911ed3c9a5416ee6c679042064b93fc637ded67e25f92e68d783891" +checksum = "d4ed310ef5ab98f5fa467900ed906cb9232dd5376597e00fd4cba2a449d06c0b" dependencies = [ "hash-db", ] [[package]] name = "trie-standardmap" -version = "0.15.2" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3161ba520ab28cd8e6b68e1126f1009f6e335339d1a73b978139011703264c8" +checksum = "684aafb332fae6f83d7fe10b3fbfdbe39a1b3234c4e2a618f030815838519516" dependencies = [ "hash-db", "keccak-hasher", diff --git a/bin/node/bench/Cargo.toml b/bin/node/bench/Cargo.toml index dfff4db43a53b..be5e94ee4df8b 100644 --- a/bin/node/bench/Cargo.toml +++ b/bin/node/bench/Cargo.toml @@ -33,7 +33,7 @@ sc-basic-authorship = { version = "0.10.0-dev", path = "../../../client/basic-au 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 = "6.0.0", path = "../../../primitives/tracing" } -hash-db = "0.15.2" +hash-db = "0.16.0" tempfile = "3.1.0" fs_extra = "1" rand = { version = "0.8.5", features = ["small_rng"] } diff --git a/client/db/Cargo.toml b/client/db/Cargo.toml index ed26f373733e4..c96e5c7405e74 100644 --- a/client/db/Cargo.toml +++ b/client/db/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.2.2", features = [ "derive", ] } -hash-db = "0.15.2" +hash-db = "0.16.0" kvdb = "0.13.0" kvdb-memorydb = "0.13.0" kvdb-rocksdb = { version = "0.17.0", optional = true } diff --git a/primitives/api/Cargo.toml b/primitives/api/Cargo.toml index 75197bcaea900..ae1b3294c281f 100644 --- a/primitives/api/Cargo.toml +++ b/primitives/api/Cargo.toml @@ -21,7 +21,7 @@ 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.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 } +hash-db = { version = "0.16.0", optional = true } thiserror = { version = "1.0.30", optional = true } log = { version = "0.4.17", default-features = false } diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index 7c045377571f6..092baeeda95f8 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -23,7 +23,7 @@ serde = { version = "1.0.136", optional = true, features = ["derive"] } bounded-collections = { version = "0.1.4", default-features = false } primitive-types = { version = "0.12.0", default-features = false, features = ["codec", "scale-info"] } impl-serde = { version = "0.4.0", optional = true } -hash-db = { version = "0.15.2", default-features = false } +hash-db = { version = "0.16.0", default-features = false } hash256-std-hasher = { version = "0.15.2", default-features = false } base58 = { version = "0.2.0", optional = true } rand = { version = "0.8.5", features = ["small_rng"], optional = true } diff --git a/primitives/state-machine/Cargo.toml b/primitives/state-machine/Cargo.toml index 56fbe0726b82e..9759547d7f384 100644 --- a/primitives/state-machine/Cargo.toml +++ b/primitives/state-machine/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false } -hash-db = { version = "0.15.2", default-features = false } +hash-db = { version = "0.16.0", default-features = false } log = { version = "0.4.17", default-features = false } parking_lot = { version = "0.12.1", optional = true } rand = { version = "0.8.5", optional = true } @@ -33,7 +33,7 @@ array-bytes = "4.1" pretty_assertions = "1.2.1" rand = "0.8.5" sp-runtime = { version = "7.0.0", path = "../runtime" } -trie-db = "0.26.0" +trie-db = "0.27.0" assert_matches = "1.5" [features] diff --git a/primitives/trie/Cargo.toml b/primitives/trie/Cargo.toml index fae39ec34c0ea..21582296b67f8 100644 --- a/primitives/trie/Cargo.toml +++ b/primitives/trie/Cargo.toml @@ -21,16 +21,16 @@ harness = false ahash = { version = "0.8.2", optional = true } codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false } hashbrown = { version = "0.12.3", optional = true } -hash-db = { version = "0.15.2", default-features = false } +hash-db = { version = "0.16.0", default-features = false } lazy_static = { version = "1.4.0", optional = true } -memory-db = { version = "0.31.0", default-features = false } +memory-db = { version = "0.32.0", default-features = false } nohash-hasher = { version = "0.2.0", optional = true } parking_lot = { version = "0.12.1", optional = true } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } thiserror = { version = "1.0.30", optional = true } tracing = { version = "0.1.29", optional = true } -trie-db = { version = "0.26.0", default-features = false } -trie-root = { version = "0.17.0", default-features = false } +trie-db = { version = "0.27.0", default-features = false } +trie-root = { version = "0.18.0", default-features = false } sp-core = { version = "7.0.0", default-features = false, path = "../core" } sp-std = { version = "5.0.0", default-features = false, path = "../std" } schnellru = { version = "0.2.1", optional = true } @@ -38,8 +38,8 @@ schnellru = { version = "0.2.1", optional = true } [dev-dependencies] array-bytes = "4.1" criterion = "0.4.0" -trie-bench = "0.36.0" -trie-standardmap = "0.15.2" +trie-bench = "0.37.0" +trie-standardmap = "0.16.0" sp-runtime = { version = "7.0.0", path = "../runtime" } [features] diff --git a/test-utils/runtime/Cargo.toml b/test-utils/runtime/Cargo.toml index e0f414b161cf5..1dcdec0dbf059 100644 --- a/test-utils/runtime/Cargo.toml +++ b/test-utils/runtime/Cargo.toml @@ -23,7 +23,7 @@ codec = { package = "parity-scale-codec", version = "3.2.2", 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.31.0", default-features = false } +memory-db = { version = "0.32.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" } @@ -41,7 +41,7 @@ pallet-timestamp = { version = "4.0.0-dev", default-features = false, path = ".. sp-consensus-grandpa = { version = "4.0.0-dev", default-features = false, path = "../../primitives/consensus/grandpa" } 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.26.0", default-features = false } +trie-db = { version = "0.27.0", default-features = false } 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" } diff --git a/utils/binary-merkle-tree/Cargo.toml b/utils/binary-merkle-tree/Cargo.toml index a59d27fb09bb9..a54dc4f2d0497 100644 --- a/utils/binary-merkle-tree/Cargo.toml +++ b/utils/binary-merkle-tree/Cargo.toml @@ -11,7 +11,7 @@ homepage = "https://substrate.io" [dependencies] array-bytes = { version = "4.1", optional = true } log = { version = "0.4", default-features = false, optional = true } -hash-db = { version = "0.15.2", default-features = false } +hash-db = { version = "0.16.0", default-features = false } [dev-dependencies] array-bytes = "4.1" diff --git a/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml b/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml index e6eccc6ff62e0..3689a87da8ae5 100644 --- a/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml +++ b/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml @@ -21,7 +21,7 @@ log = { version = "0.4.17", default-features = false } sp-core = { path = "../../../../primitives/core" } sp-state-machine = { path = "../../../../primitives/state-machine" } sp-trie = { path = "../../../../primitives/trie" } -trie-db = "0.26.0" +trie-db = "0.27.0" jsonrpsee = { version = "0.16.2", features = ["client-core", "server", "macros"] } From 9eafc96a62d160cd97f8150b2742d7048e394bba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 14 Mar 2023 22:14:58 +0100 Subject: [PATCH 507/715] sp-api: Support expanding the macro code (#13573) * sp-api: Support expanding the macro code This pr introduces the `expander` crate to expand the generated source code into a file. This gives better error reporting when trying to fix issues in the macro itself as Rustc will point to the line in this file. The feature can be enabled by setting `SP_API_EXPAND=1` at compile time. Besides that the generated code is changed to fix warnings in the exanped version. * Fixes --- Cargo.lock | 21 +++++ primitives/api/proc-macro/Cargo.toml | 4 +- primitives/api/proc-macro/src/common.rs | 3 - .../api/proc-macro/src/decl_runtime_apis.rs | 35 ++++--- .../api/proc-macro/src/impl_runtime_apis.rs | 93 ++++++++++++------- .../proc-macro/src/mock_impl_runtime_apis.rs | 16 +--- primitives/api/proc-macro/src/utils.rs | 39 +++----- primitives/api/test/tests/decl_and_impl.rs | 8 +- .../test/tests/ui/impl_missing_version.stderr | 6 +- 9 files changed, 124 insertions(+), 101 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0d048a99de668..d0aea7729bd2d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1997,6 +1997,19 @@ dependencies = [ "futures", ] +[[package]] +name = "expander" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f360349150728553f92e4c997a16af8915f418d3a0f21b440d34c5632f16ed84" +dependencies = [ + "blake2", + "fs-err", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "fake-simd" version = "0.1.2" @@ -2507,6 +2520,12 @@ dependencies = [ "sp-std", ] +[[package]] +name = "fs-err" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0845fa252299212f0389d64ba26f34fa32cfe41588355f21ed507c59a0f64541" + [[package]] name = "fs2" version = "0.4.3" @@ -9925,7 +9944,9 @@ dependencies = [ name = "sp-api-proc-macro" version = "4.0.0-dev" dependencies = [ + "Inflector", "blake2", + "expander", "proc-macro-crate", "proc-macro2", "quote", diff --git a/primitives/api/proc-macro/Cargo.toml b/primitives/api/proc-macro/Cargo.toml index 8acc15d6a0591..ba7c6312042c9 100644 --- a/primitives/api/proc-macro/Cargo.toml +++ b/primitives/api/proc-macro/Cargo.toml @@ -21,8 +21,10 @@ syn = { version = "1.0.98", features = ["full", "fold", "extra-traits", "visit"] proc-macro2 = "1.0.37" blake2 = { version = "0.10.4", default-features = false } proc-macro-crate = "1.1.3" +expander = "1.0.0" +Inflector = "0.11.4" # Required for the doc tests [features] -default = [ "std" ] +default = ["std"] std = [] diff --git a/primitives/api/proc-macro/src/common.rs b/primitives/api/proc-macro/src/common.rs index d29057723b8a4..725ad166fbe73 100644 --- a/primitives/api/proc-macro/src/common.rs +++ b/primitives/api/proc-macro/src/common.rs @@ -18,9 +18,6 @@ /// 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. diff --git a/primitives/api/proc-macro/src/decl_runtime_apis.rs b/primitives/api/proc-macro/src/decl_runtime_apis.rs index d9a72adadec98..3c3056d34487b 100644 --- a/primitives/api/proc-macro/src/decl_runtime_apis.rs +++ b/primitives/api/proc-macro/src/decl_runtime_apis.rs @@ -17,14 +17,14 @@ use crate::utils::{ 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, + 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, + RENAMED_ATTRIBUTE, SUPPORTED_ATTRIBUTE_NAMES, }; use proc_macro2::{Span, TokenStream}; @@ -62,7 +62,7 @@ impl Parse for RuntimeApiDecls { /// Extend the given generics with `Block: BlockT` as first generic parameter. fn extend_generics_with_block(generics: &mut Generics) { - let c = generate_crate_access(HIDDEN_INCLUDES_ID); + let c = generate_crate_access(); generics.lt_token = Some(Default::default()); generics.params.insert(0, parse_quote!( Block: #c::BlockT )); @@ -298,7 +298,7 @@ fn generate_runtime_decls(decls: &[ItemTrait]) -> Result { #[allow(dead_code)] #[allow(deprecated)] pub mod #mod_name { - use super::*; + pub use super::*; #( #versioned_api_traits )* @@ -495,10 +495,10 @@ impl<'a> ToClientSideDecl<'a> { __runtime_api_at_param__, #context, __runtime_api_impl_params_encoded__, - &|version| { + &|_version| { #( // Check if we need to call the function by an old name. - if version.apis.iter().any(|(s, v)| { + if _version.apis.iter().any(|(s, v)| { s == &#runtime_mod::ID && *v < #versions }) { return #old_names @@ -569,7 +569,7 @@ fn generate_runtime_api_version(version: u32) -> TokenStream { /// Generates the implementation of `RuntimeApiInfo` for the given trait. fn generate_runtime_info_impl(trait_: &ItemTrait, version: u64) -> TokenStream { let trait_name = &trait_.ident; - let crate_ = generate_crate_access(HIDDEN_INCLUDES_ID); + let crate_ = generate_crate_access(); let id = generate_runtime_api_id(&trait_name.to_string()); let version = generate_runtime_api_version(version as u32); @@ -620,7 +620,7 @@ fn generate_client_side_decls(decls: &[ItemTrait]) -> Result { for decl in decls { let decl = decl.clone(); - let crate_ = generate_crate_access(HIDDEN_INCLUDES_ID); + let crate_ = generate_crate_access(); let block_hash = quote!( ::Hash ); let mut found_attributes = HashMap::new(); let mut errors = Vec::new(); @@ -777,15 +777,20 @@ 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)?; - let hidden_includes = generate_hidden_includes(HIDDEN_INCLUDES_ID); let runtime_decls = generate_runtime_decls(api_decls)?; let client_side_decls = generate_client_side_decls(api_decls)?; - Ok(quote!( - #hidden_includes - + let decl = quote! { #runtime_decls #client_side_decls - )) + }; + + let decl = expander::Expander::new("decl_runtime_apis") + .dry(std::env::var("SP_API_EXPAND").is_err()) + .verbose(true) + .write_to_out_dir(decl) + .expect("Does not fail because of IO in OUT_DIR; qed"); + + Ok(decl) } diff --git a/primitives/api/proc-macro/src/impl_runtime_apis.rs b/primitives/api/proc-macro/src/impl_runtime_apis.rs index f32961f892bba..5ac07975df0f7 100644 --- a/primitives/api/proc-macro/src/impl_runtime_apis.rs +++ b/primitives/api/proc-macro/src/impl_runtime_apis.rs @@ -17,7 +17,7 @@ use crate::utils::{ extract_all_signature_types, extract_block_type_from_trait_path, extract_impl_trait, - extract_parameter_names_types_and_borrows, generate_crate_access, generate_hidden_includes, + extract_parameter_names_types_and_borrows, generate_crate_access, generate_runtime_mod_name_for_trait, parse_runtime_api_version, prefix_function_with_trait, versioned_trait_name, AllowSelfRefInParameters, RequireQualifiedTraitPath, }; @@ -38,9 +38,6 @@ use syn::{ use std::collections::HashSet; -/// Unique identifier used to make the hidden includes unique for this macro. -const HIDDEN_INCLUDES_ID: &str = "IMPL_RUNTIME_APIS"; - /// The structure used for parsing the runtime api implementations. struct RuntimeApiImpls { impls: Vec, @@ -73,7 +70,7 @@ fn generate_impl_call( let params = extract_parameter_names_types_and_borrows(signature, AllowSelfRefInParameters::No)?; - let c = generate_crate_access(HIDDEN_INCLUDES_ID); + let c = generate_crate_access(); let fn_name = &signature.ident; let fn_name_str = fn_name.to_string(); let pnames = params.iter().map(|v| &v.0); @@ -81,15 +78,33 @@ fn generate_impl_call( let ptypes = params.iter().map(|v| &v.1); let pborrow = params.iter().map(|v| &v.2); + let decode_params = if params.is_empty() { + quote!() + } else { + let let_binding = if params.len() == 1 { + quote! { + let #( #pnames )* : #( #ptypes )* + } + } else { + quote! { + let ( #( #pnames ),* ) : ( #( #ptypes ),* ) + } + }; + + quote!( + #let_binding = + match #c::DecodeLimit::decode_all_with_depth_limit( + #c::MAX_EXTRINSIC_DEPTH, + &mut #input, + ) { + Ok(res) => res, + Err(e) => panic!("Bad input data provided to {}: {}", #fn_name_str, e), + }; + ) + }; + Ok(quote!( - let (#( #pnames ),*) : ( #( #ptypes ),* ) = - match #c::DecodeLimit::decode_all_with_depth_limit( - #c::MAX_EXTRINSIC_DEPTH, - &mut #input, - ) { - Ok(res) => res, - Err(e) => panic!("Bad input data provided to {}: {}", #fn_name_str, e), - }; + #decode_params #[allow(deprecated)] <#runtime as #impl_trait>::#fn_name(#( #pborrow #pnames2 ),*) @@ -134,8 +149,8 @@ fn generate_impl_calls( /// Generate the dispatch function that is used in native to call into the runtime. fn generate_dispatch_function(impls: &[ItemImpl]) -> Result { - let data = Ident::new("__sp_api__input_data", Span::call_site()); - let c = generate_crate_access(HIDDEN_INCLUDES_ID); + let data = Ident::new("_sp_api_input_data_", Span::call_site()); + let c = generate_crate_access(); let impl_calls = generate_impl_calls(impls, &data)? .into_iter() @@ -161,7 +176,7 @@ fn generate_dispatch_function(impls: &[ItemImpl]) -> Result { /// Generate the interface functions that are used to call into the runtime in wasm. fn generate_wasm_interface(impls: &[ItemImpl]) -> Result { let input = Ident::new("input", Span::call_site()); - let c = generate_crate_access(HIDDEN_INCLUDES_ID); + let c = generate_crate_access(); let impl_calls = generate_impl_calls(impls, &input)? @@ -195,7 +210,7 @@ fn generate_wasm_interface(impls: &[ItemImpl]) -> Result { } fn generate_runtime_api_base_structures() -> Result { - let crate_ = generate_crate_access(HIDDEN_INCLUDES_ID); + let crate_ = generate_crate_access(); Ok(quote!( pub struct RuntimeApi {} @@ -414,7 +429,7 @@ impl<'a> ApiRuntimeImplToApiRuntimeApiImpl<'a> { fn process(mut self, input: ItemImpl) -> ItemImpl { let mut input = self.fold_item_impl(input); - let crate_ = generate_crate_access(HIDDEN_INCLUDES_ID); + let crate_ = generate_crate_access(); // 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` @@ -423,7 +438,7 @@ impl<'a> ApiRuntimeImplToApiRuntimeApiImpl<'a> { input.items.push(parse_quote! { fn __runtime_api_internal_call_api_at( &self, - at: <__SR_API_BLOCK__ as #crate_::BlockT>::Hash, + at: <__SrApiBlock__ as #crate_::BlockT>::Hash, context: #crate_::ExecutionContext, params: std::vec::Vec, fn_name: &dyn Fn(#crate_::RuntimeVersion) -> &'static str, @@ -435,7 +450,7 @@ impl<'a> ApiRuntimeImplToApiRuntimeApiImpl<'a> { } let res = (|| { - let version = #crate_::CallApiAt::<__SR_API_BLOCK__>::runtime_version_at( + let version = #crate_::CallApiAt::<__SrApiBlock__>::runtime_version_at( self.call, at, )?; @@ -450,7 +465,7 @@ impl<'a> ApiRuntimeImplToApiRuntimeApiImpl<'a> { recorder: &self.recorder, }; - #crate_::CallApiAt::<__SR_API_BLOCK__>::call_api_at( + #crate_::CallApiAt::<__SrApiBlock__>::call_api_at( self.call, params, ) @@ -469,7 +484,7 @@ impl<'a> ApiRuntimeImplToApiRuntimeApiImpl<'a> { 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 }; + if input == *self.runtime_block { parse_quote!(__SrApiBlock__) } else { input }; fold::fold_type_path(self, new_ty_path) } @@ -480,25 +495,26 @@ impl<'a> Fold for ApiRuntimeImplToApiRuntimeApiImpl<'a> { // Before we directly had the final block type and rust could determine that it is unwind // safe, but now we just have a generic parameter `Block`. - let crate_ = generate_crate_access(HIDDEN_INCLUDES_ID); + let crate_ = generate_crate_access(); // Implement the trait for the `RuntimeApiImpl` input.self_ty = - Box::new(parse_quote!( RuntimeApiImpl<__SR_API_BLOCK__, RuntimeApiImplCall> )); + Box::new(parse_quote!( RuntimeApiImpl<__SrApiBlock__, RuntimeApiImplCall> )); input.generics.params.push(parse_quote!( - __SR_API_BLOCK__: #crate_::BlockT + std::panic::UnwindSafe + + __SrApiBlock__: #crate_::BlockT + std::panic::UnwindSafe + std::panic::RefUnwindSafe )); - input.generics.params.push( - parse_quote!( RuntimeApiImplCall: #crate_::CallApiAt<__SR_API_BLOCK__> + 'static ), - ); + input + .generics + .params + .push(parse_quote!( RuntimeApiImplCall: #crate_::CallApiAt<__SrApiBlock__> + 'static )); let where_clause = input.generics.make_where_clause(); where_clause.predicates.push(parse_quote! { RuntimeApiImplCall::StateBackend: - #crate_::StateBackend<#crate_::HashFor<__SR_API_BLOCK__>> + #crate_::StateBackend<#crate_::HashFor<__SrApiBlock__>> }); where_clause.predicates.push(parse_quote! { &'static RuntimeApiImplCall: Send }); @@ -511,7 +527,7 @@ impl<'a> Fold for ApiRuntimeImplToApiRuntimeApiImpl<'a> { }); where_clause.predicates.push(parse_quote! { - __SR_API_BLOCK__::Header: std::panic::UnwindSafe + std::panic::RefUnwindSafe + __SrApiBlock__::Header: std::panic::UnwindSafe + std::panic::RefUnwindSafe }); input.attrs = filter_cfg_attrs(&input.attrs); @@ -574,7 +590,7 @@ fn generate_runtime_api_versions(impls: &[ItemImpl]) -> Result { let mut sections = Vec::::with_capacity(impls.len()); let mut processed_traits = HashSet::new(); - let c = generate_crate_access(HIDDEN_INCLUDES_ID); + let c = generate_crate_access(); for impl_ in impls { let api_ver = extract_api_version(&impl_.attrs, impl_.span())?.map(|a| a as u32); @@ -629,14 +645,11 @@ fn impl_runtime_apis_impl_inner(api_impls: &[ItemImpl]) -> Result { let dispatch_impl = generate_dispatch_function(api_impls)?; let api_impls_for_runtime = generate_api_impl_for_runtime(api_impls)?; let base_runtime_api = generate_runtime_api_base_structures()?; - let hidden_includes = generate_hidden_includes(HIDDEN_INCLUDES_ID); let runtime_api_versions = generate_runtime_api_versions(api_impls)?; let wasm_interface = generate_wasm_interface(api_impls)?; let api_impls_for_runtime_api = generate_api_impl_for_runtime_api(api_impls)?; - Ok(quote!( - #hidden_includes - + let impl_ = quote!( #base_runtime_api #api_impls_for_runtime @@ -652,7 +665,15 @@ fn impl_runtime_apis_impl_inner(api_impls: &[ItemImpl]) -> Result { #wasm_interface } - )) + ); + + let impl_ = expander::Expander::new("impl_runtime_apis") + .dry(std::env::var("SP_API_EXPAND").is_err()) + .verbose(true) + .write_to_out_dir(impl_) + .expect("Does not fail because of IO in OUT_DIR; qed"); + + Ok(impl_) } // Filters all attributes except the cfg ones. 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 4c79787a1e8df..fc0a754e26730 100644 --- a/primitives/api/proc-macro/src/mock_impl_runtime_apis.rs +++ b/primitives/api/proc-macro/src/mock_impl_runtime_apis.rs @@ -17,8 +17,8 @@ use crate::utils::{ extract_block_type_from_trait_path, extract_impl_trait, - extract_parameter_names_types_and_borrows, generate_crate_access, generate_hidden_includes, - return_type_extract_type, AllowSelfRefInParameters, RequireQualifiedTraitPath, + extract_parameter_names_types_and_borrows, generate_crate_access, return_type_extract_type, + AllowSelfRefInParameters, RequireQualifiedTraitPath, }; use proc_macro2::{Span, TokenStream}; @@ -33,9 +33,6 @@ use syn::{ Attribute, ItemImpl, Pat, Type, TypePath, }; -/// Unique identifier used to make the hidden includes unique for this macro. -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 `Hash` as first @@ -65,7 +62,7 @@ impl Parse for RuntimeApiImpls { /// Implement the `ApiExt` trait and the `Core` runtime api. fn implement_common_api_traits(block_type: TypePath, self_ty: Type) -> Result { - let crate_ = generate_crate_access(HIDDEN_INCLUDES_ID); + let crate_ = generate_crate_access(); Ok(quote!( impl #crate_::ApiExt<#block_type> for #self_ty { @@ -256,7 +253,7 @@ impl<'a> FoldRuntimeApiImpl<'a> { 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); + let crate_ = generate_crate_access(); // 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. @@ -295,7 +292,7 @@ impl<'a> FoldRuntimeApiImpl<'a> { impl<'a> Fold for FoldRuntimeApiImpl<'a> { fn fold_impl_item_method(&mut self, mut input: syn::ImplItemMethod) -> syn::ImplItemMethod { let block = { - let crate_ = generate_crate_access(HIDDEN_INCLUDES_ID); + let crate_ = generate_crate_access(); let is_advanced = has_advanced_attribute(&mut input.attrs); let mut errors = Vec::new(); @@ -469,14 +466,11 @@ pub fn mock_impl_runtime_apis_impl(input: proc_macro::TokenStream) -> proc_macro } fn mock_impl_runtime_apis_impl_inner(api_impls: &[ItemImpl]) -> Result { - let hidden_includes = generate_hidden_includes(HIDDEN_INCLUDES_ID); let GeneratedRuntimeApiImpls { impls, block_type, self_ty } = generate_runtime_api_impls(api_impls)?; let api_traits = implement_common_api_traits(block_type, self_ty)?; Ok(quote!( - #hidden_includes - #impls #api_traits diff --git a/primitives/api/proc-macro/src/utils.rs b/primitives/api/proc-macro/src/utils.rs index dee29b1a52c49..4444a2624b669 100644 --- a/primitives/api/proc-macro/src/utils.rs +++ b/primitives/api/proc-macro/src/utils.rs @@ -24,29 +24,19 @@ use syn::{ 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()) -} +use inflector::Inflector; -/// Generates the hidden includes that are required to make the macro independent from its scope. -pub fn generate_hidden_includes(unique_id: &'static str) -> TokenStream { - let mod_name = generate_hidden_includes_mod_name(unique_id); +/// Generates the access to the `sc_client` crate. +pub fn generate_crate_access() -> TokenStream { match crate_name("sp-api") { - Ok(FoundCrate::Itself) => quote!(), - Ok(FoundCrate::Name(client_name)) => { - let client_name = Ident::new(&client_name, Span::call_site()); - quote!( - #[doc(hidden)] - mod #mod_name { - pub extern crate #client_name as sp_api; - } - ) + Ok(FoundCrate::Itself) => quote!(sp_api), + Ok(FoundCrate::Name(renamed_name)) => { + let renamed_name = Ident::new(&renamed_name, Span::call_site()); + quote!(#renamed_name) }, Err(e) => { let err = Error::new(Span::call_site(), e).to_compile_error(); @@ -55,19 +45,12 @@ pub fn generate_hidden_includes(unique_id: &'static str) -> TokenStream { } } -/// Generates the access to the `sc_client` crate. -pub fn generate_crate_access(unique_id: &'static str) -> TokenStream { - if env::var("CARGO_PKG_NAME").unwrap() == "sp-api" { - quote!(sp_api) - } else { - let mod_name = generate_hidden_includes_mod_name(unique_id); - quote!( self::#mod_name::sp_api ) - } -} - /// 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_), Span::call_site()) + Ident::new( + &format!("runtime_decl_for_{}", trait_.to_string().to_snake_case()), + Span::call_site(), + ) } /// Get the type of a `syn::ReturnType`. diff --git a/primitives/api/test/tests/decl_and_impl.rs b/primitives/api/test/tests/decl_and_impl.rs index 78990d5467d0e..f07adbfa709b5 100644 --- a/primitives/api/test/tests/decl_and_impl.rs +++ b/primitives/api/test/tests/decl_and_impl.rs @@ -166,17 +166,17 @@ fn test_client_side_function_signature() { #[test] fn check_runtime_api_info() { - assert_eq!(&>::ID, &runtime_decl_for_Api::ID); - assert_eq!(>::VERSION, runtime_decl_for_Api::VERSION); + assert_eq!(&>::ID, &runtime_decl_for_api::ID); + assert_eq!(>::VERSION, runtime_decl_for_api::VERSION); assert_eq!(>::VERSION, 1); assert_eq!( >::VERSION, - runtime_decl_for_ApiWithCustomVersion::VERSION, + runtime_decl_for_api_with_custom_version::VERSION, ); assert_eq!( &>::ID, - &runtime_decl_for_ApiWithCustomVersion::ID, + &runtime_decl_for_api_with_custom_version::ID, ); assert_eq!(>::VERSION, 2); diff --git a/primitives/api/test/tests/ui/impl_missing_version.stderr b/primitives/api/test/tests/ui/impl_missing_version.stderr index c0abeffe0cccf..b8ecc466c7fcd 100644 --- a/primitives/api/test/tests/ui/impl_missing_version.stderr +++ b/primitives/api/test/tests/ui/impl_missing_version.stderr @@ -1,10 +1,10 @@ -error[E0433]: failed to resolve: could not find `ApiV4` in `runtime_decl_for_Api` +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` + | ^^^ could not find `ApiV4` in `runtime_decl_for_api` -error[E0405]: cannot find trait `ApiV4` in module `self::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 { From e44038af6440a8f941de64412794707c62e4b4e4 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Tue, 14 Mar 2023 23:53:03 +0100 Subject: [PATCH 508/715] frame epm: expose `feasibility_check` in MinerConfig (#13555) * frame epm: expose feasibity_check in miner The goal with this commit is to expose the `feasibity_check` such that anyone that implements the `MinerConfig trait` can utilize it * cleanup * fix tests --- bin/node/runtime/src/lib.rs | 1 + .../election-provider-multi-phase/src/lib.rs | 127 +++++------------- .../election-provider-multi-phase/src/mock.rs | 3 + .../src/signed.rs | 2 +- .../src/unsigned.rs | 98 +++++++++++++- 5 files changed, 134 insertions(+), 97 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 614dbc4d958c8..d8426d3b35e15 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -702,6 +702,7 @@ impl pallet_election_provider_multi_phase::MinerConfig for Runtime { type Solution = NposSolution16; type MaxVotesPerVoter = <::DataProvider as ElectionDataProvider>::MaxVotesPerVoter; + type MaxWinners = MaxActiveValidators; // The unsigned submissions have to respect the weight of the submit_unsigned call, thus their // weight estimate function is wired to this call's weight. diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index 3ba90f4112a35..80bab68074c87 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -247,10 +247,7 @@ use sp_arithmetic::{ traits::{CheckedAdd, Zero}, UpperOf, }; -use sp_npos_elections::{ - assignment_ratio_to_staked_normalized, BoundedSupports, ElectionScore, EvaluateSupport, - Supports, VoteWeight, -}; +use sp_npos_elections::{BoundedSupports, ElectionScore, IdentifierT, Supports, VoteWeight}; use sp_runtime::{ transaction_validity::{ InvalidTransaction, TransactionPriority, TransactionSource, TransactionValidity, @@ -430,13 +427,17 @@ impl Default for RawSolution { DefaultNoBound, scale_info::TypeInfo, )] -#[scale_info(skip_type_params(T))] -pub struct ReadySolution { +#[scale_info(skip_type_params(AccountId, MaxWinners))] +pub struct ReadySolution +where + AccountId: IdentifierT, + MaxWinners: Get, +{ /// The final supports of the solution. /// /// This is target-major vector, storing each winners, total backing, and each individual /// backer. - pub supports: BoundedSupports, + pub supports: BoundedSupports, /// The score of the solution. /// /// This is needed to potentially challenge the solution. @@ -451,11 +452,11 @@ pub struct ReadySolution { /// These are stored together because they are often accessed together. #[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, Default, TypeInfo)] #[scale_info(skip_type_params(T))] -pub struct RoundSnapshot { +pub struct RoundSnapshot { /// All of the voters. - pub voters: Vec>, + pub voters: Vec, /// All of the targets. - pub targets: Vec, + pub targets: Vec, } /// Encodes the length of a solution or a snapshot. @@ -614,6 +615,7 @@ pub mod pallet { type MinerConfig: crate::unsigned::MinerConfig< AccountId = Self::AccountId, MaxVotesPerVoter = ::MaxVotesPerVoter, + MaxWinners = Self::MaxWinners, >; /// Maximum number of signed submissions that can be queued. @@ -733,6 +735,11 @@ pub mod pallet { fn max_votes_per_voter() -> u32 { ::MaxVotesPerVoter::get() } + + #[pallet::constant_name(MinerMaxWinners)] + fn max_winners() -> u32 { + ::MaxWinners::get() + } } #[pallet::hooks] @@ -1247,14 +1254,15 @@ 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. /// /// 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. /// @@ -1385,7 +1393,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); @@ -1479,89 +1487,22 @@ impl Pallet { pub fn feasibility_check( raw_solution: RawSolution>, compute: ElectionCompute, - ) -> Result, FeasibilityError> { - let RawSolution { solution, score, round } = raw_solution; - - // First, check round. - ensure!(Self::round() == round, FeasibilityError::InvalidRound); - - // Winners are not directly encoded in the solution. - let winners = solution.unique_targets(); - + ) -> Result, FeasibilityError> { let desired_targets = 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; - ensure!( - Self::minimum_untrusted_score().map_or(true, |min_score| { - submitted_score.strict_threshold_better(min_score, Perbill::zero()) - }), - FeasibilityError::UntrustedScoreTooLow - ); - - // Read the entire snapshot. - let RoundSnapshot { voters: snapshot_voters, targets: snapshot_targets } = - 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); - - // Then convert solution -> assignment. This will fail if any of the indices are gibberish, - // namely any of the voters or targets. - let assignments = solution - .into_assignment(voter_at, target_at) - .map_err::(Into::into)?; - - // Ensure that assignments is correct. - 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); - - // This might fail if the normalization fails. Very unlikely. See `integrity_test`. - let staked_assignments = assignment_ratio_to_staked_normalized(assignments, stake_of) - .map_err::(Into::into)?; - let supports = sp_npos_elections::to_supports(&staked_assignments); - - // Finally, check that the claimed score was indeed correct. - 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() - .defensive_map_err(|_| FeasibilityError::BoundedConversionFailed)?; - Ok(ReadySolution { supports, compute, score }) + let snapshot = Self::snapshot().ok_or(FeasibilityError::SnapshotUnavailable)?; + let round = Self::round(); + let minimum_untrusted_score = Self::minimum_untrusted_score(); + + Miner::::feasibility_check( + raw_solution, + compute, + desired_targets, + snapshot, + round, + minimum_untrusted_score, + ) } /// Perform the tasks to be done after a new `elect` has been triggered: diff --git a/frame/election-provider-multi-phase/src/mock.rs b/frame/election-provider-multi-phase/src/mock.rs index 8dee94bb39716..da7a0cf1dd263 100644 --- a/frame/election-provider-multi-phase/src/mock.rs +++ b/frame/election-provider-multi-phase/src/mock.rs @@ -297,6 +297,8 @@ parameter_types! { pub static MockWeightInfo: MockedWeightInfo = MockedWeightInfo::Real; pub static MaxElectingVoters: VoterIndex = u32::max_value(); pub static MaxElectableTargets: TargetIndex = TargetIndex::max_value(); + + #[derive(Debug)] pub static MaxWinners: u32 = 200; pub static EpochLength: u64 = 30; @@ -359,6 +361,7 @@ impl MinerConfig for Runtime { type MaxLength = MinerMaxLength; type MaxWeight = MinerMaxWeight; type MaxVotesPerVoter = ::MaxVotesPerVoter; + type MaxWinners = MaxWinners; type Solution = TestNposSolution; fn solution_weight(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 75bbcfcf9e537..b8a27fdfafde5 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, diff --git a/frame/election-provider-multi-phase/src/unsigned.rs b/frame/election-provider-multi-phase/src/unsigned.rs index 3d80f8f4d9315..9c09cb48c7c05 100644 --- a/frame/election-provider-multi-phase/src/unsigned.rs +++ b/frame/election-provider-multi-phase/src/unsigned.rs @@ -23,12 +23,17 @@ use crate::{ }; use codec::Encode; use frame_election_provider_support::{NposSolution, NposSolver, PerThing128, VoteWeight}; -use frame_support::{dispatch::DispatchResult, ensure, traits::Get, BoundedVec}; +use frame_support::{ + dispatch::DispatchResult, + ensure, + traits::{DefensiveResult, 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, + ElectionScore, EvaluateSupport, }; use sp_runtime::{ offchain::storage::{MutateStorageError, StorageValueRef}, @@ -351,7 +356,7 @@ impl Pallet { // ensure score is being improved. Panic henceforth. ensure!( - Self::queued_solution().map_or(true, |q: ReadySolution<_>| raw_solution + Self::queued_solution().map_or(true, |q: ReadySolution<_, _>| raw_solution .score .strict_threshold_better(q.score, T::BetterUnsignedThreshold::get())), Error::::PreDispatchWeakSubmission, @@ -387,6 +392,8 @@ pub trait MinerConfig { /// /// The weight is computed using `solution_weight`. type MaxWeight: Get; + /// The maximum number of winners that can be elected. + type MaxWinners: Get; /// Something that can compute the weight of a solution. /// /// This weight estimate is then used to trim the solution, based on [`MinerConfig::MaxWeight`]. @@ -689,6 +696,91 @@ impl Miner { ); final_decision } + + /// Checks the feasibility of a solution. + pub fn feasibility_check( + raw_solution: RawSolution>, + compute: ElectionCompute, + desired_targets: u32, + snapshot: RoundSnapshot>, + current_round: u32, + minimum_untrusted_score: Option, + ) -> Result, FeasibilityError> { + let RawSolution { solution, score, round } = raw_solution; + let RoundSnapshot { voters: snapshot_voters, targets: snapshot_targets } = snapshot; + + // First, check round. + ensure!(current_round == round, FeasibilityError::InvalidRound); + + // Winners are not directly encoded in the solution. + let winners = solution.unique_targets(); + + ensure!(winners.len() as u32 == desired_targets, FeasibilityError::WrongWinnerCount); + // Fail early if targets requested by data provider exceed maximum winners supported. + ensure!(desired_targets <= T::MaxWinners::get(), FeasibilityError::TooManyDesiredTargets); + + // Ensure that the solution's score can pass absolute min-score. + let submitted_score = raw_solution.score; + ensure!( + minimum_untrusted_score.map_or(true, |min_score| { + submitted_score.strict_threshold_better(min_score, sp_runtime::Perbill::zero()) + }), + FeasibilityError::UntrustedScoreTooLow + ); + + // ----- 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); + + // Then convert solution -> assignment. This will fail if any of the indices are gibberish, + // namely any of the voters or targets. + let assignments = solution + .into_assignment(voter_at, target_at) + .map_err::(Into::into)?; + + // Ensure that assignments is correct. + 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); + + // This might fail if the normalization fails. Very unlikely. See `integrity_test`. + let staked_assignments = assignment_ratio_to_staked_normalized(assignments, stake_of) + .map_err::(Into::into)?; + let supports = sp_npos_elections::to_supports(&staked_assignments); + + // Finally, check that the claimed score was indeed correct. + 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() + .defensive_map_err(|_| FeasibilityError::BoundedConversionFailed)?; + + Ok(ReadySolution { supports, compute, score }) + } } #[cfg(test)] From ae83a672f2bbe6a4f7391f6a5b2b6fd7ad4f8651 Mon Sep 17 00:00:00 2001 From: Ross Bulat Date: Wed, 15 Mar 2023 12:07:55 +0800 Subject: [PATCH 509/715] Nomination Pool Commission (#13128) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * + nomination pool commission * fmt * use register_update() * Update frame/nomination-pools/src/lib.rs Co-authored-by: Gonçalo Pestana * Update frame/nomination-pools/src/lib.rs Co-authored-by: Gonçalo Pestana * fmt * amend comments * + test for set_commission * fix * Update frame/nomination-pools/fuzzer/src/call.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * rm comment * use PalletError * some feedback item amendments * update weights * revert PalletError stuff * ".git/.scripts/commands/fmt/fmt.sh" * make pool_events_since_last_call more modular * fmt * fix call indexes + test * add payout teste * add event to max_commisson updating current * begin refactor * some debugging * update * more tests * rewardpol not working * commission refactor * pending rewards returns commission * fmt * add claim_commission call * + claim_commission * fix benchmarks * weight 0 for now * + claim_commission benchmark * fmt * apply commission to benchmarks * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_nomination_pools * ".git/.scripts/commands/fmt/fmt.sh" * clippy * + pending * add RewardPool.total_rewards_acounted * fixes * println * more logs * Fix plus cleanups * fix assert * tidy up * tests work + tidy up * rm unused * clippy fix * persist reward_pool update * claim_commission_works tests * . * some test formatting * add high level docs * add calls * docs * rename * rename * docs * rename * fmt * use matches! * Update frame/nomination-pools/src/lib.rs Co-authored-by: Gonçalo Pestana * Update frame/nomination-pools/src/lib.rs Co-authored-by: Gonçalo Pestana * Update frame/nomination-pools/src/tests.rs Co-authored-by: Gonçalo Pestana * comment * Update frame/nomination-pools/src/lib.rs Co-authored-by: Gonçalo Pestana * . * weights order * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_nomination_pools * use from_parts * comment * ".git/.scripts/commands/fmt/fmt.sh" * revert clippy suggestions on old migrations * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_nomination_pools * add InitialGlobalMaxCommission * fix migration * reward counter comments & explanations * format * add commission implementation note * fmt * revert InitialGlobalMaxCommission * global max commission migration generic * text * 100% commission no payout test * add commission_accumulates_on_multiple_rewards * non-zero fuzzer GlobalMaxCommission * add last_recorded_total_payouts_needs_commission * commission event fix + claim commission test --------- Co-authored-by: Gonçalo Pestana Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: command-bot <> Co-authored-by: Bastian Köcher --- .../nomination-pools/benchmarking/src/lib.rs | 161 +- .../nomination-pools/benchmarking/src/mock.rs | 3 +- frame/nomination-pools/fuzzer/src/call.rs | 7 +- frame/nomination-pools/src/lib.rs | 686 ++++++- frame/nomination-pools/src/migration.rs | 101 +- frame/nomination-pools/src/mock.rs | 39 +- frame/nomination-pools/src/tests.rs | 1602 ++++++++++++++++- frame/nomination-pools/src/weights.rs | 590 +++--- .../nomination-pools/test-staking/src/mock.rs | 3 +- 9 files changed, 2730 insertions(+), 462 deletions(-) diff --git a/frame/nomination-pools/benchmarking/src/lib.rs b/frame/nomination-pools/benchmarking/src/lib.rs index 094289ee03265..d58bbaf3d117c 100644 --- a/frame/nomination-pools/benchmarking/src/lib.rs +++ b/frame/nomination-pools/benchmarking/src/lib.rs @@ -31,10 +31,14 @@ use frame_support::{assert_ok, ensure, traits::Get}; use frame_system::RawOrigin as RuntimeOrigin; use pallet_nomination_pools::{ BalanceOf, BondExtra, BondedPoolInner, BondedPools, ClaimPermission, ClaimPermissions, - ConfigOp, MaxPoolMembers, MaxPoolMembersPerPool, MaxPools, Metadata, MinCreateBond, - MinJoinBond, Pallet as Pools, PoolMembers, PoolRoles, PoolState, RewardPools, SubPoolsStorage, + Commission, CommissionChangeRate, ConfigOp, GlobalMaxCommission, MaxPoolMembers, + MaxPoolMembersPerPool, MaxPools, Metadata, MinCreateBond, MinJoinBond, Pallet as Pools, + PoolMembers, PoolRoles, PoolState, RewardPools, SubPoolsStorage, +}; +use sp_runtime::{ + traits::{Bounded, StaticLookup, Zero}, + Perbill, }; -use sp_runtime::traits::{Bounded, StaticLookup, Zero}; use sp_staking::{EraIndex, StakingInterface}; // `frame_benchmarking::benchmarks!` macro needs this use pallet_nomination_pools::Call; @@ -69,6 +73,7 @@ fn create_funded_user_with_balance( fn create_pool_account( n: u32, balance: BalanceOf, + commission: Option, ) -> (T::AccountId, T::AccountId) { let ed = CurrencyOf::::minimum_balance(); let pool_creator: T::AccountId = @@ -84,6 +89,16 @@ fn create_pool_account( ) .unwrap(); + if let Some(c) = commission { + let pool_id = pallet_nomination_pools::LastPoolId::::get(); + Pools::::set_commission( + RuntimeOrigin::Signed(pool_creator.clone()).into(), + pool_id, + Some((c, pool_creator.clone())), + ) + .expect("pool just created, commission can be set by root; qed"); + } + let pool_account = pallet_nomination_pools::BondedPools::::iter() .find(|(_, bonded_pool)| bonded_pool.roles.depositor == pool_creator) .map(|(pool_id, _)| Pools::::create_bonded_account(pool_id)) @@ -134,14 +149,18 @@ impl ListScenario { sp_std::mem::forget(i); // Create accounts with the origin weight - let (pool_creator1, pool_origin1) = create_pool_account::(USER_SEED + 1, origin_weight); + let (pool_creator1, pool_origin1) = + create_pool_account::(USER_SEED + 1, origin_weight, Some(Perbill::from_percent(50))); + T::Staking::nominate( &pool_origin1, // NOTE: these don't really need to be validators. vec![account("random_validator", 0, USER_SEED)], )?; - let (_, pool_origin2) = create_pool_account::(USER_SEED + 2, origin_weight); + let (_, pool_origin2) = + create_pool_account::(USER_SEED + 2, origin_weight, Some(Perbill::from_percent(50))); + T::Staking::nominate( &pool_origin2, vec![account("random_validator", 0, USER_SEED)].clone(), @@ -157,7 +176,9 @@ impl ListScenario { 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); + let (_, pool_dest1) = + create_pool_account::(USER_SEED + 3, dest_weight, Some(Perbill::from_percent(50))); + T::Staking::nominate(&pool_dest1, vec![account("random_validator", 0, USER_SEED)])?; let weight_of = pallet_staking::Pallet::::weight_of_fn(); @@ -269,18 +290,19 @@ frame_benchmarking::benchmarks! { }: _(RuntimeOrigin::Signed(claimer), T::Lookup::unlookup(scenario.creator1.clone()), BondExtra::Rewards) verify { + // commission of 50% deducted here. assert!( T::Staking::active_stake(&scenario.origin1).unwrap() >= - scenario.dest_weight + scenario.dest_weight / 2u32.into() ); } claim_payout { let claimer: T::AccountId = account("claimer", USER_SEED + 4, 0); - + let commission = Perbill::from_percent(50); let origin_weight = Pools::::depositor_min_bond() * 2u32.into(); let ed = CurrencyOf::::minimum_balance(); - let (depositor, pool_account) = create_pool_account::(0, origin_weight); + let (depositor, pool_account) = create_pool_account::(0, origin_weight, Some(commission)); let reward_account = Pools::::create_reward_account(1); // Send funds to the reward account of the pool @@ -301,11 +323,11 @@ frame_benchmarking::benchmarks! { verify { assert_eq!( CurrencyOf::::free_balance(&depositor), - origin_weight * 2u32.into() + origin_weight + commission * origin_weight ); assert_eq!( CurrencyOf::::free_balance(&reward_account), - ed + Zero::zero() + ed + commission * origin_weight ); } @@ -345,7 +367,7 @@ frame_benchmarking::benchmarks! { let s in 0 .. MAX_SPANS; let min_create_bond = Pools::::depositor_min_bond(); - let (depositor, pool_account) = create_pool_account::(0, min_create_bond); + let (depositor, pool_account) = create_pool_account::(0, min_create_bond, None); // Add a new member let min_join_bond = MinJoinBond::::get().max(CurrencyOf::::minimum_balance()); @@ -387,7 +409,7 @@ frame_benchmarking::benchmarks! { let s in 0 .. MAX_SPANS; let min_create_bond = Pools::::depositor_min_bond(); - let (depositor, pool_account) = create_pool_account::(0, min_create_bond); + let (depositor, pool_account) = create_pool_account::(0, min_create_bond, None); // Add a new member let min_join_bond = MinJoinBond::::get().max(CurrencyOf::::minimum_balance()); @@ -433,7 +455,7 @@ frame_benchmarking::benchmarks! { let s in 0 .. MAX_SPANS; let min_create_bond = Pools::::depositor_min_bond(); - let (depositor, pool_account) = create_pool_account::(0, min_create_bond); + let (depositor, pool_account) = create_pool_account::(0, min_create_bond, None); let depositor_lookup = T::Lookup::unlookup(depositor.clone()); // We set the pool to the destroying state so the depositor can leave @@ -523,15 +545,16 @@ frame_benchmarking::benchmarks! { assert_eq!( new_pool, BondedPoolInner { - points: min_create_bond, - state: PoolState::Open, + commission: Commission::default(), member_counter: 1, + points: min_create_bond, roles: PoolRoles { depositor: depositor.clone(), root: Some(depositor.clone()), nominator: Some(depositor.clone()), bouncer: Some(depositor.clone()), }, + state: PoolState::Open, } ); assert_eq!( @@ -545,7 +568,7 @@ frame_benchmarking::benchmarks! { // Create a pool let min_create_bond = Pools::::depositor_min_bond() * 2u32.into(); - let (depositor, pool_account) = create_pool_account::(0, min_create_bond); + let (depositor, pool_account) = create_pool_account::(0, min_create_bond, None); // Create some accounts to nominate. For the sake of benchmarking they don't need to be // actual validators @@ -562,15 +585,16 @@ frame_benchmarking::benchmarks! { assert_eq!( new_pool, BondedPoolInner { - points: min_create_bond, - state: PoolState::Open, + commission: Commission::default(), member_counter: 1, + points: min_create_bond, roles: PoolRoles { depositor: depositor.clone(), root: Some(depositor.clone()), nominator: Some(depositor.clone()), bouncer: Some(depositor.clone()), - } + }, + state: PoolState::Open, } ); assert_eq!( @@ -582,7 +606,7 @@ frame_benchmarking::benchmarks! { set_state { // Create a pool let min_create_bond = Pools::::depositor_min_bond(); - let (depositor, pool_account) = create_pool_account::(0, min_create_bond); + let (depositor, pool_account) = create_pool_account::(0, min_create_bond, None); BondedPools::::mutate(&1, |maybe_pool| { // Force the pool into an invalid state maybe_pool.as_mut().map(|mut pool| pool.points = min_create_bond * 10u32.into()); @@ -599,7 +623,7 @@ frame_benchmarking::benchmarks! { let n in 1 .. ::MaxMetadataLen::get(); // Create a pool - let (depositor, pool_account) = create_pool_account::(0, Pools::::depositor_min_bond() * 2u32.into()); + let (depositor, pool_account) = create_pool_account::(0, Pools::::depositor_min_bond() * 2u32.into(), None); // Create metadata of the max possible size let metadata: Vec = (0..n).map(|_| 42).collect(); @@ -617,18 +641,20 @@ frame_benchmarking::benchmarks! { ConfigOp::Set(BalanceOf::::max_value()), ConfigOp::Set(u32::MAX), ConfigOp::Set(u32::MAX), - ConfigOp::Set(u32::MAX) + ConfigOp::Set(u32::MAX), + ConfigOp::Set(Perbill::max_value()) ) verify { assert_eq!(MinJoinBond::::get(), BalanceOf::::max_value()); assert_eq!(MinCreateBond::::get(), BalanceOf::::max_value()); assert_eq!(MaxPools::::get(), Some(u32::MAX)); assert_eq!(MaxPoolMembers::::get(), Some(u32::MAX)); assert_eq!(MaxPoolMembersPerPool::::get(), Some(u32::MAX)); + assert_eq!(GlobalMaxCommission::::get(), Some(Perbill::max_value())); } update_roles { let first_id = pallet_nomination_pools::LastPoolId::::get() + 1; - let (root, _) = create_pool_account::(0, Pools::::depositor_min_bond() * 2u32.into()); + let (root, _) = create_pool_account::(0, Pools::::depositor_min_bond() * 2u32.into(), None); let random: T::AccountId = account("but is anything really random in computers..?", 0, USER_SEED); }:_( RuntimeOrigin::Signed(root.clone()), @@ -650,7 +676,7 @@ frame_benchmarking::benchmarks! { chill { // Create a pool - let (depositor, pool_account) = create_pool_account::(0, Pools::::depositor_min_bond() * 2u32.into()); + let (depositor, pool_account) = create_pool_account::(0, Pools::::depositor_min_bond() * 2u32.into(), None); // Nominate with the pool. let validators: Vec<_> = (0..T::MaxNominations::get()) @@ -666,10 +692,68 @@ frame_benchmarking::benchmarks! { assert!(T::Staking::nominations(Pools::::create_bonded_account(1)).is_none()); } + set_commission { + // Create a pool - do not set a commission yet. + let (depositor, pool_account) = create_pool_account::(0, Pools::::depositor_min_bond() * 2u32.into(), None); + // set a max commission + Pools::::set_commission_max(RuntimeOrigin::Signed(depositor.clone()).into(), 1u32.into(), Perbill::from_percent(50)).unwrap(); + // set a change rate + Pools::::set_commission_change_rate(RuntimeOrigin::Signed(depositor.clone()).into(), 1u32.into(), CommissionChangeRate { + max_increase: Perbill::from_percent(20), + min_delay: 0u32.into(), + }).unwrap(); + + }:_(RuntimeOrigin::Signed(depositor.clone()), 1u32.into(), Some((Perbill::from_percent(20), depositor.clone()))) + verify { + assert_eq!(BondedPools::::get(1).unwrap().commission, Commission { + current: Some((Perbill::from_percent(20), depositor)), + max: Some(Perbill::from_percent(50)), + change_rate: Some(CommissionChangeRate { + max_increase: Perbill::from_percent(20), + min_delay: 0u32.into() + }), + throttle_from: Some(1u32.into()), + }); + } + + set_commission_max { + // Create a pool, setting a commission that will update when max commission is set. + let (depositor, pool_account) = create_pool_account::(0, Pools::::depositor_min_bond() * 2u32.into(), Some(Perbill::from_percent(50))); + }:_(RuntimeOrigin::Signed(depositor.clone()), 1u32.into(), Perbill::from_percent(50)) + verify { + assert_eq!( + BondedPools::::get(1).unwrap().commission, Commission { + current: Some((Perbill::from_percent(50), depositor)), + max: Some(Perbill::from_percent(50)), + change_rate: None, + throttle_from: Some(0u32.into()), + }); + } + + set_commission_change_rate { + // Create a pool + let (depositor, pool_account) = create_pool_account::(0, Pools::::depositor_min_bond() * 2u32.into(), None); + }:_(RuntimeOrigin::Signed(depositor.clone()), 1u32.into(), CommissionChangeRate { + max_increase: Perbill::from_percent(50), + min_delay: 1000u32.into(), + }) + verify { + assert_eq!( + BondedPools::::get(1).unwrap().commission, Commission { + current: None, + max: None, + change_rate: Some(CommissionChangeRate { + max_increase: Perbill::from_percent(50), + min_delay: 1000u32.into(), + }), + throttle_from: Some(1_u32.into()), + }); + } + set_claim_permission { // Create a pool let min_create_bond = Pools::::depositor_min_bond(); - let (depositor, pool_account) = create_pool_account::(0, min_create_bond); + let (depositor, pool_account) = create_pool_account::(0, min_create_bond, None); // Join pool let min_join_bond = MinJoinBond::::get().max(CurrencyOf::::minimum_balance()); @@ -688,6 +772,31 @@ frame_benchmarking::benchmarks! { assert_eq!(ClaimPermissions::::get(joiner), ClaimPermission::PermissionlessAll); } + claim_commission { + let claimer: T::AccountId = account("claimer_member", USER_SEED + 4, 0); + let commission = Perbill::from_percent(50); + let origin_weight = Pools::::depositor_min_bond() * 2u32.into(); + let ed = CurrencyOf::::minimum_balance(); + let (depositor, pool_account) = create_pool_account::(0, origin_weight, Some(commission)); + let reward_account = Pools::::create_reward_account(1); + CurrencyOf::::make_free_balance_be(&reward_account, ed + origin_weight); + + // member claims a payout to make some commission available. + let _ = Pools::::claim_payout(RuntimeOrigin::Signed(claimer).into()); + + whitelist_account!(depositor); + }:_(RuntimeOrigin::Signed(depositor.clone()), 1u32.into()) + verify { + assert_eq!( + CurrencyOf::::free_balance(&depositor), + origin_weight + commission * origin_weight + ); + assert_eq!( + CurrencyOf::::free_balance(&reward_account), + ed + commission * origin_weight + ); + } + impl_benchmark_test_suite!( Pallet, crate::mock::new_test_ext(), diff --git a/frame/nomination-pools/benchmarking/src/mock.rs b/frame/nomination-pools/benchmarking/src/mock.rs index f6b2022bce518..4a1a52868e367 100644 --- a/frame/nomination-pools/benchmarking/src/mock.rs +++ b/frame/nomination-pools/benchmarking/src/mock.rs @@ -20,7 +20,7 @@ use frame_election_provider_support::VoteWeight; use frame_support::{pallet_prelude::*, parameter_types, traits::ConstU64, PalletId}; use sp_runtime::{ traits::{Convert, IdentityLookup}, - FixedU128, + FixedU128, Perbill, }; type AccountId = u128; @@ -195,6 +195,7 @@ pub fn new_test_ext() -> sp_io::TestExternalities { max_pools: Some(3), max_members_per_pool: Some(3), max_members: Some(3 * 3), + global_max_commission: Some(Perbill::from_percent(50)), } .assimilate_storage(&mut storage); sp_io::TestExternalities::from(storage) diff --git a/frame/nomination-pools/fuzzer/src/call.rs b/frame/nomination-pools/fuzzer/src/call.rs index 5e82471201546..027fb2b69138c 100644 --- a/frame/nomination-pools/fuzzer/src/call.rs +++ b/frame/nomination-pools/fuzzer/src/call.rs @@ -33,11 +33,11 @@ use pallet_nomination_pools::{ mock::*, pallet as pools, pallet::{BondedPools, Call as PoolsCall, Event as PoolsEvents, PoolMembers}, - BondExtra, BondedPool, LastPoolId, MaxPoolMembers, MaxPoolMembersPerPool, MaxPools, - MinCreateBond, MinJoinBond, PoolId, + BondExtra, BondedPool, GlobalMaxCommission, LastPoolId, MaxPoolMembers, MaxPoolMembersPerPool, + MaxPools, MinCreateBond, MinJoinBond, PoolId, }; use rand::{seq::SliceRandom, Rng}; -use sp_runtime::{assert_eq_error_rate, Perquintill}; +use sp_runtime::{assert_eq_error_rate, Perbill, Perquintill}; const ERA: BlockNumber = 1000; const MAX_ED_MULTIPLE: Balance = 10_000; @@ -224,6 +224,7 @@ fn main() { MaxPoolMembers::::set(Some(10_000)); MaxPoolMembersPerPool::::set(Some(1000)); MaxPools::::set(Some(1_000)); + GlobalMaxCommission::::set(Some(Perbill::from_percent(25))); MinCreateBond::::set(10 * ExistentialDeposit::get()); MinJoinBond::::set(5 * ExistentialDeposit::get()); diff --git a/frame/nomination-pools/src/lib.rs b/frame/nomination-pools/src/lib.rs index c1dda69ab5d67..e73d4b4173ecf 100644 --- a/frame/nomination-pools/src/lib.rs +++ b/frame/nomination-pools/src/lib.rs @@ -50,6 +50,11 @@ //! not nominating proper validators. //! * reward account: A similar key-less account, that is set as the `Payee` account for the bonded //! account for all staking rewards. +//! * change rate: The rate at which pool commission can be changed. A change rate consists of a +//! `max_increase` and `min_delay`, dictating the maximum percentage increase that can be applied +//! to the commission per number of blocks. +//! * throttle: An attempted commission increase is throttled if the attempted change falls outside +//! the change rate bounds. //! //! ## Usage //! @@ -125,8 +130,33 @@ //! other members have left. Once they fully withdraw their funds, the pool is destroyed. //! * Nominator: can select which validators the pool nominates. //! * Bouncer: can change the pools state and kick members if the pool is blocked. -//! * Root: can change the nominator, bouncer, or itself and can perform any of the actions the -//! nominator or bouncer can. +//! * Root: can change the nominator, bouncer, or itself, manage and claim commission, and can +//! perform any of the actions the nominator or bouncer can. +//! +//! ## Commission +//! +//! A pool can optionally have a commission configuration, via the `root` role, set with +//! [`Call::set_commission`] and claimed with [`Call::claim_commission`]. A payee account must be +//! supplied with the desired commission percentage. Beyond the commission itself, a pool can have a +//! maximum commission and a change rate. +//! +//! Importantly, both max commission [`Call::set_commission_max`] and change rate +//! [`Call::set_commission_change_rate`] can not be removed once set, and can only be set to more +//! restrictive values (i.e. a lower max commission or a slower change rate) in subsequent updates. +//! +//! If set, a pool's commission is bound to [`GlobalMaxCommission`] at the time it is applied to +//! pending rewards. [`GlobalMaxCommission`] is intended to be updated only via governance. +//! +//! When a pool is dissolved, any outstanding pending commission that has not been claimed will be +//! transferred to the depositor. +//! +//! Implementation note: Commission is analogous to a separate member account of the pool, with its +//! own reward counter in the form of `current_pending_commission`. +//! +//! Crucially, commission is applied to rewards based on the current commission in effect at the +//! time rewards are transferred into the reward pool. This is to prevent the malicious behaviour of +//! changing the commission rate to a very high value after rewards are accumulated, and thus claim +//! an unexpectedly high chunk of the reward. //! //! ### Dismantling //! @@ -232,11 +262,14 @@ //! //! ### Reward pool //! -//! When a pool is first bonded it sets up an deterministic, inaccessible account as its reward -//! destination. +//! When a pool is first bonded it sets up a deterministic, inaccessible account as its reward +//! destination. This reward account combined with `RewardPool` compose a reward pool. //! -//! 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. +//! Reward pools are completely separate entities to bonded pools. Along with its account, a reward +//! pool also tracks its outstanding and claimed rewards as counters, in addition to pending and +//! claimed commission. These counters are updated with `RewardPool::update_records`. The current +//! reward counter of the pool (the total outstanding rewards, in points) is also callable with the +//! `RewardPool::current_reward_counter` method. //! //! See [this link](https://hackmd.io/PFGn6wI5TbCmBYoEA_f2Uw) for an in-depth explanation of the //! reward pool mechanism. @@ -247,13 +280,12 @@ //! //! ### 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 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: +//! 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; @@ -262,8 +294,8 @@ //! 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 +//! 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; @@ -296,14 +328,14 @@ //! `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. +//! 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. +//! 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. @@ -332,21 +364,22 @@ use frame_support::{ Currency, Defensive, DefensiveOption, DefensiveResult, DefensiveSaturating, ExistenceRequirement, Get, }, - DefaultNoBound, + DefaultNoBound, PalletError, }; use scale_info::TypeInfo; use sp_core::U256; use sp_runtime::{ traits::{ - AccountIdConversion, CheckedAdd, CheckedSub, Convert, Saturating, StaticLookup, Zero, + AccountIdConversion, Bounded, CheckedAdd, CheckedSub, Convert, Saturating, StaticLookup, + Zero, }, - FixedPointNumber, + FixedPointNumber, Perbill, }; 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"; +pub const LOG_TARGET: &str = "runtime::nomination-pools"; // syntactic sugar for logging. #[macro_export] @@ -430,19 +463,11 @@ pub enum ClaimPermission { impl ClaimPermission { fn can_bond_extra(&self) -> bool { - match self { - ClaimPermission::PermissionlessAll => true, - ClaimPermission::PermissionlessCompound => true, - _ => false, - } + matches!(self, ClaimPermission::PermissionlessAll | ClaimPermission::PermissionlessCompound) } fn can_claim_payout(&self) -> bool { - match self { - ClaimPermission::PermissionlessAll => true, - ClaimPermission::PermissionlessWithdraw => true, - _ => false, - } + matches!(self, ClaimPermission::PermissionlessAll | ClaimPermission::PermissionlessWithdraw) } } @@ -623,25 +648,232 @@ pub struct PoolRoles { pub bouncer: Option, } +/// Pool commission. +/// +/// The pool `root` can set commission configuration after pool creation. By default, all commission +/// values are `None`. Pool `root` can also set `max` and `change_rate` configurations before +/// setting an initial `current` commission. +/// +/// `current` is a tuple of the commission percentage and payee of commission. `throttle_from` +/// keeps track of which block `current` was last updated. A `max` commission value can only be +/// decreased after the initial value is set, to prevent commission from repeatedly increasing. +/// +/// An optional commission `change_rate` allows the pool to set strict limits to how much commission +/// can change in each update, and how often updates can take place. +#[derive( + Encode, Decode, DefaultNoBound, MaxEncodedLen, TypeInfo, DebugNoBound, PartialEq, Copy, Clone, +)] +#[codec(mel_bound(T: Config))] +#[scale_info(skip_type_params(T))] +pub struct Commission { + /// Optional commission rate of the pool along with the account commission is paid to. + pub current: Option<(Perbill, T::AccountId)>, + /// Optional maximum commission that can be set by the pool `root`. Once set, this value can + /// only be updated to a decreased value. + pub max: Option, + /// Optional configuration around how often commission can be updated, and when the last + /// commission update took place. + pub change_rate: Option>, + /// The block from where throttling should be checked from. This value will be updated on all + /// commission updates and when setting an initial `change_rate`. + pub throttle_from: Option, +} + +impl Commission { + /// Returns true if the current commission updating to `to` would exhaust the change rate + /// limits. + /// + /// A commission update will be throttled (disallowed) if: + /// 1. not enough blocks have passed since the `throttle_from` block, if exists, or + /// 2. the new commission is greater than the maximum allowed increase. + fn throttling(&self, to: &Perbill) -> bool { + if let Some(t) = self.change_rate.as_ref() { + let commission_as_percent = + self.current.as_ref().map(|(x, _)| *x).unwrap_or(Perbill::zero()); + + // do not throttle if `to` is the same or a decrease in commission. + if *to <= commission_as_percent { + return false + } + // Test for `max_increase` throttling. + // + // Throttled if the attempted increase in commission is greater than `max_increase`. + if (*to).saturating_sub(commission_as_percent) > t.max_increase { + return true + } + + // Test for `min_delay` throttling. + // + // Note: matching `None` is defensive only. `throttle_from` should always exist where + // `change_rate` has already been set, so this scenario should never happen. + return self.throttle_from.map_or_else( + || { + defensive!("throttle_from should exist if change_rate is set"); + true + }, + |f| { + // if `min_delay` is zero (no delay), not throttling. + if t.min_delay == Zero::zero() { + false + } else { + // throttling if blocks passed is less than `min_delay`. + let blocks_surpassed = + >::block_number().saturating_sub(f); + blocks_surpassed < t.min_delay + } + }, + ) + } + false + } + + /// Gets the pool's current commission, or returns Perbill::zero if none is set. + /// Bounded to global max if current is greater than `GlobalMaxCommission`. + fn current(&self) -> Perbill { + self.current + .as_ref() + .map_or(Perbill::zero(), |(c, _)| *c) + .min(GlobalMaxCommission::::get().unwrap_or(Bounded::max_value())) + } + + /// Set the pool's commission. + /// + /// Update commission based on `current`. If a `None` is supplied, allow the commission to be + /// removed without any change rate restrictions. Updates `throttle_from` to the current block. + /// If the supplied commission is zero, `None` will be inserted and `payee` will be ignored. + fn try_update_current(&mut self, current: &Option<(Perbill, T::AccountId)>) -> DispatchResult { + self.current = match current { + None => None, + Some((commission, payee)) => { + ensure!(!self.throttling(commission), Error::::CommissionChangeThrottled); + ensure!( + self.max.map_or(true, |m| commission <= &m), + Error::::CommissionExceedsMaximum + ); + if commission.is_zero() { + None + } else { + Some((*commission, payee.clone())) + } + }, + }; + self.register_update(); + Ok(()) + } + + /// Set the pool's maximum commission. + /// + /// The pool's maximum commission can initially be set to any value, and only smaller values + /// thereafter. If larger values are attempted, this function will return a dispatch error. + /// + /// If `current.0` is larger than the updated max commission value, `current.0` will also be + /// updated to the new maximum. This will also register a `throttle_from` update. + /// A `PoolCommissionUpdated` event is triggered if `current.0` is updated. + fn try_update_max(&mut self, pool_id: PoolId, new_max: Perbill) -> DispatchResult { + if let Some(old) = self.max.as_mut() { + if new_max > *old { + return Err(Error::::MaxCommissionRestricted.into()) + } + *old = new_max; + } else { + self.max = Some(new_max) + }; + let updated_current = self + .current + .as_mut() + .map(|(c, _)| { + let u = *c > new_max; + *c = (*c).min(new_max); + u + }) + .unwrap_or(false); + + if updated_current { + if let Some((_, payee)) = self.current.as_ref() { + Pallet::::deposit_event(Event::::PoolCommissionUpdated { + pool_id, + current: Some((new_max, payee.clone())), + }); + } + self.register_update(); + } + Ok(()) + } + + /// Set the pool's commission `change_rate`. + /// + /// Once a change rate configuration has been set, only more restrictive values can be set + /// thereafter. These restrictions translate to increased `min_delay` values and decreased + /// `max_increase` values. + /// + /// Update `throttle_from` to the current block upon setting change rate for the first time, so + /// throttling can be checked from this block. + fn try_update_change_rate( + &mut self, + change_rate: CommissionChangeRate, + ) -> DispatchResult { + ensure!(!&self.less_restrictive(&change_rate), Error::::CommissionChangeRateNotAllowed); + + if self.change_rate.is_none() { + self.register_update(); + } + self.change_rate = Some(change_rate); + Ok(()) + } + + /// Updates a commission's `throttle_from` field to the current block. + fn register_update(&mut self) { + self.throttle_from = Some(>::block_number()); + } + + /// Checks whether a change rate is less restrictive than the current change rate, if any. + /// + /// No change rate will always be less restrictive than some change rate, so where no + /// `change_rate` is currently set, `false` is returned. + fn less_restrictive(&self, new: &CommissionChangeRate) -> bool { + self.change_rate + .as_ref() + .map(|c| new.max_increase > c.max_increase || new.min_delay < c.min_delay) + .unwrap_or(false) + } +} + +/// Pool commission change rate preferences. +/// +/// The pool root is able to set a commission change rate for their pool. A commission change rate +/// consists of 2 values; (1) the maximum allowed commission change, and (2) the minimum amount of +/// blocks that must elapse before commission updates are allowed again. +/// +/// Commission change rates are not applied to decreases in commission. +#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, Debug, PartialEq, Copy, Clone)] +pub struct CommissionChangeRate { + /// The maximum amount the commission can be updated by per `min_delay` period. + pub max_increase: Perbill, + /// How often an update can take place. + pub min_delay: BlockNumber, +} + /// 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, + /// The commission rate of the pool. + pub commission: Commission, /// Count of members that belong to the pool. pub member_counter: u32, + /// Total points of all the members in the pool who are actively bonded. + pub points: BalanceOf, /// See [`PoolRoles`]. pub roles: PoolRoles, + /// The current state of the pool. + pub state: PoolState, } /// 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. +/// 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 { @@ -670,10 +902,11 @@ impl BondedPool { Self { id, inner: BondedPoolInner { + commission: Commission::default(), + member_counter: Zero::zero(), + points: Zero::zero(), roles, state: PoolState::Open, - points: Zero::zero(), - member_counter: Zero::zero(), }, } } @@ -695,7 +928,7 @@ impl BondedPool { /// Consume self and put into storage. fn put(self) { - BondedPools::::insert(self.id, BondedPoolInner { ..self.inner }); + BondedPools::::insert(self.id, self.inner); } /// Consume self and remove from storage. @@ -800,6 +1033,10 @@ impl BondedPool { self.is_root(who) || self.is_bouncer(who) } + fn can_manage_commission(&self, who: &T::AccountId) -> bool { + self.is_root(who) + } + fn is_destroying(&self) -> bool { matches!(self.state, PoolState::Destroying) } @@ -952,7 +1189,7 @@ impl BondedPool { // Cache the value let bonded_account = self.bonded_account(); T::Currency::transfer( - &who, + who, &bonded_account, amount, match ty { @@ -1011,6 +1248,10 @@ pub struct RewardPool { last_recorded_total_payouts: BalanceOf, /// Total amount that this pool has paid out so far to the members. total_rewards_claimed: BalanceOf, + /// The amount of commission pending to be claimed. + total_commission_pending: BalanceOf, + /// The amount of commission that has been claimed. + total_commission_claimed: BalanceOf, } impl RewardPool { @@ -1024,13 +1265,40 @@ impl RewardPool { 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> { + /// Update the recorded values of the reward pool. + /// + /// This function MUST be called whenever the points in the bonded pool change, AND whenever the + /// the pools commission is updated. The reason for the former is that a change in pool points + /// will alter the share of the reward balance among pool members, and the reason for the latter + /// is that a change in commission will alter the share of the reward balance among the pool. + fn update_records( + &mut self, + id: PoolId, + bonded_points: BalanceOf, + commission: Perbill, + ) -> Result<(), Error> { let balance = Self::current_balance(id); - self.last_recorded_reward_counter = self.current_reward_counter(id, bonded_points)?; + + let (current_reward_counter, new_pending_commission) = + self.current_reward_counter(id, bonded_points, commission)?; + + // Store the reward counter at the time of this update. This is used in subsequent calls to + // `current_reward_counter`, whereby newly pending rewards (in points) are added to this + // value. + self.last_recorded_reward_counter = current_reward_counter; + + // Add any new pending commission that has been calculated from `current_reward_counter` to + // determine the total pending commission at the time of this update. + self.total_commission_pending = + self.total_commission_pending.saturating_add(new_pending_commission); + + // Store the total payouts at the time of this update. Total payouts are essentially the + // entire historical balance of the reward pool, equating to the current balance + the total + // rewards that have left the pool + the total commission that has left the pool. self.last_recorded_total_payouts = balance - .checked_add(&self.total_rewards_claimed) + .checked_add(&self.total_rewards_claimed.saturating_add(self.total_commission_claimed)) .ok_or(Error::::OverflowRisk)?; + Ok(()) } @@ -1040,15 +1308,27 @@ impl RewardPool { &self, id: PoolId, bonded_points: BalanceOf, - ) -> Result> { + commission: Perbill, + ) -> Result<(T::RewardCounter, BalanceOf), Error> { let balance = Self::current_balance(id); - let payouts_since_last_record = balance + + // Calculate the current payout balance. The first 3 values of this calculation added + // together represent what the balance would be if no payouts were made. The + // `last_recorded_total_payouts` is then subtracted from this value to cancel out previously + // recorded payouts, leaving only the remaining payouts that have not been claimed. + let current_payout_balance = balance .saturating_add(self.total_rewards_claimed) + .saturating_add(self.total_commission_claimed) .saturating_sub(self.last_recorded_total_payouts); + // Split the `current_payout_balance` into claimable rewards and claimable commission + // according to the current commission rate. + let new_pending_commission = commission * current_payout_balance; + let new_pending_rewards = current_payout_balance.saturating_sub(new_pending_commission); + // * 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 + // `current_payout_balance` 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: // @@ -1066,22 +1346,26 @@ impl RewardPool { // 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: + // 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: + // 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) + let current_reward_counter = + T::RewardCounter::checked_from_rational(new_pending_rewards, bonded_points) + .and_then(|ref r| self.last_recorded_reward_counter.checked_add(r)) + .ok_or(Error::::OverflowRisk)?; + + Ok((current_reward_counter, new_pending_commission)) } /// Current free balance of the reward pool. @@ -1209,9 +1493,10 @@ pub mod pallet { use super::*; use frame_support::traits::StorageVersion; use frame_system::{ensure_signed, pallet_prelude::*}; + use sp_runtime::Perbill; /// The current storage version. - const STORAGE_VERSION: StorageVersion = StorageVersion::new(3); + const STORAGE_VERSION: StorageVersion = StorageVersion::new(4); #[pallet::pallet] #[pallet::storage_version(STORAGE_VERSION)] @@ -1313,6 +1598,12 @@ pub mod pallet { #[pallet::storage] pub type MaxPoolMembersPerPool = StorageValue<_, u32, OptionQuery>; + /// The maximum commission that can be charged by a pool. Used on commission payouts to bound + /// pool commissions that are > `GlobalMaxCommission`, necessary if a future + /// `GlobalMaxCommission` is lower than some current pool commissions. + #[pallet::storage] + pub type GlobalMaxCommission = StorageValue<_, Perbill, OptionQuery>; + /// Active members. /// /// TWOX-NOTE: SAFE since `AccountId` is a secure hash. @@ -1326,13 +1617,13 @@ pub mod pallet { 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. + /// 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. + /// 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>; @@ -1365,6 +1656,7 @@ pub mod pallet { pub max_pools: Option, pub max_members_per_pool: Option, pub max_members: Option, + pub global_max_commission: Option, } #[cfg(feature = "std")] @@ -1376,6 +1668,7 @@ pub mod pallet { max_pools: Some(16), max_members_per_pool: Some(32), max_members: Some(16 * 32), + global_max_commission: None, } } } @@ -1394,6 +1687,9 @@ pub mod pallet { if let Some(max_members) = self.max_members { MaxPoolMembers::::put(max_members); } + if let Some(global_max_commission) = self.global_max_commission { + GlobalMaxCommission::::put(global_max_commission); + } } } @@ -1456,6 +1752,17 @@ pub mod pallet { 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 }, + /// A pool's commission setting has been changed. + PoolCommissionUpdated { pool_id: PoolId, current: Option<(Perbill, T::AccountId)> }, + /// A pool's maximum commission setting has been changed. + PoolMaxCommissionUpdated { pool_id: PoolId, max_commission: Perbill }, + /// A pool's commission `change_rate` has been changed. + PoolCommissionChangeRateUpdated { + pool_id: PoolId, + change_rate: CommissionChangeRate, + }, + /// Pool commission has been claimed. + PoolCommissionClaimed { pool_id: PoolId, commission: BalanceOf }, } #[pallet::error] @@ -1511,6 +1818,18 @@ pub mod pallet { Defensive(DefensiveError), /// Partial unbonding now allowed permissionlessly. PartialUnbondNotAllowedPermissionlessly, + /// The pool's max commission cannot be set higher than the existing value. + MaxCommissionRestricted, + /// The supplied commission exceeds the max allowed commission. + CommissionExceedsMaximum, + /// Not enough blocks have surpassed since the last commission update. + CommissionChangeThrottled, + /// The submitted changes to commission change rate are not allowed. + CommissionChangeRateNotAllowed, + /// There is no pending commission to claim. + NoPendingCommission, + /// No commission current has been set. + NoCommissionCurrentSet, /// Pool id currently in use. PoolIdInUse, /// Pool id provided is not correct/usable. @@ -1519,7 +1838,7 @@ pub mod pallet { BondExtraRestricted, } - #[derive(Encode, Decode, PartialEq, TypeInfo, frame_support::PalletError, RuntimeDebug)] + #[derive(Encode, Decode, PartialEq, TypeInfo, PalletError, RuntimeDebug)] pub enum DefensiveError { /// There isn't enough space in the unbond pool. NotEnoughSpaceInUnbondPool, @@ -1571,7 +1890,11 @@ pub mod pallet { 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)?; + reward_pool.update_records( + pool_id, + bonded_pool.points, + bonded_pool.commission.current(), + )?; bonded_pool.try_inc_members()?; let points_issued = bonded_pool.try_bond_funds(&who, amount, BondType::Later)?; @@ -1622,7 +1945,7 @@ pub mod pallet { } /// 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 + /// has accumulated since their last claimed payout (OR since joining if this is their 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 @@ -1684,7 +2007,11 @@ pub mod pallet { // 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. - let _ = reward_pool.update_records(bonded_pool.id, bonded_pool.points)?; + reward_pool.update_records( + bonded_pool.id, + bonded_pool.points, + bonded_pool.commission.current(), + )?; let _ = Self::do_reward_payout(&who, &mut member, &mut bonded_pool, &mut reward_pool)?; let current_era = T::Staking::current_era(); @@ -1731,7 +2058,7 @@ pub mod pallet { }); // Now that we know everything has worked write the items to storage. - SubPoolsStorage::insert(&member.pool_id, sub_pools); + SubPoolsStorage::insert(member.pool_id, sub_pools); Self::put_member_with_pools(&member_account, member, bonded_pool, reward_pool); Ok(()) } @@ -1820,10 +2147,10 @@ pub mod pallet { .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) { + 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); + sub_pools.with_era.remove(era); } accumulator.saturating_add(balance_to_unbond) } else { @@ -1872,12 +2199,12 @@ pub mod pallet { None } else { bonded_pool.dec_members().put(); - SubPoolsStorage::::insert(&member.pool_id, sub_pools); + 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); + SubPoolsStorage::::insert(member.pool_id, sub_pools); PoolMembers::::insert(&member_account, member); Some(T::WeightInfo::withdraw_unbonded_update(num_slashing_spans)) }; @@ -2002,8 +2329,8 @@ pub mod pallet { /// Set a new metadata for the pool. /// - /// The dispatch origin of this call must be signed by the bouncer, or the root role - /// of the pool. + /// The dispatch origin of this call must be signed by the bouncer, 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( @@ -2036,6 +2363,7 @@ pub mod pallet { /// * `max_pools` - Set [`MaxPools`]. /// * `max_members` - Set [`MaxPoolMembers`]. /// * `max_members_per_pool` - Set [`MaxPoolMembersPerPool`]. + /// * `global_max_commission` - Set [`GlobalMaxCommission`]. #[pallet::call_index(11)] #[pallet::weight(T::WeightInfo::set_configs())] pub fn set_configs( @@ -2045,6 +2373,7 @@ pub mod pallet { max_pools: ConfigOp, max_members: ConfigOp, max_members_per_pool: ConfigOp, + global_max_commission: ConfigOp, ) -> DispatchResult { ensure_root(origin)?; @@ -2063,6 +2392,7 @@ pub mod pallet { config_op_exp!(MaxPools::, max_pools); config_op_exp!(MaxPoolMembers::, max_members); config_op_exp!(MaxPoolMembersPerPool::, max_members_per_pool); + config_op_exp!(GlobalMaxCommission::, global_max_commission); Ok(()) } @@ -2195,6 +2525,103 @@ pub mod pallet { let signer = ensure_signed(origin)?; Self::do_claim_payout(signer, other) } + + /// Set the commission of a pool. + // + /// Both a commission percentage and a commission payee must be provided in the `current` + /// tuple. Where a `current` of `None` is provided, any current commission will be removed. + /// + /// - If a `None` is supplied to `new_commission`, existing commission will be removed. + #[pallet::call_index(17)] + #[pallet::weight(T::WeightInfo::set_commission())] + pub fn set_commission( + origin: OriginFor, + pool_id: PoolId, + new_commission: Option<(Perbill, T::AccountId)>, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + let mut bonded_pool = BondedPool::::get(pool_id).ok_or(Error::::PoolNotFound)?; + ensure!(bonded_pool.can_manage_commission(&who), Error::::DoesNotHavePermission); + + let mut reward_pool = RewardPools::::get(pool_id) + .defensive_ok_or::>(DefensiveError::RewardPoolNotFound.into())?; + // IMPORTANT: make sure that everything up to this point is using the current commission + // before it updates. Note that `try_update_current` could still fail at this point. + reward_pool.update_records( + pool_id, + bonded_pool.points, + bonded_pool.commission.current(), + )?; + RewardPools::insert(pool_id, reward_pool); + + bonded_pool.commission.try_update_current(&new_commission)?; + bonded_pool.put(); + Self::deposit_event(Event::::PoolCommissionUpdated { + pool_id, + current: new_commission, + }); + Ok(()) + } + + /// Set the maximum commission of a pool. + /// + /// - Initial max can be set to any `Perbill`, and only smaller values thereafter. + /// - Current commission will be lowered in the event it is higher than a new max + /// commission. + #[pallet::call_index(18)] + #[pallet::weight(T::WeightInfo::set_commission_max())] + pub fn set_commission_max( + origin: OriginFor, + pool_id: PoolId, + max_commission: Perbill, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + let mut bonded_pool = BondedPool::::get(pool_id).ok_or(Error::::PoolNotFound)?; + ensure!(bonded_pool.can_manage_commission(&who), Error::::DoesNotHavePermission); + + bonded_pool.commission.try_update_max(pool_id, max_commission)?; + bonded_pool.put(); + + Self::deposit_event(Event::::PoolMaxCommissionUpdated { pool_id, max_commission }); + Ok(()) + } + + /// Set the commission change rate for a pool. + /// + /// Initial change rate is not bounded, whereas subsequent updates can only be more + /// restrictive than the current. + #[pallet::call_index(19)] + #[pallet::weight(T::WeightInfo::set_commission_change_rate())] + pub fn set_commission_change_rate( + origin: OriginFor, + pool_id: PoolId, + change_rate: CommissionChangeRate, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + let mut bonded_pool = BondedPool::::get(pool_id).ok_or(Error::::PoolNotFound)?; + ensure!(bonded_pool.can_manage_commission(&who), Error::::DoesNotHavePermission); + + bonded_pool.commission.try_update_change_rate(change_rate)?; + bonded_pool.put(); + + Self::deposit_event(Event::::PoolCommissionChangeRateUpdated { + pool_id, + change_rate, + }); + Ok(()) + } + + /// Claim pending commission. + /// + /// The dispatch origin of this call must be signed by the `root` role of the pool. Pending + /// commission is paid out and added to total claimed commission`. Total pending commission + /// is reset to zero. the current. + #[pallet::call_index(20)] + #[pallet::weight(0)] + pub fn claim_commission(origin: OriginFor, pool_id: PoolId) -> DispatchResult { + let who = ensure_signed(origin)?; + Self::do_claim_commission(who, pool_id) + } } #[pallet::hooks] @@ -2259,7 +2686,8 @@ impl Pallet { Zero::zero() ); - // This shouldn't fail, but if it does we don't really care + // This shouldn't fail, but if it does we don't really care. Remaining balance can consist + // of unclaimed pending commission, errorneous transfers to the reward account, etc. let reward_pool_remaining = T::Currency::free_balance(&reward_account); let _ = T::Currency::transfer( &reward_account, @@ -2295,7 +2723,7 @@ impl Pallet { fn get_member_with_pools( who: &T::AccountId, ) -> Result<(PoolMember, BondedPool, RewardPool), Error> { - let member = PoolMembers::::get(&who).ok_or(Error::::PoolMemberNotFound)?; + let member = PoolMembers::::get(who).ok_or(Error::::PoolMemberNotFound)?; let bonded_pool = BondedPool::::get(member.pool_id).defensive_ok_or(DefensiveError::PoolNotFound)?; let reward_pool = @@ -2323,8 +2751,8 @@ impl Pallet { current_points: BalanceOf, new_funds: BalanceOf, ) -> BalanceOf { - let u256 = |x| T::BalanceToU256::convert(x); - let balance = |x| T::U256ToBalance::convert(x); + let u256 = T::BalanceToU256::convert; + let balance = T::U256ToBalance::convert; match (current_balance.is_zero(), current_points.is_zero()) { (_, true) => new_funds.saturating_mul(POINTS_TO_BALANCE_INIT_RATIO.into()), (true, false) => { @@ -2351,8 +2779,8 @@ impl Pallet { current_points: BalanceOf, points: BalanceOf, ) -> BalanceOf { - let u256 = |x| T::BalanceToU256::convert(x); - let balance = |x| T::U256ToBalance::convert(x); + let u256 = T::BalanceToU256::convert; + let balance = T::U256ToBalance::convert; if current_balance.is_zero() || current_points.is_zero() || points.is_zero() { // There is nothing to unbond return Zero::zero() @@ -2378,10 +2806,15 @@ impl Pallet { // a member who has no skin in the game anymore cannot claim any rewards. ensure!(!member.active_points().is_zero(), Error::::FullyUnbonding); - let current_reward_counter = - reward_pool.current_reward_counter(bonded_pool.id, bonded_pool.points)?; - let pending_rewards = member.pending_rewards(current_reward_counter)?; + let (current_reward_counter, _) = reward_pool.current_reward_counter( + bonded_pool.id, + bonded_pool.points, + bonded_pool.commission.current(), + )?; + // Determine the pending rewards. In scenarios where commission is 100%, `pending_rewards` + // will be zero. + let pending_rewards = member.pending_rewards(current_reward_counter)?; if pending_rewards.is_zero() { return Ok(pending_rewards) } @@ -2390,14 +2823,13 @@ impl Pallet { 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_account, pending_rewards, // defensive: the depositor has put existential deposit into the pool and it stays // untouched, reward account shall not die. - ExistenceRequirement::AllowDeath, + ExistenceRequirement::KeepAlive, )?; Self::deposit_event(Event::::PaidOut { @@ -2462,6 +2894,8 @@ impl Pallet { last_recorded_reward_counter: Zero::zero(), last_recorded_total_payouts: Zero::zero(), total_rewards_claimed: Zero::zero(), + total_commission_pending: Zero::zero(), + total_commission_claimed: Zero::zero(), }, ); ReversePoolIdLookup::::insert(bonded_pool.bonded_account(), pool_id); @@ -2496,7 +2930,11 @@ impl 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)?; + reward_pool.update_records( + bonded_pool.id, + bonded_pool.points, + bonded_pool.commission.current(), + )?; let claimed = Self::do_reward_payout(&who, &mut member, &mut bonded_pool, &mut reward_pool)?; @@ -2522,6 +2960,51 @@ impl Pallet { Ok(()) } + fn do_claim_commission(who: T::AccountId, pool_id: PoolId) -> DispatchResult { + let bonded_pool = BondedPool::::get(pool_id).ok_or(Error::::PoolNotFound)?; + ensure!(bonded_pool.can_manage_commission(&who), Error::::DoesNotHavePermission); + + let mut reward_pool = RewardPools::::get(pool_id) + .defensive_ok_or::>(DefensiveError::RewardPoolNotFound.into())?; + + // IMPORTANT: make sure that any newly pending commission not yet processed is added to + // `total_commission_pending`. + reward_pool.update_records( + pool_id, + bonded_pool.points, + bonded_pool.commission.current(), + )?; + + let commission = reward_pool.total_commission_pending; + ensure!(!commission.is_zero(), Error::::NoPendingCommission); + + let payee = bonded_pool + .commission + .current + .as_ref() + .map(|(_, p)| p.clone()) + .ok_or(Error::::NoCommissionCurrentSet)?; + + // Payout claimed commission. + T::Currency::transfer( + &bonded_pool.reward_account(), + &payee, + commission, + ExistenceRequirement::KeepAlive, + )?; + + // Add pending commission to total claimed counter. + reward_pool.total_commission_claimed = + reward_pool.total_commission_claimed.saturating_add(commission); + // Reset total pending commission counter to zero. + reward_pool.total_commission_pending = Zero::zero(); + // Commit reward pool updates + RewardPools::::insert(pool_id, reward_pool); + + Self::deposit_event(Event::::PoolCommissionClaimed { pool_id, commission }); + Ok(()) + } + fn do_claim_payout(signer: T::AccountId, who: T::AccountId) -> DispatchResult { if signer != who { ensure!( @@ -2608,16 +3091,18 @@ impl Pallet { let mut all_members = 0u32; PoolMembers::::iter().for_each(|(_, d)| { let bonded_pool = BondedPools::::get(d.pool_id).unwrap(); - assert!(!d.total_points().is_zero(), "no member should have zero points: {:?}", d); + 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(); + let commission = bonded_pool.commission.current(); + let (current_rc, _) = reward_pool + .current_reward_counter(d.pool_id, bonded_pool.points, commission) + .unwrap(); + let pending_rewards = d.pending_rewards(current_rc).unwrap(); + *pools_members_pending_rewards.entry(d.pool_id).or_default() += pending_rewards; } // else this pool has been heavily slashed and cannot have any rewards anymore. }); @@ -2633,14 +3118,14 @@ impl Pallet { ); assert!( RewardPool::::current_balance(id) >= - pools_members_pending_rewards.get(&id).map(|x| *x).unwrap_or_default() + pools_members_pending_rewards.get(&id).copied().unwrap_or_default() ) }); BondedPools::::iter().for_each(|(id, inner)| { let bonded_pool = BondedPool { id, inner }; assert_eq!( - pools_members.get(&id).map(|x| *x).unwrap_or_default(), + pools_members.get(&id).copied().unwrap_or_default(), bonded_pool.member_counter ); assert!(MaxPoolMembersPerPool::::get() @@ -2706,8 +3191,9 @@ impl Pallet { 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) + let commission = bonded_pool.commission.current(); + let (current_reward_counter, _) = reward_pool + .current_reward_counter(pool_member.pool_id, bonded_pool.points, commission) .ok()?; return pool_member.pending_rewards(current_reward_counter).ok() } diff --git a/frame/nomination-pools/src/migration.rs b/frame/nomination-pools/src/migration.rs index a1696326989e3..f6f166d7f5de2 100644 --- a/frame/nomination-pools/src/migration.rs +++ b/frame/nomination-pools/src/migration.rs @@ -52,9 +52,12 @@ pub mod v1 { impl OldBondedPoolInner { fn migrate_to_v1(self) -> BondedPoolInner { + // Note: `commission` field not introduced to `BondedPoolInner` until + // migration 4. BondedPoolInner { - member_counter: self.member_counter, points: self.points, + commission: Commission::default(), + member_counter: self.member_counter, state: self.state, roles: self.roles.migrate_to_v1(), } @@ -307,6 +310,8 @@ pub mod v2 { last_recorded_reward_counter: Zero::zero(), last_recorded_total_payouts: Zero::zero(), total_rewards_claimed: Zero::zero(), + total_commission_claimed: Zero::zero(), + total_commission_pending: Zero::zero(), }) }, ); @@ -449,3 +454,97 @@ pub mod v3 { } } } + +pub mod v4 { + use super::*; + + #[derive(Decode)] + pub struct OldBondedPoolInner { + pub points: BalanceOf, + pub state: PoolState, + pub member_counter: u32, + pub roles: PoolRoles, + } + + impl OldBondedPoolInner { + fn migrate_to_v4(self) -> BondedPoolInner { + BondedPoolInner { + commission: Commission::default(), + member_counter: self.member_counter, + points: self.points, + state: self.state, + roles: self.roles, + } + } + } + + /// This migration adds a `commission` field to every `BondedPoolInner`, if + /// any. + pub struct MigrateToV4(sp_std::marker::PhantomData<(T, U)>); + impl> OnRuntimeUpgrade for MigrateToV4 { + 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 == 4 && onchain == 3 { + let initial_global_max_commission = U::get(); + GlobalMaxCommission::::set(Some(initial_global_max_commission)); + log!( + info, + "Set initial global max commission to {:?}.", + initial_global_max_commission + ); + + let mut translated = 0u64; + BondedPools::::translate::, _>(|_key, old_value| { + translated.saturating_inc(); + Some(old_value.migrate_to_v4()) + }); + + current.put::>(); + log!(info, "Upgraded {} pools, storage to version {:?}", translated, current); + + // reads: translated + onchain version. + // writes: translated + current.put + initial global commission. + T::DbWeight::get().reads_writes(translated + 1, translated + 2) + } 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> { + ensure!( + Pallet::::current_storage_version() > Pallet::::on_chain_storage_version(), + "the on_chain version is equal or more than the current one" + ); + Ok(Vec::new()) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(_: Vec) -> Result<(), &'static str> { + // ensure all BondedPools items now contain an `inner.commission: Commission` field. + ensure!( + BondedPools::::iter().all(|(_, inner)| inner.commission.current.is_none() && + inner.commission.max.is_none() && + inner.commission.change_rate.is_none() && + inner.commission.throttle_from.is_none()), + "a commission value has been incorrectly set" + ); + ensure!( + GlobalMaxCommission::::get() == Some(U::get()), + "global maximum commission error" + ); + ensure!(Pallet::::on_chain_storage_version() == 4, "wrong storage version"); + Ok(()) + } + } +} diff --git a/frame/nomination-pools/src/mock.rs b/frame/nomination-pools/src/mock.rs index e8924c0b9c0fa..c6b094f0aa0f1 100644 --- a/frame/nomination-pools/src/mock.rs +++ b/frame/nomination-pools/src/mock.rs @@ -118,8 +118,8 @@ impl sp_staking::StakingInterface for StakingMock { fn stake(who: &Self::AccountId) -> Result, DispatchError> { match ( - UnbondingBalanceMap::get().get(who).map(|v| *v), - BondedBalanceMap::get().get(who).map(|v| *v), + UnbondingBalanceMap::get().get(who).copied(), + BondedBalanceMap::get().get(who).copied(), ) { (None, None) => Err(DispatchError::Other("balance not found")), (Some(v), None) => Ok(Stake { total: v, active: 0, stash: *who }), @@ -251,11 +251,17 @@ pub struct ExtBuilder { members: Vec<(AccountId, Balance)>, max_members: Option, max_members_per_pool: Option, + global_max_commission: Option, } impl Default for ExtBuilder { fn default() -> Self { - Self { members: Default::default(), max_members: Some(4), max_members_per_pool: Some(3) } + Self { + members: Default::default(), + max_members: Some(4), + max_members_per_pool: Some(3), + global_max_commission: Some(Perbill::from_percent(90)), + } } } @@ -297,6 +303,11 @@ impl ExtBuilder { self } + pub fn global_max_commission(mut self, commission: Option) -> Self { + self.global_max_commission = commission; + self + } + pub fn build(self) -> sp_io::TestExternalities { sp_tracing::try_init_simple(); let mut storage = @@ -308,6 +319,7 @@ impl ExtBuilder { max_pools: Some(2), max_members_per_pool: self.max_members_per_pool, max_members: self.max_members, + global_max_commission: self.global_max_commission, } .assimilate_storage(&mut storage); @@ -332,7 +344,7 @@ impl ExtBuilder { ext } - pub fn build_and_execute(self, test: impl FnOnce() -> ()) { + pub fn build_and_execute(self, test: impl FnOnce()) { self.build().execute_with(|| { test(); Pools::do_try_state(CheckLevel::get()).unwrap(); @@ -354,6 +366,23 @@ parameter_types! { storage BalancesEvents: u32 = 0; } +/// Helper to run a specified amount of blocks. +pub fn run_blocks(n: u64) { + let current_block = System::block_number(); + run_to_block(n + current_block); +} + +/// Helper to run to a specific block. +pub fn run_to_block(n: u64) { + let current_block = System::block_number(); + assert!(n > current_block); + while System::block_number() < n { + Pools::on_finalize(System::block_number()); + System::set_block_number(System::block_number() + 1); + Pools::on_initialize(System::block_number()); + } +} + /// All events of this pallet. pub fn pool_events_since_last_call() -> Vec> { let events = System::events() @@ -380,7 +409,7 @@ pub fn balances_events_since_last_call() -> Vec> /// Same as `fully_unbond`, in permissioned setting. pub fn fully_unbond_permissioned(member: AccountId) -> DispatchResult { - let points = PoolMembers::::get(&member) + let points = PoolMembers::::get(member) .map(|d| d.active_points()) .unwrap_or_default(); Pools::unbond(RuntimeOrigin::signed(member), member, points) diff --git a/frame/nomination-pools/src/tests.rs b/frame/nomination-pools/src/tests.rs index 33eee01948d1f..a4fda2e5d91b3 100644 --- a/frame/nomination-pools/src/tests.rs +++ b/frame/nomination-pools/src/tests.rs @@ -3,23 +3,23 @@ // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this 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, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// 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_err, assert_noop, assert_ok, assert_storage_noop, bounded_btree_map}; use pallet_balances::Event as BEvent; -use sp_runtime::traits::Dispatchable; +use sp_runtime::{traits::Dispatchable, FixedU128}; macro_rules! unbonding_pools_with_era { ($($k:expr => $v:expr),* $(,)?) => {{ @@ -55,10 +55,11 @@ fn test_setup_works() { BondedPool:: { id: last_pool, inner: BondedPoolInner { - state: PoolState::Open, - points: 10, + commission: Commission::default(), member_counter: 1, - roles: DEFAULT_ROLES + points: 10, + roles: DEFAULT_ROLES, + state: PoolState::Open, }, } ); @@ -67,7 +68,9 @@ fn test_setup_works() { RewardPool:: { last_recorded_reward_counter: Zero::zero(), last_recorded_total_payouts: 0, - total_rewards_claimed: 0 + total_rewards_claimed: 0, + total_commission_claimed: 0, + total_commission_pending: 0, } ); assert_eq!( @@ -98,10 +101,11 @@ mod bonded_pool { let mut bonded_pool = BondedPool:: { id: 123123, inner: BondedPoolInner { - state: PoolState::Open, - points: 100, + commission: Commission::default(), member_counter: 1, + points: 100, roles: DEFAULT_ROLES, + state: PoolState::Open, }, }; @@ -153,10 +157,11 @@ mod bonded_pool { let mut bonded_pool = BondedPool:: { id: 123123, inner: BondedPoolInner { - state: PoolState::Open, - points: 100, + commission: Commission::default(), member_counter: 1, + points: 100, roles: DEFAULT_ROLES, + state: PoolState::Open, }, }; @@ -241,10 +246,11 @@ mod bonded_pool { let pool = BondedPool:: { id: 123, inner: BondedPoolInner { - state: PoolState::Open, - points: 100, + commission: Commission::default(), member_counter: 1, + points: 100, roles: DEFAULT_ROLES, + state: PoolState::Open, }, }; @@ -258,7 +264,7 @@ mod bonded_pool { // Simulate a slashed pool at `MaxPointsToBalance` + 1 slashed pool StakingMock::set_bonded_balance( pool.bonded_account(), - max_points_to_balance.saturating_add(1).into(), + max_points_to_balance.saturating_add(1), ); assert_ok!(pool.ok_to_join()); @@ -470,16 +476,17 @@ mod join { let bonded = |points, member_counter| BondedPool:: { id: 1, inner: BondedPoolInner { - state: PoolState::Open, - points, + commission: Commission::default(), member_counter, + points, roles: DEFAULT_ROLES, + state: PoolState::Open, }, }; ExtBuilder::default().with_check(0).build_and_execute(|| { // Given Balances::make_free_balance_be(&11, ExistentialDeposit::get() + 2); - assert!(!PoolMembers::::contains_key(&11)); + assert!(!PoolMembers::::contains_key(11)); // When assert_ok!(Pools::join(RuntimeOrigin::signed(11), 2, 1)); @@ -496,7 +503,7 @@ mod join { ); assert_eq!( - PoolMembers::::get(&11).unwrap(), + PoolMembers::::get(11).unwrap(), PoolMember:: { pool_id: 1, points: 2, ..Default::default() } ); assert_eq!(BondedPool::::get(1).unwrap(), bonded(12, 2)); @@ -507,7 +514,7 @@ mod join { // And Balances::make_free_balance_be(&12, ExistentialDeposit::get() + 12); - assert!(!PoolMembers::::contains_key(&12)); + assert!(!PoolMembers::::contains_key(12)); // When assert_ok!(Pools::join(RuntimeOrigin::signed(12), 12, 1)); @@ -519,7 +526,7 @@ mod join { ); assert_eq!( - PoolMembers::::get(&12).unwrap(), + PoolMembers::::get(12).unwrap(), PoolMember:: { pool_id: 1, points: 24, ..Default::default() } ); assert_eq!(BondedPool::::get(1).unwrap(), bonded(12 + 24, 3)); @@ -530,7 +537,7 @@ mod join { 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_eq!(PoolMembers::::get(10).unwrap().pool_id, 1); assert_noop!( Pools::join(RuntimeOrigin::signed(10), 420, 123), @@ -553,10 +560,11 @@ mod join { BondedPool:: { id: 123, inner: BondedPoolInner { + commission: Commission::default(), member_counter: 1, - state: PoolState::Open, points: 100, roles: DEFAULT_ROLES, + state: PoolState::Open, }, } .put(); @@ -622,10 +630,11 @@ mod join { BondedPool:: { id: 123, inner: BondedPoolInner { - state: PoolState::Open, - points: 100, + commission: Commission::default(), member_counter: 1, + points: 100, roles: DEFAULT_ROLES, + state: PoolState::Open, }, } .put(); @@ -722,6 +731,8 @@ mod claim_payout { last_recorded_reward_counter: last_recorded_reward_counter.into(), last_recorded_total_payouts, total_rewards_claimed, + total_commission_claimed: 0, + total_commission_pending: 0, } } @@ -754,7 +765,7 @@ mod claim_payout { 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!(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); @@ -767,7 +778,7 @@ mod claim_payout { vec![Event::PaidOut { member: 40, pool_id: 1, payout: 40 }] ); assert_eq!(PoolMembers::::get(40).unwrap(), del(40, 1)); - assert_eq!(RewardPools::::get(&1).unwrap(), rew(0, 0, 50)); + 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); @@ -780,9 +791,9 @@ mod claim_payout { vec![Event::PaidOut { member: 50, pool_id: 1, payout: 50 }] ); assert_eq!(PoolMembers::::get(50).unwrap(), del(50, 1)); - assert_eq!(RewardPools::::get(&1).unwrap(), rew(0, 0, 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); + assert_eq!(Balances::free_balance(&default_reward_account()), ed); // Given the reward pool has some new rewards assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 50)); @@ -796,7 +807,7 @@ mod claim_payout { vec![Event::PaidOut { member: 10, pool_id: 1, payout: 5 }] ); assert_eq!(PoolMembers::::get(10).unwrap(), del_float(10, 1.5)); - assert_eq!(RewardPools::::get(&1).unwrap(), rew(0, 0, 105)); + 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); @@ -809,7 +820,7 @@ mod claim_payout { vec![Event::PaidOut { member: 40, pool_id: 1, payout: 20 }] ); assert_eq!(PoolMembers::::get(40).unwrap(), del_float(40, 1.5)); - assert_eq!(RewardPools::::get(&1).unwrap(), rew(0, 0, 125)); + 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); @@ -826,7 +837,7 @@ mod claim_payout { vec![Event::PaidOut { member: 50, pool_id: 1, payout: 50 }] ); assert_eq!(PoolMembers::::get(50).unwrap(), del_float(50, 2.0)); - assert_eq!(RewardPools::::get(&1).unwrap(), rew(0, 0, 175)); + 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); @@ -839,7 +850,7 @@ mod claim_payout { vec![Event::PaidOut { member: 10, pool_id: 1, payout: 5 }] ); assert_eq!(PoolMembers::::get(10).unwrap(), del(10, 2)); - assert_eq!(RewardPools::::get(&1).unwrap(), rew(0, 0, 180)); + 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); @@ -858,7 +869,7 @@ mod claim_payout { // We expect a payout of 40 assert_eq!(PoolMembers::::get(10).unwrap(), del(10, 6)); - assert_eq!(RewardPools::::get(&1).unwrap(), rew(0, 0, 220)); + assert_eq!(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); @@ -875,7 +886,7 @@ mod claim_payout { vec![Event::PaidOut { member: 10, pool_id: 1, payout: 2 }] ); assert_eq!(PoolMembers::::get(10).unwrap(), del_float(10, 6.2)); - assert_eq!(RewardPools::::get(&1).unwrap(), rew(0, 0, 222)); + 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); @@ -888,7 +899,7 @@ mod claim_payout { vec![Event::PaidOut { member: 40, pool_id: 1, payout: 188 }] ); assert_eq!(PoolMembers::::get(40).unwrap(), del_float(40, 6.2)); - assert_eq!(RewardPools::::get(&1).unwrap(), rew(0, 0, 410)); + 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); @@ -901,9 +912,9 @@ mod claim_payout { vec![Event::PaidOut { member: 50, pool_id: 1, payout: 210 }] ); assert_eq!(PoolMembers::::get(50).unwrap(), del_float(50, 6.2)); - assert_eq!(RewardPools::::get(&1).unwrap(), rew(0, 0, 620)); + 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); + assert_eq!(Balances::free_balance(&default_reward_account()), ed); }); } @@ -930,6 +941,56 @@ mod claim_payout { }); } + #[test] + fn claim_payout_bounds_commission_above_global() { + ExtBuilder::default().build_and_execute(|| { + let (mut member, bonded_pool, mut reward_pool) = + Pools::get_member_with_pools(&10).unwrap(); + + // top up commission payee account to existential deposit + let _ = Balances::deposit_creating(&2, 5); + + // Set a commission pool 1 to 75%, with a payee set to `2` + assert_ok!(Pools::set_commission( + RuntimeOrigin::signed(900), + bonded_pool.id, + Some((Perbill::from_percent(75), 2)), + )); + + // re-introduce the global maximum to 50% - 25% lower than the current commission of the + // pool. + GlobalMaxCommission::::set(Some(Perbill::from_percent(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::PoolCommissionUpdated { + pool_id: 1, + current: Some((Perbill::from_percent(75), 2)) + } + ] + ); + + // The pool earns 10 points + assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 10)); + + assert_ok!(Pools::do_reward_payout( + &10, + &mut member, + &mut BondedPool::::get(1).unwrap(), + &mut reward_pool + )); + + // commission applied is 50%, not 75%. Has been bounded by `GlobalMaxCommission`. + assert_eq!( + pool_events_since_last_call(), + vec![Event::PaidOut { member: 10, pool_id: 1, payout: 5 },] + ); + }) + } + #[test] fn do_reward_payout_works_with_a_pool_of_1() { let del = |last_recorded_reward_counter| del_float(10, last_recorded_reward_counter); @@ -987,7 +1048,7 @@ mod claim_payout { assert_eq!(member, del(1.5)); // Given the pool has earned no new rewards - Balances::make_free_balance_be(&default_reward_account(), ed + 0); + Balances::make_free_balance_be(&default_reward_account(), ed); // When let payout = @@ -2432,7 +2493,7 @@ mod unbond { assert_eq!( SubPoolsStorage::::get(1).unwrap().with_era, - unbonding_pools_with_era! { 0 + 3 => UnbondPool:: { points: 10, balance: 10 }} + unbonding_pools_with_era! { 3 => UnbondPool:: { points: 10, balance: 10 }} ); assert_eq!( @@ -2440,10 +2501,11 @@ mod unbond { BondedPool { id: 1, inner: BondedPoolInner { - state: PoolState::Destroying, - points: 0, + commission: Commission::default(), member_counter: 1, + points: 0, roles: DEFAULT_ROLES, + state: PoolState::Destroying, } } ); @@ -2469,17 +2531,18 @@ mod unbond { // Then assert_eq!( SubPoolsStorage::::get(1).unwrap().with_era, - unbonding_pools_with_era! { 0 + 3 => UnbondPool { points: 6, balance: 6 }} + unbonding_pools_with_era! { 3 => UnbondPool { points: 6, balance: 6 }} ); assert_eq!( BondedPool::::get(1).unwrap(), BondedPool { id: 1, inner: BondedPoolInner { - state: PoolState::Open, - points: 560, + commission: Commission::default(), member_counter: 3, + points: 560, roles: DEFAULT_ROLES, + state: PoolState::Open, } } ); @@ -2498,7 +2561,7 @@ mod unbond { assert_eq!(StakingMock::active_stake(&default_bonded_account()).unwrap(), 94); assert_eq!( PoolMembers::::get(40).unwrap().unbonding_eras, - member_unbonding_eras!(0 + 3 => 6) + member_unbonding_eras!(3 => 6) ); assert_eq!(Balances::free_balance(&40), 40 + 40); // We claim rewards when unbonding @@ -2508,25 +2571,26 @@ mod unbond { // Then assert_eq!( - SubPoolsStorage::::get(&1).unwrap().with_era, - unbonding_pools_with_era! { 0 + 3 => UnbondPool { points: 98, balance: 98 }} + SubPoolsStorage::::get(1).unwrap().with_era, + unbonding_pools_with_era! { 3 => UnbondPool { points: 98, balance: 98 }} ); assert_eq!( BondedPool::::get(1).unwrap(), BondedPool { id: 1, inner: BondedPoolInner { - state: PoolState::Destroying, - points: 10, + commission: Commission::default(), member_counter: 3, - roles: DEFAULT_ROLES + points: 10, + roles: DEFAULT_ROLES, + state: PoolState::Destroying, } } ); assert_eq!(StakingMock::active_stake(&default_bonded_account()).unwrap(), 2); assert_eq!( PoolMembers::::get(550).unwrap().unbonding_eras, - member_unbonding_eras!(0 + 3 => 92) + member_unbonding_eras!(3 => 92) ); assert_eq!(Balances::free_balance(&550), 550 + 550); assert_eq!( @@ -2559,10 +2623,11 @@ mod unbond { BondedPool { id: 1, inner: BondedPoolInner { - state: PoolState::Destroying, - points: 0, + commission: Commission::default(), member_counter: 1, - roles: DEFAULT_ROLES + points: 0, + roles: DEFAULT_ROLES, + state: PoolState::Destroying, } } ); @@ -2593,7 +2658,7 @@ mod unbond { SubPools { no_era: Default::default(), with_era: unbonding_pools_with_era! { - 0 + 3 => UnbondPool { balance: 10, points: 100 }, + 3 => UnbondPool { balance: 10, points: 100 }, 1 + 3 => UnbondPool { balance: 20, points: 20 }, 2 + 3 => UnbondPool { balance: 101, points: 101} }, @@ -2687,10 +2752,11 @@ mod unbond { BondedPool { id: 1, inner: BondedPoolInner { + commission: Commission::default(), + member_counter: 3, + points: 10, // Only 10 points because 200 + 100 was unbonded roles: DEFAULT_ROLES, state: PoolState::Blocked, - points: 10, // Only 10 points because 200 + 100 was unbonded - member_counter: 3, } } ); @@ -2700,7 +2766,7 @@ mod unbond { SubPools { no_era: Default::default(), with_era: unbonding_pools_with_era! { - 0 + 3 => UnbondPool { points: 100 + 200, balance: 100 + 200 } + 3 => UnbondPool { points: 100 + 200, balance: 100 + 200 } }, } ); @@ -2837,10 +2903,11 @@ mod unbond { BondedPool:: { id: 1, inner: BondedPoolInner { - state: PoolState::Open, - points: 10, + commission: Commission::default(), member_counter: 1, + points: 10, roles: DEFAULT_ROLES, + state: PoolState::Open, }, } .put(); @@ -3356,7 +3423,7 @@ mod withdraw_unbonded { assert_ok!(fully_unbond_permissioned(550)); assert_eq!( - SubPoolsStorage::::get(&1).unwrap().with_era, + SubPoolsStorage::::get(1).unwrap().with_era, unbonding_pools_with_era! { 3 => UnbondPool { points: 550 / 2 + 40 / 2, balance: 550 / 2 + 40 / 2 }} ); @@ -3406,7 +3473,7 @@ mod withdraw_unbonded { ); assert_eq!( - SubPoolsStorage::::get(&1).unwrap().with_era, + SubPoolsStorage::::get(1).unwrap().with_era, unbonding_pools_with_era! { 3 => UnbondPool { points: 550 / 2, balance: 550 / 2 }} ); @@ -3425,7 +3492,7 @@ mod withdraw_unbonded { Event::MemberRemoved { pool_id: 1, member: 550 } ] ); - assert!(SubPoolsStorage::::get(&1).unwrap().with_era.is_empty()); + assert!(SubPoolsStorage::::get(1).unwrap().with_era.is_empty()); // now, finally, the depositor can take out its share. unsafe_set_state(1, PoolState::Destroying); @@ -3433,7 +3500,7 @@ mod withdraw_unbonded { // because everyone else has left, the points assert_eq!( - SubPoolsStorage::::get(&1).unwrap().with_era, + SubPoolsStorage::::get(1).unwrap().with_era, unbonding_pools_with_era! { 6 => UnbondPool { points: 5, balance: 5 }} ); @@ -3487,10 +3554,10 @@ mod withdraw_unbonded { 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 } } + unbonding_pools_with_era! { 3 => UnbondPool { points: 10, balance: 10 } } ); - CurrentEra::set(0 + 3); + CurrentEra::set(3); // When assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 10, 0)); @@ -3507,7 +3574,7 @@ mod withdraw_unbonded { // 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 }}, + with_era: unbonding_pools_with_era! { 3 => UnbondPool { points: 10, balance: 10 }}, }; SubPoolsStorage::::insert(1, sub_pools.clone()); @@ -3520,7 +3587,7 @@ mod withdraw_unbonded { PoolMembers::::insert(11, member.clone()); // Simulate calling `unbond` - member.unbonding_eras = member_unbonding_eras!(3 + 0 => 10); + member.unbonding_eras = member_unbonding_eras!(3 => 10); PoolMembers::::insert(11, member.clone()); // We are still in the bonding duration @@ -3530,7 +3597,7 @@ mod withdraw_unbonded { ); // If we error the member does not get removed - assert_eq!(PoolMembers::::get(&11), Some(member)); + assert_eq!(PoolMembers::::get(11), Some(member)); // and the sub pools do not get updated. assert_eq!(SubPoolsStorage::::get(1).unwrap(), sub_pools) }); @@ -3549,10 +3616,11 @@ mod withdraw_unbonded { BondedPool { id: 1, inner: BondedPoolInner { + commission: Commission::default(), + member_counter: 3, points: 10, + roles: DEFAULT_ROLES, state: PoolState::Open, - member_counter: 3, - roles: DEFAULT_ROLES } } ); @@ -3629,10 +3697,11 @@ mod withdraw_unbonded { BondedPool { id: 1, inner: BondedPoolInner { - points: 10, - state: PoolState::Open, + commission: Commission::default(), member_counter: 2, + points: 10, roles: DEFAULT_ROLES, + state: PoolState::Open, } } ); @@ -4225,15 +4294,16 @@ mod create { BondedPool { id: 2, inner: BondedPoolInner { + commission: Commission::default(), points: StakingMock::minimum_nominator_bond(), member_counter: 1, - state: PoolState::Open, roles: PoolRoles { depositor: 11, root: Some(123), nominator: Some(456), bouncer: Some(789) - } + }, + state: PoolState::Open, } } ); @@ -4289,10 +4359,11 @@ mod create { BondedPool:: { id: 2, inner: BondedPoolInner { - state: PoolState::Open, - points: 10, + commission: Commission::default(), member_counter: 1, + points: 10, roles: DEFAULT_ROLES, + state: PoolState::Open, }, } .put(); @@ -4369,7 +4440,7 @@ fn set_claimable_actor_works() { ExtBuilder::default().build_and_execute(|| { // Given Balances::make_free_balance_be(&11, ExistentialDeposit::get() + 2); - assert!(!PoolMembers::::contains_key(&11)); + assert!(!PoolMembers::::contains_key(11)); // When assert_ok!(Pools::join(RuntimeOrigin::signed(11), 2, 1)); @@ -4574,12 +4645,14 @@ mod set_configs { ConfigOp::Set(3u32), ConfigOp::Set(4u32), ConfigOp::Set(5u32), + ConfigOp::Set(Perbill::from_percent(6)) )); 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)); + assert_eq!(GlobalMaxCommission::::get(), Some(Perbill::from_percent(6))); // Noop does nothing assert_storage_noop!(assert_ok!(Pools::set_configs( @@ -4589,6 +4662,7 @@ mod set_configs { ConfigOp::Noop, ConfigOp::Noop, ConfigOp::Noop, + ConfigOp::Noop, ))); // Removing works @@ -4599,12 +4673,14 @@ mod set_configs { 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); + assert_eq!(GlobalMaxCommission::::get(), None); }); } } @@ -4949,8 +5025,6 @@ mod update_roles { } mod reward_counter_precision { - use sp_runtime::FixedU128; - use super::*; const DOT: Balance = 10u128.pow(10u32); @@ -4967,10 +5041,12 @@ mod reward_counter_precision { } fn default_pool_reward_counter() -> FixedU128 { - RewardPools::::get(1) + let bonded_pool = BondedPools::::get(1).unwrap(); + RewardPools::::get(1) .unwrap() - .current_reward_counter(1, BondedPools::::get(1).unwrap().points) + .current_reward_counter(1, bonded_pool.points, bonded_pool.commission.current()) .unwrap() + .0 } fn pending_rewards(of: AccountId) -> Option> { @@ -5292,3 +5368,1353 @@ mod reward_counter_precision { }); } } + +mod commission { + use super::*; + + #[test] + fn set_commission_works() { + ExtBuilder::default().build_and_execute(|| { + let pool_id = 1; + let root = 900; + + // Commission can be set by the `root` role. + + // When: + assert_ok!(Pools::set_commission( + RuntimeOrigin::signed(root), + pool_id, + Some((Perbill::from_percent(50), root)) + )); + + // Then: + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Created { depositor: 10, pool_id }, + Event::Bonded { member: 10, pool_id, bonded: 10, joined: true }, + Event::PoolCommissionUpdated { + pool_id, + current: Some((Perbill::from_percent(50), root)) + }, + ] + ); + + // Commission can be updated only, while keeping the same payee. + + // When: + assert_ok!(Pools::set_commission( + RuntimeOrigin::signed(root), + 1, + Some((Perbill::from_percent(25), root)) + )); + + // Then: + assert_eq!( + pool_events_since_last_call(), + vec![Event::PoolCommissionUpdated { + pool_id, + current: Some((Perbill::from_percent(25), root)) + },] + ); + + // Payee can be updated only, while keeping the same commission. + + // Given: + let payee = 901; + + // When: + assert_ok!(Pools::set_commission( + RuntimeOrigin::signed(root), + pool_id, + Some((Perbill::from_percent(25), payee)) + )); + + // Then: + assert_eq!( + pool_events_since_last_call(), + vec![Event::PoolCommissionUpdated { + pool_id: 1, + current: Some((Perbill::from_percent(25), payee)) + },] + ); + + // Pool earns 80 points and a payout is triggered. + + // Given: + assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 80)); + assert_eq!( + PoolMembers::::get(10).unwrap(), + PoolMember:: { pool_id, points: 10, ..Default::default() } + ); + + // When: + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); + + // Then: + assert_eq!( + pool_events_since_last_call(), + vec![Event::PaidOut { member: 10, pool_id, payout: 60 }] + ); + assert_eq!(RewardPool::::current_balance(pool_id), 20); + + // Pending pool commission can be claimed by the root role. + + // When: + assert_ok!(Pools::claim_commission(RuntimeOrigin::signed(root), pool_id)); + + // Then: + assert_eq!(RewardPool::::current_balance(pool_id), 0); + assert_eq!( + pool_events_since_last_call(), + vec![Event::PoolCommissionClaimed { pool_id: 1, commission: 20 }] + ); + + // Commission can be removed from the pool completely. + + // When: + assert_ok!(Pools::set_commission(RuntimeOrigin::signed(root), pool_id, None)); + + // Then: + assert_eq!( + pool_events_since_last_call(), + vec![Event::PoolCommissionUpdated { pool_id, current: None },] + ); + + // Given a pool now has a reward counter history, additional rewards and payouts can be + // made while maintaining a correct ledger of the reward pool. Pool earns 100 points, + // payout is triggered. + // + // Note that the `total_commission_pending` will not be updated until `update_records` + // is next called, which is not done in this test segment.. + + // Given: + assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 100)); + + // When: + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); + + // Then: + assert_eq!( + pool_events_since_last_call(), + vec![Event::PaidOut { member: 10, pool_id, payout: 100 },] + ); + assert_eq!( + RewardPools::::get(pool_id).unwrap(), + RewardPool { + last_recorded_reward_counter: FixedU128::from_float(6.0), + last_recorded_total_payouts: 80, + total_rewards_claimed: 160, + total_commission_pending: 0, + total_commission_claimed: 20 + } + ); + + // When set commission is called again, update_records is called and + // `total_commission_pending` is updated, based on the current reward counter and pool + // balance. + // + // Note that commission is now 0%, so it should not come into play with subsequent + // payouts. + + // When: + assert_ok!(Pools::set_commission( + RuntimeOrigin::signed(root), + 1, + Some((Perbill::from_percent(10), root)) + )); + + // Then: + assert_eq!( + pool_events_since_last_call(), + vec![Event::PoolCommissionUpdated { + pool_id, + current: Some((Perbill::from_percent(10), root)) + },] + ); + assert_eq!( + RewardPools::::get(pool_id).unwrap(), + RewardPool { + last_recorded_reward_counter: FixedU128::from_float(16.0), + last_recorded_total_payouts: 180, + total_rewards_claimed: 160, + total_commission_pending: 0, + total_commission_claimed: 20 + } + ); + + // Supplying a 0% commission along with a payee results in a `None` current value. + + // When: + assert_ok!(Pools::set_commission( + RuntimeOrigin::signed(root), + pool_id, + Some((Perbill::from_percent(0), root)) + )); + + // Then: + assert_eq!( + BondedPool::::get(1).unwrap().commission, + Commission { current: None, max: None, change_rate: None, throttle_from: Some(1) } + ); + assert_eq!( + pool_events_since_last_call(), + vec![Event::PoolCommissionUpdated { + pool_id, + current: Some((Perbill::from_percent(0), root)) + },] + ); + + // The payee can be updated even when commission has reached maximum commission. Both + // commission and max commission are set to 10% to test this. + + // Given: + assert_ok!(Pools::set_commission_max( + RuntimeOrigin::signed(root), + pool_id, + Perbill::from_percent(10) + )); + assert_ok!(Pools::set_commission( + RuntimeOrigin::signed(root), + pool_id, + Some((Perbill::from_percent(10), root)) + )); + + // When: + assert_ok!(Pools::set_commission( + RuntimeOrigin::signed(root), + pool_id, + Some((Perbill::from_percent(10), payee)) + )); + + // Then: + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::PoolMaxCommissionUpdated { + pool_id, + max_commission: Perbill::from_percent(10) + }, + Event::PoolCommissionUpdated { + pool_id, + current: Some((Perbill::from_percent(10), root)) + }, + Event::PoolCommissionUpdated { + pool_id, + current: Some((Perbill::from_percent(10), payee)) + } + ] + ); + }); + } + + #[test] + fn commission_reward_counter_works_one_member() { + ExtBuilder::default().build_and_execute(|| { + let pool_id = 1; + let root = 900; + let member = 10; + + // Set the pool commission to 10% to test commission shares. Pool is topped up 40 points + // and `member` immediately claims their pending rewards. Reward pooll should still have + // 10% share. + + // Given: + assert_ok!(Pools::set_commission( + RuntimeOrigin::signed(root), + 1, + Some((Perbill::from_percent(10), root)), + )); + assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 40)); + + // When: + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); + + // Then: + assert_eq!(RewardPool::::current_balance(pool_id), 4); + + // Set pool commission to 20% and repeat the same process. + + // When: + assert_ok!(Pools::set_commission( + RuntimeOrigin::signed(root), + 1, + Some((Perbill::from_percent(20), root)), + )); + + // Then: + assert_eq!( + RewardPools::::get(pool_id).unwrap(), + RewardPool { + last_recorded_reward_counter: FixedU128::from_float(3.6), + last_recorded_total_payouts: 40, + total_rewards_claimed: 36, + total_commission_pending: 4, + total_commission_claimed: 0 + } + ); + + // The current reward counter should yield the correct pending rewards of zero. + + // Given: + let (current_reward_counter, _) = RewardPools::::get(pool_id) + .unwrap() + .current_reward_counter( + pool_id, + BondedPools::::get(pool_id).unwrap().points, + Perbill::from_percent(20), + ) + .unwrap(); + + // Then: + assert_eq!( + PoolMembers::::get(member) + .unwrap() + .pending_rewards(current_reward_counter) + .unwrap(), + 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::PoolCommissionUpdated { + pool_id: 1, + current: Some((Perbill::from_percent(10), 900)) + }, + Event::PaidOut { member: 10, pool_id: 1, payout: 36 }, + Event::PoolCommissionUpdated { + pool_id: 1, + current: Some((Perbill::from_percent(20), 900)) + } + ] + ); + }) + } + + #[test] + fn set_commission_handles_errors() { + ExtBuilder::default().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: 10, joined: true }, + ] + ); + + // Provided pool does not exist. + assert_noop!( + Pools::set_commission( + RuntimeOrigin::signed(900), + 9999, + Some((Perbill::from_percent(1), 900)), + ), + Error::::PoolNotFound + ); + + // Sender does not have permission to set commission. + assert_noop!( + Pools::set_commission( + RuntimeOrigin::signed(1), + 1, + Some((Perbill::from_percent(5), 900)), + ), + Error::::DoesNotHavePermission + ); + + // Commission increases will be throttled if outside of change_rate allowance. + // Commission is set to 5%. + // Change rate is set to 1% max increase, 2 block delay. + + // When: + assert_ok!(Pools::set_commission( + RuntimeOrigin::signed(900), + 1, + Some((Perbill::from_percent(5), 900)), + )); + assert_ok!(Pools::set_commission_change_rate( + RuntimeOrigin::signed(900), + 1, + CommissionChangeRate { max_increase: Perbill::from_percent(1), min_delay: 2_u64 } + )); + assert_eq!( + BondedPool::::get(1).unwrap().commission, + Commission { + current: Some((Perbill::from_percent(5), 900)), + max: None, + change_rate: Some(CommissionChangeRate { + max_increase: Perbill::from_percent(1), + min_delay: 2_u64 + }), + throttle_from: Some(1_u64), + } + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::PoolCommissionUpdated { + pool_id: 1, + current: Some((Perbill::from_percent(5), 900)) + }, + Event::PoolCommissionChangeRateUpdated { + pool_id: 1, + change_rate: CommissionChangeRate { + max_increase: Perbill::from_percent(1), + min_delay: 2 + } + } + ] + ); + + // Now try to increase commission to 10% (5% increase). This should be throttled. + // Then: + assert_noop!( + Pools::set_commission( + RuntimeOrigin::signed(900), + 1, + Some((Perbill::from_percent(10), 900)) + ), + Error::::CommissionChangeThrottled + ); + + run_blocks(2); + + // Increase commission by 1% and provide an initial payee. This should succeed and set + // the `throttle_from` field. + + // When: + assert_ok!(Pools::set_commission( + RuntimeOrigin::signed(900), + 1, + Some((Perbill::from_percent(6), 900)) + )); + assert_eq!( + BondedPool::::get(1).unwrap().commission, + Commission { + current: Some((Perbill::from_percent(6), 900)), + max: None, + change_rate: Some(CommissionChangeRate { + max_increase: Perbill::from_percent(1), + min_delay: 2_u64 + }), + throttle_from: Some(3_u64), + } + ); + assert_eq!( + pool_events_since_last_call(), + vec![Event::PoolCommissionUpdated { + pool_id: 1, + current: Some((Perbill::from_percent(6), 900)) + },] + ); + + // Attempt to increase the commission an additional 1% (now 7%). This will fail as + // `throttle_from` is now the current block. At least 2 blocks need to pass before we + // can set commission again. + + // Then: + assert_noop!( + Pools::set_commission( + RuntimeOrigin::signed(900), + 1, + Some((Perbill::from_percent(7), 900)) + ), + Error::::CommissionChangeThrottled + ); + + run_blocks(2); + + // Can now successfully increase the commission again, to 7%. + + // When: + assert_ok!(Pools::set_commission( + RuntimeOrigin::signed(900), + 1, + Some((Perbill::from_percent(7), 900)), + )); + assert_eq!( + pool_events_since_last_call(), + vec![Event::PoolCommissionUpdated { + pool_id: 1, + current: Some((Perbill::from_percent(7), 900)) + },] + ); + + run_blocks(2); + + // Now surpassed the `min_delay` threshold, but the `max_increase` threshold is + // still at play. An attempted commission change now to 8% (+2% increase) should fail. + + // Then: + assert_noop!( + Pools::set_commission( + RuntimeOrigin::signed(900), + 1, + Some((Perbill::from_percent(9), 900)), + ), + Error::::CommissionChangeThrottled + ); + + // Now set a max commission to the current 5%. This will also update the current + // commission to 5%. + + // When: + assert_ok!(Pools::set_commission_max( + RuntimeOrigin::signed(900), + 1, + Perbill::from_percent(5) + )); + assert_eq!( + BondedPool::::get(1).unwrap().commission, + Commission { + current: Some((Perbill::from_percent(5), 900)), + max: Some(Perbill::from_percent(5)), + change_rate: Some(CommissionChangeRate { + max_increase: Perbill::from_percent(1), + min_delay: 2 + }), + throttle_from: Some(7) + } + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::PoolCommissionUpdated { + pool_id: 1, + current: Some((Perbill::from_percent(5), 900)) + }, + Event::PoolMaxCommissionUpdated { + pool_id: 1, + max_commission: Perbill::from_percent(5) + } + ] + ); + + // Run 2 blocks into the future so we are eligible to update commission again. + run_blocks(2); + + // Now attempt again to increase the commission by 1%, to 6%. This is within the change + // rate allowance, but `max_commission` will now prevent us from going any higher. + + // Then: + assert_noop!( + Pools::set_commission( + RuntimeOrigin::signed(900), + 1, + Some((Perbill::from_percent(6), 900)), + ), + Error::::CommissionExceedsMaximum + ); + }); + } + + #[test] + fn set_commission_max_works_with_error_tests() { + ExtBuilder::default().build_and_execute(|| { + // Provided pool does not exist + assert_noop!( + Pools::set_commission_max( + RuntimeOrigin::signed(900), + 9999, + Perbill::from_percent(1) + ), + Error::::PoolNotFound + ); + // Sender does not have permission to set commission + assert_noop!( + Pools::set_commission_max(RuntimeOrigin::signed(1), 1, Perbill::from_percent(5)), + Error::::DoesNotHavePermission + ); + + // Set a max commission commission pool 1 to 80% + assert_ok!(Pools::set_commission_max( + RuntimeOrigin::signed(900), + 1, + Perbill::from_percent(80) + )); + assert_eq!( + BondedPools::::get(1).unwrap().commission.max, + Some(Perbill::from_percent(80)) + ); + + // We attempt to increase the max commission to 90%, but increasing is + // disallowed due to pool's max commission. + assert_noop!( + Pools::set_commission_max(RuntimeOrigin::signed(900), 1, Perbill::from_percent(90)), + Error::::MaxCommissionRestricted + ); + + // We will now set a commission to 75% and then amend the max commission + // to 50%. The max commission change should decrease the current + // commission to 50%. + assert_ok!(Pools::set_commission( + RuntimeOrigin::signed(900), + 1, + Some((Perbill::from_percent(75), 900)) + )); + assert_ok!(Pools::set_commission_max( + RuntimeOrigin::signed(900), + 1, + Perbill::from_percent(50) + )); + assert_eq!( + BondedPools::::get(1).unwrap().commission, + Commission { + current: Some((Perbill::from_percent(50), 900)), + max: Some(Perbill::from_percent(50)), + change_rate: None, + throttle_from: Some(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::PoolMaxCommissionUpdated { + pool_id: 1, + max_commission: Perbill::from_percent(80) + }, + Event::PoolCommissionUpdated { + pool_id: 1, + current: Some((Perbill::from_percent(75), 900)) + }, + Event::PoolCommissionUpdated { + pool_id: 1, + current: Some((Perbill::from_percent(50), 900)) + }, + Event::PoolMaxCommissionUpdated { + pool_id: 1, + max_commission: Perbill::from_percent(50) + } + ] + ); + }); + } + + #[test] + fn set_commission_change_rate_works_with_errors() { + ExtBuilder::default().build_and_execute(|| { + // Provided pool does not exist + assert_noop!( + Pools::set_commission_change_rate( + RuntimeOrigin::signed(900), + 9999, + CommissionChangeRate { + max_increase: Perbill::from_percent(5), + min_delay: 1000_u64 + } + ), + Error::::PoolNotFound + ); + // Sender does not have permission to set commission + assert_noop!( + Pools::set_commission_change_rate( + RuntimeOrigin::signed(1), + 1, + CommissionChangeRate { + max_increase: Perbill::from_percent(5), + min_delay: 1000_u64 + } + ), + Error::::DoesNotHavePermission + ); + + // Set a commission change rate for pool 1 + assert_ok!(Pools::set_commission_change_rate( + RuntimeOrigin::signed(900), + 1, + CommissionChangeRate { max_increase: Perbill::from_percent(5), min_delay: 10_u64 } + )); + assert_eq!( + BondedPools::::get(1).unwrap().commission.change_rate, + Some(CommissionChangeRate { + max_increase: Perbill::from_percent(5), + min_delay: 10_u64 + }) + ); + 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::PoolCommissionChangeRateUpdated { + pool_id: 1, + change_rate: CommissionChangeRate { + max_increase: Perbill::from_percent(5), + min_delay: 10 + } + }, + ] + ); + + // We now try to half the min_delay - this will be disallowed. A greater delay between + // commission changes is seen as more restrictive. + assert_noop!( + Pools::set_commission_change_rate( + RuntimeOrigin::signed(900), + 1, + CommissionChangeRate { + max_increase: Perbill::from_percent(5), + min_delay: 5_u64 + } + ), + Error::::CommissionChangeRateNotAllowed + ); + + // We now try to increase the allowed max_increase - this will fail. A smaller allowed + // commission change is seen as more restrictive. + assert_noop!( + Pools::set_commission_change_rate( + RuntimeOrigin::signed(900), + 1, + CommissionChangeRate { + max_increase: Perbill::from_percent(10), + min_delay: 10_u64 + } + ), + Error::::CommissionChangeRateNotAllowed + ); + + // Successful more restrictive change of min_delay with the current max_increase + assert_ok!(Pools::set_commission_change_rate( + RuntimeOrigin::signed(900), + 1, + CommissionChangeRate { max_increase: Perbill::from_percent(5), min_delay: 20_u64 } + )); + + // Successful more restrictive change of max_increase with the current min_delay + assert_ok!(Pools::set_commission_change_rate( + RuntimeOrigin::signed(900), + 1, + CommissionChangeRate { max_increase: Perbill::from_percent(4), min_delay: 20_u64 } + )); + + // Successful more restrictive change of both max_increase and min_delay + assert_ok!(Pools::set_commission_change_rate( + RuntimeOrigin::signed(900), + 1, + CommissionChangeRate { max_increase: Perbill::from_percent(3), min_delay: 30_u64 } + )); + + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::PoolCommissionChangeRateUpdated { + pool_id: 1, + change_rate: CommissionChangeRate { + max_increase: Perbill::from_percent(5), + min_delay: 20 + } + }, + Event::PoolCommissionChangeRateUpdated { + pool_id: 1, + change_rate: CommissionChangeRate { + max_increase: Perbill::from_percent(4), + min_delay: 20 + } + }, + Event::PoolCommissionChangeRateUpdated { + pool_id: 1, + change_rate: CommissionChangeRate { + max_increase: Perbill::from_percent(3), + min_delay: 30 + } + } + ] + ); + }); + } + + #[test] + fn change_rate_does_not_apply_to_decreasing_commission() { + ExtBuilder::default().build_and_execute(|| { + // set initial commission of the pool to 10%. + assert_ok!(Pools::set_commission( + RuntimeOrigin::signed(900), + 1, + Some((Perbill::from_percent(10), 900)) + )); + + // Set a commission change rate for pool 1, 1% every 10 blocks + assert_ok!(Pools::set_commission_change_rate( + RuntimeOrigin::signed(900), + 1, + CommissionChangeRate { max_increase: Perbill::from_percent(1), min_delay: 10_u64 } + )); + assert_eq!( + BondedPools::::get(1).unwrap().commission.change_rate, + Some(CommissionChangeRate { + max_increase: Perbill::from_percent(1), + min_delay: 10_u64 + }) + ); + + // run `min_delay` blocks to allow a commission update. + run_blocks(10_u64); + + // Test `max_increase`: attempt to decrease the commission by 5%. Should succeed. + assert_ok!(Pools::set_commission( + RuntimeOrigin::signed(900), + 1, + Some((Perbill::from_percent(5), 900)) + )); + + // Test `min_delay`: *immediately* attempt to decrease the commission by 2%. Should + // succeed. + assert_ok!(Pools::set_commission( + RuntimeOrigin::signed(900), + 1, + Some((Perbill::from_percent(3), 900)) + )); + + // Attempt to *increase* the commission by 5%. Should fail. + assert_noop!( + Pools::set_commission( + RuntimeOrigin::signed(900), + 1, + Some((Perbill::from_percent(8), 900)) + ), + Error::::CommissionChangeThrottled + ); + + // Sanity check: the resulting pool Commission state. + assert_eq!( + BondedPools::::get(1).unwrap().commission, + Commission { + current: Some((Perbill::from_percent(3), 900)), + max: None, + change_rate: Some(CommissionChangeRate { + max_increase: Perbill::from_percent(1), + min_delay: 10_u64 + }), + throttle_from: Some(11), + } + ); + + 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::PoolCommissionUpdated { + pool_id: 1, + current: Some((Perbill::from_percent(10), 900)) + }, + Event::PoolCommissionChangeRateUpdated { + pool_id: 1, + change_rate: CommissionChangeRate { + max_increase: Perbill::from_percent(1), + min_delay: 10 + } + }, + Event::PoolCommissionUpdated { + pool_id: 1, + current: Some((Perbill::from_percent(5), 900)) + }, + Event::PoolCommissionUpdated { + pool_id: 1, + current: Some((Perbill::from_percent(3), 900)) + } + ] + ); + }); + } + + #[test] + fn set_commission_max_to_zero_works() { + ExtBuilder::default().build_and_execute(|| { + // 0% max commission test. + // set commission max 0%. + assert_ok!(Pools::set_commission_max(RuntimeOrigin::signed(900), 1, Zero::zero())); + + // a max commission of 0% essentially freezes the current commission, even when None. + // All commission update attempts will fail. + assert_noop!( + Pools::set_commission( + RuntimeOrigin::signed(900), + 1, + Some((Perbill::from_percent(1), 900)) + ), + Error::::CommissionExceedsMaximum + ); + }) + } + + #[test] + fn set_commission_change_rate_zero_max_increase_works() { + ExtBuilder::default().build_and_execute(|| { + // set commission change rate to 0% per 10 blocks + assert_ok!(Pools::set_commission_change_rate( + RuntimeOrigin::signed(900), + 1, + CommissionChangeRate { max_increase: Perbill::from_percent(0), min_delay: 10_u64 } + )); + + // even though there is a min delay of 10 blocks, a max increase of 0% essentially + // freezes the commission. All commission update attempts will fail. + assert_noop!( + Pools::set_commission( + RuntimeOrigin::signed(900), + 1, + Some((Perbill::from_percent(1), 900)) + ), + Error::::CommissionChangeThrottled + ); + }) + } + + #[test] + fn set_commission_change_rate_zero_min_delay_works() { + ExtBuilder::default().build_and_execute(|| { + // set commission change rate to 1% with a 0 block `min_delay`. + assert_ok!(Pools::set_commission_change_rate( + RuntimeOrigin::signed(900), + 1, + CommissionChangeRate { max_increase: Perbill::from_percent(1), min_delay: 0_u64 } + )); + assert_eq!( + BondedPools::::get(1).unwrap().commission, + Commission { + current: None, + max: None, + change_rate: Some(CommissionChangeRate { + max_increase: Perbill::from_percent(1), + min_delay: 0 + }), + throttle_from: Some(1) + } + ); + + // since there is no min delay, we should be able to immediately set the commission. + assert_ok!(Pools::set_commission( + RuntimeOrigin::signed(900), + 1, + Some((Perbill::from_percent(1), 900)) + )); + + // sanity check: increasing again to more than +1% will fail. + assert_noop!( + Pools::set_commission( + RuntimeOrigin::signed(900), + 1, + Some((Perbill::from_percent(3), 900)) + ), + Error::::CommissionChangeThrottled + ); + }) + } + + #[test] + fn set_commission_change_rate_zero_value_works() { + ExtBuilder::default().build_and_execute(|| { + // Check zero values play nice. 0 `min_delay` and 0% max_increase test. + // set commission change rate to 0% per 0 blocks. + assert_ok!(Pools::set_commission_change_rate( + RuntimeOrigin::signed(900), + 1, + CommissionChangeRate { max_increase: Perbill::from_percent(0), min_delay: 0_u64 } + )); + + // even though there is no min delay, a max increase of 0% essentially freezes the + // commission. All commission update attempts will fail. + assert_noop!( + Pools::set_commission( + RuntimeOrigin::signed(900), + 1, + Some((Perbill::from_percent(1), 900)) + ), + Error::::CommissionChangeThrottled + ); + + 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::PoolCommissionChangeRateUpdated { + pool_id: 1, + change_rate: CommissionChangeRate { + max_increase: Perbill::from_percent(0), + min_delay: 0_u64 + } + } + ] + ); + }) + } + + #[test] + fn do_reward_payout_with_various_commissions() { + ExtBuilder::default().build_and_execute(|| { + // turn off GlobalMaxCommission for this test. + GlobalMaxCommission::::set(None); + let pool_id = 1; + + // top up commission payee account to existential deposit + let _ = Balances::deposit_creating(&2, 5); + + // Set a commission pool 1 to 33%, with a payee set to `2` + assert_ok!(Pools::set_commission( + RuntimeOrigin::signed(900), + pool_id, + Some((Perbill::from_percent(33), 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::PoolCommissionUpdated { + pool_id: 1, + current: Some((Perbill::from_percent(33), 2)) + }, + ] + ); + + // The pool earns 10 points + assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 10)); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); + + // Then: + assert_eq!( + pool_events_since_last_call(), + vec![Event::PaidOut { member: 10, pool_id: 1, payout: 7 },] + ); + + // The pool earns 17 points + assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 17)); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); + + // Then: + assert_eq!( + pool_events_since_last_call(), + vec![Event::PaidOut { member: 10, pool_id: 1, payout: 11 },] + ); + + // The pool earns 50 points + assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 50)); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); + + // Then: + assert_eq!( + pool_events_since_last_call(), + vec![Event::PaidOut { member: 10, pool_id: 1, payout: 34 },] + ); + + // The pool earns 10439 points + assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 10439)); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); + + // Then: + assert_eq!( + pool_events_since_last_call(), + vec![Event::PaidOut { member: 10, pool_id: 1, payout: 6994 },] + ); + + // Set the commission to 100% and ensure the following payout to the pool member will + // not happen. + + // When: + assert_ok!(Pools::set_commission( + RuntimeOrigin::signed(900), + pool_id, + Some((Perbill::from_percent(100), 2)), + )); + + // Given: + assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 200)); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); + + // Then: + assert_eq!( + pool_events_since_last_call(), + vec![Event::PoolCommissionUpdated { + pool_id: 1, + current: Some((Perbill::from_percent(100), 2)) + },] + ); + }) + } + + #[test] + fn commission_accumulates_on_multiple_rewards() { + ExtBuilder::default().build_and_execute(|| { + let pool_id = 1; + + // Given: + + // Set initial commission of pool 1 to 10%. + assert_ok!(Pools::set_commission( + RuntimeOrigin::signed(900), + pool_id, + Some((Perbill::from_percent(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 }, + Event::PoolCommissionUpdated { + pool_id: 1, + current: Some((Perbill::from_percent(10), 2)) + }, + ] + ); + + // When: + + // The pool earns 100 points + assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 100)); + + // Change commission to 20% + assert_ok!(Pools::set_commission( + RuntimeOrigin::signed(900), + pool_id, + Some((Perbill::from_percent(20), 2)), + )); + assert_eq!( + pool_events_since_last_call(), + vec![Event::PoolCommissionUpdated { + pool_id: 1, + current: Some((Perbill::from_percent(20), 2)) + },] + ); + + // The pool earns 100 points + assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 100)); + + // Then: + + // Claim payout: + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); + + // Claim commission: + assert_ok!(Pools::claim_commission(RuntimeOrigin::signed(900), pool_id)); + + // Then: + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::PaidOut { member: 10, pool_id: 1, payout: 90 + 80 }, + Event::PoolCommissionClaimed { pool_id: 1, commission: 30 } + ] + ); + }) + } + + #[test] + fn last_recorded_total_payouts_needs_commission() { + ExtBuilder::default().build_and_execute(|| { + let pool_id = 1; + + // Given: + + // Set initial commission of pool 1 to 10%. + assert_ok!(Pools::set_commission( + RuntimeOrigin::signed(900), + pool_id, + Some((Perbill::from_percent(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 }, + Event::PoolCommissionUpdated { + pool_id: 1, + current: Some((Perbill::from_percent(10), 2)) + }, + ] + ); + + // When: + + // The pool earns 100 points + assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 100)); + + // Claim payout: + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); + + // Claim commission: + assert_ok!(Pools::claim_commission(RuntimeOrigin::signed(900), pool_id)); + + // Then: + + assert_eq!( + RewardPools::::get(1).unwrap().last_recorded_total_payouts, + 90 + 10 + ); + + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::PaidOut { member: 10, pool_id: 1, payout: 90 }, + Event::PoolCommissionClaimed { pool_id: 1, commission: 10 } + ] + ); + }) + } + + #[test] + fn do_reward_payout_with_100_percent_commission() { + ExtBuilder::default().build_and_execute(|| { + // turn off GlobalMaxCommission for this test. + GlobalMaxCommission::::set(None); + + let (mut member, bonded_pool, mut reward_pool) = + Pools::get_member_with_pools(&10).unwrap(); + + // top up commission payee account to existential deposit + let _ = Balances::deposit_creating(&2, 5); + + // Set a commission pool 1 to 100%, with a payee set to `2` + assert_ok!(Pools::set_commission( + RuntimeOrigin::signed(900), + bonded_pool.id, + Some((Perbill::from_percent(100), 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::PoolCommissionUpdated { + pool_id: 1, + current: Some((Perbill::from_percent(100), 2)) + } + ] + ); + + // The pool earns 10 points + assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 10)); + + // execute the payout + assert_ok!(Pools::do_reward_payout( + &10, + &mut member, + &mut BondedPool::::get(1).unwrap(), + &mut reward_pool + )); + }) + } + + #[test] + fn global_max_prevents_100_percent_commission_payout() { + ExtBuilder::default().build_and_execute(|| { + // Note: GlobalMaxCommission is set at 90%. + + let (mut member, bonded_pool, mut reward_pool) = + Pools::get_member_with_pools(&10).unwrap(); + + // top up the commission payee account to existential deposit + let _ = Balances::deposit_creating(&2, 5); + + // Set a commission pool 1 to 100%, with a payee set to `2` + assert_ok!(Pools::set_commission( + RuntimeOrigin::signed(900), + bonded_pool.id, + Some((Perbill::from_percent(100), 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::PoolCommissionUpdated { + pool_id: 1, + current: Some((Perbill::from_percent(100), 2)) + } + ] + ); + + // The pool earns 10 points + assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 10)); + + // execute the payout + assert_ok!(Pools::do_reward_payout( + &10, + &mut member, + &mut BondedPool::::get(1).unwrap(), + &mut reward_pool + )); + + // Confirm the commission was only 9 points out of 10 points, and the payout was 1 out + // of 10 points, reflecting the 90% global max commission. + assert_eq!( + pool_events_since_last_call(), + vec![Event::PaidOut { member: 10, pool_id: 1, payout: 1 },] + ); + }) + } + + #[test] + fn claim_commission_works() { + ExtBuilder::default().build_and_execute(|| { + let pool_id = 1; + + let _ = Balances::deposit_creating(&900, 5); + assert_ok!(Pools::set_commission( + RuntimeOrigin::signed(900), + pool_id, + Some((Perbill::from_percent(50), 900)) + )); + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Created { depositor: 10, pool_id }, + Event::Bonded { member: 10, pool_id, bonded: 10, joined: true }, + Event::PoolCommissionUpdated { + pool_id, + current: Some((Perbill::from_percent(50), 900)) + }, + ] + ); + + // Pool earns 80 points, payout is triggered. + assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 80)); + assert_eq!( + PoolMembers::::get(10).unwrap(), + PoolMember:: { pool_id, points: 10, ..Default::default() } + ); + + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); + assert_eq!( + pool_events_since_last_call(), + vec![Event::PaidOut { member: 10, pool_id, payout: 40 }] + ); + + // Given: + assert_eq!(RewardPool::::current_balance(pool_id), 40); + + // Pool does not exist + assert_noop!( + Pools::claim_commission(RuntimeOrigin::signed(900), 9999,), + Error::::PoolNotFound + ); + + // Does not have permission. + assert_noop!( + Pools::claim_commission(RuntimeOrigin::signed(10), pool_id,), + Error::::DoesNotHavePermission + ); + + // When: + assert_ok!(Pools::claim_commission(RuntimeOrigin::signed(900), pool_id)); + + // Then: + assert_eq!(RewardPool::::current_balance(pool_id), 0); + + // No more pending commission. + assert_noop!( + Pools::claim_commission(RuntimeOrigin::signed(900), pool_id,), + Error::::NoPendingCommission + ); + }) + } +} diff --git a/frame/nomination-pools/src/weights.rs b/frame/nomination-pools/src/weights.rs index ca7de7be6e7c6..cf0048fa48dd9 100644 --- a/frame/nomination-pools/src/weights.rs +++ b/frame/nomination-pools/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_nomination_pools //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-ehxwxxsd-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! 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: @@ -33,7 +33,7 @@ // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --json-file=/builds/parity/mirrors/substrate/.git/.artifacts/bench.json +// --json-file=/var/lib/gitlab-runner/builds/zyw4fam_/0/parity/mirrors/substrate/.git/.artifacts/bench.json // --pallet=pallet_nomination_pools // --chain=dev // --header=./HEADER-APACHE2 @@ -64,7 +64,11 @@ pub trait WeightInfo { fn set_configs() -> Weight; fn update_roles() -> Weight; fn chill() -> Weight; + fn set_commission() -> Weight; + fn set_commission_max() -> Weight; + fn set_commission_change_rate() -> Weight; fn set_claim_permission() -> Weight; + fn claim_commission() -> Weight; } /// Weights for pallet_nomination_pools using the Substrate node and recommended hardware. @@ -75,13 +79,15 @@ impl WeightInfo for SubstrateWeight { /// Storage: NominationPools PoolMembers (r:1 w:1) /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(237), added: 2712, mode: MaxEncodedLen) /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) /// Storage: Staking Bonded (r:1 w:0) /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) /// Storage: Staking Ledger (r:1 w:1) /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(60), added: 2535, mode: MaxEncodedLen) + /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) + /// Storage: NominationPools GlobalMaxCommission (r:1 w:0) + /// Proof: NominationPools GlobalMaxCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: System Account (r:2 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: NominationPools MaxPoolMembersPerPool (r:1 w:0) @@ -98,20 +104,21 @@ impl WeightInfo for SubstrateWeight { /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) fn join() -> Weight { // Proof Size summary in bytes: - // Measured: `3573` - // Estimated: `37988` - // Minimum execution time: 169_857 nanoseconds. - Weight::from_parts(173_895_000, 0) - .saturating_add(Weight::from_parts(0, 37988)) - .saturating_add(T::DbWeight::get().reads(17_u64)) + // Measured: `3650` + // Estimated: `52435` + // Minimum execution time: 160_401_000 picoseconds. + Weight::from_parts(161_798_000, 52435) + .saturating_add(T::DbWeight::get().reads(18_u64)) .saturating_add(T::DbWeight::get().writes(12_u64)) } /// Storage: NominationPools PoolMembers (r:1 w:1) /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(237), added: 2712, mode: MaxEncodedLen) /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(60), added: 2535, mode: MaxEncodedLen) + /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) + /// Storage: NominationPools GlobalMaxCommission (r:1 w:0) + /// Proof: NominationPools GlobalMaxCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: System Account (r:3 w:2) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: Staking Bonded (r:1 w:0) @@ -126,12 +133,11 @@ impl WeightInfo for SubstrateWeight { /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) fn bond_extra_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `3615` - // Estimated: `38583` - // Minimum execution time: 167_372 nanoseconds. - Weight::from_parts(168_776_000, 0) - .saturating_add(Weight::from_parts(0, 38583)) - .saturating_add(T::DbWeight::get().reads(14_u64)) + // Measured: `3692` + // Estimated: `49070` + // Minimum execution time: 157_668_000 picoseconds. + Weight::from_parts(161_129_000, 49070) + .saturating_add(T::DbWeight::get().reads(15_u64)) .saturating_add(T::DbWeight::get().writes(12_u64)) } /// Storage: NominationPools ClaimPermissions (r:1 w:0) @@ -139,9 +145,11 @@ impl WeightInfo for SubstrateWeight { /// Storage: NominationPools PoolMembers (r:1 w:1) /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(237), added: 2712, mode: MaxEncodedLen) /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(60), added: 2535, mode: MaxEncodedLen) + /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) + /// Storage: NominationPools GlobalMaxCommission (r:1 w:0) + /// Proof: NominationPools GlobalMaxCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: System Account (r:3 w:3) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: Staking Bonded (r:1 w:0) @@ -156,12 +164,11 @@ impl WeightInfo for SubstrateWeight { /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) fn bond_extra_other() -> Weight { // Proof Size summary in bytes: - // Measured: `3680` - // Estimated: `41099` - // Minimum execution time: 186_346 nanoseconds. - Weight::from_parts(191_308_000, 0) - .saturating_add(Weight::from_parts(0, 41099)) - .saturating_add(T::DbWeight::get().reads(15_u64)) + // Measured: `3757` + // Estimated: `52576` + // Minimum execution time: 176_034_000 picoseconds. + Weight::from_parts(176_956_000, 52576) + .saturating_add(T::DbWeight::get().reads(16_u64)) .saturating_add(T::DbWeight::get().writes(13_u64)) } /// Storage: NominationPools ClaimPermissions (r:1 w:0) @@ -169,31 +176,34 @@ impl WeightInfo for SubstrateWeight { /// Storage: NominationPools PoolMembers (r:1 w:1) /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(237), added: 2712, mode: MaxEncodedLen) /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(60), added: 2535, mode: MaxEncodedLen) + /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) + /// Storage: NominationPools GlobalMaxCommission (r:1 w:0) + /// Proof: NominationPools GlobalMaxCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: System Account (r:1 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn claim_payout() -> Weight { // Proof Size summary in bytes: - // Measured: `1254` - // Estimated: `13005` - // Minimum execution time: 61_423 nanoseconds. - Weight::from_parts(63_219_000, 0) - .saturating_add(Weight::from_parts(0, 13005)) - .saturating_add(T::DbWeight::get().reads(5_u64)) + // Measured: `1331` + // Estimated: `19532` + // Minimum execution time: 61_551_000 picoseconds. + Weight::from_parts(62_201_000, 19532) + .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } /// Storage: NominationPools PoolMembers (r:1 w:1) /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(237), added: 2712, mode: MaxEncodedLen) /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(60), added: 2535, mode: MaxEncodedLen) + /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) /// Storage: Staking Bonded (r:1 w:0) /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) /// Storage: Staking Ledger (r:1 w:1) /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: NominationPools GlobalMaxCommission (r:1 w:0) + /// Proof: NominationPools GlobalMaxCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: System Account (r:2 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: Staking CurrentEra (r:1 w:0) @@ -212,20 +222,17 @@ impl WeightInfo for SubstrateWeight { /// Proof: NominationPools SubPoolsStorage (max_values: None, max_size: Some(24382), added: 26857, mode: MaxEncodedLen) /// Storage: NominationPools CounterForSubPoolsStorage (r:1 w:1) /// Proof: NominationPools CounterForSubPoolsStorage (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools ClaimPermissions (r:0 w:1) - /// Proof: NominationPools ClaimPermissions (max_values: None, max_size: Some(41), added: 2516, mode: MaxEncodedLen) fn unbond() -> Weight { // Proof Size summary in bytes: - // Measured: `3858` - // Estimated: `67379` - // Minimum execution time: 174_532 nanoseconds. - Weight::from_parts(180_032_000, 0) - .saturating_add(Weight::from_parts(0, 67379)) - .saturating_add(T::DbWeight::get().reads(18_u64)) - .saturating_add(T::DbWeight::get().writes(14_u64)) + // Measured: `3935` + // Estimated: `82816` + // Minimum execution time: 162_755_000 picoseconds. + Weight::from_parts(163_518_000, 82816) + .saturating_add(T::DbWeight::get().reads(19_u64)) + .saturating_add(T::DbWeight::get().writes(13_u64)) } /// Storage: NominationPools BondedPools (r:1 w:0) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) /// Storage: Staking Bonded (r:1 w:0) /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) /// Storage: Staking Ledger (r:1 w:1) @@ -237,13 +244,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[0, 100]`. fn pool_withdraw_unbonded(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1779` - // Estimated: `13025` - // Minimum execution time: 55_327 nanoseconds. - Weight::from_parts(58_947_746, 0) - .saturating_add(Weight::from_parts(0, 13025)) - // Standard Error: 1_589 - .saturating_add(Weight::from_parts(40_696, 0).saturating_mul(s.into())) + // Measured: `1783` + // Estimated: `18031` + // Minimum execution time: 54_752_000 picoseconds. + Weight::from_parts(56_248_171, 18031) + // Standard Error: 1_891 + .saturating_add(Weight::from_parts(4_767, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -252,7 +258,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: Staking CurrentEra (r:1 w:0) /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) /// Storage: NominationPools SubPoolsStorage (r:1 w:1) /// Proof: NominationPools SubPoolsStorage (max_values: None, max_size: Some(24382), added: 26857, mode: MaxEncodedLen) /// Storage: Staking Bonded (r:1 w:0) @@ -265,25 +271,26 @@ impl WeightInfo for SubstrateWeight { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: NominationPools CounterForPoolMembers (r:1 w:1) /// Proof: NominationPools CounterForPoolMembers (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: NominationPools ClaimPermissions (r:0 w:1) + /// Proof: NominationPools ClaimPermissions (max_values: None, max_size: Some(41), added: 2516, mode: MaxEncodedLen) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2303` - // Estimated: `45696` - // Minimum execution time: 105_923 nanoseconds. - Weight::from_parts(110_572_476, 0) - .saturating_add(Weight::from_parts(0, 45696)) - // Standard Error: 2_438 - .saturating_add(Weight::from_parts(69_045, 0).saturating_mul(s.into())) + // Measured: `2307` + // Estimated: `54662` + // Minimum execution time: 106_166_000 picoseconds. + Weight::from_parts(107_806_373, 54662) + // Standard Error: 6_985 + .saturating_add(Weight::from_parts(18_449, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(9_u64)) - .saturating_add(T::DbWeight::get().writes(7_u64)) + .saturating_add(T::DbWeight::get().writes(8_u64)) } /// Storage: NominationPools PoolMembers (r:1 w:1) /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(237), added: 2712, mode: MaxEncodedLen) /// Storage: Staking CurrentEra (r:1 w:0) /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) /// Storage: NominationPools SubPoolsStorage (r:1 w:1) /// Proof: NominationPools SubPoolsStorage (max_values: None, max_size: Some(24382), added: 26857, mode: MaxEncodedLen) /// Storage: Staking Bonded (r:1 w:1) @@ -307,7 +314,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: NominationPools CounterForReversePoolIdLookup (r:1 w:1) /// Proof: NominationPools CounterForReversePoolIdLookup (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(60), added: 2535, mode: MaxEncodedLen) + /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) /// Storage: NominationPools CounterForRewardPools (r:1 w:1) /// Proof: NominationPools CounterForRewardPools (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: NominationPools CounterForSubPoolsStorage (r:1 w:1) @@ -318,16 +325,19 @@ impl WeightInfo for SubstrateWeight { /// Proof: NominationPools CounterForBondedPools (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: Staking Payee (r:0 w:1) /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: NominationPools ClaimPermissions (r:0 w:1) + /// Proof: NominationPools ClaimPermissions (max_values: None, max_size: Some(41), added: 2516, mode: MaxEncodedLen) /// The range of component `s` is `[0, 100]`. - fn withdraw_unbonded_kill(_s: u32, ) -> Weight { + fn withdraw_unbonded_kill(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2690` - // Estimated: `68812` - // Minimum execution time: 169_700 nanoseconds. - Weight::from_parts(178_693_541, 0) - .saturating_add(Weight::from_parts(0, 68812)) + // Measured: `2694` + // Estimated: `87714` + // Minimum execution time: 170_047_000 picoseconds. + Weight::from_parts(172_125_770, 87714) + // Standard Error: 2_599 + .saturating_add(Weight::from_parts(9_964, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(20_u64)) - .saturating_add(T::DbWeight::get().writes(17_u64)) + .saturating_add(T::DbWeight::get().writes(18_u64)) } /// Storage: NominationPools LastPoolId (r:1 w:1) /// Proof: NominationPools LastPoolId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -360,7 +370,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(60), added: 2535, mode: MaxEncodedLen) + /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) /// Storage: NominationPools CounterForRewardPools (r:1 w:1) /// Proof: NominationPools CounterForRewardPools (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: NominationPools ReversePoolIdLookup (r:1 w:1) @@ -368,21 +378,20 @@ impl WeightInfo for SubstrateWeight { /// Storage: NominationPools CounterForReversePoolIdLookup (r:1 w:1) /// Proof: NominationPools CounterForReversePoolIdLookup (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) /// Storage: Staking Payee (r:0 w:1) /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) fn create() -> Weight { // Proof Size summary in bytes: // Measured: `1321` - // Estimated: `31522` - // Minimum execution time: 145_976 nanoseconds. - Weight::from_parts(150_664_000, 0) - .saturating_add(Weight::from_parts(0, 31522)) + // Estimated: `51410` + // Minimum execution time: 149_672_000 picoseconds. + Weight::from_parts(153_613_000, 51410) .saturating_add(T::DbWeight::get().reads(21_u64)) .saturating_add(T::DbWeight::get().writes(15_u64)) } /// Storage: NominationPools BondedPools (r:1 w:0) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) /// Storage: Staking Bonded (r:1 w:0) /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) /// Storage: Staking Ledger (r:1 w:0) @@ -408,36 +417,34 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1909` - // Estimated: `21998 + n * (2520 ±0)` - // Minimum execution time: 69_288 nanoseconds. - Weight::from_parts(71_075_293, 0) - .saturating_add(Weight::from_parts(0, 21998)) - // Standard Error: 10_508 - .saturating_add(Weight::from_parts(1_384_674, 0).saturating_mul(n.into())) + // Measured: `1913` + // Estimated: `33934 + n * (2520 ±0)` + // Minimum execution time: 68_892_000 picoseconds. + Weight::from_parts(69_062_946, 33934) + // Standard Error: 6_448 + .saturating_add(Weight::from_parts(1_422_774, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(5_u64)) .saturating_add(Weight::from_parts(0, 2520).saturating_mul(n.into())) } /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) /// Storage: Staking Bonded (r:1 w:0) /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) /// Storage: Staking Ledger (r:1 w:0) /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) fn set_state() -> Weight { // Proof Size summary in bytes: - // Measured: `1498` - // Estimated: `8752` - // Minimum execution time: 36_410 nanoseconds. - Weight::from_parts(37_585_000, 0) - .saturating_add(Weight::from_parts(0, 8752)) + // Measured: `1502` + // Estimated: `11778` + // Minimum execution time: 36_447_000 picoseconds. + Weight::from_parts(36_837_000, 11778) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: NominationPools BondedPools (r:1 w:0) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) /// Storage: NominationPools Metadata (r:1 w:1) /// Proof: NominationPools Metadata (max_values: None, max_size: Some(270), added: 2745, mode: MaxEncodedLen) /// Storage: NominationPools CounterForMetadata (r:1 w:1) @@ -445,13 +452,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[1, 256]`. fn set_metadata(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `559` - // Estimated: `5883` - // Minimum execution time: 14_322 nanoseconds. - Weight::from_parts(15_328_204, 0) - .saturating_add(Weight::from_parts(0, 5883)) - // Standard Error: 161 - .saturating_add(Weight::from_parts(1_406, 0).saturating_mul(n.into())) + // Measured: `563` + // Estimated: `8909` + // Minimum execution time: 15_221_000 picoseconds. + Weight::from_parts(15_632_286, 8909) + // Standard Error: 343 + .saturating_add(Weight::from_parts(2_299, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -463,31 +469,31 @@ impl WeightInfo for SubstrateWeight { /// Proof: NominationPools MaxPoolMembersPerPool (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: NominationPools MinCreateBond (r:0 w:1) /// Proof: NominationPools MinCreateBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: NominationPools GlobalMaxCommission (r:0 w:1) + /// Proof: NominationPools GlobalMaxCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: NominationPools MaxPools (r:0 w:1) /// Proof: NominationPools MaxPools (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn set_configs() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_968 nanoseconds. - Weight::from_parts(6_245_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(5_u64)) + // Minimum execution time: 7_409_000 picoseconds. + Weight::from_parts(7_702_000, 0) + .saturating_add(T::DbWeight::get().writes(6_u64)) } /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) fn update_roles() -> Weight { // Proof Size summary in bytes: - // Measured: `559` - // Estimated: `2639` - // Minimum execution time: 18_979 nanoseconds. - Weight::from_parts(19_795_000, 0) - .saturating_add(Weight::from_parts(0, 2639)) + // Measured: `563` + // Estimated: `3685` + // Minimum execution time: 20_451_000 picoseconds. + Weight::from_parts(20_703_000, 3685) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: NominationPools BondedPools (r:1 w:0) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) /// Storage: Staking Bonded (r:1 w:0) /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) /// Storage: Staking Ledger (r:1 w:0) @@ -506,14 +512,52 @@ impl WeightInfo for SubstrateWeight { /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn chill() -> Weight { // Proof Size summary in bytes: - // Measured: `2136` - // Estimated: `20489` - // Minimum execution time: 68_145 nanoseconds. - Weight::from_parts(70_444_000, 0) - .saturating_add(Weight::from_parts(0, 20489)) + // Measured: `2140` + // Estimated: `29455` + // Minimum execution time: 66_001_000 picoseconds. + Weight::from_parts(66_894_000, 29455) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } + /// Storage: NominationPools BondedPools (r:1 w:1) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) + /// Storage: NominationPools RewardPools (r:1 w:1) + /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) + /// Storage: NominationPools GlobalMaxCommission (r:1 w:0) + /// Proof: NominationPools GlobalMaxCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + fn set_commission() -> Weight { + // Proof Size summary in bytes: + // Measured: `866` + // Estimated: `12324` + // Minimum execution time: 34_011_000 picoseconds. + Weight::from_parts(34_521_000, 12324) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: NominationPools BondedPools (r:1 w:1) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) + fn set_commission_max() -> Weight { + // Proof Size summary in bytes: + // Measured: `603` + // Estimated: `3685` + // Minimum execution time: 19_524_000 picoseconds. + Weight::from_parts(19_855_000, 3685) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: NominationPools BondedPools (r:1 w:1) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) + fn set_commission_change_rate() -> Weight { + // Proof Size summary in bytes: + // Measured: `563` + // Estimated: `3685` + // Minimum execution time: 20_457_000 picoseconds. + Weight::from_parts(20_698_000, 3685) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } /// Storage: NominationPools PoolMembers (r:1 w:0) /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(237), added: 2712, mode: MaxEncodedLen) /// Storage: NominationPools ClaimPermissions (r:1 w:1) @@ -521,13 +565,29 @@ impl WeightInfo for SubstrateWeight { fn set_claim_permission() -> Weight { // Proof Size summary in bytes: // Measured: `542` - // Estimated: `5228` - // Minimum execution time: 15_112 nanoseconds. - Weight::from_parts(15_897_000, 0) - .saturating_add(Weight::from_parts(0, 5228)) + // Estimated: `7208` + // Minimum execution time: 15_183_000 picoseconds. + Weight::from_parts(15_597_000, 7208) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } + /// Storage: NominationPools BondedPools (r:1 w:0) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) + /// Storage: NominationPools RewardPools (r:1 w:1) + /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) + /// Storage: NominationPools GlobalMaxCommission (r:1 w:0) + /// Proof: NominationPools GlobalMaxCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + fn claim_commission() -> Weight { + // Proof Size summary in bytes: + // Measured: `1096` + // Estimated: `12324` + // Minimum execution time: 48_957_000 picoseconds. + Weight::from_parts(50_207_000, 12324) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } } // For backwards compatibility and tests @@ -537,13 +597,15 @@ impl WeightInfo for () { /// Storage: NominationPools PoolMembers (r:1 w:1) /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(237), added: 2712, mode: MaxEncodedLen) /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) /// Storage: Staking Bonded (r:1 w:0) /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) /// Storage: Staking Ledger (r:1 w:1) /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(60), added: 2535, mode: MaxEncodedLen) + /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) + /// Storage: NominationPools GlobalMaxCommission (r:1 w:0) + /// Proof: NominationPools GlobalMaxCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: System Account (r:2 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: NominationPools MaxPoolMembersPerPool (r:1 w:0) @@ -560,20 +622,21 @@ impl WeightInfo for () { /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) fn join() -> Weight { // Proof Size summary in bytes: - // Measured: `3573` - // Estimated: `37988` - // Minimum execution time: 169_857 nanoseconds. - Weight::from_parts(173_895_000, 0) - .saturating_add(Weight::from_parts(0, 37988)) - .saturating_add(RocksDbWeight::get().reads(17_u64)) + // Measured: `3650` + // Estimated: `52435` + // Minimum execution time: 160_401_000 picoseconds. + Weight::from_parts(161_798_000, 52435) + .saturating_add(RocksDbWeight::get().reads(18_u64)) .saturating_add(RocksDbWeight::get().writes(12_u64)) } /// Storage: NominationPools PoolMembers (r:1 w:1) /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(237), added: 2712, mode: MaxEncodedLen) /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(60), added: 2535, mode: MaxEncodedLen) + /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) + /// Storage: NominationPools GlobalMaxCommission (r:1 w:0) + /// Proof: NominationPools GlobalMaxCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: System Account (r:3 w:2) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: Staking Bonded (r:1 w:0) @@ -588,12 +651,11 @@ impl WeightInfo for () { /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) fn bond_extra_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `3615` - // Estimated: `38583` - // Minimum execution time: 167_372 nanoseconds. - Weight::from_parts(168_776_000, 0) - .saturating_add(Weight::from_parts(0, 38583)) - .saturating_add(RocksDbWeight::get().reads(14_u64)) + // Measured: `3692` + // Estimated: `49070` + // Minimum execution time: 157_668_000 picoseconds. + Weight::from_parts(161_129_000, 49070) + .saturating_add(RocksDbWeight::get().reads(15_u64)) .saturating_add(RocksDbWeight::get().writes(12_u64)) } /// Storage: NominationPools ClaimPermissions (r:1 w:0) @@ -601,9 +663,11 @@ impl WeightInfo for () { /// Storage: NominationPools PoolMembers (r:1 w:1) /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(237), added: 2712, mode: MaxEncodedLen) /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(60), added: 2535, mode: MaxEncodedLen) + /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) + /// Storage: NominationPools GlobalMaxCommission (r:1 w:0) + /// Proof: NominationPools GlobalMaxCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: System Account (r:3 w:3) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: Staking Bonded (r:1 w:0) @@ -618,12 +682,11 @@ impl WeightInfo for () { /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) fn bond_extra_other() -> Weight { // Proof Size summary in bytes: - // Measured: `3680` - // Estimated: `41099` - // Minimum execution time: 186_346 nanoseconds. - Weight::from_parts(191_308_000, 0) - .saturating_add(Weight::from_parts(0, 41099)) - .saturating_add(RocksDbWeight::get().reads(15_u64)) + // Measured: `3757` + // Estimated: `52576` + // Minimum execution time: 176_034_000 picoseconds. + Weight::from_parts(176_956_000, 52576) + .saturating_add(RocksDbWeight::get().reads(16_u64)) .saturating_add(RocksDbWeight::get().writes(13_u64)) } /// Storage: NominationPools ClaimPermissions (r:1 w:0) @@ -631,31 +694,34 @@ impl WeightInfo for () { /// Storage: NominationPools PoolMembers (r:1 w:1) /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(237), added: 2712, mode: MaxEncodedLen) /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(60), added: 2535, mode: MaxEncodedLen) + /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) + /// Storage: NominationPools GlobalMaxCommission (r:1 w:0) + /// Proof: NominationPools GlobalMaxCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: System Account (r:1 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn claim_payout() -> Weight { // Proof Size summary in bytes: - // Measured: `1254` - // Estimated: `13005` - // Minimum execution time: 61_423 nanoseconds. - Weight::from_parts(63_219_000, 0) - .saturating_add(Weight::from_parts(0, 13005)) - .saturating_add(RocksDbWeight::get().reads(5_u64)) + // Measured: `1331` + // Estimated: `19532` + // Minimum execution time: 61_551_000 picoseconds. + Weight::from_parts(62_201_000, 19532) + .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } /// Storage: NominationPools PoolMembers (r:1 w:1) /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(237), added: 2712, mode: MaxEncodedLen) /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(60), added: 2535, mode: MaxEncodedLen) + /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) /// Storage: Staking Bonded (r:1 w:0) /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) /// Storage: Staking Ledger (r:1 w:1) /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: NominationPools GlobalMaxCommission (r:1 w:0) + /// Proof: NominationPools GlobalMaxCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: System Account (r:2 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: Staking CurrentEra (r:1 w:0) @@ -674,20 +740,17 @@ impl WeightInfo for () { /// Proof: NominationPools SubPoolsStorage (max_values: None, max_size: Some(24382), added: 26857, mode: MaxEncodedLen) /// Storage: NominationPools CounterForSubPoolsStorage (r:1 w:1) /// Proof: NominationPools CounterForSubPoolsStorage (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: NominationPools ClaimPermissions (r:0 w:1) - /// Proof: NominationPools ClaimPermissions (max_values: None, max_size: Some(41), added: 2516, mode: MaxEncodedLen) fn unbond() -> Weight { // Proof Size summary in bytes: - // Measured: `3858` - // Estimated: `67379` - // Minimum execution time: 174_532 nanoseconds. - Weight::from_parts(180_032_000, 0) - .saturating_add(Weight::from_parts(0, 67379)) - .saturating_add(RocksDbWeight::get().reads(18_u64)) - .saturating_add(RocksDbWeight::get().writes(14_u64)) + // Measured: `3935` + // Estimated: `82816` + // Minimum execution time: 162_755_000 picoseconds. + Weight::from_parts(163_518_000, 82816) + .saturating_add(RocksDbWeight::get().reads(19_u64)) + .saturating_add(RocksDbWeight::get().writes(13_u64)) } /// Storage: NominationPools BondedPools (r:1 w:0) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) /// Storage: Staking Bonded (r:1 w:0) /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) /// Storage: Staking Ledger (r:1 w:1) @@ -699,13 +762,12 @@ impl WeightInfo for () { /// The range of component `s` is `[0, 100]`. fn pool_withdraw_unbonded(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1779` - // Estimated: `13025` - // Minimum execution time: 55_327 nanoseconds. - Weight::from_parts(58_947_746, 0) - .saturating_add(Weight::from_parts(0, 13025)) - // Standard Error: 1_589 - .saturating_add(Weight::from_parts(40_696, 0).saturating_mul(s.into())) + // Measured: `1783` + // Estimated: `18031` + // Minimum execution time: 54_752_000 picoseconds. + Weight::from_parts(56_248_171, 18031) + // Standard Error: 1_891 + .saturating_add(Weight::from_parts(4_767, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -714,7 +776,7 @@ impl WeightInfo for () { /// Storage: Staking CurrentEra (r:1 w:0) /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) /// Storage: NominationPools SubPoolsStorage (r:1 w:1) /// Proof: NominationPools SubPoolsStorage (max_values: None, max_size: Some(24382), added: 26857, mode: MaxEncodedLen) /// Storage: Staking Bonded (r:1 w:0) @@ -727,25 +789,26 @@ impl WeightInfo for () { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: NominationPools CounterForPoolMembers (r:1 w:1) /// Proof: NominationPools CounterForPoolMembers (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: NominationPools ClaimPermissions (r:0 w:1) + /// Proof: NominationPools ClaimPermissions (max_values: None, max_size: Some(41), added: 2516, mode: MaxEncodedLen) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2303` - // Estimated: `45696` - // Minimum execution time: 105_923 nanoseconds. - Weight::from_parts(110_572_476, 0) - .saturating_add(Weight::from_parts(0, 45696)) - // Standard Error: 2_438 - .saturating_add(Weight::from_parts(69_045, 0).saturating_mul(s.into())) + // Measured: `2307` + // Estimated: `54662` + // Minimum execution time: 106_166_000 picoseconds. + Weight::from_parts(107_806_373, 54662) + // Standard Error: 6_985 + .saturating_add(Weight::from_parts(18_449, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(9_u64)) - .saturating_add(RocksDbWeight::get().writes(7_u64)) + .saturating_add(RocksDbWeight::get().writes(8_u64)) } /// Storage: NominationPools PoolMembers (r:1 w:1) /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(237), added: 2712, mode: MaxEncodedLen) /// Storage: Staking CurrentEra (r:1 w:0) /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) /// Storage: NominationPools SubPoolsStorage (r:1 w:1) /// Proof: NominationPools SubPoolsStorage (max_values: None, max_size: Some(24382), added: 26857, mode: MaxEncodedLen) /// Storage: Staking Bonded (r:1 w:1) @@ -769,7 +832,7 @@ impl WeightInfo for () { /// Storage: NominationPools CounterForReversePoolIdLookup (r:1 w:1) /// Proof: NominationPools CounterForReversePoolIdLookup (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(60), added: 2535, mode: MaxEncodedLen) + /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) /// Storage: NominationPools CounterForRewardPools (r:1 w:1) /// Proof: NominationPools CounterForRewardPools (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: NominationPools CounterForSubPoolsStorage (r:1 w:1) @@ -780,16 +843,19 @@ impl WeightInfo for () { /// Proof: NominationPools CounterForBondedPools (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: Staking Payee (r:0 w:1) /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: NominationPools ClaimPermissions (r:0 w:1) + /// Proof: NominationPools ClaimPermissions (max_values: None, max_size: Some(41), added: 2516, mode: MaxEncodedLen) /// The range of component `s` is `[0, 100]`. - fn withdraw_unbonded_kill(_s: u32, ) -> Weight { + fn withdraw_unbonded_kill(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2690` - // Estimated: `68812` - // Minimum execution time: 169_700 nanoseconds. - Weight::from_parts(178_693_541, 0) - .saturating_add(Weight::from_parts(0, 68812)) + // Measured: `2694` + // Estimated: `87714` + // Minimum execution time: 170_047_000 picoseconds. + Weight::from_parts(172_125_770, 87714) + // Standard Error: 2_599 + .saturating_add(Weight::from_parts(9_964, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(20_u64)) - .saturating_add(RocksDbWeight::get().writes(17_u64)) + .saturating_add(RocksDbWeight::get().writes(18_u64)) } /// Storage: NominationPools LastPoolId (r:1 w:1) /// Proof: NominationPools LastPoolId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -822,7 +888,7 @@ impl WeightInfo for () { /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) /// Storage: NominationPools RewardPools (r:1 w:1) - /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(60), added: 2535, mode: MaxEncodedLen) + /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) /// Storage: NominationPools CounterForRewardPools (r:1 w:1) /// Proof: NominationPools CounterForRewardPools (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: NominationPools ReversePoolIdLookup (r:1 w:1) @@ -830,21 +896,20 @@ impl WeightInfo for () { /// Storage: NominationPools CounterForReversePoolIdLookup (r:1 w:1) /// Proof: NominationPools CounterForReversePoolIdLookup (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) /// Storage: Staking Payee (r:0 w:1) /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) fn create() -> Weight { // Proof Size summary in bytes: // Measured: `1321` - // Estimated: `31522` - // Minimum execution time: 145_976 nanoseconds. - Weight::from_parts(150_664_000, 0) - .saturating_add(Weight::from_parts(0, 31522)) + // Estimated: `51410` + // Minimum execution time: 149_672_000 picoseconds. + Weight::from_parts(153_613_000, 51410) .saturating_add(RocksDbWeight::get().reads(21_u64)) .saturating_add(RocksDbWeight::get().writes(15_u64)) } /// Storage: NominationPools BondedPools (r:1 w:0) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) /// Storage: Staking Bonded (r:1 w:0) /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) /// Storage: Staking Ledger (r:1 w:0) @@ -870,36 +935,34 @@ impl WeightInfo for () { /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1909` - // Estimated: `21998 + n * (2520 ±0)` - // Minimum execution time: 69_288 nanoseconds. - Weight::from_parts(71_075_293, 0) - .saturating_add(Weight::from_parts(0, 21998)) - // Standard Error: 10_508 - .saturating_add(Weight::from_parts(1_384_674, 0).saturating_mul(n.into())) + // Measured: `1913` + // Estimated: `33934 + n * (2520 ±0)` + // Minimum execution time: 68_892_000 picoseconds. + Weight::from_parts(69_062_946, 33934) + // Standard Error: 6_448 + .saturating_add(Weight::from_parts(1_422_774, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(5_u64)) .saturating_add(Weight::from_parts(0, 2520).saturating_mul(n.into())) } /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) /// Storage: Staking Bonded (r:1 w:0) /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) /// Storage: Staking Ledger (r:1 w:0) /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) fn set_state() -> Weight { // Proof Size summary in bytes: - // Measured: `1498` - // Estimated: `8752` - // Minimum execution time: 36_410 nanoseconds. - Weight::from_parts(37_585_000, 0) - .saturating_add(Weight::from_parts(0, 8752)) + // Measured: `1502` + // Estimated: `11778` + // Minimum execution time: 36_447_000 picoseconds. + Weight::from_parts(36_837_000, 11778) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: NominationPools BondedPools (r:1 w:0) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) /// Storage: NominationPools Metadata (r:1 w:1) /// Proof: NominationPools Metadata (max_values: None, max_size: Some(270), added: 2745, mode: MaxEncodedLen) /// Storage: NominationPools CounterForMetadata (r:1 w:1) @@ -907,13 +970,12 @@ impl WeightInfo for () { /// The range of component `n` is `[1, 256]`. fn set_metadata(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `559` - // Estimated: `5883` - // Minimum execution time: 14_322 nanoseconds. - Weight::from_parts(15_328_204, 0) - .saturating_add(Weight::from_parts(0, 5883)) - // Standard Error: 161 - .saturating_add(Weight::from_parts(1_406, 0).saturating_mul(n.into())) + // Measured: `563` + // Estimated: `8909` + // Minimum execution time: 15_221_000 picoseconds. + Weight::from_parts(15_632_286, 8909) + // Standard Error: 343 + .saturating_add(Weight::from_parts(2_299, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -925,31 +987,31 @@ impl WeightInfo for () { /// Proof: NominationPools MaxPoolMembersPerPool (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: NominationPools MinCreateBond (r:0 w:1) /// Proof: NominationPools MinCreateBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: NominationPools GlobalMaxCommission (r:0 w:1) + /// Proof: NominationPools GlobalMaxCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: NominationPools MaxPools (r:0 w:1) /// Proof: NominationPools MaxPools (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn set_configs() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_968 nanoseconds. - Weight::from_parts(6_245_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(RocksDbWeight::get().writes(5_u64)) + // Minimum execution time: 7_409_000 picoseconds. + Weight::from_parts(7_702_000, 0) + .saturating_add(RocksDbWeight::get().writes(6_u64)) } /// Storage: NominationPools BondedPools (r:1 w:1) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) fn update_roles() -> Weight { // Proof Size summary in bytes: - // Measured: `559` - // Estimated: `2639` - // Minimum execution time: 18_979 nanoseconds. - Weight::from_parts(19_795_000, 0) - .saturating_add(Weight::from_parts(0, 2639)) + // Measured: `563` + // Estimated: `3685` + // Minimum execution time: 20_451_000 picoseconds. + Weight::from_parts(20_703_000, 3685) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: NominationPools BondedPools (r:1 w:0) - /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(164), added: 2639, mode: MaxEncodedLen) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) /// Storage: Staking Bonded (r:1 w:0) /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) /// Storage: Staking Ledger (r:1 w:0) @@ -968,14 +1030,52 @@ impl WeightInfo for () { /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn chill() -> Weight { // Proof Size summary in bytes: - // Measured: `2136` - // Estimated: `20489` - // Minimum execution time: 68_145 nanoseconds. - Weight::from_parts(70_444_000, 0) - .saturating_add(Weight::from_parts(0, 20489)) + // Measured: `2140` + // Estimated: `29455` + // Minimum execution time: 66_001_000 picoseconds. + Weight::from_parts(66_894_000, 29455) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } + /// Storage: NominationPools BondedPools (r:1 w:1) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) + /// Storage: NominationPools RewardPools (r:1 w:1) + /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) + /// Storage: NominationPools GlobalMaxCommission (r:1 w:0) + /// Proof: NominationPools GlobalMaxCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + fn set_commission() -> Weight { + // Proof Size summary in bytes: + // Measured: `866` + // Estimated: `12324` + // Minimum execution time: 34_011_000 picoseconds. + Weight::from_parts(34_521_000, 12324) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: NominationPools BondedPools (r:1 w:1) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) + fn set_commission_max() -> Weight { + // Proof Size summary in bytes: + // Measured: `603` + // Estimated: `3685` + // Minimum execution time: 19_524_000 picoseconds. + Weight::from_parts(19_855_000, 3685) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: NominationPools BondedPools (r:1 w:1) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) + fn set_commission_change_rate() -> Weight { + // Proof Size summary in bytes: + // Measured: `563` + // Estimated: `3685` + // Minimum execution time: 20_457_000 picoseconds. + Weight::from_parts(20_698_000, 3685) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } /// Storage: NominationPools PoolMembers (r:1 w:0) /// Proof: NominationPools PoolMembers (max_values: None, max_size: Some(237), added: 2712, mode: MaxEncodedLen) /// Storage: NominationPools ClaimPermissions (r:1 w:1) @@ -983,11 +1083,27 @@ impl WeightInfo for () { fn set_claim_permission() -> Weight { // Proof Size summary in bytes: // Measured: `542` - // Estimated: `5228` - // Minimum execution time: 15_112 nanoseconds. - Weight::from_parts(15_897_000, 0) - .saturating_add(Weight::from_parts(0, 5228)) + // Estimated: `7208` + // Minimum execution time: 15_183_000 picoseconds. + Weight::from_parts(15_597_000, 7208) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } + /// Storage: NominationPools BondedPools (r:1 w:0) + /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) + /// Storage: NominationPools RewardPools (r:1 w:1) + /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) + /// Storage: NominationPools GlobalMaxCommission (r:1 w:0) + /// Proof: NominationPools GlobalMaxCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + fn claim_commission() -> Weight { + // Proof Size summary in bytes: + // Measured: `1096` + // Estimated: `12324` + // Minimum execution time: 48_957_000 picoseconds. + Weight::from_parts(50_207_000, 12324) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } } diff --git a/frame/nomination-pools/test-staking/src/mock.rs b/frame/nomination-pools/test-staking/src/mock.rs index 85d0dd6c50677..0550c8e0ca708 100644 --- a/frame/nomination-pools/test-staking/src/mock.rs +++ b/frame/nomination-pools/test-staking/src/mock.rs @@ -25,7 +25,7 @@ use frame_support::{ }; use sp_runtime::{ traits::{Convert, IdentityLookup}, - FixedU128, + FixedU128, Perbill, }; type AccountId = u128; @@ -209,6 +209,7 @@ pub fn new_test_ext() -> sp_io::TestExternalities { max_pools: Some(3), max_members_per_pool: Some(5), max_members: Some(3 * 5), + global_max_commission: Some(Perbill::from_percent(90)), } .assimilate_storage(&mut storage) .unwrap(); From d3fd5432ae6f6fcec87844b6eeb21f80ab4e31eb Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Wed, 15 Mar 2023 10:36:23 -0600 Subject: [PATCH 510/715] Pallet dispatchable+storage doc module. (#13341) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * doc-only pallet * cargo fmt * generics fix for dispatchables * use a module instead * add doc comment warning that the dispatchable functions are generated * clean up * fix typo * hide Instance4-Instance16 from `pallet` module docs * revamp Instance1-16 comment * Document storage types Signed-off-by: Oliver Tale-Yazdi * fmt Signed-off-by: Oliver Tale-Yazdi * remove unused variables * crate::Call => Call Co-authored-by: Bastian Köcher * fix indentation Co-authored-by: Bastian Köcher * remove unneeded block Co-authored-by: Bastian Köcher * don't need a Vec Co-authored-by: Bastian Köcher * add "doc only" to coment Co-authored-by: Bastian Köcher * crate::Call => Call Co-authored-by: Bastian Köcher * cargo fmt --------- Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Sam Johnson Co-authored-by: Oliver Tale-Yazdi Co-authored-by: Bastian Köcher Co-authored-by: parity-processbot <> --- .../procedural/src/pallet/expand/doc_only.rs | 79 +++++++++++++++++++ .../procedural/src/pallet/expand/mod.rs | 3 + frame/support/src/instances.rs | 49 ++++++++---- 3 files changed, 115 insertions(+), 16 deletions(-) create mode 100644 frame/support/procedural/src/pallet/expand/doc_only.rs diff --git a/frame/support/procedural/src/pallet/expand/doc_only.rs b/frame/support/procedural/src/pallet/expand/doc_only.rs new file mode 100644 index 0000000000000..32c9329f29498 --- /dev/null +++ b/frame/support/procedural/src/pallet/expand/doc_only.rs @@ -0,0 +1,79 @@ +// This file is part of Substrate. + +// Copyright (C) 2023 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use proc_macro2::Span; + +use crate::pallet::Def; + +pub fn expand_doc_only(def: &mut Def) -> proc_macro2::TokenStream { + let storage_names = def.storages.iter().map(|storage| &storage.ident); + let storage_docs = def.storages.iter().map(|storage| &storage.docs); + let dispatchables = if let Some(call_def) = &def.call { + let type_impl_generics = def.type_impl_generics(Span::call_site()); + call_def + .methods + .iter() + .map(|method| { + let name = &method.name; + let args = &method + .args + .iter() + .map(|(_, arg_name, arg_type)| quote::quote!( #arg_name: #arg_type, )) + .collect::(); + let docs = &method.docs; + let line_2 = + format!(" designed to document the [`{}`][`Call::{}`] variant of", name, name); + quote::quote!( + #( #[doc = #docs] )* + /// + /// --- + /// + /// NOTE: This function is an automatically generated, doc only, uncallable stub. + #[ doc = #line_2 ] + /// the pallet [`Call`] enum. You should not attempt to call this function + /// directly. + pub fn #name<#type_impl_generics>(#args) { unreachable!(); } + ) + }) + .collect::() + } else { + quote::quote!() + }; + + quote::quote!( + /// Auto-generated docs-only module listing all defined storage types for this pallet. + /// Note that members of this module cannot be used directly and are only provided for + /// documentation purposes. + #[cfg(doc)] + pub mod storage_types { + use super::*; + #( + #( #[doc = #storage_docs] )* + pub struct #storage_names(); + )* + } + + /// Auto-generated docs-only module listing all defined dispatchables for this pallet. + /// Note that members of this module cannot be used directly and are only provided for + /// documentation purposes. + #[cfg(doc)] + pub mod dispatchables { + use super::*; + #dispatchables + } + ) +} diff --git a/frame/support/procedural/src/pallet/expand/mod.rs b/frame/support/procedural/src/pallet/expand/mod.rs index 09a25a7101ee7..926ab0ec82d73 100644 --- a/frame/support/procedural/src/pallet/expand/mod.rs +++ b/frame/support/procedural/src/pallet/expand/mod.rs @@ -18,6 +18,7 @@ mod call; mod config; mod constants; +mod doc_only; mod documentation; mod error; mod event; @@ -72,6 +73,7 @@ pub fn expand(mut def: Def) -> proc_macro2::TokenStream { 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); + let doc_only = doc_only::expand_doc_only(&mut def); if get_doc_literals(&def.item.attrs).is_empty() { def.item.attrs.push(syn::parse_quote!( @@ -103,6 +105,7 @@ pub fn expand(mut def: Def) -> proc_macro2::TokenStream { #origins #validate_unsigned #tt_default_parts + #doc_only ); def.item diff --git a/frame/support/src/instances.rs b/frame/support/src/instances.rs index 482051c1f36d0..396018d5cbd52 100644 --- a/frame/support/src/instances.rs +++ b/frame/support/src/instances.rs @@ -31,66 +31,83 @@ //! NOTE: [`frame_support::pallet`] will reexport them inside the module, in order to make them //! accessible to [`frame_support::construct_runtime`]. -/// Instance1 to be used for instantiable pallet define with `pallet` macro. +/// `Instance1` to be used for instantiable palllets defined with the +/// [`#[pallet]`](`frame_support::pallet`) macro. Instances 2-16 are also available but are hidden +/// from docs. #[derive(Clone, Copy, PartialEq, Eq, crate::RuntimeDebugNoBound)] pub struct Instance1; -/// Instance2 to be used for instantiable pallet define with `pallet` macro. +/// `Instance2` to be used for instantiable palllets defined with the `#[pallet]` macro. +#[doc(hidden)] #[derive(Clone, Copy, PartialEq, Eq, crate::RuntimeDebugNoBound)] pub struct Instance2; -/// Instance3 to be used for instantiable pallet define with `pallet` macro. +/// `Instance3` to be used for instantiable palllets defined with the `#[pallet]` macro. +#[doc(hidden)] #[derive(Clone, Copy, PartialEq, Eq, crate::RuntimeDebugNoBound)] pub struct Instance3; -/// Instance4 to be used for instantiable pallet define with `pallet` macro. +/// `Instance4` to be used for instantiable palllets defined with the `#[pallet]` macro. +#[doc(hidden)] #[derive(Clone, Copy, PartialEq, Eq, crate::RuntimeDebugNoBound)] pub struct Instance4; -/// Instance5 to be used for instantiable pallet define with `pallet` macro. +/// `Instance5` to be used for instantiable palllets defined with the `#[pallet]` macro. +#[doc(hidden)] #[derive(Clone, Copy, PartialEq, Eq, crate::RuntimeDebugNoBound)] pub struct Instance5; -/// Instance6 to be used for instantiable pallet define with `pallet` macro. +/// `Instance6` to be used for instantiable palllets defined with the `#[pallet]` macro. +#[doc(hidden)] #[derive(Clone, Copy, PartialEq, Eq, crate::RuntimeDebugNoBound)] pub struct Instance6; -/// Instance7 to be used for instantiable pallet define with `pallet` macro. +/// `Instance7` to be used for instantiable palllets defined with the `#[pallet]` macro. +#[doc(hidden)] #[derive(Clone, Copy, PartialEq, Eq, crate::RuntimeDebugNoBound)] pub struct Instance7; -/// Instance8 to be used for instantiable pallet define with `pallet` macro. +/// `Instance8` to be used for instantiable palllets defined with the `#[pallet]` macro. +#[doc(hidden)] #[derive(Clone, Copy, PartialEq, Eq, crate::RuntimeDebugNoBound)] pub struct Instance8; -/// Instance9 to be used for instantiable pallet define with `pallet` macro. +/// `Instance9` to be used for instantiable palllets defined with the `#[pallet]` macro. +#[doc(hidden)] #[derive(Clone, Copy, PartialEq, Eq, crate::RuntimeDebugNoBound)] pub struct Instance9; -/// Instance10 to be used for instantiable pallet define with `pallet` macro. +/// `Instance10` to be used for instantiable palllets defined with the `#[pallet]` macro. +#[doc(hidden)] #[derive(Clone, Copy, PartialEq, Eq, crate::RuntimeDebugNoBound)] pub struct Instance10; -/// Instance11 to be used for instantiable pallet define with `pallet` macro. +/// `Instance11` to be used for instantiable palllets defined with the `#[pallet]` macro. +#[doc(hidden)] #[derive(Clone, Copy, PartialEq, Eq, crate::RuntimeDebugNoBound)] pub struct Instance11; -/// Instance12 to be used for instantiable pallet define with `pallet` macro. +/// `Instance12` to be used for instantiable palllets defined with the `#[pallet]` macro. +#[doc(hidden)] #[derive(Clone, Copy, PartialEq, Eq, crate::RuntimeDebugNoBound)] pub struct Instance12; -/// Instance13 to be used for instantiable pallet define with `pallet` macro. +/// `Instance13` to be used for instantiable palllets defined with the `#[pallet]` macro. +#[doc(hidden)] #[derive(Clone, Copy, PartialEq, Eq, crate::RuntimeDebugNoBound)] pub struct Instance13; -/// Instance14 to be used for instantiable pallet define with `pallet` macro. +/// `Instance14` to be used for instantiable palllets defined with the `#[pallet]` macro. +#[doc(hidden)] #[derive(Clone, Copy, PartialEq, Eq, crate::RuntimeDebugNoBound)] pub struct Instance14; -/// Instance15 to be used for instantiable pallet define with `pallet` macro. +/// `Instance15` to be used for instantiable palllets defined with the `#[pallet]` macro. +#[doc(hidden)] #[derive(Clone, Copy, PartialEq, Eq, crate::RuntimeDebugNoBound)] pub struct Instance15; -/// Instance16 to be used for instantiable pallet define with `pallet` macro. +/// `Instance16` to be used for instantiable palllets defined with the `#[pallet]` macro. +#[doc(hidden)] #[derive(Clone, Copy, PartialEq, Eq, crate::RuntimeDebugNoBound)] pub struct Instance16; From ba87188cce8c0a11c9542d7363cd5ddd46db2740 Mon Sep 17 00:00:00 2001 From: Mira Ressel Date: Wed, 15 Mar 2023 17:37:34 +0100 Subject: [PATCH 511/715] timestamp gitlab ci job outputs (#13605) * timestamp gitlab ci job outputs Based on previous work by @alvicsam in #13047. * inline timestamp script Some of our jobs don't check out the substrate repo. * include .timestamp in pipelines overriding the default before_script Still not including it in the zombienet jobs, they have their own timestamping anyway. * move timestamp.yml to shared pipeline repo https://gitlab.parity.io/parity/infrastructure/ci_cd/shared --- .gitlab-ci.yml | 4 ++++ scripts/ci/gitlab/pipeline/build.yml | 3 +++ scripts/ci/gitlab/pipeline/test.yml | 5 ++++- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 94fb3c608b771..44f98db3bf185 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -113,6 +113,7 @@ variables: .kubernetes-env: image: "${CI_IMAGE}" before_script: + - !reference [.timestamp, before_script] - !reference [.job-switcher, before_script] - !reference [.prepare-env, before_script] tags: @@ -141,6 +142,7 @@ variables: .docker-env: image: "${CI_IMAGE}" before_script: + - !reference [.timestamp, before_script] - !reference [.job-switcher, before_script] - !reference [.prepare-env, before_script] - !reference [.rust-info-script, script] @@ -310,6 +312,8 @@ include: - local: scripts/ci/gitlab/default-pipeline.yml rules: - if: $PIPELINE != "automatic-crate-publishing" + - project: parity/infrastructure/ci_cd/shared + file: /common/timestamp.yml #### stage: notify diff --git a/scripts/ci/gitlab/pipeline/build.yml b/scripts/ci/gitlab/pipeline/build.yml index 02f25a02a2c22..0a36599c70e24 100644 --- a/scripts/ci/gitlab/pipeline/build.yml +++ b/scripts/ci/gitlab/pipeline/build.yml @@ -62,6 +62,7 @@ build-linux-substrate: - job: test-linux-stable artifacts: false before_script: + - !reference [.timestamp, before_script] - !reference [.job-switcher, before_script] - mkdir -p ./artifacts/substrate/ - !reference [.rusty-cachier, before_script] @@ -95,6 +96,7 @@ build-linux-substrate: # this variable gets overriden by "rusty-cachier environment inject", use the value as default CARGO_TARGET_DIR: "$CI_PROJECT_DIR/target" before_script: + - !reference [.timestamp, before_script] - !reference [.job-switcher, before_script] - mkdir -p ./artifacts/subkey - !reference [.rusty-cachier, before_script] @@ -120,6 +122,7 @@ build-subkey-macos: # duplicating before_script & script sections from .build-subkey hidden job # to overwrite rusty-cachier integration as it doesn't work on macos before_script: + # skip timestamp script, the osx bash doesn't support printf %()T - !reference [.job-switcher, before_script] - mkdir -p ./artifacts/subkey script: diff --git a/scripts/ci/gitlab/pipeline/test.yml b/scripts/ci/gitlab/pipeline/test.yml index 49dbb194fb651..fd031d9aa56c3 100644 --- a/scripts/ci/gitlab/pipeline/test.yml +++ b/scripts/ci/gitlab/pipeline/test.yml @@ -83,6 +83,7 @@ cargo-check-benches: - .collect-artifacts - .pipeline-stopper-artifacts before_script: + - !reference [.timestamp, before_script] # perform rusty-cachier operations before any further modifications to the git repo to make cargo feel cheated not so much - !reference [.rust-info-script, script] - !reference [.job-switcher, before_script] @@ -145,7 +146,8 @@ node-bench-regression-guard: artifacts: true variables: CI_IMAGE: "paritytech/node-bench-regression-guard:latest" - before_script: [""] + before_script: + - !reference [.timestamp, before_script] script: - echo "------- IMPORTANT -------" - echo "node-bench-regression-guard depends on the results of a cargo-check-benches job" @@ -419,6 +421,7 @@ cargo-check-each-crate-macos: - .collect-artifacts - .pipeline-stopper-artifacts before_script: + # skip timestamp script, the osx bash doesn't support printf %()T - !reference [.job-switcher, before_script] - !reference [.rust-info-script, script] - !reference [.pipeline-stopper-vars, script] From bd52212085051561aee5784ff48b295894b6509d Mon Sep 17 00:00:00 2001 From: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Date: Wed, 15 Mar 2023 19:49:28 +0200 Subject: [PATCH 512/715] Metadata V15: Expose API to fetch metadata for version (#13287) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * impl_runtime_apis: Generate getters for `metadata_at` functions Signed-off-by: Alexandru Vasile * runtime: Implement new `Metadata` runtime trait Signed-off-by: Alexandru Vasile * runtime: Move `metadata_at` functions to construct_runtime macro Signed-off-by: Alexandru Vasile * contruct_runtime: Use `OpaqueMetadata` from hidden imports Signed-off-by: Alexandru Vasile * Adjust testing Signed-off-by: Alexandru Vasile * frame/tests: Add tests for the new API Signed-off-by: Alexandru Vasile * frame/tests: Adjust metdata naming Signed-off-by: Alexandru Vasile * frame/support: Expose `metadata-v14` feature flag Signed-off-by: Alexandru Vasile * frame/support: Expose metadata only under feature flags Signed-off-by: Alexandru Vasile * frame/support: Expose v14 metadata by default Signed-off-by: Alexandru Vasile * frame/support: Expose metadata feature for testing Signed-off-by: Alexandru Vasile * frame/support: Test metadata under different feature flags Signed-off-by: Alexandru Vasile * Update primitives/api/src/lib.rs Co-authored-by: Bastian Köcher * Update primitives/api/src/lib.rs Co-authored-by: Bastian Köcher * client/tests: Adjust testing to reflect trait Metadata change Signed-off-by: Alexandru Vasile * frame/metadata-ir: Add intermediate representation types for metadata Signed-off-by: Alexandru Vasile * frame/metadata-ir: Convert metadata to V14 Signed-off-by: Alexandru Vasile * frame/metadata-ir: Add API to convert metadata to multiple versions Signed-off-by: Alexandru Vasile * frame/metadata-ir: Expose V14 under feature flag Signed-off-by: Alexandru Vasile * frame/support: Adjust to metadata IR Signed-off-by: Alexandru Vasile * frame/support: More adjustments Signed-off-by: Alexandru Vasile * frame/support: Guard v14 details under feature flag Signed-off-by: Alexandru Vasile * frame/support: Adjust testing Signed-off-by: Alexandru Vasile * CI: Ensure `quick-benchmarks` uses `metadata-v14` Signed-off-by: Alexandru Vasile * frame/support: Use `metadata-v14` for benchmarks Signed-off-by: Alexandru Vasile * Adjust cargo fmt Signed-off-by: Alexandru Vasile * kitchensink-runtime: Add feature flag for `metadata-v14` Signed-off-by: Alexandru Vasile * frame/support/test: Adjust testing Signed-off-by: Alexandru Vasile * frame/support/test: Check crates locally Signed-off-by: Alexandru Vasile * Activate metadata-v14 for pallets Signed-off-by: Alexandru Vasile * Remove metadata-v14 feature flag Signed-off-by: Alexandru Vasile * frame/metadata_ir: Move `api.rs` to `mod.rs` Signed-off-by: Alexandru Vasile * frame/support: Handle latest metadata conversion via IR Signed-off-by: Alexandru Vasile * frame/tests: Add constant for metadata version 14 Signed-off-by: Alexandru Vasile * frame/support/test: Fix merge conflict Signed-off-by: Alexandru Vasile * Update frame/support/Cargo.toml Co-authored-by: Bastian Köcher * Update frame/support/src/metadata_ir/mod.rs Co-authored-by: Bastian Köcher * Update frame/support/test/Cargo.toml Co-authored-by: Bastian Köcher * Update primitives/api/src/lib.rs Co-authored-by: Bastian Köcher * frame/metadata: Collect pallet documentation for MetadataIR Signed-off-by: Alexandru Vasile * frame/tests: Check pallet documentation is propagated to MetadataIR Signed-off-by: Alexandru Vasile * frame/support: Improve documentation Signed-off-by: Alexandru Vasile --------- Signed-off-by: Alexandru Vasile Co-authored-by: parity-processbot <> Co-authored-by: Bastian Köcher --- bin/node-template/runtime/src/lib.rs | 8 + bin/node/runtime/src/lib.rs | 8 + client/rpc-spec-v2/src/chain_head/tests.rs | 2 +- client/rpc/src/state/tests.rs | 2 +- .../src/construct_runtime/expand/metadata.rs | 43 ++- frame/support/procedural/src/lib.rs | 6 +- .../procedural/src/pallet/expand/call.rs | 2 +- .../procedural/src/pallet/expand/constants.rs | 4 +- .../src/pallet/expand/documentation.rs | 4 +- .../src/pallet/expand/pallet_struct.rs | 6 +- .../procedural/src/pallet/expand/storage.rs | 4 +- .../procedural/src/storage/metadata.rs | 26 +- frame/support/procedural/src/storage/mod.rs | 14 +- frame/support/src/dispatch.rs | 16 +- frame/support/src/hash.rs | 18 +- frame/support/src/lib.rs | 92 ++--- frame/support/src/metadata_ir/mod.rs | 82 +++++ frame/support/src/metadata_ir/types.rs | 329 ++++++++++++++++++ frame/support/src/metadata_ir/v14.rs | 158 +++++++++ .../support/src/storage/types/counted_map.rs | 20 +- frame/support/src/storage/types/double_map.rs | 30 +- frame/support/src/storage/types/key.rs | 6 +- frame/support/src/storage/types/map.rs | 26 +- frame/support/src/storage/types/mod.rs | 12 +- frame/support/src/storage/types/nmap.rs | 70 ++-- frame/support/src/storage/types/value.rs | 22 +- frame/support/test/tests/decl_storage.rs | 207 +++++------ frame/support/test/tests/instance.rs | 32 +- frame/support/test/tests/pallet.rs | 40 +++ primitives/api/src/lib.rs | 12 + test-utils/runtime/src/lib.rs | 17 +- 31 files changed, 1002 insertions(+), 316 deletions(-) create mode 100644 frame/support/src/metadata_ir/mod.rs create mode 100644 frame/support/src/metadata_ir/types.rs create mode 100644 frame/support/src/metadata_ir/v14.rs diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs index ac01aa95f4f12..41871c06bd923 100644 --- a/bin/node-template/runtime/src/lib.rs +++ b/bin/node-template/runtime/src/lib.rs @@ -354,6 +354,14 @@ impl_runtime_apis! { fn metadata() -> OpaqueMetadata { OpaqueMetadata::new(Runtime::metadata().into()) } + + fn metadata_at_version(version: u32) -> Option { + Runtime::metadata_at_version(version) + } + + fn metadata_versions() -> sp_std::vec::Vec { + Runtime::metadata_versions() + } } impl sp_block_builder::BlockBuilder for Runtime { diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index d8426d3b35e15..5d1dea02e8256 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1942,6 +1942,14 @@ impl_runtime_apis! { fn metadata() -> OpaqueMetadata { OpaqueMetadata::new(Runtime::metadata().into()) } + + fn metadata_at_version(version: u32) -> Option { + Runtime::metadata_at_version(version) + } + + fn metadata_versions() -> sp_std::vec::Vec { + Runtime::metadata_versions() + } } impl sp_block_builder::BlockBuilder for Runtime { diff --git a/client/rpc-spec-v2/src/chain_head/tests.rs b/client/rpc-spec-v2/src/chain_head/tests.rs index 0886efa94a756..fcd906dcf5be0 100644 --- a/client/rpc-spec-v2/src/chain_head/tests.rs +++ b/client/rpc-spec-v2/src/chain_head/tests.rs @@ -170,7 +170,7 @@ async fn follow_with_runtime() { let runtime_str = "{\"specName\":\"test\",\"implName\":\"parity-test\",\"authoringVersion\":1,\ \"specVersion\":2,\"implVersion\":2,\"apis\":[[\"0xdf6acb689907609b\",4],\ - [\"0x37e397fc7c91f5e4\",1],[\"0xd2bc9897eed08f15\",3],[\"0x40fe3ad401f8959a\",6],\ + [\"0x37e397fc7c91f5e4\",2],[\"0xd2bc9897eed08f15\",3],[\"0x40fe3ad401f8959a\",6],\ [\"0xc6e9a76309f39b09\",1],[\"0xdd718d5cc53262d4\",1],[\"0xcbca25e39f142387\",2],\ [\"0xf78b278be53f454c\",2],[\"0xab3c0572291feb8b\",1],[\"0xbc9d89904f5b923f\",1]],\ \"transactionVersion\":1,\"stateVersion\":1}"; diff --git a/client/rpc/src/state/tests.rs b/client/rpc/src/state/tests.rs index 53f8f1d48bc95..1ccc609e4f0e4 100644 --- a/client/rpc/src/state/tests.rs +++ b/client/rpc/src/state/tests.rs @@ -484,7 +484,7 @@ async 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\",6],\ + [\"0x37e397fc7c91f5e4\",2],[\"0xd2bc9897eed08f15\",3],[\"0x40fe3ad401f8959a\",6],\ [\"0xc6e9a76309f39b09\",1],[\"0xdd718d5cc53262d4\",1],[\"0xcbca25e39f142387\",2],\ [\"0xf78b278be53f454c\",2],[\"0xab3c0572291feb8b\",1],[\"0xbc9d89904f5b923f\",1]],\ \"transactionVersion\":1,\"stateVersion\":1}"; diff --git a/frame/support/procedural/src/construct_runtime/expand/metadata.rs b/frame/support/procedural/src/construct_runtime/expand/metadata.rs index e9996121757d7..ba6a621af7523 100644 --- a/frame/support/procedural/src/construct_runtime/expand/metadata.rs +++ b/frame/support/procedural/src/construct_runtime/expand/metadata.rs @@ -48,6 +48,7 @@ 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 docs = expand_pallet_metadata_docs(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"); @@ -59,7 +60,7 @@ pub fn expand_runtime_metadata( quote! { #attr - #scrate::metadata::PalletMetadata { + #scrate::metadata_ir::PalletMetadataIR { name: stringify!(#name), index: #index, storage: #storage, @@ -67,6 +68,7 @@ pub fn expand_runtime_metadata( event: #event, constants: #constants, error: #errors, + docs: #docs, } } }) @@ -74,10 +76,10 @@ pub fn expand_runtime_metadata( quote! { impl #runtime { - pub fn metadata() -> #scrate::metadata::RuntimeMetadataPrefixed { - #scrate::metadata::RuntimeMetadataLastVersion::new( - #scrate::sp_std::vec![ #(#pallets),* ], - #scrate::metadata::ExtrinsicMetadata { + fn metadata_ir() -> #scrate::metadata_ir::MetadataIR { + #scrate::metadata_ir::MetadataIR { + pallets: #scrate::sp_std::vec![ #(#pallets),* ], + extrinsic: #scrate::metadata_ir::ExtrinsicMetadataIR { ty: #scrate::scale_info::meta_type::<#extrinsic>(), version: <#extrinsic as #scrate::sp_runtime::traits::ExtrinsicMetadata>::VERSION, signed_extensions: < @@ -86,15 +88,29 @@ pub fn expand_runtime_metadata( >::SignedExtensions as #scrate::sp_runtime::traits::SignedExtension >::metadata() .into_iter() - .map(|meta| #scrate::metadata::SignedExtensionMetadata { + .map(|meta| #scrate::metadata_ir::SignedExtensionMetadataIR { identifier: meta.identifier, ty: meta.ty, additional_signed: meta.additional_signed, }) .collect(), }, - #scrate::scale_info::meta_type::<#runtime>() - ).into() + ty: #scrate::scale_info::meta_type::<#runtime>() + } + } + + pub fn metadata() -> #scrate::metadata::RuntimeMetadataPrefixed { + #scrate::metadata_ir::into_latest(#runtime::metadata_ir()) + } + + pub fn metadata_at_version(version: u32) -> Option<#scrate::OpaqueMetadata> { + #scrate::metadata_ir::into_version(#runtime::metadata_ir(), version).map(|prefixed| { + #scrate::OpaqueMetadata::new(prefixed.into()) + }) + } + + pub fn metadata_versions() -> #scrate::sp_std::vec::Vec { + #scrate::metadata_ir::supported_versions() } } } @@ -157,7 +173,7 @@ fn expand_pallet_metadata_events( quote! { Some( - #scrate::metadata::PalletEventMetadata { + #scrate::metadata_ir::PalletEventMetadataIR { ty: #scrate::scale_info::meta_type::<#pallet_event>() } ) @@ -184,3 +200,12 @@ fn expand_pallet_metadata_errors(runtime: &Ident, decl: &Pallet) -> TokenStream #path::Pallet::<#runtime #(, #path::#instance)*>::error_metadata() } } + +fn expand_pallet_metadata_docs(runtime: &Ident, decl: &Pallet) -> TokenStream { + let path = &decl.path; + let instance = decl.instance.as_ref().into_iter(); + + quote! { + #path::Pallet::<#runtime #(, #path::#instance)*>::pallet_documentation_metadata() + } +} diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index 1d5dde20e2034..0515a4b7d2f91 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -495,7 +495,7 @@ pub fn construct_runtime(input: TokenStream) -> TokenStream { /// #[doc = include_str!("../README.md")] /// #[pallet_doc("../doc1.md")] /// #[pallet_doc("../doc2.md")] -/// pub struct Pallet(_); +/// pub mod pallet {} /// ``` /// /// The runtime metadata for this pallet contains the following @@ -514,7 +514,7 @@ pub fn construct_runtime(input: TokenStream) -> TokenStream { /// /// Documentation for pallet 1 /// /// Documentation for pallet 2 /// /// Content of README.md -/// pub struct Pallet(_); +/// pub mod pallet {} /// ``` /// /// If you want to specify the file from which the documentation is loaded, you can use the @@ -531,7 +531,7 @@ pub fn construct_runtime(input: TokenStream) -> TokenStream { /// /// This approach is beneficial when you use the `include_str` macro at the beginning of the file /// and want that documentation to extend to the runtime metadata, without reiterating the -/// documentation on the module itself. +/// documentation on the pallet module itself. #[proc_macro_attribute] pub fn pallet(attr: TokenStream, item: TokenStream) -> TokenStream { pallet::pallet(attr, item) diff --git a/frame/support/procedural/src/pallet/expand/call.rs b/frame/support/procedural/src/pallet/expand/call.rs index 3db454eb6211b..7672609a9881e 100644 --- a/frame/support/procedural/src/pallet/expand/call.rs +++ b/frame/support/procedural/src/pallet/expand/call.rs @@ -362,7 +362,7 @@ pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream { impl<#type_impl_gen> #pallet_ident<#type_use_gen> #where_clause { #[doc(hidden)] - pub fn call_functions() -> #frame_support::metadata::PalletCallMetadata { + pub fn call_functions() -> #frame_support::metadata_ir::PalletCallMetadataIR { #frame_support::scale_info::meta_type::<#call_ident<#type_use_gen>>().into() } } diff --git a/frame/support/procedural/src/pallet/expand/constants.rs b/frame/support/procedural/src/pallet/expand/constants.rs index 21ac1de3642d5..21fa492a75b56 100644 --- a/frame/support/procedural/src/pallet/expand/constants.rs +++ b/frame/support/procedural/src/pallet/expand/constants.rs @@ -85,7 +85,7 @@ pub fn expand_constants(def: &mut Def) -> proc_macro2::TokenStream { let default_byte_impl = &const_.default_byte_impl; quote::quote!({ - #frame_support::metadata::PalletConstantMetadata { + #frame_support::metadata_ir::PalletConstantMetadataIR { name: #ident_str, ty: #frame_support::scale_info::meta_type::<#const_type>(), value: { #default_byte_impl }, @@ -99,7 +99,7 @@ pub fn expand_constants(def: &mut Def) -> proc_macro2::TokenStream { #[doc(hidden)] pub fn pallet_constants_metadata() - -> #frame_support::sp_std::vec::Vec<#frame_support::metadata::PalletConstantMetadata> + -> #frame_support::sp_std::vec::Vec<#frame_support::metadata_ir::PalletConstantMetadataIR> { #frame_support::sp_std::vec![ #( #consts ),* ] } diff --git a/frame/support/procedural/src/pallet/expand/documentation.rs b/frame/support/procedural/src/pallet/expand/documentation.rs index e158448a89711..1aa46cf572847 100644 --- a/frame/support/procedural/src/pallet/expand/documentation.rs +++ b/frame/support/procedural/src/pallet/expand/documentation.rs @@ -145,7 +145,7 @@ impl ToTokens for DocMetaValue { /// Implement a `pallet_documentation_metadata` function to fetch the /// documentation that is included in the metadata. /// -/// The documentation is placed at the top of the module similar to: +/// The documentation is placed on the pallet similar to: /// /// ```ignore /// #[pallet] @@ -163,7 +163,7 @@ impl ToTokens for DocMetaValue { /// which is the file path that holds the documentation to be added to the metadata. /// /// Unlike the `doc` attribute, the documentation provided to the `proc_macro` attribute is -/// not inserted at the beginning of the module. +/// not added to the pallet. pub fn expand_documentation(def: &mut Def) -> proc_macro2::TokenStream { let frame_support = &def.frame_support; let type_impl_gen = &def.type_impl_generics(proc_macro2::Span::call_site()); diff --git a/frame/support/procedural/src/pallet/expand/pallet_struct.rs b/frame/support/procedural/src/pallet/expand/pallet_struct.rs index 27fe9d3401ea2..7acfb9090698e 100644 --- a/frame/support/procedural/src/pallet/expand/pallet_struct.rs +++ b/frame/support/procedural/src/pallet/expand/pallet_struct.rs @@ -82,8 +82,8 @@ pub fn expand_pallet_struct(def: &mut Def) -> proc_macro2::TokenStream { 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 { + pub fn error_metadata() -> Option<#frame_support::metadata_ir::PalletErrorMetadataIR> { + Some(#frame_support::metadata_ir::PalletErrorMetadataIR { ty: #frame_support::scale_info::meta_type::<#error_ident<#type_use_gen>>() }) } @@ -93,7 +93,7 @@ pub fn expand_pallet_struct(def: &mut Def) -> proc_macro2::TokenStream { 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> { + pub fn error_metadata() -> Option<#frame_support::metadata_ir::PalletErrorMetadataIR> { None } } diff --git a/frame/support/procedural/src/pallet/expand/storage.rs b/frame/support/procedural/src/pallet/expand/storage.rs index 05d61bb522180..8ba9ee7681ca9 100644 --- a/frame/support/procedural/src/pallet/expand/storage.rs +++ b/frame/support/procedural/src/pallet/expand/storage.rs @@ -639,8 +639,8 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream { #completed_where_clause { #[doc(hidden)] - pub fn storage_metadata() -> #frame_support::metadata::PalletStorageMetadata { - #frame_support::metadata::PalletStorageMetadata { + pub fn storage_metadata() -> #frame_support::metadata_ir::PalletStorageMetadataIR { + #frame_support::metadata_ir::PalletStorageMetadataIR { prefix: < ::PalletInfo as #frame_support::traits::PalletInfo diff --git a/frame/support/procedural/src/storage/metadata.rs b/frame/support/procedural/src/storage/metadata.rs index 3e3e0576f63b5..5561d0564597b 100644 --- a/frame/support/procedural/src/storage/metadata.rs +++ b/frame/support/procedural/src/storage/metadata.rs @@ -27,7 +27,7 @@ fn storage_line_metadata_type(scrate: &TokenStream, line: &StorageLineDefExt) -> match &line.storage_type { StorageLineTypeDef::Simple(_) => { quote! { - #scrate::metadata::StorageEntryType::Plain( + #scrate::metadata_ir::StorageEntryTypeIR::Plain( #scrate::scale_info::meta_type::<#value_type>() ) } @@ -36,8 +36,8 @@ fn storage_line_metadata_type(scrate: &TokenStream, line: &StorageLineDefExt) -> let hasher = map.hasher.into_metadata(); let key = &map.key; quote! { - #scrate::metadata::StorageEntryType::Map { - hashers: #scrate::sp_std::vec! [ #scrate::metadata::#hasher ], + #scrate::metadata_ir::StorageEntryTypeIR::Map { + hashers: #scrate::sp_std::vec! [ #scrate::metadata_ir::#hasher ], key: #scrate::scale_info::meta_type::<#key>(), value: #scrate::scale_info::meta_type::<#value_type>(), } @@ -49,10 +49,10 @@ fn storage_line_metadata_type(scrate: &TokenStream, line: &StorageLineDefExt) -> let key1 = &map.key1; let key2 = &map.key2; quote! { - #scrate::metadata::StorageEntryType::Map { + #scrate::metadata_ir::StorageEntryTypeIR::Map { hashers: #scrate::sp_std::vec! [ - #scrate::metadata::#hasher1, - #scrate::metadata::#hasher2, + #scrate::metadata_ir::#hasher1, + #scrate::metadata_ir::#hasher2, ], key: #scrate::scale_info::meta_type::<(#key1, #key2)>(), value: #scrate::scale_info::meta_type::<#value_type>(), @@ -67,9 +67,9 @@ fn storage_line_metadata_type(scrate: &TokenStream, line: &StorageLineDefExt) -> .map(|hasher| hasher.to_storage_hasher_struct()) .collect::>(); quote! { - #scrate::metadata::StorageEntryType::Map { + #scrate::metadata_ir::StorageEntryTypeIR::Map { hashers: #scrate::sp_std::vec! [ - #( #scrate::metadata::StorageHasher::#hashers, )* + #( #scrate::metadata_ir::StorageHasherIR::#hashers, )* ], key: #scrate::scale_info::meta_type::<#key_tuple>(), value: #scrate::scale_info::meta_type::<#value_type>(), @@ -159,9 +159,9 @@ pub fn impl_metadata(def: &DeclStorageDefExt) -> TokenStream { let str_name = line.name.to_string(); let modifier = if line.is_option { - quote!(#scrate::metadata::StorageEntryModifier::Optional) + quote!(#scrate::metadata_ir::StorageEntryModifierIR::Optional) } else { - quote!(#scrate::metadata::StorageEntryModifier::Default) + quote!(#scrate::metadata_ir::StorageEntryModifierIR::Default) }; let ty = storage_line_metadata_type(scrate, line); @@ -172,7 +172,7 @@ pub fn impl_metadata(def: &DeclStorageDefExt) -> TokenStream { let docs = get_doc_literals(&line.attrs); let entry = quote! { - #scrate::metadata::StorageEntryMetadata { + #scrate::metadata_ir::StorageEntryMetadataIR { name: #str_name, modifier: #modifier, ty: #ty, @@ -194,7 +194,7 @@ pub fn impl_metadata(def: &DeclStorageDefExt) -> TokenStream { }; let store_metadata = quote!( - #scrate::metadata::PalletStorageMetadata { + #scrate::metadata_ir::PalletStorageMetadataIR { prefix: #prefix, entries: #scrate::sp_std::vec![ #entries ], } @@ -209,7 +209,7 @@ pub fn impl_metadata(def: &DeclStorageDefExt) -> TokenStream { impl #module_impl #module_struct #where_clause { #[doc(hidden)] - pub fn storage_metadata() -> #scrate::metadata::PalletStorageMetadata { + pub fn storage_metadata() -> #scrate::metadata_ir::PalletStorageMetadataIR { #store_metadata } } diff --git a/frame/support/procedural/src/storage/mod.rs b/frame/support/procedural/src/storage/mod.rs index 1e48a1fbb06d1..3d3b1443d393f 100644 --- a/frame/support/procedural/src/storage/mod.rs +++ b/frame/support/procedural/src/storage/mod.rs @@ -454,13 +454,13 @@ impl HasherKind { fn into_metadata(&self) -> proc_macro2::TokenStream { match self { - HasherKind::Blake2_256 => quote!(StorageHasher::Blake2_256), - HasherKind::Blake2_128 => quote!(StorageHasher::Blake2_128), - HasherKind::Blake2_128Concat => quote!(StorageHasher::Blake2_128Concat), - HasherKind::Twox256 => quote!(StorageHasher::Twox256), - HasherKind::Twox128 => quote!(StorageHasher::Twox128), - HasherKind::Twox64Concat => quote!(StorageHasher::Twox64Concat), - HasherKind::Identity => quote!(StorageHasher::Identity), + HasherKind::Blake2_256 => quote!(StorageHasherIR::Blake2_256), + HasherKind::Blake2_128 => quote!(StorageHasherIR::Blake2_128), + HasherKind::Blake2_128Concat => quote!(StorageHasherIR::Blake2_128Concat), + HasherKind::Twox256 => quote!(StorageHasherIR::Twox256), + HasherKind::Twox128 => quote!(StorageHasherIR::Twox128), + HasherKind::Twox64Concat => quote!(StorageHasherIR::Twox64Concat), + HasherKind::Identity => quote!(StorageHasherIR::Identity), } } } diff --git a/frame/support/src/dispatch.rs b/frame/support/src/dispatch.rs index c5f4cc60c1f1b..390555b02d1bb 100644 --- a/frame/support/src/dispatch.rs +++ b/frame/support/src/dispatch.rs @@ -2977,7 +2977,7 @@ macro_rules! __dispatch_impl_metadata { { #[doc(hidden)] #[allow(dead_code)] - pub fn call_functions() -> $crate::metadata::PalletCallMetadata { + pub fn call_functions() -> $crate::metadata_ir::PalletCallMetadataIR { $crate::scale_info::meta_type::<$call_type<$trait_instance $(, $instance)?>>().into() } } @@ -2998,7 +2998,7 @@ macro_rules! __impl_error_metadata { { #[doc(hidden)] #[allow(dead_code)] - pub fn error_metadata() -> Option<$crate::metadata::PalletErrorMetadata> { + pub fn error_metadata() -> Option<$crate::metadata_ir::PalletErrorMetadataIR> { None } } @@ -3013,8 +3013,8 @@ macro_rules! __impl_error_metadata { { #[doc(hidden)] #[allow(dead_code)] - pub fn error_metadata() -> Option<$crate::metadata::PalletErrorMetadata> { - Some($crate::metadata::PalletErrorMetadata { + pub fn error_metadata() -> Option<$crate::metadata_ir::PalletErrorMetadataIR> { + Some($crate::metadata_ir::PalletErrorMetadataIR { ty: $crate::scale_info::meta_type::<$( $error_type )*>() }) } @@ -3109,7 +3109,7 @@ macro_rules! __impl_module_constants_metadata { { #[doc(hidden)] #[allow(dead_code)] - pub fn pallet_constants_metadata() -> $crate::sp_std::vec::Vec<$crate::metadata::PalletConstantMetadata> { + pub fn pallet_constants_metadata() -> $crate::sp_std::vec::Vec<$crate::metadata_ir::PalletConstantMetadataIR> { // Create the `ByteGetter`s $( #[allow(non_upper_case_types)] @@ -3133,7 +3133,7 @@ macro_rules! __impl_module_constants_metadata { )* $crate::sp_std::vec![ $( - $crate::metadata::PalletConstantMetadata { + $crate::metadata_ir::PalletConstantMetadataIR { name: stringify!($name), ty: $crate::scale_info::meta_type::<$type>(), value: $default_byte_name::<$const_trait_instance $(, $const_instance)?>( @@ -3207,7 +3207,7 @@ mod tests { use super::*; use crate::{ dispatch::{DispatchClass, DispatchInfo, Pays}, - metadata::*, + metadata_ir::*, traits::{ CallerTrait, CrateVersion, Get, GetCallName, IntegrityTest, OnFinalize, OnIdle, OnInitialize, OnRuntimeUpgrade, PalletInfo, @@ -3405,7 +3405,7 @@ mod tests { fn module_json_metadata() { let metadata = Module::::call_functions(); let expected_metadata = - PalletCallMetadata { ty: scale_info::meta_type::>() }; + PalletCallMetadataIR { ty: scale_info::meta_type::>() }; assert_eq!(expected_metadata, metadata); } diff --git a/frame/support/src/hash.rs b/frame/support/src/hash.rs index bf9eb2f88b0b1..115ce605d542e 100644 --- a/frame/support/src/hash.rs +++ b/frame/support/src/hash.rs @@ -17,7 +17,7 @@ //! Hash utilities. -use crate::metadata; +use crate::metadata_ir; use codec::{Codec, MaxEncodedLen}; use sp_io::hashing::{blake2_128, blake2_256, twox_128, twox_256, twox_64}; use sp_std::prelude::Vec; @@ -59,7 +59,7 @@ impl Hashable for T { /// Hasher to use to hash keys to insert to storage. pub trait StorageHasher: 'static { - const METADATA: metadata::StorageHasher; + const METADATA: metadata_ir::StorageHasherIR; type Output: AsRef<[u8]>; fn hash(x: &[u8]) -> Self::Output; @@ -80,7 +80,7 @@ pub trait ReversibleStorageHasher: StorageHasher { /// Store the key directly. pub struct Identity; impl StorageHasher for Identity { - const METADATA: metadata::StorageHasher = metadata::StorageHasher::Identity; + const METADATA: metadata_ir::StorageHasherIR = metadata_ir::StorageHasherIR::Identity; type Output = Vec; fn hash(x: &[u8]) -> Vec { x.to_vec() @@ -98,7 +98,7 @@ impl ReversibleStorageHasher for Identity { /// Hash storage keys with `concat(twox64(key), key)` pub struct Twox64Concat; impl StorageHasher for Twox64Concat { - const METADATA: metadata::StorageHasher = metadata::StorageHasher::Twox64Concat; + const METADATA: metadata_ir::StorageHasherIR = metadata_ir::StorageHasherIR::Twox64Concat; type Output = Vec; fn hash(x: &[u8]) -> Vec { twox_64(x).iter().chain(x.iter()).cloned().collect::>() @@ -120,7 +120,7 @@ impl ReversibleStorageHasher for Twox64Concat { /// Hash storage keys with `concat(blake2_128(key), key)` pub struct Blake2_128Concat; impl StorageHasher for Blake2_128Concat { - const METADATA: metadata::StorageHasher = metadata::StorageHasher::Blake2_128Concat; + const METADATA: metadata_ir::StorageHasherIR = metadata_ir::StorageHasherIR::Blake2_128Concat; type Output = Vec; fn hash(x: &[u8]) -> Vec { blake2_128(x).iter().chain(x.iter()).cloned().collect::>() @@ -142,7 +142,7 @@ impl ReversibleStorageHasher for Blake2_128Concat { /// Hash storage keys with blake2 128 pub struct Blake2_128; impl StorageHasher for Blake2_128 { - const METADATA: metadata::StorageHasher = metadata::StorageHasher::Blake2_128; + const METADATA: metadata_ir::StorageHasherIR = metadata_ir::StorageHasherIR::Blake2_128; type Output = [u8; 16]; fn hash(x: &[u8]) -> [u8; 16] { blake2_128(x) @@ -155,7 +155,7 @@ impl StorageHasher for Blake2_128 { /// Hash storage keys with blake2 256 pub struct Blake2_256; impl StorageHasher for Blake2_256 { - const METADATA: metadata::StorageHasher = metadata::StorageHasher::Blake2_256; + const METADATA: metadata_ir::StorageHasherIR = metadata_ir::StorageHasherIR::Blake2_256; type Output = [u8; 32]; fn hash(x: &[u8]) -> [u8; 32] { blake2_256(x) @@ -168,7 +168,7 @@ impl StorageHasher for Blake2_256 { /// Hash storage keys with twox 128 pub struct Twox128; impl StorageHasher for Twox128 { - const METADATA: metadata::StorageHasher = metadata::StorageHasher::Twox128; + const METADATA: metadata_ir::StorageHasherIR = metadata_ir::StorageHasherIR::Twox128; type Output = [u8; 16]; fn hash(x: &[u8]) -> [u8; 16] { twox_128(x) @@ -181,7 +181,7 @@ impl StorageHasher for Twox128 { /// Hash storage keys with twox 256 pub struct Twox256; impl StorageHasher for Twox256 { - const METADATA: metadata::StorageHasher = metadata::StorageHasher::Twox256; + const METADATA: metadata_ir::StorageHasherIR = metadata_ir::StorageHasherIR::Twox256; type Output = [u8; 32]; fn hash(x: &[u8]) -> [u8; 32] { twox_256(x) diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 4e9bc32b0043b..b845828455793 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -50,7 +50,7 @@ pub use paste; pub use scale_info; #[cfg(feature = "std")] pub use serde; -pub use sp_core::Void; +pub use sp_core::{OpaqueMetadata, Void}; #[doc(hidden)] pub use sp_core_hashing_proc_macro; #[doc(hidden)] @@ -80,10 +80,10 @@ pub mod error; pub mod crypto; pub mod dispatch_context; pub mod instances; +pub mod metadata_ir; pub mod migrations; pub mod traits; pub mod weights; - #[doc(hidden)] pub mod unsigned { #[doc(hidden)] @@ -827,9 +827,9 @@ pub use serde::{Deserialize, Serialize}; #[cfg(test)] pub mod tests { use super::*; - use crate::metadata::{ - PalletStorageMetadata, StorageEntryMetadata, StorageEntryModifier, StorageEntryType, - StorageHasher, + use crate::metadata_ir::{ + PalletStorageMetadataIR, StorageEntryMetadataIR, StorageEntryModifierIR, + StorageEntryTypeIR, StorageHasherIR, }; use codec::{Codec, EncodeLike}; use frame_support::traits::CrateVersion; @@ -1310,101 +1310,107 @@ pub mod tests { }); } - fn expected_metadata() -> PalletStorageMetadata { - PalletStorageMetadata { + fn expected_metadata() -> PalletStorageMetadataIR { + PalletStorageMetadataIR { prefix: "Test", entries: vec![ - StorageEntryMetadata { + StorageEntryMetadataIR { name: "Value", - modifier: StorageEntryModifier::Default, - ty: StorageEntryType::Plain(scale_info::meta_type::()), + modifier: StorageEntryModifierIR::Default, + ty: StorageEntryTypeIR::Plain(scale_info::meta_type::()), default: vec![0, 0, 0, 0, 0, 0, 0, 0], docs: vec![], }, - StorageEntryMetadata { + StorageEntryMetadataIR { name: "Data", - modifier: StorageEntryModifier::Default, - ty: StorageEntryType::Map { - hashers: vec![StorageHasher::Twox64Concat], + modifier: StorageEntryModifierIR::Default, + ty: StorageEntryTypeIR::Map { + hashers: vec![StorageHasherIR::Twox64Concat], key: scale_info::meta_type::(), value: scale_info::meta_type::(), }, default: vec![0, 0, 0, 0, 0, 0, 0, 0], docs: vec![], }, - StorageEntryMetadata { + StorageEntryMetadataIR { name: "OptionLinkedMap", - modifier: StorageEntryModifier::Optional, - ty: StorageEntryType::Map { - hashers: vec![StorageHasher::Blake2_128Concat], + modifier: StorageEntryModifierIR::Optional, + ty: StorageEntryTypeIR::Map { + hashers: vec![StorageHasherIR::Blake2_128Concat], key: scale_info::meta_type::(), value: scale_info::meta_type::(), }, default: vec![0], docs: vec![], }, - StorageEntryMetadata { + StorageEntryMetadataIR { name: "GenericData", - modifier: StorageEntryModifier::Default, - ty: StorageEntryType::Map { - hashers: vec![StorageHasher::Identity], + modifier: StorageEntryModifierIR::Default, + ty: StorageEntryTypeIR::Map { + hashers: vec![StorageHasherIR::Identity], key: scale_info::meta_type::(), value: scale_info::meta_type::(), }, default: vec![0, 0, 0, 0], docs: vec![], }, - StorageEntryMetadata { + StorageEntryMetadataIR { name: "GenericData2", - modifier: StorageEntryModifier::Optional, - ty: StorageEntryType::Map { - hashers: vec![StorageHasher::Blake2_128Concat], + modifier: StorageEntryModifierIR::Optional, + ty: StorageEntryTypeIR::Map { + hashers: vec![StorageHasherIR::Blake2_128Concat], key: scale_info::meta_type::(), value: scale_info::meta_type::(), }, default: vec![0], docs: vec![], }, - StorageEntryMetadata { + StorageEntryMetadataIR { name: "DataDM", - modifier: StorageEntryModifier::Default, - ty: StorageEntryType::Map { - hashers: vec![StorageHasher::Twox64Concat, StorageHasher::Blake2_128Concat], + modifier: StorageEntryModifierIR::Default, + ty: StorageEntryTypeIR::Map { + hashers: vec![ + StorageHasherIR::Twox64Concat, + StorageHasherIR::Blake2_128Concat, + ], key: scale_info::meta_type::<(u32, u32)>(), value: scale_info::meta_type::(), }, default: vec![0, 0, 0, 0, 0, 0, 0, 0], docs: vec![], }, - StorageEntryMetadata { + StorageEntryMetadataIR { name: "GenericDataDM", - modifier: StorageEntryModifier::Default, - ty: StorageEntryType::Map { - hashers: vec![StorageHasher::Blake2_128Concat, StorageHasher::Identity], + modifier: StorageEntryModifierIR::Default, + ty: StorageEntryTypeIR::Map { + hashers: vec![StorageHasherIR::Blake2_128Concat, StorageHasherIR::Identity], key: scale_info::meta_type::<(u32, u32)>(), value: scale_info::meta_type::(), }, default: vec![0, 0, 0, 0], docs: vec![], }, - StorageEntryMetadata { + StorageEntryMetadataIR { name: "GenericData2DM", - modifier: StorageEntryModifier::Optional, - ty: StorageEntryType::Map { - hashers: vec![StorageHasher::Blake2_128Concat, StorageHasher::Twox64Concat], + modifier: StorageEntryModifierIR::Optional, + ty: StorageEntryTypeIR::Map { + hashers: vec![ + StorageHasherIR::Blake2_128Concat, + StorageHasherIR::Twox64Concat, + ], key: scale_info::meta_type::<(u32, u32)>(), value: scale_info::meta_type::(), }, default: vec![0], docs: vec![], }, - StorageEntryMetadata { + StorageEntryMetadataIR { name: "AppendableDM", - modifier: StorageEntryModifier::Default, - ty: StorageEntryType::Map { + modifier: StorageEntryModifierIR::Default, + ty: StorageEntryTypeIR::Map { hashers: vec![ - StorageHasher::Blake2_128Concat, - StorageHasher::Blake2_128Concat, + StorageHasherIR::Blake2_128Concat, + StorageHasherIR::Blake2_128Concat, ], key: scale_info::meta_type::<(u32, u32)>(), value: scale_info::meta_type::>(), diff --git a/frame/support/src/metadata_ir/mod.rs b/frame/support/src/metadata_ir/mod.rs new file mode 100644 index 0000000000000..bab205d63c118 --- /dev/null +++ b/frame/support/src/metadata_ir/mod.rs @@ -0,0 +1,82 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Intermediate representation of the runtime metadata. + +mod types; +use frame_metadata::{RuntimeMetadataPrefixed, RuntimeMetadataV14}; +pub use types::*; + +mod v14; + +/// Metadata V14. +const V14: u32 = 14; + +/// Transform the IR to the specified version. +/// +/// Use [`supported_versions`] to find supported versions. +pub fn into_version(metadata: MetadataIR, version: u32) -> Option { + match version { + // Latest stable version. + V14 => { + let v14: frame_metadata::v14::RuntimeMetadataV14 = metadata.into(); + Some(v14.into()) + }, + _ => None, + } +} + +/// Returns the supported metadata versions. +pub fn supported_versions() -> sp_std::vec::Vec { + sp_std::vec![V14,] +} + +/// Transform the IR to the latest stable metadata version. +pub fn into_latest(metadata: MetadataIR) -> RuntimeMetadataPrefixed { + let latest: RuntimeMetadataV14 = metadata.into(); + latest.into() +} + +#[cfg(test)] +mod test { + use super::*; + use crate::metadata_ir::ExtrinsicMetadataIR; + use frame_metadata::{v14::META_RESERVED, RuntimeMetadata}; + use scale_info::meta_type; + + fn ir_metadata() -> MetadataIR { + MetadataIR { + pallets: vec![], + extrinsic: ExtrinsicMetadataIR { + ty: meta_type::<()>(), + version: 0, + signed_extensions: vec![], + }, + ty: meta_type::<()>(), + } + } + + #[test] + fn into_version_14() { + let ir = ir_metadata(); + let metadata = into_version(ir, V14).expect("Should return prefixed metadata"); + + assert_eq!(metadata.0, META_RESERVED); + + assert!(matches!(metadata.1, RuntimeMetadata::V14(_))); + } +} diff --git a/frame/support/src/metadata_ir/types.rs b/frame/support/src/metadata_ir/types.rs new file mode 100644 index 0000000000000..087fd3dcad249 --- /dev/null +++ b/frame/support/src/metadata_ir/types.rs @@ -0,0 +1,329 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT 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::Encode; +use scale_info::{ + form::{Form, MetaForm, PortableForm}, + prelude::vec::Vec, + IntoPortable, MetaType, Registry, +}; + +/// The intermediate representation for the runtime metadata. +/// Contains the needed context that allows conversion to multiple metadata versions. +/// +/// # Note +/// +/// Further fields could be added or removed to ensure proper conversion. +/// When the IR does not contain enough information to generate a specific version +/// of the runtime metadata an appropriate default value is used (ie, empty vector). +pub struct MetadataIR { + /// Pallet metadata. + pub pallets: Vec>, + /// Metadata of the extrinsic. + pub extrinsic: ExtrinsicMetadataIR, + /// The type of the `Runtime`. + pub ty: T::Type, +} + +/// The intermediate representation for a pallet metadata. +#[derive(Clone, PartialEq, Eq, Encode, Debug)] +pub struct PalletMetadataIR { + /// Pallet name. + pub name: T::String, + /// Pallet storage metadata. + pub storage: Option>, + /// Pallet calls metadata. + pub calls: Option>, + /// Pallet event metadata. + pub event: Option>, + /// Pallet constants metadata. + pub constants: Vec>, + /// Pallet error metadata. + pub error: Option>, + /// Define the index of the pallet, this index will be used for the encoding of pallet event, + /// call and origin variants. + pub index: u8, + /// Pallet documentation. + pub docs: Vec, +} + +impl IntoPortable for PalletMetadataIR { + type Output = PalletMetadataIR; + + fn into_portable(self, registry: &mut Registry) -> Self::Output { + PalletMetadataIR { + name: self.name.into_portable(registry), + storage: self.storage.map(|storage| storage.into_portable(registry)), + calls: self.calls.map(|calls| calls.into_portable(registry)), + event: self.event.map(|event| event.into_portable(registry)), + constants: registry.map_into_portable(self.constants), + error: self.error.map(|error| error.into_portable(registry)), + index: self.index, + docs: registry.map_into_portable(self.docs), + } + } +} + +/// Metadata of the extrinsic used by the runtime. +#[derive(Clone, PartialEq, Eq, Encode, Debug)] +pub struct ExtrinsicMetadataIR { + /// The type of the extrinsic. + pub ty: T::Type, + /// Extrinsic version. + pub version: u8, + /// The signed extensions in the order they appear in the extrinsic. + pub signed_extensions: Vec>, +} + +impl IntoPortable for ExtrinsicMetadataIR { + type Output = ExtrinsicMetadataIR; + + fn into_portable(self, registry: &mut Registry) -> Self::Output { + ExtrinsicMetadataIR { + ty: registry.register_type(&self.ty), + version: self.version, + signed_extensions: registry.map_into_portable(self.signed_extensions), + } + } +} + +/// Metadata of an extrinsic's signed extension. +#[derive(Clone, PartialEq, Eq, Encode, Debug)] +pub struct SignedExtensionMetadataIR { + /// The unique signed extension identifier, which may be different from the type name. + pub identifier: T::String, + /// The type of the signed extension, with the data to be included in the extrinsic. + pub ty: T::Type, + /// The type of the additional signed data, with the data to be included in the signed payload + pub additional_signed: T::Type, +} + +impl IntoPortable for SignedExtensionMetadataIR { + type Output = SignedExtensionMetadataIR; + + fn into_portable(self, registry: &mut Registry) -> Self::Output { + SignedExtensionMetadataIR { + identifier: self.identifier.into_portable(registry), + ty: registry.register_type(&self.ty), + additional_signed: registry.register_type(&self.additional_signed), + } + } +} + +/// All metadata of the pallet's storage. +#[derive(Clone, PartialEq, Eq, Encode, Debug)] +/// The common prefix used by all storage entries. +pub struct PalletStorageMetadataIR { + /// The common prefix used by all storage entries. + pub prefix: T::String, + /// Metadata for all storage entries. + pub entries: Vec>, +} + +impl IntoPortable for PalletStorageMetadataIR { + type Output = PalletStorageMetadataIR; + + fn into_portable(self, registry: &mut Registry) -> Self::Output { + PalletStorageMetadataIR { + prefix: self.prefix.into_portable(registry), + entries: registry.map_into_portable(self.entries), + } + } +} + +/// Metadata about one storage entry. +#[derive(Clone, PartialEq, Eq, Encode, Debug)] +pub struct StorageEntryMetadataIR { + /// Variable name of the storage entry. + pub name: T::String, + /// An `Option` modifier of that storage entry. + pub modifier: StorageEntryModifierIR, + /// Type of the value stored in the entry. + pub ty: StorageEntryTypeIR, + /// Default value (SCALE encoded). + pub default: Vec, + /// Storage entry documentation. + pub docs: Vec, +} + +impl IntoPortable for StorageEntryMetadataIR { + type Output = StorageEntryMetadataIR; + + fn into_portable(self, registry: &mut Registry) -> Self::Output { + StorageEntryMetadataIR { + name: self.name.into_portable(registry), + modifier: self.modifier, + ty: self.ty.into_portable(registry), + default: self.default, + docs: registry.map_into_portable(self.docs), + } + } +} + +/// A storage entry modifier indicates how a storage entry is returned when fetched and what the +/// value will be if the key is not present. Specifically this refers to the "return type" when +/// fetching a storage entry, and what the value will be if the key is not present. +/// +/// `Optional` means you should expect an `Option`, with `None` returned if the key is not +/// present. `Default` means you should expect a `T` with the default value of default if the key is +/// not present. +#[derive(Clone, PartialEq, Eq, Encode, Debug)] +pub enum StorageEntryModifierIR { + /// The storage entry returns an `Option`, with `None` if the key is not present. + Optional, + /// The storage entry returns `T::Default` if the key is not present. + Default, +} + +/// Hasher used by storage maps +#[derive(Clone, PartialEq, Eq, Encode, Debug)] +pub enum StorageHasherIR { + /// 128-bit Blake2 hash. + Blake2_128, + /// 256-bit Blake2 hash. + Blake2_256, + /// Multiple 128-bit Blake2 hashes concatenated. + Blake2_128Concat, + /// 128-bit XX hash. + Twox128, + /// 256-bit XX hash. + Twox256, + /// Multiple 64-bit XX hashes concatenated. + Twox64Concat, + /// Identity hashing (no hashing). + Identity, +} + +/// A type of storage value. +#[derive(Clone, PartialEq, Eq, Encode, Debug)] +pub enum StorageEntryTypeIR { + /// Plain storage entry (just the value). + Plain(T::Type), + /// A storage map. + Map { + /// One or more hashers, should be one hasher per key element. + hashers: Vec, + /// The type of the key, can be a tuple with elements for each of the hashers. + key: T::Type, + /// The type of the value. + value: T::Type, + }, +} + +impl IntoPortable for StorageEntryTypeIR { + type Output = StorageEntryTypeIR; + + fn into_portable(self, registry: &mut Registry) -> Self::Output { + match self { + Self::Plain(plain) => StorageEntryTypeIR::Plain(registry.register_type(&plain)), + Self::Map { hashers, key, value } => StorageEntryTypeIR::Map { + hashers, + key: registry.register_type(&key), + value: registry.register_type(&value), + }, + } + } +} + +/// Metadata for all calls in a pallet +#[derive(Clone, PartialEq, Eq, Encode, Debug)] +pub struct PalletCallMetadataIR { + /// The corresponding enum type for the pallet call. + pub ty: T::Type, +} + +impl IntoPortable for PalletCallMetadataIR { + type Output = PalletCallMetadataIR; + + fn into_portable(self, registry: &mut Registry) -> Self::Output { + PalletCallMetadataIR { ty: registry.register_type(&self.ty) } + } +} + +impl From for PalletCallMetadataIR { + fn from(ty: MetaType) -> Self { + Self { ty } + } +} + +/// Metadata about the pallet Event type. +#[derive(Clone, PartialEq, Eq, Encode, Debug)] +pub struct PalletEventMetadataIR { + /// The Event type. + pub ty: T::Type, +} + +impl IntoPortable for PalletEventMetadataIR { + type Output = PalletEventMetadataIR; + + fn into_portable(self, registry: &mut Registry) -> Self::Output { + PalletEventMetadataIR { ty: registry.register_type(&self.ty) } + } +} + +impl From for PalletEventMetadataIR { + fn from(ty: MetaType) -> Self { + Self { ty } + } +} + +/// Metadata about one pallet constant. +#[derive(Clone, PartialEq, Eq, Encode, Debug)] +pub struct PalletConstantMetadataIR { + /// Name of the pallet constant. + pub name: T::String, + /// Type of the pallet constant. + pub ty: T::Type, + /// Value stored in the constant (SCALE encoded). + pub value: Vec, + /// Documentation of the constant. + pub docs: Vec, +} + +impl IntoPortable for PalletConstantMetadataIR { + type Output = PalletConstantMetadataIR; + + fn into_portable(self, registry: &mut Registry) -> Self::Output { + PalletConstantMetadataIR { + name: self.name.into_portable(registry), + ty: registry.register_type(&self.ty), + value: self.value, + docs: registry.map_into_portable(self.docs), + } + } +} + +/// Metadata about a pallet error. +#[derive(Clone, PartialEq, Eq, Encode, Debug)] +pub struct PalletErrorMetadataIR { + /// The error type information. + pub ty: T::Type, +} + +impl IntoPortable for PalletErrorMetadataIR { + type Output = PalletErrorMetadataIR; + + fn into_portable(self, registry: &mut Registry) -> Self::Output { + PalletErrorMetadataIR { ty: registry.register_type(&self.ty) } + } +} + +impl From for PalletErrorMetadataIR { + fn from(ty: MetaType) -> Self { + Self { ty } + } +} diff --git a/frame/support/src/metadata_ir/v14.rs b/frame/support/src/metadata_ir/v14.rs new file mode 100644 index 0000000000000..e1b7a24f76577 --- /dev/null +++ b/frame/support/src/metadata_ir/v14.rs @@ -0,0 +1,158 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Convert the IR to V14 metadata. + +use super::types::{ + ExtrinsicMetadataIR, MetadataIR, PalletCallMetadataIR, PalletConstantMetadataIR, + PalletErrorMetadataIR, PalletEventMetadataIR, PalletMetadataIR, PalletStorageMetadataIR, + SignedExtensionMetadataIR, StorageEntryMetadataIR, StorageEntryModifierIR, StorageEntryTypeIR, + StorageHasherIR, +}; + +use frame_metadata::v14::{ + ExtrinsicMetadata, PalletCallMetadata, PalletConstantMetadata, PalletErrorMetadata, + PalletEventMetadata, PalletMetadata, PalletStorageMetadata, RuntimeMetadataV14, + SignedExtensionMetadata, StorageEntryMetadata, StorageEntryModifier, StorageEntryType, + StorageHasher, +}; + +impl From for RuntimeMetadataV14 { + fn from(ir: MetadataIR) -> Self { + RuntimeMetadataV14::new( + ir.pallets.into_iter().map(Into::into).collect(), + ir.extrinsic.into(), + ir.ty, + ) + } +} + +impl From for PalletMetadata { + fn from(ir: PalletMetadataIR) -> Self { + PalletMetadata { + name: ir.name, + storage: ir.storage.map(Into::into), + calls: ir.calls.map(Into::into), + event: ir.event.map(Into::into), + constants: ir.constants.into_iter().map(Into::into).collect(), + error: ir.error.map(Into::into), + index: ir.index, + // Note: ir.docs not part of v14. + } + } +} + +impl From for StorageEntryModifier { + fn from(ir: StorageEntryModifierIR) -> Self { + match ir { + StorageEntryModifierIR::Optional => StorageEntryModifier::Optional, + StorageEntryModifierIR::Default => StorageEntryModifier::Default, + } + } +} + +impl From for StorageHasher { + fn from(ir: StorageHasherIR) -> Self { + match ir { + StorageHasherIR::Blake2_128 => StorageHasher::Blake2_128, + StorageHasherIR::Blake2_256 => StorageHasher::Blake2_256, + StorageHasherIR::Blake2_128Concat => StorageHasher::Blake2_128Concat, + StorageHasherIR::Twox128 => StorageHasher::Twox128, + StorageHasherIR::Twox256 => StorageHasher::Twox256, + StorageHasherIR::Twox64Concat => StorageHasher::Twox64Concat, + StorageHasherIR::Identity => StorageHasher::Identity, + } + } +} + +impl From for StorageEntryType { + fn from(ir: StorageEntryTypeIR) -> Self { + match ir { + StorageEntryTypeIR::Plain(ty) => StorageEntryType::Plain(ty), + StorageEntryTypeIR::Map { hashers, key, value } => StorageEntryType::Map { + hashers: hashers.into_iter().map(Into::into).collect(), + key, + value, + }, + } + } +} + +impl From for StorageEntryMetadata { + fn from(ir: StorageEntryMetadataIR) -> Self { + StorageEntryMetadata { + name: ir.name, + modifier: ir.modifier.into(), + ty: ir.ty.into(), + default: ir.default, + docs: ir.docs, + } + } +} + +impl From for PalletStorageMetadata { + fn from(ir: PalletStorageMetadataIR) -> Self { + PalletStorageMetadata { + prefix: ir.prefix, + entries: ir.entries.into_iter().map(Into::into).collect(), + } + } +} + +impl From for PalletCallMetadata { + fn from(ir: PalletCallMetadataIR) -> Self { + PalletCallMetadata { ty: ir.ty } + } +} + +impl From for PalletEventMetadata { + fn from(ir: PalletEventMetadataIR) -> Self { + PalletEventMetadata { ty: ir.ty } + } +} + +impl From for PalletConstantMetadata { + fn from(ir: PalletConstantMetadataIR) -> Self { + PalletConstantMetadata { name: ir.name, ty: ir.ty, value: ir.value, docs: ir.docs } + } +} + +impl From for PalletErrorMetadata { + fn from(ir: PalletErrorMetadataIR) -> Self { + PalletErrorMetadata { ty: ir.ty } + } +} + +impl From for SignedExtensionMetadata { + fn from(ir: SignedExtensionMetadataIR) -> Self { + SignedExtensionMetadata { + identifier: ir.identifier, + ty: ir.ty, + additional_signed: ir.additional_signed, + } + } +} + +impl From for ExtrinsicMetadata { + fn from(ir: ExtrinsicMetadataIR) -> Self { + ExtrinsicMetadata { + ty: ir.ty, + version: ir.version, + signed_extensions: ir.signed_extensions.into_iter().map(Into::into).collect(), + } + } +} diff --git a/frame/support/src/storage/types/counted_map.rs b/frame/support/src/storage/types/counted_map.rs index 24b00be485e49..e57942cbe0667 100644 --- a/frame/support/src/storage/types/counted_map.rs +++ b/frame/support/src/storage/types/counted_map.rs @@ -18,7 +18,7 @@ //! Storage counted map type. use crate::{ - metadata::StorageEntryMetadata, + metadata_ir::StorageEntryMetadataIR, storage::{ generator::StorageMap as _, types::{ @@ -459,7 +459,7 @@ where OnEmpty: Get + 'static, MaxValues: Get>, { - fn build_metadata(docs: Vec<&'static str>, entries: &mut Vec) { + fn build_metadata(docs: Vec<&'static str>, entries: &mut Vec) { ::Map::build_metadata(docs, entries); CounterFor::::build_metadata( if cfg!(feature = "no-metadata-docs") { @@ -512,7 +512,7 @@ mod test { use super::*; use crate::{ hash::*, - metadata::{StorageEntryModifier, StorageEntryType, StorageHasher}, + metadata_ir::{StorageEntryModifierIR, StorageEntryTypeIR, StorageHasherIR}, storage::{bounded_vec::BoundedVec, types::ValueQuery}, traits::ConstU32, }; @@ -1147,21 +1147,21 @@ mod test { assert_eq!( entries, vec![ - StorageEntryMetadata { + StorageEntryMetadataIR { name: "foo", - modifier: StorageEntryModifier::Default, - ty: StorageEntryType::Map { - hashers: vec![StorageHasher::Twox64Concat], + modifier: StorageEntryModifierIR::Default, + ty: StorageEntryTypeIR::Map { + hashers: vec![StorageHasherIR::Twox64Concat], key: scale_info::meta_type::(), value: scale_info::meta_type::(), }, default: 97u32.encode(), docs: vec![], }, - StorageEntryMetadata { + StorageEntryMetadataIR { name: "counter_for_foo", - modifier: StorageEntryModifier::Default, - ty: StorageEntryType::Plain(scale_info::meta_type::()), + modifier: StorageEntryModifierIR::Default, + ty: StorageEntryTypeIR::Plain(scale_info::meta_type::()), default: vec![0, 0, 0, 0], docs: if cfg!(feature = "no-metadata-docs") { vec![] diff --git a/frame/support/src/storage/types/double_map.rs b/frame/support/src/storage/types/double_map.rs index 6a4bdc1e68d72..08ac1709c4b68 100644 --- a/frame/support/src/storage/types/double_map.rs +++ b/frame/support/src/storage/types/double_map.rs @@ -19,7 +19,7 @@ //! StoragePrefixedDoubleMap traits and their methods directly. use crate::{ - metadata::{StorageEntryMetadata, StorageEntryType}, + metadata_ir::{StorageEntryMetadataIR, StorageEntryTypeIR}, storage::{ types::{OptionQuery, QueryKindTrait, StorageEntryMetadataBuilder}, KeyLenOf, StorageAppend, StorageDecodeLength, StoragePrefixedMap, StorageTryAppend, @@ -656,13 +656,13 @@ where OnEmpty: Get + 'static, MaxValues: Get>, { - fn build_metadata(docs: Vec<&'static str>, entries: &mut Vec) { + fn build_metadata(docs: Vec<&'static str>, entries: &mut Vec) { let docs = if cfg!(feature = "no-metadata-docs") { vec![] } else { docs }; - let entry = StorageEntryMetadata { + let entry = StorageEntryMetadataIR { name: Prefix::STORAGE_PREFIX, modifier: QueryKind::METADATA, - ty: StorageEntryType::Map { + ty: StorageEntryTypeIR::Map { hashers: vec![Hasher1::METADATA, Hasher2::METADATA], key: scale_info::meta_type::<(Key1, Key2)>(), value: scale_info::meta_type::(), @@ -736,7 +736,7 @@ mod test { use super::*; use crate::{ hash::*, - metadata::{StorageEntryModifier, StorageEntryType, StorageHasher}, + metadata_ir::{StorageEntryModifierIR, StorageEntryTypeIR, StorageHasherIR}, storage::types::ValueQuery, }; use sp_io::{hashing::twox_128, TestExternalities}; @@ -916,13 +916,13 @@ mod test { assert_eq!( entries, vec![ - StorageEntryMetadata { + StorageEntryMetadataIR { name: "foo", - modifier: StorageEntryModifier::Optional, - ty: StorageEntryType::Map { + modifier: StorageEntryModifierIR::Optional, + ty: StorageEntryTypeIR::Map { hashers: vec![ - StorageHasher::Blake2_128Concat, - StorageHasher::Twox64Concat + StorageHasherIR::Blake2_128Concat, + StorageHasherIR::Twox64Concat ], key: scale_info::meta_type::<(u16, u8)>(), value: scale_info::meta_type::(), @@ -930,13 +930,13 @@ mod test { default: Option::::None.encode(), docs: vec![], }, - StorageEntryMetadata { + StorageEntryMetadataIR { name: "foo", - modifier: StorageEntryModifier::Default, - ty: StorageEntryType::Map { + modifier: StorageEntryModifierIR::Default, + ty: StorageEntryTypeIR::Map { hashers: vec![ - StorageHasher::Blake2_128Concat, - StorageHasher::Twox64Concat + StorageHasherIR::Blake2_128Concat, + StorageHasherIR::Twox64Concat ], key: scale_info::meta_type::<(u16, u8)>(), value: scale_info::meta_type::(), diff --git a/frame/support/src/storage/types/key.rs b/frame/support/src/storage/types/key.rs index 901bdb8b0514c..bf87e593b063a 100755 --- a/frame/support/src/storage/types/key.rs +++ b/frame/support/src/storage/types/key.rs @@ -41,7 +41,7 @@ pub trait KeyGenerator { type HashFn: FnOnce(&[u8]) -> Vec; type HArg; - const HASHER_METADATA: &'static [crate::metadata::StorageHasher]; + const HASHER_METADATA: &'static [crate::metadata_ir::StorageHasherIR]; /// Given a `key` tuple, calculate the final key by encoding each element individually and /// hashing them using the corresponding hasher in the `KeyGenerator`. @@ -74,7 +74,7 @@ impl KeyGenerator for Key type HashFn = Box Vec>; type HArg = (Self::HashFn,); - const HASHER_METADATA: &'static [crate::metadata::StorageHasher] = &[H::METADATA]; + const HASHER_METADATA: &'static [crate::metadata_ir::StorageHasherIR] = &[H::METADATA]; fn final_key + TupleToEncodedIter>(key: KArg) -> Vec { H::hash(&key.to_encoded_iter().next().expect("should have at least one element!")) @@ -114,7 +114,7 @@ impl KeyGenerator for Tuple { for_tuples!( type HArg = ( #(Tuple::HashFn),* ); ); type HashFn = Box Vec>; - const HASHER_METADATA: &'static [crate::metadata::StorageHasher] = + const HASHER_METADATA: &'static [crate::metadata_ir::StorageHasherIR] = &[for_tuples!( #(Tuple::Hasher::METADATA),* )]; fn final_key + TupleToEncodedIter>(key: KArg) -> Vec { diff --git a/frame/support/src/storage/types/map.rs b/frame/support/src/storage/types/map.rs index 53cf74d26f17c..2110732b2f69c 100644 --- a/frame/support/src/storage/types/map.rs +++ b/frame/support/src/storage/types/map.rs @@ -19,7 +19,7 @@ //! methods directly. use crate::{ - metadata::{StorageEntryMetadata, StorageEntryType}, + metadata_ir::{StorageEntryMetadataIR, StorageEntryTypeIR}, storage::{ types::{OptionQuery, QueryKindTrait, StorageEntryMetadataBuilder}, KeyLenOf, StorageAppend, StorageDecodeLength, StoragePrefixedMap, StorageTryAppend, @@ -409,13 +409,13 @@ where OnEmpty: Get + 'static, MaxValues: Get>, { - fn build_metadata(docs: Vec<&'static str>, entries: &mut Vec) { + fn build_metadata(docs: Vec<&'static str>, entries: &mut Vec) { let docs = if cfg!(feature = "no-metadata-docs") { vec![] } else { docs }; - let entry = StorageEntryMetadata { + let entry = StorageEntryMetadataIR { name: Prefix::STORAGE_PREFIX, modifier: QueryKind::METADATA, - ty: StorageEntryType::Map { + ty: StorageEntryTypeIR::Map { hashers: vec![Hasher::METADATA], key: scale_info::meta_type::(), value: scale_info::meta_type::(), @@ -483,7 +483,7 @@ mod test { use super::*; use crate::{ hash::*, - metadata::{StorageEntryModifier, StorageEntryType, StorageHasher}, + metadata_ir::{StorageEntryModifierIR, StorageEntryTypeIR, StorageHasherIR}, storage::types::ValueQuery, }; use sp_io::{hashing::twox_128, TestExternalities}; @@ -706,22 +706,22 @@ mod test { assert_eq!( entries, vec![ - StorageEntryMetadata { + StorageEntryMetadataIR { name: "foo", - modifier: StorageEntryModifier::Optional, - ty: StorageEntryType::Map { - hashers: vec![StorageHasher::Blake2_128Concat], + modifier: StorageEntryModifierIR::Optional, + ty: StorageEntryTypeIR::Map { + hashers: vec![StorageHasherIR::Blake2_128Concat], key: scale_info::meta_type::(), value: scale_info::meta_type::(), }, default: Option::::None.encode(), docs: vec![], }, - StorageEntryMetadata { + StorageEntryMetadataIR { name: "foo", - modifier: StorageEntryModifier::Default, - ty: StorageEntryType::Map { - hashers: vec![StorageHasher::Blake2_128Concat], + modifier: StorageEntryModifierIR::Default, + ty: StorageEntryTypeIR::Map { + hashers: vec![StorageHasherIR::Blake2_128Concat], key: scale_info::meta_type::(), value: scale_info::meta_type::(), }, diff --git a/frame/support/src/storage/types/mod.rs b/frame/support/src/storage/types/mod.rs index 9a6f15d1ee820..3a5bae2e608b7 100644 --- a/frame/support/src/storage/types/mod.rs +++ b/frame/support/src/storage/types/mod.rs @@ -18,7 +18,7 @@ //! Storage types to build abstraction on storage, they implements storage traits such as //! StorageMap and others. -use crate::metadata::{StorageEntryMetadata, StorageEntryModifier}; +use crate::metadata_ir::{StorageEntryMetadataIR, StorageEntryModifierIR}; use codec::FullCodec; use sp_std::prelude::*; @@ -50,7 +50,7 @@ pub use value::StorageValue; /// value. pub trait QueryKindTrait { /// Metadata for the storage kind. - const METADATA: StorageEntryModifier; + const METADATA: StorageEntryModifierIR; /// Type returned on query type Query: FullCodec + 'static; @@ -73,7 +73,7 @@ impl QueryKindTrait for OptionQuery where Value: FullCodec + 'static, { - const METADATA: StorageEntryModifier = StorageEntryModifier::Optional; + const METADATA: StorageEntryModifierIR = StorageEntryModifierIR::Optional; type Query = Option; @@ -95,7 +95,7 @@ where Error: FullCodec + 'static, OnEmpty: crate::traits::Get>, { - const METADATA: StorageEntryModifier = StorageEntryModifier::Optional; + const METADATA: StorageEntryModifierIR = StorageEntryModifierIR::Optional; type Query = Result; @@ -118,7 +118,7 @@ where Value: FullCodec + 'static, OnEmpty: crate::traits::Get, { - const METADATA: StorageEntryModifier = StorageEntryModifier::Default; + const METADATA: StorageEntryModifierIR = StorageEntryModifierIR::Default; type Query = Value; @@ -136,5 +136,5 @@ where /// Implemented by each of the storage types: value, map, countedmap, doublemap and nmap. pub trait StorageEntryMetadataBuilder { /// Build into `entries` the storage metadata entries of a storage given some `docs`. - fn build_metadata(doc: Vec<&'static str>, entries: &mut Vec); + fn build_metadata(doc: Vec<&'static str>, entries: &mut Vec); } diff --git a/frame/support/src/storage/types/nmap.rs b/frame/support/src/storage/types/nmap.rs index d971035968ff2..9b63ca7b0f417 100755 --- a/frame/support/src/storage/types/nmap.rs +++ b/frame/support/src/storage/types/nmap.rs @@ -19,7 +19,7 @@ //! StoragePrefixedDoubleMap traits and their methods directly. use crate::{ - metadata::{StorageEntryMetadata, StorageEntryType}, + metadata_ir::{StorageEntryMetadataIR, StorageEntryTypeIR}, storage::{ types::{ EncodeLikeTuple, HasKeyPrefix, HasReversibleKeyPrefix, OptionQuery, QueryKindTrait, @@ -550,13 +550,13 @@ where OnEmpty: Get + 'static, MaxValues: Get>, { - fn build_metadata(docs: Vec<&'static str>, entries: &mut Vec) { + fn build_metadata(docs: Vec<&'static str>, entries: &mut Vec) { let docs = if cfg!(feature = "no-metadata-docs") { vec![] } else { docs }; - let entry = StorageEntryMetadata { + let entry = StorageEntryMetadataIR { name: Prefix::STORAGE_PREFIX, modifier: QueryKind::METADATA, - ty: StorageEntryType::Map { + ty: StorageEntryTypeIR::Map { key: scale_info::meta_type::(), hashers: Key::HASHER_METADATA.to_vec(), value: scale_info::meta_type::(), @@ -620,7 +620,7 @@ mod test { use super::*; use crate::{ hash::{StorageHasher as _, *}, - metadata::{StorageEntryModifier, StorageHasher}, + metadata_ir::{StorageEntryModifierIR, StorageHasherIR}, storage::types::{Key as NMapKey, ValueQuery}, }; use sp_io::{hashing::twox_128, TestExternalities}; @@ -791,22 +791,22 @@ mod test { assert_eq!( entries, vec![ - StorageEntryMetadata { + StorageEntryMetadataIR { name: "Foo", - modifier: StorageEntryModifier::Optional, - ty: StorageEntryType::Map { - hashers: vec![StorageHasher::Blake2_128Concat], + modifier: StorageEntryModifierIR::Optional, + ty: StorageEntryTypeIR::Map { + hashers: vec![StorageHasherIR::Blake2_128Concat], key: scale_info::meta_type::(), value: scale_info::meta_type::(), }, default: Option::::None.encode(), docs: vec![], }, - StorageEntryMetadata { + StorageEntryMetadataIR { name: "Foo", - modifier: StorageEntryModifier::Default, - ty: StorageEntryType::Map { - hashers: vec![StorageHasher::Blake2_128Concat], + modifier: StorageEntryModifierIR::Default, + ty: StorageEntryTypeIR::Map { + hashers: vec![StorageHasherIR::Blake2_128Concat], key: scale_info::meta_type::(), value: scale_info::meta_type::(), }, @@ -991,13 +991,13 @@ mod test { assert_eq!( entries, vec![ - StorageEntryMetadata { + StorageEntryMetadataIR { name: "Foo", - modifier: StorageEntryModifier::Optional, - ty: StorageEntryType::Map { + modifier: StorageEntryModifierIR::Optional, + ty: StorageEntryTypeIR::Map { hashers: vec![ - StorageHasher::Blake2_128Concat, - StorageHasher::Twox64Concat + StorageHasherIR::Blake2_128Concat, + StorageHasherIR::Twox64Concat ], key: scale_info::meta_type::<(u16, u8)>(), value: scale_info::meta_type::(), @@ -1005,13 +1005,13 @@ mod test { default: Option::::None.encode(), docs: vec![], }, - StorageEntryMetadata { + StorageEntryMetadataIR { name: "Foo", - modifier: StorageEntryModifier::Default, - ty: StorageEntryType::Map { + modifier: StorageEntryModifierIR::Default, + ty: StorageEntryTypeIR::Map { hashers: vec![ - StorageHasher::Blake2_128Concat, - StorageHasher::Twox64Concat + StorageHasherIR::Blake2_128Concat, + StorageHasherIR::Twox64Concat ], key: scale_info::meta_type::<(u16, u8)>(), value: scale_info::meta_type::(), @@ -1232,14 +1232,14 @@ mod test { assert_eq!( entries, vec![ - StorageEntryMetadata { + StorageEntryMetadataIR { name: "Foo", - modifier: StorageEntryModifier::Optional, - ty: StorageEntryType::Map { + modifier: StorageEntryModifierIR::Optional, + ty: StorageEntryTypeIR::Map { hashers: vec![ - StorageHasher::Blake2_128Concat, - StorageHasher::Blake2_128Concat, - StorageHasher::Twox64Concat + StorageHasherIR::Blake2_128Concat, + StorageHasherIR::Blake2_128Concat, + StorageHasherIR::Twox64Concat ], key: scale_info::meta_type::<(u16, u16, u16)>(), value: scale_info::meta_type::(), @@ -1247,14 +1247,14 @@ mod test { default: Option::::None.encode(), docs: vec![], }, - StorageEntryMetadata { + StorageEntryMetadataIR { name: "Foo", - modifier: StorageEntryModifier::Default, - ty: StorageEntryType::Map { + modifier: StorageEntryModifierIR::Default, + ty: StorageEntryTypeIR::Map { hashers: vec![ - StorageHasher::Blake2_128Concat, - StorageHasher::Blake2_128Concat, - StorageHasher::Twox64Concat + StorageHasherIR::Blake2_128Concat, + StorageHasherIR::Blake2_128Concat, + StorageHasherIR::Twox64Concat ], key: scale_info::meta_type::<(u16, u16, u16)>(), value: scale_info::meta_type::(), diff --git a/frame/support/src/storage/types/value.rs b/frame/support/src/storage/types/value.rs index 64fb432b2dab1..d5fbb0656bbd1 100644 --- a/frame/support/src/storage/types/value.rs +++ b/frame/support/src/storage/types/value.rs @@ -18,7 +18,7 @@ //! Storage value type. Implements StorageValue trait and its method directly. use crate::{ - metadata::{StorageEntryMetadata, StorageEntryType}, + metadata_ir::{StorageEntryMetadataIR, StorageEntryTypeIR}, storage::{ generator::StorageValue as StorageValueT, types::{OptionQuery, QueryKindTrait, StorageEntryMetadataBuilder}, @@ -221,13 +221,13 @@ where QueryKind: QueryKindTrait, OnEmpty: crate::traits::Get + 'static, { - fn build_metadata(docs: Vec<&'static str>, entries: &mut Vec) { + fn build_metadata(docs: Vec<&'static str>, entries: &mut Vec) { let docs = if cfg!(feature = "no-metadata-docs") { vec![] } else { docs }; - let entry = StorageEntryMetadata { + let entry = StorageEntryMetadataIR { name: Prefix::STORAGE_PREFIX, modifier: QueryKind::METADATA, - ty: StorageEntryType::Plain(scale_info::meta_type::()), + ty: StorageEntryTypeIR::Plain(scale_info::meta_type::()), default: OnEmpty::get().encode(), docs, }; @@ -278,7 +278,7 @@ where #[cfg(test)] mod test { use super::*; - use crate::{metadata::StorageEntryModifier, storage::types::ValueQuery}; + use crate::{metadata_ir::StorageEntryModifierIR, storage::types::ValueQuery}; use sp_io::{hashing::twox_128, TestExternalities}; struct Prefix; @@ -363,17 +363,17 @@ mod test { assert_eq!( entries, vec![ - StorageEntryMetadata { + StorageEntryMetadataIR { name: "foo", - modifier: StorageEntryModifier::Optional, - ty: StorageEntryType::Plain(scale_info::meta_type::()), + modifier: StorageEntryModifierIR::Optional, + ty: StorageEntryTypeIR::Plain(scale_info::meta_type::()), default: Option::::None.encode(), docs: vec![], }, - StorageEntryMetadata { + StorageEntryMetadataIR { name: "foo", - modifier: StorageEntryModifier::Default, - ty: StorageEntryType::Plain(scale_info::meta_type::()), + modifier: StorageEntryModifierIR::Default, + ty: StorageEntryTypeIR::Plain(scale_info::meta_type::()), default: 97u32.encode(), docs: vec![], } diff --git a/frame/support/test/tests/decl_storage.rs b/frame/support/test/tests/decl_storage.rs index c2ee7742426bb..bee1dc83d5589 100644 --- a/frame/support/test/tests/decl_storage.rs +++ b/frame/support/test/tests/decl_storage.rs @@ -19,7 +19,7 @@ // Do not complain about unused `dispatch` and `dispatch_aux`. #[allow(dead_code)] mod tests { - use frame_support::metadata::*; + use frame_support::metadata_ir::*; use sp_io::TestExternalities; frame_support::decl_module! { @@ -104,195 +104,195 @@ mod tests { type Origin2 = u32; } - fn expected_metadata() -> PalletStorageMetadata { - PalletStorageMetadata { + fn expected_metadata() -> PalletStorageMetadataIR { + PalletStorageMetadataIR { prefix: "TestStorage", entries: vec![ - StorageEntryMetadata { + StorageEntryMetadataIR { name: "U32", - modifier: StorageEntryModifier::Optional, - ty: StorageEntryType::Plain(scale_info::meta_type::()), + modifier: StorageEntryModifierIR::Optional, + ty: StorageEntryTypeIR::Plain(scale_info::meta_type::()), default: vec![0], docs: vec![" Hello, this is doc!"], }, - StorageEntryMetadata { + StorageEntryMetadataIR { name: "PUBU32", - modifier: StorageEntryModifier::Optional, - ty: StorageEntryType::Plain(scale_info::meta_type::()), + modifier: StorageEntryModifierIR::Optional, + ty: StorageEntryTypeIR::Plain(scale_info::meta_type::()), default: vec![0], docs: vec![], }, - StorageEntryMetadata { + StorageEntryMetadataIR { name: "U32MYDEF", - modifier: StorageEntryModifier::Optional, - ty: StorageEntryType::Plain(scale_info::meta_type::()), + modifier: StorageEntryModifierIR::Optional, + ty: StorageEntryTypeIR::Plain(scale_info::meta_type::()), default: vec![0], docs: vec![], }, - StorageEntryMetadata { + StorageEntryMetadataIR { name: "PUBU32MYDEF", - modifier: StorageEntryModifier::Optional, - ty: StorageEntryType::Plain(scale_info::meta_type::()), + modifier: StorageEntryModifierIR::Optional, + ty: StorageEntryTypeIR::Plain(scale_info::meta_type::()), default: vec![0], docs: vec![], }, - StorageEntryMetadata { + StorageEntryMetadataIR { name: "GETU32", - modifier: StorageEntryModifier::Default, - ty: StorageEntryType::Plain(scale_info::meta_type::()), + modifier: StorageEntryModifierIR::Default, + ty: StorageEntryTypeIR::Plain(scale_info::meta_type::()), default: vec![0, 0, 0, 0], docs: vec![], }, - StorageEntryMetadata { + StorageEntryMetadataIR { name: "PUBGETU32", - modifier: StorageEntryModifier::Default, - ty: StorageEntryType::Plain(scale_info::meta_type::()), + modifier: StorageEntryModifierIR::Default, + ty: StorageEntryTypeIR::Plain(scale_info::meta_type::()), default: vec![0, 0, 0, 0], docs: vec![], }, - StorageEntryMetadata { + StorageEntryMetadataIR { name: "GETU32WITHCONFIG", - modifier: StorageEntryModifier::Default, - ty: StorageEntryType::Plain(scale_info::meta_type::()), + modifier: StorageEntryModifierIR::Default, + ty: StorageEntryTypeIR::Plain(scale_info::meta_type::()), default: vec![0, 0, 0, 0], docs: vec![], }, - StorageEntryMetadata { + StorageEntryMetadataIR { name: "PUBGETU32WITHCONFIG", - modifier: StorageEntryModifier::Default, - ty: StorageEntryType::Plain(scale_info::meta_type::()), + modifier: StorageEntryModifierIR::Default, + ty: StorageEntryTypeIR::Plain(scale_info::meta_type::()), default: vec![0, 0, 0, 0], docs: vec![], }, - StorageEntryMetadata { + StorageEntryMetadataIR { name: "GETU32MYDEF", - modifier: StorageEntryModifier::Optional, - ty: StorageEntryType::Plain(scale_info::meta_type::()), + modifier: StorageEntryModifierIR::Optional, + ty: StorageEntryTypeIR::Plain(scale_info::meta_type::()), default: vec![0], docs: vec![], }, - StorageEntryMetadata { + StorageEntryMetadataIR { name: "PUBGETU32MYDEF", - modifier: StorageEntryModifier::Default, - ty: StorageEntryType::Plain(scale_info::meta_type::()), + modifier: StorageEntryModifierIR::Default, + ty: StorageEntryTypeIR::Plain(scale_info::meta_type::()), default: vec![3, 0, 0, 0], docs: vec![], }, - StorageEntryMetadata { + StorageEntryMetadataIR { name: "GETU32WITHCONFIGMYDEF", - modifier: StorageEntryModifier::Default, - ty: StorageEntryType::Plain(scale_info::meta_type::()), + modifier: StorageEntryModifierIR::Default, + ty: StorageEntryTypeIR::Plain(scale_info::meta_type::()), default: vec![2, 0, 0, 0], docs: vec![], }, - StorageEntryMetadata { + StorageEntryMetadataIR { name: "PUBGETU32WITHCONFIGMYDEF", - modifier: StorageEntryModifier::Default, - ty: StorageEntryType::Plain(scale_info::meta_type::()), + modifier: StorageEntryModifierIR::Default, + ty: StorageEntryTypeIR::Plain(scale_info::meta_type::()), default: vec![1, 0, 0, 0], docs: vec![], }, - StorageEntryMetadata { + StorageEntryMetadataIR { name: "PUBGETU32WITHCONFIGMYDEFOPT", - modifier: StorageEntryModifier::Optional, - ty: StorageEntryType::Plain(scale_info::meta_type::()), + modifier: StorageEntryModifierIR::Optional, + ty: StorageEntryTypeIR::Plain(scale_info::meta_type::()), default: vec![0], docs: vec![], }, - StorageEntryMetadata { + StorageEntryMetadataIR { name: "GetU32WithBuilder", - modifier: StorageEntryModifier::Default, - ty: StorageEntryType::Plain(scale_info::meta_type::()), + modifier: StorageEntryModifierIR::Default, + ty: StorageEntryTypeIR::Plain(scale_info::meta_type::()), default: vec![0, 0, 0, 0], docs: vec![], }, - StorageEntryMetadata { + StorageEntryMetadataIR { name: "GetOptU32WithBuilderSome", - modifier: StorageEntryModifier::Optional, - ty: StorageEntryType::Plain(scale_info::meta_type::()), + modifier: StorageEntryModifierIR::Optional, + ty: StorageEntryTypeIR::Plain(scale_info::meta_type::()), default: vec![0], docs: vec![], }, - StorageEntryMetadata { + StorageEntryMetadataIR { name: "GetOptU32WithBuilderNone", - modifier: StorageEntryModifier::Optional, - ty: StorageEntryType::Plain(scale_info::meta_type::()), + modifier: StorageEntryModifierIR::Optional, + ty: StorageEntryTypeIR::Plain(scale_info::meta_type::()), default: vec![0], docs: vec![], }, - StorageEntryMetadata { + StorageEntryMetadataIR { name: "MAPU32", - modifier: StorageEntryModifier::Optional, - ty: StorageEntryType::Map { - hashers: vec![StorageHasher::Blake2_128Concat], + modifier: StorageEntryModifierIR::Optional, + ty: StorageEntryTypeIR::Map { + hashers: vec![StorageHasherIR::Blake2_128Concat], key: scale_info::meta_type::(), value: scale_info::meta_type::<[u8; 4]>(), }, default: vec![0], docs: vec![], }, - StorageEntryMetadata { + StorageEntryMetadataIR { name: "PUBMAPU32", - modifier: StorageEntryModifier::Optional, - ty: StorageEntryType::Map { - hashers: vec![StorageHasher::Blake2_128Concat], + modifier: StorageEntryModifierIR::Optional, + ty: StorageEntryTypeIR::Map { + hashers: vec![StorageHasherIR::Blake2_128Concat], key: scale_info::meta_type::(), value: scale_info::meta_type::<[u8; 4]>(), }, default: vec![0], docs: vec![], }, - StorageEntryMetadata { + StorageEntryMetadataIR { name: "GETMAPU32", - modifier: StorageEntryModifier::Default, - ty: StorageEntryType::Map { - hashers: vec![StorageHasher::Blake2_128Concat], + modifier: StorageEntryModifierIR::Default, + ty: StorageEntryTypeIR::Map { + hashers: vec![StorageHasherIR::Blake2_128Concat], key: scale_info::meta_type::(), value: scale_info::meta_type::<[u8; 4]>(), }, default: vec![0, 0, 0, 0], docs: vec![], }, - StorageEntryMetadata { + StorageEntryMetadataIR { name: "PUBGETMAPU32", - modifier: StorageEntryModifier::Default, - ty: StorageEntryType::Map { - hashers: vec![StorageHasher::Blake2_128Concat], + modifier: StorageEntryModifierIR::Default, + ty: StorageEntryTypeIR::Map { + hashers: vec![StorageHasherIR::Blake2_128Concat], key: scale_info::meta_type::(), value: scale_info::meta_type::<[u8; 4]>(), }, default: vec![0, 0, 0, 0], docs: vec![], }, - StorageEntryMetadata { + StorageEntryMetadataIR { name: "GETMAPU32MYDEF", - modifier: StorageEntryModifier::Default, - ty: StorageEntryType::Map { - hashers: vec![StorageHasher::Blake2_128Concat], + modifier: StorageEntryModifierIR::Default, + ty: StorageEntryTypeIR::Map { + hashers: vec![StorageHasherIR::Blake2_128Concat], key: scale_info::meta_type::(), value: scale_info::meta_type::<[u8; 4]>(), }, default: vec![109, 97, 112, 100], // "map" docs: vec![], }, - StorageEntryMetadata { + StorageEntryMetadataIR { name: "PUBGETMAPU32MYDEF", - modifier: StorageEntryModifier::Default, - ty: StorageEntryType::Map { - hashers: vec![StorageHasher::Blake2_128Concat], + modifier: StorageEntryModifierIR::Default, + ty: StorageEntryTypeIR::Map { + hashers: vec![StorageHasherIR::Blake2_128Concat], key: scale_info::meta_type::(), value: scale_info::meta_type::<[u8; 4]>(), }, default: vec![112, 117, 98, 109], // "pubmap" docs: vec![], }, - StorageEntryMetadata { + StorageEntryMetadataIR { name: "DOUBLEMAP", - modifier: StorageEntryModifier::Optional, - ty: StorageEntryType::Map { + modifier: StorageEntryModifierIR::Optional, + ty: StorageEntryTypeIR::Map { hashers: vec![ - StorageHasher::Blake2_128Concat, - StorageHasher::Blake2_128Concat, + StorageHasherIR::Blake2_128Concat, + StorageHasherIR::Blake2_128Concat, ], key: scale_info::meta_type::<(u32, u32)>(), value: scale_info::meta_type::<[u8; 4]>(), @@ -300,13 +300,13 @@ mod tests { default: vec![0], docs: vec![], }, - StorageEntryMetadata { + StorageEntryMetadataIR { name: "DOUBLEMAP2", - modifier: StorageEntryModifier::Optional, - ty: StorageEntryType::Map { + modifier: StorageEntryModifierIR::Optional, + ty: StorageEntryTypeIR::Map { hashers: vec![ - StorageHasher::Blake2_128Concat, - StorageHasher::Blake2_128Concat, + StorageHasherIR::Blake2_128Concat, + StorageHasherIR::Blake2_128Concat, ], key: scale_info::meta_type::<(u32, u32)>(), value: scale_info::meta_type::<[u8; 4]>(), @@ -314,47 +314,50 @@ mod tests { default: vec![0], docs: vec![], }, - StorageEntryMetadata { + StorageEntryMetadataIR { name: "COMPLEXTYPE1", - modifier: StorageEntryModifier::Default, - ty: StorageEntryType::Plain(scale_info::meta_type::<(Option,)>()), + modifier: StorageEntryModifierIR::Default, + ty: StorageEntryTypeIR::Plain(scale_info::meta_type::<(Option,)>()), default: vec![0], docs: vec![], }, - StorageEntryMetadata { + StorageEntryMetadataIR { name: "COMPLEXTYPE2", - modifier: StorageEntryModifier::Default, - ty: StorageEntryType::Plain(scale_info::meta_type::<( + modifier: StorageEntryModifierIR::Default, + ty: StorageEntryTypeIR::Plain(scale_info::meta_type::<( [[(u16, Option<()>); 32]; 12], u32, )>()), default: [0u8; 1156].to_vec(), docs: vec![], }, - StorageEntryMetadata { + StorageEntryMetadataIR { name: "COMPLEXTYPE3", - modifier: StorageEntryModifier::Default, - ty: StorageEntryType::Plain(scale_info::meta_type::<[u32; 25]>()), + modifier: StorageEntryModifierIR::Default, + ty: StorageEntryTypeIR::Plain(scale_info::meta_type::<[u32; 25]>()), default: [0u8; 100].to_vec(), docs: vec![], }, - StorageEntryMetadata { + StorageEntryMetadataIR { name: "NMAP", - modifier: StorageEntryModifier::Default, - ty: StorageEntryType::Map { + modifier: StorageEntryModifierIR::Default, + ty: StorageEntryTypeIR::Map { key: scale_info::meta_type::<(u32, u16)>(), - hashers: vec![StorageHasher::Blake2_128Concat, StorageHasher::Twox64Concat], + hashers: vec![ + StorageHasherIR::Blake2_128Concat, + StorageHasherIR::Twox64Concat, + ], value: scale_info::meta_type::(), }, default: vec![0], docs: vec![], }, - StorageEntryMetadata { + StorageEntryMetadataIR { name: "NMAP2", - modifier: StorageEntryModifier::Default, - ty: StorageEntryType::Map { + modifier: StorageEntryModifierIR::Default, + ty: StorageEntryTypeIR::Map { key: scale_info::meta_type::(), - hashers: vec![StorageHasher::Blake2_128Concat], + hashers: vec![StorageHasherIR::Blake2_128Concat], value: scale_info::meta_type::(), }, default: vec![0], diff --git a/frame/support/test/tests/instance.rs b/frame/support/test/tests/instance.rs index 8780e18405f27..9b08e175b1ca8 100644 --- a/frame/support/test/tests/instance.rs +++ b/frame/support/test/tests/instance.rs @@ -20,9 +20,9 @@ use codec::{Codec, Decode, Encode, EncodeLike, MaxEncodedLen}; use frame_support::{ inherent::{InherentData, InherentIdentifier, MakeFatalError, ProvideInherent}, - metadata::{ - PalletStorageMetadata, StorageEntryMetadata, StorageEntryModifier, StorageEntryType, - StorageHasher, + metadata_ir::{ + PalletStorageMetadataIR, StorageEntryMetadataIR, StorageEntryModifierIR, + StorageEntryTypeIR, StorageHasherIR, }, traits::{ConstU32, Get}, Parameter, StorageDoubleMap, StorageMap, StorageValue, @@ -410,33 +410,33 @@ fn storage_with_instance_basic_operation() { }); } -fn expected_metadata() -> PalletStorageMetadata { - PalletStorageMetadata { +fn expected_metadata() -> PalletStorageMetadataIR { + PalletStorageMetadataIR { prefix: "Instance2Module2", entries: vec![ - StorageEntryMetadata { + StorageEntryMetadataIR { name: "Value", - modifier: StorageEntryModifier::Default, - ty: StorageEntryType::Plain(scale_info::meta_type::()), + modifier: StorageEntryModifierIR::Default, + ty: StorageEntryTypeIR::Plain(scale_info::meta_type::()), default: vec![0, 0, 0, 0], docs: vec![], }, - StorageEntryMetadata { + StorageEntryMetadataIR { name: "Map", - modifier: StorageEntryModifier::Default, - ty: StorageEntryType::Map { - hashers: vec![StorageHasher::Identity], + modifier: StorageEntryModifierIR::Default, + ty: StorageEntryTypeIR::Map { + hashers: vec![StorageHasherIR::Identity], key: scale_info::meta_type::(), value: scale_info::meta_type::(), }, default: [0u8; 8].to_vec(), docs: vec![], }, - StorageEntryMetadata { + StorageEntryMetadataIR { name: "DoubleMap", - modifier: StorageEntryModifier::Default, - ty: StorageEntryType::Map { - hashers: vec![StorageHasher::Identity, StorageHasher::Identity], + modifier: StorageEntryModifierIR::Default, + ty: StorageEntryTypeIR::Map { + hashers: vec![StorageHasherIR::Identity, StorageHasherIR::Identity], key: scale_info::meta_type::<(u64, u64)>(), value: scale_info::meta_type::(), }, diff --git a/frame/support/test/tests/pallet.rs b/frame/support/test/tests/pallet.rs index fbebbef455f7b..b9e531fb42105 100644 --- a/frame/support/test/tests/pallet.rs +++ b/frame/support/test/tests/pallet.rs @@ -37,6 +37,9 @@ use sp_io::{ }; use sp_runtime::{DispatchError, ModuleError}; +/// Latest stable metadata version used for testing. +const LATEST_METADATA_VERSION: u32 = 14; + pub struct SomeType1; impl From for u64 { fn from(_t: SomeType1) -> Self { @@ -1593,6 +1596,43 @@ fn metadata() { pretty_assertions::assert_eq!(actual_metadata.pallets, expected_metadata.pallets); } +#[test] +fn metadata_at_version() { + use frame_support::metadata::*; + use sp_core::Decode; + + let metadata = Runtime::metadata(); + let at_metadata = match Runtime::metadata_at_version(LATEST_METADATA_VERSION) { + Some(opaque) => { + let bytes = &*opaque; + let metadata: RuntimeMetadataPrefixed = Decode::decode(&mut &bytes[..]).unwrap(); + metadata + }, + _ => panic!("metadata has been bumped, test needs to be updated"), + }; + + assert_eq!(metadata, at_metadata); +} + +#[test] +fn metadata_versions() { + assert_eq!(vec![LATEST_METADATA_VERSION], Runtime::metadata_versions()); +} + +#[test] +fn metadata_ir_pallet_runtime_docs() { + let ir = Runtime::metadata_ir(); + let pallet = ir + .pallets + .iter() + .find(|pallet| pallet.name == "Example") + .expect("Pallet should be present"); + + let readme = "Support code for the runtime.\n\nLicense: Apache-2.0"; + let expected = vec![" Pallet documentation", readme, readme]; + assert_eq!(pallet.docs, expected); +} + #[test] fn test_pallet_runtime_docs() { let docs = crate::pallet::Pallet::::pallet_documentation_metadata(); diff --git a/primitives/api/src/lib.rs b/primitives/api/src/lib.rs index 7542ca3f20ccd..ff101c3add947 100644 --- a/primitives/api/src/lib.rs +++ b/primitives/api/src/lib.rs @@ -729,8 +729,20 @@ decl_runtime_apis! { } /// The `Metadata` api trait that returns metadata for the runtime. + #[api_version(2)] pub trait Metadata { /// Returns the metadata of a runtime. fn metadata() -> OpaqueMetadata; + + /// Returns the metadata at a given version. + /// + /// If the given `version` isn't supported, this will return `None`. + /// Use [`Self::metadata_versions`] to find out about supported metadata version of the runtime. + fn metadata_at_version(version: u32) -> Option; + + /// Returns the supported metadata versions. + /// + /// This can be used to call `metadata_at_version`. + fn metadata_versions() -> sp_std::vec::Vec; } } diff --git a/test-utils/runtime/src/lib.rs b/test-utils/runtime/src/lib.rs index 83b4e2977b5cd..c9a0ac04d63ba 100644 --- a/test-utils/runtime/src/lib.rs +++ b/test-utils/runtime/src/lib.rs @@ -437,7 +437,6 @@ cfg_if! { #[derive(Clone, Eq, PartialEq, TypeInfo)] pub struct Runtime; - impl GetNodeBlockType for Runtime { type NodeBlock = Block; } @@ -729,6 +728,14 @@ cfg_if! { fn metadata() -> OpaqueMetadata { unimplemented!() } + + fn metadata_at_version(_version: u32) -> Option { + unimplemented!() + } + + fn metadata_versions() -> sp_std::vec::Vec { + unimplemented!() + } } impl sp_transaction_pool::runtime_api::TaggedTransactionQueue for Runtime { @@ -1021,6 +1028,14 @@ cfg_if! { fn metadata() -> OpaqueMetadata { unimplemented!() } + + fn metadata_at_version(_version: u32) -> Option { + unimplemented!() + } + + fn metadata_versions() -> sp_std::vec::Vec { + unimplemented!() + } } impl sp_transaction_pool::runtime_api::TaggedTransactionQueue for Runtime { From 36ed84069343c55ec4280b2d3cc49c49e3b019d2 Mon Sep 17 00:00:00 2001 From: Mira Ressel Date: Wed, 15 Mar 2023 19:27:18 +0100 Subject: [PATCH 513/715] pin specific version of timestamp script (#13613) --- .gitlab-ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 44f98db3bf185..6cf06273650f7 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -313,6 +313,7 @@ include: rules: - if: $PIPELINE != "automatic-crate-publishing" - project: parity/infrastructure/ci_cd/shared + ref: v0.1 file: /common/timestamp.yml #### stage: notify From 8b5306e1a607a14e08e13fd521f747319ecb6846 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Wed, 15 Mar 2023 21:43:22 +0100 Subject: [PATCH 514/715] Add dedicated `FeePolynomial` struct (#13612) * Add FeePolynomial struct Signed-off-by: Oliver Tale-Yazdi * Add Weight::without_{ref_time, proof_size} Signed-off-by: Oliver Tale-Yazdi * Docs Signed-off-by: Oliver Tale-Yazdi * Cleanup code Signed-off-by: Oliver Tale-Yazdi * Add docs Signed-off-by: Oliver Tale-Yazdi * doc Signed-off-by: Oliver Tale-Yazdi * Fix docs Signed-off-by: Oliver Tale-Yazdi * docs Signed-off-by: Oliver Tale-Yazdi --------- Signed-off-by: Oliver Tale-Yazdi --- primitives/weights/src/lib.rs | 95 ++++++++++++++++++++++------- primitives/weights/src/weight_v2.rs | 10 +++ 2 files changed, 82 insertions(+), 23 deletions(-) diff --git a/primitives/weights/src/lib.rs b/primitives/weights/src/lib.rs index 8a842307355bf..faa641a0f0c53 100644 --- a/primitives/weights/src/lib.rs +++ b/primitives/weights/src/lib.rs @@ -30,7 +30,7 @@ use scale_info::TypeInfo; use serde::{Deserialize, Serialize}; use smallvec::SmallVec; use sp_arithmetic::{ - traits::{BaseArithmetic, SaturatedConversion, Saturating, Unsigned}, + traits::{BaseArithmetic, SaturatedConversion, Unsigned}, Perbill, }; use sp_core::Get; @@ -118,9 +118,77 @@ pub struct WeightToFeeCoefficient { pub degree: u8, } -/// A list of coefficients that represent one polynomial. +impl WeightToFeeCoefficient +where + Balance: BaseArithmetic + From + Copy + Unsigned, +{ + /// Evaluate the term at `x` and saturatingly amalgamate into `result`. + /// + /// The unsigned value for the term is calculated as: + /// ```ignore + /// (frac * x^(degree) + integer * x^(degree)) + /// ``` + /// Depending on the value of `negative`, it is added or subtracted from the `result`. + pub fn saturating_eval(&self, mut result: Balance, x: Balance) -> Balance { + let power = x.saturating_pow(self.degree.into()); + + let frac = self.coeff_frac * power; // Overflow safe. + let integer = self.coeff_integer.saturating_mul(power); + // Do not add them together here to avoid an underflow. + + if self.negative { + result = result.saturating_sub(frac); + result = result.saturating_sub(integer); + } else { + result = result.saturating_add(frac); + result = result.saturating_add(integer); + } + + result + } +} + +/// A list of coefficients that represent a polynomial. pub type WeightToFeeCoefficients = SmallVec<[WeightToFeeCoefficient; 4]>; +/// A list of coefficients that represent a polynomial. +/// +/// Can be [eval](Self::eval)uated at a specific `u64` to get the fee. The evaluations happens by +/// summing up all term [results](`WeightToFeeCoefficient::saturating_eval`). The order of the +/// coefficients matters since it uses saturating arithmetic. This struct does therefore not model a +/// polynomial in the mathematical sense (polynomial ring). +/// +/// For visualization purposes, the formulas of the unsigned terms look like: +/// +/// ```ignore +/// (c[0].frac * x^(c[0].degree) + c[0].integer * x^(c[0].degree)) +/// (c[1].frac * x^(c[1].degree) + c[1].integer * x^(c[1].degree)) +/// ... +/// ``` +/// Depending on the value of `c[i].negative`, each term is added or subtracted from the result. +/// The result is initialized as zero. +pub struct FeePolynomial { + coefficients: SmallVec<[WeightToFeeCoefficient; 4]>, +} + +impl From> for FeePolynomial { + fn from(coefficients: WeightToFeeCoefficients) -> Self { + Self { coefficients } + } +} + +impl FeePolynomial +where + Balance: BaseArithmetic + From + Copy + Unsigned, +{ + /// Evaluate the polynomial at a specific `x`. + pub fn eval(&self, x: u64) -> Balance { + self.coefficients.iter().fold(Balance::zero(), |acc, term| { + term.saturating_eval(acc, Balance::saturated_from(x)) + }) + } +} + /// A trait that describes the weight to fee calculation. pub trait WeightToFee { /// The type that is returned as result from calculation. @@ -157,27 +225,8 @@ where /// 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 - }) + let poly: FeePolynomial = Self::polynomial().into(); + poly.eval(weight.ref_time()) } } diff --git a/primitives/weights/src/weight_v2.rs b/primitives/weights/src/weight_v2.rs index ca137145920bb..76c40c16cbf03 100644 --- a/primitives/weights/src/weight_v2.rs +++ b/primitives/weights/src/weight_v2.rs @@ -74,6 +74,16 @@ impl Weight { &mut self.proof_size } + /// Return self but discard any reference time. + pub const fn without_ref_time(&self) -> Self { + Self { ref_time: 0, proof_size: self.proof_size } + } + + /// Return self but discard any proof size. + pub const fn without_proof_size(&self) -> Self { + Self { ref_time: self.ref_time, proof_size: 0 } + } + pub const MAX: Self = Self { ref_time: u64::MAX, proof_size: u64::MAX }; /// Get the conservative min of `self` and `other` weight. From 86731af2629fdedc39a31bd9666fdd1b5df5ed2d Mon Sep 17 00:00:00 2001 From: Francisco Aguirre Date: Wed, 15 Mar 2023 18:04:28 -0300 Subject: [PATCH 515/715] Make Pay trait from salaries pallet more generic (#13609) * Make Pay trait from salaries pallet more generic * Rename and add missing * Update frame/support/src/traits/tokens/pay.rs * Update pay.rs * Update pay.rs * Update pay.rs * Add better documentation for the AssetKind associated type --------- Co-authored-by: Gavin Wood Co-authored-by: parity-processbot <> --- bin/node/runtime/src/lib.rs | 6 +- frame/salary/src/lib.rs | 74 ++---------------- frame/salary/src/tests.rs | 11 ++- frame/support/src/traits/tokens.rs | 2 + frame/support/src/traits/tokens/pay.rs | 103 +++++++++++++++++++++++++ 5 files changed, 122 insertions(+), 74 deletions(-) create mode 100644 frame/support/src/traits/tokens/pay.rs diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 5d1dea02e8256..9f4ad2ed26474 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -33,7 +33,7 @@ use frame_support::{ parameter_types, traits::{ fungible::ItemOf, - tokens::{nonfungibles_v2::Inspect, GetSalary}, + tokens::{nonfungibles_v2::Inspect, GetSalary, PayFromAccount}, AsEnsureOriginWithArg, ConstBool, ConstU128, ConstU16, ConstU32, Currency, EitherOfDiverse, EqualPrivilegeOnly, Everything, Imbalance, InstanceFilter, KeyOwnerProofSystem, LockIdentifier, Nothing, OnUnbalanced, U128CurrencyToVote, WithdrawReasons, @@ -56,7 +56,7 @@ use pallet_election_provider_multi_phase::SolutionAccuracyOf; use pallet_im_online::sr25519::AuthorityId as ImOnlineId; use pallet_nfts::PalletFeatures; use pallet_nis::WithMaximumOf; -use pallet_session::historical::{self as pallet_session_historical}; +use pallet_session::historical as pallet_session_historical; pub use pallet_transaction_payment::{CurrencyAdapter, Multiplier, TargetedFeeAdjustment}; use pallet_transaction_payment::{FeeDetails, RuntimeDispatchInfo}; use sp_api::impl_runtime_apis; @@ -1567,7 +1567,7 @@ impl GetSalary for SalaryForRank { impl pallet_salary::Config for Runtime { type WeightInfo = (); type RuntimeEvent = RuntimeEvent; - type Paymaster = pallet_salary::PayFromAccount; + type Paymaster = PayFromAccount; type Members = RankedCollective; type Salary = SalaryForRank; type RegistrationPeriod = ConstU32<200>; diff --git a/frame/salary/src/lib.rs b/frame/salary/src/lib.rs index 6f9e63271cc2f..0b2b4b47d8b70 100644 --- a/frame/salary/src/lib.rs +++ b/frame/salary/src/lib.rs @@ -20,18 +20,17 @@ #![cfg_attr(not(feature = "std"), no_std)] #![recursion_limit = "128"] -use codec::{Decode, Encode, FullCodec, MaxEncodedLen}; +use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; use sp_arithmetic::traits::{Saturating, Zero}; -use sp_core::TypedGet; use sp_runtime::Perbill; -use sp_std::{fmt::Debug, marker::PhantomData, prelude::*}; +use sp_std::{marker::PhantomData, prelude::*}; use frame_support::{ dispatch::DispatchResultWithPostInfo, ensure, traits::{ - tokens::{fungible, Balance, GetSalary}, + tokens::{GetSalary, Pay, PaymentStatus}, RankedMembers, }, RuntimeDebug, @@ -50,67 +49,6 @@ pub use weights::WeightInfo; /// Payroll cycle. pub type Cycle = u32; -/// Status for making a payment via the `Pay::pay` trait function. -#[derive(Encode, Decode, Eq, PartialEq, Clone, TypeInfo, MaxEncodedLen, RuntimeDebug)] -pub enum PaymentStatus { - /// Payment is in progress. Nothing to report yet. - InProgress, - /// Payment status is unknowable. It will never be reported successful or failed. - Unknown, - /// Payment happened successfully. - Success, - /// Payment failed. It may safely be retried. - Failure, -} - -/// Can be implemented by `PayFromAccount` using a `fungible` impl, but can also be implemented with -/// XCM/MultiAsset and made generic over assets. -pub trait Pay { - /// The type by which we measure units of the currency in which we make payments. - type Balance: Balance; - /// The type by which we identify the individuals to whom a payment may be made. - type AccountId; - /// An identifier given to an individual payment. - type Id: FullCodec + MaxEncodedLen + TypeInfo + Clone + Eq + PartialEq + Debug + Copy; - /// Make a payment and return an identifier for later evaluation of success in some off-chain - /// mechanism (likely an event, but possibly not on this chain). - fn pay(who: &Self::AccountId, amount: Self::Balance) -> Result; - /// Check how a payment has proceeded. `id` must have been a previously returned by `pay` for - /// the result of this call to be meaningful. - fn check_payment(id: Self::Id) -> PaymentStatus; - /// Ensure that a call to pay with the given parameters will be successful if done immediately - /// after this call. Used in benchmarking code. - #[cfg(feature = "runtime-benchmarks")] - fn ensure_successful(who: &Self::AccountId, amount: Self::Balance); - /// Ensure that a call to `check_payment` with the given parameters will return either `Success` - /// or `Failure`. - #[cfg(feature = "runtime-benchmarks")] - fn ensure_concluded(id: Self::Id); -} - -/// Simple implementation of `Pay` which makes a payment from a "pot" - i.e. a single account. -pub struct PayFromAccount(sp_std::marker::PhantomData<(F, A)>); -impl + fungible::Mutate> Pay - for PayFromAccount -{ - type Balance = F::Balance; - type AccountId = A::Type; - type Id = (); - fn pay(who: &Self::AccountId, amount: Self::Balance) -> Result { - >::transfer(&A::get(), who, amount, false).map_err(|_| ())?; - Ok(()) - } - fn check_payment(_: ()) -> PaymentStatus { - PaymentStatus::Success - } - #[cfg(feature = "runtime-benchmarks")] - fn ensure_successful(_: &Self::AccountId, amount: Self::Balance) { - >::mint_into(&A::get(), amount).unwrap(); - } - #[cfg(feature = "runtime-benchmarks")] - fn ensure_concluded(_: Self::Id) {} -} - /// The status of the pallet instance. #[derive(Encode, Decode, Eq, PartialEq, Clone, TypeInfo, MaxEncodedLen, RuntimeDebug)] pub struct StatusType { @@ -168,7 +106,7 @@ pub mod pallet { /// Means by which we can make payments to accounts. This also defines the currency and the /// balance which we use to denote that currency. - type Paymaster: Pay::AccountId>; + type Paymaster: Pay::AccountId, AssetKind = ()>; /// The current membership of payees. type Members: RankedMembers::AccountId>; @@ -498,8 +436,8 @@ pub mod pallet { claimant.last_active = status.cycle_index; - let id = - T::Paymaster::pay(&beneficiary, payout).map_err(|()| Error::::PayError)?; + let id = T::Paymaster::pay(&beneficiary, (), payout) + .map_err(|()| Error::::PayError)?; claimant.status = Attempted { registered, id, amount: payout }; diff --git a/frame/salary/src/tests.rs b/frame/salary/src/tests.rs index e54b9612b152c..1b7bc6cbb6df5 100644 --- a/frame/salary/src/tests.rs +++ b/frame/salary/src/tests.rs @@ -99,11 +99,16 @@ fn set_status(id: u64, s: PaymentStatus) { pub struct TestPay; impl Pay for TestPay { - type AccountId = u64; + type Beneficiary = u64; type Balance = u64; type Id = u64; + type AssetKind = (); - fn pay(who: &Self::AccountId, amount: Self::Balance) -> Result { + fn pay( + who: &Self::Beneficiary, + _: Self::AssetKind, + amount: Self::Balance, + ) -> Result { PAID.with(|paid| *paid.borrow_mut().entry(*who).or_default() += amount); Ok(LAST_ID.with(|lid| { let x = *lid.borrow(); @@ -115,7 +120,7 @@ impl Pay for TestPay { STATUS.with(|s| s.borrow().get(&id).cloned().unwrap_or(PaymentStatus::Unknown)) } #[cfg(feature = "runtime-benchmarks")] - fn ensure_successful(_: &Self::AccountId, _: Self::Balance) {} + fn ensure_successful(_: &Self::Beneficiary, _: Self::Balance) {} #[cfg(feature = "runtime-benchmarks")] fn ensure_concluded(id: Self::Id) { set_status(id, PaymentStatus::Failure) diff --git a/frame/support/src/traits/tokens.rs b/frame/support/src/traits/tokens.rs index e1a96f621bd4f..2d2bd63ada551 100644 --- a/frame/support/src/traits/tokens.rs +++ b/frame/support/src/traits/tokens.rs @@ -27,7 +27,9 @@ pub mod nonfungible_v2; pub mod nonfungibles; pub mod nonfungibles_v2; pub use imbalance::Imbalance; +pub mod pay; pub use misc::{ AssetId, Balance, BalanceConversion, BalanceStatus, ConvertRank, DepositConsequence, ExistenceRequirement, GetSalary, Locker, WithdrawConsequence, WithdrawReasons, }; +pub use pay::{Pay, PayFromAccount, PaymentStatus}; diff --git a/frame/support/src/traits/tokens/pay.rs b/frame/support/src/traits/tokens/pay.rs new file mode 100644 index 0000000000000..1c6a147b5f22e --- /dev/null +++ b/frame/support/src/traits/tokens/pay.rs @@ -0,0 +1,103 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT 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 Pay trait and associated types. + +use codec::{Decode, Encode, FullCodec, MaxEncodedLen}; +use scale_info::TypeInfo; +use sp_core::{RuntimeDebug, TypedGet}; +use sp_std::fmt::Debug; + +use super::{fungible, Balance}; + +/// Can be implemented by `PayFromAccount` using a `fungible` impl, but can also be implemented with +/// XCM/MultiAsset and made generic over assets. +pub trait Pay { + /// The type by which we measure units of the currency in which we make payments. + type Balance: Balance; + /// The type by which we identify the beneficiaries to whom a payment may be made. + type Beneficiary; + /// The type for the kinds of asset that are going to be paid. + /// + /// The unit type can be used here to indicate there's only one kind of asset to do payments + /// with. When implementing, it should be clear from the context what that asset is. + type AssetKind; + /// An identifier given to an individual payment. + type Id: FullCodec + MaxEncodedLen + TypeInfo + Clone + Eq + PartialEq + Debug + Copy; + /// Make a payment and return an identifier for later evaluation of success in some off-chain + /// mechanism (likely an event, but possibly not on this chain). + fn pay( + who: &Self::Beneficiary, + asset_kind: Self::AssetKind, + amount: Self::Balance, + ) -> Result; + /// Check how a payment has proceeded. `id` must have been previously returned by `pay` for + /// the result of this call to be meaningful. Once this returns anything other than + /// `InProgress` for some `id` it must return `Unknown` rather than the actual result + /// value. + fn check_payment(id: Self::Id) -> PaymentStatus; + /// Ensure that a call to pay with the given parameters will be successful if done immediately + /// after this call. Used in benchmarking code. + #[cfg(feature = "runtime-benchmarks")] + fn ensure_successful(who: &Self::Beneficiary, amount: Self::Balance); + /// Ensure that a call to `check_payment` with the given parameters will return either `Success` + /// or `Failure`. + #[cfg(feature = "runtime-benchmarks")] + fn ensure_concluded(id: Self::Id); +} + +/// Status for making a payment via the `Pay::pay` trait function. +#[derive(Encode, Decode, Eq, PartialEq, Clone, TypeInfo, MaxEncodedLen, RuntimeDebug)] +pub enum PaymentStatus { + /// Payment is in progress. Nothing to report yet. + InProgress, + /// Payment status is unknowable. It may already have reported the result, or if not then + /// it will never be reported successful or failed. + Unknown, + /// Payment happened successfully. + Success, + /// Payment failed. It may safely be retried. + Failure, +} + +/// Simple implementation of `Pay` which makes a payment from a "pot" - i.e. a single account. +pub struct PayFromAccount(sp_std::marker::PhantomData<(F, A)>); +impl + fungible::Mutate> Pay + for PayFromAccount +{ + type Balance = F::Balance; + type Beneficiary = A::Type; + type AssetKind = (); + type Id = (); + fn pay( + who: &Self::Beneficiary, + _: Self::AssetKind, + amount: Self::Balance, + ) -> Result { + >::transfer(&A::get(), who, amount, false).map_err(|_| ())?; + Ok(()) + } + fn check_payment(_: ()) -> PaymentStatus { + PaymentStatus::Success + } + #[cfg(feature = "runtime-benchmarks")] + fn ensure_successful(_: &Self::Beneficiary, amount: Self::Balance) { + >::mint_into(&A::get(), amount).unwrap(); + } + #[cfg(feature = "runtime-benchmarks")] + fn ensure_concluded(_: Self::Id) {} +} From 9f933c4d87a4682233328daaafbc9bbe2cc8e778 Mon Sep 17 00:00:00 2001 From: Sacha Lansky Date: Thu, 16 Mar 2023 08:29:20 +0000 Subject: [PATCH 516/715] Fix typos (#13616) --- frame/examples/offchain-worker/src/lib.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/frame/examples/offchain-worker/src/lib.rs b/frame/examples/offchain-worker/src/lib.rs index 418ad5d139ef3..1a63955c04741 100644 --- a/frame/examples/offchain-worker/src/lib.rs +++ b/frame/examples/offchain-worker/src/lib.rs @@ -166,7 +166,7 @@ pub mod pallet { /// /// By implementing `fn offchain_worker` you declare a new offchain worker. /// This function will be called when the node is fully synced and a new best block is - /// succesfuly imported. + /// successfully imported. /// Note that it's not guaranteed for offchain workers to run on EVERY block, there might /// be cases where some blocks are skipped, or for some the worker runs twice (re-orgs), /// so the code should be able to handle that. @@ -224,7 +224,7 @@ pub mod pallet { /// The transaction needs to be signed (see `ensure_signed`) check, so that the caller /// pays a fee to execute it. /// This makes sure that it's not easy (or rather cheap) to attack the chain by submitting - /// excesive transactions, but note that it doesn't ensure the price oracle is actually + /// excessive transactions, but note that it doesn't ensure the price oracle is actually /// 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. @@ -336,7 +336,7 @@ pub mod pallet { /// Defines the block when next unsigned transaction will be accepted. /// - /// To prevent spam of unsigned (and unpayed!) transactions on the network, + /// To prevent spam of unsigned (and unpaid!) transactions on the network, /// we only allow one transaction every `T::UnsignedInterval` blocks. /// This storage entry defines when new transaction is going to be accepted. #[pallet::storage] @@ -570,12 +570,12 @@ impl Pallet { fn fetch_price() -> Result { // We want to keep the offchain worker execution time reasonable, so we set a hard-coded // deadline to 2s to complete the external call. - // You can also wait idefinitely for the response, however you may still get a timeout + // You can also wait indefinitely for the response, however you may still get a timeout // coming from the host machine. let deadline = sp_io::offchain::timestamp().add(Duration::from_millis(2_000)); // Initiate an external HTTP GET request. // This is using high-level wrappers from `sp_runtime`, for the low-level calls that - // you can find in `sp_io`. The API is trying to be similar to `reqwest`, but + // you can find in `sp_io`. The API is trying to be similar to `request`, but // since we are running in a custom WASM execution environment we can't simply // import the library here. let request = From b0700a6d3e9a9dfa3897971ee62a06134bda17d3 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Thu, 16 Mar 2023 11:02:39 +0200 Subject: [PATCH 517/715] sc-consensus-beefy: improve beefy gossip validator (#13606) * sc-consensus-beefy: improve beefy gossip validator Old gossip validator was pretty dumb, being very permissive with incoming votes - only condition it had was to be newer than best finalized. New filter conditions: - voter rounds are initialized (discarding votes until voter is actually active), - only votes for current active set id are accepted, - only votes for rounds in the current voting session are accepted, - only votes for GRANDPA finalized blocks are accepted, - when BEEFY voter reaches mandatory round, only votes for said mandatory round are accepted. New validator uses the VoterOracle to easily implement above conditions and only allow through votes that are immediately useful to the voter. After every GRANDPA or BEEFY finality, the gossip validator filter is updated. * sc-consensus-beefy: remove votes enqueueing Since gossip validator will simply disallow votes for future rounds, and only allow votes that the voter can immediately process, there is no need for the voter to enqueue votes. It will see these "future" votes later in rebroadcasts, when voter will also be able to process them. Only at that point does gossip accept and consume them. * sc-consensus-beefy: refactor persistent state Move best-beefy and best-grandpa into VoterOracle instead of passing them around as params. VoterOracle ultimately needs to know best-beefy and/or best-grandpa for most of its functions. * sc-consensus-beefy: further restrict gossip validator Assuming mandatory done in current session: Instead of allowing votes for any round in the current session, only accept votes for rounds equal or better than best BEEFY finalized. * sc-consensus-beefy: add a couple of comments * sc-consensus-beefy: fix tests involving multiple tasks Finalize blocks one a time in tests where we want gossip to happen in a certain round. Otherwise, some tasks may be left behind in terms of gossip round numbers because once "scheduled" a task will greedily process as much as possible. This change should be in line with the real-world scenario where voters run "in parallel" across nodes, the only points of synchronization being the finality notifications. * sc-consensus-beefy: address review comments --------- Signed-off-by: acatangiu --- client/consensus/beefy/src/aux_schema.rs | 6 +- .../beefy/src/communication/gossip.rs | 204 +++---- client/consensus/beefy/src/lib.rs | 10 + client/consensus/beefy/src/metrics.rs | 24 - client/consensus/beefy/src/tests.rs | 183 ++---- client/consensus/beefy/src/worker.rs | 532 ++++++++---------- 6 files changed, 385 insertions(+), 574 deletions(-) diff --git a/client/consensus/beefy/src/aux_schema.rs b/client/consensus/beefy/src/aux_schema.rs index 2e99b4cc40638..84186140b6925 100644 --- a/client/consensus/beefy/src/aux_schema.rs +++ b/client/consensus/beefy/src/aux_schema.rs @@ -28,7 +28,7 @@ use sp_runtime::traits::Block as BlockT; const VERSION_KEY: &[u8] = b"beefy_auxschema_version"; const WORKER_STATE_KEY: &[u8] = b"beefy_voter_state"; -const CURRENT_VERSION: u32 = 2; +const CURRENT_VERSION: u32 = 3; pub(crate) fn write_current_version(backend: &BE) -> ClientResult<()> { info!(target: LOG_TARGET, "🥩 write aux schema version {:?}", CURRENT_VERSION); @@ -63,8 +63,8 @@ where match version { None => (), - Some(1) => (), // version 1 is totally obsolete and should be simply ignored - Some(2) => return load_decode::<_, PersistedState>(backend, WORKER_STATE_KEY), + Some(1) | Some(2) => (), // versions 1 & 2 are obsolete and should be simply ignored + Some(3) => return load_decode::<_, PersistedState>(backend, WORKER_STATE_KEY), other => return Err(ClientError::Backend(format!("Unsupported BEEFY DB version: {:?}", other))), } diff --git a/client/consensus/beefy/src/communication/gossip.rs b/client/consensus/beefy/src/communication/gossip.rs index 219203ee4e173..e49382251e846 100644 --- a/client/consensus/beefy/src/communication/gossip.rs +++ b/client/consensus/beefy/src/communication/gossip.rs @@ -31,11 +31,14 @@ use wasm_timer::Instant; use crate::{communication::peers::KnownPeers, keystore::BeefyKeystore, LOG_TARGET}; use sp_consensus_beefy::{ crypto::{Public, Signature}, - VoteMessage, + ValidatorSetId, VoteMessage, }; // Timeout for rebroadcasting messages. -const REBROADCAST_AFTER: Duration = Duration::from_secs(60 * 5); +#[cfg(not(test))] +const REBROADCAST_AFTER: Duration = Duration::from_secs(60); +#[cfg(test)] +const REBROADCAST_AFTER: Duration = Duration::from_secs(5); /// Gossip engine messages topic pub(crate) fn topic() -> B::Hash @@ -45,45 +48,51 @@ where <::Hashing as Hash>::hash(b"beefy") } +#[derive(Debug)] +pub(crate) struct GossipVoteFilter { + pub start: NumberFor, + pub end: NumberFor, + pub validator_set_id: ValidatorSetId, +} + /// A type that represents hash of the message. pub type MessageHash = [u8; 8]; -struct KnownVotes { - last_done: Option>, +struct VotesFilter { + filter: Option>, live: BTreeMap, fnv::FnvHashSet>, } -impl KnownVotes { +impl VotesFilter { 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(); + Self { filter: None, live: BTreeMap::new() } } - /// 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)); + /// Update filter to new `start` and `set_id`. + fn update(&mut self, filter: GossipVoteFilter) { + self.live.retain(|&round, _| round >= filter.start && round <= filter.end); + self.filter = Some(filter); } - /// Return true if `round` is newer than previously concluded rounds. + /// Return true if `round` is >= than `max(session_start, best_beefy)`, + /// and vote set id matches session set id. /// /// 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 + fn is_live(&self, round: NumberFor, set_id: ValidatorSetId) -> bool { + self.filter + .as_ref() + .map(|f| set_id == f.validator_set_id && round >= f.start && round <= f.end) + .unwrap_or(false) } /// 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)); + fn add_known(&mut self, round: NumberFor, hash: MessageHash) { + self.live.entry(round).or_default().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) + fn is_known(&self, round: NumberFor, hash: &MessageHash) -> bool { + self.live.get(&round).map(|known| known.contains(hash)).unwrap_or(false) } } @@ -100,7 +109,7 @@ where B: Block, { topic: B::Hash, - known_votes: RwLock>, + votes_filter: RwLock>, next_rebroadcast: Mutex, known_peers: Arc>>, } @@ -112,26 +121,18 @@ where pub fn new(known_peers: Arc>>) -> GossipValidator { GossipValidator { topic: topic::(), - known_votes: RwLock::new(KnownVotes::new()), + votes_filter: RwLock::new(VotesFilter::new()), next_rebroadcast: Mutex::new(Instant::now() + REBROADCAST_AFTER), known_peers, } } - /// Note a voting round. - /// - /// Noting round will track gossiped votes for `round`. - pub(crate) fn note_round(&self, round: NumberFor) { - debug!(target: LOG_TARGET, "🥩 About to note gossip round #{}", round); - self.known_votes.write().insert(round); - } - - /// Conclude a voting round. + /// Update gossip validator filter. /// - /// This can be called once round is complete so we stop gossiping for it. - pub(crate) fn conclude_round(&self, round: NumberFor) { - debug!(target: LOG_TARGET, "🥩 About to drop gossip round #{}", round); - self.known_votes.write().conclude(round); + /// Only votes for `set_id` and rounds `start <= round <= end` will be accepted. + pub(crate) fn update_filter(&self, filter: GossipVoteFilter) { + debug!(target: LOG_TARGET, "🥩 New gossip filter {:?}", filter); + self.votes_filter.write().update(filter); } } @@ -152,25 +153,26 @@ where if let Ok(msg) = VoteMessage::, Public, Signature>::decode(&mut data) { let msg_hash = twox_64(data); let round = msg.commitment.block_number; + let set_id = msg.commitment.validator_set_id; + self.known_peers.lock().note_vote_for(*sender, round); // Verify general usefulness of the message. // We are going to discard old votes right away (without verification) // Also we keep track of already received votes to avoid verifying duplicates. { - let known_votes = self.known_votes.read(); + let filter = self.votes_filter.read(); - if !known_votes.is_live(&round) { + if !filter.is_live(round, set_id) { return ValidationResult::Discard } - if known_votes.is_known(&round, &msg_hash) { + if filter.is_known(round, &msg_hash) { return ValidationResult::ProcessAndKeep(self.topic) } } 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); + self.votes_filter.write().add_known(round, msg_hash); return ValidationResult::ProcessAndKeep(self.topic) } else { // TODO: report peer @@ -185,7 +187,7 @@ where } fn message_expired<'a>(&'a self) -> Box bool + 'a> { - let known_votes = self.known_votes.read(); + let filter = self.votes_filter.read(); Box::new(move |_topic, mut data| { let msg = match VoteMessage::, Public, Signature>::decode(&mut data) { Ok(vote) => vote, @@ -193,7 +195,8 @@ where }; let round = msg.commitment.block_number; - let expired = !known_votes.is_live(&round); + let set_id = msg.commitment.validator_set_id; + let expired = !filter.is_live(round, set_id); trace!(target: LOG_TARGET, "🥩 Message for round #{} expired: {}", round, expired); @@ -208,6 +211,7 @@ where let now = Instant::now(); let mut next_rebroadcast = self.next_rebroadcast.lock(); if now >= *next_rebroadcast { + trace!(target: LOG_TARGET, "🥩 Gossip rebroadcast"); *next_rebroadcast = now + REBROADCAST_AFTER; true } else { @@ -215,7 +219,7 @@ where } }; - let known_votes = self.known_votes.read(); + let filter = self.votes_filter.read(); Box::new(move |_who, intent, _topic, mut data| { if let MessageIntent::PeriodicRebroadcast = intent { return do_rebroadcast @@ -227,7 +231,8 @@ where }; let round = msg.commitment.block_number; - let allowed = known_votes.is_live(&round); + let set_id = msg.commitment.validator_set_id; + let allowed = filter.is_live(round, set_id); trace!(target: LOG_TARGET, "🥩 Message for round #{} allowed: {}", round, allowed); @@ -252,81 +257,35 @@ mod tests { #[test] fn known_votes_insert_remove() { - let mut kv = KnownVotes::::new(); + let mut kv = VotesFilter::::new(); + let msg_hash = twox_64(b"data"); - kv.insert(1); - kv.insert(1); - kv.insert(2); + kv.add_known(1, msg_hash); + kv.add_known(1, msg_hash); + kv.add_known(2, msg_hash); assert_eq!(kv.live.len(), 2); - let mut kv = KnownVotes::::new(); - kv.insert(1); - kv.insert(2); - kv.insert(3); + kv.add_known(3, msg_hash); + assert!(kv.is_known(3, &msg_hash)); + assert!(!kv.is_known(3, &twox_64(b"other"))); + assert!(!kv.is_known(4, &msg_hash)); + assert_eq!(kv.live.len(), 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)); + assert!(kv.filter.is_none()); + assert!(!kv.is_live(1, 1)); - kv.conclude(1); - assert_eq!(kv.last_done, Some(2)); + kv.update(GossipVoteFilter { start: 3, end: 10, validator_set_id: 1 }); + assert_eq!(kv.live.len(), 1); + assert!(kv.live.contains_key(&3)); + assert!(!kv.is_live(2, 1)); + assert!(kv.is_live(3, 1)); + assert!(kv.is_live(4, 1)); + assert!(!kv.is_live(4, 2)); - kv.conclude(3); - assert_eq!(kv.last_done, Some(3)); + kv.update(GossipVoteFilter { start: 5, end: 10, validator_set_id: 2 }); assert!(kv.live.is_empty()); } - #[test] - fn note_and_drop_round_works() { - let gv = GossipValidator::::new(Arc::new(Mutex::new(KnownPeers::new()))); - - gv.note_round(1u64); - - assert!(gv.known_votes.read().is_live(&1u64)); - - gv.note_round(3u64); - gv.note_round(7u64); - gv.note_round(10u64); - - assert_eq!(gv.known_votes.read().live.len(), 4); - - gv.conclude_round(7u64); - - let votes = gv.known_votes.read(); - - // 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] - fn note_same_round_twice() { - let gv = GossipValidator::::new(Arc::new(Mutex::new(KnownPeers::new()))); - - gv.note_round(3u64); - gv.note_round(7u64); - gv.note_round(10u64); - - assert_eq!(gv.known_votes.read().live.len(), 3); - - // note round #7 again -> should not change anything - gv.note_round(7u64); - - let votes = gv.known_votes.read(); - - assert_eq!(votes.live.len(), 3); - - assert!(votes.is_live(&3u64)); - assert!(votes.is_live(&7u64)); - assert!(votes.is_live(&10u64)); - } - struct TestContext; impl ValidatorContext for TestContext { fn broadcast_topic(&mut self, _topic: B::Hash, _force: bool) { @@ -368,21 +327,18 @@ mod tests { #[test] fn should_avoid_verifying_signatures_twice() { let gv = GossipValidator::::new(Arc::new(Mutex::new(KnownPeers::new()))); + gv.update_filter(GossipVoteFilter { start: 0, end: 10, validator_set_id: 0 }); let sender = sc_network::PeerId::random(); let mut context = TestContext; let vote = dummy_vote(3); - 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().live.get(&vote.commitment.block_number).map(|x| x.len()), + gv.votes_filter.read().live.get(&vote.commitment.block_number).map(|x| x.len()), Some(1) ); @@ -392,9 +348,11 @@ mod tests { assert!(matches!(res, ValidationResult::ProcessAndKeep(_))); // next we should quickly reject if the round is not live - gv.conclude_round(7_u64); + gv.update_filter(GossipVoteFilter { start: 7, end: 10, validator_set_id: 0 }); - assert!(!gv.known_votes.read().is_live(&vote.commitment.block_number)); + let number = vote.commitment.block_number; + let set_id = vote.commitment.validator_set_id; + assert!(!gv.votes_filter.read().is_live(number, set_id)); let res = gv.validate(&mut context, &sender, &vote.encode()); @@ -404,14 +362,13 @@ mod tests { #[test] fn messages_allowed_and_expired() { let gv = GossipValidator::::new(Arc::new(Mutex::new(KnownPeers::new()))); + gv.update_filter(GossipVoteFilter { start: 0, end: 10, validator_set_id: 0 }); 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); + // conclude 2 + gv.update_filter(GossipVoteFilter { start: 2, end: 10, validator_set_id: 0 }); let mut allowed = gv.message_allowed(); let mut expired = gv.message_expired(); @@ -447,6 +404,7 @@ mod tests { #[test] fn messages_rebroadcast() { let gv = GossipValidator::::new(Arc::new(Mutex::new(KnownPeers::new()))); + gv.update_filter(GossipVoteFilter { start: 0, end: 10, validator_set_id: 0 }); let sender = sc_network::PeerId::random(); let topic = Default::default(); diff --git a/client/consensus/beefy/src/lib.rs b/client/consensus/beefy/src/lib.rs index eb56a97de1dd9..d632f58332a77 100644 --- a/client/consensus/beefy/src/lib.rs +++ b/client/consensus/beefy/src/lib.rs @@ -247,6 +247,8 @@ pub async fn start_beefy_gadget( } = network_params; let known_peers = Arc::new(Mutex::new(KnownPeers::new())); + // Default votes filter is to discard everything. + // Validator is updated later with correct starting round and set id. let gossip_validator = Arc::new(communication::gossip::GossipValidator::new(known_peers.clone())); let mut gossip_engine = sc_network_gossip::GossipEngine::new( @@ -284,6 +286,14 @@ pub async fn start_beefy_gadget( return }, }; + // Update the gossip validator with the right starting round and set id. + if let Err(e) = persisted_state + .current_gossip_filter() + .map(|f| gossip_validator.update_filter(f)) + { + error!(target: LOG_TARGET, "Error: {:?}. Terminating.", e); + return + } let worker_params = worker::WorkerParams { backend, diff --git a/client/consensus/beefy/src/metrics.rs b/client/consensus/beefy/src/metrics.rs index 0ce48e60ebc84..6653763fc6754 100644 --- a/client/consensus/beefy/src/metrics.rs +++ b/client/consensus/beefy/src/metrics.rs @@ -45,10 +45,6 @@ pub struct VoterMetrics { pub beefy_lagging_sessions: Counter, /// Number of times no Authority public key found in store pub beefy_no_authority_found_in_store: Counter, - /// Number of currently buffered votes - pub beefy_buffered_votes: Gauge, - /// Number of votes dropped due to full buffers - pub beefy_buffered_votes_dropped: Counter, /// Number of good votes successfully handled pub beefy_good_votes_processed: Counter, /// Number of equivocation votes received @@ -65,8 +61,6 @@ pub struct VoterMetrics { pub beefy_imported_justifications: Counter, /// Number of justifications dropped due to full buffers pub beefy_buffered_justifications_dropped: Counter, - /// Trying to set Best Beefy block to old block - pub beefy_best_block_set_last_failure: Gauge, } impl PrometheusRegister for VoterMetrics { @@ -110,17 +104,6 @@ impl PrometheusRegister for VoterMetrics { )?, registry, )?, - beefy_buffered_votes: register( - Gauge::new("substrate_beefy_buffered_votes", "Number of currently buffered votes")?, - registry, - )?, - beefy_buffered_votes_dropped: register( - Counter::new( - "substrate_beefy_buffered_votes_dropped", - "Number of votes dropped due to full buffers", - )?, - registry, - )?, beefy_good_votes_processed: register( Counter::new( "substrate_beefy_successful_handled_votes", @@ -174,13 +157,6 @@ impl PrometheusRegister for VoterMetrics { )?, registry, )?, - beefy_best_block_set_last_failure: register( - Gauge::new( - "substrate_beefy_best_block_to_old_block", - "Trying to set Best Beefy block to old block", - )?, - registry, - )?, }) } } diff --git a/client/consensus/beefy/src/tests.rs b/client/consensus/beefy/src/tests.rs index 27dc8d81915aa..629f144246d7f 100644 --- a/client/consensus/beefy/src/tests.rs +++ b/client/consensus/beefy/src/tests.rs @@ -526,17 +526,15 @@ async fn finalize_block_and_wait_for_beefy( net: &Arc>, // peer index and key peers: impl Iterator + Clone, - finalize_targets: &[H256], + finalize_target: &H256, expected_beefy: &[u64], ) { let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), peers.clone()); - for block in finalize_targets { - peers.clone().for_each(|(index, _)| { - let client = net.lock().peer(index).client().as_client(); - client.finalize_block(*block, None).unwrap(); - }) - } + peers.clone().for_each(|(index, _)| { + let client = net.lock().peer(index).client().as_client(); + client.finalize_block(*finalize_target, None).unwrap(); + }); if expected_beefy.is_empty() { // run for quarter second then verify no new best beefy block available @@ -574,31 +572,32 @@ async 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(), &[hashes[1], hashes[5]], &[1, 5]).await; + finalize_block_and_wait_for_beefy(&net, peers.clone(), &hashes[1], &[1]).await; + finalize_block_and_wait_for_beefy(&net, peers.clone(), &hashes[5], &[5]).await; // GRANDPA finalize #10 -> BEEFY finalize #10 (mandatory) - finalize_block_and_wait_for_beefy(&net, peers.clone(), &[hashes[10]], &[10]).await; + finalize_block_and_wait_for_beefy(&net, peers.clone(), &hashes[10], &[10]).await; // GRANDPA finalize #18 -> BEEFY finalize #14, then #18 (diff-power-of-two rule) - finalize_block_and_wait_for_beefy(&net, peers.clone(), &[hashes[18]], &[14, 18]).await; + finalize_block_and_wait_for_beefy(&net, peers.clone(), &hashes[18], &[14, 18]).await; // GRANDPA finalize #20 -> BEEFY finalize #20 (mandatory) - finalize_block_and_wait_for_beefy(&net, peers.clone(), &[hashes[20]], &[20]).await; + finalize_block_and_wait_for_beefy(&net, peers.clone(), &hashes[20], &[20]).await; // GRANDPA finalize #21 -> BEEFY finalize nothing (yet) because min delta is 4 - finalize_block_and_wait_for_beefy(&net, peers, &[hashes[21]], &[]).await; + finalize_block_and_wait_for_beefy(&net, peers, &hashes[21], &[]).await; } #[tokio::test] async fn lagging_validators() { sp_tracing::try_init_simple(); - let peers = [BeefyKeyring::Alice, BeefyKeyring::Bob]; + let peers = [BeefyKeyring::Alice, BeefyKeyring::Bob, BeefyKeyring::Charlie]; 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); + let mut net = BeefyTestNet::new(3); let api = Arc::new(TestApi::with_validator_set(&validator_set)); let beefy_peers = peers.iter().enumerate().map(|(id, key)| (id, key, api.clone())).collect(); tokio::spawn(initialize_beefy(&mut net, beefy_peers, min_block_delta)); @@ -611,55 +610,47 @@ async fn lagging_validators() { 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.clone(), - &[hashes[1], hashes[15]], - &[1, 9, 13, 14, 15], - ) - .await; - - // Alice finalizes #25, Bob lags behind + finalize_block_and_wait_for_beefy(&net, peers.clone(), &hashes[1], &[1]).await; + finalize_block_and_wait_for_beefy(&net, peers.clone(), &hashes[15], &[9, 13, 14, 15]).await; + + // Alice and Bob finalize #25, Charlie lags behind let finalize = hashes[25]; 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(1).client().as_client().finalize_block(finalize, None).unwrap(); // verify nothing gets finalized by BEEFY - let timeout = Some(Duration::from_millis(250)); + let timeout = Some(Duration::from_millis(100)); streams_empty_after_timeout(best_blocks, &net, timeout).await; streams_empty_after_timeout(versioned_finality_proof, &net, None).await; - // Bob catches up and also finalizes #25 + // Charlie 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(); - // expected beefy finalizes block #17 from diff-power-of-two + net.lock().peer(2).client().as_client().finalize_block(finalize, None).unwrap(); + // expected beefy finalizes blocks 23, 24, 25 from diff-power-of-two wait_for_best_beefy_blocks(best_blocks, &net, &[23, 24, 25]).await; wait_for_beefy_signed_commitments(versioned_finality_proof, &net, &[23, 24, 25]).await; // Both finalize #30 (mandatory session) and #32 -> BEEFY finalize #30 (mandatory), #31, #32 - finalize_block_and_wait_for_beefy( - &net, - peers.clone(), - &[hashes[30], hashes[32]], - &[30, 31, 32], - ) - .await; + finalize_block_and_wait_for_beefy(&net, peers.clone(), &hashes[30], &[30]).await; + finalize_block_and_wait_for_beefy(&net, peers.clone(), &hashes[32], &[31, 32]).await; // 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 + // Alice and Bob finalize session-boundary mandatory block #60, Charlie lags behind let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), peers.clone()); let finalize = hashes[60]; net.lock().peer(0).client().as_client().finalize_block(finalize, None).unwrap(); + net.lock().peer(1).client().as_client().finalize_block(finalize, None).unwrap(); // verify nothing gets finalized by BEEFY - let timeout = Some(Duration::from_millis(250)); + let timeout = Some(Duration::from_millis(100)); streams_empty_after_timeout(best_blocks, &net, timeout).await; streams_empty_after_timeout(versioned_finality_proof, &net, None).await; - // Bob catches up and also finalizes #60 (and should have buffered Alice's vote on #60) + // Charlie 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(2).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, &[60]).await; wait_for_beefy_signed_commitments(versioned_finality_proof, &net, &[60]).await; @@ -696,7 +687,8 @@ async 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, &[hashes[1], hashes[10]], &[1, 9]).await; + finalize_block_and_wait_for_beefy(&net, peers.clone(), &hashes[1], &[1]).await; + finalize_block_and_wait_for_beefy(&net, peers, &hashes[10], &[9]).await; let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), [(0, BeefyKeyring::Alice)].into_iter()); @@ -708,7 +700,7 @@ async fn correct_beefy_payload() { net.lock().peer(3).client().as_client().finalize_block(hashof11, None).unwrap(); // verify consensus is _not_ reached - let timeout = Some(Duration::from_millis(250)); + let timeout = Some(Duration::from_millis(100)); streams_empty_after_timeout(best_blocks, &net, timeout).await; streams_empty_after_timeout(versioned_finality_proof, &net, None).await; @@ -874,39 +866,6 @@ async fn beefy_importing_justifications() { } } -#[tokio::test] -async 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 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); - let api = Arc::new(TestApi::with_validator_set(&validator_set)); - let beefy_peers = peers.iter().enumerate().map(|(id, key)| (id, key, api.clone())).collect(); - tokio::spawn(initialize_beefy(&mut net, beefy_peers, min_block_delta)); - - // push 26 blocks - let hashes = net.generate_blocks_and_sync(26, session_len, &validator_set, false).await; - 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.into_iter().enumerate(), - &[hashes[1], hashes[6], hashes[10], hashes[17], hashes[24], hashes[26]], - &[1, 5, 10, 15, 20, 25], - ) - .await; -} - #[tokio::test] async fn on_demand_beefy_justification_sync() { sp_tracing::try_init_simple(); @@ -940,13 +899,11 @@ async fn on_demand_beefy_justification_sync() { 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(), - &[hashes[1], hashes[6], hashes[10], hashes[17], hashes[23]], - &[1, 5, 10, 15, 20], - ) - .await; + finalize_block_and_wait_for_beefy(&net, fast_peers.clone(), &hashes[1], &[1]).await; + finalize_block_and_wait_for_beefy(&net, fast_peers.clone(), &hashes[6], &[5]).await; + finalize_block_and_wait_for_beefy(&net, fast_peers.clone(), &hashes[10], &[10]).await; + finalize_block_and_wait_for_beefy(&net, fast_peers.clone(), &hashes[17], &[15]).await; + finalize_block_and_wait_for_beefy(&net, fast_peers.clone(), &hashes[24], &[20]).await; // Spawn Dave, they are now way behind voting and can only catch up through on-demand justif // sync. @@ -971,7 +928,8 @@ async fn on_demand_beefy_justification_sync() { // freshly spun up Dave now needs to listen for gossip to figure out the state of their peers. // Have the other peers do some gossip so Dave finds out about their progress. - finalize_block_and_wait_for_beefy(&net, fast_peers, &[hashes[25], hashes[29]], &[25, 29]).await; + finalize_block_and_wait_for_beefy(&net, fast_peers.clone(), &hashes[25], &[25]).await; + finalize_block_and_wait_for_beefy(&net, fast_peers, &hashes[29], &[29]).await; // Kick Dave's async loop by finalizing another block. client.finalize_block(hashes[2], None).unwrap(); @@ -982,13 +940,14 @@ async fn on_demand_beefy_justification_sync() { // Give all tasks some cpu cycles to burn through their events queues, run_for(Duration::from_millis(100), &net).await; // then verify Dave catches up through on-demand justification requests. - finalize_block_and_wait_for_beefy( - &net, - [(dave_index, BeefyKeyring::Dave)].into_iter(), - &[hashes[6], hashes[10], hashes[17], hashes[24], hashes[26]], - &[5, 10, 15, 20, 25], - ) - .await; + let (dave_best_blocks, _) = + get_beefy_streams(&mut net.lock(), [(dave_index, BeefyKeyring::Dave)].into_iter()); + client.finalize_block(hashes[6], None).unwrap(); + client.finalize_block(hashes[10], None).unwrap(); + client.finalize_block(hashes[17], None).unwrap(); + client.finalize_block(hashes[24], None).unwrap(); + client.finalize_block(hashes[26], None).unwrap(); + wait_for_best_beefy_blocks(dave_best_blocks, &net, &[5, 10, 15, 20, 25]).await; } #[tokio::test] @@ -1022,13 +981,8 @@ async fn should_initialize_voter_at_genesis() { // 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) - ); + assert_eq!(persisted_state.best_grandpa_number(), 13); + assert_eq!(persisted_state.voting_oracle().voting_target(), Some(1)); // verify state also saved to db assert!(verify_persisted_version(&*backend)); @@ -1070,13 +1024,8 @@ async fn should_initialize_voter_at_custom_genesis() { // verify next vote target is mandatory block 7 assert_eq!(persisted_state.best_beefy_block(), 0); - assert_eq!(persisted_state.best_grandpa_block(), 8); - assert_eq!( - persisted_state - .voting_oracle() - .voting_target(persisted_state.best_beefy_block(), 13), - Some(custom_pallet_genesis) - ); + assert_eq!(persisted_state.best_grandpa_number(), 8); + assert_eq!(persisted_state.voting_oracle().voting_target(), Some(custom_pallet_genesis)); // verify state also saved to db assert!(verify_persisted_version(&*backend)); @@ -1128,14 +1077,9 @@ async fn should_initialize_voter_when_last_final_is_session_boundary() { // verify block 10 is correctly marked as finalized assert_eq!(persisted_state.best_beefy_block(), 10); - assert_eq!(persisted_state.best_grandpa_block(), 13); + assert_eq!(persisted_state.best_grandpa_number(), 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) - ); + assert_eq!(persisted_state.voting_oracle().voting_target(), Some(12)); // verify state also saved to db assert!(verify_persisted_version(&*backend)); @@ -1186,13 +1130,8 @@ async fn should_initialize_voter_at_latest_finalized() { // 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) - ); + assert_eq!(persisted_state.best_grandpa_number(), 13); + assert_eq!(persisted_state.voting_oracle().voting_target(), Some(13)); // verify state also saved to db assert!(verify_persisted_version(&*backend)); @@ -1225,13 +1164,13 @@ async fn beefy_finalizing_after_pallet_genesis() { // Minimum BEEFY block delta is 1. // GRANDPA finalize blocks leading up to BEEFY pallet genesis -> BEEFY should finalize nothing. - finalize_block_and_wait_for_beefy(&net, peers.clone(), &hashes[1..14], &[]).await; + finalize_block_and_wait_for_beefy(&net, peers.clone(), &hashes[14], &[]).await; // GRANDPA finalize block #16 -> BEEFY should finalize #15 (genesis mandatory) and #16. - finalize_block_and_wait_for_beefy(&net, peers.clone(), &[hashes[16]], &[15, 16]).await; + finalize_block_and_wait_for_beefy(&net, peers.clone(), &hashes[16], &[15, 16]).await; // GRANDPA finalize #21 -> BEEFY finalize #20 (mandatory) and #21 - finalize_block_and_wait_for_beefy(&net, peers.clone(), &[hashes[21]], &[20, 21]).await; + finalize_block_and_wait_for_beefy(&net, peers.clone(), &hashes[21], &[20, 21]).await; } #[tokio::test] @@ -1249,14 +1188,14 @@ async fn beefy_reports_equivocations() { let mut api_alice = TestApi::with_validator_set(&validator_set); api_alice.allow_equivocations(); let api_alice = Arc::new(api_alice); - let alice = (0, &peers[0], api_alice.clone()); + let alice = (0, &BeefyKeyring::Alice, api_alice.clone()); tokio::spawn(initialize_beefy(&mut net, vec![alice], min_block_delta)); // Bob votes on bad MMR roots, equivocations are allowed/expected. let mut api_bob = TestApi::new(1, &validator_set, BAD_MMR_ROOT); api_bob.allow_equivocations(); let api_bob = Arc::new(api_bob); - let bob = (1, &peers[1], api_bob.clone()); + let bob = (1, &BeefyKeyring::Bob, api_bob.clone()); tokio::spawn(initialize_beefy(&mut net, vec![bob], min_block_delta)); // We spawn another node voting with Bob key, on alternate bad MMR roots (equivocating). @@ -1276,7 +1215,7 @@ async fn beefy_reports_equivocations() { let peers = peers.into_iter().enumerate(); // finalize block #1 -> BEEFY should not finalize anything (each node votes on different MMR). - finalize_block_and_wait_for_beefy(&net, peers, &[hashes[1]], &[]).await; + finalize_block_and_wait_for_beefy(&net, peers, &hashes[1], &[]).await; // Verify neither Bob or Bob_Prime report themselves as equivocating. assert!(api_bob.reported_equivocations.as_ref().unwrap().lock().is_empty()); diff --git a/client/consensus/beefy/src/worker.rs b/client/consensus/beefy/src/worker.rs index 0abb38d022ef6..0260d7693c654 100644 --- a/client/consensus/beefy/src/worker.rs +++ b/client/consensus/beefy/src/worker.rs @@ -18,13 +18,13 @@ use crate::{ communication::{ - gossip::{topic, GossipValidator}, + gossip::{topic, GossipValidator, GossipVoteFilter}, request_response::outgoing_requests_engine::OnDemandJustificationsEngine, }, error::Error, justification::BeefyVersionedFinalityProof, keystore::{BeefyKeystore, BeefySignatureHasher}, - metric_get, metric_inc, metric_set, + metric_inc, metric_set, metrics::VoterMetrics, round::{Rounds, VoteImportResult}, BeefyVoterLinks, LOG_TARGET, @@ -42,24 +42,19 @@ use sp_consensus_beefy::{ check_equivocation_proof, crypto::{AuthorityId, Signature}, BeefyApi, Commitment, ConsensusLog, EquivocationProof, PayloadProvider, ValidatorSet, - VersionedFinalityProof, VoteMessage, BEEFY_ENGINE_ID, + ValidatorSetId, VersionedFinalityProof, VoteMessage, BEEFY_ENGINE_ID, }; use sp_runtime::{ generic::OpaqueDigestItemId, - traits::{Block, ConstU32, Header, NumberFor, Zero}, - BoundedVec, SaturatedConversion, + traits::{Block, Header, NumberFor, Zero}, + SaturatedConversion, }; use std::{ collections::{BTreeMap, BTreeSet, VecDeque}, fmt::Debug, - 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; @@ -87,23 +82,34 @@ pub(crate) struct VoterOracle { sessions: VecDeque>, /// Min delta in block numbers between two blocks, BEEFY should vote on. min_block_delta: u32, + /// 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, } impl VoterOracle { /// Verify provided `sessions` satisfies requirements, then build `VoterOracle`. - pub fn checked_new(sessions: VecDeque>, min_block_delta: u32) -> Option { + pub fn checked_new( + sessions: VecDeque>, + min_block_delta: u32, + grandpa_header: ::Header, + best_beefy: NumberFor, + ) -> Option { let mut prev_start = Zero::zero(); let mut prev_validator_id = None; // verifies the let mut validate = || -> bool { - if sessions.is_empty() { + let best_grandpa = *grandpa_header.number(); + if sessions.is_empty() || best_beefy > best_grandpa { return false } for (idx, session) in sessions.iter().enumerate() { + let start = session.session_start(); if session.validators().is_empty() { return false } - if session.session_start() <= prev_start { + if start > best_grandpa || start <= prev_start { return false } #[cfg(not(test))] @@ -125,23 +131,35 @@ impl VoterOracle { sessions, // Always target at least one block better than current best beefy. min_block_delta: min_block_delta.max(1), + best_grandpa_block_header: grandpa_header, + best_beefy_block: best_beefy, }) } else { - error!(target: LOG_TARGET, "🥩 Invalid sessions queue: {:?}.", sessions); + error!( + target: LOG_TARGET, + "🥩 Invalid sessions queue: {:?}; best-beefy {:?} best-grandpa-header {:?}.", + sessions, + best_beefy, + grandpa_header + ); None } } // 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() + fn active_rounds(&self) -> Result<&Rounds, Error> { + self.sessions.front().ok_or(Error::UninitSession) } // 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() + fn active_rounds_mut(&mut self) -> Result<&mut Rounds, Error> { + self.sessions.front_mut().ok_or(Error::UninitSession) + } + + fn current_validator_set_id(&self) -> Result { + self.active_rounds().map(|r| r.validator_set_id()) } // Prune the sessions queue to keep the Oracle in one of the expected three states. @@ -164,7 +182,7 @@ impl VoterOracle { /// 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); + self.active_rounds_mut()?.conclude(block); // Prune any now "finalized" sessions from queue. self.try_prune(); Ok(()) @@ -182,30 +200,26 @@ impl VoterOracle { } /// 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> { + pub fn accepted_interval(&self) -> 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())) + // Accept any vote for a GRANDPA finalized block in a better round. + Ok(( + rounds.session_start().max(self.best_beefy_block), + (*self.best_grandpa_block_header.number()).into(), + )) } else { - // There's at least one session with mandatory not done. + // Current session has 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)?; + pub fn triage_round(&self, round: NumberFor) -> Result { + let (start, end) = self.accepted_interval()?; if start <= round && round <= end { Ok(RoundAction::Process) } else if round > end { @@ -217,17 +231,15 @@ impl VoterOracle { /// 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: NumberFor, - best_grandpa: NumberFor, - ) -> Option> { + pub fn voting_target(&self) -> Option> { let rounds = if let Some(r) = self.sessions.front() { r } else { debug!(target: LOG_TARGET, "🥩 No voting round started"); return None }; + let best_grandpa = *self.best_grandpa_block_header.number(); + let best_beefy = self.best_beefy_block; // `target` is guaranteed > `best_beefy` since `min_block_delta` is at least `1`. let target = @@ -259,10 +271,6 @@ pub(crate) struct WorkerParams { #[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, /// Best block we voted on. best_voted: NumberFor, /// Chooses which incoming votes to accept and which votes to generate. @@ -277,20 +285,26 @@ impl PersistedState { 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, - best_voted: Zero::zero(), - voting_oracle, - }) + VoterOracle::checked_new(sessions, min_block_delta, grandpa_header, best_beefy) + .map(|voting_oracle| PersistedState { best_voted: Zero::zero(), 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_beefy(&mut self, best_beefy: NumberFor) { + self.voting_oracle.best_beefy_block = best_beefy; + } + pub(crate) fn set_best_grandpa(&mut self, best_grandpa: ::Header) { - self.best_grandpa_block_header = best_grandpa; + self.voting_oracle.best_grandpa_block_header = best_grandpa; + } + + pub(crate) fn current_gossip_filter(&self) -> Result, Error> { + let (start, end) = self.voting_oracle.accepted_interval()?; + let validator_set_id = self.voting_oracle.current_validator_set_id()?; + Ok(GossipVoteFilter { start, end, validator_set_id }) } } @@ -315,14 +329,6 @@ pub(crate) struct BeefyWorker { // voter state /// BEEFY client metrics. metrics: Option, - /// Buffer holding votes for future processing. - pending_votes: BTreeMap< - NumberFor, - BoundedVec< - VoteMessage, AuthorityId, Signature>, - ConstU32, - >, - >, /// Buffer holding justifications for future processing. pending_justifications: BTreeMap, BeefyVersionedFinalityProof>, /// Persisted voter state. @@ -370,25 +376,20 @@ where on_demand_justifications, links, metrics, - pending_votes: BTreeMap::new(), pending_justifications: BTreeMap::new(), 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 + *self.persisted_state.voting_oracle.best_grandpa_block_header.number() } fn voting_oracle(&self) -> &VoterOracle { &self.persisted_state.voting_oracle } - fn active_rounds(&mut self) -> Option<&Rounds> { + fn active_rounds(&mut self) -> Result<&Rounds, Error> { self.persisted_state.voting_oracle.active_rounds() } @@ -429,7 +430,7 @@ where debug!(target: LOG_TARGET, "🥩 New active validator set: {:?}", validator_set); // BEEFY should finalize a mandatory block during each session. - if let Some(active_session) = self.active_rounds() { + if let Ok(active_session) = self.active_rounds() { if !active_session.mandatory_done() { debug!( target: LOG_TARGET, @@ -460,12 +461,17 @@ where } fn handle_finality_notification(&mut self, notification: &FinalityNotification) { - debug!(target: LOG_TARGET, "🥩 Finality notification: {:?}", notification); + debug!( + target: LOG_TARGET, + "🥩 Finality notification: header {:?} tree_route {:?}", + notification.header, + notification.tree_route, + ); let header = ¬ification.header; if *header.number() > self.best_grandpa_block() { // update best GRANDPA finalized block we have seen - self.persisted_state.best_grandpa_block_header = header.clone(); + self.persisted_state.set_best_grandpa(header.clone()); // Check all (newly) finalized blocks for new session(s). let backend = self.backend.clone(); @@ -484,38 +490,28 @@ where self.init_session_at(new_validator_set, *header.number()); } } + + // Update gossip validator votes filter. + if let Err(e) = self + .persisted_state + .current_gossip_filter() + .map(|filter| self.gossip_validator.update_filter(filter)) + { + error!(target: LOG_TARGET, "🥩 Voter error: {:?}", e); + } } } - /// Based on [VoterOracle] this vote is either processed here or enqueued for later. + /// Based on [VoterOracle] this vote is either processed here or discarded. 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(); - self.gossip_validator.note_round(block_num); - match self.voting_oracle().triage_round(block_num, best_grandpa)? { + match self.voting_oracle().triage_round(block_num)? { RoundAction::Process => self.handle_vote(vote)?, - RoundAction::Enqueue => { - debug!(target: LOG_TARGET, "🥩 Buffer vote for round: {:?}.", block_num); - 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_ok() { - metric_inc!(self, beefy_buffered_votes); - } else { - warn!( - target: LOG_TARGET, - "🥩 Buffer vote dropped for round: {:?}", block_num - ); - metric_inc!(self, beefy_buffered_votes_dropped); - } - } else { - warn!(target: LOG_TARGET, "🥩 Buffer vote dropped for round: {:?}.", block_num); - metric_inc!(self, beefy_buffered_votes_dropped); - } - }, RoundAction::Drop => metric_inc!(self, beefy_stale_votes), + RoundAction::Enqueue => error!(target: LOG_TARGET, "🥩 unexpected vote: {:?}.", vote), }; Ok(()) } @@ -531,8 +527,7 @@ where VersionedFinalityProof::V1(ref sc) => sc, }; let block_num = signed_commitment.commitment.block_number; - let best_grandpa = self.best_grandpa_block(); - match self.voting_oracle().triage_round(block_num, best_grandpa)? { + match self.voting_oracle().triage_round(block_num)? { RoundAction::Process => { debug!(target: LOG_TARGET, "🥩 Process justification for round: {:?}.", block_num); metric_inc!(self, beefy_imported_justifications); @@ -560,11 +555,7 @@ where &mut self, vote: VoteMessage, AuthorityId, Signature>, ) -> Result<(), Error> { - let rounds = self - .persisted_state - .voting_oracle - .active_rounds_mut() - .ok_or(Error::UninitSession)?; + let rounds = self.persisted_state.voting_oracle.active_rounds_mut()?; let block_number = vote.commitment.block_number; match rounds.add_vote(vote) { @@ -608,7 +599,7 @@ where /// 3. Persist voter state, /// 4. Send best block hash and `finality_proof` to RPC worker. /// - /// Expects `finality proof` to be valid. + /// Expects `finality proof` to be valid and for a block > current-best-beefy. fn finalize(&mut self, finality_proof: BeefyVersionedFinalityProof) -> Result<(), Error> { let block_num = match finality_proof { VersionedFinalityProof::V1(ref sc) => sc.commitment.block_number, @@ -616,74 +607,62 @@ where // Finalize inner round and update voting_oracle state. self.persisted_state.voting_oracle.finalize(block_num)?; - self.gossip_validator.conclude_round(block_num); - if block_num > self.best_beefy_block() { - // Set new best BEEFY block number. - 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()))?; + // Set new best BEEFY block number. + self.persisted_state.set_best_beefy(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); + metric_set!(self, beefy_best_block, block_num); - self.on_demand_justifications.cancel_requests_older_than(block_num); + self.on_demand_justifications.cancel_requests_older_than(block_num); - 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: LOG_TARGET, - "🥩 Error {:?} on appending justification: {:?}", e, finality_proof - ); - } - - self.links - .to_rpc_justif_sender - .notify(|| Ok::<_, ()>(finality_proof)) - .expect("forwards closure result; the closure always returns Ok; qed."); - } else { - debug!(target: LOG_TARGET, "🥩 Can't set best beefy to old: {}", block_num); - metric_set!(self, beefy_best_block_set_last_failure, block_num); + 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: LOG_TARGET, + "🥩 Error {:?} on appending justification: {:?}", e, finality_proof + ); } + + self.links + .to_rpc_justif_sender + .notify(|| Ok::<_, ()>(finality_proof)) + .expect("forwards closure result; the closure always returns Ok; qed."); + + // Update gossip validator votes filter. + self.persisted_state + .current_gossip_filter() + .map(|filter| self.gossip_validator.update_filter(filter))?; Ok(()) } - /// 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(); - let _ph = PhantomData::::default(); - - fn to_process_for( - pending: &mut BTreeMap, T>, - (start, end): (NumberFor, NumberFor), - _: PhantomData, - ) -> BTreeMap, T> { + /// Handle previously buffered justifications, that now land in the voting interval. + fn try_pending_justififactions(&mut self) -> Result<(), Error> { + // Interval of blocks for which we can process justifications and votes right now. + let (start, end) = self.voting_oracle().accepted_interval()?; + // Process pending justifications. + if !self.pending_justifications.is_empty() { // These are still pending. - let still_pending = pending.split_off(&end.saturating_add(1u32.into())); + let still_pending = + self.pending_justifications.split_off(&end.saturating_add(1u32.into())); // These can be processed. - let to_handle = pending.split_off(&start); + let justifs_to_process = self.pending_justifications.split_off(&start); // The rest can be dropped. - *pending = still_pending; - // 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)?; + self.pending_justifications = still_pending; - // Process pending justifications. - if !self.pending_justifications.is_empty() { - let justifs_to_handle = to_process_for(&mut self.pending_justifications, interval, _ph); - for (num, justification) in justifs_to_handle.into_iter() { + for (num, justification) in justifs_to_process.into_iter() { debug!(target: LOG_TARGET, "🥩 Handle buffered justification for: {:?}.", num); metric_inc!(self, beefy_imported_justifications); if let Err(err) = self.finalize(justification) { @@ -691,27 +670,6 @@ where } } metric_set!(self, beefy_buffered_justifications, self.pending_justifications.len()); - // Possibly new interval after processing justifications. - interval = self.voting_oracle().accepted_interval(best_grandpa)?; - } - - // Process pending votes. - if !self.pending_votes.is_empty() { - let mut processed = 0u64; - let votes_to_handle = to_process_for(&mut self.pending_votes, interval, _ph); - for (num, votes) in votes_to_handle.into_iter() { - debug!(target: LOG_TARGET, "🥩 Handle buffered votes for: {:?}.", num); - processed += votes.len() as u64; - for v in votes.into_iter() { - if let Err(err) = self.handle_vote(v) { - error!(target: LOG_TARGET, "🥩 Error handling buffered vote: {}", err); - }; - } - } - if let Some(previous) = metric_get!(self, beefy_buffered_votes) { - previous.sub(processed); - metric_set!(self, beefy_buffered_votes, previous.get()); - } } Ok(()) } @@ -719,10 +677,7 @@ where /// 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()) - { + if let Some(target) = self.voting_oracle().voting_target() { metric_set!(self, beefy_should_vote_on, target); if target > self.persisted_state.best_voted { self.do_vote(target)?; @@ -740,7 +695,7 @@ 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() { - self.persisted_state.best_grandpa_block_header.clone() + self.persisted_state.voting_oracle.best_grandpa_block_header.clone() } else { let hash = self .backend @@ -771,11 +726,7 @@ where return Ok(()) }; - let rounds = self - .persisted_state - .voting_oracle - .active_rounds_mut() - .ok_or(Error::UninitSession)?; + let rounds = self.persisted_state.voting_oracle.active_rounds_mut()?; let (validators, validator_set_id) = (rounds.validators(), rounds.validator_set_id()); let authority_id = if let Some(id) = self.key_store.authority_id(validators) { @@ -830,7 +781,7 @@ where fn process_new_state(&mut self) { // Handle pending justifications and/or votes for now GRANDPA finalized blocks. - if let Err(err) = self.try_pending_justif_and_votes() { + if let Err(err) = self.try_pending_justififactions() { debug!(target: LOG_TARGET, "🥩 {}", err); } @@ -867,12 +818,12 @@ where self.gossip_engine .messages_for(topic::()) .filter_map(|notification| async move { - trace!(target: LOG_TARGET, "🥩 Got vote message: {:?}", notification); - - VoteMessage::, AuthorityId, Signature>::decode( + let vote = VoteMessage::, AuthorityId, Signature>::decode( &mut ¬ification.message[..], ) - .ok() + .ok(); + trace!(target: LOG_TARGET, "🥩 Got vote message: {:?}", vote); + vote }) .fuse(), ); @@ -946,8 +897,7 @@ where &self, proof: EquivocationProof, AuthorityId, Signature>, ) -> Result<(), Error> { - let rounds = - self.persisted_state.voting_oracle.active_rounds().ok_or(Error::UninitSession)?; + let rounds = self.persisted_state.voting_oracle.active_rounds()?; let (validators, validator_set_id) = (rounds.validators(), rounds.validator_set_id()); let offender_id = proof.offender_id().clone(); @@ -1083,16 +1033,16 @@ pub(crate) mod tests { &self.voting_oracle } - pub fn active_round(&self) -> Option<&Rounds> { + pub fn active_round(&self) -> Result<&Rounds, Error> { self.voting_oracle.active_rounds() } pub fn best_beefy_block(&self) -> NumberFor { - self.best_beefy_block + self.voting_oracle.best_beefy_block } - pub fn best_grandpa_block(&self) -> NumberFor { - *self.best_grandpa_block_header.number() + pub fn best_grandpa_number(&self) -> NumberFor { + *self.voting_oracle.best_grandpa_block_header.number() } } @@ -1103,7 +1053,7 @@ pub(crate) mod tests { } fn create_beefy_worker( - peer: &BeefyPeer, + peer: &mut BeefyPeer, key: &Keyring, min_block_delta: u32, genesis_validator_set: ValidatorSet, @@ -1153,12 +1103,15 @@ pub(crate) mod tests { known_peers, None, ); - let genesis_header = backend + // Push 1 block - will start first session. + let hashes = peer.push_blocks(1, false); + backend.finalize_block(hashes[0], None).unwrap(); + let first_header = backend .blockchain() - .expect_header(backend.blockchain().info().genesis_hash) + .expect_header(backend.blockchain().info().best_hash) .unwrap(); let persisted_state = PersistedState::checked_new( - genesis_header, + first_header, Zero::zero(), vec![Rounds::new(One::one(), genesis_validator_set)].into(), min_block_delta, @@ -1275,10 +1228,30 @@ pub(crate) mod tests { #[test] fn should_vote_target() { - let mut oracle = VoterOracle:: { min_block_delta: 1, sessions: VecDeque::new() }; + let header = Header::new( + 1u32.into(), + Default::default(), + Default::default(), + Default::default(), + Digest::default(), + ); + let mut oracle = VoterOracle:: { + best_beefy_block: 0, + best_grandpa_block_header: header, + min_block_delta: 1, + sessions: VecDeque::new(), + }; + let voting_target_with = |oracle: &mut VoterOracle, + best_beefy: NumberFor, + best_grandpa: NumberFor| + -> Option> { + oracle.best_beefy_block = best_beefy; + oracle.best_grandpa_block_header.number = best_grandpa; + oracle.voting_target() + }; // rounds not initialized -> should vote: `None` - assert_eq!(oracle.voting_target(0, 1), None); + assert_eq!(voting_target_with(&mut oracle, 0, 1), None); let keys = &[Keyring::Alice]; let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); @@ -1287,29 +1260,29 @@ pub(crate) mod tests { // under min delta oracle.min_block_delta = 4; - assert_eq!(oracle.voting_target(1, 1), None); - assert_eq!(oracle.voting_target(2, 5), None); + assert_eq!(voting_target_with(&mut oracle, 1, 1), None); + assert_eq!(voting_target_with(&mut oracle, 2, 5), None); // vote on min delta - assert_eq!(oracle.voting_target(4, 9), Some(8)); + assert_eq!(voting_target_with(&mut oracle, 4, 9), Some(8)); oracle.min_block_delta = 8; - assert_eq!(oracle.voting_target(10, 18), Some(18)); + assert_eq!(voting_target_with(&mut oracle, 10, 18), Some(18)); // vote on power of two oracle.min_block_delta = 1; - assert_eq!(oracle.voting_target(1000, 1008), Some(1004)); - assert_eq!(oracle.voting_target(1000, 1016), Some(1008)); + assert_eq!(voting_target_with(&mut oracle, 1000, 1008), Some(1004)); + assert_eq!(voting_target_with(&mut oracle, 1000, 1016), Some(1008)); // nothing new to vote on - assert_eq!(oracle.voting_target(1000, 1000), None); + assert_eq!(voting_target_with(&mut oracle, 1000, 1000), None); // vote on mandatory oracle.sessions.clear(); oracle.add_session(Rounds::new(1000, validator_set.clone())); - assert_eq!(oracle.voting_target(0, 1008), Some(1000)); + assert_eq!(voting_target_with(&mut oracle, 0, 1008), Some(1000)); oracle.sessions.clear(); oracle.add_session(Rounds::new(1001, validator_set.clone())); - assert_eq!(oracle.voting_target(1000, 1008), Some(1001)); + assert_eq!(voting_target_with(&mut oracle, 1000, 1008), Some(1001)); } #[test] @@ -1317,16 +1290,34 @@ pub(crate) mod tests { let keys = &[Keyring::Alice]; let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); - let mut oracle = VoterOracle:: { min_block_delta: 1, sessions: VecDeque::new() }; + let header = Header::new( + 1u32.into(), + Default::default(), + Default::default(), + Default::default(), + Digest::default(), + ); + let mut oracle = VoterOracle:: { + best_beefy_block: 0, + best_grandpa_block_header: header, + min_block_delta: 1, + sessions: VecDeque::new(), + }; + let accepted_interval_with = |oracle: &mut VoterOracle, + best_grandpa: NumberFor| + -> Result<(NumberFor, NumberFor), Error> { + oracle.best_grandpa_block_header.number = best_grandpa; + oracle.accepted_interval() + }; // rounds not initialized -> should accept votes: `None` - assert!(oracle.accepted_interval(1).is_err()); + assert!(accepted_interval_with(&mut oracle, 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))); + assert_eq!(accepted_interval_with(&mut oracle, i), Ok((session_one, session_one))); } // add more sessions, nothing changes @@ -1336,7 +1327,7 @@ pub(crate) mod tests { 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))); + assert_eq!(accepted_interval_with(&mut oracle, i), Ok((session_one, session_one))); } // simulate finish mandatory for session one, prune oracle @@ -1344,7 +1335,7 @@ pub(crate) mod tests { 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))); + assert_eq!(accepted_interval_with(&mut oracle, i), Ok((session_two, session_two))); } // simulate finish mandatory for session two, prune oracle @@ -1352,26 +1343,29 @@ pub(crate) mod tests { 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))); + assert_eq!(accepted_interval_with(&mut oracle, 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))); + assert_eq!(accepted_interval_with(&mut oracle, 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))); + assert_eq!(accepted_interval_with(&mut oracle, 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))); + assert_eq!( + accepted_interval_with(&mut oracle, session_four + 10), + Ok((session_four, session_four)) + ); } #[test] @@ -1405,7 +1399,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, validator_set.clone()); + 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(())); @@ -1429,7 +1423,7 @@ 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, validator_set.clone()); + 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(); @@ -1449,7 +1443,7 @@ pub(crate) mod tests { }; // no 'best beefy block' or finality proofs - assert_eq!(worker.best_beefy_block(), 0); + assert_eq!(worker.persisted_state.best_beefy_block(), 0); 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); @@ -1457,6 +1451,7 @@ pub(crate) mod tests { }) .await; + let client = net.peer(0).client().as_client(); // unknown hash for block #1 let (mut best_block_streams, mut finality_proofs) = get_beefy_streams(&mut net, keys.clone()); @@ -1471,10 +1466,16 @@ pub(crate) mod tests { // try to finalize block #1 worker.finalize(justif.clone()).unwrap(); // verify block finalized - assert_eq!(worker.best_beefy_block(), 1); + assert_eq!(worker.persisted_state.best_beefy_block(), 1); poll_fn(move |cx| { - // unknown hash -> nothing streamed - assert_eq!(best_block_stream.poll_next_unpin(cx), Poll::Pending); + // expect Some(hash-of-block-1) + match best_block_stream.poll_next_unpin(cx) { + Poll::Ready(Some(hash)) => { + let block_num = client.number(hash).unwrap(); + assert_eq!(block_num, Some(1)); + }, + v => panic!("unexpected value: {:?}", v), + } // commitment streamed match finality_proof.poll_next_unpin(cx) { // expect justification @@ -1488,11 +1489,9 @@ 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(); - let hashes = net.peer(0).push_blocks(2, false); + let hashes = net.peer(0).push_blocks(1, false); // finalize 1 and 2 without justifications (hashes does not contain genesis) - let hashof1 = hashes[0]; - let hashof2 = hashes[1]; - backend.finalize_block(hashof1, None).unwrap(); + let hashof2 = hashes[0]; backend.finalize_block(hashof2, None).unwrap(); let justif = create_finality_proof(2); @@ -1504,7 +1503,7 @@ pub(crate) mod tests { // new session starting at #2 is in front assert_eq!(worker.active_rounds().unwrap().session_start(), 2); // verify block finalized - assert_eq!(worker.best_beefy_block(), 2); + assert_eq!(worker.persisted_state.best_beefy_block(), 2); poll_fn(move |cx| { match best_block_stream.poll_next_unpin(cx) { // expect Some(hash-of-block-2) @@ -1528,7 +1527,7 @@ 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, validator_set.clone()); + let mut worker = create_beefy_worker(net.peer(0), &keys[0], 1, validator_set.clone()); let worker_rounds = worker.active_rounds().unwrap(); assert_eq!(worker_rounds.session_start(), 1); @@ -1554,77 +1553,6 @@ pub(crate) mod tests { assert_eq!(rounds.validator_set_id(), new_validator_set.id()); } - #[tokio::test] - async 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 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, - ) -> VoteMessage, AuthorityId, Signature> { - let commitment = Commitment { - payload: Payload::from_single_entry(*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(), - ); - - 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(); - 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 - .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); - } - #[tokio::test] async fn should_not_report_bad_old_or_self_equivocations() { let block_num = 1; @@ -1637,7 +1565,7 @@ pub(crate) mod tests { let api_alice = Arc::new(api_alice); let mut net = BeefyTestNet::new(1); - let mut worker = create_beefy_worker(&net.peer(0), &keys[0], 1, validator_set.clone()); + let mut worker = create_beefy_worker(net.peer(0), &keys[0], 1, validator_set.clone()); worker.runtime = api_alice.clone(); // let there be a block with num = 1: From 8a9f48bcf0c9f92949082535d77c12166522bb2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Thu, 16 Mar 2023 12:24:20 +0100 Subject: [PATCH 518/715] Try to fix flaky `temp-base-path-work` test (#13505) * Try to fix flaky `temp-base-path-work` test The test is most of the time failing when checking if the database path was deleted. The assumption is that it takes a little bit more time by the OS to actually clean up the temp path under high load. The pr tries to fix this by checking multiple times if the path was deleted. Besides that it also ensures that the tests that require the benchmark feature don't fail when compiled without the feature. * ".git/.scripts/commands/fmt/fmt.sh" * Capture signals earlier * Rewrite tests to let them having one big timeout * Remove unneeded dep * Update bin/node/cli/tests/common.rs Co-authored-by: Koute * Review feedback * Update bin/node/cli/tests/common.rs Co-authored-by: Anton --------- Co-authored-by: command-bot <> Co-authored-by: Koute Co-authored-by: Anton --- bin/node/cli/tests/benchmark_pallet_works.rs | 2 + bin/node/cli/tests/benchmark_storage_works.rs | 2 + bin/node/cli/tests/common.rs | 132 ++++++++-------- .../tests/running_the_node_and_interrupt.rs | 143 ++++++++---------- bin/node/cli/tests/telemetry.rs | 131 ++++++++-------- bin/node/cli/tests/temp_base_path_works.rs | 63 ++++---- client/cli/src/lib.rs | 14 +- client/cli/src/runner.rs | 97 +++++++----- 8 files changed, 296 insertions(+), 288 deletions(-) diff --git a/bin/node/cli/tests/benchmark_pallet_works.rs b/bin/node/cli/tests/benchmark_pallet_works.rs index 1a278f985da4f..053516b9521d1 100644 --- a/bin/node/cli/tests/benchmark_pallet_works.rs +++ b/bin/node/cli/tests/benchmark_pallet_works.rs @@ -16,6 +16,8 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +#![cfg(feature = "runtime-benchmarks")] + use assert_cmd::cargo::cargo_bin; use std::process::Command; diff --git a/bin/node/cli/tests/benchmark_storage_works.rs b/bin/node/cli/tests/benchmark_storage_works.rs index 1f1181218db03..953c07ca7f0db 100644 --- a/bin/node/cli/tests/benchmark_storage_works.rs +++ b/bin/node/cli/tests/benchmark_storage_works.rs @@ -16,6 +16,8 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +#![cfg(feature = "runtime-benchmarks")] + use assert_cmd::cargo::cargo_bin; use std::{ path::Path, diff --git a/bin/node/cli/tests/common.rs b/bin/node/cli/tests/common.rs index a0de7300fca90..4c4824391fdc1 100644 --- a/bin/node/cli/tests/common.rs +++ b/bin/node/cli/tests/common.rs @@ -20,54 +20,26 @@ use assert_cmd::cargo::cargo_bin; use nix::{ - sys::signal::{kill, Signal::SIGINT}, + sys::signal::{kill, Signal, Signal::SIGINT}, unistd::Pid, }; use node_primitives::{Hash, Header}; +use regex::Regex; use std::{ io::{BufRead, BufReader, Read}, ops::{Deref, DerefMut}, - path::Path, - process::{self, Child, Command, ExitStatus}, + path::{Path, PathBuf}, + process::{self, Child, Command}, time::Duration, }; -use tokio::time::timeout; -/// 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: 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(()) - } -} - -/// 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, - url: &str, -) -> Result<(), tokio::time::error::Elapsed> { - timeout(Duration::from_secs(timeout_secs), wait_n_finalized_blocks_from(n, url)).await +/// Run the given `future` and panic if the `timeout` is hit. +pub async fn run_with_timeout(timeout: Duration, future: impl futures::Future) { + tokio::time::timeout(timeout, future).await.expect("Hit timeout"); } /// 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) { +pub async fn wait_n_finalized_blocks(n: usize, url: &str) { use substrate_rpc_client::{ws_client, ChainApi}; let mut built_blocks = std::collections::HashSet::new(); @@ -87,46 +59,54 @@ 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")) - .stdout(process::Stdio::piped()) - .stderr(process::Stdio::piped()) - .args(args) - .arg("-d") - .arg(base_path) - .spawn() - .unwrap(); + run_with_timeout(Duration::from_secs(60 * 10), async move { + 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 stderr = cmd.stderr.take().unwrap(); + let stderr = cmd.stderr.take().unwrap(); - let mut child = KillChildOnDrop(cmd); + let mut child = KillChildOnDrop(cmd); - let (ws_url, _) = find_ws_url_from_output(stderr); + let ws_url = extract_info_from_output(stderr).0.ws_url; - // Let it produce some blocks. - let _ = wait_n_finalized_blocks(3, 30, &ws_url).await; + // Let it produce some blocks. + wait_n_finalized_blocks(3, &ws_url).await; - assert!(child.try_wait().unwrap().is_none(), "the process should still be running"); + child.assert_still_running(); - // Stop the process - kill(Pid::from_raw(child.id().try_into().unwrap()), SIGINT).unwrap(); - assert!(wait_for(&mut child, 40).map(|x| x.success()).unwrap()); + // Stop the process + child.stop(); + }) + .await } -/// 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")); +pub struct KillChildOnDrop(pub Child); - let mut child = KillChildOnDrop(cmd.args(args).arg("-d").arg(base_path).spawn().unwrap()); +impl KillChildOnDrop { + /// Stop the child and wait until it is finished. + /// + /// Asserts if the exit status isn't success. + pub fn stop(&mut self) { + self.stop_with_signal(SIGINT); + } - // 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" - ); -} + /// Same as [`Self::stop`] but takes the `signal` that is sent to stop the child. + pub fn stop_with_signal(&mut self, signal: Signal) { + kill(Pid::from_raw(self.id().try_into().unwrap()), signal).unwrap(); + assert!(self.wait().unwrap().success()); + } -pub struct KillChildOnDrop(pub Child); + /// Asserts that the child is still running. + pub fn assert_still_running(&mut self) { + assert!(self.try_wait().unwrap().is_none(), "the process should still be running"); + } +} impl Drop for KillChildOnDrop { fn drop(&mut self) { @@ -148,18 +128,22 @@ impl DerefMut for KillChildOnDrop { } } -/// Read the WS address from the output. +/// Information extracted from a running node. +pub struct NodeInfo { + pub ws_url: String, + pub db_path: PathBuf, +} + +/// Extract [`NodeInfo`] from a running node by parsing its 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) { +/// Returns the [`NodeInfo`] and all the read data. +pub fn extract_info_from_output(read: impl Read + Send) -> (NodeInfo, 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"); + let line = line.expect("failed to obtain next line while extracting node info"); data.push_str(&line); data.push_str("\n"); @@ -176,5 +160,9 @@ pub fn find_ws_url_from_output(read: impl Read + Send) -> (String, String) { panic!("We should get a WebSocket address") }); - (ws_url, data) + // Database path is printed before the ws url! + let re = Regex::new(r"Database: .+ at (\S+)").unwrap(); + let db_path = PathBuf::from(re.captures(data.as_str()).unwrap().get(1).unwrap().as_str()); + + (NodeInfo { ws_url, db_path }, 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 fc0bf69a099ba..3d5598f3fbe23 100644 --- a/bin/node/cli/tests/running_the_node_and_interrupt.rs +++ b/bin/node/cli/tests/running_the_node_and_interrupt.rs @@ -18,94 +18,81 @@ #![cfg(unix)] use assert_cmd::cargo::cargo_bin; -use nix::{ - sys::signal::{ - kill, - Signal::{self, SIGINT, SIGTERM}, - }, - unistd::Pid, +use nix::sys::signal::Signal::{self, SIGINT, SIGTERM}; +use std::{ + process::{self, Child, Command}, + time::Duration, }; -use std::process::{self, Child, Command}; use tempfile::tempdir; pub mod common; #[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 = common::KillChildOnDrop( + common::run_with_timeout(Duration::from_secs(60 * 10), async move { + async fn run_command_and_kill(signal: Signal) { + 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") + .arg("--no-hardware-benchmarks") + .spawn() + .unwrap(), + ); + + let stderr = cmd.stderr.take().unwrap(); + + let ws_url = common::extract_info_from_output(stderr).0.ws_url; + + common::wait_n_finalized_blocks(3, &ws_url).await; + + cmd.assert_still_running(); + + cmd.stop_with_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; + run_command_and_kill(SIGTERM).await; + }) + .await; +} + +#[tokio::test] +async fn running_two_nodes_with_the_same_ws_port_should_work() { + common::run_with_timeout(Duration::from_secs(60 * 10), async move { + fn start_node() -> Child { Command::new(cargo_bin("substrate")) .stdout(process::Stdio::piped()) .stderr(process::Stdio::piped()) - .args(&["--dev", "-d"]) - .arg(base_path.path()) - .arg("--db=paritydb") - .arg("--no-hardware-benchmarks") + .args(&["--dev", "--tmp", "--ws-port=45789", "--no-hardware-benchmarks"]) .spawn() - .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!( - common::wait_for(&mut cmd, 30).map(|x| x.success()), - Ok(true), - "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; - run_command_and_kill(SIGTERM).await; -} + .unwrap() + } -#[tokio::test] -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() - } - - let mut first_node = common::KillChildOnDrop(start_node()); - let mut second_node = common::KillChildOnDrop(start_node()); - - 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"); - - kill(Pid::from_raw(first_node.id().try_into().unwrap()), SIGINT).unwrap(); - kill(Pid::from_raw(second_node.id().try_into().unwrap()), SIGINT).unwrap(); - - assert_eq!( - common::wait_for(&mut first_node, 30).map(|x| x.success()), - Ok(true), - "The first node must exit gracefully", - ); - assert_eq!( - common::wait_for(&mut second_node, 30).map(|x| x.success()), - Ok(true), - "The second node must exit gracefully", - ); + let mut first_node = common::KillChildOnDrop(start_node()); + let mut second_node = common::KillChildOnDrop(start_node()); + + let stderr = first_node.stderr.take().unwrap(); + let ws_url = common::extract_info_from_output(stderr).0.ws_url; + + common::wait_n_finalized_blocks(3, &ws_url).await; + + first_node.assert_still_running(); + second_node.assert_still_running(); + + first_node.stop(); + second_node.stop(); + }) + .await; } diff --git a/bin/node/cli/tests/telemetry.rs b/bin/node/cli/tests/telemetry.rs index 633cc996ca615..a68746a2c0011 100644 --- a/bin/node/cli/tests/telemetry.rs +++ b/bin/node/cli/tests/telemetry.rs @@ -17,78 +17,75 @@ // along with this program. If not, see . use assert_cmd::cargo::cargo_bin; -use nix::{ - sys::signal::{kill, Signal::SIGINT}, - unistd::Pid, -}; -use std::process; +use std::{process, time::Duration}; + +use crate::common::KillChildOnDrop; pub mod common; pub mod websocket_server; #[tokio::test] async fn telemetry_works() { - let config = websocket_server::Config { - capacity: 1, - max_frame_size: 1048 * 1024, - send_buffer_len: 32, - bind_address: "127.0.0.1:0".parse().unwrap(), - }; - let mut server = websocket_server::WsServer::new(config).await.unwrap(); - - let addr = server.local_addr().unwrap(); - - let server_task = tokio::spawn(async move { - loop { - use websocket_server::Event; - match server.next_event().await { - // New connection on the listener. - Event::ConnectionOpen { address } => { - println!("New connection from {:?}", address); - server.accept(); - }, - - // Received a message from a connection. - Event::BinaryFrame { message, .. } => { - let json: serde_json::Value = serde_json::from_slice(&message).unwrap(); - let object = - json.as_object().unwrap().get("payload").unwrap().as_object().unwrap(); - if matches!(object.get("best"), Some(serde_json::Value::String(_))) { - break - } - }, - - Event::TextFrame { .. } => panic!("Got a TextFrame over the socket, this is a bug"), - - // Connection has been closed. - Event::ConnectionError { .. } => {}, + common::run_with_timeout(Duration::from_secs(60 * 10), async move { + let config = websocket_server::Config { + capacity: 1, + max_frame_size: 1048 * 1024, + send_buffer_len: 32, + bind_address: "127.0.0.1:0".parse().unwrap(), + }; + let mut server = websocket_server::WsServer::new(config).await.unwrap(); + + let addr = server.local_addr().unwrap(); + + let server_task = tokio::spawn(async move { + loop { + use websocket_server::Event; + match server.next_event().await { + // New connection on the listener. + Event::ConnectionOpen { address } => { + println!("New connection from {:?}", address); + server.accept(); + }, + + // Received a message from a connection. + Event::BinaryFrame { message, .. } => { + let json: serde_json::Value = serde_json::from_slice(&message).unwrap(); + let object = + json.as_object().unwrap().get("payload").unwrap().as_object().unwrap(); + if matches!(object.get("best"), Some(serde_json::Value::String(_))) { + break + } + }, + + Event::TextFrame { .. } => + panic!("Got a TextFrame over the socket, this is a bug"), + + // Connection has been closed. + Event::ConnectionError { .. } => {}, + } } - } - }); - - let mut substrate = process::Command::new(cargo_bin("substrate")); - - 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()) - .spawn() - .unwrap(); - - server_task.await.expect("server task panicked"); - - assert!(substrate.try_wait().unwrap().is_none(), "the process should still be running"); - - // Stop the process - kill(Pid::from_raw(substrate.id().try_into().unwrap()), SIGINT).unwrap(); - assert!(common::wait_for(&mut substrate, 40).map(|x| x.success()).unwrap_or_default()); - - let output = substrate.wait_with_output().unwrap(); - - println!("{}", String::from_utf8(output.stdout).unwrap()); - eprintln!("{}", String::from_utf8(output.stderr).unwrap()); - assert!(output.status.success()); + }); + + let mut substrate = process::Command::new(cargo_bin("substrate")); + + let mut substrate = KillChildOnDrop( + 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()) + .spawn() + .unwrap(), + ); + + server_task.await.expect("server task panicked"); + + substrate.assert_still_running(); + + // Stop the process + substrate.stop(); + }) + .await; } diff --git a/bin/node/cli/tests/temp_base_path_works.rs b/bin/node/cli/tests/temp_base_path_works.rs index 4e743f2d3abd4..89e901c00e118 100644 --- a/bin/node/cli/tests/temp_base_path_works.rs +++ b/bin/node/cli/tests/temp_base_path_works.rs @@ -19,45 +19,42 @@ #![cfg(unix)] use assert_cmd::cargo::cargo_bin; -use nix::{ - sys::signal::{kill, Signal::SIGINT}, - unistd::Pid, -}; -use regex::Regex; use std::{ - io::Read, - path::PathBuf, process::{Command, Stdio}, + time::Duration, }; pub mod common; #[tokio::test] async fn temp_base_path_works() { - let mut cmd = Command::new(cargo_bin("substrate")); - let mut child = common::KillChildOnDrop( - cmd.args(&["--dev", "--tmp", "--no-hardware-benchmarks"]) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()) - .spawn() - .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, &ws_url).await.unwrap(); - assert!(child.try_wait().unwrap().is_none(), "the process should still be running"); - - // Stop the process - 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 - stderr.read_to_string(&mut data).unwrap(); - let re = Regex::new(r"Database: .+ at (\S+)").unwrap(); - let db_path = PathBuf::from(re.captures(data.as_str()).unwrap().get(1).unwrap().as_str()); - - assert!(!db_path.exists()); + common::run_with_timeout(Duration::from_secs(60 * 10), async move { + let mut cmd = Command::new(cargo_bin("substrate")); + let mut child = common::KillChildOnDrop( + cmd.args(&["--dev", "--tmp", "--no-hardware-benchmarks"]) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn() + .unwrap(), + ); + + let mut stderr = child.stderr.take().unwrap(); + let node_info = common::extract_info_from_output(&mut stderr).0; + + // Let it produce some blocks. + common::wait_n_finalized_blocks(3, &node_info.ws_url).await; + + // Ensure the db path exists while the node is running + assert!(node_info.db_path.exists()); + + child.assert_still_running(); + + // Stop the process + child.stop(); + + if node_info.db_path.exists() { + panic!("Database path `{}` wasn't deleted!", node_info.db_path.display()); + } + }) + .await; } diff --git a/client/cli/src/lib.rs b/client/cli/src/lib.rs index adbb299317ac9..e73321ecce5b3 100644 --- a/client/cli/src/lib.rs +++ b/client/cli/src/lib.rs @@ -197,10 +197,15 @@ pub trait SubstrateCli: Sized { command: &T, ) -> error::Result> { let tokio_runtime = build_runtime()?; + + // `capture` needs to be called in a tokio context. + // Also capture them as early as possible. + let signals = tokio_runtime.block_on(async { Signals::capture() })?; + let config = command.create_configuration(self, tokio_runtime.handle().clone())?; command.init(&Self::support_url(), &Self::impl_version(), |_, _| {}, &config)?; - Runner::new(config, tokio_runtime) + Runner::new(config, tokio_runtime, signals) } /// Create a runner for the command provided in argument. The `logger_hook` can be used to setup @@ -231,10 +236,15 @@ pub trait SubstrateCli: Sized { F: FnOnce(&mut LoggerBuilder, &Configuration), { let tokio_runtime = build_runtime()?; + + // `capture` needs to be called in a tokio context. + // Also capture them as early as possible. + let signals = tokio_runtime.block_on(async { Signals::capture() })?; + 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) + Runner::new(config, tokio_runtime, signals) } /// 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 8917a37c499c0..47adfcf89fe99 100644 --- a/client/cli/src/runner.rs +++ b/client/cli/src/runner.rs @@ -18,54 +18,72 @@ use crate::{error::Error as CliError, Result, SubstrateCli}; use chrono::prelude::*; -use futures::{future, future::FutureExt, pin_mut, select, Future}; +use futures::{ + future::{self, BoxFuture, 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, time::Duration}; -#[cfg(target_family = "unix")] -async fn main(func: F) -> std::result::Result<(), E> -where - F: Future> + future::FusedFuture, - E: std::error::Error + Send + Sync + 'static + From, -{ - use tokio::signal::unix::{signal, SignalKind}; +/// Abstraction over OS signals to handle the shutdown of the node smoothly. +/// +/// On `unix` this represents `SigInt` and `SigTerm`. +pub struct Signals(BoxFuture<'static, ()>); - let mut stream_int = signal(SignalKind::interrupt()).map_err(ServiceError::Io)?; - let mut stream_term = signal(SignalKind::terminate()).map_err(ServiceError::Io)?; - - let t1 = stream_int.recv().fuse(); - let t2 = stream_term.recv().fuse(); - let t3 = func; - - pin_mut!(t1, t2, t3); +impl Signals { + /// Capture the relevant signals to handle shutdown of the node smoothly. + /// + /// Needs to be called in a Tokio context to have access to the tokio reactor. + #[cfg(target_family = "unix")] + pub fn capture() -> std::result::Result { + use tokio::signal::unix::{signal, SignalKind}; + + let mut stream_int = signal(SignalKind::interrupt()).map_err(ServiceError::Io)?; + let mut stream_term = signal(SignalKind::terminate()).map_err(ServiceError::Io)?; + + Ok(Signals( + async move { + future::select(stream_int.recv().boxed(), stream_term.recv().boxed()).await; + } + .boxed(), + )) + } - select! { - _ = t1 => {}, - _ = t2 => {}, - res = t3 => res?, + /// Capture the relevant signals to handle shutdown of the node smoothly. + /// + /// Needs to be called in a Tokio context to have access to the tokio reactor. + #[cfg(not(unix))] + pub fn capture() -> std::result::Result { + use tokio::signal::ctrl_c; + + Ok(Signals( + async move { + let _ = ctrl_c().await; + } + .boxed(), + )) } - Ok(()) + /// A dummy signal that never returns. + pub fn dummy() -> Self { + Self(future::pending().boxed()) + } } -#[cfg(not(unix))] -async fn main(func: F) -> std::result::Result<(), E> +async fn main(func: F, signals: impl Future) -> std::result::Result<(), E> where F: Future> + future::FusedFuture, - E: std::error::Error + Send + Sync + 'static + From, + E: std::error::Error + Send + Sync + 'static, { - use tokio::signal::ctrl_c; - - let t1 = ctrl_c().fuse(); - let t2 = func; + let signals = signals.fuse(); - pin_mut!(t1, t2); + pin_mut!(func, signals); select! { - _ = t1 => {}, - res = t2 => res?, + _ = signals => {}, + res = func => res?, } Ok(()) @@ -89,6 +107,7 @@ fn run_until_exit( tokio_runtime: tokio::runtime::Runtime, future: F, task_manager: TaskManager, + signals: impl Future, ) -> std::result::Result<(), E> where F: Future> + future::Future, @@ -97,7 +116,7 @@ where let f = future.fuse(); pin_mut!(f); - tokio_runtime.block_on(main(f))?; + tokio_runtime.block_on(main(f, signals))?; drop(task_manager); Ok(()) @@ -107,13 +126,18 @@ where pub struct Runner { config: Configuration, tokio_runtime: tokio::runtime::Runtime, + signals: Signals, phantom: PhantomData, } impl Runner { /// Create a new runtime with the command provided in argument - pub fn new(config: Configuration, tokio_runtime: tokio::runtime::Runtime) -> Result> { - Ok(Runner { config, tokio_runtime, phantom: PhantomData }) + pub fn new( + config: Configuration, + tokio_runtime: tokio::runtime::Runtime, + signals: Signals, + ) -> Result> { + Ok(Runner { config, tokio_runtime, signals, phantom: PhantomData }) } /// Log information about the node itself. @@ -147,7 +171,7 @@ 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())); + let res = self.tokio_runtime.block_on(main(task_manager.future().fuse(), self.signals.0)); // 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 @@ -210,7 +234,7 @@ impl Runner { E: std::error::Error + Send + Sync + 'static + From + From, { let (future, task_manager) = runner(self.config)?; - run_until_exit::<_, E>(self.tokio_runtime, future, task_manager) + run_until_exit::<_, E>(self.tokio_runtime, future, task_manager, self.signals.0) } /// Get an immutable reference to the node Configuration @@ -369,6 +393,7 @@ mod tests { runtime_cache_size: 2, }, runtime, + Signals::dummy(), ) .unwrap(); From 22cca143a2c8e4a03ae770d71e94329eb518cca8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 16 Mar 2023 12:09:50 +0000 Subject: [PATCH 519/715] Integration tests for staking + election-provider-multi-phase (#12972) * EPM and staking pallets: Adds new crate for integration tests a * Adds ExtBuilder and helpers with initial conditions assertions * removes account helpers; adds staking, session, etc genesis * Adds kusama incident test case * Prepare for slashing test * Adds solution submission * slash_through_offending_threshold * Renames e2e integration tests dir and crate * consistently slash 10% of validator set * finishes continous_slashes_below_offending_threshold test * Update frame/election-provider-multi-phase/test-staking-e2e/src/lib.rs Co-authored-by: Ankan <10196091+Ank4n@users.noreply.github.com> * Update frame/election-provider-multi-phase/test-staking-e2e/src/lib.rs Co-authored-by: Ankan <10196091+Ank4n@users.noreply.github.com> * Update frame/election-provider-multi-phase/test-staking-e2e/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * mock fixes * Additional checks to delayed solution eras and mock fixes * nits and addresses review comments; splits ext_builder into one per pallet * helper to set balances ext builder * bring up mock.rs to master * integration test fixes and additions --------- Co-authored-by: Ankan <10196091+Ank4n@users.noreply.github.com> Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- .../test-staking-e2e/Cargo.lock | 3609 +++++++++++++++++ .../test-staking-e2e/Cargo.toml | 40 + .../test-staking-e2e/src/lib.rs | 206 + .../test-staking-e2e/src/mock.rs | 779 ++++ 4 files changed, 4634 insertions(+) create mode 100644 frame/election-provider-multi-phase/test-staking-e2e/Cargo.lock create mode 100644 frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml create mode 100644 frame/election-provider-multi-phase/test-staking-e2e/src/lib.rs create mode 100644 frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs diff --git a/frame/election-provider-multi-phase/test-staking-e2e/Cargo.lock b/frame/election-provider-multi-phase/test-staking-e2e/Cargo.lock new file mode 100644 index 0000000000000..b179ab7059a48 --- /dev/null +++ b/frame/election-provider-multi-phase/test-staking-e2e/Cargo.lock @@ -0,0 +1,3609 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "Inflector" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" +dependencies = [ + "lazy_static", + "regex", +] + +[[package]] +name = "addr2line" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "ahash" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +dependencies = [ + "getrandom 0.2.8", + "once_cell", + "version_check", +] + +[[package]] +name = "ahash" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +dependencies = [ + "cfg-if", + "getrandom 0.2.8", + "once_cell", + "version_check", +] + +[[package]] +name = "aho-corasick" +version = "0.7.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +dependencies = [ + "memchr", +] + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "ansi_term" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +dependencies = [ + "winapi", +] + +[[package]] +name = "anyhow" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224afbd727c3d6e4b90103ece64b8d1b67fbb1973b1046c2281eed3f3803f800" + +[[package]] +name = "approx" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" +dependencies = [ + "num-traits", +] + +[[package]] +name = "array-bytes" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52f63c5c1316a16a4b35eaac8b76a98248961a533f061684cb2a7cb0eafb6c6" + +[[package]] +name = "arrayref" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" + +[[package]] +name = "arrayvec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" + +[[package]] +name = "arrayvec" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" + +[[package]] +name = "async-trait" +version = "0.1.59" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e6e93155431f3931513b243d371981bb2770112b370c82745a1d19d2f99364" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "backtrace" +version = "0.3.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab84319d616cfb654d03394f38ab7e6f0919e181b1b57e1fd15e7fb4077d9a7" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base16ct" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" + +[[package]] +name = "base58" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6107fe1be6682a68940da878d9e9f5e90ca5745b3dec9fd1bb393c8777d4f581" + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64ct" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b645a089122eccb6111b4f81cbc1a49f5900ac4666bb93ac027feaecf15607bf" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "blake2" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b12e5fd123190ce1c2e559308a94c9bacad77907d4c6005d9e58fe1a0689e55e" +dependencies = [ + "digest 0.10.6", +] + +[[package]] +name = "blake2b_simd" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c2f0dc9a68c6317d884f97cc36cf5a3d20ba14ce404227df55e1af708ab04bc" +dependencies = [ + "arrayref", + "arrayvec 0.7.2", + "constant_time_eq", +] + +[[package]] +name = "block-buffer" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" +dependencies = [ + "block-padding", + "byte-tools", + "byteorder", + "generic-array 0.12.4", +] + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array 0.14.6", +] + +[[package]] +name = "block-buffer" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" +dependencies = [ + "generic-array 0.14.6", +] + +[[package]] +name = "block-padding" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" +dependencies = [ + "byte-tools", +] + +[[package]] +name = "bounded-collections" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a071c348a5ef6da1d3a87166b408170b46002382b1dda83992b5c2208cefb370" +dependencies = [ + "log", + "parity-scale-codec", + "scale-info", + "serde", +] + +[[package]] +name = "bumpalo" +version = "3.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" + +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + +[[package]] +name = "byte-tools" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" + +[[package]] +name = "bytemuck" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "bytes" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" + +[[package]] +name = "cc" +version = "1.0.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4" + +[[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 = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f" +dependencies = [ + "iana-time-zone", + "num-integer", + "num-traits", + "winapi", +] + +[[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 = "const-oid" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cec318a675afcb6a1ea1d4340e2d377e56e47c266f28043ceccbf4412ddfdd3b" + +[[package]] +name = "constant_time_eq" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13418e745008f7349ec7e449155f419a61b92b58a99cc3616942b926825ec76b" + +[[package]] +name = "core-foundation-sys" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" + +[[package]] +name = "cpp_demangle" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eeaa953eaad386a53111e47172c2fedba671e5684c8dd601a5f474f4f118710f" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "cpufeatures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" +dependencies = [ + "libc", +] + +[[package]] +name = "cranelift-entity" +version = "0.93.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cf583f7b093f291005f9fb1323e2c37f6ee4c7909e39ce016b2e8360d461705" +dependencies = [ + "serde", +] + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-bigint" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" +dependencies = [ + "generic-array 0.14.6", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array 0.14.6", + "typenum", +] + +[[package]] +name = "crypto-mac" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" +dependencies = [ + "generic-array 0.14.6", + "subtle", +] + +[[package]] +name = "crypto-mac" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" +dependencies = [ + "generic-array 0.14.6", + "subtle", +] + +[[package]] +name = "curve25519-dalek" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a9b85542f99a2dfa2a1b8e192662741c9859a846b296bef1c92ef9b58b5a216" +dependencies = [ + "byteorder", + "digest 0.8.1", + "rand_core 0.5.1", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" +dependencies = [ + "byteorder", + "digest 0.9.0", + "rand_core 0.5.1", + "subtle", + "zeroize", +] + +[[package]] +name = "cxx" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdf07d07d6531bfcdbe9b8b739b104610c6508dcc4d63b410585faf338241daf" +dependencies = [ + "cc", + "cxxbridge-flags", + "cxxbridge-macro", + "link-cplusplus", +] + +[[package]] +name = "cxx-build" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2eb5b96ecdc99f72657332953d4d9c50135af1bac34277801cc3937906ebd39" +dependencies = [ + "cc", + "codespan-reporting", + "once_cell", + "proc-macro2", + "quote", + "scratch", + "syn", +] + +[[package]] +name = "cxxbridge-flags" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac040a39517fd1674e0f32177648334b0f4074625b5588a64519804ba0553b12" + +[[package]] +name = "cxxbridge-macro" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1362b0ddcfc4eb0a1f57b68bd77dd99f0e826958a96abd0ae9bd092e114ffed6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "der" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "derive-syn-parse" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e79116f119dd1dba1abf1f3405f03b9b0e79a27a3883864bfebded8a3dc768cd" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "derive_more" +version = "0.99.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "digest" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" +dependencies = [ + "generic-array 0.12.4", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array 0.14.6", +] + +[[package]] +name = "digest" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" +dependencies = [ + "block-buffer 0.10.3", + "crypto-common", + "subtle", +] + +[[package]] +name = "downcast-rs" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" + +[[package]] +name = "dyn-clonable" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e9232f0e607a262ceb9bd5141a3dfb3e4db6994b31989bbfd845878cba59fd4" +dependencies = [ + "dyn-clonable-impl", + "dyn-clone", +] + +[[package]] +name = "dyn-clonable-impl" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "558e40ea573c374cf53507fd240b7ee2f5477df7cfebdb97323ec61c719399c5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "dyn-clone" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f94fa09c2aeea5b8839e414b7b841bf429fd25b9c522116ac97ee87856d88b2" + +[[package]] +name = "ecdsa" +version = "0.14.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c" +dependencies = [ + "der", + "elliptic-curve", + "rfc6979", + "signature", +] + +[[package]] +name = "ed25519" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9c280362032ea4203659fc489832d0204ef09f247a0506f170dafcac08c369" +dependencies = [ + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" +dependencies = [ + "curve25519-dalek 3.2.0", + "ed25519", + "sha2 0.9.9", + "zeroize", +] + +[[package]] +name = "ed25519-zebra" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c24f403d068ad0b359e577a77f92392118be3f3c927538f2bb544a5ecd828c6" +dependencies = [ + "curve25519-dalek 3.2.0", + "hashbrown 0.12.3", + "hex", + "rand_core 0.6.4", + "sha2 0.9.9", + "zeroize", +] + +[[package]] +name = "either" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" + +[[package]] +name = "elliptic-curve" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3" +dependencies = [ + "base16ct", + "crypto-bigint", + "der", + "digest 0.10.6", + "ff", + "generic-array 0.14.6", + "group", + "rand_core 0.6.4", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "environmental" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e48c92028aaa870e83d51c64e5d4e0b6981b360c522198c23959f219a4e1b15b" + +[[package]] +name = "errno" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" +dependencies = [ + "errno-dragonfly", + "libc", + "winapi", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "expander" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f360349150728553f92e4c997a16af8915f418d3a0f21b440d34c5632f16ed84" +dependencies = [ + "blake2", + "fs-err", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "fake-simd" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" + +[[package]] +name = "fallible-iterator" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" + +[[package]] +name = "ff" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +dependencies = [ + "byteorder", + "rand 0.8.5", + "rustc-hex", + "static_assertions", +] + +[[package]] +name = "form_urlencoded" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "frame-benchmarking" +version = "4.0.0-dev" +dependencies = [ + "frame-support", + "frame-support-procedural", + "frame-system", + "linregress", + "log", + "parity-scale-codec", + "paste", + "scale-info", + "serde", + "sp-api", + "sp-application-crypto", + "sp-core", + "sp-io", + "sp-runtime", + "sp-runtime-interface", + "sp-std", + "sp-storage", + "static_assertions", +] + +[[package]] +name = "frame-election-provider-solution-type" +version = "4.0.0-dev" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "frame-election-provider-support" +version = "4.0.0-dev" +dependencies = [ + "frame-election-provider-solution-type", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-arithmetic", + "sp-core", + "sp-npos-elections", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "frame-metadata" +version = "15.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df6bb8542ef006ef0de09a5c4420787d79823c0ed7924225822362fd2bf2ff2d" +dependencies = [ + "cfg-if", + "parity-scale-codec", + "scale-info", + "serde", +] + +[[package]] +name = "frame-support" +version = "4.0.0-dev" +dependencies = [ + "bitflags", + "environmental", + "frame-metadata", + "frame-support-procedural", + "impl-trait-for-tuples", + "k256", + "log", + "once_cell", + "parity-scale-codec", + "paste", + "scale-info", + "serde", + "smallvec", + "sp-api", + "sp-arithmetic", + "sp-core", + "sp-core-hashing-proc-macro", + "sp-inherents", + "sp-io", + "sp-runtime", + "sp-staking", + "sp-state-machine", + "sp-std", + "sp-tracing", + "sp-weights", + "tt-call", +] + +[[package]] +name = "frame-support-procedural" +version = "4.0.0-dev" +dependencies = [ + "Inflector", + "cfg-expr", + "derive-syn-parse", + "frame-support-procedural-tools", + "itertools", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "frame-support-procedural-tools" +version = "4.0.0-dev" +dependencies = [ + "frame-support-procedural-tools-derive", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "frame-support-procedural-tools-derive" +version = "3.0.0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "frame-system" +version = "4.0.0-dev" +dependencies = [ + "frame-support", + "log", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", + "sp-version", + "sp-weights", +] + +[[package]] +name = "fs-err" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0845fa252299212f0389d64ba26f34fa32cfe41588355f21ed507c59a0f64541" + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38390104763dc37a5145a53c29c63c1290b5d316d6086ec32c293f6736051bb0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac" + +[[package]] +name = "futures-executor" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7acc85df6714c176ab5edf386123fafe217be88c0840ec11f199441134a074e2" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", + "num_cpus", +] + +[[package]] +name = "futures-io" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb" + +[[package]] +name = "futures-macro" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9" + +[[package]] +name = "futures-task" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea" + +[[package]] +name = "futures-timer" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" + +[[package]] +name = "futures-util" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" +dependencies = [ + "typenum", +] + +[[package]] +name = "generic-array" +version = "0.14.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", +] + +[[package]] +name = "gimli" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d" +dependencies = [ + "fallible-iterator", + "stable_deref_trait", +] + +[[package]] +name = "group" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" +dependencies = [ + "ff", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "hash-db" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e7d7786361d7425ae2fe4f9e407eb0efaa0840f5212d109cc018c40c35c6ab4" + +[[package]] +name = "hash256-std-hasher" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92c171d55b98633f4ed3860808f004099b36c1cc29c42cfc53aa8591b21efcf2" +dependencies = [ + "crunchy", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash 0.7.6", +] + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash 0.8.3", +] + +[[package]] +name = "heck" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hmac" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" +dependencies = [ + "crypto-mac 0.8.0", + "digest 0.9.0", +] + +[[package]] +name = "hmac" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" +dependencies = [ + "crypto-mac 0.11.1", + "digest 0.9.0", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.6", +] + +[[package]] +name = "hmac-drbg" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" +dependencies = [ + "digest 0.9.0", + "generic-array 0.14.6", + "hmac 0.8.1", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "winapi", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" +dependencies = [ + "cxx", + "cxx-build", +] + +[[package]] +name = "idna" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "impl-codec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +dependencies = [ + "parity-scale-codec", +] + +[[package]] +name = "impl-serde" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc88fc67028ae3db0c853baa36269d398d5f45b6982f95549ff5def78c935cd" +dependencies = [ + "serde", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "indexmap" +version = "1.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "integer-sqrt" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "276ec31bcb4a9ee45f58bec6f9ec700ae4cf4f4f8f2fa7e06cb406bd5ffdd770" +dependencies = [ + "num-traits", +] + +[[package]] +name = "io-lifetimes" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfa919a82ea574332e2de6e74b4c36e74d41982b335080fa59d4ef31be20fdf3" +dependencies = [ + "libc", + "windows-sys 0.45.0", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" + +[[package]] +name = "js-sys" +version = "0.3.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "k256" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72c1e0b51e7ec0a97369623508396067a486bd0cbed95a2659a4b863d28cfc8b" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "sha2 0.10.6", +] + +[[package]] +name = "keccak" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3afef3b6eff9ce9d8ff9b3601125eec7f0c8cbac7abd14f355d053fa56c98768" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.138" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8" + +[[package]] +name = "libm" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb" + +[[package]] +name = "libsecp256k1" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95b09eff1b35ed3b33b877ced3a691fc7a481919c7e29c53c906226fcf55e2a1" +dependencies = [ + "arrayref", + "base64", + "digest 0.9.0", + "hmac-drbg", + "libsecp256k1-core", + "libsecp256k1-gen-ecmult", + "libsecp256k1-gen-genmult", + "rand 0.8.5", + "serde", + "sha2 0.9.9", + "typenum", +] + +[[package]] +name = "libsecp256k1-core" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be9b9bb642d8522a44d533eab56c16c738301965504753b03ad1de3425d5451" +dependencies = [ + "crunchy", + "digest 0.9.0", + "subtle", +] + +[[package]] +name = "libsecp256k1-gen-ecmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3038c808c55c87e8a172643a7d87187fc6c4174468159cb3090659d55bcb4809" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "libsecp256k1-gen-genmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db8d6ba2cec9eacc40e6e8ccc98931840301f1006e95647ceb2dd5c3aa06f7c" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "link-cplusplus" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9272ab7b96c9046fbc5bc56c06c117cb639fe2d509df0c421cad82d2915cf369" +dependencies = [ + "cc", +] + +[[package]] +name = "linregress" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "475015a7f8f017edb28d2e69813be23500ad4b32cfe3421c4148efc97324ee52" +dependencies = [ + "nalgebra", +] + +[[package]] +name = "linux-raw-sys" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" + +[[package]] +name = "lock_api" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "mach" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" +dependencies = [ + "libc", +] + +[[package]] +name = "matchers" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f099785f7595cc4b4553a174ce30dd7589ef93391ff414dbb67f62392b9e0ce1" +dependencies = [ + "regex-automata", +] + +[[package]] +name = "matrixmultiply" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "add85d4dd35074e6fedc608f8c8f513a3548619a9024b751949ef0e8e45a4d84" +dependencies = [ + "rawpointer", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "memfd" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b20a59d985586e4a5aef64564ac77299f8586d8be6cf9106a5a40207e8908efb" +dependencies = [ + "rustix", +] + +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + +[[package]] +name = "memory-db" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808b50db46293432a45e63bc15ea51e0ab4c0a1647b8eb114e31a3e698dd6fbe" +dependencies = [ + "hash-db", +] + +[[package]] +name = "memory_units" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8452105ba047068f40ff7093dd1d9da90898e63dd61736462e9cdda6a90ad3c3" + +[[package]] +name = "merlin" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e261cf0f8b3c42ded9f7d2bb59dea03aa52bc8a1cbc7482f9fc3fd1229d3b42" +dependencies = [ + "byteorder", + "keccak", + "rand_core 0.5.1", + "zeroize", +] + +[[package]] +name = "miniz_oxide" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96590ba8f175222643a85693f33d26e9c8a015f599c216509b1a6894af675d34" +dependencies = [ + "adler", +] + +[[package]] +name = "nalgebra" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d68d47bba83f9e2006d117a9a33af1524e655516b8919caac694427a6fb1e511" +dependencies = [ + "approx", + "matrixmultiply", + "nalgebra-macros", + "num-complex", + "num-rational", + "num-traits", + "simba", + "typenum", +] + +[[package]] +name = "nalgebra-macros" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d232c68884c0c99810a5a4d333ef7e47689cfd0edc85efc9e54e1e6bf5212766" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "nohash-hasher" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" + +[[package]] +name = "num-bigint" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ae39348c8bc5fbd7f40c727a9925f03517afd2ab27d46702108b6a7e5414c19" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-format" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a652d9771a63711fd3c3deb670acfbe5c30a4072e664d7a3bf5a9e1056ac72c3" +dependencies = [ + "arrayvec 0.7.2", + "itoa", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "object" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53" +dependencies = [ + "crc32fast", + "hashbrown 0.12.3", + "indexmap", + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" + +[[package]] +name = "opaque-debug" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "pallet-authorship" +version = "4.0.0-dev" +dependencies = [ + "frame-support", + "frame-system", + "impl-trait-for-tuples", + "parity-scale-codec", + "scale-info", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-bags-list" +version = "4.0.0-dev" +dependencies = [ + "frame-benchmarking", + "frame-election-provider-support", + "frame-support", + "frame-system", + "log", + "pallet-balances", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", + "sp-tracing", +] + +[[package]] +name = "pallet-balances" +version = "4.0.0-dev" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-election-provider-e2e-test" +version = "1.0.0" +dependencies = [ + "frame-election-provider-support", + "frame-support", + "frame-system", + "log", + "pallet-bags-list", + "pallet-balances", + "pallet-election-provider-multi-phase", + "pallet-session", + "pallet-staking", + "pallet-timestamp", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-npos-elections", + "sp-runtime", + "sp-staking", + "sp-std", + "sp-tracing", +] + +[[package]] +name = "pallet-election-provider-multi-phase" +version = "4.0.0-dev" +dependencies = [ + "frame-benchmarking", + "frame-election-provider-support", + "frame-support", + "frame-system", + "log", + "pallet-election-provider-support-benchmarking", + "parity-scale-codec", + "rand 0.8.5", + "scale-info", + "sp-arithmetic", + "sp-core", + "sp-io", + "sp-npos-elections", + "sp-runtime", + "sp-std", + "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-session" +version = "4.0.0-dev" +dependencies = [ + "frame-support", + "frame-system", + "impl-trait-for-tuples", + "log", + "pallet-timestamp", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-session", + "sp-staking", + "sp-std", + "sp-trie", +] + +[[package]] +name = "pallet-staking" +version = "4.0.0-dev" +dependencies = [ + "frame-benchmarking", + "frame-election-provider-support", + "frame-support", + "frame-system", + "log", + "pallet-authorship", + "pallet-session", + "parity-scale-codec", + "scale-info", + "serde", + "sp-application-crypto", + "sp-io", + "sp-runtime", + "sp-staking", + "sp-std", +] + +[[package]] +name = "pallet-timestamp" +version = "4.0.0-dev" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-inherents", + "sp-io", + "sp-runtime", + "sp-std", + "sp-timestamp", +] + +[[package]] +name = "parity-scale-codec" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "637935964ff85a605d114591d4d2c13c5d1ba2806dae97cea6bf180238a749ac" +dependencies = [ + "arrayvec 0.7.2", + "bitvec", + "byte-slice-cast", + "bytes", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b26a931f824dd4eca30b3e43bb4f31cd5f0d3a403c5f5ff27106b805bfde7b" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "parity-wasm" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1ad0aff30c1da14b1254fcb2af73e1fa9a28670e584a626f53a369d0e157304" + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ff9f3fef3968a3ec5945535ed654cb38ff72d7495a25619e2247fb15a2ed9ba" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-sys 0.42.0", +] + +[[package]] +name = "paste" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1c2c742266c2f1041c914ba65355a83ae8747b05f208319784083583494b4b" + +[[package]] +name = "pbkdf2" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d95f5254224e617595d2cc3cc73ff0a5eaf2637519e25f03388154e9378b6ffa" +dependencies = [ + "crypto-mac 0.11.1", +] + +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest 0.10.6", +] + +[[package]] +name = "percent-encoding" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" + +[[package]] +name = "pin-project-lite" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkcs8" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "primitive-types" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f3486ccba82358b11a77516035647c34ba167dfa53312630de83b12bd4f3d66" +dependencies = [ + "fixed-hash", + "impl-codec", + "impl-serde", + "scale-info", + "uint", +] + +[[package]] +name = "proc-macro-crate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eda0fc3b0fb7c975631757e14d9049da17374063edb6ebbcbc54d880d4fe94e9" +dependencies = [ + "once_cell", + "thiserror", + "toml", +] + +[[package]] +name = "proc-macro2" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "psm" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5787f7cda34e3033a72192c018bc5883100330f362ef279a8cbccfce8bb4e874" +dependencies = [ + "cc", +] + +[[package]] +name = "quote" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom 0.1.16", + "libc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.8", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "rawpointer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" + +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags", +] + +[[package]] +name = "ref-cast" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53b15debb4f9d60d767cd8ca9ef7abb2452922f3214671ff052defc7f3502c44" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abfa8511e9e94fd3de6585a3d3cd00e01ed556dc9814829280af0e8dc72a8f36" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "regex" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" + +[[package]] +name = "rfc6979" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb" +dependencies = [ + "crypto-bigint", + "hmac 0.12.1", + "zeroize", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" + +[[package]] +name = "rustix" +version = "0.36.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd5c6ff11fecd55b40746d1995a02f2eb375bf8c00d192d521ee09f42bef37bc" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys", + "windows-sys 0.45.0", +] + +[[package]] +name = "rustversion" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97477e48b4cf8603ad5f7aaf897467cf42ab4218a38ef76fb14c2d6773a6d6a8" + +[[package]] +name = "ryu" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" + +[[package]] +name = "safe_arch" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "794821e4ccb0d9f979512f9c1973480123f9bd62a90d74ab0f9426fcf8f4a529" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "scale-info" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "001cf62ece89779fd16105b5f515ad0e5cedcd5440d3dd806bb067978e7c3608" +dependencies = [ + "bitvec", + "cfg-if", + "derive_more", + "parity-scale-codec", + "scale-info-derive", + "serde", +] + +[[package]] +name = "scale-info-derive" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "303959cf613a6f6efd19ed4b4ad5bf79966a13352716299ad532cfb115f4205c" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "schnellru" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "772575a524feeb803e5b0fcbc6dd9f367e579488197c94c6e4023aad2305774d" +dependencies = [ + "ahash 0.8.3", + "cfg-if", + "hashbrown 0.13.2", +] + +[[package]] +name = "schnorrkel" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "021b403afe70d81eea68f6ea12f6b3c9588e5d536a94c3bf80f15e7faa267862" +dependencies = [ + "arrayref", + "arrayvec 0.5.2", + "curve25519-dalek 2.1.3", + "getrandom 0.1.16", + "merlin", + "rand 0.7.3", + "rand_core 0.5.1", + "sha2 0.8.2", + "subtle", + "zeroize", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "scratch" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898" + +[[package]] +name = "sec1" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" +dependencies = [ + "base16ct", + "der", + "generic-array 0.14.6", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "secp256k1" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9512ffd81e3a3503ed401f79c33168b9148c75038956039166cd750eaa037c3" +dependencies = [ + "secp256k1-sys", +] + +[[package]] +name = "secp256k1-sys" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83080e2c2fc1006e625be82e5d1eb6a43b7fd9578b617fcc55814daf286bba4b" +dependencies = [ + "cc", +] + +[[package]] +name = "secrecy" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bd1c54ea06cfd2f6b63219704de0b9b4f72dcc2b8fdef820be6cd799780e91e" +dependencies = [ + "zeroize", +] + +[[package]] +name = "serde" +version = "1.0.150" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e326c9ec8042f1b5da33252c8a37e9ffbd2c9bef0155215b6e6c80c790e05f91" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.150" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42a3df25b0713732468deadad63ab9da1f1fd75a48a15024b50363f128db627e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha2" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a256f46ea78a0c0d9ff00077504903ac881a1dafdc20da66545699e7776b3e69" +dependencies = [ + "block-buffer 0.7.3", + "digest 0.8.1", + "fake-simd", + "opaque-debug 0.2.3", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug 0.3.0", +] + +[[package]] +name = "sha2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.6", +] + +[[package]] +name = "sha3" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdf0c33fae925bdc080598b84bc15c55e7b9a4a43b3c704da051f977469691c9" +dependencies = [ + "digest 0.10.6", + "keccak", +] + +[[package]] +name = "sharded-slab" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "signature" +version = "1.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" +dependencies = [ + "digest 0.10.6", + "rand_core 0.6.4", +] + +[[package]] +name = "simba" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50582927ed6f77e4ac020c057f37a268fc6aebc29225050365aacbb9deeeddc4" +dependencies = [ + "approx", + "num-complex", + "num-traits", + "paste", + "wide", +] + +[[package]] +name = "slab" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" + +[[package]] +name = "sp-api" +version = "4.0.0-dev" +dependencies = [ + "hash-db", + "log", + "parity-scale-codec", + "sp-api-proc-macro", + "sp-core", + "sp-runtime", + "sp-state-machine", + "sp-std", + "sp-trie", + "sp-version", + "thiserror", +] + +[[package]] +name = "sp-api-proc-macro" +version = "4.0.0-dev" +dependencies = [ + "Inflector", + "blake2", + "expander", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "sp-application-crypto" +version = "7.0.0" +dependencies = [ + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-io", + "sp-std", +] + +[[package]] +name = "sp-arithmetic" +version = "6.0.0" +dependencies = [ + "integer-sqrt", + "num-traits", + "parity-scale-codec", + "scale-info", + "serde", + "sp-std", + "static_assertions", +] + +[[package]] +name = "sp-core" +version = "7.0.0" +dependencies = [ + "array-bytes", + "base58", + "bitflags", + "blake2", + "bounded-collections", + "dyn-clonable", + "ed25519-zebra", + "futures", + "hash-db", + "hash256-std-hasher", + "impl-serde", + "lazy_static", + "libsecp256k1", + "log", + "merlin", + "parity-scale-codec", + "parking_lot", + "primitive-types", + "rand 0.8.5", + "regex", + "scale-info", + "schnorrkel", + "secp256k1", + "secrecy", + "serde", + "sp-core-hashing", + "sp-debug-derive", + "sp-externalities", + "sp-runtime-interface", + "sp-std", + "sp-storage", + "ss58-registry", + "substrate-bip39", + "thiserror", + "tiny-bip39", + "zeroize", +] + +[[package]] +name = "sp-core-hashing" +version = "5.0.0" +dependencies = [ + "blake2b_simd", + "byteorder", + "digest 0.10.6", + "sha2 0.10.6", + "sha3", + "sp-std", + "twox-hash", +] + +[[package]] +name = "sp-core-hashing-proc-macro" +version = "5.0.0" +dependencies = [ + "proc-macro2", + "quote", + "sp-core-hashing", + "syn", +] + +[[package]] +name = "sp-debug-derive" +version = "5.0.0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "sp-externalities" +version = "0.13.0" +dependencies = [ + "environmental", + "parity-scale-codec", + "sp-std", + "sp-storage", +] + +[[package]] +name = "sp-inherents" +version = "4.0.0-dev" +dependencies = [ + "async-trait", + "impl-trait-for-tuples", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-runtime", + "sp-std", + "thiserror", +] + +[[package]] +name = "sp-io" +version = "7.0.0" +dependencies = [ + "bytes", + "ed25519", + "ed25519-dalek", + "futures", + "libsecp256k1", + "log", + "parity-scale-codec", + "secp256k1", + "sp-core", + "sp-externalities", + "sp-keystore", + "sp-runtime-interface", + "sp-state-machine", + "sp-std", + "sp-tracing", + "sp-trie", + "tracing", + "tracing-core", +] + +[[package]] +name = "sp-keystore" +version = "0.13.0" +dependencies = [ + "async-trait", + "futures", + "merlin", + "parity-scale-codec", + "parking_lot", + "schnorrkel", + "sp-core", + "sp-externalities", + "thiserror", +] + +[[package]] +name = "sp-npos-elections" +version = "4.0.0-dev" +dependencies = [ + "parity-scale-codec", + "scale-info", + "serde", + "sp-arithmetic", + "sp-core", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "sp-panic-handler" +version = "5.0.0" +dependencies = [ + "backtrace", + "lazy_static", + "regex", +] + +[[package]] +name = "sp-runtime" +version = "7.0.0" +dependencies = [ + "either", + "hash256-std-hasher", + "impl-trait-for-tuples", + "log", + "parity-scale-codec", + "paste", + "rand 0.8.5", + "scale-info", + "serde", + "sp-application-crypto", + "sp-arithmetic", + "sp-core", + "sp-io", + "sp-std", + "sp-weights", +] + +[[package]] +name = "sp-runtime-interface" +version = "7.0.0" +dependencies = [ + "bytes", + "impl-trait-for-tuples", + "parity-scale-codec", + "primitive-types", + "sp-externalities", + "sp-runtime-interface-proc-macro", + "sp-std", + "sp-storage", + "sp-tracing", + "sp-wasm-interface", + "static_assertions", +] + +[[package]] +name = "sp-runtime-interface-proc-macro" +version = "6.0.0" +dependencies = [ + "Inflector", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "sp-session" +version = "4.0.0-dev" +dependencies = [ + "parity-scale-codec", + "scale-info", + "sp-api", + "sp-core", + "sp-runtime", + "sp-staking", + "sp-std", +] + +[[package]] +name = "sp-staking" +version = "4.0.0-dev" +dependencies = [ + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "sp-state-machine" +version = "0.13.0" +dependencies = [ + "hash-db", + "log", + "parity-scale-codec", + "parking_lot", + "rand 0.8.5", + "smallvec", + "sp-core", + "sp-externalities", + "sp-panic-handler", + "sp-std", + "sp-trie", + "thiserror", + "tracing", +] + +[[package]] +name = "sp-std" +version = "5.0.0" + +[[package]] +name = "sp-storage" +version = "7.0.0" +dependencies = [ + "impl-serde", + "parity-scale-codec", + "ref-cast", + "serde", + "sp-debug-derive", + "sp-std", +] + +[[package]] +name = "sp-timestamp" +version = "4.0.0-dev" +dependencies = [ + "async-trait", + "futures-timer", + "log", + "parity-scale-codec", + "sp-inherents", + "sp-runtime", + "sp-std", + "thiserror", +] + +[[package]] +name = "sp-tracing" +version = "6.0.0" +dependencies = [ + "parity-scale-codec", + "sp-std", + "tracing", + "tracing-core", + "tracing-subscriber", +] + +[[package]] +name = "sp-trie" +version = "7.0.0" +dependencies = [ + "ahash 0.8.3", + "hash-db", + "hashbrown 0.12.3", + "lazy_static", + "memory-db", + "nohash-hasher", + "parity-scale-codec", + "parking_lot", + "scale-info", + "schnellru", + "sp-core", + "sp-std", + "thiserror", + "tracing", + "trie-db", + "trie-root", +] + +[[package]] +name = "sp-version" +version = "5.0.0" +dependencies = [ + "impl-serde", + "parity-scale-codec", + "parity-wasm", + "scale-info", + "serde", + "sp-core-hashing-proc-macro", + "sp-runtime", + "sp-std", + "sp-version-proc-macro", + "thiserror", +] + +[[package]] +name = "sp-version-proc-macro" +version = "4.0.0-dev" +dependencies = [ + "parity-scale-codec", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "sp-wasm-interface" +version = "7.0.0" +dependencies = [ + "anyhow", + "impl-trait-for-tuples", + "log", + "parity-scale-codec", + "sp-std", + "wasmi", + "wasmtime", +] + +[[package]] +name = "sp-weights" +version = "4.0.0" +dependencies = [ + "parity-scale-codec", + "scale-info", + "serde", + "smallvec", + "sp-arithmetic", + "sp-core", + "sp-debug-derive", + "sp-std", +] + +[[package]] +name = "spki" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "ss58-registry" +version = "1.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23d92659e7d18d82b803824a9ba5a6022cff101c3491d027c1c1d8d30e749284" +dependencies = [ + "Inflector", + "num-format", + "proc-macro2", + "quote", + "serde", + "serde_json", + "unicode-xid", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strum" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn", +] + +[[package]] +name = "substrate-bip39" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49eee6965196b32f882dd2ee85a92b1dbead41b04e53907f269de3b0dc04733c" +dependencies = [ + "hmac 0.11.0", + "pbkdf2 0.8.0", + "schnorrkel", + "sha2 0.9.9", + "zeroize", +] + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + +[[package]] +name = "syn" +version = "1.0.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b9b43d45702de4c839cb9b51d9f529c5dd26a4aff255b42b1ebc03e88ee908" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "unicode-xid", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "target-lexicon" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9410d0f6853b1d94f0e519fb95df60f29d2c1eff2d921ffdf01a4c8a3b54f12d" + +[[package]] +name = "termcolor" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thread_local" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" +dependencies = [ + "once_cell", +] + +[[package]] +name = "tiny-bip39" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62cc94d358b5a1e84a5cb9109f559aa3c4d634d2b1b4de3d0fa4adc7c78e2861" +dependencies = [ + "anyhow", + "hmac 0.12.1", + "once_cell", + "pbkdf2 0.11.0", + "rand 0.8.5", + "rustc-hash", + "sha2 0.10.6", + "thiserror", + "unicode-normalization", + "wasm-bindgen", + "zeroize", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + +[[package]] +name = "toml" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" +dependencies = [ + "serde", +] + +[[package]] +name = "tracing" +version = "0.1.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +dependencies = [ + "cfg-if", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" +dependencies = [ + "lazy_static", + "log", + "tracing-core", +] + +[[package]] +name = "tracing-serde" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc6b213177105856957181934e4920de57730fc69bf42c37ee5bb664d406d9e1" +dependencies = [ + "serde", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71" +dependencies = [ + "ansi_term", + "chrono", + "lazy_static", + "matchers", + "regex", + "serde", + "serde_json", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", + "tracing-serde", +] + +[[package]] +name = "trie-db" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d75c77ea43f2ad8ea9d9c58de49dfc9c3995bdef32b503df7883ff054e7f1" +dependencies = [ + "hash-db", + "hashbrown 0.13.2", + "log", + "rustc-hex", + "smallvec", +] + +[[package]] +name = "trie-root" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4ed310ef5ab98f5fa467900ed906cb9232dd5376597e00fd4cba2a449d06c0b" +dependencies = [ + "hash-db", +] + +[[package]] +name = "tt-call" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e66dcbec4290c69dd03c57e76c2469ea5c7ce109c6dd4351c13055cf71ea055" + +[[package]] +name = "twox-hash" +version = "1.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" +dependencies = [ + "cfg-if", + "digest 0.10.6", + "rand 0.8.5", + "static_assertions", +] + +[[package]] +name = "typenum" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" + +[[package]] +name = "uint" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524b68aca1d05e03fdf03fcdce2c6c94b6daf6d16861ddaa7e4f2b6638a9052c" + +[[package]] +name = "unicode-ident" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-width" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" + +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + +[[package]] +name = "url" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" + +[[package]] +name = "wasmi" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06c326c93fbf86419608361a2c925a31754cf109da1b8b55737070b4d6669422" +dependencies = [ + "parity-wasm", + "wasmi-validation", + "wasmi_core", +] + +[[package]] +name = "wasmi-validation" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ff416ad1ff0c42e5a926ed5d5fab74c0f098749aa0ad8b2a34b982ce0e867b" +dependencies = [ + "parity-wasm", +] + +[[package]] +name = "wasmi_core" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57d20cb3c59b788653d99541c646c561c9dd26506f25c0cebfe810659c54c6d7" +dependencies = [ + "downcast-rs", + "libm", + "memory_units", + "num-rational", + "num-traits", +] + +[[package]] +name = "wasmparser" +version = "0.100.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64b20236ab624147dfbb62cf12a19aaf66af0e41b8398838b66e997d07d269d4" +dependencies = [ + "indexmap", + "url", +] + +[[package]] +name = "wasmtime" +version = "6.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6e89f9819523447330ffd70367ef4a18d8c832e24e8150fe054d1d912841632" +dependencies = [ + "anyhow", + "bincode", + "cfg-if", + "indexmap", + "libc", + "log", + "object", + "once_cell", + "paste", + "psm", + "serde", + "target-lexicon", + "wasmparser", + "wasmtime-environ", + "wasmtime-jit", + "wasmtime-runtime", + "windows-sys 0.42.0", +] + +[[package]] +name = "wasmtime-asm-macros" +version = "6.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bd3a5e46c198032da934469f3a6e48649d1f9142438e4fd4617b68a35644b8a" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "wasmtime-environ" +version = "6.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a6db9fc52985ba06ca601f2ff0ff1f526c5d724c7ac267b47326304b0c97883" +dependencies = [ + "anyhow", + "cranelift-entity", + "gimli", + "indexmap", + "log", + "object", + "serde", + "target-lexicon", + "thiserror", + "wasmparser", + "wasmtime-types", +] + +[[package]] +name = "wasmtime-jit" +version = "6.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b77e3a52cd84d0f7f18554afa8060cfe564ccac61e3b0802d3fd4084772fa5f6" +dependencies = [ + "addr2line", + "anyhow", + "bincode", + "cfg-if", + "cpp_demangle", + "gimli", + "log", + "object", + "rustc-demangle", + "serde", + "target-lexicon", + "wasmtime-environ", + "wasmtime-jit-icache-coherence", + "wasmtime-runtime", + "windows-sys 0.42.0", +] + +[[package]] +name = "wasmtime-jit-debug" +version = "6.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0245e8a9347017c7185a72e215218a802ff561545c242953c11ba00fccc930f" +dependencies = [ + "once_cell", +] + +[[package]] +name = "wasmtime-jit-icache-coherence" +version = "6.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67d412e9340ab1c83867051d8d1d7c90aa8c9afc91da086088068e2734e25064" +dependencies = [ + "cfg-if", + "libc", + "windows-sys 0.42.0", +] + +[[package]] +name = "wasmtime-runtime" +version = "6.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d594e791b5fdd4dbaf8cf7ae62f2e4ff85018ce90f483ca6f42947688e48827d" +dependencies = [ + "anyhow", + "cc", + "cfg-if", + "indexmap", + "libc", + "log", + "mach", + "memfd", + "memoffset", + "paste", + "rand 0.8.5", + "rustix", + "wasmtime-asm-macros", + "wasmtime-environ", + "wasmtime-jit-debug", + "windows-sys 0.42.0", +] + +[[package]] +name = "wasmtime-types" +version = "6.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6688d6f96d4dbc1f89fab626c56c1778936d122b5f4ae7a57c2eb42b8d982e2" +dependencies = [ + "cranelift-entity", + "serde", + "thiserror", + "wasmparser", +] + +[[package]] +name = "wide" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b689b6c49d6549434bf944e6b0f39238cf63693cb7a147e9d887507fffa3b223" +dependencies = [ + "bytemuck", + "safe_arch", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "zeroize" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44bf07cb3e50ea2003396695d58bf46bc9887a1f362260446fad6bc4e79bd36c" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] diff --git a/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml b/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml new file mode 100644 index 0000000000000..432b732b48e9d --- /dev/null +++ b/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml @@ -0,0 +1,40 @@ +[package] +name = "pallet-election-provider-e2e-test" +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 election provider multi phase pallet tests with staking pallet, bags-list and session pallets" +publish = false + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[workspace] + +[dev-dependencies] +codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } +scale-info = { version = "2.0.1", features = ["derive"] } +log = { version = "0.4.17", default-features = false } + +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 = "7.0.0", path = "../../../primitives/core" } +sp-npos-elections = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/npos-elections" } +sp-tracing = { version = "6.0.0", path = "../../../primitives/tracing" } + +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-election-provider-multi-phase = { version = "4.0.0-dev", path = "../../election-provider-multi-phase" } +pallet-staking = { version = "4.0.0-dev", path = "../../staking" } +pallet-bags-list = { version = "4.0.0-dev", path = "../../bags-list" } +pallet-balances = { version = "4.0.0-dev", path = "../../balances" } +pallet-timestamp = { version = "4.0.0-dev", path = "../../timestamp" } +pallet-session = { version = "4.0.0-dev", path = "../../session" } + diff --git a/frame/election-provider-multi-phase/test-staking-e2e/src/lib.rs b/frame/election-provider-multi-phase/test-staking-e2e/src/lib.rs new file mode 100644 index 0000000000000..c8f7d48a89ecf --- /dev/null +++ b/frame/election-provider-multi-phase/test-staking-e2e/src/lib.rs @@ -0,0 +1,206 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT 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; + +pub(crate) const LOG_TARGET: &str = "tests::e2e-epm"; + +use mock::*; +use sp_core::Get; +use sp_npos_elections::{to_supports, StakedAssignment}; +use sp_runtime::Perbill; + +use crate::mock::RuntimeOrigin; + +// syntactic sugar for logging. +#[macro_export] +macro_rules! log { + ($level:tt, $patter:expr $(, $values:expr)* $(,)?) => { + log::$level!( + target: crate::LOG_TARGET, + concat!("🛠️ ", $patter) $(, $values)* + ) + }; +} + +fn log_current_time() { + log!( + trace, + "block: {:?}, session: {:?}, era: {:?}, EPM phase: {:?} ts: {:?}", + System::block_number(), + Session::current_index(), + Staking::current_era(), + ElectionProviderMultiPhase::current_phase(), + Timestamp::now() + ); +} + +#[test] +fn block_progression_works() { + ExtBuilder::default().build_and_execute(|| { + assert_eq!(active_era(), 0); + assert_eq!(Session::current_index(), 0); + assert!(ElectionProviderMultiPhase::current_phase().is_off()); + + assert!(start_next_active_era().is_ok()); + assert_eq!(active_era(), 1); + assert_eq!(Session::current_index(), >::get()); + + assert!(ElectionProviderMultiPhase::current_phase().is_off()); + + roll_to_epm_signed(); + assert!(ElectionProviderMultiPhase::current_phase().is_signed()); + }); + + ExtBuilder::default().build_and_execute(|| { + assert_eq!(active_era(), 0); + assert_eq!(Session::current_index(), 0); + assert!(ElectionProviderMultiPhase::current_phase().is_off()); + + assert!(start_next_active_era_delayed_solution().is_ok()); + // if the solution is delayed, EPM will end up in emergency mode.. + assert!(ElectionProviderMultiPhase::current_phase().is_emergency()); + // .. era won't progress.. + assert_eq!(active_era(), 0); + // .. but session does. + assert_eq!(Session::current_index(), 2); + }) +} + +#[test] +/// Replicates the Kusama incident of 8th Dec 2022 and its resolution through the governance +/// fallback. +/// +/// After enough slashes exceeded the `Staking::OffendingValidatorsThreshold`, the staking pallet +/// set `Forcing::ForceNew`. When a new session starts, staking will start to force a new era and +/// calls ::elect(). If at this point EPM and the staking miners did not +/// have enough time to queue a new solution (snapshot + solution submission), the election request +/// fails. If there is no election fallback mechanism in place, EPM enters in emergency mode. +/// Recovery: Once EPM is in emergency mode, subsequent calls to `elect()` will fail until a new +/// solution is added to EPM's `QueuedSolution` queue. This can be achieved through +/// `Call::set_emergency_election_result` or `Call::governance_fallback` dispatchables. Once a new +/// solution is added to the queue, EPM phase transitions to `Phase::Off` and the election flow +/// restarts. Note that in this test case, the emergency throttling is disabled. +fn enters_emergency_phase_after_forcing_before_elect() { + let epm_builder = EpmExtBuilder::default().disable_emergency_throttling(); + + ExtBuilder::default().epm(epm_builder).build_and_execute(|| { + log!( + trace, + "current validators (staking): {:?}", + >::validators() + ); + let session_validators_before = Session::validators(); + + roll_to_epm_off(); + assert!(ElectionProviderMultiPhase::current_phase().is_off()); + + assert_eq!(pallet_staking::ForceEra::::get(), pallet_staking::Forcing::NotForcing); + // slashes so that staking goes into `Forcing::ForceNew`. + slash_through_offending_threshold(); + + assert_eq!(pallet_staking::ForceEra::::get(), pallet_staking::Forcing::ForceNew); + + advance_session_delayed_solution(); + assert!(ElectionProviderMultiPhase::current_phase().is_emergency()); + log_current_time(); + + let era_before_delayed_next = Staking::current_era(); + // try to advance 2 eras. + assert!(start_next_active_era_delayed_solution().is_ok()); + assert_eq!(Staking::current_era(), era_before_delayed_next); + assert!(start_next_active_era().is_err()); + assert_eq!(Staking::current_era(), era_before_delayed_next); + + // EPM is still in emergency phase. + assert!(ElectionProviderMultiPhase::current_phase().is_emergency()); + + // session validator set remains the same. + assert_eq!(Session::validators(), session_validators_before); + + // performs recovery through the set emergency result. + let supports = to_supports(&vec![ + StakedAssignment { who: 21, distribution: vec![(21, 10)] }, + StakedAssignment { who: 31, distribution: vec![(21, 10), (31, 10)] }, + StakedAssignment { who: 41, distribution: vec![(41, 10)] }, + ]); + assert!(ElectionProviderMultiPhase::set_emergency_election_result( + RuntimeOrigin::root(), + supports + ) + .is_ok()); + + // EPM can now roll to signed phase to proceed with elections. The validator set is the + // expected (ie. set through `set_emergency_election_result`). + roll_to_epm_signed(); + //assert!(ElectionProviderMultiPhase::current_phase().is_signed()); + assert_eq!(Session::validators(), vec![21, 31, 41]); + assert_eq!(Staking::current_era(), era_before_delayed_next.map(|e| e + 1)); + }); +} + +#[test] +/// Continuously slash 10% of the active validators per era. +/// +/// Since the `OffendingValidatorsThreshold` is only checked per era staking does not force a new +/// era even as the number of active validators is decreasing across eras. When processing a new +/// slash, staking calculates the offending threshold based on the length of the current list of +/// active validators. Thus, slashing a percentage of the current validators that is lower than +/// `OffendingValidatorsThreshold` will never force a new era. However, as the slashes progress, if +/// the subsequent elections do not meet the minimum election untrusted score, the election will +/// fail and enter in emenergency mode. +fn continous_slashes_below_offending_threshold() { + let staking_builder = StakingExtBuilder::default().validator_count(10); + let epm_builder = EpmExtBuilder::default().disable_emergency_throttling(); + + ExtBuilder::default() + .staking(staking_builder) + .epm(epm_builder) + .build_and_execute(|| { + assert_eq!(Session::validators().len(), 10); + let mut active_validator_set = Session::validators(); + + roll_to_epm_signed(); + + // set a minimum election score. + assert!(set_minimum_election_score(500, 1000, 500).is_ok()); + + // slash 10% of the active validators and progress era until the minimum trusted score + // is reached. + while active_validator_set.len() > 0 { + let slashed = slash_percentage(Perbill::from_percent(10)); + assert_eq!(slashed.len(), 1); + + // break loop when era does not progress; EPM is in emergency phase as election + // failed due to election minimum score. + if start_next_active_era().is_err() { + assert!(ElectionProviderMultiPhase::current_phase().is_emergency()); + break + } + + active_validator_set = Session::validators(); + + log!( + trace, + "slashed 10% of active validators ({:?}). After slash: {:?}", + slashed, + active_validator_set + ); + } + }); +} diff --git a/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs b/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs new file mode 100644 index 0000000000000..19f568737c852 --- /dev/null +++ b/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs @@ -0,0 +1,779 @@ +// 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. + +#![allow(dead_code)] + +use _feps::ExtendedBalance; +use frame_support::{ + parameter_types, traits, + traits::{GenesisBuild, Hooks}, + weights::constants, +}; +use frame_system::EnsureRoot; +use sp_core::{ConstU32, Get, H256}; +use sp_npos_elections::{ElectionScore, VoteWeight}; +use sp_runtime::{ + testing, + traits::{IdentityLookup, Zero}, + transaction_validity, PerU16, Perbill, +}; +use sp_staking::{ + offence::{DisableStrategy, OffenceDetails, OnOffenceHandler}, + EraIndex, SessionIndex, +}; +use sp_std::prelude::*; +use std::collections::BTreeMap; + +use frame_election_provider_support::{onchain, ElectionDataProvider, SequentialPhragmen, Weight}; +use pallet_election_provider_multi_phase::{ + unsigned::MinerConfig, ElectionCompute, QueuedSolution, SolutionAccuracyOf, +}; +use pallet_staking::StakerStatus; + +use crate::{log, log_current_time}; + +pub const INIT_TIMESTAMP: u64 = 30_000; +pub const BLOCK_TIME: u64 = 1000; + +type Block = frame_system::mocking::MockBlock; +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +type Extrinsic = testing::TestXt; + +frame_support::construct_runtime!( + pub enum Runtime where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic + { + System: frame_system, + ElectionProviderMultiPhase: pallet_election_provider_multi_phase, + Staking: pallet_staking, + Balances: pallet_balances, + BagsList: pallet_bags_list, + Session: pallet_session, + Historical: pallet_session::historical, + Timestamp: pallet_timestamp, + } +); + +pub(crate) type AccountId = u128; +pub(crate) type AccountIndex = u32; +pub(crate) type BlockNumber = u64; +pub(crate) type Balance = u64; +pub(crate) type VoterIndex = u32; +pub(crate) type TargetIndex = u16; +pub(crate) type Moment = u64; + +impl frame_system::Config for Runtime { + type BaseCallFilter = traits::Everything; + type BlockWeights = BlockWeights; + type BlockLength = (); + type DbWeight = (); + type RuntimeOrigin = RuntimeOrigin; + type Index = AccountIndex; + type BlockNumber = BlockNumber; + 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 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 = traits::ConstU32<16>; +} + +const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); +parameter_types! { + pub static ExistentialDeposit: Balance = 1; + pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights + ::with_sensible_defaults( + Weight::from_parts(2u64 * constants::WEIGHT_REF_TIME_PER_SECOND, u64::MAX), + NORMAL_DISPATCH_RATIO, + ); +} + +impl pallet_balances::Config for Runtime { + type MaxLocks = traits::ConstU32<1024>; + type MaxReserves = (); + type ReserveIdentifier = [u8; 8]; + type Balance = Balance; + type RuntimeEvent = RuntimeEvent; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = (); +} + +impl pallet_timestamp::Config for Runtime { + type Moment = Moment; + type OnTimestampSet = (); + type MinimumPeriod = traits::ConstU64<5>; + type WeightInfo = (); +} + +parameter_types! { + pub static Period: BlockNumber = 30; + pub static Offset: BlockNumber = 0; +} + +sp_runtime::impl_opaque_keys! { + pub struct SessionKeys { + pub other: OtherSessionHandler, + } +} + +impl pallet_session::Config for Runtime { + type SessionManager = pallet_session::historical::NoteHistoricalRoot; + type Keys = SessionKeys; + type ShouldEndSession = pallet_session::PeriodicSessions; + type NextSessionRotation = pallet_session::PeriodicSessions; + type SessionHandler = (OtherSessionHandler,); + type RuntimeEvent = RuntimeEvent; + type ValidatorId = AccountId; + type ValidatorIdOf = pallet_staking::StashOf; + type WeightInfo = (); +} +impl pallet_session::historical::Config for Runtime { + type FullIdentification = pallet_staking::Exposure; + type FullIdentificationOf = pallet_staking::ExposureOf; +} + +frame_election_provider_support::generate_solution_type!( + #[compact] + pub struct MockNposSolution::< + VoterIndex = VoterIndex, + TargetIndex = TargetIndex, + Accuracy = PerU16, + MaxVoters = ConstU32::<2_000> + >(16) +); + +parameter_types! { + pub static SignedPhase: BlockNumber = 10; + pub static UnsignedPhase: BlockNumber = 10; + // we expect a minimum of 3 blocks in signed phase and unsigned phases before trying + // enetering in emergency phase after the election failed. + pub static MinBlocksBeforeEmergency: BlockNumber = 3; + pub static MaxElectingVoters: VoterIndex = 1000; + pub static MaxElectableTargets: TargetIndex = 1000; + pub static MaxActiveValidators: u32 = 1000; + pub static OffchainRepeat: u32 = 5; + pub static MinerMaxLength: u32 = 256; + pub static MinerMaxWeight: Weight = BlockWeights::get().max_block; + pub static TransactionPriority: transaction_validity::TransactionPriority = 1; + pub static MaxWinners: u32 = 100; + pub static MaxVotesPerVoter: u32 = 16; + pub static MaxNominations: u32 = 16; +} + +impl pallet_election_provider_multi_phase::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type EstimateCallFee = frame_support::traits::ConstU32<8>; + type SignedPhase = SignedPhase; + type UnsignedPhase = UnsignedPhase; + type BetterSignedThreshold = (); + type BetterUnsignedThreshold = (); + type OffchainRepeat = OffchainRepeat; + type MinerTxPriority = TransactionPriority; + type MinerConfig = Self; + type SignedMaxSubmissions = ConstU32<10>; + type SignedRewardBase = (); + type SignedDepositBase = (); + type SignedDepositByte = (); + type SignedMaxRefunds = ConstU32<3>; + type SignedDepositWeight = (); + type SignedMaxWeight = (); + type SlashHandler = (); + type RewardHandler = (); + type DataProvider = Staking; + type Fallback = + frame_election_provider_support::NoElection<(AccountId, BlockNumber, Staking, MaxWinners)>; + type GovernanceFallback = onchain::OnChainExecution; + type Solver = SequentialPhragmen, ()>; + type ForceOrigin = EnsureRoot; + type MaxElectableTargets = MaxElectableTargets; + type MaxElectingVoters = MaxElectingVoters; + type MaxWinners = MaxWinners; + type BenchmarkingConfig = NoopElectionProviderBenchmarkConfig; + type WeightInfo = (); +} + +impl MinerConfig for Runtime { + type AccountId = AccountId; + type Solution = MockNposSolution; + type MaxVotesPerVoter = + <::DataProvider as ElectionDataProvider>::MaxVotesPerVoter; + type MaxLength = MinerMaxLength; + type MaxWeight = MinerMaxWeight; + type MaxWinners = MaxWinners; + + fn solution_weight(_v: u32, _t: u32, _a: u32, _d: u32) -> Weight { + Weight::zero() + } +} + +const THRESHOLDS: [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; + pub const SessionsPerEra: sp_staking::SessionIndex = 2; + pub const BondingDuration: sp_staking::EraIndex = 28; + pub const SlashDeferDuration: sp_staking::EraIndex = 7; // 1/4 the bonding duration. + pub const MaxNominatorRewardedPerValidator: u32 = 256; + pub const OffendingValidatorsThreshold: Perbill = Perbill::from_percent(40); + pub HistoryDepth: u32 = 84; +} + +impl pallet_bags_list::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); + type ScoreProvider = Staking; + type BagThresholds = BagThresholds; + type Score = VoteWeight; +} + +impl pallet_staking::Config for Runtime { + type MaxNominations = MaxNominations; + type Currency = Balances; + type CurrencyBalance = Balance; + type UnixTime = Timestamp; + type CurrencyToVote = traits::SaturatingCurrencyToVote; + type RewardRemainder = (); + type RuntimeEvent = RuntimeEvent; + type Slash = (); // burn slashes + type Reward = (); // rewards are minted from the void + type SessionsPerEra = SessionsPerEra; + type BondingDuration = BondingDuration; + type SlashDeferDuration = SlashDeferDuration; + type AdminOrigin = EnsureRoot; // root can cancel slashes + type SessionInterface = Self; + type EraPayout = (); + type NextNewSession = Session; + type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; + type OffendingValidatorsThreshold = OffendingValidatorsThreshold; + type ElectionProvider = ElectionProviderMultiPhase; + type GenesisElectionProvider = onchain::OnChainExecution; + type VoterList = BagsList; + type TargetList = pallet_staking::UseValidatorsMap; + type MaxUnlockingChunks = ConstU32<32>; + type HistoryDepth = HistoryDepth; + type OnStakerSlash = (); + type WeightInfo = pallet_staking::weights::SubstrateWeight; + type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; +} + +impl frame_system::offchain::SendTransactionTypes for Runtime +where + RuntimeCall: From, +{ + type OverarchingCall = RuntimeCall; + type Extrinsic = Extrinsic; +} + +pub struct OnChainSeqPhragmen; + +parameter_types! { + pub static VotersBound: u32 = 600; + pub static TargetsBound: u32 = 400; +} + +impl onchain::Config for OnChainSeqPhragmen { + type System = Runtime; + type Solver = SequentialPhragmen< + AccountId, + pallet_election_provider_multi_phase::SolutionAccuracyOf, + >; + type DataProvider = Staking; + type WeightInfo = (); + type MaxWinners = MaxWinners; + type VotersBound = VotersBound; + type TargetsBound = TargetsBound; +} + +pub struct NoopElectionProviderBenchmarkConfig; + +impl pallet_election_provider_multi_phase::BenchmarkingConfig + for NoopElectionProviderBenchmarkConfig +{ + const VOTERS: [u32; 2] = [0, 0]; + const TARGETS: [u32; 2] = [0, 0]; + const ACTIVE_VOTERS: [u32; 2] = [0, 0]; + const DESIRED_TARGETS: [u32; 2] = [0, 0]; + const SNAPSHOT_MAXIMUM_VOTERS: u32 = 0; + const MINER_MAXIMUM_VOTERS: u32 = 0; + const MAXIMUM_TARGETS: u32 = 0; +} + +pub struct OtherSessionHandler; +impl traits::OneSessionHandler for OtherSessionHandler { + type Key = testing::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 = testing::UintAuthorityId; +} + +pub struct StakingExtBuilder { + validator_count: u32, + minimum_validator_count: u32, + min_nominator_bond: Balance, + min_validator_bond: Balance, + status: BTreeMap>, + stakes: BTreeMap, + stakers: Vec<(AccountId, AccountId, Balance, StakerStatus)>, +} + +impl Default for StakingExtBuilder { + fn default() -> Self { + 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), + // loser validatos if validator_count() is default. + (31, 30, 500, StakerStatus::::Validator), + (41, 40, 500, StakerStatus::::Validator), + (51, 50, 500, StakerStatus::::Validator), + (61, 60, 500, StakerStatus::::Validator), + (71, 70, 500, StakerStatus::::Validator), + (81, 80, 500, StakerStatus::::Validator), + (91, 90, 500, StakerStatus::::Validator), + (101, 100, 500, StakerStatus::::Validator), + // an idle validator + (201, 200, 1000, StakerStatus::::Idle), + ]; + + Self { + validator_count: 2, + minimum_validator_count: 0, + min_nominator_bond: ExistentialDeposit::get(), + min_validator_bond: ExistentialDeposit::get(), + status: Default::default(), + stakes: Default::default(), + stakers, + } + } +} + +impl StakingExtBuilder { + pub fn validator_count(mut self, n: u32) -> Self { + self.validator_count = n; + self + } +} + +pub struct EpmExtBuilder {} + +impl Default for EpmExtBuilder { + fn default() -> Self { + EpmExtBuilder {} + } +} + +impl EpmExtBuilder { + pub fn disable_emergency_throttling(self) -> Self { + ::set(0); + self + } + + pub fn phases(self, signed: BlockNumber, unsigned: BlockNumber) -> Self { + ::set(signed); + ::set(unsigned); + self + } +} + +pub struct BalancesExtBuilder { + balances: Vec<(AccountId, Balance)>, +} + +impl Default for BalancesExtBuilder { + fn default() -> Self { + let balances = vec![ + // (account_id, balance) + (1, 10), + (2, 20), + (3, 300), + (4, 400), + // controllers + (10, 100), + (20, 100), + (30, 100), + (40, 100), + (50, 100), + (60, 100), + (70, 100), + (80, 100), + (90, 100), + (100, 100), + (200, 100), + // stashes + (11, 1000), + (21, 2000), + (31, 3000), + (41, 4000), + (51, 5000), + (61, 6000), + (71, 7000), + (81, 8000), + (91, 9000), + (101, 10000), + (201, 20000), + // This allows us to have a total_payout different from 0. + (999, 1_000_000_000_000), + ]; + Self { balances } + } +} + +pub struct ExtBuilder { + staking_builder: StakingExtBuilder, + epm_builder: EpmExtBuilder, + balances_builder: BalancesExtBuilder, +} + +impl Default for ExtBuilder { + fn default() -> Self { + Self { + staking_builder: StakingExtBuilder::default(), + epm_builder: EpmExtBuilder::default(), + balances_builder: BalancesExtBuilder::default(), + } + } +} + +impl ExtBuilder { + pub fn build(self) -> sp_io::TestExternalities { + sp_tracing::try_init_simple(); + let mut storage = + frame_system::GenesisConfig::default().build_storage::().unwrap(); + + let _ = + pallet_balances::GenesisConfig:: { balances: self.balances_builder.balances } + .assimilate_storage(&mut storage); + + let mut stakers = self.staking_builder.stakers.clone(); + self.staking_builder.status.into_iter().for_each(|(stash, status)| { + let (_, _, _, ref mut prev_status) = stakers + .iter_mut() + .find(|s| s.0 == stash) + .expect("set_status staker should exist; qed"); + *prev_status = status; + }); + // replaced any of the stakes if needed. + self.staking_builder.stakes.into_iter().for_each(|(stash, stake)| { + let (_, _, ref mut prev_stake, _) = stakers + .iter_mut() + .find(|s| s.0 == stash) + .expect("set_stake staker should exits; qed."); + *prev_stake = stake; + }); + + let _ = pallet_staking::GenesisConfig:: { + stakers: stakers.clone(), + validator_count: self.staking_builder.validator_count, + minimum_validator_count: self.staking_builder.minimum_validator_count, + slash_reward_fraction: Perbill::from_percent(10), + min_nominator_bond: self.staking_builder.min_nominator_bond, + min_validator_bond: self.staking_builder.min_validator_bond, + ..Default::default() + } + .assimilate_storage(&mut storage); + + let _ = pallet_session::GenesisConfig:: { + // set the keys for the first session. + keys: stakers + .into_iter() + .map(|(id, ..)| (id, id, SessionKeys { other: (id as u64).into() })) + .collect(), + } + .assimilate_storage(&mut storage); + + let mut ext = sp_io::TestExternalities::from(storage); + + // We consider all test to start after timestamp is initialized This must be ensured by + // having `timestamp::on_initialize` called before `staking::on_initialize`. + ext.execute_with(|| { + System::set_block_number(1); + Session::on_initialize(1); + >::on_initialize(1); + Timestamp::set_timestamp(INIT_TIMESTAMP); + }); + + ext + } + pub fn staking(mut self, builder: StakingExtBuilder) -> Self { + self.staking_builder = builder; + self + } + + pub fn epm(mut self, builder: EpmExtBuilder) -> Self { + self.epm_builder = builder; + self + } + + pub fn balances(mut self, builder: BalancesExtBuilder) -> Self { + self.balances_builder = builder; + self + } + + pub fn build_and_execute(self, test: impl FnOnce() -> ()) { + self.build().execute_with(test) + } +} + +// Progress to given block, triggering session and era changes as we progress and ensuring that +// there is a solution queued when expected. +pub fn roll_to(n: BlockNumber, delay_solution: bool) { + for b in (System::block_number()) + 1..=n { + System::set_block_number(b); + Session::on_initialize(b); + Timestamp::set_timestamp(System::block_number() * BLOCK_TIME + INIT_TIMESTAMP); + + // TODO(gpestana): implement a realistic OCW worker insted of simulating it + // https://github.com/paritytech/substrate/issues/13589 + // if there's no solution queued and the solution should not be delayed, try mining and + // queue a solution. + if ElectionProviderMultiPhase::current_phase().is_signed() && !delay_solution { + let _ = try_queue_solution(ElectionCompute::Signed).map_err(|e| { + log!(info, "failed to mine/queue solution: {:?}", e); + }); + } + ElectionProviderMultiPhase::on_initialize(b); + + Staking::on_initialize(b); + if b != n { + Staking::on_finalize(System::block_number()); + } + + log_current_time(); + } +} + +/// Progresses from the current block number (whatever that may be) to the block where the session +/// `session_index` starts. +pub(crate) fn start_session(session_index: SessionIndex, delay_solution: bool) { + let end: u64 = if Offset::get().is_zero() { + Period::get() * (session_index as u64) + } else { + Offset::get() * (session_index as u64) + Period::get() * (session_index as u64) + }; + + assert!(end >= System::block_number()); + + roll_to(end, delay_solution); + + // session must have progressed properly. + assert_eq!( + Session::current_index(), + session_index, + "current session index = {}, expected = {}", + Session::current_index(), + session_index, + ); +} + +/// Go one session forward. +pub(crate) fn advance_session() { + let current_index = Session::current_index(); + start_session(current_index + 1, false); +} + +pub(crate) fn advance_session_delayed_solution() { + let current_index = Session::current_index(); + start_session(current_index + 1, true); +} + +pub(crate) fn start_next_active_era() -> Result<(), ()> { + start_active_era(active_era() + 1, false) +} + +pub(crate) fn start_next_active_era_delayed_solution() -> Result<(), ()> { + start_active_era(active_era() + 1, true) +} + +/// Progress until the given era. +pub(crate) fn start_active_era(era_index: EraIndex, delay_solution: bool) -> Result<(), ()> { + let era_before = current_era(); + + start_session((era_index * >::get()).into(), delay_solution); + + log!( + info, + "start_active_era - era_before: {}, current era: {} -> progress to: {} -> after era: {}", + era_before, + active_era(), + era_index, + current_era(), + ); + + // if the solution was not delayed, era should have progressed. + if !delay_solution && (active_era() != era_index || current_era() != active_era()) { + Err(()) + } else { + Ok(()) + } +} + +pub(crate) fn active_era() -> EraIndex { + Staking::active_era().unwrap().index +} + +pub(crate) fn current_era() -> EraIndex { + Staking::current_era().unwrap() +} + +// Fast forward until EPM signed phase. +pub fn roll_to_epm_signed() { + while !matches!( + ElectionProviderMultiPhase::current_phase(), + pallet_election_provider_multi_phase::Phase::Signed + ) { + roll_to(System::block_number() + 1, false); + } +} + +// Fast forward until EPM unsigned phase. +pub fn roll_to_epm_unsigned() { + while !matches!( + ElectionProviderMultiPhase::current_phase(), + pallet_election_provider_multi_phase::Phase::Unsigned(_) + ) { + roll_to(System::block_number() + 1, false); + } +} + +// Fast forward until EPM off. +pub fn roll_to_epm_off() { + while !matches!( + ElectionProviderMultiPhase::current_phase(), + pallet_election_provider_multi_phase::Phase::Off + ) { + roll_to(System::block_number() + 1, false); + } +} + +// Queue a solution based on the current snapshot. +pub(crate) fn try_queue_solution(when: ElectionCompute) -> Result<(), String> { + let raw_solution = ElectionProviderMultiPhase::mine_solution() + .map_err(|e| format!("error mining solution: {:?}", e))?; + + ElectionProviderMultiPhase::feasibility_check(raw_solution.0, when) + .map(|ready| { + QueuedSolution::::put(ready); + }) + .map_err(|e| format!("error in solution feasibility: {:?}", e)) +} + +pub(crate) fn on_offence_now( + offenders: &[OffenceDetails< + AccountId, + pallet_session::historical::IdentificationTuple, + >], + slash_fraction: &[Perbill], +) { + let now = Staking::active_era().unwrap().index; + let _ = Staking::on_offence( + offenders, + slash_fraction, + Staking::eras_start_session_index(now).unwrap(), + DisableStrategy::WhenSlashed, + ); +} + +// Add offence to validator, slash it. +pub(crate) fn add_slash(who: &AccountId) { + on_offence_now( + &[OffenceDetails { + offender: (*who, Staking::eras_stakers(active_era(), *who)), + reporters: vec![], + }], + &[Perbill::from_percent(10)], + ); +} + +// Slashes enough validators to cross the `Staking::OffendingValidatorsThreshold`. +pub(crate) fn slash_through_offending_threshold() { + let validators = Session::validators(); + let mut remaining_slashes = + ::OffendingValidatorsThreshold::get() * + validators.len() as u32; + + for v in validators.into_iter() { + if remaining_slashes != 0 { + add_slash(&v); + remaining_slashes -= 1; + } + } +} + +// Slashes a percentage of the active nominators that haven't been slashed yet, with +// a minimum of 1 validator slash. +pub(crate) fn slash_percentage(percentage: Perbill) -> Vec { + let validators = Session::validators(); + let mut remaining_slashes = (percentage * validators.len() as u32).max(1); + let mut slashed = vec![]; + + for v in validators.into_iter() { + if remaining_slashes != 0 { + add_slash(&v); + slashed.push(v); + remaining_slashes -= 1; + } + } + slashed +} + +pub(crate) fn set_minimum_election_score( + minimal_stake: ExtendedBalance, + sum_stake: ExtendedBalance, + sum_stake_squared: ExtendedBalance, +) -> Result<(), ()> { + let election_score = ElectionScore { minimal_stake, sum_stake, sum_stake_squared }; + ElectionProviderMultiPhase::set_minimum_untrusted_score( + RuntimeOrigin::root(), + Some(election_score), + ) + .map(|_| ()) + .map_err(|_| ()) +} From e359d8b3d14ae3c5b012704dd406ed593fcfcca2 Mon Sep 17 00:00:00 2001 From: Mira Ressel Date: Thu, 16 Mar 2023 13:41:43 +0100 Subject: [PATCH 520/715] fix BASE lookup in cargo-check-benches --- scripts/ci/gitlab/pipeline/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/ci/gitlab/pipeline/test.yml b/scripts/ci/gitlab/pipeline/test.yml index fd031d9aa56c3..c13f2f3611ba0 100644 --- a/scripts/ci/gitlab/pipeline/test.yml +++ b/scripts/ci/gitlab/pipeline/test.yml @@ -91,7 +91,7 @@ cargo-check-benches: - !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) + 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 +${BASE}:${BASE}; git fetch origin +$CI_COMMIT_REF_NAME:$CI_COMMIT_REF_NAME; From 283106b19b85bc8deb232cfa624eed195f143541 Mon Sep 17 00:00:00 2001 From: Mira Ressel Date: Thu, 16 Mar 2023 14:47:28 +0100 Subject: [PATCH 521/715] refactor cargo-check-benches logic * fix fetch refspec * assume base is master if the api call fails * merge master into pr branch rather than the other way around; same effect but imo cleaner and more readable * don't re-fetch pr branch, we want to test the version our pipeline is running on --- scripts/ci/gitlab/pipeline/test.yml | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/scripts/ci/gitlab/pipeline/test.yml b/scripts/ci/gitlab/pipeline/test.yml index c13f2f3611ba0..7c5f43c291ea7 100644 --- a/scripts/ci/gitlab/pipeline/test.yml +++ b/scripts/ci/gitlab/pipeline/test.yml @@ -90,15 +90,13 @@ 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 +${BASE}:${BASE}; - git fetch origin +$CI_COMMIT_REF_NAME:$CI_COMMIT_REF_NAME; - git checkout ${BASE}; + - 'if [ $CI_COMMIT_REF_NAME != "master" ]; then + BASE=$(curl -s -H "Authorization: Bearer ${GITHUB_PR_TOKEN}" https://api.github.com/repos/paritytech/substrate/pulls/${CI_COMMIT_REF_NAME} | jq -r .base.ref); + printf "Merging base branch %s\n" "${BASE:=master}"; git config user.email "ci@gitlab.parity.io"; - git merge $CI_COMMIT_REF_NAME --verbose --no-edit; - fi + git fetch origin "refs/heads/${BASE}"; + git merge --verbose --no-edit FETCH_HEAD; + fi' parallel: 2 script: - rusty-cachier snapshot create From be9e305d2476fa68b4278fdd7eb00decb5b80331 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Thu, 16 Mar 2023 17:57:45 +0100 Subject: [PATCH 522/715] Update all weights (#13614) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Empty commit * ".git/.scripts/commands/bench/bench.sh" all --------- Co-authored-by: Alexander Theißen Co-authored-by: command-bot <> --- frame/alliance/src/weights.rs | 523 ++-- frame/assets/src/weights.rs | 354 +-- frame/bags-list/src/weights.rs | 55 +- frame/balances/src/weights.rs | 100 +- frame/benchmarking/src/weights.rs | 70 +- frame/bounties/src/weights.rs | 199 +- frame/child-bounties/src/weights.rs | 143 +- frame/collective/src/weights.rs | 343 ++- frame/contracts/src/weights.rs | 2736 ++++++++--------- frame/conviction-voting/src/weights.rs | 143 +- frame/core-fellowship/src/weights.rs | 122 +- frame/democracy/src/weights.rs | 480 +-- .../src/weights.rs | 227 +- frame/elections-phragmen/src/weights.rs | 268 +- frame/fast-unstake/src/weights.rs | 399 ++- frame/glutton/src/weights.rs | 148 +- frame/identity/src/weights.rs | 455 ++- frame/im-online/src/weights.rs | 43 +- frame/indices/src/weights.rs | 83 +- frame/lottery/src/weights.rs | 95 +- frame/membership/src/weights.rs | 167 +- frame/message-queue/src/weights.rs | 118 +- frame/multisig/src/weights.rs | 183 +- frame/nfts/src/weights.rs | 526 ++-- frame/nis/src/weights.rs | 187 +- frame/nomination-pools/src/weights.rs | 290 +- frame/preimage/src/weights.rs | 175 +- frame/proxy/src/weights.rs | 275 +- frame/ranked-collective/src/weights.rs | 127 +- frame/recovery/src/weights.rs | 167 +- frame/referenda/src/weights.rs | 492 +-- frame/remark/src/weights.rs | 23 +- frame/salary/src/weights.rs | 97 +- frame/scheduler/src/weights.rs | 207 +- frame/session/src/weights.rs | 39 +- frame/staking/src/weights.rs | 555 ++-- frame/state-trie-migration/src/weights.rs | 99 +- frame/support/src/weights/block_weights.rs | 20 +- .../support/src/weights/extrinsic_weights.rs | 20 +- frame/system/src/weights.rs | 93 +- frame/timestamp/src/weights.rs | 27 +- frame/tips/src/weights.rs | 147 +- frame/transaction-storage/src/weights.rs | 55 +- frame/treasury/src/weights.rs | 111 +- frame/uniques/src/weights.rs | 471 +-- frame/utility/src/weights.rs | 71 +- frame/vesting/src/weights.rs | 263 +- frame/whitelist/src/weights.rs | 71 +- 48 files changed, 6019 insertions(+), 6043 deletions(-) diff --git a/frame/alliance/src/weights.rs b/frame/alliance/src/weights.rs index 8ff4bad31313c..a9756c2d27127 100644 --- a/frame/alliance/src/weights.rs +++ b/frame/alliance/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_alliance //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,6 +31,9 @@ // --steps=50 // --repeat=20 // --pallet=pallet_alliance +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -88,20 +91,20 @@ impl WeightInfo for SubstrateWeight { /// The range of component `p` is `[1, 100]`. fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `692 + m * (32 ±0) + p * (36 ±0)` - // Estimated: `11659 + m * (132 ±0) + p * (144 ±0)` - // Minimum execution time: 28_849 nanoseconds. - Weight::from_parts(29_823_933, 11659) - // Standard Error: 74 - .saturating_add(Weight::from_parts(830, 0).saturating_mul(b.into())) - // Standard Error: 775 - .saturating_add(Weight::from_parts(22_980, 0).saturating_mul(m.into())) - // Standard Error: 765 - .saturating_add(Weight::from_parts(90_520, 0).saturating_mul(p.into())) + // Measured: `618 + m * (32 ±0) + p * (36 ±0)` + // Estimated: `15463 + m * (124 ±0) + p * (148 ±0)` + // Minimum execution time: 32_788_000 picoseconds. + Weight::from_parts(36_725_375, 15463) + // Standard Error: 138 + .saturating_add(Weight::from_parts(1_252, 0).saturating_mul(b.into())) + // Standard Error: 1_445 + .saturating_add(Weight::from_parts(9_861, 0).saturating_mul(m.into())) + // Standard Error: 1_427 + .saturating_add(Weight::from_parts(127_304, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) - .saturating_add(Weight::from_parts(0, 132).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 144).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 124).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 148).saturating_mul(p.into())) } /// Storage: Alliance Members (r:1 w:0) /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) @@ -110,12 +113,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `m` is `[5, 100]`. fn vote(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1177 + m * (64 ±0)` - // Estimated: `9337 + m * (64 ±0)` - // Minimum execution time: 23_570 nanoseconds. - Weight::from_parts(25_473_196, 9337) - // Standard Error: 824 - .saturating_add(Weight::from_parts(54_603, 0).saturating_mul(m.into())) + // Measured: `1042 + m * (64 ±0)` + // Estimated: `11182 + m * (64 ±0)` + // Minimum execution time: 26_632_000 picoseconds. + Weight::from_parts(28_918_089, 11182) + // Standard Error: 947 + .saturating_add(Weight::from_parts(56_565, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) @@ -134,17 +137,17 @@ impl WeightInfo for SubstrateWeight { /// The range of component `p` is `[1, 100]`. fn close_early_disapproved(m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `730 + m * (96 ±0) + p * (36 ±0)` - // Estimated: `11979 + m * (388 ±0) + p * (148 ±0)` - // Minimum execution time: 35_373 nanoseconds. - Weight::from_parts(32_763_656, 11979) - // Standard Error: 2_041 - .saturating_add(Weight::from_parts(52_915, 0).saturating_mul(m.into())) - // Standard Error: 1_991 - .saturating_add(Weight::from_parts(78_594, 0).saturating_mul(p.into())) + // Measured: `622 + m * (96 ±0) + p * (37 ±0)` + // Estimated: `15551 + m * (384 ±0) + p * (148 ±0)` + // Minimum execution time: 40_937_000 picoseconds. + Weight::from_parts(39_361_123, 15551) + // Standard Error: 1_609 + .saturating_add(Weight::from_parts(43_225, 0).saturating_mul(m.into())) + // Standard Error: 1_569 + .saturating_add(Weight::from_parts(112_935, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 388).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 384).saturating_mul(m.into())) .saturating_add(Weight::from_parts(0, 148).saturating_mul(p.into())) } /// Storage: Alliance Members (r:1 w:0) @@ -162,20 +165,20 @@ impl WeightInfo for SubstrateWeight { /// The range of component `p` is `[1, 100]`. fn close_early_approved(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1139 + m * (96 ±0) + p * (41 ±0)` - // Estimated: `15730 + m * (388 ±0) + p * (164 ±0)` - // Minimum execution time: 44_590 nanoseconds. - Weight::from_parts(43_367_913, 15730) - // Standard Error: 71 - .saturating_add(Weight::from_parts(819, 0).saturating_mul(b.into())) - // Standard Error: 751 - .saturating_add(Weight::from_parts(39_124, 0).saturating_mul(m.into())) - // Standard Error: 732 - .saturating_add(Weight::from_parts(90_469, 0).saturating_mul(p.into())) + // Measured: `903 + m * (96 ±0) + p * (41 ±0)` + // Estimated: `20072 + m * (392 ±0) + p * (160 ±0)` + // Minimum execution time: 51_569_000 picoseconds. + Weight::from_parts(50_722_448, 20072) + // Standard Error: 120 + .saturating_add(Weight::from_parts(474, 0).saturating_mul(b.into())) + // Standard Error: 1_271 + .saturating_add(Weight::from_parts(48_855, 0).saturating_mul(m.into())) + // Standard Error: 1_239 + .saturating_add(Weight::from_parts(139_022, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 388).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 164).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 392).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 160).saturating_mul(p.into())) } /// Storage: Alliance Members (r:1 w:0) /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) @@ -193,17 +196,17 @@ impl WeightInfo for SubstrateWeight { /// The range of component `p` is `[1, 100]`. fn close_disapproved(m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `730 + m * (96 ±0) + p * (36 ±0)` - // Estimated: `13201 + m * (485 ±0) + p * (185 ±0)` - // Minimum execution time: 36_796 nanoseconds. - Weight::from_parts(34_578_765, 13201) - // Standard Error: 1_037 - .saturating_add(Weight::from_parts(43_508, 0).saturating_mul(m.into())) - // Standard Error: 1_024 - .saturating_add(Weight::from_parts(77_084, 0).saturating_mul(p.into())) + // Measured: `622 + m * (96 ±0) + p * (37 ±0)` + // Estimated: `17666 + m * (480 ±0) + p * (185 ±0)` + // Minimum execution time: 42_084_000 picoseconds. + Weight::from_parts(39_907_823, 17666) + // Standard Error: 899 + .saturating_add(Weight::from_parts(46_642, 0).saturating_mul(m.into())) + // Standard Error: 888 + .saturating_add(Weight::from_parts(114_161, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 485).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 480).saturating_mul(m.into())) .saturating_add(Weight::from_parts(0, 185).saturating_mul(p.into())) } /// Storage: Alliance Members (r:1 w:0) @@ -223,20 +226,20 @@ impl WeightInfo for SubstrateWeight { /// The range of component `p` is `[1, 100]`. fn close_approved(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `757 + m * (96 ±0) + p * (36 ±0)` - // Estimated: `13146 + m * (480 ±0) + p * (185 ±0)` - // Minimum execution time: 36_897 nanoseconds. - Weight::from_parts(34_169_666, 13146) - // Standard Error: 47 - .saturating_add(Weight::from_parts(972, 0).saturating_mul(b.into())) - // Standard Error: 510 - .saturating_add(Weight::from_parts(38_084, 0).saturating_mul(m.into())) - // Standard Error: 492 - .saturating_add(Weight::from_parts(78_576, 0).saturating_mul(p.into())) + // Measured: `591 + m * (96 ±0) + p * (36 ±0)` + // Estimated: `17471 + m * (485 ±0) + p * (180 ±0)` + // Minimum execution time: 42_322_000 picoseconds. + Weight::from_parts(38_753_429, 17471) + // Standard Error: 78 + .saturating_add(Weight::from_parts(1_053, 0).saturating_mul(b.into())) + // Standard Error: 841 + .saturating_add(Weight::from_parts(51_720, 0).saturating_mul(m.into())) + // Standard Error: 811 + .saturating_add(Weight::from_parts(113_343, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 480).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 185).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 485).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 180).saturating_mul(p.into())) } /// Storage: Alliance Members (r:2 w:2) /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) @@ -247,13 +250,13 @@ impl WeightInfo for SubstrateWeight { fn init_members(m: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `217` - // Estimated: `12084` - // Minimum execution time: 29_313 nanoseconds. - Weight::from_parts(20_502_244, 12084) - // Standard Error: 304 - .saturating_add(Weight::from_parts(107_994, 0).saturating_mul(m.into())) - // Standard Error: 300 - .saturating_add(Weight::from_parts(92_645, 0).saturating_mul(z.into())) + // Estimated: `14064` + // Minimum execution time: 33_217_000 picoseconds. + Weight::from_parts(24_495_505, 14064) + // Standard Error: 412 + .saturating_add(Weight::from_parts(108_405, 0).saturating_mul(m.into())) + // Standard Error: 407 + .saturating_add(Weight::from_parts(95_707, 0).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -274,16 +277,16 @@ impl WeightInfo for SubstrateWeight { /// The range of component `z` is `[0, 50]`. fn disband(x: u32, y: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0 + x * (50 ±0) + y * (51 ±0) + z * (283 ±0)` - // Estimated: `32201 + x * (2587 ±0) + y * (2590 ±0) + z * (3209 ±1)` - // Minimum execution time: 232_895 nanoseconds. - Weight::from_parts(233_860_000, 32201) - // Standard Error: 19_092 - .saturating_add(Weight::from_parts(445_664, 0).saturating_mul(x.into())) - // Standard Error: 19_000 - .saturating_add(Weight::from_parts(432_571, 0).saturating_mul(y.into())) - // Standard Error: 37_965 - .saturating_add(Weight::from_parts(9_386_151, 0).saturating_mul(z.into())) + // Measured: `0 + x * (50 ±0) + y * (51 ±0) + z * (251 ±0)` + // Estimated: `35975 + x * (2587 ±0) + y * (2590 ±0) + z * (3113 ±1)` + // Minimum execution time: 278_029_000 picoseconds. + Weight::from_parts(279_353_000, 35975) + // Standard Error: 23_655 + .saturating_add(Weight::from_parts(519_330, 0).saturating_mul(x.into())) + // Standard Error: 23_541 + .saturating_add(Weight::from_parts(547_382, 0).saturating_mul(y.into())) + // Standard Error: 47_040 + .saturating_add(Weight::from_parts(10_939_685, 0).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(x.into()))) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(y.into()))) @@ -292,7 +295,7 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(z.into()))) .saturating_add(Weight::from_parts(0, 2587).saturating_mul(x.into())) .saturating_add(Weight::from_parts(0, 2590).saturating_mul(y.into())) - .saturating_add(Weight::from_parts(0, 3209).saturating_mul(z.into())) + .saturating_add(Weight::from_parts(0, 3113).saturating_mul(z.into())) } /// Storage: Alliance Rule (r:0 w:1) /// Proof: Alliance Rule (max_values: Some(1), max_size: Some(87), added: 582, mode: MaxEncodedLen) @@ -300,8 +303,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_156 nanoseconds. - Weight::from_parts(9_376_000, 0) + // Minimum execution time: 10_129_000 picoseconds. + Weight::from_parts(10_370_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Alliance Announcements (r:1 w:1) @@ -309,9 +312,9 @@ impl WeightInfo for SubstrateWeight { fn announce() -> Weight { // Proof Size summary in bytes: // Measured: `246` - // Estimated: `9197` - // Minimum execution time: 12_163 nanoseconds. - Weight::from_parts(12_397_000, 9197) + // Estimated: `10187` + // Minimum execution time: 13_601_000 picoseconds. + Weight::from_parts(13_823_000, 10187) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -319,10 +322,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Alliance Announcements (max_values: Some(1), max_size: Some(8702), added: 9197, mode: MaxEncodedLen) fn remove_announcement() -> Weight { // Proof Size summary in bytes: - // Measured: `351` - // Estimated: `9197` - // Minimum execution time: 12_778 nanoseconds. - Weight::from_parts(12_991_000, 9197) + // Measured: `319` + // Estimated: `10187` + // Minimum execution time: 14_953_000 picoseconds. + Weight::from_parts(15_239_000, 10187) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -336,10 +339,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Alliance DepositOf (max_values: None, max_size: Some(64), added: 2539, mode: MaxEncodedLen) fn join_alliance() -> Weight { // Proof Size summary in bytes: - // Measured: `562` - // Estimated: `23358` - // Minimum execution time: 40_216 nanoseconds. - Weight::from_parts(40_535_000, 23358) + // Measured: `468` + // Estimated: `26328` + // Minimum execution time: 42_947_000 picoseconds. + Weight::from_parts(43_602_000, 26328) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -349,10 +352,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Alliance UnscrupulousAccounts (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) fn nominate_ally() -> Weight { // Proof Size summary in bytes: - // Measured: `429` - // Estimated: `20755` - // Minimum execution time: 28_027 nanoseconds. - Weight::from_parts(28_392_000, 20755) + // Measured: `367` + // Estimated: `22735` + // Minimum execution time: 28_787_000 picoseconds. + Weight::from_parts(29_286_000, 22735) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -366,10 +369,10 @@ impl WeightInfo for SubstrateWeight { /// Proof Skipped: AllianceMotion Prime (max_values: Some(1), max_size: None, mode: Measured) fn elevate_ally() -> Weight { // Proof Size summary in bytes: - // Measured: `505` - // Estimated: `13382` - // Minimum execution time: 24_427 nanoseconds. - Weight::from_parts(24_952_000, 13382) + // Measured: `443` + // Estimated: `15176` + // Minimum execution time: 28_476_000 picoseconds. + Weight::from_parts(28_972_000, 15176) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -385,10 +388,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Alliance RetiringMembers (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) fn give_retirement_notice() -> Weight { // Proof Size summary in bytes: - // Measured: `505` - // Estimated: `24754` - // Minimum execution time: 33_163 nanoseconds. - Weight::from_parts(33_556_000, 24754) + // Measured: `443` + // Estimated: `26548` + // Minimum execution time: 36_773_000 picoseconds. + Weight::from_parts(38_123_000, 26548) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -402,10 +405,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn retire() -> Weight { // Proof Size summary in bytes: - // Measured: `750` - // Estimated: `13355` - // Minimum execution time: 32_980 nanoseconds. - Weight::from_parts(33_452_000, 13355) + // Measured: `687` + // Estimated: `17315` + // Minimum execution time: 37_814_000 picoseconds. + Weight::from_parts(38_353_000, 17315) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -423,10 +426,10 @@ impl WeightInfo for SubstrateWeight { /// Proof Skipped: AllianceMotion Prime (max_values: Some(1), max_size: None, mode: Measured) fn kick_member() -> Weight { // Proof Size summary in bytes: - // Measured: `801` - // Estimated: `25098` - // Minimum execution time: 54_660 nanoseconds. - Weight::from_parts(55_186_000, 25098) + // Measured: `707` + // Estimated: `28776` + // Minimum execution time: 62_194_000 picoseconds. + Weight::from_parts(63_925_000, 28776) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -439,13 +442,13 @@ impl WeightInfo for SubstrateWeight { fn add_unscrupulous_items(n: u32, l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `246` - // Estimated: `29894` - // Minimum execution time: 7_709 nanoseconds. - Weight::from_parts(7_773_000, 29894) - // Standard Error: 2_645 - .saturating_add(Weight::from_parts(1_266_755, 0).saturating_mul(n.into())) - // Standard Error: 1_036 - .saturating_add(Weight::from_parts(67_359, 0).saturating_mul(l.into())) + // Estimated: `31874` + // Minimum execution time: 8_369_000 picoseconds. + Weight::from_parts(8_462_000, 31874) + // Standard Error: 3_347 + .saturating_add(Weight::from_parts(1_567_757, 0).saturating_mul(n.into())) + // Standard Error: 1_310 + .saturating_add(Weight::from_parts(72_697, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -458,13 +461,13 @@ impl WeightInfo for SubstrateWeight { fn remove_unscrupulous_items(n: u32, l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + n * (289 ±0) + l * (100 ±0)` - // Estimated: `29894` - // Minimum execution time: 7_438 nanoseconds. - Weight::from_parts(7_570_000, 29894) - // Standard Error: 165_072 - .saturating_add(Weight::from_parts(13_026_975, 0).saturating_mul(n.into())) - // Standard Error: 64_649 - .saturating_add(Weight::from_parts(485_565, 0).saturating_mul(l.into())) + // Estimated: `31874` + // Minimum execution time: 8_309_000 picoseconds. + Weight::from_parts(8_450_000, 31874) + // Standard Error: 185_163 + .saturating_add(Weight::from_parts(16_348_419, 0).saturating_mul(n.into())) + // Standard Error: 72_518 + .saturating_add(Weight::from_parts(337_571, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -478,10 +481,10 @@ impl WeightInfo for SubstrateWeight { /// Proof Skipped: AllianceMotion Prime (max_values: Some(1), max_size: None, mode: Measured) fn abdicate_fellow_status() -> Weight { // Proof Size summary in bytes: - // Measured: `505` - // Estimated: `19068` - // Minimum execution time: 31_326 nanoseconds. - Weight::from_parts(31_768_000, 19068) + // Measured: `443` + // Estimated: `20862` + // Minimum execution time: 35_363_000 picoseconds. + Weight::from_parts(35_665_000, 20862) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -504,20 +507,20 @@ impl WeightInfo for () { /// The range of component `p` is `[1, 100]`. fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `692 + m * (32 ±0) + p * (36 ±0)` - // Estimated: `11659 + m * (132 ±0) + p * (144 ±0)` - // Minimum execution time: 28_849 nanoseconds. - Weight::from_parts(29_823_933, 11659) - // Standard Error: 74 - .saturating_add(Weight::from_parts(830, 0).saturating_mul(b.into())) - // Standard Error: 775 - .saturating_add(Weight::from_parts(22_980, 0).saturating_mul(m.into())) - // Standard Error: 765 - .saturating_add(Weight::from_parts(90_520, 0).saturating_mul(p.into())) + // Measured: `618 + m * (32 ±0) + p * (36 ±0)` + // Estimated: `15463 + m * (124 ±0) + p * (148 ±0)` + // Minimum execution time: 32_788_000 picoseconds. + Weight::from_parts(36_725_375, 15463) + // Standard Error: 138 + .saturating_add(Weight::from_parts(1_252, 0).saturating_mul(b.into())) + // Standard Error: 1_445 + .saturating_add(Weight::from_parts(9_861, 0).saturating_mul(m.into())) + // Standard Error: 1_427 + .saturating_add(Weight::from_parts(127_304, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) - .saturating_add(Weight::from_parts(0, 132).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 144).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 124).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 148).saturating_mul(p.into())) } /// Storage: Alliance Members (r:1 w:0) /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) @@ -526,12 +529,12 @@ impl WeightInfo for () { /// The range of component `m` is `[5, 100]`. fn vote(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1177 + m * (64 ±0)` - // Estimated: `9337 + m * (64 ±0)` - // Minimum execution time: 23_570 nanoseconds. - Weight::from_parts(25_473_196, 9337) - // Standard Error: 824 - .saturating_add(Weight::from_parts(54_603, 0).saturating_mul(m.into())) + // Measured: `1042 + m * (64 ±0)` + // Estimated: `11182 + m * (64 ±0)` + // Minimum execution time: 26_632_000 picoseconds. + Weight::from_parts(28_918_089, 11182) + // Standard Error: 947 + .saturating_add(Weight::from_parts(56_565, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) @@ -550,17 +553,17 @@ impl WeightInfo for () { /// The range of component `p` is `[1, 100]`. fn close_early_disapproved(m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `730 + m * (96 ±0) + p * (36 ±0)` - // Estimated: `11979 + m * (388 ±0) + p * (148 ±0)` - // Minimum execution time: 35_373 nanoseconds. - Weight::from_parts(32_763_656, 11979) - // Standard Error: 2_041 - .saturating_add(Weight::from_parts(52_915, 0).saturating_mul(m.into())) - // Standard Error: 1_991 - .saturating_add(Weight::from_parts(78_594, 0).saturating_mul(p.into())) + // Measured: `622 + m * (96 ±0) + p * (37 ±0)` + // Estimated: `15551 + m * (384 ±0) + p * (148 ±0)` + // Minimum execution time: 40_937_000 picoseconds. + Weight::from_parts(39_361_123, 15551) + // Standard Error: 1_609 + .saturating_add(Weight::from_parts(43_225, 0).saturating_mul(m.into())) + // Standard Error: 1_569 + .saturating_add(Weight::from_parts(112_935, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 388).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 384).saturating_mul(m.into())) .saturating_add(Weight::from_parts(0, 148).saturating_mul(p.into())) } /// Storage: Alliance Members (r:1 w:0) @@ -578,20 +581,20 @@ impl WeightInfo for () { /// The range of component `p` is `[1, 100]`. fn close_early_approved(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1139 + m * (96 ±0) + p * (41 ±0)` - // Estimated: `15730 + m * (388 ±0) + p * (164 ±0)` - // Minimum execution time: 44_590 nanoseconds. - Weight::from_parts(43_367_913, 15730) - // Standard Error: 71 - .saturating_add(Weight::from_parts(819, 0).saturating_mul(b.into())) - // Standard Error: 751 - .saturating_add(Weight::from_parts(39_124, 0).saturating_mul(m.into())) - // Standard Error: 732 - .saturating_add(Weight::from_parts(90_469, 0).saturating_mul(p.into())) + // Measured: `903 + m * (96 ±0) + p * (41 ±0)` + // Estimated: `20072 + m * (392 ±0) + p * (160 ±0)` + // Minimum execution time: 51_569_000 picoseconds. + Weight::from_parts(50_722_448, 20072) + // Standard Error: 120 + .saturating_add(Weight::from_parts(474, 0).saturating_mul(b.into())) + // Standard Error: 1_271 + .saturating_add(Weight::from_parts(48_855, 0).saturating_mul(m.into())) + // Standard Error: 1_239 + .saturating_add(Weight::from_parts(139_022, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 388).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 164).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 392).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 160).saturating_mul(p.into())) } /// Storage: Alliance Members (r:1 w:0) /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) @@ -609,17 +612,17 @@ impl WeightInfo for () { /// The range of component `p` is `[1, 100]`. fn close_disapproved(m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `730 + m * (96 ±0) + p * (36 ±0)` - // Estimated: `13201 + m * (485 ±0) + p * (185 ±0)` - // Minimum execution time: 36_796 nanoseconds. - Weight::from_parts(34_578_765, 13201) - // Standard Error: 1_037 - .saturating_add(Weight::from_parts(43_508, 0).saturating_mul(m.into())) - // Standard Error: 1_024 - .saturating_add(Weight::from_parts(77_084, 0).saturating_mul(p.into())) + // Measured: `622 + m * (96 ±0) + p * (37 ±0)` + // Estimated: `17666 + m * (480 ±0) + p * (185 ±0)` + // Minimum execution time: 42_084_000 picoseconds. + Weight::from_parts(39_907_823, 17666) + // Standard Error: 899 + .saturating_add(Weight::from_parts(46_642, 0).saturating_mul(m.into())) + // Standard Error: 888 + .saturating_add(Weight::from_parts(114_161, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 485).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 480).saturating_mul(m.into())) .saturating_add(Weight::from_parts(0, 185).saturating_mul(p.into())) } /// Storage: Alliance Members (r:1 w:0) @@ -639,20 +642,20 @@ impl WeightInfo for () { /// The range of component `p` is `[1, 100]`. fn close_approved(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `757 + m * (96 ±0) + p * (36 ±0)` - // Estimated: `13146 + m * (480 ±0) + p * (185 ±0)` - // Minimum execution time: 36_897 nanoseconds. - Weight::from_parts(34_169_666, 13146) - // Standard Error: 47 - .saturating_add(Weight::from_parts(972, 0).saturating_mul(b.into())) - // Standard Error: 510 - .saturating_add(Weight::from_parts(38_084, 0).saturating_mul(m.into())) - // Standard Error: 492 - .saturating_add(Weight::from_parts(78_576, 0).saturating_mul(p.into())) + // Measured: `591 + m * (96 ±0) + p * (36 ±0)` + // Estimated: `17471 + m * (485 ±0) + p * (180 ±0)` + // Minimum execution time: 42_322_000 picoseconds. + Weight::from_parts(38_753_429, 17471) + // Standard Error: 78 + .saturating_add(Weight::from_parts(1_053, 0).saturating_mul(b.into())) + // Standard Error: 841 + .saturating_add(Weight::from_parts(51_720, 0).saturating_mul(m.into())) + // Standard Error: 811 + .saturating_add(Weight::from_parts(113_343, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 480).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 185).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 485).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 180).saturating_mul(p.into())) } /// Storage: Alliance Members (r:2 w:2) /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) @@ -663,13 +666,13 @@ impl WeightInfo for () { fn init_members(m: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `217` - // Estimated: `12084` - // Minimum execution time: 29_313 nanoseconds. - Weight::from_parts(20_502_244, 12084) - // Standard Error: 304 - .saturating_add(Weight::from_parts(107_994, 0).saturating_mul(m.into())) - // Standard Error: 300 - .saturating_add(Weight::from_parts(92_645, 0).saturating_mul(z.into())) + // Estimated: `14064` + // Minimum execution time: 33_217_000 picoseconds. + Weight::from_parts(24_495_505, 14064) + // Standard Error: 412 + .saturating_add(Weight::from_parts(108_405, 0).saturating_mul(m.into())) + // Standard Error: 407 + .saturating_add(Weight::from_parts(95_707, 0).saturating_mul(z.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -690,16 +693,16 @@ impl WeightInfo for () { /// The range of component `z` is `[0, 50]`. fn disband(x: u32, y: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0 + x * (50 ±0) + y * (51 ±0) + z * (283 ±0)` - // Estimated: `32201 + x * (2587 ±0) + y * (2590 ±0) + z * (3209 ±1)` - // Minimum execution time: 232_895 nanoseconds. - Weight::from_parts(233_860_000, 32201) - // Standard Error: 19_092 - .saturating_add(Weight::from_parts(445_664, 0).saturating_mul(x.into())) - // Standard Error: 19_000 - .saturating_add(Weight::from_parts(432_571, 0).saturating_mul(y.into())) - // Standard Error: 37_965 - .saturating_add(Weight::from_parts(9_386_151, 0).saturating_mul(z.into())) + // Measured: `0 + x * (50 ±0) + y * (51 ±0) + z * (251 ±0)` + // Estimated: `35975 + x * (2587 ±0) + y * (2590 ±0) + z * (3113 ±1)` + // Minimum execution time: 278_029_000 picoseconds. + Weight::from_parts(279_353_000, 35975) + // Standard Error: 23_655 + .saturating_add(Weight::from_parts(519_330, 0).saturating_mul(x.into())) + // Standard Error: 23_541 + .saturating_add(Weight::from_parts(547_382, 0).saturating_mul(y.into())) + // Standard Error: 47_040 + .saturating_add(Weight::from_parts(10_939_685, 0).saturating_mul(z.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(x.into()))) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(y.into()))) @@ -708,7 +711,7 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().writes((2_u64).saturating_mul(z.into()))) .saturating_add(Weight::from_parts(0, 2587).saturating_mul(x.into())) .saturating_add(Weight::from_parts(0, 2590).saturating_mul(y.into())) - .saturating_add(Weight::from_parts(0, 3209).saturating_mul(z.into())) + .saturating_add(Weight::from_parts(0, 3113).saturating_mul(z.into())) } /// Storage: Alliance Rule (r:0 w:1) /// Proof: Alliance Rule (max_values: Some(1), max_size: Some(87), added: 582, mode: MaxEncodedLen) @@ -716,8 +719,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_156 nanoseconds. - Weight::from_parts(9_376_000, 0) + // Minimum execution time: 10_129_000 picoseconds. + Weight::from_parts(10_370_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Alliance Announcements (r:1 w:1) @@ -725,9 +728,9 @@ impl WeightInfo for () { fn announce() -> Weight { // Proof Size summary in bytes: // Measured: `246` - // Estimated: `9197` - // Minimum execution time: 12_163 nanoseconds. - Weight::from_parts(12_397_000, 9197) + // Estimated: `10187` + // Minimum execution time: 13_601_000 picoseconds. + Weight::from_parts(13_823_000, 10187) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -735,10 +738,10 @@ impl WeightInfo for () { /// Proof: Alliance Announcements (max_values: Some(1), max_size: Some(8702), added: 9197, mode: MaxEncodedLen) fn remove_announcement() -> Weight { // Proof Size summary in bytes: - // Measured: `351` - // Estimated: `9197` - // Minimum execution time: 12_778 nanoseconds. - Weight::from_parts(12_991_000, 9197) + // Measured: `319` + // Estimated: `10187` + // Minimum execution time: 14_953_000 picoseconds. + Weight::from_parts(15_239_000, 10187) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -752,10 +755,10 @@ impl WeightInfo for () { /// Proof: Alliance DepositOf (max_values: None, max_size: Some(64), added: 2539, mode: MaxEncodedLen) fn join_alliance() -> Weight { // Proof Size summary in bytes: - // Measured: `562` - // Estimated: `23358` - // Minimum execution time: 40_216 nanoseconds. - Weight::from_parts(40_535_000, 23358) + // Measured: `468` + // Estimated: `26328` + // Minimum execution time: 42_947_000 picoseconds. + Weight::from_parts(43_602_000, 26328) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -765,10 +768,10 @@ impl WeightInfo for () { /// Proof: Alliance UnscrupulousAccounts (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) fn nominate_ally() -> Weight { // Proof Size summary in bytes: - // Measured: `429` - // Estimated: `20755` - // Minimum execution time: 28_027 nanoseconds. - Weight::from_parts(28_392_000, 20755) + // Measured: `367` + // Estimated: `22735` + // Minimum execution time: 28_787_000 picoseconds. + Weight::from_parts(29_286_000, 22735) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -782,10 +785,10 @@ impl WeightInfo for () { /// Proof Skipped: AllianceMotion Prime (max_values: Some(1), max_size: None, mode: Measured) fn elevate_ally() -> Weight { // Proof Size summary in bytes: - // Measured: `505` - // Estimated: `13382` - // Minimum execution time: 24_427 nanoseconds. - Weight::from_parts(24_952_000, 13382) + // Measured: `443` + // Estimated: `15176` + // Minimum execution time: 28_476_000 picoseconds. + Weight::from_parts(28_972_000, 15176) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -801,10 +804,10 @@ impl WeightInfo for () { /// Proof: Alliance RetiringMembers (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) fn give_retirement_notice() -> Weight { // Proof Size summary in bytes: - // Measured: `505` - // Estimated: `24754` - // Minimum execution time: 33_163 nanoseconds. - Weight::from_parts(33_556_000, 24754) + // Measured: `443` + // Estimated: `26548` + // Minimum execution time: 36_773_000 picoseconds. + Weight::from_parts(38_123_000, 26548) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -818,10 +821,10 @@ impl WeightInfo for () { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn retire() -> Weight { // Proof Size summary in bytes: - // Measured: `750` - // Estimated: `13355` - // Minimum execution time: 32_980 nanoseconds. - Weight::from_parts(33_452_000, 13355) + // Measured: `687` + // Estimated: `17315` + // Minimum execution time: 37_814_000 picoseconds. + Weight::from_parts(38_353_000, 17315) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -839,10 +842,10 @@ impl WeightInfo for () { /// Proof Skipped: AllianceMotion Prime (max_values: Some(1), max_size: None, mode: Measured) fn kick_member() -> Weight { // Proof Size summary in bytes: - // Measured: `801` - // Estimated: `25098` - // Minimum execution time: 54_660 nanoseconds. - Weight::from_parts(55_186_000, 25098) + // Measured: `707` + // Estimated: `28776` + // Minimum execution time: 62_194_000 picoseconds. + Weight::from_parts(63_925_000, 28776) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -855,13 +858,13 @@ impl WeightInfo for () { fn add_unscrupulous_items(n: u32, l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `246` - // Estimated: `29894` - // Minimum execution time: 7_709 nanoseconds. - Weight::from_parts(7_773_000, 29894) - // Standard Error: 2_645 - .saturating_add(Weight::from_parts(1_266_755, 0).saturating_mul(n.into())) - // Standard Error: 1_036 - .saturating_add(Weight::from_parts(67_359, 0).saturating_mul(l.into())) + // Estimated: `31874` + // Minimum execution time: 8_369_000 picoseconds. + Weight::from_parts(8_462_000, 31874) + // Standard Error: 3_347 + .saturating_add(Weight::from_parts(1_567_757, 0).saturating_mul(n.into())) + // Standard Error: 1_310 + .saturating_add(Weight::from_parts(72_697, 0).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -874,13 +877,13 @@ impl WeightInfo for () { fn remove_unscrupulous_items(n: u32, l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + n * (289 ±0) + l * (100 ±0)` - // Estimated: `29894` - // Minimum execution time: 7_438 nanoseconds. - Weight::from_parts(7_570_000, 29894) - // Standard Error: 165_072 - .saturating_add(Weight::from_parts(13_026_975, 0).saturating_mul(n.into())) - // Standard Error: 64_649 - .saturating_add(Weight::from_parts(485_565, 0).saturating_mul(l.into())) + // Estimated: `31874` + // Minimum execution time: 8_309_000 picoseconds. + Weight::from_parts(8_450_000, 31874) + // Standard Error: 185_163 + .saturating_add(Weight::from_parts(16_348_419, 0).saturating_mul(n.into())) + // Standard Error: 72_518 + .saturating_add(Weight::from_parts(337_571, 0).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -894,10 +897,10 @@ impl WeightInfo for () { /// Proof Skipped: AllianceMotion Prime (max_values: Some(1), max_size: None, mode: Measured) fn abdicate_fellow_status() -> Weight { // Proof Size summary in bytes: - // Measured: `505` - // Estimated: `19068` - // Minimum execution time: 31_326 nanoseconds. - Weight::from_parts(31_768_000, 19068) + // Measured: `443` + // Estimated: `20862` + // Minimum execution time: 35_363_000 picoseconds. + Weight::from_parts(35_665_000, 20862) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } diff --git a/frame/assets/src/weights.rs b/frame/assets/src/weights.rs index b9c3ab21d8a33..0d6c41b458db0 100644 --- a/frame/assets/src/weights.rs +++ b/frame/assets/src/weights.rs @@ -18,26 +18,28 @@ //! Autogenerated weights for pallet_assets //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-03, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/production/substrate +// ./target/production/substrate // benchmark // pallet +// --chain=dev // --steps=50 // --repeat=20 +// --pallet=pallet_assets +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --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 -// --header=./HEADER-APACHE2 // --output=./frame/assets/src/weights.rs +// --header=./HEADER-APACHE2 // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -87,10 +89,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn create() -> Weight { // Proof Size summary in bytes: - // Measured: `325` + // Measured: `293` // Estimated: `7268` - // Minimum execution time: 28_265_000 picoseconds. - Weight::from_parts(28_764_000, 7268) + // Minimum execution time: 27_756_000 picoseconds. + Weight::from_parts(28_637_000, 7268) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -100,8 +102,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `153` // Estimated: `3675` - // Minimum execution time: 15_125_000 picoseconds. - Weight::from_parts(15_468_000, 3675) + // Minimum execution time: 15_402_000 picoseconds. + Weight::from_parts(15_803_000, 3675) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -109,10 +111,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) fn start_destroy() -> Weight { // Proof Size summary in bytes: - // Measured: `417` + // Measured: `385` // Estimated: `3675` - // Minimum execution time: 15_368_000 picoseconds. - Weight::from_parts(15_625_000, 3675) + // Minimum execution time: 16_027_000 picoseconds. + Weight::from_parts(16_372_000, 3675) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -125,12 +127,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `c` is `[0, 1000]`. fn destroy_accounts(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `25 + c * (240 ±0)` + // Measured: `0 + c * (208 ±0)` // Estimated: `8232 + c * (5180 ±0)` - // Minimum execution time: 20_816_000 picoseconds. - Weight::from_parts(21_045_000, 8232) - // Standard Error: 7_118 - .saturating_add(Weight::from_parts(12_723_454, 0).saturating_mul(c.into())) + // Minimum execution time: 20_667_000 picoseconds. + Weight::from_parts(20_930_000, 8232) + // Standard Error: 7_226 + .saturating_add(Weight::from_parts(12_759_091, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(c.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) @@ -144,12 +146,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `a` is `[0, 1000]`. fn destroy_approvals(a: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `554 + a * (86 ±0)` + // Measured: `522 + a * (86 ±0)` // Estimated: `7288 + a * (2623 ±0)` - // Minimum execution time: 20_923_000 picoseconds. - Weight::from_parts(21_229_000, 7288) - // Standard Error: 7_215 - .saturating_add(Weight::from_parts(12_915_292, 0).saturating_mul(a.into())) + // Minimum execution time: 20_798_000 picoseconds. + Weight::from_parts(21_129_000, 7288) + // Standard Error: 7_484 + .saturating_add(Weight::from_parts(12_761_996, 0).saturating_mul(a.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(a.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) @@ -162,10 +164,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) fn finish_destroy() -> Weight { // Proof Size summary in bytes: - // Measured: `383` + // Measured: `351` // Estimated: `7280` - // Minimum execution time: 15_764_000 picoseconds. - Weight::from_parts(16_245_000, 7280) + // Minimum execution time: 15_870_000 picoseconds. + Weight::from_parts(16_280_000, 7280) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -175,10 +177,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) fn mint() -> Weight { // Proof Size summary in bytes: - // Measured: `383` + // Measured: `351` // Estimated: `7242` - // Minimum execution time: 28_814_000 picoseconds. - Weight::from_parts(29_407_000, 7242) + // Minimum execution time: 28_556_000 picoseconds. + Weight::from_parts(28_972_000, 7242) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -188,10 +190,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) fn burn() -> Weight { // Proof Size summary in bytes: - // Measured: `491` + // Measured: `459` // Estimated: `7242` - // Minimum execution time: 34_784_000 picoseconds. - Weight::from_parts(35_402_000, 7242) + // Minimum execution time: 35_379_000 picoseconds. + Weight::from_parts(35_826_000, 7242) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -203,10 +205,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `530` + // Measured: `498` // Estimated: `13412` - // Minimum execution time: 49_110_000 picoseconds. - Weight::from_parts(50_483_000, 13412) + // Minimum execution time: 48_837_000 picoseconds. + Weight::from_parts(49_305_000, 13412) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -218,10 +220,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer_keep_alive() -> Weight { // Proof Size summary in bytes: - // Measured: `530` + // Measured: `498` // Estimated: `13412` - // Minimum execution time: 43_585_000 picoseconds. - Weight::from_parts(44_207_000, 13412) + // Minimum execution time: 43_603_000 picoseconds. + Weight::from_parts(44_142_000, 13412) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -233,10 +235,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn force_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `530` + // Measured: `498` // Estimated: `13412` - // Minimum execution time: 49_238_000 picoseconds. - Weight::from_parts(77_664_000, 13412) + // Minimum execution time: 49_691_000 picoseconds. + Weight::from_parts(50_402_000, 13412) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -246,10 +248,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) fn freeze() -> Weight { // Proof Size summary in bytes: - // Measured: `491` + // Measured: `459` // Estimated: `7242` - // Minimum execution time: 19_198_000 picoseconds. - Weight::from_parts(19_585_000, 7242) + // Minimum execution time: 19_600_000 picoseconds. + Weight::from_parts(20_435_000, 7242) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -259,10 +261,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) fn thaw() -> Weight { // Proof Size summary in bytes: - // Measured: `491` + // Measured: `459` // Estimated: `7242` - // Minimum execution time: 19_659_000 picoseconds. - Weight::from_parts(20_079_000, 7242) + // Minimum execution time: 19_396_000 picoseconds. + Weight::from_parts(19_745_000, 7242) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -270,10 +272,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) fn freeze_asset() -> Weight { // Proof Size summary in bytes: - // Measured: `417` + // Measured: `385` // Estimated: `3675` - // Minimum execution time: 15_035_000 picoseconds. - Weight::from_parts(15_594_000, 3675) + // Minimum execution time: 15_503_000 picoseconds. + Weight::from_parts(15_788_000, 3675) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -281,10 +283,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) fn thaw_asset() -> Weight { // Proof Size summary in bytes: - // Measured: `417` + // Measured: `385` // Estimated: `3675` - // Minimum execution time: 15_073_000 picoseconds. - Weight::from_parts(15_862_000, 3675) + // Minimum execution time: 15_874_000 picoseconds. + Weight::from_parts(16_190_000, 3675) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -294,10 +296,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) fn transfer_ownership() -> Weight { // Proof Size summary in bytes: - // Measured: `383` + // Measured: `351` // Estimated: `7280` - // Minimum execution time: 17_343_000 picoseconds. - Weight::from_parts(17_656_000, 7280) + // Minimum execution time: 17_067_000 picoseconds. + Weight::from_parts(17_355_000, 7280) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -305,10 +307,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) fn set_team() -> Weight { // Proof Size summary in bytes: - // Measured: `383` + // Measured: `351` // Estimated: `3675` - // Minimum execution time: 15_902_000 picoseconds. - Weight::from_parts(16_439_000, 3675) + // Minimum execution time: 16_155_000 picoseconds. + Weight::from_parts(16_442_000, 3675) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -320,10 +322,10 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[0, 50]`. fn set_metadata(_n: u32, _s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `383` + // Measured: `351` // Estimated: `7280` - // Minimum execution time: 27_222_000 picoseconds. - Weight::from_parts(29_151_657, 7280) + // Minimum execution time: 27_270_000 picoseconds. + Weight::from_parts(28_634_060, 7280) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -333,10 +335,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) fn clear_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `579` + // Measured: `515` // Estimated: `7280` - // Minimum execution time: 27_976_000 picoseconds. - Weight::from_parts(28_289_000, 7280) + // Minimum execution time: 27_469_000 picoseconds. + Weight::from_parts(27_911_000, 7280) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -350,10 +352,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `190` // Estimated: `7280` - // Minimum execution time: 16_162_000 picoseconds. - Weight::from_parts(17_137_043, 7280) - // Standard Error: 982 - .saturating_add(Weight::from_parts(4_180, 0).saturating_mul(s.into())) + // Minimum execution time: 16_008_000 picoseconds. + Weight::from_parts(17_007_654, 7280) + // Standard Error: 527 + .saturating_add(Weight::from_parts(4_158, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -363,10 +365,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) fn force_clear_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `579` + // Measured: `515` // Estimated: `7280` - // Minimum execution time: 27_219_000 picoseconds. - Weight::from_parts(27_931_000, 7280) + // Minimum execution time: 27_118_000 picoseconds. + Weight::from_parts(27_776_000, 7280) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -374,10 +376,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) fn force_asset_status() -> Weight { // Proof Size summary in bytes: - // Measured: `383` + // Measured: `351` // Estimated: `3675` - // Minimum execution time: 15_313_000 picoseconds. - Weight::from_parts(15_775_000, 3675) + // Minimum execution time: 14_776_000 picoseconds. + Weight::from_parts(15_281_000, 3675) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -387,10 +389,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Assets Approvals (max_values: None, max_size: Some(148), added: 2623, mode: MaxEncodedLen) fn approve_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `417` + // Measured: `385` // Estimated: `7288` - // Minimum execution time: 31_865_000 picoseconds. - Weight::from_parts(32_316_000, 7288) + // Minimum execution time: 31_324_000 picoseconds. + Weight::from_parts(32_161_000, 7288) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -404,10 +406,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer_approved() -> Weight { // Proof Size summary in bytes: - // Measured: `700` + // Measured: `668` // Estimated: `17025` - // Minimum execution time: 67_203_000 picoseconds. - Weight::from_parts(109_742_000, 17025) + // Minimum execution time: 63_750_000 picoseconds. + Weight::from_parts(64_828_000, 17025) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -417,10 +419,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Assets Approvals (max_values: None, max_size: Some(148), added: 2623, mode: MaxEncodedLen) fn cancel_approval() -> Weight { // Proof Size summary in bytes: - // Measured: `587` + // Measured: `555` // Estimated: `7288` - // Minimum execution time: 33_430_000 picoseconds. - Weight::from_parts(33_824_000, 7288) + // Minimum execution time: 32_698_000 picoseconds. + Weight::from_parts(33_309_000, 7288) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -430,10 +432,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Assets Approvals (max_values: None, max_size: Some(148), added: 2623, mode: MaxEncodedLen) fn force_cancel_approval() -> Weight { // Proof Size summary in bytes: - // Measured: `587` + // Measured: `555` // Estimated: `7288` - // Minimum execution time: 33_596_000 picoseconds. - Weight::from_parts(34_226_000, 7288) + // Minimum execution time: 33_147_000 picoseconds. + Weight::from_parts(33_620_000, 7288) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -441,10 +443,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) fn set_min_balance() -> Weight { // Proof Size summary in bytes: - // Measured: `383` + // Measured: `351` // Estimated: `3675` - // Minimum execution time: 16_367_000 picoseconds. - Weight::from_parts(16_703_000, 3675) + // Minimum execution time: 15_910_000 picoseconds. + Weight::from_parts(16_315_000, 3675) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -458,10 +460,10 @@ impl WeightInfo for () { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn create() -> Weight { // Proof Size summary in bytes: - // Measured: `325` + // Measured: `293` // Estimated: `7268` - // Minimum execution time: 28_265_000 picoseconds. - Weight::from_parts(28_764_000, 7268) + // Minimum execution time: 27_756_000 picoseconds. + Weight::from_parts(28_637_000, 7268) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -471,8 +473,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `153` // Estimated: `3675` - // Minimum execution time: 15_125_000 picoseconds. - Weight::from_parts(15_468_000, 3675) + // Minimum execution time: 15_402_000 picoseconds. + Weight::from_parts(15_803_000, 3675) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -480,10 +482,10 @@ impl WeightInfo for () { /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) fn start_destroy() -> Weight { // Proof Size summary in bytes: - // Measured: `417` + // Measured: `385` // Estimated: `3675` - // Minimum execution time: 15_368_000 picoseconds. - Weight::from_parts(15_625_000, 3675) + // Minimum execution time: 16_027_000 picoseconds. + Weight::from_parts(16_372_000, 3675) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -496,12 +498,12 @@ impl WeightInfo for () { /// The range of component `c` is `[0, 1000]`. fn destroy_accounts(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `25 + c * (240 ±0)` + // Measured: `0 + c * (208 ±0)` // Estimated: `8232 + c * (5180 ±0)` - // Minimum execution time: 20_816_000 picoseconds. - Weight::from_parts(21_045_000, 8232) - // Standard Error: 7_118 - .saturating_add(Weight::from_parts(12_723_454, 0).saturating_mul(c.into())) + // Minimum execution time: 20_667_000 picoseconds. + Weight::from_parts(20_930_000, 8232) + // Standard Error: 7_226 + .saturating_add(Weight::from_parts(12_759_091, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(c.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) @@ -515,12 +517,12 @@ impl WeightInfo for () { /// The range of component `a` is `[0, 1000]`. fn destroy_approvals(a: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `554 + a * (86 ±0)` + // Measured: `522 + a * (86 ±0)` // Estimated: `7288 + a * (2623 ±0)` - // Minimum execution time: 20_923_000 picoseconds. - Weight::from_parts(21_229_000, 7288) - // Standard Error: 7_215 - .saturating_add(Weight::from_parts(12_915_292, 0).saturating_mul(a.into())) + // Minimum execution time: 20_798_000 picoseconds. + Weight::from_parts(21_129_000, 7288) + // Standard Error: 7_484 + .saturating_add(Weight::from_parts(12_761_996, 0).saturating_mul(a.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(a.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) @@ -533,10 +535,10 @@ impl WeightInfo for () { /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) fn finish_destroy() -> Weight { // Proof Size summary in bytes: - // Measured: `383` + // Measured: `351` // Estimated: `7280` - // Minimum execution time: 15_764_000 picoseconds. - Weight::from_parts(16_245_000, 7280) + // Minimum execution time: 15_870_000 picoseconds. + Weight::from_parts(16_280_000, 7280) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -546,10 +548,10 @@ impl WeightInfo for () { /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) fn mint() -> Weight { // Proof Size summary in bytes: - // Measured: `383` + // Measured: `351` // Estimated: `7242` - // Minimum execution time: 28_814_000 picoseconds. - Weight::from_parts(29_407_000, 7242) + // Minimum execution time: 28_556_000 picoseconds. + Weight::from_parts(28_972_000, 7242) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -559,10 +561,10 @@ impl WeightInfo for () { /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) fn burn() -> Weight { // Proof Size summary in bytes: - // Measured: `491` + // Measured: `459` // Estimated: `7242` - // Minimum execution time: 34_784_000 picoseconds. - Weight::from_parts(35_402_000, 7242) + // Minimum execution time: 35_379_000 picoseconds. + Weight::from_parts(35_826_000, 7242) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -574,10 +576,10 @@ impl WeightInfo for () { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `530` + // Measured: `498` // Estimated: `13412` - // Minimum execution time: 49_110_000 picoseconds. - Weight::from_parts(50_483_000, 13412) + // Minimum execution time: 48_837_000 picoseconds. + Weight::from_parts(49_305_000, 13412) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -589,10 +591,10 @@ impl WeightInfo for () { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer_keep_alive() -> Weight { // Proof Size summary in bytes: - // Measured: `530` + // Measured: `498` // Estimated: `13412` - // Minimum execution time: 43_585_000 picoseconds. - Weight::from_parts(44_207_000, 13412) + // Minimum execution time: 43_603_000 picoseconds. + Weight::from_parts(44_142_000, 13412) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -604,10 +606,10 @@ impl WeightInfo for () { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn force_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `530` + // Measured: `498` // Estimated: `13412` - // Minimum execution time: 49_238_000 picoseconds. - Weight::from_parts(77_664_000, 13412) + // Minimum execution time: 49_691_000 picoseconds. + Weight::from_parts(50_402_000, 13412) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -617,10 +619,10 @@ impl WeightInfo for () { /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) fn freeze() -> Weight { // Proof Size summary in bytes: - // Measured: `491` + // Measured: `459` // Estimated: `7242` - // Minimum execution time: 19_198_000 picoseconds. - Weight::from_parts(19_585_000, 7242) + // Minimum execution time: 19_600_000 picoseconds. + Weight::from_parts(20_435_000, 7242) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -630,10 +632,10 @@ impl WeightInfo for () { /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) fn thaw() -> Weight { // Proof Size summary in bytes: - // Measured: `491` + // Measured: `459` // Estimated: `7242` - // Minimum execution time: 19_659_000 picoseconds. - Weight::from_parts(20_079_000, 7242) + // Minimum execution time: 19_396_000 picoseconds. + Weight::from_parts(19_745_000, 7242) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -641,10 +643,10 @@ impl WeightInfo for () { /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) fn freeze_asset() -> Weight { // Proof Size summary in bytes: - // Measured: `417` + // Measured: `385` // Estimated: `3675` - // Minimum execution time: 15_035_000 picoseconds. - Weight::from_parts(15_594_000, 3675) + // Minimum execution time: 15_503_000 picoseconds. + Weight::from_parts(15_788_000, 3675) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -652,10 +654,10 @@ impl WeightInfo for () { /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) fn thaw_asset() -> Weight { // Proof Size summary in bytes: - // Measured: `417` + // Measured: `385` // Estimated: `3675` - // Minimum execution time: 15_073_000 picoseconds. - Weight::from_parts(15_862_000, 3675) + // Minimum execution time: 15_874_000 picoseconds. + Weight::from_parts(16_190_000, 3675) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -665,10 +667,10 @@ impl WeightInfo for () { /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) fn transfer_ownership() -> Weight { // Proof Size summary in bytes: - // Measured: `383` + // Measured: `351` // Estimated: `7280` - // Minimum execution time: 17_343_000 picoseconds. - Weight::from_parts(17_656_000, 7280) + // Minimum execution time: 17_067_000 picoseconds. + Weight::from_parts(17_355_000, 7280) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -676,10 +678,10 @@ impl WeightInfo for () { /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) fn set_team() -> Weight { // Proof Size summary in bytes: - // Measured: `383` + // Measured: `351` // Estimated: `3675` - // Minimum execution time: 15_902_000 picoseconds. - Weight::from_parts(16_439_000, 3675) + // Minimum execution time: 16_155_000 picoseconds. + Weight::from_parts(16_442_000, 3675) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -691,10 +693,10 @@ impl WeightInfo for () { /// The range of component `s` is `[0, 50]`. fn set_metadata(_n: u32, _s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `383` + // Measured: `351` // Estimated: `7280` - // Minimum execution time: 27_222_000 picoseconds. - Weight::from_parts(29_151_657, 7280) + // Minimum execution time: 27_270_000 picoseconds. + Weight::from_parts(28_634_060, 7280) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -704,10 +706,10 @@ impl WeightInfo for () { /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) fn clear_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `579` + // Measured: `515` // Estimated: `7280` - // Minimum execution time: 27_976_000 picoseconds. - Weight::from_parts(28_289_000, 7280) + // Minimum execution time: 27_469_000 picoseconds. + Weight::from_parts(27_911_000, 7280) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -721,10 +723,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `190` // Estimated: `7280` - // Minimum execution time: 16_162_000 picoseconds. - Weight::from_parts(17_137_043, 7280) - // Standard Error: 982 - .saturating_add(Weight::from_parts(4_180, 0).saturating_mul(s.into())) + // Minimum execution time: 16_008_000 picoseconds. + Weight::from_parts(17_007_654, 7280) + // Standard Error: 527 + .saturating_add(Weight::from_parts(4_158, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -734,10 +736,10 @@ impl WeightInfo for () { /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) fn force_clear_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `579` + // Measured: `515` // Estimated: `7280` - // Minimum execution time: 27_219_000 picoseconds. - Weight::from_parts(27_931_000, 7280) + // Minimum execution time: 27_118_000 picoseconds. + Weight::from_parts(27_776_000, 7280) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -745,10 +747,10 @@ impl WeightInfo for () { /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) fn force_asset_status() -> Weight { // Proof Size summary in bytes: - // Measured: `383` + // Measured: `351` // Estimated: `3675` - // Minimum execution time: 15_313_000 picoseconds. - Weight::from_parts(15_775_000, 3675) + // Minimum execution time: 14_776_000 picoseconds. + Weight::from_parts(15_281_000, 3675) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -758,10 +760,10 @@ impl WeightInfo for () { /// Proof: Assets Approvals (max_values: None, max_size: Some(148), added: 2623, mode: MaxEncodedLen) fn approve_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `417` + // Measured: `385` // Estimated: `7288` - // Minimum execution time: 31_865_000 picoseconds. - Weight::from_parts(32_316_000, 7288) + // Minimum execution time: 31_324_000 picoseconds. + Weight::from_parts(32_161_000, 7288) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -775,10 +777,10 @@ impl WeightInfo for () { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer_approved() -> Weight { // Proof Size summary in bytes: - // Measured: `700` + // Measured: `668` // Estimated: `17025` - // Minimum execution time: 67_203_000 picoseconds. - Weight::from_parts(109_742_000, 17025) + // Minimum execution time: 63_750_000 picoseconds. + Weight::from_parts(64_828_000, 17025) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -788,10 +790,10 @@ impl WeightInfo for () { /// Proof: Assets Approvals (max_values: None, max_size: Some(148), added: 2623, mode: MaxEncodedLen) fn cancel_approval() -> Weight { // Proof Size summary in bytes: - // Measured: `587` + // Measured: `555` // Estimated: `7288` - // Minimum execution time: 33_430_000 picoseconds. - Weight::from_parts(33_824_000, 7288) + // Minimum execution time: 32_698_000 picoseconds. + Weight::from_parts(33_309_000, 7288) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -801,10 +803,10 @@ impl WeightInfo for () { /// Proof: Assets Approvals (max_values: None, max_size: Some(148), added: 2623, mode: MaxEncodedLen) fn force_cancel_approval() -> Weight { // Proof Size summary in bytes: - // Measured: `587` + // Measured: `555` // Estimated: `7288` - // Minimum execution time: 33_596_000 picoseconds. - Weight::from_parts(34_226_000, 7288) + // Minimum execution time: 33_147_000 picoseconds. + Weight::from_parts(33_620_000, 7288) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -812,10 +814,10 @@ impl WeightInfo for () { /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) fn set_min_balance() -> Weight { // Proof Size summary in bytes: - // Measured: `383` + // Measured: `351` // Estimated: `3675` - // Minimum execution time: 16_367_000 picoseconds. - Weight::from_parts(16_703_000, 3675) + // Minimum execution time: 15_910_000 picoseconds. + Weight::from_parts(16_315_000, 3675) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/frame/bags-list/src/weights.rs b/frame/bags-list/src/weights.rs index 65d27c5aea4bb..30efe1ef0cb38 100644 --- a/frame/bags-list/src/weights.rs +++ b/frame/bags-list/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_bags_list //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,6 +31,9 @@ // --steps=50 // --repeat=20 // --pallet=pallet_bags_list +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -66,10 +69,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) fn rebag_non_terminal() -> Weight { // Proof Size summary in bytes: - // Measured: `1916` - // Estimated: `19186` - // Minimum execution time: 54_348 nanoseconds. - Weight::from_parts(55_024_000, 19186) + // Measured: `1724` + // Estimated: `23146` + // Minimum execution time: 63_526_000 picoseconds. + Weight::from_parts(64_125_000, 23146) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -83,10 +86,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) fn rebag_terminal() -> Weight { // Proof Size summary in bytes: - // Measured: `1810` - // Estimated: `19114` - // Minimum execution time: 53_306 nanoseconds. - Weight::from_parts(54_263_000, 19114) + // Measured: `1618` + // Estimated: `23074` + // Minimum execution time: 62_404_000 picoseconds. + Weight::from_parts(63_178_000, 23074) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -102,10 +105,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) fn put_in_front_of() -> Weight { // Proof Size summary in bytes: - // Measured: `2154` - // Estimated: `25798` - // Minimum execution time: 59_513 nanoseconds. - Weight::from_parts(60_717_000, 25798) + // Measured: `1930` + // Estimated: `30748` + // Minimum execution time: 69_938_000 picoseconds. + Weight::from_parts(70_723_000, 30748) .saturating_add(T::DbWeight::get().reads(10_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -123,10 +126,10 @@ impl WeightInfo for () { /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) fn rebag_non_terminal() -> Weight { // Proof Size summary in bytes: - // Measured: `1916` - // Estimated: `19186` - // Minimum execution time: 54_348 nanoseconds. - Weight::from_parts(55_024_000, 19186) + // Measured: `1724` + // Estimated: `23146` + // Minimum execution time: 63_526_000 picoseconds. + Weight::from_parts(64_125_000, 23146) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -140,10 +143,10 @@ impl WeightInfo for () { /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) fn rebag_terminal() -> Weight { // Proof Size summary in bytes: - // Measured: `1810` - // Estimated: `19114` - // Minimum execution time: 53_306 nanoseconds. - Weight::from_parts(54_263_000, 19114) + // Measured: `1618` + // Estimated: `23074` + // Minimum execution time: 62_404_000 picoseconds. + Weight::from_parts(63_178_000, 23074) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -159,10 +162,10 @@ impl WeightInfo for () { /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) fn put_in_front_of() -> Weight { // Proof Size summary in bytes: - // Measured: `2154` - // Estimated: `25798` - // Minimum execution time: 59_513 nanoseconds. - Weight::from_parts(60_717_000, 25798) + // Measured: `1930` + // Estimated: `30748` + // Minimum execution time: 69_938_000 picoseconds. + Weight::from_parts(70_723_000, 30748) .saturating_add(RocksDbWeight::get().reads(10_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } diff --git a/frame/balances/src/weights.rs b/frame/balances/src/weights.rs index cdc657ce1656c..500eb3371d635 100644 --- a/frame/balances/src/weights.rs +++ b/frame/balances/src/weights.rs @@ -18,26 +18,28 @@ //! Autogenerated weights for pallet_balances //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/production/substrate +// ./target/production/substrate // benchmark // pallet +// --chain=dev // --steps=50 // --repeat=20 +// --pallet=pallet_balances +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --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_balances -// --chain=dev -// --header=./HEADER-APACHE2 // --output=./frame/balances/src/weights.rs +// --header=./HEADER-APACHE2 // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -67,9 +69,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 37_815 nanoseconds. - Weight::from_parts(38_109_000, 0) - .saturating_add(Weight::from_parts(0, 3593)) + // Minimum execution time: 37_266_000 picoseconds. + Weight::from_parts(37_757_000, 3593) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -79,9 +80,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 28_184 nanoseconds. - Weight::from_parts(49_250_000, 0) - .saturating_add(Weight::from_parts(0, 3593)) + // Minimum execution time: 28_782_000 picoseconds. + Weight::from_parts(29_185_000, 3593) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -89,11 +89,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn set_balance_creating() -> Weight { // Proof Size summary in bytes: - // Measured: `206` + // Measured: `174` // Estimated: `3593` - // Minimum execution time: 17_474 nanoseconds. - Weight::from_parts(17_777_000, 0) - .saturating_add(Weight::from_parts(0, 3593)) + // Minimum execution time: 17_406_000 picoseconds. + Weight::from_parts(17_781_000, 3593) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -101,11 +100,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn set_balance_killing() -> Weight { // Proof Size summary in bytes: - // Measured: `206` + // Measured: `174` // Estimated: `3593` - // Minimum execution time: 20_962 nanoseconds. - Weight::from_parts(21_419_000, 0) - .saturating_add(Weight::from_parts(0, 3593)) + // Minimum execution time: 20_942_000 picoseconds. + Weight::from_parts(21_270_000, 3593) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -113,11 +111,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn force_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `135` + // Measured: `103` // Estimated: `6196` - // Minimum execution time: 39_713 nanoseconds. - Weight::from_parts(40_360_000, 0) - .saturating_add(Weight::from_parts(0, 6196)) + // Minimum execution time: 41_706_000 picoseconds. + Weight::from_parts(42_176_000, 6196) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -127,9 +124,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 34_878 nanoseconds. - Weight::from_parts(35_121_000, 0) - .saturating_add(Weight::from_parts(0, 3593)) + // Minimum execution time: 35_622_000 picoseconds. + Weight::from_parts(35_943_000, 3593) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -137,11 +133,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn force_unreserve() -> Weight { // Proof Size summary in bytes: - // Measured: `206` + // Measured: `174` // Estimated: `3593` - // Minimum execution time: 16_790 nanoseconds. - Weight::from_parts(17_029_000, 0) - .saturating_add(Weight::from_parts(0, 3593)) + // Minimum execution time: 16_586_000 picoseconds. + Weight::from_parts(17_352_000, 3593) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -155,9 +150,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 37_815 nanoseconds. - Weight::from_parts(38_109_000, 0) - .saturating_add(Weight::from_parts(0, 3593)) + // Minimum execution time: 37_266_000 picoseconds. + Weight::from_parts(37_757_000, 3593) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -167,9 +161,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 28_184 nanoseconds. - Weight::from_parts(49_250_000, 0) - .saturating_add(Weight::from_parts(0, 3593)) + // Minimum execution time: 28_782_000 picoseconds. + Weight::from_parts(29_185_000, 3593) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -177,11 +170,10 @@ impl WeightInfo for () { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn set_balance_creating() -> Weight { // Proof Size summary in bytes: - // Measured: `206` + // Measured: `174` // Estimated: `3593` - // Minimum execution time: 17_474 nanoseconds. - Weight::from_parts(17_777_000, 0) - .saturating_add(Weight::from_parts(0, 3593)) + // Minimum execution time: 17_406_000 picoseconds. + Weight::from_parts(17_781_000, 3593) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -189,11 +181,10 @@ impl WeightInfo for () { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn set_balance_killing() -> Weight { // Proof Size summary in bytes: - // Measured: `206` + // Measured: `174` // Estimated: `3593` - // Minimum execution time: 20_962 nanoseconds. - Weight::from_parts(21_419_000, 0) - .saturating_add(Weight::from_parts(0, 3593)) + // Minimum execution time: 20_942_000 picoseconds. + Weight::from_parts(21_270_000, 3593) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -201,11 +192,10 @@ impl WeightInfo for () { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn force_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `135` + // Measured: `103` // Estimated: `6196` - // Minimum execution time: 39_713 nanoseconds. - Weight::from_parts(40_360_000, 0) - .saturating_add(Weight::from_parts(0, 6196)) + // Minimum execution time: 41_706_000 picoseconds. + Weight::from_parts(42_176_000, 6196) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -215,9 +205,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 34_878 nanoseconds. - Weight::from_parts(35_121_000, 0) - .saturating_add(Weight::from_parts(0, 3593)) + // Minimum execution time: 35_622_000 picoseconds. + Weight::from_parts(35_943_000, 3593) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -225,11 +214,10 @@ impl WeightInfo for () { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn force_unreserve() -> Weight { // Proof Size summary in bytes: - // Measured: `206` + // Measured: `174` // Estimated: `3593` - // Minimum execution time: 16_790 nanoseconds. - Weight::from_parts(17_029_000, 0) - .saturating_add(Weight::from_parts(0, 3593)) + // Minimum execution time: 16_586_000 picoseconds. + Weight::from_parts(17_352_000, 3593) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/frame/benchmarking/src/weights.rs b/frame/benchmarking/src/weights.rs index b05feb5900a65..aa24b99ace2a7 100644 --- a/frame/benchmarking/src/weights.rs +++ b/frame/benchmarking/src/weights.rs @@ -18,26 +18,28 @@ //! Autogenerated weights for frame_benchmarking //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/production/substrate +// ./target/production/substrate // benchmark // pallet +// --chain=dev // --steps=50 // --repeat=20 +// --pallet=frame_benchmarking +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --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=frame_benchmarking -// --chain=dev -// --header=./HEADER-APACHE2 // --output=./frame/benchmarking/src/weights.rs +// --header=./HEADER-APACHE2 // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -65,49 +67,49 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 168_000 picoseconds. - Weight::from_parts(237_577, 0) + // Minimum execution time: 205_000 picoseconds. + Weight::from_parts(263_483, 0) } /// The range of component `i` is `[0, 1000000]`. fn subtraction(_i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 169_000 picoseconds. - Weight::from_parts(224_111, 0) + // Minimum execution time: 186_000 picoseconds. + Weight::from_parts(257_588, 0) } /// The range of component `i` is `[0, 1000000]`. fn multiplication(_i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 175_000 picoseconds. - Weight::from_parts(229_708, 0) + // Minimum execution time: 192_000 picoseconds. + Weight::from_parts(264_271, 0) } /// The range of component `i` is `[0, 1000000]`. fn division(_i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 173_000 picoseconds. - Weight::from_parts(229_855, 0) + // Minimum execution time: 191_000 picoseconds. + Weight::from_parts(250_785, 0) } fn hashing() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 21_286_627_000 picoseconds. - Weight::from_parts(21_405_011_000, 0) + // Minimum execution time: 21_405_207_000 picoseconds. + Weight::from_parts(21_534_243_000, 0) } /// The range of component `i` is `[0, 100]`. fn sr25519_verification(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 239_000 picoseconds. - Weight::from_parts(661_987, 0) - // Standard Error: 24_324 - .saturating_add(Weight::from_parts(47_322_399, 0).saturating_mul(i.into())) + // Minimum execution time: 255_000 picoseconds. + Weight::from_parts(271_000, 0) + // Standard Error: 12_788 + .saturating_add(Weight::from_parts(47_469_387, 0).saturating_mul(i.into())) } } @@ -118,48 +120,48 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 168_000 picoseconds. - Weight::from_parts(237_577, 0) + // Minimum execution time: 205_000 picoseconds. + Weight::from_parts(263_483, 0) } /// The range of component `i` is `[0, 1000000]`. fn subtraction(_i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 169_000 picoseconds. - Weight::from_parts(224_111, 0) + // Minimum execution time: 186_000 picoseconds. + Weight::from_parts(257_588, 0) } /// The range of component `i` is `[0, 1000000]`. fn multiplication(_i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 175_000 picoseconds. - Weight::from_parts(229_708, 0) + // Minimum execution time: 192_000 picoseconds. + Weight::from_parts(264_271, 0) } /// The range of component `i` is `[0, 1000000]`. fn division(_i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 173_000 picoseconds. - Weight::from_parts(229_855, 0) + // Minimum execution time: 191_000 picoseconds. + Weight::from_parts(250_785, 0) } fn hashing() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 21_286_627_000 picoseconds. - Weight::from_parts(21_405_011_000, 0) + // Minimum execution time: 21_405_207_000 picoseconds. + Weight::from_parts(21_534_243_000, 0) } /// The range of component `i` is `[0, 100]`. fn sr25519_verification(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 239_000 picoseconds. - Weight::from_parts(661_987, 0) - // Standard Error: 24_324 - .saturating_add(Weight::from_parts(47_322_399, 0).saturating_mul(i.into())) + // Minimum execution time: 255_000 picoseconds. + Weight::from_parts(271_000, 0) + // Standard Error: 12_788 + .saturating_add(Weight::from_parts(47_469_387, 0).saturating_mul(i.into())) } } diff --git a/frame/bounties/src/weights.rs b/frame/bounties/src/weights.rs index f0ea78b5f1e8d..b0459fee62eb1 100644 --- a/frame/bounties/src/weights.rs +++ b/frame/bounties/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_bounties //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,6 +31,9 @@ // --steps=50 // --repeat=20 // --pallet=pallet_bounties +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -73,14 +76,12 @@ impl WeightInfo for SubstrateWeight { /// Storage: Bounties Bounties (r:0 w:1) /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) /// The range of component `d` is `[0, 300]`. - fn propose_bounty(d: u32, ) -> Weight { + fn propose_bounty(_d: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `308` - // Estimated: `3102` - // Minimum execution time: 22_787 nanoseconds. - Weight::from_parts(23_898_632, 3102) - // Standard Error: 141 - .saturating_add(Weight::from_parts(568, 0).saturating_mul(d.into())) + // Measured: `276` + // Estimated: `5082` + // Minimum execution time: 26_271_000 picoseconds. + Weight::from_parts(28_048_901, 5082) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -90,10 +91,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Bounties BountyApprovals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) fn approve_bounty() -> Weight { // Proof Size summary in bytes: - // Measured: `400` - // Estimated: `3549` - // Minimum execution time: 10_526 nanoseconds. - Weight::from_parts(10_729_000, 3549) + // Measured: `368` + // Estimated: `5529` + // Minimum execution time: 12_573_000 picoseconds. + Weight::from_parts(12_827_000, 5529) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -101,10 +102,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) fn propose_curator() -> Weight { // Proof Size summary in bytes: - // Measured: `420` - // Estimated: `2652` - // Minimum execution time: 9_193 nanoseconds. - Weight::from_parts(9_455_000, 2652) + // Measured: `388` + // Estimated: `3642` + // Minimum execution time: 10_555_000 picoseconds. + Weight::from_parts(10_857_000, 3642) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -114,10 +115,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn unassign_curator() -> Weight { // Proof Size summary in bytes: - // Measured: `628` - // Estimated: `5255` - // Minimum execution time: 22_592 nanoseconds. - Weight::from_parts(22_952_000, 5255) + // Measured: `564` + // Estimated: `7235` + // Minimum execution time: 26_003_000 picoseconds. + Weight::from_parts(26_291_000, 7235) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -127,10 +128,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn accept_curator() -> Weight { // Proof Size summary in bytes: - // Measured: `624` - // Estimated: `5255` - // Minimum execution time: 20_920 nanoseconds. - Weight::from_parts(21_369_000, 5255) + // Measured: `560` + // Estimated: `7235` + // Minimum execution time: 24_371_000 picoseconds. + Weight::from_parts(24_781_000, 7235) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -140,10 +141,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: ChildBounties ParentChildBounties (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) fn award_bounty() -> Weight { // Proof Size summary in bytes: - // Measured: `570` - // Estimated: `5143` - // Minimum execution time: 17_853 nanoseconds. - Weight::from_parts(18_280_000, 5143) + // Measured: `538` + // Estimated: `7123` + // Minimum execution time: 20_688_000 picoseconds. + Weight::from_parts(20_909_000, 7123) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -157,10 +158,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Bounties BountyDescriptions (max_values: None, max_size: Some(314), added: 2789, mode: MaxEncodedLen) fn claim_bounty() -> Weight { // Proof Size summary in bytes: - // Measured: `998` - // Estimated: `12964` - // Minimum execution time: 67_538 nanoseconds. - Weight::from_parts(67_974_000, 12964) + // Measured: `902` + // Estimated: `15934` + // Minimum execution time: 78_933_000 picoseconds. + Weight::from_parts(79_884_000, 15934) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -174,10 +175,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Bounties BountyDescriptions (max_values: None, max_size: Some(314), added: 2789, mode: MaxEncodedLen) fn close_bounty_proposed() -> Weight { // Proof Size summary in bytes: - // Measured: `646` - // Estimated: `7746` - // Minimum execution time: 28_380 nanoseconds. - Weight::from_parts(28_859_000, 7746) + // Measured: `582` + // Estimated: `10716` + // Minimum execution time: 32_332_000 picoseconds. + Weight::from_parts(32_833_000, 10716) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -191,10 +192,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Bounties BountyDescriptions (max_values: None, max_size: Some(314), added: 2789, mode: MaxEncodedLen) fn close_bounty_active() -> Weight { // Proof Size summary in bytes: - // Measured: `914` - // Estimated: `10349` - // Minimum execution time: 47_739 nanoseconds. - Weight::from_parts(48_388_000, 10349) + // Measured: `818` + // Estimated: `13319` + // Minimum execution time: 55_686_000 picoseconds. + Weight::from_parts(56_271_000, 13319) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -202,10 +203,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) fn extend_bounty_expiry() -> Weight { // Proof Size summary in bytes: - // Measured: `456` - // Estimated: `2652` - // Minimum execution time: 14_188 nanoseconds. - Weight::from_parts(14_801_000, 2652) + // Measured: `424` + // Estimated: `3642` + // Minimum execution time: 16_414_000 picoseconds. + Weight::from_parts(16_681_000, 3642) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -218,12 +219,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `b` is `[0, 100]`. fn spend_funds(b: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `31 + b * (360 ±0)` - // Estimated: `897 + b * (7858 ±0)` - // Minimum execution time: 4_685 nanoseconds. - Weight::from_parts(9_932_840, 897) - // Standard Error: 14_301 - .saturating_add(Weight::from_parts(27_178_347, 0).saturating_mul(b.into())) + // Measured: `4 + b * (297 ±0)` + // Estimated: `3867 + b * (7858 ±0)` + // Minimum execution time: 5_398_000 picoseconds. + Weight::from_parts(4_478_947, 3867) + // Standard Error: 41_860 + .saturating_add(Weight::from_parts(33_082_606, 0).saturating_mul(b.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(b.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) @@ -243,14 +244,12 @@ impl WeightInfo for () { /// Storage: Bounties Bounties (r:0 w:1) /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) /// The range of component `d` is `[0, 300]`. - fn propose_bounty(d: u32, ) -> Weight { + fn propose_bounty(_d: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `308` - // Estimated: `3102` - // Minimum execution time: 22_787 nanoseconds. - Weight::from_parts(23_898_632, 3102) - // Standard Error: 141 - .saturating_add(Weight::from_parts(568, 0).saturating_mul(d.into())) + // Measured: `276` + // Estimated: `5082` + // Minimum execution time: 26_271_000 picoseconds. + Weight::from_parts(28_048_901, 5082) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -260,10 +259,10 @@ impl WeightInfo for () { /// Proof: Bounties BountyApprovals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) fn approve_bounty() -> Weight { // Proof Size summary in bytes: - // Measured: `400` - // Estimated: `3549` - // Minimum execution time: 10_526 nanoseconds. - Weight::from_parts(10_729_000, 3549) + // Measured: `368` + // Estimated: `5529` + // Minimum execution time: 12_573_000 picoseconds. + Weight::from_parts(12_827_000, 5529) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -271,10 +270,10 @@ impl WeightInfo for () { /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) fn propose_curator() -> Weight { // Proof Size summary in bytes: - // Measured: `420` - // Estimated: `2652` - // Minimum execution time: 9_193 nanoseconds. - Weight::from_parts(9_455_000, 2652) + // Measured: `388` + // Estimated: `3642` + // Minimum execution time: 10_555_000 picoseconds. + Weight::from_parts(10_857_000, 3642) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -284,10 +283,10 @@ impl WeightInfo for () { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn unassign_curator() -> Weight { // Proof Size summary in bytes: - // Measured: `628` - // Estimated: `5255` - // Minimum execution time: 22_592 nanoseconds. - Weight::from_parts(22_952_000, 5255) + // Measured: `564` + // Estimated: `7235` + // Minimum execution time: 26_003_000 picoseconds. + Weight::from_parts(26_291_000, 7235) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -297,10 +296,10 @@ impl WeightInfo for () { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn accept_curator() -> Weight { // Proof Size summary in bytes: - // Measured: `624` - // Estimated: `5255` - // Minimum execution time: 20_920 nanoseconds. - Weight::from_parts(21_369_000, 5255) + // Measured: `560` + // Estimated: `7235` + // Minimum execution time: 24_371_000 picoseconds. + Weight::from_parts(24_781_000, 7235) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -310,10 +309,10 @@ impl WeightInfo for () { /// Proof: ChildBounties ParentChildBounties (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) fn award_bounty() -> Weight { // Proof Size summary in bytes: - // Measured: `570` - // Estimated: `5143` - // Minimum execution time: 17_853 nanoseconds. - Weight::from_parts(18_280_000, 5143) + // Measured: `538` + // Estimated: `7123` + // Minimum execution time: 20_688_000 picoseconds. + Weight::from_parts(20_909_000, 7123) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -327,10 +326,10 @@ impl WeightInfo for () { /// Proof: Bounties BountyDescriptions (max_values: None, max_size: Some(314), added: 2789, mode: MaxEncodedLen) fn claim_bounty() -> Weight { // Proof Size summary in bytes: - // Measured: `998` - // Estimated: `12964` - // Minimum execution time: 67_538 nanoseconds. - Weight::from_parts(67_974_000, 12964) + // Measured: `902` + // Estimated: `15934` + // Minimum execution time: 78_933_000 picoseconds. + Weight::from_parts(79_884_000, 15934) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -344,10 +343,10 @@ impl WeightInfo for () { /// Proof: Bounties BountyDescriptions (max_values: None, max_size: Some(314), added: 2789, mode: MaxEncodedLen) fn close_bounty_proposed() -> Weight { // Proof Size summary in bytes: - // Measured: `646` - // Estimated: `7746` - // Minimum execution time: 28_380 nanoseconds. - Weight::from_parts(28_859_000, 7746) + // Measured: `582` + // Estimated: `10716` + // Minimum execution time: 32_332_000 picoseconds. + Weight::from_parts(32_833_000, 10716) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -361,10 +360,10 @@ impl WeightInfo for () { /// Proof: Bounties BountyDescriptions (max_values: None, max_size: Some(314), added: 2789, mode: MaxEncodedLen) fn close_bounty_active() -> Weight { // Proof Size summary in bytes: - // Measured: `914` - // Estimated: `10349` - // Minimum execution time: 47_739 nanoseconds. - Weight::from_parts(48_388_000, 10349) + // Measured: `818` + // Estimated: `13319` + // Minimum execution time: 55_686_000 picoseconds. + Weight::from_parts(56_271_000, 13319) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -372,10 +371,10 @@ impl WeightInfo for () { /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) fn extend_bounty_expiry() -> Weight { // Proof Size summary in bytes: - // Measured: `456` - // Estimated: `2652` - // Minimum execution time: 14_188 nanoseconds. - Weight::from_parts(14_801_000, 2652) + // Measured: `424` + // Estimated: `3642` + // Minimum execution time: 16_414_000 picoseconds. + Weight::from_parts(16_681_000, 3642) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -388,12 +387,12 @@ impl WeightInfo for () { /// The range of component `b` is `[0, 100]`. fn spend_funds(b: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `31 + b * (360 ±0)` - // Estimated: `897 + b * (7858 ±0)` - // Minimum execution time: 4_685 nanoseconds. - Weight::from_parts(9_932_840, 897) - // Standard Error: 14_301 - .saturating_add(Weight::from_parts(27_178_347, 0).saturating_mul(b.into())) + // Measured: `4 + b * (297 ±0)` + // Estimated: `3867 + b * (7858 ±0)` + // Minimum execution time: 5_398_000 picoseconds. + Weight::from_parts(4_478_947, 3867) + // Standard Error: 41_860 + .saturating_add(Weight::from_parts(33_082_606, 0).saturating_mul(b.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(b.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) diff --git a/frame/child-bounties/src/weights.rs b/frame/child-bounties/src/weights.rs index eeb14419678d7..92be77c49dc9c 100644 --- a/frame/child-bounties/src/weights.rs +++ b/frame/child-bounties/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_child_bounties //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,6 +31,9 @@ // --steps=50 // --repeat=20 // --pallet=pallet_child_bounties +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -76,12 +79,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `d` is `[0, 300]`. fn add_child_bounty(d: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `742` - // Estimated: `10848` - // Minimum execution time: 46_743 nanoseconds. - Weight::from_parts(47_762_924, 10848) - // Standard Error: 135 - .saturating_add(Weight::from_parts(599, 0).saturating_mul(d.into())) + // Measured: `678` + // Estimated: `14808` + // Minimum execution time: 54_017_000 picoseconds. + Weight::from_parts(55_142_443, 14808) + // Standard Error: 310 + .saturating_add(Weight::from_parts(1_199, 0).saturating_mul(d.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -93,10 +96,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: ChildBounties ChildrenCuratorFees (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) fn propose_curator() -> Weight { // Proof Size summary in bytes: - // Measured: `796` - // Estimated: `7775` - // Minimum execution time: 16_417 nanoseconds. - Weight::from_parts(16_712_000, 7775) + // Measured: `732` + // Estimated: `10745` + // Minimum execution time: 19_222_000 picoseconds. + Weight::from_parts(19_446_000, 10745) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -108,10 +111,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn accept_curator() -> Weight { // Proof Size summary in bytes: - // Measured: `974` - // Estimated: `7875` - // Minimum execution time: 25_548 nanoseconds. - Weight::from_parts(25_919_000, 7875) + // Measured: `878` + // Estimated: `10845` + // Minimum execution time: 31_049_000 picoseconds. + Weight::from_parts(31_546_000, 10845) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -123,10 +126,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn unassign_curator() -> Weight { // Proof Size summary in bytes: - // Measured: `974` - // Estimated: `7875` - // Minimum execution time: 27_645 nanoseconds. - Weight::from_parts(27_947_000, 7875) + // Measured: `878` + // Estimated: `10845` + // Minimum execution time: 33_860_000 picoseconds. + Weight::from_parts(34_897_000, 10845) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -136,10 +139,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: ChildBounties ChildBounties (max_values: None, max_size: Some(145), added: 2620, mode: MaxEncodedLen) fn award_child_bounty() -> Weight { // Proof Size summary in bytes: - // Measured: `839` - // Estimated: `5272` - // Minimum execution time: 20_002 nanoseconds. - Weight::from_parts(20_512_000, 5272) + // Measured: `775` + // Estimated: `7252` + // Minimum execution time: 23_178_000 picoseconds. + Weight::from_parts(23_412_000, 7252) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -153,10 +156,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: ChildBounties ChildBountyDescriptions (max_values: None, max_size: Some(314), added: 2789, mode: MaxEncodedLen) fn claim_child_bounty() -> Weight { // Proof Size summary in bytes: - // Measured: `744` - // Estimated: `12920` - // Minimum execution time: 63_752 nanoseconds. - Weight::from_parts(64_179_000, 12920) + // Measured: `648` + // Estimated: `15890` + // Minimum execution time: 76_189_000 picoseconds. + Weight::from_parts(76_770_000, 15890) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -174,10 +177,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: ChildBounties ChildBountyDescriptions (max_values: None, max_size: Some(314), added: 2789, mode: MaxEncodedLen) fn close_child_bounty_added() -> Weight { // Proof Size summary in bytes: - // Measured: `1106` - // Estimated: `15472` - // Minimum execution time: 47_388 nanoseconds. - Weight::from_parts(47_946_000, 15472) + // Measured: `978` + // Estimated: `20422` + // Minimum execution time: 55_161_000 picoseconds. + Weight::from_parts(55_578_000, 20422) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -195,10 +198,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: ChildBounties ChildBountyDescriptions (max_values: None, max_size: Some(314), added: 2789, mode: MaxEncodedLen) fn close_child_bounty_active() -> Weight { // Proof Size summary in bytes: - // Measured: `1325` - // Estimated: `18075` - // Minimum execution time: 58_008 nanoseconds. - Weight::from_parts(58_586_000, 18075) + // Measured: `1165` + // Estimated: `23025` + // Minimum execution time: 67_815_000 picoseconds. + Weight::from_parts(68_620_000, 23025) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } @@ -221,12 +224,12 @@ impl WeightInfo for () { /// The range of component `d` is `[0, 300]`. fn add_child_bounty(d: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `742` - // Estimated: `10848` - // Minimum execution time: 46_743 nanoseconds. - Weight::from_parts(47_762_924, 10848) - // Standard Error: 135 - .saturating_add(Weight::from_parts(599, 0).saturating_mul(d.into())) + // Measured: `678` + // Estimated: `14808` + // Minimum execution time: 54_017_000 picoseconds. + Weight::from_parts(55_142_443, 14808) + // Standard Error: 310 + .saturating_add(Weight::from_parts(1_199, 0).saturating_mul(d.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -238,10 +241,10 @@ impl WeightInfo for () { /// Proof: ChildBounties ChildrenCuratorFees (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) fn propose_curator() -> Weight { // Proof Size summary in bytes: - // Measured: `796` - // Estimated: `7775` - // Minimum execution time: 16_417 nanoseconds. - Weight::from_parts(16_712_000, 7775) + // Measured: `732` + // Estimated: `10745` + // Minimum execution time: 19_222_000 picoseconds. + Weight::from_parts(19_446_000, 10745) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -253,10 +256,10 @@ impl WeightInfo for () { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn accept_curator() -> Weight { // Proof Size summary in bytes: - // Measured: `974` - // Estimated: `7875` - // Minimum execution time: 25_548 nanoseconds. - Weight::from_parts(25_919_000, 7875) + // Measured: `878` + // Estimated: `10845` + // Minimum execution time: 31_049_000 picoseconds. + Weight::from_parts(31_546_000, 10845) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -268,10 +271,10 @@ impl WeightInfo for () { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn unassign_curator() -> Weight { // Proof Size summary in bytes: - // Measured: `974` - // Estimated: `7875` - // Minimum execution time: 27_645 nanoseconds. - Weight::from_parts(27_947_000, 7875) + // Measured: `878` + // Estimated: `10845` + // Minimum execution time: 33_860_000 picoseconds. + Weight::from_parts(34_897_000, 10845) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -281,10 +284,10 @@ impl WeightInfo for () { /// Proof: ChildBounties ChildBounties (max_values: None, max_size: Some(145), added: 2620, mode: MaxEncodedLen) fn award_child_bounty() -> Weight { // Proof Size summary in bytes: - // Measured: `839` - // Estimated: `5272` - // Minimum execution time: 20_002 nanoseconds. - Weight::from_parts(20_512_000, 5272) + // Measured: `775` + // Estimated: `7252` + // Minimum execution time: 23_178_000 picoseconds. + Weight::from_parts(23_412_000, 7252) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -298,10 +301,10 @@ impl WeightInfo for () { /// Proof: ChildBounties ChildBountyDescriptions (max_values: None, max_size: Some(314), added: 2789, mode: MaxEncodedLen) fn claim_child_bounty() -> Weight { // Proof Size summary in bytes: - // Measured: `744` - // Estimated: `12920` - // Minimum execution time: 63_752 nanoseconds. - Weight::from_parts(64_179_000, 12920) + // Measured: `648` + // Estimated: `15890` + // Minimum execution time: 76_189_000 picoseconds. + Weight::from_parts(76_770_000, 15890) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -319,10 +322,10 @@ impl WeightInfo for () { /// Proof: ChildBounties ChildBountyDescriptions (max_values: None, max_size: Some(314), added: 2789, mode: MaxEncodedLen) fn close_child_bounty_added() -> Weight { // Proof Size summary in bytes: - // Measured: `1106` - // Estimated: `15472` - // Minimum execution time: 47_388 nanoseconds. - Weight::from_parts(47_946_000, 15472) + // Measured: `978` + // Estimated: `20422` + // Minimum execution time: 55_161_000 picoseconds. + Weight::from_parts(55_578_000, 20422) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -340,10 +343,10 @@ impl WeightInfo for () { /// Proof: ChildBounties ChildBountyDescriptions (max_values: None, max_size: Some(314), added: 2789, mode: MaxEncodedLen) fn close_child_bounty_active() -> Weight { // Proof Size summary in bytes: - // Measured: `1325` - // Estimated: `18075` - // Minimum execution time: 58_008 nanoseconds. - Weight::from_parts(58_586_000, 18075) + // Measured: `1165` + // Estimated: `23025` + // Minimum execution time: 67_815_000 picoseconds. + Weight::from_parts(68_620_000, 23025) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } diff --git a/frame/collective/src/weights.rs b/frame/collective/src/weights.rs index df233fc248e3d..2199c02052009 100644 --- a/frame/collective/src/weights.rs +++ b/frame/collective/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_collective //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,6 +31,9 @@ // --steps=50 // --repeat=20 // --pallet=pallet_collective +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -76,20 +79,20 @@ impl WeightInfo for SubstrateWeight { /// The range of component `p` is `[0, 100]`. fn set_members(m: u32, _n: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0 + m * (3233 ±0) + p * (3223 ±0)` - // Estimated: `16586 + m * (7809 ±24) + p * (10238 ±24)` - // Minimum execution time: 17_093 nanoseconds. - Weight::from_parts(17_284_000, 16586) - // Standard Error: 64_700 - .saturating_add(Weight::from_parts(5_143_145, 0).saturating_mul(m.into())) - // Standard Error: 64_700 - .saturating_add(Weight::from_parts(7_480_941, 0).saturating_mul(p.into())) + // Measured: `0 + m * (3232 ±0) + p * (3190 ±0)` + // Estimated: `19428 + m * (7799 ±24) + p * (10110 ±24)` + // Minimum execution time: 18_772_000 picoseconds. + Weight::from_parts(18_931_000, 19428) + // Standard Error: 65_247 + .saturating_add(Weight::from_parts(5_050_136, 0).saturating_mul(m.into())) + // Standard Error: 65_247 + .saturating_add(Weight::from_parts(8_235_069, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(p.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(p.into()))) - .saturating_add(Weight::from_parts(0, 7809).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 10238).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 7799).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 10110).saturating_mul(p.into())) } /// Storage: Council Members (r:1 w:0) /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) @@ -97,14 +100,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `m` is `[1, 100]`. fn execute(b: u32, m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `234 + m * (32 ±0)` - // Estimated: `730 + m * (32 ±0)` - // Minimum execution time: 15_972 nanoseconds. - Weight::from_parts(14_971_445, 730) - // Standard Error: 32 - .saturating_add(Weight::from_parts(1_775, 0).saturating_mul(b.into())) - // Standard Error: 334 - .saturating_add(Weight::from_parts(17_052, 0).saturating_mul(m.into())) + // Measured: `202 + m * (32 ±0)` + // Estimated: `1688 + m * (32 ±0)` + // Minimum execution time: 17_741_000 picoseconds. + Weight::from_parts(17_580_031, 1688) + // Standard Error: 113 + .saturating_add(Weight::from_parts(941, 0).saturating_mul(b.into())) + // Standard Error: 1_170 + .saturating_add(Weight::from_parts(17_329, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(Weight::from_parts(0, 32).saturating_mul(m.into())) } @@ -116,14 +119,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `m` is `[1, 100]`. fn propose_execute(b: u32, m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `234 + m * (32 ±0)` - // Estimated: `3440 + m * (64 ±0)` - // Minimum execution time: 17_950 nanoseconds. - Weight::from_parts(17_019_558, 3440) - // Standard Error: 41 - .saturating_add(Weight::from_parts(1_807, 0).saturating_mul(b.into())) - // Standard Error: 432 - .saturating_add(Weight::from_parts(27_986, 0).saturating_mul(m.into())) + // Measured: `202 + m * (32 ±0)` + // Estimated: `5356 + m * (64 ±0)` + // Minimum execution time: 20_214_000 picoseconds. + Weight::from_parts(19_508_816, 5356) + // Standard Error: 46 + .saturating_add(Weight::from_parts(1_646, 0).saturating_mul(b.into())) + // Standard Error: 475 + .saturating_add(Weight::from_parts(27_145, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) } @@ -142,16 +145,16 @@ impl WeightInfo for SubstrateWeight { /// The range of component `p` is `[1, 100]`. fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `556 + m * (32 ±0) + p * (36 ±0)` - // Estimated: `6355 + m * (165 ±0) + p * (180 ±0)` - // Minimum execution time: 24_817 nanoseconds. - Weight::from_parts(24_778_955, 6355) - // Standard Error: 73 - .saturating_add(Weight::from_parts(2_355, 0).saturating_mul(b.into())) - // Standard Error: 765 - .saturating_add(Weight::from_parts(20_518, 0).saturating_mul(m.into())) - // Standard Error: 755 - .saturating_add(Weight::from_parts(85_670, 0).saturating_mul(p.into())) + // Measured: `492 + m * (32 ±0) + p * (36 ±0)` + // Estimated: `10015 + m * (165 ±0) + p * (180 ±0)` + // Minimum execution time: 27_872_000 picoseconds. + Weight::from_parts(28_010_227, 10015) + // Standard Error: 90 + .saturating_add(Weight::from_parts(2_643, 0).saturating_mul(b.into())) + // Standard Error: 944 + .saturating_add(Weight::from_parts(17_897, 0).saturating_mul(m.into())) + // Standard Error: 932 + .saturating_add(Weight::from_parts(122_368, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 165).saturating_mul(m.into())) @@ -164,12 +167,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `m` is `[5, 100]`. fn vote(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1006 + m * (64 ±0)` - // Estimated: `4980 + m * (128 ±0)` - // Minimum execution time: 19_790 nanoseconds. - Weight::from_parts(20_528_275, 4980) - // Standard Error: 651 - .saturating_add(Weight::from_parts(48_856, 0).saturating_mul(m.into())) + // Measured: `941 + m * (64 ±0)` + // Estimated: `6830 + m * (128 ±0)` + // Minimum execution time: 22_518_000 picoseconds. + Weight::from_parts(23_281_512, 6830) + // Standard Error: 647 + .saturating_add(Weight::from_parts(53_974, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 128).saturating_mul(m.into())) @@ -186,14 +189,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `p` is `[1, 100]`. fn close_early_disapproved(m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `626 + m * (64 ±0) + p * (36 ±0)` - // Estimated: `5893 + m * (260 ±0) + p * (144 ±0)` - // Minimum execution time: 25_564 nanoseconds. - Weight::from_parts(25_535_497, 5893) - // Standard Error: 610 - .saturating_add(Weight::from_parts(27_956, 0).saturating_mul(m.into())) - // Standard Error: 595 - .saturating_add(Weight::from_parts(84_835, 0).saturating_mul(p.into())) + // Measured: `530 + m * (64 ±0) + p * (36 ±0)` + // Estimated: `8475 + m * (260 ±0) + p * (144 ±0)` + // Minimum execution time: 29_020_000 picoseconds. + Weight::from_parts(29_009_937, 8475) + // Standard Error: 809 + .saturating_add(Weight::from_parts(31_952, 0).saturating_mul(m.into())) + // Standard Error: 789 + .saturating_add(Weight::from_parts(124_282, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 260).saturating_mul(m.into())) @@ -212,16 +215,16 @@ impl WeightInfo for SubstrateWeight { /// The range of component `p` is `[1, 100]`. fn close_early_approved(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `962 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` - // Estimated: `9164 + b * (4 ±0) + m * (264 ±0) + p * (160 ±0)` - // Minimum execution time: 36_515 nanoseconds. - Weight::from_parts(36_626_648, 9164) - // Standard Error: 98 - .saturating_add(Weight::from_parts(2_295, 0).saturating_mul(b.into())) - // Standard Error: 1_036 - .saturating_add(Weight::from_parts(22_182, 0).saturating_mul(m.into())) - // Standard Error: 1_010 - .saturating_add(Weight::from_parts(100_034, 0).saturating_mul(p.into())) + // Measured: `832 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` + // Estimated: `12636 + b * (4 ±0) + m * (264 ±0) + p * (160 ±0)` + // Minimum execution time: 41_541_000 picoseconds. + Weight::from_parts(43_640_322, 12636) + // Standard Error: 104 + .saturating_add(Weight::from_parts(2_178, 0).saturating_mul(b.into())) + // Standard Error: 1_101 + .saturating_add(Weight::from_parts(20_512, 0).saturating_mul(m.into())) + // Standard Error: 1_073 + .saturating_add(Weight::from_parts(133_112, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 4).saturating_mul(b.into())) @@ -242,14 +245,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `p` is `[1, 100]`. fn close_disapproved(m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `646 + m * (64 ±0) + p * (36 ±0)` - // Estimated: `7095 + m * (325 ±0) + p * (180 ±0)` - // Minimum execution time: 28_858 nanoseconds. - Weight::from_parts(28_050_047, 7095) - // Standard Error: 614 - .saturating_add(Weight::from_parts(34_031, 0).saturating_mul(m.into())) - // Standard Error: 599 - .saturating_add(Weight::from_parts(85_744, 0).saturating_mul(p.into())) + // Measured: `550 + m * (64 ±0) + p * (36 ±0)` + // Estimated: `10570 + m * (325 ±0) + p * (180 ±0)` + // Minimum execution time: 32_773_000 picoseconds. + Weight::from_parts(33_031_550, 10570) + // Standard Error: 1_205 + .saturating_add(Weight::from_parts(26_143, 0).saturating_mul(m.into())) + // Standard Error: 1_175 + .saturating_add(Weight::from_parts(137_503, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 325).saturating_mul(m.into())) @@ -270,16 +273,16 @@ impl WeightInfo for SubstrateWeight { /// The range of component `p` is `[1, 100]`. fn close_approved(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `982 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` - // Estimated: `10565 + b * (5 ±0) + m * (330 ±0) + p * (200 ±0)` - // Minimum execution time: 38_608 nanoseconds. - Weight::from_parts(39_948_329, 10565) - // Standard Error: 84 - .saturating_add(Weight::from_parts(2_045, 0).saturating_mul(b.into())) - // Standard Error: 895 - .saturating_add(Weight::from_parts(22_669, 0).saturating_mul(m.into())) - // Standard Error: 872 - .saturating_add(Weight::from_parts(95_525, 0).saturating_mul(p.into())) + // Measured: `852 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` + // Estimated: `14905 + b * (5 ±0) + m * (330 ±0) + p * (200 ±0)` + // Minimum execution time: 44_855_000 picoseconds. + Weight::from_parts(47_307_460, 14905) + // Standard Error: 100 + .saturating_add(Weight::from_parts(1_536, 0).saturating_mul(b.into())) + // Standard Error: 1_065 + .saturating_add(Weight::from_parts(20_549, 0).saturating_mul(m.into())) + // Standard Error: 1_038 + .saturating_add(Weight::from_parts(133_143, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 5).saturating_mul(b.into())) @@ -295,12 +298,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `p` is `[1, 100]`. fn disapprove_proposal(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `391 + p * (32 ±0)` - // Estimated: `1668 + p * (96 ±0)` - // Minimum execution time: 14_785 nanoseconds. - Weight::from_parts(16_393_818, 1668) - // Standard Error: 612 - .saturating_add(Weight::from_parts(76_786, 0).saturating_mul(p.into())) + // Measured: `359 + p * (32 ±0)` + // Estimated: `2562 + p * (96 ±0)` + // Minimum execution time: 16_420_000 picoseconds. + Weight::from_parts(18_236_525, 2562) + // Standard Error: 894 + .saturating_add(Weight::from_parts(115_590, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 96).saturating_mul(p.into())) @@ -322,20 +325,20 @@ impl WeightInfo for () { /// The range of component `p` is `[0, 100]`. fn set_members(m: u32, _n: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0 + m * (3233 ±0) + p * (3223 ±0)` - // Estimated: `16586 + m * (7809 ±24) + p * (10238 ±24)` - // Minimum execution time: 17_093 nanoseconds. - Weight::from_parts(17_284_000, 16586) - // Standard Error: 64_700 - .saturating_add(Weight::from_parts(5_143_145, 0).saturating_mul(m.into())) - // Standard Error: 64_700 - .saturating_add(Weight::from_parts(7_480_941, 0).saturating_mul(p.into())) + // Measured: `0 + m * (3232 ±0) + p * (3190 ±0)` + // Estimated: `19428 + m * (7799 ±24) + p * (10110 ±24)` + // Minimum execution time: 18_772_000 picoseconds. + Weight::from_parts(18_931_000, 19428) + // Standard Error: 65_247 + .saturating_add(Weight::from_parts(5_050_136, 0).saturating_mul(m.into())) + // Standard Error: 65_247 + .saturating_add(Weight::from_parts(8_235_069, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(p.into()))) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(p.into()))) - .saturating_add(Weight::from_parts(0, 7809).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 10238).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 7799).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 10110).saturating_mul(p.into())) } /// Storage: Council Members (r:1 w:0) /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) @@ -343,14 +346,14 @@ impl WeightInfo for () { /// The range of component `m` is `[1, 100]`. fn execute(b: u32, m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `234 + m * (32 ±0)` - // Estimated: `730 + m * (32 ±0)` - // Minimum execution time: 15_972 nanoseconds. - Weight::from_parts(14_971_445, 730) - // Standard Error: 32 - .saturating_add(Weight::from_parts(1_775, 0).saturating_mul(b.into())) - // Standard Error: 334 - .saturating_add(Weight::from_parts(17_052, 0).saturating_mul(m.into())) + // Measured: `202 + m * (32 ±0)` + // Estimated: `1688 + m * (32 ±0)` + // Minimum execution time: 17_741_000 picoseconds. + Weight::from_parts(17_580_031, 1688) + // Standard Error: 113 + .saturating_add(Weight::from_parts(941, 0).saturating_mul(b.into())) + // Standard Error: 1_170 + .saturating_add(Weight::from_parts(17_329, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(Weight::from_parts(0, 32).saturating_mul(m.into())) } @@ -362,14 +365,14 @@ impl WeightInfo for () { /// The range of component `m` is `[1, 100]`. fn propose_execute(b: u32, m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `234 + m * (32 ±0)` - // Estimated: `3440 + m * (64 ±0)` - // Minimum execution time: 17_950 nanoseconds. - Weight::from_parts(17_019_558, 3440) - // Standard Error: 41 - .saturating_add(Weight::from_parts(1_807, 0).saturating_mul(b.into())) - // Standard Error: 432 - .saturating_add(Weight::from_parts(27_986, 0).saturating_mul(m.into())) + // Measured: `202 + m * (32 ±0)` + // Estimated: `5356 + m * (64 ±0)` + // Minimum execution time: 20_214_000 picoseconds. + Weight::from_parts(19_508_816, 5356) + // Standard Error: 46 + .saturating_add(Weight::from_parts(1_646, 0).saturating_mul(b.into())) + // Standard Error: 475 + .saturating_add(Weight::from_parts(27_145, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) } @@ -388,16 +391,16 @@ impl WeightInfo for () { /// The range of component `p` is `[1, 100]`. fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `556 + m * (32 ±0) + p * (36 ±0)` - // Estimated: `6355 + m * (165 ±0) + p * (180 ±0)` - // Minimum execution time: 24_817 nanoseconds. - Weight::from_parts(24_778_955, 6355) - // Standard Error: 73 - .saturating_add(Weight::from_parts(2_355, 0).saturating_mul(b.into())) - // Standard Error: 765 - .saturating_add(Weight::from_parts(20_518, 0).saturating_mul(m.into())) - // Standard Error: 755 - .saturating_add(Weight::from_parts(85_670, 0).saturating_mul(p.into())) + // Measured: `492 + m * (32 ±0) + p * (36 ±0)` + // Estimated: `10015 + m * (165 ±0) + p * (180 ±0)` + // Minimum execution time: 27_872_000 picoseconds. + Weight::from_parts(28_010_227, 10015) + // Standard Error: 90 + .saturating_add(Weight::from_parts(2_643, 0).saturating_mul(b.into())) + // Standard Error: 944 + .saturating_add(Weight::from_parts(17_897, 0).saturating_mul(m.into())) + // Standard Error: 932 + .saturating_add(Weight::from_parts(122_368, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 165).saturating_mul(m.into())) @@ -410,12 +413,12 @@ impl WeightInfo for () { /// The range of component `m` is `[5, 100]`. fn vote(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1006 + m * (64 ±0)` - // Estimated: `4980 + m * (128 ±0)` - // Minimum execution time: 19_790 nanoseconds. - Weight::from_parts(20_528_275, 4980) - // Standard Error: 651 - .saturating_add(Weight::from_parts(48_856, 0).saturating_mul(m.into())) + // Measured: `941 + m * (64 ±0)` + // Estimated: `6830 + m * (128 ±0)` + // Minimum execution time: 22_518_000 picoseconds. + Weight::from_parts(23_281_512, 6830) + // Standard Error: 647 + .saturating_add(Weight::from_parts(53_974, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 128).saturating_mul(m.into())) @@ -432,14 +435,14 @@ impl WeightInfo for () { /// The range of component `p` is `[1, 100]`. fn close_early_disapproved(m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `626 + m * (64 ±0) + p * (36 ±0)` - // Estimated: `5893 + m * (260 ±0) + p * (144 ±0)` - // Minimum execution time: 25_564 nanoseconds. - Weight::from_parts(25_535_497, 5893) - // Standard Error: 610 - .saturating_add(Weight::from_parts(27_956, 0).saturating_mul(m.into())) - // Standard Error: 595 - .saturating_add(Weight::from_parts(84_835, 0).saturating_mul(p.into())) + // Measured: `530 + m * (64 ±0) + p * (36 ±0)` + // Estimated: `8475 + m * (260 ±0) + p * (144 ±0)` + // Minimum execution time: 29_020_000 picoseconds. + Weight::from_parts(29_009_937, 8475) + // Standard Error: 809 + .saturating_add(Weight::from_parts(31_952, 0).saturating_mul(m.into())) + // Standard Error: 789 + .saturating_add(Weight::from_parts(124_282, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 260).saturating_mul(m.into())) @@ -458,16 +461,16 @@ impl WeightInfo for () { /// The range of component `p` is `[1, 100]`. fn close_early_approved(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `962 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` - // Estimated: `9164 + b * (4 ±0) + m * (264 ±0) + p * (160 ±0)` - // Minimum execution time: 36_515 nanoseconds. - Weight::from_parts(36_626_648, 9164) - // Standard Error: 98 - .saturating_add(Weight::from_parts(2_295, 0).saturating_mul(b.into())) - // Standard Error: 1_036 - .saturating_add(Weight::from_parts(22_182, 0).saturating_mul(m.into())) - // Standard Error: 1_010 - .saturating_add(Weight::from_parts(100_034, 0).saturating_mul(p.into())) + // Measured: `832 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` + // Estimated: `12636 + b * (4 ±0) + m * (264 ±0) + p * (160 ±0)` + // Minimum execution time: 41_541_000 picoseconds. + Weight::from_parts(43_640_322, 12636) + // Standard Error: 104 + .saturating_add(Weight::from_parts(2_178, 0).saturating_mul(b.into())) + // Standard Error: 1_101 + .saturating_add(Weight::from_parts(20_512, 0).saturating_mul(m.into())) + // Standard Error: 1_073 + .saturating_add(Weight::from_parts(133_112, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 4).saturating_mul(b.into())) @@ -488,14 +491,14 @@ impl WeightInfo for () { /// The range of component `p` is `[1, 100]`. fn close_disapproved(m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `646 + m * (64 ±0) + p * (36 ±0)` - // Estimated: `7095 + m * (325 ±0) + p * (180 ±0)` - // Minimum execution time: 28_858 nanoseconds. - Weight::from_parts(28_050_047, 7095) - // Standard Error: 614 - .saturating_add(Weight::from_parts(34_031, 0).saturating_mul(m.into())) - // Standard Error: 599 - .saturating_add(Weight::from_parts(85_744, 0).saturating_mul(p.into())) + // Measured: `550 + m * (64 ±0) + p * (36 ±0)` + // Estimated: `10570 + m * (325 ±0) + p * (180 ±0)` + // Minimum execution time: 32_773_000 picoseconds. + Weight::from_parts(33_031_550, 10570) + // Standard Error: 1_205 + .saturating_add(Weight::from_parts(26_143, 0).saturating_mul(m.into())) + // Standard Error: 1_175 + .saturating_add(Weight::from_parts(137_503, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 325).saturating_mul(m.into())) @@ -516,16 +519,16 @@ impl WeightInfo for () { /// The range of component `p` is `[1, 100]`. fn close_approved(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `982 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` - // Estimated: `10565 + b * (5 ±0) + m * (330 ±0) + p * (200 ±0)` - // Minimum execution time: 38_608 nanoseconds. - Weight::from_parts(39_948_329, 10565) - // Standard Error: 84 - .saturating_add(Weight::from_parts(2_045, 0).saturating_mul(b.into())) - // Standard Error: 895 - .saturating_add(Weight::from_parts(22_669, 0).saturating_mul(m.into())) - // Standard Error: 872 - .saturating_add(Weight::from_parts(95_525, 0).saturating_mul(p.into())) + // Measured: `852 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` + // Estimated: `14905 + b * (5 ±0) + m * (330 ±0) + p * (200 ±0)` + // Minimum execution time: 44_855_000 picoseconds. + Weight::from_parts(47_307_460, 14905) + // Standard Error: 100 + .saturating_add(Weight::from_parts(1_536, 0).saturating_mul(b.into())) + // Standard Error: 1_065 + .saturating_add(Weight::from_parts(20_549, 0).saturating_mul(m.into())) + // Standard Error: 1_038 + .saturating_add(Weight::from_parts(133_143, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 5).saturating_mul(b.into())) @@ -541,12 +544,12 @@ impl WeightInfo for () { /// The range of component `p` is `[1, 100]`. fn disapprove_proposal(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `391 + p * (32 ±0)` - // Estimated: `1668 + p * (96 ±0)` - // Minimum execution time: 14_785 nanoseconds. - Weight::from_parts(16_393_818, 1668) - // Standard Error: 612 - .saturating_add(Weight::from_parts(76_786, 0).saturating_mul(p.into())) + // Measured: `359 + p * (32 ±0)` + // Estimated: `2562 + p * (96 ±0)` + // Minimum execution time: 16_420_000 picoseconds. + Weight::from_parts(18_236_525, 2562) + // Standard Error: 894 + .saturating_add(Weight::from_parts(115_590, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 96).saturating_mul(p.into())) diff --git a/frame/contracts/src/weights.rs b/frame/contracts/src/weights.rs index 14e680fb6a0ed..ae8638eb73431 100644 --- a/frame/contracts/src/weights.rs +++ b/frame/contracts/src/weights.rs @@ -18,26 +18,28 @@ //! Autogenerated weights for pallet_contracts //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("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 +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --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_contracts -// --chain=dev -// --header=./HEADER-APACHE2 // --output=./frame/contracts/src/weights.rs +// --header=./HEADER-APACHE2 // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -177,10 +179,9 @@ impl WeightInfo for SubstrateWeight { fn on_process_deletion_queue_batch() -> Weight { // Proof Size summary in bytes: // Measured: `109` - // Estimated: `604` - // Minimum execution time: 2_591 nanoseconds. - Weight::from_parts(2_817_000, 0) - .saturating_add(Weight::from_parts(0, 604)) + // Estimated: `1594` + // Minimum execution time: 2_679_000 picoseconds. + Weight::from_parts(2_907_000, 1594) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: Skipped Metadata (r:0 w:0) @@ -188,14 +189,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `k` is `[0, 1024]`. fn on_initialize_per_trie_key(k: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `481 + k * (69 ±0)` - // Estimated: `471 + k * (70 ±0)` - // Minimum execution time: 10_190 nanoseconds. - Weight::from_parts(6_642_117, 0) - .saturating_add(Weight::from_parts(0, 471)) - // Standard Error: 992 - .saturating_add(Weight::from_parts(919_828, 0).saturating_mul(k.into())) + // Measured: `450 + k * (69 ±0)` + // Estimated: `440 + k * (70 ±0)` + // Minimum execution time: 11_162_000 picoseconds. + Weight::from_parts(5_734_923, 440) + // Standard Error: 1_097 + .saturating_add(Weight::from_parts(976_647, 0).saturating_mul(k.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(k.into()))) .saturating_add(Weight::from_parts(0, 70).saturating_mul(k.into())) @@ -205,13 +206,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `q` is `[0, 128]`. fn on_initialize_per_queue_item(q: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `281 + q * (33 ±0)` - // Estimated: `763 + q * (33 ±0)` - // Minimum execution time: 2_598 nanoseconds. - Weight::from_parts(10_288_252, 0) - .saturating_add(Weight::from_parts(0, 763)) - // Standard Error: 2_886 - .saturating_add(Weight::from_parts(1_092_420, 0).saturating_mul(q.into())) + // Measured: `250 + q * (33 ±0)` + // Estimated: `1725 + q * (33 ±0)` + // Minimum execution time: 2_626_000 picoseconds. + Weight::from_parts(10_626_314, 1725) + // Standard Error: 4_006 + .saturating_add(Weight::from_parts(1_298_864, 0).saturating_mul(q.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 33).saturating_mul(q.into())) @@ -223,13 +223,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `c` is `[0, 61717]`. fn reinstrument(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `270 + c * (1 ±0)` - // Estimated: `3025 + c * (2 ±0)` - // Minimum execution time: 34_338 nanoseconds. - Weight::from_parts(32_159_677, 0) - .saturating_add(Weight::from_parts(0, 3025)) - // Standard Error: 53 - .saturating_add(Weight::from_parts(51_034, 0).saturating_mul(c.into())) + // Measured: `238 + c * (1 ±0)` + // Estimated: `3951 + c * (2 ±0)` + // Minimum execution time: 31_434_000 picoseconds. + Weight::from_parts(29_558_961, 3951) + // Standard Error: 55 + .saturating_add(Weight::from_parts(50_774, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 2).saturating_mul(c.into())) @@ -247,13 +246,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `c` is `[0, 125952]`. fn call_with_code_per_byte(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `803` - // Estimated: `16930 + c * (5 ±0)` - // Minimum execution time: 385_587 nanoseconds. - Weight::from_parts(395_545_811, 0) - .saturating_add(Weight::from_parts(0, 16930)) - // Standard Error: 27 - .saturating_add(Weight::from_parts(31_342, 0).saturating_mul(c.into())) + // Measured: `707` + // Estimated: `21400 + c * (5 ±0)` + // Minimum execution time: 309_015_000 picoseconds. + Weight::from_parts(318_740_885, 21400) + // Standard Error: 29 + .saturating_add(Weight::from_parts(30_993, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 5).saturating_mul(c.into())) @@ -280,16 +278,15 @@ impl WeightInfo for SubstrateWeight { fn instantiate_with_code(c: u32, i: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `270` - // Estimated: `20267` - // Minimum execution time: 3_799_742 nanoseconds. - Weight::from_parts(670_115_588, 0) - .saturating_add(Weight::from_parts(0, 20267)) - // Standard Error: 287 - .saturating_add(Weight::from_parts(93_885, 0).saturating_mul(c.into())) - // Standard Error: 16 - .saturating_add(Weight::from_parts(1_367, 0).saturating_mul(i.into())) - // Standard Error: 16 - .saturating_add(Weight::from_parts(1_781, 0).saturating_mul(s.into())) + // Estimated: `26207` + // Minimum execution time: 3_126_495_000 picoseconds. + Weight::from_parts(636_857_878, 26207) + // Standard Error: 294 + .saturating_add(Weight::from_parts(92_930, 0).saturating_mul(c.into())) + // Standard Error: 17 + .saturating_add(Weight::from_parts(1_128, 0).saturating_mul(i.into())) + // Standard Error: 17 + .saturating_add(Weight::from_parts(1_415, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(10_u64)) } @@ -311,15 +308,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[0, 1048576]`. fn instantiate(i: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `546` - // Estimated: `22039` - // Minimum execution time: 1_949_008 nanoseconds. - Weight::from_parts(214_033_418, 0) - .saturating_add(Weight::from_parts(0, 22039)) + // Measured: `482` + // Estimated: `28521` + // Minimum execution time: 1_591_415_000 picoseconds. + Weight::from_parts(228_633_516, 28521) // Standard Error: 8 - .saturating_add(Weight::from_parts(1_666, 0).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(1_449, 0).saturating_mul(i.into())) // Standard Error: 8 - .saturating_add(Weight::from_parts(1_801, 0).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_444, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } @@ -335,11 +331,10 @@ impl WeightInfo for SubstrateWeight { /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) fn call() -> Weight { // Proof Size summary in bytes: - // Measured: `855` - // Estimated: `17145` - // Minimum execution time: 146_654 nanoseconds. - Weight::from_parts(147_528_000, 0) - .saturating_add(Weight::from_parts(0, 17145)) + // Measured: `759` + // Estimated: `21615` + // Minimum execution time: 167_905_000 picoseconds. + Weight::from_parts(169_247_000, 21615) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -355,12 +350,11 @@ impl WeightInfo for SubstrateWeight { fn upload_code(c: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `109` - // Estimated: `5386` - // Minimum execution time: 387_889 nanoseconds. - Weight::from_parts(391_379_335, 0) - .saturating_add(Weight::from_parts(0, 5386)) - // Standard Error: 89 - .saturating_add(Weight::from_parts(94_810, 0).saturating_mul(c.into())) + // Estimated: `7366` + // Minimum execution time: 305_128_000 picoseconds. + Weight::from_parts(310_911_395, 7366) + // Standard Error: 70 + .saturating_add(Weight::from_parts(94_067, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -374,11 +368,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Contracts PristineCode (max_values: None, max_size: Some(125988), added: 128463, mode: Measured) fn remove_code() -> Weight { // Proof Size summary in bytes: - // Measured: `287` - // Estimated: `6098` - // Minimum execution time: 26_014 nanoseconds. - Weight::from_parts(26_510_000, 0) - .saturating_add(Weight::from_parts(0, 6098)) + // Measured: `255` + // Estimated: `7950` + // Minimum execution time: 29_605_000 picoseconds. + Weight::from_parts(29_986_000, 7950) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -390,11 +383,10 @@ impl WeightInfo for SubstrateWeight { /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) fn set_code() -> Weight { // Proof Size summary in bytes: - // Measured: `666` - // Estimated: `16848` - // Minimum execution time: 30_177 nanoseconds. - Weight::from_parts(30_639_000, 0) - .saturating_add(Weight::from_parts(0, 16848)) + // Measured: `570` + // Estimated: `19530` + // Minimum execution time: 33_824_000 picoseconds. + Weight::from_parts(34_388_000, 19530) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -411,13 +403,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_caller(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `877 + r * (480 ±0)` - // Estimated: `17295 + r * (2400 ±0)` - // Minimum execution time: 373_786 nanoseconds. - Weight::from_parts(377_332_691, 0) - .saturating_add(Weight::from_parts(0, 17295)) - // Standard Error: 51_211 - .saturating_add(Weight::from_parts(17_715_615, 0).saturating_mul(r.into())) + // Measured: `781 + r * (480 ±0)` + // Estimated: `21765 + r * (2400 ±0)` + // Minimum execution time: 295_283_000 picoseconds. + Weight::from_parts(295_895_211, 21765) + // Standard Error: 44_860 + .saturating_add(Weight::from_parts(22_913_078, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 2400).saturating_mul(r.into())) @@ -435,17 +426,16 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_is_contract(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `917 + r * (21778 ±0)` - // Estimated: `17295 + r * (306895 ±0)` - // Minimum execution time: 374_009 nanoseconds. - Weight::from_parts(238_991_986, 0) - .saturating_add(Weight::from_parts(0, 17295)) - // Standard Error: 464_711 - .saturating_add(Weight::from_parts(249_099_538, 0).saturating_mul(r.into())) + // Measured: `821 + r * (19218 ±0)` + // Estimated: `21765 + r * (294095 ±0)` + // Minimum execution time: 295_760_000 picoseconds. + Weight::from_parts(151_512_811, 21765) + // Standard Error: 522_974 + .saturating_add(Weight::from_parts(263_028_353, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 306895).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 294095).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -460,17 +450,16 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_code_hash(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `921 + r * (22099 ±0)` - // Estimated: `17340 + r * (308500 ±0)` - // Minimum execution time: 375_058 nanoseconds. - Weight::from_parts(238_765_068, 0) - .saturating_add(Weight::from_parts(0, 17340)) - // Standard Error: 662_617 - .saturating_add(Weight::from_parts(302_175_089, 0).saturating_mul(r.into())) + // Measured: `825 + r * (19539 ±0)` + // Estimated: `21810 + r * (295700 ±0)` + // Minimum execution time: 295_950_000 picoseconds. + Weight::from_parts(164_516_076, 21810) + // Standard Error: 469_540 + .saturating_add(Weight::from_parts(321_138_601, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 308500).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 295700).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -485,13 +474,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_own_code_hash(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `884 + r * (480 ±0)` - // Estimated: `17330 + r * (2400 ±0)` - // Minimum execution time: 374_747 nanoseconds. - Weight::from_parts(376_482_380, 0) - .saturating_add(Weight::from_parts(0, 17330)) - // Standard Error: 61_919 - .saturating_add(Weight::from_parts(22_376_795, 0).saturating_mul(r.into())) + // Measured: `788 + r * (480 ±0)` + // Estimated: `21800 + r * (2400 ±0)` + // Minimum execution time: 295_916_000 picoseconds. + Weight::from_parts(299_964_913, 21800) + // Standard Error: 78_211 + .saturating_add(Weight::from_parts(28_933_603, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 2400).saturating_mul(r.into())) @@ -509,13 +497,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_caller_is_origin(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `874 + r * (240 ±0)` - // Estimated: `17265 + r * (1200 ±0)` - // Minimum execution time: 372_287 nanoseconds. - Weight::from_parts(376_250_858, 0) - .saturating_add(Weight::from_parts(0, 17265)) - // Standard Error: 40_119 - .saturating_add(Weight::from_parts(11_359_647, 0).saturating_mul(r.into())) + // Measured: `778 + r * (240 ±0)` + // Estimated: `21735 + r * (1200 ±0)` + // Minimum execution time: 293_588_000 picoseconds. + Weight::from_parts(297_568_984, 21735) + // Standard Error: 35_513 + .saturating_add(Weight::from_parts(11_074_880, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1200).saturating_mul(r.into())) @@ -533,13 +520,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_address(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `878 + r * (480 ±0)` - // Estimated: `17260 + r * (2400 ±0)` - // Minimum execution time: 374_445 nanoseconds. - Weight::from_parts(377_243_521, 0) - .saturating_add(Weight::from_parts(0, 17260)) - // Standard Error: 53_032 - .saturating_add(Weight::from_parts(17_684_246, 0).saturating_mul(r.into())) + // Measured: `782 + r * (480 ±0)` + // Estimated: `21730 + r * (2400 ±0)` + // Minimum execution time: 294_929_000 picoseconds. + Weight::from_parts(295_916_817, 21730) + // Standard Error: 64_902 + .saturating_add(Weight::from_parts(22_944_018, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 2400).saturating_mul(r.into())) @@ -557,13 +543,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_gas_left(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `879 + r * (480 ±0)` - // Estimated: `17250 + r * (2405 ±0)` - // Minimum execution time: 374_029 nanoseconds. - Weight::from_parts(380_415_186, 0) - .saturating_add(Weight::from_parts(0, 17250)) - // Standard Error: 60_562 - .saturating_add(Weight::from_parts(17_152_599, 0).saturating_mul(r.into())) + // Measured: `783 + r * (480 ±0)` + // Estimated: `21720 + r * (2405 ±0)` + // Minimum execution time: 296_783_000 picoseconds. + Weight::from_parts(299_399_332, 21720) + // Standard Error: 50_982 + .saturating_add(Weight::from_parts(22_173_249, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 2405).saturating_mul(r.into())) @@ -581,16 +566,15 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_balance(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1049 + r * (480 ±0)` - // Estimated: `19849 + r * (2456 ±0)` - // Minimum execution time: 373_999 nanoseconds. - Weight::from_parts(381_757_033, 0) - .saturating_add(Weight::from_parts(0, 19849)) - // Standard Error: 97_983 - .saturating_add(Weight::from_parts(98_290_984, 0).saturating_mul(r.into())) + // Measured: `921 + r * (480 ±0)` + // Estimated: `24193 + r * (2451 ±0)` + // Minimum execution time: 294_120_000 picoseconds. + Weight::from_parts(305_889_989, 24193) + // Standard Error: 116_244 + .saturating_add(Weight::from_parts(114_781_094, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 2456).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 2451).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -605,13 +589,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_value_transferred(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `888 + r * (480 ±0)` - // Estimated: `17360 + r * (2400 ±0)` - // Minimum execution time: 374_197 nanoseconds. - Weight::from_parts(377_755_896, 0) - .saturating_add(Weight::from_parts(0, 17360)) - // Standard Error: 60_542 - .saturating_add(Weight::from_parts(17_442_065, 0).saturating_mul(r.into())) + // Measured: `792 + r * (480 ±0)` + // Estimated: `21830 + r * (2400 ±0)` + // Minimum execution time: 295_569_000 picoseconds. + Weight::from_parts(299_774_774, 21830) + // Standard Error: 46_252 + .saturating_add(Weight::from_parts(21_753_842, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 2400).saturating_mul(r.into())) @@ -629,13 +612,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_minimum_balance(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `886 + r * (480 ±0)` - // Estimated: `17290 + r * (2400 ±0)` - // Minimum execution time: 373_888 nanoseconds. - Weight::from_parts(377_825_771, 0) - .saturating_add(Weight::from_parts(0, 17290)) - // Standard Error: 38_026 - .saturating_add(Weight::from_parts(17_147_903, 0).saturating_mul(r.into())) + // Measured: `790 + r * (480 ±0)` + // Estimated: `21760 + r * (2400 ±0)` + // Minimum execution time: 295_400_000 picoseconds. + Weight::from_parts(300_637_266, 21760) + // Standard Error: 41_263 + .saturating_add(Weight::from_parts(21_565_466, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 2400).saturating_mul(r.into())) @@ -653,13 +635,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_block_number(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `883 + r * (480 ±0)` - // Estimated: `17315 + r * (2400 ±0)` - // Minimum execution time: 373_904 nanoseconds. - Weight::from_parts(378_652_372, 0) - .saturating_add(Weight::from_parts(0, 17315)) - // Standard Error: 43_833 - .saturating_add(Weight::from_parts(16_936_781, 0).saturating_mul(r.into())) + // Measured: `787 + r * (480 ±0)` + // Estimated: `21785 + r * (2400 ±0)` + // Minimum execution time: 294_696_000 picoseconds. + Weight::from_parts(297_196_796, 21785) + // Standard Error: 61_173 + .saturating_add(Weight::from_parts(21_903_191, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 2400).saturating_mul(r.into())) @@ -677,13 +658,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_now(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `874 + r * (480 ±0)` - // Estimated: `17245 + r * (2400 ±0)` - // Minimum execution time: 373_473 nanoseconds. - Weight::from_parts(376_386_312, 0) - .saturating_add(Weight::from_parts(0, 17245)) - // Standard Error: 46_945 - .saturating_add(Weight::from_parts(17_336_462, 0).saturating_mul(r.into())) + // Measured: `778 + r * (480 ±0)` + // Estimated: `21715 + r * (2400 ±0)` + // Minimum execution time: 297_714_000 picoseconds. + Weight::from_parts(306_030_237, 21715) + // Standard Error: 69_984 + .saturating_add(Weight::from_parts(21_744_413, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 2400).saturating_mul(r.into())) @@ -703,13 +683,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_weight_to_fee(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `951 + r * (800 ±0)` - // Estimated: `19046 + r * (4805 ±0)` - // Minimum execution time: 373_661 nanoseconds. - Weight::from_parts(385_824_015, 0) - .saturating_add(Weight::from_parts(0, 19046)) - // Standard Error: 75_964 - .saturating_add(Weight::from_parts(88_530_074, 0).saturating_mul(r.into())) + // Measured: `856 + r * (800 ±0)` + // Estimated: `24416 + r * (4805 ±0)` + // Minimum execution time: 295_180_000 picoseconds. + Weight::from_parts(308_851_025, 24416) + // Standard Error: 115_126 + .saturating_add(Weight::from_parts(98_678_404, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 4805).saturating_mul(r.into())) @@ -727,13 +706,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_gas(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `841 + r * (320 ±0)` - // Estimated: `17120 + r * (1600 ±0)` - // Minimum execution time: 133_849 nanoseconds. - Weight::from_parts(137_283_391, 0) - .saturating_add(Weight::from_parts(0, 17120)) - // Standard Error: 13_312 - .saturating_add(Weight::from_parts(8_055_328, 0).saturating_mul(r.into())) + // Measured: `745 + r * (320 ±0)` + // Estimated: `21590 + r * (1600 ±0)` + // Minimum execution time: 151_587_000 picoseconds. + Weight::from_parts(155_713_096, 21590) + // Standard Error: 32_464 + .saturating_add(Weight::from_parts(8_332_778, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1600).saturating_mul(r.into())) @@ -751,13 +729,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_input(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `876 + r * (480 ±0)` - // Estimated: `17245 + r * (2400 ±0)` - // Minimum execution time: 373_468 nanoseconds. - Weight::from_parts(376_121_093, 0) - .saturating_add(Weight::from_parts(0, 17245)) - // Standard Error: 61_857 - .saturating_add(Weight::from_parts(15_868_414, 0).saturating_mul(r.into())) + // Measured: `780 + r * (480 ±0)` + // Estimated: `21715 + r * (2400 ±0)` + // Minimum execution time: 295_008_000 picoseconds. + Weight::from_parts(297_982_800, 21715) + // Standard Error: 37_480 + .saturating_add(Weight::from_parts(17_970_520, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 2400).saturating_mul(r.into())) @@ -775,13 +752,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 1024]`. fn seal_input_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1356` - // Estimated: `19650` - // Minimum execution time: 390_668 nanoseconds. - Weight::from_parts(419_608_449, 0) - .saturating_add(Weight::from_parts(0, 19650)) - // Standard Error: 4_890 - .saturating_add(Weight::from_parts(9_672_288, 0).saturating_mul(n.into())) + // Measured: `1260` + // Estimated: `24120` + // Minimum execution time: 314_970_000 picoseconds. + Weight::from_parts(345_339_508, 24120) + // Standard Error: 4_112 + .saturating_add(Weight::from_parts(9_746_966, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -798,13 +774,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1]`. fn seal_return(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `864 + r * (45 ±0)` - // Estimated: `17190 + r * (225 ±0)` - // Minimum execution time: 371_309 nanoseconds. - Weight::from_parts(373_625_402, 0) - .saturating_add(Weight::from_parts(0, 17190)) - // Standard Error: 419_605 - .saturating_add(Weight::from_parts(1_737_397, 0).saturating_mul(r.into())) + // Measured: `768 + r * (45 ±0)` + // Estimated: `21660 + r * (225 ±0)` + // Minimum execution time: 293_072_000 picoseconds. + Weight::from_parts(295_694_824, 21660) + // Standard Error: 219_523 + .saturating_add(Weight::from_parts(783_975, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 225).saturating_mul(r.into())) @@ -822,13 +797,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 1024]`. fn seal_return_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `874` - // Estimated: `17285` - // Minimum execution time: 374_094 nanoseconds. - Weight::from_parts(375_965_200, 0) - .saturating_add(Weight::from_parts(0, 17285)) - // Standard Error: 1_127 - .saturating_add(Weight::from_parts(232_645, 0).saturating_mul(n.into())) + // Measured: `778` + // Estimated: `21755` + // Minimum execution time: 295_959_000 picoseconds. + Weight::from_parts(299_004_761, 21755) + // Standard Error: 3_988 + .saturating_add(Weight::from_parts(194_268, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -849,18 +823,17 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1]`. fn seal_terminate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `906 + r * (452 ±0)` - // Estimated: `20242 + r * (15004 ±0)` - // Minimum execution time: 373_123 nanoseconds. - Weight::from_parts(374_924_634, 0) - .saturating_add(Weight::from_parts(0, 20242)) - // Standard Error: 378_010 - .saturating_add(Weight::from_parts(70_441_665, 0).saturating_mul(r.into())) + // Measured: `810 + r * (356 ±0)` + // Estimated: `25511 + r * (15321 ±0)` + // Minimum execution time: 294_626_000 picoseconds. + Weight::from_parts(297_839_179, 25511) + // Standard Error: 707_428 + .saturating_add(Weight::from_parts(81_507_620, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((6_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((7_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 15004).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 15321).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -877,13 +850,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_random(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `921 + r * (800 ±0)` - // Estimated: `18835 + r * (4805 ±0)` - // Minimum execution time: 373_291 nanoseconds. - Weight::from_parts(385_684_344, 0) - .saturating_add(Weight::from_parts(0, 18835)) - // Standard Error: 99_025 - .saturating_add(Weight::from_parts(111_308_793, 0).saturating_mul(r.into())) + // Measured: `825 + r * (800 ±0)` + // Estimated: `24199 + r * (4805 ±0)` + // Minimum execution time: 295_431_000 picoseconds. + Weight::from_parts(310_428_531, 24199) + // Standard Error: 143_501 + .saturating_add(Weight::from_parts(136_529_376, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 4805).saturating_mul(r.into())) @@ -901,13 +873,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_deposit_event(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `874 + r * (800 ±0)` - // Estimated: `17250 + r * (4000 ±0)` - // Minimum execution time: 371_900 nanoseconds. - Weight::from_parts(384_166_626, 0) - .saturating_add(Weight::from_parts(0, 17250)) - // Standard Error: 205_255 - .saturating_add(Weight::from_parts(229_214_157, 0).saturating_mul(r.into())) + // Measured: `778 + r * (800 ±0)` + // Estimated: `21720 + r * (4000 ±0)` + // Minimum execution time: 293_778_000 picoseconds. + Weight::from_parts(323_404_081, 21720) + // Standard Error: 243_095 + .saturating_add(Weight::from_parts(269_012_482, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 4000).saturating_mul(r.into())) @@ -926,15 +897,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 16]`. fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1821 + t * (2608 ±0) + n * (7 ±0)` - // Estimated: `21870 + t * (211030 ±0) + n * (50 ±0)` - // Minimum execution time: 1_289_873 nanoseconds. - Weight::from_parts(581_702_206, 0) - .saturating_add(Weight::from_parts(0, 21870)) - // Standard Error: 665_638 - .saturating_add(Weight::from_parts(181_470_553, 0).saturating_mul(t.into())) - // Standard Error: 182_816 - .saturating_add(Weight::from_parts(71_635_250, 0).saturating_mul(n.into())) + // Measured: `1725 + t * (2608 ±0) + n * (7 ±0)` + // Estimated: `26340 + t * (211030 ±0) + n * (50 ±0)` + // Minimum execution time: 1_317_129_000 picoseconds. + Weight::from_parts(566_722_295, 26340) + // Standard Error: 619_390 + .saturating_add(Weight::from_parts(194_334_643, 0).saturating_mul(t.into())) + // Standard Error: 170_114 + .saturating_add(Weight::from_parts(67_458_751, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(t.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -955,13 +925,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_debug_message(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `873 + r * (560 ±0)` - // Estimated: `17240 + r * (2800 ±0)` - // Minimum execution time: 148_635 nanoseconds. - Weight::from_parts(154_095_712, 0) - .saturating_add(Weight::from_parts(0, 17240)) - // Standard Error: 77_790 - .saturating_add(Weight::from_parts(14_837_085, 0).saturating_mul(r.into())) + // Measured: `777 + r * (560 ±0)` + // Estimated: `21710 + r * (2800 ±0)` + // Minimum execution time: 159_087_000 picoseconds. + Weight::from_parts(163_703_981, 21710) + // Standard Error: 26_067 + .saturating_add(Weight::from_parts(14_810_256, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 2800).saturating_mul(r.into())) @@ -979,13 +948,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `i` is `[0, 1024]`. fn seal_debug_message_per_kb(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `125824` - // Estimated: `265128` - // Minimum execution time: 501_014 nanoseconds. - Weight::from_parts(505_634_218, 0) - .saturating_add(Weight::from_parts(0, 265128)) - // Standard Error: 2_441 - .saturating_add(Weight::from_parts(819_257, 0).saturating_mul(i.into())) + // Measured: `125728` + // Estimated: `269982` + // Minimum execution time: 413_391_000 picoseconds. + Weight::from_parts(414_927_640, 269982) + // Standard Error: 1_740 + .saturating_add(Weight::from_parts(763_359, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -994,13 +962,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 10]`. fn seal_set_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `911 + r * (23420 ±0)` - // Estimated: `911 + r * (23418 ±0)` - // Minimum execution time: 375_301 nanoseconds. - Weight::from_parts(291_498_841, 0) - .saturating_add(Weight::from_parts(0, 911)) - // Standard Error: 809_989 - .saturating_add(Weight::from_parts(464_550_291, 0).saturating_mul(r.into())) + // Measured: `815 + r * (23420 ±0)` + // Estimated: `815 + r * (23418 ±0)` + // Minimum execution time: 296_108_000 picoseconds. + Weight::from_parts(208_214_040, 815) + // Standard Error: 860_573 + .saturating_add(Weight::from_parts(480_342_550, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1012,13 +979,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_new_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `12672 + n * (11945 ±0)` - // Estimated: `8529 + n * (12814 ±61)` - // Minimum execution time: 506_318 nanoseconds. - Weight::from_parts(676_935_313, 0) - .saturating_add(Weight::from_parts(0, 8529)) - // Standard Error: 1_589_291 - .saturating_add(Weight::from_parts(97_839_399, 0).saturating_mul(n.into())) + // Measured: `12544 + n * (11945 ±0)` + // Estimated: `8401 + n * (12814 ±61)` + // Minimum execution time: 442_286_000 picoseconds. + Weight::from_parts(620_395_299, 8401) + // Standard Error: 1_661_554 + .saturating_add(Weight::from_parts(89_393_169, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(52_u64)) .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(50_u64)) @@ -1030,31 +996,29 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_old_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `15170 + n * (175775 ±0)` - // Estimated: `9914 + n * (176858 ±74)` - // Minimum execution time: 506_148 nanoseconds. - Weight::from_parts(648_278_778, 0) - .saturating_add(Weight::from_parts(0, 9914)) - // Standard Error: 1_343_586 - .saturating_add(Weight::from_parts(65_789_595, 0).saturating_mul(n.into())) + // Measured: `12532 + n * (175784 ±0)` + // Estimated: `8396 + n * (176649 ±61)` + // Minimum execution time: 440_882_000 picoseconds. + Weight::from_parts(587_317_981, 8396) + // Standard Error: 1_374_991 + .saturating_add(Weight::from_parts(66_271_084, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(51_u64)) .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(49_u64)) .saturating_add(T::DbWeight::get().writes((7_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 176858).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 176649).saturating_mul(n.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 10]`. fn seal_clear_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `903 + r * (23099 ±0)` - // Estimated: `908 + r * (23099 ±0)` - // Minimum execution time: 374_344 nanoseconds. - Weight::from_parts(293_272_061, 0) - .saturating_add(Weight::from_parts(0, 908)) - // Standard Error: 810_412 - .saturating_add(Weight::from_parts(453_315_956, 0).saturating_mul(r.into())) + // Measured: `807 + r * (23099 ±0)` + // Estimated: `812 + r * (23099 ±0)` + // Minimum execution time: 296_023_000 picoseconds. + Weight::from_parts(221_471_559, 812) + // Standard Error: 814_503 + .saturating_add(Weight::from_parts(465_928_089, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1066,31 +1030,29 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 8]`. fn seal_clear_storage_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `14895 + n * (175768 ±0)` - // Estimated: `9551 + n * (176867 ±75)` - // Minimum execution time: 478_564 nanoseconds. - Weight::from_parts(630_839_142, 0) - .saturating_add(Weight::from_parts(0, 9551)) - // Standard Error: 1_427_520 - .saturating_add(Weight::from_parts(66_813_592, 0).saturating_mul(n.into())) + // Measured: `12256 + n * (175776 ±0)` + // Estimated: `8047 + n * (176655 ±62)` + // Minimum execution time: 412_212_000 picoseconds. + Weight::from_parts(569_213_147, 8047) + // Standard Error: 1_463_771 + .saturating_add(Weight::from_parts(67_932_081, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(51_u64)) .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(48_u64)) .saturating_add(T::DbWeight::get().writes((7_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 176867).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 176655).saturating_mul(n.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 10]`. fn seal_get_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `896 + r * (23744 ±0)` - // Estimated: `909 + r * (23740 ±0)` - // Minimum execution time: 374_479 nanoseconds. - Weight::from_parts(311_839_315, 0) - .saturating_add(Weight::from_parts(0, 909)) - // Standard Error: 666_553 - .saturating_add(Weight::from_parts(371_213_042, 0).saturating_mul(r.into())) + // Measured: `800 + r * (23744 ±0)` + // Estimated: `813 + r * (23740 ±0)` + // Minimum execution time: 296_007_000 picoseconds. + Weight::from_parts(229_100_700, 813) + // Standard Error: 684_970 + .saturating_add(Weight::from_parts(394_982_991, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1101,30 +1063,28 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 8]`. fn seal_get_storage_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `15501 + n * (175775 ±0)` - // Estimated: `10042 + n * (176900 ±76)` - // Minimum execution time: 460_639 nanoseconds. - Weight::from_parts(591_187_094, 0) - .saturating_add(Weight::from_parts(0, 10042)) - // Standard Error: 1_233_792 - .saturating_add(Weight::from_parts(160_874_477, 0).saturating_mul(n.into())) + // Measured: `12863 + n * (175784 ±0)` + // Estimated: `8538 + n * (176688 ±63)` + // Minimum execution time: 392_306_000 picoseconds. + Weight::from_parts(539_188_004, 8538) + // Standard Error: 1_371_839 + .saturating_add(Weight::from_parts(155_130_373, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(51_u64)) .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 176900).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 176688).saturating_mul(n.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 10]`. fn seal_contains_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `914 + r * (23098 ±0)` - // Estimated: `920 + r * (23098 ±0)` - // Minimum execution time: 374_272 nanoseconds. - Weight::from_parts(311_446_269, 0) - .saturating_add(Weight::from_parts(0, 920)) - // Standard Error: 630_307 - .saturating_add(Weight::from_parts(357_134_931, 0).saturating_mul(r.into())) + // Measured: `818 + r * (23098 ±0)` + // Estimated: `824 + r * (23098 ±0)` + // Minimum execution time: 296_038_000 picoseconds. + Weight::from_parts(229_462_798, 824) + // Standard Error: 655_463 + .saturating_add(Weight::from_parts(372_593_685, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1135,30 +1095,28 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 8]`. fn seal_contains_storage_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `14839 + n * (175789 ±0)` - // Estimated: `9532 + n * (176874 ±75)` - // Minimum execution time: 456_013 nanoseconds. - Weight::from_parts(575_116_352, 0) - .saturating_add(Weight::from_parts(0, 9532)) - // Standard Error: 1_122_298 - .saturating_add(Weight::from_parts(61_786_107, 0).saturating_mul(n.into())) + // Measured: `12200 + n * (175798 ±0)` + // Estimated: `8028 + n * (176661 ±62)` + // Minimum execution time: 386_782_000 picoseconds. + Weight::from_parts(512_965_975, 8028) + // Standard Error: 1_168_132 + .saturating_add(Weight::from_parts(63_307_325, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(51_u64)) .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 176874).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 176661).saturating_mul(n.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 10]`. fn seal_take_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `911 + r * (23740 ±0)` - // Estimated: `913 + r * (23739 ±0)` - // Minimum execution time: 374_621 nanoseconds. - Weight::from_parts(299_689_489, 0) - .saturating_add(Weight::from_parts(0, 913)) - // Standard Error: 757_735 - .saturating_add(Weight::from_parts(465_213_246, 0).saturating_mul(r.into())) + // Measured: `815 + r * (23740 ±0)` + // Estimated: `817 + r * (23739 ±0)` + // Minimum execution time: 296_352_000 picoseconds. + Weight::from_parts(212_661_296, 817) + // Standard Error: 879_297 + .saturating_add(Weight::from_parts(494_182_672, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1170,18 +1128,17 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 8]`. fn seal_take_storage_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `15502 + n * (175775 ±0)` - // Estimated: `10042 + n * (176898 ±76)` - // Minimum execution time: 481_980 nanoseconds. - Weight::from_parts(647_289_053, 0) - .saturating_add(Weight::from_parts(0, 10042)) - // Standard Error: 1_556_155 - .saturating_add(Weight::from_parts(166_592_657, 0).saturating_mul(n.into())) + // Measured: `12864 + n * (175784 ±0)` + // Estimated: `8539 + n * (176686 ±63)` + // Minimum execution time: 414_693_000 picoseconds. + Weight::from_parts(595_693_859, 8539) + // Standard Error: 1_673_819 + .saturating_add(Weight::from_parts(163_090_316, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(51_u64)) .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(48_u64)) .saturating_add(T::DbWeight::get().writes((7_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 176898).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 176686).saturating_mul(n.into())) } /// Storage: System Account (r:1602 w:1601) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1196,18 +1153,17 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_transfer(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1457 + r * (3604 ±0)` - // Estimated: `21583 + r * (216101 ±0)` - // Minimum execution time: 374_962 nanoseconds. - Weight::from_parts(313_416_386, 0) - .saturating_add(Weight::from_parts(0, 21583)) - // Standard Error: 710_675 - .saturating_add(Weight::from_parts(1_396_551_156, 0).saturating_mul(r.into())) + // Measured: `1329 + r * (3604 ±0)` + // Estimated: `25928 + r * (216096 ±4)` + // Minimum execution time: 299_205_000 picoseconds. + Weight::from_parts(221_142_217, 25928) + // Standard Error: 1_369_909 + .saturating_add(Weight::from_parts(1_665_917_241, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(T::DbWeight::get().writes((80_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 216101).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 216096).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1222,18 +1178,17 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_call(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1609 + r * (23073 ±0)` - // Estimated: `22098 + r * (511456 ±1)` - // Minimum execution time: 375_916 nanoseconds. - Weight::from_parts(376_468_000, 0) - .saturating_add(Weight::from_parts(0, 22098)) - // Standard Error: 7_246_855 - .saturating_add(Weight::from_parts(28_982_425_139, 0).saturating_mul(r.into())) + // Measured: `1479 + r * (20514 ±0)` + // Estimated: `26429 + r * (498656 ±1)` + // Minimum execution time: 297_501_000 picoseconds. + Weight::from_parts(298_400_000, 26429) + // Standard Error: 9_372_890 + .saturating_add(Weight::from_parts(22_507_984_433, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().reads((160_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((160_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 511456).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 498656).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1248,18 +1203,17 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_delegate_call(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0 + r * (71670 ±0)` - // Estimated: `17285 + r * (659930 ±563)` - // Minimum execution time: 375_412 nanoseconds. - Weight::from_parts(376_493_000, 0) - .saturating_add(Weight::from_parts(0, 17285)) - // Standard Error: 8_239_575 - .saturating_add(Weight::from_parts(28_716_347_183, 0).saturating_mul(r.into())) + // Measured: `0 + r * (69030 ±0)` + // Estimated: `21755 + r * (647542 ±560)` + // Minimum execution time: 297_432_000 picoseconds. + Weight::from_parts(298_220_000, 21755) + // Standard Error: 9_420_834 + .saturating_add(Weight::from_parts(22_261_152_353, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((150_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((75_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 659930).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 647542).saturating_mul(r.into())) } /// Storage: System Account (r:82 w:81) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1275,20 +1229,19 @@ impl WeightInfo for SubstrateWeight { /// The range of component `c` is `[0, 1024]`. fn seal_call_per_transfer_clone_kb(t: u32, c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `24269 + t * (16910 ±0)` - // Estimated: `532690 + t * (285025 ±0)` - // Minimum execution time: 10_443_315 nanoseconds. - Weight::from_parts(9_342_574_069, 0) - .saturating_add(Weight::from_parts(0, 532690)) - // Standard Error: 7_237_279 - .saturating_add(Weight::from_parts(1_390_221_936, 0).saturating_mul(t.into())) - // Standard Error: 10_851 - .saturating_add(Weight::from_parts(9_842_151, 0).saturating_mul(c.into())) + // Measured: `21581 + t * (14318 ±0)` + // Estimated: `524200 + t * (272065 ±0)` + // Minimum execution time: 11_799_802_000 picoseconds. + Weight::from_parts(10_575_328_547, 524200) + // Standard Error: 11_952_810 + .saturating_add(Weight::from_parts(1_603_077_083, 0).saturating_mul(t.into())) + // Standard Error: 17_922 + .saturating_add(Weight::from_parts(9_876_752, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(167_u64)) .saturating_add(T::DbWeight::get().reads((81_u64).saturating_mul(t.into()))) .saturating_add(T::DbWeight::get().writes(163_u64)) .saturating_add(T::DbWeight::get().writes((81_u64).saturating_mul(t.into()))) - .saturating_add(Weight::from_parts(0, 285025).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(0, 272065).saturating_mul(t.into())) } /// Storage: System Account (r:3202 w:3202) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1307,18 +1260,17 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_instantiate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1775 + r * (25568 ±0)` - // Estimated: `26563 + r * (1367114 ±2)` - // Minimum execution time: 376_418 nanoseconds. - Weight::from_parts(377_292_000, 0) - .saturating_add(Weight::from_parts(0, 26563)) - // Standard Error: 32_312_545 - .saturating_add(Weight::from_parts(35_904_826_312, 0).saturating_mul(r.into())) + // Measured: `1646 + r * (20288 ±0)` + // Estimated: `32625 + r * (1330150 ±2)` + // Minimum execution time: 298_155_000 picoseconds. + Weight::from_parts(299_212_000, 32625) + // Standard Error: 32_410_313 + .saturating_add(Weight::from_parts(30_417_025_178, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().reads((480_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(5_u64)) .saturating_add(T::DbWeight::get().writes((400_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 1367114).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 1330150).saturating_mul(r.into())) } /// Storage: System Account (r:162 w:162) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1339,22 +1291,21 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[0, 960]`. fn seal_instantiate_per_transfer_input_salt_kb(t: u32, i: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `5785 + t * (33 ±0)` - // Estimated: `850985 + t * (2671 ±3)` - // Minimum execution time: 132_157_340 nanoseconds. - Weight::from_parts(11_329_968_948, 0) - .saturating_add(Weight::from_parts(0, 850985)) - // Standard Error: 99_102_968 - .saturating_add(Weight::from_parts(84_719_458, 0).saturating_mul(t.into())) - // Standard Error: 161_609 - .saturating_add(Weight::from_parts(126_156_627, 0).saturating_mul(i.into())) - // Standard Error: 161_609 - .saturating_add(Weight::from_parts(126_628_313, 0).saturating_mul(s.into())) + // Measured: `5625 + t * (1 ±0)` + // Estimated: `856795 + t * (2471 ±3)` + // Minimum execution time: 105_914_928_000 picoseconds. + Weight::from_parts(13_229_760_432, 856795) + // Standard Error: 96_394_437 + .saturating_add(Weight::from_parts(398_413_888, 0).saturating_mul(t.into())) + // Standard Error: 157_192 + .saturating_add(Weight::from_parts(97_104_978, 0).saturating_mul(i.into())) + // Standard Error: 157_192 + .saturating_add(Weight::from_parts(97_146_130, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(329_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(t.into()))) .saturating_add(T::DbWeight::get().writes(326_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(t.into()))) - .saturating_add(Weight::from_parts(0, 2671).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(0, 2471).saturating_mul(t.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1369,13 +1320,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1]`. fn seal_hash_sha2_256(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `871 + r * (642 ±0)` - // Estimated: `17225 + r * (3210 ±0)` - // Minimum execution time: 373_559 nanoseconds. - Weight::from_parts(375_166_904, 0) - .saturating_add(Weight::from_parts(0, 17225)) - // Standard Error: 125_024 - .saturating_add(Weight::from_parts(42_291_595, 0).saturating_mul(r.into())) + // Measured: `775 + r * (642 ±0)` + // Estimated: `21695 + r * (3210 ±0)` + // Minimum execution time: 294_309_000 picoseconds. + Weight::from_parts(296_241_318, 21695) + // Standard Error: 127_872 + .saturating_add(Weight::from_parts(45_806_281, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 3210).saturating_mul(r.into())) @@ -1393,13 +1343,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 1024]`. fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1673` - // Estimated: `21160` - // Minimum execution time: 416_233 nanoseconds. - Weight::from_parts(416_785_000, 0) - .saturating_add(Weight::from_parts(0, 21160)) - // Standard Error: 56_223 - .saturating_add(Weight::from_parts(324_513_835, 0).saturating_mul(n.into())) + // Measured: `1577` + // Estimated: `25630` + // Minimum execution time: 341_248_000 picoseconds. + Weight::from_parts(341_607_000, 25630) + // Standard Error: 66_687 + .saturating_add(Weight::from_parts(322_250_398, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1416,13 +1365,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1]`. fn seal_hash_keccak_256(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `873 + r * (642 ±0)` - // Estimated: `17235 + r * (3210 ±0)` - // Minimum execution time: 371_735 nanoseconds. - Weight::from_parts(375_979_430, 0) - .saturating_add(Weight::from_parts(0, 17235)) - // Standard Error: 968_037 - .saturating_add(Weight::from_parts(57_780_769, 0).saturating_mul(r.into())) + // Measured: `777 + r * (642 ±0)` + // Estimated: `21705 + r * (3210 ±0)` + // Minimum execution time: 293_810_000 picoseconds. + Weight::from_parts(296_719_171, 21705) + // Standard Error: 450_807 + .saturating_add(Weight::from_parts(61_627_228, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 3210).saturating_mul(r.into())) @@ -1440,13 +1388,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 1024]`. fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1675` - // Estimated: `21205` - // Minimum execution time: 428_196 nanoseconds. - Weight::from_parts(429_438_000, 0) - .saturating_add(Weight::from_parts(0, 21205)) - // Standard Error: 57_860 - .saturating_add(Weight::from_parts(260_917_896, 0).saturating_mul(n.into())) + // Measured: `1579` + // Estimated: `25675` + // Minimum execution time: 354_550_000 picoseconds. + Weight::from_parts(355_136_000, 25675) + // Standard Error: 61_761 + .saturating_add(Weight::from_parts(257_021_566, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1463,13 +1410,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1]`. fn seal_hash_blake2_256(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `873 + r * (642 ±0)` - // Estimated: `17235 + r * (3210 ±0)` - // Minimum execution time: 371_412 nanoseconds. - Weight::from_parts(373_635_818, 0) - .saturating_add(Weight::from_parts(0, 17235)) - // Standard Error: 222_973 - .saturating_add(Weight::from_parts(33_347_181, 0).saturating_mul(r.into())) + // Measured: `777 + r * (642 ±0)` + // Estimated: `21705 + r * (3210 ±0)` + // Minimum execution time: 293_369_000 picoseconds. + Weight::from_parts(295_990_893, 21705) + // Standard Error: 431_269 + .saturating_add(Weight::from_parts(32_213_406, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 3210).saturating_mul(r.into())) @@ -1487,13 +1433,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1675` - // Estimated: `21180` - // Minimum execution time: 405_858 nanoseconds. - Weight::from_parts(406_498_000, 0) - .saturating_add(Weight::from_parts(0, 21180)) - // Standard Error: 48_388 - .saturating_add(Weight::from_parts(103_283_157, 0).saturating_mul(n.into())) + // Measured: `1579` + // Estimated: `25650` + // Minimum execution time: 326_595_000 picoseconds. + Weight::from_parts(327_188_000, 25650) + // Standard Error: 53_385 + .saturating_add(Weight::from_parts(74_046_074, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1510,13 +1455,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1]`. fn seal_hash_blake2_128(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `873 + r * (679 ±0)` - // Estimated: `17235 + r * (3395 ±0)` - // Minimum execution time: 371_746 nanoseconds. - Weight::from_parts(373_538_171, 0) - .saturating_add(Weight::from_parts(0, 17235)) - // Standard Error: 387_332 - .saturating_add(Weight::from_parts(35_933_528, 0).saturating_mul(r.into())) + // Measured: `777 + r * (679 ±0)` + // Estimated: `21705 + r * (3395 ±0)` + // Minimum execution time: 292_388_000 picoseconds. + Weight::from_parts(295_090_179, 21705) + // Standard Error: 170_487 + .saturating_add(Weight::from_parts(32_577_820, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 3395).saturating_mul(r.into())) @@ -1534,13 +1478,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1675` - // Estimated: `21225` - // Minimum execution time: 405_752 nanoseconds. - Weight::from_parts(406_417_000, 0) - .saturating_add(Weight::from_parts(0, 21225)) - // Standard Error: 47_051 - .saturating_add(Weight::from_parts(103_325_027, 0).saturating_mul(n.into())) + // Measured: `1579` + // Estimated: `25695` + // Minimum execution time: 326_862_000 picoseconds. + Weight::from_parts(327_449_000, 25695) + // Standard Error: 54_539 + .saturating_add(Weight::from_parts(74_042_337, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1557,13 +1500,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1]`. fn seal_ecdsa_recover(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `917 + r * (6083 ±0)` - // Estimated: `17455 + r * (30415 ±0)` - // Minimum execution time: 373_882 nanoseconds. - Weight::from_parts(376_553_787, 0) - .saturating_add(Weight::from_parts(0, 17455)) - // Standard Error: 912_833 - .saturating_add(Weight::from_parts(3_021_100_412, 0).saturating_mul(r.into())) + // Measured: `821 + r * (6083 ±0)` + // Estimated: `21925 + r * (30415 ±0)` + // Minimum execution time: 295_597_000 picoseconds. + Weight::from_parts(298_267_200, 21925) + // Standard Error: 699_824 + .saturating_add(Weight::from_parts(3_021_734_700, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30415).saturating_mul(r.into())) @@ -1581,13 +1523,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1]`. fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `886 + r * (3362 ±0)` - // Estimated: `17300 + r * (16810 ±0)` - // Minimum execution time: 373_673 nanoseconds. - Weight::from_parts(375_712_961, 0) - .saturating_add(Weight::from_parts(0, 17300)) - // Standard Error: 596_297 - .saturating_add(Weight::from_parts(738_257_638, 0).saturating_mul(r.into())) + // Measured: `790 + r * (3362 ±0)` + // Estimated: `21770 + r * (16810 ±0)` + // Minimum execution time: 295_539_000 picoseconds. + Weight::from_parts(297_844_822, 21770) + // Standard Error: 490_532 + .saturating_add(Weight::from_parts(747_592_977, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 16810).saturating_mul(r.into())) @@ -1607,18 +1548,17 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_set_code_hash(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0 + r * (79300 ±0)` - // Estimated: `64844 + r * (942952 ±833)` - // Minimum execution time: 374_097 nanoseconds. - Weight::from_parts(374_985_000, 0) - .saturating_add(Weight::from_parts(0, 64844)) - // Standard Error: 3_772_336 - .saturating_add(Weight::from_parts(1_546_402_854, 0).saturating_mul(r.into())) + // Measured: `0 + r * (74020 ±0)` + // Estimated: `69192 + r * (913289 ±821)` + // Minimum execution time: 295_164_000 picoseconds. + Weight::from_parts(296_597_000, 69192) + // Standard Error: 3_646_577 + .saturating_add(Weight::from_parts(1_725_796_807, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((225_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((150_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 942952).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 913289).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1633,13 +1573,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_reentrance_count(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `869 + r * (240 ±0)` - // Estimated: `17215 + r * (1200 ±0)` - // Minimum execution time: 374_249 nanoseconds. - Weight::from_parts(377_990_998, 0) - .saturating_add(Weight::from_parts(0, 17215)) - // Standard Error: 38_133 - .saturating_add(Weight::from_parts(11_483_273, 0).saturating_mul(r.into())) + // Measured: `773 + r * (240 ±0)` + // Estimated: `21685 + r * (1200 ±0)` + // Minimum execution time: 296_287_000 picoseconds. + Weight::from_parts(300_696_694, 21685) + // Standard Error: 27_891 + .saturating_add(Weight::from_parts(10_943_994, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1200).saturating_mul(r.into())) @@ -1657,13 +1596,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_account_reentrance_count(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2102 + r * (3154 ±0)` - // Estimated: `21980 + r * (15875 ±2)` - // Minimum execution time: 375_552 nanoseconds. - Weight::from_parts(400_624_032, 0) - .saturating_add(Weight::from_parts(0, 21980)) - // Standard Error: 82_523 - .saturating_add(Weight::from_parts(18_057_327, 0).saturating_mul(r.into())) + // Measured: `2006 + r * (3154 ±0)` + // Estimated: `26435 + r * (15875 ±2)` + // Minimum execution time: 298_000_000 picoseconds. + Weight::from_parts(328_282_119, 26435) + // Standard Error: 104_874 + .saturating_add(Weight::from_parts(18_428_267, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 15875).saturating_mul(r.into())) @@ -1683,13 +1621,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 20]`. fn seal_instantiation_nonce(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `872 + r * (240 ±0)` - // Estimated: `18598 + r * (1440 ±0)` - // Minimum execution time: 373_899 nanoseconds. - Weight::from_parts(379_733_943, 0) - .saturating_add(Weight::from_parts(0, 18598)) - // Standard Error: 32_022 - .saturating_add(Weight::from_parts(9_381_180, 0).saturating_mul(r.into())) + // Measured: `776 + r * (240 ±0)` + // Estimated: `23962 + r * (1440 ±0)` + // Minimum execution time: 295_104_000 picoseconds. + Weight::from_parts(299_334_585, 23962) + // Standard Error: 25_840 + .saturating_add(Weight::from_parts(9_744_866, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1440).saturating_mul(r.into())) @@ -1699,572 +1636,520 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 834 nanoseconds. - Weight::from_parts(1_009_646, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 388 - .saturating_add(Weight::from_parts(411_979, 0).saturating_mul(r.into())) + // Minimum execution time: 1_132_000 picoseconds. + Weight::from_parts(1_100_159, 0) + // Standard Error: 10_131 + .saturating_add(Weight::from_parts(436_462, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64load(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 882 nanoseconds. - Weight::from_parts(1_416_377, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 1_133 - .saturating_add(Weight::from_parts(1_075_838, 0).saturating_mul(r.into())) + // Minimum execution time: 1_368_000 picoseconds. + Weight::from_parts(1_974_308, 0) + // Standard Error: 811 + .saturating_add(Weight::from_parts(1_079_620, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64store(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 878 nanoseconds. - Weight::from_parts(1_343_056, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 426 - .saturating_add(Weight::from_parts(1_001_214, 0).saturating_mul(r.into())) + // Minimum execution time: 1_354_000 picoseconds. + Weight::from_parts(2_057_834, 0) + // Standard Error: 4_277 + .saturating_add(Weight::from_parts(1_008_797, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_select(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 796 nanoseconds. - Weight::from_parts(1_079_086, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 409 - .saturating_add(Weight::from_parts(1_149_188, 0).saturating_mul(r.into())) + // Minimum execution time: 1_218_000 picoseconds. + Weight::from_parts(1_594_528, 0) + // Standard Error: 723 + .saturating_add(Weight::from_parts(1_147_486, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_if(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 800 nanoseconds. - Weight::from_parts(1_044_184, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 707 - .saturating_add(Weight::from_parts(1_315_686, 0).saturating_mul(r.into())) + // Minimum execution time: 1_156_000 picoseconds. + Weight::from_parts(1_460_611, 0) + // Standard Error: 419 + .saturating_add(Weight::from_parts(1_314_741, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_br(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 807 nanoseconds. - Weight::from_parts(1_049_633, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 361 - .saturating_add(Weight::from_parts(640_530, 0).saturating_mul(r.into())) + // Minimum execution time: 1_166_000 picoseconds. + Weight::from_parts(1_454_460, 0) + // Standard Error: 493 + .saturating_add(Weight::from_parts(642_481, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_br_if(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 774 nanoseconds. - Weight::from_parts(1_124_053, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 784 - .saturating_add(Weight::from_parts(949_398, 0).saturating_mul(r.into())) + // Minimum execution time: 1_144_000 picoseconds. + Weight::from_parts(1_410_515, 0) + // Standard Error: 894 + .saturating_add(Weight::from_parts(958_765, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_br_table(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 810 nanoseconds. - Weight::from_parts(676_581, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 2_356 - .saturating_add(Weight::from_parts(1_163_465, 0).saturating_mul(r.into())) + // Minimum execution time: 1_190_000 picoseconds. + Weight::from_parts(1_143_236, 0) + // Standard Error: 2_773 + .saturating_add(Weight::from_parts(1_164_764, 0).saturating_mul(r.into())) } /// The range of component `e` is `[1, 256]`. fn instr_br_table_per_entry(e: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_580 nanoseconds. - Weight::from_parts(2_835_656, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 71 - .saturating_add(Weight::from_parts(4_686, 0).saturating_mul(e.into())) + // Minimum execution time: 2_993_000 picoseconds. + Weight::from_parts(3_270_525, 0) + // Standard Error: 65 + .saturating_add(Weight::from_parts(4_418, 0).saturating_mul(e.into())) } /// The range of component `r` is `[0, 50]`. fn instr_call(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 826 nanoseconds. - Weight::from_parts(1_625_698, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 1_740 - .saturating_add(Weight::from_parts(2_332_187, 0).saturating_mul(r.into())) + // Minimum execution time: 1_163_000 picoseconds. + Weight::from_parts(1_999_458, 0) + // Standard Error: 1_418 + .saturating_add(Weight::from_parts(2_371_979, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_call_indirect(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 901 nanoseconds. - Weight::from_parts(2_338_620, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 1_642 - .saturating_add(Weight::from_parts(2_924_090, 0).saturating_mul(r.into())) + // Minimum execution time: 1_288_000 picoseconds. + Weight::from_parts(2_340_227, 0) + // Standard Error: 3_234 + .saturating_add(Weight::from_parts(3_038_523, 0).saturating_mul(r.into())) } /// The range of component `p` is `[0, 128]`. fn instr_call_indirect_per_param(p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_670 nanoseconds. - Weight::from_parts(5_556_246, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 1_491 - .saturating_add(Weight::from_parts(228_965, 0).saturating_mul(p.into())) + // Minimum execution time: 5_270_000 picoseconds. + Weight::from_parts(6_360_011, 0) + // Standard Error: 2_585 + .saturating_add(Weight::from_parts(226_149, 0).saturating_mul(p.into())) } /// The range of component `l` is `[0, 1024]`. fn instr_call_per_local(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_099 nanoseconds. - Weight::from_parts(3_896_177, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 99 - .saturating_add(Weight::from_parts(91_304, 0).saturating_mul(l.into())) + // Minimum execution time: 3_580_000 picoseconds. + Weight::from_parts(5_183_658, 0) + // Standard Error: 80 + .saturating_add(Weight::from_parts(46_038, 0).saturating_mul(l.into())) } /// The range of component `r` is `[0, 50]`. fn instr_local_get(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_042 nanoseconds. - Weight::from_parts(3_334_621, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 793 - .saturating_add(Weight::from_parts(459_346, 0).saturating_mul(r.into())) + // Minimum execution time: 2_559_000 picoseconds. + Weight::from_parts(2_846_350, 0) + // Standard Error: 2_809 + .saturating_add(Weight::from_parts(462_084, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_local_set(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_968 nanoseconds. - Weight::from_parts(3_235_286, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 427 - .saturating_add(Weight::from_parts(485_454, 0).saturating_mul(r.into())) + // Minimum execution time: 2_530_000 picoseconds. + Weight::from_parts(2_835_072, 0) + // Standard Error: 479 + .saturating_add(Weight::from_parts(483_451, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_local_tee(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_012 nanoseconds. - Weight::from_parts(3_303_555, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 371 - .saturating_add(Weight::from_parts(657_811, 0).saturating_mul(r.into())) + // Minimum execution time: 2_510_000 picoseconds. + Weight::from_parts(2_740_081, 0) + // Standard Error: 901 + .saturating_add(Weight::from_parts(664_354, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_global_get(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 865 nanoseconds. - Weight::from_parts(1_249_987, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 417 - .saturating_add(Weight::from_parts(896_704, 0).saturating_mul(r.into())) + // Minimum execution time: 1_295_000 picoseconds. + Weight::from_parts(1_798_174, 0) + // Standard Error: 464 + .saturating_add(Weight::from_parts(896_289, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_global_set(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 866 nanoseconds. - Weight::from_parts(1_216_218, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 503 - .saturating_add(Weight::from_parts(919_719, 0).saturating_mul(r.into())) + // Minimum execution time: 1_287_000 picoseconds. + Weight::from_parts(1_636_548, 0) + // Standard Error: 658 + .saturating_add(Weight::from_parts(923_295, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_memory_current(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 921 nanoseconds. - Weight::from_parts(1_228_408, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 309 - .saturating_add(Weight::from_parts(813_007, 0).saturating_mul(r.into())) + // Minimum execution time: 1_353_000 picoseconds. + Weight::from_parts(1_672_309, 0) + // Standard Error: 403 + .saturating_add(Weight::from_parts(818_273, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 1]`. fn instr_memory_grow(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 820 nanoseconds. - Weight::from_parts(914_830, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 6_018 - .saturating_add(Weight::from_parts(237_062_769, 0).saturating_mul(r.into())) + // Minimum execution time: 1_180_000 picoseconds. + Weight::from_parts(1_304_714, 0) + // Standard Error: 88_180 + .saturating_add(Weight::from_parts(183_952_985, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64clz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 812 nanoseconds. - Weight::from_parts(1_554_406, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 9_979 - .saturating_add(Weight::from_parts(625_434, 0).saturating_mul(r.into())) + // Minimum execution time: 1_158_000 picoseconds. + Weight::from_parts(1_800_065, 0) + // Standard Error: 2_104 + .saturating_add(Weight::from_parts(625_410, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ctz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 798 nanoseconds. - Weight::from_parts(1_095_113, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 243 - .saturating_add(Weight::from_parts(634_204, 0).saturating_mul(r.into())) + // Minimum execution time: 1_208_000 picoseconds. + Weight::from_parts(1_483_908, 0) + // Standard Error: 319 + .saturating_add(Weight::from_parts(635_095, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64popcnt(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 792 nanoseconds. - Weight::from_parts(1_109_845, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 14_944 - .saturating_add(Weight::from_parts(658_834, 0).saturating_mul(r.into())) + // Minimum execution time: 1_164_000 picoseconds. + Weight::from_parts(1_506_871, 0) + // Standard Error: 264 + .saturating_add(Weight::from_parts(633_660, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64eqz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 815 nanoseconds. - Weight::from_parts(1_068_916, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 327 - .saturating_add(Weight::from_parts(652_897, 0).saturating_mul(r.into())) + // Minimum execution time: 1_141_000 picoseconds. + Weight::from_parts(1_467_219, 0) + // Standard Error: 191 + .saturating_add(Weight::from_parts(651_156, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendsi32(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 798 nanoseconds. - Weight::from_parts(1_069_745, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 306 - .saturating_add(Weight::from_parts(618_481, 0).saturating_mul(r.into())) + // Minimum execution time: 1_170_000 picoseconds. + Weight::from_parts(1_474_718, 0) + // Standard Error: 224 + .saturating_add(Weight::from_parts(617_317, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendui32(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 799 nanoseconds. - Weight::from_parts(1_398_001, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 6_234 - .saturating_add(Weight::from_parts(611_399, 0).saturating_mul(r.into())) + // Minimum execution time: 1_195_000 picoseconds. + Weight::from_parts(1_501_421, 0) + // Standard Error: 221 + .saturating_add(Weight::from_parts(616_559, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i32wrapi64(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 811 nanoseconds. - Weight::from_parts(1_098_083, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 297 - .saturating_add(Weight::from_parts(617_692, 0).saturating_mul(r.into())) + // Minimum execution time: 1_172_000 picoseconds. + Weight::from_parts(1_482_402, 0) + // Standard Error: 2_163 + .saturating_add(Weight::from_parts(619_230, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64eq(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 815 nanoseconds. - Weight::from_parts(1_046_922, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 335 - .saturating_add(Weight::from_parts(909_196, 0).saturating_mul(r.into())) + // Minimum execution time: 1_149_000 picoseconds. + Weight::from_parts(2_021_801, 0) + // Standard Error: 20_804 + .saturating_add(Weight::from_parts(913_888, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ne(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 805 nanoseconds. - Weight::from_parts(1_093_667, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 233 - .saturating_add(Weight::from_parts(907_378, 0).saturating_mul(r.into())) + // Minimum execution time: 1_187_000 picoseconds. + Weight::from_parts(1_358_437, 0) + // Standard Error: 1_946 + .saturating_add(Weight::from_parts(916_378, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64lts(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 805 nanoseconds. - Weight::from_parts(1_290_591, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 3_201 - .saturating_add(Weight::from_parts(902_006, 0).saturating_mul(r.into())) + // Minimum execution time: 1_175_000 picoseconds. + Weight::from_parts(1_527_336, 0) + // Standard Error: 243 + .saturating_add(Weight::from_parts(907_580, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ltu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 783 nanoseconds. - Weight::from_parts(1_159_977, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 2_310 - .saturating_add(Weight::from_parts(906_489, 0).saturating_mul(r.into())) + // Minimum execution time: 1_220_000 picoseconds. + Weight::from_parts(1_530_715, 0) + // Standard Error: 224 + .saturating_add(Weight::from_parts(906_096, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64gts(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 790 nanoseconds. - Weight::from_parts(1_109_719, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 261 - .saturating_add(Weight::from_parts(906_614, 0).saturating_mul(r.into())) + // Minimum execution time: 1_107_000 picoseconds. + Weight::from_parts(1_496_553, 0) + // Standard Error: 299 + .saturating_add(Weight::from_parts(907_963, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64gtu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 776 nanoseconds. - Weight::from_parts(1_076_567, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 348 - .saturating_add(Weight::from_parts(919_374, 0).saturating_mul(r.into())) + // Minimum execution time: 1_153_000 picoseconds. + Weight::from_parts(1_482_710, 0) + // Standard Error: 182 + .saturating_add(Weight::from_parts(918_439, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64les(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 780 nanoseconds. - Weight::from_parts(1_069_663, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 265 - .saturating_add(Weight::from_parts(908_037, 0).saturating_mul(r.into())) + // Minimum execution time: 1_142_000 picoseconds. + Weight::from_parts(1_522_114, 0) + // Standard Error: 297 + .saturating_add(Weight::from_parts(906_633, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64leu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 832 nanoseconds. - Weight::from_parts(930_920, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 2_170 - .saturating_add(Weight::from_parts(929_811, 0).saturating_mul(r.into())) + // Minimum execution time: 1_119_000 picoseconds. + Weight::from_parts(2_199_831, 0) + // Standard Error: 4_234 + .saturating_add(Weight::from_parts(898_161, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ges(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 787 nanoseconds. - Weight::from_parts(1_087_325, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 315 - .saturating_add(Weight::from_parts(908_321, 0).saturating_mul(r.into())) + // Minimum execution time: 1_163_000 picoseconds. + Weight::from_parts(1_489_404, 0) + // Standard Error: 416 + .saturating_add(Weight::from_parts(908_450, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64geu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 798 nanoseconds. - Weight::from_parts(1_029_132, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 2_095 - .saturating_add(Weight::from_parts(913_553, 0).saturating_mul(r.into())) + // Minimum execution time: 1_204_000 picoseconds. + Weight::from_parts(2_266_296, 0) + // Standard Error: 13_013 + .saturating_add(Weight::from_parts(899_225, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64add(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 791 nanoseconds. - Weight::from_parts(1_086_314, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 197 - .saturating_add(Weight::from_parts(896_392, 0).saturating_mul(r.into())) + // Minimum execution time: 1_160_000 picoseconds. + Weight::from_parts(1_470_799, 0) + // Standard Error: 422 + .saturating_add(Weight::from_parts(897_325, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64sub(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 793 nanoseconds. - Weight::from_parts(1_078_172, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 404 - .saturating_add(Weight::from_parts(886_329, 0).saturating_mul(r.into())) + // Minimum execution time: 1_125_000 picoseconds. + Weight::from_parts(1_521_508, 0) + // Standard Error: 594 + .saturating_add(Weight::from_parts(886_145, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64mul(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 799 nanoseconds. - Weight::from_parts(1_095_010, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 431 - .saturating_add(Weight::from_parts(886_513, 0).saturating_mul(r.into())) + // Minimum execution time: 1_139_000 picoseconds. + Weight::from_parts(1_490_535, 0) + // Standard Error: 211 + .saturating_add(Weight::from_parts(884_929, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64divs(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 810 nanoseconds. - Weight::from_parts(1_114_325, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 452 - .saturating_add(Weight::from_parts(1_521_849, 0).saturating_mul(r.into())) + // Minimum execution time: 1_180_000 picoseconds. + Weight::from_parts(2_221_481, 0) + // Standard Error: 9_884 + .saturating_add(Weight::from_parts(1_507_511, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64divu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 784 nanoseconds. - Weight::from_parts(1_123_153, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 475 - .saturating_add(Weight::from_parts(1_457_746, 0).saturating_mul(r.into())) + // Minimum execution time: 1_131_000 picoseconds. + Weight::from_parts(1_498_652, 0) + // Standard Error: 531 + .saturating_add(Weight::from_parts(1_451_498, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64rems(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 809 nanoseconds. - Weight::from_parts(1_145_906, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 718 - .saturating_add(Weight::from_parts(1_549_964, 0).saturating_mul(r.into())) + // Minimum execution time: 1_145_000 picoseconds. + Weight::from_parts(1_504_118, 0) + // Standard Error: 439 + .saturating_add(Weight::from_parts(1_521_895, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64remu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 803 nanoseconds. - Weight::from_parts(1_110_328, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 627 - .saturating_add(Weight::from_parts(1_453_013, 0).saturating_mul(r.into())) + // Minimum execution time: 1_124_000 picoseconds. + Weight::from_parts(1_497_209, 0) + // Standard Error: 198 + .saturating_add(Weight::from_parts(1_449_843, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64and(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 786 nanoseconds. - Weight::from_parts(1_108_792, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 286 - .saturating_add(Weight::from_parts(897_035, 0).saturating_mul(r.into())) + // Minimum execution time: 1_169_000 picoseconds. + Weight::from_parts(1_534_491, 0) + // Standard Error: 283 + .saturating_add(Weight::from_parts(894_703, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64or(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 787 nanoseconds. - Weight::from_parts(830_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 15_995 - .saturating_add(Weight::from_parts(963_344, 0).saturating_mul(r.into())) + // Minimum execution time: 1_178_000 picoseconds. + Weight::from_parts(1_485_473, 0) + // Standard Error: 552 + .saturating_add(Weight::from_parts(897_878, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64xor(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 773 nanoseconds. - Weight::from_parts(1_082_459, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 330 - .saturating_add(Weight::from_parts(897_077, 0).saturating_mul(r.into())) + // Minimum execution time: 1_214_000 picoseconds. + Weight::from_parts(1_580_999, 0) + // Standard Error: 358 + .saturating_add(Weight::from_parts(894_207, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64shl(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 810 nanoseconds. - Weight::from_parts(1_325_815, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 3_352 - .saturating_add(Weight::from_parts(899_555, 0).saturating_mul(r.into())) + // Minimum execution time: 1_176_000 picoseconds. + Weight::from_parts(1_490_470, 0) + // Standard Error: 738 + .saturating_add(Weight::from_parts(904_900, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64shrs(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 808 nanoseconds. - Weight::from_parts(1_085_903, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 430 - .saturating_add(Weight::from_parts(903_249, 0).saturating_mul(r.into())) + // Minimum execution time: 1_197_000 picoseconds. + Weight::from_parts(1_519_703, 0) + // Standard Error: 336 + .saturating_add(Weight::from_parts(901_277, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64shru(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 792 nanoseconds. - Weight::from_parts(1_091_261, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 312 - .saturating_add(Weight::from_parts(902_245, 0).saturating_mul(r.into())) + // Minimum execution time: 1_166_000 picoseconds. + Weight::from_parts(1_507_499, 0) + // Standard Error: 298 + .saturating_add(Weight::from_parts(901_153, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotl(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 807 nanoseconds. - Weight::from_parts(1_121_052, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 506 - .saturating_add(Weight::from_parts(902_772, 0).saturating_mul(r.into())) + // Minimum execution time: 1_158_000 picoseconds. + Weight::from_parts(1_491_176, 0) + // Standard Error: 341 + .saturating_add(Weight::from_parts(901_880, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotr(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 823 nanoseconds. - Weight::from_parts(1_317_597, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 6_219 - .saturating_add(Weight::from_parts(896_692, 0).saturating_mul(r.into())) + // Minimum execution time: 1_207_000 picoseconds. + Weight::from_parts(1_477_261, 0) + // Standard Error: 287 + .saturating_add(Weight::from_parts(902_622, 0).saturating_mul(r.into())) } } @@ -2275,10 +2160,9 @@ impl WeightInfo for () { fn on_process_deletion_queue_batch() -> Weight { // Proof Size summary in bytes: // Measured: `109` - // Estimated: `604` - // Minimum execution time: 2_591 nanoseconds. - Weight::from_parts(2_817_000, 0) - .saturating_add(Weight::from_parts(0, 604)) + // Estimated: `1594` + // Minimum execution time: 2_679_000 picoseconds. + Weight::from_parts(2_907_000, 1594) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: Skipped Metadata (r:0 w:0) @@ -2286,14 +2170,14 @@ impl WeightInfo for () { /// The range of component `k` is `[0, 1024]`. fn on_initialize_per_trie_key(k: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `481 + k * (69 ±0)` - // Estimated: `471 + k * (70 ±0)` - // Minimum execution time: 10_190 nanoseconds. - Weight::from_parts(6_642_117, 0) - .saturating_add(Weight::from_parts(0, 471)) - // Standard Error: 992 - .saturating_add(Weight::from_parts(919_828, 0).saturating_mul(k.into())) + // Measured: `450 + k * (69 ±0)` + // Estimated: `440 + k * (70 ±0)` + // Minimum execution time: 11_162_000 picoseconds. + Weight::from_parts(5_734_923, 440) + // Standard Error: 1_097 + .saturating_add(Weight::from_parts(976_647, 0).saturating_mul(k.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(k.into()))) .saturating_add(Weight::from_parts(0, 70).saturating_mul(k.into())) @@ -2303,13 +2187,12 @@ impl WeightInfo for () { /// The range of component `q` is `[0, 128]`. fn on_initialize_per_queue_item(q: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `281 + q * (33 ±0)` - // Estimated: `763 + q * (33 ±0)` - // Minimum execution time: 2_598 nanoseconds. - Weight::from_parts(10_288_252, 0) - .saturating_add(Weight::from_parts(0, 763)) - // Standard Error: 2_886 - .saturating_add(Weight::from_parts(1_092_420, 0).saturating_mul(q.into())) + // Measured: `250 + q * (33 ±0)` + // Estimated: `1725 + q * (33 ±0)` + // Minimum execution time: 2_626_000 picoseconds. + Weight::from_parts(10_626_314, 1725) + // Standard Error: 4_006 + .saturating_add(Weight::from_parts(1_298_864, 0).saturating_mul(q.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 33).saturating_mul(q.into())) @@ -2321,13 +2204,12 @@ impl WeightInfo for () { /// The range of component `c` is `[0, 61717]`. fn reinstrument(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `270 + c * (1 ±0)` - // Estimated: `3025 + c * (2 ±0)` - // Minimum execution time: 34_338 nanoseconds. - Weight::from_parts(32_159_677, 0) - .saturating_add(Weight::from_parts(0, 3025)) - // Standard Error: 53 - .saturating_add(Weight::from_parts(51_034, 0).saturating_mul(c.into())) + // Measured: `238 + c * (1 ±0)` + // Estimated: `3951 + c * (2 ±0)` + // Minimum execution time: 31_434_000 picoseconds. + Weight::from_parts(29_558_961, 3951) + // Standard Error: 55 + .saturating_add(Weight::from_parts(50_774, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 2).saturating_mul(c.into())) @@ -2345,13 +2227,12 @@ impl WeightInfo for () { /// The range of component `c` is `[0, 125952]`. fn call_with_code_per_byte(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `803` - // Estimated: `16930 + c * (5 ±0)` - // Minimum execution time: 385_587 nanoseconds. - Weight::from_parts(395_545_811, 0) - .saturating_add(Weight::from_parts(0, 16930)) - // Standard Error: 27 - .saturating_add(Weight::from_parts(31_342, 0).saturating_mul(c.into())) + // Measured: `707` + // Estimated: `21400 + c * (5 ±0)` + // Minimum execution time: 309_015_000 picoseconds. + Weight::from_parts(318_740_885, 21400) + // Standard Error: 29 + .saturating_add(Weight::from_parts(30_993, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 5).saturating_mul(c.into())) @@ -2378,16 +2259,15 @@ impl WeightInfo for () { fn instantiate_with_code(c: u32, i: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `270` - // Estimated: `20267` - // Minimum execution time: 3_799_742 nanoseconds. - Weight::from_parts(670_115_588, 0) - .saturating_add(Weight::from_parts(0, 20267)) - // Standard Error: 287 - .saturating_add(Weight::from_parts(93_885, 0).saturating_mul(c.into())) - // Standard Error: 16 - .saturating_add(Weight::from_parts(1_367, 0).saturating_mul(i.into())) - // Standard Error: 16 - .saturating_add(Weight::from_parts(1_781, 0).saturating_mul(s.into())) + // Estimated: `26207` + // Minimum execution time: 3_126_495_000 picoseconds. + Weight::from_parts(636_857_878, 26207) + // Standard Error: 294 + .saturating_add(Weight::from_parts(92_930, 0).saturating_mul(c.into())) + // Standard Error: 17 + .saturating_add(Weight::from_parts(1_128, 0).saturating_mul(i.into())) + // Standard Error: 17 + .saturating_add(Weight::from_parts(1_415, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(10_u64)) } @@ -2409,15 +2289,14 @@ impl WeightInfo for () { /// The range of component `s` is `[0, 1048576]`. fn instantiate(i: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `546` - // Estimated: `22039` - // Minimum execution time: 1_949_008 nanoseconds. - Weight::from_parts(214_033_418, 0) - .saturating_add(Weight::from_parts(0, 22039)) + // Measured: `482` + // Estimated: `28521` + // Minimum execution time: 1_591_415_000 picoseconds. + Weight::from_parts(228_633_516, 28521) // Standard Error: 8 - .saturating_add(Weight::from_parts(1_666, 0).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(1_449, 0).saturating_mul(i.into())) // Standard Error: 8 - .saturating_add(Weight::from_parts(1_801, 0).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_444, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } @@ -2433,11 +2312,10 @@ impl WeightInfo for () { /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) fn call() -> Weight { // Proof Size summary in bytes: - // Measured: `855` - // Estimated: `17145` - // Minimum execution time: 146_654 nanoseconds. - Weight::from_parts(147_528_000, 0) - .saturating_add(Weight::from_parts(0, 17145)) + // Measured: `759` + // Estimated: `21615` + // Minimum execution time: 167_905_000 picoseconds. + Weight::from_parts(169_247_000, 21615) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -2453,12 +2331,11 @@ impl WeightInfo for () { fn upload_code(c: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `109` - // Estimated: `5386` - // Minimum execution time: 387_889 nanoseconds. - Weight::from_parts(391_379_335, 0) - .saturating_add(Weight::from_parts(0, 5386)) - // Standard Error: 89 - .saturating_add(Weight::from_parts(94_810, 0).saturating_mul(c.into())) + // Estimated: `7366` + // Minimum execution time: 305_128_000 picoseconds. + Weight::from_parts(310_911_395, 7366) + // Standard Error: 70 + .saturating_add(Weight::from_parts(94_067, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -2472,11 +2349,10 @@ impl WeightInfo for () { /// Proof: Contracts PristineCode (max_values: None, max_size: Some(125988), added: 128463, mode: Measured) fn remove_code() -> Weight { // Proof Size summary in bytes: - // Measured: `287` - // Estimated: `6098` - // Minimum execution time: 26_014 nanoseconds. - Weight::from_parts(26_510_000, 0) - .saturating_add(Weight::from_parts(0, 6098)) + // Measured: `255` + // Estimated: `7950` + // Minimum execution time: 29_605_000 picoseconds. + Weight::from_parts(29_986_000, 7950) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -2488,11 +2364,10 @@ impl WeightInfo for () { /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) fn set_code() -> Weight { // Proof Size summary in bytes: - // Measured: `666` - // Estimated: `16848` - // Minimum execution time: 30_177 nanoseconds. - Weight::from_parts(30_639_000, 0) - .saturating_add(Weight::from_parts(0, 16848)) + // Measured: `570` + // Estimated: `19530` + // Minimum execution time: 33_824_000 picoseconds. + Weight::from_parts(34_388_000, 19530) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -2509,13 +2384,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_caller(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `877 + r * (480 ±0)` - // Estimated: `17295 + r * (2400 ±0)` - // Minimum execution time: 373_786 nanoseconds. - Weight::from_parts(377_332_691, 0) - .saturating_add(Weight::from_parts(0, 17295)) - // Standard Error: 51_211 - .saturating_add(Weight::from_parts(17_715_615, 0).saturating_mul(r.into())) + // Measured: `781 + r * (480 ±0)` + // Estimated: `21765 + r * (2400 ±0)` + // Minimum execution time: 295_283_000 picoseconds. + Weight::from_parts(295_895_211, 21765) + // Standard Error: 44_860 + .saturating_add(Weight::from_parts(22_913_078, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 2400).saturating_mul(r.into())) @@ -2533,17 +2407,16 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_is_contract(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `917 + r * (21778 ±0)` - // Estimated: `17295 + r * (306895 ±0)` - // Minimum execution time: 374_009 nanoseconds. - Weight::from_parts(238_991_986, 0) - .saturating_add(Weight::from_parts(0, 17295)) - // Standard Error: 464_711 - .saturating_add(Weight::from_parts(249_099_538, 0).saturating_mul(r.into())) + // Measured: `821 + r * (19218 ±0)` + // Estimated: `21765 + r * (294095 ±0)` + // Minimum execution time: 295_760_000 picoseconds. + Weight::from_parts(151_512_811, 21765) + // Standard Error: 522_974 + .saturating_add(Weight::from_parts(263_028_353, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 306895).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 294095).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2558,17 +2431,16 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_code_hash(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `921 + r * (22099 ±0)` - // Estimated: `17340 + r * (308500 ±0)` - // Minimum execution time: 375_058 nanoseconds. - Weight::from_parts(238_765_068, 0) - .saturating_add(Weight::from_parts(0, 17340)) - // Standard Error: 662_617 - .saturating_add(Weight::from_parts(302_175_089, 0).saturating_mul(r.into())) + // Measured: `825 + r * (19539 ±0)` + // Estimated: `21810 + r * (295700 ±0)` + // Minimum execution time: 295_950_000 picoseconds. + Weight::from_parts(164_516_076, 21810) + // Standard Error: 469_540 + .saturating_add(Weight::from_parts(321_138_601, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 308500).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 295700).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2583,13 +2455,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_own_code_hash(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `884 + r * (480 ±0)` - // Estimated: `17330 + r * (2400 ±0)` - // Minimum execution time: 374_747 nanoseconds. - Weight::from_parts(376_482_380, 0) - .saturating_add(Weight::from_parts(0, 17330)) - // Standard Error: 61_919 - .saturating_add(Weight::from_parts(22_376_795, 0).saturating_mul(r.into())) + // Measured: `788 + r * (480 ±0)` + // Estimated: `21800 + r * (2400 ±0)` + // Minimum execution time: 295_916_000 picoseconds. + Weight::from_parts(299_964_913, 21800) + // Standard Error: 78_211 + .saturating_add(Weight::from_parts(28_933_603, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 2400).saturating_mul(r.into())) @@ -2607,13 +2478,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_caller_is_origin(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `874 + r * (240 ±0)` - // Estimated: `17265 + r * (1200 ±0)` - // Minimum execution time: 372_287 nanoseconds. - Weight::from_parts(376_250_858, 0) - .saturating_add(Weight::from_parts(0, 17265)) - // Standard Error: 40_119 - .saturating_add(Weight::from_parts(11_359_647, 0).saturating_mul(r.into())) + // Measured: `778 + r * (240 ±0)` + // Estimated: `21735 + r * (1200 ±0)` + // Minimum execution time: 293_588_000 picoseconds. + Weight::from_parts(297_568_984, 21735) + // Standard Error: 35_513 + .saturating_add(Weight::from_parts(11_074_880, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1200).saturating_mul(r.into())) @@ -2631,13 +2501,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_address(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `878 + r * (480 ±0)` - // Estimated: `17260 + r * (2400 ±0)` - // Minimum execution time: 374_445 nanoseconds. - Weight::from_parts(377_243_521, 0) - .saturating_add(Weight::from_parts(0, 17260)) - // Standard Error: 53_032 - .saturating_add(Weight::from_parts(17_684_246, 0).saturating_mul(r.into())) + // Measured: `782 + r * (480 ±0)` + // Estimated: `21730 + r * (2400 ±0)` + // Minimum execution time: 294_929_000 picoseconds. + Weight::from_parts(295_916_817, 21730) + // Standard Error: 64_902 + .saturating_add(Weight::from_parts(22_944_018, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 2400).saturating_mul(r.into())) @@ -2655,13 +2524,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_gas_left(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `879 + r * (480 ±0)` - // Estimated: `17250 + r * (2405 ±0)` - // Minimum execution time: 374_029 nanoseconds. - Weight::from_parts(380_415_186, 0) - .saturating_add(Weight::from_parts(0, 17250)) - // Standard Error: 60_562 - .saturating_add(Weight::from_parts(17_152_599, 0).saturating_mul(r.into())) + // Measured: `783 + r * (480 ±0)` + // Estimated: `21720 + r * (2405 ±0)` + // Minimum execution time: 296_783_000 picoseconds. + Weight::from_parts(299_399_332, 21720) + // Standard Error: 50_982 + .saturating_add(Weight::from_parts(22_173_249, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 2405).saturating_mul(r.into())) @@ -2679,16 +2547,15 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_balance(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1049 + r * (480 ±0)` - // Estimated: `19849 + r * (2456 ±0)` - // Minimum execution time: 373_999 nanoseconds. - Weight::from_parts(381_757_033, 0) - .saturating_add(Weight::from_parts(0, 19849)) - // Standard Error: 97_983 - .saturating_add(Weight::from_parts(98_290_984, 0).saturating_mul(r.into())) + // Measured: `921 + r * (480 ±0)` + // Estimated: `24193 + r * (2451 ±0)` + // Minimum execution time: 294_120_000 picoseconds. + Weight::from_parts(305_889_989, 24193) + // Standard Error: 116_244 + .saturating_add(Weight::from_parts(114_781_094, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 2456).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 2451).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2703,13 +2570,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_value_transferred(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `888 + r * (480 ±0)` - // Estimated: `17360 + r * (2400 ±0)` - // Minimum execution time: 374_197 nanoseconds. - Weight::from_parts(377_755_896, 0) - .saturating_add(Weight::from_parts(0, 17360)) - // Standard Error: 60_542 - .saturating_add(Weight::from_parts(17_442_065, 0).saturating_mul(r.into())) + // Measured: `792 + r * (480 ±0)` + // Estimated: `21830 + r * (2400 ±0)` + // Minimum execution time: 295_569_000 picoseconds. + Weight::from_parts(299_774_774, 21830) + // Standard Error: 46_252 + .saturating_add(Weight::from_parts(21_753_842, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 2400).saturating_mul(r.into())) @@ -2727,13 +2593,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_minimum_balance(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `886 + r * (480 ±0)` - // Estimated: `17290 + r * (2400 ±0)` - // Minimum execution time: 373_888 nanoseconds. - Weight::from_parts(377_825_771, 0) - .saturating_add(Weight::from_parts(0, 17290)) - // Standard Error: 38_026 - .saturating_add(Weight::from_parts(17_147_903, 0).saturating_mul(r.into())) + // Measured: `790 + r * (480 ±0)` + // Estimated: `21760 + r * (2400 ±0)` + // Minimum execution time: 295_400_000 picoseconds. + Weight::from_parts(300_637_266, 21760) + // Standard Error: 41_263 + .saturating_add(Weight::from_parts(21_565_466, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 2400).saturating_mul(r.into())) @@ -2751,13 +2616,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_block_number(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `883 + r * (480 ±0)` - // Estimated: `17315 + r * (2400 ±0)` - // Minimum execution time: 373_904 nanoseconds. - Weight::from_parts(378_652_372, 0) - .saturating_add(Weight::from_parts(0, 17315)) - // Standard Error: 43_833 - .saturating_add(Weight::from_parts(16_936_781, 0).saturating_mul(r.into())) + // Measured: `787 + r * (480 ±0)` + // Estimated: `21785 + r * (2400 ±0)` + // Minimum execution time: 294_696_000 picoseconds. + Weight::from_parts(297_196_796, 21785) + // Standard Error: 61_173 + .saturating_add(Weight::from_parts(21_903_191, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 2400).saturating_mul(r.into())) @@ -2775,13 +2639,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_now(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `874 + r * (480 ±0)` - // Estimated: `17245 + r * (2400 ±0)` - // Minimum execution time: 373_473 nanoseconds. - Weight::from_parts(376_386_312, 0) - .saturating_add(Weight::from_parts(0, 17245)) - // Standard Error: 46_945 - .saturating_add(Weight::from_parts(17_336_462, 0).saturating_mul(r.into())) + // Measured: `778 + r * (480 ±0)` + // Estimated: `21715 + r * (2400 ±0)` + // Minimum execution time: 297_714_000 picoseconds. + Weight::from_parts(306_030_237, 21715) + // Standard Error: 69_984 + .saturating_add(Weight::from_parts(21_744_413, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 2400).saturating_mul(r.into())) @@ -2801,13 +2664,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_weight_to_fee(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `951 + r * (800 ±0)` - // Estimated: `19046 + r * (4805 ±0)` - // Minimum execution time: 373_661 nanoseconds. - Weight::from_parts(385_824_015, 0) - .saturating_add(Weight::from_parts(0, 19046)) - // Standard Error: 75_964 - .saturating_add(Weight::from_parts(88_530_074, 0).saturating_mul(r.into())) + // Measured: `856 + r * (800 ±0)` + // Estimated: `24416 + r * (4805 ±0)` + // Minimum execution time: 295_180_000 picoseconds. + Weight::from_parts(308_851_025, 24416) + // Standard Error: 115_126 + .saturating_add(Weight::from_parts(98_678_404, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 4805).saturating_mul(r.into())) @@ -2825,13 +2687,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_gas(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `841 + r * (320 ±0)` - // Estimated: `17120 + r * (1600 ±0)` - // Minimum execution time: 133_849 nanoseconds. - Weight::from_parts(137_283_391, 0) - .saturating_add(Weight::from_parts(0, 17120)) - // Standard Error: 13_312 - .saturating_add(Weight::from_parts(8_055_328, 0).saturating_mul(r.into())) + // Measured: `745 + r * (320 ±0)` + // Estimated: `21590 + r * (1600 ±0)` + // Minimum execution time: 151_587_000 picoseconds. + Weight::from_parts(155_713_096, 21590) + // Standard Error: 32_464 + .saturating_add(Weight::from_parts(8_332_778, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1600).saturating_mul(r.into())) @@ -2849,13 +2710,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_input(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `876 + r * (480 ±0)` - // Estimated: `17245 + r * (2400 ±0)` - // Minimum execution time: 373_468 nanoseconds. - Weight::from_parts(376_121_093, 0) - .saturating_add(Weight::from_parts(0, 17245)) - // Standard Error: 61_857 - .saturating_add(Weight::from_parts(15_868_414, 0).saturating_mul(r.into())) + // Measured: `780 + r * (480 ±0)` + // Estimated: `21715 + r * (2400 ±0)` + // Minimum execution time: 295_008_000 picoseconds. + Weight::from_parts(297_982_800, 21715) + // Standard Error: 37_480 + .saturating_add(Weight::from_parts(17_970_520, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 2400).saturating_mul(r.into())) @@ -2873,13 +2733,12 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 1024]`. fn seal_input_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1356` - // Estimated: `19650` - // Minimum execution time: 390_668 nanoseconds. - Weight::from_parts(419_608_449, 0) - .saturating_add(Weight::from_parts(0, 19650)) - // Standard Error: 4_890 - .saturating_add(Weight::from_parts(9_672_288, 0).saturating_mul(n.into())) + // Measured: `1260` + // Estimated: `24120` + // Minimum execution time: 314_970_000 picoseconds. + Weight::from_parts(345_339_508, 24120) + // Standard Error: 4_112 + .saturating_add(Weight::from_parts(9_746_966, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -2896,13 +2755,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1]`. fn seal_return(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `864 + r * (45 ±0)` - // Estimated: `17190 + r * (225 ±0)` - // Minimum execution time: 371_309 nanoseconds. - Weight::from_parts(373_625_402, 0) - .saturating_add(Weight::from_parts(0, 17190)) - // Standard Error: 419_605 - .saturating_add(Weight::from_parts(1_737_397, 0).saturating_mul(r.into())) + // Measured: `768 + r * (45 ±0)` + // Estimated: `21660 + r * (225 ±0)` + // Minimum execution time: 293_072_000 picoseconds. + Weight::from_parts(295_694_824, 21660) + // Standard Error: 219_523 + .saturating_add(Weight::from_parts(783_975, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 225).saturating_mul(r.into())) @@ -2920,13 +2778,12 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 1024]`. fn seal_return_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `874` - // Estimated: `17285` - // Minimum execution time: 374_094 nanoseconds. - Weight::from_parts(375_965_200, 0) - .saturating_add(Weight::from_parts(0, 17285)) - // Standard Error: 1_127 - .saturating_add(Weight::from_parts(232_645, 0).saturating_mul(n.into())) + // Measured: `778` + // Estimated: `21755` + // Minimum execution time: 295_959_000 picoseconds. + Weight::from_parts(299_004_761, 21755) + // Standard Error: 3_988 + .saturating_add(Weight::from_parts(194_268, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -2947,18 +2804,17 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1]`. fn seal_terminate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `906 + r * (452 ±0)` - // Estimated: `20242 + r * (15004 ±0)` - // Minimum execution time: 373_123 nanoseconds. - Weight::from_parts(374_924_634, 0) - .saturating_add(Weight::from_parts(0, 20242)) - // Standard Error: 378_010 - .saturating_add(Weight::from_parts(70_441_665, 0).saturating_mul(r.into())) + // Measured: `810 + r * (356 ±0)` + // Estimated: `25511 + r * (15321 ±0)` + // Minimum execution time: 294_626_000 picoseconds. + Weight::from_parts(297_839_179, 25511) + // Standard Error: 707_428 + .saturating_add(Weight::from_parts(81_507_620, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((6_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((7_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 15004).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 15321).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2975,13 +2831,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_random(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `921 + r * (800 ±0)` - // Estimated: `18835 + r * (4805 ±0)` - // Minimum execution time: 373_291 nanoseconds. - Weight::from_parts(385_684_344, 0) - .saturating_add(Weight::from_parts(0, 18835)) - // Standard Error: 99_025 - .saturating_add(Weight::from_parts(111_308_793, 0).saturating_mul(r.into())) + // Measured: `825 + r * (800 ±0)` + // Estimated: `24199 + r * (4805 ±0)` + // Minimum execution time: 295_431_000 picoseconds. + Weight::from_parts(310_428_531, 24199) + // Standard Error: 143_501 + .saturating_add(Weight::from_parts(136_529_376, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 4805).saturating_mul(r.into())) @@ -2999,13 +2854,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_deposit_event(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `874 + r * (800 ±0)` - // Estimated: `17250 + r * (4000 ±0)` - // Minimum execution time: 371_900 nanoseconds. - Weight::from_parts(384_166_626, 0) - .saturating_add(Weight::from_parts(0, 17250)) - // Standard Error: 205_255 - .saturating_add(Weight::from_parts(229_214_157, 0).saturating_mul(r.into())) + // Measured: `778 + r * (800 ±0)` + // Estimated: `21720 + r * (4000 ±0)` + // Minimum execution time: 293_778_000 picoseconds. + Weight::from_parts(323_404_081, 21720) + // Standard Error: 243_095 + .saturating_add(Weight::from_parts(269_012_482, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 4000).saturating_mul(r.into())) @@ -3024,15 +2878,14 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 16]`. fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1821 + t * (2608 ±0) + n * (7 ±0)` - // Estimated: `21870 + t * (211030 ±0) + n * (50 ±0)` - // Minimum execution time: 1_289_873 nanoseconds. - Weight::from_parts(581_702_206, 0) - .saturating_add(Weight::from_parts(0, 21870)) - // Standard Error: 665_638 - .saturating_add(Weight::from_parts(181_470_553, 0).saturating_mul(t.into())) - // Standard Error: 182_816 - .saturating_add(Weight::from_parts(71_635_250, 0).saturating_mul(n.into())) + // Measured: `1725 + t * (2608 ±0) + n * (7 ±0)` + // Estimated: `26340 + t * (211030 ±0) + n * (50 ±0)` + // Minimum execution time: 1_317_129_000 picoseconds. + Weight::from_parts(566_722_295, 26340) + // Standard Error: 619_390 + .saturating_add(Weight::from_parts(194_334_643, 0).saturating_mul(t.into())) + // Standard Error: 170_114 + .saturating_add(Weight::from_parts(67_458_751, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(t.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3053,13 +2906,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_debug_message(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `873 + r * (560 ±0)` - // Estimated: `17240 + r * (2800 ±0)` - // Minimum execution time: 148_635 nanoseconds. - Weight::from_parts(154_095_712, 0) - .saturating_add(Weight::from_parts(0, 17240)) - // Standard Error: 77_790 - .saturating_add(Weight::from_parts(14_837_085, 0).saturating_mul(r.into())) + // Measured: `777 + r * (560 ±0)` + // Estimated: `21710 + r * (2800 ±0)` + // Minimum execution time: 159_087_000 picoseconds. + Weight::from_parts(163_703_981, 21710) + // Standard Error: 26_067 + .saturating_add(Weight::from_parts(14_810_256, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 2800).saturating_mul(r.into())) @@ -3077,13 +2929,12 @@ impl WeightInfo for () { /// The range of component `i` is `[0, 1024]`. fn seal_debug_message_per_kb(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `125824` - // Estimated: `265128` - // Minimum execution time: 501_014 nanoseconds. - Weight::from_parts(505_634_218, 0) - .saturating_add(Weight::from_parts(0, 265128)) - // Standard Error: 2_441 - .saturating_add(Weight::from_parts(819_257, 0).saturating_mul(i.into())) + // Measured: `125728` + // Estimated: `269982` + // Minimum execution time: 413_391_000 picoseconds. + Weight::from_parts(414_927_640, 269982) + // Standard Error: 1_740 + .saturating_add(Weight::from_parts(763_359, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3092,13 +2943,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 10]`. fn seal_set_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `911 + r * (23420 ±0)` - // Estimated: `911 + r * (23418 ±0)` - // Minimum execution time: 375_301 nanoseconds. - Weight::from_parts(291_498_841, 0) - .saturating_add(Weight::from_parts(0, 911)) - // Standard Error: 809_989 - .saturating_add(Weight::from_parts(464_550_291, 0).saturating_mul(r.into())) + // Measured: `815 + r * (23420 ±0)` + // Estimated: `815 + r * (23418 ±0)` + // Minimum execution time: 296_108_000 picoseconds. + Weight::from_parts(208_214_040, 815) + // Standard Error: 860_573 + .saturating_add(Weight::from_parts(480_342_550, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3110,13 +2960,12 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_new_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `12672 + n * (11945 ±0)` - // Estimated: `8529 + n * (12814 ±61)` - // Minimum execution time: 506_318 nanoseconds. - Weight::from_parts(676_935_313, 0) - .saturating_add(Weight::from_parts(0, 8529)) - // Standard Error: 1_589_291 - .saturating_add(Weight::from_parts(97_839_399, 0).saturating_mul(n.into())) + // Measured: `12544 + n * (11945 ±0)` + // Estimated: `8401 + n * (12814 ±61)` + // Minimum execution time: 442_286_000 picoseconds. + Weight::from_parts(620_395_299, 8401) + // Standard Error: 1_661_554 + .saturating_add(Weight::from_parts(89_393_169, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(52_u64)) .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(50_u64)) @@ -3128,31 +2977,29 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_old_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `15170 + n * (175775 ±0)` - // Estimated: `9914 + n * (176858 ±74)` - // Minimum execution time: 506_148 nanoseconds. - Weight::from_parts(648_278_778, 0) - .saturating_add(Weight::from_parts(0, 9914)) - // Standard Error: 1_343_586 - .saturating_add(Weight::from_parts(65_789_595, 0).saturating_mul(n.into())) + // Measured: `12532 + n * (175784 ±0)` + // Estimated: `8396 + n * (176649 ±61)` + // Minimum execution time: 440_882_000 picoseconds. + Weight::from_parts(587_317_981, 8396) + // Standard Error: 1_374_991 + .saturating_add(Weight::from_parts(66_271_084, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(51_u64)) .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(49_u64)) .saturating_add(RocksDbWeight::get().writes((7_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 176858).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 176649).saturating_mul(n.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 10]`. fn seal_clear_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `903 + r * (23099 ±0)` - // Estimated: `908 + r * (23099 ±0)` - // Minimum execution time: 374_344 nanoseconds. - Weight::from_parts(293_272_061, 0) - .saturating_add(Weight::from_parts(0, 908)) - // Standard Error: 810_412 - .saturating_add(Weight::from_parts(453_315_956, 0).saturating_mul(r.into())) + // Measured: `807 + r * (23099 ±0)` + // Estimated: `812 + r * (23099 ±0)` + // Minimum execution time: 296_023_000 picoseconds. + Weight::from_parts(221_471_559, 812) + // Standard Error: 814_503 + .saturating_add(Weight::from_parts(465_928_089, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3164,31 +3011,29 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 8]`. fn seal_clear_storage_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `14895 + n * (175768 ±0)` - // Estimated: `9551 + n * (176867 ±75)` - // Minimum execution time: 478_564 nanoseconds. - Weight::from_parts(630_839_142, 0) - .saturating_add(Weight::from_parts(0, 9551)) - // Standard Error: 1_427_520 - .saturating_add(Weight::from_parts(66_813_592, 0).saturating_mul(n.into())) + // Measured: `12256 + n * (175776 ±0)` + // Estimated: `8047 + n * (176655 ±62)` + // Minimum execution time: 412_212_000 picoseconds. + Weight::from_parts(569_213_147, 8047) + // Standard Error: 1_463_771 + .saturating_add(Weight::from_parts(67_932_081, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(51_u64)) .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(48_u64)) .saturating_add(RocksDbWeight::get().writes((7_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 176867).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 176655).saturating_mul(n.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 10]`. fn seal_get_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `896 + r * (23744 ±0)` - // Estimated: `909 + r * (23740 ±0)` - // Minimum execution time: 374_479 nanoseconds. - Weight::from_parts(311_839_315, 0) - .saturating_add(Weight::from_parts(0, 909)) - // Standard Error: 666_553 - .saturating_add(Weight::from_parts(371_213_042, 0).saturating_mul(r.into())) + // Measured: `800 + r * (23744 ±0)` + // Estimated: `813 + r * (23740 ±0)` + // Minimum execution time: 296_007_000 picoseconds. + Weight::from_parts(229_100_700, 813) + // Standard Error: 684_970 + .saturating_add(Weight::from_parts(394_982_991, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3199,30 +3044,28 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 8]`. fn seal_get_storage_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `15501 + n * (175775 ±0)` - // Estimated: `10042 + n * (176900 ±76)` - // Minimum execution time: 460_639 nanoseconds. - Weight::from_parts(591_187_094, 0) - .saturating_add(Weight::from_parts(0, 10042)) - // Standard Error: 1_233_792 - .saturating_add(Weight::from_parts(160_874_477, 0).saturating_mul(n.into())) + // Measured: `12863 + n * (175784 ±0)` + // Estimated: `8538 + n * (176688 ±63)` + // Minimum execution time: 392_306_000 picoseconds. + Weight::from_parts(539_188_004, 8538) + // Standard Error: 1_371_839 + .saturating_add(Weight::from_parts(155_130_373, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(51_u64)) .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 176900).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 176688).saturating_mul(n.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 10]`. fn seal_contains_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `914 + r * (23098 ±0)` - // Estimated: `920 + r * (23098 ±0)` - // Minimum execution time: 374_272 nanoseconds. - Weight::from_parts(311_446_269, 0) - .saturating_add(Weight::from_parts(0, 920)) - // Standard Error: 630_307 - .saturating_add(Weight::from_parts(357_134_931, 0).saturating_mul(r.into())) + // Measured: `818 + r * (23098 ±0)` + // Estimated: `824 + r * (23098 ±0)` + // Minimum execution time: 296_038_000 picoseconds. + Weight::from_parts(229_462_798, 824) + // Standard Error: 655_463 + .saturating_add(Weight::from_parts(372_593_685, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3233,30 +3076,28 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 8]`. fn seal_contains_storage_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `14839 + n * (175789 ±0)` - // Estimated: `9532 + n * (176874 ±75)` - // Minimum execution time: 456_013 nanoseconds. - Weight::from_parts(575_116_352, 0) - .saturating_add(Weight::from_parts(0, 9532)) - // Standard Error: 1_122_298 - .saturating_add(Weight::from_parts(61_786_107, 0).saturating_mul(n.into())) + // Measured: `12200 + n * (175798 ±0)` + // Estimated: `8028 + n * (176661 ±62)` + // Minimum execution time: 386_782_000 picoseconds. + Weight::from_parts(512_965_975, 8028) + // Standard Error: 1_168_132 + .saturating_add(Weight::from_parts(63_307_325, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(51_u64)) .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 176874).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 176661).saturating_mul(n.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 10]`. fn seal_take_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `911 + r * (23740 ±0)` - // Estimated: `913 + r * (23739 ±0)` - // Minimum execution time: 374_621 nanoseconds. - Weight::from_parts(299_689_489, 0) - .saturating_add(Weight::from_parts(0, 913)) - // Standard Error: 757_735 - .saturating_add(Weight::from_parts(465_213_246, 0).saturating_mul(r.into())) + // Measured: `815 + r * (23740 ±0)` + // Estimated: `817 + r * (23739 ±0)` + // Minimum execution time: 296_352_000 picoseconds. + Weight::from_parts(212_661_296, 817) + // Standard Error: 879_297 + .saturating_add(Weight::from_parts(494_182_672, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3268,18 +3109,17 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 8]`. fn seal_take_storage_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `15502 + n * (175775 ±0)` - // Estimated: `10042 + n * (176898 ±76)` - // Minimum execution time: 481_980 nanoseconds. - Weight::from_parts(647_289_053, 0) - .saturating_add(Weight::from_parts(0, 10042)) - // Standard Error: 1_556_155 - .saturating_add(Weight::from_parts(166_592_657, 0).saturating_mul(n.into())) + // Measured: `12864 + n * (175784 ±0)` + // Estimated: `8539 + n * (176686 ±63)` + // Minimum execution time: 414_693_000 picoseconds. + Weight::from_parts(595_693_859, 8539) + // Standard Error: 1_673_819 + .saturating_add(Weight::from_parts(163_090_316, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(51_u64)) .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(48_u64)) .saturating_add(RocksDbWeight::get().writes((7_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 176898).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 176686).saturating_mul(n.into())) } /// Storage: System Account (r:1602 w:1601) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3294,18 +3134,17 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_transfer(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1457 + r * (3604 ±0)` - // Estimated: `21583 + r * (216101 ±0)` - // Minimum execution time: 374_962 nanoseconds. - Weight::from_parts(313_416_386, 0) - .saturating_add(Weight::from_parts(0, 21583)) - // Standard Error: 710_675 - .saturating_add(Weight::from_parts(1_396_551_156, 0).saturating_mul(r.into())) + // Measured: `1329 + r * (3604 ±0)` + // Estimated: `25928 + r * (216096 ±4)` + // Minimum execution time: 299_205_000 picoseconds. + Weight::from_parts(221_142_217, 25928) + // Standard Error: 1_369_909 + .saturating_add(Weight::from_parts(1_665_917_241, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(RocksDbWeight::get().writes((80_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 216101).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 216096).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3320,18 +3159,17 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_call(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1609 + r * (23073 ±0)` - // Estimated: `22098 + r * (511456 ±1)` - // Minimum execution time: 375_916 nanoseconds. - Weight::from_parts(376_468_000, 0) - .saturating_add(Weight::from_parts(0, 22098)) - // Standard Error: 7_246_855 - .saturating_add(Weight::from_parts(28_982_425_139, 0).saturating_mul(r.into())) + // Measured: `1479 + r * (20514 ±0)` + // Estimated: `26429 + r * (498656 ±1)` + // Minimum execution time: 297_501_000 picoseconds. + Weight::from_parts(298_400_000, 26429) + // Standard Error: 9_372_890 + .saturating_add(Weight::from_parts(22_507_984_433, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().reads((160_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((160_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 511456).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 498656).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3346,18 +3184,17 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_delegate_call(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0 + r * (71670 ±0)` - // Estimated: `17285 + r * (659930 ±563)` - // Minimum execution time: 375_412 nanoseconds. - Weight::from_parts(376_493_000, 0) - .saturating_add(Weight::from_parts(0, 17285)) - // Standard Error: 8_239_575 - .saturating_add(Weight::from_parts(28_716_347_183, 0).saturating_mul(r.into())) + // Measured: `0 + r * (69030 ±0)` + // Estimated: `21755 + r * (647542 ±560)` + // Minimum execution time: 297_432_000 picoseconds. + Weight::from_parts(298_220_000, 21755) + // Standard Error: 9_420_834 + .saturating_add(Weight::from_parts(22_261_152_353, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((150_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((75_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 659930).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 647542).saturating_mul(r.into())) } /// Storage: System Account (r:82 w:81) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3373,20 +3210,19 @@ impl WeightInfo for () { /// The range of component `c` is `[0, 1024]`. fn seal_call_per_transfer_clone_kb(t: u32, c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `24269 + t * (16910 ±0)` - // Estimated: `532690 + t * (285025 ±0)` - // Minimum execution time: 10_443_315 nanoseconds. - Weight::from_parts(9_342_574_069, 0) - .saturating_add(Weight::from_parts(0, 532690)) - // Standard Error: 7_237_279 - .saturating_add(Weight::from_parts(1_390_221_936, 0).saturating_mul(t.into())) - // Standard Error: 10_851 - .saturating_add(Weight::from_parts(9_842_151, 0).saturating_mul(c.into())) + // Measured: `21581 + t * (14318 ±0)` + // Estimated: `524200 + t * (272065 ±0)` + // Minimum execution time: 11_799_802_000 picoseconds. + Weight::from_parts(10_575_328_547, 524200) + // Standard Error: 11_952_810 + .saturating_add(Weight::from_parts(1_603_077_083, 0).saturating_mul(t.into())) + // Standard Error: 17_922 + .saturating_add(Weight::from_parts(9_876_752, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(167_u64)) .saturating_add(RocksDbWeight::get().reads((81_u64).saturating_mul(t.into()))) .saturating_add(RocksDbWeight::get().writes(163_u64)) .saturating_add(RocksDbWeight::get().writes((81_u64).saturating_mul(t.into()))) - .saturating_add(Weight::from_parts(0, 285025).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(0, 272065).saturating_mul(t.into())) } /// Storage: System Account (r:3202 w:3202) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3405,18 +3241,17 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_instantiate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1775 + r * (25568 ±0)` - // Estimated: `26563 + r * (1367114 ±2)` - // Minimum execution time: 376_418 nanoseconds. - Weight::from_parts(377_292_000, 0) - .saturating_add(Weight::from_parts(0, 26563)) - // Standard Error: 32_312_545 - .saturating_add(Weight::from_parts(35_904_826_312, 0).saturating_mul(r.into())) + // Measured: `1646 + r * (20288 ±0)` + // Estimated: `32625 + r * (1330150 ±2)` + // Minimum execution time: 298_155_000 picoseconds. + Weight::from_parts(299_212_000, 32625) + // Standard Error: 32_410_313 + .saturating_add(Weight::from_parts(30_417_025_178, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().reads((480_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(5_u64)) .saturating_add(RocksDbWeight::get().writes((400_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 1367114).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 1330150).saturating_mul(r.into())) } /// Storage: System Account (r:162 w:162) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3437,22 +3272,21 @@ impl WeightInfo for () { /// The range of component `s` is `[0, 960]`. fn seal_instantiate_per_transfer_input_salt_kb(t: u32, i: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `5785 + t * (33 ±0)` - // Estimated: `850985 + t * (2671 ±3)` - // Minimum execution time: 132_157_340 nanoseconds. - Weight::from_parts(11_329_968_948, 0) - .saturating_add(Weight::from_parts(0, 850985)) - // Standard Error: 99_102_968 - .saturating_add(Weight::from_parts(84_719_458, 0).saturating_mul(t.into())) - // Standard Error: 161_609 - .saturating_add(Weight::from_parts(126_156_627, 0).saturating_mul(i.into())) - // Standard Error: 161_609 - .saturating_add(Weight::from_parts(126_628_313, 0).saturating_mul(s.into())) + // Measured: `5625 + t * (1 ±0)` + // Estimated: `856795 + t * (2471 ±3)` + // Minimum execution time: 105_914_928_000 picoseconds. + Weight::from_parts(13_229_760_432, 856795) + // Standard Error: 96_394_437 + .saturating_add(Weight::from_parts(398_413_888, 0).saturating_mul(t.into())) + // Standard Error: 157_192 + .saturating_add(Weight::from_parts(97_104_978, 0).saturating_mul(i.into())) + // Standard Error: 157_192 + .saturating_add(Weight::from_parts(97_146_130, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(329_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(t.into()))) .saturating_add(RocksDbWeight::get().writes(326_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(t.into()))) - .saturating_add(Weight::from_parts(0, 2671).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(0, 2471).saturating_mul(t.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3467,13 +3301,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1]`. fn seal_hash_sha2_256(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `871 + r * (642 ±0)` - // Estimated: `17225 + r * (3210 ±0)` - // Minimum execution time: 373_559 nanoseconds. - Weight::from_parts(375_166_904, 0) - .saturating_add(Weight::from_parts(0, 17225)) - // Standard Error: 125_024 - .saturating_add(Weight::from_parts(42_291_595, 0).saturating_mul(r.into())) + // Measured: `775 + r * (642 ±0)` + // Estimated: `21695 + r * (3210 ±0)` + // Minimum execution time: 294_309_000 picoseconds. + Weight::from_parts(296_241_318, 21695) + // Standard Error: 127_872 + .saturating_add(Weight::from_parts(45_806_281, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 3210).saturating_mul(r.into())) @@ -3491,13 +3324,12 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 1024]`. fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1673` - // Estimated: `21160` - // Minimum execution time: 416_233 nanoseconds. - Weight::from_parts(416_785_000, 0) - .saturating_add(Weight::from_parts(0, 21160)) - // Standard Error: 56_223 - .saturating_add(Weight::from_parts(324_513_835, 0).saturating_mul(n.into())) + // Measured: `1577` + // Estimated: `25630` + // Minimum execution time: 341_248_000 picoseconds. + Weight::from_parts(341_607_000, 25630) + // Standard Error: 66_687 + .saturating_add(Weight::from_parts(322_250_398, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3514,13 +3346,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1]`. fn seal_hash_keccak_256(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `873 + r * (642 ±0)` - // Estimated: `17235 + r * (3210 ±0)` - // Minimum execution time: 371_735 nanoseconds. - Weight::from_parts(375_979_430, 0) - .saturating_add(Weight::from_parts(0, 17235)) - // Standard Error: 968_037 - .saturating_add(Weight::from_parts(57_780_769, 0).saturating_mul(r.into())) + // Measured: `777 + r * (642 ±0)` + // Estimated: `21705 + r * (3210 ±0)` + // Minimum execution time: 293_810_000 picoseconds. + Weight::from_parts(296_719_171, 21705) + // Standard Error: 450_807 + .saturating_add(Weight::from_parts(61_627_228, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 3210).saturating_mul(r.into())) @@ -3538,13 +3369,12 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 1024]`. fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1675` - // Estimated: `21205` - // Minimum execution time: 428_196 nanoseconds. - Weight::from_parts(429_438_000, 0) - .saturating_add(Weight::from_parts(0, 21205)) - // Standard Error: 57_860 - .saturating_add(Weight::from_parts(260_917_896, 0).saturating_mul(n.into())) + // Measured: `1579` + // Estimated: `25675` + // Minimum execution time: 354_550_000 picoseconds. + Weight::from_parts(355_136_000, 25675) + // Standard Error: 61_761 + .saturating_add(Weight::from_parts(257_021_566, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3561,13 +3391,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1]`. fn seal_hash_blake2_256(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `873 + r * (642 ±0)` - // Estimated: `17235 + r * (3210 ±0)` - // Minimum execution time: 371_412 nanoseconds. - Weight::from_parts(373_635_818, 0) - .saturating_add(Weight::from_parts(0, 17235)) - // Standard Error: 222_973 - .saturating_add(Weight::from_parts(33_347_181, 0).saturating_mul(r.into())) + // Measured: `777 + r * (642 ±0)` + // Estimated: `21705 + r * (3210 ±0)` + // Minimum execution time: 293_369_000 picoseconds. + Weight::from_parts(295_990_893, 21705) + // Standard Error: 431_269 + .saturating_add(Weight::from_parts(32_213_406, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 3210).saturating_mul(r.into())) @@ -3585,13 +3414,12 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1675` - // Estimated: `21180` - // Minimum execution time: 405_858 nanoseconds. - Weight::from_parts(406_498_000, 0) - .saturating_add(Weight::from_parts(0, 21180)) - // Standard Error: 48_388 - .saturating_add(Weight::from_parts(103_283_157, 0).saturating_mul(n.into())) + // Measured: `1579` + // Estimated: `25650` + // Minimum execution time: 326_595_000 picoseconds. + Weight::from_parts(327_188_000, 25650) + // Standard Error: 53_385 + .saturating_add(Weight::from_parts(74_046_074, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3608,13 +3436,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1]`. fn seal_hash_blake2_128(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `873 + r * (679 ±0)` - // Estimated: `17235 + r * (3395 ±0)` - // Minimum execution time: 371_746 nanoseconds. - Weight::from_parts(373_538_171, 0) - .saturating_add(Weight::from_parts(0, 17235)) - // Standard Error: 387_332 - .saturating_add(Weight::from_parts(35_933_528, 0).saturating_mul(r.into())) + // Measured: `777 + r * (679 ±0)` + // Estimated: `21705 + r * (3395 ±0)` + // Minimum execution time: 292_388_000 picoseconds. + Weight::from_parts(295_090_179, 21705) + // Standard Error: 170_487 + .saturating_add(Weight::from_parts(32_577_820, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 3395).saturating_mul(r.into())) @@ -3632,13 +3459,12 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1675` - // Estimated: `21225` - // Minimum execution time: 405_752 nanoseconds. - Weight::from_parts(406_417_000, 0) - .saturating_add(Weight::from_parts(0, 21225)) - // Standard Error: 47_051 - .saturating_add(Weight::from_parts(103_325_027, 0).saturating_mul(n.into())) + // Measured: `1579` + // Estimated: `25695` + // Minimum execution time: 326_862_000 picoseconds. + Weight::from_parts(327_449_000, 25695) + // Standard Error: 54_539 + .saturating_add(Weight::from_parts(74_042_337, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3655,13 +3481,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1]`. fn seal_ecdsa_recover(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `917 + r * (6083 ±0)` - // Estimated: `17455 + r * (30415 ±0)` - // Minimum execution time: 373_882 nanoseconds. - Weight::from_parts(376_553_787, 0) - .saturating_add(Weight::from_parts(0, 17455)) - // Standard Error: 912_833 - .saturating_add(Weight::from_parts(3_021_100_412, 0).saturating_mul(r.into())) + // Measured: `821 + r * (6083 ±0)` + // Estimated: `21925 + r * (30415 ±0)` + // Minimum execution time: 295_597_000 picoseconds. + Weight::from_parts(298_267_200, 21925) + // Standard Error: 699_824 + .saturating_add(Weight::from_parts(3_021_734_700, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30415).saturating_mul(r.into())) @@ -3679,13 +3504,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1]`. fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `886 + r * (3362 ±0)` - // Estimated: `17300 + r * (16810 ±0)` - // Minimum execution time: 373_673 nanoseconds. - Weight::from_parts(375_712_961, 0) - .saturating_add(Weight::from_parts(0, 17300)) - // Standard Error: 596_297 - .saturating_add(Weight::from_parts(738_257_638, 0).saturating_mul(r.into())) + // Measured: `790 + r * (3362 ±0)` + // Estimated: `21770 + r * (16810 ±0)` + // Minimum execution time: 295_539_000 picoseconds. + Weight::from_parts(297_844_822, 21770) + // Standard Error: 490_532 + .saturating_add(Weight::from_parts(747_592_977, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 16810).saturating_mul(r.into())) @@ -3705,18 +3529,17 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_set_code_hash(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0 + r * (79300 ±0)` - // Estimated: `64844 + r * (942952 ±833)` - // Minimum execution time: 374_097 nanoseconds. - Weight::from_parts(374_985_000, 0) - .saturating_add(Weight::from_parts(0, 64844)) - // Standard Error: 3_772_336 - .saturating_add(Weight::from_parts(1_546_402_854, 0).saturating_mul(r.into())) + // Measured: `0 + r * (74020 ±0)` + // Estimated: `69192 + r * (913289 ±821)` + // Minimum execution time: 295_164_000 picoseconds. + Weight::from_parts(296_597_000, 69192) + // Standard Error: 3_646_577 + .saturating_add(Weight::from_parts(1_725_796_807, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((225_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((150_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 942952).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 913289).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3731,13 +3554,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_reentrance_count(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `869 + r * (240 ±0)` - // Estimated: `17215 + r * (1200 ±0)` - // Minimum execution time: 374_249 nanoseconds. - Weight::from_parts(377_990_998, 0) - .saturating_add(Weight::from_parts(0, 17215)) - // Standard Error: 38_133 - .saturating_add(Weight::from_parts(11_483_273, 0).saturating_mul(r.into())) + // Measured: `773 + r * (240 ±0)` + // Estimated: `21685 + r * (1200 ±0)` + // Minimum execution time: 296_287_000 picoseconds. + Weight::from_parts(300_696_694, 21685) + // Standard Error: 27_891 + .saturating_add(Weight::from_parts(10_943_994, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1200).saturating_mul(r.into())) @@ -3755,13 +3577,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_account_reentrance_count(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2102 + r * (3154 ±0)` - // Estimated: `21980 + r * (15875 ±2)` - // Minimum execution time: 375_552 nanoseconds. - Weight::from_parts(400_624_032, 0) - .saturating_add(Weight::from_parts(0, 21980)) - // Standard Error: 82_523 - .saturating_add(Weight::from_parts(18_057_327, 0).saturating_mul(r.into())) + // Measured: `2006 + r * (3154 ±0)` + // Estimated: `26435 + r * (15875 ±2)` + // Minimum execution time: 298_000_000 picoseconds. + Weight::from_parts(328_282_119, 26435) + // Standard Error: 104_874 + .saturating_add(Weight::from_parts(18_428_267, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 15875).saturating_mul(r.into())) @@ -3781,13 +3602,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 20]`. fn seal_instantiation_nonce(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `872 + r * (240 ±0)` - // Estimated: `18598 + r * (1440 ±0)` - // Minimum execution time: 373_899 nanoseconds. - Weight::from_parts(379_733_943, 0) - .saturating_add(Weight::from_parts(0, 18598)) - // Standard Error: 32_022 - .saturating_add(Weight::from_parts(9_381_180, 0).saturating_mul(r.into())) + // Measured: `776 + r * (240 ±0)` + // Estimated: `23962 + r * (1440 ±0)` + // Minimum execution time: 295_104_000 picoseconds. + Weight::from_parts(299_334_585, 23962) + // Standard Error: 25_840 + .saturating_add(Weight::from_parts(9_744_866, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1440).saturating_mul(r.into())) @@ -3797,571 +3617,519 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 834 nanoseconds. - Weight::from_parts(1_009_646, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 388 - .saturating_add(Weight::from_parts(411_979, 0).saturating_mul(r.into())) + // Minimum execution time: 1_132_000 picoseconds. + Weight::from_parts(1_100_159, 0) + // Standard Error: 10_131 + .saturating_add(Weight::from_parts(436_462, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64load(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 882 nanoseconds. - Weight::from_parts(1_416_377, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 1_133 - .saturating_add(Weight::from_parts(1_075_838, 0).saturating_mul(r.into())) + // Minimum execution time: 1_368_000 picoseconds. + Weight::from_parts(1_974_308, 0) + // Standard Error: 811 + .saturating_add(Weight::from_parts(1_079_620, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64store(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 878 nanoseconds. - Weight::from_parts(1_343_056, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 426 - .saturating_add(Weight::from_parts(1_001_214, 0).saturating_mul(r.into())) + // Minimum execution time: 1_354_000 picoseconds. + Weight::from_parts(2_057_834, 0) + // Standard Error: 4_277 + .saturating_add(Weight::from_parts(1_008_797, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_select(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 796 nanoseconds. - Weight::from_parts(1_079_086, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 409 - .saturating_add(Weight::from_parts(1_149_188, 0).saturating_mul(r.into())) + // Minimum execution time: 1_218_000 picoseconds. + Weight::from_parts(1_594_528, 0) + // Standard Error: 723 + .saturating_add(Weight::from_parts(1_147_486, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_if(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 800 nanoseconds. - Weight::from_parts(1_044_184, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 707 - .saturating_add(Weight::from_parts(1_315_686, 0).saturating_mul(r.into())) + // Minimum execution time: 1_156_000 picoseconds. + Weight::from_parts(1_460_611, 0) + // Standard Error: 419 + .saturating_add(Weight::from_parts(1_314_741, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_br(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 807 nanoseconds. - Weight::from_parts(1_049_633, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 361 - .saturating_add(Weight::from_parts(640_530, 0).saturating_mul(r.into())) + // Minimum execution time: 1_166_000 picoseconds. + Weight::from_parts(1_454_460, 0) + // Standard Error: 493 + .saturating_add(Weight::from_parts(642_481, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_br_if(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 774 nanoseconds. - Weight::from_parts(1_124_053, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 784 - .saturating_add(Weight::from_parts(949_398, 0).saturating_mul(r.into())) + // Minimum execution time: 1_144_000 picoseconds. + Weight::from_parts(1_410_515, 0) + // Standard Error: 894 + .saturating_add(Weight::from_parts(958_765, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_br_table(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 810 nanoseconds. - Weight::from_parts(676_581, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 2_356 - .saturating_add(Weight::from_parts(1_163_465, 0).saturating_mul(r.into())) + // Minimum execution time: 1_190_000 picoseconds. + Weight::from_parts(1_143_236, 0) + // Standard Error: 2_773 + .saturating_add(Weight::from_parts(1_164_764, 0).saturating_mul(r.into())) } /// The range of component `e` is `[1, 256]`. fn instr_br_table_per_entry(e: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_580 nanoseconds. - Weight::from_parts(2_835_656, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 71 - .saturating_add(Weight::from_parts(4_686, 0).saturating_mul(e.into())) + // Minimum execution time: 2_993_000 picoseconds. + Weight::from_parts(3_270_525, 0) + // Standard Error: 65 + .saturating_add(Weight::from_parts(4_418, 0).saturating_mul(e.into())) } /// The range of component `r` is `[0, 50]`. fn instr_call(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 826 nanoseconds. - Weight::from_parts(1_625_698, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 1_740 - .saturating_add(Weight::from_parts(2_332_187, 0).saturating_mul(r.into())) + // Minimum execution time: 1_163_000 picoseconds. + Weight::from_parts(1_999_458, 0) + // Standard Error: 1_418 + .saturating_add(Weight::from_parts(2_371_979, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_call_indirect(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 901 nanoseconds. - Weight::from_parts(2_338_620, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 1_642 - .saturating_add(Weight::from_parts(2_924_090, 0).saturating_mul(r.into())) + // Minimum execution time: 1_288_000 picoseconds. + Weight::from_parts(2_340_227, 0) + // Standard Error: 3_234 + .saturating_add(Weight::from_parts(3_038_523, 0).saturating_mul(r.into())) } /// The range of component `p` is `[0, 128]`. fn instr_call_indirect_per_param(p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_670 nanoseconds. - Weight::from_parts(5_556_246, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 1_491 - .saturating_add(Weight::from_parts(228_965, 0).saturating_mul(p.into())) + // Minimum execution time: 5_270_000 picoseconds. + Weight::from_parts(6_360_011, 0) + // Standard Error: 2_585 + .saturating_add(Weight::from_parts(226_149, 0).saturating_mul(p.into())) } /// The range of component `l` is `[0, 1024]`. fn instr_call_per_local(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_099 nanoseconds. - Weight::from_parts(3_896_177, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 99 - .saturating_add(Weight::from_parts(91_304, 0).saturating_mul(l.into())) + // Minimum execution time: 3_580_000 picoseconds. + Weight::from_parts(5_183_658, 0) + // Standard Error: 80 + .saturating_add(Weight::from_parts(46_038, 0).saturating_mul(l.into())) } /// The range of component `r` is `[0, 50]`. fn instr_local_get(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_042 nanoseconds. - Weight::from_parts(3_334_621, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 793 - .saturating_add(Weight::from_parts(459_346, 0).saturating_mul(r.into())) + // Minimum execution time: 2_559_000 picoseconds. + Weight::from_parts(2_846_350, 0) + // Standard Error: 2_809 + .saturating_add(Weight::from_parts(462_084, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_local_set(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_968 nanoseconds. - Weight::from_parts(3_235_286, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 427 - .saturating_add(Weight::from_parts(485_454, 0).saturating_mul(r.into())) + // Minimum execution time: 2_530_000 picoseconds. + Weight::from_parts(2_835_072, 0) + // Standard Error: 479 + .saturating_add(Weight::from_parts(483_451, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_local_tee(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_012 nanoseconds. - Weight::from_parts(3_303_555, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 371 - .saturating_add(Weight::from_parts(657_811, 0).saturating_mul(r.into())) + // Minimum execution time: 2_510_000 picoseconds. + Weight::from_parts(2_740_081, 0) + // Standard Error: 901 + .saturating_add(Weight::from_parts(664_354, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_global_get(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 865 nanoseconds. - Weight::from_parts(1_249_987, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 417 - .saturating_add(Weight::from_parts(896_704, 0).saturating_mul(r.into())) + // Minimum execution time: 1_295_000 picoseconds. + Weight::from_parts(1_798_174, 0) + // Standard Error: 464 + .saturating_add(Weight::from_parts(896_289, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_global_set(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 866 nanoseconds. - Weight::from_parts(1_216_218, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 503 - .saturating_add(Weight::from_parts(919_719, 0).saturating_mul(r.into())) + // Minimum execution time: 1_287_000 picoseconds. + Weight::from_parts(1_636_548, 0) + // Standard Error: 658 + .saturating_add(Weight::from_parts(923_295, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_memory_current(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 921 nanoseconds. - Weight::from_parts(1_228_408, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 309 - .saturating_add(Weight::from_parts(813_007, 0).saturating_mul(r.into())) + // Minimum execution time: 1_353_000 picoseconds. + Weight::from_parts(1_672_309, 0) + // Standard Error: 403 + .saturating_add(Weight::from_parts(818_273, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 1]`. fn instr_memory_grow(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 820 nanoseconds. - Weight::from_parts(914_830, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 6_018 - .saturating_add(Weight::from_parts(237_062_769, 0).saturating_mul(r.into())) + // Minimum execution time: 1_180_000 picoseconds. + Weight::from_parts(1_304_714, 0) + // Standard Error: 88_180 + .saturating_add(Weight::from_parts(183_952_985, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64clz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 812 nanoseconds. - Weight::from_parts(1_554_406, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 9_979 - .saturating_add(Weight::from_parts(625_434, 0).saturating_mul(r.into())) + // Minimum execution time: 1_158_000 picoseconds. + Weight::from_parts(1_800_065, 0) + // Standard Error: 2_104 + .saturating_add(Weight::from_parts(625_410, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ctz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 798 nanoseconds. - Weight::from_parts(1_095_113, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 243 - .saturating_add(Weight::from_parts(634_204, 0).saturating_mul(r.into())) + // Minimum execution time: 1_208_000 picoseconds. + Weight::from_parts(1_483_908, 0) + // Standard Error: 319 + .saturating_add(Weight::from_parts(635_095, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64popcnt(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 792 nanoseconds. - Weight::from_parts(1_109_845, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 14_944 - .saturating_add(Weight::from_parts(658_834, 0).saturating_mul(r.into())) + // Minimum execution time: 1_164_000 picoseconds. + Weight::from_parts(1_506_871, 0) + // Standard Error: 264 + .saturating_add(Weight::from_parts(633_660, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64eqz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 815 nanoseconds. - Weight::from_parts(1_068_916, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 327 - .saturating_add(Weight::from_parts(652_897, 0).saturating_mul(r.into())) + // Minimum execution time: 1_141_000 picoseconds. + Weight::from_parts(1_467_219, 0) + // Standard Error: 191 + .saturating_add(Weight::from_parts(651_156, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendsi32(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 798 nanoseconds. - Weight::from_parts(1_069_745, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 306 - .saturating_add(Weight::from_parts(618_481, 0).saturating_mul(r.into())) + // Minimum execution time: 1_170_000 picoseconds. + Weight::from_parts(1_474_718, 0) + // Standard Error: 224 + .saturating_add(Weight::from_parts(617_317, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendui32(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 799 nanoseconds. - Weight::from_parts(1_398_001, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 6_234 - .saturating_add(Weight::from_parts(611_399, 0).saturating_mul(r.into())) + // Minimum execution time: 1_195_000 picoseconds. + Weight::from_parts(1_501_421, 0) + // Standard Error: 221 + .saturating_add(Weight::from_parts(616_559, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i32wrapi64(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 811 nanoseconds. - Weight::from_parts(1_098_083, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 297 - .saturating_add(Weight::from_parts(617_692, 0).saturating_mul(r.into())) + // Minimum execution time: 1_172_000 picoseconds. + Weight::from_parts(1_482_402, 0) + // Standard Error: 2_163 + .saturating_add(Weight::from_parts(619_230, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64eq(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 815 nanoseconds. - Weight::from_parts(1_046_922, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 335 - .saturating_add(Weight::from_parts(909_196, 0).saturating_mul(r.into())) + // Minimum execution time: 1_149_000 picoseconds. + Weight::from_parts(2_021_801, 0) + // Standard Error: 20_804 + .saturating_add(Weight::from_parts(913_888, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ne(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 805 nanoseconds. - Weight::from_parts(1_093_667, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 233 - .saturating_add(Weight::from_parts(907_378, 0).saturating_mul(r.into())) + // Minimum execution time: 1_187_000 picoseconds. + Weight::from_parts(1_358_437, 0) + // Standard Error: 1_946 + .saturating_add(Weight::from_parts(916_378, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64lts(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 805 nanoseconds. - Weight::from_parts(1_290_591, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 3_201 - .saturating_add(Weight::from_parts(902_006, 0).saturating_mul(r.into())) + // Minimum execution time: 1_175_000 picoseconds. + Weight::from_parts(1_527_336, 0) + // Standard Error: 243 + .saturating_add(Weight::from_parts(907_580, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ltu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 783 nanoseconds. - Weight::from_parts(1_159_977, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 2_310 - .saturating_add(Weight::from_parts(906_489, 0).saturating_mul(r.into())) + // Minimum execution time: 1_220_000 picoseconds. + Weight::from_parts(1_530_715, 0) + // Standard Error: 224 + .saturating_add(Weight::from_parts(906_096, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64gts(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 790 nanoseconds. - Weight::from_parts(1_109_719, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 261 - .saturating_add(Weight::from_parts(906_614, 0).saturating_mul(r.into())) + // Minimum execution time: 1_107_000 picoseconds. + Weight::from_parts(1_496_553, 0) + // Standard Error: 299 + .saturating_add(Weight::from_parts(907_963, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64gtu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 776 nanoseconds. - Weight::from_parts(1_076_567, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 348 - .saturating_add(Weight::from_parts(919_374, 0).saturating_mul(r.into())) + // Minimum execution time: 1_153_000 picoseconds. + Weight::from_parts(1_482_710, 0) + // Standard Error: 182 + .saturating_add(Weight::from_parts(918_439, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64les(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 780 nanoseconds. - Weight::from_parts(1_069_663, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 265 - .saturating_add(Weight::from_parts(908_037, 0).saturating_mul(r.into())) + // Minimum execution time: 1_142_000 picoseconds. + Weight::from_parts(1_522_114, 0) + // Standard Error: 297 + .saturating_add(Weight::from_parts(906_633, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64leu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 832 nanoseconds. - Weight::from_parts(930_920, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 2_170 - .saturating_add(Weight::from_parts(929_811, 0).saturating_mul(r.into())) + // Minimum execution time: 1_119_000 picoseconds. + Weight::from_parts(2_199_831, 0) + // Standard Error: 4_234 + .saturating_add(Weight::from_parts(898_161, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64ges(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 787 nanoseconds. - Weight::from_parts(1_087_325, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 315 - .saturating_add(Weight::from_parts(908_321, 0).saturating_mul(r.into())) + // Minimum execution time: 1_163_000 picoseconds. + Weight::from_parts(1_489_404, 0) + // Standard Error: 416 + .saturating_add(Weight::from_parts(908_450, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64geu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 798 nanoseconds. - Weight::from_parts(1_029_132, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 2_095 - .saturating_add(Weight::from_parts(913_553, 0).saturating_mul(r.into())) + // Minimum execution time: 1_204_000 picoseconds. + Weight::from_parts(2_266_296, 0) + // Standard Error: 13_013 + .saturating_add(Weight::from_parts(899_225, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64add(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 791 nanoseconds. - Weight::from_parts(1_086_314, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 197 - .saturating_add(Weight::from_parts(896_392, 0).saturating_mul(r.into())) + // Minimum execution time: 1_160_000 picoseconds. + Weight::from_parts(1_470_799, 0) + // Standard Error: 422 + .saturating_add(Weight::from_parts(897_325, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64sub(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 793 nanoseconds. - Weight::from_parts(1_078_172, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 404 - .saturating_add(Weight::from_parts(886_329, 0).saturating_mul(r.into())) + // Minimum execution time: 1_125_000 picoseconds. + Weight::from_parts(1_521_508, 0) + // Standard Error: 594 + .saturating_add(Weight::from_parts(886_145, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64mul(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 799 nanoseconds. - Weight::from_parts(1_095_010, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 431 - .saturating_add(Weight::from_parts(886_513, 0).saturating_mul(r.into())) + // Minimum execution time: 1_139_000 picoseconds. + Weight::from_parts(1_490_535, 0) + // Standard Error: 211 + .saturating_add(Weight::from_parts(884_929, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64divs(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 810 nanoseconds. - Weight::from_parts(1_114_325, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 452 - .saturating_add(Weight::from_parts(1_521_849, 0).saturating_mul(r.into())) + // Minimum execution time: 1_180_000 picoseconds. + Weight::from_parts(2_221_481, 0) + // Standard Error: 9_884 + .saturating_add(Weight::from_parts(1_507_511, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64divu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 784 nanoseconds. - Weight::from_parts(1_123_153, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 475 - .saturating_add(Weight::from_parts(1_457_746, 0).saturating_mul(r.into())) + // Minimum execution time: 1_131_000 picoseconds. + Weight::from_parts(1_498_652, 0) + // Standard Error: 531 + .saturating_add(Weight::from_parts(1_451_498, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64rems(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 809 nanoseconds. - Weight::from_parts(1_145_906, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 718 - .saturating_add(Weight::from_parts(1_549_964, 0).saturating_mul(r.into())) + // Minimum execution time: 1_145_000 picoseconds. + Weight::from_parts(1_504_118, 0) + // Standard Error: 439 + .saturating_add(Weight::from_parts(1_521_895, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64remu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 803 nanoseconds. - Weight::from_parts(1_110_328, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 627 - .saturating_add(Weight::from_parts(1_453_013, 0).saturating_mul(r.into())) + // Minimum execution time: 1_124_000 picoseconds. + Weight::from_parts(1_497_209, 0) + // Standard Error: 198 + .saturating_add(Weight::from_parts(1_449_843, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64and(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 786 nanoseconds. - Weight::from_parts(1_108_792, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 286 - .saturating_add(Weight::from_parts(897_035, 0).saturating_mul(r.into())) + // Minimum execution time: 1_169_000 picoseconds. + Weight::from_parts(1_534_491, 0) + // Standard Error: 283 + .saturating_add(Weight::from_parts(894_703, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64or(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 787 nanoseconds. - Weight::from_parts(830_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 15_995 - .saturating_add(Weight::from_parts(963_344, 0).saturating_mul(r.into())) + // Minimum execution time: 1_178_000 picoseconds. + Weight::from_parts(1_485_473, 0) + // Standard Error: 552 + .saturating_add(Weight::from_parts(897_878, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64xor(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 773 nanoseconds. - Weight::from_parts(1_082_459, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 330 - .saturating_add(Weight::from_parts(897_077, 0).saturating_mul(r.into())) + // Minimum execution time: 1_214_000 picoseconds. + Weight::from_parts(1_580_999, 0) + // Standard Error: 358 + .saturating_add(Weight::from_parts(894_207, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64shl(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 810 nanoseconds. - Weight::from_parts(1_325_815, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 3_352 - .saturating_add(Weight::from_parts(899_555, 0).saturating_mul(r.into())) + // Minimum execution time: 1_176_000 picoseconds. + Weight::from_parts(1_490_470, 0) + // Standard Error: 738 + .saturating_add(Weight::from_parts(904_900, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64shrs(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 808 nanoseconds. - Weight::from_parts(1_085_903, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 430 - .saturating_add(Weight::from_parts(903_249, 0).saturating_mul(r.into())) + // Minimum execution time: 1_197_000 picoseconds. + Weight::from_parts(1_519_703, 0) + // Standard Error: 336 + .saturating_add(Weight::from_parts(901_277, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64shru(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 792 nanoseconds. - Weight::from_parts(1_091_261, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 312 - .saturating_add(Weight::from_parts(902_245, 0).saturating_mul(r.into())) + // Minimum execution time: 1_166_000 picoseconds. + Weight::from_parts(1_507_499, 0) + // Standard Error: 298 + .saturating_add(Weight::from_parts(901_153, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotl(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 807 nanoseconds. - Weight::from_parts(1_121_052, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 506 - .saturating_add(Weight::from_parts(902_772, 0).saturating_mul(r.into())) + // Minimum execution time: 1_158_000 picoseconds. + Weight::from_parts(1_491_176, 0) + // Standard Error: 341 + .saturating_add(Weight::from_parts(901_880, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotr(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 823 nanoseconds. - Weight::from_parts(1_317_597, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 6_219 - .saturating_add(Weight::from_parts(896_692, 0).saturating_mul(r.into())) + // Minimum execution time: 1_207_000 picoseconds. + Weight::from_parts(1_477_261, 0) + // Standard Error: 287 + .saturating_add(Weight::from_parts(902_622, 0).saturating_mul(r.into())) } } diff --git a/frame/conviction-voting/src/weights.rs b/frame/conviction-voting/src/weights.rs index 91c4c013051db..765a4276aea59 100644 --- a/frame/conviction-voting/src/weights.rs +++ b/frame/conviction-voting/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_conviction_voting //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,6 +31,9 @@ // --steps=50 // --repeat=20 // --pallet=pallet_conviction_voting +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -72,10 +75,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn vote_new() -> Weight { // Proof Size summary in bytes: - // Measured: `13168` - // Estimated: `257859` - // Minimum execution time: 85_569 nanoseconds. - Weight::from_parts(86_492_000, 257859) + // Measured: `13074` + // Estimated: `262809` + // Minimum execution time: 94_493_000 picoseconds. + Weight::from_parts(96_510_000, 262809) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -91,10 +94,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn vote_existing() -> Weight { // Proof Size summary in bytes: - // Measured: `20342` - // Estimated: `257859` - // Minimum execution time: 212_727 nanoseconds. - Weight::from_parts(213_741_000, 257859) + // Measured: `20216` + // Estimated: `262809` + // Minimum execution time: 252_717_000 picoseconds. + Weight::from_parts(255_200_000, 262809) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -106,10 +109,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn remove_vote() -> Weight { // Proof Size summary in bytes: - // Measured: `20062` - // Estimated: `251551` - // Minimum execution time: 200_513 nanoseconds. - Weight::from_parts(201_589_000, 251551) + // Measured: `19968` + // Estimated: `254521` + // Minimum execution time: 244_844_000 picoseconds. + Weight::from_parts(247_433_000, 254521) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -119,10 +122,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) fn remove_other_vote() -> Weight { // Proof Size summary in bytes: - // Measured: `12738` - // Estimated: `32557` - // Minimum execution time: 43_083 nanoseconds. - Weight::from_parts(43_763_000, 32557) + // Measured: `12675` + // Estimated: `34537` + // Minimum execution time: 46_271_000 picoseconds. + Weight::from_parts(47_639_000, 34537) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -139,17 +142,17 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1]`. fn delegate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `272 + r * (1689 ±0)` - // Estimated: `176657 + r * (110917 ±0)` - // Minimum execution time: 33_246 nanoseconds. - Weight::from_parts(34_560_391, 176657) - // Standard Error: 63_925 - .saturating_add(Weight::from_parts(34_500_408, 0).saturating_mul(r.into())) + // Measured: `240 + r * (1627 ±0)` + // Estimated: `180617 + r * (111908 ±0)` + // Minimum execution time: 37_578_000 picoseconds. + Weight::from_parts(39_035_446, 180617) + // Standard Error: 160_560 + .saturating_add(Weight::from_parts(39_642_553, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 110917).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 111908).saturating_mul(r.into())) } /// Storage: ConvictionVoting VotingFor (r:2 w:2) /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) @@ -160,17 +163,17 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1]`. fn undelegate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `470 + r * (1407 ±0)` - // Estimated: `170349 + r * (110917 ±0)` - // Minimum execution time: 20_508 nanoseconds. - Weight::from_parts(21_240_024, 170349) - // Standard Error: 37_314 - .saturating_add(Weight::from_parts(30_890_875, 0).saturating_mul(r.into())) + // Measured: `406 + r * (1376 ±0)` + // Estimated: `172329 + r * (111908 ±0)` + // Minimum execution time: 22_997_000 picoseconds. + Weight::from_parts(24_180_222, 172329) + // Standard Error: 87_723 + .saturating_add(Weight::from_parts(36_189_677, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 110917).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 111908).saturating_mul(r.into())) } /// Storage: ConvictionVoting VotingFor (r:1 w:1) /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) @@ -180,10 +183,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) fn unlock() -> Weight { // Proof Size summary in bytes: - // Measured: `11797` - // Estimated: `36024` - // Minimum execution time: 50_305 nanoseconds. - Weight::from_parts(51_226_000, 36024) + // Measured: `11734` + // Estimated: `38994` + // Minimum execution time: 55_906_000 picoseconds. + Weight::from_parts(56_819_000, 38994) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -203,10 +206,10 @@ impl WeightInfo for () { /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn vote_new() -> Weight { // Proof Size summary in bytes: - // Measured: `13168` - // Estimated: `257859` - // Minimum execution time: 85_569 nanoseconds. - Weight::from_parts(86_492_000, 257859) + // Measured: `13074` + // Estimated: `262809` + // Minimum execution time: 94_493_000 picoseconds. + Weight::from_parts(96_510_000, 262809) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -222,10 +225,10 @@ impl WeightInfo for () { /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn vote_existing() -> Weight { // Proof Size summary in bytes: - // Measured: `20342` - // Estimated: `257859` - // Minimum execution time: 212_727 nanoseconds. - Weight::from_parts(213_741_000, 257859) + // Measured: `20216` + // Estimated: `262809` + // Minimum execution time: 252_717_000 picoseconds. + Weight::from_parts(255_200_000, 262809) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -237,10 +240,10 @@ impl WeightInfo for () { /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn remove_vote() -> Weight { // Proof Size summary in bytes: - // Measured: `20062` - // Estimated: `251551` - // Minimum execution time: 200_513 nanoseconds. - Weight::from_parts(201_589_000, 251551) + // Measured: `19968` + // Estimated: `254521` + // Minimum execution time: 244_844_000 picoseconds. + Weight::from_parts(247_433_000, 254521) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -250,10 +253,10 @@ impl WeightInfo for () { /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) fn remove_other_vote() -> Weight { // Proof Size summary in bytes: - // Measured: `12738` - // Estimated: `32557` - // Minimum execution time: 43_083 nanoseconds. - Weight::from_parts(43_763_000, 32557) + // Measured: `12675` + // Estimated: `34537` + // Minimum execution time: 46_271_000 picoseconds. + Weight::from_parts(47_639_000, 34537) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -270,17 +273,17 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1]`. fn delegate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `272 + r * (1689 ±0)` - // Estimated: `176657 + r * (110917 ±0)` - // Minimum execution time: 33_246 nanoseconds. - Weight::from_parts(34_560_391, 176657) - // Standard Error: 63_925 - .saturating_add(Weight::from_parts(34_500_408, 0).saturating_mul(r.into())) + // Measured: `240 + r * (1627 ±0)` + // Estimated: `180617 + r * (111908 ±0)` + // Minimum execution time: 37_578_000 picoseconds. + Weight::from_parts(39_035_446, 180617) + // Standard Error: 160_560 + .saturating_add(Weight::from_parts(39_642_553, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 110917).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 111908).saturating_mul(r.into())) } /// Storage: ConvictionVoting VotingFor (r:2 w:2) /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) @@ -291,17 +294,17 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1]`. fn undelegate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `470 + r * (1407 ±0)` - // Estimated: `170349 + r * (110917 ±0)` - // Minimum execution time: 20_508 nanoseconds. - Weight::from_parts(21_240_024, 170349) - // Standard Error: 37_314 - .saturating_add(Weight::from_parts(30_890_875, 0).saturating_mul(r.into())) + // Measured: `406 + r * (1376 ±0)` + // Estimated: `172329 + r * (111908 ±0)` + // Minimum execution time: 22_997_000 picoseconds. + Weight::from_parts(24_180_222, 172329) + // Standard Error: 87_723 + .saturating_add(Weight::from_parts(36_189_677, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 110917).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 111908).saturating_mul(r.into())) } /// Storage: ConvictionVoting VotingFor (r:1 w:1) /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) @@ -311,10 +314,10 @@ impl WeightInfo for () { /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) fn unlock() -> Weight { // Proof Size summary in bytes: - // Measured: `11797` - // Estimated: `36024` - // Minimum execution time: 50_305 nanoseconds. - Weight::from_parts(51_226_000, 36024) + // Measured: `11734` + // Estimated: `38994` + // Minimum execution time: 55_906_000 picoseconds. + Weight::from_parts(56_819_000, 38994) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } diff --git a/frame/core-fellowship/src/weights.rs b/frame/core-fellowship/src/weights.rs index 9f290635ec1cf..d436826665069 100644 --- a/frame/core-fellowship/src/weights.rs +++ b/frame/core-fellowship/src/weights.rs @@ -18,26 +18,28 @@ //! Autogenerated weights for pallet_core_fellowship //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/production/substrate +// ./target/production/substrate // benchmark // pallet +// --chain=dev // --steps=50 // --repeat=20 +// --pallet=pallet_core_fellowship +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --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_core_fellowship -// --chain=dev -// --header=./HEADER-APACHE2 // --output=./frame/core-fellowship/src/weights.rs +// --header=./HEADER-APACHE2 // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -70,8 +72,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 10_489_000 picoseconds. - Weight::from_parts(10_873_000, 0) + // Minimum execution time: 10_384_000 picoseconds. + Weight::from_parts(10_787_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: CoreFellowship Member (r:1 w:1) @@ -88,10 +90,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: CoreFellowship MemberEvidence (max_values: None, max_size: Some(16429), added: 18904, mode: MaxEncodedLen) fn bump_offboard() -> Weight { // Proof Size summary in bytes: - // Measured: `16886` + // Measured: `16854` // Estimated: `35762` - // Minimum execution time: 61_794_000 picoseconds. - Weight::from_parts(62_455_000, 35762) + // Minimum execution time: 61_847_000 picoseconds. + Weight::from_parts(62_453_000, 35762) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -109,10 +111,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: CoreFellowship MemberEvidence (max_values: None, max_size: Some(16429), added: 18904, mode: MaxEncodedLen) fn bump_demote() -> Weight { // Proof Size summary in bytes: - // Measured: `16996` + // Measured: `16964` // Estimated: `35762` - // Minimum execution time: 63_921_000 picoseconds. - Weight::from_parts(64_871_000, 35762) + // Minimum execution time: 64_449_000 picoseconds. + Weight::from_parts(65_298_000, 35762) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -124,8 +126,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `355` // Estimated: `7021` - // Minimum execution time: 19_023_000 picoseconds. - Weight::from_parts(19_270_000, 7021) + // Minimum execution time: 19_308_000 picoseconds. + Weight::from_parts(19_520_000, 7021) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -143,8 +145,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `113` // Estimated: `10500` - // Minimum execution time: 29_089_000 picoseconds. - Weight::from_parts(29_718_000, 10500) + // Minimum execution time: 29_228_000 picoseconds. + Weight::from_parts(29_683_000, 10500) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -164,10 +166,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: RankedCollective IdToIndex (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) fn promote() -> Weight { // Proof Size summary in bytes: - // Measured: `16864` + // Measured: `16832` // Estimated: `32243` - // Minimum execution time: 59_529_000 picoseconds. - Weight::from_parts(60_057_000, 32243) + // Minimum execution time: 59_745_000 picoseconds. + Weight::from_parts(60_290_000, 32243) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -175,14 +177,16 @@ impl WeightInfo for SubstrateWeight { /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) /// Storage: CoreFellowship Member (r:1 w:1) /// Proof: CoreFellowship Member (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: CoreFellowship MemberEvidence (r:0 w:1) + /// Proof: CoreFellowship MemberEvidence (max_values: None, max_size: Some(16429), added: 18904, mode: MaxEncodedLen) fn offboard() -> Weight { // Proof Size summary in bytes: - // Measured: `292` + // Measured: `326` // Estimated: `7021` - // Minimum execution time: 17_221_000 picoseconds. - Weight::from_parts(17_585_000, 7021) + // Minimum execution time: 18_964_000 picoseconds. + Weight::from_parts(19_603_000, 7021) .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: CoreFellowship Member (r:1 w:1) /// Proof: CoreFellowship Member (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) @@ -192,8 +196,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `280` // Estimated: `7021` - // Minimum execution time: 18_602_000 picoseconds. - Weight::from_parts(18_813_000, 7021) + // Minimum execution time: 18_752_000 picoseconds. + Weight::from_parts(19_035_000, 7021) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -205,10 +209,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: CoreFellowship MemberEvidence (max_values: None, max_size: Some(16429), added: 18904, mode: MaxEncodedLen) fn approve() -> Weight { // Proof Size summary in bytes: - // Measured: `16842` + // Measured: `16810` // Estimated: `26915` - // Minimum execution time: 43_525_000 picoseconds. - Weight::from_parts(43_994_000, 26915) + // Minimum execution time: 44_972_000 picoseconds. + Weight::from_parts(45_391_000, 26915) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -220,8 +224,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `79` // Estimated: `23408` - // Minimum execution time: 27_960_000 picoseconds. - Weight::from_parts(28_331_000, 23408) + // Minimum execution time: 27_820_000 picoseconds. + Weight::from_parts(28_992_000, 23408) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -235,8 +239,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 10_489_000 picoseconds. - Weight::from_parts(10_873_000, 0) + // Minimum execution time: 10_384_000 picoseconds. + Weight::from_parts(10_787_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: CoreFellowship Member (r:1 w:1) @@ -253,10 +257,10 @@ impl WeightInfo for () { /// Proof: CoreFellowship MemberEvidence (max_values: None, max_size: Some(16429), added: 18904, mode: MaxEncodedLen) fn bump_offboard() -> Weight { // Proof Size summary in bytes: - // Measured: `16886` + // Measured: `16854` // Estimated: `35762` - // Minimum execution time: 61_794_000 picoseconds. - Weight::from_parts(62_455_000, 35762) + // Minimum execution time: 61_847_000 picoseconds. + Weight::from_parts(62_453_000, 35762) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -274,10 +278,10 @@ impl WeightInfo for () { /// Proof: CoreFellowship MemberEvidence (max_values: None, max_size: Some(16429), added: 18904, mode: MaxEncodedLen) fn bump_demote() -> Weight { // Proof Size summary in bytes: - // Measured: `16996` + // Measured: `16964` // Estimated: `35762` - // Minimum execution time: 63_921_000 picoseconds. - Weight::from_parts(64_871_000, 35762) + // Minimum execution time: 64_449_000 picoseconds. + Weight::from_parts(65_298_000, 35762) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -289,8 +293,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `355` // Estimated: `7021` - // Minimum execution time: 19_023_000 picoseconds. - Weight::from_parts(19_270_000, 7021) + // Minimum execution time: 19_308_000 picoseconds. + Weight::from_parts(19_520_000, 7021) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -308,8 +312,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `113` // Estimated: `10500` - // Minimum execution time: 29_089_000 picoseconds. - Weight::from_parts(29_718_000, 10500) + // Minimum execution time: 29_228_000 picoseconds. + Weight::from_parts(29_683_000, 10500) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -329,10 +333,10 @@ impl WeightInfo for () { /// Proof: RankedCollective IdToIndex (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) fn promote() -> Weight { // Proof Size summary in bytes: - // Measured: `16864` + // Measured: `16832` // Estimated: `32243` - // Minimum execution time: 59_529_000 picoseconds. - Weight::from_parts(60_057_000, 32243) + // Minimum execution time: 59_745_000 picoseconds. + Weight::from_parts(60_290_000, 32243) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -340,14 +344,16 @@ impl WeightInfo for () { /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) /// Storage: CoreFellowship Member (r:1 w:1) /// Proof: CoreFellowship Member (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: CoreFellowship MemberEvidence (r:0 w:1) + /// Proof: CoreFellowship MemberEvidence (max_values: None, max_size: Some(16429), added: 18904, mode: MaxEncodedLen) fn offboard() -> Weight { // Proof Size summary in bytes: - // Measured: `292` + // Measured: `326` // Estimated: `7021` - // Minimum execution time: 17_221_000 picoseconds. - Weight::from_parts(17_585_000, 7021) + // Minimum execution time: 18_964_000 picoseconds. + Weight::from_parts(19_603_000, 7021) .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: CoreFellowship Member (r:1 w:1) /// Proof: CoreFellowship Member (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) @@ -357,8 +363,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `280` // Estimated: `7021` - // Minimum execution time: 18_602_000 picoseconds. - Weight::from_parts(18_813_000, 7021) + // Minimum execution time: 18_752_000 picoseconds. + Weight::from_parts(19_035_000, 7021) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -370,10 +376,10 @@ impl WeightInfo for () { /// Proof: CoreFellowship MemberEvidence (max_values: None, max_size: Some(16429), added: 18904, mode: MaxEncodedLen) fn approve() -> Weight { // Proof Size summary in bytes: - // Measured: `16842` + // Measured: `16810` // Estimated: `26915` - // Minimum execution time: 43_525_000 picoseconds. - Weight::from_parts(43_994_000, 26915) + // Minimum execution time: 44_972_000 picoseconds. + Weight::from_parts(45_391_000, 26915) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -385,8 +391,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `79` // Estimated: `23408` - // Minimum execution time: 27_960_000 picoseconds. - Weight::from_parts(28_331_000, 23408) + // Minimum execution time: 27_820_000 picoseconds. + Weight::from_parts(28_992_000, 23408) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/frame/democracy/src/weights.rs b/frame/democracy/src/weights.rs index 9241b27bbe1fb..e0c970a34b372 100644 --- a/frame/democracy/src/weights.rs +++ b/frame/democracy/src/weights.rs @@ -18,26 +18,28 @@ //! Autogenerated weights for pallet_democracy //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-01-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-b3zmxxc-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! 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 // --steps=50 // --repeat=20 +// --pallet=pallet_democracy +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --json-file=/builds/parity/mirrors/substrate/.git/.artifacts/bench.json -// --pallet=pallet_democracy -// --chain=dev -// --header=./HEADER-APACHE2 // --output=./frame/democracy/src/weights.rs +// --header=./HEADER-APACHE2 // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -92,10 +94,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) fn propose() -> Weight { // Proof Size summary in bytes: - // Measured: `4864` - // Estimated: `23409` - // Minimum execution time: 42_939 nanoseconds. - Weight::from_parts(43_543_000, 23409) + // Measured: `4801` + // Estimated: `26379` + // Minimum execution time: 39_171_000 picoseconds. + Weight::from_parts(39_779_000, 26379) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -103,10 +105,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) fn second() -> Weight { // Proof Size summary in bytes: - // Measured: `3620` - // Estimated: `5705` - // Minimum execution time: 36_475 nanoseconds. - Weight::from_parts(37_863_000, 5705) + // Measured: `3556` + // Estimated: `6695` + // Minimum execution time: 35_694_000 picoseconds. + Weight::from_parts(36_181_000, 6695) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -118,10 +120,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) fn vote_new() -> Weight { // Proof Size summary in bytes: - // Measured: `3565` - // Estimated: `12720` - // Minimum execution time: 56_372 nanoseconds. - Weight::from_parts(57_483_000, 12720) + // Measured: `3470` + // Estimated: `15690` + // Minimum execution time: 50_274_000 picoseconds. + Weight::from_parts(51_216_000, 15690) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -133,10 +135,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) fn vote_existing() -> Weight { // Proof Size summary in bytes: - // Measured: `3587` - // Estimated: `12720` - // Minimum execution time: 56_789 nanoseconds. - Weight::from_parts(57_737_000, 12720) + // Measured: `3492` + // Estimated: `15690` + // Minimum execution time: 50_559_000 picoseconds. + Weight::from_parts(51_030_000, 15690) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -148,10 +150,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) fn emergency_cancel() -> Weight { // Proof Size summary in bytes: - // Measured: `398` - // Estimated: `7712` - // Minimum execution time: 24_379 nanoseconds. - Weight::from_parts(25_302_000, 7712) + // Measured: `366` + // Estimated: `10682` + // Minimum execution time: 27_539_000 picoseconds. + Weight::from_parts(28_040_000, 10682) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -171,10 +173,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) fn blacklist() -> Weight { // Proof Size summary in bytes: - // Measured: `6036` - // Estimated: `36392` - // Minimum execution time: 100_345 nanoseconds. - Weight::from_parts(102_233_000, 36392) + // Measured: `5910` + // Estimated: `42332` + // Minimum execution time: 93_053_000 picoseconds. + Weight::from_parts(94_193_000, 42332) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } @@ -184,10 +186,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) fn external_propose() -> Weight { // Proof Size summary in bytes: - // Measured: `3448` - // Estimated: `6340` - // Minimum execution time: 13_155 nanoseconds. - Weight::from_parts(14_158_000, 6340) + // Measured: `3416` + // Estimated: `8320` + // Minimum execution time: 14_664_000 picoseconds. + Weight::from_parts(15_064_000, 8320) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -197,8 +199,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_961 nanoseconds. - Weight::from_parts(3_139_000, 0) + // Minimum execution time: 4_073_000 picoseconds. + Weight::from_parts(4_242_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Democracy NextExternal (r:0 w:1) @@ -207,8 +209,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_040 nanoseconds. - Weight::from_parts(3_261_000, 0) + // Minimum execution time: 3_779_000 picoseconds. + Weight::from_parts(4_091_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Democracy NextExternal (r:1 w:1) @@ -222,9 +224,9 @@ impl WeightInfo for SubstrateWeight { fn fast_track() -> Weight { // Proof Size summary in bytes: // Measured: `286` - // Estimated: `3654` - // Minimum execution time: 26_666 nanoseconds. - Weight::from_parts(28_014_000, 3654) + // Estimated: `6624` + // Minimum execution time: 29_596_000 picoseconds. + Weight::from_parts(30_083_000, 6624) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -236,10 +238,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) fn veto_external() -> Weight { // Proof Size summary in bytes: - // Measured: `3551` - // Estimated: `8868` - // Minimum execution time: 30_180 nanoseconds. - Weight::from_parts(31_593_000, 8868) + // Measured: `3519` + // Estimated: `11838` + // Minimum execution time: 34_721_000 picoseconds. + Weight::from_parts(34_989_000, 11838) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -253,10 +255,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) fn cancel_proposal() -> Weight { // Proof Size summary in bytes: - // Measured: `5915` - // Estimated: `28033` - // Minimum execution time: 80_780 nanoseconds. - Weight::from_parts(82_070_000, 28033) + // Measured: `5821` + // Estimated: `31993` + // Minimum execution time: 74_835_000 picoseconds. + Weight::from_parts(75_807_000, 31993) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -267,9 +269,9 @@ impl WeightInfo for SubstrateWeight { fn cancel_referendum() -> Weight { // Proof Size summary in bytes: // Measured: `271` - // Estimated: `2528` - // Minimum execution time: 18_117 nanoseconds. - Weight::from_parts(19_027_000, 2528) + // Estimated: `3518` + // Minimum execution time: 20_995_000 picoseconds. + Weight::from_parts(21_425_000, 3518) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -282,12 +284,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 99]`. fn on_initialize_base(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `244 + r * (117 ±0)` - // Estimated: `998 + r * (2676 ±0)` - // Minimum execution time: 7_093 nanoseconds. - Weight::from_parts(8_792_955, 998) - // Standard Error: 6_630 - .saturating_add(Weight::from_parts(3_091_565, 0).saturating_mul(r.into())) + // Measured: `244 + r * (86 ±0)` + // Estimated: `3968 + r * (2676 ±0)` + // Minimum execution time: 7_002_000 picoseconds. + Weight::from_parts(10_543_534, 3968) + // Standard Error: 7_286 + .saturating_add(Weight::from_parts(2_911_122, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) @@ -308,12 +310,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 99]`. fn on_initialize_base_with_launch_period(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `244 + r * (117 ±0)` - // Estimated: `19318 + r * (2676 ±0)` - // Minimum execution time: 10_372 nanoseconds. - Weight::from_parts(10_961_165, 19318) - // Standard Error: 7_284 - .saturating_add(Weight::from_parts(3_112_573, 0).saturating_mul(r.into())) + // Measured: `244 + r * (86 ±0)` + // Estimated: `25258 + r * (2676 ±0)` + // Minimum execution time: 10_824_000 picoseconds. + Weight::from_parts(14_187_527, 25258) + // Standard Error: 7_148 + .saturating_add(Weight::from_parts(2_886_910, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) @@ -328,12 +330,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 99]`. fn delegate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `958 + r * (139 ±0)` - // Estimated: `22584 + r * (2676 ±0)` - // Minimum execution time: 36_618 nanoseconds. - Weight::from_parts(42_803_184, 22584) - // Standard Error: 7_268 - .saturating_add(Weight::from_parts(4_537_902, 0).saturating_mul(r.into())) + // Measured: `830 + r * (108 ±0)` + // Estimated: `25554 + r * (2676 ±0)` + // Minimum execution time: 42_940_000 picoseconds. + Weight::from_parts(45_288_082, 25554) + // Standard Error: 6_380 + .saturating_add(Weight::from_parts(4_219_163, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(4_u64)) @@ -347,12 +349,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 99]`. fn undelegate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `557 + r * (139 ±0)` - // Estimated: `12540 + r * (2676 ±0)` - // Minimum execution time: 19_758 nanoseconds. - Weight::from_parts(21_641_793, 12540) - // Standard Error: 6_889 - .saturating_add(Weight::from_parts(4_478_884, 0).saturating_mul(r.into())) + // Measured: `493 + r * (108 ±0)` + // Estimated: `14520 + r * (2676 ±0)` + // Minimum execution time: 22_203_000 picoseconds. + Weight::from_parts(22_307_372, 14520) + // Standard Error: 7_095 + .saturating_add(Weight::from_parts(4_202_995, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) @@ -365,8 +367,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_844 nanoseconds. - Weight::from_parts(3_017_000, 0) + // Minimum execution time: 4_046_000 picoseconds. + Weight::from_parts(4_191_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Democracy VotingOf (r:1 w:1) @@ -378,12 +380,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 99]`. fn unlock_remove(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `627` - // Estimated: `12647` - // Minimum execution time: 20_380 nanoseconds. - Weight::from_parts(28_295_875, 12647) - // Standard Error: 2_331 - .saturating_add(Weight::from_parts(67_348, 0).saturating_mul(r.into())) + // Measured: `563` + // Estimated: `15617` + // Minimum execution time: 22_585_000 picoseconds. + Weight::from_parts(28_461_437, 15617) + // Standard Error: 1_636 + .saturating_add(Weight::from_parts(19_140, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -396,12 +398,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 99]`. fn unlock_set(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `628 + r * (22 ±0)` - // Estimated: `12647` - // Minimum execution time: 24_475 nanoseconds. - Weight::from_parts(27_102_576, 12647) - // Standard Error: 1_464 - .saturating_add(Weight::from_parts(128_921, 0).saturating_mul(r.into())) + // Measured: `564 + r * (22 ±0)` + // Estimated: `15617` + // Minimum execution time: 26_674_000 picoseconds. + Weight::from_parts(27_815_260, 15617) + // Standard Error: 490 + .saturating_add(Weight::from_parts(68_478, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -412,12 +414,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[1, 100]`. fn remove_vote(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `791 + r * (26 ±0)` - // Estimated: `8946` - // Minimum execution time: 15_039 nanoseconds. - Weight::from_parts(19_252_498, 8946) - // Standard Error: 1_798 - .saturating_add(Weight::from_parts(131_855, 0).saturating_mul(r.into())) + // Measured: `728 + r * (26 ±0)` + // Estimated: `10926` + // Minimum execution time: 17_381_000 picoseconds. + Weight::from_parts(19_728_665, 10926) + // Standard Error: 1_065 + .saturating_add(Weight::from_parts(84_481, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -428,12 +430,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[1, 100]`. fn remove_other_vote(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `791 + r * (26 ±0)` - // Estimated: `8946` - // Minimum execution time: 14_837 nanoseconds. - Weight::from_parts(19_144_929, 8946) - // Standard Error: 1_875 - .saturating_add(Weight::from_parts(136_819, 0).saturating_mul(r.into())) + // Measured: `728 + r * (26 ±0)` + // Estimated: `10926` + // Minimum execution time: 17_496_000 picoseconds. + Weight::from_parts(19_845_941, 10926) + // Standard Error: 1_169 + .saturating_add(Weight::from_parts(85_004, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -446,9 +448,9 @@ impl WeightInfo for SubstrateWeight { fn set_external_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `356` - // Estimated: `3193` - // Minimum execution time: 17_338 nanoseconds. - Weight::from_parts(17_946_000, 3193) + // Estimated: `5173` + // Minimum execution time: 19_076_000 picoseconds. + Weight::from_parts(19_650_000, 5173) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -459,9 +461,9 @@ impl WeightInfo for SubstrateWeight { fn clear_external_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `286` - // Estimated: `3155` - // Minimum execution time: 15_364 nanoseconds. - Weight::from_parts(15_990_000, 3155) + // Estimated: `5135` + // Minimum execution time: 17_588_000 picoseconds. + Weight::from_parts(17_781_000, 5135) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -473,10 +475,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) fn set_proposal_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `4919` - // Estimated: `19763` - // Minimum execution time: 37_147 nanoseconds. - Weight::from_parts(37_778_000, 19763) + // Measured: `4888` + // Estimated: `21743` + // Minimum execution time: 34_828_000 picoseconds. + Weight::from_parts(35_364_000, 21743) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -486,10 +488,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) fn clear_proposal_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `4853` - // Estimated: `19725` - // Minimum execution time: 34_118 nanoseconds. - Weight::from_parts(34_737_000, 19725) + // Measured: `4822` + // Estimated: `21705` + // Minimum execution time: 32_035_000 picoseconds. + Weight::from_parts(32_554_000, 21705) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -500,9 +502,9 @@ impl WeightInfo for SubstrateWeight { fn set_referendum_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `144` - // Estimated: `2566` - // Minimum execution time: 12_787 nanoseconds. - Weight::from_parts(13_463_000, 2566) + // Estimated: `3556` + // Minimum execution time: 15_279_000 picoseconds. + Weight::from_parts(15_556_000, 3556) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -513,9 +515,9 @@ impl WeightInfo for SubstrateWeight { fn clear_referendum_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `302` - // Estimated: `5204` - // Minimum execution time: 17_636 nanoseconds. - Weight::from_parts(18_399_000, 5204) + // Estimated: `7184` + // Minimum execution time: 19_622_000 picoseconds. + Weight::from_parts(19_978_000, 7184) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -533,10 +535,10 @@ impl WeightInfo for () { /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) fn propose() -> Weight { // Proof Size summary in bytes: - // Measured: `4864` - // Estimated: `23409` - // Minimum execution time: 42_939 nanoseconds. - Weight::from_parts(43_543_000, 23409) + // Measured: `4801` + // Estimated: `26379` + // Minimum execution time: 39_171_000 picoseconds. + Weight::from_parts(39_779_000, 26379) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -544,10 +546,10 @@ impl WeightInfo for () { /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) fn second() -> Weight { // Proof Size summary in bytes: - // Measured: `3620` - // Estimated: `5705` - // Minimum execution time: 36_475 nanoseconds. - Weight::from_parts(37_863_000, 5705) + // Measured: `3556` + // Estimated: `6695` + // Minimum execution time: 35_694_000 picoseconds. + Weight::from_parts(36_181_000, 6695) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -559,10 +561,10 @@ impl WeightInfo for () { /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) fn vote_new() -> Weight { // Proof Size summary in bytes: - // Measured: `3565` - // Estimated: `12720` - // Minimum execution time: 56_372 nanoseconds. - Weight::from_parts(57_483_000, 12720) + // Measured: `3470` + // Estimated: `15690` + // Minimum execution time: 50_274_000 picoseconds. + Weight::from_parts(51_216_000, 15690) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -574,10 +576,10 @@ impl WeightInfo for () { /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) fn vote_existing() -> Weight { // Proof Size summary in bytes: - // Measured: `3587` - // Estimated: `12720` - // Minimum execution time: 56_789 nanoseconds. - Weight::from_parts(57_737_000, 12720) + // Measured: `3492` + // Estimated: `15690` + // Minimum execution time: 50_559_000 picoseconds. + Weight::from_parts(51_030_000, 15690) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -589,10 +591,10 @@ impl WeightInfo for () { /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) fn emergency_cancel() -> Weight { // Proof Size summary in bytes: - // Measured: `398` - // Estimated: `7712` - // Minimum execution time: 24_379 nanoseconds. - Weight::from_parts(25_302_000, 7712) + // Measured: `366` + // Estimated: `10682` + // Minimum execution time: 27_539_000 picoseconds. + Weight::from_parts(28_040_000, 10682) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -612,10 +614,10 @@ impl WeightInfo for () { /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) fn blacklist() -> Weight { // Proof Size summary in bytes: - // Measured: `6036` - // Estimated: `36392` - // Minimum execution time: 100_345 nanoseconds. - Weight::from_parts(102_233_000, 36392) + // Measured: `5910` + // Estimated: `42332` + // Minimum execution time: 93_053_000 picoseconds. + Weight::from_parts(94_193_000, 42332) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } @@ -625,10 +627,10 @@ impl WeightInfo for () { /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) fn external_propose() -> Weight { // Proof Size summary in bytes: - // Measured: `3448` - // Estimated: `6340` - // Minimum execution time: 13_155 nanoseconds. - Weight::from_parts(14_158_000, 6340) + // Measured: `3416` + // Estimated: `8320` + // Minimum execution time: 14_664_000 picoseconds. + Weight::from_parts(15_064_000, 8320) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -638,8 +640,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_961 nanoseconds. - Weight::from_parts(3_139_000, 0) + // Minimum execution time: 4_073_000 picoseconds. + Weight::from_parts(4_242_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Democracy NextExternal (r:0 w:1) @@ -648,8 +650,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_040 nanoseconds. - Weight::from_parts(3_261_000, 0) + // Minimum execution time: 3_779_000 picoseconds. + Weight::from_parts(4_091_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Democracy NextExternal (r:1 w:1) @@ -663,9 +665,9 @@ impl WeightInfo for () { fn fast_track() -> Weight { // Proof Size summary in bytes: // Measured: `286` - // Estimated: `3654` - // Minimum execution time: 26_666 nanoseconds. - Weight::from_parts(28_014_000, 3654) + // Estimated: `6624` + // Minimum execution time: 29_596_000 picoseconds. + Weight::from_parts(30_083_000, 6624) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -677,10 +679,10 @@ impl WeightInfo for () { /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) fn veto_external() -> Weight { // Proof Size summary in bytes: - // Measured: `3551` - // Estimated: `8868` - // Minimum execution time: 30_180 nanoseconds. - Weight::from_parts(31_593_000, 8868) + // Measured: `3519` + // Estimated: `11838` + // Minimum execution time: 34_721_000 picoseconds. + Weight::from_parts(34_989_000, 11838) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -694,10 +696,10 @@ impl WeightInfo for () { /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) fn cancel_proposal() -> Weight { // Proof Size summary in bytes: - // Measured: `5915` - // Estimated: `28033` - // Minimum execution time: 80_780 nanoseconds. - Weight::from_parts(82_070_000, 28033) + // Measured: `5821` + // Estimated: `31993` + // Minimum execution time: 74_835_000 picoseconds. + Weight::from_parts(75_807_000, 31993) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -708,9 +710,9 @@ impl WeightInfo for () { fn cancel_referendum() -> Weight { // Proof Size summary in bytes: // Measured: `271` - // Estimated: `2528` - // Minimum execution time: 18_117 nanoseconds. - Weight::from_parts(19_027_000, 2528) + // Estimated: `3518` + // Minimum execution time: 20_995_000 picoseconds. + Weight::from_parts(21_425_000, 3518) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -723,12 +725,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 99]`. fn on_initialize_base(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `244 + r * (117 ±0)` - // Estimated: `998 + r * (2676 ±0)` - // Minimum execution time: 7_093 nanoseconds. - Weight::from_parts(8_792_955, 998) - // Standard Error: 6_630 - .saturating_add(Weight::from_parts(3_091_565, 0).saturating_mul(r.into())) + // Measured: `244 + r * (86 ±0)` + // Estimated: `3968 + r * (2676 ±0)` + // Minimum execution time: 7_002_000 picoseconds. + Weight::from_parts(10_543_534, 3968) + // Standard Error: 7_286 + .saturating_add(Weight::from_parts(2_911_122, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) @@ -749,12 +751,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 99]`. fn on_initialize_base_with_launch_period(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `244 + r * (117 ±0)` - // Estimated: `19318 + r * (2676 ±0)` - // Minimum execution time: 10_372 nanoseconds. - Weight::from_parts(10_961_165, 19318) - // Standard Error: 7_284 - .saturating_add(Weight::from_parts(3_112_573, 0).saturating_mul(r.into())) + // Measured: `244 + r * (86 ±0)` + // Estimated: `25258 + r * (2676 ±0)` + // Minimum execution time: 10_824_000 picoseconds. + Weight::from_parts(14_187_527, 25258) + // Standard Error: 7_148 + .saturating_add(Weight::from_parts(2_886_910, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) @@ -769,12 +771,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 99]`. fn delegate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `958 + r * (139 ±0)` - // Estimated: `22584 + r * (2676 ±0)` - // Minimum execution time: 36_618 nanoseconds. - Weight::from_parts(42_803_184, 22584) - // Standard Error: 7_268 - .saturating_add(Weight::from_parts(4_537_902, 0).saturating_mul(r.into())) + // Measured: `830 + r * (108 ±0)` + // Estimated: `25554 + r * (2676 ±0)` + // Minimum execution time: 42_940_000 picoseconds. + Weight::from_parts(45_288_082, 25554) + // Standard Error: 6_380 + .saturating_add(Weight::from_parts(4_219_163, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(4_u64)) @@ -788,12 +790,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 99]`. fn undelegate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `557 + r * (139 ±0)` - // Estimated: `12540 + r * (2676 ±0)` - // Minimum execution time: 19_758 nanoseconds. - Weight::from_parts(21_641_793, 12540) - // Standard Error: 6_889 - .saturating_add(Weight::from_parts(4_478_884, 0).saturating_mul(r.into())) + // Measured: `493 + r * (108 ±0)` + // Estimated: `14520 + r * (2676 ±0)` + // Minimum execution time: 22_203_000 picoseconds. + Weight::from_parts(22_307_372, 14520) + // Standard Error: 7_095 + .saturating_add(Weight::from_parts(4_202_995, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(2_u64)) @@ -806,8 +808,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_844 nanoseconds. - Weight::from_parts(3_017_000, 0) + // Minimum execution time: 4_046_000 picoseconds. + Weight::from_parts(4_191_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Democracy VotingOf (r:1 w:1) @@ -819,12 +821,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 99]`. fn unlock_remove(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `627` - // Estimated: `12647` - // Minimum execution time: 20_380 nanoseconds. - Weight::from_parts(28_295_875, 12647) - // Standard Error: 2_331 - .saturating_add(Weight::from_parts(67_348, 0).saturating_mul(r.into())) + // Measured: `563` + // Estimated: `15617` + // Minimum execution time: 22_585_000 picoseconds. + Weight::from_parts(28_461_437, 15617) + // Standard Error: 1_636 + .saturating_add(Weight::from_parts(19_140, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -837,12 +839,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 99]`. fn unlock_set(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `628 + r * (22 ±0)` - // Estimated: `12647` - // Minimum execution time: 24_475 nanoseconds. - Weight::from_parts(27_102_576, 12647) - // Standard Error: 1_464 - .saturating_add(Weight::from_parts(128_921, 0).saturating_mul(r.into())) + // Measured: `564 + r * (22 ±0)` + // Estimated: `15617` + // Minimum execution time: 26_674_000 picoseconds. + Weight::from_parts(27_815_260, 15617) + // Standard Error: 490 + .saturating_add(Weight::from_parts(68_478, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -853,12 +855,12 @@ impl WeightInfo for () { /// The range of component `r` is `[1, 100]`. fn remove_vote(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `791 + r * (26 ±0)` - // Estimated: `8946` - // Minimum execution time: 15_039 nanoseconds. - Weight::from_parts(19_252_498, 8946) - // Standard Error: 1_798 - .saturating_add(Weight::from_parts(131_855, 0).saturating_mul(r.into())) + // Measured: `728 + r * (26 ±0)` + // Estimated: `10926` + // Minimum execution time: 17_381_000 picoseconds. + Weight::from_parts(19_728_665, 10926) + // Standard Error: 1_065 + .saturating_add(Weight::from_parts(84_481, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -869,12 +871,12 @@ impl WeightInfo for () { /// The range of component `r` is `[1, 100]`. fn remove_other_vote(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `791 + r * (26 ±0)` - // Estimated: `8946` - // Minimum execution time: 14_837 nanoseconds. - Weight::from_parts(19_144_929, 8946) - // Standard Error: 1_875 - .saturating_add(Weight::from_parts(136_819, 0).saturating_mul(r.into())) + // Measured: `728 + r * (26 ±0)` + // Estimated: `10926` + // Minimum execution time: 17_496_000 picoseconds. + Weight::from_parts(19_845_941, 10926) + // Standard Error: 1_169 + .saturating_add(Weight::from_parts(85_004, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -887,9 +889,9 @@ impl WeightInfo for () { fn set_external_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `356` - // Estimated: `3193` - // Minimum execution time: 17_338 nanoseconds. - Weight::from_parts(17_946_000, 3193) + // Estimated: `5173` + // Minimum execution time: 19_076_000 picoseconds. + Weight::from_parts(19_650_000, 5173) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -900,9 +902,9 @@ impl WeightInfo for () { fn clear_external_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `286` - // Estimated: `3155` - // Minimum execution time: 15_364 nanoseconds. - Weight::from_parts(15_990_000, 3155) + // Estimated: `5135` + // Minimum execution time: 17_588_000 picoseconds. + Weight::from_parts(17_781_000, 5135) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -914,10 +916,10 @@ impl WeightInfo for () { /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) fn set_proposal_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `4919` - // Estimated: `19763` - // Minimum execution time: 37_147 nanoseconds. - Weight::from_parts(37_778_000, 19763) + // Measured: `4888` + // Estimated: `21743` + // Minimum execution time: 34_828_000 picoseconds. + Weight::from_parts(35_364_000, 21743) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -927,10 +929,10 @@ impl WeightInfo for () { /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) fn clear_proposal_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `4853` - // Estimated: `19725` - // Minimum execution time: 34_118 nanoseconds. - Weight::from_parts(34_737_000, 19725) + // Measured: `4822` + // Estimated: `21705` + // Minimum execution time: 32_035_000 picoseconds. + Weight::from_parts(32_554_000, 21705) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -941,9 +943,9 @@ impl WeightInfo for () { fn set_referendum_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `144` - // Estimated: `2566` - // Minimum execution time: 12_787 nanoseconds. - Weight::from_parts(13_463_000, 2566) + // Estimated: `3556` + // Minimum execution time: 15_279_000 picoseconds. + Weight::from_parts(15_556_000, 3556) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -954,9 +956,9 @@ impl WeightInfo for () { fn clear_referendum_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `302` - // Estimated: `5204` - // Minimum execution time: 17_636 nanoseconds. - Weight::from_parts(18_399_000, 5204) + // Estimated: `7184` + // Minimum execution time: 19_622_000 picoseconds. + Weight::from_parts(19_978_000, 7184) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/frame/election-provider-multi-phase/src/weights.rs b/frame/election-provider-multi-phase/src/weights.rs index 90be98ece489a..f9dfdfc19aa3d 100644 --- a/frame/election-provider-multi-phase/src/weights.rs +++ b/frame/election-provider-multi-phase/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_election_provider_multi_phase //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,6 +31,9 @@ // --steps=50 // --repeat=20 // --pallet=pallet_election_provider_multi_phase +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -82,9 +85,9 @@ impl WeightInfo for SubstrateWeight { fn on_initialize_nothing() -> Weight { // Proof Size summary in bytes: // Measured: `994` - // Estimated: `6983` - // Minimum execution time: 17_801 nanoseconds. - Weight::from_parts(18_364_000, 6983) + // Estimated: `14903` + // Minimum execution time: 21_538_000 picoseconds. + Weight::from_parts(22_045_000, 14903) .saturating_add(T::DbWeight::get().reads(8_u64)) } /// Storage: ElectionProviderMultiPhase Round (r:1 w:0) @@ -94,9 +97,9 @@ impl WeightInfo for SubstrateWeight { fn on_initialize_open_signed() -> Weight { // Proof Size summary in bytes: // Measured: `114` - // Estimated: `1218` - // Minimum execution time: 12_814 nanoseconds. - Weight::from_parts(13_154_000, 1218) + // Estimated: `3198` + // Minimum execution time: 12_696_000 picoseconds. + Weight::from_parts(12_950_000, 3198) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -107,9 +110,9 @@ impl WeightInfo for SubstrateWeight { fn on_initialize_open_unsigned() -> Weight { // Proof Size summary in bytes: // Measured: `114` - // Estimated: `1218` - // Minimum execution time: 14_565 nanoseconds. - Weight::from_parts(15_097_000, 1218) + // Estimated: `3198` + // Minimum execution time: 14_029_000 picoseconds. + Weight::from_parts(14_288_000, 3198) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -119,10 +122,10 @@ impl WeightInfo for SubstrateWeight { /// Proof Skipped: ElectionProviderMultiPhase QueuedSolution (max_values: Some(1), max_size: None, mode: Measured) fn finalize_signed_phase_accept_solution() -> Weight { // Proof Size summary in bytes: - // Measured: `206` - // Estimated: `2809` - // Minimum execution time: 23_341 nanoseconds. - Weight::from_parts(23_770_000, 2809) + // Measured: `174` + // Estimated: `3767` + // Minimum execution time: 26_468_000 picoseconds. + Weight::from_parts(26_790_000, 3767) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -130,10 +133,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn finalize_signed_phase_reject_solution() -> Weight { // Proof Size summary in bytes: - // Measured: `206` - // Estimated: `2603` - // Minimum execution time: 16_662 nanoseconds. - Weight::from_parts(16_898_000, 2603) + // Measured: `174` + // Estimated: `3593` + // Minimum execution time: 18_401_000 picoseconds. + Weight::from_parts(18_686_000, 3593) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -149,10 +152,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 215_168 nanoseconds. - Weight::from_parts(219_887_000, 0) - // Standard Error: 1_444 - .saturating_add(Weight::from_parts(146_388, 0).saturating_mul(v.into())) + // Minimum execution time: 266_901_000 picoseconds. + Weight::from_parts(270_251_000, 0) + // Standard Error: 1_758 + .saturating_add(Weight::from_parts(167_310, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: ElectionProviderMultiPhase SignedSubmissionIndices (r:1 w:1) @@ -177,14 +180,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `d` is `[200, 400]`. fn elect_queued(a: u32, d: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `368 + a * (768 ±0) + d * (48 ±0)` - // Estimated: `9540 + a * (6912 ±0) + d * (441 ±0)` - // Minimum execution time: 268_021 nanoseconds. - Weight::from_parts(72_491_937, 9540) - // Standard Error: 2_910 - .saturating_add(Weight::from_parts(303_955, 0).saturating_mul(a.into())) - // Standard Error: 4_363 - .saturating_add(Weight::from_parts(167_369, 0).saturating_mul(d.into())) + // Measured: `337 + a * (768 ±0) + d * (48 ±0)` + // Estimated: `16191 + a * (6912 ±0) + d * (441 ±0)` + // Minimum execution time: 286_523_000 picoseconds. + Weight::from_parts(19_101_753, 16191) + // Standard Error: 4_194 + .saturating_add(Weight::from_parts(398_102, 0).saturating_mul(a.into())) + // Standard Error: 6_287 + .saturating_add(Weight::from_parts(188_928, 0).saturating_mul(d.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(8_u64)) .saturating_add(Weight::from_parts(0, 6912).saturating_mul(a.into())) @@ -204,10 +207,10 @@ impl WeightInfo for SubstrateWeight { /// Proof Skipped: ElectionProviderMultiPhase SignedSubmissionsMap (max_values: None, max_size: None, mode: Measured) fn submit() -> Weight { // Proof Size summary in bytes: - // Measured: `924` - // Estimated: `7111` - // Minimum execution time: 44_177 nanoseconds. - Weight::from_parts(44_663_000, 7111) + // Measured: `893` + // Estimated: `11906` + // Minimum execution time: 47_876_000 picoseconds. + Weight::from_parts(48_464_000, 11906) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -221,51 +224,51 @@ impl WeightInfo for SubstrateWeight { /// Proof Skipped: ElectionProviderMultiPhase QueuedSolution (max_values: Some(1), max_size: None, mode: Measured) /// Storage: ElectionProviderMultiPhase SnapshotMetadata (r:1 w:0) /// Proof Skipped: ElectionProviderMultiPhase SnapshotMetadata (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase MinimumUntrustedScore (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase MinimumUntrustedScore (max_values: Some(1), max_size: None, mode: Measured) /// Storage: ElectionProviderMultiPhase Snapshot (r:1 w:0) /// Proof Skipped: ElectionProviderMultiPhase Snapshot (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase MinimumUntrustedScore (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase MinimumUntrustedScore (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `v` is `[1000, 2000]`. /// The range of component `t` is `[500, 1000]`. /// The range of component `a` is `[500, 800]`. /// The range of component `d` is `[200, 400]`. fn submit_unsigned(v: u32, t: u32, a: u32, _d: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `251 + v * (553 ±0) + t * (32 ±0)` - // Estimated: `5222 + v * (3871 ±0) + t * (224 ±0)` - // Minimum execution time: 4_425_457 nanoseconds. - Weight::from_parts(4_445_889_000, 5222) - // Standard Error: 13_250 - .saturating_add(Weight::from_parts(48_844, 0).saturating_mul(v.into())) - // Standard Error: 39_266 - .saturating_add(Weight::from_parts(4_144_034, 0).saturating_mul(a.into())) + // Measured: `219 + v * (553 ±0) + t * (32 ±0)` + // Estimated: `11928 + v * (3871 ±0) + t * (224 ±0)` + // Minimum execution time: 4_702_825_000 picoseconds. + Weight::from_parts(4_752_015_000, 11928) + // Standard Error: 14_906 + .saturating_add(Weight::from_parts(131_585, 0).saturating_mul(v.into())) + // Standard Error: 44_174 + .saturating_add(Weight::from_parts(4_167_676, 0).saturating_mul(a.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 3871).saturating_mul(v.into())) .saturating_add(Weight::from_parts(0, 224).saturating_mul(t.into())) } - /// Storage: ElectionProviderMultiPhase Round (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase Round (max_values: Some(1), max_size: None, mode: Measured) /// Storage: ElectionProviderMultiPhase DesiredTargets (r:1 w:0) /// Proof Skipped: ElectionProviderMultiPhase DesiredTargets (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase MinimumUntrustedScore (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase MinimumUntrustedScore (max_values: Some(1), max_size: None, mode: Measured) /// Storage: ElectionProviderMultiPhase Snapshot (r:1 w:0) /// Proof Skipped: ElectionProviderMultiPhase Snapshot (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase Round (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase Round (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase MinimumUntrustedScore (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase MinimumUntrustedScore (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `v` is `[1000, 2000]`. /// The range of component `t` is `[500, 1000]`. /// The range of component `a` is `[500, 800]`. /// The range of component `d` is `[200, 400]`. fn feasibility_check(v: u32, t: u32, a: u32, _d: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `226 + v * (553 ±0) + t * (32 ±0)` - // Estimated: `2884 + v * (2212 ±0) + t * (128 ±0)` - // Minimum execution time: 3_812_071 nanoseconds. - Weight::from_parts(3_826_375_000, 2884) - // Standard Error: 11_601 - .saturating_add(Weight::from_parts(145_309, 0).saturating_mul(v.into())) - // Standard Error: 34_378 - .saturating_add(Weight::from_parts(3_223_977, 0).saturating_mul(a.into())) + // Measured: `194 + v * (553 ±0) + t * (32 ±0)` + // Estimated: `6716 + v * (2212 ±0) + t * (128 ±0)` + // Minimum execution time: 4_069_075_000 picoseconds. + Weight::from_parts(4_105_635_000, 6716) + // Standard Error: 12_539 + .saturating_add(Weight::from_parts(163_040, 0).saturating_mul(v.into())) + // Standard Error: 37_160 + .saturating_add(Weight::from_parts(3_343_858, 0).saturating_mul(a.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(Weight::from_parts(0, 2212).saturating_mul(v.into())) .saturating_add(Weight::from_parts(0, 128).saturating_mul(t.into())) @@ -293,9 +296,9 @@ impl WeightInfo for () { fn on_initialize_nothing() -> Weight { // Proof Size summary in bytes: // Measured: `994` - // Estimated: `6983` - // Minimum execution time: 17_801 nanoseconds. - Weight::from_parts(18_364_000, 6983) + // Estimated: `14903` + // Minimum execution time: 21_538_000 picoseconds. + Weight::from_parts(22_045_000, 14903) .saturating_add(RocksDbWeight::get().reads(8_u64)) } /// Storage: ElectionProviderMultiPhase Round (r:1 w:0) @@ -305,9 +308,9 @@ impl WeightInfo for () { fn on_initialize_open_signed() -> Weight { // Proof Size summary in bytes: // Measured: `114` - // Estimated: `1218` - // Minimum execution time: 12_814 nanoseconds. - Weight::from_parts(13_154_000, 1218) + // Estimated: `3198` + // Minimum execution time: 12_696_000 picoseconds. + Weight::from_parts(12_950_000, 3198) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -318,9 +321,9 @@ impl WeightInfo for () { fn on_initialize_open_unsigned() -> Weight { // Proof Size summary in bytes: // Measured: `114` - // Estimated: `1218` - // Minimum execution time: 14_565 nanoseconds. - Weight::from_parts(15_097_000, 1218) + // Estimated: `3198` + // Minimum execution time: 14_029_000 picoseconds. + Weight::from_parts(14_288_000, 3198) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -330,10 +333,10 @@ impl WeightInfo for () { /// Proof Skipped: ElectionProviderMultiPhase QueuedSolution (max_values: Some(1), max_size: None, mode: Measured) fn finalize_signed_phase_accept_solution() -> Weight { // Proof Size summary in bytes: - // Measured: `206` - // Estimated: `2809` - // Minimum execution time: 23_341 nanoseconds. - Weight::from_parts(23_770_000, 2809) + // Measured: `174` + // Estimated: `3767` + // Minimum execution time: 26_468_000 picoseconds. + Weight::from_parts(26_790_000, 3767) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -341,10 +344,10 @@ impl WeightInfo for () { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn finalize_signed_phase_reject_solution() -> Weight { // Proof Size summary in bytes: - // Measured: `206` - // Estimated: `2603` - // Minimum execution time: 16_662 nanoseconds. - Weight::from_parts(16_898_000, 2603) + // Measured: `174` + // Estimated: `3593` + // Minimum execution time: 18_401_000 picoseconds. + Weight::from_parts(18_686_000, 3593) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -360,10 +363,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 215_168 nanoseconds. - Weight::from_parts(219_887_000, 0) - // Standard Error: 1_444 - .saturating_add(Weight::from_parts(146_388, 0).saturating_mul(v.into())) + // Minimum execution time: 266_901_000 picoseconds. + Weight::from_parts(270_251_000, 0) + // Standard Error: 1_758 + .saturating_add(Weight::from_parts(167_310, 0).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: ElectionProviderMultiPhase SignedSubmissionIndices (r:1 w:1) @@ -388,14 +391,14 @@ impl WeightInfo for () { /// The range of component `d` is `[200, 400]`. fn elect_queued(a: u32, d: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `368 + a * (768 ±0) + d * (48 ±0)` - // Estimated: `9540 + a * (6912 ±0) + d * (441 ±0)` - // Minimum execution time: 268_021 nanoseconds. - Weight::from_parts(72_491_937, 9540) - // Standard Error: 2_910 - .saturating_add(Weight::from_parts(303_955, 0).saturating_mul(a.into())) - // Standard Error: 4_363 - .saturating_add(Weight::from_parts(167_369, 0).saturating_mul(d.into())) + // Measured: `337 + a * (768 ±0) + d * (48 ±0)` + // Estimated: `16191 + a * (6912 ±0) + d * (441 ±0)` + // Minimum execution time: 286_523_000 picoseconds. + Weight::from_parts(19_101_753, 16191) + // Standard Error: 4_194 + .saturating_add(Weight::from_parts(398_102, 0).saturating_mul(a.into())) + // Standard Error: 6_287 + .saturating_add(Weight::from_parts(188_928, 0).saturating_mul(d.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(8_u64)) .saturating_add(Weight::from_parts(0, 6912).saturating_mul(a.into())) @@ -415,10 +418,10 @@ impl WeightInfo for () { /// Proof Skipped: ElectionProviderMultiPhase SignedSubmissionsMap (max_values: None, max_size: None, mode: Measured) fn submit() -> Weight { // Proof Size summary in bytes: - // Measured: `924` - // Estimated: `7111` - // Minimum execution time: 44_177 nanoseconds. - Weight::from_parts(44_663_000, 7111) + // Measured: `893` + // Estimated: `11906` + // Minimum execution time: 47_876_000 picoseconds. + Weight::from_parts(48_464_000, 11906) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -432,51 +435,51 @@ impl WeightInfo for () { /// Proof Skipped: ElectionProviderMultiPhase QueuedSolution (max_values: Some(1), max_size: None, mode: Measured) /// Storage: ElectionProviderMultiPhase SnapshotMetadata (r:1 w:0) /// Proof Skipped: ElectionProviderMultiPhase SnapshotMetadata (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase MinimumUntrustedScore (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase MinimumUntrustedScore (max_values: Some(1), max_size: None, mode: Measured) /// Storage: ElectionProviderMultiPhase Snapshot (r:1 w:0) /// Proof Skipped: ElectionProviderMultiPhase Snapshot (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase MinimumUntrustedScore (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase MinimumUntrustedScore (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `v` is `[1000, 2000]`. /// The range of component `t` is `[500, 1000]`. /// The range of component `a` is `[500, 800]`. /// The range of component `d` is `[200, 400]`. fn submit_unsigned(v: u32, t: u32, a: u32, _d: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `251 + v * (553 ±0) + t * (32 ±0)` - // Estimated: `5222 + v * (3871 ±0) + t * (224 ±0)` - // Minimum execution time: 4_425_457 nanoseconds. - Weight::from_parts(4_445_889_000, 5222) - // Standard Error: 13_250 - .saturating_add(Weight::from_parts(48_844, 0).saturating_mul(v.into())) - // Standard Error: 39_266 - .saturating_add(Weight::from_parts(4_144_034, 0).saturating_mul(a.into())) + // Measured: `219 + v * (553 ±0) + t * (32 ±0)` + // Estimated: `11928 + v * (3871 ±0) + t * (224 ±0)` + // Minimum execution time: 4_702_825_000 picoseconds. + Weight::from_parts(4_752_015_000, 11928) + // Standard Error: 14_906 + .saturating_add(Weight::from_parts(131_585, 0).saturating_mul(v.into())) + // Standard Error: 44_174 + .saturating_add(Weight::from_parts(4_167_676, 0).saturating_mul(a.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 3871).saturating_mul(v.into())) .saturating_add(Weight::from_parts(0, 224).saturating_mul(t.into())) } - /// Storage: ElectionProviderMultiPhase Round (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase Round (max_values: Some(1), max_size: None, mode: Measured) /// Storage: ElectionProviderMultiPhase DesiredTargets (r:1 w:0) /// Proof Skipped: ElectionProviderMultiPhase DesiredTargets (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ElectionProviderMultiPhase MinimumUntrustedScore (r:1 w:0) - /// Proof Skipped: ElectionProviderMultiPhase MinimumUntrustedScore (max_values: Some(1), max_size: None, mode: Measured) /// Storage: ElectionProviderMultiPhase Snapshot (r:1 w:0) /// Proof Skipped: ElectionProviderMultiPhase Snapshot (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase Round (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase Round (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase MinimumUntrustedScore (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase MinimumUntrustedScore (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `v` is `[1000, 2000]`. /// The range of component `t` is `[500, 1000]`. /// The range of component `a` is `[500, 800]`. /// The range of component `d` is `[200, 400]`. fn feasibility_check(v: u32, t: u32, a: u32, _d: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `226 + v * (553 ±0) + t * (32 ±0)` - // Estimated: `2884 + v * (2212 ±0) + t * (128 ±0)` - // Minimum execution time: 3_812_071 nanoseconds. - Weight::from_parts(3_826_375_000, 2884) - // Standard Error: 11_601 - .saturating_add(Weight::from_parts(145_309, 0).saturating_mul(v.into())) - // Standard Error: 34_378 - .saturating_add(Weight::from_parts(3_223_977, 0).saturating_mul(a.into())) + // Measured: `194 + v * (553 ±0) + t * (32 ±0)` + // Estimated: `6716 + v * (2212 ±0) + t * (128 ±0)` + // Minimum execution time: 4_069_075_000 picoseconds. + Weight::from_parts(4_105_635_000, 6716) + // Standard Error: 12_539 + .saturating_add(Weight::from_parts(163_040, 0).saturating_mul(v.into())) + // Standard Error: 37_160 + .saturating_add(Weight::from_parts(3_343_858, 0).saturating_mul(a.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(Weight::from_parts(0, 2212).saturating_mul(v.into())) .saturating_add(Weight::from_parts(0, 128).saturating_mul(t.into())) diff --git a/frame/elections-phragmen/src/weights.rs b/frame/elections-phragmen/src/weights.rs index bbe66d52981c5..0ff6ecf290036 100644 --- a/frame/elections-phragmen/src/weights.rs +++ b/frame/elections-phragmen/src/weights.rs @@ -18,26 +18,28 @@ //! Autogenerated weights for pallet_elections_phragmen //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-03, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-b3zmxxc-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! 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 // --steps=50 // --repeat=20 +// --pallet=pallet_elections_phragmen +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --json-file=/builds/parity/mirrors/substrate/.git/.artifacts/bench.json -// --pallet=pallet_elections_phragmen -// --chain=dev -// --header=./HEADER-APACHE2 // --output=./frame/elections-phragmen/src/weights.rs +// --header=./HEADER-APACHE2 // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -79,12 +81,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `v` is `[1, 16]`. fn vote_equal(v: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `499 + v * (80 ±0)` - // Estimated: `9726 + v * (320 ±0)` - // Minimum execution time: 27_362 nanoseconds. - Weight::from_parts(28_497_963, 9726) - // Standard Error: 3_968 - .saturating_add(Weight::from_parts(176_840, 0).saturating_mul(v.into())) + // Measured: `403 + v * (80 ±0)` + // Estimated: `14292 + v * (320 ±0)` + // Minimum execution time: 30_206_000 picoseconds. + Weight::from_parts(30_696_455, 14292) + // Standard Error: 1_864 + .saturating_add(Weight::from_parts(124_941, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(Weight::from_parts(0, 320).saturating_mul(v.into())) @@ -102,12 +104,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `v` is `[2, 16]`. fn vote_more(v: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `467 + v * (80 ±0)` - // Estimated: `9598 + v * (320 ±0)` - // Minimum execution time: 37_120 nanoseconds. - Weight::from_parts(38_455_302, 9598) - // Standard Error: 5_478 - .saturating_add(Weight::from_parts(219_678, 0).saturating_mul(v.into())) + // Measured: `371 + v * (80 ±0)` + // Estimated: `14164 + v * (320 ±0)` + // Minimum execution time: 40_331_000 picoseconds. + Weight::from_parts(40_936_971, 14164) + // Standard Error: 2_377 + .saturating_add(Weight::from_parts(142_332, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(Weight::from_parts(0, 320).saturating_mul(v.into())) @@ -125,12 +127,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `v` is `[2, 16]`. fn vote_less(v: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `499 + v * (80 ±0)` - // Estimated: `9726 + v * (320 ±0)` - // Minimum execution time: 36_928 nanoseconds. - Weight::from_parts(38_334_669, 9726) - // Standard Error: 5_271 - .saturating_add(Weight::from_parts(232_355, 0).saturating_mul(v.into())) + // Measured: `403 + v * (80 ±0)` + // Estimated: `14292 + v * (320 ±0)` + // Minimum execution time: 40_343_000 picoseconds. + Weight::from_parts(41_055_673, 14292) + // Standard Error: 3_150 + .saturating_add(Weight::from_parts(129_894, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(Weight::from_parts(0, 320).saturating_mul(v.into())) @@ -141,10 +143,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) fn remove_voter() -> Weight { // Proof Size summary in bytes: - // Measured: `989` - // Estimated: `7238` - // Minimum execution time: 34_338 nanoseconds. - Weight::from_parts(35_672_000, 7238) + // Measured: `925` + // Estimated: `9154` + // Minimum execution time: 36_348_000 picoseconds. + Weight::from_parts(36_677_000, 9154) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -157,12 +159,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `c` is `[1, 64]`. fn submit_candidacy(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1697 + c * (48 ±0)` - // Estimated: `6576 + c * (144 ±0)` - // Minimum execution time: 31_864 nanoseconds. - Weight::from_parts(33_490_161, 6576) - // Standard Error: 2_643 - .saturating_add(Weight::from_parts(158_386, 0).saturating_mul(c.into())) + // Measured: `1570 + c * (48 ±0)` + // Estimated: `9165 + c * (144 ±0)` + // Minimum execution time: 32_963_000 picoseconds. + Weight::from_parts(33_778_406, 9165) + // Standard Error: 2_792 + .saturating_add(Weight::from_parts(71_214, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 144).saturating_mul(c.into())) @@ -172,12 +174,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `c` is `[1, 64]`. fn renounce_candidacy_candidate(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `349 + c * (48 ±0)` - // Estimated: `844 + c * (48 ±0)` - // Minimum execution time: 27_292 nanoseconds. - Weight::from_parts(28_364_955, 844) - // Standard Error: 1_335 - .saturating_add(Weight::from_parts(78_086, 0).saturating_mul(c.into())) + // Measured: `285 + c * (48 ±0)` + // Estimated: `1770 + c * (48 ±0)` + // Minimum execution time: 26_462_000 picoseconds. + Weight::from_parts(27_289_268, 1770) + // Standard Error: 915 + .saturating_add(Weight::from_parts(45_079, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 48).saturating_mul(c.into())) @@ -194,10 +196,10 @@ impl WeightInfo for SubstrateWeight { /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) fn renounce_candidacy_members() -> Weight { // Proof Size summary in bytes: - // Measured: `2027` - // Estimated: `12115` - // Minimum execution time: 45_975 nanoseconds. - Weight::from_parts(47_103_000, 12115) + // Measured: `1900` + // Estimated: `15440` + // Minimum execution time: 44_414_000 picoseconds. + Weight::from_parts(44_900_000, 15440) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -205,10 +207,10 @@ impl WeightInfo for SubstrateWeight { /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) fn renounce_candidacy_runners_up() -> Weight { // Proof Size summary in bytes: - // Measured: `975` - // Estimated: `1470` - // Minimum execution time: 29_243 nanoseconds. - Weight::from_parts(30_582_000, 1470) + // Measured: `880` + // Estimated: `2365` + // Minimum execution time: 28_688_000 picoseconds. + Weight::from_parts(29_027_000, 2365) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -218,7 +220,7 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_000_000_000 nanoseconds. + // Minimum execution time: 2_000_000_000_000 picoseconds. Weight::from_parts(2_000_000_000_000, 0) } /// Storage: Elections Members (r:1 w:1) @@ -235,10 +237,10 @@ impl WeightInfo for SubstrateWeight { /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) fn remove_member_with_replacement() -> Weight { // Proof Size summary in bytes: - // Measured: `2027` - // Estimated: `14718` - // Minimum execution time: 52_527 nanoseconds. - Weight::from_parts(53_538_000, 14718) + // Measured: `1900` + // Estimated: `19033` + // Minimum execution time: 50_280_000 picoseconds. + Weight::from_parts(50_906_000, 19033) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -258,16 +260,16 @@ impl WeightInfo for SubstrateWeight { /// The range of component `d` is `[0, 256]`. fn clean_defunct_voters(v: u32, _d: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1115 + v * (875 ±0)` - // Estimated: `8448 + v * (12352 ±0)` - // Minimum execution time: 14_934_185 nanoseconds. - Weight::from_parts(15_014_057_000, 8448) - // Standard Error: 245_588 - .saturating_add(Weight::from_parts(35_586_946, 0).saturating_mul(v.into())) + // Measured: `1115 + v * (811 ±0)` + // Estimated: `14388 + v * (12096 ±0)` + // Minimum execution time: 14_785_043_000 picoseconds. + Weight::from_parts(14_842_583_000, 14388) + // Standard Error: 242_757 + .saturating_add(Weight::from_parts(36_168_971, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(v.into()))) - .saturating_add(Weight::from_parts(0, 12352).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(0, 12096).saturating_mul(v.into())) } /// Storage: Elections Candidates (r:1 w:1) /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) @@ -292,20 +294,20 @@ impl WeightInfo for SubstrateWeight { /// The range of component `e` is `[512, 8192]`. fn election_phragmen(c: u32, v: u32, e: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0 + v * (638 ±0) + e * (28 ±0)` - // Estimated: `330033 + v * (5229 ±6) + e * (89 ±0) + c * (2135 ±7)` - // Minimum execution time: 1_273_671 nanoseconds. - Weight::from_parts(1_279_716_000, 330033) - // Standard Error: 543_277 - .saturating_add(Weight::from_parts(20_613_753, 0).saturating_mul(v.into())) - // Standard Error: 34_857 - .saturating_add(Weight::from_parts(688_354, 0).saturating_mul(e.into())) + // Measured: `0 + v * (606 ±0) + e * (28 ±0)` + // Estimated: `309059 + v * (5005 ±8) + e * (89 ±0) + c * (2135 ±7)` + // Minimum execution time: 1_074_961_000 picoseconds. + Weight::from_parts(1_079_460_000, 309059) + // Standard Error: 598_993 + .saturating_add(Weight::from_parts(17_097_981, 0).saturating_mul(v.into())) + // Standard Error: 38_432 + .saturating_add(Weight::from_parts(820_141, 0).saturating_mul(e.into())) .saturating_add(T::DbWeight::get().reads(21_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(c.into()))) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().writes(6_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(c.into()))) - .saturating_add(Weight::from_parts(0, 5229).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(0, 5005).saturating_mul(v.into())) .saturating_add(Weight::from_parts(0, 89).saturating_mul(e.into())) .saturating_add(Weight::from_parts(0, 2135).saturating_mul(c.into())) } @@ -326,12 +328,12 @@ impl WeightInfo for () { /// The range of component `v` is `[1, 16]`. fn vote_equal(v: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `499 + v * (80 ±0)` - // Estimated: `9726 + v * (320 ±0)` - // Minimum execution time: 27_362 nanoseconds. - Weight::from_parts(28_497_963, 9726) - // Standard Error: 3_968 - .saturating_add(Weight::from_parts(176_840, 0).saturating_mul(v.into())) + // Measured: `403 + v * (80 ±0)` + // Estimated: `14292 + v * (320 ±0)` + // Minimum execution time: 30_206_000 picoseconds. + Weight::from_parts(30_696_455, 14292) + // Standard Error: 1_864 + .saturating_add(Weight::from_parts(124_941, 0).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(Weight::from_parts(0, 320).saturating_mul(v.into())) @@ -349,12 +351,12 @@ impl WeightInfo for () { /// The range of component `v` is `[2, 16]`. fn vote_more(v: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `467 + v * (80 ±0)` - // Estimated: `9598 + v * (320 ±0)` - // Minimum execution time: 37_120 nanoseconds. - Weight::from_parts(38_455_302, 9598) - // Standard Error: 5_478 - .saturating_add(Weight::from_parts(219_678, 0).saturating_mul(v.into())) + // Measured: `371 + v * (80 ±0)` + // Estimated: `14164 + v * (320 ±0)` + // Minimum execution time: 40_331_000 picoseconds. + Weight::from_parts(40_936_971, 14164) + // Standard Error: 2_377 + .saturating_add(Weight::from_parts(142_332, 0).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(Weight::from_parts(0, 320).saturating_mul(v.into())) @@ -372,12 +374,12 @@ impl WeightInfo for () { /// The range of component `v` is `[2, 16]`. fn vote_less(v: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `499 + v * (80 ±0)` - // Estimated: `9726 + v * (320 ±0)` - // Minimum execution time: 36_928 nanoseconds. - Weight::from_parts(38_334_669, 9726) - // Standard Error: 5_271 - .saturating_add(Weight::from_parts(232_355, 0).saturating_mul(v.into())) + // Measured: `403 + v * (80 ±0)` + // Estimated: `14292 + v * (320 ±0)` + // Minimum execution time: 40_343_000 picoseconds. + Weight::from_parts(41_055_673, 14292) + // Standard Error: 3_150 + .saturating_add(Weight::from_parts(129_894, 0).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(Weight::from_parts(0, 320).saturating_mul(v.into())) @@ -388,10 +390,10 @@ impl WeightInfo for () { /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) fn remove_voter() -> Weight { // Proof Size summary in bytes: - // Measured: `989` - // Estimated: `7238` - // Minimum execution time: 34_338 nanoseconds. - Weight::from_parts(35_672_000, 7238) + // Measured: `925` + // Estimated: `9154` + // Minimum execution time: 36_348_000 picoseconds. + Weight::from_parts(36_677_000, 9154) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -404,12 +406,12 @@ impl WeightInfo for () { /// The range of component `c` is `[1, 64]`. fn submit_candidacy(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1697 + c * (48 ±0)` - // Estimated: `6576 + c * (144 ±0)` - // Minimum execution time: 31_864 nanoseconds. - Weight::from_parts(33_490_161, 6576) - // Standard Error: 2_643 - .saturating_add(Weight::from_parts(158_386, 0).saturating_mul(c.into())) + // Measured: `1570 + c * (48 ±0)` + // Estimated: `9165 + c * (144 ±0)` + // Minimum execution time: 32_963_000 picoseconds. + Weight::from_parts(33_778_406, 9165) + // Standard Error: 2_792 + .saturating_add(Weight::from_parts(71_214, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 144).saturating_mul(c.into())) @@ -419,12 +421,12 @@ impl WeightInfo for () { /// The range of component `c` is `[1, 64]`. fn renounce_candidacy_candidate(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `349 + c * (48 ±0)` - // Estimated: `844 + c * (48 ±0)` - // Minimum execution time: 27_292 nanoseconds. - Weight::from_parts(28_364_955, 844) - // Standard Error: 1_335 - .saturating_add(Weight::from_parts(78_086, 0).saturating_mul(c.into())) + // Measured: `285 + c * (48 ±0)` + // Estimated: `1770 + c * (48 ±0)` + // Minimum execution time: 26_462_000 picoseconds. + Weight::from_parts(27_289_268, 1770) + // Standard Error: 915 + .saturating_add(Weight::from_parts(45_079, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 48).saturating_mul(c.into())) @@ -441,10 +443,10 @@ impl WeightInfo for () { /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) fn renounce_candidacy_members() -> Weight { // Proof Size summary in bytes: - // Measured: `2027` - // Estimated: `12115` - // Minimum execution time: 45_975 nanoseconds. - Weight::from_parts(47_103_000, 12115) + // Measured: `1900` + // Estimated: `15440` + // Minimum execution time: 44_414_000 picoseconds. + Weight::from_parts(44_900_000, 15440) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -452,10 +454,10 @@ impl WeightInfo for () { /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) fn renounce_candidacy_runners_up() -> Weight { // Proof Size summary in bytes: - // Measured: `975` - // Estimated: `1470` - // Minimum execution time: 29_243 nanoseconds. - Weight::from_parts(30_582_000, 1470) + // Measured: `880` + // Estimated: `2365` + // Minimum execution time: 28_688_000 picoseconds. + Weight::from_parts(29_027_000, 2365) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -465,7 +467,7 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_000_000_000 nanoseconds. + // Minimum execution time: 2_000_000_000_000 picoseconds. Weight::from_parts(2_000_000_000_000, 0) } /// Storage: Elections Members (r:1 w:1) @@ -482,10 +484,10 @@ impl WeightInfo for () { /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) fn remove_member_with_replacement() -> Weight { // Proof Size summary in bytes: - // Measured: `2027` - // Estimated: `14718` - // Minimum execution time: 52_527 nanoseconds. - Weight::from_parts(53_538_000, 14718) + // Measured: `1900` + // Estimated: `19033` + // Minimum execution time: 50_280_000 picoseconds. + Weight::from_parts(50_906_000, 19033) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -505,16 +507,16 @@ impl WeightInfo for () { /// The range of component `d` is `[0, 256]`. fn clean_defunct_voters(v: u32, _d: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1115 + v * (875 ±0)` - // Estimated: `8448 + v * (12352 ±0)` - // Minimum execution time: 14_934_185 nanoseconds. - Weight::from_parts(15_014_057_000, 8448) - // Standard Error: 245_588 - .saturating_add(Weight::from_parts(35_586_946, 0).saturating_mul(v.into())) + // Measured: `1115 + v * (811 ±0)` + // Estimated: `14388 + v * (12096 ±0)` + // Minimum execution time: 14_785_043_000 picoseconds. + Weight::from_parts(14_842_583_000, 14388) + // Standard Error: 242_757 + .saturating_add(Weight::from_parts(36_168_971, 0).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(v.into()))) .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(v.into()))) - .saturating_add(Weight::from_parts(0, 12352).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(0, 12096).saturating_mul(v.into())) } /// Storage: Elections Candidates (r:1 w:1) /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) @@ -539,20 +541,20 @@ impl WeightInfo for () { /// The range of component `e` is `[512, 8192]`. fn election_phragmen(c: u32, v: u32, e: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0 + v * (638 ±0) + e * (28 ±0)` - // Estimated: `330033 + v * (5229 ±6) + e * (89 ±0) + c * (2135 ±7)` - // Minimum execution time: 1_273_671 nanoseconds. - Weight::from_parts(1_279_716_000, 330033) - // Standard Error: 543_277 - .saturating_add(Weight::from_parts(20_613_753, 0).saturating_mul(v.into())) - // Standard Error: 34_857 - .saturating_add(Weight::from_parts(688_354, 0).saturating_mul(e.into())) + // Measured: `0 + v * (606 ±0) + e * (28 ±0)` + // Estimated: `309059 + v * (5005 ±8) + e * (89 ±0) + c * (2135 ±7)` + // Minimum execution time: 1_074_961_000 picoseconds. + Weight::from_parts(1_079_460_000, 309059) + // Standard Error: 598_993 + .saturating_add(Weight::from_parts(17_097_981, 0).saturating_mul(v.into())) + // Standard Error: 38_432 + .saturating_add(Weight::from_parts(820_141, 0).saturating_mul(e.into())) .saturating_add(RocksDbWeight::get().reads(21_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(c.into()))) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(v.into()))) .saturating_add(RocksDbWeight::get().writes(6_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(c.into()))) - .saturating_add(Weight::from_parts(0, 5229).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(0, 5005).saturating_mul(v.into())) .saturating_add(Weight::from_parts(0, 89).saturating_mul(e.into())) .saturating_add(Weight::from_parts(0, 2135).saturating_mul(c.into())) } diff --git a/frame/fast-unstake/src/weights.rs b/frame/fast-unstake/src/weights.rs index ced7acb951229..b47d4f056e524 100644 --- a/frame/fast-unstake/src/weights.rs +++ b/frame/fast-unstake/src/weights.rs @@ -18,25 +18,28 @@ //! Autogenerated weights for pallet_fast_unstake //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-01-25, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `runner-b3zmxxc-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/production/substrate +// ./target/production/substrate // benchmark // pallet +// --chain=dev // --steps=50 // --repeat=20 +// --pallet=pallet_fast_unstake +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --json-file=/builds/parity/mirrors/substrate/.git/.artifacts/bench.json -// --pallet=pallet_fast_unstake -// --chain=dev -// --header=./HEADER-APACHE2 // --output=./frame/fast-unstake/src/weights.rs +// --header=./HEADER-APACHE2 // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -58,172 +61,290 @@ pub trait WeightInfo { /// 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: FastUnstake Head (r:1 w:1) - // Storage: FastUnstake CounterForQueue (r:1 w:0) - // Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) - // Storage: Staking CurrentEra (r:1 w:0) - // Storage: Staking SlashingSpans (r:1 w:0) - // 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: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: FastUnstake ErasToCheckPerBlock (r:1 w:0) + /// Proof: FastUnstake ErasToCheckPerBlock (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking ValidatorCount (r:1 w:0) + /// Proof: Staking ValidatorCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: FastUnstake Head (r:1 w:1) + /// Proof: FastUnstake Head (max_values: Some(1), max_size: Some(5768), added: 6263, mode: MaxEncodedLen) + /// Storage: FastUnstake CounterForQueue (r:1 w:0) + /// Proof: FastUnstake CounterForQueue (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Staking CurrentEra (r:1 w:0) + /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking SlashingSpans (r:64 w:0) + /// Proof Skipped: Staking SlashingSpans (max_values: None, max_size: None, mode: Measured) + /// Storage: Staking Bonded (r:64 w:64) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Validators (r:64 w:0) + /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:64 w:0) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) + /// Storage: System Account (r:64 w:64) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:64 w:64) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:0 w:64) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking Payee (r:0 w:64) + /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) /// The range of component `b` is `[1, 64]`. fn on_idle_unstake(b: u32, ) -> Weight { - // Minimum execution time: 92_833 nanoseconds. - Weight::from_parts(62_136_346, 0) - // Standard Error: 25_541 - .saturating_add(Weight::from_parts(42_904_859, 0).saturating_mul(b.into())) - .saturating_add(T::DbWeight::get().reads(6)) + // Proof Size summary in bytes: + // Measured: `1344 + b * (343 ±0)` + // Estimated: `23254 + b * (17642 ±0)` + // Minimum execution time: 78_484_000 picoseconds. + Weight::from_parts(39_186_541, 23254) + // Standard Error: 37_606 + .saturating_add(Weight::from_parts(42_433_199, 0).saturating_mul(b.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((6_u64).saturating_mul(b.into()))) - .saturating_add(T::DbWeight::get().writes(1)) + .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(T::DbWeight::get().writes((5_u64).saturating_mul(b.into()))) + .saturating_add(Weight::from_parts(0, 17642).saturating_mul(b.into())) } - // Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) - // Storage: Staking ValidatorCount (r:1 w:0) - // Storage: FastUnstake Head (r:1 w:1) - // Storage: FastUnstake CounterForQueue (r:1 w:0) - // Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) - // Storage: Staking CurrentEra (r:1 w:0) - // Storage: Staking ErasStakers (r:2 w:0) + /// Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) + /// Proof: FastUnstake ErasToCheckPerBlock (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking ValidatorCount (r:1 w:0) + /// Proof: Staking ValidatorCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: FastUnstake Head (r:1 w:1) + /// Proof: FastUnstake Head (max_values: Some(1), max_size: Some(5768), added: 6263, mode: MaxEncodedLen) + /// Storage: FastUnstake CounterForQueue (r:1 w:0) + /// Proof: FastUnstake CounterForQueue (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Staking CurrentEra (r:1 w:0) + /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking ErasStakers (r:257 w:0) + /// Proof Skipped: Staking ErasStakers (max_values: None, max_size: None, mode: Measured) /// The range of component `v` is `[1, 256]`. /// The range of component `b` is `[1, 64]`. fn on_idle_check(v: u32, b: u32, ) -> Weight { - // Minimum execution time: 1_775_293 nanoseconds. - Weight::from_parts(1_787_133_000, 0) - // Standard Error: 17_109_142 - .saturating_add(Weight::from_parts(546_766_552, 0).saturating_mul(v.into())) - // Standard Error: 68_455_625 - .saturating_add(Weight::from_parts(2_135_980_830, 0).saturating_mul(b.into())) - .saturating_add(T::DbWeight::get().reads(7)) + // Proof Size summary in bytes: + // Measured: `1512 + v * (10037 ±0) + b * (48 ±0)` + // Estimated: `20889 + v * (22551 ±0) + b * (98 ±0)` + // Minimum execution time: 1_538_727_000 picoseconds. + Weight::from_parts(1_549_586_000, 20889) + // Standard Error: 14_184_223 + .saturating_add(Weight::from_parts(452_966_006, 0).saturating_mul(v.into())) + // Standard Error: 56_752_692 + .saturating_add(Weight::from_parts(1_775_601_329, 0).saturating_mul(b.into())) + .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) - .saturating_add(T::DbWeight::get().writes(1)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + .saturating_add(Weight::from_parts(0, 22551).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(0, 98).saturating_mul(b.into())) } - // Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) - // Storage: Staking Ledger (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: 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) + /// Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) + /// Proof: FastUnstake ErasToCheckPerBlock (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:1 w:1) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: FastUnstake Queue (r:1 w:1) + /// Proof: FastUnstake Queue (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: FastUnstake Head (r:1 w:0) + /// Proof: FastUnstake Head (max_values: Some(1), max_size: Some(5768), added: 6263, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:1 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Validators (r:1 w:0) + /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:1 w:1) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) + /// Storage: Staking CounterForNominators (r:1 w:1) + /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:1 w:1) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:1 w:1) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: VoterList CounterForListNodes (r:1 w:1) + /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking CurrentEra (r:1 w:0) + /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: FastUnstake CounterForQueue (r:1 w:1) + /// Proof: FastUnstake CounterForQueue (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn register_fast_unstake() -> Weight { - // Minimum execution time: 124_849 nanoseconds. - Weight::from_parts(128_176_000, 0) - .saturating_add(T::DbWeight::get().reads(14)) - .saturating_add(T::DbWeight::get().writes(9)) + // Proof Size summary in bytes: + // Measured: `1964` + // Estimated: `45775` + // Minimum execution time: 117_552_000 picoseconds. + Weight::from_parts(118_303_000, 45775) + .saturating_add(T::DbWeight::get().reads(14_u64)) + .saturating_add(T::DbWeight::get().writes(9_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) + /// Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) + /// Proof: FastUnstake ErasToCheckPerBlock (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:1 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: FastUnstake Queue (r:1 w:1) + /// Proof: FastUnstake Queue (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: FastUnstake Head (r:1 w:0) + /// Proof: FastUnstake Head (max_values: Some(1), max_size: Some(5768), added: 6263, mode: MaxEncodedLen) + /// Storage: FastUnstake CounterForQueue (r:1 w:1) + /// Proof: FastUnstake CounterForQueue (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn deregister() -> Weight { - // Minimum execution time: 48_246 nanoseconds. - Weight::from_parts(49_720_000, 0) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(2)) + // Proof Size summary in bytes: + // Measured: `1223` + // Estimated: `18308` + // Minimum execution time: 42_291_000 picoseconds. + Weight::from_parts(42_835_000, 18308) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } - // Storage: FastUnstake ErasToCheckPerBlock (r:0 w:1) + /// Storage: FastUnstake ErasToCheckPerBlock (r:0 w:1) + /// Proof: FastUnstake ErasToCheckPerBlock (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn control() -> Weight { - // Minimum execution time: 4_611 nanoseconds. - Weight::from_parts(4_844_000, 0) - .saturating_add(T::DbWeight::get().writes(1)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_551_000 picoseconds. + Weight::from_parts(3_632_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) } } // For backwards compatibility and tests impl WeightInfo for () { - // Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) - // Storage: Staking ValidatorCount (r:1 w:0) - // Storage: FastUnstake Head (r:1 w:1) - // Storage: FastUnstake CounterForQueue (r:1 w:0) - // Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) - // Storage: Staking CurrentEra (r:1 w:0) - // Storage: Staking SlashingSpans (r:1 w:0) - // 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: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: FastUnstake ErasToCheckPerBlock (r:1 w:0) + /// Proof: FastUnstake ErasToCheckPerBlock (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking ValidatorCount (r:1 w:0) + /// Proof: Staking ValidatorCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: FastUnstake Head (r:1 w:1) + /// Proof: FastUnstake Head (max_values: Some(1), max_size: Some(5768), added: 6263, mode: MaxEncodedLen) + /// Storage: FastUnstake CounterForQueue (r:1 w:0) + /// Proof: FastUnstake CounterForQueue (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Staking CurrentEra (r:1 w:0) + /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking SlashingSpans (r:64 w:0) + /// Proof Skipped: Staking SlashingSpans (max_values: None, max_size: None, mode: Measured) + /// Storage: Staking Bonded (r:64 w:64) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Validators (r:64 w:0) + /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:64 w:0) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) + /// Storage: System Account (r:64 w:64) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:64 w:64) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:0 w:64) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking Payee (r:0 w:64) + /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) /// The range of component `b` is `[1, 64]`. fn on_idle_unstake(b: u32, ) -> Weight { - // Minimum execution time: 92_833 nanoseconds. - Weight::from_parts(62_136_346, 0) - // Standard Error: 25_541 - .saturating_add(Weight::from_parts(42_904_859, 0).saturating_mul(b.into())) - .saturating_add(RocksDbWeight::get().reads(6)) + // Proof Size summary in bytes: + // Measured: `1344 + b * (343 ±0)` + // Estimated: `23254 + b * (17642 ±0)` + // Minimum execution time: 78_484_000 picoseconds. + Weight::from_parts(39_186_541, 23254) + // Standard Error: 37_606 + .saturating_add(Weight::from_parts(42_433_199, 0).saturating_mul(b.into())) + .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((6_u64).saturating_mul(b.into()))) - .saturating_add(RocksDbWeight::get().writes(1)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(RocksDbWeight::get().writes((5_u64).saturating_mul(b.into()))) + .saturating_add(Weight::from_parts(0, 17642).saturating_mul(b.into())) } - // Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) - // Storage: Staking ValidatorCount (r:1 w:0) - // Storage: FastUnstake Head (r:1 w:1) - // Storage: FastUnstake CounterForQueue (r:1 w:0) - // Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) - // Storage: Staking CurrentEra (r:1 w:0) - // Storage: Staking ErasStakers (r:2 w:0) + /// Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) + /// Proof: FastUnstake ErasToCheckPerBlock (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking ValidatorCount (r:1 w:0) + /// Proof: Staking ValidatorCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: FastUnstake Head (r:1 w:1) + /// Proof: FastUnstake Head (max_values: Some(1), max_size: Some(5768), added: 6263, mode: MaxEncodedLen) + /// Storage: FastUnstake CounterForQueue (r:1 w:0) + /// Proof: FastUnstake CounterForQueue (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Staking CurrentEra (r:1 w:0) + /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking ErasStakers (r:257 w:0) + /// Proof Skipped: Staking ErasStakers (max_values: None, max_size: None, mode: Measured) /// The range of component `v` is `[1, 256]`. /// The range of component `b` is `[1, 64]`. fn on_idle_check(v: u32, b: u32, ) -> Weight { - // Minimum execution time: 1_775_293 nanoseconds. - Weight::from_parts(1_787_133_000, 0) - // Standard Error: 17_109_142 - .saturating_add(Weight::from_parts(546_766_552, 0).saturating_mul(v.into())) - // Standard Error: 68_455_625 - .saturating_add(Weight::from_parts(2_135_980_830, 0).saturating_mul(b.into())) - .saturating_add(RocksDbWeight::get().reads(7)) + // Proof Size summary in bytes: + // Measured: `1512 + v * (10037 ±0) + b * (48 ±0)` + // Estimated: `20889 + v * (22551 ±0) + b * (98 ±0)` + // Minimum execution time: 1_538_727_000 picoseconds. + Weight::from_parts(1_549_586_000, 20889) + // Standard Error: 14_184_223 + .saturating_add(Weight::from_parts(452_966_006, 0).saturating_mul(v.into())) + // Standard Error: 56_752_692 + .saturating_add(Weight::from_parts(1_775_601_329, 0).saturating_mul(b.into())) + .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(v.into()))) - .saturating_add(RocksDbWeight::get().writes(1)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + .saturating_add(Weight::from_parts(0, 22551).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(0, 98).saturating_mul(b.into())) } - // Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) - // Storage: Staking Ledger (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: 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) + /// Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) + /// Proof: FastUnstake ErasToCheckPerBlock (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:1 w:1) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: FastUnstake Queue (r:1 w:1) + /// Proof: FastUnstake Queue (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: FastUnstake Head (r:1 w:0) + /// Proof: FastUnstake Head (max_values: Some(1), max_size: Some(5768), added: 6263, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:1 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Validators (r:1 w:0) + /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:1 w:1) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) + /// Storage: Staking CounterForNominators (r:1 w:1) + /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:1 w:1) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:1 w:1) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: VoterList CounterForListNodes (r:1 w:1) + /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking CurrentEra (r:1 w:0) + /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: FastUnstake CounterForQueue (r:1 w:1) + /// Proof: FastUnstake CounterForQueue (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn register_fast_unstake() -> Weight { - // Minimum execution time: 124_849 nanoseconds. - Weight::from_parts(128_176_000, 0) - .saturating_add(RocksDbWeight::get().reads(14)) - .saturating_add(RocksDbWeight::get().writes(9)) + // Proof Size summary in bytes: + // Measured: `1964` + // Estimated: `45775` + // Minimum execution time: 117_552_000 picoseconds. + Weight::from_parts(118_303_000, 45775) + .saturating_add(RocksDbWeight::get().reads(14_u64)) + .saturating_add(RocksDbWeight::get().writes(9_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) + /// Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) + /// Proof: FastUnstake ErasToCheckPerBlock (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:1 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: FastUnstake Queue (r:1 w:1) + /// Proof: FastUnstake Queue (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: FastUnstake Head (r:1 w:0) + /// Proof: FastUnstake Head (max_values: Some(1), max_size: Some(5768), added: 6263, mode: MaxEncodedLen) + /// Storage: FastUnstake CounterForQueue (r:1 w:1) + /// Proof: FastUnstake CounterForQueue (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn deregister() -> Weight { - // Minimum execution time: 48_246 nanoseconds. - Weight::from_parts(49_720_000, 0) - .saturating_add(RocksDbWeight::get().reads(5)) - .saturating_add(RocksDbWeight::get().writes(2)) + // Proof Size summary in bytes: + // Measured: `1223` + // Estimated: `18308` + // Minimum execution time: 42_291_000 picoseconds. + Weight::from_parts(42_835_000, 18308) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } - // Storage: FastUnstake ErasToCheckPerBlock (r:0 w:1) + /// Storage: FastUnstake ErasToCheckPerBlock (r:0 w:1) + /// Proof: FastUnstake ErasToCheckPerBlock (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn control() -> Weight { - // Minimum execution time: 4_611 nanoseconds. - Weight::from_parts(4_844_000, 0) - .saturating_add(RocksDbWeight::get().writes(1)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_551_000 picoseconds. + Weight::from_parts(3_632_000, 0) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } } diff --git a/frame/glutton/src/weights.rs b/frame/glutton/src/weights.rs index 1a7020c17a9ab..bd409645ae8ff 100644 --- a/frame/glutton/src/weights.rs +++ b/frame/glutton/src/weights.rs @@ -18,26 +18,28 @@ //! Autogenerated weights for pallet_glutton //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/production/substrate +// ./target/production/substrate // benchmark // pallet +// --chain=dev // --steps=50 // --repeat=20 +// --pallet=pallet_glutton +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --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_glutton -// --chain=dev -// --header=./HEADER-APACHE2 // --output=./frame/glutton/src/weights.rs +// --header=./HEADER-APACHE2 // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -72,11 +74,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `4` // Estimated: `1489` - // Minimum execution time: 10_218 nanoseconds. - Weight::from_parts(10_510_000, 0) - .saturating_add(Weight::from_parts(0, 1489)) - // Standard Error: 1_582 - .saturating_add(Weight::from_parts(1_577_660, 0).saturating_mul(n.into())) + // Minimum execution time: 10_384_000 picoseconds. + Weight::from_parts(10_598_000, 1489) + // Standard Error: 1_369 + .saturating_add(Weight::from_parts(1_580_155, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) @@ -90,11 +91,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `65` // Estimated: `1489` - // Minimum execution time: 10_993 nanoseconds. - Weight::from_parts(11_208_000, 0) - .saturating_add(Weight::from_parts(0, 1489)) - // Standard Error: 1_386 - .saturating_add(Weight::from_parts(1_072_330, 0).saturating_mul(n.into())) + // Minimum execution time: 11_022_000 picoseconds. + Weight::from_parts(11_319_000, 1489) + // Standard Error: 1_108 + .saturating_add(Weight::from_parts(1_048_682, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) @@ -104,24 +104,22 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 740 nanoseconds. - Weight::from_parts(770_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 24 - .saturating_add(Weight::from_parts(96_434, 0).saturating_mul(i.into())) + // Minimum execution time: 660_000 picoseconds. + Weight::from_parts(7_814_200, 0) + // Standard Error: 33 + .saturating_add(Weight::from_parts(94_390, 0).saturating_mul(i.into())) } /// Storage: Glutton TrashData (r:5000 w:0) /// Proof: Glutton TrashData (max_values: Some(65000), max_size: Some(1036), added: 3016, mode: MaxEncodedLen) /// The range of component `i` is `[0, 5000]`. fn waste_proof_size_some(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `119036 + i * (1053 ±0)` + // Measured: `119036 + i * (1022 ±0)` // Estimated: `990 + i * (3016 ±0)` - // Minimum execution time: 630 nanoseconds. - Weight::from_parts(712_000, 0) - .saturating_add(Weight::from_parts(0, 990)) - // Standard Error: 4_326 - .saturating_add(Weight::from_parts(5_500_880, 0).saturating_mul(i.into())) + // Minimum execution time: 712_000 picoseconds. + Weight::from_parts(814_000, 990) + // Standard Error: 1_805 + .saturating_add(Weight::from_parts(5_407_690, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(i.into()))) .saturating_add(Weight::from_parts(0, 3016).saturating_mul(i.into())) } @@ -133,11 +131,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Glutton TrashData (max_values: Some(65000), max_size: Some(1036), added: 3016, mode: MaxEncodedLen) fn on_idle_high_proof_waste() -> Weight { // Proof Size summary in bytes: - // Measured: `1954313` + // Measured: `1900466` // Estimated: `5242760` - // Minimum execution time: 56_743_236 nanoseconds. - Weight::from_parts(57_088_040_000, 0) - .saturating_add(Weight::from_parts(0, 5242760)) + // Minimum execution time: 54_903_045_000 picoseconds. + Weight::from_parts(55_194_691_000, 5242760) .saturating_add(T::DbWeight::get().reads(1739_u64)) } /// Storage: Glutton Storage (r:1 w:0) @@ -148,11 +145,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Glutton TrashData (max_values: Some(65000), max_size: Some(1036), added: 3016, mode: MaxEncodedLen) fn on_idle_low_proof_waste() -> Weight { // Proof Size summary in bytes: - // Measured: `9671` + // Measured: `9516` // Estimated: `19048` - // Minimum execution time: 100_387_042 nanoseconds. - Weight::from_parts(100_987_577_000, 0) - .saturating_add(Weight::from_parts(0, 19048)) + // Minimum execution time: 97_295_331_000 picoseconds. + Weight::from_parts(97_853_502_000, 19048) .saturating_add(T::DbWeight::get().reads(7_u64)) } /// Storage: Glutton Storage (r:1 w:0) @@ -163,9 +159,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `4` // Estimated: `2978` - // Minimum execution time: 4_256 nanoseconds. - Weight::from_parts(4_447_000, 0) - .saturating_add(Weight::from_parts(0, 2978)) + // Minimum execution time: 4_280_000 picoseconds. + Weight::from_parts(4_381_000, 2978) .saturating_add(T::DbWeight::get().reads(2_u64)) } /// Storage: Glutton Compute (r:0 w:1) @@ -174,9 +169,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_663 nanoseconds. - Weight::from_parts(8_864_000, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Minimum execution time: 8_758_000 picoseconds. + Weight::from_parts(8_988_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Glutton Storage (r:0 w:1) @@ -185,9 +179,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_653 nanoseconds. - Weight::from_parts(8_998_000, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Minimum execution time: 8_901_000 picoseconds. + Weight::from_parts(9_291_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } } @@ -203,11 +196,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `4` // Estimated: `1489` - // Minimum execution time: 10_218 nanoseconds. - Weight::from_parts(10_510_000, 0) - .saturating_add(Weight::from_parts(0, 1489)) - // Standard Error: 1_582 - .saturating_add(Weight::from_parts(1_577_660, 0).saturating_mul(n.into())) + // Minimum execution time: 10_384_000 picoseconds. + Weight::from_parts(10_598_000, 1489) + // Standard Error: 1_369 + .saturating_add(Weight::from_parts(1_580_155, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) @@ -221,11 +213,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `65` // Estimated: `1489` - // Minimum execution time: 10_993 nanoseconds. - Weight::from_parts(11_208_000, 0) - .saturating_add(Weight::from_parts(0, 1489)) - // Standard Error: 1_386 - .saturating_add(Weight::from_parts(1_072_330, 0).saturating_mul(n.into())) + // Minimum execution time: 11_022_000 picoseconds. + Weight::from_parts(11_319_000, 1489) + // Standard Error: 1_108 + .saturating_add(Weight::from_parts(1_048_682, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) @@ -235,24 +226,22 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 740 nanoseconds. - Weight::from_parts(770_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 24 - .saturating_add(Weight::from_parts(96_434, 0).saturating_mul(i.into())) + // Minimum execution time: 660_000 picoseconds. + Weight::from_parts(7_814_200, 0) + // Standard Error: 33 + .saturating_add(Weight::from_parts(94_390, 0).saturating_mul(i.into())) } /// Storage: Glutton TrashData (r:5000 w:0) /// Proof: Glutton TrashData (max_values: Some(65000), max_size: Some(1036), added: 3016, mode: MaxEncodedLen) /// The range of component `i` is `[0, 5000]`. fn waste_proof_size_some(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `119036 + i * (1053 ±0)` + // Measured: `119036 + i * (1022 ±0)` // Estimated: `990 + i * (3016 ±0)` - // Minimum execution time: 630 nanoseconds. - Weight::from_parts(712_000, 0) - .saturating_add(Weight::from_parts(0, 990)) - // Standard Error: 4_326 - .saturating_add(Weight::from_parts(5_500_880, 0).saturating_mul(i.into())) + // Minimum execution time: 712_000 picoseconds. + Weight::from_parts(814_000, 990) + // Standard Error: 1_805 + .saturating_add(Weight::from_parts(5_407_690, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(i.into()))) .saturating_add(Weight::from_parts(0, 3016).saturating_mul(i.into())) } @@ -264,11 +253,10 @@ impl WeightInfo for () { /// Proof: Glutton TrashData (max_values: Some(65000), max_size: Some(1036), added: 3016, mode: MaxEncodedLen) fn on_idle_high_proof_waste() -> Weight { // Proof Size summary in bytes: - // Measured: `1954313` + // Measured: `1900466` // Estimated: `5242760` - // Minimum execution time: 56_743_236 nanoseconds. - Weight::from_parts(57_088_040_000, 0) - .saturating_add(Weight::from_parts(0, 5242760)) + // Minimum execution time: 54_903_045_000 picoseconds. + Weight::from_parts(55_194_691_000, 5242760) .saturating_add(RocksDbWeight::get().reads(1739_u64)) } /// Storage: Glutton Storage (r:1 w:0) @@ -279,11 +267,10 @@ impl WeightInfo for () { /// Proof: Glutton TrashData (max_values: Some(65000), max_size: Some(1036), added: 3016, mode: MaxEncodedLen) fn on_idle_low_proof_waste() -> Weight { // Proof Size summary in bytes: - // Measured: `9671` + // Measured: `9516` // Estimated: `19048` - // Minimum execution time: 100_387_042 nanoseconds. - Weight::from_parts(100_987_577_000, 0) - .saturating_add(Weight::from_parts(0, 19048)) + // Minimum execution time: 97_295_331_000 picoseconds. + Weight::from_parts(97_853_502_000, 19048) .saturating_add(RocksDbWeight::get().reads(7_u64)) } /// Storage: Glutton Storage (r:1 w:0) @@ -294,9 +281,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `4` // Estimated: `2978` - // Minimum execution time: 4_256 nanoseconds. - Weight::from_parts(4_447_000, 0) - .saturating_add(Weight::from_parts(0, 2978)) + // Minimum execution time: 4_280_000 picoseconds. + Weight::from_parts(4_381_000, 2978) .saturating_add(RocksDbWeight::get().reads(2_u64)) } /// Storage: Glutton Compute (r:0 w:1) @@ -305,9 +291,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_663 nanoseconds. - Weight::from_parts(8_864_000, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Minimum execution time: 8_758_000 picoseconds. + Weight::from_parts(8_988_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Glutton Storage (r:0 w:1) @@ -316,9 +301,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_653 nanoseconds. - Weight::from_parts(8_998_000, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Minimum execution time: 8_901_000 picoseconds. + Weight::from_parts(9_291_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } } diff --git a/frame/identity/src/weights.rs b/frame/identity/src/weights.rs index 65fe2b17ba527..bad6aa76854ea 100644 --- a/frame/identity/src/weights.rs +++ b/frame/identity/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_identity //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,6 +31,9 @@ // --steps=50 // --repeat=20 // --pallet=pallet_identity +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -74,12 +77,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[1, 19]`. fn add_registrar(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `64 + r * (57 ±0)` - // Estimated: `1636` - // Minimum execution time: 10_964 nanoseconds. - Weight::from_parts(11_800_935, 1636) - // Standard Error: 1_334 - .saturating_add(Weight::from_parts(96_038, 0).saturating_mul(r.into())) + // Measured: `32 + r * (57 ±0)` + // Estimated: `2626` + // Minimum execution time: 13_092_000 picoseconds. + Weight::from_parts(13_798_719, 2626) + // Standard Error: 1_553 + .saturating_add(Weight::from_parts(109_215, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -89,14 +92,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `x` is `[0, 100]`. fn set_identity(r: u32, x: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `474 + r * (5 ±0)` - // Estimated: `10013` - // Minimum execution time: 26_400 nanoseconds. - Weight::from_parts(26_060_549, 10013) - // Standard Error: 1_561 - .saturating_add(Weight::from_parts(72_083, 0).saturating_mul(r.into())) - // Standard Error: 304 - .saturating_add(Weight::from_parts(306_994, 0).saturating_mul(x.into())) + // Measured: `442 + r * (5 ±0)` + // Estimated: `11003` + // Minimum execution time: 30_800_000 picoseconds. + Weight::from_parts(31_140_040, 11003) + // Standard Error: 4_896 + .saturating_add(Weight::from_parts(69_348, 0).saturating_mul(r.into())) + // Standard Error: 955 + .saturating_add(Weight::from_parts(430_082, 0).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -110,11 +113,11 @@ impl WeightInfo for SubstrateWeight { fn set_subs_new(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `101` - // Estimated: `15746 + s * (2589 ±0)` - // Minimum execution time: 8_492 nanoseconds. - Weight::from_parts(21_645_924, 15746) - // Standard Error: 3_452 - .saturating_add(Weight::from_parts(2_442_604, 0).saturating_mul(s.into())) + // Estimated: `18716 + s * (2589 ±0)` + // Minimum execution time: 10_301_000 picoseconds. + Weight::from_parts(23_255_636, 18716) + // Standard Error: 5_562 + .saturating_add(Weight::from_parts(2_978_765, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(s.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) @@ -130,12 +133,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `p` is `[0, 100]`. fn set_subs_old(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `226 + p * (32 ±0)` - // Estimated: `15746` - // Minimum execution time: 8_488 nanoseconds. - Weight::from_parts(20_202_601, 15746) - // Standard Error: 2_834 - .saturating_add(Weight::from_parts(1_082_941, 0).saturating_mul(p.into())) + // Measured: `194 + p * (32 ±0)` + // Estimated: `17726` + // Minimum execution time: 10_095_000 picoseconds. + Weight::from_parts(23_197_533, 17726) + // Standard Error: 3_460 + .saturating_add(Weight::from_parts(1_227_498, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(p.into()))) @@ -149,18 +152,16 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[1, 20]`. /// The range of component `s` is `[0, 100]`. /// The range of component `x` is `[0, 100]`. - fn clear_identity(r: u32, s: u32, x: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `533 + r * (5 ±0) + s * (32 ±0) + x * (66 ±0)` - // Estimated: `15746` - // Minimum execution time: 41_319 nanoseconds. - Weight::from_parts(25_850_055, 15746) - // Standard Error: 4_144 - .saturating_add(Weight::from_parts(59_619, 0).saturating_mul(r.into())) - // Standard Error: 809 - .saturating_add(Weight::from_parts(1_076_550, 0).saturating_mul(s.into())) - // Standard Error: 809 - .saturating_add(Weight::from_parts(163_191, 0).saturating_mul(x.into())) + fn clear_identity(_r: u32, s: u32, x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `469 + r * (5 ±0) + s * (32 ±0) + x * (66 ±0)` + // Estimated: `17726` + // Minimum execution time: 51_054_000 picoseconds. + Weight::from_parts(30_184_047, 17726) + // Standard Error: 2_441 + .saturating_add(Weight::from_parts(1_221_983, 0).saturating_mul(s.into())) + // Standard Error: 2_441 + .saturating_add(Weight::from_parts(234_084, 0).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -173,14 +174,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `x` is `[0, 100]`. fn request_judgement(r: u32, x: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `431 + r * (57 ±0) + x * (66 ±0)` - // Estimated: `11649` - // Minimum execution time: 28_118 nanoseconds. - Weight::from_parts(27_359_471, 11649) - // Standard Error: 2_707 - .saturating_add(Weight::from_parts(107_279, 0).saturating_mul(r.into())) - // Standard Error: 528 - .saturating_add(Weight::from_parts(325_165, 0).saturating_mul(x.into())) + // Measured: `367 + r * (57 ±0) + x * (66 ±0)` + // Estimated: `13629` + // Minimum execution time: 32_747_000 picoseconds. + Weight::from_parts(29_557_659, 13629) + // Standard Error: 4_616 + .saturating_add(Weight::from_parts(200_494, 0).saturating_mul(r.into())) + // Standard Error: 900 + .saturating_add(Weight::from_parts(468_381, 0).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -190,14 +191,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `x` is `[0, 100]`. fn cancel_request(r: u32, x: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `430 + x * (66 ±0)` - // Estimated: `10013` - // Minimum execution time: 24_817 nanoseconds. - Weight::from_parts(24_749_808, 10013) - // Standard Error: 1_938 - .saturating_add(Weight::from_parts(63_396, 0).saturating_mul(r.into())) - // Standard Error: 378 - .saturating_add(Weight::from_parts(327_083, 0).saturating_mul(x.into())) + // Measured: `398 + x * (66 ±0)` + // Estimated: `11003` + // Minimum execution time: 28_853_000 picoseconds. + Weight::from_parts(26_811_119, 11003) + // Standard Error: 15_667 + .saturating_add(Weight::from_parts(240_647, 0).saturating_mul(r.into())) + // Standard Error: 3_056 + .saturating_add(Weight::from_parts(462_536, 0).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -206,12 +207,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[1, 19]`. fn set_fee(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `121 + r * (57 ±0)` - // Estimated: `1636` - // Minimum execution time: 6_664 nanoseconds. - Weight::from_parts(7_286_307, 1636) - // Standard Error: 1_560 - .saturating_add(Weight::from_parts(96_416, 0).saturating_mul(r.into())) + // Measured: `89 + r * (57 ±0)` + // Estimated: `2626` + // Minimum execution time: 8_413_000 picoseconds. + Weight::from_parts(8_846_436, 2626) + // Standard Error: 1_470 + .saturating_add(Weight::from_parts(113_780, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -220,12 +221,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[1, 19]`. fn set_account_id(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `121 + r * (57 ±0)` - // Estimated: `1636` - // Minimum execution time: 7_054 nanoseconds. - Weight::from_parts(7_382_954, 1636) - // Standard Error: 1_621 - .saturating_add(Weight::from_parts(101_595, 0).saturating_mul(r.into())) + // Measured: `89 + r * (57 ±0)` + // Estimated: `2626` + // Minimum execution time: 8_753_000 picoseconds. + Weight::from_parts(9_143_938, 2626) + // Standard Error: 1_490 + .saturating_add(Weight::from_parts(113_406, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -234,12 +235,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[1, 19]`. fn set_fields(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `121 + r * (57 ±0)` - // Estimated: `1636` - // Minimum execution time: 6_659 nanoseconds. - Weight::from_parts(7_188_883, 1636) - // Standard Error: 1_377 - .saturating_add(Weight::from_parts(98_965, 0).saturating_mul(r.into())) + // Measured: `89 + r * (57 ±0)` + // Estimated: `2626` + // Minimum execution time: 8_320_000 picoseconds. + Weight::from_parts(8_800_306, 2626) + // Standard Error: 1_345 + .saturating_add(Weight::from_parts(125_258, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -251,14 +252,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `x` is `[0, 100]`. fn provide_judgement(r: u32, x: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `509 + r * (57 ±0) + x * (66 ±0)` - // Estimated: `11649` - // Minimum execution time: 21_567 nanoseconds. - Weight::from_parts(21_015_310, 11649) - // Standard Error: 2_516 - .saturating_add(Weight::from_parts(123_992, 0).saturating_mul(r.into())) - // Standard Error: 465 - .saturating_add(Weight::from_parts(552_116, 0).saturating_mul(x.into())) + // Measured: `445 + r * (57 ±0) + x * (66 ±0)` + // Estimated: `13629` + // Minimum execution time: 25_313_000 picoseconds. + Weight::from_parts(23_968_548, 13629) + // Standard Error: 4_143 + .saturating_add(Weight::from_parts(164_678, 0).saturating_mul(r.into())) + // Standard Error: 766 + .saturating_add(Weight::from_parts(713_576, 0).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -275,16 +276,16 @@ impl WeightInfo for SubstrateWeight { /// The range of component `x` is `[0, 100]`. fn kill_identity(r: u32, s: u32, x: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `772 + r * (5 ±0) + s * (32 ±0) + x * (66 ±0)` - // Estimated: `18349` - // Minimum execution time: 52_881 nanoseconds. - Weight::from_parts(38_504_388, 18349) - // Standard Error: 3_909 - .saturating_add(Weight::from_parts(51_452, 0).saturating_mul(r.into())) - // Standard Error: 763 - .saturating_add(Weight::from_parts(1_069_924, 0).saturating_mul(s.into())) - // Standard Error: 763 - .saturating_add(Weight::from_parts(164_906, 0).saturating_mul(x.into())) + // Measured: `676 + r * (5 ±0) + s * (32 ±0) + x * (66 ±0)` + // Estimated: `21319` + // Minimum execution time: 64_638_000 picoseconds. + Weight::from_parts(43_317_654, 21319) + // Standard Error: 10_182 + .saturating_add(Weight::from_parts(61_967, 0).saturating_mul(r.into())) + // Standard Error: 1_988 + .saturating_add(Weight::from_parts(1_224_202, 0).saturating_mul(s.into())) + // Standard Error: 1_988 + .saturating_add(Weight::from_parts(233_897, 0).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -298,12 +299,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[0, 99]`. fn add_sub(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `507 + s * (36 ±0)` - // Estimated: `18335` - // Minimum execution time: 24_556 nanoseconds. - Weight::from_parts(28_641_160, 18335) - // Standard Error: 1_327 - .saturating_add(Weight::from_parts(66_150, 0).saturating_mul(s.into())) + // Measured: `475 + s * (36 ±0)` + // Estimated: `21305` + // Minimum execution time: 28_661_000 picoseconds. + Weight::from_parts(33_432_641, 21305) + // Standard Error: 1_547 + .saturating_add(Weight::from_parts(71_314, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -314,12 +315,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[1, 100]`. fn rename_sub(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `623 + s * (3 ±0)` - // Estimated: `12602` - // Minimum execution time: 11_347 nanoseconds. - Weight::from_parts(13_299_367, 12602) - // Standard Error: 525 - .saturating_add(Weight::from_parts(16_472, 0).saturating_mul(s.into())) + // Measured: `591 + s * (3 ±0)` + // Estimated: `14582` + // Minimum execution time: 13_885_000 picoseconds. + Weight::from_parts(16_105_165, 14582) + // Standard Error: 562 + .saturating_add(Weight::from_parts(17_087, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -332,12 +333,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[1, 100]`. fn remove_sub(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `702 + s * (35 ±0)` - // Estimated: `18335` - // Minimum execution time: 27_810 nanoseconds. - Weight::from_parts(30_347_763, 18335) - // Standard Error: 928 - .saturating_add(Weight::from_parts(55_342, 0).saturating_mul(s.into())) + // Measured: `638 + s * (35 ±0)` + // Estimated: `21305` + // Minimum execution time: 32_192_000 picoseconds. + Weight::from_parts(35_393_444, 21305) + // Standard Error: 2_198 + .saturating_add(Weight::from_parts(62_316, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -348,12 +349,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[0, 99]`. fn quit_sub(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `628 + s * (37 ±0)` - // Estimated: `8322` - // Minimum execution time: 17_601 nanoseconds. - Weight::from_parts(19_794_971, 8322) - // Standard Error: 934 - .saturating_add(Weight::from_parts(59_289, 0).saturating_mul(s.into())) + // Measured: `564 + s * (37 ±0)` + // Estimated: `10302` + // Minimum execution time: 20_803_000 picoseconds. + Weight::from_parts(23_462_393, 10302) + // Standard Error: 1_619 + .saturating_add(Weight::from_parts(59_938, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -366,12 +367,12 @@ impl WeightInfo for () { /// The range of component `r` is `[1, 19]`. fn add_registrar(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `64 + r * (57 ±0)` - // Estimated: `1636` - // Minimum execution time: 10_964 nanoseconds. - Weight::from_parts(11_800_935, 1636) - // Standard Error: 1_334 - .saturating_add(Weight::from_parts(96_038, 0).saturating_mul(r.into())) + // Measured: `32 + r * (57 ±0)` + // Estimated: `2626` + // Minimum execution time: 13_092_000 picoseconds. + Weight::from_parts(13_798_719, 2626) + // Standard Error: 1_553 + .saturating_add(Weight::from_parts(109_215, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -381,14 +382,14 @@ impl WeightInfo for () { /// The range of component `x` is `[0, 100]`. fn set_identity(r: u32, x: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `474 + r * (5 ±0)` - // Estimated: `10013` - // Minimum execution time: 26_400 nanoseconds. - Weight::from_parts(26_060_549, 10013) - // Standard Error: 1_561 - .saturating_add(Weight::from_parts(72_083, 0).saturating_mul(r.into())) - // Standard Error: 304 - .saturating_add(Weight::from_parts(306_994, 0).saturating_mul(x.into())) + // Measured: `442 + r * (5 ±0)` + // Estimated: `11003` + // Minimum execution time: 30_800_000 picoseconds. + Weight::from_parts(31_140_040, 11003) + // Standard Error: 4_896 + .saturating_add(Weight::from_parts(69_348, 0).saturating_mul(r.into())) + // Standard Error: 955 + .saturating_add(Weight::from_parts(430_082, 0).saturating_mul(x.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -402,11 +403,11 @@ impl WeightInfo for () { fn set_subs_new(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `101` - // Estimated: `15746 + s * (2589 ±0)` - // Minimum execution time: 8_492 nanoseconds. - Weight::from_parts(21_645_924, 15746) - // Standard Error: 3_452 - .saturating_add(Weight::from_parts(2_442_604, 0).saturating_mul(s.into())) + // Estimated: `18716 + s * (2589 ±0)` + // Minimum execution time: 10_301_000 picoseconds. + Weight::from_parts(23_255_636, 18716) + // Standard Error: 5_562 + .saturating_add(Weight::from_parts(2_978_765, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(s.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) @@ -422,12 +423,12 @@ impl WeightInfo for () { /// The range of component `p` is `[0, 100]`. fn set_subs_old(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `226 + p * (32 ±0)` - // Estimated: `15746` - // Minimum execution time: 8_488 nanoseconds. - Weight::from_parts(20_202_601, 15746) - // Standard Error: 2_834 - .saturating_add(Weight::from_parts(1_082_941, 0).saturating_mul(p.into())) + // Measured: `194 + p * (32 ±0)` + // Estimated: `17726` + // Minimum execution time: 10_095_000 picoseconds. + Weight::from_parts(23_197_533, 17726) + // Standard Error: 3_460 + .saturating_add(Weight::from_parts(1_227_498, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(p.into()))) @@ -441,18 +442,16 @@ impl WeightInfo for () { /// The range of component `r` is `[1, 20]`. /// The range of component `s` is `[0, 100]`. /// The range of component `x` is `[0, 100]`. - fn clear_identity(r: u32, s: u32, x: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `533 + r * (5 ±0) + s * (32 ±0) + x * (66 ±0)` - // Estimated: `15746` - // Minimum execution time: 41_319 nanoseconds. - Weight::from_parts(25_850_055, 15746) - // Standard Error: 4_144 - .saturating_add(Weight::from_parts(59_619, 0).saturating_mul(r.into())) - // Standard Error: 809 - .saturating_add(Weight::from_parts(1_076_550, 0).saturating_mul(s.into())) - // Standard Error: 809 - .saturating_add(Weight::from_parts(163_191, 0).saturating_mul(x.into())) + fn clear_identity(_r: u32, s: u32, x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `469 + r * (5 ±0) + s * (32 ±0) + x * (66 ±0)` + // Estimated: `17726` + // Minimum execution time: 51_054_000 picoseconds. + Weight::from_parts(30_184_047, 17726) + // Standard Error: 2_441 + .saturating_add(Weight::from_parts(1_221_983, 0).saturating_mul(s.into())) + // Standard Error: 2_441 + .saturating_add(Weight::from_parts(234_084, 0).saturating_mul(x.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -465,14 +464,14 @@ impl WeightInfo for () { /// The range of component `x` is `[0, 100]`. fn request_judgement(r: u32, x: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `431 + r * (57 ±0) + x * (66 ±0)` - // Estimated: `11649` - // Minimum execution time: 28_118 nanoseconds. - Weight::from_parts(27_359_471, 11649) - // Standard Error: 2_707 - .saturating_add(Weight::from_parts(107_279, 0).saturating_mul(r.into())) - // Standard Error: 528 - .saturating_add(Weight::from_parts(325_165, 0).saturating_mul(x.into())) + // Measured: `367 + r * (57 ±0) + x * (66 ±0)` + // Estimated: `13629` + // Minimum execution time: 32_747_000 picoseconds. + Weight::from_parts(29_557_659, 13629) + // Standard Error: 4_616 + .saturating_add(Weight::from_parts(200_494, 0).saturating_mul(r.into())) + // Standard Error: 900 + .saturating_add(Weight::from_parts(468_381, 0).saturating_mul(x.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -482,14 +481,14 @@ impl WeightInfo for () { /// The range of component `x` is `[0, 100]`. fn cancel_request(r: u32, x: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `430 + x * (66 ±0)` - // Estimated: `10013` - // Minimum execution time: 24_817 nanoseconds. - Weight::from_parts(24_749_808, 10013) - // Standard Error: 1_938 - .saturating_add(Weight::from_parts(63_396, 0).saturating_mul(r.into())) - // Standard Error: 378 - .saturating_add(Weight::from_parts(327_083, 0).saturating_mul(x.into())) + // Measured: `398 + x * (66 ±0)` + // Estimated: `11003` + // Minimum execution time: 28_853_000 picoseconds. + Weight::from_parts(26_811_119, 11003) + // Standard Error: 15_667 + .saturating_add(Weight::from_parts(240_647, 0).saturating_mul(r.into())) + // Standard Error: 3_056 + .saturating_add(Weight::from_parts(462_536, 0).saturating_mul(x.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -498,12 +497,12 @@ impl WeightInfo for () { /// The range of component `r` is `[1, 19]`. fn set_fee(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `121 + r * (57 ±0)` - // Estimated: `1636` - // Minimum execution time: 6_664 nanoseconds. - Weight::from_parts(7_286_307, 1636) - // Standard Error: 1_560 - .saturating_add(Weight::from_parts(96_416, 0).saturating_mul(r.into())) + // Measured: `89 + r * (57 ±0)` + // Estimated: `2626` + // Minimum execution time: 8_413_000 picoseconds. + Weight::from_parts(8_846_436, 2626) + // Standard Error: 1_470 + .saturating_add(Weight::from_parts(113_780, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -512,12 +511,12 @@ impl WeightInfo for () { /// The range of component `r` is `[1, 19]`. fn set_account_id(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `121 + r * (57 ±0)` - // Estimated: `1636` - // Minimum execution time: 7_054 nanoseconds. - Weight::from_parts(7_382_954, 1636) - // Standard Error: 1_621 - .saturating_add(Weight::from_parts(101_595, 0).saturating_mul(r.into())) + // Measured: `89 + r * (57 ±0)` + // Estimated: `2626` + // Minimum execution time: 8_753_000 picoseconds. + Weight::from_parts(9_143_938, 2626) + // Standard Error: 1_490 + .saturating_add(Weight::from_parts(113_406, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -526,12 +525,12 @@ impl WeightInfo for () { /// The range of component `r` is `[1, 19]`. fn set_fields(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `121 + r * (57 ±0)` - // Estimated: `1636` - // Minimum execution time: 6_659 nanoseconds. - Weight::from_parts(7_188_883, 1636) - // Standard Error: 1_377 - .saturating_add(Weight::from_parts(98_965, 0).saturating_mul(r.into())) + // Measured: `89 + r * (57 ±0)` + // Estimated: `2626` + // Minimum execution time: 8_320_000 picoseconds. + Weight::from_parts(8_800_306, 2626) + // Standard Error: 1_345 + .saturating_add(Weight::from_parts(125_258, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -543,14 +542,14 @@ impl WeightInfo for () { /// The range of component `x` is `[0, 100]`. fn provide_judgement(r: u32, x: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `509 + r * (57 ±0) + x * (66 ±0)` - // Estimated: `11649` - // Minimum execution time: 21_567 nanoseconds. - Weight::from_parts(21_015_310, 11649) - // Standard Error: 2_516 - .saturating_add(Weight::from_parts(123_992, 0).saturating_mul(r.into())) - // Standard Error: 465 - .saturating_add(Weight::from_parts(552_116, 0).saturating_mul(x.into())) + // Measured: `445 + r * (57 ±0) + x * (66 ±0)` + // Estimated: `13629` + // Minimum execution time: 25_313_000 picoseconds. + Weight::from_parts(23_968_548, 13629) + // Standard Error: 4_143 + .saturating_add(Weight::from_parts(164_678, 0).saturating_mul(r.into())) + // Standard Error: 766 + .saturating_add(Weight::from_parts(713_576, 0).saturating_mul(x.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -567,16 +566,16 @@ impl WeightInfo for () { /// The range of component `x` is `[0, 100]`. fn kill_identity(r: u32, s: u32, x: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `772 + r * (5 ±0) + s * (32 ±0) + x * (66 ±0)` - // Estimated: `18349` - // Minimum execution time: 52_881 nanoseconds. - Weight::from_parts(38_504_388, 18349) - // Standard Error: 3_909 - .saturating_add(Weight::from_parts(51_452, 0).saturating_mul(r.into())) - // Standard Error: 763 - .saturating_add(Weight::from_parts(1_069_924, 0).saturating_mul(s.into())) - // Standard Error: 763 - .saturating_add(Weight::from_parts(164_906, 0).saturating_mul(x.into())) + // Measured: `676 + r * (5 ±0) + s * (32 ±0) + x * (66 ±0)` + // Estimated: `21319` + // Minimum execution time: 64_638_000 picoseconds. + Weight::from_parts(43_317_654, 21319) + // Standard Error: 10_182 + .saturating_add(Weight::from_parts(61_967, 0).saturating_mul(r.into())) + // Standard Error: 1_988 + .saturating_add(Weight::from_parts(1_224_202, 0).saturating_mul(s.into())) + // Standard Error: 1_988 + .saturating_add(Weight::from_parts(233_897, 0).saturating_mul(x.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -590,12 +589,12 @@ impl WeightInfo for () { /// The range of component `s` is `[0, 99]`. fn add_sub(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `507 + s * (36 ±0)` - // Estimated: `18335` - // Minimum execution time: 24_556 nanoseconds. - Weight::from_parts(28_641_160, 18335) - // Standard Error: 1_327 - .saturating_add(Weight::from_parts(66_150, 0).saturating_mul(s.into())) + // Measured: `475 + s * (36 ±0)` + // Estimated: `21305` + // Minimum execution time: 28_661_000 picoseconds. + Weight::from_parts(33_432_641, 21305) + // Standard Error: 1_547 + .saturating_add(Weight::from_parts(71_314, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -606,12 +605,12 @@ impl WeightInfo for () { /// The range of component `s` is `[1, 100]`. fn rename_sub(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `623 + s * (3 ±0)` - // Estimated: `12602` - // Minimum execution time: 11_347 nanoseconds. - Weight::from_parts(13_299_367, 12602) - // Standard Error: 525 - .saturating_add(Weight::from_parts(16_472, 0).saturating_mul(s.into())) + // Measured: `591 + s * (3 ±0)` + // Estimated: `14582` + // Minimum execution time: 13_885_000 picoseconds. + Weight::from_parts(16_105_165, 14582) + // Standard Error: 562 + .saturating_add(Weight::from_parts(17_087, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -624,12 +623,12 @@ impl WeightInfo for () { /// The range of component `s` is `[1, 100]`. fn remove_sub(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `702 + s * (35 ±0)` - // Estimated: `18335` - // Minimum execution time: 27_810 nanoseconds. - Weight::from_parts(30_347_763, 18335) - // Standard Error: 928 - .saturating_add(Weight::from_parts(55_342, 0).saturating_mul(s.into())) + // Measured: `638 + s * (35 ±0)` + // Estimated: `21305` + // Minimum execution time: 32_192_000 picoseconds. + Weight::from_parts(35_393_444, 21305) + // Standard Error: 2_198 + .saturating_add(Weight::from_parts(62_316, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -640,12 +639,12 @@ impl WeightInfo for () { /// The range of component `s` is `[0, 99]`. fn quit_sub(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `628 + s * (37 ±0)` - // Estimated: `8322` - // Minimum execution time: 17_601 nanoseconds. - Weight::from_parts(19_794_971, 8322) - // Standard Error: 934 - .saturating_add(Weight::from_parts(59_289, 0).saturating_mul(s.into())) + // Measured: `564 + s * (37 ±0)` + // Estimated: `10302` + // Minimum execution time: 20_803_000 picoseconds. + Weight::from_parts(23_462_393, 10302) + // Standard Error: 1_619 + .saturating_add(Weight::from_parts(59_938, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } diff --git a/frame/im-online/src/weights.rs b/frame/im-online/src/weights.rs index 675feb075473f..f97df1c367562 100644 --- a/frame/im-online/src/weights.rs +++ b/frame/im-online/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_im_online //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,6 +31,9 @@ // --steps=50 // --repeat=20 // --pallet=pallet_im_online +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -68,17 +71,17 @@ impl WeightInfo for SubstrateWeight { /// The range of component `e` is `[1, 100]`. fn validate_unsigned_and_then_heartbeat(k: u32, e: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `359 + k * (32 ±0)` - // Estimated: `10345712 + e * (25 ±0) + k * (64 ±0)` - // Minimum execution time: 91_116 nanoseconds. - Weight::from_parts(72_526_877, 10345712) - // Standard Error: 95 - .saturating_add(Weight::from_parts(20_461, 0).saturating_mul(k.into())) - // Standard Error: 967 - .saturating_add(Weight::from_parts(307_869, 0).saturating_mul(e.into())) + // Measured: `295 + k * (32 ±0)` + // Estimated: `10349544 + e * (35 ±0) + k * (64 ±0)` + // Minimum execution time: 106_224_000 picoseconds. + Weight::from_parts(79_172_319, 10349544) + // Standard Error: 259 + .saturating_add(Weight::from_parts(29_576, 0).saturating_mul(k.into())) + // Standard Error: 2_611 + .saturating_add(Weight::from_parts(422_369, 0).saturating_mul(e.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) - .saturating_add(Weight::from_parts(0, 25).saturating_mul(e.into())) + .saturating_add(Weight::from_parts(0, 35).saturating_mul(e.into())) .saturating_add(Weight::from_parts(0, 64).saturating_mul(k.into())) } } @@ -99,17 +102,17 @@ impl WeightInfo for () { /// The range of component `e` is `[1, 100]`. fn validate_unsigned_and_then_heartbeat(k: u32, e: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `359 + k * (32 ±0)` - // Estimated: `10345712 + e * (25 ±0) + k * (64 ±0)` - // Minimum execution time: 91_116 nanoseconds. - Weight::from_parts(72_526_877, 10345712) - // Standard Error: 95 - .saturating_add(Weight::from_parts(20_461, 0).saturating_mul(k.into())) - // Standard Error: 967 - .saturating_add(Weight::from_parts(307_869, 0).saturating_mul(e.into())) + // Measured: `295 + k * (32 ±0)` + // Estimated: `10349544 + e * (35 ±0) + k * (64 ±0)` + // Minimum execution time: 106_224_000 picoseconds. + Weight::from_parts(79_172_319, 10349544) + // Standard Error: 259 + .saturating_add(Weight::from_parts(29_576, 0).saturating_mul(k.into())) + // Standard Error: 2_611 + .saturating_add(Weight::from_parts(422_369, 0).saturating_mul(e.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) - .saturating_add(Weight::from_parts(0, 25).saturating_mul(e.into())) + .saturating_add(Weight::from_parts(0, 35).saturating_mul(e.into())) .saturating_add(Weight::from_parts(0, 64).saturating_mul(k.into())) } } diff --git a/frame/indices/src/weights.rs b/frame/indices/src/weights.rs index fcb71177a5951..87160ccfbb208 100644 --- a/frame/indices/src/weights.rs +++ b/frame/indices/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_indices //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,6 +31,9 @@ // --steps=50 // --repeat=20 // --pallet=pallet_indices +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -63,9 +66,9 @@ impl WeightInfo for SubstrateWeight { fn claim() -> Weight { // Proof Size summary in bytes: // Measured: `76` - // Estimated: `2544` - // Minimum execution time: 19_738 nanoseconds. - Weight::from_parts(20_029_000, 2544) + // Estimated: `3534` + // Minimum execution time: 22_365_000 picoseconds. + Weight::from_parts(22_713_000, 3534) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -75,10 +78,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `339` - // Estimated: `5147` - // Minimum execution time: 24_494 nanoseconds. - Weight::from_parts(24_794_000, 5147) + // Measured: `275` + // Estimated: `7127` + // Minimum execution time: 28_380_000 picoseconds. + Weight::from_parts(29_251_000, 7127) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -86,10 +89,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Indices Accounts (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) fn free() -> Weight { // Proof Size summary in bytes: - // Measured: `204` - // Estimated: `2544` - // Minimum execution time: 20_041 nanoseconds. - Weight::from_parts(20_473_000, 2544) + // Measured: `172` + // Estimated: `3534` + // Minimum execution time: 22_932_000 picoseconds. + Weight::from_parts(23_442_000, 3534) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -99,10 +102,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn force_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `339` - // Estimated: `5147` - // Minimum execution time: 21_874 nanoseconds. - Weight::from_parts(22_438_000, 5147) + // Measured: `275` + // Estimated: `7127` + // Minimum execution time: 25_223_000 picoseconds. + Weight::from_parts(25_519_000, 7127) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -110,10 +113,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Indices Accounts (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) fn freeze() -> Weight { // Proof Size summary in bytes: - // Measured: `204` - // Estimated: `2544` - // Minimum execution time: 22_407 nanoseconds. - Weight::from_parts(22_768_000, 2544) + // Measured: `172` + // Estimated: `3534` + // Minimum execution time: 25_223_000 picoseconds. + Weight::from_parts(26_127_000, 3534) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -126,9 +129,9 @@ impl WeightInfo for () { fn claim() -> Weight { // Proof Size summary in bytes: // Measured: `76` - // Estimated: `2544` - // Minimum execution time: 19_738 nanoseconds. - Weight::from_parts(20_029_000, 2544) + // Estimated: `3534` + // Minimum execution time: 22_365_000 picoseconds. + Weight::from_parts(22_713_000, 3534) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -138,10 +141,10 @@ impl WeightInfo for () { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `339` - // Estimated: `5147` - // Minimum execution time: 24_494 nanoseconds. - Weight::from_parts(24_794_000, 5147) + // Measured: `275` + // Estimated: `7127` + // Minimum execution time: 28_380_000 picoseconds. + Weight::from_parts(29_251_000, 7127) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -149,10 +152,10 @@ impl WeightInfo for () { /// Proof: Indices Accounts (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) fn free() -> Weight { // Proof Size summary in bytes: - // Measured: `204` - // Estimated: `2544` - // Minimum execution time: 20_041 nanoseconds. - Weight::from_parts(20_473_000, 2544) + // Measured: `172` + // Estimated: `3534` + // Minimum execution time: 22_932_000 picoseconds. + Weight::from_parts(23_442_000, 3534) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -162,10 +165,10 @@ impl WeightInfo for () { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn force_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `339` - // Estimated: `5147` - // Minimum execution time: 21_874 nanoseconds. - Weight::from_parts(22_438_000, 5147) + // Measured: `275` + // Estimated: `7127` + // Minimum execution time: 25_223_000 picoseconds. + Weight::from_parts(25_519_000, 7127) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -173,10 +176,10 @@ impl WeightInfo for () { /// Proof: Indices Accounts (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) fn freeze() -> Weight { // Proof Size summary in bytes: - // Measured: `204` - // Estimated: `2544` - // Minimum execution time: 22_407 nanoseconds. - Weight::from_parts(22_768_000, 2544) + // Measured: `172` + // Estimated: `3534` + // Minimum execution time: 25_223_000 picoseconds. + Weight::from_parts(26_127_000, 3534) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/frame/lottery/src/weights.rs b/frame/lottery/src/weights.rs index 0038db6210d2b..c8c373ad6f88d 100644 --- a/frame/lottery/src/weights.rs +++ b/frame/lottery/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_lottery //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,6 +31,9 @@ // --steps=50 // --repeat=20 // --pallet=pallet_lottery +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -75,10 +78,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Lottery Tickets (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) fn buy_ticket() -> Weight { // Proof Size summary in bytes: - // Measured: `484` - // Estimated: `7181` - // Minimum execution time: 62_125 nanoseconds. - Weight::from_parts(63_145_000, 7181) + // Measured: `452` + // Estimated: `13121` + // Minimum execution time: 43_076_000 picoseconds. + Weight::from_parts(43_902_000, 13121) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -89,10 +92,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_650 nanoseconds. - Weight::from_parts(8_344_960, 0) - // Standard Error: 2_629 - .saturating_add(Weight::from_parts(268_557, 0).saturating_mul(n.into())) + // Minimum execution time: 8_222_000 picoseconds. + Weight::from_parts(9_166_238, 0) + // Standard Error: 3_489 + .saturating_add(Weight::from_parts(328_564, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Lottery Lottery (r:1 w:1) @@ -104,9 +107,9 @@ impl WeightInfo for SubstrateWeight { fn start_lottery() -> Weight { // Proof Size summary in bytes: // Measured: `161` - // Estimated: `3626` - // Minimum execution time: 31_324 nanoseconds. - Weight::from_parts(31_985_000, 3626) + // Estimated: `6596` + // Minimum execution time: 36_555_000 picoseconds. + Weight::from_parts(37_008_000, 6596) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -115,9 +118,9 @@ impl WeightInfo for SubstrateWeight { fn stop_repeat() -> Weight { // Proof Size summary in bytes: // Measured: `219` - // Estimated: `524` - // Minimum execution time: 7_124 nanoseconds. - Weight::from_parts(7_285_000, 524) + // Estimated: `1514` + // Minimum execution time: 8_230_000 picoseconds. + Weight::from_parts(8_355_000, 1514) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -133,10 +136,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Lottery Tickets (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) fn on_initialize_end() -> Weight { // Proof Size summary in bytes: - // Measured: `556` - // Estimated: `11837` - // Minimum execution time: 50_745 nanoseconds. - Weight::from_parts(52_232_000, 11837) + // Measured: `524` + // Estimated: `16787` + // Minimum execution time: 60_097_000 picoseconds. + Weight::from_parts(62_055_000, 16787) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -154,10 +157,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Lottery LotteryIndex (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn on_initialize_repeat() -> Weight { // Proof Size summary in bytes: - // Measured: `556` - // Estimated: `12336` - // Minimum execution time: 52_437 nanoseconds. - Weight::from_parts(53_063_000, 12336) + // Measured: `524` + // Estimated: `18276` + // Minimum execution time: 61_354_000 picoseconds. + Weight::from_parts(62_429_000, 18276) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -181,10 +184,10 @@ impl WeightInfo for () { /// Proof: Lottery Tickets (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) fn buy_ticket() -> Weight { // Proof Size summary in bytes: - // Measured: `484` - // Estimated: `7181` - // Minimum execution time: 62_125 nanoseconds. - Weight::from_parts(63_145_000, 7181) + // Measured: `452` + // Estimated: `13121` + // Minimum execution time: 43_076_000 picoseconds. + Weight::from_parts(43_902_000, 13121) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -195,10 +198,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_650 nanoseconds. - Weight::from_parts(8_344_960, 0) - // Standard Error: 2_629 - .saturating_add(Weight::from_parts(268_557, 0).saturating_mul(n.into())) + // Minimum execution time: 8_222_000 picoseconds. + Weight::from_parts(9_166_238, 0) + // Standard Error: 3_489 + .saturating_add(Weight::from_parts(328_564, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Lottery Lottery (r:1 w:1) @@ -210,9 +213,9 @@ impl WeightInfo for () { fn start_lottery() -> Weight { // Proof Size summary in bytes: // Measured: `161` - // Estimated: `3626` - // Minimum execution time: 31_324 nanoseconds. - Weight::from_parts(31_985_000, 3626) + // Estimated: `6596` + // Minimum execution time: 36_555_000 picoseconds. + Weight::from_parts(37_008_000, 6596) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -221,9 +224,9 @@ impl WeightInfo for () { fn stop_repeat() -> Weight { // Proof Size summary in bytes: // Measured: `219` - // Estimated: `524` - // Minimum execution time: 7_124 nanoseconds. - Weight::from_parts(7_285_000, 524) + // Estimated: `1514` + // Minimum execution time: 8_230_000 picoseconds. + Weight::from_parts(8_355_000, 1514) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -239,10 +242,10 @@ impl WeightInfo for () { /// Proof: Lottery Tickets (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) fn on_initialize_end() -> Weight { // Proof Size summary in bytes: - // Measured: `556` - // Estimated: `11837` - // Minimum execution time: 50_745 nanoseconds. - Weight::from_parts(52_232_000, 11837) + // Measured: `524` + // Estimated: `16787` + // Minimum execution time: 60_097_000 picoseconds. + Weight::from_parts(62_055_000, 16787) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -260,10 +263,10 @@ impl WeightInfo for () { /// Proof: Lottery LotteryIndex (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn on_initialize_repeat() -> Weight { // Proof Size summary in bytes: - // Measured: `556` - // Estimated: `12336` - // Minimum execution time: 52_437 nanoseconds. - Weight::from_parts(53_063_000, 12336) + // Measured: `524` + // Estimated: `18276` + // Minimum execution time: 61_354_000 picoseconds. + Weight::from_parts(62_429_000, 18276) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } diff --git a/frame/membership/src/weights.rs b/frame/membership/src/weights.rs index f080f842c54b4..31c359b4469eb 100644 --- a/frame/membership/src/weights.rs +++ b/frame/membership/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_membership //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,6 +31,9 @@ // --steps=50 // --repeat=20 // --pallet=pallet_membership +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -71,12 +74,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `m` is `[1, 99]`. fn add_member(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `238 + m * (64 ±0)` - // Estimated: `4903 + m * (192 ±0)` - // Minimum execution time: 15_673 nanoseconds. - Weight::from_parts(16_830_288, 4903) - // Standard Error: 570 - .saturating_add(Weight::from_parts(41_959, 0).saturating_mul(m.into())) + // Measured: `174 + m * (64 ±0)` + // Estimated: `6691 + m * (192 ±0)` + // Minimum execution time: 17_587_000 picoseconds. + Weight::from_parts(18_658_163, 6691) + // Standard Error: 710 + .saturating_add(Weight::from_parts(46_294, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 192).saturating_mul(m.into())) @@ -94,12 +97,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `m` is `[2, 100]`. fn remove_member(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `342 + m * (64 ±0)` - // Estimated: `5742 + m * (192 ±0)` - // Minimum execution time: 18_231 nanoseconds. - Weight::from_parts(19_081_297, 5742) - // Standard Error: 571 - .saturating_add(Weight::from_parts(41_331, 0).saturating_mul(m.into())) + // Measured: `278 + m * (64 ±0)` + // Estimated: `8520 + m * (192 ±0)` + // Minimum execution time: 20_402_000 picoseconds. + Weight::from_parts(21_165_819, 8520) + // Standard Error: 643 + .saturating_add(Weight::from_parts(45_481, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 192).saturating_mul(m.into())) @@ -117,12 +120,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `m` is `[2, 100]`. fn swap_member(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `342 + m * (64 ±0)` - // Estimated: `5742 + m * (192 ±0)` - // Minimum execution time: 18_517 nanoseconds. - Weight::from_parts(19_388_310, 5742) - // Standard Error: 625 - .saturating_add(Weight::from_parts(51_422, 0).saturating_mul(m.into())) + // Measured: `278 + m * (64 ±0)` + // Estimated: `8520 + m * (192 ±0)` + // Minimum execution time: 20_380_000 picoseconds. + Weight::from_parts(21_633_260, 8520) + // Standard Error: 770 + .saturating_add(Weight::from_parts(55_504, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 192).saturating_mul(m.into())) @@ -140,12 +143,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `m` is `[1, 100]`. fn reset_member(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `342 + m * (64 ±0)` - // Estimated: `5742 + m * (192 ±0)` - // Minimum execution time: 17_628 nanoseconds. - Weight::from_parts(19_258_882, 5742) - // Standard Error: 820 - .saturating_add(Weight::from_parts(153_956, 0).saturating_mul(m.into())) + // Measured: `278 + m * (64 ±0)` + // Estimated: `8520 + m * (192 ±0)` + // Minimum execution time: 19_989_000 picoseconds. + Weight::from_parts(22_352_059, 8520) + // Standard Error: 2_878 + .saturating_add(Weight::from_parts(156_367, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 192).saturating_mul(m.into())) @@ -163,12 +166,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `m` is `[1, 100]`. fn change_key(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `342 + m * (64 ±0)` - // Estimated: `5742 + m * (192 ±0)` - // Minimum execution time: 19_031 nanoseconds. - Weight::from_parts(20_264_948, 5742) - // Standard Error: 707 - .saturating_add(Weight::from_parts(51_060, 0).saturating_mul(m.into())) + // Measured: `278 + m * (64 ±0)` + // Estimated: `8520 + m * (192 ±0)` + // Minimum execution time: 21_275_000 picoseconds. + Weight::from_parts(23_344_594, 8520) + // Standard Error: 2_750 + .saturating_add(Weight::from_parts(46_736, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 192).saturating_mul(m.into())) @@ -182,12 +185,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `m` is `[1, 100]`. fn set_prime(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `64 + m * (32 ±0)` - // Estimated: `3761 + m * (32 ±0)` - // Minimum execution time: 6_897 nanoseconds. - Weight::from_parts(7_455_387, 3761) - // Standard Error: 326 - .saturating_add(Weight::from_parts(16_653, 0).saturating_mul(m.into())) + // Measured: `32 + m * (32 ±0)` + // Estimated: `4719 + m * (32 ±0)` + // Minimum execution time: 8_087_000 picoseconds. + Weight::from_parts(8_909_627, 4719) + // Standard Error: 1_572 + .saturating_add(Weight::from_parts(17_186, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(Weight::from_parts(0, 32).saturating_mul(m.into())) @@ -201,10 +204,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_400 nanoseconds. - Weight::from_parts(3_703_421, 0) - // Standard Error: 119 - .saturating_add(Weight::from_parts(915, 0).saturating_mul(m.into())) + // Minimum execution time: 3_752_000 picoseconds. + Weight::from_parts(4_081_144, 0) + // Standard Error: 229 + .saturating_add(Weight::from_parts(1_298, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().writes(2_u64)) } } @@ -222,12 +225,12 @@ impl WeightInfo for () { /// The range of component `m` is `[1, 99]`. fn add_member(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `238 + m * (64 ±0)` - // Estimated: `4903 + m * (192 ±0)` - // Minimum execution time: 15_673 nanoseconds. - Weight::from_parts(16_830_288, 4903) - // Standard Error: 570 - .saturating_add(Weight::from_parts(41_959, 0).saturating_mul(m.into())) + // Measured: `174 + m * (64 ±0)` + // Estimated: `6691 + m * (192 ±0)` + // Minimum execution time: 17_587_000 picoseconds. + Weight::from_parts(18_658_163, 6691) + // Standard Error: 710 + .saturating_add(Weight::from_parts(46_294, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 192).saturating_mul(m.into())) @@ -245,12 +248,12 @@ impl WeightInfo for () { /// The range of component `m` is `[2, 100]`. fn remove_member(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `342 + m * (64 ±0)` - // Estimated: `5742 + m * (192 ±0)` - // Minimum execution time: 18_231 nanoseconds. - Weight::from_parts(19_081_297, 5742) - // Standard Error: 571 - .saturating_add(Weight::from_parts(41_331, 0).saturating_mul(m.into())) + // Measured: `278 + m * (64 ±0)` + // Estimated: `8520 + m * (192 ±0)` + // Minimum execution time: 20_402_000 picoseconds. + Weight::from_parts(21_165_819, 8520) + // Standard Error: 643 + .saturating_add(Weight::from_parts(45_481, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 192).saturating_mul(m.into())) @@ -268,12 +271,12 @@ impl WeightInfo for () { /// The range of component `m` is `[2, 100]`. fn swap_member(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `342 + m * (64 ±0)` - // Estimated: `5742 + m * (192 ±0)` - // Minimum execution time: 18_517 nanoseconds. - Weight::from_parts(19_388_310, 5742) - // Standard Error: 625 - .saturating_add(Weight::from_parts(51_422, 0).saturating_mul(m.into())) + // Measured: `278 + m * (64 ±0)` + // Estimated: `8520 + m * (192 ±0)` + // Minimum execution time: 20_380_000 picoseconds. + Weight::from_parts(21_633_260, 8520) + // Standard Error: 770 + .saturating_add(Weight::from_parts(55_504, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 192).saturating_mul(m.into())) @@ -291,12 +294,12 @@ impl WeightInfo for () { /// The range of component `m` is `[1, 100]`. fn reset_member(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `342 + m * (64 ±0)` - // Estimated: `5742 + m * (192 ±0)` - // Minimum execution time: 17_628 nanoseconds. - Weight::from_parts(19_258_882, 5742) - // Standard Error: 820 - .saturating_add(Weight::from_parts(153_956, 0).saturating_mul(m.into())) + // Measured: `278 + m * (64 ±0)` + // Estimated: `8520 + m * (192 ±0)` + // Minimum execution time: 19_989_000 picoseconds. + Weight::from_parts(22_352_059, 8520) + // Standard Error: 2_878 + .saturating_add(Weight::from_parts(156_367, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 192).saturating_mul(m.into())) @@ -314,12 +317,12 @@ impl WeightInfo for () { /// The range of component `m` is `[1, 100]`. fn change_key(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `342 + m * (64 ±0)` - // Estimated: `5742 + m * (192 ±0)` - // Minimum execution time: 19_031 nanoseconds. - Weight::from_parts(20_264_948, 5742) - // Standard Error: 707 - .saturating_add(Weight::from_parts(51_060, 0).saturating_mul(m.into())) + // Measured: `278 + m * (64 ±0)` + // Estimated: `8520 + m * (192 ±0)` + // Minimum execution time: 21_275_000 picoseconds. + Weight::from_parts(23_344_594, 8520) + // Standard Error: 2_750 + .saturating_add(Weight::from_parts(46_736, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 192).saturating_mul(m.into())) @@ -333,12 +336,12 @@ impl WeightInfo for () { /// The range of component `m` is `[1, 100]`. fn set_prime(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `64 + m * (32 ±0)` - // Estimated: `3761 + m * (32 ±0)` - // Minimum execution time: 6_897 nanoseconds. - Weight::from_parts(7_455_387, 3761) - // Standard Error: 326 - .saturating_add(Weight::from_parts(16_653, 0).saturating_mul(m.into())) + // Measured: `32 + m * (32 ±0)` + // Estimated: `4719 + m * (32 ±0)` + // Minimum execution time: 8_087_000 picoseconds. + Weight::from_parts(8_909_627, 4719) + // Standard Error: 1_572 + .saturating_add(Weight::from_parts(17_186, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(Weight::from_parts(0, 32).saturating_mul(m.into())) @@ -352,10 +355,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_400 nanoseconds. - Weight::from_parts(3_703_421, 0) - // Standard Error: 119 - .saturating_add(Weight::from_parts(915, 0).saturating_mul(m.into())) + // Minimum execution time: 3_752_000 picoseconds. + Weight::from_parts(4_081_144, 0) + // Standard Error: 229 + .saturating_add(Weight::from_parts(1_298, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().writes(2_u64)) } } diff --git a/frame/message-queue/src/weights.rs b/frame/message-queue/src/weights.rs index fd788f2ba4052..fc44456db28bd 100644 --- a/frame/message-queue/src/weights.rs +++ b/frame/message-queue/src/weights.rs @@ -18,26 +18,28 @@ //! Autogenerated weights for pallet_message_queue //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/production/substrate +// ./target/production/substrate // benchmark // pallet +// --chain=dev // --steps=50 // --repeat=20 +// --pallet=pallet_message_queue +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --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 +// --header=./HEADER-APACHE2 // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -70,10 +72,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) fn ready_ring_knit() -> Weight { // Proof Size summary in bytes: - // Measured: `295` + // Measured: `233` // Estimated: `7527` - // Minimum execution time: 12_283_000 picoseconds. - Weight::from_parts(12_554_000, 7527) + // Minimum execution time: 12_561_000 picoseconds. + Weight::from_parts(12_758_000, 7527) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -83,10 +85,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn ready_ring_unknit() -> Weight { // Proof Size summary in bytes: - // Measured: `295` + // Measured: `233` // Estimated: `7527` - // Minimum execution time: 11_484_000 picoseconds. - Weight::from_parts(11_900_000, 7527) + // Minimum execution time: 11_854_000 picoseconds. + Weight::from_parts(12_178_000, 7527) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -96,8 +98,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `42` // Estimated: `3514` - // Minimum execution time: 4_793_000 picoseconds. - Weight::from_parts(4_990_000, 3514) + // Minimum execution time: 7_900_000 picoseconds. + Weight::from_parts(8_046_000, 3514) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -107,8 +109,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `113` // Estimated: `69049` - // Minimum execution time: 6_231_000 picoseconds. - Weight::from_parts(6_442_000, 69049) + // Minimum execution time: 6_284_000 picoseconds. + Weight::from_parts(6_433_000, 69049) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -118,8 +120,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `113` // Estimated: `69049` - // Minimum execution time: 6_660_000 picoseconds. - Weight::from_parts(6_825_000, 69049) + // Minimum execution time: 6_418_000 picoseconds. + Weight::from_parts(6_633_000, 69049) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -127,8 +129,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 72_805_000 picoseconds. - Weight::from_parts(74_650_000, 0) + // Minimum execution time: 52_661_000 picoseconds. + Weight::from_parts(52_994_000, 0) } /// Storage: MessageQueue ServiceHead (r:1 w:1) /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -136,10 +138,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) fn bump_service_head() -> Weight { // Proof Size summary in bytes: - // Measured: `172` + // Measured: `140` // Estimated: `5003` - // Minimum execution time: 7_078_000 picoseconds. - Weight::from_parts(7_230_000, 5003) + // Minimum execution time: 7_132_000 picoseconds. + Weight::from_parts(7_386_000, 5003) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -149,10 +151,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65584), added: 68059, mode: MaxEncodedLen) fn reap_page() -> Weight { // Proof Size summary in bytes: - // Measured: `65742` + // Measured: `65710` // Estimated: `72563` - // Minimum execution time: 56_799_000 picoseconds. - Weight::from_parts(57_634_000, 72563) + // Minimum execution time: 54_377_000 picoseconds. + Weight::from_parts(54_804_000, 72563) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -162,10 +164,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65584), added: 68059, mode: MaxEncodedLen) fn execute_overweight_page_removed() -> Weight { // Proof Size summary in bytes: - // Measured: `65742` + // Measured: `65710` // Estimated: `72563` - // Minimum execution time: 72_290_000 picoseconds. - Weight::from_parts(72_754_000, 72563) + // Minimum execution time: 69_461_000 picoseconds. + Weight::from_parts(70_016_000, 72563) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -175,10 +177,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65584), added: 68059, mode: MaxEncodedLen) fn execute_overweight_page_updated() -> Weight { // Proof Size summary in bytes: - // Measured: `65742` + // Measured: `65710` // Estimated: `72563` - // Minimum execution time: 84_987_000 picoseconds. - Weight::from_parts(85_562_000, 72563) + // Minimum execution time: 81_787_000 picoseconds. + Weight::from_parts(83_100_000, 72563) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -192,10 +194,10 @@ impl WeightInfo for () { /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) fn ready_ring_knit() -> Weight { // Proof Size summary in bytes: - // Measured: `295` + // Measured: `233` // Estimated: `7527` - // Minimum execution time: 12_283_000 picoseconds. - Weight::from_parts(12_554_000, 7527) + // Minimum execution time: 12_561_000 picoseconds. + Weight::from_parts(12_758_000, 7527) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -205,10 +207,10 @@ impl WeightInfo for () { /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn ready_ring_unknit() -> Weight { // Proof Size summary in bytes: - // Measured: `295` + // Measured: `233` // Estimated: `7527` - // Minimum execution time: 11_484_000 picoseconds. - Weight::from_parts(11_900_000, 7527) + // Minimum execution time: 11_854_000 picoseconds. + Weight::from_parts(12_178_000, 7527) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -218,8 +220,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `42` // Estimated: `3514` - // Minimum execution time: 4_793_000 picoseconds. - Weight::from_parts(4_990_000, 3514) + // Minimum execution time: 7_900_000 picoseconds. + Weight::from_parts(8_046_000, 3514) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -229,8 +231,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `113` // Estimated: `69049` - // Minimum execution time: 6_231_000 picoseconds. - Weight::from_parts(6_442_000, 69049) + // Minimum execution time: 6_284_000 picoseconds. + Weight::from_parts(6_433_000, 69049) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -240,8 +242,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `113` // Estimated: `69049` - // Minimum execution time: 6_660_000 picoseconds. - Weight::from_parts(6_825_000, 69049) + // Minimum execution time: 6_418_000 picoseconds. + Weight::from_parts(6_633_000, 69049) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -249,8 +251,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 72_805_000 picoseconds. - Weight::from_parts(74_650_000, 0) + // Minimum execution time: 52_661_000 picoseconds. + Weight::from_parts(52_994_000, 0) } /// Storage: MessageQueue ServiceHead (r:1 w:1) /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -258,10 +260,10 @@ impl WeightInfo for () { /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) fn bump_service_head() -> Weight { // Proof Size summary in bytes: - // Measured: `172` + // Measured: `140` // Estimated: `5003` - // Minimum execution time: 7_078_000 picoseconds. - Weight::from_parts(7_230_000, 5003) + // Minimum execution time: 7_132_000 picoseconds. + Weight::from_parts(7_386_000, 5003) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -271,10 +273,10 @@ impl WeightInfo for () { /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65584), added: 68059, mode: MaxEncodedLen) fn reap_page() -> Weight { // Proof Size summary in bytes: - // Measured: `65742` + // Measured: `65710` // Estimated: `72563` - // Minimum execution time: 56_799_000 picoseconds. - Weight::from_parts(57_634_000, 72563) + // Minimum execution time: 54_377_000 picoseconds. + Weight::from_parts(54_804_000, 72563) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -284,10 +286,10 @@ impl WeightInfo for () { /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65584), added: 68059, mode: MaxEncodedLen) fn execute_overweight_page_removed() -> Weight { // Proof Size summary in bytes: - // Measured: `65742` + // Measured: `65710` // Estimated: `72563` - // Minimum execution time: 72_290_000 picoseconds. - Weight::from_parts(72_754_000, 72563) + // Minimum execution time: 69_461_000 picoseconds. + Weight::from_parts(70_016_000, 72563) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -297,10 +299,10 @@ impl WeightInfo for () { /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65584), added: 68059, mode: MaxEncodedLen) fn execute_overweight_page_updated() -> Weight { // Proof Size summary in bytes: - // Measured: `65742` + // Measured: `65710` // Estimated: `72563` - // Minimum execution time: 84_987_000 picoseconds. - Weight::from_parts(85_562_000, 72563) + // Minimum execution time: 81_787_000 picoseconds. + Weight::from_parts(83_100_000, 72563) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } diff --git a/frame/multisig/src/weights.rs b/frame/multisig/src/weights.rs index fb155c97f2def..8941ce44f9a2b 100644 --- a/frame/multisig/src/weights.rs +++ b/frame/multisig/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_multisig //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,6 +31,9 @@ // --steps=50 // --repeat=20 // --pallet=pallet_multisig +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -65,8 +68,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 12_086 nanoseconds. - Weight::from_parts(12_464_828, 0) + // Minimum execution time: 12_096_000 picoseconds. + Weight::from_parts(12_442_958, 0) // Standard Error: 1 .saturating_add(Weight::from_parts(494, 0).saturating_mul(z.into())) } @@ -76,14 +79,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `z` is `[0, 10000]`. fn as_multi_create(s: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `352 + s * (2 ±0)` - // Estimated: `5821` - // Minimum execution time: 35_377 nanoseconds. - Weight::from_parts(29_088_956, 5821) - // Standard Error: 335 - .saturating_add(Weight::from_parts(67_846, 0).saturating_mul(s.into())) - // Standard Error: 3 - .saturating_add(Weight::from_parts(1_523, 0).saturating_mul(z.into())) + // Measured: `301 + s * (2 ±0)` + // Estimated: `6811` + // Minimum execution time: 37_609_000 picoseconds. + Weight::from_parts(32_693_100, 6811) + // Standard Error: 449 + .saturating_add(Weight::from_parts(56_623, 0).saturating_mul(s.into())) + // Standard Error: 4 + .saturating_add(Weight::from_parts(1_203, 0).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -93,14 +96,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `z` is `[0, 10000]`. fn as_multi_approve(s: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `351` - // Estimated: `5821` - // Minimum execution time: 26_138 nanoseconds. - Weight::from_parts(20_479_380, 5821) - // Standard Error: 259 - .saturating_add(Weight::from_parts(64_116, 0).saturating_mul(s.into())) - // Standard Error: 2 - .saturating_add(Weight::from_parts(1_520, 0).saturating_mul(z.into())) + // Measured: `320` + // Estimated: `6811` + // Minimum execution time: 27_434_000 picoseconds. + Weight::from_parts(22_659_090, 6811) + // Standard Error: 328 + .saturating_add(Weight::from_parts(53_508, 0).saturating_mul(s.into())) + // Standard Error: 3 + .saturating_add(Weight::from_parts(1_213, 0).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -112,14 +115,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `z` is `[0, 10000]`. fn as_multi_complete(s: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `489 + s * (33 ±0)` - // Estimated: `8424` - // Minimum execution time: 40_323 nanoseconds. - Weight::from_parts(32_311_615, 8424) - // Standard Error: 401 - .saturating_add(Weight::from_parts(85_999, 0).saturating_mul(s.into())) - // Standard Error: 3 - .saturating_add(Weight::from_parts(1_534, 0).saturating_mul(z.into())) + // Measured: `426 + s * (33 ±0)` + // Estimated: `10404` + // Minimum execution time: 43_592_000 picoseconds. + Weight::from_parts(36_465_266, 10404) + // Standard Error: 1_049 + .saturating_add(Weight::from_parts(78_833, 0).saturating_mul(s.into())) + // Standard Error: 10 + .saturating_add(Weight::from_parts(1_238, 0).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -128,12 +131,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[2, 100]`. fn approve_as_multi_create(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `359 + s * (2 ±0)` - // Estimated: `5821` - // Minimum execution time: 26_938 nanoseconds. - Weight::from_parts(27_802_216, 5821) - // Standard Error: 342 - .saturating_add(Weight::from_parts(69_282, 0).saturating_mul(s.into())) + // Measured: `301 + s * (2 ±0)` + // Estimated: `6811` + // Minimum execution time: 30_216_000 picoseconds. + Weight::from_parts(31_430_373, 6811) + // Standard Error: 967 + .saturating_add(Weight::from_parts(57_035, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -142,12 +145,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[2, 100]`. fn approve_as_multi_approve(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `351` - // Estimated: `5821` - // Minimum execution time: 18_050 nanoseconds. - Weight::from_parts(19_095_404, 5821) - // Standard Error: 419 - .saturating_add(Weight::from_parts(66_914, 0).saturating_mul(s.into())) + // Measured: `320` + // Estimated: `6811` + // Minimum execution time: 19_960_000 picoseconds. + Weight::from_parts(21_281_659, 6811) + // Standard Error: 435 + .saturating_add(Weight::from_parts(56_445, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -156,12 +159,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[2, 100]`. fn cancel_as_multi(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `555 + s * (1 ±0)` - // Estimated: `5821` - // Minimum execution time: 27_508 nanoseconds. - Weight::from_parts(28_702_686, 5821) - // Standard Error: 466 - .saturating_add(Weight::from_parts(69_419, 0).saturating_mul(s.into())) + // Measured: `492 + s * (1 ±0)` + // Estimated: `6811` + // Minimum execution time: 31_219_000 picoseconds. + Weight::from_parts(32_395_963, 6811) + // Standard Error: 500 + .saturating_add(Weight::from_parts(56_853, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -174,8 +177,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 12_086 nanoseconds. - Weight::from_parts(12_464_828, 0) + // Minimum execution time: 12_096_000 picoseconds. + Weight::from_parts(12_442_958, 0) // Standard Error: 1 .saturating_add(Weight::from_parts(494, 0).saturating_mul(z.into())) } @@ -185,14 +188,14 @@ impl WeightInfo for () { /// The range of component `z` is `[0, 10000]`. fn as_multi_create(s: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `352 + s * (2 ±0)` - // Estimated: `5821` - // Minimum execution time: 35_377 nanoseconds. - Weight::from_parts(29_088_956, 5821) - // Standard Error: 335 - .saturating_add(Weight::from_parts(67_846, 0).saturating_mul(s.into())) - // Standard Error: 3 - .saturating_add(Weight::from_parts(1_523, 0).saturating_mul(z.into())) + // Measured: `301 + s * (2 ±0)` + // Estimated: `6811` + // Minimum execution time: 37_609_000 picoseconds. + Weight::from_parts(32_693_100, 6811) + // Standard Error: 449 + .saturating_add(Weight::from_parts(56_623, 0).saturating_mul(s.into())) + // Standard Error: 4 + .saturating_add(Weight::from_parts(1_203, 0).saturating_mul(z.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -202,14 +205,14 @@ impl WeightInfo for () { /// The range of component `z` is `[0, 10000]`. fn as_multi_approve(s: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `351` - // Estimated: `5821` - // Minimum execution time: 26_138 nanoseconds. - Weight::from_parts(20_479_380, 5821) - // Standard Error: 259 - .saturating_add(Weight::from_parts(64_116, 0).saturating_mul(s.into())) - // Standard Error: 2 - .saturating_add(Weight::from_parts(1_520, 0).saturating_mul(z.into())) + // Measured: `320` + // Estimated: `6811` + // Minimum execution time: 27_434_000 picoseconds. + Weight::from_parts(22_659_090, 6811) + // Standard Error: 328 + .saturating_add(Weight::from_parts(53_508, 0).saturating_mul(s.into())) + // Standard Error: 3 + .saturating_add(Weight::from_parts(1_213, 0).saturating_mul(z.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -221,14 +224,14 @@ impl WeightInfo for () { /// The range of component `z` is `[0, 10000]`. fn as_multi_complete(s: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `489 + s * (33 ±0)` - // Estimated: `8424` - // Minimum execution time: 40_323 nanoseconds. - Weight::from_parts(32_311_615, 8424) - // Standard Error: 401 - .saturating_add(Weight::from_parts(85_999, 0).saturating_mul(s.into())) - // Standard Error: 3 - .saturating_add(Weight::from_parts(1_534, 0).saturating_mul(z.into())) + // Measured: `426 + s * (33 ±0)` + // Estimated: `10404` + // Minimum execution time: 43_592_000 picoseconds. + Weight::from_parts(36_465_266, 10404) + // Standard Error: 1_049 + .saturating_add(Weight::from_parts(78_833, 0).saturating_mul(s.into())) + // Standard Error: 10 + .saturating_add(Weight::from_parts(1_238, 0).saturating_mul(z.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -237,12 +240,12 @@ impl WeightInfo for () { /// The range of component `s` is `[2, 100]`. fn approve_as_multi_create(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `359 + s * (2 ±0)` - // Estimated: `5821` - // Minimum execution time: 26_938 nanoseconds. - Weight::from_parts(27_802_216, 5821) - // Standard Error: 342 - .saturating_add(Weight::from_parts(69_282, 0).saturating_mul(s.into())) + // Measured: `301 + s * (2 ±0)` + // Estimated: `6811` + // Minimum execution time: 30_216_000 picoseconds. + Weight::from_parts(31_430_373, 6811) + // Standard Error: 967 + .saturating_add(Weight::from_parts(57_035, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -251,12 +254,12 @@ impl WeightInfo for () { /// The range of component `s` is `[2, 100]`. fn approve_as_multi_approve(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `351` - // Estimated: `5821` - // Minimum execution time: 18_050 nanoseconds. - Weight::from_parts(19_095_404, 5821) - // Standard Error: 419 - .saturating_add(Weight::from_parts(66_914, 0).saturating_mul(s.into())) + // Measured: `320` + // Estimated: `6811` + // Minimum execution time: 19_960_000 picoseconds. + Weight::from_parts(21_281_659, 6811) + // Standard Error: 435 + .saturating_add(Weight::from_parts(56_445, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -265,12 +268,12 @@ impl WeightInfo for () { /// The range of component `s` is `[2, 100]`. fn cancel_as_multi(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `555 + s * (1 ±0)` - // Estimated: `5821` - // Minimum execution time: 27_508 nanoseconds. - Weight::from_parts(28_702_686, 5821) - // Standard Error: 466 - .saturating_add(Weight::from_parts(69_419, 0).saturating_mul(s.into())) + // Measured: `492 + s * (1 ±0)` + // Estimated: `6811` + // Minimum execution time: 31_219_000 picoseconds. + Weight::from_parts(32_395_963, 6811) + // Standard Error: 500 + .saturating_add(Weight::from_parts(56_853, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/frame/nfts/src/weights.rs b/frame/nfts/src/weights.rs index 3d447c8d264d4..c5010a73cc7cb 100644 --- a/frame/nfts/src/weights.rs +++ b/frame/nfts/src/weights.rs @@ -18,26 +18,28 @@ //! Autogenerated weights for pallet_nfts //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-10, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/production/substrate +// ./target/production/substrate // benchmark // pallet +// --chain=dev // --steps=50 // --repeat=20 +// --pallet=pallet_nfts +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --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_nfts -// --chain=dev -// --header=./HEADER-APACHE2 // --output=./frame/nfts/src/weights.rs +// --header=./HEADER-APACHE2 // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -105,10 +107,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Nfts CollectionAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) fn create() -> Weight { // Proof Size summary in bytes: - // Measured: `214` + // Measured: `182` // Estimated: `5038` - // Minimum execution time: 37_598_000 picoseconds. - Weight::from_parts(38_703_000, 5038) + // Minimum execution time: 36_780_000 picoseconds. + Weight::from_parts(37_508_000, 5038) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -126,8 +128,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `42` // Estimated: `5038` - // Minimum execution time: 25_899_000 picoseconds. - Weight::from_parts(26_385_000, 5038) + // Minimum execution time: 25_144_000 picoseconds. + Weight::from_parts(25_800_000, 5038) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -152,14 +154,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `a` is `[0, 1000]`. fn destroy(m: u32, _c: u32, a: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `32218 + a * (364 ±0)` + // Measured: `32186 + a * (332 ±0)` // Estimated: `2538589 + a * (2921 ±0)` - // Minimum execution time: 1_129_980_000 picoseconds. - Weight::from_parts(1_096_213_543, 2538589) - // Standard Error: 5_210 - .saturating_add(Weight::from_parts(92, 0).saturating_mul(m.into())) - // Standard Error: 5_210 - .saturating_add(Weight::from_parts(5_480_550, 0).saturating_mul(a.into())) + // Minimum execution time: 1_122_858_000 picoseconds. + Weight::from_parts(1_094_711_913, 2538589) + // Standard Error: 4_485 + .saturating_add(Weight::from_parts(3_481, 0).saturating_mul(m.into())) + // Standard Error: 4_485 + .saturating_add(Weight::from_parts(5_520_602, 0).saturating_mul(a.into())) .saturating_add(T::DbWeight::get().reads(1004_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(a.into()))) .saturating_add(T::DbWeight::get().writes(1005_u64)) @@ -180,10 +182,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) fn mint() -> Weight { // Proof Size summary in bytes: - // Measured: `453` + // Measured: `421` // Estimated: `18460` - // Minimum execution time: 49_434_000 picoseconds. - Weight::from_parts(50_248_000, 18460) + // Minimum execution time: 48_590_000 picoseconds. + Weight::from_parts(49_260_000, 18460) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -201,10 +203,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) fn force_mint() -> Weight { // Proof Size summary in bytes: - // Measured: `453` + // Measured: `421` // Estimated: `18460` - // Minimum execution time: 47_393_000 picoseconds. - Weight::from_parts(47_906_000, 18460) + // Minimum execution time: 46_646_000 picoseconds. + Weight::from_parts(47_331_000, 18460) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -226,10 +228,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) fn burn() -> Weight { // Proof Size summary in bytes: - // Measured: `594` + // Measured: `530` // Estimated: `14993` - // Minimum execution time: 47_188_000 picoseconds. - Weight::from_parts(47_746_000, 14993) + // Minimum execution time: 46_976_000 picoseconds. + Weight::from_parts(47_606_000, 14993) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } @@ -249,10 +251,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) fn transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `623` + // Measured: `559` // Estimated: `14926` - // Minimum execution time: 37_984_000 picoseconds. - Weight::from_parts(38_446_000, 14926) + // Minimum execution time: 38_013_000 picoseconds. + Weight::from_parts(38_420_000, 14926) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -265,12 +267,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `761 + i * (140 ±0)` + // Measured: `729 + i * (108 ±0)` // Estimated: `8077 + i * (3336 ±0)` - // Minimum execution time: 17_297_000 picoseconds. - Weight::from_parts(17_634_000, 8077) - // Standard Error: 17_773 - .saturating_add(Weight::from_parts(14_395_819, 0).saturating_mul(i.into())) + // Minimum execution time: 17_428_000 picoseconds. + Weight::from_parts(17_664_000, 8077) + // Standard Error: 16_385 + .saturating_add(Weight::from_parts(14_150_405, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(i.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) @@ -284,8 +286,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `401` // Estimated: `7047` - // Minimum execution time: 21_827_000 picoseconds. - Weight::from_parts(22_134_000, 7047) + // Minimum execution time: 21_760_000 picoseconds. + Weight::from_parts(22_063_000, 7047) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -297,8 +299,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `401` // Estimated: `7047` - // Minimum execution time: 21_549_000 picoseconds. - Weight::from_parts(21_987_000, 7047) + // Minimum execution time: 21_622_000 picoseconds. + Weight::from_parts(22_056_000, 7047) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -308,10 +310,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) fn lock_collection() -> Weight { // Proof Size summary in bytes: - // Measured: `338` + // Measured: `306` // Estimated: `7087` - // Minimum execution time: 18_930_000 picoseconds. - Weight::from_parts(19_200_000, 7087) + // Minimum execution time: 18_820_000 picoseconds. + Weight::from_parts(19_212_000, 7087) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -323,24 +325,24 @@ impl WeightInfo for SubstrateWeight { /// Proof: Nfts CollectionAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) fn transfer_ownership() -> Weight { // Proof Size summary in bytes: - // Measured: `386` + // Measured: `354` // Estimated: `7066` - // Minimum execution time: 24_929_000 picoseconds. - Weight::from_parts(25_786_000, 7066) + // Minimum execution time: 25_433_000 picoseconds. + Weight::from_parts(25_793_000, 7066) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } /// Storage: Nfts Collection (r:1 w:1) /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) - /// Storage: Nfts CollectionRoleOf (r:1 w:4) + /// Storage: Nfts CollectionRoleOf (r:2 w:4) /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) fn set_team() -> Weight { // Proof Size summary in bytes: - // Measured: `367` - // Estimated: `7083` - // Minimum execution time: 28_245_000 picoseconds. - Weight::from_parts(28_490_000, 7083) - .saturating_add(T::DbWeight::get().reads(2_u64)) + // Measured: `335` + // Estimated: `9627` + // Minimum execution time: 43_368_000 picoseconds. + Weight::from_parts(43_974_000, 9627) + .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } /// Storage: Nfts Collection (r:1 w:1) @@ -349,10 +351,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Nfts CollectionAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) fn force_collection_owner() -> Weight { // Proof Size summary in bytes: - // Measured: `309` + // Measured: `277` // Estimated: `3549` - // Minimum execution time: 19_971_000 picoseconds. - Weight::from_parts(20_276_000, 3549) + // Minimum execution time: 20_009_000 picoseconds. + Weight::from_parts(20_220_000, 3549) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -364,8 +366,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `242` // Estimated: `3549` - // Minimum execution time: 15_924_000 picoseconds. - Weight::from_parts(16_258_000, 3549) + // Minimum execution time: 16_048_000 picoseconds. + Weight::from_parts(16_353_000, 3549) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -377,8 +379,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `401` // Estimated: `7047` - // Minimum execution time: 20_780_000 picoseconds. - Weight::from_parts(21_109_000, 7047) + // Minimum execution time: 20_890_000 picoseconds. + Weight::from_parts(21_237_000, 7047) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -394,10 +396,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) fn set_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `537` + // Measured: `505` // Estimated: `18045` - // Minimum execution time: 50_817_000 picoseconds. - Weight::from_parts(51_585_000, 18045) + // Minimum execution time: 50_686_000 picoseconds. + Weight::from_parts(50_981_000, 18045) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -407,10 +409,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) fn force_set_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `342` + // Measured: `310` // Estimated: `7460` - // Minimum execution time: 28_821_000 picoseconds. - Weight::from_parts(29_417_000, 7460) + // Minimum execution time: 28_714_000 picoseconds. + Weight::from_parts(29_044_000, 7460) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -424,10 +426,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) fn clear_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `979` + // Measured: `916` // Estimated: `14507` - // Minimum execution time: 47_021_000 picoseconds. - Weight::from_parts(47_509_000, 14507) + // Minimum execution time: 46_232_000 picoseconds. + Weight::from_parts(46_738_000, 14507) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -437,10 +439,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Nfts ItemAttributesApprovalsOf (max_values: None, max_size: Some(681), added: 3156, mode: MaxEncodedLen) fn approve_item_attributes() -> Weight { // Proof Size summary in bytes: - // Measured: `379` + // Measured: `347` // Estimated: `8472` - // Minimum execution time: 19_457_000 picoseconds. - Weight::from_parts(19_738_000, 8472) + // Minimum execution time: 19_332_000 picoseconds. + Weight::from_parts(19_765_000, 8472) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -455,12 +457,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 1000]`. fn cancel_item_attributes_approval(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `899 + n * (396 ±0)` + // Measured: `803 + n * (364 ±0)` // Estimated: `15976 + n * (2921 ±0)` - // Minimum execution time: 29_027_000 picoseconds. - Weight::from_parts(29_376_000, 15976) - // Standard Error: 3_500 - .saturating_add(Weight::from_parts(5_568_116, 0).saturating_mul(n.into())) + // Minimum execution time: 29_227_000 picoseconds. + Weight::from_parts(29_661_000, 15976) + // Standard Error: 3_574 + .saturating_add(Weight::from_parts(5_442_937, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) @@ -479,10 +481,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Nfts ItemMetadataOf (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) fn set_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `537` + // Measured: `505` // Estimated: `17739` - // Minimum execution time: 41_658_000 picoseconds. - Weight::from_parts(42_241_000, 17739) + // Minimum execution time: 41_297_000 picoseconds. + Weight::from_parts(41_902_000, 17739) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -496,10 +498,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) fn clear_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `672` + // Measured: `608` // Estimated: `14201` - // Minimum execution time: 39_838_000 picoseconds. - Weight::from_parts(40_757_000, 14201) + // Minimum execution time: 39_312_000 picoseconds. + Weight::from_parts(40_048_000, 14201) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -513,10 +515,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Nfts CollectionMetadataOf (max_values: None, max_size: Some(87), added: 2562, mode: MaxEncodedLen) fn set_collection_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `396` + // Measured: `364` // Estimated: `14173` - // Minimum execution time: 37_327_000 picoseconds. - Weight::from_parts(37_874_000, 14173) + // Minimum execution time: 36_932_000 picoseconds. + Weight::from_parts(38_207_000, 14173) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -530,10 +532,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Nfts CollectionMetadataOf (max_values: None, max_size: Some(87), added: 2562, mode: MaxEncodedLen) fn clear_collection_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `539` + // Measured: `475` // Estimated: `14173` - // Minimum execution time: 35_305_000 picoseconds. - Weight::from_parts(36_213_000, 14173) + // Minimum execution time: 35_264_000 picoseconds. + Weight::from_parts(35_829_000, 14173) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -543,10 +545,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) fn approve_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `408` + // Measured: `376` // Estimated: `7864` - // Minimum execution time: 22_680_000 picoseconds. - Weight::from_parts(23_126_000, 7864) + // Minimum execution time: 22_819_000 picoseconds. + Weight::from_parts(23_121_000, 7864) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -554,10 +556,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) fn cancel_approval() -> Weight { // Proof Size summary in bytes: - // Measured: `416` + // Measured: `384` // Estimated: `4326` - // Minimum execution time: 19_837_000 picoseconds. - Weight::from_parts(20_352_000, 4326) + // Minimum execution time: 20_377_000 picoseconds. + Weight::from_parts(20_625_000, 4326) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -565,10 +567,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) fn clear_all_transfer_approvals() -> Weight { // Proof Size summary in bytes: - // Measured: `416` + // Measured: `384` // Estimated: `4326` - // Minimum execution time: 18_911_000 picoseconds. - Weight::from_parts(19_233_000, 4326) + // Minimum execution time: 19_180_000 picoseconds. + Weight::from_parts(19_468_000, 4326) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -578,8 +580,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `42` // Estimated: `3517` - // Minimum execution time: 17_292_000 picoseconds. - Weight::from_parts(17_568_000, 3517) + // Minimum execution time: 17_381_000 picoseconds. + Weight::from_parts(17_718_000, 3517) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -589,10 +591,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) fn set_collection_max_supply() -> Weight { // Proof Size summary in bytes: - // Measured: `338` + // Measured: `306` // Estimated: `7087` - // Minimum execution time: 20_323_000 picoseconds. - Weight::from_parts(20_692_000, 7087) + // Minimum execution time: 20_373_000 picoseconds. + Weight::from_parts(20_662_000, 7087) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -604,8 +606,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `289` // Estimated: `7072` - // Minimum execution time: 19_971_000 picoseconds. - Weight::from_parts(20_159_000, 7072) + // Minimum execution time: 20_154_000 picoseconds. + Weight::from_parts(20_592_000, 7072) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -619,10 +621,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Nfts ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) fn set_price() -> Weight { // Proof Size summary in bytes: - // Measured: `516` + // Measured: `484` // Estimated: `11377` - // Minimum execution time: 26_202_000 picoseconds. - Weight::from_parts(26_499_000, 11377) + // Minimum execution time: 25_644_000 picoseconds. + Weight::from_parts(25_999_000, 11377) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -642,10 +644,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) fn buy_item() -> Weight { // Proof Size summary in bytes: - // Measured: `767` + // Measured: `671` // Estimated: `18480` - // Minimum execution time: 50_601_000 picoseconds. - Weight::from_parts(51_283_000, 18480) + // Minimum execution time: 51_542_000 picoseconds. + Weight::from_parts(52_203_000, 18480) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -654,10 +656,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_733_000 picoseconds. - Weight::from_parts(5_568_590, 0) - // Standard Error: 14_136 - .saturating_add(Weight::from_parts(3_763_928, 0).saturating_mul(n.into())) + // Minimum execution time: 2_796_000 picoseconds. + Weight::from_parts(5_517_617, 0) + // Standard Error: 14_247 + .saturating_add(Weight::from_parts(3_757_796, 0).saturating_mul(n.into())) } /// Storage: Nfts Item (r:2 w:0) /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) @@ -665,10 +667,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) fn create_swap() -> Weight { // Proof Size summary in bytes: - // Measured: `524` + // Measured: `460` // Estimated: `7662` - // Minimum execution time: 22_901_000 picoseconds. - Weight::from_parts(23_673_000, 7662) + // Minimum execution time: 23_218_000 picoseconds. + Weight::from_parts(23_590_000, 7662) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -678,10 +680,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) fn cancel_swap() -> Weight { // Proof Size summary in bytes: - // Measured: `511` + // Measured: `479` // Estimated: `7862` - // Minimum execution time: 22_532_000 picoseconds. - Weight::from_parts(22_831_000, 7862) + // Minimum execution time: 22_536_000 picoseconds. + Weight::from_parts(22_874_000, 7862) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -701,21 +703,21 @@ impl WeightInfo for SubstrateWeight { /// Proof: Nfts ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) fn claim_swap() -> Weight { // Proof Size summary in bytes: - // Measured: `896` + // Measured: `800` // Estimated: `24321` - // Minimum execution time: 77_668_000 picoseconds. - Weight::from_parts(78_407_000, 24321) + // Minimum execution time: 77_372_000 picoseconds. + Weight::from_parts(78_109_000, 24321) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(10_u64)) } - /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) /// Storage: Nfts CollectionRoleOf (r:2 w:0) /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) /// Storage: Nfts CollectionConfigOf (r:1 w:0) /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) /// Storage: Nfts Item (r:1 w:1) /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) /// Storage: Nfts ItemConfigOf (r:1 w:1) /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) /// Storage: System Account (r:1 w:1) @@ -729,12 +731,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 10]`. fn mint_pre_signed(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `659` + // Measured: `595` // Estimated: `29192 + n * (2921 ±0)` - // Minimum execution time: 133_147_000 picoseconds. - Weight::from_parts(138_031_439, 29192) - // Standard Error: 28_665 - .saturating_add(Weight::from_parts(28_206_062, 0).saturating_mul(n.into())) + // Minimum execution time: 131_935_000 picoseconds. + Weight::from_parts(137_455_891, 29192) + // Standard Error: 31_617 + .saturating_add(Weight::from_parts(27_550_750, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(6_u64)) @@ -756,12 +758,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 10]`. fn set_attributes_pre_signed(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `721` + // Measured: `625` // Estimated: `20142 + n * (2921 ±0)` - // Minimum execution time: 78_243_000 picoseconds. - Weight::from_parts(90_947_408, 20142) - // Standard Error: 75_516 - .saturating_add(Weight::from_parts(28_059_623, 0).saturating_mul(n.into())) + // Minimum execution time: 77_694_000 picoseconds. + Weight::from_parts(90_089_732, 20142) + // Standard Error: 71_327 + .saturating_add(Weight::from_parts(27_832_189, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) @@ -784,10 +786,10 @@ impl WeightInfo for () { /// Proof: Nfts CollectionAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) fn create() -> Weight { // Proof Size summary in bytes: - // Measured: `214` + // Measured: `182` // Estimated: `5038` - // Minimum execution time: 37_598_000 picoseconds. - Weight::from_parts(38_703_000, 5038) + // Minimum execution time: 36_780_000 picoseconds. + Weight::from_parts(37_508_000, 5038) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -805,8 +807,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `42` // Estimated: `5038` - // Minimum execution time: 25_899_000 picoseconds. - Weight::from_parts(26_385_000, 5038) + // Minimum execution time: 25_144_000 picoseconds. + Weight::from_parts(25_800_000, 5038) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -831,14 +833,14 @@ impl WeightInfo for () { /// The range of component `a` is `[0, 1000]`. fn destroy(m: u32, _c: u32, a: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `32218 + a * (364 ±0)` + // Measured: `32186 + a * (332 ±0)` // Estimated: `2538589 + a * (2921 ±0)` - // Minimum execution time: 1_129_980_000 picoseconds. - Weight::from_parts(1_096_213_543, 2538589) - // Standard Error: 5_210 - .saturating_add(Weight::from_parts(92, 0).saturating_mul(m.into())) - // Standard Error: 5_210 - .saturating_add(Weight::from_parts(5_480_550, 0).saturating_mul(a.into())) + // Minimum execution time: 1_122_858_000 picoseconds. + Weight::from_parts(1_094_711_913, 2538589) + // Standard Error: 4_485 + .saturating_add(Weight::from_parts(3_481, 0).saturating_mul(m.into())) + // Standard Error: 4_485 + .saturating_add(Weight::from_parts(5_520_602, 0).saturating_mul(a.into())) .saturating_add(RocksDbWeight::get().reads(1004_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(a.into()))) .saturating_add(RocksDbWeight::get().writes(1005_u64)) @@ -859,10 +861,10 @@ impl WeightInfo for () { /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) fn mint() -> Weight { // Proof Size summary in bytes: - // Measured: `453` + // Measured: `421` // Estimated: `18460` - // Minimum execution time: 49_434_000 picoseconds. - Weight::from_parts(50_248_000, 18460) + // Minimum execution time: 48_590_000 picoseconds. + Weight::from_parts(49_260_000, 18460) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -880,10 +882,10 @@ impl WeightInfo for () { /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) fn force_mint() -> Weight { // Proof Size summary in bytes: - // Measured: `453` + // Measured: `421` // Estimated: `18460` - // Minimum execution time: 47_393_000 picoseconds. - Weight::from_parts(47_906_000, 18460) + // Minimum execution time: 46_646_000 picoseconds. + Weight::from_parts(47_331_000, 18460) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -905,10 +907,10 @@ impl WeightInfo for () { /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) fn burn() -> Weight { // Proof Size summary in bytes: - // Measured: `594` + // Measured: `530` // Estimated: `14993` - // Minimum execution time: 47_188_000 picoseconds. - Weight::from_parts(47_746_000, 14993) + // Minimum execution time: 46_976_000 picoseconds. + Weight::from_parts(47_606_000, 14993) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } @@ -928,10 +930,10 @@ impl WeightInfo for () { /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) fn transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `623` + // Measured: `559` // Estimated: `14926` - // Minimum execution time: 37_984_000 picoseconds. - Weight::from_parts(38_446_000, 14926) + // Minimum execution time: 38_013_000 picoseconds. + Weight::from_parts(38_420_000, 14926) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -944,12 +946,12 @@ impl WeightInfo for () { /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `761 + i * (140 ±0)` + // Measured: `729 + i * (108 ±0)` // Estimated: `8077 + i * (3336 ±0)` - // Minimum execution time: 17_297_000 picoseconds. - Weight::from_parts(17_634_000, 8077) - // Standard Error: 17_773 - .saturating_add(Weight::from_parts(14_395_819, 0).saturating_mul(i.into())) + // Minimum execution time: 17_428_000 picoseconds. + Weight::from_parts(17_664_000, 8077) + // Standard Error: 16_385 + .saturating_add(Weight::from_parts(14_150_405, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(i.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(i.into()))) @@ -963,8 +965,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `401` // Estimated: `7047` - // Minimum execution time: 21_827_000 picoseconds. - Weight::from_parts(22_134_000, 7047) + // Minimum execution time: 21_760_000 picoseconds. + Weight::from_parts(22_063_000, 7047) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -976,8 +978,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `401` // Estimated: `7047` - // Minimum execution time: 21_549_000 picoseconds. - Weight::from_parts(21_987_000, 7047) + // Minimum execution time: 21_622_000 picoseconds. + Weight::from_parts(22_056_000, 7047) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -987,10 +989,10 @@ impl WeightInfo for () { /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) fn lock_collection() -> Weight { // Proof Size summary in bytes: - // Measured: `338` + // Measured: `306` // Estimated: `7087` - // Minimum execution time: 18_930_000 picoseconds. - Weight::from_parts(19_200_000, 7087) + // Minimum execution time: 18_820_000 picoseconds. + Weight::from_parts(19_212_000, 7087) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1002,24 +1004,24 @@ impl WeightInfo for () { /// Proof: Nfts CollectionAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) fn transfer_ownership() -> Weight { // Proof Size summary in bytes: - // Measured: `386` + // Measured: `354` // Estimated: `7066` - // Minimum execution time: 24_929_000 picoseconds. - Weight::from_parts(25_786_000, 7066) + // Minimum execution time: 25_433_000 picoseconds. + Weight::from_parts(25_793_000, 7066) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } /// Storage: Nfts Collection (r:1 w:1) /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) - /// Storage: Nfts CollectionRoleOf (r:1 w:4) + /// Storage: Nfts CollectionRoleOf (r:2 w:4) /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) fn set_team() -> Weight { // Proof Size summary in bytes: - // Measured: `367` - // Estimated: `7083` - // Minimum execution time: 28_245_000 picoseconds. - Weight::from_parts(28_490_000, 7083) - .saturating_add(RocksDbWeight::get().reads(2_u64)) + // Measured: `335` + // Estimated: `9627` + // Minimum execution time: 43_368_000 picoseconds. + Weight::from_parts(43_974_000, 9627) + .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } /// Storage: Nfts Collection (r:1 w:1) @@ -1028,10 +1030,10 @@ impl WeightInfo for () { /// Proof: Nfts CollectionAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) fn force_collection_owner() -> Weight { // Proof Size summary in bytes: - // Measured: `309` + // Measured: `277` // Estimated: `3549` - // Minimum execution time: 19_971_000 picoseconds. - Weight::from_parts(20_276_000, 3549) + // Minimum execution time: 20_009_000 picoseconds. + Weight::from_parts(20_220_000, 3549) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -1043,8 +1045,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `242` // Estimated: `3549` - // Minimum execution time: 15_924_000 picoseconds. - Weight::from_parts(16_258_000, 3549) + // Minimum execution time: 16_048_000 picoseconds. + Weight::from_parts(16_353_000, 3549) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1056,8 +1058,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `401` // Estimated: `7047` - // Minimum execution time: 20_780_000 picoseconds. - Weight::from_parts(21_109_000, 7047) + // Minimum execution time: 20_890_000 picoseconds. + Weight::from_parts(21_237_000, 7047) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1073,10 +1075,10 @@ impl WeightInfo for () { /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) fn set_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `537` + // Measured: `505` // Estimated: `18045` - // Minimum execution time: 50_817_000 picoseconds. - Weight::from_parts(51_585_000, 18045) + // Minimum execution time: 50_686_000 picoseconds. + Weight::from_parts(50_981_000, 18045) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1086,10 +1088,10 @@ impl WeightInfo for () { /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) fn force_set_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `342` + // Measured: `310` // Estimated: `7460` - // Minimum execution time: 28_821_000 picoseconds. - Weight::from_parts(29_417_000, 7460) + // Minimum execution time: 28_714_000 picoseconds. + Weight::from_parts(29_044_000, 7460) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1103,10 +1105,10 @@ impl WeightInfo for () { /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) fn clear_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `979` + // Measured: `916` // Estimated: `14507` - // Minimum execution time: 47_021_000 picoseconds. - Weight::from_parts(47_509_000, 14507) + // Minimum execution time: 46_232_000 picoseconds. + Weight::from_parts(46_738_000, 14507) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1116,10 +1118,10 @@ impl WeightInfo for () { /// Proof: Nfts ItemAttributesApprovalsOf (max_values: None, max_size: Some(681), added: 3156, mode: MaxEncodedLen) fn approve_item_attributes() -> Weight { // Proof Size summary in bytes: - // Measured: `379` + // Measured: `347` // Estimated: `8472` - // Minimum execution time: 19_457_000 picoseconds. - Weight::from_parts(19_738_000, 8472) + // Minimum execution time: 19_332_000 picoseconds. + Weight::from_parts(19_765_000, 8472) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1134,12 +1136,12 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 1000]`. fn cancel_item_attributes_approval(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `899 + n * (396 ±0)` + // Measured: `803 + n * (364 ±0)` // Estimated: `15976 + n * (2921 ±0)` - // Minimum execution time: 29_027_000 picoseconds. - Weight::from_parts(29_376_000, 15976) - // Standard Error: 3_500 - .saturating_add(Weight::from_parts(5_568_116, 0).saturating_mul(n.into())) + // Minimum execution time: 29_227_000 picoseconds. + Weight::from_parts(29_661_000, 15976) + // Standard Error: 3_574 + .saturating_add(Weight::from_parts(5_442_937, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(2_u64)) @@ -1158,10 +1160,10 @@ impl WeightInfo for () { /// Proof: Nfts ItemMetadataOf (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) fn set_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `537` + // Measured: `505` // Estimated: `17739` - // Minimum execution time: 41_658_000 picoseconds. - Weight::from_parts(42_241_000, 17739) + // Minimum execution time: 41_297_000 picoseconds. + Weight::from_parts(41_902_000, 17739) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1175,10 +1177,10 @@ impl WeightInfo for () { /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) fn clear_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `672` + // Measured: `608` // Estimated: `14201` - // Minimum execution time: 39_838_000 picoseconds. - Weight::from_parts(40_757_000, 14201) + // Minimum execution time: 39_312_000 picoseconds. + Weight::from_parts(40_048_000, 14201) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1192,10 +1194,10 @@ impl WeightInfo for () { /// Proof: Nfts CollectionMetadataOf (max_values: None, max_size: Some(87), added: 2562, mode: MaxEncodedLen) fn set_collection_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `396` + // Measured: `364` // Estimated: `14173` - // Minimum execution time: 37_327_000 picoseconds. - Weight::from_parts(37_874_000, 14173) + // Minimum execution time: 36_932_000 picoseconds. + Weight::from_parts(38_207_000, 14173) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1209,10 +1211,10 @@ impl WeightInfo for () { /// Proof: Nfts CollectionMetadataOf (max_values: None, max_size: Some(87), added: 2562, mode: MaxEncodedLen) fn clear_collection_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `539` + // Measured: `475` // Estimated: `14173` - // Minimum execution time: 35_305_000 picoseconds. - Weight::from_parts(36_213_000, 14173) + // Minimum execution time: 35_264_000 picoseconds. + Weight::from_parts(35_829_000, 14173) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1222,10 +1224,10 @@ impl WeightInfo for () { /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) fn approve_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `408` + // Measured: `376` // Estimated: `7864` - // Minimum execution time: 22_680_000 picoseconds. - Weight::from_parts(23_126_000, 7864) + // Minimum execution time: 22_819_000 picoseconds. + Weight::from_parts(23_121_000, 7864) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1233,10 +1235,10 @@ impl WeightInfo for () { /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) fn cancel_approval() -> Weight { // Proof Size summary in bytes: - // Measured: `416` + // Measured: `384` // Estimated: `4326` - // Minimum execution time: 19_837_000 picoseconds. - Weight::from_parts(20_352_000, 4326) + // Minimum execution time: 20_377_000 picoseconds. + Weight::from_parts(20_625_000, 4326) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1244,10 +1246,10 @@ impl WeightInfo for () { /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) fn clear_all_transfer_approvals() -> Weight { // Proof Size summary in bytes: - // Measured: `416` + // Measured: `384` // Estimated: `4326` - // Minimum execution time: 18_911_000 picoseconds. - Weight::from_parts(19_233_000, 4326) + // Minimum execution time: 19_180_000 picoseconds. + Weight::from_parts(19_468_000, 4326) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1257,8 +1259,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `42` // Estimated: `3517` - // Minimum execution time: 17_292_000 picoseconds. - Weight::from_parts(17_568_000, 3517) + // Minimum execution time: 17_381_000 picoseconds. + Weight::from_parts(17_718_000, 3517) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1268,10 +1270,10 @@ impl WeightInfo for () { /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) fn set_collection_max_supply() -> Weight { // Proof Size summary in bytes: - // Measured: `338` + // Measured: `306` // Estimated: `7087` - // Minimum execution time: 20_323_000 picoseconds. - Weight::from_parts(20_692_000, 7087) + // Minimum execution time: 20_373_000 picoseconds. + Weight::from_parts(20_662_000, 7087) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1283,8 +1285,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `289` // Estimated: `7072` - // Minimum execution time: 19_971_000 picoseconds. - Weight::from_parts(20_159_000, 7072) + // Minimum execution time: 20_154_000 picoseconds. + Weight::from_parts(20_592_000, 7072) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1298,10 +1300,10 @@ impl WeightInfo for () { /// Proof: Nfts ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) fn set_price() -> Weight { // Proof Size summary in bytes: - // Measured: `516` + // Measured: `484` // Estimated: `11377` - // Minimum execution time: 26_202_000 picoseconds. - Weight::from_parts(26_499_000, 11377) + // Minimum execution time: 25_644_000 picoseconds. + Weight::from_parts(25_999_000, 11377) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1321,10 +1323,10 @@ impl WeightInfo for () { /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) fn buy_item() -> Weight { // Proof Size summary in bytes: - // Measured: `767` + // Measured: `671` // Estimated: `18480` - // Minimum execution time: 50_601_000 picoseconds. - Weight::from_parts(51_283_000, 18480) + // Minimum execution time: 51_542_000 picoseconds. + Weight::from_parts(52_203_000, 18480) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -1333,10 +1335,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_733_000 picoseconds. - Weight::from_parts(5_568_590, 0) - // Standard Error: 14_136 - .saturating_add(Weight::from_parts(3_763_928, 0).saturating_mul(n.into())) + // Minimum execution time: 2_796_000 picoseconds. + Weight::from_parts(5_517_617, 0) + // Standard Error: 14_247 + .saturating_add(Weight::from_parts(3_757_796, 0).saturating_mul(n.into())) } /// Storage: Nfts Item (r:2 w:0) /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) @@ -1344,10 +1346,10 @@ impl WeightInfo for () { /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) fn create_swap() -> Weight { // Proof Size summary in bytes: - // Measured: `524` + // Measured: `460` // Estimated: `7662` - // Minimum execution time: 22_901_000 picoseconds. - Weight::from_parts(23_673_000, 7662) + // Minimum execution time: 23_218_000 picoseconds. + Weight::from_parts(23_590_000, 7662) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1357,10 +1359,10 @@ impl WeightInfo for () { /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) fn cancel_swap() -> Weight { // Proof Size summary in bytes: - // Measured: `511` + // Measured: `479` // Estimated: `7862` - // Minimum execution time: 22_532_000 picoseconds. - Weight::from_parts(22_831_000, 7862) + // Minimum execution time: 22_536_000 picoseconds. + Weight::from_parts(22_874_000, 7862) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1380,21 +1382,21 @@ impl WeightInfo for () { /// Proof: Nfts ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) fn claim_swap() -> Weight { // Proof Size summary in bytes: - // Measured: `896` + // Measured: `800` // Estimated: `24321` - // Minimum execution time: 77_668_000 picoseconds. - Weight::from_parts(78_407_000, 24321) + // Minimum execution time: 77_372_000 picoseconds. + Weight::from_parts(78_109_000, 24321) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(10_u64)) } - /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) /// Storage: Nfts CollectionRoleOf (r:2 w:0) /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) /// Storage: Nfts CollectionConfigOf (r:1 w:0) /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) /// Storage: Nfts Item (r:1 w:1) /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) /// Storage: Nfts ItemConfigOf (r:1 w:1) /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) /// Storage: System Account (r:1 w:1) @@ -1408,12 +1410,12 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 10]`. fn mint_pre_signed(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `659` + // Measured: `595` // Estimated: `29192 + n * (2921 ±0)` - // Minimum execution time: 133_147_000 picoseconds. - Weight::from_parts(138_031_439, 29192) - // Standard Error: 28_665 - .saturating_add(Weight::from_parts(28_206_062, 0).saturating_mul(n.into())) + // Minimum execution time: 131_935_000 picoseconds. + Weight::from_parts(137_455_891, 29192) + // Standard Error: 31_617 + .saturating_add(Weight::from_parts(27_550_750, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(6_u64)) @@ -1435,12 +1437,12 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 10]`. fn set_attributes_pre_signed(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `721` + // Measured: `625` // Estimated: `20142 + n * (2921 ±0)` - // Minimum execution time: 78_243_000 picoseconds. - Weight::from_parts(90_947_408, 20142) - // Standard Error: 75_516 - .saturating_add(Weight::from_parts(28_059_623, 0).saturating_mul(n.into())) + // Minimum execution time: 77_694_000 picoseconds. + Weight::from_parts(90_089_732, 20142) + // Standard Error: 71_327 + .saturating_add(Weight::from_parts(27_832_189, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(2_u64)) diff --git a/frame/nis/src/weights.rs b/frame/nis/src/weights.rs index 27c2f23e0e9ec..14b7b4d9c6f9a 100644 --- a/frame/nis/src/weights.rs +++ b/frame/nis/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_nis //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,6 +31,9 @@ // --steps=50 // --repeat=20 // --pallet=pallet_nis +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -73,12 +76,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `l` is `[0, 999]`. fn place_bid(l: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `6245 + l * (48 ±0)` - // Estimated: `60718` - // Minimum execution time: 28_814 nanoseconds. - Weight::from_parts(35_245_917, 60718) - // Standard Error: 189 - .saturating_add(Weight::from_parts(45_322, 0).saturating_mul(l.into())) + // Measured: `6182 + l * (48 ±0)` + // Estimated: `63688` + // Minimum execution time: 31_160_000 picoseconds. + Weight::from_parts(39_023_414, 63688) + // Standard Error: 214 + .saturating_add(Weight::from_parts(46_106, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -90,10 +93,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Nis QueueTotals (max_values: Some(1), max_size: Some(6002), added: 6497, mode: MaxEncodedLen) fn place_bid_max() -> Weight { // Proof Size summary in bytes: - // Measured: `54247` - // Estimated: `60718` - // Minimum execution time: 80_332 nanoseconds. - Weight::from_parts(81_050_000, 60718) + // Measured: `54184` + // Estimated: `63688` + // Minimum execution time: 85_703_000 picoseconds. + Weight::from_parts(86_613_000, 63688) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -106,12 +109,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `l` is `[1, 1000]`. fn retract_bid(l: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `6245 + l * (48 ±0)` - // Estimated: `60718` - // Minimum execution time: 34_426 nanoseconds. - Weight::from_parts(36_434_166, 60718) - // Standard Error: 135 - .saturating_add(Weight::from_parts(33_923, 0).saturating_mul(l.into())) + // Measured: `6182 + l * (48 ±0)` + // Estimated: `63688` + // Minimum execution time: 37_637_000 picoseconds. + Weight::from_parts(39_977_788, 63688) + // Standard Error: 152 + .saturating_add(Weight::from_parts(34_595, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -121,10 +124,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn fund_deficit() -> Weight { // Proof Size summary in bytes: - // Measured: `222` - // Estimated: `3138` - // Minimum execution time: 32_566 nanoseconds. - Weight::from_parts(32_880_000, 3138) + // Measured: `191` + // Estimated: `5118` + // Minimum execution time: 35_807_000 picoseconds. + Weight::from_parts(36_329_000, 5118) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -138,10 +141,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Balances Reserves (max_values: None, max_size: Some(1249), added: 3724, mode: MaxEncodedLen) fn thaw_private() -> Weight { // Proof Size summary in bytes: - // Measured: `423` - // Estimated: `9418` - // Minimum execution time: 46_212 nanoseconds. - Weight::from_parts(46_748_000, 9418) + // Measured: `360` + // Estimated: `13378` + // Minimum execution time: 51_342_000 picoseconds. + Weight::from_parts(51_976_000, 13378) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -157,10 +160,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn thaw_communal() -> Weight { // Proof Size summary in bytes: - // Measured: `868` - // Estimated: `10956` - // Minimum execution time: 68_791 nanoseconds. - Weight::from_parts(69_504_000, 10956) + // Measured: `773` + // Estimated: `15906` + // Minimum execution time: 76_535_000 picoseconds. + Weight::from_parts(78_073_000, 15906) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -178,10 +181,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Balances Reserves (max_values: None, max_size: Some(1249), added: 3724, mode: MaxEncodedLen) fn privatize() -> Weight { // Proof Size summary in bytes: - // Measured: `930` - // Estimated: `14680` - // Minimum execution time: 76_784 nanoseconds. - Weight::from_parts(77_575_000, 14680) + // Measured: `835` + // Estimated: `20620` + // Minimum execution time: 84_680_000 picoseconds. + Weight::from_parts(85_661_000, 20620) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -199,10 +202,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) fn communify() -> Weight { // Proof Size summary in bytes: - // Measured: `769` - // Estimated: `14680` - // Minimum execution time: 64_543 nanoseconds. - Weight::from_parts(65_258_000, 14680) + // Measured: `674` + // Estimated: `20620` + // Minimum execution time: 72_828_000 picoseconds. + Weight::from_parts(73_553_000, 20620) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -214,10 +217,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Nis QueueTotals (max_values: Some(1), max_size: Some(6002), added: 6497, mode: MaxEncodedLen) fn process_queues() -> Weight { // Proof Size summary in bytes: - // Measured: `6655` - // Estimated: `9635` - // Minimum execution time: 21_379 nanoseconds. - Weight::from_parts(21_736_000, 9635) + // Measured: `6624` + // Estimated: `12605` + // Minimum execution time: 23_311_000 picoseconds. + Weight::from_parts(23_855_000, 12605) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -226,9 +229,9 @@ impl WeightInfo for SubstrateWeight { fn process_queue() -> Weight { // Proof Size summary in bytes: // Measured: `42` - // Estimated: `50497` - // Minimum execution time: 4_302 nanoseconds. - Weight::from_parts(4_440_000, 50497) + // Estimated: `51487` + // Minimum execution time: 4_485_000 picoseconds. + Weight::from_parts(4_717_000, 51487) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -238,8 +241,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_758 nanoseconds. - Weight::from_parts(6_911_000, 0) + // Minimum execution time: 7_837_000 picoseconds. + Weight::from_parts(12_913_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } } @@ -255,12 +258,12 @@ impl WeightInfo for () { /// The range of component `l` is `[0, 999]`. fn place_bid(l: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `6245 + l * (48 ±0)` - // Estimated: `60718` - // Minimum execution time: 28_814 nanoseconds. - Weight::from_parts(35_245_917, 60718) - // Standard Error: 189 - .saturating_add(Weight::from_parts(45_322, 0).saturating_mul(l.into())) + // Measured: `6182 + l * (48 ±0)` + // Estimated: `63688` + // Minimum execution time: 31_160_000 picoseconds. + Weight::from_parts(39_023_414, 63688) + // Standard Error: 214 + .saturating_add(Weight::from_parts(46_106, 0).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -272,10 +275,10 @@ impl WeightInfo for () { /// Proof: Nis QueueTotals (max_values: Some(1), max_size: Some(6002), added: 6497, mode: MaxEncodedLen) fn place_bid_max() -> Weight { // Proof Size summary in bytes: - // Measured: `54247` - // Estimated: `60718` - // Minimum execution time: 80_332 nanoseconds. - Weight::from_parts(81_050_000, 60718) + // Measured: `54184` + // Estimated: `63688` + // Minimum execution time: 85_703_000 picoseconds. + Weight::from_parts(86_613_000, 63688) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -288,12 +291,12 @@ impl WeightInfo for () { /// The range of component `l` is `[1, 1000]`. fn retract_bid(l: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `6245 + l * (48 ±0)` - // Estimated: `60718` - // Minimum execution time: 34_426 nanoseconds. - Weight::from_parts(36_434_166, 60718) - // Standard Error: 135 - .saturating_add(Weight::from_parts(33_923, 0).saturating_mul(l.into())) + // Measured: `6182 + l * (48 ±0)` + // Estimated: `63688` + // Minimum execution time: 37_637_000 picoseconds. + Weight::from_parts(39_977_788, 63688) + // Standard Error: 152 + .saturating_add(Weight::from_parts(34_595, 0).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -303,10 +306,10 @@ impl WeightInfo for () { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn fund_deficit() -> Weight { // Proof Size summary in bytes: - // Measured: `222` - // Estimated: `3138` - // Minimum execution time: 32_566 nanoseconds. - Weight::from_parts(32_880_000, 3138) + // Measured: `191` + // Estimated: `5118` + // Minimum execution time: 35_807_000 picoseconds. + Weight::from_parts(36_329_000, 5118) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -320,10 +323,10 @@ impl WeightInfo for () { /// Proof: Balances Reserves (max_values: None, max_size: Some(1249), added: 3724, mode: MaxEncodedLen) fn thaw_private() -> Weight { // Proof Size summary in bytes: - // Measured: `423` - // Estimated: `9418` - // Minimum execution time: 46_212 nanoseconds. - Weight::from_parts(46_748_000, 9418) + // Measured: `360` + // Estimated: `13378` + // Minimum execution time: 51_342_000 picoseconds. + Weight::from_parts(51_976_000, 13378) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -339,10 +342,10 @@ impl WeightInfo for () { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn thaw_communal() -> Weight { // Proof Size summary in bytes: - // Measured: `868` - // Estimated: `10956` - // Minimum execution time: 68_791 nanoseconds. - Weight::from_parts(69_504_000, 10956) + // Measured: `773` + // Estimated: `15906` + // Minimum execution time: 76_535_000 picoseconds. + Weight::from_parts(78_073_000, 15906) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -360,10 +363,10 @@ impl WeightInfo for () { /// Proof: Balances Reserves (max_values: None, max_size: Some(1249), added: 3724, mode: MaxEncodedLen) fn privatize() -> Weight { // Proof Size summary in bytes: - // Measured: `930` - // Estimated: `14680` - // Minimum execution time: 76_784 nanoseconds. - Weight::from_parts(77_575_000, 14680) + // Measured: `835` + // Estimated: `20620` + // Minimum execution time: 84_680_000 picoseconds. + Weight::from_parts(85_661_000, 20620) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -381,10 +384,10 @@ impl WeightInfo for () { /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) fn communify() -> Weight { // Proof Size summary in bytes: - // Measured: `769` - // Estimated: `14680` - // Minimum execution time: 64_543 nanoseconds. - Weight::from_parts(65_258_000, 14680) + // Measured: `674` + // Estimated: `20620` + // Minimum execution time: 72_828_000 picoseconds. + Weight::from_parts(73_553_000, 20620) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -396,10 +399,10 @@ impl WeightInfo for () { /// Proof: Nis QueueTotals (max_values: Some(1), max_size: Some(6002), added: 6497, mode: MaxEncodedLen) fn process_queues() -> Weight { // Proof Size summary in bytes: - // Measured: `6655` - // Estimated: `9635` - // Minimum execution time: 21_379 nanoseconds. - Weight::from_parts(21_736_000, 9635) + // Measured: `6624` + // Estimated: `12605` + // Minimum execution time: 23_311_000 picoseconds. + Weight::from_parts(23_855_000, 12605) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -408,9 +411,9 @@ impl WeightInfo for () { fn process_queue() -> Weight { // Proof Size summary in bytes: // Measured: `42` - // Estimated: `50497` - // Minimum execution time: 4_302 nanoseconds. - Weight::from_parts(4_440_000, 50497) + // Estimated: `51487` + // Minimum execution time: 4_485_000 picoseconds. + Weight::from_parts(4_717_000, 51487) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -420,8 +423,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_758 nanoseconds. - Weight::from_parts(6_911_000, 0) + // Minimum execution time: 7_837_000 picoseconds. + Weight::from_parts(12_913_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } } diff --git a/frame/nomination-pools/src/weights.rs b/frame/nomination-pools/src/weights.rs index cf0048fa48dd9..003ba93eb8a7e 100644 --- a/frame/nomination-pools/src/weights.rs +++ b/frame/nomination-pools/src/weights.rs @@ -18,26 +18,28 @@ //! Autogenerated weights for pallet_nomination_pools //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/production/substrate +// ./target/production/substrate // benchmark // pallet +// --chain=dev // --steps=50 // --repeat=20 +// --pallet=pallet_nomination_pools +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --json-file=/var/lib/gitlab-runner/builds/zyw4fam_/0/parity/mirrors/substrate/.git/.artifacts/bench.json -// --pallet=pallet_nomination_pools -// --chain=dev -// --header=./HEADER-APACHE2 // --output=./frame/nomination-pools/src/weights.rs +// --header=./HEADER-APACHE2 // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -104,10 +106,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) fn join() -> Weight { // Proof Size summary in bytes: - // Measured: `3650` + // Measured: `3300` // Estimated: `52435` - // Minimum execution time: 160_401_000 picoseconds. - Weight::from_parts(161_798_000, 52435) + // Minimum execution time: 160_675_000 picoseconds. + Weight::from_parts(162_605_000, 52435) .saturating_add(T::DbWeight::get().reads(18_u64)) .saturating_add(T::DbWeight::get().writes(12_u64)) } @@ -133,10 +135,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) fn bond_extra_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `3692` + // Measured: `3310` // Estimated: `49070` - // Minimum execution time: 157_668_000 picoseconds. - Weight::from_parts(161_129_000, 49070) + // Minimum execution time: 156_820_000 picoseconds. + Weight::from_parts(159_798_000, 49070) .saturating_add(T::DbWeight::get().reads(15_u64)) .saturating_add(T::DbWeight::get().writes(12_u64)) } @@ -164,10 +166,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) fn bond_extra_other() -> Weight { // Proof Size summary in bytes: - // Measured: `3757` + // Measured: `3375` // Estimated: `52576` - // Minimum execution time: 176_034_000 picoseconds. - Weight::from_parts(176_956_000, 52576) + // Minimum execution time: 175_820_000 picoseconds. + Weight::from_parts(177_378_000, 52576) .saturating_add(T::DbWeight::get().reads(16_u64)) .saturating_add(T::DbWeight::get().writes(13_u64)) } @@ -185,10 +187,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn claim_payout() -> Weight { // Proof Size summary in bytes: - // Measured: `1331` + // Measured: `1171` // Estimated: `19532` - // Minimum execution time: 61_551_000 picoseconds. - Weight::from_parts(62_201_000, 19532) + // Minimum execution time: 62_011_000 picoseconds. + Weight::from_parts(62_680_000, 19532) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -224,10 +226,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: NominationPools CounterForSubPoolsStorage (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn unbond() -> Weight { // Proof Size summary in bytes: - // Measured: `3935` + // Measured: `3586` // Estimated: `82816` - // Minimum execution time: 162_755_000 picoseconds. - Weight::from_parts(163_518_000, 82816) + // Minimum execution time: 163_294_000 picoseconds. + Weight::from_parts(164_375_000, 82816) .saturating_add(T::DbWeight::get().reads(19_u64)) .saturating_add(T::DbWeight::get().writes(13_u64)) } @@ -244,12 +246,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[0, 100]`. fn pool_withdraw_unbonded(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1783` + // Measured: `1687` // Estimated: `18031` - // Minimum execution time: 54_752_000 picoseconds. - Weight::from_parts(56_248_171, 18031) - // Standard Error: 1_891 - .saturating_add(Weight::from_parts(4_767, 0).saturating_mul(s.into())) + // Minimum execution time: 54_775_000 picoseconds. + Weight::from_parts(55_724_944, 18031) + // Standard Error: 536 + .saturating_add(Weight::from_parts(10_059, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -276,12 +278,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2307` + // Measured: `2115` // Estimated: `54662` - // Minimum execution time: 106_166_000 picoseconds. - Weight::from_parts(107_806_373, 54662) - // Standard Error: 6_985 - .saturating_add(Weight::from_parts(18_449, 0).saturating_mul(s.into())) + // Minimum execution time: 106_820_000 picoseconds. + Weight::from_parts(109_870_849, 54662) + // Standard Error: 11_111 + .saturating_add(Weight::from_parts(2_006, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(8_u64)) } @@ -330,12 +332,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_kill(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2694` - // Estimated: `87714` - // Minimum execution time: 170_047_000 picoseconds. - Weight::from_parts(172_125_770, 87714) - // Standard Error: 2_599 - .saturating_add(Weight::from_parts(9_964, 0).saturating_mul(s.into())) + // Measured: `2470` + // Estimated: `87490` + // Minimum execution time: 170_908_000 picoseconds. + Weight::from_parts(173_616_555, 87490) + // Standard Error: 2_324 + .saturating_add(Weight::from_parts(4_397, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(20_u64)) .saturating_add(T::DbWeight::get().writes(18_u64)) } @@ -383,10 +385,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) fn create() -> Weight { // Proof Size summary in bytes: - // Measured: `1321` + // Measured: `1289` // Estimated: `51410` - // Minimum execution time: 149_672_000 picoseconds. - Weight::from_parts(153_613_000, 51410) + // Minimum execution time: 148_934_000 picoseconds. + Weight::from_parts(149_702_000, 51410) .saturating_add(T::DbWeight::get().reads(21_u64)) .saturating_add(T::DbWeight::get().writes(15_u64)) } @@ -417,12 +419,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1913` + // Measured: `1849` // Estimated: `33934 + n * (2520 ±0)` - // Minimum execution time: 68_892_000 picoseconds. - Weight::from_parts(69_062_946, 33934) - // Standard Error: 6_448 - .saturating_add(Weight::from_parts(1_422_774, 0).saturating_mul(n.into())) + // Minimum execution time: 68_986_000 picoseconds. + Weight::from_parts(69_474_269, 33934) + // Standard Error: 6_602 + .saturating_add(Weight::from_parts(1_416_294, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(5_u64)) @@ -436,10 +438,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) fn set_state() -> Weight { // Proof Size summary in bytes: - // Measured: `1502` + // Measured: `1438` // Estimated: `11778` - // Minimum execution time: 36_447_000 picoseconds. - Weight::from_parts(36_837_000, 11778) + // Minimum execution time: 36_300_000 picoseconds. + Weight::from_parts(36_713_000, 11778) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -452,12 +454,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[1, 256]`. fn set_metadata(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `563` + // Measured: `531` // Estimated: `8909` - // Minimum execution time: 15_221_000 picoseconds. - Weight::from_parts(15_632_286, 8909) - // Standard Error: 343 - .saturating_add(Weight::from_parts(2_299, 0).saturating_mul(n.into())) + // Minimum execution time: 14_976_000 picoseconds. + Weight::from_parts(15_538_088, 8909) + // Standard Error: 71 + .saturating_add(Weight::from_parts(1_548, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -477,18 +479,18 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_409_000 picoseconds. - Weight::from_parts(7_702_000, 0) + // Minimum execution time: 7_259_000 picoseconds. + Weight::from_parts(7_499_000, 0) .saturating_add(T::DbWeight::get().writes(6_u64)) } /// Storage: NominationPools BondedPools (r:1 w:1) /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) fn update_roles() -> Weight { // Proof Size summary in bytes: - // Measured: `563` + // Measured: `531` // Estimated: `3685` - // Minimum execution time: 20_451_000 picoseconds. - Weight::from_parts(20_703_000, 3685) + // Minimum execution time: 20_454_000 picoseconds. + Weight::from_parts(20_771_000, 3685) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -512,10 +514,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn chill() -> Weight { // Proof Size summary in bytes: - // Measured: `2140` + // Measured: `2012` // Estimated: `29455` - // Minimum execution time: 66_001_000 picoseconds. - Weight::from_parts(66_894_000, 29455) + // Minimum execution time: 66_404_000 picoseconds. + Weight::from_parts(66_872_000, 29455) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -529,10 +531,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn set_commission() -> Weight { // Proof Size summary in bytes: - // Measured: `866` + // Measured: `770` // Estimated: `12324` - // Minimum execution time: 34_011_000 picoseconds. - Weight::from_parts(34_521_000, 12324) + // Minimum execution time: 34_240_000 picoseconds. + Weight::from_parts(34_797_000, 12324) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -540,10 +542,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) fn set_commission_max() -> Weight { // Proof Size summary in bytes: - // Measured: `603` + // Measured: `571` // Estimated: `3685` - // Minimum execution time: 19_524_000 picoseconds. - Weight::from_parts(19_855_000, 3685) + // Minimum execution time: 19_469_000 picoseconds. + Weight::from_parts(19_865_000, 3685) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -551,10 +553,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) fn set_commission_change_rate() -> Weight { // Proof Size summary in bytes: - // Measured: `563` + // Measured: `531` // Estimated: `3685` - // Minimum execution time: 20_457_000 picoseconds. - Weight::from_parts(20_698_000, 3685) + // Minimum execution time: 20_423_000 picoseconds. + Weight::from_parts(20_620_000, 3685) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -566,8 +568,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `542` // Estimated: `7208` - // Minimum execution time: 15_183_000 picoseconds. - Weight::from_parts(15_597_000, 7208) + // Minimum execution time: 15_346_000 picoseconds. + Weight::from_parts(15_613_000, 7208) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -581,10 +583,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn claim_commission() -> Weight { // Proof Size summary in bytes: - // Measured: `1096` + // Measured: `968` // Estimated: `12324` - // Minimum execution time: 48_957_000 picoseconds. - Weight::from_parts(50_207_000, 12324) + // Minimum execution time: 48_749_000 picoseconds. + Weight::from_parts(49_131_000, 12324) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -622,10 +624,10 @@ impl WeightInfo for () { /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) fn join() -> Weight { // Proof Size summary in bytes: - // Measured: `3650` + // Measured: `3300` // Estimated: `52435` - // Minimum execution time: 160_401_000 picoseconds. - Weight::from_parts(161_798_000, 52435) + // Minimum execution time: 160_675_000 picoseconds. + Weight::from_parts(162_605_000, 52435) .saturating_add(RocksDbWeight::get().reads(18_u64)) .saturating_add(RocksDbWeight::get().writes(12_u64)) } @@ -651,10 +653,10 @@ impl WeightInfo for () { /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) fn bond_extra_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `3692` + // Measured: `3310` // Estimated: `49070` - // Minimum execution time: 157_668_000 picoseconds. - Weight::from_parts(161_129_000, 49070) + // Minimum execution time: 156_820_000 picoseconds. + Weight::from_parts(159_798_000, 49070) .saturating_add(RocksDbWeight::get().reads(15_u64)) .saturating_add(RocksDbWeight::get().writes(12_u64)) } @@ -682,10 +684,10 @@ impl WeightInfo for () { /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) fn bond_extra_other() -> Weight { // Proof Size summary in bytes: - // Measured: `3757` + // Measured: `3375` // Estimated: `52576` - // Minimum execution time: 176_034_000 picoseconds. - Weight::from_parts(176_956_000, 52576) + // Minimum execution time: 175_820_000 picoseconds. + Weight::from_parts(177_378_000, 52576) .saturating_add(RocksDbWeight::get().reads(16_u64)) .saturating_add(RocksDbWeight::get().writes(13_u64)) } @@ -703,10 +705,10 @@ impl WeightInfo for () { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn claim_payout() -> Weight { // Proof Size summary in bytes: - // Measured: `1331` + // Measured: `1171` // Estimated: `19532` - // Minimum execution time: 61_551_000 picoseconds. - Weight::from_parts(62_201_000, 19532) + // Minimum execution time: 62_011_000 picoseconds. + Weight::from_parts(62_680_000, 19532) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -742,10 +744,10 @@ impl WeightInfo for () { /// Proof: NominationPools CounterForSubPoolsStorage (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn unbond() -> Weight { // Proof Size summary in bytes: - // Measured: `3935` + // Measured: `3586` // Estimated: `82816` - // Minimum execution time: 162_755_000 picoseconds. - Weight::from_parts(163_518_000, 82816) + // Minimum execution time: 163_294_000 picoseconds. + Weight::from_parts(164_375_000, 82816) .saturating_add(RocksDbWeight::get().reads(19_u64)) .saturating_add(RocksDbWeight::get().writes(13_u64)) } @@ -762,12 +764,12 @@ impl WeightInfo for () { /// The range of component `s` is `[0, 100]`. fn pool_withdraw_unbonded(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1783` + // Measured: `1687` // Estimated: `18031` - // Minimum execution time: 54_752_000 picoseconds. - Weight::from_parts(56_248_171, 18031) - // Standard Error: 1_891 - .saturating_add(Weight::from_parts(4_767, 0).saturating_mul(s.into())) + // Minimum execution time: 54_775_000 picoseconds. + Weight::from_parts(55_724_944, 18031) + // Standard Error: 536 + .saturating_add(Weight::from_parts(10_059, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -794,12 +796,12 @@ impl WeightInfo for () { /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2307` + // Measured: `2115` // Estimated: `54662` - // Minimum execution time: 106_166_000 picoseconds. - Weight::from_parts(107_806_373, 54662) - // Standard Error: 6_985 - .saturating_add(Weight::from_parts(18_449, 0).saturating_mul(s.into())) + // Minimum execution time: 106_820_000 picoseconds. + Weight::from_parts(109_870_849, 54662) + // Standard Error: 11_111 + .saturating_add(Weight::from_parts(2_006, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(8_u64)) } @@ -848,12 +850,12 @@ impl WeightInfo for () { /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_kill(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2694` - // Estimated: `87714` - // Minimum execution time: 170_047_000 picoseconds. - Weight::from_parts(172_125_770, 87714) - // Standard Error: 2_599 - .saturating_add(Weight::from_parts(9_964, 0).saturating_mul(s.into())) + // Measured: `2470` + // Estimated: `87490` + // Minimum execution time: 170_908_000 picoseconds. + Weight::from_parts(173_616_555, 87490) + // Standard Error: 2_324 + .saturating_add(Weight::from_parts(4_397, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(20_u64)) .saturating_add(RocksDbWeight::get().writes(18_u64)) } @@ -901,10 +903,10 @@ impl WeightInfo for () { /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) fn create() -> Weight { // Proof Size summary in bytes: - // Measured: `1321` + // Measured: `1289` // Estimated: `51410` - // Minimum execution time: 149_672_000 picoseconds. - Weight::from_parts(153_613_000, 51410) + // Minimum execution time: 148_934_000 picoseconds. + Weight::from_parts(149_702_000, 51410) .saturating_add(RocksDbWeight::get().reads(21_u64)) .saturating_add(RocksDbWeight::get().writes(15_u64)) } @@ -935,12 +937,12 @@ impl WeightInfo for () { /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1913` + // Measured: `1849` // Estimated: `33934 + n * (2520 ±0)` - // Minimum execution time: 68_892_000 picoseconds. - Weight::from_parts(69_062_946, 33934) - // Standard Error: 6_448 - .saturating_add(Weight::from_parts(1_422_774, 0).saturating_mul(n.into())) + // Minimum execution time: 68_986_000 picoseconds. + Weight::from_parts(69_474_269, 33934) + // Standard Error: 6_602 + .saturating_add(Weight::from_parts(1_416_294, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(5_u64)) @@ -954,10 +956,10 @@ impl WeightInfo for () { /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) fn set_state() -> Weight { // Proof Size summary in bytes: - // Measured: `1502` + // Measured: `1438` // Estimated: `11778` - // Minimum execution time: 36_447_000 picoseconds. - Weight::from_parts(36_837_000, 11778) + // Minimum execution time: 36_300_000 picoseconds. + Weight::from_parts(36_713_000, 11778) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -970,12 +972,12 @@ impl WeightInfo for () { /// The range of component `n` is `[1, 256]`. fn set_metadata(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `563` + // Measured: `531` // Estimated: `8909` - // Minimum execution time: 15_221_000 picoseconds. - Weight::from_parts(15_632_286, 8909) - // Standard Error: 343 - .saturating_add(Weight::from_parts(2_299, 0).saturating_mul(n.into())) + // Minimum execution time: 14_976_000 picoseconds. + Weight::from_parts(15_538_088, 8909) + // Standard Error: 71 + .saturating_add(Weight::from_parts(1_548, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -995,18 +997,18 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_409_000 picoseconds. - Weight::from_parts(7_702_000, 0) + // Minimum execution time: 7_259_000 picoseconds. + Weight::from_parts(7_499_000, 0) .saturating_add(RocksDbWeight::get().writes(6_u64)) } /// Storage: NominationPools BondedPools (r:1 w:1) /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) fn update_roles() -> Weight { // Proof Size summary in bytes: - // Measured: `563` + // Measured: `531` // Estimated: `3685` - // Minimum execution time: 20_451_000 picoseconds. - Weight::from_parts(20_703_000, 3685) + // Minimum execution time: 20_454_000 picoseconds. + Weight::from_parts(20_771_000, 3685) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1030,10 +1032,10 @@ impl WeightInfo for () { /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn chill() -> Weight { // Proof Size summary in bytes: - // Measured: `2140` + // Measured: `2012` // Estimated: `29455` - // Minimum execution time: 66_001_000 picoseconds. - Weight::from_parts(66_894_000, 29455) + // Minimum execution time: 66_404_000 picoseconds. + Weight::from_parts(66_872_000, 29455) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -1047,10 +1049,10 @@ impl WeightInfo for () { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn set_commission() -> Weight { // Proof Size summary in bytes: - // Measured: `866` + // Measured: `770` // Estimated: `12324` - // Minimum execution time: 34_011_000 picoseconds. - Weight::from_parts(34_521_000, 12324) + // Minimum execution time: 34_240_000 picoseconds. + Weight::from_parts(34_797_000, 12324) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1058,10 +1060,10 @@ impl WeightInfo for () { /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) fn set_commission_max() -> Weight { // Proof Size summary in bytes: - // Measured: `603` + // Measured: `571` // Estimated: `3685` - // Minimum execution time: 19_524_000 picoseconds. - Weight::from_parts(19_855_000, 3685) + // Minimum execution time: 19_469_000 picoseconds. + Weight::from_parts(19_865_000, 3685) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1069,10 +1071,10 @@ impl WeightInfo for () { /// Proof: NominationPools BondedPools (max_values: None, max_size: Some(220), added: 2695, mode: MaxEncodedLen) fn set_commission_change_rate() -> Weight { // Proof Size summary in bytes: - // Measured: `563` + // Measured: `531` // Estimated: `3685` - // Minimum execution time: 20_457_000 picoseconds. - Weight::from_parts(20_698_000, 3685) + // Minimum execution time: 20_423_000 picoseconds. + Weight::from_parts(20_620_000, 3685) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1084,8 +1086,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `542` // Estimated: `7208` - // Minimum execution time: 15_183_000 picoseconds. - Weight::from_parts(15_597_000, 7208) + // Minimum execution time: 15_346_000 picoseconds. + Weight::from_parts(15_613_000, 7208) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1099,10 +1101,10 @@ impl WeightInfo for () { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn claim_commission() -> Weight { // Proof Size summary in bytes: - // Measured: `1096` + // Measured: `968` // Estimated: `12324` - // Minimum execution time: 48_957_000 picoseconds. - Weight::from_parts(50_207_000, 12324) + // Minimum execution time: 48_749_000 picoseconds. + Weight::from_parts(49_131_000, 12324) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } diff --git a/frame/preimage/src/weights.rs b/frame/preimage/src/weights.rs index fa6bdc972fa47..168cb634c2d48 100644 --- a/frame/preimage/src/weights.rs +++ b/frame/preimage/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_preimage //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,6 +31,9 @@ // --steps=50 // --repeat=20 // --pallet=pallet_preimage +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -72,12 +75,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[0, 4194304]`. fn note_preimage(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `175` - // Estimated: `2566` - // Minimum execution time: 23_484 nanoseconds. - Weight::from_parts(23_828_000, 2566) + // Measured: `143` + // Estimated: `3556` + // Minimum execution time: 27_010_000 picoseconds. + Weight::from_parts(27_665_000, 3556) // Standard Error: 0 - .saturating_add(Weight::from_parts(1_705, 0).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_414, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -89,11 +92,11 @@ impl WeightInfo for SubstrateWeight { fn note_requested_preimage(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `106` - // Estimated: `2566` - // Minimum execution time: 14_812 nanoseconds. - Weight::from_parts(14_949_000, 2566) + // Estimated: `3556` + // Minimum execution time: 16_984_000 picoseconds. + Weight::from_parts(17_455_000, 3556) // Standard Error: 0 - .saturating_add(Weight::from_parts(1_707, 0).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_414, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -105,11 +108,11 @@ impl WeightInfo for SubstrateWeight { fn note_no_deposit_preimage(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `106` - // Estimated: `2566` - // Minimum execution time: 14_185 nanoseconds. - Weight::from_parts(14_398_000, 2566) + // Estimated: `3556` + // Minimum execution time: 16_579_000 picoseconds. + Weight::from_parts(16_849_000, 3556) // Standard Error: 0 - .saturating_add(Weight::from_parts(1_709, 0).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_414, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -119,10 +122,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) fn unnote_preimage() -> Weight { // Proof Size summary in bytes: - // Measured: `353` - // Estimated: `2566` - // Minimum execution time: 29_917 nanoseconds. - Weight::from_parts(30_691_000, 2566) + // Measured: `289` + // Estimated: `3556` + // Minimum execution time: 33_552_000 picoseconds. + Weight::from_parts(35_134_000, 3556) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -133,9 +136,9 @@ impl WeightInfo for SubstrateWeight { fn unnote_no_deposit_preimage() -> Weight { // Proof Size summary in bytes: // Measured: `144` - // Estimated: `2566` - // Minimum execution time: 19_281 nanoseconds. - Weight::from_parts(20_121_000, 2566) + // Estimated: `3556` + // Minimum execution time: 22_102_000 picoseconds. + Weight::from_parts(22_860_000, 3556) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -143,10 +146,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) fn request_preimage() -> Weight { // Proof Size summary in bytes: - // Measured: `220` - // Estimated: `2566` - // Minimum execution time: 17_192 nanoseconds. - Weight::from_parts(18_637_000, 2566) + // Measured: `188` + // Estimated: `3556` + // Minimum execution time: 19_590_000 picoseconds. + Weight::from_parts(20_638_000, 3556) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -155,9 +158,9 @@ impl WeightInfo for SubstrateWeight { fn request_no_deposit_preimage() -> Weight { // Proof Size summary in bytes: // Measured: `144` - // Estimated: `2566` - // Minimum execution time: 10_139 nanoseconds. - Weight::from_parts(10_773_000, 2566) + // Estimated: `3556` + // Minimum execution time: 11_689_000 picoseconds. + Weight::from_parts(12_577_000, 3556) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -166,9 +169,9 @@ impl WeightInfo for SubstrateWeight { fn request_unnoted_preimage() -> Weight { // Proof Size summary in bytes: // Measured: `42` - // Estimated: `2566` - // Minimum execution time: 11_721 nanoseconds. - Weight::from_parts(12_313_000, 2566) + // Estimated: `3556` + // Minimum execution time: 13_673_000 picoseconds. + Weight::from_parts(14_210_000, 3556) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -177,9 +180,9 @@ impl WeightInfo for SubstrateWeight { fn request_requested_preimage() -> Weight { // Proof Size summary in bytes: // Measured: `106` - // Estimated: `2566` - // Minimum execution time: 7_263 nanoseconds. - Weight::from_parts(7_547_000, 2566) + // Estimated: `3556` + // Minimum execution time: 8_810_000 picoseconds. + Weight::from_parts(9_044_000, 3556) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -190,9 +193,9 @@ impl WeightInfo for SubstrateWeight { fn unrequest_preimage() -> Weight { // Proof Size summary in bytes: // Measured: `144` - // Estimated: `2566` - // Minimum execution time: 17_785 nanoseconds. - Weight::from_parts(18_501_000, 2566) + // Estimated: `3556` + // Minimum execution time: 21_236_000 picoseconds. + Weight::from_parts(21_684_000, 3556) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -201,9 +204,9 @@ impl WeightInfo for SubstrateWeight { fn unrequest_unnoted_preimage() -> Weight { // Proof Size summary in bytes: // Measured: `106` - // Estimated: `2566` - // Minimum execution time: 7_090 nanoseconds. - Weight::from_parts(7_319_000, 2566) + // Estimated: `3556` + // Minimum execution time: 8_709_000 picoseconds. + Weight::from_parts(8_970_000, 3556) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -212,9 +215,9 @@ impl WeightInfo for SubstrateWeight { fn unrequest_multi_referenced_preimage() -> Weight { // Proof Size summary in bytes: // Measured: `106` - // Estimated: `2566` - // Minimum execution time: 7_253 nanoseconds. - Weight::from_parts(7_508_000, 2566) + // Estimated: `3556` + // Minimum execution time: 8_976_000 picoseconds. + Weight::from_parts(9_164_000, 3556) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -229,12 +232,12 @@ impl WeightInfo for () { /// The range of component `s` is `[0, 4194304]`. fn note_preimage(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `175` - // Estimated: `2566` - // Minimum execution time: 23_484 nanoseconds. - Weight::from_parts(23_828_000, 2566) + // Measured: `143` + // Estimated: `3556` + // Minimum execution time: 27_010_000 picoseconds. + Weight::from_parts(27_665_000, 3556) // Standard Error: 0 - .saturating_add(Weight::from_parts(1_705, 0).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_414, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -246,11 +249,11 @@ impl WeightInfo for () { fn note_requested_preimage(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `106` - // Estimated: `2566` - // Minimum execution time: 14_812 nanoseconds. - Weight::from_parts(14_949_000, 2566) + // Estimated: `3556` + // Minimum execution time: 16_984_000 picoseconds. + Weight::from_parts(17_455_000, 3556) // Standard Error: 0 - .saturating_add(Weight::from_parts(1_707, 0).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_414, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -262,11 +265,11 @@ impl WeightInfo for () { fn note_no_deposit_preimage(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `106` - // Estimated: `2566` - // Minimum execution time: 14_185 nanoseconds. - Weight::from_parts(14_398_000, 2566) + // Estimated: `3556` + // Minimum execution time: 16_579_000 picoseconds. + Weight::from_parts(16_849_000, 3556) // Standard Error: 0 - .saturating_add(Weight::from_parts(1_709, 0).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_414, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -276,10 +279,10 @@ impl WeightInfo for () { /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) fn unnote_preimage() -> Weight { // Proof Size summary in bytes: - // Measured: `353` - // Estimated: `2566` - // Minimum execution time: 29_917 nanoseconds. - Weight::from_parts(30_691_000, 2566) + // Measured: `289` + // Estimated: `3556` + // Minimum execution time: 33_552_000 picoseconds. + Weight::from_parts(35_134_000, 3556) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -290,9 +293,9 @@ impl WeightInfo for () { fn unnote_no_deposit_preimage() -> Weight { // Proof Size summary in bytes: // Measured: `144` - // Estimated: `2566` - // Minimum execution time: 19_281 nanoseconds. - Weight::from_parts(20_121_000, 2566) + // Estimated: `3556` + // Minimum execution time: 22_102_000 picoseconds. + Weight::from_parts(22_860_000, 3556) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -300,10 +303,10 @@ impl WeightInfo for () { /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) fn request_preimage() -> Weight { // Proof Size summary in bytes: - // Measured: `220` - // Estimated: `2566` - // Minimum execution time: 17_192 nanoseconds. - Weight::from_parts(18_637_000, 2566) + // Measured: `188` + // Estimated: `3556` + // Minimum execution time: 19_590_000 picoseconds. + Weight::from_parts(20_638_000, 3556) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -312,9 +315,9 @@ impl WeightInfo for () { fn request_no_deposit_preimage() -> Weight { // Proof Size summary in bytes: // Measured: `144` - // Estimated: `2566` - // Minimum execution time: 10_139 nanoseconds. - Weight::from_parts(10_773_000, 2566) + // Estimated: `3556` + // Minimum execution time: 11_689_000 picoseconds. + Weight::from_parts(12_577_000, 3556) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -323,9 +326,9 @@ impl WeightInfo for () { fn request_unnoted_preimage() -> Weight { // Proof Size summary in bytes: // Measured: `42` - // Estimated: `2566` - // Minimum execution time: 11_721 nanoseconds. - Weight::from_parts(12_313_000, 2566) + // Estimated: `3556` + // Minimum execution time: 13_673_000 picoseconds. + Weight::from_parts(14_210_000, 3556) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -334,9 +337,9 @@ impl WeightInfo for () { fn request_requested_preimage() -> Weight { // Proof Size summary in bytes: // Measured: `106` - // Estimated: `2566` - // Minimum execution time: 7_263 nanoseconds. - Weight::from_parts(7_547_000, 2566) + // Estimated: `3556` + // Minimum execution time: 8_810_000 picoseconds. + Weight::from_parts(9_044_000, 3556) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -347,9 +350,9 @@ impl WeightInfo for () { fn unrequest_preimage() -> Weight { // Proof Size summary in bytes: // Measured: `144` - // Estimated: `2566` - // Minimum execution time: 17_785 nanoseconds. - Weight::from_parts(18_501_000, 2566) + // Estimated: `3556` + // Minimum execution time: 21_236_000 picoseconds. + Weight::from_parts(21_684_000, 3556) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -358,9 +361,9 @@ impl WeightInfo for () { fn unrequest_unnoted_preimage() -> Weight { // Proof Size summary in bytes: // Measured: `106` - // Estimated: `2566` - // Minimum execution time: 7_090 nanoseconds. - Weight::from_parts(7_319_000, 2566) + // Estimated: `3556` + // Minimum execution time: 8_709_000 picoseconds. + Weight::from_parts(8_970_000, 3556) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -369,9 +372,9 @@ impl WeightInfo for () { fn unrequest_multi_referenced_preimage() -> Weight { // Proof Size summary in bytes: // Measured: `106` - // Estimated: `2566` - // Minimum execution time: 7_253 nanoseconds. - Weight::from_parts(7_508_000, 2566) + // Estimated: `3556` + // Minimum execution time: 8_976_000 picoseconds. + Weight::from_parts(9_164_000, 3556) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/frame/proxy/src/weights.rs b/frame/proxy/src/weights.rs index 5b70b61e569b4..28e24c4682f18 100644 --- a/frame/proxy/src/weights.rs +++ b/frame/proxy/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_proxy //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,6 +31,9 @@ // --steps=50 // --repeat=20 // --pallet=pallet_proxy +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -68,12 +71,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `p` is `[1, 31]`. fn proxy(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `193 + p * (37 ±0)` - // Estimated: `3716` - // Minimum execution time: 14_461 nanoseconds. - Weight::from_parts(14_913_927, 3716) - // Standard Error: 1_174 - .saturating_add(Weight::from_parts(36_087, 0).saturating_mul(p.into())) + // Measured: `161 + p * (37 ±0)` + // Estimated: `4706` + // Minimum execution time: 16_407_000 picoseconds. + Weight::from_parts(17_044_509, 4706) + // Standard Error: 1_177 + .saturating_add(Weight::from_parts(36_533, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: Proxy Proxies (r:1 w:0) @@ -86,14 +89,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `p` is `[1, 31]`. fn proxy_announced(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `584 + a * (68 ±0) + p * (37 ±0)` - // Estimated: `11027` - // Minimum execution time: 31_523 nanoseconds. - Weight::from_parts(31_116_270, 11027) - // Standard Error: 1_789 - .saturating_add(Weight::from_parts(135_656, 0).saturating_mul(a.into())) - // Standard Error: 1_849 - .saturating_add(Weight::from_parts(53_893, 0).saturating_mul(p.into())) + // Measured: `488 + a * (68 ±0) + p * (37 ±0)` + // Estimated: `13997` + // Minimum execution time: 38_523_000 picoseconds. + Weight::from_parts(39_227_232, 13997) + // Standard Error: 5_703 + .saturating_add(Weight::from_parts(136_003, 0).saturating_mul(a.into())) + // Standard Error: 5_893 + .saturating_add(Weight::from_parts(42_397, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -105,14 +108,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `p` is `[1, 31]`. fn remove_announcement(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `467 + a * (68 ±0)` - // Estimated: `7311` - // Minimum execution time: 19_363 nanoseconds. - Weight::from_parts(20_282_191, 7311) - // Standard Error: 1_084 - .saturating_add(Weight::from_parts(133_825, 0).saturating_mul(a.into())) - // Standard Error: 1_120 - .saturating_add(Weight::from_parts(3_434, 0).saturating_mul(p.into())) + // Measured: `403 + a * (68 ±0)` + // Estimated: `9291` + // Minimum execution time: 22_541_000 picoseconds. + Weight::from_parts(23_402_268, 9291) + // Standard Error: 3_242 + .saturating_add(Weight::from_parts(178_017, 0).saturating_mul(a.into())) + // Standard Error: 3_349 + .saturating_add(Weight::from_parts(6_230, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -124,14 +127,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `p` is `[1, 31]`. fn reject_announcement(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `467 + a * (68 ±0)` - // Estimated: `7311` - // Minimum execution time: 19_363 nanoseconds. - Weight::from_parts(20_211_584, 7311) - // Standard Error: 1_171 - .saturating_add(Weight::from_parts(136_984, 0).saturating_mul(a.into())) - // Standard Error: 1_210 - .saturating_add(Weight::from_parts(3_686, 0).saturating_mul(p.into())) + // Measured: `403 + a * (68 ±0)` + // Estimated: `9291` + // Minimum execution time: 22_539_000 picoseconds. + Weight::from_parts(23_479_286, 9291) + // Standard Error: 1_329 + .saturating_add(Weight::from_parts(174_021, 0).saturating_mul(a.into())) + // Standard Error: 1_373 + .saturating_add(Weight::from_parts(6_465, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -145,14 +148,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `p` is `[1, 31]`. fn announce(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `516 + a * (68 ±0) + p * (37 ±0)` - // Estimated: `11027` - // Minimum execution time: 27_811 nanoseconds. - Weight::from_parts(27_965_813, 11027) - // Standard Error: 1_987 - .saturating_add(Weight::from_parts(124_133, 0).saturating_mul(a.into())) - // Standard Error: 2_053 - .saturating_add(Weight::from_parts(54_692, 0).saturating_mul(p.into())) + // Measured: `420 + a * (68 ±0) + p * (37 ±0)` + // Estimated: `13997` + // Minimum execution time: 32_049_000 picoseconds. + Weight::from_parts(35_352_453, 13997) + // Standard Error: 4_389 + .saturating_add(Weight::from_parts(144_573, 0).saturating_mul(a.into())) + // Standard Error: 4_535 + .saturating_add(Weight::from_parts(41_849, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -161,12 +164,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `p` is `[1, 31]`. fn add_proxy(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `193 + p * (37 ±0)` - // Estimated: `3716` - // Minimum execution time: 20_922 nanoseconds. - Weight::from_parts(21_551_797, 3716) - // Standard Error: 1_425 - .saturating_add(Weight::from_parts(58_434, 0).saturating_mul(p.into())) + // Measured: `161 + p * (37 ±0)` + // Estimated: `4706` + // Minimum execution time: 24_491_000 picoseconds. + Weight::from_parts(25_291_582, 4706) + // Standard Error: 11_080 + .saturating_add(Weight::from_parts(68_024, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -175,12 +178,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `p` is `[1, 31]`. fn remove_proxy(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `193 + p * (37 ±0)` - // Estimated: `3716` - // Minimum execution time: 20_812 nanoseconds. - Weight::from_parts(21_660_732, 3716) - // Standard Error: 1_438 - .saturating_add(Weight::from_parts(68_740, 0).saturating_mul(p.into())) + // Measured: `161 + p * (37 ±0)` + // Estimated: `4706` + // Minimum execution time: 23_849_000 picoseconds. + Weight::from_parts(25_370_806, 4706) + // Standard Error: 8_763 + .saturating_add(Weight::from_parts(63_413, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -189,12 +192,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `p` is `[1, 31]`. fn remove_proxies(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `193 + p * (37 ±0)` - // Estimated: `3716` - // Minimum execution time: 16_786 nanoseconds. - Weight::from_parts(17_249_958, 3716) - // Standard Error: 1_007 - .saturating_add(Weight::from_parts(37_546, 0).saturating_mul(p.into())) + // Measured: `161 + p * (37 ±0)` + // Estimated: `4706` + // Minimum execution time: 19_488_000 picoseconds. + Weight::from_parts(20_219_817, 4706) + // Standard Error: 1_385 + .saturating_add(Weight::from_parts(30_354, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -204,11 +207,11 @@ impl WeightInfo for SubstrateWeight { fn create_pure(p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `173` - // Estimated: `3716` - // Minimum execution time: 22_764 nanoseconds. - Weight::from_parts(23_539_039, 3716) - // Standard Error: 814 - .saturating_add(Weight::from_parts(144, 0).saturating_mul(p.into())) + // Estimated: `4706` + // Minimum execution time: 25_864_000 picoseconds. + Weight::from_parts(26_712_232, 4706) + // Standard Error: 1_331 + .saturating_add(Weight::from_parts(4_401, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -217,12 +220,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `p` is `[0, 30]`. fn kill_pure(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `230 + p * (37 ±0)` - // Estimated: `3716` - // Minimum execution time: 17_720 nanoseconds. - Weight::from_parts(18_428_849, 3716) - // Standard Error: 1_093 - .saturating_add(Weight::from_parts(34_600, 0).saturating_mul(p.into())) + // Measured: `198 + p * (37 ±0)` + // Estimated: `4706` + // Minimum execution time: 20_488_000 picoseconds. + Weight::from_parts(21_135_155, 4706) + // Standard Error: 1_255 + .saturating_add(Weight::from_parts(36_312, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -235,12 +238,12 @@ impl WeightInfo for () { /// The range of component `p` is `[1, 31]`. fn proxy(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `193 + p * (37 ±0)` - // Estimated: `3716` - // Minimum execution time: 14_461 nanoseconds. - Weight::from_parts(14_913_927, 3716) - // Standard Error: 1_174 - .saturating_add(Weight::from_parts(36_087, 0).saturating_mul(p.into())) + // Measured: `161 + p * (37 ±0)` + // Estimated: `4706` + // Minimum execution time: 16_407_000 picoseconds. + Weight::from_parts(17_044_509, 4706) + // Standard Error: 1_177 + .saturating_add(Weight::from_parts(36_533, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: Proxy Proxies (r:1 w:0) @@ -253,14 +256,14 @@ impl WeightInfo for () { /// The range of component `p` is `[1, 31]`. fn proxy_announced(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `584 + a * (68 ±0) + p * (37 ±0)` - // Estimated: `11027` - // Minimum execution time: 31_523 nanoseconds. - Weight::from_parts(31_116_270, 11027) - // Standard Error: 1_789 - .saturating_add(Weight::from_parts(135_656, 0).saturating_mul(a.into())) - // Standard Error: 1_849 - .saturating_add(Weight::from_parts(53_893, 0).saturating_mul(p.into())) + // Measured: `488 + a * (68 ±0) + p * (37 ±0)` + // Estimated: `13997` + // Minimum execution time: 38_523_000 picoseconds. + Weight::from_parts(39_227_232, 13997) + // Standard Error: 5_703 + .saturating_add(Weight::from_parts(136_003, 0).saturating_mul(a.into())) + // Standard Error: 5_893 + .saturating_add(Weight::from_parts(42_397, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -272,14 +275,14 @@ impl WeightInfo for () { /// The range of component `p` is `[1, 31]`. fn remove_announcement(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `467 + a * (68 ±0)` - // Estimated: `7311` - // Minimum execution time: 19_363 nanoseconds. - Weight::from_parts(20_282_191, 7311) - // Standard Error: 1_084 - .saturating_add(Weight::from_parts(133_825, 0).saturating_mul(a.into())) - // Standard Error: 1_120 - .saturating_add(Weight::from_parts(3_434, 0).saturating_mul(p.into())) + // Measured: `403 + a * (68 ±0)` + // Estimated: `9291` + // Minimum execution time: 22_541_000 picoseconds. + Weight::from_parts(23_402_268, 9291) + // Standard Error: 3_242 + .saturating_add(Weight::from_parts(178_017, 0).saturating_mul(a.into())) + // Standard Error: 3_349 + .saturating_add(Weight::from_parts(6_230, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -291,14 +294,14 @@ impl WeightInfo for () { /// The range of component `p` is `[1, 31]`. fn reject_announcement(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `467 + a * (68 ±0)` - // Estimated: `7311` - // Minimum execution time: 19_363 nanoseconds. - Weight::from_parts(20_211_584, 7311) - // Standard Error: 1_171 - .saturating_add(Weight::from_parts(136_984, 0).saturating_mul(a.into())) - // Standard Error: 1_210 - .saturating_add(Weight::from_parts(3_686, 0).saturating_mul(p.into())) + // Measured: `403 + a * (68 ±0)` + // Estimated: `9291` + // Minimum execution time: 22_539_000 picoseconds. + Weight::from_parts(23_479_286, 9291) + // Standard Error: 1_329 + .saturating_add(Weight::from_parts(174_021, 0).saturating_mul(a.into())) + // Standard Error: 1_373 + .saturating_add(Weight::from_parts(6_465, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -312,14 +315,14 @@ impl WeightInfo for () { /// The range of component `p` is `[1, 31]`. fn announce(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `516 + a * (68 ±0) + p * (37 ±0)` - // Estimated: `11027` - // Minimum execution time: 27_811 nanoseconds. - Weight::from_parts(27_965_813, 11027) - // Standard Error: 1_987 - .saturating_add(Weight::from_parts(124_133, 0).saturating_mul(a.into())) - // Standard Error: 2_053 - .saturating_add(Weight::from_parts(54_692, 0).saturating_mul(p.into())) + // Measured: `420 + a * (68 ±0) + p * (37 ±0)` + // Estimated: `13997` + // Minimum execution time: 32_049_000 picoseconds. + Weight::from_parts(35_352_453, 13997) + // Standard Error: 4_389 + .saturating_add(Weight::from_parts(144_573, 0).saturating_mul(a.into())) + // Standard Error: 4_535 + .saturating_add(Weight::from_parts(41_849, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -328,12 +331,12 @@ impl WeightInfo for () { /// The range of component `p` is `[1, 31]`. fn add_proxy(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `193 + p * (37 ±0)` - // Estimated: `3716` - // Minimum execution time: 20_922 nanoseconds. - Weight::from_parts(21_551_797, 3716) - // Standard Error: 1_425 - .saturating_add(Weight::from_parts(58_434, 0).saturating_mul(p.into())) + // Measured: `161 + p * (37 ±0)` + // Estimated: `4706` + // Minimum execution time: 24_491_000 picoseconds. + Weight::from_parts(25_291_582, 4706) + // Standard Error: 11_080 + .saturating_add(Weight::from_parts(68_024, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -342,12 +345,12 @@ impl WeightInfo for () { /// The range of component `p` is `[1, 31]`. fn remove_proxy(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `193 + p * (37 ±0)` - // Estimated: `3716` - // Minimum execution time: 20_812 nanoseconds. - Weight::from_parts(21_660_732, 3716) - // Standard Error: 1_438 - .saturating_add(Weight::from_parts(68_740, 0).saturating_mul(p.into())) + // Measured: `161 + p * (37 ±0)` + // Estimated: `4706` + // Minimum execution time: 23_849_000 picoseconds. + Weight::from_parts(25_370_806, 4706) + // Standard Error: 8_763 + .saturating_add(Weight::from_parts(63_413, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -356,12 +359,12 @@ impl WeightInfo for () { /// The range of component `p` is `[1, 31]`. fn remove_proxies(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `193 + p * (37 ±0)` - // Estimated: `3716` - // Minimum execution time: 16_786 nanoseconds. - Weight::from_parts(17_249_958, 3716) - // Standard Error: 1_007 - .saturating_add(Weight::from_parts(37_546, 0).saturating_mul(p.into())) + // Measured: `161 + p * (37 ±0)` + // Estimated: `4706` + // Minimum execution time: 19_488_000 picoseconds. + Weight::from_parts(20_219_817, 4706) + // Standard Error: 1_385 + .saturating_add(Weight::from_parts(30_354, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -371,11 +374,11 @@ impl WeightInfo for () { fn create_pure(p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `173` - // Estimated: `3716` - // Minimum execution time: 22_764 nanoseconds. - Weight::from_parts(23_539_039, 3716) - // Standard Error: 814 - .saturating_add(Weight::from_parts(144, 0).saturating_mul(p.into())) + // Estimated: `4706` + // Minimum execution time: 25_864_000 picoseconds. + Weight::from_parts(26_712_232, 4706) + // Standard Error: 1_331 + .saturating_add(Weight::from_parts(4_401, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -384,12 +387,12 @@ impl WeightInfo for () { /// The range of component `p` is `[0, 30]`. fn kill_pure(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `230 + p * (37 ±0)` - // Estimated: `3716` - // Minimum execution time: 17_720 nanoseconds. - Weight::from_parts(18_428_849, 3716) - // Standard Error: 1_093 - .saturating_add(Weight::from_parts(34_600, 0).saturating_mul(p.into())) + // Measured: `198 + p * (37 ±0)` + // Estimated: `4706` + // Minimum execution time: 20_488_000 picoseconds. + Weight::from_parts(21_135_155, 4706) + // Standard Error: 1_255 + .saturating_add(Weight::from_parts(36_312, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/frame/ranked-collective/src/weights.rs b/frame/ranked-collective/src/weights.rs index 8d6c1620d81f8..e25737a1df8f0 100644 --- a/frame/ranked-collective/src/weights.rs +++ b/frame/ranked-collective/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_ranked_collective //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,6 +31,9 @@ // --steps=50 // --repeat=20 // --pallet=pallet_ranked_collective +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -70,9 +73,9 @@ impl WeightInfo for SubstrateWeight { fn add_member() -> Weight { // Proof Size summary in bytes: // Measured: `109` - // Estimated: `5006` - // Minimum execution time: 16_334 nanoseconds. - Weight::from_parts(16_784_000, 5006) + // Estimated: `6986` + // Minimum execution time: 19_174_000 picoseconds. + Weight::from_parts(19_391_000, 6986) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -88,11 +91,11 @@ impl WeightInfo for SubstrateWeight { fn remove_member(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `583 + r * (281 ±0)` - // Estimated: `10064 + r * (7547 ±0)` - // Minimum execution time: 26_177 nanoseconds. - Weight::from_parts(29_245_248, 10064) - // Standard Error: 18_611 - .saturating_add(Weight::from_parts(10_916_516, 0).saturating_mul(r.into())) + // Estimated: `14024 + r * (7547 ±0)` + // Minimum execution time: 30_972_000 picoseconds. + Weight::from_parts(35_526_205, 14024) + // Standard Error: 47_832 + .saturating_add(Weight::from_parts(12_838_739, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(4_u64)) @@ -111,11 +114,11 @@ impl WeightInfo for SubstrateWeight { fn promote_member(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `281 + r * (17 ±0)` - // Estimated: `5006` - // Minimum execution time: 18_953 nanoseconds. - Weight::from_parts(19_570_567, 5006) - // Standard Error: 4_156 - .saturating_add(Weight::from_parts(263_843, 0).saturating_mul(r.into())) + // Estimated: `6986` + // Minimum execution time: 21_573_000 picoseconds. + Weight::from_parts(22_184_210, 6986) + // Standard Error: 10_584 + .saturating_add(Weight::from_parts(289_535, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -131,11 +134,11 @@ impl WeightInfo for SubstrateWeight { fn demote_member(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `599 + r * (72 ±0)` - // Estimated: `10064` - // Minimum execution time: 26_243 nanoseconds. - Weight::from_parts(28_532_816, 10064) - // Standard Error: 22_689 - .saturating_add(Weight::from_parts(614_464, 0).saturating_mul(r.into())) + // Estimated: `14024` + // Minimum execution time: 30_249_000 picoseconds. + Weight::from_parts(32_702_502, 14024) + // Standard Error: 26_725 + .saturating_add(Weight::from_parts(651_139, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -149,10 +152,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn vote() -> Weight { // Proof Size summary in bytes: - // Measured: `626` - // Estimated: `226856` - // Minimum execution time: 41_121 nanoseconds. - Weight::from_parts(41_606_000, 226856) + // Measured: `595` + // Estimated: `230816` + // Minimum execution time: 46_972_000 picoseconds. + Weight::from_parts(47_617_000, 230816) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -160,19 +163,21 @@ impl WeightInfo for SubstrateWeight { /// Proof: RankedPolls ReferendumInfoFor (max_values: None, max_size: Some(330), added: 2805, mode: MaxEncodedLen) /// Storage: RankedCollective VotingCleanup (r:1 w:0) /// Proof: RankedCollective VotingCleanup (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) - /// Storage: RankedCollective Voting (r:0 w:100) + /// Storage: RankedCollective Voting (r:100 w:100) /// Proof: RankedCollective Voting (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) /// The range of component `n` is `[0, 100]`. fn cleanup_poll(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `461 + n * (50 ±0)` - // Estimated: `5394` - // Minimum execution time: 13_245 nanoseconds. - Weight::from_parts(17_420_271, 5394) - // Standard Error: 1_503 - .saturating_add(Weight::from_parts(952_500, 0).saturating_mul(n.into())) + // Measured: `429 + n * (50 ±0)` + // Estimated: `8364 + n * (2540 ±0)` + // Minimum execution time: 15_301_000 picoseconds. + Weight::from_parts(19_308_613, 8364) + // Standard Error: 1_792 + .saturating_add(Weight::from_parts(1_015_251, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_parts(0, 2540).saturating_mul(n.into())) } } @@ -189,9 +194,9 @@ impl WeightInfo for () { fn add_member() -> Weight { // Proof Size summary in bytes: // Measured: `109` - // Estimated: `5006` - // Minimum execution time: 16_334 nanoseconds. - Weight::from_parts(16_784_000, 5006) + // Estimated: `6986` + // Minimum execution time: 19_174_000 picoseconds. + Weight::from_parts(19_391_000, 6986) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -207,11 +212,11 @@ impl WeightInfo for () { fn remove_member(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `583 + r * (281 ±0)` - // Estimated: `10064 + r * (7547 ±0)` - // Minimum execution time: 26_177 nanoseconds. - Weight::from_parts(29_245_248, 10064) - // Standard Error: 18_611 - .saturating_add(Weight::from_parts(10_916_516, 0).saturating_mul(r.into())) + // Estimated: `14024 + r * (7547 ±0)` + // Minimum execution time: 30_972_000 picoseconds. + Weight::from_parts(35_526_205, 14024) + // Standard Error: 47_832 + .saturating_add(Weight::from_parts(12_838_739, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(4_u64)) @@ -230,11 +235,11 @@ impl WeightInfo for () { fn promote_member(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `281 + r * (17 ±0)` - // Estimated: `5006` - // Minimum execution time: 18_953 nanoseconds. - Weight::from_parts(19_570_567, 5006) - // Standard Error: 4_156 - .saturating_add(Weight::from_parts(263_843, 0).saturating_mul(r.into())) + // Estimated: `6986` + // Minimum execution time: 21_573_000 picoseconds. + Weight::from_parts(22_184_210, 6986) + // Standard Error: 10_584 + .saturating_add(Weight::from_parts(289_535, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -250,11 +255,11 @@ impl WeightInfo for () { fn demote_member(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `599 + r * (72 ±0)` - // Estimated: `10064` - // Minimum execution time: 26_243 nanoseconds. - Weight::from_parts(28_532_816, 10064) - // Standard Error: 22_689 - .saturating_add(Weight::from_parts(614_464, 0).saturating_mul(r.into())) + // Estimated: `14024` + // Minimum execution time: 30_249_000 picoseconds. + Weight::from_parts(32_702_502, 14024) + // Standard Error: 26_725 + .saturating_add(Weight::from_parts(651_139, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -268,10 +273,10 @@ impl WeightInfo for () { /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn vote() -> Weight { // Proof Size summary in bytes: - // Measured: `626` - // Estimated: `226856` - // Minimum execution time: 41_121 nanoseconds. - Weight::from_parts(41_606_000, 226856) + // Measured: `595` + // Estimated: `230816` + // Minimum execution time: 46_972_000 picoseconds. + Weight::from_parts(47_617_000, 230816) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -279,18 +284,20 @@ impl WeightInfo for () { /// Proof: RankedPolls ReferendumInfoFor (max_values: None, max_size: Some(330), added: 2805, mode: MaxEncodedLen) /// Storage: RankedCollective VotingCleanup (r:1 w:0) /// Proof: RankedCollective VotingCleanup (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) - /// Storage: RankedCollective Voting (r:0 w:100) + /// Storage: RankedCollective Voting (r:100 w:100) /// Proof: RankedCollective Voting (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) /// The range of component `n` is `[0, 100]`. fn cleanup_poll(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `461 + n * (50 ±0)` - // Estimated: `5394` - // Minimum execution time: 13_245 nanoseconds. - Weight::from_parts(17_420_271, 5394) - // Standard Error: 1_503 - .saturating_add(Weight::from_parts(952_500, 0).saturating_mul(n.into())) + // Measured: `429 + n * (50 ±0)` + // Estimated: `8364 + n * (2540 ±0)` + // Minimum execution time: 15_301_000 picoseconds. + Weight::from_parts(19_308_613, 8364) + // Standard Error: 1_792 + .saturating_add(Weight::from_parts(1_015_251, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_parts(0, 2540).saturating_mul(n.into())) } } diff --git a/frame/recovery/src/weights.rs b/frame/recovery/src/weights.rs index 6f8818f819bad..8245b9606deee 100644 --- a/frame/recovery/src/weights.rs +++ b/frame/recovery/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_recovery //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,6 +31,9 @@ // --steps=50 // --repeat=20 // --pallet=pallet_recovery +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -67,9 +70,9 @@ impl WeightInfo for SubstrateWeight { fn as_recovered() -> Weight { // Proof Size summary in bytes: // Measured: `281` - // Estimated: `2555` - // Minimum execution time: 8_866 nanoseconds. - Weight::from_parts(9_065_000, 2555) + // Estimated: `3545` + // Minimum execution time: 9_937_000 picoseconds. + Weight::from_parts(10_213_000, 3545) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: Recovery Proxy (r:0 w:1) @@ -78,8 +81,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_893 nanoseconds. - Weight::from_parts(9_177_000, 0) + // Minimum execution time: 9_704_000 picoseconds. + Weight::from_parts(9_997_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Recovery Recoverable (r:1 w:1) @@ -88,11 +91,11 @@ impl WeightInfo for SubstrateWeight { fn create_recovery(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `175` - // Estimated: `2826` - // Minimum execution time: 20_662 nanoseconds. - Weight::from_parts(21_378_064, 2826) - // Standard Error: 3_350 - .saturating_add(Weight::from_parts(83_738, 0).saturating_mul(n.into())) + // Estimated: `3816` + // Minimum execution time: 23_260_000 picoseconds. + Weight::from_parts(24_408_081, 3816) + // Standard Error: 3_086 + .saturating_add(Weight::from_parts(41_628, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -103,9 +106,9 @@ impl WeightInfo for SubstrateWeight { fn initiate_recovery() -> Weight { // Proof Size summary in bytes: // Measured: `272` - // Estimated: `5690` - // Minimum execution time: 24_805 nanoseconds. - Weight::from_parts(25_273_000, 5690) + // Estimated: `7670` + // Minimum execution time: 28_148_000 picoseconds. + Weight::from_parts(28_577_000, 7670) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -116,12 +119,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[1, 9]`. fn vouch_recovery(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `423 + n * (64 ±0)` - // Estimated: `5690` - // Minimum execution time: 17_837 nanoseconds. - Weight::from_parts(18_429_664, 5690) - // Standard Error: 3_187 - .saturating_add(Weight::from_parts(143_648, 0).saturating_mul(n.into())) + // Measured: `360 + n * (64 ±0)` + // Estimated: `7670` + // Minimum execution time: 20_395_000 picoseconds. + Weight::from_parts(21_287_972, 7670) + // Standard Error: 4_464 + .saturating_add(Weight::from_parts(170_214, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -134,12 +137,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[1, 9]`. fn claim_recovery(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `455 + n * (64 ±0)` - // Estimated: `8245` - // Minimum execution time: 21_960 nanoseconds. - Weight::from_parts(22_529_644, 8245) - // Standard Error: 2_945 - .saturating_add(Weight::from_parts(85_604, 0).saturating_mul(n.into())) + // Measured: `392 + n * (64 ±0)` + // Estimated: `11215` + // Minimum execution time: 24_902_000 picoseconds. + Weight::from_parts(25_662_621, 11215) + // Standard Error: 3_101 + .saturating_add(Weight::from_parts(60_748, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -150,12 +153,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[1, 9]`. fn close_recovery(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `576 + n * (32 ±0)` - // Estimated: `5467` - // Minimum execution time: 26_054 nanoseconds. - Weight::from_parts(26_724_866, 5467) - // Standard Error: 2_645 - .saturating_add(Weight::from_parts(104_301, 0).saturating_mul(n.into())) + // Measured: `513 + n * (32 ±0)` + // Estimated: `7447` + // Minimum execution time: 30_071_000 picoseconds. + Weight::from_parts(30_727_760, 7447) + // Standard Error: 4_442 + .saturating_add(Weight::from_parts(98_153, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -164,14 +167,12 @@ impl WeightInfo for SubstrateWeight { /// Storage: Recovery Recoverable (r:1 w:1) /// Proof: Recovery Recoverable (max_values: None, max_size: Some(351), added: 2826, mode: MaxEncodedLen) /// The range of component `n` is `[1, 9]`. - fn remove_recovery(n: u32, ) -> Weight { + fn remove_recovery(_n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `302 + n * (32 ±0)` - // Estimated: `5690` - // Minimum execution time: 25_110 nanoseconds. - Weight::from_parts(25_805_837, 5690) - // Standard Error: 2_732 - .saturating_add(Weight::from_parts(73_458, 0).saturating_mul(n.into())) + // Measured: `270 + n * (32 ±0)` + // Estimated: `7670` + // Minimum execution time: 29_088_000 picoseconds. + Weight::from_parts(30_535_744, 7670) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -180,9 +181,9 @@ impl WeightInfo for SubstrateWeight { fn cancel_recovered() -> Weight { // Proof Size summary in bytes: // Measured: `281` - // Estimated: `2555` - // Minimum execution time: 11_061 nanoseconds. - Weight::from_parts(11_291_000, 2555) + // Estimated: `3545` + // Minimum execution time: 12_712_000 picoseconds. + Weight::from_parts(12_980_000, 3545) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -195,9 +196,9 @@ impl WeightInfo for () { fn as_recovered() -> Weight { // Proof Size summary in bytes: // Measured: `281` - // Estimated: `2555` - // Minimum execution time: 8_866 nanoseconds. - Weight::from_parts(9_065_000, 2555) + // Estimated: `3545` + // Minimum execution time: 9_937_000 picoseconds. + Weight::from_parts(10_213_000, 3545) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: Recovery Proxy (r:0 w:1) @@ -206,8 +207,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_893 nanoseconds. - Weight::from_parts(9_177_000, 0) + // Minimum execution time: 9_704_000 picoseconds. + Weight::from_parts(9_997_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Recovery Recoverable (r:1 w:1) @@ -216,11 +217,11 @@ impl WeightInfo for () { fn create_recovery(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `175` - // Estimated: `2826` - // Minimum execution time: 20_662 nanoseconds. - Weight::from_parts(21_378_064, 2826) - // Standard Error: 3_350 - .saturating_add(Weight::from_parts(83_738, 0).saturating_mul(n.into())) + // Estimated: `3816` + // Minimum execution time: 23_260_000 picoseconds. + Weight::from_parts(24_408_081, 3816) + // Standard Error: 3_086 + .saturating_add(Weight::from_parts(41_628, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -231,9 +232,9 @@ impl WeightInfo for () { fn initiate_recovery() -> Weight { // Proof Size summary in bytes: // Measured: `272` - // Estimated: `5690` - // Minimum execution time: 24_805 nanoseconds. - Weight::from_parts(25_273_000, 5690) + // Estimated: `7670` + // Minimum execution time: 28_148_000 picoseconds. + Weight::from_parts(28_577_000, 7670) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -244,12 +245,12 @@ impl WeightInfo for () { /// The range of component `n` is `[1, 9]`. fn vouch_recovery(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `423 + n * (64 ±0)` - // Estimated: `5690` - // Minimum execution time: 17_837 nanoseconds. - Weight::from_parts(18_429_664, 5690) - // Standard Error: 3_187 - .saturating_add(Weight::from_parts(143_648, 0).saturating_mul(n.into())) + // Measured: `360 + n * (64 ±0)` + // Estimated: `7670` + // Minimum execution time: 20_395_000 picoseconds. + Weight::from_parts(21_287_972, 7670) + // Standard Error: 4_464 + .saturating_add(Weight::from_parts(170_214, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -262,12 +263,12 @@ impl WeightInfo for () { /// The range of component `n` is `[1, 9]`. fn claim_recovery(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `455 + n * (64 ±0)` - // Estimated: `8245` - // Minimum execution time: 21_960 nanoseconds. - Weight::from_parts(22_529_644, 8245) - // Standard Error: 2_945 - .saturating_add(Weight::from_parts(85_604, 0).saturating_mul(n.into())) + // Measured: `392 + n * (64 ±0)` + // Estimated: `11215` + // Minimum execution time: 24_902_000 picoseconds. + Weight::from_parts(25_662_621, 11215) + // Standard Error: 3_101 + .saturating_add(Weight::from_parts(60_748, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -278,12 +279,12 @@ impl WeightInfo for () { /// The range of component `n` is `[1, 9]`. fn close_recovery(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `576 + n * (32 ±0)` - // Estimated: `5467` - // Minimum execution time: 26_054 nanoseconds. - Weight::from_parts(26_724_866, 5467) - // Standard Error: 2_645 - .saturating_add(Weight::from_parts(104_301, 0).saturating_mul(n.into())) + // Measured: `513 + n * (32 ±0)` + // Estimated: `7447` + // Minimum execution time: 30_071_000 picoseconds. + Weight::from_parts(30_727_760, 7447) + // Standard Error: 4_442 + .saturating_add(Weight::from_parts(98_153, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -292,14 +293,12 @@ impl WeightInfo for () { /// Storage: Recovery Recoverable (r:1 w:1) /// Proof: Recovery Recoverable (max_values: None, max_size: Some(351), added: 2826, mode: MaxEncodedLen) /// The range of component `n` is `[1, 9]`. - fn remove_recovery(n: u32, ) -> Weight { + fn remove_recovery(_n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `302 + n * (32 ±0)` - // Estimated: `5690` - // Minimum execution time: 25_110 nanoseconds. - Weight::from_parts(25_805_837, 5690) - // Standard Error: 2_732 - .saturating_add(Weight::from_parts(73_458, 0).saturating_mul(n.into())) + // Measured: `270 + n * (32 ±0)` + // Estimated: `7670` + // Minimum execution time: 29_088_000 picoseconds. + Weight::from_parts(30_535_744, 7670) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -308,9 +307,9 @@ impl WeightInfo for () { fn cancel_recovered() -> Weight { // Proof Size summary in bytes: // Measured: `281` - // Estimated: `2555` - // Minimum execution time: 11_061 nanoseconds. - Weight::from_parts(11_291_000, 2555) + // Estimated: `3545` + // Minimum execution time: 12_712_000 picoseconds. + Weight::from_parts(12_980_000, 3545) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/frame/referenda/src/weights.rs b/frame/referenda/src/weights.rs index 817e0d88d329d..3ac0f54ed8307 100644 --- a/frame/referenda/src/weights.rs +++ b/frame/referenda/src/weights.rs @@ -18,26 +18,28 @@ //! Autogenerated weights for pallet_referenda //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-01-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-b3zmxxc-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! 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 // --steps=50 // --repeat=20 +// --pallet=pallet_referenda +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --json-file=/builds/parity/mirrors/substrate/.git/.artifacts/bench.json -// --pallet=pallet_referenda -// --chain=dev -// --header=./HEADER-APACHE2 // --output=./frame/referenda/src/weights.rs +// --header=./HEADER-APACHE2 // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -92,10 +94,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) fn submit() -> Weight { // Proof Size summary in bytes: - // Measured: `251` - // Estimated: `109996` - // Minimum execution time: 34_540 nanoseconds. - Weight::from_parts(36_144_000, 109996) + // Measured: `220` + // Estimated: `111976` + // Minimum execution time: 36_851_000 picoseconds. + Weight::from_parts(37_183_000, 111976) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -105,10 +107,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn place_decision_deposit_preparing() -> Weight { // Proof Size summary in bytes: - // Measured: `536` - // Estimated: `221835` - // Minimum execution time: 46_963 nanoseconds. - Weight::from_parts(48_459_000, 221835) + // Measured: `473` + // Estimated: `223815` + // Minimum execution time: 49_435_000 picoseconds. + Weight::from_parts(50_056_000, 223815) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -120,10 +122,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Referenda TrackQueue (max_values: None, max_size: Some(2012), added: 4487, mode: MaxEncodedLen) fn place_decision_deposit_queued() -> Weight { // Proof Size summary in bytes: - // Measured: `3203` - // Estimated: `9817` - // Minimum execution time: 55_798 nanoseconds. - Weight::from_parts(58_260_000, 9817) + // Measured: `3107` + // Estimated: `12787` + // Minimum execution time: 47_061_000 picoseconds. + Weight::from_parts(47_579_000, 12787) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -135,10 +137,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Referenda TrackQueue (max_values: None, max_size: Some(2012), added: 4487, mode: MaxEncodedLen) fn place_decision_deposit_not_queued() -> Weight { // Proof Size summary in bytes: - // Measured: `3223` - // Estimated: `9817` - // Minimum execution time: 53_888 nanoseconds. - Weight::from_parts(57_919_000, 9817) + // Measured: `3127` + // Estimated: `12787` + // Minimum execution time: 46_513_000 picoseconds. + Weight::from_parts(47_212_000, 12787) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -150,10 +152,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn place_decision_deposit_passing() -> Weight { // Proof Size summary in bytes: - // Measured: `536` - // Estimated: `224324` - // Minimum execution time: 56_121 nanoseconds. - Weight::from_parts(58_301_000, 224324) + // Measured: `473` + // Estimated: `227294` + // Minimum execution time: 59_255_000 picoseconds. + Weight::from_parts(60_114_000, 227294) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -165,10 +167,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn place_decision_deposit_failing() -> Weight { // Proof Size summary in bytes: - // Measured: `536` - // Estimated: `224324` - // Minimum execution time: 54_237 nanoseconds. - Weight::from_parts(55_681_000, 224324) + // Measured: `473` + // Estimated: `227294` + // Minimum execution time: 57_927_000 picoseconds. + Weight::from_parts(58_625_000, 227294) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -176,10 +178,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) fn refund_decision_deposit() -> Weight { // Proof Size summary in bytes: - // Measured: `415` - // Estimated: `2841` - // Minimum execution time: 25_734 nanoseconds. - Weight::from_parts(26_429_000, 2841) + // Measured: `351` + // Estimated: `3831` + // Minimum execution time: 27_186_000 picoseconds. + Weight::from_parts(27_551_000, 3831) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -187,10 +189,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) fn refund_submission_deposit() -> Weight { // Proof Size summary in bytes: - // Measured: `405` - // Estimated: `2841` - // Minimum execution time: 26_000 nanoseconds. - Weight::from_parts(26_786_000, 2841) + // Measured: `341` + // Estimated: `3831` + // Minimum execution time: 27_339_000 picoseconds. + Weight::from_parts(27_828_000, 3831) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -200,10 +202,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn cancel() -> Weight { // Proof Size summary in bytes: - // Measured: `412` - // Estimated: `221835` - // Minimum execution time: 34_567 nanoseconds. - Weight::from_parts(35_939_000, 221835) + // Measured: `381` + // Estimated: `223815` + // Minimum execution time: 37_081_000 picoseconds. + Weight::from_parts(38_110_000, 223815) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -215,10 +217,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Referenda MetadataOf (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) fn kill() -> Weight { // Proof Size summary in bytes: - // Measured: `717` - // Estimated: `224362` - // Minimum execution time: 67_744 nanoseconds. - Weight::from_parts(70_047_000, 224362) + // Measured: `622` + // Estimated: `227332` + // Minimum execution time: 70_195_000 picoseconds. + Weight::from_parts(71_451_000, 227332) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -229,9 +231,9 @@ impl WeightInfo for SubstrateWeight { fn one_fewer_deciding_queue_empty() -> Weight { // Proof Size summary in bytes: // Measured: `174` - // Estimated: `6976` - // Minimum execution time: 9_886 nanoseconds. - Weight::from_parts(10_406_000, 6976) + // Estimated: `8956` + // Minimum execution time: 10_748_000 picoseconds. + Weight::from_parts(10_912_000, 8956) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -243,10 +245,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn one_fewer_deciding_failing() -> Weight { // Proof Size summary in bytes: - // Measured: `4661` - // Estimated: `226322` - // Minimum execution time: 100_449 nanoseconds. - Weight::from_parts(101_812_000, 226322) + // Measured: `4567` + // Estimated: `229292` + // Minimum execution time: 89_144_000 picoseconds. + Weight::from_parts(90_552_000, 229292) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -258,10 +260,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn one_fewer_deciding_passing() -> Weight { // Proof Size summary in bytes: - // Measured: `4661` - // Estimated: `226322` - // Minimum execution time: 101_430 nanoseconds. - Weight::from_parts(103_704_000, 226322) + // Measured: `4567` + // Estimated: `229292` + // Minimum execution time: 92_164_000 picoseconds. + Weight::from_parts(92_947_000, 229292) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -273,10 +275,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_requeued_insertion() -> Weight { // Proof Size summary in bytes: - // Measured: `4682` - // Estimated: `116825` - // Minimum execution time: 67_224 nanoseconds. - Weight::from_parts(70_596_000, 116825) + // Measured: `4588` + // Estimated: `119795` + // Minimum execution time: 59_212_000 picoseconds. + Weight::from_parts(59_843_000, 119795) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -288,10 +290,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_requeued_slide() -> Weight { // Proof Size summary in bytes: - // Measured: `4668` - // Estimated: `116825` - // Minimum execution time: 65_461 nanoseconds. - Weight::from_parts(69_624_000, 116825) + // Measured: `4574` + // Estimated: `119795` + // Minimum execution time: 59_049_000 picoseconds. + Weight::from_parts(59_760_000, 119795) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -305,10 +307,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_queued() -> Weight { // Proof Size summary in bytes: - // Measured: `4642` - // Estimated: `119314` - // Minimum execution time: 69_848 nanoseconds. - Weight::from_parts(74_480_000, 119314) + // Measured: `4548` + // Estimated: `123274` + // Minimum execution time: 61_774_000 picoseconds. + Weight::from_parts(62_480_000, 123274) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -322,10 +324,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_not_queued() -> Weight { // Proof Size summary in bytes: - // Measured: `4676` - // Estimated: `119314` - // Minimum execution time: 70_042 nanoseconds. - Weight::from_parts(72_912_000, 119314) + // Measured: `4582` + // Estimated: `123274` + // Minimum execution time: 61_605_000 picoseconds. + Weight::from_parts(62_385_000, 123274) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -335,10 +337,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_no_deposit() -> Weight { // Proof Size summary in bytes: - // Measured: `364` - // Estimated: `112338` - // Minimum execution time: 23_008 nanoseconds. - Weight::from_parts(23_767_000, 112338) + // Measured: `333` + // Estimated: `114318` + // Minimum execution time: 24_423_000 picoseconds. + Weight::from_parts(24_747_000, 114318) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -348,10 +350,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_preparing() -> Weight { // Proof Size summary in bytes: - // Measured: `412` - // Estimated: `112338` - // Minimum execution time: 23_550 nanoseconds. - Weight::from_parts(24_081_000, 112338) + // Measured: `381` + // Estimated: `114318` + // Minimum execution time: 24_487_000 picoseconds. + Weight::from_parts(24_941_000, 114318) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -359,10 +361,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) fn nudge_referendum_timed_out() -> Weight { // Proof Size summary in bytes: - // Measured: `310` - // Estimated: `2841` - // Minimum execution time: 15_850 nanoseconds. - Weight::from_parts(16_773_000, 2841) + // Measured: `278` + // Estimated: `3831` + // Minimum execution time: 17_454_000 picoseconds. + Weight::from_parts(17_697_000, 3831) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -374,10 +376,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_begin_deciding_failing() -> Weight { // Proof Size summary in bytes: - // Measured: `412` - // Estimated: `114827` - // Minimum execution time: 32_126 nanoseconds. - Weight::from_parts(33_313_000, 114827) + // Measured: `381` + // Estimated: `117797` + // Minimum execution time: 34_721_000 picoseconds. + Weight::from_parts(35_295_000, 117797) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -389,10 +391,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_begin_deciding_passing() -> Weight { // Proof Size summary in bytes: - // Measured: `412` - // Estimated: `114827` - // Minimum execution time: 34_698 nanoseconds. - Weight::from_parts(35_802_000, 114827) + // Measured: `381` + // Estimated: `117797` + // Minimum execution time: 36_587_000 picoseconds. + Weight::from_parts(37_095_000, 117797) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -402,10 +404,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_begin_confirming() -> Weight { // Proof Size summary in bytes: - // Measured: `465` - // Estimated: `112338` - // Minimum execution time: 28_710 nanoseconds. - Weight::from_parts(29_574_000, 112338) + // Measured: `434` + // Estimated: `114318` + // Minimum execution time: 30_003_000 picoseconds. + Weight::from_parts(30_541_000, 114318) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -415,10 +417,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_end_confirming() -> Weight { // Proof Size summary in bytes: - // Measured: `448` - // Estimated: `112338` - // Minimum execution time: 29_030 nanoseconds. - Weight::from_parts(30_308_000, 112338) + // Measured: `417` + // Estimated: `114318` + // Minimum execution time: 30_479_000 picoseconds. + Weight::from_parts(30_900_000, 114318) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -428,10 +430,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_continue_not_confirming() -> Weight { // Proof Size summary in bytes: - // Measured: `465` - // Estimated: `112338` - // Minimum execution time: 26_382 nanoseconds. - Weight::from_parts(27_219_000, 112338) + // Measured: `434` + // Estimated: `114318` + // Minimum execution time: 27_657_000 picoseconds. + Weight::from_parts(28_054_000, 114318) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -441,10 +443,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_continue_confirming() -> Weight { // Proof Size summary in bytes: - // Measured: `469` - // Estimated: `112338` - // Minimum execution time: 25_445 nanoseconds. - Weight::from_parts(26_010_000, 112338) + // Measured: `438` + // Estimated: `114318` + // Minimum execution time: 26_713_000 picoseconds. + Weight::from_parts(27_284_000, 114318) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -456,10 +458,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Scheduler Lookup (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) fn nudge_referendum_approved() -> Weight { // Proof Size summary in bytes: - // Measured: `469` - // Estimated: `224358` - // Minimum execution time: 41_064 nanoseconds. - Weight::from_parts(42_895_000, 224358) + // Measured: `438` + // Estimated: `227328` + // Minimum execution time: 42_374_000 picoseconds. + Weight::from_parts(43_142_000, 227328) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -469,10 +471,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_rejected() -> Weight { // Proof Size summary in bytes: - // Measured: `465` - // Estimated: `112338` - // Minimum execution time: 29_472 nanoseconds. - Weight::from_parts(30_011_000, 112338) + // Measured: `434` + // Estimated: `114318` + // Minimum execution time: 30_213_000 picoseconds. + Weight::from_parts(30_633_000, 114318) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -484,10 +486,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Referenda MetadataOf (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) fn set_some_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `454` - // Estimated: `5407` - // Minimum execution time: 19_389 nanoseconds. - Weight::from_parts(20_490_000, 5407) + // Measured: `422` + // Estimated: `7387` + // Minimum execution time: 20_887_000 picoseconds. + Weight::from_parts(21_242_000, 7387) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -497,10 +499,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Referenda MetadataOf (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) fn clear_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `387` - // Estimated: `5368` - // Minimum execution time: 18_195 nanoseconds. - Weight::from_parts(19_917_000, 5368) + // Measured: `355` + // Estimated: `7348` + // Minimum execution time: 18_702_000 picoseconds. + Weight::from_parts(18_880_000, 7348) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -516,10 +518,10 @@ impl WeightInfo for () { /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) fn submit() -> Weight { // Proof Size summary in bytes: - // Measured: `251` - // Estimated: `109996` - // Minimum execution time: 34_540 nanoseconds. - Weight::from_parts(36_144_000, 109996) + // Measured: `220` + // Estimated: `111976` + // Minimum execution time: 36_851_000 picoseconds. + Weight::from_parts(37_183_000, 111976) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -529,10 +531,10 @@ impl WeightInfo for () { /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn place_decision_deposit_preparing() -> Weight { // Proof Size summary in bytes: - // Measured: `536` - // Estimated: `221835` - // Minimum execution time: 46_963 nanoseconds. - Weight::from_parts(48_459_000, 221835) + // Measured: `473` + // Estimated: `223815` + // Minimum execution time: 49_435_000 picoseconds. + Weight::from_parts(50_056_000, 223815) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -544,10 +546,10 @@ impl WeightInfo for () { /// Proof: Referenda TrackQueue (max_values: None, max_size: Some(2012), added: 4487, mode: MaxEncodedLen) fn place_decision_deposit_queued() -> Weight { // Proof Size summary in bytes: - // Measured: `3203` - // Estimated: `9817` - // Minimum execution time: 55_798 nanoseconds. - Weight::from_parts(58_260_000, 9817) + // Measured: `3107` + // Estimated: `12787` + // Minimum execution time: 47_061_000 picoseconds. + Weight::from_parts(47_579_000, 12787) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -559,10 +561,10 @@ impl WeightInfo for () { /// Proof: Referenda TrackQueue (max_values: None, max_size: Some(2012), added: 4487, mode: MaxEncodedLen) fn place_decision_deposit_not_queued() -> Weight { // Proof Size summary in bytes: - // Measured: `3223` - // Estimated: `9817` - // Minimum execution time: 53_888 nanoseconds. - Weight::from_parts(57_919_000, 9817) + // Measured: `3127` + // Estimated: `12787` + // Minimum execution time: 46_513_000 picoseconds. + Weight::from_parts(47_212_000, 12787) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -574,10 +576,10 @@ impl WeightInfo for () { /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn place_decision_deposit_passing() -> Weight { // Proof Size summary in bytes: - // Measured: `536` - // Estimated: `224324` - // Minimum execution time: 56_121 nanoseconds. - Weight::from_parts(58_301_000, 224324) + // Measured: `473` + // Estimated: `227294` + // Minimum execution time: 59_255_000 picoseconds. + Weight::from_parts(60_114_000, 227294) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -589,10 +591,10 @@ impl WeightInfo for () { /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn place_decision_deposit_failing() -> Weight { // Proof Size summary in bytes: - // Measured: `536` - // Estimated: `224324` - // Minimum execution time: 54_237 nanoseconds. - Weight::from_parts(55_681_000, 224324) + // Measured: `473` + // Estimated: `227294` + // Minimum execution time: 57_927_000 picoseconds. + Weight::from_parts(58_625_000, 227294) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -600,10 +602,10 @@ impl WeightInfo for () { /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) fn refund_decision_deposit() -> Weight { // Proof Size summary in bytes: - // Measured: `415` - // Estimated: `2841` - // Minimum execution time: 25_734 nanoseconds. - Weight::from_parts(26_429_000, 2841) + // Measured: `351` + // Estimated: `3831` + // Minimum execution time: 27_186_000 picoseconds. + Weight::from_parts(27_551_000, 3831) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -611,10 +613,10 @@ impl WeightInfo for () { /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) fn refund_submission_deposit() -> Weight { // Proof Size summary in bytes: - // Measured: `405` - // Estimated: `2841` - // Minimum execution time: 26_000 nanoseconds. - Weight::from_parts(26_786_000, 2841) + // Measured: `341` + // Estimated: `3831` + // Minimum execution time: 27_339_000 picoseconds. + Weight::from_parts(27_828_000, 3831) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -624,10 +626,10 @@ impl WeightInfo for () { /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn cancel() -> Weight { // Proof Size summary in bytes: - // Measured: `412` - // Estimated: `221835` - // Minimum execution time: 34_567 nanoseconds. - Weight::from_parts(35_939_000, 221835) + // Measured: `381` + // Estimated: `223815` + // Minimum execution time: 37_081_000 picoseconds. + Weight::from_parts(38_110_000, 223815) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -639,10 +641,10 @@ impl WeightInfo for () { /// Proof: Referenda MetadataOf (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) fn kill() -> Weight { // Proof Size summary in bytes: - // Measured: `717` - // Estimated: `224362` - // Minimum execution time: 67_744 nanoseconds. - Weight::from_parts(70_047_000, 224362) + // Measured: `622` + // Estimated: `227332` + // Minimum execution time: 70_195_000 picoseconds. + Weight::from_parts(71_451_000, 227332) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -653,9 +655,9 @@ impl WeightInfo for () { fn one_fewer_deciding_queue_empty() -> Weight { // Proof Size summary in bytes: // Measured: `174` - // Estimated: `6976` - // Minimum execution time: 9_886 nanoseconds. - Weight::from_parts(10_406_000, 6976) + // Estimated: `8956` + // Minimum execution time: 10_748_000 picoseconds. + Weight::from_parts(10_912_000, 8956) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -667,10 +669,10 @@ impl WeightInfo for () { /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn one_fewer_deciding_failing() -> Weight { // Proof Size summary in bytes: - // Measured: `4661` - // Estimated: `226322` - // Minimum execution time: 100_449 nanoseconds. - Weight::from_parts(101_812_000, 226322) + // Measured: `4567` + // Estimated: `229292` + // Minimum execution time: 89_144_000 picoseconds. + Weight::from_parts(90_552_000, 229292) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -682,10 +684,10 @@ impl WeightInfo for () { /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn one_fewer_deciding_passing() -> Weight { // Proof Size summary in bytes: - // Measured: `4661` - // Estimated: `226322` - // Minimum execution time: 101_430 nanoseconds. - Weight::from_parts(103_704_000, 226322) + // Measured: `4567` + // Estimated: `229292` + // Minimum execution time: 92_164_000 picoseconds. + Weight::from_parts(92_947_000, 229292) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -697,10 +699,10 @@ impl WeightInfo for () { /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_requeued_insertion() -> Weight { // Proof Size summary in bytes: - // Measured: `4682` - // Estimated: `116825` - // Minimum execution time: 67_224 nanoseconds. - Weight::from_parts(70_596_000, 116825) + // Measured: `4588` + // Estimated: `119795` + // Minimum execution time: 59_212_000 picoseconds. + Weight::from_parts(59_843_000, 119795) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -712,10 +714,10 @@ impl WeightInfo for () { /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_requeued_slide() -> Weight { // Proof Size summary in bytes: - // Measured: `4668` - // Estimated: `116825` - // Minimum execution time: 65_461 nanoseconds. - Weight::from_parts(69_624_000, 116825) + // Measured: `4574` + // Estimated: `119795` + // Minimum execution time: 59_049_000 picoseconds. + Weight::from_parts(59_760_000, 119795) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -729,10 +731,10 @@ impl WeightInfo for () { /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_queued() -> Weight { // Proof Size summary in bytes: - // Measured: `4642` - // Estimated: `119314` - // Minimum execution time: 69_848 nanoseconds. - Weight::from_parts(74_480_000, 119314) + // Measured: `4548` + // Estimated: `123274` + // Minimum execution time: 61_774_000 picoseconds. + Weight::from_parts(62_480_000, 123274) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -746,10 +748,10 @@ impl WeightInfo for () { /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_not_queued() -> Weight { // Proof Size summary in bytes: - // Measured: `4676` - // Estimated: `119314` - // Minimum execution time: 70_042 nanoseconds. - Weight::from_parts(72_912_000, 119314) + // Measured: `4582` + // Estimated: `123274` + // Minimum execution time: 61_605_000 picoseconds. + Weight::from_parts(62_385_000, 123274) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -759,10 +761,10 @@ impl WeightInfo for () { /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_no_deposit() -> Weight { // Proof Size summary in bytes: - // Measured: `364` - // Estimated: `112338` - // Minimum execution time: 23_008 nanoseconds. - Weight::from_parts(23_767_000, 112338) + // Measured: `333` + // Estimated: `114318` + // Minimum execution time: 24_423_000 picoseconds. + Weight::from_parts(24_747_000, 114318) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -772,10 +774,10 @@ impl WeightInfo for () { /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_preparing() -> Weight { // Proof Size summary in bytes: - // Measured: `412` - // Estimated: `112338` - // Minimum execution time: 23_550 nanoseconds. - Weight::from_parts(24_081_000, 112338) + // Measured: `381` + // Estimated: `114318` + // Minimum execution time: 24_487_000 picoseconds. + Weight::from_parts(24_941_000, 114318) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -783,10 +785,10 @@ impl WeightInfo for () { /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) fn nudge_referendum_timed_out() -> Weight { // Proof Size summary in bytes: - // Measured: `310` - // Estimated: `2841` - // Minimum execution time: 15_850 nanoseconds. - Weight::from_parts(16_773_000, 2841) + // Measured: `278` + // Estimated: `3831` + // Minimum execution time: 17_454_000 picoseconds. + Weight::from_parts(17_697_000, 3831) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -798,10 +800,10 @@ impl WeightInfo for () { /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_begin_deciding_failing() -> Weight { // Proof Size summary in bytes: - // Measured: `412` - // Estimated: `114827` - // Minimum execution time: 32_126 nanoseconds. - Weight::from_parts(33_313_000, 114827) + // Measured: `381` + // Estimated: `117797` + // Minimum execution time: 34_721_000 picoseconds. + Weight::from_parts(35_295_000, 117797) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -813,10 +815,10 @@ impl WeightInfo for () { /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_begin_deciding_passing() -> Weight { // Proof Size summary in bytes: - // Measured: `412` - // Estimated: `114827` - // Minimum execution time: 34_698 nanoseconds. - Weight::from_parts(35_802_000, 114827) + // Measured: `381` + // Estimated: `117797` + // Minimum execution time: 36_587_000 picoseconds. + Weight::from_parts(37_095_000, 117797) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -826,10 +828,10 @@ impl WeightInfo for () { /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_begin_confirming() -> Weight { // Proof Size summary in bytes: - // Measured: `465` - // Estimated: `112338` - // Minimum execution time: 28_710 nanoseconds. - Weight::from_parts(29_574_000, 112338) + // Measured: `434` + // Estimated: `114318` + // Minimum execution time: 30_003_000 picoseconds. + Weight::from_parts(30_541_000, 114318) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -839,10 +841,10 @@ impl WeightInfo for () { /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_end_confirming() -> Weight { // Proof Size summary in bytes: - // Measured: `448` - // Estimated: `112338` - // Minimum execution time: 29_030 nanoseconds. - Weight::from_parts(30_308_000, 112338) + // Measured: `417` + // Estimated: `114318` + // Minimum execution time: 30_479_000 picoseconds. + Weight::from_parts(30_900_000, 114318) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -852,10 +854,10 @@ impl WeightInfo for () { /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_continue_not_confirming() -> Weight { // Proof Size summary in bytes: - // Measured: `465` - // Estimated: `112338` - // Minimum execution time: 26_382 nanoseconds. - Weight::from_parts(27_219_000, 112338) + // Measured: `434` + // Estimated: `114318` + // Minimum execution time: 27_657_000 picoseconds. + Weight::from_parts(28_054_000, 114318) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -865,10 +867,10 @@ impl WeightInfo for () { /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_continue_confirming() -> Weight { // Proof Size summary in bytes: - // Measured: `469` - // Estimated: `112338` - // Minimum execution time: 25_445 nanoseconds. - Weight::from_parts(26_010_000, 112338) + // Measured: `438` + // Estimated: `114318` + // Minimum execution time: 26_713_000 picoseconds. + Weight::from_parts(27_284_000, 114318) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -880,10 +882,10 @@ impl WeightInfo for () { /// Proof: Scheduler Lookup (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) fn nudge_referendum_approved() -> Weight { // Proof Size summary in bytes: - // Measured: `469` - // Estimated: `224358` - // Minimum execution time: 41_064 nanoseconds. - Weight::from_parts(42_895_000, 224358) + // Measured: `438` + // Estimated: `227328` + // Minimum execution time: 42_374_000 picoseconds. + Weight::from_parts(43_142_000, 227328) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -893,10 +895,10 @@ impl WeightInfo for () { /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_rejected() -> Weight { // Proof Size summary in bytes: - // Measured: `465` - // Estimated: `112338` - // Minimum execution time: 29_472 nanoseconds. - Weight::from_parts(30_011_000, 112338) + // Measured: `434` + // Estimated: `114318` + // Minimum execution time: 30_213_000 picoseconds. + Weight::from_parts(30_633_000, 114318) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -908,10 +910,10 @@ impl WeightInfo for () { /// Proof: Referenda MetadataOf (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) fn set_some_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `454` - // Estimated: `5407` - // Minimum execution time: 19_389 nanoseconds. - Weight::from_parts(20_490_000, 5407) + // Measured: `422` + // Estimated: `7387` + // Minimum execution time: 20_887_000 picoseconds. + Weight::from_parts(21_242_000, 7387) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -921,10 +923,10 @@ impl WeightInfo for () { /// Proof: Referenda MetadataOf (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) fn clear_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `387` - // Estimated: `5368` - // Minimum execution time: 18_195 nanoseconds. - Weight::from_parts(19_917_000, 5368) + // Measured: `355` + // Estimated: `7348` + // Minimum execution time: 18_702_000 picoseconds. + Weight::from_parts(18_880_000, 7348) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/frame/remark/src/weights.rs b/frame/remark/src/weights.rs index f9fcb73803716..bb2e91b5dfbd0 100644 --- a/frame/remark/src/weights.rs +++ b/frame/remark/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_remark //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,6 +31,9 @@ // --steps=50 // --repeat=20 // --pallet=pallet_remark +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -59,10 +62,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_404 nanoseconds. - Weight::from_parts(343_031, 0) - // Standard Error: 1 - .saturating_add(Weight::from_parts(1_404, 0).saturating_mul(l.into())) + // Minimum execution time: 9_284_000 picoseconds. + Weight::from_parts(4_054_843, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(1_094, 0).saturating_mul(l.into())) } } @@ -73,9 +76,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_404 nanoseconds. - Weight::from_parts(343_031, 0) - // Standard Error: 1 - .saturating_add(Weight::from_parts(1_404, 0).saturating_mul(l.into())) + // Minimum execution time: 9_284_000 picoseconds. + Weight::from_parts(4_054_843, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(1_094, 0).saturating_mul(l.into())) } } diff --git a/frame/salary/src/weights.rs b/frame/salary/src/weights.rs index 6b43c58b6038c..7195a144a65a3 100644 --- a/frame/salary/src/weights.rs +++ b/frame/salary/src/weights.rs @@ -18,26 +18,29 @@ //! Autogenerated weights for pallet_salary //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-03, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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 // benchmark // pallet +// --chain=dev // --steps=50 // --repeat=20 -// --extrinsic=* // --pallet=pallet_salary +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --chain=dev -// --header=HEADER-APACHE2 -// --output=frame/salary/src/weights.rs -// --template=.maintain/frame-weight-template.hbs +// --output=./frame/salary/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -66,8 +69,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `4` // Estimated: `1541` - // Minimum execution time: 11_793_000 picoseconds. - Weight::from_parts(12_080_000, 1541) + // Minimum execution time: 11_732_000 picoseconds. + Weight::from_parts(12_162_000, 1541) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -75,10 +78,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Salary Status (max_values: Some(1), max_size: Some(56), added: 551, mode: MaxEncodedLen) fn bump() -> Weight { // Proof Size summary in bytes: - // Measured: `118` + // Measured: `86` // Estimated: `1541` - // Minimum execution time: 12_799_000 picoseconds. - Weight::from_parts(13_343_000, 1541) + // Minimum execution time: 12_966_000 picoseconds. + Weight::from_parts(13_443_000, 1541) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -90,10 +93,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Salary Claimant (max_values: None, max_size: Some(78), added: 2553, mode: MaxEncodedLen) fn induct() -> Weight { // Proof Size summary in bytes: - // Measured: `394` + // Measured: `362` // Estimated: `8591` - // Minimum execution time: 20_299_000 picoseconds. - Weight::from_parts(20_664_000, 8591) + // Minimum execution time: 20_467_000 picoseconds. + Weight::from_parts(20_782_000, 8591) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -105,10 +108,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Salary Claimant (max_values: None, max_size: Some(78), added: 2553, mode: MaxEncodedLen) fn register() -> Weight { // Proof Size summary in bytes: - // Measured: `461` + // Measured: `429` // Estimated: `8591` - // Minimum execution time: 24_195_000 picoseconds. - Weight::from_parts(24_528_000, 8591) + // Minimum execution time: 23_547_000 picoseconds. + Weight::from_parts(23_911_000, 8591) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -120,10 +123,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) fn payout() -> Weight { // Proof Size summary in bytes: - // Measured: `461` + // Measured: `429` // Estimated: `8591` - // Minimum execution time: 47_609_000 picoseconds. - Weight::from_parts(48_462_000, 8591) + // Minimum execution time: 47_145_000 picoseconds. + Weight::from_parts(47_778_000, 8591) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -137,10 +140,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn payout_other() -> Weight { // Proof Size summary in bytes: - // Measured: `461` + // Measured: `429` // Estimated: `12184` - // Minimum execution time: 48_513_000 picoseconds. - Weight::from_parts(49_053_000, 12184) + // Minimum execution time: 48_763_000 picoseconds. + Weight::from_parts(49_853_000, 12184) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -150,10 +153,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Salary Claimant (max_values: None, max_size: Some(78), added: 2553, mode: MaxEncodedLen) fn check_payment() -> Weight { // Proof Size summary in bytes: - // Measured: `202` + // Measured: `170` // Estimated: `5084` - // Minimum execution time: 12_663_000 picoseconds. - Weight::from_parts(12_858_000, 5084) + // Minimum execution time: 12_825_000 picoseconds. + Weight::from_parts(13_143_000, 5084) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -167,8 +170,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `4` // Estimated: `1541` - // Minimum execution time: 11_793_000 picoseconds. - Weight::from_parts(12_080_000, 1541) + // Minimum execution time: 11_732_000 picoseconds. + Weight::from_parts(12_162_000, 1541) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -176,10 +179,10 @@ impl WeightInfo for () { /// Proof: Salary Status (max_values: Some(1), max_size: Some(56), added: 551, mode: MaxEncodedLen) fn bump() -> Weight { // Proof Size summary in bytes: - // Measured: `118` + // Measured: `86` // Estimated: `1541` - // Minimum execution time: 12_799_000 picoseconds. - Weight::from_parts(13_343_000, 1541) + // Minimum execution time: 12_966_000 picoseconds. + Weight::from_parts(13_443_000, 1541) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -191,10 +194,10 @@ impl WeightInfo for () { /// Proof: Salary Claimant (max_values: None, max_size: Some(78), added: 2553, mode: MaxEncodedLen) fn induct() -> Weight { // Proof Size summary in bytes: - // Measured: `394` + // Measured: `362` // Estimated: `8591` - // Minimum execution time: 20_299_000 picoseconds. - Weight::from_parts(20_664_000, 8591) + // Minimum execution time: 20_467_000 picoseconds. + Weight::from_parts(20_782_000, 8591) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -206,10 +209,10 @@ impl WeightInfo for () { /// Proof: Salary Claimant (max_values: None, max_size: Some(78), added: 2553, mode: MaxEncodedLen) fn register() -> Weight { // Proof Size summary in bytes: - // Measured: `461` + // Measured: `429` // Estimated: `8591` - // Minimum execution time: 24_195_000 picoseconds. - Weight::from_parts(24_528_000, 8591) + // Minimum execution time: 23_547_000 picoseconds. + Weight::from_parts(23_911_000, 8591) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -221,10 +224,10 @@ impl WeightInfo for () { /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) fn payout() -> Weight { // Proof Size summary in bytes: - // Measured: `461` + // Measured: `429` // Estimated: `8591` - // Minimum execution time: 47_609_000 picoseconds. - Weight::from_parts(48_462_000, 8591) + // Minimum execution time: 47_145_000 picoseconds. + Weight::from_parts(47_778_000, 8591) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -238,10 +241,10 @@ impl WeightInfo for () { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn payout_other() -> Weight { // Proof Size summary in bytes: - // Measured: `461` + // Measured: `429` // Estimated: `12184` - // Minimum execution time: 48_513_000 picoseconds. - Weight::from_parts(49_053_000, 12184) + // Minimum execution time: 48_763_000 picoseconds. + Weight::from_parts(49_853_000, 12184) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -251,10 +254,10 @@ impl WeightInfo for () { /// Proof: Salary Claimant (max_values: None, max_size: Some(78), added: 2553, mode: MaxEncodedLen) fn check_payment() -> Weight { // Proof Size summary in bytes: - // Measured: `202` + // Measured: `170` // Estimated: `5084` - // Minimum execution time: 12_663_000 picoseconds. - Weight::from_parts(12_858_000, 5084) + // Minimum execution time: 12_825_000 picoseconds. + Weight::from_parts(13_143_000, 5084) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } diff --git a/frame/scheduler/src/weights.rs b/frame/scheduler/src/weights.rs index 577e5b0bc4b2d..bccb502656a72 100644 --- a/frame/scheduler/src/weights.rs +++ b/frame/scheduler/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_scheduler //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,6 +31,9 @@ // --steps=50 // --repeat=20 // --pallet=pallet_scheduler +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -69,10 +72,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Scheduler IncompleteSince (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn service_agendas_base() -> Weight { // Proof Size summary in bytes: - // Measured: `30` - // Estimated: `499` - // Minimum execution time: 3_670 nanoseconds. - Weight::from_parts(3_838_000, 499) + // Measured: `31` + // Estimated: `1489` + // Minimum execution time: 3_965_000 picoseconds. + Weight::from_parts(4_126_000, 1489) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -81,12 +84,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[0, 512]`. fn service_agenda_base(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `112 + s * (177 ±0)` - // Estimated: `109497` - // Minimum execution time: 3_079 nanoseconds. - Weight::from_parts(7_087_647, 109497) - // Standard Error: 658 - .saturating_add(Weight::from_parts(279_320, 0).saturating_mul(s.into())) + // Measured: `81 + s * (177 ±0)` + // Estimated: `110487` + // Minimum execution time: 3_662_000 picoseconds. + Weight::from_parts(8_746_597, 110487) + // Standard Error: 754 + .saturating_add(Weight::from_parts(309_350, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -94,8 +97,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_192 nanoseconds. - Weight::from_parts(5_528_000, 0) + // Minimum execution time: 5_807_000 picoseconds. + Weight::from_parts(5_963_000, 0) } /// Storage: Preimage PreimageFor (r:1 w:1) /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: Measured) @@ -104,12 +107,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[128, 4194304]`. fn service_task_fetched(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `211 + s * (1 ±0)` - // Estimated: `5252 + s * (1 ±0)` - // Minimum execution time: 17_284 nanoseconds. - Weight::from_parts(17_574_000, 5252) - // Standard Error: 0 - .saturating_add(Weight::from_parts(1_126, 0).saturating_mul(s.into())) + // Measured: `179 + s * (1 ±0)` + // Estimated: `7200 + s * (1 ±0)` + // Minimum execution time: 20_188_000 picoseconds. + Weight::from_parts(20_422_000, 7200) + // Standard Error: 1 + .saturating_add(Weight::from_parts(1_143, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(s.into())) @@ -120,42 +123,42 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_020 nanoseconds. - Weight::from_parts(7_262_000, 0) + // Minimum execution time: 7_787_000 picoseconds. + Weight::from_parts(8_046_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } fn service_task_periodic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_187 nanoseconds. - Weight::from_parts(5_368_000, 0) + // Minimum execution time: 5_730_000 picoseconds. + Weight::from_parts(5_901_000, 0) } fn execute_dispatch_signed() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_313 nanoseconds. - Weight::from_parts(2_404_000, 0) + // Minimum execution time: 2_569_000 picoseconds. + Weight::from_parts(2_710_000, 0) } fn execute_dispatch_unsigned() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_187 nanoseconds. - Weight::from_parts(2_362_000, 0) + // Minimum execution time: 2_611_000 picoseconds. + Weight::from_parts(2_765_000, 0) } /// Storage: Scheduler Agenda (r:1 w:1) /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) /// The range of component `s` is `[0, 511]`. fn schedule(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `112 + s * (177 ±0)` - // Estimated: `109497` - // Minimum execution time: 11_971 nanoseconds. - Weight::from_parts(16_060_361, 109497) - // Standard Error: 665 - .saturating_add(Weight::from_parts(286_324, 0).saturating_mul(s.into())) + // Measured: `81 + s * (177 ±0)` + // Estimated: `110487` + // Minimum execution time: 14_237_000 picoseconds. + Weight::from_parts(18_553_929, 110487) + // Standard Error: 757 + .saturating_add(Weight::from_parts(327_347, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -166,12 +169,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[1, 512]`. fn cancel(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `112 + s * (177 ±0)` - // Estimated: `109497` - // Minimum execution time: 15_594 nanoseconds. - Weight::from_parts(17_191_501, 109497) - // Standard Error: 626 - .saturating_add(Weight::from_parts(425_572, 0).saturating_mul(s.into())) + // Measured: `81 + s * (177 ±0)` + // Estimated: `110487` + // Minimum execution time: 18_003_000 picoseconds. + Weight::from_parts(19_521_283, 110487) + // Standard Error: 901 + .saturating_add(Weight::from_parts(496_401, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -182,12 +185,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[0, 511]`. fn schedule_named(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `627 + s * (178 ±0)` - // Estimated: `112020` - // Minimum execution time: 15_127 nanoseconds. - Weight::from_parts(20_932_642, 112020) - // Standard Error: 692 - .saturating_add(Weight::from_parts(288_344, 0).saturating_mul(s.into())) + // Measured: `596 + s * (178 ±0)` + // Estimated: `114000` + // Minimum execution time: 17_713_000 picoseconds. + Weight::from_parts(24_442_945, 114000) + // Standard Error: 764 + .saturating_add(Weight::from_parts(330_307, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -198,12 +201,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[1, 512]`. fn cancel_named(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `740 + s * (177 ±0)` - // Estimated: `112020` - // Minimum execution time: 16_859 nanoseconds. - Weight::from_parts(19_736_937, 112020) - // Standard Error: 676 - .saturating_add(Weight::from_parts(429_770, 0).saturating_mul(s.into())) + // Measured: `709 + s * (177 ±0)` + // Estimated: `114000` + // Minimum execution time: 19_808_000 picoseconds. + Weight::from_parts(22_601_896, 114000) + // Standard Error: 991 + .saturating_add(Weight::from_parts(496_702, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -215,10 +218,10 @@ impl WeightInfo for () { /// Proof: Scheduler IncompleteSince (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn service_agendas_base() -> Weight { // Proof Size summary in bytes: - // Measured: `30` - // Estimated: `499` - // Minimum execution time: 3_670 nanoseconds. - Weight::from_parts(3_838_000, 499) + // Measured: `31` + // Estimated: `1489` + // Minimum execution time: 3_965_000 picoseconds. + Weight::from_parts(4_126_000, 1489) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -227,12 +230,12 @@ impl WeightInfo for () { /// The range of component `s` is `[0, 512]`. fn service_agenda_base(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `112 + s * (177 ±0)` - // Estimated: `109497` - // Minimum execution time: 3_079 nanoseconds. - Weight::from_parts(7_087_647, 109497) - // Standard Error: 658 - .saturating_add(Weight::from_parts(279_320, 0).saturating_mul(s.into())) + // Measured: `81 + s * (177 ±0)` + // Estimated: `110487` + // Minimum execution time: 3_662_000 picoseconds. + Weight::from_parts(8_746_597, 110487) + // Standard Error: 754 + .saturating_add(Weight::from_parts(309_350, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -240,8 +243,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_192 nanoseconds. - Weight::from_parts(5_528_000, 0) + // Minimum execution time: 5_807_000 picoseconds. + Weight::from_parts(5_963_000, 0) } /// Storage: Preimage PreimageFor (r:1 w:1) /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: Measured) @@ -250,12 +253,12 @@ impl WeightInfo for () { /// The range of component `s` is `[128, 4194304]`. fn service_task_fetched(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `211 + s * (1 ±0)` - // Estimated: `5252 + s * (1 ±0)` - // Minimum execution time: 17_284 nanoseconds. - Weight::from_parts(17_574_000, 5252) - // Standard Error: 0 - .saturating_add(Weight::from_parts(1_126, 0).saturating_mul(s.into())) + // Measured: `179 + s * (1 ±0)` + // Estimated: `7200 + s * (1 ±0)` + // Minimum execution time: 20_188_000 picoseconds. + Weight::from_parts(20_422_000, 7200) + // Standard Error: 1 + .saturating_add(Weight::from_parts(1_143, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(s.into())) @@ -266,42 +269,42 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_020 nanoseconds. - Weight::from_parts(7_262_000, 0) + // Minimum execution time: 7_787_000 picoseconds. + Weight::from_parts(8_046_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } fn service_task_periodic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_187 nanoseconds. - Weight::from_parts(5_368_000, 0) + // Minimum execution time: 5_730_000 picoseconds. + Weight::from_parts(5_901_000, 0) } fn execute_dispatch_signed() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_313 nanoseconds. - Weight::from_parts(2_404_000, 0) + // Minimum execution time: 2_569_000 picoseconds. + Weight::from_parts(2_710_000, 0) } fn execute_dispatch_unsigned() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_187 nanoseconds. - Weight::from_parts(2_362_000, 0) + // Minimum execution time: 2_611_000 picoseconds. + Weight::from_parts(2_765_000, 0) } /// Storage: Scheduler Agenda (r:1 w:1) /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) /// The range of component `s` is `[0, 511]`. fn schedule(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `112 + s * (177 ±0)` - // Estimated: `109497` - // Minimum execution time: 11_971 nanoseconds. - Weight::from_parts(16_060_361, 109497) - // Standard Error: 665 - .saturating_add(Weight::from_parts(286_324, 0).saturating_mul(s.into())) + // Measured: `81 + s * (177 ±0)` + // Estimated: `110487` + // Minimum execution time: 14_237_000 picoseconds. + Weight::from_parts(18_553_929, 110487) + // Standard Error: 757 + .saturating_add(Weight::from_parts(327_347, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -312,12 +315,12 @@ impl WeightInfo for () { /// The range of component `s` is `[1, 512]`. fn cancel(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `112 + s * (177 ±0)` - // Estimated: `109497` - // Minimum execution time: 15_594 nanoseconds. - Weight::from_parts(17_191_501, 109497) - // Standard Error: 626 - .saturating_add(Weight::from_parts(425_572, 0).saturating_mul(s.into())) + // Measured: `81 + s * (177 ±0)` + // Estimated: `110487` + // Minimum execution time: 18_003_000 picoseconds. + Weight::from_parts(19_521_283, 110487) + // Standard Error: 901 + .saturating_add(Weight::from_parts(496_401, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -328,12 +331,12 @@ impl WeightInfo for () { /// The range of component `s` is `[0, 511]`. fn schedule_named(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `627 + s * (178 ±0)` - // Estimated: `112020` - // Minimum execution time: 15_127 nanoseconds. - Weight::from_parts(20_932_642, 112020) - // Standard Error: 692 - .saturating_add(Weight::from_parts(288_344, 0).saturating_mul(s.into())) + // Measured: `596 + s * (178 ±0)` + // Estimated: `114000` + // Minimum execution time: 17_713_000 picoseconds. + Weight::from_parts(24_442_945, 114000) + // Standard Error: 764 + .saturating_add(Weight::from_parts(330_307, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -344,12 +347,12 @@ impl WeightInfo for () { /// The range of component `s` is `[1, 512]`. fn cancel_named(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `740 + s * (177 ±0)` - // Estimated: `112020` - // Minimum execution time: 16_859 nanoseconds. - Weight::from_parts(19_736_937, 112020) - // Standard Error: 676 - .saturating_add(Weight::from_parts(429_770, 0).saturating_mul(s.into())) + // Measured: `709 + s * (177 ±0)` + // Estimated: `114000` + // Minimum execution time: 19_808_000 picoseconds. + Weight::from_parts(22_601_896, 114000) + // Standard Error: 991 + .saturating_add(Weight::from_parts(496_702, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } diff --git a/frame/session/src/weights.rs b/frame/session/src/weights.rs index c01799ce53050..3515ff4464a3a 100644 --- a/frame/session/src/weights.rs +++ b/frame/session/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_session //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,6 +31,9 @@ // --steps=50 // --repeat=20 // --pallet=pallet_session +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -63,10 +66,10 @@ impl WeightInfo for SubstrateWeight { /// Proof Skipped: Session KeyOwner (max_values: None, max_size: None, mode: Measured) fn set_keys() -> Weight { // Proof Size summary in bytes: - // Measured: `1955` - // Estimated: `19851` - // Minimum execution time: 40_867 nanoseconds. - Weight::from_parts(41_319_000, 19851) + // Measured: `1891` + // Estimated: `22693` + // Minimum execution time: 48_165_000 picoseconds. + Weight::from_parts(48_967_000, 22693) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -78,10 +81,10 @@ impl WeightInfo for SubstrateWeight { /// Proof Skipped: Session KeyOwner (max_values: None, max_size: None, mode: Measured) fn purge_keys() -> Weight { // Proof Size summary in bytes: - // Measured: `1854` - // Estimated: `9749` - // Minimum execution time: 30_286 nanoseconds. - Weight::from_parts(30_620_000, 9749) + // Measured: `1758` + // Estimated: `11537` + // Minimum execution time: 35_824_000 picoseconds. + Weight::from_parts(36_267_000, 11537) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -97,10 +100,10 @@ impl WeightInfo for () { /// Proof Skipped: Session KeyOwner (max_values: None, max_size: None, mode: Measured) fn set_keys() -> Weight { // Proof Size summary in bytes: - // Measured: `1955` - // Estimated: `19851` - // Minimum execution time: 40_867 nanoseconds. - Weight::from_parts(41_319_000, 19851) + // Measured: `1891` + // Estimated: `22693` + // Minimum execution time: 48_165_000 picoseconds. + Weight::from_parts(48_967_000, 22693) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -112,10 +115,10 @@ impl WeightInfo for () { /// Proof Skipped: Session KeyOwner (max_values: None, max_size: None, mode: Measured) fn purge_keys() -> Weight { // Proof Size summary in bytes: - // Measured: `1854` - // Estimated: `9749` - // Minimum execution time: 30_286 nanoseconds. - Weight::from_parts(30_620_000, 9749) + // Measured: `1758` + // Estimated: `11537` + // Minimum execution time: 35_824_000 picoseconds. + Weight::from_parts(36_267_000, 11537) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } diff --git a/frame/staking/src/weights.rs b/frame/staking/src/weights.rs index d1814d89d4d89..01d874d55660b 100644 --- a/frame/staking/src/weights.rs +++ b/frame/staking/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_staking //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-01-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,6 +31,9 @@ // --steps=50 // --repeat=20 // --pallet=pallet_staking +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -95,10 +98,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) fn bond() -> Weight { // Proof Size summary in bytes: - // Measured: `1079` - // Estimated: `10386` - // Minimum execution time: 40_015 nanoseconds. - Weight::from_parts(40_601_000, 10386) + // Measured: `1047` + // Estimated: `14346` + // Minimum execution time: 46_401_000 picoseconds. + Weight::from_parts(46_987_000, 14346) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -114,10 +117,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) fn bond_extra() -> Weight { // Proof Size summary in bytes: - // Measured: `2252` - // Estimated: `22888` - // Minimum execution time: 74_781 nanoseconds. - Weight::from_parts(75_188_000, 22888) + // Measured: `2028` + // Estimated: `27838` + // Minimum execution time: 87_755_000 picoseconds. + Weight::from_parts(88_802_000, 27838) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } @@ -141,10 +144,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) fn unbond() -> Weight { // Proof Size summary in bytes: - // Measured: `2457` - // Estimated: `29534` - // Minimum execution time: 81_299 nanoseconds. - Weight::from_parts(82_242_000, 29534) + // Measured: `2233` + // Estimated: `38444` + // Minimum execution time: 95_698_000 picoseconds. + Weight::from_parts(96_971_000, 38444) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(8_u64)) } @@ -159,12 +162,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1085` - // Estimated: `10442` - // Minimum execution time: 31_479 nanoseconds. - Weight::from_parts(32_410_035, 10442) - // Standard Error: 313 - .saturating_add(Weight::from_parts(9_090, 0).saturating_mul(s.into())) + // Measured: `1021` + // Estimated: `14402` + // Minimum execution time: 38_239_000 picoseconds. + Weight::from_parts(39_615_452, 14402) + // Standard Error: 447 + .saturating_add(Weight::from_parts(9_199, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -199,12 +202,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_kill(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2486 + s * (4 ±0)` - // Estimated: `32303 + s * (4 ±0)` - // Minimum execution time: 71_968 nanoseconds. - Weight::from_parts(76_631_804, 32303) - // Standard Error: 1_613 - .saturating_add(Weight::from_parts(1_058_968, 0).saturating_mul(s.into())) + // Measured: `2294 + s * (4 ±0)` + // Estimated: `43999 + s * (4 ±0)` + // Minimum execution time: 84_251_000 picoseconds. + Weight::from_parts(90_113_319, 43999) + // Standard Error: 2_177 + .saturating_add(Weight::from_parts(1_278_840, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(13_u64)) .saturating_add(T::DbWeight::get().writes(12_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -234,10 +237,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Staking CounterForValidators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn validate() -> Weight { // Proof Size summary in bytes: - // Measured: `1446` - // Estimated: `19359` - // Minimum execution time: 51_963 nanoseconds. - Weight::from_parts(52_418_000, 19359) + // Measured: `1414` + // Estimated: `30249` + // Minimum execution time: 60_509_000 picoseconds. + Weight::from_parts(61_305_000, 30249) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -248,12 +251,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `k` is `[1, 128]`. fn kick(k: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1292 + k * (601 ±0)` - // Estimated: `3566 + k * (3033 ±0)` - // Minimum execution time: 25_685 nanoseconds. - Weight::from_parts(25_290_286, 3566) - // Standard Error: 5_164 - .saturating_add(Weight::from_parts(6_445_608, 0).saturating_mul(k.into())) + // Measured: `1260 + k * (569 ±0)` + // Estimated: `5546 + k * (3033 ±0)` + // Minimum execution time: 30_063_000 picoseconds. + Weight::from_parts(31_774_698, 5546) + // Standard Error: 11_088 + .saturating_add(Weight::from_parts(7_869_325, 0).saturating_mul(k.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(k.into()))) @@ -284,12 +287,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1984 + n * (105 ±0)` - // Estimated: `21988 + n * (2520 ±0)` - // Minimum execution time: 59_542 nanoseconds. - Weight::from_parts(57_558_678, 21988) - // Standard Error: 10_364 - .saturating_add(Weight::from_parts(2_759_713, 0).saturating_mul(n.into())) + // Measured: `1888 + n * (105 ±0)` + // Estimated: `32878 + n * (2520 ±0)` + // Minimum execution time: 70_091_000 picoseconds. + Weight::from_parts(67_744_973, 32878) + // Standard Error: 12_799 + .saturating_add(Weight::from_parts(3_238_224, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(6_u64)) @@ -311,10 +314,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn chill() -> Weight { // Proof Size summary in bytes: - // Measured: `1876` - // Estimated: `17932` - // Minimum execution time: 52_132 nanoseconds. - Weight::from_parts(52_648_000, 17932) + // Measured: `1748` + // Estimated: `24862` + // Minimum execution time: 60_582_000 picoseconds. + Weight::from_parts(61_208_000, 24862) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -324,10 +327,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) fn set_payee() -> Weight { // Proof Size summary in bytes: - // Measured: `840` - // Estimated: `3566` - // Minimum execution time: 13_399 nanoseconds. - Weight::from_parts(13_567_000, 3566) + // Measured: `808` + // Estimated: `4556` + // Minimum execution time: 15_630_000 picoseconds. + Weight::from_parts(16_018_000, 4556) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -337,10 +340,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) fn set_controller() -> Weight { // Proof Size summary in bytes: - // Measured: `939` - // Estimated: `9679` - // Minimum execution time: 20_425 nanoseconds. - Weight::from_parts(20_713_000, 9679) + // Measured: `907` + // Estimated: `11659` + // Minimum execution time: 23_895_000 picoseconds. + Weight::from_parts(24_306_000, 11659) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -350,8 +353,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_069 nanoseconds. - Weight::from_parts(3_176_000, 0) + // Minimum execution time: 3_694_000 picoseconds. + Weight::from_parts(3_820_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Staking ForceEra (r:0 w:1) @@ -360,8 +363,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 11_386 nanoseconds. - Weight::from_parts(11_672_000, 0) + // Minimum execution time: 10_729_000 picoseconds. + Weight::from_parts(11_086_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Staking ForceEra (r:0 w:1) @@ -370,8 +373,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 11_591 nanoseconds. - Weight::from_parts(11_799_000, 0) + // Minimum execution time: 10_959_000 picoseconds. + Weight::from_parts(11_371_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Staking ForceEra (r:0 w:1) @@ -380,8 +383,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 11_553 nanoseconds. - Weight::from_parts(11_871_000, 0) + // Minimum execution time: 11_101_000 picoseconds. + Weight::from_parts(11_506_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Staking Invulnerables (r:0 w:1) @@ -391,10 +394,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_292 nanoseconds. - Weight::from_parts(3_754_352, 0) - // Standard Error: 40 - .saturating_add(Weight::from_parts(9_838, 0).saturating_mul(v.into())) + // Minimum execution time: 4_016_000 picoseconds. + Weight::from_parts(4_454_020, 0) + // Standard Error: 82 + .saturating_add(Weight::from_parts(10_703, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Staking Bonded (r:1 w:1) @@ -426,12 +429,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[0, 100]`. fn force_unstake(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2178 + s * (4 ±0)` - // Estimated: `27930 + s * (4 ±0)` - // Minimum execution time: 65_307 nanoseconds. - Weight::from_parts(70_227_980, 27930) - // Standard Error: 2_113 - .saturating_add(Weight::from_parts(1_059_856, 0).saturating_mul(s.into())) + // Measured: `2018 + s * (4 ±0)` + // Estimated: `37678 + s * (4 ±0)` + // Minimum execution time: 76_338_000 picoseconds. + Weight::from_parts(82_426_098, 37678) + // Standard Error: 3_761 + .saturating_add(Weight::from_parts(1_279_343, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(12_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -442,12 +445,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[1, 1000]`. fn cancel_deferred_slash(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `66671` - // Estimated: `69146` - // Minimum execution time: 89_123 nanoseconds. - Weight::from_parts(890_989_741, 69146) - // Standard Error: 58_282 - .saturating_add(Weight::from_parts(4_920_413, 0).saturating_mul(s.into())) + // Measured: `66639` + // Estimated: `70104` + // Minimum execution time: 91_160_000 picoseconds. + Weight::from_parts(794_662_495, 70104) + // Standard Error: 51_479 + .saturating_add(Weight::from_parts(4_346_694, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -472,12 +475,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 256]`. fn payout_stakers_dead_controller(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `20345 + n * (143 ±0)` - // Estimated: `54756 + n * (8024 ±1)` - // Minimum execution time: 73_652 nanoseconds. - Weight::from_parts(127_839_483, 54756) - // Standard Error: 14_195 - .saturating_add(Weight::from_parts(21_932_079, 0).saturating_mul(n.into())) + // Measured: `20217 + n * (143 ±0)` + // Estimated: `63416 + n * (8024 ±1)` + // Minimum execution time: 77_845_000 picoseconds. + Weight::from_parts(86_178_186, 63416) + // Standard Error: 21_971 + .saturating_add(Weight::from_parts(26_966_654, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) @@ -507,17 +510,17 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 256]`. fn payout_stakers_alive_staked(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `35099 + n * (465 ±0)` - // Estimated: `83594 + n * (16026 ±0)` - // Minimum execution time: 94_560 nanoseconds. - Weight::from_parts(154_033_219, 83594) - // Standard Error: 26_663 - .saturating_add(Weight::from_parts(31_269_223, 0).saturating_mul(n.into())) + // Measured: `34971 + n * (401 ±0)` + // Estimated: `93244 + n * (15898 ±0)` + // Minimum execution time: 98_209_000 picoseconds. + Weight::from_parts(102_121_432, 93244) + // Standard Error: 25_633 + .saturating_add(Weight::from_parts(39_244_200, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(10_u64)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 16026).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 15898).saturating_mul(n.into())) } /// Storage: Staking Ledger (r:1 w:1) /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) @@ -534,12 +537,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `l` is `[1, 32]`. fn rebond(l: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2253 + l * (7 ±0)` - // Estimated: `25491` - // Minimum execution time: 74_764 nanoseconds. - Weight::from_parts(75_814_067, 25491) - // Standard Error: 1_217 - .saturating_add(Weight::from_parts(64_725, 0).saturating_mul(l.into())) + // Measured: `2029 + l * (7 ±0)` + // Estimated: `31431` + // Minimum execution time: 87_067_000 picoseconds. + Weight::from_parts(87_971_483, 31431) + // Standard Error: 1_668 + .saturating_add(Weight::from_parts(56_024, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(8_u64)) } @@ -572,12 +575,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[1, 100]`. fn reap_stash(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2486 + s * (4 ±0)` - // Estimated: `31810 + s * (4 ±0)` - // Minimum execution time: 77_611 nanoseconds. - Weight::from_parts(79_760_034, 31810) - // Standard Error: 1_597 - .saturating_add(Weight::from_parts(1_039_268, 0).saturating_mul(s.into())) + // Measured: `2294 + s * (4 ±0)` + // Estimated: `42515 + s * (4 ±0)` + // Minimum execution time: 90_421_000 picoseconds. + Weight::from_parts(91_873_866, 42515) + // Standard Error: 1_867 + .saturating_add(Weight::from_parts(1_275_581, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(12_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -621,21 +624,21 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 100]`. fn new_era(v: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0 + v * (3662 ±0) + n * (816 ±0)` - // Estimated: `528203 + v * (16743 ±0) + n * (12947 ±0)` - // Minimum execution time: 489_824 nanoseconds. - Weight::from_parts(491_687_000, 528203) - // Standard Error: 1_787_577 - .saturating_add(Weight::from_parts(58_719_498, 0).saturating_mul(v.into())) - // Standard Error: 178_122 - .saturating_add(Weight::from_parts(13_273_555, 0).saturating_mul(n.into())) + // Measured: `0 + v * (3598 ±0) + n * (720 ±0)` + // Estimated: `537749 + v * (16699 ±39) + n * (12763 ±3)` + // Minimum execution time: 552_452_000 picoseconds. + Weight::from_parts(555_250_000, 537749) + // Standard Error: 1_893_951 + .saturating_add(Weight::from_parts(61_059_451, 0).saturating_mul(v.into())) + // Standard Error: 188_721 + .saturating_add(Weight::from_parts(17_220_679, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(206_u64)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(v.into()))) - .saturating_add(Weight::from_parts(0, 16743).saturating_mul(v.into())) - .saturating_add(Weight::from_parts(0, 12947).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 16699).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(0, 12763).saturating_mul(n.into())) } /// Storage: VoterList CounterForListNodes (r:1 w:0) /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -657,14 +660,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[500, 1000]`. fn get_npos_voters(v: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `3167 + v * (459 ±0) + n * (1007 ±0)` - // Estimated: `511899 + v * (14295 ±0) + n * (11775 ±0)` - // Minimum execution time: 23_373_467 nanoseconds. - Weight::from_parts(23_497_257_000, 511899) - // Standard Error: 299_205 - .saturating_add(Weight::from_parts(3_434_000, 0).saturating_mul(v.into())) - // Standard Error: 299_205 - .saturating_add(Weight::from_parts(2_568_954, 0).saturating_mul(n.into())) + // Measured: `3135 + v * (395 ±0) + n * (911 ±0)` + // Estimated: `518829 + v * (14295 ±0) + n * (11775 ±0)` + // Minimum execution time: 32_870_065_000 picoseconds. + Weight::from_parts(33_295_716_000, 518829) + // Standard Error: 371_824 + .saturating_add(Weight::from_parts(5_148_979, 0).saturating_mul(v.into())) + // Standard Error: 371_824 + .saturating_add(Weight::from_parts(3_376_262, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(201_u64)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -680,11 +683,11 @@ impl WeightInfo for SubstrateWeight { fn get_npos_targets(v: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `983 + v * (50 ±0)` - // Estimated: `3019 + v * (2520 ±0)` - // Minimum execution time: 3_882_120 nanoseconds. - Weight::from_parts(3_951_993_000, 3019) - // Standard Error: 46_729 - .saturating_add(Weight::from_parts(2_856_043, 0).saturating_mul(v.into())) + // Estimated: `4999 + v * (2520 ±0)` + // Minimum execution time: 2_321_389_000 picoseconds. + Weight::from_parts(70_122_933, 4999) + // Standard Error: 7_249 + .saturating_add(Weight::from_parts(4_632_666, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) .saturating_add(Weight::from_parts(0, 2520).saturating_mul(v.into())) @@ -705,8 +708,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_427 nanoseconds. - Weight::from_parts(8_794_000, 0) + // Minimum execution time: 9_581_000 picoseconds. + Weight::from_parts(9_802_000, 0) .saturating_add(T::DbWeight::get().writes(6_u64)) } /// Storage: Staking MinCommission (r:0 w:1) @@ -725,8 +728,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_620 nanoseconds. - Weight::from_parts(7_901_000, 0) + // Minimum execution time: 8_883_000 picoseconds. + Weight::from_parts(9_151_000, 0) .saturating_add(T::DbWeight::get().writes(6_u64)) } /// Storage: Staking Ledger (r:1 w:0) @@ -751,10 +754,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn chill_other() -> Weight { // Proof Size summary in bytes: - // Measured: `2031` - // Estimated: `19438` - // Minimum execution time: 66_188 nanoseconds. - Weight::from_parts(66_767_000, 19438) + // Measured: `1871` + // Estimated: `29338` + // Minimum execution time: 77_916_000 picoseconds. + Weight::from_parts(78_877_000, 29338) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -765,9 +768,9 @@ impl WeightInfo for SubstrateWeight { fn force_apply_min_commission() -> Weight { // Proof Size summary in bytes: // Measured: `694` - // Estimated: `3019` - // Minimum execution time: 14_703 nanoseconds. - Weight::from_parts(15_031_000, 3019) + // Estimated: `4999` + // Minimum execution time: 16_658_000 picoseconds. + Weight::from_parts(16_968_000, 4999) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -777,8 +780,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_518 nanoseconds. - Weight::from_parts(4_656_000, 0) + // Minimum execution time: 4_982_000 picoseconds. + Weight::from_parts(5_232_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } } @@ -797,10 +800,10 @@ impl WeightInfo for () { /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) fn bond() -> Weight { // Proof Size summary in bytes: - // Measured: `1079` - // Estimated: `10386` - // Minimum execution time: 40_015 nanoseconds. - Weight::from_parts(40_601_000, 10386) + // Measured: `1047` + // Estimated: `14346` + // Minimum execution time: 46_401_000 picoseconds. + Weight::from_parts(46_987_000, 14346) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -816,10 +819,10 @@ impl WeightInfo for () { /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) fn bond_extra() -> Weight { // Proof Size summary in bytes: - // Measured: `2252` - // Estimated: `22888` - // Minimum execution time: 74_781 nanoseconds. - Weight::from_parts(75_188_000, 22888) + // Measured: `2028` + // Estimated: `27838` + // Minimum execution time: 87_755_000 picoseconds. + Weight::from_parts(88_802_000, 27838) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } @@ -843,10 +846,10 @@ impl WeightInfo for () { /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) fn unbond() -> Weight { // Proof Size summary in bytes: - // Measured: `2457` - // Estimated: `29534` - // Minimum execution time: 81_299 nanoseconds. - Weight::from_parts(82_242_000, 29534) + // Measured: `2233` + // Estimated: `38444` + // Minimum execution time: 95_698_000 picoseconds. + Weight::from_parts(96_971_000, 38444) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().writes(8_u64)) } @@ -861,12 +864,12 @@ impl WeightInfo for () { /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1085` - // Estimated: `10442` - // Minimum execution time: 31_479 nanoseconds. - Weight::from_parts(32_410_035, 10442) - // Standard Error: 313 - .saturating_add(Weight::from_parts(9_090, 0).saturating_mul(s.into())) + // Measured: `1021` + // Estimated: `14402` + // Minimum execution time: 38_239_000 picoseconds. + Weight::from_parts(39_615_452, 14402) + // Standard Error: 447 + .saturating_add(Weight::from_parts(9_199, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -901,12 +904,12 @@ impl WeightInfo for () { /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_kill(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2486 + s * (4 ±0)` - // Estimated: `32303 + s * (4 ±0)` - // Minimum execution time: 71_968 nanoseconds. - Weight::from_parts(76_631_804, 32303) - // Standard Error: 1_613 - .saturating_add(Weight::from_parts(1_058_968, 0).saturating_mul(s.into())) + // Measured: `2294 + s * (4 ±0)` + // Estimated: `43999 + s * (4 ±0)` + // Minimum execution time: 84_251_000 picoseconds. + Weight::from_parts(90_113_319, 43999) + // Standard Error: 2_177 + .saturating_add(Weight::from_parts(1_278_840, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(13_u64)) .saturating_add(RocksDbWeight::get().writes(12_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -936,10 +939,10 @@ impl WeightInfo for () { /// Proof: Staking CounterForValidators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn validate() -> Weight { // Proof Size summary in bytes: - // Measured: `1446` - // Estimated: `19359` - // Minimum execution time: 51_963 nanoseconds. - Weight::from_parts(52_418_000, 19359) + // Measured: `1414` + // Estimated: `30249` + // Minimum execution time: 60_509_000 picoseconds. + Weight::from_parts(61_305_000, 30249) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -950,12 +953,12 @@ impl WeightInfo for () { /// The range of component `k` is `[1, 128]`. fn kick(k: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1292 + k * (601 ±0)` - // Estimated: `3566 + k * (3033 ±0)` - // Minimum execution time: 25_685 nanoseconds. - Weight::from_parts(25_290_286, 3566) - // Standard Error: 5_164 - .saturating_add(Weight::from_parts(6_445_608, 0).saturating_mul(k.into())) + // Measured: `1260 + k * (569 ±0)` + // Estimated: `5546 + k * (3033 ±0)` + // Minimum execution time: 30_063_000 picoseconds. + Weight::from_parts(31_774_698, 5546) + // Standard Error: 11_088 + .saturating_add(Weight::from_parts(7_869_325, 0).saturating_mul(k.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(k.into()))) @@ -986,12 +989,12 @@ impl WeightInfo for () { /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1984 + n * (105 ±0)` - // Estimated: `21988 + n * (2520 ±0)` - // Minimum execution time: 59_542 nanoseconds. - Weight::from_parts(57_558_678, 21988) - // Standard Error: 10_364 - .saturating_add(Weight::from_parts(2_759_713, 0).saturating_mul(n.into())) + // Measured: `1888 + n * (105 ±0)` + // Estimated: `32878 + n * (2520 ±0)` + // Minimum execution time: 70_091_000 picoseconds. + Weight::from_parts(67_744_973, 32878) + // Standard Error: 12_799 + .saturating_add(Weight::from_parts(3_238_224, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(6_u64)) @@ -1013,10 +1016,10 @@ impl WeightInfo for () { /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn chill() -> Weight { // Proof Size summary in bytes: - // Measured: `1876` - // Estimated: `17932` - // Minimum execution time: 52_132 nanoseconds. - Weight::from_parts(52_648_000, 17932) + // Measured: `1748` + // Estimated: `24862` + // Minimum execution time: 60_582_000 picoseconds. + Weight::from_parts(61_208_000, 24862) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -1026,10 +1029,10 @@ impl WeightInfo for () { /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) fn set_payee() -> Weight { // Proof Size summary in bytes: - // Measured: `840` - // Estimated: `3566` - // Minimum execution time: 13_399 nanoseconds. - Weight::from_parts(13_567_000, 3566) + // Measured: `808` + // Estimated: `4556` + // Minimum execution time: 15_630_000 picoseconds. + Weight::from_parts(16_018_000, 4556) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1039,10 +1042,10 @@ impl WeightInfo for () { /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) fn set_controller() -> Weight { // Proof Size summary in bytes: - // Measured: `939` - // Estimated: `9679` - // Minimum execution time: 20_425 nanoseconds. - Weight::from_parts(20_713_000, 9679) + // Measured: `907` + // Estimated: `11659` + // Minimum execution time: 23_895_000 picoseconds. + Weight::from_parts(24_306_000, 11659) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -1052,8 +1055,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_069 nanoseconds. - Weight::from_parts(3_176_000, 0) + // Minimum execution time: 3_694_000 picoseconds. + Weight::from_parts(3_820_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Staking ForceEra (r:0 w:1) @@ -1062,8 +1065,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 11_386 nanoseconds. - Weight::from_parts(11_672_000, 0) + // Minimum execution time: 10_729_000 picoseconds. + Weight::from_parts(11_086_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Staking ForceEra (r:0 w:1) @@ -1072,8 +1075,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 11_591 nanoseconds. - Weight::from_parts(11_799_000, 0) + // Minimum execution time: 10_959_000 picoseconds. + Weight::from_parts(11_371_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Staking ForceEra (r:0 w:1) @@ -1082,8 +1085,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 11_553 nanoseconds. - Weight::from_parts(11_871_000, 0) + // Minimum execution time: 11_101_000 picoseconds. + Weight::from_parts(11_506_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Staking Invulnerables (r:0 w:1) @@ -1093,10 +1096,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_292 nanoseconds. - Weight::from_parts(3_754_352, 0) - // Standard Error: 40 - .saturating_add(Weight::from_parts(9_838, 0).saturating_mul(v.into())) + // Minimum execution time: 4_016_000 picoseconds. + Weight::from_parts(4_454_020, 0) + // Standard Error: 82 + .saturating_add(Weight::from_parts(10_703, 0).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Staking Bonded (r:1 w:1) @@ -1128,12 +1131,12 @@ impl WeightInfo for () { /// The range of component `s` is `[0, 100]`. fn force_unstake(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2178 + s * (4 ±0)` - // Estimated: `27930 + s * (4 ±0)` - // Minimum execution time: 65_307 nanoseconds. - Weight::from_parts(70_227_980, 27930) - // Standard Error: 2_113 - .saturating_add(Weight::from_parts(1_059_856, 0).saturating_mul(s.into())) + // Measured: `2018 + s * (4 ±0)` + // Estimated: `37678 + s * (4 ±0)` + // Minimum execution time: 76_338_000 picoseconds. + Weight::from_parts(82_426_098, 37678) + // Standard Error: 3_761 + .saturating_add(Weight::from_parts(1_279_343, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(12_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -1144,12 +1147,12 @@ impl WeightInfo for () { /// The range of component `s` is `[1, 1000]`. fn cancel_deferred_slash(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `66671` - // Estimated: `69146` - // Minimum execution time: 89_123 nanoseconds. - Weight::from_parts(890_989_741, 69146) - // Standard Error: 58_282 - .saturating_add(Weight::from_parts(4_920_413, 0).saturating_mul(s.into())) + // Measured: `66639` + // Estimated: `70104` + // Minimum execution time: 91_160_000 picoseconds. + Weight::from_parts(794_662_495, 70104) + // Standard Error: 51_479 + .saturating_add(Weight::from_parts(4_346_694, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1174,12 +1177,12 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 256]`. fn payout_stakers_dead_controller(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `20345 + n * (143 ±0)` - // Estimated: `54756 + n * (8024 ±1)` - // Minimum execution time: 73_652 nanoseconds. - Weight::from_parts(127_839_483, 54756) - // Standard Error: 14_195 - .saturating_add(Weight::from_parts(21_932_079, 0).saturating_mul(n.into())) + // Measured: `20217 + n * (143 ±0)` + // Estimated: `63416 + n * (8024 ±1)` + // Minimum execution time: 77_845_000 picoseconds. + Weight::from_parts(86_178_186, 63416) + // Standard Error: 21_971 + .saturating_add(Weight::from_parts(26_966_654, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(2_u64)) @@ -1209,17 +1212,17 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 256]`. fn payout_stakers_alive_staked(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `35099 + n * (465 ±0)` - // Estimated: `83594 + n * (16026 ±0)` - // Minimum execution time: 94_560 nanoseconds. - Weight::from_parts(154_033_219, 83594) - // Standard Error: 26_663 - .saturating_add(Weight::from_parts(31_269_223, 0).saturating_mul(n.into())) + // Measured: `34971 + n * (401 ±0)` + // Estimated: `93244 + n * (15898 ±0)` + // Minimum execution time: 98_209_000 picoseconds. + Weight::from_parts(102_121_432, 93244) + // Standard Error: 25_633 + .saturating_add(Weight::from_parts(39_244_200, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(10_u64)) .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 16026).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 15898).saturating_mul(n.into())) } /// Storage: Staking Ledger (r:1 w:1) /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) @@ -1236,12 +1239,12 @@ impl WeightInfo for () { /// The range of component `l` is `[1, 32]`. fn rebond(l: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2253 + l * (7 ±0)` - // Estimated: `25491` - // Minimum execution time: 74_764 nanoseconds. - Weight::from_parts(75_814_067, 25491) - // Standard Error: 1_217 - .saturating_add(Weight::from_parts(64_725, 0).saturating_mul(l.into())) + // Measured: `2029 + l * (7 ±0)` + // Estimated: `31431` + // Minimum execution time: 87_067_000 picoseconds. + Weight::from_parts(87_971_483, 31431) + // Standard Error: 1_668 + .saturating_add(Weight::from_parts(56_024, 0).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(8_u64)) } @@ -1274,12 +1277,12 @@ impl WeightInfo for () { /// The range of component `s` is `[1, 100]`. fn reap_stash(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2486 + s * (4 ±0)` - // Estimated: `31810 + s * (4 ±0)` - // Minimum execution time: 77_611 nanoseconds. - Weight::from_parts(79_760_034, 31810) - // Standard Error: 1_597 - .saturating_add(Weight::from_parts(1_039_268, 0).saturating_mul(s.into())) + // Measured: `2294 + s * (4 ±0)` + // Estimated: `42515 + s * (4 ±0)` + // Minimum execution time: 90_421_000 picoseconds. + Weight::from_parts(91_873_866, 42515) + // Standard Error: 1_867 + .saturating_add(Weight::from_parts(1_275_581, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().writes(12_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -1323,21 +1326,21 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 100]`. fn new_era(v: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0 + v * (3662 ±0) + n * (816 ±0)` - // Estimated: `528203 + v * (16743 ±0) + n * (12947 ±0)` - // Minimum execution time: 489_824 nanoseconds. - Weight::from_parts(491_687_000, 528203) - // Standard Error: 1_787_577 - .saturating_add(Weight::from_parts(58_719_498, 0).saturating_mul(v.into())) - // Standard Error: 178_122 - .saturating_add(Weight::from_parts(13_273_555, 0).saturating_mul(n.into())) + // Measured: `0 + v * (3598 ±0) + n * (720 ±0)` + // Estimated: `537749 + v * (16699 ±39) + n * (12763 ±3)` + // Minimum execution time: 552_452_000 picoseconds. + Weight::from_parts(555_250_000, 537749) + // Standard Error: 1_893_951 + .saturating_add(Weight::from_parts(61_059_451, 0).saturating_mul(v.into())) + // Standard Error: 188_721 + .saturating_add(Weight::from_parts(17_220_679, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(206_u64)) .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(v.into()))) - .saturating_add(Weight::from_parts(0, 16743).saturating_mul(v.into())) - .saturating_add(Weight::from_parts(0, 12947).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 16699).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(0, 12763).saturating_mul(n.into())) } /// Storage: VoterList CounterForListNodes (r:1 w:0) /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -1359,14 +1362,14 @@ impl WeightInfo for () { /// The range of component `n` is `[500, 1000]`. fn get_npos_voters(v: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `3167 + v * (459 ±0) + n * (1007 ±0)` - // Estimated: `511899 + v * (14295 ±0) + n * (11775 ±0)` - // Minimum execution time: 23_373_467 nanoseconds. - Weight::from_parts(23_497_257_000, 511899) - // Standard Error: 299_205 - .saturating_add(Weight::from_parts(3_434_000, 0).saturating_mul(v.into())) - // Standard Error: 299_205 - .saturating_add(Weight::from_parts(2_568_954, 0).saturating_mul(n.into())) + // Measured: `3135 + v * (395 ±0) + n * (911 ±0)` + // Estimated: `518829 + v * (14295 ±0) + n * (11775 ±0)` + // Minimum execution time: 32_870_065_000 picoseconds. + Weight::from_parts(33_295_716_000, 518829) + // Standard Error: 371_824 + .saturating_add(Weight::from_parts(5_148_979, 0).saturating_mul(v.into())) + // Standard Error: 371_824 + .saturating_add(Weight::from_parts(3_376_262, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(201_u64)) .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -1382,11 +1385,11 @@ impl WeightInfo for () { fn get_npos_targets(v: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `983 + v * (50 ±0)` - // Estimated: `3019 + v * (2520 ±0)` - // Minimum execution time: 3_882_120 nanoseconds. - Weight::from_parts(3_951_993_000, 3019) - // Standard Error: 46_729 - .saturating_add(Weight::from_parts(2_856_043, 0).saturating_mul(v.into())) + // Estimated: `4999 + v * (2520 ±0)` + // Minimum execution time: 2_321_389_000 picoseconds. + Weight::from_parts(70_122_933, 4999) + // Standard Error: 7_249 + .saturating_add(Weight::from_parts(4_632_666, 0).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(v.into()))) .saturating_add(Weight::from_parts(0, 2520).saturating_mul(v.into())) @@ -1407,8 +1410,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_427 nanoseconds. - Weight::from_parts(8_794_000, 0) + // Minimum execution time: 9_581_000 picoseconds. + Weight::from_parts(9_802_000, 0) .saturating_add(RocksDbWeight::get().writes(6_u64)) } /// Storage: Staking MinCommission (r:0 w:1) @@ -1427,8 +1430,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_620 nanoseconds. - Weight::from_parts(7_901_000, 0) + // Minimum execution time: 8_883_000 picoseconds. + Weight::from_parts(9_151_000, 0) .saturating_add(RocksDbWeight::get().writes(6_u64)) } /// Storage: Staking Ledger (r:1 w:0) @@ -1453,10 +1456,10 @@ impl WeightInfo for () { /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn chill_other() -> Weight { // Proof Size summary in bytes: - // Measured: `2031` - // Estimated: `19438` - // Minimum execution time: 66_188 nanoseconds. - Weight::from_parts(66_767_000, 19438) + // Measured: `1871` + // Estimated: `29338` + // Minimum execution time: 77_916_000 picoseconds. + Weight::from_parts(78_877_000, 29338) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -1467,9 +1470,9 @@ impl WeightInfo for () { fn force_apply_min_commission() -> Weight { // Proof Size summary in bytes: // Measured: `694` - // Estimated: `3019` - // Minimum execution time: 14_703 nanoseconds. - Weight::from_parts(15_031_000, 3019) + // Estimated: `4999` + // Minimum execution time: 16_658_000 picoseconds. + Weight::from_parts(16_968_000, 4999) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1479,8 +1482,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_518 nanoseconds. - Weight::from_parts(4_656_000, 0) + // Minimum execution time: 4_982_000 picoseconds. + Weight::from_parts(5_232_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } } diff --git a/frame/state-trie-migration/src/weights.rs b/frame/state-trie-migration/src/weights.rs index e087ba185994f..961cec7bcfa51 100644 --- a/frame/state-trie-migration/src/weights.rs +++ b/frame/state-trie-migration/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_state_trie_migration //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-01-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,6 +31,9 @@ // --steps=50 // --repeat=20 // --pallet=pallet_state_trie_migration +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -67,9 +70,9 @@ impl WeightInfo for SubstrateWeight { fn continue_migrate() -> Weight { // Proof Size summary in bytes: // Measured: `108` - // Estimated: `2040` - // Minimum execution time: 15_563 nanoseconds. - Weight::from_parts(15_783_000, 2040) + // Estimated: `4020` + // Minimum execution time: 15_449_000 picoseconds. + Weight::from_parts(16_040_000, 4020) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -78,26 +81,26 @@ impl WeightInfo for SubstrateWeight { fn continue_migrate_wrong_witness() -> Weight { // Proof Size summary in bytes: // Measured: `76` - // Estimated: `503` - // Minimum execution time: 4_347 nanoseconds. - Weight::from_parts(4_558_000, 503) + // Estimated: `1493` + // Minimum execution time: 4_632_000 picoseconds. + Weight::from_parts(4_768_000, 1493) .saturating_add(T::DbWeight::get().reads(1_u64)) } fn migrate_custom_top_success() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_817 nanoseconds. - Weight::from_parts(9_027_000, 0) + // Minimum execution time: 9_596_000 picoseconds. + Weight::from_parts(9_866_000, 0) } /// Storage: unknown `0x666f6f` (r:1 w:1) /// Proof Skipped: unknown `0x666f6f` (r:1 w:1) fn migrate_custom_top_fail() -> Weight { // Proof Size summary in bytes: - // Measured: `144` - // Estimated: `2619` - // Minimum execution time: 23_854 nanoseconds. - Weight::from_parts(24_850_000, 2619) + // Measured: `113` + // Estimated: `3578` + // Minimum execution time: 27_352_000 picoseconds. + Weight::from_parts(28_089_000, 3578) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -105,17 +108,17 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_020 nanoseconds. - Weight::from_parts(9_234_000, 0) + // Minimum execution time: 10_286_000 picoseconds. + Weight::from_parts(10_761_000, 0) } /// Storage: unknown `0x666f6f` (r:1 w:1) /// Proof Skipped: unknown `0x666f6f` (r:1 w:1) fn migrate_custom_child_fail() -> Weight { // Proof Size summary in bytes: - // Measured: `136` - // Estimated: `2611` - // Minimum execution time: 24_136 nanoseconds. - Weight::from_parts(24_810_000, 2611) + // Measured: `105` + // Estimated: `3570` + // Minimum execution time: 27_355_000 picoseconds. + Weight::from_parts(28_092_000, 3570) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -124,12 +127,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `v` is `[1, 4194304]`. fn process_top_key(v: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `228 + v * (1 ±0)` - // Estimated: `2700 + v * (1 ±0)` - // Minimum execution time: 5_279 nanoseconds. - Weight::from_parts(5_517_000, 2700) + // Measured: `197 + v * (1 ±0)` + // Estimated: `3662 + v * (1 ±0)` + // Minimum execution time: 6_004_000 picoseconds. + Weight::from_parts(6_188_000, 3662) // Standard Error: 1 - .saturating_add(Weight::from_parts(1_230, 0).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(1_073, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(v.into())) @@ -145,9 +148,9 @@ impl WeightInfo for () { fn continue_migrate() -> Weight { // Proof Size summary in bytes: // Measured: `108` - // Estimated: `2040` - // Minimum execution time: 15_563 nanoseconds. - Weight::from_parts(15_783_000, 2040) + // Estimated: `4020` + // Minimum execution time: 15_449_000 picoseconds. + Weight::from_parts(16_040_000, 4020) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -156,26 +159,26 @@ impl WeightInfo for () { fn continue_migrate_wrong_witness() -> Weight { // Proof Size summary in bytes: // Measured: `76` - // Estimated: `503` - // Minimum execution time: 4_347 nanoseconds. - Weight::from_parts(4_558_000, 503) + // Estimated: `1493` + // Minimum execution time: 4_632_000 picoseconds. + Weight::from_parts(4_768_000, 1493) .saturating_add(RocksDbWeight::get().reads(1_u64)) } fn migrate_custom_top_success() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_817 nanoseconds. - Weight::from_parts(9_027_000, 0) + // Minimum execution time: 9_596_000 picoseconds. + Weight::from_parts(9_866_000, 0) } /// Storage: unknown `0x666f6f` (r:1 w:1) /// Proof Skipped: unknown `0x666f6f` (r:1 w:1) fn migrate_custom_top_fail() -> Weight { // Proof Size summary in bytes: - // Measured: `144` - // Estimated: `2619` - // Minimum execution time: 23_854 nanoseconds. - Weight::from_parts(24_850_000, 2619) + // Measured: `113` + // Estimated: `3578` + // Minimum execution time: 27_352_000 picoseconds. + Weight::from_parts(28_089_000, 3578) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -183,17 +186,17 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_020 nanoseconds. - Weight::from_parts(9_234_000, 0) + // Minimum execution time: 10_286_000 picoseconds. + Weight::from_parts(10_761_000, 0) } /// Storage: unknown `0x666f6f` (r:1 w:1) /// Proof Skipped: unknown `0x666f6f` (r:1 w:1) fn migrate_custom_child_fail() -> Weight { // Proof Size summary in bytes: - // Measured: `136` - // Estimated: `2611` - // Minimum execution time: 24_136 nanoseconds. - Weight::from_parts(24_810_000, 2611) + // Measured: `105` + // Estimated: `3570` + // Minimum execution time: 27_355_000 picoseconds. + Weight::from_parts(28_092_000, 3570) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -202,12 +205,12 @@ impl WeightInfo for () { /// The range of component `v` is `[1, 4194304]`. fn process_top_key(v: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `228 + v * (1 ±0)` - // Estimated: `2700 + v * (1 ±0)` - // Minimum execution time: 5_279 nanoseconds. - Weight::from_parts(5_517_000, 2700) + // Measured: `197 + v * (1 ±0)` + // Estimated: `3662 + v * (1 ±0)` + // Minimum execution time: 6_004_000 picoseconds. + Weight::from_parts(6_188_000, 3662) // Standard Error: 1 - .saturating_add(Weight::from_parts(1_230, 0).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(1_073, 0).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(v.into())) diff --git a/frame/support/src/weights/block_weights.rs b/frame/support/src/weights/block_weights.rs index 2389c51d9de9c..b8ac9a0383dee 100644 --- a/frame/support/src/weights/block_weights.rs +++ b/frame/support/src/weights/block_weights.rs @@ -16,8 +16,8 @@ // limitations under the License. //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-01-25 (Y/M/D) -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! DATE: 2023-03-15 (Y/M/D) +//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! //! SHORT-NAME: `block`, LONG-NAME: `BlockExecution`, RUNTIME: `Development` //! WARMUPS: `10`, REPEAT: `100` @@ -44,17 +44,17 @@ parameter_types! { /// Calculated by multiplying the *Average* with `1.0` and adding `0`. /// /// Stats nanoseconds: - /// Min, Max: 377_722, 414_752 - /// Average: 381_015 - /// Median: 379_751 - /// Std-Dev: 5462.64 + /// Min, Max: 402_748, 458_228 + /// Average: 412_772 + /// Median: 406_151 + /// Std-Dev: 13480.33 /// /// Percentiles nanoseconds: - /// 99th: 413_074 - /// 95th: 384_876 - /// 75th: 380_642 + /// 99th: 450_080 + /// 95th: 445_111 + /// 75th: 414_170 pub const BlockExecutionWeight: Weight = - Weight::from_parts(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(381_015), 0); + Weight::from_parts(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(412_772), 0); } #[cfg(test)] diff --git a/frame/support/src/weights/extrinsic_weights.rs b/frame/support/src/weights/extrinsic_weights.rs index 78798d2e3a277..44b1b94aeb8ba 100644 --- a/frame/support/src/weights/extrinsic_weights.rs +++ b/frame/support/src/weights/extrinsic_weights.rs @@ -16,8 +16,8 @@ // limitations under the License. //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-01-25 (Y/M/D) -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! DATE: 2023-03-15 (Y/M/D) +//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! //! SHORT-NAME: `extrinsic`, LONG-NAME: `ExtrinsicBase`, RUNTIME: `Development` //! WARMUPS: `10`, REPEAT: `100` @@ -44,17 +44,17 @@ parameter_types! { /// Calculated by multiplying the *Average* with `1.0` and adding `0`. /// /// Stats nanoseconds: - /// Min, Max: 99_481, 103_304 - /// Average: 99_840 - /// Median: 99_795 - /// Std-Dev: 376.17 + /// Min, Max: 109_595, 114_170 + /// Average: 110_536 + /// Median: 110_233 + /// Std-Dev: 933.39 /// /// Percentiles nanoseconds: - /// 99th: 100_078 - /// 95th: 100_051 - /// 75th: 99_916 + /// 99th: 114_120 + /// 95th: 112_680 + /// 75th: 110_858 pub const ExtrinsicBaseWeight: Weight = - Weight::from_parts(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(99_840), 0); + Weight::from_parts(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(110_536), 0); } #[cfg(test)] diff --git a/frame/system/src/weights.rs b/frame/system/src/weights.rs index 812f2d091fcfe..34c0b62dcdd2f 100644 --- a/frame/system/src/weights.rs +++ b/frame/system/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for frame_system //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,6 +31,9 @@ // --steps=50 // --repeat=20 // --pallet=frame_system +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -64,20 +67,20 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_018 nanoseconds. - Weight::from_parts(2_091_000, 0) + // Minimum execution time: 2_519_000 picoseconds. + Weight::from_parts(2_576_000, 0) // Standard Error: 0 - .saturating_add(Weight::from_parts(362, 0).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(365, 0).saturating_mul(b.into())) } /// The range of component `b` is `[0, 3932160]`. fn remark_with_event(b: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_449 nanoseconds. - Weight::from_parts(7_748_000, 0) + // Minimum execution time: 8_687_000 picoseconds. + Weight::from_parts(8_875_000, 0) // Standard Error: 0 - .saturating_add(Weight::from_parts(1_423, 0).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(1_121, 0).saturating_mul(b.into())) } /// Storage: System Digest (r:1 w:1) /// Proof Skipped: System Digest (max_values: Some(1), max_size: None, mode: Measured) @@ -86,9 +89,9 @@ impl WeightInfo for SubstrateWeight { fn set_heap_pages() -> Weight { // Proof Size summary in bytes: // Measured: `0` - // Estimated: `495` - // Minimum execution time: 4_440 nanoseconds. - Weight::from_parts(4_605_000, 495) + // Estimated: `1485` + // Minimum execution time: 5_281_000 picoseconds. + Weight::from_parts(5_383_000, 1485) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -99,10 +102,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_981 nanoseconds. - Weight::from_parts(2_114_000, 0) - // Standard Error: 804 - .saturating_add(Weight::from_parts(631_438, 0).saturating_mul(i.into())) + // Minimum execution time: 2_346_000 picoseconds. + Weight::from_parts(2_491_000, 0) + // Standard Error: 815 + .saturating_add(Weight::from_parts(731_217, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) } /// Storage: Skipped Metadata (r:0 w:0) @@ -112,10 +115,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_061 nanoseconds. - Weight::from_parts(2_153_000, 0) - // Standard Error: 952 - .saturating_add(Weight::from_parts(502_629, 0).saturating_mul(i.into())) + // Minimum execution time: 2_394_000 picoseconds. + Weight::from_parts(2_567_000, 0) + // Standard Error: 935 + .saturating_add(Weight::from_parts(554_023, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) } /// Storage: Skipped Metadata (r:0 w:0) @@ -125,10 +128,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `116 + p * (69 ±0)` // Estimated: `121 + p * (70 ±0)` - // Minimum execution time: 4_026 nanoseconds. - Weight::from_parts(4_174_000, 121) - // Standard Error: 1_148 - .saturating_add(Weight::from_parts(1_093_099, 0).saturating_mul(p.into())) + // Minimum execution time: 4_706_000 picoseconds. + Weight::from_parts(4_858_000, 121) + // Standard Error: 1_291 + .saturating_add(Weight::from_parts(1_142_198, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(p.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(p.into()))) .saturating_add(Weight::from_parts(0, 70).saturating_mul(p.into())) } @@ -141,20 +145,20 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_018 nanoseconds. - Weight::from_parts(2_091_000, 0) + // Minimum execution time: 2_519_000 picoseconds. + Weight::from_parts(2_576_000, 0) // Standard Error: 0 - .saturating_add(Weight::from_parts(362, 0).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(365, 0).saturating_mul(b.into())) } /// The range of component `b` is `[0, 3932160]`. fn remark_with_event(b: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_449 nanoseconds. - Weight::from_parts(7_748_000, 0) + // Minimum execution time: 8_687_000 picoseconds. + Weight::from_parts(8_875_000, 0) // Standard Error: 0 - .saturating_add(Weight::from_parts(1_423, 0).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(1_121, 0).saturating_mul(b.into())) } /// Storage: System Digest (r:1 w:1) /// Proof Skipped: System Digest (max_values: Some(1), max_size: None, mode: Measured) @@ -163,9 +167,9 @@ impl WeightInfo for () { fn set_heap_pages() -> Weight { // Proof Size summary in bytes: // Measured: `0` - // Estimated: `495` - // Minimum execution time: 4_440 nanoseconds. - Weight::from_parts(4_605_000, 495) + // Estimated: `1485` + // Minimum execution time: 5_281_000 picoseconds. + Weight::from_parts(5_383_000, 1485) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -176,10 +180,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_981 nanoseconds. - Weight::from_parts(2_114_000, 0) - // Standard Error: 804 - .saturating_add(Weight::from_parts(631_438, 0).saturating_mul(i.into())) + // Minimum execution time: 2_346_000 picoseconds. + Weight::from_parts(2_491_000, 0) + // Standard Error: 815 + .saturating_add(Weight::from_parts(731_217, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(i.into()))) } /// Storage: Skipped Metadata (r:0 w:0) @@ -189,10 +193,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_061 nanoseconds. - Weight::from_parts(2_153_000, 0) - // Standard Error: 952 - .saturating_add(Weight::from_parts(502_629, 0).saturating_mul(i.into())) + // Minimum execution time: 2_394_000 picoseconds. + Weight::from_parts(2_567_000, 0) + // Standard Error: 935 + .saturating_add(Weight::from_parts(554_023, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(i.into()))) } /// Storage: Skipped Metadata (r:0 w:0) @@ -202,10 +206,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `116 + p * (69 ±0)` // Estimated: `121 + p * (70 ±0)` - // Minimum execution time: 4_026 nanoseconds. - Weight::from_parts(4_174_000, 121) - // Standard Error: 1_148 - .saturating_add(Weight::from_parts(1_093_099, 0).saturating_mul(p.into())) + // Minimum execution time: 4_706_000 picoseconds. + Weight::from_parts(4_858_000, 121) + // Standard Error: 1_291 + .saturating_add(Weight::from_parts(1_142_198, 0).saturating_mul(p.into())) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(p.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(p.into()))) .saturating_add(Weight::from_parts(0, 70).saturating_mul(p.into())) } diff --git a/frame/timestamp/src/weights.rs b/frame/timestamp/src/weights.rs index 943f941d55305..e1ada6f63c961 100644 --- a/frame/timestamp/src/weights.rs +++ b/frame/timestamp/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_timestamp //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-01-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,6 +31,9 @@ // --steps=50 // --repeat=20 // --pallet=pallet_timestamp +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -62,9 +65,9 @@ impl WeightInfo for SubstrateWeight { fn set() -> Weight { // Proof Size summary in bytes: // Measured: `312` - // Estimated: `1006` - // Minimum execution time: 9_106 nanoseconds. - Weight::from_parts(9_258_000, 1006) + // Estimated: `2986` + // Minimum execution time: 10_913_000 picoseconds. + Weight::from_parts(11_453_000, 2986) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -72,8 +75,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `161` // Estimated: `0` - // Minimum execution time: 3_927 nanoseconds. - Weight::from_parts(4_078_000, 0) + // Minimum execution time: 4_400_000 picoseconds. + Weight::from_parts(4_550_000, 0) } } @@ -86,9 +89,9 @@ impl WeightInfo for () { fn set() -> Weight { // Proof Size summary in bytes: // Measured: `312` - // Estimated: `1006` - // Minimum execution time: 9_106 nanoseconds. - Weight::from_parts(9_258_000, 1006) + // Estimated: `2986` + // Minimum execution time: 10_913_000 picoseconds. + Weight::from_parts(11_453_000, 2986) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -96,7 +99,7 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `161` // Estimated: `0` - // Minimum execution time: 3_927 nanoseconds. - Weight::from_parts(4_078_000, 0) + // Minimum execution time: 4_400_000 picoseconds. + Weight::from_parts(4_550_000, 0) } } diff --git a/frame/tips/src/weights.rs b/frame/tips/src/weights.rs index 2b265d7879712..205413d52d7ff 100644 --- a/frame/tips/src/weights.rs +++ b/frame/tips/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_tips //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-01-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,6 +31,9 @@ // --steps=50 // --repeat=20 // --pallet=pallet_tips +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -67,11 +70,11 @@ impl WeightInfo for SubstrateWeight { fn report_awesome(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `4` - // Estimated: `4958` - // Minimum execution time: 23_262 nanoseconds. - Weight::from_parts(24_104_224, 4958) - // Standard Error: 148 - .saturating_add(Weight::from_parts(1_963, 0).saturating_mul(r.into())) + // Estimated: `6938` + // Minimum execution time: 26_789_000 picoseconds. + Weight::from_parts(27_619_925, 6938) + // Standard Error: 168 + .saturating_add(Weight::from_parts(1_352, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -81,10 +84,10 @@ impl WeightInfo for SubstrateWeight { /// Proof Skipped: Tips Reasons (max_values: None, max_size: None, mode: Measured) fn retract_tip() -> Weight { // Proof Size summary in bytes: - // Measured: `253` - // Estimated: `2981` - // Minimum execution time: 22_282 nanoseconds. - Weight::from_parts(22_737_000, 2981) + // Measured: `221` + // Estimated: `3907` + // Minimum execution time: 25_322_000 picoseconds. + Weight::from_parts(26_107_000, 3907) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -96,16 +99,14 @@ impl WeightInfo for SubstrateWeight { /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 300]`. /// The range of component `t` is `[1, 13]`. - fn tip_new(r: u32, t: u32, ) -> Weight { + fn tip_new(_r: u32, t: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `558 + t * (64 ±0)` - // Estimated: `4644 + t * (192 ±0)` - // Minimum execution time: 18_382 nanoseconds. - Weight::from_parts(18_195_288, 4644) - // Standard Error: 103 - .saturating_add(Weight::from_parts(2_096, 0).saturating_mul(r.into())) - // Standard Error: 2_469 - .saturating_add(Weight::from_parts(97_092, 0).saturating_mul(t.into())) + // Measured: `526 + t * (64 ±0)` + // Estimated: `6528 + t * (192 ±0)` + // Minimum execution time: 21_112_000 picoseconds. + Weight::from_parts(21_825_317, 6528) + // Standard Error: 11_230 + .saturating_add(Weight::from_parts(86_081, 0).saturating_mul(t.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(Weight::from_parts(0, 192).saturating_mul(t.into())) @@ -117,12 +118,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `t` is `[1, 13]`. fn tip(t: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `811 + t * (112 ±0)` - // Estimated: `4592 + t * (224 ±0)` - // Minimum execution time: 13_564 nanoseconds. - Weight::from_parts(13_867_280, 4592) - // Standard Error: 4_245 - .saturating_add(Weight::from_parts(206_587, 0).saturating_mul(t.into())) + // Measured: `747 + t * (112 ±0)` + // Estimated: `6444 + t * (224 ±0)` + // Minimum execution time: 16_703_000 picoseconds. + Weight::from_parts(16_679_429, 6444) + // Standard Error: 18_088 + .saturating_add(Weight::from_parts(281_667, 0).saturating_mul(t.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 224).saturating_mul(t.into())) @@ -138,12 +139,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `t` is `[1, 13]`. fn close_tip(t: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `850 + t * (112 ±0)` - // Estimated: `8096 + t * (336 ±0)` - // Minimum execution time: 39_902 nanoseconds. - Weight::from_parts(40_747_650, 8096) - // Standard Error: 5_322 - .saturating_add(Weight::from_parts(144_298, 0).saturating_mul(t.into())) + // Measured: `786 + t * (112 ±0)` + // Estimated: `10874 + t * (336 ±0)` + // Minimum execution time: 46_106_000 picoseconds. + Weight::from_parts(47_844_269, 10874) + // Standard Error: 9_247 + .saturating_add(Weight::from_parts(87_804, 0).saturating_mul(t.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 336).saturating_mul(t.into())) @@ -153,14 +154,12 @@ impl WeightInfo for SubstrateWeight { /// Storage: Tips Reasons (r:0 w:1) /// Proof Skipped: Tips Reasons (max_values: None, max_size: None, mode: Measured) /// The range of component `t` is `[1, 13]`. - fn slash_tip(t: u32, ) -> Weight { + fn slash_tip(_t: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `301` - // Estimated: `3077` - // Minimum execution time: 13_511 nanoseconds. - Weight::from_parts(14_114_101, 3077) - // Standard Error: 1_815 - .saturating_add(Weight::from_parts(7_825, 0).saturating_mul(t.into())) + // Measured: `269` + // Estimated: `4003` + // Minimum execution time: 15_508_000 picoseconds. + Weight::from_parts(16_207_284, 4003) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -176,11 +175,11 @@ impl WeightInfo for () { fn report_awesome(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `4` - // Estimated: `4958` - // Minimum execution time: 23_262 nanoseconds. - Weight::from_parts(24_104_224, 4958) - // Standard Error: 148 - .saturating_add(Weight::from_parts(1_963, 0).saturating_mul(r.into())) + // Estimated: `6938` + // Minimum execution time: 26_789_000 picoseconds. + Weight::from_parts(27_619_925, 6938) + // Standard Error: 168 + .saturating_add(Weight::from_parts(1_352, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -190,10 +189,10 @@ impl WeightInfo for () { /// Proof Skipped: Tips Reasons (max_values: None, max_size: None, mode: Measured) fn retract_tip() -> Weight { // Proof Size summary in bytes: - // Measured: `253` - // Estimated: `2981` - // Minimum execution time: 22_282 nanoseconds. - Weight::from_parts(22_737_000, 2981) + // Measured: `221` + // Estimated: `3907` + // Minimum execution time: 25_322_000 picoseconds. + Weight::from_parts(26_107_000, 3907) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -205,16 +204,14 @@ impl WeightInfo for () { /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 300]`. /// The range of component `t` is `[1, 13]`. - fn tip_new(r: u32, t: u32, ) -> Weight { + fn tip_new(_r: u32, t: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `558 + t * (64 ±0)` - // Estimated: `4644 + t * (192 ±0)` - // Minimum execution time: 18_382 nanoseconds. - Weight::from_parts(18_195_288, 4644) - // Standard Error: 103 - .saturating_add(Weight::from_parts(2_096, 0).saturating_mul(r.into())) - // Standard Error: 2_469 - .saturating_add(Weight::from_parts(97_092, 0).saturating_mul(t.into())) + // Measured: `526 + t * (64 ±0)` + // Estimated: `6528 + t * (192 ±0)` + // Minimum execution time: 21_112_000 picoseconds. + Weight::from_parts(21_825_317, 6528) + // Standard Error: 11_230 + .saturating_add(Weight::from_parts(86_081, 0).saturating_mul(t.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(Weight::from_parts(0, 192).saturating_mul(t.into())) @@ -226,12 +223,12 @@ impl WeightInfo for () { /// The range of component `t` is `[1, 13]`. fn tip(t: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `811 + t * (112 ±0)` - // Estimated: `4592 + t * (224 ±0)` - // Minimum execution time: 13_564 nanoseconds. - Weight::from_parts(13_867_280, 4592) - // Standard Error: 4_245 - .saturating_add(Weight::from_parts(206_587, 0).saturating_mul(t.into())) + // Measured: `747 + t * (112 ±0)` + // Estimated: `6444 + t * (224 ±0)` + // Minimum execution time: 16_703_000 picoseconds. + Weight::from_parts(16_679_429, 6444) + // Standard Error: 18_088 + .saturating_add(Weight::from_parts(281_667, 0).saturating_mul(t.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 224).saturating_mul(t.into())) @@ -247,12 +244,12 @@ impl WeightInfo for () { /// The range of component `t` is `[1, 13]`. fn close_tip(t: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `850 + t * (112 ±0)` - // Estimated: `8096 + t * (336 ±0)` - // Minimum execution time: 39_902 nanoseconds. - Weight::from_parts(40_747_650, 8096) - // Standard Error: 5_322 - .saturating_add(Weight::from_parts(144_298, 0).saturating_mul(t.into())) + // Measured: `786 + t * (112 ±0)` + // Estimated: `10874 + t * (336 ±0)` + // Minimum execution time: 46_106_000 picoseconds. + Weight::from_parts(47_844_269, 10874) + // Standard Error: 9_247 + .saturating_add(Weight::from_parts(87_804, 0).saturating_mul(t.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 336).saturating_mul(t.into())) @@ -262,14 +259,12 @@ impl WeightInfo for () { /// Storage: Tips Reasons (r:0 w:1) /// Proof Skipped: Tips Reasons (max_values: None, max_size: None, mode: Measured) /// The range of component `t` is `[1, 13]`. - fn slash_tip(t: u32, ) -> Weight { + fn slash_tip(_t: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `301` - // Estimated: `3077` - // Minimum execution time: 13_511 nanoseconds. - Weight::from_parts(14_114_101, 3077) - // Standard Error: 1_815 - .saturating_add(Weight::from_parts(7_825, 0).saturating_mul(t.into())) + // Measured: `269` + // Estimated: `4003` + // Minimum execution time: 15_508_000 picoseconds. + Weight::from_parts(16_207_284, 4003) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } diff --git a/frame/transaction-storage/src/weights.rs b/frame/transaction-storage/src/weights.rs index 896e1ebab43aa..2845136b7d2a9 100644 --- a/frame/transaction-storage/src/weights.rs +++ b/frame/transaction-storage/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_transaction_storage //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-01-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,6 +31,9 @@ // --steps=50 // --repeat=20 // --pallet=pallet_transaction_storage +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -66,11 +69,11 @@ impl WeightInfo for SubstrateWeight { fn store(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `176` - // Estimated: `38383` - // Minimum execution time: 28_702 nanoseconds. - Weight::from_parts(29_164_000, 38383) + // Estimated: `41353` + // Minimum execution time: 33_286_000 picoseconds. + Weight::from_parts(33_596_000, 41353) // Standard Error: 2 - .saturating_add(Weight::from_parts(5_601, 0).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(4_954, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -84,10 +87,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: TransactionStorage BlockTransactions (max_values: Some(1), max_size: Some(36866), added: 37361, mode: MaxEncodedLen) fn renew() -> Weight { // Proof Size summary in bytes: - // Measured: `358` - // Estimated: `77744` - // Minimum execution time: 36_219 nanoseconds. - Weight::from_parts(36_979_000, 77744) + // Measured: `326` + // Estimated: `81704` + // Minimum execution time: 41_892_000 picoseconds. + Weight::from_parts(42_802_000, 81704) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -103,10 +106,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: TransactionStorage Transactions (max_values: None, max_size: Some(36886), added: 39361, mode: MaxEncodedLen) fn check_proof_max() -> Weight { // Proof Size summary in bytes: - // Measured: `37177` - // Estimated: `43382` - // Minimum execution time: 55_793 nanoseconds. - Weight::from_parts(57_128_000, 43382) + // Measured: `37145` + // Estimated: `48332` + // Minimum execution time: 63_799_000 picoseconds. + Weight::from_parts(66_145_000, 48332) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -124,11 +127,11 @@ impl WeightInfo for () { fn store(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `176` - // Estimated: `38383` - // Minimum execution time: 28_702 nanoseconds. - Weight::from_parts(29_164_000, 38383) + // Estimated: `41353` + // Minimum execution time: 33_286_000 picoseconds. + Weight::from_parts(33_596_000, 41353) // Standard Error: 2 - .saturating_add(Weight::from_parts(5_601, 0).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(4_954, 0).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -142,10 +145,10 @@ impl WeightInfo for () { /// Proof: TransactionStorage BlockTransactions (max_values: Some(1), max_size: Some(36866), added: 37361, mode: MaxEncodedLen) fn renew() -> Weight { // Proof Size summary in bytes: - // Measured: `358` - // Estimated: `77744` - // Minimum execution time: 36_219 nanoseconds. - Weight::from_parts(36_979_000, 77744) + // Measured: `326` + // Estimated: `81704` + // Minimum execution time: 41_892_000 picoseconds. + Weight::from_parts(42_802_000, 81704) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -161,10 +164,10 @@ impl WeightInfo for () { /// Proof: TransactionStorage Transactions (max_values: None, max_size: Some(36886), added: 39361, mode: MaxEncodedLen) fn check_proof_max() -> Weight { // Proof Size summary in bytes: - // Measured: `37177` - // Estimated: `43382` - // Minimum execution time: 55_793 nanoseconds. - Weight::from_parts(57_128_000, 43382) + // Measured: `37145` + // Estimated: `48332` + // Minimum execution time: 63_799_000 picoseconds. + Weight::from_parts(66_145_000, 48332) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/frame/treasury/src/weights.rs b/frame/treasury/src/weights.rs index abf461c622a0f..a7c093a8001ec 100644 --- a/frame/treasury/src/weights.rs +++ b/frame/treasury/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_treasury //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-01-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,6 +31,9 @@ // --steps=50 // --repeat=20 // --pallet=pallet_treasury +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -68,9 +71,9 @@ impl WeightInfo for SubstrateWeight { fn spend() -> Weight { // Proof Size summary in bytes: // Measured: `42` - // Estimated: `1396` - // Minimum execution time: 14_277 nanoseconds. - Weight::from_parts(14_749_000, 1396) + // Estimated: `3376` + // Minimum execution time: 17_010_000 picoseconds. + Weight::from_parts(17_247_000, 3376) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -80,10 +83,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) fn propose_spend() -> Weight { // Proof Size summary in bytes: - // Measured: `175` - // Estimated: `499` - // Minimum execution time: 23_297 nanoseconds. - Weight::from_parts(23_585_000, 499) + // Measured: `143` + // Estimated: `1489` + // Minimum execution time: 25_780_000 picoseconds. + Weight::from_parts(41_064_000, 1489) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -93,10 +96,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn reject_proposal() -> Weight { // Proof Size summary in bytes: - // Measured: `365` - // Estimated: `5186` - // Minimum execution time: 23_996 nanoseconds. - Weight::from_parts(24_548_000, 5186) + // Measured: `301` + // Estimated: `7166` + // Minimum execution time: 27_805_000 picoseconds. + Weight::from_parts(28_322_000, 7166) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -107,12 +110,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `p` is `[0, 99]`. fn approve_proposal(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `501 + p * (8 ±0)` - // Estimated: `3480` - // Minimum execution time: 9_366 nanoseconds. - Weight::from_parts(11_731_455, 3480) - // Standard Error: 761 - .saturating_add(Weight::from_parts(21_665, 0).saturating_mul(p.into())) + // Measured: `470 + p * (8 ±0)` + // Estimated: `5460` + // Minimum execution time: 10_939_000 picoseconds. + Weight::from_parts(13_667_341, 5460) + // Standard Error: 907 + .saturating_add(Weight::from_parts(26_648, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -121,9 +124,9 @@ impl WeightInfo for SubstrateWeight { fn remove_approval() -> Weight { // Proof Size summary in bytes: // Measured: `127` - // Estimated: `897` - // Minimum execution time: 7_012 nanoseconds. - Weight::from_parts(7_270_000, 897) + // Estimated: `1887` + // Minimum execution time: 8_261_000 picoseconds. + Weight::from_parts(8_399_000, 1887) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -140,12 +143,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `p` is `[0, 100]`. fn on_initialize_proposals(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `415 + p * (314 ±0)` - // Estimated: `2305 + p * (7789 ±0)` - // Minimum execution time: 37_834 nanoseconds. - Weight::from_parts(47_496_917, 2305) - // Standard Error: 12_505 - .saturating_add(Weight::from_parts(26_902_474, 0).saturating_mul(p.into())) + // Measured: `387 + p * (251 ±0)` + // Estimated: `7255 + p * (7789 ±0)` + // Minimum execution time: 43_781_000 picoseconds. + Weight::from_parts(68_521_487, 7255) + // Standard Error: 58_804 + .saturating_add(Weight::from_parts(33_271_211, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(p.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -165,9 +168,9 @@ impl WeightInfo for () { fn spend() -> Weight { // Proof Size summary in bytes: // Measured: `42` - // Estimated: `1396` - // Minimum execution time: 14_277 nanoseconds. - Weight::from_parts(14_749_000, 1396) + // Estimated: `3376` + // Minimum execution time: 17_010_000 picoseconds. + Weight::from_parts(17_247_000, 3376) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -177,10 +180,10 @@ impl WeightInfo for () { /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) fn propose_spend() -> Weight { // Proof Size summary in bytes: - // Measured: `175` - // Estimated: `499` - // Minimum execution time: 23_297 nanoseconds. - Weight::from_parts(23_585_000, 499) + // Measured: `143` + // Estimated: `1489` + // Minimum execution time: 25_780_000 picoseconds. + Weight::from_parts(41_064_000, 1489) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -190,10 +193,10 @@ impl WeightInfo for () { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn reject_proposal() -> Weight { // Proof Size summary in bytes: - // Measured: `365` - // Estimated: `5186` - // Minimum execution time: 23_996 nanoseconds. - Weight::from_parts(24_548_000, 5186) + // Measured: `301` + // Estimated: `7166` + // Minimum execution time: 27_805_000 picoseconds. + Weight::from_parts(28_322_000, 7166) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -204,12 +207,12 @@ impl WeightInfo for () { /// The range of component `p` is `[0, 99]`. fn approve_proposal(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `501 + p * (8 ±0)` - // Estimated: `3480` - // Minimum execution time: 9_366 nanoseconds. - Weight::from_parts(11_731_455, 3480) - // Standard Error: 761 - .saturating_add(Weight::from_parts(21_665, 0).saturating_mul(p.into())) + // Measured: `470 + p * (8 ±0)` + // Estimated: `5460` + // Minimum execution time: 10_939_000 picoseconds. + Weight::from_parts(13_667_341, 5460) + // Standard Error: 907 + .saturating_add(Weight::from_parts(26_648, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -218,9 +221,9 @@ impl WeightInfo for () { fn remove_approval() -> Weight { // Proof Size summary in bytes: // Measured: `127` - // Estimated: `897` - // Minimum execution time: 7_012 nanoseconds. - Weight::from_parts(7_270_000, 897) + // Estimated: `1887` + // Minimum execution time: 8_261_000 picoseconds. + Weight::from_parts(8_399_000, 1887) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -237,12 +240,12 @@ impl WeightInfo for () { /// The range of component `p` is `[0, 100]`. fn on_initialize_proposals(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `415 + p * (314 ±0)` - // Estimated: `2305 + p * (7789 ±0)` - // Minimum execution time: 37_834 nanoseconds. - Weight::from_parts(47_496_917, 2305) - // Standard Error: 12_505 - .saturating_add(Weight::from_parts(26_902_474, 0).saturating_mul(p.into())) + // Measured: `387 + p * (251 ±0)` + // Estimated: `7255 + p * (7789 ±0)` + // Minimum execution time: 43_781_000 picoseconds. + Weight::from_parts(68_521_487, 7255) + // Standard Error: 58_804 + .saturating_add(Weight::from_parts(33_271_211, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(p.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) diff --git a/frame/uniques/src/weights.rs b/frame/uniques/src/weights.rs index edf3bd35dcef0..1f0e3772696f7 100644 --- a/frame/uniques/src/weights.rs +++ b/frame/uniques/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_uniques //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-01-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,6 +31,9 @@ // --steps=50 // --repeat=20 // --pallet=pallet_uniques +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -85,10 +88,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Uniques ClassAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) fn create() -> Weight { // Proof Size summary in bytes: - // Measured: `281` - // Estimated: `2653` - // Minimum execution time: 24_242 nanoseconds. - Weight::from_parts(24_682_000, 2653) + // Measured: `249` + // Estimated: `3643` + // Minimum execution time: 27_805_000 picoseconds. + Weight::from_parts(28_303_000, 3643) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -99,9 +102,9 @@ impl WeightInfo for SubstrateWeight { fn force_create() -> Weight { // Proof Size summary in bytes: // Measured: `109` - // Estimated: `2653` - // Minimum execution time: 14_145 nanoseconds. - Weight::from_parts(14_598_000, 2653) + // Estimated: `3643` + // Minimum execution time: 16_257_000 picoseconds. + Weight::from_parts(16_626_000, 3643) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -109,14 +112,14 @@ impl WeightInfo for SubstrateWeight { /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) /// Storage: Uniques Asset (r:1001 w:1000) /// Proof: Uniques Asset (max_values: None, max_size: Some(122), added: 2597, mode: MaxEncodedLen) + /// Storage: Uniques InstanceMetadataOf (r:1000 w:1000) + /// Proof: Uniques InstanceMetadataOf (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) + /// Storage: Uniques Attribute (r:1000 w:1000) + /// Proof: Uniques Attribute (max_values: None, max_size: Some(364), added: 2839, mode: MaxEncodedLen) /// Storage: Uniques ClassAccount (r:0 w:1) /// Proof: Uniques ClassAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) - /// Storage: Uniques Attribute (r:0 w:1000) - /// Proof: Uniques Attribute (max_values: None, max_size: Some(364), added: 2839, mode: MaxEncodedLen) /// Storage: Uniques ClassMetadataOf (r:0 w:1) /// Proof: Uniques ClassMetadataOf (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) - /// Storage: Uniques InstanceMetadataOf (r:0 w:1000) - /// Proof: Uniques InstanceMetadataOf (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) /// Storage: Uniques Account (r:0 w:1000) /// Proof: Uniques Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) /// Storage: Uniques CollectionMaxSupply (r:0 w:1) @@ -126,23 +129,27 @@ impl WeightInfo for SubstrateWeight { /// The range of component `a` is `[0, 1000]`. fn destroy(n: u32, m: u32, a: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `450 + n * (108 ±0) + m * (56 ±0) + a * (107 ±0)` - // Estimated: `5250 + n * (2597 ±0)` - // Minimum execution time: 2_404_081 nanoseconds. - Weight::from_parts(2_419_004_000, 5250) - // Standard Error: 27_175 - .saturating_add(Weight::from_parts(8_616_904, 0).saturating_mul(n.into())) - // Standard Error: 27_175 - .saturating_add(Weight::from_parts(334_249, 0).saturating_mul(m.into())) - // Standard Error: 27_175 - .saturating_add(Weight::from_parts(213_038, 0).saturating_mul(a.into())) + // Measured: `418 + n * (76 ±0) + m * (56 ±0) + a * (107 ±0)` + // Estimated: `9210 + n * (2597 ±0) + a * (2839 ±0) + m * (2583 ±0)` + // Minimum execution time: 2_510_772_000 picoseconds. + Weight::from_parts(2_522_511_000, 9210) + // Standard Error: 27_455 + .saturating_add(Weight::from_parts(6_708_827, 0).saturating_mul(n.into())) + // Standard Error: 27_455 + .saturating_add(Weight::from_parts(375_591, 0).saturating_mul(m.into())) + // Standard Error: 27_455 + .saturating_add(Weight::from_parts(251_697, 0).saturating_mul(a.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(m.into()))) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(a.into()))) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(m.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(a.into()))) .saturating_add(Weight::from_parts(0, 2597).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 2839).saturating_mul(a.into())) + .saturating_add(Weight::from_parts(0, 2583).saturating_mul(m.into())) } /// Storage: Uniques Asset (r:1 w:1) /// Proof: Uniques Asset (max_values: None, max_size: Some(122), added: 2597, mode: MaxEncodedLen) @@ -154,10 +161,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Uniques Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) fn mint() -> Weight { // Proof Size summary in bytes: - // Measured: `381` - // Estimated: `7749` - // Minimum execution time: 29_326 nanoseconds. - Weight::from_parts(29_671_000, 7749) + // Measured: `349` + // Estimated: `10719` + // Minimum execution time: 33_959_000 picoseconds. + Weight::from_parts(34_380_000, 10719) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -171,10 +178,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Uniques ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) fn burn() -> Weight { // Proof Size summary in bytes: - // Measured: `559` - // Estimated: `5250` - // Minimum execution time: 30_497 nanoseconds. - Weight::from_parts(30_714_000, 5250) + // Measured: `495` + // Estimated: `7230` + // Minimum execution time: 34_194_000 picoseconds. + Weight::from_parts(34_808_000, 7230) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -188,10 +195,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Uniques ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) fn transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `559` - // Estimated: `5250` - // Minimum execution time: 24_212 nanoseconds. - Weight::from_parts(24_681_000, 5250) + // Measured: `495` + // Estimated: `7230` + // Minimum execution time: 27_841_000 picoseconds. + Weight::from_parts(28_263_000, 7230) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -202,12 +209,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `837 + i * (108 ±0)` - // Estimated: `2653 + i * (2597 ±0)` - // Minimum execution time: 13_633 nanoseconds. - Weight::from_parts(13_797_000, 2653) - // Standard Error: 9_293 - .saturating_add(Weight::from_parts(11_163_914, 0).saturating_mul(i.into())) + // Measured: `805 + i * (76 ±0)` + // Estimated: `4633 + i * (2597 ±0)` + // Minimum execution time: 15_577_000 picoseconds. + Weight::from_parts(15_706_000, 4633) + // Standard Error: 17_679 + .saturating_add(Weight::from_parts(14_173_779, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(i.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) @@ -220,10 +227,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) fn freeze() -> Weight { // Proof Size summary in bytes: - // Measured: `559` - // Estimated: `5250` - // Minimum execution time: 17_126 nanoseconds. - Weight::from_parts(17_572_000, 5250) + // Measured: `495` + // Estimated: `7230` + // Minimum execution time: 19_474_000 picoseconds. + Weight::from_parts(19_807_000, 7230) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -233,10 +240,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) fn thaw() -> Weight { // Proof Size summary in bytes: - // Measured: `559` - // Estimated: `5250` - // Minimum execution time: 17_209 nanoseconds. - Weight::from_parts(17_411_000, 5250) + // Measured: `495` + // Estimated: `7230` + // Minimum execution time: 19_526_000 picoseconds. + Weight::from_parts(19_818_000, 7230) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -244,10 +251,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) fn freeze_collection() -> Weight { // Proof Size summary in bytes: - // Measured: `381` - // Estimated: `2653` - // Minimum execution time: 13_048 nanoseconds. - Weight::from_parts(13_589_000, 2653) + // Measured: `349` + // Estimated: `3643` + // Minimum execution time: 15_324_000 picoseconds. + Weight::from_parts(15_599_000, 3643) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -255,10 +262,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) fn thaw_collection() -> Weight { // Proof Size summary in bytes: - // Measured: `381` - // Estimated: `2653` - // Minimum execution time: 12_908 nanoseconds. - Weight::from_parts(13_098_000, 2653) + // Measured: `349` + // Estimated: `3643` + // Minimum execution time: 15_294_000 picoseconds. + Weight::from_parts(15_504_000, 3643) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -270,10 +277,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Uniques ClassAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) fn transfer_ownership() -> Weight { // Proof Size summary in bytes: - // Measured: `455` - // Estimated: `5180` - // Minimum execution time: 20_629 nanoseconds. - Weight::from_parts(21_448_000, 5180) + // Measured: `423` + // Estimated: `7160` + // Minimum execution time: 24_007_000 picoseconds. + Weight::from_parts(24_555_000, 7160) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -281,10 +288,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) fn set_team() -> Weight { // Proof Size summary in bytes: - // Measured: `381` - // Estimated: `2653` - // Minimum execution time: 13_740 nanoseconds. - Weight::from_parts(14_020_000, 2653) + // Measured: `349` + // Estimated: `3643` + // Minimum execution time: 15_616_000 picoseconds. + Weight::from_parts(15_897_000, 3643) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -294,10 +301,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Uniques ClassAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) fn force_item_status() -> Weight { // Proof Size summary in bytes: - // Measured: `381` - // Estimated: `2653` - // Minimum execution time: 16_293 nanoseconds. - Weight::from_parts(16_509_000, 2653) + // Measured: `349` + // Estimated: `3643` + // Minimum execution time: 18_459_000 picoseconds. + Weight::from_parts(18_705_000, 3643) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -309,10 +316,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Uniques Attribute (max_values: None, max_size: Some(364), added: 2839, mode: MaxEncodedLen) fn set_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `611` - // Estimated: `8075` - // Minimum execution time: 33_560 nanoseconds. - Weight::from_parts(34_263_000, 8075) + // Measured: `547` + // Estimated: `11045` + // Minimum execution time: 39_056_000 picoseconds. + Weight::from_parts(39_513_000, 11045) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -324,10 +331,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Uniques Attribute (max_values: None, max_size: Some(364), added: 2839, mode: MaxEncodedLen) fn clear_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `1031` - // Estimated: `8075` - // Minimum execution time: 31_955 nanoseconds. - Weight::from_parts(32_447_000, 8075) + // Measured: `936` + // Estimated: `11045` + // Minimum execution time: 37_441_000 picoseconds. + Weight::from_parts(37_859_000, 11045) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -337,10 +344,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Uniques InstanceMetadataOf (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) fn set_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `447` - // Estimated: `5236` - // Minimum execution time: 25_520 nanoseconds. - Weight::from_parts(25_843_000, 5236) + // Measured: `415` + // Estimated: `7216` + // Minimum execution time: 29_456_000 picoseconds. + Weight::from_parts(29_930_000, 7216) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -350,10 +357,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Uniques InstanceMetadataOf (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) fn clear_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `611` - // Estimated: `5236` - // Minimum execution time: 25_812 nanoseconds. - Weight::from_parts(26_141_000, 5236) + // Measured: `547` + // Estimated: `7216` + // Minimum execution time: 29_817_000 picoseconds. + Weight::from_parts(30_364_000, 7216) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -363,10 +370,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Uniques ClassMetadataOf (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) fn set_collection_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `381` - // Estimated: `5216` - // Minimum execution time: 25_055 nanoseconds. - Weight::from_parts(25_244_000, 5216) + // Measured: `349` + // Estimated: `7196` + // Minimum execution time: 29_392_000 picoseconds. + Weight::from_parts(29_878_000, 7196) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -376,10 +383,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Uniques ClassMetadataOf (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) fn clear_collection_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `525` - // Estimated: `5216` - // Minimum execution time: 23_311 nanoseconds. - Weight::from_parts(23_682_000, 5216) + // Measured: `461` + // Estimated: `7196` + // Minimum execution time: 27_234_000 picoseconds. + Weight::from_parts(27_664_000, 7196) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -389,10 +396,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Uniques Asset (max_values: None, max_size: Some(122), added: 2597, mode: MaxEncodedLen) fn approve_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `559` - // Estimated: `5250` - // Minimum execution time: 17_709 nanoseconds. - Weight::from_parts(18_308_000, 5250) + // Measured: `495` + // Estimated: `7230` + // Minimum execution time: 20_447_000 picoseconds. + Weight::from_parts(20_886_000, 7230) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -402,10 +409,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Uniques Asset (max_values: None, max_size: Some(122), added: 2597, mode: MaxEncodedLen) fn cancel_approval() -> Weight { // Proof Size summary in bytes: - // Measured: `592` - // Estimated: `5250` - // Minimum execution time: 17_656 nanoseconds. - Weight::from_parts(18_039_000, 5250) + // Measured: `528` + // Estimated: `7230` + // Minimum execution time: 20_934_000 picoseconds. + Weight::from_parts(21_271_000, 7230) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -414,9 +421,9 @@ impl WeightInfo for SubstrateWeight { fn set_accept_ownership() -> Weight { // Proof Size summary in bytes: // Measured: `109` - // Estimated: `2527` - // Minimum execution time: 14_615 nanoseconds. - Weight::from_parts(14_931_000, 2527) + // Estimated: `3517` + // Minimum execution time: 17_004_000 picoseconds. + Weight::from_parts(17_401_000, 3517) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -426,10 +433,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) fn set_collection_max_supply() -> Weight { // Proof Size summary in bytes: - // Measured: `381` - // Estimated: `5152` - // Minimum execution time: 14_974 nanoseconds. - Weight::from_parts(15_314_000, 5152) + // Measured: `349` + // Estimated: `7132` + // Minimum execution time: 17_371_000 picoseconds. + Weight::from_parts(18_103_000, 7132) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -439,10 +446,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Uniques ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) fn set_price() -> Weight { // Proof Size summary in bytes: - // Measured: `358` - // Estimated: `2597` - // Minimum execution time: 15_444 nanoseconds. - Weight::from_parts(15_886_000, 2597) + // Measured: `326` + // Estimated: `3587` + // Minimum execution time: 17_624_000 picoseconds. + Weight::from_parts(17_866_000, 3587) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -456,10 +463,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Uniques Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) fn buy_item() -> Weight { // Proof Size summary in bytes: - // Measured: `703` - // Estimated: `7814` - // Minimum execution time: 35_628 nanoseconds. - Weight::from_parts(35_886_000, 7814) + // Measured: `607` + // Estimated: `10784` + // Minimum execution time: 39_736_000 picoseconds. + Weight::from_parts(40_855_000, 10784) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -473,10 +480,10 @@ impl WeightInfo for () { /// Proof: Uniques ClassAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) fn create() -> Weight { // Proof Size summary in bytes: - // Measured: `281` - // Estimated: `2653` - // Minimum execution time: 24_242 nanoseconds. - Weight::from_parts(24_682_000, 2653) + // Measured: `249` + // Estimated: `3643` + // Minimum execution time: 27_805_000 picoseconds. + Weight::from_parts(28_303_000, 3643) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -487,9 +494,9 @@ impl WeightInfo for () { fn force_create() -> Weight { // Proof Size summary in bytes: // Measured: `109` - // Estimated: `2653` - // Minimum execution time: 14_145 nanoseconds. - Weight::from_parts(14_598_000, 2653) + // Estimated: `3643` + // Minimum execution time: 16_257_000 picoseconds. + Weight::from_parts(16_626_000, 3643) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -497,14 +504,14 @@ impl WeightInfo for () { /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) /// Storage: Uniques Asset (r:1001 w:1000) /// Proof: Uniques Asset (max_values: None, max_size: Some(122), added: 2597, mode: MaxEncodedLen) + /// Storage: Uniques InstanceMetadataOf (r:1000 w:1000) + /// Proof: Uniques InstanceMetadataOf (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) + /// Storage: Uniques Attribute (r:1000 w:1000) + /// Proof: Uniques Attribute (max_values: None, max_size: Some(364), added: 2839, mode: MaxEncodedLen) /// Storage: Uniques ClassAccount (r:0 w:1) /// Proof: Uniques ClassAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) - /// Storage: Uniques Attribute (r:0 w:1000) - /// Proof: Uniques Attribute (max_values: None, max_size: Some(364), added: 2839, mode: MaxEncodedLen) /// Storage: Uniques ClassMetadataOf (r:0 w:1) /// Proof: Uniques ClassMetadataOf (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) - /// Storage: Uniques InstanceMetadataOf (r:0 w:1000) - /// Proof: Uniques InstanceMetadataOf (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) /// Storage: Uniques Account (r:0 w:1000) /// Proof: Uniques Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) /// Storage: Uniques CollectionMaxSupply (r:0 w:1) @@ -514,23 +521,27 @@ impl WeightInfo for () { /// The range of component `a` is `[0, 1000]`. fn destroy(n: u32, m: u32, a: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `450 + n * (108 ±0) + m * (56 ±0) + a * (107 ±0)` - // Estimated: `5250 + n * (2597 ±0)` - // Minimum execution time: 2_404_081 nanoseconds. - Weight::from_parts(2_419_004_000, 5250) - // Standard Error: 27_175 - .saturating_add(Weight::from_parts(8_616_904, 0).saturating_mul(n.into())) - // Standard Error: 27_175 - .saturating_add(Weight::from_parts(334_249, 0).saturating_mul(m.into())) - // Standard Error: 27_175 - .saturating_add(Weight::from_parts(213_038, 0).saturating_mul(a.into())) + // Measured: `418 + n * (76 ±0) + m * (56 ±0) + a * (107 ±0)` + // Estimated: `9210 + n * (2597 ±0) + a * (2839 ±0) + m * (2583 ±0)` + // Minimum execution time: 2_510_772_000 picoseconds. + Weight::from_parts(2_522_511_000, 9210) + // Standard Error: 27_455 + .saturating_add(Weight::from_parts(6_708_827, 0).saturating_mul(n.into())) + // Standard Error: 27_455 + .saturating_add(Weight::from_parts(375_591, 0).saturating_mul(m.into())) + // Standard Error: 27_455 + .saturating_add(Weight::from_parts(251_697, 0).saturating_mul(a.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(m.into()))) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(a.into()))) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(RocksDbWeight::get().writes((2_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(m.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(a.into()))) .saturating_add(Weight::from_parts(0, 2597).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 2839).saturating_mul(a.into())) + .saturating_add(Weight::from_parts(0, 2583).saturating_mul(m.into())) } /// Storage: Uniques Asset (r:1 w:1) /// Proof: Uniques Asset (max_values: None, max_size: Some(122), added: 2597, mode: MaxEncodedLen) @@ -542,10 +553,10 @@ impl WeightInfo for () { /// Proof: Uniques Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) fn mint() -> Weight { // Proof Size summary in bytes: - // Measured: `381` - // Estimated: `7749` - // Minimum execution time: 29_326 nanoseconds. - Weight::from_parts(29_671_000, 7749) + // Measured: `349` + // Estimated: `10719` + // Minimum execution time: 33_959_000 picoseconds. + Weight::from_parts(34_380_000, 10719) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -559,10 +570,10 @@ impl WeightInfo for () { /// Proof: Uniques ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) fn burn() -> Weight { // Proof Size summary in bytes: - // Measured: `559` - // Estimated: `5250` - // Minimum execution time: 30_497 nanoseconds. - Weight::from_parts(30_714_000, 5250) + // Measured: `495` + // Estimated: `7230` + // Minimum execution time: 34_194_000 picoseconds. + Weight::from_parts(34_808_000, 7230) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -576,10 +587,10 @@ impl WeightInfo for () { /// Proof: Uniques ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) fn transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `559` - // Estimated: `5250` - // Minimum execution time: 24_212 nanoseconds. - Weight::from_parts(24_681_000, 5250) + // Measured: `495` + // Estimated: `7230` + // Minimum execution time: 27_841_000 picoseconds. + Weight::from_parts(28_263_000, 7230) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -590,12 +601,12 @@ impl WeightInfo for () { /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `837 + i * (108 ±0)` - // Estimated: `2653 + i * (2597 ±0)` - // Minimum execution time: 13_633 nanoseconds. - Weight::from_parts(13_797_000, 2653) - // Standard Error: 9_293 - .saturating_add(Weight::from_parts(11_163_914, 0).saturating_mul(i.into())) + // Measured: `805 + i * (76 ±0)` + // Estimated: `4633 + i * (2597 ±0)` + // Minimum execution time: 15_577_000 picoseconds. + Weight::from_parts(15_706_000, 4633) + // Standard Error: 17_679 + .saturating_add(Weight::from_parts(14_173_779, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(i.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) @@ -608,10 +619,10 @@ impl WeightInfo for () { /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) fn freeze() -> Weight { // Proof Size summary in bytes: - // Measured: `559` - // Estimated: `5250` - // Minimum execution time: 17_126 nanoseconds. - Weight::from_parts(17_572_000, 5250) + // Measured: `495` + // Estimated: `7230` + // Minimum execution time: 19_474_000 picoseconds. + Weight::from_parts(19_807_000, 7230) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -621,10 +632,10 @@ impl WeightInfo for () { /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) fn thaw() -> Weight { // Proof Size summary in bytes: - // Measured: `559` - // Estimated: `5250` - // Minimum execution time: 17_209 nanoseconds. - Weight::from_parts(17_411_000, 5250) + // Measured: `495` + // Estimated: `7230` + // Minimum execution time: 19_526_000 picoseconds. + Weight::from_parts(19_818_000, 7230) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -632,10 +643,10 @@ impl WeightInfo for () { /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) fn freeze_collection() -> Weight { // Proof Size summary in bytes: - // Measured: `381` - // Estimated: `2653` - // Minimum execution time: 13_048 nanoseconds. - Weight::from_parts(13_589_000, 2653) + // Measured: `349` + // Estimated: `3643` + // Minimum execution time: 15_324_000 picoseconds. + Weight::from_parts(15_599_000, 3643) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -643,10 +654,10 @@ impl WeightInfo for () { /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) fn thaw_collection() -> Weight { // Proof Size summary in bytes: - // Measured: `381` - // Estimated: `2653` - // Minimum execution time: 12_908 nanoseconds. - Weight::from_parts(13_098_000, 2653) + // Measured: `349` + // Estimated: `3643` + // Minimum execution time: 15_294_000 picoseconds. + Weight::from_parts(15_504_000, 3643) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -658,10 +669,10 @@ impl WeightInfo for () { /// Proof: Uniques ClassAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) fn transfer_ownership() -> Weight { // Proof Size summary in bytes: - // Measured: `455` - // Estimated: `5180` - // Minimum execution time: 20_629 nanoseconds. - Weight::from_parts(21_448_000, 5180) + // Measured: `423` + // Estimated: `7160` + // Minimum execution time: 24_007_000 picoseconds. + Weight::from_parts(24_555_000, 7160) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -669,10 +680,10 @@ impl WeightInfo for () { /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) fn set_team() -> Weight { // Proof Size summary in bytes: - // Measured: `381` - // Estimated: `2653` - // Minimum execution time: 13_740 nanoseconds. - Weight::from_parts(14_020_000, 2653) + // Measured: `349` + // Estimated: `3643` + // Minimum execution time: 15_616_000 picoseconds. + Weight::from_parts(15_897_000, 3643) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -682,10 +693,10 @@ impl WeightInfo for () { /// Proof: Uniques ClassAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) fn force_item_status() -> Weight { // Proof Size summary in bytes: - // Measured: `381` - // Estimated: `2653` - // Minimum execution time: 16_293 nanoseconds. - Weight::from_parts(16_509_000, 2653) + // Measured: `349` + // Estimated: `3643` + // Minimum execution time: 18_459_000 picoseconds. + Weight::from_parts(18_705_000, 3643) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -697,10 +708,10 @@ impl WeightInfo for () { /// Proof: Uniques Attribute (max_values: None, max_size: Some(364), added: 2839, mode: MaxEncodedLen) fn set_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `611` - // Estimated: `8075` - // Minimum execution time: 33_560 nanoseconds. - Weight::from_parts(34_263_000, 8075) + // Measured: `547` + // Estimated: `11045` + // Minimum execution time: 39_056_000 picoseconds. + Weight::from_parts(39_513_000, 11045) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -712,10 +723,10 @@ impl WeightInfo for () { /// Proof: Uniques Attribute (max_values: None, max_size: Some(364), added: 2839, mode: MaxEncodedLen) fn clear_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `1031` - // Estimated: `8075` - // Minimum execution time: 31_955 nanoseconds. - Weight::from_parts(32_447_000, 8075) + // Measured: `936` + // Estimated: `11045` + // Minimum execution time: 37_441_000 picoseconds. + Weight::from_parts(37_859_000, 11045) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -725,10 +736,10 @@ impl WeightInfo for () { /// Proof: Uniques InstanceMetadataOf (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) fn set_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `447` - // Estimated: `5236` - // Minimum execution time: 25_520 nanoseconds. - Weight::from_parts(25_843_000, 5236) + // Measured: `415` + // Estimated: `7216` + // Minimum execution time: 29_456_000 picoseconds. + Weight::from_parts(29_930_000, 7216) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -738,10 +749,10 @@ impl WeightInfo for () { /// Proof: Uniques InstanceMetadataOf (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) fn clear_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `611` - // Estimated: `5236` - // Minimum execution time: 25_812 nanoseconds. - Weight::from_parts(26_141_000, 5236) + // Measured: `547` + // Estimated: `7216` + // Minimum execution time: 29_817_000 picoseconds. + Weight::from_parts(30_364_000, 7216) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -751,10 +762,10 @@ impl WeightInfo for () { /// Proof: Uniques ClassMetadataOf (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) fn set_collection_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `381` - // Estimated: `5216` - // Minimum execution time: 25_055 nanoseconds. - Weight::from_parts(25_244_000, 5216) + // Measured: `349` + // Estimated: `7196` + // Minimum execution time: 29_392_000 picoseconds. + Weight::from_parts(29_878_000, 7196) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -764,10 +775,10 @@ impl WeightInfo for () { /// Proof: Uniques ClassMetadataOf (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) fn clear_collection_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `525` - // Estimated: `5216` - // Minimum execution time: 23_311 nanoseconds. - Weight::from_parts(23_682_000, 5216) + // Measured: `461` + // Estimated: `7196` + // Minimum execution time: 27_234_000 picoseconds. + Weight::from_parts(27_664_000, 7196) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -777,10 +788,10 @@ impl WeightInfo for () { /// Proof: Uniques Asset (max_values: None, max_size: Some(122), added: 2597, mode: MaxEncodedLen) fn approve_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `559` - // Estimated: `5250` - // Minimum execution time: 17_709 nanoseconds. - Weight::from_parts(18_308_000, 5250) + // Measured: `495` + // Estimated: `7230` + // Minimum execution time: 20_447_000 picoseconds. + Weight::from_parts(20_886_000, 7230) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -790,10 +801,10 @@ impl WeightInfo for () { /// Proof: Uniques Asset (max_values: None, max_size: Some(122), added: 2597, mode: MaxEncodedLen) fn cancel_approval() -> Weight { // Proof Size summary in bytes: - // Measured: `592` - // Estimated: `5250` - // Minimum execution time: 17_656 nanoseconds. - Weight::from_parts(18_039_000, 5250) + // Measured: `528` + // Estimated: `7230` + // Minimum execution time: 20_934_000 picoseconds. + Weight::from_parts(21_271_000, 7230) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -802,9 +813,9 @@ impl WeightInfo for () { fn set_accept_ownership() -> Weight { // Proof Size summary in bytes: // Measured: `109` - // Estimated: `2527` - // Minimum execution time: 14_615 nanoseconds. - Weight::from_parts(14_931_000, 2527) + // Estimated: `3517` + // Minimum execution time: 17_004_000 picoseconds. + Weight::from_parts(17_401_000, 3517) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -814,10 +825,10 @@ impl WeightInfo for () { /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) fn set_collection_max_supply() -> Weight { // Proof Size summary in bytes: - // Measured: `381` - // Estimated: `5152` - // Minimum execution time: 14_974 nanoseconds. - Weight::from_parts(15_314_000, 5152) + // Measured: `349` + // Estimated: `7132` + // Minimum execution time: 17_371_000 picoseconds. + Weight::from_parts(18_103_000, 7132) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -827,10 +838,10 @@ impl WeightInfo for () { /// Proof: Uniques ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) fn set_price() -> Weight { // Proof Size summary in bytes: - // Measured: `358` - // Estimated: `2597` - // Minimum execution time: 15_444 nanoseconds. - Weight::from_parts(15_886_000, 2597) + // Measured: `326` + // Estimated: `3587` + // Minimum execution time: 17_624_000 picoseconds. + Weight::from_parts(17_866_000, 3587) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -844,10 +855,10 @@ impl WeightInfo for () { /// Proof: Uniques Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) fn buy_item() -> Weight { // Proof Size summary in bytes: - // Measured: `703` - // Estimated: `7814` - // Minimum execution time: 35_628 nanoseconds. - Weight::from_parts(35_886_000, 7814) + // Measured: `607` + // Estimated: `10784` + // Minimum execution time: 39_736_000 picoseconds. + Weight::from_parts(40_855_000, 10784) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } diff --git a/frame/utility/src/weights.rs b/frame/utility/src/weights.rs index c680c9ff00f9f..0c50de4f5df88 100644 --- a/frame/utility/src/weights.rs +++ b/frame/utility/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_utility //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-01-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,6 +31,9 @@ // --steps=50 // --repeat=20 // --pallet=pallet_utility +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -63,44 +66,44 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_742 nanoseconds. - Weight::from_parts(16_087_635, 0) - // Standard Error: 2_411 - .saturating_add(Weight::from_parts(3_665_506, 0).saturating_mul(c.into())) + // Minimum execution time: 7_828_000 picoseconds. + Weight::from_parts(13_806_712, 0) + // Standard Error: 2_750 + .saturating_add(Weight::from_parts(4_169_287, 0).saturating_mul(c.into())) } fn as_derivative() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_802 nanoseconds. - Weight::from_parts(5_269_000, 0) + // Minimum execution time: 5_835_000 picoseconds. + Weight::from_parts(6_305_000, 0) } /// The range of component `c` is `[0, 1000]`. fn batch_all(c: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_100 nanoseconds. - Weight::from_parts(14_090_381, 0) - // Standard Error: 1_917 - .saturating_add(Weight::from_parts(3_744_891, 0).saturating_mul(c.into())) + // Minimum execution time: 8_010_000 picoseconds. + Weight::from_parts(10_539_696, 0) + // Standard Error: 2_681 + .saturating_add(Weight::from_parts(4_368_716, 0).saturating_mul(c.into())) } fn dispatch_as() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_840 nanoseconds. - Weight::from_parts(9_280_000, 0) + // Minimum execution time: 10_139_000 picoseconds. + Weight::from_parts(10_679_000, 0) } /// The range of component `c` is `[0, 1000]`. fn force_batch(c: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_245 nanoseconds. - Weight::from_parts(14_292_923, 0) - // Standard Error: 1_803 - .saturating_add(Weight::from_parts(3_645_950, 0).saturating_mul(c.into())) + // Minimum execution time: 7_960_000 picoseconds. + Weight::from_parts(16_874_350, 0) + // Standard Error: 3_040 + .saturating_add(Weight::from_parts(4_151_507, 0).saturating_mul(c.into())) } } @@ -111,43 +114,43 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_742 nanoseconds. - Weight::from_parts(16_087_635, 0) - // Standard Error: 2_411 - .saturating_add(Weight::from_parts(3_665_506, 0).saturating_mul(c.into())) + // Minimum execution time: 7_828_000 picoseconds. + Weight::from_parts(13_806_712, 0) + // Standard Error: 2_750 + .saturating_add(Weight::from_parts(4_169_287, 0).saturating_mul(c.into())) } fn as_derivative() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_802 nanoseconds. - Weight::from_parts(5_269_000, 0) + // Minimum execution time: 5_835_000 picoseconds. + Weight::from_parts(6_305_000, 0) } /// The range of component `c` is `[0, 1000]`. fn batch_all(c: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_100 nanoseconds. - Weight::from_parts(14_090_381, 0) - // Standard Error: 1_917 - .saturating_add(Weight::from_parts(3_744_891, 0).saturating_mul(c.into())) + // Minimum execution time: 8_010_000 picoseconds. + Weight::from_parts(10_539_696, 0) + // Standard Error: 2_681 + .saturating_add(Weight::from_parts(4_368_716, 0).saturating_mul(c.into())) } fn dispatch_as() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_840 nanoseconds. - Weight::from_parts(9_280_000, 0) + // Minimum execution time: 10_139_000 picoseconds. + Weight::from_parts(10_679_000, 0) } /// The range of component `c` is `[0, 1000]`. fn force_batch(c: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_245 nanoseconds. - Weight::from_parts(14_292_923, 0) - // Standard Error: 1_803 - .saturating_add(Weight::from_parts(3_645_950, 0).saturating_mul(c.into())) + // Minimum execution time: 7_960_000 picoseconds. + Weight::from_parts(16_874_350, 0) + // Standard Error: 3_040 + .saturating_add(Weight::from_parts(4_151_507, 0).saturating_mul(c.into())) } } diff --git a/frame/vesting/src/weights.rs b/frame/vesting/src/weights.rs index de3260fa1e6a6..400984f06823d 100644 --- a/frame/vesting/src/weights.rs +++ b/frame/vesting/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_vesting //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-01-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,6 +31,9 @@ // --steps=50 // --repeat=20 // --pallet=pallet_vesting +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -69,14 +72,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[1, 28]`. fn vest_locked(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `444 + l * (25 ±0) + s * (36 ±0)` - // Estimated: `7306` - // Minimum execution time: 28_062 nanoseconds. - Weight::from_parts(26_857_563, 7306) - // Standard Error: 623 - .saturating_add(Weight::from_parts(55_988, 0).saturating_mul(l.into())) - // Standard Error: 1_109 - .saturating_add(Weight::from_parts(59_714, 0).saturating_mul(s.into())) + // Measured: `381 + l * (25 ±0) + s * (36 ±0)` + // Estimated: `9286` + // Minimum execution time: 31_657_000 picoseconds. + Weight::from_parts(30_569_947, 9286) + // Standard Error: 794 + .saturating_add(Weight::from_parts(63_114, 0).saturating_mul(l.into())) + // Standard Error: 1_413 + .saturating_add(Weight::from_parts(58_636, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -88,14 +91,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[1, 28]`. fn vest_unlocked(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `444 + l * (25 ±0) + s * (36 ±0)` - // Estimated: `7306` - // Minimum execution time: 27_027 nanoseconds. - Weight::from_parts(26_509_364, 7306) - // Standard Error: 815 - .saturating_add(Weight::from_parts(54_711, 0).saturating_mul(l.into())) - // Standard Error: 1_451 - .saturating_add(Weight::from_parts(32_792, 0).saturating_mul(s.into())) + // Measured: `381 + l * (25 ±0) + s * (36 ±0)` + // Estimated: `9286` + // Minimum execution time: 30_474_000 picoseconds. + Weight::from_parts(30_227_344, 9286) + // Standard Error: 1_005 + .saturating_add(Weight::from_parts(56_742, 0).saturating_mul(l.into())) + // Standard Error: 1_788 + .saturating_add(Weight::from_parts(33_890, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -109,14 +112,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[1, 28]`. fn vest_other_locked(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `579 + l * (25 ±0) + s * (36 ±0)` - // Estimated: `9909` - // Minimum execution time: 29_554 nanoseconds. - Weight::from_parts(28_269_203, 9909) - // Standard Error: 623 - .saturating_add(Weight::from_parts(59_058, 0).saturating_mul(l.into())) - // Standard Error: 1_108 - .saturating_add(Weight::from_parts(63_429, 0).saturating_mul(s.into())) + // Measured: `484 + l * (25 ±0) + s * (36 ±0)` + // Estimated: `12879` + // Minimum execution time: 33_681_000 picoseconds. + Weight::from_parts(32_540_534, 12879) + // Standard Error: 2_642 + .saturating_add(Weight::from_parts(62_200, 0).saturating_mul(l.into())) + // Standard Error: 4_701 + .saturating_add(Weight::from_parts(69_703, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -130,14 +133,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[1, 28]`. fn vest_other_unlocked(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `579 + l * (25 ±0) + s * (36 ±0)` - // Estimated: `9909` - // Minimum execution time: 28_546 nanoseconds. - Weight::from_parts(28_299_251, 9909) - // Standard Error: 786 - .saturating_add(Weight::from_parts(53_401, 0).saturating_mul(l.into())) - // Standard Error: 1_399 - .saturating_add(Weight::from_parts(29_713, 0).saturating_mul(s.into())) + // Measured: `484 + l * (25 ±0) + s * (36 ±0)` + // Estimated: `12879` + // Minimum execution time: 32_255_000 picoseconds. + Weight::from_parts(31_637_918, 12879) + // Standard Error: 3_135 + .saturating_add(Weight::from_parts(62_121, 0).saturating_mul(l.into())) + // Standard Error: 5_579 + .saturating_add(Weight::from_parts(61_055, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -151,14 +154,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[0, 27]`. fn vested_transfer(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `650 + l * (25 ±0) + s * (36 ±0)` - // Estimated: `9909` - // Minimum execution time: 43_436 nanoseconds. - Weight::from_parts(44_885_707, 9909) - // Standard Error: 1_516 - .saturating_add(Weight::from_parts(59_066, 0).saturating_mul(l.into())) - // Standard Error: 2_698 - .saturating_add(Weight::from_parts(32_053, 0).saturating_mul(s.into())) + // Measured: `555 + l * (25 ±0) + s * (36 ±0)` + // Estimated: `12879` + // Minimum execution time: 51_697_000 picoseconds. + Weight::from_parts(52_048_055, 12879) + // Standard Error: 1_598 + .saturating_add(Weight::from_parts(60_508, 0).saturating_mul(l.into())) + // Standard Error: 2_843 + .saturating_add(Weight::from_parts(37_870, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -172,14 +175,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[0, 27]`. fn force_vested_transfer(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `785 + l * (25 ±0) + s * (36 ±0)` - // Estimated: `12512` - // Minimum execution time: 45_805 nanoseconds. - Weight::from_parts(46_869_490, 12512) - // Standard Error: 1_445 - .saturating_add(Weight::from_parts(52_654, 0).saturating_mul(l.into())) - // Standard Error: 2_571 - .saturating_add(Weight::from_parts(34_202, 0).saturating_mul(s.into())) + // Measured: `658 + l * (25 ±0) + s * (36 ±0)` + // Estimated: `15482` + // Minimum execution time: 54_585_000 picoseconds. + Weight::from_parts(54_492_070, 15482) + // Standard Error: 1_694 + .saturating_add(Weight::from_parts(52_633, 0).saturating_mul(l.into())) + // Standard Error: 3_014 + .saturating_add(Weight::from_parts(45_485, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -193,14 +196,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[2, 28]`. fn not_unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `577 + l * (25 ±0) + s * (36 ±0)` - // Estimated: `9909` - // Minimum execution time: 30_460 nanoseconds. - Weight::from_parts(29_407_637, 9909) - // Standard Error: 794 - .saturating_add(Weight::from_parts(63_757, 0).saturating_mul(l.into())) - // Standard Error: 1_466 - .saturating_add(Weight::from_parts(56_032, 0).saturating_mul(s.into())) + // Measured: `482 + l * (25 ±0) + s * (36 ±0)` + // Estimated: `12879` + // Minimum execution time: 34_312_000 picoseconds. + Weight::from_parts(33_740_101, 12879) + // Standard Error: 996 + .saturating_add(Weight::from_parts(62_123, 0).saturating_mul(l.into())) + // Standard Error: 1_841 + .saturating_add(Weight::from_parts(56_463, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -214,14 +217,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[2, 28]`. fn unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `577 + l * (25 ±0) + s * (36 ±0)` - // Estimated: `9909` - // Minimum execution time: 30_413 nanoseconds. - Weight::from_parts(29_350_467, 9909) - // Standard Error: 724 - .saturating_add(Weight::from_parts(65_366, 0).saturating_mul(l.into())) - // Standard Error: 1_337 - .saturating_add(Weight::from_parts(53_799, 0).saturating_mul(s.into())) + // Measured: `482 + l * (25 ±0) + s * (36 ±0)` + // Estimated: `12879` + // Minimum execution time: 34_965_000 picoseconds. + Weight::from_parts(33_831_484, 12879) + // Standard Error: 1_530 + .saturating_add(Weight::from_parts(59_136, 0).saturating_mul(l.into())) + // Standard Error: 2_827 + .saturating_add(Weight::from_parts(58_493, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -237,14 +240,14 @@ impl WeightInfo for () { /// The range of component `s` is `[1, 28]`. fn vest_locked(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `444 + l * (25 ±0) + s * (36 ±0)` - // Estimated: `7306` - // Minimum execution time: 28_062 nanoseconds. - Weight::from_parts(26_857_563, 7306) - // Standard Error: 623 - .saturating_add(Weight::from_parts(55_988, 0).saturating_mul(l.into())) - // Standard Error: 1_109 - .saturating_add(Weight::from_parts(59_714, 0).saturating_mul(s.into())) + // Measured: `381 + l * (25 ±0) + s * (36 ±0)` + // Estimated: `9286` + // Minimum execution time: 31_657_000 picoseconds. + Weight::from_parts(30_569_947, 9286) + // Standard Error: 794 + .saturating_add(Weight::from_parts(63_114, 0).saturating_mul(l.into())) + // Standard Error: 1_413 + .saturating_add(Weight::from_parts(58_636, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -256,14 +259,14 @@ impl WeightInfo for () { /// The range of component `s` is `[1, 28]`. fn vest_unlocked(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `444 + l * (25 ±0) + s * (36 ±0)` - // Estimated: `7306` - // Minimum execution time: 27_027 nanoseconds. - Weight::from_parts(26_509_364, 7306) - // Standard Error: 815 - .saturating_add(Weight::from_parts(54_711, 0).saturating_mul(l.into())) - // Standard Error: 1_451 - .saturating_add(Weight::from_parts(32_792, 0).saturating_mul(s.into())) + // Measured: `381 + l * (25 ±0) + s * (36 ±0)` + // Estimated: `9286` + // Minimum execution time: 30_474_000 picoseconds. + Weight::from_parts(30_227_344, 9286) + // Standard Error: 1_005 + .saturating_add(Weight::from_parts(56_742, 0).saturating_mul(l.into())) + // Standard Error: 1_788 + .saturating_add(Weight::from_parts(33_890, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -277,14 +280,14 @@ impl WeightInfo for () { /// The range of component `s` is `[1, 28]`. fn vest_other_locked(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `579 + l * (25 ±0) + s * (36 ±0)` - // Estimated: `9909` - // Minimum execution time: 29_554 nanoseconds. - Weight::from_parts(28_269_203, 9909) - // Standard Error: 623 - .saturating_add(Weight::from_parts(59_058, 0).saturating_mul(l.into())) - // Standard Error: 1_108 - .saturating_add(Weight::from_parts(63_429, 0).saturating_mul(s.into())) + // Measured: `484 + l * (25 ±0) + s * (36 ±0)` + // Estimated: `12879` + // Minimum execution time: 33_681_000 picoseconds. + Weight::from_parts(32_540_534, 12879) + // Standard Error: 2_642 + .saturating_add(Weight::from_parts(62_200, 0).saturating_mul(l.into())) + // Standard Error: 4_701 + .saturating_add(Weight::from_parts(69_703, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -298,14 +301,14 @@ impl WeightInfo for () { /// The range of component `s` is `[1, 28]`. fn vest_other_unlocked(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `579 + l * (25 ±0) + s * (36 ±0)` - // Estimated: `9909` - // Minimum execution time: 28_546 nanoseconds. - Weight::from_parts(28_299_251, 9909) - // Standard Error: 786 - .saturating_add(Weight::from_parts(53_401, 0).saturating_mul(l.into())) - // Standard Error: 1_399 - .saturating_add(Weight::from_parts(29_713, 0).saturating_mul(s.into())) + // Measured: `484 + l * (25 ±0) + s * (36 ±0)` + // Estimated: `12879` + // Minimum execution time: 32_255_000 picoseconds. + Weight::from_parts(31_637_918, 12879) + // Standard Error: 3_135 + .saturating_add(Weight::from_parts(62_121, 0).saturating_mul(l.into())) + // Standard Error: 5_579 + .saturating_add(Weight::from_parts(61_055, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -319,14 +322,14 @@ impl WeightInfo for () { /// The range of component `s` is `[0, 27]`. fn vested_transfer(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `650 + l * (25 ±0) + s * (36 ±0)` - // Estimated: `9909` - // Minimum execution time: 43_436 nanoseconds. - Weight::from_parts(44_885_707, 9909) - // Standard Error: 1_516 - .saturating_add(Weight::from_parts(59_066, 0).saturating_mul(l.into())) - // Standard Error: 2_698 - .saturating_add(Weight::from_parts(32_053, 0).saturating_mul(s.into())) + // Measured: `555 + l * (25 ±0) + s * (36 ±0)` + // Estimated: `12879` + // Minimum execution time: 51_697_000 picoseconds. + Weight::from_parts(52_048_055, 12879) + // Standard Error: 1_598 + .saturating_add(Weight::from_parts(60_508, 0).saturating_mul(l.into())) + // Standard Error: 2_843 + .saturating_add(Weight::from_parts(37_870, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -340,14 +343,14 @@ impl WeightInfo for () { /// The range of component `s` is `[0, 27]`. fn force_vested_transfer(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `785 + l * (25 ±0) + s * (36 ±0)` - // Estimated: `12512` - // Minimum execution time: 45_805 nanoseconds. - Weight::from_parts(46_869_490, 12512) - // Standard Error: 1_445 - .saturating_add(Weight::from_parts(52_654, 0).saturating_mul(l.into())) - // Standard Error: 2_571 - .saturating_add(Weight::from_parts(34_202, 0).saturating_mul(s.into())) + // Measured: `658 + l * (25 ±0) + s * (36 ±0)` + // Estimated: `15482` + // Minimum execution time: 54_585_000 picoseconds. + Weight::from_parts(54_492_070, 15482) + // Standard Error: 1_694 + .saturating_add(Weight::from_parts(52_633, 0).saturating_mul(l.into())) + // Standard Error: 3_014 + .saturating_add(Weight::from_parts(45_485, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -361,14 +364,14 @@ impl WeightInfo for () { /// The range of component `s` is `[2, 28]`. fn not_unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `577 + l * (25 ±0) + s * (36 ±0)` - // Estimated: `9909` - // Minimum execution time: 30_460 nanoseconds. - Weight::from_parts(29_407_637, 9909) - // Standard Error: 794 - .saturating_add(Weight::from_parts(63_757, 0).saturating_mul(l.into())) - // Standard Error: 1_466 - .saturating_add(Weight::from_parts(56_032, 0).saturating_mul(s.into())) + // Measured: `482 + l * (25 ±0) + s * (36 ±0)` + // Estimated: `12879` + // Minimum execution time: 34_312_000 picoseconds. + Weight::from_parts(33_740_101, 12879) + // Standard Error: 996 + .saturating_add(Weight::from_parts(62_123, 0).saturating_mul(l.into())) + // Standard Error: 1_841 + .saturating_add(Weight::from_parts(56_463, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -382,14 +385,14 @@ impl WeightInfo for () { /// The range of component `s` is `[2, 28]`. fn unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `577 + l * (25 ±0) + s * (36 ±0)` - // Estimated: `9909` - // Minimum execution time: 30_413 nanoseconds. - Weight::from_parts(29_350_467, 9909) - // Standard Error: 724 - .saturating_add(Weight::from_parts(65_366, 0).saturating_mul(l.into())) - // Standard Error: 1_337 - .saturating_add(Weight::from_parts(53_799, 0).saturating_mul(s.into())) + // Measured: `482 + l * (25 ±0) + s * (36 ±0)` + // Estimated: `12879` + // Minimum execution time: 34_965_000 picoseconds. + Weight::from_parts(33_831_484, 12879) + // Standard Error: 1_530 + .saturating_add(Weight::from_parts(59_136, 0).saturating_mul(l.into())) + // Standard Error: 2_827 + .saturating_add(Weight::from_parts(58_493, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } diff --git a/frame/whitelist/src/weights.rs b/frame/whitelist/src/weights.rs index 667d602a3c0ba..536cd188761b1 100644 --- a/frame/whitelist/src/weights.rs +++ b/frame/whitelist/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_whitelist //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-01-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,6 +31,9 @@ // --steps=50 // --repeat=20 // --pallet=pallet_whitelist +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -64,9 +67,9 @@ impl WeightInfo for SubstrateWeight { fn whitelist_call() -> Weight { // Proof Size summary in bytes: // Measured: `217` - // Estimated: `5081` - // Minimum execution time: 18_618 nanoseconds. - Weight::from_parts(19_133_000, 5081) + // Estimated: `7061` + // Minimum execution time: 21_530_000 picoseconds. + Weight::from_parts(21_986_000, 7061) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -77,9 +80,9 @@ impl WeightInfo for SubstrateWeight { fn remove_whitelisted_call() -> Weight { // Proof Size summary in bytes: // Measured: `346` - // Estimated: `5081` - // Minimum execution time: 16_685 nanoseconds. - Weight::from_parts(17_325_000, 5081) + // Estimated: `7061` + // Minimum execution time: 18_980_000 picoseconds. + Weight::from_parts(19_474_000, 7061) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -92,12 +95,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[1, 4194294]`. fn dispatch_whitelisted_call(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `454 + n * (1 ±0)` - // Estimated: `8007 + n * (1 ±0)` - // Minimum execution time: 27_539 nanoseconds. - Weight::from_parts(27_950_000, 8007) + // Measured: `422 + n * (1 ±0)` + // Estimated: `10947 + n * (1 ±0)` + // Minimum execution time: 32_377_000 picoseconds. + Weight::from_parts(32_643_000, 10947) // Standard Error: 0 - .saturating_add(Weight::from_parts(1_134, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(1_147, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -110,11 +113,11 @@ impl WeightInfo for SubstrateWeight { fn dispatch_whitelisted_call_with_preimage(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `346` - // Estimated: `5081` - // Minimum execution time: 20_581 nanoseconds. - Weight::from_parts(21_762_318, 5081) - // Standard Error: 4 - .saturating_add(Weight::from_parts(1_480, 0).saturating_mul(n.into())) + // Estimated: `7061` + // Minimum execution time: 23_421_000 picoseconds. + Weight::from_parts(24_488_523, 7061) + // Standard Error: 5 + .saturating_add(Weight::from_parts(1_217, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -129,9 +132,9 @@ impl WeightInfo for () { fn whitelist_call() -> Weight { // Proof Size summary in bytes: // Measured: `217` - // Estimated: `5081` - // Minimum execution time: 18_618 nanoseconds. - Weight::from_parts(19_133_000, 5081) + // Estimated: `7061` + // Minimum execution time: 21_530_000 picoseconds. + Weight::from_parts(21_986_000, 7061) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -142,9 +145,9 @@ impl WeightInfo for () { fn remove_whitelisted_call() -> Weight { // Proof Size summary in bytes: // Measured: `346` - // Estimated: `5081` - // Minimum execution time: 16_685 nanoseconds. - Weight::from_parts(17_325_000, 5081) + // Estimated: `7061` + // Minimum execution time: 18_980_000 picoseconds. + Weight::from_parts(19_474_000, 7061) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -157,12 +160,12 @@ impl WeightInfo for () { /// The range of component `n` is `[1, 4194294]`. fn dispatch_whitelisted_call(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `454 + n * (1 ±0)` - // Estimated: `8007 + n * (1 ±0)` - // Minimum execution time: 27_539 nanoseconds. - Weight::from_parts(27_950_000, 8007) + // Measured: `422 + n * (1 ±0)` + // Estimated: `10947 + n * (1 ±0)` + // Minimum execution time: 32_377_000 picoseconds. + Weight::from_parts(32_643_000, 10947) // Standard Error: 0 - .saturating_add(Weight::from_parts(1_134, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(1_147, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -175,11 +178,11 @@ impl WeightInfo for () { fn dispatch_whitelisted_call_with_preimage(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `346` - // Estimated: `5081` - // Minimum execution time: 20_581 nanoseconds. - Weight::from_parts(21_762_318, 5081) - // Standard Error: 4 - .saturating_add(Weight::from_parts(1_480, 0).saturating_mul(n.into())) + // Estimated: `7061` + // Minimum execution time: 23_421_000 picoseconds. + Weight::from_parts(24_488_523, 7061) + // Standard Error: 5 + .saturating_add(Weight::from_parts(1_217, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } From aaa9a3631d29f757552ffcc8b97aa7091c0b27b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Thu, 16 Mar 2023 20:19:48 +0100 Subject: [PATCH 523/715] contracts: Simplify benchmarks (#13595) * Remove batching * Benchmark in bytes not kilobytes * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_contracts * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_contracts * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_contracts * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_contracts * Add rationale for picking batch numbers --------- Co-authored-by: command-bot <> --- frame/contracts/src/benchmarking/code.rs | 2 +- frame/contracts/src/benchmarking/mod.rs | 789 +++-- frame/contracts/src/schedule.rs | 222 +- frame/contracts/src/wasm/prepare.rs | 2 +- frame/contracts/src/weights.rs | 3383 +++++++++++----------- 5 files changed, 2092 insertions(+), 2306 deletions(-) diff --git a/frame/contracts/src/benchmarking/code.rs b/frame/contracts/src/benchmarking/code.rs index aa44cc3976a2c..96eb5e501d068 100644 --- a/frame/contracts/src/benchmarking/code.rs +++ b/frame/contracts/src/benchmarking/code.rs @@ -512,7 +512,7 @@ pub fn max_pages() -> u32 { fn inject_gas_metering(module: Module) -> Module { let schedule = T::Schedule::get(); - let gas_rules = schedule.rules(&module, Determinism::Deterministic); + let gas_rules = schedule.rules(Determinism::Deterministic); let backend = gas_metering::host_function::Injector::new("seal0", "gas"); gas_metering::inject(module, backend, &gas_rules).unwrap() } diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index c18d9ffb4b584..873314981b7ed 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -31,7 +31,6 @@ use self::{ }; use crate::{ exec::{AccountIdOf, FixSizedKey, VarSizedKey}, - schedule::{API_BENCHMARK_BATCH_SIZE, INSTR_BENCHMARK_BATCH_SIZE}, wasm::CallFlags, Pallet as Contracts, *, }; @@ -47,10 +46,17 @@ 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; +/// +/// This is picked more or less arbitrary. We experimented with different numbers until +/// the results appeared to be stable. Reducing the number would speed up the benchmarks +/// but might make the results less precise. +const API_BENCHMARK_BATCHES: u32 = 1600; -/// How many batches we do per Instruction benchmark. -const INSTR_BENCHMARK_BATCHES: u32 = 50; +/// How many batches we do per instruction benchmark. +/// +/// Same rationale as for [`API_BENCHMARK_BATCHES`]. The number is bigger because instruction +/// benchmarks are faster. +const INSTR_BENCHMARK_BATCHES: u32 = 5000; /// An instantiated and deployed contract. struct Contract { @@ -244,7 +250,7 @@ benchmarks! { // 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)`. + // The results are supposed to be used as `call_with_code_per_byte(c) - call_with_code_per_byte(0)`. #[pov_mode = Measured] call_with_code_per_byte { let c in 0 .. T::MaxCodeLen::get(); @@ -263,9 +269,9 @@ benchmarks! { // 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. - // `i`: Size of the input in kilobytes. - // `s`: Size of the salt in kilobytes. + // `c`: Size of the code in bytes. + // `i`: Size of the input in bytes. + // `s`: Size of the salt in bytes. // // # Note // @@ -299,8 +305,8 @@ benchmarks! { } // Instantiate uses a dummy contract constructor to measure the overhead of the instantiate. - // `i`: Size of the input in kilobytes. - // `s`: Size of the salt in kilobytes. + // `i`: Size of the input in bytes. + // `s`: Size of the salt in bytes. #[pov_mode = Measured] instantiate { let i in 0 .. code::max_pages::() * 64 * 1024; @@ -333,7 +339,7 @@ benchmarks! { // The dummy contract used here does not do this. The costs for the data copy is billed as // 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. + // transaction. See `call_with_code_per_byte` for this. #[pov_mode = Measured] call { let data = vec![42u8; 1024]; @@ -362,7 +368,7 @@ benchmarks! { // 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. + // `c`: Size of the code in bytes. // // # Note // @@ -421,7 +427,7 @@ benchmarks! { seal_caller { let r in 0 .. API_BENCHMARK_BATCHES; let instance = Contract::::new(WasmModule::getter( - "seal0", "seal_caller", r * API_BENCHMARK_BATCH_SIZE + "seal0", "seal_caller", r ), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) @@ -429,7 +435,7 @@ benchmarks! { #[pov_mode = Measured] seal_is_contract { let r in 0 .. API_BENCHMARK_BATCHES; - let accounts = (0 .. r * API_BENCHMARK_BATCH_SIZE) + let accounts = (0 .. r) .map(|n| account::("account", n, 0)) .collect::>(); let account_len = accounts.get(0).map(|i| i.encode().len()).unwrap_or(0); @@ -448,7 +454,7 @@ benchmarks! { value: accounts_bytes }, ], - call_body: Some(body::repeated_dyn(r * API_BENCHMARK_BATCH_SIZE, vec![ + call_body: Some(body::repeated_dyn(r, vec![ Counter(0, account_len as u32), // address_ptr Regular(Instruction::Call(0)), Regular(Instruction::Drop), @@ -467,7 +473,7 @@ benchmarks! { #[pov_mode = Measured] seal_code_hash { let r in 0 .. API_BENCHMARK_BATCHES; - let accounts = (0 .. r * API_BENCHMARK_BATCH_SIZE) + let accounts = (0 .. r) .map(|n| account::("account", n, 0)) .collect::>(); let account_len = accounts.get(0).map(|i| i.encode().len()).unwrap_or(0); @@ -492,7 +498,7 @@ benchmarks! { value: accounts_bytes, }, ], - call_body: Some(body::repeated_dyn(r * API_BENCHMARK_BATCH_SIZE, vec![ + call_body: Some(body::repeated_dyn(r, 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 @@ -514,7 +520,7 @@ benchmarks! { seal_own_code_hash { let r in 0 .. API_BENCHMARK_BATCHES; let instance = Contract::::new(WasmModule::getter( - "seal0", "seal_own_code_hash", r * API_BENCHMARK_BATCH_SIZE + "seal0", "seal_own_code_hash", r ), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) @@ -530,7 +536,7 @@ benchmarks! { params: vec![], return_type: Some(ValueType::I32), }], - call_body: Some(body::repeated(r * API_BENCHMARK_BATCH_SIZE, &[ + call_body: Some(body::repeated(r, &[ Instruction::Call(0), Instruction::Drop, ])), @@ -544,7 +550,7 @@ benchmarks! { seal_address { let r in 0 .. API_BENCHMARK_BATCHES; let instance = Contract::::new(WasmModule::getter( - "seal0", "seal_address", r * API_BENCHMARK_BATCH_SIZE + "seal0", "seal_address", r ), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) @@ -553,7 +559,7 @@ benchmarks! { seal_gas_left { let r in 0 .. API_BENCHMARK_BATCHES; let instance = Contract::::new(WasmModule::getter( - "seal0", "seal_gas_left", r * API_BENCHMARK_BATCH_SIZE + "seal0", "seal_gas_left", r ), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) @@ -562,7 +568,7 @@ benchmarks! { seal_balance { let r in 0 .. API_BENCHMARK_BATCHES; let instance = Contract::::new(WasmModule::getter( - "seal0", "seal_balance", r * API_BENCHMARK_BATCH_SIZE + "seal0", "seal_balance", r ), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) @@ -571,7 +577,7 @@ benchmarks! { seal_value_transferred { let r in 0 .. API_BENCHMARK_BATCHES; let instance = Contract::::new(WasmModule::getter( - "seal0", "seal_value_transferred", r * API_BENCHMARK_BATCH_SIZE + "seal0", "seal_value_transferred", r ), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) @@ -580,7 +586,7 @@ benchmarks! { seal_minimum_balance { let r in 0 .. API_BENCHMARK_BATCHES; let instance = Contract::::new(WasmModule::getter( - "seal0", "seal_minimum_balance", r * API_BENCHMARK_BATCH_SIZE + "seal0", "seal_minimum_balance", r ), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) @@ -589,7 +595,7 @@ benchmarks! { seal_block_number { let r in 0 .. API_BENCHMARK_BATCHES; let instance = Contract::::new(WasmModule::getter( - "seal0", "seal_block_number", r * API_BENCHMARK_BATCH_SIZE + "seal0", "seal_block_number", r ), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) @@ -598,7 +604,7 @@ benchmarks! { seal_now { let r in 0 .. API_BENCHMARK_BATCHES; let instance = Contract::::new(WasmModule::getter( - "seal0", "seal_now", r * API_BENCHMARK_BATCH_SIZE + "seal0", "seal_now", r ), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) @@ -619,7 +625,7 @@ benchmarks! { offset: 0, value: (pages * 64 * 1024 - 4).to_le_bytes().to_vec(), }], - call_body: Some(body::repeated(r * API_BENCHMARK_BATCH_SIZE, &[ + call_body: Some(body::repeated(r, &[ Instruction::I64Const(500_000), Instruction::I32Const(4), Instruction::I32Const(0), @@ -641,7 +647,7 @@ benchmarks! { params: vec![ValueType::I64], return_type: None, }], - call_body: Some(body::repeated(r * API_BENCHMARK_BATCH_SIZE, &[ + call_body: Some(body::repeated(r, &[ Instruction::I64Const(42), Instruction::Call(0), ])), @@ -669,7 +675,7 @@ benchmarks! { value: 0u32.to_le_bytes().to_vec(), }, ], - call_body: Some(body::repeated(r * API_BENCHMARK_BATCH_SIZE, &[ + call_body: Some(body::repeated(r, &[ Instruction::I32Const(4), // ptr where to store output Instruction::I32Const(0), // ptr to length Instruction::Call(0), @@ -681,10 +687,9 @@ benchmarks! { }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) #[pov_mode = Measured] - seal_input_per_kb { - let n in 0 .. code::max_pages::() * 64; - let pages = code::max_pages::(); - let buffer_size = pages * 64 * 1024 - 4; + seal_input_per_byte { + let n in 0 .. code::max_pages::() * 64 * 1024; + let buffer_size = code::max_pages::() * 64 * 1024 - 4; let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { @@ -699,15 +704,16 @@ benchmarks! { value: buffer_size.to_le_bytes().to_vec(), }, ], - call_body: Some(body::repeated(API_BENCHMARK_BATCH_SIZE, &[ + call_body: Some(body::plain(vec![ Instruction::I32Const(4), // ptr where to store output Instruction::I32Const(0), // ptr to length Instruction::Call(0), + Instruction::End, ])), .. Default::default() }); let instance = Contract::::new(code, vec![])?; - let data = vec![42u8; (n * 1024).min(buffer_size) as usize]; + let data = vec![42u8; n.min(buffer_size) as usize]; let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, data) @@ -738,8 +744,8 @@ benchmarks! { }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) #[pov_mode = Measured] - seal_return_per_kb { - let n in 0 .. code::max_pages::() * 64; + seal_return_per_byte { + let n in 0 .. code::max_pages::() * 64 * 1024; let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { @@ -751,7 +757,7 @@ benchmarks! { call_body: Some(body::plain(vec![ Instruction::I32Const(0), // flags Instruction::I32Const(0), // data_ptr - Instruction::I32Const((n * 1024) as i32), // data_len + Instruction::I32Const(n as i32), // data_len Instruction::Call(0), Instruction::End, ])), @@ -827,7 +833,7 @@ benchmarks! { value: (pages * 64 * 1024 - subject_len - 4).to_le_bytes().to_vec(), }, ], - call_body: Some(body::repeated(r * API_BENCHMARK_BATCH_SIZE, &[ + call_body: Some(body::repeated(r, &[ Instruction::I32Const(4), // subject_ptr Instruction::I32Const(subject_len as i32), // subject_len Instruction::I32Const((subject_len + 4) as i32), // out_ptr @@ -853,7 +859,7 @@ benchmarks! { params: vec![ValueType::I32, ValueType::I32, ValueType::I32, ValueType::I32], return_type: None, }], - call_body: Some(body::repeated(r * API_BENCHMARK_BATCH_SIZE, &[ + call_body: Some(body::repeated(r, &[ Instruction::I32Const(0), // topics_ptr Instruction::I32Const(0), // topics_len Instruction::I32Const(0), // data_ptr @@ -868,16 +874,13 @@ benchmarks! { // Benchmark the overhead that topics generate. // `t`: Number of topics - // `n`: Size of event payload in kb + // `n`: Size of event payload in bytes #[pov_mode = Measured] - seal_deposit_event_per_topic_and_kb { + seal_deposit_event_per_topic_and_byte { let t in 0 .. T::Schedule::get().limits.event_topics; - let n in 0 .. T::Schedule::get().limits.payload_len / 1024; - let mut topics = (0..API_BENCHMARK_BATCH_SIZE) - .map(|n| (n * t..n * t + t).map(|i| T::Hashing::hash_of(&i)).collect::>().encode()) - .peekable(); - let topics_len = topics.peek().map(|i| i.len()).unwrap_or(0); - let topics = topics.flatten().collect(); + let n in 0 .. T::Schedule::get().limits.payload_len; + let topics = (0..t).map(|i| T::Hashing::hash_of(&i)).collect::>().encode(); + let topics_len = topics.len(); let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { @@ -892,12 +895,13 @@ benchmarks! { value: topics, }, ], - call_body: Some(body::repeated_dyn(API_BENCHMARK_BATCH_SIZE, vec![ - Counter(0, topics_len as u32), // topics_ptr - Regular(Instruction::I32Const(topics_len as i32)), // topics_len - Regular(Instruction::I32Const(0)), // data_ptr - Regular(Instruction::I32Const((n * 1024) as i32)), // data_len - Regular(Instruction::Call(0)), + call_body: Some(body::plain(vec![ + Instruction::I32Const(0), // topics_ptr + Instruction::I32Const(topics_len as i32), // topics_len + Instruction::I32Const(0), // data_ptr + Instruction::I32Const(n as i32), // data_len + Instruction::Call(0), + Instruction::End, ])), .. Default::default() }); @@ -919,7 +923,7 @@ benchmarks! { params: vec![ValueType::I32, ValueType::I32], return_type: Some(ValueType::I32), }], - call_body: Some(body::repeated(r * API_BENCHMARK_BATCH_SIZE, &[ + call_body: Some(body::repeated(r, &[ Instruction::I32Const(0), // value_ptr Instruction::I32Const(0), // value_len Instruction::Call(0), @@ -942,10 +946,10 @@ benchmarks! { .result?; } - seal_debug_message_per_kb { - // Vary size of input in kilobytes up to maximum allowed contract memory + seal_debug_message_per_byte { + // Vary size of input in bytes up to maximum allowed contract memory // or maximum allowed debug buffer size, whichever is less. - let i in 0 .. (T::Schedule::get().limits.memory_pages * 64).min(T::MaxDebugBufferLen::get() / 1024); + let i in 0 .. (T::Schedule::get().limits.memory_pages * 64 * 1024).min(T::MaxDebugBufferLen::get()); // We benchmark versus messages containing printable ASCII codes. // About 1Kb goes to the instrumented contract code instructions, // whereas all the space left we use for the initialization of the debug messages data. @@ -969,7 +973,7 @@ benchmarks! { ], call_body: Some(body::plain(vec![ Instruction::I32Const(0), // value_ptr - Instruction::I32Const((i * 1024) as i32), // value_len increments by i Kb + Instruction::I32Const(i as i32), // value_len Instruction::Call(0), Instruction::Drop, Instruction::End, @@ -994,15 +998,20 @@ benchmarks! { // Only the overhead of calling the function itself with minimal arguments. // 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. We store all the keys that we are about to write at beforehand + // accesses. We store something at all the keys that we are about to write to // because re-writing at an existing key is always more expensive than writing - // it at a virgin key. + // to an key with no data behind it. + // + // # Note + // + // We need to use a smaller `r` because the keys are big and writing them all into the wasm + // might exceed the code size. #[skip_meta] #[pov_mode = Measured] seal_set_storage { let r in 0 .. API_BENCHMARK_BATCHES/2; let max_key_len = T::MaxStorageKeyLen::get(); - let keys = (0 .. r * API_BENCHMARK_BATCH_SIZE) + let keys = (0 .. r) .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::>(); @@ -1021,7 +1030,7 @@ benchmarks! { value: keys_bytes, }, ], - call_body: Some(body::repeated_dyn(r * API_BENCHMARK_BATCH_SIZE, vec![ + call_body: Some(body::repeated_dyn(r, vec![ 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 @@ -1047,14 +1056,10 @@ benchmarks! { #[skip_meta] #[pov_mode = Measured] - seal_set_storage_per_new_kb { - let n in 0 .. T::Schedule::get().limits.payload_len / 2048; // half of the max payload_len in kb + seal_set_storage_per_new_byte { + let n in 0 .. T::Schedule::get().limits.payload_len; 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 = vec![0u8; max_key_len as usize]; let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { @@ -1066,43 +1071,38 @@ benchmarks! { data_segments: vec![ DataSegment { offset: 0, - value: key_bytes, + value: key.clone(), }, ], - call_body: Some(body::repeated_dyn(API_BENCHMARK_BATCH_SIZE, vec![ - 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 * 2048) as i32)), // value_len increments by 2kb up to max payload_len - Regular(Instruction::Call(0)), - Regular(Instruction::Drop), + call_body: Some(body::plain(vec![ + Instruction::I32Const(0), // key_ptr + Instruction::I32Const(max_key_len as i32), // key_len + Instruction::I32Const(0), // value_ptr + Instruction::I32Const(n as i32), // value_len + Instruction::Call(0), + Instruction::Drop, + Instruction::End, ])), .. Default::default() }); let instance = Contract::::new(code, vec![])?; let info = instance.info()?; - for key in keys { - info.write( - &VarSizedKey::::try_from(key).map_err(|e| "Key has wrong length")?, - Some(vec![]), - None, - false, - ) - .map_err(|_| "Failed to write to storage during setup.")?; - } + info.write( + &VarSizedKey::::try_from(key).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] #[pov_mode = Measured] - seal_set_storage_per_old_kb { - let n in 0 .. T::Schedule::get().limits.payload_len / 2048; // half of the max payload_len in kb + seal_set_storage_per_old_byte { + let n in 0 .. T::Schedule::get().limits.payload_len; 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 = vec![0u8; max_key_len as usize]; let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { @@ -1114,30 +1114,29 @@ benchmarks! { data_segments: vec![ DataSegment { offset: 0, - value: key_bytes, + value: key.clone(), }, ], - call_body: Some(body::repeated_dyn(API_BENCHMARK_BATCH_SIZE, vec![ - 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 is 0 as testing vs pre-existing value len - Regular(Instruction::Call(0)), - Regular(Instruction::Drop), + call_body: Some(body::plain(vec![ + Instruction::I32Const(0), // key_ptr + Instruction::I32Const(max_key_len as i32), // key_len + Instruction::I32Const(0), // value_ptr + Instruction::I32Const(0), // value_len is 0 as testing vs pre-existing value len + Instruction::Call(0), + Instruction::Drop, + Instruction::End, ])), .. Default::default() }); let instance = Contract::::new(code, vec![])?; let info = instance.info()?; - for key in keys { - info.write( - &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, - ) - .map_err(|_| "Failed to write to storage during setup.")?; - } + info.write( + &VarSizedKey::::try_from(key).map_err(|e| "Key has wrong length")?, + Some(vec![42u8; n 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![]) @@ -1150,7 +1149,7 @@ benchmarks! { seal_clear_storage { let r in 0 .. API_BENCHMARK_BATCHES/2; let max_key_len = T::MaxStorageKeyLen::get(); - let keys = (0 .. r * API_BENCHMARK_BATCH_SIZE) + let keys = (0 .. r) .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::>(); @@ -1169,7 +1168,7 @@ benchmarks! { value: key_bytes, }, ], - call_body: Some(body::repeated_dyn(r * API_BENCHMARK_BATCH_SIZE, vec![ + call_body: Some(body::repeated_dyn(r, vec![ Counter(0, max_key_len as u32), // key_ptr Regular(Instruction::I32Const(max_key_len as i32)), // key_len Regular(Instruction::Call(0)), @@ -1194,14 +1193,10 @@ benchmarks! { #[skip_meta] #[pov_mode = Measured] - seal_clear_storage_per_kb { - let n in 0 .. T::Schedule::get().limits.payload_len / 2048; // half of the max payload_len in kb + seal_clear_storage_per_byte { + let n in 0 .. T::Schedule::get().limits.payload_len; 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 = vec![0u8; max_key_len as usize]; let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { @@ -1213,28 +1208,27 @@ benchmarks! { data_segments: vec![ DataSegment { offset: 0, - value: key_bytes, + value: key.clone(), }, ], - call_body: Some(body::repeated_dyn(API_BENCHMARK_BATCH_SIZE, vec![ - 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), + call_body: Some(body::plain(vec![ + Instruction::I32Const(0), // key_ptr + Instruction::I32Const(max_key_len as i32), // key_len + Instruction::Call(0), + Instruction::Drop, + Instruction::End, ])), .. Default::default() }); let instance = Contract::::new(code, vec![])?; let info = instance.info()?; - for key in keys { - info.write( - &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, - ) - .map_err(|_| "Failed to write to storage during setup.")?; - } + info.write( + &VarSizedKey::::try_from(key).map_err(|e| "Key has wrong length")?, + Some(vec![42u8; n 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![]) @@ -1244,7 +1238,7 @@ benchmarks! { seal_get_storage { let r in 0 .. API_BENCHMARK_BATCHES/2; let max_key_len = T::MaxStorageKeyLen::get(); - let keys = (0 .. r * API_BENCHMARK_BATCH_SIZE) + let keys = (0 .. r) .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::>(); @@ -1268,8 +1262,8 @@ benchmarks! { 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, max_key_len as u32), // key_ptr + call_body: Some(body::repeated_dyn(r, vec![ + Counter(0, max_key_len), // 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 @@ -1295,15 +1289,10 @@ benchmarks! { #[skip_meta] #[pov_mode = Measured] - seal_get_storage_per_kb { - let n in 0 .. T::Schedule::get().limits.payload_len / 2048; // half of the max payload_len in kb + seal_get_storage_per_byte { + let n in 0 .. T::Schedule::get().limits.payload_len; 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 key = vec![0u8; max_key_len as usize]; let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { @@ -1315,34 +1304,33 @@ benchmarks! { data_segments: vec![ DataSegment { offset: 0, - value: key_bytes, + value: key.clone(), }, DataSegment { - offset: key_bytes_len as u32, + offset: max_key_len, value: T::Schedule::get().limits.payload_len.to_le_bytes().into(), }, ], - call_body: Some(body::repeated_dyn(API_BENCHMARK_BATCH_SIZE, vec![ - 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)), - Regular(Instruction::Drop), + call_body: Some(body::plain(vec![ + Instruction::I32Const(0), // key_ptr + Instruction::I32Const(max_key_len as i32), // key_len + Instruction::I32Const((max_key_len + 4) as i32), // out_ptr + Instruction::I32Const(max_key_len as i32), // out_len_ptr + Instruction::Call(0), + Instruction::Drop, + Instruction::End, ])), .. Default::default() }); let instance = Contract::::new(code, vec![])?; let info = instance.info()?; - for key in keys { - info.write( - &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, - ) - .map_err(|_| "Failed to write to storage during setup.")?; - } + info.write( + &VarSizedKey::::try_from(key).map_err(|e| "Key has wrong length")?, + Some(vec![42u8; n as usize]), + None, + false, + ) + .map_err(|_| "Failed to write to storage during setup.")?; >::insert(&instance.account_id, info); let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) @@ -1353,7 +1341,7 @@ benchmarks! { seal_contains_storage { let r in 0 .. API_BENCHMARK_BATCHES/2; let max_key_len = T::MaxStorageKeyLen::get(); - let keys = (0 .. r * API_BENCHMARK_BATCH_SIZE) + let keys = (0 .. r) .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::>(); @@ -1373,7 +1361,7 @@ benchmarks! { value: key_bytes, }, ], - call_body: Some(body::repeated_dyn(r * API_BENCHMARK_BATCH_SIZE, vec![ + call_body: Some(body::repeated_dyn(r, vec![ Counter(0, max_key_len as u32), // key_ptr Regular(Instruction::I32Const(max_key_len as i32)), // key_len Regular(Instruction::Call(0)), @@ -1398,14 +1386,10 @@ benchmarks! { #[skip_meta] #[pov_mode = Measured] - seal_contains_storage_per_kb { - let n in 0 .. T::Schedule::get().limits.payload_len / 2048; // half of the max payload_len in kb + seal_contains_storage_per_byte { + let n in 0 .. T::Schedule::get().limits.payload_len; 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 = vec![0u8; max_key_len as usize]; let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { @@ -1417,28 +1401,27 @@ benchmarks! { data_segments: vec![ DataSegment { offset: 0, - value: key_bytes, + value: key.clone(), }, ], - call_body: Some(body::repeated_dyn(API_BENCHMARK_BATCH_SIZE, vec![ - 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), + call_body: Some(body::plain(vec![ + Instruction::I32Const(0), // key_ptr + Instruction::I32Const(max_key_len as i32), // key_len + Instruction::Call(0), + Instruction::Drop, + Instruction::End, ])), .. Default::default() }); let instance = Contract::::new(code, vec![])?; let info = instance.info()?; - for key in keys { - info.write( - &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, - ) - .map_err(|_| "Failed to write to storage during setup.")?; - } + info.write( + &VarSizedKey::::try_from(key).map_err(|e| "Key has wrong length")?, + Some(vec![42u8; n as usize]), + None, + false, + ) + .map_err(|_| "Failed to write to storage during setup.")?; >::insert(&instance.account_id, info); let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) @@ -1448,7 +1431,7 @@ benchmarks! { seal_take_storage { let r in 0 .. API_BENCHMARK_BATCHES/2; let max_key_len = T::MaxStorageKeyLen::get(); - let keys = (0 .. r * API_BENCHMARK_BATCH_SIZE) + let keys = (0 .. r) .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::>(); @@ -1472,7 +1455,7 @@ benchmarks! { value: T::Schedule::get().limits.payload_len.to_le_bytes().into(), }, ], - call_body: Some(body::repeated_dyn(r * API_BENCHMARK_BATCH_SIZE, vec![ + call_body: Some(body::repeated_dyn(r, vec![ 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 @@ -1499,15 +1482,10 @@ benchmarks! { #[skip_meta] #[pov_mode = Measured] - seal_take_storage_per_kb { - let n in 0 .. T::Schedule::get().limits.payload_len / 2048; // half of the max payload_len in kb + seal_take_storage_per_byte { + let n in 0 .. T::Schedule::get().limits.payload_len; 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 key = vec![0u8; max_key_len as usize]; let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { @@ -1519,34 +1497,33 @@ benchmarks! { data_segments: vec![ DataSegment { offset: 0, - value: key_bytes, + value: key.clone(), }, DataSegment { - offset: key_bytes_len as u32, + offset: max_key_len, value: T::Schedule::get().limits.payload_len.to_le_bytes().into(), }, ], - call_body: Some(body::repeated_dyn(API_BENCHMARK_BATCH_SIZE, vec![ - 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)), - Regular(Instruction::Drop), + call_body: Some(body::plain(vec![ + Instruction::I32Const(0), // key_ptr + Instruction::I32Const(max_key_len as i32), // key_len + Instruction::I32Const((max_key_len + 4) as i32), // out_ptr + Instruction::I32Const(max_key_len as i32), // out_len_ptr + Instruction::Call(0), + Instruction::Drop, + Instruction::End, ])), .. Default::default() }); let instance = Contract::::new(code, vec![])?; let info = instance.info()?; - for key in keys { - info.write( - &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, - ) - .map_err(|_| "Failed to write to storage during setup.")?; - } + info.write( + &VarSizedKey::::try_from(key).map_err(|e| "Key has wrong length")?, + Some(vec![42u8; n as usize]), + None, + false, + ) + .map_err(|_| "Failed to write to storage during setup.")?; >::insert(&instance.account_id, info); let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) @@ -1555,7 +1532,7 @@ benchmarks! { #[pov_mode = Measured] seal_transfer { let r in 0 .. API_BENCHMARK_BATCHES; - let accounts = (0..r * API_BENCHMARK_BATCH_SIZE) + let accounts = (0..r) .map(|i| account::("receiver", i, 0)) .collect::>(); let account_len = accounts.get(0).map(|i| i.encode().len()).unwrap_or(0); @@ -1582,7 +1559,7 @@ benchmarks! { value: account_bytes, }, ], - call_body: Some(body::repeated_dyn(r * API_BENCHMARK_BATCH_SIZE, vec![ + call_body: Some(body::repeated_dyn(r, vec![ Counter(value_len as u32, account_len as u32), // account_ptr Regular(Instruction::I32Const(account_len as i32)), // account_len Regular(Instruction::I32Const(0)), // value_ptr @@ -1593,7 +1570,7 @@ benchmarks! { .. Default::default() }); let instance = Contract::::new(code, vec![])?; - instance.set_balance(value * (r * API_BENCHMARK_BATCH_SIZE + 1).into()); + instance.set_balance(value * (r + 1).into()); let origin = RawOrigin::Signed(instance.caller.clone()); for account in &accounts { assert_eq!(T::Currency::total_balance(account), 0u32.into()); @@ -1610,7 +1587,7 @@ benchmarks! { seal_call { let r in 0 .. API_BENCHMARK_BATCHES; let dummy_code = WasmModule::::dummy_with_bytes(0); - let callees = (0..r * API_BENCHMARK_BATCH_SIZE) + let callees = (0..r) .map(|i| Contract::with_index(i + 1, dummy_code.clone(), vec![])) .collect::, _>>()?; let callee_len = callees.get(0).map(|i| i.account_id.encode().len()).unwrap_or(0); @@ -1646,7 +1623,7 @@ benchmarks! { value: callee_bytes, }, ], - call_body: Some(body::repeated_dyn(r * API_BENCHMARK_BATCH_SIZE, vec![ + call_body: Some(body::repeated_dyn(r, vec![ 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 @@ -1668,7 +1645,7 @@ benchmarks! { #[pov_mode = Measured] seal_delegate_call { let r in 0 .. API_BENCHMARK_BATCHES; - let hashes = (0..r * API_BENCHMARK_BATCH_SIZE) + let hashes = (0..r) .map(|i| { let code = WasmModule::::dummy_with_bytes(i); Contracts::::store_code_raw(code.code, whitelisted_caller())?; @@ -1701,7 +1678,7 @@ benchmarks! { value: hashes_bytes, }, ], - call_body: Some(body::repeated_dyn(r * API_BENCHMARK_BATCH_SIZE, vec![ + call_body: Some(body::repeated_dyn(r, 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 @@ -1719,14 +1696,10 @@ benchmarks! { }: call(origin, callee, 0u32.into(), Weight::MAX, None, vec![]) #[pov_mode = Measured] - seal_call_per_transfer_clone_kb { + seal_call_per_transfer_clone_byte { let t in 0 .. 1; - let c in 0 .. code::max_pages::() * 64; - let callees = (0..API_BENCHMARK_BATCH_SIZE) - .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 c in 0 .. code::max_pages::() * 64 * 1024; + let callee = Contract::with_index(5, >::dummy(), vec![])?; let value: BalanceOf = t.into(); let value_bytes = value.encode(); let value_len = value_bytes.len(); @@ -1754,33 +1727,34 @@ benchmarks! { }, DataSegment { offset: value_len as u32, - value: callee_bytes, + value: callee.account_id.encode(), }, ], - 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::I64Const(0)), // gas - Regular(Instruction::I32Const(0)), // value_ptr - Regular(Instruction::I32Const(0)), // input_data_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), + call_body: Some(body::plain(vec![ + Instruction::I32Const(CallFlags::CLONE_INPUT.bits() as i32), // flags + Instruction::I32Const(value_len as i32), // callee_ptr + Instruction::I64Const(0), // gas + Instruction::I32Const(0), // value_ptr + Instruction::I32Const(0), // input_data_ptr + Instruction::I32Const(0), // input_data_len + Instruction::I32Const(SENTINEL as i32), // output_ptr + Instruction::I32Const(0), // output_len_ptr + Instruction::Call(0), + Instruction::Drop, + Instruction::End, ])), .. Default::default() }); let instance = Contract::::new(code, vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - let bytes = vec![42; (c * 1024) as usize]; + let bytes = vec![42; c as usize]; }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, bytes) // We assume that every instantiate sends at least the minimum balance. #[pov_mode = Measured] seal_instantiate { let r in 0 .. API_BENCHMARK_BATCHES; - let hashes = (0..r * API_BENCHMARK_BATCH_SIZE) + let hashes = (0..r) .map(|i| { let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), @@ -1848,7 +1822,7 @@ benchmarks! { value: addr_len.to_le_bytes().into(), }, ], - call_body: Some(body::repeated_dyn(r * API_BENCHMARK_BATCH_SIZE, vec![ + call_body: Some(body::repeated_dyn(r, vec![ Counter(hashes_offset as u32, hash_len as u32), // code_hash_ptr Regular(Instruction::I32Const(hash_len as i32)), // code_hash_len Regular(Instruction::I64Const(0)), // gas @@ -1868,7 +1842,7 @@ benchmarks! { .. Default::default() }); let instance = Contract::::new(code, vec![])?; - instance.set_balance((value + Pallet::::min_balance()) * (r * API_BENCHMARK_BATCH_SIZE + 1).into()); + instance.set_balance((value + Pallet::::min_balance()) * (r + 1).into()); let origin = RawOrigin::Signed(instance.caller.clone()); let callee = instance.addr.clone(); let addresses = hashes @@ -1892,37 +1866,24 @@ benchmarks! { } #[pov_mode = Measured] - seal_instantiate_per_transfer_input_salt_kb { + seal_instantiate_per_transfer_input_salt_byte { let t in 0 .. 1; - let i in 0 .. (code::max_pages::() - 1) * 64; - let s in 0 .. (code::max_pages::() - 1) * 64; + let i in 0 .. (code::max_pages::() - 1) * 64 * 1024; + let s in 0 .. (code::max_pages::() - 1) * 64 * 1024; let callee_code = WasmModule::::dummy(); 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())?; - 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: 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 salt_offset = 0; - let value_offset = salts_len; - let hash_offset = value_offset + value_len; - let addr_len_offset = hash_offset + hash_len; let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { - module: "seal0", + module: "seal1", name: "seal_instantiate", params: vec![ - ValueType::I32, ValueType::I32, ValueType::I64, ValueType::I32, @@ -1934,73 +1895,63 @@ benchmarks! { ValueType::I32, ValueType::I32, ValueType::I32, - ValueType::I32, ], return_type: Some(ValueType::I32), }], data_segments: vec![ DataSegment { - offset: salt_offset as u32, - value: salt_bytes, - }, - DataSegment { - offset: value_offset as u32, - value: value_bytes, - }, - DataSegment { - offset: hash_offset as u32, + offset: 0, value: hash_bytes, }, DataSegment { - offset: addr_len_offset as u32, - value: (addr_len as u32).to_le_bytes().into(), + offset: hash_len as u32, + value: value_bytes, }, ], - call_body: Some(body::repeated_dyn(API_BENCHMARK_BATCH_SIZE, vec![ - Regular(Instruction::I32Const(hash_offset as i32)), // code_hash_ptr - Regular(Instruction::I32Const(hash_len as i32)), // code_hash_len - Regular(Instruction::I64Const(0)), // gas - Regular(Instruction::I32Const(value_offset as i32)), // value_ptr - Regular(Instruction::I32Const(value_len as i32)), // value_len - Counter(salt_offset as u32, salt_len as u32), // input_data_ptr - Regular(Instruction::I32Const((i * 1024) as i32)), // 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(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) as i32)), // salt_len - Regular(Instruction::Call(0)), - Regular(Instruction::I32Eqz), - Regular(Instruction::If(BlockType::NoResult)), - Regular(Instruction::Nop), - Regular(Instruction::Else), - Regular(Instruction::Unreachable), - Regular(Instruction::End), + call_body: Some(body::plain(vec![ + Instruction::I32Const(0 as i32), // code_hash_ptr + Instruction::I64Const(0), // gas + Instruction::I32Const(hash_len as i32), // value_ptr + Instruction::I32Const(0 as i32), // input_data_ptr + Instruction::I32Const(i as i32), // input_data_len + Instruction::I32Const(SENTINEL as i32), // address_ptr + Instruction::I32Const(0), // address_len_ptr + Instruction::I32Const(SENTINEL as i32), // output_ptr + Instruction::I32Const(0), // output_len_ptr + Instruction::I32Const(0 as i32), // salt_ptr + Instruction::I32Const(s as i32), // salt_len + Instruction::Call(0), + Instruction::I32Eqz, + Instruction::If(BlockType::NoResult), + Instruction::Nop, + Instruction::Else, + Instruction::Unreachable, + Instruction::End, + Instruction::End, ])), .. Default::default() }); let instance = Contract::::new(code, vec![])?; - instance.set_balance((value + Pallet::::min_balance()) * (API_BENCHMARK_BATCH_SIZE + 1).into()); + instance.set_balance(value + (Pallet::::min_balance() * 2u32.into())); let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) // Only the overhead of calling the function itself with minimal arguments. #[pov_mode = Measured] seal_hash_sha2_256 { - let r in 0 .. 1; + let r in 0 .. API_BENCHMARK_BATCHES; let instance = Contract::::new(WasmModule::hasher( - "seal_hash_sha2_256", r * API_BENCHMARK_BATCH_SIZE, 0, + "seal_hash_sha2_256", r, 0, ), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) - // `n`: Input to hash in kilobytes + // `n`: Input to hash in bytes #[pov_mode = Measured] - seal_hash_sha2_256_per_kb { - let n in 0 .. code::max_pages::() * 64; + seal_hash_sha2_256_per_byte { + let n in 0 .. code::max_pages::() * 64 * 1024; let instance = Contract::::new(WasmModule::hasher( - "seal_hash_sha2_256", API_BENCHMARK_BATCH_SIZE, n * 1024, + "seal_hash_sha2_256", 1, n, ), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) @@ -2008,19 +1959,19 @@ benchmarks! { // Only the overhead of calling the function itself with minimal arguments. #[pov_mode = Measured] seal_hash_keccak_256 { - let r in 0 .. 1; + let r in 0 .. API_BENCHMARK_BATCHES; let instance = Contract::::new(WasmModule::hasher( - "seal_hash_keccak_256", r * API_BENCHMARK_BATCH_SIZE, 0, + "seal_hash_keccak_256", r, 0, ), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) - // `n`: Input to hash in kilobytes + // `n`: Input to hash in bytes #[pov_mode = Measured] - seal_hash_keccak_256_per_kb { - let n in 0 .. code::max_pages::() * 64; + seal_hash_keccak_256_per_byte { + let n in 0 .. code::max_pages::() * 64 * 1024; let instance = Contract::::new(WasmModule::hasher( - "seal_hash_keccak_256", API_BENCHMARK_BATCH_SIZE, n * 1024, + "seal_hash_keccak_256", 1, n, ), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) @@ -2028,19 +1979,19 @@ benchmarks! { // Only the overhead of calling the function itself with minimal arguments. #[pov_mode = Measured] seal_hash_blake2_256 { - let r in 0 .. 1; + let r in 0 .. API_BENCHMARK_BATCHES; let instance = Contract::::new(WasmModule::hasher( - "seal_hash_blake2_256", r * API_BENCHMARK_BATCH_SIZE, 0, + "seal_hash_blake2_256", r, 0, ), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) - // `n`: Input to hash in kilobytes + // `n`: Input to hash in bytes #[pov_mode = Measured] - seal_hash_blake2_256_per_kb { - let n in 0 .. code::max_pages::() * 64; + seal_hash_blake2_256_per_byte { + let n in 0 .. code::max_pages::() * 64 * 1024; let instance = Contract::::new(WasmModule::hasher( - "seal_hash_blake2_256", API_BENCHMARK_BATCH_SIZE, n * 1024, + "seal_hash_blake2_256", 1, n, ), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) @@ -2048,19 +1999,19 @@ benchmarks! { // Only the overhead of calling the function itself with minimal arguments. #[pov_mode = Measured] seal_hash_blake2_128 { - let r in 0 .. 1; + let r in 0 .. API_BENCHMARK_BATCHES; let instance = Contract::::new(WasmModule::hasher( - "seal_hash_blake2_128", r * API_BENCHMARK_BATCH_SIZE, 0, + "seal_hash_blake2_128", r, 0, ), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) - // `n`: Input to hash in kilobytes + // `n`: Input to hash in bytes #[pov_mode = Measured] - seal_hash_blake2_128_per_kb { - let n in 0 .. code::max_pages::() * 64; + seal_hash_blake2_128_per_byte { + let n in 0 .. code::max_pages::() * 64 * 1024; let instance = Contract::::new(WasmModule::hasher( - "seal_hash_blake2_128", API_BENCHMARK_BATCH_SIZE, n * 1024, + "seal_hash_blake2_128", 1, n, ), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) @@ -2069,11 +2020,11 @@ benchmarks! { // It generates different private keys and signatures for the message "Hello world". #[pov_mode = Measured] seal_ecdsa_recover { - let r in 0 .. 1; + let r in 0 .. API_BENCHMARK_BATCHES; 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) + let signatures = (0..r) .map(|i| { 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"); @@ -2101,7 +2052,7 @@ benchmarks! { value: signatures, }, ], - call_body: Some(body::repeated_dyn(r * API_BENCHMARK_BATCH_SIZE, vec![ + call_body: Some(body::repeated_dyn(r, vec![ Counter(32, 65), // signature_ptr Regular(Instruction::I32Const(0)), // message_hash_ptr Regular(Instruction::I32Const(signatures_bytes_len + 32)), // output_len_ptr @@ -2118,9 +2069,9 @@ benchmarks! { // generated different ECDSA keys. #[pov_mode = Measured] seal_ecdsa_to_eth_address { - let r in 0 .. 1; + 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) + let pub_keys_bytes = (0..r) .flat_map(|_| { sp_io::crypto::ecdsa_generate(key_type, None).0 }) @@ -2140,7 +2091,7 @@ benchmarks! { value: pub_keys_bytes, }, ], - call_body: Some(body::repeated_dyn(r * API_BENCHMARK_BATCH_SIZE, vec![ + call_body: Some(body::repeated_dyn(r, vec![ Counter(0, 33), // pub_key_ptr Regular(Instruction::I32Const(pub_keys_bytes_len)), // out_ptr Regular(Instruction::Call(0)), @@ -2155,7 +2106,7 @@ benchmarks! { #[pov_mode = Measured] seal_set_code_hash { let r in 0 .. API_BENCHMARK_BATCHES; - let code_hashes = (0..r * API_BENCHMARK_BATCH_SIZE) + let code_hashes = (0..r) .map(|i| { let new_code = WasmModule::::dummy_with_bytes(i); Contracts::::store_code_raw(new_code.code, whitelisted_caller())?; @@ -2182,7 +2133,7 @@ benchmarks! { value: code_hashes_bytes, }, ], - call_body: Some(body::repeated_dyn(r * API_BENCHMARK_BATCH_SIZE, vec![ + call_body: Some(body::repeated_dyn(r, vec![ Counter(0, code_hash_len as u32), // code_hash_ptr Regular(Instruction::Call(0)), Regular(Instruction::Drop), @@ -2204,7 +2155,7 @@ benchmarks! { params: vec![], return_type: Some(ValueType::I32), }], - call_body: Some(body::repeated(r * API_BENCHMARK_BATCH_SIZE, &[ + call_body: Some(body::repeated(r, &[ Instruction::Call(0), Instruction::Drop, ])), @@ -2218,7 +2169,7 @@ benchmarks! { 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) + let accounts = (0..r) .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); @@ -2237,7 +2188,7 @@ benchmarks! { value: account_id_bytes, }, ], - call_body: Some(body::repeated_dyn(r * API_BENCHMARK_BATCH_SIZE, vec![ + call_body: Some(body::repeated_dyn(r, vec![ Counter(0, account_id_len as u32), // account_ptr Regular(Instruction::Call(0)), Regular(Instruction::Drop), @@ -2259,7 +2210,7 @@ benchmarks! { params: vec![], return_type: Some(ValueType::I64), }], - call_body: Some(body::repeated(r * API_BENCHMARK_BATCH_SIZE, &[ + call_body: Some(body::repeated(r, &[ Instruction::Call(0), Instruction::Drop, ])), @@ -2283,7 +2234,7 @@ benchmarks! { instr_i64const { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::from(ModuleDefinition { - call_body: Some(body::repeated_dyn(r * INSTR_BENCHMARK_BATCH_SIZE, vec![ + call_body: Some(body::repeated_dyn(r, vec![ RandomI64Repeated(1), Regular(Instruction::Drop), ])), @@ -2299,7 +2250,7 @@ benchmarks! { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), - call_body: Some(body::repeated_dyn(r * INSTR_BENCHMARK_BATCH_SIZE, vec![ + call_body: Some(body::repeated_dyn(r, vec![ RandomUnaligned(0, code::max_pages::() * 64 * 1024 - 8), Regular(Instruction::I64Load(3, 0)), Regular(Instruction::Drop), @@ -2316,7 +2267,7 @@ benchmarks! { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), - call_body: Some(body::repeated_dyn(r * INSTR_BENCHMARK_BATCH_SIZE, vec![ + call_body: Some(body::repeated_dyn(r, vec![ RandomUnaligned(0, code::max_pages::() * 64 * 1024 - 8), RandomI64Repeated(1), Regular(Instruction::I64Store(3, 0)), @@ -2332,7 +2283,7 @@ benchmarks! { instr_select { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::from(ModuleDefinition { - call_body: Some(body::repeated_dyn(r * INSTR_BENCHMARK_BATCH_SIZE, vec![ + call_body: Some(body::repeated_dyn(r, vec![ RandomI64Repeated(1), RandomI64Repeated(1), RandomI32(0, 2), @@ -2350,7 +2301,7 @@ benchmarks! { instr_if { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::from(ModuleDefinition { - call_body: Some(body::repeated_dyn(r * INSTR_BENCHMARK_BATCH_SIZE, vec![ + call_body: Some(body::repeated_dyn(r, vec![ RandomI32(0, 2), Regular(Instruction::If(BlockType::Value(ValueType::I64))), RandomI64Repeated(1), @@ -2371,7 +2322,7 @@ benchmarks! { instr_br { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::from(ModuleDefinition { - call_body: Some(body::repeated_dyn(r * INSTR_BENCHMARK_BATCH_SIZE, vec![ + call_body: Some(body::repeated_dyn(r, vec![ Regular(Instruction::Block(BlockType::NoResult)), Regular(Instruction::Block(BlockType::NoResult)), Regular(Instruction::Block(BlockType::NoResult)), @@ -2398,7 +2349,7 @@ benchmarks! { instr_br_if { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::from(ModuleDefinition { - call_body: Some(body::repeated_dyn(r * INSTR_BENCHMARK_BATCH_SIZE, vec![ + call_body: Some(body::repeated_dyn(r, vec![ Regular(Instruction::Block(BlockType::NoResult)), Regular(Instruction::Block(BlockType::NoResult)), Regular(Instruction::Block(BlockType::NoResult)), @@ -2430,7 +2381,7 @@ benchmarks! { default: 1, }); let mut sbox = Sandbox::from(&WasmModule::::from(ModuleDefinition { - call_body: Some(body::repeated_dyn(r * INSTR_BENCHMARK_BATCH_SIZE, vec![ + call_body: Some(body::repeated_dyn(r, vec![ Regular(Instruction::Block(BlockType::NoResult)), Regular(Instruction::Block(BlockType::NoResult)), Regular(Instruction::Block(BlockType::NoResult)), @@ -2465,21 +2416,22 @@ benchmarks! { default: 0, }); let mut sbox = Sandbox::from(&WasmModule::::from(ModuleDefinition { - call_body: Some(body::repeated_dyn(INSTR_BENCHMARK_BATCH_SIZE, vec![ - Regular(Instruction::Block(BlockType::NoResult)), - Regular(Instruction::Block(BlockType::NoResult)), - Regular(Instruction::Block(BlockType::NoResult)), - RandomI32(0, (e + 1) as i32), // Make sure the default entry is also used - Regular(Instruction::BrTable(table)), - RandomI64Repeated(1), - Regular(Instruction::Drop), - Regular(Instruction::End), - RandomI64Repeated(1), - Regular(Instruction::Drop), - Regular(Instruction::End), - RandomI64Repeated(1), - Regular(Instruction::Drop), - Regular(Instruction::End), + call_body: Some(body::plain(vec![ + Instruction::Block(BlockType::NoResult), + Instruction::Block(BlockType::NoResult), + Instruction::Block(BlockType::NoResult), + Instruction::I32Const((e / 2) as i32), + Instruction::BrTable(table), + Instruction::I64Const(42), + Instruction::Drop, + Instruction::End, + Instruction::I64Const(42), + Instruction::Drop, + Instruction::End, + Instruction::I64Const(42), + Instruction::Drop, + Instruction::End, + Instruction::End, ])), .. Default::default() })); @@ -2499,7 +2451,7 @@ benchmarks! { Instruction::Drop, Instruction::End, ])), - call_body: Some(body::repeated(r * INSTR_BENCHMARK_BATCH_SIZE, &[ + call_body: Some(body::repeated(r, &[ Instruction::Call(2), // call aux ])), .. Default::default() @@ -2522,7 +2474,7 @@ benchmarks! { Instruction::Drop, Instruction::End, ])), - call_body: Some(body::repeated_dyn(r * INSTR_BENCHMARK_BATCH_SIZE, vec![ + call_body: Some(body::repeated_dyn(r, vec![ RandomI32(0, num_elements as i32), Regular(Instruction::CallIndirect(0, 0)), // we only have one sig: 0 ])), @@ -2536,39 +2488,6 @@ benchmarks! { sbox.invoke(); } - // w_instr_call_indirect_per_param = w_bench - 1 * w_param - // Calling a function indirectly causes it to go through a thunk function whose runtime - // linearly depend on the amount of parameters to this function. - // Please note that this is not necessary with a direct call. - #[pov_mode = Ignored] - instr_call_indirect_per_param { - let p in 0 .. T::Schedule::get().limits.parameters; - let num_elements = T::Schedule::get().limits.table_size; - use self::code::TableSegment; - let mut sbox = Sandbox::from(&WasmModule::::from(ModuleDefinition { - // We need to make use of the stack here in order to trigger stack height - // instrumentation. - aux_body: Some(body::plain(vec![ - Instruction::I64Const(42), - Instruction::Drop, - Instruction::End, - ])), - aux_arg_num: p, - call_body: Some(body::repeated_dyn(INSTR_BENCHMARK_BATCH_SIZE, vec![ - RandomI64Repeated(p as usize), - RandomI32(0, num_elements as i32), - Regular(Instruction::CallIndirect(p.min(1), 0)), // aux signature: 1 or 0 - ])), - table: Some(TableSegment { - num_elements, - function_index: 2, // aux - }), - .. Default::default() - })); - }: { - sbox.invoke(); - } - // w_per_local = w_bench #[pov_mode = Ignored] instr_call_per_local { @@ -2579,8 +2498,9 @@ benchmarks! { 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, &[ + call_body: Some(body::plain(vec![ Instruction::Call(2), // call aux + Instruction::End, ])), .. Default::default() })); @@ -2593,7 +2513,7 @@ benchmarks! { instr_local_get { let r in 0 .. INSTR_BENCHMARK_BATCHES; let max_locals = T::Schedule::get().limits.locals; - let mut call_body = body::repeated_dyn(r * INSTR_BENCHMARK_BATCH_SIZE, vec![ + let mut call_body = body::repeated_dyn(r, vec![ RandomGetLocal(0, max_locals), Regular(Instruction::Drop), ]); @@ -2611,7 +2531,7 @@ benchmarks! { instr_local_set { let r in 0 .. INSTR_BENCHMARK_BATCHES; let max_locals = T::Schedule::get().limits.locals; - let mut call_body = body::repeated_dyn(r * INSTR_BENCHMARK_BATCH_SIZE, vec![ + let mut call_body = body::repeated_dyn(r, vec![ RandomI64Repeated(1), RandomSetLocal(0, max_locals), ]); @@ -2629,7 +2549,7 @@ benchmarks! { instr_local_tee { let r in 0 .. INSTR_BENCHMARK_BATCHES; let max_locals = T::Schedule::get().limits.locals; - let mut call_body = body::repeated_dyn(r * INSTR_BENCHMARK_BATCH_SIZE, vec![ + let mut call_body = body::repeated_dyn(r, vec![ RandomI64Repeated(1), RandomTeeLocal(0, max_locals), Regular(Instruction::Drop), @@ -2649,7 +2569,7 @@ benchmarks! { let r in 0 .. INSTR_BENCHMARK_BATCHES; let max_globals = T::Schedule::get().limits.globals; let mut sbox = Sandbox::from(&WasmModule::::from(ModuleDefinition { - call_body: Some(body::repeated_dyn(r * INSTR_BENCHMARK_BATCH_SIZE, vec![ + call_body: Some(body::repeated_dyn(r, vec![ RandomGetGlobal(0, max_globals), Regular(Instruction::Drop), ])), @@ -2666,7 +2586,7 @@ benchmarks! { let r in 0 .. INSTR_BENCHMARK_BATCHES; let max_globals = T::Schedule::get().limits.globals; let mut sbox = Sandbox::from(&WasmModule::::from(ModuleDefinition { - call_body: Some(body::repeated_dyn(r * INSTR_BENCHMARK_BATCH_SIZE, vec![ + call_body: Some(body::repeated_dyn(r, vec![ RandomI64Repeated(1), RandomSetGlobal(0, max_globals), ])), @@ -2683,7 +2603,7 @@ benchmarks! { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), - call_body: Some(body::repeated(r * INSTR_BENCHMARK_BATCH_SIZE, &[ + call_body: Some(body::repeated(r, &[ Instruction::CurrentMemory(0), Instruction::Drop ])), @@ -2700,14 +2620,13 @@ benchmarks! { // depends on how much memory is already allocated. #[pov_mode = Ignored] instr_memory_grow { - let r in 0 .. 1; - let max_pages = ImportedMemory::max::().max_pages; + let r in 0 .. ImportedMemory::max::().max_pages; let mut sbox = Sandbox::from(&WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory { min_pages: 0, - max_pages, + max_pages: ImportedMemory::max::().max_pages, }), - call_body: Some(body::repeated(r * max_pages, &[ + call_body: Some(body::repeated(r, &[ Instruction::I32Const(1), Instruction::GrowMemory(0), Instruction::Drop, @@ -2726,7 +2645,7 @@ benchmarks! { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::unary_instr( Instruction::I64Clz, - r * INSTR_BENCHMARK_BATCH_SIZE, + r, )); }: { sbox.invoke(); @@ -2737,7 +2656,7 @@ benchmarks! { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::unary_instr( Instruction::I64Ctz, - r * INSTR_BENCHMARK_BATCH_SIZE, + r, )); }: { sbox.invoke(); @@ -2748,7 +2667,7 @@ benchmarks! { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::unary_instr( Instruction::I64Popcnt, - r * INSTR_BENCHMARK_BATCH_SIZE, + r, )); }: { sbox.invoke(); @@ -2759,7 +2678,7 @@ benchmarks! { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::unary_instr( Instruction::I64Eqz, - r * INSTR_BENCHMARK_BATCH_SIZE, + r, )); }: { sbox.invoke(); @@ -2769,7 +2688,7 @@ benchmarks! { instr_i64extendsi32 { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::from(ModuleDefinition { - call_body: Some(body::repeated_dyn(r * INSTR_BENCHMARK_BATCH_SIZE, vec![ + call_body: Some(body::repeated_dyn(r, vec![ RandomI32Repeated(1), Regular(Instruction::I64ExtendSI32), Regular(Instruction::Drop), @@ -2784,7 +2703,7 @@ benchmarks! { instr_i64extendui32 { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::from(ModuleDefinition { - call_body: Some(body::repeated_dyn(r * INSTR_BENCHMARK_BATCH_SIZE, vec![ + call_body: Some(body::repeated_dyn(r, vec![ RandomI32Repeated(1), Regular(Instruction::I64ExtendUI32), Regular(Instruction::Drop), @@ -2800,7 +2719,7 @@ benchmarks! { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::unary_instr( Instruction::I32WrapI64, - r * INSTR_BENCHMARK_BATCH_SIZE, + r, )); }: { sbox.invoke(); @@ -2814,7 +2733,7 @@ benchmarks! { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( Instruction::I64Eq, - r * INSTR_BENCHMARK_BATCH_SIZE, + r, )); }: { sbox.invoke(); @@ -2825,7 +2744,7 @@ benchmarks! { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( Instruction::I64Ne, - r * INSTR_BENCHMARK_BATCH_SIZE, + r, )); }: { sbox.invoke(); @@ -2836,7 +2755,7 @@ benchmarks! { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( Instruction::I64LtS, - r * INSTR_BENCHMARK_BATCH_SIZE, + r, )); }: { sbox.invoke(); @@ -2847,7 +2766,7 @@ benchmarks! { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( Instruction::I64LtU, - r * INSTR_BENCHMARK_BATCH_SIZE, + r, )); }: { sbox.invoke(); @@ -2858,7 +2777,7 @@ benchmarks! { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( Instruction::I64GtS, - r * INSTR_BENCHMARK_BATCH_SIZE, + r, )); }: { sbox.invoke(); @@ -2869,7 +2788,7 @@ benchmarks! { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( Instruction::I64GtU, - r * INSTR_BENCHMARK_BATCH_SIZE, + r, )); }: { sbox.invoke(); @@ -2880,7 +2799,7 @@ benchmarks! { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( Instruction::I64LeS, - r * INSTR_BENCHMARK_BATCH_SIZE, + r, )); }: { sbox.invoke(); @@ -2891,7 +2810,7 @@ benchmarks! { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( Instruction::I64LeU, - r * INSTR_BENCHMARK_BATCH_SIZE, + r, )); }: { sbox.invoke(); @@ -2902,7 +2821,7 @@ benchmarks! { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( Instruction::I64GeS, - r * INSTR_BENCHMARK_BATCH_SIZE, + r, )); }: { sbox.invoke(); @@ -2913,7 +2832,7 @@ benchmarks! { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( Instruction::I64GeU, - r * INSTR_BENCHMARK_BATCH_SIZE, + r, )); }: { sbox.invoke(); @@ -2924,7 +2843,7 @@ benchmarks! { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( Instruction::I64Add, - r * INSTR_BENCHMARK_BATCH_SIZE, + r, )); }: { sbox.invoke(); @@ -2935,7 +2854,7 @@ benchmarks! { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( Instruction::I64Sub, - r * INSTR_BENCHMARK_BATCH_SIZE, + r, )); }: { sbox.invoke(); @@ -2946,7 +2865,7 @@ benchmarks! { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( Instruction::I64Mul, - r * INSTR_BENCHMARK_BATCH_SIZE, + r, )); }: { sbox.invoke(); @@ -2957,7 +2876,7 @@ benchmarks! { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( Instruction::I64DivS, - r * INSTR_BENCHMARK_BATCH_SIZE, + r, )); }: { sbox.invoke(); @@ -2968,7 +2887,7 @@ benchmarks! { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( Instruction::I64DivU, - r * INSTR_BENCHMARK_BATCH_SIZE, + r, )); }: { sbox.invoke(); @@ -2979,7 +2898,7 @@ benchmarks! { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( Instruction::I64RemS, - r * INSTR_BENCHMARK_BATCH_SIZE, + r, )); }: { sbox.invoke(); @@ -2990,7 +2909,7 @@ benchmarks! { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( Instruction::I64RemU, - r * INSTR_BENCHMARK_BATCH_SIZE, + r, )); }: { sbox.invoke(); @@ -3001,7 +2920,7 @@ benchmarks! { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( Instruction::I64And, - r * INSTR_BENCHMARK_BATCH_SIZE, + r, )); }: { sbox.invoke(); @@ -3012,7 +2931,7 @@ benchmarks! { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( Instruction::I64Or, - r * INSTR_BENCHMARK_BATCH_SIZE, + r, )); }: { sbox.invoke(); @@ -3023,7 +2942,7 @@ benchmarks! { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( Instruction::I64Xor, - r * INSTR_BENCHMARK_BATCH_SIZE, + r, )); }: { sbox.invoke(); @@ -3034,7 +2953,7 @@ benchmarks! { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( Instruction::I64Shl, - r * INSTR_BENCHMARK_BATCH_SIZE, + r, )); }: { sbox.invoke(); @@ -3045,7 +2964,7 @@ benchmarks! { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( Instruction::I64ShrS, - r * INSTR_BENCHMARK_BATCH_SIZE, + r, )); }: { sbox.invoke(); @@ -3056,7 +2975,7 @@ benchmarks! { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( Instruction::I64ShrU, - r * INSTR_BENCHMARK_BATCH_SIZE, + r, )); }: { sbox.invoke(); @@ -3067,7 +2986,7 @@ benchmarks! { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( Instruction::I64Rotl, - r * INSTR_BENCHMARK_BATCH_SIZE, + r, )); }: { sbox.invoke(); @@ -3078,7 +2997,7 @@ benchmarks! { let r in 0 .. INSTR_BENCHMARK_BATCHES; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( Instruction::I64Rotr, - r * INSTR_BENCHMARK_BATCH_SIZE, + r, )); }: { sbox.invoke(); diff --git a/frame/contracts/src/schedule.rs b/frame/contracts/src/schedule.rs index 71faf08c23d6a..796a7f6d3718d 100644 --- a/frame/contracts/src/schedule.rs +++ b/frame/contracts/src/schedule.rs @@ -27,18 +27,9 @@ use scale_info::TypeInfo; #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; use sp_runtime::RuntimeDebug; -use sp_std::{marker::PhantomData, vec::Vec}; +use sp_std::marker::PhantomData; 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 = 80; - -/// How many instructions are executed in a single batch. The reasoning is the same -/// as for `API_BENCHMARK_BATCH_SIZE`. -pub const INSTR_BENCHMARK_BATCH_SIZE: u32 = 100; - /// Definition of the cost schedule and other parameterizations for the wasm vm. /// /// Its [`Default`] implementation is the designated way to initialize this type. It uses @@ -200,7 +191,6 @@ pub struct InstructionWeights { pub br_table_per_entry: u32, 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, @@ -451,66 +441,22 @@ macro_rules! cost_args { } } -macro_rules! cost_batched_args { - ($name:ident, $( $arg: expr ),+) => { - 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).ref_time() / u64::from($batch_size)) as u32 - }; -} - -macro_rules! cost_instr_with_batch_size { - ($name:ident, $num_params:expr, $batch_size:expr) => { - cost_instr_no_params_with_batch_size!($name, $batch_size).saturating_sub( - (cost_instr_no_params_with_batch_size!(instr_i64const, $batch_size) / 2) - .saturating_mul($num_params), - ) - }; -} - -macro_rules! cost_instr { - ($name:ident, $num_params:expr) => { - cost_instr_with_batch_size!($name, $num_params, INSTR_BENCHMARK_BATCH_SIZE) +macro_rules! cost_instr_no_params { + ($name:ident) => { + cost_args!($name, 1).ref_time() as u32 }; } -macro_rules! cost_byte_args { - ($name:ident, $( $arg: expr ),+) => { - cost_args!($name, $( $arg ),+) / 1024 - } -} - -macro_rules! cost_byte_batched_args { - ($name:ident, $( $arg: expr ),+) => { - cost_batched_args!($name, $( $arg ),+) / 1024 - } -} - macro_rules! cost { ($name:ident) => { cost_args!($name, 1) }; } -macro_rules! cost_batched { - ($name:ident) => { - cost_batched_args!($name, 1) - }; -} - -macro_rules! cost_byte { - ($name:ident) => { - cost_byte_args!($name, 1) - }; -} - -macro_rules! cost_byte_batched { - ($name:ident) => { - cost_byte_batched_args!($name, 1) +macro_rules! cost_instr { + ($name:ident, $num_params:expr) => { + cost_instr_no_params!($name) + .saturating_sub((cost_instr_no_params!(instr_i64const) / 2).saturating_mul($num_params)) }; } @@ -533,7 +479,6 @@ impl Default for Limits { impl Default for InstructionWeights { fn default() -> Self { - let max_pages = Limits::default().memory_pages; Self { version: 4, fallback: 0, @@ -548,7 +493,6 @@ impl Default for InstructionWeights { br_table_per_entry: cost_instr!(instr_br_table_per_entry, 0), 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, 0), call_per_local: cost_instr!(instr_call_per_local, 0), local_get: cost_instr!(instr_local_get, 1), local_set: cost_instr!(instr_local_set, 1), @@ -556,7 +500,7 @@ impl Default for InstructionWeights { global_get: cost_instr!(instr_global_get, 1), global_set: cost_instr!(instr_global_set, 1), memory_current: cost_instr!(instr_memory_current, 1), - memory_grow: cost_instr_with_batch_size!(instr_memory_grow, 1, max_pages), + memory_grow: cost_instr!(instr_memory_grow, 1), i64clz: cost_instr!(instr_i64clz, 2), i64ctz: cost_instr!(instr_i64ctz, 2), i64popcnt: cost_instr!(instr_i64popcnt, 2), @@ -597,89 +541,85 @@ impl Default for InstructionWeights { impl Default for HostFnWeights { fn default() -> Self { 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), - balance: cost_batched!(seal_balance), - value_transferred: cost_batched!(seal_value_transferred), - minimum_balance: cost_batched!(seal_minimum_balance), - block_number: cost_batched!(seal_block_number), - now: cost_batched!(seal_now), - weight_to_fee: cost_batched!(seal_weight_to_fee), + caller: cost!(seal_caller), + is_contract: cost!(seal_is_contract), + code_hash: cost!(seal_code_hash), + own_code_hash: cost!(seal_own_code_hash), + caller_is_origin: cost!(seal_caller_is_origin), + address: cost!(seal_address), + gas_left: cost!(seal_gas_left), + balance: cost!(seal_balance), + value_transferred: cost!(seal_value_transferred), + minimum_balance: cost!(seal_minimum_balance), + block_number: cost!(seal_block_number), + now: cost!(seal_now), + weight_to_fee: cost!(seal_weight_to_fee), // Manually remove proof size from basic block cost. // // Due to imperfect benchmarking some host functions incur a small // amount of proof size. Usually this is ok. However, charging a basic block is such // a frequent operation that this would be a vast overestimation. - gas: cost_batched!(seal_gas).set_proof_size(0), - input: cost_batched!(seal_input), - input_per_byte: cost_byte_batched!(seal_input_per_kb), + gas: cost!(seal_gas).set_proof_size(0), + input: cost!(seal_input), + input_per_byte: cost!(seal_input_per_byte), r#return: cost!(seal_return), - return_per_byte: cost_byte!(seal_return_per_kb), + return_per_byte: cost!(seal_return_per_byte), terminate: cost!(seal_terminate), - random: cost_batched!(seal_random), - deposit_event: cost_batched!(seal_deposit_event), - deposit_event_per_topic: cost_batched_args!(seal_deposit_event_per_topic_and_kb, 1, 0), - deposit_event_per_byte: cost_byte_batched_args!( - seal_deposit_event_per_topic_and_kb, - 0, - 1 - ), - debug_message: cost_batched!(seal_debug_message), - debug_message_per_byte: cost_byte!(seal_debug_message_per_kb), - 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), - 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), - 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_clone_kb, 1, 0), - call_per_cloned_byte: cost_byte_batched_args!(seal_call_per_transfer_clone_kb, 0, 1), - instantiate: cost_batched!(seal_instantiate), - instantiate_transfer_surcharge: cost_batched_args!( - seal_instantiate_per_transfer_input_salt_kb, + random: cost!(seal_random), + deposit_event: cost!(seal_deposit_event), + deposit_event_per_topic: cost_args!(seal_deposit_event_per_topic_and_byte, 1, 0), + deposit_event_per_byte: cost_args!(seal_deposit_event_per_topic_and_byte, 0, 1), + debug_message: cost!(seal_debug_message), + debug_message_per_byte: cost!(seal_debug_message_per_byte), + set_storage: cost!(seal_set_storage), + set_code_hash: cost!(seal_set_code_hash), + set_storage_per_new_byte: cost!(seal_set_storage_per_new_byte), + set_storage_per_old_byte: cost!(seal_set_storage_per_old_byte), + clear_storage: cost!(seal_clear_storage), + clear_storage_per_byte: cost!(seal_clear_storage_per_byte), + contains_storage: cost!(seal_contains_storage), + contains_storage_per_byte: cost!(seal_contains_storage_per_byte), + get_storage: cost!(seal_get_storage), + get_storage_per_byte: cost!(seal_get_storage_per_byte), + take_storage: cost!(seal_take_storage), + take_storage_per_byte: cost!(seal_take_storage_per_byte), + transfer: cost!(seal_transfer), + call: cost!(seal_call), + delegate_call: cost!(seal_delegate_call), + call_transfer_surcharge: cost_args!(seal_call_per_transfer_clone_byte, 1, 0), + call_per_cloned_byte: cost_args!(seal_call_per_transfer_clone_byte, 0, 1), + instantiate: cost!(seal_instantiate), + instantiate_transfer_surcharge: cost_args!( + seal_instantiate_per_transfer_input_salt_byte, 1, 0, 0 ), - instantiate_per_input_byte: cost_byte_batched_args!( - seal_instantiate_per_transfer_input_salt_kb, + instantiate_per_input_byte: cost_args!( + seal_instantiate_per_transfer_input_salt_byte, 0, 1, 0 ), - instantiate_per_salt_byte: cost_byte_batched_args!( - seal_instantiate_per_transfer_input_salt_kb, + instantiate_per_salt_byte: cost_args!( + seal_instantiate_per_transfer_input_salt_byte, 0, 0, 1 ), - hash_sha2_256: cost_batched!(seal_hash_sha2_256), - hash_sha2_256_per_byte: cost_byte_batched!(seal_hash_sha2_256_per_kb), - hash_keccak_256: cost_batched!(seal_hash_keccak_256), - hash_keccak_256_per_byte: cost_byte_batched!(seal_hash_keccak_256_per_kb), - hash_blake2_256: cost_batched!(seal_hash_blake2_256), - hash_blake2_256_per_byte: cost_byte_batched!(seal_hash_blake2_256_per_kb), - 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), - reentrance_count: cost_batched!(seal_reentrance_count), - account_reentrance_count: cost_batched!(seal_account_reentrance_count), - instantiation_nonce: cost_batched!(seal_instantiation_nonce), + hash_sha2_256: cost!(seal_hash_sha2_256), + hash_sha2_256_per_byte: cost!(seal_hash_sha2_256_per_byte), + hash_keccak_256: cost!(seal_hash_keccak_256), + hash_keccak_256_per_byte: cost!(seal_hash_keccak_256_per_byte), + hash_blake2_256: cost!(seal_hash_blake2_256), + hash_blake2_256_per_byte: cost!(seal_hash_blake2_256_per_byte), + hash_blake2_128: cost!(seal_hash_blake2_128), + hash_blake2_128_per_byte: cost!(seal_hash_blake2_128_per_byte), + ecdsa_recover: cost!(seal_ecdsa_recover), + ecdsa_to_eth_address: cost!(seal_ecdsa_to_eth_address), + reentrance_count: cost!(seal_reentrance_count), + account_reentrance_count: cost!(seal_account_reentrance_count), + instantiation_nonce: cost!(seal_instantiation_nonce), _phantom: PhantomData, } } @@ -687,29 +627,12 @@ 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, - determinism: Determinism, - ) -> impl gas_metering::Rules + '_ { - ScheduleRules { - schedule: self, - params: module - .type_section() - .iter() - .flat_map(|section| section.types()) - .map(|func| { - let elements::Type::Function(func) = func; - func.params().len() as u32 - }) - .collect(), - determinism, - } + pub(crate) fn rules(&self, determinism: Determinism) -> impl gas_metering::Rules + '_ { + ScheduleRules { schedule: self, determinism } } } @@ -717,7 +640,6 @@ 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; - let max_params = self.schedule.limits.parameters; let weight = match *instruction { End | Unreachable | Return | Else => 0, @@ -753,7 +675,7 @@ impl<'a, T: Config> gas_metering::Rules for ScheduleRules<'a, T> { SetGlobal(_) => w.global_set, CurrentMemory(_) => w.memory_current, GrowMemory(_) => w.memory_grow, - CallIndirect(idx, _) => *self.params.get(idx as usize).unwrap_or(&max_params), + CallIndirect(_, _) => w.call_indirect, BrTable(ref data) => w .br_table .saturating_add(w.br_table_per_entry.saturating_mul(data.table.len() as u32)), diff --git a/frame/contracts/src/wasm/prepare.rs b/frame/contracts/src/wasm/prepare.rs index 3c69fc2a7940f..eed60891d66f4 100644 --- a/frame/contracts/src/wasm/prepare.rs +++ b/frame/contracts/src/wasm/prepare.rs @@ -219,7 +219,7 @@ 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 gas_rules = self.schedule.rules(determinism); 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")?; diff --git a/frame/contracts/src/weights.rs b/frame/contracts/src/weights.rs index ae8638eb73431..b16f11eb7f50a 100644 --- a/frame/contracts/src/weights.rs +++ b/frame/contracts/src/weights.rs @@ -18,28 +18,26 @@ //! Autogenerated weights for pallet_contracts //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-14, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate +// target/production/substrate // benchmark // pallet -// --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet_contracts -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --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)] @@ -77,40 +75,40 @@ pub trait WeightInfo { fn seal_weight_to_fee(r: u32, ) -> Weight; fn seal_gas(r: u32, ) -> Weight; fn seal_input(r: u32, ) -> Weight; - fn seal_input_per_kb(n: u32, ) -> Weight; + fn seal_input_per_byte(n: u32, ) -> Weight; fn seal_return(r: u32, ) -> Weight; - fn seal_return_per_kb(n: u32, ) -> Weight; + fn seal_return_per_byte(n: u32, ) -> Weight; fn seal_terminate(r: u32, ) -> Weight; fn seal_random(r: u32, ) -> Weight; fn seal_deposit_event(r: u32, ) -> Weight; - fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight; + fn seal_deposit_event_per_topic_and_byte(t: u32, n: u32, ) -> Weight; fn seal_debug_message(r: u32, ) -> Weight; - fn seal_debug_message_per_kb(i: u32, ) -> Weight; + fn seal_debug_message_per_byte(i: u32, ) -> Weight; fn seal_set_storage(r: u32, ) -> Weight; - fn seal_set_storage_per_new_kb(n: u32, ) -> Weight; - fn seal_set_storage_per_old_kb(n: u32, ) -> Weight; + fn seal_set_storage_per_new_byte(n: u32, ) -> Weight; + fn seal_set_storage_per_old_byte(n: u32, ) -> Weight; fn seal_clear_storage(r: u32, ) -> Weight; - fn seal_clear_storage_per_kb(n: u32, ) -> Weight; + fn seal_clear_storage_per_byte(n: u32, ) -> Weight; fn seal_get_storage(r: u32, ) -> Weight; - fn seal_get_storage_per_kb(n: u32, ) -> Weight; + fn seal_get_storage_per_byte(n: u32, ) -> Weight; fn seal_contains_storage(r: u32, ) -> Weight; - fn seal_contains_storage_per_kb(n: u32, ) -> Weight; + fn seal_contains_storage_per_byte(n: u32, ) -> Weight; fn seal_take_storage(r: u32, ) -> Weight; - fn seal_take_storage_per_kb(n: u32, ) -> Weight; + fn seal_take_storage_per_byte(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_clone_kb(t: u32, c: u32, ) -> Weight; + fn seal_call_per_transfer_clone_byte(t: u32, c: u32, ) -> Weight; fn seal_instantiate(r: u32, ) -> Weight; - fn seal_instantiate_per_transfer_input_salt_kb(t: u32, i: u32, s: u32, ) -> Weight; + fn seal_instantiate_per_transfer_input_salt_byte(t: u32, i: 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_sha2_256_per_byte(n: u32, ) -> Weight; fn seal_hash_keccak_256(r: u32, ) -> Weight; - fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight; + fn seal_hash_keccak_256_per_byte(n: u32, ) -> Weight; fn seal_hash_blake2_256(r: u32, ) -> Weight; - fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight; + fn seal_hash_blake2_256_per_byte(n: u32, ) -> Weight; fn seal_hash_blake2_128(r: u32, ) -> Weight; - fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight; + fn seal_hash_blake2_128_per_byte(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; @@ -128,7 +126,6 @@ pub trait WeightInfo { fn instr_br_table_per_entry(e: u32, ) -> Weight; 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; @@ -180,8 +177,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `109` // Estimated: `1594` - // Minimum execution time: 2_679_000 picoseconds. - Weight::from_parts(2_907_000, 1594) + // Minimum execution time: 2_736_000 picoseconds. + Weight::from_parts(2_931_000, 1594) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: Skipped Metadata (r:0 w:0) @@ -189,12 +186,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `k` is `[0, 1024]`. fn on_initialize_per_trie_key(k: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `450 + k * (69 ±0)` - // Estimated: `440 + k * (70 ±0)` - // Minimum execution time: 11_162_000 picoseconds. - Weight::from_parts(5_734_923, 440) - // Standard Error: 1_097 - .saturating_add(Weight::from_parts(976_647, 0).saturating_mul(k.into())) + // Measured: `481 + k * (69 ±0)` + // Estimated: `471 + k * (70 ±0)` + // Minimum execution time: 10_759_000 picoseconds. + Weight::from_parts(6_965_683, 471) + // Standard Error: 1_019 + .saturating_add(Weight::from_parts(961_947, 0).saturating_mul(k.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) @@ -206,12 +203,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `q` is `[0, 128]`. fn on_initialize_per_queue_item(q: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `250 + q * (33 ±0)` - // Estimated: `1725 + q * (33 ±0)` - // Minimum execution time: 2_626_000 picoseconds. - Weight::from_parts(10_626_314, 1725) - // Standard Error: 4_006 - .saturating_add(Weight::from_parts(1_298_864, 0).saturating_mul(q.into())) + // Measured: `281 + q * (33 ±0)` + // Estimated: `1753 + q * (33 ±0)` + // Minimum execution time: 2_633_000 picoseconds. + Weight::from_parts(10_668_837, 1753) + // Standard Error: 3_538 + .saturating_add(Weight::from_parts(1_277_168, 0).saturating_mul(q.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 33).saturating_mul(q.into())) @@ -223,12 +220,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `c` is `[0, 61717]`. fn reinstrument(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `238 + c * (1 ±0)` - // Estimated: `3951 + c * (2 ±0)` - // Minimum execution time: 31_434_000 picoseconds. - Weight::from_parts(29_558_961, 3951) - // Standard Error: 55 - .saturating_add(Weight::from_parts(50_774, 0).saturating_mul(c.into())) + // Measured: `270 + c * (1 ±0)` + // Estimated: `4015 + c * (2 ±0)` + // Minimum execution time: 30_264_000 picoseconds. + Weight::from_parts(27_106_554, 4015) + // Standard Error: 53 + .saturating_add(Weight::from_parts(49_705, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 2).saturating_mul(c.into())) @@ -246,12 +243,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `c` is `[0, 125952]`. fn call_with_code_per_byte(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `707` - // Estimated: `21400 + c * (5 ±0)` - // Minimum execution time: 309_015_000 picoseconds. - Weight::from_parts(318_740_885, 21400) - // Standard Error: 29 - .saturating_add(Weight::from_parts(30_993, 0).saturating_mul(c.into())) + // Measured: `803` + // Estimated: `21880 + c * (5 ±0)` + // Minimum execution time: 309_249_000 picoseconds. + Weight::from_parts(323_353_590, 21880) + // Standard Error: 25 + .saturating_add(Weight::from_parts(31_359, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 5).saturating_mul(c.into())) @@ -279,14 +276,14 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `270` // Estimated: `26207` - // Minimum execution time: 3_126_495_000 picoseconds. - Weight::from_parts(636_857_878, 26207) - // Standard Error: 294 - .saturating_add(Weight::from_parts(92_930, 0).saturating_mul(c.into())) - // Standard Error: 17 - .saturating_add(Weight::from_parts(1_128, 0).saturating_mul(i.into())) - // Standard Error: 17 - .saturating_add(Weight::from_parts(1_415, 0).saturating_mul(s.into())) + // Minimum execution time: 3_136_707_000 picoseconds. + Weight::from_parts(564_055_378, 26207) + // Standard Error: 286 + .saturating_add(Weight::from_parts(93_308, 0).saturating_mul(c.into())) + // Standard Error: 16 + .saturating_add(Weight::from_parts(1_165, 0).saturating_mul(i.into())) + // Standard Error: 16 + .saturating_add(Weight::from_parts(1_435, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(10_u64)) } @@ -308,14 +305,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[0, 1048576]`. fn instantiate(i: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `482` - // Estimated: `28521` - // Minimum execution time: 1_591_415_000 picoseconds. - Weight::from_parts(228_633_516, 28521) + // Measured: `546` + // Estimated: `28969` + // Minimum execution time: 1_631_314_000 picoseconds. + Weight::from_parts(236_693_159, 28969) // Standard Error: 8 - .saturating_add(Weight::from_parts(1_449, 0).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(1_434, 0).saturating_mul(i.into())) // Standard Error: 8 - .saturating_add(Weight::from_parts(1_444, 0).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_445, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } @@ -331,10 +328,10 @@ impl WeightInfo for SubstrateWeight { /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) fn call() -> Weight { // Proof Size summary in bytes: - // Measured: `759` - // Estimated: `21615` - // Minimum execution time: 167_905_000 picoseconds. - Weight::from_parts(169_247_000, 21615) + // Measured: `855` + // Estimated: `22095` + // Minimum execution time: 167_139_000 picoseconds. + Weight::from_parts(168_034_000, 22095) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -351,10 +348,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `109` // Estimated: `7366` - // Minimum execution time: 305_128_000 picoseconds. - Weight::from_parts(310_911_395, 7366) - // Standard Error: 70 - .saturating_add(Weight::from_parts(94_067, 0).saturating_mul(c.into())) + // Minimum execution time: 306_518_000 picoseconds. + Weight::from_parts(325_652_407, 7366) + // Standard Error: 134 + .saturating_add(Weight::from_parts(93_502, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -368,10 +365,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Contracts PristineCode (max_values: None, max_size: Some(125988), added: 128463, mode: Measured) fn remove_code() -> Weight { // Proof Size summary in bytes: - // Measured: `255` - // Estimated: `7950` - // Minimum execution time: 29_605_000 picoseconds. - Weight::from_parts(29_986_000, 7950) + // Measured: `287` + // Estimated: `8078` + // Minimum execution time: 29_084_000 picoseconds. + Weight::from_parts(29_350_000, 8078) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -383,10 +380,10 @@ impl WeightInfo for SubstrateWeight { /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) fn set_code() -> Weight { // Proof Size summary in bytes: - // Measured: `570` - // Estimated: `19530` - // Minimum execution time: 33_824_000 picoseconds. - Weight::from_parts(34_388_000, 19530) + // Measured: `666` + // Estimated: `19818` + // Minimum execution time: 32_996_000 picoseconds. + Weight::from_parts(33_365_000, 19818) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -400,18 +397,18 @@ impl WeightInfo for SubstrateWeight { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1600]`. fn seal_caller(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `781 + r * (480 ±0)` - // Estimated: `21765 + r * (2400 ±0)` - // Minimum execution time: 295_283_000 picoseconds. - Weight::from_parts(295_895_211, 21765) - // Standard Error: 44_860 - .saturating_add(Weight::from_parts(22_913_078, 0).saturating_mul(r.into())) + // Measured: `877 + r * (6 ±0)` + // Estimated: `22210 + r * (30 ±0)` + // Minimum execution time: 298_315_000 picoseconds. + Weight::from_parts(304_612_433, 22210) + // Standard Error: 904 + .saturating_add(Weight::from_parts(285_473, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 2400).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -423,19 +420,19 @@ impl WeightInfo for SubstrateWeight { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1600]`. fn seal_is_contract(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `821 + r * (19218 ±0)` - // Estimated: `21765 + r * (294095 ±0)` - // Minimum execution time: 295_760_000 picoseconds. - Weight::from_parts(151_512_811, 21765) - // Standard Error: 522_974 - .saturating_add(Weight::from_parts(263_028_353, 0).saturating_mul(r.into())) + // Measured: `935 + r * (272 ±0)` + // Estimated: `22315 + r * (3835 ±0)` + // Minimum execution time: 299_169_000 picoseconds. + Weight::from_parts(138_157_704, 22315) + // Standard Error: 6_115 + .saturating_add(Weight::from_parts(3_244_482, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) - .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(r.into()))) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 294095).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 3835).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -447,19 +444,19 @@ impl WeightInfo for SubstrateWeight { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1600]`. fn seal_code_hash(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `825 + r * (19539 ±0)` - // Estimated: `21810 + r * (295700 ±0)` - // Minimum execution time: 295_950_000 picoseconds. - Weight::from_parts(164_516_076, 21810) - // Standard Error: 469_540 - .saturating_add(Weight::from_parts(321_138_601, 0).saturating_mul(r.into())) + // Measured: `927 + r * (276 ±0)` + // Estimated: `22335 + r * (3855 ±0)` + // Minimum execution time: 299_262_000 picoseconds. + Weight::from_parts(157_105_627, 22335) + // Standard Error: 5_634 + .saturating_add(Weight::from_parts(3_995_666, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) - .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(r.into()))) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 295700).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 3855).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -471,18 +468,18 @@ impl WeightInfo for SubstrateWeight { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1600]`. fn seal_own_code_hash(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `788 + r * (480 ±0)` - // Estimated: `21800 + r * (2400 ±0)` - // Minimum execution time: 295_916_000 picoseconds. - Weight::from_parts(299_964_913, 21800) - // Standard Error: 78_211 - .saturating_add(Weight::from_parts(28_933_603, 0).saturating_mul(r.into())) + // Measured: `884 + r * (6 ±0)` + // Estimated: `22250 + r * (30 ±0)` + // Minimum execution time: 298_259_000 picoseconds. + Weight::from_parts(303_498_245, 22250) + // Standard Error: 874 + .saturating_add(Weight::from_parts(352_839, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 2400).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -494,18 +491,18 @@ impl WeightInfo for SubstrateWeight { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1600]`. fn seal_caller_is_origin(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `778 + r * (240 ±0)` - // Estimated: `21735 + r * (1200 ±0)` - // Minimum execution time: 293_588_000 picoseconds. - Weight::from_parts(297_568_984, 21735) - // Standard Error: 35_513 - .saturating_add(Weight::from_parts(11_074_880, 0).saturating_mul(r.into())) + // Measured: `874 + r * (3 ±0)` + // Estimated: `22215 + r * (15 ±0)` + // Minimum execution time: 295_689_000 picoseconds. + Weight::from_parts(314_004_541, 22215) + // Standard Error: 1_803 + .saturating_add(Weight::from_parts(131_102, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 1200).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 15).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -517,18 +514,18 @@ impl WeightInfo for SubstrateWeight { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1600]`. fn seal_address(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `782 + r * (480 ±0)` - // Estimated: `21730 + r * (2400 ±0)` - // Minimum execution time: 294_929_000 picoseconds. - Weight::from_parts(295_916_817, 21730) - // Standard Error: 64_902 - .saturating_add(Weight::from_parts(22_944_018, 0).saturating_mul(r.into())) + // Measured: `878 + r * (6 ±0)` + // Estimated: `22220 + r * (30 ±0)` + // Minimum execution time: 297_579_000 picoseconds. + Weight::from_parts(299_326_920, 22220) + // Standard Error: 990 + .saturating_add(Weight::from_parts(284_789, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 2400).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -540,18 +537,18 @@ impl WeightInfo for SubstrateWeight { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1600]`. fn seal_gas_left(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `783 + r * (480 ±0)` - // Estimated: `21720 + r * (2405 ±0)` - // Minimum execution time: 296_783_000 picoseconds. - Weight::from_parts(299_399_332, 21720) - // Standard Error: 50_982 - .saturating_add(Weight::from_parts(22_173_249, 0).saturating_mul(r.into())) + // Measured: `879 + r * (6 ±0)` + // Estimated: `22205 + r * (30 ±0)` + // Minimum execution time: 297_651_000 picoseconds. + Weight::from_parts(304_465_467, 22205) + // Standard Error: 736 + .saturating_add(Weight::from_parts(272_149, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 2405).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) } /// Storage: System Account (r:2 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -563,18 +560,18 @@ impl WeightInfo for SubstrateWeight { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1600]`. fn seal_balance(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `921 + r * (480 ±0)` - // Estimated: `24193 + r * (2451 ±0)` - // Minimum execution time: 294_120_000 picoseconds. - Weight::from_parts(305_889_989, 24193) - // Standard Error: 116_244 - .saturating_add(Weight::from_parts(114_781_094, 0).saturating_mul(r.into())) + // Measured: `1050 + r * (6 ±0)` + // Estimated: `25258 + r * (30 ±0)` + // Minimum execution time: 296_957_000 picoseconds. + Weight::from_parts(308_680_068, 25258) + // Standard Error: 1_377 + .saturating_add(Weight::from_parts(1_419_294, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 2451).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -586,18 +583,18 @@ impl WeightInfo for SubstrateWeight { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1600]`. fn seal_value_transferred(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `792 + r * (480 ±0)` - // Estimated: `21830 + r * (2400 ±0)` - // Minimum execution time: 295_569_000 picoseconds. - Weight::from_parts(299_774_774, 21830) - // Standard Error: 46_252 - .saturating_add(Weight::from_parts(21_753_842, 0).saturating_mul(r.into())) + // Measured: `888 + r * (6 ±0)` + // Estimated: `22305 + r * (30 ±0)` + // Minimum execution time: 297_735_000 picoseconds. + Weight::from_parts(301_533_807, 22305) + // Standard Error: 1_119 + .saturating_add(Weight::from_parts(277_289, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 2400).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -609,18 +606,18 @@ impl WeightInfo for SubstrateWeight { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1600]`. fn seal_minimum_balance(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `790 + r * (480 ±0)` - // Estimated: `21760 + r * (2400 ±0)` - // Minimum execution time: 295_400_000 picoseconds. - Weight::from_parts(300_637_266, 21760) - // Standard Error: 41_263 - .saturating_add(Weight::from_parts(21_565_466, 0).saturating_mul(r.into())) + // Measured: `886 + r * (6 ±0)` + // Estimated: `22295 + r * (30 ±0)` + // Minimum execution time: 299_599_000 picoseconds. + Weight::from_parts(303_664_496, 22295) + // Standard Error: 1_009 + .saturating_add(Weight::from_parts(280_353, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 2400).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -632,18 +629,18 @@ impl WeightInfo for SubstrateWeight { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1600]`. fn seal_block_number(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `787 + r * (480 ±0)` - // Estimated: `21785 + r * (2400 ±0)` - // Minimum execution time: 294_696_000 picoseconds. - Weight::from_parts(297_196_796, 21785) - // Standard Error: 61_173 - .saturating_add(Weight::from_parts(21_903_191, 0).saturating_mul(r.into())) + // Measured: `883 + r * (6 ±0)` + // Estimated: `22285 + r * (30 ±0)` + // Minimum execution time: 297_641_000 picoseconds. + Weight::from_parts(302_437_979, 22285) + // Standard Error: 669 + .saturating_add(Weight::from_parts(270_403, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 2400).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -655,18 +652,18 @@ impl WeightInfo for SubstrateWeight { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1600]`. fn seal_now(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `778 + r * (480 ±0)` - // Estimated: `21715 + r * (2400 ±0)` - // Minimum execution time: 297_714_000 picoseconds. - Weight::from_parts(306_030_237, 21715) - // Standard Error: 69_984 - .saturating_add(Weight::from_parts(21_744_413, 0).saturating_mul(r.into())) + // Measured: `874 + r * (6 ±0)` + // Estimated: `22215 + r * (30 ±0)` + // Minimum execution time: 297_217_000 picoseconds. + Weight::from_parts(299_538_157, 22215) + // Standard Error: 732 + .saturating_add(Weight::from_parts(280_800, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 2400).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -680,18 +677,18 @@ impl WeightInfo for SubstrateWeight { /// Proof: TransactionPayment NextFeeMultiplier (max_values: Some(1), max_size: Some(16), added: 511, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1600]`. fn seal_weight_to_fee(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `856 + r * (800 ±0)` - // Estimated: `24416 + r * (4805 ±0)` - // Minimum execution time: 295_180_000 picoseconds. - Weight::from_parts(308_851_025, 24416) - // Standard Error: 115_126 - .saturating_add(Weight::from_parts(98_678_404, 0).saturating_mul(r.into())) + // Measured: `952 + r * (10 ±0)` + // Estimated: `25022 + r * (60 ±0)` + // Minimum execution time: 297_286_000 picoseconds. + Weight::from_parts(311_436_352, 25022) + // Standard Error: 6_811 + .saturating_add(Weight::from_parts(1_291_941, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 4805).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 60).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -703,18 +700,18 @@ impl WeightInfo for SubstrateWeight { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1600]`. fn seal_gas(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `745 + r * (320 ±0)` - // Estimated: `21590 + r * (1600 ±0)` - // Minimum execution time: 151_587_000 picoseconds. - Weight::from_parts(155_713_096, 21590) - // Standard Error: 32_464 - .saturating_add(Weight::from_parts(8_332_778, 0).saturating_mul(r.into())) + // Measured: `841 + r * (4 ±0)` + // Estimated: `22035 + r * (20 ±0)` + // Minimum execution time: 154_772_000 picoseconds. + Weight::from_parts(159_224_457, 22035) + // Standard Error: 212 + .saturating_add(Weight::from_parts(102_264, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 1600).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 20).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -726,18 +723,18 @@ impl WeightInfo for SubstrateWeight { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1600]`. fn seal_input(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `780 + r * (480 ±0)` - // Estimated: `21715 + r * (2400 ±0)` - // Minimum execution time: 295_008_000 picoseconds. - Weight::from_parts(297_982_800, 21715) - // Standard Error: 37_480 - .saturating_add(Weight::from_parts(17_970_520, 0).saturating_mul(r.into())) + // Measured: `876 + r * (6 ±0)` + // Estimated: `22220 + r * (30 ±0)` + // Minimum execution time: 297_248_000 picoseconds. + Weight::from_parts(303_805_584, 22220) + // Standard Error: 858 + .saturating_add(Weight::from_parts(223_587, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 2400).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -749,15 +746,15 @@ impl WeightInfo for SubstrateWeight { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `n` is `[0, 1024]`. - fn seal_input_per_kb(n: u32, ) -> Weight { + /// The range of component `n` is `[0, 1048576]`. + fn seal_input_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1260` - // Estimated: `24120` - // Minimum execution time: 314_970_000 picoseconds. - Weight::from_parts(345_339_508, 24120) - // Standard Error: 4_112 - .saturating_add(Weight::from_parts(9_746_966, 0).saturating_mul(n.into())) + // Measured: `880` + // Estimated: `22220` + // Minimum execution time: 298_464_000 picoseconds. + Weight::from_parts(300_996_431, 22220) + // Standard Error: 1 + .saturating_add(Weight::from_parts(600, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -774,12 +771,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1]`. fn seal_return(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `768 + r * (45 ±0)` - // Estimated: `21660 + r * (225 ±0)` - // Minimum execution time: 293_072_000 picoseconds. - Weight::from_parts(295_694_824, 21660) - // Standard Error: 219_523 - .saturating_add(Weight::from_parts(783_975, 0).saturating_mul(r.into())) + // Measured: `864 + r * (45 ±0)` + // Estimated: `22140 + r * (225 ±0)` + // Minimum execution time: 294_347_000 picoseconds. + Weight::from_parts(296_793_034, 22140) + // Standard Error: 277_251 + .saturating_add(Weight::from_parts(1_711_665, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 225).saturating_mul(r.into())) @@ -794,15 +791,15 @@ impl WeightInfo for SubstrateWeight { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `n` is `[0, 1024]`. - fn seal_return_per_kb(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `778` - // Estimated: `21755` - // Minimum execution time: 295_959_000 picoseconds. - Weight::from_parts(299_004_761, 21755) - // Standard Error: 3_988 - .saturating_add(Weight::from_parts(194_268, 0).saturating_mul(n.into())) + /// The range of component `n` is `[0, 1048576]`. + fn seal_return_per_byte(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `874` + // Estimated: `22255` + // Minimum execution time: 297_257_000 picoseconds. + Weight::from_parts(300_088_288, 22255) + // Standard Error: 1 + .saturating_add(Weight::from_parts(181, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -823,17 +820,17 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1]`. fn seal_terminate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `810 + r * (356 ±0)` - // Estimated: `25511 + r * (15321 ±0)` - // Minimum execution time: 294_626_000 picoseconds. - Weight::from_parts(297_839_179, 25511) - // Standard Error: 707_428 - .saturating_add(Weight::from_parts(81_507_620, 0).saturating_mul(r.into())) + // Measured: `906 + r * (452 ±0)` + // Estimated: `26183 + r * (15994 ±0)` + // Minimum execution time: 296_510_000 picoseconds. + Weight::from_parts(299_169_757, 26183) + // Standard Error: 205_313 + .saturating_add(Weight::from_parts(78_059_642, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((6_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((7_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 15321).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 15994).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -847,18 +844,18 @@ impl WeightInfo for SubstrateWeight { /// Proof: RandomnessCollectiveFlip RandomMaterial (max_values: Some(1), max_size: Some(2594), added: 3089, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1600]`. fn seal_random(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `825 + r * (800 ±0)` - // Estimated: `24199 + r * (4805 ±0)` - // Minimum execution time: 295_431_000 picoseconds. - Weight::from_parts(310_428_531, 24199) - // Standard Error: 143_501 - .saturating_add(Weight::from_parts(136_529_376, 0).saturating_mul(r.into())) + // Measured: `921 + r * (10 ±0)` + // Estimated: `24859 + r * (60 ±0)` + // Minimum execution time: 299_299_000 picoseconds. + Weight::from_parts(314_487_015, 24859) + // Standard Error: 1_552 + .saturating_add(Weight::from_parts(1_753_960, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 4805).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 60).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -870,18 +867,18 @@ impl WeightInfo for SubstrateWeight { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1600]`. fn seal_deposit_event(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `778 + r * (800 ±0)` - // Estimated: `21720 + r * (4000 ±0)` - // Minimum execution time: 293_778_000 picoseconds. - Weight::from_parts(323_404_081, 21720) - // Standard Error: 243_095 - .saturating_add(Weight::from_parts(269_012_482, 0).saturating_mul(r.into())) + // Measured: `874 + r * (10 ±0)` + // Estimated: `22215 + r * (50 ±0)` + // Minimum execution time: 296_188_000 picoseconds. + Weight::from_parts(305_901_539, 22215) + // Standard Error: 2_782 + .saturating_add(Weight::from_parts(3_456_054, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 4000).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 50).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -891,26 +888,25 @@ impl WeightInfo for SubstrateWeight { /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) - /// Storage: System EventTopics (r:322 w:322) + /// Storage: System EventTopics (r:6 w:6) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// 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 { - // Proof Size summary in bytes: - // Measured: `1725 + t * (2608 ±0) + n * (7 ±0)` - // Estimated: `26340 + t * (211030 ±0) + n * (50 ±0)` - // Minimum execution time: 1_317_129_000 picoseconds. - Weight::from_parts(566_722_295, 26340) - // Standard Error: 619_390 - .saturating_add(Weight::from_parts(194_334_643, 0).saturating_mul(t.into())) - // Standard Error: 170_114 - .saturating_add(Weight::from_parts(67_458_751, 0).saturating_mul(n.into())) + /// The range of component `n` is `[0, 16384]`. + fn seal_deposit_event_per_topic_and_byte(t: u32, n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `893 + t * (32 ±0)` + // Estimated: `22320 + t * (2640 ±0)` + // Minimum execution time: 313_860_000 picoseconds. + Weight::from_parts(312_473_092, 22320) + // Standard Error: 250_852 + .saturating_add(Weight::from_parts(2_258_502, 0).saturating_mul(t.into())) + // Standard Error: 70 + .saturating_add(Weight::from_parts(312, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) - .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(t.into()))) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(t.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(T::DbWeight::get().writes((80_u64).saturating_mul(t.into()))) - .saturating_add(Weight::from_parts(0, 211030).saturating_mul(t.into())) - .saturating_add(Weight::from_parts(0, 50).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(t.into()))) + .saturating_add(Weight::from_parts(0, 2640).saturating_mul(t.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -922,18 +918,18 @@ impl WeightInfo for SubstrateWeight { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1600]`. fn seal_debug_message(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `777 + r * (560 ±0)` - // Estimated: `21710 + r * (2800 ±0)` - // Minimum execution time: 159_087_000 picoseconds. - Weight::from_parts(163_703_981, 21710) - // Standard Error: 26_067 - .saturating_add(Weight::from_parts(14_810_256, 0).saturating_mul(r.into())) + // Measured: `873 + r * (7 ±0)` + // Estimated: `22205 + r * (35 ±0)` + // Minimum execution time: 162_043_000 picoseconds. + Weight::from_parts(166_132_332, 22205) + // Standard Error: 716 + .saturating_add(Weight::from_parts(184_981, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 2800).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 35).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) @@ -945,200 +941,187 @@ impl WeightInfo for SubstrateWeight { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `i` is `[0, 1024]`. - fn seal_debug_message_per_kb(i: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `125728` - // Estimated: `269982` - // Minimum execution time: 413_391_000 picoseconds. - Weight::from_parts(414_927_640, 269982) - // Standard Error: 1_740 - .saturating_add(Weight::from_parts(763_359, 0).saturating_mul(i.into())) + /// The range of component `i` is `[0, 1048576]`. + fn seal_debug_message_per_byte(i: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `125824` + // Estimated: `270073` + // Minimum execution time: 414_433_000 picoseconds. + Weight::from_parts(417_483_627, 270073) + // Standard Error: 1 + .saturating_add(Weight::from_parts(748, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 10]`. + /// The range of component `r` is `[0, 800]`. fn seal_set_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `815 + r * (23420 ±0)` - // Estimated: `815 + r * (23418 ±0)` - // Minimum execution time: 296_108_000 picoseconds. - Weight::from_parts(208_214_040, 815) - // Standard Error: 860_573 - .saturating_add(Weight::from_parts(480_342_550, 0).saturating_mul(r.into())) + // Measured: `941 + r * (292 ±0)` + // Estimated: `939 + r * (293 ±0)` + // Minimum execution time: 299_500_000 picoseconds. + Weight::from_parts(194_466_413, 939) + // Standard Error: 9_986 + .saturating_add(Weight::from_parts(6_010_112, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) - .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(r.into()))) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(T::DbWeight::get().writes((80_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 23418).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_parts(0, 293).saturating_mul(r.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) - /// The range of component `n` is `[0, 8]`. - fn seal_set_storage_per_new_kb(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `12544 + n * (11945 ±0)` - // Estimated: `8401 + n * (12814 ±61)` - // Minimum execution time: 442_286_000 picoseconds. - Weight::from_parts(620_395_299, 8401) - // Standard Error: 1_661_554 - .saturating_add(Weight::from_parts(89_393_169, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(52_u64)) - .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(50_u64)) - .saturating_add(T::DbWeight::get().writes((7_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 12814).saturating_mul(n.into())) + /// The range of component `n` is `[0, 16384]`. + fn seal_set_storage_per_new_byte(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1432` + // Estimated: `1405` + // Minimum execution time: 314_171_000 picoseconds. + Weight::from_parts(335_595_397, 1405) + // Standard Error: 67 + .saturating_add(Weight::from_parts(90, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(8_u64)) + .saturating_add(T::DbWeight::get().writes(6_u64)) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) - /// The range of component `n` is `[0, 8]`. - fn seal_set_storage_per_old_kb(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `12532 + n * (175784 ±0)` - // Estimated: `8396 + n * (176649 ±61)` - // Minimum execution time: 440_882_000 picoseconds. - Weight::from_parts(587_317_981, 8396) - // Standard Error: 1_374_991 - .saturating_add(Weight::from_parts(66_271_084, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(51_u64)) - .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(49_u64)) - .saturating_add(T::DbWeight::get().writes((7_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 176649).saturating_mul(n.into())) + /// The range of component `n` is `[0, 16384]`. + fn seal_set_storage_per_old_byte(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1295 + n * (1 ±0)` + // Estimated: `1292 + n * (1 ±0)` + // Minimum execution time: 313_479_000 picoseconds. + Weight::from_parts(317_435_100, 1292) + // Standard Error: 41 + .saturating_add(Weight::from_parts(106, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(7_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 10]`. + /// The range of component `r` is `[0, 800]`. fn seal_clear_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `807 + r * (23099 ±0)` - // Estimated: `812 + r * (23099 ±0)` - // Minimum execution time: 296_023_000 picoseconds. - Weight::from_parts(221_471_559, 812) - // Standard Error: 814_503 - .saturating_add(Weight::from_parts(465_928_089, 0).saturating_mul(r.into())) + // Measured: `937 + r * (288 ±0)` + // Estimated: `941 + r * (289 ±0)` + // Minimum execution time: 297_831_000 picoseconds. + Weight::from_parts(196_983_778, 941) + // Standard Error: 9_899 + .saturating_add(Weight::from_parts(5_904_642, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) - .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(r.into()))) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(T::DbWeight::get().writes((80_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 23099).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_parts(0, 289).saturating_mul(r.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) - /// The range of component `n` is `[0, 8]`. - fn seal_clear_storage_per_kb(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `12256 + n * (175776 ±0)` - // Estimated: `8047 + n * (176655 ±62)` - // Minimum execution time: 412_212_000 picoseconds. - Weight::from_parts(569_213_147, 8047) - // Standard Error: 1_463_771 - .saturating_add(Weight::from_parts(67_932_081, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(51_u64)) - .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(48_u64)) - .saturating_add(T::DbWeight::get().writes((7_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 176655).saturating_mul(n.into())) + /// The range of component `n` is `[0, 16384]`. + fn seal_clear_storage_per_byte(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1291 + n * (1 ±0)` + // Estimated: `1288 + n * (1 ±0)` + // Minimum execution time: 320_156_000 picoseconds. + Weight::from_parts(327_504_368, 1288) + .saturating_add(T::DbWeight::get().reads(7_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 10]`. + /// The range of component `r` is `[0, 800]`. fn seal_get_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `800 + r * (23744 ±0)` - // Estimated: `813 + r * (23740 ±0)` - // Minimum execution time: 296_007_000 picoseconds. - Weight::from_parts(229_100_700, 813) - // Standard Error: 684_970 - .saturating_add(Weight::from_parts(394_982_991, 0).saturating_mul(r.into())) + // Measured: `931 + r * (296 ±0)` + // Estimated: `936 + r * (297 ±0)` + // Minimum execution time: 305_849_000 picoseconds. + Weight::from_parts(219_649_351, 936) + // Standard Error: 9_157 + .saturating_add(Weight::from_parts(4_846_108, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) - .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(r.into()))) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 23740).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 297).saturating_mul(r.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) - /// The range of component `n` is `[0, 8]`. - fn seal_get_storage_per_kb(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `12863 + n * (175784 ±0)` - // Estimated: `8538 + n * (176688 ±63)` - // Minimum execution time: 392_306_000 picoseconds. - Weight::from_parts(539_188_004, 8538) - // Standard Error: 1_371_839 - .saturating_add(Weight::from_parts(155_130_373, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(51_u64)) - .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(n.into()))) + /// The range of component `n` is `[0, 16384]`. + fn seal_get_storage_per_byte(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1307 + n * (1 ±0)` + // Estimated: `1304 + n * (1 ±0)` + // Minimum execution time: 312_106_000 picoseconds. + Weight::from_parts(315_905_779, 1304) + // Standard Error: 44 + .saturating_add(Weight::from_parts(674, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 176688).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 10]`. + /// The range of component `r` is `[0, 800]`. fn seal_contains_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `818 + r * (23098 ±0)` - // Estimated: `824 + r * (23098 ±0)` - // Minimum execution time: 296_038_000 picoseconds. - Weight::from_parts(229_462_798, 824) - // Standard Error: 655_463 - .saturating_add(Weight::from_parts(372_593_685, 0).saturating_mul(r.into())) + // Measured: `952 + r * (288 ±0)` + // Estimated: `953 + r * (289 ±0)` + // Minimum execution time: 299_372_000 picoseconds. + Weight::from_parts(211_293_493, 953) + // Standard Error: 8_509 + .saturating_add(Weight::from_parts(4_688_993, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) - .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(r.into()))) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 23098).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 289).saturating_mul(r.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) - /// The range of component `n` is `[0, 8]`. - fn seal_contains_storage_per_kb(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `12200 + n * (175798 ±0)` - // Estimated: `8028 + n * (176661 ±62)` - // Minimum execution time: 386_782_000 picoseconds. - Weight::from_parts(512_965_975, 8028) - // Standard Error: 1_168_132 - .saturating_add(Weight::from_parts(63_307_325, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(51_u64)) - .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(n.into()))) + /// The range of component `n` is `[0, 16384]`. + fn seal_contains_storage_per_byte(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1294 + n * (1 ±0)` + // Estimated: `1291 + n * (1 ±0)` + // Minimum execution time: 311_605_000 picoseconds. + Weight::from_parts(315_473_850, 1291) + // Standard Error: 37 + .saturating_add(Weight::from_parts(3, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 176661).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 10]`. + /// The range of component `r` is `[0, 800]`. fn seal_take_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `815 + r * (23740 ±0)` - // Estimated: `817 + r * (23739 ±0)` - // Minimum execution time: 296_352_000 picoseconds. - Weight::from_parts(212_661_296, 817) - // Standard Error: 879_297 - .saturating_add(Weight::from_parts(494_182_672, 0).saturating_mul(r.into())) + // Measured: `925 + r * (296 ±0)` + // Estimated: `932 + r * (297 ±0)` + // Minimum execution time: 298_231_000 picoseconds. + Weight::from_parts(200_178_698, 932) + // Standard Error: 10_452 + .saturating_add(Weight::from_parts(6_107_653, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) - .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(r.into()))) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(T::DbWeight::get().writes((80_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 23739).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_parts(0, 297).saturating_mul(r.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) - /// The range of component `n` is `[0, 8]`. - fn seal_take_storage_per_kb(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `12864 + n * (175784 ±0)` - // Estimated: `8539 + n * (176686 ±63)` - // Minimum execution time: 414_693_000 picoseconds. - Weight::from_parts(595_693_859, 8539) - // Standard Error: 1_673_819 - .saturating_add(Weight::from_parts(163_090_316, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(51_u64)) - .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(48_u64)) - .saturating_add(T::DbWeight::get().writes((7_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 176686).saturating_mul(n.into())) + /// The range of component `n` is `[0, 16384]`. + fn seal_take_storage_per_byte(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1308 + n * (1 ±0)` + // Estimated: `1305 + n * (1 ±0)` + // Minimum execution time: 314_970_000 picoseconds. + Weight::from_parts(318_135_821, 1305) + // Standard Error: 26 + .saturating_add(Weight::from_parts(630, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(7_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } /// Storage: System Account (r:1602 w:1601) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1150,20 +1133,20 @@ impl WeightInfo for SubstrateWeight { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1600]`. fn seal_transfer(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1329 + r * (3604 ±0)` - // Estimated: `25928 + r * (216096 ±4)` - // Minimum execution time: 299_205_000 picoseconds. - Weight::from_parts(221_142_217, 25928) - // Standard Error: 1_369_909 - .saturating_add(Weight::from_parts(1_665_917_241, 0).saturating_mul(r.into())) + // Measured: `1501 + r * (45 ±0)` + // Estimated: `27383 + r * (2700 ±0)` + // Minimum execution time: 299_629_000 picoseconds. + Weight::from_parts(150_915_187, 27383) + // Standard Error: 25_604 + .saturating_add(Weight::from_parts(20_859_844, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) - .saturating_add(T::DbWeight::get().reads((80_u64).saturating_mul(r.into()))) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(4_u64)) - .saturating_add(T::DbWeight::get().writes((80_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 216096).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_parts(0, 2700).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1175,20 +1158,20 @@ impl WeightInfo for SubstrateWeight { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:1602 w:1602) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1600]`. fn seal_call(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1479 + r * (20514 ±0)` - // Estimated: `26429 + r * (498656 ±1)` - // Minimum execution time: 297_501_000 picoseconds. - Weight::from_parts(298_400_000, 26429) - // Standard Error: 9_372_890 - .saturating_add(Weight::from_parts(22_507_984_433, 0).saturating_mul(r.into())) + // Measured: `1670 + r * (288 ±0)` + // Estimated: `27813 + r * (6391 ±0)` + // Minimum execution time: 299_578_000 picoseconds. + Weight::from_parts(300_036_000, 27813) + // Standard Error: 102_709 + .saturating_add(Weight::from_parts(283_767_316, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) - .saturating_add(T::DbWeight::get().reads((160_u64).saturating_mul(r.into()))) + .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(T::DbWeight::get().writes((160_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 498656).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_parts(0, 6391).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1200,48 +1183,48 @@ impl WeightInfo for SubstrateWeight { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:1537 w:1537) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1600]`. fn seal_delegate_call(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0 + r * (69030 ±0)` - // Estimated: `21755 + r * (647542 ±560)` - // Minimum execution time: 297_432_000 picoseconds. - Weight::from_parts(298_220_000, 21755) - // Standard Error: 9_420_834 - .saturating_add(Weight::from_parts(22_261_152_353, 0).saturating_mul(r.into())) + // Measured: `0 + r * (935 ±0)` + // Estimated: `22235 + r * (8322 ±10)` + // Minimum execution time: 298_943_000 picoseconds. + Weight::from_parts(299_619_000, 22235) + // Standard Error: 117_493 + .saturating_add(Weight::from_parts(280_555_517, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) - .saturating_add(T::DbWeight::get().reads((150_u64).saturating_mul(r.into()))) + .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(T::DbWeight::get().writes((75_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 647542).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_parts(0, 8322).saturating_mul(r.into())) } - /// Storage: System Account (r:82 w:81) + /// Storage: System Account (r:3 w:2) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) - /// Storage: Contracts ContractInfoOf (r:81 w:81) + /// Storage: Contracts ContractInfoOf (r:2 w:2) /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:2 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) - /// Storage: System EventTopics (r:82 w:82) + /// Storage: System EventTopics (r:3 w:3) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// 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 { - // Proof Size summary in bytes: - // Measured: `21581 + t * (14318 ±0)` - // Estimated: `524200 + t * (272065 ±0)` - // Minimum execution time: 11_799_802_000 picoseconds. - Weight::from_parts(10_575_328_547, 524200) - // Standard Error: 11_952_810 - .saturating_add(Weight::from_parts(1_603_077_083, 0).saturating_mul(t.into())) - // Standard Error: 17_922 - .saturating_add(Weight::from_parts(9_876_752, 0).saturating_mul(c.into())) - .saturating_add(T::DbWeight::get().reads(167_u64)) - .saturating_add(T::DbWeight::get().reads((81_u64).saturating_mul(t.into()))) - .saturating_add(T::DbWeight::get().writes(163_u64)) - .saturating_add(T::DbWeight::get().writes((81_u64).saturating_mul(t.into()))) - .saturating_add(Weight::from_parts(0, 272065).saturating_mul(t.into())) + /// The range of component `c` is `[0, 1048576]`. + fn seal_call_per_transfer_clone_byte(t: u32, c: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1314 + t * (268 ±0)` + // Estimated: `31815 + t * (6290 ±0)` + // Minimum execution time: 453_013_000 picoseconds. + Weight::from_parts(442_536_283, 31815) + // Standard Error: 1_339_541 + .saturating_add(Weight::from_parts(17_062_445, 0).saturating_mul(t.into())) + // Standard Error: 1 + .saturating_add(Weight::from_parts(604, 0).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(9_u64)) + .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(t.into()))) + .saturating_add(T::DbWeight::get().writes(5_u64)) + .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(t.into()))) + .saturating_add(Weight::from_parts(0, 6290).saturating_mul(t.into())) } /// Storage: System Account (r:3202 w:3202) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1257,24 +1240,24 @@ impl WeightInfo for SubstrateWeight { /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Measured) /// Storage: System EventTopics (r:1602 w:1602) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1600]`. fn seal_instantiate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1646 + r * (20288 ±0)` - // Estimated: `32625 + r * (1330150 ±2)` - // Minimum execution time: 298_155_000 picoseconds. - Weight::from_parts(299_212_000, 32625) - // Standard Error: 32_410_313 - .saturating_add(Weight::from_parts(30_417_025_178, 0).saturating_mul(r.into())) + // Measured: `1988 + r * (319 ±0)` + // Estimated: `34745 + r * (17090 ±0)` + // Minimum execution time: 300_123_000 picoseconds. + Weight::from_parts(300_406_000, 34745) + // Standard Error: 420_997 + .saturating_add(Weight::from_parts(382_704_025, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) - .saturating_add(T::DbWeight::get().reads((480_u64).saturating_mul(r.into()))) - .saturating_add(T::DbWeight::get().writes(5_u64)) - .saturating_add(T::DbWeight::get().writes((400_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 1330150).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads((6_u64).saturating_mul(r.into()))) + .saturating_add(T::DbWeight::get().writes(6_u64)) + .saturating_add(T::DbWeight::get().writes((5_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_parts(0, 17090).saturating_mul(r.into())) } - /// Storage: System Account (r:162 w:162) + /// Storage: System Account (r:4 w:4) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) - /// Storage: Contracts ContractInfoOf (r:81 w:81) + /// Storage: Contracts ContractInfoOf (r:2 w:2) /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:2 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) @@ -1284,28 +1267,28 @@ impl WeightInfo for SubstrateWeight { /// Proof: Contracts Nonce (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: Contracts OwnerInfoOf (r:1 w:1) /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Measured) - /// Storage: System EventTopics (r:82 w:82) + /// Storage: System EventTopics (r:3 w:3) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `t` is `[0, 1]`. - /// The range of component `i` is `[0, 960]`. - /// The range of component `s` is `[0, 960]`. - fn seal_instantiate_per_transfer_input_salt_kb(t: u32, i: u32, s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `5625 + t * (1 ±0)` - // Estimated: `856795 + t * (2471 ±3)` - // Minimum execution time: 105_914_928_000 picoseconds. - Weight::from_parts(13_229_760_432, 856795) - // Standard Error: 96_394_437 - .saturating_add(Weight::from_parts(398_413_888, 0).saturating_mul(t.into())) - // Standard Error: 157_192 - .saturating_add(Weight::from_parts(97_104_978, 0).saturating_mul(i.into())) - // Standard Error: 157_192 - .saturating_add(Weight::from_parts(97_146_130, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(329_u64)) + /// The range of component `i` is `[0, 983040]`. + /// The range of component `s` is `[0, 983040]`. + fn seal_instantiate_per_transfer_input_salt_byte(t: u32, i: u32, s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1231 + t * (219 ±0)` + // Estimated: `43797 + t * (3812 ±2)` + // Minimum execution time: 1_636_322_000 picoseconds. + Weight::from_parts(360_859_331, 43797) + // Standard Error: 4_816_923 + .saturating_add(Weight::from_parts(109_179_023, 0).saturating_mul(t.into())) + // Standard Error: 7 + .saturating_add(Weight::from_parts(1_180, 0).saturating_mul(i.into())) + // Standard Error: 7 + .saturating_add(Weight::from_parts(1_344, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(13_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(t.into()))) - .saturating_add(T::DbWeight::get().writes(326_u64)) + .saturating_add(T::DbWeight::get().writes(10_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(t.into()))) - .saturating_add(Weight::from_parts(0, 2471).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(0, 3812).saturating_mul(t.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1317,18 +1300,18 @@ impl WeightInfo for SubstrateWeight { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 1]`. + /// The range of component `r` is `[0, 1600]`. fn seal_hash_sha2_256(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `775 + r * (642 ±0)` - // Estimated: `21695 + r * (3210 ±0)` - // Minimum execution time: 294_309_000 picoseconds. - Weight::from_parts(296_241_318, 21695) - // Standard Error: 127_872 - .saturating_add(Weight::from_parts(45_806_281, 0).saturating_mul(r.into())) + // Measured: `873 + r * (8 ±0)` + // Estimated: `22190 + r * (40 ±0)` + // Minimum execution time: 297_521_000 picoseconds. + Weight::from_parts(303_523_260, 22190) + // Standard Error: 1_162 + .saturating_add(Weight::from_parts(542_201, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 3210).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1340,15 +1323,15 @@ impl WeightInfo for SubstrateWeight { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `n` is `[0, 1024]`. - fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `1577` - // Estimated: `25630` - // Minimum execution time: 341_248_000 picoseconds. - Weight::from_parts(341_607_000, 25630) - // Standard Error: 66_687 - .saturating_add(Weight::from_parts(322_250_398, 0).saturating_mul(n.into())) + /// The range of component `n` is `[0, 1048576]`. + fn seal_hash_sha2_256_per_byte(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `881` + // Estimated: `22225` + // Minimum execution time: 299_877_000 picoseconds. + Weight::from_parts(293_538_014, 22225) + // Standard Error: 2 + .saturating_add(Weight::from_parts(3_967, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1362,18 +1345,18 @@ impl WeightInfo for SubstrateWeight { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 1]`. + /// The range of component `r` is `[0, 1600]`. fn seal_hash_keccak_256(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `777 + r * (642 ±0)` - // Estimated: `21705 + r * (3210 ±0)` - // Minimum execution time: 293_810_000 picoseconds. - Weight::from_parts(296_719_171, 21705) - // Standard Error: 450_807 - .saturating_add(Weight::from_parts(61_627_228, 0).saturating_mul(r.into())) + // Measured: `875 + r * (8 ±0)` + // Estimated: `22205 + r * (40 ±0)` + // Minimum execution time: 297_672_000 picoseconds. + Weight::from_parts(299_933_312, 22205) + // Standard Error: 1_138 + .saturating_add(Weight::from_parts(713_189, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 3210).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1385,15 +1368,15 @@ impl WeightInfo for SubstrateWeight { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `n` is `[0, 1024]`. - fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `1579` - // Estimated: `25675` - // Minimum execution time: 354_550_000 picoseconds. - Weight::from_parts(355_136_000, 25675) - // Standard Error: 61_761 - .saturating_add(Weight::from_parts(257_021_566, 0).saturating_mul(n.into())) + /// The range of component `n` is `[0, 1048576]`. + fn seal_hash_keccak_256_per_byte(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `883` + // Estimated: `22245` + // Minimum execution time: 299_048_000 picoseconds. + Weight::from_parts(293_055_982, 22245) + // Standard Error: 2 + .saturating_add(Weight::from_parts(3_179, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1407,18 +1390,18 @@ impl WeightInfo for SubstrateWeight { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 1]`. + /// The range of component `r` is `[0, 1600]`. fn seal_hash_blake2_256(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `777 + r * (642 ±0)` - // Estimated: `21705 + r * (3210 ±0)` - // Minimum execution time: 293_369_000 picoseconds. - Weight::from_parts(295_990_893, 21705) - // Standard Error: 431_269 - .saturating_add(Weight::from_parts(32_213_406, 0).saturating_mul(r.into())) + // Measured: `875 + r * (8 ±0)` + // Estimated: `22220 + r * (40 ±0)` + // Minimum execution time: 301_991_000 picoseconds. + Weight::from_parts(300_027_441, 22220) + // Standard Error: 981 + .saturating_add(Weight::from_parts(391_319, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 3210).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1430,15 +1413,15 @@ impl WeightInfo for SubstrateWeight { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `n` is `[0, 1024]`. - fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `1579` - // Estimated: `25650` - // Minimum execution time: 326_595_000 picoseconds. - Weight::from_parts(327_188_000, 25650) - // Standard Error: 53_385 - .saturating_add(Weight::from_parts(74_046_074, 0).saturating_mul(n.into())) + /// The range of component `n` is `[0, 1048576]`. + fn seal_hash_blake2_256_per_byte(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `883` + // Estimated: `22265` + // Minimum execution time: 296_522_000 picoseconds. + Weight::from_parts(296_121_638, 22265) + // Standard Error: 2 + .saturating_add(Weight::from_parts(916, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1452,18 +1435,18 @@ impl WeightInfo for SubstrateWeight { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 1]`. + /// The range of component `r` is `[0, 1600]`. fn seal_hash_blake2_128(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `777 + r * (679 ±0)` - // Estimated: `21705 + r * (3395 ±0)` - // Minimum execution time: 292_388_000 picoseconds. - Weight::from_parts(295_090_179, 21705) - // Standard Error: 170_487 - .saturating_add(Weight::from_parts(32_577_820, 0).saturating_mul(r.into())) + // Measured: `875 + r * (8 ±0)` + // Estimated: `22225 + r * (40 ±0)` + // Minimum execution time: 296_228_000 picoseconds. + Weight::from_parts(301_472_299, 22225) + // Standard Error: 875 + .saturating_add(Weight::from_parts(381_027, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 3395).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1475,15 +1458,15 @@ impl WeightInfo for SubstrateWeight { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `n` is `[0, 1024]`. - fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `1579` - // Estimated: `25695` - // Minimum execution time: 326_862_000 picoseconds. - Weight::from_parts(327_449_000, 25695) - // Standard Error: 54_539 - .saturating_add(Weight::from_parts(74_042_337, 0).saturating_mul(n.into())) + /// The range of component `n` is `[0, 1048576]`. + fn seal_hash_blake2_128_per_byte(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `883` + // Estimated: `22235` + // Minimum execution time: 296_644_000 picoseconds. + Weight::from_parts(289_879_744, 22235) + // Standard Error: 2 + .saturating_add(Weight::from_parts(925, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1497,18 +1480,18 @@ impl WeightInfo for SubstrateWeight { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 1]`. + /// The range of component `r` is `[0, 1600]`. fn seal_ecdsa_recover(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `821 + r * (6083 ±0)` - // Estimated: `21925 + r * (30415 ±0)` - // Minimum execution time: 295_597_000 picoseconds. - Weight::from_parts(298_267_200, 21925) - // Standard Error: 699_824 - .saturating_add(Weight::from_parts(3_021_734_700, 0).saturating_mul(r.into())) + // Measured: `800 + r * (78 ±0)` + // Estimated: `21845 + r * (390 ±0)` + // Minimum execution time: 297_804_000 picoseconds. + Weight::from_parts(471_994_534, 21845) + // Standard Error: 9_479 + .saturating_add(Weight::from_parts(36_886_028, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 30415).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 390).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1520,18 +1503,18 @@ impl WeightInfo for SubstrateWeight { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 1]`. + /// The range of component `r` is `[0, 1600]`. fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `790 + r * (3362 ±0)` - // Estimated: `21770 + r * (16810 ±0)` - // Minimum execution time: 295_539_000 picoseconds. - Weight::from_parts(297_844_822, 21770) - // Standard Error: 490_532 - .saturating_add(Weight::from_parts(747_592_977, 0).saturating_mul(r.into())) + // Measured: `645 + r * (44 ±0)` + // Estimated: `21110 + r * (220 ±0)` + // Minimum execution time: 298_623_000 picoseconds. + Weight::from_parts(322_192_102, 21110) + // Standard Error: 3_207 + .saturating_add(Weight::from_parts(9_243_653, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 16810).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 220).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1545,20 +1528,20 @@ impl WeightInfo for SubstrateWeight { /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Measured) /// Storage: System EventTopics (r:1538 w:1538) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1600]`. fn seal_set_code_hash(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0 + r * (74020 ±0)` - // Estimated: `69192 + r * (913289 ±821)` - // Minimum execution time: 295_164_000 picoseconds. - Weight::from_parts(296_597_000, 69192) - // Standard Error: 3_646_577 - .saturating_add(Weight::from_parts(1_725_796_807, 0).saturating_mul(r.into())) + // Measured: `0 + r * (1030 ±0)` + // Estimated: `30592 + r * (11919 ±7)` + // Minimum execution time: 298_574_000 picoseconds. + Weight::from_parts(299_383_000, 30592) + // Standard Error: 44_061 + .saturating_add(Weight::from_parts(21_625_366, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) - .saturating_add(T::DbWeight::get().reads((225_u64).saturating_mul(r.into()))) + .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(T::DbWeight::get().writes((150_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 913289).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_parts(0, 11919).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1570,18 +1553,18 @@ impl WeightInfo for SubstrateWeight { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1600]`. fn seal_reentrance_count(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `773 + r * (240 ±0)` - // Estimated: `21685 + r * (1200 ±0)` - // Minimum execution time: 296_287_000 picoseconds. - Weight::from_parts(300_696_694, 21685) - // Standard Error: 27_891 - .saturating_add(Weight::from_parts(10_943_994, 0).saturating_mul(r.into())) + // Measured: `869 + r * (3 ±0)` + // Estimated: `22215 + r * (15 ±0)` + // Minimum execution time: 297_014_000 picoseconds. + Weight::from_parts(301_226_615, 22215) + // Standard Error: 439 + .saturating_add(Weight::from_parts(143_017, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 1200).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 15).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1593,18 +1576,18 @@ impl WeightInfo for SubstrateWeight { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1600]`. fn seal_account_reentrance_count(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2006 + r * (3154 ±0)` - // Estimated: `26435 + r * (15875 ±2)` - // Minimum execution time: 298_000_000 picoseconds. - Weight::from_parts(328_282_119, 26435) - // Standard Error: 104_874 - .saturating_add(Weight::from_parts(18_428_267, 0).saturating_mul(r.into())) + // Measured: `2072 + r * (39 ±0)` + // Estimated: `27645 + r * (200 ±0)` + // Minimum execution time: 299_074_000 picoseconds. + Weight::from_parts(336_979_016, 27645) + // Standard Error: 1_163 + .saturating_add(Weight::from_parts(227_998, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 15875).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 200).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1618,538 +1601,526 @@ impl WeightInfo for SubstrateWeight { /// Proof: Contracts Nonce (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1600]`. fn seal_instantiation_nonce(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `776 + r * (240 ±0)` - // Estimated: `23962 + r * (1440 ±0)` - // Minimum execution time: 295_104_000 picoseconds. - Weight::from_parts(299_334_585, 23962) - // Standard Error: 25_840 - .saturating_add(Weight::from_parts(9_744_866, 0).saturating_mul(r.into())) + // Measured: `872 + r * (3 ±0)` + // Estimated: `24580 + r * (18 ±0)` + // Minimum execution time: 296_959_000 picoseconds. + Weight::from_parts(303_796_839, 24580) + // Standard Error: 534 + .saturating_add(Weight::from_parts(118_978, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) - .saturating_add(Weight::from_parts(0, 1440).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 18).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64const(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_132_000 picoseconds. - Weight::from_parts(1_100_159, 0) - // Standard Error: 10_131 - .saturating_add(Weight::from_parts(436_462, 0).saturating_mul(r.into())) + // Minimum execution time: 1_020_000 picoseconds. + Weight::from_parts(1_355_107, 0) + // Standard Error: 1 + .saturating_add(Weight::from_parts(4_110, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64load(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_368_000 picoseconds. - Weight::from_parts(1_974_308, 0) - // Standard Error: 811 - .saturating_add(Weight::from_parts(1_079_620, 0).saturating_mul(r.into())) + // Minimum execution time: 1_224_000 picoseconds. + Weight::from_parts(1_819_284, 0) + // Standard Error: 10 + .saturating_add(Weight::from_parts(10_803, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64store(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_354_000 picoseconds. - Weight::from_parts(2_057_834, 0) - // Standard Error: 4_277 - .saturating_add(Weight::from_parts(1_008_797, 0).saturating_mul(r.into())) + // Minimum execution time: 1_216_000 picoseconds. + Weight::from_parts(1_795_011, 0) + // Standard Error: 5 + .saturating_add(Weight::from_parts(10_000, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_select(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_218_000 picoseconds. - Weight::from_parts(1_594_528, 0) - // Standard Error: 723 - .saturating_add(Weight::from_parts(1_147_486, 0).saturating_mul(r.into())) + // Minimum execution time: 1_127_000 picoseconds. + Weight::from_parts(1_491_730, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(11_471, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_if(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_156_000 picoseconds. - Weight::from_parts(1_460_611, 0) - // Standard Error: 419 - .saturating_add(Weight::from_parts(1_314_741, 0).saturating_mul(r.into())) + // Minimum execution time: 1_044_000 picoseconds. + Weight::from_parts(2_330_852, 0) + // Standard Error: 69 + .saturating_add(Weight::from_parts(12_866, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_br(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_166_000 picoseconds. - Weight::from_parts(1_454_460, 0) - // Standard Error: 493 - .saturating_add(Weight::from_parts(642_481, 0).saturating_mul(r.into())) + // Minimum execution time: 1_067_000 picoseconds. + Weight::from_parts(1_399_626, 0) + // Standard Error: 5 + .saturating_add(Weight::from_parts(6_430, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_br_if(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_144_000 picoseconds. - Weight::from_parts(1_410_515, 0) - // Standard Error: 894 - .saturating_add(Weight::from_parts(958_765, 0).saturating_mul(r.into())) + // Minimum execution time: 1_087_000 picoseconds. + Weight::from_parts(1_463_592, 0) + // Standard Error: 12 + .saturating_add(Weight::from_parts(9_707, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_br_table(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_190_000 picoseconds. - Weight::from_parts(1_143_236, 0) - // Standard Error: 2_773 - .saturating_add(Weight::from_parts(1_164_764, 0).saturating_mul(r.into())) + // Minimum execution time: 1_110_000 picoseconds. + Weight::from_parts(1_058_258, 0) + // Standard Error: 22 + .saturating_add(Weight::from_parts(11_713, 0).saturating_mul(r.into())) } /// The range of component `e` is `[1, 256]`. - fn instr_br_table_per_entry(e: u32, ) -> Weight { + fn instr_br_table_per_entry(_e: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_993_000 picoseconds. - Weight::from_parts(3_270_525, 0) - // Standard Error: 65 - .saturating_add(Weight::from_parts(4_418, 0).saturating_mul(e.into())) + // Minimum execution time: 1_189_000 picoseconds. + Weight::from_parts(1_416_188, 0) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_call(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_163_000 picoseconds. - Weight::from_parts(1_999_458, 0) - // Standard Error: 1_418 - .saturating_add(Weight::from_parts(2_371_979, 0).saturating_mul(r.into())) + // Minimum execution time: 2_201_000 picoseconds. + Weight::from_parts(3_375_851, 0) + // Standard Error: 96 + .saturating_add(Weight::from_parts(22_970, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_call_indirect(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_288_000 picoseconds. - Weight::from_parts(2_340_227, 0) - // Standard Error: 3_234 - .saturating_add(Weight::from_parts(3_038_523, 0).saturating_mul(r.into())) - } - /// The range of component `p` is `[0, 128]`. - fn instr_call_indirect_per_param(p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 5_270_000 picoseconds. - Weight::from_parts(6_360_011, 0) - // Standard Error: 2_585 - .saturating_add(Weight::from_parts(226_149, 0).saturating_mul(p.into())) + // Minimum execution time: 1_286_000 picoseconds. + Weight::from_parts(2_817_725, 0) + // Standard Error: 55 + .saturating_add(Weight::from_parts(29_437, 0).saturating_mul(r.into())) } /// The range of component `l` is `[0, 1024]`. fn instr_call_per_local(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_580_000 picoseconds. - Weight::from_parts(5_183_658, 0) - // Standard Error: 80 - .saturating_add(Weight::from_parts(46_038, 0).saturating_mul(l.into())) + // Minimum execution time: 1_319_000 picoseconds. + Weight::from_parts(1_636_286, 0) + // Standard Error: 31 + .saturating_add(Weight::from_parts(1_240, 0).saturating_mul(l.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_local_get(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_559_000 picoseconds. - Weight::from_parts(2_846_350, 0) - // Standard Error: 2_809 - .saturating_add(Weight::from_parts(462_084, 0).saturating_mul(r.into())) + // Minimum execution time: 2_507_000 picoseconds. + Weight::from_parts(2_785_119, 0) + // Standard Error: 1 + .saturating_add(Weight::from_parts(4_601, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_local_set(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_530_000 picoseconds. - Weight::from_parts(2_835_072, 0) - // Standard Error: 479 - .saturating_add(Weight::from_parts(483_451, 0).saturating_mul(r.into())) + // Minimum execution time: 2_494_000 picoseconds. + Weight::from_parts(2_948_015, 0) + // Standard Error: 14 + .saturating_add(Weight::from_parts(4_788, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_local_tee(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_510_000 picoseconds. - Weight::from_parts(2_740_081, 0) - // Standard Error: 901 - .saturating_add(Weight::from_parts(664_354, 0).saturating_mul(r.into())) + // Minimum execution time: 2_443_000 picoseconds. + Weight::from_parts(3_065_273, 0) + // Standard Error: 15 + .saturating_add(Weight::from_parts(6_489, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_global_get(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_295_000 picoseconds. - Weight::from_parts(1_798_174, 0) - // Standard Error: 464 - .saturating_add(Weight::from_parts(896_289, 0).saturating_mul(r.into())) + // Minimum execution time: 1_214_000 picoseconds. + Weight::from_parts(1_634_049, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(8_960, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_global_set(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_287_000 picoseconds. - Weight::from_parts(1_636_548, 0) - // Standard Error: 658 - .saturating_add(Weight::from_parts(923_295, 0).saturating_mul(r.into())) + // Minimum execution time: 1_180_000 picoseconds. + Weight::from_parts(1_555_599, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(9_205, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_memory_current(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_353_000 picoseconds. - Weight::from_parts(1_672_309, 0) - // Standard Error: 403 - .saturating_add(Weight::from_parts(818_273, 0).saturating_mul(r.into())) + // Minimum execution time: 1_223_000 picoseconds. + Weight::from_parts(1_626_002, 0) + // Standard Error: 5 + .saturating_add(Weight::from_parts(8_181, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 1]`. + /// The range of component `r` is `[0, 16]`. fn instr_memory_grow(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_180_000 picoseconds. - Weight::from_parts(1_304_714, 0) - // Standard Error: 88_180 - .saturating_add(Weight::from_parts(183_952_985, 0).saturating_mul(r.into())) + // Minimum execution time: 1_148_000 picoseconds. + Weight::from_parts(307_155, 0) + // Standard Error: 138_541 + .saturating_add(Weight::from_parts(13_291_570, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64clz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_158_000 picoseconds. - Weight::from_parts(1_800_065, 0) - // Standard Error: 2_104 - .saturating_add(Weight::from_parts(625_410, 0).saturating_mul(r.into())) + // Minimum execution time: 1_079_000 picoseconds. + Weight::from_parts(1_372_409, 0) + // Standard Error: 50 + .saturating_add(Weight::from_parts(6_427, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64ctz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_208_000 picoseconds. - Weight::from_parts(1_483_908, 0) - // Standard Error: 319 - .saturating_add(Weight::from_parts(635_095, 0).saturating_mul(r.into())) + // Minimum execution time: 1_116_000 picoseconds. + Weight::from_parts(1_415_180, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(6_353, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64popcnt(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_164_000 picoseconds. - Weight::from_parts(1_506_871, 0) - // Standard Error: 264 - .saturating_add(Weight::from_parts(633_660, 0).saturating_mul(r.into())) + // Minimum execution time: 1_058_000 picoseconds. + Weight::from_parts(1_314_206, 0) + // Standard Error: 35 + .saturating_add(Weight::from_parts(6_431, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64eqz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_141_000 picoseconds. - Weight::from_parts(1_467_219, 0) - // Standard Error: 191 - .saturating_add(Weight::from_parts(651_156, 0).saturating_mul(r.into())) + // Minimum execution time: 1_059_000 picoseconds. + Weight::from_parts(1_455_331, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(6_507, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64extendsi32(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_170_000 picoseconds. - Weight::from_parts(1_474_718, 0) - // Standard Error: 224 - .saturating_add(Weight::from_parts(617_317, 0).saturating_mul(r.into())) + // Minimum execution time: 1_057_000 picoseconds. + Weight::from_parts(1_421_085, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(6_177, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64extendui32(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_195_000 picoseconds. - Weight::from_parts(1_501_421, 0) - // Standard Error: 221 - .saturating_add(Weight::from_parts(616_559, 0).saturating_mul(r.into())) + // Minimum execution time: 1_079_000 picoseconds. + Weight::from_parts(1_429_275, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(6_175, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i32wrapi64(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_172_000 picoseconds. - Weight::from_parts(1_482_402, 0) - // Standard Error: 2_163 - .saturating_add(Weight::from_parts(619_230, 0).saturating_mul(r.into())) + // Minimum execution time: 1_065_000 picoseconds. + Weight::from_parts(1_403_813, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(6_192, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64eq(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_149_000 picoseconds. - Weight::from_parts(2_021_801, 0) - // Standard Error: 20_804 - .saturating_add(Weight::from_parts(913_888, 0).saturating_mul(r.into())) + // Minimum execution time: 1_061_000 picoseconds. + Weight::from_parts(1_421_984, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(9_094, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64ne(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_187_000 picoseconds. - Weight::from_parts(1_358_437, 0) - // Standard Error: 1_946 - .saturating_add(Weight::from_parts(916_378, 0).saturating_mul(r.into())) + // Minimum execution time: 1_075_000 picoseconds. + Weight::from_parts(1_431_453, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(9_084, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64lts(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_175_000 picoseconds. - Weight::from_parts(1_527_336, 0) - // Standard Error: 243 - .saturating_add(Weight::from_parts(907_580, 0).saturating_mul(r.into())) + // Minimum execution time: 1_100_000 picoseconds. + Weight::from_parts(1_452_384, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(9_081, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64ltu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_220_000 picoseconds. - Weight::from_parts(1_530_715, 0) - // Standard Error: 224 - .saturating_add(Weight::from_parts(906_096, 0).saturating_mul(r.into())) + // Minimum execution time: 1_090_000 picoseconds. + Weight::from_parts(1_466_416, 0) + // Standard Error: 17 + .saturating_add(Weight::from_parts(9_091, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64gts(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_107_000 picoseconds. - Weight::from_parts(1_496_553, 0) - // Standard Error: 299 - .saturating_add(Weight::from_parts(907_963, 0).saturating_mul(r.into())) + // Minimum execution time: 1_056_000 picoseconds. + Weight::from_parts(1_676_091, 0) + // Standard Error: 47 + .saturating_add(Weight::from_parts(9_082, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64gtu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_153_000 picoseconds. - Weight::from_parts(1_482_710, 0) - // Standard Error: 182 - .saturating_add(Weight::from_parts(918_439, 0).saturating_mul(r.into())) + // Minimum execution time: 1_053_000 picoseconds. + Weight::from_parts(1_232_790, 0) + // Standard Error: 43 + .saturating_add(Weight::from_parts(9_329, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64les(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_142_000 picoseconds. - Weight::from_parts(1_522_114, 0) - // Standard Error: 297 - .saturating_add(Weight::from_parts(906_633, 0).saturating_mul(r.into())) + // Minimum execution time: 1_091_000 picoseconds. + Weight::from_parts(1_476_212, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(9_074, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64leu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_119_000 picoseconds. - Weight::from_parts(2_199_831, 0) - // Standard Error: 4_234 - .saturating_add(Weight::from_parts(898_161, 0).saturating_mul(r.into())) + // Minimum execution time: 1_083_000 picoseconds. + Weight::from_parts(1_484_966, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(9_184, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64ges(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_163_000 picoseconds. - Weight::from_parts(1_489_404, 0) - // Standard Error: 416 - .saturating_add(Weight::from_parts(908_450, 0).saturating_mul(r.into())) + // Minimum execution time: 1_089_000 picoseconds. + Weight::from_parts(1_516_766, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(9_063, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64geu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_204_000 picoseconds. - Weight::from_parts(2_266_296, 0) - // Standard Error: 13_013 - .saturating_add(Weight::from_parts(899_225, 0).saturating_mul(r.into())) + // Minimum execution time: 996_000 picoseconds. + Weight::from_parts(1_460_638, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(9_076, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64add(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_160_000 picoseconds. - Weight::from_parts(1_470_799, 0) - // Standard Error: 422 - .saturating_add(Weight::from_parts(897_325, 0).saturating_mul(r.into())) + // Minimum execution time: 1_095_000 picoseconds. + Weight::from_parts(1_448_412, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(8_977, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64sub(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_125_000 picoseconds. - Weight::from_parts(1_521_508, 0) - // Standard Error: 594 - .saturating_add(Weight::from_parts(886_145, 0).saturating_mul(r.into())) + // Minimum execution time: 1_071_000 picoseconds. + Weight::from_parts(1_459_165, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(8_852, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64mul(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_139_000 picoseconds. - Weight::from_parts(1_490_535, 0) - // Standard Error: 211 - .saturating_add(Weight::from_parts(884_929, 0).saturating_mul(r.into())) + // Minimum execution time: 1_082_000 picoseconds. + Weight::from_parts(1_450_718, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(8_860, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64divs(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_180_000 picoseconds. - Weight::from_parts(2_221_481, 0) - // Standard Error: 9_884 - .saturating_add(Weight::from_parts(1_507_511, 0).saturating_mul(r.into())) + // Minimum execution time: 1_065_000 picoseconds. + Weight::from_parts(1_436_871, 0) + // Standard Error: 9 + .saturating_add(Weight::from_parts(15_241, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64divu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_131_000 picoseconds. - Weight::from_parts(1_498_652, 0) - // Standard Error: 531 - .saturating_add(Weight::from_parts(1_451_498, 0).saturating_mul(r.into())) + // Minimum execution time: 1_065_000 picoseconds. + Weight::from_parts(1_423_806, 0) + // Standard Error: 17 + .saturating_add(Weight::from_parts(14_706, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64rems(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_145_000 picoseconds. - Weight::from_parts(1_504_118, 0) - // Standard Error: 439 - .saturating_add(Weight::from_parts(1_521_895, 0).saturating_mul(r.into())) + // Minimum execution time: 1_059_000 picoseconds. + Weight::from_parts(1_735_816, 0) + // Standard Error: 66 + .saturating_add(Weight::from_parts(15_230, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64remu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_124_000 picoseconds. - Weight::from_parts(1_497_209, 0) - // Standard Error: 198 - .saturating_add(Weight::from_parts(1_449_843, 0).saturating_mul(r.into())) + // Minimum execution time: 1_076_000 picoseconds. + Weight::from_parts(1_451_290, 0) + // Standard Error: 6 + .saturating_add(Weight::from_parts(14_530, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64and(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_169_000 picoseconds. - Weight::from_parts(1_534_491, 0) - // Standard Error: 283 - .saturating_add(Weight::from_parts(894_703, 0).saturating_mul(r.into())) + // Minimum execution time: 1_079_000 picoseconds. + Weight::from_parts(1_457_537, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(8_963, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64or(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_178_000 picoseconds. - Weight::from_parts(1_485_473, 0) - // Standard Error: 552 - .saturating_add(Weight::from_parts(897_878, 0).saturating_mul(r.into())) + // Minimum execution time: 1_032_000 picoseconds. + Weight::from_parts(1_475_315, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(8_956, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64xor(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_214_000 picoseconds. - Weight::from_parts(1_580_999, 0) - // Standard Error: 358 - .saturating_add(Weight::from_parts(894_207, 0).saturating_mul(r.into())) + // Minimum execution time: 1_056_000 picoseconds. + Weight::from_parts(1_450_071, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(8_960, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64shl(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_176_000 picoseconds. - Weight::from_parts(1_490_470, 0) - // Standard Error: 738 - .saturating_add(Weight::from_parts(904_900, 0).saturating_mul(r.into())) + // Minimum execution time: 1_116_000 picoseconds. + Weight::from_parts(1_429_705, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(9_027, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64shrs(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_197_000 picoseconds. - Weight::from_parts(1_519_703, 0) - // Standard Error: 336 - .saturating_add(Weight::from_parts(901_277, 0).saturating_mul(r.into())) + // Minimum execution time: 1_059_000 picoseconds. + Weight::from_parts(1_429_307, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(9_048, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64shru(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_166_000 picoseconds. - Weight::from_parts(1_507_499, 0) - // Standard Error: 298 - .saturating_add(Weight::from_parts(901_153, 0).saturating_mul(r.into())) + // Minimum execution time: 1_093_000 picoseconds. + Weight::from_parts(1_411_827, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(9_528, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64rotl(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_158_000 picoseconds. - Weight::from_parts(1_491_176, 0) - // Standard Error: 341 - .saturating_add(Weight::from_parts(901_880, 0).saturating_mul(r.into())) + // Minimum execution time: 1_115_000 picoseconds. + Weight::from_parts(1_441_025, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(9_043, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64rotr(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_207_000 picoseconds. - Weight::from_parts(1_477_261, 0) - // Standard Error: 287 - .saturating_add(Weight::from_parts(902_622, 0).saturating_mul(r.into())) + // Minimum execution time: 1_077_000 picoseconds. + Weight::from_parts(1_480_666, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(9_031, 0).saturating_mul(r.into())) } } @@ -2161,8 +2132,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `109` // Estimated: `1594` - // Minimum execution time: 2_679_000 picoseconds. - Weight::from_parts(2_907_000, 1594) + // Minimum execution time: 2_736_000 picoseconds. + Weight::from_parts(2_931_000, 1594) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: Skipped Metadata (r:0 w:0) @@ -2170,12 +2141,12 @@ impl WeightInfo for () { /// The range of component `k` is `[0, 1024]`. fn on_initialize_per_trie_key(k: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `450 + k * (69 ±0)` - // Estimated: `440 + k * (70 ±0)` - // Minimum execution time: 11_162_000 picoseconds. - Weight::from_parts(5_734_923, 440) - // Standard Error: 1_097 - .saturating_add(Weight::from_parts(976_647, 0).saturating_mul(k.into())) + // Measured: `481 + k * (69 ±0)` + // Estimated: `471 + k * (70 ±0)` + // Minimum execution time: 10_759_000 picoseconds. + Weight::from_parts(6_965_683, 471) + // Standard Error: 1_019 + .saturating_add(Weight::from_parts(961_947, 0).saturating_mul(k.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) @@ -2187,12 +2158,12 @@ impl WeightInfo for () { /// The range of component `q` is `[0, 128]`. fn on_initialize_per_queue_item(q: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `250 + q * (33 ±0)` - // Estimated: `1725 + q * (33 ±0)` - // Minimum execution time: 2_626_000 picoseconds. - Weight::from_parts(10_626_314, 1725) - // Standard Error: 4_006 - .saturating_add(Weight::from_parts(1_298_864, 0).saturating_mul(q.into())) + // Measured: `281 + q * (33 ±0)` + // Estimated: `1753 + q * (33 ±0)` + // Minimum execution time: 2_633_000 picoseconds. + Weight::from_parts(10_668_837, 1753) + // Standard Error: 3_538 + .saturating_add(Weight::from_parts(1_277_168, 0).saturating_mul(q.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 33).saturating_mul(q.into())) @@ -2204,12 +2175,12 @@ impl WeightInfo for () { /// The range of component `c` is `[0, 61717]`. fn reinstrument(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `238 + c * (1 ±0)` - // Estimated: `3951 + c * (2 ±0)` - // Minimum execution time: 31_434_000 picoseconds. - Weight::from_parts(29_558_961, 3951) - // Standard Error: 55 - .saturating_add(Weight::from_parts(50_774, 0).saturating_mul(c.into())) + // Measured: `270 + c * (1 ±0)` + // Estimated: `4015 + c * (2 ±0)` + // Minimum execution time: 30_264_000 picoseconds. + Weight::from_parts(27_106_554, 4015) + // Standard Error: 53 + .saturating_add(Weight::from_parts(49_705, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 2).saturating_mul(c.into())) @@ -2227,12 +2198,12 @@ impl WeightInfo for () { /// The range of component `c` is `[0, 125952]`. fn call_with_code_per_byte(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `707` - // Estimated: `21400 + c * (5 ±0)` - // Minimum execution time: 309_015_000 picoseconds. - Weight::from_parts(318_740_885, 21400) - // Standard Error: 29 - .saturating_add(Weight::from_parts(30_993, 0).saturating_mul(c.into())) + // Measured: `803` + // Estimated: `21880 + c * (5 ±0)` + // Minimum execution time: 309_249_000 picoseconds. + Weight::from_parts(323_353_590, 21880) + // Standard Error: 25 + .saturating_add(Weight::from_parts(31_359, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 5).saturating_mul(c.into())) @@ -2260,14 +2231,14 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `270` // Estimated: `26207` - // Minimum execution time: 3_126_495_000 picoseconds. - Weight::from_parts(636_857_878, 26207) - // Standard Error: 294 - .saturating_add(Weight::from_parts(92_930, 0).saturating_mul(c.into())) - // Standard Error: 17 - .saturating_add(Weight::from_parts(1_128, 0).saturating_mul(i.into())) - // Standard Error: 17 - .saturating_add(Weight::from_parts(1_415, 0).saturating_mul(s.into())) + // Minimum execution time: 3_136_707_000 picoseconds. + Weight::from_parts(564_055_378, 26207) + // Standard Error: 286 + .saturating_add(Weight::from_parts(93_308, 0).saturating_mul(c.into())) + // Standard Error: 16 + .saturating_add(Weight::from_parts(1_165, 0).saturating_mul(i.into())) + // Standard Error: 16 + .saturating_add(Weight::from_parts(1_435, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(10_u64)) } @@ -2289,14 +2260,14 @@ impl WeightInfo for () { /// The range of component `s` is `[0, 1048576]`. fn instantiate(i: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `482` - // Estimated: `28521` - // Minimum execution time: 1_591_415_000 picoseconds. - Weight::from_parts(228_633_516, 28521) + // Measured: `546` + // Estimated: `28969` + // Minimum execution time: 1_631_314_000 picoseconds. + Weight::from_parts(236_693_159, 28969) // Standard Error: 8 - .saturating_add(Weight::from_parts(1_449, 0).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(1_434, 0).saturating_mul(i.into())) // Standard Error: 8 - .saturating_add(Weight::from_parts(1_444, 0).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_445, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } @@ -2312,10 +2283,10 @@ impl WeightInfo for () { /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) fn call() -> Weight { // Proof Size summary in bytes: - // Measured: `759` - // Estimated: `21615` - // Minimum execution time: 167_905_000 picoseconds. - Weight::from_parts(169_247_000, 21615) + // Measured: `855` + // Estimated: `22095` + // Minimum execution time: 167_139_000 picoseconds. + Weight::from_parts(168_034_000, 22095) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -2332,10 +2303,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `109` // Estimated: `7366` - // Minimum execution time: 305_128_000 picoseconds. - Weight::from_parts(310_911_395, 7366) - // Standard Error: 70 - .saturating_add(Weight::from_parts(94_067, 0).saturating_mul(c.into())) + // Minimum execution time: 306_518_000 picoseconds. + Weight::from_parts(325_652_407, 7366) + // Standard Error: 134 + .saturating_add(Weight::from_parts(93_502, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -2349,10 +2320,10 @@ impl WeightInfo for () { /// Proof: Contracts PristineCode (max_values: None, max_size: Some(125988), added: 128463, mode: Measured) fn remove_code() -> Weight { // Proof Size summary in bytes: - // Measured: `255` - // Estimated: `7950` - // Minimum execution time: 29_605_000 picoseconds. - Weight::from_parts(29_986_000, 7950) + // Measured: `287` + // Estimated: `8078` + // Minimum execution time: 29_084_000 picoseconds. + Weight::from_parts(29_350_000, 8078) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -2364,10 +2335,10 @@ impl WeightInfo for () { /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) fn set_code() -> Weight { // Proof Size summary in bytes: - // Measured: `570` - // Estimated: `19530` - // Minimum execution time: 33_824_000 picoseconds. - Weight::from_parts(34_388_000, 19530) + // Measured: `666` + // Estimated: `19818` + // Minimum execution time: 32_996_000 picoseconds. + Weight::from_parts(33_365_000, 19818) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -2381,18 +2352,18 @@ impl WeightInfo for () { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1600]`. fn seal_caller(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `781 + r * (480 ±0)` - // Estimated: `21765 + r * (2400 ±0)` - // Minimum execution time: 295_283_000 picoseconds. - Weight::from_parts(295_895_211, 21765) - // Standard Error: 44_860 - .saturating_add(Weight::from_parts(22_913_078, 0).saturating_mul(r.into())) + // Measured: `877 + r * (6 ±0)` + // Estimated: `22210 + r * (30 ±0)` + // Minimum execution time: 298_315_000 picoseconds. + Weight::from_parts(304_612_433, 22210) + // Standard Error: 904 + .saturating_add(Weight::from_parts(285_473, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 2400).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2404,19 +2375,19 @@ impl WeightInfo for () { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1600]`. fn seal_is_contract(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `821 + r * (19218 ±0)` - // Estimated: `21765 + r * (294095 ±0)` - // Minimum execution time: 295_760_000 picoseconds. - Weight::from_parts(151_512_811, 21765) - // Standard Error: 522_974 - .saturating_add(Weight::from_parts(263_028_353, 0).saturating_mul(r.into())) + // Measured: `935 + r * (272 ±0)` + // Estimated: `22315 + r * (3835 ±0)` + // Minimum execution time: 299_169_000 picoseconds. + Weight::from_parts(138_157_704, 22315) + // Standard Error: 6_115 + .saturating_add(Weight::from_parts(3_244_482, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) - .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 294095).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 3835).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2428,19 +2399,19 @@ impl WeightInfo for () { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1600]`. fn seal_code_hash(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `825 + r * (19539 ±0)` - // Estimated: `21810 + r * (295700 ±0)` - // Minimum execution time: 295_950_000 picoseconds. - Weight::from_parts(164_516_076, 21810) - // Standard Error: 469_540 - .saturating_add(Weight::from_parts(321_138_601, 0).saturating_mul(r.into())) + // Measured: `927 + r * (276 ±0)` + // Estimated: `22335 + r * (3855 ±0)` + // Minimum execution time: 299_262_000 picoseconds. + Weight::from_parts(157_105_627, 22335) + // Standard Error: 5_634 + .saturating_add(Weight::from_parts(3_995_666, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) - .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 295700).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 3855).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2452,18 +2423,18 @@ impl WeightInfo for () { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1600]`. fn seal_own_code_hash(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `788 + r * (480 ±0)` - // Estimated: `21800 + r * (2400 ±0)` - // Minimum execution time: 295_916_000 picoseconds. - Weight::from_parts(299_964_913, 21800) - // Standard Error: 78_211 - .saturating_add(Weight::from_parts(28_933_603, 0).saturating_mul(r.into())) + // Measured: `884 + r * (6 ±0)` + // Estimated: `22250 + r * (30 ±0)` + // Minimum execution time: 298_259_000 picoseconds. + Weight::from_parts(303_498_245, 22250) + // Standard Error: 874 + .saturating_add(Weight::from_parts(352_839, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 2400).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2475,18 +2446,18 @@ impl WeightInfo for () { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1600]`. fn seal_caller_is_origin(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `778 + r * (240 ±0)` - // Estimated: `21735 + r * (1200 ±0)` - // Minimum execution time: 293_588_000 picoseconds. - Weight::from_parts(297_568_984, 21735) - // Standard Error: 35_513 - .saturating_add(Weight::from_parts(11_074_880, 0).saturating_mul(r.into())) + // Measured: `874 + r * (3 ±0)` + // Estimated: `22215 + r * (15 ±0)` + // Minimum execution time: 295_689_000 picoseconds. + Weight::from_parts(314_004_541, 22215) + // Standard Error: 1_803 + .saturating_add(Weight::from_parts(131_102, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 1200).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 15).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2498,18 +2469,18 @@ impl WeightInfo for () { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1600]`. fn seal_address(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `782 + r * (480 ±0)` - // Estimated: `21730 + r * (2400 ±0)` - // Minimum execution time: 294_929_000 picoseconds. - Weight::from_parts(295_916_817, 21730) - // Standard Error: 64_902 - .saturating_add(Weight::from_parts(22_944_018, 0).saturating_mul(r.into())) + // Measured: `878 + r * (6 ±0)` + // Estimated: `22220 + r * (30 ±0)` + // Minimum execution time: 297_579_000 picoseconds. + Weight::from_parts(299_326_920, 22220) + // Standard Error: 990 + .saturating_add(Weight::from_parts(284_789, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 2400).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2521,18 +2492,18 @@ impl WeightInfo for () { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1600]`. fn seal_gas_left(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `783 + r * (480 ±0)` - // Estimated: `21720 + r * (2405 ±0)` - // Minimum execution time: 296_783_000 picoseconds. - Weight::from_parts(299_399_332, 21720) - // Standard Error: 50_982 - .saturating_add(Weight::from_parts(22_173_249, 0).saturating_mul(r.into())) + // Measured: `879 + r * (6 ±0)` + // Estimated: `22205 + r * (30 ±0)` + // Minimum execution time: 297_651_000 picoseconds. + Weight::from_parts(304_465_467, 22205) + // Standard Error: 736 + .saturating_add(Weight::from_parts(272_149, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 2405).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) } /// Storage: System Account (r:2 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2544,18 +2515,18 @@ impl WeightInfo for () { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1600]`. fn seal_balance(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `921 + r * (480 ±0)` - // Estimated: `24193 + r * (2451 ±0)` - // Minimum execution time: 294_120_000 picoseconds. - Weight::from_parts(305_889_989, 24193) - // Standard Error: 116_244 - .saturating_add(Weight::from_parts(114_781_094, 0).saturating_mul(r.into())) + // Measured: `1050 + r * (6 ±0)` + // Estimated: `25258 + r * (30 ±0)` + // Minimum execution time: 296_957_000 picoseconds. + Weight::from_parts(308_680_068, 25258) + // Standard Error: 1_377 + .saturating_add(Weight::from_parts(1_419_294, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 2451).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2567,18 +2538,18 @@ impl WeightInfo for () { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1600]`. fn seal_value_transferred(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `792 + r * (480 ±0)` - // Estimated: `21830 + r * (2400 ±0)` - // Minimum execution time: 295_569_000 picoseconds. - Weight::from_parts(299_774_774, 21830) - // Standard Error: 46_252 - .saturating_add(Weight::from_parts(21_753_842, 0).saturating_mul(r.into())) + // Measured: `888 + r * (6 ±0)` + // Estimated: `22305 + r * (30 ±0)` + // Minimum execution time: 297_735_000 picoseconds. + Weight::from_parts(301_533_807, 22305) + // Standard Error: 1_119 + .saturating_add(Weight::from_parts(277_289, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 2400).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2590,18 +2561,18 @@ impl WeightInfo for () { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1600]`. fn seal_minimum_balance(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `790 + r * (480 ±0)` - // Estimated: `21760 + r * (2400 ±0)` - // Minimum execution time: 295_400_000 picoseconds. - Weight::from_parts(300_637_266, 21760) - // Standard Error: 41_263 - .saturating_add(Weight::from_parts(21_565_466, 0).saturating_mul(r.into())) + // Measured: `886 + r * (6 ±0)` + // Estimated: `22295 + r * (30 ±0)` + // Minimum execution time: 299_599_000 picoseconds. + Weight::from_parts(303_664_496, 22295) + // Standard Error: 1_009 + .saturating_add(Weight::from_parts(280_353, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 2400).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2613,18 +2584,18 @@ impl WeightInfo for () { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1600]`. fn seal_block_number(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `787 + r * (480 ±0)` - // Estimated: `21785 + r * (2400 ±0)` - // Minimum execution time: 294_696_000 picoseconds. - Weight::from_parts(297_196_796, 21785) - // Standard Error: 61_173 - .saturating_add(Weight::from_parts(21_903_191, 0).saturating_mul(r.into())) + // Measured: `883 + r * (6 ±0)` + // Estimated: `22285 + r * (30 ±0)` + // Minimum execution time: 297_641_000 picoseconds. + Weight::from_parts(302_437_979, 22285) + // Standard Error: 669 + .saturating_add(Weight::from_parts(270_403, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 2400).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2636,18 +2607,18 @@ impl WeightInfo for () { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1600]`. fn seal_now(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `778 + r * (480 ±0)` - // Estimated: `21715 + r * (2400 ±0)` - // Minimum execution time: 297_714_000 picoseconds. - Weight::from_parts(306_030_237, 21715) - // Standard Error: 69_984 - .saturating_add(Weight::from_parts(21_744_413, 0).saturating_mul(r.into())) + // Measured: `874 + r * (6 ±0)` + // Estimated: `22215 + r * (30 ±0)` + // Minimum execution time: 297_217_000 picoseconds. + Weight::from_parts(299_538_157, 22215) + // Standard Error: 732 + .saturating_add(Weight::from_parts(280_800, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 2400).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2661,18 +2632,18 @@ impl WeightInfo for () { /// Proof: TransactionPayment NextFeeMultiplier (max_values: Some(1), max_size: Some(16), added: 511, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1600]`. fn seal_weight_to_fee(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `856 + r * (800 ±0)` - // Estimated: `24416 + r * (4805 ±0)` - // Minimum execution time: 295_180_000 picoseconds. - Weight::from_parts(308_851_025, 24416) - // Standard Error: 115_126 - .saturating_add(Weight::from_parts(98_678_404, 0).saturating_mul(r.into())) + // Measured: `952 + r * (10 ±0)` + // Estimated: `25022 + r * (60 ±0)` + // Minimum execution time: 297_286_000 picoseconds. + Weight::from_parts(311_436_352, 25022) + // Standard Error: 6_811 + .saturating_add(Weight::from_parts(1_291_941, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 4805).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 60).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2684,18 +2655,18 @@ impl WeightInfo for () { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1600]`. fn seal_gas(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `745 + r * (320 ±0)` - // Estimated: `21590 + r * (1600 ±0)` - // Minimum execution time: 151_587_000 picoseconds. - Weight::from_parts(155_713_096, 21590) - // Standard Error: 32_464 - .saturating_add(Weight::from_parts(8_332_778, 0).saturating_mul(r.into())) + // Measured: `841 + r * (4 ±0)` + // Estimated: `22035 + r * (20 ±0)` + // Minimum execution time: 154_772_000 picoseconds. + Weight::from_parts(159_224_457, 22035) + // Standard Error: 212 + .saturating_add(Weight::from_parts(102_264, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 1600).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 20).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2707,18 +2678,18 @@ impl WeightInfo for () { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1600]`. fn seal_input(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `780 + r * (480 ±0)` - // Estimated: `21715 + r * (2400 ±0)` - // Minimum execution time: 295_008_000 picoseconds. - Weight::from_parts(297_982_800, 21715) - // Standard Error: 37_480 - .saturating_add(Weight::from_parts(17_970_520, 0).saturating_mul(r.into())) + // Measured: `876 + r * (6 ±0)` + // Estimated: `22220 + r * (30 ±0)` + // Minimum execution time: 297_248_000 picoseconds. + Weight::from_parts(303_805_584, 22220) + // Standard Error: 858 + .saturating_add(Weight::from_parts(223_587, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 2400).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2730,15 +2701,15 @@ impl WeightInfo for () { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `n` is `[0, 1024]`. - fn seal_input_per_kb(n: u32, ) -> Weight { + /// The range of component `n` is `[0, 1048576]`. + fn seal_input_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1260` - // Estimated: `24120` - // Minimum execution time: 314_970_000 picoseconds. - Weight::from_parts(345_339_508, 24120) - // Standard Error: 4_112 - .saturating_add(Weight::from_parts(9_746_966, 0).saturating_mul(n.into())) + // Measured: `880` + // Estimated: `22220` + // Minimum execution time: 298_464_000 picoseconds. + Weight::from_parts(300_996_431, 22220) + // Standard Error: 1 + .saturating_add(Weight::from_parts(600, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -2755,12 +2726,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1]`. fn seal_return(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `768 + r * (45 ±0)` - // Estimated: `21660 + r * (225 ±0)` - // Minimum execution time: 293_072_000 picoseconds. - Weight::from_parts(295_694_824, 21660) - // Standard Error: 219_523 - .saturating_add(Weight::from_parts(783_975, 0).saturating_mul(r.into())) + // Measured: `864 + r * (45 ±0)` + // Estimated: `22140 + r * (225 ±0)` + // Minimum execution time: 294_347_000 picoseconds. + Weight::from_parts(296_793_034, 22140) + // Standard Error: 277_251 + .saturating_add(Weight::from_parts(1_711_665, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 225).saturating_mul(r.into())) @@ -2775,15 +2746,15 @@ impl WeightInfo for () { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `n` is `[0, 1024]`. - fn seal_return_per_kb(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `778` - // Estimated: `21755` - // Minimum execution time: 295_959_000 picoseconds. - Weight::from_parts(299_004_761, 21755) - // Standard Error: 3_988 - .saturating_add(Weight::from_parts(194_268, 0).saturating_mul(n.into())) + /// The range of component `n` is `[0, 1048576]`. + fn seal_return_per_byte(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `874` + // Estimated: `22255` + // Minimum execution time: 297_257_000 picoseconds. + Weight::from_parts(300_088_288, 22255) + // Standard Error: 1 + .saturating_add(Weight::from_parts(181, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -2804,17 +2775,17 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1]`. fn seal_terminate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `810 + r * (356 ±0)` - // Estimated: `25511 + r * (15321 ±0)` - // Minimum execution time: 294_626_000 picoseconds. - Weight::from_parts(297_839_179, 25511) - // Standard Error: 707_428 - .saturating_add(Weight::from_parts(81_507_620, 0).saturating_mul(r.into())) + // Measured: `906 + r * (452 ±0)` + // Estimated: `26183 + r * (15994 ±0)` + // Minimum execution time: 296_510_000 picoseconds. + Weight::from_parts(299_169_757, 26183) + // Standard Error: 205_313 + .saturating_add(Weight::from_parts(78_059_642, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((6_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((7_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 15321).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 15994).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2828,18 +2799,18 @@ impl WeightInfo for () { /// Proof: RandomnessCollectiveFlip RandomMaterial (max_values: Some(1), max_size: Some(2594), added: 3089, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1600]`. fn seal_random(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `825 + r * (800 ±0)` - // Estimated: `24199 + r * (4805 ±0)` - // Minimum execution time: 295_431_000 picoseconds. - Weight::from_parts(310_428_531, 24199) - // Standard Error: 143_501 - .saturating_add(Weight::from_parts(136_529_376, 0).saturating_mul(r.into())) + // Measured: `921 + r * (10 ±0)` + // Estimated: `24859 + r * (60 ±0)` + // Minimum execution time: 299_299_000 picoseconds. + Weight::from_parts(314_487_015, 24859) + // Standard Error: 1_552 + .saturating_add(Weight::from_parts(1_753_960, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 4805).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 60).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2851,18 +2822,18 @@ impl WeightInfo for () { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1600]`. fn seal_deposit_event(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `778 + r * (800 ±0)` - // Estimated: `21720 + r * (4000 ±0)` - // Minimum execution time: 293_778_000 picoseconds. - Weight::from_parts(323_404_081, 21720) - // Standard Error: 243_095 - .saturating_add(Weight::from_parts(269_012_482, 0).saturating_mul(r.into())) + // Measured: `874 + r * (10 ±0)` + // Estimated: `22215 + r * (50 ±0)` + // Minimum execution time: 296_188_000 picoseconds. + Weight::from_parts(305_901_539, 22215) + // Standard Error: 2_782 + .saturating_add(Weight::from_parts(3_456_054, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 4000).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 50).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2872,26 +2843,25 @@ impl WeightInfo for () { /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) - /// Storage: System EventTopics (r:322 w:322) + /// Storage: System EventTopics (r:6 w:6) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// 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 { - // Proof Size summary in bytes: - // Measured: `1725 + t * (2608 ±0) + n * (7 ±0)` - // Estimated: `26340 + t * (211030 ±0) + n * (50 ±0)` - // Minimum execution time: 1_317_129_000 picoseconds. - Weight::from_parts(566_722_295, 26340) - // Standard Error: 619_390 - .saturating_add(Weight::from_parts(194_334_643, 0).saturating_mul(t.into())) - // Standard Error: 170_114 - .saturating_add(Weight::from_parts(67_458_751, 0).saturating_mul(n.into())) + /// The range of component `n` is `[0, 16384]`. + fn seal_deposit_event_per_topic_and_byte(t: u32, n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `893 + t * (32 ±0)` + // Estimated: `22320 + t * (2640 ±0)` + // Minimum execution time: 313_860_000 picoseconds. + Weight::from_parts(312_473_092, 22320) + // Standard Error: 250_852 + .saturating_add(Weight::from_parts(2_258_502, 0).saturating_mul(t.into())) + // Standard Error: 70 + .saturating_add(Weight::from_parts(312, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) - .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(t.into()))) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(t.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(RocksDbWeight::get().writes((80_u64).saturating_mul(t.into()))) - .saturating_add(Weight::from_parts(0, 211030).saturating_mul(t.into())) - .saturating_add(Weight::from_parts(0, 50).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(t.into()))) + .saturating_add(Weight::from_parts(0, 2640).saturating_mul(t.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2903,18 +2873,18 @@ impl WeightInfo for () { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1600]`. fn seal_debug_message(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `777 + r * (560 ±0)` - // Estimated: `21710 + r * (2800 ±0)` - // Minimum execution time: 159_087_000 picoseconds. - Weight::from_parts(163_703_981, 21710) - // Standard Error: 26_067 - .saturating_add(Weight::from_parts(14_810_256, 0).saturating_mul(r.into())) + // Measured: `873 + r * (7 ±0)` + // Estimated: `22205 + r * (35 ±0)` + // Minimum execution time: 162_043_000 picoseconds. + Weight::from_parts(166_132_332, 22205) + // Standard Error: 716 + .saturating_add(Weight::from_parts(184_981, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 2800).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 35).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) @@ -2926,200 +2896,187 @@ impl WeightInfo for () { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `i` is `[0, 1024]`. - fn seal_debug_message_per_kb(i: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `125728` - // Estimated: `269982` - // Minimum execution time: 413_391_000 picoseconds. - Weight::from_parts(414_927_640, 269982) - // Standard Error: 1_740 - .saturating_add(Weight::from_parts(763_359, 0).saturating_mul(i.into())) + /// The range of component `i` is `[0, 1048576]`. + fn seal_debug_message_per_byte(i: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `125824` + // Estimated: `270073` + // Minimum execution time: 414_433_000 picoseconds. + Weight::from_parts(417_483_627, 270073) + // Standard Error: 1 + .saturating_add(Weight::from_parts(748, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 10]`. + /// The range of component `r` is `[0, 800]`. fn seal_set_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `815 + r * (23420 ±0)` - // Estimated: `815 + r * (23418 ±0)` - // Minimum execution time: 296_108_000 picoseconds. - Weight::from_parts(208_214_040, 815) - // Standard Error: 860_573 - .saturating_add(Weight::from_parts(480_342_550, 0).saturating_mul(r.into())) + // Measured: `941 + r * (292 ±0)` + // Estimated: `939 + r * (293 ±0)` + // Minimum execution time: 299_500_000 picoseconds. + Weight::from_parts(194_466_413, 939) + // Standard Error: 9_986 + .saturating_add(Weight::from_parts(6_010_112, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) - .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(RocksDbWeight::get().writes((80_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 23418).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_parts(0, 293).saturating_mul(r.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) - /// The range of component `n` is `[0, 8]`. - fn seal_set_storage_per_new_kb(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `12544 + n * (11945 ±0)` - // Estimated: `8401 + n * (12814 ±61)` - // Minimum execution time: 442_286_000 picoseconds. - Weight::from_parts(620_395_299, 8401) - // Standard Error: 1_661_554 - .saturating_add(Weight::from_parts(89_393_169, 0).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(52_u64)) - .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(n.into()))) - .saturating_add(RocksDbWeight::get().writes(50_u64)) - .saturating_add(RocksDbWeight::get().writes((7_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 12814).saturating_mul(n.into())) + /// The range of component `n` is `[0, 16384]`. + fn seal_set_storage_per_new_byte(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1432` + // Estimated: `1405` + // Minimum execution time: 314_171_000 picoseconds. + Weight::from_parts(335_595_397, 1405) + // Standard Error: 67 + .saturating_add(Weight::from_parts(90, 0).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(8_u64)) + .saturating_add(RocksDbWeight::get().writes(6_u64)) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) - /// The range of component `n` is `[0, 8]`. - fn seal_set_storage_per_old_kb(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `12532 + n * (175784 ±0)` - // Estimated: `8396 + n * (176649 ±61)` - // Minimum execution time: 440_882_000 picoseconds. - Weight::from_parts(587_317_981, 8396) - // Standard Error: 1_374_991 - .saturating_add(Weight::from_parts(66_271_084, 0).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(51_u64)) - .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(n.into()))) - .saturating_add(RocksDbWeight::get().writes(49_u64)) - .saturating_add(RocksDbWeight::get().writes((7_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 176649).saturating_mul(n.into())) + /// The range of component `n` is `[0, 16384]`. + fn seal_set_storage_per_old_byte(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1295 + n * (1 ±0)` + // Estimated: `1292 + n * (1 ±0)` + // Minimum execution time: 313_479_000 picoseconds. + Weight::from_parts(317_435_100, 1292) + // Standard Error: 41 + .saturating_add(Weight::from_parts(106, 0).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(7_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 10]`. + /// The range of component `r` is `[0, 800]`. fn seal_clear_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `807 + r * (23099 ±0)` - // Estimated: `812 + r * (23099 ±0)` - // Minimum execution time: 296_023_000 picoseconds. - Weight::from_parts(221_471_559, 812) - // Standard Error: 814_503 - .saturating_add(Weight::from_parts(465_928_089, 0).saturating_mul(r.into())) + // Measured: `937 + r * (288 ±0)` + // Estimated: `941 + r * (289 ±0)` + // Minimum execution time: 297_831_000 picoseconds. + Weight::from_parts(196_983_778, 941) + // Standard Error: 9_899 + .saturating_add(Weight::from_parts(5_904_642, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) - .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(RocksDbWeight::get().writes((80_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 23099).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_parts(0, 289).saturating_mul(r.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) - /// The range of component `n` is `[0, 8]`. - fn seal_clear_storage_per_kb(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `12256 + n * (175776 ±0)` - // Estimated: `8047 + n * (176655 ±62)` - // Minimum execution time: 412_212_000 picoseconds. - Weight::from_parts(569_213_147, 8047) - // Standard Error: 1_463_771 - .saturating_add(Weight::from_parts(67_932_081, 0).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(51_u64)) - .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(n.into()))) - .saturating_add(RocksDbWeight::get().writes(48_u64)) - .saturating_add(RocksDbWeight::get().writes((7_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 176655).saturating_mul(n.into())) + /// The range of component `n` is `[0, 16384]`. + fn seal_clear_storage_per_byte(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1291 + n * (1 ±0)` + // Estimated: `1288 + n * (1 ±0)` + // Minimum execution time: 320_156_000 picoseconds. + Weight::from_parts(327_504_368, 1288) + .saturating_add(RocksDbWeight::get().reads(7_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 10]`. + /// The range of component `r` is `[0, 800]`. fn seal_get_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `800 + r * (23744 ±0)` - // Estimated: `813 + r * (23740 ±0)` - // Minimum execution time: 296_007_000 picoseconds. - Weight::from_parts(229_100_700, 813) - // Standard Error: 684_970 - .saturating_add(Weight::from_parts(394_982_991, 0).saturating_mul(r.into())) + // Measured: `931 + r * (296 ±0)` + // Estimated: `936 + r * (297 ±0)` + // Minimum execution time: 305_849_000 picoseconds. + Weight::from_parts(219_649_351, 936) + // Standard Error: 9_157 + .saturating_add(Weight::from_parts(4_846_108, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) - .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 23740).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 297).saturating_mul(r.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) - /// The range of component `n` is `[0, 8]`. - fn seal_get_storage_per_kb(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `12863 + n * (175784 ±0)` - // Estimated: `8538 + n * (176688 ±63)` - // Minimum execution time: 392_306_000 picoseconds. - Weight::from_parts(539_188_004, 8538) - // Standard Error: 1_371_839 - .saturating_add(Weight::from_parts(155_130_373, 0).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(51_u64)) - .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(n.into()))) + /// The range of component `n` is `[0, 16384]`. + fn seal_get_storage_per_byte(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1307 + n * (1 ±0)` + // Estimated: `1304 + n * (1 ±0)` + // Minimum execution time: 312_106_000 picoseconds. + Weight::from_parts(315_905_779, 1304) + // Standard Error: 44 + .saturating_add(Weight::from_parts(674, 0).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 176688).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 10]`. + /// The range of component `r` is `[0, 800]`. fn seal_contains_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `818 + r * (23098 ±0)` - // Estimated: `824 + r * (23098 ±0)` - // Minimum execution time: 296_038_000 picoseconds. - Weight::from_parts(229_462_798, 824) - // Standard Error: 655_463 - .saturating_add(Weight::from_parts(372_593_685, 0).saturating_mul(r.into())) + // Measured: `952 + r * (288 ±0)` + // Estimated: `953 + r * (289 ±0)` + // Minimum execution time: 299_372_000 picoseconds. + Weight::from_parts(211_293_493, 953) + // Standard Error: 8_509 + .saturating_add(Weight::from_parts(4_688_993, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) - .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 23098).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 289).saturating_mul(r.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) - /// The range of component `n` is `[0, 8]`. - fn seal_contains_storage_per_kb(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `12200 + n * (175798 ±0)` - // Estimated: `8028 + n * (176661 ±62)` - // Minimum execution time: 386_782_000 picoseconds. - Weight::from_parts(512_965_975, 8028) - // Standard Error: 1_168_132 - .saturating_add(Weight::from_parts(63_307_325, 0).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(51_u64)) - .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(n.into()))) + /// The range of component `n` is `[0, 16384]`. + fn seal_contains_storage_per_byte(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1294 + n * (1 ±0)` + // Estimated: `1291 + n * (1 ±0)` + // Minimum execution time: 311_605_000 picoseconds. + Weight::from_parts(315_473_850, 1291) + // Standard Error: 37 + .saturating_add(Weight::from_parts(3, 0).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 176661).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 10]`. + /// The range of component `r` is `[0, 800]`. fn seal_take_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `815 + r * (23740 ±0)` - // Estimated: `817 + r * (23739 ±0)` - // Minimum execution time: 296_352_000 picoseconds. - Weight::from_parts(212_661_296, 817) - // Standard Error: 879_297 - .saturating_add(Weight::from_parts(494_182_672, 0).saturating_mul(r.into())) + // Measured: `925 + r * (296 ±0)` + // Estimated: `932 + r * (297 ±0)` + // Minimum execution time: 298_231_000 picoseconds. + Weight::from_parts(200_178_698, 932) + // Standard Error: 10_452 + .saturating_add(Weight::from_parts(6_107_653, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) - .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(RocksDbWeight::get().writes((80_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 23739).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_parts(0, 297).saturating_mul(r.into())) } /// Storage: Skipped Metadata (r:0 w:0) /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) - /// The range of component `n` is `[0, 8]`. - fn seal_take_storage_per_kb(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `12864 + n * (175784 ±0)` - // Estimated: `8539 + n * (176686 ±63)` - // Minimum execution time: 414_693_000 picoseconds. - Weight::from_parts(595_693_859, 8539) - // Standard Error: 1_673_819 - .saturating_add(Weight::from_parts(163_090_316, 0).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(51_u64)) - .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(n.into()))) - .saturating_add(RocksDbWeight::get().writes(48_u64)) - .saturating_add(RocksDbWeight::get().writes((7_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 176686).saturating_mul(n.into())) + /// The range of component `n` is `[0, 16384]`. + fn seal_take_storage_per_byte(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1308 + n * (1 ±0)` + // Estimated: `1305 + n * (1 ±0)` + // Minimum execution time: 314_970_000 picoseconds. + Weight::from_parts(318_135_821, 1305) + // Standard Error: 26 + .saturating_add(Weight::from_parts(630, 0).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(7_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } /// Storage: System Account (r:1602 w:1601) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3131,20 +3088,20 @@ impl WeightInfo for () { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1600]`. fn seal_transfer(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1329 + r * (3604 ±0)` - // Estimated: `25928 + r * (216096 ±4)` - // Minimum execution time: 299_205_000 picoseconds. - Weight::from_parts(221_142_217, 25928) - // Standard Error: 1_369_909 - .saturating_add(Weight::from_parts(1_665_917_241, 0).saturating_mul(r.into())) + // Measured: `1501 + r * (45 ±0)` + // Estimated: `27383 + r * (2700 ±0)` + // Minimum execution time: 299_629_000 picoseconds. + Weight::from_parts(150_915_187, 27383) + // Standard Error: 25_604 + .saturating_add(Weight::from_parts(20_859_844, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) - .saturating_add(RocksDbWeight::get().reads((80_u64).saturating_mul(r.into()))) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(4_u64)) - .saturating_add(RocksDbWeight::get().writes((80_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 216096).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_parts(0, 2700).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3156,20 +3113,20 @@ impl WeightInfo for () { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:1602 w:1602) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1600]`. fn seal_call(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1479 + r * (20514 ±0)` - // Estimated: `26429 + r * (498656 ±1)` - // Minimum execution time: 297_501_000 picoseconds. - Weight::from_parts(298_400_000, 26429) - // Standard Error: 9_372_890 - .saturating_add(Weight::from_parts(22_507_984_433, 0).saturating_mul(r.into())) + // Measured: `1670 + r * (288 ±0)` + // Estimated: `27813 + r * (6391 ±0)` + // Minimum execution time: 299_578_000 picoseconds. + Weight::from_parts(300_036_000, 27813) + // Standard Error: 102_709 + .saturating_add(Weight::from_parts(283_767_316, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) - .saturating_add(RocksDbWeight::get().reads((160_u64).saturating_mul(r.into()))) + .saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(RocksDbWeight::get().writes((160_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 498656).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().writes((2_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_parts(0, 6391).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3181,48 +3138,48 @@ impl WeightInfo for () { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:1537 w:1537) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1600]`. fn seal_delegate_call(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0 + r * (69030 ±0)` - // Estimated: `21755 + r * (647542 ±560)` - // Minimum execution time: 297_432_000 picoseconds. - Weight::from_parts(298_220_000, 21755) - // Standard Error: 9_420_834 - .saturating_add(Weight::from_parts(22_261_152_353, 0).saturating_mul(r.into())) + // Measured: `0 + r * (935 ±0)` + // Estimated: `22235 + r * (8322 ±10)` + // Minimum execution time: 298_943_000 picoseconds. + Weight::from_parts(299_619_000, 22235) + // Standard Error: 117_493 + .saturating_add(Weight::from_parts(280_555_517, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) - .saturating_add(RocksDbWeight::get().reads((150_u64).saturating_mul(r.into()))) + .saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(RocksDbWeight::get().writes((75_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 647542).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_parts(0, 8322).saturating_mul(r.into())) } - /// Storage: System Account (r:82 w:81) + /// Storage: System Account (r:3 w:2) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) - /// Storage: Contracts ContractInfoOf (r:81 w:81) + /// Storage: Contracts ContractInfoOf (r:2 w:2) /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:2 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) - /// Storage: System EventTopics (r:82 w:82) + /// Storage: System EventTopics (r:3 w:3) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// 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 { - // Proof Size summary in bytes: - // Measured: `21581 + t * (14318 ±0)` - // Estimated: `524200 + t * (272065 ±0)` - // Minimum execution time: 11_799_802_000 picoseconds. - Weight::from_parts(10_575_328_547, 524200) - // Standard Error: 11_952_810 - .saturating_add(Weight::from_parts(1_603_077_083, 0).saturating_mul(t.into())) - // Standard Error: 17_922 - .saturating_add(Weight::from_parts(9_876_752, 0).saturating_mul(c.into())) - .saturating_add(RocksDbWeight::get().reads(167_u64)) - .saturating_add(RocksDbWeight::get().reads((81_u64).saturating_mul(t.into()))) - .saturating_add(RocksDbWeight::get().writes(163_u64)) - .saturating_add(RocksDbWeight::get().writes((81_u64).saturating_mul(t.into()))) - .saturating_add(Weight::from_parts(0, 272065).saturating_mul(t.into())) + /// The range of component `c` is `[0, 1048576]`. + fn seal_call_per_transfer_clone_byte(t: u32, c: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1314 + t * (268 ±0)` + // Estimated: `31815 + t * (6290 ±0)` + // Minimum execution time: 453_013_000 picoseconds. + Weight::from_parts(442_536_283, 31815) + // Standard Error: 1_339_541 + .saturating_add(Weight::from_parts(17_062_445, 0).saturating_mul(t.into())) + // Standard Error: 1 + .saturating_add(Weight::from_parts(604, 0).saturating_mul(c.into())) + .saturating_add(RocksDbWeight::get().reads(9_u64)) + .saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(t.into()))) + .saturating_add(RocksDbWeight::get().writes(5_u64)) + .saturating_add(RocksDbWeight::get().writes((2_u64).saturating_mul(t.into()))) + .saturating_add(Weight::from_parts(0, 6290).saturating_mul(t.into())) } /// Storage: System Account (r:3202 w:3202) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3238,24 +3195,24 @@ impl WeightInfo for () { /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Measured) /// Storage: System EventTopics (r:1602 w:1602) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1600]`. fn seal_instantiate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1646 + r * (20288 ±0)` - // Estimated: `32625 + r * (1330150 ±2)` - // Minimum execution time: 298_155_000 picoseconds. - Weight::from_parts(299_212_000, 32625) - // Standard Error: 32_410_313 - .saturating_add(Weight::from_parts(30_417_025_178, 0).saturating_mul(r.into())) + // Measured: `1988 + r * (319 ±0)` + // Estimated: `34745 + r * (17090 ±0)` + // Minimum execution time: 300_123_000 picoseconds. + Weight::from_parts(300_406_000, 34745) + // Standard Error: 420_997 + .saturating_add(Weight::from_parts(382_704_025, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) - .saturating_add(RocksDbWeight::get().reads((480_u64).saturating_mul(r.into()))) - .saturating_add(RocksDbWeight::get().writes(5_u64)) - .saturating_add(RocksDbWeight::get().writes((400_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 1330150).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads((6_u64).saturating_mul(r.into()))) + .saturating_add(RocksDbWeight::get().writes(6_u64)) + .saturating_add(RocksDbWeight::get().writes((5_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_parts(0, 17090).saturating_mul(r.into())) } - /// Storage: System Account (r:162 w:162) + /// Storage: System Account (r:4 w:4) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) - /// Storage: Contracts ContractInfoOf (r:81 w:81) + /// Storage: Contracts ContractInfoOf (r:2 w:2) /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:2 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) @@ -3265,28 +3222,28 @@ impl WeightInfo for () { /// Proof: Contracts Nonce (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: Contracts OwnerInfoOf (r:1 w:1) /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Measured) - /// Storage: System EventTopics (r:82 w:82) + /// Storage: System EventTopics (r:3 w:3) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `t` is `[0, 1]`. - /// The range of component `i` is `[0, 960]`. - /// The range of component `s` is `[0, 960]`. - fn seal_instantiate_per_transfer_input_salt_kb(t: u32, i: u32, s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `5625 + t * (1 ±0)` - // Estimated: `856795 + t * (2471 ±3)` - // Minimum execution time: 105_914_928_000 picoseconds. - Weight::from_parts(13_229_760_432, 856795) - // Standard Error: 96_394_437 - .saturating_add(Weight::from_parts(398_413_888, 0).saturating_mul(t.into())) - // Standard Error: 157_192 - .saturating_add(Weight::from_parts(97_104_978, 0).saturating_mul(i.into())) - // Standard Error: 157_192 - .saturating_add(Weight::from_parts(97_146_130, 0).saturating_mul(s.into())) - .saturating_add(RocksDbWeight::get().reads(329_u64)) + /// The range of component `i` is `[0, 983040]`. + /// The range of component `s` is `[0, 983040]`. + fn seal_instantiate_per_transfer_input_salt_byte(t: u32, i: u32, s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1231 + t * (219 ±0)` + // Estimated: `43797 + t * (3812 ±2)` + // Minimum execution time: 1_636_322_000 picoseconds. + Weight::from_parts(360_859_331, 43797) + // Standard Error: 4_816_923 + .saturating_add(Weight::from_parts(109_179_023, 0).saturating_mul(t.into())) + // Standard Error: 7 + .saturating_add(Weight::from_parts(1_180, 0).saturating_mul(i.into())) + // Standard Error: 7 + .saturating_add(Weight::from_parts(1_344, 0).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(13_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(t.into()))) - .saturating_add(RocksDbWeight::get().writes(326_u64)) + .saturating_add(RocksDbWeight::get().writes(10_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(t.into()))) - .saturating_add(Weight::from_parts(0, 2471).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(0, 3812).saturating_mul(t.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3298,18 +3255,18 @@ impl WeightInfo for () { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 1]`. + /// The range of component `r` is `[0, 1600]`. fn seal_hash_sha2_256(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `775 + r * (642 ±0)` - // Estimated: `21695 + r * (3210 ±0)` - // Minimum execution time: 294_309_000 picoseconds. - Weight::from_parts(296_241_318, 21695) - // Standard Error: 127_872 - .saturating_add(Weight::from_parts(45_806_281, 0).saturating_mul(r.into())) + // Measured: `873 + r * (8 ±0)` + // Estimated: `22190 + r * (40 ±0)` + // Minimum execution time: 297_521_000 picoseconds. + Weight::from_parts(303_523_260, 22190) + // Standard Error: 1_162 + .saturating_add(Weight::from_parts(542_201, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 3210).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3321,15 +3278,15 @@ impl WeightInfo for () { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `n` is `[0, 1024]`. - fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `1577` - // Estimated: `25630` - // Minimum execution time: 341_248_000 picoseconds. - Weight::from_parts(341_607_000, 25630) - // Standard Error: 66_687 - .saturating_add(Weight::from_parts(322_250_398, 0).saturating_mul(n.into())) + /// The range of component `n` is `[0, 1048576]`. + fn seal_hash_sha2_256_per_byte(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `881` + // Estimated: `22225` + // Minimum execution time: 299_877_000 picoseconds. + Weight::from_parts(293_538_014, 22225) + // Standard Error: 2 + .saturating_add(Weight::from_parts(3_967, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3343,18 +3300,18 @@ impl WeightInfo for () { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 1]`. + /// The range of component `r` is `[0, 1600]`. fn seal_hash_keccak_256(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `777 + r * (642 ±0)` - // Estimated: `21705 + r * (3210 ±0)` - // Minimum execution time: 293_810_000 picoseconds. - Weight::from_parts(296_719_171, 21705) - // Standard Error: 450_807 - .saturating_add(Weight::from_parts(61_627_228, 0).saturating_mul(r.into())) + // Measured: `875 + r * (8 ±0)` + // Estimated: `22205 + r * (40 ±0)` + // Minimum execution time: 297_672_000 picoseconds. + Weight::from_parts(299_933_312, 22205) + // Standard Error: 1_138 + .saturating_add(Weight::from_parts(713_189, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 3210).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3366,15 +3323,15 @@ impl WeightInfo for () { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `n` is `[0, 1024]`. - fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `1579` - // Estimated: `25675` - // Minimum execution time: 354_550_000 picoseconds. - Weight::from_parts(355_136_000, 25675) - // Standard Error: 61_761 - .saturating_add(Weight::from_parts(257_021_566, 0).saturating_mul(n.into())) + /// The range of component `n` is `[0, 1048576]`. + fn seal_hash_keccak_256_per_byte(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `883` + // Estimated: `22245` + // Minimum execution time: 299_048_000 picoseconds. + Weight::from_parts(293_055_982, 22245) + // Standard Error: 2 + .saturating_add(Weight::from_parts(3_179, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3388,18 +3345,18 @@ impl WeightInfo for () { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 1]`. + /// The range of component `r` is `[0, 1600]`. fn seal_hash_blake2_256(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `777 + r * (642 ±0)` - // Estimated: `21705 + r * (3210 ±0)` - // Minimum execution time: 293_369_000 picoseconds. - Weight::from_parts(295_990_893, 21705) - // Standard Error: 431_269 - .saturating_add(Weight::from_parts(32_213_406, 0).saturating_mul(r.into())) + // Measured: `875 + r * (8 ±0)` + // Estimated: `22220 + r * (40 ±0)` + // Minimum execution time: 301_991_000 picoseconds. + Weight::from_parts(300_027_441, 22220) + // Standard Error: 981 + .saturating_add(Weight::from_parts(391_319, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 3210).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3411,15 +3368,15 @@ impl WeightInfo for () { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `n` is `[0, 1024]`. - fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `1579` - // Estimated: `25650` - // Minimum execution time: 326_595_000 picoseconds. - Weight::from_parts(327_188_000, 25650) - // Standard Error: 53_385 - .saturating_add(Weight::from_parts(74_046_074, 0).saturating_mul(n.into())) + /// The range of component `n` is `[0, 1048576]`. + fn seal_hash_blake2_256_per_byte(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `883` + // Estimated: `22265` + // Minimum execution time: 296_522_000 picoseconds. + Weight::from_parts(296_121_638, 22265) + // Standard Error: 2 + .saturating_add(Weight::from_parts(916, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3433,18 +3390,18 @@ impl WeightInfo for () { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 1]`. + /// The range of component `r` is `[0, 1600]`. fn seal_hash_blake2_128(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `777 + r * (679 ±0)` - // Estimated: `21705 + r * (3395 ±0)` - // Minimum execution time: 292_388_000 picoseconds. - Weight::from_parts(295_090_179, 21705) - // Standard Error: 170_487 - .saturating_add(Weight::from_parts(32_577_820, 0).saturating_mul(r.into())) + // Measured: `875 + r * (8 ±0)` + // Estimated: `22225 + r * (40 ±0)` + // Minimum execution time: 296_228_000 picoseconds. + Weight::from_parts(301_472_299, 22225) + // Standard Error: 875 + .saturating_add(Weight::from_parts(381_027, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 3395).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3456,15 +3413,15 @@ impl WeightInfo for () { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `n` is `[0, 1024]`. - fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `1579` - // Estimated: `25695` - // Minimum execution time: 326_862_000 picoseconds. - Weight::from_parts(327_449_000, 25695) - // Standard Error: 54_539 - .saturating_add(Weight::from_parts(74_042_337, 0).saturating_mul(n.into())) + /// The range of component `n` is `[0, 1048576]`. + fn seal_hash_blake2_128_per_byte(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `883` + // Estimated: `22235` + // Minimum execution time: 296_644_000 picoseconds. + Weight::from_parts(289_879_744, 22235) + // Standard Error: 2 + .saturating_add(Weight::from_parts(925, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3478,18 +3435,18 @@ impl WeightInfo for () { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 1]`. + /// The range of component `r` is `[0, 1600]`. fn seal_ecdsa_recover(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `821 + r * (6083 ±0)` - // Estimated: `21925 + r * (30415 ±0)` - // Minimum execution time: 295_597_000 picoseconds. - Weight::from_parts(298_267_200, 21925) - // Standard Error: 699_824 - .saturating_add(Weight::from_parts(3_021_734_700, 0).saturating_mul(r.into())) + // Measured: `800 + r * (78 ±0)` + // Estimated: `21845 + r * (390 ±0)` + // Minimum execution time: 297_804_000 picoseconds. + Weight::from_parts(471_994_534, 21845) + // Standard Error: 9_479 + .saturating_add(Weight::from_parts(36_886_028, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 30415).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 390).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3501,18 +3458,18 @@ impl WeightInfo for () { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 1]`. + /// The range of component `r` is `[0, 1600]`. fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `790 + r * (3362 ±0)` - // Estimated: `21770 + r * (16810 ±0)` - // Minimum execution time: 295_539_000 picoseconds. - Weight::from_parts(297_844_822, 21770) - // Standard Error: 490_532 - .saturating_add(Weight::from_parts(747_592_977, 0).saturating_mul(r.into())) + // Measured: `645 + r * (44 ±0)` + // Estimated: `21110 + r * (220 ±0)` + // Minimum execution time: 298_623_000 picoseconds. + Weight::from_parts(322_192_102, 21110) + // Standard Error: 3_207 + .saturating_add(Weight::from_parts(9_243_653, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 16810).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 220).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3526,20 +3483,20 @@ impl WeightInfo for () { /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Measured) /// Storage: System EventTopics (r:1538 w:1538) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1600]`. fn seal_set_code_hash(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0 + r * (74020 ±0)` - // Estimated: `69192 + r * (913289 ±821)` - // Minimum execution time: 295_164_000 picoseconds. - Weight::from_parts(296_597_000, 69192) - // Standard Error: 3_646_577 - .saturating_add(Weight::from_parts(1_725_796_807, 0).saturating_mul(r.into())) + // Measured: `0 + r * (1030 ±0)` + // Estimated: `30592 + r * (11919 ±7)` + // Minimum execution time: 298_574_000 picoseconds. + Weight::from_parts(299_383_000, 30592) + // Standard Error: 44_061 + .saturating_add(Weight::from_parts(21_625_366, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) - .saturating_add(RocksDbWeight::get().reads((225_u64).saturating_mul(r.into()))) + .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(RocksDbWeight::get().writes((150_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 913289).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().writes((2_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_parts(0, 11919).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3551,18 +3508,18 @@ impl WeightInfo for () { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1600]`. fn seal_reentrance_count(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `773 + r * (240 ±0)` - // Estimated: `21685 + r * (1200 ±0)` - // Minimum execution time: 296_287_000 picoseconds. - Weight::from_parts(300_696_694, 21685) - // Standard Error: 27_891 - .saturating_add(Weight::from_parts(10_943_994, 0).saturating_mul(r.into())) + // Measured: `869 + r * (3 ±0)` + // Estimated: `22215 + r * (15 ±0)` + // Minimum execution time: 297_014_000 picoseconds. + Weight::from_parts(301_226_615, 22215) + // Standard Error: 439 + .saturating_add(Weight::from_parts(143_017, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 1200).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 15).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3574,18 +3531,18 @@ impl WeightInfo for () { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1600]`. fn seal_account_reentrance_count(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2006 + r * (3154 ±0)` - // Estimated: `26435 + r * (15875 ±2)` - // Minimum execution time: 298_000_000 picoseconds. - Weight::from_parts(328_282_119, 26435) - // Standard Error: 104_874 - .saturating_add(Weight::from_parts(18_428_267, 0).saturating_mul(r.into())) + // Measured: `2072 + r * (39 ±0)` + // Estimated: `27645 + r * (200 ±0)` + // Minimum execution time: 299_074_000 picoseconds. + Weight::from_parts(336_979_016, 27645) + // Standard Error: 1_163 + .saturating_add(Weight::from_parts(227_998, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 15875).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 200).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3599,537 +3556,525 @@ impl WeightInfo for () { /// Proof: Contracts Nonce (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 20]`. + /// The range of component `r` is `[0, 1600]`. fn seal_instantiation_nonce(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `776 + r * (240 ±0)` - // Estimated: `23962 + r * (1440 ±0)` - // Minimum execution time: 295_104_000 picoseconds. - Weight::from_parts(299_334_585, 23962) - // Standard Error: 25_840 - .saturating_add(Weight::from_parts(9_744_866, 0).saturating_mul(r.into())) + // Measured: `872 + r * (3 ±0)` + // Estimated: `24580 + r * (18 ±0)` + // Minimum execution time: 296_959_000 picoseconds. + Weight::from_parts(303_796_839, 24580) + // Standard Error: 534 + .saturating_add(Weight::from_parts(118_978, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) - .saturating_add(Weight::from_parts(0, 1440).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 18).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64const(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_132_000 picoseconds. - Weight::from_parts(1_100_159, 0) - // Standard Error: 10_131 - .saturating_add(Weight::from_parts(436_462, 0).saturating_mul(r.into())) + // Minimum execution time: 1_020_000 picoseconds. + Weight::from_parts(1_355_107, 0) + // Standard Error: 1 + .saturating_add(Weight::from_parts(4_110, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64load(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_368_000 picoseconds. - Weight::from_parts(1_974_308, 0) - // Standard Error: 811 - .saturating_add(Weight::from_parts(1_079_620, 0).saturating_mul(r.into())) + // Minimum execution time: 1_224_000 picoseconds. + Weight::from_parts(1_819_284, 0) + // Standard Error: 10 + .saturating_add(Weight::from_parts(10_803, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64store(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_354_000 picoseconds. - Weight::from_parts(2_057_834, 0) - // Standard Error: 4_277 - .saturating_add(Weight::from_parts(1_008_797, 0).saturating_mul(r.into())) + // Minimum execution time: 1_216_000 picoseconds. + Weight::from_parts(1_795_011, 0) + // Standard Error: 5 + .saturating_add(Weight::from_parts(10_000, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_select(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_218_000 picoseconds. - Weight::from_parts(1_594_528, 0) - // Standard Error: 723 - .saturating_add(Weight::from_parts(1_147_486, 0).saturating_mul(r.into())) + // Minimum execution time: 1_127_000 picoseconds. + Weight::from_parts(1_491_730, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(11_471, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_if(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_156_000 picoseconds. - Weight::from_parts(1_460_611, 0) - // Standard Error: 419 - .saturating_add(Weight::from_parts(1_314_741, 0).saturating_mul(r.into())) + // Minimum execution time: 1_044_000 picoseconds. + Weight::from_parts(2_330_852, 0) + // Standard Error: 69 + .saturating_add(Weight::from_parts(12_866, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_br(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_166_000 picoseconds. - Weight::from_parts(1_454_460, 0) - // Standard Error: 493 - .saturating_add(Weight::from_parts(642_481, 0).saturating_mul(r.into())) + // Minimum execution time: 1_067_000 picoseconds. + Weight::from_parts(1_399_626, 0) + // Standard Error: 5 + .saturating_add(Weight::from_parts(6_430, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_br_if(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_144_000 picoseconds. - Weight::from_parts(1_410_515, 0) - // Standard Error: 894 - .saturating_add(Weight::from_parts(958_765, 0).saturating_mul(r.into())) + // Minimum execution time: 1_087_000 picoseconds. + Weight::from_parts(1_463_592, 0) + // Standard Error: 12 + .saturating_add(Weight::from_parts(9_707, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_br_table(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_190_000 picoseconds. - Weight::from_parts(1_143_236, 0) - // Standard Error: 2_773 - .saturating_add(Weight::from_parts(1_164_764, 0).saturating_mul(r.into())) + // Minimum execution time: 1_110_000 picoseconds. + Weight::from_parts(1_058_258, 0) + // Standard Error: 22 + .saturating_add(Weight::from_parts(11_713, 0).saturating_mul(r.into())) } /// The range of component `e` is `[1, 256]`. - fn instr_br_table_per_entry(e: u32, ) -> Weight { + fn instr_br_table_per_entry(_e: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_993_000 picoseconds. - Weight::from_parts(3_270_525, 0) - // Standard Error: 65 - .saturating_add(Weight::from_parts(4_418, 0).saturating_mul(e.into())) + // Minimum execution time: 1_189_000 picoseconds. + Weight::from_parts(1_416_188, 0) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_call(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_163_000 picoseconds. - Weight::from_parts(1_999_458, 0) - // Standard Error: 1_418 - .saturating_add(Weight::from_parts(2_371_979, 0).saturating_mul(r.into())) + // Minimum execution time: 2_201_000 picoseconds. + Weight::from_parts(3_375_851, 0) + // Standard Error: 96 + .saturating_add(Weight::from_parts(22_970, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_call_indirect(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_288_000 picoseconds. - Weight::from_parts(2_340_227, 0) - // Standard Error: 3_234 - .saturating_add(Weight::from_parts(3_038_523, 0).saturating_mul(r.into())) - } - /// The range of component `p` is `[0, 128]`. - fn instr_call_indirect_per_param(p: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 5_270_000 picoseconds. - Weight::from_parts(6_360_011, 0) - // Standard Error: 2_585 - .saturating_add(Weight::from_parts(226_149, 0).saturating_mul(p.into())) + // Minimum execution time: 1_286_000 picoseconds. + Weight::from_parts(2_817_725, 0) + // Standard Error: 55 + .saturating_add(Weight::from_parts(29_437, 0).saturating_mul(r.into())) } /// The range of component `l` is `[0, 1024]`. fn instr_call_per_local(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_580_000 picoseconds. - Weight::from_parts(5_183_658, 0) - // Standard Error: 80 - .saturating_add(Weight::from_parts(46_038, 0).saturating_mul(l.into())) + // Minimum execution time: 1_319_000 picoseconds. + Weight::from_parts(1_636_286, 0) + // Standard Error: 31 + .saturating_add(Weight::from_parts(1_240, 0).saturating_mul(l.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_local_get(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_559_000 picoseconds. - Weight::from_parts(2_846_350, 0) - // Standard Error: 2_809 - .saturating_add(Weight::from_parts(462_084, 0).saturating_mul(r.into())) + // Minimum execution time: 2_507_000 picoseconds. + Weight::from_parts(2_785_119, 0) + // Standard Error: 1 + .saturating_add(Weight::from_parts(4_601, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_local_set(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_530_000 picoseconds. - Weight::from_parts(2_835_072, 0) - // Standard Error: 479 - .saturating_add(Weight::from_parts(483_451, 0).saturating_mul(r.into())) + // Minimum execution time: 2_494_000 picoseconds. + Weight::from_parts(2_948_015, 0) + // Standard Error: 14 + .saturating_add(Weight::from_parts(4_788, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_local_tee(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_510_000 picoseconds. - Weight::from_parts(2_740_081, 0) - // Standard Error: 901 - .saturating_add(Weight::from_parts(664_354, 0).saturating_mul(r.into())) + // Minimum execution time: 2_443_000 picoseconds. + Weight::from_parts(3_065_273, 0) + // Standard Error: 15 + .saturating_add(Weight::from_parts(6_489, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_global_get(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_295_000 picoseconds. - Weight::from_parts(1_798_174, 0) - // Standard Error: 464 - .saturating_add(Weight::from_parts(896_289, 0).saturating_mul(r.into())) + // Minimum execution time: 1_214_000 picoseconds. + Weight::from_parts(1_634_049, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(8_960, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_global_set(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_287_000 picoseconds. - Weight::from_parts(1_636_548, 0) - // Standard Error: 658 - .saturating_add(Weight::from_parts(923_295, 0).saturating_mul(r.into())) + // Minimum execution time: 1_180_000 picoseconds. + Weight::from_parts(1_555_599, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(9_205, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_memory_current(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_353_000 picoseconds. - Weight::from_parts(1_672_309, 0) - // Standard Error: 403 - .saturating_add(Weight::from_parts(818_273, 0).saturating_mul(r.into())) + // Minimum execution time: 1_223_000 picoseconds. + Weight::from_parts(1_626_002, 0) + // Standard Error: 5 + .saturating_add(Weight::from_parts(8_181, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 1]`. + /// The range of component `r` is `[0, 16]`. fn instr_memory_grow(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_180_000 picoseconds. - Weight::from_parts(1_304_714, 0) - // Standard Error: 88_180 - .saturating_add(Weight::from_parts(183_952_985, 0).saturating_mul(r.into())) + // Minimum execution time: 1_148_000 picoseconds. + Weight::from_parts(307_155, 0) + // Standard Error: 138_541 + .saturating_add(Weight::from_parts(13_291_570, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64clz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_158_000 picoseconds. - Weight::from_parts(1_800_065, 0) - // Standard Error: 2_104 - .saturating_add(Weight::from_parts(625_410, 0).saturating_mul(r.into())) + // Minimum execution time: 1_079_000 picoseconds. + Weight::from_parts(1_372_409, 0) + // Standard Error: 50 + .saturating_add(Weight::from_parts(6_427, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64ctz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_208_000 picoseconds. - Weight::from_parts(1_483_908, 0) - // Standard Error: 319 - .saturating_add(Weight::from_parts(635_095, 0).saturating_mul(r.into())) + // Minimum execution time: 1_116_000 picoseconds. + Weight::from_parts(1_415_180, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(6_353, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64popcnt(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_164_000 picoseconds. - Weight::from_parts(1_506_871, 0) - // Standard Error: 264 - .saturating_add(Weight::from_parts(633_660, 0).saturating_mul(r.into())) + // Minimum execution time: 1_058_000 picoseconds. + Weight::from_parts(1_314_206, 0) + // Standard Error: 35 + .saturating_add(Weight::from_parts(6_431, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64eqz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_141_000 picoseconds. - Weight::from_parts(1_467_219, 0) - // Standard Error: 191 - .saturating_add(Weight::from_parts(651_156, 0).saturating_mul(r.into())) + // Minimum execution time: 1_059_000 picoseconds. + Weight::from_parts(1_455_331, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(6_507, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64extendsi32(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_170_000 picoseconds. - Weight::from_parts(1_474_718, 0) - // Standard Error: 224 - .saturating_add(Weight::from_parts(617_317, 0).saturating_mul(r.into())) + // Minimum execution time: 1_057_000 picoseconds. + Weight::from_parts(1_421_085, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(6_177, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64extendui32(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_195_000 picoseconds. - Weight::from_parts(1_501_421, 0) - // Standard Error: 221 - .saturating_add(Weight::from_parts(616_559, 0).saturating_mul(r.into())) + // Minimum execution time: 1_079_000 picoseconds. + Weight::from_parts(1_429_275, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(6_175, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i32wrapi64(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_172_000 picoseconds. - Weight::from_parts(1_482_402, 0) - // Standard Error: 2_163 - .saturating_add(Weight::from_parts(619_230, 0).saturating_mul(r.into())) + // Minimum execution time: 1_065_000 picoseconds. + Weight::from_parts(1_403_813, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(6_192, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64eq(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_149_000 picoseconds. - Weight::from_parts(2_021_801, 0) - // Standard Error: 20_804 - .saturating_add(Weight::from_parts(913_888, 0).saturating_mul(r.into())) + // Minimum execution time: 1_061_000 picoseconds. + Weight::from_parts(1_421_984, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(9_094, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64ne(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_187_000 picoseconds. - Weight::from_parts(1_358_437, 0) - // Standard Error: 1_946 - .saturating_add(Weight::from_parts(916_378, 0).saturating_mul(r.into())) + // Minimum execution time: 1_075_000 picoseconds. + Weight::from_parts(1_431_453, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(9_084, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64lts(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_175_000 picoseconds. - Weight::from_parts(1_527_336, 0) - // Standard Error: 243 - .saturating_add(Weight::from_parts(907_580, 0).saturating_mul(r.into())) + // Minimum execution time: 1_100_000 picoseconds. + Weight::from_parts(1_452_384, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(9_081, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64ltu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_220_000 picoseconds. - Weight::from_parts(1_530_715, 0) - // Standard Error: 224 - .saturating_add(Weight::from_parts(906_096, 0).saturating_mul(r.into())) + // Minimum execution time: 1_090_000 picoseconds. + Weight::from_parts(1_466_416, 0) + // Standard Error: 17 + .saturating_add(Weight::from_parts(9_091, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64gts(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_107_000 picoseconds. - Weight::from_parts(1_496_553, 0) - // Standard Error: 299 - .saturating_add(Weight::from_parts(907_963, 0).saturating_mul(r.into())) + // Minimum execution time: 1_056_000 picoseconds. + Weight::from_parts(1_676_091, 0) + // Standard Error: 47 + .saturating_add(Weight::from_parts(9_082, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64gtu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_153_000 picoseconds. - Weight::from_parts(1_482_710, 0) - // Standard Error: 182 - .saturating_add(Weight::from_parts(918_439, 0).saturating_mul(r.into())) + // Minimum execution time: 1_053_000 picoseconds. + Weight::from_parts(1_232_790, 0) + // Standard Error: 43 + .saturating_add(Weight::from_parts(9_329, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64les(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_142_000 picoseconds. - Weight::from_parts(1_522_114, 0) - // Standard Error: 297 - .saturating_add(Weight::from_parts(906_633, 0).saturating_mul(r.into())) + // Minimum execution time: 1_091_000 picoseconds. + Weight::from_parts(1_476_212, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(9_074, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64leu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_119_000 picoseconds. - Weight::from_parts(2_199_831, 0) - // Standard Error: 4_234 - .saturating_add(Weight::from_parts(898_161, 0).saturating_mul(r.into())) + // Minimum execution time: 1_083_000 picoseconds. + Weight::from_parts(1_484_966, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(9_184, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64ges(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_163_000 picoseconds. - Weight::from_parts(1_489_404, 0) - // Standard Error: 416 - .saturating_add(Weight::from_parts(908_450, 0).saturating_mul(r.into())) + // Minimum execution time: 1_089_000 picoseconds. + Weight::from_parts(1_516_766, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(9_063, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64geu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_204_000 picoseconds. - Weight::from_parts(2_266_296, 0) - // Standard Error: 13_013 - .saturating_add(Weight::from_parts(899_225, 0).saturating_mul(r.into())) + // Minimum execution time: 996_000 picoseconds. + Weight::from_parts(1_460_638, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(9_076, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64add(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_160_000 picoseconds. - Weight::from_parts(1_470_799, 0) - // Standard Error: 422 - .saturating_add(Weight::from_parts(897_325, 0).saturating_mul(r.into())) + // Minimum execution time: 1_095_000 picoseconds. + Weight::from_parts(1_448_412, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(8_977, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64sub(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_125_000 picoseconds. - Weight::from_parts(1_521_508, 0) - // Standard Error: 594 - .saturating_add(Weight::from_parts(886_145, 0).saturating_mul(r.into())) + // Minimum execution time: 1_071_000 picoseconds. + Weight::from_parts(1_459_165, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(8_852, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64mul(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_139_000 picoseconds. - Weight::from_parts(1_490_535, 0) - // Standard Error: 211 - .saturating_add(Weight::from_parts(884_929, 0).saturating_mul(r.into())) + // Minimum execution time: 1_082_000 picoseconds. + Weight::from_parts(1_450_718, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(8_860, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64divs(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_180_000 picoseconds. - Weight::from_parts(2_221_481, 0) - // Standard Error: 9_884 - .saturating_add(Weight::from_parts(1_507_511, 0).saturating_mul(r.into())) + // Minimum execution time: 1_065_000 picoseconds. + Weight::from_parts(1_436_871, 0) + // Standard Error: 9 + .saturating_add(Weight::from_parts(15_241, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64divu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_131_000 picoseconds. - Weight::from_parts(1_498_652, 0) - // Standard Error: 531 - .saturating_add(Weight::from_parts(1_451_498, 0).saturating_mul(r.into())) + // Minimum execution time: 1_065_000 picoseconds. + Weight::from_parts(1_423_806, 0) + // Standard Error: 17 + .saturating_add(Weight::from_parts(14_706, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64rems(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_145_000 picoseconds. - Weight::from_parts(1_504_118, 0) - // Standard Error: 439 - .saturating_add(Weight::from_parts(1_521_895, 0).saturating_mul(r.into())) + // Minimum execution time: 1_059_000 picoseconds. + Weight::from_parts(1_735_816, 0) + // Standard Error: 66 + .saturating_add(Weight::from_parts(15_230, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64remu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_124_000 picoseconds. - Weight::from_parts(1_497_209, 0) - // Standard Error: 198 - .saturating_add(Weight::from_parts(1_449_843, 0).saturating_mul(r.into())) + // Minimum execution time: 1_076_000 picoseconds. + Weight::from_parts(1_451_290, 0) + // Standard Error: 6 + .saturating_add(Weight::from_parts(14_530, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64and(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_169_000 picoseconds. - Weight::from_parts(1_534_491, 0) - // Standard Error: 283 - .saturating_add(Weight::from_parts(894_703, 0).saturating_mul(r.into())) + // Minimum execution time: 1_079_000 picoseconds. + Weight::from_parts(1_457_537, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(8_963, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64or(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_178_000 picoseconds. - Weight::from_parts(1_485_473, 0) - // Standard Error: 552 - .saturating_add(Weight::from_parts(897_878, 0).saturating_mul(r.into())) + // Minimum execution time: 1_032_000 picoseconds. + Weight::from_parts(1_475_315, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(8_956, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64xor(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_214_000 picoseconds. - Weight::from_parts(1_580_999, 0) - // Standard Error: 358 - .saturating_add(Weight::from_parts(894_207, 0).saturating_mul(r.into())) + // Minimum execution time: 1_056_000 picoseconds. + Weight::from_parts(1_450_071, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(8_960, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64shl(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_176_000 picoseconds. - Weight::from_parts(1_490_470, 0) - // Standard Error: 738 - .saturating_add(Weight::from_parts(904_900, 0).saturating_mul(r.into())) + // Minimum execution time: 1_116_000 picoseconds. + Weight::from_parts(1_429_705, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(9_027, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64shrs(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_197_000 picoseconds. - Weight::from_parts(1_519_703, 0) - // Standard Error: 336 - .saturating_add(Weight::from_parts(901_277, 0).saturating_mul(r.into())) + // Minimum execution time: 1_059_000 picoseconds. + Weight::from_parts(1_429_307, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(9_048, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64shru(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_166_000 picoseconds. - Weight::from_parts(1_507_499, 0) - // Standard Error: 298 - .saturating_add(Weight::from_parts(901_153, 0).saturating_mul(r.into())) + // Minimum execution time: 1_093_000 picoseconds. + Weight::from_parts(1_411_827, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(9_528, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64rotl(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_158_000 picoseconds. - Weight::from_parts(1_491_176, 0) - // Standard Error: 341 - .saturating_add(Weight::from_parts(901_880, 0).saturating_mul(r.into())) + // Minimum execution time: 1_115_000 picoseconds. + Weight::from_parts(1_441_025, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(9_043, 0).saturating_mul(r.into())) } - /// The range of component `r` is `[0, 50]`. + /// The range of component `r` is `[0, 5000]`. fn instr_i64rotr(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_207_000 picoseconds. - Weight::from_parts(1_477_261, 0) - // Standard Error: 287 - .saturating_add(Weight::from_parts(902_622, 0).saturating_mul(r.into())) + // Minimum execution time: 1_077_000 picoseconds. + Weight::from_parts(1_480_666, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(9_031, 0).saturating_mul(r.into())) } } From a2d4f7dfa97c1496f964c6fe833d5128f8319c77 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Fri, 17 Mar 2023 12:24:14 +0100 Subject: [PATCH 524/715] Keystore overhaul (#13615) * Remove 'supported_keys' 'sign_with_any' and 'sign_with_all' from keystore trait * Remove the aync keystore * Renaming: - SyncCryptoStore -> Keystore - SyncCryptoStorePtr -> KeystorePtr - KeyStore -> MemoryKeystore * Fix authority discovery worker and tests * Rename 'insert_unknown' to 'insert' * Remove leftover --- Cargo.lock | 1 - bin/node-template/node/src/service.rs | 9 +- bin/node/cli/src/service.rs | 17 +- bin/node/executor/tests/submit_transaction.rs | 22 +- bin/node/rpc/src/lib.rs | 4 +- bin/utils/chain-spec-builder/src/main.rs | 6 +- client/api/src/execution_extensions.rs | 6 +- client/authority-discovery/src/tests.rs | 5 +- client/authority-discovery/src/worker.rs | 38 ++- .../authority-discovery/src/worker/tests.rs | 86 +++--- client/cli/src/commands/insert_key.rs | 8 +- client/cli/src/error.rs | 2 +- client/consensus/aura/src/lib.rs | 18 +- client/consensus/babe/rpc/src/lib.rs | 17 +- client/consensus/babe/src/authorship.rs | 20 +- client/consensus/babe/src/lib.rs | 8 +- client/consensus/babe/src/tests.rs | 17 +- .../beefy/src/communication/gossip.rs | 6 +- client/consensus/beefy/src/keystore.rs | 33 ++- client/consensus/beefy/src/lib.rs | 4 +- client/consensus/beefy/src/tests.rs | 8 +- .../grandpa/src/communication/mod.rs | 10 +- client/consensus/grandpa/src/lib.rs | 12 +- client/consensus/grandpa/src/observer.rs | 6 +- client/consensus/grandpa/src/tests.rs | 12 +- .../manual-seal/src/consensus/babe.rs | 6 +- client/keystore/src/local.rs | 158 ++--------- client/rpc-api/src/author/error.rs | 2 +- client/rpc/src/author/mod.rs | 14 +- client/rpc/src/author/tests.rs | 12 +- client/service/src/builder.rs | 39 +-- client/service/src/client/client.rs | 6 +- frame/benchmarking/src/baseline.rs | 4 +- frame/contracts/src/tests.rs | 4 +- frame/examples/offchain-worker/src/tests.rs | 20 +- frame/nfts/src/mock.rs | 4 +- .../application-crypto/test/src/ecdsa.rs | 6 +- .../application-crypto/test/src/ed25519.rs | 6 +- .../application-crypto/test/src/sr25519.rs | 6 +- primitives/consensus/beefy/src/commitment.rs | 12 +- primitives/consensus/beefy/src/witness.rs | 12 +- primitives/consensus/grandpa/src/lib.rs | 6 +- primitives/io/src/lib.rs | 24 +- primitives/keystore/Cargo.toml | 1 - primitives/keystore/src/lib.rs | 250 +----------------- primitives/keystore/src/testing.rs | 156 ++--------- test-utils/client/src/lib.rs | 6 +- .../benchmarking-cli/src/pallet/command.rs | 4 +- utils/frame/try-runtime/cli/src/lib.rs | 4 +- 49 files changed, 317 insertions(+), 820 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d0aea7729bd2d..9121a85919844 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10339,7 +10339,6 @@ dependencies = [ name = "sp-keystore" version = "0.13.0" dependencies = [ - "async-trait", "futures", "merlin", "parity-scale-codec", diff --git a/bin/node-template/node/src/service.rs b/bin/node-template/node/src/service.rs index 34e4e566d92fc..40ad80c7b3b79 100644 --- a/bin/node-template/node/src/service.rs +++ b/bin/node-template/node/src/service.rs @@ -150,7 +150,7 @@ pub fn new_partial( fn remote_keystore(_url: &String) -> Result, &'static str> { // FIXME: here would the concrete keystore be built, // must return a concrete type (NOT `LocalKeystore`) that - // implements `CryptoStore` and `SyncCryptoStore` + // implements `Keystore` Err("Remote Keystore not supported.") } @@ -233,7 +233,7 @@ pub fn new_full(mut config: Configuration) -> Result let _rpc_handlers = sc_service::spawn_tasks(sc_service::SpawnTasksParams { network: network.clone(), client: client.clone(), - keystore: keystore_container.sync_keystore(), + keystore: keystore_container.keystore(), task_manager: &mut task_manager, transaction_pool: transaction_pool.clone(), rpc_builder: rpc_extensions_builder, @@ -276,7 +276,7 @@ pub fn new_full(mut config: Configuration) -> Result }, force_authoring, backoff_authoring_blocks, - keystore: keystore_container.sync_keystore(), + keystore: keystore_container.keystore(), sync_oracle: sync_service.clone(), justification_sync_link: sync_service.clone(), block_proposal_slot_portion: SlotProportion::new(2f32 / 3f32), @@ -296,8 +296,7 @@ pub fn new_full(mut config: Configuration) -> Result 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 keystore = if role.is_authority() { Some(keystore_container.keystore()) } else { None }; let grandpa_config = sc_consensus_grandpa::Config { // FIXME #1578 make this available through chainspec diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs index 3c9716c08d1c0..a2d66cd6349de 100644 --- a/bin/node/cli/src/service.rs +++ b/bin/node/cli/src/service.rs @@ -251,7 +251,7 @@ pub fn new_partial( let client = client.clone(); let pool = transaction_pool.clone(); let select_chain = select_chain.clone(); - let keystore = keystore_container.sync_keystore(); + let keystore = keystore_container.keystore(); let chain_spec = config.chain_spec.cloned_box(); let rpc_backend = backend.clone(); @@ -386,7 +386,7 @@ pub fn new_full_base( config, backend, client: client.clone(), - keystore: keystore_container.sync_keystore(), + keystore: keystore_container.keystore(), network: network.clone(), rpc_builder: Box::new(rpc_builder), transaction_pool: transaction_pool.clone(), @@ -431,7 +431,7 @@ pub fn new_full_base( let client_clone = client.clone(); let slot_duration = babe_link.config().slot_duration(); let babe_config = sc_consensus_babe::BabeParams { - keystore: keystore_container.sync_keystore(), + keystore: keystore_container.keystore(), client: client.clone(), select_chain, env: proposer, @@ -507,8 +507,7 @@ pub fn new_full_base( // 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 keystore = if role.is_authority() { Some(keystore_container.keystore()) } else { None }; let config = grandpa::Config { // FIXME #1578 make this available through chainspec @@ -596,7 +595,7 @@ mod tests { use sp_core::{crypto::Pair as CryptoPair, Public}; use sp_inherents::InherentDataProvider; use sp_keyring::AccountKeyring; - use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; + use sp_keystore::{Keystore, KeystorePtr}; use sp_runtime::{ generic::{Digest, Era, SignedPayload}, key_types::BABE, @@ -616,10 +615,10 @@ mod tests { sp_tracing::try_init_simple(); let keystore_path = tempfile::tempdir().expect("Creates keystore path"); - let keystore: SyncCryptoStorePtr = + let keystore: KeystorePtr = Arc::new(LocalKeystore::open(keystore_path.path(), None).expect("Creates keystore")); let alice: sp_consensus_babe::AuthorityId = - SyncCryptoStore::sr25519_generate_new(&*keystore, BABE, Some("//Alice")) + Keystore::sr25519_generate_new(&*keystore, BABE, Some("//Alice")) .expect("Creates authority pair") .into(); @@ -736,7 +735,7 @@ mod tests { // sign the pre-sealed hash of the block and then // add it to a digest item. let to_sign = pre_hash.encode(); - let signature = SyncCryptoStore::sign_with( + let signature = Keystore::sign_with( &*keystore, sp_consensus_babe::AuthorityId::ID, &alice.to_public_crypto_pair(), diff --git a/bin/node/executor/tests/submit_transaction.rs b/bin/node/executor/tests/submit_transaction.rs index ab5df62a2e714..32eacd78b78b7 100644 --- a/bin/node/executor/tests/submit_transaction.rs +++ b/bin/node/executor/tests/submit_transaction.rs @@ -21,7 +21,7 @@ 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; -use sp_keystore::{testing::KeyStore, KeystoreExt, SyncCryptoStore}; +use sp_keystore::{testing::MemoryKeystore, Keystore, KeystoreExt}; use std::sync::Arc; pub mod common; @@ -62,20 +62,20 @@ fn should_submit_signed_transaction() { let (pool, state) = TestTransactionPoolExt::new(); t.register_extension(TransactionPoolExt::new(pool)); - let keystore = KeyStore::new(); - SyncCryptoStore::sr25519_generate_new( + let keystore = MemoryKeystore::new(); + Keystore::sr25519_generate_new( &keystore, sr25519::AuthorityId::ID, Some(&format!("{}/hunter1", PHRASE)), ) .unwrap(); - SyncCryptoStore::sr25519_generate_new( + Keystore::sr25519_generate_new( &keystore, sr25519::AuthorityId::ID, Some(&format!("{}/hunter2", PHRASE)), ) .unwrap(); - SyncCryptoStore::sr25519_generate_new( + Keystore::sr25519_generate_new( &keystore, sr25519::AuthorityId::ID, Some(&format!("{}/hunter3", PHRASE)), @@ -105,14 +105,14 @@ fn should_submit_signed_twice_from_the_same_account() { let (pool, state) = TestTransactionPoolExt::new(); t.register_extension(TransactionPoolExt::new(pool)); - let keystore = KeyStore::new(); - SyncCryptoStore::sr25519_generate_new( + let keystore = MemoryKeystore::new(); + Keystore::sr25519_generate_new( &keystore, sr25519::AuthorityId::ID, Some(&format!("{}/hunter1", PHRASE)), ) .unwrap(); - SyncCryptoStore::sr25519_generate_new( + Keystore::sr25519_generate_new( &keystore, sr25519::AuthorityId::ID, Some(&format!("{}/hunter2", PHRASE)), @@ -162,7 +162,7 @@ fn should_submit_signed_twice_from_all_accounts() { let (pool, state) = TestTransactionPoolExt::new(); t.register_extension(TransactionPoolExt::new(pool)); - let keystore = KeyStore::new(); + let keystore = MemoryKeystore::new(); keystore .sr25519_generate_new(sr25519::AuthorityId::ID, Some(&format!("{}/hunter1", PHRASE))) .unwrap(); @@ -226,8 +226,8 @@ fn submitted_transaction_should_be_valid() { let (pool, state) = TestTransactionPoolExt::new(); t.register_extension(TransactionPoolExt::new(pool)); - let keystore = KeyStore::new(); - SyncCryptoStore::sr25519_generate_new( + let keystore = MemoryKeystore::new(); + Keystore::sr25519_generate_new( &keystore, sr25519::AuthorityId::ID, Some(&format!("{}/hunter1", PHRASE)), diff --git a/bin/node/rpc/src/lib.rs b/bin/node/rpc/src/lib.rs index 7c2f7c15e05c8..9dcdf0f218923 100644 --- a/bin/node/rpc/src/lib.rs +++ b/bin/node/rpc/src/lib.rs @@ -49,7 +49,7 @@ use sp_block_builder::BlockBuilder; use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata}; use sp_consensus::SelectChain; use sp_consensus_babe::BabeApi; -use sp_keystore::SyncCryptoStorePtr; +use sp_keystore::KeystorePtr; /// Extra dependencies for BABE. pub struct BabeDeps { @@ -58,7 +58,7 @@ pub struct BabeDeps { /// BABE pending epoch changes. pub shared_epoch_changes: SharedEpochChanges, /// The keystore that manages the keys of the node. - pub keystore: SyncCryptoStorePtr, + pub keystore: KeystorePtr, } /// Extra dependencies for GRANDPA diff --git a/bin/utils/chain-spec-builder/src/main.rs b/bin/utils/chain-spec-builder/src/main.rs index b3f28b269fddd..f7b7d94c57d1c 100644 --- a/bin/utils/chain-spec-builder/src/main.rs +++ b/bin/utils/chain-spec-builder/src/main.rs @@ -32,7 +32,7 @@ use sp_core::{ crypto::{ByteArray, Ss58Codec}, sr25519, }; -use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; +use sp_keystore::{Keystore, KeystorePtr}; /// A utility to easily create a testnet chain spec definition with a given set /// of authorities and endowed accounts and/or generate random accounts. @@ -164,7 +164,7 @@ fn generate_chain_spec( fn generate_authority_keys_and_store(seeds: &[String], keystore_path: &Path) -> Result<(), String> { for (n, seed) in seeds.iter().enumerate() { - let keystore: SyncCryptoStorePtr = Arc::new( + let keystore: KeystorePtr = Arc::new( LocalKeystore::open(keystore_path.join(format!("auth-{}", n)), None) .map_err(|err| err.to_string())?, ); @@ -173,7 +173,7 @@ fn generate_authority_keys_and_store(seeds: &[String], keystore_path: &Path) -> chain_spec::authority_keys_from_seed(seed); let insert_key = |key_type, public| { - SyncCryptoStore::insert_unknown(&*keystore, key_type, &format!("//{}", seed), public) + Keystore::insert(&*keystore, key_type, &format!("//{}", seed), public) .map_err(|_| format!("Failed to insert key: {}", grandpa)) }; diff --git a/client/api/src/execution_extensions.rs b/client/api/src/execution_extensions.rs index b491d7672e8f0..ffa670f7bc628 100644 --- a/client/api/src/execution_extensions.rs +++ b/client/api/src/execution_extensions.rs @@ -30,7 +30,7 @@ use sp_core::{ ExecutionContext, }; use sp_externalities::{Extension, Extensions}; -use sp_keystore::{KeystoreExt, SyncCryptoStorePtr}; +use sp_keystore::{KeystoreExt, KeystorePtr}; use sp_runtime::{ generic::BlockId, traits::{Block as BlockT, NumberFor}, @@ -163,7 +163,7 @@ impl DbExternaliti /// for each call, based on required `Capabilities`. pub struct ExecutionExtensions { strategies: ExecutionStrategies, - keystore: Option, + keystore: Option, offchain_db: Option>, // FIXME: these two are only RwLock because of https://github.com/paritytech/substrate/issues/4587 // remove when fixed. @@ -191,7 +191,7 @@ impl ExecutionExtensions { /// Create new `ExecutionExtensions` given a `keystore` and `ExecutionStrategies`. pub fn new( strategies: ExecutionStrategies, - keystore: Option, + keystore: Option, offchain_db: Option>, ) -> Self { let transaction_pool = RwLock::new(None); diff --git a/client/authority-discovery/src/tests.rs b/client/authority-discovery/src/tests.rs index 982c3fc04c590..d354f6a963e73 100644 --- a/client/authority-discovery/src/tests.rs +++ b/client/authority-discovery/src/tests.rs @@ -33,7 +33,7 @@ use std::{collections::HashSet, sync::Arc}; use sp_authority_discovery::AuthorityId; use sp_core::crypto::key_types; -use sp_keystore::{testing::KeyStore, CryptoStore}; +use sp_keystore::{testing::MemoryKeystore, Keystore}; #[test] fn get_addresses_and_authority_id() { @@ -42,12 +42,11 @@ fn get_addresses_and_authority_id() { let mut pool = LocalPool::new(); - let key_store = KeyStore::new(); + let key_store = MemoryKeystore::new(); let remote_authority_id: AuthorityId = pool.run_until(async { key_store .sr25519_generate_new(key_types::AUTHORITY_DISCOVERY, None) - .await .unwrap() .into() }); diff --git a/client/authority-discovery/src/worker.rs b/client/authority-discovery/src/worker.rs index 034d72902e65d..5d7d21a5b6de4 100644 --- a/client/authority-discovery/src/worker.rs +++ b/client/authority-discovery/src/worker.rs @@ -53,7 +53,7 @@ use sp_authority_discovery::{ use sp_blockchain::HeaderBackend; use sp_core::crypto::{key_types, CryptoTypePublicPair, Pair}; -use sp_keystore::CryptoStore; +use sp_keystore::{Keystore, KeystorePtr}; use sp_runtime::traits::Block as BlockT; mod addr_cache; @@ -78,7 +78,7 @@ const MAX_IN_FLIGHT_LOOKUPS: usize = 8; /// Role an authority discovery [`Worker`] can run as. pub enum Role { /// Publish own addresses and discover addresses of others. - PublishAndDiscover(Arc), + PublishAndDiscover(KeystorePtr), /// Discover addresses of others. Discover, } @@ -364,8 +364,7 @@ where Some(peer_signature), key_store.as_ref(), keys_vec, - ) - .await?; + )?; for (key, value) in kv_pairs.into_iter() { self.network.put_value(key, value); @@ -382,7 +381,6 @@ where let local_keys = match &self.role { Role::PublishAndDiscover(key_store) => key_store .sr25519_public_keys(key_types::AUTHORITY_DISCOVERY) - .await .into_iter() .collect::>(), Role::Discover => HashSet::new(), @@ -588,12 +586,11 @@ where // next authority set with two keys. The function does not return all of the local authority // discovery public keys, but only the ones intersecting with the current or next authority set. async fn get_own_public_keys_within_authority_set( - key_store: Arc, + key_store: KeystorePtr, client: &Client, ) -> Result> { let local_pub_keys = key_store .sr25519_public_keys(key_types::AUTHORITY_DISCOVERY) - .await .into_iter() .collect::>(); @@ -663,33 +660,28 @@ fn sign_record_with_peer_id( Ok(schema::PeerSignature { signature, public_key }) } -async fn sign_record_with_authority_ids( +fn sign_record_with_authority_ids( serialized_record: Vec, peer_signature: Option, - key_store: &dyn CryptoStore, + key_store: &dyn Keystore, 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::with_capacity(keys.len()); - let mut result = vec![]; - for (sign_result, key) in signatures.into_iter().zip(keys.iter()) { - let mut signed_record = vec![]; + for key in keys.iter() { + let auth_signature = key_store + .sign_with(key_types::AUTHORITY_DISCOVERY, key, &serialized_record) + .map_err(|_| Error::Signing)? + .ok_or_else(|| Error::MissingSignature(key.clone()))?; - // 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 { + let signed_record = schema::SignedAuthorityRecord { record: serialized_record.clone(), auth_signature, peer_signature: peer_signature.clone(), } - .encode(&mut signed_record) - .map_err(Error::EncodingProto)?; + .encode_to_vec(); - result.push((hash_authority_id(key.1.as_ref()), signed_record)); + result.push((hash_authority_id(&key.1), signed_record)); } Ok(result) diff --git a/client/authority-discovery/src/worker/tests.rs b/client/authority-discovery/src/worker/tests.rs index febe40657e06a..c918d79932624 100644 --- a/client/authority-discovery/src/worker/tests.rs +++ b/client/authority-discovery/src/worker/tests.rs @@ -40,7 +40,7 @@ use prometheus_endpoint::prometheus::default_registry; use sc_client_api::HeaderBackend; use sc_network::Signature; use sp_api::{ApiRef, ProvideRuntimeApi}; -use sp_keystore::{testing::KeyStore, CryptoStore}; +use sp_keystore::{testing::MemoryKeystore, Keystore}; use sp_runtime::traits::{Block as BlockT, NumberFor, Zero}; use substrate_test_runtime_client::runtime::Block; @@ -208,10 +208,10 @@ impl<'a> NetworkSigner for TestSigner<'a> { } } -async fn build_dht_event( +fn build_dht_event( addresses: Vec, public_key: AuthorityId, - key_store: &dyn CryptoStore, + key_store: &MemoryKeystore, network: Option<&Signer>, ) -> Vec<(KademliaKey, Vec)> { let serialized_record = @@ -224,7 +224,6 @@ async fn build_dht_event( 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 @@ -234,7 +233,7 @@ async fn build_dht_event( fn new_registers_metrics() { let (_dht_event_tx, dht_event_rx) = mpsc::channel(1000); let network: Arc = Arc::new(Default::default()); - let key_store = KeyStore::new(); + let key_store = MemoryKeystore::new(); let test_api = Arc::new(TestApi { authorities: vec![] }); let registry = prometheus_endpoint::Registry::new(); @@ -266,7 +265,7 @@ fn triggers_dht_get_query() { let test_api = Arc::new(TestApi { authorities: authorities.clone() }); let network = Arc::new(TestNetwork::default()); - let key_store = KeyStore::new(); + let key_store = MemoryKeystore::new(); let (_to_worker, from_service) = mpsc::channel(0); let mut worker = Worker::new( @@ -298,14 +297,12 @@ fn publish_discover_cycle() { let network: Arc = Arc::new(Default::default()); - let key_store = KeyStore::new(); + let key_store = MemoryKeystore::new(); let _ = pool.spawner().spawn_local_obj( async move { - let node_a_public = key_store - .sr25519_generate_new(key_types::AUTHORITY_DISCOVERY, None) - .await - .unwrap(); + let node_a_public = + key_store.sr25519_generate_new(key_types::AUTHORITY_DISCOVERY, None).unwrap(); let test_api = Arc::new(TestApi { authorities: vec![node_a_public.into()] }); let (_to_worker, from_service) = mpsc::channel(0); @@ -337,7 +334,7 @@ fn publish_discover_cycle() { authorities: vec![node_a_public.into()], }); let network: Arc = Arc::new(Default::default()); - let key_store = KeyStore::new(); + let key_store = MemoryKeystore::new(); let (_to_worker, from_service) = mpsc::channel(0); let mut worker = Worker::new( @@ -371,7 +368,7 @@ fn publish_discover_cycle() { fn terminate_when_event_stream_terminates() { let (dht_event_tx, dht_event_rx) = channel(1000); let network: Arc = Arc::new(Default::default()); - let key_store = KeyStore::new(); + let key_store = MemoryKeystore::new(); let test_api = Arc::new(TestApi { authorities: vec![] }); let (to_worker, from_service) = mpsc::channel(0); @@ -420,11 +417,11 @@ fn dont_stop_polling_dht_event_stream_after_bogus_event() { address.with(multiaddr::Protocol::P2p(peer_id.into())) }; - let remote_key_store = KeyStore::new(); - let remote_public_key: AuthorityId = - block_on(remote_key_store.sr25519_generate_new(key_types::AUTHORITY_DISCOVERY, None)) - .unwrap() - .into(); + let remote_key_store = MemoryKeystore::new(); + let remote_public_key: AuthorityId = remote_key_store + .sr25519_generate_new(key_types::AUTHORITY_DISCOVERY, None) + .unwrap() + .into(); let (mut dht_event_tx, dht_event_rx) = channel(1); let (network, mut network_events) = { @@ -433,7 +430,7 @@ fn dont_stop_polling_dht_event_stream_after_bogus_event() { (Arc::new(n), r) }; - let key_store = KeyStore::new(); + let key_store = MemoryKeystore::new(); let test_api = Arc::new(TestApi { authorities: vec![remote_public_key.clone()] }); let mut pool = LocalPool::new(); @@ -480,8 +477,7 @@ fn dont_stop_polling_dht_event_stream_after_bogus_event() { remote_public_key.clone(), &remote_key_store, None, - ) - .await; + ); DhtEvent::ValueFound(kv_pairs) }; dht_event_tx.send(dht_event).await.expect("Channel has capacity of 1."); @@ -498,7 +494,7 @@ fn dont_stop_polling_dht_event_stream_after_bogus_event() { } struct DhtValueFoundTester { - pub remote_key_store: KeyStore, + pub remote_key_store: MemoryKeystore, pub remote_authority_public: sp_core::sr25519::Public, pub remote_node_key: Keypair, pub local_worker: Option< @@ -516,10 +512,10 @@ struct DhtValueFoundTester { 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 remote_key_store = MemoryKeystore::new(); + let remote_authority_public = remote_key_store + .sr25519_generate_new(key_types::AUTHORITY_DISCOVERY, None) + .unwrap(); let remote_node_key = Keypair::generate_ed25519(); Self { remote_key_store, remote_authority_public, remote_node_key, local_worker: None } @@ -542,7 +538,7 @@ impl DhtValueFoundTester { let local_test_api = Arc::new(TestApi { authorities: vec![self.remote_authority_public.into()] }); let local_network: Arc = Arc::new(Default::default()); - let local_key_store = KeyStore::new(); + let local_key_store = MemoryKeystore::new(); let (_to_worker, from_service) = mpsc::channel(0); let mut local_worker = Worker::new( @@ -576,12 +572,12 @@ 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::( + let kv_pairs = build_dht_event::( addresses, tester.remote_authority_public.into(), &tester.remote_key_store, None, - )); + ); let cached_remote_addresses = tester.process_value_found(false, kv_pairs); assert_eq!(MAX_ADDRESSES_PER_AUTHORITY, cached_remote_addresses.unwrap().len()); @@ -591,12 +587,12 @@ fn limit_number_of_addresses_added_to_cache_per_authority() { 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( + let kv_pairs = build_dht_event( vec![addr.clone()], tester.remote_authority_public.into(), &tester.remote_key_store, Some(&TestSigner { keypair: &tester.remote_node_key }), - )); + ); let cached_remote_addresses = tester.process_value_found(true, kv_pairs); @@ -611,12 +607,12 @@ fn strict_accept_address_with_peer_signature() { fn reject_address_with_rogue_peer_signature() { let mut tester = DhtValueFoundTester::new(); let rogue_remote_node_key = Keypair::generate_ed25519(); - let kv_pairs = block_on(build_dht_event( + let kv_pairs = build_dht_event( vec![tester.multiaddr_with_peer_id(1)], tester.remote_authority_public.into(), &tester.remote_key_store, Some(&TestSigner { keypair: &rogue_remote_node_key }), - )); + ); let cached_remote_addresses = tester.process_value_found(false, kv_pairs); @@ -629,12 +625,12 @@ fn reject_address_with_rogue_peer_signature() { #[test] fn reject_address_with_invalid_peer_signature() { let mut tester = DhtValueFoundTester::new(); - let mut kv_pairs = block_on(build_dht_event( + let mut kv_pairs = build_dht_event( vec![tester.multiaddr_with_peer_id(1)], tester.remote_authority_public.into(), &tester.remote_key_store, Some(&TestSigner { keypair: &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] = !p.signature[1]); @@ -651,12 +647,12 @@ fn reject_address_with_invalid_peer_signature() { #[test] fn reject_address_without_peer_signature() { let mut tester = DhtValueFoundTester::new(); - let kv_pairs = block_on(build_dht_event::( + let kv_pairs = build_dht_event::( vec![tester.multiaddr_with_peer_id(1)], tester.remote_authority_public.into(), &tester.remote_key_store, None, - )); + ); let cached_remote_addresses = tester.process_value_found(true, kv_pairs); @@ -669,12 +665,12 @@ fn do_not_cache_addresses_without_peer_id() { 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::( + let kv_pairs = build_dht_event::( vec![multiaddr_with_peer_id.clone(), multiaddr_without_peer_id], tester.remote_authority_public.into(), &tester.remote_key_store, None, - )); + ); let cached_remote_addresses = tester.process_value_found(false, kv_pairs); @@ -701,7 +697,7 @@ fn addresses_to_publish_adds_p2p() { Arc::new(TestApi { authorities: vec![] }), network.clone(), Box::pin(dht_event_rx), - Role::PublishAndDiscover(Arc::new(KeyStore::new())), + Role::PublishAndDiscover(Arc::new(MemoryKeystore::new())), Some(prometheus_endpoint::Registry::new()), Default::default(), ); @@ -735,7 +731,7 @@ fn addresses_to_publish_respects_existing_p2p_protocol() { Arc::new(TestApi { authorities: vec![] }), network.clone(), Box::pin(dht_event_rx), - Role::PublishAndDiscover(Arc::new(KeyStore::new())), + Role::PublishAndDiscover(Arc::new(MemoryKeystore::new())), Some(prometheus_endpoint::Registry::new()), Default::default(), ); @@ -755,10 +751,11 @@ fn lookup_throttling() { address.with(multiaddr::Protocol::P2p(peer_id.into())) }; - let remote_key_store = KeyStore::new(); + let remote_key_store = MemoryKeystore::new(); let remote_public_keys: Vec = (0..20) .map(|_| { - block_on(remote_key_store.sr25519_generate_new(key_types::AUTHORITY_DISCOVERY, None)) + remote_key_store + .sr25519_generate_new(key_types::AUTHORITY_DISCOVERY, None) .unwrap() .into() }) @@ -818,8 +815,7 @@ fn lookup_throttling() { remote_key, &remote_key_store, None, - ) - .await; + ); DhtEvent::ValueFound(kv_pairs) }; dht_event_tx.send(dht_event).await.expect("Channel has capacity of 1."); diff --git a/client/cli/src/commands/insert_key.rs b/client/cli/src/commands/insert_key.rs index 77d0f57780a94..b02c0181d43a2 100644 --- a/client/cli/src/commands/insert_key.rs +++ b/client/cli/src/commands/insert_key.rs @@ -24,7 +24,7 @@ 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 sp_keystore::{Keystore, KeystorePtr}; use std::sync::Arc; /// The `insert` command @@ -69,7 +69,7 @@ impl InsertKeyCmd { let (keystore, public) = match self.keystore_params.keystore_config(&config_dir)? { (_, KeystoreConfig::Path { path, password }) => { let public = with_crypto_scheme!(self.scheme, to_vec(&suri, password.clone()))?; - let keystore: SyncCryptoStorePtr = Arc::new(LocalKeystore::open(path, password)?); + let keystore: KeystorePtr = Arc::new(LocalKeystore::open(path, password)?); (keystore, public) }, _ => unreachable!("keystore_config always returns path and password; qed"), @@ -78,8 +78,8 @@ impl InsertKeyCmd { let key_type = KeyTypeId::try_from(self.key_type.as_str()).map_err(|_| Error::KeyTypeInvalid)?; - SyncCryptoStore::insert_unknown(&*keystore, key_type, &suri, &public[..]) - .map_err(|_| Error::KeyStoreOperation)?; + Keystore::insert(&*keystore, key_type, &suri, &public[..]) + .map_err(|_| Error::KeystoreOperation)?; Ok(()) } diff --git a/client/cli/src/error.rs b/client/cli/src/error.rs index 3b30ccb3ed6b0..6c0cfca4932ef 100644 --- a/client/cli/src/error.rs +++ b/client/cli/src/error.rs @@ -64,7 +64,7 @@ pub enum Error { SignatureInvalid, #[error("Key store operation failed")] - KeyStoreOperation, + KeystoreOperation, #[error("Key storage issue encountered")] KeyStorage(#[from] sc_keystore::Error), diff --git a/client/consensus/aura/src/lib.rs b/client/consensus/aura/src/lib.rs index e90494ddfc177..8cdad148d6ef4 100644 --- a/client/consensus/aura/src/lib.rs +++ b/client/consensus/aura/src/lib.rs @@ -51,7 +51,7 @@ use sp_consensus::{BlockOrigin, Environment, Error as ConsensusError, Proposer, use sp_consensus_slots::Slot; use sp_core::crypto::{ByteArray, Pair, Public}; use sp_inherents::CreateInherentDataProviders; -use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; +use sp_keystore::{Keystore, KeystorePtr}; use sp_runtime::{ traits::{Block as BlockT, Header, Member, NumberFor, Zero}, DigestItem, @@ -168,7 +168,7 @@ pub struct StartAuraParams { /// The backoff strategy when we miss slots. pub backoff_authoring_blocks: Option, /// The keystore used by the node. - pub keystore: SyncCryptoStorePtr, + pub keystore: KeystorePtr, /// 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 @@ -265,7 +265,7 @@ pub struct BuildAuraWorkerParams { /// The backoff strategy when we miss slots. pub backoff_authoring_blocks: Option, /// The keystore used by the node. - pub keystore: SyncCryptoStorePtr, + pub keystore: KeystorePtr, /// 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 @@ -346,7 +346,7 @@ struct AuraWorker { client: Arc, block_import: I, env: E, - keystore: SyncCryptoStorePtr, + keystore: KeystorePtr, sync_oracle: SO, justification_sync_link: L, force_authoring: bool, @@ -418,7 +418,7 @@ where ) -> Option { let expected_author = slot_author::

(slot, epoch_data); expected_author.and_then(|p| { - if SyncCryptoStore::has_keys( + if Keystore::has_keys( &*self.keystore, &[(p.to_raw_vec(), sp_application_crypto::key_types::AURA)], ) { @@ -449,7 +449,7 @@ where // 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( + let signature = Keystore::sign_with( &*self.keystore, as AppKey>::ID, &public_type_pair, @@ -798,7 +798,7 @@ mod tests { LocalKeystore::open(keystore_path.path(), None).expect("Creates keystore."), ); - SyncCryptoStore::sr25519_generate_new(&*keystore, AURA, Some(&key.to_seed())) + Keystore::sr25519_generate_new(&*keystore, AURA, Some(&key.to_seed())) .expect("Creates authority key"); keystore_paths.push(keystore_path); @@ -883,7 +883,7 @@ mod tests { let keystore_path = tempfile::tempdir().expect("Creates keystore path"); let keystore = LocalKeystore::open(keystore_path.path(), None).expect("Creates keystore."); - let public = SyncCryptoStore::sr25519_generate_new(&keystore, AuthorityPair::ID, None) + let public = Keystore::sr25519_generate_new(&keystore, AuthorityPair::ID, None) .expect("Key should be created"); authorities.push(public.into()); @@ -933,7 +933,7 @@ mod tests { let keystore_path = tempfile::tempdir().expect("Creates keystore path"); let keystore = LocalKeystore::open(keystore_path.path(), None).expect("Creates keystore."); - SyncCryptoStore::sr25519_generate_new( + Keystore::sr25519_generate_new( &keystore, AuthorityPair::ID, Some(&Keyring::Alice.to_seed()), diff --git a/client/consensus/babe/rpc/src/lib.rs b/client/consensus/babe/rpc/src/lib.rs index 677a4ad92c9e1..bc4d1c17eb3f1 100644 --- a/client/consensus/babe/rpc/src/lib.rs +++ b/client/consensus/babe/rpc/src/lib.rs @@ -37,7 +37,7 @@ use sp_consensus_babe::{ digests::PreDigest, AuthorityId, BabeApi as BabeRuntimeApi, BabeConfiguration, }; use sp_core::crypto::ByteArray; -use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; +use sp_keystore::{Keystore, KeystorePtr}; use sp_runtime::traits::{Block as BlockT, Header as _}; use std::{collections::HashMap, sync::Arc}; @@ -57,7 +57,7 @@ pub struct Babe { /// shared reference to EpochChanges shared_epoch_changes: SharedEpochChanges, /// shared reference to the Keystore - keystore: SyncCryptoStorePtr, + keystore: KeystorePtr, /// config (actually holds the slot duration) babe_config: BabeConfiguration, /// The SelectChain strategy @@ -71,7 +71,7 @@ impl Babe { pub fn new( client: Arc, shared_epoch_changes: SharedEpochChanges, - keystore: SyncCryptoStorePtr, + keystore: KeystorePtr, babe_config: BabeConfiguration, select_chain: SC, deny_unsafe: DenyUnsafe, @@ -117,10 +117,7 @@ where .iter() .enumerate() .filter_map(|(i, a)| { - if SyncCryptoStore::has_keys( - &*self.keystore, - &[(a.0.to_raw_vec(), AuthorityId::ID)], - ) { + if Keystore::has_keys(&*self.keystore, &[(a.0.to_raw_vec(), AuthorityId::ID)]) { Some((a.0.clone(), i)) } else { None @@ -217,7 +214,7 @@ mod tests { use sp_application_crypto::AppPair; use sp_core::crypto::key_types::BABE; use sp_keyring::Sr25519Keyring; - use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; + use sp_keystore::{Keystore, KeystorePtr}; use substrate_test_runtime_client::{ runtime::Block, Backend, DefaultTestClientBuilderExt, TestClient, TestClientBuilder, TestClientBuilderExt, @@ -229,11 +226,11 @@ mod tests { /// creates keystore backed by a temp file fn create_temp_keystore( authority: Sr25519Keyring, - ) -> (SyncCryptoStorePtr, tempfile::TempDir) { + ) -> (KeystorePtr, tempfile::TempDir) { let keystore_path = tempfile::tempdir().expect("Creates keystore path"); let keystore = Arc::new(LocalKeystore::open(keystore_path.path(), None).expect("Creates keystore")); - SyncCryptoStore::sr25519_generate_new(&*keystore, BABE, Some(&authority.to_seed())) + Keystore::sr25519_generate_new(&*keystore, BABE, Some(&authority.to_seed())) .expect("Creates authority key"); (keystore, keystore_path) diff --git a/client/consensus/babe/src/authorship.rs b/client/consensus/babe/src/authorship.rs index 195a19b3d0f61..956e886d1254c 100644 --- a/client/consensus/babe/src/authorship.rs +++ b/client/consensus/babe/src/authorship.rs @@ -29,7 +29,7 @@ use sp_consensus_babe::{ }; use sp_consensus_vrf::schnorrkel::{VRFOutput, VRFProof}; use sp_core::{blake2_256, crypto::ByteArray, U256}; -use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; +use sp_keystore::{Keystore, KeystorePtr}; /// Calculates the primary selection threshold for a given authority, taking /// into account `c` (`1 - c` represents the probability of a slot being empty). @@ -133,7 +133,7 @@ fn claim_secondary_slot( slot: Slot, epoch: &Epoch, keys: &[(AuthorityId, usize)], - keystore: &SyncCryptoStorePtr, + keystore: &KeystorePtr, author_secondary_vrf: bool, ) -> Option<(PreDigest, AuthorityId)> { let Epoch { authorities, randomness, mut epoch_index, .. } = epoch; @@ -153,7 +153,7 @@ fn claim_secondary_slot( if authority_id == expected_author { let pre_digest = if author_secondary_vrf { let transcript_data = make_transcript_data(randomness, slot, epoch_index); - let result = SyncCryptoStore::sr25519_vrf_sign( + let result = Keystore::sr25519_vrf_sign( &**keystore, AuthorityId::ID, authority_id.as_ref(), @@ -169,7 +169,7 @@ fn claim_secondary_slot( } else { None } - } else if SyncCryptoStore::has_keys( + } else if Keystore::has_keys( &**keystore, &[(authority_id.to_raw_vec(), AuthorityId::ID)], ) { @@ -197,7 +197,7 @@ fn claim_secondary_slot( pub fn claim_slot( slot: Slot, epoch: &Epoch, - keystore: &SyncCryptoStorePtr, + keystore: &KeystorePtr, ) -> Option<(PreDigest, AuthorityId)> { let authorities = epoch .authorities @@ -213,7 +213,7 @@ pub fn claim_slot( pub fn claim_slot_using_keys( slot: Slot, epoch: &Epoch, - keystore: &SyncCryptoStorePtr, + keystore: &KeystorePtr, keys: &[(AuthorityId, usize)], ) -> Option<(PreDigest, AuthorityId)> { claim_primary_slot(slot, epoch, epoch.config.c, keystore, keys).or_else(|| { @@ -241,7 +241,7 @@ fn claim_primary_slot( slot: Slot, epoch: &Epoch, c: (u64, u64), - keystore: &SyncCryptoStorePtr, + keystore: &KeystorePtr, keys: &[(AuthorityId, usize)], ) -> Option<(PreDigest, AuthorityId)> { let Epoch { authorities, randomness, mut epoch_index, .. } = epoch; @@ -254,7 +254,7 @@ 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); - let result = SyncCryptoStore::sr25519_vrf_sign( + let result = Keystore::sr25519_vrf_sign( &**keystore, AuthorityId::ID, authority_id.as_ref(), @@ -294,8 +294,8 @@ mod tests { #[test] fn claim_secondary_plain_slot_works() { - let keystore: SyncCryptoStorePtr = Arc::new(LocalKeystore::in_memory()); - let valid_public_key = SyncCryptoStore::sr25519_generate_new( + let keystore: KeystorePtr = Arc::new(LocalKeystore::in_memory()); + let valid_public_key = Keystore::sr25519_generate_new( &*keystore, AuthorityId::ID, Some(sp_core::crypto::DEV_PHRASE), diff --git a/client/consensus/babe/src/lib.rs b/client/consensus/babe/src/lib.rs index 1d42057a36b23..621aac391630b 100644 --- a/client/consensus/babe/src/lib.rs +++ b/client/consensus/babe/src/lib.rs @@ -119,7 +119,7 @@ use sp_consensus_babe::inherents::BabeInherentData; use sp_consensus_slots::Slot; use sp_core::{crypto::ByteArray, ExecutionContext}; use sp_inherents::{CreateInherentDataProviders, InherentData, InherentDataProvider}; -use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; +use sp_keystore::{Keystore, KeystorePtr}; use sp_runtime::{ generic::OpaqueDigestItemId, traits::{Block as BlockT, Header, NumberFor, SaturatedConversion, Zero}, @@ -404,7 +404,7 @@ where /// Parameters for BABE. pub struct BabeParams { /// The keystore that manages the keys of the node. - pub keystore: SyncCryptoStorePtr, + pub keystore: KeystorePtr, /// The client to use pub client: Arc, @@ -711,7 +711,7 @@ struct BabeSlotWorker { justification_sync_link: L, force_authoring: bool, backoff_authoring_blocks: Option, - keystore: SyncCryptoStorePtr, + keystore: KeystorePtr, epoch_changes: SharedEpochChanges, slot_notification_sinks: SlotNotificationSinks, config: BabeConfiguration, @@ -834,7 +834,7 @@ where // add it to a digest item. let public_type_pair = public.clone().into(); let public = public.to_raw_vec(); - let signature = SyncCryptoStore::sign_with( + let signature = Keystore::sign_with( &*self.keystore, ::ID, &public_type_pair, diff --git a/client/consensus/babe/src/tests.rs b/client/consensus/babe/src/tests.rs index 25f1f87235702..4ac15bf2634d7 100644 --- a/client/consensus/babe/src/tests.rs +++ b/client/consensus/babe/src/tests.rs @@ -41,8 +41,7 @@ use sp_consensus_vrf::schnorrkel::VRFOutput; use sp_core::crypto::Pair; use sp_keyring::Sr25519Keyring; use sp_keystore::{ - testing::KeyStore as TestKeyStore, vrf::make_transcript as transcript_from_data, - SyncCryptoStore, + testing::MemoryKeystore, vrf::make_transcript as transcript_from_data, Keystore, }; use sp_runtime::{ generic::{Digest, DigestItem}, @@ -369,9 +368,9 @@ async 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())) +fn create_keystore(authority: Sr25519Keyring) -> KeystorePtr { + let keystore = Arc::new(MemoryKeystore::new()); + Keystore::sr25519_generate_new(&*keystore, BABE, Some(&authority.to_seed())) .expect("Generates authority key"); keystore } @@ -638,7 +637,7 @@ fn claim_vrf_check() { v => panic!("Unexpected pre-digest variant {:?}", v), }; let transcript = make_transcript_data(&epoch.randomness.clone(), 0.into(), epoch.epoch_index); - let sign = SyncCryptoStore::sr25519_vrf_sign(&*keystore, AuthorityId::ID, &public, transcript) + let sign = Keystore::sr25519_vrf_sign(&*keystore, AuthorityId::ID, &public, transcript) .unwrap() .unwrap(); assert_eq!(pre_digest.vrf_output, VRFOutput(sign.output)); @@ -649,7 +648,7 @@ fn claim_vrf_check() { v => panic!("Unexpected pre-digest variant {:?}", v), }; let transcript = make_transcript_data(&epoch.randomness.clone(), 1.into(), epoch.epoch_index); - let sign = SyncCryptoStore::sr25519_vrf_sign(&*keystore, AuthorityId::ID, &public, transcript) + let sign = Keystore::sr25519_vrf_sign(&*keystore, AuthorityId::ID, &public, transcript) .unwrap() .unwrap(); assert_eq!(pre_digest.vrf_output, VRFOutput(sign.output)); @@ -662,7 +661,7 @@ fn claim_vrf_check() { }; let fixed_epoch = epoch.clone_for_slot(slot); let transcript = make_transcript_data(&epoch.randomness.clone(), slot, fixed_epoch.epoch_index); - let sign = SyncCryptoStore::sr25519_vrf_sign(&*keystore, AuthorityId::ID, &public, transcript) + let sign = Keystore::sr25519_vrf_sign(&*keystore, AuthorityId::ID, &public, transcript) .unwrap() .unwrap(); assert_eq!(fixed_epoch.epoch_index, 11); @@ -676,7 +675,7 @@ fn claim_vrf_check() { }; let fixed_epoch = epoch.clone_for_slot(slot); let transcript = make_transcript_data(&epoch.randomness.clone(), slot, fixed_epoch.epoch_index); - let sign = SyncCryptoStore::sr25519_vrf_sign(&*keystore, AuthorityId::ID, &public, transcript) + let sign = Keystore::sr25519_vrf_sign(&*keystore, AuthorityId::ID, &public, transcript) .unwrap() .unwrap(); assert_eq!(fixed_epoch.epoch_index, 11); diff --git a/client/consensus/beefy/src/communication/gossip.rs b/client/consensus/beefy/src/communication/gossip.rs index e49382251e846..4bbd7a7f68d5c 100644 --- a/client/consensus/beefy/src/communication/gossip.rs +++ b/client/consensus/beefy/src/communication/gossip.rs @@ -245,7 +245,7 @@ where mod tests { use sc_keystore::LocalKeystore; use sc_network_test::Block; - use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; + use sp_keystore::{Keystore, KeystorePtr}; use crate::keystore::BeefyKeystore; use sp_consensus_beefy::{ @@ -306,8 +306,8 @@ mod tests { } 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 store: KeystorePtr = std::sync::Arc::new(LocalKeystore::in_memory()); + Keystore::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() diff --git a/client/consensus/beefy/src/keystore.rs b/client/consensus/beefy/src/keystore.rs index 421f7149018c8..596e8f2eb9c6d 100644 --- a/client/consensus/beefy/src/keystore.rs +++ b/client/consensus/beefy/src/keystore.rs @@ -18,7 +18,7 @@ use sp_application_crypto::RuntimeAppPublic; use sp_core::keccak_256; -use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; +use sp_keystore::{Keystore, KeystorePtr}; use log::warn; @@ -33,9 +33,9 @@ use crate::{error, LOG_TARGET}; pub(crate) type BeefySignatureHasher = sp_runtime::traits::Keccak256; /// A BEEFY specific keystore implemented as a `Newtype`. This is basically a -/// wrapper around [`sp_keystore::SyncCryptoStore`] and allows to customize +/// wrapper around [`sp_keystore::Keystore`] and allows to customize /// common cryptographic functionality. -pub(crate) struct BeefyKeystore(Option); +pub(crate) struct BeefyKeystore(Option); impl BeefyKeystore { /// Check if the keystore contains a private key for one of the public keys @@ -50,7 +50,7 @@ impl BeefyKeystore { // 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)])) + .filter(|k| Keystore::has_keys(&*store, &[(k.to_raw_vec(), KEY_TYPE)])) .cloned() .collect(); @@ -77,7 +77,7 @@ impl BeefyKeystore { let msg = keccak_256(message); let public = public.as_ref(); - let sig = SyncCryptoStore::ecdsa_sign_prehashed(&*store, KEY_TYPE, public, &msg) + let sig = Keystore::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()))?; @@ -94,7 +94,7 @@ impl BeefyKeystore { 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) + let pk: Vec = Keystore::ecdsa_public_keys(&*store, KEY_TYPE) .drain(..) .map(Public::from) .collect(); @@ -110,8 +110,8 @@ impl BeefyKeystore { } } -impl From> for BeefyKeystore { - fn from(store: Option) -> BeefyKeystore { +impl From> for BeefyKeystore { + fn from(store: Option) -> BeefyKeystore { BeefyKeystore(store) } } @@ -128,7 +128,7 @@ pub mod tests { use super::*; use crate::error::Error; - fn keystore() -> SyncCryptoStorePtr { + fn keystore() -> KeystorePtr { Arc::new(LocalKeystore::in_memory()) } @@ -198,7 +198,7 @@ pub mod tests { let store = keystore(); let alice: crypto::Public = - SyncCryptoStore::ecdsa_generate_new(&*store, KEY_TYPE, Some(&Keyring::Alice.to_seed())) + Keystore::ecdsa_generate_new(&*store, KEY_TYPE, Some(&Keyring::Alice.to_seed())) .ok() .unwrap() .into(); @@ -224,7 +224,7 @@ pub mod tests { let store = keystore(); let alice: crypto::Public = - SyncCryptoStore::ecdsa_generate_new(&*store, KEY_TYPE, Some(&Keyring::Alice.to_seed())) + Keystore::ecdsa_generate_new(&*store, KEY_TYPE, Some(&Keyring::Alice.to_seed())) .ok() .unwrap() .into(); @@ -243,10 +243,9 @@ pub mod tests { fn sign_error() { let store = keystore(); - let _ = - SyncCryptoStore::ecdsa_generate_new(&*store, KEY_TYPE, Some(&Keyring::Bob.to_seed())) - .ok() - .unwrap(); + let _ = Keystore::ecdsa_generate_new(&*store, KEY_TYPE, Some(&Keyring::Bob.to_seed())) + .ok() + .unwrap(); let store: BeefyKeystore = Some(store).into(); @@ -276,7 +275,7 @@ pub mod tests { let store = keystore(); let alice: crypto::Public = - SyncCryptoStore::ecdsa_generate_new(&*store, KEY_TYPE, Some(&Keyring::Alice.to_seed())) + Keystore::ecdsa_generate_new(&*store, KEY_TYPE, Some(&Keyring::Alice.to_seed())) .ok() .unwrap() .into(); @@ -302,7 +301,7 @@ pub mod tests { let store = keystore(); let add_key = |key_type, seed: Option<&str>| { - SyncCryptoStore::ecdsa_generate_new(&*store, key_type, seed).unwrap() + Keystore::ecdsa_generate_new(&*store, key_type, seed).unwrap() }; // test keys diff --git a/client/consensus/beefy/src/lib.rs b/client/consensus/beefy/src/lib.rs index d632f58332a77..b84fa45e7e2f3 100644 --- a/client/consensus/beefy/src/lib.rs +++ b/client/consensus/beefy/src/lib.rs @@ -49,7 +49,7 @@ use sp_consensus_beefy::{ crypto::AuthorityId, BeefyApi, MmrRootHash, PayloadProvider, ValidatorSet, BEEFY_ENGINE_ID, GENESIS_AUTHORITY_SET_ID, }; -use sp_keystore::SyncCryptoStorePtr; +use sp_keystore::KeystorePtr; use sp_mmr_primitives::MmrApi; use sp_runtime::traits::{Block, Zero}; use std::{collections::VecDeque, marker::PhantomData, sync::Arc}; @@ -197,7 +197,7 @@ pub struct BeefyParams { /// Runtime Api Provider pub runtime: Arc, /// Local key store - pub key_store: Option, + pub key_store: Option, /// BEEFY voter network params pub network_params: BeefyNetworkParams, /// Minimal delta between blocks, BEEFY should vote for diff --git a/client/consensus/beefy/src/tests.rs b/client/consensus/beefy/src/tests.rs index 629f144246d7f..9a3653f7cc549 100644 --- a/client/consensus/beefy/src/tests.rs +++ b/client/consensus/beefy/src/tests.rs @@ -54,7 +54,7 @@ use sp_consensus_beefy::{ VersionedFinalityProof, BEEFY_ENGINE_ID, KEY_TYPE as BeefyKeyType, }; use sp_core::H256; -use sp_keystore::{testing::KeyStore as TestKeystore, SyncCryptoStore, SyncCryptoStorePtr}; +use sp_keystore::{testing::MemoryKeystore, Keystore, KeystorePtr}; use sp_mmr_primitives::{Error as MmrError, MmrApi}; use sp_runtime::{ codec::Encode, @@ -339,9 +339,9 @@ pub(crate) fn make_beefy_ids(keys: &[BeefyKeyring]) -> Vec { keys.iter().map(|&key| key.public().into()).collect() } -pub(crate) fn create_beefy_keystore(authority: BeefyKeyring) -> SyncCryptoStorePtr { - let keystore = Arc::new(TestKeystore::new()); - SyncCryptoStore::ecdsa_generate_new(&*keystore, BeefyKeyType, Some(&authority.to_seed())) +pub(crate) fn create_beefy_keystore(authority: BeefyKeyring) -> KeystorePtr { + let keystore = Arc::new(MemoryKeystore::new()); + Keystore::ecdsa_generate_new(&*keystore, BeefyKeyType, Some(&authority.to_seed())) .expect("Creates authority key"); keystore } diff --git a/client/consensus/grandpa/src/communication/mod.rs b/client/consensus/grandpa/src/communication/mod.rs index 3896bc36031ba..81365c20b1ebe 100644 --- a/client/consensus/grandpa/src/communication/mod.rs +++ b/client/consensus/grandpa/src/communication/mod.rs @@ -49,7 +49,7 @@ use parity_scale_codec::{Decode, Encode}; use sc_network::{NetworkBlock, NetworkSyncForkRequest, ReputationChange}; use sc_network_gossip::{GossipEngine, Network as GossipNetwork}; use sc_telemetry::{telemetry, TelemetryHandle, CONSENSUS_DEBUG, CONSENSUS_INFO}; -use sp_keystore::SyncCryptoStorePtr; +use sp_keystore::KeystorePtr; use sp_runtime::traits::{Block as BlockT, Hash as HashT, Header as HeaderT, NumberFor}; use crate::{ @@ -136,7 +136,7 @@ mod benefit { /// A type that ties together our local authority id and a keystore where it is /// available for signing. -pub struct LocalIdKeystore((AuthorityId, SyncCryptoStorePtr)); +pub struct LocalIdKeystore((AuthorityId, KeystorePtr)); impl LocalIdKeystore { /// Returns a reference to our local authority id. @@ -145,13 +145,13 @@ impl LocalIdKeystore { } /// Returns a reference to the keystore. - fn keystore(&self) -> SyncCryptoStorePtr { + fn keystore(&self) -> KeystorePtr { (self.0).1.clone() } } -impl From<(AuthorityId, SyncCryptoStorePtr)> for LocalIdKeystore { - fn from(inner: (AuthorityId, SyncCryptoStorePtr)) -> LocalIdKeystore { +impl From<(AuthorityId, KeystorePtr)> for LocalIdKeystore { + fn from(inner: (AuthorityId, KeystorePtr)) -> LocalIdKeystore { LocalIdKeystore(inner) } } diff --git a/client/consensus/grandpa/src/lib.rs b/client/consensus/grandpa/src/lib.rs index 2baa135081c55..6b3730fc7f476 100644 --- a/client/consensus/grandpa/src/lib.rs +++ b/client/consensus/grandpa/src/lib.rs @@ -79,7 +79,7 @@ use sp_consensus_grandpa::{ AuthorityList, AuthoritySignature, SetId, CLIENT_LOG_TARGET as LOG_TARGET, }; use sp_core::{crypto::ByteArray, traits::CallContext}; -use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; +use sp_keystore::{Keystore, KeystorePtr}; use sp_runtime::{ generic::BlockId, traits::{Block as BlockT, NumberFor, Zero}, @@ -228,7 +228,7 @@ pub struct Config { /// Some local identifier of the voter. pub name: Option, /// The keystore that manages the keys of this node. - pub keystore: Option, + pub keystore: Option, /// TelemetryHandle instance. pub telemetry: Option, /// Chain specific GRANDPA protocol name. See [`crate::protocol_standard_name`]. @@ -623,7 +623,7 @@ fn global_communication( voters: &Arc>, client: Arc, network: &NetworkBridge, - keystore: Option<&SyncCryptoStorePtr>, + keystore: Option<&KeystorePtr>, metrics: Option, ) -> ( impl Stream< @@ -1136,14 +1136,12 @@ where /// available. fn local_authority_id( voters: &VoterSet, - keystore: Option<&SyncCryptoStorePtr>, + keystore: Option<&KeystorePtr>, ) -> Option { keystore.and_then(|keystore| { voters .iter() - .find(|(p, _)| { - SyncCryptoStore::has_keys(&**keystore, &[(p.to_raw_vec(), AuthorityId::ID)]) - }) + .find(|(p, _)| Keystore::has_keys(&**keystore, &[(p.to_raw_vec(), AuthorityId::ID)])) .map(|(p, _)| p.clone()) }) } diff --git a/client/consensus/grandpa/src/observer.rs b/client/consensus/grandpa/src/observer.rs index 53672c1f02225..8541baa822bb4 100644 --- a/client/consensus/grandpa/src/observer.rs +++ b/client/consensus/grandpa/src/observer.rs @@ -33,7 +33,7 @@ use sc_utils::mpsc::TracingUnboundedReceiver; use sp_blockchain::HeaderMetadata; use sp_consensus::SelectChain; use sp_consensus_grandpa::AuthorityId; -use sp_keystore::SyncCryptoStorePtr; +use sp_keystore::KeystorePtr; use sp_runtime::traits::{Block as BlockT, NumberFor}; use crate::{ @@ -220,7 +220,7 @@ struct ObserverWork, S: SyncingT> { client: Arc, network: NetworkBridge, persistent_data: PersistentData, - keystore: Option, + keystore: Option, voter_commands_rx: TracingUnboundedReceiver>>, justification_sender: Option>, telemetry: Option, @@ -240,7 +240,7 @@ where client: Arc, network: NetworkBridge, persistent_data: PersistentData, - keystore: Option, + keystore: Option, voter_commands_rx: TracingUnboundedReceiver>>, justification_sender: Option>, telemetry: Option, diff --git a/client/consensus/grandpa/src/tests.rs b/client/consensus/grandpa/src/tests.rs index f5e5c45e74207..6f19ca7391e65 100644 --- a/client/consensus/grandpa/src/tests.rs +++ b/client/consensus/grandpa/src/tests.rs @@ -40,7 +40,7 @@ use sp_consensus_grandpa::{ }; use sp_core::H256; use sp_keyring::Ed25519Keyring; -use sp_keystore::{testing::KeyStore as TestKeyStore, SyncCryptoStore, SyncCryptoStorePtr}; +use sp_keystore::{testing::MemoryKeystore, Keystore, KeystorePtr}; use sp_runtime::{ codec::Encode, generic::{BlockId, DigestItem}, @@ -280,9 +280,9 @@ fn make_ids(keys: &[Ed25519Keyring]) -> AuthorityList { keys.iter().map(|&key| key.public().into()).map(|id| (id, 1)).collect() } -fn create_keystore(authority: Ed25519Keyring) -> SyncCryptoStorePtr { - let keystore = Arc::new(TestKeyStore::new()); - SyncCryptoStore::ed25519_generate_new(&*keystore, GRANDPA, Some(&authority.to_seed())) +fn create_keystore(authority: Ed25519Keyring) -> KeystorePtr { + let keystore = Arc::new(MemoryKeystore::new()); + Keystore::ed25519_generate_new(&*keystore, GRANDPA, Some(&authority.to_seed())) .expect("Creates authority key"); keystore } @@ -1376,7 +1376,7 @@ type TestEnvironment = fn test_environment_with_select_chain( link: &TestLinkHalf, - keystore: Option, + keystore: Option, network_service: N, sync_service: S, select_chain: SC, @@ -1428,7 +1428,7 @@ where fn test_environment( link: &TestLinkHalf, - keystore: Option, + keystore: Option, network_service: N, sync_service: S, voting_rule: VR, diff --git a/client/consensus/manual-seal/src/consensus/babe.rs b/client/consensus/manual-seal/src/consensus/babe.rs index 3d21fd73d95ae..2485bd603e785 100644 --- a/client/consensus/manual-seal/src/consensus/babe.rs +++ b/client/consensus/manual-seal/src/consensus/babe.rs @@ -29,7 +29,7 @@ use sc_consensus_babe::{ use sc_consensus_epochs::{ descendent_query, EpochHeader, SharedEpochChanges, ViableEpochDescriptor, }; -use sp_keystore::SyncCryptoStorePtr; +use sp_keystore::KeystorePtr; use std::{marker::PhantomData, sync::Arc}; use sc_consensus::{BlockImportParams, ForkChoiceStrategy, Verifier}; @@ -53,7 +53,7 @@ use sp_timestamp::TimestampInherentData; /// Intended for use with BABE runtimes. pub struct BabeConsensusDataProvider { /// shared reference to keystore - keystore: SyncCryptoStorePtr, + keystore: KeystorePtr, /// Shared reference to the client. client: Arc, @@ -143,7 +143,7 @@ where { pub fn new( client: Arc, - keystore: SyncCryptoStorePtr, + keystore: KeystorePtr, epoch_changes: SharedEpochChanges, authorities: Vec<(AuthorityId, BabeAuthorityWeight)>, ) -> Result { diff --git a/client/keystore/src/local.rs b/client/keystore/src/local.rs index cd55739a9fac3..18ee58b8719b9 100644 --- a/client/keystore/src/local.rs +++ b/client/keystore/src/local.rs @@ -17,7 +17,6 @@ // //! Local keystore implementation -use async_trait::async_trait; use parking_lot::RwLock; use sp_application_crypto::{ecdsa, ed25519, sr25519, AppKey, AppPair, IsWrappedBy}; use sp_core::{ @@ -29,10 +28,10 @@ use sp_core::{ }; use sp_keystore::{ vrf::{make_transcript, VRFSignature, VRFTranscriptData}, - CryptoStore, Error as TraitError, SyncCryptoStore, SyncCryptoStorePtr, + Error as TraitError, Keystore, KeystorePtr, }; use std::{ - collections::{HashMap, HashSet}, + collections::HashMap, fs::{self, File}, io::Write, path::PathBuf, @@ -69,101 +68,7 @@ impl LocalKeystore { } } -#[async_trait] -impl CryptoStore for LocalKeystore { - async fn keys( - &self, - id: KeyTypeId, - ) -> std::result::Result, TraitError> { - SyncCryptoStore::keys(self, id) - } - - async fn sr25519_public_keys(&self, id: KeyTypeId) -> Vec { - SyncCryptoStore::sr25519_public_keys(self, id) - } - - async fn sr25519_generate_new( - &self, - id: KeyTypeId, - seed: Option<&str>, - ) -> std::result::Result { - SyncCryptoStore::sr25519_generate_new(self, id, seed) - } - - async fn ed25519_public_keys(&self, id: KeyTypeId) -> Vec { - SyncCryptoStore::ed25519_public_keys(self, id) - } - - async fn ed25519_generate_new( - &self, - id: KeyTypeId, - seed: Option<&str>, - ) -> std::result::Result { - SyncCryptoStore::ed25519_generate_new(self, id, seed) - } - - async fn ecdsa_public_keys(&self, id: KeyTypeId) -> Vec { - SyncCryptoStore::ecdsa_public_keys(self, id) - } - - async fn ecdsa_generate_new( - &self, - id: KeyTypeId, - seed: Option<&str>, - ) -> std::result::Result { - SyncCryptoStore::ecdsa_generate_new(self, id, seed) - } - - async fn insert_unknown( - &self, - id: KeyTypeId, - suri: &str, - public: &[u8], - ) -> std::result::Result<(), ()> { - SyncCryptoStore::insert_unknown(self, id, suri, public) - } - - async fn has_keys(&self, public_keys: &[(Vec, KeyTypeId)]) -> bool { - SyncCryptoStore::has_keys(self, public_keys) - } - - async fn supported_keys( - &self, - id: KeyTypeId, - keys: Vec, - ) -> std::result::Result, TraitError> { - SyncCryptoStore::supported_keys(self, id, keys) - } - - async fn sign_with( - &self, - id: KeyTypeId, - key: &CryptoTypePublicPair, - msg: &[u8], - ) -> std::result::Result>, TraitError> { - SyncCryptoStore::sign_with(self, id, key, msg) - } - - async fn sr25519_vrf_sign( - &self, - key_type: KeyTypeId, - public: &sr25519::Public, - transcript_data: VRFTranscriptData, - ) -> std::result::Result, TraitError> { - SyncCryptoStore::sr25519_vrf_sign(self, key_type, public, transcript_data) - } - - async fn ecdsa_sign_prehashed( - &self, - id: KeyTypeId, - public: &ecdsa::Public, - msg: &[u8; 32], - ) -> std::result::Result, TraitError> { - SyncCryptoStore::ecdsa_sign_prehashed(self, id, public, msg) - } -} - -impl SyncCryptoStore for LocalKeystore { +impl Keystore for LocalKeystore { fn keys(&self, id: KeyTypeId) -> std::result::Result, TraitError> { let raw_keys = self.0.read().raw_public_keys(id)?; Ok(raw_keys.into_iter().fold(Vec::new(), |mut v, k| { @@ -174,15 +79,6 @@ impl SyncCryptoStore for LocalKeystore { })) } - fn supported_keys( - &self, - id: KeyTypeId, - keys: Vec, - ) -> std::result::Result, TraitError> { - let all_keys = SyncCryptoStore::keys(self, id)?.into_iter().collect::>(); - Ok(keys.into_iter().filter(|key| all_keys.contains(key)).collect::>()) - } - fn sign_with( &self, id: KeyTypeId, @@ -308,13 +204,13 @@ impl SyncCryptoStore for LocalKeystore { Ok(pair.public()) } - fn insert_unknown( + fn insert( &self, key_type: KeyTypeId, suri: &str, public: &[u8], ) -> std::result::Result<(), ()> { - self.0.write().insert_unknown(key_type, suri, public).map_err(|_| ()) + self.0.write().insert(key_type, suri, public).map_err(|_| ()) } fn has_keys(&self, public_keys: &[(Vec, KeyTypeId)]) -> bool { @@ -352,14 +248,8 @@ impl SyncCryptoStore for LocalKeystore { } } -impl Into for LocalKeystore { - fn into(self) -> SyncCryptoStorePtr { - Arc::new(self) - } -} - -impl Into> for LocalKeystore { - fn into(self) -> Arc { +impl Into for LocalKeystore { + fn into(self) -> KeystorePtr { Arc::new(self) } } @@ -414,7 +304,7 @@ impl KeystoreInner { /// Insert a new key with anonymous crypto. /// /// Places it into the file system store, if a path is configured. - fn insert_unknown(&self, key_type: KeyTypeId, suri: &str, public: &[u8]) -> Result<()> { + fn insert(&self, key_type: KeyTypeId, suri: &str, public: &[u8]) -> Result<()> { if let Some(path) = self.key_file_path(public, key_type) { Self::write_to_file(path, suri)?; } @@ -614,12 +504,9 @@ mod tests { let key: ed25519::AppPair = store.0.write().generate().unwrap(); let key2 = ed25519::Pair::generate().0; - assert!(!SyncCryptoStore::has_keys( - &store, - &[(key2.public().to_vec(), ed25519::AppPublic::ID)] - )); + assert!(!Keystore::has_keys(&store, &[(key2.public().to_vec(), ed25519::AppPublic::ID)])); - assert!(!SyncCryptoStore::has_keys( + assert!(!Keystore::has_keys( &store, &[ (key2.public().to_vec(), ed25519::AppPublic::ID), @@ -627,10 +514,7 @@ mod tests { ], )); - assert!(SyncCryptoStore::has_keys( - &store, - &[(key.public().to_raw_vec(), ed25519::AppPublic::ID)] - )); + assert!(Keystore::has_keys(&store, &[(key.public().to_raw_vec(), ed25519::AppPublic::ID)])); } #[test] @@ -723,7 +607,7 @@ mod tests { let key_pair = sr25519::AppPair::from_string(secret_uri, None).expect("Generates key pair"); store - .insert_unknown(SR25519, secret_uri, key_pair.public().as_ref()) + .insert(SR25519, secret_uri, key_pair.public().as_ref()) .expect("Inserts unknown key"); let store_key_pair = store @@ -742,7 +626,7 @@ mod tests { 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()); + assert!(Keystore::sr25519_public_keys(&store, SR25519).is_empty()); } #[test] @@ -750,23 +634,23 @@ mod tests { let temp_dir = TempDir::new().unwrap(); let store = LocalKeystore::open(temp_dir.path(), None).unwrap(); let _alice_tmp_key = - SyncCryptoStore::sr25519_generate_new(&store, TEST_KEY_TYPE, Some("//Alice")).unwrap(); + Keystore::sr25519_generate_new(&store, TEST_KEY_TYPE, Some("//Alice")).unwrap(); - assert_eq!(SyncCryptoStore::sr25519_public_keys(&store, TEST_KEY_TYPE).len(), 1); + assert_eq!(Keystore::sr25519_public_keys(&store, TEST_KEY_TYPE).len(), 1); drop(store); let store = LocalKeystore::open(temp_dir.path(), None).unwrap(); - assert_eq!(SyncCryptoStore::sr25519_public_keys(&store, TEST_KEY_TYPE).len(), 0); + assert_eq!(Keystore::sr25519_public_keys(&store, TEST_KEY_TYPE).len(), 0); } #[test] fn generate_can_be_fetched_in_memory() { let store = LocalKeystore::in_memory(); - SyncCryptoStore::sr25519_generate_new(&store, TEST_KEY_TYPE, Some("//Alice")).unwrap(); + Keystore::sr25519_generate_new(&store, TEST_KEY_TYPE, Some("//Alice")).unwrap(); - assert_eq!(SyncCryptoStore::sr25519_public_keys(&store, TEST_KEY_TYPE).len(), 1); - SyncCryptoStore::sr25519_generate_new(&store, TEST_KEY_TYPE, None).unwrap(); - assert_eq!(SyncCryptoStore::sr25519_public_keys(&store, TEST_KEY_TYPE).len(), 2); + assert_eq!(Keystore::sr25519_public_keys(&store, TEST_KEY_TYPE).len(), 1); + Keystore::sr25519_generate_new(&store, TEST_KEY_TYPE, None).unwrap(); + assert_eq!(Keystore::sr25519_public_keys(&store, TEST_KEY_TYPE).len(), 2); } #[test] @@ -777,7 +661,7 @@ mod tests { 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 public = Keystore::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(); diff --git a/client/rpc-api/src/author/error.rs b/client/rpc-api/src/author/error.rs index 7ca96bbab7f19..8149a1f8d1afe 100644 --- a/client/rpc-api/src/author/error.rs +++ b/client/rpc-api/src/author/error.rs @@ -47,7 +47,7 @@ pub enum Error { BadKeyType, /// Some random issue with the key store. Shouldn't happen. #[error("The key store is unavailable")] - KeyStoreUnavailable, + KeystoreUnavailable, /// Invalid session keys encoding. #[error("Session keys are not encoded correctly")] InvalidSessionKeys, diff --git a/client/rpc/src/author/mod.rs b/client/rpc/src/author/mod.rs index 2bb88352eb2e5..9752a32b17c67 100644 --- a/client/rpc/src/author/mod.rs +++ b/client/rpc/src/author/mod.rs @@ -40,7 +40,7 @@ use sc_transaction_pool_api::{ use sp_api::ProvideRuntimeApi; use sp_blockchain::HeaderBackend; use sp_core::Bytes; -use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; +use sp_keystore::{Keystore, KeystorePtr}; use sp_runtime::{generic, traits::Block as BlockT}; use sp_session::SessionKeys; @@ -55,7 +55,7 @@ pub struct Author { /// Transactions pool pool: Arc

, /// The key store. - keystore: SyncCryptoStorePtr, + keystore: KeystorePtr, /// Whether to deny unsafe calls deny_unsafe: DenyUnsafe, /// Executor to spawn subscriptions. @@ -67,7 +67,7 @@ impl Author { pub fn new( client: Arc, pool: Arc

, - keystore: SyncCryptoStorePtr, + keystore: KeystorePtr, deny_unsafe: DenyUnsafe, executor: SubscriptionTaskExecutor, ) -> Self { @@ -112,8 +112,8 @@ where self.deny_unsafe.check_if_safe()?; let key_type = key_type.as_str().try_into().map_err(|_| Error::BadKeyType)?; - SyncCryptoStore::insert_unknown(&*self.keystore, key_type, &suri, &public[..]) - .map_err(|_| Error::KeyStoreUnavailable)?; + Keystore::insert(&*self.keystore, key_type, &suri, &public[..]) + .map_err(|_| Error::KeystoreUnavailable)?; Ok(()) } @@ -139,14 +139,14 @@ where .map_err(|e| Error::Client(Box::new(e)))? .ok_or(Error::InvalidSessionKeys)?; - Ok(SyncCryptoStore::has_keys(&*self.keystore, &keys)) + Ok(Keystore::has_keys(&*self.keystore, &keys)) } 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)])) + Ok(Keystore::has_keys(&*self.keystore, &[(public_key.to_vec(), key_type)])) } fn pending_extrinsics(&self) -> RpcResult> { diff --git a/client/rpc/src/author/tests.rs b/client/rpc/src/author/tests.rs index bf880cfbcfe9b..209673fce2602 100644 --- a/client/rpc/src/author/tests.rs +++ b/client/rpc/src/author/tests.rs @@ -36,7 +36,7 @@ use sp_core::{ testing::{ED25519, SR25519}, H256, }; -use sp_keystore::testing::KeyStore; +use sp_keystore::testing::MemoryKeystore; use std::sync::Arc; use substrate_test_runtime_client::{ self, @@ -58,13 +58,13 @@ type FullTransactionPool = BasicPool, Block>, Block struct TestSetup { pub client: Arc>, - pub keystore: Arc, + pub keystore: Arc, pub pool: Arc, } impl Default for TestSetup { fn default() -> Self { - let keystore = Arc::new(KeyStore::new()); + let keystore = Arc::new(MemoryKeystore::new()); let client_builder = substrate_test_runtime_client::TestClientBuilder::new(); let client = Arc::new(client_builder.set_keystore(keystore.clone()).build()); @@ -225,7 +225,7 @@ async fn author_should_insert_key() { keypair.public().0.to_vec().into(), ); api.call::<_, ()>("author_insertKey", params).await.unwrap(); - let pubkeys = SyncCryptoStore::keys(&*setup.keystore, ED25519).unwrap(); + let pubkeys = Keystore::keys(&*setup.keystore, ED25519).unwrap(); assert!( pubkeys.contains(&CryptoTypePublicPair(ed25519::CRYPTO_ID, keypair.public().to_raw_vec())) @@ -240,8 +240,8 @@ async fn author_should_rotate_keys() { let new_pubkeys: Bytes = api.call("author_rotateKeys", EmptyParams::new()).await.unwrap(); let session_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(); + let ed25519_pubkeys = Keystore::keys(&*setup.keystore, ED25519).unwrap(); + let sr25519_pubkeys = Keystore::keys(&*setup.keystore, SR25519).unwrap(); assert!(ed25519_pubkeys .contains(&CryptoTypePublicPair(ed25519::CRYPTO_ID, session_keys.ed25519.to_raw_vec()))); assert!(sr25519_pubkeys diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index 91ef65cf134e4..034d056d6f66f 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -67,7 +67,7 @@ use sp_consensus::block_validation::{ BlockAnnounceValidator, Chain, DefaultBlockAnnounceValidator, }; use sp_core::traits::{CodeExecutor, SpawnNamed}; -use sp_keystore::{CryptoStore, SyncCryptoStore, SyncCryptoStorePtr}; +use sp_keystore::{Keystore, KeystorePtr}; use sp_runtime::traits::{Block as BlockT, BlockIdTo, NumberFor, Zero}; use std::{str::FromStr, sync::Arc, time::SystemTime}; @@ -85,26 +85,22 @@ pub type TFullCallExecutor = type TFullParts = (TFullClient, Arc>, KeystoreContainer, TaskManager); -trait AsCryptoStoreRef { - fn keystore_ref(&self) -> Arc; - fn sync_keystore_ref(&self) -> Arc; +trait AsKeystoreRef { + fn keystore_ref(&self) -> Arc; } -impl AsCryptoStoreRef for Arc +impl AsKeystoreRef for Arc where - T: CryptoStore + SyncCryptoStore + 'static, + T: Keystore + 'static, { - fn keystore_ref(&self) -> Arc { - self.clone() - } - fn sync_keystore_ref(&self) -> Arc { + fn keystore_ref(&self) -> Arc { self.clone() } } /// Construct and hold different layers of Keystore wrappers pub struct KeystoreContainer { - remote: Option>, + remote: Option>, local: Arc, } @@ -127,13 +123,13 @@ impl KeystoreContainer { /// stick around. pub fn set_remote_keystore(&mut self, remote: Arc) where - T: CryptoStore + SyncCryptoStore + 'static, + T: Keystore + 'static, { self.remote = Some(Box::new(remote)) } - /// Returns an adapter to the asynchronous keystore that implements `CryptoStore` - pub fn keystore(&self) -> Arc { + /// Returns an adapter to a `Keystore` implementation. + pub fn keystore(&self) -> Arc { if let Some(c) = self.remote.as_ref() { c.keystore_ref() } else { @@ -141,15 +137,6 @@ impl KeystoreContainer { } } - /// Returns the synchronous keystore wrapper - pub fn sync_keystore(&self) -> SyncCryptoStorePtr { - if let Some(c) = self.remote.as_ref() { - c.sync_keystore_ref() - } else { - self.local.clone() as SyncCryptoStorePtr - } - } - /// Returns the local keystore if available /// /// The function will return None if the available keystore is not a local keystore. @@ -234,7 +221,7 @@ where let client = { let extensions = sc_client_api::execution_extensions::ExecutionExtensions::new( config.execution_strategies.clone(), - Some(keystore_container.sync_keystore()), + Some(keystore_container.keystore()), sc_offchain::OffchainDb::factory_from_backend(&*backend), ); @@ -374,7 +361,7 @@ pub struct SpawnTasksParams<'a, TBl: BlockT, TCl, TExPool, TRpc, Backend> { /// A task manager returned by `new_full_parts`. pub task_manager: &'a mut TaskManager, /// A shared keystore returned by `new_full_parts`. - pub keystore: SyncCryptoStorePtr, + pub keystore: KeystorePtr, /// A shared transaction pool. pub transaction_pool: Arc, /// Builds additional [`RpcModule`]s that should be added to the server @@ -645,7 +632,7 @@ fn gen_rpc_module( spawn_handle: SpawnTaskHandle, client: Arc, transaction_pool: Arc, - keystore: SyncCryptoStorePtr, + keystore: KeystorePtr, system_rpc_tx: TracingUnboundedSender>, config: &Configuration, backend: Arc, diff --git a/client/service/src/client/client.rs b/client/service/src/client/client.rs index 3613cc760f569..d5212021f2d79 100644 --- a/client/service/src/client/client.rs +++ b/client/service/src/client/client.rs @@ -65,7 +65,7 @@ use sp_core::{ traits::SpawnNamed, }; #[cfg(feature = "test-helpers")] -use sp_keystore::SyncCryptoStorePtr; +use sp_keystore::KeystorePtr; use sp_runtime::{ generic::{BlockId, SignedBlock}, traits::{ @@ -161,7 +161,7 @@ pub fn new_in_mem( backend: Arc>, executor: E, genesis_block_builder: G, - keystore: Option, + keystore: Option, prometheus_registry: Option, telemetry: Option, spawn_handle: Box, @@ -224,7 +224,7 @@ pub fn new_with_backend( backend: Arc, executor: E, genesis_block_builder: G, - keystore: Option, + keystore: Option, spawn_handle: Box, prometheus_registry: Option, telemetry: Option, diff --git a/frame/benchmarking/src/baseline.rs b/frame/benchmarking/src/baseline.rs index 11d4ba5011a2f..1f6e9c5a68892 100644 --- a/frame/benchmarking/src/baseline.rs +++ b/frame/benchmarking/src/baseline.rs @@ -160,12 +160,12 @@ 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_keystore::{testing::MemoryKeystore, KeystoreExt, KeystorePtr}; use sp_std::sync::Arc; let t = frame_system::GenesisConfig::default().build_storage::().unwrap(); let mut ext = sp_io::TestExternalities::new(t); - ext.register_extension(KeystoreExt(Arc::new(KeyStore::new()) as SyncCryptoStorePtr)); + ext.register_extension(KeystoreExt(Arc::new(MemoryKeystore::new()) as KeystorePtr)); ext } diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index d74b08243df4b..ba9873f07efee 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -44,7 +44,7 @@ use frame_support::{ use frame_system::{self as system, EventRecord, Phase}; use pretty_assertions::{assert_eq, assert_ne}; use sp_io::hashing::blake2_256; -use sp_keystore::{testing::KeyStore, KeystoreExt}; +use sp_keystore::{testing::MemoryKeystore, KeystoreExt}; use sp_runtime::{ testing::{Header, H256}, traits::{BlakeTwo256, Convert, Hash, IdentityLookup}, @@ -440,7 +440,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.register_extension(KeystoreExt(Arc::new(MemoryKeystore::new()))); ext.execute_with(|| System::set_block_number(1)); ext } diff --git a/frame/examples/offchain-worker/src/tests.rs b/frame/examples/offchain-worker/src/tests.rs index 75a42e872ae52..c513590435252 100644 --- a/frame/examples/offchain-worker/src/tests.rs +++ b/frame/examples/offchain-worker/src/tests.rs @@ -29,7 +29,7 @@ use sp_core::{ }; use std::sync::Arc; -use sp_keystore::{testing::KeyStore, KeystoreExt, SyncCryptoStore}; +use sp_keystore::{testing::MemoryKeystore, Keystore, KeystoreExt}; use sp_runtime::{ testing::{Header, TestXt}, traits::{BlakeTwo256, Extrinsic as ExtrinsicT, IdentifyAccount, IdentityLookup, Verify}, @@ -205,8 +205,8 @@ fn should_submit_signed_transaction_on_chain() { let (offchain, offchain_state) = testing::TestOffchainExt::new(); let (pool, pool_state) = testing::TestTransactionPoolExt::new(); - let keystore = KeyStore::new(); - SyncCryptoStore::sr25519_generate_new( + let keystore = MemoryKeystore::new(); + Keystore::sr25519_generate_new( &keystore, crate::crypto::Public::ID, Some(&format!("{}/hunter1", PHRASE)), @@ -239,16 +239,16 @@ fn should_submit_unsigned_transaction_on_chain_for_any_account() { let (offchain, offchain_state) = testing::TestOffchainExt::new(); let (pool, pool_state) = testing::TestTransactionPoolExt::new(); - let keystore = KeyStore::new(); + let keystore = MemoryKeystore::new(); - SyncCryptoStore::sr25519_generate_new( + Keystore::sr25519_generate_new( &keystore, crate::crypto::Public::ID, Some(&format!("{}/hunter1", PHRASE)), ) .unwrap(); - let public_key = *SyncCryptoStore::sr25519_public_keys(&keystore, crate::crypto::Public::ID) + let public_key = *Keystore::sr25519_public_keys(&keystore, crate::crypto::Public::ID) .get(0) .unwrap(); @@ -298,16 +298,16 @@ fn should_submit_unsigned_transaction_on_chain_for_all_accounts() { let (offchain, offchain_state) = testing::TestOffchainExt::new(); let (pool, pool_state) = testing::TestTransactionPoolExt::new(); - let keystore = KeyStore::new(); + let keystore = MemoryKeystore::new(); - SyncCryptoStore::sr25519_generate_new( + Keystore::sr25519_generate_new( &keystore, crate::crypto::Public::ID, Some(&format!("{}/hunter1", PHRASE)), ) .unwrap(); - let public_key = *SyncCryptoStore::sr25519_public_keys(&keystore, crate::crypto::Public::ID) + let public_key = *Keystore::sr25519_public_keys(&keystore, crate::crypto::Public::ID) .get(0) .unwrap(); @@ -355,7 +355,7 @@ fn should_submit_raw_unsigned_transaction_on_chain() { let (offchain, offchain_state) = testing::TestOffchainExt::new(); let (pool, pool_state) = testing::TestTransactionPoolExt::new(); - let keystore = KeyStore::new(); + let keystore = MemoryKeystore::new(); let mut t = sp_io::TestExternalities::default(); t.register_extension(OffchainWorkerExt::new(offchain)); diff --git a/frame/nfts/src/mock.rs b/frame/nfts/src/mock.rs index a9db1a62c9d67..f21547b720c34 100644 --- a/frame/nfts/src/mock.rs +++ b/frame/nfts/src/mock.rs @@ -25,7 +25,7 @@ use frame_support::{ traits::{AsEnsureOriginWithArg, ConstU32, ConstU64}, }; use sp_core::H256; -use sp_keystore::{testing::KeyStore, KeystoreExt}; +use sp_keystore::{testing::MemoryKeystore, KeystoreExt}; use sp_runtime::{ testing::Header, traits::{BlakeTwo256, IdentifyAccount, IdentityLookup, Verify}, @@ -130,7 +130,7 @@ impl Config for Test { pub(crate) fn new_test_ext() -> sp_io::TestExternalities { let t = frame_system::GenesisConfig::default().build_storage::().unwrap(); - let keystore = KeyStore::new(); + let keystore = MemoryKeystore::new(); let mut ext = sp_io::TestExternalities::new(t); ext.register_extension(KeystoreExt(Arc::new(keystore))); ext.execute_with(|| System::set_block_number(1)); diff --git a/primitives/application-crypto/test/src/ecdsa.rs b/primitives/application-crypto/test/src/ecdsa.rs index df3be6f934304..7b96b42d5556b 100644 --- a/primitives/application-crypto/test/src/ecdsa.rs +++ b/primitives/application-crypto/test/src/ecdsa.rs @@ -19,7 +19,7 @@ use sp_api::ProvideRuntimeApi; use sp_application_crypto::ecdsa::{AppPair, AppPublic}; use sp_core::{crypto::Pair, testing::ECDSA}; -use sp_keystore::{testing::KeyStore, SyncCryptoStore}; +use sp_keystore::{testing::MemoryKeystore, Keystore}; use std::sync::Arc; use substrate_test_runtime_client::{ runtime::TestAPI, DefaultTestClientBuilderExt, TestClientBuilder, TestClientBuilderExt, @@ -27,14 +27,14 @@ use substrate_test_runtime_client::{ #[test] fn ecdsa_works_in_runtime() { - let keystore = Arc::new(KeyStore::new()); + let keystore = Arc::new(MemoryKeystore::new()); let test_client = TestClientBuilder::new().set_keystore(keystore.clone()).build(); let (signature, public) = test_client .runtime_api() .test_ecdsa_crypto(test_client.chain_info().genesis_hash) .expect("Tests `ecdsa` crypto."); - let supported_keys = SyncCryptoStore::keys(&*keystore, ECDSA).unwrap(); + let supported_keys = Keystore::keys(&*keystore, ECDSA).unwrap(); assert!(supported_keys.contains(&public.clone().into())); assert!(AppPair::verify(&signature, "ecdsa", &AppPublic::from(public))); } diff --git a/primitives/application-crypto/test/src/ed25519.rs b/primitives/application-crypto/test/src/ed25519.rs index 8ce08717a8947..1cf2b574b6bfb 100644 --- a/primitives/application-crypto/test/src/ed25519.rs +++ b/primitives/application-crypto/test/src/ed25519.rs @@ -20,7 +20,7 @@ use sp_api::ProvideRuntimeApi; use sp_application_crypto::ed25519::{AppPair, AppPublic}; use sp_core::{crypto::Pair, testing::ED25519}; -use sp_keystore::{testing::KeyStore, SyncCryptoStore}; +use sp_keystore::{testing::MemoryKeystore, Keystore}; use std::sync::Arc; use substrate_test_runtime_client::{ runtime::TestAPI, DefaultTestClientBuilderExt, TestClientBuilder, TestClientBuilderExt, @@ -28,14 +28,14 @@ use substrate_test_runtime_client::{ #[test] fn ed25519_works_in_runtime() { - let keystore = Arc::new(KeyStore::new()); + let keystore = Arc::new(MemoryKeystore::new()); let test_client = TestClientBuilder::new().set_keystore(keystore.clone()).build(); let (signature, public) = test_client .runtime_api() .test_ed25519_crypto(test_client.chain_info().genesis_hash) .expect("Tests `ed25519` crypto."); - let supported_keys = SyncCryptoStore::keys(&*keystore, ED25519).unwrap(); + let supported_keys = Keystore::keys(&*keystore, ED25519).unwrap(); assert!(supported_keys.contains(&public.clone().into())); assert!(AppPair::verify(&signature, "ed25519", &AppPublic::from(public))); } diff --git a/primitives/application-crypto/test/src/sr25519.rs b/primitives/application-crypto/test/src/sr25519.rs index 4c1d0f1ef7a97..aa8f75c0dc27a 100644 --- a/primitives/application-crypto/test/src/sr25519.rs +++ b/primitives/application-crypto/test/src/sr25519.rs @@ -20,7 +20,7 @@ use sp_api::ProvideRuntimeApi; use sp_application_crypto::sr25519::{AppPair, AppPublic}; use sp_core::{crypto::Pair, testing::SR25519}; -use sp_keystore::{testing::KeyStore, SyncCryptoStore}; +use sp_keystore::{testing::MemoryKeystore, Keystore}; use std::sync::Arc; use substrate_test_runtime_client::{ runtime::TestAPI, DefaultTestClientBuilderExt, TestClientBuilder, TestClientBuilderExt, @@ -28,14 +28,14 @@ use substrate_test_runtime_client::{ #[test] fn sr25519_works_in_runtime() { - let keystore = Arc::new(KeyStore::new()); + let keystore = Arc::new(MemoryKeystore::new()); let test_client = TestClientBuilder::new().set_keystore(keystore.clone()).build(); let (signature, public) = test_client .runtime_api() .test_sr25519_crypto(test_client.chain_info().genesis_hash) .expect("Tests `sr25519` crypto."); - let supported_keys = SyncCryptoStore::keys(&*keystore, SR25519).unwrap(); + let supported_keys = Keystore::keys(&*keystore, SR25519).unwrap(); assert!(supported_keys.contains(&public.clone().into())); assert!(AppPair::verify(&signature, "sr25519", &AppPublic::from(public))); } diff --git a/primitives/consensus/beefy/src/commitment.rs b/primitives/consensus/beefy/src/commitment.rs index f824c90e27c46..6ae17b06d96a4 100644 --- a/primitives/consensus/beefy/src/commitment.rs +++ b/primitives/consensus/beefy/src/commitment.rs @@ -253,7 +253,7 @@ mod tests { use crate::{crypto, known_payloads, KEY_TYPE}; use codec::Decode; use sp_core::{keccak_256, Pair}; - use sp_keystore::{testing::KeyStore, SyncCryptoStore, SyncCryptoStorePtr}; + use sp_keystore::{testing::MemoryKeystore, Keystore, KeystorePtr}; type TestCommitment = Commitment; type TestSignedCommitment = SignedCommitment; @@ -263,20 +263,18 @@ mod tests { // 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 store: KeystorePtr = MemoryKeystore::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 _ = Keystore::insert(&*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) + let sig1 = Keystore::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) + let sig2 = Keystore::ecdsa_sign_prehashed(&*store, KEY_TYPE, &alice.public(), &msg) .unwrap() .unwrap(); diff --git a/primitives/consensus/beefy/src/witness.rs b/primitives/consensus/beefy/src/witness.rs index 9cc31d54b4c1d..70b924c0a42fe 100644 --- a/primitives/consensus/beefy/src/witness.rs +++ b/primitives/consensus/beefy/src/witness.rs @@ -76,7 +76,7 @@ impl SignedCommitmentWitness (crypto::Signature, crypto::Signature) { - let store: SyncCryptoStorePtr = KeyStore::new().into(); + let store: KeystorePtr = MemoryKeystore::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 _ = Keystore::insert(&*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) + let sig1 = Keystore::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) + let sig2 = Keystore::ecdsa_sign_prehashed(&*store, KEY_TYPE, &alice.public(), &msg) .unwrap() .unwrap(); diff --git a/primitives/consensus/grandpa/src/lib.rs b/primitives/consensus/grandpa/src/lib.rs index 26cee07b80be8..32fc563b1facd 100644 --- a/primitives/consensus/grandpa/src/lib.rs +++ b/primitives/consensus/grandpa/src/lib.rs @@ -28,7 +28,7 @@ use serde::Serialize; use codec::{Codec, Decode, Encode, Input}; use scale_info::TypeInfo; #[cfg(feature = "std")] -use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; +use sp_keystore::{Keystore, KeystorePtr}; use sp_runtime::{ traits::{Header as HeaderT, NumberFor}, ConsensusEngineId, RuntimeDebug, @@ -444,7 +444,7 @@ where /// Localizes the message to the given set and round and signs the payload. #[cfg(feature = "std")] pub fn sign_message( - keystore: SyncCryptoStorePtr, + keystore: KeystorePtr, message: grandpa::Message, public: AuthorityId, round: RoundNumber, @@ -458,7 +458,7 @@ where use sp_core::crypto::Public; let encoded = localized_payload(round, set_id, &message); - let signature = SyncCryptoStore::sign_with( + let signature = Keystore::sign_with( &*keystore, AuthorityId::ID, &public.to_public_crypto_pair(), diff --git a/primitives/io/src/lib.rs b/primitives/io/src/lib.rs index 8c3cdc668cba3..65c583330ca73 100644 --- a/primitives/io/src/lib.rs +++ b/primitives/io/src/lib.rs @@ -43,7 +43,7 @@ use sp_core::{ traits::TaskExecutorExt, }; #[cfg(feature = "std")] -use sp_keystore::{KeystoreExt, SyncCryptoStore}; +use sp_keystore::{Keystore, KeystoreExt}; use sp_core::{ crypto::KeyTypeId, @@ -734,7 +734,7 @@ pub trait Crypto { let keystore = &***self .extension::() .expect("No `keystore` associated for the current context!"); - SyncCryptoStore::ed25519_public_keys(keystore, id) + Keystore::ed25519_public_keys(keystore, id) } /// Generate an `ed22519` key for the given key type using an optional `seed` and @@ -748,8 +748,7 @@ pub trait Crypto { let keystore = &***self .extension::() .expect("No `keystore` associated for the current context!"); - SyncCryptoStore::ed25519_generate_new(keystore, id, seed) - .expect("`ed25519_generate` failed") + Keystore::ed25519_generate_new(keystore, id, seed).expect("`ed25519_generate` failed") } /// Sign the given `msg` with the `ed25519` key that corresponds to the given public key and @@ -765,7 +764,7 @@ pub trait Crypto { let keystore = &***self .extension::() .expect("No `keystore` associated for the current context!"); - SyncCryptoStore::sign_with(keystore, id, &pub_key.into(), msg) + Keystore::sign_with(keystore, id, &pub_key.into(), msg) .ok() .flatten() .and_then(|sig| ed25519::Signature::from_slice(&sig)) @@ -877,7 +876,7 @@ pub trait Crypto { let keystore = &***self .extension::() .expect("No `keystore` associated for the current context!"); - SyncCryptoStore::sr25519_public_keys(keystore, id) + Keystore::sr25519_public_keys(keystore, id) } /// Generate an `sr22519` key for the given key type using an optional seed and @@ -891,8 +890,7 @@ pub trait Crypto { let keystore = &***self .extension::() .expect("No `keystore` associated for the current context!"); - SyncCryptoStore::sr25519_generate_new(keystore, id, seed) - .expect("`sr25519_generate` failed") + Keystore::sr25519_generate_new(keystore, id, seed).expect("`sr25519_generate` failed") } /// Sign the given `msg` with the `sr25519` key that corresponds to the given public key and @@ -908,7 +906,7 @@ pub trait Crypto { let keystore = &***self .extension::() .expect("No `keystore` associated for the current context!"); - SyncCryptoStore::sign_with(keystore, id, &pub_key.into(), msg) + Keystore::sign_with(keystore, id, &pub_key.into(), msg) .ok() .flatten() .and_then(|sig| sr25519::Signature::from_slice(&sig)) @@ -927,7 +925,7 @@ pub trait Crypto { let keystore = &***self .extension::() .expect("No `keystore` associated for the current context!"); - SyncCryptoStore::ecdsa_public_keys(keystore, id) + Keystore::ecdsa_public_keys(keystore, id) } /// Generate an `ecdsa` key for the given key type using an optional `seed` and @@ -941,7 +939,7 @@ pub trait Crypto { let keystore = &***self .extension::() .expect("No `keystore` associated for the current context!"); - SyncCryptoStore::ecdsa_generate_new(keystore, id, seed).expect("`ecdsa_generate` failed") + Keystore::ecdsa_generate_new(keystore, id, seed).expect("`ecdsa_generate` failed") } /// Sign the given `msg` with the `ecdsa` key that corresponds to the given public key and @@ -957,7 +955,7 @@ pub trait Crypto { let keystore = &***self .extension::() .expect("No `keystore` associated for the current context!"); - SyncCryptoStore::sign_with(keystore, id, &pub_key.into(), msg) + Keystore::sign_with(keystore, id, &pub_key.into(), msg) .ok() .flatten() .and_then(|sig| ecdsa::Signature::from_slice(&sig)) @@ -976,7 +974,7 @@ pub trait Crypto { let keystore = &***self .extension::() .expect("No `keystore` associated for the current context!"); - SyncCryptoStore::ecdsa_sign_prehashed(keystore, id, pub_key, msg).ok().flatten() + Keystore::ecdsa_sign_prehashed(keystore, id, pub_key, msg).ok().flatten() } /// Verify `ecdsa` signature. diff --git a/primitives/keystore/Cargo.toml b/primitives/keystore/Cargo.toml index 9386cb5d104d2..543f01059412e 100644 --- a/primitives/keystore/Cargo.toml +++ b/primitives/keystore/Cargo.toml @@ -13,7 +13,6 @@ documentation = "https://docs.rs/sp-core" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -async-trait = "0.1.57" codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } futures = "0.3.21" merlin = { version = "2.0", default-features = false } diff --git a/primitives/keystore/src/lib.rs b/primitives/keystore/src/lib.rs index 17c435483bae5..e0c00967b6b5e 100644 --- a/primitives/keystore/src/lib.rs +++ b/primitives/keystore/src/lib.rs @@ -20,15 +20,13 @@ pub mod testing; pub mod vrf; use crate::vrf::{VRFSignature, VRFTranscriptData}; -use async_trait::async_trait; -use futures::{executor::block_on, future::join_all}; use sp_core::{ crypto::{CryptoTypePublicPair, KeyTypeId}, ecdsa, ed25519, sr25519, }; use std::sync::Arc; -/// CryptoStore error +/// Keystore error #[derive(Debug, thiserror::Error)] pub enum Error { /// Public key type is not supported @@ -45,179 +43,8 @@ pub enum Error { Other(String), } -/// Something that generates, stores and provides access to keys. -#[async_trait] -pub trait CryptoStore: Send + Sync { - /// Returns all sr25519 public keys for the given key type. - async fn sr25519_public_keys(&self, id: KeyTypeId) -> Vec; - /// Generate a new sr25519 key pair for the given key type and an optional seed. - /// - /// If the given seed is `Some(_)`, the key pair will only be stored in memory. - /// - /// Returns the public key of the generated key pair. - async fn sr25519_generate_new( - &self, - id: KeyTypeId, - seed: Option<&str>, - ) -> Result; - /// Returns all ed25519 public keys for the given key type. - async fn ed25519_public_keys(&self, id: KeyTypeId) -> Vec; - /// Generate a new ed25519 key pair for the given key type and an optional seed. - /// - /// If the given seed is `Some(_)`, the key pair will only be stored in memory. - /// - /// Returns the public key of the generated key pair. - async fn ed25519_generate_new( - &self, - id: KeyTypeId, - seed: Option<&str>, - ) -> Result; - /// Returns all ecdsa public keys for the given key type. - async fn ecdsa_public_keys(&self, id: KeyTypeId) -> Vec; - /// Generate a new ecdsa key pair for the given key type and an optional seed. - /// - /// If the given seed is `Some(_)`, the key pair will only be stored in memory. - /// - /// Returns the public key of the generated key pair. - async fn ecdsa_generate_new( - &self, - id: KeyTypeId, - seed: Option<&str>, - ) -> Result; - - /// Insert a new key. This doesn't require any known of the crypto; but a public key must be - /// manually provided. - /// - /// Places it into the file system store. - /// - /// `Err` if there's some sort of weird filesystem error, but should generally be `Ok`. - async fn insert_unknown(&self, id: KeyTypeId, suri: &str, public: &[u8]) -> Result<(), ()>; - - /// Find intersection between provided keys and supported keys - /// - /// Provided a list of (CryptoTypeId,[u8]) pairs, this would return - /// a filtered set of public keys which are supported by the keystore. - async fn supported_keys( - &self, - id: KeyTypeId, - keys: Vec, - ) -> Result, Error>; - /// List all supported keys - /// - /// Returns a set of public keys the signer supports. - async fn keys(&self, id: KeyTypeId) -> Result, Error>; - - /// Checks if the private keys for the given public key and key type combinations exist. - /// - /// Returns `true` iff all private keys could be found. - async fn has_keys(&self, public_keys: &[(Vec, KeyTypeId)]) -> bool; - - /// Sign with key - /// - /// Signs a message with the private key that matches - /// the public key passed. - /// - /// Returns the SCALE encoded signature if key is found and supported, `None` if the key doesn't - /// exist or an error when something failed. - async fn sign_with( - &self, - id: KeyTypeId, - key: &CryptoTypePublicPair, - msg: &[u8], - ) -> Result>, Error>; - - /// Sign with any key - /// - /// Given a list of public keys, find the first supported key and - /// sign the provided message with that key. - /// - /// Returns a tuple of the used key and the SCALE encoded signature or `None` if no key could - /// be found to sign. - async fn sign_with_any( - &self, - id: KeyTypeId, - keys: Vec, - msg: &[u8], - ) -> Result)>, Error> { - if keys.len() == 1 { - return Ok(self.sign_with(id, &keys[0], msg).await?.map(|s| (keys[0].clone(), s))) - } else { - for k in self.supported_keys(id, keys).await? { - if let Ok(Some(sign)) = self.sign_with(id, &k, msg).await { - return Ok(Some((k, sign))) - } - } - } - - Ok(None) - } - - /// Sign with all keys - /// - /// Provided a list of public keys, sign a message with - /// each key given that the key is supported. - /// - /// Returns a list of `Result`s each representing the SCALE encoded - /// signature of each key, `None` if the key doesn't exist or a error when something failed. - async fn sign_with_all( - &self, - id: KeyTypeId, - keys: Vec, - msg: &[u8], - ) -> Result>, Error>>, ()> { - let futs = keys.iter().map(|k| self.sign_with(id, k, msg)); - - Ok(join_all(futs).await) - } - - /// Generate VRF signature for given transcript data. - /// - /// Receives KeyTypeId and Public key to be able to map - /// them to a private key that exists in the keystore which - /// is, in turn, used for signing the provided transcript. - /// - /// Returns a result containing the signature data. - /// Namely, VRFOutput and VRFProof which are returned - /// inside the `VRFSignature` container struct. - /// - /// This function will return `None` if the given `key_type` and `public` combination - /// doesn't exist in the keystore or an `Err` when something failed. - async fn sr25519_vrf_sign( - &self, - key_type: KeyTypeId, - public: &sr25519::Public, - transcript_data: VRFTranscriptData, - ) -> Result, Error>; - - /// Generate an ECDSA signature for a given pre-hashed message. - /// - /// Receives [`KeyTypeId`] and an [`ecdsa::Public`] key to be able to map - /// them to a private key that exists in the keystore. This private key is, - /// in turn, used for signing the provided pre-hashed message. - /// - /// The `msg` argument provided should be a hashed message for which an - /// ECDSA signature should be generated. - /// - /// Returns an [`ecdsa::Signature`] or `None` in case the given `id` and - /// `public` combination doesn't exist in the keystore. An `Err` will be - /// returned if generating the signature itself failed. - async fn ecdsa_sign_prehashed( - &self, - id: KeyTypeId, - public: &ecdsa::Public, - msg: &[u8; 32], - ) -> Result, Error>; -} - -/// Sync version of the CryptoStore -/// -/// Some parts of Substrate still rely on a sync version of the `CryptoStore`. -/// To make the transition easier this auto trait wraps any async `CryptoStore` and -/// exposes a `sync` interface using `block_on`. Usage of this is deprecated and it -/// will be removed as soon as the internal usage has transitioned successfully. -/// If you are starting out building something new **do not use this**, -/// instead, use [`CryptoStore`]. -pub trait SyncCryptoStore: CryptoStore + Send + Sync { +/// Something that generates, stores and provides access to secret keys. +pub trait Keystore: Send + Sync { /// Returns all sr25519 public keys for the given key type. fn sr25519_public_keys(&self, id: KeyTypeId) -> Vec; @@ -257,30 +84,13 @@ pub trait SyncCryptoStore: CryptoStore + Send + Sync { fn ecdsa_generate_new(&self, id: KeyTypeId, seed: Option<&str>) -> Result; - /// Insert a new key. This doesn't require any known of the crypto; but a public key must be - /// manually provided. - /// - /// Places it into the file system store. - /// - /// `Err` if there's some sort of weird filesystem error, but should generally be `Ok`. - fn insert_unknown(&self, key_type: KeyTypeId, suri: &str, public: &[u8]) -> Result<(), ()>; - - /// Find intersection between provided keys and supported keys - /// - /// Provided a list of (CryptoTypeId,[u8]) pairs, this would return - /// a filtered set of public keys which are supported by the keystore. - fn supported_keys( - &self, - id: KeyTypeId, - keys: Vec, - ) -> Result, Error>; + /// Insert a new secret key. + fn insert(&self, key_type: KeyTypeId, suri: &str, public: &[u8]) -> Result<(), ()>; /// List all supported keys /// /// Returns a set of public keys the signer supports. - fn keys(&self, id: KeyTypeId) -> Result, Error> { - block_on(CryptoStore::keys(self, id)) - } + fn keys(&self, id: KeyTypeId) -> Result, Error>; /// Checks if the private keys for the given public key and key type combinations exist. /// @@ -301,50 +111,6 @@ pub trait SyncCryptoStore: CryptoStore + Send + Sync { msg: &[u8], ) -> Result>, Error>; - /// Sign with any key - /// - /// Given a list of public keys, find the first supported key and - /// sign the provided message with that key. - /// - /// Returns a tuple of the used key and the SCALE encoded signature or `None` if no key could - /// be found to sign. - fn sign_with_any( - &self, - id: KeyTypeId, - keys: Vec, - msg: &[u8], - ) -> Result)>, Error> { - if keys.len() == 1 { - return Ok( - SyncCryptoStore::sign_with(self, id, &keys[0], msg)?.map(|s| (keys[0].clone(), s)) - ) - } else { - for k in SyncCryptoStore::supported_keys(self, id, keys)? { - if let Ok(Some(sign)) = SyncCryptoStore::sign_with(self, id, &k, msg) { - return Ok(Some((k, sign))) - } - } - } - - Ok(None) - } - - /// Sign with all keys - /// - /// Provided a list of public keys, sign a message with - /// each key given that the key is supported. - /// - /// Returns a list of `Result`s each representing the SCALE encoded - /// signature of each key, `None` if the key doesn't exist or an error when something failed. - fn sign_with_all( - &self, - id: KeyTypeId, - keys: Vec, - msg: &[u8], - ) -> Result>, Error>>, ()> { - Ok(keys.iter().map(|k| SyncCryptoStore::sign_with(self, id, k, msg)).collect()) - } - /// Generate VRF signature for given transcript data. /// /// Receives KeyTypeId and Public key to be able to map @@ -385,9 +151,9 @@ pub trait SyncCryptoStore: CryptoStore + Send + Sync { } /// A pointer to a keystore. -pub type SyncCryptoStorePtr = Arc; +pub type KeystorePtr = Arc; sp_externalities::decl_extension! { /// The keystore extension to register/retrieve from the externalities. - pub struct KeystoreExt(SyncCryptoStorePtr); + pub struct KeystoreExt(KeystorePtr); } diff --git a/primitives/keystore/src/testing.rs b/primitives/keystore/src/testing.rs index 5058a06508eac..fecc11342c464 100644 --- a/primitives/keystore/src/testing.rs +++ b/primitives/keystore/src/testing.rs @@ -24,23 +24,19 @@ use sp_core::{ use crate::{ vrf::{make_transcript, VRFSignature, VRFTranscriptData}, - CryptoStore, Error, SyncCryptoStore, SyncCryptoStorePtr, + Error, Keystore, KeystorePtr, }; -use async_trait::async_trait; use parking_lot::RwLock; -use std::{ - collections::{HashMap, HashSet}, - sync::Arc, -}; +use std::{collections::HashMap, sync::Arc}; /// A keystore implementation usable in tests. #[derive(Default)] -pub struct KeyStore { +pub struct MemoryKeystore { /// `KeyTypeId` maps to public keys and public keys map to private keys. keys: Arc, String>>>>, } -impl KeyStore { +impl MemoryKeystore { /// Creates a new instance of `Self`. pub fn new() -> Self { Self::default() @@ -71,93 +67,7 @@ impl KeyStore { } } -#[async_trait] -impl CryptoStore for KeyStore { - async fn keys(&self, id: KeyTypeId) -> Result, Error> { - SyncCryptoStore::keys(self, id) - } - - async fn sr25519_public_keys(&self, id: KeyTypeId) -> Vec { - SyncCryptoStore::sr25519_public_keys(self, id) - } - - async fn sr25519_generate_new( - &self, - id: KeyTypeId, - seed: Option<&str>, - ) -> Result { - SyncCryptoStore::sr25519_generate_new(self, id, seed) - } - - async fn ed25519_public_keys(&self, id: KeyTypeId) -> Vec { - SyncCryptoStore::ed25519_public_keys(self, id) - } - - async fn ed25519_generate_new( - &self, - id: KeyTypeId, - seed: Option<&str>, - ) -> Result { - SyncCryptoStore::ed25519_generate_new(self, id, seed) - } - - async fn ecdsa_public_keys(&self, id: KeyTypeId) -> Vec { - SyncCryptoStore::ecdsa_public_keys(self, id) - } - - async fn ecdsa_generate_new( - &self, - id: KeyTypeId, - seed: Option<&str>, - ) -> Result { - SyncCryptoStore::ecdsa_generate_new(self, id, seed) - } - - async fn insert_unknown(&self, id: KeyTypeId, suri: &str, public: &[u8]) -> Result<(), ()> { - SyncCryptoStore::insert_unknown(self, id, suri, public) - } - - async fn has_keys(&self, public_keys: &[(Vec, KeyTypeId)]) -> bool { - SyncCryptoStore::has_keys(self, public_keys) - } - - async fn supported_keys( - &self, - id: KeyTypeId, - keys: Vec, - ) -> std::result::Result, Error> { - SyncCryptoStore::supported_keys(self, id, keys) - } - - async fn sign_with( - &self, - id: KeyTypeId, - key: &CryptoTypePublicPair, - msg: &[u8], - ) -> Result>, Error> { - SyncCryptoStore::sign_with(self, id, key, msg) - } - - async fn sr25519_vrf_sign( - &self, - key_type: KeyTypeId, - public: &sr25519::Public, - transcript_data: VRFTranscriptData, - ) -> Result, Error> { - SyncCryptoStore::sr25519_vrf_sign(self, key_type, public, transcript_data) - } - - async fn ecdsa_sign_prehashed( - &self, - id: KeyTypeId, - public: &ecdsa::Public, - msg: &[u8; 32], - ) -> Result, Error> { - SyncCryptoStore::ecdsa_sign_prehashed(self, id, public, msg) - } -} - -impl SyncCryptoStore for KeyStore { +impl Keystore for MemoryKeystore { fn keys(&self, id: KeyTypeId) -> Result, Error> { self.keys .read() @@ -304,7 +214,7 @@ impl SyncCryptoStore for KeyStore { } } - fn insert_unknown(&self, id: KeyTypeId, suri: &str, public: &[u8]) -> Result<(), ()> { + fn insert(&self, id: KeyTypeId, suri: &str, public: &[u8]) -> Result<(), ()> { self.keys .write() .entry(id) @@ -319,17 +229,6 @@ impl SyncCryptoStore for KeyStore { .all(|(k, t)| self.keys.read().get(t).and_then(|s| s.get(k)).is_some()) } - fn supported_keys( - &self, - id: KeyTypeId, - keys: Vec, - ) -> std::result::Result, Error> { - let provided_keys = keys.into_iter().collect::>(); - let all_keys = SyncCryptoStore::keys(self, id)?.into_iter().collect::>(); - - Ok(provided_keys.intersection(&all_keys).cloned().collect()) - } - fn sign_with( &self, id: KeyTypeId, @@ -386,14 +285,8 @@ impl SyncCryptoStore for KeyStore { } } -impl Into for KeyStore { - fn into(self) -> SyncCryptoStorePtr { - Arc::new(self) - } -} - -impl Into> for KeyStore { - fn into(self) -> Arc { +impl Into for MemoryKeystore { + fn into(self) -> KeystorePtr { Arc::new(self) } } @@ -401,7 +294,7 @@ impl Into> for KeyStore { #[cfg(test)] mod tests { use super::*; - use crate::{vrf::VRFTranscriptValue, SyncCryptoStore}; + use crate::vrf::VRFTranscriptValue; use sp_core::{ sr25519, testing::{ECDSA, ED25519, SR25519}, @@ -409,34 +302,33 @@ mod tests { #[test] fn store_key_and_extract() { - let store = KeyStore::new(); + let store = MemoryKeystore::new(); - let public = - SyncCryptoStore::ed25519_generate_new(&store, ED25519, None).expect("Generates key"); + let public = Keystore::ed25519_generate_new(&store, ED25519, None).expect("Generates key"); - let public_keys = SyncCryptoStore::keys(&store, ED25519).unwrap(); + let public_keys = Keystore::keys(&store, ED25519).unwrap(); assert!(public_keys.contains(&public.into())); } #[test] fn store_unknown_and_extract_it() { - let store = KeyStore::new(); + let store = MemoryKeystore::new(); let secret_uri = "//Alice"; let key_pair = sr25519::Pair::from_string(secret_uri, None).expect("Generates key pair"); - SyncCryptoStore::insert_unknown(&store, SR25519, secret_uri, key_pair.public().as_ref()) + Keystore::insert(&store, SR25519, secret_uri, key_pair.public().as_ref()) .expect("Inserts unknown key"); - let public_keys = SyncCryptoStore::keys(&store, SR25519).unwrap(); + let public_keys = Keystore::keys(&store, SR25519).unwrap(); assert!(public_keys.contains(&key_pair.public().into())); } #[test] fn vrf_sign() { - let store = KeyStore::new(); + let store = MemoryKeystore::new(); let secret_uri = "//Alice"; let key_pair = sr25519::Pair::from_string(secret_uri, None).expect("Generates key pair"); @@ -450,7 +342,7 @@ mod tests { ], }; - let result = SyncCryptoStore::sr25519_vrf_sign( + let result = Keystore::sr25519_vrf_sign( &store, SR25519, &key_pair.public(), @@ -458,18 +350,18 @@ mod tests { ); assert!(result.unwrap().is_none()); - SyncCryptoStore::insert_unknown(&store, SR25519, secret_uri, key_pair.public().as_ref()) + Keystore::insert(&store, SR25519, secret_uri, key_pair.public().as_ref()) .expect("Inserts unknown key"); let result = - SyncCryptoStore::sr25519_vrf_sign(&store, SR25519, &key_pair.public(), transcript_data); + Keystore::sr25519_vrf_sign(&store, SR25519, &key_pair.public(), transcript_data); assert!(result.unwrap().is_some()); } #[test] fn ecdsa_sign_prehashed_works() { - let store = KeyStore::new(); + let store = MemoryKeystore::new(); let suri = "//Alice"; let pair = ecdsa::Pair::from_string(suri, None).unwrap(); @@ -477,15 +369,13 @@ mod tests { let msg = sp_core::keccak_256(b"this should be a hashed message"); // no key in key store - let res = - SyncCryptoStore::ecdsa_sign_prehashed(&store, ECDSA, &pair.public(), &msg).unwrap(); + let res = Keystore::ecdsa_sign_prehashed(&store, ECDSA, &pair.public(), &msg).unwrap(); assert!(res.is_none()); // insert key, sign again - SyncCryptoStore::insert_unknown(&store, ECDSA, suri, pair.public().as_ref()).unwrap(); + Keystore::insert(&store, ECDSA, suri, pair.public().as_ref()).unwrap(); - let res = - SyncCryptoStore::ecdsa_sign_prehashed(&store, ECDSA, &pair.public(), &msg).unwrap(); + let res = Keystore::ecdsa_sign_prehashed(&store, ECDSA, &pair.public(), &msg).unwrap(); assert!(res.is_some()); } } diff --git a/test-utils/client/src/lib.rs b/test-utils/client/src/lib.rs index a27178792579a..a91aa99929e2f 100644 --- a/test-utils/client/src/lib.rs +++ b/test-utils/client/src/lib.rs @@ -33,7 +33,7 @@ pub use sp_consensus; pub use sp_keyring::{ ed25519::Keyring as Ed25519Keyring, sr25519::Keyring as Sr25519Keyring, AccountKeyring, }; -pub use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; +pub use sp_keystore::{Keystore, KeystorePtr}; pub use sp_runtime::{Storage, StorageChild}; pub use sp_state_machine::ExecutionStrategy; @@ -70,7 +70,7 @@ pub struct TestClientBuilder, StorageChild>, backend: Arc, _executor: std::marker::PhantomData, - keystore: Option, + keystore: Option, fork_blocks: ForkBlocks, bad_blocks: BadBlocks, enable_offchain_indexing_api: bool, @@ -128,7 +128,7 @@ impl } /// Set the keystore that should be used by the externalities. - pub fn set_keystore(mut self, keystore: SyncCryptoStorePtr) -> Self { + pub fn set_keystore(mut self, keystore: KeystorePtr) -> Self { self.keystore = Some(keystore); self } diff --git a/utils/frame/benchmarking-cli/src/pallet/command.rs b/utils/frame/benchmarking-cli/src/pallet/command.rs index 60f078142e17f..f11e6bd920abf 100644 --- a/utils/frame/benchmarking-cli/src/pallet/command.rs +++ b/utils/frame/benchmarking-cli/src/pallet/command.rs @@ -38,7 +38,7 @@ use sp_core::{ traits::CallContext, }; use sp_externalities::Extensions; -use sp_keystore::{testing::KeyStore, KeystoreExt, SyncCryptoStorePtr}; +use sp_keystore::{testing::MemoryKeystore, KeystoreExt, KeystorePtr}; use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; use sp_state_machine::StateMachine; use std::{collections::HashMap, fmt::Debug, fs, str::FromStr, sync::Arc, time}; @@ -218,7 +218,7 @@ impl PalletCmd { let extensions = || -> Extensions { let mut extensions = Extensions::default(); - extensions.register(KeystoreExt(Arc::new(KeyStore::new()) as SyncCryptoStorePtr)); + extensions.register(KeystoreExt(Arc::new(MemoryKeystore::new()) as KeystorePtr)); let (offchain, _) = TestOffchainExt::new(); let (pool, _) = TestTransactionPoolExt::new(); extensions.register(OffchainWorkerExt::new(offchain.clone())); diff --git a/utils/frame/try-runtime/cli/src/lib.rs b/utils/frame/try-runtime/cli/src/lib.rs index 6fb4b44392546..e1d75064ac87f 100644 --- a/utils/frame/try-runtime/cli/src/lib.rs +++ b/utils/frame/try-runtime/cli/src/lib.rs @@ -383,7 +383,7 @@ use sp_core::{ }; use sp_externalities::Extensions; use sp_inherents::InherentData; -use sp_keystore::{testing::KeyStore, KeystoreExt}; +use sp_keystore::{testing::MemoryKeystore, KeystoreExt}; use sp_runtime::{ traits::{BlakeTwo256, Block as BlockT, NumberFor}, DeserializeOwned, Digest, @@ -820,7 +820,7 @@ pub(crate) fn full_extensions() -> Extensions { 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(KeystoreExt(std::sync::Arc::new(MemoryKeystore::new()))); extensions.register(TransactionPoolExt::new(pool)); extensions From a87aa29b4b8796afe50ffbda4ad6f7692cc9a65e Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Fri, 17 Mar 2023 14:21:02 +0100 Subject: [PATCH 525/715] Bump grandpa to 0.16.2 (#13622) --- Cargo.lock | 4 ++-- client/consensus/grandpa/Cargo.toml | 4 ++-- client/consensus/grandpa/rpc/Cargo.toml | 2 +- frame/grandpa/Cargo.toml | 2 +- primitives/consensus/grandpa/Cargo.toml | 2 +- primitives/consensus/grandpa/src/lib.rs | 7 ++----- 6 files changed, 9 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9121a85919844..df0e54a3d7ecd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2080,9 +2080,9 @@ dependencies = [ [[package]] name = "finality-grandpa" -version = "0.16.1" +version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e24e6c429951433ccb7c87fd528c60084834dcd14763182c1f83291bcde24c34" +checksum = "36530797b9bf31cd4ff126dcfee8170f86b00cfdcea3269d73133cc0415945c3" dependencies = [ "either", "futures", diff --git a/client/consensus/grandpa/Cargo.toml b/client/consensus/grandpa/Cargo.toml index 511e546aa7256..67c58d37a2cf5 100644 --- a/client/consensus/grandpa/Cargo.toml +++ b/client/consensus/grandpa/Cargo.toml @@ -18,7 +18,7 @@ ahash = "0.8.2" array-bytes = "4.1" async-trait = "0.1.57" dyn-clone = "1.0" -finality-grandpa = { version = "0.16.1", features = ["derive-codec"] } +finality-grandpa = { version = "0.16.2", features = ["derive-codec"] } futures = "0.3.21" futures-timer = "3.0.1" log = "0.4.17" @@ -50,7 +50,7 @@ sp-runtime = { version = "7.0.0", path = "../../../primitives/runtime" } [dev-dependencies] assert_matches = "1.3.0" -finality-grandpa = { version = "0.16.1", features = ["derive-codec", "test-helpers"] } +finality-grandpa = { version = "0.16.2", features = ["derive-codec", "test-helpers"] } serde = "1.0.136" tokio = "1.22.0" sc-network = { version = "0.10.0-dev", path = "../../network" } diff --git a/client/consensus/grandpa/rpc/Cargo.toml b/client/consensus/grandpa/rpc/Cargo.toml index 4880b50d30630..76a06ad298f77 100644 --- a/client/consensus/grandpa/rpc/Cargo.toml +++ b/client/consensus/grandpa/rpc/Cargo.toml @@ -10,7 +10,7 @@ readme = "README.md" homepage = "https://substrate.io" [dependencies] -finality-grandpa = { version = "0.16.1", features = ["derive-codec"] } +finality-grandpa = { version = "0.16.2", features = ["derive-codec"] } futures = "0.3.16" jsonrpsee = { version = "0.16.2", features = ["client-core", "server", "macros"] } log = "0.4.8" diff --git a/frame/grandpa/Cargo.toml b/frame/grandpa/Cargo.toml index 3ffb516423906..4eb796cf0c6b3 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 = "5.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] -grandpa = { package = "finality-grandpa", version = "0.16.1", features = ["derive-codec"] } +grandpa = { package = "finality-grandpa", version = "0.16.2", 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/consensus/grandpa/Cargo.toml b/primitives/consensus/grandpa/Cargo.toml index 7146873e0a751..5536cf73558d9 100644 --- a/primitives/consensus/grandpa/Cargo.toml +++ b/primitives/consensus/grandpa/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } -grandpa = { package = "finality-grandpa", version = "0.16.1", default-features = false, features = ["derive-codec"] } +grandpa = { package = "finality-grandpa", version = "0.16.2", default-features = false, features = ["derive-codec"] } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"], optional = true } diff --git a/primitives/consensus/grandpa/src/lib.rs b/primitives/consensus/grandpa/src/lib.rs index 32fc563b1facd..28c7de0677830 100644 --- a/primitives/consensus/grandpa/src/lib.rs +++ b/primitives/consensus/grandpa/src/lib.rs @@ -234,15 +234,12 @@ impl ConsensusLog { /// GRANDPA happens when a voter votes on the same round (either at prevote or /// precommit stage) for different blocks. Proving is achieved by collecting the /// signed messages of conflicting votes. -#[derive(Clone, Debug, Decode, Encode, PartialEq, TypeInfo)] +#[derive(Clone, Debug, Decode, Encode, PartialEq, Eq, TypeInfo)] pub struct EquivocationProof { set_id: SetId, equivocation: Equivocation, } -// Don't bother the grandpa crate... -impl Eq for EquivocationProof {} - impl EquivocationProof { /// Create a new `EquivocationProof` for the given set id and using the /// given equivocation as proof. @@ -271,7 +268,7 @@ impl EquivocationProof { /// Wrapper object for GRANDPA equivocation proofs, useful for unifying prevote /// and precommit equivocations under a common type. -#[derive(Clone, Debug, Decode, Encode, PartialEq, TypeInfo)] +#[derive(Clone, Debug, Decode, Encode, PartialEq, Eq, TypeInfo)] pub enum Equivocation { /// Proof of equivocation at prevote stage. Prevote(grandpa::Equivocation, AuthoritySignature>), From 0506da00297757babe63b7bb62e487c657066117 Mon Sep 17 00:00:00 2001 From: Oleg Plakida <112385193+oleg-plakida@users.noreply.github.com> Date: Fri, 17 Mar 2023 14:14:13 +0000 Subject: [PATCH 526/715] Fix `test-linux-stable` excessive run time (#13597) * ci-cd#754:Fix slow unit tests - Add nextest config - Add slow tests to mutual exclusion list * Update .config/nextest.toml Co-authored-by: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> --------- Co-authored-by: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> --- .config/nextest.toml | 124 +++++++++++++++++++++++++++++++++++ .github/pr-custom-review.yml | 4 +- 2 files changed, 126 insertions(+), 2 deletions(-) create mode 100644 .config/nextest.toml diff --git a/.config/nextest.toml b/.config/nextest.toml new file mode 100644 index 0000000000000..c111b0abeb7a2 --- /dev/null +++ b/.config/nextest.toml @@ -0,0 +1,124 @@ +# This is the default config used by nextest. It is embedded in the binary at +# build time. It may be used as a template for .config/nextest.toml. + +[store] +# The directory under the workspace root at which nextest-related files are +# written. Profile-specific storage is currently written to dir/. +dir = "target/nextest" + +# This section defines the default nextest profile. Custom profiles are layered +# on top of the default profile. +[profile.default] +# "retries" defines the number of times a test should be retried. If set to a +# non-zero value, tests that succeed on a subsequent attempt will be marked as +# non-flaky. Can be overridden through the `--retries` option. +# Examples +# * retries = 3 +# * retries = { backoff = "fixed", count = 2, delay = "1s" } +# * retries = { backoff = "exponential", count = 10, delay = "1s", jitter = true, max-delay = "10s" } +retries = 0 + +# The number of threads to run tests with. Supported values are either an integer or +# the string "num-cpus". Can be overridden through the `--test-threads` option. +test-threads = "num-cpus" + +# The number of threads required for each test. This is generally used in overrides to +# mark certain tests as heavier than others. However, it can also be set as a global parameter. +threads-required = 1 + +# Show these test statuses in the output. +# +# The possible values this can take are: +# * none: no output +# * fail: show failed (including exec-failed) tests +# * retry: show flaky and retried tests +# * slow: show slow tests +# * pass: show passed tests +# * skip: show skipped tests (most useful for CI) +# * all: all of the above +# +# Each value includes all the values above it; for example, "slow" includes +# failed and retried tests. +# +# Can be overridden through the `--status-level` flag. +status-level = "pass" + +# Similar to status-level, show these test statuses at the end of the run. +final-status-level = "flaky" + +# "failure-output" defines when standard output and standard error for failing tests are produced. +# Accepted values are +# * "immediate": output failures as soon as they happen +# * "final": output failures at the end of the test run +# * "immediate-final": output failures as soon as they happen and at the end of +# the test run; combination of "immediate" and "final" +# * "never": don't output failures at all +# +# For large test suites and CI it is generally useful to use "immediate-final". +# +# Can be overridden through the `--failure-output` option. +failure-output = "immediate" + +# "success-output" controls production of standard output and standard error on success. This should +# generally be set to "never". +success-output = "never" + +# Cancel the test run on the first failure. For CI runs, consider setting this +# to false. +fail-fast = true + +# Treat a test that takes longer than the configured 'period' as slow, and print a message. +# See for more information. +# +# Optional: specify the parameter 'terminate-after' with a non-zero integer, +# which will cause slow tests to be terminated after the specified number of +# periods have passed. +# Example: slow-timeout = { period = "60s", terminate-after = 2 } +slow-timeout = { period = "60s" } + +# Treat a test as leaky if after the process is shut down, standard output and standard error +# aren't closed within this duration. +# +# This usually happens in case of a test that creates a child process and lets it inherit those +# handles, but doesn't clean the child process up (especially when it fails). +# +# See for more information. +leak-timeout = "100ms" + +[profile.default.junit] +# Output a JUnit report into the given file inside 'store.dir/'. +# If unspecified, JUnit is not written out. + +# path = "junit.xml" + +# The name of the top-level "report" element in JUnit report. If aggregating +# reports across different test runs, it may be useful to provide separate names +# for each report. +report-name = "nextest-run" + +# Whether standard output and standard error for passing tests should be stored in the JUnit report. +# Output is stored in the and elements of the element. +store-success-output = false + +# Whether standard output and standard error for failing tests should be stored in the JUnit report. +# Output is stored in the and elements of the element. +# +# Note that if a description can be extracted from the output, it is always stored in the +# element. +store-failure-output = true + +# This profile is activated if MIRI_SYSROOT is set. +[profile.default-miri] +# Miri tests take up a lot of memory, so only run 1 test at a time by default. +test-threads = 1 + +# Mutual exclusion of tests with `cargo build` invocation as a lock to avoid multiple +# simultaneous invocations clobbering each other. +[test-groups] +serial-integration = { max-threads = 1 } + +# Running UI tests sequentially +# More info can be found here: https://github.com/paritytech/ci_cd/issues/754 +[[profile.default.overrides]] +filter = 'test(/(^ui$|_ui|ui_)/)' +test-group = 'serial-integration' diff --git a/.github/pr-custom-review.yml b/.github/pr-custom-review.yml index 769ac1e110d33..3620f7e770674 100644 --- a/.github/pr-custom-review.yml +++ b/.github/pr-custom-review.yml @@ -9,7 +9,7 @@ rules: condition: include: .* # excluding files from 'CI team' rules - exclude: ^\.gitlab-ci\.yml|^scripts/ci/.*|^\.github/.* + exclude: ^\.gitlab-ci\.yml|^scripts/ci/.*|^\.github/.*|^\.config/nextest.toml min_approvals: 2 teams: - core-devs @@ -17,7 +17,7 @@ rules: - name: CI team check_type: changed_files condition: - include: ^\.gitlab-ci\.yml|^scripts/ci/.*|^\.github/.* + include: ^\.gitlab-ci\.yml|^scripts/ci/.*|^\.github/.*|^\.config/nextest.toml min_approvals: 2 teams: - ci From acdbf010f5c81497edfe65377a46ba0d6e50baa5 Mon Sep 17 00:00:00 2001 From: PG Herveou Date: Fri, 17 Mar 2023 16:31:51 +0100 Subject: [PATCH 527/715] Fix typos in pallet-contracts (#13629) * Fix typos in pallet-contracts --- client/state-db/src/lib.rs | 4 ++-- frame/contracts/README.md | 2 +- frame/contracts/primitives/src/lib.rs | 4 ++-- frame/contracts/proc-macro/src/lib.rs | 6 +++--- frame/contracts/src/address.rs | 2 +- frame/contracts/src/benchmarking/code.rs | 2 +- frame/contracts/src/benchmarking/mod.rs | 8 ++++---- frame/contracts/src/chain_extension.rs | 2 +- frame/contracts/src/exec.rs | 10 +++++----- frame/contracts/src/lib.rs | 6 +++--- frame/contracts/src/storage/meter.rs | 2 +- frame/contracts/src/wasm/mod.rs | 4 ++-- frame/contracts/src/wasm/prepare.rs | 6 +++--- frame/contracts/src/wasm/runtime.rs | 16 ++++++++-------- 14 files changed, 37 insertions(+), 37 deletions(-) diff --git a/client/state-db/src/lib.rs b/client/state-db/src/lib.rs index 14b4622ac0670..5ebfbaad6d8f6 100644 --- a/client/state-db/src/lib.rs +++ b/client/state-db/src/lib.rs @@ -594,7 +594,7 @@ impl StateDb { } /// Prevents pruning of specified block and its descendants. - /// `hint` used for futher checking if the given block exists + /// `hint` used for further checking if the given block exists pub fn pin(&self, hash: &BlockHash, number: u64, hint: F) -> Result<(), PinError> where F: Fn() -> bool, @@ -665,7 +665,7 @@ pub enum IsPruned { Pruned, /// Definitely not pruned NotPruned, - /// May or may not pruned, need futher checking + /// May or may not pruned, need further checking MaybePruned, } diff --git a/frame/contracts/README.md b/frame/contracts/README.md index 4df7d9449682d..9b1d3f7d6de08 100644 --- a/frame/contracts/README.md +++ b/frame/contracts/README.md @@ -64,7 +64,7 @@ When setting up the `Schedule` for your runtime make sure to set `InstructionWei 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 +to `upload_code`. A deterministic 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.** diff --git a/frame/contracts/primitives/src/lib.rs b/frame/contracts/primitives/src/lib.rs index ee415cb822257..e73ceb031e184 100644 --- a/frame/contracts/primitives/src/lib.rs +++ b/frame/contracts/primitives/src/lib.rs @@ -131,7 +131,7 @@ pub struct InstantiateReturnValue { pub account_id: AccountId, } -/// The result of succesfully uploading a contract. +/// The result of successfully uploading a contract. #[derive(PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)] pub struct CodeUploadReturnValue { /// The key under which the new code is stored. @@ -239,7 +239,7 @@ where } } - /// If the amount of deposit (this type) is constrained by a `limit` this calcuates how + /// If the amount of deposit (this type) is constrained by a `limit` this calculates how /// much balance (if any) is still available from this limit. /// /// # Note diff --git a/frame/contracts/proc-macro/src/lib.rs b/frame/contracts/proc-macro/src/lib.rs index 1b530a409b933..c3e61dae5f000 100644 --- a/frame/contracts/proc-macro/src/lib.rs +++ b/frame/contracts/proc-macro/src/lib.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Procedural macroses used in the contracts module. +//! Procedural macros 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. @@ -527,7 +527,7 @@ fn expand_docs(def: &EnvDef) -> TokenStream2 { } } -/// Expands environment definiton. +/// Expands environment definition. /// Should generate source code for: /// - implementations of the host functions to be added to the wasm runtime environment (see /// `expand_impls()`). @@ -778,7 +778,7 @@ fn expand_functions(def: &EnvDef, expand_blocks: bool, host_state: TokenStream2) #[proc_macro_attribute] pub fn define_env(attr: TokenStream, item: TokenStream) -> TokenStream { if !attr.is_empty() && !(attr.to_string() == "doc".to_string()) { - let msg = r#"Invalid `define_env` attribute macro: expected either no attributes or a single `doc` attibute: + let msg = r#"Invalid `define_env` attribute macro: expected either no attributes or a single `doc` attribute: - `#[define_env]` - `#[define_env(doc)]`"#; let span = TokenStream2::from(attr).span(); diff --git a/frame/contracts/src/address.rs b/frame/contracts/src/address.rs index 1c25af21e8cb7..e36fc6fffd6f7 100644 --- a/frame/contracts/src/address.rs +++ b/frame/contracts/src/address.rs @@ -32,7 +32,7 @@ use sp_runtime::traits::{Hash, TrailingZeroInput}; pub trait AddressGenerator { /// The address of a contract based on the given instantiate parameters. /// - /// Changing the formular for an already deployed chain is fine as long as no collisons + /// Changing the formular for an already deployed chain is fine as long as no collisions /// with the old formular. Changes only affect existing contracts. fn contract_address( deploying_address: &T::AccountId, diff --git a/frame/contracts/src/benchmarking/code.rs b/frame/contracts/src/benchmarking/code.rs index 96eb5e501d068..c2d623ae4e834 100644 --- a/frame/contracts/src/benchmarking/code.rs +++ b/frame/contracts/src/benchmarking/code.rs @@ -39,7 +39,7 @@ use wasm_instrument::{ }, }; -/// The location where to put the genrated code. +/// The location where to put the generated code. pub enum Location { /// Generate all code into the `call` exported function. Call, diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index 873314981b7ed..96368ebb3f604 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -355,7 +355,7 @@ benchmarks! { }: _(origin, callee, value, Weight::MAX, None, data) verify { let deposit = T::Currency::free_balance(&deposit_account); - // value and value transfered via call should be removed from the caller + // value and value transferred via call should be removed from the caller assert_eq!( T::Currency::free_balance(&instance.caller), caller_funding::() - instance.value - value - deposit - Pallet::::min_balance(), @@ -2224,7 +2224,7 @@ benchmarks! { // 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 // to measure them on their own using a valid wasm module. We need their individual - // values to derive the weight of individual instructions (by substraction) from + // values to derive the weight of individual instructions (by subtraction) from // benchmarks that include those for parameter pushing and return type dropping. // We call the weight of `t.load` and `drop`: `w_param`. // The weight that would result from the respective benchmark we call: `w_bench`. @@ -3003,9 +3003,9 @@ benchmarks! { sbox.invoke(); } - // This is no benchmark. It merely exist to have an easy way to pretty print the curently + // This is no benchmark. It merely exist to have an easy way to pretty print the currently // configured `Schedule` during benchmark development. - // It can be outputed using the following command: + // It can be outputted using the following command: // cargo run --manifest-path=bin/node/cli/Cargo.toml \ // --features runtime-benchmarks -- benchmark pallet --extra --dev --execution=native \ // -p pallet_contracts -e print_schedule --no-median-slopes --no-min-squares diff --git a/frame/contracts/src/chain_extension.rs b/frame/contracts/src/chain_extension.rs index 56d41a759391b..2c378070813bd 100644 --- a/frame/contracts/src/chain_extension.rs +++ b/frame/contracts/src/chain_extension.rs @@ -138,7 +138,7 @@ pub trait ChainExtension { /// /// # Note /// -/// Currently, we support tuples of up to ten registred chain extensions. If more chain extensions +/// Currently, we support tuples of up to ten registered chain extensions. If more chain extensions /// are needed consider opening an issue. pub trait RegisteredChainExtension: ChainExtension { /// The extensions globally unique identifier. diff --git a/frame/contracts/src/exec.rs b/frame/contracts/src/exec.rs index 37be12d50d689..35ef43da5ed40 100644 --- a/frame/contracts/src/exec.rs +++ b/frame/contracts/src/exec.rs @@ -84,14 +84,14 @@ where pub enum ErrorOrigin { /// Caller error origin. /// - /// The error happened in the current exeuction context rather than in the one + /// The error happened in the current execution context rather than in the one /// of the contract that is called into. Caller, /// The error happened during execution of the called contract. Callee, } -/// Error returned by contract exection. +/// Error returned by contract execution. #[cfg_attr(test, derive(Debug, PartialEq))] pub struct ExecError { /// The reason why the execution failed. @@ -2455,7 +2455,7 @@ mod tests { #[test] fn in_memory_changes_not_discarded() { // Call stack: BOB -> CHARLIE (trap) -> BOB' (success) - // This tests verfies some edge case of the contract info cache: + // This tests verifies some edge case of the contract info cache: // We change some value in our contract info before calling into a contract // that calls into ourself. This triggers a case where BOBs contract info // is written to storage and invalidated by the successful execution of BOB'. @@ -3405,7 +3405,7 @@ mod tests { 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 + // Should not change without any instantiation in-between assert_eq!(ctx.ext.nonce(), 1); // Should not change with a failed instantiation assert_err!( @@ -3416,7 +3416,7 @@ mod tests { } ); assert_eq!(ctx.ext.nonce(), 1); - // Successful instantation increments + // Successful instantiation increments ctx.ext.instantiate(Weight::zero(), success_code, 0, vec![], &[]).unwrap(); assert_eq!(ctx.ext.nonce(), 2); exec_success() diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index 4f5d7ba305fc1..0aff18fd62083 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -403,7 +403,7 @@ pub mod pallet { T::MaxCodeLen::get(), ); - // Debug buffer should at least be large enough to accomodate a simple error message + // Debug buffer should at least be large enough to accommodate a simple error message const MIN_DEBUG_BUF_SIZE: u32 = 256; assert!( T::MaxDebugBufferLen::get() > MIN_DEBUG_BUF_SIZE, @@ -891,7 +891,7 @@ pub mod pallet { /// 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 + /// node. This happens 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 @@ -987,7 +987,7 @@ struct InternalOutput { result: Result, } -/// Helper trait to wrap contract execution entry points into a signle function +/// Helper trait to wrap contract execution entry points into a single function /// [`Invokable::run_guarded`]. trait Invokable { /// What is returned as a result of a successful invocation. diff --git a/frame/contracts/src/storage/meter.rs b/frame/contracts/src/storage/meter.rs index ef6fb3277c11b..b4fc443fe7f35 100644 --- a/frame/contracts/src/storage/meter.rs +++ b/frame/contracts/src/storage/meter.rs @@ -513,7 +513,7 @@ impl Ext for ReservingExt { // we make sure to leave at least the ed in the free balance. // // The sender always has enough balance because we track it in the `ContractInfo` and - // never send more back than we have. Noone has access to the deposit account. Hence no + // never send more back than we have. No one has access to the deposit account. Hence no // other interaction with this account takes place. Deposit::Refund(amount) => { if terminated { diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index f8c5a6ed96c57..f74df2c361442 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -186,7 +186,7 @@ impl PrefabWasmModule { code_cache::try_remove::(origin, code_hash) } - /// Returns whether there is a deposit to be payed for this module. + /// Returns whether there is a deposit to be paid for this module. /// /// Returns `0` if the module is already in storage and hence no deposit will /// be charged when storing it. @@ -689,7 +689,7 @@ mod tests { executable.execute(ext.borrow_mut(), entry_point, input_data) } - /// Execute the suppplied code. + /// Execute the supplied code. fn execute>(wat: &str, input_data: Vec, ext: E) -> ExecResult { execute_internal(wat, input_data, ext, &ExportedFunction::Call, true, false) } diff --git a/frame/contracts/src/wasm/prepare.rs b/frame/contracts/src/wasm/prepare.rs index eed60891d66f4..6a2eb6a769ecc 100644 --- a/frame/contracts/src/wasm/prepare.rs +++ b/frame/contracts/src/wasm/prepare.rs @@ -50,7 +50,7 @@ pub enum TryInstantiate { Instantiate, /// Skip the instantiation during preparation. /// - /// This makes sense when the preparation takes place as part of an instantation. Then + /// This makes sense when the preparation takes place as part of an instantiation. Then /// this instantiation would fail the whole transaction and an extra check is not /// necessary. Skip, @@ -376,7 +376,7 @@ fn get_memory_limits( }, } } else { - // If none memory imported then just crate an empty placeholder. + // If none memory imported then just create an empty placeholder. // Any access to it will lead to out of bounds trap. Ok((0, 0)) } @@ -412,7 +412,7 @@ where 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 + // process. Additionally, all instructions explicitly 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, diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index e80e2cde302fe..b30bad38bfce5 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -1336,7 +1336,7 @@ pub mod env { /// /// # Parameters /// - /// - `flags`: See `crate::wasm::runtime::CallFlags` for a documenation of the supported flags. + /// - `flags`: See `crate::wasm::runtime::CallFlags` for a documentation of the supported flags. /// - `callee_ptr`: a pointer to the address of the callee contract. Should be decodable as an /// `T::AccountId`. Traps otherwise. /// - `gas`: how much gas to devote to the execution. @@ -2038,7 +2038,7 @@ pub mod env { /// # Note /// /// The state rent functionality was removed. This is stub only exists for - /// backwards compatiblity + /// backwards compatibility #[prefixed_alias] #[deprecated] fn restore_to( @@ -2062,7 +2062,7 @@ pub mod env { /// # Note /// /// The state rent functionality was removed. This is stub only exists for - /// backwards compatiblity + /// backwards compatibility #[version(1)] #[prefixed_alias] #[deprecated] @@ -2084,7 +2084,7 @@ pub mod env { /// # Note /// /// The state rent functionality was removed. This is stub only exists for - /// backwards compatiblity. + /// backwards compatibility. #[prefixed_alias] #[deprecated] fn set_rent_allowance( @@ -2102,7 +2102,7 @@ pub mod env { /// # Note /// /// The state rent functionality was removed. This is stub only exists for - /// backwards compatiblity. + /// backwards compatibility. #[version(1)] #[prefixed_alias] #[deprecated] @@ -2116,7 +2116,7 @@ pub mod env { /// # Note /// /// The state rent functionality was removed. This is stub only exists for - /// backwards compatiblity. + /// backwards compatibility. #[prefixed_alias] #[deprecated] fn rent_allowance(ctx: _, memory: _, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> { @@ -2409,7 +2409,7 @@ pub mod env { /// /// # Return Value /// - /// Returns `ReturnCode::Success` when the dispatchable was succesfully executed and + /// Returns `ReturnCode::Success` when the dispatchable was successfully executed and /// returned `Ok`. When the dispatchable was exeuted but returned an error /// `ReturnCode::CallRuntimeFailed` is returned. The full error is not /// provided because it is not guaranteed to be stable. @@ -2603,7 +2603,7 @@ pub mod env { /// Returns a nonce that is unique per contract instantiation. /// - /// The nonce is incremented for each succesful contract instantiation. This is a + /// The nonce is incremented for each successful contract instantiation. This is a /// sensible default salt for contract instantiations. #[unstable] fn instantiation_nonce(ctx: _, _memory: _) -> Result { From 44c5c99880346d5b9d4874725500c03b30994774 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Fri, 17 Mar 2023 17:06:40 +0100 Subject: [PATCH 528/715] Ignore flaky test (#13631) * Ignore flaky test Signed-off-by: Oliver Tale-Yazdi * Re-enable running_the_node_works_and_can_be_interrupted Signed-off-by: Oliver Tale-Yazdi * Re-enable notifications_back_pressure Signed-off-by: Oliver Tale-Yazdi * Unused import Signed-off-by: Oliver Tale-Yazdi --------- Signed-off-by: Oliver Tale-Yazdi --- client/rpc-spec-v2/src/chain_head/tests.rs | 6 ++++++ client/service/test/src/client/mod.rs | 6 +++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/client/rpc-spec-v2/src/chain_head/tests.rs b/client/rpc-spec-v2/src/chain_head/tests.rs index fcd906dcf5be0..0110c97a05910 100644 --- a/client/rpc-spec-v2/src/chain_head/tests.rs +++ b/client/rpc-spec-v2/src/chain_head/tests.rs @@ -1024,6 +1024,9 @@ async fn follow_prune_best_block() { } #[tokio::test] +#[cfg(disable_flaky)] +#[allow(dead_code)] +// FIXME: https://github.com/paritytech/substrate/issues/11321 async fn follow_forks_pruned_block() { let builder = TestClientBuilder::new(); let backend = builder.backend(); @@ -1137,6 +1140,9 @@ async fn follow_forks_pruned_block() { } #[tokio::test] +#[cfg(disable_flaky)] +#[allow(dead_code)] +// FIXME: https://github.com/paritytech/substrate/issues/11321 async fn follow_report_multiple_pruned_block() { let builder = TestClientBuilder::new(); let backend = builder.backend(); diff --git a/client/service/test/src/client/mod.rs b/client/service/test/src/client/mod.rs index cae69413c7a02..96a0a8fe2a023 100644 --- a/client/service/test/src/client/mod.rs +++ b/client/service/test/src/client/mod.rs @@ -30,7 +30,7 @@ use sc_consensus::{ }; use sc_service::client::{new_in_mem, Client, LocalCallExecutor}; use sp_api::ProvideRuntimeApi; -use sp_consensus::{BlockOrigin, BlockStatus, Error as ConsensusError, SelectChain}; +use sp_consensus::{BlockOrigin, Error as ConsensusError, SelectChain}; use sp_core::{testing::TaskExecutor, traits::CallContext, H256}; use sp_runtime::{ generic::BlockId, @@ -1567,7 +1567,11 @@ fn respects_block_rules() { } #[test] +#[cfg(disable_flaky)] +#[allow(dead_code)] +// FIXME: https://github.com/paritytech/substrate/issues/11321 fn returns_status_for_pruned_blocks() { + use sc_consensus::BlockStatus; sp_tracing::try_init_simple(); let tmp = tempfile::tempdir().unwrap(); From bab32f81dd5f9261605b572595de6eb9c40cb0be Mon Sep 17 00:00:00 2001 From: Koute Date: Sat, 18 Mar 2023 01:09:28 +0900 Subject: [PATCH 529/715] Bump `trie-db` to 0.27.1 (fix storage iteration bug + change seek behavior with prefix) (#13630) --- Cargo.lock | 4 +- primitives/state-machine/Cargo.toml | 2 +- primitives/state-machine/src/trie_backend.rs | 119 ++++++++++++++++++- 3 files changed, 121 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index df0e54a3d7ecd..da100658bef9a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11653,9 +11653,9 @@ dependencies = [ [[package]] name = "trie-db" -version = "0.27.0" +version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d75c77ea43f2ad8ea9d9c58de49dfc9c3995bdef32b503df7883ff054e7f1" +checksum = "767abe6ffed88a1889671a102c2861ae742726f52e0a5a425b92c9fbfa7e9c85" dependencies = [ "hash-db", "hashbrown 0.13.2", diff --git a/primitives/state-machine/Cargo.toml b/primitives/state-machine/Cargo.toml index 9759547d7f384..cc780e51abcaf 100644 --- a/primitives/state-machine/Cargo.toml +++ b/primitives/state-machine/Cargo.toml @@ -33,7 +33,7 @@ array-bytes = "4.1" pretty_assertions = "1.2.1" rand = "0.8.5" sp-runtime = { version = "7.0.0", path = "../runtime" } -trie-db = "0.27.0" +trie-db = "0.27.1" assert_matches = "1.5" [features] diff --git a/primitives/state-machine/src/trie_backend.rs b/primitives/state-machine/src/trie_backend.rs index 10e2dfd16d66a..afbe6cbbea081 100644 --- a/primitives/state-machine/src/trie_backend.rs +++ b/primitives/state-machine/src/trie_backend.rs @@ -536,6 +536,29 @@ pub mod tests { (mdb, root) } + pub(crate) fn test_db_with_hex_keys( + state_version: StateVersion, + keys: &[&str], + ) -> (PrefixedMemoryDB, H256) { + let mut root = H256::default(); + let mut mdb = PrefixedMemoryDB::::default(); + match state_version { + StateVersion::V0 => { + let mut trie = TrieDBMutBuilderV0::new(&mut mdb, &mut root).build(); + for (index, key) in keys.iter().enumerate() { + trie.insert(&array_bytes::hex2bytes(key).unwrap(), &[index as u8]).unwrap(); + } + }, + StateVersion::V1 => { + let mut trie = TrieDBMutBuilderV1::new(&mut mdb, &mut root).build(); + for (index, key) in keys.iter().enumerate() { + trie.insert(&array_bytes::hex2bytes(key).unwrap(), &[index as u8]).unwrap(); + } + }, + }; + (mdb, root) + } + pub(crate) fn test_trie( hashed_value: StateVersion, cache: Option, @@ -549,6 +572,20 @@ pub mod tests { .build() } + pub(crate) fn test_trie_with_hex_keys( + hashed_value: StateVersion, + cache: Option, + recorder: Option, + keys: &[&str], + ) -> TrieBackend, BlakeTwo256> { + let (mdb, root) = test_db_with_hex_keys(hashed_value, keys); + + TrieBackendBuilder::new(mdb, root) + .with_optional_cache(cache) + .with_optional_recorder(recorder) + .build() + } + parameterized_test!(read_from_storage_returns_some, read_from_storage_returns_some_inner); fn read_from_storage_returns_some_inner( state_version: StateVersion, @@ -697,10 +734,25 @@ pub mod tests { ); // Fetch starting at a given key and with prefix which doesn't match that key. + // (Start *before* the prefix.) + assert_eq!( + trie.keys(IterArgs { + prefix: Some(b"value"), + start_at: Some(b"key"), + ..IterArgs::default() + }) + .unwrap() + .map(|result| result.unwrap()) + .collect::>(), + vec![b"value1".to_vec(), b"value2".to_vec(),] + ); + + // Fetch starting at a given key and with prefix which doesn't match that key. + // (Start *after* the prefix.) assert!(trie .keys(IterArgs { prefix: Some(b"value"), - start_at: Some(b"key"), + start_at: Some(b"vblue"), ..IterArgs::default() }) .unwrap() @@ -722,6 +774,71 @@ pub mod tests { ); } + // This test reproduces an actual real-world issue: https://github.com/polkadot-js/apps/issues/9103 + parameterized_test!( + storage_iter_does_not_return_out_of_prefix_keys, + storage_iter_does_not_return_out_of_prefix_keys_inner + ); + fn storage_iter_does_not_return_out_of_prefix_keys_inner( + state_version: StateVersion, + cache: Option, + recorder: Option, + ) { + let trie = test_trie_with_hex_keys(state_version, cache, recorder, &[ + "6cf4040bbce30824850f1a4823d8c65faeefaa25a5bae16a431719647c1d99da", + "6cf4040bbce30824850f1a4823d8c65ff536928ca5ba50039bc2766a48ddbbab", + "70f943199f1a2dde80afdaf3f447db834e7b9012096b41c4eb3aaf947f6ea429", + "7474449cca95dc5d0c00e71735a6d17d3cd15a3fd6e04e47bee3922dbfa92c8d007fc7effcb0c044a0c41fd8a77eb55d2133058a86d1f4d6f8e45612cd271eefd77f91caeaacfe011b8f41540e0a793b0fd51b245dae19382b45386570f2b545fab75e3277910f7324b55f47c29f9965e8298371404e50ac", + "7474449cca95dc5d0c00e71735a6d17d3cd15a3fd6e04e47bee3922dbfa92c8d0179c23cd593c770fde9fc7aa8f84b3e401e654b8986c67728844da0080ec9ee222b41a85708a471a511548302870b53f40813d8354b6d2969e1b7ca9e083ecf96f9647e004ecb41c7f26f0110f778bdb3d9da31bef323d9", + "7474449cca95dc5d0c00e71735a6d17d3cd15a3fd6e04e47bee3922dbfa92c8d024de296f88310247001277477f4ace4d0aa5685ea2928d518a807956e4806a656520d6520b8ac259f684aa0d91961d76f697716f04e6c997338d03560ab7d703829fe7b9d0e6d7eff8d8412fc428364c2f474a67b36586d", + "7474449cca95dc5d0c00e71735a6d17d3cd15a3fd6e04e47bee3922dbfa92c8d13dc5d83f2361c14d05933eb3182a92ac14665718569703baf1da25c7d571843b6489f03d8549c87bfa5709836ba729443c319659e83ad5ee133e6f11af51d883e56216e9e1bbb1e2920c7c6120cbb55cd469b1f95b61601", + "7474449cca95dc5d0c00e71735a6d17d3cd15a3fd6e04e47bee3922dbfa92c8d1786d20bbb4b91eb1f5765432d750bd0111a0807c8d04f05110ffaf73f4fa7b360422c13bc97efc3a2324d9fa8f954b424c0bcfce7236a2e8107dd31c2042a9860a964f8472fda49749dec3f146e81470b55aa0f3930d854", + "7474449cca95dc5d0c00e71735a6d17d3cd15a3fd6e04e47bee3922dbfa92c8d18c246484ec5335a40903e7cd05771be7c0b8459333f1ae2925c3669fc3e5accd0f38c4711a15544bfa5709836ba729443c319659e83ad5ee133e6f11af51d883e56216e9e1bbb1e2920c7c6120cbb55cd469b1f95b61601", + "7474449cca95dc5d0c00e71735a6d17d3cd15a3fd6e04e47bee3922dbfa92c8d1aca749033252ce75245528397430d14cb8e8c09248d81ee5de00b6ae93ee880b6d19a595e6dc106bfa5709836ba729443c319659e83ad5ee133e6f11af51d883e56216e9e1bbb1e2920c7c6120cbb55cd469b1f95b61601", + "7474449cca95dc5d0c00e71735a6d17d3cd15a3fd6e04e47bee3922dbfa92c8d1d6bceb91bc07973e7b3296f83af9f1c4300ce9198cc3b44c54dafddb58f4a43aee44a9bef1a2e9dbfa5709836ba729443c319659e83ad5ee133e6f11af51d883e56216e9e1bbb1e2920c7c6120cbb55cd469b1f95b61601", + "7474449cca95dc5d0c00e71735a6d17d3cd15a3fd6e04e47bee3922dbfa92c8d203383772f45721232139e1a8863b0f2f8d480bdc15bcc1f2033cf467e137059558da743838f6b58bfa5709836ba729443c319659e83ad5ee133e6f11af51d883e56216e9e1bbb1e2920c7c6120cbb55cd469b1f95b61601", + "7474449cca95dc5d0c00e71735a6d17d3cd15a3fd6e04e47bee3922dbfa92c8d2197cc5c3eb3a6a67538e0dc3eaaf8c820d71310d377499c4a5d276381789e0a234475e69cddf709d207458083d6146d3a36fce7f1fe05b232702bf154096e5e3a8c378bdc237d7a27909acd663563917f0f70bb0e8e61a3", + "7474449cca95dc5d0c00e71735a6d17d3cd15a3fd6e04e47bee3922dbfa92c8d4f19c117f2ea36100f753c4885aa8d63b4d65a0dc32106f829f89eeabd52c37105c9bdb75f752469729fa3f0e7d907c1d949192c8e264a1a510c32abe3a05ed50be2262d5bfb981673ec80a07fd2ce28c7f27cd0043a788c", + "7474449cca95dc5d0c00e71735a6d17d3cd15a3fd6e04e47bee3922dbfa92c8d547d5aaa651bafa63d077560dfe823ac75665ebf1dcfd96a06e45499f03dda31282977706918d4821b8f41540e0a793b0fd51b245dae19382b45386570f2b545fab75e3277910f7324b55f47c29f9965e8298371404e50ac", + "7474449cca95dc5d0c00e71735a6d17d3cd15a3fd6e04e47bee3922dbfa92c8d6037207d54d69a082ea225ab4a412e4b87d6f5612053b07c405cf05ea25e482a4908c0713be2998abfa5709836ba729443c319659e83ad5ee133e6f11af51d883e56216e9e1bbb1e2920c7c6120cbb55cd469b1f95b61601", + "7474449cca95dc5d0c00e71735a6d17d3cd15a3fd6e04e47bee3922dbfa92c8d63d0920de0c7315ebaed1d639d926961d28af89461c31eca890441e449147d23bb7c9d4fc42d7c16bfa5709836ba729443c319659e83ad5ee133e6f11af51d883e56216e9e1bbb1e2920c7c6120cbb55cd469b1f95b61601", + "7474449cca95dc5d0c00e71735a6d17d3cd15a3fd6e04e47bee3922dbfa92c8d7912c66be82a5972e5bc11c8d10551a296ba9aaff8ca6ab22a8cd1987974b87a97121c871f786d2e17e0a629acf01c38947f170b7e02a9ebb4ee60f83779acb99b71114c01a4f0a60694611a1502c399c77214ffa26e955b", + "7474449cca95dc5d0c00e71735a6d17d3cd15a3fd6e04e47bee3922dbfa92c8d7aa00f217f3a374a2f1ca0f388719f84099e8157a8a83c5ccf54eae1617f93933fa976baa629e6febfa5709836ba729443c319659e83ad5ee133e6f11af51d883e56216e9e1bbb1e2920c7c6120cbb55cd469b1f95b61601", + "7474449cca95dc5d0c00e71735a6d17d3cd15a3fd6e04e47bee3922dbfa92c8d9e1c3c8ab41943cf377b1aa724d7f518a3cfc96a732bdc4658155d09ed2bfc31b5ccbc6d8646b59f1b8f41540e0a793b0fd51b245dae19382b45386570f2b545fab75e3277910f7324b55f47c29f9965e8298371404e50ac", + "7474449cca95dc5d0c00e71735a6d17d3cd15a3fd6e04e47bee3922dbfa92c8d9fb8d6d95d5214a3305a4fa07e344eb99fad4be3565d646c8ac5af85514d9c96702c9c207be234958dbdb9185f467d2be3b84e8b2f529f7ec3844b378a889afd6bd31a9b5ed22ffee2019ad82c6692f1736dd41c8bb85726", + "7474449cca95dc5d0c00e71735a6d17d3cd15a3fd6e04e47bee3922dbfa92c8d9fb8d6d95d5214a3305a4fa07e344eb99fad4be3565d646c8ac5af85514d9c96702c9c207be23495ec1caa509591a36a8403684384ce40838c9bd7fc49d933a10d3b26e979273e2f17ebf0bf41cd90e4287e126a59d5a243", + "7474449cca95dc5d0c00e71735a6d17d3cd15a3fd6e04e47bee3922dbfa92c8da7fc066aae2ffe03b36e9a72f9a39cb2befac7e47f320309f31f1c1676288d9596045807304b3d79bfa5709836ba729443c319659e83ad5ee133e6f11af51d883e56216e9e1bbb1e2920c7c6120cbb55cd469b1f95b61601", + "7474449cca95dc5d0c00e71735a6d17d3cd15a3fd6e04e47bee3922dbfa92c8daf3c377b0fddf7c7ad6d390fab0ab45ac16c21645be880af5cab2fbbeb04820401a4c9f766c17bef9fc14a2e16ade86fe26ee81d4497dc6aab81cc5f5bb0458d6149a763ecb09aefec06950dd61db1ba025401d2a04e3b9d", + "7474449cca95dc5d0c00e71735a6d17d3cd15a3fd6e04e47bee3922dbfa92c8daf3c377b0fddf7c7ad6d390fab0ab45ac16c21645be880af5cab2fbbeb04820401a4c9f766c17befbfa5709836ba729443c319659e83ad5ee133e6f11af51d883e56216e9e1bbb1e2920c7c6120cbb55cd469b1f95b61601", + "7474449cca95dc5d0c00e71735a6d17d3cd15a3fd6e04e47bee3922dbfa92c8db60505ba8b77ef03ed805436d3242f26dc828084b12aaf4bcb96af468816a182b5360149398aad6b1dafe949b0918138ceef924f6393d1818a04842301294604972da17b24b31b155e4409a01273733b8d21a156c2e7eb71", + "7474449cca95dc5d0c00e71735a6d17d3cd15a3fd6e04e47bee3922dbfa92c8dbd27136a6e028656073cc840bfabb48fe935880c4c4c990ee98458b2fed308e9765f7f7f717dd3b2862fa5361d3b55afa6040e582687403c852b2d065b24f253276cc581226991f8e1818a78fc64c39da7f0b383c6726e0f", + "7474449cca95dc5d0c00e71735a6d17d3cd15a3fd6e04e47bee3922dbfa92c8dca40d91320edd326500f9e8b5a0b23a8bdf21549f98f0e014f66b6a18bdd78e337a6c05d670c80c88a55d4c7bb6fbae546e2d03ac9ab16e85fe11dad6adfd6a20618905477b831d7d48ca32d0bfd2bdc8dbeba26ffe2c710", + "7474449cca95dc5d0c00e71735a6d17d3cd15a3fd6e04e47bee3922dbfa92c8dd27478512243ed62c1c1f7066021798a464d4cf9099546d5d9907b3369f1b9d7a5aa5d60ca845619bfa5709836ba729443c319659e83ad5ee133e6f11af51d883e56216e9e1bbb1e2920c7c6120cbb55cd469b1f95b61601", + "7474449cca95dc5d0c00e71735a6d17d3cd15a3fd6e04e47bee3922dbfa92c8de6da5659cbbe1489abbe99c4d3a474f4d1e78edb55a9be68d8f52c6fe730388a298e6f6325db3da7bfa5709836ba729443c319659e83ad5ee133e6f11af51d883e56216e9e1bbb1e2920c7c6120cbb55cd469b1f95b61601", + "7474449cca95dc5d0c00e71735a6d17d3cd15a3fd6e04e47bee3922dbfa92c8de6da5659cbbe1489abbe99c4d3a474f4d1e78edb55a9be68d8f52c6fe730388a298e6f6325db3da7e94ca3e8c297d82f71e232a2892992d1f6480475fb797ce64e58f773d8fafd9fbcee4bdf4b14f2a71b6d3a428cf9f24b", + "7474449cca95dc5d0c00e71735a6d17d3cd15a3fd6e04e47bee3922dbfa92c8decdd1760c61ff7234f2876dbe817af803170233320d778b92043b2359e3de6d16c9e5359f6302da31c84d6f551ad2a831263ef956f0cdb3b4810cefcb2d0b57bcce7b82007016ae4fe752c31d1a01b589a7966cea03ec65c", + "7474449cca95dc5d0c00e71735a6d17d3cd15a3fd6e04e47bee3922dbfa92c8df9981ee6b69eb7af2153af34f39ffc06e2daa5272c99798c8849091284dc8905f2a76b65754c2089bfa5709836ba729443c319659e83ad5ee133e6f11af51d883e56216e9e1bbb1e2920c7c6120cbb55cd469b1f95b61601", + "7474449cca95dc5d0c00e71735a6d17d4e7b9012096b41c4eb3aaf947f6ea429", + "89d139e01a5eb2256f222e5fc5dbe6b33c9c1284130706f5aea0c8b3d4c54d89", + "89d139e01a5eb2256f222e5fc5dbe6b36254e9d55588784fa2a62b726696e2b1" + ]); + + let key = array_bytes::hex2bytes("7474449cca95dc5d0c00e71735a6d17d3cd15a3fd6e04e47bee3922dbfa92c8da7dad55cf08ffe8194efa962146801b0503092b1ed6a3fa6aee9107334aefd7965bbe568c3d24c6d").unwrap(); + + assert_eq!( + trie.keys(IterArgs { + prefix: Some(&key), + start_at: Some(&key), + start_at_exclusive: true, + ..IterArgs::default() + }) + .unwrap() + .map(|result| result.unwrap()) + .collect::>(), + Vec::>::new() + ); + } + parameterized_test!(storage_root_is_non_default, storage_root_is_non_default_inner); fn storage_root_is_non_default_inner( state_version: StateVersion, From d574cb75ce70148f5e082201beaef24b5a00741e Mon Sep 17 00:00:00 2001 From: PG Herveou Date: Fri, 17 Mar 2023 23:17:21 +0100 Subject: [PATCH 530/715] contracts: Refactor `trait Ext::*_storage_transparent` functions (#13600) * Refactor _transparent methods rewrote commits, stashed the typo changes to remove some diff noise fixed my unverified email commit * remove type alias * Get rid of From impl blocks * Get rid of KeyType impl block * remove unnecessary Key export * Update frame/contracts/src/exec.rs Co-authored-by: Sasha Gryaznov * PR review comment --------- Co-authored-by: Sasha Gryaznov --- bin/node/executor/tests/basic.rs | 6 +- frame/contracts/src/benchmarking/mod.rs | 28 +-- frame/contracts/src/exec.rs | 267 ++++++++++-------------- frame/contracts/src/lib.rs | 8 +- frame/contracts/src/storage.rs | 10 +- frame/contracts/src/tests.rs | 6 +- frame/contracts/src/wasm/mod.rs | 68 ++---- frame/contracts/src/wasm/runtime.rs | 103 ++++----- 8 files changed, 200 insertions(+), 296 deletions(-) diff --git a/bin/node/executor/tests/basic.rs b/bin/node/executor/tests/basic.rs index ecfe02aa41596..9200fe735be41 100644 --- a/bin/node/executor/tests/basic.rs +++ b/bin/node/executor/tests/basic.rs @@ -710,11 +710,7 @@ 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, - pallet_contracts::StorageKey::::default().to_vec() - ) - .is_ok()); + assert!(&pallet_contracts::Pallet::::get_storage(addr, vec![]).is_ok()); }); } diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index 96368ebb3f604..2fb033cf85d8c 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, FixSizedKey, VarSizedKey}, + exec::{AccountIdOf, Key}, wasm::CallFlags, Pallet as Contracts, *, }; @@ -135,10 +135,10 @@ where } /// Store the supplied storage items into this contracts storage. - fn store(&self, items: &Vec<(FixSizedKey, Vec)>) -> Result<(), &'static str> { + fn store(&self, items: &Vec<([u8; 32], Vec)>) -> Result<(), &'static str> { let info = self.info()?; for item in items { - info.write(&item.0 as &FixSizedKey, Some(item.1.clone()), None, false) + info.write(&Key::Fix(item.0), Some(item.1.clone()), None, false) .map_err(|_| "Failed to write storage to restoration dest")?; } >::insert(&self.account_id, info); @@ -1044,7 +1044,7 @@ benchmarks! { let info = instance.info()?; for key in keys { info.write( - &VarSizedKey::::try_from(key).map_err(|e| "Key has wrong length")?, + &Key::::try_from_var(key).map_err(|e| "Key has wrong length")?, Some(vec![]), None, false, @@ -1088,7 +1088,7 @@ benchmarks! { let instance = Contract::::new(code, vec![])?; let info = instance.info()?; info.write( - &VarSizedKey::::try_from(key).map_err(|e| "Key has wrong length")?, + &Key::::try_from_var(key).map_err(|e| "Key has wrong length")?, Some(vec![]), None, false, @@ -1131,7 +1131,7 @@ benchmarks! { let instance = Contract::::new(code, vec![])?; let info = instance.info()?; info.write( - &VarSizedKey::::try_from(key).map_err(|e| "Key has wrong length")?, + &Key::::try_from_var(key).map_err(|e| "Key has wrong length")?, Some(vec![42u8; n as usize]), None, false, @@ -1180,7 +1180,7 @@ benchmarks! { let info = instance.info()?; for key in keys { info.write( - &VarSizedKey::::try_from(key).map_err(|e| "Key has wrong length")?, + &Key::::try_from_var(key).map_err(|e| "Key has wrong length")?, Some(vec![]), None, false, @@ -1223,7 +1223,7 @@ benchmarks! { let instance = Contract::::new(code, vec![])?; let info = instance.info()?; info.write( - &VarSizedKey::::try_from(key).map_err(|e| "Key has wrong length")?, + &Key::::try_from_var(key).map_err(|e| "Key has wrong length")?, Some(vec![42u8; n as usize]), None, false, @@ -1276,7 +1276,7 @@ benchmarks! { let info = instance.info()?; for key in keys { info.write( - &VarSizedKey::::try_from(key).map_err(|e| "Key has wrong length")?, + &Key::::try_from_var(key).map_err(|e| "Key has wrong length")?, Some(vec![]), None, false, @@ -1325,7 +1325,7 @@ benchmarks! { let instance = Contract::::new(code, vec![])?; let info = instance.info()?; info.write( - &VarSizedKey::::try_from(key).map_err(|e| "Key has wrong length")?, + &Key::::try_from_var(key).map_err(|e| "Key has wrong length")?, Some(vec![42u8; n as usize]), None, false, @@ -1373,7 +1373,7 @@ benchmarks! { let info = instance.info()?; for key in keys { info.write( - &VarSizedKey::::try_from(key).map_err(|e| "Key has wrong length")?, + &Key::::try_from_var(key).map_err(|e| "Key has wrong length")?, Some(vec![]), None, false, @@ -1416,7 +1416,7 @@ benchmarks! { let instance = Contract::::new(code, vec![])?; let info = instance.info()?; info.write( - &VarSizedKey::::try_from(key).map_err(|e| "Key has wrong length")?, + &Key::::try_from_var(key).map_err(|e| "Key has wrong length")?, Some(vec![42u8; n as usize]), None, false, @@ -1469,7 +1469,7 @@ benchmarks! { let info = instance.info()?; for key in keys { info.write( - &VarSizedKey::::try_from(key).map_err(|e| "Key has wrong length")?, + &Key::::try_from_var(key).map_err(|e| "Key has wrong length")?, Some(vec![]), None, false, @@ -1518,7 +1518,7 @@ benchmarks! { let instance = Contract::::new(code, vec![])?; let info = instance.info()?; info.write( - &VarSizedKey::::try_from(key).map_err(|e| "Key has wrong length")?, + &Key::::try_from_var(key).map_err(|e| "Key has wrong length")?, Some(vec![42u8; n as usize]), None, false, diff --git a/frame/contracts/src/exec.rs b/frame/contracts/src/exec.rs index 35ef43da5ed40..bd63c524c6152 100644 --- a/frame/contracts/src/exec.rs +++ b/frame/contracts/src/exec.rs @@ -35,7 +35,7 @@ use smallvec::{Array, SmallVec}; use sp_core::ecdsa::Public as ECDSAPublic; use sp_io::{crypto::secp256k1_ecdsa_recover_compressed, hashing::blake2_256}; use sp_runtime::traits::{Convert, Hash}; -use sp_std::{marker::PhantomData, mem, prelude::*}; +use sp_std::{marker::PhantomData, mem, prelude::*, vec::Vec}; pub type AccountIdOf = ::AccountId; pub type MomentOf = <::Time as Time>::Moment; @@ -46,32 +46,39 @@ 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; +type VarSizedKey = BoundedVec::MaxStorageKeyLen>; + +/// Combined key type for both fixed and variable sized storage keys. +pub enum Key { + /// Variant for fixed sized keys. + Fix([u8; 32]), + /// Variant for variable sized keys. + Var(VarSizedKey), } -impl StorageKey for FixSizedKey { - fn hash(&self) -> Vec { - blake2_256(self.as_slice()).to_vec() +impl Key { + /// Copies self into a new vec. + pub fn to_vec(&self) -> Vec { + match self { + Key::Fix(v) => v.to_vec(), + Key::Var(v) => v.to_vec(), + } } -} -impl StorageKey for VarSizedKey -where - T: Config, -{ - fn hash(&self) -> Vec { - Blake2_128Concat::hash(self.as_slice()) + pub fn hash(&self) -> Vec { + match self { + Key::Fix(v) => blake2_256(v.as_slice()).to_vec(), + Key::Var(v) => Blake2_128Concat::hash(v.as_slice()), + } + } + + pub fn try_from_fix(v: Vec) -> Result> { + <[u8; 32]>::try_from(v).map(Self::Fix) + } + + pub fn try_from_var(v: Vec) -> Result> { + VarSizedKey::::try_from(v).map(Self::Var) } } @@ -169,44 +176,19 @@ 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: &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>; + fn get_storage(&mut self, key: &Key) -> 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: &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; + fn get_storage_size(&mut self, key: &Key) -> 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: &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, + key: &Key, value: Option>, take_old: bool, ) -> Result; @@ -1236,46 +1218,23 @@ where Self::transfer(ExistenceRequirement::KeepAlive, &self.top_frame().account_id, to, value) } - fn get_storage(&mut self, key: &FixSizedKey) -> Option> { - self.top_frame_mut().contract_info().read(key) - } - - fn get_storage_transparent(&mut self, key: &VarSizedKey) -> Option> { + fn get_storage(&mut self, key: &Key) -> Option> { self.top_frame_mut().contract_info().read(key) } - fn get_storage_size(&mut self, key: &FixSizedKey) -> Option { - self.top_frame_mut().contract_info().size(key) - } - - fn get_storage_size_transparent(&mut self, key: &VarSizedKey) -> Option { - self.top_frame_mut().contract_info().size(key) + fn get_storage_size(&mut self, key: &Key) -> Option { + self.top_frame_mut().contract_info().size(key.into()) } fn set_storage( &mut self, - key: &FixSizedKey, + key: &Key, value: Option>, take_old: bool, ) -> Result { let frame = self.top_frame_mut(); frame.contract_info.get(&frame.account_id).write( - 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(); - frame.contract_info.get(&frame.account_id).write( - key, + key.into(), value, Some(&mut frame.nested_storage), take_old, @@ -1688,7 +1647,7 @@ mod tests { 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 mut storage_meter = storage::meter::Meter::new(&origin, Some(0), value).unwrap(); let _ = MockStack::run_call( origin.clone(), @@ -2986,35 +2945,41 @@ 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(&Key::Fix([1; 32]), Some(vec![1, 2, 3]), false), + Ok(WriteOutcome::New) + ); + assert_eq!( + ctx.ext.set_storage(&Key::Fix([2; 32]), Some(vec![4, 5, 6]), true), + Ok(WriteOutcome::New) + ); + assert_eq!(ctx.ext.set_storage(&Key::Fix([3; 32]), None, false), Ok(WriteOutcome::New)); + assert_eq!(ctx.ext.set_storage(&Key::Fix([4; 32]), None, true), Ok(WriteOutcome::New)); + assert_eq!( + ctx.ext.set_storage(&Key::Fix([5; 32]), Some(vec![]), false), Ok(WriteOutcome::New) ); assert_eq!( - ctx.ext.set_storage(&[2; 32], Some(vec![4, 5, 6]), true), + ctx.ext.set_storage(&Key::Fix([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(&Key::Fix([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(&Key::Fix([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(&Key::Fix([3; 32]), None, false), Ok(WriteOutcome::New)); + assert_eq!(ctx.ext.set_storage(&Key::Fix([4; 32]), None, true), Ok(WriteOutcome::New)); assert_eq!( - ctx.ext.set_storage(&[5; 32], Some(vec![]), false), + ctx.ext.set_storage(&Key::Fix([5; 32]), Some(vec![]), false), Ok(WriteOutcome::Overwritten(0)) ); assert_eq!( - ctx.ext.set_storage(&[6; 32], Some(vec![]), true), + ctx.ext.set_storage(&Key::Fix([6; 32]), Some(vec![]), true), Ok(WriteOutcome::Taken(vec![])) ); @@ -3043,52 +3008,52 @@ mod tests { } #[test] - fn set_storage_transparent_works() { + fn set_storage_varsized_key_works() { let code_hash = MockLoader::insert(Call, |ctx, _| { // Write assert_eq!( - ctx.ext.set_storage_transparent( - &VarSizedKey::::try_from([1; 64].to_vec()).unwrap(), + ctx.ext.set_storage( + &Key::::try_from_var([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(), + ctx.ext.set_storage( + &Key::::try_from_var([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(), + ctx.ext.set_storage( + &Key::::try_from_var([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(), + ctx.ext.set_storage( + &Key::::try_from_var([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(), + ctx.ext.set_storage( + &Key::::try_from_var([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(), + ctx.ext.set_storage( + &Key::::try_from_var([6; 128].to_vec()).unwrap(), Some(vec![]), true ), @@ -3097,48 +3062,48 @@ mod tests { // Overwrite assert_eq!( - ctx.ext.set_storage_transparent( - &VarSizedKey::::try_from([1; 64].to_vec()).unwrap(), + ctx.ext.set_storage( + &Key::::try_from_var([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(), + ctx.ext.set_storage( + &Key::::try_from_var([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(), + ctx.ext.set_storage( + &Key::::try_from_var([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(), + ctx.ext.set_storage( + &Key::::try_from_var([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(), + ctx.ext.set_storage( + &Key::::try_from_var([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(), + ctx.ext.set_storage( + &Key::::try_from_var([6; 128].to_vec()).unwrap(), Some(vec![]), true ), @@ -3173,13 +3138,16 @@ mod tests { 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), + ctx.ext.set_storage(&Key::Fix([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); + assert_eq!( + ctx.ext.set_storage(&Key::Fix([2; 32]), Some(vec![]), false), + Ok(WriteOutcome::New) + ); + assert_eq!(ctx.ext.get_storage(&Key::Fix([1; 32])), Some(vec![1, 2, 3])); + assert_eq!(ctx.ext.get_storage(&Key::Fix([2; 32])), Some(vec![])); + assert_eq!(ctx.ext.get_storage(&Key::Fix([3; 32])), None); exec_success() }); @@ -3209,13 +3177,16 @@ mod tests { 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(&Key::Fix([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_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); + assert_eq!( + ctx.ext.set_storage(&Key::Fix([2; 32]), Some(vec![]), false), + Ok(WriteOutcome::New) + ); + assert_eq!(ctx.ext.get_storage_size(&Key::Fix([1; 32])), Some(3)); + assert_eq!(ctx.ext.get_storage_size(&Key::Fix([2; 32])), Some(0)); + assert_eq!(ctx.ext.get_storage_size(&Key::Fix([3; 32])), None); exec_success() }); @@ -3242,40 +3213,34 @@ mod tests { } #[test] - fn get_storage_transparent_works() { + fn get_storage_varsized_key_works() { let code_hash = MockLoader::insert(Call, |ctx, _| { assert_eq!( - ctx.ext.set_storage_transparent( - &VarSizedKey::::try_from([1; 19].to_vec()).unwrap(), + ctx.ext.set_storage( + &Key::::try_from_var([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(), + ctx.ext.set_storage( + &Key::::try_from_var([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() - ), + ctx.ext.get_storage(&Key::::try_from_var([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() - ), + ctx.ext.get_storage(&Key::::try_from_var([2; 16].to_vec()).unwrap()), Some(vec![]) ); assert_eq!( - ctx.ext.get_storage_transparent( - &VarSizedKey::::try_from([3; 8].to_vec()).unwrap() - ), + ctx.ext.get_storage(&Key::::try_from_var([3; 8].to_vec()).unwrap()), None ); @@ -3304,40 +3269,34 @@ mod tests { } #[test] - fn get_storage_size_transparent_works() { + fn get_storage_size_varsized_key_works() { let code_hash = MockLoader::insert(Call, |ctx, _| { assert_eq!( - ctx.ext.set_storage_transparent( - &VarSizedKey::::try_from([1; 19].to_vec()).unwrap(), + ctx.ext.set_storage( + &Key::::try_from_var([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(), + ctx.ext.set_storage( + &Key::::try_from_var([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() - ), + ctx.ext.get_storage_size(&Key::::try_from_var([1; 19].to_vec()).unwrap()), Some(3) ); assert_eq!( - ctx.ext.get_storage_size_transparent( - &VarSizedKey::::try_from([2; 16].to_vec()).unwrap() - ), + ctx.ext.get_storage_size(&Key::::try_from_var([2; 16].to_vec()).unwrap()), Some(0) ); assert_eq!( - ctx.ext.get_storage_size_transparent( - &VarSizedKey::::try_from([3; 8].to_vec()).unwrap() - ), + ctx.ext.get_storage_size(&Key::::try_from_var([3; 8].to_vec()).unwrap()), None ); diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index 0aff18fd62083..7aac94d11148b 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -100,7 +100,7 @@ pub mod weights; mod tests; use crate::{ - exec::{AccountIdOf, ErrorOrigin, ExecError, Executable, Stack as ExecStack}, + exec::{AccountIdOf, ErrorOrigin, ExecError, Executable, Key, Stack as ExecStack}, gas::GasMeter, storage::{meter::Meter as StorageMeter, ContractInfo, DeletedContract}, wasm::{OwnerInfo, PrefabWasmModule, TryInstantiate}, @@ -131,7 +131,7 @@ use sp_std::{fmt::Debug, marker::PhantomData, prelude::*}; pub use crate::{ address::{AddressGenerator, DefaultAddressGenerator}, - exec::{Frame, VarSizedKey as StorageKey}, + exec::Frame, migration::Migration, pallet::*, schedule::{HostFnWeights, InstructionWeights, Limits, Schedule}, @@ -1265,7 +1265,9 @@ impl Pallet { ContractInfoOf::::get(&address).ok_or(ContractAccessError::DoesntExist)?; let maybe_value = contract_info.read( - &StorageKey::::try_from(key).map_err(|_| ContractAccessError::KeyDecodingFailed)?, + &Key::::try_from_var(key) + .map_err(|_| ContractAccessError::KeyDecodingFailed)? + .into(), ); Ok(maybe_value) } diff --git a/frame/contracts/src/storage.rs b/frame/contracts/src/storage.rs index 26162b55ca393..19c5f391d670b 100644 --- a/frame/contracts/src/storage.rs +++ b/frame/contracts/src/storage.rs @@ -20,7 +20,7 @@ pub mod meter; use crate::{ - exec::{AccountIdOf, StorageKey}, + exec::{AccountIdOf, Key}, weights::WeightInfo, AddressGenerator, BalanceOf, CodeHash, Config, ContractInfoOf, DeletionQueue, Error, Pallet, TrieId, SENTINEL, @@ -132,7 +132,7 @@ impl ContractInfo { /// /// 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>(&self, key: &K) -> Option> { + pub fn read(&self, key: &Key) -> Option> { child::get_raw(&self.child_trie_info(), key.hash().as_slice()) } @@ -140,7 +140,7 @@ impl ContractInfo { /// /// Returns `None` if the `key` wasn't previously set by `set_storage` or /// was deleted. - pub fn size>(&self, key: &K) -> Option { + pub fn size(&self, key: &Key) -> Option { child::len(&self.child_trie_info(), key.hash().as_slice()) } @@ -151,9 +151,9 @@ impl ContractInfo { /// /// 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( &self, - key: &K, + key: &Key, new_value: Option>, storage_meter: Option<&mut meter::NestedMeter>, take: bool, diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index ba9873f07efee..30a39eebfcfdd 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -21,7 +21,7 @@ use crate::{ ChainExtension, Environment, Ext, InitState, RegisteredChainExtension, Result as ExtensionResult, RetVal, ReturnFlags, SysConfig, }, - exec::{FixSizedKey, Frame}, + exec::{Frame, Key}, tests::test_utils::{get_contract, get_contract_checked}, wasm::{Determinism, PrefabWasmModule, ReturnCode as RuntimeReturnCode}, weights::WeightInfo, @@ -2145,7 +2145,7 @@ fn lazy_removal_partial_remove_works() { // Put value into the contracts child trie for val in &vals { - info.write(&val.0 as &FixSizedKey, Some(val.2.clone()), None, false).unwrap(); + info.write(&Key::Fix(val.0), Some(val.2.clone()), None, false).unwrap(); } >::insert(&addr, info.clone()); @@ -2330,7 +2330,7 @@ fn lazy_removal_does_not_use_all_weight() { // Put value into the contracts child trie for val in &vals { - info.write(&val.0 as &FixSizedKey, Some(val.2.clone()), None, false).unwrap(); + info.write(&Key::Fix(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 f74df2c361442..cfda9c37611b9 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -366,10 +366,7 @@ impl Executable for PrefabWasmModule { mod tests { use super::*; use crate::{ - exec::{ - AccountIdOf, BlockNumberOf, ErrorOrigin, ExecError, Executable, Ext, FixSizedKey, - SeedOf, VarSizedKey, - }, + exec::{AccountIdOf, BlockNumberOf, ErrorOrigin, ExecError, Executable, Ext, Key, SeedOf}, gas::GasMeter, storage::WriteOutcome, tests::{RuntimeCall, Test, ALICE, BOB}, @@ -521,40 +518,15 @@ mod tests { self.terminations.push(TerminationEntry { beneficiary: beneficiary.clone() }); Ok(()) } - fn get_storage(&mut self, key: &FixSizedKey) -> Option> { + fn get_storage(&mut self, key: &Key) -> Option> { self.storage.get(&key.to_vec()).cloned() } - 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 { + fn get_storage_size(&mut self, key: &Key) -> Option { self.storage.get(&key.to_vec()).map(|val| val.len() as u32) } fn set_storage( &mut self, - key: &FixSizedKey, - 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) => - 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, + key: &Key, value: Option>, take_old: bool, ) -> Result { @@ -1071,14 +1043,14 @@ mod tests { "#; let mut ext = MockExt::default(); - ext.set_storage_transparent( - &VarSizedKey::::try_from([1u8; 64].to_vec()).unwrap(), + ext.set_storage( + &Key::::try_from_var([1u8; 64].to_vec()).unwrap(), Some(vec![42u8]), false, ) .unwrap(); - ext.set_storage_transparent( - &VarSizedKey::::try_from([2u8; 19].to_vec()).unwrap(), + ext.set_storage( + &Key::::try_from_var([2u8; 19].to_vec()).unwrap(), Some(vec![]), false, ) @@ -2547,15 +2519,15 @@ mod tests { let mut ext = MockExt::default(); - ext.set_storage_transparent( - &VarSizedKey::::try_from([1u8; 64].to_vec()).unwrap(), + ext.set_storage( + &Key::::try_from_var([1u8; 64].to_vec()).unwrap(), Some(vec![42u8]), false, ) .unwrap(); - ext.set_storage_transparent( - &VarSizedKey::::try_from([2u8; 19].to_vec()).unwrap(), + ext.set_storage( + &Key::::try_from_var([2u8; 19].to_vec()).unwrap(), Some(vec![]), false, ) @@ -2631,14 +2603,14 @@ mod tests { let mut ext = MockExt::default(); - ext.set_storage_transparent( - &VarSizedKey::::try_from([1u8; 64].to_vec()).unwrap(), + ext.set_storage( + &Key::::try_from_var([1u8; 64].to_vec()).unwrap(), Some(vec![42u8]), false, ) .unwrap(); - ext.set_storage_transparent( - &VarSizedKey::::try_from([2u8; 19].to_vec()).unwrap(), + ext.set_storage( + &Key::::try_from_var([2u8; 19].to_vec()).unwrap(), Some(vec![]), false, ) @@ -2728,15 +2700,15 @@ mod tests { let mut ext = MockExt::default(); - ext.set_storage_transparent( - &VarSizedKey::::try_from([1u8; 64].to_vec()).unwrap(), + ext.set_storage( + &Key::::try_from_var([1u8; 64].to_vec()).unwrap(), Some(vec![42u8]), false, ) .unwrap(); - ext.set_storage_transparent( - &VarSizedKey::::try_from([2u8; 19].to_vec()).unwrap(), + ext.set_storage( + &Key::::try_from_var([2u8; 19].to_vec()).unwrap(), Some(vec![]), false, ) diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index b30bad38bfce5..a8a19e6f95150 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -18,7 +18,7 @@ //! Environment definition of the wasm smart-contract runtime. use crate::{ - exec::{ExecError, ExecResult, Ext, FixSizedKey, TopicOf, VarSizedKey}, + exec::{ExecError, ExecResult, Ext, Key, TopicOf}, gas::{ChargedAmount, Token}, schedule::HostFnWeights, BalanceOf, CodeHash, Config, DebugBufferVec, Error, SENTINEL, @@ -73,19 +73,7 @@ enum KeyType { 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) - }, - } - } + Var(u32), } /// Every error that can be returned to a contract when it calls any of the host functions. @@ -752,6 +740,29 @@ impl<'a, E: Ext + 'a> Runtime<'a, E> { (err, _) => Self::err_into_return_code(err), } } + fn decode_key( + &self, + memory: &[u8], + key_type: KeyType, + key_ptr: u32, + ) -> Result, TrapReason> { + let res = match key_type { + KeyType::Fix => { + let key = self.read_sandbox_memory(memory, key_ptr, 32u32)?; + Key::try_from_fix(key) + }, + KeyType::Var(len) => { + ensure!( + len <= <::T as Config>::MaxStorageKeyLen::get(), + Error::::DecodingFailed + ); + let key = self.read_sandbox_memory(memory, key_ptr, len)?; + Key::try_from_var(key) + }, + }; + + res.map_err(|_| Error::::DecodingFailed.into()) + } fn set_storage( &mut self, @@ -767,20 +778,9 @@ impl<'a, E: Ext + 'a> Runtime<'a, E> { if value_len > max_size { return Err(Error::::ValueTooLarge.into()) } - let key = self.read_sandbox_memory(memory, key_ptr, key_type.len::()?)?; + let key = self.decode_key(memory, key_type, key_ptr)?; 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)?, - value, - false, - )?, - KeyType::Variable(_) => self.ext.set_storage_transparent( - &VarSizedKey::::try_from(key).map_err(|_| Error::::DecodingFailed)?, - value, - false, - )?, - }; + let write_outcome = self.ext.set_storage(&key, value, false)?; self.adjust_gas( charged, @@ -796,19 +796,8 @@ impl<'a, E: Ext + 'a> Runtime<'a, E> { key_ptr: u32, ) -> Result { let charged = self.charge_gas(RuntimeCosts::ClearStorage(self.ext.max_value_size()))?; - 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)?, - None, - false, - )?, - KeyType::Variable(_) => self.ext.set_storage_transparent( - &VarSizedKey::::try_from(key).map_err(|_| Error::::DecodingFailed)?, - None, - false, - )?, - }; + let key = self.decode_key(memory, key_type, key_ptr)?; + let outcome = self.ext.set_storage(&key, None, false)?; self.adjust_gas(charged, RuntimeCosts::ClearStorage(outcome.old_len())); Ok(outcome.old_len_with_sentinel()) @@ -823,15 +812,8 @@ impl<'a, E: Ext + 'a> Runtime<'a, E> { out_len_ptr: u32, ) -> Result { let charged = self.charge_gas(RuntimeCosts::GetStorage(self.ext.max_value_size()))?; - 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)?, - ), - KeyType::Variable(_) => self.ext.get_storage_transparent( - &VarSizedKey::::try_from(key).map_err(|_| Error::::DecodingFailed)?, - ), - }; + let key = self.decode_key(memory, key_type, key_ptr)?; + let outcome = self.ext.get_storage(&key); if let Some(value) = outcome { self.adjust_gas(charged, RuntimeCosts::GetStorage(value.len() as u32)); @@ -857,15 +839,8 @@ impl<'a, E: Ext + 'a> Runtime<'a, E> { key_ptr: u32, ) -> Result { let charged = self.charge_gas(RuntimeCosts::ContainsStorage(self.ext.max_value_size()))?; - 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)?, - ), - KeyType::Variable(_) => self.ext.get_storage_size_transparent( - &VarSizedKey::::try_from(key).map_err(|_| Error::::DecodingFailed)?, - ), - }; + let key = self.decode_key(memory, key_type, key_ptr)?; + let outcome = self.ext.get_storage_size(&key); self.adjust_gas(charged, RuntimeCosts::ClearStorage(outcome.unwrap_or(0))); Ok(outcome.unwrap_or(SENTINEL)) @@ -1092,7 +1067,7 @@ pub mod env { value_ptr: u32, value_len: u32, ) -> Result { - ctx.set_storage(memory, KeyType::Variable(key_len), key_ptr, value_ptr, value_len) + ctx.set_storage(memory, KeyType::Var(key_len), key_ptr, value_ptr, value_len) } /// Clear the value at the given key in the contract storage. @@ -1118,7 +1093,7 @@ pub mod env { #[version(1)] #[prefixed_alias] fn clear_storage(ctx: _, memory: _, key_ptr: u32, key_len: u32) -> Result { - ctx.clear_storage(memory, KeyType::Variable(key_len), key_ptr) + ctx.clear_storage(memory, KeyType::Var(key_len), key_ptr) } /// Retrieve the value under the given key from storage. @@ -1175,7 +1150,7 @@ pub mod env { out_ptr: u32, out_len_ptr: u32, ) -> Result { - ctx.get_storage(memory, KeyType::Variable(key_len), key_ptr, out_ptr, out_len_ptr) + ctx.get_storage(memory, KeyType::Var(key_len), key_ptr, out_ptr, out_len_ptr) } /// Checks whether there is a value stored under the given key. @@ -1212,7 +1187,7 @@ pub mod env { #[version(1)] #[prefixed_alias] fn contains_storage(ctx: _, memory: _, key_ptr: u32, key_len: u32) -> Result { - ctx.contains_storage(memory, KeyType::Variable(key_len), key_ptr) + ctx.contains_storage(memory, KeyType::Var(key_len), key_ptr) } /// Retrieve and remove the value under the given key from storage. @@ -1239,8 +1214,8 @@ pub mod env { ) -> Result { let charged = ctx.charge_gas(RuntimeCosts::TakeStorage(ctx.ext.max_value_size()))?; 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)?, + if let crate::storage::WriteOutcome::Taken(value) = ctx.ext.set_storage( + &Key::::try_from_var(key).map_err(|_| Error::::DecodingFailed)?, None, true, )? { From 29466db4b711730f5fa95f3fe1f289871b2c7c5c Mon Sep 17 00:00:00 2001 From: PG Herveou Date: Sat, 18 Mar 2023 08:44:46 +0100 Subject: [PATCH 531/715] Add linguist-generated to gitattributes (#13628) --- .gitattributes | 1 + frame/balances/src/weights.rs | 70 +++++++++++++++++------------------ 2 files changed, 35 insertions(+), 36 deletions(-) diff --git a/.gitattributes b/.gitattributes index 1762f1a04d802..a77c52fccdb77 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1,4 @@ Cargo.lock linguist-generated=true /.gitlab-ci.yml filter=ci-prettier /scripts/ci/gitlab/pipeline/*.yml filter=ci-prettier +frame/**/src/weights.rs linguist-generated=true diff --git a/frame/balances/src/weights.rs b/frame/balances/src/weights.rs index 500eb3371d635..e7fd539c061aa 100644 --- a/frame/balances/src/weights.rs +++ b/frame/balances/src/weights.rs @@ -18,28 +18,26 @@ //! Autogenerated weights for pallet_balances //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-17, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate +// target/production/substrate // benchmark // pallet -// --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet_balances -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/balances/src/weights.rs +// --json-file=/var/lib/gitlab-runner/builds/zyw4fam_/0/parity/mirrors/substrate/.git/.artifacts/bench.json +// --pallet=pallet_balances +// --chain=dev // --header=./HEADER-APACHE2 +// --output=./frame/balances/src/weights.rs // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -69,8 +67,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 37_266_000 picoseconds. - Weight::from_parts(37_757_000, 3593) + // Minimum execution time: 36_551_000 picoseconds. + Weight::from_parts(37_150_000, 3593) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -80,8 +78,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 28_782_000 picoseconds. - Weight::from_parts(29_185_000, 3593) + // Minimum execution time: 28_246_000 picoseconds. + Weight::from_parts(28_647_000, 3593) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -91,8 +89,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 17_406_000 picoseconds. - Weight::from_parts(17_781_000, 3593) + // Minimum execution time: 17_407_000 picoseconds. + Weight::from_parts(17_827_000, 3593) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -102,8 +100,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 20_942_000 picoseconds. - Weight::from_parts(21_270_000, 3593) + // Minimum execution time: 20_941_000 picoseconds. + Weight::from_parts(21_383_000, 3593) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -113,8 +111,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `103` // Estimated: `6196` - // Minimum execution time: 41_706_000 picoseconds. - Weight::from_parts(42_176_000, 6196) + // Minimum execution time: 38_741_000 picoseconds. + Weight::from_parts(39_201_000, 6196) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -124,8 +122,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 35_622_000 picoseconds. - Weight::from_parts(35_943_000, 3593) + // Minimum execution time: 33_791_000 picoseconds. + Weight::from_parts(34_500_000, 3593) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -135,8 +133,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 16_586_000 picoseconds. - Weight::from_parts(17_352_000, 3593) + // Minimum execution time: 16_538_000 picoseconds. + Weight::from_parts(16_859_000, 3593) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -150,8 +148,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 37_266_000 picoseconds. - Weight::from_parts(37_757_000, 3593) + // Minimum execution time: 36_551_000 picoseconds. + Weight::from_parts(37_150_000, 3593) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -161,8 +159,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 28_782_000 picoseconds. - Weight::from_parts(29_185_000, 3593) + // Minimum execution time: 28_246_000 picoseconds. + Weight::from_parts(28_647_000, 3593) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -172,8 +170,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 17_406_000 picoseconds. - Weight::from_parts(17_781_000, 3593) + // Minimum execution time: 17_407_000 picoseconds. + Weight::from_parts(17_827_000, 3593) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -183,8 +181,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 20_942_000 picoseconds. - Weight::from_parts(21_270_000, 3593) + // Minimum execution time: 20_941_000 picoseconds. + Weight::from_parts(21_383_000, 3593) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -194,8 +192,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `103` // Estimated: `6196` - // Minimum execution time: 41_706_000 picoseconds. - Weight::from_parts(42_176_000, 6196) + // Minimum execution time: 38_741_000 picoseconds. + Weight::from_parts(39_201_000, 6196) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -205,8 +203,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 35_622_000 picoseconds. - Weight::from_parts(35_943_000, 3593) + // Minimum execution time: 33_791_000 picoseconds. + Weight::from_parts(34_500_000, 3593) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -216,8 +214,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 16_586_000 picoseconds. - Weight::from_parts(17_352_000, 3593) + // Minimum execution time: 16_538_000 picoseconds. + Weight::from_parts(16_859_000, 3593) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } From f8a1dd4c836d7d29382ba66fc2fce40fc1364546 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Sat, 18 Mar 2023 14:47:55 +0000 Subject: [PATCH 532/715] Deprecate `Currency`; introduce holds and freezing into `fungible` traits (#12951) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * First reworking of fungibles API * New API and docs * More fungible::* API improvements * New ref-counting logic for old API * Missing files * Fixes * Use the new transfer logic * Use fungibles for the dispatchables * Use shelve/restore names * Locking works with total balance. * repotting and removal * Separate Holds from Reserves * Introduce freezes * Missing files * Tests for freezing * Fix hold+freeze combo * More tests * Fee-free dispatchable for upgrading accounts * Benchmarks and a few fixes * Another test * Docs and refactor to avoid blanket impls * Repot * Fit out ItemOf fully * Add events to Balanced traits * Introduced events into Hold traits * Fix Assets pallet tests * Assets benchmarks pass * Missing files and fixes * Fixes * Fixes * Benchmarks fixes * Fix balance benchmarks * Formatting * Expose fungible sub modules * Move NIS to fungible API * Fix broken impl and add test * Fix tests * API for `transfer_and_hold` * Use composite APIs * Formatting * Upgraded event * Fixes * Fixes * Fixes * Fixes * Repot tests and some fixed * Fix some bits * Fix dust tests * Rename `set_balance` - `Balances::set_balance` becomes `Balances::force_set_balance` - `Unbalanced::set_balance` becomes `Unbalances::write_balance` * becomes * Move dust handling to fungibles API * Formatting * Fixes and more refactoring * Fixes * Fixes * Fixes * Fixes * Fixes * Fixes * Fixes * Fixes * Fixes * Use reducible_balance for better correctness on fees * Reducing hold to zero should remove entry. * Add test * Docs * Update frame/support/src/traits/tokens/fungibles/hold.rs Co-authored-by: Muharem Ismailov * Update frame/support/src/traits/tokens/fungibles/regular.rs Co-authored-by: Muharem Ismailov * Update frame/support/src/traits/tokens/fungible/hold.rs Co-authored-by: Muharem Ismailov * Update frame/support/src/traits/tokens/fungible/regular.rs Co-authored-by: Muharem Ismailov * Docs * Docs * Docs * Fix NIS benchmarks * Doc comment * Remove post_mutation * Fix some tests * Fix some grumbles * Enumify bool args to fungible(s) functions * Fix up assets and balances * Formatting * Fix contracts * Fix tests & benchmarks build * Typify minted boolean arg * Typify on_hold boolean arg; renames * Fix numerous tests * Fix dependency issue * Privatize dangerous API mutate_account * Fix contracts (@alext - please check this commit) * Remove println * Fix tests for contracts * Fix broken rename * Fix broken rename * Fix broken rename * Docs * Update frame/support/src/traits/tokens/fungible/hold.rs Co-authored-by: Anthony Alaribe * remove from_ref_time * Update frame/executive/src/lib.rs Co-authored-by: Anthony Alaribe * Update frame/executive/src/lib.rs Co-authored-by: Anthony Alaribe * Reenable test * Update frame/support/src/traits/tokens/fungibles/hold.rs Co-authored-by: Anthony Alaribe * Update frame/support/src/traits/tokens/fungible/hold.rs Co-authored-by: Anthony Alaribe * Update frame/support/src/traits/tokens/fungible/hold.rs Co-authored-by: Anthony Alaribe * Update frame/support/src/traits/tokens/fungible/hold.rs Co-authored-by: Anthony Alaribe * Update frame/support/src/traits/tokens/currency.rs Co-authored-by: Anthony Alaribe * Update frame/lottery/src/tests.rs Co-authored-by: Anthony Alaribe * Update frame/support/src/traits/tokens/fungible/mod.rs Co-authored-by: Anthony Alaribe * Update frame/support/src/traits/tokens/fungible/regular.rs Co-authored-by: Anthony Alaribe * Update frame/support/src/traits/tokens/fungibles/freeze.rs Co-authored-by: Anthony Alaribe * Update frame/support/src/traits/tokens/fungible/regular.rs Co-authored-by: Anthony Alaribe * Update frame/support/src/traits/tokens/fungibles/hold.rs Co-authored-by: Anthony Alaribe * Update frame/support/src/traits/tokens/fungibles/hold.rs Co-authored-by: Anthony Alaribe * Update frame/support/src/traits/tokens/fungibles/hold.rs Co-authored-by: Anthony Alaribe * Rename UnwantedRemoval to UnwantedAccountRemoval * Docs * Formatting * Update frame/balances/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * Update primitives/runtime/src/lib.rs Co-authored-by: Keith Yeung * handle_raw_dust oes nothing * Formatting * Fixes * Grumble * Fixes * Add test * Add test * Tests for reducible_balance * Fixes * Fix Salary * Fixes * Disable broken test * Disable nicely * Fixes * Fixes * Fixes * Rename some events * Fix nomination pools breakage * Add compatibility stub for transfer tx * Reinstate a safely compatible version of Balances set_balance * Fixes * Grumble * Update frame/nis/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_balances * disable flakey tests * Update frame/balances/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Grumbles * Grumble --------- Co-authored-by: Muharem Ismailov Co-authored-by: Alexander Theißen Co-authored-by: Anthony Alaribe Co-authored-by: Oliver Tale-Yazdi Co-authored-by: Keith Yeung Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: command-bot <> --- bin/node-template/runtime/src/lib.rs | 4 + bin/node/cli/benches/block_production.rs | 2 +- bin/node/cli/benches/transaction_pool.rs | 8 +- bin/node/cli/src/service.rs | 2 +- bin/node/cli/tests/temp_base_path_works.rs | 4 +- bin/node/executor/benches/bench.rs | 2 +- bin/node/executor/tests/basic.rs | 57 +- bin/node/executor/tests/common.rs | 5 +- bin/node/executor/tests/fees.rs | 6 +- bin/node/executor/tests/submit_transaction.rs | 12 +- bin/node/runtime/src/impls.rs | 4 +- bin/node/runtime/src/lib.rs | 21 +- bin/node/testing/src/bench.rs | 2 +- frame/alliance/src/mock.rs | 4 + frame/assets/src/benchmarking.rs | 8 +- frame/assets/src/functions.rs | 15 +- frame/assets/src/impl_fungibles.rs | 126 +- frame/assets/src/lib.rs | 6 +- frame/assets/src/mock.rs | 6 +- frame/assets/src/tests.rs | 30 +- frame/atomic-swap/src/tests.rs | 4 + frame/babe/src/mock.rs | 4 + frame/balances/README.md | 2 +- frame/balances/src/benchmarking.rs | 74 +- frame/balances/src/impl_currency.rs | 898 +++++++ frame/balances/src/impl_fungible.rs | 358 +++ frame/balances/src/lib.rs | 2387 +++++------------ frame/balances/src/tests.rs | 1460 ---------- frame/balances/src/tests/currency_tests.rs | 1231 +++++++++ .../balances/src/tests/dispatchable_tests.rs | 224 ++ frame/balances/src/tests/fungible_tests.rs | 399 +++ frame/balances/src/tests/mod.rs | 296 ++ frame/balances/src/tests/reentrancy_tests.rs | 195 ++ frame/balances/src/tests_composite.rs | 149 - frame/balances/src/tests_local.rs | 191 -- frame/balances/src/tests_reentrancy.rs | 264 -- frame/balances/src/types.rs | 157 ++ frame/balances/src/weights.rs | 49 +- frame/beefy/src/mock.rs | 4 + frame/bounties/src/benchmarking.rs | 7 +- frame/bounties/src/tests.rs | 8 +- frame/child-bounties/src/benchmarking.rs | 12 +- frame/child-bounties/src/tests.rs | 8 +- frame/contracts/src/benchmarking/mod.rs | 12 +- frame/contracts/src/exec.rs | 15 +- frame/contracts/src/lib.rs | 2 +- frame/contracts/src/storage/meter.rs | 7 +- frame/contracts/src/tests.rs | 73 +- frame/conviction-voting/src/benchmarking.rs | 12 +- frame/conviction-voting/src/lib.rs | 7 +- frame/conviction-voting/src/tests.rs | 6 +- frame/democracy/src/tests.rs | 8 +- .../src/benchmarking.rs | 10 +- .../election-provider-multi-phase/src/mock.rs | 4 + frame/elections-phragmen/src/lib.rs | 7 +- frame/examples/basic/src/tests.rs | 4 + frame/executive/src/lib.rs | 100 +- frame/fast-unstake/src/mock.rs | 4 + frame/grandpa/src/mock.rs | 4 + frame/identity/src/tests.rs | 4 + frame/indices/src/mock.rs | 4 + frame/lottery/src/mock.rs | 4 + frame/lottery/src/tests.rs | 77 +- frame/multisig/src/tests.rs | 72 +- frame/nfts/src/mock.rs | 4 + frame/nicks/src/lib.rs | 4 + frame/nis/README.md | 5 +- frame/nis/src/benchmarking.rs | 102 +- frame/nis/src/lib.rs | 240 +- frame/nis/src/mock.rs | 50 +- frame/nis/src/tests.rs | 110 +- .../nomination-pools/benchmarking/src/mock.rs | 4 + frame/nomination-pools/src/mock.rs | 4 + frame/nomination-pools/src/tests.rs | 177 +- .../nomination-pools/test-staking/src/mock.rs | 4 + frame/offences/benchmarking/src/mock.rs | 4 + frame/preimage/src/mock.rs | 4 + frame/proxy/src/tests.rs | 28 +- frame/recovery/src/mock.rs | 4 + frame/recovery/src/tests.rs | 10 +- frame/referenda/src/migration.rs | 2 +- frame/referenda/src/mock.rs | 17 +- frame/root-offences/src/mock.rs | 4 + frame/scored-pool/src/mock.rs | 4 + frame/session/benchmarking/src/mock.rs | 4 + frame/society/src/mock.rs | 4 + frame/staking/src/mock.rs | 4 + frame/staking/src/tests.rs | 22 +- frame/state-trie-migration/src/lib.rs | 4 + frame/support/src/traits/stored_map.rs | 35 +- frame/support/src/traits/tokens.rs | 3 +- frame/support/src/traits/tokens/fungible.rs | 367 --- .../src/traits/tokens/fungible/balanced.rs | 354 --- .../src/traits/tokens/fungible/freeze.rs | 68 + .../src/traits/tokens/fungible/hold.rs | 393 +++ .../src/traits/tokens/fungible/imbalance.rs | 15 +- .../src/traits/tokens/fungible/item_of.rs | 451 ++++ .../support/src/traits/tokens/fungible/mod.rs | 56 + .../src/traits/tokens/fungible/regular.rs | 506 ++++ frame/support/src/traits/tokens/fungibles.rs | 332 --- .../src/traits/tokens/fungibles/balanced.rs | 394 --- .../src/traits/tokens/fungibles/enumerable.rs | 4 +- .../src/traits/tokens/fungibles/freeze.rs | 78 + .../src/traits/tokens/fungibles/hold.rs | 457 ++++ .../src/traits/tokens/fungibles/imbalance.rs | 13 +- .../src/traits/tokens/fungibles/lifetime.rs | 84 + .../src/traits/tokens/fungibles/mod.rs | 40 + .../src/traits/tokens/fungibles/regular.rs | 571 ++++ frame/support/src/traits/tokens/misc.rs | 62 +- frame/support/src/traits/tokens/pay.rs | 8 +- frame/system/src/lib.rs | 23 +- frame/system/src/tests.rs | 2 + frame/tips/src/tests.rs | 4 + .../asset-tx-payment/src/lib.rs | 8 +- .../asset-tx-payment/src/mock.rs | 6 +- .../asset-tx-payment/src/payment.rs | 23 +- .../asset-tx-payment/src/tests.rs | 2 +- frame/transaction-payment/src/mock.rs | 6 +- frame/transaction-payment/src/tests.rs | 10 +- frame/transaction-storage/src/mock.rs | 4 + frame/treasury/src/tests.rs | 4 + frame/uniques/src/mock.rs | 4 + frame/utility/Cargo.toml | 1 + frame/utility/src/tests.rs | 17 +- frame/vesting/src/benchmarking.rs | 12 +- frame/vesting/src/mock.rs | 4 + frame/vesting/src/tests.rs | 37 +- frame/whitelist/src/mock.rs | 4 + primitives/runtime/src/lib.rs | 22 +- 129 files changed, 8325 insertions(+), 6119 deletions(-) create mode 100644 frame/balances/src/impl_currency.rs create mode 100644 frame/balances/src/impl_fungible.rs delete mode 100644 frame/balances/src/tests.rs create mode 100644 frame/balances/src/tests/currency_tests.rs create mode 100644 frame/balances/src/tests/dispatchable_tests.rs create mode 100644 frame/balances/src/tests/fungible_tests.rs create mode 100644 frame/balances/src/tests/mod.rs create mode 100644 frame/balances/src/tests/reentrancy_tests.rs delete mode 100644 frame/balances/src/tests_composite.rs delete mode 100644 frame/balances/src/tests_local.rs delete mode 100644 frame/balances/src/tests_reentrancy.rs create mode 100644 frame/balances/src/types.rs delete mode 100644 frame/support/src/traits/tokens/fungible.rs delete mode 100644 frame/support/src/traits/tokens/fungible/balanced.rs create mode 100644 frame/support/src/traits/tokens/fungible/freeze.rs create mode 100644 frame/support/src/traits/tokens/fungible/hold.rs create mode 100644 frame/support/src/traits/tokens/fungible/item_of.rs create mode 100644 frame/support/src/traits/tokens/fungible/mod.rs create mode 100644 frame/support/src/traits/tokens/fungible/regular.rs delete mode 100644 frame/support/src/traits/tokens/fungibles.rs delete mode 100644 frame/support/src/traits/tokens/fungibles/balanced.rs create mode 100644 frame/support/src/traits/tokens/fungibles/freeze.rs create mode 100644 frame/support/src/traits/tokens/fungibles/hold.rs create mode 100644 frame/support/src/traits/tokens/fungibles/lifetime.rs create mode 100644 frame/support/src/traits/tokens/fungibles/mod.rs create mode 100644 frame/support/src/traits/tokens/fungibles/regular.rs diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs index 41871c06bd923..50bcb67cb4790 100644 --- a/bin/node-template/runtime/src/lib.rs +++ b/bin/node-template/runtime/src/lib.rs @@ -243,6 +243,10 @@ impl pallet_balances::Config for Runtime { type ExistentialDeposit = ConstU128; type AccountStore = System; type WeightInfo = pallet_balances::weights::SubstrateWeight; + type FreezeIdentifier = (); + type MaxFreezes = (); + type HoldIdentifier = (); + type MaxHolds = (); } parameter_types! { diff --git a/bin/node/cli/benches/block_production.rs b/bin/node/cli/benches/block_production.rs index 501d69fc287b7..f1c65955eaef8 100644 --- a/bin/node/cli/benches/block_production.rs +++ b/bin/node/cli/benches/block_production.rs @@ -162,7 +162,7 @@ fn prepare_benchmark(client: &FullClient) -> (usize, Vec) { let extrinsic: OpaqueExtrinsic = create_extrinsic( client, src.clone(), - BalancesCall::transfer { dest: dst.clone(), value: 1 * DOLLARS }, + BalancesCall::transfer_allow_death { dest: dst.clone(), value: 1 * DOLLARS }, Some(nonce), ) .into(); diff --git a/bin/node/cli/benches/transaction_pool.rs b/bin/node/cli/benches/transaction_pool.rs index 165c67f602777..72c1c81608e13 100644 --- a/bin/node/cli/benches/transaction_pool.rs +++ b/bin/node/cli/benches/transaction_pool.rs @@ -140,10 +140,9 @@ fn create_account_extrinsics( Sr25519Keyring::Alice.pair(), SudoCall::sudo { call: Box::new( - BalancesCall::set_balance { + BalancesCall::force_set_balance { who: AccountId::from(a.public()).into(), new_free: 0, - new_reserved: 0, } .into(), ), @@ -156,10 +155,9 @@ fn create_account_extrinsics( Sr25519Keyring::Alice.pair(), SudoCall::sudo { call: Box::new( - BalancesCall::set_balance { + BalancesCall::force_set_balance { who: AccountId::from(a.public()).into(), new_free: 1_000_000 * DOLLARS, - new_reserved: 0, } .into(), ), @@ -184,7 +182,7 @@ fn create_benchmark_extrinsics( create_extrinsic( client, account.clone(), - BalancesCall::transfer { + BalancesCall::transfer_allow_death { dest: Sr25519Keyring::Bob.to_account_id().into(), value: 1 * DOLLARS, }, diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs index a2d66cd6349de..d32223339dc4a 100644 --- a/bin/node/cli/src/service.rs +++ b/bin/node/cli/src/service.rs @@ -772,7 +772,7 @@ mod tests { }; let signer = charlie.clone(); - let function = RuntimeCall::Balances(BalancesCall::transfer { + let function = RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: to.into(), value: amount, }); diff --git a/bin/node/cli/tests/temp_base_path_works.rs b/bin/node/cli/tests/temp_base_path_works.rs index 89e901c00e118..bfc9f88220030 100644 --- a/bin/node/cli/tests/temp_base_path_works.rs +++ b/bin/node/cli/tests/temp_base_path_works.rs @@ -26,7 +26,9 @@ use std::{ pub mod common; -#[tokio::test] +#[allow(dead_code)] +// Apparently `#[ignore]` doesn't actually work to disable this one. +//#[tokio::test] async fn temp_base_path_works() { common::run_with_timeout(Duration::from_secs(60 * 10), async move { let mut cmd = Command::new(cargo_bin("substrate")); diff --git a/bin/node/executor/benches/bench.rs b/bin/node/executor/benches/bench.rs index 19e7b158a8c81..a8c31068e853b 100644 --- a/bin/node/executor/benches/bench.rs +++ b/bin/node/executor/benches/bench.rs @@ -167,7 +167,7 @@ fn test_blocks( }]; block1_extrinsics.extend((0..20).map(|i| CheckedExtrinsic { signed: Some((alice(), signed_extra(i, 0))), - function: RuntimeCall::Balances(pallet_balances::Call::transfer { + function: RuntimeCall::Balances(pallet_balances::Call::transfer_allow_death { dest: bob().into(), value: 1 * DOLLARS, }), diff --git a/bin/node/executor/tests/basic.rs b/bin/node/executor/tests/basic.rs index 9200fe735be41..d301aa06f90b0 100644 --- a/bin/node/executor/tests/basic.rs +++ b/bin/node/executor/tests/basic.rs @@ -89,7 +89,7 @@ fn changes_trie_block() -> (Vec, Hash) { }, CheckedExtrinsic { signed: Some((alice(), signed_extra(0, 0))), - function: RuntimeCall::Balances(pallet_balances::Call::transfer { + function: RuntimeCall::Balances(pallet_balances::Call::transfer_allow_death { dest: bob().into(), value: 69 * DOLLARS, }), @@ -116,7 +116,7 @@ fn blocks() -> ((Vec, Hash), (Vec, Hash)) { }, CheckedExtrinsic { signed: Some((alice(), signed_extra(0, 0))), - function: RuntimeCall::Balances(pallet_balances::Call::transfer { + function: RuntimeCall::Balances(pallet_balances::Call::transfer_allow_death { dest: bob().into(), value: 69 * DOLLARS, }), @@ -136,14 +136,14 @@ fn blocks() -> ((Vec, Hash), (Vec, Hash)) { }, CheckedExtrinsic { signed: Some((bob(), signed_extra(0, 0))), - function: RuntimeCall::Balances(pallet_balances::Call::transfer { + function: RuntimeCall::Balances(pallet_balances::Call::transfer_allow_death { dest: alice().into(), value: 5 * DOLLARS, }), }, CheckedExtrinsic { signed: Some((alice(), signed_extra(1, 0))), - function: RuntimeCall::Balances(pallet_balances::Call::transfer { + function: RuntimeCall::Balances(pallet_balances::Call::transfer_allow_death { dest: bob().into(), value: 15 * DOLLARS, }), @@ -183,7 +183,12 @@ fn panic_execution_with_foreign_code_gives_error() { let mut t = new_test_ext(bloaty_code_unwrap()); t.insert( >::hashed_key_for(alice()), - (69u128, 0u32, 0u128, 0u128, 0u128).encode(), + AccountInfo::<::Index, _> { + providers: 1, + data: (69u128, 0u128, 0u128, 1u128 << 127), + ..Default::default() + } + .encode(), ); t.insert(>::hashed_key().to_vec(), 69_u128.encode()); t.insert(>::hashed_key_for(0), vec![0u8; 32]); @@ -204,9 +209,14 @@ fn bad_extrinsic_with_native_equivalent_code_gives_error() { let mut t = new_test_ext(compact_code_unwrap()); t.insert( >::hashed_key_for(alice()), - (0u32, 0u32, 0u32, 69u128, 0u128, 0u128, 0u128).encode(), + AccountInfo::<::Index, _> { + providers: 1, + data: (69u128, 0u128, 0u128, 1u128 << 127), + ..Default::default() + } + .encode(), ); - t.insert(>::hashed_key().to_vec(), 69_u128.encode()); + t.insert(>::hashed_key().to_vec(), 69u128.encode()); t.insert(>::hashed_key_for(0), vec![0u8; 32]); let r = @@ -226,17 +236,18 @@ fn successful_execution_with_native_equivalent_code_gives_ok() { t.insert( >::hashed_key_for(alice()), AccountInfo::<::Index, _> { - data: (111 * DOLLARS, 0u128, 0u128, 0u128), + providers: 1, + data: (111 * DOLLARS, 0u128, 0u128, 1u128 << 127), ..Default::default() } .encode(), ); t.insert( >::hashed_key_for(bob()), - AccountInfo::<::Index, _> { - data: (0 * DOLLARS, 0u128, 0u128, 0u128), - ..Default::default() - } + AccountInfo::< + ::Index, + ::AccountData, + >::default() .encode(), ); t.insert( @@ -267,17 +278,18 @@ fn successful_execution_with_foreign_code_gives_ok() { t.insert( >::hashed_key_for(alice()), AccountInfo::<::Index, _> { - data: (111 * DOLLARS, 0u128, 0u128, 0u128), + providers: 1, + data: (111 * DOLLARS, 0u128, 0u128, 1u128 << 127), ..Default::default() } .encode(), ); t.insert( >::hashed_key_for(bob()), - AccountInfo::<::Index, _> { - data: (0 * DOLLARS, 0u128, 0u128, 0u128), - ..Default::default() - } + AccountInfo::< + ::Index, + ::AccountData, + >::default() .encode(), ); t.insert( @@ -784,17 +796,18 @@ fn successful_execution_gives_ok() { t.insert( >::hashed_key_for(alice()), AccountInfo::<::Index, _> { - data: (111 * DOLLARS, 0u128, 0u128, 0u128), + providers: 1, + data: (111 * DOLLARS, 0u128, 0u128, 1u128 << 127), ..Default::default() } .encode(), ); t.insert( >::hashed_key_for(bob()), - AccountInfo::<::Index, _> { - data: (0 * DOLLARS, 0u128, 0u128, 0u128), - ..Default::default() - } + AccountInfo::< + ::Index, + ::AccountData, + >::default() .encode(), ); t.insert( diff --git a/bin/node/executor/tests/common.rs b/bin/node/executor/tests/common.rs index 036528f8dae1f..2f92423ffb508 100644 --- a/bin/node/executor/tests/common.rs +++ b/bin/node/executor/tests/common.rs @@ -87,7 +87,10 @@ pub fn sign(xt: CheckedExtrinsic) -> UncheckedExtrinsic { } pub fn default_transfer_call() -> pallet_balances::Call { - pallet_balances::Call::::transfer { dest: bob().into(), value: 69 * DOLLARS } + pallet_balances::Call::::transfer_allow_death { + dest: bob().into(), + value: 69 * DOLLARS, + } } pub fn from_block_number(n: u32) -> Header { diff --git a/bin/node/executor/tests/fees.rs b/bin/node/executor/tests/fees.rs index cbf0fdce9476b..970d790a87d3b 100644 --- a/bin/node/executor/tests/fees.rs +++ b/bin/node/executor/tests/fees.rs @@ -120,9 +120,9 @@ fn new_account_info(free_dollars: u128) -> Vec { frame_system::AccountInfo { nonce: 0u32, consumers: 0, - providers: 0, + providers: 1, sufficients: 0, - data: (free_dollars * DOLLARS, 0 * DOLLARS, 0 * DOLLARS, 0 * DOLLARS), + data: (free_dollars * DOLLARS, 0 * DOLLARS, 0 * DOLLARS, 1u128 << 127), } .encode() } @@ -214,7 +214,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: RuntimeCall::Balances(pallet_balances::Call::transfer { + function: RuntimeCall::Balances(pallet_balances::Call::transfer_allow_death { dest: bob().into(), value: 0, }), diff --git a/bin/node/executor/tests/submit_transaction.rs b/bin/node/executor/tests/submit_transaction.rs index 32eacd78b78b7..a3d6681fb6928 100644 --- a/bin/node/executor/tests/submit_transaction.rs +++ b/bin/node/executor/tests/submit_transaction.rs @@ -86,7 +86,7 @@ fn should_submit_signed_transaction() { t.execute_with(|| { let results = Signer::::all_accounts().send_signed_transaction(|_| { - pallet_balances::Call::transfer { + pallet_balances::Call::transfer_allow_death { dest: Alice.to_account_id().into(), value: Default::default(), } @@ -123,7 +123,7 @@ fn should_submit_signed_twice_from_the_same_account() { t.execute_with(|| { let result = Signer::::any_account().send_signed_transaction(|_| { - pallet_balances::Call::transfer { + pallet_balances::Call::transfer_allow_death { dest: Alice.to_account_id().into(), value: Default::default(), } @@ -135,7 +135,7 @@ fn should_submit_signed_twice_from_the_same_account() { // submit another one from the same account. The nonce should be incremented. let result = Signer::::any_account().send_signed_transaction(|_| { - pallet_balances::Call::transfer { + pallet_balances::Call::transfer_allow_death { dest: Alice.to_account_id().into(), value: Default::default(), } @@ -174,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: Alice.to_account_id().into(), value: Default::default() } + pallet_balances::Call::transfer_allow_death { dest: Alice.to_account_id().into(), value: Default::default() } }); let len = results.len(); @@ -185,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: Alice.to_account_id().into(), value: Default::default() } + pallet_balances::Call::transfer_allow_death { dest: Alice.to_account_id().into(), value: Default::default() } }); let len = results.len(); @@ -238,7 +238,7 @@ fn submitted_transaction_should_be_valid() { t.execute_with(|| { let results = Signer::::all_accounts().send_signed_transaction(|_| { - pallet_balances::Call::transfer { + pallet_balances::Call::transfer_allow_death { 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 09f7b6a29e0b6..033549549a73f 100644 --- a/bin/node/runtime/src/impls.rs +++ b/bin/node/runtime/src/impls.rs @@ -24,7 +24,7 @@ use crate::{ use frame_support::{ pallet_prelude::*, traits::{ - fungibles::{Balanced, CreditOf}, + fungibles::{Balanced, Credit}, Currency, OnUnbalanced, }, }; @@ -45,7 +45,7 @@ impl OnUnbalanced for Author { /// Will drop and burn the assets in case the transfer fails. pub struct CreditToBlockAuthor; impl HandleCredit for CreditToBlockAuthor { - fn handle_credit(credit: CreditOf) { + fn handle_credit(credit: 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 9f4ad2ed26474..3f0ea07122884 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -59,6 +59,7 @@ use pallet_nis::WithMaximumOf; use pallet_session::historical as pallet_session_historical; pub use pallet_transaction_payment::{CurrencyAdapter, Multiplier, TargetedFeeAdjustment}; use pallet_transaction_payment::{FeeDetails, RuntimeDispatchInfo}; +use scale_info::TypeInfo; use sp_api::impl_runtime_apis; use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId; use sp_consensus_grandpa::AuthorityId as GrandpaId; @@ -432,6 +433,15 @@ parameter_types! { pub const MaxReserves: u32 = 50; } +/// A reason for placing a hold on funds. +#[derive( + Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, MaxEncodedLen, Debug, TypeInfo, +)] +pub enum HoldReason { + /// The NIS Pallet has reserved it for a non-fungible receipt. + Nis, +} + impl pallet_balances::Config for Runtime { type MaxLocks = MaxLocks; type MaxReserves = MaxReserves; @@ -442,6 +452,10 @@ impl pallet_balances::Config for Runtime { type ExistentialDeposit = ExistentialDeposit; type AccountStore = frame_system::Pallet; type WeightInfo = pallet_balances::weights::SubstrateWeight; + type FreezeIdentifier = (); + type MaxFreezes = (); + type HoldIdentifier = HoldReason; + type MaxHolds = ConstU32<1>; } parameter_types! { @@ -1481,7 +1495,6 @@ impl pallet_assets::Config for Runtime { } parameter_types! { - pub IgnoredIssuance: Balance = Treasury::pot(); pub const QueueCount: u32 = 300; pub const MaxQueueLen: u32 = 1000; pub const FifoQueueLen: u32 = 500; @@ -1493,7 +1506,7 @@ parameter_types! { pub const ThawThrottle: (Perquintill, BlockNumber) = (Perquintill::from_percent(25), 5); pub Target: Perquintill = Perquintill::zero(); pub const NisPalletId: PalletId = PalletId(*b"py/nis "); - pub const NisReserveId: [u8; 8] = *b"py/nis "; + pub const NisHoldReason: HoldReason = HoldReason::Nis; } impl pallet_nis::Config for Runtime { @@ -1505,7 +1518,7 @@ impl pallet_nis::Config for Runtime { type Counterpart = ItemOf, AccountId>; type CounterpartAmount = WithMaximumOf>; type Deficit = (); - type IgnoredIssuance = IgnoredIssuance; + type IgnoredIssuance = (); type Target = Target; type PalletId = NisPalletId; type QueueCount = QueueCount; @@ -1517,7 +1530,7 @@ impl pallet_nis::Config for Runtime { type IntakePeriod = IntakePeriod; type MaxIntakeWeight = MaxIntakeWeight; type ThawThrottle = ThawThrottle; - type ReserveId = NisReserveId; + type HoldReason = NisHoldReason; } parameter_types! { diff --git a/bin/node/testing/src/bench.rs b/bin/node/testing/src/bench.rs index 1a9af13028483..d6bcf6e252fe0 100644 --- a/bin/node/testing/src/bench.rs +++ b/bin/node/testing/src/bench.rs @@ -308,7 +308,7 @@ impl<'a> Iterator for BlockContentIterator<'a> { value: kitchensink_runtime::ExistentialDeposit::get() + 1, }), BlockType::RandomTransfersReaping => { - RuntimeCall::Balances(BalancesCall::transfer { + RuntimeCall::Balances(BalancesCall::transfer_allow_death { 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. diff --git a/frame/alliance/src/mock.rs b/frame/alliance/src/mock.rs index b8fd998eb20a0..848f6b2a00557 100644 --- a/frame/alliance/src/mock.rs +++ b/frame/alliance/src/mock.rs @@ -85,6 +85,10 @@ impl pallet_balances::Config for Test { type MaxLocks = MaxLocks; type MaxReserves = (); type ReserveIdentifier = [u8; 8]; + type FreezeIdentifier = (); + type MaxFreezes = (); + type HoldIdentifier = (); + type MaxHolds = (); } const MOTION_DURATION_IN_BLOCKS: BlockNumber = 3; diff --git a/frame/assets/src/benchmarking.rs b/frame/assets/src/benchmarking.rs index 5b4f1489df5db..047ede2ce6964 100644 --- a/frame/assets/src/benchmarking.rs +++ b/frame/assets/src/benchmarking.rs @@ -105,14 +105,18 @@ 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()); + T::Currency::deposit_creating( + &minter, + T::ApprovalDeposit::get() * n.into() + T::Currency::minimum_balance(), + ); let minter_lookup = T::Lookup::unlookup(minter.clone()); let origin = SystemOrigin::Signed(minter); Assets::::mint(origin.clone().into(), asset_id, minter_lookup, (100 * (n + 1)).into()) .unwrap(); + let enough = T::Currency::minimum_balance(); for i in 0..n { let target = account("approval", i, SEED); - T::Currency::make_free_balance_be(&target, T::Currency::minimum_balance()); + T::Currency::make_free_balance_be(&target, enough); let target_lookup = T::Lookup::unlookup(target); Assets::::approve_transfer( origin.clone().into(), diff --git a/frame/assets/src/functions.rs b/frame/assets/src/functions.rs index 47657ff267494..af9e269acf8bc 100644 --- a/frame/assets/src/functions.rs +++ b/frame/assets/src/functions.rs @@ -76,7 +76,14 @@ impl, I: 'static> Pallet { d.sufficients += 1; ExistenceReason::Sufficient } else { - frame_system::Pallet::::inc_consumers(who).map_err(|_| Error::::NoProvider)?; + frame_system::Pallet::::inc_consumers(who) + .map_err(|_| Error::::UnavailableConsumer)?; + // We ensure that we can still increment consumers once more because we could otherwise + // allow accidental usage of all consumer references which could cause grief. + if !frame_system::Pallet::::can_inc_consumer(who) { + frame_system::Pallet::::dec_consumers(who); + return Err(Error::::UnavailableConsumer.into()) + } ExistenceReason::Consumer }; d.accounts = accounts; @@ -165,7 +172,7 @@ impl, I: 'static> Pallet { } let account = match Account::::get(id, who) { Some(a) => a, - None => return NoFunds, + None => return BalanceLow, }; if account.is_frozen { return Frozen @@ -193,7 +200,7 @@ impl, I: 'static> Pallet { Success } } else { - NoFunds + BalanceLow } } @@ -254,7 +261,7 @@ impl, I: 'static> Pallet { ensure!(f.best_effort || actual >= amount, Error::::BalanceLow); let conseq = Self::can_decrease(id, target, actual, f.keep_alive); - let actual = match conseq.into_result() { + let actual = match conseq.into_result(f.keep_alive) { Ok(dust) => actual.saturating_add(dust), //< guaranteed by reducible_balance Err(e) => { debug_assert!(false, "passed from reducible_balance; qed"); diff --git a/frame/assets/src/impl_fungibles.rs b/frame/assets/src/impl_fungibles.rs index f420ea02c31e9..7bec884f4c56b 100644 --- a/frame/assets/src/impl_fungibles.rs +++ b/frame/assets/src/impl_fungibles.rs @@ -17,6 +17,16 @@ //! Implementations for fungibles trait. +use frame_support::{ + defensive, + traits::tokens::{ + Fortitude, + Precision::{self, BestEffort}, + Preservation::{self, Expendable}, + Provenance::{self, Minted}, + }, +}; + use super::*; impl, I: 'static> fungibles::Inspect<::AccountId> for Pallet { @@ -35,21 +45,27 @@ impl, I: 'static> fungibles::Inspect<::AccountId Pallet::::balance(asset, who) } + fn total_balance(asset: Self::AssetId, who: &::AccountId) -> Self::Balance { + Pallet::::balance(asset, who) + } + fn reducible_balance( asset: Self::AssetId, who: &::AccountId, - keep_alive: bool, + preservation: Preservation, + _: Fortitude, ) -> Self::Balance { - Pallet::::reducible_balance(asset, who, keep_alive).unwrap_or(Zero::zero()) + Pallet::::reducible_balance(asset, who, !matches!(preservation, Expendable)) + .unwrap_or(Zero::zero()) } fn can_deposit( asset: Self::AssetId, who: &::AccountId, amount: Self::Balance, - mint: bool, + provenance: Provenance, ) -> DepositConsequence { - Pallet::::can_increase(asset, who, amount, mint) + Pallet::::can_increase(asset, who, amount, provenance == Minted) } fn can_withdraw( @@ -65,69 +81,26 @@ impl, I: 'static> fungibles::Inspect<::AccountId } } -impl, I: 'static> fungibles::InspectMetadata<::AccountId> +impl, I: 'static> fungibles::Mutate<::AccountId> for Pallet {} +impl, I: 'static> fungibles::Balanced<::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, - who: &::AccountId, - amount: Self::Balance, - ) -> DispatchResult { - Self::do_mint(asset, who, amount, None) - } - - fn burn_from( - asset: Self::AssetId, - who: &::AccountId, - amount: Self::Balance, - ) -> Result { - let f = DebitFlags { keep_alive: false, best_effort: false }; - Self::do_burn(asset, who, amount, None, f) - } - - fn slash( - asset: Self::AssetId, - who: &::AccountId, - amount: Self::Balance, - ) -> Result { - let f = DebitFlags { keep_alive: false, best_effort: true }; - Self::do_burn(asset, who, amount, None, f) - } -} - -impl, I: 'static> fungibles::Transfer for Pallet { - fn transfer( - asset: Self::AssetId, - source: &T::AccountId, - dest: &T::AccountId, - amount: T::Balance, - keep_alive: bool, - ) -> Result { - let f = TransferFlags { keep_alive, best_effort: false, burn_dust: false }; - Self::do_transfer(asset, source, dest, amount, None, f) - } + type OnDropCredit = fungibles::DecreaseIssuance; + type OnDropDebt = fungibles::IncreaseIssuance; } impl, I: 'static> fungibles::Unbalanced for Pallet { - fn set_balance(_: Self::AssetId, _: &T::AccountId, _: Self::Balance) -> DispatchResult { - unreachable!("set_balance is not used if other functions are impl'd"); + fn handle_raw_dust(_: Self::AssetId, _: Self::Balance) {} + fn handle_dust(_: fungibles::Dust) { + defensive!("`decrease_balance` and `increase_balance` have non-default impls; nothing else calls this; qed"); + } + fn write_balance( + _: Self::AssetId, + _: &T::AccountId, + _: Self::Balance, + ) -> Result, DispatchError> { + defensive!("write_balance is not used if other functions are impl'd"); + Err(DispatchError::Unavailable) } fn set_total_issuance(id: T::AssetId, amount: Self::Balance) { Asset::::mutate_exists(id, |maybe_asset| { @@ -140,36 +113,27 @@ impl, I: 'static> fungibles::Unbalanced for Pallet Result { - let f = DebitFlags { keep_alive: false, best_effort: false }; + let f = DebitFlags { + keep_alive: preservation != Expendable, + best_effort: precision == BestEffort, + }; Self::decrease_balance(asset, who, amount, f, |_, _| Ok(())) } - fn decrease_balance_at_most( - asset: T::AssetId, - who: &T::AccountId, - amount: Self::Balance, - ) -> Self::Balance { - let f = DebitFlags { keep_alive: false, best_effort: true }; - Self::decrease_balance(asset, who, amount, f, |_, _| Ok(())).unwrap_or(Zero::zero()) - } fn increase_balance( asset: T::AssetId, who: &T::AccountId, amount: Self::Balance, + _: Precision, ) -> Result { Self::increase_balance(asset, who, amount, |_| Ok(()))?; Ok(amount) } - fn increase_balance_at_most( - asset: T::AssetId, - who: &T::AccountId, - amount: Self::Balance, - ) -> Self::Balance { - match Self::increase_balance(asset, who, amount, |_| Ok(())) { - Ok(()) => amount, - Err(_) => Zero::zero(), - } - } + + // TODO: #13196 implement deactivate/reactivate once we have inactive balance tracking. } impl, I: 'static> fungibles::Create for Pallet { diff --git a/frame/assets/src/lib.rs b/frame/assets/src/lib.rs index b36a5cabd377a..859a13243d509 100644 --- a/frame/assets/src/lib.rs +++ b/frame/assets/src/lib.rs @@ -540,9 +540,9 @@ pub mod pallet { /// Minimum balance should be non-zero. MinBalanceZero, /// 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, + /// reference exists to allow a non-zero balance of a non-self-sufficient asset, or one + /// fewer then the maximum number of consumers has been reached. + UnavailableConsumer, /// Invalid metadata given. BadMetadata, /// No approval exists that would allow the transfer. diff --git a/frame/assets/src/mock.rs b/frame/assets/src/mock.rs index 3f456a7de3eda..3926d2fa8b010 100644 --- a/frame/assets/src/mock.rs +++ b/frame/assets/src/mock.rs @@ -74,7 +74,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); - type MaxConsumers = ConstU32<2>; + type MaxConsumers = ConstU32<3>; } impl pallet_balances::Config for Test { @@ -87,6 +87,10 @@ impl pallet_balances::Config for Test { type MaxLocks = (); type MaxReserves = (); type ReserveIdentifier = [u8; 8]; + type HoldIdentifier = (); + type FreezeIdentifier = (); + type MaxHolds = (); + type MaxFreezes = (); } pub struct AssetsCallbackHandle; diff --git a/frame/assets/src/tests.rs b/frame/assets/src/tests.rs index bc61810a76ac4..d4a49ac5a4651 100644 --- a/frame/assets/src/tests.rs +++ b/frame/assets/src/tests.rs @@ -57,7 +57,10 @@ fn minting_too_many_insufficient_assets_fails() { Balances::make_free_balance_be(&1, 100); 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_noop!( + Assets::mint(RuntimeOrigin::signed(1), 2, 1, 100), + Error::::UnavailableConsumer + ); Balances::make_free_balance_be(&2, 1); assert_ok!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 100)); @@ -75,7 +78,10 @@ fn minting_insufficient_asset_with_deposit_should_work_when_consumers_exhausted( Balances::make_free_balance_be(&1, 100); 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_noop!( + Assets::mint(RuntimeOrigin::signed(1), 2, 1, 100), + Error::::UnavailableConsumer + ); assert_ok!(Assets::touch(RuntimeOrigin::signed(1), 2)); assert_eq!(Balances::reserved_balance(&1), 10); @@ -93,7 +99,7 @@ fn minting_insufficient_assets_with_deposit_without_consumer_should_work() { 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); + assert_eq!(System::consumers(&1), 1); }); } @@ -167,7 +173,7 @@ fn approval_lifecycle_works() { // so we create it :) 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); + Balances::make_free_balance_be(&1, 2); 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); @@ -193,7 +199,7 @@ fn transfer_approved_all_funds() { // so we create it :) 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); + Balances::make_free_balance_be(&1, 2); 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); @@ -215,7 +221,7 @@ fn approval_deposits_work() { let e = BalancesError::::InsufficientBalance; assert_noop!(Assets::approve_transfer(RuntimeOrigin::signed(1), 0, 2, 50), e); - Balances::make_free_balance_be(&1, 1); + Balances::make_free_balance_be(&1, 2); assert_ok!(Assets::approve_transfer(RuntimeOrigin::signed(1), 0, 2, 50)); assert_eq!(Balances::reserved_balance(&1), 1); @@ -233,7 +239,7 @@ fn cannot_transfer_more_than_approved() { 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, 100)); - Balances::make_free_balance_be(&1, 1); + Balances::make_free_balance_be(&1, 2); assert_ok!(Assets::approve_transfer(RuntimeOrigin::signed(1), 0, 2, 50)); let e = Error::::Unapproved; assert_noop!(Assets::transfer_approved(RuntimeOrigin::signed(2), 0, 1, 3, 51), e); @@ -245,7 +251,7 @@ fn cannot_transfer_more_than_exists() { 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, 100)); - Balances::make_free_balance_be(&1, 1); + Balances::make_free_balance_be(&1, 2); assert_ok!(Assets::approve_transfer(RuntimeOrigin::signed(1), 0, 2, 101)); let e = Error::::BalanceLow; assert_noop!(Assets::transfer_approved(RuntimeOrigin::signed(2), 0, 1, 3, 101), e); @@ -257,7 +263,7 @@ fn cancel_approval_works() { 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, 100)); - Balances::make_free_balance_be(&1, 1); + Balances::make_free_balance_be(&1, 2); assert_ok!(Assets::approve_transfer(RuntimeOrigin::signed(1), 0, 2, 50)); assert_eq!(Asset::::get(0).unwrap().approvals, 1); assert_noop!( @@ -287,7 +293,7 @@ fn force_cancel_approval_works() { 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, 100)); - Balances::make_free_balance_be(&1, 1); + Balances::make_free_balance_be(&1, 2); assert_ok!(Assets::approve_transfer(RuntimeOrigin::signed(1), 0, 2, 50)); assert_eq!(Asset::::get(0).unwrap().approvals, 1); let e = Error::::NoPermission; @@ -516,7 +522,7 @@ fn min_balance_should_work() { // Death by `transfer_approved`. assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); - Balances::make_free_balance_be(&1, 1); + Balances::make_free_balance_be(&1, 2); 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)]); @@ -1217,7 +1223,7 @@ fn querying_allowance_should_work() { use frame_support::traits::tokens::fungibles::approvals::{Inspect, Mutate}; assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); - Balances::make_free_balance_be(&1, 1); + Balances::make_free_balance_be(&1, 2); 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 diff --git a/frame/atomic-swap/src/tests.rs b/frame/atomic-swap/src/tests.rs index 081a449ec9a2e..7437d62a99c95 100644 --- a/frame/atomic-swap/src/tests.rs +++ b/frame/atomic-swap/src/tests.rs @@ -62,6 +62,10 @@ impl pallet_balances::Config for Test { type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type HoldIdentifier = (); + type MaxHolds = (); } impl Config for Test { diff --git a/frame/babe/src/mock.rs b/frame/babe/src/mock.rs index 9b832bfffdb69..94e748d0bca52 100644 --- a/frame/babe/src/mock.rs +++ b/frame/babe/src/mock.rs @@ -144,6 +144,10 @@ impl pallet_balances::Config for Test { type ExistentialDeposit = ConstU128<1>; type AccountStore = System; type WeightInfo = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type HoldIdentifier = (); + type MaxHolds = (); } pallet_staking_reward_curve::build! { diff --git a/frame/balances/README.md b/frame/balances/README.md index 93e424a89c721..dd56ab3fadfb5 100644 --- a/frame/balances/README.md +++ b/frame/balances/README.md @@ -70,7 +70,7 @@ given account is unused. ### Dispatchable Functions - `transfer` - Transfer some liquid free balance to another account. -- `set_balance` - Set the balances of a given account. The origin of this call must be root. +- `force_set_balance` - Set the balances of a given account. The origin of this call must be root. ## Usage diff --git a/frame/balances/src/benchmarking.rs b/frame/balances/src/benchmarking.rs index b36fe1e341de3..5641c68516c28 100644 --- a/frame/balances/src/benchmarking.rs +++ b/frame/balances/src/benchmarking.rs @@ -24,6 +24,8 @@ use crate::Pallet as Balances; use frame_benchmarking::v2::*; use frame_system::RawOrigin; +use sp_runtime::traits::Bounded; +use types::ExtraFlags; const SEED: u32 = 0; // existential deposit multiplier @@ -37,7 +39,7 @@ mod benchmarks { // * Transfer will kill the sender account. // * Transfer will create the recipient account. #[benchmark] - fn transfer() { + fn transfer_allow_death() { let existential_deposit = T::ExistentialDeposit::get(); let caller = whitelisted_caller(); @@ -79,7 +81,7 @@ mod benchmarks { let transfer_amount = existential_deposit.saturating_mul(ED_MULTIPLIER.into()); #[extrinsic_call] - transfer(RawOrigin::Signed(caller.clone()), recipient_lookup, transfer_amount); + transfer_allow_death(RawOrigin::Signed(caller.clone()), recipient_lookup, transfer_amount); assert!(!Balances::::free_balance(&caller).is_zero()); assert!(!Balances::::free_balance(&recipient).is_zero()); @@ -106,9 +108,9 @@ mod benchmarks { assert_eq!(Balances::::free_balance(&recipient), transfer_amount); } - // Benchmark `set_balance` coming from ROOT account. This always creates an account. + // Benchmark `force_set_balance` coming from ROOT account. This always creates an account. #[benchmark] - fn set_balance_creating() { + fn force_set_balance_creating() { let user: T::AccountId = account("user", 0, SEED); let user_lookup = T::Lookup::unlookup(user.clone()); @@ -118,15 +120,14 @@ mod benchmarks { let _ = as Currency<_>>::make_free_balance_be(&user, balance_amount); #[extrinsic_call] - set_balance(RawOrigin::Root, user_lookup, balance_amount, balance_amount); + force_set_balance(RawOrigin::Root, user_lookup, balance_amount); assert_eq!(Balances::::free_balance(&user), balance_amount); - assert_eq!(Balances::::reserved_balance(&user), balance_amount); } - // Benchmark `set_balance` coming from ROOT account. This always kills an account. + // Benchmark `force_set_balance` coming from ROOT account. This always kills an account. #[benchmark] - fn set_balance_killing() { + fn force_set_balance_killing() { let user: T::AccountId = account("user", 0, SEED); let user_lookup = T::Lookup::unlookup(user.clone()); @@ -136,7 +137,7 @@ mod benchmarks { let _ = as Currency<_>>::make_free_balance_be(&user, balance_amount); #[extrinsic_call] - set_balance(RawOrigin::Root, user_lookup, Zero::zero(), Zero::zero()); + force_set_balance(RawOrigin::Root, user_lookup, Zero::zero()); assert!(Balances::::free_balance(&user).is_zero()); } @@ -197,7 +198,7 @@ mod benchmarks { } #[extrinsic_call] - transfer(RawOrigin::Signed(caller.clone()), recipient_lookup, transfer_amount); + transfer_allow_death(RawOrigin::Signed(caller.clone()), recipient_lookup, transfer_amount); assert_eq!(Balances::::free_balance(&caller), Zero::zero()); assert_eq!(Balances::::free_balance(&recipient), transfer_amount); @@ -230,27 +231,64 @@ mod benchmarks { let user_lookup = T::Lookup::unlookup(user.clone()); // Give some multiple of the existential deposit - let existential_deposit = T::ExistentialDeposit::get(); - let balance = existential_deposit.saturating_mul(ED_MULTIPLIER.into()); + let ed = T::ExistentialDeposit::get(); + let balance = ed + ed; let _ = as Currency<_>>::make_free_balance_be(&user, balance); // Reserve the balance - as ReservableCurrency<_>>::reserve(&user, balance)?; - assert_eq!(Balances::::reserved_balance(&user), balance); - assert!(Balances::::free_balance(&user).is_zero()); + as ReservableCurrency<_>>::reserve(&user, ed)?; + assert_eq!(Balances::::reserved_balance(&user), ed); + assert_eq!(Balances::::free_balance(&user), ed); #[extrinsic_call] _(RawOrigin::Root, user_lookup, balance); assert!(Balances::::reserved_balance(&user).is_zero()); - assert_eq!(Balances::::free_balance(&user), balance); + assert_eq!(Balances::::free_balance(&user), ed + ed); Ok(()) } + #[benchmark] + fn upgrade_accounts(u: Linear<1, 1_000>) { + let caller: T::AccountId = whitelisted_caller(); + let who = (0..u) + .into_iter() + .map(|i| -> T::AccountId { + let user = account("old_user", i, SEED); + let account = AccountData { + free: T::ExistentialDeposit::get(), + reserved: T::ExistentialDeposit::get(), + frozen: Zero::zero(), + flags: ExtraFlags::old_logic(), + }; + frame_system::Pallet::::inc_providers(&user); + assert!(T::AccountStore::try_mutate_exists(&user, |a| -> DispatchResult { + *a = Some(account); + Ok(()) + }) + .is_ok()); + assert!(!Balances::::account(&user).flags.is_new_logic()); + assert_eq!(frame_system::Pallet::::providers(&user), 1); + assert_eq!(frame_system::Pallet::::consumers(&user), 0); + user + }) + .collect(); + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone()), who); + + for i in 0..u { + let user: T::AccountId = account("old_user", i, SEED); + assert!(Balances::::account(&user).flags.is_new_logic()); + assert_eq!(frame_system::Pallet::::providers(&user), 1); + assert_eq!(frame_system::Pallet::::consumers(&user), 1); + } + } + impl_benchmark_test_suite! { Balances, - crate::tests_composite::ExtBuilder::default().build(), - crate::tests_composite::Test, + crate::tests::ExtBuilder::default().build(), + crate::tests::Test, } } diff --git a/frame/balances/src/impl_currency.rs b/frame/balances/src/impl_currency.rs new file mode 100644 index 0000000000000..790a29f004764 --- /dev/null +++ b/frame/balances/src/impl_currency.rs @@ -0,0 +1,898 @@ +// 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. + +//! Implementations for the `Currency` family of traits. + +use super::*; +use frame_support::{ + ensure, + pallet_prelude::DispatchResult, + traits::{ + tokens::{fungible, BalanceStatus as Status}, + Currency, DefensiveSaturating, ExistenceRequirement, + ExistenceRequirement::AllowDeath, + Get, Imbalance, LockIdentifier, LockableCurrency, NamedReservableCurrency, + ReservableCurrency, SignedImbalance, TryDrop, WithdrawReasons, + }, +}; +pub use imbalances::{NegativeImbalance, PositiveImbalance}; + +// wrapping these imbalances in a private module is necessary to ensure absolute privacy +// of the inner member. +mod imbalances { + use super::{result, Config, Imbalance, RuntimeDebug, Saturating, TryDrop, Zero}; + use frame_support::traits::SameOrOther; + use sp_std::mem; + + /// Opaque, move-only struct with private fields that serves as a token denoting that + /// funds have been created without any equal and opposite accounting. + #[must_use] + #[derive(RuntimeDebug, PartialEq, Eq)] + pub struct PositiveImbalance, I: 'static = ()>(T::Balance); + + impl, I: 'static> PositiveImbalance { + /// Create a new positive imbalance from a balance. + pub fn new(amount: T::Balance) -> Self { + PositiveImbalance(amount) + } + } + + /// Opaque, move-only struct with private fields that serves as a token denoting that + /// funds have been destroyed without any equal and opposite accounting. + #[must_use] + #[derive(RuntimeDebug, PartialEq, Eq)] + pub struct NegativeImbalance, I: 'static = ()>(T::Balance); + + impl, I: 'static> NegativeImbalance { + /// Create a new negative imbalance from a balance. + pub fn new(amount: T::Balance) -> Self { + NegativeImbalance(amount) + } + } + + impl, I: 'static> TryDrop for PositiveImbalance { + fn try_drop(self) -> result::Result<(), Self> { + self.drop_zero() + } + } + + impl, I: 'static> Default for PositiveImbalance { + fn default() -> Self { + Self::zero() + } + } + + impl, I: 'static> Imbalance for PositiveImbalance { + type Opposite = NegativeImbalance; + + fn zero() -> Self { + Self(Zero::zero()) + } + fn drop_zero(self) -> result::Result<(), Self> { + if self.0.is_zero() { + Ok(()) + } else { + Err(self) + } + } + fn split(self, amount: T::Balance) -> (Self, Self) { + let first = self.0.min(amount); + let second = self.0 - first; + + mem::forget(self); + (Self(first), Self(second)) + } + fn merge(mut self, other: Self) -> Self { + self.0 = self.0.saturating_add(other.0); + mem::forget(other); + + self + } + fn subsume(&mut self, other: Self) { + self.0 = self.0.saturating_add(other.0); + mem::forget(other); + } + fn offset(self, other: Self::Opposite) -> SameOrOther { + let (a, b) = (self.0, other.0); + mem::forget((self, other)); + + if a > b { + SameOrOther::Same(Self(a - b)) + } else if b > a { + SameOrOther::Other(NegativeImbalance::new(b - a)) + } else { + SameOrOther::None + } + } + fn peek(&self) -> T::Balance { + self.0 + } + } + + impl, I: 'static> TryDrop for NegativeImbalance { + fn try_drop(self) -> result::Result<(), Self> { + self.drop_zero() + } + } + + impl, I: 'static> Default for NegativeImbalance { + fn default() -> Self { + Self::zero() + } + } + + impl, I: 'static> Imbalance for NegativeImbalance { + type Opposite = PositiveImbalance; + + fn zero() -> Self { + Self(Zero::zero()) + } + fn drop_zero(self) -> result::Result<(), Self> { + if self.0.is_zero() { + Ok(()) + } else { + Err(self) + } + } + fn split(self, amount: T::Balance) -> (Self, Self) { + let first = self.0.min(amount); + let second = self.0 - first; + + mem::forget(self); + (Self(first), Self(second)) + } + fn merge(mut self, other: Self) -> Self { + self.0 = self.0.saturating_add(other.0); + mem::forget(other); + + self + } + fn subsume(&mut self, other: Self) { + self.0 = self.0.saturating_add(other.0); + mem::forget(other); + } + fn offset(self, other: Self::Opposite) -> SameOrOther { + let (a, b) = (self.0, other.0); + mem::forget((self, other)); + + if a > b { + SameOrOther::Same(Self(a - b)) + } else if b > a { + SameOrOther::Other(PositiveImbalance::new(b - a)) + } else { + SameOrOther::None + } + } + fn peek(&self) -> T::Balance { + self.0 + } + } + + impl, I: 'static> Drop for PositiveImbalance { + /// Basic drop handler will just square up the total issuance. + fn drop(&mut self) { + >::mutate(|v| *v = v.saturating_add(self.0)); + } + } + + impl, I: 'static> Drop for NegativeImbalance { + /// Basic drop handler will just square up the total issuance. + fn drop(&mut self) { + >::mutate(|v| *v = v.saturating_sub(self.0)); + } + } +} + +impl, I: 'static> Currency for Pallet +where + T::Balance: MaybeSerializeDeserialize + Debug, +{ + type Balance = T::Balance; + type PositiveImbalance = PositiveImbalance; + type NegativeImbalance = NegativeImbalance; + + fn total_balance(who: &T::AccountId) -> Self::Balance { + Self::account(who).total() + } + + // Check if `value` amount of free balance can be slashed from `who`. + fn can_slash(who: &T::AccountId, value: Self::Balance) -> bool { + if value.is_zero() { + return true + } + Self::free_balance(who) >= value + } + + fn total_issuance() -> Self::Balance { + 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 { + T::ExistentialDeposit::get() + } + + // Burn funds from the total issuance, returning a positive imbalance for the amount burned. + // Is a no-op if amount to be burned is zero. + fn burn(mut amount: Self::Balance) -> Self::PositiveImbalance { + if amount.is_zero() { + return PositiveImbalance::zero() + } + >::mutate(|issued| { + *issued = issued.checked_sub(&amount).unwrap_or_else(|| { + amount = *issued; + Zero::zero() + }); + }); + PositiveImbalance::new(amount) + } + + // Create new funds into the total issuance, returning a negative imbalance + // for the amount issued. + // Is a no-op if amount to be issued it zero. + fn issue(mut amount: Self::Balance) -> Self::NegativeImbalance { + if amount.is_zero() { + return NegativeImbalance::zero() + } + >::mutate(|issued| { + *issued = issued.checked_add(&amount).unwrap_or_else(|| { + amount = Self::Balance::max_value() - *issued; + Self::Balance::max_value() + }) + }); + NegativeImbalance::new(amount) + } + + fn free_balance(who: &T::AccountId) -> Self::Balance { + Self::account(who).free + } + + // Ensure that an account can withdraw from their free balance given any existing withdrawal + // restrictions like locks and vesting balance. + // Is a no-op if amount to be withdrawn is zero. + fn ensure_can_withdraw( + who: &T::AccountId, + amount: T::Balance, + _reasons: WithdrawReasons, + new_balance: T::Balance, + ) -> DispatchResult { + if amount.is_zero() { + return Ok(()) + } + ensure!(new_balance >= Self::account(who).frozen, Error::::LiquidityRestrictions); + Ok(()) + } + + // Transfer some free balance from `transactor` to `dest`, respecting existence requirements. + // Is a no-op if value to be transferred is zero or the `transactor` is the same as `dest`. + fn transfer( + transactor: &T::AccountId, + dest: &T::AccountId, + value: Self::Balance, + existence_requirement: ExistenceRequirement, + ) -> DispatchResult { + if value.is_zero() || transactor == dest { + return Ok(()) + } + let keep_alive = match existence_requirement { + ExistenceRequirement::KeepAlive => Preserve, + ExistenceRequirement::AllowDeath => Expendable, + }; + >::transfer(transactor, dest, value, keep_alive)?; + Ok(()) + } + + /// Slash a target account `who`, returning the negative imbalance created and any left over + /// amount that could not be slashed. + /// + /// Is a no-op if `value` to be slashed is zero or the account does not exist. + /// + /// NOTE: `slash()` prefers free balance, but assumes that reserve balance can be drawn + /// from in extreme circumstances. `can_slash()` should be used prior to `slash()` to avoid + /// having to draw from reserved funds, however we err on the side of punishment if things are + /// inconsistent or `can_slash` wasn't used appropriately. + fn slash(who: &T::AccountId, value: Self::Balance) -> (Self::NegativeImbalance, Self::Balance) { + if value.is_zero() { + return (NegativeImbalance::zero(), Zero::zero()) + } + if Self::total_balance(who).is_zero() { + return (NegativeImbalance::zero(), value) + } + + let result = match Self::try_mutate_account_handling_dust( + who, + |account, _is_new| -> Result<(Self::NegativeImbalance, Self::Balance), DispatchError> { + // Best value is the most amount we can slash following liveness rules. + let ed = T::ExistentialDeposit::get(); + let actual = match system::Pallet::::can_dec_provider(who) { + true => value.min(account.free), + false => value.min(account.free.saturating_sub(ed)), + }; + account.free.saturating_reduce(actual); + let remaining = value.saturating_sub(actual); + Ok((NegativeImbalance::new(actual), remaining)) + }, + ) { + Ok((imbalance, remaining)) => { + Self::deposit_event(Event::Slashed { + who: who.clone(), + amount: value.saturating_sub(remaining), + }); + (imbalance, remaining) + }, + Err(_) => (Self::NegativeImbalance::zero(), value), + }; + result + } + + /// Deposit some `value` into the free balance of an existing target account `who`. + /// + /// Is a no-op if the `value` to be deposited is zero. + fn deposit_into_existing( + who: &T::AccountId, + value: Self::Balance, + ) -> Result { + if value.is_zero() { + return Ok(PositiveImbalance::zero()) + } + + Self::try_mutate_account_handling_dust( + who, + |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: who.clone(), amount: value }); + Ok(PositiveImbalance::new(value)) + }, + ) + } + + /// Deposit some `value` into the free balance of `who`, possibly creating a new account. + /// + /// This function is a no-op if: + /// - the `value` to be deposited is zero; or + /// - the `value` to be deposited is less than the required ED and the account does not yet + /// exist; or + /// - the deposit would necessitate the account to exist and there are no provider references; + /// or + /// - `value` is so large it would cause the balance of `who` to overflow. + fn deposit_creating(who: &T::AccountId, value: Self::Balance) -> Self::PositiveImbalance { + if value.is_zero() { + return Self::PositiveImbalance::zero() + } + + Self::try_mutate_account_handling_dust( + who, + |account, is_new| -> Result { + let ed = T::ExistentialDeposit::get(); + ensure!(value >= ed || !is_new, Error::::ExistentialDeposit); + + // defensive only: overflow should never happen, however in case it does, then this + // operation is a no-op. + account.free = match account.free.checked_add(&value) { + Some(x) => x, + None => return Ok(Self::PositiveImbalance::zero()), + }; + + Self::deposit_event(Event::Deposit { who: who.clone(), amount: value }); + Ok(PositiveImbalance::new(value)) + }, + ) + .unwrap_or_else(|_| Self::PositiveImbalance::zero()) + } + + /// Withdraw some free balance from an account, respecting existence requirements. + /// + /// Is a no-op if value to be withdrawn is zero. + fn withdraw( + who: &T::AccountId, + value: Self::Balance, + reasons: WithdrawReasons, + liveness: ExistenceRequirement, + ) -> result::Result { + if value.is_zero() { + return Ok(NegativeImbalance::zero()) + } + + Self::try_mutate_account_handling_dust( + who, + |account, _| -> Result { + let new_free_account = + account.free.checked_sub(&value).ok_or(Error::::InsufficientBalance)?; + + // bail if we need to keep the account alive and this would kill it. + let ed = T::ExistentialDeposit::get(); + let would_be_dead = new_free_account < ed; + let would_kill = would_be_dead && account.free >= ed; + ensure!(liveness == AllowDeath || !would_kill, Error::::Expendability); + + Self::ensure_can_withdraw(who, value, reasons, new_free_account)?; + + account.free = new_free_account; + + Self::deposit_event(Event::Withdraw { who: who.clone(), amount: value }); + Ok(NegativeImbalance::new(value)) + }, + ) + } + + /// Force the new free balance of a target account `who` to some new value `balance`. + fn make_free_balance_be( + who: &T::AccountId, + value: Self::Balance, + ) -> SignedImbalance { + Self::try_mutate_account_handling_dust( + who, + |account, + is_new| + -> Result, DispatchError> { + let ed = T::ExistentialDeposit::get(); + // If we're attempting to set an existing account to less than ED, then + // bypass the entire operation. It's a no-op if you follow it through, but + // since this is an instance where we might account for a negative imbalance + // (in the dust cleaner of set_account) before we account for its actual + // equal and opposite cause (returned as an Imbalance), then in the + // instance that there's no other accounts on the system at all, we might + // underflow the issuance and our arithmetic will be off. + ensure!(value >= ed || !is_new, Error::::ExistentialDeposit); + + let imbalance = if account.free <= value { + SignedImbalance::Positive(PositiveImbalance::new(value - account.free)) + } else { + SignedImbalance::Negative(NegativeImbalance::new(account.free - value)) + }; + account.free = value; + Self::deposit_event(Event::BalanceSet { who: who.clone(), free: account.free }); + Ok(imbalance) + }, + ) + .unwrap_or_else(|_| SignedImbalance::Positive(Self::PositiveImbalance::zero())) + } +} + +impl, I: 'static> ReservableCurrency for Pallet +where + T::Balance: MaybeSerializeDeserialize + Debug, +{ + /// Check if `who` can reserve `value` from their free balance. + /// + /// Always `true` if value to be reserved is zero. + fn can_reserve(who: &T::AccountId, value: Self::Balance) -> bool { + if value.is_zero() { + return true + } + Self::account(who).free.checked_sub(&value).map_or(false, |new_balance| { + Self::ensure_can_withdraw(who, value, WithdrawReasons::RESERVE, new_balance).is_ok() + }) + } + + fn reserved_balance(who: &T::AccountId) -> Self::Balance { + Self::account(who).reserved + } + + /// Move `value` from the free balance from `who` to their reserved balance. + /// + /// Is a no-op if value to be reserved is zero. + fn reserve(who: &T::AccountId, value: Self::Balance) -> DispatchResult { + if value.is_zero() { + return Ok(()) + } + + Self::try_mutate_account_handling_dust(who, |account, _| -> DispatchResult { + account.free = + 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, WithdrawReasons::RESERVE, account.free) + })?; + + Self::deposit_event(Event::Reserved { who: who.clone(), amount: value }); + Ok(()) + } + + /// 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() + } + if Self::total_balance(who).is_zero() { + return value + } + + let actual = match Self::mutate_account_handling_dust(who, |account| { + let actual = cmp::min(account.reserved, value); + 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.defensive_saturating_add(actual); + actual + }) { + Ok(x) => x, + Err(_) => { + // This should never happen since we don't alter the total amount in the account. + // If it ever does, then we should fail gracefully though, indicating that nothing + // could be done. + return value + }, + }; + + Self::deposit_event(Event::Unreserved { who: who.clone(), amount: actual }); + value - actual + } + + /// Slash from reserved balance, returning the negative imbalance created, + /// and any amount that was unable to be slashed. + /// + /// Is a no-op if the value to be slashed is zero or the account does not exist. + fn slash_reserved( + who: &T::AccountId, + value: Self::Balance, + ) -> (Self::NegativeImbalance, Self::Balance) { + if value.is_zero() { + return (NegativeImbalance::zero(), Zero::zero()) + } + if Self::total_balance(who).is_zero() { + return (NegativeImbalance::zero(), value) + } + + // NOTE: `mutate_account` may fail if it attempts to reduce the balance to the point that an + // account is attempted to be illegally destroyed. + + match Self::mutate_account_handling_dust(who, |account| { + let actual = value.min(account.reserved); + account.reserved.saturating_reduce(actual); + + // underflow should never happen, but it if does, there's nothing to be done here. + (NegativeImbalance::new(actual), value.saturating_sub(actual)) + }) { + Ok((imbalance, not_slashed)) => { + Self::deposit_event(Event::Slashed { + who: who.clone(), + amount: value.saturating_sub(not_slashed), + }); + (imbalance, not_slashed) + }, + Err(_) => (Self::NegativeImbalance::zero(), value), + } + } + + /// Move the reserved balance of one account into the balance of another, according to `status`. + /// + /// Is a no-op if: + /// - the value to be moved is zero; or + /// - the `slashed` id equal to `beneficiary` and the `status` is `Reserved`. + fn repatriate_reserved( + slashed: &T::AccountId, + beneficiary: &T::AccountId, + value: Self::Balance, + status: Status, + ) -> Result { + let actual = Self::do_transfer_reserved(slashed, beneficiary, value, true, status)?; + Ok(value.saturating_sub(actual)) + } +} + +impl, I: 'static> NamedReservableCurrency for Pallet +where + T::Balance: MaybeSerializeDeserialize + Debug, +{ + type ReserveIdentifier = T::ReserveIdentifier; + + fn reserved_balance_named(id: &Self::ReserveIdentifier, who: &T::AccountId) -> Self::Balance { + let reserves = Self::reserves(who); + reserves + .binary_search_by_key(id, |data| data.id) + .map(|index| reserves[index].amount) + .unwrap_or_default() + } + + /// Move `value` from the free balance from `who` to a named reserve balance. + /// + /// Is a no-op if value to be reserved is zero. + fn reserve_named( + id: &Self::ReserveIdentifier, + who: &T::AccountId, + value: Self::Balance, + ) -> DispatchResult { + if value.is_zero() { + return Ok(()) + } + + Reserves::::try_mutate(who, |reserves| -> DispatchResult { + 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.defensive_saturating_add(value); + }, + Err(index) => { + reserves + .try_insert(index, ReserveData { id: *id, amount: value }) + .map_err(|_| Error::::TooManyReserves)?; + }, + }; + >::reserve(who, value)?; + Ok(()) + }) + } + + /// Unreserve some funds, returning any amount that was unable to be unreserved. + /// + /// Is a no-op if the value to be unreserved is zero. + fn unreserve_named( + id: &Self::ReserveIdentifier, + who: &T::AccountId, + value: Self::Balance, + ) -> Self::Balance { + if value.is_zero() { + return Zero::zero() + } + + Reserves::::mutate_exists(who, |maybe_reserves| -> Self::Balance { + if let Some(reserves) = maybe_reserves.as_mut() { + match reserves.binary_search_by_key(id, |data| data.id) { + Ok(index) => { + let to_change = cmp::min(reserves[index].amount, value); + + let remain = >::unreserve(who, to_change); + + // 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; + + if reserves[index].amount.is_zero() { + if reserves.len() == 1 { + // no more named reserves + *maybe_reserves = None; + } else { + // remove this named reserve + reserves.remove(index); + } + } + + value - actual + }, + Err(_) => value, + } + } else { + value + } + }) + } + + /// Slash from reserved balance, returning the negative imbalance created, + /// and any amount that was unable to be slashed. + /// + /// Is a no-op if the value to be slashed is zero. + fn slash_reserved_named( + id: &Self::ReserveIdentifier, + who: &T::AccountId, + value: Self::Balance, + ) -> (Self::NegativeImbalance, Self::Balance) { + if value.is_zero() { + return (NegativeImbalance::zero(), Zero::zero()) + } + + Reserves::::mutate(who, |reserves| -> (Self::NegativeImbalance, Self::Balance) { + match reserves.binary_search_by_key(id, |data| data.id) { + Ok(index) => { + let to_change = cmp::min(reserves[index].amount, value); + + let (imb, remain) = + >::slash_reserved(who, to_change); + + // 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; + + Self::deposit_event(Event::Slashed { who: who.clone(), amount: actual }); + (imb, value - actual) + }, + Err(_) => (NegativeImbalance::zero(), value), + } + }) + } + + /// Move the reserved balance of one account into the balance of another, according to `status`. + /// If `status` is `Reserved`, the balance will be reserved with given `id`. + /// + /// Is a no-op if: + /// - the value to be moved is zero; or + /// - the `slashed` id equal to `beneficiary` and the `status` is `Reserved`. + fn repatriate_reserved_named( + id: &Self::ReserveIdentifier, + slashed: &T::AccountId, + beneficiary: &T::AccountId, + value: Self::Balance, + status: Status, + ) -> Result { + if value.is_zero() { + return Ok(Zero::zero()) + } + + if slashed == beneficiary { + return match status { + Status::Free => Ok(Self::unreserve_named(id, slashed, value)), + Status::Reserved => + Ok(value.saturating_sub(Self::reserved_balance_named(id, slashed))), + } + } + + Reserves::::try_mutate(slashed, |reserves| -> Result { + match reserves.binary_search_by_key(id, |data| data.id) { + Ok(index) => { + let to_change = cmp::min(reserves[index].amount, value); + + let actual = if status == Status::Reserved { + // make it the reserved under same identifier + Reserves::::try_mutate( + beneficiary, + |reserves| -> Result { + match reserves.binary_search_by_key(id, |data| data.id) { + Ok(index) => { + let remain = + >::repatriate_reserved( + slashed, + beneficiary, + to_change, + status, + )?; + + // remain should always be zero but just to be defensive + // 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.defensive_saturating_add(actual); + + Ok(actual) + }, + Err(index) => { + let remain = + >::repatriate_reserved( + slashed, + beneficiary, + to_change, + status, + )?; + + // remain should always be zero but just to be defensive + // here + let actual = to_change.defensive_saturating_sub(remain); + + reserves + .try_insert( + index, + ReserveData { id: *id, amount: actual }, + ) + .map_err(|_| Error::::TooManyReserves)?; + + Ok(actual) + }, + } + }, + )? + } else { + let remain = >::repatriate_reserved( + slashed, + beneficiary, + to_change, + status, + )?; + + // remain should always be zero but just to be defensive here + to_change.defensive_saturating_sub(remain) + }; + + // `actual <= to_change` and `to_change <= amount`; qed; + reserves[index].amount -= actual; + + Ok(value - actual) + }, + Err(_) => Ok(value), + } + }) + } +} + +impl, I: 'static> LockableCurrency for Pallet +where + T::Balance: MaybeSerializeDeserialize + Debug, +{ + type Moment = T::BlockNumber; + + type MaxLocks = T::MaxLocks; + + // 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, + who: &T::AccountId, + amount: T::Balance, + reasons: WithdrawReasons, + ) { + if amount.is_zero() || reasons.is_empty() { + return + } + let mut new_lock = Some(BalanceLock { id, amount, reasons: reasons.into() }); + let mut locks = Self::locks(who) + .into_iter() + .filter_map(|l| if l.id == id { new_lock.take() } else { Some(l) }) + .collect::>(); + if let Some(lock) = new_lock { + locks.push(lock) + } + Self::update_locks(who, &locks[..]); + } + + // 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, + who: &T::AccountId, + amount: T::Balance, + reasons: WithdrawReasons, + ) { + if amount.is_zero() || reasons.is_empty() { + return + } + let mut new_lock = Some(BalanceLock { id, amount, reasons: reasons.into() }); + let mut locks = Self::locks(who) + .into_iter() + .filter_map(|l| { + if l.id == id { + new_lock.take().map(|nl| BalanceLock { + id: l.id, + amount: l.amount.max(nl.amount), + reasons: l.reasons | nl.reasons, + }) + } else { + Some(l) + } + }) + .collect::>(); + if let Some(lock) = new_lock { + locks.push(lock) + } + Self::update_locks(who, &locks[..]); + } + + 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/impl_fungible.rs b/frame/balances/src/impl_fungible.rs new file mode 100644 index 0000000000000..f8f8fe17ae0ef --- /dev/null +++ b/frame/balances/src/impl_fungible.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. + +//! Implementation of `fungible` traits for Balances pallet. +use super::*; +use frame_support::traits::tokens::{ + Fortitude, + Preservation::{self, Preserve, Protect}, + Provenance::{self, Minted}, +}; + +impl, I: 'static> fungible::Inspect for Pallet { + type Balance = T::Balance; + + 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() + } + fn total_balance(who: &T::AccountId) -> Self::Balance { + Self::account(who).total() + } + fn balance(who: &T::AccountId) -> Self::Balance { + Self::account(who).free + } + fn reducible_balance( + who: &T::AccountId, + preservation: Preservation, + force: Fortitude, + ) -> Self::Balance { + let a = Self::account(who); + let mut untouchable = Zero::zero(); + if force == Polite { + // Frozen balance applies to total. Anything on hold therefore gets discounted from the + // limit given by the freezes. + untouchable = a.frozen.saturating_sub(a.reserved); + } + // If we want to keep our provider ref.. + if preservation == Preserve + // ..or we don't want the account to die and our provider ref is needed for it to live.. + || preservation == Protect && !a.free.is_zero() && + frame_system::Pallet::::providers(who) == 1 + // ..or we don't care about the account dying but our provider ref is required.. + || preservation == Expendable && !a.free.is_zero() && + !frame_system::Pallet::::can_dec_provider(who) + { + // ..then the ED needed.. + untouchable = untouchable.max(T::ExistentialDeposit::get()); + } + // Liquid balance is what is neither on hold nor frozen/required for provider. + a.free.saturating_sub(untouchable) + } + fn can_deposit( + who: &T::AccountId, + amount: Self::Balance, + provenance: Provenance, + ) -> DepositConsequence { + if amount.is_zero() { + return DepositConsequence::Success + } + + if provenance == Minted && TotalIssuance::::get().checked_add(&amount).is_none() { + return DepositConsequence::Overflow + } + + let account = Self::account(who); + let new_free = match account.free.checked_add(&amount) { + None => return DepositConsequence::Overflow, + Some(x) if x < T::ExistentialDeposit::get() => return DepositConsequence::BelowMinimum, + Some(x) => x, + }; + + match account.reserved.checked_add(&new_free) { + Some(_) => {}, + None => return DepositConsequence::Overflow, + }; + + // NOTE: We assume that we are a provider, so don't need to do any checks in the + // case of account creation. + + DepositConsequence::Success + } + fn can_withdraw( + who: &T::AccountId, + amount: Self::Balance, + ) -> WithdrawConsequence { + if amount.is_zero() { + return WithdrawConsequence::Success + } + + if TotalIssuance::::get().checked_sub(&amount).is_none() { + return WithdrawConsequence::Underflow + } + + let account = Self::account(who); + let new_free_balance = match account.free.checked_sub(&amount) { + Some(x) => x, + None => return WithdrawConsequence::BalanceLow, + }; + + let liquid = Self::reducible_balance(who, Expendable, Polite); + if amount > liquid { + return WithdrawConsequence::Frozen + } + + // Provider restriction - total account balance cannot be reduced to zero if it cannot + // sustain the loss of a provider reference. + // NOTE: This assumes that the pallet is a provider (which is true). Is this ever changes, + // then this will need to adapt accordingly. + let ed = T::ExistentialDeposit::get(); + let success = if new_free_balance < ed { + if frame_system::Pallet::::can_dec_provider(who) { + WithdrawConsequence::ReducedToZero(new_free_balance) + } else { + return WithdrawConsequence::WouldDie + } + } else { + WithdrawConsequence::Success + }; + + let new_total_balance = new_free_balance.saturating_add(account.reserved); + + // Eventual free funds must be no less than the frozen balance. + if new_total_balance < account.frozen { + return WithdrawConsequence::Frozen + } + + success + } +} + +impl, I: 'static> fungible::Unbalanced for Pallet { + fn handle_dust(dust: fungible::Dust) { + T::DustRemoval::on_unbalanced(dust.into_credit()); + } + fn write_balance( + who: &T::AccountId, + amount: Self::Balance, + ) -> Result, DispatchError> { + let max_reduction = + >::reducible_balance(who, Expendable, Force); + let (result, maybe_dust) = Self::mutate_account(who, |account| -> DispatchResult { + // Make sure the reduction (if there is one) is no more than the maximum allowed. + let reduction = account.free.saturating_sub(amount); + ensure!(reduction <= max_reduction, Error::::InsufficientBalance); + + account.free = amount; + Ok(()) + })?; + result?; + Ok(maybe_dust) + } + + fn set_total_issuance(amount: Self::Balance) { + TotalIssuance::::mutate(|t| *t = 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::Mutate for Pallet { + fn done_mint_into(who: &T::AccountId, amount: Self::Balance) { + Self::deposit_event(Event::::Minted { who: who.clone(), amount }); + } + fn done_burn_from(who: &T::AccountId, amount: Self::Balance) { + Self::deposit_event(Event::::Burned { who: who.clone(), amount }); + } + fn done_shelve(who: &T::AccountId, amount: Self::Balance) { + Self::deposit_event(Event::::Suspended { who: who.clone(), amount }); + } + fn done_restore(who: &T::AccountId, amount: Self::Balance) { + Self::deposit_event(Event::::Restored { who: who.clone(), amount }); + } + fn done_transfer(source: &T::AccountId, dest: &T::AccountId, amount: Self::Balance) { + Self::deposit_event(Event::::Transfer { + from: source.clone(), + to: dest.clone(), + amount, + }); + } +} + +impl, I: 'static> fungible::MutateHold for Pallet {} + +impl, I: 'static> fungible::InspectHold for Pallet { + type Reason = T::HoldIdentifier; + + fn total_balance_on_hold(who: &T::AccountId) -> T::Balance { + Self::account(who).reserved + } + fn reducible_total_balance_on_hold(who: &T::AccountId, force: Fortitude) -> Self::Balance { + // The total balance must never drop below the freeze requirements if we're not forcing: + let a = Self::account(who); + let unavailable = if force == Force { + Self::Balance::zero() + } else { + // The freeze lock applies to the total balance, so we can discount the free balance + // from the amount which the total reserved balance must provide to satisfy it. + a.frozen.saturating_sub(a.free) + }; + a.reserved.saturating_sub(unavailable) + } + fn balance_on_hold(reason: &Self::Reason, who: &T::AccountId) -> T::Balance { + Holds::::get(who) + .iter() + .find(|x| &x.id == reason) + .map_or_else(Zero::zero, |x| x.amount) + } + fn hold_available(reason: &Self::Reason, who: &T::AccountId) -> bool { + if frame_system::Pallet::::providers(who) == 0 { + return false + } + let holds = Holds::::get(who); + if holds.is_full() && !holds.iter().any(|x| &x.id == reason) { + return false + } + true + } +} + +impl, I: 'static> fungible::UnbalancedHold for Pallet { + fn set_balance_on_hold( + reason: &Self::Reason, + who: &T::AccountId, + amount: Self::Balance, + ) -> DispatchResult { + let mut new_account = Self::account(who); + let mut holds = Holds::::get(who); + let mut increase = true; + let mut delta = amount; + + if let Some(item) = holds.iter_mut().find(|x| &x.id == reason) { + delta = item.amount.max(amount) - item.amount.min(amount); + increase = amount > item.amount; + item.amount = amount; + holds.retain(|x| !x.amount.is_zero()); + } else { + if !amount.is_zero() { + holds + .try_push(IdAmount { id: *reason, amount }) + .map_err(|_| Error::::TooManyHolds)?; + } + } + + new_account.reserved = if increase { + new_account.reserved.checked_add(&delta).ok_or(ArithmeticError::Overflow)? + } else { + new_account.reserved.checked_sub(&delta).ok_or(ArithmeticError::Underflow)? + }; + + let (result, maybe_dust) = Self::try_mutate_account(who, |a, _| -> DispatchResult { + *a = new_account; + Ok(()) + })?; + debug_assert!( + maybe_dust.is_none(), + "Does not alter main balance; dust only happens when it is altered; qed" + ); + Holds::::insert(who, holds); + Ok(result) + } +} + +impl, I: 'static> fungible::InspectFreeze for Pallet { + type Id = T::FreezeIdentifier; + + fn balance_frozen(id: &Self::Id, who: &T::AccountId) -> Self::Balance { + let locks = Freezes::::get(who); + locks.into_iter().find(|l| &l.id == id).map_or(Zero::zero(), |l| l.amount) + } + + fn can_freeze(id: &Self::Id, who: &T::AccountId) -> bool { + let l = Freezes::::get(who); + !l.is_full() || l.iter().any(|x| &x.id == id) + } +} + +impl, I: 'static> fungible::MutateFreeze for Pallet { + fn set_freeze(id: &Self::Id, who: &T::AccountId, amount: Self::Balance) -> DispatchResult { + if amount.is_zero() { + return Self::thaw(id, who) + } + let mut locks = Freezes::::get(who); + if let Some(i) = locks.iter_mut().find(|x| &x.id == id) { + i.amount = amount; + } else { + locks + .try_push(IdAmount { id: *id, amount }) + .map_err(|_| Error::::TooManyFreezes)?; + } + Self::update_freezes(who, locks.as_bounded_slice()) + } + + fn extend_freeze(id: &Self::Id, who: &T::AccountId, amount: Self::Balance) -> DispatchResult { + if amount.is_zero() { + return Ok(()) + } + let mut locks = Freezes::::get(who); + if let Some(i) = locks.iter_mut().find(|x| &x.id == id) { + i.amount = i.amount.max(amount); + } else { + locks + .try_push(IdAmount { id: *id, amount }) + .map_err(|_| Error::::TooManyFreezes)?; + } + Self::update_freezes(who, locks.as_bounded_slice()) + } + + fn thaw(id: &Self::Id, who: &T::AccountId) -> DispatchResult { + let mut locks = Freezes::::get(who); + locks.retain(|l| &l.id != id); + Self::update_freezes(who, locks.as_bounded_slice()) + } +} + +impl, I: 'static> fungible::Balanced for Pallet { + type OnDropCredit = fungible::DecreaseIssuance; + type OnDropDebt = fungible::IncreaseIssuance; + + fn done_deposit(who: &T::AccountId, amount: Self::Balance) { + Self::deposit_event(Event::::Deposit { who: who.clone(), amount }); + } + fn done_withdraw(who: &T::AccountId, amount: Self::Balance) { + Self::deposit_event(Event::::Withdraw { who: who.clone(), amount }); + } + fn done_issue(amount: Self::Balance) { + Self::deposit_event(Event::::Issued { amount }); + } + fn done_rescind(amount: Self::Balance) { + Self::deposit_event(Event::::Rescinded { amount }); + } +} + +impl, I: 'static> fungible::BalancedHold for Pallet {} diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index ecd7e171e39ec..ca8e86ef2f64a 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -89,8 +89,9 @@ //! //! ### Dispatchable Functions //! -//! - `transfer` - Transfer some liquid free balance to another account. -//! - `set_balance` - Set the balances of a given account. The origin of this call must be root. +//! - `transfer_allow_death` - Transfer some liquid free balance to another account. +//! - `force_set_balance` - Set the balances of a given account. The origin of this call must be +//! root. //! //! ## Usage //! @@ -152,43 +153,43 @@ //! * Total issued balanced of all accounts should be less than `Config::Balance::max_value()`. #![cfg_attr(not(feature = "std"), no_std)] - -#[macro_use] -mod tests; mod benchmarking; +mod impl_currency; +mod impl_fungible; pub mod migration; -mod tests_composite; -mod tests_local; -#[cfg(test)] -mod tests_reentrancy; +mod tests; +mod types; pub mod weights; -pub use self::imbalances::{NegativeImbalance, PositiveImbalance}; -use codec::{Codec, Decode, Encode, MaxEncodedLen}; +use codec::{Codec, MaxEncodedLen}; #[cfg(feature = "std")] use frame_support::traits::GenesisBuild; use frame_support::{ ensure, pallet_prelude::DispatchResult, traits::{ - tokens::{fungible, BalanceStatus as Status, DepositConsequence, WithdrawConsequence}, - Currency, DefensiveSaturating, ExistenceRequirement, - ExistenceRequirement::{AllowDeath, KeepAlive}, - Get, Imbalance, LockIdentifier, LockableCurrency, NamedReservableCurrency, OnUnbalanced, - ReservableCurrency, SignedImbalance, StoredMap, TryDrop, WithdrawReasons, + tokens::{ + fungible, BalanceStatus as Status, DepositConsequence, + Fortitude::{self, Force, Polite}, + Preservation::{Expendable, Preserve, Protect}, + WithdrawConsequence, + }, + Currency, Defensive, Get, OnUnbalanced, ReservableCurrency, StoredMap, }, - WeakBoundedVec, + BoundedSlice, WeakBoundedVec, }; use frame_system as system; +pub use impl_currency::{NegativeImbalance, PositiveImbalance}; use scale_info::TypeInfo; use sp_runtime::{ traits::{ AtLeast32BitUnsigned, Bounded, CheckedAdd, CheckedSub, MaybeSerializeDeserialize, Saturating, StaticLookup, Zero, }, - ArithmeticError, DispatchError, FixedPointOperand, RuntimeDebug, + ArithmeticError, DispatchError, FixedPointOperand, Perbill, RuntimeDebug, TokenError, }; -use sp_std::{cmp, fmt::Debug, mem, ops::BitOr, prelude::*, result}; +use sp_std::{cmp, fmt::Debug, mem, prelude::*, result}; +pub use types::{AccountData, BalanceLock, DustCleaner, IdAmount, Reasons, ReserveData}; pub use weights::WeightInfo; pub use pallet::*; @@ -200,11 +201,20 @@ type AccountIdLookupOf = <::Lookup as StaticLookup #[frame_support::pallet] pub mod pallet { use super::*; - use frame_support::pallet_prelude::*; + use frame_support::{pallet_prelude::*, traits::fungible::Credit}; use frame_system::pallet_prelude::*; + pub type CreditOf = Credit<::AccountId, Pallet>; + #[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; + /// The balance of an account. type Balance: Parameter + Member @@ -219,11 +229,7 @@ pub mod pallet { + FixedPointOperand; /// Handler for the unbalanced reduction when removing a dust account. - type DustRemoval: OnUnbalanced>; - - /// The overarching event type. - type RuntimeEvent: From> - + IsType<::RuntimeEvent>; + type DustRemoval: OnUnbalanced>; /// The minimum amount required to keep an account open. #[pallet::constant] @@ -232,8 +238,16 @@ pub mod pallet { /// The means of storing the balances of an account. type AccountStore: StoredMap>; - /// Weight information for extrinsics in this pallet. - type WeightInfo: WeightInfo; + /// The ID type for reserves. + /// + /// Use of reserves is deprecated in favour of holds. See `https://github.com/paritytech/substrate/pull/12951/` + type ReserveIdentifier: Parameter + Member + MaxEncodedLen + Ord + Copy; + + /// The ID type for holds. + type HoldIdentifier: Parameter + Member + MaxEncodedLen + Ord + Copy; + + /// The ID type for freezes. + type FreezeIdentifier: Parameter + Member + MaxEncodedLen + Ord + Copy; /// The maximum number of locks that should exist on an account. /// Not strictly enforced, but used for weight estimation. @@ -244,8 +258,13 @@ pub mod pallet { #[pallet::constant] type MaxReserves: Get; - /// The id type for named reserves. - type ReserveIdentifier: Parameter + Member + MaxEncodedLen + Ord + Copy; + /// The maximum number of holds that can exist on an account at any time. + #[pallet::constant] + type MaxHolds: Get; + + /// The maximum number of individual freeze locks that can exist on an account at any time. + #[pallet::constant] + type MaxFreezes: Get; } /// The current storage version. @@ -256,197 +275,6 @@ pub mod pallet { #[pallet::storage_version(STORAGE_VERSION)] pub struct Pallet(PhantomData<(T, I)>); - #[pallet::call] - impl, I: 'static> Pallet { - /// Transfer some liquid free balance to another account. - /// - /// `transfer` will set the `FreeBalance` of the sender and receiver. - /// If the sender's account is below the existential deposit as a result - /// of the transfer, the account will be reaped. - /// - /// The dispatch origin for this call must be `Signed` by the transactor. - /// - /// ## Complexity - /// - Dependent on arguments but not critical, given proper implementations for input config - /// types. See related functions below. - /// - It contains a limited number of reads and writes internally and no complex - /// computation. - /// - /// Related functions: - /// - /// - `ensure_can_withdraw` is always called internally but has a bounded complexity. - /// - Transferring balances to accounts that did not exist before will cause - /// `T::OnNewAccount::on_new_account` to be called. - /// - Removing enough funds from an account will trigger `T::DustRemoval::on_unbalanced`. - /// - `transfer_keep_alive` works the same way as `transfer`, but has an additional check - /// that the transfer will not kill the origin account. - #[pallet::call_index(0)] - #[pallet::weight(T::WeightInfo::transfer())] - pub fn transfer( - origin: OriginFor, - dest: AccountIdLookupOf, - #[pallet::compact] value: T::Balance, - ) -> DispatchResultWithPostInfo { - let transactor = ensure_signed(origin)?; - let dest = T::Lookup::lookup(dest)?; - >::transfer( - &transactor, - &dest, - value, - ExistenceRequirement::AllowDeath, - )?; - Ok(().into()) - } - - /// Set the balances of a given account. - /// - /// This will alter `FreeBalance` and `ReservedBalance` in storage. it will - /// 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`). - /// - /// 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. - )] - pub fn set_balance( - origin: OriginFor, - who: AccountIdLookupOf, - #[pallet::compact] new_free: T::Balance, - #[pallet::compact] new_reserved: T::Balance, - ) -> DispatchResultWithPostInfo { - ensure_root(origin)?; - let who = T::Lookup::lookup(who)?; - let existential_deposit = T::ExistentialDeposit::get(); - - let wipeout = new_free + new_reserved < existential_deposit; - let new_free = if wipeout { Zero::zero() } else { new_free }; - let new_reserved = if wipeout { Zero::zero() } else { 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; - - (old_free, old_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()) - } - - /// Exactly as `transfer`, except the origin must be root and the source account may be - /// specified. - /// ## Complexity - /// - 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, - source: AccountIdLookupOf, - dest: AccountIdLookupOf, - #[pallet::compact] value: T::Balance, - ) -> DispatchResultWithPostInfo { - ensure_root(origin)?; - let source = T::Lookup::lookup(source)?; - let dest = T::Lookup::lookup(dest)?; - >::transfer( - &source, - &dest, - value, - ExistenceRequirement::AllowDeath, - )?; - Ok(().into()) - } - - /// Same as the [`transfer`] call, but with a check that the transfer will not kill the - /// origin account. - /// - /// 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, - dest: AccountIdLookupOf, - #[pallet::compact] value: T::Balance, - ) -> DispatchResultWithPostInfo { - let transactor = ensure_signed(origin)?; - let dest = T::Lookup::lookup(dest)?; - >::transfer(&transactor, &dest, value, KeepAlive)?; - Ok(().into()) - } - - /// Transfer the entire transferable balance from the caller account. - /// - /// NOTE: This function only attempts to transfer _transferable_ balances. This means that - /// any locked, reserved, or existential deposits (when `keep_alive` is `true`), will not be - /// transferred by this function. To ensure that this function results in a killed account, - /// you might need to prepare the account by removing any reference counters, storage - /// deposits, etc... - /// - /// The dispatch origin of this call must be Signed. - /// - /// - `dest`: The recipient of the transfer. - /// - `keep_alive`: A boolean to determine if the `transfer_all` operation should send all - /// of the funds the account has, causing the sender account to be killed (false), or - /// transfer everything except at least the existential deposit, which will guarantee to - /// keep the sender account alive (true). ## Complexity - /// - 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, - dest: AccountIdLookupOf, - keep_alive: bool, - ) -> DispatchResult { - use fungible::Inspect; - let transactor = ensure_signed(origin)?; - 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)?; - Ok(()) - } - - /// 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, - who: AccountIdLookupOf, - amount: T::Balance, - ) -> DispatchResult { - ensure_root(origin)?; - let who = T::Lookup::lookup(who)?; - let _leftover = >::unreserve(&who, amount); - Ok(()) - } - } - #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event, I: 'static = ()> { @@ -458,7 +286,7 @@ pub mod pallet { /// 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 }, + BalanceSet { who: T::AccountId, free: 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). @@ -477,26 +305,44 @@ pub mod pallet { 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 }, + /// Some amount was minted into an account. + Minted { who: T::AccountId, amount: T::Balance }, + /// Some amount was burned from an account. + Burned { who: T::AccountId, amount: T::Balance }, + /// Some amount was suspended from an account (it can be restored later). + Suspended { who: T::AccountId, amount: T::Balance }, + /// Some amount was restored into an account. + Restored { who: T::AccountId, amount: T::Balance }, + /// An account was upgraded. + Upgraded { who: T::AccountId }, + /// Total issuance was increased by `amount`, creating a credit to be balanced. + Issued { amount: T::Balance }, + /// Total issuance was decreased by `amount`, creating a debt to be balanced. + Rescinded { amount: T::Balance }, } #[pallet::error] pub enum Error { - /// Vesting balance too high to send value + /// Vesting balance too high to send value. VestingBalance, - /// Account liquidity restrictions prevent withdrawal + /// Account liquidity restrictions prevent withdrawal. LiquidityRestrictions, /// Balance too low to send value. InsufficientBalance, - /// Value too low to create account due to existential deposit + /// Value too low to create account due to existential deposit. ExistentialDeposit, - /// Transfer/payment would kill account - KeepAlive, - /// A vesting schedule already exists for this account + /// Transfer/payment would kill account. + Expendability, + /// A vesting schedule already exists for this account. ExistingVestingSchedule, - /// Beneficiary account must pre-exist + /// Beneficiary account must pre-exist. DeadAccount, - /// Number of named reserves exceed MaxReserves + /// Number of named reserves exceed `MaxReserves`. TooManyReserves, + /// Number of holds exceed `MaxHolds`. + TooManyHolds, + /// Number of freezes exceed `MaxFreezes`. + TooManyFreezes, } /// The total units issued in the system. @@ -563,6 +409,26 @@ pub mod pallet { ValueQuery, >; + /// Holds on account balances. + #[pallet::storage] + pub type Holds, I: 'static = ()> = StorageMap< + _, + Blake2_128Concat, + T::AccountId, + BoundedVec, T::MaxHolds>, + ValueQuery, + >; + + /// Freeze locks on account balances. + #[pallet::storage] + pub type Freezes, I: 'static = ()> = StorageMap< + _, + Blake2_128Concat, + T::AccountId, + BoundedVec, T::MaxFreezes>, + ValueQuery, + >; + #[pallet::genesis_config] pub struct GenesisConfig, I: 'static = ()> { pub balances: Vec<(T::AccountId, T::Balance)>, @@ -602,1601 +468,646 @@ pub mod pallet { ); for &(ref who, free) in self.balances.iter() { + frame_system::Pallet::::inc_providers(who); assert!(T::AccountStore::insert(who, AccountData { free, ..Default::default() }) .is_ok()); } } } -} - -#[cfg(feature = "std")] -impl, I: 'static> GenesisConfig { - /// Direct implementation of `GenesisBuild::build_storage`. - /// - /// Kept in order not to break dependency. - pub fn build_storage(&self) -> Result { - >::build_storage(self) - } - - /// Direct implementation of `GenesisBuild::assimilate_storage`. - /// - /// Kept in order not to break dependency. - pub fn assimilate_storage(&self, storage: &mut sp_runtime::Storage) -> Result<(), String> { - >::assimilate_storage(self, storage) - } -} - -/// Simplified reasons for withdrawing balance. -#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, MaxEncodedLen, TypeInfo)] -pub enum Reasons { - /// Paying system transaction fees. - Fee = 0, - /// Any reason other than paying system transaction fees. - Misc = 1, - /// Any reason at all. - All = 2, -} - -impl From for Reasons { - fn from(r: WithdrawReasons) -> Reasons { - if r == WithdrawReasons::TRANSACTION_PAYMENT { - Reasons::Fee - } else if r.contains(WithdrawReasons::TRANSACTION_PAYMENT) { - Reasons::All - } else { - Reasons::Misc - } - } -} -impl BitOr for Reasons { - type Output = Reasons; - fn bitor(self, other: Reasons) -> Reasons { - if self == other { - return self + #[cfg(feature = "std")] + impl, I: 'static> GenesisConfig { + /// Direct implementation of `GenesisBuild::build_storage`. + /// + /// Kept in order not to break dependency. + pub fn build_storage(&self) -> Result { + >::build_storage(self) } - Reasons::All - } -} - -/// A single lock on a balance. There can be many of these on an account and they "overlap", so the -/// same balance is frozen by multiple locks. -#[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, - /// 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. - pub reasons: Reasons, -} - -/// Store named reserved balance. -#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, MaxEncodedLen, TypeInfo)] -pub struct ReserveData { - /// The identifier for the named reserve. - pub id: ReserveIdentifier, - /// The amount of the named reserve. - pub amount: Balance, -} - -/// All balance information for an account. -#[derive(Encode, Decode, Clone, PartialEq, Eq, Default, RuntimeDebug, MaxEncodedLen, TypeInfo)] -pub struct AccountData { - /// Non-reserved part of the balance. There may still be restrictions on this, but it is the - /// total pool what may in principle be transferred, reserved and used for tipping. - /// - /// This is the only balance that matters in terms of most operations on tokens. It - /// alone is used to determine the balance when in the contract execution environment. - pub free: Balance, - /// Balance which is reserved and may not be used at all. - /// - /// This can still get slashed, but gets slashed last of all. - /// - /// This balance is a 'reserve' balance that other subsystems use in order to set aside tokens - /// that are still 'owned' by the account holder, but which are suspendable. - /// This includes named reserve and unnamed reserve. - pub reserved: Balance, - /// The amount that `free` may not drop below when withdrawing for *anything except transaction - /// fee payment*. - pub misc_frozen: Balance, - /// The amount that `free` may not drop below when withdrawing specifically for transaction - /// fee payment. - pub fee_frozen: Balance, -} -impl AccountData { - /// How much this account's balance can be reduced for the given `reasons`. - fn usable(&self, reasons: Reasons) -> Balance { - self.free.saturating_sub(self.frozen(reasons)) - } - /// The amount that this account's free balance may not be reduced beyond for the given - /// `reasons`. - fn frozen(&self, reasons: Reasons) -> Balance { - match reasons { - Reasons::All => self.misc_frozen.max(self.fee_frozen), - Reasons::Misc => self.misc_frozen, - Reasons::Fee => self.fee_frozen, + /// Direct implementation of `GenesisBuild::assimilate_storage`. + /// + /// Kept in order not to break dependency. + pub fn assimilate_storage(&self, storage: &mut sp_runtime::Storage) -> Result<(), String> { + >::assimilate_storage(self, storage) } } - /// The total balance in this account including any that is reserved and ignoring any frozen. - fn total(&self) -> Balance { - self.free.saturating_add(self.reserved) - } -} -pub struct DustCleaner, I: 'static = ()>( - Option<(T::AccountId, NegativeImbalance)>, -); - -impl, I: 'static> Drop for DustCleaner { - fn drop(&mut self) { - if let Some((who, dust)) = self.0.take() { - Pallet::::deposit_event(Event::DustLost { account: who, amount: dust.peek() }); - T::DustRemoval::on_unbalanced(dust); + #[pallet::call] + impl, I: 'static> Pallet { + /// Transfer some liquid free balance to another account. + /// + /// `transfer_allow_death` will set the `FreeBalance` of the sender and receiver. + /// If the sender's account is below the existential deposit as a result + /// of the transfer, the account will be reaped. + /// + /// The dispatch origin for this call must be `Signed` by the transactor. + #[pallet::call_index(0)] + #[pallet::weight(T::WeightInfo::transfer_allow_death())] + pub fn transfer_allow_death( + origin: OriginFor, + dest: AccountIdLookupOf, + #[pallet::compact] value: T::Balance, + ) -> DispatchResultWithPostInfo { + let source = ensure_signed(origin)?; + let dest = T::Lookup::lookup(dest)?; + >::transfer(&source, &dest, value, Expendable)?; + Ok(().into()) } - } -} -impl, I: 'static> Pallet { - /// Get the free balance of an account. - pub fn free_balance(who: impl sp_std::borrow::Borrow) -> T::Balance { - Self::account(who.borrow()).free - } + /// Set the regular balance of a given account; it also takes a reserved balance but this + /// must be the same as the account's current reserved balance. + /// + /// The dispatch origin for this call is `root`. + /// + /// WARNING: This call is DEPRECATED! Use `force_set_balance` instead. + #[pallet::call_index(1)] + #[pallet::weight( + T::WeightInfo::force_set_balance_creating() // Creates a new account. + .max(T::WeightInfo::force_set_balance_killing()) // Kills an existing account. + )] + pub fn set_balance_deprecated( + origin: OriginFor, + who: AccountIdLookupOf, + #[pallet::compact] new_free: T::Balance, + #[pallet::compact] old_reserved: T::Balance, + ) -> DispatchResultWithPostInfo { + ensure_root(origin)?; + let who = T::Lookup::lookup(who)?; + let existential_deposit = T::ExistentialDeposit::get(); - /// Get the balance of an account that can be used for transfers, reservations, or any other - /// non-locking, non-transaction-fee activity. Will be at most `free_balance`. - pub fn usable_balance(who: impl sp_std::borrow::Borrow) -> T::Balance { - Self::account(who.borrow()).usable(Reasons::Misc) - } + let wipeout = new_free < existential_deposit; + let new_free = if wipeout { Zero::zero() } else { new_free }; - /// Get the balance of an account that can be used for paying transaction fees (not tipping, - /// or any other kind of fees, though). Will be at most `free_balance`. - pub fn usable_balance_for_fees(who: impl sp_std::borrow::Borrow) -> T::Balance { - Self::account(who.borrow()).usable(Reasons::Fee) - } + // First we try to modify the account's balance to the forced balance. + let old_free = Self::try_mutate_account_handling_dust( + &who, + |account, _is_new| -> Result { + let old_free = account.free; + ensure!(account.reserved == old_reserved, TokenError::Unsupported); + account.free = new_free; + Ok(old_free) + }, + )?; - /// Get the reserved balance of an account. - pub fn reserved_balance(who: impl sp_std::borrow::Borrow) -> T::Balance { - Self::account(who.borrow()).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)); + } - /// Get both the free and reserved balances of an account. - fn account(who: &T::AccountId) -> AccountData { - T::AccountStore::get(who) - } + Self::deposit_event(Event::BalanceSet { who, free: new_free }); + Ok(().into()) + } - /// Handles any steps needed after mutating an account. - /// - /// This includes DustRemoval unbalancing, in the case than the `new` account's total balance - /// is non-zero but below ED. - /// - /// Returns two values: - /// - `Some` containing the the `new` account, iff the account has sufficient balance. - /// - `Some` containing the dust to be dropped, iff some dust should be dropped. - fn post_mutation( - _who: &T::AccountId, - new: AccountData, - ) -> (Option>, Option>) { - let total = new.total(); - if total < T::ExistentialDeposit::get() { - if total.is_zero() { - (None, None) - } else { - (None, Some(NegativeImbalance::new(total))) - } - } else { - (Some(new), None) - } - } - - fn deposit_consequence( - _who: &T::AccountId, - amount: T::Balance, - account: &AccountData, - mint: bool, - ) -> DepositConsequence { - if amount.is_zero() { - return DepositConsequence::Success - } - - if mint && TotalIssuance::::get().checked_add(&amount).is_none() { - return DepositConsequence::Overflow - } - - let new_total_balance = match account.total().checked_add(&amount) { - Some(x) => x, - None => return DepositConsequence::Overflow, - }; - - if new_total_balance < T::ExistentialDeposit::get() { - return DepositConsequence::BelowMinimum - } - - // NOTE: We assume that we are a provider, so don't need to do any checks in the - // case of account creation. - - DepositConsequence::Success - } - - fn withdraw_consequence( - who: &T::AccountId, - amount: T::Balance, - account: &AccountData, - ) -> WithdrawConsequence { - if amount.is_zero() { - return WithdrawConsequence::Success - } - - if TotalIssuance::::get().checked_sub(&amount).is_none() { - return WithdrawConsequence::Underflow + /// Exactly as `transfer_allow_death`, except the origin must be root and the source account + /// may be specified. + #[pallet::call_index(2)] + #[pallet::weight(T::WeightInfo::force_transfer())] + pub fn force_transfer( + origin: OriginFor, + source: AccountIdLookupOf, + dest: AccountIdLookupOf, + #[pallet::compact] value: T::Balance, + ) -> DispatchResultWithPostInfo { + ensure_root(origin)?; + let source = T::Lookup::lookup(source)?; + let dest = T::Lookup::lookup(dest)?; + >::transfer(&source, &dest, value, Expendable)?; + Ok(().into()) } - let new_total_balance = match account.total().checked_sub(&amount) { - Some(x) => x, - None => return WithdrawConsequence::NoFunds, - }; - - // Provider restriction - total account balance cannot be reduced to zero if it cannot - // sustain the loss of a provider reference. - // NOTE: This assumes that the pallet is a provider (which is true). Is this ever changes, - // then this will need to adapt accordingly. - let ed = T::ExistentialDeposit::get(); - let success = if new_total_balance < ed { - if frame_system::Pallet::::can_dec_provider(who) { - WithdrawConsequence::ReducedToZero(new_total_balance) - } else { - return WithdrawConsequence::WouldDie - } - } else { - WithdrawConsequence::Success - }; - - // Enough free funds to have them be reduced. - let new_free_balance = match account.free.checked_sub(&amount) { - Some(b) => b, - None => return WithdrawConsequence::NoFunds, - }; - - // Eventual free funds must be no less than the frozen balance. - let min_balance = account.frozen(Reasons::All); - if new_free_balance < min_balance { - return WithdrawConsequence::Frozen + /// Same as the [`transfer_allow_death`] call, but with a check that the transfer will not + /// kill the origin account. + /// + /// 99% of the time you want [`transfer_allow_death`] instead. + /// + /// [`transfer_allow_death`]: struct.Pallet.html#method.transfer + #[pallet::call_index(3)] + #[pallet::weight(T::WeightInfo::transfer_keep_alive())] + pub fn transfer_keep_alive( + origin: OriginFor, + dest: AccountIdLookupOf, + #[pallet::compact] value: T::Balance, + ) -> DispatchResultWithPostInfo { + let source = ensure_signed(origin)?; + let dest = T::Lookup::lookup(dest)?; + >::transfer(&source, &dest, value, Preserve)?; + Ok(().into()) } - success - } - - /// Mutate an account to some new value, or delete it entirely with `None`. Will enforce - /// `ExistentialDeposit` law, annulling the account as needed. - /// - /// NOTE: Doesn't do any preparatory work for creating a new account, so should only be used - /// when it is known that the account already exists. - /// - /// NOTE: LOW-LEVEL: This will not attempt to maintain total issuance. It is expected that - /// the caller will do this. - pub fn mutate_account( - who: &T::AccountId, - f: impl FnOnce(&mut AccountData) -> R, - ) -> Result { - Self::try_mutate_account(who, |a, _| -> Result { Ok(f(a)) }) - } - - /// Mutate an account to some new value, or delete it entirely with `None`. Will enforce - /// `ExistentialDeposit` law, annulling the account as needed. This will do nothing if the - /// result of `f` is an `Err`. - /// - /// NOTE: Doesn't do any preparatory work for creating a new account, so should only be used - /// when it is known that the account already exists. - /// - /// NOTE: LOW-LEVEL: This will not attempt to maintain total issuance. It is expected that - /// the caller will do this. - fn try_mutate_account>( - who: &T::AccountId, - f: impl FnOnce(&mut AccountData, bool) -> Result, - ) -> Result { - Self::try_mutate_account_with_dust(who, f).map(|(result, dust_cleaner)| { - drop(dust_cleaner); - result - }) - } - - /// Mutate an account to some new value, or delete it entirely with `None`. Will enforce - /// `ExistentialDeposit` law, annulling the account as needed. This will do nothing if the - /// result of `f` is an `Err`. - /// - /// It returns both the result from the closure, and an optional `DustCleaner` instance which - /// should be dropped once it is known that all nested mutates that could affect storage items - /// what the dust handler touches have completed. - /// - /// NOTE: Doesn't do any preparatory work for creating a new account, so should only be used - /// when it is known that the account already exists. - /// - /// NOTE: LOW-LEVEL: This will not attempt to maintain total issuance. It is expected that - /// the caller will do this. - fn try_mutate_account_with_dust>( - who: &T::AccountId, - f: impl FnOnce(&mut AccountData, bool) -> Result, - ) -> Result<(R, DustCleaner), E> { - let result = T::AccountStore::try_mutate_exists(who, |maybe_account| { - let is_new = maybe_account.is_none(); - let mut account = maybe_account.take().unwrap_or_default(); - f(&mut account, is_new).map(move |result| { - let maybe_endowed = if is_new { Some(account.free) } else { None }; - let maybe_account_maybe_dust = Self::post_mutation(who, account); - *maybe_account = maybe_account_maybe_dust.0; - (maybe_endowed, maybe_account_maybe_dust.1, result) - }) - }); - result.map(|(maybe_endowed, maybe_dust, result)| { - if let Some(endowed) = maybe_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) - }) - } - - /// Update the account entry for `who`, given the locks. - fn update_locks(who: &T::AccountId, locks: &[BalanceLock]) { - let bounded_locks = WeakBoundedVec::<_, T::MaxLocks>::force_from( - locks.to_vec(), - Some("Balances Update Locks"), - ); - - if locks.len() as u32 > T::MaxLocks::get() { - log::warn!( - target: LOG_TARGET, - "Warning: A user has more currency locks than expected. \ - A runtime configuration adjustment may be needed." + /// Transfer the entire transferable balance from the caller account. + /// + /// NOTE: This function only attempts to transfer _transferable_ balances. This means that + /// any locked, reserved, or existential deposits (when `keep_alive` is `true`), will not be + /// transferred by this function. To ensure that this function results in a killed account, + /// you might need to prepare the account by removing any reference counters, storage + /// deposits, etc... + /// + /// The dispatch origin of this call must be Signed. + /// + /// - `dest`: The recipient of the transfer. + /// - `keep_alive`: A boolean to determine if the `transfer_all` operation should send all + /// of the funds the account has, causing the sender account to be killed (false), or + /// transfer everything except at least the existential deposit, which will guarantee to + /// keep the sender account alive (true). + #[pallet::call_index(4)] + #[pallet::weight(T::WeightInfo::transfer_all())] + pub fn transfer_all( + origin: OriginFor, + dest: AccountIdLookupOf, + keep_alive: bool, + ) -> DispatchResult { + let transactor = ensure_signed(origin)?; + let keep_alive = if keep_alive { Preserve } else { Expendable }; + let reducible_balance = >::reducible_balance( + &transactor, + keep_alive, + Fortitude::Polite, ); - } - // No way this can fail since we do not alter the existential balances. - let res = Self::mutate_account(who, |b| { - b.misc_frozen = Zero::zero(); - b.fee_frozen = Zero::zero(); - for l in locks.iter() { - if l.reasons == Reasons::All || l.reasons == Reasons::Misc { - b.misc_frozen = b.misc_frozen.max(l.amount); - } - if l.reasons == Reasons::All || l.reasons == Reasons::Fee { - b.fee_frozen = b.fee_frozen.max(l.amount); - } - } - }); - debug_assert!(res.is_ok()); - - let existed = Locks::::contains_key(who); - if locks.is_empty() { - Locks::::remove(who); - if existed { - // TODO: use Locks::::hashed_key - // https://github.com/paritytech/substrate/issues/4969 - system::Pallet::::dec_consumers(who); - } - } else { - Locks::::insert(who, bounded_locks); - if !existed && system::Pallet::::inc_consumers_without_limit(who).is_err() { - // No providers for the locks. This is impossible under normal circumstances - // since the funds that are under the lock will themselves be stored in the - // account and therefore will need a reference. - log::warn!( - target: LOG_TARGET, - "Warning: Attempt to introduce lock consumer reference, yet no providers. \ - This is unexpected but should be safe." - ); - } - } - } - - /// Move the reserved balance of one account into the balance of another, according to `status`. - /// - /// 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, - value: T::Balance, - best_effort: bool, - status: Status, - ) -> Result { - if value.is_zero() { - return Ok(Zero::zero()) - } - - if slashed == beneficiary { - return match status { - Status::Free => Ok(value.saturating_sub(Self::unreserve(slashed, value))), - Status::Reserved => Ok(value.saturating_sub(Self::reserved_balance(slashed))), - } - } - - let ((actual, _maybe_one_dust), _maybe_other_dust) = Self::try_mutate_account_with_dust( - beneficiary, - |to_account, is_new| -> Result<(T::Balance, DustCleaner), DispatchError> { - ensure!(!is_new, Error::::DeadAccount); - Self::try_mutate_account_with_dust( - slashed, - |from_account, _| -> Result { - let actual = cmp::min(from_account.reserved, value); - ensure!(best_effort || actual == value, Error::::InsufficientBalance); - match status { - Status::Free => - to_account.free = to_account - .free - .checked_add(&actual) - .ok_or(ArithmeticError::Overflow)?, - Status::Reserved => - to_account.reserved = to_account - .reserved - .checked_add(&actual) - .ok_or(ArithmeticError::Overflow)?, - } - from_account.reserved -= actual; - Ok(actual) - }, - ) - }, - )?; - - Self::deposit_event(Event::ReserveRepatriated { - from: slashed.clone(), - to: beneficiary.clone(), - amount: actual, - destination_status: status, - }); - Ok(actual) - } -} - -impl, I: 'static> fungible::Inspect for Pallet { - type Balance = T::Balance; - - 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() - } - fn balance(who: &T::AccountId) -> Self::Balance { - Self::account(who).total() - } - fn reducible_balance(who: &T::AccountId, keep_alive: bool) -> Self::Balance { - let a = Self::account(who); - // Liquid balance is what is neither reserved nor locked/frozen. - let liquid = a.free.saturating_sub(a.fee_frozen.max(a.misc_frozen)); - if frame_system::Pallet::::can_dec_provider(who) && !keep_alive { - liquid - } else { - // `must_remain_to_exist` is the part of liquid balance which must remain to keep total - // over ED. - let must_remain_to_exist = - T::ExistentialDeposit::get().saturating_sub(a.total() - liquid); - liquid.saturating_sub(must_remain_to_exist) - } - } - 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, - amount: Self::Balance, - ) -> WithdrawConsequence { - Self::withdraw_consequence(who, amount, &Self::account(who)) - } -} - -impl, I: 'static> fungible::Mutate for Pallet { - fn mint_into(who: &T::AccountId, amount: Self::Balance) -> DispatchResult { - if amount.is_zero() { - return Ok(()) - } - Self::try_mutate_account(who, |account, _is_new| -> DispatchResult { - Self::deposit_consequence(who, amount, account, true).into_result()?; - account.free += amount; + let dest = T::Lookup::lookup(dest)?; + >::transfer( + &transactor, + &dest, + reducible_balance, + keep_alive, + )?; Ok(()) - })?; - TotalIssuance::::mutate(|t| *t += amount); - Self::deposit_event(Event::Deposit { who: who.clone(), amount }); - Ok(()) - } - - fn burn_from( - who: &T::AccountId, - amount: Self::Balance, - ) -> Result { - if amount.is_zero() { - return Ok(Self::Balance::zero()) } - let actual = Self::try_mutate_account( - who, - |account, _is_new| -> Result { - let extra = Self::withdraw_consequence(who, amount, account).into_result()?; - let actual = amount + extra; - account.free -= actual; - Ok(actual) - }, - )?; - TotalIssuance::::mutate(|t| *t -= actual); - Self::deposit_event(Event::Withdraw { who: who.clone(), amount }); - Ok(actual) - } -} - -impl, I: 'static> fungible::Transfer for Pallet { - fn transfer( - source: &T::AccountId, - dest: &T::AccountId, - amount: T::Balance, - keep_alive: bool, - ) -> Result { - 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 { - fn set_balance(who: &T::AccountId, amount: Self::Balance) -> DispatchResult { - 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, - }); + /// 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, + who: AccountIdLookupOf, + amount: T::Balance, + ) -> DispatchResult { + ensure_root(origin)?; + let who = T::Lookup::lookup(who)?; + let _leftover = >::unreserve(&who, amount); Ok(()) - })? - } - - fn set_total_issuance(amount: Self::Balance) { - TotalIssuance::::mutate(|t| *t = amount); - } -} - -impl, I: 'static> fungible::InspectHold for Pallet { - fn balance_on_hold(who: &T::AccountId) -> T::Balance { - Self::account(who).reserved - } - fn can_hold(who: &T::AccountId, amount: T::Balance) -> bool { - let a = Self::account(who); - let min_balance = T::ExistentialDeposit::get().max(a.frozen(Reasons::All)); - if a.reserved.checked_add(&amount).is_none() { - return false - } - // We require it to be min_balance + amount to ensure that the full reserved funds may be - // slashed without compromising locked funds or destroying the account. - let required_free = match min_balance.checked_add(&amount) { - Some(x) => x, - None => return false, - }; - a.free >= required_free - } -} -impl, I: 'static> fungible::MutateHold for Pallet { - fn hold(who: &T::AccountId, amount: Self::Balance) -> DispatchResult { - if amount.is_zero() { - return Ok(()) - } - ensure!(Self::can_reserve(who, amount), Error::::InsufficientBalance); - Self::mutate_account(who, |a| { - a.free -= amount; - a.reserved += amount; - })?; - Ok(()) - } - fn release( - who: &T::AccountId, - amount: Self::Balance, - best_effort: bool, - ) -> Result { - if amount.is_zero() { - return Ok(amount) } - // Done on a best-effort basis. - Self::try_mutate_account(who, |a, _| { - let new_free = a.free.saturating_add(amount.min(a.reserved)); - let actual = new_free - a.free; - ensure!(best_effort || actual == amount, Error::::InsufficientBalance); - // ^^^ Guaranteed to be <= amount and <= a.reserved - a.free = new_free; - a.reserved = a.reserved.saturating_sub(actual); - Ok(actual) - }) - } - fn transfer_held( - source: &T::AccountId, - dest: &T::AccountId, - amount: Self::Balance, - best_effort: bool, - on_hold: bool, - ) -> Result { - let status = if on_hold { Status::Reserved } else { Status::Free }; - Self::do_transfer_reserved(source, dest, amount, best_effort, status) - } -} - -// wrapping these imbalances in a private module is necessary to ensure absolute privacy -// of the inner member. -mod imbalances { - use super::{result, Config, Imbalance, RuntimeDebug, Saturating, TryDrop, Zero}; - use frame_support::traits::SameOrOther; - use sp_std::mem; - - /// Opaque, move-only struct with private fields that serves as a token denoting that - /// funds have been created without any equal and opposite accounting. - #[must_use] - #[derive(RuntimeDebug, PartialEq, Eq)] - pub struct PositiveImbalance, I: 'static = ()>(T::Balance); - - impl, I: 'static> PositiveImbalance { - /// Create a new positive imbalance from a balance. - pub fn new(amount: T::Balance) -> Self { - PositiveImbalance(amount) - } - } - /// Opaque, move-only struct with private fields that serves as a token denoting that - /// funds have been destroyed without any equal and opposite accounting. - #[must_use] - #[derive(RuntimeDebug, PartialEq, Eq)] - pub struct NegativeImbalance, I: 'static = ()>(T::Balance); - - impl, I: 'static> NegativeImbalance { - /// Create a new negative imbalance from a balance. - pub fn new(amount: T::Balance) -> Self { - NegativeImbalance(amount) - } - } - - impl, I: 'static> TryDrop for PositiveImbalance { - fn try_drop(self) -> result::Result<(), Self> { - self.drop_zero() - } - } - - impl, I: 'static> Default for PositiveImbalance { - fn default() -> Self { - Self::zero() - } - } - - impl, I: 'static> Imbalance for PositiveImbalance { - type Opposite = NegativeImbalance; - - fn zero() -> Self { - Self(Zero::zero()) - } - fn drop_zero(self) -> result::Result<(), Self> { - if self.0.is_zero() { - Ok(()) - } else { - Err(self) + /// Upgrade a specified account. + /// + /// - `origin`: Must be `Signed`. + /// - `who`: The account to be upgraded. + /// + /// This will waive the transaction fee if at least all but 10% of the accounts needed to + /// be upgraded. (We let some not have to be upgraded just in order to allow for the + /// possibililty of churn). + #[pallet::call_index(6)] + #[pallet::weight(T::WeightInfo::upgrade_accounts(who.len() as u32))] + pub fn upgrade_accounts( + origin: OriginFor, + who: Vec, + ) -> DispatchResultWithPostInfo { + ensure_signed(origin)?; + if who.is_empty() { + return Ok(Pays::Yes.into()) } - } - fn split(self, amount: T::Balance) -> (Self, Self) { - let first = self.0.min(amount); - let second = self.0 - first; - - mem::forget(self); - (Self(first), Self(second)) - } - fn merge(mut self, other: Self) -> Self { - self.0 = self.0.saturating_add(other.0); - mem::forget(other); - - self - } - fn subsume(&mut self, other: Self) { - self.0 = self.0.saturating_add(other.0); - mem::forget(other); - } - fn offset(self, other: Self::Opposite) -> SameOrOther { - let (a, b) = (self.0, other.0); - mem::forget((self, other)); - - if a > b { - SameOrOther::Same(Self(a - b)) - } else if b > a { - SameOrOther::Other(NegativeImbalance::new(b - a)) + let mut upgrade_count = 0; + for i in &who { + let upgraded = Self::ensure_upgraded(i); + if upgraded { + upgrade_count.saturating_inc(); + } + } + let proportion_upgraded = Perbill::from_rational(upgrade_count, who.len() as u32); + if proportion_upgraded >= Perbill::from_percent(90) { + Ok(Pays::No.into()) } else { - SameOrOther::None + Ok(Pays::Yes.into()) } } - fn peek(&self) -> T::Balance { - self.0 - } - } - - impl, I: 'static> TryDrop for NegativeImbalance { - fn try_drop(self) -> result::Result<(), Self> { - self.drop_zero() - } - } - impl, I: 'static> Default for NegativeImbalance { - fn default() -> Self { - Self::zero() + /// Alias for `transfer_allow_death`, provided only for name-wise compatibility. + /// + /// WARNING: DEPRECATED! Will be released in approximately 3 months. + #[pallet::call_index(7)] + #[pallet::weight(T::WeightInfo::transfer_allow_death())] + pub fn transfer( + origin: OriginFor, + dest: AccountIdLookupOf, + #[pallet::compact] value: T::Balance, + ) -> DispatchResultWithPostInfo { + let source = ensure_signed(origin)?; + let dest = T::Lookup::lookup(dest)?; + >::transfer(&source, &dest, value, Expendable)?; + Ok(().into()) } - } - impl, I: 'static> Imbalance for NegativeImbalance { - type Opposite = PositiveImbalance; + /// Set the regular balance of a given account. + /// + /// The dispatch origin for this call is `root`. + #[pallet::call_index(8)] + #[pallet::weight( + T::WeightInfo::force_set_balance_creating() // Creates a new account. + .max(T::WeightInfo::force_set_balance_killing()) // Kills an existing account. + )] + pub fn force_set_balance( + origin: OriginFor, + who: AccountIdLookupOf, + #[pallet::compact] new_free: T::Balance, + ) -> DispatchResultWithPostInfo { + ensure_root(origin)?; + let who = T::Lookup::lookup(who)?; + let existential_deposit = T::ExistentialDeposit::get(); - fn zero() -> Self { - Self(Zero::zero()) - } - fn drop_zero(self) -> result::Result<(), Self> { - if self.0.is_zero() { - Ok(()) - } else { - Err(self) - } - } - fn split(self, amount: T::Balance) -> (Self, Self) { - let first = self.0.min(amount); - let second = self.0 - first; + let wipeout = new_free < existential_deposit; + let new_free = if wipeout { Zero::zero() } else { new_free }; - mem::forget(self); - (Self(first), Self(second)) - } - fn merge(mut self, other: Self) -> Self { - self.0 = self.0.saturating_add(other.0); - mem::forget(other); + // First we try to modify the account's balance to the forced balance. + let old_free = Self::mutate_account_handling_dust(&who, |account| { + let old_free = account.free; + account.free = new_free; + old_free + })?; - self - } - fn subsume(&mut self, other: Self) { - self.0 = self.0.saturating_add(other.0); - mem::forget(other); - } - fn offset(self, other: Self::Opposite) -> SameOrOther { - let (a, b) = (self.0, other.0); - mem::forget((self, other)); - - if a > b { - SameOrOther::Same(Self(a - b)) - } else if b > a { - SameOrOther::Other(PositiveImbalance::new(b - a)) - } else { - SameOrOther::None + // 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)); } - } - fn peek(&self) -> T::Balance { - self.0 - } - } - impl, I: 'static> Drop for PositiveImbalance { - /// Basic drop handler will just square up the total issuance. - fn drop(&mut self) { - >::mutate(|v| *v = v.saturating_add(self.0)); - } - } - - impl, I: 'static> Drop for NegativeImbalance { - /// Basic drop handler will just square up the total issuance. - fn drop(&mut self) { - >::mutate(|v| *v = v.saturating_sub(self.0)); + Self::deposit_event(Event::BalanceSet { who, free: new_free }); + Ok(().into()) } } -} - -impl, I: 'static> Currency for Pallet -where - T::Balance: MaybeSerializeDeserialize + Debug, -{ - type Balance = T::Balance; - type PositiveImbalance = PositiveImbalance; - type NegativeImbalance = NegativeImbalance; - - fn total_balance(who: &T::AccountId) -> Self::Balance { - Self::account(who).total() - } - // Check if `value` amount of free balance can be slashed from `who`. - fn can_slash(who: &T::AccountId, value: Self::Balance) -> bool { - if value.is_zero() { + impl, I: 'static> Pallet { + /// Ensure the account `who` is using the new logic. + /// + /// Returns `true` if the account did get upgraded, `false` if it didn't need upgrading. + pub fn ensure_upgraded(who: &T::AccountId) -> bool { + let mut a = T::AccountStore::get(who); + if a.flags.is_new_logic() { + return false + } + a.flags.set_new_logic(); + if !a.reserved.is_zero() || !a.frozen.is_zero() { + if !system::Pallet::::can_inc_consumer(who) { + // Gah!! We have a non-zero reserve balance but no provider refs :( + // This shouldn't practically happen, but we need a failsafe anyway: let's give + // them enough for an ED. + a.free = a.free.min(T::ExistentialDeposit::get()); + system::Pallet::::inc_providers(who); + } + let _ = system::Pallet::::inc_consumers(who).defensive(); + } + // Should never fail - we're only setting a bit. + let _ = T::AccountStore::try_mutate_exists(who, |account| -> DispatchResult { + *account = Some(a); + Ok(()) + }); + Self::deposit_event(Event::Upgraded { who: who.clone() }); return true } - Self::free_balance(who) >= value - } - - fn total_issuance() -> Self::Balance { - 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 { - T::ExistentialDeposit::get() - } - - // Burn funds from the total issuance, returning a positive imbalance for the amount burned. - // Is a no-op if amount to be burned is zero. - fn burn(mut amount: Self::Balance) -> Self::PositiveImbalance { - if amount.is_zero() { - return PositiveImbalance::zero() + /// Get the free balance of an account. + pub fn free_balance(who: impl sp_std::borrow::Borrow) -> T::Balance { + Self::account(who.borrow()).free } - >::mutate(|issued| { - *issued = issued.checked_sub(&amount).unwrap_or_else(|| { - amount = *issued; - Zero::zero() - }); - }); - PositiveImbalance::new(amount) - } - // Create new funds into the total issuance, returning a negative imbalance - // for the amount issued. - // Is a no-op if amount to be issued it zero. - fn issue(mut amount: Self::Balance) -> Self::NegativeImbalance { - if amount.is_zero() { - return NegativeImbalance::zero() + /// Get the balance of an account that can be used for transfers, reservations, or any other + /// non-locking, non-transaction-fee activity. Will be at most `free_balance`. + pub fn usable_balance(who: impl sp_std::borrow::Borrow) -> T::Balance { + >::reducible_balance(who.borrow(), Expendable, Polite) } - >::mutate(|issued| { - *issued = issued.checked_add(&amount).unwrap_or_else(|| { - amount = Self::Balance::max_value() - *issued; - Self::Balance::max_value() - }) - }); - NegativeImbalance::new(amount) - } - - fn free_balance(who: &T::AccountId) -> Self::Balance { - Self::account(who).free - } - // Ensure that an account can withdraw from their free balance given any existing withdrawal - // restrictions like locks and vesting balance. - // Is a no-op if amount to be withdrawn is zero. - // - // ## Complexity - // Despite iterating over a list of locks, they are limited by the number of - // lock IDs, which means the number of runtime pallets that intend to use and create locks. - fn ensure_can_withdraw( - who: &T::AccountId, - amount: T::Balance, - reasons: WithdrawReasons, - new_balance: T::Balance, - ) -> DispatchResult { - if amount.is_zero() { - return Ok(()) + /// Get the balance of an account that can be used for paying transaction fees (not tipping, + /// or any other kind of fees, though). Will be at most `free_balance`. + /// + /// This requires that the account stays alive. + pub fn usable_balance_for_fees( + who: impl sp_std::borrow::Borrow, + ) -> T::Balance { + >::reducible_balance(who.borrow(), Protect, Polite) } - let min_balance = Self::account(who).frozen(reasons.into()); - ensure!(new_balance >= min_balance, Error::::LiquidityRestrictions); - Ok(()) - } - // Transfer some free balance from `transactor` to `dest`, respecting existence requirements. - // Is a no-op if value to be transferred is zero or the `transactor` is the same as `dest`. - fn transfer( - transactor: &T::AccountId, - dest: &T::AccountId, - value: Self::Balance, - existence_requirement: ExistenceRequirement, - ) -> DispatchResult { - if value.is_zero() || transactor == dest { - return Ok(()) + /// Get the reserved balance of an account. + pub fn reserved_balance(who: impl sp_std::borrow::Borrow) -> T::Balance { + Self::account(who.borrow()).reserved } - Self::try_mutate_account_with_dust( - dest, - |to_account, _| -> Result, DispatchError> { - Self::try_mutate_account_with_dust( - transactor, - |from_account, _| -> DispatchResult { - from_account.free = from_account - .free - .checked_sub(&value) - .ok_or(Error::::InsufficientBalance)?; - - // NOTE: total stake being stored in the same type means that this could - // never overflow but better to be safe than sorry. - to_account.free = - to_account.free.checked_add(&value).ok_or(ArithmeticError::Overflow)?; - - let ed = T::ExistentialDeposit::get(); - ensure!(to_account.total() >= ed, Error::::ExistentialDeposit); - - Self::ensure_can_withdraw( - transactor, - value, - WithdrawReasons::TRANSFER, - from_account.free, - ) - .map_err(|_| Error::::LiquidityRestrictions)?; - - // TODO: This is over-conservative. There may now be other providers, and - // 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); - ensure!( - allow_death || from_account.total() >= ed, - Error::::KeepAlive - ); - - Ok(()) - }, - ) - .map(|(_, maybe_dust_cleaner)| maybe_dust_cleaner) - }, - )?; - - // Emit transfer event. - Self::deposit_event(Event::Transfer { - from: transactor.clone(), - to: dest.clone(), - amount: value, - }); - - Ok(()) - } - - /// Slash a target account `who`, returning the negative imbalance created and any left over - /// amount that could not be slashed. - /// - /// Is a no-op if `value` to be slashed is zero or the account does not exist. - /// - /// NOTE: `slash()` prefers free balance, but assumes that reserve balance can be drawn - /// from in extreme circumstances. `can_slash()` should be used prior to `slash()` to avoid - /// having to draw from reserved funds, however we err on the side of punishment if things are - /// inconsistent or `can_slash` wasn't used appropriately. - fn slash(who: &T::AccountId, value: Self::Balance) -> (Self::NegativeImbalance, Self::Balance) { - if value.is_zero() { - return (NegativeImbalance::zero(), Zero::zero()) - } - if Self::total_balance(who).is_zero() { - return (NegativeImbalance::zero(), value) + /// Get both the free and reserved balances of an account. + pub(crate) fn account(who: &T::AccountId) -> AccountData { + T::AccountStore::get(who) } - for attempt in 0..2 { - match Self::try_mutate_account( - who, - |account, - _is_new| - -> Result<(Self::NegativeImbalance, Self::Balance), DispatchError> { - // Best value is the most amount we can slash following liveness rules. - let best_value = match attempt { - // First attempt we try to slash the full amount, and see if liveness issues - // happen. - 0 => value, - // If acting as a critical provider (i.e. first attempt failed), then slash - // as much as possible while leaving at least at ED. - _ => value.min( - (account.free + account.reserved) - .saturating_sub(T::ExistentialDeposit::get()), - ), - }; - - let free_slash = cmp::min(account.free, best_value); - account.free -= free_slash; // Safe because of above check - let remaining_slash = best_value - free_slash; // Safe because of above check - - if !remaining_slash.is_zero() { - // If we have remaining slash, take it from reserved balance. - let reserved_slash = cmp::min(account.reserved, remaining_slash); - account.reserved -= reserved_slash; // Safe because of above check - Ok(( - NegativeImbalance::new(free_slash + reserved_slash), - value - free_slash - reserved_slash, /* Safe because value is gt or - * eq total slashed */ - )) - } else { - // Else we are done! - Ok(( - NegativeImbalance::new(free_slash), - value - free_slash, // Safe because value is gt or eq to total slashed - )) - } - }, - ) { - Ok((imbalance, not_slashed)) => { - Self::deposit_event(Event::Slashed { - who: who.clone(), - amount: value.saturating_sub(not_slashed), - }); - return (imbalance, not_slashed) - }, - Err(_) => (), + /// Mutate an account to some new value, or delete it entirely with `None`. Will enforce + /// `ExistentialDeposit` law, annulling the account as needed. + /// + /// It returns the result from the closure. Any dust is handled through the low-level + /// `fungible::Unbalanced` trap-door for legacy dust management. + /// + /// NOTE: Doesn't do any preparatory work for creating a new account, so should only be used + /// when it is known that the account already exists. + /// + /// NOTE: LOW-LEVEL: This will not attempt to maintain total issuance. It is expected that + /// the caller will do this. + pub(crate) fn mutate_account_handling_dust( + who: &T::AccountId, + f: impl FnOnce(&mut AccountData) -> R, + ) -> Result { + let (r, maybe_dust) = Self::mutate_account(who, f)?; + if let Some(dust) = maybe_dust { + >::handle_raw_dust(dust); } + Ok(r) } - // Should never get here. But we'll be defensive anyway. - (Self::NegativeImbalance::zero(), value) - } - - /// Deposit some `value` into the free balance of an existing target account `who`. - /// - /// Is a no-op if the `value` to be deposited is zero. - fn deposit_into_existing( - who: &T::AccountId, - value: Self::Balance, - ) -> Result { - if value.is_zero() { - return Ok(PositiveImbalance::zero()) - } - - Self::try_mutate_account( - who, - |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: who.clone(), amount: value }); - Ok(PositiveImbalance::new(value)) - }, - ) - } - - /// Deposit some `value` into the free balance of `who`, possibly creating a new account. - /// - /// This function is a no-op if: - /// - the `value` to be deposited is zero; or - /// - the `value` to be deposited is less than the required ED and the account does not yet - /// exist; or - /// - the deposit would necessitate the account to exist and there are no provider references; - /// or - /// - `value` is so large it would cause the balance of `who` to overflow. - fn deposit_creating(who: &T::AccountId, value: Self::Balance) -> Self::PositiveImbalance { - if value.is_zero() { - return Self::PositiveImbalance::zero() - } - - Self::try_mutate_account( - who, - |account, is_new| -> Result { - let ed = T::ExistentialDeposit::get(); - ensure!(value >= ed || !is_new, Error::::ExistentialDeposit); - - // defensive only: overflow should never happen, however in case it does, then this - // operation is a no-op. - account.free = match account.free.checked_add(&value) { - Some(x) => x, - None => return Ok(Self::PositiveImbalance::zero()), - }; - - Self::deposit_event(Event::Deposit { who: who.clone(), amount: value }); - Ok(PositiveImbalance::new(value)) - }, - ) - .unwrap_or_else(|_| Self::PositiveImbalance::zero()) - } - - /// Withdraw some free balance from an account, respecting existence requirements. - /// - /// Is a no-op if value to be withdrawn is zero. - fn withdraw( - who: &T::AccountId, - value: Self::Balance, - reasons: WithdrawReasons, - liveness: ExistenceRequirement, - ) -> result::Result { - if value.is_zero() { - return Ok(NegativeImbalance::zero()) + /// Mutate an account to some new value, or delete it entirely with `None`. Will enforce + /// `ExistentialDeposit` law, annulling the account as needed. + /// + /// It returns the result from the closure. Any dust is handled through the low-level + /// `fungible::Unbalanced` trap-door for legacy dust management. + /// + /// NOTE: Doesn't do any preparatory work for creating a new account, so should only be used + /// when it is known that the account already exists. + /// + /// NOTE: LOW-LEVEL: This will not attempt to maintain total issuance. It is expected that + /// the caller will do this. + pub(crate) fn try_mutate_account_handling_dust>( + who: &T::AccountId, + f: impl FnOnce(&mut AccountData, bool) -> Result, + ) -> Result { + let (r, maybe_dust) = Self::try_mutate_account(who, f)?; + if let Some(dust) = maybe_dust { + >::handle_raw_dust(dust); + } + Ok(r) } - Self::try_mutate_account( - who, - |account, _| -> Result { - let new_free_account = - account.free.checked_sub(&value).ok_or(Error::::InsufficientBalance)?; - - // bail if we need to keep the account alive and this would kill it. - let ed = T::ExistentialDeposit::get(); - let would_be_dead = new_free_account + account.reserved < ed; - let would_kill = would_be_dead && account.free + account.reserved >= ed; - ensure!(liveness == AllowDeath || !would_kill, Error::::KeepAlive); - - Self::ensure_can_withdraw(who, value, reasons, new_free_account)?; - - account.free = new_free_account; + /// Mutate an account to some new value, or delete it entirely with `None`. Will enforce + /// `ExistentialDeposit` law, annulling the account as needed. + /// + /// It returns both the result from the closure, and an optional amount of dust + /// which should be handled once it is known that all nested mutates that could affect + /// storage items what the dust handler touches have completed. + /// + /// NOTE: Doesn't do any preparatory work for creating a new account, so should only be used + /// when it is known that the account already exists. + /// + /// NOTE: LOW-LEVEL: This will not attempt to maintain total issuance. It is expected that + /// the caller will do this. + pub(crate) fn mutate_account( + who: &T::AccountId, + f: impl FnOnce(&mut AccountData) -> R, + ) -> Result<(R, Option), DispatchError> { + Self::try_mutate_account(who, |a, _| -> Result { Ok(f(a)) }) + } + + /// Mutate an account to some new value, or delete it entirely with `None`. Will enforce + /// `ExistentialDeposit` law, annulling the account as needed. This will do nothing if the + /// result of `f` is an `Err`. + /// + /// It returns both the result from the closure, and an optional amount of dust + /// which should be handled once it is known that all nested mutates that could affect + /// storage items what the dust handler touches have completed. + /// + /// NOTE: Doesn't do any preparatory work for creating a new account, so should only be used + /// when it is known that the account already exists. + /// + /// NOTE: LOW-LEVEL: This will not attempt to maintain total issuance. It is expected that + /// the caller will do this. + pub(crate) fn try_mutate_account>( + who: &T::AccountId, + f: impl FnOnce(&mut AccountData, bool) -> Result, + ) -> Result<(R, Option), E> { + Self::ensure_upgraded(who); + let result = T::AccountStore::try_mutate_exists(who, |maybe_account| { + let is_new = maybe_account.is_none(); + let mut account = maybe_account.take().unwrap_or_default(); + let did_provide = account.free >= T::ExistentialDeposit::get(); + let did_consume = + !is_new && (!account.reserved.is_zero() || !account.frozen.is_zero()); + + let result = f(&mut account, is_new)?; + + let does_provide = account.free >= T::ExistentialDeposit::get(); + let does_consume = !account.reserved.is_zero() || !account.frozen.is_zero(); + + if !did_provide && does_provide { + frame_system::Pallet::::inc_providers(who); + } + if did_consume && !does_consume { + frame_system::Pallet::::dec_consumers(who); + } + if !did_consume && does_consume { + frame_system::Pallet::::inc_consumers(who)?; + } + if did_provide && !does_provide { + // This could reap the account so must go last. + frame_system::Pallet::::dec_providers(who).map_err(|r| { + if did_consume && !does_consume { + // best-effort revert consumer change. + let _ = frame_system::Pallet::::inc_consumers(who).defensive(); + } + if !did_consume && does_consume { + let _ = frame_system::Pallet::::dec_consumers(who); + } + r + })?; + } - Self::deposit_event(Event::Withdraw { who: who.clone(), amount: value }); - Ok(NegativeImbalance::new(value)) - }, - ) - } + let maybe_endowed = if is_new { Some(account.free) } else { None }; - /// Force the new free balance of a target account `who` to some new value `balance`. - fn make_free_balance_be( - who: &T::AccountId, - value: Self::Balance, - ) -> SignedImbalance { - Self::try_mutate_account( - who, - |account, - is_new| - -> Result, DispatchError> { + // Handle any steps needed after mutating an account. + // + // This includes DustRemoval unbalancing, in the case than the `new` account's total + // balance is non-zero but below ED. + // + // Updates `maybe_account` to `Some` iff the account has sufficient balance. + // Evaluates `maybe_dust`, which is `Some` containing the dust to be dropped, iff + // some dust should be dropped. + // + // We should never be dropping if reserved is non-zero. Reserved being non-zero + // should imply that we have a consumer ref, so this is economically safe. let ed = T::ExistentialDeposit::get(); - let total = value.saturating_add(account.reserved); - // If we're attempting to set an existing account to less than ED, then - // bypass the entire operation. It's a no-op if you follow it through, but - // since this is an instance where we might account for a negative imbalance - // (in the dust cleaner of set_account) before we account for its actual - // equal and opposite cause (returned as an Imbalance), then in the - // instance that there's no other accounts on the system at all, we might - // underflow the issuance and our arithmetic will be off. - ensure!(total >= ed || !is_new, Error::::ExistentialDeposit); - - let imbalance = if account.free <= value { - SignedImbalance::Positive(PositiveImbalance::new(value - account.free)) + let maybe_dust = if account.free < ed && account.reserved.is_zero() { + if account.free.is_zero() { + None + } else { + Some(account.free) + } } else { - SignedImbalance::Negative(NegativeImbalance::new(account.free - value)) - }; - account.free = value; - Self::deposit_event(Event::BalanceSet { - who: who.clone(), - free: account.free, - reserved: account.reserved, - }); - Ok(imbalance) - }, - ) - .unwrap_or_else(|_| SignedImbalance::Positive(Self::PositiveImbalance::zero())) - } -} - -impl, I: 'static> ReservableCurrency for Pallet -where - T::Balance: MaybeSerializeDeserialize + Debug, -{ - /// Check if `who` can reserve `value` from their free balance. - /// - /// Always `true` if value to be reserved is zero. - fn can_reserve(who: &T::AccountId, value: Self::Balance) -> bool { - if value.is_zero() { - return true - } - Self::account(who).free.checked_sub(&value).map_or(false, |new_balance| { - Self::ensure_can_withdraw(who, value, WithdrawReasons::RESERVE, new_balance).is_ok() - }) - } - - fn reserved_balance(who: &T::AccountId) -> Self::Balance { - Self::account(who).reserved - } - - /// Move `value` from the free balance from `who` to their reserved balance. - /// - /// Is a no-op if value to be reserved is zero. - fn reserve(who: &T::AccountId, value: Self::Balance) -> DispatchResult { - if value.is_zero() { - return Ok(()) - } - - Self::try_mutate_account(who, |account, _| -> DispatchResult { - account.free = - 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, WithdrawReasons::RESERVE, account.free) - })?; - - Self::deposit_event(Event::Reserved { who: who.clone(), amount: value }); - Ok(()) - } - - /// 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() - } - if Self::total_balance(who).is_zero() { - return value - } - - let actual = match Self::mutate_account(who, |account| { - let actual = cmp::min(account.reserved, value); - 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.defensive_saturating_add(actual); - actual - }) { - Ok(x) => x, - Err(_) => { - // This should never happen since we don't alter the total amount in the account. - // If it ever does, then we should fail gracefully though, indicating that nothing - // could be done. - return value - }, - }; - - Self::deposit_event(Event::Unreserved { who: who.clone(), amount: actual }); - value - actual - } - - /// Slash from reserved balance, returning the negative imbalance created, - /// and any amount that was unable to be slashed. - /// - /// Is a no-op if the value to be slashed is zero or the account does not exist. - fn slash_reserved( - who: &T::AccountId, - value: Self::Balance, - ) -> (Self::NegativeImbalance, Self::Balance) { - if value.is_zero() { - return (NegativeImbalance::zero(), Zero::zero()) - } - if Self::total_balance(who).is_zero() { - return (NegativeImbalance::zero(), value) - } - - // NOTE: `mutate_account` may fail if it attempts to reduce the balance to the point that an - // account is attempted to be illegally destroyed. - - for attempt in 0..2 { - match Self::mutate_account(who, |account| { - let best_value = match attempt { - 0 => value, - // If acting as a critical provider (i.e. first attempt failed), then ensure - // slash leaves at least the ED. - _ => value.min( - (account.free + account.reserved) - .saturating_sub(T::ExistentialDeposit::get()), - ), + assert!( + account.free.is_zero() || account.free >= ed || !account.reserved.is_zero() + ); + *maybe_account = Some(account); + None }; - - let actual = cmp::min(account.reserved, best_value); - account.reserved -= actual; - - // underflow should never happen, but it if does, there's nothing to be done here. - (NegativeImbalance::new(actual), value - actual) - }) { - Ok((imbalance, not_slashed)) => { - Self::deposit_event(Event::Slashed { - who: who.clone(), - amount: value.saturating_sub(not_slashed), + Ok((maybe_endowed, maybe_dust, result)) + }); + result.map(|(maybe_endowed, maybe_dust, result)| { + if let Some(endowed) = maybe_endowed { + Self::deposit_event(Event::Endowed { + account: who.clone(), + free_balance: endowed, }); - return (imbalance, not_slashed) - }, - Err(_) => (), - } - } - // Should never get here as we ensure that ED is left in the second attempt. - // In case we do, though, then we fail gracefully. - (Self::NegativeImbalance::zero(), value) - } - - /// Move the reserved balance of one account into the balance of another, according to `status`. - /// - /// Is a no-op if: - /// - the value to be moved is zero; or - /// - the `slashed` id equal to `beneficiary` and the `status` is `Reserved`. - fn repatriate_reserved( - slashed: &T::AccountId, - beneficiary: &T::AccountId, - value: Self::Balance, - status: Status, - ) -> Result { - let actual = Self::do_transfer_reserved(slashed, beneficiary, value, true, status)?; - Ok(value.saturating_sub(actual)) - } -} - -impl, I: 'static> NamedReservableCurrency for Pallet -where - T::Balance: MaybeSerializeDeserialize + Debug, -{ - type ReserveIdentifier = T::ReserveIdentifier; - - fn reserved_balance_named(id: &Self::ReserveIdentifier, who: &T::AccountId) -> Self::Balance { - let reserves = Self::reserves(who); - reserves - .binary_search_by_key(id, |data| data.id) - .map(|index| reserves[index].amount) - .unwrap_or_default() - } - - /// Move `value` from the free balance from `who` to a named reserve balance. - /// - /// Is a no-op if value to be reserved is zero. - fn reserve_named( - id: &Self::ReserveIdentifier, - who: &T::AccountId, - value: Self::Balance, - ) -> DispatchResult { - if value.is_zero() { - return Ok(()) - } - - Reserves::::try_mutate(who, |reserves| -> DispatchResult { - 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.defensive_saturating_add(value); - }, - Err(index) => { - reserves - .try_insert(index, ReserveData { id: *id, amount: value }) - .map_err(|_| Error::::TooManyReserves)?; - }, - }; - >::reserve(who, value)?; - Ok(()) - }) - } - - /// Unreserve some funds, returning any amount that was unable to be unreserved. - /// - /// Is a no-op if the value to be unreserved is zero. - fn unreserve_named( - id: &Self::ReserveIdentifier, - who: &T::AccountId, - value: Self::Balance, - ) -> Self::Balance { - if value.is_zero() { - return Zero::zero() + } + if let Some(amount) = maybe_dust { + Pallet::::deposit_event(Event::DustLost { account: who.clone(), amount }); + } + (result, maybe_dust) + }) } - Reserves::::mutate_exists(who, |maybe_reserves| -> Self::Balance { - if let Some(reserves) = maybe_reserves.as_mut() { - match reserves.binary_search_by_key(id, |data| data.id) { - Ok(index) => { - let to_change = cmp::min(reserves[index].amount, value); - - let remain = >::unreserve(who, to_change); - - // 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; + /// Update the account entry for `who`, given the locks. + pub(crate) fn update_locks(who: &T::AccountId, locks: &[BalanceLock]) { + let bounded_locks = WeakBoundedVec::<_, T::MaxLocks>::force_from( + locks.to_vec(), + Some("Balances Update Locks"), + ); - if reserves[index].amount.is_zero() { - if reserves.len() == 1 { - // no more named reserves - *maybe_reserves = None; - } else { - // remove this named reserve - reserves.remove(index); - } - } + if locks.len() as u32 > T::MaxLocks::get() { + log::warn!( + target: LOG_TARGET, + "Warning: A user has more currency locks than expected. \ + A runtime configuration adjustment may be needed." + ); + } + let freezes = Freezes::::get(who); + // TODO: Revisit this assumption. We no manipulate consumer/provider refs. + // No way this can fail since we do not alter the existential balances. + let res = Self::mutate_account(who, |b| { + b.frozen = Zero::zero(); + for l in locks.iter() { + b.frozen = b.frozen.max(l.amount); + } + for l in freezes.iter() { + b.frozen = b.frozen.max(l.amount); + } + }); + debug_assert!(res.is_ok()); + if let Ok((_, maybe_dust)) = res { + debug_assert!(maybe_dust.is_none(), "Not altering main balance; qed"); + } - value - actual - }, - Err(_) => value, + let existed = Locks::::contains_key(who); + if locks.is_empty() { + Locks::::remove(who); + if existed { + // TODO: use Locks::::hashed_key + // https://github.com/paritytech/substrate/issues/4969 + system::Pallet::::dec_consumers(who); } } else { - value + Locks::::insert(who, bounded_locks); + if !existed && system::Pallet::::inc_consumers_without_limit(who).is_err() { + // No providers for the locks. This is impossible under normal circumstances + // since the funds that are under the lock will themselves be stored in the + // account and therefore will need a reference. + log::warn!( + target: LOG_TARGET, + "Warning: Attempt to introduce lock consumer reference, yet no providers. \ + This is unexpected but should be safe." + ); + } } - }) - } - - /// Slash from reserved balance, returning the negative imbalance created, - /// and any amount that was unable to be slashed. - /// - /// Is a no-op if the value to be slashed is zero. - fn slash_reserved_named( - id: &Self::ReserveIdentifier, - who: &T::AccountId, - value: Self::Balance, - ) -> (Self::NegativeImbalance, Self::Balance) { - if value.is_zero() { - return (NegativeImbalance::zero(), Zero::zero()) } - Reserves::::mutate(who, |reserves| -> (Self::NegativeImbalance, Self::Balance) { - match reserves.binary_search_by_key(id, |data| data.id) { - Ok(index) => { - let to_change = cmp::min(reserves[index].amount, value); - - let (imb, remain) = - >::slash_reserved(who, to_change); - - // 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; - - Self::deposit_event(Event::Slashed { who: who.clone(), amount: actual }); - (imb, value - actual) - }, - Err(_) => (NegativeImbalance::zero(), value), + /// Update the account entry for `who`, given the locks. + pub(crate) fn update_freezes( + who: &T::AccountId, + freezes: BoundedSlice, T::MaxFreezes>, + ) -> DispatchResult { + let (_, maybe_dust) = Self::mutate_account(who, |b| { + b.frozen = Zero::zero(); + for l in Locks::::get(who).iter() { + b.frozen = b.frozen.max(l.amount); + } + for l in freezes.iter() { + b.frozen = b.frozen.max(l.amount); + } + })?; + debug_assert!(maybe_dust.is_none(), "Not altering main balance; qed"); + if freezes.is_empty() { + Freezes::::remove(who); + } else { + Freezes::::insert(who, freezes); } - }) - } - - /// Move the reserved balance of one account into the balance of another, according to `status`. - /// If `status` is `Reserved`, the balance will be reserved with given `id`. - /// - /// Is a no-op if: - /// - the value to be moved is zero; or - /// - the `slashed` id equal to `beneficiary` and the `status` is `Reserved`. - fn repatriate_reserved_named( - id: &Self::ReserveIdentifier, - slashed: &T::AccountId, - beneficiary: &T::AccountId, - value: Self::Balance, - status: Status, - ) -> Result { - if value.is_zero() { - return Ok(Zero::zero()) + Ok(()) } - if slashed == beneficiary { - return match status { - Status::Free => Ok(Self::unreserve_named(id, slashed, value)), - Status::Reserved => - Ok(value.saturating_sub(Self::reserved_balance_named(id, slashed))), + /// Move the reserved balance of one account into the balance of another, according to + /// `status`. + /// + /// 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. + pub(crate) fn do_transfer_reserved( + slashed: &T::AccountId, + beneficiary: &T::AccountId, + value: T::Balance, + best_effort: bool, + status: Status, + ) -> Result { + if value.is_zero() { + return Ok(Zero::zero()) } - } - - Reserves::::try_mutate(slashed, |reserves| -> Result { - match reserves.binary_search_by_key(id, |data| data.id) { - Ok(index) => { - let to_change = cmp::min(reserves[index].amount, value); - - let actual = if status == Status::Reserved { - // make it the reserved under same identifier - Reserves::::try_mutate( - beneficiary, - |reserves| -> Result { - match reserves.binary_search_by_key(id, |data| data.id) { - Ok(index) => { - let remain = - >::repatriate_reserved( - slashed, - beneficiary, - to_change, - status, - )?; - - // remain should always be zero but just to be defensive - // 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.defensive_saturating_add(actual); - - Ok(actual) - }, - Err(index) => { - let remain = - >::repatriate_reserved( - slashed, - beneficiary, - to_change, - status, - )?; - - // remain should always be zero but just to be defensive - // here - let actual = to_change.defensive_saturating_sub(remain); - - reserves - .try_insert( - index, - ReserveData { id: *id, amount: actual }, - ) - .map_err(|_| Error::::TooManyReserves)?; - - Ok(actual) - }, - } - }, - )? - } else { - let remain = >::repatriate_reserved( - slashed, - beneficiary, - to_change, - status, - )?; - - // remain should always be zero but just to be defensive here - to_change.defensive_saturating_sub(remain) - }; - // `actual <= to_change` and `to_change <= amount`; qed; - reserves[index].amount -= actual; + if slashed == beneficiary { + return match status { + Status::Free => Ok(value.saturating_sub(Self::unreserve(slashed, value))), + Status::Reserved => Ok(value.saturating_sub(Self::reserved_balance(slashed))), + } + } - Ok(value - actual) + let ((actual, maybe_dust_1), maybe_dust_2) = Self::try_mutate_account( + beneficiary, + |to_account, is_new| -> Result<(T::Balance, Option), DispatchError> { + ensure!(!is_new, Error::::DeadAccount); + Self::try_mutate_account( + slashed, + |from_account, _| -> Result { + let actual = cmp::min(from_account.reserved, value); + ensure!( + best_effort || actual == value, + Error::::InsufficientBalance + ); + match status { + Status::Free => + to_account.free = to_account + .free + .checked_add(&actual) + .ok_or(ArithmeticError::Overflow)?, + Status::Reserved => + to_account.reserved = to_account + .reserved + .checked_add(&actual) + .ok_or(ArithmeticError::Overflow)?, + } + from_account.reserved -= actual; + Ok(actual) + }, + ) }, - Err(_) => Ok(value), - } - }) - } -} + )?; -impl, I: 'static> LockableCurrency for Pallet -where - T::Balance: MaybeSerializeDeserialize + Debug, -{ - type Moment = T::BlockNumber; - - type MaxLocks = T::MaxLocks; - - // 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, - who: &T::AccountId, - amount: T::Balance, - reasons: WithdrawReasons, - ) { - if amount.is_zero() || reasons.is_empty() { - return - } - let mut new_lock = Some(BalanceLock { id, amount, reasons: reasons.into() }); - let mut locks = Self::locks(who) - .into_iter() - .filter_map(|l| if l.id == id { new_lock.take() } else { Some(l) }) - .collect::>(); - if let Some(lock) = new_lock { - locks.push(lock) - } - Self::update_locks(who, &locks[..]); - } + if let Some(dust) = maybe_dust_1 { + >::handle_raw_dust(dust); + } + if let Some(dust) = maybe_dust_2 { + >::handle_raw_dust(dust); + } - // 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, - who: &T::AccountId, - amount: T::Balance, - reasons: WithdrawReasons, - ) { - if amount.is_zero() || reasons.is_empty() { - return - } - let mut new_lock = Some(BalanceLock { id, amount, reasons: reasons.into() }); - let mut locks = Self::locks(who) - .into_iter() - .filter_map(|l| { - if l.id == id { - new_lock.take().map(|nl| BalanceLock { - id: l.id, - amount: l.amount.max(nl.amount), - reasons: l.reasons | nl.reasons, - }) - } else { - Some(l) - } - }) - .collect::>(); - if let Some(lock) = new_lock { - locks.push(lock) + Self::deposit_event(Event::ReserveRepatriated { + from: slashed.clone(), + to: beneficiary.clone(), + amount: actual, + destination_status: status, + }); + Ok(actual) } - Self::update_locks(who, &locks[..]); - } - - 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 deleted file mode 100644 index b4233a6c3a85c..0000000000000 --- a/frame/balances/src/tests.rs +++ /dev/null @@ -1,1460 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Macro for creating the tests for the module. - -#![cfg(test)] - -#[macro_export] -macro_rules! decl_tests { - ($test:ty, $ext_builder:ty, $existential_deposit:expr) => { - - use crate::*; - use sp_runtime::{ArithmeticError, TokenError, FixedPointNumber, traits::{SignedExtension, BadOrigin}}; - use frame_support::{ - assert_noop, assert_storage_noop, assert_ok, assert_err, - traits::{ - LockableCurrency, LockIdentifier, 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 "; - - 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 { - let evt = System::events().into_iter().map(|evt| evt.event).collect::>(); - - System::reset_events(); - - evt - } - - #[test] - fn basic_locking_should_work() { - <$ext_builder>::default().existential_deposit(1).monied(true).build().execute_with(|| { - assert_eq!(Balances::free_balance(1), 10); - Balances::set_lock(ID_1, &1, 9, WithdrawReasons::all()); - assert_noop!( - >::transfer(&1, &2, 5, AllowDeath), - Error::<$test, _>::LiquidityRestrictions - ); - }); - } - - #[test] - fn account_should_be_reaped() { - <$ext_builder>::default().existential_deposit(1).monied(true).build().execute_with(|| { - assert_eq!(Balances::free_balance(1), 10); - assert_ok!(>::transfer(&1, &2, 10, AllowDeath)); - // Check that the account is dead. - assert!(!frame_system::Account::::contains_key(&1)); - }); - } - - #[test] - fn reap_failed_due_to_provider_and_consumer() { - <$ext_builder>::default().existential_deposit(1).monied(true).build().execute_with(|| { - // SCENARIO: only one provider and there are remaining consumers. - assert_ok!(System::inc_consumers(&1)); - assert!(!System::can_dec_provider(&1)); - assert_noop!( - >::transfer(&1, &2, 10, AllowDeath), - Error::<$test, _>::KeepAlive - ); - assert!(System::account_exists(&1)); - assert_eq!(Balances::free_balance(1), 10); - - // SCENARIO: more than one provider, but will not kill account due to other provider. - assert_eq!(System::inc_providers(&1), frame_system::IncRefStatus::Existed); - assert_eq!(System::providers(&1), 2); - assert!(System::can_dec_provider(&1)); - assert_ok!(>::transfer(&1, &2, 10, AllowDeath)); - assert_eq!(System::providers(&1), 1); - assert!(System::account_exists(&1)); - assert_eq!(Balances::free_balance(1), 0); - }); - } - - #[test] - fn partial_locking_should_work() { - <$ext_builder>::default().existential_deposit(1).monied(true).build().execute_with(|| { - Balances::set_lock(ID_1, &1, 5, WithdrawReasons::all()); - assert_ok!(>::transfer(&1, &2, 1, AllowDeath)); - }); - } - - #[test] - fn lock_removal_should_work() { - <$ext_builder>::default().existential_deposit(1).monied(true).build().execute_with(|| { - Balances::set_lock(ID_1, &1, u64::MAX, WithdrawReasons::all()); - Balances::remove_lock(ID_1, &1); - assert_ok!(>::transfer(&1, &2, 1, AllowDeath)); - }); - } - - #[test] - fn lock_replacement_should_work() { - <$ext_builder>::default().existential_deposit(1).monied(true).build().execute_with(|| { - Balances::set_lock(ID_1, &1, u64::MAX, WithdrawReasons::all()); - Balances::set_lock(ID_1, &1, 5, WithdrawReasons::all()); - assert_ok!(>::transfer(&1, &2, 1, AllowDeath)); - }); - } - - #[test] - fn double_locking_should_work() { - <$ext_builder>::default().existential_deposit(1).monied(true).build().execute_with(|| { - Balances::set_lock(ID_1, &1, 5, WithdrawReasons::all()); - Balances::set_lock(ID_2, &1, 5, WithdrawReasons::all()); - assert_ok!(>::transfer(&1, &2, 1, AllowDeath)); - }); - } - - #[test] - fn combination_locking_should_work() { - <$ext_builder>::default().existential_deposit(1).monied(true).build().execute_with(|| { - Balances::set_lock(ID_1, &1, u64::MAX, WithdrawReasons::empty()); - Balances::set_lock(ID_2, &1, 0, WithdrawReasons::all()); - assert_ok!(>::transfer(&1, &2, 1, AllowDeath)); - }); - } - - #[test] - fn lock_value_extension_should_work() { - <$ext_builder>::default().existential_deposit(1).monied(true).build().execute_with(|| { - Balances::set_lock(ID_1, &1, 5, WithdrawReasons::all()); - assert_noop!( - >::transfer(&1, &2, 6, AllowDeath), - Error::<$test, _>::LiquidityRestrictions - ); - Balances::extend_lock(ID_1, &1, 2, WithdrawReasons::all()); - assert_noop!( - >::transfer(&1, &2, 6, AllowDeath), - Error::<$test, _>::LiquidityRestrictions - ); - Balances::extend_lock(ID_1, &1, 8, WithdrawReasons::all()); - assert_noop!( - >::transfer(&1, &2, 3, AllowDeath), - Error::<$test, _>::LiquidityRestrictions - ); - }); - } - - #[test] - fn lock_reasons_should_work() { - <$ext_builder>::default() - .existential_deposit(1) - .monied(true) - .build() - .execute_with(|| { - pallet_transaction_payment::NextFeeMultiplier::<$test>::put( - Multiplier::saturating_from_integer(1) - ); - Balances::set_lock(ID_1, &1, 10, WithdrawReasons::RESERVE); - assert_noop!( - >::transfer(&1, &2, 1, AllowDeath), - Error::<$test, _>::LiquidityRestrictions - ); - assert_noop!( - >::reserve(&1, 1), - Error::<$test, _>::LiquidityRestrictions, - ); - assert!( as SignedExtension>::pre_dispatch( - ChargeTransactionPayment::from(1), - &1, - CALL, - &info_from_weight(Weight::from_parts(1, 0)), - 1, - ).is_err()); - assert_ok!( as SignedExtension>::pre_dispatch( - ChargeTransactionPayment::from(0), - &1, - CALL, - &info_from_weight(Weight::from_parts(1, 0)), - 1, - )); - - Balances::set_lock(ID_1, &1, 10, WithdrawReasons::TRANSACTION_PAYMENT); - assert_ok!(>::transfer(&1, &2, 1, AllowDeath)); - assert_ok!(>::reserve(&1, 1)); - assert!( as SignedExtension>::pre_dispatch( - ChargeTransactionPayment::from(1), - &1, - CALL, - &info_from_weight(Weight::from_parts(1, 0)), - 1, - ).is_err()); - assert!( as SignedExtension>::pre_dispatch( - ChargeTransactionPayment::from(0), - &1, - CALL, - &info_from_weight(Weight::from_parts(1, 0)), - 1, - ).is_err()); - }); - } - - #[test] - fn lock_block_number_extension_should_work() { - <$ext_builder>::default().existential_deposit(1).monied(true).build().execute_with(|| { - Balances::set_lock(ID_1, &1, 10, WithdrawReasons::all()); - assert_noop!( - >::transfer(&1, &2, 6, AllowDeath), - Error::<$test, _>::LiquidityRestrictions - ); - Balances::extend_lock(ID_1, &1, 10, WithdrawReasons::all()); - assert_noop!( - >::transfer(&1, &2, 6, AllowDeath), - Error::<$test, _>::LiquidityRestrictions - ); - System::set_block_number(2); - Balances::extend_lock(ID_1, &1, 10, WithdrawReasons::all()); - assert_noop!( - >::transfer(&1, &2, 3, AllowDeath), - Error::<$test, _>::LiquidityRestrictions - ); - }); - } - - #[test] - fn lock_reasons_extension_should_work() { - <$ext_builder>::default().existential_deposit(1).monied(true).build().execute_with(|| { - Balances::set_lock(ID_1, &1, 10, WithdrawReasons::TRANSFER); - assert_noop!( - >::transfer(&1, &2, 6, AllowDeath), - Error::<$test, _>::LiquidityRestrictions - ); - Balances::extend_lock(ID_1, &1, 10, WithdrawReasons::empty()); - assert_noop!( - >::transfer(&1, &2, 6, AllowDeath), - Error::<$test, _>::LiquidityRestrictions - ); - Balances::extend_lock(ID_1, &1, 10, WithdrawReasons::RESERVE); - assert_noop!( - >::transfer(&1, &2, 6, AllowDeath), - Error::<$test, _>::LiquidityRestrictions - ); - }); - } - - #[test] - fn default_indexing_on_new_accounts_should_not_work2() { - <$ext_builder>::default() - .existential_deposit(10) - .monied(true) - .build() - .execute_with(|| { - // account 5 should not exist - // ext_deposit is 10, value is 9, not satisfies for ext_deposit - assert_noop!( - Balances::transfer(Some(1).into(), 5, 9), - Error::<$test, _>::ExistentialDeposit, - ); - assert_eq!(Balances::free_balance(1), 100); - }); - } - - #[test] - fn reserved_balance_should_prevent_reclaim_count() { - <$ext_builder>::default() - .existential_deposit(256 * 1) - .monied(true) - .build() - .execute_with(|| { - System::inc_account_nonce(&2); - assert_eq!(Balances::total_balance(&2), 256 * 20); - - assert_ok!(Balances::reserve(&2, 256 * 19 + 1)); // account 2 becomes mostly reserved - assert_eq!(Balances::free_balance(2), 255); // "free" account deleted." - assert_eq!(Balances::total_balance(&2), 256 * 20); // reserve still exists. - assert_eq!(System::account_nonce(&2), 1); - - // account 4 tries to take index 1 for account 5. - assert_ok!(Balances::transfer(Some(4).into(), 5, 256 * 1 + 0x69)); - assert_eq!(Balances::total_balance(&5), 256 * 1 + 0x69); - - assert!(Balances::slash(&2, 256 * 19 + 2).1.is_zero()); // account 2 gets slashed - // "reserve" account reduced to 255 (below ED) so account deleted - assert_eq!(Balances::total_balance(&2), 0); - assert_eq!(System::account_nonce(&2), 0); // nonce zero - - // account 4 tries to take index 1 again for account 6. - assert_ok!(Balances::transfer(Some(4).into(), 6, 256 * 1 + 0x69)); - assert_eq!(Balances::total_balance(&6), 256 * 1 + 0x69); - }); - } - - #[test] - fn reward_should_work() { - <$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(RuntimeEvent::Balances(crate::Event::Deposit { who: 1, amount: 10 })); - assert_eq!(Balances::total_balance(&1), 20); - assert_eq!(>::get(), 120); - }); - } - - #[test] - fn dust_account_removal_should_work() { - <$ext_builder>::default() - .existential_deposit(100) - .monied(true) - .build() - .execute_with(|| { - System::inc_account_nonce(&2); - assert_eq!(System::account_nonce(&2), 1); - assert_eq!(Balances::total_balance(&2), 2000); - // index 1 (account 2) becomes zombie - assert_ok!(Balances::transfer(Some(2).into(), 5, 1901)); - assert_eq!(Balances::total_balance(&2), 0); - assert_eq!(Balances::total_balance(&5), 1901); - assert_eq!(System::account_nonce(&2), 0); - }); - } - - #[test] - fn balance_works() { - <$ext_builder>::default().build().execute_with(|| { - let _ = Balances::deposit_creating(&1, 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); - assert_eq!(Balances::free_balance(2), 0); - assert_eq!(Balances::reserved_balance(2), 0); - assert_eq!(Balances::total_balance(&2), 0); - }); - } - - #[test] - fn balance_transfer_works() { - <$ext_builder>::default().build().execute_with(|| { - let _ = Balances::deposit_creating(&1, 111); - assert_ok!(Balances::transfer(Some(1).into(), 2, 69)); - assert_eq!(Balances::total_balance(&1), 42); - assert_eq!(Balances::total_balance(&2), 69); - }); - } - - #[test] - fn force_transfer_works() { - <$ext_builder>::default().build().execute_with(|| { - let _ = Balances::deposit_creating(&1, 111); - assert_noop!( - Balances::force_transfer(Some(2).into(), 1, 2, 69), - BadOrigin, - ); - assert_ok!(Balances::force_transfer(RawOrigin::Root.into(), 1, 2, 69)); - assert_eq!(Balances::total_balance(&1), 42); - assert_eq!(Balances::total_balance(&2), 69); - }); - } - - #[test] - fn reserving_balance_should_work() { - <$ext_builder>::default().build().execute_with(|| { - let _ = Balances::deposit_creating(&1, 111); - - assert_eq!(Balances::total_balance(&1), 111); - assert_eq!(Balances::free_balance(1), 111); - assert_eq!(Balances::reserved_balance(1), 0); - - assert_ok!(Balances::reserve(&1, 69)); - - assert_eq!(Balances::total_balance(&1), 111); - assert_eq!(Balances::free_balance(1), 42); - assert_eq!(Balances::reserved_balance(1), 69); - }); - } - - #[test] - fn balance_transfer_when_reserved_should_not_work() { - <$ext_builder>::default().build().execute_with(|| { - let _ = Balances::deposit_creating(&1, 111); - assert_ok!(Balances::reserve(&1, 69)); - assert_noop!( - Balances::transfer(Some(1).into(), 2, 69), - Error::<$test, _>::InsufficientBalance, - ); - }); - } - - #[test] - fn deducting_balance_should_work() { - <$ext_builder>::default().build().execute_with(|| { - let _ = Balances::deposit_creating(&1, 111); - assert_ok!(Balances::reserve(&1, 69)); - assert_eq!(Balances::free_balance(1), 42); - }); - } - - #[test] - fn refunding_balance_should_work() { - <$ext_builder>::default().build().execute_with(|| { - let _ = Balances::deposit_creating(&1, 42); - assert_ok!(Balances::mutate_account(&1, |a| a.reserved = 69)); - Balances::unreserve(&1, 69); - assert_eq!(Balances::free_balance(1), 111); - assert_eq!(Balances::reserved_balance(1), 0); - }); - } - - #[test] - fn slashing_balance_should_work() { - <$ext_builder>::default().build().execute_with(|| { - let _ = Balances::deposit_creating(&1, 111); - assert_ok!(Balances::reserve(&1, 69)); - assert!(Balances::slash(&1, 69).1.is_zero()); - assert_eq!(Balances::free_balance(1), 0); - assert_eq!(Balances::reserved_balance(1), 42); - assert_eq!(>::get(), 42); - }); - } - - #[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(RuntimeEvent::Balances(crate::Event::Withdraw { who: 2, amount: 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(|| { - let _ = Balances::deposit_creating(&1, 42); - assert_ok!(Balances::reserve(&1, 21)); - assert_eq!(Balances::slash(&1, 69).1, 27); - assert_eq!(Balances::free_balance(1), 0); - assert_eq!(Balances::reserved_balance(1), 0); - assert_eq!(>::get(), 0); - }); - } - - #[test] - fn unreserving_balance_should_work() { - <$ext_builder>::default().build().execute_with(|| { - let _ = Balances::deposit_creating(&1, 111); - assert_ok!(Balances::reserve(&1, 111)); - Balances::unreserve(&1, 42); - assert_eq!(Balances::reserved_balance(1), 69); - assert_eq!(Balances::free_balance(1), 42); - }); - } - - #[test] - fn slashing_reserved_balance_should_work() { - <$ext_builder>::default().build().execute_with(|| { - let _ = Balances::deposit_creating(&1, 111); - assert_ok!(Balances::reserve(&1, 111)); - assert_eq!(Balances::slash_reserved(&1, 42).1, 0); - assert_eq!(Balances::reserved_balance(1), 69); - assert_eq!(Balances::free_balance(1), 0); - assert_eq!(>::get(), 69); - }); - } - - #[test] - fn slashing_incomplete_reserved_balance_should_work() { - <$ext_builder>::default().build().execute_with(|| { - let _ = Balances::deposit_creating(&1, 111); - assert_ok!(Balances::reserve(&1, 42)); - assert_eq!(Balances::slash_reserved(&1, 69).1, 27); - assert_eq!(Balances::free_balance(1), 69); - assert_eq!(Balances::reserved_balance(1), 0); - assert_eq!(>::get(), 69); - }); - } - - #[test] - fn repatriating_reserved_balance_should_work() { - <$ext_builder>::default().build().execute_with(|| { - let _ = Balances::deposit_creating(&1, 110); - let _ = Balances::deposit_creating(&2, 1); - assert_ok!(Balances::reserve(&1, 110)); - assert_ok!(Balances::repatriate_reserved(&1, &2, 41, Status::Free), 0); - System::assert_last_event( - 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); - assert_eq!(Balances::reserved_balance(2), 0); - assert_eq!(Balances::free_balance(2), 42); - }); - } - - #[test] - fn transferring_reserved_balance_should_work() { - <$ext_builder>::default().build().execute_with(|| { - let _ = Balances::deposit_creating(&1, 110); - let _ = Balances::deposit_creating(&2, 1); - assert_ok!(Balances::reserve(&1, 110)); - assert_ok!(Balances::repatriate_reserved(&1, &2, 41, Status::Reserved), 0); - assert_eq!(Balances::reserved_balance(1), 69); - assert_eq!(Balances::free_balance(1), 0); - assert_eq!(Balances::reserved_balance(2), 41); - assert_eq!(Balances::free_balance(2), 1); - }); - } - - #[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(|| { - let _ = Balances::deposit_creating(&1, 111); - assert_ok!(Balances::reserve(&1, 111)); - assert_noop!(Balances::repatriate_reserved(&1, &2, 42, Status::Free), Error::<$test, _>::DeadAccount); - }); - } - - #[test] - fn transferring_incomplete_reserved_balance_should_work() { - <$ext_builder>::default().build().execute_with(|| { - let _ = Balances::deposit_creating(&1, 110); - let _ = Balances::deposit_creating(&2, 1); - assert_ok!(Balances::reserve(&1, 41)); - assert_ok!(Balances::repatriate_reserved(&1, &2, 69, Status::Free), 28); - assert_eq!(Balances::reserved_balance(1), 0); - assert_eq!(Balances::free_balance(1), 69); - assert_eq!(Balances::reserved_balance(2), 0); - assert_eq!(Balances::free_balance(2), 42); - }); - } - - #[test] - fn transferring_too_high_value_should_not_panic() { - <$ext_builder>::default().build().execute_with(|| { - Balances::make_free_balance_be(&1, u64::MAX); - Balances::make_free_balance_be(&2, 1); - - assert_err!( - Balances::transfer(Some(1).into(), 2, u64::MAX), - ArithmeticError::Overflow, - ); - - assert_eq!(Balances::free_balance(1), u64::MAX); - assert_eq!(Balances::free_balance(2), 1); - }); - } - - #[test] - fn account_create_on_free_too_low_with_other() { - <$ext_builder>::default().existential_deposit(100).build().execute_with(|| { - let _ = Balances::deposit_creating(&1, 100); - assert_eq!(>::get(), 100); - - // No-op. - let _ = Balances::deposit_creating(&2, 50); - assert_eq!(Balances::free_balance(2), 0); - assert_eq!(>::get(), 100); - }) - } - - #[test] - fn account_create_on_free_too_low() { - <$ext_builder>::default().existential_deposit(100).build().execute_with(|| { - // No-op. - let _ = Balances::deposit_creating(&2, 50); - assert_eq!(Balances::free_balance(2), 0); - assert_eq!(>::get(), 0); - }) - } - - #[test] - fn account_removal_on_free_too_low() { - <$ext_builder>::default().existential_deposit(100).build().execute_with(|| { - assert_eq!(>::get(), 0); - - // Setup two accounts with free balance above the existential threshold. - let _ = Balances::deposit_creating(&1, 110); - let _ = Balances::deposit_creating(&2, 110); - - assert_eq!(Balances::free_balance(1), 110); - assert_eq!(Balances::free_balance(2), 110); - assert_eq!(>::get(), 220); - - // Transfer funds from account 1 of such amount that after this transfer - // the balance of account 1 will be below the existential threshold. - // This should lead to the removal of all balance of this account. - assert_ok!(Balances::transfer(Some(1).into(), 2, 20)); - - // Verify free balance removal of account 1. - assert_eq!(Balances::free_balance(1), 0); - assert_eq!(Balances::free_balance(2), 130); - - // Verify that TotalIssuance tracks balance removal when free balance is too low. - assert_eq!(>::get(), 130); - }); - } - - #[test] - fn burn_must_work() { - <$ext_builder>::default().monied(true).build().execute_with(|| { - let init_total_issuance = Balances::total_issuance(); - let imbalance = Balances::burn(10); - assert_eq!(Balances::total_issuance(), init_total_issuance - 10); - drop(imbalance); - assert_eq!(Balances::total_issuance(), init_total_issuance); - }); - } - - #[test] - fn transfer_keep_alive_works() { - <$ext_builder>::default().existential_deposit(1).build().execute_with(|| { - let _ = Balances::deposit_creating(&1, 100); - assert_noop!( - Balances::transfer_keep_alive(Some(1).into(), 2, 100), - Error::<$test, _>::KeepAlive - ); - assert_eq!(Balances::total_balance(&1), 100); - assert_eq!(Balances::total_balance(&2), 0); - }); - } - - #[test] - #[should_panic = "the balance of any account should always be at least the existential deposit."] - fn cannot_set_genesis_value_below_ed() { - ($existential_deposit).with(|v| *v.borrow_mut() = 11); - let mut t = frame_system::GenesisConfig::default().build_storage::<$test>().unwrap(); - let _ = pallet_balances::GenesisConfig::<$test> { - balances: vec![(1, 10)], - }.assimilate_storage(&mut t).unwrap(); - } - - #[test] - #[should_panic = "duplicate balances in genesis."] - fn cannot_set_genesis_value_twice() { - let mut t = frame_system::GenesisConfig::default().build_storage::<$test>().unwrap(); - let _ = pallet_balances::GenesisConfig::<$test> { - balances: vec![(1, 10), (2, 20), (1, 15)], - }.assimilate_storage(&mut t).unwrap(); - } - - #[test] - fn dust_moves_between_free_and_reserved() { - <$ext_builder>::default() - .existential_deposit(100) - .build() - .execute_with(|| { - // Set balance to free and reserved at the existential deposit - assert_ok!(Balances::set_balance(RawOrigin::Root.into(), 1, 100, 0)); - // Check balance - assert_eq!(Balances::free_balance(1), 100); - assert_eq!(Balances::reserved_balance(1), 0); - - // Reserve some free balance - assert_ok!(Balances::reserve(&1, 50)); - // Check balance, the account should be ok. - assert_eq!(Balances::free_balance(1), 50); - assert_eq!(Balances::reserved_balance(1), 50); - - // Reserve the rest of the free balance - assert_ok!(Balances::reserve(&1, 50)); - // Check balance, the account should be ok. - assert_eq!(Balances::free_balance(1), 0); - assert_eq!(Balances::reserved_balance(1), 100); - - // Unreserve everything - Balances::unreserve(&1, 100); - // Check balance, all 100 should move to free_balance - assert_eq!(Balances::free_balance(1), 100); - assert_eq!(Balances::reserved_balance(1), 0); - }); - } - - #[test] - fn account_deleted_when_just_dust() { - <$ext_builder>::default() - .existential_deposit(100) - .build() - .execute_with(|| { - // Set balance to free and reserved at the existential deposit - assert_ok!(Balances::set_balance(RawOrigin::Root.into(), 1, 50, 50)); - // Check balance - assert_eq!(Balances::free_balance(1), 50); - assert_eq!(Balances::reserved_balance(1), 50); - - // Reserve some free balance - let res = Balances::slash(&1, 1); - assert_eq!(res, (NegativeImbalance::new(1), 0)); - - // The account should be dead. - assert_eq!(Balances::free_balance(1), 0); - assert_eq!(Balances::reserved_balance(1), 0); - }); - } - - #[test] - fn emit_events_with_reserve_and_unreserve() { - <$ext_builder>::default() - .build() - .execute_with(|| { - let _ = Balances::deposit_creating(&1, 100); - - System::set_block_number(2); - assert_ok!(Balances::reserve(&1, 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(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(RuntimeEvent::Balances(crate::Event::Unreserved { who: 1, amount: 5 })); - }); - } - - #[test] - fn emit_events_with_existential_deposit() { - <$ext_builder>::default() - .existential_deposit(100) - .build() - .execute_with(|| { - assert_ok!(Balances::set_balance(RawOrigin::Root.into(), 1, 100, 0)); - - assert_eq!( - events(), - [ - 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 }), - ] - ); - - let res = Balances::slash(&1, 1); - assert_eq!(res, (NegativeImbalance::new(1), 0)); - - assert_eq!( - events(), - [ - 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 }), - ] - ); - }); - } - - #[test] - fn emit_events_with_no_existential_deposit_suicide() { - <$ext_builder>::default() - .existential_deposit(1) - .build() - .execute_with(|| { - assert_ok!(Balances::set_balance(RawOrigin::Root.into(), 1, 100, 0)); - - assert_eq!( - events(), - [ - 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 }), - ] - ); - - let res = Balances::slash(&1, 100); - assert_eq!(res, (NegativeImbalance::new(100), 0)); - - assert_eq!( - events(), - [ - RuntimeEvent::System(system::Event::KilledAccount { account: 1 }), - RuntimeEvent::Balances(crate::Event::Slashed { who: 1, amount: 100 }), - ] - ); - }); - } - - #[test] - fn slash_loop_works() { - <$ext_builder>::default() - .existential_deposit(100) - .build() - .execute_with(|| { - /* User has no reference counter, so they can die in these scenarios */ - - // SCENARIO: Slash would not kill account. - 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 - assert!(System::account_exists(&1)); - 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(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(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(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(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(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 - assert!(!System::account_exists(&1)); - - /* 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(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)); - // Account is still alive - assert!(System::account_exists(&1)); - - // SCENARIO: Slash will take as much as possible without killing account. - 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(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(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(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(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 - assert!(System::account_exists(&1)); - - // Slash on non-existent account is okay. - assert_eq!(Balances::slash(&12345, 1_300), (NegativeImbalance::new(0), 1300)); - }); - } - - #[test] - fn slash_reserved_loop_works() { - <$ext_builder>::default() - .existential_deposit(100) - .build() - .execute_with(|| { - /* User has no reference counter, so they can die in these scenarios */ - - // SCENARIO: Slash would not kill account. - 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(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(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(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 - assert!(System::account_exists(&1)); - - /* User has a reference counter, so they cannot die */ - - // SCENARIO: Slash would not kill account. - 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)); - // Account is still alive - assert!(System::account_exists(&1)); - - // SCENARIO: Slash as much as possible without killing. - 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(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(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 - assert!(System::account_exists(&1)); - - // Slash on non-existent account is okay. - assert_eq!(Balances::slash_reserved(&12345, 1_300), (NegativeImbalance::new(0), 1300)); - }); - } - - #[test] - fn operations_on_dead_account_should_not_change_state() { - // These functions all use `mutate_account` which may introduce a storage change when - // the account never existed to begin with, and shouldn't exist in the end. - <$ext_builder>::default() - .existential_deposit(0) - .build() - .execute_with(|| { - assert!(!frame_system::Account::::contains_key(&1337)); - - // Unreserve - assert_storage_noop!(assert_eq!(Balances::unreserve(&1337, 42), 42)); - // Reserve - assert_noop!(Balances::reserve(&1337, 42), Error::::InsufficientBalance); - // Slash Reserve - assert_storage_noop!(assert_eq!(Balances::slash_reserved(&1337, 42).1, 42)); - // Repatriate Reserve - assert_noop!(Balances::repatriate_reserved(&1337, &1338, 42, Status::Free), Error::::DeadAccount); - // Slash - assert_storage_noop!(assert_eq!(Balances::slash(&1337, 42).1, 42)); - }); - } - - #[test] - fn transfer_keep_alive_all_free_succeed() { - <$ext_builder>::default() - .existential_deposit(100) - .build() - .execute_with(|| { - 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); - }); - } - - #[test] - fn transfer_all_works() { - <$ext_builder>::default() - .existential_deposit(100) - .build() - .execute_with(|| { - // setup - 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(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(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(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); - assert_eq!(Balances::total_balance(&2), 110); - }); - } - - #[test] - fn named_reserve_should_work() { - <$ext_builder>::default().build().execute_with(|| { - let _ = Balances::deposit_creating(&1, 111); - - let id_1 = [1u8; 8]; - let id_2 = [2u8; 8]; - let id_3 = [3u8; 8]; - - // reserve - - assert_noop!(Balances::reserve_named(&id_1, &1, 112), Error::::InsufficientBalance); - - assert_ok!(Balances::reserve_named(&id_1, &1, 12)); - - assert_eq!(Balances::reserved_balance(1), 12); - assert_eq!(Balances::reserved_balance_named(&id_1, &1), 12); - assert_eq!(Balances::reserved_balance_named(&id_2, &1), 0); - - assert_ok!(Balances::reserve_named(&id_1, &1, 2)); - - assert_eq!(Balances::reserved_balance(1), 14); - assert_eq!(Balances::reserved_balance_named(&id_1, &1), 14); - assert_eq!(Balances::reserved_balance_named(&id_2, &1), 0); - - assert_ok!(Balances::reserve_named(&id_2, &1, 23)); - - assert_eq!(Balances::reserved_balance(1), 37); - assert_eq!(Balances::reserved_balance_named(&id_1, &1), 14); - assert_eq!(Balances::reserved_balance_named(&id_2, &1), 23); - - assert_ok!(Balances::reserve(&1, 34)); - - assert_eq!(Balances::reserved_balance(1), 71); - assert_eq!(Balances::reserved_balance_named(&id_1, &1), 14); - assert_eq!(Balances::reserved_balance_named(&id_2, &1), 23); - - assert_eq!(Balances::total_balance(&1), 111); - assert_eq!(Balances::free_balance(1), 40); - - assert_noop!(Balances::reserve_named(&id_3, &1, 2), Error::::TooManyReserves); - - // unreserve - - assert_eq!(Balances::unreserve_named(&id_1, &1, 10), 0); - - assert_eq!(Balances::reserved_balance(1), 61); - assert_eq!(Balances::reserved_balance_named(&id_1, &1), 4); - assert_eq!(Balances::reserved_balance_named(&id_2, &1), 23); - - assert_eq!(Balances::unreserve_named(&id_1, &1, 5), 1); - - assert_eq!(Balances::reserved_balance(1), 57); - assert_eq!(Balances::reserved_balance_named(&id_1, &1), 0); - assert_eq!(Balances::reserved_balance_named(&id_2, &1), 23); - - assert_eq!(Balances::unreserve_named(&id_2, &1, 3), 0); - - assert_eq!(Balances::reserved_balance(1), 54); - assert_eq!(Balances::reserved_balance_named(&id_1, &1), 0); - assert_eq!(Balances::reserved_balance_named(&id_2, &1), 20); - - assert_eq!(Balances::total_balance(&1), 111); - assert_eq!(Balances::free_balance(1), 57); - - // slash_reserved_named - - assert_ok!(Balances::reserve_named(&id_1, &1, 10)); - - assert_eq!(Balances::slash_reserved_named(&id_1, &1, 25).1, 15); - - assert_eq!(Balances::reserved_balance(1), 54); - assert_eq!(Balances::reserved_balance_named(&id_1, &1), 0); - assert_eq!(Balances::reserved_balance_named(&id_2, &1), 20); - assert_eq!(Balances::total_balance(&1), 101); - - assert_eq!(Balances::slash_reserved_named(&id_2, &1, 5).1, 0); - - assert_eq!(Balances::reserved_balance(1), 49); - assert_eq!(Balances::reserved_balance_named(&id_1, &1), 0); - assert_eq!(Balances::reserved_balance_named(&id_2, &1), 15); - assert_eq!(Balances::total_balance(&1), 96); - - // repatriate_reserved_named - - let _ = Balances::deposit_creating(&2, 100); - - assert_eq!(Balances::repatriate_reserved_named(&id_2, &1, &2, 10, Status::Reserved).unwrap(), 0); - - assert_eq!(Balances::reserved_balance_named(&id_2, &1), 5); - assert_eq!(Balances::reserved_balance_named(&id_2, &2), 10); - assert_eq!(Balances::reserved_balance(&2), 10); - - assert_eq!(Balances::repatriate_reserved_named(&id_2, &2, &1, 11, Status::Reserved).unwrap(), 1); - - assert_eq!(Balances::reserved_balance_named(&id_2, &1), 15); - assert_eq!(Balances::reserved_balance_named(&id_2, &2), 0); - assert_eq!(Balances::reserved_balance(&2), 0); - - assert_eq!(Balances::repatriate_reserved_named(&id_2, &1, &2, 10, Status::Free).unwrap(), 0); - assert_eq!(Balances::reserved_balance_named(&id_2, &1), 5); - assert_eq!(Balances::reserved_balance_named(&id_2, &2), 0); - assert_eq!(Balances::free_balance(&2), 110); - - // repatriate_reserved_named to self - - assert_eq!(Balances::repatriate_reserved_named(&id_2, &1, &1, 10, Status::Reserved).unwrap(), 5); - assert_eq!(Balances::reserved_balance_named(&id_2, &1), 5); - - assert_eq!(Balances::free_balance(&1), 47); - - assert_eq!(Balances::repatriate_reserved_named(&id_2, &1, &1, 15, Status::Free).unwrap(), 10); - assert_eq!(Balances::reserved_balance_named(&id_2, &1), 0); - - assert_eq!(Balances::free_balance(&1), 52); - }); - } - - #[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(|| { - let _ = Balances::deposit_creating(&1, 111); - - let id = [1u8; 8]; - - assert_ok!(Balances::ensure_reserved_named(&id, &1, 15)); - assert_eq!(Balances::reserved_balance_named(&id, &1), 15); - - assert_ok!(Balances::ensure_reserved_named(&id, &1, 10)); - assert_eq!(Balances::reserved_balance_named(&id, &1), 10); - - assert_ok!(Balances::ensure_reserved_named(&id, &1, 20)); - assert_eq!(Balances::reserved_balance_named(&id, &1), 20); - }); - } - - #[test] - fn unreserve_all_named_should_work() { - <$ext_builder>::default().build().execute_with(|| { - let _ = Balances::deposit_creating(&1, 111); - - let id = [1u8; 8]; - - assert_ok!(Balances::reserve_named(&id, &1, 15)); - - assert_eq!(Balances::unreserve_all_named(&id, &1), 15); - assert_eq!(Balances::reserved_balance_named(&id, &1), 0); - assert_eq!(Balances::free_balance(&1), 111); - - assert_eq!(Balances::unreserve_all_named(&id, &1), 0); - }); - } - - #[test] - fn slash_all_reserved_named_should_work() { - <$ext_builder>::default().build().execute_with(|| { - let _ = Balances::deposit_creating(&1, 111); - - let id = [1u8; 8]; - - assert_ok!(Balances::reserve_named(&id, &1, 15)); - - assert_eq!(Balances::slash_all_reserved_named(&id, &1).peek(), 15); - assert_eq!(Balances::reserved_balance_named(&id, &1), 0); - assert_eq!(Balances::free_balance(&1), 96); - - assert_eq!(Balances::slash_all_reserved_named(&id, &1).peek(), 0); - }); - } - - #[test] - fn repatriate_all_reserved_named_should_work() { - <$ext_builder>::default().build().execute_with(|| { - let _ = Balances::deposit_creating(&1, 111); - let _ = Balances::deposit_creating(&2, 10); - let _ = Balances::deposit_creating(&3, 10); - - let id = [1u8; 8]; - - assert_ok!(Balances::reserve_named(&id, &1, 15)); - - assert_ok!(Balances::repatriate_all_reserved_named(&id, &1, &2, Status::Reserved)); - assert_eq!(Balances::reserved_balance_named(&id, &1), 0); - assert_eq!(Balances::reserved_balance_named(&id, &2), 15); - - assert_ok!(Balances::repatriate_all_reserved_named(&id, &2, &3, Status::Free)); - assert_eq!(Balances::reserved_balance_named(&id, &2), 0); - 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(RuntimeOrigin::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(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); - 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/balances/src/tests/currency_tests.rs b/frame/balances/src/tests/currency_tests.rs new file mode 100644 index 0000000000000..b0a38f4ac4ed7 --- /dev/null +++ b/frame/balances/src/tests/currency_tests.rs @@ -0,0 +1,1231 @@ +// 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. + +//! Tests regarding the functionality of the `Currency` trait set implementations. + +use super::*; +use crate::NegativeImbalance; +use frame_support::traits::{ + BalanceStatus::{Free, Reserved}, + Currency, + ExistenceRequirement::{self, AllowDeath}, + LockIdentifier, LockableCurrency, NamedReservableCurrency, ReservableCurrency, WithdrawReasons, +}; + +const ID_1: LockIdentifier = *b"1 "; +const ID_2: LockIdentifier = *b"2 "; + +pub const CALL: &::RuntimeCall = + &RuntimeCall::Balances(crate::Call::transfer_allow_death { dest: 0, value: 0 }); + +#[test] +fn basic_locking_should_work() { + ExtBuilder::default() + .existential_deposit(1) + .monied(true) + .build_and_execute_with(|| { + assert_eq!(Balances::free_balance(1), 10); + Balances::set_lock(ID_1, &1, 9, WithdrawReasons::all()); + assert_noop!( + >::transfer(&1, &2, 5, AllowDeath), + TokenError::Frozen + ); + }); +} + +#[test] +fn account_should_be_reaped() { + ExtBuilder::default() + .existential_deposit(1) + .monied(true) + .build_and_execute_with(|| { + assert_eq!(Balances::free_balance(1), 10); + assert_ok!(>::transfer(&1, &2, 10, AllowDeath)); + assert_eq!(System::providers(&1), 0); + assert_eq!(System::consumers(&1), 0); + // Check that the account is dead. + assert!(!frame_system::Account::::contains_key(&1)); + }); +} + +#[test] +fn reap_failed_due_to_provider_and_consumer() { + ExtBuilder::default() + .existential_deposit(1) + .monied(true) + .build_and_execute_with(|| { + // SCENARIO: only one provider and there are remaining consumers. + assert_ok!(System::inc_consumers(&1)); + assert!(!System::can_dec_provider(&1)); + assert_noop!( + >::transfer(&1, &2, 10, AllowDeath), + TokenError::Frozen + ); + assert!(System::account_exists(&1)); + assert_eq!(Balances::free_balance(1), 10); + + // SCENARIO: more than one provider, but will not kill account due to other provider. + assert_eq!(System::inc_providers(&1), frame_system::IncRefStatus::Existed); + assert_eq!(System::providers(&1), 2); + assert!(System::can_dec_provider(&1)); + assert_ok!(>::transfer(&1, &2, 10, AllowDeath)); + assert_eq!(System::providers(&1), 1); + assert!(System::account_exists(&1)); + assert_eq!(Balances::free_balance(1), 0); + }); +} + +#[test] +fn partial_locking_should_work() { + ExtBuilder::default() + .existential_deposit(1) + .monied(true) + .build_and_execute_with(|| { + Balances::set_lock(ID_1, &1, 5, WithdrawReasons::all()); + assert_ok!(>::transfer(&1, &2, 1, AllowDeath)); + }); +} + +#[test] +fn lock_removal_should_work() { + ExtBuilder::default() + .existential_deposit(1) + .monied(true) + .build_and_execute_with(|| { + Balances::set_lock(ID_1, &1, u64::MAX, WithdrawReasons::all()); + Balances::remove_lock(ID_1, &1); + assert_ok!(>::transfer(&1, &2, 1, AllowDeath)); + }); +} + +#[test] +fn lock_replacement_should_work() { + ExtBuilder::default() + .existential_deposit(1) + .monied(true) + .build_and_execute_with(|| { + Balances::set_lock(ID_1, &1, u64::MAX, WithdrawReasons::all()); + Balances::set_lock(ID_1, &1, 5, WithdrawReasons::all()); + assert_ok!(>::transfer(&1, &2, 1, AllowDeath)); + }); +} + +#[test] +fn double_locking_should_work() { + ExtBuilder::default() + .existential_deposit(1) + .monied(true) + .build_and_execute_with(|| { + Balances::set_lock(ID_1, &1, 5, WithdrawReasons::all()); + Balances::set_lock(ID_2, &1, 5, WithdrawReasons::all()); + assert_ok!(>::transfer(&1, &2, 1, AllowDeath)); + }); +} + +#[test] +fn combination_locking_should_work() { + ExtBuilder::default() + .existential_deposit(1) + .monied(true) + .build_and_execute_with(|| { + Balances::set_lock(ID_1, &1, u64::MAX, WithdrawReasons::empty()); + Balances::set_lock(ID_2, &1, 0, WithdrawReasons::all()); + assert_ok!(>::transfer(&1, &2, 1, AllowDeath)); + }); +} + +#[test] +fn lock_value_extension_should_work() { + ExtBuilder::default() + .existential_deposit(1) + .monied(true) + .build_and_execute_with(|| { + Balances::set_lock(ID_1, &1, 5, WithdrawReasons::all()); + assert_noop!( + >::transfer(&1, &2, 6, AllowDeath), + TokenError::Frozen + ); + Balances::extend_lock(ID_1, &1, 2, WithdrawReasons::all()); + assert_noop!( + >::transfer(&1, &2, 6, AllowDeath), + TokenError::Frozen + ); + Balances::extend_lock(ID_1, &1, 8, WithdrawReasons::all()); + assert_noop!( + >::transfer(&1, &2, 3, AllowDeath), + TokenError::Frozen + ); + }); +} + +#[test] +fn lock_should_work_reserve() { + ExtBuilder::default() + .existential_deposit(1) + .monied(true) + .build_and_execute_with(|| { + pallet_transaction_payment::NextFeeMultiplier::::put( + Multiplier::saturating_from_integer(1), + ); + Balances::set_lock(ID_1, &1, 10, WithdrawReasons::RESERVE); + assert_noop!( + >::transfer(&1, &2, 1, AllowDeath), + TokenError::Frozen + ); + assert_noop!(Balances::reserve(&1, 1), Error::::LiquidityRestrictions,); + assert!( as SignedExtension>::pre_dispatch( + ChargeTransactionPayment::from(1), + &1, + CALL, + &info_from_weight(Weight::from_parts(1, 0)), + 1, + ) + .is_err()); + assert!( as SignedExtension>::pre_dispatch( + ChargeTransactionPayment::from(0), + &1, + CALL, + &info_from_weight(Weight::from_parts(1, 0)), + 1, + ) + .is_err()); + }); +} + +#[test] +fn lock_should_work_tx_fee() { + ExtBuilder::default() + .existential_deposit(1) + .monied(true) + .build_and_execute_with(|| { + Balances::set_lock(ID_1, &1, 10, WithdrawReasons::TRANSACTION_PAYMENT); + assert_noop!( + >::transfer(&1, &2, 1, AllowDeath), + TokenError::Frozen + ); + assert_noop!(Balances::reserve(&1, 1), Error::::LiquidityRestrictions,); + assert!( as SignedExtension>::pre_dispatch( + ChargeTransactionPayment::from(1), + &1, + CALL, + &info_from_weight(Weight::from_parts(1, 0)), + 1, + ) + .is_err()); + assert!( as SignedExtension>::pre_dispatch( + ChargeTransactionPayment::from(0), + &1, + CALL, + &info_from_weight(Weight::from_parts(1, 0)), + 1, + ) + .is_err()); + }); +} + +#[test] +fn lock_block_number_extension_should_work() { + ExtBuilder::default() + .existential_deposit(1) + .monied(true) + .build_and_execute_with(|| { + Balances::set_lock(ID_1, &1, 10, WithdrawReasons::all()); + assert_noop!( + >::transfer(&1, &2, 6, AllowDeath), + TokenError::Frozen + ); + Balances::extend_lock(ID_1, &1, 10, WithdrawReasons::all()); + assert_noop!( + >::transfer(&1, &2, 6, AllowDeath), + TokenError::Frozen + ); + System::set_block_number(2); + Balances::extend_lock(ID_1, &1, 10, WithdrawReasons::all()); + assert_noop!( + >::transfer(&1, &2, 3, AllowDeath), + TokenError::Frozen + ); + }); +} + +#[test] +fn lock_reasons_extension_should_work() { + ExtBuilder::default() + .existential_deposit(1) + .monied(true) + .build_and_execute_with(|| { + Balances::set_lock(ID_1, &1, 10, WithdrawReasons::TRANSFER); + assert_noop!( + >::transfer(&1, &2, 6, AllowDeath), + TokenError::Frozen + ); + Balances::extend_lock(ID_1, &1, 10, WithdrawReasons::empty()); + assert_noop!( + >::transfer(&1, &2, 6, AllowDeath), + TokenError::Frozen + ); + Balances::extend_lock(ID_1, &1, 10, WithdrawReasons::RESERVE); + assert_noop!( + >::transfer(&1, &2, 6, AllowDeath), + TokenError::Frozen + ); + }); +} + +#[test] +fn reserved_balance_should_prevent_reclaim_count() { + ExtBuilder::default() + .existential_deposit(256 * 1) + .monied(true) + .build_and_execute_with(|| { + System::inc_account_nonce(&2); + assert_eq!(Balances::total_balance(&2), 256 * 20); + assert_eq!(System::providers(&2), 1); + System::inc_providers(&2); + assert_eq!(System::providers(&2), 2); + + assert_ok!(Balances::reserve(&2, 256 * 19 + 1)); // account 2 becomes mostly reserved + assert_eq!(System::providers(&2), 1); + assert_eq!(Balances::free_balance(2), 255); // "free" account would be deleted. + assert_eq!(Balances::total_balance(&2), 256 * 20); // reserve still exists. + assert_eq!(System::account_nonce(&2), 1); + + // account 4 tries to take index 1 for account 5. + assert_ok!(Balances::transfer_allow_death(Some(4).into(), 5, 256 * 1 + 0x69)); + assert_eq!(Balances::total_balance(&5), 256 * 1 + 0x69); + + assert!(Balances::slash_reserved(&2, 256 * 19 + 1).1.is_zero()); // account 2 gets slashed + + // "reserve" account reduced to 255 (below ED) so account no longer consuming + assert_ok!(System::dec_providers(&2)); + assert_eq!(System::providers(&2), 0); + // account deleted + assert_eq!(System::account_nonce(&2), 0); // nonce zero + assert_eq!(Balances::total_balance(&2), 0); + + // account 4 tries to take index 1 again for account 6. + assert_ok!(Balances::transfer_allow_death(Some(4).into(), 6, 256 * 1 + 0x69)); + assert_eq!(Balances::total_balance(&6), 256 * 1 + 0x69); + }); +} + +#[test] +fn reward_should_work() { + ExtBuilder::default().monied(true).build_and_execute_with(|| { + assert_eq!(Balances::total_balance(&1), 10); + assert_ok!(Balances::deposit_into_existing(&1, 10).map(drop)); + System::assert_last_event(RuntimeEvent::Balances(crate::Event::Deposit { + who: 1, + amount: 10, + })); + assert_eq!(Balances::total_balance(&1), 20); + assert_eq!(Balances::total_issuance(), 120); + }); +} + +#[test] +fn balance_works() { + ExtBuilder::default().build_and_execute_with(|| { + let _ = Balances::deposit_creating(&1, 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); + assert_eq!(Balances::free_balance(2), 0); + assert_eq!(Balances::reserved_balance(2), 0); + assert_eq!(Balances::total_balance(&2), 0); + }); +} + +#[test] +fn reserving_balance_should_work() { + ExtBuilder::default().build_and_execute_with(|| { + let _ = Balances::deposit_creating(&1, 111); + + assert_eq!(Balances::total_balance(&1), 111); + assert_eq!(Balances::free_balance(1), 111); + assert_eq!(Balances::reserved_balance(1), 0); + + assert_ok!(Balances::reserve(&1, 69)); + + assert_eq!(Balances::total_balance(&1), 111); + assert_eq!(Balances::free_balance(1), 42); + assert_eq!(Balances::reserved_balance(1), 69); + }); +} + +#[test] +fn deducting_balance_should_work() { + ExtBuilder::default().build_and_execute_with(|| { + let _ = Balances::deposit_creating(&1, 111); + assert_ok!(Balances::reserve(&1, 69)); + assert_eq!(Balances::free_balance(1), 42); + }); +} + +#[test] +fn refunding_balance_should_work() { + ExtBuilder::default().build_and_execute_with(|| { + let _ = Balances::deposit_creating(&1, 42); + assert_ok!(Balances::mutate_account(&1, |a| a.reserved = 69)); + Balances::unreserve(&1, 69); + assert_eq!(Balances::free_balance(1), 111); + assert_eq!(Balances::reserved_balance(1), 0); + }); +} + +#[test] +fn slashing_balance_should_work() { + ExtBuilder::default().build_and_execute_with(|| { + let _ = Balances::deposit_creating(&1, 112); + assert_ok!(Balances::reserve(&1, 69)); + assert!(Balances::slash(&1, 42).1.is_zero()); + assert_eq!(Balances::free_balance(1), 1); + assert_eq!(Balances::reserved_balance(1), 69); + assert_eq!(Balances::total_issuance(), 70); + }); +} + +#[test] +fn withdrawing_balance_should_work() { + ExtBuilder::default().build_and_execute_with(|| { + let _ = Balances::deposit_creating(&2, 111); + let _ = + Balances::withdraw(&2, 11, WithdrawReasons::TRANSFER, ExistenceRequirement::KeepAlive); + System::assert_last_event(RuntimeEvent::Balances(crate::Event::Withdraw { + who: 2, + amount: 11, + })); + assert_eq!(Balances::free_balance(2), 100); + assert_eq!(Balances::total_issuance(), 100); + }); +} + +#[test] +fn withdrawing_balance_should_fail_when_not_expendable() { + ExtBuilder::default().build_and_execute_with(|| { + ExistentialDeposit::set(10); + let _ = Balances::deposit_creating(&2, 20); + assert_ok!(Balances::reserve(&2, 5)); + assert_noop!( + Balances::withdraw(&2, 6, WithdrawReasons::TRANSFER, ExistenceRequirement::KeepAlive), + Error::::Expendability, + ); + assert_ok!(Balances::withdraw( + &2, + 5, + WithdrawReasons::TRANSFER, + ExistenceRequirement::KeepAlive + ),); + }); +} + +#[test] +fn slashing_incomplete_balance_should_work() { + ExtBuilder::default().build_and_execute_with(|| { + let _ = Balances::deposit_creating(&1, 42); + assert_ok!(Balances::reserve(&1, 21)); + assert_eq!(Balances::slash(&1, 69).1, 49); + assert_eq!(Balances::free_balance(1), 1); + assert_eq!(Balances::reserved_balance(1), 21); + assert_eq!(Balances::total_issuance(), 22); + }); +} + +#[test] +fn unreserving_balance_should_work() { + ExtBuilder::default().build_and_execute_with(|| { + let _ = Balances::deposit_creating(&1, 111); + assert_ok!(Balances::reserve(&1, 110)); + Balances::unreserve(&1, 41); + assert_eq!(Balances::reserved_balance(1), 69); + assert_eq!(Balances::free_balance(1), 42); + }); +} + +#[test] +fn slashing_reserved_balance_should_work() { + ExtBuilder::default().build_and_execute_with(|| { + let _ = Balances::deposit_creating(&1, 112); + assert_ok!(Balances::reserve(&1, 111)); + assert_eq!(Balances::slash_reserved(&1, 42).1, 0); + assert_eq!(Balances::reserved_balance(1), 69); + assert_eq!(Balances::free_balance(1), 1); + assert_eq!(Balances::total_issuance(), 70); + }); +} + +#[test] +fn slashing_incomplete_reserved_balance_should_work() { + ExtBuilder::default().build_and_execute_with(|| { + let _ = Balances::deposit_creating(&1, 111); + assert_ok!(Balances::reserve(&1, 42)); + assert_eq!(Balances::slash_reserved(&1, 69).1, 27); + assert_eq!(Balances::free_balance(1), 69); + assert_eq!(Balances::reserved_balance(1), 0); + assert_eq!(Balances::total_issuance(), 69); + }); +} + +#[test] +fn repatriating_reserved_balance_should_work() { + ExtBuilder::default().build_and_execute_with(|| { + let _ = Balances::deposit_creating(&1, 111); + let _ = Balances::deposit_creating(&2, 1); + assert_ok!(Balances::reserve(&1, 110)); + assert_ok!(Balances::repatriate_reserved(&1, &2, 41, Free), 0); + System::assert_last_event(RuntimeEvent::Balances(crate::Event::ReserveRepatriated { + from: 1, + to: 2, + amount: 41, + destination_status: Free, + })); + assert_eq!(Balances::reserved_balance(1), 69); + assert_eq!(Balances::free_balance(1), 1); + assert_eq!(Balances::reserved_balance(2), 0); + assert_eq!(Balances::free_balance(2), 42); + }); +} + +#[test] +fn transferring_reserved_balance_should_work() { + ExtBuilder::default().build_and_execute_with(|| { + let _ = Balances::deposit_creating(&1, 111); + let _ = Balances::deposit_creating(&2, 1); + assert_ok!(Balances::reserve(&1, 110)); + assert_ok!(Balances::repatriate_reserved(&1, &2, 41, Reserved), 0); + assert_eq!(Balances::reserved_balance(1), 69); + assert_eq!(Balances::free_balance(1), 1); + assert_eq!(Balances::reserved_balance(2), 41); + assert_eq!(Balances::free_balance(2), 1); + }); +} + +#[test] +fn transferring_reserved_balance_to_yourself_should_work() { + ExtBuilder::default().build_and_execute_with(|| { + let _ = Balances::deposit_creating(&1, 110); + assert_ok!(Balances::reserve(&1, 50)); + assert_ok!(Balances::repatriate_reserved(&1, &1, 50, 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, 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() { + ExtBuilder::default().build_and_execute_with(|| { + let _ = Balances::deposit_creating(&1, 111); + assert_ok!(Balances::reserve(&1, 110)); + assert_noop!( + Balances::repatriate_reserved(&1, &2, 42, Free), + Error::::DeadAccount + ); + }); +} + +#[test] +fn transferring_incomplete_reserved_balance_should_work() { + ExtBuilder::default().build_and_execute_with(|| { + let _ = Balances::deposit_creating(&1, 110); + let _ = Balances::deposit_creating(&2, 1); + assert_ok!(Balances::reserve(&1, 41)); + assert_ok!(Balances::repatriate_reserved(&1, &2, 69, Free), 28); + assert_eq!(Balances::reserved_balance(1), 0); + assert_eq!(Balances::free_balance(1), 69); + assert_eq!(Balances::reserved_balance(2), 0); + assert_eq!(Balances::free_balance(2), 42); + }); +} + +#[test] +fn transferring_too_high_value_should_not_panic() { + ExtBuilder::default().build_and_execute_with(|| { + Balances::make_free_balance_be(&1, u64::MAX); + Balances::make_free_balance_be(&2, 1); + + assert_err!( + >::transfer(&1, &2, u64::MAX, AllowDeath), + ArithmeticError::Overflow, + ); + + assert_eq!(Balances::free_balance(1), u64::MAX); + assert_eq!(Balances::free_balance(2), 1); + }); +} + +#[test] +fn account_create_on_free_too_low_with_other() { + ExtBuilder::default().existential_deposit(100).build_and_execute_with(|| { + let _ = Balances::deposit_creating(&1, 100); + assert_eq!(Balances::total_issuance(), 100); + + // No-op. + let _ = Balances::deposit_creating(&2, 50); + assert_eq!(Balances::free_balance(2), 0); + assert_eq!(Balances::total_issuance(), 100); + }) +} + +#[test] +fn account_create_on_free_too_low() { + ExtBuilder::default().existential_deposit(100).build_and_execute_with(|| { + // No-op. + let _ = Balances::deposit_creating(&2, 50); + assert_eq!(Balances::free_balance(2), 0); + assert_eq!(Balances::total_issuance(), 0); + }) +} + +#[test] +fn account_removal_on_free_too_low() { + ExtBuilder::default().existential_deposit(100).build_and_execute_with(|| { + assert_eq!(Balances::total_issuance(), 0); + + // Setup two accounts with free balance above the existential threshold. + let _ = Balances::deposit_creating(&1, 110); + let _ = Balances::deposit_creating(&2, 110); + + assert_eq!(Balances::free_balance(1), 110); + assert_eq!(Balances::free_balance(2), 110); + assert_eq!(Balances::total_issuance(), 220); + + // Transfer funds from account 1 of such amount that after this transfer + // the balance of account 1 will be below the existential threshold. + // This should lead to the removal of all balance of this account. + assert_ok!(Balances::transfer_allow_death(Some(1).into(), 2, 20)); + + // Verify free balance removal of account 1. + assert_eq!(Balances::free_balance(1), 0); + assert_eq!(Balances::free_balance(2), 130); + + // Verify that TotalIssuance tracks balance removal when free balance is too low. + assert_eq!(Balances::total_issuance(), 130); + }); +} + +#[test] +fn burn_must_work() { + ExtBuilder::default().monied(true).build_and_execute_with(|| { + let init_total_issuance = Balances::total_issuance(); + let imbalance = Balances::burn(10); + assert_eq!(Balances::total_issuance(), init_total_issuance - 10); + drop(imbalance); + assert_eq!(Balances::total_issuance(), init_total_issuance); + }); +} + +#[test] +#[should_panic = "the balance of any account should always be at least the existential deposit."] +fn cannot_set_genesis_value_below_ed() { + EXISTENTIAL_DEPOSIT.with(|v| *v.borrow_mut() = 11); + let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); + let _ = crate::GenesisConfig:: { balances: vec![(1, 10)] } + .assimilate_storage(&mut t) + .unwrap(); +} + +#[test] +#[should_panic = "duplicate balances in genesis."] +fn cannot_set_genesis_value_twice() { + let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); + let _ = crate::GenesisConfig:: { balances: vec![(1, 10), (2, 20), (1, 15)] } + .assimilate_storage(&mut t) + .unwrap(); +} + +#[test] +fn existential_deposit_respected_when_reserving() { + ExtBuilder::default().existential_deposit(100).build_and_execute_with(|| { + // Set balance to free and reserved at the existential deposit + assert_ok!(Balances::force_set_balance(RawOrigin::Root.into(), 1, 101)); + // Check balance + assert_eq!(Balances::free_balance(1), 101); + assert_eq!(Balances::reserved_balance(1), 0); + + // Reserve some free balance + assert_ok!(Balances::reserve(&1, 1)); + // Check balance, the account should be ok. + assert_eq!(Balances::free_balance(1), 100); + assert_eq!(Balances::reserved_balance(1), 1); + + // Cannot reserve any more of the free balance. + assert_noop!(Balances::reserve(&1, 1), DispatchError::ConsumerRemaining); + }); +} + +#[test] +fn slash_fails_when_account_needed() { + ExtBuilder::default().existential_deposit(50).build_and_execute_with(|| { + // Set balance to free and reserved at the existential deposit + assert_ok!(Balances::force_set_balance(RawOrigin::Root.into(), 1, 52)); + assert_ok!(Balances::reserve(&1, 1)); + // Check balance + assert_eq!(Balances::free_balance(1), 51); + assert_eq!(Balances::reserved_balance(1), 1); + + // Slash a small amount + let res = Balances::slash(&1, 1); + assert_eq!(res, (NegativeImbalance::new(1), 0)); + + // The account should be dead. + assert_eq!(Balances::free_balance(1), 50); + assert_eq!(Balances::reserved_balance(1), 1); + + // Slashing again doesn't work since we require the ED + let res = Balances::slash(&1, 1); + assert_eq!(res, (NegativeImbalance::new(0), 1)); + + // The account should be dead. + assert_eq!(Balances::free_balance(1), 50); + assert_eq!(Balances::reserved_balance(1), 1); + }); +} + +#[test] +fn account_deleted_when_just_dust() { + ExtBuilder::default().existential_deposit(50).build_and_execute_with(|| { + // Set balance to free and reserved at the existential deposit + assert_ok!(Balances::force_set_balance(RawOrigin::Root.into(), 1, 50)); + // Check balance + assert_eq!(Balances::free_balance(1), 50); + + // Slash a small amount + let res = Balances::slash(&1, 1); + assert_eq!(res, (NegativeImbalance::new(1), 0)); + + // The account should be dead. + assert_eq!(Balances::free_balance(1), 0); + }); +} + +#[test] +fn emit_events_with_reserve_and_unreserve() { + ExtBuilder::default().build_and_execute_with(|| { + let _ = Balances::deposit_creating(&1, 100); + + System::set_block_number(2); + assert_ok!(Balances::reserve(&1, 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(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(RuntimeEvent::Balances(crate::Event::Unreserved { + who: 1, + amount: 5, + })); + }); +} + +#[test] +fn emit_events_with_existential_deposit() { + ExtBuilder::default().existential_deposit(100).build_and_execute_with(|| { + assert_ok!(Balances::force_set_balance(RawOrigin::Root.into(), 1, 100)); + + assert_eq!( + events(), + [ + 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 }), + ] + ); + + let res = Balances::slash(&1, 1); + assert_eq!(res, (NegativeImbalance::new(1), 0)); + + assert_eq!( + events(), + [ + 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 }), + ] + ); + }); +} + +#[test] +fn emit_events_with_no_existential_deposit_suicide() { + ExtBuilder::default().existential_deposit(1).build_and_execute_with(|| { + Balances::make_free_balance_be(&1, 100); + + assert_eq!( + events(), + [ + RuntimeEvent::Balances(crate::Event::BalanceSet { who: 1, free: 100 }), + RuntimeEvent::System(system::Event::NewAccount { account: 1 }), + RuntimeEvent::Balances(crate::Event::Endowed { account: 1, free_balance: 100 }), + ] + ); + + let res = Balances::slash(&1, 100); + assert_eq!(res, (NegativeImbalance::new(100), 0)); + + assert_eq!( + events(), + [ + RuntimeEvent::System(system::Event::KilledAccount { account: 1 }), + RuntimeEvent::Balances(crate::Event::Slashed { who: 1, amount: 100 }), + ] + ); + }); +} + +#[test] +fn slash_over_works() { + ExtBuilder::default().existential_deposit(100).build_and_execute_with(|| { + // SCENARIO: Over-slash will kill account, and report missing slash amount. + Balances::make_free_balance_be(&1, 1_000); + // 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)); + }); +} + +#[test] +fn slash_full_works() { + ExtBuilder::default().existential_deposit(100).build_and_execute_with(|| { + Balances::make_free_balance_be(&1, 1_000); + // Slashed completed in full + assert_eq!(Balances::slash(&1, 1_000), (NegativeImbalance::new(1000), 0)); + // Account is still alive + assert!(!System::account_exists(&1)); + System::assert_last_event(RuntimeEvent::Balances(crate::Event::Slashed { + who: 1, + amount: 1000, + })); + }); +} + +#[test] +fn slash_partial_works() { + ExtBuilder::default().existential_deposit(100).build_and_execute_with(|| { + Balances::make_free_balance_be(&1, 1_000); + // Slashed completed in full + assert_eq!(Balances::slash(&1, 900), (NegativeImbalance::new(900), 0)); + // Account is still alive + assert!(System::account_exists(&1)); + System::assert_last_event(RuntimeEvent::Balances(crate::Event::Slashed { + who: 1, + amount: 900, + })); + }); +} + +#[test] +fn slash_dusting_works() { + ExtBuilder::default().existential_deposit(100).build_and_execute_with(|| { + Balances::make_free_balance_be(&1, 1_000); + // Slashed completed in full + assert_eq!(Balances::slash(&1, 950), (NegativeImbalance::new(950), 0)); + assert!(!System::account_exists(&1)); + System::assert_last_event(RuntimeEvent::Balances(crate::Event::Slashed { + who: 1, + amount: 950, + })); + }); +} + +#[test] +fn slash_does_not_take_from_reserve() { + ExtBuilder::default().existential_deposit(100).build_and_execute_with(|| { + Balances::make_free_balance_be(&1, 1_000); + assert_ok!(Balances::reserve(&1, 100)); + // Slashed completed in full + assert_eq!(Balances::slash(&1, 900), (NegativeImbalance::new(800), 100)); + assert_eq!(Balances::reserved_balance(&1), 100); + System::assert_last_event(RuntimeEvent::Balances(crate::Event::Slashed { + who: 1, + amount: 800, + })); + }); +} + +#[test] +fn slash_consumed_slash_full_works() { + ExtBuilder::default().existential_deposit(100).build_and_execute_with(|| { + Balances::make_free_balance_be(&1, 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(&1, 900), (NegativeImbalance::new(900), 0)); + // Account is still alive + assert!(System::account_exists(&1)); + }); +} + +#[test] +fn slash_consumed_slash_over_works() { + ExtBuilder::default().existential_deposit(100).build_and_execute_with(|| { + Balances::make_free_balance_be(&1, 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(&1, 1_000), (NegativeImbalance::new(900), 100)); + // Account is still alive + assert!(System::account_exists(&1)); + }); +} + +#[test] +fn slash_consumed_slash_partial_works() { + ExtBuilder::default().existential_deposit(100).build_and_execute_with(|| { + Balances::make_free_balance_be(&1, 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(&1, 800), (NegativeImbalance::new(800), 0)); + // Account is still alive + assert!(System::account_exists(&1)); + }); +} + +#[test] +fn slash_on_non_existant_works() { + ExtBuilder::default().existential_deposit(100).build_and_execute_with(|| { + // Slash on non-existent account is okay. + assert_eq!(Balances::slash(&12345, 1_300), (NegativeImbalance::new(0), 1300)); + }); +} + +#[test] +fn slash_reserved_slash_partial_works() { + ExtBuilder::default().existential_deposit(100).build_and_execute_with(|| { + Balances::make_free_balance_be(&1, 1_000); + assert_ok!(Balances::reserve(&1, 900)); + // Slashed completed in full + assert_eq!(Balances::slash_reserved(&1, 800), (NegativeImbalance::new(800), 0)); + assert_eq!(System::consumers(&1), 1); + assert_eq!(Balances::reserved_balance(&1), 100); + assert_eq!(Balances::free_balance(&1), 100); + }); +} + +#[test] +fn slash_reserved_slash_everything_works() { + ExtBuilder::default().existential_deposit(100).build_and_execute_with(|| { + Balances::make_free_balance_be(&1, 1_000); + assert_ok!(Balances::reserve(&1, 900)); + assert_eq!(System::consumers(&1), 1); + // Slashed completed in full + assert_eq!(Balances::slash_reserved(&1, 900), (NegativeImbalance::new(900), 0)); + assert_eq!(System::consumers(&1), 0); + // Account is still alive + assert!(System::account_exists(&1)); + }); +} + +#[test] +fn slash_reserved_overslash_does_not_touch_free_balance() { + ExtBuilder::default().existential_deposit(100).build_and_execute_with(|| { + // SCENARIO: Over-slash doesn't touch free balance. + Balances::make_free_balance_be(&1, 1_000); + assert_ok!(Balances::reserve(&1, 800)); + // Slashed done + assert_eq!(Balances::slash_reserved(&1, 900), (NegativeImbalance::new(800), 100)); + assert_eq!(Balances::free_balance(&1), 200); + }); +} + +#[test] +fn slash_reserved_on_non_existant_works() { + ExtBuilder::default().existential_deposit(100).build_and_execute_with(|| { + // Slash on non-existent account is okay. + assert_eq!(Balances::slash_reserved(&12345, 1_300), (NegativeImbalance::new(0), 1300)); + }); +} + +#[test] +fn operations_on_dead_account_should_not_change_state() { + // These functions all use `mutate_account` which may introduce a storage change when + // the account never existed to begin with, and shouldn't exist in the end. + ExtBuilder::default().existential_deposit(0).build_and_execute_with(|| { + assert!(!frame_system::Account::::contains_key(&1337)); + + // Unreserve + assert_storage_noop!(assert_eq!(Balances::unreserve(&1337, 42), 42)); + // Reserve + assert_noop!(Balances::reserve(&1337, 42), Error::::InsufficientBalance); + // Slash Reserve + assert_storage_noop!(assert_eq!(Balances::slash_reserved(&1337, 42).1, 42)); + // Repatriate Reserve + assert_noop!( + Balances::repatriate_reserved(&1337, &1338, 42, Free), + Error::::DeadAccount + ); + // Slash + assert_storage_noop!(assert_eq!(Balances::slash(&1337, 42).1, 42)); + }); +} + +#[test] +fn named_reserve_should_work() { + ExtBuilder::default().build_and_execute_with(|| { + let _ = Balances::deposit_creating(&1, 111); + + let id_1 = TestId::Foo; + let id_2 = TestId::Bar; + let id_3 = TestId::Baz; + + // reserve + + assert_noop!( + Balances::reserve_named(&id_1, &1, 112), + Error::::InsufficientBalance + ); + + assert_ok!(Balances::reserve_named(&id_1, &1, 12)); + + assert_eq!(Balances::reserved_balance(1), 12); + assert_eq!(Balances::reserved_balance_named(&id_1, &1), 12); + assert_eq!(Balances::reserved_balance_named(&id_2, &1), 0); + + assert_ok!(Balances::reserve_named(&id_1, &1, 2)); + + assert_eq!(Balances::reserved_balance(1), 14); + assert_eq!(Balances::reserved_balance_named(&id_1, &1), 14); + assert_eq!(Balances::reserved_balance_named(&id_2, &1), 0); + + assert_ok!(Balances::reserve_named(&id_2, &1, 23)); + + assert_eq!(Balances::reserved_balance(1), 37); + assert_eq!(Balances::reserved_balance_named(&id_1, &1), 14); + assert_eq!(Balances::reserved_balance_named(&id_2, &1), 23); + + assert_ok!(Balances::reserve(&1, 34)); + + assert_eq!(Balances::reserved_balance(1), 71); + assert_eq!(Balances::reserved_balance_named(&id_1, &1), 14); + assert_eq!(Balances::reserved_balance_named(&id_2, &1), 23); + + assert_eq!(Balances::total_balance(&1), 111); + assert_eq!(Balances::free_balance(1), 40); + + assert_noop!(Balances::reserve_named(&id_3, &1, 2), Error::::TooManyReserves); + + // unreserve + + assert_eq!(Balances::unreserve_named(&id_1, &1, 10), 0); + + assert_eq!(Balances::reserved_balance(1), 61); + assert_eq!(Balances::reserved_balance_named(&id_1, &1), 4); + assert_eq!(Balances::reserved_balance_named(&id_2, &1), 23); + + assert_eq!(Balances::unreserve_named(&id_1, &1, 5), 1); + + assert_eq!(Balances::reserved_balance(1), 57); + assert_eq!(Balances::reserved_balance_named(&id_1, &1), 0); + assert_eq!(Balances::reserved_balance_named(&id_2, &1), 23); + + assert_eq!(Balances::unreserve_named(&id_2, &1, 3), 0); + + assert_eq!(Balances::reserved_balance(1), 54); + assert_eq!(Balances::reserved_balance_named(&id_1, &1), 0); + assert_eq!(Balances::reserved_balance_named(&id_2, &1), 20); + + assert_eq!(Balances::total_balance(&1), 111); + assert_eq!(Balances::free_balance(1), 57); + + // slash_reserved_named + + assert_ok!(Balances::reserve_named(&id_1, &1, 10)); + + assert_eq!(Balances::slash_reserved_named(&id_1, &1, 25).1, 15); + + assert_eq!(Balances::reserved_balance(1), 54); + assert_eq!(Balances::reserved_balance_named(&id_1, &1), 0); + assert_eq!(Balances::reserved_balance_named(&id_2, &1), 20); + assert_eq!(Balances::total_balance(&1), 101); + + assert_eq!(Balances::slash_reserved_named(&id_2, &1, 5).1, 0); + + assert_eq!(Balances::reserved_balance(1), 49); + assert_eq!(Balances::reserved_balance_named(&id_1, &1), 0); + assert_eq!(Balances::reserved_balance_named(&id_2, &1), 15); + assert_eq!(Balances::total_balance(&1), 96); + + // repatriate_reserved_named + + let _ = Balances::deposit_creating(&2, 100); + + assert_eq!(Balances::repatriate_reserved_named(&id_2, &1, &2, 10, Reserved).unwrap(), 0); + + assert_eq!(Balances::reserved_balance_named(&id_2, &1), 5); + assert_eq!(Balances::reserved_balance_named(&id_2, &2), 10); + assert_eq!(Balances::reserved_balance(&2), 10); + + assert_eq!(Balances::repatriate_reserved_named(&id_2, &2, &1, 11, Reserved).unwrap(), 1); + + assert_eq!(Balances::reserved_balance_named(&id_2, &1), 15); + assert_eq!(Balances::reserved_balance_named(&id_2, &2), 0); + assert_eq!(Balances::reserved_balance(&2), 0); + + assert_eq!(Balances::repatriate_reserved_named(&id_2, &1, &2, 10, Free).unwrap(), 0); + assert_eq!(Balances::reserved_balance_named(&id_2, &1), 5); + assert_eq!(Balances::reserved_balance_named(&id_2, &2), 0); + assert_eq!(Balances::free_balance(&2), 110); + + // repatriate_reserved_named to self + + assert_eq!(Balances::repatriate_reserved_named(&id_2, &1, &1, 10, Reserved).unwrap(), 5); + assert_eq!(Balances::reserved_balance_named(&id_2, &1), 5); + + assert_eq!(Balances::free_balance(&1), 47); + + assert_eq!(Balances::repatriate_reserved_named(&id_2, &1, &1, 15, Free).unwrap(), 10); + assert_eq!(Balances::reserved_balance_named(&id_2, &1), 0); + + assert_eq!(Balances::free_balance(&1), 52); + }); +} + +#[test] +fn reserved_named_to_yourself_should_work() { + ExtBuilder::default().build_and_execute_with(|| { + let _ = Balances::deposit_creating(&1, 110); + + let id = TestId::Foo; + + assert_ok!(Balances::reserve_named(&id, &1, 50)); + assert_ok!(Balances::repatriate_reserved_named(&id, &1, &1, 50, 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, 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() { + ExtBuilder::default().build_and_execute_with(|| { + let _ = Balances::deposit_creating(&1, 111); + + let id = TestId::Foo; + + assert_ok!(Balances::ensure_reserved_named(&id, &1, 15)); + assert_eq!(Balances::reserved_balance_named(&id, &1), 15); + + assert_ok!(Balances::ensure_reserved_named(&id, &1, 10)); + assert_eq!(Balances::reserved_balance_named(&id, &1), 10); + + assert_ok!(Balances::ensure_reserved_named(&id, &1, 20)); + assert_eq!(Balances::reserved_balance_named(&id, &1), 20); + }); +} + +#[test] +fn unreserve_all_named_should_work() { + ExtBuilder::default().build_and_execute_with(|| { + let _ = Balances::deposit_creating(&1, 111); + + let id = TestId::Foo; + + assert_ok!(Balances::reserve_named(&id, &1, 15)); + + assert_eq!(Balances::unreserve_all_named(&id, &1), 15); + assert_eq!(Balances::reserved_balance_named(&id, &1), 0); + assert_eq!(Balances::free_balance(&1), 111); + + assert_eq!(Balances::unreserve_all_named(&id, &1), 0); + }); +} + +#[test] +fn slash_all_reserved_named_should_work() { + ExtBuilder::default().build_and_execute_with(|| { + let _ = Balances::deposit_creating(&1, 111); + + let id = TestId::Foo; + + assert_ok!(Balances::reserve_named(&id, &1, 15)); + + assert_eq!(Balances::slash_all_reserved_named(&id, &1).peek(), 15); + assert_eq!(Balances::reserved_balance_named(&id, &1), 0); + assert_eq!(Balances::free_balance(&1), 96); + + assert_eq!(Balances::slash_all_reserved_named(&id, &1).peek(), 0); + }); +} + +#[test] +fn repatriate_all_reserved_named_should_work() { + ExtBuilder::default().build_and_execute_with(|| { + let _ = Balances::deposit_creating(&1, 111); + let _ = Balances::deposit_creating(&2, 10); + let _ = Balances::deposit_creating(&3, 10); + + let id = TestId::Foo; + + assert_ok!(Balances::reserve_named(&id, &1, 15)); + + assert_ok!(Balances::repatriate_all_reserved_named(&id, &1, &2, Reserved)); + assert_eq!(Balances::reserved_balance_named(&id, &1), 0); + assert_eq!(Balances::reserved_balance_named(&id, &2), 15); + + assert_ok!(Balances::repatriate_all_reserved_named(&id, &2, &3, Free)); + assert_eq!(Balances::reserved_balance_named(&id, &2), 0); + assert_eq!(Balances::free_balance(&3), 25); + }); +} + +#[test] +fn freezing_and_locking_should_work() { + ExtBuilder::default() + .existential_deposit(1) + .monied(true) + .build_and_execute_with(|| { + assert_ok!(>::set_freeze(&TestId::Foo, &1, 4)); + Balances::set_lock(ID_1, &1, 5, WithdrawReasons::all()); + assert_eq!(System::consumers(&1), 2); + assert_eq!(Balances::account(&1).frozen, 5); + assert_ok!(>::set_freeze(&TestId::Foo, &1, 6)); + assert_eq!(Balances::account(&1).frozen, 6); + assert_ok!(>::set_freeze(&TestId::Foo, &1, 4)); + assert_eq!(Balances::account(&1).frozen, 5); + Balances::set_lock(ID_1, &1, 3, WithdrawReasons::all()); + assert_eq!(Balances::account(&1).frozen, 4); + Balances::set_lock(ID_1, &1, 5, WithdrawReasons::all()); + assert_eq!(Balances::account(&1).frozen, 5); + Balances::remove_lock(ID_1, &1); + assert_eq!(Balances::account(&1).frozen, 4); + assert_eq!(System::consumers(&1), 1); + }); +} diff --git a/frame/balances/src/tests/dispatchable_tests.rs b/frame/balances/src/tests/dispatchable_tests.rs new file mode 100644 index 0000000000000..76d0961e577d2 --- /dev/null +++ b/frame/balances/src/tests/dispatchable_tests.rs @@ -0,0 +1,224 @@ +// 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. + +//! Tests regarding the functionality of the dispatchables/extrinsics. + +use super::*; +use frame_support::traits::tokens::Preservation::Expendable; +use fungible::{hold::Mutate as HoldMutate, Inspect, Mutate}; + +#[test] +fn default_indexing_on_new_accounts_should_not_work2() { + ExtBuilder::default() + .existential_deposit(10) + .monied(true) + .build_and_execute_with(|| { + // account 5 should not exist + // ext_deposit is 10, value is 9, not satisfies for ext_deposit + assert_noop!( + Balances::transfer_allow_death(Some(1).into(), 5, 9), + TokenError::BelowMinimum, + ); + assert_eq!(Balances::free_balance(1), 100); + }); +} + +#[test] +fn dust_account_removal_should_work() { + ExtBuilder::default() + .existential_deposit(100) + .monied(true) + .build_and_execute_with(|| { + System::inc_account_nonce(&2); + assert_eq!(System::account_nonce(&2), 1); + assert_eq!(Balances::total_balance(&2), 2000); + // index 1 (account 2) becomes zombie + assert_ok!(Balances::transfer_allow_death(Some(2).into(), 5, 1901)); + assert_eq!(Balances::total_balance(&2), 0); + assert_eq!(Balances::total_balance(&5), 1901); + assert_eq!(System::account_nonce(&2), 0); + }); +} + +#[test] +fn balance_transfer_works() { + ExtBuilder::default().build_and_execute_with(|| { + let _ = Balances::mint_into(&1, 111); + assert_ok!(Balances::transfer_allow_death(Some(1).into(), 2, 69)); + assert_eq!(Balances::total_balance(&1), 42); + assert_eq!(Balances::total_balance(&2), 69); + }); +} + +#[test] +fn force_transfer_works() { + ExtBuilder::default().build_and_execute_with(|| { + let _ = Balances::mint_into(&1, 111); + assert_noop!(Balances::force_transfer(Some(2).into(), 1, 2, 69), BadOrigin,); + assert_ok!(Balances::force_transfer(RawOrigin::Root.into(), 1, 2, 69)); + assert_eq!(Balances::total_balance(&1), 42); + assert_eq!(Balances::total_balance(&2), 69); + }); +} + +#[test] +fn balance_transfer_when_on_hold_should_not_work() { + ExtBuilder::default().build_and_execute_with(|| { + let _ = Balances::mint_into(&1, 111); + assert_ok!(Balances::hold(&TestId::Foo, &1, 69)); + assert_noop!( + Balances::transfer_allow_death(Some(1).into(), 2, 69), + TokenError::FundsUnavailable, + ); + }); +} + +#[test] +fn transfer_keep_alive_works() { + ExtBuilder::default().existential_deposit(1).build_and_execute_with(|| { + let _ = Balances::mint_into(&1, 100); + assert_noop!( + Balances::transfer_keep_alive(Some(1).into(), 2, 100), + TokenError::NotExpendable + ); + assert_eq!(Balances::total_balance(&1), 100); + assert_eq!(Balances::total_balance(&2), 0); + }); +} + +#[test] +fn transfer_keep_alive_all_free_succeed() { + ExtBuilder::default().existential_deposit(100).build_and_execute_with(|| { + assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), 1, 300)); + assert_ok!(Balances::hold(&TestId::Foo, &1, 100)); + assert_ok!(Balances::transfer_keep_alive(Some(1).into(), 2, 100)); + assert_eq!(Balances::total_balance(&1), 200); + assert_eq!(Balances::total_balance(&2), 100); + }); +} + +#[test] +fn transfer_all_works_1() { + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + // setup + assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), 1, 200)); + assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), 2, 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); + }); +} + +#[test] +fn transfer_all_works_2() { + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + // setup + assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), 1, 200)); + assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), 2, 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); + }); +} + +#[test] +fn transfer_all_works_3() { + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + // setup + assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), 1, 210)); + assert_ok!(Balances::hold(&TestId::Foo, &1, 10)); + assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), 2, 0)); + // transfer all and allow death w/ reserved + assert_ok!(Balances::transfer_all(Some(1).into(), 2, false)); + assert_eq!(Balances::total_balance(&1), 110); + assert_eq!(Balances::total_balance(&2), 100); + }); +} + +#[test] +fn transfer_all_works_4() { + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + // setup + assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), 1, 210)); + assert_ok!(Balances::hold(&TestId::Foo, &1, 10)); + assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), 2, 0)); + // transfer all and keep alive w/ reserved + assert_ok!(Balances::transfer_all(Some(1).into(), 2, true)); + assert_eq!(Balances::total_balance(&1), 110); + assert_eq!(Balances::total_balance(&2), 100); + }); +} + +#[test] +fn set_balance_handles_killing_account() { + ExtBuilder::default().build_and_execute_with(|| { + let _ = Balances::mint_into(&1, 111); + assert_ok!(frame_system::Pallet::::inc_consumers(&1)); + assert_noop!( + Balances::force_set_balance(RuntimeOrigin::root(), 1, 0), + DispatchError::ConsumerRemaining, + ); + }); +} + +#[test] +fn set_balance_handles_total_issuance() { + ExtBuilder::default().build_and_execute_with(|| { + let old_total_issuance = Balances::total_issuance(); + assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), 1337, 69)); + assert_eq!(Balances::total_issuance(), old_total_issuance + 69); + assert_eq!(Balances::total_balance(&1337), 69); + assert_eq!(Balances::free_balance(&1337), 69); + }); +} + +#[test] +fn upgrade_accounts_should_work() { + ExtBuilder::default() + .existential_deposit(1) + .monied(true) + .build_and_execute_with(|| { + System::inc_providers(&7); + assert_ok!(::AccountStore::try_mutate_exists( + &7, + |a| -> DispatchResult { + *a = Some(AccountData { + free: 5, + reserved: 5, + frozen: Zero::zero(), + flags: crate::types::ExtraFlags::old_logic(), + }); + Ok(()) + } + )); + assert!(!Balances::account(&7).flags.is_new_logic()); + assert_eq!(System::providers(&7), 1); + assert_eq!(System::consumers(&7), 0); + assert_ok!(Balances::upgrade_accounts(Some(1).into(), vec![7])); + assert!(Balances::account(&7).flags.is_new_logic()); + assert_eq!(System::providers(&7), 1); + assert_eq!(System::consumers(&7), 1); + + >::unreserve(&7, 5); + assert_ok!(>::transfer(&7, &1, 10, Expendable)); + assert_eq!(Balances::total_balance(&7), 0); + assert_eq!(System::providers(&7), 0); + assert_eq!(System::consumers(&7), 0); + }); +} diff --git a/frame/balances/src/tests/fungible_tests.rs b/frame/balances/src/tests/fungible_tests.rs new file mode 100644 index 0000000000000..128086885391f --- /dev/null +++ b/frame/balances/src/tests/fungible_tests.rs @@ -0,0 +1,399 @@ +// 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. + +//! Tests regarding the functionality of the `fungible` trait set implementations. + +use super::*; +use frame_support::traits::tokens::{ + Fortitude::{Force, Polite}, + Precision::{BestEffort, Exact}, + Preservation::{Expendable, Preserve, Protect}, + Restriction::Free, +}; +use fungible::{Inspect, InspectFreeze, InspectHold, Mutate, MutateFreeze, MutateHold, Unbalanced}; + +#[test] +fn inspect_trait_reducible_balance_basic_works() { + ExtBuilder::default().existential_deposit(10).build_and_execute_with(|| { + Balances::set_balance(&1, 100); + assert_eq!(Balances::reducible_balance(&1, Expendable, Polite), 100); + assert_eq!(Balances::reducible_balance(&1, Protect, Polite), 90); + assert_eq!(Balances::reducible_balance(&1, Preserve, Polite), 90); + assert_eq!(Balances::reducible_balance(&1, Expendable, Force), 100); + assert_eq!(Balances::reducible_balance(&1, Protect, Force), 90); + assert_eq!(Balances::reducible_balance(&1, Preserve, Force), 90); + }); +} + +#[test] +fn inspect_trait_reducible_balance_other_provide_works() { + ExtBuilder::default().existential_deposit(10).build_and_execute_with(|| { + Balances::set_balance(&1, 100); + System::inc_providers(&1); + assert_eq!(Balances::reducible_balance(&1, Expendable, Polite), 100); + assert_eq!(Balances::reducible_balance(&1, Protect, Polite), 100); + assert_eq!(Balances::reducible_balance(&1, Preserve, Polite), 90); + assert_eq!(Balances::reducible_balance(&1, Expendable, Force), 100); + assert_eq!(Balances::reducible_balance(&1, Protect, Force), 100); + assert_eq!(Balances::reducible_balance(&1, Preserve, Force), 90); + }); +} + +#[test] +fn inspect_trait_reducible_balance_frozen_works() { + ExtBuilder::default().existential_deposit(10).build_and_execute_with(|| { + Balances::set_balance(&1, 100); + assert_ok!(Balances::set_freeze(&TestId::Foo, &1, 50)); + assert_eq!(Balances::reducible_balance(&1, Expendable, Polite), 50); + assert_eq!(Balances::reducible_balance(&1, Protect, Polite), 50); + assert_eq!(Balances::reducible_balance(&1, Preserve, Polite), 50); + assert_eq!(Balances::reducible_balance(&1, Expendable, Force), 90); + assert_eq!(Balances::reducible_balance(&1, Protect, Force), 90); + assert_eq!(Balances::reducible_balance(&1, Preserve, Force), 90); + }); +} + +#[test] +fn unbalanced_trait_set_balance_works() { + ExtBuilder::default().build_and_execute_with(|| { + assert_eq!(>::balance(&1337), 0); + assert_ok!(Balances::write_balance(&1337, 100)); + assert_eq!(>::balance(&1337), 100); + + assert_ok!(>::hold(&TestId::Foo, &1337, 60)); + assert_eq!(>::balance(&1337), 40); + assert_eq!(>::total_balance_on_hold(&1337), 60); + assert_eq!( + >::balance_on_hold(&TestId::Foo, &1337), + 60 + ); + + assert_noop!(Balances::write_balance(&1337, 0), Error::::InsufficientBalance); + + assert_ok!(Balances::write_balance(&1337, 1)); + assert_eq!(>::balance(&1337), 1); + assert_eq!( + >::balance_on_hold(&TestId::Foo, &1337), + 60 + ); + + assert_ok!(>::release(&TestId::Foo, &1337, 60, Exact)); + assert_eq!(>::balance_on_hold(&TestId::Foo, &1337), 0); + assert_eq!(>::total_balance_on_hold(&1337), 0); + }); +} + +#[test] +fn unbalanced_trait_set_total_issuance_works() { + ExtBuilder::default().build_and_execute_with(|| { + assert_eq!(>::total_issuance(), 0); + Balances::set_total_issuance(100); + assert_eq!(>::total_issuance(), 100); + }); +} + +#[test] +fn unbalanced_trait_decrease_balance_simple_works() { + ExtBuilder::default().build_and_execute_with(|| { + // An Account that starts at 100 + assert_ok!(Balances::write_balance(&1337, 100)); + assert_eq!(>::balance(&1337), 100); + // and reserves 50 + assert_ok!(>::hold(&TestId::Foo, &1337, 50)); + assert_eq!(>::balance(&1337), 50); + // and is decreased by 20 + assert_ok!(Balances::decrease_balance(&1337, 20, Exact, Expendable, Polite)); + assert_eq!(>::balance(&1337), 30); + }); +} + +#[test] +fn unbalanced_trait_decrease_balance_works_1() { + ExtBuilder::default().build_and_execute_with(|| { + assert_ok!(Balances::write_balance(&1337, 100)); + assert_eq!(>::balance(&1337), 100); + + assert_noop!( + Balances::decrease_balance(&1337, 101, Exact, Expendable, Polite), + TokenError::FundsUnavailable + ); + assert_eq!(Balances::decrease_balance(&1337, 100, Exact, Expendable, Polite), Ok(100)); + assert_eq!(>::balance(&1337), 0); + }); +} + +#[test] +fn unbalanced_trait_decrease_balance_works_2() { + ExtBuilder::default().build_and_execute_with(|| { + // free: 40, reserved: 60 + assert_ok!(Balances::write_balance(&1337, 100)); + assert_ok!(Balances::hold(&TestId::Foo, &1337, 60)); + assert_eq!(>::balance(&1337), 40); + assert_eq!(Balances::total_balance_on_hold(&1337), 60); + assert_noop!( + Balances::decrease_balance(&1337, 40, Exact, Expendable, Polite), + Error::::InsufficientBalance + ); + assert_eq!(Balances::decrease_balance(&1337, 39, Exact, Expendable, Polite), Ok(39)); + assert_eq!(>::balance(&1337), 1); + assert_eq!(Balances::total_balance_on_hold(&1337), 60); + }); +} + +#[test] +fn unbalanced_trait_decrease_balance_at_most_works_1() { + ExtBuilder::default().build_and_execute_with(|| { + assert_ok!(Balances::write_balance(&1337, 100)); + assert_eq!(>::balance(&1337), 100); + + assert_eq!(Balances::decrease_balance(&1337, 101, BestEffort, Expendable, Polite), Ok(100)); + assert_eq!(>::balance(&1337), 0); + }); +} + +#[test] +fn unbalanced_trait_decrease_balance_at_most_works_2() { + ExtBuilder::default().build_and_execute_with(|| { + assert_ok!(Balances::write_balance(&1337, 99)); + assert_eq!(Balances::decrease_balance(&1337, 99, BestEffort, Expendable, Polite), Ok(99)); + assert_eq!(>::balance(&1337), 0); + }); +} + +#[test] +fn unbalanced_trait_decrease_balance_at_most_works_3() { + ExtBuilder::default().build_and_execute_with(|| { + // free: 40, reserved: 60 + assert_ok!(Balances::write_balance(&1337, 100)); + assert_ok!(Balances::hold(&TestId::Foo, &1337, 60)); + assert_eq!(Balances::free_balance(1337), 40); + assert_eq!(Balances::total_balance_on_hold(&1337), 60); + assert_eq!(Balances::decrease_balance(&1337, 0, BestEffort, Expendable, Polite), Ok(0)); + assert_eq!(Balances::free_balance(1337), 40); + assert_eq!(Balances::total_balance_on_hold(&1337), 60); + assert_eq!(Balances::decrease_balance(&1337, 10, BestEffort, Expendable, Polite), Ok(10)); + assert_eq!(Balances::free_balance(1337), 30); + assert_eq!(Balances::decrease_balance(&1337, 200, BestEffort, Expendable, Polite), Ok(29)); + assert_eq!(>::balance(&1337), 1); + assert_eq!(Balances::free_balance(1337), 1); + assert_eq!(Balances::total_balance_on_hold(&1337), 60); + }); +} + +#[test] +fn unbalanced_trait_increase_balance_works() { + ExtBuilder::default().build_and_execute_with(|| { + assert_noop!(Balances::increase_balance(&1337, 0, Exact), TokenError::BelowMinimum); + assert_eq!(Balances::increase_balance(&1337, 1, Exact), Ok(1)); + assert_noop!(Balances::increase_balance(&1337, u64::MAX, Exact), ArithmeticError::Overflow); + }); +} + +#[test] +fn unbalanced_trait_increase_balance_at_most_works() { + ExtBuilder::default().build_and_execute_with(|| { + assert_eq!(Balances::increase_balance(&1337, 0, BestEffort), Ok(0)); + assert_eq!(Balances::increase_balance(&1337, 1, BestEffort), Ok(1)); + assert_eq!(Balances::increase_balance(&1337, u64::MAX, BestEffort), Ok(u64::MAX - 1)); + }); +} + +#[test] +fn freezing_and_holds_should_overlap() { + ExtBuilder::default() + .existential_deposit(1) + .monied(true) + .build_and_execute_with(|| { + assert_ok!(Balances::set_freeze(&TestId::Foo, &1, 10)); + assert_ok!(Balances::hold(&TestId::Foo, &1, 9)); + assert_eq!(Balances::account(&1).free, 1); + assert_eq!(System::consumers(&1), 1); + assert_eq!(Balances::account(&1).free, 1); + assert_eq!(Balances::account(&1).frozen, 10); + assert_eq!(Balances::account(&1).reserved, 9); + assert_eq!(Balances::total_balance_on_hold(&1), 9); + }); +} + +#[test] +fn frozen_hold_balance_cannot_be_moved_without_force() { + ExtBuilder::default() + .existential_deposit(1) + .monied(true) + .build_and_execute_with(|| { + assert_ok!(Balances::set_freeze(&TestId::Foo, &1, 10)); + assert_ok!(Balances::hold(&TestId::Foo, &1, 9)); + assert_eq!(Balances::reducible_total_balance_on_hold(&1, Force), 9); + assert_eq!(Balances::reducible_total_balance_on_hold(&1, Polite), 0); + let e = TokenError::Frozen; + assert_noop!( + Balances::transfer_on_hold(&TestId::Foo, &1, &2, 1, Exact, Free, Polite), + e + ); + assert_ok!(Balances::transfer_on_hold(&TestId::Foo, &1, &2, 1, Exact, Free, Force)); + }); +} + +#[test] +fn frozen_hold_balance_best_effort_transfer_works() { + ExtBuilder::default() + .existential_deposit(1) + .monied(true) + .build_and_execute_with(|| { + assert_ok!(Balances::set_freeze(&TestId::Foo, &1, 5)); + assert_ok!(Balances::hold(&TestId::Foo, &1, 9)); + assert_eq!(Balances::reducible_total_balance_on_hold(&1, Force), 9); + assert_eq!(Balances::reducible_total_balance_on_hold(&1, Polite), 5); + assert_ok!(Balances::transfer_on_hold( + &TestId::Foo, + &1, + &2, + 10, + BestEffort, + Free, + Polite + )); + assert_eq!(Balances::total_balance(&1), 5); + assert_eq!(Balances::total_balance(&2), 25); + }); +} + +#[test] +fn partial_freezing_should_work() { + ExtBuilder::default() + .existential_deposit(1) + .monied(true) + .build_and_execute_with(|| { + assert_ok!(Balances::set_freeze(&TestId::Foo, &1, 5)); + assert_eq!(System::consumers(&1), 1); + assert_ok!(>::transfer(&1, &2, 5, Expendable)); + assert_noop!( + >::transfer(&1, &2, 1, Expendable), + TokenError::Frozen + ); + }); +} + +#[test] +fn thaw_should_work() { + ExtBuilder::default() + .existential_deposit(1) + .monied(true) + .build_and_execute_with(|| { + assert_ok!(Balances::set_freeze(&TestId::Foo, &1, u64::MAX)); + assert_ok!(Balances::thaw(&TestId::Foo, &1)); + assert_eq!(System::consumers(&1), 0); + assert_eq!(Balances::balance_frozen(&TestId::Foo, &1), 0); + assert_eq!(Balances::account(&1).frozen, 0); + assert_ok!(>::transfer(&1, &2, 10, Expendable)); + }); +} + +#[test] +fn set_freeze_zero_should_work() { + ExtBuilder::default() + .existential_deposit(1) + .monied(true) + .build_and_execute_with(|| { + assert_ok!(Balances::set_freeze(&TestId::Foo, &1, u64::MAX)); + assert_ok!(Balances::set_freeze(&TestId::Foo, &1, 0)); + assert_eq!(System::consumers(&1), 0); + assert_eq!(Balances::balance_frozen(&TestId::Foo, &1), 0); + assert_eq!(Balances::account(&1).frozen, 0); + assert_ok!(>::transfer(&1, &2, 10, Expendable)); + }); +} + +#[test] +fn set_freeze_should_work() { + ExtBuilder::default() + .existential_deposit(1) + .monied(true) + .build_and_execute_with(|| { + assert_ok!(Balances::set_freeze(&TestId::Foo, &1, u64::MAX)); + assert_ok!(Balances::set_freeze(&TestId::Foo, &1, 5)); + assert_ok!(>::transfer(&1, &2, 5, Expendable)); + assert_noop!( + >::transfer(&1, &2, 1, Expendable), + TokenError::Frozen + ); + }); +} + +#[test] +fn extend_freeze_should_work() { + ExtBuilder::default() + .existential_deposit(1) + .monied(true) + .build_and_execute_with(|| { + assert_ok!(Balances::set_freeze(&TestId::Foo, &1, 5)); + assert_ok!(Balances::extend_freeze(&TestId::Foo, &1, 10)); + assert_eq!(Balances::account(&1).frozen, 10); + assert_eq!(Balances::balance_frozen(&TestId::Foo, &1), 10); + assert_noop!( + >::transfer(&1, &2, 1, Expendable), + TokenError::Frozen + ); + }); +} + +#[test] +fn double_freezing_should_work() { + ExtBuilder::default() + .existential_deposit(1) + .monied(true) + .build_and_execute_with(|| { + assert_ok!(Balances::set_freeze(&TestId::Foo, &1, 5)); + assert_ok!(Balances::set_freeze(&TestId::Bar, &1, 5)); + assert_eq!(System::consumers(&1), 1); + assert_ok!(>::transfer(&1, &2, 5, Expendable)); + assert_noop!( + >::transfer(&1, &2, 1, Expendable), + TokenError::Frozen + ); + }); +} + +#[test] +fn can_hold_entire_balance_when_second_provider() { + ExtBuilder::default() + .existential_deposit(1) + .monied(false) + .build_and_execute_with(|| { + >::set_balance(&1, 100); + assert_noop!(Balances::hold(&TestId::Foo, &1, 100), TokenError::FundsUnavailable); + System::inc_providers(&1); + assert_eq!(System::providers(&1), 2); + assert_ok!(Balances::hold(&TestId::Foo, &1, 100)); + assert_eq!(System::providers(&1), 1); + assert_noop!(System::dec_providers(&1), DispatchError::ConsumerRemaining); + }); +} + +#[test] +fn unholding_frees_hold_slot() { + ExtBuilder::default() + .existential_deposit(1) + .monied(false) + .build_and_execute_with(|| { + >::set_balance(&1, 100); + assert_ok!(Balances::hold(&TestId::Foo, &1, 10)); + assert_ok!(Balances::hold(&TestId::Bar, &1, 10)); + assert_ok!(Balances::release(&TestId::Foo, &1, 10, Exact)); + assert_ok!(Balances::hold(&TestId::Baz, &1, 10)); + }); +} diff --git a/frame/balances/src/tests/mod.rs b/frame/balances/src/tests/mod.rs new file mode 100644 index 0000000000000..c4a8a631cad20 --- /dev/null +++ b/frame/balances/src/tests/mod.rs @@ -0,0 +1,296 @@ +// 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. + +//! Tests. + +#![cfg(test)] + +use crate::{self as pallet_balances, AccountData, Config, CreditOf, Error, Pallet}; +use codec::{Decode, Encode, MaxEncodedLen}; +use frame_support::{ + assert_err, assert_noop, assert_ok, assert_storage_noop, + dispatch::DispatchInfo, + parameter_types, + traits::{ + tokens::fungible, ConstU32, ConstU64, ConstU8, Imbalance as ImbalanceT, OnUnbalanced, + StorageMapShim, StoredMap, + }, + weights::{IdentityFee, Weight}, + RuntimeDebug, +}; +use frame_system::{self as system, RawOrigin}; +use pallet_transaction_payment::{ChargeTransactionPayment, CurrencyAdapter, Multiplier}; +use scale_info::TypeInfo; +use sp_core::H256; +use sp_io; +use sp_runtime::{ + testing::Header, + traits::{BadOrigin, IdentityLookup, SignedExtension, Zero}, + ArithmeticError, DispatchError, DispatchResult, FixedPointNumber, TokenError, +}; + +mod currency_tests; +mod dispatchable_tests; +mod fungible_tests; +mod reentrancy_tests; + +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +type Block = frame_system::mocking::MockBlock; + +#[derive( + Encode, + Decode, + Copy, + Clone, + Eq, + PartialEq, + Ord, + PartialOrd, + MaxEncodedLen, + TypeInfo, + RuntimeDebug, +)] +pub enum TestId { + Foo, + Bar, + Baz, +} + +frame_support::construct_runtime!( + pub struct Test where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system::{Pallet, Call, Config, Storage, Event}, + Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, + TransactionPayment: pallet_transaction_payment::{Pallet, Storage, Event}, + } +); + +parameter_types! { + pub BlockWeights: frame_system::limits::BlockWeights = + frame_system::limits::BlockWeights::simple_max( + frame_support::weights::Weight::from_parts(1024, u64::MAX), + ); + pub static ExistentialDeposit: u64 = 0; +} +impl frame_system::Config for Test { + type BaseCallFilter = frame_support::traits::Everything; + type BlockWeights = BlockWeights; + type BlockLength = (); + type DbWeight = (); + type RuntimeOrigin = RuntimeOrigin; + type Index = u64; + type BlockNumber = u64; + type RuntimeCall = RuntimeCall; + type Hash = H256; + type Hashing = ::sp_runtime::traits::BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup; + type Header = Header; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = ConstU64<250>; + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = super::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; +} + +impl pallet_transaction_payment::Config for Test { + type RuntimeEvent = RuntimeEvent; + type OnChargeTransaction = CurrencyAdapter, ()>; + type OperationalFeeMultiplier = ConstU8<5>; + type WeightToFee = IdentityFee; + type LengthToFee = IdentityFee; + type FeeMultiplierUpdate = (); +} + +impl Config for Test { + type Balance = u64; + type DustRemoval = DustTrap; + type RuntimeEvent = RuntimeEvent; + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = TestAccountStore; + type MaxLocks = ConstU32<50>; + type MaxReserves = ConstU32<2>; + type ReserveIdentifier = TestId; + type WeightInfo = (); + type HoldIdentifier = TestId; + type FreezeIdentifier = TestId; + type MaxFreezes = ConstU32<2>; + type MaxHolds = ConstU32<2>; +} + +#[derive(Clone)] +pub struct ExtBuilder { + existential_deposit: u64, + monied: bool, + dust_trap: Option, +} +impl Default for ExtBuilder { + fn default() -> Self { + Self { existential_deposit: 1, monied: false, dust_trap: None } + } +} +impl ExtBuilder { + pub fn existential_deposit(mut self, existential_deposit: u64) -> Self { + self.existential_deposit = existential_deposit; + self + } + pub fn monied(mut self, monied: bool) -> Self { + self.monied = monied; + if self.existential_deposit == 0 { + self.existential_deposit = 1; + } + self + } + pub fn dust_trap(mut self, account: u64) -> Self { + self.dust_trap = Some(account); + self + } + pub fn set_associated_consts(&self) { + DUST_TRAP_TARGET.with(|v| v.replace(self.dust_trap)); + EXISTENTIAL_DEPOSIT.with(|v| v.replace(self.existential_deposit)); + } + pub fn build(self) -> sp_io::TestExternalities { + self.set_associated_consts(); + let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); + pallet_balances::GenesisConfig:: { + balances: if self.monied { + vec![ + (1, 10 * self.existential_deposit), + (2, 20 * self.existential_deposit), + (3, 30 * self.existential_deposit), + (4, 40 * self.existential_deposit), + (12, 10 * self.existential_deposit), + ] + } else { + vec![] + }, + } + .assimilate_storage(&mut t) + .unwrap(); + + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| System::set_block_number(1)); + ext + } + pub fn build_and_execute_with(self, f: impl Fn()) { + let other = self.clone(); + UseSystem::set(false); + other.build().execute_with(|| f()); + UseSystem::set(true); + self.build().execute_with(|| f()); + } +} + +parameter_types! { + static DustTrapTarget: Option = None; +} + +pub struct DustTrap; + +impl OnUnbalanced> for DustTrap { + fn on_nonzero_unbalanced(amount: CreditOf) { + match DustTrapTarget::get() { + None => drop(amount), + Some(a) => { + let result = >::resolve(&a, amount); + debug_assert!(result.is_ok()); + }, + } + } +} + +parameter_types! { + pub static UseSystem: bool = false; +} + +type BalancesAccountStore = StorageMapShim, u64, super::AccountData>; +type SystemAccountStore = frame_system::Pallet; + +pub struct TestAccountStore; +impl StoredMap> for TestAccountStore { + fn get(k: &u64) -> super::AccountData { + if UseSystem::get() { + >::get(k) + } else { + >::get(k) + } + } + fn try_mutate_exists>( + k: &u64, + f: impl FnOnce(&mut Option>) -> Result, + ) -> Result { + if UseSystem::get() { + >::try_mutate_exists(k, f) + } else { + >::try_mutate_exists(k, f) + } + } + fn mutate( + k: &u64, + f: impl FnOnce(&mut super::AccountData) -> R, + ) -> Result { + if UseSystem::get() { + >::mutate(k, f) + } else { + >::mutate(k, f) + } + } + fn mutate_exists( + k: &u64, + f: impl FnOnce(&mut Option>) -> R, + ) -> Result { + if UseSystem::get() { + >::mutate_exists(k, f) + } else { + >::mutate_exists(k, f) + } + } + fn insert(k: &u64, t: super::AccountData) -> Result<(), DispatchError> { + if UseSystem::get() { + >::insert(k, t) + } else { + >::insert(k, t) + } + } + fn remove(k: &u64) -> Result<(), DispatchError> { + if UseSystem::get() { + >::remove(k) + } else { + >::remove(k) + } + } +} + +pub fn events() -> Vec { + let evt = System::events().into_iter().map(|evt| evt.event).collect::>(); + System::reset_events(); + evt +} + +/// 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() } +} diff --git a/frame/balances/src/tests/reentrancy_tests.rs b/frame/balances/src/tests/reentrancy_tests.rs new file mode 100644 index 0000000000000..e97bf2ed2b706 --- /dev/null +++ b/frame/balances/src/tests/reentrancy_tests.rs @@ -0,0 +1,195 @@ +// 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. + +//! Tests regarding the reentrancy functionality. + +use super::*; +use frame_support::traits::tokens::{ + Fortitude::Force, + Precision::BestEffort, + Preservation::{Expendable, Protect}, +}; +use fungible::Balanced; + +#[test] +fn transfer_dust_removal_tst1_should_work() { + ExtBuilder::default() + .existential_deposit(100) + .dust_trap(1) + .build_and_execute_with(|| { + // Verification of reentrancy in dust removal + assert_ok!(Balances::force_set_balance(RawOrigin::Root.into(), 1, 1000)); + assert_ok!(Balances::force_set_balance(RawOrigin::Root.into(), 2, 500)); + + // In this transaction, account 2 free balance + // drops below existential balance + // and dust balance is removed from account 2 + assert_ok!(Balances::transfer_allow_death(RawOrigin::Signed(2).into(), 3, 450)); + + // As expected dust balance is removed. + assert_eq!(Balances::free_balance(&2), 0); + + // As expected beneficiary account 3 + // received the transfered fund. + assert_eq!(Balances::free_balance(&3), 450); + + // Dust balance is deposited to account 1 + // during the process of dust removal. + assert_eq!(Balances::free_balance(&1), 1050); + + // Verify the events + assert_eq!(System::events().len(), 12); + + System::assert_has_event(RuntimeEvent::Balances(crate::Event::Transfer { + from: 2, + to: 3, + amount: 450, + })); + System::assert_has_event(RuntimeEvent::Balances(crate::Event::DustLost { + account: 2, + amount: 50, + })); + System::assert_has_event(RuntimeEvent::Balances(crate::Event::Deposit { + who: 1, + amount: 50, + })); + }); +} + +#[test] +fn transfer_dust_removal_tst2_should_work() { + ExtBuilder::default() + .existential_deposit(100) + .dust_trap(1) + .build_and_execute_with(|| { + // Verification of reentrancy in dust removal + assert_ok!(Balances::force_set_balance(RawOrigin::Root.into(), 1, 1000)); + assert_ok!(Balances::force_set_balance(RawOrigin::Root.into(), 2, 500)); + + // In this transaction, account 2 free balance + // drops below existential balance + // and dust balance is removed from account 2 + assert_ok!(Balances::transfer_allow_death(RawOrigin::Signed(2).into(), 1, 450)); + + // As expected dust balance is removed. + assert_eq!(Balances::free_balance(&2), 0); + + // Dust balance is deposited to account 1 + // during the process of dust removal. + assert_eq!(Balances::free_balance(&1), 1500); + + // Verify the events + assert_eq!(System::events().len(), 10); + + System::assert_has_event(RuntimeEvent::Balances(crate::Event::Transfer { + from: 2, + to: 1, + amount: 450, + })); + System::assert_has_event(RuntimeEvent::Balances(crate::Event::DustLost { + account: 2, + amount: 50, + })); + System::assert_has_event(RuntimeEvent::Balances(crate::Event::Deposit { + who: 1, + amount: 50, + })); + }); +} + +#[test] +fn repatriating_reserved_balance_dust_removal_should_work() { + ExtBuilder::default() + .existential_deposit(100) + .dust_trap(1) + .build_and_execute_with(|| { + // Verification of reentrancy in dust removal + assert_ok!(Balances::force_set_balance(RawOrigin::Root.into(), 1, 1000)); + assert_ok!(Balances::force_set_balance(RawOrigin::Root.into(), 2, 500)); + + // Reserve a value on account 2, + // Such that free balance is lower than + // Exestintial deposit. + assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(2), 1, 450)); + + // Since free balance of account 2 is lower than + // existential deposit, dust amount is + // removed from the account 2 + assert_eq!(Balances::reserved_balance(2), 0); + assert_eq!(Balances::free_balance(2), 0); + + // account 1 is credited with reserved amount + // together with dust balance during dust + // removal. + assert_eq!(Balances::reserved_balance(1), 0); + assert_eq!(Balances::free_balance(1), 1500); + + // Verify the events + assert_eq!(System::events().len(), 10); + + System::assert_has_event(RuntimeEvent::Balances(crate::Event::Transfer { + from: 2, + to: 1, + amount: 450, + })); + System::assert_has_event(RuntimeEvent::Balances(crate::Event::DustLost { + account: 2, + amount: 50, + })); + System::assert_has_event(RuntimeEvent::Balances(crate::Event::Deposit { + who: 1, + amount: 50, + })); + }); +} + +#[test] +fn emit_events_with_no_existential_deposit_suicide_with_dust() { + ExtBuilder::default().existential_deposit(2).build_and_execute_with(|| { + assert_ok!(Balances::force_set_balance(RawOrigin::Root.into(), 1, 100)); + + assert_eq!( + events(), + [ + 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 }), + ] + ); + + let res = Balances::withdraw(&1, 98, BestEffort, Protect, Force); + assert_eq!(res.unwrap().peek(), 98); + + // no events + assert_eq!( + events(), + [RuntimeEvent::Balances(crate::Event::Withdraw { who: 1, amount: 98 })] + ); + + let res = Balances::withdraw(&1, 1, BestEffort, Expendable, Force); + assert_eq!(res.unwrap().peek(), 1); + + assert_eq!( + events(), + [ + RuntimeEvent::System(system::Event::KilledAccount { account: 1 }), + RuntimeEvent::Balances(crate::Event::DustLost { account: 1, amount: 1 }), + RuntimeEvent::Balances(crate::Event::Withdraw { who: 1, amount: 1 }) + ] + ); + }); +} diff --git a/frame/balances/src/tests_composite.rs b/frame/balances/src/tests_composite.rs deleted file mode 100644 index 765ab194d2011..0000000000000 --- a/frame/balances/src/tests_composite.rs +++ /dev/null @@ -1,149 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Test utilities - -#![cfg(test)] - -use crate::{self as pallet_balances, decl_tests, Config, Pallet}; -use frame_support::{ - dispatch::DispatchInfo, - parameter_types, - traits::{ConstU32, ConstU64, ConstU8}, - weights::{IdentityFee, Weight}, -}; -use pallet_transaction_payment::CurrencyAdapter; -use sp_core::H256; -use sp_io; -use sp_runtime::{testing::Header, traits::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}, - TransactionPayment: pallet_transaction_payment::{Pallet, Storage, Event}, - } -); - -parameter_types! { - pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max( - frame_support::weights::Weight::from_parts(1024, u64::MAX), - ); - pub static ExistentialDeposit: u64 = 0; -} -impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = BlockWeights; - type BlockLength = (); - type DbWeight = (); - type RuntimeOrigin = RuntimeOrigin; - type Index = u64; - type BlockNumber = u64; - type RuntimeCall = RuntimeCall; - type Hash = H256; - type Hashing = ::sp_runtime::traits::BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; - type Header = Header; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = super::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; -} - -impl pallet_transaction_payment::Config for Test { - type RuntimeEvent = RuntimeEvent; - type OnChargeTransaction = CurrencyAdapter, ()>; - type OperationalFeeMultiplier = ConstU8<5>; - type WeightToFee = IdentityFee; - type LengthToFee = IdentityFee; - type FeeMultiplierUpdate = (); -} - -impl Config for Test { - type Balance = u64; - type DustRemoval = (); - type RuntimeEvent = RuntimeEvent; - type ExistentialDeposit = ExistentialDeposit; - type AccountStore = frame_system::Pallet; - type MaxLocks = (); - type MaxReserves = ConstU32<2>; - type ReserveIdentifier = [u8; 8]; - type WeightInfo = (); -} - -pub struct ExtBuilder { - existential_deposit: u64, - monied: bool, -} -impl Default for ExtBuilder { - fn default() -> Self { - Self { existential_deposit: 1, monied: false } - } -} -impl ExtBuilder { - pub fn existential_deposit(mut self, existential_deposit: u64) -> Self { - self.existential_deposit = existential_deposit; - self - } - pub fn monied(mut self, monied: bool) -> Self { - self.monied = monied; - self - } - pub fn set_associated_consts(&self) { - EXISTENTIAL_DEPOSIT.with(|v| *v.borrow_mut() = self.existential_deposit); - } - pub fn build(self) -> sp_io::TestExternalities { - self.set_associated_consts(); - let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); - pallet_balances::GenesisConfig:: { - balances: if self.monied { - vec![ - (1, 10 * self.existential_deposit), - (2, 20 * self.existential_deposit), - (3, 30 * self.existential_deposit), - (4, 40 * self.existential_deposit), - (12, 10 * self.existential_deposit), - ] - } else { - vec![] - }, - } - .assimilate_storage(&mut t) - .unwrap(); - - let mut ext = sp_io::TestExternalities::new(t); - ext.execute_with(|| System::set_block_number(1)); - ext - } -} - -decl_tests! { Test, ExtBuilder, EXISTENTIAL_DEPOSIT } diff --git a/frame/balances/src/tests_local.rs b/frame/balances/src/tests_local.rs deleted file mode 100644 index 929f77b540fe1..0000000000000 --- a/frame/balances/src/tests_local.rs +++ /dev/null @@ -1,191 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Test utilities - -#![cfg(test)] - -use crate::{self as pallet_balances, decl_tests, Config, Pallet}; -use frame_support::{ - dispatch::DispatchInfo, - parameter_types, - traits::{ConstU32, ConstU64, ConstU8, StorageMapShim}, - weights::{IdentityFee, Weight}, -}; -use pallet_transaction_payment::CurrencyAdapter; -use sp_core::H256; -use sp_io; -use sp_runtime::{testing::Header, traits::IdentityLookup}; - -type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; -type Block = frame_system::mocking::MockBlock; - -frame_support::construct_runtime!( - pub struct Test where - Block = Block, - NodeBlock = Block, - UncheckedExtrinsic = UncheckedExtrinsic, - { - System: frame_system::{Pallet, Call, Config, Storage, Event}, - Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, - TransactionPayment: pallet_transaction_payment::{Pallet, Storage, Event}, - } -); - -parameter_types! { - pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max( - frame_support::weights::Weight::from_parts(1024, u64::MAX), - ); - pub static ExistentialDeposit: u64 = 0; -} -impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = BlockWeights; - type BlockLength = (); - type DbWeight = (); - type RuntimeOrigin = RuntimeOrigin; - type Index = u64; - type BlockNumber = u64; - type RuntimeCall = RuntimeCall; - type Hash = H256; - type Hashing = ::sp_runtime::traits::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 = frame_support::traits::ConstU32<16>; -} - -impl pallet_transaction_payment::Config for Test { - type RuntimeEvent = RuntimeEvent; - type OnChargeTransaction = CurrencyAdapter, ()>; - type OperationalFeeMultiplier = ConstU8<5>; - type WeightToFee = IdentityFee; - type LengthToFee = IdentityFee; - type FeeMultiplierUpdate = (); -} - -impl Config for Test { - type Balance = u64; - type DustRemoval = (); - type RuntimeEvent = RuntimeEvent; - type ExistentialDeposit = ExistentialDeposit; - type AccountStore = - StorageMapShim, system::Provider, u64, super::AccountData>; - type MaxLocks = ConstU32<50>; - type MaxReserves = ConstU32<2>; - type ReserveIdentifier = [u8; 8]; - type WeightInfo = (); -} - -pub struct ExtBuilder { - existential_deposit: u64, - monied: bool, -} -impl Default for ExtBuilder { - fn default() -> Self { - Self { existential_deposit: 1, monied: false } - } -} -impl ExtBuilder { - pub fn existential_deposit(mut self, existential_deposit: u64) -> Self { - self.existential_deposit = existential_deposit; - self - } - pub fn monied(mut self, monied: bool) -> Self { - self.monied = monied; - if self.existential_deposit == 0 { - self.existential_deposit = 1; - } - self - } - pub fn set_associated_consts(&self) { - EXISTENTIAL_DEPOSIT.with(|v| *v.borrow_mut() = self.existential_deposit); - } - pub fn build(self) -> sp_io::TestExternalities { - self.set_associated_consts(); - let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); - pallet_balances::GenesisConfig:: { - balances: if self.monied { - vec![ - (1, 10 * self.existential_deposit), - (2, 20 * self.existential_deposit), - (3, 30 * self.existential_deposit), - (4, 40 * self.existential_deposit), - (12, 10 * self.existential_deposit), - ] - } else { - vec![] - }, - } - .assimilate_storage(&mut t) - .unwrap(); - - let mut ext = sp_io::TestExternalities::new(t); - ext.execute_with(|| System::set_block_number(1)); - ext - } -} - -decl_tests! { Test, ExtBuilder, EXISTENTIAL_DEPOSIT } - -#[test] -fn emit_events_with_no_existential_deposit_suicide_with_dust() { - ::default().existential_deposit(2).build().execute_with(|| { - assert_ok!(Balances::set_balance(RawOrigin::Root.into(), 1, 100, 0)); - - assert_eq!( - events(), - [ - 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 }), - ] - ); - - let res = Balances::slash(&1, 98); - assert_eq!(res, (NegativeImbalance::new(98), 0)); - - // no events - 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)); - - assert_eq!( - events(), - [ - 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 deleted file mode 100644 index 828dfa23707d0..0000000000000 --- a/frame/balances/src/tests_reentrancy.rs +++ /dev/null @@ -1,264 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Test setup for potential reentracy and lost updates of nested mutations. - -#![cfg(test)] - -use crate::{self as pallet_balances, Config}; -use frame_support::{ - parameter_types, - traits::{ConstU32, ConstU64, StorageMapShim}, -}; -use sp_core::H256; -use sp_io; -use sp_runtime::{testing::Header, traits::IdentityLookup}; - -use crate::*; -use frame_support::{ - assert_ok, - traits::{Currency, ReservableCurrency}, -}; -use frame_system::RawOrigin; - -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}, - } -); - -parameter_types! { - pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max( - frame_support::weights::Weight::from_parts(1024, u64::MAX), - ); - pub static ExistentialDeposit: u64 = 0; -} -impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = BlockWeights; - type BlockLength = (); - type DbWeight = (); - type RuntimeOrigin = RuntimeOrigin; - type Index = u64; - type BlockNumber = u64; - type RuntimeCall = RuntimeCall; - type Hash = H256; - type Hashing = ::sp_runtime::traits::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 = frame_support::traits::ConstU32<16>; -} - -pub struct OnDustRemoval; -impl OnUnbalanced> for OnDustRemoval { - fn on_nonzero_unbalanced(amount: NegativeImbalance) { - assert_ok!(Balances::resolve_into_existing(&1, amount)); - } -} - -impl Config for Test { - type Balance = u64; - type DustRemoval = OnDustRemoval; - type RuntimeEvent = RuntimeEvent; - type ExistentialDeposit = ExistentialDeposit; - type AccountStore = - StorageMapShim, system::Provider, u64, super::AccountData>; - type MaxLocks = ConstU32<50>; - type MaxReserves = ConstU32<2>; - type ReserveIdentifier = [u8; 8]; - type WeightInfo = (); -} - -pub struct ExtBuilder { - existential_deposit: u64, -} -impl Default for ExtBuilder { - fn default() -> Self { - Self { existential_deposit: 1 } - } -} -impl ExtBuilder { - pub fn existential_deposit(mut self, existential_deposit: u64) -> Self { - self.existential_deposit = existential_deposit; - self - } - - pub fn set_associated_consts(&self) { - EXISTENTIAL_DEPOSIT.with(|v| *v.borrow_mut() = self.existential_deposit); - } - - pub fn build(self) -> sp_io::TestExternalities { - self.set_associated_consts(); - let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); - pallet_balances::GenesisConfig:: { balances: vec![] } - .assimilate_storage(&mut t) - .unwrap(); - let mut ext = sp_io::TestExternalities::new(t); - ext.execute_with(|| System::set_block_number(1)); - ext - } -} - -#[test] -fn transfer_dust_removal_tst1_should_work() { - ExtBuilder::default().existential_deposit(100).build().execute_with(|| { - // Verification of reentrancy in dust removal - assert_ok!(Balances::set_balance(RawOrigin::Root.into(), 1, 1000, 0)); - assert_ok!(Balances::set_balance(RawOrigin::Root.into(), 2, 500, 0)); - - // In this transaction, account 2 free balance - // drops below existential balance - // and dust balance is removed from account 2 - assert_ok!(Balances::transfer(RawOrigin::Signed(2).into(), 3, 450)); - - // As expected dust balance is removed. - assert_eq!(Balances::free_balance(&2), 0); - - // As expected beneficiary account 3 - // received the transfered fund. - assert_eq!(Balances::free_balance(&3), 450); - - // Dust balance is deposited to account 1 - // during the process of dust removal. - assert_eq!(Balances::free_balance(&1), 1050); - - // Verify the events - assert_eq!(System::events().len(), 12); - - System::assert_has_event(RuntimeEvent::Balances(crate::Event::Transfer { - from: 2, - to: 3, - amount: 450, - })); - System::assert_has_event(RuntimeEvent::Balances(crate::Event::DustLost { - account: 2, - amount: 50, - })); - System::assert_has_event(RuntimeEvent::Balances(crate::Event::Deposit { - who: 1, - amount: 50, - })); - }); -} - -#[test] -fn transfer_dust_removal_tst2_should_work() { - ExtBuilder::default().existential_deposit(100).build().execute_with(|| { - // Verification of reentrancy in dust removal - assert_ok!(Balances::set_balance(RawOrigin::Root.into(), 1, 1000, 0)); - assert_ok!(Balances::set_balance(RawOrigin::Root.into(), 2, 500, 0)); - - // In this transaction, account 2 free balance - // drops below existential balance - // and dust balance is removed from account 2 - assert_ok!(Balances::transfer(RawOrigin::Signed(2).into(), 1, 450)); - - // As expected dust balance is removed. - assert_eq!(Balances::free_balance(&2), 0); - - // Dust balance is deposited to account 1 - // during the process of dust removal. - assert_eq!(Balances::free_balance(&1), 1500); - - // Verify the events - assert_eq!(System::events().len(), 10); - - System::assert_has_event(RuntimeEvent::Balances(crate::Event::Transfer { - from: 2, - to: 1, - amount: 450, - })); - System::assert_has_event(RuntimeEvent::Balances(crate::Event::DustLost { - account: 2, - amount: 50, - })); - System::assert_has_event(RuntimeEvent::Balances(crate::Event::Deposit { - who: 1, - amount: 50, - })); - }); -} - -#[test] -fn repatriating_reserved_balance_dust_removal_should_work() { - ExtBuilder::default().existential_deposit(100).build().execute_with(|| { - // Verification of reentrancy in dust removal - assert_ok!(Balances::set_balance(RawOrigin::Root.into(), 1, 1000, 0)); - assert_ok!(Balances::set_balance(RawOrigin::Root.into(), 2, 500, 0)); - - // Reserve a value on account 2, - // Such that free balance is lower than - // Exestintial deposit. - assert_ok!(Balances::reserve(&2, 450)); - - // Transfer of reserved fund from slashed account 2 to - // beneficiary account 1 - assert_ok!(Balances::repatriate_reserved(&2, &1, 450, Status::Free), 0); - - // Since free balance of account 2 is lower than - // existential deposit, dust amount is - // removed from the account 2 - assert_eq!(Balances::reserved_balance(2), 0); - assert_eq!(Balances::free_balance(2), 0); - - // account 1 is credited with reserved amount - // together with dust balance during dust - // removal. - assert_eq!(Balances::reserved_balance(1), 0); - assert_eq!(Balances::free_balance(1), 1500); - - // Verify the events - assert_eq!(System::events().len(), 11); - - System::assert_has_event(RuntimeEvent::Balances(crate::Event::ReserveRepatriated { - from: 2, - to: 1, - amount: 450, - destination_status: Status::Free, - })); - - System::assert_has_event(RuntimeEvent::Balances(crate::Event::DustLost { - account: 2, - amount: 50, - })); - - System::assert_last_event(RuntimeEvent::Balances(crate::Event::Deposit { - who: 1, - amount: 50, - })); - }); -} diff --git a/frame/balances/src/types.rs b/frame/balances/src/types.rs new file mode 100644 index 0000000000000..c96e1e44b4165 --- /dev/null +++ b/frame/balances/src/types.rs @@ -0,0 +1,157 @@ +// 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. + +//! Types used in the pallet. + +use crate::{Config, CreditOf, Event, Pallet}; +use codec::{Decode, Encode, MaxEncodedLen}; +use core::ops::BitOr; +use frame_support::{ + traits::{Imbalance, LockIdentifier, OnUnbalanced, WithdrawReasons}, + RuntimeDebug, +}; +use scale_info::TypeInfo; +use sp_runtime::Saturating; + +/// Simplified reasons for withdrawing balance. +#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, MaxEncodedLen, TypeInfo)] +pub enum Reasons { + /// Paying system transaction fees. + Fee = 0, + /// Any reason other than paying system transaction fees. + Misc = 1, + /// Any reason at all. + All = 2, +} + +impl From for Reasons { + fn from(r: WithdrawReasons) -> Reasons { + if r == WithdrawReasons::TRANSACTION_PAYMENT { + Reasons::Fee + } else if r.contains(WithdrawReasons::TRANSACTION_PAYMENT) { + Reasons::All + } else { + Reasons::Misc + } + } +} + +impl BitOr for Reasons { + type Output = Reasons; + fn bitor(self, other: Reasons) -> Reasons { + if self == other { + return self + } + Reasons::All + } +} + +/// A single lock on a balance. There can be many of these on an account and they "overlap", so the +/// same balance is frozen by multiple locks. +#[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, + /// 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. + pub reasons: Reasons, +} + +/// Store named reserved balance. +#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, MaxEncodedLen, TypeInfo)] +pub struct ReserveData { + /// The identifier for the named reserve. + pub id: ReserveIdentifier, + /// The amount of the named reserve. + pub amount: Balance, +} + +/// An identifier and balance. +#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, MaxEncodedLen, TypeInfo)] +pub struct IdAmount { + /// An identifier for this item. + pub id: Id, + /// Some amount for this item. + pub amount: Balance, +} + +/// All balance information for an account. +#[derive(Encode, Decode, Clone, PartialEq, Eq, Default, RuntimeDebug, MaxEncodedLen, TypeInfo)] +pub struct AccountData { + /// Non-reserved part of the balance which the account holder may be able to control. + /// + /// This is the only balance that matters in terms of most operations on tokens. + pub free: Balance, + /// Balance which is has active holds on it and may not be used at all. + /// + /// This is the sum of all individual holds together with any sums still under the (deprecated) + /// reserves API. + pub reserved: Balance, + /// The amount that `free` may not drop below when reducing the balance, except for actions + /// where the account owner cannot reasonably benefit from thr balance reduction, such as + /// slashing. + pub frozen: Balance, + /// Extra information about this account. The MSB is a flag indicating whether the new ref- + /// counting logic is in place for this account. + pub flags: ExtraFlags, +} + +const IS_NEW_LOGIC: u128 = 0x80000000_00000000_00000000_00000000u128; + +#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, MaxEncodedLen, TypeInfo)] +pub struct ExtraFlags(u128); +impl Default for ExtraFlags { + fn default() -> Self { + Self(IS_NEW_LOGIC) + } +} +impl ExtraFlags { + pub fn old_logic() -> Self { + Self(0) + } + pub fn set_new_logic(&mut self) { + self.0 = self.0 | IS_NEW_LOGIC + } + pub fn is_new_logic(&self) -> bool { + (self.0 & IS_NEW_LOGIC) == IS_NEW_LOGIC + } +} + +impl AccountData { + pub fn usable(&self) -> Balance { + self.free.saturating_sub(self.frozen) + } + + /// The total balance in this account including any that is reserved and ignoring any frozen. + pub fn total(&self) -> Balance { + self.free.saturating_add(self.reserved) + } +} + +pub struct DustCleaner, I: 'static = ()>( + pub(crate) Option<(T::AccountId, CreditOf)>, +); + +impl, I: 'static> Drop for DustCleaner { + fn drop(&mut self) { + if let Some((who, dust)) = self.0.take() { + Pallet::::deposit_event(Event::DustLost { account: who, amount: dust.peek() }); + T::DustRemoval::on_unbalanced(dust); + } + } +} diff --git a/frame/balances/src/weights.rs b/frame/balances/src/weights.rs index e7fd539c061aa..a2a9f0019b931 100644 --- a/frame/balances/src/weights.rs +++ b/frame/balances/src/weights.rs @@ -49,13 +49,14 @@ use sp_std::marker::PhantomData; /// Weight functions needed for pallet_balances. pub trait WeightInfo { - fn transfer() -> Weight; + fn transfer_allow_death() -> Weight; fn transfer_keep_alive() -> Weight; - fn set_balance_creating() -> Weight; - fn set_balance_killing() -> Weight; + fn force_set_balance_creating() -> Weight; + fn force_set_balance_killing() -> Weight; fn force_transfer() -> Weight; fn transfer_all() -> Weight; fn force_unreserve() -> Weight; + fn upgrade_accounts(u: u32, ) -> Weight; } /// Weights for pallet_balances using the Substrate node and recommended hardware. @@ -63,7 +64,7 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { /// Storage: System Account (r:1 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn transfer() -> Weight { + fn transfer_allow_death() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` @@ -85,7 +86,7 @@ impl WeightInfo for SubstrateWeight { } /// Storage: System Account (r:1 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn set_balance_creating() -> Weight { + fn force_set_balance_creating() -> Weight { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` @@ -96,7 +97,7 @@ impl WeightInfo for SubstrateWeight { } /// Storage: System Account (r:1 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn set_balance_killing() -> Weight { + fn force_set_balance_killing() -> Weight { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` @@ -138,13 +139,28 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } + /// Storage: System Account (r:999 w:999) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// The range of component `u` is `[1, 1000]`. + fn upgrade_accounts(u: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0 + u * (135 ±0)` + // Estimated: `990 + u * (2603 ±0)` + // Minimum execution time: 19_851_000 picoseconds. + Weight::from_parts(20_099_000, 990) + // Standard Error: 15_586 + .saturating_add(Weight::from_parts(14_892_860, 0).saturating_mul(u.into())) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(u.into()))) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(u.into()))) + .saturating_add(Weight::from_parts(0, 2603).saturating_mul(u.into())) + } } // For backwards compatibility and tests impl WeightInfo for () { /// Storage: System Account (r:1 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn transfer() -> Weight { + fn transfer_allow_death() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` @@ -166,7 +182,7 @@ impl WeightInfo for () { } /// Storage: System Account (r:1 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn set_balance_creating() -> Weight { + fn force_set_balance_creating() -> Weight { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` @@ -177,7 +193,7 @@ impl WeightInfo for () { } /// Storage: System Account (r:1 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn set_balance_killing() -> Weight { + fn force_set_balance_killing() -> Weight { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` @@ -219,4 +235,19 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } + /// Storage: System Account (r:999 w:999) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// The range of component `u` is `[1, 1000]`. + fn upgrade_accounts(u: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0 + u * (135 ±0)` + // Estimated: `990 + u * (2603 ±0)` + // Minimum execution time: 19_851_000 picoseconds. + Weight::from_parts(20_099_000, 990) + // Standard Error: 15_586 + .saturating_add(Weight::from_parts(14_892_860, 0).saturating_mul(u.into())) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(u.into()))) + .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(u.into()))) + .saturating_add(Weight::from_parts(0, 2603).saturating_mul(u.into())) + } } diff --git a/frame/beefy/src/mock.rs b/frame/beefy/src/mock.rs index c92966235118e..ceb95263e2436 100644 --- a/frame/beefy/src/mock.rs +++ b/frame/beefy/src/mock.rs @@ -161,6 +161,10 @@ impl pallet_balances::Config for Test { type ExistentialDeposit = ConstU128<1>; type AccountStore = System; type WeightInfo = (); + type HoldIdentifier = (); + type MaxHolds = (); + type FreezeIdentifier = (); + type MaxFreezes = (); } impl pallet_timestamp::Config for Test { diff --git a/frame/bounties/src/benchmarking.rs b/frame/bounties/src/benchmarking.rs index 04465a25eb891..0675328c3d3c2 100644 --- a/frame/bounties/src/benchmarking.rs +++ b/frame/bounties/src/benchmarking.rs @@ -57,9 +57,12 @@ fn setup_bounty, I: 'static>( 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 _ = T::Currency::make_free_balance_be(&caller, deposit + T::Currency::minimum_balance()); let curator = account("curator", u, SEED); - let _ = T::Currency::make_free_balance_be(&curator, fee / 2u32.into()); + let _ = T::Currency::make_free_balance_be( + &curator, + fee / 2u32.into() + T::Currency::minimum_balance(), + ); let reason = vec![0; d as usize]; (caller, curator, fee, value, reason) } diff --git a/frame/bounties/src/tests.rs b/frame/bounties/src/tests.rs index 27aa0858523ec..ef3da7564874e 100644 --- a/frame/bounties/src/tests.rs +++ b/frame/bounties/src/tests.rs @@ -100,6 +100,10 @@ impl pallet_balances::Config for Test { type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type HoldIdentifier = (); + type MaxHolds = (); } parameter_types! { pub const ProposalBond: Permill = Permill::from_percent(5); @@ -754,7 +758,7 @@ fn award_and_claim_bounty_works() { System::set_block_number(5); >::on_initialize(5); - assert_ok!(Balances::transfer( + assert_ok!(Balances::transfer_allow_death( RuntimeOrigin::signed(0), Bounties::bounty_account_id(0), 10 @@ -832,7 +836,7 @@ fn cancel_and_refund() { System::set_block_number(2); >::on_initialize(2); - assert_ok!(Balances::transfer( + assert_ok!(Balances::transfer_allow_death( RuntimeOrigin::signed(0), Bounties::bounty_account_id(0), 10 diff --git a/frame/child-bounties/src/benchmarking.rs b/frame/child-bounties/src/benchmarking.rs index 0a83f7c394905..e49d9c836125d 100644 --- a/frame/child-bounties/src/benchmarking.rs +++ b/frame/child-bounties/src/benchmarking.rs @@ -63,9 +63,12 @@ fn setup_bounty( 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 _ = T::Currency::make_free_balance_be(&caller, deposit + T::Currency::minimum_balance()); let curator = account("curator", user, SEED); - let _ = T::Currency::make_free_balance_be(&curator, fee / 2u32.into()); + let _ = T::Currency::make_free_balance_be( + &curator, + fee / 2u32.into() + T::Currency::minimum_balance(), + ); let reason = vec![0; description as usize]; (caller, curator, fee, value, reason) } @@ -73,7 +76,10 @@ fn setup_bounty( 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 _ = T::Currency::make_free_balance_be( + &child_curator, + fee / 2u32.into() + T::Currency::minimum_balance(), + ); let child_bounty_value = (value - fee) / 4u32.into(); let child_bounty_fee = child_bounty_value / 2u32.into(); diff --git a/frame/child-bounties/src/tests.rs b/frame/child-bounties/src/tests.rs index 0172468ec55d6..a936312aec868 100644 --- a/frame/child-bounties/src/tests.rs +++ b/frame/child-bounties/src/tests.rs @@ -35,7 +35,7 @@ use sp_core::H256; use sp_runtime::{ testing::Header, traits::{BadOrigin, BlakeTwo256, IdentityLookup}, - Perbill, Permill, + Perbill, Permill, TokenError, }; use super::Event as ChildBountiesEvent; @@ -103,6 +103,10 @@ impl pallet_balances::Config for Test { type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type HoldIdentifier = (); + type MaxHolds = (); } parameter_types! { pub const ProposalBond: Permill = Permill::from_percent(5); @@ -248,7 +252,7 @@ fn add_child_bounty() { assert_noop!( ChildBounties::add_child_bounty(RuntimeOrigin::signed(4), 0, 50, b"12345-p1".to_vec()), - pallet_balances::Error::::KeepAlive, + TokenError::NotExpendable, ); assert_noop!( diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index 2fb033cf85d8c..fb8e4ac4b3634 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -798,15 +798,15 @@ benchmarks! { let instance = Contract::::new(code, vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); let deposit_account = instance.info()?.deposit_account().clone(); - assert_eq!(T::Currency::total_balance(&beneficiary), 0u32.into()); + assert_eq!(>::total_balance(&beneficiary), 0u32.into()); assert_eq!(T::Currency::free_balance(&instance.account_id), Pallet::::min_balance() * 2u32.into()); assert_ne!(T::Currency::free_balance(&deposit_account), 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(&deposit_account), 0u32.into()); - assert_eq!(T::Currency::total_balance(&beneficiary), Pallet::::min_balance() * 2u32.into()); + assert_eq!(>::total_balance(&instance.account_id), 0u32.into()); + assert_eq!(>::total_balance(&deposit_account), 0u32.into()); + assert_eq!(>::total_balance(&beneficiary), Pallet::::min_balance() * 2u32.into()); } } @@ -1573,12 +1573,12 @@ benchmarks! { instance.set_balance(value * (r + 1).into()); let origin = RawOrigin::Signed(instance.caller.clone()); for account in &accounts { - assert_eq!(T::Currency::total_balance(account), 0u32.into()); + assert_eq!(>::total_balance(account), 0u32.into()); } }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) verify { for account in &accounts { - assert_eq!(T::Currency::total_balance(account), value); + assert_eq!(>::total_balance(account), value); } } diff --git a/frame/contracts/src/exec.rs b/frame/contracts/src/exec.rs index bd63c524c6152..6a053712e66e7 100644 --- a/frame/contracts/src/exec.rs +++ b/frame/contracts/src/exec.rs @@ -25,7 +25,10 @@ use frame_support::{ crypto::ecdsa::ECDSAExt, dispatch::{DispatchError, DispatchResult, DispatchResultWithPostInfo, Dispatchable}, storage::{with_transaction, TransactionOutcome}, - traits::{Contains, Currency, ExistenceRequirement, OriginTrait, Randomness, Time}, + traits::{ + tokens::{Fortitude::Polite, Preservation::Expendable}, + Contains, Currency, ExistenceRequirement, OriginTrait, Randomness, Time, + }, weights::Weight, Blake2_128Concat, BoundedVec, StorageHasher, }; @@ -1198,7 +1201,7 @@ where T::Currency::transfer( &frame.account_id, beneficiary, - T::Currency::reducible_balance(&frame.account_id, false), + T::Currency::reducible_balance(&frame.account_id, Expendable, Polite), ExistenceRequirement::AllowDeath, )?; info.queue_trie_for_deletion()?; @@ -2751,8 +2754,10 @@ mod tests { RuntimeCall::System(SysCall::remark_with_event { remark: b"Hello".to_vec() }); // transfers are disallowed by the `TestFiler` (see below) - let forbidden_call = - RuntimeCall::Balances(BalanceCall::transfer { dest: CHARLIE, value: 22 }); + let forbidden_call = RuntimeCall::Balances(BalanceCall::transfer_allow_death { + dest: CHARLIE, + value: 22, + }); // simple cases: direct call assert_err!( @@ -2772,7 +2777,7 @@ mod tests { }); TestFilter::set_filter(|call| match call { - RuntimeCall::Balances(pallet_balances::Call::transfer { .. }) => false, + RuntimeCall::Balances(pallet_balances::Call::transfer_allow_death { .. }) => false, _ => true, }); diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index 7aac94d11148b..d3369b6c290bf 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -187,7 +187,7 @@ pub mod pallet { type Randomness: Randomness; /// The currency in which fees are paid and contract balances are held. - type Currency: ReservableCurrency + type Currency: ReservableCurrency // TODO: Move to fungible traits + Inspect>; /// The overarching event type. diff --git a/frame/contracts/src/storage/meter.rs b/frame/contracts/src/storage/meter.rs index b4fc443fe7f35..ef3e01f6d6c4f 100644 --- a/frame/contracts/src/storage/meter.rs +++ b/frame/contracts/src/storage/meter.rs @@ -25,7 +25,10 @@ use codec::Encode; use frame_support::{ dispatch::DispatchError, ensure, - traits::{tokens::WithdrawConsequence, Currency, ExistenceRequirement, Get}, + traits::{ + tokens::{Fortitude::Polite, Preservation::Protect, WithdrawConsequence}, + Currency, ExistenceRequirement, Get, + }, DefaultNoBound, RuntimeDebugNoBound, }; use pallet_contracts_primitives::StorageDeposit as Deposit; @@ -456,7 +459,7 @@ impl Ext for ReservingExt { // We are sending the `min_leftover` and the `min_balance` from the origin // account as part of a contract call. Hence origin needs to have those left over // as free balance after accounting for all deposits. - let max = T::Currency::reducible_balance(origin, true) + let max = T::Currency::reducible_balance(origin, Protect, Polite) .saturating_sub(min_leftover) .saturating_sub(Pallet::::min_balance()); let limit = limit.unwrap_or(max); diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index 30a39eebfcfdd..185945b71e5be 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -37,7 +37,7 @@ use frame_support::{ storage::child, traits::{ ConstU32, ConstU64, Contains, Currency, ExistenceRequirement, Get, LockableCurrency, - OnIdle, OnInitialize, ReservableCurrency, WithdrawReasons, + OnIdle, OnInitialize, WithdrawReasons, }, weights::{constants::WEIGHT_REF_TIME_PER_SECOND, Weight}, }; @@ -48,7 +48,7 @@ use sp_keystore::{testing::MemoryKeystore, KeystoreExt}; use sp_runtime::{ testing::{Header, H256}, traits::{BlakeTwo256, Convert, Hash, IdentityLookup}, - AccountId32, + AccountId32, TokenError, }; use std::{ops::Deref, sync::Arc}; @@ -318,6 +318,10 @@ impl pallet_balances::Config for Test { type ExistentialDeposit = ExistentialDeposit; type AccountStore = System; type WeightInfo = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type HoldIdentifier = (); + type MaxHolds = (); } impl pallet_timestamp::Config for Test { @@ -1054,7 +1058,7 @@ fn transfer_allow_death_cannot_kill_account() { total_balance, ExistenceRequirement::AllowDeath, ), - pallet_balances::Error::::KeepAlive, + TokenError::Frozen, ); assert_eq!(::Currency::total_balance(&addr), total_balance); @@ -1474,25 +1478,6 @@ fn transfer_return_code() { .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 100 balance but this balance is reserved so - // 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, - Determinism::Deterministic, - ) - .result - .unwrap(); - assert_return_code!(result, RuntimeReturnCode::TransferFailed); }); } @@ -1569,29 +1554,6 @@ fn call_return_code() { .unwrap(); assert_return_code!(result, RuntimeReturnCode::TransferFailed); - // 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. - 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()) - .cloned() - .collect(), - false, - Determinism::Deterministic, - ) - .result - .unwrap(); - assert_return_code!(result, RuntimeReturnCode::TransferFailed); - // Contract has enough balance but callee reverts because "1" is passed. Balances::make_free_balance_be(&addr_bob, min_balance + 1000); let result = Contracts::bare_call( @@ -1683,25 +1645,6 @@ fn instantiate_return_code() { .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, - Determinism::Deterministic, - ) - .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( @@ -2805,7 +2748,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 = RuntimeCall::Balances(pallet_balances::Call::transfer { + let call = RuntimeCall::Balances(pallet_balances::Call::transfer_allow_death { dest: addr_callee, value: min_balance * 10, }); diff --git a/frame/conviction-voting/src/benchmarking.rs b/frame/conviction-voting/src/benchmarking.rs index 27f46507d6078..8701ed7ebb074 100644 --- a/frame/conviction-voting/src/benchmarking.rs +++ b/frame/conviction-voting/src/benchmarking.rs @@ -23,7 +23,11 @@ use assert_matches::assert_matches; use frame_benchmarking::v1::{account, benchmarks_instance_pallet, whitelist_account}; use frame_support::{ dispatch::RawOrigin, - traits::{fungible, Currency, Get}, + traits::{ + fungible, + tokens::{Fortitude::Polite, Preservation::Expendable}, + Currency, Get, + }, }; use sp_runtime::traits::Bounded; use sp_std::collections::btree_map::BTreeMap; @@ -257,13 +261,13 @@ benchmarks_instance_pallet! { } } - let orig_usable = >::reducible_balance(&caller, false); + let orig_usable = >::reducible_balance(&caller, Expendable, Polite); 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)?; - let now_usable = >::reducible_balance(&caller, false); + let now_usable = >::reducible_balance(&caller, Expendable, Polite); assert_eq!(orig_usable - now_usable, 100u32.into()); // Remove the vote @@ -272,7 +276,7 @@ benchmarks_instance_pallet! { // We can now unlock on `class` from 200 to 100... }: _(RawOrigin::Signed(caller.clone()), class, caller_lookup) verify { - assert_eq!(orig_usable, >::reducible_balance(&caller, false)); + assert_eq!(orig_usable, >::reducible_balance(&caller, Expendable, Polite)); } impl_benchmark_test_suite!( diff --git a/frame/conviction-voting/src/lib.rs b/frame/conviction-voting/src/lib.rs index f28953c4a35b9..072e57035484d 100644 --- a/frame/conviction-voting/src/lib.rs +++ b/frame/conviction-voting/src/lib.rs @@ -388,7 +388,10 @@ impl, I: 'static> Pallet { poll_index: PollIndexOf, vote: AccountVote>, ) -> DispatchResult { - ensure!(vote.balance() <= T::Currency::free_balance(who), Error::::InsufficientFunds); + ensure!( + vote.balance() <= T::Currency::total_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| { @@ -548,7 +551,7 @@ impl, I: 'static> Pallet { ) -> 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!(balance <= T::Currency::total_balance(&who), Error::::InsufficientFunds); let votes = VotingFor::::try_mutate(&who, &class, |voting| -> Result { let old = sp_std::mem::replace( diff --git a/frame/conviction-voting/src/tests.rs b/frame/conviction-voting/src/tests.rs index e01931d7ad24a..f33e511a164f6 100644 --- a/frame/conviction-voting/src/tests.rs +++ b/frame/conviction-voting/src/tests.rs @@ -51,7 +51,7 @@ frame_support::construct_runtime!( pub struct BaseFilter; impl Contains for BaseFilter { fn contains(call: &RuntimeCall) -> bool { - !matches!(call, &RuntimeCall::Balances(pallet_balances::Call::set_balance { .. })) + !matches!(call, &RuntimeCall::Balances(pallet_balances::Call::force_set_balance { .. })) } } @@ -92,6 +92,10 @@ impl pallet_balances::Config for Test { type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type HoldIdentifier = (); + type MaxHolds = (); } #[derive(Clone, PartialEq, Eq, Debug)] diff --git a/frame/democracy/src/tests.rs b/frame/democracy/src/tests.rs index 9e735765905d6..06fde5129c6d0 100644 --- a/frame/democracy/src/tests.rs +++ b/frame/democracy/src/tests.rs @@ -72,7 +72,7 @@ frame_support::construct_runtime!( pub struct BaseFilter; impl Contains for BaseFilter { fn contains(call: &RuntimeCall) -> bool { - !matches!(call, &RuntimeCall::Balances(pallet_balances::Call::set_balance { .. })) + !matches!(call, &RuntimeCall::Balances(pallet_balances::Call::force_set_balance { .. })) } } @@ -144,6 +144,10 @@ impl pallet_balances::Config for Test { type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type HoldIdentifier = (); + type MaxHolds = (); } parameter_types! { pub static PreimageByteDeposit: u64 = 0; @@ -223,7 +227,7 @@ fn params_should_work() { } fn set_balance_proposal(value: u64) -> BoundedCallOf { - let inner = pallet_balances::Call::set_balance { who: 42, new_free: value, new_reserved: 0 }; + let inner = pallet_balances::Call::force_set_balance { who: 42, new_free: value }; let outer = RuntimeCall::Balances(inner); Preimage::bound(outer).unwrap() } diff --git a/frame/election-provider-multi-phase/src/benchmarking.rs b/frame/election-provider-multi-phase/src/benchmarking.rs index 4d48f17909c0e..a5946c6a1d3c1 100644 --- a/frame/election-provider-multi-phase/src/benchmarking.rs +++ b/frame/election-provider-multi-phase/src/benchmarking.rs @@ -219,7 +219,7 @@ frame_benchmarking::benchmarks! { finalize_signed_phase_accept_solution { let receiver = account("receiver", 0, SEED); - let initial_balance = T::Currency::minimum_balance() * 10u32.into(); + let initial_balance = T::Currency::minimum_balance() + 10u32.into(); T::Currency::make_free_balance_be(&receiver, initial_balance); let ready = Default::default(); let deposit: BalanceOf = 10u32.into(); @@ -228,7 +228,7 @@ frame_benchmarking::benchmarks! { let call_fee: BalanceOf = 30u32.into(); assert_ok!(T::Currency::reserve(&receiver, deposit)); - assert_eq!(T::Currency::free_balance(&receiver), initial_balance - 10u32.into()); + assert_eq!(T::Currency::free_balance(&receiver), T::Currency::minimum_balance()); }: { >::finalize_signed_phase_accept_solution( ready, @@ -246,17 +246,17 @@ frame_benchmarking::benchmarks! { finalize_signed_phase_reject_solution { let receiver = account("receiver", 0, SEED); - let initial_balance = T::Currency::minimum_balance().max(One::one()) * 10u32.into(); + let initial_balance = T::Currency::minimum_balance() + 10u32.into(); let deposit: BalanceOf = 10u32.into(); T::Currency::make_free_balance_be(&receiver, initial_balance); assert_ok!(T::Currency::reserve(&receiver, deposit)); - assert_eq!(T::Currency::free_balance(&receiver), initial_balance - 10u32.into()); + assert_eq!(T::Currency::free_balance(&receiver), T::Currency::minimum_balance()); assert_eq!(T::Currency::reserved_balance(&receiver), 10u32.into()); }: { >::finalize_signed_phase_reject_solution(&receiver, deposit) } verify { - assert_eq!(T::Currency::free_balance(&receiver), initial_balance - 10u32.into()); + assert_eq!(T::Currency::free_balance(&receiver), T::Currency::minimum_balance()); assert_eq!(T::Currency::reserved_balance(&receiver), 0u32.into()); } diff --git a/frame/election-provider-multi-phase/src/mock.rs b/frame/election-provider-multi-phase/src/mock.rs index da7a0cf1dd263..8c18777606048 100644 --- a/frame/election-provider-multi-phase/src/mock.rs +++ b/frame/election-provider-multi-phase/src/mock.rs @@ -254,6 +254,10 @@ impl pallet_balances::Config for Runtime { type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type WeightInfo = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type HoldIdentifier = (); + type MaxHolds = (); } #[derive(Default, Eq, PartialEq, Debug, Clone, Copy)] diff --git a/frame/elections-phragmen/src/lib.rs b/frame/elections-phragmen/src/lib.rs index e3eed6ec4bcc4..d83c94db139a4 100644 --- a/frame/elections-phragmen/src/lib.rs +++ b/frame/elections-phragmen/src/lib.rs @@ -1248,6 +1248,10 @@ mod tests { type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type WeightInfo = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type HoldIdentifier = (); + type MaxHolds = (); } frame_support::parameter_types! { @@ -2121,7 +2125,8 @@ mod tests { assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); // User has 100 free and 50 reserved. - assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 2, 100, 50)); + assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), 2, 150)); + assert_ok!(Balances::reserve(&2, 50)); // User tries to vote with 150 tokens. assert_ok!(vote(RuntimeOrigin::signed(2), vec![4, 5], 150)); // We truncate to only their free balance, after reserving additional for voting. diff --git a/frame/examples/basic/src/tests.rs b/frame/examples/basic/src/tests.rs index 2e6a03bdd857c..d9a8a4e8e1cdc 100644 --- a/frame/examples/basic/src/tests.rs +++ b/frame/examples/basic/src/tests.rs @@ -87,6 +87,10 @@ impl pallet_balances::Config for Test { type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type HoldIdentifier = (); + type MaxHolds = (); } impl Config for Test { diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index 7a8de43140c35..10cf6e06b3431 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -688,13 +688,10 @@ mod tests { use frame_support::{ assert_err, parameter_types, - traits::{ - ConstU32, ConstU64, ConstU8, Currency, LockIdentifier, LockableCurrency, - WithdrawReasons, - }, + traits::{fungible, ConstU32, ConstU64, ConstU8, Currency}, weights::{ConstantMultiplier, IdentityFee, RuntimeDbWeight, Weight, WeightToFee}, }; - use frame_system::{Call as SystemCall, ChainContext, LastRuntimeUpgradeInfo}; + use frame_system::{ChainContext, LastRuntimeUpgradeInfo}; use pallet_balances::Call as BalancesCall; use pallet_transaction_payment::CurrencyAdapter; @@ -899,6 +896,10 @@ mod tests { type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type WeightInfo = (); + type FreezeIdentifier = (); + type MaxFreezes = ConstU32<1>; + type HoldIdentifier = (); + type MaxHolds = ConstU32<1>; } parameter_types! { @@ -972,7 +973,7 @@ mod tests { } fn call_transfer(dest: u64, value: u64) -> RuntimeCall { - RuntimeCall::Balances(BalancesCall::transfer { dest, value }) + RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest, value }) } #[test] @@ -1025,13 +1026,13 @@ mod tests { block_import_works_inner( new_test_ext_v0(1), array_bytes::hex_n_into_unchecked( - "216e61b2689d1243eb56d89c9084db48e50ebebc4871d758db131432c675d7c0", + "65e953676859e7a33245908af7ad3637d6861eb90416d433d485e95e2dd174a1", ), ); block_import_works_inner( new_test_ext(1), array_bytes::hex_n_into_unchecked( - "4738b4c0aab02d6ddfa62a2a6831ccc975a9f978f7db8d7ea8e68eba8639530a", + "5a19b3d6fdb7241836349fdcbe2d9df4d4f945b949d979e31ad50bff1cbcd1c2", ), ); } @@ -1116,7 +1117,7 @@ mod tests { let mut t = new_test_ext(10000); // given: TestXt uses the encoded len as fixed Len: let xt = TestXt::new( - RuntimeCall::Balances(BalancesCall::transfer { dest: 33, value: 0 }), + RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 33, value: 0 }), sign_extra(1, 0, 0), ); let encoded = xt.encode(); @@ -1139,7 +1140,10 @@ mod tests { for nonce in 0..=num_to_exhaust_block { let xt = TestXt::new( - RuntimeCall::Balances(BalancesCall::transfer { dest: 33, value: 0 }), + RuntimeCall::Balances(BalancesCall::transfer_allow_death { + dest: 33, + value: 0, + }), sign_extra(1, nonce.into(), 0), ); let res = Executive::apply_extrinsic(xt); @@ -1164,15 +1168,15 @@ mod tests { #[test] fn block_weight_and_size_is_stored_per_tx() { let xt = TestXt::new( - RuntimeCall::Balances(BalancesCall::transfer { dest: 33, value: 0 }), + RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 33, value: 0 }), sign_extra(1, 0, 0), ); let x1 = TestXt::new( - RuntimeCall::Balances(BalancesCall::transfer { dest: 33, value: 0 }), + RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 33, value: 0 }), sign_extra(1, 1, 0), ); let x2 = TestXt::new( - RuntimeCall::Balances(BalancesCall::transfer { dest: 33, value: 0 }), + RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 33, value: 0 }), sign_extra(1, 2, 0), ); let len = xt.clone().encode().len() as u32; @@ -1258,50 +1262,30 @@ mod tests { } #[test] - fn can_pay_for_tx_fee_on_full_lock() { - let id: LockIdentifier = *b"0 "; - let execute_with_lock = |lock: WithdrawReasons| { - let mut t = new_test_ext(1); - t.execute_with(|| { - as LockableCurrency>::set_lock( - id, &1, 110, lock, - ); - let xt = TestXt::new( - RuntimeCall::System(SystemCall::remark { remark: vec![1u8] }), - sign_extra(1, 0, 0), - ); - let weight = xt.get_dispatch_info().weight + - ::BlockWeights::get() - .get(DispatchClass::Normal) - .base_extrinsic; - let fee: Balance = - ::WeightToFee::weight_to_fee( - &weight, - ); - Executive::initialize_block(&Header::new( - 1, - H256::default(), - H256::default(), - [69u8; 32].into(), - Digest::default(), - )); - - if lock == WithdrawReasons::except(WithdrawReasons::TRANSACTION_PAYMENT) { - assert!(Executive::apply_extrinsic(xt).unwrap().is_ok()); - // tx fee has been deducted. - assert_eq!(>::total_balance(&1), 111 - fee); - } else { - assert_eq!( - Executive::apply_extrinsic(xt), - Err(InvalidTransaction::Payment.into()), - ); - assert_eq!(>::total_balance(&1), 111); - } - }); - }; + fn can_not_pay_for_tx_fee_on_full_lock() { + let mut t = new_test_ext(1); + t.execute_with(|| { + as fungible::MutateFreeze>::set_freeze( + &(), + &1, + 110, + ) + .unwrap(); + let xt = TestXt::new( + RuntimeCall::System(frame_system::Call::remark { remark: vec![1u8] }), + sign_extra(1, 0, 0), + ); + Executive::initialize_block(&Header::new( + 1, + H256::default(), + H256::default(), + [69u8; 32].into(), + Digest::default(), + )); - execute_with_lock(WithdrawReasons::all()); - execute_with_lock(WithdrawReasons::except(WithdrawReasons::TRANSACTION_PAYMENT)); + assert_eq!(Executive::apply_extrinsic(xt), Err(InvalidTransaction::Payment.into()),); + assert_eq!(>::total_balance(&1), 111); + }); } #[test] @@ -1443,7 +1427,7 @@ mod tests { #[test] fn custom_runtime_upgrade_is_called_when_using_execute_block_trait() { let xt = TestXt::new( - RuntimeCall::Balances(BalancesCall::transfer { dest: 33, value: 0 }), + RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 33, value: 0 }), sign_extra(1, 0, 0), ); @@ -1569,7 +1553,7 @@ mod tests { #[should_panic(expected = "Invalid inherent position for extrinsic at index 1")] fn invalid_inherent_position_fail() { let xt1 = TestXt::new( - RuntimeCall::Balances(BalancesCall::transfer { dest: 33, value: 0 }), + RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 33, value: 0 }), sign_extra(1, 0, 0), ); let xt2 = TestXt::new(RuntimeCall::Custom(custom::Call::inherent_call {}), None); diff --git a/frame/fast-unstake/src/mock.rs b/frame/fast-unstake/src/mock.rs index c9a1d6d517308..fbe6c4592bf67 100644 --- a/frame/fast-unstake/src/mock.rs +++ b/frame/fast-unstake/src/mock.rs @@ -89,6 +89,10 @@ impl pallet_balances::Config for Runtime { type ExistentialDeposit = ExistentialDeposit; type AccountStore = System; type WeightInfo = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type HoldIdentifier = (); + type MaxHolds = (); } pallet_staking_reward_curve::build! { diff --git a/frame/grandpa/src/mock.rs b/frame/grandpa/src/mock.rs index 4e4f2f79d040e..a7359f6896db7 100644 --- a/frame/grandpa/src/mock.rs +++ b/frame/grandpa/src/mock.rs @@ -142,6 +142,10 @@ impl pallet_balances::Config for Test { type ExistentialDeposit = ConstU128<1>; type AccountStore = System; type WeightInfo = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type HoldIdentifier = (); + type MaxHolds = (); } impl pallet_timestamp::Config for Test { diff --git a/frame/identity/src/tests.rs b/frame/identity/src/tests.rs index 0e15f08ddd7e6..ba9749172e5f6 100644 --- a/frame/identity/src/tests.rs +++ b/frame/identity/src/tests.rs @@ -85,6 +85,10 @@ impl pallet_balances::Config for Test { type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type WeightInfo = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type HoldIdentifier = (); + type MaxHolds = (); } parameter_types! { diff --git a/frame/indices/src/mock.rs b/frame/indices/src/mock.rs index 6cf1f9d9740c9..8bd05d04ab4e1 100644 --- a/frame/indices/src/mock.rs +++ b/frame/indices/src/mock.rs @@ -76,6 +76,10 @@ impl pallet_balances::Config for Test { type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type HoldIdentifier = (); + type MaxHolds = (); } impl Config for Test { diff --git a/frame/lottery/src/mock.rs b/frame/lottery/src/mock.rs index 9b1a933d0a4ac..7afd0e319db34 100644 --- a/frame/lottery/src/mock.rs +++ b/frame/lottery/src/mock.rs @@ -89,6 +89,10 @@ impl pallet_balances::Config for Test { type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type HoldIdentifier = (); + type MaxHolds = (); } parameter_types! { diff --git a/frame/lottery/src/tests.rs b/frame/lottery/src/tests.rs index 09386c7e348d8..ae3a6c858f242 100644 --- a/frame/lottery/src/tests.rs +++ b/frame/lottery/src/tests.rs @@ -23,8 +23,7 @@ use mock::{ new_test_ext, run_to_block, Balances, BalancesCall, Lottery, RuntimeCall, RuntimeOrigin, SystemCall, Test, }; -use pallet_balances::Error as BalancesError; -use sp_runtime::traits::BadOrigin; +use sp_runtime::{traits::BadOrigin, TokenError}; #[test] fn initial_state() { @@ -45,7 +44,7 @@ fn basic_end_to_end_works() { let delay = 5; let calls = vec![ RuntimeCall::Balances(BalancesCall::force_transfer { source: 0, dest: 0, value: 0 }), - RuntimeCall::Balances(BalancesCall::transfer { dest: 0, value: 0 }), + RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 0, value: 0 }), ]; // Set calls for the lottery @@ -56,7 +55,10 @@ fn basic_end_to_end_works() { 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 })); + let call = Box::new(RuntimeCall::Balances(BalancesCall::transfer_allow_death { + dest: 2, + value: 20, + })); 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); @@ -129,7 +131,7 @@ fn set_calls_works() { let calls = vec![ RuntimeCall::Balances(BalancesCall::force_transfer { source: 0, dest: 0, value: 0 }), - RuntimeCall::Balances(BalancesCall::transfer { dest: 0, value: 0 }), + RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 0, value: 0 }), ]; assert_ok!(Lottery::set_calls(RuntimeOrigin::root(), calls)); @@ -137,7 +139,7 @@ fn set_calls_works() { let too_many_calls = vec![ RuntimeCall::Balances(BalancesCall::force_transfer { source: 0, dest: 0, value: 0 }), - RuntimeCall::Balances(BalancesCall::transfer { dest: 0, value: 0 }), + RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 0, value: 0 }), RuntimeCall::System(SystemCall::remark { remark: vec![] }), ]; @@ -157,7 +159,7 @@ fn call_to_indices_works() { new_test_ext().execute_with(|| { let calls = vec![ RuntimeCall::Balances(BalancesCall::force_transfer { source: 0, dest: 0, value: 0 }), - RuntimeCall::Balances(BalancesCall::transfer { dest: 0, value: 0 }), + RuntimeCall::Balances(BalancesCall::transfer_allow_death { 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 @@ -166,7 +168,7 @@ fn call_to_indices_works() { let too_many_calls = vec![ RuntimeCall::Balances(BalancesCall::force_transfer { source: 0, dest: 0, value: 0 }), - RuntimeCall::Balances(BalancesCall::transfer { dest: 0, value: 0 }), + RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 0, value: 0 }), RuntimeCall::System(SystemCall::remark { remark: vec![] }), ]; assert_noop!(Lottery::calls_to_indices(&too_many_calls), Error::::TooManyCalls); @@ -203,7 +205,10 @@ 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(RuntimeCall::Balances(BalancesCall::transfer { dest: 2, value: 20 })); + let call = Box::new(RuntimeCall::Balances(BalancesCall::transfer_allow_death { + dest: 2, + value: 20, + })); // This is just a basic transfer then assert_ok!(Lottery::buy_ticket(RuntimeOrigin::signed(1), call.clone())); assert_eq!(Balances::free_balance(&1), 100 - 20); @@ -212,7 +217,7 @@ fn buy_ticket_works_as_simple_passthrough() { // Lottery is set up, but too expensive to enter, so `do_buy_ticket` fails. let calls = vec![ RuntimeCall::Balances(BalancesCall::force_transfer { source: 0, dest: 0, value: 0 }), - RuntimeCall::Balances(BalancesCall::transfer { dest: 0, value: 0 }), + RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 0, value: 0 }), ]; assert_ok!(Lottery::set_calls(RuntimeOrigin::root(), calls)); @@ -223,11 +228,13 @@ 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(RuntimeCall::Balances(BalancesCall::transfer { dest: 2, value: 1000 })); + let fail_call = Box::new(RuntimeCall::Balances(BalancesCall::transfer_allow_death { + dest: 2, + value: 1000, + })); assert_noop!( Lottery::buy_ticket(RuntimeOrigin::signed(1), fail_call), - BalancesError::::InsufficientBalance, + ArithmeticError::Underflow, ); let bad_origin_call = Box::new(RuntimeCall::Balances(BalancesCall::force_transfer { @@ -243,8 +250,10 @@ fn buy_ticket_works_as_simple_passthrough() { 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 })); + let successful_call = Box::new(RuntimeCall::Balances(BalancesCall::transfer_allow_death { + dest: 2, + value: 1, + })); assert_ok!(Lottery::buy_ticket(RuntimeOrigin::signed(2), successful_call)); assert_eq!(TicketsCount::::get(), 1); }); @@ -256,12 +265,15 @@ fn buy_ticket_works() { // Set calls for the lottery. let calls = vec![ RuntimeCall::System(SystemCall::remark { remark: vec![] }), - RuntimeCall::Balances(BalancesCall::transfer { dest: 0, value: 0 }), + RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 0, value: 0 }), ]; 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 })); + let call = Box::new(RuntimeCall::Balances(BalancesCall::transfer_allow_death { + dest: 2, + value: 1, + })); assert_ok!(Lottery::buy_ticket(RuntimeOrigin::signed(1), call.clone())); assert_eq!(TicketsCount::::get(), 0); @@ -274,7 +286,10 @@ 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(RuntimeCall::Balances(BalancesCall::transfer { dest: 3, value: 30 })); + let call = Box::new(RuntimeCall::Balances(BalancesCall::transfer_allow_death { + dest: 3, + value: 30, + })); assert_ok!(Lottery::buy_ticket(RuntimeOrigin::signed(1), call)); assert_eq!(TicketsCount::::get(), 1); @@ -302,7 +317,8 @@ fn buy_ticket_works() { #[test] fn do_buy_ticket_already_participating() { new_test_ext().execute_with(|| { - let calls = vec![RuntimeCall::Balances(BalancesCall::transfer { dest: 0, value: 0 })]; + let calls = + vec![RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 0, value: 0 })]; assert_ok!(Lottery::set_calls(RuntimeOrigin::root(), calls.clone())); assert_ok!(Lottery::start_lottery(RuntimeOrigin::root(), 1, 10, 10, false)); @@ -317,7 +333,8 @@ fn do_buy_ticket_already_participating() { #[test] fn buy_ticket_already_participating() { new_test_ext().execute_with(|| { - let calls = vec![RuntimeCall::Balances(BalancesCall::transfer { dest: 0, value: 0 })]; + let calls = + vec![RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 0, value: 0 })]; assert_ok!(Lottery::set_calls(RuntimeOrigin::root(), calls.clone())); assert_ok!(Lottery::start_lottery(RuntimeOrigin::root(), 1, 10, 10, false)); @@ -337,7 +354,8 @@ fn buy_ticket_already_participating() { #[test] fn buy_ticket_insufficient_balance() { new_test_ext().execute_with(|| { - let calls = vec![RuntimeCall::Balances(BalancesCall::transfer { dest: 0, value: 0 })]; + let calls = + vec![RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 0, value: 0 })]; assert_ok!(Lottery::set_calls(RuntimeOrigin::root(), calls.clone())); // Price set to 100. assert_ok!(Lottery::start_lottery(RuntimeOrigin::root(), 100, 10, 10, false)); @@ -352,16 +370,14 @@ fn buy_ticket_insufficient_balance() { #[test] fn do_buy_ticket_insufficient_balance() { new_test_ext().execute_with(|| { - let calls = vec![RuntimeCall::Balances(BalancesCall::transfer { dest: 0, value: 0 })]; + let calls = + vec![RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 0, value: 0 })]; assert_ok!(Lottery::set_calls(RuntimeOrigin::root(), calls.clone())); // Price set to 101. assert_ok!(Lottery::start_lottery(RuntimeOrigin::root(), 101, 10, 10, false)); // Buying fails with InsufficientBalance. - assert_noop!( - Lottery::do_buy_ticket(&1, &calls[0]), - BalancesError::::InsufficientBalance - ); + assert_noop!(Lottery::do_buy_ticket(&1, &calls[0]), TokenError::FundsUnavailable,); assert!(TicketsCount::::get().is_zero()); }); } @@ -369,13 +385,13 @@ fn do_buy_ticket_insufficient_balance() { #[test] fn do_buy_ticket_keep_alive() { new_test_ext().execute_with(|| { - let calls = vec![RuntimeCall::Balances(BalancesCall::transfer { dest: 0, value: 0 })]; + let calls = + vec![RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 0, value: 0 })]; assert_ok!(Lottery::set_calls(RuntimeOrigin::root(), calls.clone())); // Price set to 100. 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); + assert_noop!(Lottery::do_buy_ticket(&1, &calls[0]), TokenError::NotExpendable); assert!(TicketsCount::::get().is_zero()); }); } @@ -421,7 +437,8 @@ fn choose_ticket_trivial_cases() { #[test] fn choose_account_one_participant() { new_test_ext().execute_with(|| { - let calls = vec![RuntimeCall::Balances(BalancesCall::transfer { dest: 0, value: 0 })]; + let calls = + vec![RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 0, value: 0 })]; 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()); diff --git a/frame/multisig/src/tests.rs b/frame/multisig/src/tests.rs index c5517195d149f..7e7f1668026a2 100644 --- a/frame/multisig/src/tests.rs +++ b/frame/multisig/src/tests.rs @@ -30,6 +30,7 @@ use sp_core::H256; use sp_runtime::{ testing::Header, traits::{BlakeTwo256, IdentityLookup}, + TokenError, }; type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; @@ -84,6 +85,10 @@ impl pallet_balances::Config for Test { type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type HoldIdentifier = (); + type MaxHolds = (); } pub struct TestBaseCallFilter; @@ -107,7 +112,7 @@ impl Config for Test { type WeightInfo = (); } -use pallet_balances::{Call as BalancesCall, Error as BalancesError}; +use pallet_balances::Call as BalancesCall; pub fn new_test_ext() -> sp_io::TestExternalities { let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); @@ -126,16 +131,16 @@ fn now() -> Timepoint { } fn call_transfer(dest: u64, value: u64) -> Box { - Box::new(RuntimeCall::Balances(BalancesCall::transfer { dest, value })) + Box::new(RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest, value })) } #[test] 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(RuntimeOrigin::signed(1), multi, 5)); - assert_ok!(Balances::transfer(RuntimeOrigin::signed(2), multi, 5)); - assert_ok!(Balances::transfer(RuntimeOrigin::signed(3), multi, 5)); + assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(1), multi, 5)); + assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(2), multi, 5)); + assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(3), multi, 5)); let call = call_transfer(6, 15); let call_weight = call.get_dispatch_info().weight; @@ -196,9 +201,9 @@ 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(RuntimeOrigin::signed(1), multi, 5)); - assert_ok!(Balances::transfer(RuntimeOrigin::signed(2), multi, 5)); - assert_ok!(Balances::transfer(RuntimeOrigin::signed(3), multi, 5)); + assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(1), multi, 5)); + assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(2), multi, 5)); + assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(3), multi, 5)); let call = call_transfer(6, 15); let hash = blake2_256(&call.encode()); @@ -254,9 +259,9 @@ fn timepoint_checking_works() { 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(RuntimeOrigin::signed(1), multi, 5)); - assert_ok!(Balances::transfer(RuntimeOrigin::signed(2), multi, 5)); - assert_ok!(Balances::transfer(RuntimeOrigin::signed(3), multi, 5)); + assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(1), multi, 5)); + assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(2), multi, 5)); + assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(3), multi, 5)); let call = call_transfer(6, 15); let call_weight = call.get_dispatch_info().weight; @@ -287,9 +292,9 @@ 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(RuntimeOrigin::signed(1), multi, 5)); - assert_ok!(Balances::transfer(RuntimeOrigin::signed(2), multi, 5)); - assert_ok!(Balances::transfer(RuntimeOrigin::signed(3), multi, 5)); + assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(1), multi, 5)); + assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(2), multi, 5)); + assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(3), multi, 5)); let call = call_transfer(6, 15); let call_weight = call.get_dispatch_info().weight; @@ -357,9 +362,9 @@ fn cancel_multisig_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(RuntimeOrigin::signed(1), multi, 5)); - assert_ok!(Balances::transfer(RuntimeOrigin::signed(2), multi, 5)); - assert_ok!(Balances::transfer(RuntimeOrigin::signed(3), multi, 5)); + assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(1), multi, 5)); + assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(2), multi, 5)); + assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(3), multi, 5)); let call = call_transfer(6, 15); let call_weight = call.get_dispatch_info().weight; @@ -389,9 +394,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(RuntimeOrigin::signed(1), multi, 5)); - assert_ok!(Balances::transfer(RuntimeOrigin::signed(2), multi, 5)); - assert_ok!(Balances::transfer(RuntimeOrigin::signed(3), multi, 5)); + assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(1), multi, 5)); + assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(2), multi, 5)); + assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(3), multi, 5)); let call1 = call_transfer(6, 10); let call1_weight = call1.get_dispatch_info().weight; @@ -440,9 +445,9 @@ 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(RuntimeOrigin::signed(1), multi, 5)); - assert_ok!(Balances::transfer(RuntimeOrigin::signed(2), multi, 5)); - assert_ok!(Balances::transfer(RuntimeOrigin::signed(3), multi, 5)); + assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(1), multi, 5)); + assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(2), multi, 5)); + assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(3), multi, 5)); let call = call_transfer(6, 10); let call_weight = call.get_dispatch_info().weight; @@ -482,14 +487,13 @@ fn multisig_2_of_3_cannot_reissue_same_call() { call_weight )); - let err = DispatchError::from(BalancesError::::InsufficientBalance).stripped(); System::assert_last_event( pallet_multisig::Event::MultisigExecuted { approving: 3, timepoint: now(), multisig: multi, call_hash: hash, - result: Err(err), + result: Err(TokenError::FundsUnavailable.into()), } .into(), ); @@ -593,9 +597,9 @@ 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(RuntimeOrigin::signed(1), multi, 5)); - assert_ok!(Balances::transfer(RuntimeOrigin::signed(2), multi, 5)); - assert_ok!(Balances::transfer(RuntimeOrigin::signed(3), multi, 5)); + assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(1), multi, 5)); + assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(2), multi, 5)); + assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(3), multi, 5)); let call = call_transfer(6, 15); let hash = blake2_256(&call.encode()); @@ -646,9 +650,9 @@ 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(RuntimeOrigin::signed(1), multi, 5)); - assert_ok!(Balances::transfer(RuntimeOrigin::signed(2), multi, 5)); - assert_ok!(Balances::transfer(RuntimeOrigin::signed(3), multi, 5)); + assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(1), multi, 5)); + assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(2), multi, 5)); + assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(3), multi, 5)); let call = call_transfer(6, 15); assert_ok!(Multisig::as_multi( @@ -682,9 +686,9 @@ 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(RuntimeOrigin::signed(1), multi, 5)); - assert_ok!(Balances::transfer(RuntimeOrigin::signed(2), multi, 5)); - assert_ok!(Balances::transfer(RuntimeOrigin::signed(3), multi, 5)); + assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(1), multi, 5)); + assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(2), multi, 5)); + assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(3), multi, 5)); let call = call_transfer(6, 15); let call_weight = call.get_dispatch_info().weight; diff --git a/frame/nfts/src/mock.rs b/frame/nfts/src/mock.rs index f21547b720c34..91ac5d6a72203 100644 --- a/frame/nfts/src/mock.rs +++ b/frame/nfts/src/mock.rs @@ -89,6 +89,10 @@ impl pallet_balances::Config for Test { type MaxLocks = (); type MaxReserves = ConstU32<50>; type ReserveIdentifier = [u8; 8]; + type FreezeIdentifier = (); + type MaxFreezes = (); + type HoldIdentifier = (); + type MaxHolds = (); } parameter_types! { diff --git a/frame/nicks/src/lib.rs b/frame/nicks/src/lib.rs index b74d2e6ee40b2..5f510ce8e4cc0 100644 --- a/frame/nicks/src/lib.rs +++ b/frame/nicks/src/lib.rs @@ -295,6 +295,10 @@ mod tests { type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type HoldIdentifier = (); + type MaxHolds = (); } ord_parameter_types! { diff --git a/frame/nis/README.md b/frame/nis/README.md index 4eaddae1786e7..0c3f0c383a16c 100644 --- a/frame/nis/README.md +++ b/frame/nis/README.md @@ -1,2 +1,5 @@ +# NIS Module -License: Apache-2.0 +Provides a non-interactiove variant of staking. + +License: Apache-2.0 \ No newline at end of file diff --git a/frame/nis/src/benchmarking.rs b/frame/nis/src/benchmarking.rs index 6fc9fbc2bffa2..0cc9e7421d0e6 100644 --- a/frame/nis/src/benchmarking.rs +++ b/frame/nis/src/benchmarking.rs @@ -21,7 +21,9 @@ use super::*; use frame_benchmarking::v1::{account, benchmarks, whitelisted_caller, BenchmarkError}; -use frame_support::traits::{nonfungible::Inspect, Currency, EnsureOrigin, Get}; +use frame_support::traits::{ + fungible::Inspect as FunInspect, nonfungible::Inspect, EnsureOrigin, Get, +}; use frame_system::RawOrigin; use sp_arithmetic::Perquintill; use sp_runtime::{ @@ -35,7 +37,7 @@ use crate::Pallet as Nis; const SEED: u32 = 0; type BalanceOf = - <::Currency as Currency<::AccountId>>::Balance; + <::Currency as FunInspect<::AccountId>>::Balance; fn fill_queues() -> Result<(), DispatchError> { // filling queues involves filling the first queue entirely and placing a single item in all @@ -45,10 +47,7 @@ fn fill_queues() -> Result<(), DispatchError> { 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), - ); + T::Currency::set_balance(&caller, T::MinBid::get() * BalanceOf::::from(queues + bids)); for _ in 0..bids { Nis::::place_bid(RawOrigin::Signed(caller.clone()).into(), T::MinBid::get(), 1)?; @@ -63,7 +62,9 @@ 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()); + let ed = T::Currency::minimum_balance(); + let bid = T::MinBid::get(); + T::Currency::set_balance(&caller, (ed + bid) * BalanceOf::::from(l + 1) + bid); for i in 0..l { Nis::::place_bid(RawOrigin::Signed(caller.clone()).into(), T::MinBid::get(), 1)?; } @@ -75,7 +76,10 @@ 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()); + let ed = T::Currency::minimum_balance(); + let bid = T::MinBid::get(); + let ql = T::MaxQueueLen::get(); + T::Currency::set_balance(&caller, (ed + bid) * BalanceOf::::from(ql + 1) + bid); for i in 0..T::MaxQueueLen::get() { Nis::::place_bid(origin.clone().into(), T::MinBid::get(), 1)?; } @@ -90,7 +94,9 @@ benchmarks! { 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()); + let ed = T::Currency::minimum_balance(); + let bid = T::MinBid::get(); + T::Currency::set_balance(&caller, (ed + bid) * BalanceOf::::from(l + 1) + bid); for i in 0..l { Nis::::place_bid(RawOrigin::Signed(caller.clone()).into(), T::MinBid::get(), 1)?; } @@ -104,66 +110,81 @@ benchmarks! { T::FundOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; let caller: T::AccountId = whitelisted_caller(); let bid = T::MinBid::get().max(One::one()); - T::Currency::make_free_balance_be(&caller, bid); + let ed = T::Currency::minimum_balance(); + T::Currency::set_balance(&caller, ed + bid); Nis::::place_bid(RawOrigin::Signed(caller.clone()).into(), bid, 1)?; Nis::::process_queues(Perquintill::one(), 1, 1, &mut WeightCounter::unlimited()); Nis::::communify(RawOrigin::Signed(caller.clone()).into(), 0)?; - let original = T::Currency::free_balance(&Nis::::account_id()); - T::Currency::make_free_balance_be(&Nis::::account_id(), BalanceOf::::min_value()); + let original = T::Currency::balance(&Nis::::account_id()); + T::Currency::set_balance(&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(); + T::Currency::balance(&Nis::::account_id()), original).left_from_one(); assert!(missing <= Perquintill::one() / 100_000); } - thaw_private { + communify { 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)?; + let bid = T::MinBid::get().max(One::one()) * 100u32.into(); + let ed = T::Currency::minimum_balance(); + T::Currency::set_balance(&caller, ed + bid + bid); + Nis::::place_bid(RawOrigin::Signed(caller.clone()).into(), bid, 1)?; + Nis::::place_bid(RawOrigin::Signed(caller.clone()).into(), bid, 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) + }: _(RawOrigin::Signed(caller.clone()), 0) verify { - assert!(Receipts::::get(0).is_none()); + assert_eq!(Nis::::owner(&0), None); } - thaw_communal { + privatize { 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)?; + let bid = T::MinBid::get().max(One::one()); + let ed = T::Currency::minimum_balance(); + T::Currency::set_balance(&caller, ed + bid + bid); + Nis::::place_bid(RawOrigin::Signed(caller.clone()).into(), bid, 1)?; + Nis::::place_bid(RawOrigin::Signed(caller.clone()).into(), bid, 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() }); Nis::::communify(RawOrigin::Signed(caller.clone()).into(), 0)?; }: _(RawOrigin::Signed(caller.clone()), 0) verify { - assert!(Receipts::::get(0).is_none()); + assert_eq!(Nis::::owner(&0), Some(caller)); } - privatize { + thaw_private { + let whale: T::AccountId = account("whale", 0, SEED); 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)?; + let bid = T::MinBid::get().max(One::one()); + let ed = T::Currency::minimum_balance(); + T::Currency::set_balance(&caller, ed + bid + bid); + // Ensure we don't get throttled. + T::Currency::set_balance(&whale, T::ThawThrottle::get().0.saturating_reciprocal_mul_ceil(T::Currency::balance(&caller))); + Nis::::place_bid(RawOrigin::Signed(caller.clone()).into(), bid, 1)?; + Nis::::place_bid(RawOrigin::Signed(caller.clone()).into(), bid, 1)?; Nis::::process_queues(Perquintill::one(), 1, 2, &mut WeightCounter::unlimited()); - Nis::::communify(RawOrigin::Signed(caller.clone()).into(), 0)?; - }: _(RawOrigin::Signed(caller.clone()), 0) + frame_system::Pallet::::set_block_number(Receipts::::get(0).unwrap().expiry); + }: _(RawOrigin::Signed(caller.clone()), 0, None) verify { - assert_eq!(Nis::::owner(&0), Some(caller)); + assert!(Receipts::::get(0).is_none()); } - communify { + thaw_communal { + let whale: T::AccountId = account("whale", 0, SEED); 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)?; + let bid = T::MinBid::get().max(One::one()); + let ed = T::Currency::minimum_balance(); + T::Currency::set_balance(&caller, ed + bid + bid); + // Ensure we don't get throttled. + T::Currency::set_balance(&whale, T::ThawThrottle::get().0.saturating_reciprocal_mul_ceil(T::Currency::balance(&caller))); + Nis::::place_bid(RawOrigin::Signed(caller.clone()).into(), bid, 1)?; + Nis::::place_bid(RawOrigin::Signed(caller.clone()).into(), bid, 1)?; Nis::::process_queues(Perquintill::one(), 1, 2, &mut WeightCounter::unlimited()); + frame_system::Pallet::::set_block_number(Receipts::::get(0).unwrap().expiry); + Nis::::communify(RawOrigin::Signed(caller.clone()).into(), 0)?; }: _(RawOrigin::Signed(caller.clone()), 0) verify { - assert_eq!(Nis::::owner(&0), None); + assert!(Receipts::::get(0).is_none()); } process_queues { @@ -197,6 +218,9 @@ benchmarks! { process_bid { let who = account::("bidder", 0, SEED); + let min_bid = T::MinBid::get().max(One::one()); + let ed = T::Currency::minimum_balance(); + T::Currency::set_balance(&who, ed + min_bid); let bid = Bid { amount: T::MinBid::get(), who, @@ -216,5 +240,5 @@ benchmarks! { ) } - impl_benchmark_test_suite!(Nis, crate::mock::new_test_ext(), crate::mock::Test); + impl_benchmark_test_suite!(Nis, crate::mock::new_test_ext_empty(), crate::mock::Test); } diff --git a/frame/nis/src/lib.rs b/frame/nis/src/lib.rs index 6fd9c60a89836..0b8d292ec5f45 100644 --- a/frame/nis/src/lib.rs +++ b/frame/nis/src/lib.rs @@ -71,21 +71,21 @@ //! //! ## Terms //! -//! - *Effective total issuance*: The total issuance of balances in the system, including all claims -//! of all outstanding receipts but excluding `IgnoredIssuance`. +//! - *Effective total issuance*: The total issuance of balances in the system, equal to the active +//! issuance plus the value of all outstanding receipts, less `IgnoredIssuance`. #![cfg_attr(not(feature = "std"), no_std)] -use frame_support::{ - dispatch::{DispatchError, DispatchResult}, - traits::fungible::{Inspect as FungibleInspect, Mutate as FungibleMutate}, +use frame_support::traits::{ + fungible::{self, Inspect as FunInspect, Mutate as FunMutate}, + tokens::{DepositConsequence, Fortitude, Preservation, Provenance, WithdrawConsequence}, }; pub use pallet::*; use sp_arithmetic::{traits::Unsigned, RationalArg}; use sp_core::TypedGet; use sp_runtime::{ traits::{Convert, ConvertBack}, - Perquintill, + DispatchError, Perquintill, }; mod benchmarking; @@ -117,7 +117,7 @@ where } pub struct NoCounterpart(sp_std::marker::PhantomData); -impl FungibleInspect for NoCounterpart { +impl FunInspect for NoCounterpart { type Balance = u32; fn total_issuance() -> u32 { 0 @@ -125,34 +125,30 @@ impl FungibleInspect for NoCounterpart { fn minimum_balance() -> u32 { 0 } - fn balance(_who: &T) -> u32 { + fn balance(_: &T) -> u32 { 0 } - fn reducible_balance(_who: &T, _keep_alive: bool) -> u32 { + fn total_balance(_: &T) -> u32 { 0 } - fn can_deposit( - _who: &T, - _amount: u32, - _mint: bool, - ) -> frame_support::traits::tokens::DepositConsequence { - frame_support::traits::tokens::DepositConsequence::Success + fn reducible_balance(_: &T, _: Preservation, _: Fortitude) -> u32 { + 0 } - fn can_withdraw( - _who: &T, - _amount: u32, - ) -> frame_support::traits::tokens::WithdrawConsequence { - frame_support::traits::tokens::WithdrawConsequence::Success + fn can_deposit(_: &T, _: u32, _: Provenance) -> DepositConsequence { + DepositConsequence::Success } -} -impl FungibleMutate for NoCounterpart { - fn mint_into(_who: &T, _amount: u32) -> DispatchResult { - Ok(()) + fn can_withdraw(_: &T, _: u32) -> WithdrawConsequence { + WithdrawConsequence::Success } - fn burn_from(_who: &T, _amount: u32) -> Result { - Ok(0) +} +impl fungible::Unbalanced for NoCounterpart { + fn handle_dust(_: fungible::Dust) {} + fn write_balance(_: &T, _: Self::Balance) -> Result, DispatchError> { + Ok(None) } + fn set_total_issuance(_: Self::Balance) {} } +impl FunMutate for NoCounterpart {} impl Convert for NoCounterpart { fn convert(_: Perquintill) -> u32 { 0 @@ -161,15 +157,24 @@ impl Convert for NoCounterpart { #[frame_support::pallet] pub mod pallet { - use super::{FungibleInspect, FungibleMutate}; + use super::{FunInspect, FunMutate}; pub use crate::weights::WeightInfo; use frame_support::{ pallet_prelude::*, traits::{ - nonfungible::{Inspect as NonfungibleInspect, Transfer as NonfungibleTransfer}, - Currency, Defensive, DefensiveSaturating, - ExistenceRequirement::AllowDeath, - NamedReservableCurrency, OnUnbalanced, + fungible::{ + self, + hold::{Inspect as FunHoldInspect, Mutate as FunHoldMutate}, + Balanced as FunBalanced, + }, + nonfungible::{Inspect as NftInspect, Transfer as NftTransfer}, + tokens::{ + Fortitude::Polite, + Precision::{BestEffort, Exact}, + Preservation::Expendable, + Restriction::{Free, OnHold}, + }, + Defensive, DefensiveSaturating, OnUnbalanced, }, PalletId, }; @@ -177,15 +182,14 @@ pub mod pallet { use sp_arithmetic::{PerThing, Perquintill}; use sp_runtime::{ traits::{AccountIdConversion, Bounded, Convert, ConvertBack, Saturating, Zero}, - TokenError, + Rounding, TokenError, }; use sp_std::prelude::*; type BalanceOf = - <::Currency as Currency<::AccountId>>::Balance; - type PositiveImbalanceOf = <::Currency as Currency< - ::AccountId, - >>::PositiveImbalance; + <::Currency as FunInspect<::AccountId>>::Balance; + type DebtOf = + fungible::Debt<::AccountId, ::Currency>; type ReceiptRecordOf = ReceiptRecord< ::AccountId, ::BlockNumber, @@ -209,7 +213,16 @@ pub mod pallet { type PalletId: Get; /// Currency type that this works on. - type Currency: NamedReservableCurrency; + type Currency: FunInspect + + FunMutate + + FunBalanced + + FunHoldInspect + + FunHoldMutate; + + /// The identifier of the hold reason. + + #[pallet::constant] + type HoldReason: Get<>::Reason>; /// Just the `Currency::Balance` type; we have this item to allow us to constrain it to /// `From`. @@ -231,7 +244,7 @@ pub mod pallet { type IgnoredIssuance: Get>; /// The accounting system for the fungible counterpart tokens. - type Counterpart: FungibleMutate; + type Counterpart: FunMutate; /// The system to convert an overall proportion of issuance into a number of fungible /// counterpart tokens. @@ -239,12 +252,12 @@ pub mod pallet { /// In general it's best to use `WithMaximumOf`. type CounterpartAmount: ConvertBack< Perquintill, - >::Balance, + >::Balance, >; /// Unbalanced handler to account for funds created (in case of a higher total issuance over /// freezing period). - type Deficit: OnUnbalanced>; + type Deficit: OnUnbalanced>; /// The target sum of all receipts' proportions. type Target: Get; @@ -301,12 +314,6 @@ pub mod pallet { /// The maximum proportion which may be thawed and the period over which it is reset. #[pallet::constant] type ThawThrottle: Get<(Perquintill, Self::BlockNumber)>; - - /// The name for the reserve ID. - #[pallet::constant] - type ReserveId: Get< - >::ReserveIdentifier, - >; } #[pallet::pallet] @@ -348,7 +355,7 @@ pub mod pallet { /// /// `issuance - frozen + proportion * issuance` /// - /// where `issuance = total_issuance - IgnoredIssuance` + /// where `issuance = active_issuance - IgnoredIssuance` #[derive( Clone, Eq, PartialEq, Default, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen, )] @@ -473,6 +480,9 @@ pub mod pallet { AlreadyCommunal, /// The receipt is already private. AlreadyPrivate, + Release1, + Release2, + Tah, } pub(crate) struct WeightCounter { @@ -554,16 +564,17 @@ pub mod pallet { |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_named(&T::ReserveId::get(), &who, amount)?; + T::Currency::hold(&T::HoldReason::get(), &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_named( - &T::ReserveId::get(), + let _ = T::Currency::release( + &T::HoldReason::get(), &bid.who, bid.amount, + BestEffort, ); Self::deposit_event(Event::::BidDropped { who: bid.who, @@ -615,19 +626,21 @@ pub mod pallet { 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::::UnknownBid)?; - q.remove(pos); - Ok(q.len() as u32) - })?; + let mut queue = Queues::::get(duration); + let pos = queue.iter().position(|i| i == &bid).ok_or(Error::::UnknownBid)?; + queue.remove(pos); + let new_len = queue.len() as u32; + + T::Currency::release(&T::HoldReason::get(), &bid.who, bid.amount, BestEffort)?; + + Queues::::insert(duration, queue); 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_named(&T::ReserveId::get(), &bid.who, bid.amount); Self::deposit_event(Event::BidRetracted { who: bid.who, amount: bid.amount, duration }); Ok(()) @@ -645,7 +658,7 @@ pub mod pallet { let issuance = Self::issuance_with(&our_account, &summary); let deficit = issuance.required.saturating_sub(issuance.holdings); ensure!(!deficit.is_zero(), Error::::AlreadyFunded); - T::Deficit::on_unbalanced(T::Currency::deposit_creating(&our_account, deficit)); + T::Deficit::on_unbalanced(T::Currency::deposit(&our_account, deficit, Exact)?); Self::deposit_event(Event::::Funded { deficit }); Ok(()) } @@ -702,6 +715,7 @@ pub mod pallet { // 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.mul_ceil(effective_issuance); let amount = proportion * effective_issuance; receipt.proportion.saturating_reduce(proportion); @@ -710,46 +724,40 @@ pub mod pallet { let dropped = receipt.proportion.is_zero(); if amount > on_hold { - T::Currency::unreserve_named(&T::ReserveId::get(), &who, on_hold); + T::Currency::release(&T::HoldReason::get(), &who, on_hold, Exact) + .map_err(|_| Error::::Release1)?; let deficit = amount - on_hold; // Try to transfer deficit from pot to receipt owner. summary.receipts_on_hold.saturating_reduce(on_hold); on_hold = Zero::zero(); - T::Currency::transfer(&our_account, &who, deficit, AllowDeath) + T::Currency::transfer(&our_account, &who, deficit, Expendable) .map_err(|_| Error::::Unfunded)?; } else { - T::Currency::unreserve_named(&T::ReserveId::get(), &who, amount); on_hold.saturating_reduce(amount); summary.receipts_on_hold.saturating_reduce(amount); if dropped && !on_hold.is_zero() { // Reclaim any remainder: - // Transfer `excess` to the pot if we have now fully compensated for the - // receipt. - // - // This will legitimately fail if there is no pot account in existance. - // There's nothing we can do about this so we just swallow the error. - // This code is not ideal and could fail in the second phase leaving - // the system in an invalid state. It can be fixed properly with the - // new API in https://github.com/paritytech/substrate/pull/12951 - // - // Below is what it should look like then: - // let _ = T::Currency::repatriate_reserved_named( - // &T::ReserveId::get(), - // &who, - // &our_account, - // excess, - // BalanceStatus::Free, - // ).defensive(); - T::Currency::unreserve_named(&T::ReserveId::get(), &who, on_hold); - // It could theoretically be locked, so really we should be using a more - // forceful variant. But the alternative `repatriate_reserved_named` will - // fail if the destination account doesn't exist. This should be fixed when - // we move to the `fungible::*` traits, which should include a force - // transfer function to transfer the reserved balance into free balance in - // the destination regardless of locks and create it if it doesn't exist. - let _ = T::Currency::transfer(&who, &Self::account_id(), on_hold, AllowDeath); + // Transfer excess of `on_hold` to the pot if we have now fully compensated for + // the receipt. + T::Currency::transfer_on_hold( + &T::HoldReason::get(), + &who, + &our_account, + on_hold, + Exact, + Free, + Polite, + ) + .map(|_| ()) + // We ignore this error as it just means the amount we're trying to deposit is + // dust and the beneficiary account doesn't exist. + .or_else( + |e| if e == TokenError::CannotCreate.into() { Ok(()) } else { Err(e) }, + )?; summary.receipts_on_hold.saturating_reduce(on_hold); } + T::Currency::release(&T::HoldReason::get(), &who, amount, Exact) + .map_err(|_| Error::::Release2)?; } if dropped { @@ -797,7 +805,8 @@ pub mod pallet { summary.thawed.saturating_accrue(receipt.proportion); ensure!(summary.thawed <= throttle, Error::::Throttled); - T::Counterpart::burn_from(&who, T::CounterpartAmount::convert(receipt.proportion))?; + let cp_amount = T::CounterpartAmount::convert(receipt.proportion); + T::Counterpart::burn_from(&who, cp_amount, Exact, Polite)?; // Multiply the proportion it is by the total issued. let our_account = Self::account_id(); @@ -807,7 +816,7 @@ pub mod pallet { summary.proportion_owed.saturating_reduce(receipt.proportion); // Try to transfer amount owed from pot to receipt owner. - T::Currency::transfer(&our_account, &who, amount, AllowDeath) + T::Currency::transfer(&our_account, &who, amount, Expendable) .map_err(|_| Error::::Unfunded)?; Receipts::::remove(index); @@ -840,11 +849,10 @@ pub mod pallet { ensure!(owner == who, Error::::NotOwner); // Unreserve and transfer the funds to the pot. - T::Currency::unreserve_named(&T::ReserveId::get(), &who, on_hold); - // Transfer `excess` to the pot if we have now fully compensated for the receipt. - T::Currency::transfer(&who, &Self::account_id(), on_hold, AllowDeath) + let reason = T::HoldReason::get(); + let us = Self::account_id(); + T::Currency::transfer_on_hold(&reason, &who, &us, on_hold, Exact, Free, Polite) .map_err(|_| Error::::Unfunded)?; - // TODO #12951: ^^^ The above should be done in a single operation `transfer_on_hold`. // Record that we've moved the amount reserved. let mut summary: SummaryRecordOf = Summary::::get(); @@ -881,16 +889,20 @@ pub mod pallet { let effective_issuance = Self::issuance_with(&our_account, &summary).effective; let max_amount = receipt.proportion * effective_issuance; // Avoid trying to place more in the account's reserve than we have available in the pot - let amount = max_amount.min(T::Currency::free_balance(&our_account)); + let amount = max_amount.min(T::Currency::balance(&our_account)); // Burn fungible counterparts. - T::Counterpart::burn_from(&who, T::CounterpartAmount::convert(receipt.proportion))?; + T::Counterpart::burn_from( + &who, + T::CounterpartAmount::convert(receipt.proportion), + Exact, + Polite, + )?; // Transfer the funds from the pot to the owner and reserve - T::Currency::transfer(&Self::account_id(), &who, amount, AllowDeath) - .map_err(|_| Error::::Unfunded)?; - T::Currency::reserve_named(&T::ReserveId::get(), &who, amount)?; - // TODO: ^^^ The above should be done in a single operation `transfer_and_hold`. + let reason = T::HoldReason::get(); + let us = Self::account_id(); + T::Currency::transfer_and_hold(&reason, &us, &who, amount, Exact, Expendable, Polite)?; // Record that we've moved the amount reserved. summary.receipts_on_hold.saturating_accrue(amount); @@ -920,7 +932,7 @@ pub mod pallet { pub required: Balance, } - impl NonfungibleInspect for Pallet { + impl NftInspect for Pallet { type ItemId = ReceiptIndex; fn owner(item: &ReceiptIndex) -> Option { @@ -939,31 +951,19 @@ pub mod pallet { } } - impl NonfungibleTransfer for Pallet { - fn transfer(index: &ReceiptIndex, destination: &T::AccountId) -> DispatchResult { + impl NftTransfer for Pallet { + fn transfer(index: &ReceiptIndex, dest: &T::AccountId) -> DispatchResult { let mut item = Receipts::::get(index).ok_or(TokenError::UnknownAsset)?; let (owner, on_hold) = item.owner.take().ok_or(Error::::AlreadyCommunal)?; - // TODO: This should all be replaced by a single call `transfer_held`. - let shortfall = T::Currency::unreserve_named(&T::ReserveId::get(), &owner, on_hold); - if !shortfall.is_zero() { - let _ = - T::Currency::reserve_named(&T::ReserveId::get(), &owner, on_hold - shortfall); - return Err(TokenError::NoFunds.into()) - } - if let Err(e) = T::Currency::transfer(&owner, destination, on_hold, AllowDeath) { - let _ = T::Currency::reserve_named(&T::ReserveId::get(), &owner, on_hold); - return Err(e) - } - // This can never fail, and if it somehow does, then we can't handle this gracefully. - let _ = - T::Currency::reserve_named(&T::ReserveId::get(), destination, on_hold).defensive(); + let reason = T::HoldReason::get(); + T::Currency::transfer_on_hold(&reason, &owner, dest, on_hold, Exact, OnHold, Polite)?; - item.owner = Some((destination.clone(), on_hold)); + item.owner = Some((dest.clone(), on_hold)); Receipts::::insert(&index, &item); Pallet::::deposit_event(Event::::Transferred { from: owner, - to: destination.clone(), + to: dest.clone(), index: *index, }); Ok(()) @@ -997,9 +997,9 @@ pub mod pallet { summary: &SummaryRecordOf, ) -> IssuanceInfo> { let total_issuance = - T::Currency::total_issuance().saturating_sub(T::IgnoredIssuance::get()); + T::Currency::active_issuance().saturating_sub(T::IgnoredIssuance::get()); let holdings = - T::Currency::free_balance(our_account).saturating_add(summary.receipts_on_hold); + T::Currency::balance(our_account).saturating_add(summary.receipts_on_hold); let other = total_issuance.saturating_sub(holdings); let effective = summary.proportion_owed.left_from_one().saturating_reciprocal_mul(other); @@ -1136,7 +1136,9 @@ pub mod pallet { // Now to activate the bid... let n = amount; let d = issuance.effective; - let proportion = Perquintill::from_rational(n, d); + let proportion = + Perquintill::from_rational_with_rounding(n, d, Rounding::NearestPrefDown) + .defensive_unwrap_or_default(); let who = bid.who; let index = summary.index; summary.proportion_owed.defensive_saturating_accrue(proportion); diff --git a/frame/nis/src/mock.rs b/frame/nis/src/mock.rs index 8594c88a5927d..0ca6690936818 100644 --- a/frame/nis/src/mock.rs +++ b/frame/nis/src/mock.rs @@ -19,13 +19,18 @@ use crate::{self as pallet_nis, Perquintill, WithMaximumOf}; +use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ ord_parameter_types, parameter_types, - traits::{ConstU16, ConstU32, ConstU64, Currency, OnFinalize, OnInitialize, StorageMapShim}, + traits::{ + fungible::Inspect, ConstU16, ConstU32, ConstU64, Everything, OnFinalize, OnInitialize, + StorageMapShim, + }, weights::Weight, PalletId, }; use pallet_balances::{Instance1, Instance2}; +use scale_info::TypeInfo; use sp_core::{ConstU128, H256}; use sp_runtime::{ testing::Header, @@ -35,6 +40,8 @@ use sp_runtime::{ type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; type Block = frame_system::mocking::MockBlock; +pub type Balance = u64; + // Configure a mock runtime to test the pallet. frame_support::construct_runtime!( pub enum Test where @@ -50,7 +57,7 @@ frame_support::construct_runtime!( ); impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; + type BaseCallFilter = Everything; type BlockWeights = (); type BlockLength = (); type RuntimeOrigin = RuntimeOrigin; @@ -67,35 +74,45 @@ 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 = (); type SS58Prefix = ConstU16<42>; type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; + type MaxConsumers = ConstU32<16>; } impl pallet_balances::Config for Test { - type Balance = u64; + type Balance = Balance; type DustRemoval = (); type RuntimeEvent = RuntimeEvent; - type ExistentialDeposit = frame_support::traits::ConstU64<1>; + type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); type MaxLocks = (); type MaxReserves = ConstU32<1>; type ReserveIdentifier = [u8; 8]; + type FreezeIdentifier = (); + type MaxFreezes = (); + type HoldIdentifier = HoldIdentifier; + type MaxHolds = ConstU32<1>; +} + +#[derive( + Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, MaxEncodedLen, Debug, TypeInfo, +)] +pub enum HoldIdentifier { + Nis, } impl pallet_balances::Config for Test { type Balance = u128; type DustRemoval = (); type RuntimeEvent = RuntimeEvent; - type ExistentialDeposit = frame_support::traits::ConstU128<1>; + type ExistentialDeposit = ConstU128<1>; type AccountStore = StorageMapShim< pallet_balances::Account, - frame_system::Provider, u64, pallet_balances::AccountData, >; @@ -103,16 +120,20 @@ impl pallet_balances::Config for Test { type MaxLocks = (); type MaxReserves = (); type ReserveIdentifier = [u8; 8]; + type FreezeIdentifier = (); + type MaxFreezes = (); + type HoldIdentifier = (); + type MaxHolds = (); } parameter_types! { - pub IgnoredIssuance: u64 = Balances::total_balance(&0); // Account zero is ignored. + pub IgnoredIssuance: Balance = 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_parts(2_000_000_000_000, 0); - pub const ReserveId: [u8; 8] = *b"py/nis "; + pub const HoldReason: HoldIdentifier = HoldIdentifier::Nis; } ord_parameter_types! { @@ -140,7 +161,7 @@ impl pallet_nis::Config for Test { type MaxIntakeWeight = MaxIntakeWeight; type MinReceipt = MinReceipt; type ThawThrottle = ThawThrottle; - type ReserveId = ReserveId; + type HoldReason = HoldReason; } // This function basically just builds a genesis storage key/value store according to @@ -155,6 +176,13 @@ pub fn new_test_ext() -> sp_io::TestExternalities { t.into() } +// This function basically just builds a genesis storage key/value store according to +// our desired mockup, but without any balances. +#[cfg(feature = "runtime-benchmarks")] +pub fn new_test_ext_empty() -> sp_io::TestExternalities { + frame_system::GenesisConfig::default().build_storage::().unwrap().into() +} + pub fn run_to_block(n: u64) { while System::block_number() < n { Nis::on_finalize(System::block_number()); diff --git a/frame/nis/src/tests.rs b/frame/nis/src/tests.rs index d0808367ee08c..7350da97dc60a 100644 --- a/frame/nis/src/tests.rs +++ b/frame/nis/src/tests.rs @@ -22,19 +22,22 @@ use crate::{mock::*, Error}; use frame_support::{ assert_noop, assert_ok, traits::{ + fungible::{hold::Inspect as InspectHold, Inspect as FunInspect, Mutate as FunMutate}, nonfungible::{Inspect, Transfer}, - Currency, + tokens::{Fortitude::Force, Precision::Exact}, }, }; -use pallet_balances::{Error as BalancesError, Instance1}; use sp_arithmetic::Perquintill; -use sp_runtime::{Saturating, TokenError}; +use sp_runtime::{ + Saturating, + TokenError::{self, FundsUnavailable}, +}; -fn pot() -> u64 { +fn pot() -> Balance { Balances::free_balance(&Nis::account_id()) } -fn holdings() -> u64 { +fn holdings() -> Balance { Nis::issuance().holdings } @@ -42,8 +45,8 @@ fn signed(who: u64) -> RuntimeOrigin { RuntimeOrigin::signed(who) } -fn enlarge(amount: u64, max_bids: u32) { - let summary: SummaryRecord = Summary::::get(); +fn enlarge(amount: Balance, 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()); @@ -75,10 +78,7 @@ fn place_bid_works() { new_test_ext().execute_with(|| { run_to_block(1); assert_noop!(Nis::place_bid(signed(1), 1, 2), Error::::AmountTooSmall); - assert_noop!( - Nis::place_bid(signed(1), 101, 2), - BalancesError::::InsufficientBalance - ); + assert_noop!(Nis::place_bid(signed(1), 101, 2), FundsUnavailable); assert_noop!(Nis::place_bid(signed(1), 10, 4), Error::::DurationTooBig); assert_ok!(Nis::place_bid(signed(1), 10, 2)); assert_eq!(Balances::reserved_balance(1), 10); @@ -451,16 +451,16 @@ fn communify_works() { assert_noop!(Nis::thaw_communal(signed(1), 1), Error::::UnknownReceipt); // Transfer some of the fungibles away. - assert_ok!(NisBalances::transfer(signed(1), 2, 100_000)); + assert_ok!(NisBalances::transfer_allow_death(signed(1), 2, 100_000)); assert_eq!(NisBalances::free_balance(&1), 2_000_000); assert_eq!(NisBalances::free_balance(&2), 100_000); // Communal thawing with the correct index is not possible now. - assert_noop!(Nis::thaw_communal(signed(1), 0), TokenError::NoFunds); - assert_noop!(Nis::thaw_communal(signed(2), 0), TokenError::NoFunds); + assert_noop!(Nis::thaw_communal(signed(1), 0), TokenError::FundsUnavailable); + assert_noop!(Nis::thaw_communal(signed(2), 0), TokenError::FundsUnavailable); // Transfer the rest to 2... - assert_ok!(NisBalances::transfer(signed(1), 2, 2_000_000)); + assert_ok!(NisBalances::transfer_allow_death(signed(1), 2, 2_000_000)); assert_eq!(NisBalances::free_balance(&1), 0); assert_eq!(NisBalances::free_balance(&2), 2_100_000); @@ -487,8 +487,8 @@ fn privatize_works() { assert_ok!(Nis::communify(signed(1), 0)); // Transfer the fungibles to #2 - assert_ok!(NisBalances::transfer(signed(1), 2, 2_100_000)); - assert_noop!(Nis::privatize(signed(1), 0), TokenError::NoFunds); + assert_ok!(NisBalances::transfer_allow_death(signed(1), 2, 2_100_000)); + assert_noop!(Nis::privatize(signed(1), 0), TokenError::FundsUnavailable); // Privatize assert_ok!(Nis::privatize(signed(2), 0)); @@ -513,16 +513,16 @@ fn privatize_and_thaw_with_another_receipt_works() { assert_ok!(Nis::communify(signed(2), 1)); // Transfer half of fungibles to #3 from each of #1 and #2, and the other half from #2 to #4 - assert_ok!(NisBalances::transfer(signed(1), 3, 1_050_000)); - assert_ok!(NisBalances::transfer(signed(2), 3, 1_050_000)); - assert_ok!(NisBalances::transfer(signed(2), 4, 1_050_000)); + assert_ok!(NisBalances::transfer_allow_death(signed(1), 3, 1_050_000)); + assert_ok!(NisBalances::transfer_allow_death(signed(2), 3, 1_050_000)); + assert_ok!(NisBalances::transfer_allow_death(signed(2), 4, 1_050_000)); // #3 privatizes, partially thaws, then re-communifies with #0, then transfers the fungibles // to #2 assert_ok!(Nis::privatize(signed(3), 0)); assert_ok!(Nis::thaw_private(signed(3), 0, Some(Perquintill::from_percent(5)))); assert_ok!(Nis::communify(signed(3), 0)); - assert_ok!(NisBalances::transfer(signed(3), 1, 1_050_000)); + assert_ok!(NisBalances::transfer_allow_death(signed(3), 1, 1_050_000)); // #1 now has enough to thaw using receipt 1 assert_ok!(Nis::thaw_communal(signed(1), 1)); @@ -536,17 +536,21 @@ fn privatize_and_thaw_with_another_receipt_works() { fn communal_thaw_when_issuance_higher_works() { new_test_ext().execute_with(|| { run_to_block(1); + assert_ok!(Balances::transfer_allow_death(signed(2), 1, 1)); assert_ok!(Nis::place_bid(signed(1), 100, 1)); enlarge(100, 1); + assert_eq!(Balances::total_balance(&1), 101); assert_ok!(Nis::communify(signed(1), 0)); + assert_eq!(Balances::total_balance_on_hold(&1), 0); + assert_eq!(Balances::total_balance(&1), 1); - assert_eq!(NisBalances::free_balance(1), 5_250_000); // (25% of 21m) + assert_eq!(NisBalances::free_balance(1), 5_250_000); // (12.5% 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); + assert_ok!(Balances::mint_into(&2, 50)); + assert_ok!(Balances::mint_into(&3, 50)); + assert_ok!(Balances::mint_into(&4, 50)); run_to_block(4); @@ -556,16 +560,20 @@ fn communal_thaw_when_issuance_higher_works() { assert_ok!(Nis::fund_deficit(signed(1))); // Transfer counterparts away... - assert_ok!(NisBalances::transfer(signed(1), 2, 250_000)); + assert_ok!(NisBalances::transfer_allow_death(signed(1), 2, 125_000)); // ...and it's not thawable. - assert_noop!(Nis::thaw_communal(signed(1), 0), TokenError::NoFunds); + assert_noop!(Nis::thaw_communal(signed(1), 0), TokenError::FundsUnavailable); // Transfer counterparts back... - assert_ok!(NisBalances::transfer(signed(2), 1, 250_000)); + assert_ok!(NisBalances::transfer_allow_death(signed(2), 1, 125_000)); // ...and it is. assert_ok!(Nis::thaw_communal(signed(1), 0)); + assert_eq!(Balances::total_balance(&1), 151); + assert_ok!(Balances::transfer_allow_death(signed(1), 2, 1)); + assert_eq!(Balances::total_balance(&1), 150); assert_eq!(Balances::free_balance(1), 150); + assert_eq!(Balances::total_balance_on_hold(&1), 0); assert_eq!(Balances::reserved_balance(1), 0); }); } @@ -574,13 +582,14 @@ fn communal_thaw_when_issuance_higher_works() { fn private_thaw_when_issuance_higher_works() { new_test_ext().execute_with(|| { run_to_block(1); + assert_ok!(Balances::transfer_allow_death(signed(2), 1, 1)); assert_ok!(Nis::place_bid(signed(1), 100, 1)); 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); + assert_ok!(Balances::mint_into(&2, 50)); + assert_ok!(Balances::mint_into(&3, 50)); + assert_ok!(Balances::mint_into(&4, 50)); run_to_block(4); @@ -591,6 +600,7 @@ fn private_thaw_when_issuance_higher_works() { assert_ok!(Nis::thaw_private(signed(1), 0, None)); + assert_ok!(Balances::transfer_allow_death(signed(1), 2, 1)); assert_eq!(Balances::free_balance(1), 150); assert_eq!(Balances::reserved_balance(1), 0); }); @@ -601,15 +611,16 @@ 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!(Balances::mint_into(&0, 200)); + assert_ok!(Balances::transfer_allow_death(signed(2), 1, 1)); assert_ok!(Nis::place_bid(signed(1), 100, 1)); enlarge(100, 1); // Account zero transfers 50 into everyone else's accounts. - assert_ok!(Balances::transfer(signed(0), 2, 50)); - assert_ok!(Balances::transfer(signed(0), 3, 50)); - assert_ok!(Balances::transfer(signed(0), 4, 50)); + assert_ok!(Balances::transfer_allow_death(signed(0), 2, 50)); + assert_ok!(Balances::transfer_allow_death(signed(0), 3, 50)); + assert_ok!(Balances::transfer_allow_death(signed(0), 4, 50)); run_to_block(4); // Unfunded initially... @@ -620,6 +631,7 @@ fn thaw_with_ignored_issuance_works() { assert_ok!(Nis::thaw_private(signed(1), 0, None)); // Account zero changes have been ignored. + assert_ok!(Balances::transfer_allow_death(signed(1), 2, 1)); assert_eq!(Balances::free_balance(1), 150); assert_eq!(Balances::reserved_balance(1), 0); }); @@ -629,17 +641,19 @@ fn thaw_with_ignored_issuance_works() { fn thaw_when_issuance_lower_works() { new_test_ext().execute_with(|| { run_to_block(1); + assert_ok!(Balances::transfer_allow_death(signed(2), 1, 1)); assert_ok!(Nis::place_bid(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); + assert_ok!(Balances::burn_from(&2, 25, Exact, Force)); + assert_ok!(Balances::burn_from(&3, 25, Exact, Force)); + assert_ok!(Balances::burn_from(&4, 25, Exact, Force)); run_to_block(4); assert_ok!(Nis::thaw_private(signed(1), 0, None)); + assert_ok!(Balances::transfer_allow_death(signed(1), 2, 1)); assert_eq!(Balances::free_balance(1), 75); assert_eq!(Balances::reserved_balance(1), 0); }); @@ -649,15 +663,16 @@ fn thaw_when_issuance_lower_works() { fn multiple_thaws_works() { new_test_ext().execute_with(|| { run_to_block(1); + assert_ok!(Balances::transfer_allow_death(signed(3), 1, 1)); assert_ok!(Nis::place_bid(signed(1), 40, 1)); assert_ok!(Nis::place_bid(signed(1), 60, 1)); assert_ok!(Nis::place_bid(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!(Balances::mint_into(&2, 50)); + assert_ok!(Balances::mint_into(&3, 100)); + assert_ok!(Balances::mint_into(&4, 100)); assert_ok!(Nis::fund_deficit(signed(1))); run_to_block(4); @@ -667,8 +682,11 @@ fn multiple_thaws_works() { run_to_block(5); assert_ok!(Nis::thaw_private(signed(2), 2, None)); + assert_ok!(Balances::transfer_allow_death(signed(1), 3, 1)); assert_eq!(Balances::free_balance(1), 200); assert_eq!(Balances::free_balance(2), 200); + assert_eq!(Balances::total_balance(&1), 200); + assert_eq!(Balances::total_balance(&2), 200); }); } @@ -676,15 +694,16 @@ fn multiple_thaws_works() { fn multiple_thaws_works_in_alternative_thaw_order() { new_test_ext().execute_with(|| { run_to_block(1); + assert_ok!(Balances::transfer_allow_death(signed(3), 1, 1)); assert_ok!(Nis::place_bid(signed(1), 40, 1)); assert_ok!(Nis::place_bid(signed(1), 60, 1)); assert_ok!(Nis::place_bid(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!(Balances::mint_into(&2, 50)); + assert_ok!(Balances::mint_into(&3, 100)); + assert_ok!(Balances::mint_into(&4, 100)); assert_ok!(Nis::fund_deficit(signed(1))); run_to_block(4); @@ -695,8 +714,11 @@ fn multiple_thaws_works_in_alternative_thaw_order() { run_to_block(5); assert_ok!(Nis::thaw_private(signed(1), 1, None)); + assert_ok!(Balances::transfer_allow_death(signed(1), 3, 1)); assert_eq!(Balances::free_balance(1), 200); assert_eq!(Balances::free_balance(2), 200); + assert_eq!(Balances::total_balance(&1), 200); + assert_eq!(Balances::total_balance(&2), 200); }); } diff --git a/frame/nomination-pools/benchmarking/src/mock.rs b/frame/nomination-pools/benchmarking/src/mock.rs index 4a1a52868e367..cffb712ea2ae5 100644 --- a/frame/nomination-pools/benchmarking/src/mock.rs +++ b/frame/nomination-pools/benchmarking/src/mock.rs @@ -75,6 +75,10 @@ impl pallet_balances::Config for Runtime { type ExistentialDeposit = ExistentialDeposit; type AccountStore = System; type WeightInfo = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type HoldIdentifier = (); + type MaxHolds = (); } pallet_staking_reward_curve::build! { diff --git a/frame/nomination-pools/src/mock.rs b/frame/nomination-pools/src/mock.rs index c6b094f0aa0f1..6d83ef61de793 100644 --- a/frame/nomination-pools/src/mock.rs +++ b/frame/nomination-pools/src/mock.rs @@ -196,6 +196,10 @@ impl pallet_balances::Config for Runtime { type ExistentialDeposit = ExistentialDeposit; type AccountStore = System; type WeightInfo = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type HoldIdentifier = (); + type MaxHolds = (); } pub struct BalanceToU256; diff --git a/frame/nomination-pools/src/tests.rs b/frame/nomination-pools/src/tests.rs index a4fda2e5d91b3..4cb255e23b4b8 100644 --- a/frame/nomination-pools/src/tests.rs +++ b/frame/nomination-pools/src/tests.rs @@ -39,6 +39,16 @@ macro_rules! member_unbonding_eras { pub const DEFAULT_ROLES: PoolRoles = PoolRoles { depositor: 10, root: Some(900), nominator: Some(901), bouncer: Some(902) }; +fn deposit_rewards(r: u128) { + let b = Balances::free_balance(&default_reward_account()).checked_add(r).unwrap(); + Balances::make_free_balance_be(&default_reward_account(), b); +} + +fn remove_rewards(r: u128) { + let b = Balances::free_balance(&default_reward_account()).checked_sub(r).unwrap(); + Balances::make_free_balance_be(&default_reward_account(), b); +} + #[test] fn test_setup_works() { ExtBuilder::default().build_and_execute(|| { @@ -469,6 +479,8 @@ mod sub_pools { } mod join { + use sp_runtime::TokenError; + use super::*; #[test] @@ -592,7 +604,7 @@ mod join { // Balance needs to be gt Balance::MAX / `MaxPointsToBalance` assert_noop!( Pools::join(RuntimeOrigin::signed(11), 5, 123), - pallet_balances::Error::::InsufficientBalance, + TokenError::FundsUnavailable, ); StakingMock::set_bonded_balance(Pools::create_bonded_account(1), max_points_to_balance); @@ -749,7 +761,7 @@ mod claim_payout { // and the reward pool has earned 100 in rewards assert_eq!(Balances::free_balance(default_reward_account()), ed); - assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 100)); + deposit_rewards(100); let _ = pool_events_since_last_call(); @@ -796,7 +808,7 @@ mod claim_payout { assert_eq!(Balances::free_balance(&default_reward_account()), ed); // Given the reward pool has some new rewards - assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 50)); + deposit_rewards(50); // When assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); @@ -825,7 +837,7 @@ mod claim_payout { 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)); + deposit_rewards(50); assert_eq!(Balances::free_balance(&default_reward_account()), ed + 75); // When @@ -855,7 +867,7 @@ mod claim_payout { 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)); + deposit_rewards(400); assert_eq!(Balances::free_balance(&default_reward_account()), ed + 420); // When @@ -874,7 +886,7 @@ mod claim_payout { 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)); + deposit_rewards(20); assert_eq!(Balances::free_balance(&default_reward_account()), ed + 400); // When @@ -974,7 +986,7 @@ mod claim_payout { ); // The pool earns 10 points - assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 10)); + deposit_rewards(10); assert_ok!(Pools::do_reward_payout( &10, @@ -1010,7 +1022,7 @@ mod claim_payout { assert_eq!(reward_pool, rew(0, 0, 0)); // Given the pool has earned some rewards for the first time - assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 5)); + deposit_rewards(5); // When let payout = @@ -1031,7 +1043,7 @@ mod claim_payout { assert_eq!(member, del(0.5)); // Given the pool has earned rewards again - assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 10)); + deposit_rewards(10); // When let payout = @@ -1090,7 +1102,7 @@ mod claim_payout { assert_eq!(bonded_pool.points, 100); // and the reward pool has earned 100 in rewards - assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 100)); + deposit_rewards(100); // When let payout = @@ -1135,7 +1147,7 @@ mod claim_payout { assert_eq!(reward_pool, rew(0, 0, 100)); // Given the reward pool has some new rewards - assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 50)); + deposit_rewards(50); // When let payout = @@ -1166,7 +1178,7 @@ mod claim_payout { 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)); + deposit_rewards(50); // When let payout = @@ -1197,7 +1209,7 @@ mod claim_payout { 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)); + deposit_rewards(400); // When let payout = @@ -1214,7 +1226,7 @@ mod claim_payout { 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)); + deposit_rewards(20); // When let payout = @@ -1252,14 +1264,14 @@ mod claim_payout { 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(); + deposit_rewards(10); // 20 joins afterwards. Balances::make_free_balance_be(&20, Balances::minimum_balance() + 10); assert_ok!(Pools::join(RuntimeOrigin::signed(20), 10, 1)); // reward by another 20 - Balances::mutate_account(&default_reward_account(), |f| f.free += 20).unwrap(); + deposit_rewards(20); // 10 should claim 10 + 10, 20 should claim 20 / 2. assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); @@ -1276,7 +1288,7 @@ mod claim_payout { ); // any upcoming rewards are shared equally. - Balances::mutate_account(&default_reward_account(), |f| f.free += 20).unwrap(); + deposit_rewards(20); assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(20))); @@ -1296,12 +1308,12 @@ mod claim_payout { // 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(); + deposit_rewards(3); Balances::make_free_balance_be(&20, Balances::minimum_balance() + 10); assert_ok!(Pools::join(RuntimeOrigin::signed(20), 10, 1)); - Balances::mutate_account(&default_reward_account(), |f| f.free += 6).unwrap(); + deposit_rewards(6); // 10 should claim 3, 20 should claim 3 + 3. assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); @@ -1319,7 +1331,7 @@ mod claim_payout { ); // any upcoming rewards are shared equally. - Balances::mutate_account(&default_reward_account(), |f| f.free += 8).unwrap(); + deposit_rewards(8); assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(20))); @@ -1333,7 +1345,7 @@ mod claim_payout { ); // uneven upcoming rewards are shared equally, rounded down. - Balances::mutate_account(&default_reward_account(), |f| f.free += 7).unwrap(); + deposit_rewards(7); assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(20))); @@ -1353,17 +1365,17 @@ mod claim_payout { ExtBuilder::default().build_and_execute(|| { let ed = Balances::minimum_balance(); - Balances::mutate_account(&default_reward_account(), |f| f.free += 30).unwrap(); + deposit_rewards(30); Balances::make_free_balance_be(&20, ed + 10); assert_ok!(Pools::join(RuntimeOrigin::signed(20), 10, 1)); - Balances::mutate_account(&default_reward_account(), |f| f.free += 100).unwrap(); + deposit_rewards(100); Balances::make_free_balance_be(&30, ed + 10); assert_ok!(Pools::join(RuntimeOrigin::signed(30), 10, 1)); - Balances::mutate_account(&default_reward_account(), |f| f.free += 60).unwrap(); + deposit_rewards(60); // 10 should claim 10, 20 should claim nothing. assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); @@ -1384,7 +1396,7 @@ mod claim_payout { ); // any upcoming rewards are shared equally. - Balances::mutate_account(&default_reward_account(), |f| f.free += 30).unwrap(); + deposit_rewards(30); assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(20))); @@ -1407,7 +1419,7 @@ mod claim_payout { let ed = Balances::minimum_balance(); assert_eq!(Pools::api_pending_rewards(10), Some(0)); - Balances::mutate_account(&default_reward_account(), |f| f.free += 30).unwrap(); + deposit_rewards(30); assert_eq!(Pools::api_pending_rewards(10), Some(30)); assert_eq!(Pools::api_pending_rewards(20), None); @@ -1417,7 +1429,7 @@ mod claim_payout { assert_eq!(Pools::api_pending_rewards(10), Some(30)); assert_eq!(Pools::api_pending_rewards(20), Some(0)); - Balances::mutate_account(&default_reward_account(), |f| f.free += 100).unwrap(); + deposit_rewards(100); assert_eq!(Pools::api_pending_rewards(10), Some(30 + 50)); assert_eq!(Pools::api_pending_rewards(20), Some(50)); @@ -1430,7 +1442,7 @@ mod claim_payout { assert_eq!(Pools::api_pending_rewards(20), Some(50)); assert_eq!(Pools::api_pending_rewards(30), Some(0)); - Balances::mutate_account(&default_reward_account(), |f| f.free += 60).unwrap(); + deposit_rewards(60); assert_eq!(Pools::api_pending_rewards(10), Some(30 + 50 + 20)); assert_eq!(Pools::api_pending_rewards(20), Some(50 + 20)); @@ -1464,7 +1476,7 @@ mod claim_payout { Balances::make_free_balance_be(&30, ed + 20); assert_ok!(Pools::join(RuntimeOrigin::signed(30), 10, 1)); - Balances::mutate_account(&default_reward_account(), |f| f.free += 40).unwrap(); + deposit_rewards(40); // everyone claims. assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); @@ -1488,7 +1500,7 @@ mod claim_payout { 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(); + deposit_rewards(100); assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(20))); @@ -1514,7 +1526,7 @@ mod claim_payout { Balances::make_free_balance_be(&20, ed + 20); assert_ok!(Pools::join(RuntimeOrigin::signed(20), 20, 1)); - Balances::mutate_account(&default_reward_account(), |f| f.free += 30).unwrap(); + deposit_rewards(30); // everyone claims. assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); @@ -1535,7 +1547,7 @@ mod claim_payout { assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 10)); // more rewards come in. - Balances::mutate_account(&default_reward_account(), |f| f.free += 100).unwrap(); + deposit_rewards(100); assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(20))); @@ -1562,7 +1574,7 @@ mod claim_payout { 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(); + deposit_rewards(40); // some claim. assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); @@ -1581,7 +1593,7 @@ mod claim_payout { ); // 10 gets 20, 20 gets 40, 30 gets 20 - Balances::mutate_account(&default_reward_account(), |f| f.free += 80).unwrap(); + deposit_rewards(80); // some claim. assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); @@ -1596,7 +1608,7 @@ mod claim_payout { ); // 10 gets 20, 20 gets 40, 30 gets 20 - Balances::mutate_account(&default_reward_account(), |f| f.free += 80).unwrap(); + deposit_rewards(80); // some claim. assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); @@ -1629,7 +1641,7 @@ mod claim_payout { 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(); + deposit_rewards(30); // some claim. assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); @@ -1645,7 +1657,7 @@ mod claim_payout { ); // 20 has not claimed yet, more reward comes - Balances::mutate_account(&default_reward_account(), |f| f.free += 60).unwrap(); + deposit_rewards(60); // and 20 bonds more -- they should not have more share of this reward. assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(20), BondExtra::FreeBalance(10))); @@ -1665,7 +1677,7 @@ mod claim_payout { ); // 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(); + deposit_rewards(60); // everyone claim. assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); @@ -1695,7 +1707,7 @@ mod claim_payout { 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(); + deposit_rewards(60); // create pool 2 Balances::make_free_balance_be(&20, 100); @@ -1779,7 +1791,7 @@ mod claim_payout { } // transfer some reward to pool 1. - Balances::mutate_account(&default_reward_account(), |f| f.free += 60).unwrap(); + deposit_rewards(60); { join(30, 10); @@ -1849,7 +1861,7 @@ mod claim_payout { // 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(); + deposit_rewards(30); { assert_ok!(Pools::bond_extra( @@ -1905,7 +1917,7 @@ mod claim_payout { MaxPoolMembersPerPool::::set(None); // pool receives some rewards. - Balances::mutate_account(&default_reward_account(), |f| f.free += 30).unwrap(); + deposit_rewards(30); System::reset_events(); // 10 cashes it out, and bonds it. @@ -1975,7 +1987,7 @@ mod claim_payout { } // some rewards come in. - Balances::mutate_account(&default_reward_account(), |f| f.free += 30).unwrap(); + deposit_rewards(30); // and 30 also unbonds half. { @@ -2058,7 +2070,7 @@ mod claim_payout { ); // some rewards come in. - Balances::mutate_account(&default_reward_account(), |f| f.free += 40).unwrap(); + deposit_rewards(40); // everyone claims assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); @@ -2120,8 +2132,7 @@ mod claim_payout { .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(); + deposit_rewards(unit / 1000); // everyone claims assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); @@ -3329,11 +3340,7 @@ mod withdraw_unbonded { ); assert_eq!( balances_events_since_last_call(), - vec![BEvent::BalanceSet { - who: default_bonded_account(), - free: 300, - reserved: 0 - }] + vec![BEvent::BalanceSet { who: default_bonded_account(), free: 300 }] ); // When @@ -3447,11 +3454,7 @@ mod withdraw_unbonded { ); assert_eq!( balances_events_since_last_call(), - vec![BEvent::BalanceSet { - who: default_bonded_account(), - free: 300, - reserved: 0 - },] + vec![BEvent::BalanceSet { who: default_bonded_account(), free: 300 },] ); CurrentEra::set(StakingMock::bonding_duration()); @@ -5078,18 +5081,15 @@ mod reward_counter_precision { 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)); + deposit_rewards(expected_smallest_reward - 1); assert_ok!(Pools::claim_payout(RuntimeOrigin::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)); + remove_rewards(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)); + deposit_rewards(expected_smallest_reward + 1); assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); assert_eq!( pool_events_since_last_call(), @@ -5114,9 +5114,7 @@ mod reward_counter_precision { 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)) - ); + deposit_rewards(inflation(1)); // now claim. assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); @@ -5155,8 +5153,7 @@ mod reward_counter_precision { // 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)); + deposit_rewards(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. @@ -5186,7 +5183,7 @@ mod reward_counter_precision { 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)); + deposit_rewards(DOT); assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(30))); assert_eq!( @@ -5258,9 +5255,7 @@ mod reward_counter_precision { assert_ok!(Pools::join(RuntimeOrigin::signed(20), 10 * DOT, 1)); // earn some small rewards - assert_ok!( - Balances::mutate_account(&default_reward_account(), |a| a.free += DOT / 1000) - ); + deposit_rewards(DOT / 1000); // no point in claiming for 20 (nonetheless, it should be harmless) assert!(pending_rewards(20).unwrap().is_zero()); @@ -5280,9 +5275,7 @@ mod reward_counter_precision { // 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) - ); + deposit_rewards(DOT / 1000); assert!(pending_rewards(20).unwrap().is_zero()); assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); assert_eq!( @@ -5291,9 +5284,7 @@ mod reward_counter_precision { ); // earn some more rewards, this time 20 can also claim. - assert_ok!( - Balances::mutate_account(&default_reward_account(), |a| a.free += DOT / 1000) - ); + deposit_rewards(DOT / 1000); assert_eq!(pending_rewards(20).unwrap(), 1); assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(20))); @@ -5332,9 +5323,7 @@ mod reward_counter_precision { assert_ok!(Pools::join(RuntimeOrigin::signed(20), 10 * DOT, 1)); // earn some small rewards - assert_ok!( - Balances::mutate_account(&default_reward_account(), |a| a.free += DOT / 1000) - ); + deposit_rewards(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 @@ -5442,7 +5431,7 @@ mod commission { // Pool earns 80 points and a payout is triggered. // Given: - assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 80)); + deposit_rewards(80); assert_eq!( PoolMembers::::get(10).unwrap(), PoolMember:: { pool_id, points: 10, ..Default::default() } @@ -5489,7 +5478,7 @@ mod commission { // is next called, which is not done in this test segment.. // Given: - assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 100)); + deposit_rewards(100); // When: assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); @@ -5625,7 +5614,7 @@ mod commission { 1, Some((Perbill::from_percent(10), root)), )); - assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 40)); + deposit_rewards(40); // When: assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); @@ -6377,7 +6366,7 @@ mod commission { ); // The pool earns 10 points - assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 10)); + deposit_rewards(10); assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); // Then: @@ -6387,7 +6376,7 @@ mod commission { ); // The pool earns 17 points - assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 17)); + deposit_rewards(17); assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); // Then: @@ -6397,7 +6386,7 @@ mod commission { ); // The pool earns 50 points - assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 50)); + deposit_rewards(50); assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); // Then: @@ -6407,7 +6396,7 @@ mod commission { ); // The pool earns 10439 points - assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 10439)); + deposit_rewards(10439); assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); // Then: @@ -6427,7 +6416,7 @@ mod commission { )); // Given: - assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 200)); + deposit_rewards(200); assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); // Then: @@ -6469,7 +6458,7 @@ mod commission { // When: // The pool earns 100 points - assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 100)); + deposit_rewards(100); // Change commission to 20% assert_ok!(Pools::set_commission( @@ -6486,7 +6475,7 @@ mod commission { ); // The pool earns 100 points - assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 100)); + deposit_rewards(100); // Then: @@ -6535,7 +6524,7 @@ mod commission { // When: // The pool earns 100 points - assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 100)); + deposit_rewards(100); // Claim payout: assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); @@ -6592,7 +6581,7 @@ mod commission { ); // The pool earns 10 points - assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 10)); + deposit_rewards(10); // execute the payout assert_ok!(Pools::do_reward_payout( @@ -6634,7 +6623,7 @@ mod commission { ); // The pool earns 10 points - assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 10)); + deposit_rewards(10); // execute the payout assert_ok!(Pools::do_reward_payout( @@ -6677,7 +6666,7 @@ mod commission { ); // Pool earns 80 points, payout is triggered. - assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 80)); + deposit_rewards(80); assert_eq!( PoolMembers::::get(10).unwrap(), PoolMember:: { pool_id, points: 10, ..Default::default() } diff --git a/frame/nomination-pools/test-staking/src/mock.rs b/frame/nomination-pools/test-staking/src/mock.rs index 0550c8e0ca708..9726f5e6dad27 100644 --- a/frame/nomination-pools/test-staking/src/mock.rs +++ b/frame/nomination-pools/test-staking/src/mock.rs @@ -86,6 +86,10 @@ impl pallet_balances::Config for Runtime { type ExistentialDeposit = ExistentialDeposit; type AccountStore = System; type WeightInfo = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type HoldIdentifier = (); + type MaxHolds = (); } pallet_staking_reward_curve::build! { diff --git a/frame/offences/benchmarking/src/mock.rs b/frame/offences/benchmarking/src/mock.rs index 233aa449d391c..058361e9f77e8 100644 --- a/frame/offences/benchmarking/src/mock.rs +++ b/frame/offences/benchmarking/src/mock.rs @@ -74,6 +74,10 @@ impl pallet_balances::Config for Test { type ExistentialDeposit = ConstU64<10>; type AccountStore = System; type WeightInfo = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type HoldIdentifier = (); + type MaxHolds = (); } impl pallet_timestamp::Config for Test { diff --git a/frame/preimage/src/mock.rs b/frame/preimage/src/mock.rs index 23875ccb0ef7a..5054a77a8123f 100644 --- a/frame/preimage/src/mock.rs +++ b/frame/preimage/src/mock.rs @@ -84,6 +84,10 @@ impl pallet_balances::Config for Test { type MaxLocks = (); type MaxReserves = ConstU32<50>; type ReserveIdentifier = [u8; 8]; + type FreezeIdentifier = (); + type MaxFreezes = (); + type HoldIdentifier = (); + type MaxHolds = (); } ord_parameter_types! { diff --git a/frame/proxy/src/tests.rs b/frame/proxy/src/tests.rs index c49c344aca107..f3771083c4dd4 100644 --- a/frame/proxy/src/tests.rs +++ b/frame/proxy/src/tests.rs @@ -88,6 +88,10 @@ impl pallet_balances::Config for Test { type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type HoldIdentifier = (); + type MaxHolds = (); } impl pallet_utility::Config for Test { type RuntimeEvent = RuntimeEvent; @@ -124,7 +128,10 @@ impl InstanceFilter for ProxyType { match self { ProxyType::Any => true, ProxyType::JustTransfer => { - matches!(c, RuntimeCall::Balances(pallet_balances::Call::transfer { .. })) + matches!( + c, + RuntimeCall::Balances(pallet_balances::Call::transfer_allow_death { .. }) + ) }, ProxyType::JustUtility => matches!(c, RuntimeCall::Utility { .. }), } @@ -161,7 +168,7 @@ impl Config for Test { use super::{Call as ProxyCall, Event as ProxyEvent}; use frame_system::Call as SystemCall; -use pallet_balances::{Call as BalancesCall, Error as BalancesError, Event as BalancesEvent}; +use pallet_balances::{Call as BalancesCall, Event as BalancesEvent}; use pallet_utility::{Call as UtilityCall, Event as UtilityEvent}; type SystemError = frame_system::Error; @@ -169,7 +176,7 @@ 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:: { - balances: vec![(1, 10), (2, 10), (3, 10), (4, 10), (5, 2)], + balances: vec![(1, 10), (2, 10), (3, 10), (4, 10), (5, 3)], } .assimilate_storage(&mut t) .unwrap(); @@ -193,7 +200,7 @@ fn expect_events(e: Vec) { } fn call_transfer(dest: u64, value: u64) -> RuntimeCall { - RuntimeCall::Balances(BalancesCall::transfer { dest, value }) + RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest, value }) } #[test] @@ -345,7 +352,7 @@ fn proxy_announced_removes_announcement_and_returns_deposit() { #[test] fn filtering_works() { new_test_ext().execute_with(|| { - assert!(Balances::mutate_account(&1, |a| a.free = 1000).is_ok()); + Balances::make_free_balance_be(&1, 1000); 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)); @@ -361,7 +368,7 @@ fn filtering_works() { ); let derivative_id = Utility::derivative_account_id(1, 0); - assert!(Balances::mutate_account(&derivative_id, |a| a.free = 1000).is_ok()); + Balances::make_free_balance_be(&derivative_id, 1000); let inner = Box::new(call_transfer(6, 1)); let call = Box::new(RuntimeCall::Utility(UtilityCall::as_derivative { @@ -516,7 +523,7 @@ fn cannot_add_proxy_without_balance() { assert_eq!(Balances::reserved_balance(5), 2); assert_noop!( Proxy::add_proxy(RuntimeOrigin::signed(5), 4, ProxyType::Any, 0), - BalancesError::::InsufficientBalance + DispatchError::ConsumerRemaining, ); }); } @@ -564,6 +571,7 @@ fn proxying_works() { #[test] fn pure_works() { new_test_ext().execute_with(|| { + Balances::make_free_balance_be(&1, 11); // An extra one for the ED. 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( @@ -592,7 +600,7 @@ fn pure_works() { 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)); + assert_ok!(Balances::transfer_allow_death(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); @@ -611,9 +619,9 @@ fn pure_works() { Proxy::kill_pure(RuntimeOrigin::signed(1), 1, ProxyType::Any, 0, 1, 0), Error::::NoPermission ); - assert_eq!(Balances::free_balance(1), 0); + assert_eq!(Balances::free_balance(1), 1); assert_ok!(Proxy::proxy(RuntimeOrigin::signed(1), anon, None, call.clone())); - assert_eq!(Balances::free_balance(1), 2); + assert_eq!(Balances::free_balance(1), 3); assert_noop!( Proxy::proxy(RuntimeOrigin::signed(1), anon, None, call.clone()), Error::::NotProxy diff --git a/frame/recovery/src/mock.rs b/frame/recovery/src/mock.rs index 1d21be801c85c..5c190e2a241a5 100644 --- a/frame/recovery/src/mock.rs +++ b/frame/recovery/src/mock.rs @@ -86,6 +86,10 @@ impl pallet_balances::Config for Test { type ExistentialDeposit = ExistentialDeposit; type AccountStore = System; type WeightInfo = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type HoldIdentifier = (); + type MaxHolds = (); } parameter_types! { diff --git a/frame/recovery/src/tests.rs b/frame/recovery/src/tests.rs index 9381d6a881ef1..85024d0bc4a9d 100644 --- a/frame/recovery/src/tests.rs +++ b/frame/recovery/src/tests.rs @@ -45,7 +45,10 @@ fn set_recovered_works() { // Root can set a recovered account though 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 })); + let call = Box::new(RuntimeCall::Balances(BalancesCall::transfer_allow_death { + dest: 1, + value: 100, + })); 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); @@ -93,7 +96,10 @@ fn recovery_life_cycle_works() { 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 })); + let call = Box::new(RuntimeCall::Balances(BalancesCall::transfer_allow_death { + dest: 1, + value: 110, + })); assert_ok!(Recovery::as_recovered(RuntimeOrigin::signed(1), 5, call)); // All funds have been fully recovered! assert_eq!(Balances::free_balance(1), 200); diff --git a/frame/referenda/src/migration.rs b/frame/referenda/src/migration.rs index e15eb499b42fc..c27ab452ac637 100644 --- a/frame/referenda/src/migration.rs +++ b/frame/referenda/src/migration.rs @@ -191,7 +191,7 @@ pub mod test { #[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_encoded = sp_core::Bytes::from_str("0x00000000012c01082a0000000000000004000100000000000000010000000000000001000000000000000a00000000000000000000000000000000000100").unwrap(); let ongoing_dec = v0::ReferendumInfoOf::::decode(&mut &*ongoing_encoded).unwrap(); let ongoing = v0::ReferendumInfoOf::::Ongoing(create_status_v0()); assert_eq!(ongoing, ongoing_dec); diff --git a/frame/referenda/src/mock.rs b/frame/referenda/src/mock.rs index ade2a09a9f9a4..cdedb79556f35 100644 --- a/frame/referenda/src/mock.rs +++ b/frame/referenda/src/mock.rs @@ -57,7 +57,7 @@ frame_support::construct_runtime!( pub struct BaseFilter; impl Contains for BaseFilter { fn contains(call: &RuntimeCall) -> bool { - !matches!(call, &RuntimeCall::Balances(pallet_balances::Call::set_balance { .. })) + !matches!(call, &RuntimeCall::Balances(pallet_balances::Call::force_set_balance { .. })) } } @@ -120,6 +120,10 @@ impl pallet_balances::Config for Test { type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type HoldIdentifier = (); + type MaxHolds = (); } parameter_types! { pub static AlarmInterval: u64 = 1; @@ -295,19 +299,14 @@ impl VoteTally for Tally { } pub fn set_balance_proposal(value: u64) -> Vec { - RuntimeCall::Balances(pallet_balances::Call::set_balance { - who: 42, - new_free: value, - new_reserved: 0, - }) - .encode() + RuntimeCall::Balances(pallet_balances::Call::force_set_balance { who: 42, new_free: value }) + .encode() } pub fn set_balance_proposal_bounded(value: u64) -> BoundedCallOf { - let c = RuntimeCall::Balances(pallet_balances::Call::set_balance { + let c = RuntimeCall::Balances(pallet_balances::Call::force_set_balance { who: 42, new_free: value, - new_reserved: 0, }); ::bound(c).unwrap() } diff --git a/frame/root-offences/src/mock.rs b/frame/root-offences/src/mock.rs index 0937c43d6e519..828551e4d9c19 100644 --- a/frame/root-offences/src/mock.rs +++ b/frame/root-offences/src/mock.rs @@ -121,6 +121,10 @@ impl pallet_balances::Config for Test { type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type HoldIdentifier = (); + type MaxHolds = (); } pallet_staking_reward_curve::build! { diff --git a/frame/scored-pool/src/mock.rs b/frame/scored-pool/src/mock.rs index a91b1a60f4974..f10a1320ef83c 100644 --- a/frame/scored-pool/src/mock.rs +++ b/frame/scored-pool/src/mock.rs @@ -91,6 +91,10 @@ impl pallet_balances::Config for Test { type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type HoldIdentifier = (); + type MaxHolds = (); } parameter_types! { diff --git a/frame/session/benchmarking/src/mock.rs b/frame/session/benchmarking/src/mock.rs index 4c4accbbfac8f..b7671255f68fb 100644 --- a/frame/session/benchmarking/src/mock.rs +++ b/frame/session/benchmarking/src/mock.rs @@ -84,6 +84,10 @@ impl pallet_balances::Config for Test { type ExistentialDeposit = ConstU64<10>; type AccountStore = System; type WeightInfo = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type HoldIdentifier = (); + type MaxHolds = (); } impl pallet_timestamp::Config for Test { diff --git a/frame/society/src/mock.rs b/frame/society/src/mock.rs index 73565dedc7cd1..9f72febc2106e 100644 --- a/frame/society/src/mock.rs +++ b/frame/society/src/mock.rs @@ -93,6 +93,10 @@ impl pallet_balances::Config for Test { type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type HoldIdentifier = (); + type MaxHolds = (); } impl Config for Test { diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index e876940cb92d3..c2f559a9780eb 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -157,6 +157,10 @@ impl pallet_balances::Config for Test { type ExistentialDeposit = ExistentialDeposit; type AccountStore = System; type WeightInfo = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type HoldIdentifier = (); + type MaxHolds = (); } sp_runtime::impl_opaque_keys! { diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 966eae8c1da9a..36cafcc1854db 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -30,7 +30,7 @@ use pallet_balances::Error as BalancesError; use sp_runtime::{ assert_eq_error_rate, traits::{BadOrigin, Dispatchable}, - Perbill, Percent, Rounding, + Perbill, Percent, Rounding, TokenError, }; use sp_staking::{ offence::{DisableStrategy, OffenceDetails, OnOffenceHandler}, @@ -98,8 +98,8 @@ fn force_unstake_works() { add_slash(&11); // Cant transfer assert_noop!( - Balances::transfer(RuntimeOrigin::signed(11), 1, 10), - BalancesError::::LiquidityRestrictions + Balances::transfer_allow_death(RuntimeOrigin::signed(11), 1, 10), + TokenError::Frozen, ); // Force unstake requires root. assert_noop!(Staking::force_unstake(RuntimeOrigin::signed(11), 11, 2), BadOrigin); @@ -113,7 +113,7 @@ fn force_unstake_works() { // No longer bonded. assert_eq!(Staking::bonded(&11), None); // Transfer works. - assert_ok!(Balances::transfer(RuntimeOrigin::signed(11), 1, 10)); + assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(11), 1, 10)); }); } @@ -960,14 +960,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(RuntimeOrigin::signed(11), 20, 1), - BalancesError::::LiquidityRestrictions + Balances::transfer_allow_death(RuntimeOrigin::signed(11), 20, 1), + TokenError::Frozen, ); // 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(RuntimeOrigin::signed(11), 20, 1)); + assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(11), 20, 1)); }); } @@ -985,10 +985,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(RuntimeOrigin::signed(21), 20, 1001), - BalancesError::::LiquidityRestrictions + Balances::transfer_allow_death(RuntimeOrigin::signed(21), 20, 1001), + TokenError::Frozen, ); - assert_ok!(Balances::transfer(RuntimeOrigin::signed(21), 20, 1000)); + assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(21), 20, 1000)); }); } @@ -4187,7 +4187,7 @@ fn payout_creates_controller() { bond_nominator(1234, 1337, 100, vec![11]); // kill controller - assert_ok!(Balances::transfer(RuntimeOrigin::signed(1337), 1234, 100)); + assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(1337), 1234, 100)); assert_eq!(Balances::free_balance(1337), 0); mock::start_active_era(1); diff --git a/frame/state-trie-migration/src/lib.rs b/frame/state-trie-migration/src/lib.rs index 5385c6b5f4f46..1f6266d999825 100644 --- a/frame/state-trie-migration/src/lib.rs +++ b/frame/state-trie-migration/src/lib.rs @@ -1128,6 +1128,10 @@ mod mock { type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type WeightInfo = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type HoldIdentifier = (); + type MaxHolds = (); } /// Test only Weights for state migration. diff --git a/frame/support/src/traits/stored_map.rs b/frame/support/src/traits/stored_map.rs index a073b268252ad..cbe70f2932349 100644 --- a/frame/support/src/traits/stored_map.rs +++ b/frame/support/src/traits/stored_map.rs @@ -17,7 +17,7 @@ //! Traits and associated datatypes for managing abstract stored values. -use crate::{storage::StorageMap, traits::misc::HandleLifetime}; +use crate::storage::StorageMap; use codec::FullCodec; use sp_runtime::DispatchError; @@ -81,48 +81,29 @@ pub trait StoredMap { /// be the default value), or where the account is being removed or reset back to the default value /// where previously it did exist (though may have been in a default state). This works well with /// system module's `CallOnCreatedAccount` and `CallKillAccount`. -pub struct StorageMapShim(sp_std::marker::PhantomData<(S, L, K, T)>); -impl< - S: StorageMap, - L: HandleLifetime, - K: FullCodec, - T: FullCodec + Default, - > StoredMap for StorageMapShim +pub struct StorageMapShim(sp_std::marker::PhantomData<(S, K, T)>); +impl, K: FullCodec, T: FullCodec + Default> StoredMap + for StorageMapShim { fn get(k: &K) -> T { S::get(k) } fn insert(k: &K, t: T) -> Result<(), DispatchError> { - if !S::contains_key(&k) { - L::created(k)?; - } S::insert(k, t); Ok(()) } fn remove(k: &K) -> Result<(), DispatchError> { if S::contains_key(&k) { - L::killed(k)?; S::remove(k); } Ok(()) } fn mutate(k: &K, f: impl FnOnce(&mut T) -> R) -> Result { - if !S::contains_key(&k) { - L::created(k)?; - } Ok(S::mutate(k, f)) } fn mutate_exists(k: &K, f: impl FnOnce(&mut Option) -> R) -> Result { S::try_mutate_exists(k, |maybe_value| { - let existed = maybe_value.is_some(); let r = f(maybe_value); - let exists = maybe_value.is_some(); - - if !existed && exists { - L::created(k)?; - } else if existed && !exists { - L::killed(k)?; - } Ok(r) }) } @@ -131,15 +112,7 @@ impl< f: impl FnOnce(&mut Option) -> Result, ) -> Result { S::try_mutate_exists(k, |maybe_value| { - let existed = maybe_value.is_some(); let r = f(maybe_value)?; - let exists = maybe_value.is_some(); - - if !existed && exists { - L::created(k).map_err(E::from)?; - } else if existed && !exists { - L::killed(k).map_err(E::from)?; - } Ok(r) }) } diff --git a/frame/support/src/traits/tokens.rs b/frame/support/src/traits/tokens.rs index 2d2bd63ada551..d2753caa6a79d 100644 --- a/frame/support/src/traits/tokens.rs +++ b/frame/support/src/traits/tokens.rs @@ -30,6 +30,7 @@ pub use imbalance::Imbalance; pub mod pay; pub use misc::{ AssetId, Balance, BalanceConversion, BalanceStatus, ConvertRank, DepositConsequence, - ExistenceRequirement, GetSalary, Locker, WithdrawConsequence, WithdrawReasons, + ExistenceRequirement, Fortitude, GetSalary, Locker, Precision, Preservation, Provenance, + Restriction, WithdrawConsequence, WithdrawReasons, }; pub use pay::{Pay, PayFromAccount, PaymentStatus}; diff --git a/frame/support/src/traits/tokens/fungible.rs b/frame/support/src/traits/tokens/fungible.rs deleted file mode 100644 index 12bac29727dd4..0000000000000 --- a/frame/support/src/traits/tokens/fungible.rs +++ /dev/null @@ -1,367 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! The traits for dealing with a single fungible token class and any associated types. - -use super::{ - misc::{Balance, DepositConsequence, WithdrawConsequence}, - *, -}; -use crate::{ - dispatch::{DispatchError, DispatchResult}, - traits::misc::Get, -}; -use sp_runtime::traits::Saturating; - -mod balanced; -mod imbalance; -pub use balanced::{Balanced, Unbalanced}; -pub use imbalance::{CreditOf, DebtOf, HandleImbalanceDrop, Imbalance}; - -/// Trait for providing balance-inspection access to a fungible asset. -pub trait Inspect { - /// Scalar type for representing balance of an account. - type Balance: Balance; - - /// 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; - - /// Get the balance of `who`. - fn balance(who: &AccountId) -> Self::Balance; - - /// Get the maximum amount that `who` can withdraw/transfer successfully. - fn reducible_balance(who: &AccountId, keep_alive: bool) -> Self::Balance; - - /// Returns `true` if the balance of `who` may be increased by `amount`. - /// - /// - `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. - fn can_withdraw(who: &AccountId, amount: Self::Balance) -> WithdrawConsequence; -} - -/// Trait for providing an ERC-20 style fungible asset. -pub trait Mutate: Inspect { - /// Increase the balance of `who` by exactly `amount`, minting new tokens. If that isn't - /// possible then an `Err` is returned and nothing is changed. - fn mint_into(who: &AccountId, amount: Self::Balance) -> DispatchResult; - - /// Decrease the balance of `who` by at least `amount`, possibly slightly more in the case of - /// minimum_balance requirements, burning the tokens. If that isn't possible then an `Err` is - /// returned and nothing is changed. If successful, the amount of tokens reduced is returned. - fn burn_from(who: &AccountId, amount: Self::Balance) -> Result; - - // TODO: Remove. - /// Attempt to reduce the balance of `who` by as much as possible up to `amount`, and possibly - /// slightly more due to minimum_balance requirements. If no decrease is possible then an `Err` - /// 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 it doesn't fail. - fn slash(who: &AccountId, amount: Self::Balance) -> Result { - Self::burn_from(who, Self::reducible_balance(who, false).min(amount)) - } - - /// Transfer funds from one account into another. The default implementation uses `mint_into` - /// and `burn_from` and may generate unwanted events. - fn teleport( - source: &AccountId, - dest: &AccountId, - amount: Self::Balance, - ) -> Result { - 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()?; - let actual = Self::burn_from(source, amount)?; - debug_assert!( - actual == amount.saturating_add(extra), - "can_withdraw must agree with withdraw; qed" - ); - match Self::mint_into(dest, actual) { - Ok(_) => Ok(actual), - Err(err) => { - debug_assert!(false, "can_deposit returned true previously; qed"); - // attempt to return the funds back to source - let revert = Self::mint_into(source, actual); - debug_assert!(revert.is_ok(), "withdrew funds previously; qed"); - Err(err) - }, - } - } -} - -/// Trait for providing a fungible asset which can only be transferred. -pub trait Transfer: Inspect { - /// Transfer funds from one account into another. - fn transfer( - source: &AccountId, - dest: &AccountId, - 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. -pub trait InspectHold: Inspect { - /// Amount of funds held in reserve by `who`. - fn balance_on_hold(who: &AccountId) -> Self::Balance; - - /// Check to see if some `amount` of funds of `who` may be placed on hold. - fn can_hold(who: &AccountId, amount: Self::Balance) -> bool; -} - -// TODO: Introduce `HoldReason`. -/// Trait for mutating a fungible asset which can be reserved. -pub trait MutateHold: InspectHold + Transfer { - /// Hold some funds in an account. - fn hold(who: &AccountId, amount: Self::Balance) -> DispatchResult; - - /// Release up to `amount` held funds in an account. - /// - /// The actual amount released is returned with `Ok`. - /// - /// If `best_effort` is `true`, then the amount actually unreserved and returned as the inner - /// value of `Ok` may be smaller than the `amount` passed. - fn release( - who: &AccountId, - amount: Self::Balance, - best_effort: bool, - ) -> Result; - - // TODO: Introduce repatriate_held - - /// Transfer held funds into a destination account. - /// - /// If `on_hold` is `true`, then the destination account must already exist and the assets - /// transferred will still be on hold in the destination account. If not, then the destination - /// account need not already exist, but must be creatable. - /// - /// If `best_effort` is `true`, then an amount less than `amount` may be transferred without - /// error. - /// - /// The actual amount transferred is returned, or `Err` in the case of error and nothing is - /// changed. - fn transfer_held( - source: &AccountId, - dest: &AccountId, - amount: Self::Balance, - best_effort: bool, - on_held: bool, - ) -> Result; -} - -/// Trait for slashing a fungible asset which can be reserved. -pub trait BalancedHold: Balanced + MutateHold { - /// Reduce the balance of some funds on hold in an account. - /// - /// The resulting imbalance is the first item of the tuple returned. - /// - /// As much funds that are on hold up to `amount` will be deducted as possible. If this is less - /// than `amount`, then a non-zero second item will be returned. - fn slash_held( - who: &AccountId, - amount: Self::Balance, - ) -> (CreditOf, Self::Balance); -} - -impl + MutateHold> BalancedHold for T { - // TODO: This should be implemented properly, and `slash` should be removed. - fn slash_held( - who: &AccountId, - amount: Self::Balance, - ) -> (CreditOf, Self::Balance) { - let actual = match Self::release(who, amount, true) { - Ok(x) => x, - Err(_) => return (Imbalance::default(), amount), - }; - >::slash(who, actual) - } -} - -/// Convert a `fungibles` trait implementation into a `fungible` trait implementation by identifying -/// a single item. -pub struct ItemOf< - F: fungibles::Inspect, - A: Get<>::AssetId>, - AccountId, ->(sp_std::marker::PhantomData<(F, A, AccountId)>); - -impl< - F: fungibles::Inspect, - A: Get<>::AssetId>, - AccountId, - > Inspect for ItemOf -{ - type Balance = >::Balance; - 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()) - } - fn balance(who: &AccountId) -> Self::Balance { - >::balance(A::get(), who) - } - 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, 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) - } -} - -impl< - F: fungibles::Mutate, - A: Get<>::AssetId>, - AccountId, - > Mutate for ItemOf -{ - fn mint_into(who: &AccountId, amount: Self::Balance) -> DispatchResult { - >::mint_into(A::get(), who, amount) - } - fn burn_from(who: &AccountId, amount: Self::Balance) -> Result { - >::burn_from(A::get(), who, amount) - } -} - -impl< - F: fungibles::Transfer, - A: Get<>::AssetId>, - AccountId, - > Transfer for ItemOf -{ - fn transfer( - source: &AccountId, - dest: &AccountId, - amount: Self::Balance, - keep_alive: bool, - ) -> 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< - F: fungibles::InspectHold, - A: Get<>::AssetId>, - AccountId, - > InspectHold for ItemOf -{ - fn balance_on_hold(who: &AccountId) -> Self::Balance { - >::balance_on_hold(A::get(), who) - } - fn can_hold(who: &AccountId, amount: Self::Balance) -> bool { - >::can_hold(A::get(), who, amount) - } -} - -impl< - F: fungibles::MutateHold, - A: Get<>::AssetId>, - AccountId, - > MutateHold for ItemOf -{ - fn hold(who: &AccountId, amount: Self::Balance) -> DispatchResult { - >::hold(A::get(), who, amount) - } - fn release( - who: &AccountId, - amount: Self::Balance, - best_effort: bool, - ) -> Result { - >::release(A::get(), who, amount, best_effort) - } - fn transfer_held( - source: &AccountId, - dest: &AccountId, - amount: Self::Balance, - best_effort: bool, - on_hold: bool, - ) -> Result { - >::transfer_held( - A::get(), - source, - dest, - amount, - best_effort, - on_hold, - ) - } -} - -impl< - F: fungibles::Unbalanced, - A: Get<>::AssetId>, - AccountId, - > Unbalanced for ItemOf -{ - fn set_balance(who: &AccountId, amount: Self::Balance) -> DispatchResult { - >::set_balance(A::get(), who, amount) - } - fn set_total_issuance(amount: Self::Balance) -> () { - >::set_total_issuance(A::get(), amount) - } - fn decrease_balance( - who: &AccountId, - amount: Self::Balance, - ) -> Result { - >::decrease_balance(A::get(), who, amount) - } - fn decrease_balance_at_most(who: &AccountId, amount: Self::Balance) -> Self::Balance { - >::decrease_balance_at_most(A::get(), who, amount) - } - fn increase_balance( - who: &AccountId, - amount: Self::Balance, - ) -> Result { - >::increase_balance(A::get(), who, amount) - } - fn increase_balance_at_most(who: &AccountId, amount: Self::Balance) -> Self::Balance { - >::increase_balance_at_most(A::get(), who, amount) - } -} diff --git a/frame/support/src/traits/tokens/fungible/balanced.rs b/frame/support/src/traits/tokens/fungible/balanced.rs deleted file mode 100644 index 437d2c82defee..0000000000000 --- a/frame/support/src/traits/tokens/fungible/balanced.rs +++ /dev/null @@ -1,354 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! The trait and associated types for sets of fungible tokens that manage total issuance without -//! requiring atomic balanced operations. - -use super::{super::Imbalance as ImbalanceT, *}; -use crate::{ - dispatch::{DispatchError, DispatchResult}, - traits::misc::{SameOrOther, TryDrop}, -}; -use sp_runtime::{ - traits::{CheckedAdd, Zero}, - ArithmeticError, TokenError, -}; -use sp_std::marker::PhantomData; - -/// A fungible token class where any creation and deletion of tokens is semi-explicit and where the -/// total supply is maintained automatically. -/// -/// This is auto-implemented when a token class has `Unbalanced` implemented. -pub trait Balanced: Inspect { - /// The type for managing what happens when an instance of `Debt` is dropped without being used. - type OnDropDebt: HandleImbalanceDrop; - /// The type for managing what happens when an instance of `Credit` is dropped without being - /// used. - type OnDropCredit: HandleImbalanceDrop; - - /// Reduce the total issuance by `amount` and return the according imbalance. The imbalance will - /// typically be used to reduce an account by the same amount with e.g. `settle`. - /// - /// This is infallible, but doesn't guarantee that the entire `amount` is burnt, for example - /// in the case of underflow. - fn rescind(amount: Self::Balance) -> DebtOf; - - /// Increase the total issuance by `amount` and return the according imbalance. The imbalance - /// will typically be used to increase an account by the same amount with e.g. - /// `resolve_into_existing` or `resolve_creating`. - /// - /// This is infallible, but doesn't guarantee that the entire `amount` is issued, for example - /// in the case of overflow. - fn issue(amount: Self::Balance) -> CreditOf; - - /// Produce a pair of imbalances that cancel each other out exactly. - /// - /// 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) -> (DebtOf, CreditOf) { - (Self::rescind(amount), Self::issue(amount)) - } - - /// Deducts up to `value` from the combined balance of `who`. This function cannot fail. - /// - /// The resulting imbalance is the first item of the tuple returned. - /// - /// As much funds up to `value` will be deducted as possible. If this is less than `value`, - /// then a non-zero second item will be returned. - fn slash(who: &AccountId, amount: Self::Balance) -> (CreditOf, Self::Balance); - - /// Mints exactly `value` into the account of `who`. - /// - /// If `who` doesn't exist, nothing is done and an `Err` returned. This could happen because it - /// the account doesn't yet exist and it isn't possible to create it under the current - /// circumstances and with `value` in it. - fn deposit( - who: &AccountId, - value: Self::Balance, - ) -> Result, DispatchError>; - - /// Removes `value` balance from `who` account if possible. - /// - /// If the removal is not possible, then it returns `Err` and nothing is changed. - /// - /// If the operation is successful, this will return `Ok` with a `NegativeImbalance` whose value - /// is no less than `value`. It may be more in the case that removing it reduced it below - /// `Self::minimum_balance()`. - fn withdraw( - who: &AccountId, - value: Self::Balance, - // TODO: liveness: ExistenceRequirement, - ) -> Result, DispatchError>; - - /// The balance of `who` is increased in order to counter `credit`. If the whole of `credit` - /// cannot be countered, then nothing is changed and the original `credit` is returned in an - /// `Err`. - /// - /// Please note: If `credit.peek()` is less than `Self::minimum_balance()`, then `who` must - /// already exist for this to succeed. - fn resolve( - who: &AccountId, - credit: CreditOf, - ) -> Result<(), CreditOf> { - let v = credit.peek(); - let debt = match Self::deposit(who, v) { - Err(_) => return Err(credit), - Ok(d) => d, - }; - let result = credit.offset(debt).try_drop(); - debug_assert!(result.is_ok(), "ok deposit return must be equal to credit value; qed"); - Ok(()) - } - - /// The balance of `who` is decreased in order to counter `debt`. If the whole of `debt` - /// cannot be countered, then nothing is changed and the original `debt` is returned in an - /// `Err`. - fn settle( - who: &AccountId, - debt: DebtOf, - // TODO: liveness: ExistenceRequirement, - ) -> Result, DebtOf> { - let amount = debt.peek(); - let credit = match Self::withdraw(who, amount) { - Err(_) => return Err(debt), - Ok(d) => d, - }; - match credit.offset(debt) { - SameOrOther::None => Ok(CreditOf::::zero()), - SameOrOther::Same(dust) => Ok(dust), - SameOrOther::Other(rest) => { - debug_assert!(false, "ok withdraw return must be at least debt value; qed"); - Err(rest) - }, - } - } -} - -/// A fungible token class where the balance can be set arbitrarily. -/// -/// **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 -/// for the underlying datatype to implement so the user gets the much safer `Balanced` trait to -/// use. -pub trait Unbalanced: Inspect { - /// Set the balance of `who` to `amount`. If this cannot be done for some reason (e.g. - /// because the account cannot be created or an overflow) then an `Err` is returned. - fn set_balance(who: &AccountId, amount: Self::Balance) -> DispatchResult; - - /// Set the total issuance to `amount`. - fn set_total_issuance(amount: Self::Balance); - - /// Reduce the balance of `who` by `amount`. If it cannot be reduced by that amount for - /// some reason, return `Err` and don't reduce it at all. If Ok, return the imbalance. - /// - /// Minimum balance will be respected and the returned imbalance may be up to - /// `Self::minimum_balance() - 1` greater than `amount`. - fn decrease_balance( - who: &AccountId, - amount: Self::Balance, - ) -> Result { - let old_balance = Self::balance(who); - let (mut new_balance, mut amount) = if Self::reducible_balance(who, false) < amount { - return Err(TokenError::NoFunds.into()) - } else { - (old_balance - amount, amount) - }; - if new_balance < Self::minimum_balance() { - amount = amount.saturating_add(new_balance); - new_balance = Zero::zero(); - } - // Defensive only - this should not fail now. - Self::set_balance(who, new_balance)?; - Ok(amount) - } - - /// Reduce the balance of `who` by the most that is possible, up to `amount`. - /// - /// Minimum balance will be respected and the returned imbalance may be up to - /// `Self::minimum_balance() - 1` greater than `amount`. - /// - /// 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 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) - }; - let minimum_balance = Self::minimum_balance(); - if new_balance < minimum_balance { - amount = amount.saturating_add(new_balance); - new_balance = Zero::zero(); - } - let mut r = Self::set_balance(who, new_balance); - if r.is_err() { - // Some error, probably because we tried to destroy an account which cannot be - // destroyed. - if new_balance.is_zero() && amount >= minimum_balance { - new_balance = minimum_balance; - amount -= minimum_balance; - r = Self::set_balance(who, new_balance); - } - if r.is_err() { - // Still an error. Apparently it's not possible to reduce at all. - amount = Zero::zero(); - } - } - amount - } - - /// Increase the balance of `who` by `amount`. If it cannot be increased by that amount - /// for some reason, return `Err` and don't increase it at all. If Ok, return the imbalance. - /// - /// Minimum balance will be respected and an error will be returned if - /// `amount < Self::minimum_balance()` when the account of `who` is zero. - fn increase_balance( - who: &AccountId, - amount: Self::Balance, - ) -> Result { - let old_balance = Self::balance(who); - let new_balance = old_balance.checked_add(&amount).ok_or(ArithmeticError::Overflow)?; - if new_balance < Self::minimum_balance() { - return Err(TokenError::BelowMinimum.into()) - } - if old_balance != new_balance { - Self::set_balance(who, new_balance)?; - } - Ok(amount) - } - - /// Increase the balance of `who` by the most that is possible, up to `amount`. - /// - /// Minimum balance will be respected and the returned imbalance will be zero in the case that - /// `amount < Self::minimum_balance()`. - /// - /// Return the imbalance by which the account was increased. - fn increase_balance_at_most(who: &AccountId, amount: Self::Balance) -> Self::Balance { - let old_balance = Self::balance(who); - let mut new_balance = old_balance.saturating_add(amount); - let mut amount = new_balance - old_balance; - if new_balance < Self::minimum_balance() { - new_balance = Zero::zero(); - amount = Zero::zero(); - } - if old_balance == new_balance || Self::set_balance(who, new_balance).is_ok() { - amount - } else { - Zero::zero() - } - } -} - -/// Simple handler for an imbalance drop which increases the total issuance of the system by the -/// imbalance amount. Used for leftover debt. -pub struct IncreaseIssuance(PhantomData<(AccountId, U)>); -impl> HandleImbalanceDrop - for IncreaseIssuance -{ - fn handle(amount: U::Balance) { - U::set_total_issuance(U::total_issuance().saturating_add(amount)) - } -} - -/// Simple handler for an imbalance drop which decreases the total issuance of the system by the -/// imbalance amount. Used for leftover credit. -pub struct DecreaseIssuance(PhantomData<(AccountId, U)>); -impl> HandleImbalanceDrop - for DecreaseIssuance -{ - fn handle(amount: U::Balance) { - U::set_total_issuance(U::total_issuance().saturating_sub(amount)) - } -} - -/// An imbalance type which uses `DecreaseIssuance` to deal with anything `Drop`ed. -/// -/// Basically means that funds in someone's account have been removed and not yet placed anywhere -/// else. If it gets dropped, then those funds will be assumed to be "burned" and the total supply -/// will be accordingly decreased to ensure it equals the sum of the balances of all accounts. -type Credit = Imbalance< - >::Balance, - DecreaseIssuance, - IncreaseIssuance, ->; - -/// An imbalance type which uses `IncreaseIssuance` to deal with anything `Drop`ed. -/// -/// Basically means that there are funds in someone's account whose origin is as yet unaccounted -/// for. If it gets dropped, then those funds will be assumed to be "minted" and the total supply -/// will be accordingly increased to ensure it equals the sum of the balances of all accounts. -type Debt = Imbalance< - >::Balance, - IncreaseIssuance, - DecreaseIssuance, ->; - -/// Create some `Credit` item. Only for internal use. -fn credit>(amount: U::Balance) -> Credit { - Imbalance::new(amount) -} - -/// Create some `Debt` item. Only for internal use. -fn debt>(amount: U::Balance) -> Debt { - Imbalance::new(amount) -} - -impl> Balanced for U { - type OnDropCredit = DecreaseIssuance; - type OnDropDebt = IncreaseIssuance; - fn rescind(amount: Self::Balance) -> Debt { - let old = U::total_issuance(); - let new = old.saturating_sub(amount); - U::set_total_issuance(new); - debt(old - new) - } - fn issue(amount: Self::Balance) -> Credit { - let old = U::total_issuance(); - let new = old.saturating_add(amount); - U::set_total_issuance(new); - credit(new - old) - } - fn slash(who: &AccountId, amount: Self::Balance) -> (Credit, Self::Balance) { - let slashed = U::decrease_balance_at_most(who, amount); - // `slashed` could be less than, greater than or equal to `amount`. - // If slashed == amount, it means the account had at least amount in it and it could all be - // removed without a problem. - // If slashed > amount, it means the account had more than amount in it, but not enough more - // to push it over minimum_balance. - // If slashed < amount, it means the account didn't have enough in it to be reduced by - // `amount` without being destroyed. - (credit(slashed), amount.saturating_sub(slashed)) - } - fn deposit( - who: &AccountId, - amount: Self::Balance, - ) -> Result, DispatchError> { - let increase = U::increase_balance(who, amount)?; - Ok(debt(increase)) - } - fn withdraw( - who: &AccountId, - amount: Self::Balance, - // TODO: liveness: ExistenceRequirement, - ) -> Result, DispatchError> { - let decrease = U::decrease_balance(who, amount)?; - Ok(credit(decrease)) - } -} diff --git a/frame/support/src/traits/tokens/fungible/freeze.rs b/frame/support/src/traits/tokens/fungible/freeze.rs new file mode 100644 index 0000000000000..1ec3a5fadf555 --- /dev/null +++ b/frame/support/src/traits/tokens/fungible/freeze.rs @@ -0,0 +1,68 @@ +// 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 traits for putting freezes within a single fungible token class. + +use scale_info::TypeInfo; +use sp_runtime::DispatchResult; + +/// Trait for inspecting a fungible asset which can be frozen. Freezing is essentially setting a +/// minimum balance bellow which the total balance (inclusive of any funds placed on hold) may not +/// be normally allowed to drop. Generally, freezers will provide an "update" function such that +/// if the total balance does drop below the limit, then the freezer can update their housekeeping +/// accordingly. +pub trait Inspect: super::Inspect { + /// An identifier for a freeze. + type Id: codec::Encode + TypeInfo + 'static; + + /// Amount of funds held in reserve by `who` for the given `id`. + fn balance_frozen(id: &Self::Id, who: &AccountId) -> Self::Balance; + + /// The amount of the balance which can become frozen. Defaults to `total_balance()`. + fn balance_freezable(who: &AccountId) -> Self::Balance { + Self::total_balance(who) + } + + /// Returns `true` if it's possible to introduce a freeze for the given `id` onto the + /// account of `who`. This will be true as long as the implementor supports as many + /// concurrent freeze locks as there are possible values of `id`. + fn can_freeze(id: &Self::Id, who: &AccountId) -> bool; +} + +/// Trait for introducing, altering and removing locks to freeze an account's funds so they never +/// go below a set minimum. +pub trait Mutate: Inspect { + /// Prevent actions which would reduce the balance of the account of `who` below the given + /// `amount` and identify this restriction though the given `id`. Unlike `extend_freeze`, any + /// outstanding freeze in place for `who` under the `id` are dropped. + /// + /// If `amount` is zero, it is equivalent to using `thaw`. + /// + /// Note that `amount` can be greater than the total balance, if desired. + fn set_freeze(id: &Self::Id, who: &AccountId, amount: Self::Balance) -> DispatchResult; + + /// Prevent the balance of the account of `who` from being reduced below the given `amount` and + /// identify this restriction though the given `id`. Unlike `set_freeze`, this does not + /// counteract any pre-existing freezes in place for `who` under the `id`. Also unlike + /// `set_freeze`, in the case that `amount` is zero, this is no-op and never fails. + /// + /// Note that more funds can be locked than the total balance, if desired. + fn extend_freeze(id: &Self::Id, who: &AccountId, amount: Self::Balance) -> DispatchResult; + + /// Remove an existing lock. + fn thaw(id: &Self::Id, who: &AccountId) -> DispatchResult; +} diff --git a/frame/support/src/traits/tokens/fungible/hold.rs b/frame/support/src/traits/tokens/fungible/hold.rs new file mode 100644 index 0000000000000..ddcb8c6ac1da8 --- /dev/null +++ b/frame/support/src/traits/tokens/fungible/hold.rs @@ -0,0 +1,393 @@ +// 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 traits for putting holds within a single fungible token class. + +use crate::{ + ensure, + traits::tokens::{ + DepositConsequence::Success, + Fortitude::{self, Force}, + Precision::{self, BestEffort, Exact}, + Preservation::{self, Protect}, + Provenance::Extant, + Restriction::{self, Free, OnHold}, + }, +}; +use scale_info::TypeInfo; +use sp_arithmetic::{ + traits::{CheckedAdd, CheckedSub, Zero}, + ArithmeticError, +}; +use sp_runtime::{DispatchError, DispatchResult, Saturating, TokenError}; + +use super::*; + +/// Trait for inspecting a fungible asset whose accounts support partitioning and slashing. +pub trait Inspect: super::Inspect { + /// An identifier for a hold. Used for disambiguating different holds so that + /// they can be individually replaced or removed and funds from one hold don't accidentally + /// become unreserved or slashed for another. + type Reason: codec::Encode + TypeInfo + 'static; + + /// Amount of funds on hold (for all hold reasons) of `who`. + fn total_balance_on_hold(who: &AccountId) -> Self::Balance; + + /// Get the maximum amount that the `total_balance_on_hold` of `who` can be reduced successfully + /// based on whether we are willing to force the reduction and potentially go below user-level + /// restrictions on the minimum amount of the account. Note: This cannot bring the account into + /// an inconsistent state with regards any required existential deposit. + /// + /// Always less than `total_balance_on_hold()`. + fn reducible_total_balance_on_hold(who: &AccountId, force: Fortitude) -> Self::Balance; + + /// Amount of funds on hold (for the given reason) of `who`. + fn balance_on_hold(reason: &Self::Reason, who: &AccountId) -> Self::Balance; + + /// Returns `true` if it's possible to place (additional) funds under a hold of a given + /// `reason`. This may fail if the account has exhausted a limited number of concurrent + /// holds or if it cannot be made to exist (e.g. there is no provider reference). + /// + /// NOTE: This does not take into account changes which could be made to the account of `who` + /// (such as removing a provider reference) after this call is made. Any usage of this should + /// therefore ensure the account is already in the appropriate state prior to calling it. + fn hold_available(reason: &Self::Reason, who: &AccountId) -> bool; + + /// Check to see if some `amount` of funds of `who` may be placed on hold with the given + /// `reason`. Reasons why this may not be true: + /// + /// - The implementor supports only a limited number of concurrent holds on an account which is + /// the possible values of `reason`; + /// - The total balance of the account is less than `amount`; + /// - Removing `amount` from the total balance would kill the account and remove the only + /// provider reference. + /// + /// Note: we pass `true` as the third argument to `reducible_balance` since we assume that if + /// needed the balance can slashed. If we are using a simple non-forcing reserve-transfer, then + /// we really ought to check that we are not reducing the funds below the freeze-limit (if any). + /// + /// NOTE: This does not take into account changes which could be made to the account of `who` + /// (such as removing a provider reference) after this call is made. Any usage of this should + /// therefore ensure the account is already in the appropriate state prior to calling it. + fn ensure_can_hold( + reason: &Self::Reason, + who: &AccountId, + amount: Self::Balance, + ) -> DispatchResult { + ensure!(Self::hold_available(reason, who), TokenError::CannotCreateHold); + ensure!( + amount <= Self::reducible_balance(who, Protect, Force), + TokenError::FundsUnavailable + ); + Ok(()) + } + + /// Check to see if some `amount` of funds of `who` may be placed on hold for the given + /// `reason`. Reasons why this may not be true: + /// + /// - The implementor supports only a limited number of concurrernt holds on an account which is + /// the possible values of `reason`; + /// - The main balance of the account is less than `amount`; + /// - Removing `amount` from the main balance would kill the account and remove the only + /// provider reference. + /// + /// NOTE: This does not take into account changes which could be made to the account of `who` + /// (such as removing a provider reference) after this call is made. Any usage of this should + /// therefore ensure the account is already in the appropriate state prior to calling it. + fn can_hold(reason: &Self::Reason, who: &AccountId, amount: Self::Balance) -> bool { + Self::ensure_can_hold(reason, who, amount).is_ok() + } +} + +/// A fungible, holdable token class where the balance on hold can be set arbitrarily. +/// +/// **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 +/// for the underlying datatype to implement so the user gets the much safer `Balanced` trait to +/// use. +pub trait Unbalanced: Inspect { + /// Forcefully set the balance on hold of `who` to `amount`. This is independent of any other + /// balances on hold or the main ("free") balance. + /// + /// If this call executes successfully, you can `assert_eq!(Self::balance_on_hold(), amount);`. + /// + /// This function does its best to force the balance change through, but will not break system + /// invariants such as any Existential Deposits needed or overflows/underflows. + /// If this cannot be done for some reason (e.g. because the account doesn't exist) then an + /// `Err` is returned. + // Implmentation note: This should increment the consumer refs if it moves total on hold from + // zero to non-zero and decrement in the opposite direction. + // + // Since this was not done in the previous logic, this will need either a migration or a + // state item which tracks whether the account is on the old logic or new. + fn set_balance_on_hold( + reason: &Self::Reason, + who: &AccountId, + amount: Self::Balance, + ) -> DispatchResult; + + /// Reduce the balance on hold of `who` by `amount`. + /// + /// If `precision` is `Exact` and it cannot be reduced by that amount for + /// some reason, return `Err` and don't reduce it at all. If `precision` is `BestEffort`, then + /// reduce the balance of `who` by the most that is possible, up to `amount`. + /// + /// In either case, if `Ok` is returned then the inner is the amount by which is was reduced. + fn decrease_balance_on_hold( + reason: &Self::Reason, + who: &AccountId, + mut amount: Self::Balance, + precision: Precision, + ) -> Result { + let old_balance = Self::balance_on_hold(reason, who); + if let BestEffort = precision { + amount = amount.min(old_balance); + } + let new_balance = old_balance.checked_sub(&amount).ok_or(TokenError::FundsUnavailable)?; + Self::set_balance_on_hold(reason, who, new_balance)?; + Ok(amount) + } + + /// Increase the balance on hold of `who` by `amount`. + /// + /// If it cannot be increased by that amount for some reason, return `Err` and don't increase + /// it at all. If Ok, return the imbalance. + fn increase_balance_on_hold( + reason: &Self::Reason, + who: &AccountId, + amount: Self::Balance, + precision: Precision, + ) -> Result { + let old_balance = Self::balance_on_hold(reason, who); + let new_balance = if let BestEffort = precision { + old_balance.saturating_add(amount) + } else { + old_balance.checked_add(&amount).ok_or(ArithmeticError::Overflow)? + }; + let amount = new_balance.saturating_sub(old_balance); + if !amount.is_zero() { + Self::set_balance_on_hold(reason, who, new_balance)?; + } + Ok(amount) + } +} + +/// Trait for mutating a fungible asset which can be placed on hold. +pub trait Mutate: + Inspect + super::Unbalanced + Unbalanced +{ + /// Hold some funds in an account. If a hold for `reason` is already in place, then this + /// will increase it. + fn hold(reason: &Self::Reason, who: &AccountId, amount: Self::Balance) -> DispatchResult { + // NOTE: This doesn't change the total balance of the account so there's no need to + // check liquidity. + + Self::ensure_can_hold(reason, who, amount)?; + // Should be infallible now, but we proceed softly anyway. + Self::decrease_balance(who, amount, Exact, Protect, Force)?; + Self::increase_balance_on_hold(reason, who, amount, BestEffort)?; + Self::done_hold(reason, who, amount); + Ok(()) + } + + /// Release up to `amount` held funds in an account. + /// + /// The actual amount released is returned with `Ok`. + /// + /// If `precision` is `BestEffort`, then the amount actually unreserved and returned as the + /// inner value of `Ok` may be smaller than the `amount` passed. + /// + /// NOTE! The inner of the `Ok` result variant returns the *actual* amount released. This is the + /// opposite of the `ReservableCurrency::unreserve()` result, which gives the amount not able + /// to be released! + fn release( + reason: &Self::Reason, + who: &AccountId, + amount: Self::Balance, + precision: Precision, + ) -> Result { + // NOTE: This doesn't change the total balance of the account so there's no need to + // check liquidity. + + // We want to make sure we can deposit the amount in advance. If we can't then something is + // very wrong. + ensure!(Self::can_deposit(who, amount, Extant) == Success, TokenError::CannotCreate); + // Get the amount we can actually take from the hold. This might be less than what we want + // if we're only doing a best-effort. + let amount = Self::decrease_balance_on_hold(reason, who, amount, precision)?; + // Increase the main balance by what we took. We always do a best-effort here because we + // already checked that we can deposit before. + let actual = Self::increase_balance(who, amount, BestEffort)?; + Self::done_release(reason, who, actual); + Ok(actual) + } + + /// Attempt to decrease the balance of `who` which is held for the given `reason` by `amount`. + /// + /// If `precision` is `BestEffort`, then as much as possible is reduced, up to `amount`, and the + /// amount of tokens reduced is returned. Otherwise, if the total amount can be reduced, then it + /// is and the amount returned, and if not, then nothing changes and `Err` is returned. + /// + /// If `force` is `Force`, then locks/freezes will be ignored. This should only be used when + /// conducting slashing or other activity which materially disadvantages the account holder + /// since it could provide a means of circumventing freezes. + fn burn_held( + reason: &Self::Reason, + who: &AccountId, + mut amount: Self::Balance, + precision: Precision, + force: Fortitude, + ) -> Result { + // We must check total-balance requirements if `!force`. + let liquid = Self::reducible_total_balance_on_hold(who, force); + if let BestEffort = precision { + amount = amount.min(liquid); + } else { + ensure!(amount <= liquid, TokenError::Frozen); + } + let amount = Self::decrease_balance_on_hold(reason, who, amount, precision)?; + Self::set_total_issuance(Self::total_issuance().saturating_sub(amount)); + Self::done_burn_held(reason, who, amount); + Ok(amount) + } + + /// Transfer held funds into a destination account. + /// + /// If `on_hold` is `true`, then the destination account must already exist and the assets + /// transferred will still be on hold in the destination account. If not, then the destination + /// account need not already exist, but must be creatable. + /// + /// If `precision` is `BestEffort`, then an amount less than `amount` may be transferred without + /// error. + /// + /// If `force` is `Force`, then other fund-locking mechanisms may be disregarded. It should be + /// left as `Polite` in most circumstances, but when you want the same power as a `slash`, it + /// may be `Force`. + /// + /// The actual amount transferred is returned, or `Err` in the case of error and nothing is + /// changed. + fn transfer_on_hold( + reason: &Self::Reason, + source: &AccountId, + dest: &AccountId, + mut amount: Self::Balance, + precision: Precision, + mode: Restriction, + force: Fortitude, + ) -> Result { + // We must check total-balance requirements if `force` is `Fortitude::Polite`. + let have = Self::balance_on_hold(reason, source); + let liquid = Self::reducible_total_balance_on_hold(source, force); + if let BestEffort = precision { + amount = amount.min(liquid).min(have); + } else { + ensure!(amount <= liquid, TokenError::Frozen); + ensure!(amount <= have, TokenError::FundsUnavailable); + } + + // We want to make sure we can deposit the amount in advance. If we can't then something is + // very wrong. + ensure!(Self::can_deposit(dest, amount, Extant) == Success, TokenError::CannotCreate); + ensure!(mode == Free || Self::hold_available(reason, dest), TokenError::CannotCreateHold); + + let amount = Self::decrease_balance_on_hold(reason, source, amount, precision)?; + let actual = if mode == OnHold { + Self::increase_balance_on_hold(reason, dest, amount, precision)? + } else { + Self::increase_balance(dest, amount, precision)? + }; + Self::done_transfer_on_hold(reason, source, dest, actual); + Ok(actual) + } + + /// Transfer some `amount` of free balance from `source` to become owned by `dest` but on hold + /// for `reason`. + /// + /// If `precision` is `BestEffort`, then an amount less than `amount` may be transferred without + /// error. + /// + /// `source` must obey the requirements of `keep_alive`. + /// + /// If `force` is `Force`, then other fund-locking mechanisms may be disregarded. It should be + /// left as `Polite` in most circumstances, but when you want the same power as a `slash`, it + /// may be `Force`. + /// + /// The amount placed on hold is returned or `Err` in the case of error and nothing is changed. + /// + /// WARNING: This may return an error after a partial storage mutation. It should be used only + /// inside a transactional storage context and an `Err` result must imply a storage rollback. + fn transfer_and_hold( + reason: &Self::Reason, + source: &AccountId, + dest: &AccountId, + amount: Self::Balance, + precision: Precision, + expendability: Preservation, + force: Fortitude, + ) -> Result { + ensure!(Self::hold_available(reason, dest), TokenError::CannotCreateHold); + ensure!(Self::can_deposit(dest, amount, Extant) == Success, TokenError::CannotCreate); + let actual = Self::decrease_balance(source, amount, precision, expendability, force)?; + Self::increase_balance_on_hold(reason, dest, actual, precision)?; + Self::done_transfer_on_hold(reason, source, dest, actual); + Ok(actual) + } + + fn done_hold(_reason: &Self::Reason, _who: &AccountId, _amount: Self::Balance) {} + fn done_release(_reason: &Self::Reason, _who: &AccountId, _amount: Self::Balance) {} + fn done_burn_held(_reason: &Self::Reason, _who: &AccountId, _amount: Self::Balance) {} + fn done_transfer_on_hold( + _reason: &Self::Reason, + _source: &AccountId, + _dest: &AccountId, + _amount: Self::Balance, + ) { + } + fn done_transfer_and_hold( + _reason: &Self::Reason, + _source: &AccountId, + _dest: &AccountId, + _transferred: Self::Balance, + ) { + } +} + +/// Trait for slashing a fungible asset which can be place on hold. +pub trait Balanced: super::Balanced + Unbalanced { + /// Reduce the balance of some funds on hold in an account. + /// + /// The resulting imbalance is the first item of the tuple returned. + /// + /// As much funds that are on hold up to `amount` will be deducted as possible. If this is less + /// than `amount`, then a non-zero second item will be returned. + fn slash( + reason: &Self::Reason, + who: &AccountId, + amount: Self::Balance, + ) -> (Credit, Self::Balance) { + let decrease = Self::decrease_balance_on_hold(reason, who, amount, BestEffort) + .unwrap_or(Default::default()); + let credit = + Imbalance::::new(decrease); + Self::done_slash(reason, who, decrease); + (credit, amount.saturating_sub(decrease)) + } + + fn done_slash(_reason: &Self::Reason, _who: &AccountId, _amount: Self::Balance) {} +} diff --git a/frame/support/src/traits/tokens/fungible/imbalance.rs b/frame/support/src/traits/tokens/fungible/imbalance.rs index 1b3d16c62ddf4..de85924a4de7c 100644 --- a/frame/support/src/traits/tokens/fungible/imbalance.rs +++ b/frame/support/src/traits/tokens/fungible/imbalance.rs @@ -18,8 +18,11 @@ //! The imbalance type and its associates, which handles keeps everything adding up properly with //! unbalanced operations. -use super::{super::Imbalance as ImbalanceT, balanced::Balanced, misc::Balance, *}; -use crate::traits::misc::{SameOrOther, TryDrop}; +use super::{super::Imbalance as ImbalanceT, Balanced, *}; +use crate::traits::{ + misc::{SameOrOther, TryDrop}, + tokens::Balance, +}; use sp_runtime::{traits::Zero, RuntimeDebug}; use sp_std::marker::PhantomData; @@ -30,6 +33,10 @@ pub trait HandleImbalanceDrop { fn handle(amount: Balance); } +impl HandleImbalanceDrop for () { + fn handle(_: Balance) {} +} + /// An imbalance in the system, representing a divergence of recorded token supply from the sum of /// the balances of all accounts. This is `must_use` in order to ensure it gets handled (placing /// into an account, settling from an account or altering the supply). @@ -135,7 +142,7 @@ impl, OppositeOnDrop: HandleImbalance } /// Imbalance implying that the total_issuance value is less than the sum of all account balances. -pub type DebtOf = Imbalance< +pub type Debt = Imbalance< >::Balance, // This will generally be implemented by increasing the total_issuance value. >::OnDropDebt, @@ -144,7 +151,7 @@ pub type DebtOf = Imbalance< /// Imbalance implying that the total_issuance value is greater than the sum of all account /// balances. -pub type CreditOf = Imbalance< +pub type Credit = Imbalance< >::Balance, // This will generally be implemented by decreasing the total_issuance value. >::OnDropCredit, diff --git a/frame/support/src/traits/tokens/fungible/item_of.rs b/frame/support/src/traits/tokens/fungible/item_of.rs new file mode 100644 index 0000000000000..cf2d96ef28791 --- /dev/null +++ b/frame/support/src/traits/tokens/fungible/item_of.rs @@ -0,0 +1,451 @@ +// 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. + +//! Adapter to use `fungibles::*` implementations as `fungible::*`. + +use sp_core::Get; +use sp_runtime::{DispatchError, DispatchResult}; + +use super::*; +use crate::traits::tokens::{ + fungibles, DepositConsequence, Fortitude, Imbalance as ImbalanceT, Precision, Preservation, + Provenance, Restriction, WithdrawConsequence, +}; + +/// Convert a `fungibles` trait implementation into a `fungible` trait implementation by identifying +/// a single item. +pub struct ItemOf< + F: fungibles::Inspect, + A: Get<>::AssetId>, + AccountId, +>(sp_std::marker::PhantomData<(F, A, AccountId)>); + +impl< + F: fungibles::Inspect, + A: Get<>::AssetId>, + AccountId, + > Inspect for ItemOf +{ + type Balance = >::Balance; + 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()) + } + fn balance(who: &AccountId) -> Self::Balance { + >::balance(A::get(), who) + } + fn total_balance(who: &AccountId) -> Self::Balance { + >::total_balance(A::get(), who) + } + fn reducible_balance( + who: &AccountId, + preservation: Preservation, + force: Fortitude, + ) -> Self::Balance { + >::reducible_balance(A::get(), who, preservation, force) + } + fn can_deposit( + who: &AccountId, + amount: Self::Balance, + provenance: Provenance, + ) -> DepositConsequence { + >::can_deposit(A::get(), who, amount, provenance) + } + fn can_withdraw(who: &AccountId, amount: Self::Balance) -> WithdrawConsequence { + >::can_withdraw(A::get(), who, amount) + } +} + +impl< + F: fungibles::InspectHold, + A: Get<>::AssetId>, + AccountId, + > InspectHold for ItemOf +{ + type Reason = F::Reason; + + fn reducible_total_balance_on_hold(who: &AccountId, force: Fortitude) -> Self::Balance { + >::reducible_total_balance_on_hold( + A::get(), + who, + force, + ) + } + fn hold_available(reason: &Self::Reason, who: &AccountId) -> bool { + >::hold_available(A::get(), reason, who) + } + fn total_balance_on_hold(who: &AccountId) -> Self::Balance { + >::total_balance_on_hold(A::get(), who) + } + fn balance_on_hold(reason: &Self::Reason, who: &AccountId) -> Self::Balance { + >::balance_on_hold(A::get(), reason, who) + } + fn can_hold(reason: &Self::Reason, who: &AccountId, amount: Self::Balance) -> bool { + >::can_hold(A::get(), reason, who, amount) + } +} + +impl< + F: fungibles::InspectFreeze, + A: Get<>::AssetId>, + AccountId, + > InspectFreeze for ItemOf +{ + type Id = F::Id; + fn balance_frozen(id: &Self::Id, who: &AccountId) -> Self::Balance { + >::balance_frozen(A::get(), id, who) + } + fn balance_freezable(who: &AccountId) -> Self::Balance { + >::balance_freezable(A::get(), who) + } + fn can_freeze(id: &Self::Id, who: &AccountId) -> bool { + >::can_freeze(A::get(), id, who) + } +} + +impl< + F: fungibles::Unbalanced, + A: Get<>::AssetId>, + AccountId, + > Unbalanced for ItemOf +{ + fn handle_dust(dust: regular::Dust) + where + Self: Sized, + { + >::handle_dust(fungibles::Dust(A::get(), dust.0)) + } + fn write_balance( + who: &AccountId, + amount: Self::Balance, + ) -> Result, DispatchError> { + >::write_balance(A::get(), who, amount) + } + fn set_total_issuance(amount: Self::Balance) -> () { + >::set_total_issuance(A::get(), amount) + } + fn decrease_balance( + who: &AccountId, + amount: Self::Balance, + precision: Precision, + preservation: Preservation, + force: Fortitude, + ) -> Result { + >::decrease_balance( + A::get(), + who, + amount, + precision, + preservation, + force, + ) + } + fn increase_balance( + who: &AccountId, + amount: Self::Balance, + precision: Precision, + ) -> Result { + >::increase_balance(A::get(), who, amount, precision) + } +} + +impl< + F: fungibles::UnbalancedHold, + A: Get<>::AssetId>, + AccountId, + > UnbalancedHold for ItemOf +{ + fn set_balance_on_hold( + reason: &Self::Reason, + who: &AccountId, + amount: Self::Balance, + ) -> DispatchResult { + >::set_balance_on_hold( + A::get(), + reason, + who, + amount, + ) + } + fn decrease_balance_on_hold( + reason: &Self::Reason, + who: &AccountId, + amount: Self::Balance, + precision: Precision, + ) -> Result { + >::decrease_balance_on_hold( + A::get(), + reason, + who, + amount, + precision, + ) + } + fn increase_balance_on_hold( + reason: &Self::Reason, + who: &AccountId, + amount: Self::Balance, + precision: Precision, + ) -> Result { + >::increase_balance_on_hold( + A::get(), + reason, + who, + amount, + precision, + ) + } +} + +impl< + F: fungibles::Mutate, + A: Get<>::AssetId>, + AccountId, + > Mutate for ItemOf +{ + fn mint_into(who: &AccountId, amount: Self::Balance) -> Result { + >::mint_into(A::get(), who, amount) + } + fn burn_from( + who: &AccountId, + amount: Self::Balance, + precision: Precision, + force: Fortitude, + ) -> Result { + >::burn_from(A::get(), who, amount, precision, force) + } + fn shelve(who: &AccountId, amount: Self::Balance) -> Result { + >::shelve(A::get(), who, amount) + } + fn restore(who: &AccountId, amount: Self::Balance) -> Result { + >::restore(A::get(), who, amount) + } + fn transfer( + source: &AccountId, + dest: &AccountId, + amount: Self::Balance, + preservation: Preservation, + ) -> Result { + >::transfer(A::get(), source, dest, amount, preservation) + } + + fn set_balance(who: &AccountId, amount: Self::Balance) -> Self::Balance { + >::set_balance(A::get(), who, amount) + } +} + +impl< + F: fungibles::MutateHold, + A: Get<>::AssetId>, + AccountId, + > MutateHold for ItemOf +{ + fn hold(reason: &Self::Reason, who: &AccountId, amount: Self::Balance) -> DispatchResult { + >::hold(A::get(), reason, who, amount) + } + fn release( + reason: &Self::Reason, + who: &AccountId, + amount: Self::Balance, + precision: Precision, + ) -> Result { + >::release(A::get(), reason, who, amount, precision) + } + fn burn_held( + reason: &Self::Reason, + who: &AccountId, + amount: Self::Balance, + precision: Precision, + force: Fortitude, + ) -> Result { + >::burn_held( + A::get(), + reason, + who, + amount, + precision, + force, + ) + } + fn transfer_on_hold( + reason: &Self::Reason, + source: &AccountId, + dest: &AccountId, + amount: Self::Balance, + precision: Precision, + mode: Restriction, + force: Fortitude, + ) -> Result { + >::transfer_on_hold( + A::get(), + reason, + source, + dest, + amount, + precision, + mode, + force, + ) + } + fn transfer_and_hold( + reason: &Self::Reason, + source: &AccountId, + dest: &AccountId, + amount: Self::Balance, + precision: Precision, + preservation: Preservation, + force: Fortitude, + ) -> Result { + >::transfer_and_hold( + A::get(), + reason, + source, + dest, + amount, + precision, + preservation, + force, + ) + } +} + +impl< + F: fungibles::MutateFreeze, + A: Get<>::AssetId>, + AccountId, + > MutateFreeze for ItemOf +{ + fn set_freeze(id: &Self::Id, who: &AccountId, amount: Self::Balance) -> DispatchResult { + >::set_freeze(A::get(), id, who, amount) + } + fn extend_freeze(id: &Self::Id, who: &AccountId, amount: Self::Balance) -> DispatchResult { + >::extend_freeze(A::get(), id, who, amount) + } + fn thaw(id: &Self::Id, who: &AccountId) -> DispatchResult { + >::thaw(A::get(), id, who) + } +} + +pub struct ConvertImbalanceDropHandler( + sp_std::marker::PhantomData<(AccountId, Balance, AssetIdType, AssetId, Handler)>, +); + +impl< + AccountId, + Balance, + AssetIdType, + AssetId: Get, + Handler: crate::traits::tokens::fungibles::HandleImbalanceDrop, + > HandleImbalanceDrop + for ConvertImbalanceDropHandler +{ + fn handle(amount: Balance) { + Handler::handle(AssetId::get(), amount) + } +} + +impl< + F: fungibles::Inspect + + fungibles::Unbalanced + + fungibles::Balanced, + A: Get<>::AssetId>, + AccountId, + > Balanced for ItemOf +{ + type OnDropDebt = + ConvertImbalanceDropHandler; + type OnDropCredit = + ConvertImbalanceDropHandler; + fn deposit( + who: &AccountId, + value: Self::Balance, + precision: Precision, + ) -> Result, DispatchError> { + >::deposit(A::get(), who, value, precision) + .map(|debt| Imbalance::new(debt.peek())) + } + fn issue(amount: Self::Balance) -> Credit { + Imbalance::new(>::issue(A::get(), amount).peek()) + } + fn pair(amount: Self::Balance) -> (Debt, Credit) { + let (a, b) = >::pair(A::get(), amount); + (Imbalance::new(a.peek()), Imbalance::new(b.peek())) + } + fn rescind(amount: Self::Balance) -> Debt { + Imbalance::new(>::rescind(A::get(), amount).peek()) + } + fn resolve( + who: &AccountId, + credit: Credit, + ) -> Result<(), Credit> { + let credit = fungibles::Imbalance::new(A::get(), credit.peek()); + >::resolve(who, credit) + .map_err(|credit| Imbalance::new(credit.peek())) + } + fn settle( + who: &AccountId, + debt: Debt, + preservation: Preservation, + ) -> Result, Debt> { + let debt = fungibles::Imbalance::new(A::get(), debt.peek()); + >::settle(who, debt, preservation) + .map(|credit| Imbalance::new(credit.peek())) + .map_err(|debt| Imbalance::new(debt.peek())) + } + fn withdraw( + who: &AccountId, + value: Self::Balance, + precision: Precision, + preservation: Preservation, + force: Fortitude, + ) -> Result, DispatchError> { + >::withdraw( + A::get(), + who, + value, + precision, + preservation, + force, + ) + .map(|credit| Imbalance::new(credit.peek())) + } +} + +impl< + F: fungibles::BalancedHold, + A: Get<>::AssetId>, + AccountId, + > BalancedHold for ItemOf +{ + fn slash( + reason: &Self::Reason, + who: &AccountId, + amount: Self::Balance, + ) -> (Credit, Self::Balance) { + let (credit, amount) = + >::slash(A::get(), reason, who, amount); + (Imbalance::new(credit.peek()), amount) + } +} + +#[test] +fn test() {} diff --git a/frame/support/src/traits/tokens/fungible/mod.rs b/frame/support/src/traits/tokens/fungible/mod.rs new file mode 100644 index 0000000000000..204b85ac29448 --- /dev/null +++ b/frame/support/src/traits/tokens/fungible/mod.rs @@ -0,0 +1,56 @@ +// 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 traits for dealing with a single fungible token class and any associated types. +//! +//! ### User-implememted traits +//! - `Inspect`: Regular balance inspector functions. +//! - `Unbalanced`: Low-level balance mutating functions. Does not guarantee proper book-keeping and +//! so should not be called into directly from application code. Other traits depend on this and +//! provide default implementations based on it. +//! - `UnbalancedHold`: Low-level balance mutating functions for balances placed on hold. Does not +//! guarantee proper book-keeping and so should not be called into directly from application code. +//! Other traits depend on this and provide default implementations based on it. +//! - `Mutate`: Regular balance mutator functions. Pre-implemented using `Unbalanced`, though the +//! `done_*` functions should likely be reimplemented in case you want to do something following +//! the operation such as emit events. +//! - `InspectHold`: Inspector functions for balances on hold. +//! - `MutateHold`: Mutator functions for balances on hold. Mostly pre-implemented using +//! `UnbalancedHold`. +//! - `InspectFreeze`: Inspector functions for frozen balance. +//! - `MutateFreeze`: Mutator functions for frozen balance. +//! - `Balanced`: One-sided mutator functions for regular balances, which return imbalance objects +//! which guarantee eventual book-keeping. May be useful for some sophisticated operations where +//! funds must be removed from an account before it is known precisely what should be done with +//! them. + +pub mod freeze; +pub mod hold; +mod imbalance; +mod item_of; +mod regular; + +pub use freeze::{Inspect as InspectFreeze, Mutate as MutateFreeze}; +pub use hold::{ + Balanced as BalancedHold, Inspect as InspectHold, Mutate as MutateHold, + Unbalanced as UnbalancedHold, +}; +pub use imbalance::{Credit, Debt, HandleImbalanceDrop, Imbalance}; +pub use item_of::ItemOf; +pub use regular::{ + Balanced, DecreaseIssuance, Dust, IncreaseIssuance, Inspect, Mutate, Unbalanced, +}; diff --git a/frame/support/src/traits/tokens/fungible/regular.rs b/frame/support/src/traits/tokens/fungible/regular.rs new file mode 100644 index 0000000000000..574392cac8256 --- /dev/null +++ b/frame/support/src/traits/tokens/fungible/regular.rs @@ -0,0 +1,506 @@ +// 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` and `Mutate` traits for working with regular balances. + +use crate::{ + dispatch::DispatchError, + ensure, + traits::{ + tokens::{ + misc::{ + Balance, DepositConsequence, + Fortitude::{self, Force, Polite}, + Precision::{self, BestEffort, Exact}, + Preservation::{self, Expendable}, + Provenance::{self, Extant}, + WithdrawConsequence, + }, + Imbalance as ImbalanceT, + }, + SameOrOther, TryDrop, + }, +}; +use sp_arithmetic::traits::{CheckedAdd, CheckedSub, One}; +use sp_runtime::{traits::Saturating, ArithmeticError, TokenError}; +use sp_std::marker::PhantomData; + +use super::{Credit, Debt, HandleImbalanceDrop, Imbalance}; + +/// Trait for providing balance-inspection access to a fungible asset. +pub trait Inspect: Sized { + /// Scalar type for representing balance of an account. + type Balance: Balance; + + /// 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; + + /// Get the total amount of funds whose ultimate bneficial ownership can be determined as `who`. + /// + /// This may include funds which are wholly inaccessible to `who`, either temporarily or even + /// indefinitely. + /// + /// For the amount of the balance which is currently free to be removed from the account without + /// error, use `reducible_balance`. + /// + /// For the amount of the balance which may eventually be free to be removed from the account, + /// use `balance()`. + fn total_balance(who: &AccountId) -> Self::Balance; + + /// Get the balance of `who` which does not include funds which are exclusively allocated to + /// subsystems of the chain ("on hold" or "reserved"). + /// + /// In general this isn't especially useful outside of tests, and for practical purposes, you'll + /// want to use `reducible_balance()`. + fn balance(who: &AccountId) -> Self::Balance; + + /// Get the maximum amount that `who` can withdraw/transfer successfully based on whether the + /// account should be kept alive (`preservation`) or whether we are willing to force the + /// reduction and potentially go below user-level restrictions on the minimum amount of the + /// account. + /// + /// Always less than or equal to `balance()`. + fn reducible_balance( + who: &AccountId, + preservation: Preservation, + force: Fortitude, + ) -> Self::Balance; + + /// Returns `true` if the balance of `who` may be increased by `amount`. + /// + /// - `who`: The account of which the balance should be increased by `amount`. + /// - `amount`: How much should the balance be increased? + /// - `provenance`: Will `amount` be minted to deposit it into `account` or is it already in the + /// system? + fn can_deposit( + who: &AccountId, + amount: Self::Balance, + provenance: Provenance, + ) -> DepositConsequence; + + /// Returns `Success` if the balance of `who` may be decreased by `amount`, otherwise + /// the consequence. + fn can_withdraw(who: &AccountId, amount: Self::Balance) -> WithdrawConsequence; +} + +/// Special dust type which can be type-safely converted into a `Credit`. +#[must_use] +pub struct Dust>(pub(crate) T::Balance); + +impl> Dust { + /// Convert `Dust` into an instance of `Credit`. + pub fn into_credit(self) -> Credit { + Credit::::new(self.0) + } +} + +/// A fungible token class where the balance can be set arbitrarily. +/// +/// **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 +/// for the underlying datatype to implement so the user gets the much safer `Balanced` trait to +/// use. +pub trait Unbalanced: Inspect { + /// Create some dust and handle it with `Self::handle_dust`. This is an unbalanced operation + /// and it must only be used when an account is modified in a raw fashion, outside of the entire + /// fungibles API. The `amount` is capped at `Self::minimum_balance() - 1`. + /// + /// This should not be reimplemented. + fn handle_raw_dust(amount: Self::Balance) { + Self::handle_dust(Dust(amount.min(Self::minimum_balance().saturating_sub(One::one())))) + } + + /// Do something with the dust which has been destroyed from the system. `Dust` can be converted + /// into a `Credit` with the `Balanced` trait impl. + fn handle_dust(dust: Dust); + + /// Forcefully set the balance of `who` to `amount`. + /// + /// If this call executes successfully, you can `assert_eq!(Self::balance(), amount);`. + /// + /// For implementations which include one or more balances on hold, then these are *not* + /// included in the `amount`. + /// + /// This function does its best to force the balance change through, but will not break system + /// invariants such as any Existential Deposits needed or overflows/underflows. + /// If this cannot be done for some reason (e.g. because the account cannot be created, deleted + /// or would overflow) then an `Err` is returned. + /// + /// If `Ok` is returned then its inner, if `Some` is the amount which was discarded as dust due + /// to existential deposit requirements. The default implementation of `decrease_balance` and + /// `increase_balance` converts this into an `Imbalance` and then passes it into `handle_dust`. + fn write_balance( + who: &AccountId, + amount: Self::Balance, + ) -> Result, DispatchError>; + + /// Set the total issuance to `amount`. + fn set_total_issuance(amount: Self::Balance); + + /// Reduce the balance of `who` by `amount`. + /// + /// If `precision` is `Exact` and it cannot be reduced by that amount for + /// some reason, return `Err` and don't reduce it at all. If `precision` is `BestEffort`, then + /// reduce the balance of `who` by the most that is possible, up to `amount`. + /// + /// In either case, if `Ok` is returned then the inner is the amount by which is was reduced. + /// Minimum balance will be respected and thus the returned amount may be up to + /// `Self::minimum_balance() - 1` greater than `amount` in the case that the reduction caused + /// the account to be deleted. + fn decrease_balance( + who: &AccountId, + mut amount: Self::Balance, + precision: Precision, + preservation: Preservation, + force: Fortitude, + ) -> Result { + let old_balance = Self::balance(who); + let free = Self::reducible_balance(who, preservation, force); + if let BestEffort = precision { + amount = amount.min(free); + } + let new_balance = old_balance.checked_sub(&amount).ok_or(TokenError::FundsUnavailable)?; + if let Some(dust) = Self::write_balance(who, new_balance)? { + Self::handle_dust(Dust(dust)); + } + Ok(old_balance.saturating_sub(new_balance)) + } + + /// Increase the balance of `who` by `amount`. + /// + /// If it cannot be increased by that amount for some reason, return `Err` and don't increase + /// it at all. If Ok, return the imbalance. + /// Minimum balance will be respected and an error will be returned if + /// `amount < Self::minimum_balance()` when the account of `who` is zero. + fn increase_balance( + who: &AccountId, + amount: Self::Balance, + precision: Precision, + ) -> Result { + let old_balance = Self::balance(who); + let new_balance = if let BestEffort = precision { + old_balance.saturating_add(amount) + } else { + old_balance.checked_add(&amount).ok_or(ArithmeticError::Overflow)? + }; + if new_balance < Self::minimum_balance() { + // Attempt to increase from 0 to below minimum -> stays at zero. + if let BestEffort = precision { + Ok(Default::default()) + } else { + Err(TokenError::BelowMinimum.into()) + } + } else { + if new_balance == old_balance { + Ok(Default::default()) + } else { + if let Some(dust) = Self::write_balance(who, new_balance)? { + Self::handle_dust(Dust(dust)); + } + Ok(new_balance.saturating_sub(old_balance)) + } + } + } + + /// 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 providing a basic fungible asset. +pub trait Mutate: Inspect + Unbalanced { + /// Increase the balance of `who` by exactly `amount`, minting new tokens. If that isn't + /// possible then an `Err` is returned and nothing is changed. + fn mint_into(who: &AccountId, amount: Self::Balance) -> Result { + Self::total_issuance().checked_add(&amount).ok_or(ArithmeticError::Overflow)?; + let actual = Self::increase_balance(who, amount, Exact)?; + Self::set_total_issuance(Self::total_issuance().saturating_add(actual)); + Self::done_mint_into(who, amount); + Ok(actual) + } + + /// Decrease the balance of `who` by at least `amount`, possibly slightly more in the case of + /// minimum-balance requirements, burning the tokens. If that isn't possible then an `Err` is + /// returned and nothing is changed. If successful, the amount of tokens reduced is returned. + fn burn_from( + who: &AccountId, + amount: Self::Balance, + precision: Precision, + force: Fortitude, + ) -> Result { + let actual = Self::reducible_balance(who, Expendable, force).min(amount); + ensure!(actual == amount || precision == BestEffort, TokenError::FundsUnavailable); + Self::total_issuance().checked_sub(&actual).ok_or(ArithmeticError::Overflow)?; + let actual = Self::decrease_balance(who, actual, BestEffort, Expendable, force)?; + Self::set_total_issuance(Self::total_issuance().saturating_sub(actual)); + Self::done_burn_from(who, actual); + Ok(actual) + } + + /// Attempt to decrease the `asset` balance of `who` by `amount`. + /// + /// Equivalent to `burn_from`, except with an expectation that within the bounds of some + /// universal issuance, the total assets `suspend`ed and `resume`d will be equivalent. The + /// implementation may be configured such that the total assets suspended may never be less than + /// the total assets resumed (which is the invariant for an issuing system), or the reverse + /// (which the invariant in a non-issuing system). + /// + /// Because of this expectation, any metadata associated with the asset is expected to survive + /// the suspect-resume cycle. + fn shelve(who: &AccountId, amount: Self::Balance) -> Result { + let actual = Self::reducible_balance(who, Expendable, Polite).min(amount); + ensure!(actual == amount, TokenError::FundsUnavailable); + Self::total_issuance().checked_sub(&actual).ok_or(ArithmeticError::Overflow)?; + let actual = Self::decrease_balance(who, actual, BestEffort, Expendable, Polite)?; + Self::set_total_issuance(Self::total_issuance().saturating_sub(actual)); + Self::done_shelve(who, actual); + Ok(actual) + } + + /// Attempt to increase the `asset` balance of `who` by `amount`. + /// + /// Equivalent to `mint_into`, except with an expectation that within the bounds of some + /// universal issuance, the total assets `suspend`ed and `resume`d will be equivalent. The + /// implementation may be configured such that the total assets suspended may never be less than + /// the total assets resumed (which is the invariant for an issuing system), or the reverse + /// (which the invariant in a non-issuing system). + /// + /// Because of this expectation, any metadata associated with the asset is expected to survive + /// the suspect-resume cycle. + fn restore(who: &AccountId, amount: Self::Balance) -> Result { + Self::total_issuance().checked_add(&amount).ok_or(ArithmeticError::Overflow)?; + let actual = Self::increase_balance(who, amount, Exact)?; + Self::set_total_issuance(Self::total_issuance().saturating_add(actual)); + Self::done_restore(who, amount); + Ok(actual) + } + + /// Transfer funds from one account into another. + fn transfer( + source: &AccountId, + dest: &AccountId, + amount: Self::Balance, + preservation: Preservation, + ) -> Result { + let _extra = Self::can_withdraw(source, amount).into_result(preservation != Expendable)?; + Self::can_deposit(dest, amount, Extant).into_result()?; + Self::decrease_balance(source, amount, BestEffort, preservation, Polite)?; + // This should never fail as we checked `can_deposit` earlier. But we do a best-effort + // anyway. + let _ = Self::increase_balance(dest, amount, BestEffort); + Self::done_transfer(source, dest, amount); + Ok(amount) + } + + /// Simple infallible function to force an account to have a particular balance, good for use + /// in tests and benchmarks but not recommended for production code owing to the lack of + /// error reporting. + /// + /// Returns the new balance. + fn set_balance(who: &AccountId, amount: Self::Balance) -> Self::Balance { + let b = Self::balance(who); + if b > amount { + Self::burn_from(who, b - amount, BestEffort, Force).map(|d| amount.saturating_sub(d)) + } else { + Self::mint_into(who, amount - b).map(|d| amount.saturating_add(d)) + } + .unwrap_or(b) + } + + fn done_mint_into(_who: &AccountId, _amount: Self::Balance) {} + fn done_burn_from(_who: &AccountId, _amount: Self::Balance) {} + fn done_shelve(_who: &AccountId, _amount: Self::Balance) {} + fn done_restore(_who: &AccountId, _amount: Self::Balance) {} + fn done_transfer(_source: &AccountId, _dest: &AccountId, _amount: Self::Balance) {} +} + +/// Simple handler for an imbalance drop which increases the total issuance of the system by the +/// imbalance amount. Used for leftover debt. +pub struct IncreaseIssuance(PhantomData<(AccountId, U)>); +impl> HandleImbalanceDrop + for IncreaseIssuance +{ + fn handle(amount: U::Balance) { + U::set_total_issuance(U::total_issuance().saturating_add(amount)) + } +} + +/// Simple handler for an imbalance drop which decreases the total issuance of the system by the +/// imbalance amount. Used for leftover credit. +pub struct DecreaseIssuance(PhantomData<(AccountId, U)>); +impl> HandleImbalanceDrop + for DecreaseIssuance +{ + fn handle(amount: U::Balance) { + U::set_total_issuance(U::total_issuance().saturating_sub(amount)) + } +} + +/// A fungible token class where any creation and deletion of tokens is semi-explicit and where the +/// total supply is maintained automatically. +/// +/// This is auto-implemented when a token class has `Unbalanced` implemented. +pub trait Balanced: Inspect + Unbalanced { + /// The type for managing what happens when an instance of `Debt` is dropped without being used. + type OnDropDebt: HandleImbalanceDrop; + /// The type for managing what happens when an instance of `Credit` is dropped without being + /// used. + type OnDropCredit: HandleImbalanceDrop; + + /// Reduce the total issuance by `amount` and return the according imbalance. The imbalance will + /// typically be used to reduce an account by the same amount with e.g. `settle`. + /// + /// This is infallible, but doesn't guarantee that the entire `amount` is burnt, for example + /// in the case of underflow. + fn rescind(amount: Self::Balance) -> Debt { + let old = Self::total_issuance(); + let new = old.saturating_sub(amount); + Self::set_total_issuance(new); + let delta = old - new; + Self::done_rescind(delta); + Imbalance::::new(delta) + } + + /// Increase the total issuance by `amount` and return the according imbalance. The imbalance + /// will typically be used to increase an account by the same amount with e.g. + /// `resolve_into_existing` or `resolve_creating`. + /// + /// This is infallible, but doesn't guarantee that the entire `amount` is issued, for example + /// in the case of overflow. + fn issue(amount: Self::Balance) -> Credit { + let old = Self::total_issuance(); + let new = old.saturating_add(amount); + Self::set_total_issuance(new); + let delta = new - old; + Self::done_issue(delta); + Imbalance::::new(delta) + } + + /// Produce a pair of imbalances that cancel each other out exactly. + /// + /// 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) -> (Debt, Credit) { + (Self::rescind(amount), Self::issue(amount)) + } + + /// Mints `value` into the account of `who`, creating it as needed. + /// + /// If `precision` is `BestEffort` and `value` in full could not be minted (e.g. due to + /// overflow), then the maximum is minted, up to `value`. If `precision` is `Exact`, then + /// exactly `value` must be minted into the account of `who` or the operation will fail with an + /// `Err` and nothing will change. + /// + /// If the operation is successful, this will return `Ok` with a `Debt` of the total value + /// added to the account. + fn deposit( + who: &AccountId, + value: Self::Balance, + precision: Precision, + ) -> Result, DispatchError> { + let increase = Self::increase_balance(who, value, precision)?; + Self::done_deposit(who, increase); + Ok(Imbalance::::new(increase)) + } + + /// Removes `value` balance from `who` account if possible. + /// + /// If `precision` is `BestEffort` and `value` in full could not be removed (e.g. due to + /// underflow), then the maximum is removed, up to `value`. If `precision` is `Exact`, then + /// exactly `value` must be removed from the account of `who` or the operation will fail with an + /// `Err` and nothing will change. + /// + /// If the removal is needed but not possible, then it returns `Err` and nothing is changed. + /// If the account needed to be deleted, then slightly more than `value` may be removed from the + /// account owning since up to (but not including) minimum balance may also need to be removed. + /// + /// If the operation is successful, this will return `Ok` with a `Credit` of the total value + /// removed from the account. + fn withdraw( + who: &AccountId, + value: Self::Balance, + precision: Precision, + preservation: Preservation, + force: Fortitude, + ) -> Result, DispatchError> { + let decrease = Self::decrease_balance(who, value, precision, preservation, force)?; + Self::done_withdraw(who, decrease); + Ok(Imbalance::::new(decrease)) + } + + /// The balance of `who` is increased in order to counter `credit`. If the whole of `credit` + /// cannot be countered, then nothing is changed and the original `credit` is returned in an + /// `Err`. + /// + /// Please note: If `credit.peek()` is less than `Self::minimum_balance()`, then `who` must + /// already exist for this to succeed. + fn resolve( + who: &AccountId, + credit: Credit, + ) -> Result<(), Credit> { + let v = credit.peek(); + let debt = match Self::deposit(who, v, Exact) { + Err(_) => return Err(credit), + Ok(d) => d, + }; + let result = credit.offset(debt).try_drop(); + debug_assert!(result.is_ok(), "ok deposit return must be equal to credit value; qed"); + Ok(()) + } + + /// The balance of `who` is decreased in order to counter `debt`. If the whole of `debt` + /// cannot be countered, then nothing is changed and the original `debt` is returned in an + /// `Err`. + fn settle( + who: &AccountId, + debt: Debt, + preservation: Preservation, + ) -> Result, Debt> { + let amount = debt.peek(); + let credit = match Self::withdraw(who, amount, Exact, preservation, Polite) { + Err(_) => return Err(debt), + Ok(d) => d, + }; + + match credit.offset(debt) { + SameOrOther::None => Ok(Credit::::zero()), + SameOrOther::Same(dust) => Ok(dust), + SameOrOther::Other(rest) => { + debug_assert!(false, "ok withdraw return must be at least debt value; qed"); + Err(rest) + }, + } + } + + fn done_rescind(_amount: Self::Balance) {} + fn done_issue(_amount: Self::Balance) {} + fn done_deposit(_who: &AccountId, _amount: Self::Balance) {} + fn done_withdraw(_who: &AccountId, _amount: Self::Balance) {} +} diff --git a/frame/support/src/traits/tokens/fungibles.rs b/frame/support/src/traits/tokens/fungibles.rs deleted file mode 100644 index d146832f3b649..0000000000000 --- a/frame/support/src/traits/tokens/fungibles.rs +++ /dev/null @@ -1,332 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! The traits for sets of fungible tokens and any associated types. - -use super::{ - misc::{AssetId, Balance}, - *, -}; -use crate::dispatch::{DispatchError, DispatchResult}; -use sp_runtime::traits::Saturating; -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; -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 { - /// Means of identifying one asset class from another. - type AssetId: AssetId; - - /// Scalar type for representing balance of an account. - type Balance: Balance; - - /// 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; - - /// Get the `asset` balance of `who`. - fn balance(asset: Self::AssetId, who: &AccountId) -> Self::Balance; - - /// Get the maximum amount of `asset` that `who` can withdraw/transfer successfully. - 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 - /// the consequence. - fn can_withdraw( - asset: Self::AssetId, - 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. -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`. - /// - /// If not possible then don't do anything. Possible reasons for failure include: - /// - Minimum balance not met. - /// - Account cannot be created (e.g. because there is no provider reference and/or the asset - /// isn't considered worth anything). - /// - /// Since this is an operation which should be possible to take alone, if successful it will - /// increase the overall supply of the underlying token. - fn mint_into(asset: Self::AssetId, who: &AccountId, amount: Self::Balance) -> DispatchResult; - - /// Attempt to reduce the `asset` balance of `who` by `amount`. - /// - /// If not possible then don't do anything. Possible reasons for failure include: - /// - Less funds in the account than `amount` - /// - Liquidity requirements (locks, reservations) prevent the funds from being removed - /// - Operation would require destroying the account and it is required to stay alive (e.g. - /// because it's providing a needed provider reference). - /// - /// Since this is an operation which should be possible to take alone, if successful it will - /// reduce the overall supply of the underlying token. - /// - /// Due to minimum balance requirements, it's possible that the amount withdrawn could be up to - /// `Self::minimum_balance() - 1` more than the `amount`. The total amount withdrawn is returned - /// in an `Ok` result. This may be safely ignored if you don't mind the overall supply reducing. - fn burn_from( - asset: Self::AssetId, - who: &AccountId, - amount: Self::Balance, - ) -> Result; - - /// Attempt to reduce the `asset` balance of `who` by as much as possible up to `amount`, and - /// possibly slightly more due to minimum_balance requirements. If no decrease is possible then - /// an `Err` 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. - fn slash( - asset: Self::AssetId, - who: &AccountId, - amount: Self::Balance, - ) -> Result { - Self::burn_from(asset, who, Self::reducible_balance(asset, who, false).min(amount)) - } - - /// Transfer funds from one account into another. The default implementation uses `mint_into` - /// and `burn_from` and may generate unwanted events. - fn teleport( - asset: Self::AssetId, - source: &AccountId, - dest: &AccountId, - amount: Self::Balance, - ) -> Result { - 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()?; - let actual = Self::burn_from(asset, source, amount)?; - debug_assert!( - actual == amount.saturating_add(extra), - "can_withdraw must agree with withdraw; qed" - ); - match Self::mint_into(asset, dest, actual) { - Ok(_) => Ok(actual), - Err(err) => { - debug_assert!(false, "can_deposit returned true previously; qed"); - // attempt to return the funds back to source - let revert = Self::mint_into(asset, source, actual); - debug_assert!(revert.is_ok(), "withdrew funds previously; qed"); - Err(err) - }, - } - } -} - -/// Trait for providing a set of named fungible assets which can only be transferred. -pub trait Transfer: Inspect { - /// Transfer funds from one account into another. - fn transfer( - asset: Self::AssetId, - source: &AccountId, - dest: &AccountId, - 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. -pub trait InspectHold: Inspect { - /// Amount of funds held in hold. - fn balance_on_hold(asset: Self::AssetId, who: &AccountId) -> Self::Balance; - - /// Check to see if some `amount` of `asset` may be held on the account of `who`. - fn can_hold(asset: Self::AssetId, who: &AccountId, amount: Self::Balance) -> bool; -} - -/// Trait for mutating a set of named fungible assets which can be placed on hold. -pub trait MutateHold: InspectHold + Transfer { - /// Hold some funds in an account. - fn hold(asset: Self::AssetId, who: &AccountId, amount: Self::Balance) -> DispatchResult; - - /// Release some funds in an account from being on hold. - /// - /// If `best_effort` is `true`, then the amount actually released and returned as the inner - /// value of `Ok` may be smaller than the `amount` passed. - fn release( - asset: Self::AssetId, - who: &AccountId, - amount: Self::Balance, - best_effort: bool, - ) -> Result; - - /// Transfer held funds into a destination account. - /// - /// If `on_hold` is `true`, then the destination account must already exist and the assets - /// transferred will still be on hold in the destination account. If not, then the destination - /// account need not already exist, but must be creatable. - /// - /// If `best_effort` is `true`, then an amount less than `amount` may be transferred without - /// error. - /// - /// The actual amount transferred is returned, or `Err` in the case of error and nothing is - /// changed. - fn transfer_held( - asset: Self::AssetId, - source: &AccountId, - dest: &AccountId, - amount: Self::Balance, - best_effort: bool, - on_hold: bool, - ) -> Result; -} - -/// Trait for mutating one of several types of fungible assets which can be held. -pub trait BalancedHold: Balanced + MutateHold { - /// Release and slash some funds in an account. - /// - /// The resulting imbalance is the first item of the tuple returned. - /// - /// As much funds up to `amount` will be deducted as possible. If this is less than `amount`, - /// then a non-zero second item will be returned. - fn slash_held( - asset: Self::AssetId, - who: &AccountId, - amount: Self::Balance, - ) -> (CreditOf, Self::Balance); -} - -impl + MutateHold> BalancedHold for T { - fn slash_held( - asset: Self::AssetId, - who: &AccountId, - amount: Self::Balance, - ) -> (CreditOf, Self::Balance) { - let actual = match Self::release(asset, who, amount, true) { - Ok(x) => x, - Err(_) => return (Imbalance::zero(asset), amount), - }; - >::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 { - /// 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, 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 - /// - /// * `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; -} diff --git a/frame/support/src/traits/tokens/fungibles/balanced.rs b/frame/support/src/traits/tokens/fungibles/balanced.rs deleted file mode 100644 index 598ba250ee806..0000000000000 --- a/frame/support/src/traits/tokens/fungibles/balanced.rs +++ /dev/null @@ -1,394 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! The trait and associated types for sets of fungible tokens that manage total issuance without -//! requiring atomic balanced operations. - -use super::*; -use crate::{ - dispatch::{DispatchError, DispatchResult}, - traits::misc::{SameOrOther, TryDrop}, -}; -use sp_arithmetic::traits::Saturating; -use sp_runtime::{ - traits::{CheckedAdd, Zero}, - ArithmeticError, TokenError, -}; -use sp_std::marker::PhantomData; - -/// A fungible token class where any creation and deletion of tokens is semi-explicit and where the -/// total supply is maintained automatically. -/// -/// This is auto-implemented when a token class has `Unbalanced` implemented. -pub trait Balanced: Inspect { - /// The type for managing what happens when an instance of `Debt` is dropped without being used. - type OnDropDebt: HandleImbalanceDrop; - /// The type for managing what happens when an instance of `Credit` is dropped without being - /// used. - type OnDropCredit: HandleImbalanceDrop; - - /// Reduce the total issuance by `amount` and return the according imbalance. The imbalance will - /// typically be used to reduce an account by the same amount with e.g. `settle`. - /// - /// This is infallible, but doesn't guarantee that the entire `amount` is burnt, for example - /// in the case of underflow. - fn rescind(asset: Self::AssetId, amount: Self::Balance) -> DebtOf; - - /// Increase the total issuance by `amount` and return the according imbalance. The imbalance - /// will typically be used to increase an account by the same amount with e.g. - /// `resolve_into_existing` or `resolve_creating`. - /// - /// This is infallible, but doesn't guarantee that the entire `amount` is issued, for example - /// in the case of overflow. - fn issue(asset: Self::AssetId, amount: Self::Balance) -> CreditOf; - - /// Produce a pair of imbalances that cancel each other out exactly. - /// - /// This is just the same as burning and issuing the same amount and has no effect on the - /// total issuance. - fn pair( - asset: Self::AssetId, - amount: Self::Balance, - ) -> (DebtOf, CreditOf) { - (Self::rescind(asset, amount), Self::issue(asset, amount)) - } - - /// Deducts up to `value` from the combined balance of `who`, preferring to deduct from the - /// free balance. This function cannot fail. - /// - /// The resulting imbalance is the first item of the tuple returned. - /// - /// As much funds up to `value` will be deducted as possible. If this is less than `value`, - /// then a non-zero second item will be returned. - fn slash( - asset: Self::AssetId, - who: &AccountId, - amount: Self::Balance, - ) -> (CreditOf, Self::Balance); - - /// Mints exactly `value` into the `asset` account of `who`. - /// - /// If `who` doesn't exist, nothing is done and an `Err` returned. This could happen because it - /// the account doesn't yet exist and it isn't possible to create it under the current - /// circumstances and with `value` in it. - fn deposit( - asset: Self::AssetId, - who: &AccountId, - value: Self::Balance, - ) -> Result, DispatchError>; - - /// Removes `value` free `asset` balance from `who` account if possible. - /// - /// If the removal is not possible, then it returns `Err` and nothing is changed. - /// - /// If the operation is successful, this will return `Ok` with a `NegativeImbalance` whose value - /// is no less than `value`. It may be more in the case that removing it reduced it below - /// `Self::minimum_balance()`. - fn withdraw( - asset: Self::AssetId, - who: &AccountId, - value: Self::Balance, - // TODO: liveness: ExistenceRequirement, - ) -> Result, DispatchError>; - - /// The balance of `who` is increased in order to counter `credit`. If the whole of `credit` - /// cannot be countered, then nothing is changed and the original `credit` is returned in an - /// `Err`. - /// - /// Please note: If `credit.peek()` is less than `Self::minimum_balance()`, then `who` must - /// already exist for this to succeed. - fn resolve( - who: &AccountId, - credit: CreditOf, - ) -> Result<(), CreditOf> { - let v = credit.peek(); - let debt = match Self::deposit(credit.asset(), who, v) { - Err(_) => return Err(credit), - Ok(d) => d, - }; - if let Ok(result) = credit.offset(debt) { - let result = result.try_drop(); - debug_assert!(result.is_ok(), "ok deposit return must be equal to credit value; qed"); - } else { - debug_assert!(false, "debt.asset is credit.asset; qed"); - } - Ok(()) - } - - /// The balance of `who` is decreased in order to counter `debt`. If the whole of `debt` - /// cannot be countered, then nothing is changed and the original `debt` is returned in an - /// `Err`. - fn settle( - who: &AccountId, - debt: DebtOf, - // TODO: liveness: ExistenceRequirement, - ) -> Result, DebtOf> { - let amount = debt.peek(); - let asset = debt.asset(); - let credit = match Self::withdraw(asset, who, amount) { - Err(_) => return Err(debt), - Ok(d) => d, - }; - match credit.offset(debt) { - Ok(SameOrOther::None) => Ok(CreditOf::::zero(asset)), - Ok(SameOrOther::Same(dust)) => Ok(dust), - Ok(SameOrOther::Other(rest)) => { - debug_assert!(false, "ok withdraw return must be at least debt value; qed"); - Err(rest) - }, - Err(_) => { - debug_assert!(false, "debt.asset is credit.asset; qed"); - Ok(CreditOf::::zero(asset)) - }, - } - } -} - -/// A fungible token class where the balance can be set arbitrarily. -/// -/// **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 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 { - /// Set the `asset` balance of `who` to `amount`. If this cannot be done for some reason (e.g. - /// because the account cannot be created or an overflow) then an `Err` is returned. - fn set_balance(asset: Self::AssetId, who: &AccountId, amount: Self::Balance) -> DispatchResult; - - /// Set the total issuance of `asset` to `amount`. - fn set_total_issuance(asset: Self::AssetId, amount: Self::Balance); - - /// Reduce the `asset` balance of `who` by `amount`. If it cannot be reduced by that amount for - /// some reason, return `Err` and don't reduce it at all. If Ok, return the imbalance. - /// - /// Minimum balance will be respected and the returned imbalance may be up to - /// `Self::minimum_balance() - 1` greater than `amount`. - fn decrease_balance( - asset: Self::AssetId, - who: &AccountId, - amount: Self::Balance, - ) -> Result { - let old_balance = Self::balance(asset, who); - let (mut new_balance, mut amount) = if Self::reducible_balance(asset, who, false) < amount { - return Err(TokenError::NoFunds.into()) - } else { - (old_balance - amount, amount) - }; - if new_balance < Self::minimum_balance(asset) { - amount = amount.saturating_add(new_balance); - new_balance = Zero::zero(); - } - // Defensive only - this should not fail now. - Self::set_balance(asset, who, new_balance)?; - Ok(amount) - } - - /// Reduce the `asset` balance of `who` by the most that is possible, up to `amount`. - /// - /// Minimum balance will be respected and the returned imbalance may be up to - /// `Self::minimum_balance() - 1` greater than `amount`. - /// - /// Return the imbalance by which the account was reduced. - fn decrease_balance_at_most( - asset: Self::AssetId, - who: &AccountId, - amount: Self::Balance, - ) -> Self::Balance { - let old_balance = Self::balance(asset, who); - 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) - }; - let minimum_balance = Self::minimum_balance(asset); - if new_balance < minimum_balance { - amount = amount.saturating_add(new_balance); - new_balance = Zero::zero(); - } - let mut r = Self::set_balance(asset, who, new_balance); - if r.is_err() { - // Some error, probably because we tried to destroy an account which cannot be - // destroyed. - if new_balance.is_zero() && amount >= minimum_balance { - new_balance = minimum_balance; - amount -= minimum_balance; - r = Self::set_balance(asset, who, new_balance); - } - if r.is_err() { - // Still an error. Apparently it's not possible to reduce at all. - amount = Zero::zero(); - } - } - amount - } - - /// Increase the `asset` balance of `who` by `amount`. If it cannot be increased by that amount - /// for some reason, return `Err` and don't increase it at all. If Ok, return the imbalance. - /// - /// Minimum balance will be respected and an error will be returned if - /// `amount < Self::minimum_balance()` when the account of `who` is zero. - fn increase_balance( - asset: Self::AssetId, - who: &AccountId, - amount: Self::Balance, - ) -> Result { - 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) { - return Err(TokenError::BelowMinimum.into()) - } - if old_balance != new_balance { - Self::set_balance(asset, who, new_balance)?; - } - Ok(amount) - } - - /// Increase the `asset` balance of `who` by the most that is possible, up to `amount`. - /// - /// Minimum balance will be respected and the returned imbalance will be zero in the case that - /// `amount < Self::minimum_balance()`. - /// - /// Return the imbalance by which the account was increased. - fn increase_balance_at_most( - asset: Self::AssetId, - who: &AccountId, - amount: Self::Balance, - ) -> Self::Balance { - let old_balance = Self::balance(asset, who); - let mut new_balance = old_balance.saturating_add(amount); - let mut amount = new_balance - old_balance; - if new_balance < Self::minimum_balance(asset) { - new_balance = Zero::zero(); - amount = Zero::zero(); - } - if old_balance == new_balance || Self::set_balance(asset, who, new_balance).is_ok() { - amount - } else { - Zero::zero() - } - } -} - -/// Simple handler for an imbalance drop which increases the total issuance of the system by the -/// imbalance amount. Used for leftover debt. -pub struct IncreaseIssuance(PhantomData<(AccountId, U)>); -impl> HandleImbalanceDrop - for IncreaseIssuance -{ - fn handle(asset: U::AssetId, amount: U::Balance) { - U::set_total_issuance(asset, U::total_issuance(asset).saturating_add(amount)) - } -} - -/// Simple handler for an imbalance drop which decreases the total issuance of the system by the -/// imbalance amount. Used for leftover credit. -pub struct DecreaseIssuance(PhantomData<(AccountId, U)>); -impl> HandleImbalanceDrop - for DecreaseIssuance -{ - fn handle(asset: U::AssetId, amount: U::Balance) { - U::set_total_issuance(asset, U::total_issuance(asset).saturating_sub(amount)) - } -} - -/// An imbalance type which uses `DecreaseIssuance` to deal with anything `Drop`ed. -/// -/// Basically means that funds in someone's account have been removed and not yet placed anywhere -/// else. If it gets dropped, then those funds will be assumed to be "burned" and the total supply -/// will be accordingly decreased to ensure it equals the sum of the balances of all accounts. -type Credit = Imbalance< - >::AssetId, - >::Balance, - DecreaseIssuance, - IncreaseIssuance, ->; - -/// An imbalance type which uses `IncreaseIssuance` to deal with anything `Drop`ed. -/// -/// Basically means that there are funds in someone's account whose origin is as yet unaccounted -/// for. If it gets dropped, then those funds will be assumed to be "minted" and the total supply -/// will be accordingly increased to ensure it equals the sum of the balances of all accounts. -type Debt = Imbalance< - >::AssetId, - >::Balance, - IncreaseIssuance, - DecreaseIssuance, ->; - -/// Create some `Credit` item. Only for internal use. -fn credit>( - asset: U::AssetId, - amount: U::Balance, -) -> Credit { - Imbalance::new(asset, amount) -} - -/// Create some `Debt` item. Only for internal use. -fn debt>( - asset: U::AssetId, - amount: U::Balance, -) -> Debt { - Imbalance::new(asset, amount) -} - -impl> Balanced for U { - type OnDropCredit = DecreaseIssuance; - type OnDropDebt = IncreaseIssuance; - fn rescind(asset: Self::AssetId, amount: Self::Balance) -> Debt { - U::set_total_issuance(asset, U::total_issuance(asset).saturating_sub(amount)); - debt(asset, amount) - } - fn issue(asset: Self::AssetId, amount: Self::Balance) -> Credit { - U::set_total_issuance(asset, U::total_issuance(asset).saturating_add(amount)); - credit(asset, amount) - } - fn slash( - asset: Self::AssetId, - who: &AccountId, - amount: Self::Balance, - ) -> (Credit, Self::Balance) { - let slashed = U::decrease_balance_at_most(asset, who, amount); - // `slashed` could be less than, greater than or equal to `amount`. - // If slashed == amount, it means the account had at least amount in it and it could all be - // removed without a problem. - // If slashed > amount, it means the account had more than amount in it, but not enough more - // to push it over minimum_balance. - // If slashed < amount, it means the account didn't have enough in it to be reduced by - // `amount` without being destroyed. - (credit(asset, slashed), amount.saturating_sub(slashed)) - } - fn deposit( - asset: Self::AssetId, - who: &AccountId, - amount: Self::Balance, - ) -> Result, DispatchError> { - let increase = U::increase_balance(asset, who, amount)?; - Ok(debt(asset, increase)) - } - fn withdraw( - asset: Self::AssetId, - who: &AccountId, - amount: Self::Balance, - // TODO: liveness: ExistenceRequirement, - ) -> Result, DispatchError> { - let decrease = U::decrease_balance(asset, who, amount)?; - Ok(credit(asset, decrease)) - } -} diff --git a/frame/support/src/traits/tokens/fungibles/enumerable.rs b/frame/support/src/traits/tokens/fungibles/enumerable.rs index 5d7266d9f2c16..08bb784a7dbf6 100644 --- a/frame/support/src/traits/tokens/fungibles/enumerable.rs +++ b/frame/support/src/traits/tokens/fungibles/enumerable.rs @@ -15,10 +15,8 @@ // 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 { +pub trait Inspect: super::Inspect { type AssetsIterator; /// Returns an iterator of the collections in existence. diff --git a/frame/support/src/traits/tokens/fungibles/freeze.rs b/frame/support/src/traits/tokens/fungibles/freeze.rs new file mode 100644 index 0000000000000..08549c2d4b744 --- /dev/null +++ b/frame/support/src/traits/tokens/fungibles/freeze.rs @@ -0,0 +1,78 @@ +// 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 traits for putting freezes within a single fungible token class. + +use scale_info::TypeInfo; +use sp_runtime::DispatchResult; + +/// Trait for inspecting a fungible asset which can be frozen. Freezing is essentially setting a +/// minimum balance below which the total balance (inclusive of any funds placed on hold) may not +/// be normally allowed to drop. Generally, freezers will provide an "update" function such that +/// if the total balance does drop below the limit, then the freezer can update their housekeeping +/// accordingly. +pub trait Inspect: super::Inspect { + /// An identifier for a freeze. + type Id: codec::Encode + TypeInfo + 'static; + + /// Amount of funds held in reserve by `who` for the given `id`. + fn balance_frozen(asset: Self::AssetId, id: &Self::Id, who: &AccountId) -> Self::Balance; + + /// The amount of the balance which can become frozen. Defaults to `total_balance()`. + fn balance_freezable(asset: Self::AssetId, who: &AccountId) -> Self::Balance { + Self::total_balance(asset, who) + } + + /// Returns `true` if it's possible to introduce a freeze for the given `id` onto the + /// account of `who`. This will be true as long as the implementor supports as many + /// concurrent freeze locks as there are possible values of `id`. + fn can_freeze(asset: Self::AssetId, id: &Self::Id, who: &AccountId) -> bool; +} + +/// Trait for introducing, altering and removing locks to freeze an account's funds so they never +/// go below a set minimum. +pub trait Mutate: Inspect { + /// Prevent actions which would reduce the balance of the account of `who` below the given + /// `amount` and identify this restriction though the given `id`. Unlike `extend_freeze`, any + /// outstanding freeze in place for `who` under the `id` are dropped. + /// + /// If `amount` is zero, it is equivalent to using `thaw`. + /// + /// Note that `amount` can be greater than the total balance, if desired. + fn set_freeze( + asset: Self::AssetId, + id: &Self::Id, + who: &AccountId, + amount: Self::Balance, + ) -> DispatchResult; + + /// Prevent the balance of the account of `who` from being reduced below the given `amount` and + /// identify this restriction though the given `id`. Unlike `set_freeze`, this does not + /// counteract any pre-existing freezes in place for `who` under the `id`. Also unlike + /// `set_freeze`, in the case that `amount` is zero, this is no-op and never fails. + /// + /// Note that more funds can be locked than the total balance, if desired. + fn extend_freeze( + asset: Self::AssetId, + id: &Self::Id, + who: &AccountId, + amount: Self::Balance, + ) -> DispatchResult; + + /// Remove an existing lock. + fn thaw(asset: Self::AssetId, id: &Self::Id, who: &AccountId) -> DispatchResult; +} diff --git a/frame/support/src/traits/tokens/fungibles/hold.rs b/frame/support/src/traits/tokens/fungibles/hold.rs new file mode 100644 index 0000000000000..68580ebff4bce --- /dev/null +++ b/frame/support/src/traits/tokens/fungibles/hold.rs @@ -0,0 +1,457 @@ +// 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 traits for putting holds within a single fungible token class. + +use crate::{ + ensure, + traits::tokens::{ + DepositConsequence::Success, + Fortitude::{self, Force}, + Precision::{self, BestEffort, Exact}, + Preservation::{self, Protect}, + Provenance::Extant, + Restriction::{self, Free, OnHold}, + }, +}; +use scale_info::TypeInfo; +use sp_arithmetic::{ + traits::{CheckedAdd, CheckedSub, Zero}, + ArithmeticError, +}; +use sp_runtime::{DispatchError, DispatchResult, Saturating, TokenError}; + +use super::*; + +/// Trait for inspecting a fungible asset whose accounts support partitioning and slashing. +pub trait Inspect: super::Inspect { + /// An identifier for a hold. Used for disambiguating different holds so that + /// they can be individually replaced or removed and funds from one hold don't accidentally + /// become unreserved or slashed for another. + type Reason: codec::Encode + TypeInfo + 'static; + + /// Amount of funds on hold (for all hold reasons) of `who`. + fn total_balance_on_hold(asset: Self::AssetId, who: &AccountId) -> Self::Balance; + + /// Get the maximum amount that the `total_balance_on_hold` of `who` can be reduced successfully + /// based on whether we are willing to force the reduction and potentially go below user-level + /// restrictions on the minimum amount of the account. Note: This cannot bring the account into + /// an inconsistent state with regards any required existential deposit. + /// + /// Always less than `total_balance_on_hold()`. + fn reducible_total_balance_on_hold( + asset: Self::AssetId, + who: &AccountId, + force: Fortitude, + ) -> Self::Balance; + + /// Amount of funds on hold (for the given reason) of `who`. + fn balance_on_hold( + asset: Self::AssetId, + reason: &Self::Reason, + who: &AccountId, + ) -> Self::Balance; + + /// Returns `true` if it's possible to place (additional) funds under a hold of a given + /// `reason`. This may fail if the account has exhausted a limited number of concurrent + /// holds or if it cannot be made to exist (e.g. there is no provider reference). + /// + /// NOTE: This does not take into account changes which could be made to the account of `who` + /// (such as removing a provider reference) after this call is made. Any usage of this should + /// therefore ensure the account is already in the appropriate state prior to calling it. + fn hold_available(asset: Self::AssetId, reason: &Self::Reason, who: &AccountId) -> bool; + + /// Check to see if some `amount` of funds of `who` may be placed on hold with the given + /// `reason`. Reasons why this may not be true: + /// + /// - The implementor supports only a limited number of concurrent holds on an account which is + /// the possible values of `reason`; + /// - The total balance of the account is less than `amount`; + /// - Removing `amount` from the total balance would kill the account and remove the only + /// provider reference. + /// + /// Note: we pass `Fortitude::Force` as the last argument to `reducible_balance` since we assume + /// that if needed the balance can slashed. If we are using a simple non-forcing + /// reserve-transfer, then we really ought to check that we are not reducing the funds below the + /// freeze-limit (if any). + /// + /// NOTE: This does not take into account changes which could be made to the account of `who` + /// (such as removing a provider reference) after this call is made. Any usage of this should + /// therefore ensure the account is already in the appropriate state prior to calling it. + fn ensure_can_hold( + asset: Self::AssetId, + reason: &Self::Reason, + who: &AccountId, + amount: Self::Balance, + ) -> DispatchResult { + ensure!(Self::hold_available(asset, reason, who), TokenError::CannotCreateHold); + ensure!( + amount <= Self::reducible_balance(asset, who, Protect, Force), + TokenError::FundsUnavailable + ); + Ok(()) + } + + /// Check to see if some `amount` of funds of `who` may be placed on hold for the given + /// `reason`. Reasons why this may not be true: + /// + /// - The implementor supports only a limited number of concurrent holds on an account which is + /// the possible values of `reason`; + /// - The main balance of the account is less than `amount`; + /// - Removing `amount` from the main balance would kill the account and remove the only + /// provider reference. + /// + /// NOTE: This does not take into account changes which could be made to the account of `who` + /// (such as removing a provider reference) after this call is made. Any usage of this should + /// therefore ensure the account is already in the appropriate state prior to calling it. + fn can_hold( + asset: Self::AssetId, + reason: &Self::Reason, + who: &AccountId, + amount: Self::Balance, + ) -> bool { + Self::ensure_can_hold(asset, reason, who, amount).is_ok() + } +} + +/// A fungible, holdable token class where the balance on hold can be set arbitrarily. +/// +/// **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 +/// for the underlying datatype to implement so the user gets the much safer `Balanced` trait to +/// use. +pub trait Unbalanced: Inspect { + /// Forcefully set the balance on hold of `who` to `amount`. This is independent of any other + /// balances on hold or the main ("free") balance. + /// + /// If this call executes successfully, you can `assert_eq!(Self::balance_on_hold(), amount);`. + /// + /// This function does its best to force the balance change through, but will not break system + /// invariants such as any Existential Deposits needed or overflows/underflows. + /// If this cannot be done for some reason (e.g. because the account doesn't exist) then an + /// `Err` is returned. + // Implmentation note: This should increment the consumer refs if it moves total on hold from + // zero to non-zero and decrement in the opposite direction. + // + // Since this was not done in the previous logic, this will need either a migration or a + // state item which tracks whether the account is on the old logic or new. + fn set_balance_on_hold( + asset: Self::AssetId, + reason: &Self::Reason, + who: &AccountId, + amount: Self::Balance, + ) -> DispatchResult; + + /// Reduce the balance on hold of `who` by `amount`. + /// + /// If `precision` is `Precision::Exact` and it cannot be reduced by that amount for + /// some reason, return `Err` and don't reduce it at all. If `precision` is + /// `Precision::BestEffort`, then reduce the balance of `who` by the most that is possible, up + /// to `amount`. + /// + /// In either case, if `Ok` is returned then the inner is the amount by which is was reduced. + fn decrease_balance_on_hold( + asset: Self::AssetId, + reason: &Self::Reason, + who: &AccountId, + mut amount: Self::Balance, + precision: Precision, + ) -> Result { + let old_balance = Self::balance_on_hold(asset, reason, who); + if let BestEffort = precision { + amount = amount.min(old_balance); + } + let new_balance = old_balance.checked_sub(&amount).ok_or(TokenError::FundsUnavailable)?; + Self::set_balance_on_hold(asset, reason, who, new_balance)?; + Ok(amount) + } + + /// Increase the balance on hold of `who` by `amount`. + /// + /// If it cannot be increased by that amount for some reason, return `Err` and don't increase + /// it at all. If Ok, return the imbalance. + fn increase_balance_on_hold( + asset: Self::AssetId, + reason: &Self::Reason, + who: &AccountId, + amount: Self::Balance, + precision: Precision, + ) -> Result { + let old_balance = Self::balance_on_hold(asset, reason, who); + let new_balance = if let BestEffort = precision { + old_balance.saturating_add(amount) + } else { + old_balance.checked_add(&amount).ok_or(ArithmeticError::Overflow)? + }; + let amount = new_balance.saturating_sub(old_balance); + if !amount.is_zero() { + Self::set_balance_on_hold(asset, reason, who, new_balance)?; + } + Ok(amount) + } +} + +/// Trait for slashing a fungible asset which can be place on hold. +pub trait Balanced: super::Balanced + Unbalanced { + /// Reduce the balance of some funds on hold in an account. + /// + /// The resulting imbalance is the first item of the tuple returned. + /// + /// As much funds that are on hold up to `amount` will be deducted as possible. If this is less + /// than `amount`, then a non-zero second item will be returned. + fn slash( + asset: Self::AssetId, + reason: &Self::Reason, + who: &AccountId, + amount: Self::Balance, + ) -> (Credit, Self::Balance) { + let decrease = Self::decrease_balance_on_hold(asset, reason, who, amount, BestEffort) + .unwrap_or(Default::default()); + let credit = + Imbalance::::new( + asset, decrease, + ); + Self::done_slash(asset, reason, who, decrease); + (credit, amount.saturating_sub(decrease)) + } + + fn done_slash( + _asset: Self::AssetId, + _reason: &Self::Reason, + _who: &AccountId, + _amount: Self::Balance, + ) { + } +} + +/// Trait for mutating a fungible asset which can be placed on hold. +pub trait Mutate: + Inspect + super::Unbalanced + Unbalanced +{ + /// Hold some funds in an account. If a hold for `reason` is already in place, then this + /// will increase it. + fn hold( + asset: Self::AssetId, + reason: &Self::Reason, + who: &AccountId, + amount: Self::Balance, + ) -> DispatchResult { + // NOTE: This doesn't change the total balance of the account so there's no need to + // check liquidity. + + Self::ensure_can_hold(asset, reason, who, amount)?; + // Should be infallible now, but we proceed softly anyway. + Self::decrease_balance(asset, who, amount, Exact, Protect, Force)?; + Self::increase_balance_on_hold(asset, reason, who, amount, BestEffort)?; + Self::done_hold(asset, reason, who, amount); + Ok(()) + } + + /// Release up to `amount` held funds in an account. + /// + /// The actual amount released is returned with `Ok`. + /// + /// If `precision` is `BestEffort`, then the amount actually unreserved and returned as the + /// inner value of `Ok` may be smaller than the `amount` passed. + fn release( + asset: Self::AssetId, + reason: &Self::Reason, + who: &AccountId, + amount: Self::Balance, + precision: Precision, + ) -> Result { + // NOTE: This doesn't change the total balance of the account so there's no need to + // check liquidity. + + // We want to make sure we can deposit the amount in advance. If we can't then something is + // very wrong. + ensure!(Self::can_deposit(asset, who, amount, Extant) == Success, TokenError::CannotCreate); + // Get the amount we can actually take from the hold. This might be less than what we want + // if we're only doing a best-effort. + let amount = Self::decrease_balance_on_hold(asset, reason, who, amount, precision)?; + // Increase the main balance by what we took. We always do a best-effort here because we + // already checked that we can deposit before. + let actual = Self::increase_balance(asset, who, amount, BestEffort)?; + Self::done_release(asset, reason, who, actual); + Ok(actual) + } + + /// Attempt to decrease the balance of `who` which is held for the given `reason` by `amount`. + /// + /// If `precision` is true, then as much as possible is reduced, up to `amount`, and the + /// amount of tokens reduced is returned. Otherwise, if the total amount can be reduced, then it + /// is and the amount returned, and if not, then nothing changes and `Err` is returned. + /// + /// If `force` is `Force`, then locks/freezes will be ignored. This should only be used when + /// conducting slashing or other activity which materially disadvantages the account holder + /// since it could provide a means of circumventing freezes. + fn burn_held( + asset: Self::AssetId, + reason: &Self::Reason, + who: &AccountId, + mut amount: Self::Balance, + precision: Precision, + force: Fortitude, + ) -> Result { + // We must check total-balance requirements if `!force`. + let liquid = Self::reducible_total_balance_on_hold(asset, who, force); + if let BestEffort = precision { + amount = amount.min(liquid); + } else { + ensure!(amount <= liquid, TokenError::Frozen); + } + let amount = Self::decrease_balance_on_hold(asset, reason, who, amount, precision)?; + Self::set_total_issuance(asset, Self::total_issuance(asset).saturating_sub(amount)); + Self::done_burn_held(asset, reason, who, amount); + Ok(amount) + } + + /// Transfer held funds into a destination account. + /// + /// If `on_hold` is `true`, then the destination account must already exist and the assets + /// transferred will still be on hold in the destination account. If not, then the destination + /// account need not already exist, but must be creatable. + /// + /// If `precision` is `BestEffort`, then an amount less than `amount` may be transferred without + /// error. + /// + /// If `force` is `Force`, then other fund-locking mechanisms may be disregarded. It should be + /// left as `Regular` in most circumstances, but when you want the same power as a `slash`, it + /// may be `Force`. + /// + /// The actual amount transferred is returned, or `Err` in the case of error and nothing is + /// changed. + fn transfer_on_hold( + asset: Self::AssetId, + reason: &Self::Reason, + source: &AccountId, + dest: &AccountId, + mut amount: Self::Balance, + precision: Precision, + mode: Restriction, + force: Fortitude, + ) -> Result { + // We must check total-balance requirements if `!force`. + let have = Self::balance_on_hold(asset, reason, source); + let liquid = Self::reducible_total_balance_on_hold(asset, source, force); + if let BestEffort = precision { + amount = amount.min(liquid).min(have); + } else { + ensure!(amount <= liquid, TokenError::Frozen); + ensure!(amount <= have, TokenError::FundsUnavailable); + } + + // We want to make sure we can deposit the amount in advance. If we can't then something is + // very wrong. + ensure!( + Self::can_deposit(asset, dest, amount, Extant) == Success, + TokenError::CannotCreate + ); + ensure!( + mode == Free || Self::hold_available(asset, reason, dest), + TokenError::CannotCreateHold + ); + + let amount = Self::decrease_balance_on_hold(asset, reason, source, amount, precision)?; + let actual = if mode == OnHold { + Self::increase_balance_on_hold(asset, reason, dest, amount, precision)? + } else { + Self::increase_balance(asset, dest, amount, precision)? + }; + Self::done_transfer_on_hold(asset, reason, source, dest, actual); + Ok(actual) + } + + /// Transfer some `amount` of free balance from `source` to become owned by `dest` but on hold + /// for `reason`. + /// for `reason`. + /// + /// If `precision` is `BestEffort`, then an amount less than `amount` may be transferred without + /// error. + /// + /// `source` must obey the requirements of `keep_alive`. + /// + /// If `force` is `Force`, then other fund-locking mechanisms may be disregarded. It should be + /// left as `Regular` in most circumstances, but when you want the same power as a `slash`, it + /// may be `Force`. + /// + /// The amount placed on hold is returned or `Err` in the case of error and nothing is changed. + /// + /// WARNING: This may return an error after a partial storage mutation. It should be used only + /// inside a transactional storage context and an `Err` result must imply a storage rollback. + fn transfer_and_hold( + asset: Self::AssetId, + reason: &Self::Reason, + source: &AccountId, + dest: &AccountId, + amount: Self::Balance, + precision: Precision, + expendability: Preservation, + force: Fortitude, + ) -> Result { + ensure!(Self::hold_available(asset, reason, dest), TokenError::CannotCreateHold); + ensure!( + Self::can_deposit(asset, dest, amount, Extant) == Success, + TokenError::CannotCreate + ); + let actual = + Self::decrease_balance(asset, source, amount, precision, expendability, force)?; + Self::increase_balance_on_hold(asset, reason, dest, actual, precision)?; + Self::done_transfer_on_hold(asset, reason, source, dest, actual); + Ok(actual) + } + + fn done_hold( + _asset: Self::AssetId, + _reason: &Self::Reason, + _who: &AccountId, + _amount: Self::Balance, + ) { + } + fn done_release( + _asset: Self::AssetId, + _reason: &Self::Reason, + _who: &AccountId, + _amount: Self::Balance, + ) { + } + fn done_burn_held( + _asset: Self::AssetId, + _reason: &Self::Reason, + _who: &AccountId, + _amount: Self::Balance, + ) { + } + fn done_transfer_on_hold( + _asset: Self::AssetId, + _reason: &Self::Reason, + _source: &AccountId, + _dest: &AccountId, + _amount: Self::Balance, + ) { + } + fn done_transfer_and_hold( + _asset: Self::AssetId, + _reason: &Self::Reason, + _source: &AccountId, + _dest: &AccountId, + _transferred: Self::Balance, + ) { + } +} diff --git a/frame/support/src/traits/tokens/fungibles/imbalance.rs b/frame/support/src/traits/tokens/fungibles/imbalance.rs index 87445859cb5c7..ab18eec3811ff 100644 --- a/frame/support/src/traits/tokens/fungibles/imbalance.rs +++ b/frame/support/src/traits/tokens/fungibles/imbalance.rs @@ -18,12 +18,11 @@ //! The imbalance type and its associates, which handles keeps everything adding up properly with //! unbalanced operations. -use super::{ - balanced::Balanced, - fungibles::{AssetId, Balance}, - *, +use super::*; +use crate::traits::{ + misc::{SameOrOther, TryDrop}, + tokens::{AssetId, Balance}, }; -use crate::traits::misc::{SameOrOther, TryDrop}; use sp_runtime::{traits::Zero, RuntimeDebug}; use sp_std::marker::PhantomData; @@ -160,7 +159,7 @@ impl< } /// Imbalance implying that the total_issuance value is less than the sum of all account balances. -pub type DebtOf = Imbalance< +pub type Debt = Imbalance< >::AssetId, >::Balance, // This will generally be implemented by increasing the total_issuance value. @@ -170,7 +169,7 @@ pub type DebtOf = Imbalance< /// Imbalance implying that the total_issuance value is greater than the sum of all account /// balances. -pub type CreditOf = Imbalance< +pub type Credit = Imbalance< >::AssetId, >::Balance, // This will generally be implemented by decreasing the total_issuance value. diff --git a/frame/support/src/traits/tokens/fungibles/lifetime.rs b/frame/support/src/traits/tokens/fungibles/lifetime.rs new file mode 100644 index 0000000000000..9e2c306f6f38a --- /dev/null +++ b/frame/support/src/traits/tokens/fungibles/lifetime.rs @@ -0,0 +1,84 @@ +// 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 creating and destroying assets. + +use sp_runtime::{DispatchError, DispatchResult}; + +use super::Inspect; + +/// 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 { + /// 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, 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 + /// + /// * `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; +} diff --git a/frame/support/src/traits/tokens/fungibles/mod.rs b/frame/support/src/traits/tokens/fungibles/mod.rs new file mode 100644 index 0000000000000..697eff39ff748 --- /dev/null +++ b/frame/support/src/traits/tokens/fungibles/mod.rs @@ -0,0 +1,40 @@ +// 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 traits for sets of fungible tokens and any associated types. + +pub mod approvals; +mod enumerable; +pub mod freeze; +pub mod hold; +mod imbalance; +mod lifetime; +pub mod metadata; +mod regular; +pub mod roles; + +pub use enumerable::Inspect as InspectEnumerable; +pub use freeze::{Inspect as InspectFreeze, Mutate as MutateFreeze}; +pub use hold::{ + Balanced as BalancedHold, Inspect as InspectHold, Mutate as MutateHold, + Unbalanced as UnbalancedHold, +}; +pub use imbalance::{Credit, Debt, HandleImbalanceDrop, Imbalance}; +pub use lifetime::{Create, Destroy}; +pub use regular::{ + Balanced, DecreaseIssuance, Dust, IncreaseIssuance, Inspect, Mutate, Unbalanced, +}; diff --git a/frame/support/src/traits/tokens/fungibles/regular.rs b/frame/support/src/traits/tokens/fungibles/regular.rs new file mode 100644 index 0000000000000..03c14988015ab --- /dev/null +++ b/frame/support/src/traits/tokens/fungibles/regular.rs @@ -0,0 +1,571 @@ +// 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` and `Mutate` traits for working with regular balances. + +use sp_std::marker::PhantomData; + +use crate::{ + dispatch::DispatchError, + ensure, + traits::{ + tokens::{ + misc::{ + Balance, DepositConsequence, + Fortitude::{self, Force, Polite}, + Precision::{self, BestEffort, Exact}, + Preservation::{self, Expendable}, + Provenance::{self, Extant}, + WithdrawConsequence, + }, + AssetId, + }, + SameOrOther, TryDrop, + }, +}; +use sp_arithmetic::traits::{CheckedAdd, CheckedSub, One}; +use sp_runtime::{traits::Saturating, ArithmeticError, TokenError}; + +use super::{Credit, Debt, HandleImbalanceDrop, Imbalance}; + +/// Trait for providing balance-inspection access to a set of named fungible assets. +pub trait Inspect: Sized { + /// Means of identifying one asset class from another. + type AssetId: AssetId; + + /// Scalar type for representing balance of an account. + type Balance: Balance; + + /// 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; + + /// Get the total amount of funds whose ultimate bneficial ownership can be determined as `who`. + /// + /// This may include funds which are wholly inaccessible to `who`, either temporarily or even + /// indefinitely. + /// + /// For the amount of the balance which is currently free to be removed from the account without + /// error, use `reducible_balance`. + /// + /// For the amount of the balance which may eventually be free to be removed from the account, + /// use `balance()`. + fn total_balance(asset: Self::AssetId, who: &AccountId) -> Self::Balance; + + /// Get the balance of `who` which does not include funds which are exclusively allocated to + /// subsystems of the chain ("on hold" or "reserved"). + /// + /// In general this isn't especially useful outside of tests, and for practical purposes, you'll + /// want to use `reducible_balance()`. + fn balance(asset: Self::AssetId, who: &AccountId) -> Self::Balance; + + /// Get the maximum amount that `who` can withdraw/transfer successfully based on whether the + /// account should be kept alive (`preservation`) or whether we are willing to force the + /// transfer and potentially go below user-level restrictions on the minimum amount of the + /// account. + /// + /// Always less than `free_balance()`. + fn reducible_balance( + asset: Self::AssetId, + who: &AccountId, + preservation: Preservation, + force: Fortitude, + ) -> 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, + provenance: Provenance, + ) -> DepositConsequence; + + /// Returns `Failed` if the `asset` balance of `who` may not be decreased by `amount`, otherwise + /// the consequence. + fn can_withdraw( + asset: Self::AssetId, + who: &AccountId, + amount: Self::Balance, + ) -> WithdrawConsequence; + + /// Returns `true` if an `asset` exists. + fn asset_exists(asset: Self::AssetId) -> bool; +} + +/// Special dust type which can be type-safely converted into a `Credit`. +#[must_use] +pub struct Dust>(pub(crate) T::AssetId, pub(crate) T::Balance); + +impl> Dust { + /// Convert `Dust` into an instance of `Credit`. + pub fn into_credit(self) -> Credit { + Credit::::new(self.0, self.1) + } +} + +/// A fungible token class where the balance can be set arbitrarily. +/// +/// **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 +/// for the underlying datatype to implement so the user gets the much safer `Balanced` trait to +/// use. +pub trait Unbalanced: Inspect { + /// Create some dust and handle it with `Self::handle_dust`. This is an unbalanced operation + /// and it must only be used when an account is modified in a raw fashion, outside of the entire + /// fungibles API. The `amount` is capped at `Self::minimum_balance() - 1`. + /// + /// This should not be reimplemented. + fn handle_raw_dust(asset: Self::AssetId, amount: Self::Balance) { + Self::handle_dust(Dust( + asset, + amount.min(Self::minimum_balance(asset).saturating_sub(One::one())), + )) + } + + /// Do something with the dust which has been destroyed from the system. `Dust` can be converted + /// into a `Credit` with the `Balanced` trait impl. + fn handle_dust(dust: Dust); + + /// Forcefully set the balance of `who` to `amount`. + /// + /// If this call executes successfully, you can `assert_eq!(Self::balance(), amount);`. + /// + /// For implementations which include one or more balances on hold, then these are *not* + /// included in the `amount`. + /// + /// This function does its best to force the balance change through, but will not break system + /// invariants such as any Existential Deposits needed or overflows/underflows. + /// If this cannot be done for some reason (e.g. because the account cannot be created, deleted + /// or would overflow) then an `Err` is returned. + fn write_balance( + asset: Self::AssetId, + who: &AccountId, + amount: Self::Balance, + ) -> Result, DispatchError>; + + /// Set the total issuance to `amount`. + fn set_total_issuance(asset: Self::AssetId, amount: Self::Balance); + + /// Reduce the balance of `who` by `amount`. + /// + /// If `precision` is `Exact` and it cannot be reduced by that amount for + /// some reason, return `Err` and don't reduce it at all. If `precision` is `BestEffort`, then + /// reduce the balance of `who` by the most that is possible, up to `amount`. + /// + /// In either case, if `Ok` is returned then the inner is the amount by which is was reduced. + /// Minimum balance will be respected and thus the returned amount may be up to + /// `Self::minimum_balance() - 1` greater than `amount` in the case that the reduction caused + /// the account to be deleted. + fn decrease_balance( + asset: Self::AssetId, + who: &AccountId, + mut amount: Self::Balance, + precision: Precision, + preservation: Preservation, + force: Fortitude, + ) -> Result { + let old_balance = Self::balance(asset, who); + let free = Self::reducible_balance(asset, who, preservation, force); + if let BestEffort = precision { + amount = amount.min(free); + } + let new_balance = old_balance.checked_sub(&amount).ok_or(TokenError::FundsUnavailable)?; + if let Some(dust) = Self::write_balance(asset, who, new_balance)? { + Self::handle_dust(Dust(asset, dust)); + } + Ok(old_balance.saturating_sub(new_balance)) + } + + /// Increase the balance of `who` by `amount`. + /// + /// If it cannot be increased by that amount for some reason, return `Err` and don't increase + /// it at all. If Ok, return the imbalance. + /// Minimum balance will be respected and an error will be returned if + /// `amount < Self::minimum_balance()` when the account of `who` is zero. + fn increase_balance( + asset: Self::AssetId, + who: &AccountId, + amount: Self::Balance, + precision: Precision, + ) -> Result { + let old_balance = Self::balance(asset, who); + let new_balance = if let BestEffort = precision { + old_balance.saturating_add(amount) + } else { + old_balance.checked_add(&amount).ok_or(ArithmeticError::Overflow)? + }; + if new_balance < Self::minimum_balance(asset) { + // Attempt to increase from 0 to below minimum -> stays at zero. + if let BestEffort = precision { + Ok(Self::Balance::default()) + } else { + Err(TokenError::BelowMinimum.into()) + } + } else { + if new_balance == old_balance { + Ok(Self::Balance::default()) + } else { + if let Some(dust) = Self::write_balance(asset, who, new_balance)? { + Self::handle_dust(Dust(asset, dust)); + } + Ok(new_balance.saturating_sub(old_balance)) + } + } + } + + /// Reduce the active issuance by some amount. + fn deactivate(_asset: Self::AssetId, _: Self::Balance) {} + + /// Increase the active issuance by some amount, up to the outstanding amount reduced. + fn reactivate(_asset: Self::AssetId, _: Self::Balance) {} +} + +/// Trait for providing a basic fungible asset. +pub trait Mutate: Inspect + Unbalanced { + /// Increase the balance of `who` by exactly `amount`, minting new tokens. If that isn't + /// possible then an `Err` is returned and nothing is changed. + fn mint_into( + asset: Self::AssetId, + who: &AccountId, + amount: Self::Balance, + ) -> Result { + Self::total_issuance(asset) + .checked_add(&amount) + .ok_or(ArithmeticError::Overflow)?; + let actual = Self::increase_balance(asset, who, amount, Exact)?; + Self::set_total_issuance(asset, Self::total_issuance(asset).saturating_add(actual)); + Self::done_mint_into(asset, who, amount); + Ok(actual) + } + + /// Decrease the balance of `who` by at least `amount`, possibly slightly more in the case of + /// minimum-balance requirements, burning the tokens. If that isn't possible then an `Err` is + /// returned and nothing is changed. If successful, the amount of tokens reduced is returned. + fn burn_from( + asset: Self::AssetId, + who: &AccountId, + amount: Self::Balance, + precision: Precision, + force: Fortitude, + ) -> Result { + let actual = Self::reducible_balance(asset, who, Expendable, force).min(amount); + ensure!(actual == amount || precision == BestEffort, TokenError::FundsUnavailable); + Self::total_issuance(asset) + .checked_sub(&actual) + .ok_or(ArithmeticError::Overflow)?; + let actual = Self::decrease_balance(asset, who, actual, BestEffort, Expendable, force)?; + Self::set_total_issuance(asset, Self::total_issuance(asset).saturating_sub(actual)); + Self::done_burn_from(asset, who, actual); + Ok(actual) + } + + /// Attempt to decrease the `asset` balance of `who` by `amount`. + /// + /// Equivalent to `burn_from`, except with an expectation that within the bounds of some + /// universal issuance, the total assets `suspend`ed and `resume`d will be equivalent. The + /// implementation may be configured such that the total assets suspended may never be less than + /// the total assets resumed (which is the invariant for an issuing system), or the reverse + /// (which the invariant in a non-issuing system). + /// + /// Because of this expectation, any metadata associated with the asset is expected to survive + /// the suspect-resume cycle. + fn shelve( + asset: Self::AssetId, + who: &AccountId, + amount: Self::Balance, + ) -> Result { + let actual = Self::reducible_balance(asset, who, Expendable, Polite).min(amount); + ensure!(actual == amount, TokenError::FundsUnavailable); + Self::total_issuance(asset) + .checked_sub(&actual) + .ok_or(ArithmeticError::Overflow)?; + let actual = Self::decrease_balance(asset, who, actual, BestEffort, Expendable, Polite)?; + Self::set_total_issuance(asset, Self::total_issuance(asset).saturating_sub(actual)); + Self::done_shelve(asset, who, actual); + Ok(actual) + } + + /// Attempt to increase the `asset` balance of `who` by `amount`. + /// + /// Equivalent to `mint_into`, except with an expectation that within the bounds of some + /// universal issuance, the total assets `suspend`ed and `resume`d will be equivalent. The + /// implementation may be configured such that the total assets suspended may never be less than + /// the total assets resumed (which is the invariant for an issuing system), or the reverse + /// (which the invariant in a non-issuing system). + /// + /// Because of this expectation, any metadata associated with the asset is expected to survive + /// the suspect-resume cycle. + fn restore( + asset: Self::AssetId, + who: &AccountId, + amount: Self::Balance, + ) -> Result { + Self::total_issuance(asset) + .checked_add(&amount) + .ok_or(ArithmeticError::Overflow)?; + let actual = Self::increase_balance(asset, who, amount, Exact)?; + Self::set_total_issuance(asset, Self::total_issuance(asset).saturating_add(actual)); + Self::done_restore(asset, who, amount); + Ok(actual) + } + + /// Transfer funds from one account into another. + fn transfer( + asset: Self::AssetId, + source: &AccountId, + dest: &AccountId, + amount: Self::Balance, + preservation: Preservation, + ) -> Result { + let _extra = + Self::can_withdraw(asset, source, amount).into_result(preservation != Expendable)?; + Self::can_deposit(asset, dest, amount, Extant).into_result()?; + Self::decrease_balance(asset, source, amount, BestEffort, preservation, Polite)?; + // This should never fail as we checked `can_deposit` earlier. But we do a best-effort + // anyway. + let _ = Self::increase_balance(asset, dest, amount, BestEffort); + Self::done_transfer(asset, source, dest, amount); + Ok(amount) + } + + /// Simple infallible function to force an account to have a particular balance, good for use + /// in tests and benchmarks but not recommended for production code owing to the lack of + /// error reporting. + /// + /// Returns the new balance. + fn set_balance(asset: Self::AssetId, who: &AccountId, amount: Self::Balance) -> Self::Balance { + let b = Self::balance(asset, who); + if b > amount { + Self::burn_from(asset, who, b - amount, BestEffort, Force) + .map(|d| amount.saturating_sub(d)) + } else { + Self::mint_into(asset, who, amount - b).map(|d| amount.saturating_add(d)) + } + .unwrap_or(b) + } + fn done_mint_into(_asset: Self::AssetId, _who: &AccountId, _amount: Self::Balance) {} + fn done_burn_from(_asset: Self::AssetId, _who: &AccountId, _amount: Self::Balance) {} + fn done_shelve(_asset: Self::AssetId, _who: &AccountId, _amount: Self::Balance) {} + fn done_restore(_asset: Self::AssetId, _who: &AccountId, _amount: Self::Balance) {} + fn done_transfer( + _asset: Self::AssetId, + _source: &AccountId, + _dest: &AccountId, + _amount: Self::Balance, + ) { + } +} + +/// Simple handler for an imbalance drop which increases the total issuance of the system by the +/// imbalance amount. Used for leftover debt. +pub struct IncreaseIssuance(PhantomData<(AccountId, U)>); +impl> HandleImbalanceDrop + for IncreaseIssuance +{ + fn handle(asset: U::AssetId, amount: U::Balance) { + U::set_total_issuance(asset, U::total_issuance(asset).saturating_add(amount)) + } +} + +/// Simple handler for an imbalance drop which decreases the total issuance of the system by the +/// imbalance amount. Used for leftover credit. +pub struct DecreaseIssuance(PhantomData<(AccountId, U)>); +impl> HandleImbalanceDrop + for DecreaseIssuance +{ + fn handle(asset: U::AssetId, amount: U::Balance) { + U::set_total_issuance(asset, U::total_issuance(asset).saturating_sub(amount)) + } +} + +/// A fungible token class where any creation and deletion of tokens is semi-explicit and where the +/// total supply is maintained automatically. +/// +/// This is auto-implemented when a token class has `Unbalanced` implemented. +pub trait Balanced: Inspect + Unbalanced { + /// The type for managing what happens when an instance of `Debt` is dropped without being used. + type OnDropDebt: HandleImbalanceDrop; + /// The type for managing what happens when an instance of `Credit` is dropped without being + /// used. + type OnDropCredit: HandleImbalanceDrop; + + /// Reduce the total issuance by `amount` and return the according imbalance. The imbalance will + /// typically be used to reduce an account by the same amount with e.g. `settle`. + /// + /// This is infallible, but doesn't guarantee that the entire `amount` is burnt, for example + /// in the case of underflow. + fn rescind(asset: Self::AssetId, amount: Self::Balance) -> Debt { + let old = Self::total_issuance(asset); + let new = old.saturating_sub(amount); + Self::set_total_issuance(asset, new); + let delta = old - new; + Self::done_rescind(asset, delta); + Imbalance::::new( + asset, delta, + ) + } + + /// Increase the total issuance by `amount` and return the according imbalance. The imbalance + /// will typically be used to increase an account by the same amount with e.g. + /// `resolve_into_existing` or `resolve_creating`. + /// + /// This is infallible, but doesn't guarantee that the entire `amount` is issued, for example + /// in the case of overflow. + fn issue(asset: Self::AssetId, amount: Self::Balance) -> Credit { + let old = Self::total_issuance(asset); + let new = old.saturating_add(amount); + Self::set_total_issuance(asset, new); + let delta = new - old; + Self::done_issue(asset, delta); + Imbalance::::new( + asset, delta, + ) + } + + /// Produce a pair of imbalances that cancel each other out exactly. + /// + /// This is just the same as burning and issuing the same amount and has no effect on the + /// total issuance. + fn pair( + asset: Self::AssetId, + amount: Self::Balance, + ) -> (Debt, Credit) { + (Self::rescind(asset, amount), Self::issue(asset, amount)) + } + + /// Mints `value` into the account of `who`, creating it as needed. + /// + /// If `precision` is `BestEffort` and `value` in full could not be minted (e.g. due to + /// overflow), then the maximum is minted, up to `value`. If `precision` is `Exact`, then + /// exactly `value` must be minted into the account of `who` or the operation will fail with an + /// `Err` and nothing will change. + /// + /// If the operation is successful, this will return `Ok` with a `Debt` of the total value + /// added to the account. + fn deposit( + asset: Self::AssetId, + who: &AccountId, + value: Self::Balance, + precision: Precision, + ) -> Result, DispatchError> { + let increase = Self::increase_balance(asset, who, value, precision)?; + Self::done_deposit(asset, who, increase); + Ok(Imbalance::::new( + asset, increase, + )) + } + + /// Removes `value` balance from `who` account if possible. + /// + /// If `precision` is `BestEffort` and `value` in full could not be removed (e.g. due to + /// underflow), then the maximum is removed, up to `value`. If `precision` is `Exact`, then + /// exactly `value` must be removed from the account of `who` or the operation will fail with an + /// `Err` and nothing will change. + /// + /// If the removal is needed but not possible, then it returns `Err` and nothing is changed. + /// If the account needed to be deleted, then slightly more than `value` may be removed from the + /// account owning since up to (but not including) minimum balance may also need to be removed. + /// + /// If the operation is successful, this will return `Ok` with a `Credit` of the total value + /// removed from the account. + fn withdraw( + asset: Self::AssetId, + who: &AccountId, + value: Self::Balance, + precision: Precision, + preservation: Preservation, + force: Fortitude, + ) -> Result, DispatchError> { + let decrease = Self::decrease_balance(asset, who, value, precision, preservation, force)?; + Self::done_withdraw(asset, who, decrease); + Ok(Imbalance::::new( + asset, decrease, + )) + } + + /// The balance of `who` is increased in order to counter `credit`. If the whole of `credit` + /// cannot be countered, then nothing is changed and the original `credit` is returned in an + /// `Err`. + /// + /// Please note: If `credit.peek()` is less than `Self::minimum_balance()`, then `who` must + /// already exist for this to succeed. + fn resolve( + who: &AccountId, + credit: Credit, + ) -> Result<(), Credit> { + let v = credit.peek(); + let debt = match Self::deposit(credit.asset(), who, v, Exact) { + Err(_) => return Err(credit), + Ok(d) => d, + }; + if let Ok(result) = credit.offset(debt) { + let result = result.try_drop(); + debug_assert!(result.is_ok(), "ok deposit return must be equal to credit value; qed"); + } else { + debug_assert!(false, "debt.asset is credit.asset; qed"); + } + Ok(()) + } + + /// The balance of `who` is decreased in order to counter `debt`. If the whole of `debt` + /// cannot be countered, then nothing is changed and the original `debt` is returned in an + /// `Err`. + fn settle( + who: &AccountId, + debt: Debt, + preservation: Preservation, + ) -> Result, Debt> { + let amount = debt.peek(); + let asset = debt.asset(); + let credit = match Self::withdraw(asset, who, amount, Exact, preservation, Polite) { + Err(_) => return Err(debt), + Ok(d) => d, + }; + match credit.offset(debt) { + Ok(SameOrOther::None) => Ok(Credit::::zero(asset)), + Ok(SameOrOther::Same(dust)) => Ok(dust), + Ok(SameOrOther::Other(rest)) => { + debug_assert!(false, "ok withdraw return must be at least debt value; qed"); + Err(rest) + }, + Err(_) => { + debug_assert!(false, "debt.asset is credit.asset; qed"); + Ok(Credit::::zero(asset)) + }, + } + } + + fn done_rescind(_asset: Self::AssetId, _amount: Self::Balance) {} + fn done_issue(_asset: Self::AssetId, _amount: Self::Balance) {} + fn done_deposit(_asset: Self::AssetId, _who: &AccountId, _amount: Self::Balance) {} + fn done_withdraw(_asset: Self::AssetId, _who: &AccountId, _amount: Self::Balance) {} +} diff --git a/frame/support/src/traits/tokens/misc.rs b/frame/support/src/traits/tokens/misc.rs index 6113642c83460..8ad3a9535fd0d 100644 --- a/frame/support/src/traits/tokens/misc.rs +++ b/frame/support/src/traits/tokens/misc.rs @@ -23,12 +23,65 @@ use sp_core::RuntimeDebug; use sp_runtime::{traits::Convert, ArithmeticError, DispatchError, TokenError}; use sp_std::fmt::Debug; +/// The origin of funds to be used for a deposit operation. +#[derive(Copy, Clone, RuntimeDebug, Eq, PartialEq)] +pub enum Provenance { + /// The funds will be minted into the system, increasing total issuance (and potentially + /// causing an overflow there). + Minted, + /// The funds already exist in the system, therefore will not affect total issuance. + Extant, +} + +/// The mode under which usage of funds may be restricted. +#[derive(Copy, Clone, RuntimeDebug, Eq, PartialEq)] +pub enum Restriction { + /// Funds are under the normal conditions. + Free, + /// Funds are on hold. + OnHold, +} + +/// The mode by which we describe whether an operation should keep an account alive. +#[derive(Copy, Clone, RuntimeDebug, Eq, PartialEq)] +pub enum Preservation { + /// We don't care if the account gets killed by this operation. + Expendable, + /// The account may not be killed, but we don't care if the balance gets dusted. + Protect, + /// The account may not be killed and our provider reference must remain (in the context of + /// tokens, this means that the account may not be dusted). + Preserve, +} + +/// The privilege with which a withdraw operation is conducted. +#[derive(Copy, Clone, RuntimeDebug, Eq, PartialEq)] +pub enum Fortitude { + /// The operation should execute with regular privilege. + Polite, + /// The operation should be forced to succeed if possible. This is usually employed for system- + /// level security-critical events such as slashing. + Force, +} + +/// The precision required of an operation generally involving some aspect of quantitative fund +/// withdrawal or transfer. +#[derive(Copy, Clone, RuntimeDebug, Eq, PartialEq)] +pub enum Precision { + /// The operation should must either proceed either exactly according to the amounts involved + /// or not at all. + Exact, + /// The operation may be considered successful even if less than the specified amounts are + /// available to be used. In this case a best effort will be made. + BestEffort, +} + /// One of a number of consequences of withdrawing a fungible from an account. #[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. - NoFunds, + BalanceLow, /// The withdraw would mean the account dying when it needs to exist (usually because it is a /// provider and there are consumer references on it). WouldDie, @@ -53,15 +106,16 @@ pub enum WithdrawConsequence { impl WithdrawConsequence { /// Convert the type into a `Result` with `DispatchError` as the error or the additional /// `Balance` by which the account will be reduced. - pub fn into_result(self) -> Result { + pub fn into_result(self, keep_nonzero: bool) -> Result { use WithdrawConsequence::*; match self { - NoFunds => Err(TokenError::NoFunds.into()), - WouldDie => Err(TokenError::WouldDie.into()), + BalanceLow => Err(TokenError::FundsUnavailable.into()), + WouldDie => Err(TokenError::OnlyProvider.into()), UnknownAsset => Err(TokenError::UnknownAsset.into()), Underflow => Err(ArithmeticError::Underflow.into()), Overflow => Err(ArithmeticError::Overflow.into()), Frozen => Err(TokenError::Frozen.into()), + ReducedToZero(_) if keep_nonzero => Err(TokenError::NotExpendable.into()), ReducedToZero(result) => Ok(result), Success => Ok(Zero::zero()), } diff --git a/frame/support/src/traits/tokens/pay.rs b/frame/support/src/traits/tokens/pay.rs index 1c6a147b5f22e..23bd113bfef56 100644 --- a/frame/support/src/traits/tokens/pay.rs +++ b/frame/support/src/traits/tokens/pay.rs @@ -22,7 +22,7 @@ use scale_info::TypeInfo; use sp_core::{RuntimeDebug, TypedGet}; use sp_std::fmt::Debug; -use super::{fungible, Balance}; +use super::{fungible, Balance, Preservation::Expendable}; /// Can be implemented by `PayFromAccount` using a `fungible` impl, but can also be implemented with /// XCM/MultiAsset and made generic over assets. @@ -76,9 +76,7 @@ pub enum PaymentStatus { /// Simple implementation of `Pay` which makes a payment from a "pot" - i.e. a single account. pub struct PayFromAccount(sp_std::marker::PhantomData<(F, A)>); -impl + fungible::Mutate> Pay - for PayFromAccount -{ +impl> Pay for PayFromAccount { type Balance = F::Balance; type Beneficiary = A::Type; type AssetKind = (); @@ -88,7 +86,7 @@ impl + fungible::Mutate> Pa _: Self::AssetKind, amount: Self::Balance, ) -> Result { - >::transfer(&A::get(), who, amount, false).map_err(|_| ())?; + >::transfer(&A::get(), who, amount, Expendable).map_err(|_| ())?; Ok(()) } fn check_payment(_: ()) -> PaymentStatus { diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index faa1ee5d6cf4f..88291c326edba 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -1661,10 +1661,6 @@ impl BlockNumberProvider for Pallet { } } -fn is_providing(d: &T) -> bool { - d != &T::default() -} - /// Implement StoredMap for a simple single-item, provide-when-not-default system. This works fine /// for storing a single item which allows the account to continue existing as long as it's not /// empty/default. @@ -1680,23 +1676,12 @@ impl StoredMap for Pallet { f: impl FnOnce(&mut Option) -> Result, ) -> Result { let account = Account::::get(k); - let was_providing = is_providing(&account.data); - let mut some_data = if was_providing { Some(account.data) } else { None }; + let is_default = account.data == T::AccountData::default(); + let mut some_data = if is_default { None } else { Some(account.data) }; let result = f(&mut some_data)?; - let is_providing = some_data.is_some(); - if !was_providing && is_providing { - Self::inc_providers(k); - } else if was_providing && !is_providing { - match Self::dec_providers(k)? { - DecRefStatus::Reaped => return Ok(result), - DecRefStatus::Exists => { - // Update value as normal... - }, - } - } else if !was_providing && !is_providing { - return Ok(result) + if Self::providers(k) > 0 { + Account::::mutate(k, |a| a.data = some_data.unwrap_or_default()); } - Account::::mutate(k, |a| a.data = some_data.unwrap_or_default()); Ok(result) } } diff --git a/frame/system/src/tests.rs b/frame/system/src/tests.rs index ebb28ca87bbd8..9b60c6915ab1c 100644 --- a/frame/system/src/tests.rs +++ b/frame/system/src/tests.rs @@ -37,6 +37,7 @@ fn origin_works() { #[test] fn stored_map_works() { new_test_ext().execute_with(|| { + assert_eq!(System::inc_providers(&0), IncRefStatus::Created); assert_ok!(System::insert(&0, 42)); assert!(!System::is_provider_required(&0)); @@ -56,6 +57,7 @@ fn stored_map_works() { assert!(Killed::get().is_empty()); assert_ok!(System::remove(&0)); + assert_ok!(System::dec_providers(&0)); assert_eq!(Killed::get(), vec![0u64]); }); } diff --git a/frame/tips/src/tests.rs b/frame/tips/src/tests.rs index fa4ec15014292..b2d97de18312f 100644 --- a/frame/tips/src/tests.rs +++ b/frame/tips/src/tests.rs @@ -97,6 +97,10 @@ impl pallet_balances::Config for Test { type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type HoldIdentifier = (); + type MaxHolds = (); } parameter_types! { static TenToFourteenTestValue: Vec = vec![10,11,12,13,14]; diff --git a/frame/transaction-payment/asset-tx-payment/src/lib.rs b/frame/transaction-payment/asset-tx-payment/src/lib.rs index b9cd6ef995578..4e83d8b489b70 100644 --- a/frame/transaction-payment/asset-tx-payment/src/lib.rs +++ b/frame/transaction-payment/asset-tx-payment/src/lib.rs @@ -42,7 +42,7 @@ use frame_support::{ dispatch::{DispatchInfo, DispatchResult, PostDispatchInfo}, traits::{ tokens::{ - fungibles::{Balanced, CreditOf, Inspect}, + fungibles::{Balanced, Credit, Inspect}, WithdrawConsequence, }, IsType, @@ -104,7 +104,7 @@ pub enum InitialPayment { /// The initial fee was payed in the native currency. Native(LiquidityInfoOf), /// The initial fee was payed in an asset. - Asset(CreditOf), + Asset(Credit), } pub use pallet::*; @@ -159,7 +159,7 @@ where AssetBalanceOf: Send + Sync + FixedPointOperand, BalanceOf: Send + Sync + FixedPointOperand + IsType>, ChargeAssetIdOf: Send + Sync, - CreditOf: IsType>, + Credit: IsType>, { /// Utility constructor. Used only in client/factory code. pub fn from(tip: BalanceOf, asset_id: Option>) -> Self { @@ -216,7 +216,7 @@ where AssetBalanceOf: Send + Sync + FixedPointOperand, BalanceOf: Send + Sync + From + FixedPointOperand + IsType>, ChargeAssetIdOf: Send + Sync, - CreditOf: IsType>, + Credit: IsType>, { const IDENTIFIER: &'static str = "ChargeAssetTxPayment"; type AccountId = T::AccountId; diff --git a/frame/transaction-payment/asset-tx-payment/src/mock.rs b/frame/transaction-payment/asset-tx-payment/src/mock.rs index cd5147c3acd13..be7baaf2b370e 100644 --- a/frame/transaction-payment/asset-tx-payment/src/mock.rs +++ b/frame/transaction-payment/asset-tx-payment/src/mock.rs @@ -120,6 +120,10 @@ impl pallet_balances::Config for Runtime { type WeightInfo = (); type MaxReserves = ConstU32<50>; type ReserveIdentifier = [u8; 8]; + type FreezeIdentifier = (); + type MaxFreezes = (); + type HoldIdentifier = (); + type MaxHolds = (); } impl WeightToFeeT for WeightToFee { @@ -193,7 +197,7 @@ impl pallet_authorship::Config for Runtime { pub struct CreditToBlockAuthor; impl HandleCredit for CreditToBlockAuthor { - fn handle_credit(credit: CreditOf) { + fn handle_credit(credit: 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. diff --git a/frame/transaction-payment/asset-tx-payment/src/payment.rs b/frame/transaction-payment/asset-tx-payment/src/payment.rs index e273ffcfc565c..f8d6888b9905c 100644 --- a/frame/transaction-payment/asset-tx-payment/src/payment.rs +++ b/frame/transaction-payment/asset-tx-payment/src/payment.rs @@ -20,8 +20,10 @@ use crate::Config; use codec::FullCodec; use frame_support::{ traits::{ - fungibles::{Balanced, CreditOf, Inspect}, - tokens::{Balance, BalanceConversion}, + fungibles::{Balanced, Credit, Inspect}, + tokens::{ + Balance, BalanceConversion, Fortitude::Polite, Precision::Exact, Preservation::Protect, + }, }, unsigned::TransactionValidityError, }; @@ -75,13 +77,13 @@ 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); + fn handle_credit(credit: Credit); } /// Default implementation that just drops the credit according to the `OnDrop` in the underlying /// imbalance type. impl> HandleCredit for () { - fn handle_credit(_credit: CreditOf) {} + fn handle_credit(_credit: Credit) {} } /// Implements the asset transaction for a balance to asset converter (implementing @@ -101,7 +103,7 @@ where { type Balance = BalanceOf; type AssetId = AssetIdOf; - type LiquidityInfo = CreditOf; + type LiquidityInfo = Credit; /// Withdraw the predicted fee from the transaction origin. /// @@ -126,8 +128,15 @@ where if !matches!(can_withdraw, WithdrawConsequence::Success) { return Err(InvalidTransaction::Payment.into()) } - >::withdraw(asset_id, who, converted_fee) - .map_err(|_| TransactionValidityError::from(InvalidTransaction::Payment)) + >::withdraw( + asset_id, + who, + converted_fee, + Exact, + Protect, + Polite, + ) + .map_err(|_| TransactionValidityError::from(InvalidTransaction::Payment)) } /// Hand the fee and the tip over to the `[HandleCredit]` implementation. diff --git a/frame/transaction-payment/asset-tx-payment/src/tests.rs b/frame/transaction-payment/asset-tx-payment/src/tests.rs index cd9891825db32..2fee9c849f4b4 100644 --- a/frame/transaction-payment/asset-tx-payment/src/tests.rs +++ b/frame/transaction-payment/asset-tx-payment/src/tests.rs @@ -28,7 +28,7 @@ use pallet_balances::Call as BalancesCall; use sp_runtime::traits::StaticLookup; const CALL: &::RuntimeCall = - &RuntimeCall::Balances(BalancesCall::transfer { dest: 2, value: 69 }); + &RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 2, value: 69 }); pub struct ExtBuilder { balance_factor: u64, diff --git a/frame/transaction-payment/src/mock.rs b/frame/transaction-payment/src/mock.rs index bfb9a194f8cb2..741f094481c38 100644 --- a/frame/transaction-payment/src/mock.rs +++ b/frame/transaction-payment/src/mock.rs @@ -49,7 +49,7 @@ frame_support::construct_runtime!( ); pub(crate) const CALL: &::RuntimeCall = - &RuntimeCall::Balances(BalancesCall::transfer { dest: 2, value: 69 }); + &RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 2, value: 69 }); parameter_types! { pub(crate) static ExtrinsicBaseWeight: Weight = Weight::zero(); @@ -113,6 +113,10 @@ impl pallet_balances::Config for Runtime { type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type WeightInfo = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type HoldIdentifier = (); + type MaxHolds = (); } impl WeightToFeeT for WeightToFee { diff --git a/frame/transaction-payment/src/tests.rs b/frame/transaction-payment/src/tests.rs index 218f50e1cc95f..d5109609e2975 100644 --- a/frame/transaction-payment/src/tests.rs +++ b/frame/transaction-payment/src/tests.rs @@ -285,7 +285,7 @@ fn signed_ext_length_fee_is_also_updated_per_congestion() { #[test] fn query_info_and_fee_details_works() { - let call = RuntimeCall::Balances(BalancesCall::transfer { dest: 2, value: 69 }); + let call = RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 2, value: 69 }); let origin = 111111; let extra = (); let xt = TestXt::new(call.clone(), Some((origin, extra))); @@ -348,7 +348,7 @@ fn query_info_and_fee_details_works() { #[test] fn query_call_info_and_fee_details_works() { - let call = RuntimeCall::Balances(BalancesCall::transfer { dest: 2, value: 69 }); + let call = RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 2, value: 69 }); let info = call.get_dispatch_info(); let encoded_call = call.encode(); let len = encoded_call.len() as u32; @@ -530,7 +530,11 @@ fn refund_does_not_recreate_account() { assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 100 - 5); // kill the account between pre and post dispatch - assert_ok!(Balances::transfer(Some(2).into(), 3, Balances::free_balance(2))); + assert_ok!(Balances::transfer_allow_death( + Some(2).into(), + 3, + Balances::free_balance(2) + )); assert_eq!(Balances::free_balance(2), 0); assert_ok!(ChargeTransactionPayment::::post_dispatch( diff --git a/frame/transaction-storage/src/mock.rs b/frame/transaction-storage/src/mock.rs index f54c134d74a0e..3a87d8eaea707 100644 --- a/frame/transaction-storage/src/mock.rs +++ b/frame/transaction-storage/src/mock.rs @@ -84,6 +84,10 @@ impl pallet_balances::Config for Test { type MaxLocks = (); type MaxReserves = (); type ReserveIdentifier = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type HoldIdentifier = (); + type MaxHolds = (); } impl pallet_transaction_storage::Config for Test { diff --git a/frame/treasury/src/tests.rs b/frame/treasury/src/tests.rs index 24d2d01f92f8a..67b21ff6252a8 100644 --- a/frame/treasury/src/tests.rs +++ b/frame/treasury/src/tests.rs @@ -90,6 +90,10 @@ impl pallet_balances::Config for Test { type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type HoldIdentifier = (); + type MaxHolds = (); } impl pallet_utility::Config for Test { diff --git a/frame/uniques/src/mock.rs b/frame/uniques/src/mock.rs index 67d994d7933c2..bad393a489582 100644 --- a/frame/uniques/src/mock.rs +++ b/frame/uniques/src/mock.rs @@ -82,6 +82,10 @@ impl pallet_balances::Config for Test { type MaxLocks = (); type MaxReserves = ConstU32<50>; type ReserveIdentifier = [u8; 8]; + type FreezeIdentifier = (); + type MaxFreezes = (); + type HoldIdentifier = (); + type MaxHolds = (); } impl Config for Test { diff --git a/frame/utility/Cargo.toml b/frame/utility/Cargo.toml index 099526d3dcb9e..c00255e3d33d8 100644 --- a/frame/utility/Cargo.toml +++ b/frame/utility/Cargo.toml @@ -47,5 +47,6 @@ runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", + "pallet-collective/runtime-benchmarks", ] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/utility/src/tests.rs b/frame/utility/src/tests.rs index d9ac2ebbc15a9..04f2728242874 100644 --- a/frame/utility/src/tests.rs +++ b/frame/utility/src/tests.rs @@ -35,6 +35,7 @@ use sp_core::H256; use sp_runtime::{ testing::Header, traits::{BlakeTwo256, Hash, IdentityLookup}, + TokenError, }; type BlockNumber = u64; @@ -185,6 +186,10 @@ impl pallet_balances::Config for Test { type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type HoldIdentifier = (); + type MaxHolds = (); } impl pallet_root_testing::Config for Test {} @@ -226,7 +231,7 @@ 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. - RuntimeCall::Balances(pallet_balances::Call::transfer { .. }) => true, + RuntimeCall::Balances(pallet_balances::Call::transfer_allow_death { .. }) => true, RuntimeCall::Utility(_) => true, // For benchmarking, this acts as a noop call RuntimeCall::System(frame_system::Call::remark { .. }) => true, @@ -253,7 +258,7 @@ type ExampleCall = example::Call; type UtilityCall = crate::Call; use frame_system::Call as SystemCall; -use pallet_balances::{Call as BalancesCall, Error as BalancesError}; +use pallet_balances::Call as BalancesCall; use pallet_root_testing::Call as RootTestingCall; use pallet_timestamp::Call as TimestampCall; @@ -278,7 +283,7 @@ pub fn new_test_ext() -> sp_io::TestExternalities { } fn call_transfer(dest: u64, value: u64) -> RuntimeCall { - RuntimeCall::Balances(BalancesCall::transfer { dest, value }) + RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest, value }) } fn call_foobar(err: bool, start_weight: Weight, end_weight: Option) -> RuntimeCall { @@ -289,10 +294,10 @@ 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(RuntimeOrigin::signed(1), sub_1_0, 5)); + assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(1), sub_1_0, 5)); assert_err_ignore_postinfo!( Utility::as_derivative(RuntimeOrigin::signed(1), 1, Box::new(call_transfer(6, 3)),), - BalancesError::::InsufficientBalance + TokenError::FundsUnavailable, ); assert_ok!(Utility::as_derivative( RuntimeOrigin::signed(1), @@ -599,7 +604,7 @@ fn batch_all_revert() { ), pays_fee: Pays::Yes }, - error: pallet_balances::Error::::InsufficientBalance.into() + error: TokenError::FundsUnavailable.into(), } ); assert_eq!(Balances::free_balance(1), 10); diff --git a/frame/vesting/src/benchmarking.rs b/frame/vesting/src/benchmarking.rs index 35a094a9f4f19..15be519842992 100644 --- a/frame/vesting/src/benchmarking.rs +++ b/frame/vesting/src/benchmarking.rs @@ -139,6 +139,7 @@ benchmarks! { let other: T::AccountId = account("other", 0, SEED); let other_lookup = T::Lookup::unlookup(other.clone()); + T::Currency::make_free_balance_be(&other, T::Currency::minimum_balance()); add_locks::(&other, l as u8); let expected_balance = add_vesting_schedules::(other_lookup.clone(), s)?; @@ -168,6 +169,7 @@ benchmarks! { let other: T::AccountId = account("other", 0, SEED); let other_lookup = T::Lookup::unlookup(other.clone()); + T::Currency::make_free_balance_be(&other, T::Currency::minimum_balance()); add_locks::(&other, l as u8); add_vesting_schedules::(other_lookup.clone(), s)?; // At block 21 everything is unlocked. @@ -200,8 +202,10 @@ benchmarks! { let target: T::AccountId = account("target", 0, SEED); let target_lookup = T::Lookup::unlookup(target.clone()); // Give target existing locks + T::Currency::make_free_balance_be(&target, T::Currency::minimum_balance()); add_locks::(&target, l as u8); // Add one vesting schedules. + let orig_balance = T::Currency::free_balance(&target); let mut expected_balance = add_vesting_schedules::(target_lookup.clone(), s)?; let transfer_amount = T::MinVestedTransfer::get(); @@ -216,7 +220,7 @@ benchmarks! { }: _(RawOrigin::Signed(caller), target_lookup, vesting_schedule) verify { assert_eq!( - expected_balance, + orig_balance + expected_balance, T::Currency::free_balance(&target), "Transfer didn't happen", ); @@ -238,8 +242,10 @@ benchmarks! { let target: T::AccountId = account("target", 0, SEED); let target_lookup = T::Lookup::unlookup(target.clone()); // Give target existing locks + T::Currency::make_free_balance_be(&target, T::Currency::minimum_balance()); add_locks::(&target, l as u8); // Add one less than max vesting schedules + let orig_balance = T::Currency::free_balance(&target); let mut expected_balance = add_vesting_schedules::(target_lookup.clone(), s)?; let transfer_amount = T::MinVestedTransfer::get(); @@ -254,7 +260,7 @@ benchmarks! { }: _(RawOrigin::Root, source_lookup, target_lookup, vesting_schedule) verify { assert_eq!( - expected_balance, + orig_balance + expected_balance, T::Currency::free_balance(&target), "Transfer didn't happen", ); @@ -272,6 +278,7 @@ benchmarks! { let caller: T::AccountId = account("caller", 0, SEED); let caller_lookup = T::Lookup::unlookup(caller.clone()); // Give target existing locks. + T::Currency::make_free_balance_be(&caller, T::Currency::minimum_balance()); add_locks::(&caller, l as u8); // Add max vesting schedules. let expected_balance = add_vesting_schedules::(caller_lookup, s)?; @@ -322,6 +329,7 @@ benchmarks! { let caller: T::AccountId = account("caller", 0, SEED); let caller_lookup = T::Lookup::unlookup(caller.clone()); // Give target other locks. + T::Currency::make_free_balance_be(&caller, T::Currency::minimum_balance()); add_locks::(&caller, l as u8); // Add max vesting schedules. let total_transferred = add_vesting_schedules::(caller_lookup, s)?; diff --git a/frame/vesting/src/mock.rs b/frame/vesting/src/mock.rs index f2ad6a70025e5..be6afd4a60ec8 100644 --- a/frame/vesting/src/mock.rs +++ b/frame/vesting/src/mock.rs @@ -80,6 +80,10 @@ impl pallet_balances::Config for Test { type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type WeightInfo = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type HoldIdentifier = (); + type MaxHolds = (); } parameter_types! { pub const MinVestedTransfer: u64 = 256 * 2; diff --git a/frame/vesting/src/tests.rs b/frame/vesting/src/tests.rs index efc134cab7279..46afe895f6fcc 100644 --- a/frame/vesting/src/tests.rs +++ b/frame/vesting/src/tests.rs @@ -17,7 +17,10 @@ use frame_support::{assert_noop, assert_ok, assert_storage_noop, dispatch::EncodeLike}; use frame_system::RawOrigin; -use sp_runtime::traits::{BadOrigin, Identity}; +use sp_runtime::{ + traits::{BadOrigin, Identity}, + TokenError, +}; use super::{Vesting as VestingStorage, *}; use crate::mock::{Balances, ExtBuilder, System, Test, Vesting}; @@ -180,10 +183,8 @@ fn unvested_balance_should_not_transfer() { assert_eq!(user1_free_balance, 100); // Account 1 has free balance // Account 1 has only 5 units vested at block 1 (plus 50 unvested) assert_eq!(Vesting::vesting_balance(&1), Some(45)); - assert_noop!( - Balances::transfer(Some(1).into(), 2, 56), - pallet_balances::Error::::LiquidityRestrictions, - ); // Account 1 cannot send more than vested amount + // Account 1 cannot send more than vested amount... + assert_noop!(Balances::transfer_allow_death(Some(1).into(), 2, 56), TokenError::Frozen); }); } @@ -195,7 +196,7 @@ fn vested_balance_should_transfer() { // Account 1 has only 5 units vested at block 1 (plus 50 unvested) assert_eq!(Vesting::vesting_balance(&1), Some(45)); assert_ok!(Vesting::vest(Some(1).into())); - assert_ok!(Balances::transfer(Some(1).into(), 2, 55)); + assert_ok!(Balances::transfer_allow_death(Some(1).into(), 2, 55)); }); } @@ -213,7 +214,7 @@ fn vested_balance_should_transfer_with_multi_sched() { // Account 1 has only 256 units unlocking at block 1 (plus 1280 already fee). assert_eq!(Vesting::vesting_balance(&1), Some(2304)); assert_ok!(Vesting::vest(Some(1).into())); - assert_ok!(Balances::transfer(Some(1).into(), 2, 1536)); + assert_ok!(Balances::transfer_allow_death(Some(1).into(), 2, 1536)); }); } @@ -233,7 +234,7 @@ fn vested_balance_should_transfer_using_vest_other() { // Account 1 has only 5 units vested at block 1 (plus 50 unvested) assert_eq!(Vesting::vesting_balance(&1), Some(45)); assert_ok!(Vesting::vest_other(Some(2).into(), 1)); - assert_ok!(Balances::transfer(Some(1).into(), 2, 55)); + assert_ok!(Balances::transfer_allow_death(Some(1).into(), 2, 55)); }); } @@ -251,7 +252,7 @@ fn vested_balance_should_transfer_using_vest_other_with_multi_sched() { // Account 1 has only 256 units unlocking at block 1 (plus 1280 already free). assert_eq!(Vesting::vesting_balance(&1), Some(2304)); assert_ok!(Vesting::vest_other(Some(2).into(), 1)); - assert_ok!(Balances::transfer(Some(1).into(), 2, 1536)); + assert_ok!(Balances::transfer_allow_death(Some(1).into(), 2, 1536)); }); } @@ -266,8 +267,8 @@ fn non_vested_cannot_vest_other() { #[test] fn extra_balance_should_transfer() { ExtBuilder::default().existential_deposit(10).build().execute_with(|| { - assert_ok!(Balances::transfer(Some(3).into(), 1, 100)); - assert_ok!(Balances::transfer(Some(3).into(), 2, 100)); + assert_ok!(Balances::transfer_allow_death(Some(3).into(), 1, 100)); + assert_ok!(Balances::transfer_allow_death(Some(3).into(), 2, 100)); let user1_free_balance = Balances::free_balance(&1); assert_eq!(user1_free_balance, 200); // Account 1 has 100 more free balance than normal @@ -278,12 +279,13 @@ fn extra_balance_should_transfer() { // Account 1 has only 5 units vested at block 1 (plus 150 unvested) assert_eq!(Vesting::vesting_balance(&1), Some(45)); assert_ok!(Vesting::vest(Some(1).into())); - assert_ok!(Balances::transfer(Some(1).into(), 3, 155)); // Account 1 can send extra units gained + assert_ok!(Balances::transfer_allow_death(Some(1).into(), 3, 155)); // Account 1 can send extra units gained // Account 2 has no units vested at block 1, but gained 100 assert_eq!(Vesting::vesting_balance(&2), Some(200)); assert_ok!(Vesting::vest(Some(2).into())); - assert_ok!(Balances::transfer(Some(2).into(), 3, 100)); // Account 2 can send extra units gained + assert_ok!(Balances::transfer_allow_death(Some(2).into(), 3, 100)); // Account 2 can send extra + // units gained }); } @@ -305,7 +307,7 @@ fn liquid_funds_should_transfer_with_delayed_vesting() { assert_eq!(Vesting::vesting(&12).unwrap(), vec![user12_vesting_schedule]); // Account 12 can still send liquid funds - assert_ok!(Balances::transfer(Some(12).into(), 3, 256 * 5)); + assert_ok!(Balances::transfer_allow_death(Some(12).into(), 3, 256 * 5)); }); } @@ -1144,14 +1146,11 @@ fn vested_transfer_less_than_existential_deposit_fails() { ); // vested_transfer fails. - assert_noop!( - Vesting::vested_transfer(Some(3).into(), 99, sched), - pallet_balances::Error::::ExistentialDeposit, - ); + assert_noop!(Vesting::vested_transfer(Some(3).into(), 99, sched), TokenError::BelowMinimum,); // force_vested_transfer fails. assert_noop!( Vesting::force_vested_transfer(RawOrigin::Root.into(), 3, 99, sched), - pallet_balances::Error::::ExistentialDeposit, + TokenError::BelowMinimum, ); }); } diff --git a/frame/whitelist/src/mock.rs b/frame/whitelist/src/mock.rs index b16286863d71c..d644cd661ec9f 100644 --- a/frame/whitelist/src/mock.rs +++ b/frame/whitelist/src/mock.rs @@ -86,6 +86,10 @@ impl pallet_balances::Config for Test { type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type HoldIdentifier = (); + type MaxHolds = (); } impl pallet_preimage::Config for Test { diff --git a/primitives/runtime/src/lib.rs b/primitives/runtime/src/lib.rs index dc03e074f9e89..622eac3d831af 100644 --- a/primitives/runtime/src/lib.rs +++ b/primitives/runtime/src/lib.rs @@ -606,9 +606,10 @@ impl From for DispatchError { #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] pub enum TokenError { /// Funds are unavailable. - NoFunds, - /// Account that must exist would die. - WouldDie, + FundsUnavailable, + /// Some part of the balance gives the only provider reference to the account and thus cannot + /// be (re)moved. + OnlyProvider, /// Account cannot exist with the funds that would be given. BelowMinimum, /// Account cannot be created. @@ -619,18 +620,25 @@ pub enum TokenError { Frozen, /// Operation is not supported by the asset. Unsupported, + /// Account cannot be created for a held balance. + CannotCreateHold, + /// Withdrawal would cause unwanted loss of account. + NotExpendable, } impl From for &'static str { fn from(e: TokenError) -> &'static str { match e { - TokenError::NoFunds => "Funds are unavailable", - TokenError::WouldDie => "Account that must exist would die", + TokenError::FundsUnavailable => "Funds are unavailable", + TokenError::OnlyProvider => "Account that must exist would die", TokenError::BelowMinimum => "Account cannot exist with the funds that would be given", TokenError::CannotCreate => "Account cannot be created", TokenError::UnknownAsset => "The asset in question is unknown", TokenError::Frozen => "Funds exist but are frozen", TokenError::Unsupported => "Operation is not supported by the asset", + TokenError::CannotCreateHold => + "Account cannot be created for recording amount on hold", + TokenError::NotExpendable => "Account that is desired to remain would die", } } } @@ -994,8 +1002,8 @@ mod tests { Module(ModuleError { index: 2, error: [1, 0, 0, 0], message: None }), ConsumerRemaining, NoProviders, - Token(TokenError::NoFunds), - Token(TokenError::WouldDie), + Token(TokenError::FundsUnavailable), + Token(TokenError::OnlyProvider), Token(TokenError::BelowMinimum), Token(TokenError::CannotCreate), Token(TokenError::UnknownAsset), From 5f6cc69377b2bca3f123e598597a95f023d1b981 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Mar 2023 12:27:43 +0000 Subject: [PATCH 533/715] Bump hashbrown from 0.12.3 to 0.13.2 (#13570) Bumps [hashbrown](https://github.com/rust-lang/hashbrown) from 0.12.3 to 0.13.2. - [Release notes](https://github.com/rust-lang/hashbrown/releases) - [Changelog](https://github.com/rust-lang/hashbrown/blob/master/CHANGELOG.md) - [Commits](https://github.com/rust-lang/hashbrown/compare/v0.12.3...v0.13.2) --- updated-dependencies: - dependency-name: hashbrown dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 2 +- primitives/trie/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index da100658bef9a..3145d736f8e2f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10673,7 +10673,7 @@ dependencies = [ "array-bytes", "criterion", "hash-db", - "hashbrown 0.12.3", + "hashbrown 0.13.2", "lazy_static", "memory-db", "nohash-hasher", diff --git a/primitives/trie/Cargo.toml b/primitives/trie/Cargo.toml index 21582296b67f8..0dacb76d9f27a 100644 --- a/primitives/trie/Cargo.toml +++ b/primitives/trie/Cargo.toml @@ -20,7 +20,7 @@ harness = false [dependencies] ahash = { version = "0.8.2", optional = true } codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false } -hashbrown = { version = "0.12.3", optional = true } +hashbrown = { version = "0.13.2", optional = true } hash-db = { version = "0.16.0", default-features = false } lazy_static = { version = "1.4.0", optional = true } memory-db = { version = "0.32.0", default-features = false } From 9795fa31435426137d91936a52cab8e50ebe2f50 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Mon, 20 Mar 2023 13:34:36 +0100 Subject: [PATCH 534/715] Hotfix NIS benchmark (#13651) * Hotfix NIS rounding error Signed-off-by: Oliver Tale-Yazdi * Also fix communal Signed-off-by: Oliver Tale-Yazdi --------- Signed-off-by: Oliver Tale-Yazdi --- frame/nis/src/benchmarking.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/frame/nis/src/benchmarking.rs b/frame/nis/src/benchmarking.rs index 0cc9e7421d0e6..10fee2abe3ba9 100644 --- a/frame/nis/src/benchmarking.rs +++ b/frame/nis/src/benchmarking.rs @@ -164,6 +164,9 @@ benchmarks! { Nis::::place_bid(RawOrigin::Signed(caller.clone()).into(), bid, 1)?; Nis::::process_queues(Perquintill::one(), 1, 2, &mut WeightCounter::unlimited()); frame_system::Pallet::::set_block_number(Receipts::::get(0).unwrap().expiry); + // FIXME: Ensure that the pallet has enough funding. This should already be the case, but + // a rounding error can cause it to fail. + T::Currency::set_balance(&Nis::::account_id(), BalanceOf::::max_value() / 10u32.into()); }: _(RawOrigin::Signed(caller.clone()), 0, None) verify { assert!(Receipts::::get(0).is_none()); @@ -182,6 +185,9 @@ benchmarks! { Nis::::process_queues(Perquintill::one(), 1, 2, &mut WeightCounter::unlimited()); frame_system::Pallet::::set_block_number(Receipts::::get(0).unwrap().expiry); Nis::::communify(RawOrigin::Signed(caller.clone()).into(), 0)?; + // FIXME: Ensure that the pallet has enough funding. This should already be the case, but + // a rounding error can cause it to fail. + T::Currency::set_balance(&Nis::::account_id(), BalanceOf::::max_value() / 10u32.into()); }: _(RawOrigin::Signed(caller.clone()), 0) verify { assert!(Receipts::::get(0).is_none()); From 97c68138e2da66bab9aabd072a92a42c9631f912 Mon Sep 17 00:00:00 2001 From: Mira Ressel Date: Wed, 15 Mar 2023 22:37:50 +0100 Subject: [PATCH 535/715] Bump ci-linux image for rust 1.68 --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 6cf06273650f7..f9e74364a0d6c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -48,7 +48,7 @@ variables: CARGO_INCREMENTAL: 0 DOCKER_OS: "debian:stretch" ARCH: "x86_64" - CI_IMAGE: "paritytech/ci-linux:production" + CI_IMAGE: "paritytech/ci-linux@sha256:7c76c3f9639f919447abbf9db535588178fde4df583d6926444d44cc20c094e6" # staging 2023-03-20 BUILDAH_IMAGE: "quay.io/buildah/stable:v1.27" RUSTY_CACHIER_SINGLE_BRANCH: master RUSTY_CACHIER_DONT_OPERATE_ON_MAIN_BRANCH: "true" From 46c06438bd457c42890be3102d5413c80c91a92f Mon Sep 17 00:00:00 2001 From: Mira Ressel Date: Wed, 15 Mar 2023 22:55:40 +0100 Subject: [PATCH 536/715] Update ui tests for rust 1.68 --- .../both_use_and_excluded_parts.stderr | 9 +++-- .../exclude_undefined_part.stderr | 9 +++-- .../no_std_genesis_config.stderr | 15 -------- .../old_unsupported_pallet_decl.stderr | 4 +-- .../undefined_genesis_config_part.stderr | 15 -------- .../undefined_inherent_part.stderr | 20 +++++------ .../undefined_origin_part.stderr | 18 ---------- .../undefined_validate_unsigned_part.stderr | 8 ++--- .../use_undefined_part.stderr | 9 +++-- .../test/tests/derive_no_bound_ui/eq.stderr | 20 +++++------ .../call_argument_invalid_bound_2.stderr | 14 +++----- .../genesis_default_not_satisfied.stderr | 18 +++++----- .../tests/pallet_ui/hooks_invalid_item.stderr | 20 +++++------ ...orage_result_query_missing_generics.stderr | 2 +- .../type_value_forgotten_where_clause.stderr | 18 +++++----- .../weight_argument_has_suffix.stderr | 34 ------------------- .../ui/impl_incorrect_method_signature.stderr | 8 ++--- ...reference_in_impl_runtime_apis_call.stderr | 4 +-- 18 files changed, 83 insertions(+), 162 deletions(-) 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 5f1fccd43c549..b1c1879aa56ad 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 @@ -8,9 +8,12 @@ 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: `` + | ^^^^^^^^^^^ not found in this scope + | +help: you might be missing a type parameter + | +18 | pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; + | +++++++++++++ error[E0412]: cannot find type `Runtime` in this scope --> tests/construct_runtime_ui/both_use_and_excluded_parts.rs:20:25 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 c623ecfbf4cdf..66098898bb877 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 @@ -8,9 +8,12 @@ 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: `` + | ^^^^^^^^^^^ not found in this scope + | +help: you might be missing a type parameter + | +23 | pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; + | +++++++++++++ error[E0412]: cannot find type `Runtime` in this scope --> tests/construct_runtime_ui/exclude_undefined_part.rs:25:25 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 2cf451aa65135..cfc8c9264eec6 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,18 +29,3 @@ help: consider importing this struct | 1 | use frame_system::GenesisConfig; | - -error[E0283]: type annotations needed - --> tests/construct_runtime_ui/no_std_genesis_config.rs:40:1 - | -40 | / construct_runtime! { -41 | | pub struct 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/old_unsupported_pallet_decl.stderr b/frame/support/test/tests/construct_runtime_ui/old_unsupported_pallet_decl.stderr index 6029e7e6f48bb..b1338e8920f41 100644 --- 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 @@ -18,7 +18,7 @@ error: cannot find macro `decl_storage` in this scope 6 | decl_storage! { | ^^^^^^^^^^^^ | - = note: consider importing this macro: + = help: consider importing this macro: frame_support::decl_storage error: cannot find macro `decl_module` in this scope @@ -27,5 +27,5 @@ error: cannot find macro `decl_module` in this scope 10 | decl_module! { | ^^^^^^^^^^^ | - = note: consider importing this macro: + = help: consider importing this macro: frame_support::decl_module 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 72099c1b94c0d..f56780c0b0c0d 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,18 +32,3 @@ help: consider importing this struct | 1 | use frame_system::GenesisConfig; | - -error[E0283]: type annotations needed - --> tests/construct_runtime_ui/undefined_genesis_config_part.rs:49:1 - | -49 | / construct_runtime! { -50 | | pub struct 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/construct_runtime_ui/undefined_inherent_part.stderr b/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.stderr index dab6514261420..1801379130913 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 @@ -15,7 +15,7 @@ error: `Pallet` does not have #[pallet::inherent] defined, perhaps you should re | = 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 +error[E0599]: no function or associated item named `create_inherent` found for struct `Pallet` in the current scope --> tests/construct_runtime_ui/undefined_inherent_part.rs:49:1 | 11 | pub struct Pallet(_); @@ -28,14 +28,14 @@ error[E0599]: no function or associated item named `create_inherent` found for s ... | 57 | | } 58 | | } - | |_^ function or associated item not found in `pallet::Pallet` + | |_^ function or associated item not found in `Pallet` | = help: items from traits can only be used if the trait is implemented and in scope = note: the following 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) -error[E0599]: no function or associated item named `is_inherent` found for struct `pallet::Pallet` in the current scope +error[E0599]: no function or associated item named `is_inherent` found for struct `Pallet` in the current scope --> tests/construct_runtime_ui/undefined_inherent_part.rs:49:1 | 11 | pub struct Pallet(_); @@ -48,14 +48,14 @@ error[E0599]: no function or associated item named `is_inherent` found for struc ... | 57 | | } 58 | | } - | |_^ function or associated item not found in `pallet::Pallet` + | |_^ function or associated item not found in `Pallet` | = help: items from traits can only be used if the trait is implemented and in scope = note: the following 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) -error[E0599]: no function or associated item named `check_inherent` found for struct `pallet::Pallet` in the current scope +error[E0599]: no function or associated item named `check_inherent` found for struct `Pallet` in the current scope --> tests/construct_runtime_ui/undefined_inherent_part.rs:49:1 | 11 | pub struct Pallet(_); @@ -68,14 +68,14 @@ error[E0599]: no function or associated item named `check_inherent` found for st ... | 57 | | } 58 | | } - | |_^ function or associated item not found in `pallet::Pallet` + | |_^ function or associated item not found in `Pallet` | = help: items from traits can only be used if the trait is implemented and in scope = note: the following 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 +error[E0599]: no associated item named `INHERENT_IDENTIFIER` found for struct `Pallet` in the current scope --> tests/construct_runtime_ui/undefined_inherent_part.rs:49:1 | 11 | pub struct Pallet(_); @@ -88,14 +88,14 @@ error[E0599]: no associated item named `INHERENT_IDENTIFIER` found for struct `p ... | 57 | | } 58 | | } - | |_^ associated item not found in `pallet::Pallet` + | |_^ associated item not found in `Pallet` | = help: items from traits can only be used if the trait is implemented and in scope = note: the following 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[E0599]: no function or associated item named `is_inherent_required` found for struct `pallet::Pallet` in the current scope +error[E0599]: no function or associated item named `is_inherent_required` found for struct `Pallet` in the current scope --> tests/construct_runtime_ui/undefined_inherent_part.rs:49:1 | 11 | pub struct Pallet(_); @@ -108,7 +108,7 @@ error[E0599]: no function or associated item named `is_inherent_required` found ... | 57 | | } 58 | | } - | |_^ function or associated item not found in `pallet::Pallet` + | |_^ function or associated item not found in `Pallet` | = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `is_inherent_required`, perhaps you need to implement it: 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 dd1bdf76106e6..dbade9fed2cff 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,21 +32,3 @@ help: consider importing this type alias | 1 | use frame_system::Origin; | - -error[E0282]: type annotations needed - --> tests/construct_runtime_ui/undefined_origin_part.rs:49:1 - | -49 | / construct_runtime! { -50 | | pub struct Runtime where -51 | | Block = Block, -52 | | NodeBlock = Block, -... | -57 | | } -58 | | } - | |_^ 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 14106ddd09c17..fa52ce2276635 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 @@ -29,7 +29,7 @@ error[E0599]: no variant or associated item named `Pallet` found for enum `Runti 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 +error[E0599]: no function or associated item named `pre_dispatch` found for struct `Pallet` in the current scope --> tests/construct_runtime_ui/undefined_validate_unsigned_part.rs:49:1 | 11 | pub struct Pallet(_); @@ -42,7 +42,7 @@ error[E0599]: no function or associated item named `pre_dispatch` found for stru ... | 57 | | } 58 | | } - | |_^ function or associated item not found in `pallet::Pallet` + | |_^ function or associated item not found in `Pallet` | = help: items from traits can only be used if the trait is implemented and in scope = note: the following traits define an item `pre_dispatch`, perhaps you need to implement one of them: @@ -50,7 +50,7 @@ error[E0599]: no function or associated item named `pre_dispatch` found for stru candidate #2: `ValidateUnsigned` = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0599]: no function or associated item named `validate_unsigned` found for struct `pallet::Pallet` in the current scope +error[E0599]: no function or associated item named `validate_unsigned` found for struct `Pallet` in the current scope --> tests/construct_runtime_ui/undefined_validate_unsigned_part.rs:49:1 | 11 | pub struct Pallet(_); @@ -63,7 +63,7 @@ error[E0599]: no function or associated item named `validate_unsigned` found for ... | 57 | | } 58 | | } - | |_^ function or associated item not found in `pallet::Pallet` + | |_^ function or associated item not found in `Pallet` | = help: items from traits can only be used if the trait is implemented and in scope = note: the following traits define an item `validate_unsigned`, perhaps you need to implement one of them: 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 e289c75fb008a..cb6b6a44d61da 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 @@ -8,9 +8,12 @@ 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: `` + | ^^^^^^^^^^^ not found in this scope + | +help: you might be missing a type parameter + | +23 | pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; + | +++++++++++++ error[E0412]: cannot find type `Runtime` in this scope --> tests/construct_runtime_ui/use_undefined_part.rs:25:25 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 97ac29f96902d..eb3345eede508 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` - --> tests/derive_no_bound_ui/eq.rs:6:8 - | -6 | struct Foo { - | ^^^ no implementation for `Foo == Foo` - | - = help: the trait `PartialEq` is not implemented for `Foo` + --> tests/derive_no_bound_ui/eq.rs: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` - --> $RUST/core/src/cmp.rs - | - | pub trait Eq: PartialEq { - | ^^^^^^^^^^^^^^^ required by this bound in `std::cmp::Eq` + --> $RUST/core/src/cmp.rs + | + | pub trait Eq: PartialEq { + | ^^^^^^^^^^^^^^^ required by this bound in `Eq` 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 3e2e70432a9c9..476258c03becd 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 @@ -23,17 +23,11 @@ error[E0369]: binary operation `==` cannot be applied to type `&::Bar: WrapperTypeEncode` is not satisfied --> tests/pallet_ui/call_argument_invalid_bound_2.rs:21: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 +1 | #[frame_support::pallet] + | ------------------------ required by a bound introduced by this call ... -21 | pub fn foo(origin: OriginFor, _bar: T::Bar) -> DispatchResultWithPostInfo { - | ^^^^ the trait `WrapperTypeEncode` is not implemented for `::Bar` +21 | pub fn foo(origin: OriginFor, _bar: T::Bar) -> DispatchResultWithPostInfo { + | ^^^^ the trait `WrapperTypeEncode` is not implemented for `::Bar` | = note: required for `::Bar` to implement `Encode` 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 80903928585b4..22b5ce9412ce7 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,14 +1,14 @@ error[E0277]: the trait bound `pallet::GenesisConfig: std::default::Default` is not satisfied - --> 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` - | + --> tests/pallet_ui/genesis_default_not_satisfied.rs:22:38 + | +22 | impl GenesisBuild for GenesisConfig {} + | ^^^^^^^^^^^^^ the trait `std::default::Default` is not implemented for `pallet::GenesisConfig` + | note: required by a bound in `GenesisBuild` - --> $WORKSPACE/frame/support/src/traits/hooks.rs - | - | pub trait GenesisBuild: Default + sp_runtime::traits::MaybeSerializeDeserialize { - | ^^^^^^^ required by this bound in `GenesisBuild` + --> $WORKSPACE/frame/support/src/traits/hooks.rs + | + | 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/hooks_invalid_item.stderr b/frame/support/test/tests/pallet_ui/hooks_invalid_item.stderr index ff52a094d6f8d..9c30179bc11ef 100644 --- a/frame/support/test/tests/pallet_ui/hooks_invalid_item.stderr +++ b/frame/support/test/tests/pallet_ui/hooks_invalid_item.stderr @@ -1,15 +1,15 @@ error[E0107]: missing generics for trait `Hooks` - --> tests/pallet_ui/hooks_invalid_item.rs:12:18 - | -12 | impl Hooks for Pallet {} - | ^^^^^ expected 1 generic argument - | + --> 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` - --> $WORKSPACE/frame/support/src/traits/hooks.rs - | - | pub trait Hooks { - | ^^^^^ ----------- + --> $WORKSPACE/frame/support/src/traits/hooks.rs + | + | pub trait Hooks { + | ^^^^^ ----------- help: add missing generic argument | 12 | impl Hooks for Pallet {} - | ~~~~~~~~~~~~~~~~~~ + | +++++++++++++ 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 index 98265462bbdfb..9e63fd03db52b 100644 --- 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 @@ -12,4 +12,4 @@ note: enum defined here, with 1 generic parameter: `T` help: add missing generic argument | 17 | type Foo = StorageValue<_, u8, ResultQuery::NonExistentValue>>; - | ~~~~~~~~ + | +++ 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 6288dcd534b60..4b4c78b148455 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,52 +1,52 @@ error[E0277]: the trait bound `::AccountId: From` is not satisfied - --> $DIR/type_value_forgotten_where_clause.rs:24:34 + --> tests/pallet_ui/type_value_forgotten_where_clause.rs:24:34 | 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 + --> tests/pallet_ui/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` + | ^^^^^^^^^ required by this bound in `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 + --> tests/pallet_ui/type_value_forgotten_where_clause.rs:24:12 | 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 + --> tests/pallet_ui/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` + | ^^^^^^^^^ required by this bound in `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 + --> tests/pallet_ui/type_value_forgotten_where_clause.rs:24:12 | 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 + --> tests/pallet_ui/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` + | ^^^^^^^^^ required by this bound in `Config` help: consider further restricting the associated type | 24 | #[pallet::type_value] fn Foo() -> u32 where ::AccountId: From { 3u32 } diff --git a/frame/support/test/tests/pallet_ui/weight_argument_has_suffix.stderr b/frame/support/test/tests/pallet_ui/weight_argument_has_suffix.stderr index c9b2010f88bb3..df9b0798ab93d 100644 --- a/frame/support/test/tests/pallet_ui/weight_argument_has_suffix.stderr +++ b/frame/support/test/tests/pallet_ui/weight_argument_has_suffix.stderr @@ -5,37 +5,3 @@ error: invalid suffix `something` for number literal | ^^^^^^^^^^^^^^^ invalid suffix `something` | = help: the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.) - -error[E0308]: mismatched types - --> tests/pallet_ui/weight_argument_has_suffix.rs:12:12 - | -12 | #[pallet::call] - | ^^^^ - | | - | expected trait `frame_support::dispatch::ClassifyDispatch`, found trait `frame_support::dispatch::WeighData` - | arguments to this function are incorrect - | - = note: expected reference `&dyn frame_support::dispatch::ClassifyDispatch<()>` - found reference `&dyn frame_support::dispatch::WeighData<()>` -note: associated function defined here - --> $WORKSPACE/frame/support/src/dispatch.rs - | - | fn classify_dispatch(&self, target: T) -> DispatchClass; - | ^^^^^^^^^^^^^^^^^ - -error[E0308]: mismatched types - --> tests/pallet_ui/weight_argument_has_suffix.rs:12:12 - | -12 | #[pallet::call] - | ^^^^ - | | - | expected trait `frame_support::dispatch::PaysFee`, found trait `frame_support::dispatch::WeighData` - | arguments to this function are incorrect - | - = note: expected reference `&dyn frame_support::dispatch::PaysFee<()>` - found reference `&dyn frame_support::dispatch::WeighData<()>` -note: associated function defined here - --> $WORKSPACE/frame/support/src/dispatch.rs - | - | fn pays_fee(&self, _target: T) -> Pays; - | ^^^^^^^^ 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 f5b6ac1da4576..5b36248228bff 100644 --- a/primitives/api/test/tests/ui/impl_incorrect_method_signature.stderr +++ b/primitives/api/test/tests/ui/impl_incorrect_method_signature.stderr @@ -4,7 +4,7 @@ error[E0053]: method `test` has an incompatible type for trait 19 | fn test(data: String) {} | ^^^^^^ | | - | expected `u64`, found struct `std::string::String` + | expected `u64`, found struct `String` | help: change the parameter type to match the trait: `u64` | note: type in trait @@ -12,8 +12,8 @@ note: type in trait | 13 | fn test(data: u64); | ^^^ - = note: expected fn pointer `fn(u64)` - found fn pointer `fn(std::string::String)` + = note: expected signature `fn(u64)` + found signature `fn(std::string::String)` error[E0308]: mismatched types --> tests/ui/impl_incorrect_method_signature.rs:19:11 @@ -21,7 +21,7 @@ error[E0308]: mismatched types 17 | / sp_api::impl_runtime_apis! { 18 | | impl self::Api for Runtime { 19 | | fn test(data: String) {} - | | ^^^^ expected `u64`, found struct `std::string::String` + | | ^^^^ expected `u64`, found struct `String` 20 | | } ... | 32 | | } 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 06f8226ec88bf..1515bd3a1208f 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 @@ -12,8 +12,8 @@ note: type in trait | 13 | fn test(data: u64); | ^^^ - = note: expected fn pointer `fn(u64)` - found fn pointer `fn(&u64)` + = note: expected signature `fn(u64)` + found signature `fn(&u64)` error[E0308]: mismatched types --> tests/ui/type_reference_in_impl_runtime_apis_call.rs:19:11 From ba9582568d5550c50adc9f5e3626f06eb8a5133b Mon Sep 17 00:00:00 2001 From: Mira Ressel Date: Thu, 16 Mar 2023 15:38:06 +0100 Subject: [PATCH 537/715] address clippy & rustdoc warnings The comment was out of date anyway, State::Live no longer takes a snapshot_path argument. --- client/state-db/src/lib.rs | 2 +- primitives/runtime/src/offchain/http.rs | 2 +- primitives/trie/src/lib.rs | 7 ++----- utils/frame/try-runtime/cli/src/lib.rs | 2 -- 4 files changed, 4 insertions(+), 9 deletions(-) diff --git a/client/state-db/src/lib.rs b/client/state-db/src/lib.rs index 5ebfbaad6d8f6..b41240d629b91 100644 --- a/client/state-db/src/lib.rs +++ b/client/state-db/src/lib.rs @@ -406,7 +406,7 @@ impl StateDbSync { } fn prune(&mut self, commit: &mut CommitSet) -> Result<(), Error> { - if let (&mut Some(ref mut pruning), &PruningMode::Constrained(ref constraints)) = + if let (&mut Some(ref mut pruning), PruningMode::Constrained(constraints)) = (&mut self.pruning, &self.mode) { loop { diff --git a/primitives/runtime/src/offchain/http.rs b/primitives/runtime/src/offchain/http.rs index 0229203c1de5f..25e5c1007d5da 100644 --- a/primitives/runtime/src/offchain/http.rs +++ b/primitives/runtime/src/offchain/http.rs @@ -450,7 +450,7 @@ impl Headers { /// and collect them on your own. pub fn find(&self, name: &str) -> Option<&str> { let raw = name.as_bytes(); - for &(ref key, ref val) in &self.raw { + for (key, val) in &self.raw { if &**key == raw { return str::from_utf8(val).ok() } diff --git a/primitives/trie/src/lib.rs b/primitives/trie/src/lib.rs index 175fb32d4e851..94155458569bf 100644 --- a/primitives/trie/src/lib.rs +++ b/primitives/trie/src/lib.rs @@ -647,7 +647,7 @@ mod tests { count: 1000, }; let mut d = st.make(); - d.sort_by(|&(ref a, _), &(ref b, _)| a.cmp(b)); + d.sort_by(|(a, _), (b, _)| a.cmp(b)); let dr = d.iter().map(|v| (&v.0[..], &v.1[..])).collect(); check_input(&dr); } @@ -716,10 +716,7 @@ mod tests { t } - fn unpopulate_trie<'db, T: TrieConfiguration>( - t: &mut TrieDBMut<'db, T>, - v: &[(Vec, Vec)], - ) { + fn unpopulate_trie(t: &mut TrieDBMut<'_, T>, v: &[(Vec, Vec)]) { for i in v { let key: &[u8] = &i.0; t.remove(key).unwrap(); diff --git a/utils/frame/try-runtime/cli/src/lib.rs b/utils/frame/try-runtime/cli/src/lib.rs index e1d75064ac87f..bd914d3a2e017 100644 --- a/utils/frame/try-runtime/cli/src/lib.rs +++ b/utils/frame/try-runtime/cli/src/lib.rs @@ -599,8 +599,6 @@ pub struct LiveState { #[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 { #[arg(short, long)] snapshot_path: PathBuf, From 9d2d020c5134d8c7870396cb04bca63a674abfd5 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Mon, 20 Mar 2023 19:21:26 +0100 Subject: [PATCH 538/715] Keystore overhaul (iter 2) (#13634) * Remove bloat about remote keystore * Update docs and remove unused 'KeystoreRef' trait * Use wherever possible, MemoryKeystore for testing * Remove unrequired fully qualified method syntax for Keystore --- Cargo.lock | 1 - bin/node-template/node/src/service.rs | 24 +----- bin/node/cli/benches/block_production.rs | 1 - bin/node/cli/benches/transaction_pool.rs | 1 - bin/node/cli/src/service.rs | 35 +++++---- bin/node/executor/tests/submit_transaction.rs | 63 ++++++--------- bin/utils/chain-spec-builder/src/main.rs | 12 +-- .../authority-discovery/src/worker/tests.rs | 4 +- client/cli/src/commands/insert_key.rs | 11 +-- client/cli/src/config.rs | 7 +- client/cli/src/params/keystore_params.rs | 6 +- client/cli/src/runner.rs | 1 - client/consensus/aura/src/lib.rs | 49 ++++++------ client/consensus/babe/rpc/Cargo.toml | 1 - client/consensus/babe/rpc/src/lib.rs | 29 +++---- client/consensus/babe/src/authorship.rs | 32 +++----- client/consensus/babe/src/lib.rs | 25 +++--- client/consensus/babe/src/tests.rs | 19 +++-- .../beefy/src/communication/gossip.rs | 16 ++-- client/consensus/beefy/src/keystore.rs | 61 +++++++-------- client/consensus/beefy/src/tests.rs | 7 +- client/consensus/grandpa/src/lib.rs | 4 +- client/consensus/grandpa/src/tests.rs | 7 +- client/keystore/src/local.rs | 43 ++++++----- client/rpc/src/author/mod.rs | 9 ++- client/rpc/src/author/tests.rs | 8 +- client/service/src/builder.rs | 60 +++------------ client/service/src/config.rs | 2 - client/service/test/src/lib.rs | 1 - frame/benchmarking/src/baseline.rs | 5 +- frame/contracts/src/tests.rs | 4 +- frame/examples/offchain-worker/src/tests.rs | 44 ++++------- frame/nfts/src/mock.rs | 4 +- .../application-crypto/test/src/ecdsa.rs | 2 +- .../application-crypto/test/src/ed25519.rs | 2 +- .../application-crypto/test/src/sr25519.rs | 2 +- primitives/consensus/beefy/src/commitment.rs | 12 +-- primitives/consensus/beefy/src/witness.rs | 13 +--- primitives/consensus/grandpa/src/lib.rs | 18 ++--- primitives/io/src/lib.rs | 77 +++++++++---------- primitives/keystore/src/lib.rs | 9 ++- primitives/keystore/src/testing.rs | 28 +++---- .../benchmarking-cli/src/pallet/command.rs | 7 +- utils/frame/try-runtime/cli/src/lib.rs | 3 +- 44 files changed, 312 insertions(+), 457 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3145d736f8e2f..4928873566627 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8438,7 +8438,6 @@ dependencies = [ "sp-keystore", "sp-runtime", "substrate-test-runtime-client", - "tempfile", "thiserror", "tokio", ] diff --git a/bin/node-template/node/src/service.rs b/bin/node-template/node/src/service.rs index 40ad80c7b3b79..dfbb5e96354e4 100644 --- a/bin/node-template/node/src/service.rs +++ b/bin/node-template/node/src/service.rs @@ -5,7 +5,6 @@ use sc_client_api::BlockBackend; use sc_consensus_aura::{ImportQueueParams, SlotProportion, StartAuraParams}; use sc_consensus_grandpa::SharedVoterState; pub use sc_executor::NativeElseWasmExecutor; -use sc_keystore::LocalKeystore; use sc_service::{error::Error as ServiceError, Configuration, TaskManager, WarpSyncParams}; use sc_telemetry::{Telemetry, TelemetryWorker}; use sp_consensus_aura::sr25519::AuthorityPair as AuraPair; @@ -58,10 +57,6 @@ pub fn new_partial( >, ServiceError, > { - if config.keystore_remote.is_some() { - return Err(ServiceError::Other("Remote Keystores are not supported.".into())) - } - let telemetry = config .telemetry_endpoints .clone() @@ -147,13 +142,6 @@ pub fn new_partial( }) } -fn remote_keystore(_url: &String) -> Result, &'static str> { - // FIXME: here would the concrete keystore be built, - // must return a concrete type (NOT `LocalKeystore`) that - // implements `Keystore` - Err("Remote Keystore not supported.") -} - /// Builds a new service for a full client. pub fn new_full(mut config: Configuration) -> Result { let sc_service::PartialComponents { @@ -161,22 +149,12 @@ pub fn new_full(mut config: Configuration) -> Result backend, mut task_manager, import_queue, - mut keystore_container, + keystore_container, select_chain, transaction_pool, other: (block_import, grandpa_link, mut telemetry), } = new_partial(&config)?; - if let Some(url) = &config.keystore_remote { - match remote_keystore(url) { - Ok(k) => keystore_container.set_remote_keystore(k), - Err(e) => - return Err(ServiceError::Other(format!( - "Error hooking up remote keystore for {}: {}", - url, e - ))), - }; - } let grandpa_protocol_name = sc_consensus_grandpa::protocol_standard_name( &client.block_hash(0).ok().flatten().expect("Genesis block exists; qed"), &config.chain_spec, diff --git a/bin/node/cli/benches/block_production.rs b/bin/node/cli/benches/block_production.rs index f1c65955eaef8..c7f0cd20efd5b 100644 --- a/bin/node/cli/benches/block_production.rs +++ b/bin/node/cli/benches/block_production.rs @@ -69,7 +69,6 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase { transaction_pool: Default::default(), network: network_config, keystore: KeystoreConfig::InMemory, - keystore_remote: Default::default(), database: DatabaseSource::RocksDb { path: root.join("db"), cache_size: 128 }, trie_cache_maximum_size: Some(64 * 1024 * 1024), state_pruning: Some(PruningMode::ArchiveAll), diff --git a/bin/node/cli/benches/transaction_pool.rs b/bin/node/cli/benches/transaction_pool.rs index 72c1c81608e13..7488ec03363e7 100644 --- a/bin/node/cli/benches/transaction_pool.rs +++ b/bin/node/cli/benches/transaction_pool.rs @@ -64,7 +64,6 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase { }, network: network_config, keystore: KeystoreConfig::InMemory, - keystore_remote: Default::default(), database: DatabaseSource::RocksDb { path: root.join("db"), cache_size: 128 }, trie_cache_maximum_size: Some(64 * 1024 * 1024), state_pruning: Some(PruningMode::ArchiveAll), diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs index d32223339dc4a..be8553b7b3a98 100644 --- a/bin/node/cli/src/service.rs +++ b/bin/node/cli/src/service.rs @@ -595,7 +595,7 @@ mod tests { use sp_core::{crypto::Pair as CryptoPair, Public}; use sp_inherents::InherentDataProvider; use sp_keyring::AccountKeyring; - use sp_keystore::{Keystore, KeystorePtr}; + use sp_keystore::KeystorePtr; use sp_runtime::{ generic::{Digest, Era, SignedPayload}, key_types::BABE, @@ -615,12 +615,13 @@ mod tests { sp_tracing::try_init_simple(); let keystore_path = tempfile::tempdir().expect("Creates keystore path"); - let keystore: KeystorePtr = - Arc::new(LocalKeystore::open(keystore_path.path(), None).expect("Creates keystore")); - let alice: sp_consensus_babe::AuthorityId = - Keystore::sr25519_generate_new(&*keystore, BABE, Some("//Alice")) - .expect("Creates authority pair") - .into(); + let keystore: KeystorePtr = LocalKeystore::open(keystore_path.path(), None) + .expect("Creates keystore") + .into(); + let alice: sp_consensus_babe::AuthorityId = keystore + .sr25519_generate_new(BABE, Some("//Alice")) + .expect("Creates authority pair") + .into(); let chain_spec = crate::chain_spec::tests::integration_test_config_with_single_authority(); @@ -735,16 +736,16 @@ mod tests { // sign the pre-sealed hash of the block and then // add it to a digest item. let to_sign = pre_hash.encode(); - let signature = Keystore::sign_with( - &*keystore, - sp_consensus_babe::AuthorityId::ID, - &alice.to_public_crypto_pair(), - &to_sign, - ) - .unwrap() - .unwrap() - .try_into() - .unwrap(); + let signature = keystore + .sign_with( + sp_consensus_babe::AuthorityId::ID, + &alice.to_public_crypto_pair(), + &to_sign, + ) + .unwrap() + .unwrap() + .try_into() + .unwrap(); let item = ::babe_seal(signature); slot += 1; diff --git a/bin/node/executor/tests/submit_transaction.rs b/bin/node/executor/tests/submit_transaction.rs index a3d6681fb6928..9bff415d27e45 100644 --- a/bin/node/executor/tests/submit_transaction.rs +++ b/bin/node/executor/tests/submit_transaction.rs @@ -22,7 +22,6 @@ use sp_application_crypto::AppKey; use sp_core::offchain::{testing::TestTransactionPoolExt, TransactionPoolExt}; use sp_keyring::sr25519::Keyring::Alice; use sp_keystore::{testing::MemoryKeystore, Keystore, KeystoreExt}; -use std::sync::Arc; pub mod common; use self::common::*; @@ -63,25 +62,16 @@ fn should_submit_signed_transaction() { t.register_extension(TransactionPoolExt::new(pool)); let keystore = MemoryKeystore::new(); - Keystore::sr25519_generate_new( - &keystore, - sr25519::AuthorityId::ID, - Some(&format!("{}/hunter1", PHRASE)), - ) - .unwrap(); - Keystore::sr25519_generate_new( - &keystore, - sr25519::AuthorityId::ID, - Some(&format!("{}/hunter2", PHRASE)), - ) - .unwrap(); - Keystore::sr25519_generate_new( - &keystore, - sr25519::AuthorityId::ID, - Some(&format!("{}/hunter3", PHRASE)), - ) - .unwrap(); - t.register_extension(KeystoreExt(Arc::new(keystore))); + keystore + .sr25519_generate_new(sr25519::AuthorityId::ID, Some(&format!("{}/hunter1", PHRASE))) + .unwrap(); + keystore + .sr25519_generate_new(sr25519::AuthorityId::ID, Some(&format!("{}/hunter2", PHRASE))) + .unwrap(); + keystore + .sr25519_generate_new(sr25519::AuthorityId::ID, Some(&format!("{}/hunter3", PHRASE))) + .unwrap(); + t.register_extension(KeystoreExt::new(keystore)); t.execute_with(|| { let results = @@ -106,19 +96,13 @@ fn should_submit_signed_twice_from_the_same_account() { t.register_extension(TransactionPoolExt::new(pool)); let keystore = MemoryKeystore::new(); - Keystore::sr25519_generate_new( - &keystore, - sr25519::AuthorityId::ID, - Some(&format!("{}/hunter1", PHRASE)), - ) - .unwrap(); - Keystore::sr25519_generate_new( - &keystore, - sr25519::AuthorityId::ID, - Some(&format!("{}/hunter2", PHRASE)), - ) - .unwrap(); - t.register_extension(KeystoreExt(Arc::new(keystore))); + keystore + .sr25519_generate_new(sr25519::AuthorityId::ID, Some(&format!("{}/hunter1", PHRASE))) + .unwrap(); + keystore + .sr25519_generate_new(sr25519::AuthorityId::ID, Some(&format!("{}/hunter2", PHRASE))) + .unwrap(); + t.register_extension(KeystoreExt::new(keystore)); t.execute_with(|| { let result = @@ -169,7 +153,7 @@ fn should_submit_signed_twice_from_all_accounts() { keystore .sr25519_generate_new(sr25519::AuthorityId::ID, Some(&format!("{}/hunter2", PHRASE))) .unwrap(); - t.register_extension(KeystoreExt(Arc::new(keystore))); + t.register_extension(KeystoreExt::new(keystore)); t.execute_with(|| { let results = Signer::::all_accounts() @@ -227,13 +211,10 @@ fn submitted_transaction_should_be_valid() { t.register_extension(TransactionPoolExt::new(pool)); let keystore = MemoryKeystore::new(); - Keystore::sr25519_generate_new( - &keystore, - sr25519::AuthorityId::ID, - Some(&format!("{}/hunter1", PHRASE)), - ) - .unwrap(); - t.register_extension(KeystoreExt(Arc::new(keystore))); + keystore + .sr25519_generate_new(sr25519::AuthorityId::ID, Some(&format!("{}/hunter1", PHRASE))) + .unwrap(); + t.register_extension(KeystoreExt::new(keystore)); t.execute_with(|| { let results = diff --git a/bin/utils/chain-spec-builder/src/main.rs b/bin/utils/chain-spec-builder/src/main.rs index f7b7d94c57d1c..f94fca1c1638d 100644 --- a/bin/utils/chain-spec-builder/src/main.rs +++ b/bin/utils/chain-spec-builder/src/main.rs @@ -19,7 +19,6 @@ use std::{ fs, path::{Path, PathBuf}, - sync::Arc, }; use ansi_term::Style; @@ -32,7 +31,7 @@ use sp_core::{ crypto::{ByteArray, Ss58Codec}, sr25519, }; -use sp_keystore::{Keystore, KeystorePtr}; +use sp_keystore::KeystorePtr; /// A utility to easily create a testnet chain spec definition with a given set /// of authorities and endowed accounts and/or generate random accounts. @@ -164,16 +163,17 @@ fn generate_chain_spec( fn generate_authority_keys_and_store(seeds: &[String], keystore_path: &Path) -> Result<(), String> { for (n, seed) in seeds.iter().enumerate() { - let keystore: KeystorePtr = Arc::new( + let keystore: KeystorePtr = LocalKeystore::open(keystore_path.join(format!("auth-{}", n)), None) - .map_err(|err| err.to_string())?, - ); + .map_err(|err| err.to_string())? + .into(); let (_, _, grandpa, babe, im_online, authority_discovery) = chain_spec::authority_keys_from_seed(seed); let insert_key = |key_type, public| { - Keystore::insert(&*keystore, key_type, &format!("//{}", seed), public) + keystore + .insert(key_type, &format!("//{}", seed), public) .map_err(|_| format!("Failed to insert key: {}", grandpa)) }; diff --git a/client/authority-discovery/src/worker/tests.rs b/client/authority-discovery/src/worker/tests.rs index c918d79932624..49055fec51611 100644 --- a/client/authority-discovery/src/worker/tests.rs +++ b/client/authority-discovery/src/worker/tests.rs @@ -697,7 +697,7 @@ fn addresses_to_publish_adds_p2p() { Arc::new(TestApi { authorities: vec![] }), network.clone(), Box::pin(dht_event_rx), - Role::PublishAndDiscover(Arc::new(MemoryKeystore::new())), + Role::PublishAndDiscover(MemoryKeystore::new().into()), Some(prometheus_endpoint::Registry::new()), Default::default(), ); @@ -731,7 +731,7 @@ fn addresses_to_publish_respects_existing_p2p_protocol() { Arc::new(TestApi { authorities: vec![] }), network.clone(), Box::pin(dht_event_rx), - Role::PublishAndDiscover(Arc::new(MemoryKeystore::new())), + Role::PublishAndDiscover(MemoryKeystore::new().into()), Some(prometheus_endpoint::Registry::new()), Default::default(), ); diff --git a/client/cli/src/commands/insert_key.rs b/client/cli/src/commands/insert_key.rs index b02c0181d43a2..e80058d44a5af 100644 --- a/client/cli/src/commands/insert_key.rs +++ b/client/cli/src/commands/insert_key.rs @@ -24,8 +24,7 @@ use clap::Parser; use sc_keystore::LocalKeystore; use sc_service::config::{BasePath, KeystoreConfig}; use sp_core::crypto::{KeyTypeId, SecretString}; -use sp_keystore::{Keystore, KeystorePtr}; -use std::sync::Arc; +use sp_keystore::KeystorePtr; /// The `insert` command #[derive(Debug, Clone, Parser)] @@ -67,9 +66,9 @@ impl InsertKeyCmd { let config_dir = base_path.config_dir(chain_spec.id()); let (keystore, public) = match self.keystore_params.keystore_config(&config_dir)? { - (_, KeystoreConfig::Path { path, password }) => { + KeystoreConfig::Path { path, password } => { let public = with_crypto_scheme!(self.scheme, to_vec(&suri, password.clone()))?; - let keystore: KeystorePtr = Arc::new(LocalKeystore::open(path, password)?); + let keystore: KeystorePtr = LocalKeystore::open(path, password)?.into(); (keystore, public) }, _ => unreachable!("keystore_config always returns path and password; qed"), @@ -78,7 +77,8 @@ impl InsertKeyCmd { let key_type = KeyTypeId::try_from(self.key_type.as_str()).map_err(|_| Error::KeyTypeInvalid)?; - Keystore::insert(&*keystore, key_type, &suri, &public[..]) + keystore + .insert(key_type, &suri, &public[..]) .map_err(|_| Error::KeystoreOperation)?; Ok(()) @@ -95,6 +95,7 @@ mod tests { use super::*; use sc_service::{ChainSpec, ChainType, GenericChainSpec, NoExtension}; use sp_core::{sr25519::Pair, ByteArray, Pair as _}; + use sp_keystore::Keystore; use tempfile::TempDir; struct Cli; diff --git a/client/cli/src/config.rs b/client/cli/src/config.rs index 5fedcf99a12ef..063b2c39839f4 100644 --- a/client/cli/src/config.rs +++ b/client/cli/src/config.rs @@ -185,10 +185,10 @@ pub trait CliConfiguration: Sized { /// /// By default this is retrieved from `KeystoreParams` if it is available. Otherwise it uses /// `KeystoreConfig::InMemory`. - fn keystore_config(&self, config_dir: &PathBuf) -> Result<(Option, KeystoreConfig)> { + fn keystore_config(&self, config_dir: &PathBuf) -> Result { self.keystore_params() .map(|x| x.keystore_config(config_dir)) - .unwrap_or_else(|| Ok((None, KeystoreConfig::InMemory))) + .unwrap_or_else(|| Ok(KeystoreConfig::InMemory)) } /// Get the database cache size. @@ -505,7 +505,7 @@ pub trait CliConfiguration: Sized { let role = self.role(is_dev)?; let max_runtime_instances = self.max_runtime_instances()?.unwrap_or(8); let is_validator = role.is_authority(); - let (keystore_remote, keystore) = self.keystore_config(&config_dir)?; + let keystore = self.keystore_config(&config_dir)?; let telemetry_endpoints = self.telemetry_endpoints(&chain_spec)?; let runtime_cache_size = self.runtime_cache_size()?; @@ -524,7 +524,6 @@ pub trait CliConfiguration: Sized { node_key, DCV::p2p_listen_port(), )?, - keystore_remote, keystore, database: self.database_config(&config_dir, database_cache_size, database)?, trie_cache_maximum_size: self.trie_cache_maximum_size()?, diff --git a/client/cli/src/params/keystore_params.rs b/client/cli/src/params/keystore_params.rs index e6e6fd9eb47ed..8933110c400b7 100644 --- a/client/cli/src/params/keystore_params.rs +++ b/client/cli/src/params/keystore_params.rs @@ -68,9 +68,7 @@ pub fn secret_string_from_str(s: &str) -> std::result::Result Result<(Option, KeystoreConfig)> { + pub fn keystore_config(&self, config_dir: &Path) -> Result { let password = if self.password_interactive { Some(SecretString::new(input_keystore_password()?)) } else if let Some(ref file) = self.password_filename { @@ -85,7 +83,7 @@ impl KeystoreParams { .clone() .unwrap_or_else(|| config_dir.join(DEFAULT_KEYSTORE_CONFIG_PATH)); - Ok((self.keystore_uri.clone(), KeystoreConfig::Path { path, password })) + Ok(KeystoreConfig::Path { path, password }) } /// helper method to fetch password from `KeyParams` or read from stdin diff --git a/client/cli/src/runner.rs b/client/cli/src/runner.rs index 47adfcf89fe99..3d216aef4a75c 100644 --- a/client/cli/src/runner.rs +++ b/client/cli/src/runner.rs @@ -345,7 +345,6 @@ mod tests { 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, diff --git a/client/consensus/aura/src/lib.rs b/client/consensus/aura/src/lib.rs index 8cdad148d6ef4..d06a6016a2297 100644 --- a/client/consensus/aura/src/lib.rs +++ b/client/consensus/aura/src/lib.rs @@ -51,7 +51,7 @@ use sp_consensus::{BlockOrigin, Environment, Error as ConsensusError, Proposer, use sp_consensus_slots::Slot; use sp_core::crypto::{ByteArray, Pair, Public}; use sp_inherents::CreateInherentDataProviders; -use sp_keystore::{Keystore, KeystorePtr}; +use sp_keystore::KeystorePtr; use sp_runtime::{ traits::{Block as BlockT, Header, Member, NumberFor, Zero}, DigestItem, @@ -418,10 +418,10 @@ where ) -> Option { let expected_author = slot_author::

(slot, epoch_data); expected_author.and_then(|p| { - if Keystore::has_keys( - &*self.keystore, - &[(p.to_raw_vec(), sp_application_crypto::key_types::AURA)], - ) { + if self + .keystore + .has_keys(&[(p.to_raw_vec(), sp_application_crypto::key_types::AURA)]) + { Some(p.clone()) } else { None @@ -449,19 +449,16 @@ where // add it to a digest item. let public_type_pair = public.to_public_crypto_pair(); let public = public.to_raw_vec(); - let signature = Keystore::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(), - ) - })?; + let signature = self + .keystore + .sign_with( 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(), + ) + })?; let signature = signature .clone() .try_into() @@ -648,6 +645,7 @@ mod tests { use sp_consensus_aura::sr25519::AuthorityPair; use sp_inherents::InherentData; use sp_keyring::sr25519::Keyring; + use sp_keystore::Keystore; use sp_runtime::{ traits::{Block as BlockT, Header as _}, Digest, @@ -798,7 +796,8 @@ mod tests { LocalKeystore::open(keystore_path.path(), None).expect("Creates keystore."), ); - Keystore::sr25519_generate_new(&*keystore, AURA, Some(&key.to_seed())) + keystore + .sr25519_generate_new(AURA, Some(&key.to_seed())) .expect("Creates authority key"); keystore_paths.push(keystore_path); @@ -883,7 +882,8 @@ mod tests { let keystore_path = tempfile::tempdir().expect("Creates keystore path"); let keystore = LocalKeystore::open(keystore_path.path(), None).expect("Creates keystore."); - let public = Keystore::sr25519_generate_new(&keystore, AuthorityPair::ID, None) + let public = keystore + .sr25519_generate_new(AuthorityPair::ID, None) .expect("Key should be created"); authorities.push(public.into()); @@ -933,12 +933,9 @@ mod tests { let keystore_path = tempfile::tempdir().expect("Creates keystore path"); let keystore = LocalKeystore::open(keystore_path.path(), None).expect("Creates keystore."); - Keystore::sr25519_generate_new( - &keystore, - AuthorityPair::ID, - Some(&Keyring::Alice.to_seed()), - ) - .expect("Key should be created"); + keystore + .sr25519_generate_new(AuthorityPair::ID, Some(&Keyring::Alice.to_seed())) + .expect("Key should be created"); let net = Arc::new(Mutex::new(net)); diff --git a/client/consensus/babe/rpc/Cargo.toml b/client/consensus/babe/rpc/Cargo.toml index 4f5aaf85494b9..f81a14a97c758 100644 --- a/client/consensus/babe/rpc/Cargo.toml +++ b/client/consensus/babe/rpc/Cargo.toml @@ -31,7 +31,6 @@ sp-runtime = { version = "7.0.0", path = "../../../../primitives/runtime" } [dev-dependencies] serde_json = "1.0.85" -tempfile = "3.1.0" tokio = "1.22.0" sc-consensus = { version = "0.10.0-dev", path = "../../../consensus/common" } sc-keystore = { version = "4.0.0-dev", path = "../../../keystore" } diff --git a/client/consensus/babe/rpc/src/lib.rs b/client/consensus/babe/rpc/src/lib.rs index bc4d1c17eb3f1..005d84938e28e 100644 --- a/client/consensus/babe/rpc/src/lib.rs +++ b/client/consensus/babe/rpc/src/lib.rs @@ -37,7 +37,7 @@ use sp_consensus_babe::{ digests::PreDigest, AuthorityId, BabeApi as BabeRuntimeApi, BabeConfiguration, }; use sp_core::crypto::ByteArray; -use sp_keystore::{Keystore, KeystorePtr}; +use sp_keystore::KeystorePtr; use sp_runtime::traits::{Block as BlockT, Header as _}; use std::{collections::HashMap, sync::Arc}; @@ -117,7 +117,7 @@ where .iter() .enumerate() .filter_map(|(i, a)| { - if Keystore::has_keys(&*self.keystore, &[(a.0.to_raw_vec(), AuthorityId::ID)]) { + if self.keystore.has_keys(&[(a.0.to_raw_vec(), AuthorityId::ID)]) { Some((a.0.clone(), i)) } else { None @@ -210,30 +210,21 @@ where #[cfg(test)] mod tests { use super::*; - use sc_keystore::LocalKeystore; - use sp_application_crypto::AppPair; + use sc_consensus_babe::block_import; use sp_core::crypto::key_types::BABE; use sp_keyring::Sr25519Keyring; - use sp_keystore::{Keystore, KeystorePtr}; + use sp_keystore::{testing::MemoryKeystore, Keystore}; use substrate_test_runtime_client::{ runtime::Block, Backend, DefaultTestClientBuilderExt, TestClient, TestClientBuilder, TestClientBuilderExt, }; - use sc_consensus_babe::{block_import, AuthorityPair}; - use std::sync::Arc; - - /// creates keystore backed by a temp file - fn create_temp_keystore( - authority: Sr25519Keyring, - ) -> (KeystorePtr, tempfile::TempDir) { - let keystore_path = tempfile::tempdir().expect("Creates keystore path"); - let keystore = - Arc::new(LocalKeystore::open(keystore_path.path(), None).expect("Creates keystore")); - Keystore::sr25519_generate_new(&*keystore, BABE, Some(&authority.to_seed())) + fn create_keystore(authority: Sr25519Keyring) -> KeystorePtr { + let keystore = MemoryKeystore::new(); + keystore + .sr25519_generate_new(BABE, Some(&authority.to_seed())) .expect("Creates authority key"); - - (keystore, keystore_path) + keystore.into() } fn test_babe_rpc_module( @@ -247,7 +238,7 @@ mod tests { .expect("can initialize block-import"); let epoch_changes = link.epoch_changes().clone(); - let keystore = create_temp_keystore::(Sr25519Keyring::Alice).0; + let keystore = create_keystore(Sr25519Keyring::Alice); Babe::new(client.clone(), epoch_changes, keystore, config, longest_chain, deny_unsafe) } diff --git a/client/consensus/babe/src/authorship.rs b/client/consensus/babe/src/authorship.rs index 956e886d1254c..c4b43b0d074b9 100644 --- a/client/consensus/babe/src/authorship.rs +++ b/client/consensus/babe/src/authorship.rs @@ -29,7 +29,7 @@ use sp_consensus_babe::{ }; use sp_consensus_vrf::schnorrkel::{VRFOutput, VRFProof}; use sp_core::{blake2_256, crypto::ByteArray, U256}; -use sp_keystore::{Keystore, KeystorePtr}; +use sp_keystore::KeystorePtr; /// Calculates the primary selection threshold for a given authority, taking /// into account `c` (`1 - c` represents the probability of a slot being empty). @@ -153,8 +153,7 @@ fn claim_secondary_slot( if authority_id == expected_author { let pre_digest = if author_secondary_vrf { let transcript_data = make_transcript_data(randomness, slot, epoch_index); - let result = Keystore::sr25519_vrf_sign( - &**keystore, + let result = keystore.sr25519_vrf_sign( AuthorityId::ID, authority_id.as_ref(), transcript_data, @@ -169,10 +168,7 @@ fn claim_secondary_slot( } else { None } - } else if Keystore::has_keys( - &**keystore, - &[(authority_id.to_raw_vec(), AuthorityId::ID)], - ) { + } else if keystore.has_keys(&[(authority_id.to_raw_vec(), AuthorityId::ID)]) { Some(PreDigest::SecondaryPlain(SecondaryPlainPreDigest { slot, authority_index: *authority_index as u32, @@ -254,12 +250,8 @@ 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); - let result = Keystore::sr25519_vrf_sign( - &**keystore, - AuthorityId::ID, - authority_id.as_ref(), - transcript_data, - ); + let result = + keystore.sr25519_vrf_sign(AuthorityId::ID, authority_id.as_ref(), transcript_data); if let Ok(Some(signature)) = result { let public = PublicKey::from_bytes(&authority_id.to_raw_vec()).ok()?; let inout = match signature.output.attach_input_hash(&public, transcript) { @@ -287,20 +279,16 @@ fn claim_primary_slot( #[cfg(test)] mod tests { use super::*; - use sc_keystore::LocalKeystore; use sp_consensus_babe::{AllowedSlots, AuthorityId, BabeEpochConfiguration}; use sp_core::{crypto::Pair as _, sr25519::Pair}; - use std::sync::Arc; + use sp_keystore::testing::MemoryKeystore; #[test] fn claim_secondary_plain_slot_works() { - let keystore: KeystorePtr = Arc::new(LocalKeystore::in_memory()); - let valid_public_key = Keystore::sr25519_generate_new( - &*keystore, - AuthorityId::ID, - Some(sp_core::crypto::DEV_PHRASE), - ) - .unwrap(); + let keystore: KeystorePtr = MemoryKeystore::new().into(); + let valid_public_key = keystore + .sr25519_generate_new(AuthorityId::ID, Some(sp_core::crypto::DEV_PHRASE)) + .unwrap(); let authorities = vec![ (AuthorityId::from(Pair::generate().0.public()), 5), diff --git a/client/consensus/babe/src/lib.rs b/client/consensus/babe/src/lib.rs index 621aac391630b..e2c2793b11c9d 100644 --- a/client/consensus/babe/src/lib.rs +++ b/client/consensus/babe/src/lib.rs @@ -119,7 +119,7 @@ use sp_consensus_babe::inherents::BabeInherentData; use sp_consensus_slots::Slot; use sp_core::{crypto::ByteArray, ExecutionContext}; use sp_inherents::{CreateInherentDataProviders, InherentData, InherentDataProvider}; -use sp_keystore::{Keystore, KeystorePtr}; +use sp_keystore::KeystorePtr; use sp_runtime::{ generic::OpaqueDigestItemId, traits::{Block as BlockT, Header, NumberFor, SaturatedConversion, Zero}, @@ -834,19 +834,16 @@ where // add it to a digest item. let public_type_pair = public.clone().into(); let public = public.to_raw_vec(); - let signature = Keystore::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 = self + .keystore + .sign_with(::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() diff --git a/client/consensus/babe/src/tests.rs b/client/consensus/babe/src/tests.rs index 4ac15bf2634d7..7f8448d91991c 100644 --- a/client/consensus/babe/src/tests.rs +++ b/client/consensus/babe/src/tests.rs @@ -369,10 +369,11 @@ async fn rejects_empty_block() { } fn create_keystore(authority: Sr25519Keyring) -> KeystorePtr { - let keystore = Arc::new(MemoryKeystore::new()); - Keystore::sr25519_generate_new(&*keystore, BABE, Some(&authority.to_seed())) - .expect("Generates authority key"); + let keystore = MemoryKeystore::new(); keystore + .sr25519_generate_new(BABE, Some(&authority.to_seed())) + .expect("Generates authority key"); + keystore.into() } async fn run_one_test(mutator: impl Fn(&mut TestHeader, Stage) + Send + Sync + 'static) { @@ -637,7 +638,8 @@ fn claim_vrf_check() { v => panic!("Unexpected pre-digest variant {:?}", v), }; let transcript = make_transcript_data(&epoch.randomness.clone(), 0.into(), epoch.epoch_index); - let sign = Keystore::sr25519_vrf_sign(&*keystore, AuthorityId::ID, &public, transcript) + let sign = keystore + .sr25519_vrf_sign(AuthorityId::ID, &public, transcript) .unwrap() .unwrap(); assert_eq!(pre_digest.vrf_output, VRFOutput(sign.output)); @@ -648,7 +650,8 @@ fn claim_vrf_check() { v => panic!("Unexpected pre-digest variant {:?}", v), }; let transcript = make_transcript_data(&epoch.randomness.clone(), 1.into(), epoch.epoch_index); - let sign = Keystore::sr25519_vrf_sign(&*keystore, AuthorityId::ID, &public, transcript) + let sign = keystore + .sr25519_vrf_sign(AuthorityId::ID, &public, transcript) .unwrap() .unwrap(); assert_eq!(pre_digest.vrf_output, VRFOutput(sign.output)); @@ -661,7 +664,8 @@ fn claim_vrf_check() { }; let fixed_epoch = epoch.clone_for_slot(slot); let transcript = make_transcript_data(&epoch.randomness.clone(), slot, fixed_epoch.epoch_index); - let sign = Keystore::sr25519_vrf_sign(&*keystore, AuthorityId::ID, &public, transcript) + let sign = keystore + .sr25519_vrf_sign(AuthorityId::ID, &public, transcript) .unwrap() .unwrap(); assert_eq!(fixed_epoch.epoch_index, 11); @@ -675,7 +679,8 @@ fn claim_vrf_check() { }; let fixed_epoch = epoch.clone_for_slot(slot); let transcript = make_transcript_data(&epoch.randomness.clone(), slot, fixed_epoch.epoch_index); - let sign = Keystore::sr25519_vrf_sign(&*keystore, AuthorityId::ID, &public, transcript) + let sign = keystore + .sr25519_vrf_sign(AuthorityId::ID, &public, transcript) .unwrap() .unwrap(); assert_eq!(fixed_epoch.epoch_index, 11); diff --git a/client/consensus/beefy/src/communication/gossip.rs b/client/consensus/beefy/src/communication/gossip.rs index 4bbd7a7f68d5c..2b5e772c0578f 100644 --- a/client/consensus/beefy/src/communication/gossip.rs +++ b/client/consensus/beefy/src/communication/gossip.rs @@ -243,17 +243,14 @@ where #[cfg(test)] mod tests { - use sc_keystore::LocalKeystore; - use sc_network_test::Block; - use sp_keystore::{Keystore, KeystorePtr}; - + use super::*; use crate::keystore::BeefyKeystore; + use sc_network_test::Block; use sp_consensus_beefy::{ crypto::Signature, known_payloads, Commitment, Keyring, MmrRootHash, Payload, VoteMessage, KEY_TYPE, }; - - use super::*; + use sp_keystore::{testing::MemoryKeystore, Keystore}; #[test] fn known_votes_insert_remove() { @@ -306,10 +303,9 @@ mod tests { } fn sign_commitment(who: &Keyring, commitment: &Commitment) -> Signature { - let store: KeystorePtr = std::sync::Arc::new(LocalKeystore::in_memory()); - Keystore::ecdsa_generate_new(&*store, KEY_TYPE, Some(&who.to_seed())).unwrap(); - let beefy_keystore: BeefyKeystore = Some(store).into(); - + let store = MemoryKeystore::new(); + store.ecdsa_generate_new(KEY_TYPE, Some(&who.to_seed())).unwrap(); + let beefy_keystore: BeefyKeystore = Some(store.into()).into(); beefy_keystore.sign(&who.public(), &commitment.encode()).unwrap() } diff --git a/client/consensus/beefy/src/keystore.rs b/client/consensus/beefy/src/keystore.rs index 596e8f2eb9c6d..795d4cc8ade10 100644 --- a/client/consensus/beefy/src/keystore.rs +++ b/client/consensus/beefy/src/keystore.rs @@ -18,7 +18,7 @@ use sp_application_crypto::RuntimeAppPublic; use sp_core::keccak_256; -use sp_keystore::{Keystore, KeystorePtr}; +use sp_keystore::KeystorePtr; use log::warn; @@ -50,7 +50,7 @@ impl BeefyKeystore { // we do check for multiple private keys as a key store sanity check. let public: Vec = keys .iter() - .filter(|k| Keystore::has_keys(&*store, &[(k.to_raw_vec(), KEY_TYPE)])) + .filter(|k| store.has_keys(&[(k.to_raw_vec(), KEY_TYPE)])) .cloned() .collect(); @@ -77,7 +77,8 @@ impl BeefyKeystore { let msg = keccak_256(message); let public = public.as_ref(); - let sig = Keystore::ecdsa_sign_prehashed(&*store, KEY_TYPE, public, &msg) + let sig = store + .ecdsa_sign_prehashed(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()))?; @@ -94,10 +95,8 @@ impl BeefyKeystore { 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 = Keystore::ecdsa_public_keys(&*store, KEY_TYPE) - .drain(..) - .map(Public::from) - .collect(); + let pk: Vec = + store.ecdsa_public_keys(KEY_TYPE).drain(..).map(Public::from).collect(); Ok(pk) } @@ -118,18 +117,15 @@ impl From> for BeefyKeystore { #[cfg(test)] pub mod tests { - use std::sync::Arc; - - use sc_keystore::LocalKeystore; - use sp_core::{ecdsa, Pair}; - use sp_consensus_beefy::{crypto, Keyring}; + use sp_core::{ecdsa, Pair}; + use sp_keystore::testing::MemoryKeystore; use super::*; use crate::error::Error; fn keystore() -> KeystorePtr { - Arc::new(LocalKeystore::in_memory()) + MemoryKeystore::new().into() } #[test] @@ -197,11 +193,11 @@ pub mod tests { fn authority_id_works() { let store = keystore(); - let alice: crypto::Public = - Keystore::ecdsa_generate_new(&*store, KEY_TYPE, Some(&Keyring::Alice.to_seed())) - .ok() - .unwrap() - .into(); + let alice: crypto::Public = store + .ecdsa_generate_new(KEY_TYPE, Some(&Keyring::Alice.to_seed())) + .ok() + .unwrap() + .into(); let bob = Keyring::Bob.public(); let charlie = Keyring::Charlie.public(); @@ -223,11 +219,11 @@ pub mod tests { fn sign_works() { let store = keystore(); - let alice: crypto::Public = - Keystore::ecdsa_generate_new(&*store, KEY_TYPE, Some(&Keyring::Alice.to_seed())) - .ok() - .unwrap() - .into(); + let alice: crypto::Public = store + .ecdsa_generate_new(KEY_TYPE, Some(&Keyring::Alice.to_seed())) + .ok() + .unwrap() + .into(); let store: BeefyKeystore = Some(store).into(); @@ -243,9 +239,7 @@ pub mod tests { fn sign_error() { let store = keystore(); - let _ = Keystore::ecdsa_generate_new(&*store, KEY_TYPE, Some(&Keyring::Bob.to_seed())) - .ok() - .unwrap(); + store.ecdsa_generate_new(KEY_TYPE, Some(&Keyring::Bob.to_seed())).ok().unwrap(); let store: BeefyKeystore = Some(store).into(); @@ -274,11 +268,11 @@ pub mod tests { fn verify_works() { let store = keystore(); - let alice: crypto::Public = - Keystore::ecdsa_generate_new(&*store, KEY_TYPE, Some(&Keyring::Alice.to_seed())) - .ok() - .unwrap() - .into(); + let alice: crypto::Public = store + .ecdsa_generate_new(KEY_TYPE, Some(&Keyring::Alice.to_seed())) + .ok() + .unwrap() + .into(); let store: BeefyKeystore = Some(store).into(); @@ -300,9 +294,8 @@ pub mod tests { let store = keystore(); - let add_key = |key_type, seed: Option<&str>| { - Keystore::ecdsa_generate_new(&*store, key_type, seed).unwrap() - }; + let add_key = + |key_type, seed: Option<&str>| store.ecdsa_generate_new(key_type, seed).unwrap(); // test keys let _ = add_key(TEST_TYPE, Some(Keyring::Alice.to_seed().as_str())); diff --git a/client/consensus/beefy/src/tests.rs b/client/consensus/beefy/src/tests.rs index 9a3653f7cc549..0ad5f10886093 100644 --- a/client/consensus/beefy/src/tests.rs +++ b/client/consensus/beefy/src/tests.rs @@ -340,10 +340,11 @@ pub(crate) fn make_beefy_ids(keys: &[BeefyKeyring]) -> Vec { } pub(crate) fn create_beefy_keystore(authority: BeefyKeyring) -> KeystorePtr { - let keystore = Arc::new(MemoryKeystore::new()); - Keystore::ecdsa_generate_new(&*keystore, BeefyKeyType, Some(&authority.to_seed())) - .expect("Creates authority key"); + let keystore = MemoryKeystore::new(); keystore + .ecdsa_generate_new(BeefyKeyType, Some(&authority.to_seed())) + .expect("Creates authority key"); + keystore.into() } async fn voter_init_setup( diff --git a/client/consensus/grandpa/src/lib.rs b/client/consensus/grandpa/src/lib.rs index 6b3730fc7f476..cf98e17920d5d 100644 --- a/client/consensus/grandpa/src/lib.rs +++ b/client/consensus/grandpa/src/lib.rs @@ -79,7 +79,7 @@ use sp_consensus_grandpa::{ AuthorityList, AuthoritySignature, SetId, CLIENT_LOG_TARGET as LOG_TARGET, }; use sp_core::{crypto::ByteArray, traits::CallContext}; -use sp_keystore::{Keystore, KeystorePtr}; +use sp_keystore::KeystorePtr; use sp_runtime::{ generic::BlockId, traits::{Block as BlockT, NumberFor, Zero}, @@ -1141,7 +1141,7 @@ fn local_authority_id( keystore.and_then(|keystore| { voters .iter() - .find(|(p, _)| Keystore::has_keys(&**keystore, &[(p.to_raw_vec(), AuthorityId::ID)])) + .find(|(p, _)| keystore.has_keys(&[(p.to_raw_vec(), AuthorityId::ID)])) .map(|(p, _)| p.clone()) }) } diff --git a/client/consensus/grandpa/src/tests.rs b/client/consensus/grandpa/src/tests.rs index 6f19ca7391e65..7a3f862d3602b 100644 --- a/client/consensus/grandpa/src/tests.rs +++ b/client/consensus/grandpa/src/tests.rs @@ -281,10 +281,11 @@ fn make_ids(keys: &[Ed25519Keyring]) -> AuthorityList { } fn create_keystore(authority: Ed25519Keyring) -> KeystorePtr { - let keystore = Arc::new(MemoryKeystore::new()); - Keystore::ed25519_generate_new(&*keystore, GRANDPA, Some(&authority.to_seed())) - .expect("Creates authority key"); + let keystore = MemoryKeystore::new(); keystore + .ed25519_generate_new(GRANDPA, Some(&authority.to_seed())) + .expect("Creates authority key"); + keystore.into() } async fn run_until_complete(future: impl Future + Unpin, net: &Arc>) { diff --git a/client/keystore/src/local.rs b/client/keystore/src/local.rs index 18ee58b8719b9..a4af7811721ce 100644 --- a/client/keystore/src/local.rs +++ b/client/keystore/src/local.rs @@ -135,6 +135,9 @@ impl Keystore for LocalKeystore { .unwrap_or_default() } + /// Generate a new pair compatible with the 'ed25519' signature scheme. + /// + /// If the `[seed]` is `Some` then the key will be ephemeral and stored in memory. fn sr25519_generate_new( &self, id: KeyTypeId, @@ -162,6 +165,9 @@ impl Keystore for LocalKeystore { .unwrap_or_default() } + /// Generate a new pair compatible with the 'sr25519' signature scheme. + /// + /// If the `[seed]` is `Some` then the key will be ephemeral and stored in memory. fn ed25519_generate_new( &self, id: KeyTypeId, @@ -189,6 +195,9 @@ impl Keystore for LocalKeystore { .unwrap_or_default() } + /// Generate a new pair compatible with the 'ecdsa' signature scheme. + /// + /// If the `[seed]` is `Some` then the key will be ephemeral and stored in memory. fn ecdsa_generate_new( &self, id: KeyTypeId, @@ -504,17 +513,14 @@ mod tests { let key: ed25519::AppPair = store.0.write().generate().unwrap(); let key2 = ed25519::Pair::generate().0; - assert!(!Keystore::has_keys(&store, &[(key2.public().to_vec(), ed25519::AppPublic::ID)])); + assert!(!store.has_keys(&[(key2.public().to_vec(), ed25519::AppPublic::ID)])); - assert!(!Keystore::has_keys( - &store, - &[ - (key2.public().to_vec(), ed25519::AppPublic::ID), - (key.public().to_raw_vec(), ed25519::AppPublic::ID), - ], - )); + assert!(!store.has_keys(&[ + (key2.public().to_vec(), ed25519::AppPublic::ID), + (key.public().to_raw_vec(), ed25519::AppPublic::ID), + ],)); - assert!(Keystore::has_keys(&store, &[(key.public().to_raw_vec(), ed25519::AppPublic::ID)])); + assert!(store.has_keys(&[(key.public().to_raw_vec(), ed25519::AppPublic::ID)])); } #[test] @@ -626,31 +632,30 @@ mod tests { let file_name = temp_dir.path().join(array_bytes::bytes2hex("", &SR25519.0[..2])); fs::write(file_name, "test").expect("Invalid file is written"); - assert!(Keystore::sr25519_public_keys(&store, SR25519).is_empty()); + assert!(store.sr25519_public_keys(SR25519).is_empty()); } #[test] fn generate_with_seed_is_not_stored() { let temp_dir = TempDir::new().unwrap(); let store = LocalKeystore::open(temp_dir.path(), None).unwrap(); - let _alice_tmp_key = - Keystore::sr25519_generate_new(&store, TEST_KEY_TYPE, Some("//Alice")).unwrap(); + let _alice_tmp_key = store.sr25519_generate_new(TEST_KEY_TYPE, Some("//Alice")).unwrap(); - assert_eq!(Keystore::sr25519_public_keys(&store, TEST_KEY_TYPE).len(), 1); + assert_eq!(store.sr25519_public_keys(TEST_KEY_TYPE).len(), 1); drop(store); let store = LocalKeystore::open(temp_dir.path(), None).unwrap(); - assert_eq!(Keystore::sr25519_public_keys(&store, TEST_KEY_TYPE).len(), 0); + assert_eq!(store.sr25519_public_keys(TEST_KEY_TYPE).len(), 0); } #[test] fn generate_can_be_fetched_in_memory() { let store = LocalKeystore::in_memory(); - Keystore::sr25519_generate_new(&store, TEST_KEY_TYPE, Some("//Alice")).unwrap(); + store.sr25519_generate_new(TEST_KEY_TYPE, Some("//Alice")).unwrap(); - assert_eq!(Keystore::sr25519_public_keys(&store, TEST_KEY_TYPE).len(), 1); - Keystore::sr25519_generate_new(&store, TEST_KEY_TYPE, None).unwrap(); - assert_eq!(Keystore::sr25519_public_keys(&store, TEST_KEY_TYPE).len(), 2); + assert_eq!(store.sr25519_public_keys(TEST_KEY_TYPE).len(), 1); + store.sr25519_generate_new(TEST_KEY_TYPE, None).unwrap(); + assert_eq!(store.sr25519_public_keys(TEST_KEY_TYPE).len(), 2); } #[test] @@ -661,7 +666,7 @@ mod tests { let temp_dir = TempDir::new().unwrap(); let store = LocalKeystore::open(temp_dir.path(), None).unwrap(); - let public = Keystore::sr25519_generate_new(&store, TEST_KEY_TYPE, None).unwrap(); + let public = store.sr25519_generate_new(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(); diff --git a/client/rpc/src/author/mod.rs b/client/rpc/src/author/mod.rs index 9752a32b17c67..00a126500e26d 100644 --- a/client/rpc/src/author/mod.rs +++ b/client/rpc/src/author/mod.rs @@ -40,7 +40,7 @@ use sc_transaction_pool_api::{ use sp_api::ProvideRuntimeApi; use sp_blockchain::HeaderBackend; use sp_core::Bytes; -use sp_keystore::{Keystore, KeystorePtr}; +use sp_keystore::KeystorePtr; use sp_runtime::{generic, traits::Block as BlockT}; use sp_session::SessionKeys; @@ -112,7 +112,8 @@ where self.deny_unsafe.check_if_safe()?; let key_type = key_type.as_str().try_into().map_err(|_| Error::BadKeyType)?; - Keystore::insert(&*self.keystore, key_type, &suri, &public[..]) + self.keystore + .insert(key_type, &suri, &public[..]) .map_err(|_| Error::KeystoreUnavailable)?; Ok(()) } @@ -139,14 +140,14 @@ where .map_err(|e| Error::Client(Box::new(e)))? .ok_or(Error::InvalidSessionKeys)?; - Ok(Keystore::has_keys(&*self.keystore, &keys)) + Ok(self.keystore.has_keys(&keys)) } 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(Keystore::has_keys(&*self.keystore, &[(public_key.to_vec(), key_type)])) + Ok(self.keystore.has_keys(&[(public_key.to_vec(), key_type)])) } fn pending_extrinsics(&self) -> RpcResult> { diff --git a/client/rpc/src/author/tests.rs b/client/rpc/src/author/tests.rs index 209673fce2602..75b6390c83cc7 100644 --- a/client/rpc/src/author/tests.rs +++ b/client/rpc/src/author/tests.rs @@ -36,7 +36,7 @@ use sp_core::{ testing::{ED25519, SR25519}, H256, }; -use sp_keystore::testing::MemoryKeystore; +use sp_keystore::{testing::MemoryKeystore, Keystore}; use std::sync::Arc; use substrate_test_runtime_client::{ self, @@ -225,7 +225,7 @@ async fn author_should_insert_key() { keypair.public().0.to_vec().into(), ); api.call::<_, ()>("author_insertKey", params).await.unwrap(); - let pubkeys = Keystore::keys(&*setup.keystore, ED25519).unwrap(); + let pubkeys = setup.keystore.keys(ED25519).unwrap(); assert!( pubkeys.contains(&CryptoTypePublicPair(ed25519::CRYPTO_ID, keypair.public().to_raw_vec())) @@ -240,8 +240,8 @@ async fn author_should_rotate_keys() { let new_pubkeys: Bytes = api.call("author_rotateKeys", EmptyParams::new()).await.unwrap(); let session_keys = SessionKeys::decode(&mut &new_pubkeys[..]).expect("SessionKeys decode successfully"); - let ed25519_pubkeys = Keystore::keys(&*setup.keystore, ED25519).unwrap(); - let sr25519_pubkeys = Keystore::keys(&*setup.keystore, SR25519).unwrap(); + let ed25519_pubkeys = setup.keystore.keys(ED25519).unwrap(); + let sr25519_pubkeys = setup.keystore.keys(SR25519).unwrap(); assert!(ed25519_pubkeys .contains(&CryptoTypePublicPair(ed25519::CRYPTO_ID, session_keys.ed25519.to_raw_vec()))); assert!(sr25519_pubkeys diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index 034d056d6f66f..bee40e9a3da0c 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -67,7 +67,7 @@ use sp_consensus::block_validation::{ BlockAnnounceValidator, Chain, DefaultBlockAnnounceValidator, }; use sp_core::traits::{CodeExecutor, SpawnNamed}; -use sp_keystore::{Keystore, KeystorePtr}; +use sp_keystore::KeystorePtr; use sp_runtime::traits::{Block as BlockT, BlockIdTo, NumberFor, Zero}; use std::{str::FromStr, sync::Arc, time::SystemTime}; @@ -85,24 +85,8 @@ pub type TFullCallExecutor = type TFullParts = (TFullClient, Arc>, KeystoreContainer, TaskManager); -trait AsKeystoreRef { - fn keystore_ref(&self) -> Arc; -} - -impl AsKeystoreRef for Arc -where - T: Keystore + 'static, -{ - fn keystore_ref(&self) -> Arc { - self.clone() - } -} - -/// Construct and hold different layers of Keystore wrappers -pub struct KeystoreContainer { - remote: Option>, - local: Arc, -} +/// Construct a local keystore shareable container +pub struct KeystoreContainer(Arc); impl KeystoreContainer { /// Construct KeystoreContainer @@ -113,41 +97,17 @@ impl KeystoreContainer { KeystoreConfig::InMemory => LocalKeystore::in_memory(), }); - Ok(Self { remote: Default::default(), local: keystore }) + Ok(Self(keystore)) } - /// Set the remote keystore. - /// Should be called right away at startup and not at runtime: - /// even though this overrides any previously set remote store, it - /// does not reset any references previously handed out - they will - /// stick around. - pub fn set_remote_keystore(&mut self, remote: Arc) - where - T: Keystore + 'static, - { - self.remote = Some(Box::new(remote)) + /// Returns a shared reference to a dynamic `Keystore` trait implementation. + pub fn keystore(&self) -> KeystorePtr { + self.0.clone() } - /// Returns an adapter to a `Keystore` implementation. - pub fn keystore(&self) -> Arc { - if let Some(c) = self.remote.as_ref() { - c.keystore_ref() - } else { - self.local.clone() - } - } - - /// Returns the local keystore if available - /// - /// The function will return None if the available keystore is not a local keystore. - /// - /// # Note - /// - /// Using the [`LocalKeystore`] will result in loosing the ability to use any other keystore - /// implementation, like a remote keystore for example. Only use this if you a certain that you - /// require it! - pub fn local_keystore(&self) -> Option> { - Some(self.local.clone()) + /// Returns a shared reference to the local keystore . + pub fn local_keystore(&self) -> Arc { + self.0.clone() } } diff --git a/client/service/src/config.rs b/client/service/src/config.rs index c7d98a4533436..6550fcdd8ef4f 100644 --- a/client/service/src/config.rs +++ b/client/service/src/config.rs @@ -61,8 +61,6 @@ pub struct Configuration { pub network: NetworkConfiguration, /// Configuration for the keystore. pub keystore: KeystoreConfig, - /// Remote URI to connect to for async keystore support - pub keystore_remote: Option, /// Configuration for the database. pub database: DatabaseSource, /// Maximum size of internal trie cache in bytes. diff --git a/client/service/test/src/lib.rs b/client/service/test/src/lib.rs index f80446a4d43eb..8a2e5050bd5d3 100644 --- a/client/service/test/src/lib.rs +++ b/client/service/test/src/lib.rs @@ -242,7 +242,6 @@ fn node_config< tokio_handle, transaction_pool: Default::default(), network: network_config, - keystore_remote: Default::default(), keystore: KeystoreConfig::Path { path: root.join("key"), password: None }, database: DatabaseSource::RocksDb { path: root.join("db"), cache_size: 128 }, trie_cache_maximum_size: Some(16 * 1024 * 1024), diff --git a/frame/benchmarking/src/baseline.rs b/frame/benchmarking/src/baseline.rs index 1f6e9c5a68892..25336b6974d9f 100644 --- a/frame/benchmarking/src/baseline.rs +++ b/frame/benchmarking/src/baseline.rs @@ -160,12 +160,11 @@ pub mod mock { impl super::Config for Test {} pub fn new_test_ext() -> sp_io::TestExternalities { - use sp_keystore::{testing::MemoryKeystore, KeystoreExt, KeystorePtr}; - use sp_std::sync::Arc; + use sp_keystore::{testing::MemoryKeystore, KeystoreExt}; let t = frame_system::GenesisConfig::default().build_storage::().unwrap(); let mut ext = sp_io::TestExternalities::new(t); - ext.register_extension(KeystoreExt(Arc::new(MemoryKeystore::new()) as KeystorePtr)); + ext.register_extension(KeystoreExt::new(MemoryKeystore::new())); ext } diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index 185945b71e5be..915a56a3f056c 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -50,7 +50,7 @@ use sp_runtime::{ traits::{BlakeTwo256, Convert, Hash, IdentityLookup}, AccountId32, TokenError, }; -use std::{ops::Deref, sync::Arc}; +use std::ops::Deref; use crate as pallet_contracts; @@ -444,7 +444,7 @@ impl ExtBuilder { .assimilate_storage(&mut t) .unwrap(); let mut ext = sp_io::TestExternalities::new(t); - ext.register_extension(KeystoreExt(Arc::new(MemoryKeystore::new()))); + ext.register_extension(KeystoreExt::new(MemoryKeystore::new())); ext.execute_with(|| System::set_block_number(1)); ext } diff --git a/frame/examples/offchain-worker/src/tests.rs b/frame/examples/offchain-worker/src/tests.rs index c513590435252..3df7f4a8d5439 100644 --- a/frame/examples/offchain-worker/src/tests.rs +++ b/frame/examples/offchain-worker/src/tests.rs @@ -27,7 +27,6 @@ use sp_core::{ sr25519::Signature, H256, }; -use std::sync::Arc; use sp_keystore::{testing::MemoryKeystore, Keystore, KeystoreExt}; use sp_runtime::{ @@ -206,17 +205,14 @@ fn should_submit_signed_transaction_on_chain() { let (offchain, offchain_state) = testing::TestOffchainExt::new(); let (pool, pool_state) = testing::TestTransactionPoolExt::new(); let keystore = MemoryKeystore::new(); - Keystore::sr25519_generate_new( - &keystore, - crate::crypto::Public::ID, - Some(&format!("{}/hunter1", PHRASE)), - ) - .unwrap(); + keystore + .sr25519_generate_new(crate::crypto::Public::ID, Some(&format!("{}/hunter1", PHRASE))) + .unwrap(); let mut t = sp_io::TestExternalities::default(); t.register_extension(OffchainWorkerExt::new(offchain)); t.register_extension(TransactionPoolExt::new(pool)); - t.register_extension(KeystoreExt(Arc::new(keystore))); + t.register_extension(KeystoreExt::new(keystore)); price_oracle_response(&mut offchain_state.write()); @@ -241,21 +237,16 @@ fn should_submit_unsigned_transaction_on_chain_for_any_account() { let keystore = MemoryKeystore::new(); - Keystore::sr25519_generate_new( - &keystore, - crate::crypto::Public::ID, - Some(&format!("{}/hunter1", PHRASE)), - ) - .unwrap(); - - let public_key = *Keystore::sr25519_public_keys(&keystore, crate::crypto::Public::ID) - .get(0) + keystore + .sr25519_generate_new(crate::crypto::Public::ID, Some(&format!("{}/hunter1", PHRASE))) .unwrap(); + let public_key = *keystore.sr25519_public_keys(crate::crypto::Public::ID).get(0).unwrap(); + let mut t = sp_io::TestExternalities::default(); t.register_extension(OffchainWorkerExt::new(offchain)); t.register_extension(TransactionPoolExt::new(pool)); - t.register_extension(KeystoreExt(Arc::new(keystore))); + t.register_extension(KeystoreExt::new(keystore)); price_oracle_response(&mut offchain_state.write()); @@ -300,21 +291,16 @@ fn should_submit_unsigned_transaction_on_chain_for_all_accounts() { let keystore = MemoryKeystore::new(); - Keystore::sr25519_generate_new( - &keystore, - crate::crypto::Public::ID, - Some(&format!("{}/hunter1", PHRASE)), - ) - .unwrap(); - - let public_key = *Keystore::sr25519_public_keys(&keystore, crate::crypto::Public::ID) - .get(0) + keystore + .sr25519_generate_new(crate::crypto::Public::ID, Some(&format!("{}/hunter1", PHRASE))) .unwrap(); + let public_key = *keystore.sr25519_public_keys(crate::crypto::Public::ID).get(0).unwrap(); + let mut t = sp_io::TestExternalities::default(); t.register_extension(OffchainWorkerExt::new(offchain)); t.register_extension(TransactionPoolExt::new(pool)); - t.register_extension(KeystoreExt(Arc::new(keystore))); + t.register_extension(KeystoreExt::new(keystore)); price_oracle_response(&mut offchain_state.write()); @@ -360,7 +346,7 @@ fn should_submit_raw_unsigned_transaction_on_chain() { let mut t = sp_io::TestExternalities::default(); t.register_extension(OffchainWorkerExt::new(offchain)); t.register_extension(TransactionPoolExt::new(pool)); - t.register_extension(KeystoreExt(Arc::new(keystore))); + t.register_extension(KeystoreExt::new(keystore)); price_oracle_response(&mut offchain_state.write()); diff --git a/frame/nfts/src/mock.rs b/frame/nfts/src/mock.rs index 91ac5d6a72203..e2856a07b994c 100644 --- a/frame/nfts/src/mock.rs +++ b/frame/nfts/src/mock.rs @@ -31,7 +31,6 @@ use sp_runtime::{ traits::{BlakeTwo256, IdentifyAccount, IdentityLookup, Verify}, MultiSignature, }; -use std::sync::Arc; type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; type Block = frame_system::mocking::MockBlock; @@ -134,9 +133,8 @@ impl Config for Test { pub(crate) fn new_test_ext() -> sp_io::TestExternalities { let t = frame_system::GenesisConfig::default().build_storage::().unwrap(); - let keystore = MemoryKeystore::new(); let mut ext = sp_io::TestExternalities::new(t); - ext.register_extension(KeystoreExt(Arc::new(keystore))); + ext.register_extension(KeystoreExt::new(MemoryKeystore::new())); ext.execute_with(|| System::set_block_number(1)); ext } diff --git a/primitives/application-crypto/test/src/ecdsa.rs b/primitives/application-crypto/test/src/ecdsa.rs index 7b96b42d5556b..fe9e17a65b1a7 100644 --- a/primitives/application-crypto/test/src/ecdsa.rs +++ b/primitives/application-crypto/test/src/ecdsa.rs @@ -34,7 +34,7 @@ fn ecdsa_works_in_runtime() { .test_ecdsa_crypto(test_client.chain_info().genesis_hash) .expect("Tests `ecdsa` crypto."); - let supported_keys = Keystore::keys(&*keystore, ECDSA).unwrap(); + let supported_keys = keystore.keys(ECDSA).unwrap(); assert!(supported_keys.contains(&public.clone().into())); assert!(AppPair::verify(&signature, "ecdsa", &AppPublic::from(public))); } diff --git a/primitives/application-crypto/test/src/ed25519.rs b/primitives/application-crypto/test/src/ed25519.rs index 1cf2b574b6bfb..5687bd013970a 100644 --- a/primitives/application-crypto/test/src/ed25519.rs +++ b/primitives/application-crypto/test/src/ed25519.rs @@ -35,7 +35,7 @@ fn ed25519_works_in_runtime() { .test_ed25519_crypto(test_client.chain_info().genesis_hash) .expect("Tests `ed25519` crypto."); - let supported_keys = Keystore::keys(&*keystore, ED25519).unwrap(); + let supported_keys = keystore.keys(ED25519).unwrap(); assert!(supported_keys.contains(&public.clone().into())); assert!(AppPair::verify(&signature, "ed25519", &AppPublic::from(public))); } diff --git a/primitives/application-crypto/test/src/sr25519.rs b/primitives/application-crypto/test/src/sr25519.rs index aa8f75c0dc27a..92886b80cbfb3 100644 --- a/primitives/application-crypto/test/src/sr25519.rs +++ b/primitives/application-crypto/test/src/sr25519.rs @@ -35,7 +35,7 @@ fn sr25519_works_in_runtime() { .test_sr25519_crypto(test_client.chain_info().genesis_hash) .expect("Tests `sr25519` crypto."); - let supported_keys = Keystore::keys(&*keystore, SR25519).unwrap(); + let supported_keys = keystore.keys(SR25519).unwrap(); assert!(supported_keys.contains(&public.clone().into())); assert!(AppPair::verify(&signature, "sr25519", &AppPublic::from(public))); } diff --git a/primitives/consensus/beefy/src/commitment.rs b/primitives/consensus/beefy/src/commitment.rs index 6ae17b06d96a4..8ad3cc3721a00 100644 --- a/primitives/consensus/beefy/src/commitment.rs +++ b/primitives/consensus/beefy/src/commitment.rs @@ -253,7 +253,7 @@ mod tests { use crate::{crypto, known_payloads, KEY_TYPE}; use codec::Decode; use sp_core::{keccak_256, Pair}; - use sp_keystore::{testing::MemoryKeystore, Keystore, KeystorePtr}; + use sp_keystore::{testing::MemoryKeystore, KeystorePtr}; type TestCommitment = Commitment; type TestSignedCommitment = SignedCommitment; @@ -266,17 +266,13 @@ mod tests { let store: KeystorePtr = MemoryKeystore::new().into(); let alice = sp_core::ecdsa::Pair::from_string("//Alice", None).unwrap(); - let _ = Keystore::insert(&*store, KEY_TYPE, "//Alice", alice.public().as_ref()).unwrap(); + store.insert(KEY_TYPE, "//Alice", alice.public().as_ref()).unwrap(); let msg = keccak_256(b"This is the first message"); - let sig1 = Keystore::ecdsa_sign_prehashed(&*store, KEY_TYPE, &alice.public(), &msg) - .unwrap() - .unwrap(); + let sig1 = store.ecdsa_sign_prehashed(KEY_TYPE, &alice.public(), &msg).unwrap().unwrap(); let msg = keccak_256(b"This is the second message"); - let sig2 = Keystore::ecdsa_sign_prehashed(&*store, KEY_TYPE, &alice.public(), &msg) - .unwrap() - .unwrap(); + let sig2 = store.ecdsa_sign_prehashed(KEY_TYPE, &alice.public(), &msg).unwrap().unwrap(); (sig1.into(), sig2.into()) } diff --git a/primitives/consensus/beefy/src/witness.rs b/primitives/consensus/beefy/src/witness.rs index 70b924c0a42fe..ff9a0401dc632 100644 --- a/primitives/consensus/beefy/src/witness.rs +++ b/primitives/consensus/beefy/src/witness.rs @@ -74,9 +74,8 @@ impl SignedCommitmentWitness Vec { - let keystore = &***self - .extension::() - .expect("No `keystore` associated for the current context!"); - Keystore::ed25519_public_keys(keystore, id) + self.extension::() + .expect("No `keystore` associated for the current context!") + .ed25519_public_keys(id) } /// Generate an `ed22519` key for the given key type using an optional `seed` and @@ -745,10 +744,10 @@ 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 keystore = &***self - .extension::() - .expect("No `keystore` associated for the current context!"); - Keystore::ed25519_generate_new(keystore, id, seed).expect("`ed25519_generate` failed") + self.extension::() + .expect("No `keystore` associated for the current context!") + .ed25519_generate_new(id, seed) + .expect("`ed25519_generate` failed") } /// Sign the given `msg` with the `ed25519` key that corresponds to the given public key and @@ -761,10 +760,9 @@ pub trait Crypto { pub_key: &ed25519::Public, msg: &[u8], ) -> Option { - let keystore = &***self - .extension::() - .expect("No `keystore` associated for the current context!"); - Keystore::sign_with(keystore, id, &pub_key.into(), msg) + self.extension::() + .expect("No `keystore` associated for the current context!") + .sign_with(id, &pub_key.into(), msg) .ok() .flatten() .and_then(|sig| ed25519::Signature::from_slice(&sig)) @@ -873,10 +871,9 @@ pub trait Crypto { /// Returns all `sr25519` public keys for the given key id from the keystore. fn sr25519_public_keys(&mut self, id: KeyTypeId) -> Vec { - let keystore = &***self - .extension::() - .expect("No `keystore` associated for the current context!"); - Keystore::sr25519_public_keys(keystore, id) + self.extension::() + .expect("No `keystore` associated for the current context!") + .sr25519_public_keys(id) } /// Generate an `sr22519` key for the given key type using an optional seed and @@ -887,10 +884,10 @@ 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 keystore = &***self - .extension::() - .expect("No `keystore` associated for the current context!"); - Keystore::sr25519_generate_new(keystore, id, seed).expect("`sr25519_generate` failed") + self.extension::() + .expect("No `keystore` associated for the current context!") + .sr25519_generate_new(id, seed) + .expect("`sr25519_generate` failed") } /// Sign the given `msg` with the `sr25519` key that corresponds to the given public key and @@ -903,10 +900,9 @@ pub trait Crypto { pub_key: &sr25519::Public, msg: &[u8], ) -> Option { - let keystore = &***self - .extension::() - .expect("No `keystore` associated for the current context!"); - Keystore::sign_with(keystore, id, &pub_key.into(), msg) + self.extension::() + .expect("No `keystore` associated for the current context!") + .sign_with(id, &pub_key.into(), msg) .ok() .flatten() .and_then(|sig| sr25519::Signature::from_slice(&sig)) @@ -922,10 +918,9 @@ pub trait Crypto { /// Returns all `ecdsa` public keys for the given key id from the keystore. fn ecdsa_public_keys(&mut self, id: KeyTypeId) -> Vec { - let keystore = &***self - .extension::() - .expect("No `keystore` associated for the current context!"); - Keystore::ecdsa_public_keys(keystore, id) + self.extension::() + .expect("No `keystore` associated for the current context!") + .ecdsa_public_keys(id) } /// Generate an `ecdsa` key for the given key type using an optional `seed` and @@ -936,10 +931,10 @@ 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 keystore = &***self - .extension::() - .expect("No `keystore` associated for the current context!"); - Keystore::ecdsa_generate_new(keystore, id, seed).expect("`ecdsa_generate` failed") + self.extension::() + .expect("No `keystore` associated for the current context!") + .ecdsa_generate_new(id, seed) + .expect("`ecdsa_generate` failed") } /// Sign the given `msg` with the `ecdsa` key that corresponds to the given public key and @@ -952,10 +947,9 @@ pub trait Crypto { pub_key: &ecdsa::Public, msg: &[u8], ) -> Option { - let keystore = &***self - .extension::() - .expect("No `keystore` associated for the current context!"); - Keystore::sign_with(keystore, id, &pub_key.into(), msg) + self.extension::() + .expect("No `keystore` associated for the current context!") + .sign_with(id, &pub_key.into(), msg) .ok() .flatten() .and_then(|sig| ecdsa::Signature::from_slice(&sig)) @@ -971,10 +965,11 @@ pub trait Crypto { pub_key: &ecdsa::Public, msg: &[u8; 32], ) -> Option { - let keystore = &***self - .extension::() - .expect("No `keystore` associated for the current context!"); - Keystore::ecdsa_sign_prehashed(keystore, id, pub_key, msg).ok().flatten() + self.extension::() + .expect("No `keystore` associated for the current context!") + .ecdsa_sign_prehashed(id, pub_key, msg) + .ok() + .flatten() } /// Verify `ecdsa` signature. diff --git a/primitives/keystore/src/lib.rs b/primitives/keystore/src/lib.rs index e0c00967b6b5e..d1cbe227ed551 100644 --- a/primitives/keystore/src/lib.rs +++ b/primitives/keystore/src/lib.rs @@ -150,10 +150,17 @@ pub trait Keystore: Send + Sync { ) -> Result, Error>; } -/// A pointer to a keystore. +/// A shared pointer to a keystore implementation. pub type KeystorePtr = Arc; sp_externalities::decl_extension! { /// The keystore extension to register/retrieve from the externalities. pub struct KeystoreExt(KeystorePtr); } + +impl KeystoreExt { + /// Create a new instance of `KeystoreExt` + pub fn new(keystore: T) -> Self { + Self(Arc::new(keystore)) + } +} diff --git a/primitives/keystore/src/testing.rs b/primitives/keystore/src/testing.rs index fecc11342c464..73b560d563a17 100644 --- a/primitives/keystore/src/testing.rs +++ b/primitives/keystore/src/testing.rs @@ -304,9 +304,9 @@ mod tests { fn store_key_and_extract() { let store = MemoryKeystore::new(); - let public = Keystore::ed25519_generate_new(&store, ED25519, None).expect("Generates key"); + let public = store.ed25519_generate_new(ED25519, None).expect("Generates key"); - let public_keys = Keystore::keys(&store, ED25519).unwrap(); + let public_keys = store.keys(ED25519).unwrap(); assert!(public_keys.contains(&public.into())); } @@ -318,10 +318,11 @@ mod tests { let secret_uri = "//Alice"; let key_pair = sr25519::Pair::from_string(secret_uri, None).expect("Generates key pair"); - Keystore::insert(&store, SR25519, secret_uri, key_pair.public().as_ref()) + store + .insert(SR25519, secret_uri, key_pair.public().as_ref()) .expect("Inserts unknown key"); - let public_keys = Keystore::keys(&store, SR25519).unwrap(); + let public_keys = store.keys(SR25519).unwrap(); assert!(public_keys.contains(&key_pair.public().into())); } @@ -342,19 +343,14 @@ mod tests { ], }; - let result = Keystore::sr25519_vrf_sign( - &store, - SR25519, - &key_pair.public(), - transcript_data.clone(), - ); + let result = store.sr25519_vrf_sign(SR25519, &key_pair.public(), transcript_data.clone()); assert!(result.unwrap().is_none()); - Keystore::insert(&store, SR25519, secret_uri, key_pair.public().as_ref()) + store + .insert(SR25519, secret_uri, key_pair.public().as_ref()) .expect("Inserts unknown key"); - let result = - Keystore::sr25519_vrf_sign(&store, SR25519, &key_pair.public(), transcript_data); + let result = store.sr25519_vrf_sign(SR25519, &key_pair.public(), transcript_data); assert!(result.unwrap().is_some()); } @@ -369,13 +365,13 @@ mod tests { let msg = sp_core::keccak_256(b"this should be a hashed message"); // no key in key store - let res = Keystore::ecdsa_sign_prehashed(&store, ECDSA, &pair.public(), &msg).unwrap(); + let res = store.ecdsa_sign_prehashed(ECDSA, &pair.public(), &msg).unwrap(); assert!(res.is_none()); // insert key, sign again - Keystore::insert(&store, ECDSA, suri, pair.public().as_ref()).unwrap(); + store.insert(ECDSA, suri, pair.public().as_ref()).unwrap(); - let res = Keystore::ecdsa_sign_prehashed(&store, ECDSA, &pair.public(), &msg).unwrap(); + let res = store.ecdsa_sign_prehashed(ECDSA, &pair.public(), &msg).unwrap(); assert!(res.is_some()); } } diff --git a/utils/frame/benchmarking-cli/src/pallet/command.rs b/utils/frame/benchmarking-cli/src/pallet/command.rs index f11e6bd920abf..15ebc668ff4fb 100644 --- a/utils/frame/benchmarking-cli/src/pallet/command.rs +++ b/utils/frame/benchmarking-cli/src/pallet/command.rs @@ -38,10 +38,10 @@ use sp_core::{ traits::CallContext, }; use sp_externalities::Extensions; -use sp_keystore::{testing::MemoryKeystore, KeystoreExt, KeystorePtr}; +use sp_keystore::{testing::MemoryKeystore, KeystoreExt}; use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; use sp_state_machine::StateMachine; -use std::{collections::HashMap, fmt::Debug, fs, str::FromStr, sync::Arc, time}; +use std::{collections::HashMap, fmt::Debug, fs, str::FromStr, time}; /// Logging target const LOG_TARGET: &'static str = "frame::benchmark::pallet"; @@ -218,9 +218,10 @@ impl PalletCmd { let extensions = || -> Extensions { let mut extensions = Extensions::default(); - extensions.register(KeystoreExt(Arc::new(MemoryKeystore::new()) as KeystorePtr)); let (offchain, _) = TestOffchainExt::new(); let (pool, _) = TestTransactionPoolExt::new(); + let keystore = MemoryKeystore::new(); + extensions.register(KeystoreExt::new(keystore)); extensions.register(OffchainWorkerExt::new(offchain.clone())); extensions.register(OffchainDbExt::new(offchain)); extensions.register(TransactionPoolExt::new(pool)); diff --git a/utils/frame/try-runtime/cli/src/lib.rs b/utils/frame/try-runtime/cli/src/lib.rs index bd914d3a2e017..34966fc2a1197 100644 --- a/utils/frame/try-runtime/cli/src/lib.rs +++ b/utils/frame/try-runtime/cli/src/lib.rs @@ -816,9 +816,10 @@ pub(crate) fn full_extensions() -> Extensions { extensions.register(TaskExecutorExt::new(TaskExecutor::new())); let (offchain, _offchain_state) = TestOffchainExt::new(); let (pool, _pool_state) = TestTransactionPoolExt::new(); + let keystore = MemoryKeystore::new(); extensions.register(OffchainDbExt::new(offchain.clone())); extensions.register(OffchainWorkerExt::new(offchain)); - extensions.register(KeystoreExt(std::sync::Arc::new(MemoryKeystore::new()))); + extensions.register(KeystoreExt::new(keystore)); extensions.register(TransactionPoolExt::new(pool)); extensions From b8b8cce3400c4c157579404e17d4c623a83c3617 Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Mon, 20 Mar 2023 21:58:21 +0100 Subject: [PATCH 539/715] frame::executive: LOG_TARGET const added (#13650) part of: #12873 Co-authored-by: parity-processbot <> --- frame/executive/src/lib.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index 10cf6e06b3431..5003920eadcb5 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -137,6 +137,9 @@ use sp_runtime::{ }; use sp_std::{marker::PhantomData, prelude::*}; +#[allow(dead_code)] +const LOG_TARGET: &str = "runtime::executive"; + pub type CheckedOf = >::Checked; pub type CallOf = as Applyable>::Call; pub type OriginOf = as Dispatchable>::RuntimeOrigin; @@ -240,7 +243,7 @@ where select: frame_try_runtime::TryStateSelect, ) -> Result { frame_support::log::info!( - target: "frame::executive", + target: LOG_TARGET, "try-runtime: executing block #{:?} / state root check: {:?} / signature check: {:?} / try-state-select: {:?}", block.header().number(), state_root_check, @@ -277,7 +280,7 @@ where for e in extrinsics { if let Err(err) = try_apply_extrinsic(e.clone()) { frame_support::log::error!( - target: "runtime::executive", "executing transaction {:?} failed due to {:?}. Aborting the rest of the block execution.", + target: LOG_TARGET, "executing transaction {:?} failed due to {:?}. Aborting the rest of the block execution.", e, err, ); @@ -296,7 +299,7 @@ where select, ) .map_err(|e| { - frame_support::log::error!(target: "runtime::executive", "failure: {:?}", e); + frame_support::log::error!(target: LOG_TARGET, "failure: {:?}", e); e })?; drop(_guard); From 8f0b0f69e79c0dcf1487b9858792439c35a1d4cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Tue, 21 Mar 2023 00:09:22 +0100 Subject: [PATCH 540/715] contracts: Upgrade to wasmi 0.28 (#13312) * Upgrade to wasmi 0.28 * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_contracts * Update stale comment * Renamed variants of `Determinism` * Compile fix --------- Co-authored-by: command-bot <> --- Cargo.lock | 21 +- bin/node/runtime/src/lib.rs | 2 +- frame/contracts/Cargo.toml | 4 +- frame/contracts/proc-macro/src/lib.rs | 4 +- frame/contracts/src/benchmarking/code.rs | 2 +- frame/contracts/src/benchmarking/mod.rs | 12 +- frame/contracts/src/exec.rs | 74 +- frame/contracts/src/lib.rs | 12 +- frame/contracts/src/migration.rs | 4 +- frame/contracts/src/schedule.rs | 7 +- frame/contracts/src/tests.rs | 129 +- frame/contracts/src/wasm/mod.rs | 22 +- frame/contracts/src/wasm/prepare.rs | 70 +- frame/contracts/src/wasm/runtime.rs | 6 +- frame/contracts/src/weights.rs | 2362 +++++++++++----------- 15 files changed, 1338 insertions(+), 1393 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4928873566627..5306d2015b17b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5751,7 +5751,7 @@ dependencies = [ "sp-runtime", "sp-std", "wasm-instrument 0.4.0", - "wasmi 0.20.0", + "wasmi 0.28.0", "wasmparser-nostd", "wat", ] @@ -12188,13 +12188,13 @@ dependencies = [ [[package]] name = "wasmi" -version = "0.20.0" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01bf50edb2ea9d922aa75a7bf3c15e26a6c9e2d18c56e862b49737a582901729" +checksum = "8e61a7006b0fdf24f6bbe8dcfdad5ca1b350de80061fb2827f31c82fbbb9565a" dependencies = [ "spin 0.9.5", "wasmi_arena", - "wasmi_core 0.5.0", + "wasmi_core 0.12.0", "wasmparser-nostd", ] @@ -12209,9 +12209,9 @@ dependencies = [ [[package]] name = "wasmi_arena" -version = "0.1.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1ea379cbb0b41f3a9f0bf7b47036d036aae7f43383d8cc487d4deccf40dee0a" +checksum = "401c1f35e413fac1846d4843745589d9ec678977ab35a384db8ae7830525d468" [[package]] name = "wasmi_core" @@ -12229,13 +12229,14 @@ dependencies = [ [[package]] name = "wasmi_core" -version = "0.5.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5bf998ab792be85e20e771fe14182b4295571ad1d4f89d3da521c1bef5f597a" +checksum = "624e6333e861ef49095d2d678b76ebf30b06bf37effca845be7e5b87c90071b7" dependencies = [ "downcast-rs", "libm 0.2.6", "num-traits", + "paste", ] [[package]] @@ -12250,9 +12251,9 @@ dependencies = [ [[package]] name = "wasmparser-nostd" -version = "0.91.0" +version = "0.100.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c37f310b5a62bfd5ae7c0f1d8e6f98af16a5d6d84ba764e9c36439ec14e318b" +checksum = "9157cab83003221bfd385833ab587a039f5d6fa7304854042ba358a3b09e0724" dependencies = [ "indexmap-nostd", ] diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 3f0ea07122884..48bea5ddc101f 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -2147,7 +2147,7 @@ impl_runtime_apis! { storage_deposit_limit, input_data, true, - pallet_contracts::Determinism::Deterministic, + pallet_contracts::Determinism::Enforced, ) } diff --git a/frame/contracts/Cargo.toml b/frame/contracts/Cargo.toml index e19326b785b2b..f357a21b9cf5e 100644 --- a/frame/contracts/Cargo.toml +++ b/frame/contracts/Cargo.toml @@ -26,8 +26,8 @@ serde = { version = "1", optional = true, features = ["derive"] } smallvec = { version = "1", default-features = false, features = [ "const_generics", ] } -wasmi = { version = "0.20", default-features = false } -wasmparser = { package = "wasmparser-nostd", version = "0.91", default-features = false } +wasmi = { version = "0.28", default-features = false } +wasmparser = { package = "wasmparser-nostd", version = "0.100", default-features = false } impl-trait-for-tuples = "0.2" # Only used in benchmarking to generate random contract code diff --git a/frame/contracts/proc-macro/src/lib.rs b/frame/contracts/proc-macro/src/lib.rs index c3e61dae5f000..32241068fe23f 100644 --- a/frame/contracts/proc-macro/src/lib.rs +++ b/frame/contracts/proc-macro/src/lib.rs @@ -613,7 +613,7 @@ fn expand_functions(def: &EnvDef, expand_blocks: bool, host_state: TokenStream2) let inner = if expand_blocks { quote! { || #output { let (memory, ctx) = __caller__ - .host_data() + .data() .memory() .expect("Memory must be set when setting up host data; qed") .data_and_store_mut(&mut __caller__); @@ -630,7 +630,7 @@ fn expand_functions(def: &EnvDef, expand_blocks: bool, host_state: TokenStream2) let map_err = if expand_blocks { quote! { |reason| { - ::wasmi::core::Trap::host(reason) + ::wasmi::core::Trap::from(reason) } } } else { diff --git a/frame/contracts/src/benchmarking/code.rs b/frame/contracts/src/benchmarking/code.rs index c2d623ae4e834..07f24f385b035 100644 --- a/frame/contracts/src/benchmarking/code.rs +++ b/frame/contracts/src/benchmarking/code.rs @@ -512,7 +512,7 @@ pub fn max_pages() -> u32 { fn inject_gas_metering(module: Module) -> Module { let schedule = T::Schedule::get(); - let gas_rules = schedule.rules(Determinism::Deterministic); + let gas_rules = schedule.rules(Determinism::Enforced); let backend = gas_metering::host_function::Injector::new("seal0", "gas"); gas_metering::inject(module, backend, &gas_rules).unwrap() } diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index fb8e4ac4b3634..9b75b140f03d8 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -381,7 +381,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, Determinism::Deterministic) + }: _(origin, code, None, Determinism::Enforced) verify { // uploading the code reserves some balance in the callers account assert!(T::Currency::reserved_balance(&caller) > 0u32.into()); @@ -397,7 +397,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, Determinism::Deterministic)?; + let uploaded = >::bare_upload_code(caller.clone(), code, None, Determinism::Enforced)?; assert_eq!(uploaded.code_hash, hash); assert_eq!(uploaded.deposit, T::Currency::reserved_balance(&caller)); assert!(>::code_exists(&hash)); @@ -941,7 +941,7 @@ benchmarks! { None, vec![], true, - Determinism::Deterministic, + Determinism::Enforced, ) .result?; } @@ -990,7 +990,7 @@ benchmarks! { None, vec![], true, - Determinism::Deterministic, + Determinism::Enforced, ) .result?; } @@ -3063,7 +3063,7 @@ benchmarks! { None, data, false, - Determinism::Deterministic, + Determinism::Enforced, ) .result?; } @@ -3112,7 +3112,7 @@ benchmarks! { None, data, false, - Determinism::Deterministic, + Determinism::Enforced, ) .result?; } diff --git a/frame/contracts/src/exec.rs b/frame/contracts/src/exec.rs index 6a053712e66e7..51ea234f27376 100644 --- a/frame/contracts/src/exec.rs +++ b/frame/contracts/src/exec.rs @@ -665,7 +665,7 @@ where schedule, value, debug_message, - Determinism::Deterministic, + Determinism::Enforced, )?; let account_id = stack.top_frame().account_id.clone(); stack.run(executable, input_data).map(|ret| (account_id, ret)) @@ -759,10 +759,10 @@ where }, }; - // `AllowIndeterminism` will only be ever set in case of off-chain execution. + // `Relaxed` 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!(determinism, Determinism::Relaxed) && matches!(entry_point, ExportedFunction::Call))) { return Err(Error::::Indeterministic.into()) @@ -1607,7 +1607,7 @@ mod tests { value, vec![], None, - Determinism::Deterministic, + Determinism::Enforced, ), Ok(_) ); @@ -1661,7 +1661,7 @@ mod tests { value, vec![], None, - Determinism::Deterministic, + Determinism::Enforced, ) .unwrap(); @@ -1703,7 +1703,7 @@ mod tests { value, vec![], None, - Determinism::Deterministic, + Determinism::Enforced, ) .unwrap(); @@ -1739,7 +1739,7 @@ mod tests { 55, vec![], None, - Determinism::Deterministic, + Determinism::Enforced, ) .unwrap(); @@ -1791,7 +1791,7 @@ mod tests { 0, vec![], None, - Determinism::Deterministic, + Determinism::Enforced, ); let output = result.unwrap(); @@ -1824,7 +1824,7 @@ mod tests { 0, vec![], None, - Determinism::Deterministic, + Determinism::Enforced, ); let output = result.unwrap(); @@ -1855,7 +1855,7 @@ mod tests { 0, vec![1, 2, 3, 4], None, - Determinism::Deterministic, + Determinism::Enforced, ); assert_matches!(result, Ok(_)); }); @@ -1935,7 +1935,7 @@ mod tests { value, vec![], None, - Determinism::Deterministic, + Determinism::Enforced, ); assert_matches!(result, Ok(_)); @@ -1981,7 +1981,7 @@ mod tests { 0, vec![], None, - Determinism::Deterministic, + Determinism::Enforced, ); assert_matches!(result, Ok(_)); @@ -2015,7 +2015,7 @@ mod tests { 0, vec![], None, - Determinism::Deterministic, + Determinism::Enforced, ); assert_matches!(result, Ok(_)); }); @@ -2045,7 +2045,7 @@ mod tests { 0, vec![0], None, - Determinism::Deterministic, + Determinism::Enforced, ); assert_matches!(result, Ok(_)); }); @@ -2073,7 +2073,7 @@ mod tests { 0, vec![0], None, - Determinism::Deterministic, + Determinism::Enforced, ); assert_matches!(result, Ok(_)); }); @@ -2109,7 +2109,7 @@ mod tests { 0, vec![0], None, - Determinism::Deterministic, + Determinism::Enforced, ); assert_matches!(result, Ok(_)); }); @@ -2145,7 +2145,7 @@ mod tests { 0, vec![], None, - Determinism::Deterministic, + Determinism::Enforced, ); assert_matches!(result, Ok(_)); @@ -2304,7 +2304,7 @@ mod tests { min_balance * 10, vec![], None, - Determinism::Deterministic, + Determinism::Enforced, ), Ok(_) ); @@ -2369,7 +2369,7 @@ mod tests { 0, vec![], None, - Determinism::Deterministic, + Determinism::Enforced, ), Ok(_) ); @@ -2455,7 +2455,7 @@ mod tests { 0, vec![0], None, - Determinism::Deterministic, + Determinism::Enforced, ); assert_matches!(result, Ok(_)); }); @@ -2521,7 +2521,7 @@ mod tests { 0, vec![], Some(&mut debug_buffer), - Determinism::Deterministic, + Determinism::Enforced, ) .unwrap(); }); @@ -2555,7 +2555,7 @@ mod tests { 0, vec![], Some(&mut debug_buffer), - Determinism::Deterministic, + Determinism::Enforced, ); assert!(result.is_err()); }); @@ -2592,7 +2592,7 @@ mod tests { 0, vec![], Some(&mut debug_buf_after), - Determinism::Deterministic, + Determinism::Enforced, ) .unwrap(); assert_eq!(debug_buf_before, debug_buf_after); @@ -2625,7 +2625,7 @@ mod tests { 0, CHARLIE.encode(), None, - Determinism::Deterministic + Determinism::Enforced )); // Calling into oneself fails @@ -2639,7 +2639,7 @@ mod tests { 0, BOB.encode(), None, - Determinism::Deterministic + Determinism::Enforced ) .map_err(|e| e.error), >::ReentranceDenied, @@ -2678,7 +2678,7 @@ mod tests { 0, vec![0], None, - Determinism::Deterministic + Determinism::Enforced ) .map_err(|e| e.error), >::ReentranceDenied, @@ -2713,7 +2713,7 @@ mod tests { 0, vec![], None, - Determinism::Deterministic, + Determinism::Enforced, ) .unwrap(); @@ -2798,7 +2798,7 @@ mod tests { 0, vec![], None, - Determinism::Deterministic, + Determinism::Enforced, ) .unwrap(); @@ -3007,7 +3007,7 @@ mod tests { 0, vec![], None, - Determinism::Deterministic + Determinism::Enforced )); }); } @@ -3134,7 +3134,7 @@ mod tests { 0, vec![], None, - Determinism::Deterministic + Determinism::Enforced )); }); } @@ -3173,7 +3173,7 @@ mod tests { 0, vec![], None, - Determinism::Deterministic + Determinism::Enforced )); }); } @@ -3212,7 +3212,7 @@ mod tests { 0, vec![], None, - Determinism::Deterministic + Determinism::Enforced )); }); } @@ -3268,7 +3268,7 @@ mod tests { 0, vec![], None, - Determinism::Deterministic + Determinism::Enforced )); }); } @@ -3324,7 +3324,7 @@ mod tests { 0, vec![], None, - Determinism::Deterministic + Determinism::Enforced )); }); } @@ -3356,7 +3356,7 @@ mod tests { 0, vec![], None, - Determinism::Deterministic, + Determinism::Enforced, ); assert_matches!(result, Ok(_)); }); @@ -3402,7 +3402,7 @@ mod tests { 0, vec![], None, - Determinism::Deterministic + Determinism::Enforced )); }); } @@ -3432,7 +3432,7 @@ mod tests { 0, vec![], None, - Determinism::Deterministic, + Determinism::Enforced, ); assert_matches!(result, Ok(_)); }); diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index d3369b6c290bf..cd4b7daa6da0f 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -509,9 +509,9 @@ 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. + /// - `determinism`: If this is set to any other value but [`Determinism::Enforced`] then + /// the only way to use this code is to delegate call into it from an offchain execution. + /// Set to [`Determinism::Enforced`] if in doubt. /// /// # Note /// @@ -625,8 +625,8 @@ pub mod pallet { storage_deposit_limit: storage_deposit_limit.map(Into::into), debug_message: None, }; - let mut output = CallInput:: { dest, determinism: Determinism::Deterministic } - .run_guarded(common); + let mut output = + CallInput:: { dest, determinism: Determinism::Enforced }.run_guarded(common); if let Ok(retval) = &output.result { if retval.did_revert() { output.result = Err(>::ContractReverted.into()); @@ -1096,7 +1096,7 @@ impl Invokable for InstantiateInput { binary.clone(), &schedule, common.origin.clone(), - Determinism::Deterministic, + Determinism::Enforced, TryInstantiate::Skip, ) .map_err(|(err, msg)| { diff --git a/frame/contracts/src/migration.rs b/frame/contracts/src/migration.rs index cd8f1dd1c9cd4..96a4c3203474c 100644 --- a/frame/contracts/src/migration.rs +++ b/frame/contracts/src/migration.rs @@ -394,7 +394,7 @@ mod v9 { initial: old.initial, maximum: old.maximum, code: old.code, - determinism: Determinism::Deterministic, + determinism: Determinism::Enforced, }) }); } @@ -464,7 +464,7 @@ mod post_checks { fn v9() -> Result<(), &'static str> { for value in CodeStorage::::iter_values() { ensure!( - value.determinism == Determinism::Deterministic, + value.determinism == Determinism::Enforced, "All pre-existing codes need to be deterministic." ); } diff --git a/frame/contracts/src/schedule.rs b/frame/contracts/src/schedule.rs index 796a7f6d3718d..ccf1e98bd2382 100644 --- a/frame/contracts/src/schedule.rs +++ b/frame/contracts/src/schedule.rs @@ -175,9 +175,9 @@ pub struct InstructionWeights { 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`] + /// This weight is used whenever a code is uploaded with [`Determinism::Relaxed`] /// 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 + /// used if a contract is uploaded with [`Determinism::Enforced`]. If this field is set to /// `0` (the default) only deterministic codes are allowed to be uploaded. pub fallback: u32, pub i64const: u32, @@ -715,8 +715,7 @@ impl<'a, T: Config> gas_metering::Rules for ScheduleRules<'a, T> { // Returning None makes the gas instrumentation fail which we intend for // 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, + _ if matches!(self.determinism, Determinism::Relaxed) && w.fallback > 0 => w.fallback, _ => return None, }; Some(weight) diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index 915a56a3f056c..146e5fd24ad07 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -529,7 +529,7 @@ fn instantiate_and_call_and_deposit_event() { RuntimeOrigin::signed(ALICE), wasm, None, - Determinism::Deterministic + Determinism::Enforced )); // Drop previous events @@ -726,13 +726,8 @@ 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, - Determinism::Deterministic, - ) - .unwrap(); + Contracts::upload_code(RuntimeOrigin::signed(ALICE), wasm, None, Determinism::Enforced) + .unwrap(); // Instantiate the contract and store its trie id for later comparison. let addr = Contracts::bare_instantiate( @@ -860,7 +855,7 @@ fn deploy_and_call_other_contract() { .result .unwrap() .account_id; - Contracts::bare_upload_code(ALICE, callee_wasm, None, Determinism::Deterministic).unwrap(); + Contracts::bare_upload_code(ALICE, callee_wasm, None, Determinism::Enforced).unwrap(); let callee_addr = Contracts::contract_address( &caller_addr, @@ -1011,7 +1006,7 @@ fn delegate_call() { RuntimeOrigin::signed(ALICE), callee_wasm, Some(codec::Compact(100_000)), - Determinism::Deterministic, + Determinism::Enforced, )); assert_ok!(Contracts::call( @@ -1321,7 +1316,7 @@ fn destroy_contract_and_transfer_funds() { ExtBuilder::default().existential_deposit(50).build().execute_with(|| { // Create code hash for bob to instantiate let _ = Balances::deposit_creating(&ALICE, 1_000_000); - Contracts::bare_upload_code(ALICE, callee_wasm, None, Determinism::Deterministic).unwrap(); + Contracts::bare_upload_code(ALICE, callee_wasm, None, Determinism::Enforced).unwrap(); // This deploys the BOB contract, which in turn deploys the CHARLIE contract during // construction. @@ -1431,7 +1426,7 @@ fn crypto_hashes() { None, params, false, - Determinism::Deterministic, + Determinism::Enforced, ) .result .unwrap(); @@ -1473,7 +1468,7 @@ fn transfer_return_code() { None, vec![], false, - Determinism::Deterministic, + Determinism::Enforced, ) .result .unwrap(); @@ -1514,7 +1509,7 @@ fn call_return_code() { None, AsRef::<[u8]>::as_ref(&DJANGO).to_vec(), false, - Determinism::Deterministic, + Determinism::Enforced, ) .result .unwrap(); @@ -1548,7 +1543,7 @@ fn call_return_code() { .cloned() .collect(), false, - Determinism::Deterministic, + Determinism::Enforced, ) .result .unwrap(); @@ -1568,7 +1563,7 @@ fn call_return_code() { .cloned() .collect(), false, - Determinism::Deterministic, + Determinism::Enforced, ) .result .unwrap(); @@ -1587,7 +1582,7 @@ fn call_return_code() { .cloned() .collect(), false, - Determinism::Deterministic, + Determinism::Enforced, ) .result .unwrap(); @@ -1639,7 +1634,7 @@ fn instantiate_return_code() { None, callee_hash.clone(), false, - Determinism::Deterministic, + Determinism::Enforced, ) .result .unwrap(); @@ -1655,7 +1650,7 @@ fn instantiate_return_code() { None, vec![0; 33], false, - Determinism::Deterministic, + Determinism::Enforced, ) .result .unwrap(); @@ -1670,7 +1665,7 @@ fn instantiate_return_code() { None, callee_hash.iter().chain(&1u32.to_le_bytes()).cloned().collect(), false, - Determinism::Deterministic, + Determinism::Enforced, ) .result .unwrap(); @@ -1685,7 +1680,7 @@ fn instantiate_return_code() { None, callee_hash.iter().chain(&2u32.to_le_bytes()).cloned().collect(), false, - Determinism::Deterministic, + Determinism::Enforced, ) .result .unwrap(); @@ -1772,7 +1767,7 @@ fn chain_extension_works() { None, input.clone(), false, - Determinism::Deterministic, + Determinism::Enforced, ); assert_eq!(TestExtension::last_seen_buffer(), input); assert_eq!(result.result.unwrap().data, input); @@ -1786,7 +1781,7 @@ fn chain_extension_works() { None, ExtensionInput { extension_id: 0, func_id: 1, extra: &[] }.into(), false, - Determinism::Deterministic, + Determinism::Enforced, ) .result .unwrap(); @@ -1802,7 +1797,7 @@ fn chain_extension_works() { None, ExtensionInput { extension_id: 0, func_id: 2, extra: &[0] }.into(), false, - Determinism::Deterministic, + Determinism::Enforced, ); assert_ok!(result.result); let gas_consumed = result.gas_consumed; @@ -1814,7 +1809,7 @@ fn chain_extension_works() { None, ExtensionInput { extension_id: 0, func_id: 2, extra: &[42] }.into(), false, - Determinism::Deterministic, + Determinism::Enforced, ); assert_ok!(result.result); assert_eq!(result.gas_consumed.ref_time(), gas_consumed.ref_time() + 42); @@ -1826,7 +1821,7 @@ fn chain_extension_works() { None, ExtensionInput { extension_id: 0, func_id: 2, extra: &[95] }.into(), false, - Determinism::Deterministic, + Determinism::Enforced, ); assert_ok!(result.result); assert_eq!(result.gas_consumed.ref_time(), gas_consumed.ref_time() + 95); @@ -1840,7 +1835,7 @@ fn chain_extension_works() { None, ExtensionInput { extension_id: 0, func_id: 3, extra: &[] }.into(), false, - Determinism::Deterministic, + Determinism::Enforced, ) .result .unwrap(); @@ -1858,7 +1853,7 @@ fn chain_extension_works() { None, ExtensionInput { extension_id: 1, func_id: 0, extra: &[] }.into(), false, - Determinism::Deterministic, + Determinism::Enforced, ) .result .unwrap(); @@ -1919,7 +1914,7 @@ fn chain_extension_temp_storage_works() { None, input.clone(), false, - Determinism::Deterministic + Determinism::Enforced ) .result ); @@ -2480,7 +2475,7 @@ fn reinstrument_does_charge() { None, zero.clone(), false, - Determinism::Deterministic, + Determinism::Enforced, ); assert!(!result0.result.unwrap().did_revert()); @@ -2492,7 +2487,7 @@ fn reinstrument_does_charge() { None, zero.clone(), false, - Determinism::Deterministic, + Determinism::Enforced, ); assert!(!result1.result.unwrap().did_revert()); @@ -2514,7 +2509,7 @@ fn reinstrument_does_charge() { None, zero.clone(), false, - Determinism::Deterministic, + Determinism::Enforced, ); assert!(!result2.result.unwrap().did_revert()); assert!(result2.gas_consumed.ref_time() > result1.gas_consumed.ref_time()); @@ -2553,7 +2548,7 @@ fn debug_message_works() { None, vec![], true, - Determinism::Deterministic, + Determinism::Enforced, ); assert_matches!(result.result, Ok(_)); @@ -2589,7 +2584,7 @@ fn debug_message_logging_disabled() { None, vec![], false, - Determinism::Deterministic, + Determinism::Enforced, ); assert_matches!(result.result, Ok(_)); // the dispatchables always run without debugging @@ -2625,7 +2620,7 @@ fn debug_message_invalid_utf8() { None, vec![], true, - Determinism::Deterministic, + Determinism::Enforced, ); assert_ok!(result.result); assert!(result.debug_message.is_empty()); @@ -2684,7 +2679,7 @@ fn gas_estimation_nested_call_fixed_limit() { None, input.clone(), false, - Determinism::Deterministic, + Determinism::Enforced, ); assert_ok!(&result.result); @@ -2701,7 +2696,7 @@ fn gas_estimation_nested_call_fixed_limit() { Some(result.storage_deposit.charge_or_zero()), input, false, - Determinism::Deterministic, + Determinism::Enforced, ) .result ); @@ -2760,7 +2755,7 @@ fn gas_estimation_call_runtime() { None, call.encode(), false, - Determinism::Deterministic, + Determinism::Enforced, ); // contract encodes the result of the dispatch runtime let outcome = u32::decode(&mut result.result.unwrap().data.as_ref()).unwrap(); @@ -2777,7 +2772,7 @@ fn gas_estimation_call_runtime() { None, call.encode(), false, - Determinism::Deterministic, + Determinism::Enforced, ) .result ); @@ -2840,7 +2835,7 @@ fn gas_call_runtime_reentrancy_guarded() { None, call.encode(), false, - Determinism::Deterministic, + Determinism::Enforced, ) .result .unwrap(); @@ -2902,7 +2897,7 @@ fn ecdsa_recover() { None, params, false, - Determinism::Deterministic, + Determinism::Enforced, ) .result .unwrap(); @@ -2926,7 +2921,7 @@ fn upload_code_works() { RuntimeOrigin::signed(ALICE), wasm, Some(codec::Compact(1_000)), - Determinism::Deterministic, + Determinism::Enforced, )); assert!(>::contains_key(code_hash)); @@ -2966,7 +2961,7 @@ fn upload_code_limit_too_low() { RuntimeOrigin::signed(ALICE), wasm, Some(codec::Compact(100)), - Determinism::Deterministic + Determinism::Enforced ), >::StorageDepositLimitExhausted, ); @@ -2990,7 +2985,7 @@ fn upload_code_not_enough_balance() { RuntimeOrigin::signed(ALICE), wasm, Some(codec::Compact(1_000)), - Determinism::Deterministic + Determinism::Enforced ), >::StorageDepositNotEnoughFunds, ); @@ -3013,7 +3008,7 @@ fn remove_code_works() { RuntimeOrigin::signed(ALICE), wasm, Some(codec::Compact(1_000)), - Determinism::Deterministic, + Determinism::Enforced, )); assert!(>::contains_key(code_hash)); @@ -3068,7 +3063,7 @@ fn remove_code_wrong_origin() { RuntimeOrigin::signed(ALICE), wasm, Some(codec::Compact(1_000)), - Determinism::Deterministic, + Determinism::Enforced, )); assert_noop!( @@ -3538,7 +3533,7 @@ fn set_code_extrinsic() { RuntimeOrigin::signed(ALICE), new_wasm, None, - Determinism::Deterministic + Determinism::Enforced )); // Drop previous events @@ -3658,7 +3653,7 @@ fn contract_reverted() { RuntimeOrigin::signed(ALICE), wasm.clone(), None, - Determinism::Deterministic + Determinism::Enforced )); // Calling extrinsic: revert leads to an error @@ -3746,7 +3741,7 @@ fn contract_reverted() { None, input, false, - Determinism::Deterministic, + Determinism::Enforced, ) .result .unwrap(); @@ -3766,7 +3761,7 @@ fn code_rejected_error_works() { RuntimeOrigin::signed(ALICE), wasm.clone(), None, - Determinism::Deterministic + Determinism::Enforced ), >::CodeRejected, ); @@ -3792,7 +3787,7 @@ fn code_rejected_error_works() { RuntimeOrigin::signed(ALICE), wasm.clone(), None, - Determinism::Deterministic + Determinism::Enforced ), >::CodeRejected, ); @@ -3842,7 +3837,7 @@ fn set_code_hash() { RuntimeOrigin::signed(ALICE), new_wasm.clone(), None, - Determinism::Deterministic + Determinism::Enforced )); System::reset_events(); @@ -3856,7 +3851,7 @@ fn set_code_hash() { None, new_code_hash.as_ref().to_vec(), true, - Determinism::Deterministic, + Determinism::Enforced, ) .result .unwrap(); @@ -3871,7 +3866,7 @@ fn set_code_hash() { None, vec![], true, - Determinism::Deterministic, + Determinism::Enforced, ) .result .unwrap(); @@ -4268,7 +4263,7 @@ fn cannot_instantiate_indeterministic_code() { RuntimeOrigin::signed(ALICE), wasm.clone(), None, - Determinism::Deterministic + Determinism::Enforced ), >::CodeRejected, ); @@ -4278,7 +4273,7 @@ fn cannot_instantiate_indeterministic_code() { RuntimeOrigin::signed(ALICE), wasm, None, - Determinism::AllowIndeterminism, + Determinism::Relaxed, )); assert_err_ignore_postinfo!( Contracts::instantiate( @@ -4332,7 +4327,7 @@ fn cannot_instantiate_indeterministic_code() { None, code_hash.encode(), false, - Determinism::Deterministic, + Determinism::Enforced, ) .result, >::Indeterministic, @@ -4348,7 +4343,7 @@ fn cannot_instantiate_indeterministic_code() { None, code_hash.encode(), false, - Determinism::AllowIndeterminism, + Determinism::Relaxed, ) .result, >::Indeterministic, @@ -4368,7 +4363,7 @@ fn cannot_set_code_indeterministic_code() { RuntimeOrigin::signed(ALICE), wasm, None, - Determinism::AllowIndeterminism, + Determinism::Relaxed, )); // Create the contract that will call `seal_set_code_hash` @@ -4396,7 +4391,7 @@ fn cannot_set_code_indeterministic_code() { None, code_hash.encode(), false, - Determinism::AllowIndeterminism, + Determinism::Relaxed, ) .result, >::Indeterministic, @@ -4416,7 +4411,7 @@ fn delegate_call_indeterministic_code() { RuntimeOrigin::signed(ALICE), wasm, None, - Determinism::AllowIndeterminism, + Determinism::Relaxed, )); // Create the contract that will call `seal_delegate_call` @@ -4444,7 +4439,7 @@ fn delegate_call_indeterministic_code() { None, code_hash.encode(), false, - Determinism::Deterministic, + Determinism::Enforced, ) .result, >::Indeterministic, @@ -4460,7 +4455,7 @@ fn delegate_call_indeterministic_code() { None, code_hash.encode(), false, - Determinism::AllowIndeterminism, + Determinism::Relaxed, ) .result ); @@ -4499,7 +4494,7 @@ fn reentrance_count_works_with_call() { None, input, true, - Determinism::Deterministic, + Determinism::Enforced, ) .result .unwrap(); @@ -4538,7 +4533,7 @@ fn reentrance_count_works_with_delegated_call() { None, input, true, - Determinism::Deterministic, + Determinism::Enforced, ) .result .unwrap(); @@ -4590,7 +4585,7 @@ fn account_reentrance_count_works() { None, contract_addr.encode(), true, - Determinism::Deterministic, + Determinism::Enforced, ) .result .unwrap(); @@ -4603,7 +4598,7 @@ fn account_reentrance_count_works() { None, another_contract_addr.encode(), true, - Determinism::Deterministic, + Determinism::Enforced, ) .result .unwrap(); diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index cfda9c37611b9..5e4ffcfe0a598 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -127,7 +127,7 @@ pub enum Determinism { /// allowed. /// /// Dispatchables always use this mode in order to make on-chain execution deterministic. - Deterministic, + Enforced, /// Allow calling or uploading an indeterministic code. /// /// This is only possible when calling into `pallet-contracts` directly via @@ -136,7 +136,7 @@ pub enum Determinism { /// # Note /// /// **Never** use this mode for on-chain execution. - AllowIndeterminism, + Relaxed, } impl ExportedFunction { @@ -225,7 +225,7 @@ impl PrefabWasmModule { let engine = Engine::new(&config); let module = Module::new(&engine, code)?; let mut store = Store::new(&engine, host_state); - let mut linker = Linker::new(); + let mut linker = Linker::new(&engine); E::define( &mut store, &mut linker, @@ -329,7 +329,7 @@ impl Executable for PrefabWasmModule { log::debug!(target: "runtime::contracts", "failed to instantiate code: {}", msg); Error::::CodeRejected })?; - store.state_mut().set_memory(memory); + store.data_mut().set_memory(memory); let exported_func = instance .get_export(&store, function.identifier()) @@ -346,7 +346,7 @@ impl Executable for PrefabWasmModule { let result = exported_func.call(&mut store, &[], &mut []); - store.into_state().to_execution_result(result) + store.into_data().to_execution_result(result) } fn code_hash(&self) -> &CodeHash { @@ -358,7 +358,7 @@ impl Executable for PrefabWasmModule { } fn is_deterministic(&self) -> bool { - matches!(self.determinism, Determinism::Deterministic) + matches!(self.determinism, Determinism::Enforced) } } @@ -653,7 +653,7 @@ mod tests { wasm, &schedule, ALICE, - Determinism::Deterministic, + Determinism::Enforced, TryInstantiate::Instantiate, ) .map_err(|err| err.0)? @@ -3058,12 +3058,8 @@ mod tests { let schedule = crate::Schedule::::default(); #[cfg(not(feature = "runtime-benchmarks"))] assert_err!(execute(CODE_RANDOM, vec![], MockExt::default()), >::CodeRejected); - self::prepare::reinstrument::( - &wasm, - &schedule, - Determinism::Deterministic, - ) - .unwrap(); + self::prepare::reinstrument::(&wasm, &schedule, Determinism::Enforced) + .unwrap(); } /// This test check that an unstable interface cannot be deployed. In case of runtime diff --git a/frame/contracts/src/wasm/prepare.rs b/frame/contracts/src/wasm/prepare.rs index 6a2eb6a769ecc..f0065d77a1c9a 100644 --- a/frame/contracts/src/wasm/prepare.rs +++ b/frame/contracts/src/wasm/prepare.rs @@ -155,52 +155,6 @@ impl<'a, T: Config> ContractModule<'a, T> { 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() { - for global in global_section.entries() { - match global.global_type().content_type() { - ValueType::F32 | ValueType::F64 => - return Err("use of floating point type in globals is forbidden"), - _ => {}, - } - } - } - - if let Some(code_section) = self.module.code_section() { - for func_body in code_section.bodies() { - for local in func_body.locals() { - match local.value_type() { - ValueType::F32 | ValueType::F64 => - return Err("use of floating point type in locals is forbidden"), - _ => {}, - } - } - } - } - - if let Some(type_section) = self.module.type_section() { - for wasm_type in type_section.types() { - match wasm_type { - Type::Function(func_type) => { - let return_type = func_type.results().get(0); - for value_type in func_type.params().iter().chain(return_type) { - match value_type { - ValueType::F32 | ValueType::F64 => - return Err( - "use of floating point type in function types is forbidden", - ), - _ => {}, - } - } - }, - } - } - } - - Ok(()) - } - /// Ensure that no function exists that has more parameters than allowed. fn ensure_parameter_limit(&self, limit: u32) -> Result<(), &'static str> { let type_section = if let Some(type_section) = self.module.type_section() { @@ -411,10 +365,9 @@ where 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 explicitly need to have weights assigned + // This is not our only defense: All instructions explicitly need to have weights assigned // or the deployment will fail. We have none assigned for float instructions. - deterministic_only: matches!(determinism, Determinism::Deterministic), + floats: matches!(determinism, Determinism::Relaxed), mutable_global: false, saturating_float_to_int: false, sign_extension: false, @@ -422,6 +375,7 @@ where multi_value: false, reference_types: false, simd: false, + memory_control: false, }) .validate_all(original_code) .map_err(|err| { @@ -439,10 +393,6 @@ where 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 = @@ -608,7 +558,7 @@ pub mod benchmarking { deposit: Default::default(), refcount: 0, }), - determinism: Determinism::Deterministic, + determinism: Determinism::Enforced, }) } } @@ -682,7 +632,7 @@ mod tests { wasm, &schedule, ALICE, - Determinism::Deterministic, + Determinism::Enforced, TryInstantiate::Instantiate, ); assert_matches::assert_matches!(r.map_err(|(_, msg)| msg), $($expected)*); @@ -704,7 +654,7 @@ mod tests { ) (func (export "deploy")) )"#, - Err("gas instrumentation failed") + Err("validation of new code failed") ); mod functions { @@ -1214,7 +1164,7 @@ mod tests { (func (export "deploy")) ) "#, - Err("use of floating point type in globals is forbidden") + Err("validation of new code failed") ); prepare_test!( @@ -1226,7 +1176,7 @@ mod tests { (func (export "deploy")) ) "#, - Err("use of floating point type in locals is forbidden") + Err("validation of new code failed") ); prepare_test!( @@ -1238,7 +1188,7 @@ mod tests { (func (export "deploy")) ) "#, - Err("use of floating point type in function types is forbidden") + Err("validation of new code failed") ); prepare_test!( @@ -1250,7 +1200,7 @@ mod tests { (func (export "deploy")) ) "#, - Err("use of floating point type in function types is forbidden") + Err("validation of new code failed") ); } } diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index a8a19e6f95150..43a029eadfc07 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -482,11 +482,7 @@ impl<'a, E: Ext + 'a> Runtime<'a, E> { 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"); + let reason: TrapReason = trap.downcast().ok_or(Error::::ContractTrapped)?; match reason { Return(ReturnData { flags, data }) => { let flags = diff --git a/frame/contracts/src/weights.rs b/frame/contracts/src/weights.rs index b16f11eb7f50a..4333f26c5fc5c 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: 2023-03-14, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-17, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -177,8 +177,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `109` // Estimated: `1594` - // Minimum execution time: 2_736_000 picoseconds. - Weight::from_parts(2_931_000, 1594) + // Minimum execution time: 2_567_000 picoseconds. + Weight::from_parts(2_711_000, 1594) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: Skipped Metadata (r:0 w:0) @@ -186,12 +186,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `k` is `[0, 1024]`. fn on_initialize_per_trie_key(k: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `481 + k * (69 ±0)` - // Estimated: `471 + k * (70 ±0)` - // Minimum execution time: 10_759_000 picoseconds. - Weight::from_parts(6_965_683, 471) - // Standard Error: 1_019 - .saturating_add(Weight::from_parts(961_947, 0).saturating_mul(k.into())) + // Measured: `450 + k * (69 ±0)` + // Estimated: `440 + k * (70 ±0)` + // Minimum execution time: 11_048_000 picoseconds. + Weight::from_parts(7_029_322, 440) + // Standard Error: 1_158 + .saturating_add(Weight::from_parts(975_010, 0).saturating_mul(k.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) @@ -203,12 +203,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `q` is `[0, 128]`. fn on_initialize_per_queue_item(q: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `281 + q * (33 ±0)` - // Estimated: `1753 + q * (33 ±0)` - // Minimum execution time: 2_633_000 picoseconds. - Weight::from_parts(10_668_837, 1753) - // Standard Error: 3_538 - .saturating_add(Weight::from_parts(1_277_168, 0).saturating_mul(q.into())) + // Measured: `250 + q * (33 ±0)` + // Estimated: `1725 + q * (33 ±0)` + // Minimum execution time: 2_645_000 picoseconds. + Weight::from_parts(10_865_477, 1725) + // Standard Error: 3_383 + .saturating_add(Weight::from_parts(1_295_351, 0).saturating_mul(q.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 33).saturating_mul(q.into())) @@ -220,12 +220,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `c` is `[0, 61717]`. fn reinstrument(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `270 + c * (1 ±0)` - // Estimated: `4015 + c * (2 ±0)` - // Minimum execution time: 30_264_000 picoseconds. - Weight::from_parts(27_106_554, 4015) - // Standard Error: 53 - .saturating_add(Weight::from_parts(49_705, 0).saturating_mul(c.into())) + // Measured: `238 + c * (1 ±0)` + // Estimated: `3951 + c * (2 ±0)` + // Minimum execution time: 30_817_000 picoseconds. + Weight::from_parts(29_762_622, 3951) + // Standard Error: 62 + .saturating_add(Weight::from_parts(54_714, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 2).saturating_mul(c.into())) @@ -243,12 +243,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `c` is `[0, 125952]`. fn call_with_code_per_byte(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `803` - // Estimated: `21880 + c * (5 ±0)` - // Minimum execution time: 309_249_000 picoseconds. - Weight::from_parts(323_353_590, 21880) - // Standard Error: 25 - .saturating_add(Weight::from_parts(31_359, 0).saturating_mul(c.into())) + // Measured: `707` + // Estimated: `21400 + c * (5 ±0)` + // Minimum execution time: 245_493_000 picoseconds. + Weight::from_parts(253_703_384, 21400) + // Standard Error: 27 + .saturating_add(Weight::from_parts(38_078, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 5).saturating_mul(c.into())) @@ -276,14 +276,14 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `270` // Estimated: `26207` - // Minimum execution time: 3_136_707_000 picoseconds. - Weight::from_parts(564_055_378, 26207) - // Standard Error: 286 - .saturating_add(Weight::from_parts(93_308, 0).saturating_mul(c.into())) - // Standard Error: 16 - .saturating_add(Weight::from_parts(1_165, 0).saturating_mul(i.into())) - // Standard Error: 16 - .saturating_add(Weight::from_parts(1_435, 0).saturating_mul(s.into())) + // Minimum execution time: 3_079_430_000 picoseconds. + Weight::from_parts(555_022_483, 26207) + // Standard Error: 290 + .saturating_add(Weight::from_parts(107_411, 0).saturating_mul(c.into())) + // Standard Error: 17 + .saturating_add(Weight::from_parts(1_123, 0).saturating_mul(i.into())) + // Standard Error: 17 + .saturating_add(Weight::from_parts(1_434, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(10_u64)) } @@ -305,14 +305,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[0, 1048576]`. fn instantiate(i: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `546` - // Estimated: `28969` - // Minimum execution time: 1_631_314_000 picoseconds. - Weight::from_parts(236_693_159, 28969) + // Measured: `482` + // Estimated: `28521` + // Minimum execution time: 1_600_733_000 picoseconds. + Weight::from_parts(228_681_962, 28521) // Standard Error: 8 - .saturating_add(Weight::from_parts(1_434, 0).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(1_445, 0).saturating_mul(i.into())) // Standard Error: 8 - .saturating_add(Weight::from_parts(1_445, 0).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_456, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } @@ -328,10 +328,10 @@ impl WeightInfo for SubstrateWeight { /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) fn call() -> Weight { // Proof Size summary in bytes: - // Measured: `855` - // Estimated: `22095` - // Minimum execution time: 167_139_000 picoseconds. - Weight::from_parts(168_034_000, 22095) + // Measured: `759` + // Estimated: `21615` + // Minimum execution time: 172_310_000 picoseconds. + Weight::from_parts(176_655_000, 21615) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -348,10 +348,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `109` // Estimated: `7366` - // Minimum execution time: 306_518_000 picoseconds. - Weight::from_parts(325_652_407, 7366) - // Standard Error: 134 - .saturating_add(Weight::from_parts(93_502, 0).saturating_mul(c.into())) + // Minimum execution time: 246_364_000 picoseconds. + Weight::from_parts(262_887_234, 7366) + // Standard Error: 90 + .saturating_add(Weight::from_parts(107_926, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -365,10 +365,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Contracts PristineCode (max_values: None, max_size: Some(125988), added: 128463, mode: Measured) fn remove_code() -> Weight { // Proof Size summary in bytes: - // Measured: `287` - // Estimated: `8078` - // Minimum execution time: 29_084_000 picoseconds. - Weight::from_parts(29_350_000, 8078) + // Measured: `255` + // Estimated: `7950` + // Minimum execution time: 29_226_000 picoseconds. + Weight::from_parts(29_542_000, 7950) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -380,10 +380,10 @@ impl WeightInfo for SubstrateWeight { /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) fn set_code() -> Weight { // Proof Size summary in bytes: - // Measured: `666` - // Estimated: `19818` - // Minimum execution time: 32_996_000 picoseconds. - Weight::from_parts(33_365_000, 19818) + // Measured: `570` + // Estimated: `19530` + // Minimum execution time: 33_921_000 picoseconds. + Weight::from_parts(35_056_000, 19530) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -400,12 +400,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_caller(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `877 + r * (6 ±0)` - // Estimated: `22210 + r * (30 ±0)` - // Minimum execution time: 298_315_000 picoseconds. - Weight::from_parts(304_612_433, 22210) - // Standard Error: 904 - .saturating_add(Weight::from_parts(285_473, 0).saturating_mul(r.into())) + // Measured: `781 + r * (6 ±0)` + // Estimated: `21730 + r * (30 ±0)` + // Minimum execution time: 232_118_000 picoseconds. + Weight::from_parts(233_883_823, 21730) + // Standard Error: 642 + .saturating_add(Weight::from_parts(340_543, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -423,16 +423,16 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_is_contract(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `935 + r * (272 ±0)` - // Estimated: `22315 + r * (3835 ±0)` - // Minimum execution time: 299_169_000 picoseconds. - Weight::from_parts(138_157_704, 22315) - // Standard Error: 6_115 - .saturating_add(Weight::from_parts(3_244_482, 0).saturating_mul(r.into())) + // Measured: `839 + r * (240 ±0)` + // Estimated: `21835 + r * (3675 ±0)` + // Minimum execution time: 231_712_000 picoseconds. + Weight::from_parts(74_297_097, 21835) + // Standard Error: 6_099 + .saturating_add(Weight::from_parts(3_322_192, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 3835).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 3675).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -447,16 +447,16 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_code_hash(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `927 + r * (276 ±0)` - // Estimated: `22335 + r * (3855 ±0)` - // Minimum execution time: 299_262_000 picoseconds. - Weight::from_parts(157_105_627, 22335) - // Standard Error: 5_634 - .saturating_add(Weight::from_parts(3_995_666, 0).saturating_mul(r.into())) + // Measured: `831 + r * (244 ±0)` + // Estimated: `21855 + r * (3695 ±0)` + // Minimum execution time: 233_122_000 picoseconds. + Weight::from_parts(74_369_473, 21855) + // Standard Error: 6_027 + .saturating_add(Weight::from_parts(4_177_187, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 3855).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 3695).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -471,12 +471,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_own_code_hash(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `884 + r * (6 ±0)` - // Estimated: `22250 + r * (30 ±0)` - // Minimum execution time: 298_259_000 picoseconds. - Weight::from_parts(303_498_245, 22250) - // Standard Error: 874 - .saturating_add(Weight::from_parts(352_839, 0).saturating_mul(r.into())) + // Measured: `788 + r * (6 ±0)` + // Estimated: `21770 + r * (30 ±0)` + // Minimum execution time: 232_822_000 picoseconds. + Weight::from_parts(232_507_418, 21770) + // Standard Error: 961 + .saturating_add(Weight::from_parts(419_331, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -494,12 +494,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_caller_is_origin(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `874 + r * (3 ±0)` - // Estimated: `22215 + r * (15 ±0)` - // Minimum execution time: 295_689_000 picoseconds. - Weight::from_parts(314_004_541, 22215) - // Standard Error: 1_803 - .saturating_add(Weight::from_parts(131_102, 0).saturating_mul(r.into())) + // Measured: `778 + r * (3 ±0)` + // Estimated: `21735 + r * (15 ±0)` + // Minimum execution time: 229_719_000 picoseconds. + Weight::from_parts(235_257_789, 21735) + // Standard Error: 451 + .saturating_add(Weight::from_parts(161_101, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 15).saturating_mul(r.into())) @@ -517,12 +517,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_address(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `878 + r * (6 ±0)` - // Estimated: `22220 + r * (30 ±0)` - // Minimum execution time: 297_579_000 picoseconds. - Weight::from_parts(299_326_920, 22220) - // Standard Error: 990 - .saturating_add(Weight::from_parts(284_789, 0).saturating_mul(r.into())) + // Measured: `782 + r * (6 ±0)` + // Estimated: `21740 + r * (30 ±0)` + // Minimum execution time: 231_517_000 picoseconds. + Weight::from_parts(236_185_452, 21740) + // Standard Error: 651 + .saturating_add(Weight::from_parts(334_659, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -540,12 +540,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_gas_left(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `879 + r * (6 ±0)` - // Estimated: `22205 + r * (30 ±0)` - // Minimum execution time: 297_651_000 picoseconds. - Weight::from_parts(304_465_467, 22205) - // Standard Error: 736 - .saturating_add(Weight::from_parts(272_149, 0).saturating_mul(r.into())) + // Measured: `783 + r * (6 ±0)` + // Estimated: `21725 + r * (30 ±0)` + // Minimum execution time: 232_855_000 picoseconds. + Weight::from_parts(239_986_328, 21725) + // Standard Error: 4_075 + .saturating_add(Weight::from_parts(345_726, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -563,12 +563,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_balance(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1050 + r * (6 ±0)` - // Estimated: `25258 + r * (30 ±0)` - // Minimum execution time: 296_957_000 picoseconds. - Weight::from_parts(308_680_068, 25258) - // Standard Error: 1_377 - .saturating_add(Weight::from_parts(1_419_294, 0).saturating_mul(r.into())) + // Measured: `922 + r * (6 ±0)` + // Estimated: `24633 + r * (30 ±0)` + // Minimum execution time: 231_685_000 picoseconds. + Weight::from_parts(245_514_261, 24633) + // Standard Error: 1_635 + .saturating_add(Weight::from_parts(1_523_359, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -586,12 +586,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_value_transferred(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `888 + r * (6 ±0)` - // Estimated: `22305 + r * (30 ±0)` - // Minimum execution time: 297_735_000 picoseconds. - Weight::from_parts(301_533_807, 22305) - // Standard Error: 1_119 - .saturating_add(Weight::from_parts(277_289, 0).saturating_mul(r.into())) + // Measured: `792 + r * (6 ±0)` + // Estimated: `21825 + r * (30 ±0)` + // Minimum execution time: 233_361_000 picoseconds. + Weight::from_parts(234_553_471, 21825) + // Standard Error: 1_108 + .saturating_add(Weight::from_parts(330_383, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -609,12 +609,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_minimum_balance(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `886 + r * (6 ±0)` - // Estimated: `22295 + r * (30 ±0)` - // Minimum execution time: 299_599_000 picoseconds. - Weight::from_parts(303_664_496, 22295) - // Standard Error: 1_009 - .saturating_add(Weight::from_parts(280_353, 0).saturating_mul(r.into())) + // Measured: `790 + r * (6 ±0)` + // Estimated: `21815 + r * (30 ±0)` + // Minimum execution time: 231_918_000 picoseconds. + Weight::from_parts(239_128_416, 21815) + // Standard Error: 1_473 + .saturating_add(Weight::from_parts(317_879, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -632,12 +632,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_block_number(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `883 + r * (6 ±0)` - // Estimated: `22285 + r * (30 ±0)` - // Minimum execution time: 297_641_000 picoseconds. - Weight::from_parts(302_437_979, 22285) - // Standard Error: 669 - .saturating_add(Weight::from_parts(270_403, 0).saturating_mul(r.into())) + // Measured: `787 + r * (6 ±0)` + // Estimated: `21805 + r * (30 ±0)` + // Minimum execution time: 231_936_000 picoseconds. + Weight::from_parts(232_240_207, 21805) + // Standard Error: 731 + .saturating_add(Weight::from_parts(330_713, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -655,12 +655,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_now(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `874 + r * (6 ±0)` - // Estimated: `22215 + r * (30 ±0)` - // Minimum execution time: 297_217_000 picoseconds. - Weight::from_parts(299_538_157, 22215) - // Standard Error: 732 - .saturating_add(Weight::from_parts(280_800, 0).saturating_mul(r.into())) + // Measured: `778 + r * (6 ±0)` + // Estimated: `21735 + r * (30 ±0)` + // Minimum execution time: 231_978_000 picoseconds. + Weight::from_parts(224_881_201, 21735) + // Standard Error: 1_296 + .saturating_add(Weight::from_parts(346_872, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -680,12 +680,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_weight_to_fee(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `952 + r * (10 ±0)` - // Estimated: `25022 + r * (60 ±0)` - // Minimum execution time: 297_286_000 picoseconds. - Weight::from_parts(311_436_352, 25022) - // Standard Error: 6_811 - .saturating_add(Weight::from_parts(1_291_941, 0).saturating_mul(r.into())) + // Measured: `856 + r * (10 ±0)` + // Estimated: `24446 + r * (60 ±0)` + // Minimum execution time: 231_707_000 picoseconds. + Weight::from_parts(245_939_854, 24446) + // Standard Error: 1_369 + .saturating_add(Weight::from_parts(1_380_453, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 60).saturating_mul(r.into())) @@ -703,12 +703,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_gas(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `841 + r * (4 ±0)` - // Estimated: `22035 + r * (20 ±0)` - // Minimum execution time: 154_772_000 picoseconds. - Weight::from_parts(159_224_457, 22035) - // Standard Error: 212 - .saturating_add(Weight::from_parts(102_264, 0).saturating_mul(r.into())) + // Measured: `745 + r * (4 ±0)` + // Estimated: `21555 + r * (20 ±0)` + // Minimum execution time: 157_429_000 picoseconds. + Weight::from_parts(161_047_355, 21555) + // Standard Error: 1_220 + .saturating_add(Weight::from_parts(134_497, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 20).saturating_mul(r.into())) @@ -726,12 +726,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_input(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `876 + r * (6 ±0)` - // Estimated: `22220 + r * (30 ±0)` - // Minimum execution time: 297_248_000 picoseconds. - Weight::from_parts(303_805_584, 22220) - // Standard Error: 858 - .saturating_add(Weight::from_parts(223_587, 0).saturating_mul(r.into())) + // Measured: `780 + r * (6 ±0)` + // Estimated: `21740 + r * (30 ±0)` + // Minimum execution time: 232_561_000 picoseconds. + Weight::from_parts(230_989_499, 21740) + // Standard Error: 848 + .saturating_add(Weight::from_parts(282_053, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -749,12 +749,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 1048576]`. fn seal_input_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `880` - // Estimated: `22220` - // Minimum execution time: 298_464_000 picoseconds. - Weight::from_parts(300_996_431, 22220) - // Standard Error: 1 - .saturating_add(Weight::from_parts(600, 0).saturating_mul(n.into())) + // Measured: `784` + // Estimated: `21740` + // Minimum execution time: 237_080_000 picoseconds. + Weight::from_parts(239_380_994, 21740) + // Standard Error: 2 + .saturating_add(Weight::from_parts(592, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -771,12 +771,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1]`. fn seal_return(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `864 + r * (45 ±0)` - // Estimated: `22140 + r * (225 ±0)` - // Minimum execution time: 294_347_000 picoseconds. - Weight::from_parts(296_793_034, 22140) - // Standard Error: 277_251 - .saturating_add(Weight::from_parts(1_711_665, 0).saturating_mul(r.into())) + // Measured: `768 + r * (45 ±0)` + // Estimated: `21660 + r * (225 ±0)` + // Minimum execution time: 228_669_000 picoseconds. + Weight::from_parts(230_916_471, 21660) + // Standard Error: 295_520 + .saturating_add(Weight::from_parts(1_420_928, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 225).saturating_mul(r.into())) @@ -794,12 +794,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 1048576]`. fn seal_return_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `874` - // Estimated: `22255` - // Minimum execution time: 297_257_000 picoseconds. - Weight::from_parts(300_088_288, 22255) + // Measured: `778` + // Estimated: `21775` + // Minimum execution time: 231_626_000 picoseconds. + Weight::from_parts(232_097_413, 21775) // Standard Error: 1 - .saturating_add(Weight::from_parts(181, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(185, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -820,17 +820,17 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1]`. fn seal_terminate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `906 + r * (452 ±0)` - // Estimated: `26183 + r * (15994 ±0)` - // Minimum execution time: 296_510_000 picoseconds. - Weight::from_parts(299_169_757, 26183) - // Standard Error: 205_313 - .saturating_add(Weight::from_parts(78_059_642, 0).saturating_mul(r.into())) + // Measured: `810 + r * (356 ±0)` + // Estimated: `25511 + r * (15321 ±0)` + // Minimum execution time: 230_758_000 picoseconds. + Weight::from_parts(233_235_993, 25511) + // Standard Error: 196_168 + .saturating_add(Weight::from_parts(81_177_506, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((6_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((7_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 15994).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 15321).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -847,12 +847,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_random(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `921 + r * (10 ±0)` - // Estimated: `24859 + r * (60 ±0)` - // Minimum execution time: 299_299_000 picoseconds. - Weight::from_parts(314_487_015, 24859) - // Standard Error: 1_552 - .saturating_add(Weight::from_parts(1_753_960, 0).saturating_mul(r.into())) + // Measured: `825 + r * (10 ±0)` + // Estimated: `24283 + r * (60 ±0)` + // Minimum execution time: 232_457_000 picoseconds. + Weight::from_parts(240_943_161, 24283) + // Standard Error: 3_085 + .saturating_add(Weight::from_parts(1_837_168, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 60).saturating_mul(r.into())) @@ -870,12 +870,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_deposit_event(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `874 + r * (10 ±0)` - // Estimated: `22215 + r * (50 ±0)` - // Minimum execution time: 296_188_000 picoseconds. - Weight::from_parts(305_901_539, 22215) - // Standard Error: 2_782 - .saturating_add(Weight::from_parts(3_456_054, 0).saturating_mul(r.into())) + // Measured: `778 + r * (10 ±0)` + // Estimated: `21735 + r * (50 ±0)` + // Minimum execution time: 229_788_000 picoseconds. + Weight::from_parts(233_520_858, 21735) + // Standard Error: 9_561 + .saturating_add(Weight::from_parts(3_596_294, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 50).saturating_mul(r.into())) @@ -894,14 +894,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 16384]`. fn seal_deposit_event_per_topic_and_byte(t: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `893 + t * (32 ±0)` - // Estimated: `22320 + t * (2640 ±0)` - // Minimum execution time: 313_860_000 picoseconds. - Weight::from_parts(312_473_092, 22320) - // Standard Error: 250_852 - .saturating_add(Weight::from_parts(2_258_502, 0).saturating_mul(t.into())) - // Standard Error: 70 - .saturating_add(Weight::from_parts(312, 0).saturating_mul(n.into())) + // Measured: `797 + t * (32 ±0)` + // Estimated: `21840 + t * (2640 ±0)` + // Minimum execution time: 248_294_000 picoseconds. + Weight::from_parts(239_709_759, 21840) + // Standard Error: 66_903 + .saturating_add(Weight::from_parts(2_880_732, 0).saturating_mul(t.into())) + // Standard Error: 18 + .saturating_add(Weight::from_parts(725, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(t.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -921,12 +921,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_debug_message(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `873 + r * (7 ±0)` - // Estimated: `22205 + r * (35 ±0)` - // Minimum execution time: 162_043_000 picoseconds. - Weight::from_parts(166_132_332, 22205) - // Standard Error: 716 - .saturating_add(Weight::from_parts(184_981, 0).saturating_mul(r.into())) + // Measured: `777 + r * (7 ±0)` + // Estimated: `21725 + r * (35 ±0)` + // Minimum execution time: 170_601_000 picoseconds. + Weight::from_parts(165_819_714, 21725) + // Standard Error: 452 + .saturating_add(Weight::from_parts(240_362, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 35).saturating_mul(r.into())) @@ -944,12 +944,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `i` is `[0, 1048576]`. fn seal_debug_message_per_byte(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `125824` - // Estimated: `270073` - // Minimum execution time: 414_433_000 picoseconds. - Weight::from_parts(417_483_627, 270073) - // Standard Error: 1 - .saturating_add(Weight::from_parts(748, 0).saturating_mul(i.into())) + // Measured: `125728` + // Estimated: `269977` + // Minimum execution time: 349_543_000 picoseconds. + Weight::from_parts(352_945_102, 269977) + // Standard Error: 2 + .saturating_add(Weight::from_parts(749, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -958,12 +958,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 800]`. fn seal_set_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `941 + r * (292 ±0)` - // Estimated: `939 + r * (293 ±0)` - // Minimum execution time: 299_500_000 picoseconds. - Weight::from_parts(194_466_413, 939) - // Standard Error: 9_986 - .saturating_add(Weight::from_parts(6_010_112, 0).saturating_mul(r.into())) + // Measured: `845 + r * (292 ±0)` + // Estimated: `843 + r * (293 ±0)` + // Minimum execution time: 238_766_000 picoseconds. + Weight::from_parts(130_994_282, 843) + // Standard Error: 10_413 + .saturating_add(Weight::from_parts(6_134_087, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -975,12 +975,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 16384]`. fn seal_set_storage_per_new_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1432` - // Estimated: `1405` - // Minimum execution time: 314_171_000 picoseconds. - Weight::from_parts(335_595_397, 1405) - // Standard Error: 67 - .saturating_add(Weight::from_parts(90, 0).saturating_mul(n.into())) + // Measured: `1304` + // Estimated: `1280` + // Minimum execution time: 248_137_000 picoseconds. + Weight::from_parts(265_535_917, 1280) + // Standard Error: 28 + .saturating_add(Weight::from_parts(387, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -989,12 +989,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 16384]`. fn seal_set_storage_per_old_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1295 + n * (1 ±0)` - // Estimated: `1292 + n * (1 ±0)` - // Minimum execution time: 313_479_000 picoseconds. - Weight::from_parts(317_435_100, 1292) - // Standard Error: 41 - .saturating_add(Weight::from_parts(106, 0).saturating_mul(n.into())) + // Measured: `1167 + n * (1 ±0)` + // Estimated: `1167 + n * (1 ±0)` + // Minimum execution time: 246_752_000 picoseconds. + Weight::from_parts(250_315_210, 1167) + // Standard Error: 42 + .saturating_add(Weight::from_parts(135, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -1004,12 +1004,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 800]`. fn seal_clear_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `937 + r * (288 ±0)` - // Estimated: `941 + r * (289 ±0)` - // Minimum execution time: 297_831_000 picoseconds. - Weight::from_parts(196_983_778, 941) - // Standard Error: 9_899 - .saturating_add(Weight::from_parts(5_904_642, 0).saturating_mul(r.into())) + // Measured: `841 + r * (288 ±0)` + // Estimated: `845 + r * (289 ±0)` + // Minimum execution time: 232_873_000 picoseconds. + Weight::from_parts(130_360_558, 845) + // Standard Error: 10_026 + .saturating_add(Weight::from_parts(6_023_862, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1021,10 +1021,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 16384]`. fn seal_clear_storage_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1291 + n * (1 ±0)` - // Estimated: `1288 + n * (1 ±0)` - // Minimum execution time: 320_156_000 picoseconds. - Weight::from_parts(327_504_368, 1288) + // Measured: `1163 + n * (1 ±0)` + // Estimated: `1163 + n * (1 ±0)` + // Minimum execution time: 247_079_000 picoseconds. + Weight::from_parts(248_922_003, 1163) + // Standard Error: 22 + .saturating_add(Weight::from_parts(201, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -1034,12 +1036,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 800]`. fn seal_get_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `931 + r * (296 ±0)` - // Estimated: `936 + r * (297 ±0)` - // Minimum execution time: 305_849_000 picoseconds. - Weight::from_parts(219_649_351, 936) - // Standard Error: 9_157 - .saturating_add(Weight::from_parts(4_846_108, 0).saturating_mul(r.into())) + // Measured: `835 + r * (296 ±0)` + // Estimated: `840 + r * (297 ±0)` + // Minimum execution time: 232_696_000 picoseconds. + Weight::from_parts(144_147_151, 840) + // Standard Error: 8_846 + .saturating_add(Weight::from_parts(4_931_414, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1050,12 +1052,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 16384]`. fn seal_get_storage_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1307 + n * (1 ±0)` - // Estimated: `1304 + n * (1 ±0)` - // Minimum execution time: 312_106_000 picoseconds. - Weight::from_parts(315_905_779, 1304) - // Standard Error: 44 - .saturating_add(Weight::from_parts(674, 0).saturating_mul(n.into())) + // Measured: `1179 + n * (1 ±0)` + // Estimated: `1179 + n * (1 ±0)` + // Minimum execution time: 247_795_000 picoseconds. + Weight::from_parts(252_944_118, 1179) + // Standard Error: 45 + .saturating_add(Weight::from_parts(480, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -1065,12 +1067,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 800]`. fn seal_contains_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `952 + r * (288 ±0)` - // Estimated: `953 + r * (289 ±0)` - // Minimum execution time: 299_372_000 picoseconds. - Weight::from_parts(211_293_493, 953) - // Standard Error: 8_509 - .saturating_add(Weight::from_parts(4_688_993, 0).saturating_mul(r.into())) + // Measured: `856 + r * (288 ±0)` + // Estimated: `857 + r * (289 ±0)` + // Minimum execution time: 232_166_000 picoseconds. + Weight::from_parts(148_503_428, 857) + // Standard Error: 8_704 + .saturating_add(Weight::from_parts(4_766_055, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1081,12 +1083,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 16384]`. fn seal_contains_storage_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1294 + n * (1 ±0)` - // Estimated: `1291 + n * (1 ±0)` - // Minimum execution time: 311_605_000 picoseconds. - Weight::from_parts(315_473_850, 1291) - // Standard Error: 37 - .saturating_add(Weight::from_parts(3, 0).saturating_mul(n.into())) + // Measured: `1166 + n * (1 ±0)` + // Estimated: `1166 + n * (1 ±0)` + // Minimum execution time: 246_128_000 picoseconds. + Weight::from_parts(248_323_705, 1166) + // Standard Error: 21 + .saturating_add(Weight::from_parts(92, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -1096,12 +1098,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 800]`. fn seal_take_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `925 + r * (296 ±0)` - // Estimated: `932 + r * (297 ±0)` - // Minimum execution time: 298_231_000 picoseconds. - Weight::from_parts(200_178_698, 932) - // Standard Error: 10_452 - .saturating_add(Weight::from_parts(6_107_653, 0).saturating_mul(r.into())) + // Measured: `829 + r * (296 ±0)` + // Estimated: `836 + r * (297 ±0)` + // Minimum execution time: 232_976_000 picoseconds. + Weight::from_parts(132_373_848, 836) + // Standard Error: 9_855 + .saturating_add(Weight::from_parts(6_181_821, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1113,12 +1115,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 16384]`. fn seal_take_storage_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1308 + n * (1 ±0)` - // Estimated: `1305 + n * (1 ±0)` - // Minimum execution time: 314_970_000 picoseconds. - Weight::from_parts(318_135_821, 1305) - // Standard Error: 26 - .saturating_add(Weight::from_parts(630, 0).saturating_mul(n.into())) + // Measured: `1180 + n * (1 ±0)` + // Estimated: `1180 + n * (1 ±0)` + // Minimum execution time: 247_907_000 picoseconds. + Weight::from_parts(251_984_133, 1180) + // Standard Error: 41 + .saturating_add(Weight::from_parts(639, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -1136,12 +1138,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_transfer(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1501 + r * (45 ±0)` - // Estimated: `27383 + r * (2700 ±0)` - // Minimum execution time: 299_629_000 picoseconds. - Weight::from_parts(150_915_187, 27383) - // Standard Error: 25_604 - .saturating_add(Weight::from_parts(20_859_844, 0).saturating_mul(r.into())) + // Measured: `1373 + r * (45 ±0)` + // Estimated: `26753 + r * (2700 ±0)` + // Minimum execution time: 232_614_000 picoseconds. + Weight::from_parts(127_024_367, 26753) + // Standard Error: 54_521 + .saturating_add(Weight::from_parts(20_975_575, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(4_u64)) @@ -1161,17 +1163,17 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_call(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1670 + r * (288 ±0)` - // Estimated: `27813 + r * (6391 ±0)` - // Minimum execution time: 299_578_000 picoseconds. - Weight::from_parts(300_036_000, 27813) - // Standard Error: 102_709 - .saturating_add(Weight::from_parts(283_767_316, 0).saturating_mul(r.into())) + // Measured: `1512 + r * (256 ±0)` + // Estimated: `27163 + r * (6231 ±0)` + // Minimum execution time: 233_446_000 picoseconds. + Weight::from_parts(234_338_000, 27163) + // Standard Error: 122_754 + .saturating_add(Weight::from_parts(216_709_600, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 6391).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 6231).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1186,17 +1188,17 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_delegate_call(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0 + r * (935 ±0)` - // Estimated: `22235 + r * (8322 ±10)` - // Minimum execution time: 298_943_000 picoseconds. - Weight::from_parts(299_619_000, 22235) - // Standard Error: 117_493 - .saturating_add(Weight::from_parts(280_555_517, 0).saturating_mul(r.into())) + // Measured: `0 + r * (902 ±0)` + // Estimated: `21755 + r * (8167 ±7)` + // Minimum execution time: 232_717_000 picoseconds. + Weight::from_parts(233_405_000, 21755) + // Standard Error: 98_607 + .saturating_add(Weight::from_parts(212_329_100, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 8322).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 8167).saturating_mul(r.into())) } /// Storage: System Account (r:3 w:2) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1212,19 +1214,19 @@ impl WeightInfo for SubstrateWeight { /// The range of component `c` is `[0, 1048576]`. fn seal_call_per_transfer_clone_byte(t: u32, c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1314 + t * (268 ±0)` - // Estimated: `31815 + t * (6290 ±0)` - // Minimum execution time: 453_013_000 picoseconds. - Weight::from_parts(442_536_283, 31815) - // Standard Error: 1_339_541 - .saturating_add(Weight::from_parts(17_062_445, 0).saturating_mul(t.into())) - // Standard Error: 1 - .saturating_add(Weight::from_parts(604, 0).saturating_mul(c.into())) + // Measured: `1154 + t * (204 ±0)` + // Estimated: `31015 + t * (5970 ±0)` + // Minimum execution time: 392_113_000 picoseconds. + Weight::from_parts(376_522_702, 31015) + // Standard Error: 1_388_011 + .saturating_add(Weight::from_parts(19_125_093, 0).saturating_mul(t.into())) + // Standard Error: 2 + .saturating_add(Weight::from_parts(609, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(t.into()))) .saturating_add(T::DbWeight::get().writes(5_u64)) .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(t.into()))) - .saturating_add(Weight::from_parts(0, 6290).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(0, 5970).saturating_mul(t.into())) } /// Storage: System Account (r:3202 w:3202) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1243,17 +1245,17 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_instantiate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1988 + r * (319 ±0)` - // Estimated: `34745 + r * (17090 ±0)` - // Minimum execution time: 300_123_000 picoseconds. - Weight::from_parts(300_406_000, 34745) - // Standard Error: 420_997 - .saturating_add(Weight::from_parts(382_704_025, 0).saturating_mul(r.into())) + // Measured: `1859 + r * (253 ±0)` + // Estimated: `33859 + r * (16628 ±0)` + // Minimum execution time: 234_438_000 picoseconds. + Weight::from_parts(234_751_000, 33859) + // Standard Error: 450_507 + .saturating_add(Weight::from_parts(313_121_404, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().reads((6_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(6_u64)) .saturating_add(T::DbWeight::get().writes((5_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 17090).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 16628).saturating_mul(r.into())) } /// Storage: System Account (r:4 w:4) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1274,21 +1276,21 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[0, 983040]`. fn seal_instantiate_per_transfer_input_salt_byte(t: u32, i: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1231 + t * (219 ±0)` - // Estimated: `43797 + t * (3812 ±2)` - // Minimum execution time: 1_636_322_000 picoseconds. - Weight::from_parts(360_859_331, 43797) - // Standard Error: 4_816_923 - .saturating_add(Weight::from_parts(109_179_023, 0).saturating_mul(t.into())) + // Measured: `1071 + t * (187 ±0)` + // Estimated: `42684 + t * (3588 ±2)` + // Minimum execution time: 1_570_178_000 picoseconds. + Weight::from_parts(284_062_841, 42684) + // Standard Error: 4_396_597 + .saturating_add(Weight::from_parts(106_424_960, 0).saturating_mul(t.into())) // Standard Error: 7 - .saturating_add(Weight::from_parts(1_180, 0).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(1_183, 0).saturating_mul(i.into())) // Standard Error: 7 - .saturating_add(Weight::from_parts(1_344, 0).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_354, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(13_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(t.into()))) .saturating_add(T::DbWeight::get().writes(10_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(t.into()))) - .saturating_add(Weight::from_parts(0, 3812).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(0, 3588).saturating_mul(t.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1303,12 +1305,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_hash_sha2_256(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `873 + r * (8 ±0)` - // Estimated: `22190 + r * (40 ±0)` - // Minimum execution time: 297_521_000 picoseconds. - Weight::from_parts(303_523_260, 22190) - // Standard Error: 1_162 - .saturating_add(Weight::from_parts(542_201, 0).saturating_mul(r.into())) + // Measured: `777 + r * (8 ±0)` + // Estimated: `21710 + r * (40 ±0)` + // Minimum execution time: 230_557_000 picoseconds. + Weight::from_parts(233_276_698, 21710) + // Standard Error: 1_026 + .saturating_add(Weight::from_parts(587_723, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) @@ -1326,12 +1328,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 1048576]`. fn seal_hash_sha2_256_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `881` - // Estimated: `22225` - // Minimum execution time: 299_877_000 picoseconds. - Weight::from_parts(293_538_014, 22225) - // Standard Error: 2 - .saturating_add(Weight::from_parts(3_967, 0).saturating_mul(n.into())) + // Measured: `785` + // Estimated: `21745` + // Minimum execution time: 234_151_000 picoseconds. + Weight::from_parts(240_199_365, 21745) + // Standard Error: 3 + .saturating_add(Weight::from_parts(3_941, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1348,12 +1350,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_hash_keccak_256(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `875 + r * (8 ±0)` - // Estimated: `22205 + r * (40 ±0)` - // Minimum execution time: 297_672_000 picoseconds. - Weight::from_parts(299_933_312, 22205) - // Standard Error: 1_138 - .saturating_add(Weight::from_parts(713_189, 0).saturating_mul(r.into())) + // Measured: `779 + r * (8 ±0)` + // Estimated: `21725 + r * (40 ±0)` + // Minimum execution time: 229_931_000 picoseconds. + Weight::from_parts(234_961_690, 21725) + // Standard Error: 1_073 + .saturating_add(Weight::from_parts(758_259, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) @@ -1371,12 +1373,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 1048576]`. fn seal_hash_keccak_256_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `883` - // Estimated: `22245` - // Minimum execution time: 299_048_000 picoseconds. - Weight::from_parts(293_055_982, 22245) + // Measured: `787` + // Estimated: `21765` + // Minimum execution time: 232_448_000 picoseconds. + Weight::from_parts(225_974_008, 21765) // Standard Error: 2 - .saturating_add(Weight::from_parts(3_179, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(3_174, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1393,12 +1395,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_hash_blake2_256(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `875 + r * (8 ±0)` - // Estimated: `22220 + r * (40 ±0)` - // Minimum execution time: 301_991_000 picoseconds. - Weight::from_parts(300_027_441, 22220) - // Standard Error: 981 - .saturating_add(Weight::from_parts(391_319, 0).saturating_mul(r.into())) + // Measured: `779 + r * (8 ±0)` + // Estimated: `21740 + r * (40 ±0)` + // Minimum execution time: 229_251_000 picoseconds. + Weight::from_parts(234_182_627, 21740) + // Standard Error: 836 + .saturating_add(Weight::from_parts(424_375, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) @@ -1416,12 +1418,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 1048576]`. fn seal_hash_blake2_256_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `883` - // Estimated: `22265` - // Minimum execution time: 296_522_000 picoseconds. - Weight::from_parts(296_121_638, 22265) + // Measured: `787` + // Estimated: `21785` + // Minimum execution time: 230_896_000 picoseconds. + Weight::from_parts(224_913_556, 21785) // Standard Error: 2 - .saturating_add(Weight::from_parts(916, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(919, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1438,12 +1440,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_hash_blake2_128(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `875 + r * (8 ±0)` - // Estimated: `22225 + r * (40 ±0)` - // Minimum execution time: 296_228_000 picoseconds. - Weight::from_parts(301_472_299, 22225) - // Standard Error: 875 - .saturating_add(Weight::from_parts(381_027, 0).saturating_mul(r.into())) + // Measured: `779 + r * (8 ±0)` + // Estimated: `21745 + r * (40 ±0)` + // Minimum execution time: 230_314_000 picoseconds. + Weight::from_parts(233_426_327, 21745) + // Standard Error: 926 + .saturating_add(Weight::from_parts(425_341, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) @@ -1461,12 +1463,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 1048576]`. fn seal_hash_blake2_128_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `883` - // Estimated: `22235` - // Minimum execution time: 296_644_000 picoseconds. - Weight::from_parts(289_879_744, 22235) + // Measured: `787` + // Estimated: `21755` + // Minimum execution time: 230_424_000 picoseconds. + Weight::from_parts(231_136_218, 21755) // Standard Error: 2 - .saturating_add(Weight::from_parts(925, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(917, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1483,12 +1485,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_ecdsa_recover(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `800 + r * (78 ±0)` - // Estimated: `21845 + r * (390 ±0)` - // Minimum execution time: 297_804_000 picoseconds. - Weight::from_parts(471_994_534, 21845) - // Standard Error: 9_479 - .saturating_add(Weight::from_parts(36_886_028, 0).saturating_mul(r.into())) + // Measured: `704 + r * (78 ±0)` + // Estimated: `21370 + r * (390 ±0)` + // Minimum execution time: 232_862_000 picoseconds. + Weight::from_parts(379_152_870, 21370) + // Standard Error: 11_607 + .saturating_add(Weight::from_parts(36_955_410, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 390).saturating_mul(r.into())) @@ -1506,12 +1508,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `645 + r * (44 ±0)` - // Estimated: `21110 + r * (220 ±0)` - // Minimum execution time: 298_623_000 picoseconds. - Weight::from_parts(322_192_102, 21110) - // Standard Error: 3_207 - .saturating_add(Weight::from_parts(9_243_653, 0).saturating_mul(r.into())) + // Measured: `549 + r * (44 ±0)` + // Estimated: `20630 + r * (220 ±0)` + // Minimum execution time: 232_668_000 picoseconds. + Weight::from_parts(253_308_468, 20630) + // Standard Error: 3_022 + .saturating_add(Weight::from_parts(9_249_849, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 220).saturating_mul(r.into())) @@ -1531,17 +1533,17 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_set_code_hash(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0 + r * (1030 ±0)` - // Estimated: `30592 + r * (11919 ±7)` - // Minimum execution time: 298_574_000 picoseconds. - Weight::from_parts(299_383_000, 30592) - // Standard Error: 44_061 - .saturating_add(Weight::from_parts(21_625_366, 0).saturating_mul(r.into())) + // Measured: `0 + r * (964 ±0)` + // Estimated: `29920 + r * (11544 ±7)` + // Minimum execution time: 233_910_000 picoseconds. + Weight::from_parts(234_607_000, 29920) + // Standard Error: 46_118 + .saturating_add(Weight::from_parts(21_927_957, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 11919).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 11544).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1556,12 +1558,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_reentrance_count(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `869 + r * (3 ±0)` - // Estimated: `22215 + r * (15 ±0)` - // Minimum execution time: 297_014_000 picoseconds. - Weight::from_parts(301_226_615, 22215) - // Standard Error: 439 - .saturating_add(Weight::from_parts(143_017, 0).saturating_mul(r.into())) + // Measured: `773 + r * (3 ±0)` + // Estimated: `21735 + r * (15 ±0)` + // Minimum execution time: 231_823_000 picoseconds. + Weight::from_parts(237_996_137, 21735) + // Standard Error: 598 + .saturating_add(Weight::from_parts(163_106, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 15).saturating_mul(r.into())) @@ -1579,12 +1581,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_account_reentrance_count(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2072 + r * (39 ±0)` - // Estimated: `27645 + r * (200 ±0)` - // Minimum execution time: 299_074_000 picoseconds. - Weight::from_parts(336_979_016, 27645) - // Standard Error: 1_163 - .saturating_add(Weight::from_parts(227_998, 0).saturating_mul(r.into())) + // Measured: `1975 + r * (39 ±0)` + // Estimated: `27145 + r * (200 ±0)` + // Minimum execution time: 235_077_000 picoseconds. + Weight::from_parts(267_876_360, 27145) + // Standard Error: 1_147 + .saturating_add(Weight::from_parts(256_275, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 200).saturating_mul(r.into())) @@ -1604,12 +1606,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 1600]`. fn seal_instantiation_nonce(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `872 + r * (3 ±0)` - // Estimated: `24580 + r * (18 ±0)` - // Minimum execution time: 296_959_000 picoseconds. - Weight::from_parts(303_796_839, 24580) + // Measured: `776 + r * (3 ±0)` + // Estimated: `24004 + r * (18 ±0)` + // Minimum execution time: 231_384_000 picoseconds. + Weight::from_parts(237_086_900, 24004) // Standard Error: 534 - .saturating_add(Weight::from_parts(118_978, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(140_842, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 18).saturating_mul(r.into())) @@ -1619,508 +1621,510 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_020_000 picoseconds. - Weight::from_parts(1_355_107, 0) - // Standard Error: 1 - .saturating_add(Weight::from_parts(4_110, 0).saturating_mul(r.into())) + // Minimum execution time: 1_721_000 picoseconds. + Weight::from_parts(2_456_746, 0) + // Standard Error: 30 + .saturating_add(Weight::from_parts(2_788, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64load(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_224_000 picoseconds. - Weight::from_parts(1_819_284, 0) - // Standard Error: 10 - .saturating_add(Weight::from_parts(10_803, 0).saturating_mul(r.into())) + // Minimum execution time: 1_824_000 picoseconds. + Weight::from_parts(2_366_036, 0) + // Standard Error: 5 + .saturating_add(Weight::from_parts(6_446, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64store(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_216_000 picoseconds. - Weight::from_parts(1_795_011, 0) - // Standard Error: 5 - .saturating_add(Weight::from_parts(10_000, 0).saturating_mul(r.into())) + // Minimum execution time: 1_840_000 picoseconds. + Weight::from_parts(2_332_115, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(6_012, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_select(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_127_000 picoseconds. - Weight::from_parts(1_491_730, 0) - // Standard Error: 4 - .saturating_add(Weight::from_parts(11_471, 0).saturating_mul(r.into())) + // Minimum execution time: 1_731_000 picoseconds. + Weight::from_parts(2_078_873, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(7_931, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_if(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_044_000 picoseconds. - Weight::from_parts(2_330_852, 0) - // Standard Error: 69 - .saturating_add(Weight::from_parts(12_866, 0).saturating_mul(r.into())) + // Minimum execution time: 1_768_000 picoseconds. + Weight::from_parts(1_916_551, 0) + // Standard Error: 8 + .saturating_add(Weight::from_parts(10_597, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_br(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_067_000 picoseconds. - Weight::from_parts(1_399_626, 0) - // Standard Error: 5 - .saturating_add(Weight::from_parts(6_430, 0).saturating_mul(r.into())) + // Minimum execution time: 1_735_000 picoseconds. + Weight::from_parts(1_962_845, 0) + // Standard Error: 14 + .saturating_add(Weight::from_parts(4_631, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_br_if(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_087_000 picoseconds. - Weight::from_parts(1_463_592, 0) - // Standard Error: 12 - .saturating_add(Weight::from_parts(9_707, 0).saturating_mul(r.into())) + // Minimum execution time: 1_688_000 picoseconds. + Weight::from_parts(1_172_825, 0) + // Standard Error: 76 + .saturating_add(Weight::from_parts(8_007, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_br_table(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_110_000 picoseconds. - Weight::from_parts(1_058_258, 0) - // Standard Error: 22 - .saturating_add(Weight::from_parts(11_713, 0).saturating_mul(r.into())) + // Minimum execution time: 1_725_000 picoseconds. + Weight::from_parts(1_535_833, 0) + // Standard Error: 26 + .saturating_add(Weight::from_parts(9_489, 0).saturating_mul(r.into())) } /// The range of component `e` is `[1, 256]`. - fn instr_br_table_per_entry(_e: u32, ) -> Weight { + fn instr_br_table_per_entry(e: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_189_000 picoseconds. - Weight::from_parts(1_416_188, 0) + // Minimum execution time: 1_814_000 picoseconds. + Weight::from_parts(1_926_367, 0) + // Standard Error: 16 + .saturating_add(Weight::from_parts(219, 0).saturating_mul(e.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_call(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_201_000 picoseconds. - Weight::from_parts(3_375_851, 0) - // Standard Error: 96 - .saturating_add(Weight::from_parts(22_970, 0).saturating_mul(r.into())) + // Minimum execution time: 1_770_000 picoseconds. + Weight::from_parts(2_436_918, 0) + // Standard Error: 8 + .saturating_add(Weight::from_parts(17_890, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_call_indirect(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_286_000 picoseconds. - Weight::from_parts(2_817_725, 0) - // Standard Error: 55 - .saturating_add(Weight::from_parts(29_437, 0).saturating_mul(r.into())) + // Minimum execution time: 1_920_000 picoseconds. + Weight::from_parts(2_729_712, 0) + // Standard Error: 39 + .saturating_add(Weight::from_parts(24_853, 0).saturating_mul(r.into())) } /// The range of component `l` is `[0, 1024]`. fn instr_call_per_local(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_319_000 picoseconds. - Weight::from_parts(1_636_286, 0) - // Standard Error: 31 - .saturating_add(Weight::from_parts(1_240, 0).saturating_mul(l.into())) + // Minimum execution time: 1_869_000 picoseconds. + Weight::from_parts(2_147_970, 0) + // Standard Error: 46 + .saturating_add(Weight::from_parts(1_237, 0).saturating_mul(l.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_local_get(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_507_000 picoseconds. - Weight::from_parts(2_785_119, 0) + // Minimum execution time: 3_012_000 picoseconds. + Weight::from_parts(3_234_440, 0) // Standard Error: 1 - .saturating_add(Weight::from_parts(4_601, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(2_433, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_local_set(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_494_000 picoseconds. - Weight::from_parts(2_948_015, 0) - // Standard Error: 14 - .saturating_add(Weight::from_parts(4_788, 0).saturating_mul(r.into())) + // Minimum execution time: 3_037_000 picoseconds. + Weight::from_parts(3_204_600, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(3_627, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_local_tee(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_443_000 picoseconds. - Weight::from_parts(3_065_273, 0) - // Standard Error: 15 - .saturating_add(Weight::from_parts(6_489, 0).saturating_mul(r.into())) + // Minimum execution time: 2_974_000 picoseconds. + Weight::from_parts(3_301_366, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(3_836, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_global_get(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_214_000 picoseconds. - Weight::from_parts(1_634_049, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(8_960, 0).saturating_mul(r.into())) + // Minimum execution time: 1_853_000 picoseconds. + Weight::from_parts(2_310_141, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(8_387, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_global_set(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_180_000 picoseconds. - Weight::from_parts(1_555_599, 0) + // Minimum execution time: 1_828_000 picoseconds. + Weight::from_parts(2_315_323, 0) // Standard Error: 4 - .saturating_add(Weight::from_parts(9_205, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(8_797, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_memory_current(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_223_000 picoseconds. - Weight::from_parts(1_626_002, 0) - // Standard Error: 5 - .saturating_add(Weight::from_parts(8_181, 0).saturating_mul(r.into())) + // Minimum execution time: 1_800_000 picoseconds. + Weight::from_parts(2_117_252, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(3_741, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 16]`. fn instr_memory_grow(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_148_000 picoseconds. - Weight::from_parts(307_155, 0) - // Standard Error: 138_541 - .saturating_add(Weight::from_parts(13_291_570, 0).saturating_mul(r.into())) + // Minimum execution time: 1_743_000 picoseconds. + Weight::from_parts(1_054_728, 0) + // Standard Error: 137_128 + .saturating_add(Weight::from_parts(13_179_446, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64clz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_079_000 picoseconds. - Weight::from_parts(1_372_409, 0) - // Standard Error: 50 - .saturating_add(Weight::from_parts(6_427, 0).saturating_mul(r.into())) + // Minimum execution time: 1_735_000 picoseconds. + Weight::from_parts(2_026_568, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(3_802, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64ctz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_116_000 picoseconds. - Weight::from_parts(1_415_180, 0) + // Minimum execution time: 1_630_000 picoseconds. + Weight::from_parts(1_980_222, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(6_353, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_735, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64popcnt(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_058_000 picoseconds. - Weight::from_parts(1_314_206, 0) - // Standard Error: 35 - .saturating_add(Weight::from_parts(6_431, 0).saturating_mul(r.into())) + // Minimum execution time: 1_695_000 picoseconds. + Weight::from_parts(2_040_266, 0) + // Standard Error: 8 + .saturating_add(Weight::from_parts(3_718, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64eqz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_059_000 picoseconds. - Weight::from_parts(1_455_331, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(6_507, 0).saturating_mul(r.into())) + // Minimum execution time: 1_697_000 picoseconds. + Weight::from_parts(2_004_663, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(3_661, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64extendsi32(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_057_000 picoseconds. - Weight::from_parts(1_421_085, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(6_177, 0).saturating_mul(r.into())) + // Minimum execution time: 1_705_000 picoseconds. + Weight::from_parts(2_682_122, 0) + // Standard Error: 98 + .saturating_add(Weight::from_parts(3_705, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64extendui32(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_079_000 picoseconds. - Weight::from_parts(1_429_275, 0) + // Minimum execution time: 1_674_000 picoseconds. + Weight::from_parts(1_989_835, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(6_175, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_801, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i32wrapi64(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_065_000 picoseconds. - Weight::from_parts(1_403_813, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(6_192, 0).saturating_mul(r.into())) + // Minimum execution time: 1_695_000 picoseconds. + Weight::from_parts(2_083_824, 0) + // Standard Error: 17 + .saturating_add(Weight::from_parts(3_719, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64eq(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_061_000 picoseconds. - Weight::from_parts(1_421_984, 0) + // Minimum execution time: 1_678_000 picoseconds. + Weight::from_parts(1_996_335, 0) // Standard Error: 4 - .saturating_add(Weight::from_parts(9_094, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(5_995, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64ne(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_075_000 picoseconds. - Weight::from_parts(1_431_453, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(9_084, 0).saturating_mul(r.into())) + // Minimum execution time: 1_697_000 picoseconds. + Weight::from_parts(2_046_566, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(5_936, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64lts(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_100_000 picoseconds. - Weight::from_parts(1_452_384, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(9_081, 0).saturating_mul(r.into())) + // Minimum execution time: 1_721_000 picoseconds. + Weight::from_parts(2_406_930, 0) + // Standard Error: 150 + .saturating_add(Weight::from_parts(5_992, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64ltu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_090_000 picoseconds. - Weight::from_parts(1_466_416, 0) - // Standard Error: 17 - .saturating_add(Weight::from_parts(9_091, 0).saturating_mul(r.into())) + // Minimum execution time: 1_749_000 picoseconds. + Weight::from_parts(1_987_158, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(5_994, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64gts(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_056_000 picoseconds. - Weight::from_parts(1_676_091, 0) - // Standard Error: 47 - .saturating_add(Weight::from_parts(9_082, 0).saturating_mul(r.into())) + // Minimum execution time: 1_706_000 picoseconds. + Weight::from_parts(2_038_138, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(5_802, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64gtu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_053_000 picoseconds. - Weight::from_parts(1_232_790, 0) - // Standard Error: 43 - .saturating_add(Weight::from_parts(9_329, 0).saturating_mul(r.into())) + // Minimum execution time: 1_670_000 picoseconds. + Weight::from_parts(2_555_035, 0) + // Standard Error: 74 + .saturating_add(Weight::from_parts(5_958, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64les(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_091_000 picoseconds. - Weight::from_parts(1_476_212, 0) - // Standard Error: 4 - .saturating_add(Weight::from_parts(9_074, 0).saturating_mul(r.into())) + // Minimum execution time: 1_694_000 picoseconds. + Weight::from_parts(1_991_929, 0) + // Standard Error: 27 + .saturating_add(Weight::from_parts(6_037, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64leu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_083_000 picoseconds. - Weight::from_parts(1_484_966, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(9_184, 0).saturating_mul(r.into())) + // Minimum execution time: 1_684_000 picoseconds. + Weight::from_parts(1_969_284, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(6_104, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64ges(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_089_000 picoseconds. - Weight::from_parts(1_516_766, 0) - // Standard Error: 4 - .saturating_add(Weight::from_parts(9_063, 0).saturating_mul(r.into())) + // Minimum execution time: 1_697_000 picoseconds. + Weight::from_parts(2_023_608, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(5_946, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64geu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 996_000 picoseconds. - Weight::from_parts(1_460_638, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(9_076, 0).saturating_mul(r.into())) + // Minimum execution time: 1_659_000 picoseconds. + Weight::from_parts(1_963_145, 0) + // Standard Error: 6 + .saturating_add(Weight::from_parts(6_014, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64add(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_095_000 picoseconds. - Weight::from_parts(1_448_412, 0) + // Minimum execution time: 1_722_000 picoseconds. + Weight::from_parts(2_016_286, 0) // Standard Error: 3 - .saturating_add(Weight::from_parts(8_977, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(5_889, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64sub(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_071_000 picoseconds. - Weight::from_parts(1_459_165, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(8_852, 0).saturating_mul(r.into())) + // Minimum execution time: 1_656_000 picoseconds. + Weight::from_parts(1_966_234, 0) + // Standard Error: 17 + .saturating_add(Weight::from_parts(6_171, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64mul(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_082_000 picoseconds. - Weight::from_parts(1_450_718, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(8_860, 0).saturating_mul(r.into())) + // Minimum execution time: 1_695_000 picoseconds. + Weight::from_parts(2_004_559, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(5_785, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64divs(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_065_000 picoseconds. - Weight::from_parts(1_436_871, 0) - // Standard Error: 9 - .saturating_add(Weight::from_parts(15_241, 0).saturating_mul(r.into())) + // Minimum execution time: 1_681_000 picoseconds. + Weight::from_parts(2_135_505, 0) + // Standard Error: 6 + .saturating_add(Weight::from_parts(11_761, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64divu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_065_000 picoseconds. - Weight::from_parts(1_423_806, 0) - // Standard Error: 17 - .saturating_add(Weight::from_parts(14_706, 0).saturating_mul(r.into())) + // Minimum execution time: 1_653_000 picoseconds. + Weight::from_parts(2_153_167, 0) + // Standard Error: 5 + .saturating_add(Weight::from_parts(10_523, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64rems(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_059_000 picoseconds. - Weight::from_parts(1_735_816, 0) - // Standard Error: 66 - .saturating_add(Weight::from_parts(15_230, 0).saturating_mul(r.into())) + // Minimum execution time: 1_697_000 picoseconds. + Weight::from_parts(2_570_266, 0) + // Standard Error: 50 + .saturating_add(Weight::from_parts(11_971, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64remu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_076_000 picoseconds. - Weight::from_parts(1_451_290, 0) - // Standard Error: 6 - .saturating_add(Weight::from_parts(14_530, 0).saturating_mul(r.into())) + // Minimum execution time: 1_719_000 picoseconds. + Weight::from_parts(2_101_082, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(10_709, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64and(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_079_000 picoseconds. - Weight::from_parts(1_457_537, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(8_963, 0).saturating_mul(r.into())) + // Minimum execution time: 1_745_000 picoseconds. + Weight::from_parts(2_621_890, 0) + // Standard Error: 94 + .saturating_add(Weight::from_parts(5_545, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64or(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_032_000 picoseconds. - Weight::from_parts(1_475_315, 0) - // Standard Error: 4 - .saturating_add(Weight::from_parts(8_956, 0).saturating_mul(r.into())) + // Minimum execution time: 1_670_000 picoseconds. + Weight::from_parts(2_046_821, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(5_762, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64xor(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_056_000 picoseconds. - Weight::from_parts(1_450_071, 0) + // Minimum execution time: 1_714_000 picoseconds. + Weight::from_parts(2_010_173, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(8_960, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(5_911, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64shl(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_116_000 picoseconds. - Weight::from_parts(1_429_705, 0) + // Minimum execution time: 1_756_000 picoseconds. + Weight::from_parts(2_044_772, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(9_027, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(5_857, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64shrs(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_059_000 picoseconds. - Weight::from_parts(1_429_307, 0) - // Standard Error: 4 - .saturating_add(Weight::from_parts(9_048, 0).saturating_mul(r.into())) + // Minimum execution time: 1_741_000 picoseconds. + Weight::from_parts(2_012_819, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(6_127, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64shru(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_093_000 picoseconds. - Weight::from_parts(1_411_827, 0) - // Standard Error: 4 - .saturating_add(Weight::from_parts(9_528, 0).saturating_mul(r.into())) + // Minimum execution time: 1_693_000 picoseconds. + Weight::from_parts(2_090_981, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(5_839, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64rotl(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_115_000 picoseconds. - Weight::from_parts(1_441_025, 0) + // Minimum execution time: 1_704_000 picoseconds. + Weight::from_parts(2_014_108, 0) // Standard Error: 4 - .saturating_add(Weight::from_parts(9_043, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(6_005, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64rotr(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_077_000 picoseconds. - Weight::from_parts(1_480_666, 0) - // Standard Error: 4 - .saturating_add(Weight::from_parts(9_031, 0).saturating_mul(r.into())) + // Minimum execution time: 1_715_000 picoseconds. + Weight::from_parts(2_053_720, 0) + // Standard Error: 5 + .saturating_add(Weight::from_parts(5_860, 0).saturating_mul(r.into())) } } @@ -2132,8 +2136,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `109` // Estimated: `1594` - // Minimum execution time: 2_736_000 picoseconds. - Weight::from_parts(2_931_000, 1594) + // Minimum execution time: 2_567_000 picoseconds. + Weight::from_parts(2_711_000, 1594) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: Skipped Metadata (r:0 w:0) @@ -2141,12 +2145,12 @@ impl WeightInfo for () { /// The range of component `k` is `[0, 1024]`. fn on_initialize_per_trie_key(k: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `481 + k * (69 ±0)` - // Estimated: `471 + k * (70 ±0)` - // Minimum execution time: 10_759_000 picoseconds. - Weight::from_parts(6_965_683, 471) - // Standard Error: 1_019 - .saturating_add(Weight::from_parts(961_947, 0).saturating_mul(k.into())) + // Measured: `450 + k * (69 ±0)` + // Estimated: `440 + k * (70 ±0)` + // Minimum execution time: 11_048_000 picoseconds. + Weight::from_parts(7_029_322, 440) + // Standard Error: 1_158 + .saturating_add(Weight::from_parts(975_010, 0).saturating_mul(k.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) @@ -2158,12 +2162,12 @@ impl WeightInfo for () { /// The range of component `q` is `[0, 128]`. fn on_initialize_per_queue_item(q: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `281 + q * (33 ±0)` - // Estimated: `1753 + q * (33 ±0)` - // Minimum execution time: 2_633_000 picoseconds. - Weight::from_parts(10_668_837, 1753) - // Standard Error: 3_538 - .saturating_add(Weight::from_parts(1_277_168, 0).saturating_mul(q.into())) + // Measured: `250 + q * (33 ±0)` + // Estimated: `1725 + q * (33 ±0)` + // Minimum execution time: 2_645_000 picoseconds. + Weight::from_parts(10_865_477, 1725) + // Standard Error: 3_383 + .saturating_add(Weight::from_parts(1_295_351, 0).saturating_mul(q.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 33).saturating_mul(q.into())) @@ -2175,12 +2179,12 @@ impl WeightInfo for () { /// The range of component `c` is `[0, 61717]`. fn reinstrument(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `270 + c * (1 ±0)` - // Estimated: `4015 + c * (2 ±0)` - // Minimum execution time: 30_264_000 picoseconds. - Weight::from_parts(27_106_554, 4015) - // Standard Error: 53 - .saturating_add(Weight::from_parts(49_705, 0).saturating_mul(c.into())) + // Measured: `238 + c * (1 ±0)` + // Estimated: `3951 + c * (2 ±0)` + // Minimum execution time: 30_817_000 picoseconds. + Weight::from_parts(29_762_622, 3951) + // Standard Error: 62 + .saturating_add(Weight::from_parts(54_714, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 2).saturating_mul(c.into())) @@ -2198,12 +2202,12 @@ impl WeightInfo for () { /// The range of component `c` is `[0, 125952]`. fn call_with_code_per_byte(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `803` - // Estimated: `21880 + c * (5 ±0)` - // Minimum execution time: 309_249_000 picoseconds. - Weight::from_parts(323_353_590, 21880) - // Standard Error: 25 - .saturating_add(Weight::from_parts(31_359, 0).saturating_mul(c.into())) + // Measured: `707` + // Estimated: `21400 + c * (5 ±0)` + // Minimum execution time: 245_493_000 picoseconds. + Weight::from_parts(253_703_384, 21400) + // Standard Error: 27 + .saturating_add(Weight::from_parts(38_078, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 5).saturating_mul(c.into())) @@ -2231,14 +2235,14 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `270` // Estimated: `26207` - // Minimum execution time: 3_136_707_000 picoseconds. - Weight::from_parts(564_055_378, 26207) - // Standard Error: 286 - .saturating_add(Weight::from_parts(93_308, 0).saturating_mul(c.into())) - // Standard Error: 16 - .saturating_add(Weight::from_parts(1_165, 0).saturating_mul(i.into())) - // Standard Error: 16 - .saturating_add(Weight::from_parts(1_435, 0).saturating_mul(s.into())) + // Minimum execution time: 3_079_430_000 picoseconds. + Weight::from_parts(555_022_483, 26207) + // Standard Error: 290 + .saturating_add(Weight::from_parts(107_411, 0).saturating_mul(c.into())) + // Standard Error: 17 + .saturating_add(Weight::from_parts(1_123, 0).saturating_mul(i.into())) + // Standard Error: 17 + .saturating_add(Weight::from_parts(1_434, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(10_u64)) } @@ -2260,14 +2264,14 @@ impl WeightInfo for () { /// The range of component `s` is `[0, 1048576]`. fn instantiate(i: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `546` - // Estimated: `28969` - // Minimum execution time: 1_631_314_000 picoseconds. - Weight::from_parts(236_693_159, 28969) + // Measured: `482` + // Estimated: `28521` + // Minimum execution time: 1_600_733_000 picoseconds. + Weight::from_parts(228_681_962, 28521) // Standard Error: 8 - .saturating_add(Weight::from_parts(1_434, 0).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(1_445, 0).saturating_mul(i.into())) // Standard Error: 8 - .saturating_add(Weight::from_parts(1_445, 0).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_456, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } @@ -2283,10 +2287,10 @@ impl WeightInfo for () { /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) fn call() -> Weight { // Proof Size summary in bytes: - // Measured: `855` - // Estimated: `22095` - // Minimum execution time: 167_139_000 picoseconds. - Weight::from_parts(168_034_000, 22095) + // Measured: `759` + // Estimated: `21615` + // Minimum execution time: 172_310_000 picoseconds. + Weight::from_parts(176_655_000, 21615) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -2303,10 +2307,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `109` // Estimated: `7366` - // Minimum execution time: 306_518_000 picoseconds. - Weight::from_parts(325_652_407, 7366) - // Standard Error: 134 - .saturating_add(Weight::from_parts(93_502, 0).saturating_mul(c.into())) + // Minimum execution time: 246_364_000 picoseconds. + Weight::from_parts(262_887_234, 7366) + // Standard Error: 90 + .saturating_add(Weight::from_parts(107_926, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -2320,10 +2324,10 @@ impl WeightInfo for () { /// Proof: Contracts PristineCode (max_values: None, max_size: Some(125988), added: 128463, mode: Measured) fn remove_code() -> Weight { // Proof Size summary in bytes: - // Measured: `287` - // Estimated: `8078` - // Minimum execution time: 29_084_000 picoseconds. - Weight::from_parts(29_350_000, 8078) + // Measured: `255` + // Estimated: `7950` + // Minimum execution time: 29_226_000 picoseconds. + Weight::from_parts(29_542_000, 7950) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -2335,10 +2339,10 @@ impl WeightInfo for () { /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) fn set_code() -> Weight { // Proof Size summary in bytes: - // Measured: `666` - // Estimated: `19818` - // Minimum execution time: 32_996_000 picoseconds. - Weight::from_parts(33_365_000, 19818) + // Measured: `570` + // Estimated: `19530` + // Minimum execution time: 33_921_000 picoseconds. + Weight::from_parts(35_056_000, 19530) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -2355,12 +2359,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_caller(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `877 + r * (6 ±0)` - // Estimated: `22210 + r * (30 ±0)` - // Minimum execution time: 298_315_000 picoseconds. - Weight::from_parts(304_612_433, 22210) - // Standard Error: 904 - .saturating_add(Weight::from_parts(285_473, 0).saturating_mul(r.into())) + // Measured: `781 + r * (6 ±0)` + // Estimated: `21730 + r * (30 ±0)` + // Minimum execution time: 232_118_000 picoseconds. + Weight::from_parts(233_883_823, 21730) + // Standard Error: 642 + .saturating_add(Weight::from_parts(340_543, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -2378,16 +2382,16 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_is_contract(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `935 + r * (272 ±0)` - // Estimated: `22315 + r * (3835 ±0)` - // Minimum execution time: 299_169_000 picoseconds. - Weight::from_parts(138_157_704, 22315) - // Standard Error: 6_115 - .saturating_add(Weight::from_parts(3_244_482, 0).saturating_mul(r.into())) + // Measured: `839 + r * (240 ±0)` + // Estimated: `21835 + r * (3675 ±0)` + // Minimum execution time: 231_712_000 picoseconds. + Weight::from_parts(74_297_097, 21835) + // Standard Error: 6_099 + .saturating_add(Weight::from_parts(3_322_192, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 3835).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 3675).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2402,16 +2406,16 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_code_hash(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `927 + r * (276 ±0)` - // Estimated: `22335 + r * (3855 ±0)` - // Minimum execution time: 299_262_000 picoseconds. - Weight::from_parts(157_105_627, 22335) - // Standard Error: 5_634 - .saturating_add(Weight::from_parts(3_995_666, 0).saturating_mul(r.into())) + // Measured: `831 + r * (244 ±0)` + // Estimated: `21855 + r * (3695 ±0)` + // Minimum execution time: 233_122_000 picoseconds. + Weight::from_parts(74_369_473, 21855) + // Standard Error: 6_027 + .saturating_add(Weight::from_parts(4_177_187, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 3855).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 3695).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2426,12 +2430,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_own_code_hash(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `884 + r * (6 ±0)` - // Estimated: `22250 + r * (30 ±0)` - // Minimum execution time: 298_259_000 picoseconds. - Weight::from_parts(303_498_245, 22250) - // Standard Error: 874 - .saturating_add(Weight::from_parts(352_839, 0).saturating_mul(r.into())) + // Measured: `788 + r * (6 ±0)` + // Estimated: `21770 + r * (30 ±0)` + // Minimum execution time: 232_822_000 picoseconds. + Weight::from_parts(232_507_418, 21770) + // Standard Error: 961 + .saturating_add(Weight::from_parts(419_331, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -2449,12 +2453,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_caller_is_origin(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `874 + r * (3 ±0)` - // Estimated: `22215 + r * (15 ±0)` - // Minimum execution time: 295_689_000 picoseconds. - Weight::from_parts(314_004_541, 22215) - // Standard Error: 1_803 - .saturating_add(Weight::from_parts(131_102, 0).saturating_mul(r.into())) + // Measured: `778 + r * (3 ±0)` + // Estimated: `21735 + r * (15 ±0)` + // Minimum execution time: 229_719_000 picoseconds. + Weight::from_parts(235_257_789, 21735) + // Standard Error: 451 + .saturating_add(Weight::from_parts(161_101, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 15).saturating_mul(r.into())) @@ -2472,12 +2476,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_address(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `878 + r * (6 ±0)` - // Estimated: `22220 + r * (30 ±0)` - // Minimum execution time: 297_579_000 picoseconds. - Weight::from_parts(299_326_920, 22220) - // Standard Error: 990 - .saturating_add(Weight::from_parts(284_789, 0).saturating_mul(r.into())) + // Measured: `782 + r * (6 ±0)` + // Estimated: `21740 + r * (30 ±0)` + // Minimum execution time: 231_517_000 picoseconds. + Weight::from_parts(236_185_452, 21740) + // Standard Error: 651 + .saturating_add(Weight::from_parts(334_659, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -2495,12 +2499,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_gas_left(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `879 + r * (6 ±0)` - // Estimated: `22205 + r * (30 ±0)` - // Minimum execution time: 297_651_000 picoseconds. - Weight::from_parts(304_465_467, 22205) - // Standard Error: 736 - .saturating_add(Weight::from_parts(272_149, 0).saturating_mul(r.into())) + // Measured: `783 + r * (6 ±0)` + // Estimated: `21725 + r * (30 ±0)` + // Minimum execution time: 232_855_000 picoseconds. + Weight::from_parts(239_986_328, 21725) + // Standard Error: 4_075 + .saturating_add(Weight::from_parts(345_726, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -2518,12 +2522,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_balance(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1050 + r * (6 ±0)` - // Estimated: `25258 + r * (30 ±0)` - // Minimum execution time: 296_957_000 picoseconds. - Weight::from_parts(308_680_068, 25258) - // Standard Error: 1_377 - .saturating_add(Weight::from_parts(1_419_294, 0).saturating_mul(r.into())) + // Measured: `922 + r * (6 ±0)` + // Estimated: `24633 + r * (30 ±0)` + // Minimum execution time: 231_685_000 picoseconds. + Weight::from_parts(245_514_261, 24633) + // Standard Error: 1_635 + .saturating_add(Weight::from_parts(1_523_359, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -2541,12 +2545,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_value_transferred(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `888 + r * (6 ±0)` - // Estimated: `22305 + r * (30 ±0)` - // Minimum execution time: 297_735_000 picoseconds. - Weight::from_parts(301_533_807, 22305) - // Standard Error: 1_119 - .saturating_add(Weight::from_parts(277_289, 0).saturating_mul(r.into())) + // Measured: `792 + r * (6 ±0)` + // Estimated: `21825 + r * (30 ±0)` + // Minimum execution time: 233_361_000 picoseconds. + Weight::from_parts(234_553_471, 21825) + // Standard Error: 1_108 + .saturating_add(Weight::from_parts(330_383, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -2564,12 +2568,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_minimum_balance(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `886 + r * (6 ±0)` - // Estimated: `22295 + r * (30 ±0)` - // Minimum execution time: 299_599_000 picoseconds. - Weight::from_parts(303_664_496, 22295) - // Standard Error: 1_009 - .saturating_add(Weight::from_parts(280_353, 0).saturating_mul(r.into())) + // Measured: `790 + r * (6 ±0)` + // Estimated: `21815 + r * (30 ±0)` + // Minimum execution time: 231_918_000 picoseconds. + Weight::from_parts(239_128_416, 21815) + // Standard Error: 1_473 + .saturating_add(Weight::from_parts(317_879, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -2587,12 +2591,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_block_number(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `883 + r * (6 ±0)` - // Estimated: `22285 + r * (30 ±0)` - // Minimum execution time: 297_641_000 picoseconds. - Weight::from_parts(302_437_979, 22285) - // Standard Error: 669 - .saturating_add(Weight::from_parts(270_403, 0).saturating_mul(r.into())) + // Measured: `787 + r * (6 ±0)` + // Estimated: `21805 + r * (30 ±0)` + // Minimum execution time: 231_936_000 picoseconds. + Weight::from_parts(232_240_207, 21805) + // Standard Error: 731 + .saturating_add(Weight::from_parts(330_713, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -2610,12 +2614,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_now(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `874 + r * (6 ±0)` - // Estimated: `22215 + r * (30 ±0)` - // Minimum execution time: 297_217_000 picoseconds. - Weight::from_parts(299_538_157, 22215) - // Standard Error: 732 - .saturating_add(Weight::from_parts(280_800, 0).saturating_mul(r.into())) + // Measured: `778 + r * (6 ±0)` + // Estimated: `21735 + r * (30 ±0)` + // Minimum execution time: 231_978_000 picoseconds. + Weight::from_parts(224_881_201, 21735) + // Standard Error: 1_296 + .saturating_add(Weight::from_parts(346_872, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -2635,12 +2639,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_weight_to_fee(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `952 + r * (10 ±0)` - // Estimated: `25022 + r * (60 ±0)` - // Minimum execution time: 297_286_000 picoseconds. - Weight::from_parts(311_436_352, 25022) - // Standard Error: 6_811 - .saturating_add(Weight::from_parts(1_291_941, 0).saturating_mul(r.into())) + // Measured: `856 + r * (10 ±0)` + // Estimated: `24446 + r * (60 ±0)` + // Minimum execution time: 231_707_000 picoseconds. + Weight::from_parts(245_939_854, 24446) + // Standard Error: 1_369 + .saturating_add(Weight::from_parts(1_380_453, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 60).saturating_mul(r.into())) @@ -2658,12 +2662,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_gas(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `841 + r * (4 ±0)` - // Estimated: `22035 + r * (20 ±0)` - // Minimum execution time: 154_772_000 picoseconds. - Weight::from_parts(159_224_457, 22035) - // Standard Error: 212 - .saturating_add(Weight::from_parts(102_264, 0).saturating_mul(r.into())) + // Measured: `745 + r * (4 ±0)` + // Estimated: `21555 + r * (20 ±0)` + // Minimum execution time: 157_429_000 picoseconds. + Weight::from_parts(161_047_355, 21555) + // Standard Error: 1_220 + .saturating_add(Weight::from_parts(134_497, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 20).saturating_mul(r.into())) @@ -2681,12 +2685,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_input(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `876 + r * (6 ±0)` - // Estimated: `22220 + r * (30 ±0)` - // Minimum execution time: 297_248_000 picoseconds. - Weight::from_parts(303_805_584, 22220) - // Standard Error: 858 - .saturating_add(Weight::from_parts(223_587, 0).saturating_mul(r.into())) + // Measured: `780 + r * (6 ±0)` + // Estimated: `21740 + r * (30 ±0)` + // Minimum execution time: 232_561_000 picoseconds. + Weight::from_parts(230_989_499, 21740) + // Standard Error: 848 + .saturating_add(Weight::from_parts(282_053, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -2704,12 +2708,12 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 1048576]`. fn seal_input_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `880` - // Estimated: `22220` - // Minimum execution time: 298_464_000 picoseconds. - Weight::from_parts(300_996_431, 22220) - // Standard Error: 1 - .saturating_add(Weight::from_parts(600, 0).saturating_mul(n.into())) + // Measured: `784` + // Estimated: `21740` + // Minimum execution time: 237_080_000 picoseconds. + Weight::from_parts(239_380_994, 21740) + // Standard Error: 2 + .saturating_add(Weight::from_parts(592, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -2726,12 +2730,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1]`. fn seal_return(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `864 + r * (45 ±0)` - // Estimated: `22140 + r * (225 ±0)` - // Minimum execution time: 294_347_000 picoseconds. - Weight::from_parts(296_793_034, 22140) - // Standard Error: 277_251 - .saturating_add(Weight::from_parts(1_711_665, 0).saturating_mul(r.into())) + // Measured: `768 + r * (45 ±0)` + // Estimated: `21660 + r * (225 ±0)` + // Minimum execution time: 228_669_000 picoseconds. + Weight::from_parts(230_916_471, 21660) + // Standard Error: 295_520 + .saturating_add(Weight::from_parts(1_420_928, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 225).saturating_mul(r.into())) @@ -2749,12 +2753,12 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 1048576]`. fn seal_return_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `874` - // Estimated: `22255` - // Minimum execution time: 297_257_000 picoseconds. - Weight::from_parts(300_088_288, 22255) + // Measured: `778` + // Estimated: `21775` + // Minimum execution time: 231_626_000 picoseconds. + Weight::from_parts(232_097_413, 21775) // Standard Error: 1 - .saturating_add(Weight::from_parts(181, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(185, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -2775,17 +2779,17 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1]`. fn seal_terminate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `906 + r * (452 ±0)` - // Estimated: `26183 + r * (15994 ±0)` - // Minimum execution time: 296_510_000 picoseconds. - Weight::from_parts(299_169_757, 26183) - // Standard Error: 205_313 - .saturating_add(Weight::from_parts(78_059_642, 0).saturating_mul(r.into())) + // Measured: `810 + r * (356 ±0)` + // Estimated: `25511 + r * (15321 ±0)` + // Minimum execution time: 230_758_000 picoseconds. + Weight::from_parts(233_235_993, 25511) + // Standard Error: 196_168 + .saturating_add(Weight::from_parts(81_177_506, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((6_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((7_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 15994).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 15321).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2802,12 +2806,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_random(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `921 + r * (10 ±0)` - // Estimated: `24859 + r * (60 ±0)` - // Minimum execution time: 299_299_000 picoseconds. - Weight::from_parts(314_487_015, 24859) - // Standard Error: 1_552 - .saturating_add(Weight::from_parts(1_753_960, 0).saturating_mul(r.into())) + // Measured: `825 + r * (10 ±0)` + // Estimated: `24283 + r * (60 ±0)` + // Minimum execution time: 232_457_000 picoseconds. + Weight::from_parts(240_943_161, 24283) + // Standard Error: 3_085 + .saturating_add(Weight::from_parts(1_837_168, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 60).saturating_mul(r.into())) @@ -2825,12 +2829,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_deposit_event(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `874 + r * (10 ±0)` - // Estimated: `22215 + r * (50 ±0)` - // Minimum execution time: 296_188_000 picoseconds. - Weight::from_parts(305_901_539, 22215) - // Standard Error: 2_782 - .saturating_add(Weight::from_parts(3_456_054, 0).saturating_mul(r.into())) + // Measured: `778 + r * (10 ±0)` + // Estimated: `21735 + r * (50 ±0)` + // Minimum execution time: 229_788_000 picoseconds. + Weight::from_parts(233_520_858, 21735) + // Standard Error: 9_561 + .saturating_add(Weight::from_parts(3_596_294, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 50).saturating_mul(r.into())) @@ -2849,14 +2853,14 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 16384]`. fn seal_deposit_event_per_topic_and_byte(t: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `893 + t * (32 ±0)` - // Estimated: `22320 + t * (2640 ±0)` - // Minimum execution time: 313_860_000 picoseconds. - Weight::from_parts(312_473_092, 22320) - // Standard Error: 250_852 - .saturating_add(Weight::from_parts(2_258_502, 0).saturating_mul(t.into())) - // Standard Error: 70 - .saturating_add(Weight::from_parts(312, 0).saturating_mul(n.into())) + // Measured: `797 + t * (32 ±0)` + // Estimated: `21840 + t * (2640 ±0)` + // Minimum execution time: 248_294_000 picoseconds. + Weight::from_parts(239_709_759, 21840) + // Standard Error: 66_903 + .saturating_add(Weight::from_parts(2_880_732, 0).saturating_mul(t.into())) + // Standard Error: 18 + .saturating_add(Weight::from_parts(725, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(t.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -2876,12 +2880,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_debug_message(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `873 + r * (7 ±0)` - // Estimated: `22205 + r * (35 ±0)` - // Minimum execution time: 162_043_000 picoseconds. - Weight::from_parts(166_132_332, 22205) - // Standard Error: 716 - .saturating_add(Weight::from_parts(184_981, 0).saturating_mul(r.into())) + // Measured: `777 + r * (7 ±0)` + // Estimated: `21725 + r * (35 ±0)` + // Minimum execution time: 170_601_000 picoseconds. + Weight::from_parts(165_819_714, 21725) + // Standard Error: 452 + .saturating_add(Weight::from_parts(240_362, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 35).saturating_mul(r.into())) @@ -2899,12 +2903,12 @@ impl WeightInfo for () { /// The range of component `i` is `[0, 1048576]`. fn seal_debug_message_per_byte(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `125824` - // Estimated: `270073` - // Minimum execution time: 414_433_000 picoseconds. - Weight::from_parts(417_483_627, 270073) - // Standard Error: 1 - .saturating_add(Weight::from_parts(748, 0).saturating_mul(i.into())) + // Measured: `125728` + // Estimated: `269977` + // Minimum execution time: 349_543_000 picoseconds. + Weight::from_parts(352_945_102, 269977) + // Standard Error: 2 + .saturating_add(Weight::from_parts(749, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -2913,12 +2917,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 800]`. fn seal_set_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `941 + r * (292 ±0)` - // Estimated: `939 + r * (293 ±0)` - // Minimum execution time: 299_500_000 picoseconds. - Weight::from_parts(194_466_413, 939) - // Standard Error: 9_986 - .saturating_add(Weight::from_parts(6_010_112, 0).saturating_mul(r.into())) + // Measured: `845 + r * (292 ±0)` + // Estimated: `843 + r * (293 ±0)` + // Minimum execution time: 238_766_000 picoseconds. + Weight::from_parts(130_994_282, 843) + // Standard Error: 10_413 + .saturating_add(Weight::from_parts(6_134_087, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -2930,12 +2934,12 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 16384]`. fn seal_set_storage_per_new_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1432` - // Estimated: `1405` - // Minimum execution time: 314_171_000 picoseconds. - Weight::from_parts(335_595_397, 1405) - // Standard Error: 67 - .saturating_add(Weight::from_parts(90, 0).saturating_mul(n.into())) + // Measured: `1304` + // Estimated: `1280` + // Minimum execution time: 248_137_000 picoseconds. + Weight::from_parts(265_535_917, 1280) + // Standard Error: 28 + .saturating_add(Weight::from_parts(387, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -2944,12 +2948,12 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 16384]`. fn seal_set_storage_per_old_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1295 + n * (1 ±0)` - // Estimated: `1292 + n * (1 ±0)` - // Minimum execution time: 313_479_000 picoseconds. - Weight::from_parts(317_435_100, 1292) - // Standard Error: 41 - .saturating_add(Weight::from_parts(106, 0).saturating_mul(n.into())) + // Measured: `1167 + n * (1 ±0)` + // Estimated: `1167 + n * (1 ±0)` + // Minimum execution time: 246_752_000 picoseconds. + Weight::from_parts(250_315_210, 1167) + // Standard Error: 42 + .saturating_add(Weight::from_parts(135, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -2959,12 +2963,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 800]`. fn seal_clear_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `937 + r * (288 ±0)` - // Estimated: `941 + r * (289 ±0)` - // Minimum execution time: 297_831_000 picoseconds. - Weight::from_parts(196_983_778, 941) - // Standard Error: 9_899 - .saturating_add(Weight::from_parts(5_904_642, 0).saturating_mul(r.into())) + // Measured: `841 + r * (288 ±0)` + // Estimated: `845 + r * (289 ±0)` + // Minimum execution time: 232_873_000 picoseconds. + Weight::from_parts(130_360_558, 845) + // Standard Error: 10_026 + .saturating_add(Weight::from_parts(6_023_862, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -2976,10 +2980,12 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 16384]`. fn seal_clear_storage_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1291 + n * (1 ±0)` - // Estimated: `1288 + n * (1 ±0)` - // Minimum execution time: 320_156_000 picoseconds. - Weight::from_parts(327_504_368, 1288) + // Measured: `1163 + n * (1 ±0)` + // Estimated: `1163 + n * (1 ±0)` + // Minimum execution time: 247_079_000 picoseconds. + Weight::from_parts(248_922_003, 1163) + // Standard Error: 22 + .saturating_add(Weight::from_parts(201, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -2989,12 +2995,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 800]`. fn seal_get_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `931 + r * (296 ±0)` - // Estimated: `936 + r * (297 ±0)` - // Minimum execution time: 305_849_000 picoseconds. - Weight::from_parts(219_649_351, 936) - // Standard Error: 9_157 - .saturating_add(Weight::from_parts(4_846_108, 0).saturating_mul(r.into())) + // Measured: `835 + r * (296 ±0)` + // Estimated: `840 + r * (297 ±0)` + // Minimum execution time: 232_696_000 picoseconds. + Weight::from_parts(144_147_151, 840) + // Standard Error: 8_846 + .saturating_add(Weight::from_parts(4_931_414, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3005,12 +3011,12 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 16384]`. fn seal_get_storage_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1307 + n * (1 ±0)` - // Estimated: `1304 + n * (1 ±0)` - // Minimum execution time: 312_106_000 picoseconds. - Weight::from_parts(315_905_779, 1304) - // Standard Error: 44 - .saturating_add(Weight::from_parts(674, 0).saturating_mul(n.into())) + // Measured: `1179 + n * (1 ±0)` + // Estimated: `1179 + n * (1 ±0)` + // Minimum execution time: 247_795_000 picoseconds. + Weight::from_parts(252_944_118, 1179) + // Standard Error: 45 + .saturating_add(Weight::from_parts(480, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -3020,12 +3026,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 800]`. fn seal_contains_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `952 + r * (288 ±0)` - // Estimated: `953 + r * (289 ±0)` - // Minimum execution time: 299_372_000 picoseconds. - Weight::from_parts(211_293_493, 953) - // Standard Error: 8_509 - .saturating_add(Weight::from_parts(4_688_993, 0).saturating_mul(r.into())) + // Measured: `856 + r * (288 ±0)` + // Estimated: `857 + r * (289 ±0)` + // Minimum execution time: 232_166_000 picoseconds. + Weight::from_parts(148_503_428, 857) + // Standard Error: 8_704 + .saturating_add(Weight::from_parts(4_766_055, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3036,12 +3042,12 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 16384]`. fn seal_contains_storage_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1294 + n * (1 ±0)` - // Estimated: `1291 + n * (1 ±0)` - // Minimum execution time: 311_605_000 picoseconds. - Weight::from_parts(315_473_850, 1291) - // Standard Error: 37 - .saturating_add(Weight::from_parts(3, 0).saturating_mul(n.into())) + // Measured: `1166 + n * (1 ±0)` + // Estimated: `1166 + n * (1 ±0)` + // Minimum execution time: 246_128_000 picoseconds. + Weight::from_parts(248_323_705, 1166) + // Standard Error: 21 + .saturating_add(Weight::from_parts(92, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -3051,12 +3057,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 800]`. fn seal_take_storage(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `925 + r * (296 ±0)` - // Estimated: `932 + r * (297 ±0)` - // Minimum execution time: 298_231_000 picoseconds. - Weight::from_parts(200_178_698, 932) - // Standard Error: 10_452 - .saturating_add(Weight::from_parts(6_107_653, 0).saturating_mul(r.into())) + // Measured: `829 + r * (296 ±0)` + // Estimated: `836 + r * (297 ±0)` + // Minimum execution time: 232_976_000 picoseconds. + Weight::from_parts(132_373_848, 836) + // Standard Error: 9_855 + .saturating_add(Weight::from_parts(6_181_821, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3068,12 +3074,12 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 16384]`. fn seal_take_storage_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1308 + n * (1 ±0)` - // Estimated: `1305 + n * (1 ±0)` - // Minimum execution time: 314_970_000 picoseconds. - Weight::from_parts(318_135_821, 1305) - // Standard Error: 26 - .saturating_add(Weight::from_parts(630, 0).saturating_mul(n.into())) + // Measured: `1180 + n * (1 ±0)` + // Estimated: `1180 + n * (1 ±0)` + // Minimum execution time: 247_907_000 picoseconds. + Weight::from_parts(251_984_133, 1180) + // Standard Error: 41 + .saturating_add(Weight::from_parts(639, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -3091,12 +3097,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_transfer(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1501 + r * (45 ±0)` - // Estimated: `27383 + r * (2700 ±0)` - // Minimum execution time: 299_629_000 picoseconds. - Weight::from_parts(150_915_187, 27383) - // Standard Error: 25_604 - .saturating_add(Weight::from_parts(20_859_844, 0).saturating_mul(r.into())) + // Measured: `1373 + r * (45 ±0)` + // Estimated: `26753 + r * (2700 ±0)` + // Minimum execution time: 232_614_000 picoseconds. + Weight::from_parts(127_024_367, 26753) + // Standard Error: 54_521 + .saturating_add(Weight::from_parts(20_975_575, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(4_u64)) @@ -3116,17 +3122,17 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_call(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1670 + r * (288 ±0)` - // Estimated: `27813 + r * (6391 ±0)` - // Minimum execution time: 299_578_000 picoseconds. - Weight::from_parts(300_036_000, 27813) - // Standard Error: 102_709 - .saturating_add(Weight::from_parts(283_767_316, 0).saturating_mul(r.into())) + // Measured: `1512 + r * (256 ±0)` + // Estimated: `27163 + r * (6231 ±0)` + // Minimum execution time: 233_446_000 picoseconds. + Weight::from_parts(234_338_000, 27163) + // Standard Error: 122_754 + .saturating_add(Weight::from_parts(216_709_600, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((2_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 6391).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 6231).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3141,17 +3147,17 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_delegate_call(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0 + r * (935 ±0)` - // Estimated: `22235 + r * (8322 ±10)` - // Minimum execution time: 298_943_000 picoseconds. - Weight::from_parts(299_619_000, 22235) - // Standard Error: 117_493 - .saturating_add(Weight::from_parts(280_555_517, 0).saturating_mul(r.into())) + // Measured: `0 + r * (902 ±0)` + // Estimated: `21755 + r * (8167 ±7)` + // Minimum execution time: 232_717_000 picoseconds. + Weight::from_parts(233_405_000, 21755) + // Standard Error: 98_607 + .saturating_add(Weight::from_parts(212_329_100, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 8322).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 8167).saturating_mul(r.into())) } /// Storage: System Account (r:3 w:2) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3167,19 +3173,19 @@ impl WeightInfo for () { /// The range of component `c` is `[0, 1048576]`. fn seal_call_per_transfer_clone_byte(t: u32, c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1314 + t * (268 ±0)` - // Estimated: `31815 + t * (6290 ±0)` - // Minimum execution time: 453_013_000 picoseconds. - Weight::from_parts(442_536_283, 31815) - // Standard Error: 1_339_541 - .saturating_add(Weight::from_parts(17_062_445, 0).saturating_mul(t.into())) - // Standard Error: 1 - .saturating_add(Weight::from_parts(604, 0).saturating_mul(c.into())) + // Measured: `1154 + t * (204 ±0)` + // Estimated: `31015 + t * (5970 ±0)` + // Minimum execution time: 392_113_000 picoseconds. + Weight::from_parts(376_522_702, 31015) + // Standard Error: 1_388_011 + .saturating_add(Weight::from_parts(19_125_093, 0).saturating_mul(t.into())) + // Standard Error: 2 + .saturating_add(Weight::from_parts(609, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(t.into()))) .saturating_add(RocksDbWeight::get().writes(5_u64)) .saturating_add(RocksDbWeight::get().writes((2_u64).saturating_mul(t.into()))) - .saturating_add(Weight::from_parts(0, 6290).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(0, 5970).saturating_mul(t.into())) } /// Storage: System Account (r:3202 w:3202) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3198,17 +3204,17 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_instantiate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1988 + r * (319 ±0)` - // Estimated: `34745 + r * (17090 ±0)` - // Minimum execution time: 300_123_000 picoseconds. - Weight::from_parts(300_406_000, 34745) - // Standard Error: 420_997 - .saturating_add(Weight::from_parts(382_704_025, 0).saturating_mul(r.into())) + // Measured: `1859 + r * (253 ±0)` + // Estimated: `33859 + r * (16628 ±0)` + // Minimum execution time: 234_438_000 picoseconds. + Weight::from_parts(234_751_000, 33859) + // Standard Error: 450_507 + .saturating_add(Weight::from_parts(313_121_404, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().reads((6_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(6_u64)) .saturating_add(RocksDbWeight::get().writes((5_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 17090).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 16628).saturating_mul(r.into())) } /// Storage: System Account (r:4 w:4) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3229,21 +3235,21 @@ impl WeightInfo for () { /// The range of component `s` is `[0, 983040]`. fn seal_instantiate_per_transfer_input_salt_byte(t: u32, i: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1231 + t * (219 ±0)` - // Estimated: `43797 + t * (3812 ±2)` - // Minimum execution time: 1_636_322_000 picoseconds. - Weight::from_parts(360_859_331, 43797) - // Standard Error: 4_816_923 - .saturating_add(Weight::from_parts(109_179_023, 0).saturating_mul(t.into())) + // Measured: `1071 + t * (187 ±0)` + // Estimated: `42684 + t * (3588 ±2)` + // Minimum execution time: 1_570_178_000 picoseconds. + Weight::from_parts(284_062_841, 42684) + // Standard Error: 4_396_597 + .saturating_add(Weight::from_parts(106_424_960, 0).saturating_mul(t.into())) // Standard Error: 7 - .saturating_add(Weight::from_parts(1_180, 0).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(1_183, 0).saturating_mul(i.into())) // Standard Error: 7 - .saturating_add(Weight::from_parts(1_344, 0).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_354, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(13_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(t.into()))) .saturating_add(RocksDbWeight::get().writes(10_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(t.into()))) - .saturating_add(Weight::from_parts(0, 3812).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(0, 3588).saturating_mul(t.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3258,12 +3264,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_hash_sha2_256(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `873 + r * (8 ±0)` - // Estimated: `22190 + r * (40 ±0)` - // Minimum execution time: 297_521_000 picoseconds. - Weight::from_parts(303_523_260, 22190) - // Standard Error: 1_162 - .saturating_add(Weight::from_parts(542_201, 0).saturating_mul(r.into())) + // Measured: `777 + r * (8 ±0)` + // Estimated: `21710 + r * (40 ±0)` + // Minimum execution time: 230_557_000 picoseconds. + Weight::from_parts(233_276_698, 21710) + // Standard Error: 1_026 + .saturating_add(Weight::from_parts(587_723, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) @@ -3281,12 +3287,12 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 1048576]`. fn seal_hash_sha2_256_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `881` - // Estimated: `22225` - // Minimum execution time: 299_877_000 picoseconds. - Weight::from_parts(293_538_014, 22225) - // Standard Error: 2 - .saturating_add(Weight::from_parts(3_967, 0).saturating_mul(n.into())) + // Measured: `785` + // Estimated: `21745` + // Minimum execution time: 234_151_000 picoseconds. + Weight::from_parts(240_199_365, 21745) + // Standard Error: 3 + .saturating_add(Weight::from_parts(3_941, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3303,12 +3309,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_hash_keccak_256(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `875 + r * (8 ±0)` - // Estimated: `22205 + r * (40 ±0)` - // Minimum execution time: 297_672_000 picoseconds. - Weight::from_parts(299_933_312, 22205) - // Standard Error: 1_138 - .saturating_add(Weight::from_parts(713_189, 0).saturating_mul(r.into())) + // Measured: `779 + r * (8 ±0)` + // Estimated: `21725 + r * (40 ±0)` + // Minimum execution time: 229_931_000 picoseconds. + Weight::from_parts(234_961_690, 21725) + // Standard Error: 1_073 + .saturating_add(Weight::from_parts(758_259, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) @@ -3326,12 +3332,12 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 1048576]`. fn seal_hash_keccak_256_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `883` - // Estimated: `22245` - // Minimum execution time: 299_048_000 picoseconds. - Weight::from_parts(293_055_982, 22245) + // Measured: `787` + // Estimated: `21765` + // Minimum execution time: 232_448_000 picoseconds. + Weight::from_parts(225_974_008, 21765) // Standard Error: 2 - .saturating_add(Weight::from_parts(3_179, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(3_174, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3348,12 +3354,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_hash_blake2_256(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `875 + r * (8 ±0)` - // Estimated: `22220 + r * (40 ±0)` - // Minimum execution time: 301_991_000 picoseconds. - Weight::from_parts(300_027_441, 22220) - // Standard Error: 981 - .saturating_add(Weight::from_parts(391_319, 0).saturating_mul(r.into())) + // Measured: `779 + r * (8 ±0)` + // Estimated: `21740 + r * (40 ±0)` + // Minimum execution time: 229_251_000 picoseconds. + Weight::from_parts(234_182_627, 21740) + // Standard Error: 836 + .saturating_add(Weight::from_parts(424_375, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) @@ -3371,12 +3377,12 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 1048576]`. fn seal_hash_blake2_256_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `883` - // Estimated: `22265` - // Minimum execution time: 296_522_000 picoseconds. - Weight::from_parts(296_121_638, 22265) + // Measured: `787` + // Estimated: `21785` + // Minimum execution time: 230_896_000 picoseconds. + Weight::from_parts(224_913_556, 21785) // Standard Error: 2 - .saturating_add(Weight::from_parts(916, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(919, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3393,12 +3399,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_hash_blake2_128(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `875 + r * (8 ±0)` - // Estimated: `22225 + r * (40 ±0)` - // Minimum execution time: 296_228_000 picoseconds. - Weight::from_parts(301_472_299, 22225) - // Standard Error: 875 - .saturating_add(Weight::from_parts(381_027, 0).saturating_mul(r.into())) + // Measured: `779 + r * (8 ±0)` + // Estimated: `21745 + r * (40 ±0)` + // Minimum execution time: 230_314_000 picoseconds. + Weight::from_parts(233_426_327, 21745) + // Standard Error: 926 + .saturating_add(Weight::from_parts(425_341, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) @@ -3416,12 +3422,12 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 1048576]`. fn seal_hash_blake2_128_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `883` - // Estimated: `22235` - // Minimum execution time: 296_644_000 picoseconds. - Weight::from_parts(289_879_744, 22235) + // Measured: `787` + // Estimated: `21755` + // Minimum execution time: 230_424_000 picoseconds. + Weight::from_parts(231_136_218, 21755) // Standard Error: 2 - .saturating_add(Weight::from_parts(925, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(917, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3438,12 +3444,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_ecdsa_recover(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `800 + r * (78 ±0)` - // Estimated: `21845 + r * (390 ±0)` - // Minimum execution time: 297_804_000 picoseconds. - Weight::from_parts(471_994_534, 21845) - // Standard Error: 9_479 - .saturating_add(Weight::from_parts(36_886_028, 0).saturating_mul(r.into())) + // Measured: `704 + r * (78 ±0)` + // Estimated: `21370 + r * (390 ±0)` + // Minimum execution time: 232_862_000 picoseconds. + Weight::from_parts(379_152_870, 21370) + // Standard Error: 11_607 + .saturating_add(Weight::from_parts(36_955_410, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 390).saturating_mul(r.into())) @@ -3461,12 +3467,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `645 + r * (44 ±0)` - // Estimated: `21110 + r * (220 ±0)` - // Minimum execution time: 298_623_000 picoseconds. - Weight::from_parts(322_192_102, 21110) - // Standard Error: 3_207 - .saturating_add(Weight::from_parts(9_243_653, 0).saturating_mul(r.into())) + // Measured: `549 + r * (44 ±0)` + // Estimated: `20630 + r * (220 ±0)` + // Minimum execution time: 232_668_000 picoseconds. + Weight::from_parts(253_308_468, 20630) + // Standard Error: 3_022 + .saturating_add(Weight::from_parts(9_249_849, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 220).saturating_mul(r.into())) @@ -3486,17 +3492,17 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_set_code_hash(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0 + r * (1030 ±0)` - // Estimated: `30592 + r * (11919 ±7)` - // Minimum execution time: 298_574_000 picoseconds. - Weight::from_parts(299_383_000, 30592) - // Standard Error: 44_061 - .saturating_add(Weight::from_parts(21_625_366, 0).saturating_mul(r.into())) + // Measured: `0 + r * (964 ±0)` + // Estimated: `29920 + r * (11544 ±7)` + // Minimum execution time: 233_910_000 picoseconds. + Weight::from_parts(234_607_000, 29920) + // Standard Error: 46_118 + .saturating_add(Weight::from_parts(21_927_957, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((2_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 11919).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 11544).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3511,12 +3517,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_reentrance_count(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `869 + r * (3 ±0)` - // Estimated: `22215 + r * (15 ±0)` - // Minimum execution time: 297_014_000 picoseconds. - Weight::from_parts(301_226_615, 22215) - // Standard Error: 439 - .saturating_add(Weight::from_parts(143_017, 0).saturating_mul(r.into())) + // Measured: `773 + r * (3 ±0)` + // Estimated: `21735 + r * (15 ±0)` + // Minimum execution time: 231_823_000 picoseconds. + Weight::from_parts(237_996_137, 21735) + // Standard Error: 598 + .saturating_add(Weight::from_parts(163_106, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 15).saturating_mul(r.into())) @@ -3534,12 +3540,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_account_reentrance_count(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2072 + r * (39 ±0)` - // Estimated: `27645 + r * (200 ±0)` - // Minimum execution time: 299_074_000 picoseconds. - Weight::from_parts(336_979_016, 27645) - // Standard Error: 1_163 - .saturating_add(Weight::from_parts(227_998, 0).saturating_mul(r.into())) + // Measured: `1975 + r * (39 ±0)` + // Estimated: `27145 + r * (200 ±0)` + // Minimum execution time: 235_077_000 picoseconds. + Weight::from_parts(267_876_360, 27145) + // Standard Error: 1_147 + .saturating_add(Weight::from_parts(256_275, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 200).saturating_mul(r.into())) @@ -3559,12 +3565,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 1600]`. fn seal_instantiation_nonce(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `872 + r * (3 ±0)` - // Estimated: `24580 + r * (18 ±0)` - // Minimum execution time: 296_959_000 picoseconds. - Weight::from_parts(303_796_839, 24580) + // Measured: `776 + r * (3 ±0)` + // Estimated: `24004 + r * (18 ±0)` + // Minimum execution time: 231_384_000 picoseconds. + Weight::from_parts(237_086_900, 24004) // Standard Error: 534 - .saturating_add(Weight::from_parts(118_978, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(140_842, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 18).saturating_mul(r.into())) @@ -3574,507 +3580,509 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_020_000 picoseconds. - Weight::from_parts(1_355_107, 0) - // Standard Error: 1 - .saturating_add(Weight::from_parts(4_110, 0).saturating_mul(r.into())) + // Minimum execution time: 1_721_000 picoseconds. + Weight::from_parts(2_456_746, 0) + // Standard Error: 30 + .saturating_add(Weight::from_parts(2_788, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64load(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_224_000 picoseconds. - Weight::from_parts(1_819_284, 0) - // Standard Error: 10 - .saturating_add(Weight::from_parts(10_803, 0).saturating_mul(r.into())) + // Minimum execution time: 1_824_000 picoseconds. + Weight::from_parts(2_366_036, 0) + // Standard Error: 5 + .saturating_add(Weight::from_parts(6_446, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64store(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_216_000 picoseconds. - Weight::from_parts(1_795_011, 0) - // Standard Error: 5 - .saturating_add(Weight::from_parts(10_000, 0).saturating_mul(r.into())) + // Minimum execution time: 1_840_000 picoseconds. + Weight::from_parts(2_332_115, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(6_012, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_select(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_127_000 picoseconds. - Weight::from_parts(1_491_730, 0) - // Standard Error: 4 - .saturating_add(Weight::from_parts(11_471, 0).saturating_mul(r.into())) + // Minimum execution time: 1_731_000 picoseconds. + Weight::from_parts(2_078_873, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(7_931, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_if(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_044_000 picoseconds. - Weight::from_parts(2_330_852, 0) - // Standard Error: 69 - .saturating_add(Weight::from_parts(12_866, 0).saturating_mul(r.into())) + // Minimum execution time: 1_768_000 picoseconds. + Weight::from_parts(1_916_551, 0) + // Standard Error: 8 + .saturating_add(Weight::from_parts(10_597, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_br(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_067_000 picoseconds. - Weight::from_parts(1_399_626, 0) - // Standard Error: 5 - .saturating_add(Weight::from_parts(6_430, 0).saturating_mul(r.into())) + // Minimum execution time: 1_735_000 picoseconds. + Weight::from_parts(1_962_845, 0) + // Standard Error: 14 + .saturating_add(Weight::from_parts(4_631, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_br_if(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_087_000 picoseconds. - Weight::from_parts(1_463_592, 0) - // Standard Error: 12 - .saturating_add(Weight::from_parts(9_707, 0).saturating_mul(r.into())) + // Minimum execution time: 1_688_000 picoseconds. + Weight::from_parts(1_172_825, 0) + // Standard Error: 76 + .saturating_add(Weight::from_parts(8_007, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_br_table(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_110_000 picoseconds. - Weight::from_parts(1_058_258, 0) - // Standard Error: 22 - .saturating_add(Weight::from_parts(11_713, 0).saturating_mul(r.into())) + // Minimum execution time: 1_725_000 picoseconds. + Weight::from_parts(1_535_833, 0) + // Standard Error: 26 + .saturating_add(Weight::from_parts(9_489, 0).saturating_mul(r.into())) } /// The range of component `e` is `[1, 256]`. - fn instr_br_table_per_entry(_e: u32, ) -> Weight { + fn instr_br_table_per_entry(e: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_189_000 picoseconds. - Weight::from_parts(1_416_188, 0) + // Minimum execution time: 1_814_000 picoseconds. + Weight::from_parts(1_926_367, 0) + // Standard Error: 16 + .saturating_add(Weight::from_parts(219, 0).saturating_mul(e.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_call(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_201_000 picoseconds. - Weight::from_parts(3_375_851, 0) - // Standard Error: 96 - .saturating_add(Weight::from_parts(22_970, 0).saturating_mul(r.into())) + // Minimum execution time: 1_770_000 picoseconds. + Weight::from_parts(2_436_918, 0) + // Standard Error: 8 + .saturating_add(Weight::from_parts(17_890, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_call_indirect(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_286_000 picoseconds. - Weight::from_parts(2_817_725, 0) - // Standard Error: 55 - .saturating_add(Weight::from_parts(29_437, 0).saturating_mul(r.into())) + // Minimum execution time: 1_920_000 picoseconds. + Weight::from_parts(2_729_712, 0) + // Standard Error: 39 + .saturating_add(Weight::from_parts(24_853, 0).saturating_mul(r.into())) } /// The range of component `l` is `[0, 1024]`. fn instr_call_per_local(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_319_000 picoseconds. - Weight::from_parts(1_636_286, 0) - // Standard Error: 31 - .saturating_add(Weight::from_parts(1_240, 0).saturating_mul(l.into())) + // Minimum execution time: 1_869_000 picoseconds. + Weight::from_parts(2_147_970, 0) + // Standard Error: 46 + .saturating_add(Weight::from_parts(1_237, 0).saturating_mul(l.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_local_get(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_507_000 picoseconds. - Weight::from_parts(2_785_119, 0) + // Minimum execution time: 3_012_000 picoseconds. + Weight::from_parts(3_234_440, 0) // Standard Error: 1 - .saturating_add(Weight::from_parts(4_601, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(2_433, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_local_set(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_494_000 picoseconds. - Weight::from_parts(2_948_015, 0) - // Standard Error: 14 - .saturating_add(Weight::from_parts(4_788, 0).saturating_mul(r.into())) + // Minimum execution time: 3_037_000 picoseconds. + Weight::from_parts(3_204_600, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(3_627, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_local_tee(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_443_000 picoseconds. - Weight::from_parts(3_065_273, 0) - // Standard Error: 15 - .saturating_add(Weight::from_parts(6_489, 0).saturating_mul(r.into())) + // Minimum execution time: 2_974_000 picoseconds. + Weight::from_parts(3_301_366, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(3_836, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_global_get(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_214_000 picoseconds. - Weight::from_parts(1_634_049, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(8_960, 0).saturating_mul(r.into())) + // Minimum execution time: 1_853_000 picoseconds. + Weight::from_parts(2_310_141, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(8_387, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_global_set(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_180_000 picoseconds. - Weight::from_parts(1_555_599, 0) + // Minimum execution time: 1_828_000 picoseconds. + Weight::from_parts(2_315_323, 0) // Standard Error: 4 - .saturating_add(Weight::from_parts(9_205, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(8_797, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_memory_current(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_223_000 picoseconds. - Weight::from_parts(1_626_002, 0) - // Standard Error: 5 - .saturating_add(Weight::from_parts(8_181, 0).saturating_mul(r.into())) + // Minimum execution time: 1_800_000 picoseconds. + Weight::from_parts(2_117_252, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(3_741, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 16]`. fn instr_memory_grow(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_148_000 picoseconds. - Weight::from_parts(307_155, 0) - // Standard Error: 138_541 - .saturating_add(Weight::from_parts(13_291_570, 0).saturating_mul(r.into())) + // Minimum execution time: 1_743_000 picoseconds. + Weight::from_parts(1_054_728, 0) + // Standard Error: 137_128 + .saturating_add(Weight::from_parts(13_179_446, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64clz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_079_000 picoseconds. - Weight::from_parts(1_372_409, 0) - // Standard Error: 50 - .saturating_add(Weight::from_parts(6_427, 0).saturating_mul(r.into())) + // Minimum execution time: 1_735_000 picoseconds. + Weight::from_parts(2_026_568, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(3_802, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64ctz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_116_000 picoseconds. - Weight::from_parts(1_415_180, 0) + // Minimum execution time: 1_630_000 picoseconds. + Weight::from_parts(1_980_222, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(6_353, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_735, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64popcnt(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_058_000 picoseconds. - Weight::from_parts(1_314_206, 0) - // Standard Error: 35 - .saturating_add(Weight::from_parts(6_431, 0).saturating_mul(r.into())) + // Minimum execution time: 1_695_000 picoseconds. + Weight::from_parts(2_040_266, 0) + // Standard Error: 8 + .saturating_add(Weight::from_parts(3_718, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64eqz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_059_000 picoseconds. - Weight::from_parts(1_455_331, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(6_507, 0).saturating_mul(r.into())) + // Minimum execution time: 1_697_000 picoseconds. + Weight::from_parts(2_004_663, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(3_661, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64extendsi32(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_057_000 picoseconds. - Weight::from_parts(1_421_085, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(6_177, 0).saturating_mul(r.into())) + // Minimum execution time: 1_705_000 picoseconds. + Weight::from_parts(2_682_122, 0) + // Standard Error: 98 + .saturating_add(Weight::from_parts(3_705, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64extendui32(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_079_000 picoseconds. - Weight::from_parts(1_429_275, 0) + // Minimum execution time: 1_674_000 picoseconds. + Weight::from_parts(1_989_835, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(6_175, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_801, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i32wrapi64(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_065_000 picoseconds. - Weight::from_parts(1_403_813, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(6_192, 0).saturating_mul(r.into())) + // Minimum execution time: 1_695_000 picoseconds. + Weight::from_parts(2_083_824, 0) + // Standard Error: 17 + .saturating_add(Weight::from_parts(3_719, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64eq(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_061_000 picoseconds. - Weight::from_parts(1_421_984, 0) + // Minimum execution time: 1_678_000 picoseconds. + Weight::from_parts(1_996_335, 0) // Standard Error: 4 - .saturating_add(Weight::from_parts(9_094, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(5_995, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64ne(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_075_000 picoseconds. - Weight::from_parts(1_431_453, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(9_084, 0).saturating_mul(r.into())) + // Minimum execution time: 1_697_000 picoseconds. + Weight::from_parts(2_046_566, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(5_936, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64lts(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_100_000 picoseconds. - Weight::from_parts(1_452_384, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(9_081, 0).saturating_mul(r.into())) + // Minimum execution time: 1_721_000 picoseconds. + Weight::from_parts(2_406_930, 0) + // Standard Error: 150 + .saturating_add(Weight::from_parts(5_992, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64ltu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_090_000 picoseconds. - Weight::from_parts(1_466_416, 0) - // Standard Error: 17 - .saturating_add(Weight::from_parts(9_091, 0).saturating_mul(r.into())) + // Minimum execution time: 1_749_000 picoseconds. + Weight::from_parts(1_987_158, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(5_994, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64gts(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_056_000 picoseconds. - Weight::from_parts(1_676_091, 0) - // Standard Error: 47 - .saturating_add(Weight::from_parts(9_082, 0).saturating_mul(r.into())) + // Minimum execution time: 1_706_000 picoseconds. + Weight::from_parts(2_038_138, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(5_802, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64gtu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_053_000 picoseconds. - Weight::from_parts(1_232_790, 0) - // Standard Error: 43 - .saturating_add(Weight::from_parts(9_329, 0).saturating_mul(r.into())) + // Minimum execution time: 1_670_000 picoseconds. + Weight::from_parts(2_555_035, 0) + // Standard Error: 74 + .saturating_add(Weight::from_parts(5_958, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64les(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_091_000 picoseconds. - Weight::from_parts(1_476_212, 0) - // Standard Error: 4 - .saturating_add(Weight::from_parts(9_074, 0).saturating_mul(r.into())) + // Minimum execution time: 1_694_000 picoseconds. + Weight::from_parts(1_991_929, 0) + // Standard Error: 27 + .saturating_add(Weight::from_parts(6_037, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64leu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_083_000 picoseconds. - Weight::from_parts(1_484_966, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(9_184, 0).saturating_mul(r.into())) + // Minimum execution time: 1_684_000 picoseconds. + Weight::from_parts(1_969_284, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(6_104, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64ges(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_089_000 picoseconds. - Weight::from_parts(1_516_766, 0) - // Standard Error: 4 - .saturating_add(Weight::from_parts(9_063, 0).saturating_mul(r.into())) + // Minimum execution time: 1_697_000 picoseconds. + Weight::from_parts(2_023_608, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(5_946, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64geu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 996_000 picoseconds. - Weight::from_parts(1_460_638, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(9_076, 0).saturating_mul(r.into())) + // Minimum execution time: 1_659_000 picoseconds. + Weight::from_parts(1_963_145, 0) + // Standard Error: 6 + .saturating_add(Weight::from_parts(6_014, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64add(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_095_000 picoseconds. - Weight::from_parts(1_448_412, 0) + // Minimum execution time: 1_722_000 picoseconds. + Weight::from_parts(2_016_286, 0) // Standard Error: 3 - .saturating_add(Weight::from_parts(8_977, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(5_889, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64sub(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_071_000 picoseconds. - Weight::from_parts(1_459_165, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(8_852, 0).saturating_mul(r.into())) + // Minimum execution time: 1_656_000 picoseconds. + Weight::from_parts(1_966_234, 0) + // Standard Error: 17 + .saturating_add(Weight::from_parts(6_171, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64mul(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_082_000 picoseconds. - Weight::from_parts(1_450_718, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(8_860, 0).saturating_mul(r.into())) + // Minimum execution time: 1_695_000 picoseconds. + Weight::from_parts(2_004_559, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(5_785, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64divs(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_065_000 picoseconds. - Weight::from_parts(1_436_871, 0) - // Standard Error: 9 - .saturating_add(Weight::from_parts(15_241, 0).saturating_mul(r.into())) + // Minimum execution time: 1_681_000 picoseconds. + Weight::from_parts(2_135_505, 0) + // Standard Error: 6 + .saturating_add(Weight::from_parts(11_761, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64divu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_065_000 picoseconds. - Weight::from_parts(1_423_806, 0) - // Standard Error: 17 - .saturating_add(Weight::from_parts(14_706, 0).saturating_mul(r.into())) + // Minimum execution time: 1_653_000 picoseconds. + Weight::from_parts(2_153_167, 0) + // Standard Error: 5 + .saturating_add(Weight::from_parts(10_523, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64rems(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_059_000 picoseconds. - Weight::from_parts(1_735_816, 0) - // Standard Error: 66 - .saturating_add(Weight::from_parts(15_230, 0).saturating_mul(r.into())) + // Minimum execution time: 1_697_000 picoseconds. + Weight::from_parts(2_570_266, 0) + // Standard Error: 50 + .saturating_add(Weight::from_parts(11_971, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64remu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_076_000 picoseconds. - Weight::from_parts(1_451_290, 0) - // Standard Error: 6 - .saturating_add(Weight::from_parts(14_530, 0).saturating_mul(r.into())) + // Minimum execution time: 1_719_000 picoseconds. + Weight::from_parts(2_101_082, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(10_709, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64and(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_079_000 picoseconds. - Weight::from_parts(1_457_537, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(8_963, 0).saturating_mul(r.into())) + // Minimum execution time: 1_745_000 picoseconds. + Weight::from_parts(2_621_890, 0) + // Standard Error: 94 + .saturating_add(Weight::from_parts(5_545, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64or(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_032_000 picoseconds. - Weight::from_parts(1_475_315, 0) - // Standard Error: 4 - .saturating_add(Weight::from_parts(8_956, 0).saturating_mul(r.into())) + // Minimum execution time: 1_670_000 picoseconds. + Weight::from_parts(2_046_821, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(5_762, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64xor(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_056_000 picoseconds. - Weight::from_parts(1_450_071, 0) + // Minimum execution time: 1_714_000 picoseconds. + Weight::from_parts(2_010_173, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(8_960, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(5_911, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64shl(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_116_000 picoseconds. - Weight::from_parts(1_429_705, 0) + // Minimum execution time: 1_756_000 picoseconds. + Weight::from_parts(2_044_772, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(9_027, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(5_857, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64shrs(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_059_000 picoseconds. - Weight::from_parts(1_429_307, 0) - // Standard Error: 4 - .saturating_add(Weight::from_parts(9_048, 0).saturating_mul(r.into())) + // Minimum execution time: 1_741_000 picoseconds. + Weight::from_parts(2_012_819, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(6_127, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64shru(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_093_000 picoseconds. - Weight::from_parts(1_411_827, 0) - // Standard Error: 4 - .saturating_add(Weight::from_parts(9_528, 0).saturating_mul(r.into())) + // Minimum execution time: 1_693_000 picoseconds. + Weight::from_parts(2_090_981, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(5_839, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64rotl(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_115_000 picoseconds. - Weight::from_parts(1_441_025, 0) + // Minimum execution time: 1_704_000 picoseconds. + Weight::from_parts(2_014_108, 0) // Standard Error: 4 - .saturating_add(Weight::from_parts(9_043, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(6_005, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64rotr(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_077_000 picoseconds. - Weight::from_parts(1_480_666, 0) - // Standard Error: 4 - .saturating_add(Weight::from_parts(9_031, 0).saturating_mul(r.into())) + // Minimum execution time: 1_715_000 picoseconds. + Weight::from_parts(2_053_720, 0) + // Standard Error: 5 + .saturating_add(Weight::from_parts(5_860, 0).saturating_mul(r.into())) } } From cb7e510ee0df351e26c8032eabe19b8f3948d35f Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Tue, 21 Mar 2023 08:56:33 +0100 Subject: [PATCH 541/715] zombienet: renamed deprecated transfer function (#13652) * zombienet: renamed deprecated transfer function * camelCase --- zombienet/0000-block-building/transaction-gets-finalized.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zombienet/0000-block-building/transaction-gets-finalized.js b/zombienet/0000-block-building/transaction-gets-finalized.js index a38cf603fc57e..d16e85f2c4e60 100644 --- a/zombienet/0000-block-building/transaction-gets-finalized.js +++ b/zombienet/0000-block-building/transaction-gets-finalized.js @@ -14,7 +14,7 @@ async function run(nodeName, networkInfo, args) { const bob = '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty'; // Create a extrinsic, transferring 10^20 units to Bob - const transfer = api.tx.balances.transfer(bob, 10n**20n); + const transfer = api.tx.balances.transferAllowDeath(bob, 10n**20n); let transaction_success_event = false; try { From 6e71ebb00a06605fd45d236e17be741055f37ccd Mon Sep 17 00:00:00 2001 From: Arkadiy Paronyan Date: Tue, 21 Mar 2023 10:45:40 +0100 Subject: [PATCH 542/715] Bump parity-db (#13656) --- Cargo.lock | 16 ++++++++-------- bin/node/bench/Cargo.toml | 2 +- client/db/Cargo.toml | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5306d2015b17b..e2ec461e1e03e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -652,9 +652,9 @@ dependencies = [ [[package]] name = "block-buffer" -version = "0.10.3" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ "generic-array 0.14.6", ] @@ -1706,7 +1706,7 @@ version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" dependencies = [ - "block-buffer 0.10.3", + "block-buffer 0.10.4", "crypto-common", "subtle", ] @@ -3667,9 +3667,9 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "libc" -version = "0.2.139" +version = "0.2.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" +checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c" [[package]] name = "libgit2-sys" @@ -6925,9 +6925,9 @@ dependencies = [ [[package]] name = "parity-db" -version = "0.4.4" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df89dd8311063c54ae4e03d9aeb597b04212a57e82c339344130a9cad9b3e2d9" +checksum = "00bfb81cf5c90a222db2fb7b3a7cbf8cc7f38dfb6647aca4d98edf8281f56ed5" dependencies = [ "blake2", "crc32fast", @@ -11820,7 +11820,7 @@ checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" dependencies = [ "cfg-if", "digest 0.10.6", - "rand 0.8.5", + "rand 0.7.3", "static_assertions", ] diff --git a/bin/node/bench/Cargo.toml b/bin/node/bench/Cargo.toml index be5e94ee4df8b..153a721da41f8 100644 --- a/bin/node/bench/Cargo.toml +++ b/bin/node/bench/Cargo.toml @@ -38,7 +38,7 @@ tempfile = "3.1.0" fs_extra = "1" rand = { version = "0.8.5", features = ["small_rng"] } lazy_static = "1.4.0" -parity-db = "0.4.4" +parity-db = "0.4.6" 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 c96e5c7405e74..8e4bcf18a2d04 100644 --- a/client/db/Cargo.toml +++ b/client/db/Cargo.toml @@ -22,7 +22,7 @@ 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.4" +parity-db = "0.4.6" 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 859bb12cd83b685f1c128133412b3afd8cc6de68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Tue, 21 Mar 2023 10:46:25 +0100 Subject: [PATCH 543/715] contracts: Follow up for benchmark simplification (#13635) * Rename BATCHES -> RUNS * Reduce runs of slow benchmarks * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_contracts --------- Co-authored-by: command-bot <> --- frame/contracts/src/benchmarking/mod.rs | 188 +-- frame/contracts/src/weights.rs | 1930 +++++++++++------------ 2 files changed, 1060 insertions(+), 1058 deletions(-) diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index 9b75b140f03d8..5494b57b65a2a 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -45,18 +45,18 @@ use sp_runtime::{ use sp_std::prelude::*; use wasm_instrument::parity_wasm::elements::{BlockType, BrTableData, Instruction, ValueType}; -/// How many batches we do per API benchmark. +/// How many runs we do per API benchmark. /// /// This is picked more or less arbitrary. We experimented with different numbers until /// the results appeared to be stable. Reducing the number would speed up the benchmarks /// but might make the results less precise. -const API_BENCHMARK_BATCHES: u32 = 1600; +const API_BENCHMARK_RUNS: u32 = 1600; -/// How many batches we do per instruction benchmark. +/// How many runs we do per instruction benchmark. /// -/// Same rationale as for [`API_BENCHMARK_BATCHES`]. The number is bigger because instruction +/// Same rationale as for [`API_BENCHMARK_RUNS`]. The number is bigger because instruction /// benchmarks are faster. -const INSTR_BENCHMARK_BATCHES: u32 = 5000; +const INSTR_BENCHMARK_RUNS: u32 = 5000; /// An instantiated and deployed contract. struct Contract { @@ -425,7 +425,7 @@ benchmarks! { #[pov_mode = Measured] seal_caller { - let r in 0 .. API_BENCHMARK_BATCHES; + let r in 0 .. API_BENCHMARK_RUNS; let instance = Contract::::new(WasmModule::getter( "seal0", "seal_caller", r ), vec![])?; @@ -434,7 +434,7 @@ benchmarks! { #[pov_mode = Measured] seal_is_contract { - let r in 0 .. API_BENCHMARK_BATCHES; + let r in 0 .. API_BENCHMARK_RUNS; let accounts = (0 .. r) .map(|n| account::("account", n, 0)) .collect::>(); @@ -472,7 +472,7 @@ benchmarks! { #[pov_mode = Measured] seal_code_hash { - let r in 0 .. API_BENCHMARK_BATCHES; + let r in 0 .. API_BENCHMARK_RUNS; let accounts = (0 .. r) .map(|n| account::("account", n, 0)) .collect::>(); @@ -518,7 +518,7 @@ benchmarks! { #[pov_mode = Measured] seal_own_code_hash { - let r in 0 .. API_BENCHMARK_BATCHES; + let r in 0 .. API_BENCHMARK_RUNS; let instance = Contract::::new(WasmModule::getter( "seal0", "seal_own_code_hash", r ), vec![])?; @@ -527,7 +527,7 @@ benchmarks! { #[pov_mode = Measured] seal_caller_is_origin { - let r in 0 .. API_BENCHMARK_BATCHES; + let r in 0 .. API_BENCHMARK_RUNS; let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { @@ -548,7 +548,7 @@ benchmarks! { #[pov_mode = Measured] seal_address { - let r in 0 .. API_BENCHMARK_BATCHES; + let r in 0 .. API_BENCHMARK_RUNS; let instance = Contract::::new(WasmModule::getter( "seal0", "seal_address", r ), vec![])?; @@ -557,7 +557,7 @@ benchmarks! { #[pov_mode = Measured] seal_gas_left { - let r in 0 .. API_BENCHMARK_BATCHES; + let r in 0 .. API_BENCHMARK_RUNS; let instance = Contract::::new(WasmModule::getter( "seal0", "seal_gas_left", r ), vec![])?; @@ -566,7 +566,7 @@ benchmarks! { #[pov_mode = Measured] seal_balance { - let r in 0 .. API_BENCHMARK_BATCHES; + let r in 0 .. API_BENCHMARK_RUNS; let instance = Contract::::new(WasmModule::getter( "seal0", "seal_balance", r ), vec![])?; @@ -575,7 +575,7 @@ benchmarks! { #[pov_mode = Measured] seal_value_transferred { - let r in 0 .. API_BENCHMARK_BATCHES; + let r in 0 .. API_BENCHMARK_RUNS; let instance = Contract::::new(WasmModule::getter( "seal0", "seal_value_transferred", r ), vec![])?; @@ -584,7 +584,7 @@ benchmarks! { #[pov_mode = Measured] seal_minimum_balance { - let r in 0 .. API_BENCHMARK_BATCHES; + let r in 0 .. API_BENCHMARK_RUNS; let instance = Contract::::new(WasmModule::getter( "seal0", "seal_minimum_balance", r ), vec![])?; @@ -593,7 +593,7 @@ benchmarks! { #[pov_mode = Measured] seal_block_number { - let r in 0 .. API_BENCHMARK_BATCHES; + let r in 0 .. API_BENCHMARK_RUNS; let instance = Contract::::new(WasmModule::getter( "seal0", "seal_block_number", r ), vec![])?; @@ -602,7 +602,7 @@ benchmarks! { #[pov_mode = Measured] seal_now { - let r in 0 .. API_BENCHMARK_BATCHES; + let r in 0 .. API_BENCHMARK_RUNS; let instance = Contract::::new(WasmModule::getter( "seal0", "seal_now", r ), vec![])?; @@ -611,7 +611,7 @@ benchmarks! { #[pov_mode = Measured] seal_weight_to_fee { - let r in 0 .. API_BENCHMARK_BATCHES; + let r in 0 .. API_BENCHMARK_RUNS; let pages = code::max_pages::(); let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), @@ -639,7 +639,7 @@ benchmarks! { #[pov_mode = Measured] seal_gas { - let r in 0 .. API_BENCHMARK_BATCHES; + let r in 0 .. API_BENCHMARK_RUNS; let code = WasmModule::::from(ModuleDefinition { imported_functions: vec![ImportedFunction { module: "seal0", @@ -660,7 +660,7 @@ benchmarks! { #[pov_mode = Measured] seal_input { - let r in 0 .. API_BENCHMARK_BATCHES; + let r in 0 .. API_BENCHMARK_RUNS; let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { @@ -815,7 +815,7 @@ benchmarks! { // used. #[pov_mode = Measured] seal_random { - let r in 0 .. API_BENCHMARK_BATCHES; + let r in 0 .. API_BENCHMARK_RUNS; let pages = code::max_pages::(); let subject_len = T::Schedule::get().limits.subject_len; assert!(subject_len < 1024); @@ -850,7 +850,7 @@ benchmarks! { // We benchmark for the worst case (largest event). #[pov_mode = Measured] seal_deposit_event { - let r in 0 .. API_BENCHMARK_BATCHES; + let r in 0 .. API_BENCHMARK_RUNS; let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { @@ -914,7 +914,7 @@ benchmarks! { // against an excessive use. #[pov_mode = Measured] seal_debug_message { - let r in 0 .. API_BENCHMARK_BATCHES; + let r in 0 .. API_BENCHMARK_RUNS; let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory { min_pages: 1, max_pages: 1 }), imported_functions: vec![ImportedFunction { @@ -1009,7 +1009,7 @@ benchmarks! { #[skip_meta] #[pov_mode = Measured] seal_set_storage { - let r in 0 .. API_BENCHMARK_BATCHES/2; + let r in 0 .. API_BENCHMARK_RUNS/2; let max_key_len = T::MaxStorageKeyLen::get(); let keys = (0 .. r) .map(|n| { let mut h = T::Hashing::hash_of(&n).as_ref().to_vec(); @@ -1143,11 +1143,11 @@ benchmarks! { // 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. We generate keys of a maximum length, and have to - // reduce batch size in order to make resulting contract code size less than MaxCodeLen. + // the amount of runs in order to make resulting contract code size less than MaxCodeLen. #[skip_meta] #[pov_mode = Measured] seal_clear_storage { - let r in 0 .. API_BENCHMARK_BATCHES/2; + let r in 0 .. API_BENCHMARK_RUNS/2; let max_key_len = T::MaxStorageKeyLen::get(); let keys = (0 .. r) .map(|n| { let mut h = T::Hashing::hash_of(&n).as_ref().to_vec(); @@ -1236,7 +1236,7 @@ benchmarks! { #[skip_meta] #[pov_mode = Measured] seal_get_storage { - let r in 0 .. API_BENCHMARK_BATCHES/2; + let r in 0 .. API_BENCHMARK_RUNS/2; let max_key_len = T::MaxStorageKeyLen::get(); let keys = (0 .. r) .map(|n| { let mut h = T::Hashing::hash_of(&n).as_ref().to_vec(); @@ -1339,7 +1339,7 @@ benchmarks! { #[skip_meta] #[pov_mode = Measured] seal_contains_storage { - let r in 0 .. API_BENCHMARK_BATCHES/2; + let r in 0 .. API_BENCHMARK_RUNS/2; let max_key_len = T::MaxStorageKeyLen::get(); let keys = (0 .. r) .map(|n| { let mut h = T::Hashing::hash_of(&n).as_ref().to_vec(); @@ -1429,7 +1429,7 @@ benchmarks! { #[skip_meta] #[pov_mode = Measured] seal_take_storage { - let r in 0 .. API_BENCHMARK_BATCHES/2; + let r in 0 .. API_BENCHMARK_RUNS/2; let max_key_len = T::MaxStorageKeyLen::get(); let keys = (0 .. r) .map(|n| { let mut h = T::Hashing::hash_of(&n).as_ref().to_vec(); @@ -1531,7 +1531,7 @@ benchmarks! { // We transfer to unique accounts. #[pov_mode = Measured] seal_transfer { - let r in 0 .. API_BENCHMARK_BATCHES; + let r in 0 .. API_BENCHMARK_RUNS; let accounts = (0..r) .map(|i| account::("receiver", i, 0)) .collect::>(); @@ -1583,9 +1583,11 @@ benchmarks! { } // We call unique accounts. + // + // This is a slow call: We redeuce the number of runs. #[pov_mode = Measured] seal_call { - let r in 0 .. API_BENCHMARK_BATCHES; + let r in 0 .. API_BENCHMARK_RUNS / 2; let dummy_code = WasmModule::::dummy_with_bytes(0); let callees = (0..r) .map(|i| Contract::with_index(i + 1, dummy_code.clone(), vec![])) @@ -1642,9 +1644,10 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + // This is a slow call: We redeuce the number of runs. #[pov_mode = Measured] seal_delegate_call { - let r in 0 .. API_BENCHMARK_BATCHES; + let r in 0 .. API_BENCHMARK_RUNS / 2; let hashes = (0..r) .map(|i| { let code = WasmModule::::dummy_with_bytes(i); @@ -1751,9 +1754,10 @@ benchmarks! { }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, bytes) // We assume that every instantiate sends at least the minimum balance. + // This is a slow call: We redeuce the number of runs. #[pov_mode = Measured] seal_instantiate { - let r in 0 .. API_BENCHMARK_BATCHES; + let r in 0 .. API_BENCHMARK_RUNS / 2; let hashes = (0..r) .map(|i| { let code = WasmModule::::from(ModuleDefinition { @@ -1939,7 +1943,7 @@ benchmarks! { // Only the overhead of calling the function itself with minimal arguments. #[pov_mode = Measured] seal_hash_sha2_256 { - let r in 0 .. API_BENCHMARK_BATCHES; + let r in 0 .. API_BENCHMARK_RUNS; let instance = Contract::::new(WasmModule::hasher( "seal_hash_sha2_256", r, 0, ), vec![])?; @@ -1959,7 +1963,7 @@ benchmarks! { // Only the overhead of calling the function itself with minimal arguments. #[pov_mode = Measured] seal_hash_keccak_256 { - let r in 0 .. API_BENCHMARK_BATCHES; + let r in 0 .. API_BENCHMARK_RUNS; let instance = Contract::::new(WasmModule::hasher( "seal_hash_keccak_256", r, 0, ), vec![])?; @@ -1979,7 +1983,7 @@ benchmarks! { // Only the overhead of calling the function itself with minimal arguments. #[pov_mode = Measured] seal_hash_blake2_256 { - let r in 0 .. API_BENCHMARK_BATCHES; + let r in 0 .. API_BENCHMARK_RUNS; let instance = Contract::::new(WasmModule::hasher( "seal_hash_blake2_256", r, 0, ), vec![])?; @@ -1999,7 +2003,7 @@ benchmarks! { // Only the overhead of calling the function itself with minimal arguments. #[pov_mode = Measured] seal_hash_blake2_128 { - let r in 0 .. API_BENCHMARK_BATCHES; + let r in 0 .. API_BENCHMARK_RUNS; let instance = Contract::::new(WasmModule::hasher( "seal_hash_blake2_128", r, 0, ), vec![])?; @@ -2018,9 +2022,10 @@ benchmarks! { // Only calling the function itself with valid arguments. // It generates different private keys and signatures for the message "Hello world". + // This is a slow call: We redeuce the number of runs. #[pov_mode = Measured] seal_ecdsa_recover { - let r in 0 .. API_BENCHMARK_BATCHES; + let r in 0 .. API_BENCHMARK_RUNS / 10; let message_hash = sp_io::hashing::blake2_256("Hello world".as_bytes()); let key_type = sp_core::crypto::KeyTypeId(*b"code"); @@ -2067,9 +2072,10 @@ benchmarks! { // Only calling the function itself for the list of // generated different ECDSA keys. + // This is a slow call: We redeuce the number of runs. #[pov_mode = Measured] seal_ecdsa_to_eth_address { - let r in 0 .. API_BENCHMARK_BATCHES; + let r in 0 .. API_BENCHMARK_RUNS / 10; let key_type = sp_core::crypto::KeyTypeId(*b"code"); let pub_keys_bytes = (0..r) .flat_map(|_| { @@ -2105,7 +2111,7 @@ benchmarks! { #[pov_mode = Measured] seal_set_code_hash { - let r in 0 .. API_BENCHMARK_BATCHES; + let r in 0 .. API_BENCHMARK_RUNS; let code_hashes = (0..r) .map(|i| { let new_code = WasmModule::::dummy_with_bytes(i); @@ -2146,7 +2152,7 @@ benchmarks! { #[pov_mode = Measured] seal_reentrance_count { - let r in 0 .. API_BENCHMARK_BATCHES; + let r in 0 .. API_BENCHMARK_RUNS; let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { @@ -2167,7 +2173,7 @@ benchmarks! { #[pov_mode = Measured] seal_account_reentrance_count { - let r in 0 .. API_BENCHMARK_BATCHES; + let r in 0 .. API_BENCHMARK_RUNS; let dummy_code = WasmModule::::dummy_with_bytes(0); let accounts = (0..r) .map(|i| Contract::with_index(i + 1, dummy_code.clone(), vec![])) @@ -2201,7 +2207,7 @@ benchmarks! { #[pov_mode = Measured] seal_instantiation_nonce { - let r in 0 .. API_BENCHMARK_BATCHES; + let r in 0 .. API_BENCHMARK_RUNS; let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { @@ -2232,7 +2238,7 @@ benchmarks! { // w_i{32,64}const = w_drop = w_bench / 2 #[pov_mode = Ignored] instr_i64const { - let r in 0 .. INSTR_BENCHMARK_BATCHES; + let r in 0 .. INSTR_BENCHMARK_RUNS; let mut sbox = Sandbox::from(&WasmModule::::from(ModuleDefinition { call_body: Some(body::repeated_dyn(r, vec![ RandomI64Repeated(1), @@ -2247,7 +2253,7 @@ benchmarks! { // w_i{32,64}load = w_bench - 2 * w_param #[pov_mode = Ignored] instr_i64load { - let r in 0 .. INSTR_BENCHMARK_BATCHES; + let r in 0 .. INSTR_BENCHMARK_RUNS; let mut sbox = Sandbox::from(&WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), call_body: Some(body::repeated_dyn(r, vec![ @@ -2264,7 +2270,7 @@ benchmarks! { // w_i{32,64}store{...} = w_bench - 2 * w_param #[pov_mode = Ignored] instr_i64store { - let r in 0 .. INSTR_BENCHMARK_BATCHES; + let r in 0 .. INSTR_BENCHMARK_RUNS; let mut sbox = Sandbox::from(&WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), call_body: Some(body::repeated_dyn(r, vec![ @@ -2281,7 +2287,7 @@ benchmarks! { // w_select = w_bench - 4 * w_param #[pov_mode = Ignored] instr_select { - let r in 0 .. INSTR_BENCHMARK_BATCHES; + let r in 0 .. INSTR_BENCHMARK_RUNS; let mut sbox = Sandbox::from(&WasmModule::::from(ModuleDefinition { call_body: Some(body::repeated_dyn(r, vec![ RandomI64Repeated(1), @@ -2299,7 +2305,7 @@ benchmarks! { // w_if = w_bench - 3 * w_param #[pov_mode = Ignored] instr_if { - let r in 0 .. INSTR_BENCHMARK_BATCHES; + let r in 0 .. INSTR_BENCHMARK_RUNS; let mut sbox = Sandbox::from(&WasmModule::::from(ModuleDefinition { call_body: Some(body::repeated_dyn(r, vec![ RandomI32(0, 2), @@ -2320,7 +2326,7 @@ benchmarks! { // Block instructions are not counted. #[pov_mode = Ignored] instr_br { - let r in 0 .. INSTR_BENCHMARK_BATCHES; + let r in 0 .. INSTR_BENCHMARK_RUNS; let mut sbox = Sandbox::from(&WasmModule::::from(ModuleDefinition { call_body: Some(body::repeated_dyn(r, vec![ Regular(Instruction::Block(BlockType::NoResult)), @@ -2347,7 +2353,7 @@ benchmarks! { // Block instructions are not counted. #[pov_mode = Ignored] instr_br_if { - let r in 0 .. INSTR_BENCHMARK_BATCHES; + let r in 0 .. INSTR_BENCHMARK_RUNS; let mut sbox = Sandbox::from(&WasmModule::::from(ModuleDefinition { call_body: Some(body::repeated_dyn(r, vec![ Regular(Instruction::Block(BlockType::NoResult)), @@ -2375,7 +2381,7 @@ benchmarks! { // Block instructions are not counted. #[pov_mode = Ignored] instr_br_table { - let r in 0 .. INSTR_BENCHMARK_BATCHES; + let r in 0 .. INSTR_BENCHMARK_RUNS; let table = Box::new(BrTableData { table: Box::new([1, 1, 1]), default: 1, @@ -2442,7 +2448,7 @@ benchmarks! { // w_call = w_bench - 2 * w_param #[pov_mode = Ignored] instr_call { - let r in 0 .. INSTR_BENCHMARK_BATCHES; + let r in 0 .. INSTR_BENCHMARK_RUNS; let mut sbox = Sandbox::from(&WasmModule::::from(ModuleDefinition { // We need to make use of the stack here in order to trigger stack height // instrumentation. @@ -2463,7 +2469,7 @@ benchmarks! { // w_call_indrect = w_bench - 3 * w_param #[pov_mode = Ignored] instr_call_indirect { - let r in 0 .. INSTR_BENCHMARK_BATCHES; + let r in 0 .. INSTR_BENCHMARK_RUNS; let num_elements = T::Schedule::get().limits.table_size; use self::code::TableSegment; let mut sbox = Sandbox::from(&WasmModule::::from(ModuleDefinition { @@ -2511,7 +2517,7 @@ benchmarks! { // w_local_get = w_bench - 1 * w_param #[pov_mode = Ignored] instr_local_get { - let r in 0 .. INSTR_BENCHMARK_BATCHES; + let r in 0 .. INSTR_BENCHMARK_RUNS; let max_locals = T::Schedule::get().limits.locals; let mut call_body = body::repeated_dyn(r, vec![ RandomGetLocal(0, max_locals), @@ -2529,7 +2535,7 @@ benchmarks! { // w_local_set = w_bench - 1 * w_param #[pov_mode = Ignored] instr_local_set { - let r in 0 .. INSTR_BENCHMARK_BATCHES; + let r in 0 .. INSTR_BENCHMARK_RUNS; let max_locals = T::Schedule::get().limits.locals; let mut call_body = body::repeated_dyn(r, vec![ RandomI64Repeated(1), @@ -2547,7 +2553,7 @@ benchmarks! { // w_local_tee = w_bench - 2 * w_param #[pov_mode = Ignored] instr_local_tee { - let r in 0 .. INSTR_BENCHMARK_BATCHES; + let r in 0 .. INSTR_BENCHMARK_RUNS; let max_locals = T::Schedule::get().limits.locals; let mut call_body = body::repeated_dyn(r, vec![ RandomI64Repeated(1), @@ -2566,7 +2572,7 @@ benchmarks! { // w_global_get = w_bench - 1 * w_param #[pov_mode = Ignored] instr_global_get { - let r in 0 .. INSTR_BENCHMARK_BATCHES; + let r in 0 .. INSTR_BENCHMARK_RUNS; let max_globals = T::Schedule::get().limits.globals; let mut sbox = Sandbox::from(&WasmModule::::from(ModuleDefinition { call_body: Some(body::repeated_dyn(r, vec![ @@ -2583,7 +2589,7 @@ benchmarks! { // w_global_set = w_bench - 1 * w_param #[pov_mode = Ignored] instr_global_set { - let r in 0 .. INSTR_BENCHMARK_BATCHES; + let r in 0 .. INSTR_BENCHMARK_RUNS; let max_globals = T::Schedule::get().limits.globals; let mut sbox = Sandbox::from(&WasmModule::::from(ModuleDefinition { call_body: Some(body::repeated_dyn(r, vec![ @@ -2600,7 +2606,7 @@ benchmarks! { // w_memory_get = w_bench - 1 * w_param #[pov_mode = Ignored] instr_memory_current { - let r in 0 .. INSTR_BENCHMARK_BATCHES; + let r in 0 .. INSTR_BENCHMARK_RUNS; let mut sbox = Sandbox::from(&WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), call_body: Some(body::repeated(r, &[ @@ -2642,7 +2648,7 @@ benchmarks! { #[pov_mode = Ignored] instr_i64clz { - let r in 0 .. INSTR_BENCHMARK_BATCHES; + let r in 0 .. INSTR_BENCHMARK_RUNS; let mut sbox = Sandbox::from(&WasmModule::::unary_instr( Instruction::I64Clz, r, @@ -2653,7 +2659,7 @@ benchmarks! { #[pov_mode = Ignored] instr_i64ctz { - let r in 0 .. INSTR_BENCHMARK_BATCHES; + let r in 0 .. INSTR_BENCHMARK_RUNS; let mut sbox = Sandbox::from(&WasmModule::::unary_instr( Instruction::I64Ctz, r, @@ -2664,7 +2670,7 @@ benchmarks! { #[pov_mode = Ignored] instr_i64popcnt { - let r in 0 .. INSTR_BENCHMARK_BATCHES; + let r in 0 .. INSTR_BENCHMARK_RUNS; let mut sbox = Sandbox::from(&WasmModule::::unary_instr( Instruction::I64Popcnt, r, @@ -2675,7 +2681,7 @@ benchmarks! { #[pov_mode = Ignored] instr_i64eqz { - let r in 0 .. INSTR_BENCHMARK_BATCHES; + let r in 0 .. INSTR_BENCHMARK_RUNS; let mut sbox = Sandbox::from(&WasmModule::::unary_instr( Instruction::I64Eqz, r, @@ -2686,7 +2692,7 @@ benchmarks! { #[pov_mode = Ignored] instr_i64extendsi32 { - let r in 0 .. INSTR_BENCHMARK_BATCHES; + let r in 0 .. INSTR_BENCHMARK_RUNS; let mut sbox = Sandbox::from(&WasmModule::::from(ModuleDefinition { call_body: Some(body::repeated_dyn(r, vec![ RandomI32Repeated(1), @@ -2701,7 +2707,7 @@ benchmarks! { #[pov_mode = Ignored] instr_i64extendui32 { - let r in 0 .. INSTR_BENCHMARK_BATCHES; + let r in 0 .. INSTR_BENCHMARK_RUNS; let mut sbox = Sandbox::from(&WasmModule::::from(ModuleDefinition { call_body: Some(body::repeated_dyn(r, vec![ RandomI32Repeated(1), @@ -2716,7 +2722,7 @@ benchmarks! { #[pov_mode = Ignored] instr_i32wrapi64 { - let r in 0 .. INSTR_BENCHMARK_BATCHES; + let r in 0 .. INSTR_BENCHMARK_RUNS; let mut sbox = Sandbox::from(&WasmModule::::unary_instr( Instruction::I32WrapI64, r, @@ -2730,7 +2736,7 @@ benchmarks! { #[pov_mode = Ignored] instr_i64eq { - let r in 0 .. INSTR_BENCHMARK_BATCHES; + let r in 0 .. INSTR_BENCHMARK_RUNS; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( Instruction::I64Eq, r, @@ -2741,7 +2747,7 @@ benchmarks! { #[pov_mode = Ignored] instr_i64ne { - let r in 0 .. INSTR_BENCHMARK_BATCHES; + let r in 0 .. INSTR_BENCHMARK_RUNS; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( Instruction::I64Ne, r, @@ -2752,7 +2758,7 @@ benchmarks! { #[pov_mode = Ignored] instr_i64lts { - let r in 0 .. INSTR_BENCHMARK_BATCHES; + let r in 0 .. INSTR_BENCHMARK_RUNS; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( Instruction::I64LtS, r, @@ -2763,7 +2769,7 @@ benchmarks! { #[pov_mode = Ignored] instr_i64ltu { - let r in 0 .. INSTR_BENCHMARK_BATCHES; + let r in 0 .. INSTR_BENCHMARK_RUNS; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( Instruction::I64LtU, r, @@ -2774,7 +2780,7 @@ benchmarks! { #[pov_mode = Ignored] instr_i64gts { - let r in 0 .. INSTR_BENCHMARK_BATCHES; + let r in 0 .. INSTR_BENCHMARK_RUNS; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( Instruction::I64GtS, r, @@ -2785,7 +2791,7 @@ benchmarks! { #[pov_mode = Ignored] instr_i64gtu { - let r in 0 .. INSTR_BENCHMARK_BATCHES; + let r in 0 .. INSTR_BENCHMARK_RUNS; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( Instruction::I64GtU, r, @@ -2796,7 +2802,7 @@ benchmarks! { #[pov_mode = Ignored] instr_i64les { - let r in 0 .. INSTR_BENCHMARK_BATCHES; + let r in 0 .. INSTR_BENCHMARK_RUNS; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( Instruction::I64LeS, r, @@ -2807,7 +2813,7 @@ benchmarks! { #[pov_mode = Ignored] instr_i64leu { - let r in 0 .. INSTR_BENCHMARK_BATCHES; + let r in 0 .. INSTR_BENCHMARK_RUNS; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( Instruction::I64LeU, r, @@ -2818,7 +2824,7 @@ benchmarks! { #[pov_mode = Ignored] instr_i64ges { - let r in 0 .. INSTR_BENCHMARK_BATCHES; + let r in 0 .. INSTR_BENCHMARK_RUNS; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( Instruction::I64GeS, r, @@ -2829,7 +2835,7 @@ benchmarks! { #[pov_mode = Ignored] instr_i64geu { - let r in 0 .. INSTR_BENCHMARK_BATCHES; + let r in 0 .. INSTR_BENCHMARK_RUNS; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( Instruction::I64GeU, r, @@ -2840,7 +2846,7 @@ benchmarks! { #[pov_mode = Ignored] instr_i64add { - let r in 0 .. INSTR_BENCHMARK_BATCHES; + let r in 0 .. INSTR_BENCHMARK_RUNS; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( Instruction::I64Add, r, @@ -2851,7 +2857,7 @@ benchmarks! { #[pov_mode = Ignored] instr_i64sub { - let r in 0 .. INSTR_BENCHMARK_BATCHES; + let r in 0 .. INSTR_BENCHMARK_RUNS; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( Instruction::I64Sub, r, @@ -2862,7 +2868,7 @@ benchmarks! { #[pov_mode = Ignored] instr_i64mul { - let r in 0 .. INSTR_BENCHMARK_BATCHES; + let r in 0 .. INSTR_BENCHMARK_RUNS; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( Instruction::I64Mul, r, @@ -2873,7 +2879,7 @@ benchmarks! { #[pov_mode = Ignored] instr_i64divs { - let r in 0 .. INSTR_BENCHMARK_BATCHES; + let r in 0 .. INSTR_BENCHMARK_RUNS; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( Instruction::I64DivS, r, @@ -2884,7 +2890,7 @@ benchmarks! { #[pov_mode = Ignored] instr_i64divu { - let r in 0 .. INSTR_BENCHMARK_BATCHES; + let r in 0 .. INSTR_BENCHMARK_RUNS; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( Instruction::I64DivU, r, @@ -2895,7 +2901,7 @@ benchmarks! { #[pov_mode = Ignored] instr_i64rems { - let r in 0 .. INSTR_BENCHMARK_BATCHES; + let r in 0 .. INSTR_BENCHMARK_RUNS; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( Instruction::I64RemS, r, @@ -2906,7 +2912,7 @@ benchmarks! { #[pov_mode = Ignored] instr_i64remu { - let r in 0 .. INSTR_BENCHMARK_BATCHES; + let r in 0 .. INSTR_BENCHMARK_RUNS; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( Instruction::I64RemU, r, @@ -2917,7 +2923,7 @@ benchmarks! { #[pov_mode = Ignored] instr_i64and { - let r in 0 .. INSTR_BENCHMARK_BATCHES; + let r in 0 .. INSTR_BENCHMARK_RUNS; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( Instruction::I64And, r, @@ -2928,7 +2934,7 @@ benchmarks! { #[pov_mode = Ignored] instr_i64or { - let r in 0 .. INSTR_BENCHMARK_BATCHES; + let r in 0 .. INSTR_BENCHMARK_RUNS; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( Instruction::I64Or, r, @@ -2939,7 +2945,7 @@ benchmarks! { #[pov_mode = Ignored] instr_i64xor { - let r in 0 .. INSTR_BENCHMARK_BATCHES; + let r in 0 .. INSTR_BENCHMARK_RUNS; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( Instruction::I64Xor, r, @@ -2950,7 +2956,7 @@ benchmarks! { #[pov_mode = Ignored] instr_i64shl { - let r in 0 .. INSTR_BENCHMARK_BATCHES; + let r in 0 .. INSTR_BENCHMARK_RUNS; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( Instruction::I64Shl, r, @@ -2961,7 +2967,7 @@ benchmarks! { #[pov_mode = Ignored] instr_i64shrs { - let r in 0 .. INSTR_BENCHMARK_BATCHES; + let r in 0 .. INSTR_BENCHMARK_RUNS; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( Instruction::I64ShrS, r, @@ -2972,7 +2978,7 @@ benchmarks! { #[pov_mode = Ignored] instr_i64shru { - let r in 0 .. INSTR_BENCHMARK_BATCHES; + let r in 0 .. INSTR_BENCHMARK_RUNS; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( Instruction::I64ShrU, r, @@ -2983,7 +2989,7 @@ benchmarks! { #[pov_mode = Ignored] instr_i64rotl { - let r in 0 .. INSTR_BENCHMARK_BATCHES; + let r in 0 .. INSTR_BENCHMARK_RUNS; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( Instruction::I64Rotl, r, @@ -2994,7 +3000,7 @@ benchmarks! { #[pov_mode = Ignored] instr_i64rotr { - let r in 0 .. INSTR_BENCHMARK_BATCHES; + let r in 0 .. INSTR_BENCHMARK_RUNS; let mut sbox = Sandbox::from(&WasmModule::::binary_instr( Instruction::I64Rotr, r, diff --git a/frame/contracts/src/weights.rs b/frame/contracts/src/weights.rs index 4333f26c5fc5c..dfe6fb20de7bc 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: 2023-03-17, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -177,8 +177,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `109` // Estimated: `1594` - // Minimum execution time: 2_567_000 picoseconds. - Weight::from_parts(2_711_000, 1594) + // Minimum execution time: 2_585_000 picoseconds. + Weight::from_parts(2_802_000, 1594) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: Skipped Metadata (r:0 w:0) @@ -188,10 +188,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `450 + k * (69 ±0)` // Estimated: `440 + k * (70 ±0)` - // Minimum execution time: 11_048_000 picoseconds. - Weight::from_parts(7_029_322, 440) - // Standard Error: 1_158 - .saturating_add(Weight::from_parts(975_010, 0).saturating_mul(k.into())) + // Minimum execution time: 10_825_000 picoseconds. + Weight::from_parts(5_747_064, 440) + // Standard Error: 1_037 + .saturating_add(Weight::from_parts(973_689, 0).saturating_mul(k.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) @@ -205,10 +205,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `250 + q * (33 ±0)` // Estimated: `1725 + q * (33 ±0)` - // Minimum execution time: 2_645_000 picoseconds. - Weight::from_parts(10_865_477, 1725) - // Standard Error: 3_383 - .saturating_add(Weight::from_parts(1_295_351, 0).saturating_mul(q.into())) + // Minimum execution time: 2_718_000 picoseconds. + Weight::from_parts(11_436_305, 1725) + // Standard Error: 3_619 + .saturating_add(Weight::from_parts(1_296_955, 0).saturating_mul(q.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 33).saturating_mul(q.into())) @@ -222,10 +222,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `238 + c * (1 ±0)` // Estimated: `3951 + c * (2 ±0)` - // Minimum execution time: 30_817_000 picoseconds. - Weight::from_parts(29_762_622, 3951) - // Standard Error: 62 - .saturating_add(Weight::from_parts(54_714, 0).saturating_mul(c.into())) + // Minimum execution time: 37_882_000 picoseconds. + Weight::from_parts(43_548_816, 3951) + // Standard Error: 49 + .saturating_add(Weight::from_parts(53_936, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 2).saturating_mul(c.into())) @@ -245,10 +245,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `707` // Estimated: `21400 + c * (5 ±0)` - // Minimum execution time: 245_493_000 picoseconds. - Weight::from_parts(253_703_384, 21400) - // Standard Error: 27 - .saturating_add(Weight::from_parts(38_078, 0).saturating_mul(c.into())) + // Minimum execution time: 313_392_000 picoseconds. + Weight::from_parts(325_419_093, 21400) + // Standard Error: 25 + .saturating_add(Weight::from_parts(37_877, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 5).saturating_mul(c.into())) @@ -276,14 +276,14 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `270` // Estimated: `26207` - // Minimum execution time: 3_079_430_000 picoseconds. - Weight::from_parts(555_022_483, 26207) - // Standard Error: 290 - .saturating_add(Weight::from_parts(107_411, 0).saturating_mul(c.into())) - // Standard Error: 17 - .saturating_add(Weight::from_parts(1_123, 0).saturating_mul(i.into())) - // Standard Error: 17 - .saturating_add(Weight::from_parts(1_434, 0).saturating_mul(s.into())) + // Minimum execution time: 3_274_352_000 picoseconds. + Weight::from_parts(681_171_416, 26207) + // Standard Error: 336 + .saturating_add(Weight::from_parts(106_391, 0).saturating_mul(c.into())) + // Standard Error: 19 + .saturating_add(Weight::from_parts(1_147, 0).saturating_mul(i.into())) + // Standard Error: 19 + .saturating_add(Weight::from_parts(1_493, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(10_u64)) } @@ -307,12 +307,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `482` // Estimated: `28521` - // Minimum execution time: 1_600_733_000 picoseconds. - Weight::from_parts(228_681_962, 28521) + // Minimum execution time: 1_692_637_000 picoseconds. + Weight::from_parts(283_252_265, 28521) // Standard Error: 8 - .saturating_add(Weight::from_parts(1_445, 0).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(1_498, 0).saturating_mul(i.into())) // Standard Error: 8 - .saturating_add(Weight::from_parts(1_456, 0).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_487, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } @@ -330,8 +330,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `759` // Estimated: `21615` - // Minimum execution time: 172_310_000 picoseconds. - Weight::from_parts(176_655_000, 21615) + // Minimum execution time: 192_369_000 picoseconds. + Weight::from_parts(193_417_000, 21615) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -348,10 +348,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `109` // Estimated: `7366` - // Minimum execution time: 246_364_000 picoseconds. - Weight::from_parts(262_887_234, 7366) - // Standard Error: 90 - .saturating_add(Weight::from_parts(107_926, 0).saturating_mul(c.into())) + // Minimum execution time: 301_972_000 picoseconds. + Weight::from_parts(313_248_051, 7366) + // Standard Error: 82 + .saturating_add(Weight::from_parts(107_321, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -367,8 +367,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `255` // Estimated: `7950` - // Minimum execution time: 29_226_000 picoseconds. - Weight::from_parts(29_542_000, 7950) + // Minimum execution time: 33_013_000 picoseconds. + Weight::from_parts(33_622_000, 7950) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -382,8 +382,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `570` // Estimated: `19530` - // Minimum execution time: 33_921_000 picoseconds. - Weight::from_parts(35_056_000, 19530) + // Minimum execution time: 33_518_000 picoseconds. + Weight::from_parts(33_819_000, 19530) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -402,10 +402,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `781 + r * (6 ±0)` // Estimated: `21730 + r * (30 ±0)` - // Minimum execution time: 232_118_000 picoseconds. - Weight::from_parts(233_883_823, 21730) - // Standard Error: 642 - .saturating_add(Weight::from_parts(340_543, 0).saturating_mul(r.into())) + // Minimum execution time: 283_945_000 picoseconds. + Weight::from_parts(289_209_599, 21730) + // Standard Error: 901 + .saturating_add(Weight::from_parts(327_601, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -425,10 +425,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `839 + r * (240 ±0)` // Estimated: `21835 + r * (3675 ±0)` - // Minimum execution time: 231_712_000 picoseconds. - Weight::from_parts(74_297_097, 21835) - // Standard Error: 6_099 - .saturating_add(Weight::from_parts(3_322_192, 0).saturating_mul(r.into())) + // Minimum execution time: 284_949_000 picoseconds. + Weight::from_parts(126_196_485, 21835) + // Standard Error: 6_260 + .saturating_add(Weight::from_parts(3_368_849, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -449,10 +449,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `831 + r * (244 ±0)` // Estimated: `21855 + r * (3695 ±0)` - // Minimum execution time: 233_122_000 picoseconds. - Weight::from_parts(74_369_473, 21855) - // Standard Error: 6_027 - .saturating_add(Weight::from_parts(4_177_187, 0).saturating_mul(r.into())) + // Minimum execution time: 286_429_000 picoseconds. + Weight::from_parts(124_820_396, 21855) + // Standard Error: 6_539 + .saturating_add(Weight::from_parts(4_163_535, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -473,10 +473,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `788 + r * (6 ±0)` // Estimated: `21770 + r * (30 ±0)` - // Minimum execution time: 232_822_000 picoseconds. - Weight::from_parts(232_507_418, 21770) - // Standard Error: 961 - .saturating_add(Weight::from_parts(419_331, 0).saturating_mul(r.into())) + // Minimum execution time: 285_042_000 picoseconds. + Weight::from_parts(288_096_303, 21770) + // Standard Error: 972 + .saturating_add(Weight::from_parts(409_782, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -496,10 +496,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `778 + r * (3 ±0)` // Estimated: `21735 + r * (15 ±0)` - // Minimum execution time: 229_719_000 picoseconds. - Weight::from_parts(235_257_789, 21735) - // Standard Error: 451 - .saturating_add(Weight::from_parts(161_101, 0).saturating_mul(r.into())) + // Minimum execution time: 282_820_000 picoseconds. + Weight::from_parts(287_104_710, 21735) + // Standard Error: 421 + .saturating_add(Weight::from_parts(167_907, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 15).saturating_mul(r.into())) @@ -519,10 +519,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `782 + r * (6 ±0)` // Estimated: `21740 + r * (30 ±0)` - // Minimum execution time: 231_517_000 picoseconds. - Weight::from_parts(236_185_452, 21740) - // Standard Error: 651 - .saturating_add(Weight::from_parts(334_659, 0).saturating_mul(r.into())) + // Minimum execution time: 284_619_000 picoseconds. + Weight::from_parts(281_326_785, 21740) + // Standard Error: 1_379 + .saturating_add(Weight::from_parts(342_779, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -542,10 +542,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `783 + r * (6 ±0)` // Estimated: `21725 + r * (30 ±0)` - // Minimum execution time: 232_855_000 picoseconds. - Weight::from_parts(239_986_328, 21725) - // Standard Error: 4_075 - .saturating_add(Weight::from_parts(345_726, 0).saturating_mul(r.into())) + // Minimum execution time: 284_703_000 picoseconds. + Weight::from_parts(289_479_932, 21725) + // Standard Error: 745 + .saturating_add(Weight::from_parts(323_625, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -565,10 +565,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `922 + r * (6 ±0)` // Estimated: `24633 + r * (30 ±0)` - // Minimum execution time: 231_685_000 picoseconds. - Weight::from_parts(245_514_261, 24633) - // Standard Error: 1_635 - .saturating_add(Weight::from_parts(1_523_359, 0).saturating_mul(r.into())) + // Minimum execution time: 283_610_000 picoseconds. + Weight::from_parts(299_901_534, 24633) + // Standard Error: 1_177 + .saturating_add(Weight::from_parts(1_474_603, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -588,10 +588,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `792 + r * (6 ±0)` // Estimated: `21825 + r * (30 ±0)` - // Minimum execution time: 233_361_000 picoseconds. - Weight::from_parts(234_553_471, 21825) - // Standard Error: 1_108 - .saturating_add(Weight::from_parts(330_383, 0).saturating_mul(r.into())) + // Minimum execution time: 284_474_000 picoseconds. + Weight::from_parts(283_540_273, 21825) + // Standard Error: 1_164 + .saturating_add(Weight::from_parts(339_262, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -611,10 +611,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `790 + r * (6 ±0)` // Estimated: `21815 + r * (30 ±0)` - // Minimum execution time: 231_918_000 picoseconds. - Weight::from_parts(239_128_416, 21815) - // Standard Error: 1_473 - .saturating_add(Weight::from_parts(317_879, 0).saturating_mul(r.into())) + // Minimum execution time: 284_521_000 picoseconds. + Weight::from_parts(285_747_754, 21815) + // Standard Error: 889 + .saturating_add(Weight::from_parts(326_428, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -634,10 +634,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `787 + r * (6 ±0)` // Estimated: `21805 + r * (30 ±0)` - // Minimum execution time: 231_936_000 picoseconds. - Weight::from_parts(232_240_207, 21805) - // Standard Error: 731 - .saturating_add(Weight::from_parts(330_713, 0).saturating_mul(r.into())) + // Minimum execution time: 284_103_000 picoseconds. + Weight::from_parts(283_801_256, 21805) + // Standard Error: 1_051 + .saturating_add(Weight::from_parts(334_081, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -657,10 +657,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `778 + r * (6 ±0)` // Estimated: `21735 + r * (30 ±0)` - // Minimum execution time: 231_978_000 picoseconds. - Weight::from_parts(224_881_201, 21735) - // Standard Error: 1_296 - .saturating_add(Weight::from_parts(346_872, 0).saturating_mul(r.into())) + // Minimum execution time: 284_187_000 picoseconds. + Weight::from_parts(289_414_364, 21735) + // Standard Error: 796 + .saturating_add(Weight::from_parts(324_603, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -682,10 +682,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `856 + r * (10 ±0)` // Estimated: `24446 + r * (60 ±0)` - // Minimum execution time: 231_707_000 picoseconds. - Weight::from_parts(245_939_854, 24446) - // Standard Error: 1_369 - .saturating_add(Weight::from_parts(1_380_453, 0).saturating_mul(r.into())) + // Minimum execution time: 284_953_000 picoseconds. + Weight::from_parts(290_535_752, 24446) + // Standard Error: 2_462 + .saturating_add(Weight::from_parts(1_361_518, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 60).saturating_mul(r.into())) @@ -705,10 +705,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `745 + r * (4 ±0)` // Estimated: `21555 + r * (20 ±0)` - // Minimum execution time: 157_429_000 picoseconds. - Weight::from_parts(161_047_355, 21555) - // Standard Error: 1_220 - .saturating_add(Weight::from_parts(134_497, 0).saturating_mul(r.into())) + // Minimum execution time: 160_775_000 picoseconds. + Weight::from_parts(164_652_364, 21555) + // Standard Error: 284 + .saturating_add(Weight::from_parts(132_574, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 20).saturating_mul(r.into())) @@ -728,10 +728,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `780 + r * (6 ±0)` // Estimated: `21740 + r * (30 ±0)` - // Minimum execution time: 232_561_000 picoseconds. - Weight::from_parts(230_989_499, 21740) - // Standard Error: 848 - .saturating_add(Weight::from_parts(282_053, 0).saturating_mul(r.into())) + // Minimum execution time: 284_072_000 picoseconds. + Weight::from_parts(288_418_644, 21740) + // Standard Error: 792 + .saturating_add(Weight::from_parts(272_881, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -751,10 +751,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `784` // Estimated: `21740` - // Minimum execution time: 237_080_000 picoseconds. - Weight::from_parts(239_380_994, 21740) - // Standard Error: 2 - .saturating_add(Weight::from_parts(592, 0).saturating_mul(n.into())) + // Minimum execution time: 286_671_000 picoseconds. + Weight::from_parts(292_151_662, 21740) + // Standard Error: 1 + .saturating_add(Weight::from_parts(638, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -773,10 +773,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `768 + r * (45 ±0)` // Estimated: `21660 + r * (225 ±0)` - // Minimum execution time: 228_669_000 picoseconds. - Weight::from_parts(230_916_471, 21660) - // Standard Error: 295_520 - .saturating_add(Weight::from_parts(1_420_928, 0).saturating_mul(r.into())) + // Minimum execution time: 280_334_000 picoseconds. + Weight::from_parts(283_487_571, 21660) + // Standard Error: 267_797 + .saturating_add(Weight::from_parts(3_803_128, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 225).saturating_mul(r.into())) @@ -796,10 +796,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `778` // Estimated: `21775` - // Minimum execution time: 231_626_000 picoseconds. - Weight::from_parts(232_097_413, 21775) + // Minimum execution time: 284_004_000 picoseconds. + Weight::from_parts(283_681_350, 21775) // Standard Error: 1 - .saturating_add(Weight::from_parts(185, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(232, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -822,10 +822,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `810 + r * (356 ±0)` // Estimated: `25511 + r * (15321 ±0)` - // Minimum execution time: 230_758_000 picoseconds. - Weight::from_parts(233_235_993, 25511) - // Standard Error: 196_168 - .saturating_add(Weight::from_parts(81_177_506, 0).saturating_mul(r.into())) + // Minimum execution time: 284_143_000 picoseconds. + Weight::from_parts(287_218_324, 25511) + // Standard Error: 343_611 + .saturating_add(Weight::from_parts(109_895_675, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((6_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -849,10 +849,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `825 + r * (10 ±0)` // Estimated: `24283 + r * (60 ±0)` - // Minimum execution time: 232_457_000 picoseconds. - Weight::from_parts(240_943_161, 24283) - // Standard Error: 3_085 - .saturating_add(Weight::from_parts(1_837_168, 0).saturating_mul(r.into())) + // Minimum execution time: 285_037_000 picoseconds. + Weight::from_parts(299_804_606, 24283) + // Standard Error: 5_518 + .saturating_add(Weight::from_parts(1_848_164, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 60).saturating_mul(r.into())) @@ -872,10 +872,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `778 + r * (10 ±0)` // Estimated: `21735 + r * (50 ±0)` - // Minimum execution time: 229_788_000 picoseconds. - Weight::from_parts(233_520_858, 21735) - // Standard Error: 9_561 - .saturating_add(Weight::from_parts(3_596_294, 0).saturating_mul(r.into())) + // Minimum execution time: 282_886_000 picoseconds. + Weight::from_parts(293_171_736, 21735) + // Standard Error: 2_171 + .saturating_add(Weight::from_parts(3_491_303, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 50).saturating_mul(r.into())) @@ -896,12 +896,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `797 + t * (32 ±0)` // Estimated: `21840 + t * (2640 ±0)` - // Minimum execution time: 248_294_000 picoseconds. - Weight::from_parts(239_709_759, 21840) - // Standard Error: 66_903 - .saturating_add(Weight::from_parts(2_880_732, 0).saturating_mul(t.into())) - // Standard Error: 18 - .saturating_add(Weight::from_parts(725, 0).saturating_mul(n.into())) + // Minimum execution time: 300_675_000 picoseconds. + Weight::from_parts(296_092_420, 21840) + // Standard Error: 130_733 + .saturating_add(Weight::from_parts(2_487_957, 0).saturating_mul(t.into())) + // Standard Error: 36 + .saturating_add(Weight::from_parts(565, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(t.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -923,10 +923,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `777 + r * (7 ±0)` // Estimated: `21725 + r * (35 ±0)` - // Minimum execution time: 170_601_000 picoseconds. - Weight::from_parts(165_819_714, 21725) - // Standard Error: 452 - .saturating_add(Weight::from_parts(240_362, 0).saturating_mul(r.into())) + // Minimum execution time: 166_638_000 picoseconds. + Weight::from_parts(171_353_083, 21725) + // Standard Error: 550 + .saturating_add(Weight::from_parts(238_768, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 35).saturating_mul(r.into())) @@ -946,10 +946,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `125728` // Estimated: `269977` - // Minimum execution time: 349_543_000 picoseconds. - Weight::from_parts(352_945_102, 269977) - // Standard Error: 2 - .saturating_add(Weight::from_parts(749, 0).saturating_mul(i.into())) + // Minimum execution time: 414_136_000 picoseconds. + Weight::from_parts(416_093_921, 269977) + // Standard Error: 3 + .saturating_add(Weight::from_parts(794, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -960,10 +960,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `845 + r * (292 ±0)` // Estimated: `843 + r * (293 ±0)` - // Minimum execution time: 238_766_000 picoseconds. - Weight::from_parts(130_994_282, 843) - // Standard Error: 10_413 - .saturating_add(Weight::from_parts(6_134_087, 0).saturating_mul(r.into())) + // Minimum execution time: 285_920_000 picoseconds. + Weight::from_parts(184_945_789, 843) + // Standard Error: 9_604 + .saturating_add(Weight::from_parts(6_012_522, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -977,10 +977,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1304` // Estimated: `1280` - // Minimum execution time: 248_137_000 picoseconds. - Weight::from_parts(265_535_917, 1280) - // Standard Error: 28 - .saturating_add(Weight::from_parts(387, 0).saturating_mul(n.into())) + // Minimum execution time: 299_772_000 picoseconds. + Weight::from_parts(333_451_106, 1280) + // Standard Error: 54 + .saturating_add(Weight::from_parts(579, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -991,10 +991,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1167 + n * (1 ±0)` // Estimated: `1167 + n * (1 ±0)` - // Minimum execution time: 246_752_000 picoseconds. - Weight::from_parts(250_315_210, 1167) - // Standard Error: 42 - .saturating_add(Weight::from_parts(135, 0).saturating_mul(n.into())) + // Minimum execution time: 299_279_000 picoseconds. + Weight::from_parts(302_336_567, 1167) + // Standard Error: 25 + .saturating_add(Weight::from_parts(86, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -1006,10 +1006,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `841 + r * (288 ±0)` // Estimated: `845 + r * (289 ±0)` - // Minimum execution time: 232_873_000 picoseconds. - Weight::from_parts(130_360_558, 845) - // Standard Error: 10_026 - .saturating_add(Weight::from_parts(6_023_862, 0).saturating_mul(r.into())) + // Minimum execution time: 284_689_000 picoseconds. + Weight::from_parts(185_207_302, 845) + // Standard Error: 10_030 + .saturating_add(Weight::from_parts(5_871_325, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1023,10 +1023,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1163 + n * (1 ±0)` // Estimated: `1163 + n * (1 ±0)` - // Minimum execution time: 247_079_000 picoseconds. - Weight::from_parts(248_922_003, 1163) - // Standard Error: 22 - .saturating_add(Weight::from_parts(201, 0).saturating_mul(n.into())) + // Minimum execution time: 299_364_000 picoseconds. + Weight::from_parts(302_089_070, 1163) + // Standard Error: 23 + .saturating_add(Weight::from_parts(128, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -1038,10 +1038,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `835 + r * (296 ±0)` // Estimated: `840 + r * (297 ±0)` - // Minimum execution time: 232_696_000 picoseconds. - Weight::from_parts(144_147_151, 840) - // Standard Error: 8_846 - .saturating_add(Weight::from_parts(4_931_414, 0).saturating_mul(r.into())) + // Minimum execution time: 285_175_000 picoseconds. + Weight::from_parts(200_262_957, 840) + // Standard Error: 8_681 + .saturating_add(Weight::from_parts(4_899_266, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1054,10 +1054,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1179 + n * (1 ±0)` // Estimated: `1179 + n * (1 ±0)` - // Minimum execution time: 247_795_000 picoseconds. - Weight::from_parts(252_944_118, 1179) - // Standard Error: 45 - .saturating_add(Weight::from_parts(480, 0).saturating_mul(n.into())) + // Minimum execution time: 299_459_000 picoseconds. + Weight::from_parts(302_451_160, 1179) + // Standard Error: 36 + .saturating_add(Weight::from_parts(731, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -1069,10 +1069,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `856 + r * (288 ±0)` // Estimated: `857 + r * (289 ±0)` - // Minimum execution time: 232_166_000 picoseconds. - Weight::from_parts(148_503_428, 857) - // Standard Error: 8_704 - .saturating_add(Weight::from_parts(4_766_055, 0).saturating_mul(r.into())) + // Minimum execution time: 286_384_000 picoseconds. + Weight::from_parts(203_389_467, 857) + // Standard Error: 8_817 + .saturating_add(Weight::from_parts(4_692_347, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1085,10 +1085,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1166 + n * (1 ±0)` // Estimated: `1166 + n * (1 ±0)` - // Minimum execution time: 246_128_000 picoseconds. - Weight::from_parts(248_323_705, 1166) - // Standard Error: 21 - .saturating_add(Weight::from_parts(92, 0).saturating_mul(n.into())) + // Minimum execution time: 297_450_000 picoseconds. + Weight::from_parts(300_459_851, 1166) + // Standard Error: 39 + .saturating_add(Weight::from_parts(108, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -1100,10 +1100,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `829 + r * (296 ±0)` // Estimated: `836 + r * (297 ±0)` - // Minimum execution time: 232_976_000 picoseconds. - Weight::from_parts(132_373_848, 836) - // Standard Error: 9_855 - .saturating_add(Weight::from_parts(6_181_821, 0).saturating_mul(r.into())) + // Minimum execution time: 285_572_000 picoseconds. + Weight::from_parts(182_642_557, 836) + // Standard Error: 9_977 + .saturating_add(Weight::from_parts(6_090_684, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1117,10 +1117,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1180 + n * (1 ±0)` // Estimated: `1180 + n * (1 ±0)` - // Minimum execution time: 247_907_000 picoseconds. - Weight::from_parts(251_984_133, 1180) - // Standard Error: 41 - .saturating_add(Weight::from_parts(639, 0).saturating_mul(n.into())) + // Minimum execution time: 301_344_000 picoseconds. + Weight::from_parts(303_770_522, 1180) + // Standard Error: 29 + .saturating_add(Weight::from_parts(807, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -1140,10 +1140,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1373 + r * (45 ±0)` // Estimated: `26753 + r * (2700 ±0)` - // Minimum execution time: 232_614_000 picoseconds. - Weight::from_parts(127_024_367, 26753) - // Standard Error: 54_521 - .saturating_add(Weight::from_parts(20_975_575, 0).saturating_mul(r.into())) + // Minimum execution time: 286_835_000 picoseconds. + Weight::from_parts(245_206_457, 26753) + // Standard Error: 73_782 + .saturating_add(Weight::from_parts(36_414_448, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(4_u64)) @@ -1152,53 +1152,53 @@ impl WeightInfo for SubstrateWeight { } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) - /// Storage: Contracts ContractInfoOf (r:1601 w:1601) + /// Storage: Contracts ContractInfoOf (r:801 w:801) /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:2 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) - /// Storage: System EventTopics (r:1602 w:1602) + /// Storage: System EventTopics (r:802 w:802) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 1600]`. + /// The range of component `r` is `[0, 800]`. fn seal_call(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1512 + r * (256 ±0)` - // Estimated: `27163 + r * (6231 ±0)` - // Minimum execution time: 233_446_000 picoseconds. - Weight::from_parts(234_338_000, 27163) - // Standard Error: 122_754 - .saturating_add(Weight::from_parts(216_709_600, 0).saturating_mul(r.into())) + // Measured: `1237 + r * (256 ±0)` + // Estimated: `26028 + r * (6235 ±0)` + // Minimum execution time: 287_184_000 picoseconds. + Weight::from_parts(287_525_000, 26028) + // Standard Error: 66_791 + .saturating_add(Weight::from_parts(261_473_539, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 6231).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 6235).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) - /// Storage: Contracts CodeStorage (r:1536 w:0) + /// Storage: Contracts CodeStorage (r:736 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) - /// Storage: System EventTopics (r:1537 w:1537) + /// Storage: System EventTopics (r:737 w:737) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 1600]`. + /// The range of component `r` is `[0, 800]`. fn seal_delegate_call(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0 + r * (902 ±0)` - // Estimated: `21755 + r * (8167 ±7)` - // Minimum execution time: 232_717_000 picoseconds. - Weight::from_parts(233_405_000, 21755) - // Standard Error: 98_607 - .saturating_add(Weight::from_parts(212_329_100, 0).saturating_mul(r.into())) + // Measured: `0 + r * (502 ±0)` + // Estimated: `21755 + r * (6329 ±10)` + // Minimum execution time: 285_759_000 picoseconds. + Weight::from_parts(286_643_000, 21755) + // Standard Error: 133_180 + .saturating_add(Weight::from_parts(257_186_897, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 8167).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 6329).saturating_mul(r.into())) } /// Storage: System Account (r:3 w:2) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1216,46 +1216,46 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1154 + t * (204 ±0)` // Estimated: `31015 + t * (5970 ±0)` - // Minimum execution time: 392_113_000 picoseconds. - Weight::from_parts(376_522_702, 31015) - // Standard Error: 1_388_011 - .saturating_add(Weight::from_parts(19_125_093, 0).saturating_mul(t.into())) - // Standard Error: 2 - .saturating_add(Weight::from_parts(609, 0).saturating_mul(c.into())) + // Minimum execution time: 459_675_000 picoseconds. + Weight::from_parts(427_010_987, 31015) + // Standard Error: 1_277_377 + .saturating_add(Weight::from_parts(36_899_889, 0).saturating_mul(t.into())) + // Standard Error: 1 + .saturating_add(Weight::from_parts(651, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(t.into()))) .saturating_add(T::DbWeight::get().writes(5_u64)) .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(t.into()))) .saturating_add(Weight::from_parts(0, 5970).saturating_mul(t.into())) } - /// Storage: System Account (r:3202 w:3202) + /// Storage: System Account (r:1602 w:1602) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) - /// Storage: Contracts ContractInfoOf (r:1601 w:1601) + /// Storage: Contracts ContractInfoOf (r:801 w:801) /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) - /// Storage: Contracts CodeStorage (r:1601 w:0) + /// Storage: Contracts CodeStorage (r:801 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: Contracts Nonce (r:1 w:1) /// Proof: Contracts Nonce (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) - /// Storage: Contracts OwnerInfoOf (r:1600 w:1600) + /// Storage: Contracts OwnerInfoOf (r:800 w:800) /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Measured) - /// Storage: System EventTopics (r:1602 w:1602) + /// Storage: System EventTopics (r:802 w:802) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 1600]`. + /// The range of component `r` is `[0, 800]`. fn seal_instantiate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1859 + r * (253 ±0)` - // Estimated: `33859 + r * (16628 ±0)` - // Minimum execution time: 234_438_000 picoseconds. - Weight::from_parts(234_751_000, 33859) - // Standard Error: 450_507 - .saturating_add(Weight::from_parts(313_121_404, 0).saturating_mul(r.into())) + // Measured: `1301 + r * (254 ±0)` + // Estimated: `30977 + r * (16635 ±0)` + // Minimum execution time: 285_816_000 picoseconds. + Weight::from_parts(286_349_000, 30977) + // Standard Error: 269_144 + .saturating_add(Weight::from_parts(394_282_520, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().reads((6_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(6_u64)) .saturating_add(T::DbWeight::get().writes((5_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 16628).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 16635).saturating_mul(r.into())) } /// Storage: System Account (r:4 w:4) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1278,14 +1278,14 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1071 + t * (187 ±0)` // Estimated: `42684 + t * (3588 ±2)` - // Minimum execution time: 1_570_178_000 picoseconds. - Weight::from_parts(284_062_841, 42684) - // Standard Error: 4_396_597 - .saturating_add(Weight::from_parts(106_424_960, 0).saturating_mul(t.into())) + // Minimum execution time: 1_708_330_000 picoseconds. + Weight::from_parts(395_059_764, 42684) + // Standard Error: 4_545_552 + .saturating_add(Weight::from_parts(114_039_862, 0).saturating_mul(t.into())) // Standard Error: 7 - .saturating_add(Weight::from_parts(1_183, 0).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(1_213, 0).saturating_mul(i.into())) // Standard Error: 7 - .saturating_add(Weight::from_parts(1_354, 0).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_379, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(13_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(t.into()))) .saturating_add(T::DbWeight::get().writes(10_u64)) @@ -1307,10 +1307,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `777 + r * (8 ±0)` // Estimated: `21710 + r * (40 ±0)` - // Minimum execution time: 230_557_000 picoseconds. - Weight::from_parts(233_276_698, 21710) - // Standard Error: 1_026 - .saturating_add(Weight::from_parts(587_723, 0).saturating_mul(r.into())) + // Minimum execution time: 283_738_000 picoseconds. + Weight::from_parts(289_885_978, 21710) + // Standard Error: 1_057 + .saturating_add(Weight::from_parts(575_432, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) @@ -1330,10 +1330,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `785` // Estimated: `21745` - // Minimum execution time: 234_151_000 picoseconds. - Weight::from_parts(240_199_365, 21745) - // Standard Error: 3 - .saturating_add(Weight::from_parts(3_941, 0).saturating_mul(n.into())) + // Minimum execution time: 285_070_000 picoseconds. + Weight::from_parts(283_987_687, 21745) + // Standard Error: 6 + .saturating_add(Weight::from_parts(4_008, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1352,10 +1352,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `779 + r * (8 ±0)` // Estimated: `21725 + r * (40 ±0)` - // Minimum execution time: 229_931_000 picoseconds. - Weight::from_parts(234_961_690, 21725) - // Standard Error: 1_073 - .saturating_add(Weight::from_parts(758_259, 0).saturating_mul(r.into())) + // Minimum execution time: 281_613_000 picoseconds. + Weight::from_parts(285_429_053, 21725) + // Standard Error: 1_164 + .saturating_add(Weight::from_parts(756_244, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) @@ -1375,10 +1375,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `787` // Estimated: `21765` - // Minimum execution time: 232_448_000 picoseconds. - Weight::from_parts(225_974_008, 21765) + // Minimum execution time: 284_593_000 picoseconds. + Weight::from_parts(278_467_111, 21765) // Standard Error: 2 - .saturating_add(Weight::from_parts(3_174, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(3_217, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1397,10 +1397,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `779 + r * (8 ±0)` // Estimated: `21740 + r * (40 ±0)` - // Minimum execution time: 229_251_000 picoseconds. - Weight::from_parts(234_182_627, 21740) - // Standard Error: 836 - .saturating_add(Weight::from_parts(424_375, 0).saturating_mul(r.into())) + // Minimum execution time: 281_759_000 picoseconds. + Weight::from_parts(288_807_137, 21740) + // Standard Error: 805 + .saturating_add(Weight::from_parts(424_378, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) @@ -1420,10 +1420,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `787` // Estimated: `21785` - // Minimum execution time: 230_896_000 picoseconds. - Weight::from_parts(224_913_556, 21785) + // Minimum execution time: 282_666_000 picoseconds. + Weight::from_parts(274_357_944, 21785) // Standard Error: 2 - .saturating_add(Weight::from_parts(919, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(974, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1442,10 +1442,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `779 + r * (8 ±0)` // Estimated: `21745 + r * (40 ±0)` - // Minimum execution time: 230_314_000 picoseconds. - Weight::from_parts(233_426_327, 21745) - // Standard Error: 926 - .saturating_add(Weight::from_parts(425_341, 0).saturating_mul(r.into())) + // Minimum execution time: 285_073_000 picoseconds. + Weight::from_parts(287_226_796, 21745) + // Standard Error: 951 + .saturating_add(Weight::from_parts(425_368, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) @@ -1465,10 +1465,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `787` // Estimated: `21755` - // Minimum execution time: 230_424_000 picoseconds. - Weight::from_parts(231_136_218, 21755) + // Minimum execution time: 283_407_000 picoseconds. + Weight::from_parts(276_737_242, 21755) // Standard Error: 2 - .saturating_add(Weight::from_parts(917, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(967, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1482,18 +1482,18 @@ impl WeightInfo for SubstrateWeight { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 1600]`. + /// The range of component `r` is `[0, 160]`. fn seal_ecdsa_recover(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `704 + r * (78 ±0)` - // Estimated: `21370 + r * (390 ±0)` - // Minimum execution time: 232_862_000 picoseconds. - Weight::from_parts(379_152_870, 21370) - // Standard Error: 11_607 - .saturating_add(Weight::from_parts(36_955_410, 0).saturating_mul(r.into())) + // Measured: `822 + r * (76 ±0)` + // Estimated: `21705 + r * (385 ±0)` + // Minimum execution time: 285_130_000 picoseconds. + Weight::from_parts(299_449_202, 21705) + // Standard Error: 16_535 + .saturating_add(Weight::from_parts(37_655_189, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 390).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 385).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1505,18 +1505,18 @@ impl WeightInfo for SubstrateWeight { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 1600]`. + /// The range of component `r` is `[0, 160]`. fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `549 + r * (44 ±0)` - // Estimated: `20630 + r * (220 ±0)` - // Minimum execution time: 232_668_000 picoseconds. - Weight::from_parts(253_308_468, 20630) - // Standard Error: 3_022 - .saturating_add(Weight::from_parts(9_249_849, 0).saturating_mul(r.into())) + // Measured: `792 + r * (42 ±0)` + // Estimated: `21780 + r * (210 ±0)` + // Minimum execution time: 284_494_000 picoseconds. + Weight::from_parts(282_154_339, 21780) + // Standard Error: 12_278 + .saturating_add(Weight::from_parts(9_501_559, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 220).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 210).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1535,10 +1535,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0 + r * (964 ±0)` // Estimated: `29920 + r * (11544 ±7)` - // Minimum execution time: 233_910_000 picoseconds. - Weight::from_parts(234_607_000, 29920) - // Standard Error: 46_118 - .saturating_add(Weight::from_parts(21_927_957, 0).saturating_mul(r.into())) + // Minimum execution time: 285_306_000 picoseconds. + Weight::from_parts(286_080_000, 29920) + // Standard Error: 43_813 + .saturating_add(Weight::from_parts(21_758_329, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1560,10 +1560,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `773 + r * (3 ±0)` // Estimated: `21735 + r * (15 ±0)` - // Minimum execution time: 231_823_000 picoseconds. - Weight::from_parts(237_996_137, 21735) - // Standard Error: 598 - .saturating_add(Weight::from_parts(163_106, 0).saturating_mul(r.into())) + // Minimum execution time: 283_487_000 picoseconds. + Weight::from_parts(289_280_189, 21735) + // Standard Error: 829 + .saturating_add(Weight::from_parts(168_973, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 15).saturating_mul(r.into())) @@ -1583,10 +1583,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1975 + r * (39 ±0)` // Estimated: `27145 + r * (200 ±0)` - // Minimum execution time: 235_077_000 picoseconds. - Weight::from_parts(267_876_360, 27145) - // Standard Error: 1_147 - .saturating_add(Weight::from_parts(256_275, 0).saturating_mul(r.into())) + // Minimum execution time: 287_413_000 picoseconds. + Weight::from_parts(314_662_286, 27145) + // Standard Error: 1_099 + .saturating_add(Weight::from_parts(262_201, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 200).saturating_mul(r.into())) @@ -1608,10 +1608,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `776 + r * (3 ±0)` // Estimated: `24004 + r * (18 ±0)` - // Minimum execution time: 231_384_000 picoseconds. - Weight::from_parts(237_086_900, 24004) - // Standard Error: 534 - .saturating_add(Weight::from_parts(140_842, 0).saturating_mul(r.into())) + // Minimum execution time: 282_601_000 picoseconds. + Weight::from_parts(289_374_203, 24004) + // Standard Error: 452 + .saturating_add(Weight::from_parts(142_661, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 18).saturating_mul(r.into())) @@ -1621,510 +1621,508 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_721_000 picoseconds. - Weight::from_parts(2_456_746, 0) - // Standard Error: 30 - .saturating_add(Weight::from_parts(2_788, 0).saturating_mul(r.into())) + // Minimum execution time: 1_692_000 picoseconds. + Weight::from_parts(2_069_482, 0) + // Standard Error: 40 + .saturating_add(Weight::from_parts(2_922, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64load(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_824_000 picoseconds. - Weight::from_parts(2_366_036, 0) - // Standard Error: 5 - .saturating_add(Weight::from_parts(6_446, 0).saturating_mul(r.into())) + // Minimum execution time: 1_690_000 picoseconds. + Weight::from_parts(2_303_602, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(6_433, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64store(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_840_000 picoseconds. - Weight::from_parts(2_332_115, 0) + // Minimum execution time: 1_701_000 picoseconds. + Weight::from_parts(2_321_142, 0) // Standard Error: 4 - .saturating_add(Weight::from_parts(6_012, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(6_025, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_select(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_731_000 picoseconds. - Weight::from_parts(2_078_873, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(7_931, 0).saturating_mul(r.into())) + // Minimum execution time: 1_656_000 picoseconds. + Weight::from_parts(2_090_881, 0) + // Standard Error: 5 + .saturating_add(Weight::from_parts(7_941, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_if(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_768_000 picoseconds. - Weight::from_parts(1_916_551, 0) - // Standard Error: 8 - .saturating_add(Weight::from_parts(10_597, 0).saturating_mul(r.into())) + // Minimum execution time: 1_659_000 picoseconds. + Weight::from_parts(1_816_547, 0) + // Standard Error: 5 + .saturating_add(Weight::from_parts(10_578, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_br(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_735_000 picoseconds. - Weight::from_parts(1_962_845, 0) - // Standard Error: 14 - .saturating_add(Weight::from_parts(4_631, 0).saturating_mul(r.into())) + // Minimum execution time: 1_683_000 picoseconds. + Weight::from_parts(1_970_907, 0) + // Standard Error: 12 + .saturating_add(Weight::from_parts(4_636, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_br_if(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_688_000 picoseconds. - Weight::from_parts(1_172_825, 0) - // Standard Error: 76 - .saturating_add(Weight::from_parts(8_007, 0).saturating_mul(r.into())) + // Minimum execution time: 1_651_000 picoseconds. + Weight::from_parts(2_263_817, 0) + // Standard Error: 68 + .saturating_add(Weight::from_parts(7_529, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_br_table(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_725_000 picoseconds. - Weight::from_parts(1_535_833, 0) - // Standard Error: 26 - .saturating_add(Weight::from_parts(9_489, 0).saturating_mul(r.into())) + // Minimum execution time: 1_687_000 picoseconds. + Weight::from_parts(1_349_186, 0) + // Standard Error: 31 + .saturating_add(Weight::from_parts(9_732, 0).saturating_mul(r.into())) } /// The range of component `e` is `[1, 256]`. - fn instr_br_table_per_entry(e: u32, ) -> Weight { + fn instr_br_table_per_entry(_e: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_814_000 picoseconds. - Weight::from_parts(1_926_367, 0) - // Standard Error: 16 - .saturating_add(Weight::from_parts(219, 0).saturating_mul(e.into())) + // Minimum execution time: 1_777_000 picoseconds. + Weight::from_parts(2_036_446, 0) } /// The range of component `r` is `[0, 5000]`. fn instr_call(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_770_000 picoseconds. - Weight::from_parts(2_436_918, 0) - // Standard Error: 8 - .saturating_add(Weight::from_parts(17_890, 0).saturating_mul(r.into())) + // Minimum execution time: 1_686_000 picoseconds. + Weight::from_parts(464_449, 0) + // Standard Error: 383 + .saturating_add(Weight::from_parts(19_121, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_call_indirect(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_920_000 picoseconds. - Weight::from_parts(2_729_712, 0) - // Standard Error: 39 - .saturating_add(Weight::from_parts(24_853, 0).saturating_mul(r.into())) + // Minimum execution time: 1_855_000 picoseconds. + Weight::from_parts(3_381_585, 0) + // Standard Error: 18 + .saturating_add(Weight::from_parts(24_245, 0).saturating_mul(r.into())) } /// The range of component `l` is `[0, 1024]`. fn instr_call_per_local(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_869_000 picoseconds. - Weight::from_parts(2_147_970, 0) - // Standard Error: 46 - .saturating_add(Weight::from_parts(1_237, 0).saturating_mul(l.into())) + // Minimum execution time: 1_792_000 picoseconds. + Weight::from_parts(2_006_024, 0) + // Standard Error: 16 + .saturating_add(Weight::from_parts(2_181, 0).saturating_mul(l.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_local_get(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_012_000 picoseconds. - Weight::from_parts(3_234_440, 0) - // Standard Error: 1 - .saturating_add(Weight::from_parts(2_433, 0).saturating_mul(r.into())) + // Minimum execution time: 3_918_000 picoseconds. + Weight::from_parts(4_618_761, 0) + // Standard Error: 49 + .saturating_add(Weight::from_parts(2_312, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_local_set(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_037_000 picoseconds. - Weight::from_parts(3_204_600, 0) + // Minimum execution time: 3_889_000 picoseconds. + Weight::from_parts(4_151_280, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(3_627, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_623, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_local_tee(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_974_000 picoseconds. - Weight::from_parts(3_301_366, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(3_836, 0).saturating_mul(r.into())) + // Minimum execution time: 3_880_000 picoseconds. + Weight::from_parts(4_225_780, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(3_847, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_global_get(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_853_000 picoseconds. - Weight::from_parts(2_310_141, 0) + // Minimum execution time: 1_765_000 picoseconds. + Weight::from_parts(2_216_674, 0) // Standard Error: 4 - .saturating_add(Weight::from_parts(8_387, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(8_393, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_global_set(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_828_000 picoseconds. - Weight::from_parts(2_315_323, 0) - // Standard Error: 4 - .saturating_add(Weight::from_parts(8_797, 0).saturating_mul(r.into())) + // Minimum execution time: 1_764_000 picoseconds. + Weight::from_parts(2_246_735, 0) + // Standard Error: 5 + .saturating_add(Weight::from_parts(8_877, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_memory_current(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_800_000 picoseconds. - Weight::from_parts(2_117_252, 0) - // Standard Error: 4 - .saturating_add(Weight::from_parts(3_741, 0).saturating_mul(r.into())) + // Minimum execution time: 1_758_000 picoseconds. + Weight::from_parts(1_922_386, 0) + // Standard Error: 94 + .saturating_add(Weight::from_parts(3_868, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 16]`. fn instr_memory_grow(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_743_000 picoseconds. - Weight::from_parts(1_054_728, 0) - // Standard Error: 137_128 - .saturating_add(Weight::from_parts(13_179_446, 0).saturating_mul(r.into())) + // Minimum execution time: 1_635_000 picoseconds. + Weight::from_parts(1_118_785, 0) + // Standard Error: 134_978 + .saturating_add(Weight::from_parts(16_343_664, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64clz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_735_000 picoseconds. - Weight::from_parts(2_026_568, 0) + // Minimum execution time: 1_648_000 picoseconds. + Weight::from_parts(2_012_545, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(3_802, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_824, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64ctz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_630_000 picoseconds. - Weight::from_parts(1_980_222, 0) + // Minimum execution time: 1_688_000 picoseconds. + Weight::from_parts(1_995_956, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(3_735, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_757, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64popcnt(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_695_000 picoseconds. - Weight::from_parts(2_040_266, 0) - // Standard Error: 8 - .saturating_add(Weight::from_parts(3_718, 0).saturating_mul(r.into())) + // Minimum execution time: 1_631_000 picoseconds. + Weight::from_parts(2_011_493, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(3_755, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64eqz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_697_000 picoseconds. - Weight::from_parts(2_004_663, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(3_661, 0).saturating_mul(r.into())) + // Minimum execution time: 1_667_000 picoseconds. + Weight::from_parts(1_958_798, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(3_677, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64extendsi32(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_705_000 picoseconds. - Weight::from_parts(2_682_122, 0) - // Standard Error: 98 - .saturating_add(Weight::from_parts(3_705, 0).saturating_mul(r.into())) + // Minimum execution time: 1_674_000 picoseconds. + Weight::from_parts(2_009_555, 0) + // Standard Error: 7 + .saturating_add(Weight::from_parts(3_863, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64extendui32(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_674_000 picoseconds. - Weight::from_parts(1_989_835, 0) + // Minimum execution time: 1_659_000 picoseconds. + Weight::from_parts(2_014_985, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(3_801, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_821, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i32wrapi64(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_695_000 picoseconds. - Weight::from_parts(2_083_824, 0) - // Standard Error: 17 - .saturating_add(Weight::from_parts(3_719, 0).saturating_mul(r.into())) + // Minimum execution time: 1_640_000 picoseconds. + Weight::from_parts(2_013_939, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(3_708, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64eq(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_678_000 picoseconds. - Weight::from_parts(1_996_335, 0) - // Standard Error: 4 - .saturating_add(Weight::from_parts(5_995, 0).saturating_mul(r.into())) + // Minimum execution time: 1_631_000 picoseconds. + Weight::from_parts(2_002_814, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(6_008, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64ne(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_697_000 picoseconds. - Weight::from_parts(2_046_566, 0) + // Minimum execution time: 1_647_000 picoseconds. + Weight::from_parts(2_032_158, 0) // Standard Error: 3 - .saturating_add(Weight::from_parts(5_936, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(5_944, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64lts(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_721_000 picoseconds. - Weight::from_parts(2_406_930, 0) - // Standard Error: 150 - .saturating_add(Weight::from_parts(5_992, 0).saturating_mul(r.into())) + // Minimum execution time: 1_669_000 picoseconds. + Weight::from_parts(2_040_386, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(6_009, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64ltu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_749_000 picoseconds. - Weight::from_parts(1_987_158, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(5_994, 0).saturating_mul(r.into())) + // Minimum execution time: 1_637_000 picoseconds. + Weight::from_parts(1_983_695, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(6_027, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64gts(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_706_000 picoseconds. - Weight::from_parts(2_038_138, 0) + // Minimum execution time: 1_701_000 picoseconds. + Weight::from_parts(2_054_295, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(5_802, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(5_799, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64gtu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_670_000 picoseconds. - Weight::from_parts(2_555_035, 0) - // Standard Error: 74 - .saturating_add(Weight::from_parts(5_958, 0).saturating_mul(r.into())) + // Minimum execution time: 1_653_000 picoseconds. + Weight::from_parts(2_749_807, 0) + // Standard Error: 90 + .saturating_add(Weight::from_parts(5_945, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64les(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_694_000 picoseconds. - Weight::from_parts(1_991_929, 0) - // Standard Error: 27 - .saturating_add(Weight::from_parts(6_037, 0).saturating_mul(r.into())) + // Minimum execution time: 1_651_000 picoseconds. + Weight::from_parts(1_979_111, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(6_011, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64leu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_684_000 picoseconds. - Weight::from_parts(1_969_284, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(6_104, 0).saturating_mul(r.into())) + // Minimum execution time: 1_743_000 picoseconds. + Weight::from_parts(2_058_081, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(6_085, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64ges(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_697_000 picoseconds. - Weight::from_parts(2_023_608, 0) + // Minimum execution time: 1_638_000 picoseconds. + Weight::from_parts(2_038_929, 0) // Standard Error: 3 - .saturating_add(Weight::from_parts(5_946, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(5_941, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64geu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_659_000 picoseconds. - Weight::from_parts(1_963_145, 0) - // Standard Error: 6 - .saturating_add(Weight::from_parts(6_014, 0).saturating_mul(r.into())) + // Minimum execution time: 1_641_000 picoseconds. + Weight::from_parts(2_036_587, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(6_008, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64add(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_722_000 picoseconds. - Weight::from_parts(2_016_286, 0) + // Minimum execution time: 1_624_000 picoseconds. + Weight::from_parts(2_080_562, 0) // Standard Error: 3 - .saturating_add(Weight::from_parts(5_889, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(5_826, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64sub(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_656_000 picoseconds. - Weight::from_parts(1_966_234, 0) - // Standard Error: 17 - .saturating_add(Weight::from_parts(6_171, 0).saturating_mul(r.into())) + // Minimum execution time: 1_652_000 picoseconds. + Weight::from_parts(2_039_535, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(6_137, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64mul(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_695_000 picoseconds. - Weight::from_parts(2_004_559, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(5_785, 0).saturating_mul(r.into())) + // Minimum execution time: 1_666_000 picoseconds. + Weight::from_parts(2_056_354, 0) + // Standard Error: 6 + .saturating_add(Weight::from_parts(5_780, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64divs(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_681_000 picoseconds. - Weight::from_parts(2_135_505, 0) - // Standard Error: 6 - .saturating_add(Weight::from_parts(11_761, 0).saturating_mul(r.into())) + // Minimum execution time: 1_648_000 picoseconds. + Weight::from_parts(2_077_695, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(11_775, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64divu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_653_000 picoseconds. - Weight::from_parts(2_153_167, 0) - // Standard Error: 5 - .saturating_add(Weight::from_parts(10_523, 0).saturating_mul(r.into())) + // Minimum execution time: 1_797_000 picoseconds. + Weight::from_parts(2_772_388, 0) + // Standard Error: 33 + .saturating_add(Weight::from_parts(10_333, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64rems(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_697_000 picoseconds. - Weight::from_parts(2_570_266, 0) - // Standard Error: 50 - .saturating_add(Weight::from_parts(11_971, 0).saturating_mul(r.into())) + // Minimum execution time: 1_699_000 picoseconds. + Weight::from_parts(2_174_288, 0) + // Standard Error: 6 + .saturating_add(Weight::from_parts(11_778, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64remu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_719_000 picoseconds. - Weight::from_parts(2_101_082, 0) + // Minimum execution time: 1_685_000 picoseconds. + Weight::from_parts(2_091_037, 0) // Standard Error: 3 - .saturating_add(Weight::from_parts(10_709, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(10_694, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64and(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_745_000 picoseconds. - Weight::from_parts(2_621_890, 0) - // Standard Error: 94 - .saturating_add(Weight::from_parts(5_545, 0).saturating_mul(r.into())) + // Minimum execution time: 1_636_000 picoseconds. + Weight::from_parts(1_975_521, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(5_695, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64or(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_670_000 picoseconds. - Weight::from_parts(2_046_821, 0) + // Minimum execution time: 1_619_000 picoseconds. + Weight::from_parts(2_045_492, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(5_762, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(5_770, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64xor(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_714_000 picoseconds. - Weight::from_parts(2_010_173, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(5_911, 0).saturating_mul(r.into())) + // Minimum execution time: 1_668_000 picoseconds. + Weight::from_parts(2_055_460, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(5_851, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64shl(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_756_000 picoseconds. - Weight::from_parts(2_044_772, 0) + // Minimum execution time: 1_681_000 picoseconds. + Weight::from_parts(2_023_370, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(5_857, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(5_853, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64shrs(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_741_000 picoseconds. - Weight::from_parts(2_012_819, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(6_127, 0).saturating_mul(r.into())) + // Minimum execution time: 1_714_000 picoseconds. + Weight::from_parts(2_067_584, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(6_133, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64shru(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_693_000 picoseconds. - Weight::from_parts(2_090_981, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(5_839, 0).saturating_mul(r.into())) + // Minimum execution time: 1_602_000 picoseconds. + Weight::from_parts(2_055_530, 0) + // Standard Error: 138 + .saturating_add(Weight::from_parts(6_014, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64rotl(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_704_000 picoseconds. - Weight::from_parts(2_014_108, 0) - // Standard Error: 4 - .saturating_add(Weight::from_parts(6_005, 0).saturating_mul(r.into())) + // Minimum execution time: 1_709_000 picoseconds. + Weight::from_parts(2_016_365, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(5_985, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64rotr(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_715_000 picoseconds. - Weight::from_parts(2_053_720, 0) - // Standard Error: 5 - .saturating_add(Weight::from_parts(5_860, 0).saturating_mul(r.into())) + // Minimum execution time: 1_661_000 picoseconds. + Weight::from_parts(2_003_063, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(5_863, 0).saturating_mul(r.into())) } } @@ -2136,8 +2134,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `109` // Estimated: `1594` - // Minimum execution time: 2_567_000 picoseconds. - Weight::from_parts(2_711_000, 1594) + // Minimum execution time: 2_585_000 picoseconds. + Weight::from_parts(2_802_000, 1594) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: Skipped Metadata (r:0 w:0) @@ -2147,10 +2145,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `450 + k * (69 ±0)` // Estimated: `440 + k * (70 ±0)` - // Minimum execution time: 11_048_000 picoseconds. - Weight::from_parts(7_029_322, 440) - // Standard Error: 1_158 - .saturating_add(Weight::from_parts(975_010, 0).saturating_mul(k.into())) + // Minimum execution time: 10_825_000 picoseconds. + Weight::from_parts(5_747_064, 440) + // Standard Error: 1_037 + .saturating_add(Weight::from_parts(973_689, 0).saturating_mul(k.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) @@ -2164,10 +2162,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `250 + q * (33 ±0)` // Estimated: `1725 + q * (33 ±0)` - // Minimum execution time: 2_645_000 picoseconds. - Weight::from_parts(10_865_477, 1725) - // Standard Error: 3_383 - .saturating_add(Weight::from_parts(1_295_351, 0).saturating_mul(q.into())) + // Minimum execution time: 2_718_000 picoseconds. + Weight::from_parts(11_436_305, 1725) + // Standard Error: 3_619 + .saturating_add(Weight::from_parts(1_296_955, 0).saturating_mul(q.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 33).saturating_mul(q.into())) @@ -2181,10 +2179,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `238 + c * (1 ±0)` // Estimated: `3951 + c * (2 ±0)` - // Minimum execution time: 30_817_000 picoseconds. - Weight::from_parts(29_762_622, 3951) - // Standard Error: 62 - .saturating_add(Weight::from_parts(54_714, 0).saturating_mul(c.into())) + // Minimum execution time: 37_882_000 picoseconds. + Weight::from_parts(43_548_816, 3951) + // Standard Error: 49 + .saturating_add(Weight::from_parts(53_936, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 2).saturating_mul(c.into())) @@ -2204,10 +2202,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `707` // Estimated: `21400 + c * (5 ±0)` - // Minimum execution time: 245_493_000 picoseconds. - Weight::from_parts(253_703_384, 21400) - // Standard Error: 27 - .saturating_add(Weight::from_parts(38_078, 0).saturating_mul(c.into())) + // Minimum execution time: 313_392_000 picoseconds. + Weight::from_parts(325_419_093, 21400) + // Standard Error: 25 + .saturating_add(Weight::from_parts(37_877, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 5).saturating_mul(c.into())) @@ -2235,14 +2233,14 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `270` // Estimated: `26207` - // Minimum execution time: 3_079_430_000 picoseconds. - Weight::from_parts(555_022_483, 26207) - // Standard Error: 290 - .saturating_add(Weight::from_parts(107_411, 0).saturating_mul(c.into())) - // Standard Error: 17 - .saturating_add(Weight::from_parts(1_123, 0).saturating_mul(i.into())) - // Standard Error: 17 - .saturating_add(Weight::from_parts(1_434, 0).saturating_mul(s.into())) + // Minimum execution time: 3_274_352_000 picoseconds. + Weight::from_parts(681_171_416, 26207) + // Standard Error: 336 + .saturating_add(Weight::from_parts(106_391, 0).saturating_mul(c.into())) + // Standard Error: 19 + .saturating_add(Weight::from_parts(1_147, 0).saturating_mul(i.into())) + // Standard Error: 19 + .saturating_add(Weight::from_parts(1_493, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(10_u64)) } @@ -2266,12 +2264,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `482` // Estimated: `28521` - // Minimum execution time: 1_600_733_000 picoseconds. - Weight::from_parts(228_681_962, 28521) + // Minimum execution time: 1_692_637_000 picoseconds. + Weight::from_parts(283_252_265, 28521) // Standard Error: 8 - .saturating_add(Weight::from_parts(1_445, 0).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(1_498, 0).saturating_mul(i.into())) // Standard Error: 8 - .saturating_add(Weight::from_parts(1_456, 0).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_487, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } @@ -2289,8 +2287,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `759` // Estimated: `21615` - // Minimum execution time: 172_310_000 picoseconds. - Weight::from_parts(176_655_000, 21615) + // Minimum execution time: 192_369_000 picoseconds. + Weight::from_parts(193_417_000, 21615) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -2307,10 +2305,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `109` // Estimated: `7366` - // Minimum execution time: 246_364_000 picoseconds. - Weight::from_parts(262_887_234, 7366) - // Standard Error: 90 - .saturating_add(Weight::from_parts(107_926, 0).saturating_mul(c.into())) + // Minimum execution time: 301_972_000 picoseconds. + Weight::from_parts(313_248_051, 7366) + // Standard Error: 82 + .saturating_add(Weight::from_parts(107_321, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -2326,8 +2324,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `255` // Estimated: `7950` - // Minimum execution time: 29_226_000 picoseconds. - Weight::from_parts(29_542_000, 7950) + // Minimum execution time: 33_013_000 picoseconds. + Weight::from_parts(33_622_000, 7950) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -2341,8 +2339,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `570` // Estimated: `19530` - // Minimum execution time: 33_921_000 picoseconds. - Weight::from_parts(35_056_000, 19530) + // Minimum execution time: 33_518_000 picoseconds. + Weight::from_parts(33_819_000, 19530) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -2361,10 +2359,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `781 + r * (6 ±0)` // Estimated: `21730 + r * (30 ±0)` - // Minimum execution time: 232_118_000 picoseconds. - Weight::from_parts(233_883_823, 21730) - // Standard Error: 642 - .saturating_add(Weight::from_parts(340_543, 0).saturating_mul(r.into())) + // Minimum execution time: 283_945_000 picoseconds. + Weight::from_parts(289_209_599, 21730) + // Standard Error: 901 + .saturating_add(Weight::from_parts(327_601, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -2384,10 +2382,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `839 + r * (240 ±0)` // Estimated: `21835 + r * (3675 ±0)` - // Minimum execution time: 231_712_000 picoseconds. - Weight::from_parts(74_297_097, 21835) - // Standard Error: 6_099 - .saturating_add(Weight::from_parts(3_322_192, 0).saturating_mul(r.into())) + // Minimum execution time: 284_949_000 picoseconds. + Weight::from_parts(126_196_485, 21835) + // Standard Error: 6_260 + .saturating_add(Weight::from_parts(3_368_849, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -2408,10 +2406,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `831 + r * (244 ±0)` // Estimated: `21855 + r * (3695 ±0)` - // Minimum execution time: 233_122_000 picoseconds. - Weight::from_parts(74_369_473, 21855) - // Standard Error: 6_027 - .saturating_add(Weight::from_parts(4_177_187, 0).saturating_mul(r.into())) + // Minimum execution time: 286_429_000 picoseconds. + Weight::from_parts(124_820_396, 21855) + // Standard Error: 6_539 + .saturating_add(Weight::from_parts(4_163_535, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -2432,10 +2430,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `788 + r * (6 ±0)` // Estimated: `21770 + r * (30 ±0)` - // Minimum execution time: 232_822_000 picoseconds. - Weight::from_parts(232_507_418, 21770) - // Standard Error: 961 - .saturating_add(Weight::from_parts(419_331, 0).saturating_mul(r.into())) + // Minimum execution time: 285_042_000 picoseconds. + Weight::from_parts(288_096_303, 21770) + // Standard Error: 972 + .saturating_add(Weight::from_parts(409_782, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -2455,10 +2453,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `778 + r * (3 ±0)` // Estimated: `21735 + r * (15 ±0)` - // Minimum execution time: 229_719_000 picoseconds. - Weight::from_parts(235_257_789, 21735) - // Standard Error: 451 - .saturating_add(Weight::from_parts(161_101, 0).saturating_mul(r.into())) + // Minimum execution time: 282_820_000 picoseconds. + Weight::from_parts(287_104_710, 21735) + // Standard Error: 421 + .saturating_add(Weight::from_parts(167_907, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 15).saturating_mul(r.into())) @@ -2478,10 +2476,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `782 + r * (6 ±0)` // Estimated: `21740 + r * (30 ±0)` - // Minimum execution time: 231_517_000 picoseconds. - Weight::from_parts(236_185_452, 21740) - // Standard Error: 651 - .saturating_add(Weight::from_parts(334_659, 0).saturating_mul(r.into())) + // Minimum execution time: 284_619_000 picoseconds. + Weight::from_parts(281_326_785, 21740) + // Standard Error: 1_379 + .saturating_add(Weight::from_parts(342_779, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -2501,10 +2499,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `783 + r * (6 ±0)` // Estimated: `21725 + r * (30 ±0)` - // Minimum execution time: 232_855_000 picoseconds. - Weight::from_parts(239_986_328, 21725) - // Standard Error: 4_075 - .saturating_add(Weight::from_parts(345_726, 0).saturating_mul(r.into())) + // Minimum execution time: 284_703_000 picoseconds. + Weight::from_parts(289_479_932, 21725) + // Standard Error: 745 + .saturating_add(Weight::from_parts(323_625, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -2524,10 +2522,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `922 + r * (6 ±0)` // Estimated: `24633 + r * (30 ±0)` - // Minimum execution time: 231_685_000 picoseconds. - Weight::from_parts(245_514_261, 24633) - // Standard Error: 1_635 - .saturating_add(Weight::from_parts(1_523_359, 0).saturating_mul(r.into())) + // Minimum execution time: 283_610_000 picoseconds. + Weight::from_parts(299_901_534, 24633) + // Standard Error: 1_177 + .saturating_add(Weight::from_parts(1_474_603, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -2547,10 +2545,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `792 + r * (6 ±0)` // Estimated: `21825 + r * (30 ±0)` - // Minimum execution time: 233_361_000 picoseconds. - Weight::from_parts(234_553_471, 21825) - // Standard Error: 1_108 - .saturating_add(Weight::from_parts(330_383, 0).saturating_mul(r.into())) + // Minimum execution time: 284_474_000 picoseconds. + Weight::from_parts(283_540_273, 21825) + // Standard Error: 1_164 + .saturating_add(Weight::from_parts(339_262, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -2570,10 +2568,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `790 + r * (6 ±0)` // Estimated: `21815 + r * (30 ±0)` - // Minimum execution time: 231_918_000 picoseconds. - Weight::from_parts(239_128_416, 21815) - // Standard Error: 1_473 - .saturating_add(Weight::from_parts(317_879, 0).saturating_mul(r.into())) + // Minimum execution time: 284_521_000 picoseconds. + Weight::from_parts(285_747_754, 21815) + // Standard Error: 889 + .saturating_add(Weight::from_parts(326_428, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -2593,10 +2591,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `787 + r * (6 ±0)` // Estimated: `21805 + r * (30 ±0)` - // Minimum execution time: 231_936_000 picoseconds. - Weight::from_parts(232_240_207, 21805) - // Standard Error: 731 - .saturating_add(Weight::from_parts(330_713, 0).saturating_mul(r.into())) + // Minimum execution time: 284_103_000 picoseconds. + Weight::from_parts(283_801_256, 21805) + // Standard Error: 1_051 + .saturating_add(Weight::from_parts(334_081, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -2616,10 +2614,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `778 + r * (6 ±0)` // Estimated: `21735 + r * (30 ±0)` - // Minimum execution time: 231_978_000 picoseconds. - Weight::from_parts(224_881_201, 21735) - // Standard Error: 1_296 - .saturating_add(Weight::from_parts(346_872, 0).saturating_mul(r.into())) + // Minimum execution time: 284_187_000 picoseconds. + Weight::from_parts(289_414_364, 21735) + // Standard Error: 796 + .saturating_add(Weight::from_parts(324_603, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -2641,10 +2639,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `856 + r * (10 ±0)` // Estimated: `24446 + r * (60 ±0)` - // Minimum execution time: 231_707_000 picoseconds. - Weight::from_parts(245_939_854, 24446) - // Standard Error: 1_369 - .saturating_add(Weight::from_parts(1_380_453, 0).saturating_mul(r.into())) + // Minimum execution time: 284_953_000 picoseconds. + Weight::from_parts(290_535_752, 24446) + // Standard Error: 2_462 + .saturating_add(Weight::from_parts(1_361_518, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 60).saturating_mul(r.into())) @@ -2664,10 +2662,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `745 + r * (4 ±0)` // Estimated: `21555 + r * (20 ±0)` - // Minimum execution time: 157_429_000 picoseconds. - Weight::from_parts(161_047_355, 21555) - // Standard Error: 1_220 - .saturating_add(Weight::from_parts(134_497, 0).saturating_mul(r.into())) + // Minimum execution time: 160_775_000 picoseconds. + Weight::from_parts(164_652_364, 21555) + // Standard Error: 284 + .saturating_add(Weight::from_parts(132_574, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 20).saturating_mul(r.into())) @@ -2687,10 +2685,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `780 + r * (6 ±0)` // Estimated: `21740 + r * (30 ±0)` - // Minimum execution time: 232_561_000 picoseconds. - Weight::from_parts(230_989_499, 21740) - // Standard Error: 848 - .saturating_add(Weight::from_parts(282_053, 0).saturating_mul(r.into())) + // Minimum execution time: 284_072_000 picoseconds. + Weight::from_parts(288_418_644, 21740) + // Standard Error: 792 + .saturating_add(Weight::from_parts(272_881, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -2710,10 +2708,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `784` // Estimated: `21740` - // Minimum execution time: 237_080_000 picoseconds. - Weight::from_parts(239_380_994, 21740) - // Standard Error: 2 - .saturating_add(Weight::from_parts(592, 0).saturating_mul(n.into())) + // Minimum execution time: 286_671_000 picoseconds. + Weight::from_parts(292_151_662, 21740) + // Standard Error: 1 + .saturating_add(Weight::from_parts(638, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -2732,10 +2730,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `768 + r * (45 ±0)` // Estimated: `21660 + r * (225 ±0)` - // Minimum execution time: 228_669_000 picoseconds. - Weight::from_parts(230_916_471, 21660) - // Standard Error: 295_520 - .saturating_add(Weight::from_parts(1_420_928, 0).saturating_mul(r.into())) + // Minimum execution time: 280_334_000 picoseconds. + Weight::from_parts(283_487_571, 21660) + // Standard Error: 267_797 + .saturating_add(Weight::from_parts(3_803_128, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 225).saturating_mul(r.into())) @@ -2755,10 +2753,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `778` // Estimated: `21775` - // Minimum execution time: 231_626_000 picoseconds. - Weight::from_parts(232_097_413, 21775) + // Minimum execution time: 284_004_000 picoseconds. + Weight::from_parts(283_681_350, 21775) // Standard Error: 1 - .saturating_add(Weight::from_parts(185, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(232, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -2781,10 +2779,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `810 + r * (356 ±0)` // Estimated: `25511 + r * (15321 ±0)` - // Minimum execution time: 230_758_000 picoseconds. - Weight::from_parts(233_235_993, 25511) - // Standard Error: 196_168 - .saturating_add(Weight::from_parts(81_177_506, 0).saturating_mul(r.into())) + // Minimum execution time: 284_143_000 picoseconds. + Weight::from_parts(287_218_324, 25511) + // Standard Error: 343_611 + .saturating_add(Weight::from_parts(109_895_675, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((6_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -2808,10 +2806,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `825 + r * (10 ±0)` // Estimated: `24283 + r * (60 ±0)` - // Minimum execution time: 232_457_000 picoseconds. - Weight::from_parts(240_943_161, 24283) - // Standard Error: 3_085 - .saturating_add(Weight::from_parts(1_837_168, 0).saturating_mul(r.into())) + // Minimum execution time: 285_037_000 picoseconds. + Weight::from_parts(299_804_606, 24283) + // Standard Error: 5_518 + .saturating_add(Weight::from_parts(1_848_164, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 60).saturating_mul(r.into())) @@ -2831,10 +2829,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `778 + r * (10 ±0)` // Estimated: `21735 + r * (50 ±0)` - // Minimum execution time: 229_788_000 picoseconds. - Weight::from_parts(233_520_858, 21735) - // Standard Error: 9_561 - .saturating_add(Weight::from_parts(3_596_294, 0).saturating_mul(r.into())) + // Minimum execution time: 282_886_000 picoseconds. + Weight::from_parts(293_171_736, 21735) + // Standard Error: 2_171 + .saturating_add(Weight::from_parts(3_491_303, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 50).saturating_mul(r.into())) @@ -2855,12 +2853,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `797 + t * (32 ±0)` // Estimated: `21840 + t * (2640 ±0)` - // Minimum execution time: 248_294_000 picoseconds. - Weight::from_parts(239_709_759, 21840) - // Standard Error: 66_903 - .saturating_add(Weight::from_parts(2_880_732, 0).saturating_mul(t.into())) - // Standard Error: 18 - .saturating_add(Weight::from_parts(725, 0).saturating_mul(n.into())) + // Minimum execution time: 300_675_000 picoseconds. + Weight::from_parts(296_092_420, 21840) + // Standard Error: 130_733 + .saturating_add(Weight::from_parts(2_487_957, 0).saturating_mul(t.into())) + // Standard Error: 36 + .saturating_add(Weight::from_parts(565, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(t.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -2882,10 +2880,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `777 + r * (7 ±0)` // Estimated: `21725 + r * (35 ±0)` - // Minimum execution time: 170_601_000 picoseconds. - Weight::from_parts(165_819_714, 21725) - // Standard Error: 452 - .saturating_add(Weight::from_parts(240_362, 0).saturating_mul(r.into())) + // Minimum execution time: 166_638_000 picoseconds. + Weight::from_parts(171_353_083, 21725) + // Standard Error: 550 + .saturating_add(Weight::from_parts(238_768, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 35).saturating_mul(r.into())) @@ -2905,10 +2903,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `125728` // Estimated: `269977` - // Minimum execution time: 349_543_000 picoseconds. - Weight::from_parts(352_945_102, 269977) - // Standard Error: 2 - .saturating_add(Weight::from_parts(749, 0).saturating_mul(i.into())) + // Minimum execution time: 414_136_000 picoseconds. + Weight::from_parts(416_093_921, 269977) + // Standard Error: 3 + .saturating_add(Weight::from_parts(794, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -2919,10 +2917,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `845 + r * (292 ±0)` // Estimated: `843 + r * (293 ±0)` - // Minimum execution time: 238_766_000 picoseconds. - Weight::from_parts(130_994_282, 843) - // Standard Error: 10_413 - .saturating_add(Weight::from_parts(6_134_087, 0).saturating_mul(r.into())) + // Minimum execution time: 285_920_000 picoseconds. + Weight::from_parts(184_945_789, 843) + // Standard Error: 9_604 + .saturating_add(Weight::from_parts(6_012_522, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -2936,10 +2934,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1304` // Estimated: `1280` - // Minimum execution time: 248_137_000 picoseconds. - Weight::from_parts(265_535_917, 1280) - // Standard Error: 28 - .saturating_add(Weight::from_parts(387, 0).saturating_mul(n.into())) + // Minimum execution time: 299_772_000 picoseconds. + Weight::from_parts(333_451_106, 1280) + // Standard Error: 54 + .saturating_add(Weight::from_parts(579, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -2950,10 +2948,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1167 + n * (1 ±0)` // Estimated: `1167 + n * (1 ±0)` - // Minimum execution time: 246_752_000 picoseconds. - Weight::from_parts(250_315_210, 1167) - // Standard Error: 42 - .saturating_add(Weight::from_parts(135, 0).saturating_mul(n.into())) + // Minimum execution time: 299_279_000 picoseconds. + Weight::from_parts(302_336_567, 1167) + // Standard Error: 25 + .saturating_add(Weight::from_parts(86, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -2965,10 +2963,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `841 + r * (288 ±0)` // Estimated: `845 + r * (289 ±0)` - // Minimum execution time: 232_873_000 picoseconds. - Weight::from_parts(130_360_558, 845) - // Standard Error: 10_026 - .saturating_add(Weight::from_parts(6_023_862, 0).saturating_mul(r.into())) + // Minimum execution time: 284_689_000 picoseconds. + Weight::from_parts(185_207_302, 845) + // Standard Error: 10_030 + .saturating_add(Weight::from_parts(5_871_325, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -2982,10 +2980,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1163 + n * (1 ±0)` // Estimated: `1163 + n * (1 ±0)` - // Minimum execution time: 247_079_000 picoseconds. - Weight::from_parts(248_922_003, 1163) - // Standard Error: 22 - .saturating_add(Weight::from_parts(201, 0).saturating_mul(n.into())) + // Minimum execution time: 299_364_000 picoseconds. + Weight::from_parts(302_089_070, 1163) + // Standard Error: 23 + .saturating_add(Weight::from_parts(128, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -2997,10 +2995,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `835 + r * (296 ±0)` // Estimated: `840 + r * (297 ±0)` - // Minimum execution time: 232_696_000 picoseconds. - Weight::from_parts(144_147_151, 840) - // Standard Error: 8_846 - .saturating_add(Weight::from_parts(4_931_414, 0).saturating_mul(r.into())) + // Minimum execution time: 285_175_000 picoseconds. + Weight::from_parts(200_262_957, 840) + // Standard Error: 8_681 + .saturating_add(Weight::from_parts(4_899_266, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3013,10 +3011,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1179 + n * (1 ±0)` // Estimated: `1179 + n * (1 ±0)` - // Minimum execution time: 247_795_000 picoseconds. - Weight::from_parts(252_944_118, 1179) - // Standard Error: 45 - .saturating_add(Weight::from_parts(480, 0).saturating_mul(n.into())) + // Minimum execution time: 299_459_000 picoseconds. + Weight::from_parts(302_451_160, 1179) + // Standard Error: 36 + .saturating_add(Weight::from_parts(731, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -3028,10 +3026,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `856 + r * (288 ±0)` // Estimated: `857 + r * (289 ±0)` - // Minimum execution time: 232_166_000 picoseconds. - Weight::from_parts(148_503_428, 857) - // Standard Error: 8_704 - .saturating_add(Weight::from_parts(4_766_055, 0).saturating_mul(r.into())) + // Minimum execution time: 286_384_000 picoseconds. + Weight::from_parts(203_389_467, 857) + // Standard Error: 8_817 + .saturating_add(Weight::from_parts(4_692_347, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3044,10 +3042,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1166 + n * (1 ±0)` // Estimated: `1166 + n * (1 ±0)` - // Minimum execution time: 246_128_000 picoseconds. - Weight::from_parts(248_323_705, 1166) - // Standard Error: 21 - .saturating_add(Weight::from_parts(92, 0).saturating_mul(n.into())) + // Minimum execution time: 297_450_000 picoseconds. + Weight::from_parts(300_459_851, 1166) + // Standard Error: 39 + .saturating_add(Weight::from_parts(108, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -3059,10 +3057,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `829 + r * (296 ±0)` // Estimated: `836 + r * (297 ±0)` - // Minimum execution time: 232_976_000 picoseconds. - Weight::from_parts(132_373_848, 836) - // Standard Error: 9_855 - .saturating_add(Weight::from_parts(6_181_821, 0).saturating_mul(r.into())) + // Minimum execution time: 285_572_000 picoseconds. + Weight::from_parts(182_642_557, 836) + // Standard Error: 9_977 + .saturating_add(Weight::from_parts(6_090_684, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3076,10 +3074,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1180 + n * (1 ±0)` // Estimated: `1180 + n * (1 ±0)` - // Minimum execution time: 247_907_000 picoseconds. - Weight::from_parts(251_984_133, 1180) - // Standard Error: 41 - .saturating_add(Weight::from_parts(639, 0).saturating_mul(n.into())) + // Minimum execution time: 301_344_000 picoseconds. + Weight::from_parts(303_770_522, 1180) + // Standard Error: 29 + .saturating_add(Weight::from_parts(807, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -3099,10 +3097,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1373 + r * (45 ±0)` // Estimated: `26753 + r * (2700 ±0)` - // Minimum execution time: 232_614_000 picoseconds. - Weight::from_parts(127_024_367, 26753) - // Standard Error: 54_521 - .saturating_add(Weight::from_parts(20_975_575, 0).saturating_mul(r.into())) + // Minimum execution time: 286_835_000 picoseconds. + Weight::from_parts(245_206_457, 26753) + // Standard Error: 73_782 + .saturating_add(Weight::from_parts(36_414_448, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(4_u64)) @@ -3111,53 +3109,53 @@ impl WeightInfo for () { } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) - /// Storage: Contracts ContractInfoOf (r:1601 w:1601) + /// Storage: Contracts ContractInfoOf (r:801 w:801) /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) /// Storage: Contracts CodeStorage (r:2 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) - /// Storage: System EventTopics (r:1602 w:1602) + /// Storage: System EventTopics (r:802 w:802) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 1600]`. + /// The range of component `r` is `[0, 800]`. fn seal_call(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1512 + r * (256 ±0)` - // Estimated: `27163 + r * (6231 ±0)` - // Minimum execution time: 233_446_000 picoseconds. - Weight::from_parts(234_338_000, 27163) - // Standard Error: 122_754 - .saturating_add(Weight::from_parts(216_709_600, 0).saturating_mul(r.into())) + // Measured: `1237 + r * (256 ±0)` + // Estimated: `26028 + r * (6235 ±0)` + // Minimum execution time: 287_184_000 picoseconds. + Weight::from_parts(287_525_000, 26028) + // Standard Error: 66_791 + .saturating_add(Weight::from_parts(261_473_539, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((2_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 6231).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 6235).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) /// Storage: Contracts ContractInfoOf (r:1 w:1) /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) - /// Storage: Contracts CodeStorage (r:1536 w:0) + /// Storage: Contracts CodeStorage (r:736 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) - /// Storage: System EventTopics (r:1537 w:1537) + /// Storage: System EventTopics (r:737 w:737) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 1600]`. + /// The range of component `r` is `[0, 800]`. fn seal_delegate_call(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0 + r * (902 ±0)` - // Estimated: `21755 + r * (8167 ±7)` - // Minimum execution time: 232_717_000 picoseconds. - Weight::from_parts(233_405_000, 21755) - // Standard Error: 98_607 - .saturating_add(Weight::from_parts(212_329_100, 0).saturating_mul(r.into())) + // Measured: `0 + r * (502 ±0)` + // Estimated: `21755 + r * (6329 ±10)` + // Minimum execution time: 285_759_000 picoseconds. + Weight::from_parts(286_643_000, 21755) + // Standard Error: 133_180 + .saturating_add(Weight::from_parts(257_186_897, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 8167).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 6329).saturating_mul(r.into())) } /// Storage: System Account (r:3 w:2) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3175,46 +3173,46 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1154 + t * (204 ±0)` // Estimated: `31015 + t * (5970 ±0)` - // Minimum execution time: 392_113_000 picoseconds. - Weight::from_parts(376_522_702, 31015) - // Standard Error: 1_388_011 - .saturating_add(Weight::from_parts(19_125_093, 0).saturating_mul(t.into())) - // Standard Error: 2 - .saturating_add(Weight::from_parts(609, 0).saturating_mul(c.into())) + // Minimum execution time: 459_675_000 picoseconds. + Weight::from_parts(427_010_987, 31015) + // Standard Error: 1_277_377 + .saturating_add(Weight::from_parts(36_899_889, 0).saturating_mul(t.into())) + // Standard Error: 1 + .saturating_add(Weight::from_parts(651, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(t.into()))) .saturating_add(RocksDbWeight::get().writes(5_u64)) .saturating_add(RocksDbWeight::get().writes((2_u64).saturating_mul(t.into()))) .saturating_add(Weight::from_parts(0, 5970).saturating_mul(t.into())) } - /// Storage: System Account (r:3202 w:3202) + /// Storage: System Account (r:1602 w:1602) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) - /// Storage: Contracts ContractInfoOf (r:1601 w:1601) + /// Storage: Contracts ContractInfoOf (r:801 w:801) /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) - /// Storage: Contracts CodeStorage (r:1601 w:0) + /// Storage: Contracts CodeStorage (r:801 w:0) /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: Contracts Nonce (r:1 w:1) /// Proof: Contracts Nonce (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) - /// Storage: Contracts OwnerInfoOf (r:1600 w:1600) + /// Storage: Contracts OwnerInfoOf (r:800 w:800) /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Measured) - /// Storage: System EventTopics (r:1602 w:1602) + /// Storage: System EventTopics (r:802 w:802) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 1600]`. + /// The range of component `r` is `[0, 800]`. fn seal_instantiate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1859 + r * (253 ±0)` - // Estimated: `33859 + r * (16628 ±0)` - // Minimum execution time: 234_438_000 picoseconds. - Weight::from_parts(234_751_000, 33859) - // Standard Error: 450_507 - .saturating_add(Weight::from_parts(313_121_404, 0).saturating_mul(r.into())) + // Measured: `1301 + r * (254 ±0)` + // Estimated: `30977 + r * (16635 ±0)` + // Minimum execution time: 285_816_000 picoseconds. + Weight::from_parts(286_349_000, 30977) + // Standard Error: 269_144 + .saturating_add(Weight::from_parts(394_282_520, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().reads((6_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(6_u64)) .saturating_add(RocksDbWeight::get().writes((5_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 16628).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 16635).saturating_mul(r.into())) } /// Storage: System Account (r:4 w:4) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3237,14 +3235,14 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1071 + t * (187 ±0)` // Estimated: `42684 + t * (3588 ±2)` - // Minimum execution time: 1_570_178_000 picoseconds. - Weight::from_parts(284_062_841, 42684) - // Standard Error: 4_396_597 - .saturating_add(Weight::from_parts(106_424_960, 0).saturating_mul(t.into())) + // Minimum execution time: 1_708_330_000 picoseconds. + Weight::from_parts(395_059_764, 42684) + // Standard Error: 4_545_552 + .saturating_add(Weight::from_parts(114_039_862, 0).saturating_mul(t.into())) // Standard Error: 7 - .saturating_add(Weight::from_parts(1_183, 0).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(1_213, 0).saturating_mul(i.into())) // Standard Error: 7 - .saturating_add(Weight::from_parts(1_354, 0).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_379, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(13_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(t.into()))) .saturating_add(RocksDbWeight::get().writes(10_u64)) @@ -3266,10 +3264,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `777 + r * (8 ±0)` // Estimated: `21710 + r * (40 ±0)` - // Minimum execution time: 230_557_000 picoseconds. - Weight::from_parts(233_276_698, 21710) - // Standard Error: 1_026 - .saturating_add(Weight::from_parts(587_723, 0).saturating_mul(r.into())) + // Minimum execution time: 283_738_000 picoseconds. + Weight::from_parts(289_885_978, 21710) + // Standard Error: 1_057 + .saturating_add(Weight::from_parts(575_432, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) @@ -3289,10 +3287,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `785` // Estimated: `21745` - // Minimum execution time: 234_151_000 picoseconds. - Weight::from_parts(240_199_365, 21745) - // Standard Error: 3 - .saturating_add(Weight::from_parts(3_941, 0).saturating_mul(n.into())) + // Minimum execution time: 285_070_000 picoseconds. + Weight::from_parts(283_987_687, 21745) + // Standard Error: 6 + .saturating_add(Weight::from_parts(4_008, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3311,10 +3309,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `779 + r * (8 ±0)` // Estimated: `21725 + r * (40 ±0)` - // Minimum execution time: 229_931_000 picoseconds. - Weight::from_parts(234_961_690, 21725) - // Standard Error: 1_073 - .saturating_add(Weight::from_parts(758_259, 0).saturating_mul(r.into())) + // Minimum execution time: 281_613_000 picoseconds. + Weight::from_parts(285_429_053, 21725) + // Standard Error: 1_164 + .saturating_add(Weight::from_parts(756_244, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) @@ -3334,10 +3332,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `787` // Estimated: `21765` - // Minimum execution time: 232_448_000 picoseconds. - Weight::from_parts(225_974_008, 21765) + // Minimum execution time: 284_593_000 picoseconds. + Weight::from_parts(278_467_111, 21765) // Standard Error: 2 - .saturating_add(Weight::from_parts(3_174, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(3_217, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3356,10 +3354,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `779 + r * (8 ±0)` // Estimated: `21740 + r * (40 ±0)` - // Minimum execution time: 229_251_000 picoseconds. - Weight::from_parts(234_182_627, 21740) - // Standard Error: 836 - .saturating_add(Weight::from_parts(424_375, 0).saturating_mul(r.into())) + // Minimum execution time: 281_759_000 picoseconds. + Weight::from_parts(288_807_137, 21740) + // Standard Error: 805 + .saturating_add(Weight::from_parts(424_378, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) @@ -3379,10 +3377,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `787` // Estimated: `21785` - // Minimum execution time: 230_896_000 picoseconds. - Weight::from_parts(224_913_556, 21785) + // Minimum execution time: 282_666_000 picoseconds. + Weight::from_parts(274_357_944, 21785) // Standard Error: 2 - .saturating_add(Weight::from_parts(919, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(974, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3401,10 +3399,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `779 + r * (8 ±0)` // Estimated: `21745 + r * (40 ±0)` - // Minimum execution time: 230_314_000 picoseconds. - Weight::from_parts(233_426_327, 21745) - // Standard Error: 926 - .saturating_add(Weight::from_parts(425_341, 0).saturating_mul(r.into())) + // Minimum execution time: 285_073_000 picoseconds. + Weight::from_parts(287_226_796, 21745) + // Standard Error: 951 + .saturating_add(Weight::from_parts(425_368, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) @@ -3424,10 +3422,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `787` // Estimated: `21755` - // Minimum execution time: 230_424_000 picoseconds. - Weight::from_parts(231_136_218, 21755) + // Minimum execution time: 283_407_000 picoseconds. + Weight::from_parts(276_737_242, 21755) // Standard Error: 2 - .saturating_add(Weight::from_parts(917, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(967, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3441,18 +3439,18 @@ impl WeightInfo for () { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 1600]`. + /// The range of component `r` is `[0, 160]`. fn seal_ecdsa_recover(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `704 + r * (78 ±0)` - // Estimated: `21370 + r * (390 ±0)` - // Minimum execution time: 232_862_000 picoseconds. - Weight::from_parts(379_152_870, 21370) - // Standard Error: 11_607 - .saturating_add(Weight::from_parts(36_955_410, 0).saturating_mul(r.into())) + // Measured: `822 + r * (76 ±0)` + // Estimated: `21705 + r * (385 ±0)` + // Minimum execution time: 285_130_000 picoseconds. + Weight::from_parts(299_449_202, 21705) + // Standard Error: 16_535 + .saturating_add(Weight::from_parts(37_655_189, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 390).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 385).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3464,18 +3462,18 @@ impl WeightInfo for () { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) - /// The range of component `r` is `[0, 1600]`. + /// The range of component `r` is `[0, 160]`. fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `549 + r * (44 ±0)` - // Estimated: `20630 + r * (220 ±0)` - // Minimum execution time: 232_668_000 picoseconds. - Weight::from_parts(253_308_468, 20630) - // Standard Error: 3_022 - .saturating_add(Weight::from_parts(9_249_849, 0).saturating_mul(r.into())) + // Measured: `792 + r * (42 ±0)` + // Estimated: `21780 + r * (210 ±0)` + // Minimum execution time: 284_494_000 picoseconds. + Weight::from_parts(282_154_339, 21780) + // Standard Error: 12_278 + .saturating_add(Weight::from_parts(9_501_559, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 220).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 210).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3494,10 +3492,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0 + r * (964 ±0)` // Estimated: `29920 + r * (11544 ±7)` - // Minimum execution time: 233_910_000 picoseconds. - Weight::from_parts(234_607_000, 29920) - // Standard Error: 46_118 - .saturating_add(Weight::from_parts(21_927_957, 0).saturating_mul(r.into())) + // Minimum execution time: 285_306_000 picoseconds. + Weight::from_parts(286_080_000, 29920) + // Standard Error: 43_813 + .saturating_add(Weight::from_parts(21_758_329, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3519,10 +3517,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `773 + r * (3 ±0)` // Estimated: `21735 + r * (15 ±0)` - // Minimum execution time: 231_823_000 picoseconds. - Weight::from_parts(237_996_137, 21735) - // Standard Error: 598 - .saturating_add(Weight::from_parts(163_106, 0).saturating_mul(r.into())) + // Minimum execution time: 283_487_000 picoseconds. + Weight::from_parts(289_280_189, 21735) + // Standard Error: 829 + .saturating_add(Weight::from_parts(168_973, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 15).saturating_mul(r.into())) @@ -3542,10 +3540,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1975 + r * (39 ±0)` // Estimated: `27145 + r * (200 ±0)` - // Minimum execution time: 235_077_000 picoseconds. - Weight::from_parts(267_876_360, 27145) - // Standard Error: 1_147 - .saturating_add(Weight::from_parts(256_275, 0).saturating_mul(r.into())) + // Minimum execution time: 287_413_000 picoseconds. + Weight::from_parts(314_662_286, 27145) + // Standard Error: 1_099 + .saturating_add(Weight::from_parts(262_201, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 200).saturating_mul(r.into())) @@ -3567,10 +3565,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `776 + r * (3 ±0)` // Estimated: `24004 + r * (18 ±0)` - // Minimum execution time: 231_384_000 picoseconds. - Weight::from_parts(237_086_900, 24004) - // Standard Error: 534 - .saturating_add(Weight::from_parts(140_842, 0).saturating_mul(r.into())) + // Minimum execution time: 282_601_000 picoseconds. + Weight::from_parts(289_374_203, 24004) + // Standard Error: 452 + .saturating_add(Weight::from_parts(142_661, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 18).saturating_mul(r.into())) @@ -3580,509 +3578,507 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_721_000 picoseconds. - Weight::from_parts(2_456_746, 0) - // Standard Error: 30 - .saturating_add(Weight::from_parts(2_788, 0).saturating_mul(r.into())) + // Minimum execution time: 1_692_000 picoseconds. + Weight::from_parts(2_069_482, 0) + // Standard Error: 40 + .saturating_add(Weight::from_parts(2_922, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64load(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_824_000 picoseconds. - Weight::from_parts(2_366_036, 0) - // Standard Error: 5 - .saturating_add(Weight::from_parts(6_446, 0).saturating_mul(r.into())) + // Minimum execution time: 1_690_000 picoseconds. + Weight::from_parts(2_303_602, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(6_433, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64store(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_840_000 picoseconds. - Weight::from_parts(2_332_115, 0) + // Minimum execution time: 1_701_000 picoseconds. + Weight::from_parts(2_321_142, 0) // Standard Error: 4 - .saturating_add(Weight::from_parts(6_012, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(6_025, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_select(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_731_000 picoseconds. - Weight::from_parts(2_078_873, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(7_931, 0).saturating_mul(r.into())) + // Minimum execution time: 1_656_000 picoseconds. + Weight::from_parts(2_090_881, 0) + // Standard Error: 5 + .saturating_add(Weight::from_parts(7_941, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_if(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_768_000 picoseconds. - Weight::from_parts(1_916_551, 0) - // Standard Error: 8 - .saturating_add(Weight::from_parts(10_597, 0).saturating_mul(r.into())) + // Minimum execution time: 1_659_000 picoseconds. + Weight::from_parts(1_816_547, 0) + // Standard Error: 5 + .saturating_add(Weight::from_parts(10_578, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_br(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_735_000 picoseconds. - Weight::from_parts(1_962_845, 0) - // Standard Error: 14 - .saturating_add(Weight::from_parts(4_631, 0).saturating_mul(r.into())) + // Minimum execution time: 1_683_000 picoseconds. + Weight::from_parts(1_970_907, 0) + // Standard Error: 12 + .saturating_add(Weight::from_parts(4_636, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_br_if(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_688_000 picoseconds. - Weight::from_parts(1_172_825, 0) - // Standard Error: 76 - .saturating_add(Weight::from_parts(8_007, 0).saturating_mul(r.into())) + // Minimum execution time: 1_651_000 picoseconds. + Weight::from_parts(2_263_817, 0) + // Standard Error: 68 + .saturating_add(Weight::from_parts(7_529, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_br_table(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_725_000 picoseconds. - Weight::from_parts(1_535_833, 0) - // Standard Error: 26 - .saturating_add(Weight::from_parts(9_489, 0).saturating_mul(r.into())) + // Minimum execution time: 1_687_000 picoseconds. + Weight::from_parts(1_349_186, 0) + // Standard Error: 31 + .saturating_add(Weight::from_parts(9_732, 0).saturating_mul(r.into())) } /// The range of component `e` is `[1, 256]`. - fn instr_br_table_per_entry(e: u32, ) -> Weight { + fn instr_br_table_per_entry(_e: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_814_000 picoseconds. - Weight::from_parts(1_926_367, 0) - // Standard Error: 16 - .saturating_add(Weight::from_parts(219, 0).saturating_mul(e.into())) + // Minimum execution time: 1_777_000 picoseconds. + Weight::from_parts(2_036_446, 0) } /// The range of component `r` is `[0, 5000]`. fn instr_call(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_770_000 picoseconds. - Weight::from_parts(2_436_918, 0) - // Standard Error: 8 - .saturating_add(Weight::from_parts(17_890, 0).saturating_mul(r.into())) + // Minimum execution time: 1_686_000 picoseconds. + Weight::from_parts(464_449, 0) + // Standard Error: 383 + .saturating_add(Weight::from_parts(19_121, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_call_indirect(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_920_000 picoseconds. - Weight::from_parts(2_729_712, 0) - // Standard Error: 39 - .saturating_add(Weight::from_parts(24_853, 0).saturating_mul(r.into())) + // Minimum execution time: 1_855_000 picoseconds. + Weight::from_parts(3_381_585, 0) + // Standard Error: 18 + .saturating_add(Weight::from_parts(24_245, 0).saturating_mul(r.into())) } /// The range of component `l` is `[0, 1024]`. fn instr_call_per_local(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_869_000 picoseconds. - Weight::from_parts(2_147_970, 0) - // Standard Error: 46 - .saturating_add(Weight::from_parts(1_237, 0).saturating_mul(l.into())) + // Minimum execution time: 1_792_000 picoseconds. + Weight::from_parts(2_006_024, 0) + // Standard Error: 16 + .saturating_add(Weight::from_parts(2_181, 0).saturating_mul(l.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_local_get(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_012_000 picoseconds. - Weight::from_parts(3_234_440, 0) - // Standard Error: 1 - .saturating_add(Weight::from_parts(2_433, 0).saturating_mul(r.into())) + // Minimum execution time: 3_918_000 picoseconds. + Weight::from_parts(4_618_761, 0) + // Standard Error: 49 + .saturating_add(Weight::from_parts(2_312, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_local_set(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_037_000 picoseconds. - Weight::from_parts(3_204_600, 0) + // Minimum execution time: 3_889_000 picoseconds. + Weight::from_parts(4_151_280, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(3_627, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_623, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_local_tee(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_974_000 picoseconds. - Weight::from_parts(3_301_366, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(3_836, 0).saturating_mul(r.into())) + // Minimum execution time: 3_880_000 picoseconds. + Weight::from_parts(4_225_780, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(3_847, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_global_get(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_853_000 picoseconds. - Weight::from_parts(2_310_141, 0) + // Minimum execution time: 1_765_000 picoseconds. + Weight::from_parts(2_216_674, 0) // Standard Error: 4 - .saturating_add(Weight::from_parts(8_387, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(8_393, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_global_set(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_828_000 picoseconds. - Weight::from_parts(2_315_323, 0) - // Standard Error: 4 - .saturating_add(Weight::from_parts(8_797, 0).saturating_mul(r.into())) + // Minimum execution time: 1_764_000 picoseconds. + Weight::from_parts(2_246_735, 0) + // Standard Error: 5 + .saturating_add(Weight::from_parts(8_877, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_memory_current(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_800_000 picoseconds. - Weight::from_parts(2_117_252, 0) - // Standard Error: 4 - .saturating_add(Weight::from_parts(3_741, 0).saturating_mul(r.into())) + // Minimum execution time: 1_758_000 picoseconds. + Weight::from_parts(1_922_386, 0) + // Standard Error: 94 + .saturating_add(Weight::from_parts(3_868, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 16]`. fn instr_memory_grow(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_743_000 picoseconds. - Weight::from_parts(1_054_728, 0) - // Standard Error: 137_128 - .saturating_add(Weight::from_parts(13_179_446, 0).saturating_mul(r.into())) + // Minimum execution time: 1_635_000 picoseconds. + Weight::from_parts(1_118_785, 0) + // Standard Error: 134_978 + .saturating_add(Weight::from_parts(16_343_664, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64clz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_735_000 picoseconds. - Weight::from_parts(2_026_568, 0) + // Minimum execution time: 1_648_000 picoseconds. + Weight::from_parts(2_012_545, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(3_802, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_824, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64ctz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_630_000 picoseconds. - Weight::from_parts(1_980_222, 0) + // Minimum execution time: 1_688_000 picoseconds. + Weight::from_parts(1_995_956, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(3_735, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_757, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64popcnt(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_695_000 picoseconds. - Weight::from_parts(2_040_266, 0) - // Standard Error: 8 - .saturating_add(Weight::from_parts(3_718, 0).saturating_mul(r.into())) + // Minimum execution time: 1_631_000 picoseconds. + Weight::from_parts(2_011_493, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(3_755, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64eqz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_697_000 picoseconds. - Weight::from_parts(2_004_663, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(3_661, 0).saturating_mul(r.into())) + // Minimum execution time: 1_667_000 picoseconds. + Weight::from_parts(1_958_798, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(3_677, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64extendsi32(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_705_000 picoseconds. - Weight::from_parts(2_682_122, 0) - // Standard Error: 98 - .saturating_add(Weight::from_parts(3_705, 0).saturating_mul(r.into())) + // Minimum execution time: 1_674_000 picoseconds. + Weight::from_parts(2_009_555, 0) + // Standard Error: 7 + .saturating_add(Weight::from_parts(3_863, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64extendui32(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_674_000 picoseconds. - Weight::from_parts(1_989_835, 0) + // Minimum execution time: 1_659_000 picoseconds. + Weight::from_parts(2_014_985, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(3_801, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_821, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i32wrapi64(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_695_000 picoseconds. - Weight::from_parts(2_083_824, 0) - // Standard Error: 17 - .saturating_add(Weight::from_parts(3_719, 0).saturating_mul(r.into())) + // Minimum execution time: 1_640_000 picoseconds. + Weight::from_parts(2_013_939, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(3_708, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64eq(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_678_000 picoseconds. - Weight::from_parts(1_996_335, 0) - // Standard Error: 4 - .saturating_add(Weight::from_parts(5_995, 0).saturating_mul(r.into())) + // Minimum execution time: 1_631_000 picoseconds. + Weight::from_parts(2_002_814, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(6_008, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64ne(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_697_000 picoseconds. - Weight::from_parts(2_046_566, 0) + // Minimum execution time: 1_647_000 picoseconds. + Weight::from_parts(2_032_158, 0) // Standard Error: 3 - .saturating_add(Weight::from_parts(5_936, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(5_944, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64lts(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_721_000 picoseconds. - Weight::from_parts(2_406_930, 0) - // Standard Error: 150 - .saturating_add(Weight::from_parts(5_992, 0).saturating_mul(r.into())) + // Minimum execution time: 1_669_000 picoseconds. + Weight::from_parts(2_040_386, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(6_009, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64ltu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_749_000 picoseconds. - Weight::from_parts(1_987_158, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(5_994, 0).saturating_mul(r.into())) + // Minimum execution time: 1_637_000 picoseconds. + Weight::from_parts(1_983_695, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(6_027, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64gts(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_706_000 picoseconds. - Weight::from_parts(2_038_138, 0) + // Minimum execution time: 1_701_000 picoseconds. + Weight::from_parts(2_054_295, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(5_802, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(5_799, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64gtu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_670_000 picoseconds. - Weight::from_parts(2_555_035, 0) - // Standard Error: 74 - .saturating_add(Weight::from_parts(5_958, 0).saturating_mul(r.into())) + // Minimum execution time: 1_653_000 picoseconds. + Weight::from_parts(2_749_807, 0) + // Standard Error: 90 + .saturating_add(Weight::from_parts(5_945, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64les(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_694_000 picoseconds. - Weight::from_parts(1_991_929, 0) - // Standard Error: 27 - .saturating_add(Weight::from_parts(6_037, 0).saturating_mul(r.into())) + // Minimum execution time: 1_651_000 picoseconds. + Weight::from_parts(1_979_111, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(6_011, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64leu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_684_000 picoseconds. - Weight::from_parts(1_969_284, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(6_104, 0).saturating_mul(r.into())) + // Minimum execution time: 1_743_000 picoseconds. + Weight::from_parts(2_058_081, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(6_085, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64ges(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_697_000 picoseconds. - Weight::from_parts(2_023_608, 0) + // Minimum execution time: 1_638_000 picoseconds. + Weight::from_parts(2_038_929, 0) // Standard Error: 3 - .saturating_add(Weight::from_parts(5_946, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(5_941, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64geu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_659_000 picoseconds. - Weight::from_parts(1_963_145, 0) - // Standard Error: 6 - .saturating_add(Weight::from_parts(6_014, 0).saturating_mul(r.into())) + // Minimum execution time: 1_641_000 picoseconds. + Weight::from_parts(2_036_587, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(6_008, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64add(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_722_000 picoseconds. - Weight::from_parts(2_016_286, 0) + // Minimum execution time: 1_624_000 picoseconds. + Weight::from_parts(2_080_562, 0) // Standard Error: 3 - .saturating_add(Weight::from_parts(5_889, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(5_826, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64sub(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_656_000 picoseconds. - Weight::from_parts(1_966_234, 0) - // Standard Error: 17 - .saturating_add(Weight::from_parts(6_171, 0).saturating_mul(r.into())) + // Minimum execution time: 1_652_000 picoseconds. + Weight::from_parts(2_039_535, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(6_137, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64mul(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_695_000 picoseconds. - Weight::from_parts(2_004_559, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(5_785, 0).saturating_mul(r.into())) + // Minimum execution time: 1_666_000 picoseconds. + Weight::from_parts(2_056_354, 0) + // Standard Error: 6 + .saturating_add(Weight::from_parts(5_780, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64divs(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_681_000 picoseconds. - Weight::from_parts(2_135_505, 0) - // Standard Error: 6 - .saturating_add(Weight::from_parts(11_761, 0).saturating_mul(r.into())) + // Minimum execution time: 1_648_000 picoseconds. + Weight::from_parts(2_077_695, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(11_775, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64divu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_653_000 picoseconds. - Weight::from_parts(2_153_167, 0) - // Standard Error: 5 - .saturating_add(Weight::from_parts(10_523, 0).saturating_mul(r.into())) + // Minimum execution time: 1_797_000 picoseconds. + Weight::from_parts(2_772_388, 0) + // Standard Error: 33 + .saturating_add(Weight::from_parts(10_333, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64rems(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_697_000 picoseconds. - Weight::from_parts(2_570_266, 0) - // Standard Error: 50 - .saturating_add(Weight::from_parts(11_971, 0).saturating_mul(r.into())) + // Minimum execution time: 1_699_000 picoseconds. + Weight::from_parts(2_174_288, 0) + // Standard Error: 6 + .saturating_add(Weight::from_parts(11_778, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64remu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_719_000 picoseconds. - Weight::from_parts(2_101_082, 0) + // Minimum execution time: 1_685_000 picoseconds. + Weight::from_parts(2_091_037, 0) // Standard Error: 3 - .saturating_add(Weight::from_parts(10_709, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(10_694, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64and(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_745_000 picoseconds. - Weight::from_parts(2_621_890, 0) - // Standard Error: 94 - .saturating_add(Weight::from_parts(5_545, 0).saturating_mul(r.into())) + // Minimum execution time: 1_636_000 picoseconds. + Weight::from_parts(1_975_521, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(5_695, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64or(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_670_000 picoseconds. - Weight::from_parts(2_046_821, 0) + // Minimum execution time: 1_619_000 picoseconds. + Weight::from_parts(2_045_492, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(5_762, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(5_770, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64xor(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_714_000 picoseconds. - Weight::from_parts(2_010_173, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(5_911, 0).saturating_mul(r.into())) + // Minimum execution time: 1_668_000 picoseconds. + Weight::from_parts(2_055_460, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(5_851, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64shl(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_756_000 picoseconds. - Weight::from_parts(2_044_772, 0) + // Minimum execution time: 1_681_000 picoseconds. + Weight::from_parts(2_023_370, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(5_857, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(5_853, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64shrs(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_741_000 picoseconds. - Weight::from_parts(2_012_819, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(6_127, 0).saturating_mul(r.into())) + // Minimum execution time: 1_714_000 picoseconds. + Weight::from_parts(2_067_584, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(6_133, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64shru(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_693_000 picoseconds. - Weight::from_parts(2_090_981, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(5_839, 0).saturating_mul(r.into())) + // Minimum execution time: 1_602_000 picoseconds. + Weight::from_parts(2_055_530, 0) + // Standard Error: 138 + .saturating_add(Weight::from_parts(6_014, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64rotl(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_704_000 picoseconds. - Weight::from_parts(2_014_108, 0) - // Standard Error: 4 - .saturating_add(Weight::from_parts(6_005, 0).saturating_mul(r.into())) + // Minimum execution time: 1_709_000 picoseconds. + Weight::from_parts(2_016_365, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(5_985, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64rotr(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_715_000 picoseconds. - Weight::from_parts(2_053_720, 0) - // Standard Error: 5 - .saturating_add(Weight::from_parts(5_860, 0).saturating_mul(r.into())) + // Minimum execution time: 1_661_000 picoseconds. + Weight::from_parts(2_003_063, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(5_863, 0).saturating_mul(r.into())) } } From a1cf6ee484c28e313df8082c1efc643ba54810b7 Mon Sep 17 00:00:00 2001 From: Sergejs Kostjucenko <85877331+sergejparity@users.noreply.github.com> Date: Tue, 21 Mar 2023 14:05:26 +0200 Subject: [PATCH 544/715] fix publish docker description ci job (#13663) * fix publish docker description ci job * remove publish-refs from docker description jobs --- scripts/ci/gitlab/pipeline/publish.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/ci/gitlab/pipeline/publish.yml b/scripts/ci/gitlab/pipeline/publish.yml index 188a093864cc0..6a3d928f6e0f9 100644 --- a/scripts/ci/gitlab/pipeline/publish.yml +++ b/scripts/ci/gitlab/pipeline/publish.yml @@ -52,7 +52,6 @@ stage: publish extends: - .kubernetes-env - - .publish-refs variables: CI_IMAGE: paritytech/dockerhub-description DOCKERHUB_REPOSITORY: parity/$PRODUCT @@ -63,6 +62,8 @@ - if: $CI_COMMIT_REF_NAME == "master" changes: - scripts/ci/docker/$PRODUCT.Dockerfile.README.md + before_script: + - echo script: - cd / && sh entrypoint.sh From b3cacfb059e9d79d1cde270c796dc0f33ff3ef20 Mon Sep 17 00:00:00 2001 From: Mira Ressel Date: Tue, 21 Mar 2023 13:06:55 +0100 Subject: [PATCH 545/715] only push docker descriptions on master branch pipelines (#13664) Currently those jobs also get included in multi-project pipelines such as https://gitlab.parity.io/parity/mirrors/scripts/-/pipelines/255546, even when the description hasn't actually changed, because `changes:` conditions always evaluate to true on non-branch pipelines. --- scripts/ci/gitlab/pipeline/publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/ci/gitlab/pipeline/publish.yml b/scripts/ci/gitlab/pipeline/publish.yml index 6a3d928f6e0f9..a772096447663 100644 --- a/scripts/ci/gitlab/pipeline/publish.yml +++ b/scripts/ci/gitlab/pipeline/publish.yml @@ -59,7 +59,7 @@ DOCKER_PASSWORD: $Docker_Hub_Pass_Parity README_FILEPATH: $CI_PROJECT_DIR/scripts/ci/docker/$PRODUCT.Dockerfile.README.md rules: - - if: $CI_COMMIT_REF_NAME == "master" + - if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH && $CI_PIPELINE_SOURCE == "push" changes: - scripts/ci/docker/$PRODUCT.Dockerfile.README.md before_script: From a14236059c2d3da052fb08295082341aa7b87240 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 21 Mar 2023 13:53:04 +0000 Subject: [PATCH 546/715] Bump k256 from 0.11.6 to 0.13.0 (#13624) Bumps [k256](https://github.com/RustCrypto/elliptic-curves) from 0.11.6 to 0.13.0. - [Release notes](https://github.com/RustCrypto/elliptic-curves/releases) - [Commits](https://github.com/RustCrypto/elliptic-curves/compare/k256/v0.11.6...k256/v0.13.0) --- updated-dependencies: - dependency-name: k256 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: Davide Galassi --- Cargo.lock | 202 ++++++++++++++++++++++++++++++++------- frame/support/Cargo.toml | 2 +- 2 files changed, 170 insertions(+), 34 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e2ec461e1e03e..4a0cc4cd38a96 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -484,6 +484,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + [[package]] name = "base58" version = "0.2.0" @@ -1374,6 +1380,18 @@ dependencies = [ "zeroize", ] +[[package]] +name = "crypto-bigint" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c2538c4e68e52548bacb3e83ac549f903d44f011ac9d5abb5e132e67d0808f7" +dependencies = [ + "generic-array 0.14.6", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + [[package]] name = "crypto-common" version = "0.1.6" @@ -1589,6 +1607,16 @@ dependencies = [ "zeroize", ] +[[package]] +name = "der" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc906908ea6458456e5eaa160a9c08543ec3d1e6f71e2235cedd660cb65f9df0" +dependencies = [ + "const-oid", + "zeroize", +] + [[package]] name = "der-parser" version = "7.0.0" @@ -1826,10 +1854,22 @@ version = "0.14.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c" dependencies = [ - "der", - "elliptic-curve", - "rfc6979", - "signature", + "der 0.6.1", + "elliptic-curve 0.12.3", + "rfc6979 0.3.1", + "signature 1.6.4", +] + +[[package]] +name = "ecdsa" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1b0a1222f8072619e8a6b667a854020a03d363738303203c09468b3424a420a" +dependencies = [ + "der 0.7.1", + "elliptic-curve 0.13.2", + "rfc6979 0.4.0", + "signature 2.0.0", ] [[package]] @@ -1838,7 +1878,7 @@ version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" dependencies = [ - "signature", + "signature 1.6.4", ] [[package]] @@ -1881,18 +1921,37 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3" dependencies = [ - "base16ct", - "crypto-bigint", - "der", + "base16ct 0.1.1", + "crypto-bigint 0.4.9", + "der 0.6.1", "digest 0.10.6", - "ff", + "ff 0.12.1", "generic-array 0.14.6", - "group", + "group 0.12.1", "hkdf", "pem-rfc7468", - "pkcs8", + "pkcs8 0.9.0", "rand_core 0.6.4", - "sec1", + "sec1 0.3.0", + "subtle", + "zeroize", +] + +[[package]] +name = "elliptic-curve" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea5a92946e8614bb585254898bb7dd1ddad241ace60c52149e3765e34cc039d" +dependencies = [ + "base16ct 0.2.0", + "crypto-bigint 0.5.1", + "digest 0.10.6", + "ff 0.13.0", + "generic-array 0.14.6", + "group 0.13.0", + "pkcs8 0.10.1", + "rand_core 0.6.4", + "sec1 0.7.1", "subtle", "zeroize", ] @@ -2050,6 +2109,16 @@ dependencies = [ "subtle", ] +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "fiat-crypto" version = "0.1.17" @@ -2720,6 +2789,7 @@ checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" dependencies = [ "typenum", "version_check", + "zeroize", ] [[package]] @@ -2829,7 +2899,18 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" dependencies = [ - "ff", + "ff 0.12.1", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff 0.13.0", "rand_core 0.6.4", "subtle", ] @@ -3482,13 +3563,14 @@ dependencies = [ [[package]] name = "k256" -version = "0.11.6" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72c1e0b51e7ec0a97369623508396067a486bd0cbed95a2659a4b863d28cfc8b" +checksum = "955890845095ccf31ef83ad41a05aabb4d8cc23dc3cac5a9f5c89cf26dd0da75" dependencies = [ "cfg-if", - "ecdsa", - "elliptic-curve", + "ecdsa 0.16.1", + "elliptic-curve 0.13.2", + "once_cell", "sha2 0.10.6", ] @@ -3764,7 +3846,7 @@ dependencies = [ "prost-build", "rand 0.8.5", "rw-stream-sink", - "sec1", + "sec1 0.3.0", "sha2 0.10.6", "smallvec", "thiserror", @@ -3798,7 +3880,7 @@ dependencies = [ "prost-build", "rand 0.8.5", "rw-stream-sink", - "sec1", + "sec1 0.3.0", "sha2 0.10.6", "smallvec", "thiserror", @@ -5372,8 +5454,8 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51f44edd08f51e2ade572f141051021c5af22677e42b7dd28a88155151c33594" dependencies = [ - "ecdsa", - "elliptic-curve", + "ecdsa 0.14.8", + "elliptic-curve 0.12.3", "sha2 0.10.6", ] @@ -5383,8 +5465,8 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfc8c5bf642dde52bb9e87c0ecd8ca5a76faac2eeed98dedb7c717997e1080aa" dependencies = [ - "ecdsa", - "elliptic-curve", + "ecdsa 0.14.8", + "elliptic-curve 0.12.3", "sha2 0.10.6", ] @@ -7188,8 +7270,18 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" dependencies = [ - "der", - "spki", + "der 0.6.1", + "spki 0.6.0", +] + +[[package]] +name = "pkcs8" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d2820d87d2b008616e5c27212dd9e0e694fb4c6b522de06094106813328cb49" +dependencies = [ + "der 0.7.1", + "spki 0.7.0", ] [[package]] @@ -7822,11 +7914,21 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb" dependencies = [ - "crypto-bigint", + "crypto-bigint 0.4.9", "hmac 0.12.1", "zeroize", ] +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac 0.12.1", + "subtle", +] + [[package]] name = "ring" version = "0.16.20" @@ -9605,10 +9707,24 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" dependencies = [ - "base16ct", - "der", + "base16ct 0.1.1", + "der 0.6.1", "generic-array 0.14.6", - "pkcs8", + "pkcs8 0.9.0", + "subtle", + "zeroize", +] + +[[package]] +name = "sec1" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48518a2b5775ba8ca5b46596aae011caa431e6ce7e4a67ead66d92f08884220e" +dependencies = [ + "base16ct 0.2.0", + "der 0.7.1", + "generic-array 0.14.6", + "pkcs8 0.10.1", "subtle", "zeroize", ] @@ -9831,6 +9947,16 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "signature" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fe458c98333f9c8152221191a77e2a44e8325d0193484af2e9421a53019e57d" +dependencies = [ + "digest 0.10.6", + "rand_core 0.6.4", +] + [[package]] name = "simba" version = "0.8.0" @@ -10764,7 +10890,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" dependencies = [ "base64ct", - "der", + "der 0.6.1", +] + +[[package]] +name = "spki" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0445c905640145c7ea8c1993555957f65e7c46d0535b91ba501bc9bfc85522f" +dependencies = [ + "base64ct", + "der 0.7.1", ] [[package]] @@ -12568,7 +12704,7 @@ dependencies = [ "ccm", "curve25519-dalek 3.2.0", "der-parser 8.1.0", - "elliptic-curve", + "elliptic-curve 0.12.3", "hkdf", "hmac 0.12.1", "log", @@ -12580,11 +12716,11 @@ dependencies = [ "rcgen 0.9.3", "ring", "rustls 0.19.1", - "sec1", + "sec1 0.3.0", "serde", "sha1", "sha2 0.10.6", - "signature", + "signature 1.6.4", "subtle", "thiserror", "tokio", diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index 008d4b3f26015..820658372afd9 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.11.5", default-features = false, features = ["ecdsa"] } +k256 = { version = "0.13.0", default-features = false, features = ["ecdsa"] } environmental = { version = "1.1.4", default-features = false } [dev-dependencies] From 936e995d91be03f8efe7e75b1be2f6ad1e3a60e9 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Tue, 21 Mar 2023 16:25:33 +0100 Subject: [PATCH 547/715] refactor: state RPC remove `max_rpc_payload_size` (#13649) This limit is not needed anymore as the JSON-RPC servers doesn't terminate the connection if the RPC max limit is exceeded anymore --- client/rpc/src/state/mod.rs | 10 ++---- client/rpc/src/state/state_full.rs | 10 ++---- client/rpc/src/state/tests.rs | 24 +++++++------- client/service/src/builder.rs | 8 ++--- client/tracing/src/block/mod.rs | 53 +++++++----------------------- 5 files changed, 30 insertions(+), 75 deletions(-) diff --git a/client/rpc/src/state/mod.rs b/client/rpc/src/state/mod.rs index 12d59ad3b382d..f81ec991db133 100644 --- a/client/rpc/src/state/mod.rs +++ b/client/rpc/src/state/mod.rs @@ -169,7 +169,6 @@ pub fn new_full( client: Arc, executor: SubscriptionTaskExecutor, deny_unsafe: DenyUnsafe, - rpc_max_payload: Option, ) -> (State, ChildState) where Block: BlockT + 'static, @@ -189,12 +188,9 @@ where + 'static, Client::Api: Metadata, { - let child_backend = Box::new(self::state_full::FullState::new( - client.clone(), - executor.clone(), - rpc_max_payload, - )); - let backend = Box::new(self::state_full::FullState::new(client, executor, rpc_max_payload)); + let child_backend = + Box::new(self::state_full::FullState::new(client.clone(), executor.clone())); + let backend = Box::new(self::state_full::FullState::new(client, executor)); (State { backend, deny_unsafe }, ChildState { backend: child_backend }) } diff --git a/client/rpc/src/state/state_full.rs b/client/rpc/src/state/state_full.rs index f26d42484f24f..20ca5f7131e71 100644 --- a/client/rpc/src/state/state_full.rs +++ b/client/rpc/src/state/state_full.rs @@ -66,7 +66,6 @@ pub struct FullState { client: Arc, executor: SubscriptionTaskExecutor, _phantom: PhantomData<(BE, Block)>, - rpc_max_payload: Option, } impl FullState @@ -79,12 +78,8 @@ where Block: BlockT + 'static, { /// Create new state API backend for full nodes. - pub fn new( - client: Arc, - executor: SubscriptionTaskExecutor, - rpc_max_payload: Option, - ) -> Self { - Self { client, executor, _phantom: PhantomData, rpc_max_payload } + pub fn new(client: Arc, executor: SubscriptionTaskExecutor) -> Self { + Self { client, executor, _phantom: PhantomData } } /// Returns given block hash or best block hash if None is passed. @@ -481,7 +476,6 @@ where targets, storage_keys, methods, - self.rpc_max_payload, ) .trace_block() .map_err(|e| invalid_block::(block, None, e.to_string())) diff --git a/client/rpc/src/state/tests.rs b/client/rpc/src/state/tests.rs index 1ccc609e4f0e4..ae193e662b0e7 100644 --- a/client/rpc/src/state/tests.rs +++ b/client/rpc/src/state/tests.rs @@ -55,7 +55,7 @@ async 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), test_executor(), DenyUnsafe::No, None); + let (client, child) = new_full(Arc::new(client), test_executor(), DenyUnsafe::No); let key = StorageKey(KEY.to_vec()); assert_eq!( @@ -103,7 +103,7 @@ async 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), test_executor(), DenyUnsafe::No, None); + let (_client, child) = new_full(Arc::new(client), test_executor(), DenyUnsafe::No); let keys = &[StorageKey(KEY1.to_vec()), StorageKey(KEY2.to_vec())]; assert_eq!( @@ -134,7 +134,7 @@ async fn should_return_child_storage() { .build(), ); let genesis_hash = client.genesis_hash(); - let (_client, child) = new_full(client, test_executor(), DenyUnsafe::No, None); + let (_client, child) = new_full(client, test_executor(), DenyUnsafe::No); let child_key = prefixed_storage_key(); let key = StorageKey(b"key".to_vec()); @@ -165,7 +165,7 @@ async fn should_return_child_storage_entries() { .build(), ); let genesis_hash = client.genesis_hash(); - let (_client, child) = new_full(client, test_executor(), DenyUnsafe::No, None); + let (_client, child) = new_full(client, test_executor(), DenyUnsafe::No); let child_key = prefixed_storage_key(); let keys = vec![StorageKey(b"key1".to_vec()), StorageKey(b"key2".to_vec())]; @@ -196,7 +196,7 @@ async fn should_return_child_storage_entries() { 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, test_executor(), DenyUnsafe::No, None); + let (client, _child) = new_full(client, test_executor(), DenyUnsafe::No); use jsonrpsee::{core::Error, types::error::CallError}; @@ -210,7 +210,7 @@ async fn should_call_contract() { 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(), test_executor(), DenyUnsafe::No, None); + let (api, _child) = new_full(client.clone(), test_executor(), DenyUnsafe::No); let api_rpc = api.into_rpc(); let sub = api_rpc.subscribe("state_subscribeStorage", EmptyParams::new()).await.unwrap(); @@ -242,7 +242,7 @@ async fn should_notify_about_storage_changes() { 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(), test_executor(), DenyUnsafe::No, None); + let (api, _child) = new_full(client.clone(), test_executor(), DenyUnsafe::No); let alice_balance_key = blake2_256(&runtime::system::balance_of_key(AccountKeyring::Alice.into())); @@ -278,7 +278,7 @@ async fn should_send_initial_storage_changes_and_notifications() { #[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 (api, _child) = new_full(client.clone(), test_executor(), DenyUnsafe::No); let mut add_block = |nonce| { let mut builder = client.new_block(Default::default()).unwrap(); @@ -480,7 +480,7 @@ async fn should_query_storage() { #[tokio::test] async fn should_return_runtime_version() { let client = Arc::new(substrate_test_runtime_client::new()); - let (api, _child) = new_full(client.clone(), test_executor(), DenyUnsafe::No, None); + let (api, _child) = new_full(client.clone(), test_executor(), DenyUnsafe::No); let result = "{\"specName\":\"test\",\"implName\":\"parity-test\",\"authoringVersion\":1,\ \"specVersion\":2,\"implVersion\":2,\"apis\":[[\"0xdf6acb689907609b\",4],\ @@ -501,7 +501,7 @@ async fn should_return_runtime_version() { 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, test_executor(), DenyUnsafe::No, None); + let (api, _child) = new_full(client, test_executor(), DenyUnsafe::No); let api_rpc = api.into_rpc(); let sub = api_rpc @@ -530,7 +530,7 @@ fn should_deserialize_storage_key() { #[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, test_executor(), DenyUnsafe::Yes, None); + let (api, _child) = new_full(client, test_executor(), DenyUnsafe::Yes); let api_rpc = api.into_rpc(); let err = api_rpc.subscribe("state_subscribeStorage", EmptyParams::new()).await; @@ -540,7 +540,7 @@ async fn wildcard_storage_subscriptions_are_rpc_unsafe() { #[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, test_executor(), DenyUnsafe::Yes, None); + let (api, _child) = new_full(client, test_executor(), DenyUnsafe::Yes); let api_rpc = api.into_rpc(); let key = StorageKey(STORAGE_KEY.to_vec()); diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index bee40e9a3da0c..f0f9a7ed0d4d7 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -631,12 +631,8 @@ where let (chain, state, child_state) = { 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(), - task_executor.clone(), - deny_unsafe, - config.rpc_max_payload, - ); + let (state, child_state) = + sc_rpc::state::new_full(client.clone(), task_executor.clone(), deny_unsafe); let state = state.into_rpc(); let child_state = child_state.into_rpc(); diff --git a/client/tracing/src/block/mod.rs b/client/tracing/src/block/mod.rs index f5efadc34fb92..c0442abc125b9 100644 --- a/client/tracing/src/block/mod.rs +++ b/client/tracing/src/block/mod.rs @@ -34,38 +34,21 @@ use tracing::{ use crate::{SpanDatum, TraceEvent, Values}; use sc_client_api::BlockBackend; -use sc_rpc_server::RPC_MAX_PAYLOAD_DEFAULT; use sp_api::{Core, Encode, Metadata, ProvideRuntimeApi}; use sp_blockchain::HeaderBackend; use sp_core::hexdisplay::HexDisplay; -use sp_rpc::tracing::{BlockTrace, Span, TraceBlockResponse, TraceError}; +use sp_rpc::tracing::{BlockTrace, Span, TraceBlockResponse}; use sp_runtime::{ generic::BlockId, traits::{Block as BlockT, Header}, }; use sp_tracing::{WASM_NAME_KEY, WASM_TARGET_KEY, WASM_TRACE_IDENTIFIER}; -// Heuristic for average event size in bytes. -const AVG_EVENT: usize = 600 * 8; -// Heuristic for average span size in bytes. -const AVG_SPAN: usize = 100 * 8; -// Estimate of the max base RPC payload size when the Id is bound as a u64. If strings -// 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 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 -// messages larger than `sc_rpc_server::MAX_PAYLOAD` and the caller will not get any -// response. -const BASE_PAYLOAD: usize = 100; // Default to only pallet, frame support and state related traces const DEFAULT_TARGETS: &str = "pallet,frame,state"; const TRACE_TARGET: &str = "block_trace"; // The name of a field required for all events. const REQUIRED_EVENT_FIELD: &str = "method"; -const MEGABYTE: usize = 1024 * 1024; /// Tracing Block Result type alias pub type TraceBlockResult = Result; @@ -182,7 +165,6 @@ pub struct BlockExecutor { targets: Option, storage_keys: Option, methods: Option, - rpc_max_payload: usize, } impl BlockExecutor @@ -203,12 +185,8 @@ where targets: Option, storage_keys: Option, methods: Option, - rpc_max_payload: Option, ) -> Self { - let rpc_max_payload = rpc_max_payload - .map(|mb| mb.saturating_mul(MEGABYTE)) - .unwrap_or(RPC_MAX_PAYLOAD_DEFAULT); - Self { client, block, targets, storage_keys, methods, rpc_max_payload } + Self { client, block, targets, storage_keys, methods } } /// Execute block, record all spans and events belonging to `Self::targets` @@ -289,24 +267,15 @@ where .collect(); tracing::debug!(target: "state_tracing", "Captured {} spans and {} events", spans.len(), events.len()); - let approx_payload_size = BASE_PAYLOAD + events.len() * AVG_EVENT + spans.len() * AVG_SPAN; - let response = if approx_payload_size > self.rpc_max_payload { - TraceBlockResponse::TraceError(TraceError { - error: "Payload likely exceeds max payload size of RPC server.".to_string(), - }) - } else { - TraceBlockResponse::BlockTrace(BlockTrace { - block_hash: block_id_as_string(BlockId::::Hash(self.block)), - parent_hash: block_id_as_string(BlockId::::Hash(parent_hash)), - tracing_targets: targets.to_string(), - storage_keys: self.storage_keys.clone().unwrap_or_default(), - methods: self.methods.clone().unwrap_or_default(), - spans, - events, - }) - }; - - Ok(response) + Ok(TraceBlockResponse::BlockTrace(BlockTrace { + block_hash: block_id_as_string(BlockId::::Hash(self.block)), + parent_hash: block_id_as_string(BlockId::::Hash(parent_hash)), + tracing_targets: targets.to_string(), + storage_keys: self.storage_keys.clone().unwrap_or_default(), + methods: self.methods.clone().unwrap_or_default(), + spans, + events, + })) } } From 81aa7f317d0bb8476ab660bc67853f59aed84d4e Mon Sep 17 00:00:00 2001 From: Mira Ressel Date: Tue, 21 Mar 2023 13:05:06 +0100 Subject: [PATCH 548/715] core-fellowship: Remove unused dev-dependencies --- frame/core-fellowship/Cargo.toml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/frame/core-fellowship/Cargo.toml b/frame/core-fellowship/Cargo.toml index 2785346c7341f..16b673fb41b98 100644 --- a/frame/core-fellowship/Cargo.toml +++ b/frame/core-fellowship/Cargo.toml @@ -25,10 +25,6 @@ sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/ 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-ranked-collective = { version = "4.0.0-dev", default-features = false, path = "../ranked-collective" } -pallet-salary = { version = "4.0.0-dev", default-features = false, path = "../salary" } - [features] default = ["std"] std = [ @@ -49,7 +45,5 @@ runtime-benchmarks = [ "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", "sp-runtime/runtime-benchmarks", - "pallet-ranked-collective/runtime-benchmarks", - "pallet-salary/runtime-benchmarks", ] try-runtime = ["frame-support/try-runtime"] From 6f79a5a26480cca90727edd0e9193c876788dcc3 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Tue, 21 Mar 2023 17:27:45 +0100 Subject: [PATCH 549/715] Update lockfile The CI needs this. Signed-off-by: Oliver Tale-Yazdi --- Cargo.lock | 2 -- 1 file changed, 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4a0cc4cd38a96..5b2879e1ba9b6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5886,8 +5886,6 @@ dependencies = [ "frame-support", "frame-system", "log", - "pallet-ranked-collective", - "pallet-salary", "parity-scale-codec", "scale-info", "sp-arithmetic", From 5b29f150365cc6eacb1f618e8797d81f0aada46a Mon Sep 17 00:00:00 2001 From: Mira Ressel Date: Wed, 22 Mar 2023 09:33:06 +0100 Subject: [PATCH 550/715] move back to ci-linux@production image (#13669) --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f9e74364a0d6c..6cf06273650f7 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -48,7 +48,7 @@ variables: CARGO_INCREMENTAL: 0 DOCKER_OS: "debian:stretch" ARCH: "x86_64" - CI_IMAGE: "paritytech/ci-linux@sha256:7c76c3f9639f919447abbf9db535588178fde4df583d6926444d44cc20c094e6" # staging 2023-03-20 + 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" From 2b42fbd860d7034ce9c716a37016b0101be69491 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Wed, 22 Mar 2023 11:09:10 +0100 Subject: [PATCH 551/715] Crypto Pair trait refactory (#13657) * Crypto pair refactory * Remove unused method * Apply review suggestions * Remove leftovers * Associated type is not really required * Fix after refactory * Fix benchmark-ui test --------- Co-authored-by: Anton --- ...bad_return_type_blank_with_question.stderr | 2 +- primitives/application-crypto/src/lib.rs | 5 +- primitives/core/src/crypto.rs | 79 ++++++++++++----- primitives/core/src/ecdsa.rs | 49 +---------- primitives/core/src/ed25519.rs | 51 +---------- primitives/core/src/sr25519.rs | 85 +++---------------- 6 files changed, 75 insertions(+), 196 deletions(-) diff --git a/frame/support/test/tests/benchmark_ui/bad_return_type_blank_with_question.stderr b/frame/support/test/tests/benchmark_ui/bad_return_type_blank_with_question.stderr index 1f8c9f1e171eb..601bbd20fb73d 100644 --- a/frame/support/test/tests/benchmark_ui/bad_return_type_blank_with_question.stderr +++ b/frame/support/test/tests/benchmark_ui/bad_return_type_blank_with_question.stderr @@ -7,4 +7,4 @@ error[E0277]: the `?` operator can only be used in a function that returns `Resu 15 | something()?; | ^ cannot use the `?` operator in a function that returns `()` | - = help: the trait `FromResidual>` is not implemented for `()` + = help: the trait `FromResidual>` is not implemented for `()` diff --git a/primitives/application-crypto/src/lib.rs b/primitives/application-crypto/src/lib.rs index 992ecd1d05621..0685477ddff8d 100644 --- a/primitives/application-crypto/src/lib.rs +++ b/primitives/application-crypto/src/lib.rs @@ -23,7 +23,7 @@ pub use sp_core::crypto::{key_types, CryptoTypeId, KeyTypeId}; #[doc(hidden)] #[cfg(feature = "full_crypto")] -pub use sp_core::crypto::{DeriveJunction, Pair, SecretStringError, Ss58Codec}; +pub use sp_core::crypto::{DeriveError, DeriveJunction, Pair, SecretStringError, Ss58Codec}; #[doc(hidden)] pub use sp_core::{ self, @@ -129,7 +129,6 @@ macro_rules! app_crypto_pair { type Public = Public; type Seed = <$pair as $crate::Pair>::Seed; type Signature = Signature; - type DeriveError = <$pair as $crate::Pair>::DeriveError; $crate::app_crypto_pair_functions_if_std!($pair); @@ -137,7 +136,7 @@ macro_rules! app_crypto_pair { &self, path: Iter, seed: Option, - ) -> Result<(Self, Option), Self::DeriveError> { + ) -> Result<(Self, Option), $crate::DeriveError> { self.0.derive(path, seed).map(|x| (Self(x.0), x.1)) } fn from_seed(seed: &Self::Seed) -> Self { diff --git a/primitives/core/src/crypto.rs b/primitives/core/src/crypto.rs index 16af3d06963ab..80e65b342cbd7 100644 --- a/primitives/core/src/crypto.rs +++ b/primitives/core/src/crypto.rs @@ -24,6 +24,8 @@ use crate::hexdisplay::HexDisplay; use crate::{ed25519, sr25519}; #[cfg(feature = "std")] use base58::{FromBase58, ToBase58}; +#[cfg(feature = "std")] +use bip39::{Language, Mnemonic, MnemonicType}; use codec::{Decode, Encode, MaxEncodedLen}; #[cfg(feature = "std")] use rand::{rngs::OsRng, RngCore}; @@ -52,10 +54,6 @@ pub const DEV_PHRASE: &str = /// The address of the associated root phrase for our publicly known keys. pub const DEV_ADDRESS: &str = "5DfhGyQdFobKM8NsWvEeAKk5EQQgYe9AydgJ7rMB6E1EqRzV"; -/// The infallible type. -#[derive(crate::RuntimeDebug)] -pub enum Infallible {} - /// The length of the junction identifier. Note that this is also referred to as the /// `CHAIN_CODE_LENGTH` in the context of Schnorrkel. #[cfg(feature = "full_crypto")] @@ -108,6 +106,16 @@ pub enum SecretStringError { InvalidPath, } +/// An error when deriving a key. +#[cfg_attr(feature = "std", derive(thiserror::Error))] +#[derive(Debug, Clone, PartialEq, Eq)] +#[cfg(feature = "full_crypto")] +pub enum DeriveError { + /// A soft key was found in the path (and is unsupported). + #[cfg_attr(feature = "std", error("Soft key in path"))] + SoftKeyInPath, +} + /// A since derivation junction description. It is the single parameter used when creating /// a new secret key from an existing secret key and, in the case of `SoftRaw` and `SoftIndex` /// a new public key from an existing public key. @@ -691,40 +699,45 @@ mod dummy { type Public = Dummy; type Seed = Dummy; type Signature = Dummy; - type DeriveError = (); + #[cfg(feature = "std")] fn generate_with_phrase(_: Option<&str>) -> (Self, String, Self::Seed) { Default::default() } + #[cfg(feature = "std")] fn from_phrase(_: &str, _: Option<&str>) -> Result<(Self, Self::Seed), SecretStringError> { Ok(Default::default()) } + fn derive>( &self, _: Iter, _: Option, - ) -> Result<(Self, Option), Self::DeriveError> { + ) -> Result<(Self, Option), DeriveError> { Ok((Self, None)) } - fn from_seed(_: &Self::Seed) -> Self { - Self - } + fn from_seed_slice(_: &[u8]) -> Result { Ok(Self) } + fn sign(&self, _: &[u8]) -> Self::Signature { Self } + fn verify>(_: &Self::Signature, _: M, _: &Self::Public) -> bool { true } + fn verify_weak, M: AsRef<[u8]>>(_: &[u8], _: M, _: P) -> bool { true } + fn public(&self) -> Self::Public { Self } + fn to_raw_vec(&self) -> Vec { vec![] } @@ -845,9 +858,6 @@ pub trait Pair: CryptoType + Sized + Clone + Send + Sync + 'static { /// and verified with the message and a public key. type Signature: AsRef<[u8]>; - /// Error returned from the `derive` function. - type DeriveError; - /// Generate new secure (random) key pair. /// /// This is only for ephemeral keys really, since you won't have access to the secret key @@ -866,27 +876,47 @@ pub trait Pair: CryptoType + Sized + Clone + Send + Sync + 'static { /// This is generally slower than `generate()`, so prefer that unless you need to persist /// the key from the current session. #[cfg(feature = "std")] - fn generate_with_phrase(password: Option<&str>) -> (Self, String, Self::Seed); + fn generate_with_phrase(password: Option<&str>) -> (Self, String, Self::Seed) { + let mnemonic = Mnemonic::new(MnemonicType::Words12, Language::English); + let phrase = mnemonic.phrase(); + let (pair, seed) = Self::from_phrase(phrase, password) + .expect("All phrases generated by Mnemonic are valid; qed"); + (pair, phrase.to_owned(), seed) + } /// Returns the KeyPair from the English BIP39 seed `phrase`, or `None` if it's invalid. #[cfg(feature = "std")] fn from_phrase( phrase: &str, password: Option<&str>, - ) -> Result<(Self, Self::Seed), SecretStringError>; + ) -> Result<(Self, Self::Seed), SecretStringError> { + let mnemonic = Mnemonic::from_phrase(phrase, Language::English) + .map_err(|_| SecretStringError::InvalidPhrase)?; + let big_seed = + substrate_bip39::seed_from_entropy(mnemonic.entropy(), password.unwrap_or("")) + .map_err(|_| SecretStringError::InvalidSeed)?; + let mut seed = Self::Seed::default(); + let seed_slice = seed.as_mut(); + let seed_len = seed_slice.len(); + debug_assert!(seed_len <= big_seed.len()); + seed_slice[..seed_len].copy_from_slice(&big_seed[..seed_len]); + Self::from_seed_slice(seed_slice).map(|x| (x, seed)) + } /// Derive a child key from a series of given junctions. fn derive>( &self, path: Iter, seed: Option, - ) -> Result<(Self, Option), Self::DeriveError>; + ) -> Result<(Self, Option), DeriveError>; /// Generate new key pair from the provided `seed`. /// /// @WARNING: THIS WILL ONLY BE SECURE IF THE `seed` IS SECURE. If it can be guessed /// by an attacker then they can also derive your key. - fn from_seed(seed: &Self::Seed) -> Self; + fn from_seed(seed: &Self::Seed) -> Self { + Self::from_seed_slice(seed.as_ref()).expect("seed has valid length; qed") + } /// Make a new key pair from secret seed material. The slice must be the correct size or /// it will return `None`. @@ -1202,14 +1232,15 @@ mod tests { type Public = TestPublic; type Seed = [u8; 8]; type Signature = [u8; 0]; - type DeriveError = (); fn generate() -> (Self, ::Seed) { (TestPair::Generated, [0u8; 8]) } + fn generate_with_phrase(_password: Option<&str>) -> (Self, String, ::Seed) { (TestPair::GeneratedWithPhrase, "".into(), [0u8; 8]) } + fn from_phrase( phrase: &str, password: Option<&str>, @@ -1222,11 +1253,12 @@ mod tests { [0u8; 8], )) } + fn derive>( &self, path_iter: Iter, _: Option<[u8; 8]>, - ) -> Result<(Self, Option<[u8; 8]>), Self::DeriveError> { + ) -> Result<(Self, Option<[u8; 8]>), DeriveError> { Ok(( match self.clone() { TestPair::Standard { phrase, password, path } => TestPair::Standard { @@ -1240,21 +1272,21 @@ mod tests { if path_iter.count() == 0 { x } else { - return Err(()) + return Err(DeriveError::SoftKeyInPath) }, }, None, )) } - fn from_seed(_seed: &::Seed) -> Self { - TestPair::Seed(_seed.as_ref().to_owned()) - } + fn sign(&self, _message: &[u8]) -> Self::Signature { [] } + fn verify>(_: &Self::Signature, _: M, _: &Self::Public) -> bool { true } + fn verify_weak, M: AsRef<[u8]>>( _sig: &[u8], _message: M, @@ -1262,12 +1294,15 @@ mod tests { ) -> bool { true } + fn public(&self) -> Self::Public { TestPublic } + fn from_seed_slice(seed: &[u8]) -> Result { Ok(TestPair::Seed(seed.to_owned())) } + fn to_raw_vec(&self) -> Vec { vec![] } diff --git a/primitives/core/src/ecdsa.rs b/primitives/core/src/ecdsa.rs index d68ba39a0fb79..e63b283d26ee3 100644 --- a/primitives/core/src/ecdsa.rs +++ b/primitives/core/src/ecdsa.rs @@ -29,11 +29,9 @@ use crate::crypto::{ }; #[cfg(feature = "full_crypto")] use crate::{ - crypto::{DeriveJunction, Pair as TraitPair, SecretStringError}, + crypto::{DeriveError, DeriveJunction, Pair as TraitPair, SecretStringError}, hashing::blake2_256, }; -#[cfg(feature = "std")] -use bip39::{Language, Mnemonic, MnemonicType}; #[cfg(all(feature = "full_crypto", not(feature = "std")))] use secp256k1::Secp256k1; #[cfg(feature = "std")] @@ -367,13 +365,6 @@ fn derive_hard_junction(secret_seed: &Seed, cc: &[u8; 32]) -> Seed { ("Secp256k1HDKD", secret_seed, cc).using_encoded(sp_core_hashing::blake2_256) } -/// An error when deriving a key. -#[cfg(feature = "full_crypto")] -pub enum DeriveError { - /// A soft key was found in the path (and is unsupported). - SoftKeyInPath, -} - /// A key pair. #[cfg(feature = "full_crypto")] #[derive(Clone)] @@ -387,44 +378,6 @@ impl TraitPair for Pair { type Public = Public; type Seed = Seed; type Signature = Signature; - type DeriveError = DeriveError; - - /// Generate new secure (random) key pair and provide the recovery phrase. - /// - /// You can recover the same key later with `from_phrase`. - #[cfg(feature = "std")] - fn generate_with_phrase(password: Option<&str>) -> (Pair, String, Seed) { - let mnemonic = Mnemonic::new(MnemonicType::Words12, Language::English); - let phrase = mnemonic.phrase(); - let (pair, seed) = Self::from_phrase(phrase, password) - .expect("All phrases generated by Mnemonic are valid; qed"); - (pair, phrase.to_owned(), seed) - } - - /// Generate key pair from given recovery phrase and password. - #[cfg(feature = "std")] - fn from_phrase( - phrase: &str, - password: Option<&str>, - ) -> Result<(Pair, Seed), SecretStringError> { - let big_seed = substrate_bip39::seed_from_entropy( - Mnemonic::from_phrase(phrase, Language::English) - .map_err(|_| SecretStringError::InvalidPhrase)? - .entropy(), - password.unwrap_or(""), - ) - .map_err(|_| SecretStringError::InvalidSeed)?; - let mut seed = Seed::default(); - seed.copy_from_slice(&big_seed[0..32]); - Self::from_seed_slice(&big_seed[0..32]).map(|x| (x, seed)) - } - - /// Make a new key pair from secret seed material. - /// - /// You should never need to use this; generate(), generate_with_phrase - fn from_seed(seed: &Seed) -> Pair { - Self::from_seed_slice(&seed[..]).expect("seed has valid length; qed") - } /// Make a new key pair from secret seed material. The slice must be 32 bytes long or it /// will return `None`. diff --git a/primitives/core/src/ed25519.rs b/primitives/core/src/ed25519.rs index 76b3064ad5a44..503c127a9e06b 100644 --- a/primitives/core/src/ed25519.rs +++ b/primitives/core/src/ed25519.rs @@ -35,9 +35,7 @@ use crate::crypto::{ CryptoType, CryptoTypeId, CryptoTypePublicPair, Derive, Public as TraitPublic, UncheckedFrom, }; #[cfg(feature = "full_crypto")] -use crate::crypto::{DeriveJunction, Pair as TraitPair, SecretStringError}; -#[cfg(feature = "std")] -use bip39::{Language, Mnemonic, MnemonicType}; +use crate::crypto::{DeriveError, DeriveJunction, Pair as TraitPair, SecretStringError}; #[cfg(feature = "full_crypto")] use core::convert::TryFrom; #[cfg(feature = "full_crypto")] @@ -46,8 +44,6 @@ use ed25519_zebra::{SigningKey, VerificationKey}; use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; use sp_runtime_interface::pass_by::PassByInner; use sp_std::ops::Deref; -#[cfg(feature = "std")] -use substrate_bip39::seed_from_entropy; /// An identifier used to match public keys against ed25519 keys pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"ed25"); @@ -385,56 +381,11 @@ fn derive_hard_junction(secret_seed: &Seed, cc: &[u8; 32]) -> Seed { ("Ed25519HDKD", secret_seed, cc).using_encoded(sp_core_hashing::blake2_256) } -/// An error when deriving a key. -#[cfg(feature = "full_crypto")] -pub enum DeriveError { - /// A soft key was found in the path (and is unsupported). - SoftKeyInPath, -} - #[cfg(feature = "full_crypto")] impl TraitPair for Pair { type Public = Public; type Seed = Seed; type Signature = Signature; - type DeriveError = DeriveError; - - /// Generate new secure (random) key pair and provide the recovery phrase. - /// - /// You can recover the same key later with `from_phrase`. - #[cfg(feature = "std")] - fn generate_with_phrase(password: Option<&str>) -> (Pair, String, Seed) { - let mnemonic = Mnemonic::new(MnemonicType::Words12, Language::English); - let phrase = mnemonic.phrase(); - let (pair, seed) = Self::from_phrase(phrase, password) - .expect("All phrases generated by Mnemonic are valid; qed"); - (pair, phrase.to_owned(), seed) - } - - /// Generate key pair from given recovery phrase and password. - #[cfg(feature = "std")] - fn from_phrase( - phrase: &str, - password: Option<&str>, - ) -> Result<(Pair, Seed), SecretStringError> { - let big_seed = seed_from_entropy( - Mnemonic::from_phrase(phrase, Language::English) - .map_err(|_| SecretStringError::InvalidPhrase)? - .entropy(), - password.unwrap_or(""), - ) - .map_err(|_| SecretStringError::InvalidSeed)?; - let mut seed = Seed::default(); - seed.copy_from_slice(&big_seed[0..32]); - Self::from_seed_slice(&big_seed[0..32]).map(|x| (x, seed)) - } - - /// Make a new key pair from secret seed material. - /// - /// You should never need to use this; generate(), generate_with_phrase - fn from_seed(seed: &Seed) -> Pair { - Self::from_seed_slice(&seed[..]).expect("seed has valid length; qed") - } /// Make a new key pair from secret seed material. The slice must be 32 bytes long or it /// will return `None`. diff --git a/primitives/core/src/sr25519.rs b/primitives/core/src/sr25519.rs index 809d83aaf08a8..8dbcca9e2673e 100644 --- a/primitives/core/src/sr25519.rs +++ b/primitives/core/src/sr25519.rs @@ -24,9 +24,7 @@ #[cfg(feature = "std")] use crate::crypto::Ss58Codec; #[cfg(feature = "full_crypto")] -use crate::crypto::{DeriveJunction, Infallible, Pair as TraitPair, SecretStringError}; -#[cfg(feature = "std")] -use bip39::{Language, Mnemonic, MnemonicType}; +use crate::crypto::{DeriveError, DeriveJunction, Pair as TraitPair, SecretStringError}; #[cfg(feature = "full_crypto")] use schnorrkel::{ derive::{ChainCode, Derivation, CHAIN_CODE_LENGTH}, @@ -34,8 +32,6 @@ use schnorrkel::{ }; #[cfg(feature = "full_crypto")] use sp_std::vec::Vec; -#[cfg(feature = "std")] -use substrate_bip39::mini_secret_from_entropy; use crate::{ crypto::{ @@ -458,16 +454,6 @@ impl TraitPair for Pair { type Public = Public; type Seed = Seed; type Signature = Signature; - type DeriveError = Infallible; - - /// Make a new key pair from raw secret seed material. - /// - /// This is generated using schnorrkel's Mini-Secret-Keys. - /// - /// A MiniSecretKey is literally what Ed25519 calls a SecretKey, which is just 32 random bytes. - fn from_seed(seed: &Seed) -> Pair { - Self::from_seed_slice(&seed[..]).expect("32 bytes can always build a key; qed") - } /// Get the public key. fn public(&self) -> Public { @@ -476,10 +462,12 @@ impl TraitPair for Pair { Public(pk) } - /// Make a new key pair from secret seed material. The slice must be 32 bytes long or it - /// will return `None`. + /// Make a new key pair from raw secret seed material. + /// + /// This is generated using schnorrkel's Mini-Secret-Keys. /// - /// You should never need to use this; generate(), generate_with_phrase(), from_phrase() + /// A `MiniSecretKey` is literally what Ed25519 calls a `SecretKey`, which is just 32 random + /// bytes. fn from_seed_slice(seed: &[u8]) -> Result { match seed.len() { MINI_SECRET_KEY_LENGTH => Ok(Pair( @@ -495,42 +483,16 @@ impl TraitPair for Pair { _ => Err(SecretStringError::InvalidSeedLength), } } - #[cfg(feature = "std")] - fn generate_with_phrase(password: Option<&str>) -> (Pair, String, Seed) { - let mnemonic = Mnemonic::new(MnemonicType::Words12, Language::English); - let phrase = mnemonic.phrase(); - let (pair, seed) = Self::from_phrase(phrase, password) - .expect("All phrases generated by Mnemonic are valid; qed"); - (pair, phrase.to_owned(), seed) - } - #[cfg(feature = "std")] - fn from_phrase( - phrase: &str, - password: Option<&str>, - ) -> Result<(Pair, Seed), SecretStringError> { - Mnemonic::from_phrase(phrase, Language::English) - .map_err(|_| SecretStringError::InvalidPhrase) - .map(|m| Self::from_entropy(m.entropy(), password)) - } fn derive>( &self, path: Iter, seed: Option, - ) -> Result<(Pair, Option), Self::DeriveError> { - let seed = if let Some(s) = seed { - if let Ok(msk) = MiniSecretKey::from_bytes(&s) { - if msk.expand(ExpansionMode::Ed25519) == self.0.secret { - Some(msk) - } else { - None - } - } else { - None - } - } else { - None - }; + ) -> Result<(Pair, Option), DeriveError> { + let seed = seed + .and_then(|s| MiniSecretKey::from_bytes(&s).ok()) + .filter(|msk| msk.expand(ExpansionMode::Ed25519) == self.0.secret); + let init = self.0.secret.clone(); let (result, seed) = path.fold((init, seed), |(acc, acc_seed), j| match (j, acc_seed) { (DeriveJunction::Soft(cc), _) => (acc.derived_key_simple(ChainCode(cc), &[]).0, None), @@ -572,18 +534,6 @@ impl TraitPair for Pair { #[cfg(feature = "std")] impl Pair { - /// Make a new key pair from binary data derived from a valid seed phrase. - /// - /// This uses a key derivation function to convert the entropy into a seed, then returns - /// the pair generated from it. - pub fn from_entropy(entropy: &[u8], password: Option<&str>) -> (Pair, Seed) { - let mini_key: MiniSecretKey = mini_secret_from_entropy(entropy, password.unwrap_or("")) - .expect("32 bytes can always build a key; qed"); - - let kp = mini_key.expand_to_keypair(ExpansionMode::Ed25519); - (Pair(kp), mini_key.to_bytes()) - } - /// Verify a signature on a message. Returns `true` if the signature is good. /// Supports old 0.1.1 deprecated signatures and should be used only for backward /// compatibility. @@ -652,10 +602,8 @@ pub fn verify_batch( #[cfg(test)] mod compatibility_test { use super::*; - use crate::crypto::DEV_PHRASE; - - // NOTE: tests to ensure addresses that are created with the `0.1.x` version (pre-audit) are - // still functional. + use crate::crypto::{Ss58Codec, DEV_ADDRESS, DEV_PHRASE}; + use serde_json; #[test] fn derive_soft_known_pair_should_work() { @@ -690,13 +638,6 @@ mod compatibility_test { assert!(Pair::verify_deprecated(&signature, &message[..], &public)); assert!(!Pair::verify(&signature, &message[..], &public)); } -} - -#[cfg(test)] -mod test { - use super::*; - use crate::crypto::{Ss58Codec, DEV_ADDRESS, DEV_PHRASE}; - use serde_json; #[test] fn default_phrase_should_be_used() { From c120cd35b2e087ff4ee54683f9ead3d93e4a30f1 Mon Sep 17 00:00:00 2001 From: Liam Aharon Date: Wed, 22 Mar 2023 21:47:44 +1100 Subject: [PATCH 552/715] Fix try_runtime_cli doc broken links (#13672) --- utils/frame/try-runtime/cli/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/frame/try-runtime/cli/src/lib.rs b/utils/frame/try-runtime/cli/src/lib.rs index 34966fc2a1197..0a521d1215562 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. //! //! --- //! From d6899f8215810975defe48b423f4b1b1b6fcc17e Mon Sep 17 00:00:00 2001 From: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Date: Wed, 22 Mar 2023 12:52:10 +0200 Subject: [PATCH 553/715] fix/chain_head: Ensure correct events for finalized branch (#13632) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chain_head/follow: Ensure correct events for finalized branch Signed-off-by: Alexandru Vasile * Reenable tests Signed-off-by: Alexandru Vasile * Do some clean ups and add some more docs * Fix gramatic * Update client/rpc-spec-v2/src/chain_head/chain_head_follow.rs Co-authored-by: Sebastian Kunert * rpc/chain_head: Introduce error for absent headers Signed-off-by: Alexandru Vasile --------- Signed-off-by: Alexandru Vasile Co-authored-by: Bastian Köcher Co-authored-by: Bastian Köcher Co-authored-by: Sebastian Kunert --- .../src/chain_head/chain_head_follow.rs | 100 ++++++------------ .../src/chain_head/subscription.rs | 6 +- client/rpc-spec-v2/src/chain_head/tests.rs | 6 -- 3 files changed, 34 insertions(+), 78 deletions(-) diff --git a/client/rpc-spec-v2/src/chain_head/chain_head_follow.rs b/client/rpc-spec-v2/src/chain_head/chain_head_follow.rs index 9173b7340b7e5..a0d19654e7959 100644 --- a/client/rpc-spec-v2/src/chain_head/chain_head_follow.rs +++ b/client/rpc-spec-v2/src/chain_head/chain_head_follow.rs @@ -40,10 +40,7 @@ use sp_api::CallApiAt; use sp_blockchain::{ Backend as BlockChainBackend, Error as BlockChainError, HeaderBackend, HeaderMetadata, Info, }; -use sp_runtime::{ - traits::{Block as BlockT, Header as HeaderT, One}, - Saturating, -}; +use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor}; use std::{collections::HashSet, sync::Arc}; /// Generates the events of the `chainHead_follow` method. @@ -116,7 +113,7 @@ struct StartupPoint { /// The head of the finalized chain. pub finalized_hash: Block::Hash, /// Last finalized block number. - pub finalized_number: <::Header as HeaderT>::Number, + pub finalized_number: NumberFor, } impl From> for StartupPoint { @@ -318,10 +315,7 @@ where } // Ensure we are only reporting blocks after the starting point. - let Some(block_number) = self.client.number(notification.hash)? else { - return Err(SubscriptionManagementError::BlockNumberAbsent) - }; - if block_number < startup_point.finalized_number { + if *notification.header.number() < startup_point.finalized_number { return Ok(Default::default()) } @@ -349,59 +343,48 @@ where return Ok(Default::default()) }; - // Find the parent hash. - let Some(first_number) = self.client.number(*first_hash)? else { - return Err(SubscriptionManagementError::BlockNumberAbsent) - }; - let Some(parent) = self.client.hash(first_number.saturating_sub(One::one()))? else { - return Err(SubscriptionManagementError::BlockHashAbsent) + // Find the parent header. + let Some(first_header) = self.client.header(*first_hash)? else { + return Err(SubscriptionManagementError::BlockHeaderAbsent) }; - let last_finalized = finalized_block_hashes - .last() - .expect("At least one finalized hash inserted; qed"); - let parents = std::iter::once(&parent).chain(finalized_block_hashes.iter()); - for (hash, parent) in finalized_block_hashes.iter().zip(parents) { - // This block is already reported by the import notification. + let parents = + std::iter::once(first_header.parent_hash()).chain(finalized_block_hashes.iter()); + for (i, (hash, parent)) in finalized_block_hashes.iter().zip(parents).enumerate() { + // Check if the block was already reported and thus, is already pinned. if !self.sub_handle.pin_block(*hash)? { continue } - // Generate only the `NewBlock` event for this block. - if hash != last_finalized { + // Generate `NewBlock` events for all blocks beside the last block in the list + if i + 1 != finalized_block_hashes.len() { + // Generate only the `NewBlock` event for this block. events.extend(self.generate_import_events(*hash, *parent, false)); - continue - } - - match self.best_block_cache { - Some(best_block_hash) => { - // If the best reported block is a children of the last finalized, - // then we had a gap in notification. + } else { + // If we end up here and the `best_block` is a descendent of the finalized block + // (last block in the list), it means that there were skipped notifications. + // Otherwise `pin_block` would had returned `true`. + // + // When the node falls out of sync and then syncs up to the tip of the chain, it can + // happen that we skip notifications. Then it is better to terminate the connection + // instead of trying to send notifications for all missed blocks. + if let Some(best_block_hash) = self.best_block_cache { let ancestor = sp_blockchain::lowest_common_ancestor( &*self.client, - *last_finalized, + *hash, best_block_hash, )?; - // A descendent of the finalized block was already reported - // before the `NewBlock` event containing the finalized block - // is reported. - if ancestor.hash == *last_finalized { + if ancestor.hash == *hash { return Err(SubscriptionManagementError::Custom( "A descendent of the finalized block was already reported".into(), )) } - self.best_block_cache = Some(*hash); - }, - // This is the first best block event that we generate. - None => { - self.best_block_cache = Some(*hash); - }, - }; + } - // This is the first time we see this block. Generate the `NewBlock` event; if this is - // the last block, also generate the `BestBlock` event. - events.extend(self.generate_import_events(*hash, *parent, true)) + // Let's generate the `NewBlock` and `NewBestBlock` events for the block. + events.extend(self.generate_import_events(*hash, *parent, true)) + } } Ok(events) @@ -448,17 +431,13 @@ where let last_finalized = notification.hash; // Ensure we are only reporting blocks after the starting point. - let Some(block_number) = self.client.number(last_finalized)? else { - return Err(SubscriptionManagementError::BlockNumberAbsent) - }; - if block_number < startup_point.finalized_number { + if *notification.header.number() < startup_point.finalized_number { return Ok(Default::default()) } // The tree route contains the exclusive path from the last finalized block to the block // reported by the notification. Ensure the finalized block is also reported. - let mut finalized_block_hashes = - notification.tree_route.iter().cloned().collect::>(); + let mut finalized_block_hashes = notification.tree_route.to_vec(); finalized_block_hashes.push(last_finalized); // If the finalized hashes were not reported yet, generate the `NewBlock` events. @@ -476,9 +455,8 @@ where match self.best_block_cache { Some(block_cache) => { - // Check if the current best block is also reported as pruned. - let reported_pruned = pruned_block_hashes.iter().find(|&&hash| hash == block_cache); - if reported_pruned.is_none() { + // If the best block wasn't pruned, we are done here. + if !pruned_block_hashes.iter().any(|hash| *hash == block_cache) { events.push(finalized_event); return Ok(events) } @@ -499,20 +477,6 @@ where events.push(finalized_event); Ok(events) } else { - let ancestor = sp_blockchain::lowest_common_ancestor( - &*self.client, - last_finalized, - best_block_hash, - )?; - - // The client's best block must be a descendent of the last finalized block. - // In other words, the lowest common ancestor must be the last finalized block. - if ancestor.hash != last_finalized { - return Err(SubscriptionManagementError::Custom( - "The finalized block is not an ancestor of the best block".into(), - )) - } - // The RPC needs to also submit a new best block changed before the // finalized event. self.best_block_cache = Some(best_block_hash); diff --git a/client/rpc-spec-v2/src/chain_head/subscription.rs b/client/rpc-spec-v2/src/chain_head/subscription.rs index 77d57e747ebc1..687374bba5e00 100644 --- a/client/rpc-spec-v2/src/chain_head/subscription.rs +++ b/client/rpc-spec-v2/src/chain_head/subscription.rs @@ -36,10 +36,8 @@ pub enum SubscriptionManagementError { ExceededLimits, /// Error originated from the blockchain (client or backend). Blockchain(Error), - /// The database does not contain a block number. - BlockNumberAbsent, - /// The database does not contain a block hash. - BlockHashAbsent, + /// The database does not contain a block header. + BlockHeaderAbsent, /// Custom error. Custom(String), } diff --git a/client/rpc-spec-v2/src/chain_head/tests.rs b/client/rpc-spec-v2/src/chain_head/tests.rs index 0110c97a05910..fcd906dcf5be0 100644 --- a/client/rpc-spec-v2/src/chain_head/tests.rs +++ b/client/rpc-spec-v2/src/chain_head/tests.rs @@ -1024,9 +1024,6 @@ async fn follow_prune_best_block() { } #[tokio::test] -#[cfg(disable_flaky)] -#[allow(dead_code)] -// FIXME: https://github.com/paritytech/substrate/issues/11321 async fn follow_forks_pruned_block() { let builder = TestClientBuilder::new(); let backend = builder.backend(); @@ -1140,9 +1137,6 @@ async fn follow_forks_pruned_block() { } #[tokio::test] -#[cfg(disable_flaky)] -#[allow(dead_code)] -// FIXME: https://github.com/paritytech/substrate/issues/11321 async fn follow_report_multiple_pruned_block() { let builder = TestClientBuilder::new(); let backend = builder.backend(); From 8bd57418b79d2450079755c0d631168b8fad2e97 Mon Sep 17 00:00:00 2001 From: Kasper Ziemianek Date: Wed, 22 Mar 2023 13:13:31 +0100 Subject: [PATCH 554/715] GetCallIndex trait (#13558) * GetCallIndex trait * final impl * ".git/.scripts/commands/fmt/fmt.sh" * Docs Signed-off-by: Oliver Tale-Yazdi * One more test Signed-off-by: Oliver Tale-Yazdi * Doc Signed-off-by: Oliver Tale-Yazdi --------- Signed-off-by: Oliver Tale-Yazdi Co-authored-by: command-bot <> Co-authored-by: Oliver Tale-Yazdi --- frame/support/procedural/src/lib.rs | 3 +- .../procedural/src/pallet/expand/call.rs | 15 ++++++++++ frame/support/src/dispatch.rs | 3 +- frame/support/src/traits.rs | 4 +-- frame/support/src/traits/metadata.rs | 10 ++++++- frame/support/test/tests/pallet.rs | 29 +++++++++++++++++-- 6 files changed, 56 insertions(+), 8 deletions(-) diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index 0515a4b7d2f91..45f22202991e8 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -984,7 +984,8 @@ pub fn compact(_: TokenStream, _: TokenStream) -> TokenStream { /// /// 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`. +/// `Encode`, `Decode`, `GetDispatchInfo`, `GetCallName`, `GetCallIndex` and +/// `UnfilteredDispatchable`. /// /// The macro implements the `Callable` trait on `Pallet` and a function `call_functions` /// which returns the dispatchable metadata. diff --git a/frame/support/procedural/src/pallet/expand/call.rs b/frame/support/procedural/src/pallet/expand/call.rs index 7672609a9881e..0fdf4455ae7d0 100644 --- a/frame/support/procedural/src/pallet/expand/call.rs +++ b/frame/support/procedural/src/pallet/expand/call.rs @@ -324,6 +324,21 @@ pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream { } } + impl<#type_impl_gen> #frame_support::dispatch::GetCallIndex for #call_ident<#type_use_gen> + #where_clause + { + fn get_call_index(&self) -> u8 { + match *self { + #( Self::#fn_name { .. } => #call_index, )* + Self::__Ignore(_, _) => unreachable!("__PhantomItem cannot be used."), + } + } + + fn get_call_indices() -> &'static [u8] { + &[ #( #call_index, )* ] + } + } + impl<#type_impl_gen> #frame_support::traits::UnfilteredDispatchable for #call_ident<#type_use_gen> #where_clause diff --git a/frame/support/src/dispatch.rs b/frame/support/src/dispatch.rs index 390555b02d1bb..1b87acb4db8dd 100644 --- a/frame/support/src/dispatch.rs +++ b/frame/support/src/dispatch.rs @@ -29,7 +29,8 @@ pub use crate::{ result, }, traits::{ - CallMetadata, GetCallMetadata, GetCallName, GetStorageVersion, UnfilteredDispatchable, + CallMetadata, GetCallIndex, GetCallMetadata, GetCallName, GetStorageVersion, + UnfilteredDispatchable, }, }; #[cfg(feature = "std")] diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index 4b92cfbaee69c..17d2fb06c8118 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -74,8 +74,8 @@ pub use randomness::Randomness; mod metadata; pub use metadata::{ - CallMetadata, CrateVersion, GetCallMetadata, GetCallName, GetStorageVersion, PalletInfo, - PalletInfoAccess, PalletInfoData, PalletsInfoAccess, StorageVersion, + CallMetadata, CrateVersion, GetCallIndex, GetCallMetadata, GetCallName, GetStorageVersion, + PalletInfo, PalletInfoAccess, PalletInfoData, PalletsInfoAccess, StorageVersion, STORAGE_VERSION_STORAGE_KEY_POSTFIX, }; diff --git a/frame/support/src/traits/metadata.rs b/frame/support/src/traits/metadata.rs index f3e4b955da4a9..20ddb1d34ca1a 100644 --- a/frame/support/src/traits/metadata.rs +++ b/frame/support/src/traits/metadata.rs @@ -101,12 +101,20 @@ pub struct CallMetadata { /// Gets the function name of the Call. pub trait GetCallName { - /// Return all function names. + /// Return all function names in the same order as [`GetCallIndex`]. fn get_call_names() -> &'static [&'static str]; /// Return the function name of the Call. fn get_call_name(&self) -> &'static str; } +/// Gets the function index of the Call. +pub trait GetCallIndex { + /// Return all call indices in the same order as [`GetCallName`]. + fn get_call_indices() -> &'static [u8]; + /// Return the index of this Call. + fn get_call_index(&self) -> u8; +} + /// Gets the metadata for the Call - function name and pallet name. pub trait GetCallMetadata { /// Return all module names. diff --git a/frame/support/test/tests/pallet.rs b/frame/support/test/tests/pallet.rs index b9e531fb42105..52acdc5c26e03 100644 --- a/frame/support/test/tests/pallet.rs +++ b/frame/support/test/tests/pallet.rs @@ -25,8 +25,8 @@ use frame_support::{ pallet_prelude::{StorageInfoTrait, ValueQuery}, storage::unhashed, traits::{ - ConstU32, GetCallName, GetStorageVersion, OnFinalize, OnGenesis, OnInitialize, - OnRuntimeUpgrade, PalletError, PalletInfoAccess, StorageVersion, + ConstU32, GetCallIndex, GetCallName, GetStorageVersion, OnFinalize, OnGenesis, + OnInitialize, OnRuntimeUpgrade, PalletError, PalletInfoAccess, StorageVersion, }, weights::{RuntimeDbWeight, Weight}, }; @@ -231,6 +231,12 @@ pub mod pallet { Ok(().into()) } + #[pallet::call_index(4)] + #[pallet::weight(1)] + pub fn foo_index_out_of_order(_origin: OriginFor) -> DispatchResult { + Ok(()) + } + // Test for DispatchResult return type #[pallet::call_index(2)] #[pallet::weight(1)] @@ -728,8 +734,25 @@ fn call_expand() { assert_eq!(call_foo.get_call_name(), "foo"); assert_eq!( pallet::Call::::get_call_names(), - &["foo", "foo_storage_layer", "foo_no_post_info", "check_for_dispatch_context"], + &[ + "foo", + "foo_storage_layer", + "foo_index_out_of_order", + "foo_no_post_info", + "check_for_dispatch_context" + ], ); + + assert_eq!(call_foo.get_call_index(), 0u8); + assert_eq!(pallet::Call::::get_call_indices(), &[0u8, 1u8, 4u8, 2u8, 3u8]) +} + +#[test] +fn call_expand_index() { + let call_foo = pallet::Call::::foo_index_out_of_order {}; + + assert_eq!(call_foo.get_call_index(), 4u8); + assert_eq!(pallet::Call::::get_call_indices(), &[0u8, 1u8, 4u8, 2u8, 3u8]) } #[test] From a9e85ae50d0efbf66f9a715af3b31bf37b884a6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 22 Mar 2023 20:46:35 +0100 Subject: [PATCH 555/715] Remove unused trait (#13682) --- primitives/core/src/traits.rs | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/primitives/core/src/traits.rs b/primitives/core/src/traits.rs index 0e42ee3ad4b12..091b1cdb14a34 100644 --- a/primitives/core/src/traits.rs +++ b/primitives/core/src/traits.rs @@ -181,19 +181,6 @@ impl TaskExecutorExt { } } -/// Runtime spawn extension. -pub trait RuntimeSpawn: Send { - /// Create new runtime instance and use dynamic dispatch to invoke with specified payload. - /// - /// Returns handle of the spawned task. - /// - /// Function pointers (`dispatcher_ref`, `func`) are WASM pointer types. - fn spawn_call(&self, dispatcher_ref: u32, func: u32, payload: Vec) -> u64; - - /// Join the result of previously created runtime instance invocation. - fn join(&self, handle: u64) -> Vec; -} - /// Something that can spawn tasks (blocking and non-blocking) with an assigned name /// and optional group. #[dyn_clonable::clonable] From 118414302ace70fff0a913fe7ee825569c16c612 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Thu, 23 Mar 2023 11:35:39 +0100 Subject: [PATCH 556/715] Remove unused light-client leftover (#13687) * Remove unused light-client leftover * Remove more unused code --- client/network/sync/src/engine.rs | 39 +------------------------------ 1 file changed, 1 insertion(+), 38 deletions(-) diff --git a/client/network/sync/src/engine.rs b/client/network/sync/src/engine.rs index e6e62101ffcd0..a9c9afc3c6f4c 100644 --- a/client/network/sync/src/engine.rs +++ b/client/network/sync/src/engine.rs @@ -58,10 +58,7 @@ use sc_network_common::{ use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; use sp_blockchain::HeaderMetadata; use sp_consensus::block_validation::BlockAnnounceValidator; -use sp_runtime::{ - traits::{Block as BlockT, CheckedSub, Header, NumberFor, Zero}, - SaturatedConversion, -}; +use sp_runtime::traits::{Block as BlockT, Header, NumberFor, Zero}; use std::{ collections::{HashMap, HashSet}, @@ -77,24 +74,15 @@ use std::{ /// Interval at which we perform time based maintenance const TICK_TIMEOUT: std::time::Duration = std::time::Duration::from_millis(1100); -/// When light node connects to the full node and the full node is behind light node -/// for at least `LIGHT_MAXIMAL_BLOCKS_DIFFERENCE` blocks, we consider it not useful -/// and disconnect to free connection slot. -const LIGHT_MAXIMAL_BLOCKS_DIFFERENCE: u64 = 8192; - /// Maximum number of known block hashes to keep for a peer. const MAX_KNOWN_BLOCKS: usize = 1024; // ~32kb per peer + LruHashSet overhead mod rep { use sc_peerset::ReputationChange as Rep; - /// 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 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. pub const BAD_BLOCK_ANNOUNCEMENT: Rep = Rep::new(-(1 << 12), "Bad block announcement"); } @@ -834,31 +822,6 @@ where return Err(()) } - if self.roles.is_light() { - // we're not interested in light peers - if status.roles.is_light() { - log::debug!(target: "sync", "Peer {} is unable to serve light requests", who); - self.network_service.report_peer(who, rep::BAD_ROLE); - self.network_service - .disconnect_peer(who, self.block_announce_protocol_name.clone()); - return Err(()) - } - - // we don't interested in peers that are far behind us - let self_best_block = self.client.info().best_number; - let blocks_difference = self_best_block - .checked_sub(&status.best_number) - .unwrap_or_else(Zero::zero) - .saturated_into::(); - if blocks_difference > LIGHT_MAXIMAL_BLOCKS_DIFFERENCE { - log::debug!(target: "sync", "Peer {} is far behind us and will unable to serve light requests", who); - self.network_service.report_peer(who, rep::PEER_BEHIND_US_LIGHT); - self.network_service - .disconnect_peer(who, self.block_announce_protocol_name.clone()); - return Err(()) - } - } - 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 }; From 988f6add941b57ceb2af00ab815b3727f03fc1fb Mon Sep 17 00:00:00 2001 From: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Date: Thu, 23 Mar 2023 15:40:02 +0200 Subject: [PATCH 557/715] chain_head/tests: Check finalized block event before new block (#13680) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chain_head/tests: Mock client for custom block notification Signed-off-by: Alexandru Vasile * chain_head/tests: Check finalized block event before new block Signed-off-by: Alexandru Vasile * Update client/rpc-spec-v2/src/chain_head/test_utils.rs Co-authored-by: Bastian Köcher * Update client/rpc-spec-v2/src/chain_head/test_utils.rs Co-authored-by: Bastian Köcher * Update client/rpc-spec-v2/src/chain_head/test_utils.rs Co-authored-by: Bastian Köcher * chain_head/tests: Run import events with 10min timeout Signed-off-by: Alexandru Vasile * chain_head/tests: Add comments about test Signed-off-by: Alexandru Vasile --------- Signed-off-by: Alexandru Vasile Co-authored-by: Bastian Köcher --- Cargo.lock | 3 +- client/rpc-spec-v2/Cargo.toml | 1 + client/rpc-spec-v2/src/chain_head/mod.rs | 2 + .../rpc-spec-v2/src/chain_head/test_utils.rs | 320 ++++++++++++++++++ client/rpc-spec-v2/src/chain_head/tests.rs | 103 +++++- 5 files changed, 427 insertions(+), 2 deletions(-) create mode 100644 client/rpc-spec-v2/src/chain_head/test_utils.rs diff --git a/Cargo.lock b/Cargo.lock index 5b2879e1ba9b6..a645ecec60d86 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9275,6 +9275,7 @@ dependencies = [ "sc-chain-spec", "sc-client-api", "sc-transaction-pool-api", + "sc-utils", "serde", "serde_json", "sp-api", @@ -11954,7 +11955,7 @@ checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" dependencies = [ "cfg-if", "digest 0.10.6", - "rand 0.7.3", + "rand 0.8.5", "static_assertions", ] diff --git a/client/rpc-spec-v2/Cargo.toml b/client/rpc-spec-v2/Cargo.toml index 43fb189081bae..23b96877f3b17 100644 --- a/client/rpc-spec-v2/Cargo.toml +++ b/client/rpc-spec-v2/Cargo.toml @@ -43,4 +43,5 @@ substrate-test-runtime = { version = "2.0.0", path = "../../test-utils/runtime" sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } sp-maybe-compressed-blob = { version = "4.1.0-dev", path = "../../primitives/maybe-compressed-blob" } sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" } +sc-utils = { version = "4.0.0-dev", path = "../utils" } assert_matches = "1.3.0" diff --git a/client/rpc-spec-v2/src/chain_head/mod.rs b/client/rpc-spec-v2/src/chain_head/mod.rs index afa8d3b2189ae..1c489d323f195 100644 --- a/client/rpc-spec-v2/src/chain_head/mod.rs +++ b/client/rpc-spec-v2/src/chain_head/mod.rs @@ -22,6 +22,8 @@ //! //! Methods are prefixed by `chainHead`. +#[cfg(test)] +mod test_utils; #[cfg(test)] mod tests; diff --git a/client/rpc-spec-v2/src/chain_head/test_utils.rs b/client/rpc-spec-v2/src/chain_head/test_utils.rs new file mode 100644 index 0000000000000..ee563debb4502 --- /dev/null +++ b/client/rpc-spec-v2/src/chain_head/test_utils.rs @@ -0,0 +1,320 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use parking_lot::Mutex; +use sc_client_api::{ + execution_extensions::ExecutionExtensions, BlockBackend, BlockImportNotification, + BlockchainEvents, CallExecutor, ChildInfo, ExecutorProvider, FinalityNotification, + FinalityNotifications, FinalizeSummary, ImportNotifications, KeysIter, PairsIter, StorageData, + StorageEventStream, StorageKey, StorageProvider, +}; +use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedSender}; +use sp_api::{CallApiAt, CallApiAtParams, NumberFor, RuntimeVersion}; +use sp_blockchain::{BlockStatus, CachedHeaderMetadata, HeaderBackend, HeaderMetadata, Info}; +use sp_consensus::BlockOrigin; +use sp_runtime::{ + generic::SignedBlock, + traits::{Block as BlockT, Header as HeaderT}, + Justifications, +}; +use std::sync::Arc; +use substrate_test_runtime::{Block, Hash, Header}; + +pub struct ChainHeadMockClient { + client: Arc, + import_sinks: Mutex>>>, + finality_sinks: Mutex>>>, +} + +impl ChainHeadMockClient { + pub fn new(client: Arc) -> Self { + ChainHeadMockClient { + client, + import_sinks: Default::default(), + finality_sinks: Default::default(), + } + } + + pub async fn trigger_import_stream(&self, header: Header) { + // Ensure the client called the `import_notification_stream`. + while self.import_sinks.lock().is_empty() { + tokio::time::sleep(tokio::time::Duration::from_secs(1)).await; + } + + // Build the notification. + let (sink, _stream) = tracing_unbounded("test_sink", 100_000); + let notification = + BlockImportNotification::new(header.hash(), BlockOrigin::Own, header, true, None, sink); + + for sink in self.import_sinks.lock().iter_mut() { + sink.unbounded_send(notification.clone()).unwrap(); + } + } + + pub async fn trigger_finality_stream(&self, header: Header) { + // Ensure the client called the `finality_notification_stream`. + while self.finality_sinks.lock().is_empty() { + tokio::time::sleep(tokio::time::Duration::from_secs(1)).await; + } + + // Build the notification. + let (sink, _stream) = tracing_unbounded("test_sink", 100_000); + let summary = FinalizeSummary { + header: header.clone(), + finalized: vec![header.hash()], + stale_heads: vec![], + }; + let notification = FinalityNotification::from_summary(summary, sink); + + for sink in self.finality_sinks.lock().iter_mut() { + sink.unbounded_send(notification.clone()).unwrap(); + } + } +} + +// ChainHead calls `import_notification_stream` and `finality_notification_stream` in order to +// subscribe to block events. +impl BlockchainEvents for ChainHeadMockClient { + fn import_notification_stream(&self) -> ImportNotifications { + let (sink, stream) = tracing_unbounded("import_notification_stream", 1024); + self.import_sinks.lock().push(sink); + stream + } + + fn every_import_notification_stream(&self) -> ImportNotifications { + unimplemented!() + } + + fn finality_notification_stream(&self) -> FinalityNotifications { + let (sink, stream) = tracing_unbounded("finality_notification_stream", 1024); + self.finality_sinks.lock().push(sink); + stream + } + + fn storage_changes_notification_stream( + &self, + _filter_keys: Option<&[StorageKey]>, + _child_filter_keys: Option<&[(StorageKey, Option>)]>, + ) -> sp_blockchain::Result> { + unimplemented!() + } +} + +// The following implementations are imposed by the `chainHead` trait bounds. + +impl, Client: ExecutorProvider> + ExecutorProvider for ChainHeadMockClient +{ + type Executor = >::Executor; + + fn executor(&self) -> &Self::Executor { + self.client.executor() + } + + fn execution_extensions(&self) -> &ExecutionExtensions { + self.client.execution_extensions() + } +} + +impl< + BE: sc_client_api::backend::Backend + Send + Sync + 'static, + Block: BlockT, + Client: StorageProvider, + > StorageProvider for ChainHeadMockClient +{ + fn storage( + &self, + hash: Block::Hash, + key: &StorageKey, + ) -> sp_blockchain::Result> { + self.client.storage(hash, key) + } + + fn storage_hash( + &self, + hash: Block::Hash, + key: &StorageKey, + ) -> sp_blockchain::Result> { + self.client.storage_hash(hash, key) + } + + fn storage_keys( + &self, + hash: Block::Hash, + prefix: Option<&StorageKey>, + start_key: Option<&StorageKey>, + ) -> sp_blockchain::Result> { + self.client.storage_keys(hash, prefix, start_key) + } + + fn storage_pairs( + &self, + hash: ::Hash, + prefix: Option<&StorageKey>, + start_key: Option<&StorageKey>, + ) -> sp_blockchain::Result> { + self.client.storage_pairs(hash, prefix, start_key) + } + + fn child_storage( + &self, + hash: Block::Hash, + child_info: &ChildInfo, + key: &StorageKey, + ) -> sp_blockchain::Result> { + self.client.child_storage(hash, child_info, key) + } + + fn child_storage_keys( + &self, + hash: Block::Hash, + child_info: ChildInfo, + prefix: Option<&StorageKey>, + start_key: Option<&StorageKey>, + ) -> sp_blockchain::Result> { + self.client.child_storage_keys(hash, child_info, prefix, start_key) + } + + fn child_storage_hash( + &self, + hash: Block::Hash, + child_info: &ChildInfo, + key: &StorageKey, + ) -> sp_blockchain::Result> { + self.client.child_storage_hash(hash, child_info, key) + } +} + +impl> CallApiAt for ChainHeadMockClient { + type StateBackend = >::StateBackend; + + fn call_api_at( + &self, + params: CallApiAtParams>::StateBackend>, + ) -> Result, sp_api::ApiError> { + self.client.call_api_at(params) + } + + fn runtime_version_at(&self, hash: Block::Hash) -> Result { + self.client.runtime_version_at(hash) + } + + fn state_at(&self, at: Block::Hash) -> Result { + self.client.state_at(at) + } +} + +impl> BlockBackend + for ChainHeadMockClient +{ + fn block_body( + &self, + hash: Block::Hash, + ) -> sp_blockchain::Result::Extrinsic>>> { + self.client.block_body(hash) + } + + fn block(&self, hash: Block::Hash) -> sp_blockchain::Result>> { + self.client.block(hash) + } + + fn block_status(&self, hash: Block::Hash) -> sp_blockchain::Result { + self.client.block_status(hash) + } + + fn justifications(&self, hash: Block::Hash) -> sp_blockchain::Result> { + self.client.justifications(hash) + } + + fn block_hash(&self, number: NumberFor) -> sp_blockchain::Result> { + self.client.block_hash(number) + } + + fn indexed_transaction(&self, hash: Block::Hash) -> sp_blockchain::Result>> { + self.client.indexed_transaction(hash) + } + + fn has_indexed_transaction(&self, hash: Block::Hash) -> sp_blockchain::Result { + self.client.has_indexed_transaction(hash) + } + + fn block_indexed_body(&self, hash: Block::Hash) -> sp_blockchain::Result>>> { + self.client.block_indexed_body(hash) + } + fn requires_full_sync(&self) -> bool { + self.client.requires_full_sync() + } +} + +impl + Send + Sync> HeaderMetadata + for ChainHeadMockClient +{ + type Error = >::Error; + + fn header_metadata( + &self, + hash: Block::Hash, + ) -> Result, Self::Error> { + self.client.header_metadata(hash) + } + + fn insert_header_metadata( + &self, + hash: Block::Hash, + header_metadata: CachedHeaderMetadata, + ) { + self.client.insert_header_metadata(hash, header_metadata) + } + + fn remove_header_metadata(&self, hash: Block::Hash) { + self.client.remove_header_metadata(hash) + } +} + +impl + Send + Sync> HeaderBackend + for ChainHeadMockClient +{ + fn header( + &self, + hash: Block::Hash, + ) -> sp_blockchain::Result::Header>> { + self.client.header(hash) + } + + fn info(&self) -> Info { + self.client.info() + } + + fn status(&self, hash: Block::Hash) -> sc_client_api::blockchain::Result { + self.client.status(hash) + } + + fn number( + &self, + hash: Block::Hash, + ) -> sc_client_api::blockchain::Result::Header as HeaderT>::Number>> { + self.client.number(hash) + } + + fn hash( + &self, + number: <::Header as HeaderT>::Number, + ) -> sp_blockchain::Result> { + self.client.hash(number) + } +} diff --git a/client/rpc-spec-v2/src/chain_head/tests.rs b/client/rpc-spec-v2/src/chain_head/tests.rs index fcd906dcf5be0..1d5cb8da26305 100644 --- a/client/rpc-spec-v2/src/chain_head/tests.rs +++ b/client/rpc-spec-v2/src/chain_head/tests.rs @@ -1,6 +1,9 @@ +use crate::chain_head::test_utils::ChainHeadMockClient; + use super::*; use assert_matches::assert_matches; use codec::{Decode, Encode}; +use futures::Future; use jsonrpsee::{ core::{error::Error, server::rpc_module::Subscription as RpcSubscription}, types::{error::CallError, EmptyServerParams as EmptyParams}, @@ -33,7 +36,7 @@ const CHILD_STORAGE_KEY: &[u8] = b"child"; const CHILD_VALUE: &[u8] = b"child value"; async fn get_next_event(sub: &mut RpcSubscription) -> T { - let (event, _sub_id) = tokio::time::timeout(std::time::Duration::from_secs(1), sub.next()) + let (event, _sub_id) = tokio::time::timeout(std::time::Duration::from_secs(60), sub.next()) .await .unwrap() .unwrap() @@ -41,6 +44,12 @@ async fn get_next_event(sub: &mut RpcSubscriptio event } +async fn run_with_timeout(future: F) -> ::Output { + tokio::time::timeout(std::time::Duration::from_secs(60 * 10), future) + .await + .unwrap() +} + async fn setup_api() -> ( Arc>, RpcModule>>, @@ -1317,3 +1326,95 @@ async fn follow_report_multiple_pruned_block() { }); assert_eq!(event, expected); } + +#[tokio::test] +async fn follow_finalized_before_new_block() { + let builder = TestClientBuilder::new(); + let backend = builder.backend(); + let mut client = Arc::new(builder.build()); + + let client_mock = Arc::new(ChainHeadMockClient::new(client.clone())); + + let api = ChainHead::new( + client_mock.clone(), + backend, + Arc::new(TaskExecutor::default()), + CHAIN_GENESIS, + MAX_PINNED_BLOCKS, + ) + .into_rpc(); + + // Make sure the block is imported for it to be pinned. + let block_1 = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block_1_hash = block_1.header.hash(); + client.import(BlockOrigin::Own, block_1.clone()).await.unwrap(); + + let mut sub = api.subscribe("chainHead_unstable_follow", [false]).await.unwrap(); + + // Trigger the `FinalizedNotification` for block 1 before the `BlockImportNotification`, and + // expect for the `chainHead` to generate `NewBlock`, `BestBlock` and `Finalized` events. + + // Trigger the Finalized notification before the NewBlock one. + run_with_timeout(client_mock.trigger_finality_stream(block_1.header.clone())).await; + + // Initialized must always be reported first. + let finalized_hash = client.info().finalized_hash; + let event: FollowEvent = get_next_event(&mut sub).await; + let expected = FollowEvent::Initialized(Initialized { + finalized_block_hash: format!("{:?}", finalized_hash), + finalized_block_runtime: None, + runtime_updates: false, + }); + assert_eq!(event, expected); + + // Block 1 must be reported because we triggered the finalized notification. + let event: FollowEvent = get_next_event(&mut sub).await; + let expected = FollowEvent::NewBlock(NewBlock { + block_hash: format!("{:?}", block_1_hash), + parent_block_hash: format!("{:?}", finalized_hash), + new_runtime: None, + runtime_updates: false, + }); + assert_eq!(event, expected); + + let event: FollowEvent = get_next_event(&mut sub).await; + let expected = FollowEvent::BestBlockChanged(BestBlockChanged { + best_block_hash: format!("{:?}", block_1_hash), + }); + assert_eq!(event, expected); + + let event: FollowEvent = get_next_event(&mut sub).await; + let expected = FollowEvent::Finalized(Finalized { + finalized_block_hashes: vec![format!("{:?}", block_1_hash)], + pruned_block_hashes: vec![], + }); + assert_eq!(event, expected); + + let block_2 = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block_2_hash = block_2.header.hash(); + client.import(BlockOrigin::Own, block_2.clone()).await.unwrap(); + + // Triggering the `BlockImportNotification` notification for block 1 should have no effect + // on the notification because the events were handled by the `FinalizedNotification`. + // Also trigger the `BlockImportNotification` notification for block 2 to ensure + // `NewBlock and `BestBlock` events are generated. + + // Trigger NewBlock notification for block 1 and block 2. + run_with_timeout(client_mock.trigger_import_stream(block_1.header)).await; + run_with_timeout(client_mock.trigger_import_stream(block_2.header)).await; + + let event: FollowEvent = get_next_event(&mut sub).await; + let expected = FollowEvent::NewBlock(NewBlock { + block_hash: format!("{:?}", block_2_hash), + parent_block_hash: format!("{:?}", block_1_hash), + new_runtime: None, + runtime_updates: false, + }); + assert_eq!(event, expected); + + let event: FollowEvent = get_next_event(&mut sub).await; + let expected = FollowEvent::BestBlockChanged(BestBlockChanged { + best_block_hash: format!("{:?}", block_2_hash), + }); + assert_eq!(event, expected); +} From 905861780ee0f6556d915a70a7a49371fc1fad2c Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Thu, 23 Mar 2023 18:09:29 +0100 Subject: [PATCH 558/715] Remove Weight::without_{ref_time, proof_size} (#13637) Signed-off-by: Oliver Tale-Yazdi --- primitives/weights/src/weight_v2.rs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/primitives/weights/src/weight_v2.rs b/primitives/weights/src/weight_v2.rs index 76c40c16cbf03..ca137145920bb 100644 --- a/primitives/weights/src/weight_v2.rs +++ b/primitives/weights/src/weight_v2.rs @@ -74,16 +74,6 @@ impl Weight { &mut self.proof_size } - /// Return self but discard any reference time. - pub const fn without_ref_time(&self) -> Self { - Self { ref_time: 0, proof_size: self.proof_size } - } - - /// Return self but discard any proof size. - pub const fn without_proof_size(&self) -> Self { - Self { ref_time: self.ref_time, proof_size: 0 } - } - pub const MAX: Self = Self { ref_time: u64::MAX, proof_size: u64::MAX }; /// Get the conservative min of `self` and `other` weight. From bf395c8308c481a9774373e0b0b14bd7a2e4b8d2 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Fri, 24 Mar 2023 14:46:02 +0100 Subject: [PATCH 559/715] Keystore overhaul (final) (#13683) * Introduce keystore specialized sign methods * Get rid of 'AppKey::UntypedGeneric' associated type. Untyped generics are accessible using associated types 'Generic' associated type. I.e. ::Public::Generic * Get rid of 'CryptoTypePublicPair' * Trivial fix * Small refactory of local keystore implementations * Remove 'crypto_id' method from 'Public' * Trivial rename of 'AppKey' to 'AppCrypto' * Remove unused import * Improve docs * Better signature related errors for authority-discovery * Apply review suggestion * Apply review suggestions Co-authored-by: Koute * Authority discoverty signing error revisited * Signing error revisited for babe and aura as well * Further cleanup --------- Co-authored-by: Koute --- bin/node/cli/src/service.rs | 12 +- bin/node/executor/tests/submit_transaction.rs | 2 +- client/authority-discovery/src/error.rs | 9 +- client/authority-discovery/src/worker.rs | 27 ++- client/consensus/aura/src/lib.rs | 59 +++-- client/consensus/babe/rpc/src/lib.rs | 2 +- client/consensus/babe/src/authorship.rs | 2 +- client/consensus/babe/src/lib.rs | 47 ++-- client/consensus/grandpa/src/lib.rs | 2 +- client/consensus/slots/src/lib.rs | 2 +- client/keystore/src/local.rs | 214 +++++++++--------- client/rpc/src/author/tests.rs | 14 +- primitives/application-crypto/src/lib.rs | 39 +--- primitives/application-crypto/src/traits.rs | 29 ++- .../application-crypto/test/src/ecdsa.rs | 11 +- .../application-crypto/test/src/ed25519.rs | 11 +- .../application-crypto/test/src/sr25519.rs | 11 +- primitives/consensus/common/src/error.rs | 4 +- primitives/consensus/grandpa/src/lib.rs | 5 +- primitives/core/src/crypto.rs | 37 +-- primitives/core/src/ecdsa.rs | 21 +- primitives/core/src/ed25519.rs | 22 +- primitives/core/src/sr25519.rs | 23 +- primitives/io/src/lib.rs | 9 +- primitives/keystore/src/lib.rs | 191 ++++++++++------ primitives/keystore/src/testing.rs | 197 ++++++++-------- primitives/runtime/src/traits.rs | 18 +- 27 files changed, 478 insertions(+), 542 deletions(-) diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs index be8553b7b3a98..ca6830085b055 100644 --- a/bin/node/cli/src/service.rs +++ b/bin/node/cli/src/service.rs @@ -592,7 +592,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}; + use sp_core::crypto::Pair; use sp_inherents::InherentDataProvider; use sp_keyring::AccountKeyring; use sp_keystore::KeystorePtr; @@ -737,16 +737,10 @@ mod tests { // add it to a digest item. let to_sign = pre_hash.encode(); let signature = keystore - .sign_with( - sp_consensus_babe::AuthorityId::ID, - &alice.to_public_crypto_pair(), - &to_sign, - ) - .unwrap() + .sr25519_sign(sp_consensus_babe::AuthorityId::ID, alice.as_ref(), &to_sign) .unwrap() - .try_into() .unwrap(); - let item = ::babe_seal(signature); + let item = ::babe_seal(signature.into()); slot += 1; let mut params = BlockImportParams::new(BlockOrigin::File, new_header); diff --git a/bin/node/executor/tests/submit_transaction.rs b/bin/node/executor/tests/submit_transaction.rs index 9bff415d27e45..b260f90a87466 100644 --- a/bin/node/executor/tests/submit_transaction.rs +++ b/bin/node/executor/tests/submit_transaction.rs @@ -18,7 +18,7 @@ use codec::Decode; use frame_system::offchain::{SendSignedTransaction, Signer, SubmitTransaction}; use kitchensink_runtime::{Executive, Indices, Runtime, UncheckedExtrinsic}; -use sp_application_crypto::AppKey; +use sp_application_crypto::AppCrypto; use sp_core::offchain::{testing::TestTransactionPoolExt, TransactionPoolExt}; use sp_keyring::sr25519::Keyring::Alice; use sp_keystore::{testing::MemoryKeystore, Keystore, KeystoreExt}; diff --git a/client/authority-discovery/src/error.rs b/client/authority-discovery/src/error.rs index 89c05b71b9ea6..447116b0f6b56 100644 --- a/client/authority-discovery/src/error.rs +++ b/client/authority-discovery/src/error.rs @@ -18,8 +18,6 @@ //! Authority discovery errors. -use sp_core::crypto::CryptoTypePublicPair; - /// AuthorityDiscovery Result. pub type Result = std::result::Result; @@ -59,11 +57,8 @@ pub enum Error { #[error("Failed to parse a libp2p key.")] ParsingLibp2pIdentity(#[from] libp2p::identity::error::DecodingError), - #[error("Failed to sign using a specific public key.")] - MissingSignature(CryptoTypePublicPair), - - #[error("Failed to sign using all public keys.")] - Signing, + #[error("Failed to sign: {0}.")] + CannotSign(String), #[error("Failed to register Prometheus metric.")] Prometheus(#[from] prometheus_endpoint::PrometheusError), diff --git a/client/authority-discovery/src/worker.rs b/client/authority-discovery/src/worker.rs index 5d7d21a5b6de4..43e44cac4d3fe 100644 --- a/client/authority-discovery/src/worker.rs +++ b/client/authority-discovery/src/worker.rs @@ -32,7 +32,7 @@ use std::{ use futures::{channel::mpsc, future, stream::Fuse, FutureExt, Stream, StreamExt}; use addr_cache::AddrCache; -use codec::Decode; +use codec::{Decode, Encode}; use ip_network::IpNetwork; use libp2p::{ core::multiaddr, @@ -43,6 +43,7 @@ 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_network::{ event::DhtEvent, KademliaKey, NetworkDHTProvider, NetworkSigner, NetworkStateInfo, Signature, }; @@ -51,8 +52,7 @@ use sp_authority_discovery::{ AuthorityDiscoveryApi, AuthorityId, AuthorityPair, AuthoritySignature, }; use sp_blockchain::HeaderBackend; - -use sp_core::crypto::{key_types, CryptoTypePublicPair, Pair}; +use sp_core::crypto::{key_types, ByteArray, Pair}; use sp_keystore::{Keystore, KeystorePtr}; use sp_runtime::traits::Block as BlockT; @@ -127,7 +127,7 @@ pub struct Worker { publish_if_changed_interval: ExpIncInterval, /// List of keys onto which addresses have been published at the latest publication. /// Used to check whether they have changed. - latest_published_keys: HashSet, + latest_published_keys: HashSet, /// Same value as in the configuration. publish_non_global_ips: bool, /// Same value as in the configuration. @@ -339,7 +339,7 @@ where let keys = Worker::::get_own_public_keys_within_authority_set( key_store.clone(), self.client.as_ref(), - ).await?.into_iter().map(Into::into).collect::>(); + ).await?.into_iter().collect::>(); if only_if_changed && keys == self.latest_published_keys { return Ok(()) @@ -654,7 +654,7 @@ fn sign_record_with_peer_id( ) -> Result { let signature = network .sign_with_local_identity(serialized_record) - .map_err(|_| Error::Signing)?; + .map_err(|e| Error::CannotSign(format!("{} (network packet)", e)))?; let public_key = signature.public_key.to_protobuf_encoding(); let signature = signature.bytes; Ok(schema::PeerSignature { signature, public_key }) @@ -664,15 +664,20 @@ fn sign_record_with_authority_ids( serialized_record: Vec, peer_signature: Option, key_store: &dyn Keystore, - keys: Vec, + keys: Vec, ) -> Result)>> { let mut result = Vec::with_capacity(keys.len()); for key in keys.iter() { let auth_signature = key_store - .sign_with(key_types::AUTHORITY_DISCOVERY, key, &serialized_record) - .map_err(|_| Error::Signing)? - .ok_or_else(|| Error::MissingSignature(key.clone()))?; + .sr25519_sign(key_types::AUTHORITY_DISCOVERY, key.as_ref(), &serialized_record) + .map_err(|e| Error::CannotSign(format!("{}. Key: {:?}", e, key)))? + .ok_or_else(|| { + Error::CannotSign(format!("Could not find key in keystore. Key: {:?}", key)) + })?; + + // Scale encode + let auth_signature = auth_signature.encode(); let signed_record = schema::SignedAuthorityRecord { record: serialized_record.clone(), @@ -681,7 +686,7 @@ fn sign_record_with_authority_ids( } .encode_to_vec(); - result.push((hash_authority_id(&key.1), signed_record)); + result.push((hash_authority_id(key.as_slice()), signed_record)); } Ok(result) diff --git a/client/consensus/aura/src/lib.rs b/client/consensus/aura/src/lib.rs index d06a6016a2297..a48eeac5ce8b2 100644 --- a/client/consensus/aura/src/lib.rs +++ b/client/consensus/aura/src/lib.rs @@ -45,7 +45,7 @@ use sc_consensus_slots::{ }; use sc_telemetry::TelemetryHandle; use sp_api::{Core, ProvideRuntimeApi}; -use sp_application_crypto::{AppKey, AppPublic}; +use sp_application_crypto::{AppCrypto, AppPublic}; use sp_blockchain::{HeaderBackend, Result as CResult}; use sp_consensus::{BlockOrigin, Environment, Error as ConsensusError, Proposer, SelectChain}; use sp_consensus_slots::Slot; @@ -205,7 +205,7 @@ pub fn start_aura( telemetry, compatibility_mode, }: StartAuraParams>, -) -> Result, sp_consensus::Error> +) -> Result, ConsensusError> where P: Pair + Send + Sync, P::Public: AppPublic + Hash + Member + Encode + Decode, @@ -222,7 +222,7 @@ where CIDP: CreateInherentDataProviders + Send + 'static, CIDP::InherentDataProviders: InherentDataProviderExt + Send, BS: BackoffAuthoringBlocksStrategy> + Send + Sync + 'static, - Error: std::error::Error + Send + From + 'static, + Error: std::error::Error + Send + From + 'static, { let worker = build_aura_worker::(BuildAuraWorkerParams { client, @@ -320,7 +320,7 @@ where P::Public: AppPublic + Hash + Member + Encode + Decode, P::Signature: TryFrom> + Hash + Member + Encode + Decode, I: BlockImport> + Send + Sync + 'static, - Error: std::error::Error + Send + From + 'static, + Error: std::error::Error + Send + From + 'static, SO: SyncOracle + Send + Sync + Clone, L: sc_consensus::JustificationSyncLink, BS: BackoffAuthoringBlocksStrategy> + Send + Sync + 'static, @@ -374,13 +374,13 @@ where SO: SyncOracle + Send + Clone + Sync, L: sc_consensus::JustificationSyncLink, BS: BackoffAuthoringBlocksStrategy> + Send + Sync + 'static, - Error: std::error::Error + Send + From + 'static, + Error: std::error::Error + Send + From + 'static, { type BlockImport = I; type SyncOracle = SO; type JustificationSyncLink = L; type CreateProposer = - Pin> + Send + 'static>>; + Pin> + Send + 'static>>; type Proposer = E::Proposer; type Claim = P::Public; type AuxData = Vec>; @@ -393,11 +393,7 @@ where &mut self.block_import } - fn aux_data( - &self, - header: &B::Header, - _slot: Slot, - ) -> Result { + fn aux_data(&self, header: &B::Header, _slot: Slot) -> Result { authorities( self.client.as_ref(), header.hash(), @@ -406,17 +402,17 @@ where ) } - fn authorities_len(&self, epoch_data: &Self::AuxData) -> Option { - Some(epoch_data.len()) + fn authorities_len(&self, authorities: &Self::AuxData) -> Option { + Some(authorities.len()) } async fn claim_slot( &self, _header: &B::Header, slot: Slot, - epoch_data: &Self::AuxData, + authorities: &Self::AuxData, ) -> Option { - let expected_author = slot_author::

(slot, epoch_data); + let expected_author = slot_author::

(slot, authorities); expected_author.and_then(|p| { if self .keystore @@ -440,29 +436,30 @@ where body: Vec, storage_changes: StorageChanges<>::Transaction, B>, public: Self::Claim, - _epoch: Self::AuxData, + _authorities: Self::AuxData, ) -> Result< sc_consensus::BlockImportParams>::Transaction>, - sp_consensus::Error, + ConsensusError, > { - // 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 = self .keystore - .sign_with( as AppKey>::ID, &public_type_pair, header_hash.as_ref()) - .map_err(|e| sp_consensus::Error::CannotSign(public.clone(), e.to_string()))? + .sign_with( + as AppCrypto>::ID, + as AppCrypto>::CRYPTO_ID, + public.as_slice(), + header_hash.as_ref(), + ) + .map_err(|e| ConsensusError::CannotSign(format!("{}. Key: {:?}", e, public)))? .ok_or_else(|| { - sp_consensus::Error::CannotSign( - public.clone(), - "Could not find key in keystore.".into(), - ) + ConsensusError::CannotSign(format!( + "Could not find key in keystore. Key: {:?}", + public + )) })?; let signature = signature .clone() .try_into() - .map_err(|_| sp_consensus::Error::InvalidSignature(signature, public))?; + .map_err(|_| ConsensusError::InvalidSignature(signature, public.to_raw_vec()))?; let signature_digest_item = >::aura_seal(signature); @@ -507,7 +504,7 @@ where fn proposer(&mut self, block: &B::Header) -> Self::CreateProposer { self.env .init(block) - .map_err(|e| sp_consensus::Error::ClientImport(format!("{:?}", e))) + .map_err(|e| ConsensusError::ClientImport(format!("{:?}", e))) .boxed() } @@ -620,14 +617,14 @@ where Default::default(), ), ) - .map_err(|_| sp_consensus::Error::InvalidAuthoritiesSet)?; + .map_err(|_| ConsensusError::InvalidAuthoritiesSet)?; }, } runtime_api .authorities(parent_hash) .ok() - .ok_or(sp_consensus::Error::InvalidAuthoritiesSet) + .ok_or(ConsensusError::InvalidAuthoritiesSet) } #[cfg(test)] diff --git a/client/consensus/babe/rpc/src/lib.rs b/client/consensus/babe/rpc/src/lib.rs index 005d84938e28e..cdc8dbfd80a34 100644 --- a/client/consensus/babe/rpc/src/lib.rs +++ b/client/consensus/babe/rpc/src/lib.rs @@ -30,7 +30,7 @@ use sc_consensus_epochs::{descendent_query, Epoch as EpochT, SharedEpochChanges} use sc_rpc_api::DenyUnsafe; use serde::{Deserialize, Serialize}; use sp_api::ProvideRuntimeApi; -use sp_application_crypto::AppKey; +use sp_application_crypto::AppCrypto; use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata}; use sp_consensus::{Error as ConsensusError, SelectChain}; use sp_consensus_babe::{ diff --git a/client/consensus/babe/src/authorship.rs b/client/consensus/babe/src/authorship.rs index c4b43b0d074b9..3ff4c393ffd67 100644 --- a/client/consensus/babe/src/authorship.rs +++ b/client/consensus/babe/src/authorship.rs @@ -22,7 +22,7 @@ use super::Epoch; use codec::Encode; use sc_consensus_epochs::Epoch as EpochT; use schnorrkel::{keys::PublicKey, vrf::VRFInOut}; -use sp_application_crypto::AppKey; +use sp_application_crypto::AppCrypto; use sp_consensus_babe::{ digests::{PreDigest, PrimaryPreDigest, SecondaryPlainPreDigest, SecondaryVRFPreDigest}, make_transcript, make_transcript_data, AuthorityId, BabeAuthorityWeight, Slot, BABE_VRF_PREFIX, diff --git a/client/consensus/babe/src/lib.rs b/client/consensus/babe/src/lib.rs index e2c2793b11c9d..a59870ced0693 100644 --- a/client/consensus/babe/src/lib.rs +++ b/client/consensus/babe/src/lib.rs @@ -108,7 +108,7 @@ use sc_consensus_slots::{ }; use sc_telemetry::{telemetry, TelemetryHandle, CONSENSUS_DEBUG, CONSENSUS_TRACE}; use sp_api::{ApiExt, ProvideRuntimeApi}; -use sp_application_crypto::AppKey; +use sp_application_crypto::AppCrypto; use sp_block_builder::BlockBuilder as BlockBuilderApi; use sp_blockchain::{ Backend as _, BlockStatus, Error as ClientError, ForkBackend, HeaderBackend, HeaderMetadata, @@ -117,7 +117,7 @@ use sp_blockchain::{ use sp_consensus::{BlockOrigin, Environment, Error as ConsensusError, Proposer, SelectChain}; use sp_consensus_babe::inherents::BabeInherentData; use sp_consensus_slots::Slot; -use sp_core::{crypto::ByteArray, ExecutionContext}; +use sp_core::ExecutionContext; use sp_inherents::{CreateInherentDataProviders, InherentData, InherentDataProvider}; use sp_keystore::KeystorePtr; use sp_runtime::{ @@ -274,7 +274,7 @@ pub enum Error { MultipleConfigChangeDigests, /// Could not extract timestamp and slot #[error("Could not extract timestamp and slot: {0}")] - Extraction(sp_consensus::Error), + Extraction(ConsensusError), /// Could not fetch epoch #[error("Could not fetch epoch at {0:?}")] FetchEpoch(B::Hash), @@ -471,7 +471,7 @@ pub fn start_babe( max_block_proposal_slot_portion, telemetry, }: BabeParams, -) -> Result, sp_consensus::Error> +) -> Result, ConsensusError> where B: BlockT, C: ProvideRuntimeApi @@ -739,7 +739,7 @@ where type SyncOracle = SO; type JustificationSyncLink = L; type CreateProposer = - Pin> + Send + 'static>>; + Pin> + Send + 'static>>; type Proposer = E::Proposer; type BlockImport = I; type AuxData = ViableEpochDescriptor, Epoch>; @@ -762,7 +762,7 @@ where slot, ) .map_err(|e| ConsensusError::ChainLookup(e.to_string()))? - .ok_or(sp_consensus::Error::InvalidAuthoritiesSet) + .ok_or(ConsensusError::InvalidAuthoritiesSet) } fn authorities_len(&self, epoch_descriptor: &Self::AuxData) -> Option { @@ -827,28 +827,21 @@ where (_, public): Self::Claim, epoch_descriptor: Self::AuxData, ) -> Result< - sc_consensus::BlockImportParams>::Transaction>, - sp_consensus::Error, + BlockImportParams>::Transaction>, + ConsensusError, > { - // 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 = self .keystore - .sign_with(::ID, &public_type_pair, header_hash.as_ref()) - .map_err(|e| sp_consensus::Error::CannotSign(public.clone(), e.to_string()))? + .sr25519_sign(::ID, public.as_ref(), header_hash.as_ref()) + .map_err(|e| ConsensusError::CannotSign(format!("{}. Key: {:?}", e, public)))? .ok_or_else(|| { - sp_consensus::Error::CannotSign( - public.clone(), - "Could not find key in keystore.".into(), - ) + ConsensusError::CannotSign(format!( + "Could not find key in keystore. Key: {:?}", + public + )) })?; - let signature: AuthoritySignature = signature - .clone() - .try_into() - .map_err(|_| sp_consensus::Error::InvalidSignature(signature, public))?; - let digest_item = ::babe_seal(signature); + + let digest_item = ::babe_seal(signature.into()); let mut import_block = BlockImportParams::new(BlockOrigin::Own, header); import_block.post_digests.push(digest_item); @@ -891,11 +884,7 @@ 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))), - ) + Box::pin(self.env.init(block).map_err(|e| ConsensusError::ClientImport(e.to_string()))) } fn telemetry(&self) -> Option { @@ -1182,7 +1171,7 @@ where .create_inherent_data_providers .create_inherent_data_providers(parent_hash, ()) .await - .map_err(|e| Error::::Client(sp_consensus::Error::from(e).into()))?; + .map_err(|e| Error::::Client(ConsensusError::from(e).into()))?; let slot_now = create_inherent_data_providers.slot(); diff --git a/client/consensus/grandpa/src/lib.rs b/client/consensus/grandpa/src/lib.rs index cf98e17920d5d..90cb8a51fa6f4 100644 --- a/client/consensus/grandpa/src/lib.rs +++ b/client/consensus/grandpa/src/lib.rs @@ -72,7 +72,7 @@ use sc_network::types::ProtocolName; 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_application_crypto::AppCrypto; use sp_blockchain::{Error as ClientError, HeaderBackend, HeaderMetadata, Result as ClientResult}; use sp_consensus::SelectChain; use sp_consensus_grandpa::{ diff --git a/client/consensus/slots/src/lib.rs b/client/consensus/slots/src/lib.rs index f1d817ab7d8cf..e4147340793a4 100644 --- a/client/consensus/slots/src/lib.rs +++ b/client/consensus/slots/src/lib.rs @@ -150,7 +150,7 @@ pub trait SimpleSlotWorker { body: Vec, storage_changes: StorageChanges<>::Transaction, B>, public: Self::Claim, - epoch: Self::AuxData, + aux_data: Self::AuxData, ) -> Result< sc_consensus::BlockImportParams>::Transaction>, sp_consensus::Error, diff --git a/client/keystore/src/local.rs b/client/keystore/src/local.rs index a4af7811721ce..abdf97bb22aad 100644 --- a/client/keystore/src/local.rs +++ b/client/keystore/src/local.rs @@ -18,13 +18,10 @@ //! Local keystore implementation use parking_lot::RwLock; -use sp_application_crypto::{ecdsa, ed25519, sr25519, AppKey, AppPair, IsWrappedBy}; +use sp_application_crypto::{AppCrypto, AppPair, IsWrappedBy}; use sp_core::{ - crypto::{ - ByteArray, CryptoTypePublicPair, ExposeSecret, KeyTypeId, Pair as PairT, SecretString, - }, - sr25519::{Pair as Sr25519Pair, Public as Sr25519Public}, - Encode, + crypto::{ByteArray, ExposeSecret, KeyTypeId, Pair as CorePair, SecretString}, + ecdsa, ed25519, sr25519, }; use sp_keystore::{ vrf::{make_transcript, VRFSignature, VRFTranscriptData}, @@ -62,67 +59,13 @@ impl LocalKeystore { /// `Err(_)` when something failed. pub fn key_pair( &self, - public: &::Public, + public: &::Public, ) -> Result> { self.0.read().key_pair::(public) } } impl Keystore for LocalKeystore { - fn keys(&self, id: KeyTypeId) -> std::result::Result, TraitError> { - let raw_keys = self.0.read().raw_public_keys(id)?; - Ok(raw_keys.into_iter().fold(Vec::new(), |mut v, k| { - v.push(CryptoTypePublicPair(sr25519::CRYPTO_ID, k.clone())); - v.push(CryptoTypePublicPair(ed25519::CRYPTO_ID, k.clone())); - v.push(CryptoTypePublicPair(ecdsa::CRYPTO_ID, k)); - v - })) - } - - fn sign_with( - &self, - id: KeyTypeId, - key: &CryptoTypePublicPair, - msg: &[u8], - ) -> std::result::Result>, TraitError> { - match key.0 { - ed25519::CRYPTO_ID => { - 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() - .key_pair_by_type::(&pub_key, id) - .map_err(TraitError::from)?; - 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()).map_err(|()| { - TraitError::Other("Corrupted public key - Invalid size".into()) - })?; - let key_pair = self - .0 - .read() - .key_pair_by_type::(&pub_key, id) - .map_err(TraitError::from)?; - 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()).map_err(|()| { - TraitError::Other("Corrupted public key - Invalid size".into()) - })?; - let key_pair = self - .0 - .read() - .key_pair_by_type::(&pub_key, id) - .map_err(TraitError::from)?; - key_pair.map(|k| k.sign(msg).encode()).map(Ok).transpose() - }, - _ => Err(TraitError::KeyNotSupported(id)), - } - } - fn sr25519_public_keys(&self, key_type: KeyTypeId) -> Vec { self.0 .read() @@ -140,19 +83,49 @@ impl Keystore for LocalKeystore { /// If the `[seed]` is `Some` then the key will be ephemeral and stored in memory. fn sr25519_generate_new( &self, - id: KeyTypeId, + key_type: KeyTypeId, seed: Option<&str>, ) -> std::result::Result { let pair = match seed { - Some(seed) => - self.0.write().insert_ephemeral_from_seed_by_type::(seed, id), - None => self.0.write().generate_by_type::(id), + Some(seed) => self + .0 + .write() + .insert_ephemeral_from_seed_by_type::(seed, key_type), + None => self.0.write().generate_by_type::(key_type), } .map_err(|e| -> TraitError { e.into() })?; Ok(pair.public()) } + fn sr25519_sign( + &self, + key_type: KeyTypeId, + public: &sr25519::Public, + msg: &[u8], + ) -> std::result::Result, TraitError> { + let res = self + .0 + .read() + .key_pair_by_type::(public, key_type)? + .map(|pair| pair.sign(msg)); + Ok(res) + } + + fn sr25519_vrf_sign( + &self, + key_type: KeyTypeId, + public: &sr25519::Public, + transcript_data: VRFTranscriptData, + ) -> std::result::Result, TraitError> { + let res = self.0.read().key_pair_by_type::(public, key_type)?.map(|pair| { + let transcript = make_transcript(transcript_data); + let (inout, proof, _) = pair.as_ref().vrf_sign(transcript); + VRFSignature { output: inout.to_output(), proof } + }); + Ok(res) + } + fn ed25519_public_keys(&self, key_type: KeyTypeId) -> Vec { self.0 .read() @@ -170,19 +143,35 @@ impl Keystore for LocalKeystore { /// If the `[seed]` is `Some` then the key will be ephemeral and stored in memory. fn ed25519_generate_new( &self, - id: KeyTypeId, + key_type: KeyTypeId, seed: Option<&str>, ) -> std::result::Result { let pair = match seed { - Some(seed) => - self.0.write().insert_ephemeral_from_seed_by_type::(seed, id), - None => self.0.write().generate_by_type::(id), + Some(seed) => self + .0 + .write() + .insert_ephemeral_from_seed_by_type::(seed, key_type), + None => self.0.write().generate_by_type::(key_type), } .map_err(|e| -> TraitError { e.into() })?; Ok(pair.public()) } + fn ed25519_sign( + &self, + key_type: KeyTypeId, + public: &ed25519::Public, + msg: &[u8], + ) -> std::result::Result, TraitError> { + let res = self + .0 + .read() + .key_pair_by_type::(public, key_type)? + .map(|pair| pair.sign(msg)); + Ok(res) + } + fn ecdsa_public_keys(&self, key_type: KeyTypeId) -> Vec { self.0 .read() @@ -200,19 +189,47 @@ impl Keystore for LocalKeystore { /// If the `[seed]` is `Some` then the key will be ephemeral and stored in memory. fn ecdsa_generate_new( &self, - id: KeyTypeId, + key_type: KeyTypeId, seed: Option<&str>, ) -> std::result::Result { let pair = match seed { Some(seed) => - self.0.write().insert_ephemeral_from_seed_by_type::(seed, id), - None => self.0.write().generate_by_type::(id), + self.0.write().insert_ephemeral_from_seed_by_type::(seed, key_type), + None => self.0.write().generate_by_type::(key_type), } .map_err(|e| -> TraitError { e.into() })?; Ok(pair.public()) } + fn ecdsa_sign( + &self, + key_type: KeyTypeId, + public: &ecdsa::Public, + msg: &[u8], + ) -> std::result::Result, TraitError> { + let res = self + .0 + .read() + .key_pair_by_type::(public, key_type)? + .map(|pair| pair.sign(msg)); + Ok(res) + } + + fn ecdsa_sign_prehashed( + &self, + key_type: KeyTypeId, + public: &ecdsa::Public, + msg: &[u8; 32], + ) -> std::result::Result, TraitError> { + let res = self + .0 + .read() + .key_pair_by_type::(public, key_type)? + .map(|pair| pair.sign_prehashed(msg)); + Ok(res) + } + fn insert( &self, key_type: KeyTypeId, @@ -222,39 +239,15 @@ impl Keystore for LocalKeystore { self.0.write().insert(key_type, suri, public).map_err(|_| ()) } + fn keys(&self, key_type: KeyTypeId) -> std::result::Result>, TraitError> { + self.0.read().raw_public_keys(key_type).map_err(|e| e.into()) + } + fn has_keys(&self, public_keys: &[(Vec, KeyTypeId)]) -> bool { public_keys .iter() .all(|(p, t)| self.0.read().key_phrase_by_type(p, *t).ok().flatten().is_some()) } - - fn sr25519_vrf_sign( - &self, - key_type: KeyTypeId, - public: &Sr25519Public, - transcript_data: VRFTranscriptData, - ) -> std::result::Result, TraitError> { - let transcript = make_transcript(transcript_data); - let pair = self.0.read().key_pair_by_type::(public, key_type)?; - - if let Some(pair) = pair { - let (inout, proof, _) = pair.as_ref().vrf_sign(transcript); - Ok(Some(VRFSignature { output: inout.to_output(), proof })) - } else { - Ok(None) - } - } - - fn ecdsa_sign_prehashed( - &self, - id: KeyTypeId, - public: &ecdsa::Public, - msg: &[u8; 32], - ) -> std::result::Result, TraitError> { - let pair = self.0.read().key_pair_by_type::(public, id)?; - - pair.map(|k| k.sign_prehashed(msg)).map(Ok).transpose() - } } impl Into for LocalKeystore { @@ -305,7 +298,12 @@ impl KeystoreInner { /// Insert the given public/private key pair with the given key type. /// /// Does not place it into the file system store. - fn insert_ephemeral_pair(&mut self, pair: &Pair, seed: &str, key_type: KeyTypeId) { + fn insert_ephemeral_pair( + &mut self, + pair: &Pair, + seed: &str, + key_type: KeyTypeId, + ) { let key = (key_type, pair.public().to_raw_vec()); self.additional.insert(key, seed.into()); } @@ -325,7 +323,7 @@ impl KeystoreInner { /// /// Places it into the file system store, if a path is configured. Otherwise insert /// it into the memory cache only. - fn generate_by_type(&mut self, key_type: KeyTypeId) -> Result { + 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) { Self::write_to_file(path, &phrase)?; @@ -354,7 +352,7 @@ impl KeystoreInner { /// Create a new key from seed. /// /// Does not place it into the file system store. - fn insert_ephemeral_from_seed_by_type( + fn insert_ephemeral_from_seed_by_type( &mut self, seed: &str, key_type: KeyTypeId, @@ -386,7 +384,7 @@ impl KeystoreInner { } /// Get a key pair for the given public key and key type. - fn key_pair_by_type( + fn key_pair_by_type( &self, public: &Pair::Public, key_type: KeyTypeId, @@ -418,12 +416,12 @@ impl KeystoreInner { } /// Returns a list of raw public keys filtered by `KeyTypeId` - fn raw_public_keys(&self, id: KeyTypeId) -> Result>> { + fn raw_public_keys(&self, key_type: KeyTypeId) -> Result>> { let mut public_keys: Vec> = self .additional .keys() .into_iter() - .filter_map(|k| if k.0 == id { Some(k.1.clone()) } else { None }) + .filter_map(|k| if k.0 == key_type { Some(k.1.clone()) } else { None }) .collect(); if let Some(path) = &self.path { @@ -435,7 +433,7 @@ impl KeystoreInner { if let Some(name) = path.file_name().and_then(|n| n.to_str()) { match array_bytes::hex2bytes(name) { Ok(ref hex) if hex.len() > 4 => { - if hex[0..4] != id.0 { + if hex[0..4] != key_type.0 { continue } let public = hex[4..].to_vec(); @@ -456,7 +454,7 @@ impl KeystoreInner { /// when something failed. pub fn key_pair( &self, - public: &::Public, + public: &::Public, ) -> Result> { self.key_pair_by_type::(IsWrappedBy::from_ref(public), Pair::ID) .map(|v| v.map(Into::into)) diff --git a/client/rpc/src/author/tests.rs b/client/rpc/src/author/tests.rs index 75b6390c83cc7..fbbd1a92fdaa7 100644 --- a/client/rpc/src/author/tests.rs +++ b/client/rpc/src/author/tests.rs @@ -31,8 +31,8 @@ use sc_transaction_pool_api::TransactionStatus; use sp_core::{ blake2_256, bytes::to_hex, - crypto::{ByteArray, CryptoTypePublicPair, Pair}, - ed25519, sr25519, + crypto::{ByteArray, Pair}, + ed25519, testing::{ED25519, SR25519}, H256, }; @@ -227,9 +227,7 @@ async fn author_should_insert_key() { api.call::<_, ()>("author_insertKey", params).await.unwrap(); let pubkeys = setup.keystore.keys(ED25519).unwrap(); - assert!( - pubkeys.contains(&CryptoTypePublicPair(ed25519::CRYPTO_ID, keypair.public().to_raw_vec())) - ); + assert!(pubkeys.contains(&keypair.public().to_raw_vec())); } #[tokio::test] @@ -242,10 +240,8 @@ async fn author_should_rotate_keys() { SessionKeys::decode(&mut &new_pubkeys[..]).expect("SessionKeys decode successfully"); let ed25519_pubkeys = setup.keystore.keys(ED25519).unwrap(); let sr25519_pubkeys = setup.keystore.keys(SR25519).unwrap(); - assert!(ed25519_pubkeys - .contains(&CryptoTypePublicPair(ed25519::CRYPTO_ID, session_keys.ed25519.to_raw_vec()))); - assert!(sr25519_pubkeys - .contains(&CryptoTypePublicPair(sr25519::CRYPTO_ID, session_keys.sr25519.to_raw_vec()))); + assert!(ed25519_pubkeys.contains(&session_keys.ed25519.to_raw_vec())); + assert!(sr25519_pubkeys.contains(&session_keys.sr25519.to_raw_vec())); } #[tokio::test] diff --git a/primitives/application-crypto/src/lib.rs b/primitives/application-crypto/src/lib.rs index 0685477ddff8d..bf738813333be 100644 --- a/primitives/application-crypto/src/lib.rs +++ b/primitives/application-crypto/src/lib.rs @@ -27,10 +27,7 @@ pub use sp_core::crypto::{DeriveError, DeriveJunction, Pair, SecretStringError, #[doc(hidden)] pub use sp_core::{ self, - crypto::{ - ByteArray, CryptoType, CryptoTypePublicPair, Derive, IsWrappedBy, Public, UncheckedFrom, - Wraps, - }, + crypto::{ByteArray, CryptoType, Derive, IsWrappedBy, Public, UncheckedFrom, Wraps}, RuntimeDebug, }; @@ -170,8 +167,7 @@ macro_rules! app_crypto_pair { } } - impl $crate::AppKey for Pair { - type UntypedGeneric = $pair; + impl $crate::AppCrypto for Pair { type Public = Public; type Pair = Pair; type Signature = Signature; @@ -238,8 +234,7 @@ macro_rules! app_crypto_public_full_crypto { type Pair = Pair; } - impl $crate::AppKey for Public { - type UntypedGeneric = $public; + impl $crate::AppCrypto for Public { type Public = Public; type Pair = Pair; type Signature = Signature; @@ -272,8 +267,7 @@ macro_rules! app_crypto_public_not_full_crypto { impl $crate::CryptoType for Public {} - impl $crate::AppKey for Public { - type UntypedGeneric = $public; + impl $crate::AppCrypto for Public { type Public = Public; type Signature = Signature; const ID: $crate::KeyTypeId = $key_type; @@ -306,11 +300,8 @@ macro_rules! app_crypto_public_common { impl $crate::ByteArray for Public { const LEN: usize = <$public>::LEN; } - impl $crate::Public for Public { - fn to_public_crypto_pair(&self) -> $crate::CryptoTypePublicPair { - $crate::CryptoTypePublicPair($crypto_type, $crate::ByteArray::to_raw_vec(self)) - } - } + + impl $crate::Public for Public {} impl $crate::AppPublic for Public { type Generic = $public; @@ -350,18 +341,6 @@ macro_rules! app_crypto_public_common { } } - impl From for $crate::CryptoTypePublicPair { - fn from(key: Public) -> Self { - (&key).into() - } - } - - impl From<&Public> for $crate::CryptoTypePublicPair { - fn from(key: &Public) -> Self { - $crate::CryptoTypePublicPair($crypto_type, $crate::ByteArray::to_raw_vec(key)) - } - } - impl<'a> TryFrom<&'a [u8]> for Public { type Error = (); @@ -450,8 +429,7 @@ macro_rules! app_crypto_signature_full_crypto { type Pair = Pair; } - impl $crate::AppKey for Signature { - type UntypedGeneric = $sig; + impl $crate::AppCrypto for Signature { type Public = Public; type Pair = Pair; type Signature = Signature; @@ -482,8 +460,7 @@ macro_rules! app_crypto_signature_not_full_crypto { impl $crate::CryptoType for Signature {} - impl $crate::AppKey for Signature { - type UntypedGeneric = $sig; + impl $crate::AppCrypto for Signature { type Public = Public; type Signature = Signature; const ID: $crate::KeyTypeId = $key_type; diff --git a/primitives/application-crypto/src/traits.rs b/primitives/application-crypto/src/traits.rs index e3586ccecd0d8..f672efb8a890a 100644 --- a/primitives/application-crypto/src/traits.rs +++ b/primitives/application-crypto/src/traits.rs @@ -23,24 +23,22 @@ use sp_core::crypto::{CryptoType, CryptoTypeId, IsWrappedBy, KeyTypeId, Public}; use sp_std::{fmt::Debug, vec::Vec}; /// An application-specific key. -pub trait AppKey: 'static + Send + Sync + Sized + CryptoType + Clone { - /// The corresponding type as a generic crypto type. - type UntypedGeneric: IsWrappedBy; +pub trait AppCrypto: 'static + Send + Sync + Sized + CryptoType + Clone { + /// Identifier for application-specific key type. + const ID: KeyTypeId; + + /// Identifier of the crypto type of this application-specific key type. + const CRYPTO_ID: CryptoTypeId; /// The corresponding public key type in this application scheme. type Public: AppPublic; - /// The corresponding key pair type in this application scheme. - #[cfg(feature = "full_crypto")] - type Pair: AppPair; - /// The corresponding signature type in this application scheme. type Signature: AppSignature; - /// An identifier for this application-specific key type. - const ID: KeyTypeId; - /// The identifier of the crypto type of this application-specific key type. - const CRYPTO_ID: CryptoTypeId; + /// The corresponding key pair type in this application scheme. + #[cfg(feature = "full_crypto")] + type Pair: AppPair; } /// Type which implements Hash in std, not when no-std (std variant). @@ -63,7 +61,7 @@ impl MaybeDebugHash for T {} /// A application's public key. pub trait AppPublic: - AppKey + Public + Ord + PartialOrd + Eq + PartialEq + Debug + MaybeHash + codec::Codec + AppCrypto + Public + Ord + PartialOrd + Eq + PartialEq + Debug + MaybeHash + codec::Codec { /// The wrapped type which is just a plain instance of `Public`. type Generic: IsWrappedBy @@ -79,14 +77,15 @@ pub trait AppPublic: /// A application's key pair. #[cfg(feature = "full_crypto")] -pub trait AppPair: AppKey + Pair::Public> { +pub trait AppPair: AppCrypto + Pair::Public> { /// The wrapped type which is just a plain instance of `Pair`. type Generic: IsWrappedBy - + Pair::Public as AppPublic>::Generic>; + + Pair::Public as AppPublic>::Generic> + + Pair::Signature as AppSignature>::Generic>; } /// A application's signature. -pub trait AppSignature: AppKey + Eq + PartialEq + Debug + MaybeHash { +pub trait AppSignature: AppCrypto + Eq + PartialEq + Debug + MaybeHash { /// The wrapped type which is just a plain instance of `Signature`. type Generic: IsWrappedBy + Eq + PartialEq + Debug + MaybeHash; } diff --git a/primitives/application-crypto/test/src/ecdsa.rs b/primitives/application-crypto/test/src/ecdsa.rs index fe9e17a65b1a7..99ca6f4c4adf2 100644 --- a/primitives/application-crypto/test/src/ecdsa.rs +++ b/primitives/application-crypto/test/src/ecdsa.rs @@ -17,8 +17,11 @@ //! Integration tests for ecdsa use sp_api::ProvideRuntimeApi; -use sp_application_crypto::ecdsa::{AppPair, AppPublic}; -use sp_core::{crypto::Pair, testing::ECDSA}; +use sp_application_crypto::ecdsa::AppPair; +use sp_core::{ + crypto::{ByteArray, Pair}, + testing::ECDSA, +}; use sp_keystore::{testing::MemoryKeystore, Keystore}; use std::sync::Arc; use substrate_test_runtime_client::{ @@ -35,6 +38,6 @@ fn ecdsa_works_in_runtime() { .expect("Tests `ecdsa` crypto."); let supported_keys = keystore.keys(ECDSA).unwrap(); - assert!(supported_keys.contains(&public.clone().into())); - assert!(AppPair::verify(&signature, "ecdsa", &AppPublic::from(public))); + assert!(supported_keys.contains(&public.to_raw_vec())); + assert!(AppPair::verify(&signature, "ecdsa", &public)); } diff --git a/primitives/application-crypto/test/src/ed25519.rs b/primitives/application-crypto/test/src/ed25519.rs index 5687bd013970a..f4553f95bf1f8 100644 --- a/primitives/application-crypto/test/src/ed25519.rs +++ b/primitives/application-crypto/test/src/ed25519.rs @@ -18,8 +18,11 @@ //! Integration tests for ed25519 use sp_api::ProvideRuntimeApi; -use sp_application_crypto::ed25519::{AppPair, AppPublic}; -use sp_core::{crypto::Pair, testing::ED25519}; +use sp_application_crypto::ed25519::AppPair; +use sp_core::{ + crypto::{ByteArray, Pair}, + testing::ED25519, +}; use sp_keystore::{testing::MemoryKeystore, Keystore}; use std::sync::Arc; use substrate_test_runtime_client::{ @@ -36,6 +39,6 @@ fn ed25519_works_in_runtime() { .expect("Tests `ed25519` crypto."); let supported_keys = keystore.keys(ED25519).unwrap(); - assert!(supported_keys.contains(&public.clone().into())); - assert!(AppPair::verify(&signature, "ed25519", &AppPublic::from(public))); + assert!(supported_keys.contains(&public.to_raw_vec())); + assert!(AppPair::verify(&signature, "ed25519", &public)); } diff --git a/primitives/application-crypto/test/src/sr25519.rs b/primitives/application-crypto/test/src/sr25519.rs index 92886b80cbfb3..736521d7d9f3a 100644 --- a/primitives/application-crypto/test/src/sr25519.rs +++ b/primitives/application-crypto/test/src/sr25519.rs @@ -18,8 +18,11 @@ //! Integration tests for sr25519 use sp_api::ProvideRuntimeApi; -use sp_application_crypto::sr25519::{AppPair, AppPublic}; -use sp_core::{crypto::Pair, testing::SR25519}; +use sp_application_crypto::sr25519::AppPair; +use sp_core::{ + crypto::{ByteArray, Pair}, + testing::SR25519, +}; use sp_keystore::{testing::MemoryKeystore, Keystore}; use std::sync::Arc; use substrate_test_runtime_client::{ @@ -36,6 +39,6 @@ fn sr25519_works_in_runtime() { .expect("Tests `sr25519` crypto."); let supported_keys = keystore.keys(SR25519).unwrap(); - assert!(supported_keys.contains(&public.clone().into())); - assert!(AppPair::verify(&signature, "sr25519", &AppPublic::from(public))); + assert!(supported_keys.contains(&public.to_raw_vec())); + assert!(AppPair::verify(&signature, "sr25519", &public)); } diff --git a/primitives/consensus/common/src/error.rs b/primitives/consensus/common/src/error.rs index e881259da11e4..fb8d0447fe3d6 100644 --- a/primitives/consensus/common/src/error.rs +++ b/primitives/consensus/common/src/error.rs @@ -48,8 +48,8 @@ pub enum Error { #[error("Chain lookup failed: {0}")] ChainLookup(String), /// Signing failed. - #[error("Failed to sign using key: {0:?}. Reason: {1}")] - CannotSign(Vec, String), + #[error("Failed to sign: {0}")] + CannotSign(String), /// Some other error. #[error(transparent)] Other(#[from] Box), diff --git a/primitives/consensus/grandpa/src/lib.rs b/primitives/consensus/grandpa/src/lib.rs index 7f5857e4ba26a..728ce3092888b 100644 --- a/primitives/consensus/grandpa/src/lib.rs +++ b/primitives/consensus/grandpa/src/lib.rs @@ -451,12 +451,11 @@ where H: Encode, N: Encode, { - use sp_application_crypto::AppKey; - use sp_core::crypto::Public; + use sp_application_crypto::AppCrypto; let encoded = localized_payload(round, set_id, &message); let signature = keystore - .sign_with(AuthorityId::ID, &public.to_public_crypto_pair(), &encoded[..]) + .ed25519_sign(AuthorityId::ID, public.as_ref(), &encoded[..]) .ok() .flatten()? .try_into() diff --git a/primitives/core/src/crypto.rs b/primitives/core/src/crypto.rs index 80e65b342cbd7..2e60ac2370a16 100644 --- a/primitives/core/src/crypto.rs +++ b/primitives/core/src/crypto.rs @@ -19,8 +19,6 @@ //! Cryptographic utilities. // end::description[] -#[cfg(feature = "std")] -use crate::hexdisplay::HexDisplay; use crate::{ed25519, sr25519}; #[cfg(feature = "std")] use base58::{FromBase58, ToBase58}; @@ -487,10 +485,7 @@ pub trait ByteArray: AsRef<[u8]> + AsMut<[u8]> + for<'a> TryFrom<&'a [u8], Error } /// 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; -} +pub trait Public: ByteArray + Derive + CryptoType + PartialEq + Eq + Clone + Send + Sync {} /// An opaque 32-byte cryptographic identifier. #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, MaxEncodedLen, TypeInfo)] @@ -689,11 +684,7 @@ mod dummy { b"" } } - impl Public for Dummy { - fn to_public_crypto_pair(&self) -> CryptoTypePublicPair { - CryptoTypePublicPair(CryptoTypeId(*b"dumm"), ::to_raw_vec(self)) - } - } + impl Public for Dummy {} impl Pair for Dummy { type Public = Dummy; @@ -1118,24 +1109,6 @@ impl<'a> TryFrom<&'a str> for KeyTypeId { #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] pub struct CryptoTypeId(pub [u8; 4]); -/// A type alias of CryptoTypeId & a public key -#[derive(Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Encode, Decode)] -#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] -pub struct CryptoTypePublicPair(pub CryptoTypeId, pub Vec); - -#[cfg(feature = "std")] -impl sp_std::fmt::Display for CryptoTypePublicPair { - fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { - let id = match str::from_utf8(&(self.0).0[..]) { - Ok(id) => id.to_string(), - Err(_) => { - format!("{:#?}", self.0) - }, - }; - write!(f, "{}-{}", id, HexDisplay::from(&self.1)) - } -} - /// Known key types; this also functions as a global registry of key types for projects wishing to /// avoid collisions with each other. /// @@ -1223,11 +1196,7 @@ mod tests { vec![] } } - impl Public for TestPublic { - fn to_public_crypto_pair(&self) -> CryptoTypePublicPair { - CryptoTypePublicPair(CryptoTypeId(*b"dumm"), self.to_raw_vec()) - } - } + impl Public for TestPublic {} impl Pair for TestPair { type Public = TestPublic; type Seed = [u8; 8]; diff --git a/primitives/core/src/ecdsa.rs b/primitives/core/src/ecdsa.rs index e63b283d26ee3..8dc4a55130fd6 100644 --- a/primitives/core/src/ecdsa.rs +++ b/primitives/core/src/ecdsa.rs @@ -24,8 +24,7 @@ use sp_runtime_interface::pass_by::PassByInner; #[cfg(feature = "std")] use crate::crypto::Ss58Codec; use crate::crypto::{ - ByteArray, CryptoType, CryptoTypeId, CryptoTypePublicPair, Derive, Public as TraitPublic, - UncheckedFrom, + ByteArray, CryptoType, CryptoTypeId, Derive, Public as TraitPublic, UncheckedFrom, }; #[cfg(feature = "full_crypto")] use crate::{ @@ -103,23 +102,7 @@ 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()) - } -} - -impl From for CryptoTypePublicPair { - fn from(key: Public) -> Self { - (&key).into() - } -} - -impl From<&Public> for CryptoTypePublicPair { - fn from(key: &Public) -> Self { - CryptoTypePublicPair(CRYPTO_ID, key.to_raw_vec()) - } -} +impl TraitPublic for Public {} impl Derive for Public {} diff --git a/primitives/core/src/ed25519.rs b/primitives/core/src/ed25519.rs index 503c127a9e06b..884d29dc122e9 100644 --- a/primitives/core/src/ed25519.rs +++ b/primitives/core/src/ed25519.rs @@ -31,9 +31,7 @@ use scale_info::TypeInfo; #[cfg(feature = "std")] use crate::crypto::Ss58Codec; -use crate::crypto::{ - CryptoType, CryptoTypeId, CryptoTypePublicPair, Derive, Public as TraitPublic, UncheckedFrom, -}; +use crate::crypto::{CryptoType, CryptoTypeId, Derive, Public as TraitPublic, UncheckedFrom}; #[cfg(feature = "full_crypto")] use crate::crypto::{DeriveError, DeriveJunction, Pair as TraitPair, SecretStringError}; #[cfg(feature = "full_crypto")] @@ -355,26 +353,10 @@ 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()) - } -} +impl TraitPublic for Public {} impl Derive for Public {} -impl From for CryptoTypePublicPair { - fn from(key: Public) -> Self { - (&key).into() - } -} - -impl From<&Public> for CryptoTypePublicPair { - fn from(key: &Public) -> Self { - CryptoTypePublicPair(CRYPTO_ID, key.to_raw_vec()) - } -} - /// Derive a single hard junction. #[cfg(feature = "full_crypto")] fn derive_hard_junction(secret_seed: &Seed, cc: &[u8; 32]) -> Seed { diff --git a/primitives/core/src/sr25519.rs b/primitives/core/src/sr25519.rs index 8dbcca9e2673e..d7c1c79c3f42b 100644 --- a/primitives/core/src/sr25519.rs +++ b/primitives/core/src/sr25519.rs @@ -34,10 +34,7 @@ use schnorrkel::{ use sp_std::vec::Vec; use crate::{ - crypto::{ - ByteArray, CryptoType, CryptoTypeId, CryptoTypePublicPair, Derive, Public as TraitPublic, - UncheckedFrom, - }, + crypto::{ByteArray, CryptoType, CryptoTypeId, Derive, Public as TraitPublic, UncheckedFrom}, hash::{H256, H512}, }; use codec::{Decode, Encode, MaxEncodedLen}; @@ -386,23 +383,7 @@ 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()) - } -} - -impl From for CryptoTypePublicPair { - fn from(key: Public) -> Self { - (&key).into() - } -} - -impl From<&Public> for CryptoTypePublicPair { - fn from(key: &Public) -> Self { - CryptoTypePublicPair(CRYPTO_ID, key.to_raw_vec()) - } -} +impl TraitPublic for Public {} #[cfg(feature = "std")] impl From for Pair { diff --git a/primitives/io/src/lib.rs b/primitives/io/src/lib.rs index 709e1fa642f80..306ac8e60c529 100644 --- a/primitives/io/src/lib.rs +++ b/primitives/io/src/lib.rs @@ -762,10 +762,9 @@ pub trait Crypto { ) -> Option { self.extension::() .expect("No `keystore` associated for the current context!") - .sign_with(id, &pub_key.into(), msg) + .ed25519_sign(id, pub_key, msg) .ok() .flatten() - .and_then(|sig| ed25519::Signature::from_slice(&sig)) } /// Verify `ed25519` signature. @@ -902,10 +901,9 @@ pub trait Crypto { ) -> Option { self.extension::() .expect("No `keystore` associated for the current context!") - .sign_with(id, &pub_key.into(), msg) + .sr25519_sign(id, pub_key, msg) .ok() .flatten() - .and_then(|sig| sr25519::Signature::from_slice(&sig)) } /// Verify an `sr25519` signature. @@ -949,10 +947,9 @@ pub trait Crypto { ) -> Option { self.extension::() .expect("No `keystore` associated for the current context!") - .sign_with(id, &pub_key.into(), msg) + .ecdsa_sign(id, pub_key, msg) .ok() .flatten() - .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 diff --git a/primitives/keystore/src/lib.rs b/primitives/keystore/src/lib.rs index d1cbe227ed551..577969cdfecd8 100644 --- a/primitives/keystore/src/lib.rs +++ b/primitives/keystore/src/lib.rs @@ -21,7 +21,7 @@ pub mod vrf; use crate::vrf::{VRFSignature, VRFTranscriptData}; use sp_core::{ - crypto::{CryptoTypePublicPair, KeyTypeId}, + crypto::{ByteArray, CryptoTypeId, KeyTypeId}, ecdsa, ed25519, sr25519, }; use std::sync::Arc; @@ -45,109 +45,174 @@ pub enum Error { /// Something that generates, stores and provides access to secret keys. pub trait Keystore: Send + Sync { - /// Returns all sr25519 public keys for the given key type. - fn sr25519_public_keys(&self, id: KeyTypeId) -> Vec; + /// Returns all the sr25519 public keys for the given key type. + fn sr25519_public_keys(&self, key_type: KeyTypeId) -> Vec; /// Generate a new sr25519 key pair for the given key type and an optional seed. /// - /// If the given seed is `Some(_)`, the key pair will only be stored in memory. - /// - /// Returns the public key of the generated key pair. + /// Returns an `sr25519::Public` key of the generated key pair or an `Err` if + /// something failed during key generation. fn sr25519_generate_new( &self, - id: KeyTypeId, + key_type: KeyTypeId, seed: Option<&str>, ) -> Result; + /// Generate an sr25519 signature for a given message. + /// + /// Receives [`KeyTypeId`] and an [`sr25519::Public`] key to be able to map + /// them to a private key that exists in the keystore. + /// + /// Returns an [`sr25519::Signature`] or `None` in case the given `key_type` + /// and `public` combination doesn't exist in the keystore. + /// An `Err` will be returned if generating the signature itself failed. + fn sr25519_sign( + &self, + key_type: KeyTypeId, + public: &sr25519::Public, + msg: &[u8], + ) -> Result, Error>; + + /// Generate an sr25519 VRF signature for a given transcript data. + /// + /// Receives [`KeyTypeId`] and an [`sr25519::Public`] key to be able to map + /// them to a private key that exists in the keystore. + /// + /// Returns a result containing the signature data. + /// Namely, VRFOutput and VRFProof which are returned inside the `VRFSignature` + /// container struct. + /// Returns `None` if the given `key_type` and `public` combination doesn't + /// exist in the keystore or an `Err` when something failed. + fn sr25519_vrf_sign( + &self, + key_type: KeyTypeId, + public: &sr25519::Public, + transcript_data: VRFTranscriptData, + ) -> Result, Error>; + /// Returns all ed25519 public keys for the given key type. - fn ed25519_public_keys(&self, id: KeyTypeId) -> Vec; + fn ed25519_public_keys(&self, key_type: KeyTypeId) -> Vec; /// Generate a new ed25519 key pair for the given key type and an optional seed. /// - /// If the given seed is `Some(_)`, the key pair will only be stored in memory. - /// - /// Returns the public key of the generated key pair. + /// Returns an `ed25519::Public` key of the generated key pair or an `Err` if + /// something failed during key generation. fn ed25519_generate_new( &self, - id: KeyTypeId, + key_type: KeyTypeId, seed: Option<&str>, ) -> Result; + /// Generate an ed25519 signature for a given message. + /// + /// Receives [`KeyTypeId`] and an [`ed25519::Public`] key to be able to map + /// them to a private key that exists in the keystore. + /// + /// Returns an [`ed25519::Signature`] or `None` in case the given `key_type` + /// and `public` combination doesn't exist in the keystore. + /// An `Err` will be returned if generating the signature itself failed. + fn ed25519_sign( + &self, + key_type: KeyTypeId, + public: &ed25519::Public, + msg: &[u8], + ) -> Result, Error>; + /// Returns all ecdsa public keys for the given key type. - fn ecdsa_public_keys(&self, id: KeyTypeId) -> Vec; + fn ecdsa_public_keys(&self, key_type: KeyTypeId) -> Vec; /// Generate a new ecdsa key pair for the given key type and an optional seed. /// - /// If the given seed is `Some(_)`, the key pair will only be stored in memory. + /// Returns an `ecdsa::Public` key of the generated key pair or an `Err` if + /// something failed during key generation. + fn ecdsa_generate_new( + &self, + key_type: KeyTypeId, + seed: Option<&str>, + ) -> Result; + + /// Generate an ecdsa signature for a given message. + /// + /// Receives [`KeyTypeId`] and an [`ecdsa::Public`] key to be able to map + /// them to a private key that exists in the keystore. + /// + /// Returns an [`ecdsa::Signature`] or `None` in case the given `key_type` + /// and `public` combination doesn't exist in the keystore. + /// An `Err` will be returned if generating the signature itself failed. + fn ecdsa_sign( + &self, + key_type: KeyTypeId, + public: &ecdsa::Public, + msg: &[u8], + ) -> Result, Error>; + + /// Generate an ecdsa signature for a given pre-hashed message. + /// + /// Receives [`KeyTypeId`] and an [`ecdsa::Public`] key to be able to map + /// them to a private key that exists in the keystore. /// - /// Returns the public key of the generated key pair. - fn ecdsa_generate_new(&self, id: KeyTypeId, seed: Option<&str>) - -> Result; + /// Returns an [`ecdsa::Signature`] or `None` in case the given `key_type` + /// and `public` combination doesn't exist in the keystore. + /// An `Err` will be returned if generating the signature itself failed. + fn ecdsa_sign_prehashed( + &self, + key_type: KeyTypeId, + public: &ecdsa::Public, + msg: &[u8; 32], + ) -> Result, Error>; /// Insert a new secret key. fn insert(&self, key_type: KeyTypeId, suri: &str, public: &[u8]) -> Result<(), ()>; - /// List all supported keys + /// List all supported keys of a given type. /// - /// Returns a set of public keys the signer supports. - fn keys(&self, id: KeyTypeId) -> Result, Error>; + /// Returns a set of public keys the signer supports in raw format. + fn keys(&self, key_type: KeyTypeId) -> Result>, Error>; /// Checks if the private keys for the given public key and key type combinations exist. /// /// Returns `true` iff all private keys could be found. fn has_keys(&self, public_keys: &[(Vec, KeyTypeId)]) -> bool; - /// Sign with key + /// Convenience method to sign a message using the given key type and a raw public key + /// for secret lookup. /// - /// Signs a message with the private key that matches - /// the public key passed. + /// The message is signed using the cryptographic primitive specified by `crypto_id`. + /// + /// Schemes supported by the default trait implementation: sr25519, ed25519 and ecdsa. + /// To support more schemes you can overwrite this method. /// /// Returns the SCALE encoded signature if key is found and supported, `None` if the key doesn't /// exist or an error when something failed. fn sign_with( &self, id: KeyTypeId, - key: &CryptoTypePublicPair, + crypto_id: CryptoTypeId, + public: &[u8], msg: &[u8], - ) -> Result>, Error>; - - /// Generate VRF signature for given transcript data. - /// - /// Receives KeyTypeId and Public key to be able to map - /// them to a private key that exists in the keystore which - /// is, in turn, used for signing the provided transcript. - /// - /// Returns a result containing the signature data. - /// Namely, VRFOutput and VRFProof which are returned - /// inside the `VRFSignature` container struct. - /// - /// This function will return `None` if the given `key_type` and `public` combination - /// doesn't exist in the keystore or an `Err` when something failed. - fn sr25519_vrf_sign( - &self, - key_type: KeyTypeId, - public: &sr25519::Public, - transcript_data: VRFTranscriptData, - ) -> Result, Error>; - - /// Generate an ECDSA signature for a given pre-hashed message. - /// - /// Receives [`KeyTypeId`] and an [`ecdsa::Public`] key to be able to map - /// them to a private key that exists in the keystore. This private key is, - /// in turn, used for signing the provided pre-hashed message. - /// - /// The `msg` argument provided should be a hashed message for which an - /// ECDSA signature should be generated. - /// - /// Returns an [`ecdsa::Signature`] or `None` in case the given `id` and - /// `public` combination doesn't exist in the keystore. An `Err` will be - /// returned if generating the signature itself failed. - fn ecdsa_sign_prehashed( - &self, - id: KeyTypeId, - public: &ecdsa::Public, - msg: &[u8; 32], - ) -> Result, Error>; + ) -> Result>, Error> { + use codec::Encode; + + let signature = match crypto_id { + sr25519::CRYPTO_ID => { + let public = sr25519::Public::from_slice(public) + .map_err(|_| Error::ValidationError("Invalid public key format".into()))?; + self.sr25519_sign(id, &public, msg)?.map(|s| s.encode()) + }, + ed25519::CRYPTO_ID => { + let public = ed25519::Public::from_slice(public) + .map_err(|_| Error::ValidationError("Invalid public key format".into()))?; + self.ed25519_sign(id, &public, msg)?.map(|s| s.encode()) + }, + ecdsa::CRYPTO_ID => { + let public = ecdsa::Public::from_slice(public) + .map_err(|_| Error::ValidationError("Invalid public key format".into()))?; + self.ecdsa_sign(id, &public, msg)?.map(|s| s.encode()) + }, + _ => return Err(Error::KeyNotSupported(id)), + }; + Ok(signature) + } } /// A shared pointer to a keystore implementation. diff --git a/primitives/keystore/src/testing.rs b/primitives/keystore/src/testing.rs index 73b560d563a17..de034c65889ff 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::{ByteArray, CryptoTypePublicPair, KeyTypeId, Pair}, + crypto::{ByteArray, KeyTypeId, Pair}, ecdsa, ed25519, sr25519, }; @@ -42,51 +42,44 @@ impl MemoryKeystore { Self::default() } - fn sr25519_key_pair(&self, id: KeyTypeId, pub_key: &sr25519::Public) -> Option { - self.keys.read().get(&id).and_then(|inner| { - inner.get(pub_key.as_slice()).map(|s| { + fn sr25519_key_pair( + &self, + key_type: KeyTypeId, + public: &sr25519::Public, + ) -> Option { + self.keys.read().get(&key_type).and_then(|inner| { + inner.get(public.as_slice()).map(|s| { sr25519::Pair::from_string(s, None).expect("`sr25519` seed slice is valid") }) }) } - fn ed25519_key_pair(&self, id: KeyTypeId, pub_key: &ed25519::Public) -> Option { - self.keys.read().get(&id).and_then(|inner| { - inner.get(pub_key.as_slice()).map(|s| { + fn ed25519_key_pair( + &self, + key_type: KeyTypeId, + public: &ed25519::Public, + ) -> Option { + self.keys.read().get(&key_type).and_then(|inner| { + inner.get(public.as_slice()).map(|s| { ed25519::Pair::from_string(s, None).expect("`ed25519` seed slice is valid") }) }) } - fn ecdsa_key_pair(&self, id: KeyTypeId, pub_key: &ecdsa::Public) -> Option { - self.keys.read().get(&id).and_then(|inner| { + fn ecdsa_key_pair(&self, key_type: KeyTypeId, public: &ecdsa::Public) -> Option { + self.keys.read().get(&key_type).and_then(|inner| { inner - .get(pub_key.as_slice()) + .get(public.as_slice()) .map(|s| ecdsa::Pair::from_string(s, None).expect("`ecdsa` seed slice is valid")) }) } } impl Keystore for MemoryKeystore { - fn keys(&self, id: KeyTypeId) -> Result, Error> { - self.keys - .read() - .get(&id) - .map(|map| { - Ok(map.keys().fold(Vec::new(), |mut v, k| { - v.push(CryptoTypePublicPair(sr25519::CRYPTO_ID, k.clone())); - v.push(CryptoTypePublicPair(ed25519::CRYPTO_ID, k.clone())); - v.push(CryptoTypePublicPair(ecdsa::CRYPTO_ID, k.clone())); - v - })) - }) - .unwrap_or_else(|| Ok(vec![])) - } - - fn sr25519_public_keys(&self, id: KeyTypeId) -> Vec { + fn sr25519_public_keys(&self, key_type: KeyTypeId) -> Vec { self.keys .read() - .get(&id) + .get(&key_type) .map(|keys| { keys.values() .map(|s| { @@ -100,7 +93,7 @@ impl Keystore for MemoryKeystore { fn sr25519_generate_new( &self, - id: KeyTypeId, + key_type: KeyTypeId, seed: Option<&str>, ) -> Result { match seed { @@ -110,7 +103,7 @@ impl Keystore for MemoryKeystore { })?; self.keys .write() - .entry(id) + .entry(key_type) .or_default() .insert(pair.public().to_raw_vec(), seed.into()); Ok(pair.public()) @@ -119,7 +112,7 @@ impl Keystore for MemoryKeystore { let (pair, phrase, _) = sr25519::Pair::generate_with_phrase(None); self.keys .write() - .entry(id) + .entry(key_type) .or_default() .insert(pair.public().to_raw_vec(), phrase); Ok(pair.public()) @@ -127,10 +120,33 @@ impl Keystore for MemoryKeystore { } } - fn ed25519_public_keys(&self, id: KeyTypeId) -> Vec { + fn sr25519_sign( + &self, + key_type: KeyTypeId, + public: &sr25519::Public, + msg: &[u8], + ) -> Result, Error> { + Ok(self.sr25519_key_pair(key_type, public).map(|pair| pair.sign(msg))) + } + + fn sr25519_vrf_sign( + &self, + key_type: KeyTypeId, + public: &sr25519::Public, + transcript_data: VRFTranscriptData, + ) -> Result, Error> { + let transcript = make_transcript(transcript_data); + let pair = + if let Some(k) = self.sr25519_key_pair(key_type, public) { k } else { return Ok(None) }; + + let (inout, proof, _) = pair.as_ref().vrf_sign(transcript); + Ok(Some(VRFSignature { output: inout.to_output(), proof })) + } + + fn ed25519_public_keys(&self, key_type: KeyTypeId) -> Vec { self.keys .read() - .get(&id) + .get(&key_type) .map(|keys| { keys.values() .map(|s| { @@ -144,7 +160,7 @@ impl Keystore for MemoryKeystore { fn ed25519_generate_new( &self, - id: KeyTypeId, + key_type: KeyTypeId, seed: Option<&str>, ) -> Result { match seed { @@ -154,7 +170,7 @@ impl Keystore for MemoryKeystore { })?; self.keys .write() - .entry(id) + .entry(key_type) .or_default() .insert(pair.public().to_raw_vec(), seed.into()); Ok(pair.public()) @@ -163,7 +179,7 @@ impl Keystore for MemoryKeystore { let (pair, phrase, _) = ed25519::Pair::generate_with_phrase(None); self.keys .write() - .entry(id) + .entry(key_type) .or_default() .insert(pair.public().to_raw_vec(), phrase); Ok(pair.public()) @@ -171,10 +187,19 @@ impl Keystore for MemoryKeystore { } } - fn ecdsa_public_keys(&self, id: KeyTypeId) -> Vec { + fn ed25519_sign( + &self, + key_type: KeyTypeId, + public: &ed25519::Public, + msg: &[u8], + ) -> Result, Error> { + Ok(self.ed25519_key_pair(key_type, public).map(|pair| pair.sign(msg))) + } + + fn ecdsa_public_keys(&self, key_type: KeyTypeId) -> Vec { self.keys .read() - .get(&id) + .get(&key_type) .map(|keys| { keys.values() .map(|s| { @@ -188,7 +213,7 @@ impl Keystore for MemoryKeystore { fn ecdsa_generate_new( &self, - id: KeyTypeId, + key_type: KeyTypeId, seed: Option<&str>, ) -> Result { match seed { @@ -197,7 +222,7 @@ impl Keystore for MemoryKeystore { .map_err(|_| Error::ValidationError("Generates an `ecdsa` pair.".to_owned()))?; self.keys .write() - .entry(id) + .entry(key_type) .or_default() .insert(pair.public().to_raw_vec(), seed.into()); Ok(pair.public()) @@ -206,7 +231,7 @@ impl Keystore for MemoryKeystore { let (pair, phrase, _) = ecdsa::Pair::generate_with_phrase(None); self.keys .write() - .entry(id) + .entry(key_type) .or_default() .insert(pair.public().to_raw_vec(), phrase); Ok(pair.public()) @@ -214,75 +239,49 @@ impl Keystore for MemoryKeystore { } } - fn insert(&self, id: KeyTypeId, suri: &str, public: &[u8]) -> Result<(), ()> { + fn ecdsa_sign( + &self, + key_type: KeyTypeId, + public: &ecdsa::Public, + msg: &[u8], + ) -> Result, Error> { + Ok(self.ecdsa_key_pair(key_type, public).map(|pair| pair.sign(msg))) + } + + fn ecdsa_sign_prehashed( + &self, + key_type: KeyTypeId, + public: &ecdsa::Public, + msg: &[u8; 32], + ) -> Result, Error> { + let pair = self.ecdsa_key_pair(key_type, public); + pair.map(|pair| pair.sign_prehashed(msg)).map(Ok).transpose() + } + + fn insert(&self, key_type: KeyTypeId, suri: &str, public: &[u8]) -> Result<(), ()> { self.keys .write() - .entry(id) + .entry(key_type) .or_default() .insert(public.to_owned(), suri.to_string()); Ok(()) } + fn keys(&self, key_type: KeyTypeId) -> Result>, Error> { + let keys = self + .keys + .read() + .get(&key_type) + .map(|map| map.keys().cloned().collect()) + .unwrap_or_default(); + Ok(keys) + } + 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()) } - - fn sign_with( - &self, - id: KeyTypeId, - key: &CryptoTypePublicPair, - msg: &[u8], - ) -> Result>, Error> { - use codec::Encode; - - match key.0 { - ed25519::CRYPTO_ID => { - 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()).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()).unwrap()); - - key_pair.map(|k| k.sign(msg).encode()).map(Ok).transpose() - }, - _ => Err(Error::KeyNotSupported(id)), - } - } - - fn sr25519_vrf_sign( - &self, - key_type: KeyTypeId, - public: &sr25519::Public, - transcript_data: VRFTranscriptData, - ) -> Result, Error> { - let transcript = make_transcript(transcript_data); - let pair = - if let Some(k) = self.sr25519_key_pair(key_type, public) { k } else { return Ok(None) }; - - let (inout, proof, _) = pair.as_ref().vrf_sign(transcript); - Ok(Some(VRFSignature { output: inout.to_output(), proof })) - } - - fn ecdsa_sign_prehashed( - &self, - id: KeyTypeId, - public: &ecdsa::Public, - msg: &[u8; 32], - ) -> Result, Error> { - let pair = self.ecdsa_key_pair(id, public); - pair.map(|k| k.sign_prehashed(msg)).map(Ok).transpose() - } } impl Into for MemoryKeystore { @@ -306,7 +305,7 @@ mod tests { let public = store.ed25519_generate_new(ED25519, None).expect("Generates key"); - let public_keys = store.keys(ED25519).unwrap(); + let public_keys = store.ed25519_public_keys(ED25519); assert!(public_keys.contains(&public.into())); } @@ -322,7 +321,7 @@ mod tests { .insert(SR25519, secret_uri, key_pair.public().as_ref()) .expect("Inserts unknown key"); - let public_keys = store.keys(SR25519).unwrap(); + let public_keys = store.sr25519_public_keys(SR25519); assert!(public_keys.contains(&key_pair.public().into())); } diff --git a/primitives/runtime/src/traits.rs b/primitives/runtime/src/traits.rs index 4bba6f6bc1283..95f977077e704 100644 --- a/primitives/runtime/src/traits.rs +++ b/primitives/runtime/src/traits.rs @@ -30,7 +30,7 @@ use crate::{ use impl_trait_for_tuples::impl_for_tuples; #[cfg(feature = "std")] use serde::{de::DeserializeOwned, Deserialize, Serialize}; -use sp_application_crypto::AppKey; +use sp_application_crypto::AppCrypto; pub use sp_arithmetic::traits::{ checked_pow, ensure_pow, AtLeast32Bit, AtLeast32BitUnsigned, Bounded, CheckedAdd, CheckedDiv, CheckedMul, CheckedShl, CheckedShr, CheckedSub, Ensure, EnsureAdd, EnsureAddAssign, EnsureDiv, @@ -148,10 +148,10 @@ pub trait AppVerify { } impl< - S: Verify::Public as sp_application_crypto::AppPublic>::Generic> + S: Verify::Public as sp_application_crypto::AppPublic>::Generic> + From, T: sp_application_crypto::Wraps - + sp_application_crypto::AppKey + + sp_application_crypto::AppCrypto + sp_application_crypto::AppSignature + AsRef + AsMut @@ -159,16 +159,18 @@ impl< > AppVerify for T where ::Signer: IdentifyAccount::Signer>, - <::Public as sp_application_crypto::AppPublic>::Generic: IdentifyAccount< - AccountId = <::Public as sp_application_crypto::AppPublic>::Generic, + <::Public as sp_application_crypto::AppPublic>::Generic: IdentifyAccount< + AccountId = <::Public as sp_application_crypto::AppPublic>::Generic, >, { - type AccountId = ::Public; - fn verify>(&self, msg: L, signer: &::Public) -> bool { + type AccountId = ::Public; + fn verify>(&self, msg: L, signer: &::Public) -> bool { 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) } } From 656b139c24b660c9b3edd39e2418a0dd4a075cbd Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Fri, 24 Mar 2023 14:48:37 +0000 Subject: [PATCH 560/715] Use sensible maths for `from_rational` (#13660) * Use sensible maths for from_rational * Fixes * Fixes * More fixes * Remove debugging * Add fuzzer tests Signed-off-by: Oliver Tale-Yazdi * Prevent panics Signed-off-by: Oliver Tale-Yazdi * docs Signed-off-by: Oliver Tale-Yazdi * Clean up old code Signed-off-by: Oliver Tale-Yazdi * Test all rounding modes of from_rational Signed-off-by: Oliver Tale-Yazdi * Clean up code Signed-off-by: Oliver Tale-Yazdi * Revert "Prevent panics" This reverts commit 7e88ac76138a1b590e68b68318505b69efe1e1f6. * fix imports Signed-off-by: Oliver Tale-Yazdi * cleanup Signed-off-by: Oliver Tale-Yazdi * Fuzz test multiply_rational Signed-off-by: Oliver Tale-Yazdi * Fix import Signed-off-by: Oliver Tale-Yazdi * fmt Signed-off-by: Oliver Tale-Yazdi * Return None in multiply_rational on zero div Signed-off-by: Oliver Tale-Yazdi --------- Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Oliver Tale-Yazdi --- Cargo.lock | 42 ++++++- frame/staking/src/tests.rs | 8 +- primitives/arithmetic/fuzzer/Cargo.toml | 11 +- .../src/multiply_by_rational_with_rounding.rs | 99 +++++++++------ .../fuzzer/src/per_thing_from_rational.rs | 105 ++++++++++++++++ .../fuzzer/src/per_thing_mult_fraction.rs | 69 +++++++++++ .../fuzzer/src/per_thing_rational.rs | 116 ------------------ primitives/arithmetic/src/helpers_128bit.rs | 4 +- primitives/arithmetic/src/lib.rs | 2 +- primitives/arithmetic/src/per_things.rs | 89 ++++---------- primitives/arithmetic/src/rational.rs | 48 ++++++++ primitives/arithmetic/src/traits.rs | 6 +- 12 files changed, 372 insertions(+), 227 deletions(-) create mode 100644 primitives/arithmetic/fuzzer/src/per_thing_from_rational.rs create mode 100644 primitives/arithmetic/fuzzer/src/per_thing_mult_fraction.rs delete mode 100644 primitives/arithmetic/fuzzer/src/per_thing_rational.rs diff --git a/Cargo.lock b/Cargo.lock index a645ecec60d86..33bca4005483c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -220,9 +220,9 @@ dependencies = [ [[package]] name = "arbitrary" -version = "1.2.3" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e90af4de65aa7b293ef2d09daff88501eb254f58edde2e1ac02c82d873eadad" +checksum = "e2d098ff73c1ca148721f37baad5ea6a465a13f9573aba8641fbbbae8164a54e" [[package]] name = "arc-swap" @@ -2224,6 +2224,16 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fraction" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3027ae1df8d41b4bed2241c8fdad4acc1e7af60c8e17743534b545e77182d678" +dependencies = [ + "lazy_static", + "num", +] + [[package]] name = "fragile" version = "2.0.0" @@ -5286,6 +5296,20 @@ dependencies = [ "winapi", ] +[[package]] +name = "num" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + [[package]] name = "num-bigint" version = "0.4.3" @@ -5326,6 +5350,17 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-iter" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + [[package]] name = "num-rational" version = "0.4.1" @@ -10143,8 +10178,11 @@ dependencies = [ name = "sp-arithmetic-fuzzer" version = "2.0.0" dependencies = [ + "arbitrary", + "fraction", "honggfuzz", "num-bigint", + "num-traits", "primitive-types", "sp-arithmetic", ] diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 36cafcc1854db..d97eb3ef89cab 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -5461,7 +5461,7 @@ fn proportional_ledger_slash_works() { ledger.active = unit; ledger.total = unit * 4 + value; // When - assert_eq!(ledger.slash(slash, 0, 0), slash - 5); + assert_eq!(ledger.slash(slash, 0, 0), slash); // Then // The amount slashed out of `unit` let affected_balance = value + unit * 4; @@ -5477,12 +5477,12 @@ fn proportional_ledger_slash_works() { 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!(ledger.unlocking, vec![c(5, value_slashed), c(7, 32)]); + assert_eq!(ledger.total, value_slashed + 32); assert_eq!(LedgerSlashPerEra::get().0, 0); assert_eq!( LedgerSlashPerEra::get().1, - BTreeMap::from([(4, 0), (5, value_slashed), (6, 0), (7, 0)]) + BTreeMap::from([(4, 0), (5, value_slashed), (6, 0), (7, 32)]) ); } diff --git a/primitives/arithmetic/fuzzer/Cargo.toml b/primitives/arithmetic/fuzzer/Cargo.toml index 7be800a2e966c..99dbdf7487320 100644 --- a/primitives/arithmetic/fuzzer/Cargo.toml +++ b/primitives/arithmetic/fuzzer/Cargo.toml @@ -14,8 +14,11 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] +arbitrary = "1.3.0" +fraction = "0.13.1" honggfuzz = "0.5.49" num-bigint = "0.4.3" +num-traits = "0.2.15" primitive-types = "0.12.0" sp-arithmetic = { version = "6.0.0", path = ".." } @@ -28,8 +31,12 @@ name = "normalize" path = "src/normalize.rs" [[bin]] -name = "per_thing_rational" -path = "src/per_thing_rational.rs" +name = "per_thing_from_rational" +path = "src/per_thing_from_rational.rs" + +[[bin]] +name = "per_thing_mult_fraction" +path = "src/per_thing_mult_fraction.rs" [[bin]] name = "multiply_by_rational_with_rounding" diff --git a/primitives/arithmetic/fuzzer/src/multiply_by_rational_with_rounding.rs b/primitives/arithmetic/fuzzer/src/multiply_by_rational_with_rounding.rs index 13c9d022be6bd..e9a3208a738ef 100644 --- a/primitives/arithmetic/fuzzer/src/multiply_by_rational_with_rounding.rs +++ b/primitives/arithmetic/fuzzer/src/multiply_by_rational_with_rounding.rs @@ -29,52 +29,79 @@ //! More information about `honggfuzz` can be found //! [here](https://docs.rs/honggfuzz/). +use fraction::prelude::BigFraction as Fraction; use honggfuzz::fuzz; -use sp_arithmetic::{helpers_128bit::multiply_by_rational_with_rounding, traits::Zero, Rounding}; +use sp_arithmetic::{MultiplyRational, Rounding, Rounding::*}; +/// Tries to demonstrate that `multiply_by_rational_with_rounding` is incorrect. fn main() { loop { - fuzz!(|data: ([u8; 16], [u8; 16], [u8; 16])| { - let (a_bytes, b_bytes, c_bytes) = data; - let (a, b, c) = ( - u128::from_be_bytes(a_bytes), - u128::from_be_bytes(b_bytes), - u128::from_be_bytes(c_bytes), - ); + fuzz!(|data: (u128, u128, u128, ArbitraryRounding)| { + let (f, n, d, r) = (data.0, data.1, data.2, data.3 .0); - println!("++ Equation: {} * {} / {}", 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 { - println!("++ Expected {}", truth); - println!("+++++++ Got {}", result); - panic!(); - } - } + check::(f as u8, n as u8, d as u8, r); + check::(f as u16, n as u16, d as u16, r); + check::(f as u32, n as u32, d as u32, r); + check::(f as u64, n as u64, d as u64, r); + check::(f, n, d, r); }) } } -fn mul_div(a: u128, b: u128, c: u128) -> u128 { - use primitive_types::U256; - if a.is_zero() { - return Zero::zero() - } - let c = c.max(1); +fn check(f: N, n: N, d: N, r: Rounding) +where + N: MultiplyRational + Into + Copy + core::fmt::Debug, +{ + let Some(got) = f.multiply_rational(n, d, r) else { + return; + }; + + let (ae, be, ce) = + (Fraction::from(f.into()), Fraction::from(n.into()), Fraction::from(d.into())); + let want = round(ae * be / ce, r); - // e for extended - let ae: U256 = a.into(); - let be: U256 = b.into(); - let ce: U256 = c.into(); + assert_eq!( + Fraction::from(got.into()), + want, + "{:?} * {:?} / {:?} = {:?} != {:?}", + f, + n, + d, + got, + want + ); +} + +/// Round a `Fraction` according to the given mode. +fn round(f: Fraction, r: Rounding) -> Fraction { + match r { + Up => f.ceil(), + NearestPrefUp => + if f.fract() < Fraction::from(0.5) { + f.floor() + } else { + f.ceil() + }, + Down => f.floor(), + NearestPrefDown => + if f.fract() > Fraction::from(0.5) { + f.ceil() + } else { + f.floor() + }, + } +} - let r = ae * be / ce; - if r > u128::MAX.into() { - a - } else { - r.as_u128() +/// An [`arbitrary::Arbitrary`] [`Rounding`] mode. +struct ArbitraryRounding(Rounding); +impl arbitrary::Arbitrary<'_> for ArbitraryRounding { + fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result { + Ok(Self(match u.int_in_range(0..=3).unwrap() { + 0 => Up, + 1 => NearestPrefUp, + 2 => Down, + 3 => NearestPrefDown, + _ => unreachable!(), + })) } } diff --git a/primitives/arithmetic/fuzzer/src/per_thing_from_rational.rs b/primitives/arithmetic/fuzzer/src/per_thing_from_rational.rs new file mode 100644 index 0000000000000..93af4df9e8e55 --- /dev/null +++ b/primitives/arithmetic/fuzzer/src/per_thing_from_rational.rs @@ -0,0 +1,105 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT 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 per_thing_from_rational`. `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_from_rational hfuzz_workspace/per_thing_from_rational/*.fuzz`. + +use fraction::prelude::BigFraction as Fraction; +use honggfuzz::fuzz; +use sp_arithmetic::{ + traits::SaturatedConversion, PerThing, Perbill, Percent, Perquintill, Rounding::*, *, +}; + +/// Tries to demonstrate that `from_rational` is incorrect for any rounding modes. +/// +/// NOTE: This `Fraction` library is really slow. Using f128/f256 does not work for the large +/// numbers. But an optimization could be done do use either floats or Fraction depending on the +/// size of the inputs. +fn main() { + loop { + fuzz!(|data: (u128, u128, ArbitraryRounding)| { + let (n, d, r) = (data.0.min(data.1), data.0.max(data.1).max(1), data.2); + + check::(n, d, r.0); + check::(n, d, r.0); + check::(n, d, r.0); + check::(n, d, r.0); + check::(n, d, r.0); + }) + } +} + +/// Assert that the parts of `from_rational` are correct for the given rounding mode. +fn check(a: u128, b: u128, r: Rounding) +where + Per::Inner: Into, +{ + let approx_ratio = Per::from_rational_with_rounding(a, b, r).unwrap(); + let approx_parts = Fraction::from(approx_ratio.deconstruct().saturated_into::()); + + let perfect_ratio = if a == 0 && b == 0 { + Fraction::from(1) + } else { + Fraction::from(a) / Fraction::from(b.max(1)) + }; + let perfect_parts = round(perfect_ratio * Fraction::from(Per::ACCURACY.into()), r); + + assert_eq!( + approx_parts, perfect_parts, + "approx_parts: {}, perfect_parts: {}, a: {}, b: {}", + approx_parts, perfect_parts, a, b + ); +} + +/// Round a `Fraction` according to the given mode. +fn round(f: Fraction, r: Rounding) -> Fraction { + match r { + Up => f.ceil(), + NearestPrefUp => + if f.fract() < Fraction::from(0.5) { + f.floor() + } else { + f.ceil() + }, + Down => f.floor(), + NearestPrefDown => + if f.fract() > Fraction::from(0.5) { + f.ceil() + } else { + f.floor() + }, + } +} + +/// An [`arbitrary::Arbitrary`] [`Rounding`] mode. +struct ArbitraryRounding(Rounding); +impl arbitrary::Arbitrary<'_> for ArbitraryRounding { + fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result { + Ok(Self(match u.int_in_range(0..=3).unwrap() { + 0 => Up, + 1 => NearestPrefUp, + 2 => Down, + 3 => NearestPrefDown, + _ => unreachable!(), + })) + } +} diff --git a/primitives/arithmetic/fuzzer/src/per_thing_mult_fraction.rs b/primitives/arithmetic/fuzzer/src/per_thing_mult_fraction.rs new file mode 100644 index 0000000000000..9cfe28a7800b0 --- /dev/null +++ b/primitives/arithmetic/fuzzer/src/per_thing_mult_fraction.rs @@ -0,0 +1,69 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT 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 per_thing_mult_fraction`. `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_mult_fraction hfuzz_workspace/per_thing_mult_fraction/*.fuzz`. + +use honggfuzz::fuzz; +use sp_arithmetic::{PerThing, Perbill, Percent, Perquintill, *}; + +/// Tries to disprove `(n / d) * d <= n` for any `PerThing`s. +fn main() { + loop { + fuzz!(|data: (u128, u128)| { + let (n, d) = (data.0.min(data.1), data.0.max(data.1).max(1)); + + check_mul::(n, d); + check_mul::(n, d); + check_mul::(n, d); + check_mul::(n, d); + + check_reciprocal_mul::(n, d); + check_reciprocal_mul::(n, d); + check_reciprocal_mul::(n, d); + check_reciprocal_mul::(n, d); + }) + } +} + +/// Checks that `(n / d) * d <= n`. +fn check_mul(n: u128, d: u128) +where + P: PerThing + core::ops::Mul, +{ + let q = P::from_rational_with_rounding(n, d, Rounding::Down).unwrap(); + assert!(q * d <= n, "{:?} * {:?} <= {:?}", q, d, n); +} + +/// Checks that `n / (n / d) >= d`. +fn check_reciprocal_mul(n: u128, d: u128) +where + P: PerThing + core::ops::Mul, +{ + let q = P::from_rational_with_rounding(n, d, Rounding::Down).unwrap(); + if q.is_zero() { + return + } + + let r = q.saturating_reciprocal_mul_floor(n); + assert!(r >= d, "{} / ({} / {}) != {} but {}", n, n, d, d, r); +} diff --git a/primitives/arithmetic/fuzzer/src/per_thing_rational.rs b/primitives/arithmetic/fuzzer/src/per_thing_rational.rs deleted file mode 100644 index c9c5146565cc7..0000000000000 --- a/primitives/arithmetic/fuzzer/src/per_thing_rational.rs +++ /dev/null @@ -1,116 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! # Running -//! Running this fuzzer can be done with `cargo hfuzz run per_thing_rational`. `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/per_thing_rational/*.fuzz`. - -use honggfuzz::fuzz; -use sp_arithmetic::{traits::SaturatedConversion, PerThing, PerU16, Perbill, Percent, Perquintill}; - -fn main() { - loop { - fuzz!(|data: ((u16, u16), (u32, u32), (u64, u64))| { - let (u16_pair, u32_pair, u64_pair) = data; - - // peru16 - let (smaller, bigger) = (u16_pair.0.min(u16_pair.1), u16_pair.0.max(u16_pair.1)); - let ratio = PerU16::from_rational(smaller, bigger); - assert_per_thing_equal_error( - ratio, - PerU16::from_float(smaller as f64 / bigger.max(1) as f64), - 1, - ); - let (smaller, bigger) = (u32_pair.0.min(u32_pair.1), u32_pair.0.max(u32_pair.1)); - let ratio = PerU16::from_rational(smaller, bigger); - assert_per_thing_equal_error( - ratio, - PerU16::from_float(smaller as f64 / bigger.max(1) as f64), - 1, - ); - let (smaller, bigger) = (u64_pair.0.min(u64_pair.1), u64_pair.0.max(u64_pair.1)); - let ratio = PerU16::from_rational(smaller, bigger); - assert_per_thing_equal_error( - ratio, - PerU16::from_float(smaller as f64 / bigger.max(1) as f64), - 1, - ); - - // percent - let (smaller, bigger) = (u16_pair.0.min(u16_pair.1), u16_pair.0.max(u16_pair.1)); - let ratio = Percent::from_rational(smaller, bigger); - assert_per_thing_equal_error( - ratio, - Percent::from_float(smaller as f64 / bigger.max(1) as f64), - 1, - ); - - let (smaller, bigger) = (u32_pair.0.min(u32_pair.1), u32_pair.0.max(u32_pair.1)); - let ratio = Percent::from_rational(smaller, bigger); - assert_per_thing_equal_error( - ratio, - Percent::from_float(smaller as f64 / bigger.max(1) as f64), - 1, - ); - - let (smaller, bigger) = (u64_pair.0.min(u64_pair.1), u64_pair.0.max(u64_pair.1)); - let ratio = Percent::from_rational(smaller, bigger); - assert_per_thing_equal_error( - ratio, - Percent::from_float(smaller as f64 / bigger.max(1) as f64), - 1, - ); - - // perbill - let (smaller, bigger) = (u32_pair.0.min(u32_pair.1), u32_pair.0.max(u32_pair.1)); - let ratio = Perbill::from_rational(smaller, bigger); - assert_per_thing_equal_error( - ratio, - Perbill::from_float(smaller as f64 / bigger.max(1) as f64), - 100, - ); - - let (smaller, bigger) = (u64_pair.0.min(u64_pair.1), u64_pair.0.max(u64_pair.1)); - let ratio = Perbill::from_rational(smaller, bigger); - assert_per_thing_equal_error( - ratio, - Perbill::from_float(smaller as f64 / bigger.max(1) as f64), - 100, - ); - - // perquintillion - let (smaller, bigger) = (u64_pair.0.min(u64_pair.1), u64_pair.0.max(u64_pair.1)); - let ratio = Perquintill::from_rational(smaller, bigger); - assert_per_thing_equal_error( - ratio, - Perquintill::from_float(smaller as f64 / bigger.max(1) as f64), - 1000, - ); - }) - } -} - -fn assert_per_thing_equal_error(a: P, b: P, err: u128) { - let a_abs = a.deconstruct().saturated_into::(); - let b_abs = b.deconstruct().saturated_into::(); - let diff = a_abs.max(b_abs) - a_abs.min(b_abs); - assert!(diff <= err, "{:?} !~ {:?}", a, b); -} diff --git a/primitives/arithmetic/src/helpers_128bit.rs b/primitives/arithmetic/src/helpers_128bit.rs index 56432d15a7260..9b9c74ba55774 100644 --- a/primitives/arithmetic/src/helpers_128bit.rs +++ b/primitives/arithmetic/src/helpers_128bit.rs @@ -182,8 +182,8 @@ mod double128 { } } -/// Returns `a * b / c` and `(a * b) % c` (wrapping to 128 bits) or `None` in the case of -/// overflow and c = 0. +/// Returns `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, diff --git a/primitives/arithmetic/src/lib.rs b/primitives/arithmetic/src/lib.rs index 581206b6d4460..e7ba08a532909 100644 --- a/primitives/arithmetic/src/lib.rs +++ b/primitives/arithmetic/src/lib.rs @@ -45,7 +45,7 @@ pub use per_things::{ InnerOf, MultiplyArg, PerThing, PerU16, Perbill, Percent, Permill, Perquintill, RationalArg, ReciprocalArg, Rounding, SignedRounding, UpperOf, }; -pub use rational::{Rational128, RationalInfinite}; +pub use rational::{MultiplyRational, Rational128, RationalInfinite}; use sp_std::{cmp::Ordering, fmt::Debug, prelude::*}; use traits::{BaseArithmetic, One, SaturatedConversion, Unsigned, Zero}; diff --git a/primitives/arithmetic/src/per_things.rs b/primitives/arithmetic/src/per_things.rs index 068bdb4e17b0d..c4cb5196602ea 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, AddAssign, Div, Rem, Sub}, + ops::{Add, Sub}, prelude::*, }; @@ -46,6 +46,7 @@ pub trait RationalArg: + Unsigned + Zero + One + + crate::MultiplyRational { } @@ -58,7 +59,8 @@ impl< + ops::AddAssign + Unsigned + Zero - + One, + + One + + crate::MultiplyRational, > RationalArg for T { } @@ -105,7 +107,7 @@ pub trait PerThing: + Pow { /// The data type used to build this per-thingy. - type Inner: BaseArithmetic + Unsigned + Copy + Into + fmt::Debug; + type Inner: BaseArithmetic + Unsigned + Copy + Into + fmt::Debug + crate::MultiplyRational; /// A data type larger than `Self::Inner`, used to avoid overflow in some computations. /// It must be able to compute `ACCURACY^2`. @@ -115,7 +117,8 @@ pub trait PerThing: + TryInto + UniqueSaturatedInto + Unsigned - + fmt::Debug; + + fmt::Debug + + crate::MultiplyRational; /// The accuracy of this type. const ACCURACY: Self::Inner; @@ -538,39 +541,6 @@ where 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, @@ -687,7 +657,8 @@ macro_rules! implement_per_thing { + ops::AddAssign + Unsigned + Zero - + One, + + One + + $crate::MultiplyRational, Self::Inner: Into { // q cannot be zero. @@ -695,30 +666,8 @@ macro_rules! implement_per_thing { // p should not be bigger than q. if p > q { return Err(()) } - 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 = 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 \ - does not satisfy this; qed" - ); - let p_reduce: $type = div_rounded(p, factor, r) - .try_into() - .map_err(|_| "Failed to convert") - .expect( - "`p / ceil(p/$max) < $max`; macro prevents any type being created that \ - does not satisfy this; qed" - ); - - // `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)) + let max: N = $max.into(); + max.multiply_rational(p, q, r).ok_or(())?.try_into().map(|x| $name(x)).map_err(|_| ()) } } @@ -1862,6 +1811,22 @@ fn from_rational_with_rounding_works_in_extreme_case() { } } +#[test] +fn from_rational_with_rounding_breakage() { + let n = 372633774963620730670986667244911905u128; + let d = 512593663333074177468745541591173060u128; + let q = Perquintill::from_rational_with_rounding(n, d, Rounding::Down).unwrap(); + assert!(q * d <= n); +} + +#[test] +fn from_rational_with_rounding_breakage_2() { + let n = 36893488147419103230u128; + let d = 36893488147419103630u128; + let q = Perquintill::from_rational_with_rounding(n, d, Rounding::Up).unwrap(); + assert!(q * d >= n); +} + 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/rational.rs b/primitives/arithmetic/src/rational.rs index 0fcb7d4d9462a..ebd89c615a38b 100644 --- a/primitives/arithmetic/src/rational.rs +++ b/primitives/arithmetic/src/rational.rs @@ -284,6 +284,54 @@ impl PartialEq for Rational128 { } } +pub trait MultiplyRational: Sized { + fn multiply_rational(self, n: Self, d: Self, r: Rounding) -> Option; +} + +macro_rules! impl_rrm { + ($ulow:ty, $uhi:ty) => { + impl MultiplyRational for $ulow { + fn multiply_rational(self, n: Self, d: Self, r: Rounding) -> Option { + if d.is_zero() { + return None + } + + let sn = (self as $uhi) * (n as $uhi); + let mut result = sn / (d as $uhi); + let remainder = (sn % (d as $uhi)) as $ulow; + if match r { + Rounding::Up => remainder > 0, + // cannot be `(d + 1) / 2` since `d` might be `max_value` and overflow. + Rounding::NearestPrefUp => remainder >= d / 2 + d % 2, + Rounding::NearestPrefDown => remainder > d / 2, + Rounding::Down => false, + } { + result = match result.checked_add(1) { + Some(v) => v, + None => return None, + }; + } + if result > (<$ulow>::max_value() as $uhi) { + None + } else { + Some(result as $ulow) + } + } + } + }; +} + +impl_rrm!(u8, u16); +impl_rrm!(u16, u32); +impl_rrm!(u32, u64); +impl_rrm!(u64, u128); + +impl MultiplyRational for u128 { + fn multiply_rational(self, n: Self, d: Self, r: Rounding) -> Option { + crate::helpers_128bit::multiply_by_rational_with_rounding(self, n, d, r) + } +} + #[cfg(test)] mod tests { use super::{helpers_128bit::*, *}; diff --git a/primitives/arithmetic/src/traits.rs b/primitives/arithmetic/src/traits.rs index 33b4e376aaf9d..061b11b3e9c72 100644 --- a/primitives/arithmetic/src/traits.rs +++ b/primitives/arithmetic/src/traits.rs @@ -32,6 +32,8 @@ use sp_std::ops::{ Add, AddAssign, Div, DivAssign, Mul, MulAssign, Rem, RemAssign, Shl, Shr, Sub, SubAssign, }; +use crate::MultiplyRational; + /// A meta trait for arithmetic type operations, regardless of any limitation on size. pub trait BaseArithmetic: From @@ -186,9 +188,9 @@ pub trait AtLeast32Bit: BaseArithmetic + From + From {} impl + From> AtLeast32Bit for T {} /// A meta trait for arithmetic. Same as [`AtLeast32Bit `], but also bounded to be unsigned. -pub trait AtLeast32BitUnsigned: AtLeast32Bit + Unsigned {} +pub trait AtLeast32BitUnsigned: AtLeast32Bit + Unsigned + MultiplyRational {} -impl AtLeast32BitUnsigned for T {} +impl AtLeast32BitUnsigned for T {} /// Just like `From` except that if the source value is too big to fit into the destination type /// then it'll saturate the destination. From ad66dd2ff1c6c97d9d5d25a0dc7d3a44342c9a3a Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Fri, 24 Mar 2023 16:09:34 +0100 Subject: [PATCH 561/715] try-runtime: run migration checks per default (#13684) * try-runtime: run migration checks per default The current behaviour of having to explicetly specify --checks seems to cause confusion. Therefore bringing back the old behaviour of running the pre- and post-upgrade checks per default. Signed-off-by: Oliver Tale-Yazdi * Fix docs Signed-off-by: Oliver Tale-Yazdi --------- Signed-off-by: Oliver Tale-Yazdi --- .../try-runtime/cli/src/commands/on_runtime_upgrade.rs | 4 ++-- utils/frame/try-runtime/cli/src/lib.rs | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) 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 c8582ea4d2a60..948ff9c030ea9 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 @@ -40,8 +40,8 @@ pub struct OnRuntimeUpgradeCmd { /// Performing any checks will potentially invalidate the measured PoV/Weight. // NOTE: The clap attributes make it backwards compatible with the previous `--checks` flag. #[clap(long, - default_value = "None", - default_missing_value = "All", + default_value = "pre-and-post", + default_missing_value = "all", num_args = 0..=1, require_equals = true, verbatim_doc_comment)] diff --git a/utils/frame/try-runtime/cli/src/lib.rs b/utils/frame/try-runtime/cli/src/lib.rs index 0a521d1215562..bc9fd99d3e628 100644 --- a/utils/frame/try-runtime/cli/src/lib.rs +++ b/utils/frame/try-runtime/cli/src/lib.rs @@ -134,10 +134,10 @@ //! //! ```ignore //! -//! #[cfg(feature = try-runtime)] +//! #[cfg(feature = "try-runtime")] //! fn pre_upgrade() -> Result, &'static str> {} //! -//! #[cfg(feature = try-runtime)] +//! #[cfg(feature = "try-runtime")] //! fn post_upgrade(state: Vec) -> Result<(), &'static str> {} //! ``` //! @@ -152,9 +152,9 @@ //! //! Similarly, each pallet can expose a function in `#[pallet::hooks]` section as follows: //! -//! ``` -//! #[cfg(feature = try-runtime)] -//! fn try_state(_) -> Result<(), &'static str> {} +//! ```ignore +//! #[cfg(feature = "try-runtime")] +//! fn try_state(_: BlockNumber) -> Result<(), &'static str> {} //! ``` //! //! which is called on numerous code paths in the try-runtime tool. These checks should ensure that From 770d23709a7e004ae8f5fff1598bb4cf72928b43 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Fri, 24 Mar 2023 17:48:21 +0000 Subject: [PATCH 562/715] Make ED of zero (kind of) work (#13655) * Minimum of 1 for ED * Avoid need for ED to be minimum one * Docs * Ban ED of zero unless feature enabled * use integrity_test * Docs * Cleanup * Update frame/balances/Cargo.toml Co-authored-by: Oliver Tale-Yazdi * Update frame/balances/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * Update frame/balances/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * Ensure dodgy code is disabled by default * zero_ed -> insecure_zero_ed --------- Co-authored-by: Oliver Tale-Yazdi Co-authored-by: parity-processbot <> --- frame/balances/Cargo.toml | 2 + frame/balances/src/lib.rs | 55 +++++++++++++++++++--- frame/balances/src/tests/currency_tests.rs | 15 +++++- frame/balances/src/tests/mod.rs | 2 +- frame/vesting/src/mock.rs | 2 +- 5 files changed, 65 insertions(+), 11 deletions(-) diff --git a/frame/balances/Cargo.toml b/frame/balances/Cargo.toml index 15ef136aa3800..9646a934df00e 100644 --- a/frame/balances/Cargo.toml +++ b/frame/balances/Cargo.toml @@ -39,5 +39,7 @@ std = [ "sp-runtime/std", "sp-std/std", ] +# Enable support for setting the existential deposit to zero. +insecure_zero_ed = [] runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks"] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index ca8e86ef2f64a..460f2be37ff2d 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -151,6 +151,10 @@ //! ## Assumptions //! //! * Total issued balanced of all accounts should be less than `Config::Balance::max_value()`. +//! * Existential Deposit is set to a value greater than zero. +//! +//! Note, you may find the Balances pallet still functions with an ED of zero in some circumstances, +//! however this is not a configuration which is generally supported, nor will it be. #![cfg_attr(not(feature = "std"), no_std)] mod benchmarking; @@ -231,7 +235,14 @@ pub mod pallet { /// Handler for the unbalanced reduction when removing a dust account. type DustRemoval: OnUnbalanced>; - /// The minimum amount required to keep an account open. + /// The minimum amount required to keep an account open. MUST BE GREATER THAN ZERO! + /// + /// If you *really* need it to be zero, you can enable the feature `insecure_zero_ed` for + /// this pallet. However, you do so at your own risk: this will open up a major DoS vector. + /// In case you have multiple sources of provider references, you may also get unexpected + /// behaviour if you set this to zero. + /// + /// Bottom line: Do yourself a favour and make it at least one! #[pallet::constant] type ExistentialDeposit: Get; @@ -445,6 +456,7 @@ pub mod pallet { impl, I: 'static> GenesisBuild for GenesisConfig { fn build(&self) { let total = self.balances.iter().fold(Zero::zero(), |acc: T::Balance, &(_, n)| acc + n); + >::put(total); for (_, balance) in &self.balances { @@ -492,6 +504,17 @@ pub mod pallet { } } + #[pallet::hooks] + impl, I: 'static> Hooks for Pallet { + #[cfg(not(feature = "insecure_zero_ed"))] + fn integrity_test() { + assert!( + !>::ExistentialDeposit::get().is_zero(), + "The existential deposit must be greater than zero!" + ); + } + } + #[pallet::call] impl, I: 'static> Pallet { /// Transfer some liquid free balance to another account. @@ -533,7 +556,7 @@ pub mod pallet { ) -> DispatchResultWithPostInfo { ensure_root(origin)?; let who = T::Lookup::lookup(who)?; - let existential_deposit = T::ExistentialDeposit::get(); + let existential_deposit = Self::ed(); let wipeout = new_free < existential_deposit; let new_free = if wipeout { Zero::zero() } else { new_free }; @@ -716,7 +739,7 @@ pub mod pallet { ) -> DispatchResultWithPostInfo { ensure_root(origin)?; let who = T::Lookup::lookup(who)?; - let existential_deposit = T::ExistentialDeposit::get(); + let existential_deposit = Self::ed(); let wipeout = new_free < existential_deposit; let new_free = if wipeout { Zero::zero() } else { new_free }; @@ -742,6 +765,9 @@ pub mod pallet { } impl, I: 'static> Pallet { + fn ed() -> T::Balance { + T::ExistentialDeposit::get() + } /// Ensure the account `who` is using the new logic. /// /// Returns `true` if the account did get upgraded, `false` if it didn't need upgrading. @@ -756,7 +782,7 @@ pub mod pallet { // Gah!! We have a non-zero reserve balance but no provider refs :( // This shouldn't practically happen, but we need a failsafe anyway: let's give // them enough for an ED. - a.free = a.free.min(T::ExistentialDeposit::get()); + a.free = a.free.min(Self::ed()); system::Pallet::::inc_providers(who); } let _ = system::Pallet::::inc_consumers(who).defensive(); @@ -864,6 +890,20 @@ pub mod pallet { Self::try_mutate_account(who, |a, _| -> Result { Ok(f(a)) }) } + /// Returns `true` when `who` has some providers or `insecure_zero_ed` feature is disnabled. + /// Returns `false` otherwise. + #[cfg(not(feature = "insecure_zero_ed"))] + fn have_providers_or_no_zero_ed(_: &T::AccountId) -> bool { + true + } + + /// Returns `true` when `who` has some providers or `insecure_zero_ed` feature is disnabled. + /// Returns `false` otherwise. + #[cfg(feature = "insecure_zero_ed")] + fn have_providers_or_no_zero_ed(who: &T::AccountId) -> bool { + frame_system::Pallet::::providers(who) > 0 + } + /// Mutate an account to some new value, or delete it entirely with `None`. Will enforce /// `ExistentialDeposit` law, annulling the account as needed. This will do nothing if the /// result of `f` is an `Err`. @@ -885,13 +925,14 @@ pub mod pallet { let result = T::AccountStore::try_mutate_exists(who, |maybe_account| { let is_new = maybe_account.is_none(); let mut account = maybe_account.take().unwrap_or_default(); - let did_provide = account.free >= T::ExistentialDeposit::get(); + let did_provide = + account.free >= Self::ed() && Self::have_providers_or_no_zero_ed(who); let did_consume = !is_new && (!account.reserved.is_zero() || !account.frozen.is_zero()); let result = f(&mut account, is_new)?; - let does_provide = account.free >= T::ExistentialDeposit::get(); + let does_provide = account.free >= Self::ed(); let does_consume = !account.reserved.is_zero() || !account.frozen.is_zero(); if !did_provide && does_provide { @@ -930,7 +971,7 @@ pub mod pallet { // // We should never be dropping if reserved is non-zero. Reserved being non-zero // should imply that we have a consumer ref, so this is economically safe. - let ed = T::ExistentialDeposit::get(); + let ed = Self::ed(); let maybe_dust = if account.free < ed && account.reserved.is_zero() { if account.free.is_zero() { None diff --git a/frame/balances/src/tests/currency_tests.rs b/frame/balances/src/tests/currency_tests.rs index b0a38f4ac4ed7..f74e6bb8c4993 100644 --- a/frame/balances/src/tests/currency_tests.rs +++ b/frame/balances/src/tests/currency_tests.rs @@ -23,7 +23,8 @@ use frame_support::traits::{ BalanceStatus::{Free, Reserved}, Currency, ExistenceRequirement::{self, AllowDeath}, - LockIdentifier, LockableCurrency, NamedReservableCurrency, ReservableCurrency, WithdrawReasons, + Hooks, LockIdentifier, LockableCurrency, NamedReservableCurrency, ReservableCurrency, + WithdrawReasons, }; const ID_1: LockIdentifier = *b"1 "; @@ -974,7 +975,7 @@ fn slash_reserved_on_non_existant_works() { fn operations_on_dead_account_should_not_change_state() { // These functions all use `mutate_account` which may introduce a storage change when // the account never existed to begin with, and shouldn't exist in the end. - ExtBuilder::default().existential_deposit(0).build_and_execute_with(|| { + ExtBuilder::default().existential_deposit(1).build_and_execute_with(|| { assert!(!frame_system::Account::::contains_key(&1337)); // Unreserve @@ -993,6 +994,16 @@ fn operations_on_dead_account_should_not_change_state() { }); } +#[test] +#[should_panic = "The existential deposit must be greater than zero!"] +fn zero_ed_is_prohibited() { + // These functions all use `mutate_account` which may introduce a storage change when + // the account never existed to begin with, and shouldn't exist in the end. + ExtBuilder::default().existential_deposit(0).build_and_execute_with(|| { + Balances::integrity_test(); + }); +} + #[test] fn named_reserve_should_work() { ExtBuilder::default().build_and_execute_with(|| { diff --git a/frame/balances/src/tests/mod.rs b/frame/balances/src/tests/mod.rs index c4a8a631cad20..68e7e82035b0e 100644 --- a/frame/balances/src/tests/mod.rs +++ b/frame/balances/src/tests/mod.rs @@ -87,7 +87,7 @@ parameter_types! { frame_system::limits::BlockWeights::simple_max( frame_support::weights::Weight::from_parts(1024, u64::MAX), ); - pub static ExistentialDeposit: u64 = 0; + pub static ExistentialDeposit: u64 = 1; } impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; diff --git a/frame/vesting/src/mock.rs b/frame/vesting/src/mock.rs index be6afd4a60ec8..1adb36b730b1a 100644 --- a/frame/vesting/src/mock.rs +++ b/frame/vesting/src/mock.rs @@ -89,7 +89,7 @@ parameter_types! { pub const MinVestedTransfer: u64 = 256 * 2; pub UnvestedFundsAllowedWithdrawReasons: WithdrawReasons = WithdrawReasons::except(WithdrawReasons::TRANSFER | WithdrawReasons::RESERVE); - pub static ExistentialDeposit: u64 = 0; + pub static ExistentialDeposit: u64 = 1; } impl Config for Test { type BlockNumberToBalance = Identity; From d0449fd4219cb3c77e46a9916c7996a1136ca63e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Fri, 24 Mar 2023 18:50:16 +0100 Subject: [PATCH 563/715] try-runtime: Use configured wasm execution method (#13694) * try-runtime: Use configured wasm execution method * Fix compilation --- client/cli/src/arg_enums.rs | 4 ++-- utils/frame/try-runtime/cli/src/lib.rs | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/client/cli/src/arg_enums.rs b/client/cli/src/arg_enums.rs index c3399a89680d1..7e2498cec4b7f 100644 --- a/client/cli/src/arg_enums.rs +++ b/client/cli/src/arg_enums.rs @@ -74,12 +74,12 @@ impl std::fmt::Display for WasmExecutionMethod { /// into an execution method which can be used internally. pub fn execution_method_from_cli( execution_method: WasmExecutionMethod, - _instantiation_strategy: WasmtimeInstantiationStrategy, + instantiation_strategy: WasmtimeInstantiationStrategy, ) -> sc_service::config::WasmExecutionMethod { match execution_method { WasmExecutionMethod::Interpreted => sc_service::config::WasmExecutionMethod::Interpreted, WasmExecutionMethod::Compiled => sc_service::config::WasmExecutionMethod::Compiled { - instantiation_strategy: match _instantiation_strategy { + instantiation_strategy: match instantiation_strategy { WasmtimeInstantiationStrategy::PoolingCopyOnWrite => sc_service::config::WasmtimeInstantiationStrategy::PoolingCopyOnWrite, WasmtimeInstantiationStrategy::RecreateInstanceCopyOnWrite => diff --git a/utils/frame/try-runtime/cli/src/lib.rs b/utils/frame/try-runtime/cli/src/lib.rs index bc9fd99d3e628..e1873f6a04abd 100644 --- a/utils/frame/try-runtime/cli/src/lib.rs +++ b/utils/frame/try-runtime/cli/src/lib.rs @@ -133,7 +133,6 @@ //! given the right flag: //! //! ```ignore -//! //! #[cfg(feature = "try-runtime")] //! fn pre_upgrade() -> Result, &'static str> {} //! @@ -365,8 +364,9 @@ use remote_externalities::{ TestExternalities, }; use sc_cli::{ - CliConfiguration, RuntimeVersion, WasmExecutionMethod, WasmtimeInstantiationStrategy, - DEFAULT_WASMTIME_INSTANTIATION_STRATEGY, DEFAULT_WASM_EXECUTION_METHOD, + execution_method_from_cli, CliConfiguration, RuntimeVersion, WasmExecutionMethod, + WasmtimeInstantiationStrategy, DEFAULT_WASMTIME_INSTANTIATION_STRATEGY, + DEFAULT_WASM_EXECUTION_METHOD, }; use sc_executor::{sp_wasm_interface::HostFunctions, WasmExecutor}; use sp_api::HashT; @@ -831,7 +831,7 @@ pub(crate) fn build_executor(shared: &SharedParams) -> WasmExe let runtime_cache_size = 2; WasmExecutor::new( - sc_executor::WasmExecutionMethod::Interpreted, + execution_method_from_cli(shared.wasm_method, shared.wasmtime_instantiation_strategy), heap_pages, max_runtime_instances, None, From e87f7acc4191274a2889f1b9adb59260e038b0a8 Mon Sep 17 00:00:00 2001 From: Mira Ressel Date: Fri, 24 Mar 2023 22:00:48 +0100 Subject: [PATCH 564/715] bump timestamp script to v0.2 (#13710) --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 6cf06273650f7..c4d88ebde75f2 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -313,7 +313,7 @@ include: rules: - if: $PIPELINE != "automatic-crate-publishing" - project: parity/infrastructure/ci_cd/shared - ref: v0.1 + ref: v0.2 file: /common/timestamp.yml #### stage: notify From a3df63ef370adb7f806aa6ffa876eb17672b7ca8 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Fri, 24 Mar 2023 23:54:32 +0100 Subject: [PATCH 565/715] Fix docs (#13709) --- primitives/application-crypto/src/traits.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/primitives/application-crypto/src/traits.rs b/primitives/application-crypto/src/traits.rs index f672efb8a890a..b3bcd0ce2b701 100644 --- a/primitives/application-crypto/src/traits.rs +++ b/primitives/application-crypto/src/traits.rs @@ -22,7 +22,14 @@ use codec::Codec; use sp_core::crypto::{CryptoType, CryptoTypeId, IsWrappedBy, KeyTypeId, Public}; use sp_std::{fmt::Debug, vec::Vec}; -/// An application-specific key. +/// An application-specific cryptographic object. +/// +/// Combines all the core types and constants that are defined by a particular +/// cryptographic scheme when it is used in a specific application domain. +/// +/// Typically, the implementers of this trait are its associated types themselves. +/// This provides a convenient way to access generic information about the scheme +/// given any of the associated types. pub trait AppCrypto: 'static + Send + Sync + Sized + CryptoType + Clone { /// Identifier for application-specific key type. const ID: KeyTypeId; From 5766265306d104b4a5d7cf1082bcae78986dfff0 Mon Sep 17 00:00:00 2001 From: Aaro Altonen <48052676+altonen@users.noreply.github.com> Date: Sat, 25 Mar 2023 01:47:28 +0200 Subject: [PATCH 566/715] Get the correct number of connected peers in `SyncState` (#13700) `Protocol` is not a reliable source for the information of connected peers because it doesn't have real-time information of the actual connectivity state because it's not resposible for accepting/rejecting connections and gets that information with delay from `SyncinEngine`. --- client/informant/src/display.rs | 2 +- client/network/common/src/sync.rs | 2 ++ client/network/sync/src/engine.rs | 4 +++- client/network/sync/src/lib.rs | 1 + 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/client/informant/src/display.rs b/client/informant/src/display.rs index 46e7229273d79..2f101307229da 100644 --- a/client/informant/src/display.rs +++ b/client/informant/src/display.rs @@ -76,7 +76,7 @@ impl InformantDisplay { let best_number = info.chain.best_number; let best_hash = info.chain.best_hash; let finalized_number = info.chain.finalized_number; - let num_connected_peers = net_status.num_connected_peers; + let num_connected_peers = sync_status.num_connected_peers; let speed = speed::(best_number, self.last_number, self.last_update); let total_bytes_inbound = net_status.total_bytes_inbound; let total_bytes_outbound = net_status.total_bytes_outbound; diff --git a/client/network/common/src/sync.rs b/client/network/common/src/sync.rs index 130f354b70050..d02a81379aea0 100644 --- a/client/network/common/src/sync.rs +++ b/client/network/common/src/sync.rs @@ -94,6 +94,8 @@ pub struct SyncStatus { pub best_seen_block: Option>, /// Number of peers participating in syncing. pub num_peers: u32, + /// Number of peers known to `SyncingEngine` (both full and light). + pub num_connected_peers: u32, /// Number of blocks queued for import pub queued_blocks: u32, /// State sync status in progress, if any. diff --git a/client/network/sync/src/engine.rs b/client/network/sync/src/engine.rs index a9c9afc3c6f4c..b4c1a2ed05bb0 100644 --- a/client/network/sync/src/engine.rs +++ b/client/network/sync/src/engine.rs @@ -711,7 +711,9 @@ where ToServiceCommand::NewBestBlockImported(hash, number) => self.new_best_block_imported(hash, number), ToServiceCommand::Status(tx) => { - let _ = tx.send(self.chain_sync.status()); + let mut status = self.chain_sync.status(); + status.num_connected_peers = self.peers.len() as u32; + let _ = tx.send(status); }, ToServiceCommand::NumActivePeers(tx) => { let _ = tx.send(self.chain_sync.num_active_peers()); diff --git a/client/network/sync/src/lib.rs b/client/network/sync/src/lib.rs index 45d14ffa7bb37..28959e7f9c886 100644 --- a/client/network/sync/src/lib.rs +++ b/client/network/sync/src/lib.rs @@ -523,6 +523,7 @@ where state: sync_state, best_seen_block, num_peers: self.peers.len() as u32, + num_connected_peers: 0u32, queued_blocks: self.queue_blocks.len() as u32, state_sync: self.state_sync.as_ref().map(|s| s.progress()), warp_sync: warp_sync_progress, From ea7238237da06731ff2c4280d71f00c0b361e74c Mon Sep 17 00:00:00 2001 From: Harald Heckmann Date: Sat, 25 Mar 2023 00:53:18 +0100 Subject: [PATCH 567/715] Emit event when changing total locked value in pallet-balances (#12287) * Emit Locked/Unlocked events * Implement lock event tests * Adhere to style guide * Use saturating math Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Fix typo * Emit event on change locks and add tests * Adjust event docstring --------- Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: parity-processbot <> --- frame/balances/src/lib.rs | 16 +++++++ frame/balances/src/tests/currency_tests.rs | 55 ++++++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index 460f2be37ff2d..d4be806982dfe 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -330,6 +330,10 @@ pub mod pallet { Issued { amount: T::Balance }, /// Total issuance was decreased by `amount`, creating a debt to be balanced. Rescinded { amount: T::Balance }, + /// Some balance was locked. + Locked { who: T::AccountId, amount: T::Balance }, + /// Some balance was unlocked. + Unlocked { who: T::AccountId, amount: T::Balance }, } #[pallet::error] @@ -1016,9 +1020,12 @@ pub mod pallet { ); } let freezes = Freezes::::get(who); + let mut prev_frozen = Zero::zero(); + let mut after_frozen = Zero::zero(); // TODO: Revisit this assumption. We no manipulate consumer/provider refs. // No way this can fail since we do not alter the existential balances. let res = Self::mutate_account(who, |b| { + prev_frozen = b.frozen; b.frozen = Zero::zero(); for l in locks.iter() { b.frozen = b.frozen.max(l.amount); @@ -1026,6 +1033,7 @@ pub mod pallet { for l in freezes.iter() { b.frozen = b.frozen.max(l.amount); } + after_frozen = b.frozen; }); debug_assert!(res.is_ok()); if let Ok((_, maybe_dust)) = res { @@ -1053,6 +1061,14 @@ pub mod pallet { ); } } + + if prev_frozen > after_frozen { + let amount = prev_frozen.saturating_sub(after_frozen); + Self::deposit_event(Event::Unlocked { who: who.clone(), amount }); + } else if after_frozen > prev_frozen { + let amount = after_frozen.saturating_sub(prev_frozen); + Self::deposit_event(Event::Locked { who: who.clone(), amount }); + } } /// Update the account entry for `who`, given the locks. diff --git a/frame/balances/src/tests/currency_tests.rs b/frame/balances/src/tests/currency_tests.rs index f74e6bb8c4993..034c92f65689b 100644 --- a/frame/balances/src/tests/currency_tests.rs +++ b/frame/balances/src/tests/currency_tests.rs @@ -754,6 +754,61 @@ fn emit_events_with_reserve_and_unreserve() { }); } +#[test] +fn emit_events_with_changing_locks() { + ExtBuilder::default().build_and_execute_with(|| { + let _ = Balances::deposit_creating(&1, 100); + System::reset_events(); + + // Locks = [] --> [10] + Balances::set_lock(*b"LOCK_000", &1, 10, WithdrawReasons::TRANSFER); + assert_eq!(events(), [RuntimeEvent::Balances(crate::Event::Locked { who: 1, amount: 10 })]); + + // Locks = [10] --> [15] + Balances::set_lock(*b"LOCK_000", &1, 15, WithdrawReasons::TRANSFER); + assert_eq!(events(), [RuntimeEvent::Balances(crate::Event::Locked { who: 1, amount: 5 })]); + + // Locks = [15] --> [15, 20] + Balances::set_lock(*b"LOCK_001", &1, 20, WithdrawReasons::TRANSACTION_PAYMENT); + assert_eq!(events(), [RuntimeEvent::Balances(crate::Event::Locked { who: 1, amount: 5 })]); + + // Locks = [15, 20] --> [17, 20] + Balances::set_lock(*b"LOCK_000", &1, 17, WithdrawReasons::TRANSACTION_PAYMENT); + for event in events() { + match event { + RuntimeEvent::Balances(crate::Event::Locked { .. }) => { + assert!(false, "unexpected lock event") + }, + RuntimeEvent::Balances(crate::Event::Unlocked { .. }) => { + assert!(false, "unexpected unlock event") + }, + _ => continue, + } + } + + // Locks = [17, 20] --> [17, 15] + Balances::set_lock(*b"LOCK_001", &1, 15, WithdrawReasons::TRANSFER); + assert_eq!( + events(), + [RuntimeEvent::Balances(crate::Event::Unlocked { who: 1, amount: 3 })] + ); + + // Locks = [17, 15] --> [15] + Balances::remove_lock(*b"LOCK_000", &1); + assert_eq!( + events(), + [RuntimeEvent::Balances(crate::Event::Unlocked { who: 1, amount: 2 })] + ); + + // Locks = [15] --> [] + Balances::remove_lock(*b"LOCK_001", &1); + assert_eq!( + events(), + [RuntimeEvent::Balances(crate::Event::Unlocked { who: 1, amount: 15 })] + ); + }); +} + #[test] fn emit_events_with_existential_deposit() { ExtBuilder::default().existential_deposit(100).build_and_execute_with(|| { From 78c99dadc961a46aaa90c231a209f0855a97e8ca Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Sat, 25 Mar 2023 16:59:31 +0100 Subject: [PATCH 568/715] Fix failing offences bench test (#13712) Signed-off-by: Oliver Tale-Yazdi --- frame/offences/benchmarking/src/lib.rs | 11 ++++++++++- frame/offences/benchmarking/src/mock.rs | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/frame/offences/benchmarking/src/lib.rs b/frame/offences/benchmarking/src/lib.rs index 0efbdcd48ecf3..894a725b5ce2f 100644 --- a/frame/offences/benchmarking/src/lib.rs +++ b/frame/offences/benchmarking/src/lib.rs @@ -335,6 +335,12 @@ benchmarks! { let balance_slash = |id| core::iter::once( ::RuntimeEvent::from(pallet_balances::Event::::Slashed{ who: id, amount: slash_amount.into() }) ); + let balance_locked = |id| core::iter::once( + ::RuntimeEvent::from(pallet_balances::Event::::Locked{ who: id, amount: slash_amount.into() }) + ); + let balance_unlocked = |id| core::iter::once( + ::RuntimeEvent::from(pallet_balances::Event::::Unlocked{ who: id, amount: slash_amount.into() }) + ); let chill = |id| core::iter::once( ::RuntimeEvent::from(StakingEvent::::Chilled{ stash: id }) ); @@ -349,12 +355,15 @@ benchmarks! { let slash_events = raw_offenders.into_iter() .flat_map(|offender| { let nom_slashes = offender.nominator_stashes.into_iter().flat_map(|nom| { - balance_slash(nom.clone()).map(Into::into).chain(slash(nom).map(Into::into)).map(Box::new) + balance_slash(nom.clone()).map(Into::into) + .chain(balance_unlocked(nom.clone()).map(Into::into)) + .chain(slash(nom).map(Into::into)).map(Box::new) }); let events = chill(offender.stash.clone()).map(Into::into).map(Box::new) .chain(slash_report(offender.stash.clone()).map(Into::into).map(Box::new)) .chain(balance_slash(offender.stash.clone()).map(Into::into).map(Box::new)) + .chain(balance_unlocked(offender.stash.clone()).map(Into::into).map(Box::new)) .chain(slash(offender.stash).map(Into::into).map(Box::new)) .chain(nom_slashes) .collect::>(); diff --git a/frame/offences/benchmarking/src/mock.rs b/frame/offences/benchmarking/src/mock.rs index 058361e9f77e8..668d88e0bf3d0 100644 --- a/frame/offences/benchmarking/src/mock.rs +++ b/frame/offences/benchmarking/src/mock.rs @@ -65,7 +65,7 @@ impl frame_system::Config for Test { } impl pallet_balances::Config for Test { - type MaxLocks = (); + type MaxLocks = ConstU32<128>; type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type Balance = Balance; From aeefc8bda0c0eecc67ca2d5ad24665ff27191968 Mon Sep 17 00:00:00 2001 From: yjh Date: Mon, 27 Mar 2023 06:07:17 +0800 Subject: [PATCH 569/715] chore(sc-cli): improve runner and signals (#13688) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore(sc-cli): improve runner and signals * Update client/cli/src/runner.rs * fmt --------- Co-authored-by: Bastian Köcher --- client/cli/src/lib.rs | 2 + client/cli/src/runner.rs | 101 +++++--------------------------------- client/cli/src/signals.rs | 92 ++++++++++++++++++++++++++++++++++ 3 files changed, 106 insertions(+), 89 deletions(-) create mode 100644 client/cli/src/signals.rs diff --git a/client/cli/src/lib.rs b/client/cli/src/lib.rs index e73321ecce5b3..5d451bbed6562 100644 --- a/client/cli/src/lib.rs +++ b/client/cli/src/lib.rs @@ -31,6 +31,7 @@ mod config; mod error; mod params; mod runner; +mod signals; pub use arg_enums::*; pub use clap; @@ -41,6 +42,7 @@ pub use params::*; pub use runner::*; pub use sc_service::{ChainSpec, Role}; pub use sc_tracing::logging::LoggerBuilder; +pub use signals::Signals; pub use sp_version::RuntimeVersion; /// Substrate client CLI diff --git a/client/cli/src/runner.rs b/client/cli/src/runner.rs index 3d216aef4a75c..a8b75f2665aea 100644 --- a/client/cli/src/runner.rs +++ b/client/cli/src/runner.rs @@ -16,80 +16,15 @@ // 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, Result, SubstrateCli}; +use crate::{error::Error as CliError, Result, Signals, SubstrateCli}; use chrono::prelude::*; -use futures::{ - future::{self, BoxFuture, FutureExt}, - pin_mut, select, Future, -}; +use futures::{future::FutureExt, 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, time::Duration}; -/// Abstraction over OS signals to handle the shutdown of the node smoothly. -/// -/// On `unix` this represents `SigInt` and `SigTerm`. -pub struct Signals(BoxFuture<'static, ()>); - -impl Signals { - /// Capture the relevant signals to handle shutdown of the node smoothly. - /// - /// Needs to be called in a Tokio context to have access to the tokio reactor. - #[cfg(target_family = "unix")] - pub fn capture() -> std::result::Result { - use tokio::signal::unix::{signal, SignalKind}; - - let mut stream_int = signal(SignalKind::interrupt()).map_err(ServiceError::Io)?; - let mut stream_term = signal(SignalKind::terminate()).map_err(ServiceError::Io)?; - - Ok(Signals( - async move { - future::select(stream_int.recv().boxed(), stream_term.recv().boxed()).await; - } - .boxed(), - )) - } - - /// Capture the relevant signals to handle shutdown of the node smoothly. - /// - /// Needs to be called in a Tokio context to have access to the tokio reactor. - #[cfg(not(unix))] - pub fn capture() -> std::result::Result { - use tokio::signal::ctrl_c; - - Ok(Signals( - async move { - let _ = ctrl_c().await; - } - .boxed(), - )) - } - - /// A dummy signal that never returns. - pub fn dummy() -> Self { - Self(future::pending().boxed()) - } -} - -async fn main(func: F, signals: impl Future) -> std::result::Result<(), E> -where - F: Future> + future::FusedFuture, - E: std::error::Error + Send + Sync + 'static, -{ - let signals = signals.fuse(); - - pin_mut!(func, signals); - - select! { - _ = signals => {}, - res = func => res?, - } - - Ok(()) -} - -/// Build a tokio runtime with all features +/// Build a tokio runtime with all features. pub fn build_runtime() -> std::result::Result { tokio::runtime::Builder::new_multi_thread() .on_thread_start(|| { @@ -103,25 +38,6 @@ pub fn build_runtime() -> std::result::Result( - tokio_runtime: tokio::runtime::Runtime, - future: F, - task_manager: TaskManager, - signals: impl Future, -) -> std::result::Result<(), E> -where - F: Future> + future::Future, - E: std::error::Error + Send + Sync + 'static + From, -{ - let f = future.fuse(); - pin_mut!(f); - - tokio_runtime.block_on(main(f, signals))?; - drop(task_manager); - - Ok(()) -} - /// A Substrate CLI runtime that can be used to run a node or a command pub struct Runner { config: Configuration, @@ -171,7 +87,10 @@ 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.signals.0)); + + let res = self + .tokio_runtime + .block_on(self.signals.run_until_signal(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 @@ -234,7 +153,11 @@ impl Runner { E: std::error::Error + Send + Sync + 'static + From + From, { let (future, task_manager) = runner(self.config)?; - run_until_exit::<_, E>(self.tokio_runtime, future, task_manager, self.signals.0) + self.tokio_runtime.block_on(self.signals.run_until_signal(future.fuse()))?; + // Drop the task manager before dropping the rest, to ensure that all futures were informed + // about the shut down. + drop(task_manager); + Ok(()) } /// Get an immutable reference to the node Configuration diff --git a/client/cli/src/signals.rs b/client/cli/src/signals.rs new file mode 100644 index 0000000000000..4b6a6f957a766 --- /dev/null +++ b/client/cli/src/signals.rs @@ -0,0 +1,92 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use futures::{ + future::{self, BoxFuture, FutureExt}, + pin_mut, select, Future, +}; + +use sc_service::Error as ServiceError; + +/// Abstraction over OS signals to handle the shutdown of the node smoothly. +/// +/// On `unix` this represents `SigInt` and `SigTerm`. +pub struct Signals(BoxFuture<'static, ()>); + +impl Signals { + /// Return the signals future. + pub fn future(self) -> BoxFuture<'static, ()> { + self.0 + } + + /// Capture the relevant signals to handle shutdown of the node smoothly. + /// + /// Needs to be called in a Tokio context to have access to the tokio reactor. + #[cfg(target_family = "unix")] + pub fn capture() -> std::result::Result { + use tokio::signal::unix::{signal, SignalKind}; + + let mut stream_int = signal(SignalKind::interrupt()).map_err(ServiceError::Io)?; + let mut stream_term = signal(SignalKind::terminate()).map_err(ServiceError::Io)?; + + Ok(Signals( + async move { + future::select(stream_int.recv().boxed(), stream_term.recv().boxed()).await; + } + .boxed(), + )) + } + + /// Capture the relevant signals to handle shutdown of the node smoothly. + /// + /// Needs to be called in a Tokio context to have access to the tokio reactor. + #[cfg(not(unix))] + pub fn capture() -> Result { + use tokio::signal::ctrl_c; + + Ok(Signals( + async move { + let _ = ctrl_c().await; + } + .boxed(), + )) + } + + /// A dummy signal that never returns. + pub fn dummy() -> Self { + Self(future::pending().boxed()) + } + + /// Run a future task until receive a signal. + pub async fn run_until_signal(self, func: F) -> Result<(), E> + where + F: Future> + future::FusedFuture, + E: std::error::Error + Send + Sync + 'static, + { + let signals = self.future().fuse(); + + pin_mut!(func, signals); + + select! { + _ = signals => {}, + res = func => res?, + } + + Ok(()) + } +} From 83c81985521b9f956890539d8b62371c40093c60 Mon Sep 17 00:00:00 2001 From: Mira Ressel Date: Mon, 27 Mar 2023 07:23:53 +0200 Subject: [PATCH 570/715] add a new ci job to fuzz sp-arithmetic (#13673) as requested in https://github.com/paritytech/ci_cd/issues/761 --- scripts/ci/gitlab/pipeline/test.yml | 36 +++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/scripts/ci/gitlab/pipeline/test.yml b/scripts/ci/gitlab/pipeline/test.yml index 7c5f43c291ea7..b5c37d243f1b3 100644 --- a/scripts/ci/gitlab/pipeline/test.yml +++ b/scripts/ci/gitlab/pipeline/test.yml @@ -432,3 +432,39 @@ cargo-check-each-crate-macos: - time cargo check --workspace --locked tags: - osx + +cargo-hfuzz: + stage: test + extends: + - .docker-env + - .test-refs + - .pipeline-stopper-artifacts + variables: + # max 10s per iteration, 60s per file + HFUZZ_RUN_ARGS: > + --exit_upon_crash + --exit_code_upon_crash 1 + --timeout 10 + --run_time 60 + artifacts: + name: "hfuzz-$CI_COMMIT_SHORT_SHA" + expire_in: 7 days + when: on_failure + paths: + - primitives/arithmetic/fuzzer/hfuzz_workspace/ + script: + # use git version of honggfuzz-rs until v0.5.56 is out, we need a few recent changes: + # https://github.com/rust-fuzz/honggfuzz-rs/pull/75 to avoid breakage on debian + # https://github.com/rust-fuzz/honggfuzz-rs/pull/81 fix to the above pr + # https://github.com/rust-fuzz/honggfuzz-rs/pull/82 fix for handling rusty-cachier's absolute CARGO_TARGET_DIR + - | + cat >>Cargo.toml < Date: Mon, 27 Mar 2023 09:50:31 +0200 Subject: [PATCH 571/715] sc-slots: Forward block size limit (#13716) --- client/consensus/slots/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/consensus/slots/src/lib.rs b/client/consensus/slots/src/lib.rs index e4147340793a4..5057e7858a0bc 100644 --- a/client/consensus/slots/src/lib.rs +++ b/client/consensus/slots/src/lib.rs @@ -217,7 +217,7 @@ pub trait SimpleSlotWorker { inherent_data, sp_runtime::generic::Digest { logs }, proposing_remaining_duration.mul_f32(0.98), - None, + slot_info.block_size_limit, ) .map_err(|e| sp_consensus::Error::ClientImport(e.to_string())); From bede15d5085fd5741e2522f85f36a7ec45cd9554 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Mon, 27 Mar 2023 14:04:24 +0200 Subject: [PATCH 572/715] FRAME: Fix the Referenda confirming alarm (#13704) * Fix the Referenda confirming alarm * Add minimal regression test This fails on bf395c8308c481a9774373e0b0b14bd7a2e4b8d2 since the downwards rounding voids the curve delay. Signed-off-by: Oliver Tale-Yazdi --------- Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Oliver Tale-Yazdi --- frame/referenda/src/lib.rs | 2 +- frame/referenda/src/tests.rs | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/frame/referenda/src/lib.rs b/frame/referenda/src/lib.rs index f699850062267..b96cf5a76733d 100644 --- a/frame/referenda/src/lib.rs +++ b/frame/referenda/src/lib.rs @@ -1206,7 +1206,7 @@ impl, I: 'static> Pallet { let until_approval = track.min_approval.delay(approval); let until_support = track.min_support.delay(support); let offset = until_support.max(until_approval); - deciding.since.saturating_add(offset * track.decision_period) + deciding.since.saturating_add(offset.mul_ceil(track.decision_period)) }) } diff --git a/frame/referenda/src/tests.rs b/frame/referenda/src/tests.rs index f728350c37e6f..0a1561d001a7d 100644 --- a/frame/referenda/src/tests.rs +++ b/frame/referenda/src/tests.rs @@ -286,6 +286,24 @@ fn alarm_interval_works() { }); } +#[test] +fn decision_time_is_correct() { + new_test_ext().execute_with(|| { + let decision_time = |since: u64| { + Pallet::::decision_time( + &DecidingStatus { since: since.into(), confirming: None }, + &Tally { ayes: 100, nays: 5 }, + TestTracksInfo::tracks()[0].0, + &TestTracksInfo::tracks()[0].1, + ) + }; + + for i in 0u64..=100 { + assert!(decision_time(i) > i, "The decision time should be delayed by the curve"); + } + }); +} + #[test] fn auto_timeout_should_happen_with_nothing_but_submit() { new_test_ext().execute_with(|| { From 8f0414c761486eb6cea2a091ebdb3d3efbdebb9b Mon Sep 17 00:00:00 2001 From: Aaron Bassett Date: Mon, 27 Mar 2023 16:03:04 +0200 Subject: [PATCH 573/715] Update pallet licenses to Apache-2.0 (#13467) --- frame/fast-unstake/Cargo.toml | 2 +- frame/scheduler/README.md | 2 +- frame/transaction-storage/Cargo.toml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/frame/fast-unstake/Cargo.toml b/frame/fast-unstake/Cargo.toml index 36b4c3a5ec1cb..8e4df2f2b9eb5 100644 --- a/frame/fast-unstake/Cargo.toml +++ b/frame/fast-unstake/Cargo.toml @@ -3,7 +3,7 @@ name = "pallet-fast-unstake" 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 fast unstake pallet" diff --git a/frame/scheduler/README.md b/frame/scheduler/README.md index 9a209031d7402..bdd2c2226c88e 100644 --- a/frame/scheduler/README.md +++ b/frame/scheduler/README.md @@ -31,4 +31,4 @@ then those filter will not be used when dispatching the schedule call. `Vec` parameter that can be used for identification. * `cancel_named` - the named complement to the cancel function. -License: Unlicense +License: Apache 2.0 diff --git a/frame/transaction-storage/Cargo.toml b/frame/transaction-storage/Cargo.toml index 527ff4f240169..c23be8194d87f 100644 --- a/frame/transaction-storage/Cargo.toml +++ b/frame/transaction-storage/Cargo.toml @@ -3,7 +3,7 @@ name = "pallet-transaction-storage" 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 = "Storage chain pallet" From 46bdb43422007619c4efa4b03e32ad7b2f9b282e Mon Sep 17 00:00:00 2001 From: Ross Bulat Date: Mon, 27 Mar 2023 16:02:03 +0100 Subject: [PATCH 574/715] Reward pool migration fix (#13715) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * reward pool migration fix * comment * remove generic * rm max * foramtting * Add note to V4 migration Signed-off-by: Oliver Tale-Yazdi * Add more asserts to the V5 migration Signed-off-by: Oliver Tale-Yazdi * Make compile Signed-off-by: Oliver Tale-Yazdi * Update frame/nomination-pools/src/migration.rs Co-authored-by: Gonçalo Pestana * Make V4 migration re-usable Otherwise it wont chain together with the V5. Signed-off-by: Oliver Tale-Yazdi * Add MigrateV3ToV5 wrapper Signed-off-by: Oliver Tale-Yazdi --------- Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Oliver Tale-Yazdi Co-authored-by: Gonçalo Pestana --- frame/nomination-pools/src/lib.rs | 2 +- frame/nomination-pools/src/migration.rs | 162 +++++++++++++++++++++++- 2 files changed, 161 insertions(+), 3 deletions(-) diff --git a/frame/nomination-pools/src/lib.rs b/frame/nomination-pools/src/lib.rs index e73d4b4173ecf..cfde05ffeeabe 100644 --- a/frame/nomination-pools/src/lib.rs +++ b/frame/nomination-pools/src/lib.rs @@ -1496,7 +1496,7 @@ pub mod pallet { use sp_runtime::Perbill; /// The current storage version. - const STORAGE_VERSION: StorageVersion = StorageVersion::new(4); + const STORAGE_VERSION: StorageVersion = StorageVersion::new(5); #[pallet::pallet] #[pallet::storage_version(STORAGE_VERSION)] diff --git a/frame/nomination-pools/src/migration.rs b/frame/nomination-pools/src/migration.rs index f6f166d7f5de2..45d6424119900 100644 --- a/frame/nomination-pools/src/migration.rs +++ b/frame/nomination-pools/src/migration.rs @@ -478,9 +478,22 @@ pub mod v4 { } } + /// Migrates from `v3` directly to `v5` to avoid the broken `v4` migration. + #[allow(deprecated)] + pub type MigrateV3ToV5 = (v4::MigrateToV4, v5::MigrateToV5); + + /// # Warning + /// + /// To avoid mangled storage please use `MigrateV3ToV5` instead. + /// See: github.com/paritytech/substrate/pull/13715 + /// /// This migration adds a `commission` field to every `BondedPoolInner`, if /// any. + #[deprecated( + note = "To avoid mangled storage please use `MigrateV3ToV5` instead. See: github.com/paritytech/substrate/pull/13715" + )] pub struct MigrateToV4(sp_std::marker::PhantomData<(T, U)>); + #[allow(deprecated)] impl> OnRuntimeUpgrade for MigrateToV4 { fn on_runtime_upgrade() -> Weight { let current = Pallet::::current_storage_version(); @@ -493,7 +506,8 @@ pub mod v4 { onchain ); - if current == 4 && onchain == 3 { + if onchain == 3 { + log!(warn, "Please run MigrateToV5 immediately after this migration. See github.com/paritytech/substrate/pull/13715"); let initial_global_max_commission = U::get(); GlobalMaxCommission::::set(Some(initial_global_max_commission)); log!( @@ -508,7 +522,7 @@ pub mod v4 { Some(old_value.migrate_to_v4()) }); - current.put::>(); + StorageVersion::new(4).put::>(); log!(info, "Upgraded {} pools, storage to version {:?}", translated, current); // reads: translated + onchain version. @@ -548,3 +562,147 @@ pub mod v4 { } } } + +pub mod v5 { + use super::*; + + #[derive(Decode)] + pub struct OldRewardPool { + last_recorded_reward_counter: T::RewardCounter, + last_recorded_total_payouts: BalanceOf, + total_rewards_claimed: BalanceOf, + } + + impl OldRewardPool { + fn migrate_to_v5(self) -> RewardPool { + RewardPool { + last_recorded_reward_counter: self.last_recorded_reward_counter, + last_recorded_total_payouts: self.last_recorded_total_payouts, + total_rewards_claimed: self.total_rewards_claimed, + total_commission_pending: Zero::zero(), + total_commission_claimed: Zero::zero(), + } + } + } + + /// This migration adds `total_commission_pending` and `total_commission_claimed` field to every + /// `RewardPool`, if any. + pub struct MigrateToV5(sp_std::marker::PhantomData); + impl OnRuntimeUpgrade for MigrateToV5 { + fn on_runtime_upgrade() -> Weight { + let current = Pallet::::current_storage_version(); + let onchain = Pallet::::on_chain_storage_version(); + + log!( + info, + "Running migration with current storage version {:?} / onchain {:?}", + current, + onchain + ); + + if current == 5 && onchain == 4 { + let mut translated = 0u64; + RewardPools::::translate::, _>(|_id, old_value| { + translated.saturating_inc(); + Some(old_value.migrate_to_v5()) + }); + + current.put::>(); + log!(info, "Upgraded {} pools, storage to version {:?}", translated, current); + + // reads: translated + onchain version. + // writes: translated + current.put. + T::DbWeight::get().reads_writes(translated + 1, translated + 1) + } else { + log!(info, "Migration did not execute. This probably should be removed"); + T::DbWeight::get().reads(1) + } + } + + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, &'static str> { + ensure!( + Pallet::::current_storage_version() > Pallet::::on_chain_storage_version(), + "the on_chain version is equal or more than the current one" + ); + + let rpool_keys = RewardPools::::iter_keys().count(); + let rpool_values = RewardPools::::iter_values().count(); + if rpool_keys != rpool_values { + log!(info, "🔥 There are {} undecodable RewardPools in storage. This migration will try to correct them. keys: {}, values: {}", rpool_keys.saturating_sub(rpool_values), rpool_keys, rpool_values); + } + + ensure!( + PoolMembers::::iter_keys().count() == PoolMembers::::iter_values().count(), + "There are undecodable PoolMembers in storage. This migration will not fix that." + ); + ensure!( + BondedPools::::iter_keys().count() == BondedPools::::iter_values().count(), + "There are undecodable BondedPools in storage. This migration will not fix that." + ); + ensure!( + SubPoolsStorage::::iter_keys().count() == + SubPoolsStorage::::iter_values().count(), + "There are undecodable SubPools in storage. This migration will not fix that." + ); + ensure!( + Metadata::::iter_keys().count() == Metadata::::iter_values().count(), + "There are undecodable Metadata in storage. This migration will not fix that." + ); + + Ok((rpool_values as u64).encode()) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(data: Vec) -> Result<(), &'static str> { + let old_rpool_values: u64 = Decode::decode(&mut &data[..]).unwrap(); + let rpool_keys = RewardPools::::iter_keys().count() as u64; + let rpool_values = RewardPools::::iter_values().count() as u64; + ensure!( + rpool_keys == rpool_values, + "There are STILL undecodable RewardPools - migration failed" + ); + + if old_rpool_values != rpool_values { + log!( + info, + "🎉 Fixed {} undecodable RewardPools.", + rpool_values.saturating_sub(old_rpool_values) + ); + } + + // ensure all RewardPools items now contain `total_commission_pending` and + // `total_commission_claimed` field. + ensure!( + RewardPools::::iter().all(|(_, reward_pool)| reward_pool + .total_commission_pending + .is_zero() && reward_pool + .total_commission_claimed + .is_zero()), + "a commission value has been incorrectly set" + ); + ensure!(Pallet::::on_chain_storage_version() == 5, "wrong storage version"); + + // These should not have been touched - just in case. + ensure!( + PoolMembers::::iter_keys().count() == PoolMembers::::iter_values().count(), + "There are undecodable PoolMembers in storage." + ); + ensure!( + BondedPools::::iter_keys().count() == BondedPools::::iter_values().count(), + "There are undecodable BondedPools in storage." + ); + ensure!( + SubPoolsStorage::::iter_keys().count() == + SubPoolsStorage::::iter_values().count(), + "There are undecodable SubPools in storage." + ); + ensure!( + Metadata::::iter_keys().count() == Metadata::::iter_values().count(), + "There are undecodable Metadata in storage." + ); + + Ok(()) + } + } +} From f2c12fd68a0d225864baec488136a2334070d712 Mon Sep 17 00:00:00 2001 From: PG Herveou Date: Mon, 27 Mar 2023 19:33:59 +0200 Subject: [PATCH 575/715] contracts: Add host function tracing (#13648) --- frame/contracts/README.md | 12 + frame/contracts/proc-macro/src/lib.rs | 36 +- frame/contracts/src/wasm/runtime.rs | 1 + frame/contracts/src/weights.rs | 1818 +++++++++++++------------ 4 files changed, 959 insertions(+), 908 deletions(-) diff --git a/frame/contracts/README.md b/frame/contracts/README.md index 9b1d3f7d6de08..4f5f10a3af333 100644 --- a/frame/contracts/README.md +++ b/frame/contracts/README.md @@ -135,6 +135,18 @@ to `error` in order to prevent them from spamming the console. `--dev`: Use a dev chain spec `--tmp`: Use temporary storage for chain data (the chain state is deleted on exit) +## Host function tracing + +For contract authors, it can be a helpful debugging tool to see which host functions are called, with which arguments, and what the result was. + +In order to see these messages on the node console, the log level for the `runtime::contracts::strace` target needs to be raised to the `trace` level. + +Example: + +```bash +cargo run --release -- --dev -lerror,runtime::contracts::strace=trace,runtime::contracts=debug +``` + ## Unstable Interfaces Driven by the desire to have an iterative approach in developing new contract interfaces diff --git a/frame/contracts/proc-macro/src/lib.rs b/frame/contracts/proc-macro/src/lib.rs index 32241068fe23f..d54470dd06f97 100644 --- a/frame/contracts/proc-macro/src/lib.rs +++ b/frame/contracts/proc-macro/src/lib.rs @@ -596,6 +596,7 @@ fn expand_functions(def: &EnvDef, expand_blocks: bool, host_state: 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, @@ -606,6 +607,39 @@ fn expand_functions(def: &EnvDef, expand_blocks: bool, host_state: TokenStream2) let is_stable = f.is_stable; let not_deprecated = f.not_deprecated; + // wrapped host function body call with host function traces + // see https://github.com/paritytech/substrate/tree/master/frame/contracts#host-function-tracing + let wrapped_body_with_trace = { + let trace_fmt_args = params.clone().filter_map(|arg| match arg { + syn::FnArg::Receiver(_) => None, + syn::FnArg::Typed(p) => { + match *p.pat.clone() { + syn::Pat::Ident(ref pat_ident) => Some(pat_ident.ident.clone()), + _ => None, + } + }, + }); + + let params_fmt_str = trace_fmt_args.clone().map(|s| format!("{s}: {{:?}}")).collect::>().join(", "); + let trace_fmt_str = format!("{}::{}({}) = {{:?}}\n", module, name, params_fmt_str); + + quote! { + if ::log::log_enabled!(target: "runtime::contracts::strace", ::log::Level::Trace) { + let result = #body; + { + use sp_std::fmt::Write; + let mut w = sp_std::Writer::default(); + let _ = core::write!(&mut w, #trace_fmt_str, #( #trace_fmt_args, )* result); + let msg = core::str::from_utf8(&w.inner()).unwrap_or_default(); + ctx.ext().append_debug_buffer(msg); + } + result + } else { + #body + } + } + }; + // 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 @@ -617,7 +651,7 @@ fn expand_functions(def: &EnvDef, expand_blocks: bool, host_state: TokenStream2) .memory() .expect("Memory must be set when setting up host data; qed") .data_and_store_mut(&mut __caller__); - #body + #wrapped_body_with_trace } } } else { quote! { || -> #wasm_output { diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index 43a029eadfc07..88b5b87dda411 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -84,6 +84,7 @@ enum KeyType { /// will not be changed or removed. This means that any contract **must not** exhaustively /// match return codes. Instead, contracts should prepare for unknown variants and deal with /// those errors gracefully in order to be forward compatible. +#[derive(Debug)] #[repr(u32)] pub enum ReturnCode { /// API call successful. diff --git a/frame/contracts/src/weights.rs b/frame/contracts/src/weights.rs index dfe6fb20de7bc..9e37a238b7d59 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: 2023-03-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -177,8 +177,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `109` // Estimated: `1594` - // Minimum execution time: 2_585_000 picoseconds. - Weight::from_parts(2_802_000, 1594) + // Minimum execution time: 2_713_000 picoseconds. + Weight::from_parts(2_811_000, 1594) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: Skipped Metadata (r:0 w:0) @@ -188,10 +188,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `450 + k * (69 ±0)` // Estimated: `440 + k * (70 ±0)` - // Minimum execution time: 10_825_000 picoseconds. - Weight::from_parts(5_747_064, 440) - // Standard Error: 1_037 - .saturating_add(Weight::from_parts(973_689, 0).saturating_mul(k.into())) + // Minimum execution time: 11_011_000 picoseconds. + Weight::from_parts(7_025_244, 440) + // Standard Error: 1_217 + .saturating_add(Weight::from_parts(980_818, 0).saturating_mul(k.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) @@ -205,10 +205,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `250 + q * (33 ±0)` // Estimated: `1725 + q * (33 ±0)` - // Minimum execution time: 2_718_000 picoseconds. - Weight::from_parts(11_436_305, 1725) - // Standard Error: 3_619 - .saturating_add(Weight::from_parts(1_296_955, 0).saturating_mul(q.into())) + // Minimum execution time: 2_802_000 picoseconds. + Weight::from_parts(10_768_336, 1725) + // Standard Error: 3_424 + .saturating_add(Weight::from_parts(1_323_649, 0).saturating_mul(q.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 33).saturating_mul(q.into())) @@ -222,10 +222,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `238 + c * (1 ±0)` // Estimated: `3951 + c * (2 ±0)` - // Minimum execution time: 37_882_000 picoseconds. - Weight::from_parts(43_548_816, 3951) - // Standard Error: 49 - .saturating_add(Weight::from_parts(53_936, 0).saturating_mul(c.into())) + // Minimum execution time: 30_299_000 picoseconds. + Weight::from_parts(24_608_986, 3951) + // Standard Error: 75 + .saturating_add(Weight::from_parts(54_619, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 2).saturating_mul(c.into())) @@ -245,10 +245,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `707` // Estimated: `21400 + c * (5 ±0)` - // Minimum execution time: 313_392_000 picoseconds. - Weight::from_parts(325_419_093, 21400) - // Standard Error: 25 - .saturating_add(Weight::from_parts(37_877, 0).saturating_mul(c.into())) + // Minimum execution time: 265_835_000 picoseconds. + Weight::from_parts(275_985_164, 21400) + // Standard Error: 36 + .saturating_add(Weight::from_parts(37_980, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 5).saturating_mul(c.into())) @@ -276,14 +276,14 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `270` // Estimated: `26207` - // Minimum execution time: 3_274_352_000 picoseconds. - Weight::from_parts(681_171_416, 26207) - // Standard Error: 336 - .saturating_add(Weight::from_parts(106_391, 0).saturating_mul(c.into())) - // Standard Error: 19 - .saturating_add(Weight::from_parts(1_147, 0).saturating_mul(i.into())) - // Standard Error: 19 - .saturating_add(Weight::from_parts(1_493, 0).saturating_mul(s.into())) + // Minimum execution time: 3_124_508_000 picoseconds. + Weight::from_parts(617_467_897, 26207) + // Standard Error: 293 + .saturating_add(Weight::from_parts(106_971, 0).saturating_mul(c.into())) + // Standard Error: 17 + .saturating_add(Weight::from_parts(1_156, 0).saturating_mul(i.into())) + // Standard Error: 17 + .saturating_add(Weight::from_parts(1_395, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(10_u64)) } @@ -307,12 +307,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `482` // Estimated: `28521` - // Minimum execution time: 1_692_637_000 picoseconds. - Weight::from_parts(283_252_265, 28521) + // Minimum execution time: 1_649_483_000 picoseconds. + Weight::from_parts(287_642_416, 28521) // Standard Error: 8 - .saturating_add(Weight::from_parts(1_498, 0).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(1_450, 0).saturating_mul(i.into())) // Standard Error: 8 - .saturating_add(Weight::from_parts(1_487, 0).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_443, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } @@ -330,8 +330,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `759` // Estimated: `21615` - // Minimum execution time: 192_369_000 picoseconds. - Weight::from_parts(193_417_000, 21615) + // Minimum execution time: 192_302_000 picoseconds. + Weight::from_parts(193_192_000, 21615) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -348,10 +348,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `109` // Estimated: `7366` - // Minimum execution time: 301_972_000 picoseconds. - Weight::from_parts(313_248_051, 7366) - // Standard Error: 82 - .saturating_add(Weight::from_parts(107_321, 0).saturating_mul(c.into())) + // Minimum execution time: 246_401_000 picoseconds. + Weight::from_parts(261_505_456, 7366) + // Standard Error: 83 + .saturating_add(Weight::from_parts(109_136, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -367,8 +367,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `255` // Estimated: `7950` - // Minimum execution time: 33_013_000 picoseconds. - Weight::from_parts(33_622_000, 7950) + // Minimum execution time: 33_913_000 picoseconds. + Weight::from_parts(34_186_000, 7950) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -382,8 +382,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `570` // Estimated: `19530` - // Minimum execution time: 33_518_000 picoseconds. - Weight::from_parts(33_819_000, 19530) + // Minimum execution time: 33_801_000 picoseconds. + Weight::from_parts(34_877_000, 19530) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -402,10 +402,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `781 + r * (6 ±0)` // Estimated: `21730 + r * (30 ±0)` - // Minimum execution time: 283_945_000 picoseconds. - Weight::from_parts(289_209_599, 21730) - // Standard Error: 901 - .saturating_add(Weight::from_parts(327_601, 0).saturating_mul(r.into())) + // Minimum execution time: 237_679_000 picoseconds. + Weight::from_parts(243_022_905, 21730) + // Standard Error: 940 + .saturating_add(Weight::from_parts(324_389, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -425,10 +425,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `839 + r * (240 ±0)` // Estimated: `21835 + r * (3675 ±0)` - // Minimum execution time: 284_949_000 picoseconds. - Weight::from_parts(126_196_485, 21835) - // Standard Error: 6_260 - .saturating_add(Weight::from_parts(3_368_849, 0).saturating_mul(r.into())) + // Minimum execution time: 235_635_000 picoseconds. + Weight::from_parts(76_942_144, 21835) + // Standard Error: 6_214 + .saturating_add(Weight::from_parts(3_328_756, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -449,10 +449,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `831 + r * (244 ±0)` // Estimated: `21855 + r * (3695 ±0)` - // Minimum execution time: 286_429_000 picoseconds. - Weight::from_parts(124_820_396, 21855) - // Standard Error: 6_539 - .saturating_add(Weight::from_parts(4_163_535, 0).saturating_mul(r.into())) + // Minimum execution time: 237_123_000 picoseconds. + Weight::from_parts(77_880_739, 21855) + // Standard Error: 5_970 + .saturating_add(Weight::from_parts(4_103_281, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -473,10 +473,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `788 + r * (6 ±0)` // Estimated: `21770 + r * (30 ±0)` - // Minimum execution time: 285_042_000 picoseconds. - Weight::from_parts(288_096_303, 21770) - // Standard Error: 972 - .saturating_add(Weight::from_parts(409_782, 0).saturating_mul(r.into())) + // Minimum execution time: 236_621_000 picoseconds. + Weight::from_parts(238_240_015, 21770) + // Standard Error: 742 + .saturating_add(Weight::from_parts(404_691, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -496,10 +496,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `778 + r * (3 ±0)` // Estimated: `21735 + r * (15 ±0)` - // Minimum execution time: 282_820_000 picoseconds. - Weight::from_parts(287_104_710, 21735) - // Standard Error: 421 - .saturating_add(Weight::from_parts(167_907, 0).saturating_mul(r.into())) + // Minimum execution time: 233_274_000 picoseconds. + Weight::from_parts(239_596_227, 21735) + // Standard Error: 551 + .saturating_add(Weight::from_parts(164_429, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 15).saturating_mul(r.into())) @@ -519,10 +519,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `782 + r * (6 ±0)` // Estimated: `21740 + r * (30 ±0)` - // Minimum execution time: 284_619_000 picoseconds. - Weight::from_parts(281_326_785, 21740) - // Standard Error: 1_379 - .saturating_add(Weight::from_parts(342_779, 0).saturating_mul(r.into())) + // Minimum execution time: 235_661_000 picoseconds. + Weight::from_parts(239_063_406, 21740) + // Standard Error: 933 + .saturating_add(Weight::from_parts(327_679, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -542,10 +542,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `783 + r * (6 ±0)` // Estimated: `21725 + r * (30 ±0)` - // Minimum execution time: 284_703_000 picoseconds. - Weight::from_parts(289_479_932, 21725) - // Standard Error: 745 - .saturating_add(Weight::from_parts(323_625, 0).saturating_mul(r.into())) + // Minimum execution time: 235_583_000 picoseconds. + Weight::from_parts(251_641_549, 21725) + // Standard Error: 1_104 + .saturating_add(Weight::from_parts(315_873, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -565,10 +565,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `922 + r * (6 ±0)` // Estimated: `24633 + r * (30 ±0)` - // Minimum execution time: 283_610_000 picoseconds. - Weight::from_parts(299_901_534, 24633) - // Standard Error: 1_177 - .saturating_add(Weight::from_parts(1_474_603, 0).saturating_mul(r.into())) + // Minimum execution time: 235_325_000 picoseconds. + Weight::from_parts(256_582_010, 24633) + // Standard Error: 1_349 + .saturating_add(Weight::from_parts(1_483_116, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -588,10 +588,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `792 + r * (6 ±0)` // Estimated: `21825 + r * (30 ±0)` - // Minimum execution time: 284_474_000 picoseconds. - Weight::from_parts(283_540_273, 21825) - // Standard Error: 1_164 - .saturating_add(Weight::from_parts(339_262, 0).saturating_mul(r.into())) + // Minimum execution time: 235_358_000 picoseconds. + Weight::from_parts(233_421_484, 21825) + // Standard Error: 1_178 + .saturating_add(Weight::from_parts(337_947, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -611,10 +611,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `790 + r * (6 ±0)` // Estimated: `21815 + r * (30 ±0)` - // Minimum execution time: 284_521_000 picoseconds. - Weight::from_parts(285_747_754, 21815) - // Standard Error: 889 - .saturating_add(Weight::from_parts(326_428, 0).saturating_mul(r.into())) + // Minimum execution time: 236_570_000 picoseconds. + Weight::from_parts(245_853_078, 21815) + // Standard Error: 1_947 + .saturating_add(Weight::from_parts(319_972, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -634,10 +634,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `787 + r * (6 ±0)` // Estimated: `21805 + r * (30 ±0)` - // Minimum execution time: 284_103_000 picoseconds. - Weight::from_parts(283_801_256, 21805) - // Standard Error: 1_051 - .saturating_add(Weight::from_parts(334_081, 0).saturating_mul(r.into())) + // Minimum execution time: 235_027_000 picoseconds. + Weight::from_parts(239_719_689, 21805) + // Standard Error: 654 + .saturating_add(Weight::from_parts(326_988, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -657,10 +657,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `778 + r * (6 ±0)` // Estimated: `21735 + r * (30 ±0)` - // Minimum execution time: 284_187_000 picoseconds. - Weight::from_parts(289_414_364, 21735) - // Standard Error: 796 - .saturating_add(Weight::from_parts(324_603, 0).saturating_mul(r.into())) + // Minimum execution time: 236_547_000 picoseconds. + Weight::from_parts(239_390_326, 21735) + // Standard Error: 912 + .saturating_add(Weight::from_parts(327_495, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -682,10 +682,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `856 + r * (10 ±0)` // Estimated: `24446 + r * (60 ±0)` - // Minimum execution time: 284_953_000 picoseconds. - Weight::from_parts(290_535_752, 24446) - // Standard Error: 2_462 - .saturating_add(Weight::from_parts(1_361_518, 0).saturating_mul(r.into())) + // Minimum execution time: 235_710_000 picoseconds. + Weight::from_parts(238_998_789, 24446) + // Standard Error: 2_055 + .saturating_add(Weight::from_parts(1_373_992, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 60).saturating_mul(r.into())) @@ -705,10 +705,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `745 + r * (4 ±0)` // Estimated: `21555 + r * (20 ±0)` - // Minimum execution time: 160_775_000 picoseconds. - Weight::from_parts(164_652_364, 21555) - // Standard Error: 284 - .saturating_add(Weight::from_parts(132_574, 0).saturating_mul(r.into())) + // Minimum execution time: 161_133_000 picoseconds. + Weight::from_parts(167_097_346, 21555) + // Standard Error: 245 + .saturating_add(Weight::from_parts(128_503, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 20).saturating_mul(r.into())) @@ -728,10 +728,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `780 + r * (6 ±0)` // Estimated: `21740 + r * (30 ±0)` - // Minimum execution time: 284_072_000 picoseconds. - Weight::from_parts(288_418_644, 21740) - // Standard Error: 792 - .saturating_add(Weight::from_parts(272_881, 0).saturating_mul(r.into())) + // Minimum execution time: 234_790_000 picoseconds. + Weight::from_parts(242_392_710, 21740) + // Standard Error: 2_506 + .saturating_add(Weight::from_parts(273_470, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -751,10 +751,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `784` // Estimated: `21740` - // Minimum execution time: 286_671_000 picoseconds. - Weight::from_parts(292_151_662, 21740) - // Standard Error: 1 - .saturating_add(Weight::from_parts(638, 0).saturating_mul(n.into())) + // Minimum execution time: 236_837_000 picoseconds. + Weight::from_parts(237_860_073, 21740) + // Standard Error: 2 + .saturating_add(Weight::from_parts(602, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -773,10 +773,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `768 + r * (45 ±0)` // Estimated: `21660 + r * (225 ±0)` - // Minimum execution time: 280_334_000 picoseconds. - Weight::from_parts(283_487_571, 21660) - // Standard Error: 267_797 - .saturating_add(Weight::from_parts(3_803_128, 0).saturating_mul(r.into())) + // Minimum execution time: 232_047_000 picoseconds. + Weight::from_parts(234_629_293, 21660) + // Standard Error: 171_808 + .saturating_add(Weight::from_parts(663_306, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 225).saturating_mul(r.into())) @@ -796,10 +796,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `778` // Estimated: `21775` - // Minimum execution time: 284_004_000 picoseconds. - Weight::from_parts(283_681_350, 21775) + // Minimum execution time: 235_035_000 picoseconds. + Weight::from_parts(234_442_091, 21775) // Standard Error: 1 - .saturating_add(Weight::from_parts(232, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(185, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -822,10 +822,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `810 + r * (356 ±0)` // Estimated: `25511 + r * (15321 ±0)` - // Minimum execution time: 284_143_000 picoseconds. - Weight::from_parts(287_218_324, 25511) - // Standard Error: 343_611 - .saturating_add(Weight::from_parts(109_895_675, 0).saturating_mul(r.into())) + // Minimum execution time: 234_140_000 picoseconds. + Weight::from_parts(236_805_906, 25511) + // Standard Error: 435_181 + .saturating_add(Weight::from_parts(118_144_693, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((6_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -849,10 +849,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `825 + r * (10 ±0)` // Estimated: `24283 + r * (60 ±0)` - // Minimum execution time: 285_037_000 picoseconds. - Weight::from_parts(299_804_606, 24283) - // Standard Error: 5_518 - .saturating_add(Weight::from_parts(1_848_164, 0).saturating_mul(r.into())) + // Minimum execution time: 235_271_000 picoseconds. + Weight::from_parts(256_019_682, 24283) + // Standard Error: 2_016 + .saturating_add(Weight::from_parts(1_862_085, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 60).saturating_mul(r.into())) @@ -872,10 +872,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `778 + r * (10 ±0)` // Estimated: `21735 + r * (50 ±0)` - // Minimum execution time: 282_886_000 picoseconds. - Weight::from_parts(293_171_736, 21735) - // Standard Error: 2_171 - .saturating_add(Weight::from_parts(3_491_303, 0).saturating_mul(r.into())) + // Minimum execution time: 233_092_000 picoseconds. + Weight::from_parts(248_483_473, 21735) + // Standard Error: 2_182 + .saturating_add(Weight::from_parts(3_551_674, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 50).saturating_mul(r.into())) @@ -896,12 +896,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `797 + t * (32 ±0)` // Estimated: `21840 + t * (2640 ±0)` - // Minimum execution time: 300_675_000 picoseconds. - Weight::from_parts(296_092_420, 21840) - // Standard Error: 130_733 - .saturating_add(Weight::from_parts(2_487_957, 0).saturating_mul(t.into())) - // Standard Error: 36 - .saturating_add(Weight::from_parts(565, 0).saturating_mul(n.into())) + // Minimum execution time: 252_307_000 picoseconds. + Weight::from_parts(245_237_726, 21840) + // Standard Error: 79_824 + .saturating_add(Weight::from_parts(2_364_618, 0).saturating_mul(t.into())) + // Standard Error: 22 + .saturating_add(Weight::from_parts(636, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(t.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -923,10 +923,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `777 + r * (7 ±0)` // Estimated: `21725 + r * (35 ±0)` - // Minimum execution time: 166_638_000 picoseconds. - Weight::from_parts(171_353_083, 21725) - // Standard Error: 550 - .saturating_add(Weight::from_parts(238_768, 0).saturating_mul(r.into())) + // Minimum execution time: 165_367_000 picoseconds. + Weight::from_parts(170_164_725, 21725) + // Standard Error: 487 + .saturating_add(Weight::from_parts(237_281, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 35).saturating_mul(r.into())) @@ -946,10 +946,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `125728` // Estimated: `269977` - // Minimum execution time: 414_136_000 picoseconds. - Weight::from_parts(416_093_921, 269977) - // Standard Error: 3 - .saturating_add(Weight::from_parts(794, 0).saturating_mul(i.into())) + // Minimum execution time: 350_914_000 picoseconds. + Weight::from_parts(354_461_646, 269977) + // Standard Error: 1 + .saturating_add(Weight::from_parts(747, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -960,10 +960,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `845 + r * (292 ±0)` // Estimated: `843 + r * (293 ±0)` - // Minimum execution time: 285_920_000 picoseconds. - Weight::from_parts(184_945_789, 843) - // Standard Error: 9_604 - .saturating_add(Weight::from_parts(6_012_522, 0).saturating_mul(r.into())) + // Minimum execution time: 236_273_000 picoseconds. + Weight::from_parts(137_922_946, 843) + // Standard Error: 10_363 + .saturating_add(Weight::from_parts(6_034_776, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -977,10 +977,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1304` // Estimated: `1280` - // Minimum execution time: 299_772_000 picoseconds. - Weight::from_parts(333_451_106, 1280) - // Standard Error: 54 - .saturating_add(Weight::from_parts(579, 0).saturating_mul(n.into())) + // Minimum execution time: 251_462_000 picoseconds. + Weight::from_parts(287_009_907, 1280) + // Standard Error: 62 + .saturating_add(Weight::from_parts(384, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -991,10 +991,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1167 + n * (1 ±0)` // Estimated: `1167 + n * (1 ±0)` - // Minimum execution time: 299_279_000 picoseconds. - Weight::from_parts(302_336_567, 1167) - // Standard Error: 25 - .saturating_add(Weight::from_parts(86, 0).saturating_mul(n.into())) + // Minimum execution time: 250_985_000 picoseconds. + Weight::from_parts(253_693_249, 1167) + // Standard Error: 21 + .saturating_add(Weight::from_parts(92, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -1006,10 +1006,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `841 + r * (288 ±0)` // Estimated: `845 + r * (289 ±0)` - // Minimum execution time: 284_689_000 picoseconds. - Weight::from_parts(185_207_302, 845) - // Standard Error: 10_030 - .saturating_add(Weight::from_parts(5_871_325, 0).saturating_mul(r.into())) + // Minimum execution time: 235_462_000 picoseconds. + Weight::from_parts(141_240_297, 845) + // Standard Error: 9_687 + .saturating_add(Weight::from_parts(5_906_737, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1023,10 +1023,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1163 + n * (1 ±0)` // Estimated: `1163 + n * (1 ±0)` - // Minimum execution time: 299_364_000 picoseconds. - Weight::from_parts(302_089_070, 1163) - // Standard Error: 23 - .saturating_add(Weight::from_parts(128, 0).saturating_mul(n.into())) + // Minimum execution time: 250_887_000 picoseconds. + Weight::from_parts(253_321_064, 1163) + // Standard Error: 28 + .saturating_add(Weight::from_parts(169, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -1038,10 +1038,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `835 + r * (296 ±0)` // Estimated: `840 + r * (297 ±0)` - // Minimum execution time: 285_175_000 picoseconds. - Weight::from_parts(200_262_957, 840) - // Standard Error: 8_681 - .saturating_add(Weight::from_parts(4_899_266, 0).saturating_mul(r.into())) + // Minimum execution time: 236_542_000 picoseconds. + Weight::from_parts(147_992_508, 840) + // Standard Error: 8_849 + .saturating_add(Weight::from_parts(4_946_692, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1054,10 +1054,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1179 + n * (1 ±0)` // Estimated: `1179 + n * (1 ±0)` - // Minimum execution time: 299_459_000 picoseconds. - Weight::from_parts(302_451_160, 1179) - // Standard Error: 36 - .saturating_add(Weight::from_parts(731, 0).saturating_mul(n.into())) + // Minimum execution time: 249_987_000 picoseconds. + Weight::from_parts(254_866_627, 1179) + // Standard Error: 53 + .saturating_add(Weight::from_parts(554, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -1069,10 +1069,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `856 + r * (288 ±0)` // Estimated: `857 + r * (289 ±0)` - // Minimum execution time: 286_384_000 picoseconds. - Weight::from_parts(203_389_467, 857) - // Standard Error: 8_817 - .saturating_add(Weight::from_parts(4_692_347, 0).saturating_mul(r.into())) + // Minimum execution time: 236_635_000 picoseconds. + Weight::from_parts(157_805_789, 857) + // Standard Error: 7_699 + .saturating_add(Weight::from_parts(4_709_422, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1085,10 +1085,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1166 + n * (1 ±0)` // Estimated: `1166 + n * (1 ±0)` - // Minimum execution time: 297_450_000 picoseconds. - Weight::from_parts(300_459_851, 1166) - // Standard Error: 39 - .saturating_add(Weight::from_parts(108, 0).saturating_mul(n.into())) + // Minimum execution time: 252_660_000 picoseconds. + Weight::from_parts(255_250_747, 1166) + // Standard Error: 14 + .saturating_add(Weight::from_parts(133, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -1100,10 +1100,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `829 + r * (296 ±0)` // Estimated: `836 + r * (297 ±0)` - // Minimum execution time: 285_572_000 picoseconds. - Weight::from_parts(182_642_557, 836) - // Standard Error: 9_977 - .saturating_add(Weight::from_parts(6_090_684, 0).saturating_mul(r.into())) + // Minimum execution time: 240_198_000 picoseconds. + Weight::from_parts(133_188_357, 836) + // Standard Error: 10_661 + .saturating_add(Weight::from_parts(6_147_538, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1117,10 +1117,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1180 + n * (1 ±0)` // Estimated: `1180 + n * (1 ±0)` - // Minimum execution time: 301_344_000 picoseconds. - Weight::from_parts(303_770_522, 1180) - // Standard Error: 29 - .saturating_add(Weight::from_parts(807, 0).saturating_mul(n.into())) + // Minimum execution time: 252_131_000 picoseconds. + Weight::from_parts(259_960_286, 1180) + // Standard Error: 121 + .saturating_add(Weight::from_parts(192, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -1140,10 +1140,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1373 + r * (45 ±0)` // Estimated: `26753 + r * (2700 ±0)` - // Minimum execution time: 286_835_000 picoseconds. - Weight::from_parts(245_206_457, 26753) - // Standard Error: 73_782 - .saturating_add(Weight::from_parts(36_414_448, 0).saturating_mul(r.into())) + // Minimum execution time: 235_860_000 picoseconds. + Weight::from_parts(124_993_651, 26753) + // Standard Error: 22_811 + .saturating_add(Weight::from_parts(36_467_740, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(4_u64)) @@ -1165,10 +1165,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1237 + r * (256 ±0)` // Estimated: `26028 + r * (6235 ±0)` - // Minimum execution time: 287_184_000 picoseconds. - Weight::from_parts(287_525_000, 26028) - // Standard Error: 66_791 - .saturating_add(Weight::from_parts(261_473_539, 0).saturating_mul(r.into())) + // Minimum execution time: 237_221_000 picoseconds. + Weight::from_parts(237_632_000, 26028) + // Standard Error: 89_502 + .saturating_add(Weight::from_parts(212_211_534, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1189,11 +1189,11 @@ impl WeightInfo for SubstrateWeight { fn seal_delegate_call(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + r * (502 ±0)` - // Estimated: `21755 + r * (6329 ±10)` - // Minimum execution time: 285_759_000 picoseconds. - Weight::from_parts(286_643_000, 21755) - // Standard Error: 133_180 - .saturating_add(Weight::from_parts(257_186_897, 0).saturating_mul(r.into())) + // Estimated: `21755 + r * (6329 ±3)` + // Minimum execution time: 236_965_000 picoseconds. + Weight::from_parts(238_110_000, 21755) + // Standard Error: 101_332 + .saturating_add(Weight::from_parts(206_790_203, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1216,12 +1216,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1154 + t * (204 ±0)` // Estimated: `31015 + t * (5970 ±0)` - // Minimum execution time: 459_675_000 picoseconds. - Weight::from_parts(427_010_987, 31015) - // Standard Error: 1_277_377 - .saturating_add(Weight::from_parts(36_899_889, 0).saturating_mul(t.into())) + // Minimum execution time: 411_974_000 picoseconds. + Weight::from_parts(391_387_689, 31015) + // Standard Error: 1_320_695 + .saturating_add(Weight::from_parts(29_766_122, 0).saturating_mul(t.into())) // Standard Error: 1 - .saturating_add(Weight::from_parts(651, 0).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(597, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(t.into()))) .saturating_add(T::DbWeight::get().writes(5_u64)) @@ -1247,10 +1247,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1301 + r * (254 ±0)` // Estimated: `30977 + r * (16635 ±0)` - // Minimum execution time: 285_816_000 picoseconds. - Weight::from_parts(286_349_000, 30977) - // Standard Error: 269_144 - .saturating_add(Weight::from_parts(394_282_520, 0).saturating_mul(r.into())) + // Minimum execution time: 237_595_000 picoseconds. + Weight::from_parts(238_068_000, 30977) + // Standard Error: 254_409 + .saturating_add(Weight::from_parts(346_436_154, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().reads((6_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(6_u64)) @@ -1278,14 +1278,14 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1071 + t * (187 ±0)` // Estimated: `42684 + t * (3588 ±2)` - // Minimum execution time: 1_708_330_000 picoseconds. - Weight::from_parts(395_059_764, 42684) - // Standard Error: 4_545_552 - .saturating_add(Weight::from_parts(114_039_862, 0).saturating_mul(t.into())) + // Minimum execution time: 1_616_768_000 picoseconds. + Weight::from_parts(363_003_254, 42684) + // Standard Error: 4_398_669 + .saturating_add(Weight::from_parts(104_529_967, 0).saturating_mul(t.into())) // Standard Error: 7 - .saturating_add(Weight::from_parts(1_213, 0).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(1_162, 0).saturating_mul(i.into())) // Standard Error: 7 - .saturating_add(Weight::from_parts(1_379, 0).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_333, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(13_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(t.into()))) .saturating_add(T::DbWeight::get().writes(10_u64)) @@ -1307,10 +1307,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `777 + r * (8 ±0)` // Estimated: `21710 + r * (40 ±0)` - // Minimum execution time: 283_738_000 picoseconds. - Weight::from_parts(289_885_978, 21710) - // Standard Error: 1_057 - .saturating_add(Weight::from_parts(575_432, 0).saturating_mul(r.into())) + // Minimum execution time: 233_814_000 picoseconds. + Weight::from_parts(241_291_041, 21710) + // Standard Error: 1_422 + .saturating_add(Weight::from_parts(575_846, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) @@ -1330,10 +1330,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `785` // Estimated: `21745` - // Minimum execution time: 285_070_000 picoseconds. - Weight::from_parts(283_987_687, 21745) - // Standard Error: 6 - .saturating_add(Weight::from_parts(4_008, 0).saturating_mul(n.into())) + // Minimum execution time: 236_572_000 picoseconds. + Weight::from_parts(235_648_055, 21745) + // Standard Error: 3 + .saturating_add(Weight::from_parts(3_947, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1352,10 +1352,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `779 + r * (8 ±0)` // Estimated: `21725 + r * (40 ±0)` - // Minimum execution time: 281_613_000 picoseconds. - Weight::from_parts(285_429_053, 21725) - // Standard Error: 1_164 - .saturating_add(Weight::from_parts(756_244, 0).saturating_mul(r.into())) + // Minimum execution time: 234_473_000 picoseconds. + Weight::from_parts(239_805_309, 21725) + // Standard Error: 1_113 + .saturating_add(Weight::from_parts(752_507, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) @@ -1375,10 +1375,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `787` // Estimated: `21765` - // Minimum execution time: 284_593_000 picoseconds. - Weight::from_parts(278_467_111, 21765) + // Minimum execution time: 235_209_000 picoseconds. + Weight::from_parts(228_548_524, 21765) // Standard Error: 2 - .saturating_add(Weight::from_parts(3_217, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(3_171, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1397,10 +1397,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `779 + r * (8 ±0)` // Estimated: `21740 + r * (40 ±0)` - // Minimum execution time: 281_759_000 picoseconds. - Weight::from_parts(288_807_137, 21740) - // Standard Error: 805 - .saturating_add(Weight::from_parts(424_378, 0).saturating_mul(r.into())) + // Minimum execution time: 233_282_000 picoseconds. + Weight::from_parts(240_864_680, 21740) + // Standard Error: 958 + .saturating_add(Weight::from_parts(418_308, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) @@ -1420,10 +1420,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `787` // Estimated: `21785` - // Minimum execution time: 282_666_000 picoseconds. - Weight::from_parts(274_357_944, 21785) + // Minimum execution time: 234_667_000 picoseconds. + Weight::from_parts(227_810_077, 21785) // Standard Error: 2 - .saturating_add(Weight::from_parts(974, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(925, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1442,10 +1442,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `779 + r * (8 ±0)` // Estimated: `21745 + r * (40 ±0)` - // Minimum execution time: 285_073_000 picoseconds. - Weight::from_parts(287_226_796, 21745) - // Standard Error: 951 - .saturating_add(Weight::from_parts(425_368, 0).saturating_mul(r.into())) + // Minimum execution time: 234_040_000 picoseconds. + Weight::from_parts(237_970_694, 21745) + // Standard Error: 979 + .saturating_add(Weight::from_parts(416_562, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) @@ -1465,10 +1465,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `787` // Estimated: `21755` - // Minimum execution time: 283_407_000 picoseconds. - Weight::from_parts(276_737_242, 21755) + // Minimum execution time: 234_840_000 picoseconds. + Weight::from_parts(227_849_778, 21755) // Standard Error: 2 - .saturating_add(Weight::from_parts(967, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(923, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1487,10 +1487,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `822 + r * (76 ±0)` // Estimated: `21705 + r * (385 ±0)` - // Minimum execution time: 285_130_000 picoseconds. - Weight::from_parts(299_449_202, 21705) - // Standard Error: 16_535 - .saturating_add(Weight::from_parts(37_655_189, 0).saturating_mul(r.into())) + // Minimum execution time: 236_174_000 picoseconds. + Weight::from_parts(252_457_690, 21705) + // Standard Error: 20_130 + .saturating_add(Weight::from_parts(37_792_805, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 385).saturating_mul(r.into())) @@ -1510,10 +1510,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `792 + r * (42 ±0)` // Estimated: `21780 + r * (210 ±0)` - // Minimum execution time: 284_494_000 picoseconds. - Weight::from_parts(282_154_339, 21780) - // Standard Error: 12_278 - .saturating_add(Weight::from_parts(9_501_559, 0).saturating_mul(r.into())) + // Minimum execution time: 236_251_000 picoseconds. + Weight::from_parts(242_254_305, 21780) + // Standard Error: 9_765 + .saturating_add(Weight::from_parts(9_341_334, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 210).saturating_mul(r.into())) @@ -1535,10 +1535,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0 + r * (964 ±0)` // Estimated: `29920 + r * (11544 ±7)` - // Minimum execution time: 285_306_000 picoseconds. - Weight::from_parts(286_080_000, 29920) - // Standard Error: 43_813 - .saturating_add(Weight::from_parts(21_758_329, 0).saturating_mul(r.into())) + // Minimum execution time: 236_462_000 picoseconds. + Weight::from_parts(236_997_000, 29920) + // Standard Error: 46_527 + .saturating_add(Weight::from_parts(21_858_761, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1560,10 +1560,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `773 + r * (3 ±0)` // Estimated: `21735 + r * (15 ±0)` - // Minimum execution time: 283_487_000 picoseconds. - Weight::from_parts(289_280_189, 21735) - // Standard Error: 829 - .saturating_add(Weight::from_parts(168_973, 0).saturating_mul(r.into())) + // Minimum execution time: 235_085_000 picoseconds. + Weight::from_parts(239_410_836, 21735) + // Standard Error: 414 + .saturating_add(Weight::from_parts(167_067, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 15).saturating_mul(r.into())) @@ -1583,10 +1583,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1975 + r * (39 ±0)` // Estimated: `27145 + r * (200 ±0)` - // Minimum execution time: 287_413_000 picoseconds. - Weight::from_parts(314_662_286, 27145) - // Standard Error: 1_099 - .saturating_add(Weight::from_parts(262_201, 0).saturating_mul(r.into())) + // Minimum execution time: 236_690_000 picoseconds. + Weight::from_parts(268_793_030, 27145) + // Standard Error: 1_210 + .saturating_add(Weight::from_parts(263_330, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 200).saturating_mul(r.into())) @@ -1608,10 +1608,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `776 + r * (3 ±0)` // Estimated: `24004 + r * (18 ±0)` - // Minimum execution time: 282_601_000 picoseconds. - Weight::from_parts(289_374_203, 24004) - // Standard Error: 452 - .saturating_add(Weight::from_parts(142_661, 0).saturating_mul(r.into())) + // Minimum execution time: 236_289_000 picoseconds. + Weight::from_parts(246_581_099, 24004) + // Standard Error: 1_300 + .saturating_add(Weight::from_parts(137_499, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 18).saturating_mul(r.into())) @@ -1621,508 +1621,510 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_692_000 picoseconds. - Weight::from_parts(2_069_482, 0) - // Standard Error: 40 - .saturating_add(Weight::from_parts(2_922, 0).saturating_mul(r.into())) + // Minimum execution time: 1_679_000 picoseconds. + Weight::from_parts(1_934_194, 0) + // Standard Error: 1 + .saturating_add(Weight::from_parts(3_000, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64load(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_690_000 picoseconds. - Weight::from_parts(2_303_602, 0) - // Standard Error: 4 - .saturating_add(Weight::from_parts(6_433, 0).saturating_mul(r.into())) + // Minimum execution time: 1_872_000 picoseconds. + Weight::from_parts(2_605_712, 0) + // Standard Error: 43 + .saturating_add(Weight::from_parts(6_321, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64store(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_701_000 picoseconds. - Weight::from_parts(2_321_142, 0) - // Standard Error: 4 - .saturating_add(Weight::from_parts(6_025, 0).saturating_mul(r.into())) + // Minimum execution time: 1_837_000 picoseconds. + Weight::from_parts(2_035_143, 0) + // Standard Error: 65 + .saturating_add(Weight::from_parts(6_202, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_select(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_656_000 picoseconds. - Weight::from_parts(2_090_881, 0) + // Minimum execution time: 1_684_000 picoseconds. + Weight::from_parts(2_044_218, 0) // Standard Error: 5 - .saturating_add(Weight::from_parts(7_941, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(7_929, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_if(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_659_000 picoseconds. - Weight::from_parts(1_816_547, 0) - // Standard Error: 5 - .saturating_add(Weight::from_parts(10_578, 0).saturating_mul(r.into())) + // Minimum execution time: 1_635_000 picoseconds. + Weight::from_parts(2_009_851, 0) + // Standard Error: 6 + .saturating_add(Weight::from_parts(10_724, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_br(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_683_000 picoseconds. - Weight::from_parts(1_970_907, 0) + // Minimum execution time: 1_667_000 picoseconds. + Weight::from_parts(1_869_395, 0) // Standard Error: 12 - .saturating_add(Weight::from_parts(4_636, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(4_618, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_br_if(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_651_000 picoseconds. - Weight::from_parts(2_263_817, 0) - // Standard Error: 68 - .saturating_add(Weight::from_parts(7_529, 0).saturating_mul(r.into())) + // Minimum execution time: 1_698_000 picoseconds. + Weight::from_parts(2_184_182, 0) + // Standard Error: 16 + .saturating_add(Weight::from_parts(6_833, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_br_table(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_687_000 picoseconds. - Weight::from_parts(1_349_186, 0) - // Standard Error: 31 - .saturating_add(Weight::from_parts(9_732, 0).saturating_mul(r.into())) + // Minimum execution time: 1_670_000 picoseconds. + Weight::from_parts(1_471_988, 0) + // Standard Error: 30 + .saturating_add(Weight::from_parts(9_550, 0).saturating_mul(r.into())) } /// The range of component `e` is `[1, 256]`. - fn instr_br_table_per_entry(_e: u32, ) -> Weight { + fn instr_br_table_per_entry(e: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_777_000 picoseconds. - Weight::from_parts(2_036_446, 0) + // Minimum execution time: 1_778_000 picoseconds. + Weight::from_parts(1_925_086, 0) + // Standard Error: 136 + .saturating_add(Weight::from_parts(502, 0).saturating_mul(e.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_call(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_686_000 picoseconds. - Weight::from_parts(464_449, 0) - // Standard Error: 383 - .saturating_add(Weight::from_parts(19_121, 0).saturating_mul(r.into())) + // Minimum execution time: 1_759_000 picoseconds. + Weight::from_parts(2_372_048, 0) + // Standard Error: 16 + .saturating_add(Weight::from_parts(17_953, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_call_indirect(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_855_000 picoseconds. - Weight::from_parts(3_381_585, 0) - // Standard Error: 18 - .saturating_add(Weight::from_parts(24_245, 0).saturating_mul(r.into())) + // Minimum execution time: 1_852_000 picoseconds. + Weight::from_parts(3_125_003, 0) + // Standard Error: 25 + .saturating_add(Weight::from_parts(24_218, 0).saturating_mul(r.into())) } /// The range of component `l` is `[0, 1024]`. fn instr_call_per_local(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_792_000 picoseconds. - Weight::from_parts(2_006_024, 0) - // Standard Error: 16 - .saturating_add(Weight::from_parts(2_181, 0).saturating_mul(l.into())) + // Minimum execution time: 1_795_000 picoseconds. + Weight::from_parts(2_121_763, 0) + // Standard Error: 45 + .saturating_add(Weight::from_parts(1_207, 0).saturating_mul(l.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_local_get(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_918_000 picoseconds. - Weight::from_parts(4_618_761, 0) - // Standard Error: 49 - .saturating_add(Weight::from_parts(2_312, 0).saturating_mul(r.into())) + // Minimum execution time: 3_019_000 picoseconds. + Weight::from_parts(3_267_108, 0) + // Standard Error: 55 + .saturating_add(Weight::from_parts(2_527, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_local_set(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_889_000 picoseconds. - Weight::from_parts(4_151_280, 0) + // Minimum execution time: 2_944_000 picoseconds. + Weight::from_parts(3_183_331, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(3_623, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_618, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_local_tee(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_880_000 picoseconds. - Weight::from_parts(4_225_780, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(3_847, 0).saturating_mul(r.into())) + // Minimum execution time: 3_009_000 picoseconds. + Weight::from_parts(3_178_158, 0) + // Standard Error: 41 + .saturating_add(Weight::from_parts(4_075, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_global_get(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_765_000 picoseconds. - Weight::from_parts(2_216_674, 0) - // Standard Error: 4 - .saturating_add(Weight::from_parts(8_393, 0).saturating_mul(r.into())) + // Minimum execution time: 1_748_000 picoseconds. + Weight::from_parts(2_371_911, 0) + // Standard Error: 10 + .saturating_add(Weight::from_parts(8_378, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_global_set(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_764_000 picoseconds. - Weight::from_parts(2_246_735, 0) - // Standard Error: 5 - .saturating_add(Weight::from_parts(8_877, 0).saturating_mul(r.into())) + // Minimum execution time: 1_795_000 picoseconds. + Weight::from_parts(1_311_997, 0) + // Standard Error: 157 + .saturating_add(Weight::from_parts(9_410, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_memory_current(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_758_000 picoseconds. - Weight::from_parts(1_922_386, 0) - // Standard Error: 94 - .saturating_add(Weight::from_parts(3_868, 0).saturating_mul(r.into())) + // Minimum execution time: 2_059_000 picoseconds. + Weight::from_parts(2_416_611, 0) + // Standard Error: 5 + .saturating_add(Weight::from_parts(3_775, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 16]`. fn instr_memory_grow(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_635_000 picoseconds. - Weight::from_parts(1_118_785, 0) - // Standard Error: 134_978 - .saturating_add(Weight::from_parts(16_343_664, 0).saturating_mul(r.into())) + // Minimum execution time: 1_764_000 picoseconds. + Weight::from_parts(1_414_442, 0) + // Standard Error: 142_321 + .saturating_add(Weight::from_parts(13_210_495, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64clz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_648_000 picoseconds. - Weight::from_parts(2_012_545, 0) + // Minimum execution time: 1_665_000 picoseconds. + Weight::from_parts(2_047_968, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(3_824, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(4_035, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64ctz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_688_000 picoseconds. - Weight::from_parts(1_995_956, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(3_757, 0).saturating_mul(r.into())) + // Minimum execution time: 1_696_000 picoseconds. + Weight::from_parts(2_101_548, 0) + // Standard Error: 13 + .saturating_add(Weight::from_parts(3_754, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64popcnt(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_631_000 picoseconds. - Weight::from_parts(2_011_493, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(3_755, 0).saturating_mul(r.into())) + // Minimum execution time: 1_686_000 picoseconds. + Weight::from_parts(2_023_482, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(3_770, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64eqz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_667_000 picoseconds. - Weight::from_parts(1_958_798, 0) + // Minimum execution time: 1_700_000 picoseconds. + Weight::from_parts(2_035_759, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(3_677, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_660, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64extendsi32(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_674_000 picoseconds. - Weight::from_parts(2_009_555, 0) - // Standard Error: 7 - .saturating_add(Weight::from_parts(3_863, 0).saturating_mul(r.into())) + // Minimum execution time: 1_682_000 picoseconds. + Weight::from_parts(2_015_828, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(3_977, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64extendui32(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_659_000 picoseconds. - Weight::from_parts(2_014_985, 0) + // Minimum execution time: 1_660_000 picoseconds. + Weight::from_parts(2_032_387, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(3_821, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_826, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i32wrapi64(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_640_000 picoseconds. - Weight::from_parts(2_013_939, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(3_708, 0).saturating_mul(r.into())) + // Minimum execution time: 1_635_000 picoseconds. + Weight::from_parts(2_013_228, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(3_752, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64eq(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_631_000 picoseconds. - Weight::from_parts(2_002_814, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(6_008, 0).saturating_mul(r.into())) + // Minimum execution time: 1_698_000 picoseconds. + Weight::from_parts(2_844_817, 0) + // Standard Error: 56 + .saturating_add(Weight::from_parts(5_746, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64ne(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_647_000 picoseconds. - Weight::from_parts(2_032_158, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(5_944, 0).saturating_mul(r.into())) + // Minimum execution time: 1_686_000 picoseconds. + Weight::from_parts(2_208_884, 0) + // Standard Error: 138 + .saturating_add(Weight::from_parts(6_032, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64lts(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_669_000 picoseconds. - Weight::from_parts(2_040_386, 0) + // Minimum execution time: 1_695_000 picoseconds. + Weight::from_parts(2_060_880, 0) // Standard Error: 3 - .saturating_add(Weight::from_parts(6_009, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(5_966, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64ltu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_637_000 picoseconds. - Weight::from_parts(1_983_695, 0) - // Standard Error: 4 - .saturating_add(Weight::from_parts(6_027, 0).saturating_mul(r.into())) + // Minimum execution time: 1_700_000 picoseconds. + Weight::from_parts(2_143_484, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(5_932, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64gts(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_701_000 picoseconds. - Weight::from_parts(2_054_295, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(5_799, 0).saturating_mul(r.into())) + // Minimum execution time: 1_677_000 picoseconds. + Weight::from_parts(2_081_646, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(5_813, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64gtu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_653_000 picoseconds. - Weight::from_parts(2_749_807, 0) - // Standard Error: 90 - .saturating_add(Weight::from_parts(5_945, 0).saturating_mul(r.into())) + // Minimum execution time: 2_476_000 picoseconds. + Weight::from_parts(2_161_801, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(6_078, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64les(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_651_000 picoseconds. - Weight::from_parts(1_979_111, 0) + // Minimum execution time: 1_677_000 picoseconds. + Weight::from_parts(2_043_451, 0) // Standard Error: 3 - .saturating_add(Weight::from_parts(6_011, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(5_988, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64leu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_743_000 picoseconds. - Weight::from_parts(2_058_081, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(6_085, 0).saturating_mul(r.into())) + // Minimum execution time: 1_694_000 picoseconds. + Weight::from_parts(2_058_196, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(6_058, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64ges(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_638_000 picoseconds. - Weight::from_parts(2_038_929, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(5_941, 0).saturating_mul(r.into())) + // Minimum execution time: 1_675_000 picoseconds. + Weight::from_parts(2_036_798, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(5_956, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64geu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_641_000 picoseconds. - Weight::from_parts(2_036_587, 0) + // Minimum execution time: 1_712_000 picoseconds. + Weight::from_parts(2_121_407, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(6_008, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(5_944, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64add(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_624_000 picoseconds. - Weight::from_parts(2_080_562, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(5_826, 0).saturating_mul(r.into())) + // Minimum execution time: 1_675_000 picoseconds. + Weight::from_parts(2_061_053, 0) + // Standard Error: 6 + .saturating_add(Weight::from_parts(5_823, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64sub(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_652_000 picoseconds. - Weight::from_parts(2_039_535, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(6_137, 0).saturating_mul(r.into())) + // Minimum execution time: 1_686_000 picoseconds. + Weight::from_parts(2_023_347, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(6_126, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64mul(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_666_000 picoseconds. - Weight::from_parts(2_056_354, 0) - // Standard Error: 6 - .saturating_add(Weight::from_parts(5_780, 0).saturating_mul(r.into())) + // Minimum execution time: 1_678_000 picoseconds. + Weight::from_parts(2_390_920, 0) + // Standard Error: 55 + .saturating_add(Weight::from_parts(5_635, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64divs(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_648_000 picoseconds. - Weight::from_parts(2_077_695, 0) - // Standard Error: 4 - .saturating_add(Weight::from_parts(11_775, 0).saturating_mul(r.into())) + // Minimum execution time: 1_728_000 picoseconds. + Weight::from_parts(1_944_457, 0) + // Standard Error: 7 + .saturating_add(Weight::from_parts(11_848, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64divu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_797_000 picoseconds. - Weight::from_parts(2_772_388, 0) - // Standard Error: 33 - .saturating_add(Weight::from_parts(10_333, 0).saturating_mul(r.into())) + // Minimum execution time: 1_649_000 picoseconds. + Weight::from_parts(1_881_148, 0) + // Standard Error: 6 + .saturating_add(Weight::from_parts(10_618, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64rems(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_699_000 picoseconds. - Weight::from_parts(2_174_288, 0) + // Minimum execution time: 1_708_000 picoseconds. + Weight::from_parts(1_767_912, 0) // Standard Error: 6 - .saturating_add(Weight::from_parts(11_778, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(12_099, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64remu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_685_000 picoseconds. - Weight::from_parts(2_091_037, 0) + // Minimum execution time: 1_650_000 picoseconds. + Weight::from_parts(1_998_575, 0) // Standard Error: 3 - .saturating_add(Weight::from_parts(10_694, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(10_632, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64and(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_636_000 picoseconds. - Weight::from_parts(1_975_521, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(5_695, 0).saturating_mul(r.into())) + // Minimum execution time: 1_633_000 picoseconds. + Weight::from_parts(2_029_981, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(5_662, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64or(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_619_000 picoseconds. - Weight::from_parts(2_045_492, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(5_770, 0).saturating_mul(r.into())) + // Minimum execution time: 1_621_000 picoseconds. + Weight::from_parts(2_029_743, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(5_762, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64xor(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_668_000 picoseconds. - Weight::from_parts(2_055_460, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(5_851, 0).saturating_mul(r.into())) + // Minimum execution time: 1_641_000 picoseconds. + Weight::from_parts(2_127_132, 0) + // Standard Error: 5 + .saturating_add(Weight::from_parts(5_818, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64shl(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_681_000 picoseconds. - Weight::from_parts(2_023_370, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(5_853, 0).saturating_mul(r.into())) + // Minimum execution time: 1_690_000 picoseconds. + Weight::from_parts(2_021_035, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(5_917, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64shrs(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_714_000 picoseconds. - Weight::from_parts(2_067_584, 0) + // Minimum execution time: 1_661_000 picoseconds. + Weight::from_parts(2_055_069, 0) // Standard Error: 3 - .saturating_add(Weight::from_parts(6_133, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(6_094, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64shru(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_602_000 picoseconds. - Weight::from_parts(2_055_530, 0) - // Standard Error: 138 - .saturating_add(Weight::from_parts(6_014, 0).saturating_mul(r.into())) + // Minimum execution time: 1_677_000 picoseconds. + Weight::from_parts(2_024_748, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(5_862, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64rotl(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_709_000 picoseconds. - Weight::from_parts(2_016_365, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(5_985, 0).saturating_mul(r.into())) + // Minimum execution time: 1_651_000 picoseconds. + Weight::from_parts(2_005_814, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(6_007, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64rotr(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_661_000 picoseconds. - Weight::from_parts(2_003_063, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(5_863, 0).saturating_mul(r.into())) + // Minimum execution time: 1_703_000 picoseconds. + Weight::from_parts(2_019_636, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(5_862, 0).saturating_mul(r.into())) } } @@ -2134,8 +2136,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `109` // Estimated: `1594` - // Minimum execution time: 2_585_000 picoseconds. - Weight::from_parts(2_802_000, 1594) + // Minimum execution time: 2_713_000 picoseconds. + Weight::from_parts(2_811_000, 1594) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: Skipped Metadata (r:0 w:0) @@ -2145,10 +2147,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `450 + k * (69 ±0)` // Estimated: `440 + k * (70 ±0)` - // Minimum execution time: 10_825_000 picoseconds. - Weight::from_parts(5_747_064, 440) - // Standard Error: 1_037 - .saturating_add(Weight::from_parts(973_689, 0).saturating_mul(k.into())) + // Minimum execution time: 11_011_000 picoseconds. + Weight::from_parts(7_025_244, 440) + // Standard Error: 1_217 + .saturating_add(Weight::from_parts(980_818, 0).saturating_mul(k.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) @@ -2162,10 +2164,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `250 + q * (33 ±0)` // Estimated: `1725 + q * (33 ±0)` - // Minimum execution time: 2_718_000 picoseconds. - Weight::from_parts(11_436_305, 1725) - // Standard Error: 3_619 - .saturating_add(Weight::from_parts(1_296_955, 0).saturating_mul(q.into())) + // Minimum execution time: 2_802_000 picoseconds. + Weight::from_parts(10_768_336, 1725) + // Standard Error: 3_424 + .saturating_add(Weight::from_parts(1_323_649, 0).saturating_mul(q.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 33).saturating_mul(q.into())) @@ -2179,10 +2181,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `238 + c * (1 ±0)` // Estimated: `3951 + c * (2 ±0)` - // Minimum execution time: 37_882_000 picoseconds. - Weight::from_parts(43_548_816, 3951) - // Standard Error: 49 - .saturating_add(Weight::from_parts(53_936, 0).saturating_mul(c.into())) + // Minimum execution time: 30_299_000 picoseconds. + Weight::from_parts(24_608_986, 3951) + // Standard Error: 75 + .saturating_add(Weight::from_parts(54_619, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 2).saturating_mul(c.into())) @@ -2202,10 +2204,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `707` // Estimated: `21400 + c * (5 ±0)` - // Minimum execution time: 313_392_000 picoseconds. - Weight::from_parts(325_419_093, 21400) - // Standard Error: 25 - .saturating_add(Weight::from_parts(37_877, 0).saturating_mul(c.into())) + // Minimum execution time: 265_835_000 picoseconds. + Weight::from_parts(275_985_164, 21400) + // Standard Error: 36 + .saturating_add(Weight::from_parts(37_980, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 5).saturating_mul(c.into())) @@ -2233,14 +2235,14 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `270` // Estimated: `26207` - // Minimum execution time: 3_274_352_000 picoseconds. - Weight::from_parts(681_171_416, 26207) - // Standard Error: 336 - .saturating_add(Weight::from_parts(106_391, 0).saturating_mul(c.into())) - // Standard Error: 19 - .saturating_add(Weight::from_parts(1_147, 0).saturating_mul(i.into())) - // Standard Error: 19 - .saturating_add(Weight::from_parts(1_493, 0).saturating_mul(s.into())) + // Minimum execution time: 3_124_508_000 picoseconds. + Weight::from_parts(617_467_897, 26207) + // Standard Error: 293 + .saturating_add(Weight::from_parts(106_971, 0).saturating_mul(c.into())) + // Standard Error: 17 + .saturating_add(Weight::from_parts(1_156, 0).saturating_mul(i.into())) + // Standard Error: 17 + .saturating_add(Weight::from_parts(1_395, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(10_u64)) } @@ -2264,12 +2266,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `482` // Estimated: `28521` - // Minimum execution time: 1_692_637_000 picoseconds. - Weight::from_parts(283_252_265, 28521) + // Minimum execution time: 1_649_483_000 picoseconds. + Weight::from_parts(287_642_416, 28521) // Standard Error: 8 - .saturating_add(Weight::from_parts(1_498, 0).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(1_450, 0).saturating_mul(i.into())) // Standard Error: 8 - .saturating_add(Weight::from_parts(1_487, 0).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_443, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } @@ -2287,8 +2289,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `759` // Estimated: `21615` - // Minimum execution time: 192_369_000 picoseconds. - Weight::from_parts(193_417_000, 21615) + // Minimum execution time: 192_302_000 picoseconds. + Weight::from_parts(193_192_000, 21615) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -2305,10 +2307,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `109` // Estimated: `7366` - // Minimum execution time: 301_972_000 picoseconds. - Weight::from_parts(313_248_051, 7366) - // Standard Error: 82 - .saturating_add(Weight::from_parts(107_321, 0).saturating_mul(c.into())) + // Minimum execution time: 246_401_000 picoseconds. + Weight::from_parts(261_505_456, 7366) + // Standard Error: 83 + .saturating_add(Weight::from_parts(109_136, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -2324,8 +2326,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `255` // Estimated: `7950` - // Minimum execution time: 33_013_000 picoseconds. - Weight::from_parts(33_622_000, 7950) + // Minimum execution time: 33_913_000 picoseconds. + Weight::from_parts(34_186_000, 7950) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -2339,8 +2341,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `570` // Estimated: `19530` - // Minimum execution time: 33_518_000 picoseconds. - Weight::from_parts(33_819_000, 19530) + // Minimum execution time: 33_801_000 picoseconds. + Weight::from_parts(34_877_000, 19530) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -2359,10 +2361,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `781 + r * (6 ±0)` // Estimated: `21730 + r * (30 ±0)` - // Minimum execution time: 283_945_000 picoseconds. - Weight::from_parts(289_209_599, 21730) - // Standard Error: 901 - .saturating_add(Weight::from_parts(327_601, 0).saturating_mul(r.into())) + // Minimum execution time: 237_679_000 picoseconds. + Weight::from_parts(243_022_905, 21730) + // Standard Error: 940 + .saturating_add(Weight::from_parts(324_389, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -2382,10 +2384,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `839 + r * (240 ±0)` // Estimated: `21835 + r * (3675 ±0)` - // Minimum execution time: 284_949_000 picoseconds. - Weight::from_parts(126_196_485, 21835) - // Standard Error: 6_260 - .saturating_add(Weight::from_parts(3_368_849, 0).saturating_mul(r.into())) + // Minimum execution time: 235_635_000 picoseconds. + Weight::from_parts(76_942_144, 21835) + // Standard Error: 6_214 + .saturating_add(Weight::from_parts(3_328_756, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -2406,10 +2408,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `831 + r * (244 ±0)` // Estimated: `21855 + r * (3695 ±0)` - // Minimum execution time: 286_429_000 picoseconds. - Weight::from_parts(124_820_396, 21855) - // Standard Error: 6_539 - .saturating_add(Weight::from_parts(4_163_535, 0).saturating_mul(r.into())) + // Minimum execution time: 237_123_000 picoseconds. + Weight::from_parts(77_880_739, 21855) + // Standard Error: 5_970 + .saturating_add(Weight::from_parts(4_103_281, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -2430,10 +2432,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `788 + r * (6 ±0)` // Estimated: `21770 + r * (30 ±0)` - // Minimum execution time: 285_042_000 picoseconds. - Weight::from_parts(288_096_303, 21770) - // Standard Error: 972 - .saturating_add(Weight::from_parts(409_782, 0).saturating_mul(r.into())) + // Minimum execution time: 236_621_000 picoseconds. + Weight::from_parts(238_240_015, 21770) + // Standard Error: 742 + .saturating_add(Weight::from_parts(404_691, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -2453,10 +2455,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `778 + r * (3 ±0)` // Estimated: `21735 + r * (15 ±0)` - // Minimum execution time: 282_820_000 picoseconds. - Weight::from_parts(287_104_710, 21735) - // Standard Error: 421 - .saturating_add(Weight::from_parts(167_907, 0).saturating_mul(r.into())) + // Minimum execution time: 233_274_000 picoseconds. + Weight::from_parts(239_596_227, 21735) + // Standard Error: 551 + .saturating_add(Weight::from_parts(164_429, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 15).saturating_mul(r.into())) @@ -2476,10 +2478,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `782 + r * (6 ±0)` // Estimated: `21740 + r * (30 ±0)` - // Minimum execution time: 284_619_000 picoseconds. - Weight::from_parts(281_326_785, 21740) - // Standard Error: 1_379 - .saturating_add(Weight::from_parts(342_779, 0).saturating_mul(r.into())) + // Minimum execution time: 235_661_000 picoseconds. + Weight::from_parts(239_063_406, 21740) + // Standard Error: 933 + .saturating_add(Weight::from_parts(327_679, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -2499,10 +2501,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `783 + r * (6 ±0)` // Estimated: `21725 + r * (30 ±0)` - // Minimum execution time: 284_703_000 picoseconds. - Weight::from_parts(289_479_932, 21725) - // Standard Error: 745 - .saturating_add(Weight::from_parts(323_625, 0).saturating_mul(r.into())) + // Minimum execution time: 235_583_000 picoseconds. + Weight::from_parts(251_641_549, 21725) + // Standard Error: 1_104 + .saturating_add(Weight::from_parts(315_873, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -2522,10 +2524,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `922 + r * (6 ±0)` // Estimated: `24633 + r * (30 ±0)` - // Minimum execution time: 283_610_000 picoseconds. - Weight::from_parts(299_901_534, 24633) - // Standard Error: 1_177 - .saturating_add(Weight::from_parts(1_474_603, 0).saturating_mul(r.into())) + // Minimum execution time: 235_325_000 picoseconds. + Weight::from_parts(256_582_010, 24633) + // Standard Error: 1_349 + .saturating_add(Weight::from_parts(1_483_116, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -2545,10 +2547,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `792 + r * (6 ±0)` // Estimated: `21825 + r * (30 ±0)` - // Minimum execution time: 284_474_000 picoseconds. - Weight::from_parts(283_540_273, 21825) - // Standard Error: 1_164 - .saturating_add(Weight::from_parts(339_262, 0).saturating_mul(r.into())) + // Minimum execution time: 235_358_000 picoseconds. + Weight::from_parts(233_421_484, 21825) + // Standard Error: 1_178 + .saturating_add(Weight::from_parts(337_947, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -2568,10 +2570,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `790 + r * (6 ±0)` // Estimated: `21815 + r * (30 ±0)` - // Minimum execution time: 284_521_000 picoseconds. - Weight::from_parts(285_747_754, 21815) - // Standard Error: 889 - .saturating_add(Weight::from_parts(326_428, 0).saturating_mul(r.into())) + // Minimum execution time: 236_570_000 picoseconds. + Weight::from_parts(245_853_078, 21815) + // Standard Error: 1_947 + .saturating_add(Weight::from_parts(319_972, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -2591,10 +2593,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `787 + r * (6 ±0)` // Estimated: `21805 + r * (30 ±0)` - // Minimum execution time: 284_103_000 picoseconds. - Weight::from_parts(283_801_256, 21805) - // Standard Error: 1_051 - .saturating_add(Weight::from_parts(334_081, 0).saturating_mul(r.into())) + // Minimum execution time: 235_027_000 picoseconds. + Weight::from_parts(239_719_689, 21805) + // Standard Error: 654 + .saturating_add(Weight::from_parts(326_988, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -2614,10 +2616,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `778 + r * (6 ±0)` // Estimated: `21735 + r * (30 ±0)` - // Minimum execution time: 284_187_000 picoseconds. - Weight::from_parts(289_414_364, 21735) - // Standard Error: 796 - .saturating_add(Weight::from_parts(324_603, 0).saturating_mul(r.into())) + // Minimum execution time: 236_547_000 picoseconds. + Weight::from_parts(239_390_326, 21735) + // Standard Error: 912 + .saturating_add(Weight::from_parts(327_495, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -2639,10 +2641,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `856 + r * (10 ±0)` // Estimated: `24446 + r * (60 ±0)` - // Minimum execution time: 284_953_000 picoseconds. - Weight::from_parts(290_535_752, 24446) - // Standard Error: 2_462 - .saturating_add(Weight::from_parts(1_361_518, 0).saturating_mul(r.into())) + // Minimum execution time: 235_710_000 picoseconds. + Weight::from_parts(238_998_789, 24446) + // Standard Error: 2_055 + .saturating_add(Weight::from_parts(1_373_992, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 60).saturating_mul(r.into())) @@ -2662,10 +2664,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `745 + r * (4 ±0)` // Estimated: `21555 + r * (20 ±0)` - // Minimum execution time: 160_775_000 picoseconds. - Weight::from_parts(164_652_364, 21555) - // Standard Error: 284 - .saturating_add(Weight::from_parts(132_574, 0).saturating_mul(r.into())) + // Minimum execution time: 161_133_000 picoseconds. + Weight::from_parts(167_097_346, 21555) + // Standard Error: 245 + .saturating_add(Weight::from_parts(128_503, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 20).saturating_mul(r.into())) @@ -2685,10 +2687,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `780 + r * (6 ±0)` // Estimated: `21740 + r * (30 ±0)` - // Minimum execution time: 284_072_000 picoseconds. - Weight::from_parts(288_418_644, 21740) - // Standard Error: 792 - .saturating_add(Weight::from_parts(272_881, 0).saturating_mul(r.into())) + // Minimum execution time: 234_790_000 picoseconds. + Weight::from_parts(242_392_710, 21740) + // Standard Error: 2_506 + .saturating_add(Weight::from_parts(273_470, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -2708,10 +2710,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `784` // Estimated: `21740` - // Minimum execution time: 286_671_000 picoseconds. - Weight::from_parts(292_151_662, 21740) - // Standard Error: 1 - .saturating_add(Weight::from_parts(638, 0).saturating_mul(n.into())) + // Minimum execution time: 236_837_000 picoseconds. + Weight::from_parts(237_860_073, 21740) + // Standard Error: 2 + .saturating_add(Weight::from_parts(602, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -2730,10 +2732,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `768 + r * (45 ±0)` // Estimated: `21660 + r * (225 ±0)` - // Minimum execution time: 280_334_000 picoseconds. - Weight::from_parts(283_487_571, 21660) - // Standard Error: 267_797 - .saturating_add(Weight::from_parts(3_803_128, 0).saturating_mul(r.into())) + // Minimum execution time: 232_047_000 picoseconds. + Weight::from_parts(234_629_293, 21660) + // Standard Error: 171_808 + .saturating_add(Weight::from_parts(663_306, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 225).saturating_mul(r.into())) @@ -2753,10 +2755,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `778` // Estimated: `21775` - // Minimum execution time: 284_004_000 picoseconds. - Weight::from_parts(283_681_350, 21775) + // Minimum execution time: 235_035_000 picoseconds. + Weight::from_parts(234_442_091, 21775) // Standard Error: 1 - .saturating_add(Weight::from_parts(232, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(185, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -2779,10 +2781,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `810 + r * (356 ±0)` // Estimated: `25511 + r * (15321 ±0)` - // Minimum execution time: 284_143_000 picoseconds. - Weight::from_parts(287_218_324, 25511) - // Standard Error: 343_611 - .saturating_add(Weight::from_parts(109_895_675, 0).saturating_mul(r.into())) + // Minimum execution time: 234_140_000 picoseconds. + Weight::from_parts(236_805_906, 25511) + // Standard Error: 435_181 + .saturating_add(Weight::from_parts(118_144_693, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((6_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -2806,10 +2808,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `825 + r * (10 ±0)` // Estimated: `24283 + r * (60 ±0)` - // Minimum execution time: 285_037_000 picoseconds. - Weight::from_parts(299_804_606, 24283) - // Standard Error: 5_518 - .saturating_add(Weight::from_parts(1_848_164, 0).saturating_mul(r.into())) + // Minimum execution time: 235_271_000 picoseconds. + Weight::from_parts(256_019_682, 24283) + // Standard Error: 2_016 + .saturating_add(Weight::from_parts(1_862_085, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 60).saturating_mul(r.into())) @@ -2829,10 +2831,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `778 + r * (10 ±0)` // Estimated: `21735 + r * (50 ±0)` - // Minimum execution time: 282_886_000 picoseconds. - Weight::from_parts(293_171_736, 21735) - // Standard Error: 2_171 - .saturating_add(Weight::from_parts(3_491_303, 0).saturating_mul(r.into())) + // Minimum execution time: 233_092_000 picoseconds. + Weight::from_parts(248_483_473, 21735) + // Standard Error: 2_182 + .saturating_add(Weight::from_parts(3_551_674, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 50).saturating_mul(r.into())) @@ -2853,12 +2855,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `797 + t * (32 ±0)` // Estimated: `21840 + t * (2640 ±0)` - // Minimum execution time: 300_675_000 picoseconds. - Weight::from_parts(296_092_420, 21840) - // Standard Error: 130_733 - .saturating_add(Weight::from_parts(2_487_957, 0).saturating_mul(t.into())) - // Standard Error: 36 - .saturating_add(Weight::from_parts(565, 0).saturating_mul(n.into())) + // Minimum execution time: 252_307_000 picoseconds. + Weight::from_parts(245_237_726, 21840) + // Standard Error: 79_824 + .saturating_add(Weight::from_parts(2_364_618, 0).saturating_mul(t.into())) + // Standard Error: 22 + .saturating_add(Weight::from_parts(636, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(t.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -2880,10 +2882,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `777 + r * (7 ±0)` // Estimated: `21725 + r * (35 ±0)` - // Minimum execution time: 166_638_000 picoseconds. - Weight::from_parts(171_353_083, 21725) - // Standard Error: 550 - .saturating_add(Weight::from_parts(238_768, 0).saturating_mul(r.into())) + // Minimum execution time: 165_367_000 picoseconds. + Weight::from_parts(170_164_725, 21725) + // Standard Error: 487 + .saturating_add(Weight::from_parts(237_281, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 35).saturating_mul(r.into())) @@ -2903,10 +2905,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `125728` // Estimated: `269977` - // Minimum execution time: 414_136_000 picoseconds. - Weight::from_parts(416_093_921, 269977) - // Standard Error: 3 - .saturating_add(Weight::from_parts(794, 0).saturating_mul(i.into())) + // Minimum execution time: 350_914_000 picoseconds. + Weight::from_parts(354_461_646, 269977) + // Standard Error: 1 + .saturating_add(Weight::from_parts(747, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -2917,10 +2919,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `845 + r * (292 ±0)` // Estimated: `843 + r * (293 ±0)` - // Minimum execution time: 285_920_000 picoseconds. - Weight::from_parts(184_945_789, 843) - // Standard Error: 9_604 - .saturating_add(Weight::from_parts(6_012_522, 0).saturating_mul(r.into())) + // Minimum execution time: 236_273_000 picoseconds. + Weight::from_parts(137_922_946, 843) + // Standard Error: 10_363 + .saturating_add(Weight::from_parts(6_034_776, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -2934,10 +2936,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1304` // Estimated: `1280` - // Minimum execution time: 299_772_000 picoseconds. - Weight::from_parts(333_451_106, 1280) - // Standard Error: 54 - .saturating_add(Weight::from_parts(579, 0).saturating_mul(n.into())) + // Minimum execution time: 251_462_000 picoseconds. + Weight::from_parts(287_009_907, 1280) + // Standard Error: 62 + .saturating_add(Weight::from_parts(384, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -2948,10 +2950,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1167 + n * (1 ±0)` // Estimated: `1167 + n * (1 ±0)` - // Minimum execution time: 299_279_000 picoseconds. - Weight::from_parts(302_336_567, 1167) - // Standard Error: 25 - .saturating_add(Weight::from_parts(86, 0).saturating_mul(n.into())) + // Minimum execution time: 250_985_000 picoseconds. + Weight::from_parts(253_693_249, 1167) + // Standard Error: 21 + .saturating_add(Weight::from_parts(92, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -2963,10 +2965,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `841 + r * (288 ±0)` // Estimated: `845 + r * (289 ±0)` - // Minimum execution time: 284_689_000 picoseconds. - Weight::from_parts(185_207_302, 845) - // Standard Error: 10_030 - .saturating_add(Weight::from_parts(5_871_325, 0).saturating_mul(r.into())) + // Minimum execution time: 235_462_000 picoseconds. + Weight::from_parts(141_240_297, 845) + // Standard Error: 9_687 + .saturating_add(Weight::from_parts(5_906_737, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -2980,10 +2982,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1163 + n * (1 ±0)` // Estimated: `1163 + n * (1 ±0)` - // Minimum execution time: 299_364_000 picoseconds. - Weight::from_parts(302_089_070, 1163) - // Standard Error: 23 - .saturating_add(Weight::from_parts(128, 0).saturating_mul(n.into())) + // Minimum execution time: 250_887_000 picoseconds. + Weight::from_parts(253_321_064, 1163) + // Standard Error: 28 + .saturating_add(Weight::from_parts(169, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -2995,10 +2997,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `835 + r * (296 ±0)` // Estimated: `840 + r * (297 ±0)` - // Minimum execution time: 285_175_000 picoseconds. - Weight::from_parts(200_262_957, 840) - // Standard Error: 8_681 - .saturating_add(Weight::from_parts(4_899_266, 0).saturating_mul(r.into())) + // Minimum execution time: 236_542_000 picoseconds. + Weight::from_parts(147_992_508, 840) + // Standard Error: 8_849 + .saturating_add(Weight::from_parts(4_946_692, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3011,10 +3013,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1179 + n * (1 ±0)` // Estimated: `1179 + n * (1 ±0)` - // Minimum execution time: 299_459_000 picoseconds. - Weight::from_parts(302_451_160, 1179) - // Standard Error: 36 - .saturating_add(Weight::from_parts(731, 0).saturating_mul(n.into())) + // Minimum execution time: 249_987_000 picoseconds. + Weight::from_parts(254_866_627, 1179) + // Standard Error: 53 + .saturating_add(Weight::from_parts(554, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -3026,10 +3028,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `856 + r * (288 ±0)` // Estimated: `857 + r * (289 ±0)` - // Minimum execution time: 286_384_000 picoseconds. - Weight::from_parts(203_389_467, 857) - // Standard Error: 8_817 - .saturating_add(Weight::from_parts(4_692_347, 0).saturating_mul(r.into())) + // Minimum execution time: 236_635_000 picoseconds. + Weight::from_parts(157_805_789, 857) + // Standard Error: 7_699 + .saturating_add(Weight::from_parts(4_709_422, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3042,10 +3044,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1166 + n * (1 ±0)` // Estimated: `1166 + n * (1 ±0)` - // Minimum execution time: 297_450_000 picoseconds. - Weight::from_parts(300_459_851, 1166) - // Standard Error: 39 - .saturating_add(Weight::from_parts(108, 0).saturating_mul(n.into())) + // Minimum execution time: 252_660_000 picoseconds. + Weight::from_parts(255_250_747, 1166) + // Standard Error: 14 + .saturating_add(Weight::from_parts(133, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -3057,10 +3059,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `829 + r * (296 ±0)` // Estimated: `836 + r * (297 ±0)` - // Minimum execution time: 285_572_000 picoseconds. - Weight::from_parts(182_642_557, 836) - // Standard Error: 9_977 - .saturating_add(Weight::from_parts(6_090_684, 0).saturating_mul(r.into())) + // Minimum execution time: 240_198_000 picoseconds. + Weight::from_parts(133_188_357, 836) + // Standard Error: 10_661 + .saturating_add(Weight::from_parts(6_147_538, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3074,10 +3076,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1180 + n * (1 ±0)` // Estimated: `1180 + n * (1 ±0)` - // Minimum execution time: 301_344_000 picoseconds. - Weight::from_parts(303_770_522, 1180) - // Standard Error: 29 - .saturating_add(Weight::from_parts(807, 0).saturating_mul(n.into())) + // Minimum execution time: 252_131_000 picoseconds. + Weight::from_parts(259_960_286, 1180) + // Standard Error: 121 + .saturating_add(Weight::from_parts(192, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -3097,10 +3099,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1373 + r * (45 ±0)` // Estimated: `26753 + r * (2700 ±0)` - // Minimum execution time: 286_835_000 picoseconds. - Weight::from_parts(245_206_457, 26753) - // Standard Error: 73_782 - .saturating_add(Weight::from_parts(36_414_448, 0).saturating_mul(r.into())) + // Minimum execution time: 235_860_000 picoseconds. + Weight::from_parts(124_993_651, 26753) + // Standard Error: 22_811 + .saturating_add(Weight::from_parts(36_467_740, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(4_u64)) @@ -3122,10 +3124,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1237 + r * (256 ±0)` // Estimated: `26028 + r * (6235 ±0)` - // Minimum execution time: 287_184_000 picoseconds. - Weight::from_parts(287_525_000, 26028) - // Standard Error: 66_791 - .saturating_add(Weight::from_parts(261_473_539, 0).saturating_mul(r.into())) + // Minimum execution time: 237_221_000 picoseconds. + Weight::from_parts(237_632_000, 26028) + // Standard Error: 89_502 + .saturating_add(Weight::from_parts(212_211_534, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3146,11 +3148,11 @@ impl WeightInfo for () { fn seal_delegate_call(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + r * (502 ±0)` - // Estimated: `21755 + r * (6329 ±10)` - // Minimum execution time: 285_759_000 picoseconds. - Weight::from_parts(286_643_000, 21755) - // Standard Error: 133_180 - .saturating_add(Weight::from_parts(257_186_897, 0).saturating_mul(r.into())) + // Estimated: `21755 + r * (6329 ±3)` + // Minimum execution time: 236_965_000 picoseconds. + Weight::from_parts(238_110_000, 21755) + // Standard Error: 101_332 + .saturating_add(Weight::from_parts(206_790_203, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3173,12 +3175,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1154 + t * (204 ±0)` // Estimated: `31015 + t * (5970 ±0)` - // Minimum execution time: 459_675_000 picoseconds. - Weight::from_parts(427_010_987, 31015) - // Standard Error: 1_277_377 - .saturating_add(Weight::from_parts(36_899_889, 0).saturating_mul(t.into())) + // Minimum execution time: 411_974_000 picoseconds. + Weight::from_parts(391_387_689, 31015) + // Standard Error: 1_320_695 + .saturating_add(Weight::from_parts(29_766_122, 0).saturating_mul(t.into())) // Standard Error: 1 - .saturating_add(Weight::from_parts(651, 0).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(597, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(t.into()))) .saturating_add(RocksDbWeight::get().writes(5_u64)) @@ -3204,10 +3206,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1301 + r * (254 ±0)` // Estimated: `30977 + r * (16635 ±0)` - // Minimum execution time: 285_816_000 picoseconds. - Weight::from_parts(286_349_000, 30977) - // Standard Error: 269_144 - .saturating_add(Weight::from_parts(394_282_520, 0).saturating_mul(r.into())) + // Minimum execution time: 237_595_000 picoseconds. + Weight::from_parts(238_068_000, 30977) + // Standard Error: 254_409 + .saturating_add(Weight::from_parts(346_436_154, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().reads((6_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(6_u64)) @@ -3235,14 +3237,14 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1071 + t * (187 ±0)` // Estimated: `42684 + t * (3588 ±2)` - // Minimum execution time: 1_708_330_000 picoseconds. - Weight::from_parts(395_059_764, 42684) - // Standard Error: 4_545_552 - .saturating_add(Weight::from_parts(114_039_862, 0).saturating_mul(t.into())) + // Minimum execution time: 1_616_768_000 picoseconds. + Weight::from_parts(363_003_254, 42684) + // Standard Error: 4_398_669 + .saturating_add(Weight::from_parts(104_529_967, 0).saturating_mul(t.into())) // Standard Error: 7 - .saturating_add(Weight::from_parts(1_213, 0).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(1_162, 0).saturating_mul(i.into())) // Standard Error: 7 - .saturating_add(Weight::from_parts(1_379, 0).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_333, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(13_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(t.into()))) .saturating_add(RocksDbWeight::get().writes(10_u64)) @@ -3264,10 +3266,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `777 + r * (8 ±0)` // Estimated: `21710 + r * (40 ±0)` - // Minimum execution time: 283_738_000 picoseconds. - Weight::from_parts(289_885_978, 21710) - // Standard Error: 1_057 - .saturating_add(Weight::from_parts(575_432, 0).saturating_mul(r.into())) + // Minimum execution time: 233_814_000 picoseconds. + Weight::from_parts(241_291_041, 21710) + // Standard Error: 1_422 + .saturating_add(Weight::from_parts(575_846, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) @@ -3287,10 +3289,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `785` // Estimated: `21745` - // Minimum execution time: 285_070_000 picoseconds. - Weight::from_parts(283_987_687, 21745) - // Standard Error: 6 - .saturating_add(Weight::from_parts(4_008, 0).saturating_mul(n.into())) + // Minimum execution time: 236_572_000 picoseconds. + Weight::from_parts(235_648_055, 21745) + // Standard Error: 3 + .saturating_add(Weight::from_parts(3_947, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3309,10 +3311,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `779 + r * (8 ±0)` // Estimated: `21725 + r * (40 ±0)` - // Minimum execution time: 281_613_000 picoseconds. - Weight::from_parts(285_429_053, 21725) - // Standard Error: 1_164 - .saturating_add(Weight::from_parts(756_244, 0).saturating_mul(r.into())) + // Minimum execution time: 234_473_000 picoseconds. + Weight::from_parts(239_805_309, 21725) + // Standard Error: 1_113 + .saturating_add(Weight::from_parts(752_507, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) @@ -3332,10 +3334,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `787` // Estimated: `21765` - // Minimum execution time: 284_593_000 picoseconds. - Weight::from_parts(278_467_111, 21765) + // Minimum execution time: 235_209_000 picoseconds. + Weight::from_parts(228_548_524, 21765) // Standard Error: 2 - .saturating_add(Weight::from_parts(3_217, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(3_171, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3354,10 +3356,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `779 + r * (8 ±0)` // Estimated: `21740 + r * (40 ±0)` - // Minimum execution time: 281_759_000 picoseconds. - Weight::from_parts(288_807_137, 21740) - // Standard Error: 805 - .saturating_add(Weight::from_parts(424_378, 0).saturating_mul(r.into())) + // Minimum execution time: 233_282_000 picoseconds. + Weight::from_parts(240_864_680, 21740) + // Standard Error: 958 + .saturating_add(Weight::from_parts(418_308, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) @@ -3377,10 +3379,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `787` // Estimated: `21785` - // Minimum execution time: 282_666_000 picoseconds. - Weight::from_parts(274_357_944, 21785) + // Minimum execution time: 234_667_000 picoseconds. + Weight::from_parts(227_810_077, 21785) // Standard Error: 2 - .saturating_add(Weight::from_parts(974, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(925, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3399,10 +3401,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `779 + r * (8 ±0)` // Estimated: `21745 + r * (40 ±0)` - // Minimum execution time: 285_073_000 picoseconds. - Weight::from_parts(287_226_796, 21745) - // Standard Error: 951 - .saturating_add(Weight::from_parts(425_368, 0).saturating_mul(r.into())) + // Minimum execution time: 234_040_000 picoseconds. + Weight::from_parts(237_970_694, 21745) + // Standard Error: 979 + .saturating_add(Weight::from_parts(416_562, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) @@ -3422,10 +3424,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `787` // Estimated: `21755` - // Minimum execution time: 283_407_000 picoseconds. - Weight::from_parts(276_737_242, 21755) + // Minimum execution time: 234_840_000 picoseconds. + Weight::from_parts(227_849_778, 21755) // Standard Error: 2 - .saturating_add(Weight::from_parts(967, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(923, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3444,10 +3446,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `822 + r * (76 ±0)` // Estimated: `21705 + r * (385 ±0)` - // Minimum execution time: 285_130_000 picoseconds. - Weight::from_parts(299_449_202, 21705) - // Standard Error: 16_535 - .saturating_add(Weight::from_parts(37_655_189, 0).saturating_mul(r.into())) + // Minimum execution time: 236_174_000 picoseconds. + Weight::from_parts(252_457_690, 21705) + // Standard Error: 20_130 + .saturating_add(Weight::from_parts(37_792_805, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 385).saturating_mul(r.into())) @@ -3467,10 +3469,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `792 + r * (42 ±0)` // Estimated: `21780 + r * (210 ±0)` - // Minimum execution time: 284_494_000 picoseconds. - Weight::from_parts(282_154_339, 21780) - // Standard Error: 12_278 - .saturating_add(Weight::from_parts(9_501_559, 0).saturating_mul(r.into())) + // Minimum execution time: 236_251_000 picoseconds. + Weight::from_parts(242_254_305, 21780) + // Standard Error: 9_765 + .saturating_add(Weight::from_parts(9_341_334, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 210).saturating_mul(r.into())) @@ -3492,10 +3494,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0 + r * (964 ±0)` // Estimated: `29920 + r * (11544 ±7)` - // Minimum execution time: 285_306_000 picoseconds. - Weight::from_parts(286_080_000, 29920) - // Standard Error: 43_813 - .saturating_add(Weight::from_parts(21_758_329, 0).saturating_mul(r.into())) + // Minimum execution time: 236_462_000 picoseconds. + Weight::from_parts(236_997_000, 29920) + // Standard Error: 46_527 + .saturating_add(Weight::from_parts(21_858_761, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3517,10 +3519,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `773 + r * (3 ±0)` // Estimated: `21735 + r * (15 ±0)` - // Minimum execution time: 283_487_000 picoseconds. - Weight::from_parts(289_280_189, 21735) - // Standard Error: 829 - .saturating_add(Weight::from_parts(168_973, 0).saturating_mul(r.into())) + // Minimum execution time: 235_085_000 picoseconds. + Weight::from_parts(239_410_836, 21735) + // Standard Error: 414 + .saturating_add(Weight::from_parts(167_067, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 15).saturating_mul(r.into())) @@ -3540,10 +3542,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1975 + r * (39 ±0)` // Estimated: `27145 + r * (200 ±0)` - // Minimum execution time: 287_413_000 picoseconds. - Weight::from_parts(314_662_286, 27145) - // Standard Error: 1_099 - .saturating_add(Weight::from_parts(262_201, 0).saturating_mul(r.into())) + // Minimum execution time: 236_690_000 picoseconds. + Weight::from_parts(268_793_030, 27145) + // Standard Error: 1_210 + .saturating_add(Weight::from_parts(263_330, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 200).saturating_mul(r.into())) @@ -3565,10 +3567,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `776 + r * (3 ±0)` // Estimated: `24004 + r * (18 ±0)` - // Minimum execution time: 282_601_000 picoseconds. - Weight::from_parts(289_374_203, 24004) - // Standard Error: 452 - .saturating_add(Weight::from_parts(142_661, 0).saturating_mul(r.into())) + // Minimum execution time: 236_289_000 picoseconds. + Weight::from_parts(246_581_099, 24004) + // Standard Error: 1_300 + .saturating_add(Weight::from_parts(137_499, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 18).saturating_mul(r.into())) @@ -3578,507 +3580,509 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_692_000 picoseconds. - Weight::from_parts(2_069_482, 0) - // Standard Error: 40 - .saturating_add(Weight::from_parts(2_922, 0).saturating_mul(r.into())) + // Minimum execution time: 1_679_000 picoseconds. + Weight::from_parts(1_934_194, 0) + // Standard Error: 1 + .saturating_add(Weight::from_parts(3_000, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64load(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_690_000 picoseconds. - Weight::from_parts(2_303_602, 0) - // Standard Error: 4 - .saturating_add(Weight::from_parts(6_433, 0).saturating_mul(r.into())) + // Minimum execution time: 1_872_000 picoseconds. + Weight::from_parts(2_605_712, 0) + // Standard Error: 43 + .saturating_add(Weight::from_parts(6_321, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64store(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_701_000 picoseconds. - Weight::from_parts(2_321_142, 0) - // Standard Error: 4 - .saturating_add(Weight::from_parts(6_025, 0).saturating_mul(r.into())) + // Minimum execution time: 1_837_000 picoseconds. + Weight::from_parts(2_035_143, 0) + // Standard Error: 65 + .saturating_add(Weight::from_parts(6_202, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_select(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_656_000 picoseconds. - Weight::from_parts(2_090_881, 0) + // Minimum execution time: 1_684_000 picoseconds. + Weight::from_parts(2_044_218, 0) // Standard Error: 5 - .saturating_add(Weight::from_parts(7_941, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(7_929, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_if(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_659_000 picoseconds. - Weight::from_parts(1_816_547, 0) - // Standard Error: 5 - .saturating_add(Weight::from_parts(10_578, 0).saturating_mul(r.into())) + // Minimum execution time: 1_635_000 picoseconds. + Weight::from_parts(2_009_851, 0) + // Standard Error: 6 + .saturating_add(Weight::from_parts(10_724, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_br(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_683_000 picoseconds. - Weight::from_parts(1_970_907, 0) + // Minimum execution time: 1_667_000 picoseconds. + Weight::from_parts(1_869_395, 0) // Standard Error: 12 - .saturating_add(Weight::from_parts(4_636, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(4_618, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_br_if(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_651_000 picoseconds. - Weight::from_parts(2_263_817, 0) - // Standard Error: 68 - .saturating_add(Weight::from_parts(7_529, 0).saturating_mul(r.into())) + // Minimum execution time: 1_698_000 picoseconds. + Weight::from_parts(2_184_182, 0) + // Standard Error: 16 + .saturating_add(Weight::from_parts(6_833, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_br_table(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_687_000 picoseconds. - Weight::from_parts(1_349_186, 0) - // Standard Error: 31 - .saturating_add(Weight::from_parts(9_732, 0).saturating_mul(r.into())) + // Minimum execution time: 1_670_000 picoseconds. + Weight::from_parts(1_471_988, 0) + // Standard Error: 30 + .saturating_add(Weight::from_parts(9_550, 0).saturating_mul(r.into())) } /// The range of component `e` is `[1, 256]`. - fn instr_br_table_per_entry(_e: u32, ) -> Weight { + fn instr_br_table_per_entry(e: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_777_000 picoseconds. - Weight::from_parts(2_036_446, 0) + // Minimum execution time: 1_778_000 picoseconds. + Weight::from_parts(1_925_086, 0) + // Standard Error: 136 + .saturating_add(Weight::from_parts(502, 0).saturating_mul(e.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_call(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_686_000 picoseconds. - Weight::from_parts(464_449, 0) - // Standard Error: 383 - .saturating_add(Weight::from_parts(19_121, 0).saturating_mul(r.into())) + // Minimum execution time: 1_759_000 picoseconds. + Weight::from_parts(2_372_048, 0) + // Standard Error: 16 + .saturating_add(Weight::from_parts(17_953, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_call_indirect(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_855_000 picoseconds. - Weight::from_parts(3_381_585, 0) - // Standard Error: 18 - .saturating_add(Weight::from_parts(24_245, 0).saturating_mul(r.into())) + // Minimum execution time: 1_852_000 picoseconds. + Weight::from_parts(3_125_003, 0) + // Standard Error: 25 + .saturating_add(Weight::from_parts(24_218, 0).saturating_mul(r.into())) } /// The range of component `l` is `[0, 1024]`. fn instr_call_per_local(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_792_000 picoseconds. - Weight::from_parts(2_006_024, 0) - // Standard Error: 16 - .saturating_add(Weight::from_parts(2_181, 0).saturating_mul(l.into())) + // Minimum execution time: 1_795_000 picoseconds. + Weight::from_parts(2_121_763, 0) + // Standard Error: 45 + .saturating_add(Weight::from_parts(1_207, 0).saturating_mul(l.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_local_get(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_918_000 picoseconds. - Weight::from_parts(4_618_761, 0) - // Standard Error: 49 - .saturating_add(Weight::from_parts(2_312, 0).saturating_mul(r.into())) + // Minimum execution time: 3_019_000 picoseconds. + Weight::from_parts(3_267_108, 0) + // Standard Error: 55 + .saturating_add(Weight::from_parts(2_527, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_local_set(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_889_000 picoseconds. - Weight::from_parts(4_151_280, 0) + // Minimum execution time: 2_944_000 picoseconds. + Weight::from_parts(3_183_331, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(3_623, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_618, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_local_tee(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_880_000 picoseconds. - Weight::from_parts(4_225_780, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(3_847, 0).saturating_mul(r.into())) + // Minimum execution time: 3_009_000 picoseconds. + Weight::from_parts(3_178_158, 0) + // Standard Error: 41 + .saturating_add(Weight::from_parts(4_075, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_global_get(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_765_000 picoseconds. - Weight::from_parts(2_216_674, 0) - // Standard Error: 4 - .saturating_add(Weight::from_parts(8_393, 0).saturating_mul(r.into())) + // Minimum execution time: 1_748_000 picoseconds. + Weight::from_parts(2_371_911, 0) + // Standard Error: 10 + .saturating_add(Weight::from_parts(8_378, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_global_set(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_764_000 picoseconds. - Weight::from_parts(2_246_735, 0) - // Standard Error: 5 - .saturating_add(Weight::from_parts(8_877, 0).saturating_mul(r.into())) + // Minimum execution time: 1_795_000 picoseconds. + Weight::from_parts(1_311_997, 0) + // Standard Error: 157 + .saturating_add(Weight::from_parts(9_410, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_memory_current(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_758_000 picoseconds. - Weight::from_parts(1_922_386, 0) - // Standard Error: 94 - .saturating_add(Weight::from_parts(3_868, 0).saturating_mul(r.into())) + // Minimum execution time: 2_059_000 picoseconds. + Weight::from_parts(2_416_611, 0) + // Standard Error: 5 + .saturating_add(Weight::from_parts(3_775, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 16]`. fn instr_memory_grow(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_635_000 picoseconds. - Weight::from_parts(1_118_785, 0) - // Standard Error: 134_978 - .saturating_add(Weight::from_parts(16_343_664, 0).saturating_mul(r.into())) + // Minimum execution time: 1_764_000 picoseconds. + Weight::from_parts(1_414_442, 0) + // Standard Error: 142_321 + .saturating_add(Weight::from_parts(13_210_495, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64clz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_648_000 picoseconds. - Weight::from_parts(2_012_545, 0) + // Minimum execution time: 1_665_000 picoseconds. + Weight::from_parts(2_047_968, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(3_824, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(4_035, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64ctz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_688_000 picoseconds. - Weight::from_parts(1_995_956, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(3_757, 0).saturating_mul(r.into())) + // Minimum execution time: 1_696_000 picoseconds. + Weight::from_parts(2_101_548, 0) + // Standard Error: 13 + .saturating_add(Weight::from_parts(3_754, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64popcnt(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_631_000 picoseconds. - Weight::from_parts(2_011_493, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(3_755, 0).saturating_mul(r.into())) + // Minimum execution time: 1_686_000 picoseconds. + Weight::from_parts(2_023_482, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(3_770, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64eqz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_667_000 picoseconds. - Weight::from_parts(1_958_798, 0) + // Minimum execution time: 1_700_000 picoseconds. + Weight::from_parts(2_035_759, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(3_677, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_660, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64extendsi32(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_674_000 picoseconds. - Weight::from_parts(2_009_555, 0) - // Standard Error: 7 - .saturating_add(Weight::from_parts(3_863, 0).saturating_mul(r.into())) + // Minimum execution time: 1_682_000 picoseconds. + Weight::from_parts(2_015_828, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(3_977, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64extendui32(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_659_000 picoseconds. - Weight::from_parts(2_014_985, 0) + // Minimum execution time: 1_660_000 picoseconds. + Weight::from_parts(2_032_387, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(3_821, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_826, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i32wrapi64(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_640_000 picoseconds. - Weight::from_parts(2_013_939, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(3_708, 0).saturating_mul(r.into())) + // Minimum execution time: 1_635_000 picoseconds. + Weight::from_parts(2_013_228, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(3_752, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64eq(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_631_000 picoseconds. - Weight::from_parts(2_002_814, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(6_008, 0).saturating_mul(r.into())) + // Minimum execution time: 1_698_000 picoseconds. + Weight::from_parts(2_844_817, 0) + // Standard Error: 56 + .saturating_add(Weight::from_parts(5_746, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64ne(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_647_000 picoseconds. - Weight::from_parts(2_032_158, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(5_944, 0).saturating_mul(r.into())) + // Minimum execution time: 1_686_000 picoseconds. + Weight::from_parts(2_208_884, 0) + // Standard Error: 138 + .saturating_add(Weight::from_parts(6_032, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64lts(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_669_000 picoseconds. - Weight::from_parts(2_040_386, 0) + // Minimum execution time: 1_695_000 picoseconds. + Weight::from_parts(2_060_880, 0) // Standard Error: 3 - .saturating_add(Weight::from_parts(6_009, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(5_966, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64ltu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_637_000 picoseconds. - Weight::from_parts(1_983_695, 0) - // Standard Error: 4 - .saturating_add(Weight::from_parts(6_027, 0).saturating_mul(r.into())) + // Minimum execution time: 1_700_000 picoseconds. + Weight::from_parts(2_143_484, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(5_932, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64gts(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_701_000 picoseconds. - Weight::from_parts(2_054_295, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(5_799, 0).saturating_mul(r.into())) + // Minimum execution time: 1_677_000 picoseconds. + Weight::from_parts(2_081_646, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(5_813, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64gtu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_653_000 picoseconds. - Weight::from_parts(2_749_807, 0) - // Standard Error: 90 - .saturating_add(Weight::from_parts(5_945, 0).saturating_mul(r.into())) + // Minimum execution time: 2_476_000 picoseconds. + Weight::from_parts(2_161_801, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(6_078, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64les(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_651_000 picoseconds. - Weight::from_parts(1_979_111, 0) + // Minimum execution time: 1_677_000 picoseconds. + Weight::from_parts(2_043_451, 0) // Standard Error: 3 - .saturating_add(Weight::from_parts(6_011, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(5_988, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64leu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_743_000 picoseconds. - Weight::from_parts(2_058_081, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(6_085, 0).saturating_mul(r.into())) + // Minimum execution time: 1_694_000 picoseconds. + Weight::from_parts(2_058_196, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(6_058, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64ges(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_638_000 picoseconds. - Weight::from_parts(2_038_929, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(5_941, 0).saturating_mul(r.into())) + // Minimum execution time: 1_675_000 picoseconds. + Weight::from_parts(2_036_798, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(5_956, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64geu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_641_000 picoseconds. - Weight::from_parts(2_036_587, 0) + // Minimum execution time: 1_712_000 picoseconds. + Weight::from_parts(2_121_407, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(6_008, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(5_944, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64add(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_624_000 picoseconds. - Weight::from_parts(2_080_562, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(5_826, 0).saturating_mul(r.into())) + // Minimum execution time: 1_675_000 picoseconds. + Weight::from_parts(2_061_053, 0) + // Standard Error: 6 + .saturating_add(Weight::from_parts(5_823, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64sub(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_652_000 picoseconds. - Weight::from_parts(2_039_535, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(6_137, 0).saturating_mul(r.into())) + // Minimum execution time: 1_686_000 picoseconds. + Weight::from_parts(2_023_347, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(6_126, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64mul(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_666_000 picoseconds. - Weight::from_parts(2_056_354, 0) - // Standard Error: 6 - .saturating_add(Weight::from_parts(5_780, 0).saturating_mul(r.into())) + // Minimum execution time: 1_678_000 picoseconds. + Weight::from_parts(2_390_920, 0) + // Standard Error: 55 + .saturating_add(Weight::from_parts(5_635, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64divs(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_648_000 picoseconds. - Weight::from_parts(2_077_695, 0) - // Standard Error: 4 - .saturating_add(Weight::from_parts(11_775, 0).saturating_mul(r.into())) + // Minimum execution time: 1_728_000 picoseconds. + Weight::from_parts(1_944_457, 0) + // Standard Error: 7 + .saturating_add(Weight::from_parts(11_848, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64divu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_797_000 picoseconds. - Weight::from_parts(2_772_388, 0) - // Standard Error: 33 - .saturating_add(Weight::from_parts(10_333, 0).saturating_mul(r.into())) + // Minimum execution time: 1_649_000 picoseconds. + Weight::from_parts(1_881_148, 0) + // Standard Error: 6 + .saturating_add(Weight::from_parts(10_618, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64rems(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_699_000 picoseconds. - Weight::from_parts(2_174_288, 0) + // Minimum execution time: 1_708_000 picoseconds. + Weight::from_parts(1_767_912, 0) // Standard Error: 6 - .saturating_add(Weight::from_parts(11_778, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(12_099, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64remu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_685_000 picoseconds. - Weight::from_parts(2_091_037, 0) + // Minimum execution time: 1_650_000 picoseconds. + Weight::from_parts(1_998_575, 0) // Standard Error: 3 - .saturating_add(Weight::from_parts(10_694, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(10_632, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64and(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_636_000 picoseconds. - Weight::from_parts(1_975_521, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(5_695, 0).saturating_mul(r.into())) + // Minimum execution time: 1_633_000 picoseconds. + Weight::from_parts(2_029_981, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(5_662, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64or(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_619_000 picoseconds. - Weight::from_parts(2_045_492, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(5_770, 0).saturating_mul(r.into())) + // Minimum execution time: 1_621_000 picoseconds. + Weight::from_parts(2_029_743, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(5_762, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64xor(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_668_000 picoseconds. - Weight::from_parts(2_055_460, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(5_851, 0).saturating_mul(r.into())) + // Minimum execution time: 1_641_000 picoseconds. + Weight::from_parts(2_127_132, 0) + // Standard Error: 5 + .saturating_add(Weight::from_parts(5_818, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64shl(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_681_000 picoseconds. - Weight::from_parts(2_023_370, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(5_853, 0).saturating_mul(r.into())) + // Minimum execution time: 1_690_000 picoseconds. + Weight::from_parts(2_021_035, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(5_917, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64shrs(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_714_000 picoseconds. - Weight::from_parts(2_067_584, 0) + // Minimum execution time: 1_661_000 picoseconds. + Weight::from_parts(2_055_069, 0) // Standard Error: 3 - .saturating_add(Weight::from_parts(6_133, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(6_094, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64shru(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_602_000 picoseconds. - Weight::from_parts(2_055_530, 0) - // Standard Error: 138 - .saturating_add(Weight::from_parts(6_014, 0).saturating_mul(r.into())) + // Minimum execution time: 1_677_000 picoseconds. + Weight::from_parts(2_024_748, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(5_862, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64rotl(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_709_000 picoseconds. - Weight::from_parts(2_016_365, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(5_985, 0).saturating_mul(r.into())) + // Minimum execution time: 1_651_000 picoseconds. + Weight::from_parts(2_005_814, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(6_007, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64rotr(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_661_000 picoseconds. - Weight::from_parts(2_003_063, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(5_863, 0).saturating_mul(r.into())) + // Minimum execution time: 1_703_000 picoseconds. + Weight::from_parts(2_019_636, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(5_862, 0).saturating_mul(r.into())) } } From faeed2895ad8f275c7f06075ea17269459605087 Mon Sep 17 00:00:00 2001 From: Aaron Bassett Date: Mon, 27 Mar 2023 22:36:20 +0200 Subject: [PATCH 576/715] Change license of node-template and FRAME examples to MIT-0 (#13465) * Change node-template license from Unlicense to MIT-0 * Change frame examples license from Unlicense to MIT-0 * Update bin/node-template/LICENSE --------- Co-authored-by: Oliver Tale-Yazdi Co-authored-by: parity-processbot <> --- bin/node-template/LICENSE | 34 +++++++------------ bin/node-template/node/Cargo.toml | 2 +- bin/node-template/pallets/template/Cargo.toml | 2 +- bin/node-template/pallets/template/README.md | 2 +- bin/node-template/runtime/Cargo.toml | 2 +- frame/examples/basic/Cargo.toml | 2 +- frame/examples/basic/README.md | 2 +- frame/examples/offchain-worker/Cargo.toml | 2 +- frame/examples/offchain-worker/README.md | 2 +- 9 files changed, 21 insertions(+), 29 deletions(-) diff --git a/bin/node-template/LICENSE b/bin/node-template/LICENSE index cf1ab25da0349..ffa0b3f2df035 100644 --- a/bin/node-template/LICENSE +++ b/bin/node-template/LICENSE @@ -1,24 +1,16 @@ -This is free and unencumbered software released into the public domain. +MIT No Attribution -Anyone is free to copy, modify, publish, use, compile, sell, or -distribute this software, either in source code form or as a compiled -binary, for any purpose, commercial or non-commercial, and by any -means. +Copyright Parity Technologies (UK) Ltd. -In jurisdictions that recognize copyright laws, the author or authors -of this software dedicate any and all copyright interest in the -software to the public domain. We make this dedication for the benefit -of the public at large and to the detriment of our heirs and -successors. We intend this dedication to be an overt act of -relinquishment in perpetuity of all present and future rights to this -software under copyright law. +Permission is hereby granted, free of charge, to any person obtaining a copy of this +software and associated documentation files (the "Software"), to deal in the Software +without restriction, including without limitation the rights to use, copy, modify, +merge, publish, distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR -OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. - -For more information, please refer to +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/bin/node-template/node/Cargo.toml b/bin/node-template/node/Cargo.toml index 979c00120ddb7..ac64b8881caef 100644 --- a/bin/node-template/node/Cargo.toml +++ b/bin/node-template/node/Cargo.toml @@ -5,7 +5,7 @@ description = "A fresh FRAME-based Substrate node, ready for hacking." authors = ["Substrate DevHub "] homepage = "https://substrate.io/" edition = "2021" -license = "Unlicense" +license = "MIT-0" publish = false repository = "https://github.com/substrate-developer-hub/substrate-node-template/" build = "build.rs" diff --git a/bin/node-template/pallets/template/Cargo.toml b/bin/node-template/pallets/template/Cargo.toml index f6607b25c4d62..ddf7c6e52fb2f 100644 --- a/bin/node-template/pallets/template/Cargo.toml +++ b/bin/node-template/pallets/template/Cargo.toml @@ -5,7 +5,7 @@ description = "FRAME pallet template for defining custom runtime logic." authors = ["Substrate DevHub "] homepage = "https://substrate.io" edition = "2021" -license = "Unlicense" +license = "MIT-0" publish = false repository = "https://github.com/substrate-developer-hub/substrate-node-template/" diff --git a/bin/node-template/pallets/template/README.md b/bin/node-template/pallets/template/README.md index 8d751a42207dd..d0d59537c12d7 100644 --- a/bin/node-template/pallets/template/README.md +++ b/bin/node-template/pallets/template/README.md @@ -1 +1 @@ -License: Unlicense \ No newline at end of file +License: MIT-0 \ No newline at end of file diff --git a/bin/node-template/runtime/Cargo.toml b/bin/node-template/runtime/Cargo.toml index 90fa6269ebe8c..8915061c17c6d 100644 --- a/bin/node-template/runtime/Cargo.toml +++ b/bin/node-template/runtime/Cargo.toml @@ -5,7 +5,7 @@ description = "A fresh FRAME-based Substrate node, ready for hacking." authors = ["Substrate DevHub "] homepage = "https://substrate.io/" edition = "2021" -license = "Unlicense" +license = "MIT-0" publish = false repository = "https://github.com/substrate-developer-hub/substrate-node-template/" diff --git a/frame/examples/basic/Cargo.toml b/frame/examples/basic/Cargo.toml index 47f623f45381c..2f854011b0abd 100644 --- a/frame/examples/basic/Cargo.toml +++ b/frame/examples/basic/Cargo.toml @@ -3,7 +3,7 @@ name = "pallet-example-basic" version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2021" -license = "Unlicense" +license = "MIT-0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME example pallet" diff --git a/frame/examples/basic/README.md b/frame/examples/basic/README.md index 358829192f11d..2af50573f8075 100644 --- a/frame/examples/basic/README.md +++ b/frame/examples/basic/README.md @@ -237,4 +237,4 @@ pub trait Config: ::Config { } // that the implementation is based on.

-License: Unlicense +License: MIT-0 diff --git a/frame/examples/offchain-worker/Cargo.toml b/frame/examples/offchain-worker/Cargo.toml index f94cf36b2b992..fb4c12ae0b61d 100644 --- a/frame/examples/offchain-worker/Cargo.toml +++ b/frame/examples/offchain-worker/Cargo.toml @@ -3,7 +3,7 @@ name = "pallet-example-offchain-worker" version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2021" -license = "Unlicense" +license = "MIT-0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME example pallet for offchain worker" diff --git a/frame/examples/offchain-worker/README.md b/frame/examples/offchain-worker/README.md index 587431c92c0ed..7b8905cda3074 100644 --- a/frame/examples/offchain-worker/README.md +++ b/frame/examples/offchain-worker/README.md @@ -26,4 +26,4 @@ Additional logic in OCW is put in place to prevent spamming the network with bot and unsigned transactions, and custom `UnsignedValidator` makes sure that there is only one unsigned transaction floating in the network. -License: Unlicense +License: MIT-0 From 3fa99a9859fd552b81963c20198210db2f0e6ed6 Mon Sep 17 00:00:00 2001 From: Joyce Siqueira <98593770+the-right-joyce@users.noreply.github.com> Date: Mon, 27 Mar 2023 18:27:16 -0300 Subject: [PATCH 577/715] updating labels descriptions (#13557) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * updating labels descriptions * delete milestones * Update docs/CONTRIBUTING.adoc Co-authored-by: Bastian Köcher * link to label docs * Update docs/CONTRIBUTING.adoc Co-authored-by: Oliver Tale-Yazdi --------- Co-authored-by: Bastian Köcher Co-authored-by: parity-processbot <> Co-authored-by: Oliver Tale-Yazdi --- docs/CONTRIBUTING.adoc | 38 +++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/docs/CONTRIBUTING.adoc b/docs/CONTRIBUTING.adoc index d39b8a6d729ff..05a9434ac81ab 100644 --- a/docs/CONTRIBUTING.adoc +++ b/docs/CONTRIBUTING.adoc @@ -30,26 +30,23 @@ A Pull Request (PR) needs to be reviewed and approved by project maintainers unl - `A-*` Pull request status. ONE REQUIRED. - `B-*` Changelog and/or Runtime-upgrade post composition markers. ONE REQUIRED. (used by automation) -- `C-*` Release notes release-priority markers. EXACTLY ONE REQUIRED. (used by automation) -- `D-*` More general tags on the PR denoting various implications and requirements. +- `C-*` Release notes release-criticality markers. EXACTLY ONE REQUIRED. (used by automation) +- `D-*` Audit tags denoting auditing requirements on the PR. *Process:* . Please tag each PR with exactly one `A`, `B`, `C` and `D` label at the minimum. -. Once a PR is ready for review please add the https://github.com/paritytech/substrate/pulls?q=is%3Apr+is%3Aopen+label%3AA0-pleasereview[`A0-pleasereview`] label. Generally PRs should sit with this label for 48 hours in order to garner feedback. It may be merged before if all relevant parties had a look at it. -. If the first review is not an approval, swap `A0-pleasereview` to any label `[A3, A7]` to indicate that the PR has received some feedback, but needs further work. For example. https://github.com/paritytech/substrate/labels/A3-inprogress[`A3-inprogress`] is a general indicator that the PR is work in progress and https://github.com/paritytech/substrate/labels/A4-gotissues[`A4-gotissues`] means that it has significant problems that need fixing. Once the work is done, change the label back to `A0-pleasereview`. You might end up swapping a few times back and forth to climb up the A label group. Once a PR is https://github.com/paritytech/substrate/labels/A8-mergeoncegreen[`A8-mergeoncegreen`], it is ready to merge. -. PRs must be tagged with their release notes requirements via the `B1-B9` labels. -. PRs must be tagged with their release importance via the `C1-C9` labels. +. Once a PR is ready for review please add the https://github.com/paritytech/substrate/pulls?q=is%3Apr+is%3Aopen+label%3AA0-please_review+[`A0-please_review`] label. Generally PRs should sit with this label for 48 hours in order to garner feedback. It may be merged before if all relevant parties had a look at it. +. If the first review is not an approval, swap `A0-please_review` to any label `[A3, A5]` to indicate that the PR has received some feedback, but needs further work. For example. https://github.com/paritytech/substrate/labels/A3-in_progress[`A3-in_progress`] is a general indicator that the PR is work in progress. +. PRs must be tagged with their release notes requirements via the `B*` labels. If a PR should be mentioned in the release notes, use `B1` and add either: `T0-node`, `T1-runtime`or `T2-API` - this defines in which section of the release notes the PR will be shown. +. PRs must be tagged with their release importance via the `C1-C7` 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`]. 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`]. -. PRs that materially change the FRAME/runtime semantics must be tagged with https://github.com/paritytech/substrate/labels/E6-transactionversion[`E6-transactionversion`]. -. PRs that change the mechanism for block authoring in a backwards-incompatible way must be tagged with https://github.com/paritytech/substrate/labels/E7-breaksauthoring[`E7-breaksauthoring`]. -. PRs that "break everything" must be tagged with https://github.com/paritytech/substrate/labels/E8-breakseverything[`E8-breakseverything`]. -. PRs that block a new release must be tagged with https://github.com/paritytech/substrate/labels/E9-blocker%20%E2%9B%94%EF%B8%8F[`E9-blocker`]. +. PRs that introduce runtime migrations must be tagged with https://github.com/paritytech/substrate/labels/E0-runtime_migration[`E0-runtime_migration`]. 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/E1-database_migration[`E1-database_migration`]. +. PRs that add host functions must be tagged with with https://github.com/paritytech/substrate/labels/E3-host_functions[`E3-host_functions`]. +. PRs that break the external API must be tagged with https://github.com/paritytech/substrate/labels/F3-breaks_API[`F3-breaks_API`]. +. PRs that change the mechanism for block authoring in a backwards-incompatible way must be tagged with https://github.com/paritytech/substrate/labels/F1-breaks_authoring[`F1-breaks_authoring`]. +. PRs that "break everything" must be tagged with https://github.com/paritytech/substrate/labels/F0-breaks_everything[`F0-breaks_everything`]. . PRs should be categorized into projects. . No PR should be merged until all reviews' comments are addressed and CI is successful. @@ -91,21 +88,20 @@ To create a Polkadot companion PR: 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. +If your PR is reviewed well, but a Polkadot PR is missing, signal it with https://github.com/paritytech/substrate/labels/E6-needs_polkadot_pr[`E6-needs_polkadot_pr`] to prevent it from getting automatically merged. In most cases the CI will add this label automatically. As there might be multiple pending PRs that might conflict with one another, a) you should not merge the substrate PR until the Polkadot PR has also been reviewed and b) both should be merged pretty quickly after another to not block others. == Helping out -We use https://github.com/paritytech/substrate/labels[labels] to manage PRs and issues and communicate state of a PR. Please familiarize yourself with them. Furthermore we are organizing issues in https://github.com/paritytech/substrate/milestones[milestones]. Best way to get started is to a pick a ticket from the current milestone tagged https://github.com/paritytech/substrate/issues?q=is%3Aissue+is%3Aopen+label%3AQ2-easy[`easy`] or https://github.com/paritytech/substrate/issues?q=is%3Aissue+is%3Aopen+label%3AQ3-medium[`medium`] and get going or https://github.com/paritytech/substrate/issues?q=is%3Aissue+is%3Aopen+label%3AX1-mentor[`mentor`] and get in contact with the mentor offering their support on that larger task. +We use https://paritytech.github.io/labels/doc_substrate.html[labels] to manage PRs and issues and communicate state of a PR. Please familiarize yourself with them. Best way to get started is to a pick a ticket tagged https://github.com/paritytech/substrate/issues?q=is%3Aissue+is%3Aopen+label%3AZ1-easy[`easy`] or https://github.com/paritytech/substrate/issues?q=is%3Aissue+is%3Aopen+label%3AZ2-medium[`medium`] and get going or https://github.com/paritytech/substrate/issues?q=is%3Aissue+is%3Aopen+label%3AZ6-mentor[`mentor`] and get in contact with the mentor offering their support on that larger task. == Issues Please label issues with the following labels: -. `I-*` Issue severity and type. EXACTLY ONE REQUIRED. -. `P-*` Issue priority. AT MOST ONE ALLOWED. -. `Q-*` Issue difficulty. AT MOST ONE ALLOWED. -. `Z-*` More general tags on the issue, denoting context and resolution. +. `I-*` or `J-*` Issue severity and type. EXACTLY ONE REQUIRED. +. `U-*` Issue urgency, suggesting in what time manner does this issue need to be resolved. AT MOST ONE ALLOWED. +. `Z-*` Issue difficulty. AT MOST ONE ALLOWED. == Releases From ae49625b5f7a4fa267082f8d415ea4f66ac02423 Mon Sep 17 00:00:00 2001 From: Vladimir Istyufeev Date: Tue, 28 Mar 2023 04:00:18 +0400 Subject: [PATCH 578/715] CI: Investigate why `RUSTFLAGS` differs on `master` and PRs (#13686) --- scripts/ci/gitlab/pipeline/test.yml | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/scripts/ci/gitlab/pipeline/test.yml b/scripts/ci/gitlab/pipeline/test.yml index b5c37d243f1b3..d00f06b099671 100644 --- a/scripts/ci/gitlab/pipeline/test.yml +++ b/scripts/ci/gitlab/pipeline/test.yml @@ -236,17 +236,20 @@ test-frame-support: variables: # Enable debug assertions since we are running optimized builds for testing # but still want to have debug assertions. - RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" + RUSTFLAGS: "-C debug-assertions -D warnings" RUST_BACKTRACE: 1 WASM_BUILD_NO_COLOR: 1 - WASM_BUILD_RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" + WASM_BUILD_RUSTFLAGS: "-C debug-assertions -D warnings" # Ensure we run the UI tests. RUN_UI_TESTS: 1 script: + - echo $RUSTFLAGS - 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 + - cat /cargo_target_dir/debug/.fingerprint/memory_units-759eddf317490d2b/lib-memory_units.json || true + - time cargo test --verbose --locked -p frame-support-test --features=frame-feature-testing,no-metadata-docs --manifest-path ./frame/support/test/Cargo.toml --test pallet + - time cargo test --verbose --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 - SUBSTRATE_TEST_TIMEOUT=1 time cargo test -p substrate-test-utils --release --verbose --locked -- --ignored timeout + - cat /cargo_target_dir/debug/.fingerprint/memory_units-759eddf317490d2b/lib-memory_units.json || true - rusty-cachier cache upload # This job runs tests that don't work with cargo-nextest in test-linux-stable From 9b43d8f891b1e53be2aa55687632ac6b17800cf8 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Tue, 28 Mar 2023 09:10:50 +0200 Subject: [PATCH 579/715] Remove HeaderBackend requirement from AuthorityDiscovery and NetworkWorker (#13730) * Remove `HeaderBackend` requirement from `NetworkWorker` * Remove HeaderBackend from authority-discovery --- client/authority-discovery/src/error.rs | 4 ++++ client/authority-discovery/src/lib.rs | 3 ++- client/authority-discovery/src/worker.rs | 15 +++++++++++---- client/network/src/config.rs | 10 +++++----- client/network/src/service.rs | 19 +++++++------------ client/network/test/src/lib.rs | 8 +++++--- client/network/test/src/service.rs | 9 ++++++--- client/service/src/builder.rs | 5 +++-- 8 files changed, 43 insertions(+), 30 deletions(-) diff --git a/client/authority-discovery/src/error.rs b/client/authority-discovery/src/error.rs index 447116b0f6b56..13148bb338c2f 100644 --- a/client/authority-discovery/src/error.rs +++ b/client/authority-discovery/src/error.rs @@ -23,6 +23,7 @@ pub type Result = std::result::Result; /// Error type for the authority discovery module. #[derive(Debug, thiserror::Error)] +#[allow(missing_docs)] pub enum Error { #[error("Received dht value found event with records with different keys.")] ReceivingDhtValueFoundEventWithDifferentKeys, @@ -71,4 +72,7 @@ pub enum Error { #[error("Received authority record without a valid signature for the remote peer id.")] MissingPeerIdSignature, + + #[error("Unable to fetch best block.")] + BestBlockFetchingError, } diff --git a/client/authority-discovery/src/lib.rs b/client/authority-discovery/src/lib.rs index a3c6699091297..6bb12804cada3 100644 --- a/client/authority-discovery/src/lib.rs +++ b/client/authority-discovery/src/lib.rs @@ -28,6 +28,7 @@ //! See [`Worker`] and [`Service`] for more documentation. pub use crate::{ + error::Error, service::Service, worker::{AuthorityDiscovery, NetworkProvider, Role, Worker}, }; @@ -148,7 +149,7 @@ pub fn new_worker_and_service_with_config + HeaderBackend + 'static, + Client: AuthorityDiscovery + '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 43e44cac4d3fe..590d1dd19dc12 100644 --- a/client/authority-discovery/src/worker.rs +++ b/client/authority-discovery/src/worker.rs @@ -157,12 +157,15 @@ pub trait AuthorityDiscovery { /// Retrieve authority identifiers of the current and next authority set. async fn authorities(&self, at: Block::Hash) -> std::result::Result, ApiError>; + + /// Retrieve best block hash + async fn best_hash(&self) -> std::result::Result; } #[async_trait::async_trait] impl AuthorityDiscovery for T where - T: ProvideRuntimeApi + Send + Sync, + T: ProvideRuntimeApi + HeaderBackend + Send + Sync, T::Api: AuthorityDiscoveryApi, Block: BlockT, { @@ -172,13 +175,17 @@ where ) -> std::result::Result, ApiError> { self.runtime_api().authorities(at) } + + async fn best_hash(&self) -> std::result::Result { + Ok(self.info().best_hash) + } } impl Worker where Block: BlockT + Unpin + 'static, Network: NetworkProvider, - Client: AuthorityDiscovery + HeaderBackend + 'static, + Client: AuthorityDiscovery + 'static, DhtEventStream: Stream + Unpin, { /// Construct a [`Worker`]. @@ -376,7 +383,7 @@ where } async fn refill_pending_lookups_queue(&mut self) -> Result<()> { - let best_hash = self.client.info().best_hash; + let best_hash = self.client.best_hash().await?; let local_keys = match &self.role { Role::PublishAndDiscover(key_store) => key_store @@ -594,7 +601,7 @@ where .into_iter() .collect::>(); - let best_hash = client.info().best_hash; + let best_hash = client.best_hash().await?; let authorities = client .authorities(best_hash) .await diff --git a/client/network/src/config.rs b/client/network/src/config.rs index 925a7795d290f..3c6801f22a35c 100644 --- a/client/network/src/config.rs +++ b/client/network/src/config.rs @@ -34,6 +34,7 @@ use prometheus_endpoint::Registry; pub use sc_network_common::{role::Role, sync::warp::WarpSyncProvider, ExHashT}; use zeroize::Zeroize; +use sp_runtime::traits::Block as BlockT; use std::{ error::Error, fmt, fs, @@ -44,7 +45,6 @@ use std::{ path::{Path, PathBuf}, pin::Pin, str::{self, FromStr}, - sync::Arc, }; pub use libp2p::{ @@ -688,7 +688,7 @@ impl NetworkConfiguration { } /// Network initialization parameters. -pub struct Params { +pub struct Params { /// Assigned role for our node (full, light, ...). pub role: Role, @@ -698,12 +698,12 @@ pub struct Params { /// Network layer configuration. pub network_config: NetworkConfiguration, - /// Client that contains the blockchain. - pub chain: Arc, - /// Legacy name of the protocol to use on the wire. Should be different for each chain. pub protocol_id: ProtocolId, + /// Genesis hash of the chain + pub genesis_hash: Block::Hash, + /// Fork ID to distinguish protocols of different hard forks. Part of the standard protocol /// name on the wire. pub fork_id: Option, diff --git a/client/network/src/service.rs b/client/network/src/service.rs index 6dc00b36ceb53..5f60f51321b42 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -73,8 +73,7 @@ use parking_lot::Mutex; use sc_network_common::ExHashT; use sc_peerset::PeersetHandle; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; -use sp_blockchain::HeaderBackend; -use sp_runtime::traits::{Block as BlockT, Zero}; +use sp_runtime::traits::Block as BlockT; use std::{ cmp, @@ -147,9 +146,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 + 'static>( - 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(); @@ -277,13 +274,11 @@ where config.discovery_limit( u64::from(params.network_config.default_peers_set.out_peers) + 15, ); - 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_kademlia( + params.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( diff --git a/client/network/test/src/lib.rs b/client/network/test/src/lib.rs index 75b8287b08dcf..6a99304035ab8 100644 --- a/client/network/test/src/lib.rs +++ b/client/network/test/src/lib.rs @@ -83,7 +83,7 @@ use sp_core::H256; use sp_runtime::{ codec::{Decode, Encode}, generic::BlockId, - 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; @@ -916,13 +916,15 @@ where let sync_service_import_queue = Box::new(sync_service.clone()); let sync_service = Arc::new(sync_service.clone()); - let network = NetworkWorker::new(sc_network::config::Params { + let genesis_hash = + client.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: Box::new(|f| { tokio::spawn(f); }), network_config, - chain: client.clone(), + genesis_hash, protocol_id, fork_id, metrics_registry: None, diff --git a/client/network/test/src/service.rs b/client/network/test/src/service.rs index b1de2a91ebcc9..67915c38637ed 100644 --- a/client/network/test/src/service.rs +++ b/client/network/test/src/service.rs @@ -34,7 +34,8 @@ use sc_network_sync::{ service::network::{NetworkServiceHandle, NetworkServiceProvider}, state_request_handler::StateRequestHandler, }; -use sp_runtime::traits::Block as BlockT; +use sp_blockchain::HeaderBackend; +use sp_runtime::traits::{Block as BlockT, Zero}; use substrate_test_runtime_client::{ runtime::{Block as TestBlock, Hash as TestHash}, TestClientBuilder, TestClientBuilderExt as _, @@ -194,17 +195,19 @@ impl TestNetworkBuilder { ) .unwrap(); let mut link = self.link.unwrap_or(Box::new(chain_sync_service.clone())); + let genesis_hash = + client.hash(Zero::zero()).ok().flatten().expect("Genesis block exists; qed"); let worker = NetworkWorker::< substrate_test_runtime_client::runtime::Block, substrate_test_runtime_client::runtime::Hash, - >::new(config::Params { + >::new(config::Params:: { block_announce_config, role: config::Role::Full, executor: Box::new(|f| { tokio::spawn(f); }), + genesis_hash, network_config, - chain: client.clone(), protocol_id, fork_id, metrics_registry: None, diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index f0f9a7ed0d4d7..7cbbf2a4dda0f 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -850,7 +850,8 @@ where protocol_config })); - let mut network_params = sc_network::config::Params { + let genesis_hash = client.hash(Zero::zero()).ok().flatten().expect("Genesis block exists; qed"); + let mut network_params = sc_network::config::Params:: { role: config.role.clone(), executor: { let spawn_handle = Clone::clone(&spawn_handle); @@ -859,7 +860,7 @@ where }) }, network_config: config.network.clone(), - chain: client.clone(), + genesis_hash, protocol_id: protocol_id.clone(), fork_id: config.chain_spec.fork_id().map(ToOwned::to_owned), metrics_registry: config.prometheus_config.as_ref().map(|config| config.registry.clone()), From dec0369a35893c2be432e74358c4c7039e1e57be Mon Sep 17 00:00:00 2001 From: Vladimir Istyufeev Date: Tue, 28 Mar 2023 15:41:10 +0400 Subject: [PATCH 580/715] CI: rephrase `RUSTFLAGS` (#13735) --- .gitlab-ci.yml | 2 ++ scripts/ci/gitlab/pipeline/test.yml | 21 ++++++++++----------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index c4d88ebde75f2..093a0bb415d09 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -105,6 +105,8 @@ variables: # $WASM_BUILD_WORKSPACE_HINT enables wasm-builder to find the Cargo.lock from within generated # packages - export WASM_BUILD_WORKSPACE_HINT="$PWD" + # ensure that RUSTFLAGS are set correctly + - echo $RUSTFLAGS .job-switcher: before_script: diff --git a/scripts/ci/gitlab/pipeline/test.yml b/scripts/ci/gitlab/pipeline/test.yml index d00f06b099671..331b382e41a6f 100644 --- a/scripts/ci/gitlab/pipeline/test.yml +++ b/scripts/ci/gitlab/pipeline/test.yml @@ -202,10 +202,10 @@ test-linux-stable: variables: # Enable debug assertions since we are running optimized builds for testing # but still want to have debug assertions. - RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" + RUSTFLAGS: "-C debug-assertions -D warnings" RUST_BACKTRACE: 1 WASM_BUILD_NO_COLOR: 1 - WASM_BUILD_RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" + WASM_BUILD_RUSTFLAGS: "-C debug-assertions -D warnings" # Ensure we run the UI tests. RUN_UI_TESTS: 1 # needed for rusty-cachier to keep cache in test-linux-stable folder and not in test-linux-stable-1/3 @@ -243,7 +243,6 @@ test-frame-support: # Ensure we run the UI tests. RUN_UI_TESTS: 1 script: - - echo $RUSTFLAGS - rusty-cachier snapshot create - cat /cargo_target_dir/debug/.fingerprint/memory_units-759eddf317490d2b/lib-memory_units.json || true - time cargo test --verbose --locked -p frame-support-test --features=frame-feature-testing,no-metadata-docs --manifest-path ./frame/support/test/Cargo.toml --test pallet @@ -261,10 +260,10 @@ test-linux-stable-extra: variables: # Enable debug assertions since we are running optimized builds for testing # but still want to have debug assertions. - RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" + RUSTFLAGS: "-C debug-assertions -D warnings" RUST_BACKTRACE: 1 WASM_BUILD_NO_COLOR: 1 - WASM_BUILD_RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" + WASM_BUILD_RUSTFLAGS: "-C debug-assertions -D warnings" # Ensure we run the UI tests. RUN_UI_TESTS: 1 script: @@ -286,10 +285,10 @@ quick-benchmarks: variables: # Enable debug assertions since we are running optimized builds for testing # but still want to have debug assertions. - RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" + RUSTFLAGS: "-C debug-assertions -D warnings" RUST_BACKTRACE: "full" WASM_BUILD_NO_COLOR: 1 - WASM_BUILD_RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" + WASM_BUILD_RUSTFLAGS: "-C debug-assertions -D warnings" script: - rusty-cachier snapshot create - time cargo run --locked --release --features runtime-benchmarks -- benchmark pallet --execution wasm --wasm-execution compiled --chain dev --pallet "*" --extrinsic "*" --steps 2 --repeat 1 @@ -305,7 +304,7 @@ test-frame-examples-compile-to-wasm: RUSTY_CACHIER_TOOLCHAIN: nightly # Enable debug assertions since we are running optimized builds for testing # but still want to have debug assertions. - RUSTFLAGS: "-Cdebug-assertions=y" + RUSTFLAGS: "-C debug-assertions" RUST_BACKTRACE: 1 script: - rusty-cachier snapshot create @@ -324,10 +323,10 @@ test-linux-stable-int: variables: # Enable debug assertions since we are running optimized builds for testing # but still want to have debug assertions. - RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" + RUSTFLAGS: "-C debug-assertions -D warnings" RUST_BACKTRACE: 1 WASM_BUILD_NO_COLOR: 1 - WASM_BUILD_RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" + WASM_BUILD_RUSTFLAGS: "-C debug-assertions -D warnings" # Ensure we run the UI tests. RUN_UI_TESTS: 1 script: @@ -373,7 +372,7 @@ test-full-crypto-feature: RUSTY_CACHIER_TOOLCHAIN: nightly # Enable debug assertions since we are running optimized builds for testing # but still want to have debug assertions. - RUSTFLAGS: "-Cdebug-assertions=y" + RUSTFLAGS: "-C debug-assertions" RUST_BACKTRACE: 1 script: - rusty-cachier snapshot create From 549165727c3b3c14b6f90011085aaebbeff9d7e3 Mon Sep 17 00:00:00 2001 From: Kasper Ziemianek Date: Tue, 28 Mar 2023 16:38:13 +0200 Subject: [PATCH 581/715] contracts: proper event link in docs (#13729) --- frame/contracts/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/contracts/README.md b/frame/contracts/README.md index 4f5f10a3af333..68fa49debc580 100644 --- a/frame/contracts/README.md +++ b/frame/contracts/README.md @@ -5,7 +5,7 @@ The Contract module provides functionality for the runtime to deploy and execute - [`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) +- [`Event`](https://paritytech.github.io/substrate/master/pallet_contracts/pallet/enum.Event.html) ## Overview From f40ba0d09785159a31a43b16b47ddb5ae8e62e1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 29 Mar 2023 09:17:50 +0200 Subject: [PATCH 582/715] Support stable rust for compiling the runtime (#13580) * Support stable rust for compiling the runtime This pull request brings support for compiling the runtime with stable Rust. This requires at least rust 1.68.0 to work on stable. The code is written in a way that it is backwards compatible and should automatically work when someone compiles with 1.68.0+ stable. * We always support nightlies! * :facepalm: * Sort by version * Review feedback * Review feedback * Fix version parsing * Apply suggestions from code review Co-authored-by: Koute --------- Co-authored-by: Koute --- Cargo.lock | 1 + primitives/io/Cargo.toml | 4 + primitives/io/build.rs | 27 ++++ primitives/io/src/lib.rs | 4 +- utils/wasm-builder/README.md | 11 +- utils/wasm-builder/src/lib.rs | 124 ++++++++++----- utils/wasm-builder/src/prerequisites.rs | 9 +- utils/wasm-builder/src/version.rs | 198 ++++++++++++++++++++++++ 8 files changed, 327 insertions(+), 51 deletions(-) create mode 100644 primitives/io/build.rs create mode 100644 utils/wasm-builder/src/version.rs diff --git a/Cargo.lock b/Cargo.lock index 33bca4005483c..cf30a6a94ae8f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10474,6 +10474,7 @@ dependencies = [ "libsecp256k1", "log", "parity-scale-codec", + "rustversion", "secp256k1", "sp-core", "sp-externalities", diff --git a/primitives/io/Cargo.toml b/primitives/io/Cargo.toml index e56bfcf56041a..c6e716396aea4 100644 --- a/primitives/io/Cargo.toml +++ b/primitives/io/Cargo.toml @@ -9,6 +9,7 @@ repository = "https://github.com/paritytech/substrate/" description = "I/O for Substrate runtimes" documentation = "https://docs.rs/sp-io" readme = "README.md" +build = "build.rs" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] @@ -37,6 +38,9 @@ ed25519-dalek = { version = "1.0.1", default-features = false, optional = true } # Force the usage of ed25519, this is being used in `ed25519-dalek`. ed25519 = { version = "1.5.2", optional = true } +[build-dependencies] +rustversion = "1.0.6" + [features] default = ["std"] std = [ diff --git a/primitives/io/build.rs b/primitives/io/build.rs new file mode 100644 index 0000000000000..8a9c0b6420b29 --- /dev/null +++ b/primitives/io/build.rs @@ -0,0 +1,27 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#[rustversion::before(1.68)] +fn main() { + if !cfg!(feature = "std") { + println!("cargo:rustc-cfg=enable_alloc_error_handler"); + } +} + +#[rustversion::since(1.68)] +fn main() {} diff --git a/primitives/io/src/lib.rs b/primitives/io/src/lib.rs index 306ac8e60c529..72300eb102177 100644 --- a/primitives/io/src/lib.rs +++ b/primitives/io/src/lib.rs @@ -19,7 +19,7 @@ #![warn(missing_docs)] #![cfg_attr(not(feature = "std"), no_std)] -#![cfg_attr(not(feature = "std"), feature(alloc_error_handler))] +#![cfg_attr(enable_alloc_error_handler, feature(alloc_error_handler))] #![cfg_attr( feature = "std", doc = "Substrate runtime standard library as compiled when linked with Rust's standard library." @@ -1643,7 +1643,7 @@ pub fn panic(info: &core::panic::PanicInfo) -> ! { } /// A default OOM handler for WASM environment. -#[cfg(all(not(feature = "disable_oom"), not(feature = "std")))] +#[cfg(all(not(feature = "disable_oom"), enable_alloc_error_handler))] #[alloc_error_handler] pub fn oom(_: core::alloc::Layout) -> ! { #[cfg(feature = "improved_panic_error_reporting")] diff --git a/utils/wasm-builder/README.md b/utils/wasm-builder/README.md index a10611cc26a00..b1ccb1b35b10e 100644 --- a/utils/wasm-builder/README.md +++ b/utils/wasm-builder/README.md @@ -77,8 +77,13 @@ Wasm builder requires the following prerequisites for building the Wasm binary: - rust nightly + `wasm32-unknown-unknown` toolchain -If a specific rust nightly is installed with `rustup`, it is important that the wasm target is installed -as well. For example if installing the rust nightly from 20.02.2020 using `rustup install nightly-2020-02-20`, -the wasm target needs to be installed as well `rustup target add wasm32-unknown-unknown --toolchain nightly-2020-02-20`. +or + +- rust stable and version at least 1.68.0 + `wasm32-unknown-unknown` toolchain + +If a specific rust is installed with `rustup`, it is important that the wasm target is +installed as well. For example if installing the rust from 20.02.2020 using `rustup +install nightly-2020-02-20`, the wasm target needs to be installed as well `rustup target add +wasm32-unknown-unknown --toolchain nightly-2020-02-20`. License: Apache-2.0 diff --git a/utils/wasm-builder/src/lib.rs b/utils/wasm-builder/src/lib.rs index 659b955256af7..8405b5a0bda9e 100644 --- a/utils/wasm-builder/src/lib.rs +++ b/utils/wasm-builder/src/lib.rs @@ -100,8 +100,12 @@ //! //! - rust nightly + `wasm32-unknown-unknown` toolchain //! -//! If a specific rust nightly is installed with `rustup`, it is important that the wasm target is -//! installed as well. For example if installing the rust nightly from 20.02.2020 using `rustup +//! or +//! +//! - rust stable and version at least 1.68.0 + `wasm32-unknown-unknown` toolchain +//! +//! If a specific rust is installed with `rustup`, it is important that the wasm target is +//! installed as well. For example if installing the rust from 20.02.2020 using `rustup //! install nightly-2020-02-20`, the wasm target needs to be installed as well `rustup target add //! wasm32-unknown-unknown --toolchain nightly-2020-02-20`. @@ -111,9 +115,11 @@ use std::{ path::{Path, PathBuf}, process::Command, }; +use version::Version; mod builder; mod prerequisites; +mod version; mod wasm_project; pub use builder::{WasmBuilder, WasmBuilderSelectProject}; @@ -172,53 +178,59 @@ fn copy_file_if_changed(src: PathBuf, dst: PathBuf) { } } -/// Get a cargo command that compiles with nightly -fn get_nightly_cargo() -> CargoCommand { +/// Get a cargo command that should be used to invoke the compilation. +fn get_cargo_command() -> CargoCommand { let env_cargo = CargoCommand::new(&env::var("CARGO").expect("`CARGO` env variable is always set by cargo")); let default_cargo = CargoCommand::new("cargo"); - let rustup_run_nightly = CargoCommand::new_with_args("rustup", &["run", "nightly", "cargo"]); let wasm_toolchain = env::var(WASM_BUILD_TOOLCHAIN).ok(); // First check if the user requested a specific toolchain - if let Some(cmd) = wasm_toolchain.and_then(|t| get_rustup_nightly(Some(t))) { + if let Some(cmd) = + wasm_toolchain.map(|t| CargoCommand::new_with_args("rustup", &["run", &t, "cargo"])) + { cmd - } else if env_cargo.is_nightly() { + } else if env_cargo.supports_substrate_wasm_env() { env_cargo - } else if default_cargo.is_nightly() { + } else if default_cargo.supports_substrate_wasm_env() { default_cargo - } else if rustup_run_nightly.is_nightly() { - rustup_run_nightly } else { - // If no command before provided us with a nightly compiler, we try to search one - // with rustup. If that fails as well, we return the default cargo and let the prequisities - // check fail. - get_rustup_nightly(None).unwrap_or(default_cargo) + // If no command before provided us with a cargo that supports our Substrate wasm env, we + // try to search one with rustup. If that fails as well, we return the default cargo and let + // the prequisities check fail. + get_rustup_command().unwrap_or(default_cargo) } } -/// Get a nightly from rustup. If `selected` is `Some(_)`, a `CargoCommand` using the given -/// nightly is returned. -fn get_rustup_nightly(selected: Option) -> Option { +/// Get the newest rustup command that supports our Substrate wasm env. +/// +/// Stable versions are always favored over nightly versions even if the nightly versions are +/// newer. +fn get_rustup_command() -> Option { let host = format!("-{}", env::var("HOST").expect("`HOST` is always set by cargo")); - let version = match selected { - Some(selected) => selected, - None => { - let output = Command::new("rustup").args(&["toolchain", "list"]).output().ok()?.stdout; - let lines = output.as_slice().lines(); + let output = Command::new("rustup").args(&["toolchain", "list"]).output().ok()?.stdout; + let lines = output.as_slice().lines(); + + let mut versions = Vec::new(); + for line in lines.filter_map(|l| l.ok()) { + let rustup_version = line.trim_end_matches(&host); + + let cmd = CargoCommand::new_with_args("rustup", &["run", &rustup_version, "cargo"]); - let mut latest_nightly = None; - for line in lines.filter_map(|l| l.ok()) { - if line.starts_with("nightly-") && line.ends_with(&host) { - // Rustup prints them sorted - latest_nightly = Some(line.clone()); - } - } + if !cmd.supports_substrate_wasm_env() { + continue + } + + let Some(cargo_version) = cmd.version() else { continue; }; - latest_nightly?.trim_end_matches(&host).into() - }, - }; + versions.push((cargo_version, rustup_version.to_string())); + } + + // Sort by the parsed version to get the latest version (greatest version) at the end of the + // vec. + versions.sort_by_key(|v| v.0); + let version = &versions.last()?.1; Some(CargoCommand::new_with_args("rustup", &["run", &version, "cargo"])) } @@ -228,17 +240,23 @@ fn get_rustup_nightly(selected: Option) -> Option { struct CargoCommand { program: String, args: Vec, + version: Option, } impl CargoCommand { fn new(program: &str) -> Self { - CargoCommand { program: program.into(), args: Vec::new() } + let version = Self::extract_version(program, &[]); + + CargoCommand { program: program.into(), args: Vec::new(), version } } fn new_with_args(program: &str, args: &[&str]) -> Self { + let version = Self::extract_version(program, args); + CargoCommand { program: program.into(), args: args.iter().map(ToString::to_string).collect(), + version, } } @@ -248,20 +266,40 @@ impl CargoCommand { cmd } - /// Check if the supplied cargo command is a nightly version - fn is_nightly(&self) -> bool { + fn extract_version(program: &str, args: &[&str]) -> Option { + let version = Command::new(program) + .args(args) + .arg("--version") + .output() + .ok() + .and_then(|o| String::from_utf8(o.stdout).ok())?; + + Version::extract(&version) + } + + /// Returns the version of this cargo command or `None` if it failed to extract the version. + fn version(&self) -> Option { + self.version + } + + /// Check if the supplied cargo command supports our Substrate wasm environment. + /// + /// This means that either the cargo version is at minimum 1.68.0 or this is a nightly cargo. + /// + /// Assumes that cargo version matches the rustc version. + fn supports_substrate_wasm_env(&self) -> bool { // `RUSTC_BOOTSTRAP` tells a stable compiler to behave like a nightly. So, when this env // variable is set, we can assume that whatever rust compiler we have, it is a nightly // compiler. For "more" information, see: // https://github.com/rust-lang/rust/blob/fa0f7d0080d8e7e9eb20aa9cbf8013f96c81287f/src/libsyntax/feature_gate/check.rs#L891 - env::var("RUSTC_BOOTSTRAP").is_ok() || - self.command() - .arg("--version") - .output() - .map_err(|_| ()) - .and_then(|o| String::from_utf8(o.stdout).map_err(|_| ())) - .unwrap_or_default() - .contains("-nightly") + if env::var("RUSTC_BOOTSTRAP").is_ok() { + return true + } + + let Some(version) = self.version() else { return false }; + + // Check if major and minor are greater or equal than 1.68 or this is a nightly. + version.major > 1 || (version.major == 1 && version.minor >= 68) || version.is_nightly } } diff --git a/utils/wasm-builder/src/prerequisites.rs b/utils/wasm-builder/src/prerequisites.rs index ca07a029281a8..f5a985ab92b5d 100644 --- a/utils/wasm-builder/src/prerequisites.rs +++ b/utils/wasm-builder/src/prerequisites.rs @@ -35,10 +35,13 @@ fn print_error_message(message: &str) -> String { /// /// Returns the versioned cargo command on success. pub(crate) fn check() -> Result { - let cargo_command = crate::get_nightly_cargo(); + let cargo_command = crate::get_cargo_command(); - if !cargo_command.is_nightly() { - return Err(print_error_message("Rust nightly not installed, please install it!")) + if !cargo_command.supports_substrate_wasm_env() { + return Err(print_error_message( + "Cannot compile the WASM runtime: no compatible Rust compiler found!\n\ + Install at least Rust 1.68.0 or a recent nightly version.", + )) } check_wasm_toolchain_installed(cargo_command) diff --git a/utils/wasm-builder/src/version.rs b/utils/wasm-builder/src/version.rs new file mode 100644 index 0000000000000..77e62b394bd55 --- /dev/null +++ b/utils/wasm-builder/src/version.rs @@ -0,0 +1,198 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT 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::cmp::Ordering; + +/// The version of rustc/cargo. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Version { + pub major: u32, + pub minor: u32, + pub patch: u32, + pub is_nightly: bool, + pub year: u32, + pub month: u32, + pub day: u32, +} + +impl Version { + /// Returns if `self` is a stable version. + pub fn is_stable(&self) -> bool { + !self.is_nightly + } + + /// Return if `self` is a nightly version. + pub fn is_nightly(&self) -> bool { + self.is_nightly + } + + /// Extract from the given `version` string. + pub fn extract(version: &str) -> Option { + let mut is_nightly = false; + let version_parts = version + .trim() + .split(" ") + .nth(1)? + .split(".") + .filter_map(|v| { + if let Some(rest) = v.strip_suffix("-nightly") { + is_nightly = true; + rest.parse().ok() + } else { + v.parse().ok() + } + }) + .collect::>(); + + if version_parts.len() != 3 { + return None + } + + let date = version.split(" ").nth(3)?; + + let date_parts = date + .split("-") + .filter_map(|v| v.trim().strip_suffix(")").unwrap_or(v).parse().ok()) + .collect::>(); + + if date_parts.len() != 3 { + return None + } + + Some(Version { + major: version_parts[0], + minor: version_parts[1], + patch: version_parts[2], + is_nightly, + year: date_parts[0], + month: date_parts[1], + day: date_parts[2], + }) + } +} + +/// Ordering is done in the following way: +/// +/// 1. `stable` > `nightly` +/// 2. Then compare major, minor and patch. +/// 3. Last compare the date. +impl Ord for Version { + fn cmp(&self, other: &Self) -> Ordering { + if self == other { + return Ordering::Equal + } + + // Ensure that `stable > nightly` + if self.is_stable() && other.is_nightly() { + return Ordering::Greater + } else if self.is_nightly() && other.is_stable() { + return Ordering::Less + } + + let to_compare = [ + (self.major, other.major), + (self.minor, other.minor), + (self.patch, other.patch), + (self.year, other.year), + (self.month, other.month), + (self.day, other.day), + ]; + + to_compare + .iter() + .find_map(|(l, r)| if l != r { l.partial_cmp(&r) } else { None }) + // We already checked this right at the beginning, so we should never return here + // `Equal`. + .unwrap_or(Ordering::Equal) + } +} + +impl PartialOrd for Version { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn version_compare_and_extract_works() { + let version_1_66_0 = Version::extract("cargo 1.66.0 (d65d197ad 2022-11-15)").unwrap(); + let version_1_66_1 = Version::extract("cargo 1.66.1 (d65d197ad 2022-11-15)").unwrap(); + let version_1_66_0_nightly = + Version::extract("cargo 1.66.0-nightly (d65d197ad 2022-10-15)").unwrap(); + let version_1_66_0_nightly_older_date = + Version::extract("cargo 1.66.0-nightly (d65d197ad 2022-10-14)").unwrap(); + let version_1_65_0 = Version::extract("cargo 1.65.0 (d65d197ad 2022-10-15)").unwrap(); + let version_1_65_0_older_date = + Version::extract("cargo 1.65.0 (d65d197ad 2022-10-14)").unwrap(); + + assert!(version_1_66_1 > version_1_66_0); + assert!(version_1_66_1 > version_1_65_0); + assert!(version_1_66_1 > version_1_66_0_nightly); + assert!(version_1_66_1 > version_1_66_0_nightly_older_date); + assert!(version_1_66_1 > version_1_65_0_older_date); + + assert!(version_1_66_0 > version_1_65_0); + assert!(version_1_66_0 > version_1_66_0_nightly); + assert!(version_1_66_0 > version_1_66_0_nightly_older_date); + assert!(version_1_66_0 > version_1_65_0_older_date); + + assert!(version_1_65_0 > version_1_66_0_nightly); + assert!(version_1_65_0 > version_1_66_0_nightly_older_date); + assert!(version_1_65_0 > version_1_65_0_older_date); + + let mut versions = vec![ + version_1_66_0, + version_1_66_0_nightly, + version_1_66_0_nightly_older_date, + version_1_65_0_older_date, + version_1_65_0, + version_1_66_1, + ]; + versions.sort_by(|a, b| b.cmp(a)); + + let expected_versions_order = vec![ + version_1_66_1, + version_1_66_0, + version_1_65_0, + version_1_65_0_older_date, + version_1_66_0_nightly, + version_1_66_0_nightly_older_date, + ]; + assert_eq!(expected_versions_order, versions); + } + + #[test] + fn parse_with_newline() { + let version_1_66_0 = Version::extract("cargo 1.66.0 (d65d197ad 2022-11-15)\n").unwrap(); + assert_eq!( + Version { + major: 1, + minor: 66, + patch: 0, + is_nightly: false, + year: 2022, + month: 11, + day: 15 + }, + version_1_66_0 + ); + } +} From 4498e271881194bd626b1ac94e7ae7aa1f2e37c4 Mon Sep 17 00:00:00 2001 From: Mira Ressel Date: Wed, 29 Mar 2023 12:27:48 +0200 Subject: [PATCH 583/715] provide a default value for RELENG_SCRIPTS_BRANCH (#13743) Currently this variable is configured exclusively via a project variable, which makes it impossible to override for specific test prs. --- .gitlab-ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 093a0bb415d09..c9b68bca1ea09 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -50,6 +50,7 @@ variables: ARCH: "x86_64" CI_IMAGE: "paritytech/ci-linux:production" BUILDAH_IMAGE: "quay.io/buildah/stable:v1.27" + RELENG_SCRIPTS_BRANCH: "master" RUSTY_CACHIER_SINGLE_BRANCH: master RUSTY_CACHIER_DONT_OPERATE_ON_MAIN_BRANCH: "true" RUSTY_CACHIER_COMPRESSION_METHOD: zstd From 56d8cbfcac926439aa78b684b7c77921dd2f4a7f Mon Sep 17 00:00:00 2001 From: Mira Ressel Date: Wed, 29 Mar 2023 15:27:40 +0200 Subject: [PATCH 584/715] roll out new debian 11 ci image (#13744) --- .gitlab-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index c9b68bca1ea09..3928c190113ea 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -48,9 +48,9 @@ variables: CARGO_INCREMENTAL: 0 DOCKER_OS: "debian:stretch" ARCH: "x86_64" - CI_IMAGE: "paritytech/ci-linux:production" + CI_IMAGE: "paritytech/ci-linux@sha256:a8b63e4f1ab37f90034b9edd3a936a1d4ae897560e25010e0f2fccd8274c6f27" # staging 2023-03-28 BUILDAH_IMAGE: "quay.io/buildah/stable:v1.27" - RELENG_SCRIPTS_BRANCH: "master" + RELENG_SCRIPTS_BRANCH: "mira/pg-13" # TODO: back to master when the ci image is moved back to prod RUSTY_CACHIER_SINGLE_BRANCH: master RUSTY_CACHIER_DONT_OPERATE_ON_MAIN_BRANCH: "true" RUSTY_CACHIER_COMPRESSION_METHOD: zstd From 49ba186c53c24a3ace99c55ecd75370d8e65da1f Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Wed, 29 Mar 2023 15:46:05 +0200 Subject: [PATCH 585/715] Swap 'base58' with 'bs58' (#13739) * Swap base58 with bs58 * Removed unused clone * std flag --- Cargo.lock | 8 +------- primitives/core/Cargo.toml | 14 ++++---------- primitives/core/src/crypto.rs | 6 ++---- 3 files changed, 7 insertions(+), 21 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cf30a6a94ae8f..a49f8fc4208a2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -490,12 +490,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" -[[package]] -name = "base58" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6107fe1be6682a68940da878d9e9f5e90ca5745b3dec9fd1bb393c8777d4f581" - [[package]] name = "base64" version = "0.13.1" @@ -10357,10 +10351,10 @@ name = "sp-core" version = "7.0.0" dependencies = [ "array-bytes", - "base58", "bitflags", "blake2", "bounded-collections", + "bs58", "criterion", "dyn-clonable", "ed25519-zebra", diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index 092baeeda95f8..9b253fd154675 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -13,10 +13,7 @@ documentation = "https://docs.rs/sp-core" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = [ - "derive", - "max-encoded-len", -] } +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive","max-encoded-len"] } 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"] } @@ -25,7 +22,7 @@ primitive-types = { version = "0.12.0", default-features = false, features = ["c impl-serde = { version = "0.4.0", optional = true } hash-db = { version = "0.16.0", default-features = false } hash256-std-hasher = { version = "0.15.2", default-features = false } -base58 = { version = "0.2.0", optional = true } +bs58 = { version = "0.4.0", default-features = false, optional = true } rand = { version = "0.8.5", features = ["small_rng"], optional = true } substrate-bip39 = { version = "0.4.4", optional = true } tiny-bip39 = { version = "1.0.0", optional = true } @@ -47,10 +44,7 @@ bitflags = "1.3" array-bytes = { version = "4.1", 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", - "u64_backend", -], default-features = false, optional = true } +schnorrkel = { version = "0.9.1", features = ["preaudit_deprecated", "u64_backend"], 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 } @@ -96,7 +90,7 @@ std = [ "blake2/std", "array-bytes", "ed25519-zebra/std", - "base58", + "bs58/std", "substrate-bip39", "tiny-bip39", "rand", diff --git a/primitives/core/src/crypto.rs b/primitives/core/src/crypto.rs index 2e60ac2370a16..0f86abf8671ad 100644 --- a/primitives/core/src/crypto.rs +++ b/primitives/core/src/crypto.rs @@ -21,8 +21,6 @@ use crate::{ed25519, sr25519}; #[cfg(feature = "std")] -use base58::{FromBase58, ToBase58}; -#[cfg(feature = "std")] use bip39::{Language, Mnemonic, MnemonicType}; use codec::{Decode, Encode, MaxEncodedLen}; #[cfg(feature = "std")] @@ -276,7 +274,7 @@ pub trait Ss58Codec: Sized + AsMut<[u8]> + AsRef<[u8]> + ByteArray { const CHECKSUM_LEN: usize = 2; let body_len = Self::LEN; - let data = s.from_base58().map_err(|_| PublicError::BadBase58)?; + let data = bs58::decode(s).into_vec().map_err(|_| PublicError::BadBase58)?; if data.len() < 2 { return Err(PublicError::BadLength) } @@ -345,7 +343,7 @@ pub trait Ss58Codec: Sized + AsMut<[u8]> + AsRef<[u8]> + ByteArray { v.extend(self.as_ref()); let r = ss58hash(&v); v.extend(&r[0..2]); - v.to_base58() + bs58::encode(v).into_string() } /// Return the ss58-check string for this key. From d7b9969c96f621b9cd93f91ebc8220aa620ac0e8 Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Wed, 29 Mar 2023 16:54:02 +0200 Subject: [PATCH 586/715] proc-macro: check for non-args runtime calls added (#13742) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * proc-macro: check for non-args runtime calls added * Update primitives/api/proc-macro/src/impl_runtime_apis.rs Co-authored-by: Bastian Köcher --------- Co-authored-by: Bastian Köcher Co-authored-by: parity-processbot <> --- primitives/api/proc-macro/src/impl_runtime_apis.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/primitives/api/proc-macro/src/impl_runtime_apis.rs b/primitives/api/proc-macro/src/impl_runtime_apis.rs index 5ac07975df0f7..d0725ffd2ba54 100644 --- a/primitives/api/proc-macro/src/impl_runtime_apis.rs +++ b/primitives/api/proc-macro/src/impl_runtime_apis.rs @@ -79,7 +79,14 @@ fn generate_impl_call( let pborrow = params.iter().map(|v| &v.2); let decode_params = if params.is_empty() { - quote!() + quote!( + if !#input.is_empty() { + panic!( + "Bad input data provided to {}: expected no parameters, but input buffer is not empty.", + #fn_name_str + ); + } + ) } else { let let_binding = if params.len() == 1 { quote! { From bf8e565791ca2760a52a1074168808d6858cd8cb Mon Sep 17 00:00:00 2001 From: Mira Ressel Date: Wed, 29 Mar 2023 20:25:41 +0200 Subject: [PATCH 587/715] Clean up after debian 11 rollout (#13762) This reverts commit 56d8cbfcac926439aa78b684b7c77921dd2f4a7f. --- .gitlab-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 3928c190113ea..c9b68bca1ea09 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -48,9 +48,9 @@ variables: CARGO_INCREMENTAL: 0 DOCKER_OS: "debian:stretch" ARCH: "x86_64" - CI_IMAGE: "paritytech/ci-linux@sha256:a8b63e4f1ab37f90034b9edd3a936a1d4ae897560e25010e0f2fccd8274c6f27" # staging 2023-03-28 + CI_IMAGE: "paritytech/ci-linux:production" BUILDAH_IMAGE: "quay.io/buildah/stable:v1.27" - RELENG_SCRIPTS_BRANCH: "mira/pg-13" # TODO: back to master when the ci image is moved back to prod + RELENG_SCRIPTS_BRANCH: "master" RUSTY_CACHIER_SINGLE_BRANCH: master RUSTY_CACHIER_DONT_OPERATE_ON_MAIN_BRANCH: "true" RUSTY_CACHIER_COMPRESSION_METHOD: zstd From e2176625e4120c01fa524fca858747c7a78c1bb7 Mon Sep 17 00:00:00 2001 From: Roman Useinov Date: Wed, 29 Mar 2023 22:30:15 +0200 Subject: [PATCH 588/715] [Fix] Bump tuple element number in frame-support. (#13760) That is to avoid hitting the pallet limit that emits a cryptic error. More detail could be found here: https://substrate.stackexchange.com/questions/7212 . Co-authored-by: parity-processbot <> --- bin/node/runtime/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index 16f1d0a4cb532..bc9f3af9d879a 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -46,7 +46,7 @@ sp-io = { version = "7.0.0", default-features = false, path = "../../../primitiv frame-executive = { version = "4.0.0-dev", default-features = false, path = "../../../frame/executive" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../../../frame/benchmarking" } frame-benchmarking-pallet-pov = { version = "4.0.0-dev", default-features = false, path = "../../../frame/benchmarking/pov" } -frame-support = { version = "4.0.0-dev", default-features = false, path = "../../../frame/support" } +frame-support = { version = "4.0.0-dev", default-features = false, path = "../../../frame/support", features = ["tuples-96"] } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../../frame/system" } frame-system-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../../../frame/system/benchmarking", optional = true } frame-election-provider-support = { version = "4.0.0-dev", default-features = false, path = "../../../frame/election-provider-support" } From 9c92e4987160a17daa72f79186d981b6fbe5879e Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Thu, 30 Mar 2023 01:22:34 +0200 Subject: [PATCH 589/715] Generic keystore internals (#13749) * Generic testing keystore internals * Generic local keystore internals * Restore deleted comment --- client/keystore/src/local.rs | 121 +++++++++------------ primitives/keystore/src/testing.rs | 164 +++++++++-------------------- 2 files changed, 95 insertions(+), 190 deletions(-) diff --git a/client/keystore/src/local.rs b/client/keystore/src/local.rs index abdf97bb22aad..2486b2fd045d5 100644 --- a/client/keystore/src/local.rs +++ b/client/keystore/src/local.rs @@ -63,21 +63,50 @@ impl LocalKeystore { ) -> Result> { self.0.read().key_pair::(public) } -} -impl Keystore for LocalKeystore { - fn sr25519_public_keys(&self, key_type: KeyTypeId) -> Vec { + fn public_keys(&self, key_type: KeyTypeId) -> Vec { self.0 .read() .raw_public_keys(key_type) .map(|v| { - v.into_iter() - .filter_map(|k| sr25519::Public::from_slice(k.as_slice()).ok()) - .collect() + v.into_iter().filter_map(|k| T::Public::from_slice(k.as_slice()).ok()).collect() }) .unwrap_or_default() } + fn generate_new( + &self, + key_type: KeyTypeId, + seed: Option<&str>, + ) -> std::result::Result { + let pair = match seed { + Some(seed) => self.0.write().insert_ephemeral_from_seed_by_type::(seed, key_type), + None => self.0.write().generate_by_type::(key_type), + } + .map_err(|e| -> TraitError { e.into() })?; + Ok(pair.public()) + } + + fn sign( + &self, + key_type: KeyTypeId, + public: &T::Public, + msg: &[u8], + ) -> std::result::Result, TraitError> { + let signature = self + .0 + .read() + .key_pair_by_type::(public, key_type)? + .map(|pair| pair.sign(msg)); + Ok(signature) + } +} + +impl Keystore for LocalKeystore { + fn sr25519_public_keys(&self, key_type: KeyTypeId) -> Vec { + self.public_keys::(key_type) + } + /// Generate a new pair compatible with the 'ed25519' signature scheme. /// /// If the `[seed]` is `Some` then the key will be ephemeral and stored in memory. @@ -86,16 +115,7 @@ impl Keystore for LocalKeystore { key_type: KeyTypeId, seed: Option<&str>, ) -> std::result::Result { - let pair = match seed { - Some(seed) => self - .0 - .write() - .insert_ephemeral_from_seed_by_type::(seed, key_type), - None => self.0.write().generate_by_type::(key_type), - } - .map_err(|e| -> TraitError { e.into() })?; - - Ok(pair.public()) + self.generate_new::(key_type, seed) } fn sr25519_sign( @@ -104,12 +124,7 @@ impl Keystore for LocalKeystore { public: &sr25519::Public, msg: &[u8], ) -> std::result::Result, TraitError> { - let res = self - .0 - .read() - .key_pair_by_type::(public, key_type)? - .map(|pair| pair.sign(msg)); - Ok(res) + self.sign::(key_type, public, msg) } fn sr25519_vrf_sign( @@ -118,24 +133,16 @@ impl Keystore for LocalKeystore { public: &sr25519::Public, transcript_data: VRFTranscriptData, ) -> std::result::Result, TraitError> { - let res = self.0.read().key_pair_by_type::(public, key_type)?.map(|pair| { + let sig = self.0.read().key_pair_by_type::(public, key_type)?.map(|pair| { let transcript = make_transcript(transcript_data); let (inout, proof, _) = pair.as_ref().vrf_sign(transcript); VRFSignature { output: inout.to_output(), proof } }); - Ok(res) + Ok(sig) } fn ed25519_public_keys(&self, key_type: KeyTypeId) -> Vec { - self.0 - .read() - .raw_public_keys(key_type) - .map(|v| { - v.into_iter() - .filter_map(|k| ed25519::Public::from_slice(k.as_slice()).ok()) - .collect() - }) - .unwrap_or_default() + self.public_keys::(key_type) } /// Generate a new pair compatible with the 'sr25519' signature scheme. @@ -146,16 +153,7 @@ impl Keystore for LocalKeystore { key_type: KeyTypeId, seed: Option<&str>, ) -> std::result::Result { - let pair = match seed { - Some(seed) => self - .0 - .write() - .insert_ephemeral_from_seed_by_type::(seed, key_type), - None => self.0.write().generate_by_type::(key_type), - } - .map_err(|e| -> TraitError { e.into() })?; - - Ok(pair.public()) + self.generate_new::(key_type, seed) } fn ed25519_sign( @@ -164,24 +162,11 @@ impl Keystore for LocalKeystore { public: &ed25519::Public, msg: &[u8], ) -> std::result::Result, TraitError> { - let res = self - .0 - .read() - .key_pair_by_type::(public, key_type)? - .map(|pair| pair.sign(msg)); - Ok(res) + self.sign::(key_type, public, msg) } fn ecdsa_public_keys(&self, key_type: KeyTypeId) -> Vec { - self.0 - .read() - .raw_public_keys(key_type) - .map(|v| { - v.into_iter() - .filter_map(|k| ecdsa::Public::from_slice(k.as_slice()).ok()) - .collect() - }) - .unwrap_or_default() + self.public_keys::(key_type) } /// Generate a new pair compatible with the 'ecdsa' signature scheme. @@ -192,14 +177,7 @@ impl Keystore for LocalKeystore { key_type: KeyTypeId, seed: Option<&str>, ) -> std::result::Result { - let pair = match seed { - Some(seed) => - self.0.write().insert_ephemeral_from_seed_by_type::(seed, key_type), - None => self.0.write().generate_by_type::(key_type), - } - .map_err(|e| -> TraitError { e.into() })?; - - Ok(pair.public()) + self.generate_new::(key_type, seed) } fn ecdsa_sign( @@ -208,12 +186,7 @@ impl Keystore for LocalKeystore { public: &ecdsa::Public, msg: &[u8], ) -> std::result::Result, TraitError> { - let res = self - .0 - .read() - .key_pair_by_type::(public, key_type)? - .map(|pair| pair.sign(msg)); - Ok(res) + self.sign::(key_type, public, msg) } fn ecdsa_sign_prehashed( @@ -222,12 +195,12 @@ impl Keystore for LocalKeystore { public: &ecdsa::Public, msg: &[u8; 32], ) -> std::result::Result, TraitError> { - let res = self + let sig = self .0 .read() .key_pair_by_type::(public, key_type)? .map(|pair| pair.sign_prehashed(msg)); - Ok(res) + Ok(sig) } fn insert( diff --git a/primitives/keystore/src/testing.rs b/primitives/keystore/src/testing.rs index de034c65889ff..e5107cba746f2 100644 --- a/primitives/keystore/src/testing.rs +++ b/primitives/keystore/src/testing.rs @@ -42,65 +42,36 @@ impl MemoryKeystore { Self::default() } - fn sr25519_key_pair( - &self, - key_type: KeyTypeId, - public: &sr25519::Public, - ) -> Option { - self.keys.read().get(&key_type).and_then(|inner| { - inner.get(public.as_slice()).map(|s| { - sr25519::Pair::from_string(s, None).expect("`sr25519` seed slice is valid") - }) - }) - } - - fn ed25519_key_pair( - &self, - key_type: KeyTypeId, - public: &ed25519::Public, - ) -> Option { - self.keys.read().get(&key_type).and_then(|inner| { - inner.get(public.as_slice()).map(|s| { - ed25519::Pair::from_string(s, None).expect("`ed25519` seed slice is valid") - }) - }) - } - - fn ecdsa_key_pair(&self, key_type: KeyTypeId, public: &ecdsa::Public) -> Option { + fn pair(&self, key_type: KeyTypeId, public: &T::Public) -> Option { self.keys.read().get(&key_type).and_then(|inner| { inner .get(public.as_slice()) - .map(|s| ecdsa::Pair::from_string(s, None).expect("`ecdsa` seed slice is valid")) + .map(|s| T::from_string(s, None).expect("seed slice is valid")) }) } -} -impl Keystore for MemoryKeystore { - fn sr25519_public_keys(&self, key_type: KeyTypeId) -> Vec { + fn public_keys(&self, key_type: KeyTypeId) -> Vec { self.keys .read() .get(&key_type) .map(|keys| { keys.values() - .map(|s| { - sr25519::Pair::from_string(s, None).expect("`sr25519` seed slice is valid") - }) + .map(|s| T::from_string(s, None).expect("seed slice is valid")) .map(|p| p.public()) .collect() }) .unwrap_or_default() } - fn sr25519_generate_new( + fn generate_new( &self, key_type: KeyTypeId, seed: Option<&str>, - ) -> Result { + ) -> Result { match seed { Some(seed) => { - let pair = sr25519::Pair::from_string(seed, None).map_err(|_| { - Error::ValidationError("Generates an `sr25519` pair.".to_owned()) - })?; + let pair = T::from_string(seed, None) + .map_err(|_| Error::ValidationError("Generates a pair.".to_owned()))?; self.keys .write() .entry(key_type) @@ -109,7 +80,7 @@ impl Keystore for MemoryKeystore { Ok(pair.public()) }, None => { - let (pair, phrase, _) = sr25519::Pair::generate_with_phrase(None); + let (pair, phrase, _) = T::generate_with_phrase(None); self.keys .write() .entry(key_type) @@ -120,13 +91,37 @@ impl Keystore for MemoryKeystore { } } + fn sign( + &self, + key_type: KeyTypeId, + public: &T::Public, + msg: &[u8], + ) -> Result, Error> { + let sig = self.pair::(key_type, public).map(|pair| pair.sign(msg)); + Ok(sig) + } +} + +impl Keystore for MemoryKeystore { + fn sr25519_public_keys(&self, key_type: KeyTypeId) -> Vec { + self.public_keys::(key_type) + } + + fn sr25519_generate_new( + &self, + key_type: KeyTypeId, + seed: Option<&str>, + ) -> Result { + self.generate_new::(key_type, seed) + } + fn sr25519_sign( &self, key_type: KeyTypeId, public: &sr25519::Public, msg: &[u8], ) -> Result, Error> { - Ok(self.sr25519_key_pair(key_type, public).map(|pair| pair.sign(msg))) + self.sign::(key_type, public, msg) } fn sr25519_vrf_sign( @@ -135,27 +130,16 @@ impl Keystore for MemoryKeystore { public: &sr25519::Public, transcript_data: VRFTranscriptData, ) -> Result, Error> { - let transcript = make_transcript(transcript_data); - let pair = - if let Some(k) = self.sr25519_key_pair(key_type, public) { k } else { return Ok(None) }; - - let (inout, proof, _) = pair.as_ref().vrf_sign(transcript); - Ok(Some(VRFSignature { output: inout.to_output(), proof })) + let sig = self.pair::(key_type, public).map(|pair| { + let transcript = make_transcript(transcript_data); + let (inout, proof, _) = pair.as_ref().vrf_sign(transcript); + VRFSignature { output: inout.to_output(), proof } + }); + Ok(sig) } fn ed25519_public_keys(&self, key_type: KeyTypeId) -> Vec { - self.keys - .read() - .get(&key_type) - .map(|keys| { - keys.values() - .map(|s| { - ed25519::Pair::from_string(s, None).expect("`ed25519` seed slice is valid") - }) - .map(|p| p.public()) - .collect() - }) - .unwrap_or_default() + self.public_keys::(key_type) } fn ed25519_generate_new( @@ -163,28 +147,7 @@ impl Keystore for MemoryKeystore { key_type: KeyTypeId, seed: Option<&str>, ) -> Result { - match seed { - Some(seed) => { - let pair = ed25519::Pair::from_string(seed, None).map_err(|_| { - Error::ValidationError("Generates an `ed25519` pair.".to_owned()) - })?; - self.keys - .write() - .entry(key_type) - .or_default() - .insert(pair.public().to_raw_vec(), seed.into()); - Ok(pair.public()) - }, - None => { - let (pair, phrase, _) = ed25519::Pair::generate_with_phrase(None); - self.keys - .write() - .entry(key_type) - .or_default() - .insert(pair.public().to_raw_vec(), phrase); - Ok(pair.public()) - }, - } + self.generate_new::(key_type, seed) } fn ed25519_sign( @@ -193,22 +156,11 @@ impl Keystore for MemoryKeystore { public: &ed25519::Public, msg: &[u8], ) -> Result, Error> { - Ok(self.ed25519_key_pair(key_type, public).map(|pair| pair.sign(msg))) + self.sign::(key_type, public, msg) } fn ecdsa_public_keys(&self, key_type: KeyTypeId) -> Vec { - self.keys - .read() - .get(&key_type) - .map(|keys| { - keys.values() - .map(|s| { - ecdsa::Pair::from_string(s, None).expect("`ecdsa` seed slice is valid") - }) - .map(|p| p.public()) - .collect() - }) - .unwrap_or_default() + self.public_keys::(key_type) } fn ecdsa_generate_new( @@ -216,27 +168,7 @@ impl Keystore for MemoryKeystore { key_type: KeyTypeId, seed: Option<&str>, ) -> Result { - match seed { - Some(seed) => { - let pair = ecdsa::Pair::from_string(seed, None) - .map_err(|_| Error::ValidationError("Generates an `ecdsa` pair.".to_owned()))?; - self.keys - .write() - .entry(key_type) - .or_default() - .insert(pair.public().to_raw_vec(), seed.into()); - Ok(pair.public()) - }, - None => { - let (pair, phrase, _) = ecdsa::Pair::generate_with_phrase(None); - self.keys - .write() - .entry(key_type) - .or_default() - .insert(pair.public().to_raw_vec(), phrase); - Ok(pair.public()) - }, - } + self.generate_new::(key_type, seed) } fn ecdsa_sign( @@ -245,7 +177,7 @@ impl Keystore for MemoryKeystore { public: &ecdsa::Public, msg: &[u8], ) -> Result, Error> { - Ok(self.ecdsa_key_pair(key_type, public).map(|pair| pair.sign(msg))) + self.sign::(key_type, public, msg) } fn ecdsa_sign_prehashed( @@ -254,8 +186,8 @@ impl Keystore for MemoryKeystore { public: &ecdsa::Public, msg: &[u8; 32], ) -> Result, Error> { - let pair = self.ecdsa_key_pair(key_type, public); - pair.map(|pair| pair.sign_prehashed(msg)).map(Ok).transpose() + let sig = self.pair::(key_type, public).map(|pair| pair.sign_prehashed(msg)); + Ok(sig) } fn insert(&self, key_type: KeyTypeId, suri: &str, public: &[u8]) -> Result<(), ()> { From 14f1a3951d5a9de4dd3ae3ff83fd5ef66c4fbbe7 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Thu, 30 Mar 2023 10:30:35 +0200 Subject: [PATCH 590/715] Application Crypto cleanup (#13746) * Adjust application crypto docs * Blanket implementation for 'RuntimeAppPublic' trait * Blanket implementation for 'BoundToRuntimeAppPublic' for 'RuntimeAppPublic' * Relax type bounds * Docs fix * restore MaybeHash * Commit suggestion Co-authored-by: Anton --------- Co-authored-by: Anton --- primitives/application-crypto/src/ecdsa.rs | 8 +- primitives/application-crypto/src/ed25519.rs | 8 +- primitives/application-crypto/src/lib.rs | 100 +++++++------------ primitives/application-crypto/src/sr25519.rs | 8 +- primitives/application-crypto/src/traits.rs | 69 +++++++++---- primitives/core/src/crypto.rs | 2 +- primitives/runtime/src/testing.rs | 7 +- 7 files changed, 91 insertions(+), 111 deletions(-) diff --git a/primitives/application-crypto/src/ecdsa.rs b/primitives/application-crypto/src/ecdsa.rs index 011456df08fae..27ffe12579f55 100644 --- a/primitives/application-crypto/src/ecdsa.rs +++ b/primitives/application-crypto/src/ecdsa.rs @@ -24,13 +24,7 @@ use sp_std::vec::Vec; pub use sp_core::ecdsa::*; mod app { - use sp_core::testing::ECDSA; - - crate::app_crypto!(super, ECDSA); - - impl crate::traits::BoundToRuntimeAppPublic for Public { - type Public = Self; - } + crate::app_crypto!(super, sp_core::testing::ECDSA); } #[cfg(feature = "full_crypto")] diff --git a/primitives/application-crypto/src/ed25519.rs b/primitives/application-crypto/src/ed25519.rs index 822dd3fa5c422..bc05018370edb 100644 --- a/primitives/application-crypto/src/ed25519.rs +++ b/primitives/application-crypto/src/ed25519.rs @@ -24,13 +24,7 @@ use sp_std::vec::Vec; pub use sp_core::ed25519::*; mod app { - use sp_core::testing::ED25519; - - crate::app_crypto!(super, ED25519); - - impl crate::traits::BoundToRuntimeAppPublic for Public { - type Public = Self; - } + crate::app_crypto!(super, sp_core::testing::ED25519); } #[cfg(feature = "full_crypto")] diff --git a/primitives/application-crypto/src/lib.rs b/primitives/application-crypto/src/lib.rs index bf738813333be..3f12e06e11ec3 100644 --- a/primitives/application-crypto/src/lib.rs +++ b/primitives/application-crypto/src/lib.rs @@ -48,14 +48,15 @@ mod traits; pub use traits::*; -/// Declares Public, Pair, Signature types which are functionally equivalent to `$pair`, but are new -/// Application-specific types whose identifier is `$key_type`. +/// Declares `Public`, `Pair` and `Signature` types which are functionally equivalent +/// to the corresponding types defined by `$module` but are new application-specific +/// types whose identifier is `$key_type`. /// /// ```rust -/// # use sp_application_crypto::{app_crypto, wrap, ed25519, KeyTypeId}; -/// // Declare a new set of crypto types using Ed25519 logic that identifies as `KeyTypeId` +/// # use sp_application_crypto::{app_crypto, ed25519, KeyTypeId}; +/// // Declare a new set of crypto types using ed25519 logic that identifies as `KeyTypeId` /// // of value `b"fuba"`. -/// app_crypto!(ed25519, KeyTypeId(*b"_uba")); +/// app_crypto!(ed25519, KeyTypeId(*b"fuba")); /// ``` #[cfg(feature = "full_crypto")] #[macro_export] @@ -78,14 +79,15 @@ macro_rules! app_crypto { }; } -/// Declares Public, Pair, Signature types which are functionally equivalent to `$pair`, but are new -/// Application-specific types whose identifier is `$key_type`. +/// Declares `Public`, `Pair` and `Signature` types which are functionally equivalent +/// to the corresponding types defined by `$module` but that are new application-specific +/// types whose identifier is `$key_type`. /// /// ```rust -/// # use sp_application_crypto::{app_crypto, wrap, ed25519, KeyTypeId}; -/// // Declare a new set of crypto types using Ed25519 logic that identifies as `KeyTypeId` +/// # use sp_application_crypto::{app_crypto, ed25519, KeyTypeId}; +/// // Declare a new set of crypto types using ed25519 logic that identifies as `KeyTypeId` /// // of value `b"fuba"`. -/// app_crypto!(ed25519, KeyTypeId(*b"_uba")); +/// app_crypto!(ed25519, KeyTypeId(*b"fuba")); /// ``` #[cfg(not(feature = "full_crypto"))] #[macro_export] @@ -107,8 +109,8 @@ macro_rules! app_crypto { }; } -/// Declares Pair type which is functionally equivalent to `$pair`, but is new -/// Application-specific type whose identifier is `$key_type`. +/// Declares `Pair` type which is functionally equivalent to `$pair`, but is +/// new application-specific type whose identifier is `$key_type`. #[macro_export] macro_rules! app_crypto_pair { ($pair:ty, $key_type:expr, $crypto_type:expr) => { @@ -208,10 +210,10 @@ macro_rules! app_crypto_pair_functions_if_std { ($pair:ty) => {}; } -/// Declares Public type which is functionally equivalent to `$public`, but is new -/// Application-specific type whose identifier is `$key_type`. -/// can only be used together with `full_crypto` feature -/// For full functionality, app_crypto_public_common! must be called too. +/// Declares `Public` type which is functionally equivalent to `$public` but is +/// new application-specific type whose identifier is `$key_type`. +/// For full functionality, `app_crypto_public_common!` must be called too. +/// Can only be used with `full_crypto` feature. #[doc(hidden)] #[macro_export] macro_rules! app_crypto_public_full_crypto { @@ -244,10 +246,10 @@ macro_rules! app_crypto_public_full_crypto { }; } -/// Declares Public type which is functionally equivalent to `$public`, but is new -/// Application-specific type whose identifier is `$key_type`. -/// can only be used without `full_crypto` feature -/// For full functionality, app_crypto_public_common! must be called too. +/// Declares `Public` type which is functionally equivalent to `$public` but is +/// new application-specific type whose identifier is `$key_type`. +/// For full functionality, `app_crypto_public_common!` must be called too. +/// Can only be used without `full_crypto` feature. #[doc(hidden)] #[macro_export] macro_rules! app_crypto_public_not_full_crypto { @@ -276,9 +278,9 @@ macro_rules! app_crypto_public_not_full_crypto { }; } -/// Declares Public type which is functionally equivalent to `$public`, but is new -/// Application-specific type whose identifier is `$key_type`. -/// For full functionality, app_crypto_public_(not)_full_crypto! must be called too. +/// Declares `Public` type which is functionally equivalent to `$public` but is +/// new application-specific type whose identifier is `$key_type`. +/// For full functionality, `app_crypto_public_(not)_full_crypto!` must be called too. #[doc(hidden)] #[macro_export] macro_rules! app_crypto_public_common { @@ -307,40 +309,6 @@ macro_rules! app_crypto_public_common { type Generic = $public; } - impl $crate::RuntimeAppPublic for Public - where - $public: $crate::RuntimePublic, - { - const ID: $crate::KeyTypeId = $key_type; - const CRYPTO_ID: $crate::CryptoTypeId = $crypto_type; - - type Signature = Signature; - - fn all() -> $crate::Vec { - <$public as $crate::RuntimePublic>::all($key_type) - .into_iter() - .map(Self) - .collect() - } - - fn generate_pair(seed: Option<$crate::Vec>) -> Self { - Self(<$public as $crate::RuntimePublic>::generate_pair($key_type, seed)) - } - - fn sign>(&self, msg: &M) -> Option { - <$public as $crate::RuntimePublic>::sign(self.as_ref(), $key_type, msg) - .map(Signature) - } - - fn verify>(&self, msg: &M, signature: &Self::Signature) -> bool { - <$public as $crate::RuntimePublic>::verify(self.as_ref(), msg, &signature.as_ref()) - } - - fn to_raw_vec(&self) -> $crate::Vec { - <$public as $crate::RuntimePublic>::to_raw_vec(&self.0) - } - } - impl<'a> TryFrom<&'a [u8]> for Public { type Error = (); @@ -407,8 +375,8 @@ macro_rules! app_crypto_public_common_if_std { /// Declares Signature type which is functionally equivalent to `$sig`, but is new /// Application-specific type whose identifier is `$key_type`. -/// can only be used together with `full_crypto` feature /// For full functionality, app_crypto_public_common! must be called too. +/// Can only be used with `full_crypto` feature #[doc(hidden)] #[macro_export] macro_rules! app_crypto_signature_full_crypto { @@ -439,10 +407,10 @@ macro_rules! app_crypto_signature_full_crypto { }; } -/// Declares Signature type which is functionally equivalent to `$sig`, but is new -/// Application-specific type whose identifier is `$key_type`. -/// can only be used without `full_crypto` feature -/// For full functionality, app_crypto_public_common! must be called too. +/// Declares `Signature` type which is functionally equivalent to `$sig`, but is new +/// application-specific type whose identifier is `$key_type`. +/// For full functionality, `app_crypto_signature_common` must be called too. +/// Can only be used without `full_crypto` feature. #[doc(hidden)] #[macro_export] macro_rules! app_crypto_signature_not_full_crypto { @@ -452,8 +420,8 @@ macro_rules! app_crypto_signature_not_full_crypto { #[derive(Clone, Eq, PartialEq, $crate::codec::Encode, $crate::codec::Decode, - $crate::scale_info::TypeInfo, $crate::RuntimeDebug, + $crate::scale_info::TypeInfo, )] pub struct Signature($sig); } @@ -469,9 +437,9 @@ macro_rules! app_crypto_signature_not_full_crypto { }; } -/// Declares Signature type which is functionally equivalent to `$sig`, but is new -/// Application-specific type whose identifier is `$key_type`. -/// For full functionality, app_crypto_public_(not)_full_crypto! must be called too. +/// Declares `Signature` type which is functionally equivalent to `$sig`, but is new +/// application-specific type whose identifier is `$key_type`. +/// For full functionality, app_crypto_signature_(not)_full_crypto! must be called too. #[doc(hidden)] #[macro_export] macro_rules! app_crypto_signature_common { diff --git a/primitives/application-crypto/src/sr25519.rs b/primitives/application-crypto/src/sr25519.rs index a961f5cf3edf0..7c91bfa7bb5ff 100644 --- a/primitives/application-crypto/src/sr25519.rs +++ b/primitives/application-crypto/src/sr25519.rs @@ -24,13 +24,7 @@ use sp_std::vec::Vec; pub use sp_core::sr25519::*; mod app { - use sp_core::testing::SR25519; - - crate::app_crypto!(super, SR25519); - - impl crate::traits::BoundToRuntimeAppPublic for Public { - type Public = Self; - } + crate::app_crypto!(super, sp_core::testing::SR25519); } #[cfg(feature = "full_crypto")] diff --git a/primitives/application-crypto/src/traits.rs b/primitives/application-crypto/src/traits.rs index b3bcd0ce2b701..88d4bf36915d0 100644 --- a/primitives/application-crypto/src/traits.rs +++ b/primitives/application-crypto/src/traits.rs @@ -15,10 +15,11 @@ // See the License for the specific language governing permissions and // limitations under the License. +use codec::Codec; +use scale_info::TypeInfo; + #[cfg(feature = "full_crypto")] use sp_core::crypto::Pair; - -use codec::Codec; use sp_core::crypto::{CryptoType, CryptoTypeId, IsWrappedBy, KeyTypeId, Public}; use sp_std::{fmt::Debug, vec::Vec}; @@ -60,15 +61,9 @@ pub trait MaybeHash {} #[cfg(all(not(feature = "std"), not(feature = "full_crypto")))] impl MaybeHash for T {} -/// Type which implements Debug and Hash in std, not when no-std (no-std variant with crypto). -#[cfg(all(not(feature = "std"), feature = "full_crypto"))] -pub trait MaybeDebugHash: sp_std::hash::Hash {} -#[cfg(all(not(feature = "std"), feature = "full_crypto"))] -impl MaybeDebugHash for T {} - /// A application's public key. pub trait AppPublic: - AppCrypto + Public + Ord + PartialOrd + Eq + PartialEq + Debug + MaybeHash + codec::Codec + AppCrypto + Public + Ord + PartialOrd + Eq + PartialEq + Debug + MaybeHash + Codec { /// The wrapped type which is just a plain instance of `Public`. type Generic: IsWrappedBy @@ -79,7 +74,7 @@ pub trait AppPublic: + PartialEq + Debug + MaybeHash - + codec::Codec; + + Codec; } /// A application's key pair. @@ -92,15 +87,15 @@ pub trait AppPair: AppCrypto + Pair::Public> { } /// A application's signature. -pub trait AppSignature: AppCrypto + Eq + PartialEq + Debug + MaybeHash { +pub trait AppSignature: AppCrypto + Eq + PartialEq + Debug { /// The wrapped type which is just a plain instance of `Signature`. - type Generic: IsWrappedBy + Eq + PartialEq + Debug + MaybeHash; + type Generic: IsWrappedBy + Eq + PartialEq + Debug; } /// A runtime interface for a public key. pub trait RuntimePublic: Sized { /// The signature that will be generated when signing with the corresponding private key. - type Signature: Codec + Debug + MaybeHash + Eq + PartialEq + Clone; + type Signature: Debug + Eq + PartialEq + Clone; /// Returns all public keys for the given key type in the keystore. fn all(key_type: KeyTypeId) -> crate::Vec; @@ -132,11 +127,9 @@ pub trait RuntimePublic: Sized { pub trait RuntimeAppPublic: Sized { /// An identifier for this application-specific key type. const ID: KeyTypeId; - /// The identifier of the crypto type of this application-specific key type. - const CRYPTO_ID: CryptoTypeId; /// The signature that will be generated when signing with the corresponding private key. - type Signature: Codec + Debug + MaybeHash + Eq + PartialEq + Clone + scale_info::TypeInfo; + type Signature: Debug + Eq + PartialEq + Clone + TypeInfo + Codec; /// Returns all public keys for this application in the keystore. fn all() -> crate::Vec; @@ -163,8 +156,50 @@ pub trait RuntimeAppPublic: Sized { fn to_raw_vec(&self) -> Vec; } -/// Something that bound to a fixed [`RuntimeAppPublic`]. +impl RuntimeAppPublic for T +where + T: AppPublic + AsRef<::Generic>, + ::Generic: RuntimePublic, + ::Signature: TypeInfo + + Codec + + From<<::Generic as RuntimePublic>::Signature> + + AsRef<<::Generic as RuntimePublic>::Signature>, +{ + const ID: KeyTypeId = ::ID; + + type Signature = ::Signature; + + fn all() -> crate::Vec { + <::Generic as RuntimePublic>::all(Self::ID) + .into_iter() + .map(|p| p.into()) + .collect() + } + + fn generate_pair(seed: Option>) -> Self { + <::Generic as RuntimePublic>::generate_pair(Self::ID, seed).into() + } + + fn sign>(&self, msg: &M) -> Option { + <::Generic as RuntimePublic>::sign(self.as_ref(), Self::ID, msg) + .map(|s| s.into()) + } + + fn verify>(&self, msg: &M, signature: &Self::Signature) -> bool { + <::Generic as RuntimePublic>::verify(self.as_ref(), msg, signature.as_ref()) + } + + fn to_raw_vec(&self) -> Vec { + <::Generic as RuntimePublic>::to_raw_vec(self.as_ref()) + } +} + +/// Something that is bound to a fixed [`RuntimeAppPublic`]. pub trait BoundToRuntimeAppPublic { /// The [`RuntimeAppPublic`] this type is bound to. type Public: RuntimeAppPublic; } + +impl BoundToRuntimeAppPublic for T { + type Public = Self; +} diff --git a/primitives/core/src/crypto.rs b/primitives/core/src/crypto.rs index 0f86abf8671ad..f77e952d84546 100644 --- a/primitives/core/src/crypto.rs +++ b/primitives/core/src/crypto.rs @@ -482,7 +482,7 @@ pub trait ByteArray: AsRef<[u8]> + AsMut<[u8]> + for<'a> TryFrom<&'a [u8], Error } } -/// Trait suitable for typical cryptographic PKI key public type. +/// Trait suitable for typical cryptographic key public type. pub trait Public: ByteArray + Derive + CryptoType + PartialEq + Eq + Clone + Send + Sync {} /// An opaque 32-byte cryptographic identifier. diff --git a/primitives/runtime/src/testing.rs b/primitives/runtime/src/testing.rs index 7e2ee5403f3ea..6d02e23094f90 100644 --- a/primitives/runtime/src/testing.rs +++ b/primitives/runtime/src/testing.rs @@ -26,7 +26,7 @@ use crate::{ PostDispatchInfoOf, SignedExtension, ValidateUnsigned, }, transaction_validity::{TransactionSource, TransactionValidity, TransactionValidityError}, - ApplyExtrinsicResultWithInfo, CryptoTypeId, KeyTypeId, + ApplyExtrinsicResultWithInfo, KeyTypeId, }; use serde::{de::Error as DeError, Deserialize, Deserializer, Serialize, Serializer}; use sp_core::{ @@ -115,7 +115,6 @@ impl UintAuthorityId { impl sp_application_crypto::RuntimeAppPublic for UintAuthorityId { const ID: KeyTypeId = key_types::DUMMY; - const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"dumm"); type Signature = TestSignature; @@ -157,10 +156,6 @@ impl OpaqueKeys for UintAuthorityId { } } -impl crate::BoundToRuntimeAppPublic for UintAuthorityId { - type Public = Self; -} - impl traits::IdentifyAccount for UintAuthorityId { type AccountId = u64; From 44998291834b3a36a11c8dede63ce60362f1a3a5 Mon Sep 17 00:00:00 2001 From: Aaro Altonen <48052676+altonen@users.noreply.github.com> Date: Thu, 30 Mar 2023 14:59:58 +0300 Subject: [PATCH 591/715] Attempt to relieve pressure on `mpsc_network_worker` (#13725) * Attempt to relieve pressure on `mpsc_network_worker` `SyncingEngine` interacting with `NetworkWorker` can put a lot of strain on the channel if the number of inbound connections is high. This is because `SyncingEngine` is notified of each inbound substream which it then can either accept or reject and this causes a lot of message exchange on the already busy channel. Use a direct channel pair between `Protocol` and `SyncingEngine` to exchange notification events. It is a temporary change to alleviate the problems caused by syncing being an independent protocol and the fix will be removed once `NotificationService` is implemented. * Apply review comments * fixes * trigger ci * Fix tests Verify that both peers have a connection now that the validation goes through `SyncingEngine`. Depending on how the tasks are scheduled, one of them might not have the peer registered in `SyncingEngine` at which point the test won't make any progress because block announcement received from an unknown peer is discarded. Move polling of `ChainSync` at the end of the function so that if a block announcement causes a block request to be sent, that can be sent in the same call to `SyncingEngine::poll()`. --------- Co-authored-by: parity-processbot <> --- Cargo.lock | 1 + client/network/src/config.rs | 11 +- client/network/src/event.rs | 47 ++++++- client/network/src/lib.rs | 6 +- client/network/src/protocol.rs | 108 +++++++++++++--- client/network/src/service.rs | 6 +- client/network/sync/src/engine.rs | 199 +++++++++++++---------------- client/network/test/Cargo.toml | 1 + client/network/test/src/lib.rs | 12 +- client/network/test/src/service.rs | 6 +- client/network/test/src/sync.rs | 2 +- client/service/src/builder.rs | 13 +- 12 files changed, 259 insertions(+), 153 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a49f8fc4208a2..7fd0122f3cc0f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9128,6 +9128,7 @@ dependencies = [ "sc-network-light", "sc-network-sync", "sc-service", + "sc-utils", "sp-blockchain", "sp-consensus", "sp-consensus-babe", diff --git a/client/network/src/config.rs b/client/network/src/config.rs index 3c6801f22a35c..781ae9c786694 100644 --- a/client/network/src/config.rs +++ b/client/network/src/config.rs @@ -22,6 +22,7 @@ //! See the documentation of [`Params`]. pub use crate::{ + protocol::NotificationsSink, request_responses::{ IncomingRequest, OutgoingResponse, ProtocolConfig as RequestResponseConfig, }, @@ -31,7 +32,12 @@ pub use crate::{ use codec::Encode; use libp2p::{identity::Keypair, multiaddr, Multiaddr, PeerId}; use prometheus_endpoint::Registry; -pub use sc_network_common::{role::Role, sync::warp::WarpSyncProvider, ExHashT}; +pub use sc_network_common::{ + role::{Role, Roles}, + sync::warp::WarpSyncProvider, + ExHashT, +}; +use sc_utils::mpsc::TracingUnboundedSender; use zeroize::Zeroize; use sp_runtime::traits::Block as BlockT; @@ -714,6 +720,9 @@ pub struct Params { /// Block announce protocol configuration pub block_announce_config: NonDefaultSetConfig, + /// TX channel for direct communication with `SyncingEngine` and `Protocol`. + pub tx: TracingUnboundedSender>, + /// Request response protocol configurations pub request_response_protocol_configs: Vec, } diff --git a/client/network/src/event.rs b/client/network/src/event.rs index 3ecd8f9311429..975fde0e40a28 100644 --- a/client/network/src/event.rs +++ b/client/network/src/event.rs @@ -19,12 +19,14 @@ //! Network event types. These are are not the part of the protocol, but rather //! events that happen on the network like DHT get/put results received. -use crate::types::ProtocolName; +use crate::{types::ProtocolName, NotificationsSink}; use bytes::Bytes; +use futures::channel::oneshot; use libp2p::{core::PeerId, kad::record::Key}; -use sc_network_common::role::ObservedRole; +use sc_network_common::{role::ObservedRole, sync::message::BlockAnnouncesHandshake}; +use sp_runtime::traits::Block as BlockT; /// Events generated by DHT as a response to get_value and put_value requests. #[derive(Debug, Clone)] @@ -90,3 +92,44 @@ pub enum Event { messages: Vec<(ProtocolName, Bytes)>, }, } + +/// Event sent to `SyncingEngine` +// TODO: remove once `NotificationService` is implemented. +pub enum SyncEvent { + /// Opened a substream with the given node with the given notifications protocol. + /// + /// The protocol is always one of the notification protocols that have been registered. + NotificationStreamOpened { + /// Node we opened the substream with. + remote: PeerId, + /// Received handshake. + received_handshake: BlockAnnouncesHandshake, + /// Notification sink. + sink: NotificationsSink, + /// Channel for reporting accept/reject of the substream. + tx: oneshot::Sender, + }, + + /// Closed a substream with the given node. Always matches a corresponding previous + /// `NotificationStreamOpened` message. + NotificationStreamClosed { + /// Node we closed the substream with. + remote: PeerId, + }, + + /// Notification sink was replaced. + NotificationSinkReplaced { + /// Node we closed the substream with. + remote: PeerId, + /// Notification sink. + sink: NotificationsSink, + }, + + /// Received one or more messages from the given node using the given protocol. + NotificationsReceived { + /// Node we received the message from. + remote: PeerId, + /// Concerned protocol and associated message. + messages: Vec, + }, +} diff --git a/client/network/src/lib.rs b/client/network/src/lib.rs index c290f4b94db53..5374ac13435be 100644 --- a/client/network/src/lib.rs +++ b/client/network/src/lib.rs @@ -259,7 +259,7 @@ pub mod request_responses; pub mod types; pub mod utils; -pub use event::{DhtEvent, Event}; +pub use event::{DhtEvent, Event, SyncEvent}; #[doc(inline)] pub use libp2p::{multiaddr, Multiaddr, PeerId}; pub use request_responses::{IfDisconnected, RequestFailure, RequestResponseConfig}; @@ -278,8 +278,8 @@ pub use service::{ NetworkStatusProvider, NetworkSyncForkRequest, NotificationSender as NotificationSenderT, NotificationSenderError, NotificationSenderReady, }, - DecodingError, Keypair, NetworkService, NetworkWorker, NotificationSender, OutboundFailure, - PublicKey, + DecodingError, Keypair, NetworkService, NetworkWorker, NotificationSender, NotificationsSink, + OutboundFailure, PublicKey, }; pub use types::ProtocolName; diff --git a/client/network/src/protocol.rs b/client/network/src/protocol.rs index 06ca02c0ca8d5..a7e6f36ef6215 100644 --- a/client/network/src/protocol.rs +++ b/client/network/src/protocol.rs @@ -24,6 +24,7 @@ use crate::{ use bytes::Bytes; use codec::{DecodeAll, Encode}; +use futures::{channel::oneshot, stream::FuturesUnordered, StreamExt}; use libp2p::{ core::connection::ConnectionId, swarm::{ @@ -35,11 +36,14 @@ use libp2p::{ use log::{debug, error, warn}; use sc_network_common::{role::Roles, sync::message::BlockAnnouncesHandshake}; +use sc_utils::mpsc::TracingUnboundedSender; use sp_runtime::traits::Block as BlockT; use std::{ collections::{HashMap, HashSet, VecDeque}, + future::Future, iter, + pin::Pin, task::Poll, }; @@ -68,6 +72,9 @@ mod rep { pub const BAD_MESSAGE: Rep = Rep::new(-(1 << 12), "Bad message"); } +type PendingSyncSubstreamValidation = + Pin> + Send>>; + // Lock must always be taken in order declared here. pub struct Protocol { /// Pending list of messages to return from `poll` as a priority. @@ -87,6 +94,8 @@ pub struct Protocol { bad_handshake_substreams: HashSet<(PeerId, sc_peerset::SetId)>, /// Connected peers. peers: HashMap, + sync_substream_validations: FuturesUnordered, + tx: TracingUnboundedSender>, _marker: std::marker::PhantomData, } @@ -96,6 +105,7 @@ impl Protocol { roles: Roles, network_config: &config::NetworkConfiguration, block_announces_protocol: config::NonDefaultSetConfig, + tx: TracingUnboundedSender>, ) -> error::Result<(Self, sc_peerset::PeersetHandle, Vec<(PeerId, Multiaddr)>)> { let mut known_addresses = Vec::new(); @@ -179,6 +189,8 @@ impl Protocol { .collect(), bad_handshake_substreams: Default::default(), peers: HashMap::new(), + sync_substream_validations: FuturesUnordered::new(), + tx, // TODO: remove when `BlockAnnouncesHandshake` is moved away from `Protocol` _marker: Default::default(), }; @@ -418,6 +430,23 @@ impl NetworkBehaviour for Protocol { return Poll::Ready(NetworkBehaviourAction::CloseConnection { peer_id, connection }), }; + while let Poll::Ready(Some(validation_result)) = + self.sync_substream_validations.poll_next_unpin(cx) + { + match validation_result { + Ok((peer, roles)) => { + self.peers.insert(peer, roles); + }, + Err(peer) => { + log::debug!( + target: "sub-libp2p", + "`SyncingEngine` rejected stream" + ); + self.behaviour.disconnect_peer(&peer, HARDCODED_PEERSETS_SYNC); + }, + } + } + let outcome = match event { NotificationsOut::CustomProtocolOpen { peer_id, @@ -440,16 +469,29 @@ impl NetworkBehaviour for Protocol { best_hash: handshake.best_hash, genesis_hash: handshake.genesis_hash, }; - self.peers.insert(peer_id, roles); - CustomMessageOutcome::NotificationStreamOpened { - remote: peer_id, - protocol: self.notification_protocols[usize::from(set_id)].clone(), - negotiated_fallback, - received_handshake: handshake.encode(), - roles, - notifications_sink, - } + let (tx, rx) = oneshot::channel(); + let _ = self.tx.unbounded_send( + crate::SyncEvent::NotificationStreamOpened { + remote: peer_id, + received_handshake: handshake, + sink: notifications_sink, + tx, + }, + ); + self.sync_substream_validations.push(Box::pin(async move { + match rx.await { + Ok(accepted) => + if accepted { + Ok((peer_id, roles)) + } else { + Err(peer_id) + }, + Err(_) => Err(peer_id), + } + })); + + CustomMessageOutcome::None }, Ok(msg) => { debug!( @@ -469,15 +511,27 @@ impl NetworkBehaviour for Protocol { let roles = handshake.roles; self.peers.insert(peer_id, roles); - CustomMessageOutcome::NotificationStreamOpened { - remote: peer_id, - protocol: self.notification_protocols[usize::from(set_id)] - .clone(), - negotiated_fallback, - received_handshake, - roles, - notifications_sink, - } + let (tx, rx) = oneshot::channel(); + let _ = self.tx.unbounded_send( + crate::SyncEvent::NotificationStreamOpened { + remote: peer_id, + received_handshake: handshake, + sink: notifications_sink, + tx, + }, + ); + self.sync_substream_validations.push(Box::pin(async move { + match rx.await { + Ok(accepted) => + if accepted { + Ok((peer_id, roles)) + } else { + Err(peer_id) + }, + Err(_) => Err(peer_id), + } + })); + CustomMessageOutcome::None }, Err(err2) => { log::debug!( @@ -535,6 +589,12 @@ impl NetworkBehaviour for Protocol { NotificationsOut::CustomProtocolReplaced { peer_id, notifications_sink, set_id } => if self.bad_handshake_substreams.contains(&(peer_id, set_id)) { CustomMessageOutcome::None + } else if set_id == HARDCODED_PEERSETS_SYNC { + let _ = self.tx.unbounded_send(crate::SyncEvent::NotificationSinkReplaced { + remote: peer_id, + sink: notifications_sink, + }); + CustomMessageOutcome::None } else { CustomMessageOutcome::NotificationStreamReplaced { remote: peer_id, @@ -548,6 +608,12 @@ impl NetworkBehaviour for Protocol { // handshake. The outer layers have never received an opening event about this // substream, and consequently shouldn't receive a closing event either. CustomMessageOutcome::None + } else if set_id == HARDCODED_PEERSETS_SYNC { + let _ = self.tx.unbounded_send(crate::SyncEvent::NotificationStreamClosed { + remote: peer_id, + }); + self.peers.remove(&peer_id); + CustomMessageOutcome::None } else { CustomMessageOutcome::NotificationStreamClosed { remote: peer_id, @@ -558,6 +624,12 @@ impl NetworkBehaviour for Protocol { NotificationsOut::Notification { peer_id, set_id, message } => { if self.bad_handshake_substreams.contains(&(peer_id, set_id)) { CustomMessageOutcome::None + } else if set_id == HARDCODED_PEERSETS_SYNC { + let _ = self.tx.unbounded_send(crate::SyncEvent::NotificationsReceived { + remote: peer_id, + messages: vec![message.freeze()], + }); + CustomMessageOutcome::None } else { let protocol_name = self.notification_protocols[usize::from(set_id)].clone(); CustomMessageOutcome::NotificationsReceived { diff --git a/client/network/src/service.rs b/client/network/src/service.rs index 5f60f51321b42..9708b24d29b52 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -36,7 +36,7 @@ use crate::{ network_state::{ NetworkState, NotConnectedPeer as NetworkStateNotConnectedPeer, Peer as NetworkStatePeer, }, - protocol::{self, NotificationsSink, NotifsHandlerError, Protocol, Ready}, + protocol::{self, NotifsHandlerError, Protocol, Ready}, request_responses::{IfDisconnected, RequestFailure}, service::{ signature::{Signature, SigningError}, @@ -91,6 +91,7 @@ use std::{ pub use behaviour::{InboundFailure, OutboundFailure, ResponseFailure}; pub use libp2p::identity::{error::DecodingError, Keypair, PublicKey}; +pub use protocol::NotificationsSink; mod metrics; mod out_events; @@ -146,7 +147,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(); @@ -227,6 +228,7 @@ where From::from(¶ms.role), ¶ms.network_config, params.block_announce_config, + params.tx, )?; // List of multiaddresses that we know in the network. diff --git a/client/network/sync/src/engine.rs b/client/network/sync/src/engine.rs index b4c1a2ed05bb0..e3d45a980a0b4 100644 --- a/client/network/sync/src/engine.rs +++ b/client/network/sync/src/engine.rs @@ -24,8 +24,8 @@ use crate::{ ChainSync, ClientError, SyncingService, }; -use codec::{Decode, DecodeAll, Encode}; -use futures::{FutureExt, Stream, StreamExt}; +use codec::{Decode, Encode}; +use futures::{FutureExt, StreamExt}; use futures_timer::Delay; use libp2p::PeerId; use lru::LruCache; @@ -39,9 +39,8 @@ use sc_network::{ config::{ NetworkConfiguration, NonDefaultSetConfig, ProtocolId, SyncMode as SyncOperationMode, }, - event::Event, utils::LruHashSet, - ProtocolName, + NotificationsSink, ProtocolName, }; use sc_network_common::{ role::Roles, @@ -63,7 +62,6 @@ use sp_runtime::traits::{Block as BlockT, Header, NumberFor, Zero}; use std::{ collections::{HashMap, HashSet}, num::NonZeroUsize, - pin::Pin, sync::{ atomic::{AtomicBool, AtomicUsize, Ordering}, Arc, @@ -79,8 +77,6 @@ const MAX_KNOWN_BLOCKS: usize = 1024; // ~32kb per peer + LruHashSet overhead mod rep { use sc_peerset::ReputationChange as Rep; - /// 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 send us a block announcement that failed at validation. @@ -162,6 +158,8 @@ pub struct Peer { pub info: ExtendedPeerInfo, /// Holds a set of blocks known to this peer. pub known_blocks: LruHashSet, + /// Notification sink. + sink: NotificationsSink, } pub struct SyncingEngine { @@ -184,6 +182,9 @@ pub struct SyncingEngine { /// Channel for receiving service commands service_rx: TracingUnboundedReceiver>, + /// Channel for receiving inbound connections from `Protocol`. + rx: sc_utils::mpsc::TracingUnboundedReceiver>, + /// Assigned roles. roles: Roles, @@ -254,6 +255,7 @@ where block_request_protocol_name: ProtocolName, state_request_protocol_name: ProtocolName, warp_sync_protocol_name: Option, + rx: sc_utils::mpsc::TracingUnboundedReceiver>, ) -> Result<(Self, SyncingService, NonDefaultSetConfig), ClientError> { let mode = match network_config.sync_mode { SyncOperationMode::Full => SyncMode::Full, @@ -347,6 +349,7 @@ where num_connected: num_connected.clone(), is_major_syncing: is_major_syncing.clone(), service_rx, + rx, genesis_hash, important_peers, default_peers_set_no_slot_connected_peers: HashSet::new(), @@ -554,11 +557,7 @@ where data: Some(data.clone()), }; - self.network_service.write_notification( - *who, - self.block_announce_protocol_name.clone(), - message.encode(), - ); + peer.sink.send_sync_notification(message.encode()); } } } @@ -575,17 +574,13 @@ where ) } - pub async fn run(mut self, mut stream: Pin + Send>>) { + pub async fn run(mut self) { loop { - futures::future::poll_fn(|cx| self.poll(cx, &mut stream)).await; + futures::future::poll_fn(|cx| self.poll(cx)).await; } } - pub fn poll( - &mut self, - cx: &mut std::task::Context, - event_stream: &mut Pin + Send>>, - ) -> Poll<()> { + pub fn poll(&mut self, cx: &mut std::task::Context) -> Poll<()> { self.num_connected.store(self.peers.len(), Ordering::Relaxed); self.is_major_syncing .store(self.chain_sync.status().state.is_major_syncing(), Ordering::Relaxed); @@ -595,84 +590,6 @@ where self.tick_timeout.reset(TICK_TIMEOUT); } - while let Poll::Ready(Some(event)) = event_stream.poll_next_unpin(cx) { - match event { - Event::NotificationStreamOpened { - remote, protocol, received_handshake, .. - } => { - if protocol != self.block_announce_protocol_name { - continue - } - - match as DecodeAll>::decode_all( - &mut &received_handshake[..], - ) { - Ok(handshake) => { - if self.on_sync_peer_connected(remote, handshake).is_err() { - log::debug!( - target: "sync", - "Failed to register peer {remote:?}: {received_handshake:?}", - ); - } - }, - Err(err) => { - log::debug!( - target: "sync", - "Couldn't decode handshake sent by {}: {:?}: {}", - remote, - received_handshake, - err, - ); - self.network_service.report_peer(remote, rep::BAD_MESSAGE); - }, - } - }, - Event::NotificationStreamClosed { remote, protocol } => { - if protocol != self.block_announce_protocol_name { - continue - } - - if self.on_sync_peer_disconnected(remote).is_err() { - log::trace!( - target: "sync", - "Disconnected peer which had earlier been refused by on_sync_peer_connected {}", - remote - ); - } - }, - Event::NotificationsReceived { remote, messages } => { - for (protocol, message) in messages { - if protocol != self.block_announce_protocol_name { - continue - } - - if self.peers.contains_key(&remote) { - if let Ok(announce) = BlockAnnounce::decode(&mut message.as_ref()) { - self.push_block_announce_validation(remote, announce); - - // Make sure that the newly added block announce validation future - // was polled once to be registered in the task. - if let Poll::Ready(res) = - self.chain_sync.poll_block_announce_validation(cx) - { - self.process_block_announce_validation_result(res) - } - } else { - log::warn!(target: "sub-libp2p", "Failed to decode block announce"); - } - } else { - log::trace!( - target: "sync", - "Received sync for peer earlier refused by sync layer: {}", - remote - ); - } - } - }, - _ => {}, - } - } - while let Poll::Ready(Some(event)) = self.service_rx.poll_next_unpin(cx) { match event { ToServiceCommand::SetSyncForkRequest(peers, hash, number) => { @@ -746,6 +663,70 @@ where } } + while let Poll::Ready(Some(event)) = self.rx.poll_next_unpin(cx) { + match event { + sc_network::SyncEvent::NotificationStreamOpened { + remote, + received_handshake, + sink, + tx, + } => match self.on_sync_peer_connected(remote, &received_handshake, sink) { + Ok(()) => { + let _ = tx.send(true); + }, + Err(()) => { + log::debug!( + target: "sync", + "Failed to register peer {remote:?}: {received_handshake:?}", + ); + let _ = tx.send(false); + }, + }, + sc_network::SyncEvent::NotificationStreamClosed { remote } => { + if self.on_sync_peer_disconnected(remote).is_err() { + log::trace!( + target: "sync", + "Disconnected peer which had earlier been refused by on_sync_peer_connected {}", + remote + ); + } + }, + sc_network::SyncEvent::NotificationsReceived { remote, messages } => { + for message in messages { + if self.peers.contains_key(&remote) { + if let Ok(announce) = BlockAnnounce::decode(&mut message.as_ref()) { + self.push_block_announce_validation(remote, announce); + + // Make sure that the newly added block announce validation future + // was polled once to be registered in the task. + if let Poll::Ready(res) = + self.chain_sync.poll_block_announce_validation(cx) + { + self.process_block_announce_validation_result(res) + } + } else { + log::warn!(target: "sub-libp2p", "Failed to decode block announce"); + } + } else { + log::trace!( + target: "sync", + "Received sync for peer earlier refused by sync layer: {}", + remote + ); + } + } + }, + sc_network::SyncEvent::NotificationSinkReplaced { remote, sink } => { + if let Some(peer) = self.peers.get_mut(&remote) { + peer.sink = sink; + } + }, + } + } + + // poll `ChainSync` last because of a block announcement was received through the + // event stream between `SyncingEngine` and `Protocol` and the validation finished + // right after it as queued, the resulting block request (if any) can be sent right away. while let Poll::Ready(result) = self.chain_sync.poll(cx) { self.process_block_announce_validation_result(result); } @@ -757,13 +738,13 @@ where /// /// Returns a result if the handshake of this peer was indeed accepted. pub fn on_sync_peer_disconnected(&mut self, peer: PeerId) -> Result<(), ()> { - if self.important_peers.contains(&peer) { - log::warn!(target: "sync", "Reserved peer {} disconnected", peer); - } else { - log::debug!(target: "sync", "{} disconnected", peer); - } - if self.peers.remove(&peer).is_some() { + if self.important_peers.contains(&peer) { + log::warn!(target: "sync", "Reserved peer {} disconnected", peer); + } else { + log::debug!(target: "sync", "{} disconnected", peer); + } + self.chain_sync.peer_disconnected(&peer); self.default_peers_set_no_slot_connected_peers.remove(&peer); self.event_streams @@ -782,7 +763,8 @@ where pub fn on_sync_peer_connected( &mut self, who: PeerId, - status: BlockAnnouncesHandshake, + status: &BlockAnnouncesHandshake, + sink: NotificationsSink, ) -> Result<(), ()> { log::trace!(target: "sync", "New peer {} {:?}", who, status); @@ -794,8 +776,6 @@ where if status.genesis_hash != self.genesis_hash { self.network_service.report_peer(who, rep::GENESIS_MISMATCH); - self.network_service - .disconnect_peer(who, self.block_announce_protocol_name.clone()); if self.important_peers.contains(&who) { log::error!( @@ -834,8 +814,6 @@ where this_peer_reserved_slot { log::debug!(target: "sync", "Too many full nodes, rejecting {}", who); - self.network_service - .disconnect_peer(who, self.block_announce_protocol_name.clone()); return Err(()) } @@ -844,8 +822,6 @@ where { // Make sure that not all slots are occupied by light clients. log::debug!(target: "sync", "Too many light nodes, rejecting {}", who); - self.network_service - .disconnect_peer(who, self.block_announce_protocol_name.clone()); return Err(()) } @@ -858,14 +834,13 @@ where known_blocks: LruHashSet::new( NonZeroUsize::new(MAX_KNOWN_BLOCKS).expect("Constant is nonzero"), ), + sink, }; let req = if peer.info.roles.is_full() { match self.chain_sync.new_peer(who, peer.info.best_hash, peer.info.best_number) { Ok(req) => req, Err(BadPeer(id, repu)) => { - self.network_service - .disconnect_peer(id, self.block_announce_protocol_name.clone()); self.network_service.report_peer(id, repu); return Err(()) }, diff --git a/client/network/test/Cargo.toml b/client/network/test/Cargo.toml index 8368fa278712a..9763feed5ea54 100644 --- a/client/network/test/Cargo.toml +++ b/client/network/test/Cargo.toml @@ -26,6 +26,7 @@ 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-utils = { version = "4.0.0-dev", path = "../../utils" } 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" } diff --git a/client/network/test/src/lib.rs b/client/network/test/src/lib.rs index 6a99304035ab8..f85d6ed63c247 100644 --- a/client/network/test/src/lib.rs +++ b/client/network/test/src/lib.rs @@ -55,8 +55,8 @@ use sc_network::{ }, request_responses::ProtocolConfig as RequestResponseConfig, types::ProtocolName, - Multiaddr, NetworkBlock, NetworkEventStream, NetworkService, NetworkStateInfo, - NetworkSyncForkRequest, NetworkWorker, + Multiaddr, NetworkBlock, NetworkService, NetworkStateInfo, NetworkSyncForkRequest, + NetworkWorker, }; use sc_network_common::{ role::Roles, @@ -896,6 +896,7 @@ where let (chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new(); + let (tx, rx) = sc_utils::mpsc::tracing_unbounded("mpsc_syncing_engine_protocol", 100_000); let (engine, sync_service, block_announce_config) = sc_network_sync::engine::SyncingEngine::new( Roles::from(if config.is_authority { &Role::Authority } else { &Role::Full }), @@ -911,6 +912,7 @@ where block_request_protocol_config.name.clone(), state_request_protocol_config.name.clone(), Some(warp_protocol_config.name.clone()), + rx, ) .unwrap(); let sync_service_import_queue = Box::new(sync_service.clone()); @@ -918,7 +920,7 @@ where let genesis_hash = client.hash(Zero::zero()).ok().flatten().expect("Genesis block exists; qed"); - let network = NetworkWorker::new::(sc_network::config::Params { + let network = NetworkWorker::new(sc_network::config::Params { role: if config.is_authority { Role::Authority } else { Role::Full }, executor: Box::new(|f| { tokio::spawn(f); @@ -929,6 +931,7 @@ where fork_id, metrics_registry: None, block_announce_config, + tx, request_response_protocol_configs: [ block_request_protocol_config, state_request_protocol_config, @@ -950,9 +953,8 @@ where import_queue.run(sync_service_import_queue).await; }); - let service = network.service().clone(); tokio::spawn(async move { - engine.run(service.event_stream("syncing")).await; + engine.run().await; }); self.mut_peers(move |peers| { diff --git a/client/network/test/src/service.rs b/client/network/test/src/service.rs index 67915c38637ed..5871860a7c4a6 100644 --- a/client/network/test/src/service.rs +++ b/client/network/test/src/service.rs @@ -177,6 +177,7 @@ impl TestNetworkBuilder { let (chain_sync_network_provider, chain_sync_network_handle) = self.chain_sync_network.unwrap_or(NetworkServiceProvider::new()); + let (tx, rx) = sc_utils::mpsc::tracing_unbounded("mpsc_syncing_engine_protocol", 100_000); let (engine, chain_sync_service, block_announce_config) = SyncingEngine::new( Roles::from(&config::Role::Full), @@ -192,6 +193,7 @@ impl TestNetworkBuilder { block_request_protocol_config.name.clone(), state_request_protocol_config.name.clone(), None, + rx, ) .unwrap(); let mut link = self.link.unwrap_or(Box::new(chain_sync_service.clone())); @@ -217,6 +219,7 @@ impl TestNetworkBuilder { light_client_request_protocol_config, ] .to_vec(), + tx, }) .unwrap(); @@ -234,8 +237,7 @@ impl TestNetworkBuilder { tokio::time::sleep(std::time::Duration::from_millis(250)).await; } }); - let stream = worker.service().event_stream("syncing"); - tokio::spawn(engine.run(stream)); + tokio::spawn(engine.run()); TestNetwork::new(worker) } diff --git a/client/network/test/src/sync.rs b/client/network/test/src/sync.rs index d87b03fb3a78c..af46d15a2bacd 100644 --- a/client/network/test/src/sync.rs +++ b/client/network/test/src/sync.rs @@ -414,7 +414,7 @@ async fn can_sync_small_non_best_forks() { // poll until the two nodes connect, otherwise announcing the block will not work futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); - if net.peer(0).num_peers() == 0 { + if net.peer(0).num_peers() == 0 || net.peer(1).num_peers() == 0 { Poll::Pending } else { Poll::Ready(()) diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index 7cbbf2a4dda0f..b04228e6bfc34 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -38,9 +38,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, NetworkEventStream, NetworkService, NetworkStateInfo, NetworkStatusProvider, -}; +use sc_network::{config::SyncMode, NetworkService, NetworkStateInfo, NetworkStatusProvider}; use sc_network_bitswap::BitswapRequestHandler; use sc_network_common::{role::Roles, sync::warp::WarpSyncParams}; use sc_network_light::light_client_requests::handler::LightClientRequestHandler; @@ -825,6 +823,7 @@ where protocol_config }; + let (tx, rx) = sc_utils::mpsc::tracing_unbounded("mpsc_syncing_engine_protocol", 100_000); let (chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new(); let (engine, sync_service, block_announce_config) = SyncingEngine::new( Roles::from(&config.role), @@ -840,6 +839,7 @@ where block_request_protocol_config.name.clone(), state_request_protocol_config.name.clone(), warp_sync_protocol_config.as_ref().map(|config| config.name.clone()), + rx, )?; let sync_service_import_queue = sync_service.clone(); let sync_service = Arc::new(sync_service); @@ -865,6 +865,7 @@ where fork_id: config.chain_spec.fork_id().map(ToOwned::to_owned), metrics_registry: config.prometheus_config.as_ref().map(|config| config.registry.clone()), block_announce_config, + tx, request_response_protocol_configs: request_response_protocol_configs .into_iter() .chain([ @@ -904,15 +905,13 @@ where )?; spawn_handle.spawn("network-transactions-handler", Some("networking"), tx_handler.run()); - spawn_handle.spawn( + spawn_handle.spawn_blocking( "chain-sync-network-service-provider", Some("networking"), chain_sync_network_provider.run(network.clone()), ); spawn_handle.spawn("import-queue", None, import_queue.run(Box::new(sync_service_import_queue))); - - let event_stream = network.event_stream("syncing"); - spawn_handle.spawn("syncing", None, engine.run(event_stream)); + spawn_handle.spawn_blocking("syncing", None, engine.run()); let (system_rpc_tx, system_rpc_rx) = tracing_unbounded("mpsc_system_rpc", 10_000); spawn_handle.spawn( From 9b8e6e780352051029b0fdc56fcac5074bd74552 Mon Sep 17 00:00:00 2001 From: Roman Useinov Date: Thu, 30 Mar 2023 14:53:47 +0200 Subject: [PATCH 592/715] [Enhancement] Throw an error when there are too many pallets (#13763) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [Enhancement] Throw an error when there are too many pallets * fix ui test * fix PR comments * Update frame/support/procedural/src/construct_runtime/mod.rs Co-authored-by: Bastian Köcher * Update frame/support/procedural/src/construct_runtime/mod.rs Co-authored-by: Bastian Köcher * ".git/.scripts/commands/fmt/fmt.sh" --------- Co-authored-by: Bastian Köcher Co-authored-by: command-bot <> --- .../procedural/src/construct_runtime/mod.rs | 40 ++++- .../number_of_pallets_exceeds_tuple_size.rs | 169 ++++++++++++++++++ ...umber_of_pallets_exceeds_tuple_size.stderr | 61 +++++++ 3 files changed, 267 insertions(+), 3 deletions(-) create mode 100644 frame/support/test/tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs create mode 100644 frame/support/test/tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.stderr diff --git a/frame/support/procedural/src/construct_runtime/mod.rs b/frame/support/procedural/src/construct_runtime/mod.rs index 37f23efed36c1..9250186dc38e6 100644 --- a/frame/support/procedural/src/construct_runtime/mod.rs +++ b/frame/support/procedural/src/construct_runtime/mod.rs @@ -157,7 +157,7 @@ use proc_macro::TokenStream; use proc_macro2::TokenStream as TokenStream2; use quote::quote; use std::{collections::HashSet, str::FromStr}; -use syn::{Ident, Result}; +use syn::{spanned::Spanned, Ident, Result}; /// The fixed name of the system pallet. const SYSTEM_PALLET_NAME: &str = "System"; @@ -170,9 +170,12 @@ pub fn construct_runtime(input: TokenStream) -> TokenStream { let res = match definition { RuntimeDeclaration::Implicit(implicit_def) => - construct_runtime_intermediary_expansion(input_copy.into(), implicit_def), + check_pallet_number(input_copy.clone().into(), implicit_def.pallets.len()).and_then( + |_| construct_runtime_intermediary_expansion(input_copy.into(), implicit_def), + ), RuntimeDeclaration::Explicit(explicit_decl) => - construct_runtime_final_expansion(explicit_decl), + check_pallet_number(input_copy.into(), explicit_decl.pallets.len()) + .and_then(|_| construct_runtime_final_expansion(explicit_decl)), }; res.unwrap_or_else(|e| e.to_compile_error()).into() @@ -616,3 +619,34 @@ fn decl_static_assertions( #(#error_encoded_size_check)* } } + +fn check_pallet_number(input: TokenStream2, pallet_num: usize) -> Result<()> { + let max_pallet_num = { + if cfg!(feature = "tuples-96") { + 96 + } else if cfg!(feature = "tuples-128") { + 128 + } else { + 64 + } + }; + + if pallet_num > max_pallet_num { + let no_feature = max_pallet_num == 128; + return Err(syn::Error::new( + input.span(), + format!( + "{} To increase this limit, enable the tuples-{} feature of [frame_support]. {}", + "The number of pallets exceeds the maximum number of tuple elements.", + max_pallet_num + 32, + if no_feature { + "If the feature does not exist - it needs to be implemented." + } else { + "" + }, + ), + )) + } + + Ok(()) +} diff --git a/frame/support/test/tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs b/frame/support/test/tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs new file mode 100644 index 0000000000000..5dfc67c83836a --- /dev/null +++ b/frame/support/test/tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs @@ -0,0 +1,169 @@ +use frame_support::construct_runtime; +use sp_core::sr25519; +use sp_runtime::{generic, traits::BlakeTwo256}; + +#[frame_support::pallet] +mod pallet { + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); +} + +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 RuntimeOrigin = RuntimeOrigin; + type Index = u64; + type BlockNumber = u32; + 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 RuntimeEvent = RuntimeEvent; + 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 struct Runtime where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic + { + System: frame_system::{Pallet, Call, Storage, Config, Event}, + Pallet1: pallet::{Pallet}, + Pallet2: pallet::{Pallet}, + Pallet3: pallet::{Pallet}, + Pallet4: pallet::{Pallet}, + Pallet5: pallet::{Pallet}, + Pallet6: pallet::{Pallet}, + Pallet7: pallet::{Pallet}, + Pallet8: pallet::{Pallet}, + Pallet9: pallet::{Pallet}, + Pallet10: pallet::{Pallet}, + Pallet11: pallet::{Pallet}, + Pallet12: pallet::{Pallet}, + Pallet13: pallet::{Pallet}, + Pallet14: pallet::{Pallet}, + Pallet15: pallet::{Pallet}, + Pallet16: pallet::{Pallet}, + Pallet17: pallet::{Pallet}, + Pallet18: pallet::{Pallet}, + Pallet19: pallet::{Pallet}, + Pallet20: pallet::{Pallet}, + Pallet21: pallet::{Pallet}, + Pallet22: pallet::{Pallet}, + Pallet23: pallet::{Pallet}, + Pallet24: pallet::{Pallet}, + Pallet25: pallet::{Pallet}, + Pallet26: pallet::{Pallet}, + Pallet27: pallet::{Pallet}, + Pallet28: pallet::{Pallet}, + Pallet29: pallet::{Pallet}, + Pallet30: pallet::{Pallet}, + Pallet31: pallet::{Pallet}, + Pallet32: pallet::{Pallet}, + Pallet33: pallet::{Pallet}, + Pallet34: pallet::{Pallet}, + Pallet35: pallet::{Pallet}, + Pallet36: pallet::{Pallet}, + Pallet37: pallet::{Pallet}, + Pallet38: pallet::{Pallet}, + Pallet39: pallet::{Pallet}, + Pallet40: pallet::{Pallet}, + Pallet41: pallet::{Pallet}, + Pallet42: pallet::{Pallet}, + Pallet43: pallet::{Pallet}, + Pallet44: pallet::{Pallet}, + Pallet45: pallet::{Pallet}, + Pallet46: pallet::{Pallet}, + Pallet47: pallet::{Pallet}, + Pallet48: pallet::{Pallet}, + Pallet49: pallet::{Pallet}, + Pallet50: pallet::{Pallet}, + Pallet51: pallet::{Pallet}, + Pallet52: pallet::{Pallet}, + Pallet53: pallet::{Pallet}, + Pallet54: pallet::{Pallet}, + Pallet55: pallet::{Pallet}, + Pallet56: pallet::{Pallet}, + Pallet57: pallet::{Pallet}, + Pallet58: pallet::{Pallet}, + Pallet59: pallet::{Pallet}, + Pallet60: pallet::{Pallet}, + Pallet61: pallet::{Pallet}, + Pallet62: pallet::{Pallet}, + Pallet63: pallet::{Pallet}, + Pallet64: pallet::{Pallet}, + Pallet65: pallet::{Pallet}, + Pallet66: pallet::{Pallet}, + Pallet67: pallet::{Pallet}, + Pallet68: pallet::{Pallet}, + Pallet69: pallet::{Pallet}, + Pallet70: pallet::{Pallet}, + Pallet71: pallet::{Pallet}, + Pallet72: pallet::{Pallet}, + Pallet73: pallet::{Pallet}, + Pallet74: pallet::{Pallet}, + Pallet75: pallet::{Pallet}, + Pallet76: pallet::{Pallet}, + Pallet77: pallet::{Pallet}, + Pallet78: pallet::{Pallet}, + Pallet79: pallet::{Pallet}, + Pallet80: pallet::{Pallet}, + Pallet81: pallet::{Pallet}, + Pallet82: pallet::{Pallet}, + Pallet83: pallet::{Pallet}, + Pallet84: pallet::{Pallet}, + Pallet85: pallet::{Pallet}, + Pallet86: pallet::{Pallet}, + Pallet87: pallet::{Pallet}, + Pallet88: pallet::{Pallet}, + Pallet89: pallet::{Pallet}, + Pallet90: pallet::{Pallet}, + Pallet91: pallet::{Pallet}, + Pallet92: pallet::{Pallet}, + Pallet93: pallet::{Pallet}, + Pallet94: pallet::{Pallet}, + Pallet95: pallet::{Pallet}, + Pallet96: pallet::{Pallet}, + Pallet97: pallet::{Pallet}, + Pallet98: pallet::{Pallet}, + Pallet99: pallet::{Pallet}, + Pallet100: pallet::{Pallet}, + Pallet101: pallet::{Pallet}, + Pallet102: pallet::{Pallet}, + Pallet103: pallet::{Pallet}, + Pallet104: pallet::{Pallet}, + Pallet105: pallet::{Pallet}, + Pallet106: pallet::{Pallet}, + Pallet107: pallet::{Pallet}, + Pallet108: pallet::{Pallet}, + Pallet109: pallet::{Pallet}, + Pallet110: pallet::{Pallet}, + } +} + +fn main() {} diff --git a/frame/support/test/tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.stderr b/frame/support/test/tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.stderr new file mode 100644 index 0000000000000..dbd81ef367a9f --- /dev/null +++ b/frame/support/test/tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.stderr @@ -0,0 +1,61 @@ +error: The number of pallets exceeds the maximum number of tuple elements. To increase this limit, enable the tuples-96 feature of [frame_support]. + --> tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs:50:2 + | +50 | pub struct Runtime where + | ^^^ + +error[E0412]: cannot find type `RuntimeCall` in this scope + --> tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs:18:64 + | +18 | pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; + | ^^^^^^^^^^^ not found in this scope + | +help: you might be missing a type parameter + | +18 | pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; + | +++++++++++++ + +error[E0412]: cannot find type `Runtime` in this scope + --> tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs:20:25 + | +20 | impl pallet::Config for Runtime {} + | ^^^^^^^ not found in this scope + +error[E0412]: cannot find type `Runtime` in this scope + --> tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs:22:31 + | +22 | impl frame_system::Config for Runtime { + | ^^^^^^^ not found in this scope + +error[E0412]: cannot find type `RuntimeOrigin` in this scope + --> tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs:24:23 + | +24 | type RuntimeOrigin = RuntimeOrigin; + | ^^^^^^^^^^^^^ help: you might have meant to use the associated type: `Self::RuntimeOrigin` + +error[E0412]: cannot find type `RuntimeCall` in this scope + --> tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs:27:21 + | +27 | type RuntimeCall = RuntimeCall; + | ^^^^^^^^^^^ help: you might have meant to use the associated type: `Self::RuntimeCall` + +error[E0412]: cannot find type `RuntimeEvent` in this scope + --> tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs:33:22 + | +33 | type RuntimeEvent = RuntimeEvent; + | ^^^^^^^^^^^^ help: you might have meant to use the associated type: `Self::RuntimeEvent` + +error[E0412]: cannot find type `PalletInfo` in this scope + --> tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs:39:20 + | +39 | type PalletInfo = PalletInfo; + | ^^^^^^^^^^ + | +help: you might have meant to use the associated type + | +39 | type PalletInfo = Self::PalletInfo; + | ~~~~~~~~~~~~~~~~ +help: consider importing this trait + | +1 | use frame_support::traits::PalletInfo; + | From a0468b335a4bb57ad83d6b0a19a8088ec1319eb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Thu, 30 Mar 2023 16:20:12 +0200 Subject: [PATCH 593/715] Build wasm for mvp cpu (#13758) --- utils/wasm-builder/src/wasm_project.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/wasm-builder/src/wasm_project.rs b/utils/wasm-builder/src/wasm_project.rs index a3038c4e934c9..d25fb4acd2345 100644 --- a/utils/wasm-builder/src/wasm_project.rs +++ b/utils/wasm-builder/src/wasm_project.rs @@ -632,7 +632,7 @@ fn build_project( let mut build_cmd = cargo_cmd.command(); let rustflags = format!( - "-C link-arg=--export-table {} {}", + "-C target-cpu=mvp -C link-arg=--export-table {} {}", default_rustflags, env::var(crate::WASM_BUILD_RUSTFLAGS_ENV).unwrap_or_default(), ); From 025325d0c2c478a6f27789408ecaabaf8b9e8680 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Thu, 30 Mar 2023 17:23:36 +0300 Subject: [PATCH 594/715] BEEFY: gossip finality proofs (#13727) * sc-consensus-beefy: add justifications to gossip protocol * sc-consensus-beefy: voter gossips finality proofs * sc-consensus-beefy: add finality proof gossip test * sc-consensus-beefy: always gossip finality proof Gossip finality proof in _both_ cases of reaching finality threshold through votes: 1. threshold reached through self vote, 2. threshold reached through incoming vote. * address comments --- .../beefy/src/communication/gossip.rs | 516 +++++++++++++----- .../consensus/beefy/src/communication/mod.rs | 6 +- client/consensus/beefy/src/justification.rs | 16 +- client/consensus/beefy/src/lib.rs | 2 +- client/consensus/beefy/src/round.rs | 38 +- client/consensus/beefy/src/tests.rs | 176 +++++- client/consensus/beefy/src/worker.rs | 94 +++- 7 files changed, 642 insertions(+), 206 deletions(-) diff --git a/client/consensus/beefy/src/communication/gossip.rs b/client/consensus/beefy/src/communication/gossip.rs index 2b5e772c0578f..376172fc23370 100644 --- a/client/consensus/beefy/src/communication/gossip.rs +++ b/client/consensus/beefy/src/communication/gossip.rs @@ -28,10 +28,17 @@ use log::{debug, trace}; use parking_lot::{Mutex, RwLock}; use wasm_timer::Instant; -use crate::{communication::peers::KnownPeers, keystore::BeefyKeystore, LOG_TARGET}; +use crate::{ + communication::peers::KnownPeers, + justification::{ + proof_block_num_and_set_id, verify_with_validator_set, BeefyVersionedFinalityProof, + }, + keystore::BeefyKeystore, + LOG_TARGET, +}; use sp_consensus_beefy::{ - crypto::{Public, Signature}, - ValidatorSetId, VoteMessage, + crypto::{AuthorityId, Signature}, + ValidatorSet, ValidatorSetId, VoteMessage, }; // Timeout for rebroadcasting messages. @@ -40,59 +47,128 @@ const REBROADCAST_AFTER: Duration = Duration::from_secs(60); #[cfg(test)] const REBROADCAST_AFTER: Duration = Duration::from_secs(5); -/// Gossip engine messages topic -pub(crate) fn topic() -> B::Hash +/// BEEFY gossip message type that gets encoded and sent on the network. +#[derive(Debug, Encode, Decode)] +pub(crate) enum GossipMessage { + /// BEEFY message with commitment and single signature. + Vote(VoteMessage, AuthorityId, Signature>), + /// BEEFY justification with commitment and signatures. + FinalityProof(BeefyVersionedFinalityProof), +} + +impl GossipMessage { + /// Return inner vote if this message is a Vote. + pub fn unwrap_vote(self) -> Option, AuthorityId, Signature>> { + match self { + GossipMessage::Vote(vote) => Some(vote), + GossipMessage::FinalityProof(_) => None, + } + } + + /// Return inner finality proof if this message is a FinalityProof. + pub fn unwrap_finality_proof(self) -> Option> { + match self { + GossipMessage::Vote(_) => None, + GossipMessage::FinalityProof(proof) => Some(proof), + } + } +} + +/// Gossip engine votes messages topic +pub(crate) fn votes_topic() -> B::Hash where B: Block, { - <::Hashing as Hash>::hash(b"beefy") + <::Hashing as Hash>::hash(b"beefy-votes") } -#[derive(Debug)] -pub(crate) struct GossipVoteFilter { - pub start: NumberFor, - pub end: NumberFor, - pub validator_set_id: ValidatorSetId, +/// Gossip engine justifications messages topic +pub(crate) fn proofs_topic() -> B::Hash +where + B: Block, +{ + <::Hashing as Hash>::hash(b"beefy-justifications") } /// A type that represents hash of the message. pub type MessageHash = [u8; 8]; -struct VotesFilter { - filter: Option>, - live: BTreeMap, fnv::FnvHashSet>, +#[derive(Clone, Debug)] +pub(crate) struct GossipFilterCfg<'a, B: Block> { + pub start: NumberFor, + pub end: NumberFor, + pub validator_set: &'a ValidatorSet, +} + +#[derive(Clone, Debug)] +struct FilterInner { + pub start: NumberFor, + pub end: NumberFor, + pub validator_set: ValidatorSet, +} + +struct Filter { + inner: Option>, + live_votes: BTreeMap, fnv::FnvHashSet>, } -impl VotesFilter { +impl Filter { pub fn new() -> Self { - Self { filter: None, live: BTreeMap::new() } + Self { inner: None, live_votes: BTreeMap::new() } } /// Update filter to new `start` and `set_id`. - fn update(&mut self, filter: GossipVoteFilter) { - self.live.retain(|&round, _| round >= filter.start && round <= filter.end); - self.filter = Some(filter); + fn update(&mut self, cfg: GossipFilterCfg) { + self.live_votes.retain(|&round, _| round >= cfg.start && round <= cfg.end); + // only clone+overwrite big validator_set if set_id changed + match self.inner.as_mut() { + Some(f) if f.validator_set.id() == cfg.validator_set.id() => { + f.start = cfg.start; + f.end = cfg.end; + }, + _ => + self.inner = Some(FilterInner { + start: cfg.start, + end: cfg.end, + validator_set: cfg.validator_set.clone(), + }), + } + } + + /// Return true if `max(session_start, best_beefy) <= round <= best_grandpa`, + /// and vote `set_id` matches session set id. + /// + /// Latest concluded round is still considered alive to allow proper gossiping for it. + fn is_vote_accepted(&self, round: NumberFor, set_id: ValidatorSetId) -> bool { + self.inner + .as_ref() + .map(|f| set_id == f.validator_set.id() && round >= f.start && round <= f.end) + .unwrap_or(false) } /// Return true if `round` is >= than `max(session_start, best_beefy)`, - /// and vote set id matches session set id. + /// and proof `set_id` matches session set id. /// /// Latest concluded round is still considered alive to allow proper gossiping for it. - fn is_live(&self, round: NumberFor, set_id: ValidatorSetId) -> bool { - self.filter + fn is_finality_proof_accepted(&self, round: NumberFor, set_id: ValidatorSetId) -> bool { + self.inner .as_ref() - .map(|f| set_id == f.validator_set_id && round >= f.start && round <= f.end) + .map(|f| set_id == f.validator_set.id() && round >= f.start) .unwrap_or(false) } /// Add new _known_ `hash` to the round's known votes. - fn add_known(&mut self, round: NumberFor, hash: MessageHash) { - self.live.entry(round).or_default().insert(hash); + fn add_known_vote(&mut self, round: NumberFor, hash: MessageHash) { + self.live_votes.entry(round).or_default().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) + fn is_known_vote(&self, round: NumberFor, hash: &MessageHash) -> bool { + self.live_votes.get(&round).map(|known| known.contains(hash)).unwrap_or(false) + } + + fn validator_set(&self) -> Option<&ValidatorSet> { + self.inner.as_ref().map(|f| &f.validator_set) } } @@ -108,8 +184,9 @@ pub(crate) struct GossipValidator where B: Block, { - topic: B::Hash, - votes_filter: RwLock>, + votes_topic: B::Hash, + justifs_topic: B::Hash, + gossip_filter: RwLock>, next_rebroadcast: Mutex, known_peers: Arc>>, } @@ -120,8 +197,9 @@ where { pub fn new(known_peers: Arc>>) -> GossipValidator { GossipValidator { - topic: topic::(), - votes_filter: RwLock::new(VotesFilter::new()), + votes_topic: votes_topic::(), + justifs_topic: proofs_topic::(), + gossip_filter: RwLock::new(Filter::new()), next_rebroadcast: Mutex::new(Instant::now() + REBROADCAST_AFTER), known_peers, } @@ -130,9 +208,79 @@ where /// Update gossip validator filter. /// /// Only votes for `set_id` and rounds `start <= round <= end` will be accepted. - pub(crate) fn update_filter(&self, filter: GossipVoteFilter) { + pub(crate) fn update_filter(&self, filter: GossipFilterCfg) { debug!(target: LOG_TARGET, "🥩 New gossip filter {:?}", filter); - self.votes_filter.write().update(filter); + self.gossip_filter.write().update(filter); + } + + fn validate_vote( + &self, + vote: VoteMessage, AuthorityId, Signature>, + sender: &PeerId, + data: &[u8], + ) -> ValidationResult { + let msg_hash = twox_64(data); + let round = vote.commitment.block_number; + let set_id = vote.commitment.validator_set_id; + self.known_peers.lock().note_vote_for(*sender, round); + + // Verify general usefulness of the message. + // We are going to discard old votes right away (without verification) + // Also we keep track of already received votes to avoid verifying duplicates. + { + let filter = self.gossip_filter.read(); + + if !filter.is_vote_accepted(round, set_id) { + return ValidationResult::Discard + } + + if filter.is_known_vote(round, &msg_hash) { + return ValidationResult::ProcessAndKeep(self.votes_topic) + } + } + + if BeefyKeystore::verify(&vote.id, &vote.signature, &vote.commitment.encode()) { + self.gossip_filter.write().add_known_vote(round, msg_hash); + ValidationResult::ProcessAndKeep(self.votes_topic) + } else { + // TODO: report peer + debug!( + target: LOG_TARGET, + "🥩 Bad signature on message: {:?}, from: {:?}", vote, sender + ); + ValidationResult::Discard + } + } + + fn validate_finality_proof( + &self, + proof: BeefyVersionedFinalityProof, + sender: &PeerId, + ) -> ValidationResult { + let (round, set_id) = proof_block_num_and_set_id::(&proof); + self.known_peers.lock().note_vote_for(*sender, round); + + let guard = self.gossip_filter.read(); + // Verify general usefulness of the justifications. + if !guard.is_finality_proof_accepted(round, set_id) { + return ValidationResult::Discard + } + // Verify justification signatures. + guard + .validator_set() + .map(|validator_set| { + if let Ok(()) = verify_with_validator_set::(round, validator_set, &proof) { + ValidationResult::ProcessAndKeep(self.justifs_topic) + } else { + // TODO: report peer + debug!( + target: LOG_TARGET, + "🥩 Bad signatures on message: {:?}, from: {:?}", proof, sender + ); + ValidationResult::Discard + } + }) + .unwrap_or(ValidationResult::Discard) } } @@ -150,57 +298,38 @@ where 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; - let set_id = msg.commitment.validator_set_id; - self.known_peers.lock().note_vote_for(*sender, round); - - // Verify general usefulness of the message. - // We are going to discard old votes right away (without verification) - // Also we keep track of already received votes to avoid verifying duplicates. - { - let filter = self.votes_filter.read(); - - if !filter.is_live(round, set_id) { - return ValidationResult::Discard - } - - if filter.is_known(round, &msg_hash) { - return ValidationResult::ProcessAndKeep(self.topic) - } - } - - if BeefyKeystore::verify(&msg.id, &msg.signature, &msg.commitment.encode()) { - self.votes_filter.write().add_known(round, msg_hash); - return ValidationResult::ProcessAndKeep(self.topic) - } else { - // TODO: report peer - debug!( - target: LOG_TARGET, - "🥩 Bad signature on message: {:?}, from: {:?}", msg, sender - ); - } + match GossipMessage::::decode(&mut data) { + Ok(GossipMessage::Vote(msg)) => self.validate_vote(msg, sender, data), + Ok(GossipMessage::FinalityProof(proof)) => self.validate_finality_proof(proof, sender), + Err(e) => { + debug!(target: LOG_TARGET, "Error decoding message: {}", e); + ValidationResult::Discard + }, } - - ValidationResult::Discard } fn message_expired<'a>(&'a self) -> Box bool + 'a> { - let filter = self.votes_filter.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 set_id = msg.commitment.validator_set_id; - let expired = !filter.is_live(round, set_id); - - trace!(target: LOG_TARGET, "🥩 Message for round #{} expired: {}", round, expired); - - expired + let filter = self.gossip_filter.read(); + Box::new(move |_topic, mut data| match GossipMessage::::decode(&mut data) { + Ok(GossipMessage::Vote(msg)) => { + let round = msg.commitment.block_number; + let set_id = msg.commitment.validator_set_id; + let expired = !filter.is_vote_accepted(round, set_id); + trace!(target: LOG_TARGET, "🥩 Vote for round #{} expired: {}", round, expired); + expired + }, + Ok(GossipMessage::FinalityProof(proof)) => { + let (round, set_id) = proof_block_num_and_set_id::(&proof); + let expired = !filter.is_finality_proof_accepted(round, set_id); + trace!( + target: LOG_TARGET, + "🥩 Finality proof for round #{} expired: {}", + round, + expired + ); + expired + }, + Err(_) => true, }) } @@ -219,68 +348,80 @@ where } }; - let filter = self.votes_filter.read(); + let filter = self.gossip_filter.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 false, - }; - - let round = msg.commitment.block_number; - let set_id = msg.commitment.validator_set_id; - let allowed = filter.is_live(round, set_id); - - trace!(target: LOG_TARGET, "🥩 Message for round #{} allowed: {}", round, allowed); - - allowed + match GossipMessage::::decode(&mut data) { + Ok(GossipMessage::Vote(msg)) => { + let round = msg.commitment.block_number; + let set_id = msg.commitment.validator_set_id; + let allowed = filter.is_vote_accepted(round, set_id); + trace!(target: LOG_TARGET, "🥩 Vote for round #{} allowed: {}", round, allowed); + allowed + }, + Ok(GossipMessage::FinalityProof(proof)) => { + let (round, set_id) = proof_block_num_and_set_id::(&proof); + let allowed = filter.is_finality_proof_accepted(round, set_id); + trace!( + target: LOG_TARGET, + "🥩 Finality proof for round #{} allowed: {}", + round, + allowed + ); + allowed + }, + Err(_) => false, + } }) } } #[cfg(test)] -mod tests { +pub(crate) mod tests { use super::*; use crate::keystore::BeefyKeystore; use sc_network_test::Block; use sp_consensus_beefy::{ - crypto::Signature, known_payloads, Commitment, Keyring, MmrRootHash, Payload, VoteMessage, - KEY_TYPE, + crypto::Signature, known_payloads, Commitment, Keyring, MmrRootHash, Payload, + SignedCommitment, VoteMessage, KEY_TYPE, }; use sp_keystore::{testing::MemoryKeystore, Keystore}; #[test] fn known_votes_insert_remove() { - let mut kv = VotesFilter::::new(); + let mut filter = Filter::::new(); let msg_hash = twox_64(b"data"); - - kv.add_known(1, msg_hash); - kv.add_known(1, msg_hash); - kv.add_known(2, msg_hash); - assert_eq!(kv.live.len(), 2); - - kv.add_known(3, msg_hash); - assert!(kv.is_known(3, &msg_hash)); - assert!(!kv.is_known(3, &twox_64(b"other"))); - assert!(!kv.is_known(4, &msg_hash)); - assert_eq!(kv.live.len(), 3); - - assert!(kv.filter.is_none()); - assert!(!kv.is_live(1, 1)); - - kv.update(GossipVoteFilter { start: 3, end: 10, validator_set_id: 1 }); - assert_eq!(kv.live.len(), 1); - assert!(kv.live.contains_key(&3)); - assert!(!kv.is_live(2, 1)); - assert!(kv.is_live(3, 1)); - assert!(kv.is_live(4, 1)); - assert!(!kv.is_live(4, 2)); - - kv.update(GossipVoteFilter { start: 5, end: 10, validator_set_id: 2 }); - assert!(kv.live.is_empty()); + let keys = vec![Keyring::Alice.public()]; + let validator_set = ValidatorSet::::new(keys.clone(), 1).unwrap(); + + filter.add_known_vote(1, msg_hash); + filter.add_known_vote(1, msg_hash); + filter.add_known_vote(2, msg_hash); + assert_eq!(filter.live_votes.len(), 2); + + filter.add_known_vote(3, msg_hash); + assert!(filter.is_known_vote(3, &msg_hash)); + assert!(!filter.is_known_vote(3, &twox_64(b"other"))); + assert!(!filter.is_known_vote(4, &msg_hash)); + assert_eq!(filter.live_votes.len(), 3); + + assert!(filter.inner.is_none()); + assert!(!filter.is_vote_accepted(1, 1)); + + filter.update(GossipFilterCfg { start: 3, end: 10, validator_set: &validator_set }); + assert_eq!(filter.live_votes.len(), 1); + assert!(filter.live_votes.contains_key(&3)); + assert!(!filter.is_vote_accepted(2, 1)); + assert!(filter.is_vote_accepted(3, 1)); + assert!(filter.is_vote_accepted(4, 1)); + assert!(!filter.is_vote_accepted(4, 2)); + + let validator_set = ValidatorSet::::new(keys, 2).unwrap(); + filter.update(GossipFilterCfg { start: 5, end: 10, validator_set: &validator_set }); + assert!(filter.live_votes.is_empty()); } struct TestContext; @@ -302,14 +443,14 @@ mod tests { } } - fn sign_commitment(who: &Keyring, commitment: &Commitment) -> Signature { + pub fn sign_commitment(who: &Keyring, commitment: &Commitment) -> Signature { let store = MemoryKeystore::new(); store.ecdsa_generate_new(KEY_TYPE, Some(&who.to_seed())).unwrap(); let beefy_keystore: BeefyKeystore = Some(store.into()).into(); beefy_keystore.sign(&who.public(), &commitment.encode()).unwrap() } - fn dummy_vote(block_number: u64) -> VoteMessage { + fn dummy_vote(block_number: u64) -> VoteMessage { let payload = Payload::from_single_entry( known_payloads::MMR_ROOT_ID, MmrRootHash::default().encode(), @@ -320,51 +461,111 @@ mod tests { VoteMessage { commitment, id: Keyring::Alice.public(), signature } } + pub fn dummy_proof( + block_number: u64, + validator_set: &ValidatorSet, + ) -> BeefyVersionedFinalityProof { + let payload = Payload::from_single_entry( + known_payloads::MMR_ROOT_ID, + MmrRootHash::default().encode(), + ); + let commitment = Commitment { payload, block_number, validator_set_id: validator_set.id() }; + let signatures = validator_set + .validators() + .iter() + .map(|validator: &AuthorityId| { + Some(sign_commitment(&Keyring::from_public(validator).unwrap(), &commitment)) + }) + .collect(); + + BeefyVersionedFinalityProof::::V1(SignedCommitment { commitment, signatures }) + } + #[test] - fn should_avoid_verifying_signatures_twice() { + fn should_validate_messages() { + let keys = vec![Keyring::Alice.public()]; + let validator_set = ValidatorSet::::new(keys.clone(), 0).unwrap(); let gv = GossipValidator::::new(Arc::new(Mutex::new(KnownPeers::new()))); - gv.update_filter(GossipVoteFilter { start: 0, end: 10, validator_set_id: 0 }); + gv.update_filter(GossipFilterCfg { start: 0, end: 10, validator_set: &validator_set }); let sender = sc_network::PeerId::random(); let mut context = TestContext; let vote = dummy_vote(3); + let gossip_vote = GossipMessage::::Vote(vote.clone()); // first time the cache should be populated - let res = gv.validate(&mut context, &sender, &vote.encode()); + let res = gv.validate(&mut context, &sender, &gossip_vote.encode()); assert!(matches!(res, ValidationResult::ProcessAndKeep(_))); assert_eq!( - gv.votes_filter.read().live.get(&vote.commitment.block_number).map(|x| x.len()), + gv.gossip_filter + .read() + .live_votes + .get(&vote.commitment.block_number) + .map(|x| x.len()), Some(1) ); // second time we should hit the cache - let res = gv.validate(&mut context, &sender, &vote.encode()); - + let res = gv.validate(&mut context, &sender, &gossip_vote.encode()); assert!(matches!(res, ValidationResult::ProcessAndKeep(_))); // next we should quickly reject if the round is not live - gv.update_filter(GossipVoteFilter { start: 7, end: 10, validator_set_id: 0 }); + gv.update_filter(GossipFilterCfg { start: 7, end: 10, validator_set: &validator_set }); let number = vote.commitment.block_number; let set_id = vote.commitment.validator_set_id; - assert!(!gv.votes_filter.read().is_live(number, set_id)); + assert!(!gv.gossip_filter.read().is_vote_accepted(number, set_id)); let res = gv.validate(&mut context, &sender, &vote.encode()); + assert!(matches!(res, ValidationResult::Discard)); + + // reject old proof + let proof = dummy_proof(5, &validator_set); + let encoded_proof = GossipMessage::::FinalityProof(proof).encode(); + let res = gv.validate(&mut context, &sender, &encoded_proof); + assert!(matches!(res, ValidationResult::Discard)); + + // accept next proof with good set_id + let proof = dummy_proof(7, &validator_set); + let encoded_proof = GossipMessage::::FinalityProof(proof).encode(); + let res = gv.validate(&mut context, &sender, &encoded_proof); + assert!(matches!(res, ValidationResult::ProcessAndKeep(_))); + + // accept future proof with good set_id + let proof = dummy_proof(20, &validator_set); + let encoded_proof = GossipMessage::::FinalityProof(proof).encode(); + let res = gv.validate(&mut context, &sender, &encoded_proof); + assert!(matches!(res, ValidationResult::ProcessAndKeep(_))); + // reject proof, wrong set_id + let bad_validator_set = ValidatorSet::::new(keys, 1).unwrap(); + let proof = dummy_proof(20, &bad_validator_set); + let encoded_proof = GossipMessage::::FinalityProof(proof).encode(); + let res = gv.validate(&mut context, &sender, &encoded_proof); + assert!(matches!(res, ValidationResult::Discard)); + + // reject proof, bad signatures (Bob instead of Alice) + let bad_validator_set = + ValidatorSet::::new(vec![Keyring::Bob.public()], 0).unwrap(); + let proof = dummy_proof(20, &bad_validator_set); + let encoded_proof = GossipMessage::::FinalityProof(proof).encode(); + let res = gv.validate(&mut context, &sender, &encoded_proof); assert!(matches!(res, ValidationResult::Discard)); } #[test] fn messages_allowed_and_expired() { + let keys = vec![Keyring::Alice.public()]; + let validator_set = ValidatorSet::::new(keys.clone(), 0).unwrap(); let gv = GossipValidator::::new(Arc::new(Mutex::new(KnownPeers::new()))); - gv.update_filter(GossipVoteFilter { start: 0, end: 10, validator_set_id: 0 }); + gv.update_filter(GossipFilterCfg { start: 0, end: 10, validator_set: &validator_set }); let sender = sc_network::PeerId::random(); let topic = Default::default(); let intent = MessageIntent::Broadcast; // conclude 2 - gv.update_filter(GossipVoteFilter { start: 2, end: 10, validator_set_id: 0 }); + gv.update_filter(GossipFilterCfg { start: 2, end: 10, validator_set: &validator_set }); let mut allowed = gv.message_allowed(); let mut expired = gv.message_expired(); @@ -374,33 +575,68 @@ mod tests { // inactive round 1 -> expired let vote = dummy_vote(1); - let mut encoded_vote = vote.encode(); + let mut encoded_vote = GossipMessage::::Vote(vote).encode(); assert!(!allowed(&sender, intent, &topic, &mut encoded_vote)); assert!(expired(topic, &mut encoded_vote)); + let proof = dummy_proof(1, &validator_set); + let mut encoded_proof = GossipMessage::::FinalityProof(proof).encode(); + assert!(!allowed(&sender, intent, &topic, &mut encoded_proof)); + assert!(expired(topic, &mut encoded_proof)); // active round 2 -> !expired - concluded but still gossiped let vote = dummy_vote(2); - let mut encoded_vote = vote.encode(); + let mut encoded_vote = GossipMessage::::Vote(vote).encode(); assert!(allowed(&sender, intent, &topic, &mut encoded_vote)); assert!(!expired(topic, &mut encoded_vote)); + let proof = dummy_proof(2, &validator_set); + let mut encoded_proof = GossipMessage::::FinalityProof(proof).encode(); + assert!(allowed(&sender, intent, &topic, &mut encoded_proof)); + assert!(!expired(topic, &mut encoded_proof)); + // using wrong set_id -> !allowed, expired + let bad_validator_set = ValidatorSet::::new(keys.clone(), 1).unwrap(); + let proof = dummy_proof(2, &bad_validator_set); + let mut encoded_proof = GossipMessage::::FinalityProof(proof).encode(); + assert!(!allowed(&sender, intent, &topic, &mut encoded_proof)); + assert!(expired(topic, &mut encoded_proof)); // in progress round 3 -> !expired let vote = dummy_vote(3); - let mut encoded_vote = vote.encode(); + let mut encoded_vote = GossipMessage::::Vote(vote).encode(); assert!(allowed(&sender, intent, &topic, &mut encoded_vote)); assert!(!expired(topic, &mut encoded_vote)); + let proof = dummy_proof(3, &validator_set); + let mut encoded_proof = GossipMessage::::FinalityProof(proof).encode(); + assert!(allowed(&sender, intent, &topic, &mut encoded_proof)); + assert!(!expired(topic, &mut encoded_proof)); // unseen round 4 -> !expired - let vote = dummy_vote(3); - let mut encoded_vote = vote.encode(); + let vote = dummy_vote(4); + let mut encoded_vote = GossipMessage::::Vote(vote).encode(); assert!(allowed(&sender, intent, &topic, &mut encoded_vote)); assert!(!expired(topic, &mut encoded_vote)); + let proof = dummy_proof(4, &validator_set); + let mut encoded_proof = GossipMessage::::FinalityProof(proof).encode(); + assert!(allowed(&sender, intent, &topic, &mut encoded_proof)); + assert!(!expired(topic, &mut encoded_proof)); + + // future round 11 -> expired + let vote = dummy_vote(11); + let mut encoded_vote = GossipMessage::::Vote(vote).encode(); + assert!(!allowed(&sender, intent, &topic, &mut encoded_vote)); + assert!(expired(topic, &mut encoded_vote)); + // future proofs allowed while same set_id -> allowed + let proof = dummy_proof(11, &validator_set); + let mut encoded_proof = GossipMessage::::FinalityProof(proof).encode(); + assert!(allowed(&sender, intent, &topic, &mut encoded_proof)); + assert!(!expired(topic, &mut encoded_proof)); } #[test] fn messages_rebroadcast() { + let keys = vec![Keyring::Alice.public()]; + let validator_set = ValidatorSet::::new(keys.clone(), 0).unwrap(); let gv = GossipValidator::::new(Arc::new(Mutex::new(KnownPeers::new()))); - gv.update_filter(GossipVoteFilter { start: 0, end: 10, validator_set_id: 0 }); + gv.update_filter(GossipFilterCfg { start: 0, end: 10, validator_set: &validator_set }); let sender = sc_network::PeerId::random(); let topic = Default::default(); diff --git a/client/consensus/beefy/src/communication/mod.rs b/client/consensus/beefy/src/communication/mod.rs index 295d549bb1ba8..13735a9d3211b 100644 --- a/client/consensus/beefy/src/communication/mod.rs +++ b/client/consensus/beefy/src/communication/mod.rs @@ -29,7 +29,7 @@ pub(crate) mod beefy_protocol_name { use sc_network::ProtocolName; /// BEEFY votes gossip protocol name suffix. - const GOSSIP_NAME: &str = "/beefy/1"; + const GOSSIP_NAME: &str = "/beefy/2"; /// BEEFY justifications protocol name suffix. const JUSTIFICATIONS_NAME: &str = "/beefy/justifications/1"; @@ -86,7 +86,7 @@ mod tests { 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 expected_gossip_name = format!("/{}/beefy/2", genesis_hex); let gossip_proto_name = gossip_protocol_name(&genesis_hash, None); assert_eq!(gossip_proto_name.to_string(), expected_gossip_name); @@ -101,7 +101,7 @@ mod tests { ]; let genesis_hex = "32043c7b3a6ad8f6c2bc8bc121d4caab09377b5e082b0cfbbb39ad13bc4acd93"; - let expected_gossip_name = format!("/{}/beefy/1", genesis_hex); + let expected_gossip_name = format!("/{}/beefy/2", genesis_hex); let gossip_proto_name = gossip_protocol_name(&genesis_hash, None); assert_eq!(gossip_proto_name.to_string(), expected_gossip_name); diff --git a/client/consensus/beefy/src/justification.rs b/client/consensus/beefy/src/justification.rs index 1bd250b2a25f3..5175fd17d4ea3 100644 --- a/client/consensus/beefy/src/justification.rs +++ b/client/consensus/beefy/src/justification.rs @@ -21,13 +21,21 @@ use codec::{Decode, Encode}; use sp_consensus::Error as ConsensusError; use sp_consensus_beefy::{ crypto::{AuthorityId, Signature}, - ValidatorSet, VersionedFinalityProof, + ValidatorSet, ValidatorSetId, VersionedFinalityProof, }; use sp_runtime::traits::{Block as BlockT, NumberFor}; /// A finality proof with matching BEEFY authorities' signatures. -pub type BeefyVersionedFinalityProof = - sp_consensus_beefy::VersionedFinalityProof, Signature>; +pub type BeefyVersionedFinalityProof = VersionedFinalityProof, Signature>; + +pub(crate) fn proof_block_num_and_set_id( + proof: &BeefyVersionedFinalityProof, +) -> (NumberFor, ValidatorSetId) { + match proof { + VersionedFinalityProof::V1(sc) => + (sc.commitment.block_number, sc.commitment.validator_set_id), + } +} /// Decode and verify a Beefy FinalityProof. pub(crate) fn decode_and_verify_finality_proof( @@ -41,7 +49,7 @@ pub(crate) fn decode_and_verify_finality_proof( } /// Verify the Beefy finality proof against the validator set at the block it was generated. -fn verify_with_validator_set( +pub(crate) fn verify_with_validator_set( target_number: NumberFor, validator_set: &ValidatorSet, proof: &BeefyVersionedFinalityProof, diff --git a/client/consensus/beefy/src/lib.rs b/client/consensus/beefy/src/lib.rs index b84fa45e7e2f3..3c66cc6eb716d 100644 --- a/client/consensus/beefy/src/lib.rs +++ b/client/consensus/beefy/src/lib.rs @@ -288,7 +288,7 @@ pub async fn start_beefy_gadget( }; // Update the gossip validator with the right starting round and set id. if let Err(e) = persisted_state - .current_gossip_filter() + .gossip_filter_config() .map(|f| gossip_validator.update_filter(f)) { error!(target: LOG_TARGET, "Error: {:?}. Terminating.", e); diff --git a/client/consensus/beefy/src/round.rs b/client/consensus/beefy/src/round.rs index 64d03beeee854..d8948ff98c552 100644 --- a/client/consensus/beefy/src/round.rs +++ b/client/consensus/beefy/src/round.rs @@ -21,7 +21,7 @@ use crate::LOG_TARGET; use codec::{Decode, Encode}; use log::debug; use sp_consensus_beefy::{ - crypto::{AuthorityId, Public, Signature}, + crypto::{AuthorityId, Signature}, Commitment, EquivocationProof, SignedCommitment, ValidatorSet, ValidatorSetId, VoteMessage, }; use sp_runtime::traits::{Block, NumberFor}; @@ -33,11 +33,11 @@ use std::collections::BTreeMap; /// Does not do any validation on votes or signatures, layers above need to handle that (gossip). #[derive(Debug, Decode, Default, Encode, PartialEq)] pub(crate) struct RoundTracker { - votes: BTreeMap, + votes: BTreeMap, } impl RoundTracker { - fn add_vote(&mut self, vote: (Public, Signature)) -> bool { + fn add_vote(&mut self, vote: (AuthorityId, Signature)) -> bool { if self.votes.contains_key(&vote.0) { return false } @@ -61,7 +61,7 @@ pub fn threshold(authorities: usize) -> usize { pub enum VoteImportResult { Ok, RoundConcluded(SignedCommitment, Signature>), - Equivocation(EquivocationProof, Public, Signature>), + Equivocation(EquivocationProof, AuthorityId, Signature>), Invalid, Stale, } @@ -73,9 +73,10 @@ pub enum VoteImportResult { #[derive(Debug, Decode, Encode, PartialEq)] pub(crate) struct Rounds { rounds: BTreeMap>, RoundTracker>, - previous_votes: BTreeMap<(Public, NumberFor), VoteMessage, Public, Signature>>, + previous_votes: + BTreeMap<(AuthorityId, NumberFor), VoteMessage, AuthorityId, Signature>>, session_start: NumberFor, - validator_set: ValidatorSet, + validator_set: ValidatorSet, mandatory_done: bool, best_done: Option>, } @@ -84,7 +85,10 @@ impl Rounds where B: Block, { - pub(crate) fn new(session_start: NumberFor, validator_set: ValidatorSet) -> Self { + pub(crate) fn new( + session_start: NumberFor, + validator_set: ValidatorSet, + ) -> Self { Rounds { rounds: BTreeMap::new(), previous_votes: BTreeMap::new(), @@ -95,7 +99,7 @@ where } } - pub(crate) fn validator_set(&self) -> &ValidatorSet { + pub(crate) fn validator_set(&self) -> &ValidatorSet { &self.validator_set } @@ -103,7 +107,7 @@ where self.validator_set.id() } - pub(crate) fn validators(&self) -> &[Public] { + pub(crate) fn validators(&self) -> &[AuthorityId] { self.validator_set.validators() } @@ -199,11 +203,11 @@ mod tests { use sc_network_test::Block; use sp_consensus_beefy::{ - crypto::Public, known_payloads::MMR_ROOT_ID, Commitment, EquivocationProof, Keyring, - Payload, SignedCommitment, ValidatorSet, VoteMessage, + known_payloads::MMR_ROOT_ID, Commitment, EquivocationProof, Keyring, Payload, + SignedCommitment, ValidatorSet, VoteMessage, }; - use super::{threshold, Block as BlockT, RoundTracker, Rounds}; + use super::{threshold, AuthorityId, Block as BlockT, RoundTracker, Rounds}; use crate::round::VoteImportResult; impl Rounds @@ -251,7 +255,7 @@ mod tests { fn new_rounds() { sp_tracing::try_init_simple(); - let validators = ValidatorSet::::new( + let validators = ValidatorSet::::new( vec![Keyring::Alice.public(), Keyring::Bob.public(), Keyring::Charlie.public()], 42, ) @@ -272,7 +276,7 @@ mod tests { fn add_and_conclude_votes() { sp_tracing::try_init_simple(); - let validators = ValidatorSet::::new( + let validators = ValidatorSet::::new( vec![ Keyring::Alice.public(), Keyring::Bob.public(), @@ -338,7 +342,7 @@ mod tests { fn old_rounds_not_accepted() { sp_tracing::try_init_simple(); - let validators = ValidatorSet::::new( + let validators = ValidatorSet::::new( vec![Keyring::Alice.public(), Keyring::Bob.public(), Keyring::Charlie.public()], 42, ) @@ -384,7 +388,7 @@ mod tests { fn multiple_rounds() { sp_tracing::try_init_simple(); - let validators = ValidatorSet::::new( + let validators = ValidatorSet::::new( vec![Keyring::Alice.public(), Keyring::Bob.public(), Keyring::Charlie.public()], Default::default(), ) @@ -459,7 +463,7 @@ mod tests { fn should_provide_equivocation_proof() { sp_tracing::try_init_simple(); - let validators = ValidatorSet::::new( + let validators = ValidatorSet::::new( vec![Keyring::Alice.public(), Keyring::Bob.public()], Default::default(), ) diff --git a/client/consensus/beefy/src/tests.rs b/client/consensus/beefy/src/tests.rs index 0ad5f10886093..f36c2cd68f97f 100644 --- a/client/consensus/beefy/src/tests.rs +++ b/client/consensus/beefy/src/tests.rs @@ -21,15 +21,18 @@ use crate::{ aux_schema::{load_persistent, tests::verify_persisted_version}, beefy_block_import_and_links, - communication::request_response::{ - on_demand_justifications_protocol_config, BeefyJustifsRequestHandler, + communication::{ + gossip::{ + proofs_topic, tests::sign_commitment, votes_topic, GossipFilterCfg, GossipMessage, + }, + request_response::{on_demand_justifications_protocol_config, BeefyJustifsRequestHandler}, }, gossip_protocol_name, justification::*, load_or_init_voter_state, wait_for_runtime_pallet, BeefyRPCLinks, BeefyVoterLinks, KnownPeers, PersistedState, }; -use futures::{future, stream::FuturesUnordered, Future, StreamExt}; +use futures::{future, stream::FuturesUnordered, Future, FutureExt, StreamExt}; use parking_lot::Mutex; use sc_client_api::{Backend as BackendT, BlockchainEvents, FinalityNotifications, HeaderBackend}; use sc_consensus::{ @@ -48,16 +51,16 @@ use sp_consensus::BlockOrigin; use sp_consensus_beefy::{ crypto::{AuthorityId, Signature}, known_payloads, - mmr::MmrRootProvider, + mmr::{find_mmr_root_digest, MmrRootProvider}, BeefyApi, Commitment, ConsensusLog, EquivocationProof, Keyring as BeefyKeyring, MmrRootHash, OpaqueKeyOwnershipProof, Payload, SignedCommitment, ValidatorSet, ValidatorSetId, - VersionedFinalityProof, BEEFY_ENGINE_ID, KEY_TYPE as BeefyKeyType, + VersionedFinalityProof, VoteMessage, BEEFY_ENGINE_ID, KEY_TYPE as BeefyKeyType, }; use sp_core::H256; use sp_keystore::{testing::MemoryKeystore, Keystore, KeystorePtr}; use sp_mmr_primitives::{Error as MmrError, MmrApi}; use sp_runtime::{ - codec::Encode, + codec::{Decode, Encode}, traits::{Header as HeaderT, NumberFor}, BuildStorage, DigestItem, EncodedJustification, Justifications, Storage, }; @@ -503,16 +506,15 @@ async fn wait_for_beefy_signed_commitments( run_until(wait_for, net).await; } -async fn streams_empty_after_timeout( +async fn streams_empty_after_future( streams: Vec>, - net: &Arc>, - timeout: Option, + future: Option, ) where T: std::fmt::Debug, T: std::cmp::PartialEq, { - if let Some(timeout) = timeout { - run_for(timeout, net).await; + if let Some(future) = future { + future.await; } for mut stream in streams.into_iter() { future::poll_fn(move |cx| { @@ -523,6 +525,18 @@ async fn streams_empty_after_timeout( } } +async fn streams_empty_after_timeout( + streams: Vec>, + net: &Arc>, + timeout: Option, +) where + T: std::fmt::Debug, + T: std::cmp::PartialEq, +{ + let timeout = timeout.map(|timeout| Box::pin(run_for(timeout, net))); + streams_empty_after_future(streams, timeout).await; +} + async fn finalize_block_and_wait_for_beefy( net: &Arc>, // peer index and key @@ -1229,3 +1243,143 @@ async fn beefy_reports_equivocations() { assert_eq!(equivocation_proof.first.id, BeefyKeyring::Bob.public()); assert_eq!(equivocation_proof.first.commitment.block_number, 1); } + +#[tokio::test] +async fn gossipped_finality_proofs() { + sp_tracing::try_init_simple(); + + let validators = [BeefyKeyring::Alice, BeefyKeyring::Bob, BeefyKeyring::Charlie]; + // Only Alice and Bob are running the voter -> finality threshold not reached + let peers = [BeefyKeyring::Alice, BeefyKeyring::Bob]; + let validator_set = ValidatorSet::new(make_beefy_ids(&validators), 0).unwrap(); + let session_len = 30; + let min_block_delta = 1; + + let mut net = BeefyTestNet::new(3); + let api = Arc::new(TestApi::with_validator_set(&validator_set)); + let beefy_peers = peers.iter().enumerate().map(|(id, key)| (id, key, api.clone())).collect(); + + let charlie = &net.peers[2]; + let known_peers = Arc::new(Mutex::new(KnownPeers::::new())); + // Charlie will run just the gossip engine and not the full voter. + let charlie_gossip_validator = + Arc::new(crate::communication::gossip::GossipValidator::new(known_peers)); + charlie_gossip_validator.update_filter(GossipFilterCfg:: { + start: 1, + end: 10, + validator_set: &validator_set, + }); + let mut charlie_gossip_engine = sc_network_gossip::GossipEngine::new( + charlie.network_service().clone(), + charlie.sync_service().clone(), + beefy_gossip_proto_name(), + charlie_gossip_validator.clone(), + None, + ); + + // Alice and Bob run full voter. + tokio::spawn(initialize_beefy(&mut net, beefy_peers, min_block_delta)); + + let net = Arc::new(Mutex::new(net)); + + // Pump net + Charlie gossip to see peers. + let timeout = Box::pin(tokio::time::sleep(Duration::from_millis(200))); + let gossip_engine_pump = &mut charlie_gossip_engine; + let pump_with_timeout = future::select(gossip_engine_pump, timeout); + run_until(pump_with_timeout, &net).await; + + // push 10 blocks + let hashes = net.lock().generate_blocks_and_sync(10, session_len, &validator_set, true).await; + + let peers = peers.into_iter().enumerate(); + + // Alice, Bob and Charlie finalize #1, Alice and Bob vote on it, but not Charlie. + let finalize = hashes[1]; + 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(1).client().as_client().finalize_block(finalize, None).unwrap(); + net.lock().peer(2).client().as_client().finalize_block(finalize, None).unwrap(); + // verify nothing gets finalized by BEEFY + let timeout = Box::pin(tokio::time::sleep(Duration::from_millis(100))); + let pump_net = futures::future::poll_fn(|cx| { + net.lock().poll(cx); + Poll::<()>::Pending + }); + let pump_gossip = &mut charlie_gossip_engine; + let pump_with_timeout = future::select(pump_gossip, future::select(pump_net, timeout)); + streams_empty_after_future(best_blocks, Some(pump_with_timeout)).await; + streams_empty_after_timeout(versioned_finality_proof, &net, None).await; + + let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), peers.clone()); + // Charlie gossips finality proof for #1 -> Alice and Bob also finalize. + let proof = crate::communication::gossip::tests::dummy_proof(1, &validator_set); + let gossip_proof = GossipMessage::::FinalityProof(proof); + let encoded_proof = gossip_proof.encode(); + charlie_gossip_engine.gossip_message(proofs_topic::(), encoded_proof, true); + // Expect #1 is finalized. + wait_for_best_beefy_blocks(best_blocks, &net, &[1]).await; + wait_for_beefy_signed_commitments(versioned_finality_proof, &net, &[1]).await; + + // Code above verifies gossipped finality proofs are correctly imported and consumed by voters. + // Next, let's verify finality proofs are correctly generated and gossipped by voters. + + // Everyone finalizes #2 + let block_number = 2u64; + let finalize = hashes[block_number as usize]; + 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(1).client().as_client().finalize_block(finalize, None).unwrap(); + net.lock().peer(2).client().as_client().finalize_block(finalize, None).unwrap(); + + // Simulate Charlie vote on #2 + let header = net.lock().peer(2).client().as_client().expect_header(finalize).unwrap(); + let mmr_root = find_mmr_root_digest::(&header).unwrap(); + let payload = Payload::from_single_entry(known_payloads::MMR_ROOT_ID, mmr_root.encode()); + let commitment = Commitment { payload, block_number, validator_set_id: validator_set.id() }; + let signature = sign_commitment(&BeefyKeyring::Charlie, &commitment); + let vote_message = VoteMessage { commitment, id: BeefyKeyring::Charlie.public(), signature }; + let encoded_vote = GossipMessage::::Vote(vote_message).encode(); + charlie_gossip_engine.gossip_message(votes_topic::(), encoded_vote, true); + + // Expect #2 is finalized. + wait_for_best_beefy_blocks(best_blocks, &net, &[2]).await; + wait_for_beefy_signed_commitments(versioned_finality_proof, &net, &[2]).await; + + // Now verify Charlie also sees the gossipped proof generated by either Alice or Bob. + let mut charlie_gossip_proofs = Box::pin( + charlie_gossip_engine + .messages_for(proofs_topic::()) + .filter_map(|notification| async move { + GossipMessage::::decode(&mut ¬ification.message[..]).ok().and_then( + |message| match message { + GossipMessage::::Vote(_) => unreachable!(), + GossipMessage::::FinalityProof(proof) => Some(proof), + }, + ) + }) + .fuse(), + ); + loop { + let pump_net = futures::future::poll_fn(|cx| { + net.lock().poll(cx); + Poll::<()>::Pending + }); + let mut gossip_engine = &mut charlie_gossip_engine; + futures::select! { + // pump gossip engine + _ = gossip_engine => unreachable!(), + // pump network + _ = pump_net.fuse() => unreachable!(), + // verify finality proof has been gossipped + proof = charlie_gossip_proofs.next() => { + let proof = proof.unwrap(); + let (round, _) = proof_block_num_and_set_id::(&proof); + match round { + 1 => continue, // finality proof generated by Charlie in the previous round + 2 => break, // finality proof generated by Alice or Bob and gossiped to Charlie + _ => panic!("Charlie got unexpected finality proof"), + } + }, + } + } +} diff --git a/client/consensus/beefy/src/worker.rs b/client/consensus/beefy/src/worker.rs index 0260d7693c654..19225ec214578 100644 --- a/client/consensus/beefy/src/worker.rs +++ b/client/consensus/beefy/src/worker.rs @@ -18,7 +18,7 @@ use crate::{ communication::{ - gossip::{topic, GossipValidator, GossipVoteFilter}, + gossip::{proofs_topic, votes_topic, GossipFilterCfg, GossipMessage, GossipValidator}, request_response::outgoing_requests_engine::OnDemandJustificationsEngine, }, error::Error, @@ -42,7 +42,7 @@ use sp_consensus_beefy::{ check_equivocation_proof, crypto::{AuthorityId, Signature}, BeefyApi, Commitment, ConsensusLog, EquivocationProof, PayloadProvider, ValidatorSet, - ValidatorSetId, VersionedFinalityProof, VoteMessage, BEEFY_ENGINE_ID, + VersionedFinalityProof, VoteMessage, BEEFY_ENGINE_ID, }; use sp_runtime::{ generic::OpaqueDigestItemId, @@ -158,8 +158,8 @@ impl VoterOracle { self.sessions.front_mut().ok_or(Error::UninitSession) } - fn current_validator_set_id(&self) -> Result { - self.active_rounds().map(|r| r.validator_set_id()) + fn current_validator_set(&self) -> Result<&ValidatorSet, Error> { + self.active_rounds().map(|r| r.validator_set()) } // Prune the sessions queue to keep the Oracle in one of the expected three states. @@ -301,10 +301,10 @@ impl PersistedState { self.voting_oracle.best_grandpa_block_header = best_grandpa; } - pub(crate) fn current_gossip_filter(&self) -> Result, Error> { + pub(crate) fn gossip_filter_config(&self) -> Result, Error> { let (start, end) = self.voting_oracle.accepted_interval()?; - let validator_set_id = self.voting_oracle.current_validator_set_id()?; - Ok(GossipVoteFilter { start, end, validator_set_id }) + let validator_set = self.voting_oracle.current_validator_set()?; + Ok(GossipFilterCfg { start, end, validator_set }) } } @@ -494,7 +494,7 @@ where // Update gossip validator votes filter. if let Err(e) = self .persisted_state - .current_gossip_filter() + .gossip_filter_config() .map(|filter| self.gossip_validator.update_filter(filter)) { error!(target: LOG_TARGET, "🥩 Voter error: {:?}", e); @@ -509,7 +509,12 @@ where ) -> Result<(), Error> { let block_num = vote.commitment.block_number; match self.voting_oracle().triage_round(block_num)? { - RoundAction::Process => self.handle_vote(vote)?, + RoundAction::Process => + if let Some(finality_proof) = self.handle_vote(vote)? { + let gossip_proof = GossipMessage::::FinalityProof(finality_proof); + let encoded_proof = gossip_proof.encode(); + self.gossip_engine.gossip_message(proofs_topic::(), encoded_proof, true); + }, RoundAction::Drop => metric_inc!(self, beefy_stale_votes), RoundAction::Enqueue => error!(target: LOG_TARGET, "🥩 unexpected vote: {:?}.", vote), }; @@ -554,7 +559,7 @@ where fn handle_vote( &mut self, vote: VoteMessage, AuthorityId, Signature>, - ) -> Result<(), Error> { + ) -> Result>, Error> { let rounds = self.persisted_state.voting_oracle.active_rounds_mut()?; let block_number = vote.commitment.block_number; @@ -567,8 +572,9 @@ where ); // We created the `finality_proof` and know to be valid. // New state is persisted after finalization. - self.finalize(finality_proof)?; + self.finalize(finality_proof.clone())?; metric_inc!(self, beefy_good_votes_processed); + return Ok(Some(finality_proof)) }, VoteImportResult::Ok => { // Persist state after handling mandatory block vote. @@ -590,7 +596,7 @@ where VoteImportResult::Invalid => metric_inc!(self, beefy_invalid_votes), VoteImportResult::Stale => metric_inc!(self, beefy_stale_votes), }; - Ok(()) + Ok(None) } /// Provide BEEFY finality for block based on `finality_proof`: @@ -643,7 +649,7 @@ where // Update gossip validator votes filter. self.persisted_state - .current_gossip_filter() + .gossip_filter_config() .map(|filter| self.gossip_validator.update_filter(filter))?; Ok(()) } @@ -758,20 +764,20 @@ where 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: LOG_TARGET, "🥩 Sent vote message: {:?}", message); - - if let Err(err) = self.handle_vote(message) { + let vote = VoteMessage { commitment, id: authority_id, signature }; + if let Some(finality_proof) = self.handle_vote(vote.clone()).map_err(|err| { error!(target: LOG_TARGET, "🥩 Error handling self vote: {}", err); + err + })? { + let encoded_proof = GossipMessage::::FinalityProof(finality_proof).encode(); + self.gossip_engine.gossip_message(proofs_topic::(), encoded_proof, true); + } else { + metric_inc!(self, beefy_votes_sent); + debug!(target: LOG_TARGET, "🥩 Sent vote message: {:?}", vote); + let encoded_vote = GossipMessage::::Vote(vote).encode(); + self.gossip_engine.gossip_message(votes_topic::(), encoded_vote, false); } - self.gossip_engine.gossip_message(topic::(), encoded_message, false); - // Persist state after vote to avoid double voting in case of voter restarts. self.persisted_state.best_voted = target_number; metric_set!(self, beefy_best_voted, target_number); @@ -816,17 +822,28 @@ where let mut votes = Box::pin( self.gossip_engine - .messages_for(topic::()) + .messages_for(votes_topic::()) .filter_map(|notification| async move { - let vote = VoteMessage::, AuthorityId, Signature>::decode( - &mut ¬ification.message[..], - ) - .ok(); + let vote = GossipMessage::::decode(&mut ¬ification.message[..]) + .ok() + .and_then(|message| message.unwrap_vote()); trace!(target: LOG_TARGET, "🥩 Got vote message: {:?}", vote); vote }) .fuse(), ); + let mut gossip_proofs = Box::pin( + self.gossip_engine + .messages_for(proofs_topic::()) + .filter_map(|notification| async move { + let proof = GossipMessage::::decode(&mut ¬ification.message[..]) + .ok() + .and_then(|message| message.unwrap_finality_proof()); + trace!(target: LOG_TARGET, "🥩 Got gossip proof message: {:?}", proof); + proof + }) + .fuse(), + ); loop { // Act on changed 'state'. @@ -872,6 +889,20 @@ where return; } }, + justif = gossip_proofs.next() => { + if let Some(justif) = justif { + // Gossiped justifications have already been verified by `GossipValidator`. + if let Err(err) = self.triage_incoming_justif(justif) { + debug!(target: LOG_TARGET, "🥩 {}", err); + } + } else { + error!( + target: LOG_TARGET, + "🥩 Finality proofs gossiping stream terminated, closing worker." + ); + return; + } + }, // Finally process incoming votes. vote = votes.next() => { if let Some(vote) = vote { @@ -880,7 +911,10 @@ where debug!(target: LOG_TARGET, "🥩 {}", err); } } else { - error!(target: LOG_TARGET, "🥩 Votes gossiping stream terminated, closing worker."); + error!( + target: LOG_TARGET, + "🥩 Votes gossiping stream terminated, closing worker." + ); return; } }, From 4c7866a0df02e1c45fb4b5f473b2265a6bdb5465 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Thu, 30 Mar 2023 16:50:45 +0200 Subject: [PATCH 595/715] Fix nomiantion pools doc render (#13748) Co-authored-by: parity-processbot <> --- frame/nomination-pools/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/nomination-pools/src/lib.rs b/frame/nomination-pools/src/lib.rs index cfde05ffeeabe..e7c99e023289b 100644 --- a/frame/nomination-pools/src/lib.rs +++ b/frame/nomination-pools/src/lib.rs @@ -133,7 +133,7 @@ //! * Root: can change the nominator, bouncer, or itself, manage and claim commission, and can //! perform any of the actions the nominator or bouncer can. //! -//! ## Commission +//! ### Commission //! //! A pool can optionally have a commission configuration, via the `root` role, set with //! [`Call::set_commission`] and claimed with [`Call::claim_commission`]. A payee account must be From ee38a52d9ea643e4eec1e954b0b603aea4461416 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Thu, 30 Mar 2023 21:31:08 +0200 Subject: [PATCH 596/715] sp-runtime-interface-test: Fix flaky test (#13770) --- primitives/runtime-interface/test/src/lib.rs | 105 +++++++++++-------- 1 file changed, 64 insertions(+), 41 deletions(-) diff --git a/primitives/runtime-interface/test/src/lib.rs b/primitives/runtime-interface/test/src/lib.rs index d691d4846c330..269b62333bd26 100644 --- a/primitives/runtime-interface/test/src/lib.rs +++ b/primitives/runtime-interface/test/src/lib.rs @@ -176,62 +176,85 @@ fn test_versionining_register_only() { call_wasm_method::(wasm_binary_unwrap(), "test_versionning_register_only_works"); } +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 test_tracing() { - use std::fmt; - use tracing::span::Id as SpanId; - use tracing_core::field::{Field, Visit}; - - #[derive(Clone)] - struct TracingSubscriber(Arc>); - - struct FieldConsumer(&'static str, Option); - impl Visit for FieldConsumer { - fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) { - if field.name() == self.0 { - self.1 = Some(format!("{:?}", value)) + // Run in a different process to ensure that the `Span` is registered with our local + // `TracingSubscriber`. + run_test_in_another_process("test_tracing", || { + use std::fmt; + use tracing::span::Id as SpanId; + use tracing_core::field::{Field, Visit}; + + #[derive(Clone)] + struct TracingSubscriber(Arc>); + + struct FieldConsumer(&'static str, Option); + impl Visit for FieldConsumer { + fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) { + if field.name() == self.0 { + self.1 = Some(format!("{:?}", value)) + } } } - } - #[derive(Default)] - struct Inner { - spans: HashSet, - } - - impl tracing::subscriber::Subscriber for TracingSubscriber { - fn enabled(&self, _: &tracing::Metadata) -> bool { - true + #[derive(Default)] + struct Inner { + spans: HashSet, } - fn new_span(&self, span: &tracing::span::Attributes) -> tracing::Id { - let mut inner = self.0.lock().unwrap(); - let id = SpanId::from_u64((inner.spans.len() + 1) as _); - let mut f = FieldConsumer("name", None); - span.record(&mut f); - inner.spans.insert(f.1.unwrap_or_else(|| span.metadata().name().to_owned())); - id - } + impl tracing::subscriber::Subscriber for TracingSubscriber { + fn enabled(&self, _: &tracing::Metadata) -> bool { + true + } - fn record(&self, _: &SpanId, _: &tracing::span::Record) {} + fn new_span(&self, span: &tracing::span::Attributes) -> tracing::Id { + let mut inner = self.0.lock().unwrap(); + let id = SpanId::from_u64((inner.spans.len() + 1) as _); + let mut f = FieldConsumer("name", None); + span.record(&mut f); + inner.spans.insert(f.1.unwrap_or_else(|| span.metadata().name().to_owned())); + id + } - fn record_follows_from(&self, _: &SpanId, _: &SpanId) {} + fn record(&self, _: &SpanId, _: &tracing::span::Record) {} - fn event(&self, _: &tracing::Event) {} + fn record_follows_from(&self, _: &SpanId, _: &SpanId) {} - fn enter(&self, _: &SpanId) {} + fn event(&self, _: &tracing::Event) {} - fn exit(&self, _: &SpanId) {} - } + fn enter(&self, _: &SpanId) {} - let subscriber = TracingSubscriber(Default::default()); - let _guard = tracing::subscriber::set_default(subscriber.clone()); + fn exit(&self, _: &SpanId) {} + } - // Call some method to generate a trace - call_wasm_method::(wasm_binary_unwrap(), "test_return_data"); + let subscriber = TracingSubscriber(Default::default()); + let _guard = tracing::subscriber::set_default(subscriber.clone()); + + // Call some method to generate a trace + call_wasm_method::(wasm_binary_unwrap(), "test_return_data"); - let inner = subscriber.0.lock().unwrap(); - assert!(inner.spans.contains("return_input_version_1")); + let inner = subscriber.0.lock().unwrap(); + assert!(inner.spans.contains("return_input_version_1")); + }); } #[test] From 4bf67fb3dc0f095e4210b5ebc5f1f2ea24bf36c0 Mon Sep 17 00:00:00 2001 From: Javier Viola Date: Thu, 30 Mar 2023 18:01:50 -0300 Subject: [PATCH 597/715] bump zombienet version (#13772) --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index c9b68bca1ea09..470ce2ce3180e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -56,7 +56,7 @@ variables: RUSTY_CACHIER_COMPRESSION_METHOD: zstd NEXTEST_FAILURE_OUTPUT: immediate-final NEXTEST_SUCCESS_OUTPUT: final - ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.3.37" + ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.3.43" .shared-default: &shared-default retry: From de4cca40b5da41e76c111c66229521f1052ea298 Mon Sep 17 00:00:00 2001 From: PG Herveou Date: Fri, 31 Mar 2023 13:03:56 +0200 Subject: [PATCH 598/715] [Contracts] Overflowing bounded `DeletionQueue` allows DoS against contract termination (#13702) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [Contracts review] Overflowing bounded `DeletionQueue` allows DoS against contract termination * wip * wip * wip * wip * wip * fix doc * wip * PR review * unbreak tests * fixes * update budget computation * PR comment: use BlockWeights::get().max_block * PR comment: Update queue_trie_for_deletion signature * PR comment: update deletion budget docstring * PR comment: impl Default with derive(DefaultNoBound) * PR comment: Remove DeletedContract * PR comment Add ring_buffer test * remove missed comment * misc comments * contracts: add sr25519_recover * Revert "contracts: add sr25519_recover" This reverts commit d4600e00934b90e5882cf5288f36f98911b51722. * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_contracts * PR comments update print_schedule * Update frame/contracts/src/benchmarking/mod.rs * Update frame/contracts/src/storage.rs * Update frame/contracts/src/storage.rs * rm temporary fixes * fix extra ; * Update frame/contracts/src/storage.rs Co-authored-by: juangirini * Update frame/contracts/src/storage.rs Co-authored-by: Alexander Theißen * Update frame/contracts/src/lib.rs Co-authored-by: Alexander Theißen * Update frame/contracts/src/lib.rs Co-authored-by: Alexander Theißen * Support stable rust for compiling the runtime (#13580) * Support stable rust for compiling the runtime This pull request brings support for compiling the runtime with stable Rust. This requires at least rust 1.68.0 to work on stable. The code is written in a way that it is backwards compatible and should automatically work when someone compiles with 1.68.0+ stable. * We always support nightlies! * :facepalm: * Sort by version * Review feedback * Review feedback * Fix version parsing * Apply suggestions from code review Co-authored-by: Koute --------- Co-authored-by: Koute * github PR commit fixes * Revert "Support stable rust for compiling the runtime (#13580)" This reverts commit 0b985aa5ad114a42003519b712d25a6acc40b0ad. * Restore DeletionQueueMap * fix namings * PR comment * move comments * Update frame/contracts/src/storage.rs * Update frame/contracts/src/storage.rs * fixes --------- Co-authored-by: command-bot <> Co-authored-by: juangirini Co-authored-by: Alexander Theißen Co-authored-by: Bastian Köcher Co-authored-by: Koute --- bin/node/runtime/src/lib.rs | 9 - frame/contracts/src/benchmarking/mod.rs | 26 +- frame/contracts/src/exec.rs | 2 +- frame/contracts/src/lib.rs | 65 +- frame/contracts/src/storage.rs | 154 +- frame/contracts/src/tests.rs | 153 +- frame/contracts/src/weights.rs | 1885 +++++++++++------------ 7 files changed, 1118 insertions(+), 1176 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 48bea5ddc101f..5562dc263ddc8 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1198,13 +1198,6 @@ impl pallet_tips::Config for Runtime { parameter_types! { pub const DepositPerItem: Balance = deposit(1, 0); pub const DepositPerByte: Balance = deposit(0, 1); - 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); pub Schedule: pallet_contracts::Schedule = Default::default(); } @@ -1227,8 +1220,6 @@ impl pallet_contracts::Config for Runtime { type WeightPrice = pallet_transaction_payment::Pallet; type WeightInfo = pallet_contracts::weights::SubstrateWeight; type ChainExtension = (); - type DeletionQueueDepth = DeletionQueueDepth; - type DeletionWeightLimit = DeletionWeightLimit; type Schedule = Schedule; type AddressGenerator = pallet_contracts::DefaultAddressGenerator; type MaxCodeLen = ConstU32<{ 123 * 1024 }>; diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index 5494b57b65a2a..1bb6f3395fcef 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -214,19 +214,7 @@ benchmarks! { on_initialize_per_trie_key { let k in 0..1024; let instance = Contract::::with_storage(WasmModule::dummy(), k, T::Schedule::get().limits.payload_len)?; - instance.info()?.queue_trie_for_deletion()?; - }: { - ContractInfo::::process_deletion_queue_batch(Weight::MAX) - } - - #[pov_mode = Measured] - on_initialize_per_queue_item { - let q in 0..1024.min(T::DeletionQueueDepth::get()); - for i in 0 .. q { - let instance = Contract::::with_index(i, WasmModule::dummy(), vec![])?; - instance.info()?.queue_trie_for_deletion()?; - ContractInfoOf::::remove(instance.account_id); - } + instance.info()?.queue_trie_for_deletion(); }: { ContractInfo::::process_deletion_queue_batch(Weight::MAX) } @@ -3020,16 +3008,12 @@ benchmarks! { print_schedule { #[cfg(feature = "std")] { - let weight_limit = T::DeletionWeightLimit::get(); - let max_queue_depth = T::DeletionQueueDepth::get() as usize; - let empty_queue_throughput = ContractInfo::::deletion_budget(0, weight_limit); - let full_queue_throughput = ContractInfo::::deletion_budget(max_queue_depth, weight_limit); + let max_weight = ::BlockWeights::get().max_block; + let (weight_per_key, key_budget) = ContractInfo::::deletion_budget(max_weight); println!("{:#?}", Schedule::::default()); println!("###############################################"); - println!("Lazy deletion weight per key: {}", empty_queue_throughput.0); - println!("Lazy deletion throughput per block (empty queue, full queue): {}, {}", - empty_queue_throughput.1, full_queue_throughput.1, - ); + println!("Lazy deletion weight per key: {weight_per_key}"); + println!("Lazy deletion throughput per block: {key_budget}"); } #[cfg(not(feature = "std"))] Err("Run this bench with a native runtime in order to see the schedule.")?; diff --git a/frame/contracts/src/exec.rs b/frame/contracts/src/exec.rs index 51ea234f27376..03e1c4fd32585 100644 --- a/frame/contracts/src/exec.rs +++ b/frame/contracts/src/exec.rs @@ -1204,7 +1204,7 @@ where T::Currency::reducible_balance(&frame.account_id, Expendable, Polite), ExistenceRequirement::AllowDeath, )?; - info.queue_trie_for_deletion()?; + info.queue_trie_for_deletion(); ContractInfoOf::::remove(&frame.account_id); E::remove_user(info.code_hash); Contracts::::deposit_event( diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index cd4b7daa6da0f..dc93a7f06ff2d 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -102,7 +102,7 @@ mod tests; use crate::{ exec::{AccountIdOf, ErrorOrigin, ExecError, Executable, Key, Stack as ExecStack}, gas::GasMeter, - storage::{meter::Meter as StorageMeter, ContractInfo, DeletedContract}, + storage::{meter::Meter as StorageMeter, ContractInfo, DeletionQueueManager}, wasm::{OwnerInfo, PrefabWasmModule, TryInstantiate}, weights::WeightInfo, }; @@ -245,33 +245,6 @@ pub mod pallet { /// memory usage of your runtime. type CallStack: Array>; - /// 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; - /// The amount of balance a caller has to pay for each byte of storage. /// /// # Note @@ -329,25 +302,6 @@ pub mod pallet { .saturating_add(T::WeightInfo::on_process_deletion_queue_batch()) } - fn on_initialize(_block: T::BlockNumber) -> Weight { - // 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()); - ContractInfo::::process_deletion_queue_batch(weight_limit) - .saturating_add(T::WeightInfo::on_process_deletion_queue_batch()) - } else { - T::WeightInfo::on_process_deletion_queue_batch() - } - } - fn integrity_test() { // Total runtime memory is expected to have 128Mb upper limit const MAX_RUNTIME_MEM: u32 = 1024 * 1024 * 128; @@ -860,12 +814,6 @@ pub mod pallet { /// in this error. Note that this usually shouldn't happen as deploying such contracts /// is rejected. NoChainExtension, - /// Removal of a contract failed because the deletion queue is full. - /// - /// This can happen when calling `seal_terminate`. - /// 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 contract with the same AccountId already exists. DuplicateContract, /// A contract self destructed in its constructor. @@ -949,10 +897,15 @@ pub mod pallet { /// Evicted contracts that await child trie deletion. /// /// 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`. + /// stored in said trie. Therefore this operation is performed lazily in `on_idle`. + #[pallet::storage] + pub(crate) type DeletionQueue = StorageMap<_, Twox64Concat, u32, TrieId>; + + /// A pair of monotonic counters used to track the latest contract marked for deletion + /// and the latest deleted contract in queue. #[pallet::storage] - pub(crate) type DeletionQueue = - StorageValue<_, BoundedVec, ValueQuery>; + pub(crate) type DeletionQueueCounter = + StorageValue<_, DeletionQueueManager, ValueQuery>; } /// Context of a contract invocation. diff --git a/frame/contracts/src/storage.rs b/frame/contracts/src/storage.rs index 19c5f391d670b..769caef0736fe 100644 --- a/frame/contracts/src/storage.rs +++ b/frame/contracts/src/storage.rs @@ -22,15 +22,15 @@ pub mod meter; use crate::{ exec::{AccountIdOf, Key}, weights::WeightInfo, - AddressGenerator, BalanceOf, CodeHash, Config, ContractInfoOf, DeletionQueue, Error, Pallet, - TrieId, SENTINEL, + AddressGenerator, BalanceOf, CodeHash, Config, ContractInfoOf, DeletionQueue, + DeletionQueueCounter, Error, Pallet, TrieId, SENTINEL, }; use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ - dispatch::{DispatchError, DispatchResult}, + dispatch::DispatchError, storage::child::{self, ChildInfo}, weights::Weight, - RuntimeDebugNoBound, + DefaultNoBound, RuntimeDebugNoBound, }; use scale_info::TypeInfo; use sp_io::KillStorageResult; @@ -38,7 +38,7 @@ use sp_runtime::{ traits::{Hash, Saturating, Zero}, RuntimeDebug, }; -use sp_std::{ops::Deref, prelude::*}; +use sp_std::{marker::PhantomData, ops::Deref, prelude::*}; /// Information for managing an account and its sub trie abstraction. /// This is the required info to cache for an account. @@ -204,27 +204,21 @@ impl ContractInfo { /// Push a contract's trie to the deletion queue for lazy removal. /// /// You must make sure that the contract is also removed when queuing the trie for deletion. - pub fn queue_trie_for_deletion(&self) -> DispatchResult { - >::try_append(DeletedContract { trie_id: self.trie_id.clone() }) - .map_err(|_| >::DeletionQueueFull.into()) + pub fn queue_trie_for_deletion(&self) { + DeletionQueueManager::::load().insert(self.trie_id.clone()); } /// Calculates the weight that is necessary to remove one key from the trie and how many - /// 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) -> (Weight, u32) { + /// of those keys can be deleted from the deletion queue given the supplied weight limit. + pub fn deletion_budget(weight_limit: Weight) -> (Weight, u32) { 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 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. let key_budget = weight_limit .saturating_sub(base_weight) - .saturating_sub(decoding_weight) .checked_div_per_component(&weight_per_key) .unwrap_or(0) as u32; @@ -235,13 +229,13 @@ impl ContractInfo { /// /// It returns the amount of weight used for that task. pub fn process_deletion_queue_batch(weight_limit: Weight) -> Weight { - let queue_len = >::decode_len().unwrap_or(0); - if queue_len == 0 { + let mut queue = >::load(); + + if queue.is_empty() { return Weight::zero() } - let (weight_per_key, mut remaining_key_budget) = - Self::deletion_budget(queue_len, weight_limit); + let (weight_per_key, mut remaining_key_budget) = Self::deletion_budget(weight_limit); // We want to check whether we have enough weight to decode the queue before // proceeding. Too little weight for decoding might happen during runtime upgrades @@ -250,30 +244,25 @@ impl ContractInfo { return weight_limit } - let mut queue = >::get(); + while remaining_key_budget > 0 { + let Some(entry) = queue.next() else { break }; - while !queue.is_empty() && remaining_key_budget > 0 { - // Cannot panic due to loop condition - let trie = &mut queue[0]; #[allow(deprecated)] let outcome = child::kill_storage( - &ChildInfo::new_default(&trie.trie_id), + &ChildInfo::new_default(&entry.trie_id), Some(remaining_key_budget), ); - let keys_removed = match outcome { + + match outcome { // This happens when our budget wasn't large enough to remove all keys. - 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); - c + KillStorageResult::SomeRemaining(_) => return weight_limit, + KillStorageResult::AllRemoved(keys_removed) => { + entry.remove(); + remaining_key_budget = remaining_key_budget.saturating_sub(keys_removed); }, }; - remaining_key_budget = remaining_key_budget.saturating_sub(keys_removed); } - >::put(queue); weight_limit.saturating_sub(weight_per_key.saturating_mul(u64::from(remaining_key_budget))) } @@ -281,25 +270,9 @@ impl ContractInfo { pub fn load_code_hash(account: &AccountIdOf) -> Option> { >::get(account).map(|i| i.code_hash) } - - /// Fill up the queue in order to exercise the limits during testing. - #[cfg(test)] - pub fn fill_queue_with_dummies() { - use frame_support::{traits::Get, BoundedVec}; - let queue: Vec = (0..T::DeletionQueueDepth::get()) - .map(|_| DeletedContract { trie_id: TrieId::default() }) - .collect(); - let bounded: BoundedVec<_, _> = queue.try_into().map_err(|_| ()).unwrap(); - >::put(bounded); - } } -#[derive(Encode, Decode, TypeInfo, MaxEncodedLen)] -pub struct DeletedContract { - pub(crate) trie_id: TrieId, -} - -/// Information about what happended to the pre-existing value when calling [`ContractInfo::write`]. +/// Information about what happened to the pre-existing value when calling [`ContractInfo::write`]. #[cfg_attr(test, derive(Debug, PartialEq))] pub enum WriteOutcome { /// No value existed at the specified key. @@ -352,3 +325,84 @@ impl Deref for DepositAccount { &self.0 } } + +/// Manage the removal of contracts storage that are marked 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 by pulling the contract from the queue in the `on_idle` hook. +#[derive(Encode, Decode, TypeInfo, MaxEncodedLen, DefaultNoBound, Clone)] +#[scale_info(skip_type_params(T))] +pub struct DeletionQueueManager { + /// Counter used as a key for inserting a new deleted contract in the queue. + /// The counter is incremented after each insertion. + insert_counter: u32, + /// The index used to read the next element to be deleted in the queue. + /// The counter is incremented after each deletion. + delete_counter: u32, + + _phantom: PhantomData, +} + +/// View on a contract that is marked for deletion. +struct DeletionQueueEntry<'a, T: Config> { + /// the trie id of the contract to delete. + trie_id: TrieId, + + /// A mutable reference on the queue so that the contract can be removed, and none can be added + /// or read in the meantime. + queue: &'a mut DeletionQueueManager, +} + +impl<'a, T: Config> DeletionQueueEntry<'a, T> { + /// Remove the contract from the deletion queue. + fn remove(self) { + >::remove(self.queue.delete_counter); + self.queue.delete_counter = self.queue.delete_counter.wrapping_add(1); + >::set(self.queue.clone()); + } +} + +impl DeletionQueueManager { + /// Load the `DeletionQueueCounter`, so we can perform read or write operations on the + /// DeletionQueue storage. + fn load() -> Self { + >::get() + } + + /// Returns `true` if the queue contains no elements. + fn is_empty(&self) -> bool { + self.insert_counter.wrapping_sub(self.delete_counter) == 0 + } + + /// Insert a contract in the deletion queue. + fn insert(&mut self, trie_id: TrieId) { + >::insert(self.insert_counter, trie_id); + self.insert_counter = self.insert_counter.wrapping_add(1); + >::set(self.clone()); + } + + /// Fetch the next contract to be deleted. + /// + /// Note: + /// we use the delete counter to get the next value to read from the queue and thus don't pay + /// the cost of an extra call to `sp_io::storage::next_key` to lookup the next entry in the map + fn next(&mut self) -> Option> { + if self.is_empty() { + return None + } + + let entry = >::get(self.delete_counter); + entry.map(|trie_id| DeletionQueueEntry { trie_id, queue: self }) + } +} + +#[cfg(test)] +impl DeletionQueueManager { + pub fn from_test_values(insert_counter: u32, delete_counter: u32) -> Self { + Self { insert_counter, delete_counter, _phantom: Default::default() } + } + pub fn as_test_tuple(&self) -> (u32, u32) { + (self.insert_counter, self.delete_counter) + } +} diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index 146e5fd24ad07..beaec458e36f7 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -22,26 +22,27 @@ use crate::{ Result as ExtensionResult, RetVal, ReturnFlags, SysConfig, }, exec::{Frame, Key}, + storage::DeletionQueueManager, tests::test_utils::{get_contract, get_contract_checked}, wasm::{Determinism, PrefabWasmModule, ReturnCode as RuntimeReturnCode}, weights::WeightInfo, BalanceOf, Code, CodeStorage, Config, ContractInfo, ContractInfoOf, DefaultAddressGenerator, - DeletionQueue, Error, Pallet, Schedule, + DeletionQueueCounter, Error, Pallet, Schedule, }; use assert_matches::assert_matches; use codec::Encode; use frame_support::{ assert_err, assert_err_ignore_postinfo, assert_noop, assert_ok, - dispatch::{DispatchClass, DispatchErrorWithPostInfo, PostDispatchInfo}, + dispatch::{DispatchErrorWithPostInfo, PostDispatchInfo}, parameter_types, storage::child, traits::{ - ConstU32, ConstU64, Contains, Currency, ExistenceRequirement, Get, LockableCurrency, - OnIdle, OnInitialize, WithdrawReasons, + ConstU32, ConstU64, Contains, Currency, ExistenceRequirement, LockableCurrency, OnIdle, + OnInitialize, WithdrawReasons, }, weights::{constants::WEIGHT_REF_TIME_PER_SECOND, Weight}, }; -use frame_system::{self as system, EventRecord, Phase}; +use frame_system::{EventRecord, Phase}; use pretty_assertions::{assert_eq, assert_ne}; use sp_io::hashing::blake2_256; use sp_keystore::{testing::MemoryKeystore, KeystoreExt}; @@ -383,7 +384,6 @@ impl Contains for TestFilter { } parameter_types! { - pub const DeletionWeightLimit: Weight = GAS_LIMIT; pub static UnstableInterface: bool = true; } @@ -399,8 +399,6 @@ impl Config for Test { type WeightInfo = (); type ChainExtension = (TestExtension, DisabledExtension, RevertingExtension, TempStorageExtension); - type DeletionQueueDepth = ConstU32<1024>; - type DeletionWeightLimit = DeletionWeightLimit; type Schedule = MySchedule; type DepositPerByte = DepositPerByte; type DepositPerItem = DepositPerItem; @@ -1972,25 +1970,6 @@ fn lazy_removal_works() { }); } -#[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 - ContractInfo::::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(); @@ -2054,7 +2033,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 = Weight::from_parts(5_000_000_000, 0); - let (_, max_keys) = ContractInfo::::deletion_budget(1, weight_limit); + let (_, max_keys) = ContractInfo::::deletion_budget(weight_limit); let vals: Vec<_> = (0..max_keys + extra_keys) .map(|i| (blake2_256(&i.encode()), (i as u32), (i as u32).encode())) .collect(); @@ -2139,33 +2118,6 @@ fn lazy_removal_partial_remove_works() { }); } -#[test] -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 - ContractInfo::::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(); @@ -2209,7 +2161,7 @@ fn lazy_removal_does_no_run_on_low_remaining_weight() { // But value should be still there as the lazy removal did not run, yet. assert_matches!(child::get(trie, &[99]), Some(42)); - // Assign a remaining weight which is too low for a successfull deletion of the contract + // Assign a remaining weight which is too low for a successful deletion of the contract let low_remaining_weight = <::WeightInfo as WeightInfo>::on_process_deletion_queue_batch(); @@ -2259,7 +2211,7 @@ fn lazy_removal_does_not_use_all_weight() { .account_id; let info = get_contract(&addr); - let (weight_per_key, max_keys) = ContractInfo::::deletion_budget(1, weight_limit); + let (weight_per_key, max_keys) = ContractInfo::::deletion_budget(weight_limit); // We create a contract with one less storage item than we can remove within the limit let vals: Vec<_> = (0..max_keys - 1) @@ -2314,40 +2266,75 @@ fn lazy_removal_does_not_use_all_weight() { } #[test] -fn deletion_queue_full() { +fn deletion_queue_ring_buffer_overflow() { let (code, _hash) = compile_module::("self_destruct").unwrap(); - ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + let mut ext = ExtBuilder::default().existential_deposit(50).build(); + + // setup the deletion queue with custom counters + ext.execute_with(|| { + let queue = DeletionQueueManager::from_test_values(u32::MAX - 1, u32::MAX - 1); + >::set(queue); + }); + + // commit the changes to the storage + ext.commit_all().unwrap(); + + ext.execute_with(|| { let min_balance = ::Currency::minimum_balance(); let _ = Balances::deposit_creating(&ALICE, 1000 * min_balance); + let mut tries: Vec = vec![]; - let addr = Contracts::bare_instantiate( - ALICE, - min_balance * 100, - GAS_LIMIT, - None, - Code::Upload(code), - vec![], - vec![], - false, - ) - .result - .unwrap() - .account_id; + // add 3 contracts to the deletion queue + for i in 0..3u8 { + let addr = Contracts::bare_instantiate( + ALICE, + min_balance * 100, + GAS_LIMIT, + None, + Code::Upload(code.clone()), + vec![], + vec![i], + false, + ) + .result + .unwrap() + .account_id; - // fill the deletion queue up until its limit - ContractInfo::::fill_queue_with_dummies(); + let info = get_contract(&addr); + let trie = &info.child_trie_info(); - // Terminate the contract should fail - assert_err_ignore_postinfo!( - Contracts::call(RuntimeOrigin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, None, vec![],), - Error::::DeletionQueueFull, - ); + // Put value into the contracts child trie + child::put(trie, &[99], &42); - // Contract should exist because removal failed - get_contract(&addr); - }); -} + // 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( + RuntimeOrigin::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_idle(System::block_number(), Weight::MAX); + // The single lazy removal should have removed all queued tries + for trie in tries.iter() { + assert_matches!(child::get::(trie, &[99]), None); + } + + // insert and delete counter values should go from u32::MAX - 1 to 1 + assert_eq!(>::get().as_test_tuple(), (1, 1)); + }) +} #[test] fn refcounter() { let (wasm, code_hash) = compile_module::("self_destruct").unwrap(); diff --git a/frame/contracts/src/weights.rs b/frame/contracts/src/weights.rs index 9e37a238b7d59..22a24aa27fe01 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: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -51,7 +51,6 @@ use sp_std::marker::PhantomData; pub trait WeightInfo { 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; fn call_with_code_per_byte(c: u32, ) -> Weight; fn instantiate_with_code(c: u32, i: u32, s: u32, ) -> Weight; @@ -171,14 +170,14 @@ pub trait WeightInfo { /// Weights for pallet_contracts using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: Contracts DeletionQueue (r:1 w:0) - /// Proof: Contracts DeletionQueue (max_values: Some(1), max_size: Some(16642), added: 17137, mode: Measured) + /// Storage: Contracts DeletionQueueCounter (r:1 w:0) + /// Proof: Contracts DeletionQueueCounter (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) fn on_process_deletion_queue_batch() -> Weight { // Proof Size summary in bytes: // Measured: `109` // Estimated: `1594` - // Minimum execution time: 2_713_000 picoseconds. - Weight::from_parts(2_811_000, 1594) + // Minimum execution time: 2_677_000 picoseconds. + Weight::from_parts(2_899_000, 1594) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: Skipped Metadata (r:0 w:0) @@ -186,33 +185,18 @@ impl WeightInfo for SubstrateWeight { /// The range of component `k` is `[0, 1024]`. fn on_initialize_per_trie_key(k: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `450 + k * (69 ±0)` - // Estimated: `440 + k * (70 ±0)` - // Minimum execution time: 11_011_000 picoseconds. - Weight::from_parts(7_025_244, 440) - // Standard Error: 1_217 - .saturating_add(Weight::from_parts(980_818, 0).saturating_mul(k.into())) - .saturating_add(T::DbWeight::get().reads(1_u64)) + // Measured: `488 + k * (69 ±0)` + // Estimated: `478 + k * (70 ±0)` + // Minimum execution time: 14_006_000 picoseconds. + Weight::from_parts(8_735_946, 478) + // Standard Error: 1_370 + .saturating_add(Weight::from_parts(989_501, 0).saturating_mul(k.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(k.into()))) - .saturating_add(T::DbWeight::get().writes(1_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(k.into()))) .saturating_add(Weight::from_parts(0, 70).saturating_mul(k.into())) } - /// Storage: Contracts DeletionQueue (r:1 w:1) - /// Proof: Contracts DeletionQueue (max_values: Some(1), max_size: Some(16642), added: 17137, mode: Measured) - /// The range of component `q` is `[0, 128]`. - fn on_initialize_per_queue_item(q: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `250 + q * (33 ±0)` - // Estimated: `1725 + q * (33 ±0)` - // Minimum execution time: 2_802_000 picoseconds. - Weight::from_parts(10_768_336, 1725) - // Standard Error: 3_424 - .saturating_add(Weight::from_parts(1_323_649, 0).saturating_mul(q.into())) - .saturating_add(T::DbWeight::get().reads(1_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) - .saturating_add(Weight::from_parts(0, 33).saturating_mul(q.into())) - } /// Storage: Contracts PristineCode (r:1 w:0) /// Proof: Contracts PristineCode (max_values: None, max_size: Some(125988), added: 128463, mode: Measured) /// Storage: Contracts CodeStorage (r:0 w:1) @@ -222,10 +206,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `238 + c * (1 ±0)` // Estimated: `3951 + c * (2 ±0)` - // Minimum execution time: 30_299_000 picoseconds. - Weight::from_parts(24_608_986, 3951) - // Standard Error: 75 - .saturating_add(Weight::from_parts(54_619, 0).saturating_mul(c.into())) + // Minimum execution time: 30_951_000 picoseconds. + Weight::from_parts(25_988_560, 3951) + // Standard Error: 57 + .saturating_add(Weight::from_parts(54_692, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 2).saturating_mul(c.into())) @@ -245,10 +229,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `707` // Estimated: `21400 + c * (5 ±0)` - // Minimum execution time: 265_835_000 picoseconds. - Weight::from_parts(275_985_164, 21400) - // Standard Error: 36 - .saturating_add(Weight::from_parts(37_980, 0).saturating_mul(c.into())) + // Minimum execution time: 263_107_000 picoseconds. + Weight::from_parts(268_289_665, 21400) + // Standard Error: 33 + .saturating_add(Weight::from_parts(38_534, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 5).saturating_mul(c.into())) @@ -276,14 +260,14 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `270` // Estimated: `26207` - // Minimum execution time: 3_124_508_000 picoseconds. - Weight::from_parts(617_467_897, 26207) - // Standard Error: 293 - .saturating_add(Weight::from_parts(106_971, 0).saturating_mul(c.into())) - // Standard Error: 17 - .saturating_add(Weight::from_parts(1_156, 0).saturating_mul(i.into())) - // Standard Error: 17 - .saturating_add(Weight::from_parts(1_395, 0).saturating_mul(s.into())) + // Minimum execution time: 3_122_319_000 picoseconds. + Weight::from_parts(487_802_180, 26207) + // Standard Error: 345 + .saturating_add(Weight::from_parts(108_237, 0).saturating_mul(c.into())) + // Standard Error: 20 + .saturating_add(Weight::from_parts(1_166, 0).saturating_mul(i.into())) + // Standard Error: 20 + .saturating_add(Weight::from_parts(1_505, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(10_u64)) } @@ -307,12 +291,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `482` // Estimated: `28521` - // Minimum execution time: 1_649_483_000 picoseconds. - Weight::from_parts(287_642_416, 28521) + // Minimum execution time: 1_650_623_000 picoseconds. + Weight::from_parts(286_494_456, 28521) // Standard Error: 8 - .saturating_add(Weight::from_parts(1_450, 0).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(1_438, 0).saturating_mul(i.into())) // Standard Error: 8 - .saturating_add(Weight::from_parts(1_443, 0).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_453, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } @@ -330,8 +314,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `759` // Estimated: `21615` - // Minimum execution time: 192_302_000 picoseconds. - Weight::from_parts(193_192_000, 21615) + // Minimum execution time: 191_046_000 picoseconds. + Weight::from_parts(192_544_000, 21615) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -348,10 +332,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `109` // Estimated: `7366` - // Minimum execution time: 246_401_000 picoseconds. - Weight::from_parts(261_505_456, 7366) - // Standard Error: 83 - .saturating_add(Weight::from_parts(109_136, 0).saturating_mul(c.into())) + // Minimum execution time: 244_260_000 picoseconds. + Weight::from_parts(254_693_985, 7366) + // Standard Error: 80 + .saturating_add(Weight::from_parts(108_246, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -367,8 +351,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `255` // Estimated: `7950` - // Minimum execution time: 33_913_000 picoseconds. - Weight::from_parts(34_186_000, 7950) + // Minimum execution time: 33_492_000 picoseconds. + Weight::from_parts(34_079_000, 7950) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -382,8 +366,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `570` // Estimated: `19530` - // Minimum execution time: 33_801_000 picoseconds. - Weight::from_parts(34_877_000, 19530) + // Minimum execution time: 33_475_000 picoseconds. + Weight::from_parts(33_856_000, 19530) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -402,10 +386,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `781 + r * (6 ±0)` // Estimated: `21730 + r * (30 ±0)` - // Minimum execution time: 237_679_000 picoseconds. - Weight::from_parts(243_022_905, 21730) - // Standard Error: 940 - .saturating_add(Weight::from_parts(324_389, 0).saturating_mul(r.into())) + // Minimum execution time: 234_197_000 picoseconds. + Weight::from_parts(236_830_305, 21730) + // Standard Error: 818 + .saturating_add(Weight::from_parts(336_446, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -425,10 +409,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `839 + r * (240 ±0)` // Estimated: `21835 + r * (3675 ±0)` - // Minimum execution time: 235_635_000 picoseconds. - Weight::from_parts(76_942_144, 21835) - // Standard Error: 6_214 - .saturating_add(Weight::from_parts(3_328_756, 0).saturating_mul(r.into())) + // Minimum execution time: 235_872_000 picoseconds. + Weight::from_parts(78_877_890, 21835) + // Standard Error: 6_405 + .saturating_add(Weight::from_parts(3_358_341, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -449,10 +433,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `831 + r * (244 ±0)` // Estimated: `21855 + r * (3695 ±0)` - // Minimum execution time: 237_123_000 picoseconds. - Weight::from_parts(77_880_739, 21855) - // Standard Error: 5_970 - .saturating_add(Weight::from_parts(4_103_281, 0).saturating_mul(r.into())) + // Minimum execution time: 239_035_000 picoseconds. + Weight::from_parts(93_255_085, 21855) + // Standard Error: 5_922 + .saturating_add(Weight::from_parts(4_144_910, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -473,10 +457,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `788 + r * (6 ±0)` // Estimated: `21770 + r * (30 ±0)` - // Minimum execution time: 236_621_000 picoseconds. - Weight::from_parts(238_240_015, 21770) - // Standard Error: 742 - .saturating_add(Weight::from_parts(404_691, 0).saturating_mul(r.into())) + // Minimum execution time: 236_507_000 picoseconds. + Weight::from_parts(238_253_211, 21770) + // Standard Error: 975 + .saturating_add(Weight::from_parts(413_919, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -496,10 +480,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `778 + r * (3 ±0)` // Estimated: `21735 + r * (15 ±0)` - // Minimum execution time: 233_274_000 picoseconds. - Weight::from_parts(239_596_227, 21735) - // Standard Error: 551 - .saturating_add(Weight::from_parts(164_429, 0).saturating_mul(r.into())) + // Minimum execution time: 235_521_000 picoseconds. + Weight::from_parts(238_397_362, 21735) + // Standard Error: 452 + .saturating_add(Weight::from_parts(160_860, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 15).saturating_mul(r.into())) @@ -519,10 +503,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `782 + r * (6 ±0)` // Estimated: `21740 + r * (30 ±0)` - // Minimum execution time: 235_661_000 picoseconds. - Weight::from_parts(239_063_406, 21740) - // Standard Error: 933 - .saturating_add(Weight::from_parts(327_679, 0).saturating_mul(r.into())) + // Minimum execution time: 234_722_000 picoseconds. + Weight::from_parts(242_936_096, 21740) + // Standard Error: 1_178 + .saturating_add(Weight::from_parts(329_075, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -542,10 +526,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `783 + r * (6 ±0)` // Estimated: `21725 + r * (30 ±0)` - // Minimum execution time: 235_583_000 picoseconds. - Weight::from_parts(251_641_549, 21725) - // Standard Error: 1_104 - .saturating_add(Weight::from_parts(315_873, 0).saturating_mul(r.into())) + // Minimum execution time: 235_654_000 picoseconds. + Weight::from_parts(245_887_792, 21725) + // Standard Error: 903 + .saturating_add(Weight::from_parts(325_168, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -565,10 +549,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `922 + r * (6 ±0)` // Estimated: `24633 + r * (30 ±0)` - // Minimum execution time: 235_325_000 picoseconds. - Weight::from_parts(256_582_010, 24633) - // Standard Error: 1_349 - .saturating_add(Weight::from_parts(1_483_116, 0).saturating_mul(r.into())) + // Minimum execution time: 233_599_000 picoseconds. + Weight::from_parts(251_561_602, 24633) + // Standard Error: 3_348 + .saturating_add(Weight::from_parts(1_475_443, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -588,10 +572,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `792 + r * (6 ±0)` // Estimated: `21825 + r * (30 ±0)` - // Minimum execution time: 235_358_000 picoseconds. - Weight::from_parts(233_421_484, 21825) - // Standard Error: 1_178 - .saturating_add(Weight::from_parts(337_947, 0).saturating_mul(r.into())) + // Minimum execution time: 235_087_000 picoseconds. + Weight::from_parts(235_855_322, 21825) + // Standard Error: 867 + .saturating_add(Weight::from_parts(346_707, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -611,10 +595,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `790 + r * (6 ±0)` // Estimated: `21815 + r * (30 ±0)` - // Minimum execution time: 236_570_000 picoseconds. - Weight::from_parts(245_853_078, 21815) - // Standard Error: 1_947 - .saturating_add(Weight::from_parts(319_972, 0).saturating_mul(r.into())) + // Minimum execution time: 237_103_000 picoseconds. + Weight::from_parts(239_272_188, 21815) + // Standard Error: 892 + .saturating_add(Weight::from_parts(328_334, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -634,10 +618,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `787 + r * (6 ±0)` // Estimated: `21805 + r * (30 ±0)` - // Minimum execution time: 235_027_000 picoseconds. - Weight::from_parts(239_719_689, 21805) - // Standard Error: 654 - .saturating_add(Weight::from_parts(326_988, 0).saturating_mul(r.into())) + // Minimum execution time: 234_761_000 picoseconds. + Weight::from_parts(238_601_784, 21805) + // Standard Error: 725 + .saturating_add(Weight::from_parts(325_758, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -657,10 +641,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `778 + r * (6 ±0)` // Estimated: `21735 + r * (30 ±0)` - // Minimum execution time: 236_547_000 picoseconds. - Weight::from_parts(239_390_326, 21735) - // Standard Error: 912 - .saturating_add(Weight::from_parts(327_495, 0).saturating_mul(r.into())) + // Minimum execution time: 235_249_000 picoseconds. + Weight::from_parts(239_861_242, 21735) + // Standard Error: 751 + .saturating_add(Weight::from_parts(325_795, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -682,10 +666,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `856 + r * (10 ±0)` // Estimated: `24446 + r * (60 ±0)` - // Minimum execution time: 235_710_000 picoseconds. - Weight::from_parts(238_998_789, 24446) - // Standard Error: 2_055 - .saturating_add(Weight::from_parts(1_373_992, 0).saturating_mul(r.into())) + // Minimum execution time: 234_912_000 picoseconds. + Weight::from_parts(254_783_734, 24446) + // Standard Error: 1_610 + .saturating_add(Weight::from_parts(1_307_506, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 60).saturating_mul(r.into())) @@ -705,10 +689,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `745 + r * (4 ±0)` // Estimated: `21555 + r * (20 ±0)` - // Minimum execution time: 161_133_000 picoseconds. - Weight::from_parts(167_097_346, 21555) - // Standard Error: 245 - .saturating_add(Weight::from_parts(128_503, 0).saturating_mul(r.into())) + // Minimum execution time: 160_125_000 picoseconds. + Weight::from_parts(164_915_574, 21555) + // Standard Error: 332 + .saturating_add(Weight::from_parts(132_326, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 20).saturating_mul(r.into())) @@ -728,10 +712,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `780 + r * (6 ±0)` // Estimated: `21740 + r * (30 ±0)` - // Minimum execution time: 234_790_000 picoseconds. - Weight::from_parts(242_392_710, 21740) - // Standard Error: 2_506 - .saturating_add(Weight::from_parts(273_470, 0).saturating_mul(r.into())) + // Minimum execution time: 234_717_000 picoseconds. + Weight::from_parts(238_540_521, 21740) + // Standard Error: 599 + .saturating_add(Weight::from_parts(277_303, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -751,10 +735,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `784` // Estimated: `21740` - // Minimum execution time: 236_837_000 picoseconds. - Weight::from_parts(237_860_073, 21740) - // Standard Error: 2 - .saturating_add(Weight::from_parts(602, 0).saturating_mul(n.into())) + // Minimum execution time: 235_792_000 picoseconds. + Weight::from_parts(244_114_692, 21740) + // Standard Error: 1 + .saturating_add(Weight::from_parts(589, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -773,10 +757,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `768 + r * (45 ±0)` // Estimated: `21660 + r * (225 ±0)` - // Minimum execution time: 232_047_000 picoseconds. - Weight::from_parts(234_629_293, 21660) - // Standard Error: 171_808 - .saturating_add(Weight::from_parts(663_306, 0).saturating_mul(r.into())) + // Minimum execution time: 231_166_000 picoseconds. + Weight::from_parts(233_339_177, 21660) + // Standard Error: 155_889 + .saturating_add(Weight::from_parts(3_124_322, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 225).saturating_mul(r.into())) @@ -796,10 +780,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `778` // Estimated: `21775` - // Minimum execution time: 235_035_000 picoseconds. - Weight::from_parts(234_442_091, 21775) + // Minimum execution time: 235_721_000 picoseconds. + Weight::from_parts(237_413_703, 21775) // Standard Error: 1 - .saturating_add(Weight::from_parts(185, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(177, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -811,26 +795,28 @@ impl WeightInfo for SubstrateWeight { /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) - /// Storage: Contracts DeletionQueue (r:1 w:1) - /// Proof: Contracts DeletionQueue (max_values: Some(1), max_size: Some(16642), added: 17137, mode: Measured) + /// Storage: Contracts DeletionQueueCounter (r:1 w:1) + /// Proof: Contracts DeletionQueueCounter (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: Contracts OwnerInfoOf (r:1 w:1) /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Measured) /// Storage: System EventTopics (r:3 w:3) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) + /// Storage: Contracts DeletionQueue (r:0 w:1) + /// Proof: Contracts DeletionQueue (max_values: None, max_size: Some(142), added: 2617, mode: Measured) /// The range of component `r` is `[0, 1]`. fn seal_terminate(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `810 + r * (356 ±0)` - // Estimated: `25511 + r * (15321 ±0)` - // Minimum execution time: 234_140_000 picoseconds. - Weight::from_parts(236_805_906, 25511) - // Standard Error: 435_181 - .saturating_add(Weight::from_parts(118_144_693, 0).saturating_mul(r.into())) + // Estimated: `26094 + r * (15904 ±0)` + // Minimum execution time: 233_525_000 picoseconds. + Weight::from_parts(235_871_034, 26094) + // Standard Error: 235_338 + .saturating_add(Weight::from_parts(118_659_865, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((6_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(T::DbWeight::get().writes((7_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 15321).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().writes((8_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_parts(0, 15904).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -849,10 +835,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `825 + r * (10 ±0)` // Estimated: `24283 + r * (60 ±0)` - // Minimum execution time: 235_271_000 picoseconds. - Weight::from_parts(256_019_682, 24283) - // Standard Error: 2_016 - .saturating_add(Weight::from_parts(1_862_085, 0).saturating_mul(r.into())) + // Minimum execution time: 235_007_000 picoseconds. + Weight::from_parts(248_419_686, 24283) + // Standard Error: 1_847 + .saturating_add(Weight::from_parts(1_815_822, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 60).saturating_mul(r.into())) @@ -872,10 +858,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `778 + r * (10 ±0)` // Estimated: `21735 + r * (50 ±0)` - // Minimum execution time: 233_092_000 picoseconds. - Weight::from_parts(248_483_473, 21735) - // Standard Error: 2_182 - .saturating_add(Weight::from_parts(3_551_674, 0).saturating_mul(r.into())) + // Minimum execution time: 232_912_000 picoseconds. + Weight::from_parts(256_142_885, 21735) + // Standard Error: 2_741 + .saturating_add(Weight::from_parts(3_542_482, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 50).saturating_mul(r.into())) @@ -896,12 +882,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `797 + t * (32 ±0)` // Estimated: `21840 + t * (2640 ±0)` - // Minimum execution time: 252_307_000 picoseconds. - Weight::from_parts(245_237_726, 21840) - // Standard Error: 79_824 - .saturating_add(Weight::from_parts(2_364_618, 0).saturating_mul(t.into())) - // Standard Error: 22 - .saturating_add(Weight::from_parts(636, 0).saturating_mul(n.into())) + // Minimum execution time: 251_018_000 picoseconds. + Weight::from_parts(245_280_765, 21840) + // Standard Error: 90_317 + .saturating_add(Weight::from_parts(2_434_496, 0).saturating_mul(t.into())) + // Standard Error: 25 + .saturating_add(Weight::from_parts(599, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(t.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -923,10 +909,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `777 + r * (7 ±0)` // Estimated: `21725 + r * (35 ±0)` - // Minimum execution time: 165_367_000 picoseconds. - Weight::from_parts(170_164_725, 21725) - // Standard Error: 487 - .saturating_add(Weight::from_parts(237_281, 0).saturating_mul(r.into())) + // Minimum execution time: 164_022_000 picoseconds. + Weight::from_parts(168_658_387, 21725) + // Standard Error: 685 + .saturating_add(Weight::from_parts(238_133, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 35).saturating_mul(r.into())) @@ -946,10 +932,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `125728` // Estimated: `269977` - // Minimum execution time: 350_914_000 picoseconds. - Weight::from_parts(354_461_646, 269977) - // Standard Error: 1 - .saturating_add(Weight::from_parts(747, 0).saturating_mul(i.into())) + // Minimum execution time: 351_043_000 picoseconds. + Weight::from_parts(353_707_344, 269977) + // Standard Error: 3 + .saturating_add(Weight::from_parts(752, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -960,10 +946,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `845 + r * (292 ±0)` // Estimated: `843 + r * (293 ±0)` - // Minimum execution time: 236_273_000 picoseconds. - Weight::from_parts(137_922_946, 843) - // Standard Error: 10_363 - .saturating_add(Weight::from_parts(6_034_776, 0).saturating_mul(r.into())) + // Minimum execution time: 235_854_000 picoseconds. + Weight::from_parts(133_986_225, 843) + // Standard Error: 9_550 + .saturating_add(Weight::from_parts(6_093_051, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -977,10 +963,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1304` // Estimated: `1280` - // Minimum execution time: 251_462_000 picoseconds. - Weight::from_parts(287_009_907, 1280) - // Standard Error: 62 - .saturating_add(Weight::from_parts(384, 0).saturating_mul(n.into())) + // Minimum execution time: 252_321_000 picoseconds. + Weight::from_parts(285_820_577, 1280) + // Standard Error: 60 + .saturating_add(Weight::from_parts(600, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -991,10 +977,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1167 + n * (1 ±0)` // Estimated: `1167 + n * (1 ±0)` - // Minimum execution time: 250_985_000 picoseconds. - Weight::from_parts(253_693_249, 1167) - // Standard Error: 21 - .saturating_add(Weight::from_parts(92, 0).saturating_mul(n.into())) + // Minimum execution time: 252_047_000 picoseconds. + Weight::from_parts(254_244_310, 1167) + // Standard Error: 15 + .saturating_add(Weight::from_parts(144, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -1006,10 +992,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `841 + r * (288 ±0)` // Estimated: `845 + r * (289 ±0)` - // Minimum execution time: 235_462_000 picoseconds. - Weight::from_parts(141_240_297, 845) - // Standard Error: 9_687 - .saturating_add(Weight::from_parts(5_906_737, 0).saturating_mul(r.into())) + // Minimum execution time: 235_697_000 picoseconds. + Weight::from_parts(143_200_942, 845) + // Standard Error: 11_358 + .saturating_add(Weight::from_parts(5_934_318, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1023,10 +1009,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1163 + n * (1 ±0)` // Estimated: `1163 + n * (1 ±0)` - // Minimum execution time: 250_887_000 picoseconds. - Weight::from_parts(253_321_064, 1163) - // Standard Error: 28 - .saturating_add(Weight::from_parts(169, 0).saturating_mul(n.into())) + // Minimum execution time: 250_360_000 picoseconds. + Weight::from_parts(252_712_722, 1163) + // Standard Error: 15 + .saturating_add(Weight::from_parts(130, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -1038,10 +1024,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `835 + r * (296 ±0)` // Estimated: `840 + r * (297 ±0)` - // Minimum execution time: 236_542_000 picoseconds. - Weight::from_parts(147_992_508, 840) - // Standard Error: 8_849 - .saturating_add(Weight::from_parts(4_946_692, 0).saturating_mul(r.into())) + // Minimum execution time: 235_613_000 picoseconds. + Weight::from_parts(150_213_792, 840) + // Standard Error: 8_617 + .saturating_add(Weight::from_parts(4_962_874, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1054,10 +1040,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1179 + n * (1 ±0)` // Estimated: `1179 + n * (1 ±0)` - // Minimum execution time: 249_987_000 picoseconds. - Weight::from_parts(254_866_627, 1179) - // Standard Error: 53 - .saturating_add(Weight::from_parts(554, 0).saturating_mul(n.into())) + // Minimum execution time: 249_137_000 picoseconds. + Weight::from_parts(253_529_386, 1179) + // Standard Error: 41 + .saturating_add(Weight::from_parts(612, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -1069,10 +1055,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `856 + r * (288 ±0)` // Estimated: `857 + r * (289 ±0)` - // Minimum execution time: 236_635_000 picoseconds. - Weight::from_parts(157_805_789, 857) - // Standard Error: 7_699 - .saturating_add(Weight::from_parts(4_709_422, 0).saturating_mul(r.into())) + // Minimum execution time: 235_659_000 picoseconds. + Weight::from_parts(158_846_683, 857) + // Standard Error: 7_806 + .saturating_add(Weight::from_parts(4_728_537, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1085,10 +1071,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1166 + n * (1 ±0)` // Estimated: `1166 + n * (1 ±0)` - // Minimum execution time: 252_660_000 picoseconds. - Weight::from_parts(255_250_747, 1166) - // Standard Error: 14 - .saturating_add(Weight::from_parts(133, 0).saturating_mul(n.into())) + // Minimum execution time: 248_553_000 picoseconds. + Weight::from_parts(250_703_269, 1166) + // Standard Error: 17 + .saturating_add(Weight::from_parts(163, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -1100,10 +1086,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `829 + r * (296 ±0)` // Estimated: `836 + r * (297 ±0)` - // Minimum execution time: 240_198_000 picoseconds. - Weight::from_parts(133_188_357, 836) - // Standard Error: 10_661 - .saturating_add(Weight::from_parts(6_147_538, 0).saturating_mul(r.into())) + // Minimum execution time: 236_431_000 picoseconds. + Weight::from_parts(131_745_419, 836) + // Standard Error: 10_161 + .saturating_add(Weight::from_parts(6_182_174, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1117,10 +1103,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1180 + n * (1 ±0)` // Estimated: `1180 + n * (1 ±0)` - // Minimum execution time: 252_131_000 picoseconds. - Weight::from_parts(259_960_286, 1180) - // Standard Error: 121 - .saturating_add(Weight::from_parts(192, 0).saturating_mul(n.into())) + // Minimum execution time: 252_551_000 picoseconds. + Weight::from_parts(254_517_030, 1180) + // Standard Error: 16 + .saturating_add(Weight::from_parts(712, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -1140,10 +1126,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1373 + r * (45 ±0)` // Estimated: `26753 + r * (2700 ±0)` - // Minimum execution time: 235_860_000 picoseconds. - Weight::from_parts(124_993_651, 26753) - // Standard Error: 22_811 - .saturating_add(Weight::from_parts(36_467_740, 0).saturating_mul(r.into())) + // Minimum execution time: 236_663_000 picoseconds. + Weight::from_parts(237_485_000, 26753) + // Standard Error: 42_414 + .saturating_add(Weight::from_parts(36_849_514, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(4_u64)) @@ -1165,10 +1151,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1237 + r * (256 ±0)` // Estimated: `26028 + r * (6235 ±0)` - // Minimum execution time: 237_221_000 picoseconds. - Weight::from_parts(237_632_000, 26028) - // Standard Error: 89_502 - .saturating_add(Weight::from_parts(212_211_534, 0).saturating_mul(r.into())) + // Minimum execution time: 237_101_000 picoseconds. + Weight::from_parts(237_827_000, 26028) + // Standard Error: 82_878 + .saturating_add(Weight::from_parts(211_777_724, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1190,10 +1176,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0 + r * (502 ±0)` // Estimated: `21755 + r * (6329 ±3)` - // Minimum execution time: 236_965_000 picoseconds. - Weight::from_parts(238_110_000, 21755) - // Standard Error: 101_332 - .saturating_add(Weight::from_parts(206_790_203, 0).saturating_mul(r.into())) + // Minimum execution time: 241_213_000 picoseconds. + Weight::from_parts(241_900_000, 21755) + // Standard Error: 99_976 + .saturating_add(Weight::from_parts(207_520_077, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1216,12 +1202,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1154 + t * (204 ±0)` // Estimated: `31015 + t * (5970 ±0)` - // Minimum execution time: 411_974_000 picoseconds. - Weight::from_parts(391_387_689, 31015) - // Standard Error: 1_320_695 - .saturating_add(Weight::from_parts(29_766_122, 0).saturating_mul(t.into())) + // Minimum execution time: 414_784_000 picoseconds. + Weight::from_parts(384_902_379, 31015) + // Standard Error: 1_228_593 + .saturating_add(Weight::from_parts(33_226_901, 0).saturating_mul(t.into())) // Standard Error: 1 - .saturating_add(Weight::from_parts(597, 0).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(601, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(t.into()))) .saturating_add(T::DbWeight::get().writes(5_u64)) @@ -1247,10 +1233,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1301 + r * (254 ±0)` // Estimated: `30977 + r * (16635 ±0)` - // Minimum execution time: 237_595_000 picoseconds. - Weight::from_parts(238_068_000, 30977) - // Standard Error: 254_409 - .saturating_add(Weight::from_parts(346_436_154, 0).saturating_mul(r.into())) + // Minimum execution time: 236_963_000 picoseconds. + Weight::from_parts(237_711_000, 30977) + // Standard Error: 265_576 + .saturating_add(Weight::from_parts(347_359_908, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().reads((6_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(6_u64)) @@ -1278,14 +1264,14 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1071 + t * (187 ±0)` // Estimated: `42684 + t * (3588 ±2)` - // Minimum execution time: 1_616_768_000 picoseconds. - Weight::from_parts(363_003_254, 42684) - // Standard Error: 4_398_669 - .saturating_add(Weight::from_parts(104_529_967, 0).saturating_mul(t.into())) + // Minimum execution time: 1_615_191_000 picoseconds. + Weight::from_parts(337_408_450, 42684) + // Standard Error: 4_581_951 + .saturating_add(Weight::from_parts(115_730_776, 0).saturating_mul(t.into())) // Standard Error: 7 - .saturating_add(Weight::from_parts(1_162, 0).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(1_171, 0).saturating_mul(i.into())) // Standard Error: 7 - .saturating_add(Weight::from_parts(1_333, 0).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_346, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(13_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(t.into()))) .saturating_add(T::DbWeight::get().writes(10_u64)) @@ -1307,10 +1293,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `777 + r * (8 ±0)` // Estimated: `21710 + r * (40 ±0)` - // Minimum execution time: 233_814_000 picoseconds. - Weight::from_parts(241_291_041, 21710) - // Standard Error: 1_422 - .saturating_add(Weight::from_parts(575_846, 0).saturating_mul(r.into())) + // Minimum execution time: 233_601_000 picoseconds. + Weight::from_parts(246_594_905, 21710) + // Standard Error: 2_840 + .saturating_add(Weight::from_parts(578_751, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) @@ -1330,10 +1316,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `785` // Estimated: `21745` - // Minimum execution time: 236_572_000 picoseconds. - Weight::from_parts(235_648_055, 21745) + // Minimum execution time: 233_735_000 picoseconds. + Weight::from_parts(243_432_330, 21745) // Standard Error: 3 - .saturating_add(Weight::from_parts(3_947, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(3_927, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1352,10 +1338,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `779 + r * (8 ±0)` // Estimated: `21725 + r * (40 ±0)` - // Minimum execution time: 234_473_000 picoseconds. - Weight::from_parts(239_805_309, 21725) - // Standard Error: 1_113 - .saturating_add(Weight::from_parts(752_507, 0).saturating_mul(r.into())) + // Minimum execution time: 232_173_000 picoseconds. + Weight::from_parts(239_806_011, 21725) + // Standard Error: 1_530 + .saturating_add(Weight::from_parts(749_641, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) @@ -1375,10 +1361,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `787` // Estimated: `21765` - // Minimum execution time: 235_209_000 picoseconds. - Weight::from_parts(228_548_524, 21765) + // Minimum execution time: 235_046_000 picoseconds. + Weight::from_parts(229_500_792, 21765) // Standard Error: 2 - .saturating_add(Weight::from_parts(3_171, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(3_166, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1397,10 +1383,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `779 + r * (8 ±0)` // Estimated: `21740 + r * (40 ±0)` - // Minimum execution time: 233_282_000 picoseconds. - Weight::from_parts(240_864_680, 21740) - // Standard Error: 958 - .saturating_add(Weight::from_parts(418_308, 0).saturating_mul(r.into())) + // Minimum execution time: 231_708_000 picoseconds. + Weight::from_parts(235_347_566, 21740) + // Standard Error: 987 + .saturating_add(Weight::from_parts(428_819, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) @@ -1420,10 +1406,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `787` // Estimated: `21785` - // Minimum execution time: 234_667_000 picoseconds. - Weight::from_parts(227_810_077, 21785) - // Standard Error: 2 - .saturating_add(Weight::from_parts(925, 0).saturating_mul(n.into())) + // Minimum execution time: 234_068_000 picoseconds. + Weight::from_parts(226_519_852, 21785) + // Standard Error: 1 + .saturating_add(Weight::from_parts(916, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1442,10 +1428,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `779 + r * (8 ±0)` // Estimated: `21745 + r * (40 ±0)` - // Minimum execution time: 234_040_000 picoseconds. - Weight::from_parts(237_970_694, 21745) - // Standard Error: 979 - .saturating_add(Weight::from_parts(416_562, 0).saturating_mul(r.into())) + // Minimum execution time: 231_872_000 picoseconds. + Weight::from_parts(236_694_763, 21745) + // Standard Error: 870 + .saturating_add(Weight::from_parts(420_853, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) @@ -1465,10 +1451,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `787` // Estimated: `21755` - // Minimum execution time: 234_840_000 picoseconds. - Weight::from_parts(227_849_778, 21755) + // Minimum execution time: 233_707_000 picoseconds. + Weight::from_parts(226_312_559, 21755) // Standard Error: 2 - .saturating_add(Weight::from_parts(923, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(924, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1487,10 +1473,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `822 + r * (76 ±0)` // Estimated: `21705 + r * (385 ±0)` - // Minimum execution time: 236_174_000 picoseconds. - Weight::from_parts(252_457_690, 21705) - // Standard Error: 20_130 - .saturating_add(Weight::from_parts(37_792_805, 0).saturating_mul(r.into())) + // Minimum execution time: 234_962_000 picoseconds. + Weight::from_parts(252_611_292, 21705) + // Standard Error: 20_134 + .saturating_add(Weight::from_parts(37_745_358, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 385).saturating_mul(r.into())) @@ -1509,11 +1495,11 @@ impl WeightInfo for SubstrateWeight { fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `792 + r * (42 ±0)` - // Estimated: `21780 + r * (210 ±0)` - // Minimum execution time: 236_251_000 picoseconds. - Weight::from_parts(242_254_305, 21780) - // Standard Error: 9_765 - .saturating_add(Weight::from_parts(9_341_334, 0).saturating_mul(r.into())) + // Estimated: `21775 + r * (210 ±0)` + // Minimum execution time: 234_869_000 picoseconds. + Weight::from_parts(240_188_331, 21775) + // Standard Error: 9_910 + .saturating_add(Weight::from_parts(9_332_432, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 210).saturating_mul(r.into())) @@ -1534,11 +1520,11 @@ impl WeightInfo for SubstrateWeight { fn seal_set_code_hash(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + r * (964 ±0)` - // Estimated: `29920 + r * (11544 ±7)` - // Minimum execution time: 236_462_000 picoseconds. - Weight::from_parts(236_997_000, 29920) - // Standard Error: 46_527 - .saturating_add(Weight::from_parts(21_858_761, 0).saturating_mul(r.into())) + // Estimated: `29920 + r * (11544 ±10)` + // Minimum execution time: 235_036_000 picoseconds. + Weight::from_parts(235_538_000, 29920) + // Standard Error: 47_360 + .saturating_add(Weight::from_parts(22_113_144, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1560,10 +1546,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `773 + r * (3 ±0)` // Estimated: `21735 + r * (15 ±0)` - // Minimum execution time: 235_085_000 picoseconds. - Weight::from_parts(239_410_836, 21735) - // Standard Error: 414 - .saturating_add(Weight::from_parts(167_067, 0).saturating_mul(r.into())) + // Minimum execution time: 237_884_000 picoseconds. + Weight::from_parts(243_315_095, 21735) + // Standard Error: 560 + .saturating_add(Weight::from_parts(162_206, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 15).saturating_mul(r.into())) @@ -1583,10 +1569,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1975 + r * (39 ±0)` // Estimated: `27145 + r * (200 ±0)` - // Minimum execution time: 236_690_000 picoseconds. - Weight::from_parts(268_793_030, 27145) - // Standard Error: 1_210 - .saturating_add(Weight::from_parts(263_330, 0).saturating_mul(r.into())) + // Minimum execution time: 239_402_000 picoseconds. + Weight::from_parts(267_214_783, 27145) + // Standard Error: 1_166 + .saturating_add(Weight::from_parts(261_915, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 200).saturating_mul(r.into())) @@ -1608,10 +1594,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `776 + r * (3 ±0)` // Estimated: `24004 + r * (18 ±0)` - // Minimum execution time: 236_289_000 picoseconds. - Weight::from_parts(246_581_099, 24004) - // Standard Error: 1_300 - .saturating_add(Weight::from_parts(137_499, 0).saturating_mul(r.into())) + // Minimum execution time: 233_153_000 picoseconds. + Weight::from_parts(238_999_965, 24004) + // Standard Error: 291 + .saturating_add(Weight::from_parts(143_971, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 18).saturating_mul(r.into())) @@ -1621,9 +1607,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_679_000 picoseconds. - Weight::from_parts(1_934_194, 0) - // Standard Error: 1 + // Minimum execution time: 1_706_000 picoseconds. + Weight::from_parts(1_962_558, 0) + // Standard Error: 2 .saturating_add(Weight::from_parts(3_000, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. @@ -1631,513 +1617,513 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_872_000 picoseconds. - Weight::from_parts(2_605_712, 0) - // Standard Error: 43 - .saturating_add(Weight::from_parts(6_321, 0).saturating_mul(r.into())) + // Minimum execution time: 1_870_000 picoseconds. + Weight::from_parts(2_481_243, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(6_346, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64store(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_837_000 picoseconds. - Weight::from_parts(2_035_143, 0) - // Standard Error: 65 - .saturating_add(Weight::from_parts(6_202, 0).saturating_mul(r.into())) + // Minimum execution time: 1_830_000 picoseconds. + Weight::from_parts(2_389_658, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(5_997, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_select(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_684_000 picoseconds. - Weight::from_parts(2_044_218, 0) - // Standard Error: 5 - .saturating_add(Weight::from_parts(7_929, 0).saturating_mul(r.into())) + // Minimum execution time: 1_734_000 picoseconds. + Weight::from_parts(2_170_618, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(7_919, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_if(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_635_000 picoseconds. - Weight::from_parts(2_009_851, 0) - // Standard Error: 6 - .saturating_add(Weight::from_parts(10_724, 0).saturating_mul(r.into())) + // Minimum execution time: 1_661_000 picoseconds. + Weight::from_parts(1_945_771, 0) + // Standard Error: 11 + .saturating_add(Weight::from_parts(10_840, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_br(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_667_000 picoseconds. - Weight::from_parts(1_869_395, 0) - // Standard Error: 12 - .saturating_add(Weight::from_parts(4_618, 0).saturating_mul(r.into())) + // Minimum execution time: 1_682_000 picoseconds. + Weight::from_parts(1_970_774, 0) + // Standard Error: 11 + .saturating_add(Weight::from_parts(4_569, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_br_if(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_698_000 picoseconds. - Weight::from_parts(2_184_182, 0) - // Standard Error: 16 - .saturating_add(Weight::from_parts(6_833, 0).saturating_mul(r.into())) + // Minimum execution time: 1_668_000 picoseconds. + Weight::from_parts(1_227_080, 0) + // Standard Error: 76 + .saturating_add(Weight::from_parts(8_066, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_br_table(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_670_000 picoseconds. - Weight::from_parts(1_471_988, 0) - // Standard Error: 30 - .saturating_add(Weight::from_parts(9_550, 0).saturating_mul(r.into())) + // Minimum execution time: 1_653_000 picoseconds. + Weight::from_parts(1_394_759, 0) + // Standard Error: 39 + .saturating_add(Weight::from_parts(9_566, 0).saturating_mul(r.into())) } /// The range of component `e` is `[1, 256]`. fn instr_br_table_per_entry(e: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_778_000 picoseconds. - Weight::from_parts(1_925_086, 0) - // Standard Error: 136 - .saturating_add(Weight::from_parts(502, 0).saturating_mul(e.into())) + // Minimum execution time: 1_771_000 picoseconds. + Weight::from_parts(1_905_594, 0) + // Standard Error: 147 + .saturating_add(Weight::from_parts(925, 0).saturating_mul(e.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_call(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_759_000 picoseconds. - Weight::from_parts(2_372_048, 0) - // Standard Error: 16 - .saturating_add(Weight::from_parts(17_953, 0).saturating_mul(r.into())) + // Minimum execution time: 1_863_000 picoseconds. + Weight::from_parts(2_472_635, 0) + // Standard Error: 13 + .saturating_add(Weight::from_parts(17_892, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_call_indirect(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_852_000 picoseconds. - Weight::from_parts(3_125_003, 0) - // Standard Error: 25 - .saturating_add(Weight::from_parts(24_218, 0).saturating_mul(r.into())) + // Minimum execution time: 2_013_000 picoseconds. + Weight::from_parts(3_077_100, 0) + // Standard Error: 18 + .saturating_add(Weight::from_parts(24_287, 0).saturating_mul(r.into())) } /// The range of component `l` is `[0, 1024]`. fn instr_call_per_local(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_795_000 picoseconds. - Weight::from_parts(2_121_763, 0) - // Standard Error: 45 - .saturating_add(Weight::from_parts(1_207, 0).saturating_mul(l.into())) + // Minimum execution time: 1_818_000 picoseconds. + Weight::from_parts(2_109_143, 0) + // Standard Error: 34 + .saturating_add(Weight::from_parts(1_249, 0).saturating_mul(l.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_local_get(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_019_000 picoseconds. - Weight::from_parts(3_267_108, 0) - // Standard Error: 55 - .saturating_add(Weight::from_parts(2_527, 0).saturating_mul(r.into())) + // Minimum execution time: 3_083_000 picoseconds. + Weight::from_parts(3_291_328, 0) + // Standard Error: 1 + .saturating_add(Weight::from_parts(2_505, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_local_set(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_944_000 picoseconds. - Weight::from_parts(3_183_331, 0) + // Minimum execution time: 2_987_000 picoseconds. + Weight::from_parts(3_276_863, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(3_618, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_617, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_local_tee(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_009_000 picoseconds. - Weight::from_parts(3_178_158, 0) - // Standard Error: 41 - .saturating_add(Weight::from_parts(4_075, 0).saturating_mul(r.into())) + // Minimum execution time: 2_942_000 picoseconds. + Weight::from_parts(3_350_581, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(3_976, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_global_get(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_748_000 picoseconds. - Weight::from_parts(2_371_911, 0) - // Standard Error: 10 - .saturating_add(Weight::from_parts(8_378, 0).saturating_mul(r.into())) + // Minimum execution time: 1_867_000 picoseconds. + Weight::from_parts(2_920_748, 0) + // Standard Error: 44 + .saturating_add(Weight::from_parts(8_229, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_global_set(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_795_000 picoseconds. - Weight::from_parts(1_311_997, 0) - // Standard Error: 157 - .saturating_add(Weight::from_parts(9_410, 0).saturating_mul(r.into())) + // Minimum execution time: 1_757_000 picoseconds. + Weight::from_parts(2_235_198, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(8_815, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_memory_current(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_059_000 picoseconds. - Weight::from_parts(2_416_611, 0) - // Standard Error: 5 - .saturating_add(Weight::from_parts(3_775, 0).saturating_mul(r.into())) + // Minimum execution time: 1_824_000 picoseconds. + Weight::from_parts(1_941_816, 0) + // Standard Error: 86 + .saturating_add(Weight::from_parts(4_043, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 16]`. fn instr_memory_grow(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_764_000 picoseconds. - Weight::from_parts(1_414_442, 0) - // Standard Error: 142_321 - .saturating_add(Weight::from_parts(13_210_495, 0).saturating_mul(r.into())) + // Minimum execution time: 1_793_000 picoseconds. + Weight::from_parts(1_104_829, 0) + // Standard Error: 137_800 + .saturating_add(Weight::from_parts(13_336_784, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64clz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_665_000 picoseconds. - Weight::from_parts(2_047_968, 0) + // Minimum execution time: 1_693_000 picoseconds. + Weight::from_parts(2_037_305, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(4_035, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(4_044, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64ctz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_696_000 picoseconds. - Weight::from_parts(2_101_548, 0) - // Standard Error: 13 - .saturating_add(Weight::from_parts(3_754, 0).saturating_mul(r.into())) + // Minimum execution time: 1_751_000 picoseconds. + Weight::from_parts(2_082_016, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(3_767, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64popcnt(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_686_000 picoseconds. - Weight::from_parts(2_023_482, 0) + // Minimum execution time: 1_751_000 picoseconds. + Weight::from_parts(2_110_625, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(3_770, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_754, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64eqz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_700_000 picoseconds. - Weight::from_parts(2_035_759, 0) + // Minimum execution time: 1_756_000 picoseconds. + Weight::from_parts(2_100_327, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(3_660, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_664, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64extendsi32(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_682_000 picoseconds. - Weight::from_parts(2_015_828, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(3_977, 0).saturating_mul(r.into())) + // Minimum execution time: 1_643_000 picoseconds. + Weight::from_parts(2_169_153, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(3_961, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64extendui32(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_660_000 picoseconds. - Weight::from_parts(2_032_387, 0) + // Minimum execution time: 1_704_000 picoseconds. + Weight::from_parts(2_049_172, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(3_826, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_833, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i32wrapi64(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_635_000 picoseconds. - Weight::from_parts(2_013_228, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(3_752, 0).saturating_mul(r.into())) + // Minimum execution time: 1_726_000 picoseconds. + Weight::from_parts(2_064_387, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(3_745, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64eq(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_698_000 picoseconds. - Weight::from_parts(2_844_817, 0) + // Minimum execution time: 1_696_000 picoseconds. + Weight::from_parts(2_426_905, 0) // Standard Error: 56 - .saturating_add(Weight::from_parts(5_746, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(5_915, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64ne(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_686_000 picoseconds. - Weight::from_parts(2_208_884, 0) - // Standard Error: 138 - .saturating_add(Weight::from_parts(6_032, 0).saturating_mul(r.into())) + // Minimum execution time: 1_617_000 picoseconds. + Weight::from_parts(2_035_161, 0) + // Standard Error: 94 + .saturating_add(Weight::from_parts(6_073, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64lts(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_695_000 picoseconds. - Weight::from_parts(2_060_880, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(5_966, 0).saturating_mul(r.into())) + // Minimum execution time: 1_756_000 picoseconds. + Weight::from_parts(2_098_926, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(6_002, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64ltu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_700_000 picoseconds. - Weight::from_parts(2_143_484, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(5_932, 0).saturating_mul(r.into())) + // Minimum execution time: 1_706_000 picoseconds. + Weight::from_parts(2_257_972, 0) + // Standard Error: 23 + .saturating_add(Weight::from_parts(5_982, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64gts(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_677_000 picoseconds. - Weight::from_parts(2_081_646, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(5_813, 0).saturating_mul(r.into())) + // Minimum execution time: 1_761_000 picoseconds. + Weight::from_parts(2_114_141, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(5_815, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64gtu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_476_000 picoseconds. - Weight::from_parts(2_161_801, 0) - // Standard Error: 4 - .saturating_add(Weight::from_parts(6_078, 0).saturating_mul(r.into())) + // Minimum execution time: 1_700_000 picoseconds. + Weight::from_parts(2_053_201, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(6_137, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64les(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_677_000 picoseconds. - Weight::from_parts(2_043_451, 0) + // Minimum execution time: 1_705_000 picoseconds. + Weight::from_parts(2_101_782, 0) // Standard Error: 3 - .saturating_add(Weight::from_parts(5_988, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(6_014, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64leu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_694_000 picoseconds. - Weight::from_parts(2_058_196, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(6_058, 0).saturating_mul(r.into())) + // Minimum execution time: 1_856_000 picoseconds. + Weight::from_parts(2_149_707, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(6_086, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64ges(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_675_000 picoseconds. - Weight::from_parts(2_036_798, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(5_956, 0).saturating_mul(r.into())) + // Minimum execution time: 1_739_000 picoseconds. + Weight::from_parts(2_143_216, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(5_934, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64geu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_712_000 picoseconds. - Weight::from_parts(2_121_407, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(5_944, 0).saturating_mul(r.into())) + // Minimum execution time: 1_716_000 picoseconds. + Weight::from_parts(2_065_762, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(6_009, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64add(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_675_000 picoseconds. - Weight::from_parts(2_061_053, 0) - // Standard Error: 6 - .saturating_add(Weight::from_parts(5_823, 0).saturating_mul(r.into())) + // Minimum execution time: 1_664_000 picoseconds. + Weight::from_parts(3_062_283, 0) + // Standard Error: 94 + .saturating_add(Weight::from_parts(5_645, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64sub(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_686_000 picoseconds. - Weight::from_parts(2_023_347, 0) - // Standard Error: 4 - .saturating_add(Weight::from_parts(6_126, 0).saturating_mul(r.into())) + // Minimum execution time: 1_671_000 picoseconds. + Weight::from_parts(2_011_145, 0) + // Standard Error: 44 + .saturating_add(Weight::from_parts(6_220, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64mul(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_678_000 picoseconds. - Weight::from_parts(2_390_920, 0) - // Standard Error: 55 - .saturating_add(Weight::from_parts(5_635, 0).saturating_mul(r.into())) + // Minimum execution time: 1_759_000 picoseconds. + Weight::from_parts(2_095_420, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(5_723, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64divs(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_728_000 picoseconds. - Weight::from_parts(1_944_457, 0) - // Standard Error: 7 - .saturating_add(Weight::from_parts(11_848, 0).saturating_mul(r.into())) + // Minimum execution time: 1_672_000 picoseconds. + Weight::from_parts(2_184_044, 0) + // Standard Error: 5 + .saturating_add(Weight::from_parts(11_782, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64divu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_649_000 picoseconds. - Weight::from_parts(1_881_148, 0) - // Standard Error: 6 - .saturating_add(Weight::from_parts(10_618, 0).saturating_mul(r.into())) + // Minimum execution time: 1_752_000 picoseconds. + Weight::from_parts(2_276_209, 0) + // Standard Error: 5 + .saturating_add(Weight::from_parts(10_513, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64rems(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_708_000 picoseconds. - Weight::from_parts(1_767_912, 0) - // Standard Error: 6 - .saturating_add(Weight::from_parts(12_099, 0).saturating_mul(r.into())) + // Minimum execution time: 1_711_000 picoseconds. + Weight::from_parts(2_720_989, 0) + // Standard Error: 24 + .saturating_add(Weight::from_parts(11_884, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64remu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_650_000 picoseconds. - Weight::from_parts(1_998_575, 0) + // Minimum execution time: 1_713_000 picoseconds. + Weight::from_parts(2_091_403, 0) // Standard Error: 3 - .saturating_add(Weight::from_parts(10_632, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(10_628, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64and(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_633_000 picoseconds. - Weight::from_parts(2_029_981, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(5_662, 0).saturating_mul(r.into())) + // Minimum execution time: 1_704_000 picoseconds. + Weight::from_parts(2_054_652, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(5_672, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64or(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_621_000 picoseconds. - Weight::from_parts(2_029_743, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(5_762, 0).saturating_mul(r.into())) + // Minimum execution time: 1_743_000 picoseconds. + Weight::from_parts(2_032_806, 0) + // Standard Error: 19 + .saturating_add(Weight::from_parts(5_795, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64xor(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_641_000 picoseconds. - Weight::from_parts(2_127_132, 0) + // Minimum execution time: 1_667_000 picoseconds. + Weight::from_parts(2_031_702, 0) // Standard Error: 5 - .saturating_add(Weight::from_parts(5_818, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(5_923, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64shl(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_690_000 picoseconds. - Weight::from_parts(2_021_035, 0) - // Standard Error: 4 - .saturating_add(Weight::from_parts(5_917, 0).saturating_mul(r.into())) + // Minimum execution time: 1_735_000 picoseconds. + Weight::from_parts(2_946_634, 0) + // Standard Error: 54 + .saturating_add(Weight::from_parts(5_685, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64shrs(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_661_000 picoseconds. - Weight::from_parts(2_055_069, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(6_094, 0).saturating_mul(r.into())) + // Minimum execution time: 1_652_000 picoseconds. + Weight::from_parts(2_023_049, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(6_146, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64shru(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_677_000 picoseconds. - Weight::from_parts(2_024_748, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(5_862, 0).saturating_mul(r.into())) + // Minimum execution time: 1_654_000 picoseconds. + Weight::from_parts(2_148_951, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(5_869, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64rotl(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_651_000 picoseconds. - Weight::from_parts(2_005_814, 0) + // Minimum execution time: 1_730_000 picoseconds. + Weight::from_parts(2_130_543, 0) // Standard Error: 3 - .saturating_add(Weight::from_parts(6_007, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(5_999, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64rotr(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_703_000 picoseconds. - Weight::from_parts(2_019_636, 0) + // Minimum execution time: 1_728_000 picoseconds. + Weight::from_parts(2_172_886, 0) // Standard Error: 3 - .saturating_add(Weight::from_parts(5_862, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(5_843, 0).saturating_mul(r.into())) } } // For backwards compatibility and tests impl WeightInfo for () { - /// Storage: Contracts DeletionQueue (r:1 w:0) - /// Proof: Contracts DeletionQueue (max_values: Some(1), max_size: Some(16642), added: 17137, mode: Measured) + /// Storage: Contracts DeletionQueueCounter (r:1 w:0) + /// Proof: Contracts DeletionQueueCounter (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) fn on_process_deletion_queue_batch() -> Weight { // Proof Size summary in bytes: // Measured: `109` // Estimated: `1594` - // Minimum execution time: 2_713_000 picoseconds. - Weight::from_parts(2_811_000, 1594) + // Minimum execution time: 2_677_000 picoseconds. + Weight::from_parts(2_899_000, 1594) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: Skipped Metadata (r:0 w:0) @@ -2145,33 +2131,18 @@ impl WeightInfo for () { /// The range of component `k` is `[0, 1024]`. fn on_initialize_per_trie_key(k: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `450 + k * (69 ±0)` - // Estimated: `440 + k * (70 ±0)` - // Minimum execution time: 11_011_000 picoseconds. - Weight::from_parts(7_025_244, 440) - // Standard Error: 1_217 - .saturating_add(Weight::from_parts(980_818, 0).saturating_mul(k.into())) - .saturating_add(RocksDbWeight::get().reads(1_u64)) + // Measured: `488 + k * (69 ±0)` + // Estimated: `478 + k * (70 ±0)` + // Minimum execution time: 14_006_000 picoseconds. + Weight::from_parts(8_735_946, 478) + // Standard Error: 1_370 + .saturating_add(Weight::from_parts(989_501, 0).saturating_mul(k.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(k.into()))) - .saturating_add(RocksDbWeight::get().writes(1_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(k.into()))) .saturating_add(Weight::from_parts(0, 70).saturating_mul(k.into())) } - /// Storage: Contracts DeletionQueue (r:1 w:1) - /// Proof: Contracts DeletionQueue (max_values: Some(1), max_size: Some(16642), added: 17137, mode: Measured) - /// The range of component `q` is `[0, 128]`. - fn on_initialize_per_queue_item(q: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `250 + q * (33 ±0)` - // Estimated: `1725 + q * (33 ±0)` - // Minimum execution time: 2_802_000 picoseconds. - Weight::from_parts(10_768_336, 1725) - // Standard Error: 3_424 - .saturating_add(Weight::from_parts(1_323_649, 0).saturating_mul(q.into())) - .saturating_add(RocksDbWeight::get().reads(1_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) - .saturating_add(Weight::from_parts(0, 33).saturating_mul(q.into())) - } /// Storage: Contracts PristineCode (r:1 w:0) /// Proof: Contracts PristineCode (max_values: None, max_size: Some(125988), added: 128463, mode: Measured) /// Storage: Contracts CodeStorage (r:0 w:1) @@ -2181,10 +2152,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `238 + c * (1 ±0)` // Estimated: `3951 + c * (2 ±0)` - // Minimum execution time: 30_299_000 picoseconds. - Weight::from_parts(24_608_986, 3951) - // Standard Error: 75 - .saturating_add(Weight::from_parts(54_619, 0).saturating_mul(c.into())) + // Minimum execution time: 30_951_000 picoseconds. + Weight::from_parts(25_988_560, 3951) + // Standard Error: 57 + .saturating_add(Weight::from_parts(54_692, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 2).saturating_mul(c.into())) @@ -2204,10 +2175,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `707` // Estimated: `21400 + c * (5 ±0)` - // Minimum execution time: 265_835_000 picoseconds. - Weight::from_parts(275_985_164, 21400) - // Standard Error: 36 - .saturating_add(Weight::from_parts(37_980, 0).saturating_mul(c.into())) + // Minimum execution time: 263_107_000 picoseconds. + Weight::from_parts(268_289_665, 21400) + // Standard Error: 33 + .saturating_add(Weight::from_parts(38_534, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 5).saturating_mul(c.into())) @@ -2235,14 +2206,14 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `270` // Estimated: `26207` - // Minimum execution time: 3_124_508_000 picoseconds. - Weight::from_parts(617_467_897, 26207) - // Standard Error: 293 - .saturating_add(Weight::from_parts(106_971, 0).saturating_mul(c.into())) - // Standard Error: 17 - .saturating_add(Weight::from_parts(1_156, 0).saturating_mul(i.into())) - // Standard Error: 17 - .saturating_add(Weight::from_parts(1_395, 0).saturating_mul(s.into())) + // Minimum execution time: 3_122_319_000 picoseconds. + Weight::from_parts(487_802_180, 26207) + // Standard Error: 345 + .saturating_add(Weight::from_parts(108_237, 0).saturating_mul(c.into())) + // Standard Error: 20 + .saturating_add(Weight::from_parts(1_166, 0).saturating_mul(i.into())) + // Standard Error: 20 + .saturating_add(Weight::from_parts(1_505, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(10_u64)) } @@ -2266,12 +2237,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `482` // Estimated: `28521` - // Minimum execution time: 1_649_483_000 picoseconds. - Weight::from_parts(287_642_416, 28521) + // Minimum execution time: 1_650_623_000 picoseconds. + Weight::from_parts(286_494_456, 28521) // Standard Error: 8 - .saturating_add(Weight::from_parts(1_450, 0).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(1_438, 0).saturating_mul(i.into())) // Standard Error: 8 - .saturating_add(Weight::from_parts(1_443, 0).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_453, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } @@ -2289,8 +2260,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `759` // Estimated: `21615` - // Minimum execution time: 192_302_000 picoseconds. - Weight::from_parts(193_192_000, 21615) + // Minimum execution time: 191_046_000 picoseconds. + Weight::from_parts(192_544_000, 21615) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -2307,10 +2278,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `109` // Estimated: `7366` - // Minimum execution time: 246_401_000 picoseconds. - Weight::from_parts(261_505_456, 7366) - // Standard Error: 83 - .saturating_add(Weight::from_parts(109_136, 0).saturating_mul(c.into())) + // Minimum execution time: 244_260_000 picoseconds. + Weight::from_parts(254_693_985, 7366) + // Standard Error: 80 + .saturating_add(Weight::from_parts(108_246, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -2326,8 +2297,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `255` // Estimated: `7950` - // Minimum execution time: 33_913_000 picoseconds. - Weight::from_parts(34_186_000, 7950) + // Minimum execution time: 33_492_000 picoseconds. + Weight::from_parts(34_079_000, 7950) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -2341,8 +2312,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `570` // Estimated: `19530` - // Minimum execution time: 33_801_000 picoseconds. - Weight::from_parts(34_877_000, 19530) + // Minimum execution time: 33_475_000 picoseconds. + Weight::from_parts(33_856_000, 19530) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -2361,10 +2332,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `781 + r * (6 ±0)` // Estimated: `21730 + r * (30 ±0)` - // Minimum execution time: 237_679_000 picoseconds. - Weight::from_parts(243_022_905, 21730) - // Standard Error: 940 - .saturating_add(Weight::from_parts(324_389, 0).saturating_mul(r.into())) + // Minimum execution time: 234_197_000 picoseconds. + Weight::from_parts(236_830_305, 21730) + // Standard Error: 818 + .saturating_add(Weight::from_parts(336_446, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -2384,10 +2355,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `839 + r * (240 ±0)` // Estimated: `21835 + r * (3675 ±0)` - // Minimum execution time: 235_635_000 picoseconds. - Weight::from_parts(76_942_144, 21835) - // Standard Error: 6_214 - .saturating_add(Weight::from_parts(3_328_756, 0).saturating_mul(r.into())) + // Minimum execution time: 235_872_000 picoseconds. + Weight::from_parts(78_877_890, 21835) + // Standard Error: 6_405 + .saturating_add(Weight::from_parts(3_358_341, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -2408,10 +2379,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `831 + r * (244 ±0)` // Estimated: `21855 + r * (3695 ±0)` - // Minimum execution time: 237_123_000 picoseconds. - Weight::from_parts(77_880_739, 21855) - // Standard Error: 5_970 - .saturating_add(Weight::from_parts(4_103_281, 0).saturating_mul(r.into())) + // Minimum execution time: 239_035_000 picoseconds. + Weight::from_parts(93_255_085, 21855) + // Standard Error: 5_922 + .saturating_add(Weight::from_parts(4_144_910, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -2432,10 +2403,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `788 + r * (6 ±0)` // Estimated: `21770 + r * (30 ±0)` - // Minimum execution time: 236_621_000 picoseconds. - Weight::from_parts(238_240_015, 21770) - // Standard Error: 742 - .saturating_add(Weight::from_parts(404_691, 0).saturating_mul(r.into())) + // Minimum execution time: 236_507_000 picoseconds. + Weight::from_parts(238_253_211, 21770) + // Standard Error: 975 + .saturating_add(Weight::from_parts(413_919, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -2455,10 +2426,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `778 + r * (3 ±0)` // Estimated: `21735 + r * (15 ±0)` - // Minimum execution time: 233_274_000 picoseconds. - Weight::from_parts(239_596_227, 21735) - // Standard Error: 551 - .saturating_add(Weight::from_parts(164_429, 0).saturating_mul(r.into())) + // Minimum execution time: 235_521_000 picoseconds. + Weight::from_parts(238_397_362, 21735) + // Standard Error: 452 + .saturating_add(Weight::from_parts(160_860, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 15).saturating_mul(r.into())) @@ -2478,10 +2449,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `782 + r * (6 ±0)` // Estimated: `21740 + r * (30 ±0)` - // Minimum execution time: 235_661_000 picoseconds. - Weight::from_parts(239_063_406, 21740) - // Standard Error: 933 - .saturating_add(Weight::from_parts(327_679, 0).saturating_mul(r.into())) + // Minimum execution time: 234_722_000 picoseconds. + Weight::from_parts(242_936_096, 21740) + // Standard Error: 1_178 + .saturating_add(Weight::from_parts(329_075, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -2501,10 +2472,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `783 + r * (6 ±0)` // Estimated: `21725 + r * (30 ±0)` - // Minimum execution time: 235_583_000 picoseconds. - Weight::from_parts(251_641_549, 21725) - // Standard Error: 1_104 - .saturating_add(Weight::from_parts(315_873, 0).saturating_mul(r.into())) + // Minimum execution time: 235_654_000 picoseconds. + Weight::from_parts(245_887_792, 21725) + // Standard Error: 903 + .saturating_add(Weight::from_parts(325_168, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -2524,10 +2495,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `922 + r * (6 ±0)` // Estimated: `24633 + r * (30 ±0)` - // Minimum execution time: 235_325_000 picoseconds. - Weight::from_parts(256_582_010, 24633) - // Standard Error: 1_349 - .saturating_add(Weight::from_parts(1_483_116, 0).saturating_mul(r.into())) + // Minimum execution time: 233_599_000 picoseconds. + Weight::from_parts(251_561_602, 24633) + // Standard Error: 3_348 + .saturating_add(Weight::from_parts(1_475_443, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -2547,10 +2518,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `792 + r * (6 ±0)` // Estimated: `21825 + r * (30 ±0)` - // Minimum execution time: 235_358_000 picoseconds. - Weight::from_parts(233_421_484, 21825) - // Standard Error: 1_178 - .saturating_add(Weight::from_parts(337_947, 0).saturating_mul(r.into())) + // Minimum execution time: 235_087_000 picoseconds. + Weight::from_parts(235_855_322, 21825) + // Standard Error: 867 + .saturating_add(Weight::from_parts(346_707, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -2570,10 +2541,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `790 + r * (6 ±0)` // Estimated: `21815 + r * (30 ±0)` - // Minimum execution time: 236_570_000 picoseconds. - Weight::from_parts(245_853_078, 21815) - // Standard Error: 1_947 - .saturating_add(Weight::from_parts(319_972, 0).saturating_mul(r.into())) + // Minimum execution time: 237_103_000 picoseconds. + Weight::from_parts(239_272_188, 21815) + // Standard Error: 892 + .saturating_add(Weight::from_parts(328_334, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -2593,10 +2564,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `787 + r * (6 ±0)` // Estimated: `21805 + r * (30 ±0)` - // Minimum execution time: 235_027_000 picoseconds. - Weight::from_parts(239_719_689, 21805) - // Standard Error: 654 - .saturating_add(Weight::from_parts(326_988, 0).saturating_mul(r.into())) + // Minimum execution time: 234_761_000 picoseconds. + Weight::from_parts(238_601_784, 21805) + // Standard Error: 725 + .saturating_add(Weight::from_parts(325_758, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -2616,10 +2587,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `778 + r * (6 ±0)` // Estimated: `21735 + r * (30 ±0)` - // Minimum execution time: 236_547_000 picoseconds. - Weight::from_parts(239_390_326, 21735) - // Standard Error: 912 - .saturating_add(Weight::from_parts(327_495, 0).saturating_mul(r.into())) + // Minimum execution time: 235_249_000 picoseconds. + Weight::from_parts(239_861_242, 21735) + // Standard Error: 751 + .saturating_add(Weight::from_parts(325_795, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -2641,10 +2612,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `856 + r * (10 ±0)` // Estimated: `24446 + r * (60 ±0)` - // Minimum execution time: 235_710_000 picoseconds. - Weight::from_parts(238_998_789, 24446) - // Standard Error: 2_055 - .saturating_add(Weight::from_parts(1_373_992, 0).saturating_mul(r.into())) + // Minimum execution time: 234_912_000 picoseconds. + Weight::from_parts(254_783_734, 24446) + // Standard Error: 1_610 + .saturating_add(Weight::from_parts(1_307_506, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 60).saturating_mul(r.into())) @@ -2664,10 +2635,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `745 + r * (4 ±0)` // Estimated: `21555 + r * (20 ±0)` - // Minimum execution time: 161_133_000 picoseconds. - Weight::from_parts(167_097_346, 21555) - // Standard Error: 245 - .saturating_add(Weight::from_parts(128_503, 0).saturating_mul(r.into())) + // Minimum execution time: 160_125_000 picoseconds. + Weight::from_parts(164_915_574, 21555) + // Standard Error: 332 + .saturating_add(Weight::from_parts(132_326, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 20).saturating_mul(r.into())) @@ -2687,10 +2658,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `780 + r * (6 ±0)` // Estimated: `21740 + r * (30 ±0)` - // Minimum execution time: 234_790_000 picoseconds. - Weight::from_parts(242_392_710, 21740) - // Standard Error: 2_506 - .saturating_add(Weight::from_parts(273_470, 0).saturating_mul(r.into())) + // Minimum execution time: 234_717_000 picoseconds. + Weight::from_parts(238_540_521, 21740) + // Standard Error: 599 + .saturating_add(Weight::from_parts(277_303, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -2710,10 +2681,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `784` // Estimated: `21740` - // Minimum execution time: 236_837_000 picoseconds. - Weight::from_parts(237_860_073, 21740) - // Standard Error: 2 - .saturating_add(Weight::from_parts(602, 0).saturating_mul(n.into())) + // Minimum execution time: 235_792_000 picoseconds. + Weight::from_parts(244_114_692, 21740) + // Standard Error: 1 + .saturating_add(Weight::from_parts(589, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -2732,10 +2703,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `768 + r * (45 ±0)` // Estimated: `21660 + r * (225 ±0)` - // Minimum execution time: 232_047_000 picoseconds. - Weight::from_parts(234_629_293, 21660) - // Standard Error: 171_808 - .saturating_add(Weight::from_parts(663_306, 0).saturating_mul(r.into())) + // Minimum execution time: 231_166_000 picoseconds. + Weight::from_parts(233_339_177, 21660) + // Standard Error: 155_889 + .saturating_add(Weight::from_parts(3_124_322, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 225).saturating_mul(r.into())) @@ -2755,10 +2726,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `778` // Estimated: `21775` - // Minimum execution time: 235_035_000 picoseconds. - Weight::from_parts(234_442_091, 21775) + // Minimum execution time: 235_721_000 picoseconds. + Weight::from_parts(237_413_703, 21775) // Standard Error: 1 - .saturating_add(Weight::from_parts(185, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(177, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -2770,26 +2741,28 @@ impl WeightInfo for () { /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) /// Storage: Timestamp Now (r:1 w:0) /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) - /// Storage: Contracts DeletionQueue (r:1 w:1) - /// Proof: Contracts DeletionQueue (max_values: Some(1), max_size: Some(16642), added: 17137, mode: Measured) + /// Storage: Contracts DeletionQueueCounter (r:1 w:1) + /// Proof: Contracts DeletionQueueCounter (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: Contracts OwnerInfoOf (r:1 w:1) /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Measured) /// Storage: System EventTopics (r:3 w:3) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) + /// Storage: Contracts DeletionQueue (r:0 w:1) + /// Proof: Contracts DeletionQueue (max_values: None, max_size: Some(142), added: 2617, mode: Measured) /// The range of component `r` is `[0, 1]`. fn seal_terminate(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `810 + r * (356 ±0)` - // Estimated: `25511 + r * (15321 ±0)` - // Minimum execution time: 234_140_000 picoseconds. - Weight::from_parts(236_805_906, 25511) - // Standard Error: 435_181 - .saturating_add(Weight::from_parts(118_144_693, 0).saturating_mul(r.into())) + // Estimated: `26094 + r * (15904 ±0)` + // Minimum execution time: 233_525_000 picoseconds. + Weight::from_parts(235_871_034, 26094) + // Standard Error: 235_338 + .saturating_add(Weight::from_parts(118_659_865, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((6_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(RocksDbWeight::get().writes((7_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 15321).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().writes((8_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_parts(0, 15904).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2808,10 +2781,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `825 + r * (10 ±0)` // Estimated: `24283 + r * (60 ±0)` - // Minimum execution time: 235_271_000 picoseconds. - Weight::from_parts(256_019_682, 24283) - // Standard Error: 2_016 - .saturating_add(Weight::from_parts(1_862_085, 0).saturating_mul(r.into())) + // Minimum execution time: 235_007_000 picoseconds. + Weight::from_parts(248_419_686, 24283) + // Standard Error: 1_847 + .saturating_add(Weight::from_parts(1_815_822, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 60).saturating_mul(r.into())) @@ -2831,10 +2804,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `778 + r * (10 ±0)` // Estimated: `21735 + r * (50 ±0)` - // Minimum execution time: 233_092_000 picoseconds. - Weight::from_parts(248_483_473, 21735) - // Standard Error: 2_182 - .saturating_add(Weight::from_parts(3_551_674, 0).saturating_mul(r.into())) + // Minimum execution time: 232_912_000 picoseconds. + Weight::from_parts(256_142_885, 21735) + // Standard Error: 2_741 + .saturating_add(Weight::from_parts(3_542_482, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 50).saturating_mul(r.into())) @@ -2855,12 +2828,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `797 + t * (32 ±0)` // Estimated: `21840 + t * (2640 ±0)` - // Minimum execution time: 252_307_000 picoseconds. - Weight::from_parts(245_237_726, 21840) - // Standard Error: 79_824 - .saturating_add(Weight::from_parts(2_364_618, 0).saturating_mul(t.into())) - // Standard Error: 22 - .saturating_add(Weight::from_parts(636, 0).saturating_mul(n.into())) + // Minimum execution time: 251_018_000 picoseconds. + Weight::from_parts(245_280_765, 21840) + // Standard Error: 90_317 + .saturating_add(Weight::from_parts(2_434_496, 0).saturating_mul(t.into())) + // Standard Error: 25 + .saturating_add(Weight::from_parts(599, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(t.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -2882,10 +2855,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `777 + r * (7 ±0)` // Estimated: `21725 + r * (35 ±0)` - // Minimum execution time: 165_367_000 picoseconds. - Weight::from_parts(170_164_725, 21725) - // Standard Error: 487 - .saturating_add(Weight::from_parts(237_281, 0).saturating_mul(r.into())) + // Minimum execution time: 164_022_000 picoseconds. + Weight::from_parts(168_658_387, 21725) + // Standard Error: 685 + .saturating_add(Weight::from_parts(238_133, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 35).saturating_mul(r.into())) @@ -2905,10 +2878,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `125728` // Estimated: `269977` - // Minimum execution time: 350_914_000 picoseconds. - Weight::from_parts(354_461_646, 269977) - // Standard Error: 1 - .saturating_add(Weight::from_parts(747, 0).saturating_mul(i.into())) + // Minimum execution time: 351_043_000 picoseconds. + Weight::from_parts(353_707_344, 269977) + // Standard Error: 3 + .saturating_add(Weight::from_parts(752, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -2919,10 +2892,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `845 + r * (292 ±0)` // Estimated: `843 + r * (293 ±0)` - // Minimum execution time: 236_273_000 picoseconds. - Weight::from_parts(137_922_946, 843) - // Standard Error: 10_363 - .saturating_add(Weight::from_parts(6_034_776, 0).saturating_mul(r.into())) + // Minimum execution time: 235_854_000 picoseconds. + Weight::from_parts(133_986_225, 843) + // Standard Error: 9_550 + .saturating_add(Weight::from_parts(6_093_051, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -2936,10 +2909,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1304` // Estimated: `1280` - // Minimum execution time: 251_462_000 picoseconds. - Weight::from_parts(287_009_907, 1280) - // Standard Error: 62 - .saturating_add(Weight::from_parts(384, 0).saturating_mul(n.into())) + // Minimum execution time: 252_321_000 picoseconds. + Weight::from_parts(285_820_577, 1280) + // Standard Error: 60 + .saturating_add(Weight::from_parts(600, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -2950,10 +2923,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1167 + n * (1 ±0)` // Estimated: `1167 + n * (1 ±0)` - // Minimum execution time: 250_985_000 picoseconds. - Weight::from_parts(253_693_249, 1167) - // Standard Error: 21 - .saturating_add(Weight::from_parts(92, 0).saturating_mul(n.into())) + // Minimum execution time: 252_047_000 picoseconds. + Weight::from_parts(254_244_310, 1167) + // Standard Error: 15 + .saturating_add(Weight::from_parts(144, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -2965,10 +2938,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `841 + r * (288 ±0)` // Estimated: `845 + r * (289 ±0)` - // Minimum execution time: 235_462_000 picoseconds. - Weight::from_parts(141_240_297, 845) - // Standard Error: 9_687 - .saturating_add(Weight::from_parts(5_906_737, 0).saturating_mul(r.into())) + // Minimum execution time: 235_697_000 picoseconds. + Weight::from_parts(143_200_942, 845) + // Standard Error: 11_358 + .saturating_add(Weight::from_parts(5_934_318, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -2982,10 +2955,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1163 + n * (1 ±0)` // Estimated: `1163 + n * (1 ±0)` - // Minimum execution time: 250_887_000 picoseconds. - Weight::from_parts(253_321_064, 1163) - // Standard Error: 28 - .saturating_add(Weight::from_parts(169, 0).saturating_mul(n.into())) + // Minimum execution time: 250_360_000 picoseconds. + Weight::from_parts(252_712_722, 1163) + // Standard Error: 15 + .saturating_add(Weight::from_parts(130, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -2997,10 +2970,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `835 + r * (296 ±0)` // Estimated: `840 + r * (297 ±0)` - // Minimum execution time: 236_542_000 picoseconds. - Weight::from_parts(147_992_508, 840) - // Standard Error: 8_849 - .saturating_add(Weight::from_parts(4_946_692, 0).saturating_mul(r.into())) + // Minimum execution time: 235_613_000 picoseconds. + Weight::from_parts(150_213_792, 840) + // Standard Error: 8_617 + .saturating_add(Weight::from_parts(4_962_874, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3013,10 +2986,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1179 + n * (1 ±0)` // Estimated: `1179 + n * (1 ±0)` - // Minimum execution time: 249_987_000 picoseconds. - Weight::from_parts(254_866_627, 1179) - // Standard Error: 53 - .saturating_add(Weight::from_parts(554, 0).saturating_mul(n.into())) + // Minimum execution time: 249_137_000 picoseconds. + Weight::from_parts(253_529_386, 1179) + // Standard Error: 41 + .saturating_add(Weight::from_parts(612, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -3028,10 +3001,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `856 + r * (288 ±0)` // Estimated: `857 + r * (289 ±0)` - // Minimum execution time: 236_635_000 picoseconds. - Weight::from_parts(157_805_789, 857) - // Standard Error: 7_699 - .saturating_add(Weight::from_parts(4_709_422, 0).saturating_mul(r.into())) + // Minimum execution time: 235_659_000 picoseconds. + Weight::from_parts(158_846_683, 857) + // Standard Error: 7_806 + .saturating_add(Weight::from_parts(4_728_537, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3044,10 +3017,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1166 + n * (1 ±0)` // Estimated: `1166 + n * (1 ±0)` - // Minimum execution time: 252_660_000 picoseconds. - Weight::from_parts(255_250_747, 1166) - // Standard Error: 14 - .saturating_add(Weight::from_parts(133, 0).saturating_mul(n.into())) + // Minimum execution time: 248_553_000 picoseconds. + Weight::from_parts(250_703_269, 1166) + // Standard Error: 17 + .saturating_add(Weight::from_parts(163, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -3059,10 +3032,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `829 + r * (296 ±0)` // Estimated: `836 + r * (297 ±0)` - // Minimum execution time: 240_198_000 picoseconds. - Weight::from_parts(133_188_357, 836) - // Standard Error: 10_661 - .saturating_add(Weight::from_parts(6_147_538, 0).saturating_mul(r.into())) + // Minimum execution time: 236_431_000 picoseconds. + Weight::from_parts(131_745_419, 836) + // Standard Error: 10_161 + .saturating_add(Weight::from_parts(6_182_174, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3076,10 +3049,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1180 + n * (1 ±0)` // Estimated: `1180 + n * (1 ±0)` - // Minimum execution time: 252_131_000 picoseconds. - Weight::from_parts(259_960_286, 1180) - // Standard Error: 121 - .saturating_add(Weight::from_parts(192, 0).saturating_mul(n.into())) + // Minimum execution time: 252_551_000 picoseconds. + Weight::from_parts(254_517_030, 1180) + // Standard Error: 16 + .saturating_add(Weight::from_parts(712, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -3099,10 +3072,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1373 + r * (45 ±0)` // Estimated: `26753 + r * (2700 ±0)` - // Minimum execution time: 235_860_000 picoseconds. - Weight::from_parts(124_993_651, 26753) - // Standard Error: 22_811 - .saturating_add(Weight::from_parts(36_467_740, 0).saturating_mul(r.into())) + // Minimum execution time: 236_663_000 picoseconds. + Weight::from_parts(237_485_000, 26753) + // Standard Error: 42_414 + .saturating_add(Weight::from_parts(36_849_514, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(4_u64)) @@ -3124,10 +3097,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1237 + r * (256 ±0)` // Estimated: `26028 + r * (6235 ±0)` - // Minimum execution time: 237_221_000 picoseconds. - Weight::from_parts(237_632_000, 26028) - // Standard Error: 89_502 - .saturating_add(Weight::from_parts(212_211_534, 0).saturating_mul(r.into())) + // Minimum execution time: 237_101_000 picoseconds. + Weight::from_parts(237_827_000, 26028) + // Standard Error: 82_878 + .saturating_add(Weight::from_parts(211_777_724, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3149,10 +3122,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0 + r * (502 ±0)` // Estimated: `21755 + r * (6329 ±3)` - // Minimum execution time: 236_965_000 picoseconds. - Weight::from_parts(238_110_000, 21755) - // Standard Error: 101_332 - .saturating_add(Weight::from_parts(206_790_203, 0).saturating_mul(r.into())) + // Minimum execution time: 241_213_000 picoseconds. + Weight::from_parts(241_900_000, 21755) + // Standard Error: 99_976 + .saturating_add(Weight::from_parts(207_520_077, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3175,12 +3148,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1154 + t * (204 ±0)` // Estimated: `31015 + t * (5970 ±0)` - // Minimum execution time: 411_974_000 picoseconds. - Weight::from_parts(391_387_689, 31015) - // Standard Error: 1_320_695 - .saturating_add(Weight::from_parts(29_766_122, 0).saturating_mul(t.into())) + // Minimum execution time: 414_784_000 picoseconds. + Weight::from_parts(384_902_379, 31015) + // Standard Error: 1_228_593 + .saturating_add(Weight::from_parts(33_226_901, 0).saturating_mul(t.into())) // Standard Error: 1 - .saturating_add(Weight::from_parts(597, 0).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(601, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(t.into()))) .saturating_add(RocksDbWeight::get().writes(5_u64)) @@ -3206,10 +3179,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1301 + r * (254 ±0)` // Estimated: `30977 + r * (16635 ±0)` - // Minimum execution time: 237_595_000 picoseconds. - Weight::from_parts(238_068_000, 30977) - // Standard Error: 254_409 - .saturating_add(Weight::from_parts(346_436_154, 0).saturating_mul(r.into())) + // Minimum execution time: 236_963_000 picoseconds. + Weight::from_parts(237_711_000, 30977) + // Standard Error: 265_576 + .saturating_add(Weight::from_parts(347_359_908, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().reads((6_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(6_u64)) @@ -3237,14 +3210,14 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1071 + t * (187 ±0)` // Estimated: `42684 + t * (3588 ±2)` - // Minimum execution time: 1_616_768_000 picoseconds. - Weight::from_parts(363_003_254, 42684) - // Standard Error: 4_398_669 - .saturating_add(Weight::from_parts(104_529_967, 0).saturating_mul(t.into())) + // Minimum execution time: 1_615_191_000 picoseconds. + Weight::from_parts(337_408_450, 42684) + // Standard Error: 4_581_951 + .saturating_add(Weight::from_parts(115_730_776, 0).saturating_mul(t.into())) // Standard Error: 7 - .saturating_add(Weight::from_parts(1_162, 0).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(1_171, 0).saturating_mul(i.into())) // Standard Error: 7 - .saturating_add(Weight::from_parts(1_333, 0).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_346, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(13_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(t.into()))) .saturating_add(RocksDbWeight::get().writes(10_u64)) @@ -3266,10 +3239,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `777 + r * (8 ±0)` // Estimated: `21710 + r * (40 ±0)` - // Minimum execution time: 233_814_000 picoseconds. - Weight::from_parts(241_291_041, 21710) - // Standard Error: 1_422 - .saturating_add(Weight::from_parts(575_846, 0).saturating_mul(r.into())) + // Minimum execution time: 233_601_000 picoseconds. + Weight::from_parts(246_594_905, 21710) + // Standard Error: 2_840 + .saturating_add(Weight::from_parts(578_751, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) @@ -3289,10 +3262,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `785` // Estimated: `21745` - // Minimum execution time: 236_572_000 picoseconds. - Weight::from_parts(235_648_055, 21745) + // Minimum execution time: 233_735_000 picoseconds. + Weight::from_parts(243_432_330, 21745) // Standard Error: 3 - .saturating_add(Weight::from_parts(3_947, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(3_927, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3311,10 +3284,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `779 + r * (8 ±0)` // Estimated: `21725 + r * (40 ±0)` - // Minimum execution time: 234_473_000 picoseconds. - Weight::from_parts(239_805_309, 21725) - // Standard Error: 1_113 - .saturating_add(Weight::from_parts(752_507, 0).saturating_mul(r.into())) + // Minimum execution time: 232_173_000 picoseconds. + Weight::from_parts(239_806_011, 21725) + // Standard Error: 1_530 + .saturating_add(Weight::from_parts(749_641, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) @@ -3334,10 +3307,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `787` // Estimated: `21765` - // Minimum execution time: 235_209_000 picoseconds. - Weight::from_parts(228_548_524, 21765) + // Minimum execution time: 235_046_000 picoseconds. + Weight::from_parts(229_500_792, 21765) // Standard Error: 2 - .saturating_add(Weight::from_parts(3_171, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(3_166, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3356,10 +3329,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `779 + r * (8 ±0)` // Estimated: `21740 + r * (40 ±0)` - // Minimum execution time: 233_282_000 picoseconds. - Weight::from_parts(240_864_680, 21740) - // Standard Error: 958 - .saturating_add(Weight::from_parts(418_308, 0).saturating_mul(r.into())) + // Minimum execution time: 231_708_000 picoseconds. + Weight::from_parts(235_347_566, 21740) + // Standard Error: 987 + .saturating_add(Weight::from_parts(428_819, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) @@ -3379,10 +3352,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `787` // Estimated: `21785` - // Minimum execution time: 234_667_000 picoseconds. - Weight::from_parts(227_810_077, 21785) - // Standard Error: 2 - .saturating_add(Weight::from_parts(925, 0).saturating_mul(n.into())) + // Minimum execution time: 234_068_000 picoseconds. + Weight::from_parts(226_519_852, 21785) + // Standard Error: 1 + .saturating_add(Weight::from_parts(916, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3401,10 +3374,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `779 + r * (8 ±0)` // Estimated: `21745 + r * (40 ±0)` - // Minimum execution time: 234_040_000 picoseconds. - Weight::from_parts(237_970_694, 21745) - // Standard Error: 979 - .saturating_add(Weight::from_parts(416_562, 0).saturating_mul(r.into())) + // Minimum execution time: 231_872_000 picoseconds. + Weight::from_parts(236_694_763, 21745) + // Standard Error: 870 + .saturating_add(Weight::from_parts(420_853, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) @@ -3424,10 +3397,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `787` // Estimated: `21755` - // Minimum execution time: 234_840_000 picoseconds. - Weight::from_parts(227_849_778, 21755) + // Minimum execution time: 233_707_000 picoseconds. + Weight::from_parts(226_312_559, 21755) // Standard Error: 2 - .saturating_add(Weight::from_parts(923, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(924, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3446,10 +3419,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `822 + r * (76 ±0)` // Estimated: `21705 + r * (385 ±0)` - // Minimum execution time: 236_174_000 picoseconds. - Weight::from_parts(252_457_690, 21705) - // Standard Error: 20_130 - .saturating_add(Weight::from_parts(37_792_805, 0).saturating_mul(r.into())) + // Minimum execution time: 234_962_000 picoseconds. + Weight::from_parts(252_611_292, 21705) + // Standard Error: 20_134 + .saturating_add(Weight::from_parts(37_745_358, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 385).saturating_mul(r.into())) @@ -3468,11 +3441,11 @@ impl WeightInfo for () { fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `792 + r * (42 ±0)` - // Estimated: `21780 + r * (210 ±0)` - // Minimum execution time: 236_251_000 picoseconds. - Weight::from_parts(242_254_305, 21780) - // Standard Error: 9_765 - .saturating_add(Weight::from_parts(9_341_334, 0).saturating_mul(r.into())) + // Estimated: `21775 + r * (210 ±0)` + // Minimum execution time: 234_869_000 picoseconds. + Weight::from_parts(240_188_331, 21775) + // Standard Error: 9_910 + .saturating_add(Weight::from_parts(9_332_432, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 210).saturating_mul(r.into())) @@ -3493,11 +3466,11 @@ impl WeightInfo for () { fn seal_set_code_hash(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + r * (964 ±0)` - // Estimated: `29920 + r * (11544 ±7)` - // Minimum execution time: 236_462_000 picoseconds. - Weight::from_parts(236_997_000, 29920) - // Standard Error: 46_527 - .saturating_add(Weight::from_parts(21_858_761, 0).saturating_mul(r.into())) + // Estimated: `29920 + r * (11544 ±10)` + // Minimum execution time: 235_036_000 picoseconds. + Weight::from_parts(235_538_000, 29920) + // Standard Error: 47_360 + .saturating_add(Weight::from_parts(22_113_144, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3519,10 +3492,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `773 + r * (3 ±0)` // Estimated: `21735 + r * (15 ±0)` - // Minimum execution time: 235_085_000 picoseconds. - Weight::from_parts(239_410_836, 21735) - // Standard Error: 414 - .saturating_add(Weight::from_parts(167_067, 0).saturating_mul(r.into())) + // Minimum execution time: 237_884_000 picoseconds. + Weight::from_parts(243_315_095, 21735) + // Standard Error: 560 + .saturating_add(Weight::from_parts(162_206, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 15).saturating_mul(r.into())) @@ -3542,10 +3515,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1975 + r * (39 ±0)` // Estimated: `27145 + r * (200 ±0)` - // Minimum execution time: 236_690_000 picoseconds. - Weight::from_parts(268_793_030, 27145) - // Standard Error: 1_210 - .saturating_add(Weight::from_parts(263_330, 0).saturating_mul(r.into())) + // Minimum execution time: 239_402_000 picoseconds. + Weight::from_parts(267_214_783, 27145) + // Standard Error: 1_166 + .saturating_add(Weight::from_parts(261_915, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 200).saturating_mul(r.into())) @@ -3567,10 +3540,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `776 + r * (3 ±0)` // Estimated: `24004 + r * (18 ±0)` - // Minimum execution time: 236_289_000 picoseconds. - Weight::from_parts(246_581_099, 24004) - // Standard Error: 1_300 - .saturating_add(Weight::from_parts(137_499, 0).saturating_mul(r.into())) + // Minimum execution time: 233_153_000 picoseconds. + Weight::from_parts(238_999_965, 24004) + // Standard Error: 291 + .saturating_add(Weight::from_parts(143_971, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 18).saturating_mul(r.into())) @@ -3580,9 +3553,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_679_000 picoseconds. - Weight::from_parts(1_934_194, 0) - // Standard Error: 1 + // Minimum execution time: 1_706_000 picoseconds. + Weight::from_parts(1_962_558, 0) + // Standard Error: 2 .saturating_add(Weight::from_parts(3_000, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. @@ -3590,499 +3563,499 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_872_000 picoseconds. - Weight::from_parts(2_605_712, 0) - // Standard Error: 43 - .saturating_add(Weight::from_parts(6_321, 0).saturating_mul(r.into())) + // Minimum execution time: 1_870_000 picoseconds. + Weight::from_parts(2_481_243, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(6_346, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64store(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_837_000 picoseconds. - Weight::from_parts(2_035_143, 0) - // Standard Error: 65 - .saturating_add(Weight::from_parts(6_202, 0).saturating_mul(r.into())) + // Minimum execution time: 1_830_000 picoseconds. + Weight::from_parts(2_389_658, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(5_997, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_select(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_684_000 picoseconds. - Weight::from_parts(2_044_218, 0) - // Standard Error: 5 - .saturating_add(Weight::from_parts(7_929, 0).saturating_mul(r.into())) + // Minimum execution time: 1_734_000 picoseconds. + Weight::from_parts(2_170_618, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(7_919, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_if(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_635_000 picoseconds. - Weight::from_parts(2_009_851, 0) - // Standard Error: 6 - .saturating_add(Weight::from_parts(10_724, 0).saturating_mul(r.into())) + // Minimum execution time: 1_661_000 picoseconds. + Weight::from_parts(1_945_771, 0) + // Standard Error: 11 + .saturating_add(Weight::from_parts(10_840, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_br(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_667_000 picoseconds. - Weight::from_parts(1_869_395, 0) - // Standard Error: 12 - .saturating_add(Weight::from_parts(4_618, 0).saturating_mul(r.into())) + // Minimum execution time: 1_682_000 picoseconds. + Weight::from_parts(1_970_774, 0) + // Standard Error: 11 + .saturating_add(Weight::from_parts(4_569, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_br_if(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_698_000 picoseconds. - Weight::from_parts(2_184_182, 0) - // Standard Error: 16 - .saturating_add(Weight::from_parts(6_833, 0).saturating_mul(r.into())) + // Minimum execution time: 1_668_000 picoseconds. + Weight::from_parts(1_227_080, 0) + // Standard Error: 76 + .saturating_add(Weight::from_parts(8_066, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_br_table(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_670_000 picoseconds. - Weight::from_parts(1_471_988, 0) - // Standard Error: 30 - .saturating_add(Weight::from_parts(9_550, 0).saturating_mul(r.into())) + // Minimum execution time: 1_653_000 picoseconds. + Weight::from_parts(1_394_759, 0) + // Standard Error: 39 + .saturating_add(Weight::from_parts(9_566, 0).saturating_mul(r.into())) } /// The range of component `e` is `[1, 256]`. fn instr_br_table_per_entry(e: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_778_000 picoseconds. - Weight::from_parts(1_925_086, 0) - // Standard Error: 136 - .saturating_add(Weight::from_parts(502, 0).saturating_mul(e.into())) + // Minimum execution time: 1_771_000 picoseconds. + Weight::from_parts(1_905_594, 0) + // Standard Error: 147 + .saturating_add(Weight::from_parts(925, 0).saturating_mul(e.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_call(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_759_000 picoseconds. - Weight::from_parts(2_372_048, 0) - // Standard Error: 16 - .saturating_add(Weight::from_parts(17_953, 0).saturating_mul(r.into())) + // Minimum execution time: 1_863_000 picoseconds. + Weight::from_parts(2_472_635, 0) + // Standard Error: 13 + .saturating_add(Weight::from_parts(17_892, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_call_indirect(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_852_000 picoseconds. - Weight::from_parts(3_125_003, 0) - // Standard Error: 25 - .saturating_add(Weight::from_parts(24_218, 0).saturating_mul(r.into())) + // Minimum execution time: 2_013_000 picoseconds. + Weight::from_parts(3_077_100, 0) + // Standard Error: 18 + .saturating_add(Weight::from_parts(24_287, 0).saturating_mul(r.into())) } /// The range of component `l` is `[0, 1024]`. fn instr_call_per_local(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_795_000 picoseconds. - Weight::from_parts(2_121_763, 0) - // Standard Error: 45 - .saturating_add(Weight::from_parts(1_207, 0).saturating_mul(l.into())) + // Minimum execution time: 1_818_000 picoseconds. + Weight::from_parts(2_109_143, 0) + // Standard Error: 34 + .saturating_add(Weight::from_parts(1_249, 0).saturating_mul(l.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_local_get(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_019_000 picoseconds. - Weight::from_parts(3_267_108, 0) - // Standard Error: 55 - .saturating_add(Weight::from_parts(2_527, 0).saturating_mul(r.into())) + // Minimum execution time: 3_083_000 picoseconds. + Weight::from_parts(3_291_328, 0) + // Standard Error: 1 + .saturating_add(Weight::from_parts(2_505, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_local_set(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_944_000 picoseconds. - Weight::from_parts(3_183_331, 0) + // Minimum execution time: 2_987_000 picoseconds. + Weight::from_parts(3_276_863, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(3_618, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_617, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_local_tee(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_009_000 picoseconds. - Weight::from_parts(3_178_158, 0) - // Standard Error: 41 - .saturating_add(Weight::from_parts(4_075, 0).saturating_mul(r.into())) + // Minimum execution time: 2_942_000 picoseconds. + Weight::from_parts(3_350_581, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(3_976, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_global_get(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_748_000 picoseconds. - Weight::from_parts(2_371_911, 0) - // Standard Error: 10 - .saturating_add(Weight::from_parts(8_378, 0).saturating_mul(r.into())) + // Minimum execution time: 1_867_000 picoseconds. + Weight::from_parts(2_920_748, 0) + // Standard Error: 44 + .saturating_add(Weight::from_parts(8_229, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_global_set(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_795_000 picoseconds. - Weight::from_parts(1_311_997, 0) - // Standard Error: 157 - .saturating_add(Weight::from_parts(9_410, 0).saturating_mul(r.into())) + // Minimum execution time: 1_757_000 picoseconds. + Weight::from_parts(2_235_198, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(8_815, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_memory_current(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_059_000 picoseconds. - Weight::from_parts(2_416_611, 0) - // Standard Error: 5 - .saturating_add(Weight::from_parts(3_775, 0).saturating_mul(r.into())) + // Minimum execution time: 1_824_000 picoseconds. + Weight::from_parts(1_941_816, 0) + // Standard Error: 86 + .saturating_add(Weight::from_parts(4_043, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 16]`. fn instr_memory_grow(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_764_000 picoseconds. - Weight::from_parts(1_414_442, 0) - // Standard Error: 142_321 - .saturating_add(Weight::from_parts(13_210_495, 0).saturating_mul(r.into())) + // Minimum execution time: 1_793_000 picoseconds. + Weight::from_parts(1_104_829, 0) + // Standard Error: 137_800 + .saturating_add(Weight::from_parts(13_336_784, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64clz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_665_000 picoseconds. - Weight::from_parts(2_047_968, 0) + // Minimum execution time: 1_693_000 picoseconds. + Weight::from_parts(2_037_305, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(4_035, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(4_044, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64ctz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_696_000 picoseconds. - Weight::from_parts(2_101_548, 0) - // Standard Error: 13 - .saturating_add(Weight::from_parts(3_754, 0).saturating_mul(r.into())) + // Minimum execution time: 1_751_000 picoseconds. + Weight::from_parts(2_082_016, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(3_767, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64popcnt(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_686_000 picoseconds. - Weight::from_parts(2_023_482, 0) + // Minimum execution time: 1_751_000 picoseconds. + Weight::from_parts(2_110_625, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(3_770, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_754, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64eqz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_700_000 picoseconds. - Weight::from_parts(2_035_759, 0) + // Minimum execution time: 1_756_000 picoseconds. + Weight::from_parts(2_100_327, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(3_660, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_664, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64extendsi32(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_682_000 picoseconds. - Weight::from_parts(2_015_828, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(3_977, 0).saturating_mul(r.into())) + // Minimum execution time: 1_643_000 picoseconds. + Weight::from_parts(2_169_153, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(3_961, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64extendui32(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_660_000 picoseconds. - Weight::from_parts(2_032_387, 0) + // Minimum execution time: 1_704_000 picoseconds. + Weight::from_parts(2_049_172, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(3_826, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_833, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i32wrapi64(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_635_000 picoseconds. - Weight::from_parts(2_013_228, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(3_752, 0).saturating_mul(r.into())) + // Minimum execution time: 1_726_000 picoseconds. + Weight::from_parts(2_064_387, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(3_745, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64eq(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_698_000 picoseconds. - Weight::from_parts(2_844_817, 0) + // Minimum execution time: 1_696_000 picoseconds. + Weight::from_parts(2_426_905, 0) // Standard Error: 56 - .saturating_add(Weight::from_parts(5_746, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(5_915, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64ne(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_686_000 picoseconds. - Weight::from_parts(2_208_884, 0) - // Standard Error: 138 - .saturating_add(Weight::from_parts(6_032, 0).saturating_mul(r.into())) + // Minimum execution time: 1_617_000 picoseconds. + Weight::from_parts(2_035_161, 0) + // Standard Error: 94 + .saturating_add(Weight::from_parts(6_073, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64lts(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_695_000 picoseconds. - Weight::from_parts(2_060_880, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(5_966, 0).saturating_mul(r.into())) + // Minimum execution time: 1_756_000 picoseconds. + Weight::from_parts(2_098_926, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(6_002, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64ltu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_700_000 picoseconds. - Weight::from_parts(2_143_484, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(5_932, 0).saturating_mul(r.into())) + // Minimum execution time: 1_706_000 picoseconds. + Weight::from_parts(2_257_972, 0) + // Standard Error: 23 + .saturating_add(Weight::from_parts(5_982, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64gts(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_677_000 picoseconds. - Weight::from_parts(2_081_646, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(5_813, 0).saturating_mul(r.into())) + // Minimum execution time: 1_761_000 picoseconds. + Weight::from_parts(2_114_141, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(5_815, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64gtu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_476_000 picoseconds. - Weight::from_parts(2_161_801, 0) - // Standard Error: 4 - .saturating_add(Weight::from_parts(6_078, 0).saturating_mul(r.into())) + // Minimum execution time: 1_700_000 picoseconds. + Weight::from_parts(2_053_201, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(6_137, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64les(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_677_000 picoseconds. - Weight::from_parts(2_043_451, 0) + // Minimum execution time: 1_705_000 picoseconds. + Weight::from_parts(2_101_782, 0) // Standard Error: 3 - .saturating_add(Weight::from_parts(5_988, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(6_014, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64leu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_694_000 picoseconds. - Weight::from_parts(2_058_196, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(6_058, 0).saturating_mul(r.into())) + // Minimum execution time: 1_856_000 picoseconds. + Weight::from_parts(2_149_707, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(6_086, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64ges(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_675_000 picoseconds. - Weight::from_parts(2_036_798, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(5_956, 0).saturating_mul(r.into())) + // Minimum execution time: 1_739_000 picoseconds. + Weight::from_parts(2_143_216, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(5_934, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64geu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_712_000 picoseconds. - Weight::from_parts(2_121_407, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(5_944, 0).saturating_mul(r.into())) + // Minimum execution time: 1_716_000 picoseconds. + Weight::from_parts(2_065_762, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(6_009, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64add(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_675_000 picoseconds. - Weight::from_parts(2_061_053, 0) - // Standard Error: 6 - .saturating_add(Weight::from_parts(5_823, 0).saturating_mul(r.into())) + // Minimum execution time: 1_664_000 picoseconds. + Weight::from_parts(3_062_283, 0) + // Standard Error: 94 + .saturating_add(Weight::from_parts(5_645, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64sub(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_686_000 picoseconds. - Weight::from_parts(2_023_347, 0) - // Standard Error: 4 - .saturating_add(Weight::from_parts(6_126, 0).saturating_mul(r.into())) + // Minimum execution time: 1_671_000 picoseconds. + Weight::from_parts(2_011_145, 0) + // Standard Error: 44 + .saturating_add(Weight::from_parts(6_220, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64mul(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_678_000 picoseconds. - Weight::from_parts(2_390_920, 0) - // Standard Error: 55 - .saturating_add(Weight::from_parts(5_635, 0).saturating_mul(r.into())) + // Minimum execution time: 1_759_000 picoseconds. + Weight::from_parts(2_095_420, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(5_723, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64divs(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_728_000 picoseconds. - Weight::from_parts(1_944_457, 0) - // Standard Error: 7 - .saturating_add(Weight::from_parts(11_848, 0).saturating_mul(r.into())) + // Minimum execution time: 1_672_000 picoseconds. + Weight::from_parts(2_184_044, 0) + // Standard Error: 5 + .saturating_add(Weight::from_parts(11_782, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64divu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_649_000 picoseconds. - Weight::from_parts(1_881_148, 0) - // Standard Error: 6 - .saturating_add(Weight::from_parts(10_618, 0).saturating_mul(r.into())) + // Minimum execution time: 1_752_000 picoseconds. + Weight::from_parts(2_276_209, 0) + // Standard Error: 5 + .saturating_add(Weight::from_parts(10_513, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64rems(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_708_000 picoseconds. - Weight::from_parts(1_767_912, 0) - // Standard Error: 6 - .saturating_add(Weight::from_parts(12_099, 0).saturating_mul(r.into())) + // Minimum execution time: 1_711_000 picoseconds. + Weight::from_parts(2_720_989, 0) + // Standard Error: 24 + .saturating_add(Weight::from_parts(11_884, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64remu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_650_000 picoseconds. - Weight::from_parts(1_998_575, 0) + // Minimum execution time: 1_713_000 picoseconds. + Weight::from_parts(2_091_403, 0) // Standard Error: 3 - .saturating_add(Weight::from_parts(10_632, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(10_628, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64and(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_633_000 picoseconds. - Weight::from_parts(2_029_981, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(5_662, 0).saturating_mul(r.into())) + // Minimum execution time: 1_704_000 picoseconds. + Weight::from_parts(2_054_652, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(5_672, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64or(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_621_000 picoseconds. - Weight::from_parts(2_029_743, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(5_762, 0).saturating_mul(r.into())) + // Minimum execution time: 1_743_000 picoseconds. + Weight::from_parts(2_032_806, 0) + // Standard Error: 19 + .saturating_add(Weight::from_parts(5_795, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64xor(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_641_000 picoseconds. - Weight::from_parts(2_127_132, 0) + // Minimum execution time: 1_667_000 picoseconds. + Weight::from_parts(2_031_702, 0) // Standard Error: 5 - .saturating_add(Weight::from_parts(5_818, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(5_923, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64shl(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_690_000 picoseconds. - Weight::from_parts(2_021_035, 0) - // Standard Error: 4 - .saturating_add(Weight::from_parts(5_917, 0).saturating_mul(r.into())) + // Minimum execution time: 1_735_000 picoseconds. + Weight::from_parts(2_946_634, 0) + // Standard Error: 54 + .saturating_add(Weight::from_parts(5_685, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64shrs(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_661_000 picoseconds. - Weight::from_parts(2_055_069, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(6_094, 0).saturating_mul(r.into())) + // Minimum execution time: 1_652_000 picoseconds. + Weight::from_parts(2_023_049, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(6_146, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64shru(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_677_000 picoseconds. - Weight::from_parts(2_024_748, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(5_862, 0).saturating_mul(r.into())) + // Minimum execution time: 1_654_000 picoseconds. + Weight::from_parts(2_148_951, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(5_869, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64rotl(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_651_000 picoseconds. - Weight::from_parts(2_005_814, 0) + // Minimum execution time: 1_730_000 picoseconds. + Weight::from_parts(2_130_543, 0) // Standard Error: 3 - .saturating_add(Weight::from_parts(6_007, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(5_999, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64rotr(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_703_000 picoseconds. - Weight::from_parts(2_019_636, 0) + // Minimum execution time: 1_728_000 picoseconds. + Weight::from_parts(2_172_886, 0) // Standard Error: 3 - .saturating_add(Weight::from_parts(5_862, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(5_843, 0).saturating_mul(r.into())) } } From a7bc9c2a8c0a14fd6033de1f972a11a2b3dbb73a Mon Sep 17 00:00:00 2001 From: asynchronous rob Date: Fri, 31 Mar 2023 05:00:07 -0700 Subject: [PATCH 599/715] Refactor: extract most aura logic out to standalone module, make use of these (#13764) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Extract most aura logic out to standalone module, make use of these * Update client/consensus/aura/src/standalone.rs improve docs Co-authored-by: Bastian Köcher * add slot_duration_at * ".git/.scripts/commands/fmt/fmt.sh" --------- Co-authored-by: Bastian Köcher Co-authored-by: parity-processbot <> --- client/consensus/aura/src/import_queue.rs | 46 ++- client/consensus/aura/src/lib.rs | 127 +------- client/consensus/aura/src/standalone.rs | 357 ++++++++++++++++++++++ 3 files changed, 393 insertions(+), 137 deletions(-) create mode 100644 client/consensus/aura/src/standalone.rs diff --git a/client/consensus/aura/src/import_queue.rs b/client/consensus/aura/src/import_queue.rs index 46e0ccb4e302a..ef7a2a1cc865b 100644 --- a/client/consensus/aura/src/import_queue.rs +++ b/client/consensus/aura/src/import_queue.rs @@ -19,7 +19,7 @@ //! Module implementing the logic for verifying and importing AuRa blocks. use crate::{ - aura_err, authorities, find_pre_digest, slot_author, AuthorityId, CompatibilityMode, Error, + authorities, standalone::SealVerificationError, AuthorityId, CompatibilityMode, Error, LOG_TARGET, }; use codec::{Codec, Decode, Encode}; @@ -36,7 +36,7 @@ use sp_api::{ApiExt, ProvideRuntimeApi}; use sp_block_builder::BlockBuilder as BlockBuilderApi; use sp_blockchain::HeaderBackend; use sp_consensus::Error as ConsensusError; -use sp_consensus_aura::{digests::CompatibleDigestItem, inherents::AuraInherentData, AuraApi}; +use sp_consensus_aura::{inherents::AuraInherentData, AuraApi}; use sp_consensus_slots::Slot; use sp_core::{crypto::Pair, ExecutionContext}; use sp_inherents::{CreateInherentDataProviders, InherentDataProvider as _}; @@ -54,7 +54,7 @@ use std::{fmt::Debug, hash::Hash, marker::PhantomData, sync::Arc}; fn check_header( client: &C, slot_now: Slot, - mut header: B::Header, + header: B::Header, hash: B::Hash, authorities: &[AuthorityId

], check_for_equivocation: CheckForEquivocation, @@ -64,27 +64,16 @@ where C: sc_client_api::backend::AuxStore, P::Public: Encode + Decode + PartialEq + Clone, { - 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)))?; - - let slot = find_pre_digest::(&header)?; - - if slot > slot_now { - header.digest_mut().push(seal); - Ok(CheckedHeader::Deferred(header, slot)) - } else { - // check the signature is valid under the expected authority and - // chain state. - let expected_author = - slot_author::

(slot, authorities).ok_or(Error::SlotAuthorNotFound)?; - - let pre_hash = header.hash(); - - if P::verify(&sig, pre_hash.as_ref(), expected_author) { - if check_for_equivocation.check_for_equivocation() { + let check_result = + crate::standalone::check_header_slot_and_seal::(slot_now, header, authorities); + + match check_result { + Ok((header, slot, seal)) => { + let expected_author = crate::standalone::slot_author::

(slot, &authorities); + let should_equiv_check = check_for_equivocation.check_for_equivocation(); + if let (true, Some(expected)) = (should_equiv_check, expected_author) { if let Some(equivocation_proof) = - check_equivocation(client, slot_now, slot, &header, expected_author) + check_equivocation(client, slot_now, slot, &header, expected) .map_err(Error::Client)? { info!( @@ -98,9 +87,14 @@ where } Ok(CheckedHeader::Checked(header, (slot, seal))) - } else { - Err(Error::BadSignature(hash)) - } + }, + Err(SealVerificationError::Deferred(header, slot)) => + Ok(CheckedHeader::Deferred(header, slot)), + Err(SealVerificationError::Unsealed) => Err(Error::HeaderUnsealed(hash)), + Err(SealVerificationError::BadSeal) => Err(Error::HeaderBadSeal(hash)), + Err(SealVerificationError::BadSignature) => Err(Error::BadSignature(hash)), + Err(SealVerificationError::SlotAuthorNotFound) => Err(Error::SlotAuthorNotFound), + Err(SealVerificationError::InvalidPreDigest(e)) => Err(Error::from(e)), } } diff --git a/client/consensus/aura/src/lib.rs b/client/consensus/aura/src/lib.rs index a48eeac5ce8b2..1dc364283d5b6 100644 --- a/client/consensus/aura/src/lib.rs +++ b/client/consensus/aura/src/lib.rs @@ -33,11 +33,10 @@ use std::{fmt::Debug, hash::Hash, marker::PhantomData, pin::Pin, sync::Arc}; use futures::prelude::*; -use log::{debug, trace}; use codec::{Codec, Decode, Encode}; -use sc_client_api::{backend::AuxStore, BlockOf, UsageProvider}; +use sc_client_api::{backend::AuxStore, BlockOf}; use sc_consensus::{BlockImport, BlockImportParams, ForkChoiceStrategy, StateAction}; use sc_consensus_slots::{ BackoffAuthoringBlocksStrategy, InherentDataProviderExt, SimpleSlotWorkerToSlotWorker, @@ -45,20 +44,19 @@ use sc_consensus_slots::{ }; use sc_telemetry::TelemetryHandle; use sp_api::{Core, ProvideRuntimeApi}; -use sp_application_crypto::{AppCrypto, AppPublic}; -use sp_blockchain::{HeaderBackend, Result as CResult}; +use sp_application_crypto::AppPublic; +use sp_blockchain::HeaderBackend; use sp_consensus::{BlockOrigin, Environment, Error as ConsensusError, Proposer, SelectChain}; use sp_consensus_slots::Slot; -use sp_core::crypto::{ByteArray, Pair, Public}; +use sp_core::crypto::{Pair, Public}; use sp_inherents::CreateInherentDataProviders; use sp_keystore::KeystorePtr; -use sp_runtime::{ - traits::{Block as BlockT, Header, Member, NumberFor, Zero}, - DigestItem, -}; +use sp_runtime::traits::{Block as BlockT, Header, Member, NumberFor}; mod import_queue; +pub mod standalone; +pub use crate::standalone::{find_pre_digest, slot_duration}; pub use import_queue::{ build_verifier, import_queue, AuraVerifier, BuildVerifierParams, CheckForEquivocation, ImportQueueParams, @@ -112,39 +110,6 @@ impl Default for CompatibilityMode { } } -/// Get the slot duration for Aura. -pub fn slot_duration(client: &C) -> CResult -where - A: Codec, - B: BlockT, - C: AuxStore + ProvideRuntimeApi + UsageProvider, - C::Api: AuraApi, -{ - client - .runtime_api() - .slot_duration(client.usage_info().chain.best_hash) - .map_err(|err| err.into()) -} - -/// Get slot author for given block along with authorities. -fn slot_author(slot: Slot, authorities: &[AuthorityId

]) -> Option<&AuthorityId

> { - if authorities.is_empty() { - return None - } - - let idx = *slot % (authorities.len() as u64); - assert!( - idx <= usize::MAX as u64, - "It is impossible to have a vector with length beyond the address space; qed", - ); - - let current_author = authorities.get(idx as usize).expect( - "authorities not empty; index constrained to list length;this is a valid index; qed", - ); - - Some(current_author) -} - /// Parameters of [`start_aura`]. pub struct StartAuraParams { /// The duration of a slot. @@ -412,21 +377,11 @@ where slot: Slot, authorities: &Self::AuxData, ) -> Option { - let expected_author = slot_author::

(slot, authorities); - expected_author.and_then(|p| { - if self - .keystore - .has_keys(&[(p.to_raw_vec(), sp_application_crypto::key_types::AURA)]) - { - Some(p.clone()) - } else { - None - } - }) + crate::standalone::claim_slot::

(slot, authorities, &self.keystore).await } fn pre_digest_data(&self, slot: Slot, _claim: &Self::Claim) -> Vec { - vec![>::aura_pre_digest(slot)] + vec![crate::standalone::pre_digest::

(slot)] } async fn block_import_params( @@ -441,28 +396,8 @@ where sc_consensus::BlockImportParams>::Transaction>, ConsensusError, > { - let signature = self - .keystore - .sign_with( - as AppCrypto>::ID, - as AppCrypto>::CRYPTO_ID, - public.as_slice(), - header_hash.as_ref(), - ) - .map_err(|e| ConsensusError::CannotSign(format!("{}. Key: {:?}", e, public)))? - .ok_or_else(|| { - ConsensusError::CannotSign(format!( - "Could not find key in keystore. Key: {:?}", - public - )) - })?; - let signature = signature - .clone() - .try_into() - .map_err(|_| ConsensusError::InvalidSignature(signature, public.to_raw_vec()))?; - let signature_digest_item = - >::aura_seal(signature); + crate::standalone::seal::<_, P>(header_hash, &public, &self.keystore)?; let mut import_block = BlockImportParams::new(BlockOrigin::Own, header); import_block.post_digests.push(signature_digest_item); @@ -526,11 +461,6 @@ where } } -fn aura_err(error: Error) -> Error { - debug!(target: LOG_TARGET, "{}", error); - error -} - /// Aura Errors #[derive(Debug, thiserror::Error)] pub enum Error { @@ -569,22 +499,13 @@ impl From> for String { } } -/// Get pre-digests from the header -pub fn find_pre_digest(header: &B::Header) -> Result> { - if header.number().is_zero() { - return Ok(0.into()) - } - - let mut pre_digest: Option = None; - for log in header.digest().logs() { - trace!(target: LOG_TARGET, "Checking log {:?}", log); - match (CompatibleDigestItem::::as_aura_pre_digest(log), pre_digest.is_some()) { - (Some(_), true) => return Err(aura_err(Error::MultipleHeaders)), - (None, _) => trace!(target: LOG_TARGET, "Ignoring digest not meant for us"), - (s, false) => pre_digest = s, +impl From for Error { + fn from(e: crate::standalone::PreDigestLookupError) -> Self { + match e { + crate::standalone::PreDigestLookupError::MultipleHeaders => Error::MultipleHeaders, + crate::standalone::PreDigestLookupError::NoDigestFound => Error::NoDigestFound, } } - pre_digest.ok_or_else(|| aura_err(Error::NoDigestFound)) } fn authorities( @@ -637,7 +558,7 @@ mod tests { use sc_consensus_slots::{BackoffAuthoringOnFinalizedHeadLagging, SimpleSlotWorker}; use sc_keystore::LocalKeystore; use sc_network_test::{Block as TestBlock, *}; - use sp_application_crypto::key_types::AURA; + use sp_application_crypto::{key_types::AURA, AppCrypto}; use sp_consensus::{DisableProofRecording, NoNetwork as DummyOracle, Proposal}; use sp_consensus_aura::sr25519::AuthorityPair; use sp_inherents::InherentData; @@ -851,22 +772,6 @@ mod tests { .await; } - #[test] - fn authorities_call_works() { - let client = substrate_test_runtime_client::new(); - - assert_eq!(client.chain_info().best_number, 0); - assert_eq!( - authorities(&client, client.chain_info().best_hash, 1, &CompatibilityMode::None) - .unwrap(), - vec![ - Keyring::Alice.public().into(), - Keyring::Bob.public().into(), - Keyring::Charlie.public().into() - ] - ); - } - #[tokio::test] async fn current_node_authority_should_claim_slot() { let net = AuraTestNet::new(4); diff --git a/client/consensus/aura/src/standalone.rs b/client/consensus/aura/src/standalone.rs new file mode 100644 index 0000000000000..0f9b8668d4478 --- /dev/null +++ b/client/consensus/aura/src/standalone.rs @@ -0,0 +1,357 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Standalone functions used within the implementation of Aura. + +use std::fmt::Debug; + +use log::trace; + +use codec::Codec; + +use sc_client_api::{backend::AuxStore, UsageProvider}; +use sp_api::{Core, ProvideRuntimeApi}; +use sp_application_crypto::{AppCrypto, AppPublic}; +use sp_blockchain::Result as CResult; +use sp_consensus::Error as ConsensusError; +use sp_consensus_slots::Slot; +use sp_core::crypto::{ByteArray, Pair}; +use sp_keystore::KeystorePtr; +use sp_runtime::{ + traits::{Block as BlockT, Header, NumberFor, Zero}, + DigestItem, +}; + +pub use sc_consensus_slots::check_equivocation; + +use super::{ + AuraApi, AuthorityId, CompatibilityMode, CompatibleDigestItem, SlotDuration, LOG_TARGET, +}; + +/// Get the slot duration for Aura by reading from a runtime API at the best block's state. +pub fn slot_duration(client: &C) -> CResult +where + A: Codec, + B: BlockT, + C: AuxStore + ProvideRuntimeApi + UsageProvider, + C::Api: AuraApi, +{ + slot_duration_at(client, client.usage_info().chain.best_hash) +} + +/// Get the slot duration for Aura by reading from a runtime API at a given block's state. +pub fn slot_duration_at(client: &C, block_hash: B::Hash) -> CResult +where + A: Codec, + B: BlockT, + C: AuxStore + ProvideRuntimeApi, + C::Api: AuraApi, +{ + client.runtime_api().slot_duration(block_hash).map_err(|err| err.into()) +} + +/// Get the slot author for given block along with authorities. +pub fn slot_author(slot: Slot, authorities: &[AuthorityId

]) -> Option<&AuthorityId

> { + if authorities.is_empty() { + return None + } + + let idx = *slot % (authorities.len() as u64); + assert!( + idx <= usize::MAX as u64, + "It is impossible to have a vector with length beyond the address space; qed", + ); + + let current_author = authorities.get(idx as usize).expect( + "authorities not empty; index constrained to list length;this is a valid index; qed", + ); + + Some(current_author) +} + +/// Attempt to claim a slot using a keystore. +/// +/// This returns `None` if the slot author is not locally controlled, and `Some` if it is, +/// with the public key of the slot author. +pub async fn claim_slot( + slot: Slot, + authorities: &[AuthorityId

], + keystore: &KeystorePtr, +) -> Option { + let expected_author = slot_author::

(slot, authorities); + expected_author.and_then(|p| { + if keystore.has_keys(&[(p.to_raw_vec(), sp_application_crypto::key_types::AURA)]) { + Some(p.clone()) + } else { + None + } + }) +} + +/// Produce the pre-runtime digest containing the slot info. +/// +/// This is intended to be put into the block header prior to runtime execution, +/// so the runtime can read the slot in this way. +pub fn pre_digest(slot: Slot) -> sp_runtime::DigestItem +where + P::Signature: Codec, +{ + >::aura_pre_digest(slot) +} + +/// Produce the seal digest item by signing the hash of a block. +/// +/// Note that after this is added to a block header, the hash of the block will change. +pub fn seal( + header_hash: &Hash, + public: &P::Public, + keystore: &KeystorePtr, +) -> Result +where + Hash: AsRef<[u8]>, + P: Pair, + P::Signature: Codec + TryFrom>, + P::Public: AppPublic, +{ + let signature = keystore + .sign_with( + as AppCrypto>::ID, + as AppCrypto>::CRYPTO_ID, + public.as_slice(), + header_hash.as_ref(), + ) + .map_err(|e| ConsensusError::CannotSign(format!("{}. Key: {:?}", e, public)))? + .ok_or_else(|| { + ConsensusError::CannotSign(format!("Could not find key in keystore. Key: {:?}", public)) + })?; + + let signature = signature + .clone() + .try_into() + .map_err(|_| ConsensusError::InvalidSignature(signature, public.to_raw_vec()))?; + + let signature_digest_item = + >::aura_seal(signature); + + Ok(signature_digest_item) +} + +/// Errors in pre-digest lookup. +#[derive(Debug, thiserror::Error)] +pub enum PreDigestLookupError { + /// Multiple Aura pre-runtime headers + #[error("Multiple Aura pre-runtime headers")] + MultipleHeaders, + /// No Aura pre-runtime digest found + #[error("No Aura pre-runtime digest found")] + NoDigestFound, +} + +/// Extract a pre-digest from a block header. +/// +/// This fails if there is no pre-digest or there are multiple. +/// +/// Returns the `slot` stored in the pre-digest or an error if no pre-digest was found. +pub fn find_pre_digest( + header: &B::Header, +) -> Result { + if header.number().is_zero() { + return Ok(0.into()) + } + + let mut pre_digest: Option = None; + for log in header.digest().logs() { + trace!(target: LOG_TARGET, "Checking log {:?}", log); + match (CompatibleDigestItem::::as_aura_pre_digest(log), pre_digest.is_some()) { + (Some(_), true) => return Err(PreDigestLookupError::MultipleHeaders), + (None, _) => trace!(target: LOG_TARGET, "Ignoring digest not meant for us"), + (s, false) => pre_digest = s, + } + } + pre_digest.ok_or_else(|| PreDigestLookupError::NoDigestFound) +} + +/// Fetch the current set of authorities from the runtime at a specific block. +/// +/// The compatibility mode and context block number informs this function whether +/// to initialize the hypothetical block created by the runtime API as backwards compatibility +/// for older chains. +pub fn fetch_authorities_with_compatibility_mode( + client: &C, + parent_hash: B::Hash, + context_block_number: NumberFor, + compatibility_mode: &CompatibilityMode>, +) -> Result, ConsensusError> +where + A: Codec + Debug, + B: BlockT, + C: ProvideRuntimeApi, + C::Api: AuraApi, +{ + 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( + parent_hash, + &B::Header::new( + context_block_number, + Default::default(), + Default::default(), + parent_hash, + Default::default(), + ), + ) + .map_err(|_| ConsensusError::InvalidAuthoritiesSet)?; + }, + } + + runtime_api + .authorities(parent_hash) + .ok() + .ok_or(ConsensusError::InvalidAuthoritiesSet) +} + +/// Load the current set of authorities from a runtime at a specific block. +pub fn fetch_authorities( + client: &C, + parent_hash: B::Hash, +) -> Result, ConsensusError> +where + A: Codec + Debug, + B: BlockT, + C: ProvideRuntimeApi, + C::Api: AuraApi, +{ + client + .runtime_api() + .authorities(parent_hash) + .ok() + .ok_or(ConsensusError::InvalidAuthoritiesSet) +} + +/// Errors in slot and seal verification. +#[derive(Debug, thiserror::Error)] +pub enum SealVerificationError

{ + /// Header is deferred to the future. + #[error("Header slot is in the future")] + Deferred(Header, Slot), + + /// The header has no seal digest. + #[error("Header is unsealed.")] + Unsealed, + + /// The header has a malformed seal. + #[error("Header has a malformed seal")] + BadSeal, + + /// The header has a bad signature. + #[error("Header has a bad signature")] + BadSignature, + + /// No slot author found. + #[error("No slot author for provided slot")] + SlotAuthorNotFound, + + /// Header has no valid slot pre-digest. + #[error("Header has no valid slot pre-digest")] + InvalidPreDigest(PreDigestLookupError), +} + +/// Check a header has been signed by the right key. If the slot is too far in the future, an error +/// will be returned. If it's successful, returns the pre-header (i.e. without the seal), +/// the slot, and the digest item containing the seal. +/// +/// Note that this does not check for equivocations, and [`check_equivocation`] is recommended +/// for that purpose. +/// +/// This digest item will always return `Some` when used with `as_aura_seal`. +pub fn check_header_slot_and_seal( + slot_now: Slot, + mut header: B::Header, + authorities: &[AuthorityId

], +) -> Result<(B::Header, Slot, DigestItem), SealVerificationError> +where + P::Signature: Codec, + P::Public: Codec + PartialEq + Clone, +{ + let seal = header.digest_mut().pop().ok_or(SealVerificationError::Unsealed)?; + + let sig = seal.as_aura_seal().ok_or(SealVerificationError::BadSeal)?; + + let slot = find_pre_digest::(&header) + .map_err(SealVerificationError::InvalidPreDigest)?; + + if slot > slot_now { + header.digest_mut().push(seal); + return Err(SealVerificationError::Deferred(header, slot)) + } else { + // check the signature is valid under the expected authority and + // chain state. + let expected_author = + slot_author::

(slot, authorities).ok_or(SealVerificationError::SlotAuthorNotFound)?; + + let pre_hash = header.hash(); + + if P::verify(&sig, pre_hash.as_ref(), expected_author) { + Ok((header, slot, seal)) + } else { + Err(SealVerificationError::BadSignature) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use sp_keyring::sr25519::Keyring; + + #[test] + fn authorities_call_works() { + let client = substrate_test_runtime_client::new(); + + assert_eq!(client.chain_info().best_number, 0); + assert_eq!( + fetch_authorities_with_compatibility_mode( + &client, + client.chain_info().best_hash, + 1, + &CompatibilityMode::None + ) + .unwrap(), + vec![ + Keyring::Alice.public().into(), + Keyring::Bob.public().into(), + Keyring::Charlie.public().into() + ] + ); + + assert_eq!( + fetch_authorities(&client, client.chain_info().best_hash).unwrap(), + vec![ + Keyring::Alice.public().into(), + Keyring::Bob.public().into(), + Keyring::Charlie.public().into() + ] + ); + } +} From 75dee3c6fc72f6399a43f498e0e42f94fb82a7bd Mon Sep 17 00:00:00 2001 From: PG Herveou Date: Fri, 31 Mar 2023 19:44:29 +0200 Subject: [PATCH 600/715] contracts: make test work with debugger (#13776) * contracts: make test work with debugger * fix path * PR review * Add comment * space * Update frame/contracts/src/tests.rs * lint * spelling --- frame/contracts/src/tests.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index beaec458e36f7..bae6c1946e183 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -456,7 +456,14 @@ fn compile_module(fixture_name: &str) -> wat::Result<(Vec, Date: Sat, 1 Apr 2023 18:19:12 +0100 Subject: [PATCH 601/715] add claim_commission weight (#13774) --- frame/nomination-pools/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/nomination-pools/src/lib.rs b/frame/nomination-pools/src/lib.rs index e7c99e023289b..78f0c730ce5dd 100644 --- a/frame/nomination-pools/src/lib.rs +++ b/frame/nomination-pools/src/lib.rs @@ -2617,7 +2617,7 @@ pub mod pallet { /// commission is paid out and added to total claimed commission`. Total pending commission /// is reset to zero. the current. #[pallet::call_index(20)] - #[pallet::weight(0)] + #[pallet::weight(T::WeightInfo::claim_commission())] pub fn claim_commission(origin: OriginFor, pool_id: PoolId) -> DispatchResult { let who = ensure_signed(origin)?; Self::do_claim_commission(who, pool_id) From d6f278b9685ac871c79e45551b66111b77cb1b71 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Sat, 1 Apr 2023 23:59:37 +0200 Subject: [PATCH 602/715] FRAME: Minor fix for failsafe. (#13741) * max instead of min * Remove debug stuff * remove debug code * warn log on no provider ref * format string for log --------- Co-authored-by: muharem --- frame/balances/src/lib.rs | 7 ++++++- frame/nis/src/lib.rs | 9 ++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index d4be806982dfe..dcf602cd5e0bf 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -786,7 +786,12 @@ pub mod pallet { // Gah!! We have a non-zero reserve balance but no provider refs :( // This shouldn't practically happen, but we need a failsafe anyway: let's give // them enough for an ED. - a.free = a.free.min(Self::ed()); + log::warn!( + target: LOG_TARGET, + "account with a non-zero reserve balance has no provider refs, account_id: '{:?}'.", + who + ); + a.free = a.free.max(Self::ed()); system::Pallet::::inc_providers(who); } let _ = system::Pallet::::inc_consumers(who).defensive(); diff --git a/frame/nis/src/lib.rs b/frame/nis/src/lib.rs index 0b8d292ec5f45..539011c5149d0 100644 --- a/frame/nis/src/lib.rs +++ b/frame/nis/src/lib.rs @@ -480,9 +480,6 @@ pub mod pallet { AlreadyCommunal, /// The receipt is already private. AlreadyPrivate, - Release1, - Release2, - Tah, } pub(crate) struct WeightCounter { @@ -724,8 +721,7 @@ pub mod pallet { let dropped = receipt.proportion.is_zero(); if amount > on_hold { - T::Currency::release(&T::HoldReason::get(), &who, on_hold, Exact) - .map_err(|_| Error::::Release1)?; + T::Currency::release(&T::HoldReason::get(), &who, on_hold, Exact)?; let deficit = amount - on_hold; // Try to transfer deficit from pot to receipt owner. summary.receipts_on_hold.saturating_reduce(on_hold); @@ -756,8 +752,7 @@ pub mod pallet { )?; summary.receipts_on_hold.saturating_reduce(on_hold); } - T::Currency::release(&T::HoldReason::get(), &who, amount, Exact) - .map_err(|_| Error::::Release2)?; + T::Currency::release(&T::HoldReason::get(), &who, amount, Exact)?; } if dropped { From db40c484953a17a1eefb92ee743415749892a727 Mon Sep 17 00:00:00 2001 From: Damian Straszak Date: Mon, 3 Apr 2023 10:36:28 +0200 Subject: [PATCH 603/715] Adjustments to RPC-query docstrings. (#13698) * Changes in RPC docs. * ".git/.scripts/commands/fmt/fmt.sh" --------- Co-authored-by: command-bot <> --- client/rpc-api/src/state/mod.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/client/rpc-api/src/state/mod.rs b/client/rpc-api/src/state/mod.rs index ebc1eb9b4ff52..dbc2a505456a5 100644 --- a/client/rpc-api/src/state/mod.rs +++ b/client/rpc-api/src/state/mod.rs @@ -33,7 +33,7 @@ pub use self::helpers::ReadProof; /// Substrate state API #[rpc(client, server)] pub trait StateApi { - /// Call a contract at a block's state. + /// Call a method from the runtime API at a block's state. #[method(name = "state_call", aliases = ["state_callAt"], blocking)] fn call(&self, name: String, bytes: Bytes, hash: Option) -> RpcResult; @@ -85,8 +85,10 @@ pub trait StateApi { /// 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. + /// NOTE: The first returned result contains the initial state of storage for all keys. /// Subsequent values in the vector represent changes to the previous state (diffs). + /// WARNING: The time complexity of this query is O(|keys|*dist(block, hash)), and the + /// memory complexity is O(dist(block, hash)) -- use with caution. #[method(name = "state_queryStorage", blocking)] fn query_storage( &self, @@ -95,7 +97,9 @@ pub trait StateApi { hash: Option, ) -> RpcResult>>; - /// Query storage entries (by key) starting at block hash given as the second parameter. + /// Query storage entries (by key) at a block hash given as the second parameter. + /// NOTE: Each StorageChangeSet in the result corresponds to exactly one element -- + /// the storage value under an input key at the input block hash. #[method(name = "state_queryStorageAt", blocking)] fn query_storage_at( &self, From be9fa62238fcfd7eb49218809a6b981f71c34eb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Mon, 3 Apr 2023 11:37:18 +0200 Subject: [PATCH 604/715] Force upgrade snow to 0.9.2 (#13806) This fixes the compilation on master for the node template that was not pulling the latest release as part of its build. --- Cargo.lock | 11 ++++++----- client/network/Cargo.toml | 4 ++++ 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7fd0122f3cc0f..1e9a87e818641 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1473,9 +1473,9 @@ dependencies = [ [[package]] name = "curve25519-dalek" -version = "4.0.0-rc.0" +version = "4.0.0-rc.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da00a7a9a4eb92a0a0f8e75660926d48f0d0f3c537e455c457bcdaa1e16b1ac" +checksum = "8d4ba9852b42210c7538b75484f9daa0655e9a3ac04f693747bb0f02cf3cfe16" dependencies = [ "cfg-if", "fiat-crypto", @@ -8955,6 +8955,7 @@ dependencies = [ "serde", "serde_json", "smallvec", + "snow", "sp-arithmetic", "sp-blockchain", "sp-consensus", @@ -10034,14 +10035,14 @@ checksum = "5e9f0ab6ef7eb7353d9119c170a436d1bf248eea575ac42d19d12f4e34130831" [[package]] name = "snow" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12ba5f4d4ff12bdb6a169ed51b7c48c0e0ac4b0b4b31012b2571e97d78d3201d" +checksum = "5ccba027ba85743e09d15c03296797cad56395089b832b48b5a5217880f57733" dependencies = [ "aes-gcm 0.9.4", "blake2", "chacha20poly1305", - "curve25519-dalek 4.0.0-rc.0", + "curve25519-dalek 4.0.0-rc.1", "rand_core 0.6.4", "ring", "rustc_version 0.4.0", diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index 90b5ce871ef1a..6fc4131f74e10 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -51,6 +51,10 @@ 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-runtime = { version = "7.0.0", path = "../../primitives/runtime" } +# Force 0.9.2 as snow release to fix the compilation. +# +# When libp2p also enforces this version, we can get rid off this extra dep here. +snow = "0.9.2" [dev-dependencies] assert_matches = "1.3" From b94d98bfcb167c80a96a748955671a60ce09360d Mon Sep 17 00:00:00 2001 From: Muharem Ismailov Date: Mon, 3 Apr 2023 12:59:01 +0200 Subject: [PATCH 605/715] Scheduler pre block limit note (#13231) Co-authored-by: parity-processbot <> --- bin/node/runtime/src/lib.rs | 3 +++ frame/referenda/src/lib.rs | 15 +++++++-------- frame/scheduler/src/lib.rs | 4 ++++ 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 5562dc263ddc8..433ca8e8b839e 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -364,7 +364,10 @@ impl pallet_scheduler::Config for Runtime { type RuntimeCall = RuntimeCall; type MaximumWeight = MaximumSchedulerWeight; type ScheduleOrigin = EnsureRoot; + #[cfg(feature = "runtime-benchmarks")] type MaxScheduledPerBlock = ConstU32<512>; + #[cfg(not(feature = "runtime-benchmarks"))] + type MaxScheduledPerBlock = ConstU32<50>; type WeightInfo = pallet_scheduler::weights::SubstrateWeight; type OriginPrivilegeCmp = EqualPrivilegeOnly; type Preimages = Preimage; diff --git a/frame/referenda/src/lib.rs b/frame/referenda/src/lib.rs index b96cf5a76733d..68837376c5b33 100644 --- a/frame/referenda/src/lib.rs +++ b/frame/referenda/src/lib.rs @@ -874,22 +874,21 @@ impl, I: 'static> Pallet { let when = (when.saturating_add(alarm_interval.saturating_sub(One::one())) / alarm_interval) .saturating_mul(alarm_interval); - let maybe_result = T::Scheduler::schedule( + let result = T::Scheduler::schedule( DispatchTime::At(when), None, 128u8, frame_system::RawOrigin::Root.into(), call, - ) - .ok() - .map(|x| (when, x)); + ); debug_assert!( - maybe_result.is_some(), - "Unable to schedule a new alarm at #{:?} (now: #{:?})?!", + result.is_ok(), + "Unable to schedule a new alarm at #{:?} (now: #{:?}), scheduler error: `{:?}`", when, - frame_system::Pallet::::block_number() + frame_system::Pallet::::block_number(), + result.unwrap_err(), ); - maybe_result + result.ok().map(|x| (when, x)) } /// Mutate a referendum's `status` into the correct deciding state. diff --git a/frame/scheduler/src/lib.rs b/frame/scheduler/src/lib.rs index 09bb3561188f8..8194f286c8323 100644 --- a/frame/scheduler/src/lib.rs +++ b/frame/scheduler/src/lib.rs @@ -216,6 +216,10 @@ pub mod pallet { type OriginPrivilegeCmp: PrivilegeCmp; /// The maximum number of scheduled calls in the queue for a single block. + /// + /// NOTE: + /// + Dependent pallets' benchmarks might require a higher limit for the setting. Set a + /// higher limit under `runtime-benchmarks` feature. #[pallet::constant] type MaxScheduledPerBlock: Get; From dd45632f298db02f6946c906296bbf86a74f4f46 Mon Sep 17 00:00:00 2001 From: Koute Date: Mon, 3 Apr 2023 21:00:31 +0900 Subject: [PATCH 606/715] Disable `sign-ext` WASM feature when building runtimes (#13804) Co-authored-by: parity-processbot <> --- utils/wasm-builder/src/wasm_project.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/wasm-builder/src/wasm_project.rs b/utils/wasm-builder/src/wasm_project.rs index d25fb4acd2345..c45a40a6b9202 100644 --- a/utils/wasm-builder/src/wasm_project.rs +++ b/utils/wasm-builder/src/wasm_project.rs @@ -632,7 +632,7 @@ fn build_project( let mut build_cmd = cargo_cmd.command(); let rustflags = format!( - "-C target-cpu=mvp -C link-arg=--export-table {} {}", + "-C target-cpu=mvp -C target-feature=-sign-ext -C link-arg=--export-table {} {}", default_rustflags, env::var(crate::WASM_BUILD_RUSTFLAGS_ENV).unwrap_or_default(), ); From bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Tue, 4 Apr 2023 09:40:30 +0200 Subject: [PATCH 607/715] refactor: inconsistent BalanceConversion fn (#13610) * refactor: inconsistent BalanceConversion fn * Revert "refactor: inconsistent BalanceConversion fn" This reverts commit 1177877631a11b64df6f019b5390a8a7018e3a3f. * refactor: rename BalanceConversion trait * feat: add ConversionFromAssetBalance --- frame/assets/src/tests.rs | 2 +- frame/assets/src/types.rs | 4 ++-- frame/support/src/traits/tokens.rs | 6 +++--- frame/support/src/traits/tokens/misc.rs | 14 ++++++++++++-- .../asset-tx-payment/src/payment.rs | 7 ++++--- 5 files changed, 22 insertions(+), 11 deletions(-) diff --git a/frame/assets/src/tests.rs b/frame/assets/src/tests.rs index d4a49ac5a4651..afd224ad66642 100644 --- a/frame/assets/src/tests.rs +++ b/frame/assets/src/tests.rs @@ -1162,7 +1162,7 @@ fn set_min_balance_should_work() { #[test] fn balance_conversion_should_work() { new_test_ext().execute_with(|| { - use frame_support::traits::tokens::BalanceConversion; + use frame_support::traits::tokens::ConversionToAssetBalance; let id = 42; assert_ok!(Assets::force_create(RuntimeOrigin::root(), id, 1, true, 10)); diff --git a/frame/assets/src/types.rs b/frame/assets/src/types.rs index d50461ba59898..c83e764f4a68d 100644 --- a/frame/assets/src/types.rs +++ b/frame/assets/src/types.rs @@ -20,7 +20,7 @@ use super::*; use frame_support::{ pallet_prelude::*, - traits::{fungible, tokens::BalanceConversion}, + traits::{fungible, tokens::ConversionToAssetBalance}, }; use sp_runtime::{traits::Convert, FixedPointNumber, FixedPointOperand, FixedU128}; @@ -228,7 +228,7 @@ type BalanceOf = >>::Balance; /// Converts a balance value into an asset balance based on the ratio between the fungible's /// minimum balance and the minimum asset balance. pub struct BalanceToAssetBalance(PhantomData<(F, T, CON, I)>); -impl BalanceConversion, AssetIdOf, AssetBalanceOf> +impl ConversionToAssetBalance, AssetIdOf, AssetBalanceOf> for BalanceToAssetBalance where F: fungible::Inspect>, diff --git a/frame/support/src/traits/tokens.rs b/frame/support/src/traits/tokens.rs index d2753caa6a79d..253b49c6671f8 100644 --- a/frame/support/src/traits/tokens.rs +++ b/frame/support/src/traits/tokens.rs @@ -29,8 +29,8 @@ pub mod nonfungibles_v2; pub use imbalance::Imbalance; pub mod pay; pub use misc::{ - AssetId, Balance, BalanceConversion, BalanceStatus, ConvertRank, DepositConsequence, - ExistenceRequirement, Fortitude, GetSalary, Locker, Precision, Preservation, Provenance, - Restriction, WithdrawConsequence, WithdrawReasons, + AssetId, Balance, BalanceStatus, ConversionFromAssetBalance, ConversionToAssetBalance, + ConvertRank, DepositConsequence, ExistenceRequirement, Fortitude, GetSalary, Locker, Precision, + Preservation, Provenance, Restriction, WithdrawConsequence, WithdrawReasons, }; pub use pay::{Pay, PayFromAccount, PaymentStatus}; diff --git a/frame/support/src/traits/tokens/misc.rs b/frame/support/src/traits/tokens/misc.rs index 8ad3a9535fd0d..75aef0e04ea65 100644 --- a/frame/support/src/traits/tokens/misc.rs +++ b/frame/support/src/traits/tokens/misc.rs @@ -244,9 +244,19 @@ impl< } /// Converts a balance value into an asset balance. -pub trait BalanceConversion { +pub trait ConversionToAssetBalance { type Error; - fn to_asset_balance(balance: InBalance, asset_id: AssetId) -> Result; + fn to_asset_balance(balance: InBalance, asset_id: AssetId) + -> Result; +} + +/// Converts an asset balance value into balance. +pub trait ConversionFromAssetBalance { + type Error; + fn from_asset_balance( + balance: AssetBalance, + asset_id: AssetId, + ) -> Result; } /// Trait to handle asset locking mechanism to ensure interactions with the asset can be implemented diff --git a/frame/transaction-payment/asset-tx-payment/src/payment.rs b/frame/transaction-payment/asset-tx-payment/src/payment.rs index f8d6888b9905c..49e78fb8bce01 100644 --- a/frame/transaction-payment/asset-tx-payment/src/payment.rs +++ b/frame/transaction-payment/asset-tx-payment/src/payment.rs @@ -22,7 +22,8 @@ use frame_support::{ traits::{ fungibles::{Balanced, Credit, Inspect}, tokens::{ - Balance, BalanceConversion, Fortitude::Polite, Precision::Exact, Preservation::Protect, + Balance, ConversionToAssetBalance, Fortitude::Polite, Precision::Exact, + Preservation::Protect, }, }, unsigned::TransactionValidityError, @@ -87,7 +88,7 @@ impl> HandleCredit for () { } /// Implements the asset transaction for a balance to asset converter (implementing -/// [`BalanceConversion`]) and a credit handler (implementing [`HandleCredit`]). +/// [`ConversionToAssetBalance`]) 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)>); @@ -97,7 +98,7 @@ pub struct FungiblesAdapter(PhantomData<(CON, HC)>); impl OnChargeAssetTransaction for FungiblesAdapter where T: Config, - CON: BalanceConversion, AssetIdOf, AssetBalanceOf>, + CON: ConversionToAssetBalance, AssetIdOf, AssetBalanceOf>, HC: HandleCredit, AssetIdOf: FullCodec + Copy + MaybeSerializeDeserialize + Debug + Default + Eq + TypeInfo, { From 842e651fac49176781660704c643b63f0fb72705 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 4 Apr 2023 12:02:47 +0200 Subject: [PATCH 608/715] Remove deprecated batch verification (#13799) This removes the deprecated batch verification. This was actually never really activated. Nevertheless, we need to keep the host functions around to support old runtimes which may import these host functions. However, we do not give access to these functions anymore. This means that any new runtime can not call them anymore. The host function implementations we keep will not do batch verification and will instead fall back to the always existing option of directly verifying the passed signature. `finish_batch_verification` will return the combined result of all the batch verify calls. This removes the `TaskExecutorExt` which only existed to support the batch verification. So, any code that used this extension can just remove the registration of them. It also removes `SignatureBatching` that was used by `frame-executive` to control the batch verification. However, there wasn't any `Verify` implementation that called the batch verification functions. --- client/service/src/builder.rs | 1 - client/service/src/client/call_executor.rs | 11 +- client/service/src/client/client.rs | 9 +- client/service/test/src/client/mod.rs | 7 - frame/executive/src/lib.rs | 6 - primitives/api/test/tests/runtime_calls.rs | 1 - primitives/core/src/traits.rs | 12 - primitives/io/src/batch_verifier.rs | 211 ---------------- primitives/io/src/lib.rs | 228 +++++------------- primitives/runtime/src/lib.rs | 66 +---- primitives/state-machine/src/lib.rs | 36 +-- primitives/state-machine/src/testing.rs | 7 +- test-utils/client/src/lib.rs | 1 - .../benchmarking-cli/src/pallet/command.rs | 4 - utils/frame/try-runtime/cli/src/lib.rs | 6 +- 15 files changed, 76 insertions(+), 530 deletions(-) delete mode 100644 primitives/io/src/batch_verifier.rs diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index b04228e6bfc34..5d639431f427b 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -272,7 +272,6 @@ where let executor = crate::client::LocalCallExecutor::new( backend.clone(), executor, - spawn_handle.clone(), config.clone(), execution_extensions, )?; diff --git a/client/service/src/client/call_executor.rs b/client/service/src/client/call_executor.rs index 82d3e36ac80ea..4d019be908b86 100644 --- a/client/service/src/client/call_executor.rs +++ b/client/service/src/client/call_executor.rs @@ -23,7 +23,7 @@ use sc_client_api::{ use sc_executor::{RuntimeVersion, RuntimeVersionOf}; use sp_api::{ProofRecorder, StorageTransactionCache}; use sp_core::{ - traits::{CallContext, CodeExecutor, RuntimeCode, SpawnNamed}, + traits::{CallContext, CodeExecutor, RuntimeCode}, ExecutionContext, }; use sp_runtime::{generic::BlockId, traits::Block as BlockT}; @@ -39,7 +39,6 @@ pub struct LocalCallExecutor { executor: E, wasm_override: Arc>, wasm_substitutes: WasmSubstitutes, - spawn_handle: Box, execution_extensions: Arc>, } @@ -52,7 +51,6 @@ where pub fn new( backend: Arc, executor: E, - spawn_handle: Box, client_config: ClientConfig, execution_extensions: ExecutionExtensions, ) -> sp_blockchain::Result { @@ -72,7 +70,6 @@ where backend, executor, wasm_override: Arc::new(wasm_override), - spawn_handle, wasm_substitutes, execution_extensions: Arc::new(execution_extensions), }) @@ -142,7 +139,6 @@ where backend: self.backend.clone(), executor: self.executor.clone(), wasm_override: self.wasm_override.clone(), - spawn_handle: self.spawn_handle.clone(), wasm_substitutes: self.wasm_substitutes.clone(), execution_extensions: self.execution_extensions.clone(), } @@ -196,7 +192,6 @@ where call_data, extensions, &runtime_code, - self.spawn_handle.clone(), context, ) .set_parent_hash(at_hash); @@ -256,7 +251,6 @@ where call_data, extensions, &runtime_code, - self.spawn_handle.clone(), call_context, ) .with_storage_transaction_cache(storage_transaction_cache.as_deref_mut()) @@ -272,7 +266,6 @@ where call_data, extensions, &runtime_code, - self.spawn_handle.clone(), call_context, ) .with_storage_transaction_cache(storage_transaction_cache.as_deref_mut()) @@ -313,7 +306,6 @@ where trie_backend, &mut Default::default(), &self.executor, - self.spawn_handle.clone(), method, call_data, &runtime_code, @@ -425,7 +417,6 @@ mod tests { backend: backend.clone(), executor: executor.clone(), wasm_override: Arc::new(Some(overrides)), - spawn_handle: Box::new(TaskExecutor::new()), wasm_substitutes: WasmSubstitutes::new( Default::default(), executor.clone(), diff --git a/client/service/src/client/client.rs b/client/service/src/client/client.rs index d5212021f2d79..3adb6d8976969 100644 --- a/client/service/src/client/client.rs +++ b/client/service/src/client/client.rs @@ -245,13 +245,8 @@ where sc_offchain::OffchainDb::factory_from_backend(&*backend), ); - let call_executor = LocalCallExecutor::new( - backend.clone(), - executor, - spawn_handle.clone(), - config.clone(), - extensions, - )?; + let call_executor = + LocalCallExecutor::new(backend.clone(), executor, config.clone(), extensions)?; Client::new( backend, diff --git a/client/service/test/src/client/mod.rs b/client/service/test/src/client/mod.rs index 96a0a8fe2a023..e6545abf1bc73 100644 --- a/client/service/test/src/client/mod.rs +++ b/client/service/test/src/client/mod.rs @@ -104,7 +104,6 @@ fn construct_block( let mut overlay = OverlayedChanges::default(); let backend_runtime_code = sp_state_machine::backend::BackendRuntimeCode::new(backend); let runtime_code = backend_runtime_code.runtime_code().expect("Code is part of the backend"); - let task_executor = Box::new(TaskExecutor::new()); StateMachine::new( backend, @@ -114,7 +113,6 @@ fn construct_block( &header.encode(), Default::default(), &runtime_code, - task_executor.clone() as Box<_>, CallContext::Onchain, ) .execute(ExecutionStrategy::NativeElseWasm) @@ -129,7 +127,6 @@ fn construct_block( &tx.encode(), Default::default(), &runtime_code, - task_executor.clone() as Box<_>, CallContext::Onchain, ) .execute(ExecutionStrategy::NativeElseWasm) @@ -144,7 +141,6 @@ fn construct_block( &[], Default::default(), &runtime_code, - task_executor.clone() as Box<_>, CallContext::Onchain, ) .execute(ExecutionStrategy::NativeElseWasm) @@ -217,7 +213,6 @@ fn construct_genesis_should_work_with_native() { &b1data, Default::default(), &runtime_code, - TaskExecutor::new(), CallContext::Onchain, ) .execute(ExecutionStrategy::NativeElseWasm) @@ -251,7 +246,6 @@ fn construct_genesis_should_work_with_wasm() { &b1data, Default::default(), &runtime_code, - TaskExecutor::new(), CallContext::Onchain, ) .execute(ExecutionStrategy::AlwaysWasm) @@ -285,7 +279,6 @@ fn construct_genesis_with_bad_transaction_should_panic() { &b1data, Default::default(), &runtime_code, - TaskExecutor::new(), CallContext::Onchain, ) .execute(ExecutionStrategy::NativeElseWasm); diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index 5003920eadcb5..6a1041a28e31b 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -480,16 +480,10 @@ where // any initial checks Self::initial_checks(&block); - let signature_batching = sp_runtime::SignatureBatching::start(); - // execute extrinsics let (header, extrinsics) = block.deconstruct(); Self::execute_extrinsics_with_book_keeping(extrinsics, *header.number()); - if !signature_batching.verify() { - panic!("Signature verification failed."); - } - // any final checks Self::final_checks(&header); } diff --git a/primitives/api/test/tests/runtime_calls.rs b/primitives/api/test/tests/runtime_calls.rs index 69f9a88ffadb3..b57793aad1253 100644 --- a/primitives/api/test/tests/runtime_calls.rs +++ b/primitives/api/test/tests/runtime_calls.rs @@ -188,7 +188,6 @@ fn record_proof_works() { &backend, &mut overlay, &executor, - sp_core::testing::TaskExecutor::new(), "Core_execute_block", &block.encode(), &runtime_code, diff --git a/primitives/core/src/traits.rs b/primitives/core/src/traits.rs index 091b1cdb14a34..51327868474a0 100644 --- a/primitives/core/src/traits.rs +++ b/primitives/core/src/traits.rs @@ -169,18 +169,6 @@ impl ReadRuntimeVersionExt { } } -sp_externalities::decl_extension! { - /// Task executor extension. - pub struct TaskExecutorExt(Box); -} - -impl TaskExecutorExt { - /// New instance of task executor extension. - pub fn new(spawn_handle: impl SpawnNamed + Send + 'static) -> Self { - Self(Box::new(spawn_handle)) - } -} - /// 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/batch_verifier.rs b/primitives/io/src/batch_verifier.rs deleted file mode 100644 index e6d8c6131f778..0000000000000 --- a/primitives/io/src/batch_verifier.rs +++ /dev/null @@ -1,211 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Batch/parallel verification. - -use futures::{channel::oneshot, future::FutureExt}; -use sp_core::{crypto::Pair, ecdsa, ed25519, sr25519, traits::SpawnNamed}; -use std::sync::{ - atomic::{AtomicBool, Ordering as AtomicOrdering}, - Arc, -}; - -#[derive(Debug, Clone)] -struct Sr25519BatchItem { - signature: sr25519::Signature, - pub_key: sr25519::Public, - message: Vec, -} - -/// Batch verifier. -/// -/// Used to parallel-verify signatures for runtime host. Provide task executor and -/// just push (`push_ed25519`, `push_sr25519`) as many signature as you need. At the end, -/// call `verify_and_clear to get a result. After that, batch verifier is ready for the -/// next batching job. -pub struct BatchVerifier { - scheduler: Box, - sr25519_items: Vec, - invalid: Arc, - pending_tasks: Vec>, -} - -impl BatchVerifier { - pub fn new(scheduler: Box) -> Self { - BatchVerifier { - scheduler, - sr25519_items: Default::default(), - invalid: Arc::new(false.into()), - pending_tasks: vec![], - } - } - - /// Spawn a verification task. - /// - /// Returns `false` if there was already an invalid verification or if - /// the verification could not be spawned. - fn spawn_verification_task( - &mut self, - f: impl FnOnce() -> bool + Send + 'static, - name: &'static str, - ) -> bool { - // there is already invalid transaction encountered - if self.invalid.load(AtomicOrdering::Relaxed) { - return false - } - - let invalid_clone = self.invalid.clone(); - let (sender, receiver) = oneshot::channel(); - self.pending_tasks.push(receiver); - - self.scheduler.spawn( - name, - None, - async move { - if !f() { - invalid_clone.store(true, AtomicOrdering::Relaxed); - } - if sender.send(()).is_err() { - // sanity - log::warn!("Verification halted while result was pending"); - invalid_clone.store(true, AtomicOrdering::Relaxed); - } - } - .boxed(), - ); - - true - } - - /// Push ed25519 signature to verify. - /// - /// Returns false if some of the pushed signatures before already failed the check - /// (in this case it won't verify anything else) - pub fn push_ed25519( - &mut self, - signature: ed25519::Signature, - pub_key: ed25519::Public, - message: Vec, - ) -> bool { - self.spawn_verification_task( - move || ed25519::Pair::verify(&signature, &message, &pub_key), - "substrate_ed25519_verify", - ) - } - - /// Push sr25519 signature to verify. - /// - /// Returns false if some of the pushed signatures before already failed the check. - /// (in this case it won't verify anything else) - pub fn push_sr25519( - &mut self, - signature: sr25519::Signature, - pub_key: sr25519::Public, - message: Vec, - ) -> bool { - if self.invalid.load(AtomicOrdering::Relaxed) { - return false - } - self.sr25519_items.push(Sr25519BatchItem { signature, pub_key, message }); - - if self.sr25519_items.len() >= 128 { - let items = std::mem::take(&mut self.sr25519_items); - self.spawn_verification_task( - move || Self::verify_sr25519_batch(items), - "substrate_sr25519_verify", - ) - } else { - true - } - } - - /// Push ecdsa signature to verify. - /// - /// Returns false if some of the pushed signatures before already failed the check - /// (in this case it won't verify anything else) - pub fn push_ecdsa( - &mut self, - signature: ecdsa::Signature, - pub_key: ecdsa::Public, - message: Vec, - ) -> bool { - self.spawn_verification_task( - move || ecdsa::Pair::verify(&signature, &message, &pub_key), - "substrate_ecdsa_verify", - ) - } - - fn verify_sr25519_batch(items: Vec) -> bool { - let messages = items.iter().map(|item| &item.message[..]).collect(); - let signatures = items.iter().map(|item| &item.signature).collect(); - let pub_keys = items.iter().map(|item| &item.pub_key).collect(); - - sr25519::verify_batch(messages, signatures, pub_keys) - } - - /// Verify all previously pushed signatures since last call and return - /// aggregated result. - #[must_use] - pub fn verify_and_clear(&mut self) -> bool { - let pending = std::mem::take(&mut self.pending_tasks); - let started = std::time::Instant::now(); - - log::trace!( - target: "runtime", - "Batch-verification: {} pending tasks, {} sr25519 signatures", - pending.len(), - self.sr25519_items.len(), - ); - - if !Self::verify_sr25519_batch(std::mem::take(&mut self.sr25519_items)) { - return false - } - - if pending.len() > 0 { - let (sender, receiver) = std::sync::mpsc::channel(); - self.scheduler.spawn( - "substrate-batch-verify-join", - None, - async move { - futures::future::join_all(pending).await; - sender.send(()).expect( - "Channel never panics if receiver is live. \ - Receiver is always live until received this data; qed. ", - ); - } - .boxed(), - ); - - if receiver.recv().is_err() { - log::warn!( - target: "runtime", - "Haven't received async result from verification task. Returning false.", - ); - - return false - } - } - - log::trace!( - target: "runtime", - "Finalization of batch verification took {} ms", - started.elapsed().as_millis(), - ); - - !self.invalid.swap(false, AtomicOrdering::Relaxed) - } -} diff --git a/primitives/io/src/lib.rs b/primitives/io/src/lib.rs index 72300eb102177..750b5d5924637 100644 --- a/primitives/io/src/lib.rs +++ b/primitives/io/src/lib.rs @@ -40,7 +40,6 @@ use sp_core::{ hexdisplay::HexDisplay, offchain::{OffchainDbExt, OffchainWorkerExt, TransactionPoolExt}, storage::ChildInfo, - traits::TaskExecutorExt, }; #[cfg(feature = "std")] use sp_keystore::KeystoreExt; @@ -75,12 +74,6 @@ use secp256k1::{ #[cfg(feature = "std")] use sp_externalities::{Externalities, ExternalitiesExt}; -#[cfg(feature = "std")] -mod batch_verifier; - -#[cfg(feature = "std")] -use batch_verifier::BatchVerifier; - pub use sp_externalities::MultiRemovalResults; #[cfg(feature = "std")] @@ -801,15 +794,25 @@ pub trait Crypto { /// needs to be called. /// /// Returns `true` when the verification is either successful or batched. + /// + /// NOTE: Is tagged with `register_only` to keep the functions around for backwards + /// compatibility with old runtimes, but it should not be used anymore by new runtimes. + /// The implementation emulates the old behavior, but isn't doing any batch verification + /// anymore. + #[version(1, register_only)] fn ed25519_batch_verify( &mut self, sig: &ed25519::Signature, msg: &[u8], pub_key: &ed25519::Public, ) -> bool { - self.extension::() - .map(|extension| extension.push_ed25519(sig.clone(), *pub_key, msg.to_vec())) - .unwrap_or_else(|| ed25519_verify(sig, msg, pub_key)) + let res = ed25519_verify(sig, msg, pub_key); + + if let Some(ext) = self.extension::() { + ext.0 &= res; + } + + res } /// Verify `sr25519` signature. @@ -828,25 +831,36 @@ pub trait Crypto { /// needs to be called. /// /// Returns `true` when the verification is either successful or batched. + /// + /// NOTE: Is tagged with `register_only` to keep the functions around for backwards + /// compatibility with old runtimes, but it should not be used anymore by new runtimes. + /// The implementation emulates the old behavior, but isn't doing any batch verification + /// anymore. + #[version(1, register_only)] fn sr25519_batch_verify( &mut self, sig: &sr25519::Signature, msg: &[u8], pub_key: &sr25519::Public, ) -> bool { - self.extension::() - .map(|extension| extension.push_sr25519(sig.clone(), *pub_key, msg.to_vec())) - .unwrap_or_else(|| sr25519_verify(sig, msg, pub_key)) + let res = sr25519_verify(sig, msg, pub_key); + + if let Some(ext) = self.extension::() { + ext.0 &= res; + } + + res } /// Start verification extension. + /// + /// NOTE: Is tagged with `register_only` to keep the functions around for backwards + /// compatibility with old runtimes, but it should not be used anymore by new runtimes. + /// The implementation emulates the old behavior, but isn't doing any batch verification + /// anymore. + #[version(1, register_only)] fn start_batch_verify(&mut self) { - let scheduler = self - .extension::() - .expect("No task executor associated with the current context!") - .clone(); - - self.register_extension(VerificationExt(BatchVerifier::new(scheduler))) + self.register_extension(VerificationExtDeprecated(true)) .expect("Failed to register required extension: `VerificationExt`"); } @@ -856,13 +870,19 @@ pub trait Crypto { /// deferred by `sr25519_verify`/`ed25519_verify`. /// /// Will panic if no `VerificationExt` is registered (`start_batch_verify` was not called). + /// + /// NOTE: Is tagged with `register_only` to keep the functions around for backwards + /// compatibility with old runtimes, but it should not be used anymore by new runtimes. + /// The implementation emulates the old behavior, but isn't doing any batch verification + /// anymore. + #[version(1, register_only)] fn finish_batch_verify(&mut self) -> bool { let result = self - .extension::() + .extension::() .expect("`finish_batch_verify` should only be called after `start_batch_verify`") - .verify_and_clear(); + .0; - self.deregister_extension::() + self.deregister_extension::() .expect("No verification extension in current context!"); result @@ -1005,15 +1025,25 @@ pub trait Crypto { /// needs to be called. /// /// Returns `true` when the verification is either successful or batched. + /// + /// NOTE: Is tagged with `register_only` to keep the functions around for backwards + /// compatibility with old runtimes, but it should not be used anymore by new runtimes. + /// The implementation emulates the old behavior, but isn't doing any batch verification + /// anymore. + #[version(1, register_only)] fn ecdsa_batch_verify( &mut self, sig: &ecdsa::Signature, msg: &[u8], pub_key: &ecdsa::Public, ) -> bool { - self.extension::() - .map(|extension| extension.push_ecdsa(sig.clone(), *pub_key, msg.to_vec())) - .unwrap_or_else(|| ecdsa_verify(sig, msg, pub_key)) + let res = ecdsa_verify(sig, msg, pub_key); + + if let Some(ext) = self.extension::() { + ext.0 &= res; + } + + res } /// Verify and recover a SECP256k1 ECDSA signature. @@ -1186,8 +1216,10 @@ pub trait OffchainIndex { #[cfg(feature = "std")] sp_externalities::decl_extension! { - /// Batch verification extension to register/retrieve from the externalities. - pub struct VerificationExt(BatchVerifier); + /// Deprecated verification context. + /// + /// Stores the combined result of all verifications that are done in the same context. + struct VerificationExtDeprecated(bool); } /// Interface that provides functions to access the offchain functionality. @@ -1376,7 +1408,7 @@ pub trait Offchain { /// Read all response headers. /// /// Returns a vector of pairs `(HeaderKey, HeaderValue)`. - /// NOTE response headers have to be read before response body. + /// NOTE: response headers have to be read before response body. fn http_response_headers(&mut self, request_id: HttpRequestId) -> Vec<(Vec, Vec)> { self.extension::() .expect("http_response_headers can be called only in the offchain worker context") @@ -1389,7 +1421,7 @@ pub trait Offchain { /// is reached or server closed the connection. /// If `0` is returned it means that the response has been fully consumed /// and the `request_id` is now invalid. - /// NOTE this implies that response headers must be read before draining the body. + /// NOTE: this implies that response headers must be read before draining the body. /// Passing `None` as a deadline blocks forever. fn http_response_read_body( &mut self, @@ -1684,12 +1716,8 @@ pub type SubstrateHostFunctions = ( #[cfg(test)] mod tests { use super::*; - use sp_core::{ - crypto::UncheckedInto, map, storage::Storage, testing::TaskExecutor, - traits::TaskExecutorExt, - }; + use sp_core::{crypto::UncheckedInto, map, storage::Storage}; use sp_state_machine::BasicExternalities; - use std::any::TypeId; #[test] fn storage_works() { @@ -1781,54 +1809,6 @@ mod tests { }); } - #[test] - fn batch_verify_start_finish_works() { - let mut ext = BasicExternalities::default(); - ext.register_extension(TaskExecutorExt::new(TaskExecutor::new())); - - ext.execute_with(|| { - crypto::start_batch_verify(); - }); - - assert!(ext.extensions().get_mut(TypeId::of::()).is_some()); - - ext.execute_with(|| { - assert!(crypto::finish_batch_verify()); - }); - - assert!(ext.extensions().get_mut(TypeId::of::()).is_none()); - } - - #[test] - fn long_sr25519_batching() { - let mut ext = BasicExternalities::default(); - 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); - let signature = pair.sign(msg.as_bytes()); - crypto::sr25519_batch_verify(&signature, msg.as_bytes(), &pair.public()); - } - - // 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(); - for it in 0..70 { - let msg = format!("Schnorrkel {}!", it); - let signature = pair.sign(msg.as_bytes()); - crypto::sr25519_batch_verify(&signature, msg.as_bytes(), &pair.public()); - } - assert!(crypto::finish_batch_verify()); - }); - } - fn zero_ed_pub() -> ed25519::Public { [0u8; 32].unchecked_into() } @@ -1837,90 +1817,6 @@ mod tests { 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(|| { - // valid ed25519 signature - crypto::start_batch_verify(); - crypto::ed25519_batch_verify(&zero_ed_sig(), &Vec::new(), &zero_ed_pub()); - assert!(crypto::finish_batch_verify()); - - // 2 valid ed25519 signatures - crypto::start_batch_verify(); - - let pair = 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 pair = ed25519::Pair::generate_with_phrase(None).0; - let msg = b"Even more important message"; - let signature = pair.sign(msg); - crypto::ed25519_batch_verify(&signature, msg, &pair.public()); - - assert!(crypto::finish_batch_verify()); - - // 1 valid, 1 invalid ed25519 signature - crypto::start_batch_verify(); - - 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 = 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()); - - // 1 valid ed25519, 2 valid sr25519 - crypto::start_batch_verify(); - - let pair = ed25519::Pair::generate_with_phrase(None).0; - let msg = b"Ed25519 batching"; - let signature = pair.sign(msg); - crypto::ed25519_batch_verify(&signature, msg, &pair.public()); - - let pair = sr25519::Pair::generate_with_phrase(None).0; - let msg = b"Schnorrkel rules"; - let signature = pair.sign(msg); - crypto::sr25519_batch_verify(&signature, msg, &pair.public()); - - let pair = sr25519::Pair::generate_with_phrase(None).0; - let msg = b"Schnorrkel batches!"; - let signature = pair.sign(msg); - crypto::sr25519_batch_verify(&signature, msg, &pair.public()); - - assert!(crypto::finish_batch_verify()); - - // 1 valid sr25519, 1 invalid sr25519 - crypto::start_batch_verify(); - - let pair1 = sr25519::Pair::generate_with_phrase(None).0; - let pair2 = sr25519::Pair::generate_with_phrase(None).0; - let msg = b"Schnorrkcel!"; - 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()); - }); - } - #[test] fn use_dalek_ext_works() { let mut ext = BasicExternalities::default(); diff --git a/primitives/runtime/src/lib.rs b/primitives/runtime/src/lib.rs index 622eac3d831af..2d959425e0f8e 100644 --- a/primitives/runtime/src/lib.rs +++ b/primitives/runtime/src/lib.rs @@ -904,40 +904,6 @@ pub fn print(print: impl traits::Printable) { print.print(); } -/// Batching session. -/// -/// To be used in runtime only. Outside of runtime, just construct -/// `BatchVerifier` directly. -#[must_use = "`verify()` needs to be called to finish batch signature verification!"] -pub struct SignatureBatching(bool); - -impl SignatureBatching { - /// Start new batching session. - pub fn start() -> Self { - sp_io::crypto::start_batch_verify(); - SignatureBatching(false) - } - - /// Verify all signatures submitted during the batching session. - #[must_use] - pub fn verify(mut self) -> bool { - self.0 = true; - sp_io::crypto::finish_batch_verify() - } -} - -impl Drop for SignatureBatching { - fn drop(&mut self) { - // Sanity check. If user forgets to actually call `verify()`. - // - // We should not panic if the current thread is already panicking, - // because Rust otherwise aborts the process. - if !self.0 && !sp_std::thread::panicking() { - panic!("Signature verification has not been called before `SignatureBatching::drop`") - } - } -} - /// Describes on what should happen with a storage transaction. pub enum TransactionOutcome { /// Commit the transaction. @@ -962,7 +928,7 @@ mod tests { use super::*; use codec::{Decode, Encode}; - use sp_core::crypto::{Pair, UncheckedFrom}; + use sp_core::crypto::Pair; use sp_io::TestExternalities; use sp_state_machine::create_proof_check_backend; @@ -1045,36 +1011,6 @@ mod tests { assert!(multi_sig.verify(msg, &multi_signer.into_account())); } - #[test] - #[should_panic(expected = "Signature verification has not been called")] - fn batching_still_finishes_when_not_called_directly() { - let mut ext = sp_state_machine::BasicExternalities::default(); - ext.register_extension(sp_core::traits::TaskExecutorExt::new( - sp_core::testing::TaskExecutor::new(), - )); - - ext.execute_with(|| { - let _batching = SignatureBatching::start(); - 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); - }); - } - - #[test] - #[should_panic(expected = "Hey, I'm an error")] - fn batching_does_not_panic_while_thread_is_already_panicking() { - let mut ext = sp_state_machine::BasicExternalities::default(); - ext.register_extension(sp_core::traits::TaskExecutorExt::new( - sp_core::testing::TaskExecutor::new(), - )); - - ext.execute_with(|| { - let _batching = SignatureBatching::start(); - panic!("Hey, I'm an error"); - }); - } - #[test] fn execute_and_generate_proof_works() { use codec::Encode; diff --git a/primitives/state-machine/src/lib.rs b/primitives/state-machine/src/lib.rs index 90ee962dafa9e..c68cf4d004529 100644 --- a/primitives/state-machine/src/lib.rs +++ b/primitives/state-machine/src/lib.rs @@ -163,7 +163,7 @@ mod execution { use sp_core::{ hexdisplay::HexDisplay, storage::{ChildInfo, ChildType, PrefixedStorageKey}, - traits::{CallContext, CodeExecutor, ReadRuntimeVersionExt, RuntimeCode, SpawnNamed}, + traits::{CallContext, CodeExecutor, ReadRuntimeVersionExt, RuntimeCode}, }; use sp_externalities::Extensions; use std::{ @@ -324,11 +324,9 @@ mod execution { call_data: &'a [u8], mut extensions: Extensions, runtime_code: &'a RuntimeCode, - spawn_handle: impl SpawnNamed + Send + 'static, context: CallContext, ) -> Self { extensions.register(ReadRuntimeVersionExt::new(exec.clone())); - extensions.register(sp_core::traits::TaskExecutorExt::new(spawn_handle)); Self { backend, @@ -511,11 +509,10 @@ 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, - spawn_handle: Spawn, method: &str, call_data: &[u8], runtime_code: &RuntimeCode, @@ -525,14 +522,12 @@ mod execution { H: Hasher, H::Out: Ord + 'static + codec::Codec, Exec: CodeExecutor + Clone + 'static, - Spawn: SpawnNamed + Send + 'static, { let trie_backend = backend.as_trie_backend(); - prove_execution_on_trie_backend::<_, _, _, _>( + prove_execution_on_trie_backend::<_, _, _>( trie_backend, overlay, exec, - spawn_handle, method, call_data, runtime_code, @@ -549,11 +544,10 @@ 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, - spawn_handle: Spawn, method: &str, call_data: &[u8], runtime_code: &RuntimeCode, @@ -564,7 +558,6 @@ mod execution { H: Hasher, H::Out: Ord + 'static + codec::Codec, Exec: CodeExecutor + 'static + Clone, - Spawn: SpawnNamed + Send + 'static, { let proving_backend = TrieBackendBuilder::wrap(trie_backend).with_recorder(Default::default()).build(); @@ -577,7 +570,6 @@ mod execution { call_data, extensions, runtime_code, - spawn_handle, CallContext::Offchain, ) .execute_using_consensus_failure_handler::<_>(always_wasm())?; @@ -590,12 +582,11 @@ 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, exec: &Exec, - spawn_handle: Spawn, method: &str, call_data: &[u8], runtime_code: &RuntimeCode, @@ -604,14 +595,12 @@ mod execution { H: Hasher + 'static, Exec: CodeExecutor + Clone + 'static, H::Out: Ord + 'static + codec::Codec, - Spawn: SpawnNamed + Send + 'static, { let trie_backend = create_proof_check_backend::(root, proof)?; - execution_proof_check_on_trie_backend::<_, _, _>( + execution_proof_check_on_trie_backend::<_, _>( &trie_backend, overlay, exec, - spawn_handle, method, call_data, runtime_code, @@ -619,11 +608,10 @@ 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, - spawn_handle: Spawn, method: &str, call_data: &[u8], runtime_code: &RuntimeCode, @@ -632,7 +620,6 @@ mod execution { H: Hasher, H::Out: Ord + 'static + codec::Codec, Exec: CodeExecutor + Clone + 'static, - Spawn: SpawnNamed + Send + 'static, { StateMachine::<_, H, Exec>::new( trie_backend, @@ -642,7 +629,6 @@ mod execution { call_data, Extensions::default(), runtime_code, - spawn_handle, CallContext::Offchain, ) .execute_using_consensus_failure_handler(always_untrusted_wasm()) @@ -1309,7 +1295,6 @@ mod tests { use sp_core::{ map, storage::{ChildInfo, StateVersion}, - testing::TaskExecutor, traits::{CallContext, CodeExecutor, Externalities, RuntimeCode}, H256, }; @@ -1384,7 +1369,6 @@ mod tests { &[], Default::default(), &wasm_code, - TaskExecutor::new(), CallContext::Offchain, ); @@ -1413,7 +1397,6 @@ mod tests { &[], Default::default(), &wasm_code, - TaskExecutor::new(), CallContext::Offchain, ); @@ -1443,7 +1426,6 @@ mod tests { &[], Default::default(), &wasm_code, - TaskExecutor::new(), CallContext::Offchain, ); @@ -1475,7 +1457,6 @@ mod tests { &mut remote_backend, &mut Default::default(), &executor, - TaskExecutor::new(), "test", &[], &RuntimeCode::empty(), @@ -1483,12 +1464,11 @@ 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(), &executor, - TaskExecutor::new(), "test", &[], &RuntimeCode::empty(), diff --git a/primitives/state-machine/src/testing.rs b/primitives/state-machine/src/testing.rs index a9f6399a9a1b5..3a0165fe4588d 100644 --- a/primitives/state-machine/src/testing.rs +++ b/primitives/state-machine/src/testing.rs @@ -34,8 +34,6 @@ use sp_core::{ well_known_keys::{is_child_storage_key, CODE}, StateVersion, Storage, }, - testing::TaskExecutor, - traits::TaskExecutorExt, }; use sp_externalities::{Extension, ExtensionStore, Extensions}; use sp_trie::StorageProof; @@ -105,9 +103,6 @@ where storage.top.insert(CODE.to_vec(), code.to_vec()); - let mut extensions = Extensions::default(); - extensions.register(TaskExecutorExt::new(TaskExecutor::new())); - let offchain_db = TestPersistentOffchainDB::new(); let backend = (storage, state_version).into(); @@ -115,7 +110,7 @@ where TestExternalities { overlay: OverlayedChanges::default(), offchain_db, - extensions, + extensions: Default::default(), backend, storage_transaction_cache: Default::default(), state_version, diff --git a/test-utils/client/src/lib.rs b/test-utils/client/src/lib.rs index a91aa99929e2f..5e3c9f703fea1 100644 --- a/test-utils/client/src/lib.rs +++ b/test-utils/client/src/lib.rs @@ -291,7 +291,6 @@ impl let executor = LocalCallExecutor::new( self.backend.clone(), executor, - Box::new(sp_core::testing::TaskExecutor::new()), Default::default(), ExecutionExtensions::new( self.execution_strategies.clone(), diff --git a/utils/frame/benchmarking-cli/src/pallet/command.rs b/utils/frame/benchmarking-cli/src/pallet/command.rs index 15ebc668ff4fb..5016d65b89beb 100644 --- a/utils/frame/benchmarking-cli/src/pallet/command.rs +++ b/utils/frame/benchmarking-cli/src/pallet/command.rs @@ -238,7 +238,6 @@ impl PalletCmd { &(self.extra).encode(), extensions(), &sp_state_machine::backend::BackendRuntimeCode::new(state).runtime_code()?, - sp_core::testing::TaskExecutor::new(), CallContext::Offchain, ) .execute(strategy.into()) @@ -376,7 +375,6 @@ impl PalletCmd { extensions(), &sp_state_machine::backend::BackendRuntimeCode::new(state) .runtime_code()?, - sp_core::testing::TaskExecutor::new(), CallContext::Offchain, ) .execute(strategy.into()) @@ -417,7 +415,6 @@ impl PalletCmd { extensions(), &sp_state_machine::backend::BackendRuntimeCode::new(state) .runtime_code()?, - sp_core::testing::TaskExecutor::new(), CallContext::Offchain, ) .execute(strategy.into()) @@ -450,7 +447,6 @@ impl PalletCmd { extensions(), &sp_state_machine::backend::BackendRuntimeCode::new(state) .runtime_code()?, - sp_core::testing::TaskExecutor::new(), CallContext::Offchain, ) .execute(strategy.into()) diff --git a/utils/frame/try-runtime/cli/src/lib.rs b/utils/frame/try-runtime/cli/src/lib.rs index e1873f6a04abd..733eab7f5a262 100644 --- a/utils/frame/try-runtime/cli/src/lib.rs +++ b/utils/frame/try-runtime/cli/src/lib.rs @@ -377,8 +377,7 @@ use sp_core::{ OffchainDbExt, OffchainWorkerExt, TransactionPoolExt, }, storage::well_known_keys, - testing::TaskExecutor, - traits::{CallContext, ReadRuntimeVersion, TaskExecutorExt}, + traits::{CallContext, ReadRuntimeVersion}, twox_128, H256, }; use sp_externalities::Extensions; @@ -813,7 +812,6 @@ where /// 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(); let keystore = MemoryKeystore::new(); @@ -875,7 +873,6 @@ pub(crate) fn state_machine_call( data, extensions, &sp_state_machine::backend::BackendRuntimeCode::new(&ext.backend).runtime_code()?, - sp_core::testing::TaskExecutor::new(), CallContext::Offchain, ) .execute(sp_state_machine::ExecutionStrategy::AlwaysWasm) @@ -915,7 +912,6 @@ pub(crate) fn state_machine_call_with_proof Date: Tue, 4 Apr 2023 13:32:10 +0200 Subject: [PATCH 609/715] Uniform pallet warnings (#13798) * Use proc-macro-warning crate Signed-off-by: Oliver Tale-Yazdi * Fixup Signed-off-by: Oliver Tale-Yazdi * Fix pallet_ui tests Also renamed some of the odd-named ones. Signed-off-by: Oliver Tale-Yazdi * Update dep Signed-off-by: Oliver Tale-Yazdi * Ignore hardcoded weight warning To be fixed in https://github.com/paritytech/substrate/issues/13813 Signed-off-by: Oliver Tale-Yazdi * Fix test pallet Signed-off-by: Oliver Tale-Yazdi * Fix more tests Signed-off-by: Oliver Tale-Yazdi --------- Signed-off-by: Oliver Tale-Yazdi Co-authored-by: parity-processbot <> --- Cargo.lock | 12 +++++ frame/benchmarking/pov/src/lib.rs | 4 +- frame/benchmarking/src/tests.rs | 2 +- frame/benchmarking/src/tests_instance.rs | 4 +- frame/collective/src/tests.rs | 2 +- frame/examples/offchain-worker/src/lib.rs | 6 +-- frame/executive/src/lib.rs | 2 +- frame/membership/src/lib.rs | 14 ++--- frame/nicks/src/lib.rs | 8 +-- frame/scored-pool/src/lib.rs | 12 ++--- frame/sudo/src/lib.rs | 2 +- frame/support/procedural/Cargo.toml | 1 + .../procedural/src/pallet/expand/call.rs | 54 ++++++++++++------- frame/support/test/tests/pallet.rs | 8 +-- frame/support/test/tests/pallet_instance.rs | 2 +- .../call_argument_invalid_bound.stderr | 13 +++++ .../call_argument_invalid_bound_2.stderr | 13 +++++ .../call_argument_invalid_bound_3.stderr | 13 +++++ .../tests/pallet_ui/call_missing_index.rs | 5 ++ .../tests/pallet_ui/call_missing_index.stderr | 47 +++++++++++++--- ....rs => call_weight_argument_has_suffix.rs} | 4 +- .../call_weight_argument_has_suffix.stderr | 20 +++++++ .../pallet_ui/call_weight_const_warning.rs | 21 ++++++++ .../call_weight_const_warning.stderr | 12 +++++ .../call_weight_const_warning_twice.rs | 25 +++++++++ .../call_weight_const_warning_twice.stderr | 31 +++++++++++ ...ev_mode_without_arg_max_encoded_len.stderr | 24 ++++++--- .../weight_argument_has_suffix.stderr | 7 --- frame/support/test/tests/storage_layers.rs | 2 +- frame/utility/src/tests.rs | 4 +- 30 files changed, 299 insertions(+), 75 deletions(-) rename frame/support/test/tests/pallet_ui/{weight_argument_has_suffix.rs => call_weight_argument_has_suffix.rs} (70%) create mode 100644 frame/support/test/tests/pallet_ui/call_weight_argument_has_suffix.stderr create mode 100644 frame/support/test/tests/pallet_ui/call_weight_const_warning.rs create mode 100644 frame/support/test/tests/pallet_ui/call_weight_const_warning.stderr create mode 100644 frame/support/test/tests/pallet_ui/call_weight_const_warning_twice.rs create mode 100644 frame/support/test/tests/pallet_ui/call_weight_const_warning_twice.stderr delete mode 100644 frame/support/test/tests/pallet_ui/weight_argument_has_suffix.stderr diff --git a/Cargo.lock b/Cargo.lock index 1e9a87e818641..ed633fcaa8978 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2468,6 +2468,7 @@ dependencies = [ "derive-syn-parse", "frame-support-procedural-tools", "itertools", + "proc-macro-warning", "proc-macro2", "quote", "syn", @@ -7511,6 +7512,17 @@ dependencies = [ "version_check", ] +[[package]] +name = "proc-macro-warning" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d4f284d87b9cedc2ff57223cbc4e3937cd6063c01e92c8e2a8c080df0013933" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "proc-macro2" version = "1.0.51" diff --git a/frame/benchmarking/pov/src/lib.rs b/frame/benchmarking/pov/src/lib.rs index dccfe72d3f243..66000e54151b0 100644 --- a/frame/benchmarking/pov/src/lib.rs +++ b/frame/benchmarking/pov/src/lib.rs @@ -120,14 +120,14 @@ pub mod pallet { #[pallet::call] impl Pallet { #[pallet::call_index(0)] - #[pallet::weight(0)] + #[pallet::weight({0})] pub fn emit_event(_origin: OriginFor) -> DispatchResult { Self::deposit_event(Event::TestEvent); Ok(()) } #[pallet::call_index(1)] - #[pallet::weight(0)] + #[pallet::weight({0})] pub fn noop(_origin: OriginFor) -> DispatchResult { Ok(()) } diff --git a/frame/benchmarking/src/tests.rs b/frame/benchmarking/src/tests.rs index 453e8e125cbb3..80b631bb73668 100644 --- a/frame/benchmarking/src/tests.rs +++ b/frame/benchmarking/src/tests.rs @@ -29,7 +29,7 @@ use sp_runtime::{ use sp_std::prelude::*; use std::cell::RefCell; -#[frame_support::pallet] +#[frame_support::pallet(dev_mode)] mod pallet_test { use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; diff --git a/frame/benchmarking/src/tests_instance.rs b/frame/benchmarking/src/tests_instance.rs index d49d7cc817c6b..92d78b9ecbbe1 100644 --- a/frame/benchmarking/src/tests_instance.rs +++ b/frame/benchmarking/src/tests_instance.rs @@ -61,7 +61,7 @@ mod pallet_test { ::OtherEvent: Into<>::RuntimeEvent>, { #[pallet::call_index(0)] - #[pallet::weight(0)] + #[pallet::weight({0})] pub fn set_value(origin: OriginFor, n: u32) -> DispatchResult { let _sender = ensure_signed(origin)?; Value::::put(n); @@ -69,7 +69,7 @@ mod pallet_test { } #[pallet::call_index(1)] - #[pallet::weight(0)] + #[pallet::weight({0})] pub fn dummy(origin: OriginFor, _n: u32) -> DispatchResult { let _sender = ensure_none(origin)?; Ok(()) diff --git a/frame/collective/src/tests.rs b/frame/collective/src/tests.rs index 79f6cc27fadbd..2550ab3ed2017 100644 --- a/frame/collective/src/tests.rs +++ b/frame/collective/src/tests.rs @@ -51,7 +51,7 @@ frame_support::construct_runtime!( mod mock_democracy { pub use pallet::*; - #[frame_support::pallet] + #[frame_support::pallet(dev_mode)] pub mod pallet { use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; diff --git a/frame/examples/offchain-worker/src/lib.rs b/frame/examples/offchain-worker/src/lib.rs index 1a63955c04741..6ce8524174200 100644 --- a/frame/examples/offchain-worker/src/lib.rs +++ b/frame/examples/offchain-worker/src/lib.rs @@ -229,7 +229,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(0)] - #[pallet::weight(0)] + #[pallet::weight({0})] pub fn submit_price(origin: OriginFor, price: u32) -> DispatchResultWithPostInfo { // Retrieve sender of the transaction. let who = ensure_signed(origin)?; @@ -255,7 +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)] + #[pallet::weight({0})] pub fn submit_price_unsigned( origin: OriginFor, _block_number: T::BlockNumber, @@ -272,7 +272,7 @@ pub mod pallet { } #[pallet::call_index(2)] - #[pallet::weight(0)] + #[pallet::weight({0})] pub fn submit_price_unsigned_with_signed_payload( origin: OriginFor, price_payload: PricePayload, diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index 6a1041a28e31b..aad1de11d2c7b 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -694,7 +694,7 @@ mod tests { const TEST_KEY: &[u8] = b":test:key:"; - #[frame_support::pallet] + #[frame_support::pallet(dev_mode)] mod custom { use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; diff --git a/frame/membership/src/lib.rs b/frame/membership/src/lib.rs index 0be33a95613fe..e703b88f3657e 100644 --- a/frame/membership/src/lib.rs +++ b/frame/membership/src/lib.rs @@ -168,7 +168,7 @@ pub mod pallet { /// /// May only be called from `T::AddOrigin`. #[pallet::call_index(0)] - #[pallet::weight(50_000_000)] + #[pallet::weight({50_000_000})] pub fn add_member(origin: OriginFor, who: AccountIdLookupOf) -> DispatchResult { T::AddOrigin::ensure_origin(origin)?; let who = T::Lookup::lookup(who)?; @@ -191,7 +191,7 @@ pub mod pallet { /// /// May only be called from `T::RemoveOrigin`. #[pallet::call_index(1)] - #[pallet::weight(50_000_000)] + #[pallet::weight({50_000_000})] pub fn remove_member(origin: OriginFor, who: AccountIdLookupOf) -> DispatchResult { T::RemoveOrigin::ensure_origin(origin)?; let who = T::Lookup::lookup(who)?; @@ -215,7 +215,7 @@ pub mod pallet { /// /// Prime membership is *not* passed from `remove` to `add`, if extant. #[pallet::call_index(2)] - #[pallet::weight(50_000_000)] + #[pallet::weight({50_000_000})] pub fn swap_member( origin: OriginFor, remove: AccountIdLookupOf, @@ -249,7 +249,7 @@ pub mod pallet { /// /// May only be called from `T::ResetOrigin`. #[pallet::call_index(3)] - #[pallet::weight(50_000_000)] + #[pallet::weight({50_000_000})] pub fn reset_members(origin: OriginFor, members: Vec) -> DispatchResult { T::ResetOrigin::ensure_origin(origin)?; @@ -272,7 +272,7 @@ pub mod pallet { /// /// Prime membership is passed from the origin account to `new`, if extant. #[pallet::call_index(4)] - #[pallet::weight(50_000_000)] + #[pallet::weight({50_000_000})] pub fn change_key(origin: OriginFor, new: AccountIdLookupOf) -> DispatchResult { let remove = ensure_signed(origin)?; let new = T::Lookup::lookup(new)?; @@ -307,7 +307,7 @@ pub mod pallet { /// /// May only be called from `T::PrimeOrigin`. #[pallet::call_index(5)] - #[pallet::weight(50_000_000)] + #[pallet::weight({50_000_000})] pub fn set_prime(origin: OriginFor, who: AccountIdLookupOf) -> DispatchResult { T::PrimeOrigin::ensure_origin(origin)?; let who = T::Lookup::lookup(who)?; @@ -321,7 +321,7 @@ pub mod pallet { /// /// May only be called from `T::PrimeOrigin`. #[pallet::call_index(6)] - #[pallet::weight(50_000_000)] + #[pallet::weight({50_000_000})] pub fn clear_prime(origin: OriginFor) -> DispatchResult { T::PrimeOrigin::ensure_origin(origin)?; Prime::::kill(); diff --git a/frame/nicks/src/lib.rs b/frame/nicks/src/lib.rs index 5f510ce8e4cc0..92865c773d886 100644 --- a/frame/nicks/src/lib.rs +++ b/frame/nicks/src/lib.rs @@ -131,7 +131,7 @@ pub mod pallet { /// ## Complexity /// - O(1). #[pallet::call_index(0)] - #[pallet::weight(50_000_000)] + #[pallet::weight({50_000_000})] pub fn set_name(origin: OriginFor, name: Vec) -> DispatchResult { let sender = ensure_signed(origin)?; @@ -160,7 +160,7 @@ pub mod pallet { /// ## Complexity /// - O(1). #[pallet::call_index(1)] - #[pallet::weight(70_000_000)] + #[pallet::weight({70_000_000})] pub fn clear_name(origin: OriginFor) -> DispatchResult { let sender = ensure_signed(origin)?; @@ -183,7 +183,7 @@ pub mod pallet { /// ## Complexity /// - O(1). #[pallet::call_index(2)] - #[pallet::weight(70_000_000)] + #[pallet::weight({70_000_000})] pub fn kill_name(origin: OriginFor, target: AccountIdLookupOf) -> DispatchResult { T::ForceOrigin::ensure_origin(origin)?; @@ -207,7 +207,7 @@ pub mod pallet { /// ## Complexity /// - O(1). #[pallet::call_index(3)] - #[pallet::weight(70_000_000)] + #[pallet::weight({70_000_000})] pub fn force_name( origin: OriginFor, target: AccountIdLookupOf, diff --git a/frame/scored-pool/src/lib.rs b/frame/scored-pool/src/lib.rs index 336a69a798477..8bd44e2ffac8a 100644 --- a/frame/scored-pool/src/lib.rs +++ b/frame/scored-pool/src/lib.rs @@ -70,7 +70,7 @@ //! //! #[pallet::call] //! impl Pallet { -//! #[pallet::weight(0)] +//! #[pallet::weight({0})] //! pub fn candidate(origin: OriginFor) -> DispatchResult { //! let who = ensure_signed(origin)?; //! @@ -311,7 +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)] + #[pallet::weight({0})] pub fn submit_candidacy(origin: OriginFor) -> DispatchResult { let who = ensure_signed(origin)?; ensure!(!>::contains_key(&who), Error::::AlreadyInPool); @@ -341,7 +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)] + #[pallet::weight({0})] pub fn withdraw_candidacy(origin: OriginFor, index: u32) -> DispatchResult { let who = ensure_signed(origin)?; @@ -360,7 +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)] + #[pallet::weight({0})] pub fn kick( origin: OriginFor, dest: AccountIdLookupOf, @@ -385,7 +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)] + #[pallet::weight({0})] pub fn score( origin: OriginFor, dest: AccountIdLookupOf, @@ -425,7 +425,7 @@ pub mod pallet { /// /// May only be called from root. #[pallet::call_index(4)] - #[pallet::weight(0)] + #[pallet::weight({0})] pub fn change_member_count(origin: OriginFor, count: u32) -> DispatchResult { ensure_root(origin)?; Self::update_member_count(count).map_err(Into::into) diff --git a/frame/sudo/src/lib.rs b/frame/sudo/src/lib.rs index 47309833a0681..1bc206e0063e4 100644 --- a/frame/sudo/src/lib.rs +++ b/frame/sudo/src/lib.rs @@ -195,7 +195,7 @@ pub mod pallet { /// ## Complexity /// - O(1). #[pallet::call_index(2)] - #[pallet::weight(0)] + #[pallet::weight({0})] // FIXME pub fn set_key( origin: OriginFor, new: AccountIdLookupOf, diff --git a/frame/support/procedural/Cargo.toml b/frame/support/procedural/Cargo.toml index ee1ca4dff8873..6dbdd3b3a594d 100644 --- a/frame/support/procedural/Cargo.toml +++ b/frame/support/procedural/Cargo.toml @@ -23,6 +23,7 @@ proc-macro2 = "1.0.37" quote = "1.0.10" syn = { version = "1.0.98", features = ["full"] } frame-support-procedural-tools = { version = "4.0.0-dev", path = "./tools" } +proc-macro-warning = { version = "0.2.0", default-features = false } [features] default = ["std"] diff --git a/frame/support/procedural/src/pallet/expand/call.rs b/frame/support/procedural/src/pallet/expand/call.rs index 0fdf4455ae7d0..74075848d9e9b 100644 --- a/frame/support/procedural/src/pallet/expand/call.rs +++ b/frame/support/procedural/src/pallet/expand/call.rs @@ -54,30 +54,47 @@ pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream { .map(|fn_name| format!("Create a call with the variant `{}`.", fn_name)) .collect::>(); - let mut warning_structs = Vec::new(); - let mut warning_names = Vec::new(); + let mut call_index_warnings = Vec::new(); // Emit a warning for each call that is missing `call_index` when not in dev-mode. for method in &methods { if method.explicit_call_index || def.dev_mode { continue } - let name = syn::Ident::new(&format!("{}", method.name), method.name.span()); - let warning: syn::ItemStruct = syn::parse_quote!( - #[deprecated(note = r" - Implicit call indices are deprecated in favour of explicit ones. - Please ensure that all calls have the `pallet::call_index` attribute or that the - `dev-mode` of the pallet is enabled. For more info see: - and - .")] - #[allow(non_camel_case_types)] - struct #name; - ); - warning_names.push(name); - warning_structs.push(warning); + let warning = proc_macro_warning::Warning::new_deprecated("ImplicitCallIndex") + .index(call_index_warnings.len()) + .old("use implicit call indices") + .new("ensure that all calls have a `pallet::call_index` attribute or put the pallet into `dev` mode") + .help_links(&[ + "https://github.com/paritytech/substrate/pull/12891", + "https://github.com/paritytech/substrate/pull/11381" + ]) + .span(method.name.span()) + .build(); + call_index_warnings.push(warning); } let fn_weight = methods.iter().map(|method| &method.weight); + let mut weight_warnings = Vec::new(); + for weight in fn_weight.clone() { + if def.dev_mode { + continue + } + + match weight { + syn::Expr::Lit(lit) => { + let warning = proc_macro_warning::Warning::new_deprecated("ConstantWeight") + .index(weight_warnings.len()) + .old("use hard-coded constant as call weight") + .new("benchmark all calls or put the pallet into `dev` mode") + .help_link("https://github.com/paritytech/substrate/pull/13798") + .span(lit.span()) + .build(); + weight_warnings.push(warning); + }, + _ => {}, + } + } let fn_doc = methods.iter().map(|method| &method.docs).collect::>(); @@ -203,9 +220,10 @@ pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream { quote::quote_spanned!(span => mod warnings { #( - #warning_structs - // This triggers each deprecated warning once. - const _: Option<#warning_names> = None; + #call_index_warnings + )* + #( + #weight_warnings )* } diff --git a/frame/support/test/tests/pallet.rs b/frame/support/test/tests/pallet.rs index 52acdc5c26e03..1a367c8b379f0 100644 --- a/frame/support/test/tests/pallet.rs +++ b/frame/support/test/tests/pallet.rs @@ -218,7 +218,7 @@ pub mod pallet { /// Doc comment put in metadata #[pallet::call_index(1)] - #[pallet::weight(1)] + #[pallet::weight({1})] pub fn foo_storage_layer( _origin: OriginFor, #[pallet::compact] foo: u32, @@ -232,20 +232,20 @@ pub mod pallet { } #[pallet::call_index(4)] - #[pallet::weight(1)] + #[pallet::weight({1})] pub fn foo_index_out_of_order(_origin: OriginFor) -> DispatchResult { Ok(()) } // Test for DispatchResult return type #[pallet::call_index(2)] - #[pallet::weight(1)] + #[pallet::weight({1})] pub fn foo_no_post_info(_origin: OriginFor) -> DispatchResult { Ok(()) } #[pallet::call_index(3)] - #[pallet::weight(1)] + #[pallet::weight({1})] pub fn check_for_dispatch_context(_origin: OriginFor) -> DispatchResult { with_context::<(), _>(|_| ()).ok_or_else(|| DispatchError::Unavailable) } diff --git a/frame/support/test/tests/pallet_instance.rs b/frame/support/test/tests/pallet_instance.rs index 517f920c5ce07..241492a596993 100644 --- a/frame/support/test/tests/pallet_instance.rs +++ b/frame/support/test/tests/pallet_instance.rs @@ -27,7 +27,7 @@ use sp_io::{ }; use sp_runtime::{DispatchError, ModuleError}; -#[frame_support::pallet] +#[frame_support::pallet(dev_mode)] pub mod pallet { use codec::MaxEncodedLen; use frame_support::{pallet_prelude::*, parameter_types, scale_info}; 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 aed53b07b5e63..d10bf1359019a 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,3 +1,16 @@ +error: use of deprecated constant `pallet::warnings::ConstantWeight_0::_w`: + It is deprecated to use hard-coded constant as call weight. + Please instead benchmark all calls or put the pallet into `dev` mode. + + For more info see: + + --> tests/pallet_ui/call_argument_invalid_bound.rs:19:20 + | +19 | #[pallet::weight(0)] + | ^ + | + = note: `-D deprecated` implied by `-D warnings` + error[E0277]: `::Bar` doesn't implement `std::fmt::Debug` --> tests/pallet_ui/call_argument_invalid_bound.rs:21:36 | 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 476258c03becd..7173cdcd47361 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,3 +1,16 @@ +error: use of deprecated constant `pallet::warnings::ConstantWeight_0::_w`: + It is deprecated to use hard-coded constant as call weight. + Please instead benchmark all calls or put the pallet into `dev` mode. + + For more info see: + + --> tests/pallet_ui/call_argument_invalid_bound_2.rs:19:20 + | +19 | #[pallet::weight(0)] + | ^ + | + = note: `-D deprecated` implied by `-D warnings` + error[E0277]: `::Bar` doesn't implement `std::fmt::Debug` --> tests/pallet_ui/call_argument_invalid_bound_2.rs:21:36 | 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 395da09cb0d6d..1b084dd2f76bc 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,3 +1,16 @@ +error: use of deprecated constant `pallet::warnings::ConstantWeight_0::_w`: + It is deprecated to use hard-coded constant as call weight. + Please instead benchmark all calls or put the pallet into `dev` mode. + + For more info see: + + --> tests/pallet_ui/call_argument_invalid_bound_3.rs:21:20 + | +21 | #[pallet::weight(0)] + | ^ + | + = note: `-D deprecated` implied by `-D warnings` + error[E0277]: `Bar` doesn't implement `std::fmt::Debug` --> tests/pallet_ui/call_argument_invalid_bound_3.rs:23:36 | diff --git a/frame/support/test/tests/pallet_ui/call_missing_index.rs b/frame/support/test/tests/pallet_ui/call_missing_index.rs index 7e305a573d622..98c49f493e50d 100644 --- a/frame/support/test/tests/pallet_ui/call_missing_index.rs +++ b/frame/support/test/tests/pallet_ui/call_missing_index.rs @@ -15,6 +15,11 @@ mod pallet { pub fn foo(_: OriginFor) -> DispatchResult { Ok(()) } + + #[pallet::weight(0)] + pub fn bar(_: OriginFor) -> DispatchResult { + Ok(()) + } } } diff --git a/frame/support/test/tests/pallet_ui/call_missing_index.stderr b/frame/support/test/tests/pallet_ui/call_missing_index.stderr index 9d00204979211..82dbe1d24c28e 100644 --- a/frame/support/test/tests/pallet_ui/call_missing_index.stderr +++ b/frame/support/test/tests/pallet_ui/call_missing_index.stderr @@ -1,12 +1,47 @@ -error: use of deprecated struct `pallet::warnings::foo`: - Implicit call indices are deprecated in favour of explicit ones. - Please ensure that all calls have the `pallet::call_index` attribute or that the - `dev-mode` of the pallet is enabled. For more info see: - and - . +error: use of deprecated constant `pallet::warnings::ImplicitCallIndex_0::_w`: + It is deprecated to use implicit call indices. + Please instead ensure that all calls have a `pallet::call_index` attribute or put the pallet into `dev` mode. + + For more info see: + + --> tests/pallet_ui/call_missing_index.rs:15:10 | 15 | pub fn foo(_: OriginFor) -> DispatchResult { | ^^^ | = note: `-D deprecated` implied by `-D warnings` + +error: use of deprecated constant `pallet::warnings::ImplicitCallIndex_1::_w`: + It is deprecated to use implicit call indices. + Please instead ensure that all calls have a `pallet::call_index` attribute or put the pallet into `dev` mode. + + For more info see: + + + --> tests/pallet_ui/call_missing_index.rs:20:10 + | +20 | pub fn bar(_: OriginFor) -> DispatchResult { + | ^^^ + +error: use of deprecated constant `pallet::warnings::ConstantWeight_0::_w`: + It is deprecated to use hard-coded constant as call weight. + Please instead benchmark all calls or put the pallet into `dev` mode. + + For more info see: + + --> tests/pallet_ui/call_missing_index.rs:14:20 + | +14 | #[pallet::weight(0)] + | ^ + +error: use of deprecated constant `pallet::warnings::ConstantWeight_1::_w`: + It is deprecated to use hard-coded constant as call weight. + Please instead benchmark all calls or put the pallet into `dev` mode. + + For more info see: + + --> tests/pallet_ui/call_missing_index.rs:19:20 + | +19 | #[pallet::weight(0)] + | ^ diff --git a/frame/support/test/tests/pallet_ui/weight_argument_has_suffix.rs b/frame/support/test/tests/pallet_ui/call_weight_argument_has_suffix.rs similarity index 70% rename from frame/support/test/tests/pallet_ui/weight_argument_has_suffix.rs rename to frame/support/test/tests/pallet_ui/call_weight_argument_has_suffix.rs index 99195d21be62e..c122877e8a075 100644 --- a/frame/support/test/tests/pallet_ui/weight_argument_has_suffix.rs +++ b/frame/support/test/tests/pallet_ui/call_weight_argument_has_suffix.rs @@ -1,6 +1,6 @@ #[frame_support::pallet] mod pallet { - use frame_support::pallet_prelude::DispatchResultWithPostInfo; + use frame_support::pallet_prelude::DispatchResult; use frame_system::pallet_prelude::OriginFor; #[pallet::config] @@ -13,7 +13,7 @@ mod pallet { impl Pallet { #[pallet::call_index(0)] #[pallet::weight(10_000something)] - pub fn foo(origin: OriginFor) -> DispatchResultWithPostInfo { Ok(().into()) } + pub fn foo(_: OriginFor) -> DispatchResult { Ok(()) } } } diff --git a/frame/support/test/tests/pallet_ui/call_weight_argument_has_suffix.stderr b/frame/support/test/tests/pallet_ui/call_weight_argument_has_suffix.stderr new file mode 100644 index 0000000000000..0651f003b9e23 --- /dev/null +++ b/frame/support/test/tests/pallet_ui/call_weight_argument_has_suffix.stderr @@ -0,0 +1,20 @@ +error: invalid suffix `something` for number literal + --> tests/pallet_ui/call_weight_argument_has_suffix.rs:15:26 + | +15 | #[pallet::weight(10_000something)] + | ^^^^^^^^^^^^^^^ invalid suffix `something` + | + = help: the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.) + +error: use of deprecated constant `pallet::warnings::ConstantWeight_0::_w`: + It is deprecated to use hard-coded constant as call weight. + Please instead benchmark all calls or put the pallet into `dev` mode. + + For more info see: + + --> tests/pallet_ui/call_weight_argument_has_suffix.rs:15:26 + | +15 | #[pallet::weight(10_000something)] + | ^^^^^^^^^^^^^^^ + | + = note: `-D deprecated` implied by `-D warnings` diff --git a/frame/support/test/tests/pallet_ui/call_weight_const_warning.rs b/frame/support/test/tests/pallet_ui/call_weight_const_warning.rs new file mode 100644 index 0000000000000..2e5dc2a649e70 --- /dev/null +++ b/frame/support/test/tests/pallet_ui/call_weight_const_warning.rs @@ -0,0 +1,21 @@ +#[frame_support::pallet] +mod pallet { + use frame_support::pallet_prelude::DispatchResult; + use frame_system::pallet_prelude::OriginFor; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::call] + impl Pallet { + #[pallet::call_index(0)] + #[pallet::weight(123_u64)] + pub fn foo(_: OriginFor) -> DispatchResult { Ok(()) } + } +} + +fn main() { +} diff --git a/frame/support/test/tests/pallet_ui/call_weight_const_warning.stderr b/frame/support/test/tests/pallet_ui/call_weight_const_warning.stderr new file mode 100644 index 0000000000000..b04c3ec395ce6 --- /dev/null +++ b/frame/support/test/tests/pallet_ui/call_weight_const_warning.stderr @@ -0,0 +1,12 @@ +error: use of deprecated constant `pallet::warnings::ConstantWeight_0::_w`: + It is deprecated to use hard-coded constant as call weight. + Please instead benchmark all calls or put the pallet into `dev` mode. + + For more info see: + + --> tests/pallet_ui/call_weight_const_warning.rs:15:26 + | +15 | #[pallet::weight(123_u64)] + | ^^^^^^^ + | + = note: `-D deprecated` implied by `-D warnings` diff --git a/frame/support/test/tests/pallet_ui/call_weight_const_warning_twice.rs b/frame/support/test/tests/pallet_ui/call_weight_const_warning_twice.rs new file mode 100644 index 0000000000000..798911dba33d9 --- /dev/null +++ b/frame/support/test/tests/pallet_ui/call_weight_const_warning_twice.rs @@ -0,0 +1,25 @@ +#[frame_support::pallet] +mod pallet { + use frame_support::pallet_prelude::DispatchResult; + use frame_system::pallet_prelude::OriginFor; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::call] + impl Pallet { + #[pallet::call_index(0)] + #[pallet::weight(123)] + pub fn foo(_: OriginFor) -> DispatchResult { Ok(()) } + + #[pallet::call_index(1)] + #[pallet::weight(123_custom_prefix)] + pub fn bar(_: OriginFor) -> DispatchResult { Ok(()) } + } +} + +fn main() { +} diff --git a/frame/support/test/tests/pallet_ui/call_weight_const_warning_twice.stderr b/frame/support/test/tests/pallet_ui/call_weight_const_warning_twice.stderr new file mode 100644 index 0000000000000..c656790207504 --- /dev/null +++ b/frame/support/test/tests/pallet_ui/call_weight_const_warning_twice.stderr @@ -0,0 +1,31 @@ +error: invalid suffix `custom_prefix` for number literal + --> tests/pallet_ui/call_weight_const_warning_twice.rs:19:26 + | +19 | #[pallet::weight(123_custom_prefix)] + | ^^^^^^^^^^^^^^^^^ invalid suffix `custom_prefix` + | + = help: the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.) + +error: use of deprecated constant `pallet::warnings::ConstantWeight_0::_w`: + It is deprecated to use hard-coded constant as call weight. + Please instead benchmark all calls or put the pallet into `dev` mode. + + For more info see: + + --> tests/pallet_ui/call_weight_const_warning_twice.rs:15:26 + | +15 | #[pallet::weight(123)] + | ^^^ + | + = note: `-D deprecated` implied by `-D warnings` + +error: use of deprecated constant `pallet::warnings::ConstantWeight_1::_w`: + It is deprecated to use hard-coded constant as call weight. + Please instead benchmark all calls or put the pallet into `dev` mode. + + For more info see: + + --> tests/pallet_ui/call_weight_const_warning_twice.rs:19:26 + | +19 | #[pallet::weight(123_custom_prefix)] + | ^^^^^^^^^^^^^^^^^ 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 c9de991135082..cf502ac5be475 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 @@ -1,9 +1,10 @@ -error: use of deprecated struct `pallet::warnings::my_call`: - Implicit call indices are deprecated in favour of explicit ones. - Please ensure that all calls have the `pallet::call_index` attribute or that the - `dev-mode` of the pallet is enabled. For more info see: - and - . +error: use of deprecated constant `pallet::warnings::ImplicitCallIndex_0::_w`: + It is deprecated to use implicit call indices. + Please instead ensure that all calls have a `pallet::call_index` attribute or put the pallet into `dev` mode. + + For more info see: + + --> tests/pallet_ui/dev_mode_without_arg_max_encoded_len.rs:25:10 | 25 | pub fn my_call(_origin: OriginFor) -> DispatchResult { @@ -11,6 +12,17 @@ error: use of deprecated struct `pallet::warnings::my_call`: | = note: `-D deprecated` implied by `-D warnings` +error: use of deprecated constant `pallet::warnings::ConstantWeight_0::_w`: + It is deprecated to use hard-coded constant as call weight. + Please instead benchmark all calls or put the pallet into `dev` mode. + + For more info see: + + --> tests/pallet_ui/dev_mode_without_arg_max_encoded_len.rs:24:20 + | +24 | #[pallet::weight(0)] + | ^ + error[E0277]: the trait bound `Vec: MaxEncodedLen` is not satisfied --> tests/pallet_ui/dev_mode_without_arg_max_encoded_len.rs:11:12 | diff --git a/frame/support/test/tests/pallet_ui/weight_argument_has_suffix.stderr b/frame/support/test/tests/pallet_ui/weight_argument_has_suffix.stderr deleted file mode 100644 index df9b0798ab93d..0000000000000 --- a/frame/support/test/tests/pallet_ui/weight_argument_has_suffix.stderr +++ /dev/null @@ -1,7 +0,0 @@ -error: invalid suffix `something` for number literal - --> tests/pallet_ui/weight_argument_has_suffix.rs:15:26 - | -15 | #[pallet::weight(10_000something)] - | ^^^^^^^^^^^^^^^ invalid suffix `something` - | - = help: the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.) diff --git a/frame/support/test/tests/storage_layers.rs b/frame/support/test/tests/storage_layers.rs index f124aed9aa561..82174bf9d7141 100644 --- a/frame/support/test/tests/storage_layers.rs +++ b/frame/support/test/tests/storage_layers.rs @@ -22,7 +22,7 @@ use frame_support::{ use pallet::*; use sp_io::TestExternalities; -#[frame_support::pallet] +#[frame_support::pallet(dev_mode)] pub mod pallet { use frame_support::{ensure, pallet_prelude::*}; use frame_system::pallet_prelude::*; diff --git a/frame/utility/src/tests.rs b/frame/utility/src/tests.rs index 04f2728242874..d23c57e69bec5 100644 --- a/frame/utility/src/tests.rs +++ b/frame/utility/src/tests.rs @@ -41,7 +41,7 @@ use sp_runtime::{ type BlockNumber = u64; // example module to test behaviors. -#[frame_support::pallet] +#[frame_support::pallet(dev_mode)] pub mod example { use frame_support::{dispatch::WithPostDispatchInfo, pallet_prelude::*}; use frame_system::pallet_prelude::*; @@ -91,7 +91,7 @@ pub mod example { mod mock_democracy { pub use pallet::*; - #[frame_support::pallet] + #[frame_support::pallet(dev_mode)] pub mod pallet { use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; From 1f0973906057ebdf58b88e3681847e79f6b9c7a9 Mon Sep 17 00:00:00 2001 From: Fredrik Simonsson Date: Tue, 4 Apr 2023 20:42:46 +0900 Subject: [PATCH 610/715] Update documentation for uniques (This PR renames classes and instances to collections and items in the Uniques pallet in order to follow the commonly accepted NFTs terminology.) (#13322) * Update documentation for uniques The documentation was outdated after merge of #11389 Using the widely spread term collections and item instead of the previous class and instance. * Update README.md --------- Co-authored-by: Jegor Sidorenko <5252494+jsidorenko@users.noreply.github.com> Co-authored-by: Jegor Sidorenko --- frame/uniques/README.md | 74 ++++++++++++++++++++++------------------- 1 file changed, 39 insertions(+), 35 deletions(-) diff --git a/frame/uniques/README.md b/frame/uniques/README.md index 8a91a558b5b5f..6cdbcf79f1c95 100644 --- a/frame/uniques/README.md +++ b/frame/uniques/README.md @@ -4,67 +4,71 @@ A simple, secure module for dealing with non-fungible assets. ## Overview -The Uniques module provides functionality for asset management of non-fungible asset classes, including: +The Uniques module provides functionality for non-fungible tokens' management, including: -* Asset Issuance -* Asset Transfer -* Asset Destruction +* Collection Creation +* Item Minting +* Item Transfers +* Item Trading methods +* Attributes Management +* Item Burning -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). +To use it in your runtime, you need to implement [`uniques::Config`](https://paritytech.github.io/substrate/master/pallet_uniques/pallet/trait.Config.html). The supported dispatchable functions are documented in the [`uniques::Call`](https://paritytech.github.io/substrate/master/pallet_uniques/pallet/enum.Call.html) enum. ### Terminology -* **Asset issuance:** The creation of a new asset instance. -* **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 existence and there is exactly one owning account. +* **Collection creation:** The creation of a new collection. +* **Item minting:** The action of creating a new item within a collection. +* **Item transfer:** The action of sending an item from one account to another. +* **Item burning:** The destruction of an item. +* **Non-fungible token (NFT):** An item for which each unit has unique characteristics. There is exactly + one instance of such an item in existence and there is exactly one owning account. ### Goals The Uniques pallet in Substrate is designed to make the following possible: -* Allow accounts to permissionlessly create asset classes (collections of asset instances). -* Allow a named (permissioned) account to mint and burn unique assets within a class. -* Move asset instances between accounts permissionlessly. -* Allow a named (permissioned) account to freeze and unfreeze unique assets within a - class or the entire class. -* Allow the owner of an asset instance to delegate the ability to transfer the asset to some +* Allow accounts to permissionlessly create NFT collections. +* Allow a named (permissioned) account to mint and burn unique items within a collection. +* Move items between accounts permissionlessly. +* Allow a named (permissioned) account to freeze and unfreeze unique items within a + collection or the entire collection. +* Allow the owner of an item to delegate the ability to transfer the item to some named third-party. ## Interface ### Permissionless dispatchables -* `create`: Create a new asset class by placing a deposit. -* `transfer`: Transfer an asset instance to a new owner. -* `redeposit`: Update the deposit amount of an asset instance, potentially freeing funds. +* `create`: Create a new collection by placing a deposit. +* `transfer`: Transfer an item to a new owner. +* `redeposit`: Update the deposit amount of an item, potentially freeing funds. * `approve_transfer`: Name a delegate who may authorise a transfer. * `cancel_approval`: Revert the effects of a previous `approve_transfer`. ### Permissioned dispatchables -* `destroy`: Destroy an asset class. -* `mint`: Mint a new asset instance within an asset class. -* `burn`: Burn an asset instance within an asset class. -* `freeze`: Prevent an individual asset from being transferred. +* `destroy`: Destroy a collection. +* `mint`: Mint a new item within a collection. +* `burn`: Burn an item within a collection. +* `freeze`: Prevent an individual item from being transferred. * `thaw`: Revert the effects of a previous `freeze`. -* `freeze_class`: Prevent all asset within a class from being transferred. -* `thaw_class`: Revert the effects of a previous `freeze_class`. -* `transfer_ownership`: Alter the owner of an asset class, moving all associated deposits. -* `set_team`: Alter the permissioned accounts of an asset class. +* `freeze_collection`: Prevent all items within a collection from being transferred. +* `thaw_collection`: Revert the effects of a previous `freeze_collection`. +* `transfer_ownership`: Alter the owner of a collection, moving all associated deposits. +* `set_team`: Alter the permissioned accounts of a collection. ### Metadata (permissioned) dispatchables -* `set_attribute`: Set a metadata attribute of an asset instance or class. -* `clear_attribute`: Remove a metadata attribute of an asset instance or class. -* `set_metadata`: Set general metadata of an asset instance. -* `clear_metadata`: Remove general metadata of an asset instance. -* `set_class_metadata`: Set general metadata of an asset class. -* `clear_class_metadata`: Remove general metadata of an asset class. +* `set_attribute`: Set an attribute of an item or collection. +* `clear_attribute`: Remove an attribute of an item or collection. +* `set_metadata`: Set general metadata of an item. +* `clear_metadata`: Remove general metadata of an item. +* `set_collection_metadata`: Set general metadata of a collection. +* `clear_collection_metadata`: Remove general metadata of a collection. ### Force (i.e. governance) dispatchables -* `force_create`: Create a new asset class. -* `force_asset_status`: Alter the underlying characteristics of an asset class. +* `force_create`: Create a new collection. +* `force_asset_status`: Alter the underlying characteristics of a collection. 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. From 057f2afd686dceb48c08d8a31f35b338bb5992d3 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Tue, 4 Apr 2023 20:28:46 +0800 Subject: [PATCH 611/715] Implement #[pallet::composite_enum] (#13722) * Implement #[pallet::hold_reason] * Appease clippy * cargo fmt * Update test expectations * Update test expectations * Support composite_enum attribute instead * Update test expectations * Change hold_reason to composite_enum * Add UI test for unsupported identifier when using composite_enum * Fix comment * Add documentation for pallet::composable_enum * More docs * cargo fmt --- .../construct_runtime/expand/freeze_reason.rs | 67 +++++++++ .../construct_runtime/expand/hold_reason.rs | 67 +++++++++ .../src/construct_runtime/expand/lock_id.rs | 67 +++++++++ .../src/construct_runtime/expand/mod.rs | 8 + .../construct_runtime/expand/slash_reason.rs | 67 +++++++++ .../procedural/src/construct_runtime/mod.rs | 12 ++ .../procedural/src/construct_runtime/parse.rs | 24 +++ frame/support/procedural/src/lib.rs | 27 ++++ .../src/pallet/expand/tt_default_parts.rs | 32 +++- frame/support/procedural/src/pallet/mod.rs | 2 +- .../procedural/src/pallet/parse/composite.rs | 139 ++++++++++++++++++ .../procedural/src/pallet/parse/event.rs | 2 +- .../procedural/src/pallet/parse/mod.rs | 36 +++++ frame/support/src/lib.rs | 33 ++++- .../invalid_module_details_keyword.stderr | 2 +- .../invalid_module_entry.stderr | 2 +- frame/support/test/tests/pallet.rs | 26 ++++ .../composite_enum_unsupported_identifier.rs | 13 ++ ...mposite_enum_unsupported_identifier.stderr | 5 + .../tests/pallet_ui/event_wrong_item.stderr | 2 +- .../tests/pallet_ui/hold_reason_non_enum.rs | 14 ++ .../pallet_ui/hold_reason_non_enum.stderr | 5 + .../tests/pallet_ui/hold_reason_not_pub.rs | 14 ++ .../pallet_ui/hold_reason_not_pub.stderr | 5 + .../test/tests/pallet_ui/lock_id_duplicate.rs | 17 +++ .../tests/pallet_ui/lock_id_duplicate.stderr | 5 + 26 files changed, 682 insertions(+), 11 deletions(-) create mode 100644 frame/support/procedural/src/construct_runtime/expand/freeze_reason.rs create mode 100644 frame/support/procedural/src/construct_runtime/expand/hold_reason.rs create mode 100644 frame/support/procedural/src/construct_runtime/expand/lock_id.rs create mode 100644 frame/support/procedural/src/construct_runtime/expand/slash_reason.rs create mode 100644 frame/support/procedural/src/pallet/parse/composite.rs create mode 100644 frame/support/test/tests/pallet_ui/composite_enum_unsupported_identifier.rs create mode 100644 frame/support/test/tests/pallet_ui/composite_enum_unsupported_identifier.stderr create mode 100644 frame/support/test/tests/pallet_ui/hold_reason_non_enum.rs create mode 100644 frame/support/test/tests/pallet_ui/hold_reason_non_enum.stderr create mode 100644 frame/support/test/tests/pallet_ui/hold_reason_not_pub.rs create mode 100644 frame/support/test/tests/pallet_ui/hold_reason_not_pub.stderr create mode 100644 frame/support/test/tests/pallet_ui/lock_id_duplicate.rs create mode 100644 frame/support/test/tests/pallet_ui/lock_id_duplicate.stderr diff --git a/frame/support/procedural/src/construct_runtime/expand/freeze_reason.rs b/frame/support/procedural/src/construct_runtime/expand/freeze_reason.rs new file mode 100644 index 0000000000000..889168bf6c215 --- /dev/null +++ b/frame/support/procedural/src/construct_runtime/expand/freeze_reason.rs @@ -0,0 +1,67 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License + +use crate::construct_runtime::{parse::PalletPath, Pallet}; +use proc_macro2::{Ident, TokenStream}; +use quote::quote; + +pub fn expand_outer_freeze_reason(pallet_decls: &[Pallet], scrate: &TokenStream) -> TokenStream { + let mut conversion_fns = Vec::new(); + let mut freeze_reason_variants = Vec::new(); + for decl in pallet_decls { + if let Some(_) = decl.find_part("FreezeReason") { + let variant_name = &decl.name; + let path = &decl.path; + let index = decl.index; + + conversion_fns.push(expand_conversion_fn(path, variant_name)); + + freeze_reason_variants.push(expand_variant(index, path, variant_name)); + } + } + + quote! { + #[derive( + Copy, Clone, Eq, PartialEq, Ord, PartialOrd, + #scrate::codec::Encode, #scrate::codec::Decode, #scrate::codec::MaxEncodedLen, + #scrate::scale_info::TypeInfo, + #scrate::RuntimeDebug, + )] + pub enum RuntimeFreezeReason { + #( #freeze_reason_variants )* + } + + #( #conversion_fns )* + } +} + +fn expand_conversion_fn(path: &PalletPath, variant_name: &Ident) -> TokenStream { + quote! { + impl From<#path::FreezeReason> for RuntimeFreezeReason { + fn from(hr: #path::FreezeReason) -> Self { + RuntimeFreezeReason::#variant_name(hr) + } + } + } +} + +fn expand_variant(index: u8, path: &PalletPath, variant_name: &Ident) -> TokenStream { + quote! { + #[codec(index = #index)] + #variant_name(#path::FreezeReason), + } +} diff --git a/frame/support/procedural/src/construct_runtime/expand/hold_reason.rs b/frame/support/procedural/src/construct_runtime/expand/hold_reason.rs new file mode 100644 index 0000000000000..60fc094a4d5e4 --- /dev/null +++ b/frame/support/procedural/src/construct_runtime/expand/hold_reason.rs @@ -0,0 +1,67 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License + +use crate::construct_runtime::{parse::PalletPath, Pallet}; +use proc_macro2::{Ident, TokenStream}; +use quote::quote; + +pub fn expand_outer_hold_reason(pallet_decls: &[Pallet], scrate: &TokenStream) -> TokenStream { + let mut conversion_fns = Vec::new(); + let mut hold_reason_variants = Vec::new(); + for decl in pallet_decls { + if let Some(_) = decl.find_part("HoldReason") { + let variant_name = &decl.name; + let path = &decl.path; + let index = decl.index; + + conversion_fns.push(expand_conversion_fn(path, variant_name)); + + hold_reason_variants.push(expand_variant(index, path, variant_name)); + } + } + + quote! { + #[derive( + Copy, Clone, Eq, PartialEq, Ord, PartialOrd, + #scrate::codec::Encode, #scrate::codec::Decode, #scrate::codec::MaxEncodedLen, + #scrate::scale_info::TypeInfo, + #scrate::RuntimeDebug, + )] + pub enum RuntimeHoldReason { + #( #hold_reason_variants )* + } + + #( #conversion_fns )* + } +} + +fn expand_conversion_fn(path: &PalletPath, variant_name: &Ident) -> TokenStream { + quote! { + impl From<#path::HoldReason> for RuntimeHoldReason { + fn from(hr: #path::HoldReason) -> Self { + RuntimeHoldReason::#variant_name(hr) + } + } + } +} + +fn expand_variant(index: u8, path: &PalletPath, variant_name: &Ident) -> TokenStream { + quote! { + #[codec(index = #index)] + #variant_name(#path::HoldReason), + } +} diff --git a/frame/support/procedural/src/construct_runtime/expand/lock_id.rs b/frame/support/procedural/src/construct_runtime/expand/lock_id.rs new file mode 100644 index 0000000000000..77c6fefa0aabd --- /dev/null +++ b/frame/support/procedural/src/construct_runtime/expand/lock_id.rs @@ -0,0 +1,67 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License + +use crate::construct_runtime::{parse::PalletPath, Pallet}; +use proc_macro2::{Ident, TokenStream}; +use quote::quote; + +pub fn expand_outer_lock_id(pallet_decls: &[Pallet], scrate: &TokenStream) -> TokenStream { + let mut conversion_fns = Vec::new(); + let mut lock_id_variants = Vec::new(); + for decl in pallet_decls { + if let Some(_) = decl.find_part("LockId") { + let variant_name = &decl.name; + let path = &decl.path; + let index = decl.index; + + conversion_fns.push(expand_conversion_fn(path, variant_name)); + + lock_id_variants.push(expand_variant(index, path, variant_name)); + } + } + + quote! { + #[derive( + Copy, Clone, Eq, PartialEq, Ord, PartialOrd, + #scrate::codec::Encode, #scrate::codec::Decode, #scrate::codec::MaxEncodedLen, + #scrate::scale_info::TypeInfo, + #scrate::RuntimeDebug, + )] + pub enum RuntimeLockId { + #( #lock_id_variants )* + } + + #( #conversion_fns )* + } +} + +fn expand_conversion_fn(path: &PalletPath, variant_name: &Ident) -> TokenStream { + quote! { + impl From<#path::LockId> for RuntimeLockId { + fn from(hr: #path::LockId) -> Self { + RuntimeLockId::#variant_name(hr) + } + } + } +} + +fn expand_variant(index: u8, path: &PalletPath, variant_name: &Ident) -> TokenStream { + quote! { + #[codec(index = #index)] + #variant_name(#path::LockId), + } +} diff --git a/frame/support/procedural/src/construct_runtime/expand/mod.rs b/frame/support/procedural/src/construct_runtime/expand/mod.rs index ace0b23bd7f85..0fd98bb4dda13 100644 --- a/frame/support/procedural/src/construct_runtime/expand/mod.rs +++ b/frame/support/procedural/src/construct_runtime/expand/mod.rs @@ -18,15 +18,23 @@ mod call; mod config; mod event; +mod freeze_reason; +mod hold_reason; mod inherent; +mod lock_id; mod metadata; mod origin; +mod slash_reason; mod unsigned; pub use call::expand_outer_dispatch; pub use config::expand_outer_config; pub use event::expand_outer_event; +pub use freeze_reason::expand_outer_freeze_reason; +pub use hold_reason::expand_outer_hold_reason; pub use inherent::expand_outer_inherent; +pub use lock_id::expand_outer_lock_id; pub use metadata::expand_runtime_metadata; pub use origin::expand_outer_origin; +pub use slash_reason::expand_outer_slash_reason; pub use unsigned::expand_outer_validate_unsigned; diff --git a/frame/support/procedural/src/construct_runtime/expand/slash_reason.rs b/frame/support/procedural/src/construct_runtime/expand/slash_reason.rs new file mode 100644 index 0000000000000..2bf647aa7c1f4 --- /dev/null +++ b/frame/support/procedural/src/construct_runtime/expand/slash_reason.rs @@ -0,0 +1,67 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License + +use crate::construct_runtime::{parse::PalletPath, Pallet}; +use proc_macro2::{Ident, TokenStream}; +use quote::quote; + +pub fn expand_outer_slash_reason(pallet_decls: &[Pallet], scrate: &TokenStream) -> TokenStream { + let mut conversion_fns = Vec::new(); + let mut slash_reason_variants = Vec::new(); + for decl in pallet_decls { + if let Some(_) = decl.find_part("SlashReason") { + let variant_name = &decl.name; + let path = &decl.path; + let index = decl.index; + + conversion_fns.push(expand_conversion_fn(path, variant_name)); + + slash_reason_variants.push(expand_variant(index, path, variant_name)); + } + } + + quote! { + #[derive( + Copy, Clone, Eq, PartialEq, Ord, PartialOrd, + #scrate::codec::Encode, #scrate::codec::Decode, #scrate::codec::MaxEncodedLen, + #scrate::scale_info::TypeInfo, + #scrate::RuntimeDebug, + )] + pub enum RuntimeSlashReason { + #( #slash_reason_variants )* + } + + #( #conversion_fns )* + } +} + +fn expand_conversion_fn(path: &PalletPath, variant_name: &Ident) -> TokenStream { + quote! { + impl From<#path::SlashReason> for RuntimeSlashReason { + fn from(hr: #path::SlashReason) -> Self { + RuntimeSlashReason::#variant_name(hr) + } + } + } +} + +fn expand_variant(index: u8, path: &PalletPath, variant_name: &Ident) -> TokenStream { + quote! { + #[codec(index = #index)] + #variant_name(#path::SlashReason), + } +} diff --git a/frame/support/procedural/src/construct_runtime/mod.rs b/frame/support/procedural/src/construct_runtime/mod.rs index 9250186dc38e6..a0d414154bfcc 100644 --- a/frame/support/procedural/src/construct_runtime/mod.rs +++ b/frame/support/procedural/src/construct_runtime/mod.rs @@ -268,6 +268,10 @@ fn construct_runtime_final_expansion( let inherent = expand::expand_outer_inherent(&name, &block, &unchecked_extrinsic, &pallets, &scrate); let validate_unsigned = expand::expand_outer_validate_unsigned(&name, &pallets, &scrate); + let freeze_reason = expand::expand_outer_freeze_reason(&pallets, &scrate); + let hold_reason = expand::expand_outer_hold_reason(&pallets, &scrate); + let lock_id = expand::expand_outer_lock_id(&pallets, &scrate); + let slash_reason = expand::expand_outer_slash_reason(&pallets, &scrate); let integrity_test = decl_integrity_test(&scrate); let static_assertions = decl_static_assertions(&name, &pallets, &scrate); @@ -310,6 +314,14 @@ fn construct_runtime_final_expansion( #validate_unsigned + #freeze_reason + + #hold_reason + + #lock_id + + #slash_reason + #integrity_test #static_assertions diff --git a/frame/support/procedural/src/construct_runtime/parse.rs b/frame/support/procedural/src/construct_runtime/parse.rs index b0bebcd9e0f21..5e6979f1d2b3b 100644 --- a/frame/support/procedural/src/construct_runtime/parse.rs +++ b/frame/support/procedural/src/construct_runtime/parse.rs @@ -38,6 +38,10 @@ mod keyword { syn::custom_keyword!(Origin); syn::custom_keyword!(Inherent); syn::custom_keyword!(ValidateUnsigned); + syn::custom_keyword!(FreezeReason); + syn::custom_keyword!(HoldReason); + syn::custom_keyword!(LockId); + syn::custom_keyword!(SlashReason); syn::custom_keyword!(exclude_parts); syn::custom_keyword!(use_parts); } @@ -370,6 +374,10 @@ pub enum PalletPartKeyword { Origin(keyword::Origin), Inherent(keyword::Inherent), ValidateUnsigned(keyword::ValidateUnsigned), + FreezeReason(keyword::FreezeReason), + HoldReason(keyword::HoldReason), + LockId(keyword::LockId), + SlashReason(keyword::SlashReason), } impl Parse for PalletPartKeyword { @@ -392,6 +400,14 @@ impl Parse for PalletPartKeyword { Ok(Self::Inherent(input.parse()?)) } else if lookahead.peek(keyword::ValidateUnsigned) { Ok(Self::ValidateUnsigned(input.parse()?)) + } else if lookahead.peek(keyword::FreezeReason) { + Ok(Self::FreezeReason(input.parse()?)) + } else if lookahead.peek(keyword::HoldReason) { + Ok(Self::HoldReason(input.parse()?)) + } else if lookahead.peek(keyword::LockId) { + Ok(Self::LockId(input.parse()?)) + } else if lookahead.peek(keyword::SlashReason) { + Ok(Self::SlashReason(input.parse()?)) } else { Err(lookahead.error()) } @@ -410,6 +426,10 @@ impl PalletPartKeyword { Self::Origin(_) => "Origin", Self::Inherent(_) => "Inherent", Self::ValidateUnsigned(_) => "ValidateUnsigned", + Self::FreezeReason(_) => "FreezeReason", + Self::HoldReason(_) => "HoldReason", + Self::LockId(_) => "LockId", + Self::SlashReason(_) => "SlashReason", } } @@ -435,6 +455,10 @@ impl Spanned for PalletPartKeyword { Self::Origin(inner) => inner.span(), Self::Inherent(inner) => inner.span(), Self::ValidateUnsigned(inner) => inner.span(), + Self::FreezeReason(inner) => inner.span(), + Self::HoldReason(inner) => inner.span(), + Self::LockId(inner) => inner.span(), + Self::SlashReason(inner) => inner.span(), } } } diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index 45f22202991e8..dea2d4943de00 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -1411,3 +1411,30 @@ pub fn validate_unsigned(_: TokenStream, _: TokenStream) -> TokenStream { pub fn origin(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } + +/// The `#[pallet::composable_enum]` attribute allows you to define an enum that gets composed as an +/// aggregate enum by `construct_runtime`. This is similar in principle with `#[pallet::event]` and +/// `#[pallet::error]`. +/// +/// The attribute currently only supports enum definitions, and identifiers that are named +/// `FreezeReason`, `HoldReason`, `LockId` or `SlashReason`. Arbitrary identifiers for the enum are +/// not supported. The aggregate enum generated by `construct_runtime` will have the name of +/// `RuntimeFreezeReason`, `RuntimeHoldReason`, `RuntimeLockId` and `RuntimeSlashReason` +/// respectively. +/// +/// NOTE: The aggregate enum generated by `construct_runtime` generates a conversion function from +/// the pallet enum to the aggregate enum, and automatically derives the following traits: +/// +/// ```ignore +/// Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, MaxEncodedLen, TypeInfo, +/// RuntimeDebug +/// ``` +/// +/// For ease of usage, when no `#[derive]` attributes are found for the enum under +/// `#[pallet::composable_enum]`, the aforementioned traits are automatically derived for it. The +/// inverse is also true: if there are any `#[derive]` attributes found for the enum, then no traits +/// will automatically be derived for it. +#[proc_macro_attribute] +pub fn composable_enum(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} 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 564b526e93536..f36c765f7beb6 100644 --- a/frame/support/procedural/src/pallet/expand/tt_default_parts.rs +++ b/frame/support/procedural/src/pallet/expand/tt_default_parts.rs @@ -15,7 +15,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::{pallet::Def, COUNTER}; +use crate::{ + pallet::{CompositeKeyword, Def}, + COUNTER, +}; use syn::spanned::Spanned; /// Generate the `tt_default_parts` macro. @@ -48,6 +51,30 @@ pub fn expand_tt_default_parts(def: &mut Def) -> proc_macro2::TokenStream { let validate_unsigned_part = def.validate_unsigned.as_ref().map(|_| quote::quote!(ValidateUnsigned,)); + let freeze_reason_part = def + .composites + .iter() + .any(|c| matches!(c.composite_keyword, CompositeKeyword::FreezeReason(_))) + .then_some(quote::quote!(FreezeReason,)); + + let hold_reason_part = def + .composites + .iter() + .any(|c| matches!(c.composite_keyword, CompositeKeyword::HoldReason(_))) + .then_some(quote::quote!(HoldReason,)); + + let lock_id_part = def + .composites + .iter() + .any(|c| matches!(c.composite_keyword, CompositeKeyword::LockId(_))) + .then_some(quote::quote!(LockId,)); + + let slash_reason_part = def + .composites + .iter() + .any(|c| matches!(c.composite_keyword, CompositeKeyword::SlashReason(_))) + .then_some(quote::quote!(SlashReason,)); + 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 @@ -70,7 +97,8 @@ pub fn expand_tt_default_parts(def: &mut Def) -> proc_macro2::TokenStream { tokens = [{ ::{ Pallet, #call_part #storage_part #event_part #origin_part #config_part - #inherent_part #validate_unsigned_part + #inherent_part #validate_unsigned_part #freeze_reason_part + #hold_reason_part #lock_id_part #slash_reason_part } }] } diff --git a/frame/support/procedural/src/pallet/mod.rs b/frame/support/procedural/src/pallet/mod.rs index 31048841c64e7..3618711051d7f 100644 --- a/frame/support/procedural/src/pallet/mod.rs +++ b/frame/support/procedural/src/pallet/mod.rs @@ -28,7 +28,7 @@ mod expand; mod parse; -pub use parse::Def; +pub use parse::{composite::keyword::CompositeKeyword, Def}; use syn::spanned::Spanned; mod keyword { diff --git a/frame/support/procedural/src/pallet/parse/composite.rs b/frame/support/procedural/src/pallet/parse/composite.rs new file mode 100644 index 0000000000000..2406f10d50a33 --- /dev/null +++ b/frame/support/procedural/src/pallet/parse/composite.rs @@ -0,0 +1,139 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT 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::ToTokens; +use syn::spanned::Spanned; + +pub mod keyword { + use super::*; + + syn::custom_keyword!(FreezeReason); + syn::custom_keyword!(HoldReason); + syn::custom_keyword!(LockId); + syn::custom_keyword!(SlashReason); + pub enum CompositeKeyword { + FreezeReason(FreezeReason), + HoldReason(HoldReason), + LockId(LockId), + SlashReason(SlashReason), + } + + impl Spanned for CompositeKeyword { + fn span(&self) -> proc_macro2::Span { + use CompositeKeyword::*; + match self { + FreezeReason(inner) => inner.span(), + HoldReason(inner) => inner.span(), + LockId(inner) => inner.span(), + SlashReason(inner) => inner.span(), + } + } + } + + impl syn::parse::Parse for CompositeKeyword { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + let lookahead = input.lookahead1(); + if lookahead.peek(FreezeReason) { + Ok(Self::FreezeReason(input.parse()?)) + } else if lookahead.peek(HoldReason) { + Ok(Self::HoldReason(input.parse()?)) + } else if lookahead.peek(LockId) { + Ok(Self::LockId(input.parse()?)) + } else if lookahead.peek(SlashReason) { + Ok(Self::SlashReason(input.parse()?)) + } else { + Err(lookahead.error()) + } + } + } + + impl std::fmt::Display for CompositeKeyword { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + use CompositeKeyword::*; + write!( + f, + "{}", + match self { + FreezeReason(_) => "FreezeReason", + HoldReason(_) => "HoldReason", + LockId(_) => "LockId", + SlashReason(_) => "SlashReason", + } + ) + } + } +} + +pub struct CompositeDef { + /// The index of the HoldReason item in the pallet module. + pub index: usize, + /// The composite keyword used (contains span). + pub composite_keyword: keyword::CompositeKeyword, + /// The span of the pallet::composite_enum attribute. + pub attr_span: proc_macro2::Span, +} + +impl CompositeDef { + pub fn try_from( + attr_span: proc_macro2::Span, + index: usize, + scrate: &proc_macro2::Ident, + item: &mut syn::Item, + ) -> syn::Result { + let item = if let syn::Item::Enum(item) = item { + item + } else { + return Err(syn::Error::new( + item.span(), + "Invalid pallet::composite_enum, expected enum item", + )) + }; + + if !matches!(item.vis, syn::Visibility::Public(_)) { + let msg = format!("Invalid pallet::composite_enum, `{}` must be public", item.ident); + return Err(syn::Error::new(item.span(), msg)) + } + + let has_derive_attr = item.attrs.iter().any(|attr| { + attr.parse_meta() + .ok() + .map(|meta| match meta { + syn::Meta::List(syn::MetaList { path, .. }) => + path.get_ident().map(|ident| ident == "derive").unwrap_or(false), + _ => false, + }) + .unwrap_or(false) + }); + + if !has_derive_attr { + let derive_attr: syn::Attribute = syn::parse_quote! { + #[derive( + Copy, Clone, Eq, PartialEq, Ord, PartialOrd, + #scrate::codec::Encode, #scrate::codec::Decode, #scrate::codec::MaxEncodedLen, + #scrate::scale_info::TypeInfo, + #scrate::RuntimeDebug, + )] + }; + item.attrs.push(derive_attr); + } + + let composite_keyword = + syn::parse2::(item.ident.to_token_stream())?; + + Ok(CompositeDef { index, composite_keyword, attr_span }) + } +} diff --git a/frame/support/procedural/src/pallet/parse/event.rs b/frame/support/procedural/src/pallet/parse/event.rs index 64c3afd557335..0fb8ee4f54977 100644 --- a/frame/support/procedural/src/pallet/parse/event.rs +++ b/frame/support/procedural/src/pallet/parse/event.rs @@ -104,7 +104,7 @@ impl EventDef { let item = if let syn::Item::Enum(item) = item { item } else { - return Err(syn::Error::new(item.span(), "Invalid pallet::event, expected item enum")) + return Err(syn::Error::new(item.span(), "Invalid pallet::event, expected enum item")) }; let event_attrs: Vec = diff --git a/frame/support/procedural/src/pallet/parse/mod.rs b/frame/support/procedural/src/pallet/parse/mod.rs index 94e6f7a7c2f7d..06b9899d03b97 100644 --- a/frame/support/procedural/src/pallet/parse/mod.rs +++ b/frame/support/procedural/src/pallet/parse/mod.rs @@ -20,6 +20,7 @@ //! Parse the module into `Def` struct through `Def::try_from` function. pub mod call; +pub mod composite; pub mod config; pub mod error; pub mod event; @@ -35,6 +36,7 @@ pub mod storage; pub mod type_value; pub mod validate_unsigned; +use composite::{keyword::CompositeKeyword, CompositeDef}; use frame_support_procedural_tools::generate_crate_access_2018; use syn::spanned::Spanned; @@ -56,6 +58,7 @@ pub struct Def { pub genesis_build: Option, pub validate_unsigned: Option, pub extra_constants: Option, + pub composites: Vec, pub type_values: Vec, pub frame_system: syn::Ident, pub frame_support: syn::Ident, @@ -91,6 +94,7 @@ impl Def { let mut extra_constants = None; let mut storages = vec![]; let mut type_values = vec![]; + let mut composites: Vec = vec![]; for (index, item) in items.iter_mut().enumerate() { let pallet_attr: Option = helper::take_first_item_pallet_attr(item)?; @@ -135,6 +139,32 @@ impl Def { Some(PalletAttr::ExtraConstants(_)) => extra_constants = Some(extra_constants::ExtraConstantsDef::try_from(index, item)?), + Some(PalletAttr::Composite(span)) => { + let composite = + composite::CompositeDef::try_from(span, index, &frame_support, item)?; + if composites.iter().any(|def| { + match (&def.composite_keyword, &composite.composite_keyword) { + ( + CompositeKeyword::FreezeReason(_), + CompositeKeyword::FreezeReason(_), + ) | + (CompositeKeyword::HoldReason(_), CompositeKeyword::HoldReason(_)) | + (CompositeKeyword::LockId(_), CompositeKeyword::LockId(_)) | + ( + CompositeKeyword::SlashReason(_), + CompositeKeyword::SlashReason(_), + ) => true, + _ => false, + } + }) { + let msg = format!( + "Invalid duplicated `{}` definition", + composite.composite_keyword + ); + return Err(syn::Error::new(composite.composite_keyword.span(), &msg)) + } + composites.push(composite); + }, Some(attr) => { let msg = "Invalid duplicated attribute"; return Err(syn::Error::new(attr.span(), msg)) @@ -171,6 +201,7 @@ impl Def { origin, inherent, storages, + composites, type_values, frame_system, frame_support, @@ -385,6 +416,7 @@ mod keyword { syn::custom_keyword!(generate_store); syn::custom_keyword!(Store); syn::custom_keyword!(extra_constants); + syn::custom_keyword!(composite_enum); } /// Parse attributes for item in pallet module @@ -404,6 +436,7 @@ enum PalletAttr { ValidateUnsigned(proc_macro2::Span), TypeValue(proc_macro2::Span), ExtraConstants(proc_macro2::Span), + Composite(proc_macro2::Span), } impl PalletAttr { @@ -423,6 +456,7 @@ impl PalletAttr { Self::ValidateUnsigned(span) => *span, Self::TypeValue(span) => *span, Self::ExtraConstants(span) => *span, + Self::Composite(span) => *span, } } } @@ -464,6 +498,8 @@ impl syn::parse::Parse for PalletAttr { Ok(PalletAttr::TypeValue(content.parse::()?.span())) } else if lookahead.peek(keyword::extra_constants) { Ok(PalletAttr::ExtraConstants(content.parse::()?.span())) + } else if lookahead.peek(keyword::composite_enum) { + Ok(PalletAttr::Composite(content.parse::()?.span())) } else { Err(lookahead.error()) } diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index b845828455793..e0ebeb68a3eaf 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -1552,6 +1552,7 @@ pub mod pallet_prelude { /// * [`pallet::inherent`](#inherent-palletinherent-optional) /// * [`pallet::validate_unsigned`](#validate-unsigned-palletvalidate_unsigned-optional) /// * [`pallet::origin`](#origin-palletorigin-optional) +/// * [`pallet::composable_enum`](#composable-enum-palletcomposable_enum-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 @@ -2277,6 +2278,29 @@ pub mod pallet_prelude { /// /// Also see [`pallet::origin`](`frame_support::pallet_macros::origin`) /// +/// # Composable enum `#[pallet::composable_enum]` (optional) +/// +/// The `#[pallet::composable_enum]` attribute allows you to define an enum on the pallet which +/// will then instruct `construct_runtime` to amalgamate all similarly-named enums from other +/// pallets into an aggregate enum. This is similar in principle with how the aggregate enum is +/// generated for `#[pallet::event]` or `#[pallet::error]`. +/// +/// The item tagged with `#[pallet::composable_enum]` MUST be an enum declaration, and can ONLY +/// be the following identifiers: `FreezeReason`, `HoldReason`, `LockId` or `SlashReason`. +/// Custom identifiers are not supported. +/// +/// NOTE: For ease of usage, when no `#[derive]` attributes are detected, the +/// `#[pallet::composable_enum]` attribute will automatically derive the following traits for +/// the enum: +/// +/// ```ignore +/// Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, MaxEncodedLen, TypeInfo, +/// RuntimeDebug +/// ``` +/// +/// The inverse is also true: if there are any #[derive] attributes present for the enum, then +/// the attribute will not automatically derive any of the traits described above. +/// /// # General notes on instantiable pallets /// /// An instantiable pallet is one where Config is generic, i.e. `Config`. This allows @@ -2808,10 +2832,11 @@ 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, + call_index, compact, composable_enum, 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, }; } diff --git a/frame/support/test/tests/construct_runtime_ui/invalid_module_details_keyword.stderr b/frame/support/test/tests/construct_runtime_ui/invalid_module_details_keyword.stderr index 29df6e4bd8cb5..42f79e96d4473 100644 --- a/frame/support/test/tests/construct_runtime_ui/invalid_module_details_keyword.stderr +++ b/frame/support/test/tests/construct_runtime_ui/invalid_module_details_keyword.stderr @@ -1,4 +1,4 @@ -error: expected one of: `Pallet`, `Call`, `Storage`, `Event`, `Config`, `Origin`, `Inherent`, `ValidateUnsigned` +error: expected one of: `Pallet`, `Call`, `Storage`, `Event`, `Config`, `Origin`, `Inherent`, `ValidateUnsigned`, `FreezeReason`, `HoldReason`, `LockId`, `SlashReason` --> $DIR/invalid_module_details_keyword.rs:9:20 | 9 | system: System::{enum}, diff --git a/frame/support/test/tests/construct_runtime_ui/invalid_module_entry.stderr b/frame/support/test/tests/construct_runtime_ui/invalid_module_entry.stderr index bd3e672dc8b40..6d535ca4335fc 100644 --- a/frame/support/test/tests/construct_runtime_ui/invalid_module_entry.stderr +++ b/frame/support/test/tests/construct_runtime_ui/invalid_module_entry.stderr @@ -1,4 +1,4 @@ -error: expected one of: `Pallet`, `Call`, `Storage`, `Event`, `Config`, `Origin`, `Inherent`, `ValidateUnsigned` +error: expected one of: `Pallet`, `Call`, `Storage`, `Event`, `Config`, `Origin`, `Inherent`, `ValidateUnsigned`, `FreezeReason`, `HoldReason`, `LockId`, `SlashReason` --> $DIR/invalid_module_entry.rs:10:23 | 10 | Balance: balances::{Error}, diff --git a/frame/support/test/tests/pallet.rs b/frame/support/test/tests/pallet.rs index 1a367c8b379f0..37f1219a800f5 100644 --- a/frame/support/test/tests/pallet.rs +++ b/frame/support/test/tests/pallet.rs @@ -476,6 +476,11 @@ pub mod pallet { } } + #[pallet::composite_enum] + pub enum HoldReason { + Staking, + } + #[derive(codec::Encode, sp_runtime::RuntimeDebug)] #[cfg_attr(feature = "std", derive(codec::Decode))] pub enum InherentError { @@ -570,6 +575,16 @@ pub mod pallet2 { { fn build(&self) {} } + + #[pallet::composite_enum] + pub enum HoldReason { + Governance, + } + + #[pallet::composite_enum] + pub enum SlashReason { + Equivocation, + } } /// Test that the supertrait check works when we pass some parameter to the `frame_system::Config`. @@ -974,6 +989,17 @@ fn validate_unsigned_expand() { assert_eq!(validity, ValidTransaction::default()); } +#[test] +fn composite_expand() { + let hold_reason: RuntimeHoldReason = pallet::HoldReason::Staking.into(); + let hold_reason2: RuntimeHoldReason = pallet2::HoldReason::Governance.into(); + let slash_reason: RuntimeSlashReason = pallet2::SlashReason::Equivocation.into(); + + assert_eq!(hold_reason, RuntimeHoldReason::Example(pallet::HoldReason::Staking)); + assert_eq!(hold_reason2, RuntimeHoldReason::Example2(pallet2::HoldReason::Governance)); + assert_eq!(slash_reason, RuntimeSlashReason::Example2(pallet2::SlashReason::Equivocation)); +} + #[test] fn pallet_expand_deposit_event() { TestExternalities::default().execute_with(|| { diff --git a/frame/support/test/tests/pallet_ui/composite_enum_unsupported_identifier.rs b/frame/support/test/tests/pallet_ui/composite_enum_unsupported_identifier.rs new file mode 100644 index 0000000000000..74692ee94efd2 --- /dev/null +++ b/frame/support/test/tests/pallet_ui/composite_enum_unsupported_identifier.rs @@ -0,0 +1,13 @@ +#[frame_support::pallet] +mod pallet { + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::composite_enum] + pub enum HoldReasons {} +} + +fn main() {} \ No newline at end of file diff --git a/frame/support/test/tests/pallet_ui/composite_enum_unsupported_identifier.stderr b/frame/support/test/tests/pallet_ui/composite_enum_unsupported_identifier.stderr new file mode 100644 index 0000000000000..902e8923759b2 --- /dev/null +++ b/frame/support/test/tests/pallet_ui/composite_enum_unsupported_identifier.stderr @@ -0,0 +1,5 @@ +error: expected one of: `FreezeReason`, `HoldReason`, `LockId`, `SlashReason` + --> tests/pallet_ui/composite_enum_unsupported_identifier.rs:10:11 + | +10 | pub enum HoldReasons {} + | ^^^^^^^^^^^ diff --git a/frame/support/test/tests/pallet_ui/event_wrong_item.stderr b/frame/support/test/tests/pallet_ui/event_wrong_item.stderr index 21eb0ed35e936..0ef150dfd62e1 100644 --- a/frame/support/test/tests/pallet_ui/event_wrong_item.stderr +++ b/frame/support/test/tests/pallet_ui/event_wrong_item.stderr @@ -1,4 +1,4 @@ -error: Invalid pallet::event, expected item enum +error: Invalid pallet::event, expected enum item --> $DIR/event_wrong_item.rs:19:2 | 19 | pub struct Foo; diff --git a/frame/support/test/tests/pallet_ui/hold_reason_non_enum.rs b/frame/support/test/tests/pallet_ui/hold_reason_non_enum.rs new file mode 100644 index 0000000000000..8008c465e61ad --- /dev/null +++ b/frame/support/test/tests/pallet_ui/hold_reason_non_enum.rs @@ -0,0 +1,14 @@ +#[frame_support::pallet] +mod pallet { + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::composite_enum] + pub struct HoldReason; +} + +fn main() { +} \ No newline at end of file diff --git a/frame/support/test/tests/pallet_ui/hold_reason_non_enum.stderr b/frame/support/test/tests/pallet_ui/hold_reason_non_enum.stderr new file mode 100644 index 0000000000000..7d86b8d4f1bd5 --- /dev/null +++ b/frame/support/test/tests/pallet_ui/hold_reason_non_enum.stderr @@ -0,0 +1,5 @@ +error: Invalid pallet::composite_enum, expected enum item + --> tests/pallet_ui/hold_reason_non_enum.rs:10:2 + | +10 | pub struct HoldReason; + | ^^^ diff --git a/frame/support/test/tests/pallet_ui/hold_reason_not_pub.rs b/frame/support/test/tests/pallet_ui/hold_reason_not_pub.rs new file mode 100644 index 0000000000000..626dad7411319 --- /dev/null +++ b/frame/support/test/tests/pallet_ui/hold_reason_not_pub.rs @@ -0,0 +1,14 @@ +#[frame_support::pallet] +mod pallet { + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::composite_enum] + enum HoldReason {} +} + +fn main() { +} \ No newline at end of file diff --git a/frame/support/test/tests/pallet_ui/hold_reason_not_pub.stderr b/frame/support/test/tests/pallet_ui/hold_reason_not_pub.stderr new file mode 100644 index 0000000000000..e8b0c14e967dd --- /dev/null +++ b/frame/support/test/tests/pallet_ui/hold_reason_not_pub.stderr @@ -0,0 +1,5 @@ +error: Invalid pallet::composite_enum, `HoldReason` must be public + --> tests/pallet_ui/hold_reason_not_pub.rs:10:5 + | +10 | enum HoldReason {} + | ^^^^ diff --git a/frame/support/test/tests/pallet_ui/lock_id_duplicate.rs b/frame/support/test/tests/pallet_ui/lock_id_duplicate.rs new file mode 100644 index 0000000000000..70418efc41421 --- /dev/null +++ b/frame/support/test/tests/pallet_ui/lock_id_duplicate.rs @@ -0,0 +1,17 @@ +#[frame_support::pallet] +mod pallet { + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::composite_enum] + pub enum LockId {} + + #[pallet::composite_enum] + pub enum LockId {} +} + +fn main() { +} \ No newline at end of file diff --git a/frame/support/test/tests/pallet_ui/lock_id_duplicate.stderr b/frame/support/test/tests/pallet_ui/lock_id_duplicate.stderr new file mode 100644 index 0000000000000..1b7097d0a1095 --- /dev/null +++ b/frame/support/test/tests/pallet_ui/lock_id_duplicate.stderr @@ -0,0 +1,5 @@ +error: Invalid duplicated `LockId` definition + --> tests/pallet_ui/lock_id_duplicate.rs:13:14 + | +13 | pub enum LockId {} + | ^^^^^^ From 8548a97f9272c7ca43ac7c091d81e6b9cc8b69e2 Mon Sep 17 00:00:00 2001 From: s0me0ne-unkn0wn <48632512+s0me0ne-unkn0wn@users.noreply.github.com> Date: Tue, 4 Apr 2023 17:10:27 +0200 Subject: [PATCH 612/715] Expose WASM extensions in executor semantics (#13811) * Expose WASM extensions in executor semantics * Fix benches * Remove redundant extensions --- client/executor/benches/bench.rs | 4 ++++ client/executor/src/wasm_runtime.rs | 4 ++++ client/executor/wasmtime/src/runtime.rs | 20 ++++++++++++++++---- client/executor/wasmtime/src/tests.rs | 8 ++++++++ 4 files changed, 32 insertions(+), 4 deletions(-) diff --git a/client/executor/benches/bench.rs b/client/executor/benches/bench.rs index 10425ea461c21..f129ebf64de12 100644 --- a/client/executor/benches/bench.rs +++ b/client/executor/benches/bench.rs @@ -72,6 +72,10 @@ fn initialize( deterministic_stack_limit: None, canonicalize_nans: false, parallel_compilation: true, + wasm_multi_value: false, + wasm_bulk_memory: false, + wasm_reference_types: false, + wasm_simd: false, }, }; diff --git a/client/executor/src/wasm_runtime.rs b/client/executor/src/wasm_runtime.rs index 254380dbb3693..fb3dd0f38006c 100644 --- a/client/executor/src/wasm_runtime.rs +++ b/client/executor/src/wasm_runtime.rs @@ -326,6 +326,10 @@ where deterministic_stack_limit: None, canonicalize_nans: false, parallel_compilation: true, + wasm_multi_value: false, + wasm_bulk_memory: false, + wasm_reference_types: false, + wasm_simd: false, }, }, ) diff --git a/client/executor/wasmtime/src/runtime.rs b/client/executor/wasmtime/src/runtime.rs index de7a2ea0e73df..e01a51f6cf2a7 100644 --- a/client/executor/wasmtime/src/runtime.rs +++ b/client/executor/wasmtime/src/runtime.rs @@ -325,10 +325,10 @@ fn common_config(semantics: &Semantics) -> std::result::Result Date: Tue, 4 Apr 2023 20:57:21 +0200 Subject: [PATCH 613/715] Deprecate V1 Weights (#13699) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Remove deprecated pallet calls Signed-off-by: Oliver Tale-Yazdi * Deprecate old weight Signed-off-by: Oliver Tale-Yazdi * Update Runtime API Signed-off-by: Oliver Tale-Yazdi * Fix tests Signed-off-by: Oliver Tale-Yazdi * Delete shitty code Signed-off-by: Oliver Tale-Yazdi * Fix doctest Signed-off-by: Oliver Tale-Yazdi * Update frame/alliance/src/lib.rs Co-authored-by: Koute * Add doc Signed-off-by: Oliver Tale-Yazdi * contracts: Use u64 as old weight type Signed-off-by: Oliver Tale-Yazdi * Update frame/contracts/src/lib.rs Co-authored-by: Alexander Theißen --------- Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Koute Co-authored-by: Alexander Theißen Co-authored-by: parity-processbot <> --- frame/alliance/src/lib.rs | 33 +------- frame/collective/src/lib.rs | 56 +------------- frame/contracts/src/lib.rs | 10 ++- frame/contracts/src/wasm/mod.rs | 19 +++-- frame/support/src/dispatch.rs | 75 ++++++++++--------- frame/system/src/tests.rs | 31 ++++++-- .../rpc/runtime-api/src/lib.rs | 4 +- frame/transaction-payment/rpc/src/lib.rs | 41 +++------- primitives/weights/src/lib.rs | 4 + primitives/weights/src/weight_v2.rs | 7 +- 10 files changed, 108 insertions(+), 172 deletions(-) diff --git a/frame/alliance/src/lib.rs b/frame/alliance/src/lib.rs index 6cc162f7d2f3d..d50e20ba00c07 100644 --- a/frame/alliance/src/lib.rs +++ b/frame/alliance/src/lib.rs @@ -114,7 +114,7 @@ use frame_support::{ ChangeMembers, Currency, Get, InitializeMembers, IsSubType, OnUnbalanced, ReservableCurrency, }, - weights::{OldWeight, Weight}, + weights::Weight, }; use pallet_identity::IdentityField; @@ -539,36 +539,7 @@ pub mod pallet { Ok(()) } - /// 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(); - 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.into()) - })] - #[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: 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); - - Self::do_close(proposal_hash, index, proposal_weight_bound, length_bound) - } + // Index 2 was `close_old_weight`; it was removed due to weights v1 deprecation. /// Initialize the Alliance, onboard fellows and allies. /// diff --git a/frame/collective/src/lib.rs b/frame/collective/src/lib.rs index c58965d2c9199..bde08f08c13b4 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::{OldWeight, Weight}, + weights::Weight, }; #[cfg(test)] @@ -557,59 +557,7 @@ pub mod pallet { } } - /// 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. - /// - /// ## Complexity - /// - `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) - #[pallet::call_index(4)] - #[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.into()) - }, - DispatchClass::Operational - ))] - #[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: 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) - } + // Index 4 was `close_old_weight`; it was removed due to weights v1 deprecation. /// Disapprove a proposal, close, and remove it from the system, regardless of its current /// state. diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index dc93a7f06ff2d..6b8b85458c40c 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -115,7 +115,7 @@ use frame_support::{ tokens::fungible::Inspect, ConstU32, Contains, Currency, Get, Randomness, ReservableCurrency, Time, }, - weights::{OldWeight, Weight}, + weights::Weight, BoundedVec, WeakBoundedVec, }; use frame_system::Pallet as System; @@ -150,6 +150,12 @@ type RelaxedCodeVec = WeakBoundedVec::MaxCodeLen>; type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; type DebugBufferVec = BoundedVec::MaxDebugBufferLen>; +/// The old weight type. +/// +/// This is a copy of the [`frame_support::weights::OldWeight`] type since the contracts pallet +/// needs to support it indefinitely. +type OldWeight = u64; + /// 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 @@ -1281,7 +1287,7 @@ impl Pallet { /// Used by backwards compatible extrinsics. We cannot just set the proof_size weight limit to /// zero or an old `Call` will just fail with OutOfGas. fn compat_weight_limit(gas_limit: OldWeight) -> Weight { - Weight::from_parts(gas_limit.0, u64::from(T::MaxCodeLen::get()) * 2) + Weight::from_parts(gas_limit, u64::from(T::MaxCodeLen::get()) * 2) } } diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index 5e4ffcfe0a598..e4e8bea7eb04a 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -370,13 +370,11 @@ mod tests { gas::GasMeter, storage::WriteOutcome, tests::{RuntimeCall, Test, ALICE, BOB}, - BalanceOf, CodeHash, Error, Pallet as Contracts, + BalanceOf, CodeHash, Error, OldWeight, Pallet as Contracts, }; use assert_matches::assert_matches; use frame_support::{ - assert_err, assert_ok, - dispatch::DispatchResultWithPostInfo, - weights::{OldWeight, Weight}, + assert_err, assert_ok, dispatch::DispatchResultWithPostInfo, weights::Weight, }; use pallet_contracts_primitives::{ExecReturnValue, ReturnFlags}; use pretty_assertions::assert_eq; @@ -1632,13 +1630,24 @@ mod tests { let output = execute(CODE_GAS_LEFT, vec![], &mut ext).unwrap(); - let OldWeight(gas_left) = OldWeight::decode(&mut &*output.data).unwrap(); + let gas_left = OldWeight::decode(&mut &*output.data).unwrap(); let actual_left = ext.gas_meter.gas_left(); // 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"); } + /// Test that [`frame_support::weights::OldWeight`] en/decodes the same as our + /// [`crate::OldWeight`]. + #[test] + fn old_weight_decode() { + #![allow(deprecated)] + let sp = frame_support::weights::OldWeight(42).encode(); + let our = crate::OldWeight::decode(&mut &*sp).unwrap(); + + assert_eq!(our, 42); + } + const CODE_VALUE_TRANSFERRED: &str = r#" (module (import "seal0" "seal_value_transferred" (func $seal_value_transferred (param i32 i32))) diff --git a/frame/support/src/dispatch.rs b/frame/support/src/dispatch.rs index 1b87acb4db8dd..9e949ef6d4a21 100644 --- a/frame/support/src/dispatch.rs +++ b/frame/support/src/dispatch.rs @@ -550,27 +550,6 @@ impl ClassifyDispatch for (Weight, DispatchClass, Pays) { // 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::from_parts(actual_computation, 0)), - 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::from_parts(actual_time, 0)), - None => None, - }; - Self { actual_weight, pays_fee } - } -} - impl ClassifyDispatch for u64 { fn classify_dispatch(&self, _: T) -> DispatchClass { DispatchClass::Normal @@ -730,7 +709,7 @@ impl PaysFee for (u64, Pays) { /// ``` /// # #[macro_use] /// # extern crate frame_support; -/// # use frame_support::{weights::Weight, dispatch::{DispatchResultWithPostInfo, WithPostDispatchInfo}}; +/// # use frame_support::{weights::Weight, dispatch::{DispatchResultWithPostInfo, WithPostDispatchInfo, PostDispatchInfo}}; /// # use frame_system::{Config, ensure_signed}; /// decl_module! { /// pub struct Module for enum Call where origin: T::RuntimeOrigin { @@ -744,7 +723,7 @@ impl PaysFee for (u64, Pays) { /// return Ok(None::.into()); /// } /// // expensive calculation not executed: use only a portion of the weight -/// Ok(Some(100_000).into()) +/// Ok(PostDispatchInfo { actual_weight: Some(Weight::from_parts(100_000, 0)), ..Default::default() }) /// } /// } /// } @@ -3214,7 +3193,7 @@ mod tests { OnInitialize, OnRuntimeUpgrade, PalletInfo, }, }; - use sp_weights::RuntimeDbWeight; + use sp_weights::{RuntimeDbWeight, Weight}; pub trait Config: system::Config + Sized where @@ -3535,13 +3514,24 @@ mod tests { fn test_new_call_variant() { Call::::new_call_variant_aux_0(); } + + pub fn from_actual_ref_time(ref_time: Option) -> PostDispatchInfo { + PostDispatchInfo { + actual_weight: ref_time.map(|t| Weight::from_all(t)), + pays_fee: Default::default(), + } + } + + pub fn from_post_weight_info(ref_time: Option, pays_fee: Pays) -> PostDispatchInfo { + PostDispatchInfo { actual_weight: ref_time.map(|t| Weight::from_all(t)), pays_fee } + } } #[cfg(test)] // Do not complain about unused `dispatch` and `dispatch_aux`. #[allow(dead_code)] mod weight_tests { - use super::*; + use super::{tests::*, *}; use sp_core::{parameter_types, Get}; use sp_weights::RuntimeDbWeight; @@ -3655,9 +3645,12 @@ mod weight_tests { #[test] fn extract_actual_weight_works() { let pre = DispatchInfo { weight: Weight::from_parts(1000, 0), ..Default::default() }; - assert_eq!(extract_actual_weight(&Ok(Some(7).into()), &pre), Weight::from_parts(7, 0)); assert_eq!( - extract_actual_weight(&Ok(Some(1000).into()), &pre), + extract_actual_weight(&Ok(from_actual_ref_time(Some(7))), &pre), + Weight::from_parts(7, 0) + ); + assert_eq!( + extract_actual_weight(&Ok(from_actual_ref_time(Some(1000))), &pre), Weight::from_parts(1000, 0) ); assert_eq!( @@ -3673,7 +3666,7 @@ mod weight_tests { fn extract_actual_weight_caps_at_pre_weight() { let pre = DispatchInfo { weight: Weight::from_parts(1000, 0), ..Default::default() }; assert_eq!( - extract_actual_weight(&Ok(Some(1250).into()), &pre), + extract_actual_weight(&Ok(from_actual_ref_time(Some(1250))), &pre), Weight::from_parts(1000, 0) ); assert_eq!( @@ -3688,10 +3681,19 @@ mod weight_tests { #[test] fn extract_actual_pays_fee_works() { let pre = DispatchInfo { weight: Weight::from_parts(1000, 0), ..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(&Ok(from_actual_ref_time(Some(7))), &pre), Pays::Yes); + assert_eq!( + extract_actual_pays_fee(&Ok(from_actual_ref_time(Some(1000)).into()), &pre), + Pays::Yes + ); + assert_eq!( + extract_actual_pays_fee(&Ok(from_post_weight_info(Some(1000), Pays::Yes)), &pre), + Pays::Yes + ); + assert_eq!( + extract_actual_pays_fee(&Ok(from_post_weight_info(Some(1000), Pays::No)), &pre), + Pays::No + ); assert_eq!( extract_actual_pays_fee( &Err(DispatchError::BadOrigin.with_weight(Weight::from_parts(9, 0))), @@ -3715,9 +3717,12 @@ mod weight_tests { 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); + assert_eq!(extract_actual_pays_fee(&Ok(from_actual_ref_time(Some(7))), &pre), Pays::No); + assert_eq!(extract_actual_pays_fee(&Ok(from_actual_ref_time(Some(1000))), &pre), Pays::No); + assert_eq!( + extract_actual_pays_fee(&Ok(from_post_weight_info(Some(1000), Pays::Yes)), &pre), + Pays::No + ); } } diff --git a/frame/system/src/tests.rs b/frame/system/src/tests.rs index 9b60c6915ab1c..fc388800e13b4 100644 --- a/frame/system/src/tests.rs +++ b/frame/system/src/tests.rs @@ -236,17 +236,23 @@ fn deposit_event_uses_actual_weight_and_pays_fee() { .get(DispatchClass::Normal) .base_extrinsic; let pre_info = DispatchInfo { weight: Weight::from_parts(1000, 0), ..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(&Ok(from_actual_ref_time(Some(300))), pre_info); + System::note_applied_extrinsic(&Ok(from_actual_ref_time(Some(1000))), pre_info); System::note_applied_extrinsic( // values over the pre info should be capped at pre dispatch value - &Ok(Some(1200).into()), + &Ok(from_actual_ref_time(Some(1200))), + pre_info, + ); + System::note_applied_extrinsic( + &Ok(from_post_weight_info(Some(2_500_000), Pays::Yes)), 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( + &Ok(from_post_weight_info(Some(2_500_000), Pays::No)), + pre_info, + ); + System::note_applied_extrinsic(&Ok(from_post_weight_info(Some(500), Pays::No)), pre_info); System::note_applied_extrinsic( &Err(DispatchError::BadOrigin.with_weight(Weight::from_parts(999, 0))), pre_info, @@ -289,7 +295,7 @@ fn deposit_event_uses_actual_weight_and_pays_fee() { class: DispatchClass::Operational, ..Default::default() }; - System::note_applied_extrinsic(&Ok(Some(300).into()), pre_info); + System::note_applied_extrinsic(&Ok(from_actual_ref_time(Some(300))), pre_info); let got = System::events(); let want = vec![ @@ -691,3 +697,14 @@ fn ensure_signed_stuff_works() { assert_ok!(EnsureSignedBy::::try_origin(successful_origin)); } } + +pub fn from_actual_ref_time(ref_time: Option) -> PostDispatchInfo { + PostDispatchInfo { + actual_weight: ref_time.map(|t| Weight::from_all(t)), + pays_fee: Default::default(), + } +} + +pub fn from_post_weight_info(ref_time: Option, pays_fee: Pays) -> PostDispatchInfo { + PostDispatchInfo { actual_weight: ref_time.map(|t| Weight::from_all(t)), pays_fee } +} diff --git a/frame/transaction-payment/rpc/runtime-api/src/lib.rs b/frame/transaction-payment/rpc/runtime-api/src/lib.rs index ae4a25bf1711d..0d9c3338250e7 100644 --- a/frame/transaction-payment/rpc/runtime-api/src/lib.rs +++ b/frame/transaction-payment/rpc/runtime-api/src/lib.rs @@ -25,12 +25,10 @@ use sp_runtime::traits::MaybeDisplay; pub use pallet_transaction_payment::{FeeDetails, InclusionFee, RuntimeDispatchInfo}; sp_api::decl_runtime_apis! { - #[api_version(3)] + #[api_version(4)] 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; fn query_weight_to_fee(weight: sp_weights::Weight) -> Balance; diff --git a/frame/transaction-payment/rpc/src/lib.rs b/frame/transaction-payment/rpc/src/lib.rs index 1207a8cbf747a..7f8ed4b802675 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::{ApiExt, ProvideRuntimeApi}; +use sp_api::ProvideRuntimeApi; use sp_blockchain::HeaderBackend; use sp_core::Bytes; use sp_rpc::number::NumberOrHex; @@ -81,7 +81,7 @@ impl From for i32 { impl TransactionPaymentApiServer< ::Hash, - RuntimeDispatchInfo, + RuntimeDispatchInfo, > for TransactionPayment where Block: BlockT, @@ -93,7 +93,7 @@ where &self, encoded_xt: Bytes, at: Option, - ) -> RpcResult> { + ) -> RpcResult> { let api = self.client.runtime_api(); let at_hash = at.unwrap_or_else(|| self.client.info().best_hash); @@ -115,32 +115,15 @@ where )) } - let api_version = api - .api_version::>(at_hash) - .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_hash, uxt, encoded_len) - .map_err(|e| map_err(e, "Unable to query dispatch info.").into()) - } else { - let res = api - .query_info(at_hash, 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, - }) - } + let res = api + .query_info(at_hash, uxt, encoded_len) + .map_err(|e| map_err(e, "Unable to query dispatch info."))?; + + Ok(RuntimeDispatchInfo { + weight: res.weight, + class: res.class, + partial_fee: res.partial_fee, + }) } fn query_fee_details( diff --git a/primitives/weights/src/lib.rs b/primitives/weights/src/lib.rs index faa641a0f0c53..55d9104b00b77 100644 --- a/primitives/weights/src/lib.rs +++ b/primitives/weights/src/lib.rs @@ -18,6 +18,9 @@ //! # Primitives for transaction weighting. #![cfg_attr(not(feature = "std"), no_std)] +// TODO remove once `OldWeight` is gone. I dont know why this is needed, maybe by one of the macros +// of `OldWeight`. +#![allow(deprecated)] extern crate self as sp_weights; @@ -68,6 +71,7 @@ pub mod constants { )] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] #[cfg_attr(feature = "std", serde(transparent))] +#[deprecated(note = "Will be removed soon; use `Weight` instead.")] pub struct OldWeight(pub u64); /// The weight of database operations that the runtime can invoke. diff --git a/primitives/weights/src/weight_v2.rs b/primitives/weights/src/weight_v2.rs index ca137145920bb..cb1cedf18ce87 100644 --- a/primitives/weights/src/weight_v2.rs +++ b/primitives/weights/src/weight_v2.rs @@ -35,12 +35,6 @@ pub struct Weight { proof_size: u64, } -impl From for Weight { - fn from(old: OldWeight) -> Self { - Weight::from_parts(old.0, 0) - } -} - impl Weight { /// Set the reference time part of the weight. pub const fn set_ref_time(mut self, c: u64) -> Self { @@ -74,6 +68,7 @@ impl Weight { &mut self.proof_size } + /// The maximal weight in all dimensions. pub const MAX: Self = Self { ref_time: u64::MAX, proof_size: u64::MAX }; /// Get the conservative min of `self` and `other` weight. From 3b0f4b205e72076357d2b555dbb745ceb8807672 Mon Sep 17 00:00:00 2001 From: Sasha Gryaznov Date: Wed, 5 Apr 2023 07:34:42 +0300 Subject: [PATCH 614/715] update links to ink! (#13819) --- frame/contracts/README.md | 4 ++-- frame/contracts/benchmarks/README.md | 2 +- frame/contracts/src/chain_extension.rs | 4 ++-- frame/contracts/src/lib.rs | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/frame/contracts/README.md b/frame/contracts/README.md index 68fa49debc580..cf89c9514142d 100644 --- a/frame/contracts/README.md +++ b/frame/contracts/README.md @@ -106,14 +106,14 @@ Look for the `define_env!` macro invocation. This module executes WebAssembly smart contracts. These can potentially be written in any language that compiles to web assembly. However, using a language that specifically targets this module -will make things a lot easier. One such language is [`ink`](https://github.com/paritytech/ink) +will make things a lot easier. One such language is [`ink!`](https://use.ink) which is an [`eDSL`](https://wiki.haskell.org/Embedded_domain_specific_language) that enables writing WebAssembly based smart contracts in the Rust programming language. ## Debugging Contracts can emit messages to the client when called as RPC through the `seal_debug_message` -API. This is exposed in ink! via +API. This is exposed in [ink!](https://use.ink) via [`ink_env::debug_message()`](https://paritytech.github.io/ink/ink_env/fn.debug_message.html). Those messages are gathered into an internal buffer and send to the RPC client. diff --git a/frame/contracts/benchmarks/README.md b/frame/contracts/benchmarks/README.md index a4b15bd840db4..a621dd65d5931 100644 --- a/frame/contracts/benchmarks/README.md +++ b/frame/contracts/benchmarks/README.md @@ -1,6 +1,6 @@ # Benchmarks -This directory contains real world (ink!, solang) contracts which are used in macro benchmarks. +This directory contains real world ([ink!](https://use.ink), [solang](https://github.com/hyperledger/solang)) contracts which are used in macro benchmarks. Those benchmarks are not used to determine weights but rather to compare different contract languages and execution engines with larger wasm modules. diff --git a/frame/contracts/src/chain_extension.rs b/frame/contracts/src/chain_extension.rs index 2c378070813bd..6d1f3df90f23e 100644 --- a/frame/contracts/src/chain_extension.rs +++ b/frame/contracts/src/chain_extension.rs @@ -66,8 +66,8 @@ //! //! # Example //! -//! The ink! repository maintains an -//! [end-to-end example](https://github.com/paritytech/ink/tree/master/examples/rand-extension) +//! The ink-examples repository maintains an +//! [end-to-end example](https://github.com/paritytech/ink-examples/tree/main/rand-extension) //! on how to use a chain extension in order to provide new features to ink! contracts. use crate::{ diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index 6b8b85458c40c..26b16b3291a2f 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -76,7 +76,7 @@ //! The Contract module is a work in progress. The following examples show how this Contract module //! can be used to instantiate and call contracts. //! -//! * [`ink`](https://github.com/paritytech/ink) is +//! * [`ink!`](https://use.ink) is //! an [`eDSL`](https://wiki.haskell.org/Embedded_domain_specific_language) that enables writing //! WebAssembly based smart contracts in the Rust programming language. From 395853ac15e6e1b2405b7244624499c4fc01cbc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 5 Apr 2023 14:27:26 +0200 Subject: [PATCH 615/715] Move registration of `ReadRuntimeVersionExt` to `ExecutionExtension` (#13820) Instead of registering `ReadRuntimeVersionExt` in `sp-state-machine` it is moved to `ExecutionExtension` which provides the default extensions. --- bin/node/testing/src/bench.rs | 9 +++++++-- client/api/src/execution_extensions.rs | 18 ++++++------------ client/service/src/builder.rs | 1 + client/service/src/client/call_executor.rs | 1 + client/service/src/client/client.rs | 1 + primitives/core/src/traits.rs | 10 ++++++++++ primitives/state-machine/src/lib.rs | 6 ++---- test-utils/client/src/lib.rs | 3 ++- .../benchmarking-cli/src/pallet/command.rs | 3 ++- .../cli/src/commands/execute_block.rs | 2 +- .../cli/src/commands/fast_forward.rs | 4 ++-- .../cli/src/commands/follow_chain.rs | 2 +- .../cli/src/commands/offchain_worker.rs | 2 +- utils/frame/try-runtime/cli/src/lib.rs | 5 +++-- 14 files changed, 40 insertions(+), 27 deletions(-) diff --git a/bin/node/testing/src/bench.rs b/bin/node/testing/src/bench.rs index d6bcf6e252fe0..392b78241d288 100644 --- a/bin/node/testing/src/bench.rs +++ b/bin/node/testing/src/bench.rs @@ -411,11 +411,16 @@ impl BenchDb { let client = sc_service::new_client( backend.clone(), - executor, + executor.clone(), genesis_block_builder, None, None, - ExecutionExtensions::new(profile.into_execution_strategies(), None, None), + ExecutionExtensions::new( + profile.into_execution_strategies(), + None, + None, + Arc::new(executor), + ), Box::new(task_executor.clone()), None, None, diff --git a/client/api/src/execution_extensions.rs b/client/api/src/execution_extensions.rs index ffa670f7bc628..9344afbd3e6dd 100644 --- a/client/api/src/execution_extensions.rs +++ b/client/api/src/execution_extensions.rs @@ -27,6 +27,7 @@ use parking_lot::RwLock; use sc_transaction_pool_api::OffchainSubmitTransaction; use sp_core::{ offchain::{self, OffchainDbExt, OffchainWorkerExt, TransactionPoolExt}, + traits::{ReadRuntimeVersion, ReadRuntimeVersionExt}, ExecutionContext, }; use sp_externalities::{Extension, Extensions}; @@ -173,18 +174,7 @@ pub struct ExecutionExtensions { // during initialization. transaction_pool: RwLock>>>, extensions_factory: RwLock>>, -} - -impl Default for ExecutionExtensions { - fn default() -> Self { - Self { - strategies: Default::default(), - keystore: None, - offchain_db: None, - transaction_pool: RwLock::new(None), - extensions_factory: RwLock::new(Box::new(())), - } - } + read_runtime_version: Arc, } impl ExecutionExtensions { @@ -193,6 +183,7 @@ impl ExecutionExtensions { strategies: ExecutionStrategies, keystore: Option, offchain_db: Option>, + read_runtime_version: Arc, ) -> Self { let transaction_pool = RwLock::new(None); let extensions_factory = Box::new(()); @@ -202,6 +193,7 @@ impl ExecutionExtensions { offchain_db, extensions_factory: RwLock::new(extensions_factory), transaction_pool, + read_runtime_version, } } @@ -271,6 +263,8 @@ impl ExecutionExtensions { ))); } + extensions.register(ReadRuntimeVersionExt::new(self.read_runtime_version.clone())); + extensions } diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index 5d639431f427b..d399b315414f8 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -181,6 +181,7 @@ where config.execution_strategies.clone(), Some(keystore_container.keystore()), sc_offchain::OffchainDb::factory_from_backend(&*backend), + Arc::new(executor.clone()), ); let wasm_runtime_substitutes = config diff --git a/client/service/src/client/call_executor.rs b/client/service/src/client/call_executor.rs index 4d019be908b86..ef36768febdbd 100644 --- a/client/service/src/client/call_executor.rs +++ b/client/service/src/client/call_executor.rs @@ -427,6 +427,7 @@ mod tests { Default::default(), None, None, + Arc::new(executor.clone()), )), }; diff --git a/client/service/src/client/client.rs b/client/service/src/client/client.rs index 3adb6d8976969..eee7e6b82363c 100644 --- a/client/service/src/client/client.rs +++ b/client/service/src/client/client.rs @@ -243,6 +243,7 @@ where Default::default(), keystore, sc_offchain::OffchainDb::factory_from_backend(&*backend), + Arc::new(executor.clone()), ); let call_executor = diff --git a/primitives/core/src/traits.rs b/primitives/core/src/traits.rs index 51327868474a0..40137053ab752 100644 --- a/primitives/core/src/traits.rs +++ b/primitives/core/src/traits.rs @@ -157,6 +157,16 @@ pub trait ReadRuntimeVersion: Send + Sync { ) -> Result, String>; } +impl ReadRuntimeVersion for std::sync::Arc { + fn read_runtime_version( + &self, + wasm_code: &[u8], + ext: &mut dyn Externalities, + ) -> Result, String> { + (**self).read_runtime_version(wasm_code, ext) + } +} + sp_externalities::decl_extension! { /// An extension that provides functionality to read version information from a given wasm blob. pub struct ReadRuntimeVersionExt(Box); diff --git a/primitives/state-machine/src/lib.rs b/primitives/state-machine/src/lib.rs index c68cf4d004529..0001d0026c394 100644 --- a/primitives/state-machine/src/lib.rs +++ b/primitives/state-machine/src/lib.rs @@ -163,7 +163,7 @@ mod execution { use sp_core::{ hexdisplay::HexDisplay, storage::{ChildInfo, ChildType, PrefixedStorageKey}, - traits::{CallContext, CodeExecutor, ReadRuntimeVersionExt, RuntimeCode}, + traits::{CallContext, CodeExecutor, RuntimeCode}, }; use sp_externalities::Extensions; use std::{ @@ -322,12 +322,10 @@ mod execution { exec: &'a Exec, method: &'a str, call_data: &'a [u8], - mut extensions: Extensions, + extensions: Extensions, runtime_code: &'a RuntimeCode, context: CallContext, ) -> Self { - extensions.register(ReadRuntimeVersionExt::new(exec.clone())); - Self { backend, exec, diff --git a/test-utils/client/src/lib.rs b/test-utils/client/src/lib.rs index 5e3c9f703fea1..c4572061c48af 100644 --- a/test-utils/client/src/lib.rs +++ b/test-utils/client/src/lib.rs @@ -290,12 +290,13 @@ impl }); let executor = LocalCallExecutor::new( self.backend.clone(), - executor, + executor.clone(), Default::default(), ExecutionExtensions::new( self.execution_strategies.clone(), self.keystore.clone(), sc_offchain::OffchainDb::factory_from_backend(&*self.backend), + Arc::new(executor), ), ) .expect("Creates LocalCallExecutor"); diff --git a/utils/frame/benchmarking-cli/src/pallet/command.rs b/utils/frame/benchmarking-cli/src/pallet/command.rs index 5016d65b89beb..4d583950d7b3e 100644 --- a/utils/frame/benchmarking-cli/src/pallet/command.rs +++ b/utils/frame/benchmarking-cli/src/pallet/command.rs @@ -35,7 +35,7 @@ use sp_core::{ testing::{TestOffchainExt, TestTransactionPoolExt}, OffchainDbExt, OffchainWorkerExt, TransactionPoolExt, }, - traits::CallContext, + traits::{CallContext, ReadRuntimeVersionExt}, }; use sp_externalities::Extensions; use sp_keystore::{testing::MemoryKeystore, KeystoreExt}; @@ -225,6 +225,7 @@ impl PalletCmd { extensions.register(OffchainWorkerExt::new(offchain.clone())); extensions.register(OffchainDbExt::new(offchain)); extensions.register(TransactionPoolExt::new(pool)); + extensions.register(ReadRuntimeVersionExt::new(executor.clone())); extensions }; 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 561bc57c70c5a..48dab6b9bd1b3 100644 --- a/utils/frame/try-runtime/cli/src/commands/execute_block.rs +++ b/utils/frame/try-runtime/cli/src/commands/execute_block.rs @@ -133,7 +133,7 @@ where &executor, "TryRuntime_execute_block", &payload, - full_extensions(), + full_extensions(executor.clone()), shared.export_proof, )?; diff --git a/utils/frame/try-runtime/cli/src/commands/fast_forward.rs b/utils/frame/try-runtime/cli/src/commands/fast_forward.rs index 75c48c3c402f3..0c517c02fbe81 100644 --- a/utils/frame/try-runtime/cli/src/commands/fast_forward.rs +++ b/utils/frame/try-runtime/cli/src/commands/fast_forward.rs @@ -103,7 +103,7 @@ async fn dry_run( executor, method, data, - full_extensions(), + full_extensions(executor.clone()), )?; Ok(::decode(&mut &*result)?) @@ -121,7 +121,7 @@ async fn run( executor, method, data, - full_extensions(), + full_extensions(executor.clone()), )?; let storage_changes = changes.drain_storage_changes( 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 2a67d269c87f1..413c68550b76d 100644 --- a/utils/frame/try-runtime/cli/src/commands/follow_chain.rs +++ b/utils/frame/try-runtime/cli/src/commands/follow_chain.rs @@ -149,7 +149,7 @@ where &executor, "TryRuntime_execute_block", (block, command.state_root_check, command.try_state.clone()).encode().as_ref(), - full_extensions(), + full_extensions(executor.clone()), shared .export_proof .as_ref() 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 352d552a3f358..4da6f07836cd1 100644 --- a/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs +++ b/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs @@ -97,7 +97,7 @@ where &executor, "OffchainWorkerApi_offchain_worker", &payload, - full_extensions(), + full_extensions(executor.clone()), )?; Ok(()) diff --git a/utils/frame/try-runtime/cli/src/lib.rs b/utils/frame/try-runtime/cli/src/lib.rs index 733eab7f5a262..db690e5086a6c 100644 --- a/utils/frame/try-runtime/cli/src/lib.rs +++ b/utils/frame/try-runtime/cli/src/lib.rs @@ -377,7 +377,7 @@ use sp_core::{ OffchainDbExt, OffchainWorkerExt, TransactionPoolExt, }, storage::well_known_keys, - traits::{CallContext, ReadRuntimeVersion}, + traits::{CallContext, ReadRuntimeVersion, ReadRuntimeVersionExt}, twox_128, H256, }; use sp_externalities::Extensions; @@ -810,7 +810,7 @@ where } /// Build all extensions that we typically use. -pub(crate) fn full_extensions() -> Extensions { +pub(crate) fn full_extensions(wasm_executor: WasmExecutor) -> Extensions { let mut extensions = Extensions::default(); let (offchain, _offchain_state) = TestOffchainExt::new(); let (pool, _pool_state) = TestTransactionPoolExt::new(); @@ -819,6 +819,7 @@ pub(crate) fn full_extensions() -> Extensions { extensions.register(OffchainWorkerExt::new(offchain)); extensions.register(KeystoreExt::new(keystore)); extensions.register(TransactionPoolExt::new(pool)); + extensions.register(ReadRuntimeVersionExt::new(wasm_executor)); extensions } From 5380a9a513918c144175cf2a48d66a35e6e7cad4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Wed, 5 Apr 2023 14:14:46 +0100 Subject: [PATCH 616/715] Mention `on_idle` round-robin logic to `trait Hooks` cargo doc (#13797) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Adds on_idle round-robin logic to trait Hooks docs * Makes the docs more concise * Update frame/support/src/traits/hooks.rs Co-authored-by: Bastian Köcher * fmt --------- Co-authored-by: Bastian Köcher --- frame/support/src/traits/hooks.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/frame/support/src/traits/hooks.rs b/frame/support/src/traits/hooks.rs index a3374d0bf537f..2d346ccd38a8b 100644 --- a/frame/support/src/traits/hooks.rs +++ b/frame/support/src/traits/hooks.rs @@ -227,10 +227,15 @@ pub trait Hooks { fn on_finalize(_n: BlockNumber) {} /// This will be run when the block is being finalized (before `on_finalize`). - /// Implement to have something happen using the remaining weight. - /// 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. + /// + /// Implement to have something happen using the remaining weight. Will not fire if the + /// remaining weight is 0. + /// + /// Each pallet's `on_idle` is chosen to be the first to execute in a round-robin fashion + /// indexed by the block number. + /// + /// Return the weight used, the caller will use this to calculate the remaining weight and then + /// call the next pallet `on_idle` hook if there is still weight left. fn on_idle(_n: BlockNumber, _remaining_weight: Weight) -> Weight { Weight::zero() } From 5601965f39d5899e20f6d89526607ace852c33d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 5 Apr 2023 16:43:17 +0200 Subject: [PATCH 617/715] ProofRecorder: Implement transactional support (#13769) * TrieRecorder: Start adding support for transactions * Adds `transactions` functions and some test * More tests * Docs * Ensure that we rollback failed transactions in the storage proof * FMT * Update primitives/trie/src/recorder.rs Co-authored-by: Dmitry Markin * Review comments * Update primitives/trie/src/recorder.rs Co-authored-by: Sebastian Kunert * ".git/.scripts/commands/fmt/fmt.sh" * For the holy clippy! * Update primitives/trie/src/recorder.rs Co-authored-by: Anton --------- Co-authored-by: Dmitry Markin Co-authored-by: Sebastian Kunert Co-authored-by: command-bot <> Co-authored-by: Anton --- client/block-builder/src/lib.rs | 62 ++- .../api/proc-macro/src/impl_runtime_apis.rs | 50 +- primitives/trie/src/recorder.rs | 463 ++++++++++++++++-- test-utils/runtime/src/lib.rs | 12 +- test-utils/runtime/src/system.rs | 26 + 5 files changed, 573 insertions(+), 40 deletions(-) diff --git a/client/block-builder/src/lib.rs b/client/block-builder/src/lib.rs index d97afadd40156..21f8e6fdd3999 100644 --- a/client/block-builder/src/lib.rs +++ b/client/block-builder/src/lib.rs @@ -312,7 +312,9 @@ mod tests { use sp_blockchain::HeaderBackend; use sp_core::Blake2Hasher; use sp_state_machine::Backend; - use substrate_test_runtime_client::{DefaultTestClientBuilderExt, TestClientBuilderExt}; + use substrate_test_runtime_client::{ + runtime::Extrinsic, DefaultTestClientBuilderExt, TestClientBuilderExt, + }; #[test] fn block_building_storage_proof_does_not_include_runtime_by_default() { @@ -345,4 +347,62 @@ mod tests { .unwrap_err() .contains("Database missing expected key"),); } + + #[test] + fn failing_extrinsic_rolls_back_changes_in_storage_proof() { + let builder = substrate_test_runtime_client::TestClientBuilder::new(); + let backend = builder.backend(); + let client = builder.build(); + + let mut block_builder = BlockBuilder::new( + &client, + client.info().best_hash, + client.info().best_number, + RecordProof::Yes, + Default::default(), + &*backend, + ) + .unwrap(); + + block_builder.push(Extrinsic::ReadAndPanic(8)).unwrap_err(); + + let block = block_builder.build().unwrap(); + + let proof_with_panic = block.proof.expect("Proof is build on request").encoded_size(); + + let mut block_builder = BlockBuilder::new( + &client, + client.info().best_hash, + client.info().best_number, + RecordProof::Yes, + Default::default(), + &*backend, + ) + .unwrap(); + + block_builder.push(Extrinsic::Read(8)).unwrap(); + + let block = block_builder.build().unwrap(); + + let proof_without_panic = block.proof.expect("Proof is build on request").encoded_size(); + + let block = BlockBuilder::new( + &client, + client.info().best_hash, + client.info().best_number, + RecordProof::Yes, + Default::default(), + &*backend, + ) + .unwrap() + .build() + .unwrap(); + + let proof_empty_block = block.proof.expect("Proof is build on request").encoded_size(); + + // Ensure that we rolled back the changes of the panicked transaction. + assert!(proof_without_panic > proof_with_panic); + assert!(proof_without_panic > proof_empty_block); + assert_eq!(proof_empty_block, proof_with_panic); + } } diff --git a/primitives/api/proc-macro/src/impl_runtime_apis.rs b/primitives/api/proc-macro/src/impl_runtime_apis.rs index d0725ffd2ba54..0d265293ecf42 100644 --- a/primitives/api/proc-macro/src/impl_runtime_apis.rs +++ b/primitives/api/proc-macro/src/impl_runtime_apis.rs @@ -243,7 +243,8 @@ fn generate_runtime_api_base_structures() -> Result { &self, call: F, ) -> R where Self: Sized { - #crate_::OverlayedChanges::start_transaction(&mut std::cell::RefCell::borrow_mut(&self.changes)); + self.start_transaction(); + *std::cell::RefCell::borrow_mut(&self.commit_on_success) = false; let res = call(self); *std::cell::RefCell::borrow_mut(&self.commit_on_success) = true; @@ -347,18 +348,51 @@ fn generate_runtime_api_base_structures() -> Result { transactions; qed"; if *std::cell::RefCell::borrow(&self.commit_on_success) { let res = if commit { - #crate_::OverlayedChanges::commit_transaction( + let res = if let Some(recorder) = &self.recorder { + #crate_::ProofRecorder::::commit_transaction(&recorder) + } else { + Ok(()) + }; + + let res2 = #crate_::OverlayedChanges::commit_transaction( &mut std::cell::RefCell::borrow_mut(&self.changes) - ) + ); + + // Will panic on an `Err` below, however we should call commit + // on the recorder and the changes together. + std::result::Result::and(res, std::result::Result::map_err(res2, drop)) } else { - #crate_::OverlayedChanges::rollback_transaction( + let res = if let Some(recorder) = &self.recorder { + #crate_::ProofRecorder::::rollback_transaction(&recorder) + } else { + Ok(()) + }; + + let res2 = #crate_::OverlayedChanges::rollback_transaction( &mut std::cell::RefCell::borrow_mut(&self.changes) - ) + ); + + // Will panic on an `Err` below, however we should call commit + // on the recorder and the changes together. + std::result::Result::and(res, std::result::Result::map_err(res2, drop)) }; std::result::Result::expect(res, proof); } } + + fn start_transaction(&self) { + if !*std::cell::RefCell::borrow(&self.commit_on_success) { + return + } + + #crate_::OverlayedChanges::start_transaction( + &mut std::cell::RefCell::borrow_mut(&self.changes) + ); + if let Some(recorder) = &self.recorder { + #crate_::ProofRecorder::::start_transaction(&recorder); + } + } } )) } @@ -450,11 +484,7 @@ impl<'a> ApiRuntimeImplToApiRuntimeApiImpl<'a> { 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) - ); - } + self.start_transaction(); let res = (|| { let version = #crate_::CallApiAt::<__SrApiBlock__>::runtime_version_at( diff --git a/primitives/trie/src/recorder.rs b/primitives/trie/src/recorder.rs index 3bdfda01532cc..728dc836205b5 100644 --- a/primitives/trie/src/recorder.rs +++ b/primitives/trie/src/recorder.rs @@ -25,7 +25,7 @@ use codec::Encode; use hash_db::Hasher; use parking_lot::Mutex; use std::{ - collections::HashMap, + collections::{HashMap, HashSet}, marker::PhantomData, mem, ops::DerefMut, @@ -38,17 +38,43 @@ use trie_db::{RecordedForKey, TrieAccess}; const LOG_TARGET: &str = "trie-recorder"; +/// Stores all the information per transaction. +#[derive(Default)] +struct Transaction { + /// Stores transaction information about [`RecorderInner::recorded_keys`]. + /// + /// For each transaction we only store the `storage_root` and the old states per key. `None` + /// state means that the key wasn't recorded before. + recorded_keys: HashMap, Option>>, + /// Stores transaction information about [`RecorderInner::accessed_nodes`]. + /// + /// For each transaction we only store the hashes of added nodes. + accessed_nodes: HashSet, +} + /// 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>>, + /// + /// Mapping: `StorageRoot -> (Key -> RecordedForKey)`. + recorded_keys: HashMap, RecordedForKey>>, + + /// Currently active transactions. + transactions: Vec>, + /// The encoded nodes we accessed while recording. + /// + /// Mapping: `Hash(Node) -> Node`. accessed_nodes: HashMap>, } impl Default for RecorderInner { fn default() -> Self { - Self { recorded_keys: Default::default(), accessed_nodes: Default::default() } + Self { + recorded_keys: Default::default(), + accessed_nodes: Default::default(), + transactions: Vec::new(), + } } } @@ -83,6 +109,8 @@ impl Recorder { /// /// - `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). + /// + /// NOTE: This locks a mutex that stays locked until the return value is dropped. #[inline] pub fn as_trie_recorder( &self, @@ -135,6 +163,72 @@ impl Recorder { mem::take(&mut *self.inner.lock()); self.encoded_size_estimation.store(0, Ordering::Relaxed); } + + /// Start a new transaction. + pub fn start_transaction(&self) { + let mut inner = self.inner.lock(); + inner.transactions.push(Default::default()); + } + + /// Rollback the latest transaction. + /// + /// Returns an error if there wasn't any active transaction. + pub fn rollback_transaction(&self) -> Result<(), ()> { + let mut inner = self.inner.lock(); + + // We locked `inner` and can just update the encoded size locally and then store it back to + // the atomic. + let mut new_encoded_size_estimation = self.encoded_size_estimation.load(Ordering::Relaxed); + let transaction = inner.transactions.pop().ok_or(())?; + + transaction.accessed_nodes.into_iter().for_each(|n| { + if let Some(old) = inner.accessed_nodes.remove(&n) { + new_encoded_size_estimation = + new_encoded_size_estimation.saturating_sub(old.encoded_size()); + } + }); + + transaction.recorded_keys.into_iter().for_each(|(storage_root, keys)| { + keys.into_iter().for_each(|(k, old_state)| { + if let Some(state) = old_state { + inner.recorded_keys.entry(storage_root).or_default().insert(k, state); + } else { + inner.recorded_keys.entry(storage_root).or_default().remove(&k); + } + }); + }); + + self.encoded_size_estimation + .store(new_encoded_size_estimation, Ordering::Relaxed); + + Ok(()) + } + + /// Commit the latest transaction. + /// + /// Returns an error if there wasn't any active transaction. + pub fn commit_transaction(&self) -> Result<(), ()> { + let mut inner = self.inner.lock(); + + let transaction = inner.transactions.pop().ok_or(())?; + + if let Some(parent_transaction) = inner.transactions.last_mut() { + parent_transaction.accessed_nodes.extend(transaction.accessed_nodes); + + transaction.recorded_keys.into_iter().for_each(|(storage_root, keys)| { + keys.into_iter().for_each(|(k, old_state)| { + parent_transaction + .recorded_keys + .entry(storage_root) + .or_default() + .entry(k) + .or_insert(old_state); + }) + }); + } + + Ok(()) + } } /// The [`TrieRecorder`](trie_db::TrieRecorder) implementation. @@ -145,6 +239,50 @@ struct TrieRecorder { _phantom: PhantomData, } +impl>> TrieRecorder { + /// Update the recorded keys entry for the given `full_key`. + fn update_recorded_keys(&mut self, full_key: &[u8], access: RecordedForKey) { + let inner = self.inner.deref_mut(); + + let entry = + inner.recorded_keys.entry(self.storage_root).or_default().entry(full_key.into()); + + let key = entry.key().clone(); + + // We don't need to update the record if we only accessed the `Hash` for the given + // `full_key`. Only `Value` access can be an upgrade from `Hash`. + let entry = if matches!(access, RecordedForKey::Value) { + entry.and_modify(|e| { + if let Some(tx) = inner.transactions.last_mut() { + // Store the previous state only once per transaction. + tx.recorded_keys + .entry(self.storage_root) + .or_default() + .entry(key.clone()) + .or_insert(Some(*e)); + } + + *e = access; + }) + } else { + entry + }; + + entry.or_insert_with(|| { + if let Some(tx) = inner.transactions.last_mut() { + // The key wasn't yet recorded, so there isn't any old state. + tx.recorded_keys + .entry(self.storage_root) + .or_default() + .entry(key) + .or_insert(None); + } + + access + }); + } +} + impl>> trie_db::TrieRecorder for TrieRecorder { @@ -159,11 +297,17 @@ impl>> trie_db::TrieRecord "Recording node", ); - self.inner.accessed_nodes.entry(hash).or_insert_with(|| { + let inner = self.inner.deref_mut(); + + inner.accessed_nodes.entry(hash).or_insert_with(|| { let node = node_owned.to_encoded::>(); encoded_size_update += node.encoded_size(); + if let Some(tx) = inner.transactions.last_mut() { + tx.accessed_nodes.insert(hash); + } + node }); }, @@ -174,11 +318,17 @@ impl>> trie_db::TrieRecord "Recording node", ); - self.inner.accessed_nodes.entry(hash).or_insert_with(|| { + let inner = self.inner.deref_mut(); + + inner.accessed_nodes.entry(hash).or_insert_with(|| { let node = encoded_node.into_owned(); encoded_size_update += node.encoded_size(); + if let Some(tx) = inner.transactions.last_mut() { + tx.accessed_nodes.insert(hash); + } + node }); }, @@ -190,21 +340,21 @@ impl>> trie_db::TrieRecord "Recording value", ); - self.inner.accessed_nodes.entry(hash).or_insert_with(|| { + let inner = self.inner.deref_mut(); + + inner.accessed_nodes.entry(hash).or_insert_with(|| { let value = value.into_owned(); encoded_size_update += value.encoded_size(); + if let Some(tx) = inner.transactions.last_mut() { + tx.accessed_nodes.insert(hash); + } + value }); - 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); + self.update_recorded_keys(full_key, RecordedForKey::Value); }, TrieAccess::Hash { full_key } => { tracing::trace!( @@ -215,12 +365,7 @@ impl>> trie_db::TrieRecord // 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(self.storage_root) - .or_default() - .entry(full_key.to_vec()) - .or_insert(RecordedForKey::Hash); + self.update_recorded_keys(full_key, RecordedForKey::Hash); }, TrieAccess::NonExisting { full_key } => { tracing::trace!( @@ -232,13 +377,7 @@ impl>> trie_db::TrieRecord // 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(self.storage_root) - .or_default() - .entry(full_key.to_vec()) - .and_modify(|e| *e = RecordedForKey::Value) - .or_insert(RecordedForKey::Value); + self.update_recorded_keys(full_key, RecordedForKey::Value); }, }; @@ -256,14 +395,15 @@ impl>> trie_db::TrieRecord #[cfg(test)] mod tests { - use trie_db::{Trie, TrieDBBuilder, TrieDBMutBuilder, TrieHash, TrieMut}; + use super::*; + use trie_db::{Trie, TrieDBBuilder, TrieDBMutBuilder, TrieHash, TrieMut, TrieRecorder}; 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")]; + &[(b"key1", &[1; 64]), (b"key2", &[2; 64]), (b"key3", &[3; 64]), (b"key4", &[4; 64])]; fn create_trie() -> (MemoryDB, TrieHash) { let mut db = MemoryDB::default(); @@ -300,4 +440,271 @@ mod tests { let trie = TrieDBBuilder::::new(&memory_db, &root).build(); assert_eq!(TEST_DATA[0].1.to_vec(), trie.get(TEST_DATA[0].0).unwrap().unwrap()); } + + #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] + struct RecorderStats { + accessed_nodes: usize, + recorded_keys: usize, + estimated_size: usize, + } + + impl RecorderStats { + fn extract(recorder: &Recorder) -> Self { + let inner = recorder.inner.lock(); + + let recorded_keys = + inner.recorded_keys.iter().flat_map(|(_, keys)| keys.keys()).count(); + + Self { + recorded_keys, + accessed_nodes: inner.accessed_nodes.len(), + estimated_size: recorder.estimate_encoded_size(), + } + } + } + + #[test] + fn recorder_transactions_rollback_work() { + let (db, root) = create_trie(); + + let recorder = Recorder::default(); + let mut stats = vec![RecorderStats::default()]; + + for i in 0..4 { + recorder.start_transaction(); + { + let mut trie_recorder = recorder.as_trie_recorder(root); + let trie = TrieDBBuilder::::new(&db, &root) + .with_recorder(&mut trie_recorder) + .build(); + + assert_eq!(TEST_DATA[i].1.to_vec(), trie.get(TEST_DATA[i].0).unwrap().unwrap()); + } + stats.push(RecorderStats::extract(&recorder)); + } + + assert_eq!(4, recorder.inner.lock().transactions.len()); + + for i in 0..5 { + assert_eq!(stats[4 - i], RecorderStats::extract(&recorder)); + + let storage_proof = recorder.to_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(); + + // Check that the required data is still present. + for a in 0..4 { + if a < 4 - i { + assert_eq!(TEST_DATA[a].1.to_vec(), trie.get(TEST_DATA[a].0).unwrap().unwrap()); + } else { + // All the data that we already rolled back, should be gone! + assert!(trie.get(TEST_DATA[a].0).is_err()); + } + } + + if i < 4 { + recorder.rollback_transaction().unwrap(); + } + } + + assert_eq!(0, recorder.inner.lock().transactions.len()); + } + + #[test] + fn recorder_transactions_commit_work() { + let (db, root) = create_trie(); + + let recorder = Recorder::default(); + + for i in 0..4 { + recorder.start_transaction(); + { + let mut trie_recorder = recorder.as_trie_recorder(root); + let trie = TrieDBBuilder::::new(&db, &root) + .with_recorder(&mut trie_recorder) + .build(); + + assert_eq!(TEST_DATA[i].1.to_vec(), trie.get(TEST_DATA[i].0).unwrap().unwrap()); + } + } + + let stats = RecorderStats::extract(&recorder); + assert_eq!(4, recorder.inner.lock().transactions.len()); + + for _ in 0..4 { + recorder.commit_transaction().unwrap(); + } + assert_eq!(0, recorder.inner.lock().transactions.len()); + assert_eq!(stats, RecorderStats::extract(&recorder)); + + let storage_proof = recorder.to_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(); + + // Check that the required data is still present. + for i in 0..4 { + assert_eq!(TEST_DATA[i].1.to_vec(), trie.get(TEST_DATA[i].0).unwrap().unwrap()); + } + } + + #[test] + fn recorder_transactions_commit_and_rollback_work() { + let (db, root) = create_trie(); + + let recorder = Recorder::default(); + + for i in 0..2 { + recorder.start_transaction(); + { + let mut trie_recorder = recorder.as_trie_recorder(root); + let trie = TrieDBBuilder::::new(&db, &root) + .with_recorder(&mut trie_recorder) + .build(); + + assert_eq!(TEST_DATA[i].1.to_vec(), trie.get(TEST_DATA[i].0).unwrap().unwrap()); + } + } + + recorder.rollback_transaction().unwrap(); + + for i in 2..4 { + recorder.start_transaction(); + { + let mut trie_recorder = recorder.as_trie_recorder(root); + let trie = TrieDBBuilder::::new(&db, &root) + .with_recorder(&mut trie_recorder) + .build(); + + assert_eq!(TEST_DATA[i].1.to_vec(), trie.get(TEST_DATA[i].0).unwrap().unwrap()); + } + } + + recorder.rollback_transaction().unwrap(); + + assert_eq!(2, recorder.inner.lock().transactions.len()); + + for _ in 0..2 { + recorder.commit_transaction().unwrap(); + } + + assert_eq!(0, recorder.inner.lock().transactions.len()); + + let storage_proof = recorder.to_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(); + + // Check that the required data is still present. + for i in 0..4 { + if i % 2 == 0 { + assert_eq!(TEST_DATA[i].1.to_vec(), trie.get(TEST_DATA[i].0).unwrap().unwrap()); + } else { + assert!(trie.get(TEST_DATA[i].0).is_err()); + } + } + } + + #[test] + fn recorder_transaction_accessed_keys_works() { + let key = TEST_DATA[0].0; + let (db, root) = create_trie(); + + let recorder = Recorder::default(); + + { + let trie_recorder = recorder.as_trie_recorder(root); + assert!(matches!(trie_recorder.trie_nodes_recorded_for_key(key), RecordedForKey::None)); + } + + recorder.start_transaction(); + { + let mut trie_recorder = recorder.as_trie_recorder(root); + let trie = TrieDBBuilder::::new(&db, &root) + .with_recorder(&mut trie_recorder) + .build(); + + assert_eq!( + sp_core::Blake2Hasher::hash(TEST_DATA[0].1), + trie.get_hash(TEST_DATA[0].0).unwrap().unwrap() + ); + assert!(matches!(trie_recorder.trie_nodes_recorded_for_key(key), RecordedForKey::Hash)); + } + + recorder.start_transaction(); + { + let mut trie_recorder = recorder.as_trie_recorder(root); + 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()); + assert!(matches!( + trie_recorder.trie_nodes_recorded_for_key(key), + RecordedForKey::Value, + )); + } + + recorder.rollback_transaction().unwrap(); + { + let trie_recorder = recorder.as_trie_recorder(root); + assert!(matches!(trie_recorder.trie_nodes_recorded_for_key(key), RecordedForKey::Hash)); + } + + recorder.rollback_transaction().unwrap(); + { + let trie_recorder = recorder.as_trie_recorder(root); + assert!(matches!(trie_recorder.trie_nodes_recorded_for_key(key), RecordedForKey::None)); + } + + recorder.start_transaction(); + { + let mut trie_recorder = recorder.as_trie_recorder(root); + 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()); + assert!(matches!( + trie_recorder.trie_nodes_recorded_for_key(key), + RecordedForKey::Value, + )); + } + + recorder.start_transaction(); + { + let mut trie_recorder = recorder.as_trie_recorder(root); + let trie = TrieDBBuilder::::new(&db, &root) + .with_recorder(&mut trie_recorder) + .build(); + + assert_eq!( + sp_core::Blake2Hasher::hash(TEST_DATA[0].1), + trie.get_hash(TEST_DATA[0].0).unwrap().unwrap() + ); + assert!(matches!( + trie_recorder.trie_nodes_recorded_for_key(key), + RecordedForKey::Value + )); + } + + recorder.rollback_transaction().unwrap(); + { + let trie_recorder = recorder.as_trie_recorder(root); + assert!(matches!( + trie_recorder.trie_nodes_recorded_for_key(key), + RecordedForKey::Value + )); + } + + recorder.rollback_transaction().unwrap(); + { + let trie_recorder = recorder.as_trie_recorder(root); + assert!(matches!(trie_recorder.trie_nodes_recorded_for_key(key), RecordedForKey::None)); + } + } } diff --git a/test-utils/runtime/src/lib.rs b/test-utils/runtime/src/lib.rs index c9a0ac04d63ba..b5600843c2749 100644 --- a/test-utils/runtime/src/lib.rs +++ b/test-utils/runtime/src/lib.rs @@ -164,13 +164,21 @@ pub enum Extrinsic { OffchainIndexSet(Vec, Vec), OffchainIndexClear(Vec), Store(Vec), + /// Read X times from the state some data and then panic! + /// + /// Returns `Ok` if it didn't read anything. + ReadAndPanic(u32), + /// Read X times from the state some data. + /// + /// Panics if it can not read `X` times. + Read(u32), } #[cfg(feature = "std")] impl serde::Serialize for Extrinsic { fn serialize(&self, seq: S) -> Result where - S: ::serde::Serializer, + S: serde::Serializer, { self.using_encoded(|bytes| seq.serialize_bytes(bytes)) } @@ -210,6 +218,8 @@ impl BlindCheckable for Extrinsic { Extrinsic::OffchainIndexSet(key, value) => Ok(Extrinsic::OffchainIndexSet(key, value)), Extrinsic::OffchainIndexClear(key) => Ok(Extrinsic::OffchainIndexClear(key)), Extrinsic::Store(data) => Ok(Extrinsic::Store(data)), + Extrinsic::ReadAndPanic(i) => Ok(Extrinsic::ReadAndPanic(i)), + Extrinsic::Read(i) => Ok(Extrinsic::Read(i)), } } } diff --git a/test-utils/runtime/src/system.rs b/test-utils/runtime/src/system.rs index 12ebf486bb1b9..fc750531529b6 100644 --- a/test-utils/runtime/src/system.rs +++ b/test-utils/runtime/src/system.rs @@ -275,6 +275,32 @@ fn execute_transaction_backend(utx: &Extrinsic, extrinsic_index: u32) -> ApplyEx Ok(Ok(())) }, Extrinsic::Store(data) => execute_store(data.clone()), + Extrinsic::ReadAndPanic(i) => execute_read(*i, true), + Extrinsic::Read(i) => execute_read(*i, false), + } +} + +fn execute_read(read: u32, panic_at_end: bool) -> ApplyExtrinsicResult { + let mut next_key = vec![]; + for _ in 0..(read as usize) { + if let Some(next) = sp_io::storage::next_key(&next_key) { + // Read the value + sp_io::storage::get(&next); + + next_key = next; + } else { + if panic_at_end { + return Ok(Ok(())) + } else { + panic!("Could not read {read} times from the state"); + } + } + } + + if panic_at_end { + panic!("BYE") + } else { + Ok(Ok(())) } } From 2bb370fbc36b2631dd85e6f1c1952cdfe7b8db8c Mon Sep 17 00:00:00 2001 From: Liam Aharon Date: Thu, 6 Apr 2023 15:28:21 +1000 Subject: [PATCH 618/715] remove duplicate sync option documentation (#13828) --- client/cli/src/params/network_params.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/client/cli/src/params/network_params.rs b/client/cli/src/params/network_params.rs index 106fba75aa727..acec4b2ac872a 100644 --- a/client/cli/src/params/network_params.rs +++ b/client/cli/src/params/network_params.rs @@ -132,11 +132,6 @@ pub struct NetworkParams { pub ipfs_server: bool, /// Blockchain syncing mode. - /// - /// - `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. #[arg( long, value_enum, From c0793b58c509f352b6006e402350ac9ad8017823 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Thu, 6 Apr 2023 14:24:45 +0800 Subject: [PATCH 619/715] Add HoldReason to the NIS pallet (#13823) * Add HoldReason to the NIS pallet * Rename composable_enum to composite_enum * Add encoding test * Add more doc comments --- frame/nis/src/lib.rs | 8 ++++++++ .../src/construct_runtime/expand/freeze_reason.rs | 1 + .../src/construct_runtime/expand/hold_reason.rs | 1 + .../src/construct_runtime/expand/lock_id.rs | 1 + .../src/construct_runtime/expand/slash_reason.rs | 1 + frame/support/procedural/src/lib.rs | 6 +++--- frame/support/src/lib.rs | 12 ++++++------ frame/support/test/tests/pallet.rs | 6 ++++++ 8 files changed, 27 insertions(+), 9 deletions(-) diff --git a/frame/nis/src/lib.rs b/frame/nis/src/lib.rs index 539011c5149d0..9cac5f4b616e7 100644 --- a/frame/nis/src/lib.rs +++ b/frame/nis/src/lib.rs @@ -482,6 +482,14 @@ pub mod pallet { AlreadyPrivate, } + /// A reason for the NIS pallet placing a hold on funds. + #[pallet::composite_enum] + pub enum HoldReason { + /// The NIS Pallet has reserved it for a non-fungible receipt. + #[codec(index = 0)] + NftReceipt, + } + pub(crate) struct WeightCounter { pub(crate) used: Weight, pub(crate) limit: Weight, diff --git a/frame/support/procedural/src/construct_runtime/expand/freeze_reason.rs b/frame/support/procedural/src/construct_runtime/expand/freeze_reason.rs index 889168bf6c215..d357fab72115b 100644 --- a/frame/support/procedural/src/construct_runtime/expand/freeze_reason.rs +++ b/frame/support/procedural/src/construct_runtime/expand/freeze_reason.rs @@ -35,6 +35,7 @@ pub fn expand_outer_freeze_reason(pallet_decls: &[Pallet], scrate: &TokenStream) } quote! { + /// A reason for placing a freeze on funds. #[derive( Copy, Clone, Eq, PartialEq, Ord, PartialOrd, #scrate::codec::Encode, #scrate::codec::Decode, #scrate::codec::MaxEncodedLen, diff --git a/frame/support/procedural/src/construct_runtime/expand/hold_reason.rs b/frame/support/procedural/src/construct_runtime/expand/hold_reason.rs index 60fc094a4d5e4..6acfe5382f18a 100644 --- a/frame/support/procedural/src/construct_runtime/expand/hold_reason.rs +++ b/frame/support/procedural/src/construct_runtime/expand/hold_reason.rs @@ -35,6 +35,7 @@ pub fn expand_outer_hold_reason(pallet_decls: &[Pallet], scrate: &TokenStream) - } quote! { + /// A reason for placing a hold on funds. #[derive( Copy, Clone, Eq, PartialEq, Ord, PartialOrd, #scrate::codec::Encode, #scrate::codec::Decode, #scrate::codec::MaxEncodedLen, diff --git a/frame/support/procedural/src/construct_runtime/expand/lock_id.rs b/frame/support/procedural/src/construct_runtime/expand/lock_id.rs index 77c6fefa0aabd..d7031dcaf552b 100644 --- a/frame/support/procedural/src/construct_runtime/expand/lock_id.rs +++ b/frame/support/procedural/src/construct_runtime/expand/lock_id.rs @@ -35,6 +35,7 @@ pub fn expand_outer_lock_id(pallet_decls: &[Pallet], scrate: &TokenStream) -> To } quote! { + /// An identifier for each lock placed on funds. #[derive( Copy, Clone, Eq, PartialEq, Ord, PartialOrd, #scrate::codec::Encode, #scrate::codec::Decode, #scrate::codec::MaxEncodedLen, diff --git a/frame/support/procedural/src/construct_runtime/expand/slash_reason.rs b/frame/support/procedural/src/construct_runtime/expand/slash_reason.rs index 2bf647aa7c1f4..abffb97d43981 100644 --- a/frame/support/procedural/src/construct_runtime/expand/slash_reason.rs +++ b/frame/support/procedural/src/construct_runtime/expand/slash_reason.rs @@ -35,6 +35,7 @@ pub fn expand_outer_slash_reason(pallet_decls: &[Pallet], scrate: &TokenStream) } quote! { + /// A reason for slashing funds. #[derive( Copy, Clone, Eq, PartialEq, Ord, PartialOrd, #scrate::codec::Encode, #scrate::codec::Decode, #scrate::codec::MaxEncodedLen, diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index dea2d4943de00..ea997752c3a53 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -1412,7 +1412,7 @@ pub fn origin(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } -/// The `#[pallet::composable_enum]` attribute allows you to define an enum that gets composed as an +/// The `#[pallet::composite_enum]` attribute allows you to define an enum that gets composed as an /// aggregate enum by `construct_runtime`. This is similar in principle with `#[pallet::event]` and /// `#[pallet::error]`. /// @@ -1431,10 +1431,10 @@ pub fn origin(_: TokenStream, _: TokenStream) -> TokenStream { /// ``` /// /// For ease of usage, when no `#[derive]` attributes are found for the enum under -/// `#[pallet::composable_enum]`, the aforementioned traits are automatically derived for it. The +/// `#[pallet::composite_enum]`, the aforementioned traits are automatically derived for it. The /// inverse is also true: if there are any `#[derive]` attributes found for the enum, then no traits /// will automatically be derived for it. #[proc_macro_attribute] -pub fn composable_enum(_: TokenStream, _: TokenStream) -> TokenStream { +pub fn composite_enum(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index e0ebeb68a3eaf..916a8696ed678 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -1552,7 +1552,7 @@ pub mod pallet_prelude { /// * [`pallet::inherent`](#inherent-palletinherent-optional) /// * [`pallet::validate_unsigned`](#validate-unsigned-palletvalidate_unsigned-optional) /// * [`pallet::origin`](#origin-palletorigin-optional) -/// * [`pallet::composable_enum`](#composable-enum-palletcomposable_enum-optional) +/// * [`pallet::composite_enum`](#composite-enum-palletcomposite_enum-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 @@ -2278,19 +2278,19 @@ pub mod pallet_prelude { /// /// Also see [`pallet::origin`](`frame_support::pallet_macros::origin`) /// -/// # Composable enum `#[pallet::composable_enum]` (optional) +/// # Composite enum `#[pallet::composite_enum]` (optional) /// -/// The `#[pallet::composable_enum]` attribute allows you to define an enum on the pallet which +/// The `#[pallet::composite_enum]` attribute allows you to define an enum on the pallet which /// will then instruct `construct_runtime` to amalgamate all similarly-named enums from other /// pallets into an aggregate enum. This is similar in principle with how the aggregate enum is /// generated for `#[pallet::event]` or `#[pallet::error]`. /// -/// The item tagged with `#[pallet::composable_enum]` MUST be an enum declaration, and can ONLY +/// The item tagged with `#[pallet::composite_enum]` MUST be an enum declaration, and can ONLY /// be the following identifiers: `FreezeReason`, `HoldReason`, `LockId` or `SlashReason`. /// Custom identifiers are not supported. /// /// NOTE: For ease of usage, when no `#[derive]` attributes are detected, the -/// `#[pallet::composable_enum]` attribute will automatically derive the following traits for +/// `#[pallet::composite_enum]` attribute will automatically derive the following traits for /// the enum: /// /// ```ignore @@ -2832,7 +2832,7 @@ 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, composable_enum, config, constant, + call_index, compact, composite_enum, 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, diff --git a/frame/support/test/tests/pallet.rs b/frame/support/test/tests/pallet.rs index 37f1219a800f5..11f82c4c0d266 100644 --- a/frame/support/test/tests/pallet.rs +++ b/frame/support/test/tests/pallet.rs @@ -991,6 +991,8 @@ fn validate_unsigned_expand() { #[test] fn composite_expand() { + use codec::Encode; + let hold_reason: RuntimeHoldReason = pallet::HoldReason::Staking.into(); let hold_reason2: RuntimeHoldReason = pallet2::HoldReason::Governance.into(); let slash_reason: RuntimeSlashReason = pallet2::SlashReason::Equivocation.into(); @@ -998,6 +1000,10 @@ fn composite_expand() { assert_eq!(hold_reason, RuntimeHoldReason::Example(pallet::HoldReason::Staking)); assert_eq!(hold_reason2, RuntimeHoldReason::Example2(pallet2::HoldReason::Governance)); assert_eq!(slash_reason, RuntimeSlashReason::Example2(pallet2::SlashReason::Equivocation)); + + assert_eq!(hold_reason.encode(), [1, 0]); + assert_eq!(hold_reason2.encode(), [2, 0]); + assert_eq!(slash_reason.encode(), [2, 0]); } #[test] From a1d3d5004379976b13deab86b975c04ad78bcd72 Mon Sep 17 00:00:00 2001 From: Liam Aharon Date: Thu, 6 Apr 2023 19:49:53 +1000 Subject: [PATCH 620/715] Fix `try-runtime follow-chain`, try-runtime upgrade tuple tests, cli test utils (#13794) * new test for try-runtime tuple stuff * fix * remove development comment * formatting * remove todo comment * follow-chain working test * refactor common cli testing utils * fix comment * revert Cargo.lock changes * update Cargo.lock * improve doc comment * fix error typo * update Cargo.lock * feature gate try-runtime test * build_substrate cli test util * feature gate follow_chain tests * move fn start_node to test-utils * improve test pkg name * use tokio Child and Command * remove redundant import * fix ci * fix ci * don't leave hanging processes * improved child process cleanup * use existing KillChildOnDrop * remove redundant comment * Update test-utils/cli/src/lib.rs Co-authored-by: Koute --------- Co-authored-by: kianenigma Co-authored-by: Koute --- Cargo.lock | 317 +++++++++++------- bin/node/cli/Cargo.toml | 1 + bin/node/cli/tests/benchmark_block_works.rs | 2 +- bin/node/cli/tests/benchmark_pallet_works.rs | 2 - 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 +- .../cli/tests/remember_state_pruning_works.rs | 2 +- .../tests/running_the_node_and_interrupt.rs | 17 +- bin/node/cli/tests/telemetry.rs | 2 +- bin/node/cli/tests/temp_base_path_works.rs | 2 +- frame/support/src/lib.rs | 6 +- frame/support/src/traits/hooks.rs | 58 +++- test-utils/cli/Cargo.toml | 23 ++ .../common.rs => test-utils/cli/src/lib.rs | 134 ++++++++ utils/frame/try-runtime/cli/Cargo.toml | 10 +- .../cli/src/commands/follow_chain.rs | 12 +- .../try-runtime/cli/tests/follow_chain.rs | 65 ++++ 19 files changed, 508 insertions(+), 153 deletions(-) create mode 100644 test-utils/cli/Cargo.toml rename bin/node/cli/tests/common.rs => test-utils/cli/src/lib.rs (52%) create mode 100644 utils/frame/try-runtime/cli/tests/follow_chain.rs diff --git a/Cargo.lock b/Cargo.lock index ed633fcaa8978..d4185103f8c96 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -203,6 +203,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "anstyle" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23ea9e81bd02e310c216d080f6223c179012256e5151c41db88d12c88a1684d2" + [[package]] name = "anyhow" version = "1.0.69" @@ -294,7 +300,7 @@ checksum = "db8b7511298d5b7784b40b092d9e9dcd3a627a5707e4b5e507931ab0d44eeebf" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", "synstructure", ] @@ -306,7 +312,7 @@ checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", "synstructure", ] @@ -318,7 +324,7 @@ checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -329,13 +335,14 @@ checksum = "e22d1f4b888c298a027c99dc9048015fac177587de20fc30232a057dfbe24a21" [[package]] name = "assert_cmd" -version = "2.0.8" +version = "2.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9834fcc22e0874394a010230586367d4a3e9f11b560f469262678547e1d2575e" +checksum = "ec0b2340f55d9661d76793b2bfc2eb0e62689bd79d067a95707ea762afd5e9dd" dependencies = [ + "anstyle", "bstr", "doc-comment", - "predicates", + "predicates 3.0.2", "predicates-core", "predicates-tree", "wait-timeout", @@ -407,7 +414,7 @@ checksum = "e4655ae1a7b0cdf149156f780c5bf3f1352bc53cbd9e0a361a7ef7b22947e965" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -418,7 +425,7 @@ checksum = "1cd7fce9ba8c3c042128ce72d8b2ddbf3a05747efb67ea0313c635e10bda47a2" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -564,7 +571,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn", + "syn 1.0.109", ] [[package]] @@ -1046,7 +1053,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -1424,7 +1431,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096" dependencies = [ "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -1509,7 +1516,7 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn", + "syn 1.0.109", ] [[package]] @@ -1526,7 +1533,7 @@ checksum = "086c685979a698443656e5cf7856c95c642295a38599f12fb1ff76fb28d19892" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -1550,7 +1557,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn", + "syn 1.0.109", ] [[package]] @@ -1561,7 +1568,7 @@ checksum = "b36230598a2d5de7ec1c6f51f72d8a99a9208daff41de2084d06e3fd3ea56685" dependencies = [ "darling_core", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -1587,7 +1594,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a5bbed42daaa95e780b60a50546aa345b8413a1e46f9a40a12907d3598f038db" dependencies = [ "data-encoding", - "syn", + "syn 1.0.109", ] [[package]] @@ -1647,7 +1654,7 @@ checksum = "e79116f119dd1dba1abf1f3405f03b9b0e79a27a3883864bfebded8a3dc768cd" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -1668,7 +1675,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -1678,7 +1685,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f0314b72bed045f3a68671b3c86328386762c93f82d98c65c3cb5e5f573dd68" dependencies = [ "derive_builder_core", - "syn", + "syn 1.0.109", ] [[package]] @@ -1689,7 +1696,7 @@ checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -1782,7 +1789,7 @@ checksum = "3bf95dc3f046b9da4f2d51833c0d3547d8564ef6910f5c1ed130306a75b92886" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -1833,7 +1840,7 @@ checksum = "558e40ea573c374cf53507fd240b7ee2f5477df7cfebdb97323ec61c719399c5" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -1959,7 +1966,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -1979,7 +1986,7 @@ checksum = "f58dc3c5e468259f19f2d46304a6b28f1c3d034442e14b322d2b850e36f6d5ae" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -2025,6 +2032,17 @@ dependencies = [ "winapi", ] +[[package]] +name = "errno" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d6a0976c999d473fe89ad888d5a284e55366d9dc9038b1ba2aa15128c4afa0" +dependencies = [ + "errno-dragonfly", + "libc", + "windows-sys 0.45.0", +] + [[package]] name = "errno-dragonfly" version = "0.1.2" @@ -2060,7 +2078,7 @@ dependencies = [ "fs-err", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -2137,7 +2155,7 @@ checksum = "8a3de6e8d11b22ff9edc6d916f890800597d60f8b2da1caf2955c274638d6412" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.2.16", "windows-sys 0.45.0", ] @@ -2333,7 +2351,7 @@ dependencies = [ "quote", "scale-info", "sp-arithmetic", - "syn", + "syn 1.0.109", "trybuild", ] @@ -2471,7 +2489,7 @@ dependencies = [ "proc-macro-warning", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -2482,7 +2500,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -2491,7 +2509,7 @@ version = "3.0.0" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -2635,9 +2653,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.26" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13e2792b0ff0340399d58445b88fd9770e3489eff258a4cbc1523418f12abf84" +checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" dependencies = [ "futures-channel", "futures-core", @@ -2650,9 +2668,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.26" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e5317663a9089767a1ec00a487df42e0ca174b61b4483213ac24448e4664df5" +checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" dependencies = [ "futures-core", "futures-sink", @@ -2660,15 +2678,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.26" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec90ff4d0fe1f57d600049061dc6bb68ed03c7d2fbd697274c41805dcb3f8608" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" [[package]] name = "futures-executor" -version = "0.3.26" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8de0a35a6ab97ec8869e32a2473f4b1324459e14c29275d14b10cb1fd19b50e" +checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" dependencies = [ "futures-core", "futures-task", @@ -2678,9 +2696,9 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.26" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfb8371b6fb2aeb2d280374607aeabfc99d95c72edfe51692e42d3d7f0d08531" +checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" [[package]] name = "futures-lite" @@ -2699,13 +2717,13 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.26" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95a73af87da33b5acf53acfebdc339fe592ecf5357ac7c0a7734ab9d8c876a70" +checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.13", ] [[package]] @@ -2721,15 +2739,15 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.26" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f310820bb3e8cfd46c80db4d7fb8353e15dfff853a127158425f31e0be6c8364" +checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" [[package]] name = "futures-task" -version = "0.3.26" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf79a1bf610b10f42aea489289c5a2c478a786509693b80cd39c44ccd936366" +checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" [[package]] name = "futures-timer" @@ -2739,9 +2757,9 @@ checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" [[package]] name = "futures-util" -version = "0.3.26" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c1d6de3acfef38d2be4b1f543f553131788603495be83da675e180c8d6b7bd1" +checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" dependencies = [ "futures-channel", "futures-core", @@ -3291,7 +3309,7 @@ checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -3515,7 +3533,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -4140,7 +4158,7 @@ checksum = "9d527d5827582abd44a6d80c07ff8b50b4ee238a8979e05998474179e79dc400" dependencies = [ "heck", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -4375,6 +4393,12 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" +[[package]] +name = "linux-raw-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f" + [[package]] name = "lite-json" version = "0.2.0" @@ -4662,7 +4686,7 @@ dependencies = [ "fragile", "lazy_static", "mockall_derive", - "predicates", + "predicates 2.1.5", "predicates-tree", ] @@ -4675,7 +4699,7 @@ dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -4765,7 +4789,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn", + "syn 1.0.109", "synstructure", ] @@ -4813,7 +4837,7 @@ checksum = "d232c68884c0c99810a5a4d333ef7e47689cfd0edc85efc9e54e1e6bf5212766" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -5030,6 +5054,7 @@ dependencies = [ "sp-transaction-pool", "sp-transaction-storage-proof", "substrate-build-script-utils", + "substrate-cli-test-utils", "substrate-frame-cli", "substrate-rpc-client", "tempfile", @@ -5886,7 +5911,7 @@ version = "4.0.0-dev" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -6769,7 +6794,7 @@ dependencies = [ "proc-macro2", "quote", "sp-runtime", - "syn", + "syn 1.0.109", ] [[package]] @@ -7077,7 +7102,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -7128,7 +7153,7 @@ dependencies = [ "cfg-if", "instant", "libc", - "redox_syscall", + "redox_syscall 0.2.16", "smallvec", "winapi", ] @@ -7141,7 +7166,7 @@ checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.2.16", "smallvec", "windows-sys 0.45.0", ] @@ -7230,7 +7255,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -7271,7 +7296,7 @@ checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -7427,11 +7452,23 @@ dependencies = [ "regex", ] +[[package]] +name = "predicates" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c575290b64d24745b6c57a12a31465f0a66f3a4799686a6921526a33b0797965" +dependencies = [ + "anstyle", + "difflib", + "itertools", + "predicates-core", +] + [[package]] name = "predicates-core" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72f883590242d3c6fc5bf50299011695fa6590c2c70eac95ee1bdb9a733ad1a2" +checksum = "b794032607612e7abeb4db69adb4e33590fa6cf1149e95fd7cb00e634b92f174" [[package]] name = "predicates-tree" @@ -7462,7 +7499,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e97e3215779627f01ee256d2fad52f3d95e8e1c11e9fc6fd08f7cd455d5d5c78" dependencies = [ "proc-macro2", - "syn", + "syn 1.0.109", ] [[package]] @@ -7497,7 +7534,7 @@ dependencies = [ "proc-macro-error-attr", "proc-macro2", "quote", - "syn", + "syn 1.0.109", "version_check", ] @@ -7520,14 +7557,14 @@ checksum = "9d4f284d87b9cedc2ff57223cbc4e3937cd6063c01e92c8e2a8c080df0013933" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] name = "proc-macro2" -version = "1.0.51" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" +checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" dependencies = [ "unicode-ident", ] @@ -7566,7 +7603,7 @@ checksum = "66a455fbcb954c1a7decf3c586e860fd7889cddf4b8e164be736dbac95a953cd" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -7596,7 +7633,7 @@ dependencies = [ "prost", "prost-types", "regex", - "syn", + "syn 1.0.109", "tempfile", "which", ] @@ -7624,7 +7661,7 @@ dependencies = [ "itertools", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -7691,9 +7728,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.23" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" dependencies = [ "proc-macro2", ] @@ -7856,6 +7893,15 @@ dependencies = [ "bitflags", ] +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags", +] + [[package]] name = "redox_users" version = "0.4.3" @@ -7863,7 +7909,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ "getrandom 0.2.8", - "redox_syscall", + "redox_syscall 0.2.16", "thiserror", ] @@ -7884,7 +7930,7 @@ checksum = "9f9c0c92af03644e4806106281fe2e068ac5bc0ae74a707266d06ea27bccee5f" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -7901,9 +7947,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.7.1" +version = "1.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" +checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d" dependencies = [ "aho-corasick", "memchr", @@ -7921,9 +7967,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.28" +version = "0.6.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "region" @@ -8106,7 +8152,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "727a1a6d65f786ec22df8a81ca3121107f235970dc1705ed681d3e6e8b9cd5f9" dependencies = [ "bitflags", - "errno", + "errno 0.2.8", "io-lifetimes 0.7.5", "libc", "linux-raw-sys 0.0.46", @@ -8120,13 +8166,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f43abb88211988493c1abb44a70efa56ff0ce98f233b7b276146f1f3f7ba9644" dependencies = [ "bitflags", - "errno", + "errno 0.2.8", "io-lifetimes 1.0.5", "libc", "linux-raw-sys 0.1.4", "windows-sys 0.45.0", ] +[[package]] +name = "rustix" +version = "0.37.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2aae838e49b3d63e9274e1c01833cc8139d3fec468c3b84688c628f44b1ae11d" +dependencies = [ + "bitflags", + "errno 0.3.0", + "io-lifetimes 1.0.5", + "libc", + "linux-raw-sys 0.3.1", + "windows-sys 0.45.0", +] + [[package]] name = "rustls" version = "0.19.1" @@ -8340,7 +8400,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -9569,7 +9629,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -9658,7 +9718,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -9871,7 +9931,7 @@ checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -10064,9 +10124,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" +checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" dependencies = [ "libc", "winapi", @@ -10117,7 +10177,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -10426,7 +10486,7 @@ dependencies = [ "proc-macro2", "quote", "sp-core-hashing", - "syn", + "syn 1.0.109", ] [[package]] @@ -10443,7 +10503,7 @@ version = "5.0.0" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -10663,7 +10723,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -10887,7 +10947,7 @@ dependencies = [ "proc-macro2", "quote", "sp-version", - "syn", + "syn 1.0.109", ] [[package]] @@ -11001,7 +11061,7 @@ dependencies = [ "memchr", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -11029,7 +11089,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn", + "syn 1.0.109", ] [[package]] @@ -11079,6 +11139,20 @@ dependencies = [ "platforms 2.0.0", ] +[[package]] +name = "substrate-cli-test-utils" +version = "0.1.0" +dependencies = [ + "assert_cmd", + "futures", + "nix 0.26.2", + "node-primitives", + "regex", + "substrate-rpc-client", + "tempfile", + "tokio", +] + [[package]] name = "substrate-frame-cli" version = "4.0.0-dev" @@ -11299,7 +11373,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -11353,6 +11427,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn" +version = "2.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c9da457c5285ac1f936ebd076af6dac17a61cfe7826f2076b4d015cf47bc8ec" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "synstructure" version = "0.12.6" @@ -11361,7 +11446,7 @@ checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", "unicode-xid", ] @@ -11400,15 +11485,15 @@ checksum = "8ae9980cab1db3fceee2f6c6f643d5d8de2997c58ee8d25fb0cc8a9e9e7348e5" [[package]] name = "tempfile" -version = "3.4.0" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af18f7ae1acd354b992402e9ec5864359d693cd8a79dcbef59f76891701c1e95" +checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" dependencies = [ "cfg-if", "fastrand", - "redox_syscall", - "rustix 0.36.8", - "windows-sys 0.42.0", + "redox_syscall 0.3.5", + "rustix 0.37.7", + "windows-sys 0.45.0", ] [[package]] @@ -11449,7 +11534,7 @@ checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -11580,14 +11665,13 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.25.0" +version = "1.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e00990ebabbe4c14c08aca901caed183ecd5c09562a12c824bb53d3c3fd3af" +checksum = "d0de47a4eecbe11f498978a9b29d792f0d2692d1dd003650c24c76510e3bc001" dependencies = [ "autocfg", "bytes", "libc", - "memchr", "mio", "num_cpus", "parking_lot 0.12.1", @@ -11595,18 +11679,18 @@ dependencies = [ "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys 0.42.0", + "windows-sys 0.45.0", ] [[package]] name = "tokio-macros" -version = "1.8.2" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8" +checksum = "61a573bdc87985e9d6ddeed1b3d864e8a302c847e40d647746df2f1de209d1ce" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.13", ] [[package]] @@ -11731,7 +11815,7 @@ checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -11920,6 +12004,7 @@ checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" name = "try-runtime-cli" version = "0.10.0-dev" dependencies = [ + "assert_cmd", "async-trait", "clap 4.1.8", "frame-remote-externalities", @@ -11927,6 +12012,7 @@ dependencies = [ "hex", "log", "parity-scale-codec", + "regex", "sc-cli", "sc-executor", "sc-service", @@ -11948,6 +12034,7 @@ dependencies = [ "sp-transaction-storage-proof", "sp-version", "sp-weights", + "substrate-cli-test-utils", "substrate-rpc-client", "tokio", "zstd", @@ -12229,7 +12316,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn", + "syn 1.0.109", "wasm-bindgen-shared", ] @@ -12263,7 +12350,7 @@ checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -13205,7 +13292,7 @@ checksum = "44bf07cb3e50ea2003396695d58bf46bc9887a1f362260446fad6bc4e79bd36c" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", "synstructure", ] diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index 4451935c36035..77e49ff07d6b5 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -127,6 +127,7 @@ 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" } +substrate-cli-test-utils = { path = "../../../test-utils/cli" } [build-dependencies] clap = { version = "4.0.9", optional = true } diff --git a/bin/node/cli/tests/benchmark_block_works.rs b/bin/node/cli/tests/benchmark_block_works.rs index 369e1b3e52d87..50103a66a4d40 100644 --- a/bin/node/cli/tests/benchmark_block_works.rs +++ b/bin/node/cli/tests/benchmark_block_works.rs @@ -23,7 +23,7 @@ use assert_cmd::cargo::cargo_bin; use std::process::Command; use tempfile::tempdir; -pub mod common; +use substrate_cli_test_utils as common; /// `benchmark block` works for the dev runtime using the wasm executor. #[tokio::test] diff --git a/bin/node/cli/tests/benchmark_pallet_works.rs b/bin/node/cli/tests/benchmark_pallet_works.rs index 053516b9521d1..2d9946543eed2 100644 --- a/bin/node/cli/tests/benchmark_pallet_works.rs +++ b/bin/node/cli/tests/benchmark_pallet_works.rs @@ -21,8 +21,6 @@ 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() { diff --git a/bin/node/cli/tests/check_block_works.rs b/bin/node/cli/tests/check_block_works.rs index 019d97aa8228e..67bc5e6031ea0 100644 --- a/bin/node/cli/tests/check_block_works.rs +++ b/bin/node/cli/tests/check_block_works.rs @@ -22,7 +22,7 @@ use assert_cmd::cargo::cargo_bin; use std::process::Command; use tempfile::tempdir; -pub mod common; +use substrate_cli_test_utils as common; #[tokio::test] async fn check_block_works() { diff --git a/bin/node/cli/tests/export_import_flow.rs b/bin/node/cli/tests/export_import_flow.rs index afee9ef70c15a..b5785f99ea81f 100644 --- a/bin/node/cli/tests/export_import_flow.rs +++ b/bin/node/cli/tests/export_import_flow.rs @@ -23,7 +23,7 @@ use regex::Regex; use std::{fs, path::PathBuf, process::Command}; use tempfile::{tempdir, TempDir}; -pub mod common; +use substrate_cli_test_utils as common; fn contains_error(logged_output: &str) -> bool { logged_output.contains("Error") diff --git a/bin/node/cli/tests/inspect_works.rs b/bin/node/cli/tests/inspect_works.rs index 56569248befc0..3695c318a8df2 100644 --- a/bin/node/cli/tests/inspect_works.rs +++ b/bin/node/cli/tests/inspect_works.rs @@ -22,7 +22,7 @@ use assert_cmd::cargo::cargo_bin; use std::process::Command; use tempfile::tempdir; -pub mod common; +use substrate_cli_test_utils as common; #[tokio::test] async fn inspect_works() { diff --git a/bin/node/cli/tests/purge_chain_works.rs b/bin/node/cli/tests/purge_chain_works.rs index 470c0a7e48fba..77421f865a0d9 100644 --- a/bin/node/cli/tests/purge_chain_works.rs +++ b/bin/node/cli/tests/purge_chain_works.rs @@ -20,7 +20,7 @@ use assert_cmd::cargo::cargo_bin; use std::process::Command; use tempfile::tempdir; -pub mod common; +use substrate_cli_test_utils as common; #[tokio::test] #[cfg(unix)] diff --git a/bin/node/cli/tests/remember_state_pruning_works.rs b/bin/node/cli/tests/remember_state_pruning_works.rs index b8c5ddf4a4864..e28b2ef55ef6c 100644 --- a/bin/node/cli/tests/remember_state_pruning_works.rs +++ b/bin/node/cli/tests/remember_state_pruning_works.rs @@ -18,7 +18,7 @@ use tempfile::tempdir; -pub mod common; +use substrate_cli_test_utils as common; #[tokio::test] #[cfg(unix)] 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 3d5598f3fbe23..1308067da0256 100644 --- a/bin/node/cli/tests/running_the_node_and_interrupt.rs +++ b/bin/node/cli/tests/running_the_node_and_interrupt.rs @@ -20,12 +20,12 @@ use assert_cmd::cargo::cargo_bin; use nix::sys::signal::Signal::{self, SIGINT, SIGTERM}; use std::{ - process::{self, Child, Command}, + process::{self, Command}, time::Duration, }; use tempfile::tempdir; -pub mod common; +use substrate_cli_test_utils as common; #[tokio::test] async fn running_the_node_works_and_can_be_interrupted() { @@ -71,17 +71,8 @@ async fn running_the_node_works_and_can_be_interrupted() { #[tokio::test] async fn running_two_nodes_with_the_same_ws_port_should_work() { common::run_with_timeout(Duration::from_secs(60 * 10), async move { - 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() - } - - let mut first_node = common::KillChildOnDrop(start_node()); - let mut second_node = common::KillChildOnDrop(start_node()); + let mut first_node = common::KillChildOnDrop(common::start_node()); + let mut second_node = common::KillChildOnDrop(common::start_node()); let stderr = first_node.stderr.take().unwrap(); let ws_url = common::extract_info_from_output(stderr).0.ws_url; diff --git a/bin/node/cli/tests/telemetry.rs b/bin/node/cli/tests/telemetry.rs index a68746a2c0011..f6e46775a22fb 100644 --- a/bin/node/cli/tests/telemetry.rs +++ b/bin/node/cli/tests/telemetry.rs @@ -21,7 +21,7 @@ use std::{process, time::Duration}; use crate::common::KillChildOnDrop; -pub mod common; +use substrate_cli_test_utils as common; pub mod websocket_server; #[tokio::test] diff --git a/bin/node/cli/tests/temp_base_path_works.rs b/bin/node/cli/tests/temp_base_path_works.rs index bfc9f88220030..fdcd9e23dde5a 100644 --- a/bin/node/cli/tests/temp_base_path_works.rs +++ b/bin/node/cli/tests/temp_base_path_works.rs @@ -24,7 +24,7 @@ use std::{ time::Duration, }; -pub mod common; +use substrate_cli_test_utils as common; #[allow(dead_code)] // Apparently `#[ignore]` doesn't actually work to disable this one. diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 916a8696ed678..ac897fef0d872 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -371,16 +371,14 @@ macro_rules! parameter_types { /// Set the value of this parameter type in the storage. /// - /// This needs to be executed in an externalities provided - /// environment. + /// This needs to be executed in an externalities provided environment. pub fn set(value: &$type) { $crate::storage::unhashed::put(&Self::key(), value); } /// Returns the value of this parameter type. /// - /// This needs to be executed in an externalities provided - /// environment. + /// This needs to be executed in an externalities provided environment. #[allow(unused)] pub fn get() -> $type { $crate::storage::unhashed::get(&Self::key()).unwrap_or_else(|| $value) diff --git a/frame/support/src/traits/hooks.rs b/frame/support/src/traits/hooks.rs index 2d346ccd38a8b..5fea98ee036b5 100644 --- a/frame/support/src/traits/hooks.rs +++ b/frame/support/src/traits/hooks.rs @@ -197,10 +197,10 @@ impl OnRuntimeUpgrade for Tuple { weight } - #[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. + #[cfg(feature = "try-runtime")] fn try_on_runtime_upgrade(checks: bool) -> Result { let mut weight = Weight::zero(); for_tuples!( #( weight = weight.saturating_add(Tuple::try_on_runtime_upgrade(checks)?); )* ); @@ -364,10 +364,64 @@ pub trait OnTimestampSet { #[cfg(test)] mod tests { use super::*; + use sp_io::TestExternalities; + + #[cfg(feature = "try-runtime")] + #[test] + fn on_runtime_upgrade_pre_post_executed_tuple() { + crate::parameter_types! { + pub static Pre: Vec<&'static str> = Default::default(); + pub static Post: Vec<&'static str> = Default::default(); + } + + macro_rules! impl_test_type { + ($name:ident) => { + struct $name; + impl OnRuntimeUpgrade for $name { + fn on_runtime_upgrade() -> Weight { + Default::default() + } + + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, &'static str> { + Pre::mutate(|s| s.push(stringify!($name))); + Ok(Vec::new()) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(_: Vec) -> Result<(), &'static str> { + Post::mutate(|s| s.push(stringify!($name))); + Ok(()) + } + } + }; + } + + impl_test_type!(Foo); + impl_test_type!(Bar); + impl_test_type!(Baz); + + TestExternalities::default().execute_with(|| { + Foo::try_on_runtime_upgrade(true).unwrap(); + assert_eq!(Pre::take(), vec!["Foo"]); + assert_eq!(Post::take(), vec!["Foo"]); + + <(Foo, Bar, Baz)>::try_on_runtime_upgrade(true).unwrap(); + assert_eq!(Pre::take(), vec!["Foo", "Bar", "Baz"]); + assert_eq!(Post::take(), vec!["Foo", "Bar", "Baz"]); + + <((Foo, Bar), Baz)>::try_on_runtime_upgrade(true).unwrap(); + assert_eq!(Pre::take(), vec!["Foo", "Bar", "Baz"]); + assert_eq!(Post::take(), vec!["Foo", "Bar", "Baz"]); + + <(Foo, (Bar, Baz))>::try_on_runtime_upgrade(true).unwrap(); + assert_eq!(Pre::take(), vec!["Foo", "Bar", "Baz"]); + assert_eq!(Post::take(), vec!["Foo", "Bar", "Baz"]); + }); + } #[test] fn on_initialize_and_on_runtime_upgrade_weight_merge_works() { - use sp_io::TestExternalities; struct Test; impl OnInitialize for Test { diff --git a/test-utils/cli/Cargo.toml b/test-utils/cli/Cargo.toml new file mode 100644 index 0000000000000..cc05884a6ebcd --- /dev/null +++ b/test-utils/cli/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "substrate-cli-test-utils" +description = "CLI testing utilities" +version = "0.1.0" +authors = ["Parity Technologies "] +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"] + +[dependencies] +substrate-rpc-client = { path = "../../utils/frame/rpc/client" } +assert_cmd = "2.0.10" +nix = "0.26.2" +regex = "1.7.3" +tempfile = "3.5.0" +tokio = { version = "1.22.0", features = ["full"] } +node-primitives = { path = "../../bin/node/primitives" } +futures = "0.3.28" diff --git a/bin/node/cli/tests/common.rs b/test-utils/cli/src/lib.rs similarity index 52% rename from bin/node/cli/tests/common.rs rename to test-utils/cli/src/lib.rs index 4c4824391fdc1..1846f19090b33 100644 --- a/bin/node/cli/tests/common.rs +++ b/test-utils/cli/src/lib.rs @@ -26,12 +26,146 @@ use nix::{ use node_primitives::{Hash, Header}; use regex::Regex; use std::{ + env, io::{BufRead, BufReader, Read}, ops::{Deref, DerefMut}, path::{Path, PathBuf}, process::{self, Child, Command}, time::Duration, }; +use tokio::io::{AsyncBufReadExt, AsyncRead}; + +/// Starts a new Substrate node in development mode with a temporary chain. +/// +/// This function creates a new Substrate node using the `substrate` binary. +/// It configures the node to run in development mode (`--dev`) with a temporary chain (`--tmp`), +/// sets the WebSocket port to 45789 (`--ws-port=45789`). +/// +/// # Returns +/// +/// A [`Child`] process representing the spawned Substrate node. +/// +/// # Panics +/// +/// This function will panic if the `substrate` binary is not found or if the node fails to start. +/// +/// # Examples +/// +/// ```ignore +/// use my_crate::start_node; +/// +/// let child = start_node(); +/// // Interact with the Substrate node using the WebSocket port 45789. +/// // When done, the node will be killed when the `child` is dropped. +/// ``` +/// +/// [`Child`]: std::process::Child +pub 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() +} + +/// Builds the Substrate project using the provided arguments. +/// +/// This function reads the CARGO_MANIFEST_DIR environment variable to find the root workspace +/// directory. It then runs the `cargo b` command in the root directory with the specified +/// arguments. +/// +/// This can be useful for building the Substrate binary with a desired set of features prior +/// to using the binary in a CLI test. +/// +/// # Arguments +/// +/// * `args: &[&str]` - A slice of string references representing the arguments to pass to the +/// `cargo b` command. +/// +/// # Panics +/// +/// This function will panic if: +/// +/// * The CARGO_MANIFEST_DIR environment variable is not set. +/// * The root workspace directory cannot be determined. +/// * The 'cargo b' command fails to execute. +/// * The 'cargo b' command returns a non-successful status. +/// +/// # Examples +/// +/// ```ignore +/// build_substrate(&["--features=try-runtime"]); +/// ``` +pub fn build_substrate(args: &[&str]) { + // Get the root workspace directory from the CARGO_MANIFEST_DIR environment variable + let manifest_dir = env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set"); + let root_dir = std::path::Path::new(&manifest_dir) + .parent() + .expect("Failed to find root workspace directory"); + let output = Command::new("cargo") + .arg("build") + .args(args) + .current_dir(root_dir) + .output() + .expect(format!("Failed to execute 'cargo b' with args {:?}'", args).as_str()); + + if !output.status.success() { + panic!( + "Failed to execute 'cargo b' with args {:?}': \n{}", + args, + String::from_utf8_lossy(&output.stderr) + ); + } +} + +/// Takes a readable tokio stream (e.g. from a child process `ChildStderr` or `ChildStdout`) and +/// a `Regex` pattern, and checks each line against the given pattern as it is produced. +/// The function returns OK(()) as soon as a line matching the pattern is found, or an Err if +/// the stream ends without any lines matching the pattern. +/// +/// # Arguments +/// +/// * `child_stream` - An async tokio stream, e.g. from a child process `ChildStderr` or +/// `ChildStdout`. +/// * `re` - A `Regex` pattern to search for in the stream. +/// +/// # Returns +/// +/// * `Ok(())` if a line matching the pattern is found. +/// * `Err(String)` if the stream ends without any lines matching the pattern. +/// +/// # Examples +/// +/// ```ignore +/// use regex::Regex; +/// use tokio::process::Command; +/// use tokio::io::AsyncRead; +/// +/// # async fn run() { +/// let child = Command::new("some-command").stderr(std::process::Stdio::piped()).spawn().unwrap(); +/// let stderr = child.stderr.unwrap(); +/// let re = Regex::new("error:").unwrap(); +/// +/// match wait_for_pattern_match_in_stream(stderr, re).await { +/// Ok(()) => println!("Error found in stderr"), +/// Err(e) => println!("Error: {}", e), +/// } +/// # } +/// ``` +pub async fn wait_for_stream_pattern_match(stream: R, re: Regex) -> Result<(), String> +where + R: AsyncRead + Unpin, +{ + let mut stdio_reader = tokio::io::BufReader::new(stream).lines(); + while let Ok(Some(line)) = stdio_reader.next_line().await { + match re.find(line.as_str()) { + Some(_) => return Ok(()), + None => (), + } + } + Err(String::from("Stream closed without any lines matching the regex.")) +} /// Run the given `future` and panic if the `timeout` is hit. pub async fn run_with_timeout(timeout: Duration, future: impl futures::Future) { diff --git a/utils/frame/try-runtime/cli/Cargo.toml b/utils/frame/try-runtime/cli/Cargo.toml index a220289542464..a4d24986eddff 100644 --- a/utils/frame/try-runtime/cli/Cargo.toml +++ b/utils/frame/try-runtime/cli/Cargo.toml @@ -45,10 +45,10 @@ serde_json = "1.0.85" zstd = { version = "0.11.2", default-features = false } [dev-dependencies] -tokio = "1.22.0" +assert_cmd = "2.0.10" +regex = "1.7.3" +substrate-cli-test-utils = { path = "../../../../test-utils/cli" } +tokio = "1.27.0" [features] -try-runtime = [ - "sp-debug-derive/force-debug", - "frame-try-runtime/try-runtime", -] +try-runtime = ["sp-debug-derive/force-debug", "frame-try-runtime/try-runtime"] 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 413c68550b76d..d5c68978eb61a 100644 --- a/utils/frame/try-runtime/cli/src/commands/follow_chain.rs +++ b/utils/frame/try-runtime/cli/src/commands/follow_chain.rs @@ -108,10 +108,12 @@ where .or_else(|e| { if matches!(e, substrate_rpc_client::Error::ParseError(_)) { log::error!( + target: LOG_TARGET, "failed to parse the block format of remote against the local \ - codebase. The block format has changed, and follow-chain cannot run in \ - this case. Try running this command in a branch of your codebase that has \ - the same block format as the remote chain. For now, we replace the block with an empty one" + codebase. The block format has changed, and follow-chain cannot run in \ + this case. Try running this command in a branch of your codebase that + has the same block format as the remote chain. For now, we replace the \ + block with an empty one." ); } Err(rpc_err_handler(e)) @@ -148,7 +150,9 @@ where state_ext, &executor, "TryRuntime_execute_block", - (block, command.state_root_check, command.try_state.clone()).encode().as_ref(), + (block, command.state_root_check, true, command.try_state.clone()) + .encode() + .as_ref(), full_extensions(executor.clone()), shared .export_proof diff --git a/utils/frame/try-runtime/cli/tests/follow_chain.rs b/utils/frame/try-runtime/cli/tests/follow_chain.rs new file mode 100644 index 0000000000000..a4961aa280171 --- /dev/null +++ b/utils/frame/try-runtime/cli/tests/follow_chain.rs @@ -0,0 +1,65 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#![cfg(unix)] + +#[cfg(feature = "try-runtime")] +mod tests { + use assert_cmd::cargo::cargo_bin; + use regex::Regex; + use std::{ + process::{self}, + time::Duration, + }; + use substrate_cli_test_utils as common; + use tokio::process::{Child, Command}; + + #[tokio::test] + async fn follow_chain_works() { + // Build substrate so binaries used in the test use the latest code. + common::build_substrate(&["--features=try-runtime"]); + + common::run_with_timeout(Duration::from_secs(60), async move { + fn start_follow(ws_url: &str) -> Child { + Command::new(cargo_bin("substrate")) + .stdout(process::Stdio::piped()) + .stderr(process::Stdio::piped()) + .args(&["try-runtime", "--runtime=existing"]) + .args(&["follow-chain", format!("--uri={}", ws_url).as_str()]) + .kill_on_drop(true) + .spawn() + .unwrap() + } + + // Start a node and wait for it to begin finalizing blocks + let mut node = common::KillChildOnDrop(common::start_node()); + let ws_url = common::extract_info_from_output(node.stderr.take().unwrap()).0.ws_url; + common::wait_n_finalized_blocks(1, &ws_url).await; + + // Kick off the follow-chain process and wait for it to process at least 3 blocks. + let mut follow = start_follow(&ws_url); + let re = Regex::new(r#".*executed block ([3-9]|[1-9]\d+).*"#).unwrap(); + let matched = + common::wait_for_stream_pattern_match(follow.stderr.take().unwrap(), re).await; + + // Assert that the follow-chain process has followed at least 3 blocks. + assert!(matches!(matched, Ok(_))); + }) + .await; + } +} From 9e1fa3db3547df432acd42aa6e6419b030212edc Mon Sep 17 00:00:00 2001 From: alexd10s Date: Thu, 6 Apr 2023 12:27:43 +0100 Subject: [PATCH 621/715] Use proper weights in the `pallet-template` (#13817) * benchmarking to generate weights file * add the calculated weights in the extrinsics * use benchmarking v2 syntax to generate the weights * minor syntax change when benchmarking * added WeightInfo in the mock to pass tests * minor cargo fmt format changes --- Cargo.lock | 1 + bin/node-template/pallets/template/Cargo.toml | 1 + .../pallets/template/src/benchmarking.rs | 31 +++++-- bin/node-template/pallets/template/src/lib.rs | 9 +- .../pallets/template/src/mock.rs | 1 + .../pallets/template/src/weights.rs | 91 +++++++++++++++++++ bin/node-template/runtime/src/lib.rs | 1 + 7 files changed, 125 insertions(+), 10 deletions(-) create mode 100644 bin/node-template/pallets/template/src/weights.rs diff --git a/Cargo.lock b/Cargo.lock index d4185103f8c96..525f40cedc8db 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6864,6 +6864,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", + "sp-std", ] [[package]] diff --git a/bin/node-template/pallets/template/Cargo.toml b/bin/node-template/pallets/template/Cargo.toml index ddf7c6e52fb2f..818dc0bbc8c3c 100644 --- a/bin/node-template/pallets/template/Cargo.toml +++ b/bin/node-template/pallets/template/Cargo.toml @@ -20,6 +20,7 @@ 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" } +sp-std = { version = "5.0.0", default-features = false, path = "../../../../primitives/std" } [dev-dependencies] sp-core = { version = "7.0.0", path = "../../../../primitives/core" } diff --git a/bin/node-template/pallets/template/src/benchmarking.rs b/bin/node-template/pallets/template/src/benchmarking.rs index 1790849970440..5a262417629c5 100644 --- a/bin/node-template/pallets/template/src/benchmarking.rs +++ b/bin/node-template/pallets/template/src/benchmarking.rs @@ -1,19 +1,34 @@ //! Benchmarking setup for pallet-template - +#![cfg(feature = "runtime-benchmarks")] use super::*; #[allow(unused)] use crate::Pallet as Template; -use frame_benchmarking::v1::{benchmarks, whitelisted_caller}; +use frame_benchmarking::v2::*; use frame_system::RawOrigin; -benchmarks! { - do_something { - let s in 0 .. 100; +#[benchmarks] +mod benchmarks { + use super::*; + + #[benchmark] + fn do_something() { + let value = 100u32.into(); let caller: T::AccountId = whitelisted_caller(); - }: _(RawOrigin::Signed(caller), s) - verify { - assert_eq!(Something::::get(), Some(s)); + #[extrinsic_call] + do_something(RawOrigin::Signed(caller), value); + + assert_eq!(Something::::get(), Some(value)); + } + + #[benchmark] + fn cause_error() { + Something::::put(100u32); + let caller: T::AccountId = whitelisted_caller(); + #[extrinsic_call] + cause_error(RawOrigin::Signed(caller)); + + assert_eq!(Something::::get(), Some(101u32)); } impl_benchmark_test_suite!(Template, crate::mock::new_test_ext(), crate::mock::Test); diff --git a/bin/node-template/pallets/template/src/lib.rs b/bin/node-template/pallets/template/src/lib.rs index 9f17623db328f..9550d3d546cca 100644 --- a/bin/node-template/pallets/template/src/lib.rs +++ b/bin/node-template/pallets/template/src/lib.rs @@ -13,9 +13,12 @@ mod tests; #[cfg(feature = "runtime-benchmarks")] mod benchmarking; +pub mod weights; +pub use weights::*; #[frame_support::pallet] pub mod pallet { + use super::*; use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; @@ -27,6 +30,8 @@ pub mod pallet { pub trait Config: frame_system::Config { /// Because this pallet emits events, it depends on the runtime's definition of an event. type RuntimeEvent: From> + IsType<::RuntimeEvent>; + /// Type representing the weight of this pallet + type WeightInfo: WeightInfo; } // The pallet's runtime storage items. @@ -64,7 +69,7 @@ pub mod 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())] + #[pallet::weight(T::WeightInfo::do_something())] pub fn do_something(origin: OriginFor, something: u32) -> DispatchResult { // Check that the extrinsic was signed and get the signer. // This function will return an error if the extrinsic is not signed. @@ -82,7 +87,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())] + #[pallet::weight(T::WeightInfo::cause_error())] pub fn cause_error(origin: OriginFor) -> DispatchResult { let _who = ensure_signed(origin)?; diff --git a/bin/node-template/pallets/template/src/mock.rs b/bin/node-template/pallets/template/src/mock.rs index 91a1bf6ed5fc8..b4d6905378a5d 100644 --- a/bin/node-template/pallets/template/src/mock.rs +++ b/bin/node-template/pallets/template/src/mock.rs @@ -50,6 +50,7 @@ impl frame_system::Config for Test { impl pallet_template::Config for Test { type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); } // Build genesis storage according to the mock runtime. diff --git a/bin/node-template/pallets/template/src/weights.rs b/bin/node-template/pallets/template/src/weights.rs new file mode 100644 index 0000000000000..952aba49bb3d4 --- /dev/null +++ b/bin/node-template/pallets/template/src/weights.rs @@ -0,0 +1,91 @@ + +//! Autogenerated weights for pallet_template +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-04-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `Alexs-MacBook-Pro-2.local`, CPU: `` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 + +// Executed Command: +// ../../target/release/node-template +// benchmark +// pallet +// --chain +// dev +// --pallet +// pallet_template +// --extrinsic +// * +// --steps=50 +// --repeat=20 +// --execution=wasm +// --wasm-execution=compiled +// --output +// pallets/template/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_template. +pub trait WeightInfo { + fn do_something() -> Weight; + fn cause_error() -> Weight; +} + +/// Weights for pallet_template using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + /// Storage: TemplateModule Something (r:0 w:1) + /// Proof: TemplateModule Something (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + fn do_something() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 8_000_000 picoseconds. + Weight::from_parts(8_000_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: TemplateModule Something (r:1 w:1) + /// Proof: TemplateModule Something (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + fn cause_error() -> Weight { + // Proof Size summary in bytes: + // Measured: `32` + // Estimated: `1489` + // Minimum execution time: 5_000_000 picoseconds. + Weight::from_parts(6_000_000, 1489) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } +} + +// For backwards compatibility and tests +impl WeightInfo for () { + /// Storage: TemplateModule Something (r:0 w:1) + /// Proof: TemplateModule Something (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + fn do_something() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 8_000_000 picoseconds. + Weight::from_parts(8_000_000, 0) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: TemplateModule Something (r:1 w:1) + /// Proof: TemplateModule Something (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + fn cause_error() -> Weight { + // Proof Size summary in bytes: + // Measured: `32` + // Estimated: `1489` + // Minimum execution time: 5_000_000 picoseconds. + Weight::from_parts(6_000_000, 1489) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } +} diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs index 50bcb67cb4790..3dcf1b5564dec 100644 --- a/bin/node-template/runtime/src/lib.rs +++ b/bin/node-template/runtime/src/lib.rs @@ -270,6 +270,7 @@ impl pallet_sudo::Config for Runtime { /// Configure the pallet-template in pallets/template. impl pallet_template::Config for Runtime { type RuntimeEvent = RuntimeEvent; + type WeightInfo = pallet_template::weights::SubstrateWeight; } // Create the runtime by composing the FRAME pallets that were previously configured. From 9a07e9d564636198afef9260de390ebcd40ac1fc Mon Sep 17 00:00:00 2001 From: Liam Aharon Date: Fri, 7 Apr 2023 00:27:25 +1000 Subject: [PATCH 622/715] `RemovePallet` migration utility struct (#13835) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * remove pallet utility struct * Update frame/support/src/remove_pallet.rs Co-authored-by: Bastian Köcher * Update frame/support/src/remove_pallet.rs Co-authored-by: Bastian Köcher * make removepallet a module of migrations * fix rust doc lint --------- Co-authored-by: Bastian Köcher --- frame/support/src/migrations.rs | 116 ++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) diff --git a/frame/support/src/migrations.rs b/frame/support/src/migrations.rs index 645316042b38c..f54b73aad8889 100644 --- a/frame/support/src/migrations.rs +++ b/frame/support/src/migrations.rs @@ -15,11 +15,18 @@ // See the License for the specific language governing permissions and // limitations under the License. +#[cfg(feature = "try-runtime")] +use crate::storage::unhashed::contains_prefixed_key; use crate::{ traits::{GetStorageVersion, PalletInfoAccess}, weights::{RuntimeDbWeight, Weight}, }; use impl_trait_for_tuples::impl_for_tuples; +use sp_core::Get; +use sp_io::{hashing::twox_128, storage::clear_prefix, KillStorageResult}; +use sp_std::marker::PhantomData; +#[cfg(feature = "try-runtime")] +use sp_std::vec::Vec; /// Trait used by [`migrate_from_pallet_version_to_storage_version`] to do the actual migration. pub trait PalletVersionToStorageVersionHelper { @@ -67,3 +74,112 @@ pub fn migrate_from_pallet_version_to_storage_version< ) -> Weight { Pallets::migrate(db_weight) } + +/// `RemovePallet` is a utility struct used to remove all storage items associated with a specific +/// pallet. +/// +/// This struct is generic over two parameters: +/// - `P` is a type that implements the `Get` trait for a static string, representing the pallet's +/// name. +/// - `DbWeight` is a type that implements the `Get` trait for `RuntimeDbWeight`, providing the +/// weight for database operations. +/// +/// On runtime upgrade, the `on_runtime_upgrade` function will clear all storage items associated +/// with the specified pallet, logging the number of keys removed. If the `try-runtime` feature is +/// enabled, the `pre_upgrade` and `post_upgrade` functions can be used to verify the storage +/// removal before and after the upgrade. +/// +/// # Examples: +/// ```ignore +/// construct_runtime! { +/// pub enum Runtime where +/// Block = Block, +/// NodeBlock = primitives::Block, +/// UncheckedExtrinsic = UncheckedExtrinsic +/// { +/// System: frame_system::{Pallet, Call, Storage, Config, Event} = 0, +/// +/// SomePalletToRemove: pallet_something::{Pallet, Call, Storage, Event} = 1, +/// AnotherPalletToRemove: pallet_something_else::{Pallet, Call, Storage, Event} = 2, +/// +/// YourOtherPallets... +/// } +/// }; +/// +/// parameter_types! { +/// pub const SomePalletToRemoveStr: &'static str = "SomePalletToRemove"; +/// pub const AnotherPalletToRemoveStr: &'static str = "AnotherPalletToRemove"; +/// } +/// +/// pub type Migrations = ( +/// RemovePallet, +/// RemovePallet, +/// AnyOtherMigrations... +/// ); +/// +/// pub type Executive = frame_executive::Executive< +/// Runtime, +/// Block, +/// frame_system::ChainContext, +/// Runtime, +/// Migrations +/// >; +/// ``` +/// +/// WARNING: `RemovePallet` has no guard rails preventing it from bricking the chain if the +/// operation of removing storage for the given pallet would exceed the block weight limit. +/// +/// If your pallet has too many keys to be removed in a single block, it is advised to wait for +/// a multi-block scheduler currently under development which will allow for removal of storage +/// items (and performing other heavy migrations) over multiple blocks +/// (see ). +pub struct RemovePallet, DbWeight: Get>( + PhantomData<(P, DbWeight)>, +); +impl, DbWeight: Get> frame_support::traits::OnRuntimeUpgrade + for RemovePallet +{ + fn on_runtime_upgrade() -> frame_support::weights::Weight { + let hashed_prefix = twox_128(P::get().as_bytes()); + let keys_removed = match clear_prefix(&hashed_prefix, None) { + KillStorageResult::AllRemoved(value) => value, + KillStorageResult::SomeRemaining(value) => { + log::error!( + "`clear_prefix` failed to remove all keys for {}. THIS SHOULD NEVER HAPPEN! 🚨", + P::get() + ); + value + }, + } as u64; + + log::info!("Removed {} {} keys 🧹", keys_removed, P::get()); + + DbWeight::get().reads_writes(keys_removed + 1, keys_removed) + } + + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, &'static str> { + let hashed_prefix = twox_128(P::get().as_bytes()); + match contains_prefixed_key(&hashed_prefix) { + true => log::info!("Found {} keys pre-removal 👀", P::get()), + false => log::warn!( + "Migration RemovePallet<{}> can be removed (no keys found pre-removal).", + P::get() + ), + }; + Ok(Vec::new()) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(_state: Vec) -> Result<(), &'static str> { + let hashed_prefix = twox_128(P::get().as_bytes()); + match contains_prefixed_key(&hashed_prefix) { + true => { + log::error!("{} has keys remaining post-removal ❗", P::get()); + return Err("Keys remaining post-removal, this should never happen 🚨") + }, + false => log::info!("No {} keys found post-removal 🎉", P::get()), + }; + Ok(()) + } +} From e08235acd2a98b7403b526ff11f63d2869e6cd15 Mon Sep 17 00:00:00 2001 From: Chris Kerr <120631257+piffle-rack@users.noreply.github.com> Date: Thu, 6 Apr 2023 19:06:15 +0300 Subject: [PATCH 623/715] Fix typos (#13842) * Fix typo GRANPA -> GRANDPA * Fix capitalisation Fixed words capitalised in the middle of sentences. --- client/network/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/network/README.md b/client/network/README.md index d396747241ab1..b9c0e028ffe77 100644 --- a/client/network/README.md +++ b/client/network/README.md @@ -223,7 +223,7 @@ For each peer the sync maintains the number of our common best block with that p whenever peer announce new blocks or our best block advances. This allows to keep track of peers that have new block data and request new information as soon as it is announced. In keep-up mode, we also track peers that announce blocks on all branches and not just the best branch. The sync algorithm tries to be greedy and download -All data that's announced. +all data that's announced. ## Fast sync @@ -262,8 +262,8 @@ After the latest state has been imported the node is fully operational, but is s data. I.e. it is unable to serve bock bodies and headers other than the most recent one. To make sure all nodes have block history available, a background sync process is started that downloads all the missing blocks. It is run in parallel with the keep-up sync and does not interfere with downloading of the recent blocks. -During this download we also import GRANPA justifications for blocks with authority set changes, so that -The warp-synced node has all the data to serve for other nodes nodes that might want to sync from it with +During this download we also import GRANDPA justifications for blocks with authority set changes, so that +the warp-synced node has all the data to serve for other nodes nodes that might want to sync from it with any method. # Usage From 851a8264909acb14d77a0f25a281147f4e689152 Mon Sep 17 00:00:00 2001 From: alexd10s Date: Thu, 6 Apr 2023 17:19:46 +0100 Subject: [PATCH 624/715] Update the frame-weight-template to use PhantomData from core (#13844) * update weights template and recalculate weights from pallet template * update template file in benchmarking-cli --- .maintain/frame-weight-template.hbs | 2 +- Cargo.lock | 1 - bin/node-template/pallets/template/Cargo.toml | 1 - bin/node-template/pallets/template/src/weights.rs | 12 ++++++------ utils/frame/benchmarking-cli/src/pallet/template.hbs | 2 +- 5 files changed, 8 insertions(+), 10 deletions(-) diff --git a/.maintain/frame-weight-template.hbs b/.maintain/frame-weight-template.hbs index ba9ac0798844d..0df6bef5d3bee 100644 --- a/.maintain/frame-weight-template.hbs +++ b/.maintain/frame-weight-template.hbs @@ -17,7 +17,7 @@ #![allow(unused_imports)] use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; -use sp_std::marker::PhantomData; +use core::marker::PhantomData; /// Weight functions needed for {{pallet}}. pub trait WeightInfo { diff --git a/Cargo.lock b/Cargo.lock index 525f40cedc8db..d4185103f8c96 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6864,7 +6864,6 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", ] [[package]] diff --git a/bin/node-template/pallets/template/Cargo.toml b/bin/node-template/pallets/template/Cargo.toml index 818dc0bbc8c3c..ddf7c6e52fb2f 100644 --- a/bin/node-template/pallets/template/Cargo.toml +++ b/bin/node-template/pallets/template/Cargo.toml @@ -20,7 +20,6 @@ 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" } -sp-std = { version = "5.0.0", default-features = false, path = "../../../../primitives/std" } [dev-dependencies] sp-core = { version = "7.0.0", path = "../../../../primitives/core" } diff --git a/bin/node-template/pallets/template/src/weights.rs b/bin/node-template/pallets/template/src/weights.rs index 952aba49bb3d4..e8fbc09bad8e9 100644 --- a/bin/node-template/pallets/template/src/weights.rs +++ b/bin/node-template/pallets/template/src/weights.rs @@ -2,7 +2,7 @@ //! Autogenerated weights for pallet_template //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-04-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `Alexs-MacBook-Pro-2.local`, CPU: `` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -31,7 +31,7 @@ #![allow(unused_imports)] use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; -use sp_std::marker::PhantomData; +use core::marker::PhantomData; /// Weight functions needed for pallet_template. pub trait WeightInfo { @@ -49,7 +49,7 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 8_000_000 picoseconds. - Weight::from_parts(8_000_000, 0) + Weight::from_parts(9_000_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: TemplateModule Something (r:1 w:1) @@ -58,7 +58,7 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `32` // Estimated: `1489` - // Minimum execution time: 5_000_000 picoseconds. + // Minimum execution time: 6_000_000 picoseconds. Weight::from_parts(6_000_000, 1489) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) @@ -74,7 +74,7 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 8_000_000 picoseconds. - Weight::from_parts(8_000_000, 0) + Weight::from_parts(9_000_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: TemplateModule Something (r:1 w:1) @@ -83,7 +83,7 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `32` // Estimated: `1489` - // Minimum execution time: 5_000_000 picoseconds. + // Minimum execution time: 6_000_000 picoseconds. Weight::from_parts(6_000_000, 1489) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) diff --git a/utils/frame/benchmarking-cli/src/pallet/template.hbs b/utils/frame/benchmarking-cli/src/pallet/template.hbs index 88d6b69a6c339..f852e773ce7d7 100644 --- a/utils/frame/benchmarking-cli/src/pallet/template.hbs +++ b/utils/frame/benchmarking-cli/src/pallet/template.hbs @@ -17,7 +17,7 @@ #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; -use sp_std::marker::PhantomData; +use core::marker::PhantomData; /// Weight functions for `{{pallet}}`. pub struct WeightInfo(PhantomData); From d443f148ce0aa6a51798b86c6b3ae54113786f94 Mon Sep 17 00:00:00 2001 From: Aaro Altonen <48052676+altonen@users.noreply.github.com> Date: Fri, 7 Apr 2023 11:20:17 +0300 Subject: [PATCH 625/715] Make blocks per request configurable (#13824) * Make blocks per request configurable * Correct type * Update docs * Update client/cli/src/params/network_params.rs --- client/cli/src/params/network_params.rs | 8 ++ client/network/src/config.rs | 5 ++ .../network/sync/src/block_request_handler.rs | 6 +- client/network/sync/src/blocks.rs | 2 +- client/network/sync/src/engine.rs | 9 ++ client/network/sync/src/lib.rs | 84 ++++++++++++------- 6 files changed, 81 insertions(+), 33 deletions(-) diff --git a/client/cli/src/params/network_params.rs b/client/cli/src/params/network_params.rs index acec4b2ac872a..9d61e7204295d 100644 --- a/client/cli/src/params/network_params.rs +++ b/client/cli/src/params/network_params.rs @@ -141,6 +141,13 @@ pub struct NetworkParams { verbatim_doc_comment )] pub sync: SyncMode, + + /// Maximum number of blocks per request. + /// + /// Try reducing this number from the default value if you have a slow network connection + /// and observe block requests timing out. + #[arg(long, value_name = "COUNT", default_value_t = 64)] + pub max_blocks_per_request: u32, } impl NetworkParams { @@ -230,6 +237,7 @@ impl NetworkParams { allow_private_ip, }, max_parallel_downloads: self.max_parallel_downloads, + max_blocks_per_request: self.max_blocks_per_request, enable_dht_random_walk: !self.reserved_only, allow_non_globals_in_dht, kademlia_disjoint_query_paths: self.kademlia_disjoint_query_paths, diff --git a/client/network/src/config.rs b/client/network/src/config.rs index 781ae9c786694..e00bfac79f650 100644 --- a/client/network/src/config.rs +++ b/client/network/src/config.rs @@ -566,6 +566,7 @@ pub struct NetworkConfiguration { /// List of request-response protocols that the node supports. pub request_response_protocols: Vec, + /// Configuration for the default set of nodes used for block syncing and transactions. pub default_peers_set: SetConfig, @@ -590,6 +591,9 @@ pub struct NetworkConfiguration { /// Maximum number of peers to ask the same blocks in parallel. pub max_parallel_downloads: u32, + /// Maximum number of blocks per request. + pub max_blocks_per_request: u32, + /// Initial syncing mode. pub sync_mode: SyncMode, @@ -653,6 +657,7 @@ impl NetworkConfiguration { node_name: node_name.into(), transport: TransportConfig::Normal { enable_mdns: false, allow_private_ip: true }, max_parallel_downloads: 5, + max_blocks_per_request: 64, sync_mode: SyncMode::Full, enable_dht_random_walk: true, allow_non_globals_in_dht: false, diff --git a/client/network/sync/src/block_request_handler.rs b/client/network/sync/src/block_request_handler.rs index 921efd7def622..ece565aad4b09 100644 --- a/client/network/sync/src/block_request_handler.rs +++ b/client/network/sync/src/block_request_handler.rs @@ -17,7 +17,10 @@ //! Helper for handling (i.e. answering) block requests from a remote peer via the //! `crate::request_responses::RequestResponsesBehaviour`. -use crate::schema::v1::{block_request::FromBlock, BlockResponse, Direction}; +use crate::{ + schema::v1::{block_request::FromBlock, BlockResponse, Direction}, + MAX_BLOCKS_IN_RESPONSE, +}; use codec::{Decode, Encode}; use futures::{ @@ -50,7 +53,6 @@ use std::{ }; const LOG_TARGET: &str = "sync"; -const MAX_BLOCKS_IN_RESPONSE: usize = 128; const MAX_BODY_BYTES: usize = 8 * 1024 * 1024; const MAX_NUMBER_OF_SAME_REQUESTS_PER_PEER: usize = 2; diff --git a/client/network/sync/src/blocks.rs b/client/network/sync/src/blocks.rs index 4cc1ca080d177..3c76238be1b5f 100644 --- a/client/network/sync/src/blocks.rs +++ b/client/network/sync/src/blocks.rs @@ -109,7 +109,7 @@ impl BlockCollection { pub fn needed_blocks( &mut self, who: PeerId, - count: usize, + count: u32, peer_best: NumberFor, common: NumberFor, max_parallel: u32, diff --git a/client/network/sync/src/engine.rs b/client/network/sync/src/engine.rs index e3d45a980a0b4..6fb618a571c25 100644 --- a/client/network/sync/src/engine.rs +++ b/client/network/sync/src/engine.rs @@ -264,6 +264,14 @@ where SyncOperationMode::Warp => SyncMode::Warp, }; let max_parallel_downloads = network_config.max_parallel_downloads; + let max_blocks_per_request = if network_config.max_blocks_per_request > + crate::MAX_BLOCKS_IN_RESPONSE as u32 + { + log::info!(target: "sync", "clamping maximum blocks per request to {}", crate::MAX_BLOCKS_IN_RESPONSE); + crate::MAX_BLOCKS_IN_RESPONSE as u32 + } else { + network_config.max_blocks_per_request + }; let cache_capacity = NonZeroUsize::new( (network_config.default_peers_set.in_peers as usize + network_config.default_peers_set.out_peers as usize) @@ -318,6 +326,7 @@ where roles, block_announce_validator, max_parallel_downloads, + max_blocks_per_request, warp_sync_params, metrics_registry, network_service.clone(), diff --git a/client/network/sync/src/lib.rs b/client/network/sync/src/lib.rs index 28959e7f9c886..e112a1715ced1 100644 --- a/client/network/sync/src/lib.rs +++ b/client/network/sync/src/lib.rs @@ -107,9 +107,6 @@ pub mod state_request_handler; pub mod warp; pub mod warp_request_handler; -/// Maximum blocks to request in a single packet. -const MAX_BLOCKS_TO_REQUEST: usize = 64; - /// Maximum blocks to store in the import queue. const MAX_IMPORTING_BLOCKS: usize = 2048; @@ -147,6 +144,9 @@ const MIN_PEERS_TO_START_WARP_SYNC: usize = 3; /// Maximum allowed size for a block announce. const MAX_BLOCK_ANNOUNCE_SIZE: u64 = 1024 * 1024; +/// Maximum blocks per response. +pub(crate) const MAX_BLOCKS_IN_RESPONSE: usize = 128; + mod rep { use sc_peerset::ReputationChange as Rep; /// Reputation change when a peer sent us a message that led to a @@ -311,6 +311,8 @@ pub struct ChainSync { block_announce_validator: Box + Send>, /// Maximum number of peers to ask the same blocks in parallel. max_parallel_downloads: u32, + /// Maximum blocks per request. + max_blocks_per_request: u32, /// Total number of downloaded blocks. downloaded_blocks: usize, /// All block announcement that are currently being validated. @@ -1403,6 +1405,7 @@ where roles: Roles, block_announce_validator: Box + Send>, max_parallel_downloads: u32, + max_blocks_per_request: u32, warp_sync_params: Option>, metrics_registry: Option<&Registry>, network_service: service::network::NetworkServiceHandle, @@ -1437,6 +1440,7 @@ where allowed_requests: Default::default(), block_announce_validator, max_parallel_downloads, + max_blocks_per_request, downloaded_blocks: 0, block_announce_validation: Default::default(), block_announce_validation_per_peer_stats: Default::default(), @@ -2365,6 +2369,7 @@ where let queue = &self.queue_blocks; let allowed_requests = self.allowed_requests.take(); let max_parallel = if is_major_syncing { 1 } else { self.max_parallel_downloads }; + let max_blocks_per_request = self.max_blocks_per_request; let gap_sync = &mut self.gap_sync; self.peers .iter_mut() @@ -2404,6 +2409,7 @@ where blocks, attrs, max_parallel, + max_blocks_per_request, last_finalized, best_queued, ) { @@ -2430,6 +2436,7 @@ where client.block_status(*hash).unwrap_or(BlockStatus::Unknown) } }, + max_blocks_per_request, ) { trace!(target: "sync", "Downloading fork {:?} from {}", hash, id); peer.state = PeerSyncState::DownloadingStale(hash); @@ -2442,6 +2449,7 @@ where attrs, sync.target, sync.best_queued_number, + max_blocks_per_request, ) }) { peer.state = PeerSyncState::DownloadingGap(range.start); @@ -2910,6 +2918,7 @@ fn peer_block_request( blocks: &mut BlockCollection, attrs: BlockAttributes, max_parallel_downloads: u32, + max_blocks_per_request: u32, finalized: NumberFor, best_num: NumberFor, ) -> Option<(Range>, BlockRequest)> { @@ -2925,7 +2934,7 @@ fn peer_block_request( } let range = blocks.needed_blocks( *id, - MAX_BLOCKS_TO_REQUEST, + max_blocks_per_request, peer.best_number, peer.common_number, max_parallel_downloads, @@ -2960,10 +2969,11 @@ fn peer_gap_block_request( attrs: BlockAttributes, target: NumberFor, common_number: NumberFor, + max_blocks_per_request: u32, ) -> Option<(Range>, BlockRequest)> { let range = blocks.needed_blocks( *id, - MAX_BLOCKS_TO_REQUEST, + max_blocks_per_request, std::cmp::min(peer.best_number, target), common_number, 1, @@ -2992,6 +3002,7 @@ fn fork_sync_request( finalized: NumberFor, attributes: BlockAttributes, check_block: impl Fn(&B::Hash) -> BlockStatus, + max_blocks_per_request: u32, ) -> Option<(B::Hash, BlockRequest)> { targets.retain(|hash, r| { if r.number <= finalized { @@ -3011,7 +3022,7 @@ fn fork_sync_request( // 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 + (r.number - best_num).saturated_into::() < max_blocks_per_request as u32 { let parent_status = r.parent_hash.as_ref().map_or(BlockStatus::Unknown, check_block); let count = if parent_status == BlockStatus::Unknown { @@ -3199,6 +3210,7 @@ mod test { Roles::from(&Role::Full), block_announce_validator, 1, + 64, None, None, chain_sync_network_handle, @@ -3265,6 +3277,7 @@ mod test { Roles::from(&Role::Full), Box::new(DefaultBlockAnnounceValidator), 1, + 64, None, None, chain_sync_network_handle, @@ -3446,6 +3459,7 @@ mod test { Roles::from(&Role::Full), Box::new(DefaultBlockAnnounceValidator), 5, + 64, None, None, chain_sync_network_handle, @@ -3572,6 +3586,7 @@ mod test { Roles::from(&Role::Full), Box::new(DefaultBlockAnnounceValidator), 5, + 64, None, None, chain_sync_network_handle, @@ -3586,6 +3601,7 @@ mod test { let peer_id2 = PeerId::random(); let best_block = blocks.last().unwrap().clone(); + let max_blocks_to_request = sync.max_blocks_per_request; // Connect the node we will sync from sync.new_peer(peer_id1, best_block.hash(), *best_block.header().number()) .unwrap(); @@ -3595,8 +3611,8 @@ mod test { while best_block_num < MAX_DOWNLOAD_AHEAD { let request = get_block_request( &mut sync, - FromBlock::Number(MAX_BLOCKS_TO_REQUEST as u64 + best_block_num as u64), - MAX_BLOCKS_TO_REQUEST as u32, + FromBlock::Number(max_blocks_to_request as u64 + best_block_num as u64), + max_blocks_to_request as u32, &peer_id1, ); @@ -3610,14 +3626,14 @@ mod test { let res = sync.on_block_data(&peer_id1, Some(request), response).unwrap(); assert!(matches!( res, - OnBlockData::Import(_, blocks) if blocks.len() == MAX_BLOCKS_TO_REQUEST + OnBlockData::Import(_, blocks) if blocks.len() == max_blocks_to_request as usize ),); - best_block_num += MAX_BLOCKS_TO_REQUEST as u32; + 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, + max_blocks_to_request as usize, + max_blocks_to_request as usize, resp_blocks .iter() .rev() @@ -3675,8 +3691,8 @@ mod test { // peer 2 as well. get_block_request( &mut sync, - FromBlock::Number(peer1_from + MAX_BLOCKS_TO_REQUEST as u64), - MAX_BLOCKS_TO_REQUEST as u32, + FromBlock::Number(peer1_from + max_blocks_to_request as u64), + max_blocks_to_request as u32, &peer_id2, ); } @@ -3728,6 +3744,7 @@ mod test { Roles::from(&Role::Full), Box::new(DefaultBlockAnnounceValidator), 5, + 64, None, None, chain_sync_network_handle, @@ -3773,11 +3790,12 @@ mod test { // Now request and import the fork. let mut best_block_num = *finalized_block.header().number() as u32; + let max_blocks_to_request = sync.max_blocks_per_request; while best_block_num < *fork_blocks.last().unwrap().header().number() as u32 - 1 { let request = get_block_request( &mut sync, - FromBlock::Number(MAX_BLOCKS_TO_REQUEST as u64 + best_block_num as u64), - MAX_BLOCKS_TO_REQUEST as u32, + FromBlock::Number(max_blocks_to_request as u64 + best_block_num as u64), + max_blocks_to_request as u32, &peer_id1, ); @@ -3791,14 +3809,14 @@ mod test { let res = sync.on_block_data(&peer_id1, Some(request), response).unwrap(); assert!(matches!( res, - OnBlockData::Import(_, blocks) if blocks.len() == MAX_BLOCKS_TO_REQUEST + OnBlockData::Import(_, blocks) if blocks.len() == sync.max_blocks_per_request as usize ),); - best_block_num += MAX_BLOCKS_TO_REQUEST as u32; + best_block_num += sync.max_blocks_per_request as u32; let _ = sync.on_blocks_processed( - MAX_BLOCKS_TO_REQUEST as usize, - MAX_BLOCKS_TO_REQUEST as usize, + max_blocks_to_request as usize, + max_blocks_to_request as usize, resp_blocks .iter() .rev() @@ -3869,6 +3887,7 @@ mod test { Roles::from(&Role::Full), Box::new(DefaultBlockAnnounceValidator), 5, + 64, None, None, chain_sync_network_handle, @@ -3914,10 +3933,12 @@ mod test { // Now request and import the fork. let mut best_block_num = *finalized_block.header().number() as u32; + let max_blocks_to_request = sync.max_blocks_per_request; + let mut request = get_block_request( &mut sync, - FromBlock::Number(MAX_BLOCKS_TO_REQUEST as u64 + best_block_num as u64), - MAX_BLOCKS_TO_REQUEST as u32, + 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; @@ -3932,18 +3953,18 @@ mod test { let res = sync.on_block_data(&peer_id1, Some(request.clone()), response).unwrap(); assert!(matches!( res, - OnBlockData::Import(_, blocks) if blocks.len() == MAX_BLOCKS_TO_REQUEST + OnBlockData::Import(_, blocks) if blocks.len() == max_blocks_to_request as usize ),); - best_block_num += MAX_BLOCKS_TO_REQUEST as u32; + 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, + FromBlock::Number(max_blocks_to_request as u64 + best_block_num as u64), + max_blocks_to_request as u32, &peer_id1, ); } @@ -3965,16 +3986,17 @@ mod test { // The import queue may send notifications in batches of varying size. So we simulate // this here by splitting the batch into 2 notifications. + let max_blocks_to_request = sync.max_blocks_per_request; let second_batch = notify_imported.split_off(notify_imported.len() / 2); let _ = sync.on_blocks_processed( - MAX_BLOCKS_TO_REQUEST as usize, - MAX_BLOCKS_TO_REQUEST as usize, + max_blocks_to_request as usize, + max_blocks_to_request as usize, notify_imported, ); let _ = sync.on_blocks_processed( - MAX_BLOCKS_TO_REQUEST as usize, - MAX_BLOCKS_TO_REQUEST as usize, + max_blocks_to_request as usize, + max_blocks_to_request as usize, second_batch, ); @@ -4010,6 +4032,7 @@ mod test { Roles::from(&Role::Full), Box::new(DefaultBlockAnnounceValidator), 1, + 64, None, None, chain_sync_network_handle, @@ -4055,6 +4078,7 @@ mod test { Roles::from(&Role::Full), Box::new(DefaultBlockAnnounceValidator), 1, + 64, None, None, chain_sync_network_handle, From 72dd574acf805fda1dc1e64b7bbd510e12a81312 Mon Sep 17 00:00:00 2001 From: Marcin S Date: Fri, 7 Apr 2023 12:35:41 +0200 Subject: [PATCH 626/715] WASM executor: add `OutputExceedsBounds` variant to `Error` (#13841) * WASM executor: add `OutputExceedsBounds` variant to `Error` Previously this was a `WasmError`, which is intended for runtime construction errors. However this led to confusion as output-exceeds-bounds occurs due to execution of `validate_block`. * Fix warning --- client/executor/common/src/error.rs | 5 ++++- client/executor/src/integration_tests/mod.rs | 11 ++++------- client/executor/wasmtime/src/runtime.rs | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/client/executor/common/src/error.rs b/client/executor/common/src/error.rs index c47164a60655f..2dfe0bf02df2f 100644 --- a/client/executor/common/src/error.rs +++ b/client/executor/common/src/error.rs @@ -104,6 +104,9 @@ pub enum Error { #[error("Execution aborted due to trap: {0}")] AbortedDueToTrap(MessageWithBacktrace), + + #[error("Output exceeds bounds of wasm memory")] + OutputExceedsBounds, } impl wasmi::HostError for Error {} @@ -153,7 +156,7 @@ pub enum WasmError { Instantiation(String), /// Other error happenend. - #[error("{0}")] + #[error("Other error happened while constructing the runtime: {0}")] Other(String), } diff --git a/client/executor/src/integration_tests/mod.rs b/client/executor/src/integration_tests/mod.rs index 066b1497fb6ec..0148968f98a38 100644 --- a/client/executor/src/integration_tests/mod.rs +++ b/client/executor/src/integration_tests/mod.rs @@ -22,7 +22,7 @@ mod linux; use assert_matches::assert_matches; use codec::{Decode, Encode}; use sc_executor_common::{ - error::{Error, WasmError}, + error::Error, runtime_blob::RuntimeBlob, wasm_runtime::{HeapAllocStrategy, WasmModule}, }; @@ -819,9 +819,8 @@ fn return_huge_len(wasm_method: WasmExecutionMethod) { Error::Runtime => { assert_matches!(wasm_method, WasmExecutionMethod::Interpreted); }, - Error::RuntimeConstruction(WasmError::Other(error)) => { + Error::OutputExceedsBounds => { assert_matches!(wasm_method, WasmExecutionMethod::Compiled { .. }); - assert_eq!(error, "output exceeds bounds of wasm memory"); }, error => panic!("unexpected error: {:?}", error), } @@ -849,9 +848,8 @@ fn return_max_memory_offset_plus_one(wasm_method: WasmExecutionMethod) { Error::Runtime => { assert_matches!(wasm_method, WasmExecutionMethod::Interpreted); }, - Error::RuntimeConstruction(WasmError::Other(error)) => { + Error::OutputExceedsBounds => { assert_matches!(wasm_method, WasmExecutionMethod::Compiled { .. }); - assert_eq!(error, "output exceeds bounds of wasm memory"); }, error => panic!("unexpected error: {:?}", error), } @@ -866,9 +864,8 @@ fn return_overflow(wasm_method: WasmExecutionMethod) { Error::Runtime => { assert_matches!(wasm_method, WasmExecutionMethod::Interpreted); }, - Error::RuntimeConstruction(WasmError::Other(error)) => { + Error::OutputExceedsBounds => { assert_matches!(wasm_method, WasmExecutionMethod::Compiled { .. }); - assert_eq!(error, "output exceeds bounds of wasm memory"); }, error => panic!("unexpected error: {:?}", error), } diff --git a/client/executor/wasmtime/src/runtime.rs b/client/executor/wasmtime/src/runtime.rs index e01a51f6cf2a7..c9a2c83e0493c 100644 --- a/client/executor/wasmtime/src/runtime.rs +++ b/client/executor/wasmtime/src/runtime.rs @@ -26,7 +26,7 @@ use crate::{ use sc_allocator::{AllocationStats, FreeingBumpHeapAllocator}; use sc_executor_common::{ - error::{Result, WasmError}, + error::{Error, Result, WasmError}, runtime_blob::{ self, DataSegmentsSnapshot, ExposedMutableGlobalsSet, GlobalsSnapshot, RuntimeBlob, }, @@ -776,7 +776,7 @@ fn extract_output_data( // Get the size of the WASM memory in bytes. let memory_size = ctx.as_context().data().memory().data_size(ctx); if checked_range(output_ptr as usize, output_len as usize, memory_size).is_none() { - Err(WasmError::Other("output exceeds bounds of wasm memory".into()))? + Err(Error::OutputExceedsBounds)? } let mut output = vec![0; output_len as usize]; From 82e824bc0d21c63943b06d753e53a1e17e5a23c3 Mon Sep 17 00:00:00 2001 From: Sergej Sakac <73715684+Szegoo@users.noreply.github.com> Date: Sat, 8 Apr 2023 20:20:13 +0300 Subject: [PATCH 627/715] Warn if pallet provided to try-state does not exist (#13858) * Warn if pallet does not exist in try-state * unwrap_or_default --- frame/support/src/traits/try_runtime.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/frame/support/src/traits/try_runtime.rs b/frame/support/src/traits/try_runtime.rs index 6103f07a73c78..bebc248721c99 100644 --- a/frame/support/src/traits/try_runtime.rs +++ b/frame/support/src/traits/try_runtime.rs @@ -168,11 +168,19 @@ impl TryState::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()) { + pallet_names.iter().for_each(|pallet_name| { + if let Some((name, try_state_fn)) = + try_state_fns.iter().find(|(name, _)| name.as_bytes() == pallet_name) + { result = result.and(try_state_fn(n.clone(), targets.clone())); + } else { + crate::log::warn!( + "Pallet {:?} not found", + sp_std::str::from_utf8(pallet_name).unwrap_or_default() + ); } - } + }); + result }, } From 2e94e253950457571e91a5df1e60f82ba7b841dd Mon Sep 17 00:00:00 2001 From: yjh Date: Mon, 10 Apr 2023 07:48:40 +0800 Subject: [PATCH 628/715] refactor(sc-executor): use wasm executor builder instead of old apis (#13740) * refactor: use builder api for all executors * improve a lot * remove unused args * cleanup deps * fix inconsistency about heap alloc * add `heap_pages` back to try-runtime * fix * chore: reduce duplicated code for sc-service-test * cleanup code * fmt * improve test executor * improve * use #[deprecated] * set runtime_cache_size: 4 * fix and improve * refactor builder * fix * fix bench * fix tests * fix warnings * fix warnings * fix * fix * update by suggestions * update name --- bin/node-template/node/src/service.rs | 7 +-- bin/node/cli/benches/transaction_pool.rs | 4 +- bin/node/cli/src/service.rs | 7 +-- bin/node/executor/benches/bench.rs | 11 ++-- bin/node/executor/tests/common.rs | 4 +- bin/node/inspect/src/command.rs | 25 ++++----- bin/node/testing/src/bench.rs | 14 ++--- client/executor/benches/bench.rs | 7 ++- client/executor/common/src/wasm_runtime.rs | 7 +++ .../src/{native_executor.rs => executor.rs} | 51 +++++++++++-------- .../executor/src/integration_tests/linux.rs | 4 +- client/executor/src/integration_tests/mod.rs | 34 ++++++------- client/executor/src/lib.rs | 25 +++++---- client/executor/src/wasm_runtime.rs | 2 +- client/executor/wasmtime/src/tests.rs | 6 +-- client/service/src/builder.rs | 35 ++++++++++--- client/service/src/client/call_executor.rs | 25 +++++---- client/service/src/client/wasm_override.rs | 28 +++++----- client/service/src/lib.rs | 6 +-- client/service/test/src/client/mod.rs | 38 +++----------- client/service/test/src/lib.rs | 8 ++- frame/system/src/tests.rs | 4 +- primitives/api/test/tests/runtime_calls.rs | 8 ++- primitives/runtime-interface/test/src/lib.rs | 3 +- test-utils/client/src/lib.rs | 4 +- test-utils/runtime/client/src/lib.rs | 7 +-- test-utils/runtime/src/system.rs | 4 +- .../benchmarking-cli/src/pallet/command.rs | 17 ++++--- utils/frame/try-runtime/cli/src/lib.rs | 28 +++++----- 29 files changed, 213 insertions(+), 210 deletions(-) rename client/executor/src/{native_executor.rs => executor.rs} (94%) diff --git a/bin/node-template/node/src/service.rs b/bin/node-template/node/src/service.rs index dfbb5e96354e4..723d1db3eea37 100644 --- a/bin/node-template/node/src/service.rs +++ b/bin/node-template/node/src/service.rs @@ -68,12 +68,7 @@ pub fn new_partial( }) .transpose()?; - let executor = NativeElseWasmExecutor::::new( - config.wasm_method, - config.default_heap_pages, - config.max_runtime_instances, - config.runtime_cache_size, - ); + let executor = sc_service::new_native_or_wasm_executor(&config); let (client, backend, keystore_container, task_manager) = sc_service::new_full_parts::( diff --git a/bin/node/cli/benches/transaction_pool.rs b/bin/node/cli/benches/transaction_pool.rs index 7488ec03363e7..abee9c846245f 100644 --- a/bin/node/cli/benches/transaction_pool.rs +++ b/bin/node/cli/benches/transaction_pool.rs @@ -27,7 +27,7 @@ use sc_client_api::execution_extensions::ExecutionStrategies; use sc_service::{ config::{ BlocksPruning, DatabaseSource, KeystoreConfig, NetworkConfiguration, OffchainWorkerConfig, - PruningMode, TransactionPoolOptions, WasmExecutionMethod, + PruningMode, TransactionPoolOptions, }, BasePath, Configuration, Role, }; @@ -69,7 +69,7 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase { state_pruning: Some(PruningMode::ArchiveAll), blocks_pruning: BlocksPruning::KeepAll, chain_spec: spec, - wasm_method: WasmExecutionMethod::Interpreted, + wasm_method: Default::default(), // NOTE: we enforce the use of the native runtime to make the errors more debuggable execution_strategies: ExecutionStrategies { syncing: sc_client_api::ExecutionStrategy::NativeWhenPossible, diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs index ca6830085b055..7b0dfcda6ff0e 100644 --- a/bin/node/cli/src/service.rs +++ b/bin/node/cli/src/service.rs @@ -163,12 +163,7 @@ pub fn new_partial( }) .transpose()?; - let executor = NativeElseWasmExecutor::::new( - config.wasm_method, - config.default_heap_pages, - config.max_runtime_instances, - config.runtime_cache_size, - ); + let executor = sc_service::new_native_or_wasm_executor(&config); let (client, backend, keystore_container, task_manager) = sc_service::new_full_parts::( diff --git a/bin/node/executor/benches/bench.rs b/bin/node/executor/benches/bench.rs index a8c31068e853b..aa7d9eb0f31ff 100644 --- a/bin/node/executor/benches/bench.rs +++ b/bin/node/executor/benches/bench.rs @@ -26,7 +26,7 @@ use node_executor::ExecutorDispatch; use node_primitives::{BlockNumber, Hash}; use node_testing::keyring::*; use sc_executor::{ - Externalities, NativeElseWasmExecutor, RuntimeVersionOf, WasmExecutionMethod, + Externalities, NativeElseWasmExecutor, RuntimeVersionOf, WasmExecutionMethod, WasmExecutor, WasmtimeInstantiationStrategy, }; use sp_core::{ @@ -191,12 +191,13 @@ fn bench_execute_block(c: &mut Criterion) { for strategy in execution_methods { group.bench_function(format!("{:?}", strategy), |b| { let genesis_config = node_testing::genesis::config(Some(compact_code_unwrap())); - let (use_native, wasm_method) = match strategy { - ExecutionMethod::Native => (true, WasmExecutionMethod::Interpreted), - ExecutionMethod::Wasm(wasm_method) => (false, wasm_method), + let use_native = match strategy { + ExecutionMethod::Native => true, + ExecutionMethod::Wasm(..) => false, }; - let executor = NativeElseWasmExecutor::new(wasm_method, None, 8, 2); + let executor = + NativeElseWasmExecutor::new_with_wasm_executor(WasmExecutor::builder().build()); let runtime_code = RuntimeCode { code_fetcher: &sp_core::traits::WrappedRuntimeCode(compact_code_unwrap().into()), hash: vec![1, 2, 3], diff --git a/bin/node/executor/tests/common.rs b/bin/node/executor/tests/common.rs index 2f92423ffb508..6ce9ea3a01090 100644 --- a/bin/node/executor/tests/common.rs +++ b/bin/node/executor/tests/common.rs @@ -18,7 +18,7 @@ use codec::{Decode, Encode}; use frame_support::Hashable; use frame_system::offchain::AppCrypto; -use sc_executor::{error::Result, NativeElseWasmExecutor, WasmExecutionMethod}; +use sc_executor::{error::Result, NativeElseWasmExecutor, WasmExecutor}; use sp_consensus_babe::{ digests::{PreDigest, SecondaryPlainPreDigest}, Slot, BABE_ENGINE_ID, @@ -98,7 +98,7 @@ pub fn from_block_number(n: u32) -> Header { } pub fn executor() -> NativeElseWasmExecutor { - NativeElseWasmExecutor::new(WasmExecutionMethod::Interpreted, None, 8, 2) + NativeElseWasmExecutor::new_with_wasm_executor(WasmExecutor::builder().build()) } pub fn executor_call( diff --git a/bin/node/inspect/src/command.rs b/bin/node/inspect/src/command.rs index 3dca979eb9e4a..9702576833ccf 100644 --- a/bin/node/inspect/src/command.rs +++ b/bin/node/inspect/src/command.rs @@ -23,41 +23,34 @@ use crate::{ Inspector, }; use sc_cli::{CliConfiguration, ImportParams, Result, SharedParams}; -use sc_executor::NativeElseWasmExecutor; -use sc_service::{new_full_client, Configuration, NativeExecutionDispatch}; +use sc_service::{Configuration, NativeExecutionDispatch}; use sp_runtime::traits::Block; use std::str::FromStr; impl InspectCmd { /// Run the inspect command, passing the inspector. - pub fn run(&self, config: Configuration) -> Result<()> + pub fn run(&self, config: Configuration) -> Result<()> where B: Block, B::Hash: FromStr, RA: Send + Sync + 'static, - EX: NativeExecutionDispatch + 'static, + D: NativeExecutionDispatch + 'static, { - let executor = NativeElseWasmExecutor::::new( - config.wasm_method, - config.default_heap_pages, - config.max_runtime_instances, - config.runtime_cache_size, - ); - - let client = new_full_client::(&config, None, executor)?; + let executor = sc_service::new_native_or_wasm_executor::(&config); + let client = sc_service::new_full_client::(&config, None, executor)?; let inspect = Inspector::::new(client); match &self.command { InspectSubCmd::Block { input } => { let input = input.parse()?; - let res = inspect.block(input).map_err(|e| format!("{}", e))?; - println!("{}", res); + let res = inspect.block(input).map_err(|e| e.to_string())?; + println!("{res}"); Ok(()) }, InspectSubCmd::Extrinsic { input } => { let input = input.parse()?; - let res = inspect.extrinsic(input).map_err(|e| format!("{}", e))?; - println!("{}", res); + let res = inspect.extrinsic(input).map_err(|e| e.to_string())?; + println!("{res}"); Ok(()) }, } diff --git a/bin/node/testing/src/bench.rs b/bin/node/testing/src/bench.rs index 392b78241d288..9dbb26a906e6f 100644 --- a/bin/node/testing/src/bench.rs +++ b/bin/node/testing/src/bench.rs @@ -392,14 +392,14 @@ impl BenchDb { let task_executor = TaskExecutor::new(); let backend = sc_service::new_db_backend(db_config).expect("Should not fail"); - let executor = NativeElseWasmExecutor::new( - WasmExecutionMethod::Compiled { - instantiation_strategy: WasmtimeInstantiationStrategy::PoolingCopyOnWrite, - }, - None, - 8, - 2, + let executor = NativeElseWasmExecutor::new_with_wasm_executor( + sc_executor::WasmExecutor::builder() + .with_execution_method(WasmExecutionMethod::Compiled { + instantiation_strategy: WasmtimeInstantiationStrategy::PoolingCopyOnWrite, + }) + .build(), ); + let client_config = sc_service::ClientConfig::default(); let genesis_block_builder = sc_service::GenesisBlockBuilder::new( &keyring.generate_genesis(), diff --git a/client/executor/benches/bench.rs b/client/executor/benches/bench.rs index f129ebf64de12..e293329e75104 100644 --- a/client/executor/benches/bench.rs +++ b/client/executor/benches/bench.rs @@ -21,7 +21,7 @@ use codec::Encode; use sc_executor_common::{ runtime_blob::RuntimeBlob, - wasm_runtime::{HeapAllocStrategy, WasmInstance, WasmModule}, + wasm_runtime::{HeapAllocStrategy, WasmInstance, WasmModule, DEFAULT_HEAP_ALLOC_STRATEGY}, }; use sc_executor_wasmtime::InstantiationStrategy; use sc_runtime_test::wasm_binary_unwrap as test_runtime; @@ -51,13 +51,12 @@ fn initialize( ) -> Arc { let blob = RuntimeBlob::uncompress_if_needed(runtime).unwrap(); let host_functions = sp_io::SubstrateHostFunctions::host_functions(); - let extra_pages = 2048; let allow_missing_func_imports = true; match method { Method::Interpreted => sc_executor_wasmi::create_runtime( blob, - HeapAllocStrategy::Static { extra_pages }, + DEFAULT_HEAP_ALLOC_STRATEGY, host_functions, allow_missing_func_imports, ) @@ -67,7 +66,7 @@ fn initialize( allow_missing_func_imports, cache_path: None, semantics: sc_executor_wasmtime::Semantics { - heap_alloc_strategy: HeapAllocStrategy::Static { extra_pages }, + heap_alloc_strategy: DEFAULT_HEAP_ALLOC_STRATEGY, instantiation_strategy, deterministic_stack_limit: None, canonicalize_nans: false, diff --git a/client/executor/common/src/wasm_runtime.rs b/client/executor/common/src/wasm_runtime.rs index e3db7e52fc7e7..5dac77e59fa74 100644 --- a/client/executor/common/src/wasm_runtime.rs +++ b/client/executor/common/src/wasm_runtime.rs @@ -23,6 +23,13 @@ use sp_wasm_interface::Value; pub use sc_allocator::AllocationStats; +/// Default heap allocation strategy. +pub const DEFAULT_HEAP_ALLOC_STRATEGY: HeapAllocStrategy = + HeapAllocStrategy::Static { extra_pages: DEFAULT_HEAP_ALLOC_PAGES }; + +/// Default heap allocation pages. +pub const DEFAULT_HEAP_ALLOC_PAGES: u32 = 2048; + /// 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. diff --git a/client/executor/src/native_executor.rs b/client/executor/src/executor.rs similarity index 94% rename from client/executor/src/native_executor.rs rename to client/executor/src/executor.rs index c72cf3c9c91df..79250ee0d621c 100644 --- a/client/executor/src/native_executor.rs +++ b/client/executor/src/executor.rs @@ -32,16 +32,14 @@ use std::{ use codec::Encode; use sc_executor_common::{ runtime_blob::RuntimeBlob, - wasm_runtime::{AllocationStats, HeapAllocStrategy, WasmInstance, WasmModule}, + wasm_runtime::{ + AllocationStats, HeapAllocStrategy, WasmInstance, WasmModule, DEFAULT_HEAP_ALLOC_STRATEGY, + }, }; use sp_core::traits::{CallContext, CodeExecutor, Externalities, RuntimeCode}; use sp_version::{GetNativeVersion, NativeVersion, RuntimeVersion}; use sp_wasm_interface::{ExtendedHostFunctions, HostFunctions}; -/// Default heap allocation strategy. -const DEFAULT_HEAP_ALLOC_STRATEGY: HeapAllocStrategy = - HeapAllocStrategy::Static { extra_pages: 2048 }; - /// Set up the externalities and safe calling environment to execute runtime calls. /// /// If the inner closure panics, it will be caught and return an error. @@ -100,10 +98,10 @@ impl WasmExecutorBuilder { /// Create a new instance of `Self` /// /// - `method`: The wasm execution method that should be used by the executor. - pub fn new(method: WasmExecutionMethod) -> Self { + pub fn new() -> Self { Self { _phantom: PhantomData, - method, + method: WasmExecutionMethod::default(), onchain_heap_alloc_strategy: None, offchain_heap_alloc_strategy: None, max_runtime_instances: 2, @@ -113,6 +111,12 @@ impl WasmExecutorBuilder { } } + /// Create the wasm executor with execution method that should be used by the executor. + pub fn with_execution_method(mut self, method: WasmExecutionMethod) -> Self { + self.method = method; + self + } + /// Create the wasm executor with the given number of `heap_alloc_strategy` for onchain runtime /// calls. pub fn with_onchain_heap_alloc_strategy( @@ -256,6 +260,7 @@ where /// compiled execution method is used. /// /// `runtime_cache_size` - The capacity of runtime cache. + #[deprecated(note = "use `Self::builder` method instead of it")] pub fn new( method: WasmExecutionMethod, default_heap_pages: Option, @@ -283,11 +288,12 @@ where } /// Instantiate a builder for creating an instance of `Self`. - pub fn builder(method: WasmExecutionMethod) -> WasmExecutorBuilder { - WasmExecutorBuilder::new(method) + pub fn builder() -> WasmExecutorBuilder { + WasmExecutorBuilder::new() } /// Ignore missing function imports if set true. + #[deprecated(note = "use `Self::builder` method instead of it")] pub fn allow_missing_host_functions(&mut self, allow_missing_host_functions: bool) { self.allow_missing_host_functions = allow_missing_host_functions } @@ -539,6 +545,7 @@ pub struct NativeElseWasmExecutor { } impl NativeElseWasmExecutor { + /// /// Create new instance. /// /// # Parameters @@ -553,19 +560,23 @@ impl NativeElseWasmExecutor { /// `max_runtime_instances` - The number of runtime instances to keep in memory ready for reuse. /// /// `runtime_cache_size` - The capacity of runtime cache. + #[deprecated(note = "use `Self::new_with_wasm_executor` method instead of it")] pub fn new( fallback_method: WasmExecutionMethod, default_heap_pages: Option, max_runtime_instances: usize, runtime_cache_size: u8, ) -> Self { - let wasm = WasmExecutor::new( - fallback_method, - default_heap_pages, - max_runtime_instances, - None, - runtime_cache_size, - ); + let heap_pages = default_heap_pages.map_or(DEFAULT_HEAP_ALLOC_STRATEGY, |h| { + HeapAllocStrategy::Static { extra_pages: h as _ } + }); + let wasm = WasmExecutor::builder() + .with_execution_method(fallback_method) + .with_onchain_heap_alloc_strategy(heap_pages) + .with_offchain_heap_alloc_strategy(heap_pages) + .with_max_runtime_instances(max_runtime_instances) + .with_runtime_cache_size(runtime_cache_size) + .build(); NativeElseWasmExecutor { native_version: D::native_version(), wasm } } @@ -580,6 +591,7 @@ impl NativeElseWasmExecutor { } /// Ignore missing function imports if set true. + #[deprecated(note = "use `Self::new_with_wasm_executor` method instead of it")] pub fn allow_missing_host_functions(&mut self, allow_missing_host_functions: bool) { self.wasm.allow_missing_host_functions = allow_missing_host_functions } @@ -714,11 +726,8 @@ mod tests { #[test] fn native_executor_registers_custom_interface() { - let executor = NativeElseWasmExecutor::::new( - WasmExecutionMethod::Interpreted, - None, - 8, - 2, + let executor = NativeElseWasmExecutor::::new_with_wasm_executor( + WasmExecutor::builder().build(), ); fn extract_host_functions( diff --git a/client/executor/src/integration_tests/linux.rs b/client/executor/src/integration_tests/linux.rs index 38d75da4eb7e8..434cb69bfdd32 100644 --- a/client/executor/src/integration_tests/linux.rs +++ b/client/executor/src/integration_tests/linux.rs @@ -21,7 +21,7 @@ use super::mk_test_runtime; use crate::WasmExecutionMethod; use codec::Encode as _; -use sc_executor_common::wasm_runtime::HeapAllocStrategy; +use sc_executor_common::wasm_runtime::DEFAULT_HEAP_ALLOC_STRATEGY; mod smaps; @@ -74,7 +74,7 @@ fn memory_consumption(wasm_method: WasmExecutionMethod) { // For that we make a series of runtime calls, probing the RSS for the VMA matching the linear // memory. After the call we expect RSS to be equal to 0. - let runtime = mk_test_runtime(wasm_method, HeapAllocStrategy::Static { extra_pages: 1024 }); + let runtime = mk_test_runtime(wasm_method, DEFAULT_HEAP_ALLOC_STRATEGY); let mut instance = runtime.new_instance().unwrap(); let heap_base = instance diff --git a/client/executor/src/integration_tests/mod.rs b/client/executor/src/integration_tests/mod.rs index 0148968f98a38..63a642f990642 100644 --- a/client/executor/src/integration_tests/mod.rs +++ b/client/executor/src/integration_tests/mod.rs @@ -24,7 +24,7 @@ use codec::{Decode, Encode}; use sc_executor_common::{ error::Error, runtime_blob::RuntimeBlob, - wasm_runtime::{HeapAllocStrategy, WasmModule}, + wasm_runtime::{HeapAllocStrategy, WasmModule, DEFAULT_HEAP_ALLOC_STRATEGY}, }; use sc_runtime_test::wasm_binary_unwrap; use sp_core::{ @@ -114,8 +114,10 @@ fn call_in_wasm( execution_method: WasmExecutionMethod, ext: &mut E, ) -> Result, Error> { - let executor = - crate::WasmExecutor::::new(execution_method, Some(1024), 8, None, 2); + let executor = crate::WasmExecutor::::builder() + .with_execution_method(execution_method) + .build(); + executor.uncached_call( RuntimeBlob::uncompress_if_needed(wasm_binary_unwrap()).unwrap(), ext, @@ -446,13 +448,11 @@ 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( - wasm_method, - Some(17), // `17` is the initial number of pages compiled into the binary. - 8, - None, - 2, - ); + let executor = crate::WasmExecutor::::builder() + .with_execution_method(wasm_method) + // `17` is the initial number of pages compiled into the binary. + .with_onchain_heap_alloc_strategy(HeapAllocStrategy::Static { extra_pages: 17 }) + .build(); let err = executor .uncached_call( @@ -560,7 +560,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, HeapAllocStrategy::Static { extra_pages: 1024 }); + let runtime = mk_test_runtime(wasm_method, DEFAULT_HEAP_ALLOC_STRATEGY); let mut instance = runtime.new_instance().unwrap(); let heap_base = instance @@ -579,13 +579,11 @@ 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( - wasm_method, - Some(1024), - 8, - None, - 2, - )); + let executor = Arc::new( + crate::WasmExecutor::::builder() + .with_execution_method(wasm_method) + .build(), + ); let threads: Vec<_> = (0..8) .map(|_| { let executor = executor.clone(); diff --git a/client/executor/src/lib.rs b/client/executor/src/lib.rs index e5bae474e9e25..42e7dc7d16bd8 100644 --- a/client/executor/src/lib.rs +++ b/client/executor/src/lib.rs @@ -32,24 +32,29 @@ #![recursion_limit = "128"] #[macro_use] -mod native_executor; +mod executor; #[cfg(test)] mod integration_tests; mod wasm_runtime; -pub use codec::Codec; -pub use native_executor::{ - with_externalities_safe, NativeElseWasmExecutor, NativeExecutionDispatch, WasmExecutor, +pub use self::{ + executor::{ + with_externalities_safe, NativeElseWasmExecutor, NativeExecutionDispatch, WasmExecutor, + }, + wasm_runtime::{read_embedded_version, WasmExecutionMethod}, }; +pub use codec::Codec; #[doc(hidden)] pub use sp_core::traits::Externalities; pub use sp_version::{NativeVersion, RuntimeVersion}; #[doc(hidden)] pub use sp_wasm_interface; -pub use wasm_runtime::{read_embedded_version, WasmExecutionMethod}; pub use wasmi; -pub use sc_executor_common::error; +pub use sc_executor_common::{ + error, + wasm_runtime::{HeapAllocStrategy, DEFAULT_HEAP_ALLOC_PAGES, DEFAULT_HEAP_ALLOC_STRATEGY}, +}; pub use sc_executor_wasmtime::InstantiationStrategy as WasmtimeInstantiationStrategy; /// Extracts the runtime version of a given runtime code. @@ -74,13 +79,7 @@ mod tests { let mut ext = TestExternalities::default(); let mut ext = ext.ext(); - let executor = WasmExecutor::::new( - WasmExecutionMethod::Interpreted, - Some(8), - 8, - None, - 2, - ); + let executor = WasmExecutor::::builder().build(); let res = executor .uncached_call( RuntimeBlob::uncompress_if_needed(wasm_binary_unwrap()).unwrap(), diff --git a/client/executor/src/wasm_runtime.rs b/client/executor/src/wasm_runtime.rs index fb3dd0f38006c..351b6f377b8af 100644 --- a/client/executor/src/wasm_runtime.rs +++ b/client/executor/src/wasm_runtime.rs @@ -434,7 +434,7 @@ where // The following unwind safety assertion is OK because if the method call panics, the // runtime will be dropped. let runtime = AssertUnwindSafe(runtime.as_ref()); - crate::native_executor::with_externalities_safe(&mut **ext, move || { + crate::executor::with_externalities_safe(&mut **ext, move || { runtime.new_instance()?.call("Core_version".into(), &[]) }) .map_err(|_| WasmError::Instantiation("panic in call to get runtime version".into()))? diff --git a/client/executor/wasmtime/src/tests.rs b/client/executor/wasmtime/src/tests.rs index 0ca6095165572..e8d7c5ab1afac 100644 --- a/client/executor/wasmtime/src/tests.rs +++ b/client/executor/wasmtime/src/tests.rs @@ -20,7 +20,7 @@ use codec::{Decode as _, Encode as _}; use sc_executor_common::{ error::Error, runtime_blob::RuntimeBlob, - wasm_runtime::{HeapAllocStrategy, WasmModule}, + wasm_runtime::{HeapAllocStrategy, WasmModule, DEFAULT_HEAP_ALLOC_STRATEGY}, }; use sc_runtime_test::wasm_binary_unwrap; @@ -93,7 +93,7 @@ impl RuntimeBuilder { instantiation_strategy, canonicalize_nans: false, deterministic_stack: false, - heap_pages: HeapAllocStrategy::Static { extra_pages: 1024 }, + heap_pages: DEFAULT_HEAP_ALLOC_STRATEGY, precompile_runtime: false, tmpdir: None, } @@ -477,7 +477,7 @@ fn test_instances_without_reuse_are_not_leaked() { deterministic_stack_limit: None, canonicalize_nans: false, parallel_compilation: true, - heap_alloc_strategy: HeapAllocStrategy::Static { extra_pages: 2048 }, + heap_alloc_strategy: DEFAULT_HEAP_ALLOC_STRATEGY, wasm_multi_value: false, wasm_bulk_memory: false, wasm_reference_types: false, diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index d399b315414f8..415fa03a10020 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -36,7 +36,10 @@ use sc_client_api::{ }; use sc_client_db::{Backend, DatabaseSettings}; use sc_consensus::import_queue::ImportQueue; -use sc_executor::RuntimeVersionOf; +use sc_executor::{ + sp_wasm_interface::HostFunctions, HeapAllocStrategy, NativeElseWasmExecutor, + NativeExecutionDispatch, RuntimeVersionOf, WasmExecutor, DEFAULT_HEAP_ALLOC_STRATEGY, +}; use sc_keystore::LocalKeystore; use sc_network::{config::SyncMode, NetworkService, NetworkStateInfo, NetworkStatusProvider}; use sc_network_bitswap::BitswapRequestHandler; @@ -74,11 +77,10 @@ pub type TFullClient = Client, TFullCallExecutor, TBl, TRtApi>; /// Full client backend type. -pub type TFullBackend = sc_client_db::Backend; +pub type TFullBackend = Backend; /// Full client call executor type. -pub type TFullCallExecutor = - crate::client::LocalCallExecutor, TExec>; +pub type TFullCallExecutor = crate::client::LocalCallExecutor, TExec>; type TFullParts = (TFullClient, Arc>, KeystoreContainer, TaskManager); @@ -229,6 +231,27 @@ where Ok((client, backend, keystore_container, task_manager)) } +/// Creates a [`NativeElseWasmExecutor`] according to [`Configuration`]. +pub fn new_native_or_wasm_executor( + config: &Configuration, +) -> NativeElseWasmExecutor { + NativeElseWasmExecutor::new_with_wasm_executor(new_wasm_executor(config)) +} + +/// Creates a [`WasmExecutor`] according to [`Configuration`]. +pub fn new_wasm_executor(config: &Configuration) -> WasmExecutor { + let strategy = config + .default_heap_pages + .map_or(DEFAULT_HEAP_ALLOC_STRATEGY, |p| HeapAllocStrategy::Static { extra_pages: p as _ }); + WasmExecutor::::builder() + .with_execution_method(config.wasm_method) + .with_onchain_heap_alloc_strategy(strategy) + .with_offchain_heap_alloc_strategy(strategy) + .with_max_runtime_instances(config.max_runtime_instances) + .with_runtime_cache_size(config.runtime_cache_size) + .build() +} + /// Create an instance of default DB-backend backend. pub fn new_db_backend( settings: DatabaseSettings, @@ -254,7 +277,7 @@ pub fn new_client( telemetry: Option, config: ClientConfig, ) -> Result< - crate::client::Client< + Client< Backend, crate::client::LocalCallExecutor, E>, Block, @@ -277,7 +300,7 @@ where execution_extensions, )?; - crate::client::Client::new( + Client::new( backend, executor, spawn_handle, diff --git a/client/service/src/client/call_executor.rs b/client/service/src/client/call_executor.rs index ef36768febdbd..7979c139e2a6c 100644 --- a/client/service/src/client/call_executor.rs +++ b/client/service/src/client/call_executor.rs @@ -360,7 +360,7 @@ mod tests { use super::*; use backend::Backend; use sc_client_api::in_mem; - use sc_executor::{NativeElseWasmExecutor, WasmExecutionMethod}; + use sc_executor::{NativeElseWasmExecutor, WasmExecutor}; use sp_core::{ testing::TaskExecutor, traits::{FetchRuntimeCode, WrappedRuntimeCode}, @@ -368,14 +368,18 @@ mod tests { use std::collections::HashMap; use substrate_test_runtime_client::{runtime, GenesisInit, LocalExecutorDispatch}; + fn executor() -> NativeElseWasmExecutor { + NativeElseWasmExecutor::new_with_wasm_executor( + WasmExecutor::builder() + .with_max_runtime_instances(1) + .with_runtime_cache_size(2) + .build(), + ) + } + #[test] fn should_get_override_if_exists() { - let executor = NativeElseWasmExecutor::::new( - WasmExecutionMethod::Interpreted, - Some(128), - 1, - 2, - ); + let executor = executor(); let overrides = crate::client::wasm_override::dummy_overrides(); let onchain_code = WrappedRuntimeCode(substrate_test_runtime::wasm_binary_unwrap().into()); @@ -443,12 +447,7 @@ mod tests { fn returns_runtime_version_from_substitute() { const SUBSTITUTE_SPEC_NAME: &str = "substitute-spec-name-cool"; - let executor = NativeElseWasmExecutor::::new( - WasmExecutionMethod::Interpreted, - Some(128), - 1, - 2, - ); + let executor = executor(); let backend = Arc::new(in_mem::Backend::::new()); diff --git a/client/service/src/client/wasm_override.rs b/client/service/src/client/wasm_override.rs index 3a56e5c595829..725c8ab9429ac 100644 --- a/client/service/src/client/wasm_override.rs +++ b/client/service/src/client/wasm_override.rs @@ -264,21 +264,26 @@ pub fn dummy_overrides() -> WasmOverride { #[cfg(test)] mod tests { use super::*; - use sc_executor::{NativeElseWasmExecutor, WasmExecutionMethod}; + use sc_executor::{HeapAllocStrategy, NativeElseWasmExecutor, WasmExecutor}; use std::fs::{self, File}; use substrate_test_runtime_client::LocalExecutorDispatch; + fn executor() -> NativeElseWasmExecutor { + NativeElseWasmExecutor::::new_with_wasm_executor( + WasmExecutor::builder() + .with_onchain_heap_alloc_strategy(HeapAllocStrategy::Static {extra_pages: 128}) + .with_offchain_heap_alloc_strategy(HeapAllocStrategy::Static {extra_pages: 128}) + .with_max_runtime_instances(1) + .with_runtime_cache_size(2) + .build() + ) + } + fn wasm_test(fun: F) where F: Fn(&Path, &[u8], &NativeElseWasmExecutor), { - let exec = - NativeElseWasmExecutor::::new( - WasmExecutionMethod::Interpreted, - Some(128), - 1, - 2, - ); + let exec = executor(); let bytes = substrate_test_runtime::wasm_binary_unwrap(); let dir = tempfile::tempdir().expect("Create a temporary directory"); fun(dir.path(), bytes, &exec); @@ -287,12 +292,7 @@ mod tests { #[test] fn should_get_runtime_version() { - let executor = NativeElseWasmExecutor::::new( - WasmExecutionMethod::Interpreted, - Some(128), - 1, - 2, - ); + let executor = executor(); let version = WasmOverride::runtime_version( &executor, diff --git a/client/service/src/lib.rs b/client/service/src/lib.rs index 54f11ec25a02a..c0c7c537c64dc 100644 --- a/client/service/src/lib.rs +++ b/client/service/src/lib.rs @@ -56,9 +56,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_full_parts_with_genesis_builder, spawn_tasks, BuildNetworkParams, - KeystoreContainer, NetworkStarter, SpawnTasksParams, TFullBackend, TFullCallExecutor, - TFullClient, + new_full_parts, new_full_parts_with_genesis_builder, new_native_or_wasm_executor, + spawn_tasks, BuildNetworkParams, KeystoreContainer, NetworkStarter, SpawnTasksParams, + TFullBackend, TFullCallExecutor, TFullClient, }, client::{ClientConfig, LocalCallExecutor}, error::Error, diff --git a/client/service/test/src/client/mod.rs b/client/service/test/src/client/mod.rs index e6545abf1bc73..1b282a342d5e6 100644 --- a/client/service/test/src/client/mod.rs +++ b/client/service/test/src/client/mod.rs @@ -45,6 +45,7 @@ use sp_trie::{LayoutV0, TrieConfiguration}; use std::{collections::HashSet, sync::Arc}; use substrate_test_runtime::TestAPI; use substrate_test_runtime_client::{ + new_native_or_wasm_executor, prelude::*, runtime::{ genesismap::{insert_genesis_block, GenesisConfig}, @@ -58,29 +59,6 @@ mod db; const TEST_ENGINE_ID: ConsensusEngineId = *b"TEST"; -pub struct ExecutorDispatch; - -impl sc_executor::NativeExecutionDispatch for ExecutorDispatch { - type ExtendHostFunctions = (); - - fn dispatch(method: &str, data: &[u8]) -> Option> { - substrate_test_runtime_client::runtime::api::dispatch(method, data) - } - - fn native_version() -> sc_executor::NativeVersion { - substrate_test_runtime_client::runtime::native_version() - } -} - -fn executor() -> sc_executor::NativeElseWasmExecutor { - sc_executor::NativeElseWasmExecutor::new( - sc_executor::WasmExecutionMethod::Interpreted, - None, - 8, - 2, - ) -} - fn construct_block( backend: &InMemoryBackend, number: BlockNumber, @@ -108,7 +86,7 @@ fn construct_block( StateMachine::new( backend, &mut overlay, - &executor(), + &new_native_or_wasm_executor(), "Core_initialize_block", &header.encode(), Default::default(), @@ -122,7 +100,7 @@ fn construct_block( StateMachine::new( backend, &mut overlay, - &executor(), + &new_native_or_wasm_executor(), "BlockBuilder_apply_extrinsic", &tx.encode(), Default::default(), @@ -136,7 +114,7 @@ fn construct_block( let ret_data = StateMachine::new( backend, &mut overlay, - &executor(), + &new_native_or_wasm_executor(), "BlockBuilder_finalize_block", &[], Default::default(), @@ -208,7 +186,7 @@ fn construct_genesis_should_work_with_native() { let _ = StateMachine::new( &backend, &mut overlay, - &executor(), + &new_native_or_wasm_executor(), "Core_execute_block", &b1data, Default::default(), @@ -241,7 +219,7 @@ fn construct_genesis_should_work_with_wasm() { let _ = StateMachine::new( &backend, &mut overlay, - &executor(), + &new_native_or_wasm_executor(), "Core_execute_block", &b1data, Default::default(), @@ -274,7 +252,7 @@ fn construct_genesis_with_bad_transaction_should_panic() { let r = StateMachine::new( &backend, &mut overlay, - &executor(), + &new_native_or_wasm_executor(), "Core_execute_block", &b1data, Default::default(), @@ -1910,7 +1888,7 @@ fn cleans_up_closed_notification_sinks_on_block_import() { use substrate_test_runtime_client::GenesisInit; let backend = Arc::new(sc_client_api::in_mem::Backend::new()); - let executor = substrate_test_runtime_client::new_native_executor(); + let executor = new_native_or_wasm_executor(); let client_config = sc_service::ClientConfig::default(); let genesis_block_builder = sc_service::GenesisBlockBuilder::new( diff --git a/client/service/test/src/lib.rs b/client/service/test/src/lib.rs index 8a2e5050bd5d3..0f20376fe809e 100644 --- a/client/service/test/src/lib.rs +++ b/client/service/test/src/lib.rs @@ -65,9 +65,7 @@ impl Drop for TestNet { } } -pub trait TestNetNode: - Clone + Future> + Send + 'static -{ +pub trait TestNetNode: Clone + Future> + Send + 'static { type Block: BlockT; type Backend: Backend; type Executor: CallExecutor + Send + Sync; @@ -128,7 +126,7 @@ impl Clone impl Future for TestNetComponents { - type Output = Result<(), sc_service::Error>; + type Output = Result<(), Error>; fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll { Pin::new(&mut self.task_manager.lock().future()).poll(cx) @@ -248,7 +246,7 @@ fn node_config< state_pruning: Default::default(), blocks_pruning: BlocksPruning::KeepFinalized, chain_spec: Box::new((*spec).clone()), - wasm_method: sc_service::config::WasmExecutionMethod::Interpreted, + wasm_method: Default::default(), wasm_runtime_overrides: Default::default(), execution_strategies: Default::default(), rpc_http: None, diff --git a/frame/system/src/tests.rs b/frame/system/src/tests.rs index fc388800e13b4..19b8d6a487ab5 100644 --- a/frame/system/src/tests.rs +++ b/frame/system/src/tests.rs @@ -589,7 +589,7 @@ fn assert_runtime_updated_digest(num: usize) { #[test] fn set_code_with_real_wasm_blob() { - let executor = substrate_test_runtime_client::new_native_executor(); + let executor = substrate_test_runtime_client::new_native_or_wasm_executor(); let mut ext = new_test_ext(); ext.register_extension(sp_core::traits::ReadRuntimeVersionExt::new(executor)); ext.execute_with(|| { @@ -613,7 +613,7 @@ fn set_code_with_real_wasm_blob() { #[test] fn runtime_upgraded_with_set_storage() { - let executor = substrate_test_runtime_client::new_native_executor(); + let executor = substrate_test_runtime_client::new_native_or_wasm_executor(); let mut ext = new_test_ext(); ext.register_extension(sp_core::traits::ReadRuntimeVersionExt::new(executor)); ext.execute_with(|| { diff --git a/primitives/api/test/tests/runtime_calls.rs b/primitives/api/test/tests/runtime_calls.rs index b57793aad1253..956a6a25f1558 100644 --- a/primitives/api/test/tests/runtime_calls.rs +++ b/primitives/api/test/tests/runtime_calls.rs @@ -29,6 +29,7 @@ use substrate_test_runtime_client::{ use codec::Encode; use sc_block_builder::BlockBuilderProvider; use sp_consensus::SelectChain; +use substrate_test_runtime_client::sc_executor::WasmExecutor; fn calling_function_with_strat(strat: ExecutionStrategy) { let client = TestClientBuilder::new().set_execution_strategy(strat).build(); @@ -178,11 +179,8 @@ fn record_proof_works() { // Use the proof backend to execute `execute_block`. let mut overlay = Default::default(); - let executor = NativeElseWasmExecutor::::new( - WasmExecutionMethod::Interpreted, - None, - 8, - 2, + let executor = NativeElseWasmExecutor::::new_with_wasm_executor( + WasmExecutor::builder().build(), ); 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 269b62333bd26..e1be3b5d99d9b 100644 --- a/primitives/runtime-interface/test/src/lib.rs +++ b/primitives/runtime-interface/test/src/lib.rs @@ -42,7 +42,8 @@ fn call_wasm_method_with_result( let executor = sc_executor::WasmExecutor::< ExtendedHostFunctions, - >::new(sc_executor::WasmExecutionMethod::Interpreted, Some(8), 8, None, 2); + >::builder() + .build(); let (result, allocation_stats) = executor.uncached_call_with_allocation_stats( RuntimeBlob::uncompress_if_needed(binary).expect("Failed to parse binary"), diff --git a/test-utils/client/src/lib.rs b/test-utils/client/src/lib.rs index c4572061c48af..fc9ba1c9e0dd9 100644 --- a/test-utils/client/src/lib.rs +++ b/test-utils/client/src/lib.rs @@ -27,7 +27,7 @@ pub use sc_client_api::{ BadBlocks, ForkBlocks, }; pub use sc_client_db::{self, Backend, BlocksPruning}; -pub use sc_executor::{self, NativeElseWasmExecutor, WasmExecutionMethod}; +pub use sc_executor::{self, NativeElseWasmExecutor, WasmExecutionMethod, WasmExecutor}; pub use sc_service::{client, RpcHandlers}; pub use sp_consensus; pub use sp_keyring::{ @@ -286,7 +286,7 @@ impl Backend: sc_client_api::backend::Backend + 'static, { let executor = executor.into().unwrap_or_else(|| { - NativeElseWasmExecutor::new(WasmExecutionMethod::Interpreted, None, 8, 2) + NativeElseWasmExecutor::new_with_wasm_executor(WasmExecutor::builder().build()) }); 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 099aeab11f768..5e4b5d6a12dd9 100644 --- a/test-utils/runtime/client/src/lib.rs +++ b/test-utils/runtime/client/src/lib.rs @@ -38,6 +38,7 @@ use sp_core::{ Pair, }; use sp_runtime::traits::{Block as BlockT, Hash as HashT, Header as HeaderT}; +use substrate_test_client::sc_executor::WasmExecutor; use substrate_test_runtime::genesismap::{additional_storage_with_genesis, GenesisConfig}; /// A prelude to import in tests. @@ -171,7 +172,7 @@ pub type Client = client::Client< client::LocalCallExecutor< substrate_test_runtime::Block, B, - sc_executor::NativeElseWasmExecutor, + NativeElseWasmExecutor, >, substrate_test_runtime::Block, substrate_test_runtime::RuntimeApi, @@ -290,6 +291,6 @@ pub fn new() -> Client { } /// Create a new native executor. -pub fn new_native_executor() -> NativeElseWasmExecutor { - NativeElseWasmExecutor::new(sc_executor::WasmExecutionMethod::Interpreted, None, 8, 2) +pub fn new_native_or_wasm_executor() -> NativeElseWasmExecutor { + NativeElseWasmExecutor::new_with_wasm_executor(WasmExecutor::builder().build()) } diff --git a/test-utils/runtime/src/system.rs b/test-utils/runtime/src/system.rs index fc750531529b6..caabad336c069 100644 --- a/test-utils/runtime/src/system.rs +++ b/test-utils/runtime/src/system.rs @@ -376,7 +376,7 @@ mod tests { use super::*; use crate::{wasm_binary_unwrap, Header, Transfer}; - use sc_executor::{NativeElseWasmExecutor, WasmExecutionMethod}; + use sc_executor::{NativeElseWasmExecutor, WasmExecutor}; use sp_core::{ map, traits::{CallContext, CodeExecutor, RuntimeCode}, @@ -400,7 +400,7 @@ mod tests { } fn executor() -> NativeElseWasmExecutor { - NativeElseWasmExecutor::new(WasmExecutionMethod::Interpreted, None, 8, 2) + NativeElseWasmExecutor::new_with_wasm_executor(WasmExecutor::builder().build()) } fn new_test_ext() -> TestExternalities { diff --git a/utils/frame/benchmarking-cli/src/pallet/command.rs b/utils/frame/benchmarking-cli/src/pallet/command.rs index 4d583950d7b3e..0c3b6b3e8f45c 100644 --- a/utils/frame/benchmarking-cli/src/pallet/command.rs +++ b/utils/frame/benchmarking-cli/src/pallet/command.rs @@ -27,7 +27,7 @@ use sc_cli::{ execution_method_from_cli, CliConfiguration, ExecutionStrategy, Result, SharedParams, }; use sc_client_db::BenchmarkingState; -use sc_executor::NativeElseWasmExecutor; +use sc_executor::{NativeElseWasmExecutor, WasmExecutor}; use sc_service::{Configuration, NativeExecutionDispatch}; use serde::Serialize; use sp_core::{ @@ -209,11 +209,16 @@ impl PalletCmd { // Do not enable storage tracking false, )?; - let executor = NativeElseWasmExecutor::::new( - 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 + + let method = + execution_method_from_cli(self.wasm_method, self.wasmtime_instantiation_strategy); + + let executor = NativeElseWasmExecutor::::new_with_wasm_executor( + WasmExecutor::builder() + .with_execution_method(method) + .with_max_runtime_instances(2) + .with_runtime_cache_size(2) + .build(), ); let extensions = || -> Extensions { diff --git a/utils/frame/try-runtime/cli/src/lib.rs b/utils/frame/try-runtime/cli/src/lib.rs index db690e5086a6c..cd6c48f52f45e 100644 --- a/utils/frame/try-runtime/cli/src/lib.rs +++ b/utils/frame/try-runtime/cli/src/lib.rs @@ -368,7 +368,9 @@ use sc_cli::{ WasmtimeInstantiationStrategy, DEFAULT_WASMTIME_INSTANTIATION_STRATEGY, DEFAULT_WASM_EXECUTION_METHOD, }; -use sc_executor::{sp_wasm_interface::HostFunctions, WasmExecutor}; +use sc_executor::{ + sp_wasm_interface::HostFunctions, HeapAllocStrategy, WasmExecutor, DEFAULT_HEAP_ALLOC_STRATEGY, +}; use sp_api::HashT; use sp_core::{ hexdisplay::HexDisplay, @@ -824,18 +826,20 @@ pub(crate) fn full_extensions(wasm_executor: WasmExecutor) extensions } +/// Build wasm executor by default config. pub(crate) fn build_executor(shared: &SharedParams) -> WasmExecutor { - let heap_pages = shared.heap_pages.or(Some(2048)); - let max_runtime_instances = 8; - let runtime_cache_size = 2; - - WasmExecutor::new( - execution_method_from_cli(shared.wasm_method, shared.wasmtime_instantiation_strategy), - heap_pages, - max_runtime_instances, - None, - runtime_cache_size, - ) + let heap_pages = shared + .heap_pages + .map_or(DEFAULT_HEAP_ALLOC_STRATEGY, |p| HeapAllocStrategy::Static { extra_pages: p as _ }); + + WasmExecutor::builder() + .with_execution_method(execution_method_from_cli( + shared.wasm_method, + shared.wasmtime_instantiation_strategy, + )) + .with_onchain_heap_alloc_strategy(heap_pages) + .with_offchain_heap_alloc_strategy(heap_pages) + .build() } /// Ensure that the given `ext` is compiled with `try-runtime` From 7363dce0375fd628b6bcea6e41256a0561a4a73f Mon Sep 17 00:00:00 2001 From: Liam Aharon Date: Tue, 11 Apr 2023 07:25:12 +1000 Subject: [PATCH 629/715] remove unused import (#13868) --- client/executor/benches/bench.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/executor/benches/bench.rs b/client/executor/benches/bench.rs index e293329e75104..6cce05f6c75f4 100644 --- a/client/executor/benches/bench.rs +++ b/client/executor/benches/bench.rs @@ -21,7 +21,7 @@ use codec::Encode; use sc_executor_common::{ runtime_blob::RuntimeBlob, - wasm_runtime::{HeapAllocStrategy, WasmInstance, WasmModule, DEFAULT_HEAP_ALLOC_STRATEGY}, + wasm_runtime::{WasmInstance, WasmModule, DEFAULT_HEAP_ALLOC_STRATEGY}, }; use sc_executor_wasmtime::InstantiationStrategy; use sc_runtime_test::wasm_binary_unwrap as test_runtime; From 2b61b1d22d78694bdc83d2b6cb0b3b749a0e668a Mon Sep 17 00:00:00 2001 From: yjh Date: Tue, 11 Apr 2023 18:42:49 +0800 Subject: [PATCH 630/715] chore: remove duplicated arc (#13871) --- client/executor/benches/bench.rs | 6 +++--- client/executor/src/executor.rs | 2 +- client/executor/src/integration_tests/mod.rs | 2 +- client/executor/src/wasm_runtime.rs | 20 ++++++++++---------- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/client/executor/benches/bench.rs b/client/executor/benches/bench.rs index 6cce05f6c75f4..772898b8c76b3 100644 --- a/client/executor/benches/bench.rs +++ b/client/executor/benches/bench.rs @@ -48,7 +48,7 @@ fn initialize( _tmpdir: &mut Option, runtime: &[u8], method: Method, -) -> Arc { +) -> Box { let blob = RuntimeBlob::uncompress_if_needed(runtime).unwrap(); let host_functions = sp_io::SubstrateHostFunctions::host_functions(); let allow_missing_func_imports = true; @@ -60,7 +60,7 @@ fn initialize( host_functions, allow_missing_func_imports, ) - .map(|runtime| -> Arc { Arc::new(runtime) }), + .map(|runtime| -> Box { Box::new(runtime) }), Method::Compiled { instantiation_strategy, precompile } => { let config = sc_executor_wasmtime::Config { allow_missing_func_imports, @@ -98,7 +98,7 @@ fn initialize( } else { sc_executor_wasmtime::create_runtime::(blob, config) } - .map(|runtime| -> Arc { Arc::new(runtime) }) + .map(|runtime| -> Box { Box::new(runtime) }) }, } .unwrap() diff --git a/client/executor/src/executor.rs b/client/executor/src/executor.rs index 79250ee0d621c..a3717f4d29002 100644 --- a/client/executor/src/executor.rs +++ b/client/executor/src/executor.rs @@ -320,7 +320,7 @@ where ) -> Result where F: FnOnce( - AssertUnwindSafe<&Arc>, + AssertUnwindSafe<&dyn WasmModule>, AssertUnwindSafe<&mut dyn WasmInstance>, Option<&RuntimeVersion>, AssertUnwindSafe<&mut dyn Externalities>, diff --git a/client/executor/src/integration_tests/mod.rs b/client/executor/src/integration_tests/mod.rs index 63a642f990642..b65aeb8d01109 100644 --- a/client/executor/src/integration_tests/mod.rs +++ b/client/executor/src/integration_tests/mod.rs @@ -483,7 +483,7 @@ fn should_trap_when_heap_exhausted(wasm_method: WasmExecutionMethod) { fn mk_test_runtime( wasm_method: WasmExecutionMethod, pages: HeapAllocStrategy, -) -> Arc { +) -> Box { let blob = RuntimeBlob::uncompress_if_needed(wasm_binary_unwrap()) .expect("failed to create a runtime blob out of test runtime"); diff --git a/client/executor/src/wasm_runtime.rs b/client/executor/src/wasm_runtime.rs index 351b6f377b8af..41a095081f8d1 100644 --- a/client/executor/src/wasm_runtime.rs +++ b/client/executor/src/wasm_runtime.rs @@ -71,14 +71,14 @@ struct VersionedRuntimeId { /// A Wasm runtime object along with its cached runtime version. struct VersionedRuntime { /// Shared runtime that can spawn instances. - module: Arc, + module: Box, /// 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>>>>, + instances: Vec>>>, } impl VersionedRuntime { @@ -86,7 +86,7 @@ impl VersionedRuntime { fn with_instance(&self, ext: &mut dyn Externalities, f: F) -> Result where F: FnOnce( - &Arc, + &dyn WasmModule, &mut dyn WasmInstance, Option<&RuntimeVersion>, &mut dyn Externalities, @@ -106,7 +106,7 @@ impl VersionedRuntime { .map(|r| Ok((r, false))) .unwrap_or_else(|| self.module.new_instance().map(|i| (i, true)))?; - let result = f(&self.module, &mut *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 { tracing::warn!( @@ -142,7 +142,7 @@ impl VersionedRuntime { // Allocate a new instance let mut instance = self.module.new_instance()?; - f(&self.module, &mut *instance, self.version.as_ref(), ext) + f(&*self.module, &mut *instance, self.version.as_ref(), ext) }, } } @@ -228,7 +228,7 @@ impl RuntimeCache { where H: HostFunctions, F: FnOnce( - &Arc, + &dyn WasmModule, &mut dyn WasmInstance, Option<&RuntimeVersion>, &mut dyn Externalities, @@ -294,7 +294,7 @@ pub fn create_wasm_runtime_with_code( blob: RuntimeBlob, allow_missing_func_imports: bool, cache_path: Option<&Path>, -) -> Result, WasmError> +) -> Result, WasmError> where H: HostFunctions, { @@ -312,7 +312,7 @@ where H::host_functions(), allow_missing_func_imports, ) - .map(|runtime| -> Arc { Arc::new(runtime) }) + .map(|runtime| -> Box { Box::new(runtime) }) }, WasmExecutionMethod::Compiled { instantiation_strategy } => sc_executor_wasmtime::create_runtime::( @@ -333,7 +333,7 @@ where }, }, ) - .map(|runtime| -> Arc { Arc::new(runtime) }), + .map(|runtime| -> Box { Box::new(runtime) }), } } @@ -448,7 +448,7 @@ where let mut instances = Vec::with_capacity(max_instances); instances.resize_with(max_instances, || Mutex::new(None)); - Ok(VersionedRuntime { module: runtime, version, instances: Arc::new(instances) }) + Ok(VersionedRuntime { module: runtime, version, instances }) } #[cfg(test)] From 932f820625b37913f901c6d25c40fe542bbeb6b5 Mon Sep 17 00:00:00 2001 From: Mira Ressel Date: Tue, 11 Apr 2023 12:57:14 +0200 Subject: [PATCH 631/715] simplify some pattern matches to appease 1.68 clippy (#13833) --- .../grandpa/src/communication/mod.rs | 4 +-- client/network/common/src/sync.rs | 4 +-- .../src/protocol/notifications/behaviour.rs | 27 +++++++------------ client/network/sync/src/blocks.rs | 2 +- client/network/transactions/src/lib.rs | 2 +- client/service/test/src/lib.rs | 5 +--- .../election-provider-multi-phase/src/lib.rs | 8 +++--- frame/offences/src/lib.rs | 2 +- frame/session/src/lib.rs | 2 +- frame/staking/src/pallet/impls.rs | 4 +-- 10 files changed, 23 insertions(+), 37 deletions(-) diff --git a/client/consensus/grandpa/src/communication/mod.rs b/client/consensus/grandpa/src/communication/mod.rs index 81365c20b1ebe..9d90035d71cbb 100644 --- a/client/consensus/grandpa/src/communication/mod.rs +++ b/client/consensus/grandpa/src/communication/mod.rs @@ -852,9 +852,7 @@ fn check_compact_commit( // check signatures on all contained precommits. let mut buf = Vec::new(); - for (i, (precommit, &(ref sig, ref id))) in - msg.precommits.iter().zip(&msg.auth_data).enumerate() - { + for (i, (precommit, (sig, id))) in msg.precommits.iter().zip(&msg.auth_data).enumerate() { use crate::communication::gossip::Misbehavior; use finality_grandpa::Message as GrandpaMessage; diff --git a/client/network/common/src/sync.rs b/client/network/common/src/sync.rs index d02a81379aea0..b01091ae01641 100644 --- a/client/network/common/src/sync.rs +++ b/client/network/common/src/sync.rs @@ -424,9 +424,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<'a>( + fn poll_block_announce_validation( &mut self, - cx: &mut std::task::Context<'a>, + cx: &mut std::task::Context<'_>, ) -> Poll>; /// Call when a peer has disconnected. diff --git a/client/network/src/protocol/notifications/behaviour.rs b/client/network/src/protocol/notifications/behaviour.rs index 74e27fa17c602..9e93389389d29 100644 --- a/client/network/src/protocol/notifications/behaviour.rs +++ b/client/network/src/protocol/notifications/behaviour.rs @@ -2628,8 +2628,7 @@ mod tests { conn, NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, ); - if let Some(&PeerState::Incoming { ref connections, .. }) = notif.peers.get(&(peer, set_id)) - { + if let Some(PeerState::Incoming { connections, .. }) = notif.peers.get(&(peer, set_id)) { assert_eq!(connections.len(), 1); assert_eq!(connections[0], (conn, ConnectionState::OpenDesiredByRemote)); } else { @@ -2647,8 +2646,7 @@ mod tests { }, )); - if let Some(&PeerState::Incoming { ref connections, .. }) = notif.peers.get(&(peer, set_id)) - { + if let Some(PeerState::Incoming { connections, .. }) = notif.peers.get(&(peer, set_id)) { assert_eq!(connections.len(), 2); assert_eq!(connections[0], (conn, ConnectionState::OpenDesiredByRemote)); assert_eq!(connections[1], (conn2, ConnectionState::Closed)); @@ -2797,8 +2795,7 @@ mod tests { }, )); - if let Some(&PeerState::Disabled { ref connections, .. }) = notif.peers.get(&(peer, set_id)) - { + if let Some(PeerState::Disabled { connections, .. }) = notif.peers.get(&(peer, set_id)) { assert_eq!(connections.len(), 1); assert_eq!(connections[0], (conn1, ConnectionState::Closed)); } else { @@ -2884,8 +2881,7 @@ mod tests { )); } - if let Some(&PeerState::Disabled { ref connections, .. }) = notif.peers.get(&(peer, set_id)) - { + if let Some(PeerState::Disabled { connections, .. }) = notif.peers.get(&(peer, set_id)) { assert_eq!(connections[0], (conn1, ConnectionState::Closed)); assert_eq!(connections[1], (conn2, ConnectionState::Closed)); } else { @@ -2900,8 +2896,7 @@ mod tests { NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, ); - if let Some(&PeerState::Enabled { ref connections, .. }) = notif.peers.get(&(peer, set_id)) - { + if let Some(PeerState::Enabled { connections, .. }) = notif.peers.get(&(peer, set_id)) { assert_eq!(connections[0], (conn1, ConnectionState::Opening)); assert_eq!(connections[1], (conn2, ConnectionState::Opening)); } else { @@ -3297,8 +3292,7 @@ mod tests { )); } - if let Some(&PeerState::Disabled { ref connections, .. }) = notif.peers.get(&(peer, set_id)) - { + if let Some(PeerState::Disabled { connections, .. }) = notif.peers.get(&(peer, set_id)) { assert_eq!(connections[0], (conn1, ConnectionState::Closed)); assert_eq!(connections[1], (conn2, ConnectionState::Closed)); } else { @@ -3356,8 +3350,7 @@ mod tests { )); } - if let Some(&PeerState::Disabled { ref connections, .. }) = notif.peers.get(&(peer, set_id)) - { + if let Some(PeerState::Disabled { connections, .. }) = notif.peers.get(&(peer, set_id)) { assert_eq!(connections[0], (conn1, ConnectionState::Closed)); assert_eq!(connections[1], (conn2, ConnectionState::Closed)); } else { @@ -3413,8 +3406,7 @@ mod tests { )); } - if let Some(&PeerState::Disabled { ref connections, .. }) = notif.peers.get(&(peer, set_id)) - { + if let Some(PeerState::Disabled { connections, .. }) = notif.peers.get(&(peer, set_id)) { assert_eq!(connections[0], (conn1, ConnectionState::Closed)); assert_eq!(connections[1], (conn2, ConnectionState::Closed)); } else { @@ -3424,8 +3416,7 @@ mod tests { // open substreams on both active connections notif.peerset_report_connect(peer, set_id); - if let Some(&PeerState::Enabled { ref connections, .. }) = notif.peers.get(&(peer, set_id)) - { + if let Some(PeerState::Enabled { connections, .. }) = notif.peers.get(&(peer, set_id)) { assert_eq!(connections[0], (conn1, ConnectionState::Opening)); assert_eq!(connections[1], (conn2, ConnectionState::Closed)); } else { diff --git a/client/network/sync/src/blocks.rs b/client/network/sync/src/blocks.rs index 3c76238be1b5f..240c1ca1f8b26 100644 --- a/client/network/sync/src/blocks.rs +++ b/client/network/sync/src/blocks.rs @@ -89,7 +89,7 @@ impl BlockCollection { Some(&BlockRangeState::Downloading { .. }) => { trace!(target: "sync", "Inserting block data still marked as being downloaded: {}", start); }, - Some(&BlockRangeState::Complete(ref existing)) if existing.len() >= blocks.len() => { + Some(BlockRangeState::Complete(existing)) if existing.len() >= blocks.len() => { trace!(target: "sync", "Ignored block data already downloaded: {}", start); return }, diff --git a/client/network/transactions/src/lib.rs b/client/network/transactions/src/lib.rs index 381dd654b600b..f57556d3986b0 100644 --- a/client/network/transactions/src/lib.rs +++ b/client/network/transactions/src/lib.rs @@ -473,7 +473,7 @@ where let (hashes, to_send): (Vec<_>, Vec<_>) = transactions .iter() - .filter(|&(ref hash, _)| peer.known_transactions.insert(hash.clone())) + .filter(|(hash, _)| peer.known_transactions.insert(hash.clone())) .cloned() .unzip(); diff --git a/client/service/test/src/lib.rs b/client/service/test/src/lib.rs index 0f20376fe809e..29e68261a1025 100644 --- a/client/service/test/src/lib.rs +++ b/client/service/test/src/lib.rs @@ -182,10 +182,7 @@ where loop { interval.tick().await; - if full_nodes - .iter() - .all(|&(ref id, ref service, _, _)| full_predicate(*id, service)) - { + if full_nodes.iter().all(|(id, service, _, _)| full_predicate(*id, service)) { break } } diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index 80bab68074c87..3599037104d18 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -502,10 +502,10 @@ where fn eq(&self, other: &Self) -> bool { use ElectionError::*; match (self, other) { - (&Feasibility(ref x), &Feasibility(ref y)) if x == y => true, - (&Miner(ref x), &Miner(ref y)) if x == y => true, - (&DataProvider(ref x), &DataProvider(ref y)) if x == y => true, - (&Fallback(ref x), &Fallback(ref y)) if x == y => true, + (Feasibility(x), Feasibility(y)) if x == y => true, + (Miner(x), Miner(y)) if x == y => true, + (DataProvider(x), DataProvider(y)) if x == y => true, + (Fallback(x), Fallback(y)) if x == y => true, _ => false, } } diff --git a/frame/offences/src/lib.rs b/frame/offences/src/lib.rs index c89d93c12bd95..96c7c119c2038 100644 --- a/frame/offences/src/lib.rs +++ b/frame/offences/src/lib.rs @@ -247,7 +247,7 @@ impl> ReportIndexStorage { fn insert(&mut self, time_slot: &O::TimeSlot, report_id: ReportIdOf) { // Insert the report id into the list while maintaining the ordering by the time // slot. - let pos = self.same_kind_reports.partition_point(|&(ref when, _)| when <= time_slot); + let pos = self.same_kind_reports.partition_point(|(when, _)| when <= time_slot); self.same_kind_reports.insert(pos, (time_slot.clone(), report_id)); // Update the list of concurrent reports. diff --git a/frame/session/src/lib.rs b/frame/session/src/lib.rs index ed5f80e6099c1..a9f89412a71c4 100644 --- a/frame/session/src/lib.rs +++ b/frame/session/src/lib.rs @@ -678,7 +678,7 @@ impl Pallet { // since a new validator set always leads to `changed` starting // as true, we can ensure that `now_session_keys` and `next_validators` // have the same length. this function is called once per iteration. - if let Some(&(_, ref old_keys)) = now_session_keys.next() { + if let Some((_, old_keys)) = now_session_keys.next() { if old_keys != keys { changed = true; } diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 760345e8ddb28..d5072476fb37e 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -1299,8 +1299,8 @@ where add_db_reads_writes(1, 0); // Reverse because it's more likely to find reports from recent eras. - match eras.iter().rev().find(|&&(_, ref sesh)| sesh <= &slash_session) { - Some(&(ref slash_era, _)) => *slash_era, + match eras.iter().rev().find(|&(_, sesh)| sesh <= &slash_session) { + Some((slash_era, _)) => *slash_era, // Before bonding period. defensive - should be filtered out. None => return consumed_weight, } From 416b0f50bba519146ec7ea45a67980b45cd658e7 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Date: Tue, 11 Apr 2023 14:07:52 +0300 Subject: [PATCH 632/715] Metadata V15: Add Runtime API metadata (#13302) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * impl_runtime_apis: Generate getters for `metadata_at` functions Signed-off-by: Alexandru Vasile * runtime: Implement new `Metadata` runtime trait Signed-off-by: Alexandru Vasile * runtime: Move `metadata_at` functions to construct_runtime macro Signed-off-by: Alexandru Vasile * contruct_runtime: Use `OpaqueMetadata` from hidden imports Signed-off-by: Alexandru Vasile * Adjust testing Signed-off-by: Alexandru Vasile * frame/tests: Add tests for the new API Signed-off-by: Alexandru Vasile * primitives/proc-macro: Helper to extract documentation literals Signed-off-by: Alexandru Vasile * primitives/proc-macro: Helper to filter all `cfg` attributes Signed-off-by: Alexandru Vasile * primitives/proc-macro: Generate documentation getters for metadata Signed-off-by: Alexandru Vasile * primitives/proc-macro: Avoid trait collision with snake case methods Signed-off-by: Alexandru Vasile * proc-macro/tests: Check doc getters Signed-off-by: Alexandru Vasile * primitives/proc-macro: Generate metadata for runtime methods Signed-off-by: Alexandru Vasile * primitives/api: Export scale-info and frame-metadata Signed-off-by: Alexandru Vasile * primitives/proc-macro: Generate metadata for runtime traits Signed-off-by: Alexandru Vasile * frame/runtime: Expose metadata v15 internally Signed-off-by: Alexandru Vasile * test: Use metadata v15 from `lexnv/md_v15_test` branch Signed-off-by: Alexandru Vasile * primitives/proc-macro: Generate crate access one module up Signed-off-by: Alexandru Vasile * frame: Implement `runtime_metadata` for mocks and tests Signed-off-by: Alexandru Vasile * primitives/proc-macro: Fix warnings Signed-off-by: Alexandru Vasile * primitives/proc-macro: Add no-docs flag Signed-off-by: Alexandru Vasile * frame: Adjust more tests Signed-off-by: Alexandru Vasile * frame/tests: Check runtime metadata correctness Signed-off-by: Alexandru Vasile * frame/benchmarking: Adjust benchmarks Signed-off-by: Alexandru Vasile * frame/benchmarks: Adjust more benchmarks Signed-off-by: Alexandru Vasile * primitives/api: Fix clippy Signed-off-by: Alexandru Vasile * primitives/proc-macro: Generate runtime metadata on the `decl_runtime_apis` Signed-off-by: Alexandru Vasile * frame: Abuse Deref to resolve `runtime_metadata` Signed-off-by: Alexandru Vasile * Revert "frame: Implement `runtime_metadata` for mocks and tests" This reverts commit e4782de008148d1f9b2758e9a919314c0a62ed9a. Revert "frame: Adjust more tests" This reverts commit de1352c8c9af14f8f45218d500885567ea0cc84f. Revert "frame/benchmarking: Adjust benchmarks" This reverts commit ae85bbeca3ea1a4dc0ab12958fa903f8c07ba53e. Signed-off-by: Alexandru Vasile Revert "frame/benchmarks: Adjust more benchmarks" This reverts commit d37aa2205e80cceaa04e7f2971bb542d4ce8a6db. * primitives/proc-macro: Remove unused imports and function Signed-off-by: Alexandru Vasile * frame/support: Adjust runtime metadata test Signed-off-by: Alexandru Vasile * primitives/tests: Remove doc getter test Signed-off-by: Alexandru Vasile * frame/support: Enable `no-metadata-docs` feature from `sp-api` Signed-off-by: Alexandru Vasile * primitives/tests: Add `TypeInfo` for test::extrinsic Signed-off-by: Alexandru Vasile * primitives/api: Expose scale-info and frame-metadata Signed-off-by: Alexandru Vasile * Update frame-metadata to include v15 Signed-off-by: Alexandru Vasile * Fix merge conflicts Signed-off-by: Alexandru Vasile * frame/metadata_ir: Add IR for runtime API metadata Signed-off-by: Alexandru Vasile * frame/metadata_ir: Convert IR to V15 Signed-off-by: Alexandru Vasile * primitives/api: Collect IR metadata for runtime API Signed-off-by: Alexandru Vasile * primitives/api: Move `metadata_ir` from frame/support Signed-off-by: Alexandru Vasile * frame/tests: Adjust testing Signed-off-by: Alexandru Vasile * frame/tests: Adjust `metadata_versions` test Signed-off-by: Alexandru Vasile * primitives/runtime_metadata: Exclude default type parameters from methods Signed-off-by: Alexandru Vasile * Update primitives/api/proc-macro/src/runtime_metadata.rs Co-authored-by: Bastian Köcher * Update primitives/api/src/metadata_ir/types.rs Co-authored-by: Bastian Köcher * Update primitives/api/src/metadata_ir/mod.rs Co-authored-by: Bastian Köcher * Update primitives/api/proc-macro/src/utils.rs Co-authored-by: Bastian Köcher * Update primitives/api/proc-macro/src/runtime_metadata.rs Co-authored-by: Bastian Köcher * Update primitives/api/proc-macro/src/runtime_metadata.rs Co-authored-by: Bastian Köcher * Update primitives/api/proc-macro/src/runtime_metadata.rs Co-authored-by: Bastian Köcher * Update primitives/api/proc-macro/src/runtime_metadata.rs Co-authored-by: Bastian Köcher * Update primitives/api/proc-macro/src/runtime_metadata.rs Co-authored-by: Bastian Köcher * Update primitives/api/proc-macro/src/runtime_metadata.rs Co-authored-by: Bastian Köcher * primitives: Fix build Signed-off-by: Alexandru Vasile * primitives/metadata-ir: Move IR to dedicated crate Signed-off-by: Alexandru Vasile * primitives: Reexport metadata-ir and frame-metadata Signed-off-by: Alexandru Vasile * frame: Use apis field instead of runtime Signed-off-by: Alexandru Vasile * Better documentation for the `Deref` abstraction Signed-off-by: Alexandru Vasile * ui-tests: Check empty `impl_runtime_apis` Signed-off-by: Alexandru Vasile * primitives: Remove unneeded bounds on generic params Signed-off-by: Alexandru Vasile * primitives: Rename `collect_where_bounds` to `get_argument_type_param` Signed-off-by: Alexandru Vasile * primitives: Generate crate access per fn call Signed-off-by: Alexandru Vasile * Revert "primitives: Remove unneeded bounds on generic params" This reverts commit 5178e38cf21cfb481156eefd628d62989201d59a. * metadata-ir: Add no-std Signed-off-by: Alexandru Vasile * primitives: Adjust where bounds Signed-off-by: Alexandru Vasile * Change `frame-metadata` branch to "origin/main" Signed-off-by: Alexandru Vasile * Update to `main` from origin Signed-off-by: Alexandru Vasile * Update frame-metadata to crates.io v15.1 Signed-off-by: Alexandru Vasile * Revert "ui-tests: Check empty `impl_runtime_apis`" This reverts commit cf78a7190ad9cba3c3bb2e78dc3d0dc382b2fea9. * Move ui test to primitives/ui Signed-off-by: Alexandru Vasile * Update frame/support/test/tests/runtime_metadata.rs Co-authored-by: Bastian Köcher * Update primitives/api/proc-macro/src/runtime_metadata.rs Co-authored-by: Bastian Köcher * Test already covered by `empty_impl_runtime_apis_call.stderr` This reverts commit 3bafb294cbe9745569bf5e5a1a2e6b4a4c1aadc5. * Retriger CI Signed-off-by: Alexandru Vasile * Import `TokenStream` as `TokenStream2` Signed-off-by: Alexandru Vasile --------- Signed-off-by: Alexandru Vasile Co-authored-by: parity-processbot <> Co-authored-by: Bastian Köcher --- Cargo.lock | 19 +- Cargo.toml | 1 + frame/support/Cargo.toml | 4 +- .../src/construct_runtime/expand/metadata.rs | 21 +- .../procedural/src/construct_runtime/mod.rs | 25 ++ frame/support/src/lib.rs | 2 +- frame/support/test/Cargo.toml | 2 + frame/support/test/tests/pallet.rs | 2 +- frame/support/test/tests/runtime_metadata.rs | 222 ++++++++++++++ primitives/api/Cargo.toml | 7 +- primitives/api/proc-macro/Cargo.toml | 3 + .../api/proc-macro/src/decl_runtime_apis.rs | 25 +- .../api/proc-macro/src/impl_runtime_apis.rs | 19 +- primitives/api/proc-macro/src/lib.rs | 1 + .../api/proc-macro/src/runtime_metadata.rs | 271 ++++++++++++++++++ primitives/api/proc-macro/src/utils.rs | 69 ++++- primitives/api/src/lib.rs | 6 +- primitives/consensus/beefy/src/lib.rs | 2 +- primitives/metadata-ir/Cargo.toml | 28 ++ .../metadata-ir/src/lib.rs | 32 ++- .../metadata-ir/src}/types.rs | 71 +++++ .../metadata-ir/src}/v14.rs | 0 primitives/metadata-ir/src/v15.rs | 188 ++++++++++++ primitives/test-primitives/Cargo.toml | 2 + primitives/test-primitives/src/lib.rs | 2 +- 25 files changed, 993 insertions(+), 31 deletions(-) create mode 100644 frame/support/test/tests/runtime_metadata.rs create mode 100644 primitives/api/proc-macro/src/runtime_metadata.rs create mode 100644 primitives/metadata-ir/Cargo.toml rename frame/support/src/metadata_ir/mod.rs => primitives/metadata-ir/src/lib.rs (76%) rename {frame/support/src/metadata_ir => primitives/metadata-ir/src}/types.rs (83%) rename {frame/support/src/metadata_ir => primitives/metadata-ir/src}/v14.rs (100%) create mode 100644 primitives/metadata-ir/src/v15.rs diff --git a/Cargo.lock b/Cargo.lock index d4185103f8c96..f55180f9ca942 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2413,9 +2413,9 @@ dependencies = [ [[package]] name = "frame-metadata" -version = "15.0.0" +version = "15.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df6bb8542ef006ef0de09a5c4420787d79823c0ed7924225822362fd2bf2ff2d" +checksum = "878babb0b136e731cc77ec2fd883ff02745ff21e6fb662729953d44923df009c" dependencies = [ "cfg-if", "parity-scale-codec", @@ -2525,6 +2525,7 @@ dependencies = [ "rustversion", "scale-info", "serde", + "sp-api", "sp-arithmetic", "sp-core", "sp-io", @@ -10156,8 +10157,10 @@ dependencies = [ "hash-db", "log", "parity-scale-codec", + "scale-info", "sp-api-proc-macro", "sp-core", + "sp-metadata-ir", "sp-runtime", "sp-state-machine", "sp-std", @@ -10172,6 +10175,7 @@ name = "sp-api-proc-macro" version = "4.0.0-dev" dependencies = [ "Inflector", + "assert_matches", "blake2", "expander", "proc-macro-crate", @@ -10591,6 +10595,16 @@ dependencies = [ "zstd", ] +[[package]] +name = "sp-metadata-ir" +version = "0.1.0" +dependencies = [ + "frame-metadata", + "parity-scale-codec", + "scale-info", + "sp-std", +] + [[package]] name = "sp-mmr-primitives" version = "4.0.0-dev" @@ -10842,6 +10856,7 @@ name = "sp-test-primitives" version = "2.0.0" dependencies = [ "parity-scale-codec", + "scale-info", "serde", "sp-application-crypto", "sp-core", diff --git a/Cargo.toml b/Cargo.toml index de562ad79e47e..cae8976cca4a9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -202,6 +202,7 @@ members = [ "primitives/keystore", "primitives/maybe-compressed-blob", "primitives/merkle-mountain-range", + "primitives/metadata-ir", "primitives/npos-elections", "primitives/npos-elections/fuzzer", "primitives/offchain", diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index 820658372afd9..7792fdf015ba5 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.136", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.2.2", 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"] } +frame-metadata = { version = "15.1.0", default-features = false, features = ["v14", "v15-unstable"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../primitives/api" } sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } @@ -74,7 +74,7 @@ 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"] +no-metadata-docs = ["frame-support-procedural/no-metadata-docs", "sp-api/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/src/construct_runtime/expand/metadata.rs b/frame/support/procedural/src/construct_runtime/expand/metadata.rs index ba6a621af7523..81fc93ba3c9ef 100644 --- a/frame/support/procedural/src/construct_runtime/expand/metadata.rs +++ b/frame/support/procedural/src/construct_runtime/expand/metadata.rs @@ -77,6 +77,24 @@ pub fn expand_runtime_metadata( quote! { impl #runtime { fn metadata_ir() -> #scrate::metadata_ir::MetadataIR { + // Each runtime must expose the `runtime_metadata()` to fetch the runtime API metadata. + // The function is implemented by calling `impl_runtime_apis!`. + // + // However, the `construct_runtime!` may be called without calling `impl_runtime_apis!`. + // Rely on the `Deref` trait to differentiate between a runtime that implements + // APIs (by macro impl_runtime_apis!) and a runtime that is simply created (by macro construct_runtime!). + // + // Both `InternalConstructRuntime` and `InternalImplRuntimeApis` expose a `runtime_metadata()` function. + // `InternalConstructRuntime` is implemented by the `construct_runtime!` for Runtime references (`& Runtime`), + // while `InternalImplRuntimeApis` is implemented by the `impl_runtime_apis!` for Runtime (`Runtime`). + // + // Therefore, the `Deref` trait will resolve the `runtime_metadata` from `impl_runtime_apis!` + // when both macros are called; and will resolve an empty `runtime_metadata` when only the `construct_runtime!` + // is called. + // + // `Deref` needs a reference for resolving the function call. + let rt = #runtime; + #scrate::metadata_ir::MetadataIR { pallets: #scrate::sp_std::vec![ #(#pallets),* ], extrinsic: #scrate::metadata_ir::ExtrinsicMetadataIR { @@ -95,7 +113,8 @@ pub fn expand_runtime_metadata( }) .collect(), }, - ty: #scrate::scale_info::meta_type::<#runtime>() + ty: #scrate::scale_info::meta_type::<#runtime>(), + apis: (&rt).runtime_metadata(), } } diff --git a/frame/support/procedural/src/construct_runtime/mod.rs b/frame/support/procedural/src/construct_runtime/mod.rs index a0d414154bfcc..c5a48a98063a4 100644 --- a/frame/support/procedural/src/construct_runtime/mod.rs +++ b/frame/support/procedural/src/construct_runtime/mod.rs @@ -296,6 +296,31 @@ fn construct_runtime_final_expansion( type RuntimeBlock = #block; } + // Each runtime must expose the `runtime_metadata()` to fetch the runtime API metadata. + // The function is implemented by calling `impl_runtime_apis!`. + // + // However, the `construct_runtime!` may be called without calling `impl_runtime_apis!`. + // Rely on the `Deref` trait to differentiate between a runtime that implements + // APIs (by macro impl_runtime_apis!) and a runtime that is simply created (by macro construct_runtime!). + // + // Both `InternalConstructRuntime` and `InternalImplRuntimeApis` expose a `runtime_metadata()` function. + // `InternalConstructRuntime` is implemented by the `construct_runtime!` for Runtime references (`& Runtime`), + // while `InternalImplRuntimeApis` is implemented by the `impl_runtime_apis!` for Runtime (`Runtime`). + // + // Therefore, the `Deref` trait will resolve the `runtime_metadata` from `impl_runtime_apis!` + // when both macros are called; and will resolve an empty `runtime_metadata` when only the `construct_runtime!` + // is called. + + #[doc(hidden)] + trait InternalConstructRuntime { + #[inline(always)] + fn runtime_metadata(&self) -> #scrate::sp_std::vec::Vec<#scrate::metadata_ir::RuntimeApiMetadataIR> { + Default::default() + } + } + #[doc(hidden)] + impl InternalConstructRuntime for &#name {} + #outer_event #outer_origin diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index ac897fef0d872..036bd93464b9f 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -50,6 +50,7 @@ pub use paste; pub use scale_info; #[cfg(feature = "std")] pub use serde; +pub use sp_api::metadata_ir; pub use sp_core::{OpaqueMetadata, Void}; #[doc(hidden)] pub use sp_core_hashing_proc_macro; @@ -80,7 +81,6 @@ pub mod error; pub mod crypto; pub mod dispatch_context; pub mod instances; -pub mod metadata_ir; pub mod migrations; pub mod traits; pub mod weights; diff --git a/frame/support/test/Cargo.toml b/frame/support/test/Cargo.toml index 90ef243eed6c6..ad4589c734fde 100644 --- a/frame/support/test/Cargo.toml +++ b/frame/support/test/Cargo.toml @@ -15,6 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] serde = { version = "1.0.136", default-features = false, features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.2.2", 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 = "../../../primitives/api" } 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" } @@ -47,6 +48,7 @@ std = [ "sp-state-machine", "sp-arithmetic/std", "sp-version/std", + "sp-api/std", ] try-runtime = ["frame-support/try-runtime"] # WARNING: diff --git a/frame/support/test/tests/pallet.rs b/frame/support/test/tests/pallet.rs index 11f82c4c0d266..f1dc97223322f 100644 --- a/frame/support/test/tests/pallet.rs +++ b/frame/support/test/tests/pallet.rs @@ -1671,7 +1671,7 @@ fn metadata_at_version() { #[test] fn metadata_versions() { - assert_eq!(vec![LATEST_METADATA_VERSION], Runtime::metadata_versions()); + assert_eq!(vec![LATEST_METADATA_VERSION, u32::MAX], Runtime::metadata_versions()); } #[test] diff --git a/frame/support/test/tests/runtime_metadata.rs b/frame/support/test/tests/runtime_metadata.rs new file mode 100644 index 0000000000000..8c04c785a35af --- /dev/null +++ b/frame/support/test/tests/runtime_metadata.rs @@ -0,0 +1,222 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT 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::{ + metadata_ir::{ + RuntimeApiMetadataIR, RuntimeApiMethodMetadataIR, RuntimeApiMethodParamMetadataIR, + }, + traits::ConstU32, +}; +use scale_info::{form::MetaForm, meta_type}; +use sp_runtime::traits::Block as BlockT; + +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 RuntimeOrigin = RuntimeOrigin; + type Index = u64; + type BlockNumber = u32; + 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 RuntimeEvent = RuntimeEvent; + 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>; +} + +frame_support::construct_runtime!( + pub enum Runtime where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic + { + System: frame_system, + } +); + +sp_api::decl_runtime_apis! { + /// ApiWithCustomVersion trait documentation + /// + /// Documentation on multiline. + pub trait Api { + fn test(data: u64); + /// something_with_block. + fn something_with_block(block: Block) -> Block; + fn function_with_two_args(data: u64, block: Block); + fn same_name(); + fn wild_card(_: u32); + } +} + +sp_api::impl_runtime_apis! { + impl self::Api for Runtime { + fn test(_data: u64) { + unimplemented!() + } + + fn something_with_block(_: Block) -> Block { + unimplemented!() + } + + fn function_with_two_args(_: u64, _: Block) { + unimplemented!() + } + + fn same_name() {} + + fn wild_card(_: u32) {} + } + + impl sp_api::Core for Runtime { + fn version() -> sp_version::RuntimeVersion { + unimplemented!() + } + fn execute_block(_: Block) { + unimplemented!() + } + fn initialize_block(_: &::Header) { + unimplemented!() + } + } +} + +#[test] +fn runtime_metadata() { + fn maybe_docs(doc: Vec<&'static str>) -> Vec<&'static str> { + if cfg!(feature = "no-metadata-docs") { + vec![] + } else { + doc + } + } + + let expected_runtime_metadata = vec![ + RuntimeApiMetadataIR { + name: "Api", + methods: vec![ + RuntimeApiMethodMetadataIR { + name: "test", + inputs: vec![RuntimeApiMethodParamMetadataIR:: { + name: "data", + ty: meta_type::(), + }], + output: meta_type::<()>(), + docs: vec![], + }, + RuntimeApiMethodMetadataIR { + name: "something_with_block", + inputs: vec![RuntimeApiMethodParamMetadataIR:: { + name: "block", + ty: meta_type::(), + }], + output: meta_type::(), + docs: maybe_docs(vec![" something_with_block."]), + }, + RuntimeApiMethodMetadataIR { + name: "function_with_two_args", + inputs: vec![ + RuntimeApiMethodParamMetadataIR:: { + name: "data", + ty: meta_type::(), + }, + RuntimeApiMethodParamMetadataIR:: { + name: "block", + ty: meta_type::(), + }, + ], + output: meta_type::<()>(), + docs: vec![], + }, + RuntimeApiMethodMetadataIR { + name: "same_name", + inputs: vec![], + output: meta_type::<()>(), + docs: vec![], + }, + RuntimeApiMethodMetadataIR { + name: "wild_card", + inputs: vec![RuntimeApiMethodParamMetadataIR:: { + name: "_", + ty: meta_type::(), + }], + output: meta_type::<()>(), + docs: vec![], + }, + ], + docs: maybe_docs(vec![ + " ApiWithCustomVersion trait documentation", + "", + " Documentation on multiline.", + ]), + }, + RuntimeApiMetadataIR { + name: "Core", + methods: vec![ + RuntimeApiMethodMetadataIR { + name: "version", + inputs: vec![], + output: meta_type::(), + docs: maybe_docs(vec![" Returns the version of the runtime."]), + }, + RuntimeApiMethodMetadataIR { + name: "execute_block", + inputs: vec![RuntimeApiMethodParamMetadataIR:: { + name: "block", + ty: meta_type::(), + }], + output: meta_type::<()>(), + docs: maybe_docs(vec![" Execute the given block."]), + }, + RuntimeApiMethodMetadataIR { + name: "initialize_block", + inputs: vec![RuntimeApiMethodParamMetadataIR:: { + name: "header", + ty: meta_type::<&::Header>(), + }], + output: meta_type::<()>(), + docs: maybe_docs(vec![" Initialize a block with the given header."]), + }, + ], + docs: maybe_docs(vec![ + " The `Core` runtime api that every Substrate runtime needs to implement.", + ]), + }, + ]; + + let rt = Runtime; + let runtime_metadata = (&rt).runtime_metadata(); + assert_eq!(runtime_metadata, expected_runtime_metadata); +} diff --git a/primitives/api/Cargo.toml b/primitives/api/Cargo.toml index ae1b3294c281f..55e3993466a6d 100644 --- a/primitives/api/Cargo.toml +++ b/primitives/api/Cargo.toml @@ -23,7 +23,8 @@ sp-state-machine = { version = "0.13.0", default-features = false, optional = tr sp-trie = { version = "7.0.0", default-features = false, optional = true, path = "../trie" } hash-db = { version = "0.16.0", optional = true } thiserror = { version = "1.0.30", optional = true } - +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +sp-metadata-ir = { version = "0.1.0", default-features = false, path = "../metadata-ir" } log = { version = "0.4.17", default-features = false } [dev-dependencies] @@ -42,6 +43,8 @@ std = [ "hash-db", "thiserror", "log/std", + "scale-info/std", + "sp-metadata-ir/std", ] # Special feature to disable logging completly. # @@ -51,3 +54,5 @@ std = [ # # This sets the max logging level to `off` for `log`. disable-logging = ["log/max_level_off"] +# Do not report the documentation in the metadata. +no-metadata-docs = [] diff --git a/primitives/api/proc-macro/Cargo.toml b/primitives/api/proc-macro/Cargo.toml index ba7c6312042c9..1ba62cc53d5aa 100644 --- a/primitives/api/proc-macro/Cargo.toml +++ b/primitives/api/proc-macro/Cargo.toml @@ -24,6 +24,9 @@ proc-macro-crate = "1.1.3" expander = "1.0.0" Inflector = "0.11.4" +[dev-dependencies] +assert_matches = "1.3.0" + # Required for the doc tests [features] default = ["std"] diff --git a/primitives/api/proc-macro/src/decl_runtime_apis.rs b/primitives/api/proc-macro/src/decl_runtime_apis.rs index 3c3056d34487b..43e1e7969c5d1 100644 --- a/primitives/api/proc-macro/src/decl_runtime_apis.rs +++ b/primitives/api/proc-macro/src/decl_runtime_apis.rs @@ -15,16 +15,18 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::utils::{ - extract_parameter_names_types_and_borrows, fold_fn_decl_for_client_side, generate_crate_access, - 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, - RENAMED_ATTRIBUTE, SUPPORTED_ATTRIBUTE_NAMES, +use crate::{ + common::{ + API_VERSION_ATTRIBUTE, BLOCK_GENERIC_IDENT, CHANGED_IN_ATTRIBUTE, CORE_TRAIT_ATTRIBUTE, + RENAMED_ATTRIBUTE, SUPPORTED_ATTRIBUTE_NAMES, + }, + runtime_metadata::generate_decl_runtime_metadata, + utils::{ + extract_parameter_names_types_and_borrows, fold_fn_decl_for_client_side, + generate_crate_access, 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 proc_macro2::{Span, TokenStream}; @@ -219,6 +221,7 @@ fn generate_runtime_decls(decls: &[ItemTrait]) -> Result { let mut decl = decl.clone(); let decl_span = decl.span(); extend_generics_with_block(&mut decl.generics); + let metadata = generate_decl_runtime_metadata(&decl); let mod_name = generate_runtime_mod_name_for_trait(&decl.ident); let found_attributes = remove_supported_attributes(&mut decl.attrs); let api_version = @@ -304,6 +307,8 @@ fn generate_runtime_decls(decls: &[ItemTrait]) -> Result { pub use #versioned_ident as #main_api_ident; + #metadata + pub #api_version pub #id diff --git a/primitives/api/proc-macro/src/impl_runtime_apis.rs b/primitives/api/proc-macro/src/impl_runtime_apis.rs index 0d265293ecf42..c0da8ccf30458 100644 --- a/primitives/api/proc-macro/src/impl_runtime_apis.rs +++ b/primitives/api/proc-macro/src/impl_runtime_apis.rs @@ -15,15 +15,17 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::utils::{ - extract_all_signature_types, extract_block_type_from_trait_path, extract_impl_trait, - extract_parameter_names_types_and_borrows, generate_crate_access, - 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, + runtime_metadata::generate_impl_runtime_metadata, + utils::{ + extract_all_signature_types, extract_block_type_from_trait_path, extract_impl_trait, + extract_parameter_names_types_and_borrows, generate_crate_access, + 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; @@ -685,6 +687,7 @@ fn impl_runtime_apis_impl_inner(api_impls: &[ItemImpl]) -> Result { let runtime_api_versions = generate_runtime_api_versions(api_impls)?; let wasm_interface = generate_wasm_interface(api_impls)?; let api_impls_for_runtime_api = generate_api_impl_for_runtime_api(api_impls)?; + let runtime_metadata = generate_impl_runtime_metadata(api_impls)?; let impl_ = quote!( #base_runtime_api @@ -695,6 +698,8 @@ fn impl_runtime_apis_impl_inner(api_impls: &[ItemImpl]) -> Result { #runtime_api_versions + #runtime_metadata + pub mod api { use super::*; diff --git a/primitives/api/proc-macro/src/lib.rs b/primitives/api/proc-macro/src/lib.rs index cea958426879e..d34f4b7f9cf6a 100644 --- a/primitives/api/proc-macro/src/lib.rs +++ b/primitives/api/proc-macro/src/lib.rs @@ -25,6 +25,7 @@ mod common; mod decl_runtime_apis; mod impl_runtime_apis; mod mock_impl_runtime_apis; +mod runtime_metadata; mod utils; #[proc_macro] diff --git a/primitives/api/proc-macro/src/runtime_metadata.rs b/primitives/api/proc-macro/src/runtime_metadata.rs new file mode 100644 index 0000000000000..02b03baeaeee3 --- /dev/null +++ b/primitives/api/proc-macro/src/runtime_metadata.rs @@ -0,0 +1,271 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT 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 proc_macro2::TokenStream as TokenStream2; +use quote::quote; +use syn::{parse_quote, ItemImpl, ItemTrait, Result}; + +use crate::{ + common::CHANGED_IN_ATTRIBUTE, + utils::{ + extract_impl_trait, filter_cfg_attributes, generate_crate_access, + generate_runtime_mod_name_for_trait, get_doc_literals, RequireQualifiedTraitPath, + }, +}; + +/// Get the type parameter argument without lifetime or mutability +/// of a runtime metadata function. +/// +/// In the following example, both the `AccountId` and `Index` generic +/// type parameters must implement `scale_info::TypeInfo` because they +/// are added into the metadata using `scale_info::meta_type`. +/// +/// ```ignore +/// trait ExampleAccountNonceApi { +/// fn account_nonce<'a>(account: &'a AccountId) -> Index; +/// } +/// ``` +/// +/// Instead of returning `&'a AccountId` for the first parameter, this function +/// returns `AccountId` to place bounds around it. +fn get_type_param(ty: &syn::Type) -> syn::Type { + // Remove the lifetime and mutability of the type T to + // place bounds around it. + let ty_elem = match &ty { + syn::Type::Reference(reference) => &reference.elem, + syn::Type::Ptr(ptr) => &ptr.elem, + syn::Type::Slice(slice) => &slice.elem, + syn::Type::Array(arr) => &arr.elem, + _ => ty, + }; + + ty_elem.clone() +} + +/// Extract the documentation from the provided attributes. +/// +/// It takes into account the `no-metadata-docs` feature. +fn collect_docs(attrs: &[syn::Attribute], crate_: &TokenStream2) -> TokenStream2 { + if cfg!(feature = "no-metadata-docs") { + quote!(#crate_::vec![]) + } else { + let docs = get_doc_literals(&attrs); + quote!(#crate_::vec![ #( #docs, )* ]) + } +} + +/// Generate the runtime metadata of the provided trait. +/// +/// The metadata is exposed as a generic function on the hidden module +/// of the trait generated by the `decl_runtime_apis`. +pub fn generate_decl_runtime_metadata(decl: &ItemTrait) -> TokenStream2 { + let crate_ = generate_crate_access(); + let mut methods = Vec::new(); + + // Ensure that any function parameter that relies on the `BlockT` bounds + // also has `TypeInfo + 'static` bounds (required by `scale_info::meta_type`). + // + // For example, if a runtime API defines a method that has an input: + // `fn func(input: ::Header)` + // then the runtime metadata will imply `::Header: TypeInfo + 'static`. + // + // This restricts the bounds at the metadata level, without needing to modify the `BlockT` + // itself, since the concrete implementations are already satisfying `TypeInfo`. + let mut where_clause = Vec::new(); + for item in &decl.items { + // Collect metadata for methods only. + let syn::TraitItem::Method(method) = item else { + continue + }; + + // Collect metadata only for the latest methods. + let is_changed_in = + method.attrs.iter().any(|attr| attr.path.is_ident(CHANGED_IN_ATTRIBUTE)); + if is_changed_in { + continue + } + + let mut inputs = Vec::new(); + let signature = &method.sig; + for input in &signature.inputs { + // Exclude `self` from metadata collection. + let syn::FnArg::Typed(typed) = input else { + continue + }; + + let pat = &typed.pat; + let name = quote!(#pat).to_string(); + let ty = &typed.ty; + + where_clause.push(get_type_param(ty)); + + inputs.push(quote!( + #crate_::metadata_ir::RuntimeApiMethodParamMetadataIR { + name: #name, + ty: #crate_::scale_info::meta_type::<#ty>(), + } + )); + } + + let output = match &signature.output { + syn::ReturnType::Default => quote!(#crate_::scale_info::meta_type::<()>()), + syn::ReturnType::Type(_, ty) => { + where_clause.push(get_type_param(ty)); + quote!(#crate_::scale_info::meta_type::<#ty>()) + }, + }; + + // String method name including quotes for constructing `v15::RuntimeApiMethodMetadata`. + let method_name = signature.ident.to_string(); + let docs = collect_docs(&method.attrs, &crate_); + + // Include the method metadata only if its `cfg` features are enabled. + let attrs = filter_cfg_attributes(&method.attrs); + methods.push(quote!( + #( #attrs )* + #crate_::metadata_ir::RuntimeApiMethodMetadataIR { + name: #method_name, + inputs: #crate_::vec![ #( #inputs, )* ], + output: #output, + docs: #docs, + } + )); + } + + let trait_name_ident = &decl.ident; + let trait_name = trait_name_ident.to_string(); + let docs = collect_docs(&decl.attrs, &crate_); + let attrs = filter_cfg_attributes(&decl.attrs); + // The trait generics where already extended with `Block: BlockT`. + let mut generics = decl.generics.clone(); + for generic_param in generics.params.iter_mut() { + let syn::GenericParam::Type(ty) = generic_param else { + continue + }; + + // Default type parameters are not allowed in functions. + ty.eq_token = None; + ty.default = None; + } + + let where_clause = where_clause + .iter() + .map(|ty| quote!(#ty: #crate_::scale_info::TypeInfo + 'static)); + + quote!( + #( #attrs )* + #[inline(always)] + pub fn runtime_metadata #generics () -> #crate_::metadata_ir::RuntimeApiMetadataIR + where #( #where_clause, )* + { + #crate_::metadata_ir::RuntimeApiMetadataIR { + name: #trait_name, + methods: #crate_::vec![ #( #methods, )* ], + docs: #docs, + } + } + ) +} + +/// Implement the `runtime_metadata` function on the runtime that +/// generates the metadata for the given traits. +/// +/// The metadata of each trait is extracted from the generic function +/// exposed by `generate_decl_runtime_metadata`. +pub fn generate_impl_runtime_metadata(impls: &[ItemImpl]) -> Result { + if impls.is_empty() { + return Ok(quote!()) + } + + let crate_ = generate_crate_access(); + + // Get the name of the runtime for which the traits are implemented. + let runtime_name = &impls + .get(0) + .expect("Traits should contain at least one implementation; qed") + .self_ty; + + let mut metadata = Vec::new(); + + for impl_ in impls { + let mut trait_ = extract_impl_trait(&impl_, RequireQualifiedTraitPath::Yes)?.clone(); + + // Implementation traits are always references with a path `impl client::Core ...` + // The trait name is the last segment of this path. + let trait_name_ident = &trait_ + .segments + .last() + .as_ref() + .expect("Trait path should always contain at least one item; qed") + .ident; + + // Extract the generics from the trait to pass to the `runtime_metadata` + // function on the hidden module. + let generics = trait_ + .segments + .iter() + .find_map(|segment| { + if let syn::PathArguments::AngleBracketed(generics) = &segment.arguments { + Some(generics.clone()) + } else { + None + } + }) + .expect("Trait path should always contain at least one generic parameter; qed"); + + let mod_name = generate_runtime_mod_name_for_trait(&trait_name_ident); + // Get absolute path to the `runtime_decl_for_` module by replacing the last segment. + if let Some(segment) = trait_.segments.last_mut() { + *segment = parse_quote!(#mod_name); + } + + let attrs = filter_cfg_attributes(&impl_.attrs); + metadata.push(quote!( + #( #attrs )* + #trait_::runtime_metadata::#generics() + )); + } + + // Each runtime must expose the `runtime_metadata()` to fetch the runtime API metadata. + // The function is implemented by calling `impl_runtime_apis!`. + // + // However, the `construct_runtime!` may be called without calling `impl_runtime_apis!`. + // Rely on the `Deref` trait to differentiate between a runtime that implements + // APIs (by macro impl_runtime_apis!) and a runtime that is simply created (by macro + // construct_runtime!). + // + // Both `InternalConstructRuntime` and `InternalImplRuntimeApis` expose a `runtime_metadata()` + // function. `InternalConstructRuntime` is implemented by the `construct_runtime!` for Runtime + // references (`& Runtime`), while `InternalImplRuntimeApis` is implemented by the + // `impl_runtime_apis!` for Runtime (`Runtime`). + // + // Therefore, the `Deref` trait will resolve the `runtime_metadata` from `impl_runtime_apis!` + // when both macros are called; and will resolve an empty `runtime_metadata` when only the + // `construct_runtime!` is called. + + Ok(quote!( + #[doc(hidden)] + trait InternalImplRuntimeApis { + #[inline(always)] + fn runtime_metadata(&self) -> #crate_::vec::Vec<#crate_::metadata_ir::RuntimeApiMetadataIR> { + #crate_::vec![ #( #metadata, )* ] + } + } + #[doc(hidden)] + impl InternalImplRuntimeApis for #runtime_name {} + )) +} diff --git a/primitives/api/proc-macro/src/utils.rs b/primitives/api/proc-macro/src/utils.rs index 4444a2624b669..cffaf317fbb10 100644 --- a/primitives/api/proc-macro/src/utils.rs +++ b/primitives/api/proc-macro/src/utils.rs @@ -253,7 +253,74 @@ pub fn parse_runtime_api_version(version: &Attribute) -> Result { version.base10_parse() } -// Each versioned trait is named 'ApiNameVN' where N is the specific version. E.g. ParachainHostV2 +/// 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) } + +/// Extract the documentation from the provided attributes. +pub fn get_doc_literals(attrs: &[syn::Attribute]) -> Vec { + attrs + .iter() + .filter_map(|attr| { + let Ok(syn::Meta::NameValue(meta)) = attr.parse_meta() else { + return None + }; + + meta.path.get_ident().filter(|ident| *ident == "doc").map(|_| meta.lit) + }) + .collect() +} + +/// Filters all attributes except the cfg ones. +pub fn filter_cfg_attributes(attrs: &[syn::Attribute]) -> Vec { + attrs.iter().filter(|a| a.path.is_ident("cfg")).cloned().collect() +} + +#[cfg(test)] +mod tests { + use assert_matches::assert_matches; + + use super::*; + + #[test] + fn check_get_doc_literals() { + const FIRST: &'static str = "hello"; + const SECOND: &'static str = "WORLD"; + + let doc: Attribute = parse_quote!(#[doc = #FIRST]); + let doc_world: Attribute = parse_quote!(#[doc = #SECOND]); + + let attrs = vec![ + doc.clone(), + parse_quote!(#[derive(Debug)]), + parse_quote!(#[test]), + parse_quote!(#[allow(non_camel_case_types)]), + doc_world.clone(), + ]; + + let docs = get_doc_literals(&attrs); + assert_eq!(docs.len(), 2); + assert_matches!(&docs[0], syn::Lit::Str(val) if val.value() == FIRST); + assert_matches!(&docs[1], syn::Lit::Str(val) if val.value() == SECOND); + } + + #[test] + fn check_filter_cfg_attributes() { + let cfg_std: Attribute = parse_quote!(#[cfg(feature = "std")]); + let cfg_benchmarks: Attribute = parse_quote!(#[cfg(feature = "runtime-benchmarks")]); + + let attrs = vec![ + cfg_std.clone(), + parse_quote!(#[derive(Debug)]), + parse_quote!(#[test]), + cfg_benchmarks.clone(), + parse_quote!(#[allow(non_camel_case_types)]), + ]; + + let filtered = filter_cfg_attributes(&attrs); + assert_eq!(filtered.len(), 2); + assert_eq!(cfg_std, filtered[0]); + assert_eq!(cfg_benchmarks, filtered[1]); + } +} diff --git a/primitives/api/src/lib.rs b/primitives/api/src/lib.rs index ff101c3add947..02770280f7b90 100644 --- a/primitives/api/src/lib.rs +++ b/primitives/api/src/lib.rs @@ -76,12 +76,16 @@ pub use codec::{self, Decode, DecodeLimit, Encode}; #[cfg(feature = "std")] pub use hash_db::Hasher; #[doc(hidden)] +pub use scale_info; +#[doc(hidden)] #[cfg(not(feature = "std"))] pub use sp_core::to_substrate_wasm_fn_return_value; use sp_core::OpaqueMetadata; #[doc(hidden)] pub use sp_core::{offchain, ExecutionContext}; #[doc(hidden)] +pub use sp_metadata_ir::{self as metadata_ir, frame_metadata as metadata}; +#[doc(hidden)] #[cfg(feature = "std")] pub use sp_runtime::StateVersion; #[doc(hidden)] @@ -101,7 +105,7 @@ pub use sp_state_machine::{ StorageProof, TrieBackend, TrieBackendBuilder, }; #[doc(hidden)] -pub use sp_std::{mem, slice}; +pub use sp_std::{mem, slice, vec}; #[doc(hidden)] pub use sp_version::{create_apis_vec, ApiId, ApisVec, RuntimeVersion}; #[cfg(feature = "std")] diff --git a/primitives/consensus/beefy/src/lib.rs b/primitives/consensus/beefy/src/lib.rs index cc5d1e8cb9a3b..268e1925b4449 100644 --- a/primitives/consensus/beefy/src/lib.rs +++ b/primitives/consensus/beefy/src/lib.rs @@ -284,7 +284,7 @@ impl OnNewValidatorSet for () { /// the runtime API boundary this type is unknown and as such we keep this /// opaque representation, implementors of the runtime API will have to make /// sure that all usages of `OpaqueKeyOwnershipProof` refer to the same type. -#[derive(Decode, Encode, PartialEq)] +#[derive(Decode, Encode, PartialEq, TypeInfo)] pub struct OpaqueKeyOwnershipProof(Vec); impl OpaqueKeyOwnershipProof { /// Create a new `OpaqueKeyOwnershipProof` using the given encoded diff --git a/primitives/metadata-ir/Cargo.toml b/primitives/metadata-ir/Cargo.toml new file mode 100644 index 0000000000000..27fada9c6f34e --- /dev/null +++ b/primitives/metadata-ir/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "sp-metadata-ir" +version = "0.1.0" +authors = ["Parity Technologies "] +edition = "2021" +license = "Apache-2.0" +homepage = "https://substrate.io" +repository = "https://github.com/paritytech/substrate/" +description = "Intermediate representation of the runtime metadata." +documentation = "https://docs.rs/sp-metadata-ir" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false } +frame-metadata = { version = "15.1.0", default-features = false, features = ["v14", "v15-unstable"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +sp-std = { version = "5.0.0", default-features = false, path = "../std" } + +[features] +default = ["std"] +std = [ + "codec/std", + "frame-metadata/std", + "scale-info/std", + "sp-std/std", +] diff --git a/frame/support/src/metadata_ir/mod.rs b/primitives/metadata-ir/src/lib.rs similarity index 76% rename from frame/support/src/metadata_ir/mod.rs rename to primitives/metadata-ir/src/lib.rs index bab205d63c118..3ddc2911d4c93 100644 --- a/frame/support/src/metadata_ir/mod.rs +++ b/primitives/metadata-ir/src/lib.rs @@ -17,15 +17,28 @@ //! Intermediate representation of the runtime metadata. +#![cfg_attr(not(feature = "std"), no_std)] +#![warn(missing_docs)] + +// Re-export. +#[doc(hidden)] +pub use frame_metadata; + mod types; use frame_metadata::{RuntimeMetadataPrefixed, RuntimeMetadataV14}; pub use types::*; mod v14; +mod v15; /// Metadata V14. const V14: u32 = 14; +/// Metadata V15. +/// +/// Not yet stable, thus we set it to `u32::MAX`. +const V15: u32 = u32::MAX; + /// Transform the IR to the specified version. /// /// Use [`supported_versions`] to find supported versions. @@ -36,13 +49,18 @@ pub fn into_version(metadata: MetadataIR, version: u32) -> Option { + let v15: frame_metadata::v15::RuntimeMetadataV15 = metadata.into(); + Some(v15.into()) + }, _ => None, } } /// Returns the supported metadata versions. pub fn supported_versions() -> sp_std::vec::Vec { - sp_std::vec![V14,] + sp_std::vec![V14, V15] } /// Transform the IR to the latest stable metadata version. @@ -54,7 +72,6 @@ pub fn into_latest(metadata: MetadataIR) -> RuntimeMetadataPrefixed { #[cfg(test)] mod test { use super::*; - use crate::metadata_ir::ExtrinsicMetadataIR; use frame_metadata::{v14::META_RESERVED, RuntimeMetadata}; use scale_info::meta_type; @@ -67,6 +84,7 @@ mod test { signed_extensions: vec![], }, ty: meta_type::<()>(), + apis: vec![], } } @@ -79,4 +97,14 @@ mod test { assert!(matches!(metadata.1, RuntimeMetadata::V14(_))); } + + #[test] + fn into_version_15() { + let ir = ir_metadata(); + let metadata = into_version(ir, V15).expect("Should return prefixed metadata"); + + assert_eq!(metadata.0, META_RESERVED); + + assert!(matches!(metadata.1, RuntimeMetadata::V15(_))); + } } diff --git a/frame/support/src/metadata_ir/types.rs b/primitives/metadata-ir/src/types.rs similarity index 83% rename from frame/support/src/metadata_ir/types.rs rename to primitives/metadata-ir/src/types.rs index 087fd3dcad249..93ee54891d89f 100644 --- a/frame/support/src/metadata_ir/types.rs +++ b/primitives/metadata-ir/src/types.rs @@ -37,6 +37,77 @@ pub struct MetadataIR { pub extrinsic: ExtrinsicMetadataIR, /// The type of the `Runtime`. pub ty: T::Type, + /// Metadata of the Runtime API. + pub apis: Vec>, +} + +/// Metadata of a runtime trait. +#[derive(Clone, PartialEq, Eq, Encode, Debug)] +pub struct RuntimeApiMetadataIR { + /// Trait name. + pub name: T::String, + /// Trait methods. + pub methods: Vec>, + /// Trait documentation. + pub docs: Vec, +} + +impl IntoPortable for RuntimeApiMetadataIR { + type Output = RuntimeApiMetadataIR; + + fn into_portable(self, registry: &mut Registry) -> Self::Output { + RuntimeApiMetadataIR { + name: self.name.into_portable(registry), + methods: registry.map_into_portable(self.methods), + docs: registry.map_into_portable(self.docs), + } + } +} + +/// Metadata of a runtime method. +#[derive(Clone, PartialEq, Eq, Encode, Debug)] +pub struct RuntimeApiMethodMetadataIR { + /// Method name. + pub name: T::String, + /// Method parameters. + pub inputs: Vec>, + /// Method output. + pub output: T::Type, + /// Method documentation. + pub docs: Vec, +} + +impl IntoPortable for RuntimeApiMethodMetadataIR { + type Output = RuntimeApiMethodMetadataIR; + + fn into_portable(self, registry: &mut Registry) -> Self::Output { + RuntimeApiMethodMetadataIR { + name: self.name.into_portable(registry), + inputs: registry.map_into_portable(self.inputs), + output: registry.register_type(&self.output), + docs: registry.map_into_portable(self.docs), + } + } +} + +/// Metadata of a runtime method parameter. +#[derive(Clone, PartialEq, Eq, Encode, Debug)] +pub struct RuntimeApiMethodParamMetadataIR { + /// Parameter name. + pub name: T::String, + /// Parameter type. + pub ty: T::Type, +} + +impl IntoPortable for RuntimeApiMethodParamMetadataIR { + type Output = RuntimeApiMethodParamMetadataIR; + + fn into_portable(self, registry: &mut Registry) -> Self::Output { + RuntimeApiMethodParamMetadataIR { + name: self.name.into_portable(registry), + ty: registry.register_type(&self.ty), + } + } } /// The intermediate representation for a pallet metadata. diff --git a/frame/support/src/metadata_ir/v14.rs b/primitives/metadata-ir/src/v14.rs similarity index 100% rename from frame/support/src/metadata_ir/v14.rs rename to primitives/metadata-ir/src/v14.rs diff --git a/primitives/metadata-ir/src/v15.rs b/primitives/metadata-ir/src/v15.rs new file mode 100644 index 0000000000000..86441228d008e --- /dev/null +++ b/primitives/metadata-ir/src/v15.rs @@ -0,0 +1,188 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Convert the IR to V15 metadata. + +use super::types::{ + ExtrinsicMetadataIR, MetadataIR, PalletCallMetadataIR, PalletConstantMetadataIR, + PalletErrorMetadataIR, PalletEventMetadataIR, PalletMetadataIR, PalletStorageMetadataIR, + RuntimeApiMetadataIR, RuntimeApiMethodMetadataIR, RuntimeApiMethodParamMetadataIR, + SignedExtensionMetadataIR, StorageEntryMetadataIR, StorageEntryModifierIR, StorageEntryTypeIR, + StorageHasherIR, +}; + +use frame_metadata::v15::{ + ExtrinsicMetadata, PalletCallMetadata, PalletConstantMetadata, PalletErrorMetadata, + PalletEventMetadata, PalletMetadata, PalletStorageMetadata, RuntimeApiMetadata, + RuntimeApiMethodMetadata, RuntimeApiMethodParamMetadata, RuntimeMetadataV15, + SignedExtensionMetadata, StorageEntryMetadata, StorageEntryModifier, StorageEntryType, + StorageHasher, +}; + +impl From for RuntimeMetadataV15 { + fn from(ir: MetadataIR) -> Self { + RuntimeMetadataV15::new( + ir.pallets.into_iter().map(Into::into).collect(), + ir.extrinsic.into(), + ir.ty, + ir.apis.into_iter().map(Into::into).collect(), + ) + } +} + +impl From for RuntimeApiMetadata { + fn from(ir: RuntimeApiMetadataIR) -> Self { + RuntimeApiMetadata { + name: ir.name, + methods: ir.methods.into_iter().map(Into::into).collect(), + docs: ir.docs, + } + } +} + +impl From for RuntimeApiMethodMetadata { + fn from(ir: RuntimeApiMethodMetadataIR) -> Self { + RuntimeApiMethodMetadata { + name: ir.name, + inputs: ir.inputs.into_iter().map(Into::into).collect(), + output: ir.output, + docs: ir.docs, + } + } +} + +impl From for RuntimeApiMethodParamMetadata { + fn from(ir: RuntimeApiMethodParamMetadataIR) -> Self { + RuntimeApiMethodParamMetadata { name: ir.name, ty: ir.ty } + } +} + +impl From for PalletMetadata { + fn from(ir: PalletMetadataIR) -> Self { + PalletMetadata { + name: ir.name, + storage: ir.storage.map(Into::into), + calls: ir.calls.map(Into::into), + event: ir.event.map(Into::into), + constants: ir.constants.into_iter().map(Into::into).collect(), + error: ir.error.map(Into::into), + index: ir.index, + docs: ir.docs, + } + } +} + +impl From for StorageEntryModifier { + fn from(ir: StorageEntryModifierIR) -> Self { + match ir { + StorageEntryModifierIR::Optional => StorageEntryModifier::Optional, + StorageEntryModifierIR::Default => StorageEntryModifier::Default, + } + } +} + +impl From for StorageHasher { + fn from(ir: StorageHasherIR) -> Self { + match ir { + StorageHasherIR::Blake2_128 => StorageHasher::Blake2_128, + StorageHasherIR::Blake2_256 => StorageHasher::Blake2_256, + StorageHasherIR::Blake2_128Concat => StorageHasher::Blake2_128Concat, + StorageHasherIR::Twox128 => StorageHasher::Twox128, + StorageHasherIR::Twox256 => StorageHasher::Twox256, + StorageHasherIR::Twox64Concat => StorageHasher::Twox64Concat, + StorageHasherIR::Identity => StorageHasher::Identity, + } + } +} + +impl From for StorageEntryType { + fn from(ir: StorageEntryTypeIR) -> Self { + match ir { + StorageEntryTypeIR::Plain(ty) => StorageEntryType::Plain(ty), + StorageEntryTypeIR::Map { hashers, key, value } => StorageEntryType::Map { + hashers: hashers.into_iter().map(Into::into).collect(), + key, + value, + }, + } + } +} + +impl From for StorageEntryMetadata { + fn from(ir: StorageEntryMetadataIR) -> Self { + StorageEntryMetadata { + name: ir.name, + modifier: ir.modifier.into(), + ty: ir.ty.into(), + default: ir.default, + docs: ir.docs, + } + } +} + +impl From for PalletStorageMetadata { + fn from(ir: PalletStorageMetadataIR) -> Self { + PalletStorageMetadata { + prefix: ir.prefix, + entries: ir.entries.into_iter().map(Into::into).collect(), + } + } +} + +impl From for PalletCallMetadata { + fn from(ir: PalletCallMetadataIR) -> Self { + PalletCallMetadata { ty: ir.ty } + } +} + +impl From for PalletEventMetadata { + fn from(ir: PalletEventMetadataIR) -> Self { + PalletEventMetadata { ty: ir.ty } + } +} + +impl From for PalletConstantMetadata { + fn from(ir: PalletConstantMetadataIR) -> Self { + PalletConstantMetadata { name: ir.name, ty: ir.ty, value: ir.value, docs: ir.docs } + } +} + +impl From for PalletErrorMetadata { + fn from(ir: PalletErrorMetadataIR) -> Self { + PalletErrorMetadata { ty: ir.ty } + } +} + +impl From for SignedExtensionMetadata { + fn from(ir: SignedExtensionMetadataIR) -> Self { + SignedExtensionMetadata { + identifier: ir.identifier, + ty: ir.ty, + additional_signed: ir.additional_signed, + } + } +} + +impl From for ExtrinsicMetadata { + fn from(ir: ExtrinsicMetadataIR) -> Self { + ExtrinsicMetadata { + ty: ir.ty, + version: ir.version, + signed_extensions: ir.signed_extensions.into_iter().map(Into::into).collect(), + } + } +} diff --git a/primitives/test-primitives/Cargo.toml b/primitives/test-primitives/Cargo.toml index deb120104b717..f6d57ce70fc05 100644 --- a/primitives/test-primitives/Cargo.toml +++ b/primitives/test-primitives/Cargo.toml @@ -13,6 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } 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" } @@ -28,4 +29,5 @@ std = [ "sp-application-crypto/std", "sp-core/std", "sp-runtime/std", + "scale-info/std", ] diff --git a/primitives/test-primitives/src/lib.rs b/primitives/test-primitives/src/lib.rs index 3a5f3dac40d68..035acc7a35ef6 100644 --- a/primitives/test-primitives/src/lib.rs +++ b/primitives/test-primitives/src/lib.rs @@ -28,7 +28,7 @@ pub use sp_core::{hash::H256, RuntimeDebug}; use sp_runtime::traits::{BlakeTwo256, Extrinsic as ExtrinsicT, Verify}; /// Extrinsic for test-runtime. -#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug)] +#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, scale_info::TypeInfo)] pub enum Extrinsic { IncludeData(Vec), StorageChange(Vec, Option>), From a2f6e05cc4e77734c2fa22167dbe20c845d0702e Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Tue, 11 Apr 2023 15:53:16 +0200 Subject: [PATCH 633/715] pallet nis: remove benchmarking hack (#13759) * pallet nis: remove benchmark hack Signed-off-by: Oliver Tale-Yazdi * NearestPrefDown -> Down Tested on the kitchensink and in case that n = 10000000000000000 and d = 12000100600000000000000 it rounds the Perquintill up (correctly) since 833326347280+47318160/60000503 should round up. That triggers the path 'amount <= on_hold' in L736. Signed-off-by: Oliver Tale-Yazdi --------- Signed-off-by: Oliver Tale-Yazdi --- frame/nis/src/benchmarking.rs | 6 ------ frame/nis/src/lib.rs | 5 ++--- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/frame/nis/src/benchmarking.rs b/frame/nis/src/benchmarking.rs index 10fee2abe3ba9..0cc9e7421d0e6 100644 --- a/frame/nis/src/benchmarking.rs +++ b/frame/nis/src/benchmarking.rs @@ -164,9 +164,6 @@ benchmarks! { Nis::::place_bid(RawOrigin::Signed(caller.clone()).into(), bid, 1)?; Nis::::process_queues(Perquintill::one(), 1, 2, &mut WeightCounter::unlimited()); frame_system::Pallet::::set_block_number(Receipts::::get(0).unwrap().expiry); - // FIXME: Ensure that the pallet has enough funding. This should already be the case, but - // a rounding error can cause it to fail. - T::Currency::set_balance(&Nis::::account_id(), BalanceOf::::max_value() / 10u32.into()); }: _(RawOrigin::Signed(caller.clone()), 0, None) verify { assert!(Receipts::::get(0).is_none()); @@ -185,9 +182,6 @@ benchmarks! { Nis::::process_queues(Perquintill::one(), 1, 2, &mut WeightCounter::unlimited()); frame_system::Pallet::::set_block_number(Receipts::::get(0).unwrap().expiry); Nis::::communify(RawOrigin::Signed(caller.clone()).into(), 0)?; - // FIXME: Ensure that the pallet has enough funding. This should already be the case, but - // a rounding error can cause it to fail. - T::Currency::set_balance(&Nis::::account_id(), BalanceOf::::max_value() / 10u32.into()); }: _(RawOrigin::Signed(caller.clone()), 0) verify { assert!(Receipts::::get(0).is_none()); diff --git a/frame/nis/src/lib.rs b/frame/nis/src/lib.rs index 9cac5f4b616e7..c4d0d0d420290 100644 --- a/frame/nis/src/lib.rs +++ b/frame/nis/src/lib.rs @@ -1139,9 +1139,8 @@ pub mod pallet { // Now to activate the bid... let n = amount; let d = issuance.effective; - let proportion = - Perquintill::from_rational_with_rounding(n, d, Rounding::NearestPrefDown) - .defensive_unwrap_or_default(); + let proportion = Perquintill::from_rational_with_rounding(n, d, Rounding::Down) + .defensive_unwrap_or_default(); let who = bid.who; let index = summary.index; summary.proportion_owed.defensive_saturating_accrue(proportion); From a1f71b8ef5dd531b101d2c9ec1a43f40715b4db4 Mon Sep 17 00:00:00 2001 From: Liam Aharon Date: Wed, 12 Apr 2023 00:17:25 +1000 Subject: [PATCH 634/715] Fix fungible and fungibles set_balance return value (#13851) * Fix fungible set_balance return value * fix fungibles set_balance return value --- frame/support/src/traits/tokens/fungible/regular.rs | 4 ++-- frame/support/src/traits/tokens/fungibles/regular.rs | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/frame/support/src/traits/tokens/fungible/regular.rs b/frame/support/src/traits/tokens/fungible/regular.rs index 574392cac8256..5a201b33b7cd9 100644 --- a/frame/support/src/traits/tokens/fungible/regular.rs +++ b/frame/support/src/traits/tokens/fungible/regular.rs @@ -327,9 +327,9 @@ pub trait Mutate: Inspect + Unbalanced { fn set_balance(who: &AccountId, amount: Self::Balance) -> Self::Balance { let b = Self::balance(who); if b > amount { - Self::burn_from(who, b - amount, BestEffort, Force).map(|d| amount.saturating_sub(d)) + Self::burn_from(who, b - amount, BestEffort, Force).map(|d| b.saturating_sub(d)) } else { - Self::mint_into(who, amount - b).map(|d| amount.saturating_add(d)) + Self::mint_into(who, amount - b).map(|d| b.saturating_add(d)) } .unwrap_or(b) } diff --git a/frame/support/src/traits/tokens/fungibles/regular.rs b/frame/support/src/traits/tokens/fungibles/regular.rs index 03c14988015ab..27d1a50b34805 100644 --- a/frame/support/src/traits/tokens/fungibles/regular.rs +++ b/frame/support/src/traits/tokens/fungibles/regular.rs @@ -365,10 +365,9 @@ pub trait Mutate: Inspect + Unbalanced { fn set_balance(asset: Self::AssetId, who: &AccountId, amount: Self::Balance) -> Self::Balance { let b = Self::balance(asset, who); if b > amount { - Self::burn_from(asset, who, b - amount, BestEffort, Force) - .map(|d| amount.saturating_sub(d)) + Self::burn_from(asset, who, b - amount, BestEffort, Force).map(|d| b.saturating_sub(d)) } else { - Self::mint_into(asset, who, amount - b).map(|d| amount.saturating_add(d)) + Self::mint_into(asset, who, amount - b).map(|d| b.saturating_add(d)) } .unwrap_or(b) } From ca6af5d19fc6439d2afae38d2ce68bf250663370 Mon Sep 17 00:00:00 2001 From: Mira Ressel Date: Tue, 11 Apr 2023 17:02:50 +0200 Subject: [PATCH 635/715] use stable rust toolchain in ci (#13830) cargo-fmt stays on the nightly pipeline; our fmt config uses a heap of unstable features. --- scripts/ci/gitlab/pipeline/build.yml | 3 +-- scripts/ci/gitlab/pipeline/test.yml | 27 +++++++++------------------ 2 files changed, 10 insertions(+), 20 deletions(-) diff --git a/scripts/ci/gitlab/pipeline/build.yml b/scripts/ci/gitlab/pipeline/build.yml index 0a36599c70e24..806a4ef970960 100644 --- a/scripts/ci/gitlab/pipeline/build.yml +++ b/scripts/ci/gitlab/pipeline/build.yml @@ -148,7 +148,6 @@ build-rustdoc: variables: 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: "$CI_PROJECT_DIR/target" artifacts: @@ -163,7 +162,7 @@ build-rustdoc: artifacts: false script: - rusty-cachier snapshot create - - time cargo +nightly doc --locked --workspace --all-features --verbose --no-deps + - time cargo doc --locked --workspace --all-features --verbose --no-deps - rm -f $CARGO_TARGET_DIR/doc/.lock - mv $CARGO_TARGET_DIR/doc ./crate-docs # FIXME: remove me after CI image gets nonroot diff --git a/scripts/ci/gitlab/pipeline/test.yml b/scripts/ci/gitlab/pipeline/test.yml index 331b382e41a6f..50f926215062d 100644 --- a/scripts/ci/gitlab/pipeline/test.yml +++ b/scripts/ci/gitlab/pipeline/test.yml @@ -61,21 +61,17 @@ 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 + - SKIP_WASM_BUILD=1 env -u RUSTFLAGS cargo clippy --all-targets - rusty-cachier cache upload cargo-check-benches: stage: test variables: - # Override to use nightly toolchain - RUSTY_CACHIER_TOOLCHAIN: "nightly" CI_JOB_NAME: "cargo-check-benches" extends: - .docker-env @@ -105,7 +101,7 @@ cargo-check-benches: - echo "___Running benchmarks___"; - case ${CI_NODE_INDEX} in 1) - SKIP_WASM_BUILD=1 time cargo +nightly check --locked --benches --all; + SKIP_WASM_BUILD=1 time cargo check --locked --benches --all; cargo run --locked --release -p node-bench -- ::trie::read::small --json | tee ./artifacts/benches/$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA/::trie::read::small.json; echo "___Uploading cache for rusty-cachier___"; @@ -301,7 +297,6 @@ test-frame-examples-compile-to-wasm: - .docker-env - .test-refs variables: - RUSTY_CACHIER_TOOLCHAIN: nightly # Enable debug assertions since we are running optimized builds for testing # but still want to have debug assertions. RUSTFLAGS: "-C debug-assertions" @@ -309,9 +304,9 @@ test-frame-examples-compile-to-wasm: script: - rusty-cachier snapshot create - cd ./frame/examples/offchain-worker/ - - cargo +nightly build --locked --target=wasm32-unknown-unknown --no-default-features + - cargo build --locked --target=wasm32-unknown-unknown --no-default-features - cd ../basic - - cargo +nightly build --locked --target=wasm32-unknown-unknown --no-default-features + - cargo build --locked --target=wasm32-unknown-unknown --no-default-features - rusty-cachier cache upload test-linux-stable-int: @@ -344,8 +339,6 @@ check-tracing: needs: - job: test-linux-stable-int artifacts: false - variables: - RUSTY_CACHIER_TOOLCHAIN: nightly extends: - .docker-env - .test-refs @@ -353,8 +346,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 --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 + - time cargo test --locked --manifest-path ./primitives/tracing/Cargo.toml --no-default-features + - time cargo test --locked --manifest-path ./primitives/tracing/Cargo.toml --no-default-features --features=with-tracing - rusty-cachier cache upload # more information about this job can be found here: @@ -369,7 +362,6 @@ test-full-crypto-feature: - .docker-env - .test-refs variables: - RUSTY_CACHIER_TOOLCHAIN: nightly # Enable debug assertions since we are running optimized builds for testing # but still want to have debug assertions. RUSTFLAGS: "-C debug-assertions" @@ -377,9 +369,9 @@ test-full-crypto-feature: script: - rusty-cachier snapshot create - cd primitives/core/ - - time cargo +nightly build --locked --verbose --no-default-features --features full_crypto + - time cargo build --locked --verbose --no-default-features --features full_crypto - cd ../application-crypto - - time cargo +nightly build --locked --verbose --no-default-features --features full_crypto + - time cargo build --locked --verbose --no-default-features --features full_crypto - rusty-cachier cache upload check-rustdoc: @@ -388,12 +380,11 @@ check-rustdoc: - .docker-env - .test-refs variables: - RUSTY_CACHIER_TOOLCHAIN: nightly SKIP_WASM_BUILD: 1 RUSTDOCFLAGS: "-Dwarnings" script: - rusty-cachier snapshot create - - time cargo +nightly doc --locked --workspace --all-features --verbose --no-deps + - time cargo doc --locked --workspace --all-features --verbose --no-deps - rusty-cachier cache upload cargo-check-each-crate: From da9f88dcac328d8f6de38dd61e33078c20bd6685 Mon Sep 17 00:00:00 2001 From: gupnik Date: Tue, 11 Apr 2023 20:40:10 +0530 Subject: [PATCH 636/715] Makes storage hashers optional in dev mode (#13815) * Initial changes * Adds UI test for error when _ is used without dev_mode * Minor * ".git/.scripts/commands/fmt/fmt.sh" * Adds test to verify hasher --------- Co-authored-by: command-bot <> --- .../procedural/src/pallet/expand/storage.rs | 13 +++ .../procedural/src/pallet/parse/storage.rs | 44 +++++++--- .../dev_mode_without_arg_default_hasher.rs | 33 +++++++ ...dev_mode_without_arg_default_hasher.stderr | 19 +++++ .../tests/pallet_ui/pass/dev_mode_valid.rs | 85 ++++++++++++++++++- 5 files changed, 182 insertions(+), 12 deletions(-) create mode 100644 frame/support/test/tests/pallet_ui/dev_mode_without_arg_default_hasher.rs create mode 100644 frame/support/test/tests/pallet_ui/dev_mode_without_arg_default_hasher.stderr diff --git a/frame/support/procedural/src/pallet/expand/storage.rs b/frame/support/procedural/src/pallet/expand/storage.rs index 8ba9ee7681ca9..efc803033d3bf 100644 --- a/frame/support/procedural/src/pallet/expand/storage.rs +++ b/frame/support/procedural/src/pallet/expand/storage.rs @@ -269,6 +269,19 @@ pub fn process_generics(def: &mut Def) -> syn::Result (5, 6, 7), }; + if storage_def.use_default_hasher { + let hasher_indices: Vec = match storage_def.metadata { + Metadata::Map { .. } | Metadata::CountedMap { .. } => vec![1], + Metadata::DoubleMap { .. } => vec![1, 3], + _ => vec![], + }; + for hasher_idx in hasher_indices { + args.args[hasher_idx] = syn::GenericArgument::Type( + syn::parse_quote!(#frame_support::Blake2_128Concat), + ); + } + } + 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)?; diff --git a/frame/support/procedural/src/pallet/parse/storage.rs b/frame/support/procedural/src/pallet/parse/storage.rs index 3ed7ce54ebd64..fee6ec9f1ca87 100644 --- a/frame/support/procedural/src/pallet/parse/storage.rs +++ b/frame/support/procedural/src/pallet/parse/storage.rs @@ -185,6 +185,8 @@ pub struct StorageDef { pub unbounded: bool, /// Whether or not reads to this storage key will be ignored by benchmarking pub whitelisted: bool, + /// Whether or not a default hasher is allowed to replace `_` + pub use_default_hasher: bool, } /// The parsed generic from the @@ -325,12 +327,12 @@ fn check_generics( } } -/// Returns `(named generics, metadata, query kind)` +/// Returns `(named generics, metadata, query kind, use_default_hasher)` fn process_named_generics( storage: &StorageKind, args_span: proc_macro2::Span, args: &[syn::Binding], -) -> syn::Result<(Option, Metadata, Option)> { +) -> syn::Result<(Option, Metadata, Option, bool)> { let mut parsed = HashMap::::new(); // Ensure no duplicate. @@ -480,15 +482,16 @@ fn process_named_generics( let metadata = generics.metadata()?; let query_kind = generics.query_kind(); - Ok((Some(generics), metadata, query_kind)) + Ok((Some(generics), metadata, query_kind, false)) } -/// Returns `(named generics, metadata, query kind)` +/// Returns `(named generics, metadata, query kind, use_default_hasher)` fn process_unnamed_generics( storage: &StorageKind, args_span: proc_macro2::Span, args: &[syn::Type], -) -> syn::Result<(Option, Metadata, Option)> { + dev_mode: bool, +) -> syn::Result<(Option, Metadata, Option, bool)> { let retrieve_arg = |arg_pos| { args.get(arg_pos).cloned().ok_or_else(|| { let msg = format!( @@ -510,18 +513,28 @@ fn process_unnamed_generics( err })?; + let use_default_hasher = |arg_pos| { + if let Some(arg) = retrieve_arg(arg_pos).ok() { + dev_mode && syn::parse2::(arg.to_token_stream()).is_ok() + } else { + false + } + }; + let res = match storage { StorageKind::Value => - (None, Metadata::Value { value: retrieve_arg(1)? }, retrieve_arg(2).ok()), + (None, Metadata::Value { value: retrieve_arg(1)? }, retrieve_arg(2).ok(), false), StorageKind::Map => ( None, Metadata::Map { key: retrieve_arg(2)?, value: retrieve_arg(3)? }, retrieve_arg(4).ok(), + use_default_hasher(1), ), StorageKind::CountedMap => ( None, Metadata::CountedMap { key: retrieve_arg(2)?, value: retrieve_arg(3)? }, retrieve_arg(4).ok(), + use_default_hasher(1), ), StorageKind::DoubleMap => ( None, @@ -531,21 +544,28 @@ fn process_unnamed_generics( value: retrieve_arg(5)?, }, retrieve_arg(6).ok(), + use_default_hasher(1) && use_default_hasher(3), ), StorageKind::NMap => { let keygen = retrieve_arg(1)?; let keys = collect_keys(&keygen)?; - (None, Metadata::NMap { keys, keygen, value: retrieve_arg(2)? }, retrieve_arg(3).ok()) + ( + None, + Metadata::NMap { keys, keygen, value: retrieve_arg(2)? }, + retrieve_arg(3).ok(), + false, + ) }, }; Ok(res) } -/// Returns `(named generics, metadata, query kind)` +/// Returns `(named generics, metadata, query kind, use_default_hasher)` fn process_generics( segment: &syn::PathSegment, -) -> syn::Result<(Option, Metadata, Option)> { + dev_mode: bool, +) -> syn::Result<(Option, Metadata, Option, bool)> { let storage_kind = match &*segment.ident.to_string() { "StorageValue" => StorageKind::Value, "StorageMap" => StorageKind::Map, @@ -583,7 +603,7 @@ fn process_generics( _ => unreachable!("It is asserted above that all generics are types"), }) .collect::>(); - process_unnamed_generics(&storage_kind, args_span, &args) + process_unnamed_generics(&storage_kind, args_span, &args, dev_mode) } else if args.args.iter().all(|gen| matches!(gen, syn::GenericArgument::Binding(_))) { let args = args .args @@ -711,7 +731,8 @@ impl StorageDef { return Err(syn::Error::new(item.ty.span(), msg)) } - let (named_generics, metadata, query_kind) = process_generics(&typ.path.segments[0])?; + let (named_generics, metadata, query_kind, use_default_hasher) = + process_generics(&typ.path.segments[0], dev_mode)?; let query_kind = query_kind .map(|query_kind| { @@ -832,6 +853,7 @@ impl StorageDef { named_generics, unbounded, whitelisted, + use_default_hasher, }) } } diff --git a/frame/support/test/tests/pallet_ui/dev_mode_without_arg_default_hasher.rs b/frame/support/test/tests/pallet_ui/dev_mode_without_arg_default_hasher.rs new file mode 100644 index 0000000000000..fb1139479566a --- /dev/null +++ b/frame/support/test/tests/pallet_ui/dev_mode_without_arg_default_hasher.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::*; + + // 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>; + + #[pallet::storage] + type MyStorageMap = StorageMap<_, _, u32, u64>; + + #[pallet::storage] + type MyStorageDoubleMap = StorageDoubleMap<_, _, u32, _, u64, u64>; + + #[pallet::storage] + type MyCountedStorageMap = CountedStorageMap<_, _, u32, u64>; + + // Your Pallet's internal functions. + impl Pallet {} +} + +fn main() {} diff --git a/frame/support/test/tests/pallet_ui/dev_mode_without_arg_default_hasher.stderr b/frame/support/test/tests/pallet_ui/dev_mode_without_arg_default_hasher.stderr new file mode 100644 index 0000000000000..5317f5c52b9b6 --- /dev/null +++ b/frame/support/test/tests/pallet_ui/dev_mode_without_arg_default_hasher.stderr @@ -0,0 +1,19 @@ +error[E0121]: the placeholder `_` is not allowed within types on item signatures for type aliases + --> tests/pallet_ui/dev_mode_without_arg_default_hasher.rs:21:47 + | +21 | type MyStorageMap = StorageMap<_, _, u32, u64>; + | ^ not allowed in type signatures + +error[E0121]: the placeholder `_` is not allowed within types on item signatures for type aliases + --> tests/pallet_ui/dev_mode_without_arg_default_hasher.rs:24:59 + | +24 | type MyStorageDoubleMap = StorageDoubleMap<_, _, u32, _, u64, u64>; + | ^ ^ not allowed in type signatures + | | + | not allowed in type signatures + +error[E0121]: the placeholder `_` is not allowed within types on item signatures for type aliases + --> tests/pallet_ui/dev_mode_without_arg_default_hasher.rs:27:61 + | +27 | type MyCountedStorageMap = CountedStorageMap<_, _, u32, u64>; + | ^ not allowed in type signatures 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 index 97e0d585d0ce9..483ed9579bd0a 100644 --- a/frame/support/test/tests/pallet_ui/pass/dev_mode_valid.rs +++ b/frame/support/test/tests/pallet_ui/pass/dev_mode_valid.rs @@ -1,5 +1,11 @@ #![cfg_attr(not(feature = "std"), no_std)] +use frame_support::{ + traits::{ + ConstU32, + }, +}; + pub use pallet::*; #[frame_support::pallet(dev_mode)] @@ -19,6 +25,16 @@ pub mod pallet { #[pallet::storage] type MyStorage = StorageValue<_, Vec>; + // The Hasher requirement skipped by `dev_mode`. + #[pallet::storage] + pub type MyStorageMap = StorageMap<_, _, u32, u64>; + + #[pallet::storage] + type MyStorageDoubleMap = StorageDoubleMap<_, _, u32, _, u64, u64>; + + #[pallet::storage] + type MyCountedStorageMap = CountedStorageMap<_, _, u32, u64>; + // Your Pallet's callable functions. #[pallet::call] impl Pallet { @@ -32,4 +48,71 @@ pub mod pallet { impl Pallet {} } -fn main() {} +impl frame_system::Config for Runtime { + type BaseCallFilter = frame_support::traits::Everything; + type RuntimeOrigin = RuntimeOrigin; + type Index = u64; + type BlockNumber = u32; + 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 RuntimeEvent = RuntimeEvent; + type BlockHashCount = 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 = ConstU32<16>; +} + +pub type Header = sp_runtime::generic::Header; +pub type Block = sp_runtime::generic::Block; +pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; + +frame_support::construct_runtime!( + pub struct Runtime where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic + { + // Exclude part `Storage` in order not to check its metadata in tests. + System: frame_system exclude_parts { Pallet, Storage }, + Example: pallet, + } +); + +impl pallet::Config for Runtime { + +} + +fn main() { + use frame_support::{pallet_prelude::*}; + use storage::unhashed; + use sp_io::{ + hashing::{blake2_128, twox_128}, + TestExternalities, + }; + + fn blake2_128_concat(d: &[u8]) -> Vec { + let mut v = blake2_128(d).to_vec(); + v.extend_from_slice(d); + v + } + + TestExternalities::default().execute_with(|| { + pallet::MyStorageMap::::insert(1, 2); + let mut k = [twox_128(b"Example"), twox_128(b"MyStorageMap")].concat(); + k.extend(1u32.using_encoded(blake2_128_concat)); + assert_eq!(unhashed::get::(&k), Some(2u64)); + }); +} From 32221d47b68f38139323009615d69493338914e1 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Tue, 11 Apr 2023 19:12:08 +0200 Subject: [PATCH 637/715] Force incrementing of consumers (#13878) --- frame/balances/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index dcf602cd5e0bf..029a170535a10 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -782,8 +782,8 @@ pub mod pallet { } a.flags.set_new_logic(); if !a.reserved.is_zero() || !a.frozen.is_zero() { - if !system::Pallet::::can_inc_consumer(who) { - // Gah!! We have a non-zero reserve balance but no provider refs :( + if system::Pallet::::providers(who) == 0 { + // Gah!! We have no provider refs :( // This shouldn't practically happen, but we need a failsafe anyway: let's give // them enough for an ED. log::warn!( @@ -794,7 +794,7 @@ pub mod pallet { a.free = a.free.max(Self::ed()); system::Pallet::::inc_providers(who); } - let _ = system::Pallet::::inc_consumers(who).defensive(); + let _ = system::Pallet::::inc_consumers_without_limit(who).defensive(); } // Should never fail - we're only setting a bit. let _ = T::AccountStore::try_mutate_exists(who, |account| -> DispatchResult { From 2b9ca86696bf87a63f8b9a8e48ebfed9d918fbcc Mon Sep 17 00:00:00 2001 From: gupnik Date: Wed, 12 Apr 2023 13:56:40 +0530 Subject: [PATCH 638/715] Fixes error message when _ is used without dev mode (#13886) * Initial changes * Adds UI test for error when _ is used without dev_mode * Minor * ".git/.scripts/commands/fmt/fmt.sh" * Adds test to verify hasher * Fixes error message when _ is used without dev mode * Updates test * Addresses review comment --------- Co-authored-by: command-bot <> --- .../procedural/src/pallet/parse/storage.rs | 18 ++++++++++----- ...dev_mode_without_arg_default_hasher.stderr | 22 ++++++------------- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/frame/support/procedural/src/pallet/parse/storage.rs b/frame/support/procedural/src/pallet/parse/storage.rs index fee6ec9f1ca87..4e90a423f79ef 100644 --- a/frame/support/procedural/src/pallet/parse/storage.rs +++ b/frame/support/procedural/src/pallet/parse/storage.rs @@ -514,10 +514,16 @@ fn process_unnamed_generics( })?; let use_default_hasher = |arg_pos| { - if let Some(arg) = retrieve_arg(arg_pos).ok() { - dev_mode && syn::parse2::(arg.to_token_stream()).is_ok() + let arg = retrieve_arg(arg_pos)?; + if syn::parse2::(arg.to_token_stream()).is_ok() { + if dev_mode { + Ok(true) + } else { + let msg = "`_` can only be used in dev_mode. Please specify an appropriate hasher."; + Err(syn::Error::new(arg.span(), msg)) + } } else { - false + Ok(false) } }; @@ -528,13 +534,13 @@ fn process_unnamed_generics( None, Metadata::Map { key: retrieve_arg(2)?, value: retrieve_arg(3)? }, retrieve_arg(4).ok(), - use_default_hasher(1), + use_default_hasher(1)?, ), StorageKind::CountedMap => ( None, Metadata::CountedMap { key: retrieve_arg(2)?, value: retrieve_arg(3)? }, retrieve_arg(4).ok(), - use_default_hasher(1), + use_default_hasher(1)?, ), StorageKind::DoubleMap => ( None, @@ -544,7 +550,7 @@ fn process_unnamed_generics( value: retrieve_arg(5)?, }, retrieve_arg(6).ok(), - use_default_hasher(1) && use_default_hasher(3), + use_default_hasher(1)? && use_default_hasher(3)?, ), StorageKind::NMap => { let keygen = retrieve_arg(1)?; diff --git a/frame/support/test/tests/pallet_ui/dev_mode_without_arg_default_hasher.stderr b/frame/support/test/tests/pallet_ui/dev_mode_without_arg_default_hasher.stderr index 5317f5c52b9b6..e0dbc8c953b4e 100644 --- a/frame/support/test/tests/pallet_ui/dev_mode_without_arg_default_hasher.stderr +++ b/frame/support/test/tests/pallet_ui/dev_mode_without_arg_default_hasher.stderr @@ -1,19 +1,11 @@ -error[E0121]: the placeholder `_` is not allowed within types on item signatures for type aliases +error: `_` can only be used in dev_mode. Please specify an appropriate hasher. --> tests/pallet_ui/dev_mode_without_arg_default_hasher.rs:21:47 | 21 | type MyStorageMap = StorageMap<_, _, u32, u64>; - | ^ not allowed in type signatures + | ^ -error[E0121]: the placeholder `_` is not allowed within types on item signatures for type aliases - --> tests/pallet_ui/dev_mode_without_arg_default_hasher.rs:24:59 - | -24 | type MyStorageDoubleMap = StorageDoubleMap<_, _, u32, _, u64, u64>; - | ^ ^ not allowed in type signatures - | | - | not allowed in type signatures - -error[E0121]: the placeholder `_` is not allowed within types on item signatures for type aliases - --> tests/pallet_ui/dev_mode_without_arg_default_hasher.rs:27:61 - | -27 | type MyCountedStorageMap = CountedStorageMap<_, _, u32, u64>; - | ^ not allowed in type signatures +error[E0432]: unresolved import `pallet` + --> tests/pallet_ui/dev_mode_without_arg_default_hasher.rs:3:9 + | +3 | pub use pallet::*; + | ^^^^^^ help: a similar path exists: `test_pallet::pallet` From 4d608f9c42e8d70d835a748fa929e59a99497e90 Mon Sep 17 00:00:00 2001 From: Mira Ressel Date: Wed, 12 Apr 2023 12:05:11 +0200 Subject: [PATCH 639/715] invoke clippy with `--locked` (#13882) --- scripts/ci/gitlab/pipeline/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/ci/gitlab/pipeline/test.yml b/scripts/ci/gitlab/pipeline/test.yml index 50f926215062d..bf7803d56505c 100644 --- a/scripts/ci/gitlab/pipeline/test.yml +++ b/scripts/ci/gitlab/pipeline/test.yml @@ -66,7 +66,7 @@ cargo-clippy: - .test-refs script: - rusty-cachier snapshot create - - SKIP_WASM_BUILD=1 env -u RUSTFLAGS cargo clippy --all-targets + - SKIP_WASM_BUILD=1 env -u RUSTFLAGS cargo clippy --locked --all-targets - rusty-cachier cache upload cargo-check-benches: From f751d63c1db7bbdb00930eba4ef2e2172ddac83a Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Wed, 12 Apr 2023 14:09:50 +0300 Subject: [PATCH 640/715] sc-consensus-beefy: add peer reputation cost/benefit changes (#13881) * add cost/benefit to gossip messages * report BEEFY gossip peer reputation changes * drop WorkerParams helper struct * add reputation costs to tests * add peer reputation cost/benefit to on-demand-requests protocol * include amount of signatures checked in invalid proof reputation cost Signed-off-by: Adrian Catangiu --- .../beefy/src/communication/gossip.rs | 264 ++++++++++++++---- .../consensus/beefy/src/communication/mod.rs | 33 +++ .../beefy/src/communication/peers.rs | 12 +- .../incoming_requests_handler.rs | 64 +++-- .../src/communication/request_response/mod.rs | 9 +- .../outgoing_requests_engine.rs | 76 +++-- client/consensus/beefy/src/import.rs | 1 + client/consensus/beefy/src/justification.rs | 40 +-- client/consensus/beefy/src/lib.rs | 19 +- client/consensus/beefy/src/metrics.rs | 10 +- client/consensus/beefy/src/tests.rs | 9 +- client/consensus/beefy/src/worker.rs | 118 +++----- 12 files changed, 430 insertions(+), 225 deletions(-) diff --git a/client/consensus/beefy/src/communication/gossip.rs b/client/consensus/beefy/src/communication/gossip.rs index 376172fc23370..9be648f8796c3 100644 --- a/client/consensus/beefy/src/communication/gossip.rs +++ b/client/consensus/beefy/src/communication/gossip.rs @@ -18,7 +18,7 @@ use std::{collections::BTreeMap, sync::Arc, time::Duration}; -use sc_network::PeerId; +use sc_network::{PeerId, ReputationChange}; use sc_network_gossip::{MessageIntent, ValidationResult, Validator, ValidatorContext}; use sp_core::hashing::twox_64; use sp_runtime::traits::{Block, Hash, Header, NumberFor}; @@ -26,10 +26,14 @@ use sp_runtime::traits::{Block, Hash, Header, NumberFor}; use codec::{Decode, Encode}; use log::{debug, trace}; use parking_lot::{Mutex, RwLock}; +use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; use wasm_timer::Instant; use crate::{ - communication::peers::KnownPeers, + communication::{ + benefit, cost, + peers::{KnownPeers, PeerReport}, + }, justification::{ proof_block_num_and_set_id, verify_with_validator_set, BeefyVersionedFinalityProof, }, @@ -47,6 +51,27 @@ const REBROADCAST_AFTER: Duration = Duration::from_secs(60); #[cfg(test)] const REBROADCAST_AFTER: Duration = Duration::from_secs(5); +#[derive(Debug, PartialEq)] +pub(super) enum Action { + // repropagate under given topic, to the given peers, applying cost/benefit to originator. + Keep(H, ReputationChange), + // discard, applying cost/benefit to originator. + Discard(ReputationChange), +} + +/// An outcome of examining a message. +#[derive(Debug, PartialEq, Clone, Copy)] +enum Consider { + /// Accept the message. + Accept, + /// Message is too early. Reject. + RejectPast, + /// Message is from the future. Reject. + RejectFuture, + /// Message cannot be evaluated. Reject. + RejectOutOfScope, +} + /// BEEFY gossip message type that gets encoded and sent on the network. #[derive(Debug, Encode, Decode)] pub(crate) enum GossipMessage { @@ -135,26 +160,47 @@ impl Filter { } } - /// Return true if `max(session_start, best_beefy) <= round <= best_grandpa`, + /// Accept if `max(session_start, best_beefy) <= round <= best_grandpa`, /// and vote `set_id` matches session set id. /// /// Latest concluded round is still considered alive to allow proper gossiping for it. - fn is_vote_accepted(&self, round: NumberFor, set_id: ValidatorSetId) -> bool { + fn consider_vote(&self, round: NumberFor, set_id: ValidatorSetId) -> Consider { self.inner .as_ref() - .map(|f| set_id == f.validator_set.id() && round >= f.start && round <= f.end) - .unwrap_or(false) + .map(|f| + // only from current set and only [filter.start, filter.end] + if set_id < f.validator_set.id() { + Consider::RejectPast + } else if set_id > f.validator_set.id() { + Consider::RejectFuture + } else if round < f.start { + Consider::RejectPast + } else if round > f.end { + Consider::RejectFuture + } else { + Consider::Accept + }) + .unwrap_or(Consider::RejectOutOfScope) } /// Return true if `round` is >= than `max(session_start, best_beefy)`, /// and proof `set_id` matches session set id. /// /// Latest concluded round is still considered alive to allow proper gossiping for it. - fn is_finality_proof_accepted(&self, round: NumberFor, set_id: ValidatorSetId) -> bool { + fn consider_finality_proof(&self, round: NumberFor, set_id: ValidatorSetId) -> Consider { self.inner .as_ref() - .map(|f| set_id == f.validator_set.id() && round >= f.start) - .unwrap_or(false) + .map(|f| + // only from current set and only >= filter.start + if round < f.start || set_id < f.validator_set.id() { + Consider::RejectPast + } else if set_id > f.validator_set.id() { + Consider::RejectFuture + } else { + Consider::Accept + } + ) + .unwrap_or(Consider::RejectOutOfScope) } /// Add new _known_ `hash` to the round's known votes. @@ -189,20 +235,26 @@ where gossip_filter: RwLock>, next_rebroadcast: Mutex, known_peers: Arc>>, + report_sender: TracingUnboundedSender, } impl GossipValidator where B: Block, { - pub fn new(known_peers: Arc>>) -> GossipValidator { - GossipValidator { + pub(crate) fn new( + known_peers: Arc>>, + ) -> (GossipValidator, TracingUnboundedReceiver) { + let (tx, rx) = tracing_unbounded("mpsc_beefy_gossip_validator", 10_000); + let val = GossipValidator { votes_topic: votes_topic::(), justifs_topic: proofs_topic::(), gossip_filter: RwLock::new(Filter::new()), next_rebroadcast: Mutex::new(Instant::now() + REBROADCAST_AFTER), known_peers, - } + report_sender: tx, + }; + (val, rx) } /// Update gossip validator filter. @@ -213,12 +265,16 @@ where self.gossip_filter.write().update(filter); } + fn report(&self, who: PeerId, cost_benefit: ReputationChange) { + let _ = self.report_sender.unbounded_send(PeerReport { who, cost_benefit }); + } + fn validate_vote( &self, vote: VoteMessage, AuthorityId, Signature>, sender: &PeerId, data: &[u8], - ) -> ValidationResult { + ) -> Action { let msg_hash = twox_64(data); let round = vote.commitment.block_number; let set_id = vote.commitment.validator_set_id; @@ -230,25 +286,37 @@ where { let filter = self.gossip_filter.read(); - if !filter.is_vote_accepted(round, set_id) { - return ValidationResult::Discard + match filter.consider_vote(round, set_id) { + Consider::RejectPast => return Action::Discard(cost::OUTDATED_MESSAGE), + Consider::RejectFuture => return Action::Discard(cost::FUTURE_MESSAGE), + Consider::RejectOutOfScope => return Action::Discard(cost::OUT_OF_SCOPE_MESSAGE), + Consider::Accept => {}, } if filter.is_known_vote(round, &msg_hash) { - return ValidationResult::ProcessAndKeep(self.votes_topic) + return Action::Keep(self.votes_topic, benefit::KNOWN_VOTE_MESSAGE) + } + + // ensure authority is part of the set. + if !filter + .validator_set() + .map(|set| set.validators().contains(&vote.id)) + .unwrap_or(false) + { + debug!(target: LOG_TARGET, "Message from voter not in validator set: {}", vote.id); + return Action::Discard(cost::UNKNOWN_VOTER) } } if BeefyKeystore::verify(&vote.id, &vote.signature, &vote.commitment.encode()) { self.gossip_filter.write().add_known_vote(round, msg_hash); - ValidationResult::ProcessAndKeep(self.votes_topic) + Action::Keep(self.votes_topic, benefit::VOTE_MESSAGE) } else { - // TODO: report peer debug!( target: LOG_TARGET, "🥩 Bad signature on message: {:?}, from: {:?}", vote, sender ); - ValidationResult::Discard + Action::Discard(cost::BAD_SIGNATURE) } } @@ -256,31 +324,38 @@ where &self, proof: BeefyVersionedFinalityProof, sender: &PeerId, - ) -> ValidationResult { + ) -> Action { let (round, set_id) = proof_block_num_and_set_id::(&proof); self.known_peers.lock().note_vote_for(*sender, round); let guard = self.gossip_filter.read(); - // Verify general usefulness of the justifications. - if !guard.is_finality_proof_accepted(round, set_id) { - return ValidationResult::Discard + // Verify general usefulness of the justification. + match guard.consider_finality_proof(round, set_id) { + Consider::RejectPast => return Action::Discard(cost::OUTDATED_MESSAGE), + Consider::RejectFuture => return Action::Discard(cost::FUTURE_MESSAGE), + Consider::RejectOutOfScope => return Action::Discard(cost::OUT_OF_SCOPE_MESSAGE), + Consider::Accept => {}, } // Verify justification signatures. guard .validator_set() .map(|validator_set| { - if let Ok(()) = verify_with_validator_set::(round, validator_set, &proof) { - ValidationResult::ProcessAndKeep(self.justifs_topic) - } else { - // TODO: report peer + if let Err((_, signatures_checked)) = + verify_with_validator_set::(round, validator_set, &proof) + { debug!( target: LOG_TARGET, "🥩 Bad signatures on message: {:?}, from: {:?}", proof, sender ); - ValidationResult::Discard + let mut cost = cost::INVALID_PROOF; + cost.value += + cost::PER_SIGNATURE_CHECKED.saturating_mul(signatures_checked as i32); + Action::Discard(cost) + } else { + Action::Keep(self.justifs_topic, benefit::VALIDATED_PROOF) } }) - .unwrap_or(ValidationResult::Discard) + .unwrap_or(Action::Discard(cost::OUT_OF_SCOPE_MESSAGE)) } } @@ -294,15 +369,32 @@ where fn validate( &self, - _context: &mut dyn ValidatorContext, + context: &mut dyn ValidatorContext, sender: &PeerId, mut data: &[u8], ) -> ValidationResult { - match GossipMessage::::decode(&mut data) { - Ok(GossipMessage::Vote(msg)) => self.validate_vote(msg, sender, data), + let raw = data; + let action = match GossipMessage::::decode(&mut data) { + Ok(GossipMessage::Vote(msg)) => self.validate_vote(msg, sender, raw), Ok(GossipMessage::FinalityProof(proof)) => self.validate_finality_proof(proof, sender), Err(e) => { debug!(target: LOG_TARGET, "Error decoding message: {}", e); + let bytes = raw.len().min(i32::MAX as usize) as i32; + let cost = ReputationChange::new( + bytes.saturating_mul(cost::PER_UNDECODABLE_BYTE), + "BEEFY: Bad packet", + ); + Action::Discard(cost) + }, + }; + match action { + Action::Keep(topic, cb) => { + self.report(*sender, cb); + context.broadcast_message(topic, data.to_vec(), false); + ValidationResult::ProcessAndKeep(topic) + }, + Action::Discard(cb) => { + self.report(*sender, cb); ValidationResult::Discard }, } @@ -314,13 +406,13 @@ where Ok(GossipMessage::Vote(msg)) => { let round = msg.commitment.block_number; let set_id = msg.commitment.validator_set_id; - let expired = !filter.is_vote_accepted(round, set_id); + let expired = filter.consider_vote(round, set_id) != Consider::Accept; trace!(target: LOG_TARGET, "🥩 Vote for round #{} expired: {}", round, expired); expired }, Ok(GossipMessage::FinalityProof(proof)) => { let (round, set_id) = proof_block_num_and_set_id::(&proof); - let expired = !filter.is_finality_proof_accepted(round, set_id); + let expired = filter.consider_finality_proof(round, set_id) != Consider::Accept; trace!( target: LOG_TARGET, "🥩 Finality proof for round #{} expired: {}", @@ -358,13 +450,13 @@ where Ok(GossipMessage::Vote(msg)) => { let round = msg.commitment.block_number; let set_id = msg.commitment.validator_set_id; - let allowed = filter.is_vote_accepted(round, set_id); + let allowed = filter.consider_vote(round, set_id) == Consider::Accept; trace!(target: LOG_TARGET, "🥩 Vote for round #{} allowed: {}", round, allowed); allowed }, Ok(GossipMessage::FinalityProof(proof)) => { let (round, set_id) = proof_block_num_and_set_id::(&proof); - let allowed = filter.is_finality_proof_accepted(round, set_id); + let allowed = filter.consider_finality_proof(round, set_id) == Consider::Accept; trace!( target: LOG_TARGET, "🥩 Finality proof for round #{} allowed: {}", @@ -409,15 +501,16 @@ pub(crate) mod tests { assert_eq!(filter.live_votes.len(), 3); assert!(filter.inner.is_none()); - assert!(!filter.is_vote_accepted(1, 1)); + assert_eq!(filter.consider_vote(1, 1), Consider::RejectOutOfScope); filter.update(GossipFilterCfg { start: 3, end: 10, validator_set: &validator_set }); assert_eq!(filter.live_votes.len(), 1); assert!(filter.live_votes.contains_key(&3)); - assert!(!filter.is_vote_accepted(2, 1)); - assert!(filter.is_vote_accepted(3, 1)); - assert!(filter.is_vote_accepted(4, 1)); - assert!(!filter.is_vote_accepted(4, 2)); + assert_eq!(filter.consider_vote(2, 1), Consider::RejectPast); + assert_eq!(filter.consider_vote(3, 1), Consider::Accept); + assert_eq!(filter.consider_vote(4, 1), Consider::Accept); + assert_eq!(filter.consider_vote(20, 1), Consider::RejectFuture); + assert_eq!(filter.consider_vote(4, 2), Consider::RejectFuture); let validator_set = ValidatorSet::::new(keys, 2).unwrap(); filter.update(GossipFilterCfg { start: 5, end: 10, validator_set: &validator_set }); @@ -430,9 +523,7 @@ pub(crate) mod tests { todo!() } - fn broadcast_message(&mut self, _topic: B::Hash, _message: Vec, _force: bool) { - todo!() - } + fn broadcast_message(&mut self, _topic: B::Hash, _message: Vec, _force: bool) {} fn send_message(&mut self, _who: &sc_network::PeerId, _message: Vec) { todo!() @@ -485,18 +576,39 @@ pub(crate) mod tests { fn should_validate_messages() { let keys = vec![Keyring::Alice.public()]; let validator_set = ValidatorSet::::new(keys.clone(), 0).unwrap(); - let gv = GossipValidator::::new(Arc::new(Mutex::new(KnownPeers::new()))); - gv.update_filter(GossipFilterCfg { start: 0, end: 10, validator_set: &validator_set }); - let sender = sc_network::PeerId::random(); + let (gv, mut report_stream) = + GossipValidator::::new(Arc::new(Mutex::new(KnownPeers::new()))); + let sender = PeerId::random(); let mut context = TestContext; + // reject message, decoding error + let bad_encoding = b"0000000000".as_slice(); + let expected_cost = ReputationChange::new( + (bad_encoding.len() as i32).saturating_mul(cost::PER_UNDECODABLE_BYTE), + "BEEFY: Bad packet", + ); + let mut expected_report = PeerReport { who: sender, cost_benefit: expected_cost }; + let res = gv.validate(&mut context, &sender, bad_encoding); + assert!(matches!(res, ValidationResult::Discard)); + assert_eq!(report_stream.try_recv().unwrap(), expected_report); + + // verify votes validation + let vote = dummy_vote(3); - let gossip_vote = GossipMessage::::Vote(vote.clone()); + let encoded = GossipMessage::::Vote(vote.clone()).encode(); - // first time the cache should be populated - let res = gv.validate(&mut context, &sender, &gossip_vote.encode()); + // filter not initialized + let res = gv.validate(&mut context, &sender, &encoded); + assert!(matches!(res, ValidationResult::Discard)); + expected_report.cost_benefit = cost::OUT_OF_SCOPE_MESSAGE; + assert_eq!(report_stream.try_recv().unwrap(), expected_report); + gv.update_filter(GossipFilterCfg { start: 0, end: 10, validator_set: &validator_set }); + // nothing in cache first time + let res = gv.validate(&mut context, &sender, &encoded); assert!(matches!(res, ValidationResult::ProcessAndKeep(_))); + expected_report.cost_benefit = benefit::VOTE_MESSAGE; + assert_eq!(report_stream.try_recv().unwrap(), expected_report); assert_eq!( gv.gossip_filter .read() @@ -507,43 +619,74 @@ pub(crate) mod tests { ); // second time we should hit the cache - let res = gv.validate(&mut context, &sender, &gossip_vote.encode()); + let res = gv.validate(&mut context, &sender, &encoded); assert!(matches!(res, ValidationResult::ProcessAndKeep(_))); + expected_report.cost_benefit = benefit::KNOWN_VOTE_MESSAGE; + assert_eq!(report_stream.try_recv().unwrap(), expected_report); + + // reject vote, voter not in validator set + let mut bad_vote = vote.clone(); + bad_vote.id = Keyring::Bob.public(); + let bad_vote = GossipMessage::::Vote(bad_vote).encode(); + let res = gv.validate(&mut context, &sender, &bad_vote); + assert!(matches!(res, ValidationResult::Discard)); + expected_report.cost_benefit = cost::UNKNOWN_VOTER; + assert_eq!(report_stream.try_recv().unwrap(), expected_report); - // next we should quickly reject if the round is not live - gv.update_filter(GossipFilterCfg { start: 7, end: 10, validator_set: &validator_set }); - + // reject if the round is not GRANDPA finalized + gv.update_filter(GossipFilterCfg { start: 1, end: 2, validator_set: &validator_set }); let number = vote.commitment.block_number; let set_id = vote.commitment.validator_set_id; - assert!(!gv.gossip_filter.read().is_vote_accepted(number, set_id)); + assert_eq!(gv.gossip_filter.read().consider_vote(number, set_id), Consider::RejectFuture); + let res = gv.validate(&mut context, &sender, &encoded); + assert!(matches!(res, ValidationResult::Discard)); + expected_report.cost_benefit = cost::FUTURE_MESSAGE; + assert_eq!(report_stream.try_recv().unwrap(), expected_report); - let res = gv.validate(&mut context, &sender, &vote.encode()); + // reject if the round is not live anymore + gv.update_filter(GossipFilterCfg { start: 7, end: 10, validator_set: &validator_set }); + let number = vote.commitment.block_number; + let set_id = vote.commitment.validator_set_id; + assert_eq!(gv.gossip_filter.read().consider_vote(number, set_id), Consider::RejectPast); + let res = gv.validate(&mut context, &sender, &encoded); assert!(matches!(res, ValidationResult::Discard)); + expected_report.cost_benefit = cost::OUTDATED_MESSAGE; + assert_eq!(report_stream.try_recv().unwrap(), expected_report); + + // now verify proofs validation // reject old proof let proof = dummy_proof(5, &validator_set); let encoded_proof = GossipMessage::::FinalityProof(proof).encode(); let res = gv.validate(&mut context, &sender, &encoded_proof); assert!(matches!(res, ValidationResult::Discard)); + expected_report.cost_benefit = cost::OUTDATED_MESSAGE; + assert_eq!(report_stream.try_recv().unwrap(), expected_report); // accept next proof with good set_id let proof = dummy_proof(7, &validator_set); let encoded_proof = GossipMessage::::FinalityProof(proof).encode(); let res = gv.validate(&mut context, &sender, &encoded_proof); assert!(matches!(res, ValidationResult::ProcessAndKeep(_))); + expected_report.cost_benefit = benefit::VALIDATED_PROOF; + assert_eq!(report_stream.try_recv().unwrap(), expected_report); // accept future proof with good set_id let proof = dummy_proof(20, &validator_set); let encoded_proof = GossipMessage::::FinalityProof(proof).encode(); let res = gv.validate(&mut context, &sender, &encoded_proof); assert!(matches!(res, ValidationResult::ProcessAndKeep(_))); + expected_report.cost_benefit = benefit::VALIDATED_PROOF; + assert_eq!(report_stream.try_recv().unwrap(), expected_report); - // reject proof, wrong set_id + // reject proof, future set_id let bad_validator_set = ValidatorSet::::new(keys, 1).unwrap(); let proof = dummy_proof(20, &bad_validator_set); let encoded_proof = GossipMessage::::FinalityProof(proof).encode(); let res = gv.validate(&mut context, &sender, &encoded_proof); assert!(matches!(res, ValidationResult::Discard)); + expected_report.cost_benefit = cost::FUTURE_MESSAGE; + assert_eq!(report_stream.try_recv().unwrap(), expected_report); // reject proof, bad signatures (Bob instead of Alice) let bad_validator_set = @@ -552,13 +695,16 @@ pub(crate) mod tests { let encoded_proof = GossipMessage::::FinalityProof(proof).encode(); let res = gv.validate(&mut context, &sender, &encoded_proof); assert!(matches!(res, ValidationResult::Discard)); + expected_report.cost_benefit = cost::INVALID_PROOF; + expected_report.cost_benefit.value += cost::PER_SIGNATURE_CHECKED; + assert_eq!(report_stream.try_recv().unwrap(), expected_report); } #[test] fn messages_allowed_and_expired() { let keys = vec![Keyring::Alice.public()]; let validator_set = ValidatorSet::::new(keys.clone(), 0).unwrap(); - let gv = GossipValidator::::new(Arc::new(Mutex::new(KnownPeers::new()))); + let (gv, _) = GossipValidator::::new(Arc::new(Mutex::new(KnownPeers::new()))); gv.update_filter(GossipFilterCfg { start: 0, end: 10, validator_set: &validator_set }); let sender = sc_network::PeerId::random(); let topic = Default::default(); @@ -635,7 +781,7 @@ pub(crate) mod tests { fn messages_rebroadcast() { let keys = vec![Keyring::Alice.public()]; let validator_set = ValidatorSet::::new(keys.clone(), 0).unwrap(); - let gv = GossipValidator::::new(Arc::new(Mutex::new(KnownPeers::new()))); + let (gv, _) = GossipValidator::::new(Arc::new(Mutex::new(KnownPeers::new()))); gv.update_filter(GossipFilterCfg { start: 0, end: 10, validator_set: &validator_set }); let sender = sc_network::PeerId::random(); let topic = Default::default(); diff --git a/client/consensus/beefy/src/communication/mod.rs b/client/consensus/beefy/src/communication/mod.rs index 13735a9d3211b..d8e4d22053628 100644 --- a/client/consensus/beefy/src/communication/mod.rs +++ b/client/consensus/beefy/src/communication/mod.rs @@ -73,6 +73,39 @@ pub fn beefy_peers_set_config( cfg } +// cost scalars for reporting peers. +mod cost { + use sc_network::ReputationChange as Rep; + // Message that's for an outdated round. + pub(super) const OUTDATED_MESSAGE: Rep = Rep::new(-50, "BEEFY: Past message"); + // Message that's from the future relative to our current set-id. + pub(super) const FUTURE_MESSAGE: Rep = Rep::new(-100, "BEEFY: Future message"); + // Vote message containing bad signature. + pub(super) const BAD_SIGNATURE: Rep = Rep::new(-100, "BEEFY: Bad signature"); + // Message received with vote from voter not in validator set. + pub(super) const UNKNOWN_VOTER: Rep = Rep::new(-150, "BEEFY: Unknown voter"); + // A message received that cannot be evaluated relative to our current state. + pub(super) const OUT_OF_SCOPE_MESSAGE: Rep = Rep::new(-500, "BEEFY: Out-of-scope message"); + // Message containing invalid proof. + pub(super) const INVALID_PROOF: Rep = Rep::new(-5000, "BEEFY: Invalid commit"); + // Reputation cost per signature checked for invalid proof. + pub(super) const PER_SIGNATURE_CHECKED: i32 = -25; + // Reputation cost per byte for un-decodable message. + pub(super) const PER_UNDECODABLE_BYTE: i32 = -5; + // On-demand request was refused by peer. + pub(super) const REFUSAL_RESPONSE: Rep = Rep::new(-100, "BEEFY: Proof request refused"); + // On-demand request for a proof that can't be found in the backend. + pub(super) const UNKOWN_PROOF_REQUEST: Rep = Rep::new(-150, "BEEFY: Unknown proof request"); +} + +// benefit scalars for reporting peers. +mod benefit { + use sc_network::ReputationChange as Rep; + pub(super) const VOTE_MESSAGE: Rep = Rep::new(100, "BEEFY: Round vote message"); + pub(super) const KNOWN_VOTE_MESSAGE: Rep = Rep::new(50, "BEEFY: Known vote"); + pub(super) const VALIDATED_PROOF: Rep = Rep::new(100, "BEEFY: Justification"); +} + #[cfg(test)] mod tests { use super::*; diff --git a/client/consensus/beefy/src/communication/peers.rs b/client/consensus/beefy/src/communication/peers.rs index c2fb06faddf0c..4704b8dcf4576 100644 --- a/client/consensus/beefy/src/communication/peers.rs +++ b/client/consensus/beefy/src/communication/peers.rs @@ -18,13 +18,17 @@ //! 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 sc_network::{PeerId, ReputationChange}; use sp_runtime::traits::{Block, NumberFor, Zero}; use std::collections::{HashMap, VecDeque}; +/// Report specifying a reputation change for a given peer. +#[derive(Debug, PartialEq)] +pub(crate) struct PeerReport { + pub who: PeerId, + pub cost_benefit: ReputationChange, +} + struct PeerData { last_voted_on: NumberFor, } diff --git a/client/consensus/beefy/src/communication/request_response/incoming_requests_handler.rs b/client/consensus/beefy/src/communication/request_response/incoming_requests_handler.rs index 1670e99828831..d4f4b59f0195e 100644 --- a/client/consensus/beefy/src/communication/request_response/incoming_requests_handler.rs +++ b/client/consensus/beefy/src/communication/request_response/incoming_requests_handler.rs @@ -32,9 +32,12 @@ use sp_runtime::traits::Block; use std::{marker::PhantomData, sync::Arc}; use crate::{ - communication::request_response::{ - on_demand_justifications_protocol_config, Error, JustificationRequest, - BEEFY_SYNC_LOG_TARGET, + communication::{ + cost, + request_response::{ + on_demand_justifications_protocol_config, Error, JustificationRequest, + BEEFY_SYNC_LOG_TARGET, + }, }, metric_inc, metrics::{register_metrics, OnDemandIncomingRequestsMetrics}, @@ -69,17 +72,20 @@ impl IncomingRequest { /// Params: /// - The raw request to decode /// - Reputation changes to apply for the peer in case decoding fails. - pub fn try_from_raw( + pub fn try_from_raw( raw: netconfig::IncomingRequest, - reputation_changes: Vec, - ) -> Result { + reputation_changes_on_err: F, + ) -> Result + where + F: FnOnce(usize) -> Vec, + { 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, + reputation_changes: reputation_changes_on_err(payload.len()), sent_feedback: None, }; if let Err(_) = pending_response.send(response) { @@ -111,11 +117,11 @@ impl IncomingRequestReceiver { pub async fn recv(&mut self, reputation_changes: F) -> Result, Error> where B: Block, - F: FnOnce() -> Vec, + F: FnOnce(usize) -> Vec, { let req = match self.raw.next().await { None => return Err(Error::RequestChannelExhausted), - Some(raw) => IncomingRequest::::try_from_raw(raw, reputation_changes())?, + Some(raw) => IncomingRequest::::try_from_raw(raw, reputation_changes)?, }; Ok(req) } @@ -159,26 +165,20 @@ where // 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 = 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(()) - }; - + let mut reputation_changes = vec![]; + let maybe_encoded_proof = self + .client + .block_hash(request.payload.begin) + .ok() + .flatten() + .and_then(|hash| self.client.justifications(hash).ok().flatten()) + .and_then(|justifs| justifs.get(BEEFY_ENGINE_ID).cloned()) + .ok_or_else(|| reputation_changes.push(cost::UNKOWN_PROOF_REQUEST)); request .pending_response .send(netconfig::OutgoingResponse { result: maybe_encoded_proof, - reputation_changes: Vec::new(), + reputation_changes, sent_feedback: None, }) .map_err(|_| Error::SendResponse) @@ -188,7 +188,17 @@ where pub async fn run(mut self) { trace!(target: BEEFY_SYNC_LOG_TARGET, "🥩 Running BeefyJustifsRequestHandler"); - while let Ok(request) = self.request_receiver.recv(|| vec![]).await { + while let Ok(request) = self + .request_receiver + .recv(|bytes| { + let bytes = bytes.min(i32::MAX as usize) as i32; + vec![ReputationChange::new( + bytes.saturating_mul(cost::PER_UNDECODABLE_BYTE), + "BEEFY: Bad request payload", + )] + }) + .await + { let peer = request.peer; match self.handle_request(request) { Ok(()) => { @@ -199,8 +209,8 @@ where ) }, Err(e) => { + // peer reputation changes already applied in `self.handle_request()` metric_inc!(self, beefy_failed_justification_responses); - // TODO (issue #12293): apply reputation changes here based on error type. debug!( target: BEEFY_SYNC_LOG_TARGET, "🥩 Failed to handle BEEFY justification request from {:?}: {}", peer, e, diff --git a/client/consensus/beefy/src/communication/request_response/mod.rs b/client/consensus/beefy/src/communication/request_response/mod.rs index c528d06bbe0c5..545ab18cf1d34 100644 --- a/client/consensus/beefy/src/communication/request_response/mod.rs +++ b/client/consensus/beefy/src/communication/request_response/mod.rs @@ -30,7 +30,7 @@ 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 crate::communication::{beefy_protocol_name::justifications_protocol_name, peers::PeerReport}; use incoming_requests_handler::IncomingRequestReceiver; // 10 seems reasonable, considering justifs are explicitly requested only @@ -76,7 +76,7 @@ pub struct JustificationRequest { } #[derive(Debug, thiserror::Error)] -pub enum Error { +pub(crate) enum Error { #[error(transparent)] Client(#[from] sp_blockchain::Error), @@ -99,5 +99,8 @@ pub enum Error { SendResponse, #[error("Received invalid response.")] - InvalidResponse, + InvalidResponse(PeerReport), + + #[error("Internal error while getting response.")] + ResponseError, } diff --git a/client/consensus/beefy/src/communication/request_response/outgoing_requests_engine.rs b/client/consensus/beefy/src/communication/request_response/outgoing_requests_engine.rs index fbf464bd639d9..10105ff2d417d 100644 --- a/client/consensus/beefy/src/communication/request_response/outgoing_requests_engine.rs +++ b/client/consensus/beefy/src/communication/request_response/outgoing_requests_engine.rs @@ -31,7 +31,11 @@ use sp_runtime::traits::{Block, NumberFor}; use std::{collections::VecDeque, result::Result, sync::Arc}; use crate::{ - communication::request_response::{Error, JustificationRequest, BEEFY_SYNC_LOG_TARGET}, + communication::{ + benefit, cost, + peers::PeerReport, + request_response::{Error, JustificationRequest, BEEFY_SYNC_LOG_TARGET}, + }, justification::{decode_and_verify_finality_proof, BeefyVersionedFinalityProof}, metric_inc, metrics::{register_metrics, OnDemandOutgoingRequestsMetrics}, @@ -54,6 +58,16 @@ enum State { AwaitingResponse(PeerId, RequestInfo, ResponseReceiver), } +/// Possible engine responses. +pub(crate) enum ResponseInfo { + /// No peer response available yet. + Pending, + /// Valid justification provided alongside peer reputation changes. + ValidProof(BeefyVersionedFinalityProof, PeerReport), + /// No justification yet, only peer reputation changes. + PeerReport(PeerReport), +} + pub struct OnDemandJustificationsEngine { network: Arc, protocol_name: ProtocolName, @@ -84,12 +98,10 @@ impl OnDemandJustificationsEngine { } 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().further_than(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) { @@ -159,24 +171,19 @@ impl OnDemandJustificationsEngine { fn process_response( &mut self, - peer: PeerId, + peer: &PeerId, req_info: &RequestInfo, response: Result, ) -> Result, Error> { response .map_err(|e| { - metric_inc!(self, beefy_on_demand_justification_peer_hang_up); debug!( target: BEEFY_SYNC_LOG_TARGET, - "🥩 for on demand justification #{:?}, peer {:?} hung up: {:?}", - req_info.block, - peer, - e + "🥩 on-demand sc-network channel sender closed, err: {:?}", e ); - Error::InvalidResponse + Error::ResponseError })? .map_err(|e| { - metric_inc!(self, beefy_on_demand_justification_peer_error); debug!( target: BEEFY_SYNC_LOG_TARGET, "🥩 for on demand justification #{:?}, peer {:?} error: {:?}", @@ -184,7 +191,18 @@ impl OnDemandJustificationsEngine { peer, e ); - Error::InvalidResponse + match e { + RequestFailure::Refused => { + metric_inc!(self, beefy_on_demand_justification_peer_refused); + let peer_report = + PeerReport { who: *peer, cost_benefit: cost::REFUSAL_RESPONSE }; + Error::InvalidResponse(peer_report) + }, + _ => { + metric_inc!(self, beefy_on_demand_justification_peer_error); + Error::ResponseError + }, + } }) .and_then(|encoded| { decode_and_verify_finality_proof::( @@ -192,23 +210,26 @@ impl OnDemandJustificationsEngine { req_info.block, &req_info.active_set, ) - .map_err(|e| { + .map_err(|(err, signatures_checked)| { metric_inc!(self, beefy_on_demand_justification_invalid_proof); debug!( target: BEEFY_SYNC_LOG_TARGET, "🥩 for on demand justification #{:?}, peer {:?} responded with invalid proof: {:?}", - req_info.block, peer, e + req_info.block, peer, err ); - Error::InvalidResponse + let mut cost = cost::INVALID_PROOF; + cost.value += + cost::PER_SIGNATURE_CHECKED.saturating_mul(signatures_checked as i32); + Error::InvalidResponse(PeerReport { who: *peer, cost_benefit: cost }) }) }) } - pub async fn next(&mut self) -> Option> { + pub(crate) async fn next(&mut self) -> ResponseInfo { let (peer, req_info, resp) = match &mut self.state { State::Idle => { futures::future::pending::<()>().await; - return None + return ResponseInfo::Pending }, State::AwaitingResponse(peer, req_info, receiver) => { let resp = receiver.await; @@ -220,8 +241,8 @@ impl OnDemandJustificationsEngine { self.state = State::Idle; let block = req_info.block; - self.process_response(peer, &req_info, resp) - .map_err(|_| { + match self.process_response(&peer, &req_info, resp) { + Err(err) => { // No valid justification received, try next peer in our set. if let Some(peer) = self.try_next_peer() { self.request_from_peer(peer, req_info); @@ -231,15 +252,22 @@ impl OnDemandJustificationsEngine { "🥩 ran out of peers to request justif #{:?} from", block ); } - }) - .map(|proof| { + // Report peer based on error type. + if let Error::InvalidResponse(peer_report) = err { + ResponseInfo::PeerReport(peer_report) + } else { + ResponseInfo::Pending + } + }, + Ok(proof) => { metric_inc!(self, beefy_on_demand_justification_good_proof); debug!( target: BEEFY_SYNC_LOG_TARGET, "🥩 received valid on-demand justif #{:?} from {:?}", block, peer ); - proof - }) - .ok() + let peer_report = PeerReport { who: peer, cost_benefit: benefit::VALIDATED_PROOF }; + ResponseInfo::ValidProof(proof, peer_report) + }, + } } } diff --git a/client/consensus/beefy/src/import.rs b/client/consensus/beefy/src/import.rs index dd2ed92ef8353..bda8169d95013 100644 --- a/client/consensus/beefy/src/import.rs +++ b/client/consensus/beefy/src/import.rs @@ -109,6 +109,7 @@ where .ok_or_else(|| ImportError("Unknown validator set".to_string()))?; decode_and_verify_finality_proof::(&encoded[..], number, &validator_set) + .map_err(|(err, _)| err) } } diff --git a/client/consensus/beefy/src/justification.rs b/client/consensus/beefy/src/justification.rs index 5175fd17d4ea3..731acdfa63389 100644 --- a/client/consensus/beefy/src/justification.rs +++ b/client/consensus/beefy/src/justification.rs @@ -42,9 +42,9 @@ pub(crate) fn decode_and_verify_finality_proof( encoded: &[u8], target_number: NumberFor, validator_set: &ValidatorSet, -) -> Result, ConsensusError> { +) -> Result, (ConsensusError, u32)> { let proof = >::decode(&mut &*encoded) - .map_err(|_| ConsensusError::InvalidJustification)?; + .map_err(|_| (ConsensusError::InvalidJustification, 0))?; verify_with_validator_set::(target_number, validator_set, &proof).map(|_| proof) } @@ -53,14 +53,15 @@ pub(crate) fn verify_with_validator_set( target_number: NumberFor, validator_set: &ValidatorSet, proof: &BeefyVersionedFinalityProof, -) -> Result<(), ConsensusError> { +) -> Result<(), (ConsensusError, u32)> { + let mut signatures_checked = 0u32; 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) + return Err((ConsensusError::InvalidJustification, 0)) } // Arrangement of signatures in the commitment should be in the same order @@ -73,14 +74,17 @@ pub(crate) fn verify_with_validator_set( .filter(|(id, signature)| { signature .as_ref() - .map(|sig| BeefyKeystore::verify(id, sig, &message[..])) + .map(|sig| { + signatures_checked += 1; + BeefyKeystore::verify(id, sig, &message[..]) + }) .unwrap_or(false) }) .count(); if valid_signatures >= crate::round::threshold(validator_set.len()) { Ok(()) } else { - Err(ConsensusError::InvalidJustification) + Err((ConsensusError::InvalidJustification, signatures_checked)) } }, } @@ -127,16 +131,16 @@ pub(crate) mod tests { // 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)"), + Err((ConsensusError::InvalidJustification, 0)) => (), + e => assert!(false, "Got unexpected {:?}", e), }; // 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)"), + Err((ConsensusError::InvalidJustification, 0)) => (), + e => assert!(false, "Got unexpected {:?}", e), }; // wrong signatures length -> should fail verification @@ -147,8 +151,8 @@ pub(crate) mod tests { }; 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)"), + Err((ConsensusError::InvalidJustification, 0)) => (), + e => assert!(false, "Got unexpected {:?}", e), }; // not enough signatures -> should fail verification @@ -158,9 +162,9 @@ pub(crate) mod tests { }; // remove a signature (but same length) *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)"), + match verify_with_validator_set::(block_num, &validator_set, &bad_proof.into()) { + Err((ConsensusError::InvalidJustification, 2)) => (), + e => assert!(false, "Got unexpected {:?}", e), }; // not enough _correct_ signatures -> should fail verification @@ -171,9 +175,9 @@ pub(crate) mod tests { // change a signature to a different key *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)"), + match verify_with_validator_set::(block_num, &validator_set, &bad_proof.into()) { + Err((ConsensusError::InvalidJustification, 3)) => (), + e => assert!(false, "Got unexpected {:?}", e), }; } diff --git a/client/consensus/beefy/src/lib.rs b/client/consensus/beefy/src/lib.rs index 3c66cc6eb716d..d3e5e4bc68936 100644 --- a/client/consensus/beefy/src/lib.rs +++ b/client/consensus/beefy/src/lib.rs @@ -52,7 +52,11 @@ use sp_consensus_beefy::{ use sp_keystore::KeystorePtr; use sp_mmr_primitives::MmrApi; use sp_runtime::traits::{Block, Zero}; -use std::{collections::VecDeque, marker::PhantomData, sync::Arc}; +use std::{ + collections::{BTreeMap, VecDeque}, + marker::PhantomData, + sync::Arc, +}; mod aux_schema; mod error; @@ -249,9 +253,10 @@ pub async fn start_beefy_gadget( let known_peers = Arc::new(Mutex::new(KnownPeers::new())); // Default votes filter is to discard everything. // Validator is updated later with correct starting round and set id. - let gossip_validator = - Arc::new(communication::gossip::GossipValidator::new(known_peers.clone())); - let mut gossip_engine = sc_network_gossip::GossipEngine::new( + let (gossip_validator, gossip_report_stream) = + communication::gossip::GossipValidator::new(known_peers.clone()); + let gossip_validator = Arc::new(gossip_validator); + let mut gossip_engine = GossipEngine::new( network.clone(), sync.clone(), gossip_protocol_name, @@ -295,7 +300,7 @@ pub async fn start_beefy_gadget( return } - let worker_params = worker::WorkerParams { + let worker = worker::BeefyWorker { backend, payload_provider, runtime, @@ -303,14 +308,14 @@ pub async fn start_beefy_gadget( key_store: key_store.into(), gossip_engine, gossip_validator, + gossip_report_stream, on_demand_justifications, links, metrics, + pending_justifications: BTreeMap::new(), persisted_state, }; - let worker = worker::BeefyWorker::<_, _, _, _, _>::new(worker_params); - futures::future::join( worker.run(block_import_justif, finality_notifications), on_demand_justifications_handler.run(), diff --git a/client/consensus/beefy/src/metrics.rs b/client/consensus/beefy/src/metrics.rs index 6653763fc6754..031748bdceab5 100644 --- a/client/consensus/beefy/src/metrics.rs +++ b/client/consensus/beefy/src/metrics.rs @@ -228,8 +228,8 @@ impl PrometheusRegister for OnDemandIncomingRequestsMetrics { pub struct OnDemandOutgoingRequestsMetrics { /// Number of times there was no good peer to request justification from pub beefy_on_demand_justification_no_peer_to_request_from: Counter, - /// Number of on-demand justification peer hang up - pub beefy_on_demand_justification_peer_hang_up: Counter, + /// Number of on-demand justification peer refused valid requests + pub beefy_on_demand_justification_peer_refused: Counter, /// Number of on-demand justification peer error pub beefy_on_demand_justification_peer_error: Counter, /// Number of on-demand justification invalid proof @@ -249,10 +249,10 @@ impl PrometheusRegister for OnDemandOutgoingRequestsMetrics { )?, registry, )?, - beefy_on_demand_justification_peer_hang_up: register( + beefy_on_demand_justification_peer_refused: register( Counter::new( - "substrate_beefy_on_demand_justification_peer_hang_up", - "Number of on-demand justification peer hang up", + "beefy_on_demand_justification_peer_refused", + "Number of on-demand justification peer refused valid requests", )?, registry, )?, diff --git a/client/consensus/beefy/src/tests.rs b/client/consensus/beefy/src/tests.rs index f36c2cd68f97f..48ecebdac3581 100644 --- a/client/consensus/beefy/src/tests.rs +++ b/client/consensus/beefy/src/tests.rs @@ -24,6 +24,7 @@ use crate::{ communication::{ gossip::{ proofs_topic, tests::sign_commitment, votes_topic, GossipFilterCfg, GossipMessage, + GossipValidator, }, request_response::{on_demand_justifications_protocol_config, BeefyJustifsRequestHandler}, }, @@ -357,8 +358,8 @@ async fn voter_init_setup( ) -> sp_blockchain::Result> { let backend = net.peer(0).client().as_backend(); let known_peers = Arc::new(Mutex::new(KnownPeers::new())); - let gossip_validator = - Arc::new(crate::communication::gossip::GossipValidator::new(known_peers)); + let (gossip_validator, _) = GossipValidator::new(known_peers); + let gossip_validator = Arc::new(gossip_validator); let mut gossip_engine = sc_network_gossip::GossipEngine::new( net.peer(0).network_service().clone(), net.peer(0).sync_service().clone(), @@ -1262,8 +1263,8 @@ async fn gossipped_finality_proofs() { let charlie = &net.peers[2]; let known_peers = Arc::new(Mutex::new(KnownPeers::::new())); // Charlie will run just the gossip engine and not the full voter. - let charlie_gossip_validator = - Arc::new(crate::communication::gossip::GossipValidator::new(known_peers)); + let (gossip_validator, _) = GossipValidator::new(known_peers); + let charlie_gossip_validator = Arc::new(gossip_validator); charlie_gossip_validator.update_filter(GossipFilterCfg:: { start: 1, end: 10, diff --git a/client/consensus/beefy/src/worker.rs b/client/consensus/beefy/src/worker.rs index 19225ec214578..c05de197d58fd 100644 --- a/client/consensus/beefy/src/worker.rs +++ b/client/consensus/beefy/src/worker.rs @@ -19,7 +19,8 @@ use crate::{ communication::{ gossip::{proofs_topic, votes_topic, GossipFilterCfg, GossipMessage, GossipValidator}, - request_response::outgoing_requests_engine::OnDemandJustificationsEngine, + peers::PeerReport, + request_response::outgoing_requests_engine::{OnDemandJustificationsEngine, ResponseInfo}, }, error::Error, justification::BeefyVersionedFinalityProof, @@ -34,7 +35,7 @@ use futures::{stream::Fuse, FutureExt, StreamExt}; use log::{debug, error, info, log_enabled, trace, warn}; use sc_client_api::{Backend, FinalityNotification, FinalityNotifications, HeaderBackend}; use sc_network_gossip::GossipEngine; -use sc_utils::notification::NotificationReceiver; +use sc_utils::{mpsc::TracingUnboundedReceiver, notification::NotificationReceiver}; use sp_api::{BlockId, ProvideRuntimeApi}; use sp_arithmetic::traits::{AtLeast32Bit, Saturating}; use sp_consensus::SyncOracle; @@ -255,20 +256,6 @@ impl VoterOracle { } } -pub(crate) struct WorkerParams { - pub backend: Arc, - pub payload_provider: P, - pub runtime: Arc, - pub sync: Arc, - pub key_store: BeefyKeystore, - pub gossip_engine: GossipEngine, - pub gossip_validator: Arc>, - pub on_demand_justifications: OnDemandJustificationsEngine, - pub links: BeefyVoterLinks, - pub metrics: Option, - pub persisted_state: PersistedState, -} - #[derive(Debug, Decode, Encode, PartialEq)] pub(crate) struct PersistedState { /// Best block we voted on. @@ -311,28 +298,29 @@ impl PersistedState { /// A BEEFY worker plays the BEEFY protocol pub(crate) struct BeefyWorker { // utilities - backend: Arc, - payload_provider: P, - runtime: Arc, - sync: Arc, - key_store: BeefyKeystore, + pub backend: Arc, + pub payload_provider: P, + pub runtime: Arc, + pub sync: Arc, + pub key_store: BeefyKeystore, // communication - gossip_engine: GossipEngine, - gossip_validator: Arc>, - on_demand_justifications: OnDemandJustificationsEngine, + pub gossip_engine: GossipEngine, + pub gossip_validator: Arc>, + pub gossip_report_stream: TracingUnboundedReceiver, + pub on_demand_justifications: OnDemandJustificationsEngine, // channels /// Links between the block importer, the background voter and the RPC layer. - links: BeefyVoterLinks, + pub links: BeefyVoterLinks, // voter state /// BEEFY client metrics. - metrics: Option, + pub metrics: Option, /// Buffer holding justifications for future processing. - pending_justifications: BTreeMap, BeefyVersionedFinalityProof>, + pub pending_justifications: BTreeMap, BeefyVersionedFinalityProof>, /// Persisted voter state. - persisted_state: PersistedState, + pub persisted_state: PersistedState, } impl BeefyWorker @@ -344,43 +332,6 @@ where R: ProvideRuntimeApi, R::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 { - backend, - payload_provider, - runtime, - key_store, - sync, - gossip_engine, - gossip_validator, - on_demand_justifications, - links, - metrics, - persisted_state, - } = worker_params; - - BeefyWorker { - backend, - payload_provider, - runtime, - sync, - key_store, - gossip_engine, - gossip_validator, - on_demand_justifications, - links, - metrics, - pending_justifications: BTreeMap::new(), - persisted_state, - } - } - fn best_grandpa_block(&self) -> NumberFor { *self.persisted_state.voting_oracle.best_grandpa_block_header.number() } @@ -849,7 +800,12 @@ where // Act on changed 'state'. self.process_new_state(); + // Mutable reference used to drive the gossip engine. let mut gossip_engine = &mut self.gossip_engine; + // Use temp val and report after async section, + // to avoid having to Mutex-wrap `gossip_engine`. + let mut gossip_report: Option = None; + // Wait for, and handle external events. // The branches below only change 'state', actual voting happens afterwards, // based on the new resulting 'state'. @@ -870,11 +826,16 @@ where return; }, // 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: LOG_TARGET, "🥩 {}", err); - } + response_info = self.on_demand_justifications.next().fuse() => { + match response_info { + ResponseInfo::ValidProof(justif, peer_report) => { + if let Err(err) = self.triage_incoming_justif(justif) { + debug!(target: LOG_TARGET, "🥩 {}", err); + } + gossip_report = Some(peer_report); + }, + ResponseInfo::PeerReport(peer_report) => gossip_report = Some(peer_report), + ResponseInfo::Pending => (), } }, justif = block_import_justif.next() => { @@ -918,6 +879,13 @@ where return; } }, + // Process peer reports. + report = self.gossip_report_stream.next() => { + gossip_report = report; + }, + } + if let Some(PeerReport { who, cost_benefit }) = gossip_report { + self.gossip_engine.report(who, cost_benefit); } } } @@ -1122,7 +1090,8 @@ pub(crate) mod tests { let network = peer.network_service().clone(); let sync = peer.sync_service().clone(); let known_peers = Arc::new(Mutex::new(KnownPeers::new())); - let gossip_validator = Arc::new(GossipValidator::new(known_peers.clone())); + let (gossip_validator, gossip_report_stream) = GossipValidator::new(known_peers.clone()); + let gossip_validator = Arc::new(gossip_validator); let gossip_engine = GossipEngine::new( network.clone(), sync.clone(), @@ -1152,7 +1121,7 @@ pub(crate) mod tests { ) .unwrap(); let payload_provider = MmrRootProvider::new(api.clone()); - let worker_params = crate::worker::WorkerParams { + BeefyWorker { backend, payload_provider, runtime: api, @@ -1160,12 +1129,13 @@ pub(crate) mod tests { links, gossip_engine, gossip_validator, + gossip_report_stream, metrics, sync: Arc::new(sync), on_demand_justifications, + pending_justifications: BTreeMap::new(), persisted_state, - }; - BeefyWorker::<_, _, _, _, _>::new(worker_params) + } } #[test] From ea9ce4c0af36310c0b0db264ab12cf4766b83750 Mon Sep 17 00:00:00 2001 From: Roman Useinov Date: Wed, 12 Apr 2023 14:14:06 +0200 Subject: [PATCH 641/715] [Deps] Bump scale-info to match cumulus and polkadot (#13873) * [Deps] Bump scale-info to match cumulus and polkadot * fix Cargo.lock * fix identity * more fixes * fix * fixes * more fixes --- 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/consensus/babe/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/benchmarking/pov/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/primitives/Cargo.toml | 2 +- frame/conviction-voting/Cargo.toml | 2 +- frame/democracy/Cargo.toml | 2 +- .../election-provider-multi-phase/Cargo.toml | 2 +- frame/election-provider-support/Cargo.toml | 2 +- .../solution-type/fuzzer/Cargo.toml | 2 +- frame/examples/basic/Cargo.toml | 2 +- frame/examples/offchain-worker/Cargo.toml | 2 +- frame/executive/Cargo.toml | 2 +- frame/fast-unstake/Cargo.toml | 2 +- frame/glutton/Cargo.toml | 2 +- frame/grandpa/Cargo.toml | 2 +- frame/identity/Cargo.toml | 2 +- frame/identity/src/types.rs | 18 +++++----- frame/im-online/Cargo.toml | 2 +- frame/indices/Cargo.toml | 2 +- .../Cargo.toml | 2 +- frame/lottery/Cargo.toml | 2 +- frame/membership/Cargo.toml | 2 +- frame/merkle-mountain-range/Cargo.toml | 2 +- frame/message-queue/Cargo.toml | 2 +- frame/multisig/Cargo.toml | 2 +- frame/nfts/Cargo.toml | 2 +- frame/nicks/Cargo.toml | 2 +- frame/nis/Cargo.toml | 2 +- frame/node-authorization/Cargo.toml | 2 +- frame/nomination-pools/Cargo.toml | 2 +- .../nomination-pools/benchmarking/Cargo.toml | 2 +- frame/offences/Cargo.toml | 2 +- frame/preimage/Cargo.toml | 2 +- frame/proxy/Cargo.toml | 2 +- frame/recovery/Cargo.toml | 2 +- frame/referenda/Cargo.toml | 2 +- frame/remark/Cargo.toml | 2 +- frame/root-offences/Cargo.toml | 2 +- frame/root-testing/Cargo.toml | 2 +- frame/scheduler/Cargo.toml | 2 +- frame/scored-pool/Cargo.toml | 2 +- frame/session/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/support/test/tests/pallet.rs | 6 ++-- .../test/tests/pallet_compatibility.rs | 36 +++++++++---------- .../tests/pallet_compatibility_instance.rs | 36 +++++++++---------- 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-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/consensus/aura/Cargo.toml | 2 +- primitives/consensus/babe/Cargo.toml | 2 +- primitives/consensus/beefy/Cargo.toml | 2 +- primitives/consensus/grandpa/Cargo.toml | 2 +- primitives/consensus/vrf/Cargo.toml | 2 +- primitives/core/Cargo.toml | 2 +- primitives/inherents/Cargo.toml | 2 +- primitives/merkle-mountain-range/Cargo.toml | 2 +- primitives/npos-elections/Cargo.toml | 2 +- primitives/npos-elections/fuzzer/Cargo.toml | 2 +- primitives/runtime/Cargo.toml | 2 +- primitives/runtime/src/generic/digest.rs | 8 ++--- primitives/session/Cargo.toml | 2 +- primitives/staking/Cargo.toml | 2 +- .../transaction-storage-proof/Cargo.toml | 2 +- primitives/trie/Cargo.toml | 2 +- primitives/version/Cargo.toml | 2 +- primitives/weights/Cargo.toml | 2 +- test-utils/runtime/Cargo.toml | 2 +- .../rpc/state-trie-migration-rpc/Cargo.toml | 2 +- 108 files changed, 158 insertions(+), 158 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f55180f9ca942..6a1f29aa28e20 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9698,9 +9698,9 @@ dependencies = [ [[package]] name = "scale-info" -version = "2.3.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "001cf62ece89779fd16105b5f515ad0e5cedcd5440d3dd806bb067978e7c3608" +checksum = "0cfdffd972d76b22f3d7f81c8be34b2296afd3a25e0a547bd9abe340a4dbbe97" dependencies = [ "bitvec", "cfg-if", @@ -9712,9 +9712,9 @@ dependencies = [ [[package]] name = "scale-info-derive" -version = "2.3.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "303959cf613a6f6efd19ed4b4ad5bf79966a13352716299ad532cfb115f4205c" +checksum = "61fa974aea2d63dd18a4ec3a49d59af9f34178c73a4f56d2f18205628d00681e" 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 ddf7c6e52fb2f..bb6d8c511af7e 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.2.2", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } 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 8915061c17c6d..930c5b5c49ade 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.2.2", default-features = false, features = ["derive"] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } 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 cb661f536f7b7..c4711adcb0e82 100644 --- a/bin/node/executor/Cargo.toml +++ b/bin/node/executor/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.2.2" } -scale-info = { version = "2.1.1", features = ["derive"] } +scale-info = { version = "2.5.0", features = ["derive"] } frame-benchmarking = { version = "4.0.0-dev", path = "../../../frame/benchmarking" } node-primitives = { version = "2.0.0", path = "../primitives" } kitchensink-runtime = { version = "3.0.0-dev", path = "../runtime" } diff --git a/bin/node/primitives/Cargo.toml b/bin/node/primitives/Cargo.toml index 1f515f3e3a5b5..78cbf67ce7710 100644 --- a/bin/node/primitives/Cargo.toml +++ b/bin/node/primitives/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../../frame/system" } 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" } diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index bc9f3af9d879a..65a8d208d7f4c 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -20,7 +20,7 @@ codec = { package = "parity-scale-codec", version = "3.2.2", default-features = "derive", "max-encoded-len", ] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } static_assertions = "1.1.0" log = { version = "0.4.17", default-features = false } diff --git a/client/consensus/babe/Cargo.toml b/client/consensus/babe/Cargo.toml index 8088bef9d7e1b..d10ef21c4dad4 100644 --- a/client/consensus/babe/Cargo.toml +++ b/client/consensus/babe/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-trait = "0.1.57" -scale-info = { version = "2.1.1", features = ["derive"] } +scale-info = { version = "2.5.0", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.2.2", features = ["derive"] } futures = "0.3.21" log = "0.4.17" diff --git a/client/rpc-api/Cargo.toml b/client/rpc-api/Cargo.toml index 261339f131888..ba18a1d4fc70d 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.2.2" } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"] } serde_json = "1.0.85" thiserror = "1.0" diff --git a/frame/assets/Cargo.toml b/frame/assets/Cargo.toml index 6fe0e3e6c3042..d3adc47f5f803 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.2.2", default-features = false } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } # Needed for various traits. In our case, `OnFinalize`. sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } diff --git a/frame/atomic-swap/Cargo.toml b/frame/atomic-swap/Cargo.toml index 9c3bcf73af985..fb0f9c0e47957 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.2.2", default-features = false } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } 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 = "7.0.0", default-features = false, path = "../../primitives/core" } diff --git a/frame/aura/Cargo.toml b/frame/aura/Cargo.toml index d2fd5a5b9c372..ee6465ad3967f 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.2.2", default-features = false, features = ["derive", "max-encoded-len"] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.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-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 50c6c411c5ae0..d8693bd85bffb 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.2.2", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } 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 a205c51f9c62d..6d8cdd9371e94 100644 --- a/frame/authorship/Cargo.toml +++ b/frame/authorship/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "3.2.2", default-features = "derive", ] } impl-trait-for-tuples = "0.2.2" -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.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 = "7.0.0", default-features = false, path = "../../primitives/runtime" } diff --git a/frame/babe/Cargo.toml b/frame/babe/Cargo.toml index aa581392721ae..c4f6592dba9e1 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.2.2", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } 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 379698b1d39e1..1678ce1ba2ac6 100644 --- a/frame/bags-list/Cargo.toml +++ b/frame/bags-list/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] # parity codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } # primitives sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } diff --git a/frame/balances/Cargo.toml b/frame/balances/Cargo.toml index 9646a934df00e..b3457dd8d141c 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.2.2", default-features = false, features = ["derive", "max-encoded-len"] } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } 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 721e24282c45b..9840162149a38 100644 --- a/frame/beefy-mmr/Cargo.toml +++ b/frame/beefy-mmr/Cargo.toml @@ -12,7 +12,7 @@ homepage = "https://substrate.io" array-bytes = { version = "4.1", optional = true } codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } serde = { version = "1.0.136", optional = true } binary-merkle-tree = { version = "4.0.0-dev", default-features = false, path = "../../utils/binary-merkle-tree" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } diff --git a/frame/beefy/Cargo.toml b/frame/beefy/Cargo.toml index 3778ca5f37a56..21c96ff952731 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.2.2", default-features = false, features = ["derive"] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } 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/benchmarking/Cargo.toml b/frame/benchmarking/Cargo.toml index 7b8a7c5eaa940..bebe74b1f4b3e 100644 --- a/frame/benchmarking/Cargo.toml +++ b/frame/benchmarking/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "3.2.2", default-features = linregress = { version = "0.5.1", optional = true } log = { version = "0.4.17", default-features = false } paste = "1.0" -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } serde = { version = "1.0.136", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-support-procedural = { version = "4.0.0-dev", default-features = false, path = "../support/procedural" } diff --git a/frame/benchmarking/pov/Cargo.toml b/frame/benchmarking/pov/Cargo.toml index d885821bc1fc7..28358142b674a 100644 --- a/frame/benchmarking/pov/Cargo.toml +++ b/frame/benchmarking/pov/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.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } 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" } diff --git a/frame/bounties/Cargo.toml b/frame/bounties/Cargo.toml index dcb1adae05777..a2f39ccd7ec0b 100644 --- a/frame/bounties/Cargo.toml +++ b/frame/bounties/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "3.2.2", default-features = "derive", ] } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } 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 8d29b7619759d..48fa222616152 100644 --- a/frame/child-bounties/Cargo.toml +++ b/frame/child-bounties/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "3.2.2", default-features = "derive", ] } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } 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 26cd5a8ab44cc..7ae8817474a47 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.2.2", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } 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 f357a21b9cf5e..6ab60846fd412 100644 --- a/frame/contracts/Cargo.toml +++ b/frame/contracts/Cargo.toml @@ -19,7 +19,7 @@ codec = { package = "parity-scale-codec", version = "3.2.2", default-features = "derive", "max-encoded-len", ] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } log = { version = "0.4", default-features = false } wasm-instrument = { version = "0.4", default-features = false } serde = { version = "1", optional = true, features = ["derive"] } diff --git a/frame/contracts/primitives/Cargo.toml b/frame/contracts/primitives/Cargo.toml index 2460edc5a7b2f..b643f03a9d511 100644 --- a/frame/contracts/primitives/Cargo.toml +++ b/frame/contracts/primitives/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] bitflags = "1.0" -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } # Substrate Dependencies (This crate should not rely on frame) diff --git a/frame/conviction-voting/Cargo.toml b/frame/conviction-voting/Cargo.toml index d112c54fb64a7..f9390d6b6efe1 100644 --- a/frame/conviction-voting/Cargo.toml +++ b/frame/conviction-voting/Cargo.toml @@ -18,7 +18,7 @@ codec = { package = "parity-scale-codec", version = "3.2.2", default-features = "derive", "max-encoded-len", ] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } serde = { version = "1.0.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 fa107218cf698..1f46bfaed8c0b 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.2.2", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } 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 aa734850aae43..c88ed0120fe59 100644 --- a/frame/election-provider-multi-phase/Cargo.toml +++ b/frame/election-provider-multi-phase/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.1.1", default-features = false, features = [ +scale-info = { version = "2.5.0", 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 114caee793f1a..a519d964c60dc 100644 --- a/frame/election-provider-support/Cargo.toml +++ b/frame/election-provider-support/Cargo.toml @@ -13,7 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } 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/fuzzer/Cargo.toml b/frame/election-provider-support/solution-type/fuzzer/Cargo.toml index 9275692788d48..580e5eba9247d 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.2.2", default-features = false, features = ["derive"] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } frame-election-provider-solution-type = { version = "4.0.0-dev", path = ".." } frame-election-provider-support = { version = "4.0.0-dev", path = "../.." } sp-arithmetic = { version = "6.0.0", path = "../../../../primitives/arithmetic" } diff --git a/frame/examples/basic/Cargo.toml b/frame/examples/basic/Cargo.toml index 2f854011b0abd..848d4bbc94d72 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.2.2", default-features = false } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } 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 fb4c12ae0b61d..e582b0f99714f 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.2.2", 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"] } +scale-info = { version = "2.5.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 = "7.0.0", default-features = false, path = "../../../primitives/core" } diff --git a/frame/executive/Cargo.toml b/frame/executive/Cargo.toml index 1636cb3929d92..ed661b8ac9493 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.2.2", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } 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 } diff --git a/frame/fast-unstake/Cargo.toml b/frame/fast-unstake/Cargo.toml index 8e4df2f2b9eb5..93fceefa2de51 100644 --- a/frame/fast-unstake/Cargo.toml +++ b/frame/fast-unstake/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.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/glutton/Cargo.toml b/frame/glutton/Cargo.toml index c0f0312464ee6..bee0d3db625fb 100644 --- a/frame/glutton/Cargo.toml +++ b/frame/glutton/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] blake2 = { version = "0.10.4", default-features = false } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } log = { version = "0.4.14", default-features = false } 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/grandpa/Cargo.toml b/frame/grandpa/Cargo.toml index 4eb796cf0c6b3..288d63512588b 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.2.2", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } 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 c1a250368fade..23c690889e19c 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.2.2", default-features = false, features = ["derive", "max-encoded-len"] } enumflags2 = { version = "0.7.4" } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.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" } diff --git a/frame/identity/src/types.rs b/frame/identity/src/types.rs index 4d59a528021a0..1837b30b027f9 100644 --- a/frame/identity/src/types.rs +++ b/frame/identity/src/types.rs @@ -442,7 +442,7 @@ mod tests { let mut registry = scale_info::Registry::new(); let type_id = registry.register_type(&scale_info::meta_type::()); let registry: scale_info::PortableRegistry = registry.into(); - let type_info = registry.resolve(type_id.id()).unwrap(); + let type_info = registry.resolve(type_id.id).unwrap(); let check_type_info = |data: &Data| { let variant_name = match data { @@ -453,20 +453,20 @@ mod tests { Data::ShaThree256(_) => "ShaThree256".to_string(), Data::Raw(bytes) => format!("Raw{}", bytes.len()), }; - if let scale_info::TypeDef::Variant(variant) = type_info.type_def() { + if let scale_info::TypeDef::Variant(variant) = &type_info.type_def { let variant = variant - .variants() + .variants .iter() - .find(|v| v.name() == &variant_name) + .find(|v| v.name == variant_name) .expect(&format!("Expected to find variant {}", variant_name)); let field_arr_len = variant - .fields() + .fields .first() - .and_then(|f| registry.resolve(f.ty().id())) + .and_then(|f| registry.resolve(f.ty.id)) .map(|ty| { - if let scale_info::TypeDef::Array(arr) = ty.type_def() { - arr.len() + if let scale_info::TypeDef::Array(arr) = &ty.type_def { + arr.len } else { panic!("Should be an array type") } @@ -474,7 +474,7 @@ mod tests { .unwrap_or(0); let encoded = data.encode(); - assert_eq!(encoded[0], variant.index()); + assert_eq!(encoded[0], variant.index); assert_eq!(encoded.len() as u32 - 1, field_arr_len); } else { panic!("Should be a variant type") diff --git a/frame/im-online/Cargo.toml b/frame/im-online/Cargo.toml index d76fba4fb6495..881139ad5aa84 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.2.2", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } 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 b667916ebcb49..6895f076da22d 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.2.2", default-features = false, features = ["derive"] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } 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/insecure-randomness-collective-flip/Cargo.toml b/frame/insecure-randomness-collective-flip/Cargo.toml index 68ccfadfc8edf..bcebff6a9663f 100644 --- a/frame/insecure-randomness-collective-flip/Cargo.toml +++ b/frame/insecure-randomness-collective-flip/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } safe-mix = { version = "1.0", default-features = false } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } 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 = "7.0.0", default-features = false, path = "../../primitives/runtime" } diff --git a/frame/lottery/Cargo.toml b/frame/lottery/Cargo.toml index 8c1bf30106852..4d8839612b2ef 100644 --- a/frame/lottery/Cargo.toml +++ b/frame/lottery/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } 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 bba5700cdd848..330d9401df2c7 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.2.2", default-features = false } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } 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 3f7180f79adbe..5f6094af1648e 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.2.2", default-features = false } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } 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/message-queue/Cargo.toml b/frame/message-queue/Cargo.toml index 115200b826763..404e678137211 100644 --- a/frame/message-queue/Cargo.toml +++ b/frame/message-queue/Cargo.toml @@ -10,7 +10,7 @@ description = "FRAME pallet to queue and process messages" [dependencies] codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } -scale-info = { version = "2.1.2", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } serde = { version = "1.0.137", optional = true, features = ["derive"] } log = { version = "0.4.17", default-features = false } diff --git a/frame/multisig/Cargo.toml b/frame/multisig/Cargo.toml index 5cd744124ef24..98a15c5a5aada 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.2.2", default-features = false } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } 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/nfts/Cargo.toml b/frame/nfts/Cargo.toml index 59aa4e091fe68..96d46dacbbd0c 100644 --- a/frame/nfts/Cargo.toml +++ b/frame/nfts/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false } enumflags2 = { version = "0.7.5" } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } 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 1c829efc2d601..50fc4ef68788f 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.2.2", default-features = false, features = ["derive"] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } 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 = "7.0.0", default-features = false, path = "../../primitives/io" } diff --git a/frame/nis/Cargo.toml b/frame/nis/Cargo.toml index a5fc29cd79150..c12d4f2c0a1eb 100644 --- a/frame/nis/Cargo.toml +++ b/frame/nis/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } 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/node-authorization/Cargo.toml b/frame/node-authorization/Cargo.toml index c60ce1d12ce09..ed3f59a9a1e24 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.2.2", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } 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 = "7.0.0", default-features = false, path = "../../primitives/core" } diff --git a/frame/nomination-pools/Cargo.toml b/frame/nomination-pools/Cargo.toml index d51bcec51f478..c92d9b5124697 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.2.2", default-features = false, features = ["derive"] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } # 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 b96024af7d3c5..4f757cafa2fd1 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.2.2", default-features = false, features = ["derive"] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } # 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 47ae264a69cf8..6ebe870a78c9b 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.2.2", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } 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 6bc6c8c53c012..57dda88b1e70a 100644 --- a/frame/preimage/Cargo.toml +++ b/frame/preimage/Cargo.toml @@ -10,7 +10,7 @@ description = "FRAME pallet for storing preimages of hashes" [dependencies] codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } 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 5c69fcfb9f55e..065cbe5eba252 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.2.2", default-features = false, features = ["max-encoded-len"] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.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" } diff --git a/frame/recovery/Cargo.toml b/frame/recovery/Cargo.toml index 3c25c0002b709..b2e3236e4dfc5 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.2.2", default-features = false, features = ["derive"] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } 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 ac4c8044da359..5a092c63beec0 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.2.2", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"], optional = true } 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" } diff --git a/frame/remark/Cargo.toml b/frame/remark/Cargo.toml index 151cc38884490..5fc595d710680 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.2.2", default-features = false } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } serde = { version = "1.0.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/root-offences/Cargo.toml b/frame/root-offences/Cargo.toml index fd1f7c6325ea2..58fa281dc3d76 100644 --- a/frame/root-offences/Cargo.toml +++ b/frame/root-offences/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } 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" } diff --git a/frame/root-testing/Cargo.toml b/frame/root-testing/Cargo.toml index 09262b3d31db2..6e8c13f775de0 100644 --- a/frame/root-testing/Cargo.toml +++ b/frame/root-testing/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.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 = "7.0.0", default-features = false, path = "../../primitives/core" } diff --git a/frame/scheduler/Cargo.toml b/frame/scheduler/Cargo.toml index 9a67e68a01640..50afac933f119 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.2.2", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } 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 d44fc1b2f1548..f38743e8b5f96 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.2.2", default-features = false, features = ["derive"] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } 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 = "7.0.0", default-features = false, path = "../../primitives/io" } diff --git a/frame/session/Cargo.toml b/frame/session/Cargo.toml index bd28bffffd8d9..ccf3f7d86e497 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.2.2", default-features = false, features = ["derive"] } impl-trait-for-tuples = "0.2.2" log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } 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/society/Cargo.toml b/frame/society/Cargo.toml index ddc6ea6aac7d7..ab74e39e4f83b 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.2.2", default-features = false, features = ["derive"] } rand_chacha = { version = "0.2", default-features = false } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } 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 = "7.0.0", default-features = false, path = "../../primitives/runtime" } diff --git a/frame/staking/Cargo.toml b/frame/staking/Cargo.toml index 79c0bb5c2a32d..c20f003108d76 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.2.2", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } 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" } diff --git a/frame/state-trie-migration/Cargo.toml b/frame/state-trie-migration/Cargo.toml index 36b5912a60302..8485db5a3c98d 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.2.2", default-features = false } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } serde = { version = "1.0.133", optional = true } thousands = { version = "0.2.0", optional = true } zstd = { version = "0.11.2", default-features = false, optional = true } diff --git a/frame/sudo/Cargo.toml b/frame/sudo/Cargo.toml index 56d04b172c268..e1161497b1744 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.2.2", default-features = false, features = ["derive"] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } 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 = "7.0.0", default-features = false, path = "../../primitives/io" } diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index 7792fdf015ba5..f62609585818a 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.2.2", default-features = false, features = ["derive", "max-encoded-len"] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } frame-metadata = { version = "15.1.0", default-features = false, features = ["v14", "v15-unstable"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../primitives/api" } sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } diff --git a/frame/support/test/Cargo.toml b/frame/support/test/Cargo.toml index ad4589c734fde..9564b6a04d7e7 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.2.2", default-features = false, features = ["derive"] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/api" } sp-arithmetic = { version = "6.0.0", default-features = false, path = "../../../primitives/arithmetic" } sp-io = { version = "7.0.0", path = "../../../primitives/io", default-features = false } diff --git a/frame/support/test/compile_pass/Cargo.toml b/frame/support/test/compile_pass/Cargo.toml index dd5e1b996db9c..4466c24d64f15 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.2.2", default-features = false, features = ["derive"] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } 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 = "7.0.0", default-features = false, path = "../../../../primitives/core" } diff --git a/frame/support/test/tests/pallet.rs b/frame/support/test/tests/pallet.rs index f1dc97223322f..f3c4e07403af8 100644 --- a/frame/support/test/tests/pallet.rs +++ b/frame/support/test/tests/pallet.rs @@ -1616,9 +1616,9 @@ 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(); + 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) diff --git a/frame/support/test/tests/pallet_compatibility.rs b/frame/support/test/tests/pallet_compatibility.rs index 077b3c96e992c..610316ecf1a6f 100644 --- a/frame/support/test/tests/pallet_compatibility.rs +++ b/frame/support/test/tests/pallet_compatibility.rs @@ -295,14 +295,14 @@ mod test { }; let assert_meta_types = |ty_id1, ty_id2| { - let ty1 = types.resolve(ty_id1).map(|ty| ty.type_def()); - let ty2 = types.resolve(ty_id2).map(|ty| ty.type_def()); + let ty1 = types.resolve(ty_id1).map(|ty| ty.type_def.clone()); + let ty2 = types.resolve(ty_id2).map(|ty| ty.type_def.clone()); pretty_assertions::assert_eq!(ty1, ty2); }; - let get_enum_variants = |ty_id| match types.resolve(ty_id).map(|ty| ty.type_def()) { + let get_enum_variants = |ty_id| match types.resolve(ty_id).map(|ty| ty.type_def.clone()) { Some(ty) => match ty { - scale_info::TypeDef::Variant(var) => var.variants(), + scale_info::TypeDef::Variant(var) => var.variants, _ => panic!("Expected variant type"), }, _ => panic!("No type found"), @@ -314,12 +314,12 @@ mod test { for i in 0..vs1.len() { let v1 = &vs2[i]; let v2 = &vs2[i]; - assert_eq!(v1.fields().len(), v2.fields().len()); - for f in 0..v1.fields().len() { - let f1 = &v1.fields()[f]; - let f2 = &v2.fields()[f]; - pretty_assertions::assert_eq!(f1.name(), f2.name()); - pretty_assertions::assert_eq!(f1.ty(), f2.ty()); + assert_eq!(v1.fields.len(), v2.fields.len()); + for f in 0..v1.fields.len() { + let f1 = &v1.fields[f]; + let f2 = &v2.fields[f]; + pretty_assertions::assert_eq!(f1.name, f2.name); + pretty_assertions::assert_eq!(f1.ty, f2.ty); } } }; @@ -328,21 +328,21 @@ mod test { let calls1 = pallets[1].calls.as_ref().unwrap(); let calls2 = pallets[2].calls.as_ref().unwrap(); - assert_meta_types(calls1.ty.id(), calls2.ty.id()); + assert_meta_types(calls1.ty.id, calls2.ty.id); // event: check variants and fields but ignore the type name which will be different - let event1_variants = get_enum_variants(pallets[1].event.as_ref().unwrap().ty.id()); - let event2_variants = get_enum_variants(pallets[2].event.as_ref().unwrap().ty.id()); - assert_enum_variants(event1_variants, event2_variants); + let event1_variants = get_enum_variants(pallets[1].event.as_ref().unwrap().ty.id); + let event2_variants = get_enum_variants(pallets[2].event.as_ref().unwrap().ty.id); + assert_enum_variants(&event1_variants, &event2_variants); - let err1 = get_enum_variants(pallets[1].error.as_ref().unwrap().ty.id()) + let err1 = get_enum_variants(pallets[1].error.as_ref().unwrap().ty.id) .iter() - .filter(|v| v.name() == "__Ignore") + .filter(|v| v.name == "__Ignore") .cloned() .collect::>(); - let err2 = get_enum_variants(pallets[2].error.as_ref().unwrap().ty.id()) + let err2 = get_enum_variants(pallets[2].error.as_ref().unwrap().ty.id) .iter() - .filter(|v| v.name() == "__Ignore") + .filter(|v| v.name == "__Ignore") .cloned() .collect::>(); assert_enum_variants(&err1, &err2); diff --git a/frame/support/test/tests/pallet_compatibility_instance.rs b/frame/support/test/tests/pallet_compatibility_instance.rs index c641556beda20..73014d99657c9 100644 --- a/frame/support/test/tests/pallet_compatibility_instance.rs +++ b/frame/support/test/tests/pallet_compatibility_instance.rs @@ -298,9 +298,9 @@ mod test { _ => unreachable!(), }; - let get_enum_variants = |ty_id| match types.resolve(ty_id).map(|ty| ty.type_def()) { + let get_enum_variants = |ty_id| match types.resolve(ty_id).map(|ty| ty.type_def.clone()) { Some(ty) => match ty { - scale_info::TypeDef::Variant(var) => var.variants(), + scale_info::TypeDef::Variant(var) => var.variants, _ => panic!("Expected variant type"), }, _ => panic!("No type found"), @@ -312,12 +312,12 @@ mod test { for i in 0..vs1.len() { let v1 = &vs2[i]; let v2 = &vs2[i]; - assert_eq!(v1.fields().len(), v2.fields().len()); - for f in 0..v1.fields().len() { - let f1 = &v1.fields()[f]; - let f2 = &v2.fields()[f]; - pretty_assertions::assert_eq!(f1.name(), f2.name()); - pretty_assertions::assert_eq!(f1.ty(), f2.ty()); + assert_eq!(v1.fields.len(), v2.fields.len()); + for f in 0..v1.fields.len() { + let f1 = &v1.fields[f]; + let f2 = &v2.fields[f]; + pretty_assertions::assert_eq!(f1.name, f2.name); + pretty_assertions::assert_eq!(f1.ty, f2.ty); } } }; @@ -325,23 +325,23 @@ mod test { for i in vec![1, 3, 5].into_iter() { pretty_assertions::assert_eq!(pallets[i].storage, pallets[i + 1].storage); - let call1_variants = get_enum_variants(pallets[i].calls.as_ref().unwrap().ty.id()); - let call2_variants = get_enum_variants(pallets[i + 1].calls.as_ref().unwrap().ty.id()); - assert_enum_variants(call1_variants, call2_variants); + let call1_variants = get_enum_variants(pallets[i].calls.as_ref().unwrap().ty.id); + let call2_variants = get_enum_variants(pallets[i + 1].calls.as_ref().unwrap().ty.id); + assert_enum_variants(&call1_variants, &call2_variants); // event: check variants and fields but ignore the type name which will be different - let event1_variants = get_enum_variants(pallets[i].event.as_ref().unwrap().ty.id()); - let event2_variants = get_enum_variants(pallets[i + 1].event.as_ref().unwrap().ty.id()); - assert_enum_variants(event1_variants, event2_variants); + let event1_variants = get_enum_variants(pallets[i].event.as_ref().unwrap().ty.id); + let event2_variants = get_enum_variants(pallets[i + 1].event.as_ref().unwrap().ty.id); + assert_enum_variants(&event1_variants, &event2_variants); - let err1 = get_enum_variants(pallets[i].error.as_ref().unwrap().ty.id()) + let err1 = get_enum_variants(pallets[i].error.as_ref().unwrap().ty.id) .iter() - .filter(|v| v.name() == "__Ignore") + .filter(|v| v.name == "__Ignore") .cloned() .collect::>(); - let err2 = get_enum_variants(pallets[i + 1].error.as_ref().unwrap().ty.id()) + let err2 = get_enum_variants(pallets[i + 1].error.as_ref().unwrap().ty.id) .iter() - .filter(|v| v.name() == "__Ignore") + .filter(|v| v.name == "__Ignore") .cloned() .collect::>(); assert_enum_variants(&err1, &err2); diff --git a/frame/system/Cargo.toml b/frame/system/Cargo.toml index 5a6c89aae32ea..c97eb66382ed6 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.2.2", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"], optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } sp-core = { version = "7.0.0", default-features = false, path = "../../primitives/core" } diff --git a/frame/system/benchmarking/Cargo.toml b/frame/system/benchmarking/Cargo.toml index 8f00097254609..50009387a2088 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.2.2", default-features = false } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } 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 84c56da24e9d4..0f28955259cce 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.2.2", default-features = false, features = ["derive", "max-encoded-len"] } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } 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 c7db61613c03a..caed4edec5f48 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.2.2", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } 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 0c98796e4d1a7..b1e22d3e9145a 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.2.2", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } 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/transaction-payment/asset-tx-payment/Cargo.toml b/frame/transaction-payment/asset-tx-payment/Cargo.toml index 324e17a0808a4..574eb9e23742b 100644 --- a/frame/transaction-payment/asset-tx-payment/Cargo.toml +++ b/frame/transaction-payment/asset-tx-payment/Cargo.toml @@ -26,7 +26,7 @@ frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = " # Other dependencies codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } serde = { version = "1.0.136", optional = true } [dev-dependencies] diff --git a/frame/transaction-storage/Cargo.toml b/frame/transaction-storage/Cargo.toml index c23be8194d87f..aa19ce3fe2840 100644 --- a/frame/transaction-storage/Cargo.toml +++ b/frame/transaction-storage/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] array-bytes = { version = "4.1", optional = true } codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } serde = { version = "1.0.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 23fcb7944bfb7..f3c06735f8871 100644 --- a/frame/treasury/Cargo.toml +++ b/frame/treasury/Cargo.toml @@ -18,7 +18,7 @@ codec = { package = "parity-scale-codec", version = "3.2.2", default-features = "max-encoded-len", ] } impl-trait-for-tuples = "0.2.2" -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } serde = { version = "1.0.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 a01ea60d8c3e5..f88a862daba48 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.2.2", default-features = false } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } 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 c00255e3d33d8..a30feec467804 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.2.2", default-features = false } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } 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 c18d1f45e038b..2aa095bd74bff 100644 --- a/frame/vesting/Cargo.toml +++ b/frame/vesting/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "3.2.2", default-features = "derive", ] } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } 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 56ceaca9f81a4..21ecc4be374d3 100644 --- a/frame/whitelist/Cargo.toml +++ b/frame/whitelist/Cargo.toml @@ -13,7 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive", "max-encoded-len"] } -scale-info = { version = "2.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.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" } diff --git a/primitives/application-crypto/Cargo.toml b/primitives/application-crypto/Cargo.toml index e7aa118dfd6ac..37b58bc2bf649 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 = "7.0.0", default-features = false, path = "../core" } codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } serde = { version = "1.0.136", optional = true, features = ["derive"] } sp-std = { version = "5.0.0", default-features = false, path = "../std" } sp-io = { version = "7.0.0", default-features = false, path = "../io" } diff --git a/primitives/arithmetic/Cargo.toml b/primitives/arithmetic/Cargo.toml index b3fc6abc33ffd..92eebd4a6d8d6 100644 --- a/primitives/arithmetic/Cargo.toml +++ b/primitives/arithmetic/Cargo.toml @@ -20,7 +20,7 @@ codec = { package = "parity-scale-codec", version = "3.2.2", default-features = ] } integer-sqrt = "0.1.2" num-traits = { version = "0.2.8", default-features = false } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"], optional = true } static_assertions = "1.1.0" sp-std = { version = "5.0.0", default-features = false, path = "../std" } diff --git a/primitives/authority-discovery/Cargo.toml b/primitives/authority-discovery/Cargo.toml index ff36cf58d366e..e3a82b5fda514 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.2.2", default-features = false } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } sp-application-crypto = { version = "7.0.0", default-features = false, path = "../application-crypto" } sp-runtime = { version = "7.0.0", default-features = false, path = "../runtime" } diff --git a/primitives/consensus/aura/Cargo.toml b/primitives/consensus/aura/Cargo.toml index 001dc4a69aca4..94a031a547368 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.57", optional = true } codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../api" } sp-application-crypto = { version = "7.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 334fff2811941..d106cd0d0c875 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.57", optional = true } codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false } merlin = { version = "2.0", default-features = false } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"], optional = true } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../api" } sp-application-crypto = { version = "7.0.0", default-features = false, path = "../../application-crypto" } diff --git a/primitives/consensus/beefy/Cargo.toml b/primitives/consensus/beefy/Cargo.toml index 657569d122b05..144c8452d71b0 100644 --- a/primitives/consensus/beefy/Cargo.toml +++ b/primitives/consensus/beefy/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.2.2", 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"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../api" } sp-application-crypto = { version = "7.0.0", default-features = false, path = "../../application-crypto" } sp-core = { version = "7.0.0", default-features = false, path = "../../core" } diff --git a/primitives/consensus/grandpa/Cargo.toml b/primitives/consensus/grandpa/Cargo.toml index 5536cf73558d9..446471da8361a 100644 --- a/primitives/consensus/grandpa/Cargo.toml +++ b/primitives/consensus/grandpa/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } grandpa = { package = "finality-grandpa", version = "0.16.2", default-features = false, features = ["derive-codec"] } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", 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 = "7.0.0", default-features = false, path = "../../application-crypto" } diff --git a/primitives/consensus/vrf/Cargo.toml b/primitives/consensus/vrf/Cargo.toml index a4f92c30cca03..e7b4f0f0dec0e 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.2.2", default-features = false } -scale-info = { version = "2.1.1", default-features = false } +scale-info = { version = "2.5.0", default-features = false } schnorrkel = { version = "0.9.1", default-features = false, features = ["preaudit_deprecated", "u64_backend"] } sp-core = { version = "7.0.0", default-features = false, path = "../../core" } sp-runtime = { version = "7.0.0", default-features = false, path = "../../runtime" } diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index 9b253fd154675..1edd28b3fca7e 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive","max-encoded-len"] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } serde = { version = "1.0.136", optional = true, features = ["derive"] } bounded-collections = { version = "0.1.4", default-features = false } diff --git a/primitives/inherents/Cargo.toml b/primitives/inherents/Cargo.toml index fd073db69a6af..2f5616770d681 100644 --- a/primitives/inherents/Cargo.toml +++ b/primitives/inherents/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-trait = { version = "0.1.57", optional = true } codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } impl-trait-for-tuples = "0.2.2" thiserror = { version = "1.0.30", optional = true } sp-core = { version = "7.0.0", default-features = false, path = "../core" } diff --git a/primitives/merkle-mountain-range/Cargo.toml b/primitives/merkle-mountain-range/Cargo.toml index 97add1ed1d37c..cb3d6ddd51ad2 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.2.2", default-features = false } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } 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 } diff --git a/primitives/npos-elections/Cargo.toml b/primitives/npos-elections/Cargo.toml index 7a4bdbd679f0e..50a7a5bcd6088 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.2.2", default-features = false, features = ["derive"] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"], optional = true } sp-arithmetic = { version = "6.0.0", default-features = false, path = "../arithmetic" } sp-core = { version = "7.0.0", default-features = false, path = "../core" } diff --git a/primitives/npos-elections/fuzzer/Cargo.toml b/primitives/npos-elections/fuzzer/Cargo.toml index 8a058cc92edcf..d7cc684546a5f 100644 --- a/primitives/npos-elections/fuzzer/Cargo.toml +++ b/primitives/npos-elections/fuzzer/Cargo.toml @@ -18,7 +18,7 @@ clap = { version = "4.0.9", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } honggfuzz = "0.5" rand = { version = "0.8", features = ["std", "small_rng"] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } sp-npos-elections = { version = "4.0.0-dev", path = ".." } sp-runtime = { version = "7.0.0", path = "../../runtime" } diff --git a/primitives/runtime/Cargo.toml b/primitives/runtime/Cargo.toml index 3976de60cdcf9..056cfa3ddd3a4 100644 --- a/primitives/runtime/Cargo.toml +++ b/primitives/runtime/Cargo.toml @@ -21,7 +21,7 @@ impl-trait-for-tuples = "0.2.2" log = { version = "0.4.17", default-features = false } paste = "1.0" rand = { version = "0.8.5", optional = true } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"], optional = true } sp-application-crypto = { version = "7.0.0", default-features = false, path = "../application-crypto" } sp-arithmetic = { version = "6.0.0", default-features = false, path = "../arithmetic" } diff --git a/primitives/runtime/src/generic/digest.rs b/primitives/runtime/src/generic/digest.rs index 73741ba5d1dae..143fc2ce58d90 100644 --- a/primitives/runtime/src/generic/digest.rs +++ b/primitives/runtime/src/generic/digest.rs @@ -453,8 +453,8 @@ mod tests { #[test] fn digest_item_type_info() { let type_info = DigestItem::type_info(); - let variants = if let scale_info::TypeDef::Variant(variant) = type_info.type_def() { - variant.variants() + let variants = if let scale_info::TypeDef::Variant(variant) = type_info.type_def { + variant.variants } else { panic!("Should be a TypeDef::TypeDefVariant") }; @@ -475,10 +475,10 @@ mod tests { let encoded = digest_item.encode(); let variant = variants .iter() - .find(|v| v.name() == &variant_name) + .find(|v| v.name == variant_name) .expect(&format!("Variant {} not found", variant_name)); - assert_eq!(encoded[0], variant.index()) + assert_eq!(encoded[0], variant.index) }; check(DigestItemType::Other); diff --git a/primitives/session/Cargo.toml b/primitives/session/Cargo.toml index 31ec009ab2c64..6f362974b91b4 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.2.2", default-features = false, features = ["derive"] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } sp-core = { version = "7.0.0", default-features = false, path = "../core" } sp-runtime = { version = "7.0.0", optional = true, path = "../runtime" } diff --git a/primitives/staking/Cargo.toml b/primitives/staking/Cargo.toml index a8e5a543dbf75..f92bca2788c41 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.2.2", default-features = false, features = ["derive"] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } 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" } diff --git a/primitives/transaction-storage-proof/Cargo.toml b/primitives/transaction-storage-proof/Cargo.toml index 565d3d8d29f1c..72d3175a577cf 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.57", optional = true } codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } log = { version = "0.4.17", optional = true } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } 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 = "7.0.0", default-features = false, path = "../runtime" } diff --git a/primitives/trie/Cargo.toml b/primitives/trie/Cargo.toml index 0dacb76d9f27a..be02303003fd0 100644 --- a/primitives/trie/Cargo.toml +++ b/primitives/trie/Cargo.toml @@ -26,7 +26,7 @@ lazy_static = { version = "1.4.0", optional = true } memory-db = { version = "0.32.0", default-features = false } nohash-hasher = { version = "0.2.0", optional = true } parking_lot = { version = "0.12.1", optional = true } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } thiserror = { version = "1.0.30", optional = true } tracing = { version = "0.1.29", optional = true } trie-db = { version = "0.27.0", default-features = false } diff --git a/primitives/version/Cargo.toml b/primitives/version/Cargo.toml index 7d32c540f9a10..6b425aa7b9d27 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.2.2", default-features = false, features = ["derive"] } 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"] } +scale-info = { version = "2.5.0", 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/primitives/weights/Cargo.toml b/primitives/weights/Cargo.toml index 2368b913b3b2f..af1b5647e24d7 100644 --- a/primitives/weights/Cargo.toml +++ b/primitives/weights/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } serde = { version = "1.0.136", optional = true, features = ["derive"] } smallvec = "1.8.0" sp-arithmetic = { version = "6.0.0", default-features = false, path = "../arithmetic" } diff --git a/test-utils/runtime/Cargo.toml b/test-utils/runtime/Cargo.toml index 1dcdec0dbf059..68267e91d62cf 100644 --- a/test-utils/runtime/Cargo.toml +++ b/test-utils/runtime/Cargo.toml @@ -20,7 +20,7 @@ sp-consensus-babe = { version = "0.10.0-dev", default-features = false, path = " sp-consensus-beefy = { version = "4.0.0-dev", default-features = false, path = "../../primitives/consensus/beefy" } sp-block-builder = { version = "4.0.0-dev", default-features = false, path = "../../primitives/block-builder" } codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } 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.32.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 3689a87da8ae5..91f50014667cc 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.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false } serde = { version = "1", features = ["derive"] } log = { version = "0.4.17", default-features = false } From b4f857e14768ebdffe0993886e397c54387b90ee Mon Sep 17 00:00:00 2001 From: PG Herveou Date: Wed, 12 Apr 2023 16:49:10 +0200 Subject: [PATCH 642/715] contracts: add sr25519_verify (#13724) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * wip * fix * wip * fix lint * rm fixture fix * missing comment * fix lint * add comment to the wsm file * fix comment * Apply suggestions from code review Co-authored-by: Sasha Gryaznov * wip * wip weights * wip weights * PR comment: test with return code * wip * PR review add mock test * remove * lint * Update frame/contracts/fixtures/sr25519_verify.wat * fix comments * Update frame/contracts/src/benchmarking/mod.rs * Update frame/contracts/src/wasm/runtime.rs * Update frame/contracts/fixtures/sr25519_verify.wat * Update frame/contracts/src/benchmarking/mod.rs * fix lint * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_contracts * Update frame/contracts/src/wasm/runtime.rs Co-authored-by: Alexander Theißen * PR: review use unstable + remove arbitrary index 4 * Add benchmark for calculating overhead of calling sr25519_verify * fix message length encoding * fix weights * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_contracts * Apply suggestions from code review * Update frame/contracts/src/wasm/runtime.rs * Update frame/contracts/src/wasm/runtime.rs * Update frame/contracts/src/benchmarking/mod.rs * Update frame/contracts/src/benchmarking/mod.rs * Update frame/contracts/src/schedule.rs Co-authored-by: Sasha Gryaznov * Update frame/contracts/src/schedule.rs Co-authored-by: Sasha Gryaznov * Update frame/contracts/src/wasm/runtime.rs * Update frame/contracts/src/wasm/runtime.rs Co-authored-by: Sasha Gryaznov * PR review --------- Co-authored-by: Sasha Gryaznov Co-authored-by: command-bot <> Co-authored-by: Alexander Theißen --- frame/contracts/fixtures/sr25519_verify.wat | 55 + frame/contracts/src/benchmarking/mod.rs | 107 +- frame/contracts/src/exec.rs | 16 +- frame/contracts/src/schedule.rs | 10 +- frame/contracts/src/tests.rs | 66 + frame/contracts/src/wasm/mod.rs | 49 + frame/contracts/src/wasm/runtime.rs | 47 + frame/contracts/src/weights.rs | 1876 ++++++++++--------- 8 files changed, 1332 insertions(+), 894 deletions(-) create mode 100644 frame/contracts/fixtures/sr25519_verify.wat diff --git a/frame/contracts/fixtures/sr25519_verify.wat b/frame/contracts/fixtures/sr25519_verify.wat new file mode 100644 index 0000000000000..2da1ceb87eab0 --- /dev/null +++ b/frame/contracts/fixtures/sr25519_verify.wat @@ -0,0 +1,55 @@ +;; This contract: +;; 1) Reads signature, message and public key from the input +;; 2) Calls and return the result of sr25519_verify + +(module + ;; import the host functions from the seal0 module + (import "seal0" "sr25519_verify" (func $sr25519_verify (param i32 i32 i32 i32) (result i32))) + (import "seal0" "seal_input" (func $seal_input (param i32 i32))) + (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32))) + + ;; give the program 1 page of memory + (import "env" "memory" (memory 1 1)) + + ;; [0, 4) length of signature + message + public key - 64 + 11 + 32 = 107 bytes + ;; write the length of the input (6b = 107) bytes at offset 0 + (data (i32.const 0) "\6b") + + (func (export "deploy")) + + (func (export "call") + ;; define local variables + (local $signature_ptr i32) + (local $pub_key_ptr i32) + (local $message_len i32) + (local $message_ptr i32) + + ;; set the pointers to the memory locations + ;; Memory layout during `call` + ;; [10, 74) signature + ;; [74, 106) public key + ;; [106, 117) message (11 bytes) + (local.set $signature_ptr (i32.const 10)) + (local.set $pub_key_ptr (i32.const 74)) + (local.set $message_ptr (i32.const 106)) + + ;; store the input into the memory, starting at the signature and + ;; up to 107 bytes stored at offset 0 + (call $seal_input (local.get $signature_ptr) (i32.const 0)) + + ;; call sr25519_verify and store the return code + (i32.store + (i32.const 0) + (call $sr25519_verify + (local.get $signature_ptr) + (local.get $pub_key_ptr) + (i32.const 11) + (local.get $message_ptr) + ) + ) + + ;; exit with success and take transfer return code to the output buffer + (call $seal_return (i32.const 0) (i32.const 0) (i32.const 4)) + ) +) + diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index 1bb6f3395fcef..98a3dc36b7b68 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -2008,9 +2008,114 @@ benchmarks! { let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + // `n`: Message input length to verify in bytes. + #[pov_mode = Measured] + seal_sr25519_verify_per_byte { + let n in 0 .. T::MaxCodeLen::get() - 255; // need some buffer so the code size does not + // exceed the max code size. + + let message = (0..n).zip((32u8..127u8).cycle()).map(|(_, c)| c).collect::>(); + let message_len = message.len() as i32; + + let key_type = sp_core::crypto::KeyTypeId(*b"code"); + let pub_key = sp_io::crypto::sr25519_generate(key_type, None); + let sig = sp_io::crypto::sr25519_sign(key_type, &pub_key, &message).expect("Generates signature"); + let sig = AsRef::<[u8; 64]>::as_ref(&sig).to_vec(); + + let code = WasmModule::::from(ModuleDefinition { + memory: Some(ImportedMemory::max::()), + imported_functions: vec![ImportedFunction { + module: "seal0", + name: "sr25519_verify", + params: vec![ValueType::I32, ValueType::I32, ValueType::I32, ValueType::I32], + return_type: Some(ValueType::I32), + }], + data_segments: vec![ + DataSegment { + offset: 0, + value: sig, + }, + DataSegment { + offset: 64, + value: pub_key.to_vec(), + }, + DataSegment { + offset: 96, + value: message, + }, + ], + call_body: Some(body::plain(vec![ + Instruction::I32Const(0), // signature_ptr + Instruction::I32Const(64), // pub_key_ptr + Instruction::I32Const(message_len), // message_len + Instruction::I32Const(96), // message_ptr + Instruction::Call(0), + Instruction::Drop, + Instruction::End, + ])), + .. 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![]) + // Only calling the function itself with valid arguments. // It generates different private keys and signatures for the message "Hello world". - // This is a slow call: We redeuce the number of runs. + // This is a slow call: We reduce the number of runs. + #[pov_mode = Measured] + seal_sr25519_verify { + let r in 0 .. API_BENCHMARK_RUNS / 10; + + let message = b"Hello world".to_vec(); + let message_len = message.len() as i32; + let key_type = sp_core::crypto::KeyTypeId(*b"code"); + let sig_params = (0..r) + .map(|i| { + let pub_key = sp_io::crypto::sr25519_generate(key_type, None); + let sig = sp_io::crypto::sr25519_sign(key_type, &pub_key, &message).expect("Generates signature"); + let data: [u8; 96] = [AsRef::<[u8]>::as_ref(&sig), AsRef::<[u8]>::as_ref(&pub_key)].concat().try_into().unwrap(); + data + }) + .flatten() + .collect::>(); + let sig_params_len = sig_params.len() as i32; + + let code = WasmModule::::from(ModuleDefinition { + memory: Some(ImportedMemory::max::()), + imported_functions: vec![ImportedFunction { + module: "seal0", + name: "sr25519_verify", + params: vec![ValueType::I32, ValueType::I32, ValueType::I32, ValueType::I32], + return_type: Some(ValueType::I32), + }], + data_segments: vec![ + DataSegment { + offset: 0, + value: sig_params + }, + DataSegment { + offset: sig_params_len as u32, + value: message, + }, + ], + call_body: Some(body::repeated_dyn(r, vec![ + Counter(0, 96), // signature_ptr + Counter(64, 96), // pub_key_ptr + Regular(Instruction::I32Const(message_len)), // message_len + Regular(Instruction::I32Const(sig_params_len)), // message_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![]) + + // Only calling the function itself with valid arguments. + // It generates different private keys and signatures for the message "Hello world". + // This is a slow call: We reduce the number of runs. #[pov_mode = Measured] seal_ecdsa_recover { let r in 0 .. API_BENCHMARK_RUNS / 10; diff --git a/frame/contracts/src/exec.rs b/frame/contracts/src/exec.rs index 03e1c4fd32585..574f4495e479f 100644 --- a/frame/contracts/src/exec.rs +++ b/frame/contracts/src/exec.rs @@ -35,7 +35,10 @@ use frame_support::{ use frame_system::RawOrigin; use pallet_contracts_primitives::ExecReturnValue; use smallvec::{Array, SmallVec}; -use sp_core::ecdsa::Public as ECDSAPublic; +use sp_core::{ + ecdsa::Public as ECDSAPublic, + sr25519::{Public as SR25519Public, Signature as SR25519Signature}, +}; use sp_io::{crypto::secp256k1_ecdsa_recover_compressed, hashing::blake2_256}; use sp_runtime::traits::{Convert, Hash}; use sp_std::{marker::PhantomData, mem, prelude::*, vec::Vec}; @@ -272,6 +275,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], ()>; + /// Verify a sr25519 signature. + fn sr25519_verify(&self, signature: &[u8; 64], message: &[u8], pub_key: &[u8; 32]) -> bool; + /// Returns Ethereum address from the ECDSA compressed public key. fn ecdsa_to_eth_address(&self, pk: &[u8; 33]) -> Result<[u8; 20], ()>; @@ -1347,6 +1353,14 @@ where secp256k1_ecdsa_recover_compressed(signature, message_hash).map_err(|_| ()) } + fn sr25519_verify(&self, signature: &[u8; 64], message: &[u8], pub_key: &[u8; 32]) -> bool { + sp_io::crypto::sr25519_verify( + &SR25519Signature(*signature), + message, + &SR25519Public(*pub_key), + ) + } + fn ecdsa_to_eth_address(&self, pk: &[u8; 33]) -> Result<[u8; 20], ()> { ECDSAPublic(*pk).to_eth_address() } diff --git a/frame/contracts/src/schedule.rs b/frame/contracts/src/schedule.rs index ccf1e98bd2382..747540bce6359 100644 --- a/frame/contracts/src/schedule.rs +++ b/frame/contracts/src/schedule.rs @@ -139,7 +139,7 @@ impl Limits { /// Describes the weight for all categories of supported wasm instructions. /// /// There there is one field for each wasm instruction that describes the weight to -/// execute one instruction of that name. There are a few execptions: +/// execute one instruction of that name. There are a few exceptions: /// /// 1. If there is a i64 and a i32 variant of an instruction we use the weight /// of the former for both. @@ -409,6 +409,12 @@ pub struct HostFnWeights { /// Weight of calling `seal_ecdsa_to_eth_address`. pub ecdsa_to_eth_address: Weight, + /// Weight of calling `sr25519_verify`. + pub sr25519_verify: Weight, + + /// Weight per byte of calling `sr25519_verify`. + pub sr25519_verify_per_byte: Weight, + /// Weight of calling `reentrance_count`. pub reentrance_count: Weight, @@ -616,6 +622,8 @@ impl Default for HostFnWeights { hash_blake2_128: cost!(seal_hash_blake2_128), hash_blake2_128_per_byte: cost!(seal_hash_blake2_128_per_byte), ecdsa_recover: cost!(seal_ecdsa_recover), + sr25519_verify: cost!(seal_sr25519_verify), + sr25519_verify_per_byte: cost!(seal_sr25519_verify_per_byte), ecdsa_to_eth_address: cost!(seal_ecdsa_to_eth_address), reentrance_count: cost!(seal_reentrance_count), account_reentrance_count: cost!(seal_account_reentrance_count), diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index bae6c1946e183..ac1fb07bf5ce0 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -2900,6 +2900,72 @@ fn ecdsa_recover() { }) } +#[test] +fn sr25519_verify() { + let (wasm, _code_hash) = compile_module::("sr25519_verify").unwrap(); + + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + let _ = Balances::deposit_creating(&ALICE, 1_000_000); + + // Instantiate the sr25519_verify contract. + let addr = Contracts::bare_instantiate( + ALICE, + 100_000, + GAS_LIMIT, + None, + Code::Upload(wasm), + vec![], + vec![], + false, + ) + .result + .unwrap() + .account_id; + + let call_with = |message: &[u8; 11]| { + // Alice's signature for "hello world" + #[rustfmt::skip] + let signature: [u8; 64] = [ + 184, 49, 74, 238, 78, 165, 102, 252, 22, 92, 156, 176, 124, 118, 168, 116, 247, + 99, 0, 94, 2, 45, 9, 170, 73, 222, 182, 74, 60, 32, 75, 64, 98, 174, 69, 55, 83, + 85, 180, 98, 208, 75, 231, 57, 205, 62, 4, 105, 26, 136, 172, 17, 123, 99, 90, 255, + 228, 54, 115, 63, 30, 207, 205, 131, + ]; + + // Alice's public key + #[rustfmt::skip] + let public_key: [u8; 32] = [ + 212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, + 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125, + ]; + + let mut params = vec![]; + params.extend_from_slice(&signature); + params.extend_from_slice(&public_key); + params.extend_from_slice(message); + + >::bare_call( + ALICE, + addr.clone(), + 0, + GAS_LIMIT, + None, + params, + false, + Determinism::Enforced, + ) + .result + .unwrap() + }; + + // verification should succeed for "hello world" + assert_return_code!(call_with(&b"hello world"), RuntimeReturnCode::Success); + + // verification should fail for other messages + assert_return_code!(call_with(&b"hello worlD"), RuntimeReturnCode::Sr25519VerifyFailed); + }) +} + #[test] fn upload_code_works() { let (wasm, code_hash) = compile_module::("dummy").unwrap(); diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index e4e8bea7eb04a..c8f1be6dd9db1 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -434,6 +434,7 @@ mod tests { gas_meter: GasMeter, debug_buffer: Vec, ecdsa_recover: RefCell>, + sr25519_verify: RefCell, [u8; 32])>>, code_hashes: Vec>, } @@ -458,6 +459,7 @@ mod tests { gas_meter: GasMeter::new(Weight::from_parts(10_000_000_000, 10 * 1024 * 1024)), debug_buffer: Default::default(), ecdsa_recover: Default::default(), + sr25519_verify: Default::default(), } } } @@ -612,6 +614,10 @@ mod tests { self.ecdsa_recover.borrow_mut().push((*signature, *message_hash)); Ok([3; 33]) } + fn sr25519_verify(&self, signature: &[u8; 64], message: &[u8], pub_key: &[u8; 32]) -> bool { + self.sr25519_verify.borrow_mut().push((*signature, message.to_vec(), *pub_key)); + true + } fn contract_info(&mut self) -> &mut crate::ContractInfo { unimplemented!() } @@ -1319,6 +1325,49 @@ mod tests { ); } + #[test] + fn contract_sr25519() { + const CODE_SR25519: &str = r#" +(module + (import "seal0" "sr25519_verify" (func $sr25519_verify (param i32 i32 i32 i32) (result i32))) + (import "env" "memory" (memory 1 1)) + (func (export "call") + (drop + (call $sr25519_verify + (i32.const 0) ;; Pointer to signature. + (i32.const 64) ;; Pointer to public key. + (i32.const 16) ;; message length. + (i32.const 96) ;; Pointer to message. + ) + ) + ) + (func (export "deploy")) + + ;; Signature (64 bytes) + (data (i32.const 0) + "\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01" + "\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01" + "\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01" + "\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01" + ) + + ;; public key (32 bytes) + (data (i32.const 64) + "\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01" + "\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01" + ) + + ;; message. (16 bytes) + (data (i32.const 96) + "\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01" + ) +) +"#; + let mut mock_ext = MockExt::default(); + assert_ok!(execute(&CODE_SR25519, vec![], &mut mock_ext)); + assert_eq!(mock_ext.sr25519_verify.into_inner(), [([1; 64], [1; 16].to_vec(), [1; 32])]); + } + 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 88b5b87dda411..19eb0fb50739b 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -109,6 +109,8 @@ pub enum ReturnCode { /// ECDSA compressed pubkey conversion into Ethereum address failed (most probably /// wrong pubkey provided). EcdsaRecoverFailed = 11, + /// sr25519 signature verification failed. + Sr25519VerifyFailed = 12, } impl From for ReturnCode { @@ -251,6 +253,8 @@ pub enum RuntimeCosts { HashBlake128(u32), /// Weight of calling `seal_ecdsa_recover`. EcdsaRecovery, + /// Weight of calling `seal_sr25519_verify` for the given input size. + Sr25519Verify(u32), /// Weight charged by a chain extension through `seal_call_chain_extension`. ChainExtension(Weight), /// Weight charged for calling into the runtime. @@ -336,6 +340,9 @@ impl RuntimeCosts { .hash_blake2_128 .saturating_add(s.hash_blake2_128_per_byte.saturating_mul(len.into())), EcdsaRecovery => s.ecdsa_recover, + Sr25519Verify(len) => s + .sr25519_verify + .saturating_add(s.sr25519_verify_per_byte.saturating_mul(len.into())), ChainExtension(weight) => weight, CallRuntime(weight) => weight, SetCodeHash => s.set_code_hash, @@ -2466,6 +2473,46 @@ pub mod env { } } + /// Verify a sr25519 signature + /// + /// # Parameters + /// + /// - `signature_ptr`: the pointer into the linear memory where the signature is placed. Should + /// be a value of 64 bytes. + /// - `pub_key_ptr`: the pointer into the linear memory where the public key is placed. Should + /// be a value of 32 bytes. + /// - `message_len`: the length of the message payload. + /// - `message_ptr`: the pointer into the linear memory where the message is placed. + /// + /// # Errors + /// + /// - `ReturnCode::Sr25519VerifyFailed + #[unstable] + fn sr25519_verify( + ctx: _, + memory: _, + signature_ptr: u32, + pub_key_ptr: u32, + message_len: u32, + message_ptr: u32, + ) -> Result { + ctx.charge_gas(RuntimeCosts::Sr25519Verify(message_len))?; + + let mut signature: [u8; 64] = [0; 64]; + ctx.read_sandbox_memory_into_buf(memory, signature_ptr, &mut signature)?; + + let mut pub_key: [u8; 32] = [0; 32]; + ctx.read_sandbox_memory_into_buf(memory, pub_key_ptr, &mut pub_key)?; + + let message: Vec = ctx.read_sandbox_memory(memory, message_ptr, message_len)?; + + if ctx.ext.sr25519_verify(&signature, &message, &pub_key) { + Ok(ReturnCode::Success) + } else { + Ok(ReturnCode::Sr25519VerifyFailed) + } + } + /// Replace the contract code at the specified address with new code. /// /// # Note diff --git a/frame/contracts/src/weights.rs b/frame/contracts/src/weights.rs index 22a24aa27fe01..8e81364acf449 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: 2023-03-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -108,6 +108,8 @@ pub trait WeightInfo { fn seal_hash_blake2_256_per_byte(n: u32, ) -> Weight; fn seal_hash_blake2_128(r: u32, ) -> Weight; fn seal_hash_blake2_128_per_byte(n: u32, ) -> Weight; + fn seal_sr25519_verify_per_byte(n: u32, ) -> Weight; + fn seal_sr25519_verify(r: 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; @@ -176,8 +178,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `109` // Estimated: `1594` - // Minimum execution time: 2_677_000 picoseconds. - Weight::from_parts(2_899_000, 1594) + // Minimum execution time: 2_503_000 picoseconds. + Weight::from_parts(2_603_000, 1594) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: Skipped Metadata (r:0 w:0) @@ -187,10 +189,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `488 + k * (69 ±0)` // Estimated: `478 + k * (70 ±0)` - // Minimum execution time: 14_006_000 picoseconds. - Weight::from_parts(8_735_946, 478) - // Standard Error: 1_370 - .saturating_add(Weight::from_parts(989_501, 0).saturating_mul(k.into())) + // Minimum execution time: 13_292_000 picoseconds. + Weight::from_parts(9_180_439, 478) + // Standard Error: 997 + .saturating_add(Weight::from_parts(967_522, 0).saturating_mul(k.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) @@ -206,10 +208,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `238 + c * (1 ±0)` // Estimated: `3951 + c * (2 ±0)` - // Minimum execution time: 30_951_000 picoseconds. - Weight::from_parts(25_988_560, 3951) - // Standard Error: 57 - .saturating_add(Weight::from_parts(54_692, 0).saturating_mul(c.into())) + // Minimum execution time: 30_822_000 picoseconds. + Weight::from_parts(26_457_115, 3951) + // Standard Error: 58 + .saturating_add(Weight::from_parts(54_868, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 2).saturating_mul(c.into())) @@ -229,10 +231,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `707` // Estimated: `21400 + c * (5 ±0)` - // Minimum execution time: 263_107_000 picoseconds. - Weight::from_parts(268_289_665, 21400) - // Standard Error: 33 - .saturating_add(Weight::from_parts(38_534, 0).saturating_mul(c.into())) + // Minimum execution time: 263_719_000 picoseconds. + Weight::from_parts(275_281_941, 21400) + // Standard Error: 32 + .saturating_add(Weight::from_parts(37_880, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 5).saturating_mul(c.into())) @@ -260,14 +262,14 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `270` // Estimated: `26207` - // Minimum execution time: 3_122_319_000 picoseconds. - Weight::from_parts(487_802_180, 26207) - // Standard Error: 345 - .saturating_add(Weight::from_parts(108_237, 0).saturating_mul(c.into())) - // Standard Error: 20 - .saturating_add(Weight::from_parts(1_166, 0).saturating_mul(i.into())) - // Standard Error: 20 - .saturating_add(Weight::from_parts(1_505, 0).saturating_mul(s.into())) + // Minimum execution time: 3_133_756_000 picoseconds. + Weight::from_parts(556_483_545, 26207) + // Standard Error: 294 + .saturating_add(Weight::from_parts(107_914, 0).saturating_mul(c.into())) + // Standard Error: 17 + .saturating_add(Weight::from_parts(1_143, 0).saturating_mul(i.into())) + // Standard Error: 17 + .saturating_add(Weight::from_parts(1_456, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(10_u64)) } @@ -291,12 +293,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `482` // Estimated: `28521` - // Minimum execution time: 1_650_623_000 picoseconds. - Weight::from_parts(286_494_456, 28521) + // Minimum execution time: 1_646_953_000 picoseconds. + Weight::from_parts(262_115_215, 28521) // Standard Error: 8 - .saturating_add(Weight::from_parts(1_438, 0).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(1_454, 0).saturating_mul(i.into())) // Standard Error: 8 - .saturating_add(Weight::from_parts(1_453, 0).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_463, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } @@ -314,8 +316,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `759` // Estimated: `21615` - // Minimum execution time: 191_046_000 picoseconds. - Weight::from_parts(192_544_000, 21615) + // Minimum execution time: 190_769_000 picoseconds. + Weight::from_parts(191_717_000, 21615) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -332,10 +334,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `109` // Estimated: `7366` - // Minimum execution time: 244_260_000 picoseconds. - Weight::from_parts(254_693_985, 7366) - // Standard Error: 80 - .saturating_add(Weight::from_parts(108_246, 0).saturating_mul(c.into())) + // Minimum execution time: 246_204_000 picoseconds. + Weight::from_parts(243_234_754, 7366) + // Standard Error: 78 + .saturating_add(Weight::from_parts(109_232, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -351,8 +353,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `255` // Estimated: `7950` - // Minimum execution time: 33_492_000 picoseconds. - Weight::from_parts(34_079_000, 7950) + // Minimum execution time: 33_516_000 picoseconds. + Weight::from_parts(33_995_000, 7950) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -366,8 +368,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `570` // Estimated: `19530` - // Minimum execution time: 33_475_000 picoseconds. - Weight::from_parts(33_856_000, 19530) + // Minimum execution time: 33_255_000 picoseconds. + Weight::from_parts(33_692_000, 19530) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -386,10 +388,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `781 + r * (6 ±0)` // Estimated: `21730 + r * (30 ±0)` - // Minimum execution time: 234_197_000 picoseconds. - Weight::from_parts(236_830_305, 21730) - // Standard Error: 818 - .saturating_add(Weight::from_parts(336_446, 0).saturating_mul(r.into())) + // Minimum execution time: 235_074_000 picoseconds. + Weight::from_parts(243_735_179, 21730) + // Standard Error: 972 + .saturating_add(Weight::from_parts(328_571, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -409,10 +411,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `839 + r * (240 ±0)` // Estimated: `21835 + r * (3675 ±0)` - // Minimum execution time: 235_872_000 picoseconds. - Weight::from_parts(78_877_890, 21835) - // Standard Error: 6_405 - .saturating_add(Weight::from_parts(3_358_341, 0).saturating_mul(r.into())) + // Minimum execution time: 236_455_000 picoseconds. + Weight::from_parts(81_818_936, 21835) + // Standard Error: 5_874 + .saturating_add(Weight::from_parts(3_316_006, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -433,10 +435,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `831 + r * (244 ±0)` // Estimated: `21855 + r * (3695 ±0)` - // Minimum execution time: 239_035_000 picoseconds. - Weight::from_parts(93_255_085, 21855) - // Standard Error: 5_922 - .saturating_add(Weight::from_parts(4_144_910, 0).saturating_mul(r.into())) + // Minimum execution time: 237_724_000 picoseconds. + Weight::from_parts(91_384_964, 21855) + // Standard Error: 5_828 + .saturating_add(Weight::from_parts(4_063_221, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -457,10 +459,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `788 + r * (6 ±0)` // Estimated: `21770 + r * (30 ±0)` - // Minimum execution time: 236_507_000 picoseconds. - Weight::from_parts(238_253_211, 21770) - // Standard Error: 975 - .saturating_add(Weight::from_parts(413_919, 0).saturating_mul(r.into())) + // Minimum execution time: 236_144_000 picoseconds. + Weight::from_parts(239_917_873, 21770) + // Standard Error: 629 + .saturating_add(Weight::from_parts(409_752, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -480,10 +482,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `778 + r * (3 ±0)` // Estimated: `21735 + r * (15 ±0)` - // Minimum execution time: 235_521_000 picoseconds. - Weight::from_parts(238_397_362, 21735) - // Standard Error: 452 - .saturating_add(Weight::from_parts(160_860, 0).saturating_mul(r.into())) + // Minimum execution time: 232_946_000 picoseconds. + Weight::from_parts(243_163_112, 21735) + // Standard Error: 1_940 + .saturating_add(Weight::from_parts(162_705, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 15).saturating_mul(r.into())) @@ -503,10 +505,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `782 + r * (6 ±0)` // Estimated: `21740 + r * (30 ±0)` - // Minimum execution time: 234_722_000 picoseconds. - Weight::from_parts(242_936_096, 21740) - // Standard Error: 1_178 - .saturating_add(Weight::from_parts(329_075, 0).saturating_mul(r.into())) + // Minimum execution time: 235_301_000 picoseconds. + Weight::from_parts(240_802_312, 21740) + // Standard Error: 5_362 + .saturating_add(Weight::from_parts(339_001, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -526,10 +528,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `783 + r * (6 ±0)` // Estimated: `21725 + r * (30 ±0)` - // Minimum execution time: 235_654_000 picoseconds. - Weight::from_parts(245_887_792, 21725) - // Standard Error: 903 - .saturating_add(Weight::from_parts(325_168, 0).saturating_mul(r.into())) + // Minimum execution time: 235_683_000 picoseconds. + Weight::from_parts(237_357_276, 21725) + // Standard Error: 726 + .saturating_add(Weight::from_parts(333_264, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -549,10 +551,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `922 + r * (6 ±0)` // Estimated: `24633 + r * (30 ±0)` - // Minimum execution time: 233_599_000 picoseconds. - Weight::from_parts(251_561_602, 24633) - // Standard Error: 3_348 - .saturating_add(Weight::from_parts(1_475_443, 0).saturating_mul(r.into())) + // Minimum execution time: 234_327_000 picoseconds. + Weight::from_parts(239_792_456, 24633) + // Standard Error: 3_460 + .saturating_add(Weight::from_parts(1_496_090, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -572,10 +574,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `792 + r * (6 ±0)` // Estimated: `21825 + r * (30 ±0)` - // Minimum execution time: 235_087_000 picoseconds. - Weight::from_parts(235_855_322, 21825) - // Standard Error: 867 - .saturating_add(Weight::from_parts(346_707, 0).saturating_mul(r.into())) + // Minimum execution time: 235_466_000 picoseconds. + Weight::from_parts(242_580_658, 21825) + // Standard Error: 1_439 + .saturating_add(Weight::from_parts(323_842, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -595,10 +597,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `790 + r * (6 ±0)` // Estimated: `21815 + r * (30 ±0)` - // Minimum execution time: 237_103_000 picoseconds. - Weight::from_parts(239_272_188, 21815) - // Standard Error: 892 - .saturating_add(Weight::from_parts(328_334, 0).saturating_mul(r.into())) + // Minimum execution time: 238_529_000 picoseconds. + Weight::from_parts(249_276_722, 21815) + // Standard Error: 1_216 + .saturating_add(Weight::from_parts(328_600, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -618,10 +620,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `787 + r * (6 ±0)` // Estimated: `21805 + r * (30 ±0)` - // Minimum execution time: 234_761_000 picoseconds. - Weight::from_parts(238_601_784, 21805) - // Standard Error: 725 - .saturating_add(Weight::from_parts(325_758, 0).saturating_mul(r.into())) + // Minimum execution time: 234_360_000 picoseconds. + Weight::from_parts(239_927_876, 21805) + // Standard Error: 541 + .saturating_add(Weight::from_parts(319_553, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -641,10 +643,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `778 + r * (6 ±0)` // Estimated: `21735 + r * (30 ±0)` - // Minimum execution time: 235_249_000 picoseconds. - Weight::from_parts(239_861_242, 21735) - // Standard Error: 751 - .saturating_add(Weight::from_parts(325_795, 0).saturating_mul(r.into())) + // Minimum execution time: 234_461_000 picoseconds. + Weight::from_parts(239_682_633, 21735) + // Standard Error: 544 + .saturating_add(Weight::from_parts(322_943, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -666,10 +668,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `856 + r * (10 ±0)` // Estimated: `24446 + r * (60 ±0)` - // Minimum execution time: 234_912_000 picoseconds. - Weight::from_parts(254_783_734, 24446) - // Standard Error: 1_610 - .saturating_add(Weight::from_parts(1_307_506, 0).saturating_mul(r.into())) + // Minimum execution time: 234_862_000 picoseconds. + Weight::from_parts(252_614_390, 24446) + // Standard Error: 1_180 + .saturating_add(Weight::from_parts(1_313_286, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 60).saturating_mul(r.into())) @@ -689,10 +691,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `745 + r * (4 ±0)` // Estimated: `21555 + r * (20 ±0)` - // Minimum execution time: 160_125_000 picoseconds. - Weight::from_parts(164_915_574, 21555) - // Standard Error: 332 - .saturating_add(Weight::from_parts(132_326, 0).saturating_mul(r.into())) + // Minimum execution time: 161_003_000 picoseconds. + Weight::from_parts(165_793_675, 21555) + // Standard Error: 323 + .saturating_add(Weight::from_parts(128_941, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 20).saturating_mul(r.into())) @@ -712,10 +714,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `780 + r * (6 ±0)` // Estimated: `21740 + r * (30 ±0)` - // Minimum execution time: 234_717_000 picoseconds. - Weight::from_parts(238_540_521, 21740) - // Standard Error: 599 - .saturating_add(Weight::from_parts(277_303, 0).saturating_mul(r.into())) + // Minimum execution time: 235_192_000 picoseconds. + Weight::from_parts(241_225_671, 21740) + // Standard Error: 1_132 + .saturating_add(Weight::from_parts(272_760, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -735,10 +737,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `784` // Estimated: `21740` - // Minimum execution time: 235_792_000 picoseconds. - Weight::from_parts(244_114_692, 21740) + // Minimum execution time: 238_050_000 picoseconds. + Weight::from_parts(241_274_832, 21740) // Standard Error: 1 - .saturating_add(Weight::from_parts(589, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(590, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -757,10 +759,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `768 + r * (45 ±0)` // Estimated: `21660 + r * (225 ±0)` - // Minimum execution time: 231_166_000 picoseconds. - Weight::from_parts(233_339_177, 21660) - // Standard Error: 155_889 - .saturating_add(Weight::from_parts(3_124_322, 0).saturating_mul(r.into())) + // Minimum execution time: 231_807_000 picoseconds. + Weight::from_parts(234_264_848, 21660) + // Standard Error: 185_298 + .saturating_add(Weight::from_parts(1_000_351, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 225).saturating_mul(r.into())) @@ -780,10 +782,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `778` // Estimated: `21775` - // Minimum execution time: 235_721_000 picoseconds. - Weight::from_parts(237_413_703, 21775) - // Standard Error: 1 - .saturating_add(Weight::from_parts(177, 0).saturating_mul(n.into())) + // Minimum execution time: 234_347_000 picoseconds. + Weight::from_parts(234_774_467, 21775) + // Standard Error: 0 + .saturating_add(Weight::from_parts(183, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -808,10 +810,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `810 + r * (356 ±0)` // Estimated: `26094 + r * (15904 ±0)` - // Minimum execution time: 233_525_000 picoseconds. - Weight::from_parts(235_871_034, 26094) - // Standard Error: 235_338 - .saturating_add(Weight::from_parts(118_659_865, 0).saturating_mul(r.into())) + // Minimum execution time: 234_356_000 picoseconds. + Weight::from_parts(236_844_659, 26094) + // Standard Error: 161_035 + .saturating_add(Weight::from_parts(110_725_340, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((6_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -835,10 +837,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `825 + r * (10 ±0)` // Estimated: `24283 + r * (60 ±0)` - // Minimum execution time: 235_007_000 picoseconds. - Weight::from_parts(248_419_686, 24283) - // Standard Error: 1_847 - .saturating_add(Weight::from_parts(1_815_822, 0).saturating_mul(r.into())) + // Minimum execution time: 234_248_000 picoseconds. + Weight::from_parts(255_712_101, 24283) + // Standard Error: 1_474 + .saturating_add(Weight::from_parts(1_753_943, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 60).saturating_mul(r.into())) @@ -858,10 +860,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `778 + r * (10 ±0)` // Estimated: `21735 + r * (50 ±0)` - // Minimum execution time: 232_912_000 picoseconds. - Weight::from_parts(256_142_885, 21735) - // Standard Error: 2_741 - .saturating_add(Weight::from_parts(3_542_482, 0).saturating_mul(r.into())) + // Minimum execution time: 232_456_000 picoseconds. + Weight::from_parts(230_738_907, 21735) + // Standard Error: 4_163 + .saturating_add(Weight::from_parts(3_496_817, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 50).saturating_mul(r.into())) @@ -882,12 +884,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `797 + t * (32 ±0)` // Estimated: `21840 + t * (2640 ±0)` - // Minimum execution time: 251_018_000 picoseconds. - Weight::from_parts(245_280_765, 21840) - // Standard Error: 90_317 - .saturating_add(Weight::from_parts(2_434_496, 0).saturating_mul(t.into())) + // Minimum execution time: 251_638_000 picoseconds. + Weight::from_parts(244_791_817, 21840) + // Standard Error: 89_537 + .saturating_add(Weight::from_parts(2_459_492, 0).saturating_mul(t.into())) // Standard Error: 25 - .saturating_add(Weight::from_parts(599, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(626, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(t.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -909,10 +911,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `777 + r * (7 ±0)` // Estimated: `21725 + r * (35 ±0)` - // Minimum execution time: 164_022_000 picoseconds. - Weight::from_parts(168_658_387, 21725) - // Standard Error: 685 - .saturating_add(Weight::from_parts(238_133, 0).saturating_mul(r.into())) + // Minimum execution time: 164_736_000 picoseconds. + Weight::from_parts(164_496_597, 21725) + // Standard Error: 4_619 + .saturating_add(Weight::from_parts(252_013, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 35).saturating_mul(r.into())) @@ -932,10 +934,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `125728` // Estimated: `269977` - // Minimum execution time: 351_043_000 picoseconds. - Weight::from_parts(353_707_344, 269977) - // Standard Error: 3 - .saturating_add(Weight::from_parts(752, 0).saturating_mul(i.into())) + // Minimum execution time: 352_146_000 picoseconds. + Weight::from_parts(357_758_251, 269977) + // Standard Error: 1 + .saturating_add(Weight::from_parts(735, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -946,10 +948,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `845 + r * (292 ±0)` // Estimated: `843 + r * (293 ±0)` - // Minimum execution time: 235_854_000 picoseconds. - Weight::from_parts(133_986_225, 843) - // Standard Error: 9_550 - .saturating_add(Weight::from_parts(6_093_051, 0).saturating_mul(r.into())) + // Minimum execution time: 236_170_000 picoseconds. + Weight::from_parts(136_284_582, 843) + // Standard Error: 10_269 + .saturating_add(Weight::from_parts(5_995_228, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -963,10 +965,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1304` // Estimated: `1280` - // Minimum execution time: 252_321_000 picoseconds. - Weight::from_parts(285_820_577, 1280) - // Standard Error: 60 - .saturating_add(Weight::from_parts(600, 0).saturating_mul(n.into())) + // Minimum execution time: 253_837_000 picoseconds. + Weight::from_parts(287_029_261, 1280) + // Standard Error: 51 + .saturating_add(Weight::from_parts(534, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -977,10 +979,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1167 + n * (1 ±0)` // Estimated: `1167 + n * (1 ±0)` - // Minimum execution time: 252_047_000 picoseconds. - Weight::from_parts(254_244_310, 1167) - // Standard Error: 15 - .saturating_add(Weight::from_parts(144, 0).saturating_mul(n.into())) + // Minimum execution time: 253_037_000 picoseconds. + Weight::from_parts(256_401_533, 1167) + // Standard Error: 18 + .saturating_add(Weight::from_parts(32, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -992,10 +994,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `841 + r * (288 ±0)` // Estimated: `845 + r * (289 ±0)` - // Minimum execution time: 235_697_000 picoseconds. - Weight::from_parts(143_200_942, 845) - // Standard Error: 11_358 - .saturating_add(Weight::from_parts(5_934_318, 0).saturating_mul(r.into())) + // Minimum execution time: 236_800_000 picoseconds. + Weight::from_parts(134_748_031, 845) + // Standard Error: 9_560 + .saturating_add(Weight::from_parts(5_923_187, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1009,10 +1011,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1163 + n * (1 ±0)` // Estimated: `1163 + n * (1 ±0)` - // Minimum execution time: 250_360_000 picoseconds. - Weight::from_parts(252_712_722, 1163) - // Standard Error: 15 - .saturating_add(Weight::from_parts(130, 0).saturating_mul(n.into())) + // Minimum execution time: 250_601_000 picoseconds. + Weight::from_parts(253_618_803, 1163) + // Standard Error: 18 + .saturating_add(Weight::from_parts(74, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -1024,10 +1026,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `835 + r * (296 ±0)` // Estimated: `840 + r * (297 ±0)` - // Minimum execution time: 235_613_000 picoseconds. - Weight::from_parts(150_213_792, 840) - // Standard Error: 8_617 - .saturating_add(Weight::from_parts(4_962_874, 0).saturating_mul(r.into())) + // Minimum execution time: 236_194_000 picoseconds. + Weight::from_parts(152_630_909, 840) + // Standard Error: 8_573 + .saturating_add(Weight::from_parts(4_896_099, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1040,10 +1042,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1179 + n * (1 ±0)` // Estimated: `1179 + n * (1 ±0)` - // Minimum execution time: 249_137_000 picoseconds. - Weight::from_parts(253_529_386, 1179) - // Standard Error: 41 - .saturating_add(Weight::from_parts(612, 0).saturating_mul(n.into())) + // Minimum execution time: 250_989_000 picoseconds. + Weight::from_parts(260_170_747, 1179) + // Standard Error: 162 + .saturating_add(Weight::from_parts(224, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -1055,10 +1057,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `856 + r * (288 ±0)` // Estimated: `857 + r * (289 ±0)` - // Minimum execution time: 235_659_000 picoseconds. - Weight::from_parts(158_846_683, 857) - // Standard Error: 7_806 - .saturating_add(Weight::from_parts(4_728_537, 0).saturating_mul(r.into())) + // Minimum execution time: 236_574_000 picoseconds. + Weight::from_parts(155_573_955, 857) + // Standard Error: 10_270 + .saturating_add(Weight::from_parts(4_667_644, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1071,10 +1073,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1166 + n * (1 ±0)` // Estimated: `1166 + n * (1 ±0)` - // Minimum execution time: 248_553_000 picoseconds. - Weight::from_parts(250_703_269, 1166) - // Standard Error: 17 - .saturating_add(Weight::from_parts(163, 0).saturating_mul(n.into())) + // Minimum execution time: 249_502_000 picoseconds. + Weight::from_parts(251_496_311, 1166) + // Standard Error: 26 + .saturating_add(Weight::from_parts(186, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -1086,10 +1088,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `829 + r * (296 ±0)` // Estimated: `836 + r * (297 ±0)` - // Minimum execution time: 236_431_000 picoseconds. - Weight::from_parts(131_745_419, 836) - // Standard Error: 10_161 - .saturating_add(Weight::from_parts(6_182_174, 0).saturating_mul(r.into())) + // Minimum execution time: 236_030_000 picoseconds. + Weight::from_parts(128_595_856, 836) + // Standard Error: 10_530 + .saturating_add(Weight::from_parts(6_072_638, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1103,10 +1105,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1180 + n * (1 ±0)` // Estimated: `1180 + n * (1 ±0)` - // Minimum execution time: 252_551_000 picoseconds. - Weight::from_parts(254_517_030, 1180) - // Standard Error: 16 - .saturating_add(Weight::from_parts(712, 0).saturating_mul(n.into())) + // Minimum execution time: 254_027_000 picoseconds. + Weight::from_parts(260_739_475, 1180) + // Standard Error: 115 + .saturating_add(Weight::from_parts(330, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -1126,10 +1128,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1373 + r * (45 ±0)` // Estimated: `26753 + r * (2700 ±0)` - // Minimum execution time: 236_663_000 picoseconds. - Weight::from_parts(237_485_000, 26753) - // Standard Error: 42_414 - .saturating_add(Weight::from_parts(36_849_514, 0).saturating_mul(r.into())) + // Minimum execution time: 237_634_000 picoseconds. + Weight::from_parts(238_177_000, 26753) + // Standard Error: 23_320 + .saturating_add(Weight::from_parts(35_467_618, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(4_u64)) @@ -1151,10 +1153,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1237 + r * (256 ±0)` // Estimated: `26028 + r * (6235 ±0)` - // Minimum execution time: 237_101_000 picoseconds. - Weight::from_parts(237_827_000, 26028) - // Standard Error: 82_878 - .saturating_add(Weight::from_parts(211_777_724, 0).saturating_mul(r.into())) + // Minimum execution time: 237_076_000 picoseconds. + Weight::from_parts(237_792_000, 26028) + // Standard Error: 91_566 + .saturating_add(Weight::from_parts(212_893_975, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1176,10 +1178,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0 + r * (502 ±0)` // Estimated: `21755 + r * (6329 ±3)` - // Minimum execution time: 241_213_000 picoseconds. - Weight::from_parts(241_900_000, 21755) - // Standard Error: 99_976 - .saturating_add(Weight::from_parts(207_520_077, 0).saturating_mul(r.into())) + // Minimum execution time: 236_275_000 picoseconds. + Weight::from_parts(236_849_000, 21755) + // Standard Error: 92_724 + .saturating_add(Weight::from_parts(207_159_396, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1202,12 +1204,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1154 + t * (204 ±0)` // Estimated: `31015 + t * (5970 ±0)` - // Minimum execution time: 414_784_000 picoseconds. - Weight::from_parts(384_902_379, 31015) - // Standard Error: 1_228_593 - .saturating_add(Weight::from_parts(33_226_901, 0).saturating_mul(t.into())) + // Minimum execution time: 412_628_000 picoseconds. + Weight::from_parts(385_108_035, 31015) + // Standard Error: 1_002_078 + .saturating_add(Weight::from_parts(31_204_678, 0).saturating_mul(t.into())) // Standard Error: 1 - .saturating_add(Weight::from_parts(601, 0).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(598, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(t.into()))) .saturating_add(T::DbWeight::get().writes(5_u64)) @@ -1233,10 +1235,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1301 + r * (254 ±0)` // Estimated: `30977 + r * (16635 ±0)` - // Minimum execution time: 236_963_000 picoseconds. - Weight::from_parts(237_711_000, 30977) - // Standard Error: 265_576 - .saturating_add(Weight::from_parts(347_359_908, 0).saturating_mul(r.into())) + // Minimum execution time: 237_161_000 picoseconds. + Weight::from_parts(237_620_000, 30977) + // Standard Error: 258_036 + .saturating_add(Weight::from_parts(344_869_637, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().reads((6_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(6_u64)) @@ -1264,14 +1266,14 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1071 + t * (187 ±0)` // Estimated: `42684 + t * (3588 ±2)` - // Minimum execution time: 1_615_191_000 picoseconds. - Weight::from_parts(337_408_450, 42684) - // Standard Error: 4_581_951 - .saturating_add(Weight::from_parts(115_730_776, 0).saturating_mul(t.into())) + // Minimum execution time: 1_613_172_000 picoseconds. + Weight::from_parts(326_952_137, 42684) + // Standard Error: 4_738_925 + .saturating_add(Weight::from_parts(113_657_996, 0).saturating_mul(t.into())) // Standard Error: 7 - .saturating_add(Weight::from_parts(1_171, 0).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(1_173, 0).saturating_mul(i.into())) // Standard Error: 7 - .saturating_add(Weight::from_parts(1_346, 0).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_347, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(13_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(t.into()))) .saturating_add(T::DbWeight::get().writes(10_u64)) @@ -1293,10 +1295,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `777 + r * (8 ±0)` // Estimated: `21710 + r * (40 ±0)` - // Minimum execution time: 233_601_000 picoseconds. - Weight::from_parts(246_594_905, 21710) - // Standard Error: 2_840 - .saturating_add(Weight::from_parts(578_751, 0).saturating_mul(r.into())) + // Minimum execution time: 233_679_000 picoseconds. + Weight::from_parts(238_638_820, 21710) + // Standard Error: 681 + .saturating_add(Weight::from_parts(573_320, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) @@ -1316,10 +1318,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `785` // Estimated: `21745` - // Minimum execution time: 233_735_000 picoseconds. - Weight::from_parts(243_432_330, 21745) - // Standard Error: 3 - .saturating_add(Weight::from_parts(3_927, 0).saturating_mul(n.into())) + // Minimum execution time: 235_992_000 picoseconds. + Weight::from_parts(219_924_252, 21745) + // Standard Error: 5 + .saturating_add(Weight::from_parts(3_978, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1338,10 +1340,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `779 + r * (8 ±0)` // Estimated: `21725 + r * (40 ±0)` - // Minimum execution time: 232_173_000 picoseconds. - Weight::from_parts(239_806_011, 21725) - // Standard Error: 1_530 - .saturating_add(Weight::from_parts(749_641, 0).saturating_mul(r.into())) + // Minimum execution time: 240_661_000 picoseconds. + Weight::from_parts(238_809_422, 21725) + // Standard Error: 820 + .saturating_add(Weight::from_parts(741_326, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) @@ -1361,10 +1363,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `787` // Estimated: `21765` - // Minimum execution time: 235_046_000 picoseconds. - Weight::from_parts(229_500_792, 21765) + // Minimum execution time: 235_136_000 picoseconds. + Weight::from_parts(228_678_487, 21765) // Standard Error: 2 - .saturating_add(Weight::from_parts(3_166, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(3_164, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1383,10 +1385,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `779 + r * (8 ±0)` // Estimated: `21740 + r * (40 ±0)` - // Minimum execution time: 231_708_000 picoseconds. - Weight::from_parts(235_347_566, 21740) - // Standard Error: 987 - .saturating_add(Weight::from_parts(428_819, 0).saturating_mul(r.into())) + // Minimum execution time: 233_364_000 picoseconds. + Weight::from_parts(243_294_285, 21740) + // Standard Error: 1_607 + .saturating_add(Weight::from_parts(413_186, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) @@ -1406,10 +1408,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `787` // Estimated: `21785` - // Minimum execution time: 234_068_000 picoseconds. - Weight::from_parts(226_519_852, 21785) + // Minimum execution time: 234_315_000 picoseconds. + Weight::from_parts(225_569_537, 21785) // Standard Error: 1 - .saturating_add(Weight::from_parts(916, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(919, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1428,10 +1430,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `779 + r * (8 ±0)` // Estimated: `21745 + r * (40 ±0)` - // Minimum execution time: 231_872_000 picoseconds. - Weight::from_parts(236_694_763, 21745) - // Standard Error: 870 - .saturating_add(Weight::from_parts(420_853, 0).saturating_mul(r.into())) + // Minimum execution time: 233_288_000 picoseconds. + Weight::from_parts(239_289_154, 21745) + // Standard Error: 612 + .saturating_add(Weight::from_parts(414_275, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) @@ -1451,10 +1453,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `787` // Estimated: `21755` - // Minimum execution time: 233_707_000 picoseconds. - Weight::from_parts(226_312_559, 21755) - // Standard Error: 2 - .saturating_add(Weight::from_parts(924, 0).saturating_mul(n.into())) + // Minimum execution time: 233_686_000 picoseconds. + Weight::from_parts(227_406_694, 21755) + // Standard Error: 1 + .saturating_add(Weight::from_parts(919, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1468,15 +1470,61 @@ impl WeightInfo for SubstrateWeight { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) + /// The range of component `n` is `[0, 125697]`. + fn seal_sr25519_verify_per_byte(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `916 + n * (1 ±0)` + // Estimated: `22375 + n * (5 ±0)` + // Minimum execution time: 287_258_000 picoseconds. + Weight::from_parts(290_941_609, 22375) + // Standard Error: 8 + .saturating_add(Weight::from_parts(4_785, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_parts(0, 5).saturating_mul(n.into())) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) + /// The range of component `r` is `[0, 160]`. + fn seal_sr25519_verify(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `728 + r * (112 ±0)` + // Estimated: `21455 + r * (560 ±0)` + // Minimum execution time: 238_340_000 picoseconds. + Weight::from_parts(246_009_851, 21455) + // Standard Error: 21_677 + .saturating_add(Weight::from_parts(48_139_487, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_parts(0, 560).saturating_mul(r.into())) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 160]`. fn seal_ecdsa_recover(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `822 + r * (76 ±0)` // Estimated: `21705 + r * (385 ±0)` - // Minimum execution time: 234_962_000 picoseconds. - Weight::from_parts(252_611_292, 21705) - // Standard Error: 20_134 - .saturating_add(Weight::from_parts(37_745_358, 0).saturating_mul(r.into())) + // Minimum execution time: 236_244_000 picoseconds. + Weight::from_parts(253_749_242, 21705) + // Standard Error: 19_216 + .saturating_add(Weight::from_parts(37_706_782, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 385).saturating_mul(r.into())) @@ -1496,10 +1544,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `792 + r * (42 ±0)` // Estimated: `21775 + r * (210 ±0)` - // Minimum execution time: 234_869_000 picoseconds. - Weight::from_parts(240_188_331, 21775) - // Standard Error: 9_910 - .saturating_add(Weight::from_parts(9_332_432, 0).saturating_mul(r.into())) + // Minimum execution time: 235_770_000 picoseconds. + Weight::from_parts(230_780_347, 21775) + // Standard Error: 12_015 + .saturating_add(Weight::from_parts(9_584_947, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 210).saturating_mul(r.into())) @@ -1520,11 +1568,11 @@ impl WeightInfo for SubstrateWeight { fn seal_set_code_hash(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + r * (964 ±0)` - // Estimated: `29920 + r * (11544 ±10)` - // Minimum execution time: 235_036_000 picoseconds. - Weight::from_parts(235_538_000, 29920) - // Standard Error: 47_360 - .saturating_add(Weight::from_parts(22_113_144, 0).saturating_mul(r.into())) + // Estimated: `29920 + r * (11544 ±7)` + // Minimum execution time: 235_857_000 picoseconds. + Weight::from_parts(236_482_000, 29920) + // Standard Error: 47_818 + .saturating_add(Weight::from_parts(21_765_273, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1546,10 +1594,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `773 + r * (3 ±0)` // Estimated: `21735 + r * (15 ±0)` - // Minimum execution time: 237_884_000 picoseconds. - Weight::from_parts(243_315_095, 21735) - // Standard Error: 560 - .saturating_add(Weight::from_parts(162_206, 0).saturating_mul(r.into())) + // Minimum execution time: 235_388_000 picoseconds. + Weight::from_parts(240_149_512, 21735) + // Standard Error: 555 + .saturating_add(Weight::from_parts(162_666, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 15).saturating_mul(r.into())) @@ -1569,10 +1617,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1975 + r * (39 ±0)` // Estimated: `27145 + r * (200 ±0)` - // Minimum execution time: 239_402_000 picoseconds. - Weight::from_parts(267_214_783, 27145) - // Standard Error: 1_166 - .saturating_add(Weight::from_parts(261_915, 0).saturating_mul(r.into())) + // Minimum execution time: 237_485_000 picoseconds. + Weight::from_parts(268_044_053, 27145) + // Standard Error: 1_147 + .saturating_add(Weight::from_parts(260_572, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 200).saturating_mul(r.into())) @@ -1594,10 +1642,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `776 + r * (3 ±0)` // Estimated: `24004 + r * (18 ±0)` - // Minimum execution time: 233_153_000 picoseconds. - Weight::from_parts(238_999_965, 24004) - // Standard Error: 291 - .saturating_add(Weight::from_parts(143_971, 0).saturating_mul(r.into())) + // Minimum execution time: 234_123_000 picoseconds. + Weight::from_parts(245_872_832, 24004) + // Standard Error: 943 + .saturating_add(Weight::from_parts(136_460, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 18).saturating_mul(r.into())) @@ -1607,510 +1655,510 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_706_000 picoseconds. - Weight::from_parts(1_962_558, 0) + // Minimum execution time: 1_606_000 picoseconds. + Weight::from_parts(1_845_698, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(3_000, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(2_995, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64load(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_870_000 picoseconds. - Weight::from_parts(2_481_243, 0) + // Minimum execution time: 1_711_000 picoseconds. + Weight::from_parts(2_281_581, 0) // Standard Error: 4 - .saturating_add(Weight::from_parts(6_346, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(6_354, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64store(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_830_000 picoseconds. - Weight::from_parts(2_389_658, 0) + // Minimum execution time: 1_680_000 picoseconds. + Weight::from_parts(2_269_238, 0) // Standard Error: 4 - .saturating_add(Weight::from_parts(5_997, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(6_014, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_select(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_734_000 picoseconds. - Weight::from_parts(2_170_618, 0) - // Standard Error: 4 - .saturating_add(Weight::from_parts(7_919, 0).saturating_mul(r.into())) + // Minimum execution time: 1_592_000 picoseconds. + Weight::from_parts(2_010_963, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(7_927, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_if(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_661_000 picoseconds. - Weight::from_parts(1_945_771, 0) - // Standard Error: 11 - .saturating_add(Weight::from_parts(10_840, 0).saturating_mul(r.into())) + // Minimum execution time: 1_631_000 picoseconds. + Weight::from_parts(1_936_549, 0) + // Standard Error: 6 + .saturating_add(Weight::from_parts(10_426, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_br(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_682_000 picoseconds. - Weight::from_parts(1_970_774, 0) - // Standard Error: 11 - .saturating_add(Weight::from_parts(4_569, 0).saturating_mul(r.into())) + // Minimum execution time: 1_616_000 picoseconds. + Weight::from_parts(1_938_716, 0) + // Standard Error: 15 + .saturating_add(Weight::from_parts(4_525, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_br_if(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_668_000 picoseconds. - Weight::from_parts(1_227_080, 0) - // Standard Error: 76 - .saturating_add(Weight::from_parts(8_066, 0).saturating_mul(r.into())) + // Minimum execution time: 1_535_000 picoseconds. + Weight::from_parts(1_109_860, 0) + // Standard Error: 77 + .saturating_add(Weight::from_parts(7_998, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_br_table(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_653_000 picoseconds. - Weight::from_parts(1_394_759, 0) - // Standard Error: 39 - .saturating_add(Weight::from_parts(9_566, 0).saturating_mul(r.into())) + // Minimum execution time: 1_594_000 picoseconds. + Weight::from_parts(1_478_654, 0) + // Standard Error: 36 + .saturating_add(Weight::from_parts(9_525, 0).saturating_mul(r.into())) } /// The range of component `e` is `[1, 256]`. fn instr_br_table_per_entry(e: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_771_000 picoseconds. - Weight::from_parts(1_905_594, 0) - // Standard Error: 147 - .saturating_add(Weight::from_parts(925, 0).saturating_mul(e.into())) + // Minimum execution time: 1_730_000 picoseconds. + Weight::from_parts(1_836_342, 0) + // Standard Error: 14 + .saturating_add(Weight::from_parts(206, 0).saturating_mul(e.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_call(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_863_000 picoseconds. - Weight::from_parts(2_472_635, 0) - // Standard Error: 13 - .saturating_add(Weight::from_parts(17_892, 0).saturating_mul(r.into())) + // Minimum execution time: 1_607_000 picoseconds. + Weight::from_parts(2_150_133, 0) + // Standard Error: 17 + .saturating_add(Weight::from_parts(18_630, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_call_indirect(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_013_000 picoseconds. - Weight::from_parts(3_077_100, 0) - // Standard Error: 18 - .saturating_add(Weight::from_parts(24_287, 0).saturating_mul(r.into())) + // Minimum execution time: 1_824_000 picoseconds. + Weight::from_parts(3_119_825, 0) + // Standard Error: 15 + .saturating_add(Weight::from_parts(25_304, 0).saturating_mul(r.into())) } /// The range of component `l` is `[0, 1024]`. fn instr_call_per_local(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_818_000 picoseconds. - Weight::from_parts(2_109_143, 0) - // Standard Error: 34 - .saturating_add(Weight::from_parts(1_249, 0).saturating_mul(l.into())) + // Minimum execution time: 1_692_000 picoseconds. + Weight::from_parts(1_927_049, 0) + // Standard Error: 14 + .saturating_add(Weight::from_parts(1_217, 0).saturating_mul(l.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_local_get(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_083_000 picoseconds. - Weight::from_parts(3_291_328, 0) - // Standard Error: 1 - .saturating_add(Weight::from_parts(2_505, 0).saturating_mul(r.into())) + // Minimum execution time: 2_795_000 picoseconds. + Weight::from_parts(3_107_843, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(2_445, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_local_set(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_987_000 picoseconds. - Weight::from_parts(3_276_863, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(3_617, 0).saturating_mul(r.into())) + // Minimum execution time: 2_815_000 picoseconds. + Weight::from_parts(3_114_618, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(3_639, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_local_tee(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_942_000 picoseconds. - Weight::from_parts(3_350_581, 0) + // Minimum execution time: 2_861_000 picoseconds. + Weight::from_parts(3_193_592, 0) // Standard Error: 3 - .saturating_add(Weight::from_parts(3_976, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_957, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_global_get(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_867_000 picoseconds. - Weight::from_parts(2_920_748, 0) - // Standard Error: 44 - .saturating_add(Weight::from_parts(8_229, 0).saturating_mul(r.into())) + // Minimum execution time: 1_710_000 picoseconds. + Weight::from_parts(2_148_021, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(8_391, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_global_set(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_757_000 picoseconds. - Weight::from_parts(2_235_198, 0) - // Standard Error: 4 - .saturating_add(Weight::from_parts(8_815, 0).saturating_mul(r.into())) + // Minimum execution time: 1_663_000 picoseconds. + Weight::from_parts(2_170_373, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(8_812, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_memory_current(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_824_000 picoseconds. - Weight::from_parts(1_941_816, 0) - // Standard Error: 86 - .saturating_add(Weight::from_parts(4_043, 0).saturating_mul(r.into())) + // Minimum execution time: 1_662_000 picoseconds. + Weight::from_parts(2_601_398, 0) + // Standard Error: 198 + .saturating_add(Weight::from_parts(3_851, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 16]`. fn instr_memory_grow(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_793_000 picoseconds. - Weight::from_parts(1_104_829, 0) - // Standard Error: 137_800 - .saturating_add(Weight::from_parts(13_336_784, 0).saturating_mul(r.into())) + // Minimum execution time: 1_603_000 picoseconds. + Weight::from_parts(332_932, 0) + // Standard Error: 137_529 + .saturating_add(Weight::from_parts(13_233_734, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64clz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_693_000 picoseconds. - Weight::from_parts(2_037_305, 0) + // Minimum execution time: 1_613_000 picoseconds. + Weight::from_parts(1_922_391, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(4_044, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_903, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64ctz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_751_000 picoseconds. - Weight::from_parts(2_082_016, 0) + // Minimum execution time: 1_522_000 picoseconds. + Weight::from_parts(1_920_023, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(3_767, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_876, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64popcnt(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_751_000 picoseconds. - Weight::from_parts(2_110_625, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(3_754, 0).saturating_mul(r.into())) + // Minimum execution time: 1_590_000 picoseconds. + Weight::from_parts(1_867_406, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(3_910, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64eqz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_756_000 picoseconds. - Weight::from_parts(2_100_327, 0) + // Minimum execution time: 1_577_000 picoseconds. + Weight::from_parts(1_918_037, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(3_664, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_673, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64extendsi32(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_643_000 picoseconds. - Weight::from_parts(2_169_153, 0) + // Minimum execution time: 1_589_000 picoseconds. + Weight::from_parts(1_917_901, 0) // Standard Error: 3 - .saturating_add(Weight::from_parts(3_961, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_956, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64extendui32(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_704_000 picoseconds. - Weight::from_parts(2_049_172, 0) + // Minimum execution time: 1_573_000 picoseconds. + Weight::from_parts(1_902_324, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(3_833, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_865, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i32wrapi64(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_726_000 picoseconds. - Weight::from_parts(2_064_387, 0) + // Minimum execution time: 1_586_000 picoseconds. + Weight::from_parts(1_953_738, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(3_745, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_838, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64eq(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_696_000 picoseconds. - Weight::from_parts(2_426_905, 0) - // Standard Error: 56 - .saturating_add(Weight::from_parts(5_915, 0).saturating_mul(r.into())) + // Minimum execution time: 1_598_000 picoseconds. + Weight::from_parts(1_912_180, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(5_994, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64ne(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_617_000 picoseconds. - Weight::from_parts(2_035_161, 0) - // Standard Error: 94 - .saturating_add(Weight::from_parts(6_073, 0).saturating_mul(r.into())) + // Minimum execution time: 1_573_000 picoseconds. + Weight::from_parts(1_943_725, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(5_998, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64lts(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_756_000 picoseconds. - Weight::from_parts(2_098_926, 0) + // Minimum execution time: 1_584_000 picoseconds. + Weight::from_parts(1_949_209, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(6_002, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(5_991, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64ltu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_706_000 picoseconds. - Weight::from_parts(2_257_972, 0) - // Standard Error: 23 - .saturating_add(Weight::from_parts(5_982, 0).saturating_mul(r.into())) + // Minimum execution time: 1_576_000 picoseconds. + Weight::from_parts(1_927_466, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(6_005, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64gts(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_761_000 picoseconds. - Weight::from_parts(2_114_141, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(5_815, 0).saturating_mul(r.into())) + // Minimum execution time: 1_566_000 picoseconds. + Weight::from_parts(2_004_312, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(5_799, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64gtu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_700_000 picoseconds. - Weight::from_parts(2_053_201, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(6_137, 0).saturating_mul(r.into())) + // Minimum execution time: 1_538_000 picoseconds. + Weight::from_parts(1_922_703, 0) + // Standard Error: 9 + .saturating_add(Weight::from_parts(6_129, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64les(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_705_000 picoseconds. - Weight::from_parts(2_101_782, 0) + // Minimum execution time: 1_575_000 picoseconds. + Weight::from_parts(1_978_271, 0) // Standard Error: 3 - .saturating_add(Weight::from_parts(6_014, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(5_991, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64leu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_856_000 picoseconds. - Weight::from_parts(2_149_707, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(6_086, 0).saturating_mul(r.into())) + // Minimum execution time: 1_572_000 picoseconds. + Weight::from_parts(4_028_578, 0) + // Standard Error: 263 + .saturating_add(Weight::from_parts(5_784, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64ges(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_739_000 picoseconds. - Weight::from_parts(2_143_216, 0) + // Minimum execution time: 1_615_000 picoseconds. + Weight::from_parts(1_962_065, 0) // Standard Error: 3 - .saturating_add(Weight::from_parts(5_934, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(5_945, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64geu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_716_000 picoseconds. - Weight::from_parts(2_065_762, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(6_009, 0).saturating_mul(r.into())) + // Minimum execution time: 1_578_000 picoseconds. + Weight::from_parts(1_909_721, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(5_993, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64add(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_664_000 picoseconds. - Weight::from_parts(3_062_283, 0) - // Standard Error: 94 - .saturating_add(Weight::from_parts(5_645, 0).saturating_mul(r.into())) + // Minimum execution time: 1_609_000 picoseconds. + Weight::from_parts(1_926_472, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(5_888, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64sub(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_671_000 picoseconds. - Weight::from_parts(2_011_145, 0) - // Standard Error: 44 - .saturating_add(Weight::from_parts(6_220, 0).saturating_mul(r.into())) + // Minimum execution time: 1_620_000 picoseconds. + Weight::from_parts(2_875_196, 0) + // Standard Error: 177 + .saturating_add(Weight::from_parts(5_990, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64mul(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_759_000 picoseconds. - Weight::from_parts(2_095_420, 0) - // Standard Error: 4 - .saturating_add(Weight::from_parts(5_723, 0).saturating_mul(r.into())) + // Minimum execution time: 1_570_000 picoseconds. + Weight::from_parts(2_155_483, 0) + // Standard Error: 83 + .saturating_add(Weight::from_parts(5_675, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64divs(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_672_000 picoseconds. - Weight::from_parts(2_184_044, 0) + // Minimum execution time: 1_558_000 picoseconds. + Weight::from_parts(2_108_263, 0) // Standard Error: 5 - .saturating_add(Weight::from_parts(11_782, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(11_755, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64divu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_752_000 picoseconds. - Weight::from_parts(2_276_209, 0) - // Standard Error: 5 - .saturating_add(Weight::from_parts(10_513, 0).saturating_mul(r.into())) + // Minimum execution time: 1_568_000 picoseconds. + Weight::from_parts(1_606_397, 0) + // Standard Error: 51 + .saturating_add(Weight::from_parts(11_011, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64rems(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_711_000 picoseconds. - Weight::from_parts(2_720_989, 0) + // Minimum execution time: 1_630_000 picoseconds. + Weight::from_parts(2_872_487, 0) // Standard Error: 24 - .saturating_add(Weight::from_parts(11_884, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(11_761, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64remu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_713_000 picoseconds. - Weight::from_parts(2_091_403, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(10_628, 0).saturating_mul(r.into())) + // Minimum execution time: 1_575_000 picoseconds. + Weight::from_parts(2_385_398, 0) + // Standard Error: 45 + .saturating_add(Weight::from_parts(10_650, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64and(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_704_000 picoseconds. - Weight::from_parts(2_054_652, 0) + // Minimum execution time: 1_622_000 picoseconds. + Weight::from_parts(1_957_246, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(5_672, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(5_659, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64or(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_743_000 picoseconds. - Weight::from_parts(2_032_806, 0) - // Standard Error: 19 - .saturating_add(Weight::from_parts(5_795, 0).saturating_mul(r.into())) + // Minimum execution time: 1_551_000 picoseconds. + Weight::from_parts(1_897_168, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(5_774, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64xor(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_667_000 picoseconds. - Weight::from_parts(2_031_702, 0) - // Standard Error: 5 - .saturating_add(Weight::from_parts(5_923, 0).saturating_mul(r.into())) + // Minimum execution time: 1_549_000 picoseconds. + Weight::from_parts(1_915_938, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(5_915, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64shl(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_735_000 picoseconds. - Weight::from_parts(2_946_634, 0) - // Standard Error: 54 - .saturating_add(Weight::from_parts(5_685, 0).saturating_mul(r.into())) + // Minimum execution time: 1_617_000 picoseconds. + Weight::from_parts(1_932_618, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(5_854, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64shrs(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_652_000 picoseconds. - Weight::from_parts(2_023_049, 0) - // Standard Error: 4 - .saturating_add(Weight::from_parts(6_146, 0).saturating_mul(r.into())) + // Minimum execution time: 1_617_000 picoseconds. + Weight::from_parts(1_937_566, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(6_134, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64shru(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_654_000 picoseconds. - Weight::from_parts(2_148_951, 0) + // Minimum execution time: 1_584_000 picoseconds. + Weight::from_parts(1_980_681, 0) // Standard Error: 3 - .saturating_add(Weight::from_parts(5_869, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(5_842, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64rotl(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_730_000 picoseconds. - Weight::from_parts(2_130_543, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(5_999, 0).saturating_mul(r.into())) + // Minimum execution time: 1_542_000 picoseconds. + Weight::from_parts(2_131_567, 0) + // Standard Error: 57 + .saturating_add(Weight::from_parts(6_010, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64rotr(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_728_000 picoseconds. - Weight::from_parts(2_172_886, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(5_843, 0).saturating_mul(r.into())) + // Minimum execution time: 1_609_000 picoseconds. + Weight::from_parts(1_643_214, 0) + // Standard Error: 91 + .saturating_add(Weight::from_parts(6_062, 0).saturating_mul(r.into())) } } @@ -2122,8 +2170,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `109` // Estimated: `1594` - // Minimum execution time: 2_677_000 picoseconds. - Weight::from_parts(2_899_000, 1594) + // Minimum execution time: 2_503_000 picoseconds. + Weight::from_parts(2_603_000, 1594) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: Skipped Metadata (r:0 w:0) @@ -2133,10 +2181,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `488 + k * (69 ±0)` // Estimated: `478 + k * (70 ±0)` - // Minimum execution time: 14_006_000 picoseconds. - Weight::from_parts(8_735_946, 478) - // Standard Error: 1_370 - .saturating_add(Weight::from_parts(989_501, 0).saturating_mul(k.into())) + // Minimum execution time: 13_292_000 picoseconds. + Weight::from_parts(9_180_439, 478) + // Standard Error: 997 + .saturating_add(Weight::from_parts(967_522, 0).saturating_mul(k.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(RocksDbWeight::get().writes(2_u64)) @@ -2152,10 +2200,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `238 + c * (1 ±0)` // Estimated: `3951 + c * (2 ±0)` - // Minimum execution time: 30_951_000 picoseconds. - Weight::from_parts(25_988_560, 3951) - // Standard Error: 57 - .saturating_add(Weight::from_parts(54_692, 0).saturating_mul(c.into())) + // Minimum execution time: 30_822_000 picoseconds. + Weight::from_parts(26_457_115, 3951) + // Standard Error: 58 + .saturating_add(Weight::from_parts(54_868, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 2).saturating_mul(c.into())) @@ -2175,10 +2223,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `707` // Estimated: `21400 + c * (5 ±0)` - // Minimum execution time: 263_107_000 picoseconds. - Weight::from_parts(268_289_665, 21400) - // Standard Error: 33 - .saturating_add(Weight::from_parts(38_534, 0).saturating_mul(c.into())) + // Minimum execution time: 263_719_000 picoseconds. + Weight::from_parts(275_281_941, 21400) + // Standard Error: 32 + .saturating_add(Weight::from_parts(37_880, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 5).saturating_mul(c.into())) @@ -2206,14 +2254,14 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `270` // Estimated: `26207` - // Minimum execution time: 3_122_319_000 picoseconds. - Weight::from_parts(487_802_180, 26207) - // Standard Error: 345 - .saturating_add(Weight::from_parts(108_237, 0).saturating_mul(c.into())) - // Standard Error: 20 - .saturating_add(Weight::from_parts(1_166, 0).saturating_mul(i.into())) - // Standard Error: 20 - .saturating_add(Weight::from_parts(1_505, 0).saturating_mul(s.into())) + // Minimum execution time: 3_133_756_000 picoseconds. + Weight::from_parts(556_483_545, 26207) + // Standard Error: 294 + .saturating_add(Weight::from_parts(107_914, 0).saturating_mul(c.into())) + // Standard Error: 17 + .saturating_add(Weight::from_parts(1_143, 0).saturating_mul(i.into())) + // Standard Error: 17 + .saturating_add(Weight::from_parts(1_456, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(10_u64)) } @@ -2237,12 +2285,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `482` // Estimated: `28521` - // Minimum execution time: 1_650_623_000 picoseconds. - Weight::from_parts(286_494_456, 28521) + // Minimum execution time: 1_646_953_000 picoseconds. + Weight::from_parts(262_115_215, 28521) // Standard Error: 8 - .saturating_add(Weight::from_parts(1_438, 0).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(1_454, 0).saturating_mul(i.into())) // Standard Error: 8 - .saturating_add(Weight::from_parts(1_453, 0).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_463, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } @@ -2260,8 +2308,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `759` // Estimated: `21615` - // Minimum execution time: 191_046_000 picoseconds. - Weight::from_parts(192_544_000, 21615) + // Minimum execution time: 190_769_000 picoseconds. + Weight::from_parts(191_717_000, 21615) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -2278,10 +2326,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `109` // Estimated: `7366` - // Minimum execution time: 244_260_000 picoseconds. - Weight::from_parts(254_693_985, 7366) - // Standard Error: 80 - .saturating_add(Weight::from_parts(108_246, 0).saturating_mul(c.into())) + // Minimum execution time: 246_204_000 picoseconds. + Weight::from_parts(243_234_754, 7366) + // Standard Error: 78 + .saturating_add(Weight::from_parts(109_232, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -2297,8 +2345,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `255` // Estimated: `7950` - // Minimum execution time: 33_492_000 picoseconds. - Weight::from_parts(34_079_000, 7950) + // Minimum execution time: 33_516_000 picoseconds. + Weight::from_parts(33_995_000, 7950) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -2312,8 +2360,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `570` // Estimated: `19530` - // Minimum execution time: 33_475_000 picoseconds. - Weight::from_parts(33_856_000, 19530) + // Minimum execution time: 33_255_000 picoseconds. + Weight::from_parts(33_692_000, 19530) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -2332,10 +2380,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `781 + r * (6 ±0)` // Estimated: `21730 + r * (30 ±0)` - // Minimum execution time: 234_197_000 picoseconds. - Weight::from_parts(236_830_305, 21730) - // Standard Error: 818 - .saturating_add(Weight::from_parts(336_446, 0).saturating_mul(r.into())) + // Minimum execution time: 235_074_000 picoseconds. + Weight::from_parts(243_735_179, 21730) + // Standard Error: 972 + .saturating_add(Weight::from_parts(328_571, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -2355,10 +2403,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `839 + r * (240 ±0)` // Estimated: `21835 + r * (3675 ±0)` - // Minimum execution time: 235_872_000 picoseconds. - Weight::from_parts(78_877_890, 21835) - // Standard Error: 6_405 - .saturating_add(Weight::from_parts(3_358_341, 0).saturating_mul(r.into())) + // Minimum execution time: 236_455_000 picoseconds. + Weight::from_parts(81_818_936, 21835) + // Standard Error: 5_874 + .saturating_add(Weight::from_parts(3_316_006, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -2379,10 +2427,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `831 + r * (244 ±0)` // Estimated: `21855 + r * (3695 ±0)` - // Minimum execution time: 239_035_000 picoseconds. - Weight::from_parts(93_255_085, 21855) - // Standard Error: 5_922 - .saturating_add(Weight::from_parts(4_144_910, 0).saturating_mul(r.into())) + // Minimum execution time: 237_724_000 picoseconds. + Weight::from_parts(91_384_964, 21855) + // Standard Error: 5_828 + .saturating_add(Weight::from_parts(4_063_221, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -2403,10 +2451,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `788 + r * (6 ±0)` // Estimated: `21770 + r * (30 ±0)` - // Minimum execution time: 236_507_000 picoseconds. - Weight::from_parts(238_253_211, 21770) - // Standard Error: 975 - .saturating_add(Weight::from_parts(413_919, 0).saturating_mul(r.into())) + // Minimum execution time: 236_144_000 picoseconds. + Weight::from_parts(239_917_873, 21770) + // Standard Error: 629 + .saturating_add(Weight::from_parts(409_752, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -2426,10 +2474,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `778 + r * (3 ±0)` // Estimated: `21735 + r * (15 ±0)` - // Minimum execution time: 235_521_000 picoseconds. - Weight::from_parts(238_397_362, 21735) - // Standard Error: 452 - .saturating_add(Weight::from_parts(160_860, 0).saturating_mul(r.into())) + // Minimum execution time: 232_946_000 picoseconds. + Weight::from_parts(243_163_112, 21735) + // Standard Error: 1_940 + .saturating_add(Weight::from_parts(162_705, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 15).saturating_mul(r.into())) @@ -2449,10 +2497,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `782 + r * (6 ±0)` // Estimated: `21740 + r * (30 ±0)` - // Minimum execution time: 234_722_000 picoseconds. - Weight::from_parts(242_936_096, 21740) - // Standard Error: 1_178 - .saturating_add(Weight::from_parts(329_075, 0).saturating_mul(r.into())) + // Minimum execution time: 235_301_000 picoseconds. + Weight::from_parts(240_802_312, 21740) + // Standard Error: 5_362 + .saturating_add(Weight::from_parts(339_001, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -2472,10 +2520,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `783 + r * (6 ±0)` // Estimated: `21725 + r * (30 ±0)` - // Minimum execution time: 235_654_000 picoseconds. - Weight::from_parts(245_887_792, 21725) - // Standard Error: 903 - .saturating_add(Weight::from_parts(325_168, 0).saturating_mul(r.into())) + // Minimum execution time: 235_683_000 picoseconds. + Weight::from_parts(237_357_276, 21725) + // Standard Error: 726 + .saturating_add(Weight::from_parts(333_264, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -2495,10 +2543,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `922 + r * (6 ±0)` // Estimated: `24633 + r * (30 ±0)` - // Minimum execution time: 233_599_000 picoseconds. - Weight::from_parts(251_561_602, 24633) - // Standard Error: 3_348 - .saturating_add(Weight::from_parts(1_475_443, 0).saturating_mul(r.into())) + // Minimum execution time: 234_327_000 picoseconds. + Weight::from_parts(239_792_456, 24633) + // Standard Error: 3_460 + .saturating_add(Weight::from_parts(1_496_090, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -2518,10 +2566,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `792 + r * (6 ±0)` // Estimated: `21825 + r * (30 ±0)` - // Minimum execution time: 235_087_000 picoseconds. - Weight::from_parts(235_855_322, 21825) - // Standard Error: 867 - .saturating_add(Weight::from_parts(346_707, 0).saturating_mul(r.into())) + // Minimum execution time: 235_466_000 picoseconds. + Weight::from_parts(242_580_658, 21825) + // Standard Error: 1_439 + .saturating_add(Weight::from_parts(323_842, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -2541,10 +2589,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `790 + r * (6 ±0)` // Estimated: `21815 + r * (30 ±0)` - // Minimum execution time: 237_103_000 picoseconds. - Weight::from_parts(239_272_188, 21815) - // Standard Error: 892 - .saturating_add(Weight::from_parts(328_334, 0).saturating_mul(r.into())) + // Minimum execution time: 238_529_000 picoseconds. + Weight::from_parts(249_276_722, 21815) + // Standard Error: 1_216 + .saturating_add(Weight::from_parts(328_600, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -2564,10 +2612,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `787 + r * (6 ±0)` // Estimated: `21805 + r * (30 ±0)` - // Minimum execution time: 234_761_000 picoseconds. - Weight::from_parts(238_601_784, 21805) - // Standard Error: 725 - .saturating_add(Weight::from_parts(325_758, 0).saturating_mul(r.into())) + // Minimum execution time: 234_360_000 picoseconds. + Weight::from_parts(239_927_876, 21805) + // Standard Error: 541 + .saturating_add(Weight::from_parts(319_553, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -2587,10 +2635,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `778 + r * (6 ±0)` // Estimated: `21735 + r * (30 ±0)` - // Minimum execution time: 235_249_000 picoseconds. - Weight::from_parts(239_861_242, 21735) - // Standard Error: 751 - .saturating_add(Weight::from_parts(325_795, 0).saturating_mul(r.into())) + // Minimum execution time: 234_461_000 picoseconds. + Weight::from_parts(239_682_633, 21735) + // Standard Error: 544 + .saturating_add(Weight::from_parts(322_943, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -2612,10 +2660,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `856 + r * (10 ±0)` // Estimated: `24446 + r * (60 ±0)` - // Minimum execution time: 234_912_000 picoseconds. - Weight::from_parts(254_783_734, 24446) - // Standard Error: 1_610 - .saturating_add(Weight::from_parts(1_307_506, 0).saturating_mul(r.into())) + // Minimum execution time: 234_862_000 picoseconds. + Weight::from_parts(252_614_390, 24446) + // Standard Error: 1_180 + .saturating_add(Weight::from_parts(1_313_286, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 60).saturating_mul(r.into())) @@ -2635,10 +2683,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `745 + r * (4 ±0)` // Estimated: `21555 + r * (20 ±0)` - // Minimum execution time: 160_125_000 picoseconds. - Weight::from_parts(164_915_574, 21555) - // Standard Error: 332 - .saturating_add(Weight::from_parts(132_326, 0).saturating_mul(r.into())) + // Minimum execution time: 161_003_000 picoseconds. + Weight::from_parts(165_793_675, 21555) + // Standard Error: 323 + .saturating_add(Weight::from_parts(128_941, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 20).saturating_mul(r.into())) @@ -2658,10 +2706,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `780 + r * (6 ±0)` // Estimated: `21740 + r * (30 ±0)` - // Minimum execution time: 234_717_000 picoseconds. - Weight::from_parts(238_540_521, 21740) - // Standard Error: 599 - .saturating_add(Weight::from_parts(277_303, 0).saturating_mul(r.into())) + // Minimum execution time: 235_192_000 picoseconds. + Weight::from_parts(241_225_671, 21740) + // Standard Error: 1_132 + .saturating_add(Weight::from_parts(272_760, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) @@ -2681,10 +2729,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `784` // Estimated: `21740` - // Minimum execution time: 235_792_000 picoseconds. - Weight::from_parts(244_114_692, 21740) + // Minimum execution time: 238_050_000 picoseconds. + Weight::from_parts(241_274_832, 21740) // Standard Error: 1 - .saturating_add(Weight::from_parts(589, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(590, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -2703,10 +2751,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `768 + r * (45 ±0)` // Estimated: `21660 + r * (225 ±0)` - // Minimum execution time: 231_166_000 picoseconds. - Weight::from_parts(233_339_177, 21660) - // Standard Error: 155_889 - .saturating_add(Weight::from_parts(3_124_322, 0).saturating_mul(r.into())) + // Minimum execution time: 231_807_000 picoseconds. + Weight::from_parts(234_264_848, 21660) + // Standard Error: 185_298 + .saturating_add(Weight::from_parts(1_000_351, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 225).saturating_mul(r.into())) @@ -2726,10 +2774,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `778` // Estimated: `21775` - // Minimum execution time: 235_721_000 picoseconds. - Weight::from_parts(237_413_703, 21775) - // Standard Error: 1 - .saturating_add(Weight::from_parts(177, 0).saturating_mul(n.into())) + // Minimum execution time: 234_347_000 picoseconds. + Weight::from_parts(234_774_467, 21775) + // Standard Error: 0 + .saturating_add(Weight::from_parts(183, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -2754,10 +2802,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `810 + r * (356 ±0)` // Estimated: `26094 + r * (15904 ±0)` - // Minimum execution time: 233_525_000 picoseconds. - Weight::from_parts(235_871_034, 26094) - // Standard Error: 235_338 - .saturating_add(Weight::from_parts(118_659_865, 0).saturating_mul(r.into())) + // Minimum execution time: 234_356_000 picoseconds. + Weight::from_parts(236_844_659, 26094) + // Standard Error: 161_035 + .saturating_add(Weight::from_parts(110_725_340, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((6_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -2781,10 +2829,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `825 + r * (10 ±0)` // Estimated: `24283 + r * (60 ±0)` - // Minimum execution time: 235_007_000 picoseconds. - Weight::from_parts(248_419_686, 24283) - // Standard Error: 1_847 - .saturating_add(Weight::from_parts(1_815_822, 0).saturating_mul(r.into())) + // Minimum execution time: 234_248_000 picoseconds. + Weight::from_parts(255_712_101, 24283) + // Standard Error: 1_474 + .saturating_add(Weight::from_parts(1_753_943, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 60).saturating_mul(r.into())) @@ -2804,10 +2852,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `778 + r * (10 ±0)` // Estimated: `21735 + r * (50 ±0)` - // Minimum execution time: 232_912_000 picoseconds. - Weight::from_parts(256_142_885, 21735) - // Standard Error: 2_741 - .saturating_add(Weight::from_parts(3_542_482, 0).saturating_mul(r.into())) + // Minimum execution time: 232_456_000 picoseconds. + Weight::from_parts(230_738_907, 21735) + // Standard Error: 4_163 + .saturating_add(Weight::from_parts(3_496_817, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 50).saturating_mul(r.into())) @@ -2828,12 +2876,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `797 + t * (32 ±0)` // Estimated: `21840 + t * (2640 ±0)` - // Minimum execution time: 251_018_000 picoseconds. - Weight::from_parts(245_280_765, 21840) - // Standard Error: 90_317 - .saturating_add(Weight::from_parts(2_434_496, 0).saturating_mul(t.into())) + // Minimum execution time: 251_638_000 picoseconds. + Weight::from_parts(244_791_817, 21840) + // Standard Error: 89_537 + .saturating_add(Weight::from_parts(2_459_492, 0).saturating_mul(t.into())) // Standard Error: 25 - .saturating_add(Weight::from_parts(599, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(626, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(t.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -2855,10 +2903,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `777 + r * (7 ±0)` // Estimated: `21725 + r * (35 ±0)` - // Minimum execution time: 164_022_000 picoseconds. - Weight::from_parts(168_658_387, 21725) - // Standard Error: 685 - .saturating_add(Weight::from_parts(238_133, 0).saturating_mul(r.into())) + // Minimum execution time: 164_736_000 picoseconds. + Weight::from_parts(164_496_597, 21725) + // Standard Error: 4_619 + .saturating_add(Weight::from_parts(252_013, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 35).saturating_mul(r.into())) @@ -2878,10 +2926,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `125728` // Estimated: `269977` - // Minimum execution time: 351_043_000 picoseconds. - Weight::from_parts(353_707_344, 269977) - // Standard Error: 3 - .saturating_add(Weight::from_parts(752, 0).saturating_mul(i.into())) + // Minimum execution time: 352_146_000 picoseconds. + Weight::from_parts(357_758_251, 269977) + // Standard Error: 1 + .saturating_add(Weight::from_parts(735, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -2892,10 +2940,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `845 + r * (292 ±0)` // Estimated: `843 + r * (293 ±0)` - // Minimum execution time: 235_854_000 picoseconds. - Weight::from_parts(133_986_225, 843) - // Standard Error: 9_550 - .saturating_add(Weight::from_parts(6_093_051, 0).saturating_mul(r.into())) + // Minimum execution time: 236_170_000 picoseconds. + Weight::from_parts(136_284_582, 843) + // Standard Error: 10_269 + .saturating_add(Weight::from_parts(5_995_228, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -2909,10 +2957,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1304` // Estimated: `1280` - // Minimum execution time: 252_321_000 picoseconds. - Weight::from_parts(285_820_577, 1280) - // Standard Error: 60 - .saturating_add(Weight::from_parts(600, 0).saturating_mul(n.into())) + // Minimum execution time: 253_837_000 picoseconds. + Weight::from_parts(287_029_261, 1280) + // Standard Error: 51 + .saturating_add(Weight::from_parts(534, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -2923,10 +2971,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1167 + n * (1 ±0)` // Estimated: `1167 + n * (1 ±0)` - // Minimum execution time: 252_047_000 picoseconds. - Weight::from_parts(254_244_310, 1167) - // Standard Error: 15 - .saturating_add(Weight::from_parts(144, 0).saturating_mul(n.into())) + // Minimum execution time: 253_037_000 picoseconds. + Weight::from_parts(256_401_533, 1167) + // Standard Error: 18 + .saturating_add(Weight::from_parts(32, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -2938,10 +2986,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `841 + r * (288 ±0)` // Estimated: `845 + r * (289 ±0)` - // Minimum execution time: 235_697_000 picoseconds. - Weight::from_parts(143_200_942, 845) - // Standard Error: 11_358 - .saturating_add(Weight::from_parts(5_934_318, 0).saturating_mul(r.into())) + // Minimum execution time: 236_800_000 picoseconds. + Weight::from_parts(134_748_031, 845) + // Standard Error: 9_560 + .saturating_add(Weight::from_parts(5_923_187, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -2955,10 +3003,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1163 + n * (1 ±0)` // Estimated: `1163 + n * (1 ±0)` - // Minimum execution time: 250_360_000 picoseconds. - Weight::from_parts(252_712_722, 1163) - // Standard Error: 15 - .saturating_add(Weight::from_parts(130, 0).saturating_mul(n.into())) + // Minimum execution time: 250_601_000 picoseconds. + Weight::from_parts(253_618_803, 1163) + // Standard Error: 18 + .saturating_add(Weight::from_parts(74, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -2970,10 +3018,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `835 + r * (296 ±0)` // Estimated: `840 + r * (297 ±0)` - // Minimum execution time: 235_613_000 picoseconds. - Weight::from_parts(150_213_792, 840) - // Standard Error: 8_617 - .saturating_add(Weight::from_parts(4_962_874, 0).saturating_mul(r.into())) + // Minimum execution time: 236_194_000 picoseconds. + Weight::from_parts(152_630_909, 840) + // Standard Error: 8_573 + .saturating_add(Weight::from_parts(4_896_099, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -2986,10 +3034,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1179 + n * (1 ±0)` // Estimated: `1179 + n * (1 ±0)` - // Minimum execution time: 249_137_000 picoseconds. - Weight::from_parts(253_529_386, 1179) - // Standard Error: 41 - .saturating_add(Weight::from_parts(612, 0).saturating_mul(n.into())) + // Minimum execution time: 250_989_000 picoseconds. + Weight::from_parts(260_170_747, 1179) + // Standard Error: 162 + .saturating_add(Weight::from_parts(224, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -3001,10 +3049,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `856 + r * (288 ±0)` // Estimated: `857 + r * (289 ±0)` - // Minimum execution time: 235_659_000 picoseconds. - Weight::from_parts(158_846_683, 857) - // Standard Error: 7_806 - .saturating_add(Weight::from_parts(4_728_537, 0).saturating_mul(r.into())) + // Minimum execution time: 236_574_000 picoseconds. + Weight::from_parts(155_573_955, 857) + // Standard Error: 10_270 + .saturating_add(Weight::from_parts(4_667_644, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3017,10 +3065,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1166 + n * (1 ±0)` // Estimated: `1166 + n * (1 ±0)` - // Minimum execution time: 248_553_000 picoseconds. - Weight::from_parts(250_703_269, 1166) - // Standard Error: 17 - .saturating_add(Weight::from_parts(163, 0).saturating_mul(n.into())) + // Minimum execution time: 249_502_000 picoseconds. + Weight::from_parts(251_496_311, 1166) + // Standard Error: 26 + .saturating_add(Weight::from_parts(186, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -3032,10 +3080,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `829 + r * (296 ±0)` // Estimated: `836 + r * (297 ±0)` - // Minimum execution time: 236_431_000 picoseconds. - Weight::from_parts(131_745_419, 836) - // Standard Error: 10_161 - .saturating_add(Weight::from_parts(6_182_174, 0).saturating_mul(r.into())) + // Minimum execution time: 236_030_000 picoseconds. + Weight::from_parts(128_595_856, 836) + // Standard Error: 10_530 + .saturating_add(Weight::from_parts(6_072_638, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3049,10 +3097,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1180 + n * (1 ±0)` // Estimated: `1180 + n * (1 ±0)` - // Minimum execution time: 252_551_000 picoseconds. - Weight::from_parts(254_517_030, 1180) - // Standard Error: 16 - .saturating_add(Weight::from_parts(712, 0).saturating_mul(n.into())) + // Minimum execution time: 254_027_000 picoseconds. + Weight::from_parts(260_739_475, 1180) + // Standard Error: 115 + .saturating_add(Weight::from_parts(330, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -3072,10 +3120,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1373 + r * (45 ±0)` // Estimated: `26753 + r * (2700 ±0)` - // Minimum execution time: 236_663_000 picoseconds. - Weight::from_parts(237_485_000, 26753) - // Standard Error: 42_414 - .saturating_add(Weight::from_parts(36_849_514, 0).saturating_mul(r.into())) + // Minimum execution time: 237_634_000 picoseconds. + Weight::from_parts(238_177_000, 26753) + // Standard Error: 23_320 + .saturating_add(Weight::from_parts(35_467_618, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(4_u64)) @@ -3097,10 +3145,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1237 + r * (256 ±0)` // Estimated: `26028 + r * (6235 ±0)` - // Minimum execution time: 237_101_000 picoseconds. - Weight::from_parts(237_827_000, 26028) - // Standard Error: 82_878 - .saturating_add(Weight::from_parts(211_777_724, 0).saturating_mul(r.into())) + // Minimum execution time: 237_076_000 picoseconds. + Weight::from_parts(237_792_000, 26028) + // Standard Error: 91_566 + .saturating_add(Weight::from_parts(212_893_975, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3122,10 +3170,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0 + r * (502 ±0)` // Estimated: `21755 + r * (6329 ±3)` - // Minimum execution time: 241_213_000 picoseconds. - Weight::from_parts(241_900_000, 21755) - // Standard Error: 99_976 - .saturating_add(Weight::from_parts(207_520_077, 0).saturating_mul(r.into())) + // Minimum execution time: 236_275_000 picoseconds. + Weight::from_parts(236_849_000, 21755) + // Standard Error: 92_724 + .saturating_add(Weight::from_parts(207_159_396, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3148,12 +3196,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1154 + t * (204 ±0)` // Estimated: `31015 + t * (5970 ±0)` - // Minimum execution time: 414_784_000 picoseconds. - Weight::from_parts(384_902_379, 31015) - // Standard Error: 1_228_593 - .saturating_add(Weight::from_parts(33_226_901, 0).saturating_mul(t.into())) + // Minimum execution time: 412_628_000 picoseconds. + Weight::from_parts(385_108_035, 31015) + // Standard Error: 1_002_078 + .saturating_add(Weight::from_parts(31_204_678, 0).saturating_mul(t.into())) // Standard Error: 1 - .saturating_add(Weight::from_parts(601, 0).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(598, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(t.into()))) .saturating_add(RocksDbWeight::get().writes(5_u64)) @@ -3179,10 +3227,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1301 + r * (254 ±0)` // Estimated: `30977 + r * (16635 ±0)` - // Minimum execution time: 236_963_000 picoseconds. - Weight::from_parts(237_711_000, 30977) - // Standard Error: 265_576 - .saturating_add(Weight::from_parts(347_359_908, 0).saturating_mul(r.into())) + // Minimum execution time: 237_161_000 picoseconds. + Weight::from_parts(237_620_000, 30977) + // Standard Error: 258_036 + .saturating_add(Weight::from_parts(344_869_637, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().reads((6_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(6_u64)) @@ -3210,14 +3258,14 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1071 + t * (187 ±0)` // Estimated: `42684 + t * (3588 ±2)` - // Minimum execution time: 1_615_191_000 picoseconds. - Weight::from_parts(337_408_450, 42684) - // Standard Error: 4_581_951 - .saturating_add(Weight::from_parts(115_730_776, 0).saturating_mul(t.into())) + // Minimum execution time: 1_613_172_000 picoseconds. + Weight::from_parts(326_952_137, 42684) + // Standard Error: 4_738_925 + .saturating_add(Weight::from_parts(113_657_996, 0).saturating_mul(t.into())) // Standard Error: 7 - .saturating_add(Weight::from_parts(1_171, 0).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(1_173, 0).saturating_mul(i.into())) // Standard Error: 7 - .saturating_add(Weight::from_parts(1_346, 0).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_347, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(13_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(t.into()))) .saturating_add(RocksDbWeight::get().writes(10_u64)) @@ -3239,10 +3287,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `777 + r * (8 ±0)` // Estimated: `21710 + r * (40 ±0)` - // Minimum execution time: 233_601_000 picoseconds. - Weight::from_parts(246_594_905, 21710) - // Standard Error: 2_840 - .saturating_add(Weight::from_parts(578_751, 0).saturating_mul(r.into())) + // Minimum execution time: 233_679_000 picoseconds. + Weight::from_parts(238_638_820, 21710) + // Standard Error: 681 + .saturating_add(Weight::from_parts(573_320, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) @@ -3262,10 +3310,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `785` // Estimated: `21745` - // Minimum execution time: 233_735_000 picoseconds. - Weight::from_parts(243_432_330, 21745) - // Standard Error: 3 - .saturating_add(Weight::from_parts(3_927, 0).saturating_mul(n.into())) + // Minimum execution time: 235_992_000 picoseconds. + Weight::from_parts(219_924_252, 21745) + // Standard Error: 5 + .saturating_add(Weight::from_parts(3_978, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3284,10 +3332,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `779 + r * (8 ±0)` // Estimated: `21725 + r * (40 ±0)` - // Minimum execution time: 232_173_000 picoseconds. - Weight::from_parts(239_806_011, 21725) - // Standard Error: 1_530 - .saturating_add(Weight::from_parts(749_641, 0).saturating_mul(r.into())) + // Minimum execution time: 240_661_000 picoseconds. + Weight::from_parts(238_809_422, 21725) + // Standard Error: 820 + .saturating_add(Weight::from_parts(741_326, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) @@ -3307,10 +3355,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `787` // Estimated: `21765` - // Minimum execution time: 235_046_000 picoseconds. - Weight::from_parts(229_500_792, 21765) + // Minimum execution time: 235_136_000 picoseconds. + Weight::from_parts(228_678_487, 21765) // Standard Error: 2 - .saturating_add(Weight::from_parts(3_166, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(3_164, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3329,10 +3377,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `779 + r * (8 ±0)` // Estimated: `21740 + r * (40 ±0)` - // Minimum execution time: 231_708_000 picoseconds. - Weight::from_parts(235_347_566, 21740) - // Standard Error: 987 - .saturating_add(Weight::from_parts(428_819, 0).saturating_mul(r.into())) + // Minimum execution time: 233_364_000 picoseconds. + Weight::from_parts(243_294_285, 21740) + // Standard Error: 1_607 + .saturating_add(Weight::from_parts(413_186, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) @@ -3352,10 +3400,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `787` // Estimated: `21785` - // Minimum execution time: 234_068_000 picoseconds. - Weight::from_parts(226_519_852, 21785) + // Minimum execution time: 234_315_000 picoseconds. + Weight::from_parts(225_569_537, 21785) // Standard Error: 1 - .saturating_add(Weight::from_parts(916, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(919, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3374,10 +3422,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `779 + r * (8 ±0)` // Estimated: `21745 + r * (40 ±0)` - // Minimum execution time: 231_872_000 picoseconds. - Weight::from_parts(236_694_763, 21745) - // Standard Error: 870 - .saturating_add(Weight::from_parts(420_853, 0).saturating_mul(r.into())) + // Minimum execution time: 233_288_000 picoseconds. + Weight::from_parts(239_289_154, 21745) + // Standard Error: 612 + .saturating_add(Weight::from_parts(414_275, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) @@ -3397,10 +3445,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `787` // Estimated: `21755` - // Minimum execution time: 233_707_000 picoseconds. - Weight::from_parts(226_312_559, 21755) - // Standard Error: 2 - .saturating_add(Weight::from_parts(924, 0).saturating_mul(n.into())) + // Minimum execution time: 233_686_000 picoseconds. + Weight::from_parts(227_406_694, 21755) + // Standard Error: 1 + .saturating_add(Weight::from_parts(919, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3414,15 +3462,61 @@ impl WeightInfo for () { /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) /// Storage: System EventTopics (r:2 w:2) /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) + /// The range of component `n` is `[0, 125697]`. + fn seal_sr25519_verify_per_byte(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `916 + n * (1 ±0)` + // Estimated: `22375 + n * (5 ±0)` + // Minimum execution time: 287_258_000 picoseconds. + Weight::from_parts(290_941_609, 22375) + // Standard Error: 8 + .saturating_add(Weight::from_parts(4_785, 0).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_parts(0, 5).saturating_mul(n.into())) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) + /// The range of component `r` is `[0, 160]`. + fn seal_sr25519_verify(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `728 + r * (112 ±0)` + // Estimated: `21455 + r * (560 ±0)` + // Minimum execution time: 238_340_000 picoseconds. + Weight::from_parts(246_009_851, 21455) + // Standard Error: 21_677 + .saturating_add(Weight::from_parts(48_139_487, 0).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_parts(0, 560).saturating_mul(r.into())) + } + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) + /// Storage: Contracts ContractInfoOf (r:1 w:1) + /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) + /// Storage: Contracts CodeStorage (r:1 w:0) + /// Proof: Contracts CodeStorage (max_values: None, max_size: Some(126001), added: 128476, mode: Measured) + /// Storage: Timestamp Now (r:1 w:0) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: Measured) + /// Storage: System EventTopics (r:2 w:2) + /// Proof Skipped: System EventTopics (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 160]`. fn seal_ecdsa_recover(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `822 + r * (76 ±0)` // Estimated: `21705 + r * (385 ±0)` - // Minimum execution time: 234_962_000 picoseconds. - Weight::from_parts(252_611_292, 21705) - // Standard Error: 20_134 - .saturating_add(Weight::from_parts(37_745_358, 0).saturating_mul(r.into())) + // Minimum execution time: 236_244_000 picoseconds. + Weight::from_parts(253_749_242, 21705) + // Standard Error: 19_216 + .saturating_add(Weight::from_parts(37_706_782, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 385).saturating_mul(r.into())) @@ -3442,10 +3536,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `792 + r * (42 ±0)` // Estimated: `21775 + r * (210 ±0)` - // Minimum execution time: 234_869_000 picoseconds. - Weight::from_parts(240_188_331, 21775) - // Standard Error: 9_910 - .saturating_add(Weight::from_parts(9_332_432, 0).saturating_mul(r.into())) + // Minimum execution time: 235_770_000 picoseconds. + Weight::from_parts(230_780_347, 21775) + // Standard Error: 12_015 + .saturating_add(Weight::from_parts(9_584_947, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 210).saturating_mul(r.into())) @@ -3466,11 +3560,11 @@ impl WeightInfo for () { fn seal_set_code_hash(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + r * (964 ±0)` - // Estimated: `29920 + r * (11544 ±10)` - // Minimum execution time: 235_036_000 picoseconds. - Weight::from_parts(235_538_000, 29920) - // Standard Error: 47_360 - .saturating_add(Weight::from_parts(22_113_144, 0).saturating_mul(r.into())) + // Estimated: `29920 + r * (11544 ±7)` + // Minimum execution time: 235_857_000 picoseconds. + Weight::from_parts(236_482_000, 29920) + // Standard Error: 47_818 + .saturating_add(Weight::from_parts(21_765_273, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3492,10 +3586,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `773 + r * (3 ±0)` // Estimated: `21735 + r * (15 ±0)` - // Minimum execution time: 237_884_000 picoseconds. - Weight::from_parts(243_315_095, 21735) - // Standard Error: 560 - .saturating_add(Weight::from_parts(162_206, 0).saturating_mul(r.into())) + // Minimum execution time: 235_388_000 picoseconds. + Weight::from_parts(240_149_512, 21735) + // Standard Error: 555 + .saturating_add(Weight::from_parts(162_666, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 15).saturating_mul(r.into())) @@ -3515,10 +3609,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1975 + r * (39 ±0)` // Estimated: `27145 + r * (200 ±0)` - // Minimum execution time: 239_402_000 picoseconds. - Weight::from_parts(267_214_783, 27145) - // Standard Error: 1_166 - .saturating_add(Weight::from_parts(261_915, 0).saturating_mul(r.into())) + // Minimum execution time: 237_485_000 picoseconds. + Weight::from_parts(268_044_053, 27145) + // Standard Error: 1_147 + .saturating_add(Weight::from_parts(260_572, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 200).saturating_mul(r.into())) @@ -3540,10 +3634,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `776 + r * (3 ±0)` // Estimated: `24004 + r * (18 ±0)` - // Minimum execution time: 233_153_000 picoseconds. - Weight::from_parts(238_999_965, 24004) - // Standard Error: 291 - .saturating_add(Weight::from_parts(143_971, 0).saturating_mul(r.into())) + // Minimum execution time: 234_123_000 picoseconds. + Weight::from_parts(245_872_832, 24004) + // Standard Error: 943 + .saturating_add(Weight::from_parts(136_460, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 18).saturating_mul(r.into())) @@ -3553,509 +3647,509 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_706_000 picoseconds. - Weight::from_parts(1_962_558, 0) + // Minimum execution time: 1_606_000 picoseconds. + Weight::from_parts(1_845_698, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(3_000, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(2_995, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64load(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_870_000 picoseconds. - Weight::from_parts(2_481_243, 0) + // Minimum execution time: 1_711_000 picoseconds. + Weight::from_parts(2_281_581, 0) // Standard Error: 4 - .saturating_add(Weight::from_parts(6_346, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(6_354, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64store(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_830_000 picoseconds. - Weight::from_parts(2_389_658, 0) + // Minimum execution time: 1_680_000 picoseconds. + Weight::from_parts(2_269_238, 0) // Standard Error: 4 - .saturating_add(Weight::from_parts(5_997, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(6_014, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_select(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_734_000 picoseconds. - Weight::from_parts(2_170_618, 0) - // Standard Error: 4 - .saturating_add(Weight::from_parts(7_919, 0).saturating_mul(r.into())) + // Minimum execution time: 1_592_000 picoseconds. + Weight::from_parts(2_010_963, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(7_927, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_if(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_661_000 picoseconds. - Weight::from_parts(1_945_771, 0) - // Standard Error: 11 - .saturating_add(Weight::from_parts(10_840, 0).saturating_mul(r.into())) + // Minimum execution time: 1_631_000 picoseconds. + Weight::from_parts(1_936_549, 0) + // Standard Error: 6 + .saturating_add(Weight::from_parts(10_426, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_br(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_682_000 picoseconds. - Weight::from_parts(1_970_774, 0) - // Standard Error: 11 - .saturating_add(Weight::from_parts(4_569, 0).saturating_mul(r.into())) + // Minimum execution time: 1_616_000 picoseconds. + Weight::from_parts(1_938_716, 0) + // Standard Error: 15 + .saturating_add(Weight::from_parts(4_525, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_br_if(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_668_000 picoseconds. - Weight::from_parts(1_227_080, 0) - // Standard Error: 76 - .saturating_add(Weight::from_parts(8_066, 0).saturating_mul(r.into())) + // Minimum execution time: 1_535_000 picoseconds. + Weight::from_parts(1_109_860, 0) + // Standard Error: 77 + .saturating_add(Weight::from_parts(7_998, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_br_table(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_653_000 picoseconds. - Weight::from_parts(1_394_759, 0) - // Standard Error: 39 - .saturating_add(Weight::from_parts(9_566, 0).saturating_mul(r.into())) + // Minimum execution time: 1_594_000 picoseconds. + Weight::from_parts(1_478_654, 0) + // Standard Error: 36 + .saturating_add(Weight::from_parts(9_525, 0).saturating_mul(r.into())) } /// The range of component `e` is `[1, 256]`. fn instr_br_table_per_entry(e: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_771_000 picoseconds. - Weight::from_parts(1_905_594, 0) - // Standard Error: 147 - .saturating_add(Weight::from_parts(925, 0).saturating_mul(e.into())) + // Minimum execution time: 1_730_000 picoseconds. + Weight::from_parts(1_836_342, 0) + // Standard Error: 14 + .saturating_add(Weight::from_parts(206, 0).saturating_mul(e.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_call(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_863_000 picoseconds. - Weight::from_parts(2_472_635, 0) - // Standard Error: 13 - .saturating_add(Weight::from_parts(17_892, 0).saturating_mul(r.into())) + // Minimum execution time: 1_607_000 picoseconds. + Weight::from_parts(2_150_133, 0) + // Standard Error: 17 + .saturating_add(Weight::from_parts(18_630, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_call_indirect(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_013_000 picoseconds. - Weight::from_parts(3_077_100, 0) - // Standard Error: 18 - .saturating_add(Weight::from_parts(24_287, 0).saturating_mul(r.into())) + // Minimum execution time: 1_824_000 picoseconds. + Weight::from_parts(3_119_825, 0) + // Standard Error: 15 + .saturating_add(Weight::from_parts(25_304, 0).saturating_mul(r.into())) } /// The range of component `l` is `[0, 1024]`. fn instr_call_per_local(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_818_000 picoseconds. - Weight::from_parts(2_109_143, 0) - // Standard Error: 34 - .saturating_add(Weight::from_parts(1_249, 0).saturating_mul(l.into())) + // Minimum execution time: 1_692_000 picoseconds. + Weight::from_parts(1_927_049, 0) + // Standard Error: 14 + .saturating_add(Weight::from_parts(1_217, 0).saturating_mul(l.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_local_get(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_083_000 picoseconds. - Weight::from_parts(3_291_328, 0) - // Standard Error: 1 - .saturating_add(Weight::from_parts(2_505, 0).saturating_mul(r.into())) + // Minimum execution time: 2_795_000 picoseconds. + Weight::from_parts(3_107_843, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(2_445, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_local_set(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_987_000 picoseconds. - Weight::from_parts(3_276_863, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(3_617, 0).saturating_mul(r.into())) + // Minimum execution time: 2_815_000 picoseconds. + Weight::from_parts(3_114_618, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(3_639, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_local_tee(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_942_000 picoseconds. - Weight::from_parts(3_350_581, 0) + // Minimum execution time: 2_861_000 picoseconds. + Weight::from_parts(3_193_592, 0) // Standard Error: 3 - .saturating_add(Weight::from_parts(3_976, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_957, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_global_get(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_867_000 picoseconds. - Weight::from_parts(2_920_748, 0) - // Standard Error: 44 - .saturating_add(Weight::from_parts(8_229, 0).saturating_mul(r.into())) + // Minimum execution time: 1_710_000 picoseconds. + Weight::from_parts(2_148_021, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(8_391, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_global_set(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_757_000 picoseconds. - Weight::from_parts(2_235_198, 0) - // Standard Error: 4 - .saturating_add(Weight::from_parts(8_815, 0).saturating_mul(r.into())) + // Minimum execution time: 1_663_000 picoseconds. + Weight::from_parts(2_170_373, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(8_812, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_memory_current(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_824_000 picoseconds. - Weight::from_parts(1_941_816, 0) - // Standard Error: 86 - .saturating_add(Weight::from_parts(4_043, 0).saturating_mul(r.into())) + // Minimum execution time: 1_662_000 picoseconds. + Weight::from_parts(2_601_398, 0) + // Standard Error: 198 + .saturating_add(Weight::from_parts(3_851, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 16]`. fn instr_memory_grow(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_793_000 picoseconds. - Weight::from_parts(1_104_829, 0) - // Standard Error: 137_800 - .saturating_add(Weight::from_parts(13_336_784, 0).saturating_mul(r.into())) + // Minimum execution time: 1_603_000 picoseconds. + Weight::from_parts(332_932, 0) + // Standard Error: 137_529 + .saturating_add(Weight::from_parts(13_233_734, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64clz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_693_000 picoseconds. - Weight::from_parts(2_037_305, 0) + // Minimum execution time: 1_613_000 picoseconds. + Weight::from_parts(1_922_391, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(4_044, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_903, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64ctz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_751_000 picoseconds. - Weight::from_parts(2_082_016, 0) + // Minimum execution time: 1_522_000 picoseconds. + Weight::from_parts(1_920_023, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(3_767, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_876, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64popcnt(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_751_000 picoseconds. - Weight::from_parts(2_110_625, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(3_754, 0).saturating_mul(r.into())) + // Minimum execution time: 1_590_000 picoseconds. + Weight::from_parts(1_867_406, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(3_910, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64eqz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_756_000 picoseconds. - Weight::from_parts(2_100_327, 0) + // Minimum execution time: 1_577_000 picoseconds. + Weight::from_parts(1_918_037, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(3_664, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_673, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64extendsi32(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_643_000 picoseconds. - Weight::from_parts(2_169_153, 0) + // Minimum execution time: 1_589_000 picoseconds. + Weight::from_parts(1_917_901, 0) // Standard Error: 3 - .saturating_add(Weight::from_parts(3_961, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_956, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64extendui32(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_704_000 picoseconds. - Weight::from_parts(2_049_172, 0) + // Minimum execution time: 1_573_000 picoseconds. + Weight::from_parts(1_902_324, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(3_833, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_865, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i32wrapi64(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_726_000 picoseconds. - Weight::from_parts(2_064_387, 0) + // Minimum execution time: 1_586_000 picoseconds. + Weight::from_parts(1_953_738, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(3_745, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_838, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64eq(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_696_000 picoseconds. - Weight::from_parts(2_426_905, 0) - // Standard Error: 56 - .saturating_add(Weight::from_parts(5_915, 0).saturating_mul(r.into())) + // Minimum execution time: 1_598_000 picoseconds. + Weight::from_parts(1_912_180, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(5_994, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64ne(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_617_000 picoseconds. - Weight::from_parts(2_035_161, 0) - // Standard Error: 94 - .saturating_add(Weight::from_parts(6_073, 0).saturating_mul(r.into())) + // Minimum execution time: 1_573_000 picoseconds. + Weight::from_parts(1_943_725, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(5_998, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64lts(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_756_000 picoseconds. - Weight::from_parts(2_098_926, 0) + // Minimum execution time: 1_584_000 picoseconds. + Weight::from_parts(1_949_209, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(6_002, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(5_991, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64ltu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_706_000 picoseconds. - Weight::from_parts(2_257_972, 0) - // Standard Error: 23 - .saturating_add(Weight::from_parts(5_982, 0).saturating_mul(r.into())) + // Minimum execution time: 1_576_000 picoseconds. + Weight::from_parts(1_927_466, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(6_005, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64gts(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_761_000 picoseconds. - Weight::from_parts(2_114_141, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(5_815, 0).saturating_mul(r.into())) + // Minimum execution time: 1_566_000 picoseconds. + Weight::from_parts(2_004_312, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(5_799, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64gtu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_700_000 picoseconds. - Weight::from_parts(2_053_201, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(6_137, 0).saturating_mul(r.into())) + // Minimum execution time: 1_538_000 picoseconds. + Weight::from_parts(1_922_703, 0) + // Standard Error: 9 + .saturating_add(Weight::from_parts(6_129, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64les(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_705_000 picoseconds. - Weight::from_parts(2_101_782, 0) + // Minimum execution time: 1_575_000 picoseconds. + Weight::from_parts(1_978_271, 0) // Standard Error: 3 - .saturating_add(Weight::from_parts(6_014, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(5_991, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64leu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_856_000 picoseconds. - Weight::from_parts(2_149_707, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(6_086, 0).saturating_mul(r.into())) + // Minimum execution time: 1_572_000 picoseconds. + Weight::from_parts(4_028_578, 0) + // Standard Error: 263 + .saturating_add(Weight::from_parts(5_784, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64ges(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_739_000 picoseconds. - Weight::from_parts(2_143_216, 0) + // Minimum execution time: 1_615_000 picoseconds. + Weight::from_parts(1_962_065, 0) // Standard Error: 3 - .saturating_add(Weight::from_parts(5_934, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(5_945, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64geu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_716_000 picoseconds. - Weight::from_parts(2_065_762, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(6_009, 0).saturating_mul(r.into())) + // Minimum execution time: 1_578_000 picoseconds. + Weight::from_parts(1_909_721, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(5_993, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64add(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_664_000 picoseconds. - Weight::from_parts(3_062_283, 0) - // Standard Error: 94 - .saturating_add(Weight::from_parts(5_645, 0).saturating_mul(r.into())) + // Minimum execution time: 1_609_000 picoseconds. + Weight::from_parts(1_926_472, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(5_888, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64sub(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_671_000 picoseconds. - Weight::from_parts(2_011_145, 0) - // Standard Error: 44 - .saturating_add(Weight::from_parts(6_220, 0).saturating_mul(r.into())) + // Minimum execution time: 1_620_000 picoseconds. + Weight::from_parts(2_875_196, 0) + // Standard Error: 177 + .saturating_add(Weight::from_parts(5_990, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64mul(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_759_000 picoseconds. - Weight::from_parts(2_095_420, 0) - // Standard Error: 4 - .saturating_add(Weight::from_parts(5_723, 0).saturating_mul(r.into())) + // Minimum execution time: 1_570_000 picoseconds. + Weight::from_parts(2_155_483, 0) + // Standard Error: 83 + .saturating_add(Weight::from_parts(5_675, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64divs(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_672_000 picoseconds. - Weight::from_parts(2_184_044, 0) + // Minimum execution time: 1_558_000 picoseconds. + Weight::from_parts(2_108_263, 0) // Standard Error: 5 - .saturating_add(Weight::from_parts(11_782, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(11_755, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64divu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_752_000 picoseconds. - Weight::from_parts(2_276_209, 0) - // Standard Error: 5 - .saturating_add(Weight::from_parts(10_513, 0).saturating_mul(r.into())) + // Minimum execution time: 1_568_000 picoseconds. + Weight::from_parts(1_606_397, 0) + // Standard Error: 51 + .saturating_add(Weight::from_parts(11_011, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64rems(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_711_000 picoseconds. - Weight::from_parts(2_720_989, 0) + // Minimum execution time: 1_630_000 picoseconds. + Weight::from_parts(2_872_487, 0) // Standard Error: 24 - .saturating_add(Weight::from_parts(11_884, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(11_761, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64remu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_713_000 picoseconds. - Weight::from_parts(2_091_403, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(10_628, 0).saturating_mul(r.into())) + // Minimum execution time: 1_575_000 picoseconds. + Weight::from_parts(2_385_398, 0) + // Standard Error: 45 + .saturating_add(Weight::from_parts(10_650, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64and(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_704_000 picoseconds. - Weight::from_parts(2_054_652, 0) + // Minimum execution time: 1_622_000 picoseconds. + Weight::from_parts(1_957_246, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(5_672, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(5_659, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64or(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_743_000 picoseconds. - Weight::from_parts(2_032_806, 0) - // Standard Error: 19 - .saturating_add(Weight::from_parts(5_795, 0).saturating_mul(r.into())) + // Minimum execution time: 1_551_000 picoseconds. + Weight::from_parts(1_897_168, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(5_774, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64xor(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_667_000 picoseconds. - Weight::from_parts(2_031_702, 0) - // Standard Error: 5 - .saturating_add(Weight::from_parts(5_923, 0).saturating_mul(r.into())) + // Minimum execution time: 1_549_000 picoseconds. + Weight::from_parts(1_915_938, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(5_915, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64shl(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_735_000 picoseconds. - Weight::from_parts(2_946_634, 0) - // Standard Error: 54 - .saturating_add(Weight::from_parts(5_685, 0).saturating_mul(r.into())) + // Minimum execution time: 1_617_000 picoseconds. + Weight::from_parts(1_932_618, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(5_854, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64shrs(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_652_000 picoseconds. - Weight::from_parts(2_023_049, 0) - // Standard Error: 4 - .saturating_add(Weight::from_parts(6_146, 0).saturating_mul(r.into())) + // Minimum execution time: 1_617_000 picoseconds. + Weight::from_parts(1_937_566, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(6_134, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64shru(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_654_000 picoseconds. - Weight::from_parts(2_148_951, 0) + // Minimum execution time: 1_584_000 picoseconds. + Weight::from_parts(1_980_681, 0) // Standard Error: 3 - .saturating_add(Weight::from_parts(5_869, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(5_842, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64rotl(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_730_000 picoseconds. - Weight::from_parts(2_130_543, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(5_999, 0).saturating_mul(r.into())) + // Minimum execution time: 1_542_000 picoseconds. + Weight::from_parts(2_131_567, 0) + // Standard Error: 57 + .saturating_add(Weight::from_parts(6_010, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64rotr(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_728_000 picoseconds. - Weight::from_parts(2_172_886, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(5_843, 0).saturating_mul(r.into())) + // Minimum execution time: 1_609_000 picoseconds. + Weight::from_parts(1_643_214, 0) + // Standard Error: 91 + .saturating_add(Weight::from_parts(6_062, 0).saturating_mul(r.into())) } } From f0d3bbbbc3da6c5455dea0c7cb18f9d0862b5558 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 12 Apr 2023 14:42:22 -0400 Subject: [PATCH 643/715] Globally upgrade to syn 2.x and latest quote and proc_macro2 1x versions (#13846) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * globally upgrade quote to latest 1.0.x (1.0.26) * globally upgrade syn to final 1.0.x version (1.0.109) * globally upgrade proc-macro2 to 1.0.56 * upgrade to syn v2.0.13 and fix everything except NestedMeta * fix parse nested metadata code in decl_runtime_apis.rs * Port more stuff to syn 2.0 * Make the rest compile * Ignore error * update to syn 2.0.14 --------- Co-authored-by: Bastian Köcher --- Cargo.lock | 36 +++--- bin/node/cli/tests/telemetry.rs | 5 +- client/chain-spec/derive/Cargo.toml | 6 +- client/chain-spec/derive/src/impls.rs | 2 +- client/consensus/babe/src/lib.rs | 5 +- client/db/src/pinned_blocks_cache.rs | 5 +- client/service/test/src/client/mod.rs | 5 +- client/state-db/src/lib.rs | 10 +- client/tracing/proc-macro/Cargo.toml | 6 +- frame/contracts/proc-macro/Cargo.toml | 6 +- frame/contracts/proc-macro/src/lib.rs | 10 +- .../solution-type/Cargo.toml | 6 +- .../solution-type/src/lib.rs | 4 +- frame/nfts/src/tests.rs | 6 +- frame/scheduler/src/migration.rs | 10 +- frame/staking/reward-curve/Cargo.toml | 6 +- frame/support/procedural/Cargo.toml | 6 +- frame/support/procedural/src/benchmark.rs | 90 ++++++------- .../procedural/src/construct_runtime/mod.rs | 2 +- .../procedural/src/construct_runtime/parse.rs | 31 ++--- .../procedural/src/default_no_bound.rs | 4 +- .../procedural/src/pallet/expand/call.rs | 10 +- .../procedural/src/pallet/expand/constants.rs | 2 +- .../src/pallet/expand/documentation.rs | 119 ++++++------------ .../procedural/src/pallet/expand/storage.rs | 25 ++-- .../procedural/src/pallet/parse/call.rs | 6 +- .../procedural/src/pallet/parse/composite.rs | 25 ++-- .../procedural/src/pallet/parse/config.rs | 36 ++++-- .../procedural/src/pallet/parse/error.rs | 2 +- .../src/pallet/parse/extra_constants.rs | 4 +- .../procedural/src/pallet/parse/helper.rs | 9 +- .../procedural/src/pallet/parse/hooks.rs | 2 +- .../procedural/src/pallet/parse/storage.rs | 12 +- .../procedural/src/pallet/parse/type_value.rs | 6 +- frame/support/procedural/src/pallet_error.rs | 79 +++++------- .../genesis_config/genesis_config_def.rs | 7 +- frame/support/procedural/src/storage/mod.rs | 4 +- .../src/storage/print_pallet_upgrade.rs | 14 +-- frame/support/procedural/tools/Cargo.toml | 6 +- .../procedural/tools/derive/Cargo.toml | 6 +- frame/support/procedural/tools/src/lib.rs | 13 +- .../pallet_ui/pallet_doc_arg_non_path.stderr | 2 +- .../tests/pallet_ui/pallet_doc_empty.stderr | 2 +- .../pallet_ui/pallet_doc_invalid_arg.stderr | 2 +- .../pallet_ui/pallet_doc_multiple_args.stderr | 2 +- ...result_query_parenthesized_generics.stderr | 4 +- primitives/api/proc-macro/Cargo.toml | 6 +- .../api/proc-macro/src/decl_runtime_apis.rs | 91 ++++++-------- .../api/proc-macro/src/impl_runtime_apis.rs | 6 +- .../proc-macro/src/mock_impl_runtime_apis.rs | 8 +- .../api/proc-macro/src/runtime_metadata.rs | 4 +- primitives/api/proc-macro/src/utils.rs | 14 ++- primitives/arithmetic/src/per_things.rs | 10 +- primitives/core/hashing/proc-macro/Cargo.toml | 6 +- primitives/debug-derive/Cargo.toml | 6 +- .../runtime-interface/proc-macro/Cargo.toml | 6 +- .../bare_function_interface.rs | 15 ++- .../host_function_interface.rs | 6 +- .../src/runtime_interface/trait_decl_impl.rs | 18 +-- .../runtime-interface/proc-macro/src/utils.rs | 26 ++-- primitives/version/proc-macro/Cargo.toml | 6 +- test-utils/derive/Cargo.toml | 6 +- 62 files changed, 409 insertions(+), 485 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6a1f29aa28e20..b0a96af545b2f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2351,7 +2351,7 @@ dependencies = [ "quote", "scale-info", "sp-arithmetic", - "syn 1.0.109", + "syn 2.0.14", "trybuild", ] @@ -2489,7 +2489,7 @@ dependencies = [ "proc-macro-warning", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.14", ] [[package]] @@ -2500,7 +2500,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.14", ] [[package]] @@ -2509,7 +2509,7 @@ version = "3.0.0" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.14", ] [[package]] @@ -2724,7 +2724,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.13", + "syn 2.0.14", ] [[package]] @@ -5912,7 +5912,7 @@ version = "4.0.0-dev" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.14", ] [[package]] @@ -6795,7 +6795,7 @@ dependencies = [ "proc-macro2", "quote", "sp-runtime", - "syn 1.0.109", + "syn 2.0.14", ] [[package]] @@ -8401,7 +8401,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.14", ] [[package]] @@ -9630,7 +9630,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.14", ] [[package]] @@ -10181,7 +10181,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.14", ] [[package]] @@ -10490,7 +10490,7 @@ dependencies = [ "proc-macro2", "quote", "sp-core-hashing", - "syn 1.0.109", + "syn 2.0.14", ] [[package]] @@ -10507,7 +10507,7 @@ version = "5.0.0" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.14", ] [[package]] @@ -10737,7 +10737,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.14", ] [[package]] @@ -10962,7 +10962,7 @@ dependencies = [ "proc-macro2", "quote", "sp-version", - "syn 1.0.109", + "syn 2.0.14", ] [[package]] @@ -11388,7 +11388,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.14", ] [[package]] @@ -11444,9 +11444,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.13" +version = "2.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c9da457c5285ac1f936ebd076af6dac17a61cfe7826f2076b4d015cf47bc8ec" +checksum = "fcf316d5356ed6847742d036f8a39c3b8435cac10bd528a4bd461928a6ab34d5" dependencies = [ "proc-macro2", "quote", @@ -11705,7 +11705,7 @@ checksum = "61a573bdc87985e9d6ddeed1b3d864e8a302c847e40d647746df2f1de209d1ce" dependencies = [ "proc-macro2", "quote", - "syn 2.0.13", + "syn 2.0.14", ] [[package]] diff --git a/bin/node/cli/tests/telemetry.rs b/bin/node/cli/tests/telemetry.rs index f6e46775a22fb..176d2e81ad06b 100644 --- a/bin/node/cli/tests/telemetry.rs +++ b/bin/node/cli/tests/telemetry.rs @@ -57,8 +57,9 @@ async fn telemetry_works() { } }, - Event::TextFrame { .. } => - panic!("Got a TextFrame over the socket, this is a bug"), + Event::TextFrame { .. } => { + panic!("Got a TextFrame over the socket, this is a bug") + }, // Connection has been closed. Event::ConnectionError { .. } => {}, diff --git a/client/chain-spec/derive/Cargo.toml b/client/chain-spec/derive/Cargo.toml index d733bda9b1692..c16cd45a99433 100644 --- a/client/chain-spec/derive/Cargo.toml +++ b/client/chain-spec/derive/Cargo.toml @@ -16,6 +16,6 @@ proc-macro = true [dependencies] proc-macro-crate = "1.1.3" -proc-macro2 = "1.0.37" -quote = "1.0.10" -syn = "1.0.98" +proc-macro2 = "1.0.56" +quote = "1.0.26" +syn = "2.0.14" diff --git a/client/chain-spec/derive/src/impls.rs b/client/chain-spec/derive/src/impls.rs index e54c1895e4a4b..c0624897c133e 100644 --- a/client/chain-spec/derive/src/impls.rs +++ b/client/chain-spec/derive/src/impls.rs @@ -35,7 +35,7 @@ pub fn extension_derive(ast: &DeriveInput) -> proc_macro::TokenStream { .named .iter() .find_map(|f| { - if f.attrs.iter().any(|attr| attr.path.is_ident(ATTRIBUTE_NAME)) { + if f.attrs.iter().any(|attr| attr.path().is_ident(ATTRIBUTE_NAME)) { let typ = &f.ty; Some(quote! { #typ }) } else { diff --git a/client/consensus/babe/src/lib.rs b/client/consensus/babe/src/lib.rs index a59870ced0693..e540cae1f7e76 100644 --- a/client/consensus/babe/src/lib.rs +++ b/client/consensus/babe/src/lib.rs @@ -556,8 +556,9 @@ fn aux_storage_cleanup + HeaderBackend, Block: B Ok(meta) => { hashes.insert(meta.parent); }, - Err(err) => - warn!(target: LOG_TARGET, "Failed to lookup metadata for block `{:?}`: {}", first, err,), + Err(err) => { + warn!(target: LOG_TARGET, "Failed to lookup metadata for block `{:?}`: {}", first, err,) + }, } // Cleans data for finalized block's ancestors diff --git a/client/db/src/pinned_blocks_cache.rs b/client/db/src/pinned_blocks_cache.rs index f50a7081df6a8..7b346b4631eee 100644 --- a/client/db/src/pinned_blocks_cache.rs +++ b/client/db/src/pinned_blocks_cache.rs @@ -149,8 +149,9 @@ impl PinnedBlocksCache { self.cache.len() ); }, - None => - log::warn!(target: LOG_TARGET, "Unable to bump reference count. hash = {}", hash), + None => { + log::warn!(target: LOG_TARGET, "Unable to bump reference count. hash = {}", hash) + }, }; } diff --git a/client/service/test/src/client/mod.rs b/client/service/test/src/client/mod.rs index 1b282a342d5e6..520a9b52feab0 100644 --- a/client/service/test/src/client/mod.rs +++ b/client/service/test/src/client/mod.rs @@ -158,8 +158,9 @@ fn finality_notification_check( assert_eq!(notif.hash, *finalized.last().unwrap()); assert_eq!(stale_heads, stale_heads_expected); }, - Err(TryRecvError::Closed) => - panic!("unexpected notification result, client send channel was closed"), + Err(TryRecvError::Closed) => { + panic!("unexpected notification result, client send channel was closed") + }, Err(TryRecvError::Empty) => assert!(finalized.is_empty()), } } diff --git a/client/state-db/src/lib.rs b/client/state-db/src/lib.rs index b41240d629b91..c656f126ae6eb 100644 --- a/client/state-db/src/lib.rs +++ b/client/state-db/src/lib.rs @@ -187,12 +187,14 @@ impl fmt::Debug for StateDbError { "Incompatible pruning modes [stored: {:?}; requested: {:?}]", stored, requested ), - Self::TooManySiblingBlocks { number } => - write!(f, "Too many sibling blocks at #{number} inserted"), + Self::TooManySiblingBlocks { number } => { + write!(f, "Too many sibling blocks at #{number} 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::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"), } } diff --git a/client/tracing/proc-macro/Cargo.toml b/client/tracing/proc-macro/Cargo.toml index 031f1fe49d970..54078fe1f2cae 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.37" -quote = { version = "1.0.10", features = ["proc-macro"] } -syn = { version = "1.0.98", features = ["proc-macro", "full", "extra-traits", "parsing"] } +proc-macro2 = "1.0.56" +quote = { version = "1.0.26", features = ["proc-macro"] } +syn = { version = "2.0.14", features = ["proc-macro", "full", "extra-traits", "parsing"] } diff --git a/frame/contracts/proc-macro/Cargo.toml b/frame/contracts/proc-macro/Cargo.toml index 08dafcc6a8fca..c700d1e335639 100644 --- a/frame/contracts/proc-macro/Cargo.toml +++ b/frame/contracts/proc-macro/Cargo.toml @@ -15,9 +15,9 @@ targets = ["x86_64-unknown-linux-gnu"] proc-macro = true [dependencies] -proc-macro2 = "1" -quote = "1" -syn = { version = "1.0.98", features = ["full"] } +proc-macro2 = "1.0.56" +quote = "1.0.26" +syn = { version = "2.0.14", features = ["full"] } [dev-dependencies] diff --git a/frame/contracts/proc-macro/src/lib.rs b/frame/contracts/proc-macro/src/lib.rs index d54470dd06f97..a6a8187bc8aaa 100644 --- a/frame/contracts/proc-macro/src/lib.rs +++ b/frame/contracts/proc-macro/src/lib.rs @@ -209,13 +209,13 @@ impl HostFn { "only #[version()], #[unstable], #[prefixed_alias] and #[deprecated] attributes are allowed."; let span = item.span(); let mut attrs = item.attrs.clone(); - attrs.retain(|a| !a.path.is_ident("doc")); + attrs.retain(|a| !a.path().is_ident("doc")); let mut maybe_version = None; let mut is_stable = true; let mut alias_to = None; let mut not_deprecated = true; while let Some(attr) = attrs.pop() { - let ident = attr.path.get_ident().ok_or(err(span, msg))?.to_string(); + let ident = attr.path().get_ident().ok_or(err(span, msg))?.to_string(); match ident.as_str() { "version" => { if maybe_version.is_some() { @@ -377,7 +377,7 @@ impl EnvDef { _ => None, }; - let selector = |a: &syn::Attribute| a.path.is_ident("prefixed_alias"); + let selector = |a: &syn::Attribute| a.path().is_ident("prefixed_alias"); let aliases = items .iter() @@ -401,7 +401,7 @@ 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 FnArg::Typed(pat) = arg 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", @@ -434,7 +434,7 @@ fn expand_func_doc(func: &HostFn) -> TokenStream2 { ); quote! { #[doc = #alias_doc] } } else { - let docs = func.item.attrs.iter().filter(|a| a.path.is_ident("doc")).map(|d| { + let docs = func.item.attrs.iter().filter(|a| a.path().is_ident("doc")).map(|d| { let docs = d.to_token_stream(); quote! { #docs } }); diff --git a/frame/election-provider-support/solution-type/Cargo.toml b/frame/election-provider-support/solution-type/Cargo.toml index eb9598dca20b8..95ad6f226663b 100644 --- a/frame/election-provider-support/solution-type/Cargo.toml +++ b/frame/election-provider-support/solution-type/Cargo.toml @@ -15,9 +15,9 @@ targets = ["x86_64-unknown-linux-gnu"] proc-macro = true [dependencies] -syn = { version = "1.0.98", features = ["full", "visit"] } -quote = "1.0" -proc-macro2 = "1.0.37" +syn = { version = "2.0.14", features = ["full", "visit"] } +quote = "1.0.26" +proc-macro2 = "1.0.56" proc-macro-crate = "1.1.3" [dev-dependencies] diff --git a/frame/election-provider-support/solution-type/src/lib.rs b/frame/election-provider-support/solution-type/src/lib.rs index f79554321d54e..6938953071a7c 100644 --- a/frame/election-provider-support/solution-type/src/lib.rs +++ b/frame/election-provider-support/solution-type/src/lib.rs @@ -161,7 +161,7 @@ fn check_attributes(input: ParseStream) -> syn::Result { return Ok(false) } let attr = attrs.pop().expect("attributes vec with len 1 can be popped."); - if attr.path.is_ident("compact") { + if attr.path().is_ident("compact") { Ok(true) } else { Err(syn::Error::new_spanned(attr, "compact solution can accept only #[compact]")) @@ -200,7 +200,7 @@ impl Parse for SolutionDef { format!("Expected binding: `{} = ...`", expected), )) }, - syn::GenericArgument::Binding(syn::Binding { ident, ty, .. }) => { + syn::GenericArgument::AssocType(syn::AssocType { ident, ty, .. }) => { // check that we have the right keyword for this position in the argument list if ident == expected { Ok(ty.clone()) diff --git a/frame/nfts/src/tests.rs b/frame/nfts/src/tests.rs index 0fc6fcd15c45f..d36f8b54e2b91 100644 --- a/frame/nfts/src/tests.rs +++ b/frame/nfts/src/tests.rs @@ -2700,7 +2700,11 @@ fn claim_swap_should_work() { Balances::make_free_balance_be(&user_1, initial_balance); Balances::make_free_balance_be(&user_2, initial_balance); - assert_ok!(Nfts::force_create(RuntimeOrigin::root(), user_1.clone(), default_collection_config())); + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + user_1.clone(), + default_collection_config() + )); assert_ok!(Nfts::mint( RuntimeOrigin::signed(user_1.clone()), diff --git a/frame/scheduler/src/migration.rs b/frame/scheduler/src/migration.rs index e641d2895aa0c..5b3a7631eeac9 100644 --- a/frame/scheduler/src/migration.rs +++ b/frame/scheduler/src/migration.rs @@ -297,8 +297,9 @@ pub mod v4 { target: TARGET, "Did not clean up any agendas. v4::CleanupAgendas can be removed." ), - Some(n) => - log::info!(target: TARGET, "Cleaned up {} agendas, now {}", n, new_agendas), + Some(n) => { + log::info!(target: TARGET, "Cleaned up {} agendas, now {}", n, new_agendas) + }, None => unreachable!( "Number of agendas cannot increase, old {} new {}", old_agendas, new_agendas @@ -560,8 +561,9 @@ mod test { "Agenda {} should be removed", i ), - Some(new) => - assert_eq!(Agenda::::get(i as u64), new, "Agenda wrong {}", i), + Some(new) => { + assert_eq!(Agenda::::get(i as u64), new, "Agenda wrong {}", i) + }, } } }); diff --git a/frame/staking/reward-curve/Cargo.toml b/frame/staking/reward-curve/Cargo.toml index c761517ea6829..4a97d20a5f0af 100644 --- a/frame/staking/reward-curve/Cargo.toml +++ b/frame/staking/reward-curve/Cargo.toml @@ -16,9 +16,9 @@ proc-macro = true [dependencies] proc-macro-crate = "1.1.3" -proc-macro2 = "1.0.37" -quote = "1.0.10" -syn = { version = "1.0.98", features = ["full", "visit"] } +proc-macro2 = "1.0.56" +quote = "1.0.26" +syn = { version = "2.0.14", features = ["full", "visit"] } [dev-dependencies] sp-runtime = { version = "7.0.0", path = "../../../primitives/runtime" } diff --git a/frame/support/procedural/Cargo.toml b/frame/support/procedural/Cargo.toml index 6dbdd3b3a594d..d57b81a3444fe 100644 --- a/frame/support/procedural/Cargo.toml +++ b/frame/support/procedural/Cargo.toml @@ -19,9 +19,9 @@ derive-syn-parse = "0.1.5" 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"] } +proc-macro2 = "1.0.56" +quote = "1.0.26" +syn = { version = "2.0.14", features = ["full"] } frame-support-procedural-tools = { version = "4.0.0-dev", path = "./tools" } proc-macro-warning = { version = "0.2.0", default-features = false } diff --git a/frame/support/procedural/src/benchmark.rs b/frame/support/procedural/src/benchmark.rs index 4f9994b6cd073..cf091e7cb0cf7 100644 --- a/frame/support/procedural/src/benchmark.rs +++ b/frame/support/procedural/src/benchmark.rs @@ -21,14 +21,13 @@ use derive_syn_parse::Parse; use frame_support_procedural_tools::generate_crate_access_2018; use proc_macro::TokenStream; use proc_macro2::{Ident, Span, TokenStream as TokenStream2}; -use quote::{quote, quote_spanned, ToTokens}; +use quote::{quote, ToTokens}; use syn::{ - parenthesized, parse::{Nothing, ParseStream}, parse_quote, punctuated::Punctuated, spanned::Spanned, - token::{Colon2, Comma, Gt, Lt, Paren}, + token::{Comma, Gt, Lt, PathSep}, Attribute, Error, Expr, ExprBlock, ExprCall, ExprPath, FnArg, Item, ItemFn, ItemMod, LitInt, Pat, Path, PathArguments, PathSegment, Result, ReturnType, Signature, Stmt, Token, Type, TypePath, Visibility, WhereClause, @@ -45,6 +44,9 @@ mod keywords { custom_keyword!(skip_meta); custom_keyword!(BenchmarkError); custom_keyword!(Result); + + pub const BENCHMARK_TOKEN: &str = stringify!(benchmark); + pub const BENCHMARKS_TOKEN: &str = stringify!(benchmarks); } /// This represents the raw parsed data for a param definition such as `x: Linear<10, 20>`. @@ -95,27 +97,20 @@ impl syn::parse::Parse for BenchmarkAttrKeyword { impl syn::parse::Parse for BenchmarkAttrs { fn parse(input: ParseStream) -> syn::Result { - let lookahead = input.lookahead1(); - if !lookahead.peek(Paren) { - let _nothing: Nothing = input.parse()?; - return Ok(BenchmarkAttrs { skip_meta: false, extra: false }) - } - let content; - let _paren: Paren = parenthesized!(content in input); let mut extra = false; let mut skip_meta = false; - let args = Punctuated::::parse_terminated(&content)?; + let args = Punctuated::::parse_terminated(&input)?; for arg in args.into_iter() { match arg { BenchmarkAttrKeyword::Extra => { if extra { - return Err(content.error("`extra` can only be specified once")) + return Err(input.error("`extra` can only be specified once")) } extra = true; }, BenchmarkAttrKeyword::SkipMeta => { if skip_meta { - return Err(content.error("`skip_meta` can only be specified once")) + return Err(input.error("`skip_meta` can only be specified once")) } skip_meta = true; }, @@ -150,8 +145,6 @@ struct BenchmarkDef { call_def: BenchmarkCallDef, verify_stmts: Vec, last_stmt: Option, - extra: bool, - skip_meta: bool, fn_sig: Signature, fn_vis: Visibility, fn_attrs: Vec, @@ -218,7 +211,7 @@ fn parse_params(item_fn: &ItemFn) -> Result> { return Err(Error::new( var_span, "Benchmark parameter names must consist of a single lowercase letter (a-z) and no other characters.", - )) + )); }; let name = ident.ident.to_token_stream().to_string(); if name.len() > 1 { @@ -253,9 +246,9 @@ fn parse_params(item_fn: &ItemFn) -> Result> { /// Used in several places where the `#[extrinsic_call]` or `#[body]` annotation is missing fn missing_call(item_fn: &ItemFn) -> Result { return Err(Error::new( - item_fn.block.brace_token.span, + item_fn.block.brace_token.span.join(), "No valid #[extrinsic_call] or #[block] annotation could be found in benchmark function body." - )) + )); } /// Finds the `BenchmarkCallDef` and its index (within the list of stmts for the fn) and @@ -264,10 +257,10 @@ fn missing_call(item_fn: &ItemFn) -> Result { fn parse_call_def(item_fn: &ItemFn) -> Result<(usize, BenchmarkCallDef)> { // #[extrinsic_call] / #[block] handling let call_defs = item_fn.block.stmts.iter().enumerate().filter_map(|(i, child)| { - if let Stmt::Semi(Expr::Call(expr_call), _semi) = child { + if let Stmt::Expr(Expr::Call(expr_call), _semi) = child { // #[extrinsic_call] case expr_call.attrs.iter().enumerate().find_map(|(k, attr)| { - let segment = attr.path.segments.last()?; + let segment = attr.path().segments.last()?; let _: keywords::extrinsic_call = syn::parse(segment.ident.to_token_stream().into()).ok()?; let mut expr_call = expr_call.clone(); @@ -281,10 +274,10 @@ fn parse_call_def(item_fn: &ItemFn) -> Result<(usize, BenchmarkCallDef)> { Some(Ok((i, BenchmarkCallDef::ExtrinsicCall { origin, expr_call, attr_span: attr.span() }))) }) - } else if let Stmt::Expr(Expr::Block(block)) = child { + } else if let Stmt::Expr(Expr::Block(block), _) = child { // #[block] case block.attrs.iter().enumerate().find_map(|(k, attr)| { - let segment = attr.path.segments.last()?; + let segment = attr.path().segments.last()?; let _: keywords::block = syn::parse(segment.ident.to_token_stream().into()).ok()?; let mut block = block.clone(); @@ -310,7 +303,7 @@ fn parse_call_def(item_fn: &ItemFn) -> Result<(usize, BenchmarkCallDef)> { impl BenchmarkDef { /// Constructs a [`BenchmarkDef`] by traversing an existing [`ItemFn`] node. - pub fn from(item_fn: &ItemFn, extra: bool, skip_meta: bool) -> Result { + pub fn from(item_fn: &ItemFn) -> Result { let params = parse_params(item_fn)?; ensure_valid_return_type(item_fn)?; let (i, call_def) = parse_call_def(&item_fn)?; @@ -346,8 +339,6 @@ impl BenchmarkDef { call_def, verify_stmts, last_stmt, - extra, - skip_meta, fn_sig: item_fn.sig.clone(), fn_vis: item_fn.vis.clone(), fn_attrs: item_fn.attrs.clone(), @@ -375,7 +366,7 @@ pub fn benchmarks( let mod_attrs: Vec<&Attribute> = module .attrs .iter() - .filter(|attr| syn::parse2::(attr.to_token_stream()).is_err()) + .filter(|attr| !attr.path().is_ident(keywords::BENCHMARKS_TOKEN)) .collect(); let mut benchmark_names: Vec = Vec::new(); @@ -391,35 +382,32 @@ pub fn benchmarks( let Item::Fn(func) = stmt else { return None }; // find #[benchmark] attribute on function def - let benchmark_attr = func.attrs.iter().find_map(|attr| { - let seg = attr.path.segments.last()?; - syn::parse::(seg.ident.to_token_stream().into()).ok()?; - Some(attr) - })?; + let benchmark_attr = + func.attrs.iter().find(|attr| attr.path().is_ident(keywords::BENCHMARK_TOKEN))?; Some((benchmark_attr.clone(), func.clone(), stmt)) }); // parse individual benchmark defs and args for (benchmark_attr, func, stmt) in benchmark_fn_metas { - // parse any args provided to #[benchmark] - let attr_tokens = benchmark_attr.tokens.to_token_stream().into(); - let benchmark_args: BenchmarkAttrs = syn::parse(attr_tokens)?; - // parse benchmark def - let benchmark_def = - BenchmarkDef::from(&func, benchmark_args.extra, benchmark_args.skip_meta)?; + let benchmark_def = BenchmarkDef::from(&func)?; // record benchmark name let name = &func.sig.ident; benchmark_names.push(name.clone()); - // record name sets - if benchmark_def.extra { - extra_benchmark_names.push(name.clone()); - } - if benchmark_def.skip_meta { - skip_meta_benchmark_names.push(name.clone()) + // Check if we need to parse any args + if benchmark_attr.meta.require_path_only().is_err() { + // parse any args provided to #[benchmark] + let benchmark_attrs: BenchmarkAttrs = benchmark_attr.parse_args()?; + + // record name sets + if benchmark_attrs.extra { + extra_benchmark_names.push(name.clone()); + } else if benchmark_attrs.skip_meta { + skip_meta_benchmark_names.push(name.clone()); + } } // expand benchmark @@ -787,7 +775,8 @@ fn expand_benchmark( // determine call name (handles `_` and normal call syntax) let expr_span = expr_call.span(); let call_err = || { - quote_spanned!(expr_span=> "Extrinsic call must be a function call or `_`".to_compile_error()).into() + syn::Error::new(expr_span, "Extrinsic call must be a function call or `_`") + .to_compile_error() }; let call_name = match *expr_call.func { Expr::Path(expr_path) => { @@ -795,10 +784,9 @@ fn expand_benchmark( let Some(segment) = expr_path.path.segments.last() else { return call_err(); }; segment.ident.to_string() }, - Expr::Verbatim(tokens) => { + Expr::Infer(_) => { // `_` style // replace `_` with fn name - let Ok(_) = syn::parse::(tokens.to_token_stream().into()) else { return call_err(); }; name.to_string() }, _ => return call_err(), @@ -806,7 +794,7 @@ fn expand_benchmark( // modify extrinsic call to be prefixed with "new_call_variant" let call_name = format!("new_call_variant_{}", call_name); - let mut punct: Punctuated = Punctuated::new(); + let mut punct: Punctuated = Punctuated::new(); punct.push(PathSegment { arguments: PathArguments::None, ident: Ident::new(call_name.as_str(), Span::call_site()), @@ -847,11 +835,10 @@ fn expand_benchmark( let vis = benchmark_def.fn_vis; // remove #[benchmark] attribute - let fn_attrs: Vec<&Attribute> = benchmark_def + let fn_attrs = benchmark_def .fn_attrs .iter() - .filter(|attr| !syn::parse2::(attr.path.to_token_stream()).is_ok()) - .collect(); + .filter(|attr| !attr.path().is_ident(keywords::BENCHMARK_TOKEN)); // modify signature generics, ident, and inputs, e.g: // before: `fn bench(u: Linear<1, 100>) -> Result<(), BenchmarkError>` @@ -874,10 +861,11 @@ fn expand_benchmark( Some(stmt) => quote!(#stmt), None => quote!(Ok(())), }; + let fn_attrs_clone = fn_attrs.clone(); let fn_def = quote! { #( - #fn_attrs + #fn_attrs_clone )* #vis #sig { #( diff --git a/frame/support/procedural/src/construct_runtime/mod.rs b/frame/support/procedural/src/construct_runtime/mod.rs index c5a48a98063a4..1af44fc00a0ec 100644 --- a/frame/support/procedural/src/construct_runtime/mod.rs +++ b/frame/support/procedural/src/construct_runtime/mod.rs @@ -224,7 +224,7 @@ fn construct_runtime_final_expansion( let system_pallet = pallets.iter().find(|decl| decl.name == SYSTEM_PALLET_NAME).ok_or_else(|| { syn::Error::new( - pallets_token.span, + pallets_token.span.join(), "`System` pallet declaration is missing. \ Please add this line: `System: frame_system::{Pallet, Call, Storage, Config, Event},`", ) diff --git a/frame/support/procedural/src/construct_runtime/parse.rs b/frame/support/procedural/src/construct_runtime/parse.rs index 5e6979f1d2b3b..f819a90d1b5cd 100644 --- a/frame/support/procedural/src/construct_runtime/parse.rs +++ b/frame/support/procedural/src/construct_runtime/parse.rs @@ -17,6 +17,7 @@ use frame_support_procedural_tools::syn_ext as ext; use proc_macro2::{Span, TokenStream}; +use quote::ToTokens; use std::collections::{HashMap, HashSet}; use syn::{ ext::IdentExt, @@ -444,21 +445,21 @@ impl PalletPartKeyword { } } -impl Spanned for PalletPartKeyword { - fn span(&self) -> Span { +impl ToTokens for PalletPartKeyword { + fn to_tokens(&self, tokens: &mut TokenStream) { match self { - Self::Pallet(inner) => inner.span(), - Self::Call(inner) => inner.span(), - Self::Storage(inner) => inner.span(), - Self::Event(inner) => inner.span(), - Self::Config(inner) => inner.span(), - Self::Origin(inner) => inner.span(), - Self::Inherent(inner) => inner.span(), - Self::ValidateUnsigned(inner) => inner.span(), - Self::FreezeReason(inner) => inner.span(), - Self::HoldReason(inner) => inner.span(), - Self::LockId(inner) => inner.span(), - Self::SlashReason(inner) => inner.span(), + Self::Pallet(inner) => inner.to_tokens(tokens), + Self::Call(inner) => inner.to_tokens(tokens), + Self::Storage(inner) => inner.to_tokens(tokens), + Self::Event(inner) => inner.to_tokens(tokens), + Self::Config(inner) => inner.to_tokens(tokens), + Self::Origin(inner) => inner.to_tokens(tokens), + Self::Inherent(inner) => inner.to_tokens(tokens), + Self::ValidateUnsigned(inner) => inner.to_tokens(tokens), + Self::FreezeReason(inner) => inner.to_tokens(tokens), + Self::HoldReason(inner) => inner.to_tokens(tokens), + Self::LockId(inner) => inner.to_tokens(tokens), + Self::SlashReason(inner) => inner.to_tokens(tokens), } } } @@ -681,7 +682,7 @@ fn convert_pallets(pallets: Vec) -> syn::Result proc_macro::To let default_variants = enum_ .variants .into_iter() - .filter(|variant| variant.attrs.iter().any(|attr| attr.path.is_ident("default"))) + .filter(|variant| variant.attrs.iter().any(|attr| attr.path().is_ident("default"))) .collect::>(); match &*default_variants { @@ -80,7 +80,7 @@ pub fn derive_default_no_bound(input: proc_macro::TokenStream) -> proc_macro::To let variant_attrs = default_variant .attrs .iter() - .filter(|a| a.path.is_ident("default")) + .filter(|a| a.path().is_ident("default")) .collect::>(); // check that there is only one #[default] attribute on the variant diff --git a/frame/support/procedural/src/pallet/expand/call.rs b/frame/support/procedural/src/pallet/expand/call.rs index 74075848d9e9b..aa5af9d54882f 100644 --- a/frame/support/procedural/src/pallet/expand/call.rs +++ b/frame/support/procedural/src/pallet/expand/call.rs @@ -188,7 +188,7 @@ pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream { .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 { + if let syn::ImplItem::Fn(method) = i { let block = &method.block; method.block = syn::parse_quote! {{ // We execute all dispatchable in a new storage layer, allowing them @@ -206,13 +206,7 @@ pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream { 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 - } - }) + .find(|attr| attr.path().is_ident("allow")) .map_or(proc_macro2::TokenStream::new(), |attr| attr.to_token_stream()) }) .collect::>(); diff --git a/frame/support/procedural/src/pallet/expand/constants.rs b/frame/support/procedural/src/pallet/expand/constants.rs index 21fa492a75b56..6e1cd3df627f3 100644 --- a/frame/support/procedural/src/pallet/expand/constants.rs +++ b/frame/support/procedural/src/pallet/expand/constants.rs @@ -23,7 +23,7 @@ struct ConstDef { /// The type in Get, e.g. `u32` in `type Foo: Get;`, but `Self` is replaced by `T` pub type_: syn::Type, /// The doc associated - pub doc: Vec, + pub doc: Vec, /// default_byte implementation pub default_byte_impl: proc_macro2::TokenStream, /// Constant name for Metadata (optional) diff --git a/frame/support/procedural/src/pallet/expand/documentation.rs b/frame/support/procedural/src/pallet/expand/documentation.rs index 1aa46cf572847..4e6347e83bb73 100644 --- a/frame/support/procedural/src/pallet/expand/documentation.rs +++ b/frame/support/procedural/src/pallet/expand/documentation.rs @@ -16,54 +16,24 @@ // limitations under the License. use crate::pallet::Def; -use derive_syn_parse::Parse; use proc_macro2::TokenStream; use quote::ToTokens; -use syn::{ - parse::{self, Parse, ParseStream}, - spanned::Spanned, - Attribute, Lit, -}; +use syn::{spanned::Spanned, Attribute, Lit, LitStr}; const DOC: &'static str = "doc"; const PALLET_DOC: &'static str = "pallet_doc"; -mod keywords { - syn::custom_keyword!(include_str); -} - /// Get the documentation file path from the `pallet_doc` attribute. /// /// Supported format: /// `#[pallet_doc(PATH)]`: The path of the file from which the documentation is loaded fn parse_pallet_doc_value(attr: &Attribute) -> syn::Result { - let span = attr.span(); - - let meta = attr.parse_meta()?; - let syn::Meta::List(metalist) = meta else { - let msg = "The `pallet_doc` attribute must receive arguments as a list. Supported format: `pallet_doc(PATH)`"; - return Err(syn::Error::new(span, msg)) - }; + let lit: syn::LitStr = attr.parse_args().map_err(|_| { + let msg = "The `pallet_doc` received an unsupported argument. Supported format: `pallet_doc(\"PATH\")`"; + syn::Error::new(attr.span(), msg) + })?; - let paths: Vec<_> = metalist - .nested - .into_iter() - .map(|nested| { - let syn::NestedMeta::Lit(lit) = nested else { - let msg = "The `pallet_doc` received an unsupported argument. Supported format: `pallet_doc(PATH)`"; - return Err(syn::Error::new(span, msg)) - }; - - Ok(lit) - }) - .collect::>()?; - - if paths.len() != 1 { - let msg = "The `pallet_doc` attribute must receive only one argument. Supported format: `pallet_doc(PATH)`"; - return Err(syn::Error::new(span, msg)) - } - - Ok(DocMetaValue::Path(paths[0].clone())) + Ok(DocMetaValue::Path(lit)) } /// Get the value from the `doc` comment attribute: @@ -71,47 +41,22 @@ fn parse_pallet_doc_value(attr: &Attribute) -> syn::Result { /// Supported formats: /// - `#[doc = "A doc string"]`: Documentation as a string literal /// - `#[doc = include_str!(PATH)]`: Documentation obtained from a path -fn parse_doc_value(attr: &Attribute) -> Option { - let Some(ident) = attr.path.get_ident() else { - return None - }; - if ident != DOC { - return None +fn parse_doc_value(attr: &Attribute) -> syn::Result> { + if !attr.path().is_ident(DOC) { + return Ok(None) } - let parser = |input: ParseStream| DocParser::parse(input); - let result = parse::Parser::parse2(parser, attr.tokens.clone()).ok()?; + let meta = attr.meta.require_name_value()?; - if let Some(lit) = result.lit { - Some(DocMetaValue::Lit(lit)) - } else if let Some(include_doc) = result.include_doc { - Some(DocMetaValue::Path(include_doc.lit)) - } else { - None + match &meta.value { + syn::Expr::Lit(lit) => Ok(Some(DocMetaValue::Lit(lit.lit.clone()))), + syn::Expr::Macro(mac) if mac.mac.path.is_ident("include_str") => + Ok(Some(DocMetaValue::Path(mac.mac.parse_body()?))), + _ => + Err(syn::Error::new(attr.span(), "Expected `= \"docs\"` or `= include_str!(\"PATH\")`")), } } -/// Parse the include_str attribute. -#[derive(Debug, Parse)] -struct IncludeDocParser { - _include_str: keywords::include_str, - _eq_token: syn::token::Bang, - #[paren] - _paren: syn::token::Paren, - #[inside(_paren)] - lit: Lit, -} - -/// Parse the doc literal. -#[derive(Debug, Parse)] -struct DocParser { - _eq_token: syn::token::Eq, - #[peek(Lit)] - lit: Option, - #[parse_if(lit.is_none())] - include_doc: Option, -} - /// Supported documentation tokens. #[derive(Debug)] enum DocMetaValue { @@ -124,7 +69,7 @@ enum DocMetaValue { /// The string literal represents the file `PATH`. /// /// `#[doc = include_str!(PATH)]` - Path(Lit), + Path(LitStr), } impl ToTokens for DocMetaValue { @@ -179,33 +124,39 @@ pub fn expand_documentation(def: &mut Def) -> proc_macro2::TokenStream { let mut index = 0; while index < def.item.attrs.len() { let attr = &def.item.attrs[index]; - if let Some(ident) = attr.path.get_ident() { - if ident == PALLET_DOC { - let elem = def.item.attrs.remove(index); - pallet_docs.push(elem); - // Do not increment the index, we have just removed the - // element from the attributes. - continue - } + if attr.path().get_ident().map_or(false, |i| *i == PALLET_DOC) { + pallet_docs.push(def.item.attrs.remove(index)); + // Do not increment the index, we have just removed the + // element from the attributes. + continue } index += 1; } // Capture the `#[doc = include_str!("../README.md")]` and `#[doc = "Documentation"]`. - let mut docs: Vec<_> = def.item.attrs.iter().filter_map(parse_doc_value).collect(); + let docs = match def + .item + .attrs + .iter() + .filter_map(|v| parse_doc_value(v).transpose()) + .collect::>>() + { + Ok(r) => r, + Err(err) => return err.into_compile_error(), + }; // Capture the `#[pallet_doc("../README.md")]`. - let pallet_docs: Vec<_> = match pallet_docs + let pallet_docs = match pallet_docs .into_iter() .map(|attr| parse_pallet_doc_value(&attr)) - .collect::>() + .collect::>>() { Ok(docs) => docs, Err(err) => return err.into_compile_error(), }; - docs.extend(pallet_docs); + let docs = docs.iter().chain(pallet_docs.iter()); quote::quote!( impl<#type_impl_gen> #pallet_ident<#type_use_gen> #where_clauses{ diff --git a/frame/support/procedural/src/pallet/expand/storage.rs b/frame/support/procedural/src/pallet/expand/storage.rs index efc803033d3bf..c742ddcd25fbc 100644 --- a/frame/support/procedural/src/pallet/expand/storage.rs +++ b/frame/support/procedural/src/pallet/expand/storage.rs @@ -384,10 +384,11 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream { QueryKind::OptionQuery => quote::quote_spanned!(storage.attr_span => Option<#value> ), - QueryKind::ResultQuery(error_path, _) => + 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 => @@ -407,10 +408,11 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream { QueryKind::OptionQuery => quote::quote_spanned!(storage.attr_span => Option<#value> ), - QueryKind::ResultQuery(error_path, _) => + 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 => @@ -432,10 +434,11 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream { QueryKind::OptionQuery => quote::quote_spanned!(storage.attr_span => Option<#value> ), - QueryKind::ResultQuery(error_path, _) => + 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 => @@ -457,10 +460,11 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream { QueryKind::OptionQuery => quote::quote_spanned!(storage.attr_span => Option<#value> ), - QueryKind::ResultQuery(error_path, _) => + 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 => @@ -484,10 +488,11 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream { QueryKind::OptionQuery => quote::quote_spanned!(storage.attr_span => Option<#value> ), - QueryKind::ResultQuery(error_path, _) => + 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 => diff --git a/frame/support/procedural/src/pallet/parse/call.rs b/frame/support/procedural/src/pallet/parse/call.rs index 5b90c2d98b85e..ae1c039c9ddde 100644 --- a/frame/support/procedural/src/pallet/parse/call.rs +++ b/frame/support/procedural/src/pallet/parse/call.rs @@ -45,7 +45,7 @@ pub struct CallDef { /// The span of the pallet::call attribute. pub attr_span: proc_macro2::Span, /// Docs, specified on the impl Block. - pub docs: Vec, + pub docs: Vec, } /// Definition of dispatchable typically: `#[weight...] fn foo(origin .., param1: ...) -> ..` @@ -62,7 +62,7 @@ pub struct CallVariantDef { /// Whether an explicit call index was specified. pub explicit_call_index: bool, /// Docs, used for metadata. - pub docs: Vec, + pub docs: Vec, /// Attributes annotated at the top of the dispatchable function. pub attrs: Vec, } @@ -173,7 +173,7 @@ impl CallDef { let mut indices = HashMap::new(); let mut last_index: Option = None; for item in &mut item_impl.items { - if let syn::ImplItem::Method(method) = item { + if let syn::ImplItem::Fn(method) = item { if !matches!(method.vis, syn::Visibility::Public(_)) { let msg = "Invalid pallet::call, dispatchable function must be public: \ `pub fn`"; diff --git a/frame/support/procedural/src/pallet/parse/composite.rs b/frame/support/procedural/src/pallet/parse/composite.rs index 2406f10d50a33..2bbfcd2e998ab 100644 --- a/frame/support/procedural/src/pallet/parse/composite.rs +++ b/frame/support/procedural/src/pallet/parse/composite.rs @@ -32,14 +32,14 @@ pub mod keyword { SlashReason(SlashReason), } - impl Spanned for CompositeKeyword { - fn span(&self) -> proc_macro2::Span { + impl ToTokens for CompositeKeyword { + fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { use CompositeKeyword::*; match self { - FreezeReason(inner) => inner.span(), - HoldReason(inner) => inner.span(), - LockId(inner) => inner.span(), - SlashReason(inner) => inner.span(), + FreezeReason(inner) => inner.to_tokens(tokens), + HoldReason(inner) => inner.to_tokens(tokens), + LockId(inner) => inner.to_tokens(tokens), + SlashReason(inner) => inner.to_tokens(tokens), } } } @@ -109,14 +109,11 @@ impl CompositeDef { } let has_derive_attr = item.attrs.iter().any(|attr| { - attr.parse_meta() - .ok() - .map(|meta| match meta { - syn::Meta::List(syn::MetaList { path, .. }) => - path.get_ident().map(|ident| ident == "derive").unwrap_or(false), - _ => false, - }) - .unwrap_or(false) + if let syn::Meta::List(syn::MetaList { path, .. }) = &attr.meta { + path.get_ident().map(|ident| ident == "derive").unwrap_or(false) + } else { + false + } }); if !has_derive_attr { diff --git a/frame/support/procedural/src/pallet/parse/config.rs b/frame/support/procedural/src/pallet/parse/config.rs index 4d22e50ef2bbf..7b52c1664ba45 100644 --- a/frame/support/procedural/src/pallet/parse/config.rs +++ b/frame/support/procedural/src/pallet/parse/config.rs @@ -61,7 +61,7 @@ pub struct ConstMetadataDef { /// The type in Get, e.g. `u32` in `type Foo: Get;`, but `Self` is replaced by `T` pub type_: syn::Type, /// The doc associated - pub doc: Vec, + pub doc: Vec, } impl TryFrom<&syn::TraitItemType> for ConstMetadataDef { @@ -124,23 +124,35 @@ impl syn::parse::Parse for DisableFrameSystemSupertraitCheck { } /// Parse for `#[pallet::constant]` -pub struct TypeAttrConst(proc_macro2::Span); - -impl Spanned for TypeAttrConst { - fn span(&self) -> proc_macro2::Span { - self.0 - } +pub struct TypeAttrConst { + pound_token: syn::Token![#], + bracket_token: syn::token::Bracket, + pallet_ident: syn::Ident, + path_sep_token: syn::token::PathSep, + constant_keyword: keyword::constant, } impl syn::parse::Parse for TypeAttrConst { fn parse(input: syn::parse::ParseStream) -> syn::Result { - input.parse::()?; + let pound_token = input.parse::()?; let content; - syn::bracketed!(content in input); - content.parse::()?; - content.parse::()?; + let bracket_token = syn::bracketed!(content in input); + let pallet_ident = content.parse::()?; + let path_sep_token = content.parse::()?; + let constant_keyword = content.parse::()?; - Ok(TypeAttrConst(content.parse::()?.span())) + Ok(Self { pound_token, bracket_token, pallet_ident, path_sep_token, constant_keyword }) + } +} + +impl ToTokens for TypeAttrConst { + fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { + self.pound_token.to_tokens(tokens); + self.bracket_token.surround(tokens, |tokens| { + self.pallet_ident.to_tokens(tokens); + self.path_sep_token.to_tokens(tokens); + self.constant_keyword.to_tokens(tokens); + }) } } diff --git a/frame/support/procedural/src/pallet/parse/error.rs b/frame/support/procedural/src/pallet/parse/error.rs index f344c5d27a877..6f82ce61fc93f 100644 --- a/frame/support/procedural/src/pallet/parse/error.rs +++ b/frame/support/procedural/src/pallet/parse/error.rs @@ -37,7 +37,7 @@ pub struct ErrorDef { /// The index of error item in pallet module. pub index: usize, /// Variants ident, optional field and doc literals (ordered as declaration order) - pub variants: Vec<(syn::Ident, Option, Vec)>, + 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). diff --git a/frame/support/procedural/src/pallet/parse/extra_constants.rs b/frame/support/procedural/src/pallet/parse/extra_constants.rs index 8e85d2c2622d5..2ba6c44b7d158 100644 --- a/frame/support/procedural/src/pallet/parse/extra_constants.rs +++ b/frame/support/procedural/src/pallet/parse/extra_constants.rs @@ -50,7 +50,7 @@ pub struct ExtraConstantDef { /// The type returned by the function pub type_: syn::Type, /// The doc associated - pub doc: Vec, + pub doc: Vec, /// Optional MetaData Name pub metadata_name: Option, } @@ -100,7 +100,7 @@ impl ExtraConstantsDef { let mut extra_constants = vec![]; for impl_item in &mut item.items { - let method = if let syn::ImplItem::Method(method) = impl_item { + let method = if let syn::ImplItem::Fn(method) = impl_item { method } else { let msg = "Invalid pallet::call, only method accepted"; diff --git a/frame/support/procedural/src/pallet/parse/helper.rs b/frame/support/procedural/src/pallet/parse/helper.rs index 4814dce5a3dfa..3cdbfb1f591d9 100644 --- a/frame/support/procedural/src/pallet/parse/helper.rs +++ b/frame/support/procedural/src/pallet/parse/helper.rs @@ -54,7 +54,7 @@ where let attrs = if let Some(attrs) = item.mut_item_attrs() { attrs } else { return Ok(None) }; if let Some(index) = attrs.iter().position(|attr| { - attr.path.segments.first().map_or(false, |segment| segment.ident == "pallet") + attr.path().segments.first().map_or(false, |segment| segment.ident == "pallet") }) { let pallet_attr = attrs.remove(index); Ok(Some(syn::parse2(pallet_attr.into_token_stream())?)) @@ -82,7 +82,7 @@ pub fn get_item_cfg_attrs(attrs: &[syn::Attribute]) -> Vec { attrs .iter() .filter_map(|attr| { - if attr.path.segments.first().map_or(false, |segment| segment.ident == "cfg") { + if attr.path().segments.first().map_or(false, |segment| segment.ident == "cfg") { Some(attr.clone()) } else { None @@ -101,7 +101,6 @@ impl MutItemAttrs for syn::Item { Self::ForeignMod(item) => Some(item.attrs.as_mut()), Self::Impl(item) => Some(item.attrs.as_mut()), Self::Macro(item) => Some(item.attrs.as_mut()), - Self::Macro2(item) => Some(item.attrs.as_mut()), Self::Mod(item) => Some(item.attrs.as_mut()), Self::Static(item) => Some(item.attrs.as_mut()), Self::Struct(item) => Some(item.attrs.as_mut()), @@ -119,7 +118,7 @@ impl MutItemAttrs for syn::TraitItem { fn mut_item_attrs(&mut self) -> Option<&mut Vec> { match self { Self::Const(item) => Some(item.attrs.as_mut()), - Self::Method(item) => Some(item.attrs.as_mut()), + Self::Fn(item) => Some(item.attrs.as_mut()), Self::Type(item) => Some(item.attrs.as_mut()), Self::Macro(item) => Some(item.attrs.as_mut()), _ => None, @@ -139,7 +138,7 @@ impl MutItemAttrs for syn::ItemMod { } } -impl MutItemAttrs for syn::ImplItemMethod { +impl MutItemAttrs for syn::ImplItemFn { fn mut_item_attrs(&mut self) -> Option<&mut Vec> { Some(&mut self.attrs) } diff --git a/frame/support/procedural/src/pallet/parse/hooks.rs b/frame/support/procedural/src/pallet/parse/hooks.rs index f941df5f29272..37d7d22f4b6bb 100644 --- a/frame/support/procedural/src/pallet/parse/hooks.rs +++ b/frame/support/procedural/src/pallet/parse/hooks.rs @@ -71,7 +71,7 @@ impl HooksDef { } let has_runtime_upgrade = item.items.iter().any(|i| match i { - syn::ImplItem::Method(method) => method.sig.ident == "on_runtime_upgrade", + syn::ImplItem::Fn(method) => method.sig.ident == "on_runtime_upgrade", _ => false, }); diff --git a/frame/support/procedural/src/pallet/parse/storage.rs b/frame/support/procedural/src/pallet/parse/storage.rs index 4e90a423f79ef..16c0851ce7a04 100644 --- a/frame/support/procedural/src/pallet/parse/storage.rs +++ b/frame/support/procedural/src/pallet/parse/storage.rs @@ -159,7 +159,7 @@ pub struct StorageDef { /// The keys and value metadata of the storage. pub metadata: Metadata, /// The doc associated to the storage. - pub docs: Vec, + pub docs: Vec, /// A set of usage of instance, must be check for consistency with config. pub instances: Vec, /// Optional getter to generate. If some then query_kind is ensured to be some as well. @@ -270,7 +270,7 @@ enum StorageKind { /// Check the generics in the `map` contains the generics in `gen` may contains generics in /// `optional_gen`, and doesn't contains any other. fn check_generics( - map: &HashMap, + map: &HashMap, mandatory_generics: &[&str], optional_generics: &[&str], storage_type_name: &str, @@ -331,9 +331,9 @@ fn check_generics( fn process_named_generics( storage: &StorageKind, args_span: proc_macro2::Span, - args: &[syn::Binding], + args: &[syn::AssocType], ) -> syn::Result<(Option, Metadata, Option, bool)> { - let mut parsed = HashMap::::new(); + let mut parsed = HashMap::::new(); // Ensure no duplicate. for arg in args { @@ -610,12 +610,12 @@ fn process_generics( }) .collect::>(); process_unnamed_generics(&storage_kind, args_span, &args, dev_mode) - } else if args.args.iter().all(|gen| matches!(gen, syn::GenericArgument::Binding(_))) { + } else if args.args.iter().all(|gen| matches!(gen, syn::GenericArgument::AssocType(_))) { let args = args .args .iter() .map(|gen| match gen { - syn::GenericArgument::Binding(gen) => gen.clone(), + syn::GenericArgument::AssocType(gen) => gen.clone(), _ => unreachable!("It is asserted above that all generics are bindings"), }) .collect::>(); diff --git a/frame/support/procedural/src/pallet/parse/type_value.rs b/frame/support/procedural/src/pallet/parse/type_value.rs index 4b80506889dfd..4d9db30b3a788 100644 --- a/frame/support/procedural/src/pallet/parse/type_value.rs +++ b/frame/support/procedural/src/pallet/parse/type_value.rs @@ -39,7 +39,7 @@ pub struct TypeValueDef { /// The span of the pallet::type_value attribute. pub attr_span: proc_macro2::Span, /// Docs on the item. - pub docs: Vec, + pub docs: Vec, } impl TypeValueDef { @@ -57,9 +57,9 @@ impl TypeValueDef { let mut docs = vec![]; for attr in &item.attrs { - if let Ok(syn::Meta::NameValue(meta)) = attr.parse_meta() { + if let syn::Meta::NameValue(meta) = &attr.meta { if meta.path.get_ident().map_or(false, |ident| ident == "doc") { - docs.push(meta.lit); + docs.push(meta.value.clone()); continue } } diff --git a/frame/support/procedural/src/pallet_error.rs b/frame/support/procedural/src/pallet_error.rs index fb0bf52f69094..246a5bd4a219a 100644 --- a/frame/support/procedural/src/pallet_error.rs +++ b/frame/support/procedural/src/pallet_error.rs @@ -17,7 +17,6 @@ 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 { @@ -117,38 +116,24 @@ fn generate_field_types( 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)) - }, - - _ => (), - } - }, - _ => (), + if attr.path().is_ident("codec") { + let mut res = None; + + attr.parse_nested_meta(|meta| { + if meta.path.is_ident("skip") { + res = Some(None); + } else if meta.path.is_ident("compact") { + let field_ty = &field.ty; + res = Some(Some(quote::quote!(#scrate::codec::Compact<#field_ty>))); + } else if meta.path.is_ident("compact") { + res = Some(Some(meta.value()?.parse()?)); + } + + Ok(()) + })?; + + if let Some(v) = res { + return Ok(v) } } } @@ -163,22 +148,18 @@ fn generate_variant_field_types( 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), - - _ => (), - } - }, - _ => (), + if attr.path().is_ident("codec") { + let mut skip = false; + + // We ignore the error intentionally as this isn't `codec(skip)` when + // `parse_nested_meta` fails. + let _ = attr.parse_nested_meta(|meta| { + skip = meta.path.is_ident("skip"); + Ok(()) + }); + + if skip { + return Ok(None) } } } 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 491db59184fd9..31e9996ee51f4 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 @@ -133,14 +133,13 @@ impl GenesisConfigDef { .attrs .iter() .map(|attr| { - let meta = attr.parse_meta()?; - if meta.path().is_ident("cfg") { + if attr.meta.path().is_ident("cfg") { return Err(syn::Error::new( - meta.span(), + attr.meta.span(), "extra genesis config items do not support `cfg` attribute", )) } - Ok(meta) + Ok(attr.meta.clone()) }) .collect::>()?; diff --git a/frame/support/procedural/src/storage/mod.rs b/frame/support/procedural/src/storage/mod.rs index 3d3b1443d393f..c04862256a7bc 100644 --- a/frame/support/procedural/src/storage/mod.rs +++ b/frame/support/procedural/src/storage/mod.rs @@ -332,8 +332,8 @@ impl StorageLineDefExt { let doc_attrs = storage_def .attrs .iter() - .filter_map(|a| a.parse_meta().ok()) - .filter(|m| m.path().is_ident("doc")) + .filter(|a| a.meta.path().is_ident("doc")) + .map(|a| a.meta.clone()) .collect(); Self { diff --git a/frame/support/procedural/src/storage/print_pallet_upgrade.rs b/frame/support/procedural/src/storage/print_pallet_upgrade.rs index 03f09a7edb48e..4e330fd4b85f2 100644 --- a/frame/support/procedural/src/storage/print_pallet_upgrade.rs +++ b/frame/support/procedural/src/storage/print_pallet_upgrade.rs @@ -273,14 +273,12 @@ pub fn maybe_print_pallet_upgrade(def: &super::DeclStorageDefExt) { doc = line.doc_attrs.iter().fold(String::new(), |mut res, attr| { if let syn::Meta::NameValue(name_value) = attr { if name_value.path.is_ident("doc") { - if let syn::Lit::Str(string) = &name_value.lit { - res = format!( - "{} - ///{}", - res, - string.value(), - ); - } + res = format!( + "{} + ///{}", + res, + name_value.value.to_token_stream(), + ); } } res diff --git a/frame/support/procedural/tools/Cargo.toml b/frame/support/procedural/tools/Cargo.toml index 755483f7db9aa..bf828b01b6f76 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] proc-macro-crate = "1.1.3" -proc-macro2 = "1.0.37" -quote = "1.0.10" -syn = { version = "1.0.98", features = ["full", "visit", "extra-traits"] } +proc-macro2 = "1.0.56" +quote = "1.0.26" +syn = { version = "2.0.14", 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 a688ee13a7d17..81b5a8487449b 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.37" -quote = { version = "1.0.10", features = ["proc-macro"] } -syn = { version = "1.0.98", features = ["proc-macro", "full", "extra-traits", "parsing"] } +proc-macro2 = "1.0.56" +quote = { version = "1.0.26", features = ["proc-macro"] } +syn = { version = "2.0.14", features = ["proc-macro", "full", "extra-traits", "parsing"] } diff --git a/frame/support/procedural/tools/src/lib.rs b/frame/support/procedural/tools/src/lib.rs index 385b20ad05dc8..541accc8ab96a 100644 --- a/frame/support/procedural/tools/src/lib.rs +++ b/frame/support/procedural/tools/src/lib.rs @@ -102,16 +102,15 @@ pub fn clean_type_string(input: &str) -> String { } /// Return all doc attributes literals found. -pub fn get_doc_literals(attrs: &[syn::Attribute]) -> Vec { +pub fn get_doc_literals(attrs: &[syn::Attribute]) -> Vec { attrs .iter() .filter_map(|attr| { - if let Ok(syn::Meta::NameValue(meta)) = attr.parse_meta() { - if meta.path.get_ident().map_or(false, |ident| ident == "doc") { - Some(meta.lit) - } else { - None - } + if let syn::Meta::NameValue(meta) = &attr.meta { + meta.path + .get_ident() + .filter(|ident| *ident == "doc") + .map(|_| meta.value.clone()) } else { None } diff --git a/frame/support/test/tests/pallet_ui/pallet_doc_arg_non_path.stderr b/frame/support/test/tests/pallet_ui/pallet_doc_arg_non_path.stderr index ba60479c07202..9a1249dd36f37 100644 --- a/frame/support/test/tests/pallet_ui/pallet_doc_arg_non_path.stderr +++ b/frame/support/test/tests/pallet_ui/pallet_doc_arg_non_path.stderr @@ -1,4 +1,4 @@ -error: The `pallet_doc` received an unsupported argument. Supported format: `pallet_doc(PATH)` +error: The `pallet_doc` received an unsupported argument. Supported format: `pallet_doc("PATH")` --> tests/pallet_ui/pallet_doc_arg_non_path.rs:3:1 | 3 | #[pallet_doc(X)] diff --git a/frame/support/test/tests/pallet_ui/pallet_doc_empty.stderr b/frame/support/test/tests/pallet_ui/pallet_doc_empty.stderr index d6a189d7918f5..a220cbe9e9990 100644 --- a/frame/support/test/tests/pallet_ui/pallet_doc_empty.stderr +++ b/frame/support/test/tests/pallet_ui/pallet_doc_empty.stderr @@ -1,4 +1,4 @@ -error: The `pallet_doc` attribute must receive arguments as a list. Supported format: `pallet_doc(PATH)` +error: The `pallet_doc` received an unsupported argument. Supported format: `pallet_doc("PATH")` --> tests/pallet_ui/pallet_doc_empty.rs:3:1 | 3 | #[pallet_doc] diff --git a/frame/support/test/tests/pallet_ui/pallet_doc_invalid_arg.stderr b/frame/support/test/tests/pallet_ui/pallet_doc_invalid_arg.stderr index 9dd03978934a4..bee7c708507d2 100644 --- a/frame/support/test/tests/pallet_ui/pallet_doc_invalid_arg.stderr +++ b/frame/support/test/tests/pallet_ui/pallet_doc_invalid_arg.stderr @@ -1,4 +1,4 @@ -error: The `pallet_doc` attribute must receive arguments as a list. Supported format: `pallet_doc(PATH)` +error: The `pallet_doc` received an unsupported argument. Supported format: `pallet_doc("PATH")` --> tests/pallet_ui/pallet_doc_invalid_arg.rs:3:1 | 3 | #[pallet_doc = "invalid"] diff --git a/frame/support/test/tests/pallet_ui/pallet_doc_multiple_args.stderr b/frame/support/test/tests/pallet_ui/pallet_doc_multiple_args.stderr index 58ad75a0a2aec..e769555438e13 100644 --- a/frame/support/test/tests/pallet_ui/pallet_doc_multiple_args.stderr +++ b/frame/support/test/tests/pallet_ui/pallet_doc_multiple_args.stderr @@ -1,4 +1,4 @@ -error: The `pallet_doc` attribute must receive only one argument. Supported format: `pallet_doc(PATH)` +error: The `pallet_doc` received an unsupported argument. Supported format: `pallet_doc("PATH")` --> tests/pallet_ui/pallet_doc_multiple_args.rs:3:1 | 3 | #[pallet_doc("A", "B")] 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 index caffd846f272a..89ddd1599ac97 100644 --- 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 @@ -1,5 +1,5 @@ -error: Invalid pallet::storage, unexpected generic args for ResultQuery, expected angle-bracketed arguments, found `(NonExistentValue)` +error: expected `,` --> tests/pallet_ui/storage_result_query_parenthesized_generics.rs:18:55 | 18 | type Foo = StorageValue<_, u8, ResultQuery(NonExistentValue)>; - | ^^^^^^^^^^^^^^^^^^ + | ^ diff --git a/primitives/api/proc-macro/Cargo.toml b/primitives/api/proc-macro/Cargo.toml index 1ba62cc53d5aa..594c20e82c94e 100644 --- a/primitives/api/proc-macro/Cargo.toml +++ b/primitives/api/proc-macro/Cargo.toml @@ -16,9 +16,9 @@ targets = ["x86_64-unknown-linux-gnu"] proc-macro = true [dependencies] -quote = "1.0.10" -syn = { version = "1.0.98", features = ["full", "fold", "extra-traits", "visit"] } -proc-macro2 = "1.0.37" +quote = "1.0.26" +syn = { version = "2.0.14", features = ["full", "fold", "extra-traits", "visit"] } +proc-macro2 = "1.0.56" blake2 = { version = "0.10.4", default-features = false } proc-macro-crate = "1.1.3" expander = "1.0.0" diff --git a/primitives/api/proc-macro/src/decl_runtime_apis.rs b/primitives/api/proc-macro/src/decl_runtime_apis.rs index 43e1e7969c5d1..cde33c19016bd 100644 --- a/primitives/api/proc-macro/src/decl_runtime_apis.rs +++ b/primitives/api/proc-macro/src/decl_runtime_apis.rs @@ -38,9 +38,10 @@ use syn::{ parse::{Error, Parse, ParseStream, Result}, parse_macro_input, parse_quote, spanned::Spanned, + token::Comma, visit::{self, Visit}, - Attribute, FnArg, GenericParam, Generics, Ident, ItemTrait, Lit, Meta, NestedMeta, TraitBound, - TraitItem, TraitItemMethod, + Attribute, FnArg, GenericParam, Generics, Ident, ItemTrait, LitInt, LitStr, TraitBound, + TraitItem, TraitItemFn, }; use std::collections::{BTreeMap, HashMap}; @@ -76,7 +77,7 @@ fn extend_generics_with_block(generics: &mut Generics) { /// attribute body as `TokenStream`. fn remove_supported_attributes(attrs: &mut Vec) -> HashMap<&'static str, Attribute> { let mut result = HashMap::new(); - attrs.retain(|v| match SUPPORTED_ATTRIBUTE_NAMES.iter().find(|a| v.path.is_ident(a)) { + attrs.retain(|v| match SUPPORTED_ATTRIBUTE_NAMES.iter().find(|a| v.path().is_ident(a)) { Some(attribute) => { result.insert(*attribute, v.clone()); false @@ -159,7 +160,7 @@ impl Fold for ReplaceBlockWithNodeBlock { /// ``` fn generate_versioned_api_traits( api: ItemTrait, - methods: BTreeMap>, + methods: BTreeMap>, ) -> Vec { let mut result = Vec::::new(); for (version, _) in &methods { @@ -169,7 +170,7 @@ fn generate_versioned_api_traits( // 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))); + versioned_trait.items.extend(m.iter().cloned().map(|m| TraitItem::Fn(m))); } result.push(versioned_trait); @@ -180,37 +181,29 @@ fn generate_versioned_api_traits( /// Try to parse the given `Attribute` as `renamed` attribute. fn parse_renamed_attribute(renamed: &Attribute) -> Result<(String, u32)> { - let meta = renamed.parse_meta()?; - - let err = Err(Error::new( - meta.span(), + let err = || { + Error::new( + renamed.span(), &format!( - "Unexpected `{renamed}` attribute. The supported format is `{renamed}(\"old_name\", version_it_was_renamed)`", - renamed = RENAMED_ATTRIBUTE, - ) + "Unexpected `{RENAMED_ATTRIBUTE}` attribute. \ + The supported format is `{RENAMED_ATTRIBUTE}(\"old_name\", version_it_was_renamed)`", + ), ) - ); - - match meta { - Meta::List(list) => - if list.nested.len() > 2 && list.nested.is_empty() { - err - } else { - let mut itr = list.nested.iter(); - let old_name = match itr.next() { - Some(NestedMeta::Lit(Lit::Str(i))) => i.value(), - _ => return err, - }; - - let version = match itr.next() { - Some(NestedMeta::Lit(Lit::Int(i))) => i.base10_parse()?, - _ => return err, - }; - - Ok((old_name, version)) - }, - _ => err, - } + }; + + renamed + .parse_args_with(|input: ParseStream| { + let old_name: LitStr = input.parse()?; + let _comma: Comma = input.parse()?; + let version: LitInt = input.parse()?; + + if !input.is_empty() { + return Err(input.error("No more arguments expected")) + } + + Ok((old_name.value(), version.base10_parse()?)) + }) + .map_err(|_| err()) } /// Generate the declaration of the trait for the runtime. @@ -230,12 +223,12 @@ fn generate_runtime_decls(decls: &[ItemTrait]) -> Result { let trait_api_version = get_api_version(&found_attributes)?; - let mut methods_by_version: BTreeMap> = BTreeMap::new(); + 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) => { + TraitItem::Fn(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 @@ -364,9 +357,8 @@ impl<'a> ToClientSideDecl<'a> { let mut result = Vec::new(); items.into_iter().for_each(|i| match i { - TraitItem::Method(method) => { - let (fn_decl, fn_decl_ctx) = - self.fold_trait_item_method(method, trait_generics_num); + TraitItem::Fn(method) => { + let (fn_decl, fn_decl_ctx) = self.fold_trait_item_fn(method, trait_generics_num); result.push(fn_decl.into()); result.push(fn_decl_ctx.into()); }, @@ -376,11 +368,11 @@ impl<'a> ToClientSideDecl<'a> { result } - fn fold_trait_item_method( + fn fold_trait_item_fn( &mut self, - method: TraitItemMethod, + method: TraitItemFn, trait_generics_num: usize, - ) -> (TraitItemMethod, TraitItemMethod) { + ) -> (TraitItemFn, TraitItemFn) { let crate_ = self.crate_; let context = quote!( #crate_::ExecutionContext::OffchainCall(None) ); let fn_decl = self.create_method_decl(method.clone(), context, trait_generics_num); @@ -391,9 +383,9 @@ impl<'a> ToClientSideDecl<'a> { fn create_method_decl_with_context( &mut self, - method: TraitItemMethod, + method: TraitItemFn, trait_generics_num: usize, - ) -> TraitItemMethod { + ) -> TraitItemFn { 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), trait_generics_num); @@ -409,10 +401,10 @@ impl<'a> ToClientSideDecl<'a> { /// the actual call into the runtime. fn create_method_decl( &mut self, - mut method: TraitItemMethod, + mut method: TraitItemFn, context: TokenStream, trait_generics_num: usize, - ) -> TraitItemMethod { + ) -> TraitItemFn { let params = match extract_parameter_names_types_and_borrows( &method.sig, AllowSelfRefInParameters::No, @@ -661,7 +653,7 @@ impl CheckTraitDecl { /// All errors will be collected in `self.errors`. fn check(&mut self, trait_: &ItemTrait) { self.check_method_declarations(trait_.items.iter().filter_map(|i| match i { - TraitItem::Method(method) => Some(method), + TraitItem::Fn(method) => Some(method), _ => None, })); @@ -671,10 +663,7 @@ impl CheckTraitDecl { /// Check that the given method declarations are correct. /// /// Any error is stored in `self.errors`. - fn check_method_declarations<'a>( - &mut self, - methods: impl Iterator, - ) { + fn check_method_declarations<'a>(&mut self, methods: impl Iterator) { let mut method_to_signature_changed = HashMap::>>::new(); methods.into_iter().for_each(|method| { diff --git a/primitives/api/proc-macro/src/impl_runtime_apis.rs b/primitives/api/proc-macro/src/impl_runtime_apis.rs index c0da8ccf30458..b8dcf625df45e 100644 --- a/primitives/api/proc-macro/src/impl_runtime_apis.rs +++ b/primitives/api/proc-macro/src/impl_runtime_apis.rs @@ -139,7 +139,7 @@ fn generate_impl_calls( .ident; for item in &impl_.items { - if let ImplItem::Method(method) = item { + if let ImplItem::Fn(method) = item { let impl_call = generate_impl_call(&method.sig, &impl_.self_ty, input, &impl_trait)?; @@ -720,7 +720,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.iter().filter(|a| a.path.is_ident("cfg")).cloned().collect() + attrs.iter().filter(|a| a.path().is_ident("cfg")).cloned().collect() } // Extracts the value of `API_VERSION_ATTRIBUTE` and handles errors. @@ -732,7 +732,7 @@ 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)) + .filter(|a| a.path().is_ident(API_VERSION_ATTRIBUTE)) .collect::>(); if api_ver.len() > 1 { 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 fc0a754e26730..be8c8ca0f8527 100644 --- a/primitives/api/proc-macro/src/mock_impl_runtime_apis.rs +++ b/primitives/api/proc-macro/src/mock_impl_runtime_apis.rs @@ -192,7 +192,7 @@ fn implement_common_api_traits(block_type: TypePath, self_ty: Type) -> Result) -> bool { let mut found = false; attributes.retain(|attr| { - if attr.path.is_ident(ADVANCED_ATTRIBUTE) { + if attr.path().is_ident(ADVANCED_ATTRIBUTE) { found = true; false } else { @@ -258,7 +258,7 @@ impl<'a> FoldRuntimeApiImpl<'a> { // 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 { + if let syn::ImplItem::Fn(mut m) = i { m.sig.ident = quote::format_ident!("{}_with_context", m.sig.ident); m.sig.inputs.insert(2, parse_quote!( _: #crate_::ExecutionContext )); @@ -290,7 +290,7 @@ impl<'a> FoldRuntimeApiImpl<'a> { } impl<'a> Fold for FoldRuntimeApiImpl<'a> { - fn fold_impl_item_method(&mut self, mut input: syn::ImplItemMethod) -> syn::ImplItemMethod { + fn fold_impl_item_fn(&mut self, mut input: syn::ImplItemFn) -> syn::ImplItemFn { let block = { let crate_ = generate_crate_access(); let is_advanced = has_advanced_attribute(&mut input.attrs); @@ -377,7 +377,7 @@ impl<'a> Fold for FoldRuntimeApiImpl<'a> { ) }; - let mut input = fold::fold_impl_item_method(self, input); + let mut input = fold::fold_impl_item_fn(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; diff --git a/primitives/api/proc-macro/src/runtime_metadata.rs b/primitives/api/proc-macro/src/runtime_metadata.rs index 02b03baeaeee3..ae78fb52dbd5a 100644 --- a/primitives/api/proc-macro/src/runtime_metadata.rs +++ b/primitives/api/proc-macro/src/runtime_metadata.rs @@ -88,13 +88,13 @@ pub fn generate_decl_runtime_metadata(decl: &ItemTrait) -> TokenStream2 { let mut where_clause = Vec::new(); for item in &decl.items { // Collect metadata for methods only. - let syn::TraitItem::Method(method) = item else { + let syn::TraitItem::Fn(method) = item else { continue }; // Collect metadata only for the latest methods. let is_changed_in = - method.attrs.iter().any(|attr| attr.path.is_ident(CHANGED_IN_ATTRIBUTE)); + method.attrs.iter().any(|attr| attr.path().is_ident(CHANGED_IN_ATTRIBUTE)); if is_changed_in { continue } diff --git a/primitives/api/proc-macro/src/utils.rs b/primitives/api/proc-macro/src/utils.rs index cffaf317fbb10..6716be142febc 100644 --- a/primitives/api/proc-macro/src/utils.rs +++ b/primitives/api/proc-macro/src/utils.rs @@ -22,7 +22,7 @@ use syn::{ ImplItem, ItemImpl, Pat, Path, PathArguments, Result, ReturnType, Signature, Type, TypePath, }; -use quote::{format_ident, quote}; +use quote::{format_ident, quote, ToTokens}; use proc_macro_crate::{crate_name, FoundCrate}; @@ -158,7 +158,7 @@ pub fn extract_all_signature_types(items: &[ImplItem]) -> Vec { items .iter() .filter_map(|i| match i { - ImplItem::Method(method) => Some(&method.sig), + ImplItem::Fn(method) => Some(&method.sig), _ => None, }) .flat_map(|sig| { @@ -263,18 +263,20 @@ pub fn get_doc_literals(attrs: &[syn::Attribute]) -> Vec { attrs .iter() .filter_map(|attr| { - let Ok(syn::Meta::NameValue(meta)) = attr.parse_meta() else { + let syn::Meta::NameValue(meta) = &attr.meta else { return None }; - - meta.path.get_ident().filter(|ident| *ident == "doc").map(|_| meta.lit) + let Ok(lit) = syn::parse2::(meta.value.to_token_stream()) else { + unreachable!("non-lit doc attribute values do not exist"); + }; + meta.path.get_ident().filter(|ident| *ident == "doc").map(|_| lit) }) .collect() } /// Filters all attributes except the cfg ones. pub fn filter_cfg_attributes(attrs: &[syn::Attribute]) -> Vec { - attrs.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/arithmetic/src/per_things.rs b/primitives/arithmetic/src/per_things.rs index c4cb5196602ea..611a4e05e1027 100644 --- a/primitives/arithmetic/src/per_things.rs +++ b/primitives/arithmetic/src/per_things.rs @@ -527,16 +527,18 @@ where rem_mul_div_inner += 1.into(); } }, - Rounding::NearestPrefDown => + 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 => + } + }, + 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() } diff --git a/primitives/core/hashing/proc-macro/Cargo.toml b/primitives/core/hashing/proc-macro/Cargo.toml index 6d9747de871c7..66e9667c8468c 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] -proc-macro2 = "1.0.37" -quote = "1.0.6" -syn = { version = "1.0.98", features = ["full", "parsing"] } +proc-macro2 = "1.0.56" +quote = "1.0.26" +syn = { version = "2.0.14", features = ["full", "parsing"] } 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 a903b704410c2..183d7bd5a7720 100644 --- a/primitives/debug-derive/Cargo.toml +++ b/primitives/debug-derive/Cargo.toml @@ -17,9 +17,9 @@ targets = ["x86_64-unknown-linux-gnu"] proc-macro = true [dependencies] -quote = "1.0.10" -syn = "1.0.98" -proc-macro2 = "1.0" +quote = "1.0.26" +syn = "2.0.14" +proc-macro2 = "1.0.56" [features] default = [ "std" ] diff --git a/primitives/runtime-interface/proc-macro/Cargo.toml b/primitives/runtime-interface/proc-macro/Cargo.toml index 9bc7161012cb1..3a63c1ef55dab 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] Inflector = "0.11.4" proc-macro-crate = "1.1.3" -proc-macro2 = "1.0.37" -quote = "1.0.10" -syn = { version = "1.0.98", features = ["full", "visit", "fold", "extra-traits"] } +proc-macro2 = "1.0.56" +quote = "1.0.26" +syn = { version = "2.0.14", features = ["full", "visit", "fold", "extra-traits"] } 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 16c1cffb78158..77a29bec3807f 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 @@ -36,8 +36,7 @@ use crate::utils::{ }; use syn::{ - parse_quote, spanned::Spanned, FnArg, Ident, ItemTrait, Result, Signature, Token, - TraitItemMethod, + parse_quote, spanned::Spanned, FnArg, Ident, ItemTrait, Result, Signature, Token, TraitItemFn, }; use proc_macro2::{Span, TokenStream}; @@ -116,7 +115,7 @@ fn function_no_std_impl( quote! {} }; - let attrs = method.attrs.iter().filter(|a| !a.path.is_ident("version")); + 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")] } @@ -139,12 +138,12 @@ fn function_no_std_impl( /// Generate call to latest function version for `cfg((feature = "std")` /// /// This should generate simple `fn func(..) { func_version_(..) }`. -fn function_std_latest_impl(method: &TraitItemMethod, latest_version: u32) -> Result { +fn function_std_latest_impl(method: &TraitItemFn, latest_version: u32) -> Result { let function_name = &method.sig.ident; let args = get_function_arguments(&method.sig).map(FnArg::Typed); let arg_names = get_function_argument_names(&method.sig).collect::>(); let return_value = &method.sig.output; - let attrs = method.attrs.iter().filter(|a| !a.path.is_ident("version")); + let attrs = method.attrs.iter().filter(|a| !a.path().is_ident("version")); let latest_function_name = create_function_ident_with_version(&method.sig.ident, latest_version); @@ -162,7 +161,7 @@ fn function_std_latest_impl(method: &TraitItemMethod, latest_version: u32) -> Re /// Generates the bare function implementation for `cfg(feature = "std")`. fn function_std_impl( trait_name: &Ident, - method: &TraitItemMethod, + method: &TraitItemFn, version: u32, is_wasm_only: bool, tracing: bool, @@ -185,7 +184,7 @@ fn function_std_impl( .take(1), ); let return_value = &method.sig.output; - let attrs = method.attrs.iter().filter(|a| !a.path.is_ident("version")); + let attrs = method.attrs.iter().filter(|a| !a.path().is_ident("version")); // Don't make the function public accessible when this is a wasm only interface. let call_to_trait = generate_call_to_trait(trait_name, method, version, is_wasm_only); let call_to_trait = if !tracing { @@ -210,7 +209,7 @@ fn function_std_impl( /// Generate the call to the interface trait. fn generate_call_to_trait( trait_name: &Ident, - method: &TraitItemMethod, + method: &TraitItemFn, version: u32, is_wasm_only: bool, ) -> TokenStream { 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 fb751c69bc86d..f3cdcf7fd54a9 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 @@ -30,7 +30,7 @@ use crate::utils::{ }; use syn::{ - spanned::Spanned, Error, Ident, ItemTrait, Pat, Result, ReturnType, Signature, TraitItemMethod, + spanned::Spanned, Error, Ident, ItemTrait, Pat, Result, ReturnType, Signature, TraitItemFn, }; use proc_macro2::{Span, TokenStream}; @@ -78,7 +78,7 @@ pub fn generate(trait_def: &ItemTrait, is_wasm_only: bool) -> Result Result { @@ -136,7 +136,7 @@ fn generate_extern_host_function( } /// Generate the host exchangeable function for the given method. -fn generate_exchangeable_host_function(method: &TraitItemMethod) -> Result { +fn generate_exchangeable_host_function(method: &TraitItemFn) -> Result { let crate_ = generate_crate_access(); let arg_types = get_function_argument_types(&method.sig); let function = &method.sig.ident; 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 4a3a688e5c3bd..540e930b0c14b 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 @@ -26,7 +26,7 @@ use crate::utils::{ use syn::{ fold::{self, Fold}, spanned::Spanned, - Error, Generics, ItemTrait, Receiver, Result, TraitItemMethod, Type, Visibility, + Error, Generics, ItemTrait, Receiver, Result, TraitItemFn, Type, Visibility, }; use proc_macro2::TokenStream; @@ -51,7 +51,7 @@ pub fn process(trait_def: &ItemTrait, is_wasm_only: bool) -> Result struct ToEssentialTraitDef { /// All errors found while doing the conversion. errors: Vec, - methods: Vec, + methods: Vec, } impl ToEssentialTraitDef { @@ -59,7 +59,7 @@ impl ToEssentialTraitDef { ToEssentialTraitDef { errors: vec![], methods: vec![] } } - fn into_methods(self) -> Result> { + fn into_methods(self) -> Result> { let mut errors = self.errors; let methods = self.methods; if let Some(first_error) = errors.pop() { @@ -72,8 +72,8 @@ impl ToEssentialTraitDef { } } - fn process(&mut self, method: &TraitItemMethod, version: u32) { - let mut folded = self.fold_trait_item_method(method.clone()); + fn process(&mut self, method: &TraitItemFn, version: u32) { + let mut folded = self.fold_trait_item_fn(method.clone()); folded.sig.ident = create_function_ident_with_version(&folded.sig.ident, version); self.methods.push(folded); } @@ -90,7 +90,7 @@ impl ToEssentialTraitDef { } impl Fold for ToEssentialTraitDef { - fn fold_trait_item_method(&mut self, mut method: TraitItemMethod) -> TraitItemMethod { + fn fold_trait_item_fn(&mut self, mut method: TraitItemFn) -> TraitItemFn { if method.default.take().is_none() { self.push_error(&method, "Methods need to have an implementation."); } @@ -105,9 +105,9 @@ impl Fold for ToEssentialTraitDef { self.error_on_generic_parameters(&method.sig.generics); - method.attrs.retain(|a| !a.path.is_ident("version")); + method.attrs.retain(|a| !a.path().is_ident("version")); - fold::fold_trait_item_method(self, method) + fold::fold_trait_item_fn(self, method) } fn fold_item_trait(&mut self, mut trait_def: ItemTrait) -> ItemTrait { @@ -154,7 +154,7 @@ fn impl_trait_for_externalities(trait_def: &ItemTrait, is_wasm_only: bool) -> Re let interface = get_runtime_interface(trait_def)?; let methods = interface.all_versions().map(|(version, method)| { let mut cloned = (*method).clone(); - cloned.attrs.retain(|a| !a.path.is_ident("version")); + 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 07f9b5ce09802..9818fd6842a63 100644 --- a/primitives/runtime-interface/proc-macro/src/utils.rs +++ b/primitives/runtime-interface/proc-macro/src/utils.rs @@ -21,7 +21,7 @@ use proc_macro2::{Span, TokenStream}; use syn::{ parse::Parse, parse_quote, spanned::Spanned, token, Error, FnArg, Ident, ItemTrait, LitInt, - Pat, PatType, Result, Signature, TraitItem, TraitItemMethod, Type, + Pat, PatType, Result, Signature, TraitItem, TraitItemFn, Type, }; use proc_macro_crate::{crate_name, FoundCrate}; @@ -41,23 +41,23 @@ mod attributes { /// A concrete, specific version of a runtime interface function. pub struct RuntimeInterfaceFunction { - item: TraitItemMethod, + item: TraitItemFn, should_trap_on_return: bool, } impl std::ops::Deref for RuntimeInterfaceFunction { - type Target = TraitItemMethod; + type Target = TraitItemFn; fn deref(&self) -> &Self::Target { &self.item } } impl RuntimeInterfaceFunction { - fn new(item: &TraitItemMethod) -> Result { + fn new(item: &TraitItemFn) -> 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") { + if attr.path().is_ident("trap_on_return") { should_trap_on_return = true; false } else { @@ -87,7 +87,7 @@ struct RuntimeInterfaceFunctionSet { } impl RuntimeInterfaceFunctionSet { - fn new(version: VersionAttribute, trait_item: &TraitItemMethod) -> Result { + fn new(version: VersionAttribute, trait_item: &TraitItemFn) -> Result { Ok(Self { latest_version_to_call: version.is_callable().then(|| version.version), versions: BTreeMap::from([( @@ -115,11 +115,7 @@ impl RuntimeInterfaceFunctionSet { } /// Add a different version of the function. - fn add_version( - &mut self, - version: VersionAttribute, - trait_item: &TraitItemMethod, - ) -> Result<()> { + fn add_version(&mut self, version: VersionAttribute, trait_item: &TraitItemFn) -> 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( @@ -275,9 +271,9 @@ pub fn get_function_argument_types_ref_and_mut( } /// Returns an iterator over all trait methods for the given trait definition. -fn get_trait_methods(trait_def: &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), + TraitItem::Fn(ref method) => Some(method), _ => None, }) } @@ -326,10 +322,10 @@ impl Parse for VersionAttribute { } /// Return [`VersionAttribute`], if present. -fn get_item_version(item: &TraitItemMethod) -> Result> { +fn get_item_version(item: &TraitItemFn) -> Result> { item.attrs .iter() - .find(|attr| attr.path.is_ident("version")) + .find(|attr| attr.path().is_ident("version")) .map(|attr| attr.parse_args()) .transpose() } diff --git a/primitives/version/proc-macro/Cargo.toml b/primitives/version/proc-macro/Cargo.toml index abe9e579a20da..aac41dd43dd08 100644 --- a/primitives/version/proc-macro/Cargo.toml +++ b/primitives/version/proc-macro/Cargo.toml @@ -17,9 +17,9 @@ proc-macro = true [dependencies] codec = { package = "parity-scale-codec", version = "3.2.2", features = [ "derive" ] } -proc-macro2 = "1.0.37" -quote = "1.0.10" -syn = { version = "1.0.98", features = ["full", "fold", "extra-traits", "visit"] } +proc-macro2 = "1.0.56" +quote = "1.0.26" +syn = { version = "2.0.14", 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 b55ace822ceb3..f3e38ada2b30d 100644 --- a/test-utils/derive/Cargo.toml +++ b/test-utils/derive/Cargo.toml @@ -11,9 +11,9 @@ publish = false [dependencies] proc-macro-crate = "1.1.3" -proc-macro2 = "1.0.37" -quote = "1.0.10" -syn = { version = "1.0.98", features = ["full"] } +proc-macro2 = "1.0.56" +quote = "1.0.26" +syn = { version = "2.0.14", features = ["full"] } [lib] proc-macro = true From 07c77323010d54410143103c2617ebc12e0a12f3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 Apr 2023 22:50:31 +0000 Subject: [PATCH 644/715] Bump zstd from 0.11.2+zstd.1.5.2 to 0.12.3+zstd.1.5.2 (#13671) Bumps [zstd](https://github.com/gyscos/zstd-rs) from 0.11.2+zstd.1.5.2 to 0.12.3+zstd.1.5.2. - [Release notes](https://github.com/gyscos/zstd-rs/releases) - [Commits](https://github.com/gyscos/zstd-rs/commits) --- updated-dependencies: - dependency-name: zstd dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 31 +++++++++++++++++---- frame/state-trie-migration/Cargo.toml | 2 +- primitives/maybe-compressed-blob/Cargo.toml | 2 +- primitives/runtime/Cargo.toml | 2 +- utils/frame/try-runtime/cli/Cargo.toml | 2 +- 5 files changed, 29 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b0a96af545b2f..fc0b37baed4ff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6836,7 +6836,7 @@ dependencies = [ "substrate-state-trie-migration-rpc", "thousands", "tokio", - "zstd", + "zstd 0.12.3+zstd.1.5.2", ] [[package]] @@ -10592,7 +10592,7 @@ name = "sp-maybe-compressed-blob" version = "4.1.0-dev" dependencies = [ "thiserror", - "zstd", + "zstd 0.12.3+zstd.1.5.2", ] [[package]] @@ -10703,7 +10703,7 @@ dependencies = [ "sp-tracing", "sp-weights", "substrate-test-runtime-client", - "zstd", + "zstd 0.12.3+zstd.1.5.2", ] [[package]] @@ -12052,7 +12052,7 @@ dependencies = [ "substrate-cli-test-utils", "substrate-rpc-client", "tokio", - "zstd", + "zstd 0.12.3+zstd.1.5.2", ] [[package]] @@ -12596,7 +12596,7 @@ dependencies = [ "sha2 0.10.6", "toml", "windows-sys 0.42.0", - "zstd", + "zstd 0.11.2+zstd.1.5.2", ] [[package]] @@ -13317,7 +13317,16 @@ version = "0.11.2+zstd.1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" dependencies = [ - "zstd-safe", + "zstd-safe 5.0.2+zstd.1.5.2", +] + +[[package]] +name = "zstd" +version = "0.12.3+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76eea132fb024e0e13fd9c2f5d5d595d8a967aa72382ac2f9d39fcc95afd0806" +dependencies = [ + "zstd-safe 6.0.5+zstd.1.5.4", ] [[package]] @@ -13330,6 +13339,16 @@ dependencies = [ "zstd-sys", ] +[[package]] +name = "zstd-safe" +version = "6.0.5+zstd.1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d56d9e60b4b1758206c238a10165fbcae3ca37b01744e394c463463f6529d23b" +dependencies = [ + "libc", + "zstd-sys", +] + [[package]] name = "zstd-sys" version = "2.0.7+zstd.1.5.4" diff --git a/frame/state-trie-migration/Cargo.toml b/frame/state-trie-migration/Cargo.toml index 8485db5a3c98d..9cd875932ceaf 100644 --- a/frame/state-trie-migration/Cargo.toml +++ b/frame/state-trie-migration/Cargo.toml @@ -17,7 +17,7 @@ log = { version = "0.4.17", default-features = false } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } serde = { version = "1.0.133", optional = true } thousands = { version = "0.2.0", optional = true } -zstd = { version = "0.11.2", default-features = false, optional = true } +zstd = { version = "0.12.3", 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" } diff --git a/primitives/maybe-compressed-blob/Cargo.toml b/primitives/maybe-compressed-blob/Cargo.toml index 7e2780aa23355..67f93c517274c 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.11.2", default-features = false } +zstd = { version = "0.12.3", default-features = false } diff --git a/primitives/runtime/Cargo.toml b/primitives/runtime/Cargo.toml index 056cfa3ddd3a4..4ec55162e9774 100644 --- a/primitives/runtime/Cargo.toml +++ b/primitives/runtime/Cargo.toml @@ -33,7 +33,7 @@ sp-weights = { version = "4.0.0", default-features = false, path = "../weights" [dev-dependencies] rand = "0.8.5" serde_json = "1.0.85" -zstd = { version = "0.11.2", default-features = false } +zstd = { version = "0.12.3", default-features = false } sp-api = { version = "4.0.0-dev", path = "../api" } sp-state-machine = { version = "0.13.0", path = "../state-machine" } sp-tracing = { version = "6.0.0", path = "../../primitives/tracing" } diff --git a/utils/frame/try-runtime/cli/Cargo.toml b/utils/frame/try-runtime/cli/Cargo.toml index a4d24986eddff..686d27eefbf13 100644 --- a/utils/frame/try-runtime/cli/Cargo.toml +++ b/utils/frame/try-runtime/cli/Cargo.toml @@ -42,7 +42,7 @@ log = "0.4.17" parity-scale-codec = "3.2.2" serde = "1.0.136" serde_json = "1.0.85" -zstd = { version = "0.11.2", default-features = false } +zstd = { version = "0.12.3", default-features = false } [dev-dependencies] assert_cmd = "2.0.10" From a6cb6d0fb79c303c9af513e856abfb61fc6d8d74 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 13 Apr 2023 11:30:42 +0200 Subject: [PATCH 645/715] Bump toml from 0.5.11 to 0.7.3 (#13619) Bumps [toml](https://github.com/toml-rs/toml) from 0.5.11 to 0.7.3. - [Release notes](https://github.com/toml-rs/toml/releases) - [Commits](https://github.com/toml-rs/toml/compare/toml-v0.5.11...toml-v0.7.3) --- updated-dependencies: - dependency-name: toml 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 +++++++++++++++++++++++++++++++++-- utils/wasm-builder/Cargo.toml | 2 +- 2 files changed, 56 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fc0b37baed4ff..45542b8c269e5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7523,7 +7523,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e17d47ce914bf4de440332250b0edd23ce48c005f59fab39d3335866b114f11a" dependencies = [ "thiserror", - "toml", + "toml 0.5.11", ] [[package]] @@ -9946,6 +9946,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0efd8caf556a6cebd3b285caf480045fcc1ac04f6bd786b09a6f11af30c4fcf4" +dependencies = [ + "serde", +] + [[package]] name = "sha-1" version = "0.9.8" @@ -11411,7 +11420,7 @@ dependencies = [ "sp-maybe-compressed-blob", "strum", "tempfile", - "toml", + "toml 0.7.3", "walkdir", "wasm-opt", ] @@ -11768,6 +11777,40 @@ dependencies = [ "serde", ] +[[package]] +name = "toml" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b403acf6f2bb0859c93c7f0d967cb4a75a7ac552100f9322faf64dc047669b21" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.19.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "239410c8609e8125456927e6707163a3b1fdb40561e4b803bc041f466ccfdc13" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + [[package]] name = "tower" version = "0.4.13" @@ -12594,7 +12637,7 @@ dependencies = [ "rustix 0.36.8", "serde", "sha2 0.10.6", - "toml", + "toml 0.5.11", "windows-sys 0.42.0", "zstd 0.11.2+zstd.1.5.2", ] @@ -13184,6 +13227,15 @@ version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" +[[package]] +name = "winnow" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae8970b36c66498d8ff1d66685dc86b91b29db0c7739899012f63a63814b4b28" +dependencies = [ + "memchr", +] + [[package]] name = "winreg" version = "0.10.1" diff --git a/utils/wasm-builder/Cargo.toml b/utils/wasm-builder/Cargo.toml index c1ef006b5a92f..e1444a24042d1 100644 --- a/utils/wasm-builder/Cargo.toml +++ b/utils/wasm-builder/Cargo.toml @@ -18,7 +18,7 @@ build-helper = "0.1.1" cargo_metadata = "0.15.2" strum = { version = "0.24.1", features = ["derive"] } tempfile = "3.1.0" -toml = "0.5.4" +toml = "0.7.3" walkdir = "2.3.2" sp-maybe-compressed-blob = { version = "4.1.0-dev", path = "../../primitives/maybe-compressed-blob" } filetime = "0.2.16" From be58e48f609c044fb832d78cf0f85c51e894d2dc Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Thu, 13 Apr 2023 15:11:58 +0200 Subject: [PATCH 646/715] Fixes PoV over-estimation (#13766) * Align log Signed-off-by: Oliver Tale-Yazdi * Use max instead of sum Signed-off-by: Oliver Tale-Yazdi * Make comment ordering deterministic Signed-off-by: Oliver Tale-Yazdi * Dont add Pov overhead when all is ignored Signed-off-by: Oliver Tale-Yazdi * Update test pallet weights Signed-off-by: Oliver Tale-Yazdi * Re-run weights on bm2 Signed-off-by: Oliver Tale-Yazdi * Fix test Signed-off-by: Oliver Tale-Yazdi * Actually use new weights Fucked up the merge for this file... Signed-off-by: Oliver Tale-Yazdi * Update contract weights Signed-off-by: Oliver Tale-Yazdi --------- Signed-off-by: Oliver Tale-Yazdi --- frame/alliance/src/weights.rs | 475 ++-- frame/assets/src/weights.rs | 347 +-- frame/bags-list/src/weights.rs | 43 +- frame/balances/src/weights.rs | 85 +- frame/benchmarking/pov/src/benchmarking.rs | 1 + frame/benchmarking/pov/src/tests.rs | 4 +- frame/benchmarking/pov/src/weights.rs | 555 ++-- frame/benchmarking/src/weights.rs | 63 +- frame/bounties/src/weights.rs | 151 +- frame/child-bounties/src/weights.rs | 111 +- frame/collective/src/weights.rs | 355 ++- frame/contracts/src/weights.rs | 2239 ++++++++--------- frame/conviction-voting/src/weights.rs | 147 +- frame/core-fellowship/src/weights.rs | 123 +- frame/democracy/src/weights.rs | 423 ++-- .../src/weights.rs | 207 +- frame/elections-phragmen/src/weights.rs | 267 +- frame/fast-unstake/src/weights.rs | 119 +- frame/glutton/src/weights.rs | 123 +- frame/identity/src/weights.rs | 359 ++- frame/im-online/src/weights.rs | 39 +- frame/indices/src/weights.rs | 55 +- frame/lottery/src/weights.rs | 79 +- frame/membership/src/weights.rs | 163 +- frame/message-queue/src/weights.rs | 111 +- frame/multisig/src/weights.rs | 147 +- frame/nfts/src/weights.rs | 503 ++-- frame/nis/src/weights.rs | 299 ++- frame/nomination-pools/src/weights.rs | 335 +-- frame/preimage/src/weights.rs | 115 +- frame/proxy/src/weights.rs | 215 +- frame/ranked-collective/src/weights.rs | 115 +- frame/recovery/src/weights.rs | 139 +- frame/referenda/src/weights.rs | 355 ++- frame/remark/src/weights.rs | 23 +- frame/salary/src/weights.rs | 83 +- frame/scheduler/src/weights.rs | 163 +- frame/session/src/weights.rs | 31 +- frame/staking/src/weights.rs | 563 +++-- frame/state-trie-migration/src/weights.rs | 75 +- frame/support/src/weights/block_weights.rs | 20 +- .../support/src/weights/extrinsic_weights.rs | 20 +- frame/system/src/weights.rs | 87 +- frame/timestamp/src/weights.rs | 27 +- frame/tips/src/weights.rs | 139 +- frame/transaction-storage/src/weights.rs | 47 +- frame/treasury/src/weights.rs | 91 +- frame/uniques/src/weights.rs | 327 ++- frame/utility/src/weights.rs | 71 +- frame/vesting/src/weights.rs | 295 ++- frame/whitelist/src/weights.rs | 67 +- scripts/run_all_benchmarks.sh | 2 +- .../benchmarking-cli/src/pallet/command.rs | 2 +- .../benchmarking-cli/src/pallet/writer.rs | 8 +- 54 files changed, 5500 insertions(+), 5508 deletions(-) diff --git a/frame/alliance/src/weights.rs b/frame/alliance/src/weights.rs index a9756c2d27127..0276a9844a4a9 100644 --- a/frame/alliance/src/weights.rs +++ b/frame/alliance/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_alliance //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,9 +31,6 @@ // --steps=50 // --repeat=20 // --pallet=pallet_alliance -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -92,19 +89,19 @@ impl WeightInfo for SubstrateWeight { fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `618 + m * (32 ±0) + p * (36 ±0)` - // Estimated: `15463 + m * (124 ±0) + p * (148 ±0)` - // Minimum execution time: 32_788_000 picoseconds. - Weight::from_parts(36_725_375, 15463) - // Standard Error: 138 - .saturating_add(Weight::from_parts(1_252, 0).saturating_mul(b.into())) - // Standard Error: 1_445 - .saturating_add(Weight::from_parts(9_861, 0).saturating_mul(m.into())) - // Standard Error: 1_427 - .saturating_add(Weight::from_parts(127_304, 0).saturating_mul(p.into())) + // Estimated: `6676 + m * (31 ±0) + p * (37 ±0)` + // Minimum execution time: 32_316_000 picoseconds. + Weight::from_parts(35_185_484, 6676) + // Standard Error: 83 + .saturating_add(Weight::from_parts(1_089, 0).saturating_mul(b.into())) + // Standard Error: 871 + .saturating_add(Weight::from_parts(21_235, 0).saturating_mul(m.into())) + // Standard Error: 860 + .saturating_add(Weight::from_parts(120_353, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) - .saturating_add(Weight::from_parts(0, 124).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 148).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 31).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 37).saturating_mul(p.into())) } /// Storage: Alliance Members (r:1 w:0) /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) @@ -114,11 +111,11 @@ impl WeightInfo for SubstrateWeight { fn vote(m: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `1042 + m * (64 ±0)` - // Estimated: `11182 + m * (64 ±0)` - // Minimum execution time: 26_632_000 picoseconds. - Weight::from_parts(28_918_089, 11182) - // Standard Error: 947 - .saturating_add(Weight::from_parts(56_565, 0).saturating_mul(m.into())) + // Estimated: `6676 + m * (64 ±0)` + // Minimum execution time: 25_982_000 picoseconds. + Weight::from_parts(28_118_657, 6676) + // Standard Error: 855 + .saturating_add(Weight::from_parts(61_309, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) @@ -138,17 +135,17 @@ impl WeightInfo for SubstrateWeight { fn close_early_disapproved(m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `622 + m * (96 ±0) + p * (37 ±0)` - // Estimated: `15551 + m * (384 ±0) + p * (148 ±0)` - // Minimum execution time: 40_937_000 picoseconds. - Weight::from_parts(39_361_123, 15551) - // Standard Error: 1_609 - .saturating_add(Weight::from_parts(43_225, 0).saturating_mul(m.into())) - // Standard Error: 1_569 - .saturating_add(Weight::from_parts(112_935, 0).saturating_mul(p.into())) + // Estimated: `6676 + m * (96 ±0) + p * (37 ±0)` + // Minimum execution time: 40_922_000 picoseconds. + Weight::from_parts(39_098_903, 6676) + // Standard Error: 714 + .saturating_add(Weight::from_parts(44_125, 0).saturating_mul(m.into())) + // Standard Error: 696 + .saturating_add(Weight::from_parts(111_263, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 384).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 148).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 96).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 37).saturating_mul(p.into())) } /// Storage: Alliance Members (r:1 w:0) /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) @@ -166,19 +163,19 @@ impl WeightInfo for SubstrateWeight { fn close_early_approved(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `903 + m * (96 ±0) + p * (41 ±0)` - // Estimated: `20072 + m * (392 ±0) + p * (160 ±0)` - // Minimum execution time: 51_569_000 picoseconds. - Weight::from_parts(50_722_448, 20072) - // Standard Error: 120 - .saturating_add(Weight::from_parts(474, 0).saturating_mul(b.into())) - // Standard Error: 1_271 - .saturating_add(Weight::from_parts(48_855, 0).saturating_mul(m.into())) - // Standard Error: 1_239 - .saturating_add(Weight::from_parts(139_022, 0).saturating_mul(p.into())) + // Estimated: `6676 + m * (98 ±0) + p * (40 ±0)` + // Minimum execution time: 51_890_000 picoseconds. + Weight::from_parts(49_880_817, 6676) + // Standard Error: 81 + .saturating_add(Weight::from_parts(688, 0).saturating_mul(b.into())) + // Standard Error: 862 + .saturating_add(Weight::from_parts(54_419, 0).saturating_mul(m.into())) + // Standard Error: 840 + .saturating_add(Weight::from_parts(122_253, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 392).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 160).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 98).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 40).saturating_mul(p.into())) } /// Storage: Alliance Members (r:1 w:0) /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) @@ -197,17 +194,17 @@ impl WeightInfo for SubstrateWeight { fn close_disapproved(m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `622 + m * (96 ±0) + p * (37 ±0)` - // Estimated: `17666 + m * (480 ±0) + p * (185 ±0)` - // Minimum execution time: 42_084_000 picoseconds. - Weight::from_parts(39_907_823, 17666) - // Standard Error: 899 - .saturating_add(Weight::from_parts(46_642, 0).saturating_mul(m.into())) - // Standard Error: 888 - .saturating_add(Weight::from_parts(114_161, 0).saturating_mul(p.into())) + // Estimated: `6676 + m * (96 ±0) + p * (37 ±0)` + // Minimum execution time: 42_391_000 picoseconds. + Weight::from_parts(40_156_254, 6676) + // Standard Error: 728 + .saturating_add(Weight::from_parts(47_889, 0).saturating_mul(m.into())) + // Standard Error: 719 + .saturating_add(Weight::from_parts(112_596, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 480).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 185).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 96).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 37).saturating_mul(p.into())) } /// Storage: Alliance Members (r:1 w:0) /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) @@ -227,19 +224,19 @@ impl WeightInfo for SubstrateWeight { fn close_approved(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `591 + m * (96 ±0) + p * (36 ±0)` - // Estimated: `17471 + m * (485 ±0) + p * (180 ±0)` - // Minimum execution time: 42_322_000 picoseconds. - Weight::from_parts(38_753_429, 17471) - // Standard Error: 78 - .saturating_add(Weight::from_parts(1_053, 0).saturating_mul(b.into())) - // Standard Error: 841 - .saturating_add(Weight::from_parts(51_720, 0).saturating_mul(m.into())) - // Standard Error: 811 - .saturating_add(Weight::from_parts(113_343, 0).saturating_mul(p.into())) + // Estimated: `6676 + m * (97 ±0) + p * (36 ±0)` + // Minimum execution time: 42_320_000 picoseconds. + Weight::from_parts(40_205_526, 6676) + // Standard Error: 64 + .saturating_add(Weight::from_parts(49, 0).saturating_mul(b.into())) + // Standard Error: 690 + .saturating_add(Weight::from_parts(46_508, 0).saturating_mul(m.into())) + // Standard Error: 665 + .saturating_add(Weight::from_parts(112_222, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 485).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 180).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 97).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) } /// Storage: Alliance Members (r:2 w:2) /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) @@ -250,13 +247,13 @@ impl WeightInfo for SubstrateWeight { fn init_members(m: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `217` - // Estimated: `14064` - // Minimum execution time: 33_217_000 picoseconds. - Weight::from_parts(24_495_505, 14064) - // Standard Error: 412 - .saturating_add(Weight::from_parts(108_405, 0).saturating_mul(m.into())) - // Standard Error: 407 - .saturating_add(Weight::from_parts(95_707, 0).saturating_mul(z.into())) + // Estimated: `12362` + // Minimum execution time: 32_509_000 picoseconds. + Weight::from_parts(23_584_337, 12362) + // Standard Error: 377 + .saturating_add(Weight::from_parts(114_917, 0).saturating_mul(m.into())) + // Standard Error: 373 + .saturating_add(Weight::from_parts(97_593, 0).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -278,24 +275,24 @@ impl WeightInfo for SubstrateWeight { fn disband(x: u32, y: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + x * (50 ±0) + y * (51 ±0) + z * (251 ±0)` - // Estimated: `35975 + x * (2587 ±0) + y * (2590 ±0) + z * (3113 ±1)` - // Minimum execution time: 278_029_000 picoseconds. - Weight::from_parts(279_353_000, 35975) - // Standard Error: 23_655 - .saturating_add(Weight::from_parts(519_330, 0).saturating_mul(x.into())) - // Standard Error: 23_541 - .saturating_add(Weight::from_parts(547_382, 0).saturating_mul(y.into())) - // Standard Error: 47_040 - .saturating_add(Weight::from_parts(10_939_685, 0).saturating_mul(z.into())) + // Estimated: `12362 + x * (2539 ±0) + y * (2539 ±0) + z * (2603 ±1)` + // Minimum execution time: 275_061_000 picoseconds. + Weight::from_parts(565_248, 12362) + // Standard Error: 15_948 + .saturating_add(Weight::from_parts(1_636_348, 0).saturating_mul(x.into())) + // Standard Error: 15_761 + .saturating_add(Weight::from_parts(1_580_146, 0).saturating_mul(y.into())) + // Standard Error: 31_496 + .saturating_add(Weight::from_parts(17_217_382, 0).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(x.into()))) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(y.into()))) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(z.into()))) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(z.into()))) - .saturating_add(Weight::from_parts(0, 2587).saturating_mul(x.into())) - .saturating_add(Weight::from_parts(0, 2590).saturating_mul(y.into())) - .saturating_add(Weight::from_parts(0, 3113).saturating_mul(z.into())) + .saturating_add(Weight::from_parts(0, 2539).saturating_mul(x.into())) + .saturating_add(Weight::from_parts(0, 2539).saturating_mul(y.into())) + .saturating_add(Weight::from_parts(0, 2603).saturating_mul(z.into())) } /// Storage: Alliance Rule (r:0 w:1) /// Proof: Alliance Rule (max_values: Some(1), max_size: Some(87), added: 582, mode: MaxEncodedLen) @@ -303,8 +300,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 10_129_000 picoseconds. - Weight::from_parts(10_370_000, 0) + // Minimum execution time: 10_261_000 picoseconds. + Weight::from_parts(10_389_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Alliance Announcements (r:1 w:1) @@ -313,8 +310,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `246` // Estimated: `10187` - // Minimum execution time: 13_601_000 picoseconds. - Weight::from_parts(13_823_000, 10187) + // Minimum execution time: 13_483_000 picoseconds. + Weight::from_parts(13_805_000, 10187) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -324,8 +321,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `319` // Estimated: `10187` - // Minimum execution time: 14_953_000 picoseconds. - Weight::from_parts(15_239_000, 10187) + // Minimum execution time: 14_816_000 picoseconds. + Weight::from_parts(15_163_000, 10187) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -340,9 +337,9 @@ impl WeightInfo for SubstrateWeight { fn join_alliance() -> Weight { // Proof Size summary in bytes: // Measured: `468` - // Estimated: `26328` - // Minimum execution time: 42_947_000 picoseconds. - Weight::from_parts(43_602_000, 26328) + // Estimated: `18048` + // Minimum execution time: 46_149_000 picoseconds. + Weight::from_parts(46_827_000, 18048) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -353,9 +350,9 @@ impl WeightInfo for SubstrateWeight { fn nominate_ally() -> Weight { // Proof Size summary in bytes: // Measured: `367` - // Estimated: `22735` - // Minimum execution time: 28_787_000 picoseconds. - Weight::from_parts(29_286_000, 22735) + // Estimated: `18048` + // Minimum execution time: 28_463_000 picoseconds. + Weight::from_parts(28_730_000, 18048) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -370,9 +367,9 @@ impl WeightInfo for SubstrateWeight { fn elevate_ally() -> Weight { // Proof Size summary in bytes: // Measured: `443` - // Estimated: `15176` - // Minimum execution time: 28_476_000 picoseconds. - Weight::from_parts(28_972_000, 15176) + // Estimated: `12362` + // Minimum execution time: 28_401_000 picoseconds. + Weight::from_parts(28_717_000, 12362) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -389,9 +386,9 @@ impl WeightInfo for SubstrateWeight { fn give_retirement_notice() -> Weight { // Proof Size summary in bytes: // Measured: `443` - // Estimated: `26548` - // Minimum execution time: 36_773_000 picoseconds. - Weight::from_parts(38_123_000, 26548) + // Estimated: `23734` + // Minimum execution time: 36_538_000 picoseconds. + Weight::from_parts(37_197_000, 23734) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -406,9 +403,9 @@ impl WeightInfo for SubstrateWeight { fn retire() -> Weight { // Proof Size summary in bytes: // Measured: `687` - // Estimated: `17315` - // Minimum execution time: 37_814_000 picoseconds. - Weight::from_parts(38_353_000, 17315) + // Estimated: `6676` + // Minimum execution time: 42_324_000 picoseconds. + Weight::from_parts(42_890_000, 6676) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -427,9 +424,9 @@ impl WeightInfo for SubstrateWeight { fn kick_member() -> Weight { // Proof Size summary in bytes: // Measured: `707` - // Estimated: `28776` - // Minimum execution time: 62_194_000 picoseconds. - Weight::from_parts(63_925_000, 28776) + // Estimated: `18048` + // Minimum execution time: 68_003_000 picoseconds. + Weight::from_parts(68_657_000, 18048) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -442,13 +439,13 @@ impl WeightInfo for SubstrateWeight { fn add_unscrupulous_items(n: u32, l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `246` - // Estimated: `31874` - // Minimum execution time: 8_369_000 picoseconds. - Weight::from_parts(8_462_000, 31874) - // Standard Error: 3_347 - .saturating_add(Weight::from_parts(1_567_757, 0).saturating_mul(n.into())) - // Standard Error: 1_310 - .saturating_add(Weight::from_parts(72_697, 0).saturating_mul(l.into())) + // Estimated: `27187` + // Minimum execution time: 8_304_000 picoseconds. + Weight::from_parts(8_424_000, 27187) + // Standard Error: 2_765 + .saturating_add(Weight::from_parts(1_529_793, 0).saturating_mul(n.into())) + // Standard Error: 1_082 + .saturating_add(Weight::from_parts(71_352, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -460,14 +457,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `l` is `[0, 255]`. fn remove_unscrupulous_items(n: u32, l: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0 + n * (289 ±0) + l * (100 ±0)` - // Estimated: `31874` - // Minimum execution time: 8_309_000 picoseconds. - Weight::from_parts(8_450_000, 31874) - // Standard Error: 185_163 - .saturating_add(Weight::from_parts(16_348_419, 0).saturating_mul(n.into())) - // Standard Error: 72_518 - .saturating_add(Weight::from_parts(337_571, 0).saturating_mul(l.into())) + // Measured: `0 + l * (100 ±0) + n * (289 ±0)` + // Estimated: `27187` + // Minimum execution time: 8_348_000 picoseconds. + Weight::from_parts(8_505_000, 27187) + // Standard Error: 187_398 + .saturating_add(Weight::from_parts(16_545_597, 0).saturating_mul(n.into())) + // Standard Error: 73_393 + .saturating_add(Weight::from_parts(350_415, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -482,9 +479,9 @@ impl WeightInfo for SubstrateWeight { fn abdicate_fellow_status() -> Weight { // Proof Size summary in bytes: // Measured: `443` - // Estimated: `20862` - // Minimum execution time: 35_363_000 picoseconds. - Weight::from_parts(35_665_000, 20862) + // Estimated: `18048` + // Minimum execution time: 34_461_000 picoseconds. + Weight::from_parts(34_992_000, 18048) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -508,19 +505,19 @@ impl WeightInfo for () { fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `618 + m * (32 ±0) + p * (36 ±0)` - // Estimated: `15463 + m * (124 ±0) + p * (148 ±0)` - // Minimum execution time: 32_788_000 picoseconds. - Weight::from_parts(36_725_375, 15463) - // Standard Error: 138 - .saturating_add(Weight::from_parts(1_252, 0).saturating_mul(b.into())) - // Standard Error: 1_445 - .saturating_add(Weight::from_parts(9_861, 0).saturating_mul(m.into())) - // Standard Error: 1_427 - .saturating_add(Weight::from_parts(127_304, 0).saturating_mul(p.into())) + // Estimated: `6676 + m * (31 ±0) + p * (37 ±0)` + // Minimum execution time: 32_316_000 picoseconds. + Weight::from_parts(35_185_484, 6676) + // Standard Error: 83 + .saturating_add(Weight::from_parts(1_089, 0).saturating_mul(b.into())) + // Standard Error: 871 + .saturating_add(Weight::from_parts(21_235, 0).saturating_mul(m.into())) + // Standard Error: 860 + .saturating_add(Weight::from_parts(120_353, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) - .saturating_add(Weight::from_parts(0, 124).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 148).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 31).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 37).saturating_mul(p.into())) } /// Storage: Alliance Members (r:1 w:0) /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) @@ -530,11 +527,11 @@ impl WeightInfo for () { fn vote(m: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `1042 + m * (64 ±0)` - // Estimated: `11182 + m * (64 ±0)` - // Minimum execution time: 26_632_000 picoseconds. - Weight::from_parts(28_918_089, 11182) - // Standard Error: 947 - .saturating_add(Weight::from_parts(56_565, 0).saturating_mul(m.into())) + // Estimated: `6676 + m * (64 ±0)` + // Minimum execution time: 25_982_000 picoseconds. + Weight::from_parts(28_118_657, 6676) + // Standard Error: 855 + .saturating_add(Weight::from_parts(61_309, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) @@ -554,17 +551,17 @@ impl WeightInfo for () { fn close_early_disapproved(m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `622 + m * (96 ±0) + p * (37 ±0)` - // Estimated: `15551 + m * (384 ±0) + p * (148 ±0)` - // Minimum execution time: 40_937_000 picoseconds. - Weight::from_parts(39_361_123, 15551) - // Standard Error: 1_609 - .saturating_add(Weight::from_parts(43_225, 0).saturating_mul(m.into())) - // Standard Error: 1_569 - .saturating_add(Weight::from_parts(112_935, 0).saturating_mul(p.into())) + // Estimated: `6676 + m * (96 ±0) + p * (37 ±0)` + // Minimum execution time: 40_922_000 picoseconds. + Weight::from_parts(39_098_903, 6676) + // Standard Error: 714 + .saturating_add(Weight::from_parts(44_125, 0).saturating_mul(m.into())) + // Standard Error: 696 + .saturating_add(Weight::from_parts(111_263, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 384).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 148).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 96).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 37).saturating_mul(p.into())) } /// Storage: Alliance Members (r:1 w:0) /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) @@ -582,19 +579,19 @@ impl WeightInfo for () { fn close_early_approved(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `903 + m * (96 ±0) + p * (41 ±0)` - // Estimated: `20072 + m * (392 ±0) + p * (160 ±0)` - // Minimum execution time: 51_569_000 picoseconds. - Weight::from_parts(50_722_448, 20072) - // Standard Error: 120 - .saturating_add(Weight::from_parts(474, 0).saturating_mul(b.into())) - // Standard Error: 1_271 - .saturating_add(Weight::from_parts(48_855, 0).saturating_mul(m.into())) - // Standard Error: 1_239 - .saturating_add(Weight::from_parts(139_022, 0).saturating_mul(p.into())) + // Estimated: `6676 + m * (98 ±0) + p * (40 ±0)` + // Minimum execution time: 51_890_000 picoseconds. + Weight::from_parts(49_880_817, 6676) + // Standard Error: 81 + .saturating_add(Weight::from_parts(688, 0).saturating_mul(b.into())) + // Standard Error: 862 + .saturating_add(Weight::from_parts(54_419, 0).saturating_mul(m.into())) + // Standard Error: 840 + .saturating_add(Weight::from_parts(122_253, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 392).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 160).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 98).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 40).saturating_mul(p.into())) } /// Storage: Alliance Members (r:1 w:0) /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) @@ -613,17 +610,17 @@ impl WeightInfo for () { fn close_disapproved(m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `622 + m * (96 ±0) + p * (37 ±0)` - // Estimated: `17666 + m * (480 ±0) + p * (185 ±0)` - // Minimum execution time: 42_084_000 picoseconds. - Weight::from_parts(39_907_823, 17666) - // Standard Error: 899 - .saturating_add(Weight::from_parts(46_642, 0).saturating_mul(m.into())) - // Standard Error: 888 - .saturating_add(Weight::from_parts(114_161, 0).saturating_mul(p.into())) + // Estimated: `6676 + m * (96 ±0) + p * (37 ±0)` + // Minimum execution time: 42_391_000 picoseconds. + Weight::from_parts(40_156_254, 6676) + // Standard Error: 728 + .saturating_add(Weight::from_parts(47_889, 0).saturating_mul(m.into())) + // Standard Error: 719 + .saturating_add(Weight::from_parts(112_596, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 480).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 185).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 96).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 37).saturating_mul(p.into())) } /// Storage: Alliance Members (r:1 w:0) /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) @@ -643,19 +640,19 @@ impl WeightInfo for () { fn close_approved(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `591 + m * (96 ±0) + p * (36 ±0)` - // Estimated: `17471 + m * (485 ±0) + p * (180 ±0)` - // Minimum execution time: 42_322_000 picoseconds. - Weight::from_parts(38_753_429, 17471) - // Standard Error: 78 - .saturating_add(Weight::from_parts(1_053, 0).saturating_mul(b.into())) - // Standard Error: 841 - .saturating_add(Weight::from_parts(51_720, 0).saturating_mul(m.into())) - // Standard Error: 811 - .saturating_add(Weight::from_parts(113_343, 0).saturating_mul(p.into())) + // Estimated: `6676 + m * (97 ±0) + p * (36 ±0)` + // Minimum execution time: 42_320_000 picoseconds. + Weight::from_parts(40_205_526, 6676) + // Standard Error: 64 + .saturating_add(Weight::from_parts(49, 0).saturating_mul(b.into())) + // Standard Error: 690 + .saturating_add(Weight::from_parts(46_508, 0).saturating_mul(m.into())) + // Standard Error: 665 + .saturating_add(Weight::from_parts(112_222, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 485).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 180).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 97).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) } /// Storage: Alliance Members (r:2 w:2) /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) @@ -666,13 +663,13 @@ impl WeightInfo for () { fn init_members(m: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `217` - // Estimated: `14064` - // Minimum execution time: 33_217_000 picoseconds. - Weight::from_parts(24_495_505, 14064) - // Standard Error: 412 - .saturating_add(Weight::from_parts(108_405, 0).saturating_mul(m.into())) - // Standard Error: 407 - .saturating_add(Weight::from_parts(95_707, 0).saturating_mul(z.into())) + // Estimated: `12362` + // Minimum execution time: 32_509_000 picoseconds. + Weight::from_parts(23_584_337, 12362) + // Standard Error: 377 + .saturating_add(Weight::from_parts(114_917, 0).saturating_mul(m.into())) + // Standard Error: 373 + .saturating_add(Weight::from_parts(97_593, 0).saturating_mul(z.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -694,24 +691,24 @@ impl WeightInfo for () { fn disband(x: u32, y: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + x * (50 ±0) + y * (51 ±0) + z * (251 ±0)` - // Estimated: `35975 + x * (2587 ±0) + y * (2590 ±0) + z * (3113 ±1)` - // Minimum execution time: 278_029_000 picoseconds. - Weight::from_parts(279_353_000, 35975) - // Standard Error: 23_655 - .saturating_add(Weight::from_parts(519_330, 0).saturating_mul(x.into())) - // Standard Error: 23_541 - .saturating_add(Weight::from_parts(547_382, 0).saturating_mul(y.into())) - // Standard Error: 47_040 - .saturating_add(Weight::from_parts(10_939_685, 0).saturating_mul(z.into())) + // Estimated: `12362 + x * (2539 ±0) + y * (2539 ±0) + z * (2603 ±1)` + // Minimum execution time: 275_061_000 picoseconds. + Weight::from_parts(565_248, 12362) + // Standard Error: 15_948 + .saturating_add(Weight::from_parts(1_636_348, 0).saturating_mul(x.into())) + // Standard Error: 15_761 + .saturating_add(Weight::from_parts(1_580_146, 0).saturating_mul(y.into())) + // Standard Error: 31_496 + .saturating_add(Weight::from_parts(17_217_382, 0).saturating_mul(z.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(x.into()))) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(y.into()))) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(z.into()))) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(RocksDbWeight::get().writes((2_u64).saturating_mul(z.into()))) - .saturating_add(Weight::from_parts(0, 2587).saturating_mul(x.into())) - .saturating_add(Weight::from_parts(0, 2590).saturating_mul(y.into())) - .saturating_add(Weight::from_parts(0, 3113).saturating_mul(z.into())) + .saturating_add(Weight::from_parts(0, 2539).saturating_mul(x.into())) + .saturating_add(Weight::from_parts(0, 2539).saturating_mul(y.into())) + .saturating_add(Weight::from_parts(0, 2603).saturating_mul(z.into())) } /// Storage: Alliance Rule (r:0 w:1) /// Proof: Alliance Rule (max_values: Some(1), max_size: Some(87), added: 582, mode: MaxEncodedLen) @@ -719,8 +716,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 10_129_000 picoseconds. - Weight::from_parts(10_370_000, 0) + // Minimum execution time: 10_261_000 picoseconds. + Weight::from_parts(10_389_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Alliance Announcements (r:1 w:1) @@ -729,8 +726,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `246` // Estimated: `10187` - // Minimum execution time: 13_601_000 picoseconds. - Weight::from_parts(13_823_000, 10187) + // Minimum execution time: 13_483_000 picoseconds. + Weight::from_parts(13_805_000, 10187) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -740,8 +737,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `319` // Estimated: `10187` - // Minimum execution time: 14_953_000 picoseconds. - Weight::from_parts(15_239_000, 10187) + // Minimum execution time: 14_816_000 picoseconds. + Weight::from_parts(15_163_000, 10187) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -756,9 +753,9 @@ impl WeightInfo for () { fn join_alliance() -> Weight { // Proof Size summary in bytes: // Measured: `468` - // Estimated: `26328` - // Minimum execution time: 42_947_000 picoseconds. - Weight::from_parts(43_602_000, 26328) + // Estimated: `18048` + // Minimum execution time: 46_149_000 picoseconds. + Weight::from_parts(46_827_000, 18048) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -769,9 +766,9 @@ impl WeightInfo for () { fn nominate_ally() -> Weight { // Proof Size summary in bytes: // Measured: `367` - // Estimated: `22735` - // Minimum execution time: 28_787_000 picoseconds. - Weight::from_parts(29_286_000, 22735) + // Estimated: `18048` + // Minimum execution time: 28_463_000 picoseconds. + Weight::from_parts(28_730_000, 18048) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -786,9 +783,9 @@ impl WeightInfo for () { fn elevate_ally() -> Weight { // Proof Size summary in bytes: // Measured: `443` - // Estimated: `15176` - // Minimum execution time: 28_476_000 picoseconds. - Weight::from_parts(28_972_000, 15176) + // Estimated: `12362` + // Minimum execution time: 28_401_000 picoseconds. + Weight::from_parts(28_717_000, 12362) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -805,9 +802,9 @@ impl WeightInfo for () { fn give_retirement_notice() -> Weight { // Proof Size summary in bytes: // Measured: `443` - // Estimated: `26548` - // Minimum execution time: 36_773_000 picoseconds. - Weight::from_parts(38_123_000, 26548) + // Estimated: `23734` + // Minimum execution time: 36_538_000 picoseconds. + Weight::from_parts(37_197_000, 23734) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -822,9 +819,9 @@ impl WeightInfo for () { fn retire() -> Weight { // Proof Size summary in bytes: // Measured: `687` - // Estimated: `17315` - // Minimum execution time: 37_814_000 picoseconds. - Weight::from_parts(38_353_000, 17315) + // Estimated: `6676` + // Minimum execution time: 42_324_000 picoseconds. + Weight::from_parts(42_890_000, 6676) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -843,9 +840,9 @@ impl WeightInfo for () { fn kick_member() -> Weight { // Proof Size summary in bytes: // Measured: `707` - // Estimated: `28776` - // Minimum execution time: 62_194_000 picoseconds. - Weight::from_parts(63_925_000, 28776) + // Estimated: `18048` + // Minimum execution time: 68_003_000 picoseconds. + Weight::from_parts(68_657_000, 18048) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -858,13 +855,13 @@ impl WeightInfo for () { fn add_unscrupulous_items(n: u32, l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `246` - // Estimated: `31874` - // Minimum execution time: 8_369_000 picoseconds. - Weight::from_parts(8_462_000, 31874) - // Standard Error: 3_347 - .saturating_add(Weight::from_parts(1_567_757, 0).saturating_mul(n.into())) - // Standard Error: 1_310 - .saturating_add(Weight::from_parts(72_697, 0).saturating_mul(l.into())) + // Estimated: `27187` + // Minimum execution time: 8_304_000 picoseconds. + Weight::from_parts(8_424_000, 27187) + // Standard Error: 2_765 + .saturating_add(Weight::from_parts(1_529_793, 0).saturating_mul(n.into())) + // Standard Error: 1_082 + .saturating_add(Weight::from_parts(71_352, 0).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -876,14 +873,14 @@ impl WeightInfo for () { /// The range of component `l` is `[0, 255]`. fn remove_unscrupulous_items(n: u32, l: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0 + n * (289 ±0) + l * (100 ±0)` - // Estimated: `31874` - // Minimum execution time: 8_309_000 picoseconds. - Weight::from_parts(8_450_000, 31874) - // Standard Error: 185_163 - .saturating_add(Weight::from_parts(16_348_419, 0).saturating_mul(n.into())) - // Standard Error: 72_518 - .saturating_add(Weight::from_parts(337_571, 0).saturating_mul(l.into())) + // Measured: `0 + l * (100 ±0) + n * (289 ±0)` + // Estimated: `27187` + // Minimum execution time: 8_348_000 picoseconds. + Weight::from_parts(8_505_000, 27187) + // Standard Error: 187_398 + .saturating_add(Weight::from_parts(16_545_597, 0).saturating_mul(n.into())) + // Standard Error: 73_393 + .saturating_add(Weight::from_parts(350_415, 0).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -898,9 +895,9 @@ impl WeightInfo for () { fn abdicate_fellow_status() -> Weight { // Proof Size summary in bytes: // Measured: `443` - // Estimated: `20862` - // Minimum execution time: 35_363_000 picoseconds. - Weight::from_parts(35_665_000, 20862) + // Estimated: `18048` + // Minimum execution time: 34_461_000 picoseconds. + Weight::from_parts(34_992_000, 18048) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } diff --git a/frame/assets/src/weights.rs b/frame/assets/src/weights.rs index 0d6c41b458db0..4cc90e25f43fa 100644 --- a/frame/assets/src/weights.rs +++ b/frame/assets/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_assets //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,9 +31,6 @@ // --steps=50 // --repeat=20 // --pallet=pallet_assets -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -90,9 +87,9 @@ impl WeightInfo for SubstrateWeight { fn create() -> Weight { // Proof Size summary in bytes: // Measured: `293` - // Estimated: `7268` - // Minimum execution time: 27_756_000 picoseconds. - Weight::from_parts(28_637_000, 7268) + // Estimated: `3675` + // Minimum execution time: 33_678_000 picoseconds. + Weight::from_parts(34_320_000, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -102,8 +99,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `153` // Estimated: `3675` - // Minimum execution time: 15_402_000 picoseconds. - Weight::from_parts(15_803_000, 3675) + // Minimum execution time: 15_521_000 picoseconds. + Weight::from_parts(16_035_000, 3675) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -113,8 +110,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `385` // Estimated: `3675` - // Minimum execution time: 16_027_000 picoseconds. - Weight::from_parts(16_372_000, 3675) + // Minimum execution time: 15_921_000 picoseconds. + Weight::from_parts(16_153_000, 3675) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -128,16 +125,16 @@ impl WeightInfo for SubstrateWeight { fn destroy_accounts(c: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + c * (208 ±0)` - // Estimated: `8232 + c * (5180 ±0)` - // Minimum execution time: 20_667_000 picoseconds. - Weight::from_parts(20_930_000, 8232) - // Standard Error: 7_226 - .saturating_add(Weight::from_parts(12_759_091, 0).saturating_mul(c.into())) + // Estimated: `3675 + c * (2603 ±0)` + // Minimum execution time: 21_242_000 picoseconds. + Weight::from_parts(21_532_000, 3675) + // Standard Error: 6_449 + .saturating_add(Weight::from_parts(13_150_845, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(c.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(c.into()))) - .saturating_add(Weight::from_parts(0, 5180).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(0, 2603).saturating_mul(c.into())) } /// Storage: Assets Asset (r:1 w:1) /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) @@ -147,11 +144,11 @@ impl WeightInfo for SubstrateWeight { fn destroy_approvals(a: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `522 + a * (86 ±0)` - // Estimated: `7288 + a * (2623 ±0)` - // Minimum execution time: 20_798_000 picoseconds. - Weight::from_parts(21_129_000, 7288) - // Standard Error: 7_484 - .saturating_add(Weight::from_parts(12_761_996, 0).saturating_mul(a.into())) + // Estimated: `3675 + a * (2623 ±0)` + // Minimum execution time: 21_604_000 picoseconds. + Weight::from_parts(21_881_000, 3675) + // Standard Error: 4_225 + .saturating_add(Weight::from_parts(15_968_205, 0).saturating_mul(a.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(a.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) @@ -165,9 +162,9 @@ impl WeightInfo for SubstrateWeight { fn finish_destroy() -> Weight { // Proof Size summary in bytes: // Measured: `351` - // Estimated: `7280` - // Minimum execution time: 15_870_000 picoseconds. - Weight::from_parts(16_280_000, 7280) + // Estimated: `3675` + // Minimum execution time: 16_465_000 picoseconds. + Weight::from_parts(16_775_000, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -178,9 +175,9 @@ impl WeightInfo for SubstrateWeight { fn mint() -> Weight { // Proof Size summary in bytes: // Measured: `351` - // Estimated: `7242` - // Minimum execution time: 28_556_000 picoseconds. - Weight::from_parts(28_972_000, 7242) + // Estimated: `3675` + // Minimum execution time: 30_709_000 picoseconds. + Weight::from_parts(31_159_000, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -191,9 +188,9 @@ impl WeightInfo for SubstrateWeight { fn burn() -> Weight { // Proof Size summary in bytes: // Measured: `459` - // Estimated: `7242` - // Minimum execution time: 35_379_000 picoseconds. - Weight::from_parts(35_826_000, 7242) + // Estimated: `3675` + // Minimum execution time: 36_944_000 picoseconds. + Weight::from_parts(38_166_000, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -206,9 +203,9 @@ impl WeightInfo for SubstrateWeight { fn transfer() -> Weight { // Proof Size summary in bytes: // Measured: `498` - // Estimated: `13412` - // Minimum execution time: 48_837_000 picoseconds. - Weight::from_parts(49_305_000, 13412) + // Estimated: `6144` + // Minimum execution time: 52_497_000 picoseconds. + Weight::from_parts(53_147_000, 6144) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -221,9 +218,9 @@ impl WeightInfo for SubstrateWeight { fn transfer_keep_alive() -> Weight { // Proof Size summary in bytes: // Measured: `498` - // Estimated: `13412` - // Minimum execution time: 43_603_000 picoseconds. - Weight::from_parts(44_142_000, 13412) + // Estimated: `6144` + // Minimum execution time: 46_203_000 picoseconds. + Weight::from_parts(46_853_000, 6144) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -236,9 +233,9 @@ impl WeightInfo for SubstrateWeight { fn force_transfer() -> Weight { // Proof Size summary in bytes: // Measured: `498` - // Estimated: `13412` - // Minimum execution time: 49_691_000 picoseconds. - Weight::from_parts(50_402_000, 13412) + // Estimated: `6144` + // Minimum execution time: 52_911_000 picoseconds. + Weight::from_parts(55_511_000, 6144) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -249,9 +246,9 @@ impl WeightInfo for SubstrateWeight { fn freeze() -> Weight { // Proof Size summary in bytes: // Measured: `459` - // Estimated: `7242` - // Minimum execution time: 19_600_000 picoseconds. - Weight::from_parts(20_435_000, 7242) + // Estimated: `3675` + // Minimum execution time: 20_308_000 picoseconds. + Weight::from_parts(20_524_000, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -262,9 +259,9 @@ impl WeightInfo for SubstrateWeight { fn thaw() -> Weight { // Proof Size summary in bytes: // Measured: `459` - // Estimated: `7242` - // Minimum execution time: 19_396_000 picoseconds. - Weight::from_parts(19_745_000, 7242) + // Estimated: `3675` + // Minimum execution time: 20_735_000 picoseconds. + Weight::from_parts(21_026_000, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -274,8 +271,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `385` // Estimated: `3675` - // Minimum execution time: 15_503_000 picoseconds. - Weight::from_parts(15_788_000, 3675) + // Minimum execution time: 16_148_000 picoseconds. + Weight::from_parts(16_404_000, 3675) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -285,8 +282,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `385` // Estimated: `3675` - // Minimum execution time: 15_874_000 picoseconds. - Weight::from_parts(16_190_000, 3675) + // Minimum execution time: 16_075_000 picoseconds. + Weight::from_parts(16_542_000, 3675) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -297,9 +294,9 @@ impl WeightInfo for SubstrateWeight { fn transfer_ownership() -> Weight { // Proof Size summary in bytes: // Measured: `351` - // Estimated: `7280` - // Minimum execution time: 17_067_000 picoseconds. - Weight::from_parts(17_355_000, 7280) + // Estimated: `3675` + // Minimum execution time: 17_866_000 picoseconds. + Weight::from_parts(18_129_000, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -309,8 +306,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 16_155_000 picoseconds. - Weight::from_parts(16_442_000, 3675) + // Minimum execution time: 16_637_000 picoseconds. + Weight::from_parts(16_918_000, 3675) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -320,12 +317,14 @@ impl WeightInfo for SubstrateWeight { /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) /// The range of component `n` is `[0, 50]`. /// The range of component `s` is `[0, 50]`. - fn set_metadata(_n: u32, _s: u32, ) -> Weight { + fn set_metadata(_n: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `351` - // Estimated: `7280` - // Minimum execution time: 27_270_000 picoseconds. - Weight::from_parts(28_634_060, 7280) + // Estimated: `3675` + // Minimum execution time: 33_304_000 picoseconds. + Weight::from_parts(34_764_544, 3675) + // Standard Error: 634 + .saturating_add(Weight::from_parts(4_733, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -336,9 +335,9 @@ impl WeightInfo for SubstrateWeight { fn clear_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `515` - // Estimated: `7280` - // Minimum execution time: 27_469_000 picoseconds. - Weight::from_parts(27_911_000, 7280) + // Estimated: `3675` + // Minimum execution time: 33_640_000 picoseconds. + Weight::from_parts(34_100_000, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -348,14 +347,16 @@ impl WeightInfo for SubstrateWeight { /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) /// The range of component `n` is `[0, 50]`. /// The range of component `s` is `[0, 50]`. - fn force_set_metadata(_n: u32, s: u32, ) -> Weight { + fn force_set_metadata(n: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `190` - // Estimated: `7280` - // Minimum execution time: 16_008_000 picoseconds. - Weight::from_parts(17_007_654, 7280) - // Standard Error: 527 - .saturating_add(Weight::from_parts(4_158, 0).saturating_mul(s.into())) + // Estimated: `3675` + // Minimum execution time: 16_549_000 picoseconds. + Weight::from_parts(17_337_982, 3675) + // Standard Error: 586 + .saturating_add(Weight::from_parts(4_584, 0).saturating_mul(n.into())) + // Standard Error: 586 + .saturating_add(Weight::from_parts(4_288, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -366,9 +367,9 @@ impl WeightInfo for SubstrateWeight { fn force_clear_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `515` - // Estimated: `7280` - // Minimum execution time: 27_118_000 picoseconds. - Weight::from_parts(27_776_000, 7280) + // Estimated: `3675` + // Minimum execution time: 34_183_000 picoseconds. + Weight::from_parts(34_577_000, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -378,8 +379,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 14_776_000 picoseconds. - Weight::from_parts(15_281_000, 3675) + // Minimum execution time: 15_505_000 picoseconds. + Weight::from_parts(15_784_000, 3675) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -390,9 +391,9 @@ impl WeightInfo for SubstrateWeight { fn approve_transfer() -> Weight { // Proof Size summary in bytes: // Measured: `385` - // Estimated: `7288` - // Minimum execution time: 31_324_000 picoseconds. - Weight::from_parts(32_161_000, 7288) + // Estimated: `3675` + // Minimum execution time: 38_762_000 picoseconds. + Weight::from_parts(39_138_000, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -407,9 +408,9 @@ impl WeightInfo for SubstrateWeight { fn transfer_approved() -> Weight { // Proof Size summary in bytes: // Measured: `668` - // Estimated: `17025` - // Minimum execution time: 63_750_000 picoseconds. - Weight::from_parts(64_828_000, 17025) + // Estimated: `6144` + // Minimum execution time: 73_396_000 picoseconds. + Weight::from_parts(73_986_000, 6144) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -420,9 +421,9 @@ impl WeightInfo for SubstrateWeight { fn cancel_approval() -> Weight { // Proof Size summary in bytes: // Measured: `555` - // Estimated: `7288` - // Minimum execution time: 32_698_000 picoseconds. - Weight::from_parts(33_309_000, 7288) + // Estimated: `3675` + // Minimum execution time: 39_707_000 picoseconds. + Weight::from_parts(40_222_000, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -433,9 +434,9 @@ impl WeightInfo for SubstrateWeight { fn force_cancel_approval() -> Weight { // Proof Size summary in bytes: // Measured: `555` - // Estimated: `7288` - // Minimum execution time: 33_147_000 picoseconds. - Weight::from_parts(33_620_000, 7288) + // Estimated: `3675` + // Minimum execution time: 40_357_000 picoseconds. + Weight::from_parts(40_731_000, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -445,8 +446,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 15_910_000 picoseconds. - Weight::from_parts(16_315_000, 3675) + // Minimum execution time: 16_937_000 picoseconds. + Weight::from_parts(17_219_000, 3675) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -461,9 +462,9 @@ impl WeightInfo for () { fn create() -> Weight { // Proof Size summary in bytes: // Measured: `293` - // Estimated: `7268` - // Minimum execution time: 27_756_000 picoseconds. - Weight::from_parts(28_637_000, 7268) + // Estimated: `3675` + // Minimum execution time: 33_678_000 picoseconds. + Weight::from_parts(34_320_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -473,8 +474,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `153` // Estimated: `3675` - // Minimum execution time: 15_402_000 picoseconds. - Weight::from_parts(15_803_000, 3675) + // Minimum execution time: 15_521_000 picoseconds. + Weight::from_parts(16_035_000, 3675) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -484,8 +485,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `385` // Estimated: `3675` - // Minimum execution time: 16_027_000 picoseconds. - Weight::from_parts(16_372_000, 3675) + // Minimum execution time: 15_921_000 picoseconds. + Weight::from_parts(16_153_000, 3675) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -499,16 +500,16 @@ impl WeightInfo for () { fn destroy_accounts(c: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + c * (208 ±0)` - // Estimated: `8232 + c * (5180 ±0)` - // Minimum execution time: 20_667_000 picoseconds. - Weight::from_parts(20_930_000, 8232) - // Standard Error: 7_226 - .saturating_add(Weight::from_parts(12_759_091, 0).saturating_mul(c.into())) + // Estimated: `3675 + c * (2603 ±0)` + // Minimum execution time: 21_242_000 picoseconds. + Weight::from_parts(21_532_000, 3675) + // Standard Error: 6_449 + .saturating_add(Weight::from_parts(13_150_845, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(c.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(RocksDbWeight::get().writes((2_u64).saturating_mul(c.into()))) - .saturating_add(Weight::from_parts(0, 5180).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(0, 2603).saturating_mul(c.into())) } /// Storage: Assets Asset (r:1 w:1) /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) @@ -518,11 +519,11 @@ impl WeightInfo for () { fn destroy_approvals(a: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `522 + a * (86 ±0)` - // Estimated: `7288 + a * (2623 ±0)` - // Minimum execution time: 20_798_000 picoseconds. - Weight::from_parts(21_129_000, 7288) - // Standard Error: 7_484 - .saturating_add(Weight::from_parts(12_761_996, 0).saturating_mul(a.into())) + // Estimated: `3675 + a * (2623 ±0)` + // Minimum execution time: 21_604_000 picoseconds. + Weight::from_parts(21_881_000, 3675) + // Standard Error: 4_225 + .saturating_add(Weight::from_parts(15_968_205, 0).saturating_mul(a.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(a.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) @@ -536,9 +537,9 @@ impl WeightInfo for () { fn finish_destroy() -> Weight { // Proof Size summary in bytes: // Measured: `351` - // Estimated: `7280` - // Minimum execution time: 15_870_000 picoseconds. - Weight::from_parts(16_280_000, 7280) + // Estimated: `3675` + // Minimum execution time: 16_465_000 picoseconds. + Weight::from_parts(16_775_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -549,9 +550,9 @@ impl WeightInfo for () { fn mint() -> Weight { // Proof Size summary in bytes: // Measured: `351` - // Estimated: `7242` - // Minimum execution time: 28_556_000 picoseconds. - Weight::from_parts(28_972_000, 7242) + // Estimated: `3675` + // Minimum execution time: 30_709_000 picoseconds. + Weight::from_parts(31_159_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -562,9 +563,9 @@ impl WeightInfo for () { fn burn() -> Weight { // Proof Size summary in bytes: // Measured: `459` - // Estimated: `7242` - // Minimum execution time: 35_379_000 picoseconds. - Weight::from_parts(35_826_000, 7242) + // Estimated: `3675` + // Minimum execution time: 36_944_000 picoseconds. + Weight::from_parts(38_166_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -577,9 +578,9 @@ impl WeightInfo for () { fn transfer() -> Weight { // Proof Size summary in bytes: // Measured: `498` - // Estimated: `13412` - // Minimum execution time: 48_837_000 picoseconds. - Weight::from_parts(49_305_000, 13412) + // Estimated: `6144` + // Minimum execution time: 52_497_000 picoseconds. + Weight::from_parts(53_147_000, 6144) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -592,9 +593,9 @@ impl WeightInfo for () { fn transfer_keep_alive() -> Weight { // Proof Size summary in bytes: // Measured: `498` - // Estimated: `13412` - // Minimum execution time: 43_603_000 picoseconds. - Weight::from_parts(44_142_000, 13412) + // Estimated: `6144` + // Minimum execution time: 46_203_000 picoseconds. + Weight::from_parts(46_853_000, 6144) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -607,9 +608,9 @@ impl WeightInfo for () { fn force_transfer() -> Weight { // Proof Size summary in bytes: // Measured: `498` - // Estimated: `13412` - // Minimum execution time: 49_691_000 picoseconds. - Weight::from_parts(50_402_000, 13412) + // Estimated: `6144` + // Minimum execution time: 52_911_000 picoseconds. + Weight::from_parts(55_511_000, 6144) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -620,9 +621,9 @@ impl WeightInfo for () { fn freeze() -> Weight { // Proof Size summary in bytes: // Measured: `459` - // Estimated: `7242` - // Minimum execution time: 19_600_000 picoseconds. - Weight::from_parts(20_435_000, 7242) + // Estimated: `3675` + // Minimum execution time: 20_308_000 picoseconds. + Weight::from_parts(20_524_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -633,9 +634,9 @@ impl WeightInfo for () { fn thaw() -> Weight { // Proof Size summary in bytes: // Measured: `459` - // Estimated: `7242` - // Minimum execution time: 19_396_000 picoseconds. - Weight::from_parts(19_745_000, 7242) + // Estimated: `3675` + // Minimum execution time: 20_735_000 picoseconds. + Weight::from_parts(21_026_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -645,8 +646,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `385` // Estimated: `3675` - // Minimum execution time: 15_503_000 picoseconds. - Weight::from_parts(15_788_000, 3675) + // Minimum execution time: 16_148_000 picoseconds. + Weight::from_parts(16_404_000, 3675) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -656,8 +657,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `385` // Estimated: `3675` - // Minimum execution time: 15_874_000 picoseconds. - Weight::from_parts(16_190_000, 3675) + // Minimum execution time: 16_075_000 picoseconds. + Weight::from_parts(16_542_000, 3675) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -668,9 +669,9 @@ impl WeightInfo for () { fn transfer_ownership() -> Weight { // Proof Size summary in bytes: // Measured: `351` - // Estimated: `7280` - // Minimum execution time: 17_067_000 picoseconds. - Weight::from_parts(17_355_000, 7280) + // Estimated: `3675` + // Minimum execution time: 17_866_000 picoseconds. + Weight::from_parts(18_129_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -680,8 +681,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 16_155_000 picoseconds. - Weight::from_parts(16_442_000, 3675) + // Minimum execution time: 16_637_000 picoseconds. + Weight::from_parts(16_918_000, 3675) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -691,12 +692,14 @@ impl WeightInfo for () { /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) /// The range of component `n` is `[0, 50]`. /// The range of component `s` is `[0, 50]`. - fn set_metadata(_n: u32, _s: u32, ) -> Weight { + fn set_metadata(_n: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `351` - // Estimated: `7280` - // Minimum execution time: 27_270_000 picoseconds. - Weight::from_parts(28_634_060, 7280) + // Estimated: `3675` + // Minimum execution time: 33_304_000 picoseconds. + Weight::from_parts(34_764_544, 3675) + // Standard Error: 634 + .saturating_add(Weight::from_parts(4_733, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -707,9 +710,9 @@ impl WeightInfo for () { fn clear_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `515` - // Estimated: `7280` - // Minimum execution time: 27_469_000 picoseconds. - Weight::from_parts(27_911_000, 7280) + // Estimated: `3675` + // Minimum execution time: 33_640_000 picoseconds. + Weight::from_parts(34_100_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -719,14 +722,16 @@ impl WeightInfo for () { /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) /// The range of component `n` is `[0, 50]`. /// The range of component `s` is `[0, 50]`. - fn force_set_metadata(_n: u32, s: u32, ) -> Weight { + fn force_set_metadata(n: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `190` - // Estimated: `7280` - // Minimum execution time: 16_008_000 picoseconds. - Weight::from_parts(17_007_654, 7280) - // Standard Error: 527 - .saturating_add(Weight::from_parts(4_158, 0).saturating_mul(s.into())) + // Estimated: `3675` + // Minimum execution time: 16_549_000 picoseconds. + Weight::from_parts(17_337_982, 3675) + // Standard Error: 586 + .saturating_add(Weight::from_parts(4_584, 0).saturating_mul(n.into())) + // Standard Error: 586 + .saturating_add(Weight::from_parts(4_288, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -737,9 +742,9 @@ impl WeightInfo for () { fn force_clear_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `515` - // Estimated: `7280` - // Minimum execution time: 27_118_000 picoseconds. - Weight::from_parts(27_776_000, 7280) + // Estimated: `3675` + // Minimum execution time: 34_183_000 picoseconds. + Weight::from_parts(34_577_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -749,8 +754,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 14_776_000 picoseconds. - Weight::from_parts(15_281_000, 3675) + // Minimum execution time: 15_505_000 picoseconds. + Weight::from_parts(15_784_000, 3675) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -761,9 +766,9 @@ impl WeightInfo for () { fn approve_transfer() -> Weight { // Proof Size summary in bytes: // Measured: `385` - // Estimated: `7288` - // Minimum execution time: 31_324_000 picoseconds. - Weight::from_parts(32_161_000, 7288) + // Estimated: `3675` + // Minimum execution time: 38_762_000 picoseconds. + Weight::from_parts(39_138_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -778,9 +783,9 @@ impl WeightInfo for () { fn transfer_approved() -> Weight { // Proof Size summary in bytes: // Measured: `668` - // Estimated: `17025` - // Minimum execution time: 63_750_000 picoseconds. - Weight::from_parts(64_828_000, 17025) + // Estimated: `6144` + // Minimum execution time: 73_396_000 picoseconds. + Weight::from_parts(73_986_000, 6144) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -791,9 +796,9 @@ impl WeightInfo for () { fn cancel_approval() -> Weight { // Proof Size summary in bytes: // Measured: `555` - // Estimated: `7288` - // Minimum execution time: 32_698_000 picoseconds. - Weight::from_parts(33_309_000, 7288) + // Estimated: `3675` + // Minimum execution time: 39_707_000 picoseconds. + Weight::from_parts(40_222_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -804,9 +809,9 @@ impl WeightInfo for () { fn force_cancel_approval() -> Weight { // Proof Size summary in bytes: // Measured: `555` - // Estimated: `7288` - // Minimum execution time: 33_147_000 picoseconds. - Weight::from_parts(33_620_000, 7288) + // Estimated: `3675` + // Minimum execution time: 40_357_000 picoseconds. + Weight::from_parts(40_731_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -816,8 +821,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 15_910_000 picoseconds. - Weight::from_parts(16_315_000, 3675) + // Minimum execution time: 16_937_000 picoseconds. + Weight::from_parts(17_219_000, 3675) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/frame/bags-list/src/weights.rs b/frame/bags-list/src/weights.rs index 30efe1ef0cb38..f2b65beba2c80 100644 --- a/frame/bags-list/src/weights.rs +++ b/frame/bags-list/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_bags_list //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,9 +31,6 @@ // --steps=50 // --repeat=20 // --pallet=pallet_bags_list -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -70,9 +67,9 @@ impl WeightInfo for SubstrateWeight { fn rebag_non_terminal() -> Weight { // Proof Size summary in bytes: // Measured: `1724` - // Estimated: `23146` - // Minimum execution time: 63_526_000 picoseconds. - Weight::from_parts(64_125_000, 23146) + // Estimated: `11506` + // Minimum execution time: 63_335_000 picoseconds. + Weight::from_parts(64_097_000, 11506) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -87,9 +84,9 @@ impl WeightInfo for SubstrateWeight { fn rebag_terminal() -> Weight { // Proof Size summary in bytes: // Measured: `1618` - // Estimated: `23074` - // Minimum execution time: 62_404_000 picoseconds. - Weight::from_parts(63_178_000, 23074) + // Estimated: `8877` + // Minimum execution time: 62_151_000 picoseconds. + Weight::from_parts(62_827_000, 8877) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -106,9 +103,9 @@ impl WeightInfo for SubstrateWeight { fn put_in_front_of() -> Weight { // Proof Size summary in bytes: // Measured: `1930` - // Estimated: `30748` - // Minimum execution time: 69_938_000 picoseconds. - Weight::from_parts(70_723_000, 30748) + // Estimated: `11506` + // Minimum execution time: 69_179_000 picoseconds. + Weight::from_parts(69_898_000, 11506) .saturating_add(T::DbWeight::get().reads(10_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -127,9 +124,9 @@ impl WeightInfo for () { fn rebag_non_terminal() -> Weight { // Proof Size summary in bytes: // Measured: `1724` - // Estimated: `23146` - // Minimum execution time: 63_526_000 picoseconds. - Weight::from_parts(64_125_000, 23146) + // Estimated: `11506` + // Minimum execution time: 63_335_000 picoseconds. + Weight::from_parts(64_097_000, 11506) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -144,9 +141,9 @@ impl WeightInfo for () { fn rebag_terminal() -> Weight { // Proof Size summary in bytes: // Measured: `1618` - // Estimated: `23074` - // Minimum execution time: 62_404_000 picoseconds. - Weight::from_parts(63_178_000, 23074) + // Estimated: `8877` + // Minimum execution time: 62_151_000 picoseconds. + Weight::from_parts(62_827_000, 8877) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -163,9 +160,9 @@ impl WeightInfo for () { fn put_in_front_of() -> Weight { // Proof Size summary in bytes: // Measured: `1930` - // Estimated: `30748` - // Minimum execution time: 69_938_000 picoseconds. - Weight::from_parts(70_723_000, 30748) + // Estimated: `11506` + // Minimum execution time: 69_179_000 picoseconds. + Weight::from_parts(69_898_000, 11506) .saturating_add(RocksDbWeight::get().reads(10_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } diff --git a/frame/balances/src/weights.rs b/frame/balances/src/weights.rs index a2a9f0019b931..f35d9c697028b 100644 --- a/frame/balances/src/weights.rs +++ b/frame/balances/src/weights.rs @@ -18,26 +18,25 @@ //! Autogenerated weights for pallet_balances //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-17, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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 // --steps=50 // --repeat=20 +// --pallet=pallet_balances // --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_balances -// --chain=dev -// --header=./HEADER-APACHE2 // --output=./frame/balances/src/weights.rs +// --header=./HEADER-APACHE2 // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -68,8 +67,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 36_551_000 picoseconds. - Weight::from_parts(37_150_000, 3593) + // Minimum execution time: 59_458_000 picoseconds. + Weight::from_parts(60_307_000, 3593) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -79,8 +78,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 28_246_000 picoseconds. - Weight::from_parts(28_647_000, 3593) + // Minimum execution time: 43_056_000 picoseconds. + Weight::from_parts(43_933_000, 3593) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -90,8 +89,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 17_407_000 picoseconds. - Weight::from_parts(17_827_000, 3593) + // Minimum execution time: 17_428_000 picoseconds. + Weight::from_parts(17_731_000, 3593) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -101,8 +100,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 20_941_000 picoseconds. - Weight::from_parts(21_383_000, 3593) + // Minimum execution time: 22_809_000 picoseconds. + Weight::from_parts(23_225_000, 3593) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -112,8 +111,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `103` // Estimated: `6196` - // Minimum execution time: 38_741_000 picoseconds. - Weight::from_parts(39_201_000, 6196) + // Minimum execution time: 56_929_000 picoseconds. + Weight::from_parts(57_688_000, 6196) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -123,8 +122,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 33_791_000 picoseconds. - Weight::from_parts(34_500_000, 3593) + // Minimum execution time: 49_820_000 picoseconds. + Weight::from_parts(50_832_000, 3593) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -134,8 +133,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 16_538_000 picoseconds. - Weight::from_parts(16_859_000, 3593) + // Minimum execution time: 20_270_000 picoseconds. + Weight::from_parts(20_597_000, 3593) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -146,10 +145,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0 + u * (135 ±0)` // Estimated: `990 + u * (2603 ±0)` - // Minimum execution time: 19_851_000 picoseconds. - Weight::from_parts(20_099_000, 990) - // Standard Error: 15_586 - .saturating_add(Weight::from_parts(14_892_860, 0).saturating_mul(u.into())) + // Minimum execution time: 19_847_000 picoseconds. + Weight::from_parts(20_053_000, 990) + // Standard Error: 11_643 + .saturating_add(Weight::from_parts(14_563_782, 0).saturating_mul(u.into())) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(u.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(u.into()))) .saturating_add(Weight::from_parts(0, 2603).saturating_mul(u.into())) @@ -164,8 +163,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 36_551_000 picoseconds. - Weight::from_parts(37_150_000, 3593) + // Minimum execution time: 59_458_000 picoseconds. + Weight::from_parts(60_307_000, 3593) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -175,8 +174,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 28_246_000 picoseconds. - Weight::from_parts(28_647_000, 3593) + // Minimum execution time: 43_056_000 picoseconds. + Weight::from_parts(43_933_000, 3593) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -186,8 +185,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 17_407_000 picoseconds. - Weight::from_parts(17_827_000, 3593) + // Minimum execution time: 17_428_000 picoseconds. + Weight::from_parts(17_731_000, 3593) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -197,8 +196,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 20_941_000 picoseconds. - Weight::from_parts(21_383_000, 3593) + // Minimum execution time: 22_809_000 picoseconds. + Weight::from_parts(23_225_000, 3593) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -208,8 +207,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `103` // Estimated: `6196` - // Minimum execution time: 38_741_000 picoseconds. - Weight::from_parts(39_201_000, 6196) + // Minimum execution time: 56_929_000 picoseconds. + Weight::from_parts(57_688_000, 6196) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -219,8 +218,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 33_791_000 picoseconds. - Weight::from_parts(34_500_000, 3593) + // Minimum execution time: 49_820_000 picoseconds. + Weight::from_parts(50_832_000, 3593) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -230,8 +229,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 16_538_000 picoseconds. - Weight::from_parts(16_859_000, 3593) + // Minimum execution time: 20_270_000 picoseconds. + Weight::from_parts(20_597_000, 3593) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -242,10 +241,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0 + u * (135 ±0)` // Estimated: `990 + u * (2603 ±0)` - // Minimum execution time: 19_851_000 picoseconds. - Weight::from_parts(20_099_000, 990) - // Standard Error: 15_586 - .saturating_add(Weight::from_parts(14_892_860, 0).saturating_mul(u.into())) + // Minimum execution time: 19_847_000 picoseconds. + Weight::from_parts(20_053_000, 990) + // Standard Error: 11_643 + .saturating_add(Weight::from_parts(14_563_782, 0).saturating_mul(u.into())) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(u.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(u.into()))) .saturating_add(Weight::from_parts(0, 2603).saturating_mul(u.into())) diff --git a/frame/benchmarking/pov/src/benchmarking.rs b/frame/benchmarking/pov/src/benchmarking.rs index 46a98ae3ff183..27191e37219fd 100644 --- a/frame/benchmarking/pov/src/benchmarking.rs +++ b/frame/benchmarking/pov/src/benchmarking.rs @@ -192,6 +192,7 @@ frame_benchmarking::benchmarks! { // Same as above, but we still expect a mathematical worst case PoV size for the bounded one. storage_value_bounded_and_unbounded_read { + (0..1024).for_each(|i| Map1M::::insert(i, i)); }: { assert!(UnboundedValue::::get().is_none()); assert!(BoundedValue::::get().is_none()); diff --git a/frame/benchmarking/pov/src/tests.rs b/frame/benchmarking/pov/src/tests.rs index 19156b93060bc..b908925cccd8e 100644 --- a/frame/benchmarking/pov/src/tests.rs +++ b/frame/benchmarking/pov/src/tests.rs @@ -144,9 +144,9 @@ fn unbounded_read_best_effort() { fn partial_unbounded_read_best_effort() { let w_unbounded = W::storage_value_unbounded_read().proof_size(); let w_bounded = W::storage_value_bounded_read().proof_size(); - let w_partial = W::storage_value_bounded_and_unbounded_read().proof_size(); + let w_both = W::storage_value_bounded_and_unbounded_read().proof_size(); - assert_eq!(w_bounded + w_unbounded, w_partial, "The bounded part increases the PoV"); + assert!(w_both > w_bounded && w_both > w_unbounded, "The bounded part increases the PoV"); } #[test] diff --git a/frame/benchmarking/pov/src/weights.rs b/frame/benchmarking/pov/src/weights.rs index df6dba33b2dd3..f16ac7fbc2733 100644 --- a/frame/benchmarking/pov/src/weights.rs +++ b/frame/benchmarking/pov/src/weights.rs @@ -2,7 +2,7 @@ //! Autogenerated weights for frame_benchmarking_pallet_pov //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-04-12, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `i9`, CPU: `13th Gen Intel(R) Core(TM) i9-13900K` //! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 1024 @@ -28,7 +28,7 @@ #![allow(unused_imports)] use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; -use sp_std::marker::PhantomData; +use core::marker::PhantomData; /// Weight functions needed for frame_benchmarking_pallet_pov. pub trait WeightInfo { @@ -61,6 +61,7 @@ pub trait WeightInfo { fn storage_map_partial_unbounded_ignored_read(i: u32, ) -> Weight; fn emit_event() -> Weight; fn noop() -> Weight; + fn storage_iteration() -> Weight; } /// Weights for frame_benchmarking_pallet_pov using the Substrate node and recommended hardware. @@ -72,9 +73,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `136` // Estimated: `1489` - // Minimum execution time: 1_968 nanoseconds. - Weight::from_parts(2_060_000, 0) - .saturating_add(Weight::from_parts(0, 1489)) + // Minimum execution time: 1_706_000 picoseconds. + Weight::from_parts(1_788_000, 1489) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: Pov Value (r:1 w:0) @@ -83,9 +83,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `136` // Estimated: `0` - // Minimum execution time: 1_934 nanoseconds. - Weight::from_parts(2_092_000, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Minimum execution time: 1_661_000 picoseconds. + Weight::from_parts(1_718_000, 0) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: Pov Value (r:1 w:0) @@ -95,10 +94,9 @@ impl WeightInfo for SubstrateWeight { fn storage_single_value_ignored_some_read() -> Weight { // Proof Size summary in bytes: // Measured: `160` - // Estimated: `1649` - // Minimum execution time: 2_605 nanoseconds. - Weight::from_parts(2_786_000, 0) - .saturating_add(Weight::from_parts(0, 1649)) + // Estimated: `1489` + // Minimum execution time: 2_226_000 picoseconds. + Weight::from_parts(2_365_000, 1489) .saturating_add(T::DbWeight::get().reads(2_u64)) } /// Storage: Pov Value (r:1 w:0) @@ -107,9 +105,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `136` // Estimated: `1489` - // Minimum execution time: 2_019 nanoseconds. - Weight::from_parts(2_214_000, 0) - .saturating_add(Weight::from_parts(0, 1489)) + // Minimum execution time: 1_785_000 picoseconds. + Weight::from_parts(1_980_000, 1489) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: Pov Value (r:0 w:1) @@ -118,9 +115,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 279 nanoseconds. - Weight::from_parts(357_000, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Minimum execution time: 254_000 picoseconds. + Weight::from_parts(326_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Pov Value (r:0 w:1) @@ -129,9 +125,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 291 nanoseconds. - Weight::from_parts(378_000, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Minimum execution time: 239_000 picoseconds. + Weight::from_parts(277_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Pov Map1M (r:1 w:0) @@ -140,9 +135,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1275` // Estimated: `4740` - // Minimum execution time: 5_077 nanoseconds. - Weight::from_parts(5_400_000, 0) - .saturating_add(Weight::from_parts(0, 4740)) + // Minimum execution time: 4_760_000 picoseconds. + Weight::from_parts(5_051_000, 4740) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: Pov Map1M (r:1 w:0) @@ -151,9 +145,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1544` // Estimated: `5009` - // Minimum execution time: 5_878 nanoseconds. - Weight::from_parts(6_239_000, 0) - .saturating_add(Weight::from_parts(0, 5009)) + // Minimum execution time: 5_490_000 picoseconds. + Weight::from_parts(5_703_000, 5009) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: Pov Map1M (r:1 w:0) @@ -162,9 +155,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `2044` // Estimated: `5509` - // Minimum execution time: 7_282 nanoseconds. - Weight::from_parts(8_022_000, 0) - .saturating_add(Weight::from_parts(0, 5509)) + // Minimum execution time: 6_397_000 picoseconds. + Weight::from_parts(7_084_000, 5509) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: Pov Map1M (r:100 w:0) @@ -175,19 +167,18 @@ impl WeightInfo for SubstrateWeight { /// The range of component `m` is `[0, 100]`. fn storage_map_read_per_component(n: u32, m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `515 + n * (188 ±0) + m * (188 ±0)` - // Estimated: `1980 + n * (3006 ±0) + m * (2511 ±0)` - // Minimum execution time: 195_406 nanoseconds. - Weight::from_parts(129_093_464, 0) - .saturating_add(Weight::from_parts(0, 1980)) - // Standard Error: 12_134 - .saturating_add(Weight::from_parts(855_330, 0).saturating_mul(n.into())) - // Standard Error: 12_134 - .saturating_add(Weight::from_parts(870_523, 0).saturating_mul(m.into())) + // Measured: `515 + m * (188 ±0) + n * (188 ±0)` + // Estimated: `990 + m * (2511 ±0) + n * (3006 ±0)` + // Minimum execution time: 181_481_000 picoseconds. + Weight::from_parts(129_275_141, 990) + // Standard Error: 13_049 + .saturating_add(Weight::from_parts(787_667, 0).saturating_mul(n.into())) + // Standard Error: 13_049 + .saturating_add(Weight::from_parts(830_378, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(m.into()))) - .saturating_add(Weight::from_parts(0, 3006).saturating_mul(n.into())) .saturating_add(Weight::from_parts(0, 2511).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 3006).saturating_mul(n.into())) } /// Storage: Pov Map1M (r:100 w:0) /// Proof: Pov Map1M (max_values: Some(1000000), max_size: Some(36), added: 2511, mode: Ignored) @@ -197,19 +188,18 @@ impl WeightInfo for SubstrateWeight { /// The range of component `m` is `[0, 100]`. fn storage_map_read_per_component_one_ignored(n: u32, m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `515 + n * (188 ±0) + m * (188 ±0)` - // Estimated: `1685 + n * (3195 ±0) + m * (189 ±0)` - // Minimum execution time: 195_053 nanoseconds. - Weight::from_parts(131_322_479, 0) - .saturating_add(Weight::from_parts(0, 1685)) - // Standard Error: 12_161 - .saturating_add(Weight::from_parts(843_047, 0).saturating_mul(n.into())) - // Standard Error: 12_161 - .saturating_add(Weight::from_parts(858_668, 0).saturating_mul(m.into())) + // Measured: `515 + m * (188 ±0) + n * (188 ±0)` + // Estimated: `1685 + m * (189 ±0) + n * (3006 ±0)` + // Minimum execution time: 181_925_000 picoseconds. + Weight::from_parts(134_416_814, 1685) + // Standard Error: 15_678 + .saturating_add(Weight::from_parts(827_168, 0).saturating_mul(n.into())) + // Standard Error: 15_678 + .saturating_add(Weight::from_parts(813_655, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(m.into()))) - .saturating_add(Weight::from_parts(0, 3195).saturating_mul(n.into())) .saturating_add(Weight::from_parts(0, 189).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 3006).saturating_mul(n.into())) } /// Storage: Pov Map1M (r:1 w:0) /// Proof: Pov Map1M (max_values: Some(1000000), max_size: Some(36), added: 2511, mode: MaxEncodedLen) @@ -218,11 +208,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `170` // Estimated: `3501` - // Minimum execution time: 22 nanoseconds. - Weight::from_parts(2_334_945, 0) - .saturating_add(Weight::from_parts(0, 3501)) - // Standard Error: 624 - .saturating_add(Weight::from_parts(282_046, 0).saturating_mul(n.into())) + // Minimum execution time: 20_000 picoseconds. + Weight::from_parts(2_006_399, 3501) + // Standard Error: 808 + .saturating_add(Weight::from_parts(263_609, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: Pov Map1M (r:100 w:0) @@ -232,11 +221,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `147 + n * (40 ±0)` // Estimated: `990 + n * (2511 ±0)` - // Minimum execution time: 20 nanoseconds. - Weight::from_parts(525_027, 0) - .saturating_add(Weight::from_parts(0, 990)) - // Standard Error: 2_767 - .saturating_add(Weight::from_parts(3_887_350, 0).saturating_mul(n.into())) + // Minimum execution time: 21_000 picoseconds. + Weight::from_parts(3_940_044, 990) + // Standard Error: 4_906 + .saturating_add(Weight::from_parts(3_454_882, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(Weight::from_parts(0, 2511).saturating_mul(n.into())) } @@ -247,11 +235,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `21938 + n * (57 ±0)` // Estimated: `990 + n * (2543 ±0)` - // Minimum execution time: 34 nanoseconds. - Weight::from_parts(18_341_393, 0) - .saturating_add(Weight::from_parts(0, 990)) - // Standard Error: 1_312 - .saturating_add(Weight::from_parts(2_053_135, 0).saturating_mul(n.into())) + // Minimum execution time: 28_000 picoseconds. + Weight::from_parts(20_674_869, 990) + // Standard Error: 3_035 + .saturating_add(Weight::from_parts(1_995_730, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(Weight::from_parts(0, 2543).saturating_mul(n.into())) } @@ -261,9 +248,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `109` // Estimated: `1518` - // Minimum execution time: 1_163 nanoseconds. - Weight::from_parts(1_274_000, 0) - .saturating_add(Weight::from_parts(0, 1518)) + // Minimum execution time: 1_091_000 picoseconds. + Weight::from_parts(1_181_000, 1518) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: Pov UnboundedValue (r:1 w:0) @@ -272,9 +258,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `109` // Estimated: `1594` - // Minimum execution time: 1_167 nanoseconds. - Weight::from_parts(1_367_000, 0) - .saturating_add(Weight::from_parts(0, 1594)) + // Minimum execution time: 1_079_000 picoseconds. + Weight::from_parts(1_176_000, 1594) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: Pov UnboundedValue (r:1 w:0) @@ -283,9 +268,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `109` // Estimated: `0` - // Minimum execution time: 1_155 nanoseconds. - Weight::from_parts(1_248_000, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Minimum execution time: 1_101_000 picoseconds. + Weight::from_parts(1_160_000, 0) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: Pov UnboundedValue (r:1 w:0) @@ -294,11 +278,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Pov BoundedValue (max_values: Some(1), max_size: Some(33), added: 528, mode: MaxEncodedLen) fn storage_value_bounded_and_unbounded_read() -> Weight { // Proof Size summary in bytes: - // Measured: `109` - // Estimated: `3112` - // Minimum execution time: 1_424 nanoseconds. - Weight::from_parts(1_601_000, 0) - .saturating_add(Weight::from_parts(0, 3112)) + // Measured: `147` + // Estimated: `1632` + // Minimum execution time: 2_143_000 picoseconds. + Weight::from_parts(2_280_000, 1632) .saturating_add(T::DbWeight::get().reads(2_u64)) } /// Storage: Pov LargeValue (r:1 w:0) @@ -306,13 +289,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `l` is `[0, 4194304]`. fn measured_storage_value_read_linear_size(l: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `174 + l * (1 ±0)` - // Estimated: `1656 + l * (1 ±0)` - // Minimum execution time: 1_744 nanoseconds. - Weight::from_parts(1_800_000, 0) - .saturating_add(Weight::from_parts(0, 1656)) - // Standard Error: 4 - .saturating_add(Weight::from_parts(443, 0).saturating_mul(l.into())) + // Measured: `142 + l * (1 ±0)` + // Estimated: `1626 + l * (1 ±0)` + // Minimum execution time: 1_665_000 picoseconds. + Weight::from_parts(1_725_000, 1626) + // Standard Error: 3 + .saturating_add(Weight::from_parts(376, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(l.into())) } @@ -321,13 +303,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `l` is `[0, 4194304]`. fn mel_storage_value_read_linear_size(l: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `174 + l * (1 ±0)` + // Measured: `142 + l * (1 ±0)` // Estimated: `4195793` - // Minimum execution time: 1_770 nanoseconds. - Weight::from_parts(1_813_000, 0) - .saturating_add(Weight::from_parts(0, 4195793)) - // Standard Error: 6 - .saturating_add(Weight::from_parts(495, 0).saturating_mul(l.into())) + // Minimum execution time: 1_640_000 picoseconds. + Weight::from_parts(1_724_000, 4195793) + // Standard Error: 4 + .saturating_add(Weight::from_parts(395, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: Pov LargeValue (r:1 w:0) @@ -337,15 +318,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `l` is `[0, 4194304]`. fn measured_storage_double_value_read_linear_size(l: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `235 + l * (2 ±0)` - // Estimated: `3428 + l * (4 ±0)` - // Minimum execution time: 2_349 nanoseconds. - Weight::from_parts(2_423_000, 0) - .saturating_add(Weight::from_parts(0, 3428)) - // Standard Error: 11 - .saturating_add(Weight::from_parts(950, 0).saturating_mul(l.into())) + // Measured: `171 + l * (2 ±0)` + // Estimated: `1655 + l * (2 ±0)` + // Minimum execution time: 2_263_000 picoseconds. + Weight::from_parts(2_358_000, 1655) + // Standard Error: 8 + .saturating_add(Weight::from_parts(737, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(Weight::from_parts(0, 4).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(0, 2).saturating_mul(l.into())) } /// Storage: Pov LargeValue (r:1 w:0) /// Proof: Pov LargeValue (max_values: Some(1), max_size: Some(4194308), added: 4194803, mode: MaxEncodedLen) @@ -354,13 +334,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `l` is `[0, 4194304]`. fn mel_storage_double_value_read_linear_size(l: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `235 + l * (2 ±0)` - // Estimated: `8391586` - // Minimum execution time: 2_315 nanoseconds. - Weight::from_parts(2_409_000, 0) - .saturating_add(Weight::from_parts(0, 8391586)) - // Standard Error: 12 - .saturating_add(Weight::from_parts(984, 0).saturating_mul(l.into())) + // Measured: `171 + l * (2 ±0)` + // Estimated: `4195793` + // Minimum execution time: 2_161_000 picoseconds. + Weight::from_parts(2_233_000, 4195793) + // Standard Error: 5 + .saturating_add(Weight::from_parts(639, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) } /// Storage: Pov LargeValue (r:1 w:0) @@ -370,13 +349,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `l` is `[0, 4194304]`. fn mel_mixed_storage_double_value_read_linear_size(l: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `235 + l * (2 ±0)` - // Estimated: `4197507 + l * (2 ±0)` - // Minimum execution time: 2_370 nanoseconds. - Weight::from_parts(2_474_000, 0) - .saturating_add(Weight::from_parts(0, 4197507)) - // Standard Error: 11 - .saturating_add(Weight::from_parts(956, 0).saturating_mul(l.into())) + // Measured: `171 + l * (2 ±0)` + // Estimated: `4195793 + l * (2 ±0)` + // Minimum execution time: 2_149_000 picoseconds. + Weight::from_parts(2_256_000, 4195793) + // Standard Error: 6 + .saturating_add(Weight::from_parts(677, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(Weight::from_parts(0, 2).saturating_mul(l.into())) } @@ -387,13 +365,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `l` is `[0, 4194304]`. fn measured_mixed_storage_double_value_read_linear_size(l: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `235 + l * (2 ±0)` - // Estimated: `4197507 + l * (2 ±0)` - // Minimum execution time: 2_375 nanoseconds. - Weight::from_parts(2_420_000, 0) - .saturating_add(Weight::from_parts(0, 4197507)) - // Standard Error: 9 - .saturating_add(Weight::from_parts(914, 0).saturating_mul(l.into())) + // Measured: `171 + l * (2 ±0)` + // Estimated: `4195793 + l * (2 ±0)` + // Minimum execution time: 2_254_000 picoseconds. + Weight::from_parts(2_319_000, 4195793) + // Standard Error: 5 + .saturating_add(Weight::from_parts(664, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(Weight::from_parts(0, 2).saturating_mul(l.into())) } @@ -404,15 +381,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `i` is `[0, 1000]`. fn storage_map_unbounded_both_measured_read(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `293 + i * (8 ±0)` - // Estimated: `7504 + i * (16 ±0)` - // Minimum execution time: 3_305 nanoseconds. - Weight::from_parts(3_689_335, 0) - .saturating_add(Weight::from_parts(0, 7504)) - // Standard Error: 29 - .saturating_add(Weight::from_parts(638, 0).saturating_mul(i.into())) + // Measured: `229 + i * (8 ±0)` + // Estimated: `3693 + i * (8 ±0)` + // Minimum execution time: 3_071_000 picoseconds. + Weight::from_parts(3_487_712, 3693) + // Standard Error: 26 + .saturating_add(Weight::from_parts(748, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(Weight::from_parts(0, 16).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(0, 8).saturating_mul(i.into())) } /// Storage: Pov Map1M (r:1 w:0) /// Proof: Pov Map1M (max_values: Some(1000000), max_size: Some(36), added: 2511, mode: MaxEncodedLen) @@ -421,13 +397,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `i` is `[0, 1000]`. fn storage_map_partial_unbounded_read(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `260 + i * (4 ±0)` - // Estimated: `7223 + i * (4 ±0)` - // Minimum execution time: 3_469 nanoseconds. - Weight::from_parts(3_878_896, 0) - .saturating_add(Weight::from_parts(0, 7223)) - // Standard Error: 33 - .saturating_add(Weight::from_parts(356, 0).saturating_mul(i.into())) + // Measured: `228 + i * (4 ±0)` + // Estimated: `3692 + i * (4 ±0)` + // Minimum execution time: 3_150_000 picoseconds. + Weight::from_parts(3_582_963, 3692) + // Standard Error: 18 + .saturating_add(Weight::from_parts(380, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(Weight::from_parts(0, 4).saturating_mul(i.into())) } @@ -438,13 +413,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `i` is `[0, 1000]`. fn storage_map_partial_unbounded_ignored_read(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `260 + i * (4 ±0)` - // Estimated: `3758 + i * (4 ±0)` - // Minimum execution time: 3_442 nanoseconds. - Weight::from_parts(3_881_051, 0) - .saturating_add(Weight::from_parts(0, 3758)) - // Standard Error: 35 - .saturating_add(Weight::from_parts(384, 0).saturating_mul(i.into())) + // Measured: `228 + i * (4 ±0)` + // Estimated: `3501 + i * (4 ±0)` + // Minimum execution time: 3_092_000 picoseconds. + Weight::from_parts(3_595_328, 3501) + // Standard Error: 20 + .saturating_add(Weight::from_parts(243, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(Weight::from_parts(0, 4).saturating_mul(i.into())) } @@ -452,17 +426,25 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_619 nanoseconds. - Weight::from_parts(1_728_000, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Minimum execution time: 1_705_000 picoseconds. + Weight::from_parts(1_818_000, 0) } fn noop() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 546 nanoseconds. - Weight::from_parts(640_000, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Minimum execution time: 533_000 picoseconds. + Weight::from_parts(587_000, 0) + } + /// Storage: Pov UnboundedMapTwox (r:65001 w:0) + /// Proof Skipped: Pov UnboundedMapTwox (max_values: None, max_size: None, mode: Measured) + fn storage_iteration() -> Weight { + // Proof Size summary in bytes: + // Measured: `17985289` + // Estimated: `178863754` + // Minimum execution time: 118_753_057_000 picoseconds. + Weight::from_parts(121_396_503_000, 178863754) + .saturating_add(T::DbWeight::get().reads(65001_u64)) } } @@ -474,9 +456,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `136` // Estimated: `1489` - // Minimum execution time: 1_968 nanoseconds. - Weight::from_parts(2_060_000, 0) - .saturating_add(Weight::from_parts(0, 1489)) + // Minimum execution time: 1_706_000 picoseconds. + Weight::from_parts(1_788_000, 1489) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: Pov Value (r:1 w:0) @@ -485,9 +466,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `136` // Estimated: `0` - // Minimum execution time: 1_934 nanoseconds. - Weight::from_parts(2_092_000, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Minimum execution time: 1_661_000 picoseconds. + Weight::from_parts(1_718_000, 0) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: Pov Value (r:1 w:0) @@ -497,10 +477,9 @@ impl WeightInfo for () { fn storage_single_value_ignored_some_read() -> Weight { // Proof Size summary in bytes: // Measured: `160` - // Estimated: `1649` - // Minimum execution time: 2_605 nanoseconds. - Weight::from_parts(2_786_000, 0) - .saturating_add(Weight::from_parts(0, 1649)) + // Estimated: `1489` + // Minimum execution time: 2_226_000 picoseconds. + Weight::from_parts(2_365_000, 1489) .saturating_add(RocksDbWeight::get().reads(2_u64)) } /// Storage: Pov Value (r:1 w:0) @@ -509,9 +488,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `136` // Estimated: `1489` - // Minimum execution time: 2_019 nanoseconds. - Weight::from_parts(2_214_000, 0) - .saturating_add(Weight::from_parts(0, 1489)) + // Minimum execution time: 1_785_000 picoseconds. + Weight::from_parts(1_980_000, 1489) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: Pov Value (r:0 w:1) @@ -520,9 +498,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 279 nanoseconds. - Weight::from_parts(357_000, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Minimum execution time: 254_000 picoseconds. + Weight::from_parts(326_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Pov Value (r:0 w:1) @@ -531,9 +508,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 291 nanoseconds. - Weight::from_parts(378_000, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Minimum execution time: 239_000 picoseconds. + Weight::from_parts(277_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Pov Map1M (r:1 w:0) @@ -542,9 +518,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1275` // Estimated: `4740` - // Minimum execution time: 5_077 nanoseconds. - Weight::from_parts(5_400_000, 0) - .saturating_add(Weight::from_parts(0, 4740)) + // Minimum execution time: 4_760_000 picoseconds. + Weight::from_parts(5_051_000, 4740) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: Pov Map1M (r:1 w:0) @@ -553,9 +528,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1544` // Estimated: `5009` - // Minimum execution time: 5_878 nanoseconds. - Weight::from_parts(6_239_000, 0) - .saturating_add(Weight::from_parts(0, 5009)) + // Minimum execution time: 5_490_000 picoseconds. + Weight::from_parts(5_703_000, 5009) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: Pov Map1M (r:1 w:0) @@ -564,9 +538,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `2044` // Estimated: `5509` - // Minimum execution time: 7_282 nanoseconds. - Weight::from_parts(8_022_000, 0) - .saturating_add(Weight::from_parts(0, 5509)) + // Minimum execution time: 6_397_000 picoseconds. + Weight::from_parts(7_084_000, 5509) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: Pov Map1M (r:100 w:0) @@ -577,19 +550,18 @@ impl WeightInfo for () { /// The range of component `m` is `[0, 100]`. fn storage_map_read_per_component(n: u32, m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `515 + n * (188 ±0) + m * (188 ±0)` - // Estimated: `1980 + n * (3006 ±0) + m * (2511 ±0)` - // Minimum execution time: 195_406 nanoseconds. - Weight::from_parts(129_093_464, 0) - .saturating_add(Weight::from_parts(0, 1980)) - // Standard Error: 12_134 - .saturating_add(Weight::from_parts(855_330, 0).saturating_mul(n.into())) - // Standard Error: 12_134 - .saturating_add(Weight::from_parts(870_523, 0).saturating_mul(m.into())) + // Measured: `515 + m * (188 ±0) + n * (188 ±0)` + // Estimated: `990 + m * (2511 ±0) + n * (3006 ±0)` + // Minimum execution time: 181_481_000 picoseconds. + Weight::from_parts(129_275_141, 990) + // Standard Error: 13_049 + .saturating_add(Weight::from_parts(787_667, 0).saturating_mul(n.into())) + // Standard Error: 13_049 + .saturating_add(Weight::from_parts(830_378, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(m.into()))) - .saturating_add(Weight::from_parts(0, 3006).saturating_mul(n.into())) .saturating_add(Weight::from_parts(0, 2511).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 3006).saturating_mul(n.into())) } /// Storage: Pov Map1M (r:100 w:0) /// Proof: Pov Map1M (max_values: Some(1000000), max_size: Some(36), added: 2511, mode: Ignored) @@ -599,19 +571,18 @@ impl WeightInfo for () { /// The range of component `m` is `[0, 100]`. fn storage_map_read_per_component_one_ignored(n: u32, m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `515 + n * (188 ±0) + m * (188 ±0)` - // Estimated: `1685 + n * (3195 ±0) + m * (189 ±0)` - // Minimum execution time: 195_053 nanoseconds. - Weight::from_parts(131_322_479, 0) - .saturating_add(Weight::from_parts(0, 1685)) - // Standard Error: 12_161 - .saturating_add(Weight::from_parts(843_047, 0).saturating_mul(n.into())) - // Standard Error: 12_161 - .saturating_add(Weight::from_parts(858_668, 0).saturating_mul(m.into())) + // Measured: `515 + m * (188 ±0) + n * (188 ±0)` + // Estimated: `1685 + m * (189 ±0) + n * (3006 ±0)` + // Minimum execution time: 181_925_000 picoseconds. + Weight::from_parts(134_416_814, 1685) + // Standard Error: 15_678 + .saturating_add(Weight::from_parts(827_168, 0).saturating_mul(n.into())) + // Standard Error: 15_678 + .saturating_add(Weight::from_parts(813_655, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(m.into()))) - .saturating_add(Weight::from_parts(0, 3195).saturating_mul(n.into())) .saturating_add(Weight::from_parts(0, 189).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 3006).saturating_mul(n.into())) } /// Storage: Pov Map1M (r:1 w:0) /// Proof: Pov Map1M (max_values: Some(1000000), max_size: Some(36), added: 2511, mode: MaxEncodedLen) @@ -620,11 +591,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `170` // Estimated: `3501` - // Minimum execution time: 22 nanoseconds. - Weight::from_parts(2_334_945, 0) - .saturating_add(Weight::from_parts(0, 3501)) - // Standard Error: 624 - .saturating_add(Weight::from_parts(282_046, 0).saturating_mul(n.into())) + // Minimum execution time: 20_000 picoseconds. + Weight::from_parts(2_006_399, 3501) + // Standard Error: 808 + .saturating_add(Weight::from_parts(263_609, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: Pov Map1M (r:100 w:0) @@ -634,11 +604,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `147 + n * (40 ±0)` // Estimated: `990 + n * (2511 ±0)` - // Minimum execution time: 20 nanoseconds. - Weight::from_parts(525_027, 0) - .saturating_add(Weight::from_parts(0, 990)) - // Standard Error: 2_767 - .saturating_add(Weight::from_parts(3_887_350, 0).saturating_mul(n.into())) + // Minimum execution time: 21_000 picoseconds. + Weight::from_parts(3_940_044, 990) + // Standard Error: 4_906 + .saturating_add(Weight::from_parts(3_454_882, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(Weight::from_parts(0, 2511).saturating_mul(n.into())) } @@ -649,11 +618,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `21938 + n * (57 ±0)` // Estimated: `990 + n * (2543 ±0)` - // Minimum execution time: 34 nanoseconds. - Weight::from_parts(18_341_393, 0) - .saturating_add(Weight::from_parts(0, 990)) - // Standard Error: 1_312 - .saturating_add(Weight::from_parts(2_053_135, 0).saturating_mul(n.into())) + // Minimum execution time: 28_000 picoseconds. + Weight::from_parts(20_674_869, 990) + // Standard Error: 3_035 + .saturating_add(Weight::from_parts(1_995_730, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(Weight::from_parts(0, 2543).saturating_mul(n.into())) } @@ -663,9 +631,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `109` // Estimated: `1518` - // Minimum execution time: 1_163 nanoseconds. - Weight::from_parts(1_274_000, 0) - .saturating_add(Weight::from_parts(0, 1518)) + // Minimum execution time: 1_091_000 picoseconds. + Weight::from_parts(1_181_000, 1518) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: Pov UnboundedValue (r:1 w:0) @@ -674,9 +641,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `109` // Estimated: `1594` - // Minimum execution time: 1_167 nanoseconds. - Weight::from_parts(1_367_000, 0) - .saturating_add(Weight::from_parts(0, 1594)) + // Minimum execution time: 1_079_000 picoseconds. + Weight::from_parts(1_176_000, 1594) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: Pov UnboundedValue (r:1 w:0) @@ -685,9 +651,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `109` // Estimated: `0` - // Minimum execution time: 1_155 nanoseconds. - Weight::from_parts(1_248_000, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Minimum execution time: 1_101_000 picoseconds. + Weight::from_parts(1_160_000, 0) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: Pov UnboundedValue (r:1 w:0) @@ -696,11 +661,10 @@ impl WeightInfo for () { /// Proof: Pov BoundedValue (max_values: Some(1), max_size: Some(33), added: 528, mode: MaxEncodedLen) fn storage_value_bounded_and_unbounded_read() -> Weight { // Proof Size summary in bytes: - // Measured: `109` - // Estimated: `3112` - // Minimum execution time: 1_424 nanoseconds. - Weight::from_parts(1_601_000, 0) - .saturating_add(Weight::from_parts(0, 3112)) + // Measured: `147` + // Estimated: `1632` + // Minimum execution time: 2_143_000 picoseconds. + Weight::from_parts(2_280_000, 1632) .saturating_add(RocksDbWeight::get().reads(2_u64)) } /// Storage: Pov LargeValue (r:1 w:0) @@ -708,13 +672,12 @@ impl WeightInfo for () { /// The range of component `l` is `[0, 4194304]`. fn measured_storage_value_read_linear_size(l: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `174 + l * (1 ±0)` - // Estimated: `1656 + l * (1 ±0)` - // Minimum execution time: 1_744 nanoseconds. - Weight::from_parts(1_800_000, 0) - .saturating_add(Weight::from_parts(0, 1656)) - // Standard Error: 4 - .saturating_add(Weight::from_parts(443, 0).saturating_mul(l.into())) + // Measured: `142 + l * (1 ±0)` + // Estimated: `1626 + l * (1 ±0)` + // Minimum execution time: 1_665_000 picoseconds. + Weight::from_parts(1_725_000, 1626) + // Standard Error: 3 + .saturating_add(Weight::from_parts(376, 0).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(l.into())) } @@ -723,13 +686,12 @@ impl WeightInfo for () { /// The range of component `l` is `[0, 4194304]`. fn mel_storage_value_read_linear_size(l: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `174 + l * (1 ±0)` + // Measured: `142 + l * (1 ±0)` // Estimated: `4195793` - // Minimum execution time: 1_770 nanoseconds. - Weight::from_parts(1_813_000, 0) - .saturating_add(Weight::from_parts(0, 4195793)) - // Standard Error: 6 - .saturating_add(Weight::from_parts(495, 0).saturating_mul(l.into())) + // Minimum execution time: 1_640_000 picoseconds. + Weight::from_parts(1_724_000, 4195793) + // Standard Error: 4 + .saturating_add(Weight::from_parts(395, 0).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: Pov LargeValue (r:1 w:0) @@ -739,15 +701,14 @@ impl WeightInfo for () { /// The range of component `l` is `[0, 4194304]`. fn measured_storage_double_value_read_linear_size(l: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `235 + l * (2 ±0)` - // Estimated: `3428 + l * (4 ±0)` - // Minimum execution time: 2_349 nanoseconds. - Weight::from_parts(2_423_000, 0) - .saturating_add(Weight::from_parts(0, 3428)) - // Standard Error: 11 - .saturating_add(Weight::from_parts(950, 0).saturating_mul(l.into())) + // Measured: `171 + l * (2 ±0)` + // Estimated: `1655 + l * (2 ±0)` + // Minimum execution time: 2_263_000 picoseconds. + Weight::from_parts(2_358_000, 1655) + // Standard Error: 8 + .saturating_add(Weight::from_parts(737, 0).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(Weight::from_parts(0, 4).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(0, 2).saturating_mul(l.into())) } /// Storage: Pov LargeValue (r:1 w:0) /// Proof: Pov LargeValue (max_values: Some(1), max_size: Some(4194308), added: 4194803, mode: MaxEncodedLen) @@ -756,13 +717,12 @@ impl WeightInfo for () { /// The range of component `l` is `[0, 4194304]`. fn mel_storage_double_value_read_linear_size(l: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `235 + l * (2 ±0)` - // Estimated: `8391586` - // Minimum execution time: 2_315 nanoseconds. - Weight::from_parts(2_409_000, 0) - .saturating_add(Weight::from_parts(0, 8391586)) - // Standard Error: 12 - .saturating_add(Weight::from_parts(984, 0).saturating_mul(l.into())) + // Measured: `171 + l * (2 ±0)` + // Estimated: `4195793` + // Minimum execution time: 2_161_000 picoseconds. + Weight::from_parts(2_233_000, 4195793) + // Standard Error: 5 + .saturating_add(Weight::from_parts(639, 0).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) } /// Storage: Pov LargeValue (r:1 w:0) @@ -772,13 +732,12 @@ impl WeightInfo for () { /// The range of component `l` is `[0, 4194304]`. fn mel_mixed_storage_double_value_read_linear_size(l: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `235 + l * (2 ±0)` - // Estimated: `4197507 + l * (2 ±0)` - // Minimum execution time: 2_370 nanoseconds. - Weight::from_parts(2_474_000, 0) - .saturating_add(Weight::from_parts(0, 4197507)) - // Standard Error: 11 - .saturating_add(Weight::from_parts(956, 0).saturating_mul(l.into())) + // Measured: `171 + l * (2 ±0)` + // Estimated: `4195793 + l * (2 ±0)` + // Minimum execution time: 2_149_000 picoseconds. + Weight::from_parts(2_256_000, 4195793) + // Standard Error: 6 + .saturating_add(Weight::from_parts(677, 0).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(Weight::from_parts(0, 2).saturating_mul(l.into())) } @@ -789,13 +748,12 @@ impl WeightInfo for () { /// The range of component `l` is `[0, 4194304]`. fn measured_mixed_storage_double_value_read_linear_size(l: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `235 + l * (2 ±0)` - // Estimated: `4197507 + l * (2 ±0)` - // Minimum execution time: 2_375 nanoseconds. - Weight::from_parts(2_420_000, 0) - .saturating_add(Weight::from_parts(0, 4197507)) - // Standard Error: 9 - .saturating_add(Weight::from_parts(914, 0).saturating_mul(l.into())) + // Measured: `171 + l * (2 ±0)` + // Estimated: `4195793 + l * (2 ±0)` + // Minimum execution time: 2_254_000 picoseconds. + Weight::from_parts(2_319_000, 4195793) + // Standard Error: 5 + .saturating_add(Weight::from_parts(664, 0).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(Weight::from_parts(0, 2).saturating_mul(l.into())) } @@ -806,15 +764,14 @@ impl WeightInfo for () { /// The range of component `i` is `[0, 1000]`. fn storage_map_unbounded_both_measured_read(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `293 + i * (8 ±0)` - // Estimated: `7504 + i * (16 ±0)` - // Minimum execution time: 3_305 nanoseconds. - Weight::from_parts(3_689_335, 0) - .saturating_add(Weight::from_parts(0, 7504)) - // Standard Error: 29 - .saturating_add(Weight::from_parts(638, 0).saturating_mul(i.into())) + // Measured: `229 + i * (8 ±0)` + // Estimated: `3693 + i * (8 ±0)` + // Minimum execution time: 3_071_000 picoseconds. + Weight::from_parts(3_487_712, 3693) + // Standard Error: 26 + .saturating_add(Weight::from_parts(748, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(Weight::from_parts(0, 16).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(0, 8).saturating_mul(i.into())) } /// Storage: Pov Map1M (r:1 w:0) /// Proof: Pov Map1M (max_values: Some(1000000), max_size: Some(36), added: 2511, mode: MaxEncodedLen) @@ -823,13 +780,12 @@ impl WeightInfo for () { /// The range of component `i` is `[0, 1000]`. fn storage_map_partial_unbounded_read(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `260 + i * (4 ±0)` - // Estimated: `7223 + i * (4 ±0)` - // Minimum execution time: 3_469 nanoseconds. - Weight::from_parts(3_878_896, 0) - .saturating_add(Weight::from_parts(0, 7223)) - // Standard Error: 33 - .saturating_add(Weight::from_parts(356, 0).saturating_mul(i.into())) + // Measured: `228 + i * (4 ±0)` + // Estimated: `3692 + i * (4 ±0)` + // Minimum execution time: 3_150_000 picoseconds. + Weight::from_parts(3_582_963, 3692) + // Standard Error: 18 + .saturating_add(Weight::from_parts(380, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(Weight::from_parts(0, 4).saturating_mul(i.into())) } @@ -840,13 +796,12 @@ impl WeightInfo for () { /// The range of component `i` is `[0, 1000]`. fn storage_map_partial_unbounded_ignored_read(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `260 + i * (4 ±0)` - // Estimated: `3758 + i * (4 ±0)` - // Minimum execution time: 3_442 nanoseconds. - Weight::from_parts(3_881_051, 0) - .saturating_add(Weight::from_parts(0, 3758)) - // Standard Error: 35 - .saturating_add(Weight::from_parts(384, 0).saturating_mul(i.into())) + // Measured: `228 + i * (4 ±0)` + // Estimated: `3501 + i * (4 ±0)` + // Minimum execution time: 3_092_000 picoseconds. + Weight::from_parts(3_595_328, 3501) + // Standard Error: 20 + .saturating_add(Weight::from_parts(243, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(Weight::from_parts(0, 4).saturating_mul(i.into())) } @@ -854,16 +809,24 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_619 nanoseconds. - Weight::from_parts(1_728_000, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Minimum execution time: 1_705_000 picoseconds. + Weight::from_parts(1_818_000, 0) } fn noop() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 546 nanoseconds. - Weight::from_parts(640_000, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Minimum execution time: 533_000 picoseconds. + Weight::from_parts(587_000, 0) + } + /// Storage: Pov UnboundedMapTwox (r:65001 w:0) + /// Proof Skipped: Pov UnboundedMapTwox (max_values: None, max_size: None, mode: Measured) + fn storage_iteration() -> Weight { + // Proof Size summary in bytes: + // Measured: `17985289` + // Estimated: `178863754` + // Minimum execution time: 118_753_057_000 picoseconds. + Weight::from_parts(121_396_503_000, 178863754) + .saturating_add(RocksDbWeight::get().reads(65001_u64)) } } diff --git a/frame/benchmarking/src/weights.rs b/frame/benchmarking/src/weights.rs index aa24b99ace2a7..25e2702f702d1 100644 --- a/frame/benchmarking/src/weights.rs +++ b/frame/benchmarking/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for frame_benchmarking //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,9 +31,6 @@ // --steps=50 // --repeat=20 // --pallet=frame_benchmarking -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -67,49 +64,49 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 205_000 picoseconds. - Weight::from_parts(263_483, 0) + // Minimum execution time: 173_000 picoseconds. + Weight::from_parts(205_895, 0) } /// The range of component `i` is `[0, 1000000]`. fn subtraction(_i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 186_000 picoseconds. - Weight::from_parts(257_588, 0) + // Minimum execution time: 180_000 picoseconds. + Weight::from_parts(206_967, 0) } /// The range of component `i` is `[0, 1000000]`. fn multiplication(_i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 192_000 picoseconds. - Weight::from_parts(264_271, 0) + // Minimum execution time: 174_000 picoseconds. + Weight::from_parts(214_304, 0) } /// The range of component `i` is `[0, 1000000]`. fn division(_i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 191_000 picoseconds. - Weight::from_parts(250_785, 0) + // Minimum execution time: 173_000 picoseconds. + Weight::from_parts(207_804, 0) } fn hashing() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 21_405_207_000 picoseconds. - Weight::from_parts(21_534_243_000, 0) + // Minimum execution time: 21_173_551_000 picoseconds. + Weight::from_parts(21_256_886_000, 0) } /// The range of component `i` is `[0, 100]`. fn sr25519_verification(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 255_000 picoseconds. - Weight::from_parts(271_000, 0) - // Standard Error: 12_788 - .saturating_add(Weight::from_parts(47_469_387, 0).saturating_mul(i.into())) + // Minimum execution time: 208_000 picoseconds. + Weight::from_parts(1_227_077, 0) + // Standard Error: 9_390 + .saturating_add(Weight::from_parts(47_152_841, 0).saturating_mul(i.into())) } } @@ -120,48 +117,48 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 205_000 picoseconds. - Weight::from_parts(263_483, 0) + // Minimum execution time: 173_000 picoseconds. + Weight::from_parts(205_895, 0) } /// The range of component `i` is `[0, 1000000]`. fn subtraction(_i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 186_000 picoseconds. - Weight::from_parts(257_588, 0) + // Minimum execution time: 180_000 picoseconds. + Weight::from_parts(206_967, 0) } /// The range of component `i` is `[0, 1000000]`. fn multiplication(_i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 192_000 picoseconds. - Weight::from_parts(264_271, 0) + // Minimum execution time: 174_000 picoseconds. + Weight::from_parts(214_304, 0) } /// The range of component `i` is `[0, 1000000]`. fn division(_i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 191_000 picoseconds. - Weight::from_parts(250_785, 0) + // Minimum execution time: 173_000 picoseconds. + Weight::from_parts(207_804, 0) } fn hashing() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 21_405_207_000 picoseconds. - Weight::from_parts(21_534_243_000, 0) + // Minimum execution time: 21_173_551_000 picoseconds. + Weight::from_parts(21_256_886_000, 0) } /// The range of component `i` is `[0, 100]`. fn sr25519_verification(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 255_000 picoseconds. - Weight::from_parts(271_000, 0) - // Standard Error: 12_788 - .saturating_add(Weight::from_parts(47_469_387, 0).saturating_mul(i.into())) + // Minimum execution time: 208_000 picoseconds. + Weight::from_parts(1_227_077, 0) + // Standard Error: 9_390 + .saturating_add(Weight::from_parts(47_152_841, 0).saturating_mul(i.into())) } } diff --git a/frame/bounties/src/weights.rs b/frame/bounties/src/weights.rs index b0459fee62eb1..5a84adf08210c 100644 --- a/frame/bounties/src/weights.rs +++ b/frame/bounties/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_bounties //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,9 +31,6 @@ // --steps=50 // --repeat=20 // --pallet=pallet_bounties -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -76,12 +73,14 @@ impl WeightInfo for SubstrateWeight { /// Storage: Bounties Bounties (r:0 w:1) /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) /// The range of component `d` is `[0, 300]`. - fn propose_bounty(_d: u32, ) -> Weight { + fn propose_bounty(d: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `276` - // Estimated: `5082` - // Minimum execution time: 26_271_000 picoseconds. - Weight::from_parts(28_048_901, 5082) + // Estimated: `3593` + // Minimum execution time: 30_793_000 picoseconds. + Weight::from_parts(31_509_544, 3593) + // Standard Error: 168 + .saturating_add(Weight::from_parts(2_219, 0).saturating_mul(d.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -92,9 +91,9 @@ impl WeightInfo for SubstrateWeight { fn approve_bounty() -> Weight { // Proof Size summary in bytes: // Measured: `368` - // Estimated: `5529` - // Minimum execution time: 12_573_000 picoseconds. - Weight::from_parts(12_827_000, 5529) + // Estimated: `3642` + // Minimum execution time: 12_471_000 picoseconds. + Weight::from_parts(12_677_000, 3642) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -104,8 +103,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `388` // Estimated: `3642` - // Minimum execution time: 10_555_000 picoseconds. - Weight::from_parts(10_857_000, 3642) + // Minimum execution time: 10_560_000 picoseconds. + Weight::from_parts(10_744_000, 3642) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -116,9 +115,9 @@ impl WeightInfo for SubstrateWeight { fn unassign_curator() -> Weight { // Proof Size summary in bytes: // Measured: `564` - // Estimated: `7235` - // Minimum execution time: 26_003_000 picoseconds. - Weight::from_parts(26_291_000, 7235) + // Estimated: `3642` + // Minimum execution time: 30_980_000 picoseconds. + Weight::from_parts(31_354_000, 3642) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -129,9 +128,9 @@ impl WeightInfo for SubstrateWeight { fn accept_curator() -> Weight { // Proof Size summary in bytes: // Measured: `560` - // Estimated: `7235` - // Minimum execution time: 24_371_000 picoseconds. - Weight::from_parts(24_781_000, 7235) + // Estimated: `3642` + // Minimum execution time: 29_257_000 picoseconds. + Weight::from_parts(29_656_000, 3642) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -142,9 +141,9 @@ impl WeightInfo for SubstrateWeight { fn award_bounty() -> Weight { // Proof Size summary in bytes: // Measured: `538` - // Estimated: `7123` - // Minimum execution time: 20_688_000 picoseconds. - Weight::from_parts(20_909_000, 7123) + // Estimated: `3642` + // Minimum execution time: 20_662_000 picoseconds. + Weight::from_parts(20_956_000, 3642) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -159,9 +158,9 @@ impl WeightInfo for SubstrateWeight { fn claim_bounty() -> Weight { // Proof Size summary in bytes: // Measured: `902` - // Estimated: `15934` - // Minimum execution time: 78_933_000 picoseconds. - Weight::from_parts(79_884_000, 15934) + // Estimated: `8799` + // Minimum execution time: 119_287_000 picoseconds. + Weight::from_parts(121_468_000, 8799) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -176,9 +175,9 @@ impl WeightInfo for SubstrateWeight { fn close_bounty_proposed() -> Weight { // Proof Size summary in bytes: // Measured: `582` - // Estimated: `10716` - // Minimum execution time: 32_332_000 picoseconds. - Weight::from_parts(32_833_000, 10716) + // Estimated: `3642` + // Minimum execution time: 37_759_000 picoseconds. + Weight::from_parts(38_185_000, 3642) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -193,9 +192,9 @@ impl WeightInfo for SubstrateWeight { fn close_bounty_active() -> Weight { // Proof Size summary in bytes: // Measured: `818` - // Estimated: `13319` - // Minimum execution time: 55_686_000 picoseconds. - Weight::from_parts(56_271_000, 13319) + // Estimated: `6196` + // Minimum execution time: 80_332_000 picoseconds. + Weight::from_parts(81_328_000, 6196) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -205,8 +204,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `424` // Estimated: `3642` - // Minimum execution time: 16_414_000 picoseconds. - Weight::from_parts(16_681_000, 3642) + // Minimum execution time: 16_301_000 picoseconds. + Weight::from_parts(16_611_000, 3642) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -220,16 +219,16 @@ impl WeightInfo for SubstrateWeight { fn spend_funds(b: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `4 + b * (297 ±0)` - // Estimated: `3867 + b * (7858 ±0)` - // Minimum execution time: 5_398_000 picoseconds. - Weight::from_parts(4_478_947, 3867) - // Standard Error: 41_860 - .saturating_add(Weight::from_parts(33_082_606, 0).saturating_mul(b.into())) + // Estimated: `1887 + b * (5206 ±0)` + // Minimum execution time: 5_430_000 picoseconds. + Weight::from_parts(4_463_976, 1887) + // Standard Error: 43_695 + .saturating_add(Weight::from_parts(39_370_113, 0).saturating_mul(b.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(b.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(b.into()))) - .saturating_add(Weight::from_parts(0, 7858).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(0, 5206).saturating_mul(b.into())) } } @@ -244,12 +243,14 @@ impl WeightInfo for () { /// Storage: Bounties Bounties (r:0 w:1) /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) /// The range of component `d` is `[0, 300]`. - fn propose_bounty(_d: u32, ) -> Weight { + fn propose_bounty(d: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `276` - // Estimated: `5082` - // Minimum execution time: 26_271_000 picoseconds. - Weight::from_parts(28_048_901, 5082) + // Estimated: `3593` + // Minimum execution time: 30_793_000 picoseconds. + Weight::from_parts(31_509_544, 3593) + // Standard Error: 168 + .saturating_add(Weight::from_parts(2_219, 0).saturating_mul(d.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -260,9 +261,9 @@ impl WeightInfo for () { fn approve_bounty() -> Weight { // Proof Size summary in bytes: // Measured: `368` - // Estimated: `5529` - // Minimum execution time: 12_573_000 picoseconds. - Weight::from_parts(12_827_000, 5529) + // Estimated: `3642` + // Minimum execution time: 12_471_000 picoseconds. + Weight::from_parts(12_677_000, 3642) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -272,8 +273,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `388` // Estimated: `3642` - // Minimum execution time: 10_555_000 picoseconds. - Weight::from_parts(10_857_000, 3642) + // Minimum execution time: 10_560_000 picoseconds. + Weight::from_parts(10_744_000, 3642) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -284,9 +285,9 @@ impl WeightInfo for () { fn unassign_curator() -> Weight { // Proof Size summary in bytes: // Measured: `564` - // Estimated: `7235` - // Minimum execution time: 26_003_000 picoseconds. - Weight::from_parts(26_291_000, 7235) + // Estimated: `3642` + // Minimum execution time: 30_980_000 picoseconds. + Weight::from_parts(31_354_000, 3642) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -297,9 +298,9 @@ impl WeightInfo for () { fn accept_curator() -> Weight { // Proof Size summary in bytes: // Measured: `560` - // Estimated: `7235` - // Minimum execution time: 24_371_000 picoseconds. - Weight::from_parts(24_781_000, 7235) + // Estimated: `3642` + // Minimum execution time: 29_257_000 picoseconds. + Weight::from_parts(29_656_000, 3642) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -310,9 +311,9 @@ impl WeightInfo for () { fn award_bounty() -> Weight { // Proof Size summary in bytes: // Measured: `538` - // Estimated: `7123` - // Minimum execution time: 20_688_000 picoseconds. - Weight::from_parts(20_909_000, 7123) + // Estimated: `3642` + // Minimum execution time: 20_662_000 picoseconds. + Weight::from_parts(20_956_000, 3642) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -327,9 +328,9 @@ impl WeightInfo for () { fn claim_bounty() -> Weight { // Proof Size summary in bytes: // Measured: `902` - // Estimated: `15934` - // Minimum execution time: 78_933_000 picoseconds. - Weight::from_parts(79_884_000, 15934) + // Estimated: `8799` + // Minimum execution time: 119_287_000 picoseconds. + Weight::from_parts(121_468_000, 8799) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -344,9 +345,9 @@ impl WeightInfo for () { fn close_bounty_proposed() -> Weight { // Proof Size summary in bytes: // Measured: `582` - // Estimated: `10716` - // Minimum execution time: 32_332_000 picoseconds. - Weight::from_parts(32_833_000, 10716) + // Estimated: `3642` + // Minimum execution time: 37_759_000 picoseconds. + Weight::from_parts(38_185_000, 3642) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -361,9 +362,9 @@ impl WeightInfo for () { fn close_bounty_active() -> Weight { // Proof Size summary in bytes: // Measured: `818` - // Estimated: `13319` - // Minimum execution time: 55_686_000 picoseconds. - Weight::from_parts(56_271_000, 13319) + // Estimated: `6196` + // Minimum execution time: 80_332_000 picoseconds. + Weight::from_parts(81_328_000, 6196) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -373,8 +374,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `424` // Estimated: `3642` - // Minimum execution time: 16_414_000 picoseconds. - Weight::from_parts(16_681_000, 3642) + // Minimum execution time: 16_301_000 picoseconds. + Weight::from_parts(16_611_000, 3642) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -388,15 +389,15 @@ impl WeightInfo for () { fn spend_funds(b: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `4 + b * (297 ±0)` - // Estimated: `3867 + b * (7858 ±0)` - // Minimum execution time: 5_398_000 picoseconds. - Weight::from_parts(4_478_947, 3867) - // Standard Error: 41_860 - .saturating_add(Weight::from_parts(33_082_606, 0).saturating_mul(b.into())) + // Estimated: `1887 + b * (5206 ±0)` + // Minimum execution time: 5_430_000 picoseconds. + Weight::from_parts(4_463_976, 1887) + // Standard Error: 43_695 + .saturating_add(Weight::from_parts(39_370_113, 0).saturating_mul(b.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(b.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(b.into()))) - .saturating_add(Weight::from_parts(0, 7858).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(0, 5206).saturating_mul(b.into())) } } diff --git a/frame/child-bounties/src/weights.rs b/frame/child-bounties/src/weights.rs index 92be77c49dc9c..be30e80a19f27 100644 --- a/frame/child-bounties/src/weights.rs +++ b/frame/child-bounties/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_child_bounties //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,9 +31,6 @@ // --steps=50 // --repeat=20 // --pallet=pallet_child_bounties -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -77,14 +74,12 @@ impl WeightInfo for SubstrateWeight { /// Storage: ChildBounties ChildBounties (r:0 w:1) /// Proof: ChildBounties ChildBounties (max_values: None, max_size: Some(145), added: 2620, mode: MaxEncodedLen) /// The range of component `d` is `[0, 300]`. - fn add_child_bounty(d: u32, ) -> Weight { + fn add_child_bounty(_d: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `678` - // Estimated: `14808` - // Minimum execution time: 54_017_000 picoseconds. - Weight::from_parts(55_142_443, 14808) - // Standard Error: 310 - .saturating_add(Weight::from_parts(1_199, 0).saturating_mul(d.into())) + // Estimated: `6196` + // Minimum execution time: 69_784_000 picoseconds. + Weight::from_parts(71_225_354, 6196) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -97,9 +92,9 @@ impl WeightInfo for SubstrateWeight { fn propose_curator() -> Weight { // Proof Size summary in bytes: // Measured: `732` - // Estimated: `10745` - // Minimum execution time: 19_222_000 picoseconds. - Weight::from_parts(19_446_000, 10745) + // Estimated: `3642` + // Minimum execution time: 19_008_000 picoseconds. + Weight::from_parts(19_219_000, 3642) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -112,9 +107,9 @@ impl WeightInfo for SubstrateWeight { fn accept_curator() -> Weight { // Proof Size summary in bytes: // Measured: `878` - // Estimated: `10845` - // Minimum execution time: 31_049_000 picoseconds. - Weight::from_parts(31_546_000, 10845) + // Estimated: `3642` + // Minimum execution time: 35_457_000 picoseconds. + Weight::from_parts(36_088_000, 3642) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -127,9 +122,9 @@ impl WeightInfo for SubstrateWeight { fn unassign_curator() -> Weight { // Proof Size summary in bytes: // Measured: `878` - // Estimated: `10845` - // Minimum execution time: 33_860_000 picoseconds. - Weight::from_parts(34_897_000, 10845) + // Estimated: `3642` + // Minimum execution time: 38_244_000 picoseconds. + Weight::from_parts(38_611_000, 3642) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -140,9 +135,9 @@ impl WeightInfo for SubstrateWeight { fn award_child_bounty() -> Weight { // Proof Size summary in bytes: // Measured: `775` - // Estimated: `7252` - // Minimum execution time: 23_178_000 picoseconds. - Weight::from_parts(23_412_000, 7252) + // Estimated: `3642` + // Minimum execution time: 22_762_000 picoseconds. + Weight::from_parts(23_249_000, 3642) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -157,9 +152,9 @@ impl WeightInfo for SubstrateWeight { fn claim_child_bounty() -> Weight { // Proof Size summary in bytes: // Measured: `648` - // Estimated: `15890` - // Minimum execution time: 76_189_000 picoseconds. - Weight::from_parts(76_770_000, 15890) + // Estimated: `8799` + // Minimum execution time: 112_019_000 picoseconds. + Weight::from_parts(113_190_000, 8799) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -178,9 +173,9 @@ impl WeightInfo for SubstrateWeight { fn close_child_bounty_added() -> Weight { // Proof Size summary in bytes: // Measured: `978` - // Estimated: `20422` - // Minimum execution time: 55_161_000 picoseconds. - Weight::from_parts(55_578_000, 20422) + // Estimated: `6196` + // Minimum execution time: 72_477_000 picoseconds. + Weight::from_parts(73_573_000, 6196) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -199,9 +194,9 @@ impl WeightInfo for SubstrateWeight { fn close_child_bounty_active() -> Weight { // Proof Size summary in bytes: // Measured: `1165` - // Estimated: `23025` - // Minimum execution time: 67_815_000 picoseconds. - Weight::from_parts(68_620_000, 23025) + // Estimated: `8799` + // Minimum execution time: 91_049_000 picoseconds. + Weight::from_parts(91_874_000, 8799) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } @@ -222,14 +217,12 @@ impl WeightInfo for () { /// Storage: ChildBounties ChildBounties (r:0 w:1) /// Proof: ChildBounties ChildBounties (max_values: None, max_size: Some(145), added: 2620, mode: MaxEncodedLen) /// The range of component `d` is `[0, 300]`. - fn add_child_bounty(d: u32, ) -> Weight { + fn add_child_bounty(_d: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `678` - // Estimated: `14808` - // Minimum execution time: 54_017_000 picoseconds. - Weight::from_parts(55_142_443, 14808) - // Standard Error: 310 - .saturating_add(Weight::from_parts(1_199, 0).saturating_mul(d.into())) + // Estimated: `6196` + // Minimum execution time: 69_784_000 picoseconds. + Weight::from_parts(71_225_354, 6196) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -242,9 +235,9 @@ impl WeightInfo for () { fn propose_curator() -> Weight { // Proof Size summary in bytes: // Measured: `732` - // Estimated: `10745` - // Minimum execution time: 19_222_000 picoseconds. - Weight::from_parts(19_446_000, 10745) + // Estimated: `3642` + // Minimum execution time: 19_008_000 picoseconds. + Weight::from_parts(19_219_000, 3642) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -257,9 +250,9 @@ impl WeightInfo for () { fn accept_curator() -> Weight { // Proof Size summary in bytes: // Measured: `878` - // Estimated: `10845` - // Minimum execution time: 31_049_000 picoseconds. - Weight::from_parts(31_546_000, 10845) + // Estimated: `3642` + // Minimum execution time: 35_457_000 picoseconds. + Weight::from_parts(36_088_000, 3642) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -272,9 +265,9 @@ impl WeightInfo for () { fn unassign_curator() -> Weight { // Proof Size summary in bytes: // Measured: `878` - // Estimated: `10845` - // Minimum execution time: 33_860_000 picoseconds. - Weight::from_parts(34_897_000, 10845) + // Estimated: `3642` + // Minimum execution time: 38_244_000 picoseconds. + Weight::from_parts(38_611_000, 3642) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -285,9 +278,9 @@ impl WeightInfo for () { fn award_child_bounty() -> Weight { // Proof Size summary in bytes: // Measured: `775` - // Estimated: `7252` - // Minimum execution time: 23_178_000 picoseconds. - Weight::from_parts(23_412_000, 7252) + // Estimated: `3642` + // Minimum execution time: 22_762_000 picoseconds. + Weight::from_parts(23_249_000, 3642) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -302,9 +295,9 @@ impl WeightInfo for () { fn claim_child_bounty() -> Weight { // Proof Size summary in bytes: // Measured: `648` - // Estimated: `15890` - // Minimum execution time: 76_189_000 picoseconds. - Weight::from_parts(76_770_000, 15890) + // Estimated: `8799` + // Minimum execution time: 112_019_000 picoseconds. + Weight::from_parts(113_190_000, 8799) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -323,9 +316,9 @@ impl WeightInfo for () { fn close_child_bounty_added() -> Weight { // Proof Size summary in bytes: // Measured: `978` - // Estimated: `20422` - // Minimum execution time: 55_161_000 picoseconds. - Weight::from_parts(55_578_000, 20422) + // Estimated: `6196` + // Minimum execution time: 72_477_000 picoseconds. + Weight::from_parts(73_573_000, 6196) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -344,9 +337,9 @@ impl WeightInfo for () { fn close_child_bounty_active() -> Weight { // Proof Size summary in bytes: // Measured: `1165` - // Estimated: `23025` - // Minimum execution time: 67_815_000 picoseconds. - Weight::from_parts(68_620_000, 23025) + // Estimated: `8799` + // Minimum execution time: 91_049_000 picoseconds. + Weight::from_parts(91_874_000, 8799) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } diff --git a/frame/collective/src/weights.rs b/frame/collective/src/weights.rs index 2199c02052009..bf739daca0931 100644 --- a/frame/collective/src/weights.rs +++ b/frame/collective/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_collective //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,9 +31,6 @@ // --steps=50 // --repeat=20 // --pallet=pallet_collective -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -80,19 +77,19 @@ impl WeightInfo for SubstrateWeight { fn set_members(m: u32, _n: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + m * (3232 ±0) + p * (3190 ±0)` - // Estimated: `19428 + m * (7799 ±24) + p * (10110 ±24)` - // Minimum execution time: 18_772_000 picoseconds. - Weight::from_parts(18_931_000, 19428) - // Standard Error: 65_247 - .saturating_add(Weight::from_parts(5_050_136, 0).saturating_mul(m.into())) - // Standard Error: 65_247 - .saturating_add(Weight::from_parts(8_235_069, 0).saturating_mul(p.into())) + // Estimated: `15861 + m * (1967 ±23) + p * (4332 ±23)` + // Minimum execution time: 19_398_000 picoseconds. + Weight::from_parts(19_542_000, 15861) + // Standard Error: 71_395 + .saturating_add(Weight::from_parts(5_630_062, 0).saturating_mul(m.into())) + // Standard Error: 71_395 + .saturating_add(Weight::from_parts(8_634_133, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(p.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(p.into()))) - .saturating_add(Weight::from_parts(0, 7799).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 10110).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 1967).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 4332).saturating_mul(p.into())) } /// Storage: Council Members (r:1 w:0) /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) @@ -102,12 +99,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `202 + m * (32 ±0)` // Estimated: `1688 + m * (32 ±0)` - // Minimum execution time: 17_741_000 picoseconds. - Weight::from_parts(17_580_031, 1688) - // Standard Error: 113 - .saturating_add(Weight::from_parts(941, 0).saturating_mul(b.into())) - // Standard Error: 1_170 - .saturating_add(Weight::from_parts(17_329, 0).saturating_mul(m.into())) + // Minimum execution time: 17_579_000 picoseconds. + Weight::from_parts(16_874_624, 1688) + // Standard Error: 34 + .saturating_add(Weight::from_parts(1_617, 0).saturating_mul(b.into())) + // Standard Error: 353 + .saturating_add(Weight::from_parts(19_759, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(Weight::from_parts(0, 32).saturating_mul(m.into())) } @@ -120,15 +117,15 @@ impl WeightInfo for SubstrateWeight { fn propose_execute(b: u32, m: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `202 + m * (32 ±0)` - // Estimated: `5356 + m * (64 ±0)` - // Minimum execution time: 20_214_000 picoseconds. - Weight::from_parts(19_508_816, 5356) - // Standard Error: 46 - .saturating_add(Weight::from_parts(1_646, 0).saturating_mul(b.into())) - // Standard Error: 475 - .saturating_add(Weight::from_parts(27_145, 0).saturating_mul(m.into())) + // Estimated: `3668 + m * (32 ±0)` + // Minimum execution time: 20_339_000 picoseconds. + Weight::from_parts(19_534_549, 3668) + // Standard Error: 45 + .saturating_add(Weight::from_parts(1_636, 0).saturating_mul(b.into())) + // Standard Error: 469 + .saturating_add(Weight::from_parts(28_178, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 32).saturating_mul(m.into())) } /// Storage: Council Members (r:1 w:0) /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) @@ -146,19 +143,19 @@ impl WeightInfo for SubstrateWeight { fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `492 + m * (32 ±0) + p * (36 ±0)` - // Estimated: `10015 + m * (165 ±0) + p * (180 ±0)` - // Minimum execution time: 27_872_000 picoseconds. - Weight::from_parts(28_010_227, 10015) - // Standard Error: 90 - .saturating_add(Weight::from_parts(2_643, 0).saturating_mul(b.into())) - // Standard Error: 944 - .saturating_add(Weight::from_parts(17_897, 0).saturating_mul(m.into())) - // Standard Error: 932 - .saturating_add(Weight::from_parts(122_368, 0).saturating_mul(p.into())) + // Estimated: `3884 + m * (33 ±0) + p * (36 ±0)` + // Minimum execution time: 27_793_000 picoseconds. + Weight::from_parts(28_095_462, 3884) + // Standard Error: 82 + .saturating_add(Weight::from_parts(2_646, 0).saturating_mul(b.into())) + // Standard Error: 861 + .saturating_add(Weight::from_parts(22_332, 0).saturating_mul(m.into())) + // Standard Error: 850 + .saturating_add(Weight::from_parts(121_560, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) - .saturating_add(Weight::from_parts(0, 165).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 180).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 33).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) } /// Storage: Council Members (r:1 w:0) /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) @@ -168,14 +165,14 @@ impl WeightInfo for SubstrateWeight { fn vote(m: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `941 + m * (64 ±0)` - // Estimated: `6830 + m * (128 ±0)` - // Minimum execution time: 22_518_000 picoseconds. - Weight::from_parts(23_281_512, 6830) - // Standard Error: 647 - .saturating_add(Weight::from_parts(53_974, 0).saturating_mul(m.into())) + // Estimated: `4405 + m * (64 ±0)` + // Minimum execution time: 23_096_000 picoseconds. + Weight::from_parts(23_793_304, 4405) + // Standard Error: 675 + .saturating_add(Weight::from_parts(51_741, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) - .saturating_add(Weight::from_parts(0, 128).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) } /// Storage: Council Voting (r:1 w:1) /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) @@ -190,17 +187,17 @@ impl WeightInfo for SubstrateWeight { fn close_early_disapproved(m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `530 + m * (64 ±0) + p * (36 ±0)` - // Estimated: `8475 + m * (260 ±0) + p * (144 ±0)` - // Minimum execution time: 29_020_000 picoseconds. - Weight::from_parts(29_009_937, 8475) - // Standard Error: 809 - .saturating_add(Weight::from_parts(31_952, 0).saturating_mul(m.into())) - // Standard Error: 789 - .saturating_add(Weight::from_parts(124_282, 0).saturating_mul(p.into())) + // Estimated: `3975 + m * (65 ±0) + p * (36 ±0)` + // Minimum execution time: 29_635_000 picoseconds. + Weight::from_parts(29_574_124, 3975) + // Standard Error: 755 + .saturating_add(Weight::from_parts(29_126, 0).saturating_mul(m.into())) + // Standard Error: 737 + .saturating_add(Weight::from_parts(123_438, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 260).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 144).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 65).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) } /// Storage: Council Voting (r:1 w:1) /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) @@ -216,20 +213,20 @@ impl WeightInfo for SubstrateWeight { fn close_early_approved(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `832 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` - // Estimated: `12636 + b * (4 ±0) + m * (264 ±0) + p * (160 ±0)` - // Minimum execution time: 41_541_000 picoseconds. - Weight::from_parts(43_640_322, 12636) - // Standard Error: 104 - .saturating_add(Weight::from_parts(2_178, 0).saturating_mul(b.into())) - // Standard Error: 1_101 - .saturating_add(Weight::from_parts(20_512, 0).saturating_mul(m.into())) - // Standard Error: 1_073 - .saturating_add(Weight::from_parts(133_112, 0).saturating_mul(p.into())) + // Estimated: `4149 + b * (1 ±0) + m * (66 ±0) + p * (40 ±0)` + // Minimum execution time: 41_934_000 picoseconds. + Weight::from_parts(44_022_379, 4149) + // Standard Error: 105 + .saturating_add(Weight::from_parts(2_266, 0).saturating_mul(b.into())) + // Standard Error: 1_112 + .saturating_add(Weight::from_parts(18_074, 0).saturating_mul(m.into())) + // Standard Error: 1_084 + .saturating_add(Weight::from_parts(132_405, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 4).saturating_mul(b.into())) - .saturating_add(Weight::from_parts(0, 264).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 160).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 1).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(0, 66).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 40).saturating_mul(p.into())) } /// Storage: Council Voting (r:1 w:1) /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) @@ -246,17 +243,17 @@ impl WeightInfo for SubstrateWeight { fn close_disapproved(m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `550 + m * (64 ±0) + p * (36 ±0)` - // Estimated: `10570 + m * (325 ±0) + p * (180 ±0)` - // Minimum execution time: 32_773_000 picoseconds. - Weight::from_parts(33_031_550, 10570) - // Standard Error: 1_205 - .saturating_add(Weight::from_parts(26_143, 0).saturating_mul(m.into())) - // Standard Error: 1_175 - .saturating_add(Weight::from_parts(137_503, 0).saturating_mul(p.into())) + // Estimated: `3995 + m * (65 ±0) + p * (36 ±0)` + // Minimum execution time: 33_146_000 picoseconds. + Weight::from_parts(31_957_128, 3995) + // Standard Error: 2_321 + .saturating_add(Weight::from_parts(31_272, 0).saturating_mul(m.into())) + // Standard Error: 2_264 + .saturating_add(Weight::from_parts(156_129, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 325).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 180).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 65).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) } /// Storage: Council Voting (r:1 w:1) /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) @@ -274,20 +271,20 @@ impl WeightInfo for SubstrateWeight { fn close_approved(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `852 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` - // Estimated: `14905 + b * (5 ±0) + m * (330 ±0) + p * (200 ±0)` - // Minimum execution time: 44_855_000 picoseconds. - Weight::from_parts(47_307_460, 14905) + // Estimated: `4169 + b * (1 ±0) + m * (66 ±0) + p * (40 ±0)` + // Minimum execution time: 44_278_000 picoseconds. + Weight::from_parts(46_039_907, 4169) // Standard Error: 100 - .saturating_add(Weight::from_parts(1_536, 0).saturating_mul(b.into())) - // Standard Error: 1_065 - .saturating_add(Weight::from_parts(20_549, 0).saturating_mul(m.into())) - // Standard Error: 1_038 - .saturating_add(Weight::from_parts(133_143, 0).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(2_257, 0).saturating_mul(b.into())) + // Standard Error: 1_062 + .saturating_add(Weight::from_parts(25_055, 0).saturating_mul(m.into())) + // Standard Error: 1_035 + .saturating_add(Weight::from_parts(136_282, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 5).saturating_mul(b.into())) - .saturating_add(Weight::from_parts(0, 330).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 200).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 1).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(0, 66).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 40).saturating_mul(p.into())) } /// Storage: Council Proposals (r:1 w:1) /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) @@ -299,14 +296,14 @@ impl WeightInfo for SubstrateWeight { fn disapprove_proposal(p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `359 + p * (32 ±0)` - // Estimated: `2562 + p * (96 ±0)` - // Minimum execution time: 16_420_000 picoseconds. - Weight::from_parts(18_236_525, 2562) - // Standard Error: 894 - .saturating_add(Weight::from_parts(115_590, 0).saturating_mul(p.into())) + // Estimated: `1844 + p * (32 ±0)` + // Minimum execution time: 16_500_000 picoseconds. + Weight::from_parts(18_376_538, 1844) + // Standard Error: 755 + .saturating_add(Weight::from_parts(113_189, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 96).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 32).saturating_mul(p.into())) } } @@ -326,19 +323,19 @@ impl WeightInfo for () { fn set_members(m: u32, _n: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + m * (3232 ±0) + p * (3190 ±0)` - // Estimated: `19428 + m * (7799 ±24) + p * (10110 ±24)` - // Minimum execution time: 18_772_000 picoseconds. - Weight::from_parts(18_931_000, 19428) - // Standard Error: 65_247 - .saturating_add(Weight::from_parts(5_050_136, 0).saturating_mul(m.into())) - // Standard Error: 65_247 - .saturating_add(Weight::from_parts(8_235_069, 0).saturating_mul(p.into())) + // Estimated: `15861 + m * (1967 ±23) + p * (4332 ±23)` + // Minimum execution time: 19_398_000 picoseconds. + Weight::from_parts(19_542_000, 15861) + // Standard Error: 71_395 + .saturating_add(Weight::from_parts(5_630_062, 0).saturating_mul(m.into())) + // Standard Error: 71_395 + .saturating_add(Weight::from_parts(8_634_133, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(p.into()))) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(p.into()))) - .saturating_add(Weight::from_parts(0, 7799).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 10110).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 1967).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 4332).saturating_mul(p.into())) } /// Storage: Council Members (r:1 w:0) /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) @@ -348,12 +345,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `202 + m * (32 ±0)` // Estimated: `1688 + m * (32 ±0)` - // Minimum execution time: 17_741_000 picoseconds. - Weight::from_parts(17_580_031, 1688) - // Standard Error: 113 - .saturating_add(Weight::from_parts(941, 0).saturating_mul(b.into())) - // Standard Error: 1_170 - .saturating_add(Weight::from_parts(17_329, 0).saturating_mul(m.into())) + // Minimum execution time: 17_579_000 picoseconds. + Weight::from_parts(16_874_624, 1688) + // Standard Error: 34 + .saturating_add(Weight::from_parts(1_617, 0).saturating_mul(b.into())) + // Standard Error: 353 + .saturating_add(Weight::from_parts(19_759, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(Weight::from_parts(0, 32).saturating_mul(m.into())) } @@ -366,15 +363,15 @@ impl WeightInfo for () { fn propose_execute(b: u32, m: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `202 + m * (32 ±0)` - // Estimated: `5356 + m * (64 ±0)` - // Minimum execution time: 20_214_000 picoseconds. - Weight::from_parts(19_508_816, 5356) - // Standard Error: 46 - .saturating_add(Weight::from_parts(1_646, 0).saturating_mul(b.into())) - // Standard Error: 475 - .saturating_add(Weight::from_parts(27_145, 0).saturating_mul(m.into())) + // Estimated: `3668 + m * (32 ±0)` + // Minimum execution time: 20_339_000 picoseconds. + Weight::from_parts(19_534_549, 3668) + // Standard Error: 45 + .saturating_add(Weight::from_parts(1_636, 0).saturating_mul(b.into())) + // Standard Error: 469 + .saturating_add(Weight::from_parts(28_178, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 32).saturating_mul(m.into())) } /// Storage: Council Members (r:1 w:0) /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) @@ -392,19 +389,19 @@ impl WeightInfo for () { fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `492 + m * (32 ±0) + p * (36 ±0)` - // Estimated: `10015 + m * (165 ±0) + p * (180 ±0)` - // Minimum execution time: 27_872_000 picoseconds. - Weight::from_parts(28_010_227, 10015) - // Standard Error: 90 - .saturating_add(Weight::from_parts(2_643, 0).saturating_mul(b.into())) - // Standard Error: 944 - .saturating_add(Weight::from_parts(17_897, 0).saturating_mul(m.into())) - // Standard Error: 932 - .saturating_add(Weight::from_parts(122_368, 0).saturating_mul(p.into())) + // Estimated: `3884 + m * (33 ±0) + p * (36 ±0)` + // Minimum execution time: 27_793_000 picoseconds. + Weight::from_parts(28_095_462, 3884) + // Standard Error: 82 + .saturating_add(Weight::from_parts(2_646, 0).saturating_mul(b.into())) + // Standard Error: 861 + .saturating_add(Weight::from_parts(22_332, 0).saturating_mul(m.into())) + // Standard Error: 850 + .saturating_add(Weight::from_parts(121_560, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) - .saturating_add(Weight::from_parts(0, 165).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 180).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 33).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) } /// Storage: Council Members (r:1 w:0) /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) @@ -414,14 +411,14 @@ impl WeightInfo for () { fn vote(m: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `941 + m * (64 ±0)` - // Estimated: `6830 + m * (128 ±0)` - // Minimum execution time: 22_518_000 picoseconds. - Weight::from_parts(23_281_512, 6830) - // Standard Error: 647 - .saturating_add(Weight::from_parts(53_974, 0).saturating_mul(m.into())) + // Estimated: `4405 + m * (64 ±0)` + // Minimum execution time: 23_096_000 picoseconds. + Weight::from_parts(23_793_304, 4405) + // Standard Error: 675 + .saturating_add(Weight::from_parts(51_741, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) - .saturating_add(Weight::from_parts(0, 128).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) } /// Storage: Council Voting (r:1 w:1) /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) @@ -436,17 +433,17 @@ impl WeightInfo for () { fn close_early_disapproved(m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `530 + m * (64 ±0) + p * (36 ±0)` - // Estimated: `8475 + m * (260 ±0) + p * (144 ±0)` - // Minimum execution time: 29_020_000 picoseconds. - Weight::from_parts(29_009_937, 8475) - // Standard Error: 809 - .saturating_add(Weight::from_parts(31_952, 0).saturating_mul(m.into())) - // Standard Error: 789 - .saturating_add(Weight::from_parts(124_282, 0).saturating_mul(p.into())) + // Estimated: `3975 + m * (65 ±0) + p * (36 ±0)` + // Minimum execution time: 29_635_000 picoseconds. + Weight::from_parts(29_574_124, 3975) + // Standard Error: 755 + .saturating_add(Weight::from_parts(29_126, 0).saturating_mul(m.into())) + // Standard Error: 737 + .saturating_add(Weight::from_parts(123_438, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 260).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 144).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 65).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) } /// Storage: Council Voting (r:1 w:1) /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) @@ -462,20 +459,20 @@ impl WeightInfo for () { fn close_early_approved(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `832 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` - // Estimated: `12636 + b * (4 ±0) + m * (264 ±0) + p * (160 ±0)` - // Minimum execution time: 41_541_000 picoseconds. - Weight::from_parts(43_640_322, 12636) - // Standard Error: 104 - .saturating_add(Weight::from_parts(2_178, 0).saturating_mul(b.into())) - // Standard Error: 1_101 - .saturating_add(Weight::from_parts(20_512, 0).saturating_mul(m.into())) - // Standard Error: 1_073 - .saturating_add(Weight::from_parts(133_112, 0).saturating_mul(p.into())) + // Estimated: `4149 + b * (1 ±0) + m * (66 ±0) + p * (40 ±0)` + // Minimum execution time: 41_934_000 picoseconds. + Weight::from_parts(44_022_379, 4149) + // Standard Error: 105 + .saturating_add(Weight::from_parts(2_266, 0).saturating_mul(b.into())) + // Standard Error: 1_112 + .saturating_add(Weight::from_parts(18_074, 0).saturating_mul(m.into())) + // Standard Error: 1_084 + .saturating_add(Weight::from_parts(132_405, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 4).saturating_mul(b.into())) - .saturating_add(Weight::from_parts(0, 264).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 160).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 1).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(0, 66).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 40).saturating_mul(p.into())) } /// Storage: Council Voting (r:1 w:1) /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) @@ -492,17 +489,17 @@ impl WeightInfo for () { fn close_disapproved(m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `550 + m * (64 ±0) + p * (36 ±0)` - // Estimated: `10570 + m * (325 ±0) + p * (180 ±0)` - // Minimum execution time: 32_773_000 picoseconds. - Weight::from_parts(33_031_550, 10570) - // Standard Error: 1_205 - .saturating_add(Weight::from_parts(26_143, 0).saturating_mul(m.into())) - // Standard Error: 1_175 - .saturating_add(Weight::from_parts(137_503, 0).saturating_mul(p.into())) + // Estimated: `3995 + m * (65 ±0) + p * (36 ±0)` + // Minimum execution time: 33_146_000 picoseconds. + Weight::from_parts(31_957_128, 3995) + // Standard Error: 2_321 + .saturating_add(Weight::from_parts(31_272, 0).saturating_mul(m.into())) + // Standard Error: 2_264 + .saturating_add(Weight::from_parts(156_129, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 325).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 180).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 65).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) } /// Storage: Council Voting (r:1 w:1) /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) @@ -520,20 +517,20 @@ impl WeightInfo for () { fn close_approved(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `852 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` - // Estimated: `14905 + b * (5 ±0) + m * (330 ±0) + p * (200 ±0)` - // Minimum execution time: 44_855_000 picoseconds. - Weight::from_parts(47_307_460, 14905) + // Estimated: `4169 + b * (1 ±0) + m * (66 ±0) + p * (40 ±0)` + // Minimum execution time: 44_278_000 picoseconds. + Weight::from_parts(46_039_907, 4169) // Standard Error: 100 - .saturating_add(Weight::from_parts(1_536, 0).saturating_mul(b.into())) - // Standard Error: 1_065 - .saturating_add(Weight::from_parts(20_549, 0).saturating_mul(m.into())) - // Standard Error: 1_038 - .saturating_add(Weight::from_parts(133_143, 0).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(2_257, 0).saturating_mul(b.into())) + // Standard Error: 1_062 + .saturating_add(Weight::from_parts(25_055, 0).saturating_mul(m.into())) + // Standard Error: 1_035 + .saturating_add(Weight::from_parts(136_282, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 5).saturating_mul(b.into())) - .saturating_add(Weight::from_parts(0, 330).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 200).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 1).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(0, 66).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 40).saturating_mul(p.into())) } /// Storage: Council Proposals (r:1 w:1) /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) @@ -545,13 +542,13 @@ impl WeightInfo for () { fn disapprove_proposal(p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `359 + p * (32 ±0)` - // Estimated: `2562 + p * (96 ±0)` - // Minimum execution time: 16_420_000 picoseconds. - Weight::from_parts(18_236_525, 2562) - // Standard Error: 894 - .saturating_add(Weight::from_parts(115_590, 0).saturating_mul(p.into())) + // Estimated: `1844 + p * (32 ±0)` + // Minimum execution time: 16_500_000 picoseconds. + Weight::from_parts(18_376_538, 1844) + // Standard Error: 755 + .saturating_add(Weight::from_parts(113_189, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 96).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 32).saturating_mul(p.into())) } } diff --git a/frame/contracts/src/weights.rs b/frame/contracts/src/weights.rs index 8e81364acf449..cdaba7f59b72f 100644 --- a/frame/contracts/src/weights.rs +++ b/frame/contracts/src/weights.rs @@ -18,26 +18,25 @@ //! Autogenerated weights for pallet_contracts //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-04-12, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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 // --steps=50 // --repeat=20 +// --pallet=pallet_contracts // --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_contracts -// --chain=dev -// --header=./HEADER-APACHE2 // --output=./frame/contracts/src/weights.rs +// --header=./HEADER-APACHE2 // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -45,7 +44,7 @@ #![allow(unused_imports)] use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; -use sp_std::marker::PhantomData; +use core::marker::PhantomData; /// Weight functions needed for pallet_contracts. pub trait WeightInfo { @@ -178,8 +177,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `109` // Estimated: `1594` - // Minimum execution time: 2_503_000 picoseconds. - Weight::from_parts(2_603_000, 1594) + // Minimum execution time: 2_565_000 picoseconds. + Weight::from_parts(2_759_000, 1594) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: Skipped Metadata (r:0 w:0) @@ -189,10 +188,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `488 + k * (69 ±0)` // Estimated: `478 + k * (70 ±0)` - // Minimum execution time: 13_292_000 picoseconds. - Weight::from_parts(9_180_439, 478) - // Standard Error: 997 - .saturating_add(Weight::from_parts(967_522, 0).saturating_mul(k.into())) + // Minimum execution time: 13_480_000 picoseconds. + Weight::from_parts(10_153_869, 478) + // Standard Error: 427 + .saturating_add(Weight::from_parts(958_726, 0).saturating_mul(k.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) @@ -207,14 +206,14 @@ impl WeightInfo for SubstrateWeight { fn reinstrument(c: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `238 + c * (1 ±0)` - // Estimated: `3951 + c * (2 ±0)` - // Minimum execution time: 30_822_000 picoseconds. - Weight::from_parts(26_457_115, 3951) - // Standard Error: 58 - .saturating_add(Weight::from_parts(54_868, 0).saturating_mul(c.into())) + // Estimated: `3708 + c * (1 ±0)` + // Minimum execution time: 30_406_000 picoseconds. + Weight::from_parts(28_467_370, 3708) + // Standard Error: 46 + .saturating_add(Weight::from_parts(53_724, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) - .saturating_add(Weight::from_parts(0, 2).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(0, 1).saturating_mul(c.into())) } /// Storage: Contracts ContractInfoOf (r:1 w:1) /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) @@ -230,14 +229,14 @@ impl WeightInfo for SubstrateWeight { fn call_with_code_per_byte(c: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `707` - // Estimated: `21400 + c * (5 ±0)` - // Minimum execution time: 263_719_000 picoseconds. - Weight::from_parts(275_281_941, 21400) - // Standard Error: 32 - .saturating_add(Weight::from_parts(37_880, 0).saturating_mul(c.into())) + // Estimated: `6656 + c * (1 ±0)` + // Minimum execution time: 263_198_000 picoseconds. + Weight::from_parts(276_162_279, 6656) + // Standard Error: 18 + .saturating_add(Weight::from_parts(37_378, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) - .saturating_add(Weight::from_parts(0, 5).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(0, 1).saturating_mul(c.into())) } /// Storage: Contracts OwnerInfoOf (r:1 w:1) /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Measured) @@ -261,15 +260,15 @@ impl WeightInfo for SubstrateWeight { fn instantiate_with_code(c: u32, i: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `270` - // Estimated: `26207` - // Minimum execution time: 3_133_756_000 picoseconds. - Weight::from_parts(556_483_545, 26207) - // Standard Error: 294 - .saturating_add(Weight::from_parts(107_914, 0).saturating_mul(c.into())) - // Standard Error: 17 - .saturating_add(Weight::from_parts(1_143, 0).saturating_mul(i.into())) - // Standard Error: 17 - .saturating_add(Weight::from_parts(1_456, 0).saturating_mul(s.into())) + // Estimated: `8659` + // Minimum execution time: 3_132_259_000 picoseconds. + Weight::from_parts(513_284_834, 8659) + // Standard Error: 280 + .saturating_add(Weight::from_parts(106_723, 0).saturating_mul(c.into())) + // Standard Error: 16 + .saturating_add(Weight::from_parts(1_166, 0).saturating_mul(i.into())) + // Standard Error: 16 + .saturating_add(Weight::from_parts(1_436, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(10_u64)) } @@ -292,13 +291,13 @@ impl WeightInfo for SubstrateWeight { fn instantiate(i: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `482` - // Estimated: `28521` - // Minimum execution time: 1_646_953_000 picoseconds. - Weight::from_parts(262_115_215, 28521) - // Standard Error: 8 - .saturating_add(Weight::from_parts(1_454, 0).saturating_mul(i.into())) - // Standard Error: 8 - .saturating_add(Weight::from_parts(1_463, 0).saturating_mul(s.into())) + // Estimated: `6408` + // Minimum execution time: 1_646_604_000 picoseconds. + Weight::from_parts(271_369_256, 6408) + // Standard Error: 7 + .saturating_add(Weight::from_parts(1_426, 0).saturating_mul(i.into())) + // Standard Error: 7 + .saturating_add(Weight::from_parts(1_438, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } @@ -315,9 +314,9 @@ impl WeightInfo for SubstrateWeight { fn call() -> Weight { // Proof Size summary in bytes: // Measured: `759` - // Estimated: `21615` - // Minimum execution time: 190_769_000 picoseconds. - Weight::from_parts(191_717_000, 21615) + // Estimated: `6699` + // Minimum execution time: 191_360_000 picoseconds. + Weight::from_parts(192_625_000, 6699) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -333,11 +332,11 @@ impl WeightInfo for SubstrateWeight { fn upload_code(c: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `109` - // Estimated: `7366` - // Minimum execution time: 246_204_000 picoseconds. - Weight::from_parts(243_234_754, 7366) - // Standard Error: 78 - .saturating_add(Weight::from_parts(109_232, 0).saturating_mul(c.into())) + // Estimated: `3574` + // Minimum execution time: 245_207_000 picoseconds. + Weight::from_parts(244_703_457, 3574) + // Standard Error: 61 + .saturating_add(Weight::from_parts(106_850, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -352,9 +351,9 @@ impl WeightInfo for SubstrateWeight { fn remove_code() -> Weight { // Proof Size summary in bytes: // Measured: `255` - // Estimated: `7950` - // Minimum execution time: 33_516_000 picoseconds. - Weight::from_parts(33_995_000, 7950) + // Estimated: `3720` + // Minimum execution time: 33_560_000 picoseconds. + Weight::from_parts(33_833_000, 3720) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -367,9 +366,9 @@ impl WeightInfo for SubstrateWeight { fn set_code() -> Weight { // Proof Size summary in bytes: // Measured: `570` - // Estimated: `19530` - // Minimum execution time: 33_255_000 picoseconds. - Weight::from_parts(33_692_000, 19530) + // Estimated: `8985` + // Minimum execution time: 33_288_000 picoseconds. + Weight::from_parts(33_775_000, 8985) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -387,14 +386,14 @@ impl WeightInfo for SubstrateWeight { fn seal_caller(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `781 + r * (6 ±0)` - // Estimated: `21730 + r * (30 ±0)` - // Minimum execution time: 235_074_000 picoseconds. - Weight::from_parts(243_735_179, 21730) - // Standard Error: 972 - .saturating_add(Weight::from_parts(328_571, 0).saturating_mul(r.into())) + // Estimated: `6722 + r * (6 ±0)` + // Minimum execution time: 234_292_000 picoseconds. + Weight::from_parts(235_941_911, 6722) + // Standard Error: 413 + .saturating_add(Weight::from_parts(339_913, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -410,15 +409,15 @@ impl WeightInfo for SubstrateWeight { fn seal_is_contract(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `839 + r * (240 ±0)` - // Estimated: `21835 + r * (3675 ±0)` - // Minimum execution time: 236_455_000 picoseconds. - Weight::from_parts(81_818_936, 21835) - // Standard Error: 5_874 - .saturating_add(Weight::from_parts(3_316_006, 0).saturating_mul(r.into())) + // Estimated: `6743 + r * (2715 ±0)` + // Minimum execution time: 236_273_000 picoseconds. + Weight::from_parts(74_380_906, 6743) + // Standard Error: 5_745 + .saturating_add(Weight::from_parts(3_331_781, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 3675).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 2715).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -434,15 +433,15 @@ impl WeightInfo for SubstrateWeight { fn seal_code_hash(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `831 + r * (244 ±0)` - // Estimated: `21855 + r * (3695 ±0)` - // Minimum execution time: 237_724_000 picoseconds. - Weight::from_parts(91_384_964, 21855) - // Standard Error: 5_828 - .saturating_add(Weight::from_parts(4_063_221, 0).saturating_mul(r.into())) + // Estimated: `6747 + r * (2719 ±0)` + // Minimum execution time: 236_573_000 picoseconds. + Weight::from_parts(82_473_906, 6747) + // Standard Error: 5_510 + .saturating_add(Weight::from_parts(4_131_820, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 3695).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 2719).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -458,14 +457,14 @@ impl WeightInfo for SubstrateWeight { fn seal_own_code_hash(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `788 + r * (6 ±0)` - // Estimated: `21770 + r * (30 ±0)` - // Minimum execution time: 236_144_000 picoseconds. - Weight::from_parts(239_917_873, 21770) - // Standard Error: 629 - .saturating_add(Weight::from_parts(409_752, 0).saturating_mul(r.into())) + // Estimated: `6730 + r * (6 ±0)` + // Minimum execution time: 235_878_000 picoseconds. + Weight::from_parts(238_387_359, 6730) + // Standard Error: 318 + .saturating_add(Weight::from_parts(409_923, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -481,14 +480,14 @@ impl WeightInfo for SubstrateWeight { fn seal_caller_is_origin(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `778 + r * (3 ±0)` - // Estimated: `21735 + r * (15 ±0)` - // Minimum execution time: 232_946_000 picoseconds. - Weight::from_parts(243_163_112, 21735) - // Standard Error: 1_940 - .saturating_add(Weight::from_parts(162_705, 0).saturating_mul(r.into())) + // Estimated: `6723 + r * (3 ±0)` + // Minimum execution time: 233_476_000 picoseconds. + Weight::from_parts(238_014_452, 6723) + // Standard Error: 145 + .saturating_add(Weight::from_parts(165_823, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 15).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 3).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -504,14 +503,14 @@ impl WeightInfo for SubstrateWeight { fn seal_address(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `782 + r * (6 ±0)` - // Estimated: `21740 + r * (30 ±0)` - // Minimum execution time: 235_301_000 picoseconds. - Weight::from_parts(240_802_312, 21740) - // Standard Error: 5_362 - .saturating_add(Weight::from_parts(339_001, 0).saturating_mul(r.into())) + // Estimated: `6724 + r * (6 ±0)` + // Minimum execution time: 235_490_000 picoseconds. + Weight::from_parts(240_039_685, 6724) + // Standard Error: 330 + .saturating_add(Weight::from_parts(332_291, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -527,14 +526,14 @@ impl WeightInfo for SubstrateWeight { fn seal_gas_left(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `783 + r * (6 ±0)` - // Estimated: `21725 + r * (30 ±0)` - // Minimum execution time: 235_683_000 picoseconds. - Weight::from_parts(237_357_276, 21725) - // Standard Error: 726 - .saturating_add(Weight::from_parts(333_264, 0).saturating_mul(r.into())) + // Estimated: `6721 + r * (6 ±0)` + // Minimum execution time: 236_093_000 picoseconds. + Weight::from_parts(238_513_328, 6721) + // Standard Error: 206 + .saturating_add(Weight::from_parts(328_899, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) } /// Storage: System Account (r:2 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -550,14 +549,14 @@ impl WeightInfo for SubstrateWeight { fn seal_balance(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `922 + r * (6 ±0)` - // Estimated: `24633 + r * (30 ±0)` - // Minimum execution time: 234_327_000 picoseconds. - Weight::from_parts(239_792_456, 24633) - // Standard Error: 3_460 - .saturating_add(Weight::from_parts(1_496_090, 0).saturating_mul(r.into())) + // Estimated: `6846 + r * (6 ±0)` + // Minimum execution time: 234_801_000 picoseconds. + Weight::from_parts(243_519_159, 6846) + // Standard Error: 1_367 + .saturating_add(Weight::from_parts(1_449_599, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -573,14 +572,14 @@ impl WeightInfo for SubstrateWeight { fn seal_value_transferred(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `792 + r * (6 ±0)` - // Estimated: `21825 + r * (30 ±0)` - // Minimum execution time: 235_466_000 picoseconds. - Weight::from_parts(242_580_658, 21825) - // Standard Error: 1_439 - .saturating_add(Weight::from_parts(323_842, 0).saturating_mul(r.into())) + // Estimated: `6741 + r * (6 ±0)` + // Minimum execution time: 236_765_000 picoseconds. + Weight::from_parts(237_843_244, 6741) + // Standard Error: 308 + .saturating_add(Weight::from_parts(329_911, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -596,14 +595,14 @@ impl WeightInfo for SubstrateWeight { fn seal_minimum_balance(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `790 + r * (6 ±0)` - // Estimated: `21815 + r * (30 ±0)` - // Minimum execution time: 238_529_000 picoseconds. - Weight::from_parts(249_276_722, 21815) - // Standard Error: 1_216 - .saturating_add(Weight::from_parts(328_600, 0).saturating_mul(r.into())) + // Estimated: `6739 + r * (6 ±0)` + // Minimum execution time: 236_690_000 picoseconds. + Weight::from_parts(241_743_164, 6739) + // Standard Error: 333 + .saturating_add(Weight::from_parts(324_693, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -619,14 +618,14 @@ impl WeightInfo for SubstrateWeight { fn seal_block_number(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `787 + r * (6 ±0)` - // Estimated: `21805 + r * (30 ±0)` - // Minimum execution time: 234_360_000 picoseconds. - Weight::from_parts(239_927_876, 21805) - // Standard Error: 541 - .saturating_add(Weight::from_parts(319_553, 0).saturating_mul(r.into())) + // Estimated: `6737 + r * (6 ±0)` + // Minimum execution time: 236_149_000 picoseconds. + Weight::from_parts(239_090_707, 6737) + // Standard Error: 246 + .saturating_add(Weight::from_parts(344_488, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -642,14 +641,14 @@ impl WeightInfo for SubstrateWeight { fn seal_now(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `778 + r * (6 ±0)` - // Estimated: `21735 + r * (30 ±0)` - // Minimum execution time: 234_461_000 picoseconds. - Weight::from_parts(239_682_633, 21735) - // Standard Error: 544 - .saturating_add(Weight::from_parts(322_943, 0).saturating_mul(r.into())) + // Estimated: `6723 + r * (6 ±0)` + // Minimum execution time: 235_057_000 picoseconds. + Weight::from_parts(237_752_870, 6723) + // Standard Error: 236 + .saturating_add(Weight::from_parts(328_235, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -667,14 +666,14 @@ impl WeightInfo for SubstrateWeight { fn seal_weight_to_fee(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `856 + r * (10 ±0)` - // Estimated: `24446 + r * (60 ±0)` - // Minimum execution time: 234_862_000 picoseconds. - Weight::from_parts(252_614_390, 24446) - // Standard Error: 1_180 - .saturating_add(Weight::from_parts(1_313_286, 0).saturating_mul(r.into())) + // Estimated: `6796 + r * (10 ±0)` + // Minimum execution time: 234_995_000 picoseconds. + Weight::from_parts(246_473_554, 6796) + // Standard Error: 1_015 + .saturating_add(Weight::from_parts(1_337_653, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 60).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 10).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -690,14 +689,14 @@ impl WeightInfo for SubstrateWeight { fn seal_gas(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `745 + r * (4 ±0)` - // Estimated: `21555 + r * (20 ±0)` - // Minimum execution time: 161_003_000 picoseconds. - Weight::from_parts(165_793_675, 21555) - // Standard Error: 323 - .saturating_add(Weight::from_parts(128_941, 0).saturating_mul(r.into())) + // Estimated: `6687 + r * (4 ±0)` + // Minimum execution time: 160_445_000 picoseconds. + Weight::from_parts(165_558_135, 6687) + // Standard Error: 234 + .saturating_add(Weight::from_parts(133_607, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 20).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 4).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -713,14 +712,14 @@ impl WeightInfo for SubstrateWeight { fn seal_input(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `780 + r * (6 ±0)` - // Estimated: `21740 + r * (30 ±0)` - // Minimum execution time: 235_192_000 picoseconds. - Weight::from_parts(241_225_671, 21740) - // Standard Error: 1_132 - .saturating_add(Weight::from_parts(272_760, 0).saturating_mul(r.into())) + // Estimated: `6724 + r * (6 ±0)` + // Minimum execution time: 235_065_000 picoseconds. + Weight::from_parts(237_797_177, 6724) + // Standard Error: 336 + .saturating_add(Weight::from_parts(267_302, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -736,11 +735,11 @@ impl WeightInfo for SubstrateWeight { fn seal_input_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `784` - // Estimated: `21740` - // Minimum execution time: 238_050_000 picoseconds. - Weight::from_parts(241_274_832, 21740) - // Standard Error: 1 - .saturating_add(Weight::from_parts(590, 0).saturating_mul(n.into())) + // Estimated: `6724` + // Minimum execution time: 236_215_000 picoseconds. + Weight::from_parts(239_347_313, 6724) + // Standard Error: 0 + .saturating_add(Weight::from_parts(587, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -758,14 +757,14 @@ impl WeightInfo for SubstrateWeight { fn seal_return(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `768 + r * (45 ±0)` - // Estimated: `21660 + r * (225 ±0)` - // Minimum execution time: 231_807_000 picoseconds. - Weight::from_parts(234_264_848, 21660) - // Standard Error: 185_298 - .saturating_add(Weight::from_parts(1_000_351, 0).saturating_mul(r.into())) + // Estimated: `6708 + r * (45 ±0)` + // Minimum execution time: 231_571_000 picoseconds. + Weight::from_parts(233_477_918, 6708) + // Standard Error: 95_776 + .saturating_add(Weight::from_parts(1_733_181, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 225).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 45).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -781,11 +780,11 @@ impl WeightInfo for SubstrateWeight { fn seal_return_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `778` - // Estimated: `21775` - // Minimum execution time: 234_347_000 picoseconds. - Weight::from_parts(234_774_467, 21775) + // Estimated: `6731` + // Minimum execution time: 234_956_000 picoseconds. + Weight::from_parts(236_785_051, 6731) // Standard Error: 0 - .saturating_add(Weight::from_parts(183, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(177, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -809,16 +808,16 @@ impl WeightInfo for SubstrateWeight { fn seal_terminate(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `810 + r * (356 ±0)` - // Estimated: `26094 + r * (15904 ±0)` - // Minimum execution time: 234_356_000 picoseconds. - Weight::from_parts(236_844_659, 26094) - // Standard Error: 161_035 - .saturating_add(Weight::from_parts(110_725_340, 0).saturating_mul(r.into())) + // Estimated: `6750 + r * (7781 ±0)` + // Minimum execution time: 234_275_000 picoseconds. + Weight::from_parts(236_776_769, 6750) + // Standard Error: 137_203 + .saturating_add(Weight::from_parts(110_758_930, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((6_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((8_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 15904).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 7781).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -836,14 +835,14 @@ impl WeightInfo for SubstrateWeight { fn seal_random(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `825 + r * (10 ±0)` - // Estimated: `24283 + r * (60 ±0)` - // Minimum execution time: 234_248_000 picoseconds. - Weight::from_parts(255_712_101, 24283) - // Standard Error: 1_474 - .saturating_add(Weight::from_parts(1_753_943, 0).saturating_mul(r.into())) + // Estimated: `6769 + r * (10 ±0)` + // Minimum execution time: 235_593_000 picoseconds. + Weight::from_parts(253_731_242, 6769) + // Standard Error: 2_129 + .saturating_add(Weight::from_parts(1_771_297, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 60).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 10).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -859,14 +858,14 @@ impl WeightInfo for SubstrateWeight { fn seal_deposit_event(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `778 + r * (10 ±0)` - // Estimated: `21735 + r * (50 ±0)` - // Minimum execution time: 232_456_000 picoseconds. - Weight::from_parts(230_738_907, 21735) - // Standard Error: 4_163 - .saturating_add(Weight::from_parts(3_496_817, 0).saturating_mul(r.into())) + // Estimated: `6723 + r * (10 ±0)` + // Minimum execution time: 232_124_000 picoseconds. + Weight::from_parts(245_904_447, 6723) + // Standard Error: 2_185 + .saturating_add(Weight::from_parts(3_470_410, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 50).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 10).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -883,18 +882,18 @@ impl WeightInfo for SubstrateWeight { fn seal_deposit_event_per_topic_and_byte(t: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `797 + t * (32 ±0)` - // Estimated: `21840 + t * (2640 ±0)` - // Minimum execution time: 251_638_000 picoseconds. - Weight::from_parts(244_791_817, 21840) - // Standard Error: 89_537 - .saturating_add(Weight::from_parts(2_459_492, 0).saturating_mul(t.into())) - // Standard Error: 25 - .saturating_add(Weight::from_parts(626, 0).saturating_mul(n.into())) + // Estimated: `6744 + t * (2508 ±0)` + // Minimum execution time: 250_301_000 picoseconds. + Weight::from_parts(245_292_258, 6744) + // Standard Error: 29_864 + .saturating_add(Weight::from_parts(2_163_531, 0).saturating_mul(t.into())) + // Standard Error: 8 + .saturating_add(Weight::from_parts(583, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(t.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(t.into()))) - .saturating_add(Weight::from_parts(0, 2640).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(0, 2508).saturating_mul(t.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -910,14 +909,14 @@ impl WeightInfo for SubstrateWeight { fn seal_debug_message(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `777 + r * (7 ±0)` - // Estimated: `21725 + r * (35 ±0)` - // Minimum execution time: 164_736_000 picoseconds. - Weight::from_parts(164_496_597, 21725) - // Standard Error: 4_619 - .saturating_add(Weight::from_parts(252_013, 0).saturating_mul(r.into())) + // Estimated: `6721 + r * (7 ±0)` + // Minimum execution time: 165_711_000 picoseconds. + Weight::from_parts(168_792_571, 6721) + // Standard Error: 216 + .saturating_add(Weight::from_parts(230_285, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 35).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 7).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) @@ -933,11 +932,11 @@ impl WeightInfo for SubstrateWeight { fn seal_debug_message_per_byte(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `125728` - // Estimated: `269977` - // Minimum execution time: 352_146_000 picoseconds. - Weight::from_parts(357_758_251, 269977) - // Standard Error: 1 - .saturating_add(Weight::from_parts(735, 0).saturating_mul(i.into())) + // Estimated: `131670` + // Minimum execution time: 348_928_000 picoseconds. + Weight::from_parts(352_224_793, 131670) + // Standard Error: 0 + .saturating_add(Weight::from_parts(731, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -948,10 +947,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `845 + r * (292 ±0)` // Estimated: `843 + r * (293 ±0)` - // Minimum execution time: 236_170_000 picoseconds. - Weight::from_parts(136_284_582, 843) - // Standard Error: 10_269 - .saturating_add(Weight::from_parts(5_995_228, 0).saturating_mul(r.into())) + // Minimum execution time: 236_418_000 picoseconds. + Weight::from_parts(129_862_840, 843) + // Standard Error: 9_733 + .saturating_add(Weight::from_parts(6_005_187, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -965,10 +964,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1304` // Estimated: `1280` - // Minimum execution time: 253_837_000 picoseconds. - Weight::from_parts(287_029_261, 1280) - // Standard Error: 51 - .saturating_add(Weight::from_parts(534, 0).saturating_mul(n.into())) + // Minimum execution time: 251_599_000 picoseconds. + Weight::from_parts(285_284_665, 1280) + // Standard Error: 46 + .saturating_add(Weight::from_parts(410, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -979,10 +978,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1167 + n * (1 ±0)` // Estimated: `1167 + n * (1 ±0)` - // Minimum execution time: 253_037_000 picoseconds. - Weight::from_parts(256_401_533, 1167) - // Standard Error: 18 - .saturating_add(Weight::from_parts(32, 0).saturating_mul(n.into())) + // Minimum execution time: 251_309_000 picoseconds. + Weight::from_parts(253_555_552, 1167) + // Standard Error: 9 + .saturating_add(Weight::from_parts(27, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -994,10 +993,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `841 + r * (288 ±0)` // Estimated: `845 + r * (289 ±0)` - // Minimum execution time: 236_800_000 picoseconds. - Weight::from_parts(134_748_031, 845) - // Standard Error: 9_560 - .saturating_add(Weight::from_parts(5_923_187, 0).saturating_mul(r.into())) + // Minimum execution time: 235_441_000 picoseconds. + Weight::from_parts(132_980_942, 845) + // Standard Error: 9_421 + .saturating_add(Weight::from_parts(5_854_896, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1011,9 +1010,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1163 + n * (1 ±0)` // Estimated: `1163 + n * (1 ±0)` - // Minimum execution time: 250_601_000 picoseconds. - Weight::from_parts(253_618_803, 1163) - // Standard Error: 18 + // Minimum execution time: 249_967_000 picoseconds. + Weight::from_parts(252_122_186, 1163) + // Standard Error: 10 .saturating_add(Weight::from_parts(74, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) @@ -1026,10 +1025,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `835 + r * (296 ±0)` // Estimated: `840 + r * (297 ±0)` - // Minimum execution time: 236_194_000 picoseconds. - Weight::from_parts(152_630_909, 840) - // Standard Error: 8_573 - .saturating_add(Weight::from_parts(4_896_099, 0).saturating_mul(r.into())) + // Minimum execution time: 235_647_000 picoseconds. + Weight::from_parts(145_525_169, 840) + // Standard Error: 8_553 + .saturating_add(Weight::from_parts(4_948_021, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1042,10 +1041,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1179 + n * (1 ±0)` // Estimated: `1179 + n * (1 ±0)` - // Minimum execution time: 250_989_000 picoseconds. - Weight::from_parts(260_170_747, 1179) - // Standard Error: 162 - .saturating_add(Weight::from_parts(224, 0).saturating_mul(n.into())) + // Minimum execution time: 249_576_000 picoseconds. + Weight::from_parts(250_747_191, 1179) + // Standard Error: 8 + .saturating_add(Weight::from_parts(717, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -1057,10 +1056,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `856 + r * (288 ±0)` // Estimated: `857 + r * (289 ±0)` - // Minimum execution time: 236_574_000 picoseconds. - Weight::from_parts(155_573_955, 857) - // Standard Error: 10_270 - .saturating_add(Weight::from_parts(4_667_644, 0).saturating_mul(r.into())) + // Minimum execution time: 236_110_000 picoseconds. + Weight::from_parts(148_420_625, 857) + // Standard Error: 8_175 + .saturating_add(Weight::from_parts(4_684_126, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1073,10 +1072,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1166 + n * (1 ±0)` // Estimated: `1166 + n * (1 ±0)` - // Minimum execution time: 249_502_000 picoseconds. - Weight::from_parts(251_496_311, 1166) - // Standard Error: 26 - .saturating_add(Weight::from_parts(186, 0).saturating_mul(n.into())) + // Minimum execution time: 247_800_000 picoseconds. + Weight::from_parts(249_410_575, 1166) + // Standard Error: 6 + .saturating_add(Weight::from_parts(99, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -1088,10 +1087,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `829 + r * (296 ±0)` // Estimated: `836 + r * (297 ±0)` - // Minimum execution time: 236_030_000 picoseconds. - Weight::from_parts(128_595_856, 836) - // Standard Error: 10_530 - .saturating_add(Weight::from_parts(6_072_638, 0).saturating_mul(r.into())) + // Minimum execution time: 235_251_000 picoseconds. + Weight::from_parts(128_816_707, 836) + // Standard Error: 9_887 + .saturating_add(Weight::from_parts(6_167_176, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1105,10 +1104,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1180 + n * (1 ±0)` // Estimated: `1180 + n * (1 ±0)` - // Minimum execution time: 254_027_000 picoseconds. - Weight::from_parts(260_739_475, 1180) - // Standard Error: 115 - .saturating_add(Weight::from_parts(330, 0).saturating_mul(n.into())) + // Minimum execution time: 250_401_000 picoseconds. + Weight::from_parts(253_298_243, 1180) + // Standard Error: 9 + .saturating_add(Weight::from_parts(667, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -1127,16 +1126,16 @@ impl WeightInfo for SubstrateWeight { fn seal_transfer(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `1373 + r * (45 ±0)` - // Estimated: `26753 + r * (2700 ±0)` - // Minimum execution time: 237_634_000 picoseconds. - Weight::from_parts(238_177_000, 26753) - // Standard Error: 23_320 - .saturating_add(Weight::from_parts(35_467_618, 0).saturating_mul(r.into())) + // Estimated: `7270 + r * (2520 ±0)` + // Minimum execution time: 236_470_000 picoseconds. + Weight::from_parts(98_898_727, 7270) + // Standard Error: 33_316 + .saturating_add(Weight::from_parts(35_149_946, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 2700).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 2520).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1152,16 +1151,16 @@ impl WeightInfo for SubstrateWeight { fn seal_call(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `1237 + r * (256 ±0)` - // Estimated: `26028 + r * (6235 ±0)` - // Minimum execution time: 237_076_000 picoseconds. - Weight::from_parts(237_792_000, 26028) - // Standard Error: 91_566 - .saturating_add(Weight::from_parts(212_893_975, 0).saturating_mul(r.into())) + // Estimated: `7125 + r * (2732 ±0)` + // Minimum execution time: 238_303_000 picoseconds. + Weight::from_parts(239_024_000, 7125) + // Standard Error: 65_907 + .saturating_add(Weight::from_parts(209_419_071, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 6235).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 2732).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1177,16 +1176,16 @@ impl WeightInfo for SubstrateWeight { fn seal_delegate_call(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + r * (502 ±0)` - // Estimated: `21755 + r * (6329 ±3)` - // Minimum execution time: 236_275_000 picoseconds. - Weight::from_parts(236_849_000, 21755) - // Standard Error: 92_724 - .saturating_add(Weight::from_parts(207_159_396, 0).saturating_mul(r.into())) + // Estimated: `6727 + r * (2572 ±10)` + // Minimum execution time: 235_961_000 picoseconds. + Weight::from_parts(236_939_000, 6727) + // Standard Error: 83_087 + .saturating_add(Weight::from_parts(205_646_517, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 6329).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 2572).saturating_mul(r.into())) } /// Storage: System Account (r:3 w:2) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1203,18 +1202,18 @@ impl WeightInfo for SubstrateWeight { fn seal_call_per_transfer_clone_byte(t: u32, c: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `1154 + t * (204 ±0)` - // Estimated: `31015 + t * (5970 ±0)` - // Minimum execution time: 412_628_000 picoseconds. - Weight::from_parts(385_108_035, 31015) - // Standard Error: 1_002_078 - .saturating_add(Weight::from_parts(31_204_678, 0).saturating_mul(t.into())) - // Standard Error: 1 - .saturating_add(Weight::from_parts(598, 0).saturating_mul(c.into())) + // Estimated: `9569 + t * (5154 ±0)` + // Minimum execution time: 410_156_000 picoseconds. + Weight::from_parts(378_378_143, 9569) + // Standard Error: 285_172 + .saturating_add(Weight::from_parts(34_736_740, 0).saturating_mul(t.into())) + // Standard Error: 0 + .saturating_add(Weight::from_parts(591, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(t.into()))) .saturating_add(T::DbWeight::get().writes(5_u64)) .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(t.into()))) - .saturating_add(Weight::from_parts(0, 5970).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(0, 5154).saturating_mul(t.into())) } /// Storage: System Account (r:1602 w:1602) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1234,16 +1233,16 @@ impl WeightInfo for SubstrateWeight { fn seal_instantiate(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `1301 + r * (254 ±0)` - // Estimated: `30977 + r * (16635 ±0)` - // Minimum execution time: 237_161_000 picoseconds. - Weight::from_parts(237_620_000, 30977) - // Standard Error: 258_036 - .saturating_add(Weight::from_parts(344_869_637, 0).saturating_mul(r.into())) + // Estimated: `7131 + r * (5205 ±0)` + // Minimum execution time: 236_748_000 picoseconds. + Weight::from_parts(237_129_000, 7131) + // Standard Error: 280_059 + .saturating_add(Weight::from_parts(341_428_013, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().reads((6_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(6_u64)) .saturating_add(T::DbWeight::get().writes((5_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 16635).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 5205).saturating_mul(r.into())) } /// Storage: System Account (r:4 w:4) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1265,20 +1264,20 @@ impl WeightInfo for SubstrateWeight { fn seal_instantiate_per_transfer_input_salt_byte(t: u32, i: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `1071 + t * (187 ±0)` - // Estimated: `42684 + t * (3588 ±2)` - // Minimum execution time: 1_613_172_000 picoseconds. - Weight::from_parts(326_952_137, 42684) - // Standard Error: 4_738_925 - .saturating_add(Weight::from_parts(113_657_996, 0).saturating_mul(t.into())) - // Standard Error: 7 - .saturating_add(Weight::from_parts(1_173, 0).saturating_mul(i.into())) - // Standard Error: 7 - .saturating_add(Weight::from_parts(1_347, 0).saturating_mul(s.into())) + // Estimated: `9492 + t * (2634 ±2)` + // Minimum execution time: 1_613_796_000 picoseconds. + Weight::from_parts(340_002_206, 9492) + // Standard Error: 4_296_381 + .saturating_add(Weight::from_parts(115_239_834, 0).saturating_mul(t.into())) + // Standard Error: 6 + .saturating_add(Weight::from_parts(1_145, 0).saturating_mul(i.into())) + // Standard Error: 6 + .saturating_add(Weight::from_parts(1_315, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(13_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(t.into()))) .saturating_add(T::DbWeight::get().writes(10_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(t.into()))) - .saturating_add(Weight::from_parts(0, 3588).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(0, 2634).saturating_mul(t.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1294,14 +1293,14 @@ impl WeightInfo for SubstrateWeight { fn seal_hash_sha2_256(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `777 + r * (8 ±0)` - // Estimated: `21710 + r * (40 ±0)` - // Minimum execution time: 233_679_000 picoseconds. - Weight::from_parts(238_638_820, 21710) - // Standard Error: 681 - .saturating_add(Weight::from_parts(573_320, 0).saturating_mul(r.into())) + // Estimated: `6718 + r * (8 ±0)` + // Minimum execution time: 233_111_000 picoseconds. + Weight::from_parts(238_643_933, 6718) + // Standard Error: 184 + .saturating_add(Weight::from_parts(572_296, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 8).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1317,11 +1316,11 @@ impl WeightInfo for SubstrateWeight { fn seal_hash_sha2_256_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `785` - // Estimated: `21745` - // Minimum execution time: 235_992_000 picoseconds. - Weight::from_parts(219_924_252, 21745) - // Standard Error: 5 - .saturating_add(Weight::from_parts(3_978, 0).saturating_mul(n.into())) + // Estimated: `6725` + // Minimum execution time: 234_746_000 picoseconds. + Weight::from_parts(229_815_552, 6725) + // Standard Error: 1 + .saturating_add(Weight::from_parts(3_892, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1339,14 +1338,14 @@ impl WeightInfo for SubstrateWeight { fn seal_hash_keccak_256(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `779 + r * (8 ±0)` - // Estimated: `21725 + r * (40 ±0)` - // Minimum execution time: 240_661_000 picoseconds. - Weight::from_parts(238_809_422, 21725) - // Standard Error: 820 - .saturating_add(Weight::from_parts(741_326, 0).saturating_mul(r.into())) + // Estimated: `6721 + r * (8 ±0)` + // Minimum execution time: 232_732_000 picoseconds. + Weight::from_parts(239_007_209, 6721) + // Standard Error: 256 + .saturating_add(Weight::from_parts(733_879, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 8).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1362,11 +1361,11 @@ impl WeightInfo for SubstrateWeight { fn seal_hash_keccak_256_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `787` - // Estimated: `21765` - // Minimum execution time: 235_136_000 picoseconds. - Weight::from_parts(228_678_487, 21765) - // Standard Error: 2 - .saturating_add(Weight::from_parts(3_164, 0).saturating_mul(n.into())) + // Estimated: `6729` + // Minimum execution time: 234_184_000 picoseconds. + Weight::from_parts(227_603_375, 6729) + // Standard Error: 1 + .saturating_add(Weight::from_parts(3_127, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1384,14 +1383,14 @@ impl WeightInfo for SubstrateWeight { fn seal_hash_blake2_256(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `779 + r * (8 ±0)` - // Estimated: `21740 + r * (40 ±0)` - // Minimum execution time: 233_364_000 picoseconds. - Weight::from_parts(243_294_285, 21740) - // Standard Error: 1_607 - .saturating_add(Weight::from_parts(413_186, 0).saturating_mul(r.into())) + // Estimated: `6724 + r * (8 ±0)` + // Minimum execution time: 233_038_000 picoseconds. + Weight::from_parts(238_515_817, 6724) + // Standard Error: 255 + .saturating_add(Weight::from_parts(413_343, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 8).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1407,11 +1406,11 @@ impl WeightInfo for SubstrateWeight { fn seal_hash_blake2_256_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `787` - // Estimated: `21785` - // Minimum execution time: 234_315_000 picoseconds. - Weight::from_parts(225_569_537, 21785) + // Estimated: `6733` + // Minimum execution time: 232_996_000 picoseconds. + Weight::from_parts(226_706_997, 6733) // Standard Error: 1 - .saturating_add(Weight::from_parts(919, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(908, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1429,14 +1428,14 @@ impl WeightInfo for SubstrateWeight { fn seal_hash_blake2_128(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `779 + r * (8 ±0)` - // Estimated: `21745 + r * (40 ±0)` - // Minimum execution time: 233_288_000 picoseconds. - Weight::from_parts(239_289_154, 21745) - // Standard Error: 612 - .saturating_add(Weight::from_parts(414_275, 0).saturating_mul(r.into())) + // Estimated: `6725 + r * (8 ±0)` + // Minimum execution time: 232_292_000 picoseconds. + Weight::from_parts(237_997_001, 6725) + // Standard Error: 219 + .saturating_add(Weight::from_parts(410_177, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 8).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1452,11 +1451,11 @@ impl WeightInfo for SubstrateWeight { fn seal_hash_blake2_128_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `787` - // Estimated: `21755` - // Minimum execution time: 233_686_000 picoseconds. - Weight::from_parts(227_406_694, 21755) + // Estimated: `6727` + // Minimum execution time: 234_815_000 picoseconds. + Weight::from_parts(226_317_150, 6727) // Standard Error: 1 - .saturating_add(Weight::from_parts(919, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(911, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1473,15 +1472,15 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 125697]`. fn seal_sr25519_verify_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `916 + n * (1 ±0)` - // Estimated: `22375 + n * (5 ±0)` - // Minimum execution time: 287_258_000 picoseconds. - Weight::from_parts(290_941_609, 22375) - // Standard Error: 8 - .saturating_add(Weight::from_parts(4_785, 0).saturating_mul(n.into())) + // Measured: `912 + n * (1 ±0)` + // Estimated: `6848 + n * (1 ±0)` + // Minimum execution time: 286_323_000 picoseconds. + Weight::from_parts(290_287_955, 6848) + // Standard Error: 1 + .saturating_add(Weight::from_parts(4_693, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 5).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1496,15 +1495,15 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 160]`. fn seal_sr25519_verify(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `728 + r * (112 ±0)` - // Estimated: `21455 + r * (560 ±0)` - // Minimum execution time: 238_340_000 picoseconds. - Weight::from_parts(246_009_851, 21455) - // Standard Error: 21_677 - .saturating_add(Weight::from_parts(48_139_487, 0).saturating_mul(r.into())) + // Measured: `727 + r * (112 ±0)` + // Estimated: `6666 + r * (112 ±0)` + // Minimum execution time: 235_938_000 picoseconds. + Weight::from_parts(242_728_358, 6666) + // Standard Error: 9_725 + .saturating_add(Weight::from_parts(47_527_740, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 560).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 112).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1520,14 +1519,14 @@ impl WeightInfo for SubstrateWeight { fn seal_ecdsa_recover(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `822 + r * (76 ±0)` - // Estimated: `21705 + r * (385 ±0)` - // Minimum execution time: 236_244_000 picoseconds. - Weight::from_parts(253_749_242, 21705) - // Standard Error: 19_216 - .saturating_add(Weight::from_parts(37_706_782, 0).saturating_mul(r.into())) + // Estimated: `6716 + r * (77 ±0)` + // Minimum execution time: 236_108_000 picoseconds. + Weight::from_parts(248_577_226, 6716) + // Standard Error: 9_565 + .saturating_add(Weight::from_parts(36_733_552, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 385).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 77).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1543,14 +1542,14 @@ impl WeightInfo for SubstrateWeight { fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `792 + r * (42 ±0)` - // Estimated: `21775 + r * (210 ±0)` - // Minimum execution time: 235_770_000 picoseconds. - Weight::from_parts(230_780_347, 21775) - // Standard Error: 12_015 - .saturating_add(Weight::from_parts(9_584_947, 0).saturating_mul(r.into())) + // Estimated: `6731 + r * (42 ±0)` + // Minimum execution time: 236_440_000 picoseconds. + Weight::from_parts(240_771_418, 6731) + // Standard Error: 1_849 + .saturating_add(Weight::from_parts(9_185_896, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 210).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 42).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1568,16 +1567,16 @@ impl WeightInfo for SubstrateWeight { fn seal_set_code_hash(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + r * (964 ±0)` - // Estimated: `29920 + r * (11544 ±7)` - // Minimum execution time: 235_857_000 picoseconds. - Weight::from_parts(236_482_000, 29920) - // Standard Error: 47_818 - .saturating_add(Weight::from_parts(21_765_273, 0).saturating_mul(r.into())) + // Estimated: `8190 + r * (3090 ±10)` + // Minimum execution time: 235_056_000 picoseconds. + Weight::from_parts(235_743_000, 8190) + // Standard Error: 46_122 + .saturating_add(Weight::from_parts(21_447_984, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 11544).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 3090).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1593,14 +1592,14 @@ impl WeightInfo for SubstrateWeight { fn seal_reentrance_count(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `773 + r * (3 ±0)` - // Estimated: `21735 + r * (15 ±0)` - // Minimum execution time: 235_388_000 picoseconds. - Weight::from_parts(240_149_512, 21735) - // Standard Error: 555 - .saturating_add(Weight::from_parts(162_666, 0).saturating_mul(r.into())) + // Estimated: `6723 + r * (3 ±0)` + // Minimum execution time: 235_213_000 picoseconds. + Weight::from_parts(239_456_464, 6723) + // Standard Error: 130 + .saturating_add(Weight::from_parts(159_851, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 15).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 3).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1616,14 +1615,14 @@ impl WeightInfo for SubstrateWeight { fn seal_account_reentrance_count(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `1975 + r * (39 ±0)` - // Estimated: `27145 + r * (200 ±0)` - // Minimum execution time: 237_485_000 picoseconds. - Weight::from_parts(268_044_053, 27145) - // Standard Error: 1_147 - .saturating_add(Weight::from_parts(260_572, 0).saturating_mul(r.into())) + // Estimated: `7805 + r * (40 ±0)` + // Minimum execution time: 237_886_000 picoseconds. + Weight::from_parts(262_430_157, 7805) + // Standard Error: 939 + .saturating_add(Weight::from_parts(260_005, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 200).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -1641,524 +1640,524 @@ impl WeightInfo for SubstrateWeight { fn seal_instantiation_nonce(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `776 + r * (3 ±0)` - // Estimated: `24004 + r * (18 ±0)` - // Minimum execution time: 234_123_000 picoseconds. - Weight::from_parts(245_872_832, 24004) - // Standard Error: 943 - .saturating_add(Weight::from_parts(136_460, 0).saturating_mul(r.into())) + // Estimated: `6723 + r * (3 ±0)` + // Minimum execution time: 234_014_000 picoseconds. + Weight::from_parts(240_042_671, 6723) + // Standard Error: 152 + .saturating_add(Weight::from_parts(138_382, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) - .saturating_add(Weight::from_parts(0, 18).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 3).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64const(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_606_000 picoseconds. - Weight::from_parts(1_845_698, 0) + // Minimum execution time: 1_533_000 picoseconds. + Weight::from_parts(1_846_015, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(2_995, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(2_935, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64load(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_711_000 picoseconds. - Weight::from_parts(2_281_581, 0) - // Standard Error: 4 - .saturating_add(Weight::from_parts(6_354, 0).saturating_mul(r.into())) + // Minimum execution time: 1_671_000 picoseconds. + Weight::from_parts(2_197_197, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(6_335, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64store(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_680_000 picoseconds. - Weight::from_parts(2_269_238, 0) - // Standard Error: 4 - .saturating_add(Weight::from_parts(6_014, 0).saturating_mul(r.into())) + // Minimum execution time: 1_665_000 picoseconds. + Weight::from_parts(2_200_545, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(6_011, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_select(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_592_000 picoseconds. - Weight::from_parts(2_010_963, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(7_927, 0).saturating_mul(r.into())) + // Minimum execution time: 1_545_000 picoseconds. + Weight::from_parts(1_977_462, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(7_901, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_if(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_631_000 picoseconds. - Weight::from_parts(1_936_549, 0) - // Standard Error: 6 - .saturating_add(Weight::from_parts(10_426, 0).saturating_mul(r.into())) + // Minimum execution time: 1_515_000 picoseconds. + Weight::from_parts(1_866_184, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(10_514, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_br(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_616_000 picoseconds. - Weight::from_parts(1_938_716, 0) - // Standard Error: 15 - .saturating_add(Weight::from_parts(4_525, 0).saturating_mul(r.into())) + // Minimum execution time: 1_618_000 picoseconds. + Weight::from_parts(1_895_104, 0) + // Standard Error: 12 + .saturating_add(Weight::from_parts(4_523, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_br_if(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_535_000 picoseconds. - Weight::from_parts(1_109_860, 0) - // Standard Error: 77 - .saturating_add(Weight::from_parts(7_998, 0).saturating_mul(r.into())) + // Minimum execution time: 1_510_000 picoseconds. + Weight::from_parts(1_779_998, 0) + // Standard Error: 8 + .saturating_add(Weight::from_parts(6_832, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_br_table(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_594_000 picoseconds. - Weight::from_parts(1_478_654, 0) - // Standard Error: 36 - .saturating_add(Weight::from_parts(9_525, 0).saturating_mul(r.into())) + // Minimum execution time: 1_529_000 picoseconds. + Weight::from_parts(1_726_996, 0) + // Standard Error: 26 + .saturating_add(Weight::from_parts(9_199, 0).saturating_mul(r.into())) } /// The range of component `e` is `[1, 256]`. fn instr_br_table_per_entry(e: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_730_000 picoseconds. - Weight::from_parts(1_836_342, 0) - // Standard Error: 14 - .saturating_add(Weight::from_parts(206, 0).saturating_mul(e.into())) + // Minimum execution time: 1_682_000 picoseconds. + Weight::from_parts(1_789_910, 0) + // Standard Error: 16 + .saturating_add(Weight::from_parts(42, 0).saturating_mul(e.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_call(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_607_000 picoseconds. - Weight::from_parts(2_150_133, 0) - // Standard Error: 17 - .saturating_add(Weight::from_parts(18_630, 0).saturating_mul(r.into())) + // Minimum execution time: 1_539_000 picoseconds. + Weight::from_parts(2_093_056, 0) + // Standard Error: 27 + .saturating_add(Weight::from_parts(18_917, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_call_indirect(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_824_000 picoseconds. - Weight::from_parts(3_119_825, 0) - // Standard Error: 15 - .saturating_add(Weight::from_parts(25_304, 0).saturating_mul(r.into())) + // Minimum execution time: 1_851_000 picoseconds. + Weight::from_parts(3_134_610, 0) + // Standard Error: 34 + .saturating_add(Weight::from_parts(24_714, 0).saturating_mul(r.into())) } /// The range of component `l` is `[0, 1024]`. fn instr_call_per_local(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_692_000 picoseconds. - Weight::from_parts(1_927_049, 0) + // Minimum execution time: 1_654_000 picoseconds. + Weight::from_parts(1_885_921, 0) // Standard Error: 14 - .saturating_add(Weight::from_parts(1_217, 0).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(1_243, 0).saturating_mul(l.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_local_get(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_795_000 picoseconds. - Weight::from_parts(3_107_843, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(2_445, 0).saturating_mul(r.into())) + // Minimum execution time: 2_744_000 picoseconds. + Weight::from_parts(3_014_725, 0) + // Standard Error: 1 + .saturating_add(Weight::from_parts(2_447, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_local_set(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_815_000 picoseconds. - Weight::from_parts(3_114_618, 0) + // Minimum execution time: 2_881_000 picoseconds. + Weight::from_parts(3_137_711, 0) // Standard Error: 3 - .saturating_add(Weight::from_parts(3_639, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_608, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_local_tee(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_861_000 picoseconds. - Weight::from_parts(3_193_592, 0) + // Minimum execution time: 2_809_000 picoseconds. + Weight::from_parts(3_142_066, 0) // Standard Error: 3 - .saturating_add(Weight::from_parts(3_957, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_841, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_global_get(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_710_000 picoseconds. - Weight::from_parts(2_148_021, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(8_391, 0).saturating_mul(r.into())) + // Minimum execution time: 1_704_000 picoseconds. + Weight::from_parts(2_083_619, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(8_366, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_global_set(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_663_000 picoseconds. - Weight::from_parts(2_170_373, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(8_812, 0).saturating_mul(r.into())) + // Minimum execution time: 1_652_000 picoseconds. + Weight::from_parts(2_048_256, 0) + // Standard Error: 5 + .saturating_add(Weight::from_parts(8_826, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_memory_current(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_662_000 picoseconds. - Weight::from_parts(2_601_398, 0) - // Standard Error: 198 - .saturating_add(Weight::from_parts(3_851, 0).saturating_mul(r.into())) + // Minimum execution time: 1_671_000 picoseconds. + Weight::from_parts(1_924_626, 0) + // Standard Error: 1 + .saturating_add(Weight::from_parts(3_746, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 16]`. fn instr_memory_grow(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_603_000 picoseconds. - Weight::from_parts(332_932, 0) - // Standard Error: 137_529 - .saturating_add(Weight::from_parts(13_233_734, 0).saturating_mul(r.into())) + // Minimum execution time: 1_585_000 picoseconds. + Weight::from_parts(490_856, 0) + // Standard Error: 133_673 + .saturating_add(Weight::from_parts(13_182_582, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64clz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_613_000 picoseconds. - Weight::from_parts(1_922_391, 0) + // Minimum execution time: 1_533_000 picoseconds. + Weight::from_parts(1_851_563, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(3_903, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_820, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64ctz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_522_000 picoseconds. - Weight::from_parts(1_920_023, 0) + // Minimum execution time: 1_564_000 picoseconds. + Weight::from_parts(1_914_178, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(3_876, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_732, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64popcnt(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_590_000 picoseconds. - Weight::from_parts(1_867_406, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(3_910, 0).saturating_mul(r.into())) + // Minimum execution time: 1_559_000 picoseconds. + Weight::from_parts(1_886_992, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(3_731, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64eqz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_577_000 picoseconds. - Weight::from_parts(1_918_037, 0) + // Minimum execution time: 1_553_000 picoseconds. + Weight::from_parts(1_886_545, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(3_673, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_658, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64extendsi32(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_589_000 picoseconds. - Weight::from_parts(1_917_901, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(3_956, 0).saturating_mul(r.into())) + // Minimum execution time: 1_507_000 picoseconds. + Weight::from_parts(1_853_647, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(3_852, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64extendui32(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_573_000 picoseconds. - Weight::from_parts(1_902_324, 0) + // Minimum execution time: 1_554_000 picoseconds. + Weight::from_parts(1_868_877, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(3_865, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_806, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i32wrapi64(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_586_000 picoseconds. - Weight::from_parts(1_953_738, 0) + // Minimum execution time: 1_514_000 picoseconds. + Weight::from_parts(1_882_233, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(3_838, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_700, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64eq(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_598_000 picoseconds. - Weight::from_parts(1_912_180, 0) + // Minimum execution time: 1_529_000 picoseconds. + Weight::from_parts(1_897_247, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(5_994, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(5_955, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64ne(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_573_000 picoseconds. - Weight::from_parts(1_943_725, 0) + // Minimum execution time: 1_513_000 picoseconds. + Weight::from_parts(1_922_333, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(5_998, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(5_933, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64lts(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_584_000 picoseconds. - Weight::from_parts(1_949_209, 0) + // Minimum execution time: 1_512_000 picoseconds. + Weight::from_parts(1_848_668, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(5_991, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(5_966, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64ltu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_576_000 picoseconds. - Weight::from_parts(1_927_466, 0) + // Minimum execution time: 1_522_000 picoseconds. + Weight::from_parts(1_875_257, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(6_005, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(5_965, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64gts(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_566_000 picoseconds. - Weight::from_parts(2_004_312, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(5_799, 0).saturating_mul(r.into())) + // Minimum execution time: 1_546_000 picoseconds. + Weight::from_parts(1_836_691, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(5_842, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64gtu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_538_000 picoseconds. - Weight::from_parts(1_922_703, 0) - // Standard Error: 9 - .saturating_add(Weight::from_parts(6_129, 0).saturating_mul(r.into())) + // Minimum execution time: 1_505_000 picoseconds. + Weight::from_parts(1_907_551, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(6_075, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64les(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_575_000 picoseconds. - Weight::from_parts(1_978_271, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(5_991, 0).saturating_mul(r.into())) + // Minimum execution time: 1_527_000 picoseconds. + Weight::from_parts(1_891_008, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(5_971, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64leu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_572_000 picoseconds. - Weight::from_parts(4_028_578, 0) - // Standard Error: 263 - .saturating_add(Weight::from_parts(5_784, 0).saturating_mul(r.into())) + // Minimum execution time: 1_556_000 picoseconds. + Weight::from_parts(1_910_864, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(6_059, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64ges(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_615_000 picoseconds. - Weight::from_parts(1_962_065, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(5_945, 0).saturating_mul(r.into())) + // Minimum execution time: 1_544_000 picoseconds. + Weight::from_parts(1_912_650, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(5_943, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64geu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_578_000 picoseconds. - Weight::from_parts(1_909_721, 0) + // Minimum execution time: 1_513_000 picoseconds. + Weight::from_parts(1_855_260, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(5_993, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(5_975, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64add(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_609_000 picoseconds. - Weight::from_parts(1_926_472, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(5_888, 0).saturating_mul(r.into())) + // Minimum execution time: 1_521_000 picoseconds. + Weight::from_parts(1_867_259, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(5_846, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64sub(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_620_000 picoseconds. - Weight::from_parts(2_875_196, 0) - // Standard Error: 177 - .saturating_add(Weight::from_parts(5_990, 0).saturating_mul(r.into())) + // Minimum execution time: 1_509_000 picoseconds. + Weight::from_parts(1_893_018, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(6_096, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64mul(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_570_000 picoseconds. - Weight::from_parts(2_155_483, 0) - // Standard Error: 83 - .saturating_add(Weight::from_parts(5_675, 0).saturating_mul(r.into())) + // Minimum execution time: 1_496_000 picoseconds. + Weight::from_parts(1_886_659, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(5_754, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64divs(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_558_000 picoseconds. - Weight::from_parts(2_108_263, 0) - // Standard Error: 5 - .saturating_add(Weight::from_parts(11_755, 0).saturating_mul(r.into())) + // Minimum execution time: 1_527_000 picoseconds. + Weight::from_parts(1_890_548, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(11_842, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64divu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_568_000 picoseconds. - Weight::from_parts(1_606_397, 0) - // Standard Error: 51 - .saturating_add(Weight::from_parts(11_011, 0).saturating_mul(r.into())) + // Minimum execution time: 1_518_000 picoseconds. + Weight::from_parts(1_891_903, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(10_613, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64rems(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_630_000 picoseconds. - Weight::from_parts(2_872_487, 0) - // Standard Error: 24 - .saturating_add(Weight::from_parts(11_761, 0).saturating_mul(r.into())) + // Minimum execution time: 1_504_000 picoseconds. + Weight::from_parts(1_632_694, 0) + // Standard Error: 7 + .saturating_add(Weight::from_parts(12_281, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64remu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_575_000 picoseconds. - Weight::from_parts(2_385_398, 0) - // Standard Error: 45 - .saturating_add(Weight::from_parts(10_650, 0).saturating_mul(r.into())) + // Minimum execution time: 1_507_000 picoseconds. + Weight::from_parts(1_878_413, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(10_737, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64and(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_622_000 picoseconds. - Weight::from_parts(1_957_246, 0) + // Minimum execution time: 1_534_000 picoseconds. + Weight::from_parts(1_898_519, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(5_659, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(5_645, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64or(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_551_000 picoseconds. - Weight::from_parts(1_897_168, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(5_774, 0).saturating_mul(r.into())) + // Minimum execution time: 1_503_000 picoseconds. + Weight::from_parts(1_895_532, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(5_745, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64xor(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_549_000 picoseconds. - Weight::from_parts(1_915_938, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(5_915, 0).saturating_mul(r.into())) + // Minimum execution time: 1_507_000 picoseconds. + Weight::from_parts(1_868_720, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(5_873, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64shl(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_617_000 picoseconds. - Weight::from_parts(1_932_618, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(5_854, 0).saturating_mul(r.into())) + // Minimum execution time: 1_513_000 picoseconds. + Weight::from_parts(1_894_207, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(5_843, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64shrs(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_617_000 picoseconds. - Weight::from_parts(1_937_566, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(6_134, 0).saturating_mul(r.into())) + // Minimum execution time: 1_473_000 picoseconds. + Weight::from_parts(1_880_224, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(6_107, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64shru(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_584_000 picoseconds. - Weight::from_parts(1_980_681, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(5_842, 0).saturating_mul(r.into())) + // Minimum execution time: 1_447_000 picoseconds. + Weight::from_parts(1_884_551, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(5_849, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64rotl(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_542_000 picoseconds. - Weight::from_parts(2_131_567, 0) - // Standard Error: 57 - .saturating_add(Weight::from_parts(6_010, 0).saturating_mul(r.into())) + // Minimum execution time: 1_538_000 picoseconds. + Weight::from_parts(1_908_813, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(5_987, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64rotr(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_609_000 picoseconds. - Weight::from_parts(1_643_214, 0) - // Standard Error: 91 - .saturating_add(Weight::from_parts(6_062, 0).saturating_mul(r.into())) + // Minimum execution time: 1_538_000 picoseconds. + Weight::from_parts(1_878_015, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(5_848, 0).saturating_mul(r.into())) } } @@ -2170,8 +2169,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `109` // Estimated: `1594` - // Minimum execution time: 2_503_000 picoseconds. - Weight::from_parts(2_603_000, 1594) + // Minimum execution time: 2_565_000 picoseconds. + Weight::from_parts(2_759_000, 1594) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: Skipped Metadata (r:0 w:0) @@ -2181,10 +2180,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `488 + k * (69 ±0)` // Estimated: `478 + k * (70 ±0)` - // Minimum execution time: 13_292_000 picoseconds. - Weight::from_parts(9_180_439, 478) - // Standard Error: 997 - .saturating_add(Weight::from_parts(967_522, 0).saturating_mul(k.into())) + // Minimum execution time: 13_480_000 picoseconds. + Weight::from_parts(10_153_869, 478) + // Standard Error: 427 + .saturating_add(Weight::from_parts(958_726, 0).saturating_mul(k.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(RocksDbWeight::get().writes(2_u64)) @@ -2199,14 +2198,14 @@ impl WeightInfo for () { fn reinstrument(c: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `238 + c * (1 ±0)` - // Estimated: `3951 + c * (2 ±0)` - // Minimum execution time: 30_822_000 picoseconds. - Weight::from_parts(26_457_115, 3951) - // Standard Error: 58 - .saturating_add(Weight::from_parts(54_868, 0).saturating_mul(c.into())) + // Estimated: `3708 + c * (1 ±0)` + // Minimum execution time: 30_406_000 picoseconds. + Weight::from_parts(28_467_370, 3708) + // Standard Error: 46 + .saturating_add(Weight::from_parts(53_724, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) - .saturating_add(Weight::from_parts(0, 2).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(0, 1).saturating_mul(c.into())) } /// Storage: Contracts ContractInfoOf (r:1 w:1) /// Proof: Contracts ContractInfoOf (max_values: None, max_size: Some(290), added: 2765, mode: Measured) @@ -2222,14 +2221,14 @@ impl WeightInfo for () { fn call_with_code_per_byte(c: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `707` - // Estimated: `21400 + c * (5 ±0)` - // Minimum execution time: 263_719_000 picoseconds. - Weight::from_parts(275_281_941, 21400) - // Standard Error: 32 - .saturating_add(Weight::from_parts(37_880, 0).saturating_mul(c.into())) + // Estimated: `6656 + c * (1 ±0)` + // Minimum execution time: 263_198_000 picoseconds. + Weight::from_parts(276_162_279, 6656) + // Standard Error: 18 + .saturating_add(Weight::from_parts(37_378, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) - .saturating_add(Weight::from_parts(0, 5).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(0, 1).saturating_mul(c.into())) } /// Storage: Contracts OwnerInfoOf (r:1 w:1) /// Proof: Contracts OwnerInfoOf (max_values: None, max_size: Some(88), added: 2563, mode: Measured) @@ -2253,15 +2252,15 @@ impl WeightInfo for () { fn instantiate_with_code(c: u32, i: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `270` - // Estimated: `26207` - // Minimum execution time: 3_133_756_000 picoseconds. - Weight::from_parts(556_483_545, 26207) - // Standard Error: 294 - .saturating_add(Weight::from_parts(107_914, 0).saturating_mul(c.into())) - // Standard Error: 17 - .saturating_add(Weight::from_parts(1_143, 0).saturating_mul(i.into())) - // Standard Error: 17 - .saturating_add(Weight::from_parts(1_456, 0).saturating_mul(s.into())) + // Estimated: `8659` + // Minimum execution time: 3_132_259_000 picoseconds. + Weight::from_parts(513_284_834, 8659) + // Standard Error: 280 + .saturating_add(Weight::from_parts(106_723, 0).saturating_mul(c.into())) + // Standard Error: 16 + .saturating_add(Weight::from_parts(1_166, 0).saturating_mul(i.into())) + // Standard Error: 16 + .saturating_add(Weight::from_parts(1_436, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(10_u64)) } @@ -2284,13 +2283,13 @@ impl WeightInfo for () { fn instantiate(i: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `482` - // Estimated: `28521` - // Minimum execution time: 1_646_953_000 picoseconds. - Weight::from_parts(262_115_215, 28521) - // Standard Error: 8 - .saturating_add(Weight::from_parts(1_454, 0).saturating_mul(i.into())) - // Standard Error: 8 - .saturating_add(Weight::from_parts(1_463, 0).saturating_mul(s.into())) + // Estimated: `6408` + // Minimum execution time: 1_646_604_000 picoseconds. + Weight::from_parts(271_369_256, 6408) + // Standard Error: 7 + .saturating_add(Weight::from_parts(1_426, 0).saturating_mul(i.into())) + // Standard Error: 7 + .saturating_add(Weight::from_parts(1_438, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } @@ -2307,9 +2306,9 @@ impl WeightInfo for () { fn call() -> Weight { // Proof Size summary in bytes: // Measured: `759` - // Estimated: `21615` - // Minimum execution time: 190_769_000 picoseconds. - Weight::from_parts(191_717_000, 21615) + // Estimated: `6699` + // Minimum execution time: 191_360_000 picoseconds. + Weight::from_parts(192_625_000, 6699) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -2325,11 +2324,11 @@ impl WeightInfo for () { fn upload_code(c: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `109` - // Estimated: `7366` - // Minimum execution time: 246_204_000 picoseconds. - Weight::from_parts(243_234_754, 7366) - // Standard Error: 78 - .saturating_add(Weight::from_parts(109_232, 0).saturating_mul(c.into())) + // Estimated: `3574` + // Minimum execution time: 245_207_000 picoseconds. + Weight::from_parts(244_703_457, 3574) + // Standard Error: 61 + .saturating_add(Weight::from_parts(106_850, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -2344,9 +2343,9 @@ impl WeightInfo for () { fn remove_code() -> Weight { // Proof Size summary in bytes: // Measured: `255` - // Estimated: `7950` - // Minimum execution time: 33_516_000 picoseconds. - Weight::from_parts(33_995_000, 7950) + // Estimated: `3720` + // Minimum execution time: 33_560_000 picoseconds. + Weight::from_parts(33_833_000, 3720) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -2359,9 +2358,9 @@ impl WeightInfo for () { fn set_code() -> Weight { // Proof Size summary in bytes: // Measured: `570` - // Estimated: `19530` - // Minimum execution time: 33_255_000 picoseconds. - Weight::from_parts(33_692_000, 19530) + // Estimated: `8985` + // Minimum execution time: 33_288_000 picoseconds. + Weight::from_parts(33_775_000, 8985) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -2379,14 +2378,14 @@ impl WeightInfo for () { fn seal_caller(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `781 + r * (6 ±0)` - // Estimated: `21730 + r * (30 ±0)` - // Minimum execution time: 235_074_000 picoseconds. - Weight::from_parts(243_735_179, 21730) - // Standard Error: 972 - .saturating_add(Weight::from_parts(328_571, 0).saturating_mul(r.into())) + // Estimated: `6722 + r * (6 ±0)` + // Minimum execution time: 234_292_000 picoseconds. + Weight::from_parts(235_941_911, 6722) + // Standard Error: 413 + .saturating_add(Weight::from_parts(339_913, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2402,15 +2401,15 @@ impl WeightInfo for () { fn seal_is_contract(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `839 + r * (240 ±0)` - // Estimated: `21835 + r * (3675 ±0)` - // Minimum execution time: 236_455_000 picoseconds. - Weight::from_parts(81_818_936, 21835) - // Standard Error: 5_874 - .saturating_add(Weight::from_parts(3_316_006, 0).saturating_mul(r.into())) + // Estimated: `6743 + r * (2715 ±0)` + // Minimum execution time: 236_273_000 picoseconds. + Weight::from_parts(74_380_906, 6743) + // Standard Error: 5_745 + .saturating_add(Weight::from_parts(3_331_781, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 3675).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 2715).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2426,15 +2425,15 @@ impl WeightInfo for () { fn seal_code_hash(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `831 + r * (244 ±0)` - // Estimated: `21855 + r * (3695 ±0)` - // Minimum execution time: 237_724_000 picoseconds. - Weight::from_parts(91_384_964, 21855) - // Standard Error: 5_828 - .saturating_add(Weight::from_parts(4_063_221, 0).saturating_mul(r.into())) + // Estimated: `6747 + r * (2719 ±0)` + // Minimum execution time: 236_573_000 picoseconds. + Weight::from_parts(82_473_906, 6747) + // Standard Error: 5_510 + .saturating_add(Weight::from_parts(4_131_820, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 3695).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 2719).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2450,14 +2449,14 @@ impl WeightInfo for () { fn seal_own_code_hash(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `788 + r * (6 ±0)` - // Estimated: `21770 + r * (30 ±0)` - // Minimum execution time: 236_144_000 picoseconds. - Weight::from_parts(239_917_873, 21770) - // Standard Error: 629 - .saturating_add(Weight::from_parts(409_752, 0).saturating_mul(r.into())) + // Estimated: `6730 + r * (6 ±0)` + // Minimum execution time: 235_878_000 picoseconds. + Weight::from_parts(238_387_359, 6730) + // Standard Error: 318 + .saturating_add(Weight::from_parts(409_923, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2473,14 +2472,14 @@ impl WeightInfo for () { fn seal_caller_is_origin(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `778 + r * (3 ±0)` - // Estimated: `21735 + r * (15 ±0)` - // Minimum execution time: 232_946_000 picoseconds. - Weight::from_parts(243_163_112, 21735) - // Standard Error: 1_940 - .saturating_add(Weight::from_parts(162_705, 0).saturating_mul(r.into())) + // Estimated: `6723 + r * (3 ±0)` + // Minimum execution time: 233_476_000 picoseconds. + Weight::from_parts(238_014_452, 6723) + // Standard Error: 145 + .saturating_add(Weight::from_parts(165_823, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 15).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 3).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2496,14 +2495,14 @@ impl WeightInfo for () { fn seal_address(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `782 + r * (6 ±0)` - // Estimated: `21740 + r * (30 ±0)` - // Minimum execution time: 235_301_000 picoseconds. - Weight::from_parts(240_802_312, 21740) - // Standard Error: 5_362 - .saturating_add(Weight::from_parts(339_001, 0).saturating_mul(r.into())) + // Estimated: `6724 + r * (6 ±0)` + // Minimum execution time: 235_490_000 picoseconds. + Weight::from_parts(240_039_685, 6724) + // Standard Error: 330 + .saturating_add(Weight::from_parts(332_291, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2519,14 +2518,14 @@ impl WeightInfo for () { fn seal_gas_left(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `783 + r * (6 ±0)` - // Estimated: `21725 + r * (30 ±0)` - // Minimum execution time: 235_683_000 picoseconds. - Weight::from_parts(237_357_276, 21725) - // Standard Error: 726 - .saturating_add(Weight::from_parts(333_264, 0).saturating_mul(r.into())) + // Estimated: `6721 + r * (6 ±0)` + // Minimum execution time: 236_093_000 picoseconds. + Weight::from_parts(238_513_328, 6721) + // Standard Error: 206 + .saturating_add(Weight::from_parts(328_899, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) } /// Storage: System Account (r:2 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2542,14 +2541,14 @@ impl WeightInfo for () { fn seal_balance(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `922 + r * (6 ±0)` - // Estimated: `24633 + r * (30 ±0)` - // Minimum execution time: 234_327_000 picoseconds. - Weight::from_parts(239_792_456, 24633) - // Standard Error: 3_460 - .saturating_add(Weight::from_parts(1_496_090, 0).saturating_mul(r.into())) + // Estimated: `6846 + r * (6 ±0)` + // Minimum execution time: 234_801_000 picoseconds. + Weight::from_parts(243_519_159, 6846) + // Standard Error: 1_367 + .saturating_add(Weight::from_parts(1_449_599, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2565,14 +2564,14 @@ impl WeightInfo for () { fn seal_value_transferred(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `792 + r * (6 ±0)` - // Estimated: `21825 + r * (30 ±0)` - // Minimum execution time: 235_466_000 picoseconds. - Weight::from_parts(242_580_658, 21825) - // Standard Error: 1_439 - .saturating_add(Weight::from_parts(323_842, 0).saturating_mul(r.into())) + // Estimated: `6741 + r * (6 ±0)` + // Minimum execution time: 236_765_000 picoseconds. + Weight::from_parts(237_843_244, 6741) + // Standard Error: 308 + .saturating_add(Weight::from_parts(329_911, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2588,14 +2587,14 @@ impl WeightInfo for () { fn seal_minimum_balance(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `790 + r * (6 ±0)` - // Estimated: `21815 + r * (30 ±0)` - // Minimum execution time: 238_529_000 picoseconds. - Weight::from_parts(249_276_722, 21815) - // Standard Error: 1_216 - .saturating_add(Weight::from_parts(328_600, 0).saturating_mul(r.into())) + // Estimated: `6739 + r * (6 ±0)` + // Minimum execution time: 236_690_000 picoseconds. + Weight::from_parts(241_743_164, 6739) + // Standard Error: 333 + .saturating_add(Weight::from_parts(324_693, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2611,14 +2610,14 @@ impl WeightInfo for () { fn seal_block_number(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `787 + r * (6 ±0)` - // Estimated: `21805 + r * (30 ±0)` - // Minimum execution time: 234_360_000 picoseconds. - Weight::from_parts(239_927_876, 21805) - // Standard Error: 541 - .saturating_add(Weight::from_parts(319_553, 0).saturating_mul(r.into())) + // Estimated: `6737 + r * (6 ±0)` + // Minimum execution time: 236_149_000 picoseconds. + Weight::from_parts(239_090_707, 6737) + // Standard Error: 246 + .saturating_add(Weight::from_parts(344_488, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2634,14 +2633,14 @@ impl WeightInfo for () { fn seal_now(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `778 + r * (6 ±0)` - // Estimated: `21735 + r * (30 ±0)` - // Minimum execution time: 234_461_000 picoseconds. - Weight::from_parts(239_682_633, 21735) - // Standard Error: 544 - .saturating_add(Weight::from_parts(322_943, 0).saturating_mul(r.into())) + // Estimated: `6723 + r * (6 ±0)` + // Minimum execution time: 235_057_000 picoseconds. + Weight::from_parts(237_752_870, 6723) + // Standard Error: 236 + .saturating_add(Weight::from_parts(328_235, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2659,14 +2658,14 @@ impl WeightInfo for () { fn seal_weight_to_fee(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `856 + r * (10 ±0)` - // Estimated: `24446 + r * (60 ±0)` - // Minimum execution time: 234_862_000 picoseconds. - Weight::from_parts(252_614_390, 24446) - // Standard Error: 1_180 - .saturating_add(Weight::from_parts(1_313_286, 0).saturating_mul(r.into())) + // Estimated: `6796 + r * (10 ±0)` + // Minimum execution time: 234_995_000 picoseconds. + Weight::from_parts(246_473_554, 6796) + // Standard Error: 1_015 + .saturating_add(Weight::from_parts(1_337_653, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 60).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 10).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2682,14 +2681,14 @@ impl WeightInfo for () { fn seal_gas(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `745 + r * (4 ±0)` - // Estimated: `21555 + r * (20 ±0)` - // Minimum execution time: 161_003_000 picoseconds. - Weight::from_parts(165_793_675, 21555) - // Standard Error: 323 - .saturating_add(Weight::from_parts(128_941, 0).saturating_mul(r.into())) + // Estimated: `6687 + r * (4 ±0)` + // Minimum execution time: 160_445_000 picoseconds. + Weight::from_parts(165_558_135, 6687) + // Standard Error: 234 + .saturating_add(Weight::from_parts(133_607, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 20).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 4).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2705,14 +2704,14 @@ impl WeightInfo for () { fn seal_input(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `780 + r * (6 ±0)` - // Estimated: `21740 + r * (30 ±0)` - // Minimum execution time: 235_192_000 picoseconds. - Weight::from_parts(241_225_671, 21740) - // Standard Error: 1_132 - .saturating_add(Weight::from_parts(272_760, 0).saturating_mul(r.into())) + // Estimated: `6724 + r * (6 ±0)` + // Minimum execution time: 235_065_000 picoseconds. + Weight::from_parts(237_797_177, 6724) + // Standard Error: 336 + .saturating_add(Weight::from_parts(267_302, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 30).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2728,11 +2727,11 @@ impl WeightInfo for () { fn seal_input_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `784` - // Estimated: `21740` - // Minimum execution time: 238_050_000 picoseconds. - Weight::from_parts(241_274_832, 21740) - // Standard Error: 1 - .saturating_add(Weight::from_parts(590, 0).saturating_mul(n.into())) + // Estimated: `6724` + // Minimum execution time: 236_215_000 picoseconds. + Weight::from_parts(239_347_313, 6724) + // Standard Error: 0 + .saturating_add(Weight::from_parts(587, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -2750,14 +2749,14 @@ impl WeightInfo for () { fn seal_return(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `768 + r * (45 ±0)` - // Estimated: `21660 + r * (225 ±0)` - // Minimum execution time: 231_807_000 picoseconds. - Weight::from_parts(234_264_848, 21660) - // Standard Error: 185_298 - .saturating_add(Weight::from_parts(1_000_351, 0).saturating_mul(r.into())) + // Estimated: `6708 + r * (45 ±0)` + // Minimum execution time: 231_571_000 picoseconds. + Weight::from_parts(233_477_918, 6708) + // Standard Error: 95_776 + .saturating_add(Weight::from_parts(1_733_181, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 225).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 45).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2773,11 +2772,11 @@ impl WeightInfo for () { fn seal_return_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `778` - // Estimated: `21775` - // Minimum execution time: 234_347_000 picoseconds. - Weight::from_parts(234_774_467, 21775) + // Estimated: `6731` + // Minimum execution time: 234_956_000 picoseconds. + Weight::from_parts(236_785_051, 6731) // Standard Error: 0 - .saturating_add(Weight::from_parts(183, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(177, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -2801,16 +2800,16 @@ impl WeightInfo for () { fn seal_terminate(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `810 + r * (356 ±0)` - // Estimated: `26094 + r * (15904 ±0)` - // Minimum execution time: 234_356_000 picoseconds. - Weight::from_parts(236_844_659, 26094) - // Standard Error: 161_035 - .saturating_add(Weight::from_parts(110_725_340, 0).saturating_mul(r.into())) + // Estimated: `6750 + r * (7781 ±0)` + // Minimum execution time: 234_275_000 picoseconds. + Weight::from_parts(236_776_769, 6750) + // Standard Error: 137_203 + .saturating_add(Weight::from_parts(110_758_930, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((6_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((8_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 15904).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 7781).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2828,14 +2827,14 @@ impl WeightInfo for () { fn seal_random(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `825 + r * (10 ±0)` - // Estimated: `24283 + r * (60 ±0)` - // Minimum execution time: 234_248_000 picoseconds. - Weight::from_parts(255_712_101, 24283) - // Standard Error: 1_474 - .saturating_add(Weight::from_parts(1_753_943, 0).saturating_mul(r.into())) + // Estimated: `6769 + r * (10 ±0)` + // Minimum execution time: 235_593_000 picoseconds. + Weight::from_parts(253_731_242, 6769) + // Standard Error: 2_129 + .saturating_add(Weight::from_parts(1_771_297, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 60).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 10).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2851,14 +2850,14 @@ impl WeightInfo for () { fn seal_deposit_event(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `778 + r * (10 ±0)` - // Estimated: `21735 + r * (50 ±0)` - // Minimum execution time: 232_456_000 picoseconds. - Weight::from_parts(230_738_907, 21735) - // Standard Error: 4_163 - .saturating_add(Weight::from_parts(3_496_817, 0).saturating_mul(r.into())) + // Estimated: `6723 + r * (10 ±0)` + // Minimum execution time: 232_124_000 picoseconds. + Weight::from_parts(245_904_447, 6723) + // Standard Error: 2_185 + .saturating_add(Weight::from_parts(3_470_410, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 50).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 10).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2875,18 +2874,18 @@ impl WeightInfo for () { fn seal_deposit_event_per_topic_and_byte(t: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `797 + t * (32 ±0)` - // Estimated: `21840 + t * (2640 ±0)` - // Minimum execution time: 251_638_000 picoseconds. - Weight::from_parts(244_791_817, 21840) - // Standard Error: 89_537 - .saturating_add(Weight::from_parts(2_459_492, 0).saturating_mul(t.into())) - // Standard Error: 25 - .saturating_add(Weight::from_parts(626, 0).saturating_mul(n.into())) + // Estimated: `6744 + t * (2508 ±0)` + // Minimum execution time: 250_301_000 picoseconds. + Weight::from_parts(245_292_258, 6744) + // Standard Error: 29_864 + .saturating_add(Weight::from_parts(2_163_531, 0).saturating_mul(t.into())) + // Standard Error: 8 + .saturating_add(Weight::from_parts(583, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(t.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(t.into()))) - .saturating_add(Weight::from_parts(0, 2640).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(0, 2508).saturating_mul(t.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -2902,14 +2901,14 @@ impl WeightInfo for () { fn seal_debug_message(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `777 + r * (7 ±0)` - // Estimated: `21725 + r * (35 ±0)` - // Minimum execution time: 164_736_000 picoseconds. - Weight::from_parts(164_496_597, 21725) - // Standard Error: 4_619 - .saturating_add(Weight::from_parts(252_013, 0).saturating_mul(r.into())) + // Estimated: `6721 + r * (7 ±0)` + // Minimum execution time: 165_711_000 picoseconds. + Weight::from_parts(168_792_571, 6721) + // Standard Error: 216 + .saturating_add(Weight::from_parts(230_285, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 35).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 7).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) @@ -2925,11 +2924,11 @@ impl WeightInfo for () { fn seal_debug_message_per_byte(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `125728` - // Estimated: `269977` - // Minimum execution time: 352_146_000 picoseconds. - Weight::from_parts(357_758_251, 269977) - // Standard Error: 1 - .saturating_add(Weight::from_parts(735, 0).saturating_mul(i.into())) + // Estimated: `131670` + // Minimum execution time: 348_928_000 picoseconds. + Weight::from_parts(352_224_793, 131670) + // Standard Error: 0 + .saturating_add(Weight::from_parts(731, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -2940,10 +2939,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `845 + r * (292 ±0)` // Estimated: `843 + r * (293 ±0)` - // Minimum execution time: 236_170_000 picoseconds. - Weight::from_parts(136_284_582, 843) - // Standard Error: 10_269 - .saturating_add(Weight::from_parts(5_995_228, 0).saturating_mul(r.into())) + // Minimum execution time: 236_418_000 picoseconds. + Weight::from_parts(129_862_840, 843) + // Standard Error: 9_733 + .saturating_add(Weight::from_parts(6_005_187, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -2957,10 +2956,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1304` // Estimated: `1280` - // Minimum execution time: 253_837_000 picoseconds. - Weight::from_parts(287_029_261, 1280) - // Standard Error: 51 - .saturating_add(Weight::from_parts(534, 0).saturating_mul(n.into())) + // Minimum execution time: 251_599_000 picoseconds. + Weight::from_parts(285_284_665, 1280) + // Standard Error: 46 + .saturating_add(Weight::from_parts(410, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -2971,10 +2970,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1167 + n * (1 ±0)` // Estimated: `1167 + n * (1 ±0)` - // Minimum execution time: 253_037_000 picoseconds. - Weight::from_parts(256_401_533, 1167) - // Standard Error: 18 - .saturating_add(Weight::from_parts(32, 0).saturating_mul(n.into())) + // Minimum execution time: 251_309_000 picoseconds. + Weight::from_parts(253_555_552, 1167) + // Standard Error: 9 + .saturating_add(Weight::from_parts(27, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -2986,10 +2985,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `841 + r * (288 ±0)` // Estimated: `845 + r * (289 ±0)` - // Minimum execution time: 236_800_000 picoseconds. - Weight::from_parts(134_748_031, 845) - // Standard Error: 9_560 - .saturating_add(Weight::from_parts(5_923_187, 0).saturating_mul(r.into())) + // Minimum execution time: 235_441_000 picoseconds. + Weight::from_parts(132_980_942, 845) + // Standard Error: 9_421 + .saturating_add(Weight::from_parts(5_854_896, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3003,9 +3002,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1163 + n * (1 ±0)` // Estimated: `1163 + n * (1 ±0)` - // Minimum execution time: 250_601_000 picoseconds. - Weight::from_parts(253_618_803, 1163) - // Standard Error: 18 + // Minimum execution time: 249_967_000 picoseconds. + Weight::from_parts(252_122_186, 1163) + // Standard Error: 10 .saturating_add(Weight::from_parts(74, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) @@ -3018,10 +3017,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `835 + r * (296 ±0)` // Estimated: `840 + r * (297 ±0)` - // Minimum execution time: 236_194_000 picoseconds. - Weight::from_parts(152_630_909, 840) - // Standard Error: 8_573 - .saturating_add(Weight::from_parts(4_896_099, 0).saturating_mul(r.into())) + // Minimum execution time: 235_647_000 picoseconds. + Weight::from_parts(145_525_169, 840) + // Standard Error: 8_553 + .saturating_add(Weight::from_parts(4_948_021, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3034,10 +3033,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1179 + n * (1 ±0)` // Estimated: `1179 + n * (1 ±0)` - // Minimum execution time: 250_989_000 picoseconds. - Weight::from_parts(260_170_747, 1179) - // Standard Error: 162 - .saturating_add(Weight::from_parts(224, 0).saturating_mul(n.into())) + // Minimum execution time: 249_576_000 picoseconds. + Weight::from_parts(250_747_191, 1179) + // Standard Error: 8 + .saturating_add(Weight::from_parts(717, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -3049,10 +3048,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `856 + r * (288 ±0)` // Estimated: `857 + r * (289 ±0)` - // Minimum execution time: 236_574_000 picoseconds. - Weight::from_parts(155_573_955, 857) - // Standard Error: 10_270 - .saturating_add(Weight::from_parts(4_667_644, 0).saturating_mul(r.into())) + // Minimum execution time: 236_110_000 picoseconds. + Weight::from_parts(148_420_625, 857) + // Standard Error: 8_175 + .saturating_add(Weight::from_parts(4_684_126, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3065,10 +3064,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1166 + n * (1 ±0)` // Estimated: `1166 + n * (1 ±0)` - // Minimum execution time: 249_502_000 picoseconds. - Weight::from_parts(251_496_311, 1166) - // Standard Error: 26 - .saturating_add(Weight::from_parts(186, 0).saturating_mul(n.into())) + // Minimum execution time: 247_800_000 picoseconds. + Weight::from_parts(249_410_575, 1166) + // Standard Error: 6 + .saturating_add(Weight::from_parts(99, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -3080,10 +3079,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `829 + r * (296 ±0)` // Estimated: `836 + r * (297 ±0)` - // Minimum execution time: 236_030_000 picoseconds. - Weight::from_parts(128_595_856, 836) - // Standard Error: 10_530 - .saturating_add(Weight::from_parts(6_072_638, 0).saturating_mul(r.into())) + // Minimum execution time: 235_251_000 picoseconds. + Weight::from_parts(128_816_707, 836) + // Standard Error: 9_887 + .saturating_add(Weight::from_parts(6_167_176, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3097,10 +3096,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1180 + n * (1 ±0)` // Estimated: `1180 + n * (1 ±0)` - // Minimum execution time: 254_027_000 picoseconds. - Weight::from_parts(260_739_475, 1180) - // Standard Error: 115 - .saturating_add(Weight::from_parts(330, 0).saturating_mul(n.into())) + // Minimum execution time: 250_401_000 picoseconds. + Weight::from_parts(253_298_243, 1180) + // Standard Error: 9 + .saturating_add(Weight::from_parts(667, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -3119,16 +3118,16 @@ impl WeightInfo for () { fn seal_transfer(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `1373 + r * (45 ±0)` - // Estimated: `26753 + r * (2700 ±0)` - // Minimum execution time: 237_634_000 picoseconds. - Weight::from_parts(238_177_000, 26753) - // Standard Error: 23_320 - .saturating_add(Weight::from_parts(35_467_618, 0).saturating_mul(r.into())) + // Estimated: `7270 + r * (2520 ±0)` + // Minimum execution time: 236_470_000 picoseconds. + Weight::from_parts(98_898_727, 7270) + // Standard Error: 33_316 + .saturating_add(Weight::from_parts(35_149_946, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 2700).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 2520).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3144,16 +3143,16 @@ impl WeightInfo for () { fn seal_call(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `1237 + r * (256 ±0)` - // Estimated: `26028 + r * (6235 ±0)` - // Minimum execution time: 237_076_000 picoseconds. - Weight::from_parts(237_792_000, 26028) - // Standard Error: 91_566 - .saturating_add(Weight::from_parts(212_893_975, 0).saturating_mul(r.into())) + // Estimated: `7125 + r * (2732 ±0)` + // Minimum execution time: 238_303_000 picoseconds. + Weight::from_parts(239_024_000, 7125) + // Standard Error: 65_907 + .saturating_add(Weight::from_parts(209_419_071, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((2_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 6235).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 2732).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3169,16 +3168,16 @@ impl WeightInfo for () { fn seal_delegate_call(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + r * (502 ±0)` - // Estimated: `21755 + r * (6329 ±3)` - // Minimum execution time: 236_275_000 picoseconds. - Weight::from_parts(236_849_000, 21755) - // Standard Error: 92_724 - .saturating_add(Weight::from_parts(207_159_396, 0).saturating_mul(r.into())) + // Estimated: `6727 + r * (2572 ±10)` + // Minimum execution time: 235_961_000 picoseconds. + Weight::from_parts(236_939_000, 6727) + // Standard Error: 83_087 + .saturating_add(Weight::from_parts(205_646_517, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 6329).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 2572).saturating_mul(r.into())) } /// Storage: System Account (r:3 w:2) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3195,18 +3194,18 @@ impl WeightInfo for () { fn seal_call_per_transfer_clone_byte(t: u32, c: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `1154 + t * (204 ±0)` - // Estimated: `31015 + t * (5970 ±0)` - // Minimum execution time: 412_628_000 picoseconds. - Weight::from_parts(385_108_035, 31015) - // Standard Error: 1_002_078 - .saturating_add(Weight::from_parts(31_204_678, 0).saturating_mul(t.into())) - // Standard Error: 1 - .saturating_add(Weight::from_parts(598, 0).saturating_mul(c.into())) + // Estimated: `9569 + t * (5154 ±0)` + // Minimum execution time: 410_156_000 picoseconds. + Weight::from_parts(378_378_143, 9569) + // Standard Error: 285_172 + .saturating_add(Weight::from_parts(34_736_740, 0).saturating_mul(t.into())) + // Standard Error: 0 + .saturating_add(Weight::from_parts(591, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(t.into()))) .saturating_add(RocksDbWeight::get().writes(5_u64)) .saturating_add(RocksDbWeight::get().writes((2_u64).saturating_mul(t.into()))) - .saturating_add(Weight::from_parts(0, 5970).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(0, 5154).saturating_mul(t.into())) } /// Storage: System Account (r:1602 w:1602) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3226,16 +3225,16 @@ impl WeightInfo for () { fn seal_instantiate(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `1301 + r * (254 ±0)` - // Estimated: `30977 + r * (16635 ±0)` - // Minimum execution time: 237_161_000 picoseconds. - Weight::from_parts(237_620_000, 30977) - // Standard Error: 258_036 - .saturating_add(Weight::from_parts(344_869_637, 0).saturating_mul(r.into())) + // Estimated: `7131 + r * (5205 ±0)` + // Minimum execution time: 236_748_000 picoseconds. + Weight::from_parts(237_129_000, 7131) + // Standard Error: 280_059 + .saturating_add(Weight::from_parts(341_428_013, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().reads((6_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(6_u64)) .saturating_add(RocksDbWeight::get().writes((5_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 16635).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 5205).saturating_mul(r.into())) } /// Storage: System Account (r:4 w:4) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3257,20 +3256,20 @@ impl WeightInfo for () { fn seal_instantiate_per_transfer_input_salt_byte(t: u32, i: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `1071 + t * (187 ±0)` - // Estimated: `42684 + t * (3588 ±2)` - // Minimum execution time: 1_613_172_000 picoseconds. - Weight::from_parts(326_952_137, 42684) - // Standard Error: 4_738_925 - .saturating_add(Weight::from_parts(113_657_996, 0).saturating_mul(t.into())) - // Standard Error: 7 - .saturating_add(Weight::from_parts(1_173, 0).saturating_mul(i.into())) - // Standard Error: 7 - .saturating_add(Weight::from_parts(1_347, 0).saturating_mul(s.into())) + // Estimated: `9492 + t * (2634 ±2)` + // Minimum execution time: 1_613_796_000 picoseconds. + Weight::from_parts(340_002_206, 9492) + // Standard Error: 4_296_381 + .saturating_add(Weight::from_parts(115_239_834, 0).saturating_mul(t.into())) + // Standard Error: 6 + .saturating_add(Weight::from_parts(1_145, 0).saturating_mul(i.into())) + // Standard Error: 6 + .saturating_add(Weight::from_parts(1_315, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(13_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(t.into()))) .saturating_add(RocksDbWeight::get().writes(10_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(t.into()))) - .saturating_add(Weight::from_parts(0, 3588).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(0, 2634).saturating_mul(t.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3286,14 +3285,14 @@ impl WeightInfo for () { fn seal_hash_sha2_256(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `777 + r * (8 ±0)` - // Estimated: `21710 + r * (40 ±0)` - // Minimum execution time: 233_679_000 picoseconds. - Weight::from_parts(238_638_820, 21710) - // Standard Error: 681 - .saturating_add(Weight::from_parts(573_320, 0).saturating_mul(r.into())) + // Estimated: `6718 + r * (8 ±0)` + // Minimum execution time: 233_111_000 picoseconds. + Weight::from_parts(238_643_933, 6718) + // Standard Error: 184 + .saturating_add(Weight::from_parts(572_296, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 8).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3309,11 +3308,11 @@ impl WeightInfo for () { fn seal_hash_sha2_256_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `785` - // Estimated: `21745` - // Minimum execution time: 235_992_000 picoseconds. - Weight::from_parts(219_924_252, 21745) - // Standard Error: 5 - .saturating_add(Weight::from_parts(3_978, 0).saturating_mul(n.into())) + // Estimated: `6725` + // Minimum execution time: 234_746_000 picoseconds. + Weight::from_parts(229_815_552, 6725) + // Standard Error: 1 + .saturating_add(Weight::from_parts(3_892, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3331,14 +3330,14 @@ impl WeightInfo for () { fn seal_hash_keccak_256(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `779 + r * (8 ±0)` - // Estimated: `21725 + r * (40 ±0)` - // Minimum execution time: 240_661_000 picoseconds. - Weight::from_parts(238_809_422, 21725) - // Standard Error: 820 - .saturating_add(Weight::from_parts(741_326, 0).saturating_mul(r.into())) + // Estimated: `6721 + r * (8 ±0)` + // Minimum execution time: 232_732_000 picoseconds. + Weight::from_parts(239_007_209, 6721) + // Standard Error: 256 + .saturating_add(Weight::from_parts(733_879, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 8).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3354,11 +3353,11 @@ impl WeightInfo for () { fn seal_hash_keccak_256_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `787` - // Estimated: `21765` - // Minimum execution time: 235_136_000 picoseconds. - Weight::from_parts(228_678_487, 21765) - // Standard Error: 2 - .saturating_add(Weight::from_parts(3_164, 0).saturating_mul(n.into())) + // Estimated: `6729` + // Minimum execution time: 234_184_000 picoseconds. + Weight::from_parts(227_603_375, 6729) + // Standard Error: 1 + .saturating_add(Weight::from_parts(3_127, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3376,14 +3375,14 @@ impl WeightInfo for () { fn seal_hash_blake2_256(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `779 + r * (8 ±0)` - // Estimated: `21740 + r * (40 ±0)` - // Minimum execution time: 233_364_000 picoseconds. - Weight::from_parts(243_294_285, 21740) - // Standard Error: 1_607 - .saturating_add(Weight::from_parts(413_186, 0).saturating_mul(r.into())) + // Estimated: `6724 + r * (8 ±0)` + // Minimum execution time: 233_038_000 picoseconds. + Weight::from_parts(238_515_817, 6724) + // Standard Error: 255 + .saturating_add(Weight::from_parts(413_343, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 8).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3399,11 +3398,11 @@ impl WeightInfo for () { fn seal_hash_blake2_256_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `787` - // Estimated: `21785` - // Minimum execution time: 234_315_000 picoseconds. - Weight::from_parts(225_569_537, 21785) + // Estimated: `6733` + // Minimum execution time: 232_996_000 picoseconds. + Weight::from_parts(226_706_997, 6733) // Standard Error: 1 - .saturating_add(Weight::from_parts(919, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(908, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3421,14 +3420,14 @@ impl WeightInfo for () { fn seal_hash_blake2_128(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `779 + r * (8 ±0)` - // Estimated: `21745 + r * (40 ±0)` - // Minimum execution time: 233_288_000 picoseconds. - Weight::from_parts(239_289_154, 21745) - // Standard Error: 612 - .saturating_add(Weight::from_parts(414_275, 0).saturating_mul(r.into())) + // Estimated: `6725 + r * (8 ±0)` + // Minimum execution time: 232_292_000 picoseconds. + Weight::from_parts(237_997_001, 6725) + // Standard Error: 219 + .saturating_add(Weight::from_parts(410_177, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 8).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3444,11 +3443,11 @@ impl WeightInfo for () { fn seal_hash_blake2_128_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `787` - // Estimated: `21755` - // Minimum execution time: 233_686_000 picoseconds. - Weight::from_parts(227_406_694, 21755) + // Estimated: `6727` + // Minimum execution time: 234_815_000 picoseconds. + Weight::from_parts(226_317_150, 6727) // Standard Error: 1 - .saturating_add(Weight::from_parts(919, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(911, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3465,15 +3464,15 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 125697]`. fn seal_sr25519_verify_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `916 + n * (1 ±0)` - // Estimated: `22375 + n * (5 ±0)` - // Minimum execution time: 287_258_000 picoseconds. - Weight::from_parts(290_941_609, 22375) - // Standard Error: 8 - .saturating_add(Weight::from_parts(4_785, 0).saturating_mul(n.into())) + // Measured: `912 + n * (1 ±0)` + // Estimated: `6848 + n * (1 ±0)` + // Minimum execution time: 286_323_000 picoseconds. + Weight::from_parts(290_287_955, 6848) + // Standard Error: 1 + .saturating_add(Weight::from_parts(4_693, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 5).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3488,15 +3487,15 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 160]`. fn seal_sr25519_verify(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `728 + r * (112 ±0)` - // Estimated: `21455 + r * (560 ±0)` - // Minimum execution time: 238_340_000 picoseconds. - Weight::from_parts(246_009_851, 21455) - // Standard Error: 21_677 - .saturating_add(Weight::from_parts(48_139_487, 0).saturating_mul(r.into())) + // Measured: `727 + r * (112 ±0)` + // Estimated: `6666 + r * (112 ±0)` + // Minimum execution time: 235_938_000 picoseconds. + Weight::from_parts(242_728_358, 6666) + // Standard Error: 9_725 + .saturating_add(Weight::from_parts(47_527_740, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 560).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 112).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3512,14 +3511,14 @@ impl WeightInfo for () { fn seal_ecdsa_recover(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `822 + r * (76 ±0)` - // Estimated: `21705 + r * (385 ±0)` - // Minimum execution time: 236_244_000 picoseconds. - Weight::from_parts(253_749_242, 21705) - // Standard Error: 19_216 - .saturating_add(Weight::from_parts(37_706_782, 0).saturating_mul(r.into())) + // Estimated: `6716 + r * (77 ±0)` + // Minimum execution time: 236_108_000 picoseconds. + Weight::from_parts(248_577_226, 6716) + // Standard Error: 9_565 + .saturating_add(Weight::from_parts(36_733_552, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 385).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 77).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3535,14 +3534,14 @@ impl WeightInfo for () { fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `792 + r * (42 ±0)` - // Estimated: `21775 + r * (210 ±0)` - // Minimum execution time: 235_770_000 picoseconds. - Weight::from_parts(230_780_347, 21775) - // Standard Error: 12_015 - .saturating_add(Weight::from_parts(9_584_947, 0).saturating_mul(r.into())) + // Estimated: `6731 + r * (42 ±0)` + // Minimum execution time: 236_440_000 picoseconds. + Weight::from_parts(240_771_418, 6731) + // Standard Error: 1_849 + .saturating_add(Weight::from_parts(9_185_896, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 210).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 42).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3560,16 +3559,16 @@ impl WeightInfo for () { fn seal_set_code_hash(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + r * (964 ±0)` - // Estimated: `29920 + r * (11544 ±7)` - // Minimum execution time: 235_857_000 picoseconds. - Weight::from_parts(236_482_000, 29920) - // Standard Error: 47_818 - .saturating_add(Weight::from_parts(21_765_273, 0).saturating_mul(r.into())) + // Estimated: `8190 + r * (3090 ±10)` + // Minimum execution time: 235_056_000 picoseconds. + Weight::from_parts(235_743_000, 8190) + // Standard Error: 46_122 + .saturating_add(Weight::from_parts(21_447_984, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((2_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 11544).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 3090).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3585,14 +3584,14 @@ impl WeightInfo for () { fn seal_reentrance_count(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `773 + r * (3 ±0)` - // Estimated: `21735 + r * (15 ±0)` - // Minimum execution time: 235_388_000 picoseconds. - Weight::from_parts(240_149_512, 21735) - // Standard Error: 555 - .saturating_add(Weight::from_parts(162_666, 0).saturating_mul(r.into())) + // Estimated: `6723 + r * (3 ±0)` + // Minimum execution time: 235_213_000 picoseconds. + Weight::from_parts(239_456_464, 6723) + // Standard Error: 130 + .saturating_add(Weight::from_parts(159_851, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 15).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 3).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3608,14 +3607,14 @@ impl WeightInfo for () { fn seal_account_reentrance_count(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `1975 + r * (39 ±0)` - // Estimated: `27145 + r * (200 ±0)` - // Minimum execution time: 237_485_000 picoseconds. - Weight::from_parts(268_044_053, 27145) - // Standard Error: 1_147 - .saturating_add(Weight::from_parts(260_572, 0).saturating_mul(r.into())) + // Estimated: `7805 + r * (40 ±0)` + // Minimum execution time: 237_886_000 picoseconds. + Weight::from_parts(262_430_157, 7805) + // Standard Error: 939 + .saturating_add(Weight::from_parts(260_005, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 200).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) } /// Storage: System Account (r:1 w:0) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: Measured) @@ -3633,523 +3632,523 @@ impl WeightInfo for () { fn seal_instantiation_nonce(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `776 + r * (3 ±0)` - // Estimated: `24004 + r * (18 ±0)` - // Minimum execution time: 234_123_000 picoseconds. - Weight::from_parts(245_872_832, 24004) - // Standard Error: 943 - .saturating_add(Weight::from_parts(136_460, 0).saturating_mul(r.into())) + // Estimated: `6723 + r * (3 ±0)` + // Minimum execution time: 234_014_000 picoseconds. + Weight::from_parts(240_042_671, 6723) + // Standard Error: 152 + .saturating_add(Weight::from_parts(138_382, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) - .saturating_add(Weight::from_parts(0, 18).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 3).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64const(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_606_000 picoseconds. - Weight::from_parts(1_845_698, 0) + // Minimum execution time: 1_533_000 picoseconds. + Weight::from_parts(1_846_015, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(2_995, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(2_935, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64load(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_711_000 picoseconds. - Weight::from_parts(2_281_581, 0) - // Standard Error: 4 - .saturating_add(Weight::from_parts(6_354, 0).saturating_mul(r.into())) + // Minimum execution time: 1_671_000 picoseconds. + Weight::from_parts(2_197_197, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(6_335, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64store(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_680_000 picoseconds. - Weight::from_parts(2_269_238, 0) - // Standard Error: 4 - .saturating_add(Weight::from_parts(6_014, 0).saturating_mul(r.into())) + // Minimum execution time: 1_665_000 picoseconds. + Weight::from_parts(2_200_545, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(6_011, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_select(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_592_000 picoseconds. - Weight::from_parts(2_010_963, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(7_927, 0).saturating_mul(r.into())) + // Minimum execution time: 1_545_000 picoseconds. + Weight::from_parts(1_977_462, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(7_901, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_if(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_631_000 picoseconds. - Weight::from_parts(1_936_549, 0) - // Standard Error: 6 - .saturating_add(Weight::from_parts(10_426, 0).saturating_mul(r.into())) + // Minimum execution time: 1_515_000 picoseconds. + Weight::from_parts(1_866_184, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(10_514, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_br(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_616_000 picoseconds. - Weight::from_parts(1_938_716, 0) - // Standard Error: 15 - .saturating_add(Weight::from_parts(4_525, 0).saturating_mul(r.into())) + // Minimum execution time: 1_618_000 picoseconds. + Weight::from_parts(1_895_104, 0) + // Standard Error: 12 + .saturating_add(Weight::from_parts(4_523, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_br_if(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_535_000 picoseconds. - Weight::from_parts(1_109_860, 0) - // Standard Error: 77 - .saturating_add(Weight::from_parts(7_998, 0).saturating_mul(r.into())) + // Minimum execution time: 1_510_000 picoseconds. + Weight::from_parts(1_779_998, 0) + // Standard Error: 8 + .saturating_add(Weight::from_parts(6_832, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_br_table(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_594_000 picoseconds. - Weight::from_parts(1_478_654, 0) - // Standard Error: 36 - .saturating_add(Weight::from_parts(9_525, 0).saturating_mul(r.into())) + // Minimum execution time: 1_529_000 picoseconds. + Weight::from_parts(1_726_996, 0) + // Standard Error: 26 + .saturating_add(Weight::from_parts(9_199, 0).saturating_mul(r.into())) } /// The range of component `e` is `[1, 256]`. fn instr_br_table_per_entry(e: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_730_000 picoseconds. - Weight::from_parts(1_836_342, 0) - // Standard Error: 14 - .saturating_add(Weight::from_parts(206, 0).saturating_mul(e.into())) + // Minimum execution time: 1_682_000 picoseconds. + Weight::from_parts(1_789_910, 0) + // Standard Error: 16 + .saturating_add(Weight::from_parts(42, 0).saturating_mul(e.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_call(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_607_000 picoseconds. - Weight::from_parts(2_150_133, 0) - // Standard Error: 17 - .saturating_add(Weight::from_parts(18_630, 0).saturating_mul(r.into())) + // Minimum execution time: 1_539_000 picoseconds. + Weight::from_parts(2_093_056, 0) + // Standard Error: 27 + .saturating_add(Weight::from_parts(18_917, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_call_indirect(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_824_000 picoseconds. - Weight::from_parts(3_119_825, 0) - // Standard Error: 15 - .saturating_add(Weight::from_parts(25_304, 0).saturating_mul(r.into())) + // Minimum execution time: 1_851_000 picoseconds. + Weight::from_parts(3_134_610, 0) + // Standard Error: 34 + .saturating_add(Weight::from_parts(24_714, 0).saturating_mul(r.into())) } /// The range of component `l` is `[0, 1024]`. fn instr_call_per_local(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_692_000 picoseconds. - Weight::from_parts(1_927_049, 0) + // Minimum execution time: 1_654_000 picoseconds. + Weight::from_parts(1_885_921, 0) // Standard Error: 14 - .saturating_add(Weight::from_parts(1_217, 0).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(1_243, 0).saturating_mul(l.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_local_get(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_795_000 picoseconds. - Weight::from_parts(3_107_843, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(2_445, 0).saturating_mul(r.into())) + // Minimum execution time: 2_744_000 picoseconds. + Weight::from_parts(3_014_725, 0) + // Standard Error: 1 + .saturating_add(Weight::from_parts(2_447, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_local_set(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_815_000 picoseconds. - Weight::from_parts(3_114_618, 0) + // Minimum execution time: 2_881_000 picoseconds. + Weight::from_parts(3_137_711, 0) // Standard Error: 3 - .saturating_add(Weight::from_parts(3_639, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_608, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_local_tee(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_861_000 picoseconds. - Weight::from_parts(3_193_592, 0) + // Minimum execution time: 2_809_000 picoseconds. + Weight::from_parts(3_142_066, 0) // Standard Error: 3 - .saturating_add(Weight::from_parts(3_957, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_841, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_global_get(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_710_000 picoseconds. - Weight::from_parts(2_148_021, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(8_391, 0).saturating_mul(r.into())) + // Minimum execution time: 1_704_000 picoseconds. + Weight::from_parts(2_083_619, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(8_366, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_global_set(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_663_000 picoseconds. - Weight::from_parts(2_170_373, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(8_812, 0).saturating_mul(r.into())) + // Minimum execution time: 1_652_000 picoseconds. + Weight::from_parts(2_048_256, 0) + // Standard Error: 5 + .saturating_add(Weight::from_parts(8_826, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_memory_current(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_662_000 picoseconds. - Weight::from_parts(2_601_398, 0) - // Standard Error: 198 - .saturating_add(Weight::from_parts(3_851, 0).saturating_mul(r.into())) + // Minimum execution time: 1_671_000 picoseconds. + Weight::from_parts(1_924_626, 0) + // Standard Error: 1 + .saturating_add(Weight::from_parts(3_746, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 16]`. fn instr_memory_grow(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_603_000 picoseconds. - Weight::from_parts(332_932, 0) - // Standard Error: 137_529 - .saturating_add(Weight::from_parts(13_233_734, 0).saturating_mul(r.into())) + // Minimum execution time: 1_585_000 picoseconds. + Weight::from_parts(490_856, 0) + // Standard Error: 133_673 + .saturating_add(Weight::from_parts(13_182_582, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64clz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_613_000 picoseconds. - Weight::from_parts(1_922_391, 0) + // Minimum execution time: 1_533_000 picoseconds. + Weight::from_parts(1_851_563, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(3_903, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_820, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64ctz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_522_000 picoseconds. - Weight::from_parts(1_920_023, 0) + // Minimum execution time: 1_564_000 picoseconds. + Weight::from_parts(1_914_178, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(3_876, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_732, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64popcnt(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_590_000 picoseconds. - Weight::from_parts(1_867_406, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(3_910, 0).saturating_mul(r.into())) + // Minimum execution time: 1_559_000 picoseconds. + Weight::from_parts(1_886_992, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(3_731, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64eqz(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_577_000 picoseconds. - Weight::from_parts(1_918_037, 0) + // Minimum execution time: 1_553_000 picoseconds. + Weight::from_parts(1_886_545, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(3_673, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_658, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64extendsi32(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_589_000 picoseconds. - Weight::from_parts(1_917_901, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(3_956, 0).saturating_mul(r.into())) + // Minimum execution time: 1_507_000 picoseconds. + Weight::from_parts(1_853_647, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(3_852, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64extendui32(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_573_000 picoseconds. - Weight::from_parts(1_902_324, 0) + // Minimum execution time: 1_554_000 picoseconds. + Weight::from_parts(1_868_877, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(3_865, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_806, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i32wrapi64(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_586_000 picoseconds. - Weight::from_parts(1_953_738, 0) + // Minimum execution time: 1_514_000 picoseconds. + Weight::from_parts(1_882_233, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(3_838, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(3_700, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64eq(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_598_000 picoseconds. - Weight::from_parts(1_912_180, 0) + // Minimum execution time: 1_529_000 picoseconds. + Weight::from_parts(1_897_247, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(5_994, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(5_955, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64ne(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_573_000 picoseconds. - Weight::from_parts(1_943_725, 0) + // Minimum execution time: 1_513_000 picoseconds. + Weight::from_parts(1_922_333, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(5_998, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(5_933, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64lts(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_584_000 picoseconds. - Weight::from_parts(1_949_209, 0) + // Minimum execution time: 1_512_000 picoseconds. + Weight::from_parts(1_848_668, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(5_991, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(5_966, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64ltu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_576_000 picoseconds. - Weight::from_parts(1_927_466, 0) + // Minimum execution time: 1_522_000 picoseconds. + Weight::from_parts(1_875_257, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(6_005, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(5_965, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64gts(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_566_000 picoseconds. - Weight::from_parts(2_004_312, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(5_799, 0).saturating_mul(r.into())) + // Minimum execution time: 1_546_000 picoseconds. + Weight::from_parts(1_836_691, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(5_842, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64gtu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_538_000 picoseconds. - Weight::from_parts(1_922_703, 0) - // Standard Error: 9 - .saturating_add(Weight::from_parts(6_129, 0).saturating_mul(r.into())) + // Minimum execution time: 1_505_000 picoseconds. + Weight::from_parts(1_907_551, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(6_075, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64les(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_575_000 picoseconds. - Weight::from_parts(1_978_271, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(5_991, 0).saturating_mul(r.into())) + // Minimum execution time: 1_527_000 picoseconds. + Weight::from_parts(1_891_008, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(5_971, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64leu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_572_000 picoseconds. - Weight::from_parts(4_028_578, 0) - // Standard Error: 263 - .saturating_add(Weight::from_parts(5_784, 0).saturating_mul(r.into())) + // Minimum execution time: 1_556_000 picoseconds. + Weight::from_parts(1_910_864, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(6_059, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64ges(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_615_000 picoseconds. - Weight::from_parts(1_962_065, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(5_945, 0).saturating_mul(r.into())) + // Minimum execution time: 1_544_000 picoseconds. + Weight::from_parts(1_912_650, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(5_943, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64geu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_578_000 picoseconds. - Weight::from_parts(1_909_721, 0) + // Minimum execution time: 1_513_000 picoseconds. + Weight::from_parts(1_855_260, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(5_993, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(5_975, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64add(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_609_000 picoseconds. - Weight::from_parts(1_926_472, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(5_888, 0).saturating_mul(r.into())) + // Minimum execution time: 1_521_000 picoseconds. + Weight::from_parts(1_867_259, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(5_846, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64sub(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_620_000 picoseconds. - Weight::from_parts(2_875_196, 0) - // Standard Error: 177 - .saturating_add(Weight::from_parts(5_990, 0).saturating_mul(r.into())) + // Minimum execution time: 1_509_000 picoseconds. + Weight::from_parts(1_893_018, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(6_096, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64mul(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_570_000 picoseconds. - Weight::from_parts(2_155_483, 0) - // Standard Error: 83 - .saturating_add(Weight::from_parts(5_675, 0).saturating_mul(r.into())) + // Minimum execution time: 1_496_000 picoseconds. + Weight::from_parts(1_886_659, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(5_754, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64divs(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_558_000 picoseconds. - Weight::from_parts(2_108_263, 0) - // Standard Error: 5 - .saturating_add(Weight::from_parts(11_755, 0).saturating_mul(r.into())) + // Minimum execution time: 1_527_000 picoseconds. + Weight::from_parts(1_890_548, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(11_842, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64divu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_568_000 picoseconds. - Weight::from_parts(1_606_397, 0) - // Standard Error: 51 - .saturating_add(Weight::from_parts(11_011, 0).saturating_mul(r.into())) + // Minimum execution time: 1_518_000 picoseconds. + Weight::from_parts(1_891_903, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(10_613, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64rems(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_630_000 picoseconds. - Weight::from_parts(2_872_487, 0) - // Standard Error: 24 - .saturating_add(Weight::from_parts(11_761, 0).saturating_mul(r.into())) + // Minimum execution time: 1_504_000 picoseconds. + Weight::from_parts(1_632_694, 0) + // Standard Error: 7 + .saturating_add(Weight::from_parts(12_281, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64remu(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_575_000 picoseconds. - Weight::from_parts(2_385_398, 0) - // Standard Error: 45 - .saturating_add(Weight::from_parts(10_650, 0).saturating_mul(r.into())) + // Minimum execution time: 1_507_000 picoseconds. + Weight::from_parts(1_878_413, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(10_737, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64and(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_622_000 picoseconds. - Weight::from_parts(1_957_246, 0) + // Minimum execution time: 1_534_000 picoseconds. + Weight::from_parts(1_898_519, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(5_659, 0).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(5_645, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64or(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_551_000 picoseconds. - Weight::from_parts(1_897_168, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(5_774, 0).saturating_mul(r.into())) + // Minimum execution time: 1_503_000 picoseconds. + Weight::from_parts(1_895_532, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(5_745, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64xor(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_549_000 picoseconds. - Weight::from_parts(1_915_938, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(5_915, 0).saturating_mul(r.into())) + // Minimum execution time: 1_507_000 picoseconds. + Weight::from_parts(1_868_720, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(5_873, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64shl(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_617_000 picoseconds. - Weight::from_parts(1_932_618, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(5_854, 0).saturating_mul(r.into())) + // Minimum execution time: 1_513_000 picoseconds. + Weight::from_parts(1_894_207, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(5_843, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64shrs(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_617_000 picoseconds. - Weight::from_parts(1_937_566, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(6_134, 0).saturating_mul(r.into())) + // Minimum execution time: 1_473_000 picoseconds. + Weight::from_parts(1_880_224, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(6_107, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64shru(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_584_000 picoseconds. - Weight::from_parts(1_980_681, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(5_842, 0).saturating_mul(r.into())) + // Minimum execution time: 1_447_000 picoseconds. + Weight::from_parts(1_884_551, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(5_849, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64rotl(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_542_000 picoseconds. - Weight::from_parts(2_131_567, 0) - // Standard Error: 57 - .saturating_add(Weight::from_parts(6_010, 0).saturating_mul(r.into())) + // Minimum execution time: 1_538_000 picoseconds. + Weight::from_parts(1_908_813, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(5_987, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 5000]`. fn instr_i64rotr(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_609_000 picoseconds. - Weight::from_parts(1_643_214, 0) - // Standard Error: 91 - .saturating_add(Weight::from_parts(6_062, 0).saturating_mul(r.into())) + // Minimum execution time: 1_538_000 picoseconds. + Weight::from_parts(1_878_015, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(5_848, 0).saturating_mul(r.into())) } } diff --git a/frame/conviction-voting/src/weights.rs b/frame/conviction-voting/src/weights.rs index 765a4276aea59..bc53855b6b18e 100644 --- a/frame/conviction-voting/src/weights.rs +++ b/frame/conviction-voting/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_conviction_voting //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,9 +31,6 @@ // --steps=50 // --repeat=20 // --pallet=pallet_conviction_voting -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -71,15 +68,17 @@ impl WeightInfo for SubstrateWeight { /// Proof: ConvictionVoting ClassLocksFor (max_values: None, max_size: Some(59), added: 2534, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: Scheduler Agenda (r:2 w:2) /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn vote_new() -> Weight { // Proof Size summary in bytes: // Measured: `13074` - // Estimated: `262809` - // Minimum execution time: 94_493_000 picoseconds. - Weight::from_parts(96_510_000, 262809) - .saturating_add(T::DbWeight::get().reads(6_u64)) + // Estimated: `219984` + // Minimum execution time: 99_130_000 picoseconds. + Weight::from_parts(100_355_000, 219984) + .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } /// Storage: Referenda ReferendumInfoFor (r:1 w:1) @@ -90,15 +89,17 @@ impl WeightInfo for SubstrateWeight { /// Proof: ConvictionVoting ClassLocksFor (max_values: None, max_size: Some(59), added: 2534, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: Scheduler Agenda (r:2 w:2) /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn vote_existing() -> Weight { // Proof Size summary in bytes: // Measured: `20216` - // Estimated: `262809` - // Minimum execution time: 252_717_000 picoseconds. - Weight::from_parts(255_200_000, 262809) - .saturating_add(T::DbWeight::get().reads(6_u64)) + // Estimated: `219984` + // Minimum execution time: 276_420_000 picoseconds. + Weight::from_parts(277_433_000, 219984) + .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } /// Storage: ConvictionVoting VotingFor (r:1 w:1) @@ -110,9 +111,9 @@ impl WeightInfo for SubstrateWeight { fn remove_vote() -> Weight { // Proof Size summary in bytes: // Measured: `19968` - // Estimated: `254521` - // Minimum execution time: 244_844_000 picoseconds. - Weight::from_parts(247_433_000, 254521) + // Estimated: `219984` + // Minimum execution time: 241_058_000 picoseconds. + Weight::from_parts(242_235_000, 219984) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -123,9 +124,9 @@ impl WeightInfo for SubstrateWeight { fn remove_other_vote() -> Weight { // Proof Size summary in bytes: // Measured: `12675` - // Estimated: `34537` - // Minimum execution time: 46_271_000 picoseconds. - Weight::from_parts(47_639_000, 34537) + // Estimated: `30706` + // Minimum execution time: 46_385_000 picoseconds. + Weight::from_parts(46_709_000, 30706) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -139,20 +140,22 @@ impl WeightInfo for SubstrateWeight { /// Proof: ConvictionVoting ClassLocksFor (max_values: None, max_size: Some(59), added: 2534, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// The range of component `r` is `[0, 1]`. fn delegate(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `240 + r * (1627 ±0)` - // Estimated: `180617 + r * (111908 ±0)` - // Minimum execution time: 37_578_000 picoseconds. - Weight::from_parts(39_035_446, 180617) - // Standard Error: 160_560 - .saturating_add(Weight::from_parts(39_642_553, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(4_u64)) + // Estimated: `109992 + r * (109992 ±0)` + // Minimum execution time: 48_947_000 picoseconds. + Weight::from_parts(50_219_593, 109992) + // Standard Error: 70_238 + .saturating_add(Weight::from_parts(40_509_706, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 111908).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 109992).saturating_mul(r.into())) } /// Storage: ConvictionVoting VotingFor (r:2 w:2) /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) @@ -164,16 +167,16 @@ impl WeightInfo for SubstrateWeight { fn undelegate(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `406 + r * (1376 ±0)` - // Estimated: `172329 + r * (111908 ±0)` - // Minimum execution time: 22_997_000 picoseconds. - Weight::from_parts(24_180_222, 172329) - // Standard Error: 87_723 - .saturating_add(Weight::from_parts(36_189_677, 0).saturating_mul(r.into())) + // Estimated: `109992 + r * (109992 ±0)` + // Minimum execution time: 23_408_000 picoseconds. + Weight::from_parts(24_087_793, 109992) + // Standard Error: 31_776 + .saturating_add(Weight::from_parts(36_594_606, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 111908).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 109992).saturating_mul(r.into())) } /// Storage: ConvictionVoting VotingFor (r:1 w:1) /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) @@ -181,13 +184,15 @@ impl WeightInfo for SubstrateWeight { /// Proof: ConvictionVoting ClassLocksFor (max_values: None, max_size: Some(59), added: 2534, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) fn unlock() -> Weight { // Proof Size summary in bytes: // Measured: `11734` - // Estimated: `38994` - // Minimum execution time: 55_906_000 picoseconds. - Weight::from_parts(56_819_000, 38994) - .saturating_add(T::DbWeight::get().reads(3_u64)) + // Estimated: `30706` + // Minimum execution time: 65_903_000 picoseconds. + Weight::from_parts(66_460_000, 30706) + .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } } @@ -202,15 +207,17 @@ impl WeightInfo for () { /// Proof: ConvictionVoting ClassLocksFor (max_values: None, max_size: Some(59), added: 2534, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: Scheduler Agenda (r:2 w:2) /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn vote_new() -> Weight { // Proof Size summary in bytes: // Measured: `13074` - // Estimated: `262809` - // Minimum execution time: 94_493_000 picoseconds. - Weight::from_parts(96_510_000, 262809) - .saturating_add(RocksDbWeight::get().reads(6_u64)) + // Estimated: `219984` + // Minimum execution time: 99_130_000 picoseconds. + Weight::from_parts(100_355_000, 219984) + .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } /// Storage: Referenda ReferendumInfoFor (r:1 w:1) @@ -221,15 +228,17 @@ impl WeightInfo for () { /// Proof: ConvictionVoting ClassLocksFor (max_values: None, max_size: Some(59), added: 2534, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: Scheduler Agenda (r:2 w:2) /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn vote_existing() -> Weight { // Proof Size summary in bytes: // Measured: `20216` - // Estimated: `262809` - // Minimum execution time: 252_717_000 picoseconds. - Weight::from_parts(255_200_000, 262809) - .saturating_add(RocksDbWeight::get().reads(6_u64)) + // Estimated: `219984` + // Minimum execution time: 276_420_000 picoseconds. + Weight::from_parts(277_433_000, 219984) + .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } /// Storage: ConvictionVoting VotingFor (r:1 w:1) @@ -241,9 +250,9 @@ impl WeightInfo for () { fn remove_vote() -> Weight { // Proof Size summary in bytes: // Measured: `19968` - // Estimated: `254521` - // Minimum execution time: 244_844_000 picoseconds. - Weight::from_parts(247_433_000, 254521) + // Estimated: `219984` + // Minimum execution time: 241_058_000 picoseconds. + Weight::from_parts(242_235_000, 219984) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -254,9 +263,9 @@ impl WeightInfo for () { fn remove_other_vote() -> Weight { // Proof Size summary in bytes: // Measured: `12675` - // Estimated: `34537` - // Minimum execution time: 46_271_000 picoseconds. - Weight::from_parts(47_639_000, 34537) + // Estimated: `30706` + // Minimum execution time: 46_385_000 picoseconds. + Weight::from_parts(46_709_000, 30706) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -270,20 +279,22 @@ impl WeightInfo for () { /// Proof: ConvictionVoting ClassLocksFor (max_values: None, max_size: Some(59), added: 2534, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// The range of component `r` is `[0, 1]`. fn delegate(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `240 + r * (1627 ±0)` - // Estimated: `180617 + r * (111908 ±0)` - // Minimum execution time: 37_578_000 picoseconds. - Weight::from_parts(39_035_446, 180617) - // Standard Error: 160_560 - .saturating_add(Weight::from_parts(39_642_553, 0).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(4_u64)) + // Estimated: `109992 + r * (109992 ±0)` + // Minimum execution time: 48_947_000 picoseconds. + Weight::from_parts(50_219_593, 109992) + // Standard Error: 70_238 + .saturating_add(Weight::from_parts(40_509_706, 0).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 111908).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 109992).saturating_mul(r.into())) } /// Storage: ConvictionVoting VotingFor (r:2 w:2) /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) @@ -295,16 +306,16 @@ impl WeightInfo for () { fn undelegate(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `406 + r * (1376 ±0)` - // Estimated: `172329 + r * (111908 ±0)` - // Minimum execution time: 22_997_000 picoseconds. - Weight::from_parts(24_180_222, 172329) - // Standard Error: 87_723 - .saturating_add(Weight::from_parts(36_189_677, 0).saturating_mul(r.into())) + // Estimated: `109992 + r * (109992 ±0)` + // Minimum execution time: 23_408_000 picoseconds. + Weight::from_parts(24_087_793, 109992) + // Standard Error: 31_776 + .saturating_add(Weight::from_parts(36_594_606, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 111908).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 109992).saturating_mul(r.into())) } /// Storage: ConvictionVoting VotingFor (r:1 w:1) /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) @@ -312,13 +323,15 @@ impl WeightInfo for () { /// Proof: ConvictionVoting ClassLocksFor (max_values: None, max_size: Some(59), added: 2534, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) fn unlock() -> Weight { // Proof Size summary in bytes: // Measured: `11734` - // Estimated: `38994` - // Minimum execution time: 55_906_000 picoseconds. - Weight::from_parts(56_819_000, 38994) - .saturating_add(RocksDbWeight::get().reads(3_u64)) + // Estimated: `30706` + // Minimum execution time: 65_903_000 picoseconds. + Weight::from_parts(66_460_000, 30706) + .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } } diff --git a/frame/core-fellowship/src/weights.rs b/frame/core-fellowship/src/weights.rs index d436826665069..28ebeae64733e 100644 --- a/frame/core-fellowship/src/weights.rs +++ b/frame/core-fellowship/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_core_fellowship //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,9 +31,6 @@ // --steps=50 // --repeat=20 // --pallet=pallet_core_fellowship -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -72,8 +69,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 10_384_000 picoseconds. - Weight::from_parts(10_787_000, 0) + // Minimum execution time: 10_390_000 picoseconds. + Weight::from_parts(10_847_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: CoreFellowship Member (r:1 w:1) @@ -91,9 +88,9 @@ impl WeightInfo for SubstrateWeight { fn bump_offboard() -> Weight { // Proof Size summary in bytes: // Measured: `16854` - // Estimated: `35762` - // Minimum execution time: 61_847_000 picoseconds. - Weight::from_parts(62_453_000, 35762) + // Estimated: `19894` + // Minimum execution time: 61_737_000 picoseconds. + Weight::from_parts(62_207_000, 19894) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -112,9 +109,9 @@ impl WeightInfo for SubstrateWeight { fn bump_demote() -> Weight { // Proof Size summary in bytes: // Measured: `16964` - // Estimated: `35762` - // Minimum execution time: 64_449_000 picoseconds. - Weight::from_parts(65_298_000, 35762) + // Estimated: `19894` + // Minimum execution time: 64_226_000 picoseconds. + Weight::from_parts(64_678_000, 19894) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -125,9 +122,9 @@ impl WeightInfo for SubstrateWeight { fn set_active() -> Weight { // Proof Size summary in bytes: // Measured: `355` - // Estimated: `7021` - // Minimum execution time: 19_308_000 picoseconds. - Weight::from_parts(19_520_000, 7021) + // Estimated: `3514` + // Minimum execution time: 18_977_000 picoseconds. + Weight::from_parts(19_157_000, 3514) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -144,9 +141,9 @@ impl WeightInfo for SubstrateWeight { fn induct() -> Weight { // Proof Size summary in bytes: // Measured: `113` - // Estimated: `10500` - // Minimum execution time: 29_228_000 picoseconds. - Weight::from_parts(29_683_000, 10500) + // Estimated: `3514` + // Minimum execution time: 28_633_000 picoseconds. + Weight::from_parts(29_074_000, 3514) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -167,9 +164,9 @@ impl WeightInfo for SubstrateWeight { fn promote() -> Weight { // Proof Size summary in bytes: // Measured: `16832` - // Estimated: `32243` - // Minimum execution time: 59_745_000 picoseconds. - Weight::from_parts(60_290_000, 32243) + // Estimated: `19894` + // Minimum execution time: 59_008_000 picoseconds. + Weight::from_parts(59_690_000, 19894) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -182,9 +179,9 @@ impl WeightInfo for SubstrateWeight { fn offboard() -> Weight { // Proof Size summary in bytes: // Measured: `326` - // Estimated: `7021` - // Minimum execution time: 18_964_000 picoseconds. - Weight::from_parts(19_603_000, 7021) + // Estimated: `3514` + // Minimum execution time: 18_892_000 picoseconds. + Weight::from_parts(19_095_000, 3514) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -195,9 +192,9 @@ impl WeightInfo for SubstrateWeight { fn import() -> Weight { // Proof Size summary in bytes: // Measured: `280` - // Estimated: `7021` - // Minimum execution time: 18_752_000 picoseconds. - Weight::from_parts(19_035_000, 7021) + // Estimated: `3514` + // Minimum execution time: 18_107_000 picoseconds. + Weight::from_parts(18_371_000, 3514) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -210,9 +207,9 @@ impl WeightInfo for SubstrateWeight { fn approve() -> Weight { // Proof Size summary in bytes: // Measured: `16810` - // Estimated: `26915` - // Minimum execution time: 44_972_000 picoseconds. - Weight::from_parts(45_391_000, 26915) + // Estimated: `19894` + // Minimum execution time: 43_243_000 picoseconds. + Weight::from_parts(43_965_000, 19894) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -223,9 +220,9 @@ impl WeightInfo for SubstrateWeight { fn submit_evidence() -> Weight { // Proof Size summary in bytes: // Measured: `79` - // Estimated: `23408` - // Minimum execution time: 27_820_000 picoseconds. - Weight::from_parts(28_992_000, 23408) + // Estimated: `19894` + // Minimum execution time: 27_881_000 picoseconds. + Weight::from_parts(28_208_000, 19894) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -239,8 +236,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 10_384_000 picoseconds. - Weight::from_parts(10_787_000, 0) + // Minimum execution time: 10_390_000 picoseconds. + Weight::from_parts(10_847_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: CoreFellowship Member (r:1 w:1) @@ -258,9 +255,9 @@ impl WeightInfo for () { fn bump_offboard() -> Weight { // Proof Size summary in bytes: // Measured: `16854` - // Estimated: `35762` - // Minimum execution time: 61_847_000 picoseconds. - Weight::from_parts(62_453_000, 35762) + // Estimated: `19894` + // Minimum execution time: 61_737_000 picoseconds. + Weight::from_parts(62_207_000, 19894) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -279,9 +276,9 @@ impl WeightInfo for () { fn bump_demote() -> Weight { // Proof Size summary in bytes: // Measured: `16964` - // Estimated: `35762` - // Minimum execution time: 64_449_000 picoseconds. - Weight::from_parts(65_298_000, 35762) + // Estimated: `19894` + // Minimum execution time: 64_226_000 picoseconds. + Weight::from_parts(64_678_000, 19894) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -292,9 +289,9 @@ impl WeightInfo for () { fn set_active() -> Weight { // Proof Size summary in bytes: // Measured: `355` - // Estimated: `7021` - // Minimum execution time: 19_308_000 picoseconds. - Weight::from_parts(19_520_000, 7021) + // Estimated: `3514` + // Minimum execution time: 18_977_000 picoseconds. + Weight::from_parts(19_157_000, 3514) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -311,9 +308,9 @@ impl WeightInfo for () { fn induct() -> Weight { // Proof Size summary in bytes: // Measured: `113` - // Estimated: `10500` - // Minimum execution time: 29_228_000 picoseconds. - Weight::from_parts(29_683_000, 10500) + // Estimated: `3514` + // Minimum execution time: 28_633_000 picoseconds. + Weight::from_parts(29_074_000, 3514) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -334,9 +331,9 @@ impl WeightInfo for () { fn promote() -> Weight { // Proof Size summary in bytes: // Measured: `16832` - // Estimated: `32243` - // Minimum execution time: 59_745_000 picoseconds. - Weight::from_parts(60_290_000, 32243) + // Estimated: `19894` + // Minimum execution time: 59_008_000 picoseconds. + Weight::from_parts(59_690_000, 19894) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -349,9 +346,9 @@ impl WeightInfo for () { fn offboard() -> Weight { // Proof Size summary in bytes: // Measured: `326` - // Estimated: `7021` - // Minimum execution time: 18_964_000 picoseconds. - Weight::from_parts(19_603_000, 7021) + // Estimated: `3514` + // Minimum execution time: 18_892_000 picoseconds. + Weight::from_parts(19_095_000, 3514) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -362,9 +359,9 @@ impl WeightInfo for () { fn import() -> Weight { // Proof Size summary in bytes: // Measured: `280` - // Estimated: `7021` - // Minimum execution time: 18_752_000 picoseconds. - Weight::from_parts(19_035_000, 7021) + // Estimated: `3514` + // Minimum execution time: 18_107_000 picoseconds. + Weight::from_parts(18_371_000, 3514) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -377,9 +374,9 @@ impl WeightInfo for () { fn approve() -> Weight { // Proof Size summary in bytes: // Measured: `16810` - // Estimated: `26915` - // Minimum execution time: 44_972_000 picoseconds. - Weight::from_parts(45_391_000, 26915) + // Estimated: `19894` + // Minimum execution time: 43_243_000 picoseconds. + Weight::from_parts(43_965_000, 19894) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -390,9 +387,9 @@ impl WeightInfo for () { fn submit_evidence() -> Weight { // Proof Size summary in bytes: // Measured: `79` - // Estimated: `23408` - // Minimum execution time: 27_820_000 picoseconds. - Weight::from_parts(28_992_000, 23408) + // Estimated: `19894` + // Minimum execution time: 27_881_000 picoseconds. + Weight::from_parts(28_208_000, 19894) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/frame/democracy/src/weights.rs b/frame/democracy/src/weights.rs index e0c970a34b372..a263f2982d862 100644 --- a/frame/democracy/src/weights.rs +++ b/frame/democracy/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_democracy //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,9 +31,6 @@ // --steps=50 // --repeat=20 // --pallet=pallet_democracy -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -95,9 +92,9 @@ impl WeightInfo for SubstrateWeight { fn propose() -> Weight { // Proof Size summary in bytes: // Measured: `4801` - // Estimated: `26379` - // Minimum execution time: 39_171_000 picoseconds. - Weight::from_parts(39_779_000, 26379) + // Estimated: `18187` + // Minimum execution time: 43_810_000 picoseconds. + Weight::from_parts(44_439_000, 18187) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -107,8 +104,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `3556` // Estimated: `6695` - // Minimum execution time: 35_694_000 picoseconds. - Weight::from_parts(36_181_000, 6695) + // Minimum execution time: 40_003_000 picoseconds. + Weight::from_parts(40_448_000, 6695) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -118,13 +115,15 @@ impl WeightInfo for SubstrateWeight { /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) fn vote_new() -> Weight { // Proof Size summary in bytes: // Measured: `3470` - // Estimated: `15690` - // Minimum execution time: 50_274_000 picoseconds. - Weight::from_parts(51_216_000, 15690) - .saturating_add(T::DbWeight::get().reads(3_u64)) + // Estimated: `7260` + // Minimum execution time: 54_737_000 picoseconds. + Weight::from_parts(55_154_000, 7260) + .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: Democracy ReferendumInfoOf (r:1 w:1) @@ -133,13 +132,15 @@ impl WeightInfo for SubstrateWeight { /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) fn vote_existing() -> Weight { // Proof Size summary in bytes: // Measured: `3492` - // Estimated: `15690` - // Minimum execution time: 50_559_000 picoseconds. - Weight::from_parts(51_030_000, 15690) - .saturating_add(T::DbWeight::get().reads(3_u64)) + // Estimated: `7260` + // Minimum execution time: 59_545_000 picoseconds. + Weight::from_parts(59_955_000, 7260) + .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: Democracy ReferendumInfoOf (r:1 w:1) @@ -151,9 +152,9 @@ impl WeightInfo for SubstrateWeight { fn emergency_cancel() -> Weight { // Proof Size summary in bytes: // Measured: `366` - // Estimated: `10682` - // Minimum execution time: 27_539_000 picoseconds. - Weight::from_parts(28_040_000, 10682) + // Estimated: `3666` + // Minimum execution time: 27_886_000 picoseconds. + Weight::from_parts(28_372_000, 3666) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -174,9 +175,9 @@ impl WeightInfo for SubstrateWeight { fn blacklist() -> Weight { // Proof Size summary in bytes: // Measured: `5910` - // Estimated: `42332` - // Minimum execution time: 93_053_000 picoseconds. - Weight::from_parts(94_193_000, 42332) + // Estimated: `18187` + // Minimum execution time: 99_273_000 picoseconds. + Weight::from_parts(100_398_000, 18187) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } @@ -187,9 +188,9 @@ impl WeightInfo for SubstrateWeight { fn external_propose() -> Weight { // Proof Size summary in bytes: // Measured: `3416` - // Estimated: `8320` - // Minimum execution time: 14_664_000 picoseconds. - Weight::from_parts(15_064_000, 8320) + // Estimated: `6703` + // Minimum execution time: 14_946_000 picoseconds. + Weight::from_parts(15_114_000, 6703) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -199,8 +200,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_073_000 picoseconds. - Weight::from_parts(4_242_000, 0) + // Minimum execution time: 3_870_000 picoseconds. + Weight::from_parts(4_083_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Democracy NextExternal (r:0 w:1) @@ -209,8 +210,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_779_000 picoseconds. - Weight::from_parts(4_091_000, 0) + // Minimum execution time: 3_989_000 picoseconds. + Weight::from_parts(4_166_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Democracy NextExternal (r:1 w:1) @@ -224,9 +225,9 @@ impl WeightInfo for SubstrateWeight { fn fast_track() -> Weight { // Proof Size summary in bytes: // Measured: `286` - // Estimated: `6624` - // Minimum execution time: 29_596_000 picoseconds. - Weight::from_parts(30_083_000, 6624) + // Estimated: `3518` + // Minimum execution time: 29_776_000 picoseconds. + Weight::from_parts(30_186_000, 3518) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -239,9 +240,9 @@ impl WeightInfo for SubstrateWeight { fn veto_external() -> Weight { // Proof Size summary in bytes: // Measured: `3519` - // Estimated: `11838` - // Minimum execution time: 34_721_000 picoseconds. - Weight::from_parts(34_989_000, 11838) + // Estimated: `6703` + // Minimum execution time: 33_891_000 picoseconds. + Weight::from_parts(34_265_000, 6703) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -256,9 +257,9 @@ impl WeightInfo for SubstrateWeight { fn cancel_proposal() -> Weight { // Proof Size summary in bytes: // Measured: `5821` - // Estimated: `31993` - // Minimum execution time: 74_835_000 picoseconds. - Weight::from_parts(75_807_000, 31993) + // Estimated: `18187` + // Minimum execution time: 81_510_000 picoseconds. + Weight::from_parts(82_483_000, 18187) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -270,8 +271,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `271` // Estimated: `3518` - // Minimum execution time: 20_995_000 picoseconds. - Weight::from_parts(21_425_000, 3518) + // Minimum execution time: 21_164_000 picoseconds. + Weight::from_parts(21_624_000, 3518) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -285,11 +286,11 @@ impl WeightInfo for SubstrateWeight { fn on_initialize_base(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `244 + r * (86 ±0)` - // Estimated: `3968 + r * (2676 ±0)` - // Minimum execution time: 7_002_000 picoseconds. - Weight::from_parts(10_543_534, 3968) - // Standard Error: 7_286 - .saturating_add(Weight::from_parts(2_911_122, 0).saturating_mul(r.into())) + // Estimated: `1489 + r * (2676 ±0)` + // Minimum execution time: 6_925_000 picoseconds. + Weight::from_parts(10_624_198, 1489) + // Standard Error: 5_780 + .saturating_add(Weight::from_parts(2_934_169, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) @@ -311,11 +312,11 @@ impl WeightInfo for SubstrateWeight { fn on_initialize_base_with_launch_period(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `244 + r * (86 ±0)` - // Estimated: `25258 + r * (2676 ±0)` - // Minimum execution time: 10_824_000 picoseconds. - Weight::from_parts(14_187_527, 25258) - // Standard Error: 7_148 - .saturating_add(Weight::from_parts(2_886_910, 0).saturating_mul(r.into())) + // Estimated: `18187 + r * (2676 ±0)` + // Minimum execution time: 10_551_000 picoseconds. + Weight::from_parts(13_126_123, 18187) + // Standard Error: 6_391 + .saturating_add(Weight::from_parts(2_952_789, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) @@ -327,16 +328,18 @@ impl WeightInfo for SubstrateWeight { /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// The range of component `r` is `[0, 99]`. fn delegate(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `830 + r * (108 ±0)` - // Estimated: `25554 + r * (2676 ±0)` - // Minimum execution time: 42_940_000 picoseconds. - Weight::from_parts(45_288_082, 25554) - // Standard Error: 6_380 - .saturating_add(Weight::from_parts(4_219_163, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(4_u64)) + // Estimated: `19800 + r * (2676 ±0)` + // Minimum execution time: 47_172_000 picoseconds. + Weight::from_parts(49_667_954, 19800) + // Standard Error: 6_129 + .saturating_add(Weight::from_parts(4_230_402, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r.into()))) @@ -350,11 +353,11 @@ impl WeightInfo for SubstrateWeight { fn undelegate(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `493 + r * (108 ±0)` - // Estimated: `14520 + r * (2676 ±0)` - // Minimum execution time: 22_203_000 picoseconds. - Weight::from_parts(22_307_372, 14520) - // Standard Error: 7_095 - .saturating_add(Weight::from_parts(4_202_995, 0).saturating_mul(r.into())) + // Estimated: `13530 + r * (2676 ±0)` + // Minimum execution time: 22_360_000 picoseconds. + Weight::from_parts(25_063_237, 13530) + // Standard Error: 5_326 + .saturating_add(Weight::from_parts(4_163_683, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) @@ -367,44 +370,48 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_046_000 picoseconds. - Weight::from_parts(4_191_000, 0) + // Minimum execution time: 4_047_000 picoseconds. + Weight::from_parts(4_139_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Democracy VotingOf (r:1 w:1) /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: System Account (r:1 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `r` is `[0, 99]`. fn unlock_remove(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `563` - // Estimated: `15617` - // Minimum execution time: 22_585_000 picoseconds. - Weight::from_parts(28_461_437, 15617) - // Standard Error: 1_636 - .saturating_add(Weight::from_parts(19_140, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(3_u64)) + // Estimated: `7260` + // Minimum execution time: 27_322_000 picoseconds. + Weight::from_parts(39_909_589, 7260) + // Standard Error: 2_758 + .saturating_add(Weight::from_parts(29_497, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: Democracy VotingOf (r:1 w:1) /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: System Account (r:1 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `r` is `[0, 99]`. fn unlock_set(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `564 + r * (22 ±0)` - // Estimated: `15617` - // Minimum execution time: 26_674_000 picoseconds. - Weight::from_parts(27_815_260, 15617) - // Standard Error: 490 - .saturating_add(Weight::from_parts(68_478, 0).saturating_mul(r.into())) - .saturating_add(T::DbWeight::get().reads(3_u64)) + // Estimated: `7260` + // Minimum execution time: 37_082_000 picoseconds. + Weight::from_parts(38_580_061, 7260) + // Standard Error: 664 + .saturating_add(Weight::from_parts(62_401, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: Democracy ReferendumInfoOf (r:1 w:1) @@ -415,11 +422,11 @@ impl WeightInfo for SubstrateWeight { fn remove_vote(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `728 + r * (26 ±0)` - // Estimated: `10926` - // Minimum execution time: 17_381_000 picoseconds. - Weight::from_parts(19_728_665, 10926) - // Standard Error: 1_065 - .saturating_add(Weight::from_parts(84_481, 0).saturating_mul(r.into())) + // Estimated: `7260` + // Minimum execution time: 17_528_000 picoseconds. + Weight::from_parts(20_075_412, 7260) + // Standard Error: 1_072 + .saturating_add(Weight::from_parts(81_734, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -431,11 +438,11 @@ impl WeightInfo for SubstrateWeight { fn remove_other_vote(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `728 + r * (26 ±0)` - // Estimated: `10926` - // Minimum execution time: 17_496_000 picoseconds. - Weight::from_parts(19_845_941, 10926) - // Standard Error: 1_169 - .saturating_add(Weight::from_parts(85_004, 0).saturating_mul(r.into())) + // Estimated: `7260` + // Minimum execution time: 17_517_000 picoseconds. + Weight::from_parts(20_090_718, 7260) + // Standard Error: 1_105 + .saturating_add(Weight::from_parts(82_651, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -448,9 +455,9 @@ impl WeightInfo for SubstrateWeight { fn set_external_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `356` - // Estimated: `5173` - // Minimum execution time: 19_076_000 picoseconds. - Weight::from_parts(19_650_000, 5173) + // Estimated: `3556` + // Minimum execution time: 19_234_000 picoseconds. + Weight::from_parts(19_755_000, 3556) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -461,9 +468,9 @@ impl WeightInfo for SubstrateWeight { fn clear_external_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `286` - // Estimated: `5135` - // Minimum execution time: 17_588_000 picoseconds. - Weight::from_parts(17_781_000, 5135) + // Estimated: `3518` + // Minimum execution time: 17_621_000 picoseconds. + Weight::from_parts(17_861_000, 3518) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -476,9 +483,9 @@ impl WeightInfo for SubstrateWeight { fn set_proposal_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `4888` - // Estimated: `21743` - // Minimum execution time: 34_828_000 picoseconds. - Weight::from_parts(35_364_000, 21743) + // Estimated: `18187` + // Minimum execution time: 35_785_000 picoseconds. + Weight::from_parts(36_102_000, 18187) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -489,9 +496,9 @@ impl WeightInfo for SubstrateWeight { fn clear_proposal_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `4822` - // Estimated: `21705` - // Minimum execution time: 32_035_000 picoseconds. - Weight::from_parts(32_554_000, 21705) + // Estimated: `18187` + // Minimum execution time: 33_493_000 picoseconds. + Weight::from_parts(33_747_000, 18187) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -503,8 +510,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `144` // Estimated: `3556` - // Minimum execution time: 15_279_000 picoseconds. - Weight::from_parts(15_556_000, 3556) + // Minimum execution time: 15_557_000 picoseconds. + Weight::from_parts(15_844_000, 3556) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -515,9 +522,9 @@ impl WeightInfo for SubstrateWeight { fn clear_referendum_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `302` - // Estimated: `7184` - // Minimum execution time: 19_622_000 picoseconds. - Weight::from_parts(19_978_000, 7184) + // Estimated: `3666` + // Minimum execution time: 19_940_000 picoseconds. + Weight::from_parts(20_301_000, 3666) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -536,9 +543,9 @@ impl WeightInfo for () { fn propose() -> Weight { // Proof Size summary in bytes: // Measured: `4801` - // Estimated: `26379` - // Minimum execution time: 39_171_000 picoseconds. - Weight::from_parts(39_779_000, 26379) + // Estimated: `18187` + // Minimum execution time: 43_810_000 picoseconds. + Weight::from_parts(44_439_000, 18187) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -548,8 +555,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `3556` // Estimated: `6695` - // Minimum execution time: 35_694_000 picoseconds. - Weight::from_parts(36_181_000, 6695) + // Minimum execution time: 40_003_000 picoseconds. + Weight::from_parts(40_448_000, 6695) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -559,13 +566,15 @@ impl WeightInfo for () { /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) fn vote_new() -> Weight { // Proof Size summary in bytes: // Measured: `3470` - // Estimated: `15690` - // Minimum execution time: 50_274_000 picoseconds. - Weight::from_parts(51_216_000, 15690) - .saturating_add(RocksDbWeight::get().reads(3_u64)) + // Estimated: `7260` + // Minimum execution time: 54_737_000 picoseconds. + Weight::from_parts(55_154_000, 7260) + .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: Democracy ReferendumInfoOf (r:1 w:1) @@ -574,13 +583,15 @@ impl WeightInfo for () { /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) fn vote_existing() -> Weight { // Proof Size summary in bytes: // Measured: `3492` - // Estimated: `15690` - // Minimum execution time: 50_559_000 picoseconds. - Weight::from_parts(51_030_000, 15690) - .saturating_add(RocksDbWeight::get().reads(3_u64)) + // Estimated: `7260` + // Minimum execution time: 59_545_000 picoseconds. + Weight::from_parts(59_955_000, 7260) + .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: Democracy ReferendumInfoOf (r:1 w:1) @@ -592,9 +603,9 @@ impl WeightInfo for () { fn emergency_cancel() -> Weight { // Proof Size summary in bytes: // Measured: `366` - // Estimated: `10682` - // Minimum execution time: 27_539_000 picoseconds. - Weight::from_parts(28_040_000, 10682) + // Estimated: `3666` + // Minimum execution time: 27_886_000 picoseconds. + Weight::from_parts(28_372_000, 3666) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -615,9 +626,9 @@ impl WeightInfo for () { fn blacklist() -> Weight { // Proof Size summary in bytes: // Measured: `5910` - // Estimated: `42332` - // Minimum execution time: 93_053_000 picoseconds. - Weight::from_parts(94_193_000, 42332) + // Estimated: `18187` + // Minimum execution time: 99_273_000 picoseconds. + Weight::from_parts(100_398_000, 18187) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } @@ -628,9 +639,9 @@ impl WeightInfo for () { fn external_propose() -> Weight { // Proof Size summary in bytes: // Measured: `3416` - // Estimated: `8320` - // Minimum execution time: 14_664_000 picoseconds. - Weight::from_parts(15_064_000, 8320) + // Estimated: `6703` + // Minimum execution time: 14_946_000 picoseconds. + Weight::from_parts(15_114_000, 6703) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -640,8 +651,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_073_000 picoseconds. - Weight::from_parts(4_242_000, 0) + // Minimum execution time: 3_870_000 picoseconds. + Weight::from_parts(4_083_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Democracy NextExternal (r:0 w:1) @@ -650,8 +661,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_779_000 picoseconds. - Weight::from_parts(4_091_000, 0) + // Minimum execution time: 3_989_000 picoseconds. + Weight::from_parts(4_166_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Democracy NextExternal (r:1 w:1) @@ -665,9 +676,9 @@ impl WeightInfo for () { fn fast_track() -> Weight { // Proof Size summary in bytes: // Measured: `286` - // Estimated: `6624` - // Minimum execution time: 29_596_000 picoseconds. - Weight::from_parts(30_083_000, 6624) + // Estimated: `3518` + // Minimum execution time: 29_776_000 picoseconds. + Weight::from_parts(30_186_000, 3518) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -680,9 +691,9 @@ impl WeightInfo for () { fn veto_external() -> Weight { // Proof Size summary in bytes: // Measured: `3519` - // Estimated: `11838` - // Minimum execution time: 34_721_000 picoseconds. - Weight::from_parts(34_989_000, 11838) + // Estimated: `6703` + // Minimum execution time: 33_891_000 picoseconds. + Weight::from_parts(34_265_000, 6703) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -697,9 +708,9 @@ impl WeightInfo for () { fn cancel_proposal() -> Weight { // Proof Size summary in bytes: // Measured: `5821` - // Estimated: `31993` - // Minimum execution time: 74_835_000 picoseconds. - Weight::from_parts(75_807_000, 31993) + // Estimated: `18187` + // Minimum execution time: 81_510_000 picoseconds. + Weight::from_parts(82_483_000, 18187) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -711,8 +722,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `271` // Estimated: `3518` - // Minimum execution time: 20_995_000 picoseconds. - Weight::from_parts(21_425_000, 3518) + // Minimum execution time: 21_164_000 picoseconds. + Weight::from_parts(21_624_000, 3518) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -726,11 +737,11 @@ impl WeightInfo for () { fn on_initialize_base(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `244 + r * (86 ±0)` - // Estimated: `3968 + r * (2676 ±0)` - // Minimum execution time: 7_002_000 picoseconds. - Weight::from_parts(10_543_534, 3968) - // Standard Error: 7_286 - .saturating_add(Weight::from_parts(2_911_122, 0).saturating_mul(r.into())) + // Estimated: `1489 + r * (2676 ±0)` + // Minimum execution time: 6_925_000 picoseconds. + Weight::from_parts(10_624_198, 1489) + // Standard Error: 5_780 + .saturating_add(Weight::from_parts(2_934_169, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) @@ -752,11 +763,11 @@ impl WeightInfo for () { fn on_initialize_base_with_launch_period(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `244 + r * (86 ±0)` - // Estimated: `25258 + r * (2676 ±0)` - // Minimum execution time: 10_824_000 picoseconds. - Weight::from_parts(14_187_527, 25258) - // Standard Error: 7_148 - .saturating_add(Weight::from_parts(2_886_910, 0).saturating_mul(r.into())) + // Estimated: `18187 + r * (2676 ±0)` + // Minimum execution time: 10_551_000 picoseconds. + Weight::from_parts(13_126_123, 18187) + // Standard Error: 6_391 + .saturating_add(Weight::from_parts(2_952_789, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) @@ -768,16 +779,18 @@ impl WeightInfo for () { /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// The range of component `r` is `[0, 99]`. fn delegate(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `830 + r * (108 ±0)` - // Estimated: `25554 + r * (2676 ±0)` - // Minimum execution time: 42_940_000 picoseconds. - Weight::from_parts(45_288_082, 25554) - // Standard Error: 6_380 - .saturating_add(Weight::from_parts(4_219_163, 0).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(4_u64)) + // Estimated: `19800 + r * (2676 ±0)` + // Minimum execution time: 47_172_000 picoseconds. + Weight::from_parts(49_667_954, 19800) + // Standard Error: 6_129 + .saturating_add(Weight::from_parts(4_230_402, 0).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(r.into()))) @@ -791,11 +804,11 @@ impl WeightInfo for () { fn undelegate(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `493 + r * (108 ±0)` - // Estimated: `14520 + r * (2676 ±0)` - // Minimum execution time: 22_203_000 picoseconds. - Weight::from_parts(22_307_372, 14520) - // Standard Error: 7_095 - .saturating_add(Weight::from_parts(4_202_995, 0).saturating_mul(r.into())) + // Estimated: `13530 + r * (2676 ±0)` + // Minimum execution time: 22_360_000 picoseconds. + Weight::from_parts(25_063_237, 13530) + // Standard Error: 5_326 + .saturating_add(Weight::from_parts(4_163_683, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(2_u64)) @@ -808,44 +821,48 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_046_000 picoseconds. - Weight::from_parts(4_191_000, 0) + // Minimum execution time: 4_047_000 picoseconds. + Weight::from_parts(4_139_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Democracy VotingOf (r:1 w:1) /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: System Account (r:1 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `r` is `[0, 99]`. fn unlock_remove(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `563` - // Estimated: `15617` - // Minimum execution time: 22_585_000 picoseconds. - Weight::from_parts(28_461_437, 15617) - // Standard Error: 1_636 - .saturating_add(Weight::from_parts(19_140, 0).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(3_u64)) + // Estimated: `7260` + // Minimum execution time: 27_322_000 picoseconds. + Weight::from_parts(39_909_589, 7260) + // Standard Error: 2_758 + .saturating_add(Weight::from_parts(29_497, 0).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: Democracy VotingOf (r:1 w:1) /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: System Account (r:1 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `r` is `[0, 99]`. fn unlock_set(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `564 + r * (22 ±0)` - // Estimated: `15617` - // Minimum execution time: 26_674_000 picoseconds. - Weight::from_parts(27_815_260, 15617) - // Standard Error: 490 - .saturating_add(Weight::from_parts(68_478, 0).saturating_mul(r.into())) - .saturating_add(RocksDbWeight::get().reads(3_u64)) + // Estimated: `7260` + // Minimum execution time: 37_082_000 picoseconds. + Weight::from_parts(38_580_061, 7260) + // Standard Error: 664 + .saturating_add(Weight::from_parts(62_401, 0).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: Democracy ReferendumInfoOf (r:1 w:1) @@ -856,11 +873,11 @@ impl WeightInfo for () { fn remove_vote(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `728 + r * (26 ±0)` - // Estimated: `10926` - // Minimum execution time: 17_381_000 picoseconds. - Weight::from_parts(19_728_665, 10926) - // Standard Error: 1_065 - .saturating_add(Weight::from_parts(84_481, 0).saturating_mul(r.into())) + // Estimated: `7260` + // Minimum execution time: 17_528_000 picoseconds. + Weight::from_parts(20_075_412, 7260) + // Standard Error: 1_072 + .saturating_add(Weight::from_parts(81_734, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -872,11 +889,11 @@ impl WeightInfo for () { fn remove_other_vote(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `728 + r * (26 ±0)` - // Estimated: `10926` - // Minimum execution time: 17_496_000 picoseconds. - Weight::from_parts(19_845_941, 10926) - // Standard Error: 1_169 - .saturating_add(Weight::from_parts(85_004, 0).saturating_mul(r.into())) + // Estimated: `7260` + // Minimum execution time: 17_517_000 picoseconds. + Weight::from_parts(20_090_718, 7260) + // Standard Error: 1_105 + .saturating_add(Weight::from_parts(82_651, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -889,9 +906,9 @@ impl WeightInfo for () { fn set_external_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `356` - // Estimated: `5173` - // Minimum execution time: 19_076_000 picoseconds. - Weight::from_parts(19_650_000, 5173) + // Estimated: `3556` + // Minimum execution time: 19_234_000 picoseconds. + Weight::from_parts(19_755_000, 3556) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -902,9 +919,9 @@ impl WeightInfo for () { fn clear_external_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `286` - // Estimated: `5135` - // Minimum execution time: 17_588_000 picoseconds. - Weight::from_parts(17_781_000, 5135) + // Estimated: `3518` + // Minimum execution time: 17_621_000 picoseconds. + Weight::from_parts(17_861_000, 3518) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -917,9 +934,9 @@ impl WeightInfo for () { fn set_proposal_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `4888` - // Estimated: `21743` - // Minimum execution time: 34_828_000 picoseconds. - Weight::from_parts(35_364_000, 21743) + // Estimated: `18187` + // Minimum execution time: 35_785_000 picoseconds. + Weight::from_parts(36_102_000, 18187) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -930,9 +947,9 @@ impl WeightInfo for () { fn clear_proposal_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `4822` - // Estimated: `21705` - // Minimum execution time: 32_035_000 picoseconds. - Weight::from_parts(32_554_000, 21705) + // Estimated: `18187` + // Minimum execution time: 33_493_000 picoseconds. + Weight::from_parts(33_747_000, 18187) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -944,8 +961,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `144` // Estimated: `3556` - // Minimum execution time: 15_279_000 picoseconds. - Weight::from_parts(15_556_000, 3556) + // Minimum execution time: 15_557_000 picoseconds. + Weight::from_parts(15_844_000, 3556) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -956,9 +973,9 @@ impl WeightInfo for () { fn clear_referendum_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `302` - // Estimated: `7184` - // Minimum execution time: 19_622_000 picoseconds. - Weight::from_parts(19_978_000, 7184) + // Estimated: `3666` + // Minimum execution time: 19_940_000 picoseconds. + Weight::from_parts(20_301_000, 3666) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/frame/election-provider-multi-phase/src/weights.rs b/frame/election-provider-multi-phase/src/weights.rs index f9dfdfc19aa3d..a1ba3514ca469 100644 --- a/frame/election-provider-multi-phase/src/weights.rs +++ b/frame/election-provider-multi-phase/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_election_provider_multi_phase //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,9 +31,6 @@ // --steps=50 // --repeat=20 // --pallet=pallet_election_provider_multi_phase -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -85,9 +82,9 @@ impl WeightInfo for SubstrateWeight { fn on_initialize_nothing() -> Weight { // Proof Size summary in bytes: // Measured: `994` - // Estimated: `14903` - // Minimum execution time: 21_538_000 picoseconds. - Weight::from_parts(22_045_000, 14903) + // Estimated: `3481` + // Minimum execution time: 21_239_000 picoseconds. + Weight::from_parts(21_970_000, 3481) .saturating_add(T::DbWeight::get().reads(8_u64)) } /// Storage: ElectionProviderMultiPhase Round (r:1 w:0) @@ -97,9 +94,9 @@ impl WeightInfo for SubstrateWeight { fn on_initialize_open_signed() -> Weight { // Proof Size summary in bytes: // Measured: `114` - // Estimated: `3198` - // Minimum execution time: 12_696_000 picoseconds. - Weight::from_parts(12_950_000, 3198) + // Estimated: `1599` + // Minimum execution time: 13_913_000 picoseconds. + Weight::from_parts(14_329_000, 1599) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -110,9 +107,9 @@ impl WeightInfo for SubstrateWeight { fn on_initialize_open_unsigned() -> Weight { // Proof Size summary in bytes: // Measured: `114` - // Estimated: `3198` - // Minimum execution time: 14_029_000 picoseconds. - Weight::from_parts(14_288_000, 3198) + // Estimated: `1599` + // Minimum execution time: 15_377_000 picoseconds. + Weight::from_parts(15_714_000, 1599) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -123,9 +120,9 @@ impl WeightInfo for SubstrateWeight { fn finalize_signed_phase_accept_solution() -> Weight { // Proof Size summary in bytes: // Measured: `174` - // Estimated: `3767` - // Minimum execution time: 26_468_000 picoseconds. - Weight::from_parts(26_790_000, 3767) + // Estimated: `3593` + // Minimum execution time: 32_899_000 picoseconds. + Weight::from_parts(33_455_000, 3593) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -135,8 +132,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 18_401_000 picoseconds. - Weight::from_parts(18_686_000, 3593) + // Minimum execution time: 22_532_000 picoseconds. + Weight::from_parts(23_039_000, 3593) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -152,10 +149,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 266_901_000 picoseconds. - Weight::from_parts(270_251_000, 0) - // Standard Error: 1_758 - .saturating_add(Weight::from_parts(167_310, 0).saturating_mul(v.into())) + // Minimum execution time: 253_511_000 picoseconds. + Weight::from_parts(261_190_000, 0) + // Standard Error: 1_621 + .saturating_add(Weight::from_parts(157_608, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: ElectionProviderMultiPhase SignedSubmissionIndices (r:1 w:1) @@ -181,17 +178,17 @@ impl WeightInfo for SubstrateWeight { fn elect_queued(a: u32, d: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `337 + a * (768 ±0) + d * (48 ±0)` - // Estimated: `16191 + a * (6912 ±0) + d * (441 ±0)` - // Minimum execution time: 286_523_000 picoseconds. - Weight::from_parts(19_101_753, 16191) - // Standard Error: 4_194 - .saturating_add(Weight::from_parts(398_102, 0).saturating_mul(a.into())) - // Standard Error: 6_287 - .saturating_add(Weight::from_parts(188_928, 0).saturating_mul(d.into())) + // Estimated: `3889 + a * (768 ±0) + d * (49 ±0)` + // Minimum execution time: 284_994_000 picoseconds. + Weight::from_parts(97_696_734, 3889) + // Standard Error: 4_172 + .saturating_add(Weight::from_parts(331_569, 0).saturating_mul(a.into())) + // Standard Error: 6_254 + .saturating_add(Weight::from_parts(92_198, 0).saturating_mul(d.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(8_u64)) - .saturating_add(Weight::from_parts(0, 6912).saturating_mul(a.into())) - .saturating_add(Weight::from_parts(0, 441).saturating_mul(d.into())) + .saturating_add(Weight::from_parts(0, 768).saturating_mul(a.into())) + .saturating_add(Weight::from_parts(0, 49).saturating_mul(d.into())) } /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) @@ -208,9 +205,9 @@ impl WeightInfo for SubstrateWeight { fn submit() -> Weight { // Proof Size summary in bytes: // Measured: `893` - // Estimated: `11906` - // Minimum execution time: 47_876_000 picoseconds. - Weight::from_parts(48_464_000, 11906) + // Estimated: `2378` + // Minimum execution time: 52_194_000 picoseconds. + Weight::from_parts(53_062_000, 2378) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -234,18 +231,18 @@ impl WeightInfo for SubstrateWeight { /// The range of component `d` is `[200, 400]`. fn submit_unsigned(v: u32, t: u32, a: u32, _d: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `219 + v * (553 ±0) + t * (32 ±0)` - // Estimated: `11928 + v * (3871 ±0) + t * (224 ±0)` - // Minimum execution time: 4_702_825_000 picoseconds. - Weight::from_parts(4_752_015_000, 11928) - // Standard Error: 14_906 - .saturating_add(Weight::from_parts(131_585, 0).saturating_mul(v.into())) - // Standard Error: 44_174 - .saturating_add(Weight::from_parts(4_167_676, 0).saturating_mul(a.into())) + // Measured: `219 + t * (32 ±0) + v * (553 ±0)` + // Estimated: `1704 + t * (32 ±0) + v * (553 ±0)` + // Minimum execution time: 4_843_067_000 picoseconds. + Weight::from_parts(4_860_833_000, 1704) + // Standard Error: 14_594 + .saturating_add(Weight::from_parts(76_611, 0).saturating_mul(v.into())) + // Standard Error: 43_249 + .saturating_add(Weight::from_parts(4_347_887, 0).saturating_mul(a.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) - .saturating_add(Weight::from_parts(0, 3871).saturating_mul(v.into())) - .saturating_add(Weight::from_parts(0, 224).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(0, 32).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(0, 553).saturating_mul(v.into())) } /// Storage: ElectionProviderMultiPhase DesiredTargets (r:1 w:0) /// Proof Skipped: ElectionProviderMultiPhase DesiredTargets (max_values: Some(1), max_size: None, mode: Measured) @@ -261,17 +258,17 @@ impl WeightInfo for SubstrateWeight { /// The range of component `d` is `[200, 400]`. fn feasibility_check(v: u32, t: u32, a: u32, _d: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `194 + v * (553 ±0) + t * (32 ±0)` - // Estimated: `6716 + v * (2212 ±0) + t * (128 ±0)` - // Minimum execution time: 4_069_075_000 picoseconds. - Weight::from_parts(4_105_635_000, 6716) - // Standard Error: 12_539 - .saturating_add(Weight::from_parts(163_040, 0).saturating_mul(v.into())) - // Standard Error: 37_160 - .saturating_add(Weight::from_parts(3_343_858, 0).saturating_mul(a.into())) + // Measured: `194 + t * (32 ±0) + v * (553 ±0)` + // Estimated: `1679 + t * (32 ±0) + v * (553 ±0)` + // Minimum execution time: 4_190_524_000 picoseconds. + Weight::from_parts(4_200_207_000, 1679) + // Standard Error: 12_454 + .saturating_add(Weight::from_parts(166_342, 0).saturating_mul(v.into())) + // Standard Error: 36_906 + .saturating_add(Weight::from_parts(3_493_372, 0).saturating_mul(a.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) - .saturating_add(Weight::from_parts(0, 2212).saturating_mul(v.into())) - .saturating_add(Weight::from_parts(0, 128).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(0, 32).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(0, 553).saturating_mul(v.into())) } } @@ -296,9 +293,9 @@ impl WeightInfo for () { fn on_initialize_nothing() -> Weight { // Proof Size summary in bytes: // Measured: `994` - // Estimated: `14903` - // Minimum execution time: 21_538_000 picoseconds. - Weight::from_parts(22_045_000, 14903) + // Estimated: `3481` + // Minimum execution time: 21_239_000 picoseconds. + Weight::from_parts(21_970_000, 3481) .saturating_add(RocksDbWeight::get().reads(8_u64)) } /// Storage: ElectionProviderMultiPhase Round (r:1 w:0) @@ -308,9 +305,9 @@ impl WeightInfo for () { fn on_initialize_open_signed() -> Weight { // Proof Size summary in bytes: // Measured: `114` - // Estimated: `3198` - // Minimum execution time: 12_696_000 picoseconds. - Weight::from_parts(12_950_000, 3198) + // Estimated: `1599` + // Minimum execution time: 13_913_000 picoseconds. + Weight::from_parts(14_329_000, 1599) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -321,9 +318,9 @@ impl WeightInfo for () { fn on_initialize_open_unsigned() -> Weight { // Proof Size summary in bytes: // Measured: `114` - // Estimated: `3198` - // Minimum execution time: 14_029_000 picoseconds. - Weight::from_parts(14_288_000, 3198) + // Estimated: `1599` + // Minimum execution time: 15_377_000 picoseconds. + Weight::from_parts(15_714_000, 1599) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -334,9 +331,9 @@ impl WeightInfo for () { fn finalize_signed_phase_accept_solution() -> Weight { // Proof Size summary in bytes: // Measured: `174` - // Estimated: `3767` - // Minimum execution time: 26_468_000 picoseconds. - Weight::from_parts(26_790_000, 3767) + // Estimated: `3593` + // Minimum execution time: 32_899_000 picoseconds. + Weight::from_parts(33_455_000, 3593) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -346,8 +343,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 18_401_000 picoseconds. - Weight::from_parts(18_686_000, 3593) + // Minimum execution time: 22_532_000 picoseconds. + Weight::from_parts(23_039_000, 3593) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -363,10 +360,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 266_901_000 picoseconds. - Weight::from_parts(270_251_000, 0) - // Standard Error: 1_758 - .saturating_add(Weight::from_parts(167_310, 0).saturating_mul(v.into())) + // Minimum execution time: 253_511_000 picoseconds. + Weight::from_parts(261_190_000, 0) + // Standard Error: 1_621 + .saturating_add(Weight::from_parts(157_608, 0).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: ElectionProviderMultiPhase SignedSubmissionIndices (r:1 w:1) @@ -392,17 +389,17 @@ impl WeightInfo for () { fn elect_queued(a: u32, d: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `337 + a * (768 ±0) + d * (48 ±0)` - // Estimated: `16191 + a * (6912 ±0) + d * (441 ±0)` - // Minimum execution time: 286_523_000 picoseconds. - Weight::from_parts(19_101_753, 16191) - // Standard Error: 4_194 - .saturating_add(Weight::from_parts(398_102, 0).saturating_mul(a.into())) - // Standard Error: 6_287 - .saturating_add(Weight::from_parts(188_928, 0).saturating_mul(d.into())) + // Estimated: `3889 + a * (768 ±0) + d * (49 ±0)` + // Minimum execution time: 284_994_000 picoseconds. + Weight::from_parts(97_696_734, 3889) + // Standard Error: 4_172 + .saturating_add(Weight::from_parts(331_569, 0).saturating_mul(a.into())) + // Standard Error: 6_254 + .saturating_add(Weight::from_parts(92_198, 0).saturating_mul(d.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(8_u64)) - .saturating_add(Weight::from_parts(0, 6912).saturating_mul(a.into())) - .saturating_add(Weight::from_parts(0, 441).saturating_mul(d.into())) + .saturating_add(Weight::from_parts(0, 768).saturating_mul(a.into())) + .saturating_add(Weight::from_parts(0, 49).saturating_mul(d.into())) } /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) @@ -419,9 +416,9 @@ impl WeightInfo for () { fn submit() -> Weight { // Proof Size summary in bytes: // Measured: `893` - // Estimated: `11906` - // Minimum execution time: 47_876_000 picoseconds. - Weight::from_parts(48_464_000, 11906) + // Estimated: `2378` + // Minimum execution time: 52_194_000 picoseconds. + Weight::from_parts(53_062_000, 2378) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -445,18 +442,18 @@ impl WeightInfo for () { /// The range of component `d` is `[200, 400]`. fn submit_unsigned(v: u32, t: u32, a: u32, _d: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `219 + v * (553 ±0) + t * (32 ±0)` - // Estimated: `11928 + v * (3871 ±0) + t * (224 ±0)` - // Minimum execution time: 4_702_825_000 picoseconds. - Weight::from_parts(4_752_015_000, 11928) - // Standard Error: 14_906 - .saturating_add(Weight::from_parts(131_585, 0).saturating_mul(v.into())) - // Standard Error: 44_174 - .saturating_add(Weight::from_parts(4_167_676, 0).saturating_mul(a.into())) + // Measured: `219 + t * (32 ±0) + v * (553 ±0)` + // Estimated: `1704 + t * (32 ±0) + v * (553 ±0)` + // Minimum execution time: 4_843_067_000 picoseconds. + Weight::from_parts(4_860_833_000, 1704) + // Standard Error: 14_594 + .saturating_add(Weight::from_parts(76_611, 0).saturating_mul(v.into())) + // Standard Error: 43_249 + .saturating_add(Weight::from_parts(4_347_887, 0).saturating_mul(a.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) - .saturating_add(Weight::from_parts(0, 3871).saturating_mul(v.into())) - .saturating_add(Weight::from_parts(0, 224).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(0, 32).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(0, 553).saturating_mul(v.into())) } /// Storage: ElectionProviderMultiPhase DesiredTargets (r:1 w:0) /// Proof Skipped: ElectionProviderMultiPhase DesiredTargets (max_values: Some(1), max_size: None, mode: Measured) @@ -472,16 +469,16 @@ impl WeightInfo for () { /// The range of component `d` is `[200, 400]`. fn feasibility_check(v: u32, t: u32, a: u32, _d: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `194 + v * (553 ±0) + t * (32 ±0)` - // Estimated: `6716 + v * (2212 ±0) + t * (128 ±0)` - // Minimum execution time: 4_069_075_000 picoseconds. - Weight::from_parts(4_105_635_000, 6716) - // Standard Error: 12_539 - .saturating_add(Weight::from_parts(163_040, 0).saturating_mul(v.into())) - // Standard Error: 37_160 - .saturating_add(Weight::from_parts(3_343_858, 0).saturating_mul(a.into())) + // Measured: `194 + t * (32 ±0) + v * (553 ±0)` + // Estimated: `1679 + t * (32 ±0) + v * (553 ±0)` + // Minimum execution time: 4_190_524_000 picoseconds. + Weight::from_parts(4_200_207_000, 1679) + // Standard Error: 12_454 + .saturating_add(Weight::from_parts(166_342, 0).saturating_mul(v.into())) + // Standard Error: 36_906 + .saturating_add(Weight::from_parts(3_493_372, 0).saturating_mul(a.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) - .saturating_add(Weight::from_parts(0, 2212).saturating_mul(v.into())) - .saturating_add(Weight::from_parts(0, 128).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(0, 32).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(0, 553).saturating_mul(v.into())) } } diff --git a/frame/elections-phragmen/src/weights.rs b/frame/elections-phragmen/src/weights.rs index 0ff6ecf290036..f0ebb8639e259 100644 --- a/frame/elections-phragmen/src/weights.rs +++ b/frame/elections-phragmen/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_elections_phragmen //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,9 +31,6 @@ // --steps=50 // --repeat=20 // --pallet=pallet_elections_phragmen -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -78,18 +75,20 @@ impl WeightInfo for SubstrateWeight { /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// The range of component `v` is `[1, 16]`. fn vote_equal(v: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `403 + v * (80 ±0)` - // Estimated: `14292 + v * (320 ±0)` - // Minimum execution time: 30_206_000 picoseconds. - Weight::from_parts(30_696_455, 14292) - // Standard Error: 1_864 - .saturating_add(Weight::from_parts(124_941, 0).saturating_mul(v.into())) - .saturating_add(T::DbWeight::get().reads(5_u64)) + // Estimated: `4764 + v * (80 ±0)` + // Minimum execution time: 33_623_000 picoseconds. + Weight::from_parts(34_531_239, 4764) + // Standard Error: 1_913 + .saturating_add(Weight::from_parts(131_360, 0).saturating_mul(v.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) - .saturating_add(Weight::from_parts(0, 320).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(0, 80).saturating_mul(v.into())) } /// Storage: Elections Candidates (r:1 w:0) /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) @@ -101,18 +100,20 @@ impl WeightInfo for SubstrateWeight { /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// The range of component `v` is `[2, 16]`. fn vote_more(v: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `371 + v * (80 ±0)` - // Estimated: `14164 + v * (320 ±0)` - // Minimum execution time: 40_331_000 picoseconds. - Weight::from_parts(40_936_971, 14164) - // Standard Error: 2_377 - .saturating_add(Weight::from_parts(142_332, 0).saturating_mul(v.into())) - .saturating_add(T::DbWeight::get().reads(5_u64)) + // Estimated: `4764 + v * (80 ±0)` + // Minimum execution time: 46_106_000 picoseconds. + Weight::from_parts(47_067_453, 4764) + // Standard Error: 2_441 + .saturating_add(Weight::from_parts(130_306, 0).saturating_mul(v.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) - .saturating_add(Weight::from_parts(0, 320).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(0, 80).saturating_mul(v.into())) } /// Storage: Elections Candidates (r:1 w:0) /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) @@ -124,30 +125,34 @@ impl WeightInfo for SubstrateWeight { /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// The range of component `v` is `[2, 16]`. fn vote_less(v: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `403 + v * (80 ±0)` - // Estimated: `14292 + v * (320 ±0)` - // Minimum execution time: 40_343_000 picoseconds. - Weight::from_parts(41_055_673, 14292) - // Standard Error: 3_150 - .saturating_add(Weight::from_parts(129_894, 0).saturating_mul(v.into())) - .saturating_add(T::DbWeight::get().reads(5_u64)) + // Estimated: `4764 + v * (80 ±0)` + // Minimum execution time: 46_094_000 picoseconds. + Weight::from_parts(47_054_638, 4764) + // Standard Error: 2_651 + .saturating_add(Weight::from_parts(137_251, 0).saturating_mul(v.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) - .saturating_add(Weight::from_parts(0, 320).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(0, 80).saturating_mul(v.into())) } /// Storage: Elections Voting (r:1 w:1) /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) fn remove_voter() -> Weight { // Proof Size summary in bytes: // Measured: `925` - // Estimated: `9154` - // Minimum execution time: 36_348_000 picoseconds. - Weight::from_parts(36_677_000, 9154) - .saturating_add(T::DbWeight::get().reads(2_u64)) + // Estimated: `4764` + // Minimum execution time: 49_652_000 picoseconds. + Weight::from_parts(50_217_000, 4764) + .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: Elections Candidates (r:1 w:1) @@ -160,14 +165,14 @@ impl WeightInfo for SubstrateWeight { fn submit_candidacy(c: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `1570 + c * (48 ±0)` - // Estimated: `9165 + c * (144 ±0)` - // Minimum execution time: 32_963_000 picoseconds. - Weight::from_parts(33_778_406, 9165) - // Standard Error: 2_792 - .saturating_add(Weight::from_parts(71_214, 0).saturating_mul(c.into())) + // Estimated: `3055 + c * (48 ±0)` + // Minimum execution time: 37_797_000 picoseconds. + Weight::from_parts(38_384_713, 3055) + // Standard Error: 1_008 + .saturating_add(Weight::from_parts(71_486, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) - .saturating_add(Weight::from_parts(0, 144).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(0, 48).saturating_mul(c.into())) } /// Storage: Elections Candidates (r:1 w:1) /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) @@ -176,10 +181,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `285 + c * (48 ±0)` // Estimated: `1770 + c * (48 ±0)` - // Minimum execution time: 26_462_000 picoseconds. - Weight::from_parts(27_289_268, 1770) - // Standard Error: 915 - .saturating_add(Weight::from_parts(45_079, 0).saturating_mul(c.into())) + // Minimum execution time: 31_112_000 picoseconds. + Weight::from_parts(31_660_924, 1770) + // Standard Error: 754 + .saturating_add(Weight::from_parts(48_689, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 48).saturating_mul(c.into())) @@ -197,9 +202,9 @@ impl WeightInfo for SubstrateWeight { fn renounce_candidacy_members() -> Weight { // Proof Size summary in bytes: // Measured: `1900` - // Estimated: `15440` - // Minimum execution time: 44_414_000 picoseconds. - Weight::from_parts(44_900_000, 15440) + // Estimated: `3385` + // Minimum execution time: 47_487_000 picoseconds. + Weight::from_parts(47_795_000, 3385) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -209,8 +214,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `880` // Estimated: `2365` - // Minimum execution time: 28_688_000 picoseconds. - Weight::from_parts(29_027_000, 2365) + // Minimum execution time: 31_479_000 picoseconds. + Weight::from_parts(32_093_000, 2365) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -238,9 +243,9 @@ impl WeightInfo for SubstrateWeight { fn remove_member_with_replacement() -> Weight { // Proof Size summary in bytes: // Measured: `1900` - // Estimated: `19033` - // Minimum execution time: 50_280_000 picoseconds. - Weight::from_parts(50_906_000, 19033) + // Estimated: `3593` + // Minimum execution time: 53_395_000 picoseconds. + Weight::from_parts(53_952_000, 3593) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -254,6 +259,8 @@ impl WeightInfo for SubstrateWeight { /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) /// Storage: Balances Locks (r:512 w:512) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:512 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: System Account (r:512 w:512) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `v` is `[256, 512]`. @@ -261,15 +268,15 @@ impl WeightInfo for SubstrateWeight { fn clean_defunct_voters(v: u32, _d: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `1115 + v * (811 ±0)` - // Estimated: `14388 + v * (12096 ±0)` - // Minimum execution time: 14_785_043_000 picoseconds. - Weight::from_parts(14_842_583_000, 14388) - // Standard Error: 242_757 - .saturating_add(Weight::from_parts(36_168_971, 0).saturating_mul(v.into())) + // Estimated: `4587 + v * (3774 ±0)` + // Minimum execution time: 18_089_406_000 picoseconds. + Weight::from_parts(18_125_024_000, 4587) + // Standard Error: 296_666 + .saturating_add(Weight::from_parts(42_527_045, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) - .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(v.into()))) + .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(v.into()))) - .saturating_add(Weight::from_parts(0, 12096).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(0, 3774).saturating_mul(v.into())) } /// Storage: Elections Candidates (r:1 w:1) /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) @@ -294,22 +301,22 @@ impl WeightInfo for SubstrateWeight { /// The range of component `e` is `[512, 8192]`. fn election_phragmen(c: u32, v: u32, e: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0 + v * (606 ±0) + e * (28 ±0)` - // Estimated: `309059 + v * (5005 ±8) + e * (89 ±0) + c * (2135 ±7)` - // Minimum execution time: 1_074_961_000 picoseconds. - Weight::from_parts(1_079_460_000, 309059) - // Standard Error: 598_993 - .saturating_add(Weight::from_parts(17_097_981, 0).saturating_mul(v.into())) - // Standard Error: 38_432 - .saturating_add(Weight::from_parts(820_141, 0).saturating_mul(e.into())) + // Measured: `0 + e * (28 ±0) + v * (606 ±0)` + // Estimated: `178887 + c * (2135 ±7) + e * (12 ±0) + v * (2653 ±6)` + // Minimum execution time: 1_193_774_000 picoseconds. + Weight::from_parts(1_196_649_000, 178887) + // Standard Error: 617_531 + .saturating_add(Weight::from_parts(17_672_923, 0).saturating_mul(v.into())) + // Standard Error: 39_622 + .saturating_add(Weight::from_parts(846_866, 0).saturating_mul(e.into())) .saturating_add(T::DbWeight::get().reads(21_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(c.into()))) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().writes(6_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(c.into()))) - .saturating_add(Weight::from_parts(0, 5005).saturating_mul(v.into())) - .saturating_add(Weight::from_parts(0, 89).saturating_mul(e.into())) .saturating_add(Weight::from_parts(0, 2135).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(0, 12).saturating_mul(e.into())) + .saturating_add(Weight::from_parts(0, 2653).saturating_mul(v.into())) } } @@ -325,18 +332,20 @@ impl WeightInfo for () { /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// The range of component `v` is `[1, 16]`. fn vote_equal(v: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `403 + v * (80 ±0)` - // Estimated: `14292 + v * (320 ±0)` - // Minimum execution time: 30_206_000 picoseconds. - Weight::from_parts(30_696_455, 14292) - // Standard Error: 1_864 - .saturating_add(Weight::from_parts(124_941, 0).saturating_mul(v.into())) - .saturating_add(RocksDbWeight::get().reads(5_u64)) + // Estimated: `4764 + v * (80 ±0)` + // Minimum execution time: 33_623_000 picoseconds. + Weight::from_parts(34_531_239, 4764) + // Standard Error: 1_913 + .saturating_add(Weight::from_parts(131_360, 0).saturating_mul(v.into())) + .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) - .saturating_add(Weight::from_parts(0, 320).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(0, 80).saturating_mul(v.into())) } /// Storage: Elections Candidates (r:1 w:0) /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) @@ -348,18 +357,20 @@ impl WeightInfo for () { /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// The range of component `v` is `[2, 16]`. fn vote_more(v: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `371 + v * (80 ±0)` - // Estimated: `14164 + v * (320 ±0)` - // Minimum execution time: 40_331_000 picoseconds. - Weight::from_parts(40_936_971, 14164) - // Standard Error: 2_377 - .saturating_add(Weight::from_parts(142_332, 0).saturating_mul(v.into())) - .saturating_add(RocksDbWeight::get().reads(5_u64)) + // Estimated: `4764 + v * (80 ±0)` + // Minimum execution time: 46_106_000 picoseconds. + Weight::from_parts(47_067_453, 4764) + // Standard Error: 2_441 + .saturating_add(Weight::from_parts(130_306, 0).saturating_mul(v.into())) + .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) - .saturating_add(Weight::from_parts(0, 320).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(0, 80).saturating_mul(v.into())) } /// Storage: Elections Candidates (r:1 w:0) /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) @@ -371,30 +382,34 @@ impl WeightInfo for () { /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// The range of component `v` is `[2, 16]`. fn vote_less(v: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `403 + v * (80 ±0)` - // Estimated: `14292 + v * (320 ±0)` - // Minimum execution time: 40_343_000 picoseconds. - Weight::from_parts(41_055_673, 14292) - // Standard Error: 3_150 - .saturating_add(Weight::from_parts(129_894, 0).saturating_mul(v.into())) - .saturating_add(RocksDbWeight::get().reads(5_u64)) + // Estimated: `4764 + v * (80 ±0)` + // Minimum execution time: 46_094_000 picoseconds. + Weight::from_parts(47_054_638, 4764) + // Standard Error: 2_651 + .saturating_add(Weight::from_parts(137_251, 0).saturating_mul(v.into())) + .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) - .saturating_add(Weight::from_parts(0, 320).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(0, 80).saturating_mul(v.into())) } /// Storage: Elections Voting (r:1 w:1) /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) fn remove_voter() -> Weight { // Proof Size summary in bytes: // Measured: `925` - // Estimated: `9154` - // Minimum execution time: 36_348_000 picoseconds. - Weight::from_parts(36_677_000, 9154) - .saturating_add(RocksDbWeight::get().reads(2_u64)) + // Estimated: `4764` + // Minimum execution time: 49_652_000 picoseconds. + Weight::from_parts(50_217_000, 4764) + .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: Elections Candidates (r:1 w:1) @@ -407,14 +422,14 @@ impl WeightInfo for () { fn submit_candidacy(c: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `1570 + c * (48 ±0)` - // Estimated: `9165 + c * (144 ±0)` - // Minimum execution time: 32_963_000 picoseconds. - Weight::from_parts(33_778_406, 9165) - // Standard Error: 2_792 - .saturating_add(Weight::from_parts(71_214, 0).saturating_mul(c.into())) + // Estimated: `3055 + c * (48 ±0)` + // Minimum execution time: 37_797_000 picoseconds. + Weight::from_parts(38_384_713, 3055) + // Standard Error: 1_008 + .saturating_add(Weight::from_parts(71_486, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) - .saturating_add(Weight::from_parts(0, 144).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(0, 48).saturating_mul(c.into())) } /// Storage: Elections Candidates (r:1 w:1) /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) @@ -423,10 +438,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `285 + c * (48 ±0)` // Estimated: `1770 + c * (48 ±0)` - // Minimum execution time: 26_462_000 picoseconds. - Weight::from_parts(27_289_268, 1770) - // Standard Error: 915 - .saturating_add(Weight::from_parts(45_079, 0).saturating_mul(c.into())) + // Minimum execution time: 31_112_000 picoseconds. + Weight::from_parts(31_660_924, 1770) + // Standard Error: 754 + .saturating_add(Weight::from_parts(48_689, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 48).saturating_mul(c.into())) @@ -444,9 +459,9 @@ impl WeightInfo for () { fn renounce_candidacy_members() -> Weight { // Proof Size summary in bytes: // Measured: `1900` - // Estimated: `15440` - // Minimum execution time: 44_414_000 picoseconds. - Weight::from_parts(44_900_000, 15440) + // Estimated: `3385` + // Minimum execution time: 47_487_000 picoseconds. + Weight::from_parts(47_795_000, 3385) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -456,8 +471,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `880` // Estimated: `2365` - // Minimum execution time: 28_688_000 picoseconds. - Weight::from_parts(29_027_000, 2365) + // Minimum execution time: 31_479_000 picoseconds. + Weight::from_parts(32_093_000, 2365) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -485,9 +500,9 @@ impl WeightInfo for () { fn remove_member_with_replacement() -> Weight { // Proof Size summary in bytes: // Measured: `1900` - // Estimated: `19033` - // Minimum execution time: 50_280_000 picoseconds. - Weight::from_parts(50_906_000, 19033) + // Estimated: `3593` + // Minimum execution time: 53_395_000 picoseconds. + Weight::from_parts(53_952_000, 3593) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -501,6 +516,8 @@ impl WeightInfo for () { /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) /// Storage: Balances Locks (r:512 w:512) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:512 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: System Account (r:512 w:512) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `v` is `[256, 512]`. @@ -508,15 +525,15 @@ impl WeightInfo for () { fn clean_defunct_voters(v: u32, _d: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `1115 + v * (811 ±0)` - // Estimated: `14388 + v * (12096 ±0)` - // Minimum execution time: 14_785_043_000 picoseconds. - Weight::from_parts(14_842_583_000, 14388) - // Standard Error: 242_757 - .saturating_add(Weight::from_parts(36_168_971, 0).saturating_mul(v.into())) + // Estimated: `4587 + v * (3774 ±0)` + // Minimum execution time: 18_089_406_000 picoseconds. + Weight::from_parts(18_125_024_000, 4587) + // Standard Error: 296_666 + .saturating_add(Weight::from_parts(42_527_045, 0).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) - .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(v.into()))) + .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(v.into()))) .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(v.into()))) - .saturating_add(Weight::from_parts(0, 12096).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(0, 3774).saturating_mul(v.into())) } /// Storage: Elections Candidates (r:1 w:1) /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) @@ -541,21 +558,21 @@ impl WeightInfo for () { /// The range of component `e` is `[512, 8192]`. fn election_phragmen(c: u32, v: u32, e: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0 + v * (606 ±0) + e * (28 ±0)` - // Estimated: `309059 + v * (5005 ±8) + e * (89 ±0) + c * (2135 ±7)` - // Minimum execution time: 1_074_961_000 picoseconds. - Weight::from_parts(1_079_460_000, 309059) - // Standard Error: 598_993 - .saturating_add(Weight::from_parts(17_097_981, 0).saturating_mul(v.into())) - // Standard Error: 38_432 - .saturating_add(Weight::from_parts(820_141, 0).saturating_mul(e.into())) + // Measured: `0 + e * (28 ±0) + v * (606 ±0)` + // Estimated: `178887 + c * (2135 ±7) + e * (12 ±0) + v * (2653 ±6)` + // Minimum execution time: 1_193_774_000 picoseconds. + Weight::from_parts(1_196_649_000, 178887) + // Standard Error: 617_531 + .saturating_add(Weight::from_parts(17_672_923, 0).saturating_mul(v.into())) + // Standard Error: 39_622 + .saturating_add(Weight::from_parts(846_866, 0).saturating_mul(e.into())) .saturating_add(RocksDbWeight::get().reads(21_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(c.into()))) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(v.into()))) .saturating_add(RocksDbWeight::get().writes(6_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(c.into()))) - .saturating_add(Weight::from_parts(0, 5005).saturating_mul(v.into())) - .saturating_add(Weight::from_parts(0, 89).saturating_mul(e.into())) .saturating_add(Weight::from_parts(0, 2135).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(0, 12).saturating_mul(e.into())) + .saturating_add(Weight::from_parts(0, 2653).saturating_mul(v.into())) } } diff --git a/frame/fast-unstake/src/weights.rs b/frame/fast-unstake/src/weights.rs index b47d4f056e524..27414a8a8cc0d 100644 --- a/frame/fast-unstake/src/weights.rs +++ b/frame/fast-unstake/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_fast_unstake //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,9 +31,6 @@ // --steps=50 // --repeat=20 // --pallet=pallet_fast_unstake -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -85,6 +82,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: Balances Locks (r:64 w:64) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:64 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: Staking Ledger (r:0 w:64) /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) /// Storage: Staking Payee (r:0 w:64) @@ -93,16 +92,16 @@ impl WeightInfo for SubstrateWeight { fn on_idle_unstake(b: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `1344 + b * (343 ±0)` - // Estimated: `23254 + b * (17642 ±0)` - // Minimum execution time: 78_484_000 picoseconds. - Weight::from_parts(39_186_541, 23254) - // Standard Error: 37_606 - .saturating_add(Weight::from_parts(42_433_199, 0).saturating_mul(b.into())) + // Estimated: `7253 + b * (3774 ±0)` + // Minimum execution time: 92_282_000 picoseconds. + Weight::from_parts(31_665_344, 7253) + // Standard Error: 35_348 + .saturating_add(Weight::from_parts(57_005_152, 0).saturating_mul(b.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) - .saturating_add(T::DbWeight::get().reads((6_u64).saturating_mul(b.into()))) + .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(b.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(T::DbWeight::get().writes((5_u64).saturating_mul(b.into()))) - .saturating_add(Weight::from_parts(0, 17642).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(0, 3774).saturating_mul(b.into())) } /// Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) /// Proof: FastUnstake ErasToCheckPerBlock (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -122,19 +121,19 @@ impl WeightInfo for SubstrateWeight { /// The range of component `b` is `[1, 64]`. fn on_idle_check(v: u32, b: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1512 + v * (10037 ±0) + b * (48 ±0)` - // Estimated: `20889 + v * (22551 ±0) + b * (98 ±0)` - // Minimum execution time: 1_538_727_000 picoseconds. - Weight::from_parts(1_549_586_000, 20889) - // Standard Error: 14_184_223 - .saturating_add(Weight::from_parts(452_966_006, 0).saturating_mul(v.into())) - // Standard Error: 56_752_692 - .saturating_add(Weight::from_parts(1_775_601_329, 0).saturating_mul(b.into())) + // Measured: `1512 + b * (48 ±0) + v * (10037 ±0)` + // Estimated: `7253 + b * (49 ±0) + v * (12513 ±0)` + // Minimum execution time: 1_547_716_000 picoseconds. + Weight::from_parts(1_552_476_000, 7253) + // Standard Error: 13_914_457 + .saturating_add(Weight::from_parts(445_314_876, 0).saturating_mul(v.into())) + // Standard Error: 55_673_329 + .saturating_add(Weight::from_parts(1_749_024_692, 0).saturating_mul(b.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) - .saturating_add(Weight::from_parts(0, 22551).saturating_mul(v.into())) - .saturating_add(Weight::from_parts(0, 98).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(0, 49).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(0, 12513).saturating_mul(v.into())) } /// Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) /// Proof: FastUnstake ErasToCheckPerBlock (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -162,15 +161,17 @@ impl WeightInfo for SubstrateWeight { /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: FastUnstake CounterForQueue (r:1 w:1) /// Proof: FastUnstake CounterForQueue (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn register_fast_unstake() -> Weight { // Proof Size summary in bytes: // Measured: `1964` - // Estimated: `45775` - // Minimum execution time: 117_552_000 picoseconds. - Weight::from_parts(118_303_000, 45775) - .saturating_add(T::DbWeight::get().reads(14_u64)) + // Estimated: `7253` + // Minimum execution time: 124_644_000 picoseconds. + Weight::from_parts(125_793_000, 7253) + .saturating_add(T::DbWeight::get().reads(15_u64)) .saturating_add(T::DbWeight::get().writes(9_u64)) } /// Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) @@ -186,9 +187,9 @@ impl WeightInfo for SubstrateWeight { fn deregister() -> Weight { // Proof Size summary in bytes: // Measured: `1223` - // Estimated: `18308` - // Minimum execution time: 42_291_000 picoseconds. - Weight::from_parts(42_835_000, 18308) + // Estimated: `7253` + // Minimum execution time: 45_037_000 picoseconds. + Weight::from_parts(45_545_000, 7253) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -198,8 +199,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_551_000 picoseconds. - Weight::from_parts(3_632_000, 0) + // Minimum execution time: 3_228_000 picoseconds. + Weight::from_parts(3_428_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } } @@ -230,6 +231,8 @@ impl WeightInfo for () { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: Balances Locks (r:64 w:64) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:64 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: Staking Ledger (r:0 w:64) /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) /// Storage: Staking Payee (r:0 w:64) @@ -238,16 +241,16 @@ impl WeightInfo for () { fn on_idle_unstake(b: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `1344 + b * (343 ±0)` - // Estimated: `23254 + b * (17642 ±0)` - // Minimum execution time: 78_484_000 picoseconds. - Weight::from_parts(39_186_541, 23254) - // Standard Error: 37_606 - .saturating_add(Weight::from_parts(42_433_199, 0).saturating_mul(b.into())) + // Estimated: `7253 + b * (3774 ±0)` + // Minimum execution time: 92_282_000 picoseconds. + Weight::from_parts(31_665_344, 7253) + // Standard Error: 35_348 + .saturating_add(Weight::from_parts(57_005_152, 0).saturating_mul(b.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) - .saturating_add(RocksDbWeight::get().reads((6_u64).saturating_mul(b.into()))) + .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(b.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(RocksDbWeight::get().writes((5_u64).saturating_mul(b.into()))) - .saturating_add(Weight::from_parts(0, 17642).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(0, 3774).saturating_mul(b.into())) } /// Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) /// Proof: FastUnstake ErasToCheckPerBlock (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -267,19 +270,19 @@ impl WeightInfo for () { /// The range of component `b` is `[1, 64]`. fn on_idle_check(v: u32, b: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1512 + v * (10037 ±0) + b * (48 ±0)` - // Estimated: `20889 + v * (22551 ±0) + b * (98 ±0)` - // Minimum execution time: 1_538_727_000 picoseconds. - Weight::from_parts(1_549_586_000, 20889) - // Standard Error: 14_184_223 - .saturating_add(Weight::from_parts(452_966_006, 0).saturating_mul(v.into())) - // Standard Error: 56_752_692 - .saturating_add(Weight::from_parts(1_775_601_329, 0).saturating_mul(b.into())) + // Measured: `1512 + b * (48 ±0) + v * (10037 ±0)` + // Estimated: `7253 + b * (49 ±0) + v * (12513 ±0)` + // Minimum execution time: 1_547_716_000 picoseconds. + Weight::from_parts(1_552_476_000, 7253) + // Standard Error: 13_914_457 + .saturating_add(Weight::from_parts(445_314_876, 0).saturating_mul(v.into())) + // Standard Error: 55_673_329 + .saturating_add(Weight::from_parts(1_749_024_692, 0).saturating_mul(b.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(v.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) - .saturating_add(Weight::from_parts(0, 22551).saturating_mul(v.into())) - .saturating_add(Weight::from_parts(0, 98).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(0, 49).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(0, 12513).saturating_mul(v.into())) } /// Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) /// Proof: FastUnstake ErasToCheckPerBlock (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -307,15 +310,17 @@ impl WeightInfo for () { /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: FastUnstake CounterForQueue (r:1 w:1) /// Proof: FastUnstake CounterForQueue (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn register_fast_unstake() -> Weight { // Proof Size summary in bytes: // Measured: `1964` - // Estimated: `45775` - // Minimum execution time: 117_552_000 picoseconds. - Weight::from_parts(118_303_000, 45775) - .saturating_add(RocksDbWeight::get().reads(14_u64)) + // Estimated: `7253` + // Minimum execution time: 124_644_000 picoseconds. + Weight::from_parts(125_793_000, 7253) + .saturating_add(RocksDbWeight::get().reads(15_u64)) .saturating_add(RocksDbWeight::get().writes(9_u64)) } /// Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) @@ -331,9 +336,9 @@ impl WeightInfo for () { fn deregister() -> Weight { // Proof Size summary in bytes: // Measured: `1223` - // Estimated: `18308` - // Minimum execution time: 42_291_000 picoseconds. - Weight::from_parts(42_835_000, 18308) + // Estimated: `7253` + // Minimum execution time: 45_037_000 picoseconds. + Weight::from_parts(45_545_000, 7253) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -343,8 +348,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_551_000 picoseconds. - Weight::from_parts(3_632_000, 0) + // Minimum execution time: 3_228_000 picoseconds. + Weight::from_parts(3_428_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } } diff --git a/frame/glutton/src/weights.rs b/frame/glutton/src/weights.rs index bd409645ae8ff..82bac91c6d785 100644 --- a/frame/glutton/src/weights.rs +++ b/frame/glutton/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_glutton //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,9 +31,6 @@ // --steps=50 // --repeat=20 // --pallet=pallet_glutton -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -74,10 +71,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `4` // Estimated: `1489` - // Minimum execution time: 10_384_000 picoseconds. - Weight::from_parts(10_598_000, 1489) - // Standard Error: 1_369 - .saturating_add(Weight::from_parts(1_580_155, 0).saturating_mul(n.into())) + // Minimum execution time: 10_410_000 picoseconds. + Weight::from_parts(10_515_000, 1489) + // Standard Error: 1_069 + .saturating_add(Weight::from_parts(1_513_013, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) @@ -91,10 +88,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `65` // Estimated: `1489` - // Minimum execution time: 11_022_000 picoseconds. - Weight::from_parts(11_319_000, 1489) - // Standard Error: 1_108 - .saturating_add(Weight::from_parts(1_048_682, 0).saturating_mul(n.into())) + // Minimum execution time: 11_105_000 picoseconds. + Weight::from_parts(584_850, 1489) + // Standard Error: 1_417 + .saturating_add(Weight::from_parts(1_054_988, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) @@ -104,10 +101,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 660_000 picoseconds. - Weight::from_parts(7_814_200, 0) - // Standard Error: 33 - .saturating_add(Weight::from_parts(94_390, 0).saturating_mul(i.into())) + // Minimum execution time: 709_000 picoseconds. + Weight::from_parts(7_409_096, 0) + // Standard Error: 23 + .saturating_add(Weight::from_parts(95_342, 0).saturating_mul(i.into())) } /// Storage: Glutton TrashData (r:5000 w:0) /// Proof: Glutton TrashData (max_values: Some(65000), max_size: Some(1036), added: 3016, mode: MaxEncodedLen) @@ -116,10 +113,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `119036 + i * (1022 ±0)` // Estimated: `990 + i * (3016 ±0)` - // Minimum execution time: 712_000 picoseconds. - Weight::from_parts(814_000, 990) - // Standard Error: 1_805 - .saturating_add(Weight::from_parts(5_407_690, 0).saturating_mul(i.into())) + // Minimum execution time: 584_000 picoseconds. + Weight::from_parts(674_000, 990) + // Standard Error: 1_802 + .saturating_add(Weight::from_parts(5_360_522, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(i.into()))) .saturating_add(Weight::from_parts(0, 3016).saturating_mul(i.into())) } @@ -132,9 +129,9 @@ impl WeightInfo for SubstrateWeight { fn on_idle_high_proof_waste() -> Weight { // Proof Size summary in bytes: // Measured: `1900466` - // Estimated: `5242760` - // Minimum execution time: 54_903_045_000 picoseconds. - Weight::from_parts(55_194_691_000, 5242760) + // Estimated: `5239782` + // Minimum execution time: 57_124_610_000 picoseconds. + Weight::from_parts(57_256_059_000, 5239782) .saturating_add(T::DbWeight::get().reads(1739_u64)) } /// Storage: Glutton Storage (r:1 w:0) @@ -146,9 +143,9 @@ impl WeightInfo for SubstrateWeight { fn on_idle_low_proof_waste() -> Weight { // Proof Size summary in bytes: // Measured: `9516` - // Estimated: `19048` - // Minimum execution time: 97_295_331_000 picoseconds. - Weight::from_parts(97_853_502_000, 19048) + // Estimated: `16070` + // Minimum execution time: 101_500_066_000 picoseconds. + Weight::from_parts(101_621_640_000, 16070) .saturating_add(T::DbWeight::get().reads(7_u64)) } /// Storage: Glutton Storage (r:1 w:0) @@ -158,9 +155,9 @@ impl WeightInfo for SubstrateWeight { fn empty_on_idle() -> Weight { // Proof Size summary in bytes: // Measured: `4` - // Estimated: `2978` - // Minimum execution time: 4_280_000 picoseconds. - Weight::from_parts(4_381_000, 2978) + // Estimated: `1489` + // Minimum execution time: 4_164_000 picoseconds. + Weight::from_parts(4_378_000, 1489) .saturating_add(T::DbWeight::get().reads(2_u64)) } /// Storage: Glutton Compute (r:0 w:1) @@ -169,8 +166,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_758_000 picoseconds. - Weight::from_parts(8_988_000, 0) + // Minimum execution time: 8_795_000 picoseconds. + Weight::from_parts(9_076_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Glutton Storage (r:0 w:1) @@ -179,8 +176,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_901_000 picoseconds. - Weight::from_parts(9_291_000, 0) + // Minimum execution time: 8_979_000 picoseconds. + Weight::from_parts(9_195_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } } @@ -196,10 +193,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `4` // Estimated: `1489` - // Minimum execution time: 10_384_000 picoseconds. - Weight::from_parts(10_598_000, 1489) - // Standard Error: 1_369 - .saturating_add(Weight::from_parts(1_580_155, 0).saturating_mul(n.into())) + // Minimum execution time: 10_410_000 picoseconds. + Weight::from_parts(10_515_000, 1489) + // Standard Error: 1_069 + .saturating_add(Weight::from_parts(1_513_013, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) @@ -213,10 +210,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `65` // Estimated: `1489` - // Minimum execution time: 11_022_000 picoseconds. - Weight::from_parts(11_319_000, 1489) - // Standard Error: 1_108 - .saturating_add(Weight::from_parts(1_048_682, 0).saturating_mul(n.into())) + // Minimum execution time: 11_105_000 picoseconds. + Weight::from_parts(584_850, 1489) + // Standard Error: 1_417 + .saturating_add(Weight::from_parts(1_054_988, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) @@ -226,10 +223,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 660_000 picoseconds. - Weight::from_parts(7_814_200, 0) - // Standard Error: 33 - .saturating_add(Weight::from_parts(94_390, 0).saturating_mul(i.into())) + // Minimum execution time: 709_000 picoseconds. + Weight::from_parts(7_409_096, 0) + // Standard Error: 23 + .saturating_add(Weight::from_parts(95_342, 0).saturating_mul(i.into())) } /// Storage: Glutton TrashData (r:5000 w:0) /// Proof: Glutton TrashData (max_values: Some(65000), max_size: Some(1036), added: 3016, mode: MaxEncodedLen) @@ -238,10 +235,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `119036 + i * (1022 ±0)` // Estimated: `990 + i * (3016 ±0)` - // Minimum execution time: 712_000 picoseconds. - Weight::from_parts(814_000, 990) - // Standard Error: 1_805 - .saturating_add(Weight::from_parts(5_407_690, 0).saturating_mul(i.into())) + // Minimum execution time: 584_000 picoseconds. + Weight::from_parts(674_000, 990) + // Standard Error: 1_802 + .saturating_add(Weight::from_parts(5_360_522, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(i.into()))) .saturating_add(Weight::from_parts(0, 3016).saturating_mul(i.into())) } @@ -254,9 +251,9 @@ impl WeightInfo for () { fn on_idle_high_proof_waste() -> Weight { // Proof Size summary in bytes: // Measured: `1900466` - // Estimated: `5242760` - // Minimum execution time: 54_903_045_000 picoseconds. - Weight::from_parts(55_194_691_000, 5242760) + // Estimated: `5239782` + // Minimum execution time: 57_124_610_000 picoseconds. + Weight::from_parts(57_256_059_000, 5239782) .saturating_add(RocksDbWeight::get().reads(1739_u64)) } /// Storage: Glutton Storage (r:1 w:0) @@ -268,9 +265,9 @@ impl WeightInfo for () { fn on_idle_low_proof_waste() -> Weight { // Proof Size summary in bytes: // Measured: `9516` - // Estimated: `19048` - // Minimum execution time: 97_295_331_000 picoseconds. - Weight::from_parts(97_853_502_000, 19048) + // Estimated: `16070` + // Minimum execution time: 101_500_066_000 picoseconds. + Weight::from_parts(101_621_640_000, 16070) .saturating_add(RocksDbWeight::get().reads(7_u64)) } /// Storage: Glutton Storage (r:1 w:0) @@ -280,9 +277,9 @@ impl WeightInfo for () { fn empty_on_idle() -> Weight { // Proof Size summary in bytes: // Measured: `4` - // Estimated: `2978` - // Minimum execution time: 4_280_000 picoseconds. - Weight::from_parts(4_381_000, 2978) + // Estimated: `1489` + // Minimum execution time: 4_164_000 picoseconds. + Weight::from_parts(4_378_000, 1489) .saturating_add(RocksDbWeight::get().reads(2_u64)) } /// Storage: Glutton Compute (r:0 w:1) @@ -291,8 +288,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_758_000 picoseconds. - Weight::from_parts(8_988_000, 0) + // Minimum execution time: 8_795_000 picoseconds. + Weight::from_parts(9_076_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Glutton Storage (r:0 w:1) @@ -301,8 +298,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_901_000 picoseconds. - Weight::from_parts(9_291_000, 0) + // Minimum execution time: 8_979_000 picoseconds. + Weight::from_parts(9_195_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } } diff --git a/frame/identity/src/weights.rs b/frame/identity/src/weights.rs index bad6aa76854ea..faefd00fb961f 100644 --- a/frame/identity/src/weights.rs +++ b/frame/identity/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_identity //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,9 +31,6 @@ // --steps=50 // --repeat=20 // --pallet=pallet_identity -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -79,10 +76,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `32 + r * (57 ±0)` // Estimated: `2626` - // Minimum execution time: 13_092_000 picoseconds. - Weight::from_parts(13_798_719, 2626) - // Standard Error: 1_553 - .saturating_add(Weight::from_parts(109_215, 0).saturating_mul(r.into())) + // Minimum execution time: 12_851_000 picoseconds. + Weight::from_parts(13_448_645, 2626) + // Standard Error: 1_636 + .saturating_add(Weight::from_parts(113_654, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -94,12 +91,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `442 + r * (5 ±0)` // Estimated: `11003` - // Minimum execution time: 30_800_000 picoseconds. - Weight::from_parts(31_140_040, 11003) - // Standard Error: 4_896 - .saturating_add(Weight::from_parts(69_348, 0).saturating_mul(r.into())) - // Standard Error: 955 - .saturating_add(Weight::from_parts(430_082, 0).saturating_mul(x.into())) + // Minimum execution time: 33_342_000 picoseconds. + Weight::from_parts(33_155_116, 11003) + // Standard Error: 2_307 + .saturating_add(Weight::from_parts(56_409, 0).saturating_mul(r.into())) + // Standard Error: 450 + .saturating_add(Weight::from_parts(437_684, 0).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -113,11 +110,11 @@ impl WeightInfo for SubstrateWeight { fn set_subs_new(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `101` - // Estimated: `18716 + s * (2589 ±0)` - // Minimum execution time: 10_301_000 picoseconds. - Weight::from_parts(23_255_636, 18716) - // Standard Error: 5_562 - .saturating_add(Weight::from_parts(2_978_765, 0).saturating_mul(s.into())) + // Estimated: `11003 + s * (2589 ±0)` + // Minimum execution time: 10_315_000 picoseconds. + Weight::from_parts(26_535_526, 11003) + // Standard Error: 4_344 + .saturating_add(Weight::from_parts(3_016_873, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(s.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) @@ -134,11 +131,11 @@ impl WeightInfo for SubstrateWeight { fn set_subs_old(p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `194 + p * (32 ±0)` - // Estimated: `17726` - // Minimum execution time: 10_095_000 picoseconds. - Weight::from_parts(23_197_533, 17726) - // Standard Error: 3_460 - .saturating_add(Weight::from_parts(1_227_498, 0).saturating_mul(p.into())) + // Estimated: `11003` + // Minimum execution time: 10_220_000 picoseconds. + Weight::from_parts(25_050_056, 11003) + // Standard Error: 3_621 + .saturating_add(Weight::from_parts(1_291_143, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(p.into()))) @@ -155,13 +152,13 @@ impl WeightInfo for SubstrateWeight { fn clear_identity(_r: u32, s: u32, x: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `469 + r * (5 ±0) + s * (32 ±0) + x * (66 ±0)` - // Estimated: `17726` - // Minimum execution time: 51_054_000 picoseconds. - Weight::from_parts(30_184_047, 17726) - // Standard Error: 2_441 - .saturating_add(Weight::from_parts(1_221_983, 0).saturating_mul(s.into())) - // Standard Error: 2_441 - .saturating_add(Weight::from_parts(234_084, 0).saturating_mul(x.into())) + // Estimated: `11003` + // Minimum execution time: 56_018_000 picoseconds. + Weight::from_parts(37_757_186, 11003) + // Standard Error: 1_852 + .saturating_add(Weight::from_parts(1_257_980, 0).saturating_mul(s.into())) + // Standard Error: 1_852 + .saturating_add(Weight::from_parts(215_426, 0).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -175,13 +172,13 @@ impl WeightInfo for SubstrateWeight { fn request_judgement(r: u32, x: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `367 + r * (57 ±0) + x * (66 ±0)` - // Estimated: `13629` - // Minimum execution time: 32_747_000 picoseconds. - Weight::from_parts(29_557_659, 13629) - // Standard Error: 4_616 - .saturating_add(Weight::from_parts(200_494, 0).saturating_mul(r.into())) - // Standard Error: 900 - .saturating_add(Weight::from_parts(468_381, 0).saturating_mul(x.into())) + // Estimated: `11003` + // Minimum execution time: 34_792_000 picoseconds. + Weight::from_parts(35_368_327, 11003) + // Standard Error: 3_476 + .saturating_add(Weight::from_parts(78_981, 0).saturating_mul(r.into())) + // Standard Error: 678 + .saturating_add(Weight::from_parts(459_077, 0).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -189,16 +186,14 @@ impl WeightInfo for SubstrateWeight { /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) /// The range of component `r` is `[1, 20]`. /// The range of component `x` is `[0, 100]`. - fn cancel_request(r: u32, x: u32, ) -> Weight { + fn cancel_request(_r: u32, x: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `398 + x * (66 ±0)` // Estimated: `11003` - // Minimum execution time: 28_853_000 picoseconds. - Weight::from_parts(26_811_119, 11003) - // Standard Error: 15_667 - .saturating_add(Weight::from_parts(240_647, 0).saturating_mul(r.into())) - // Standard Error: 3_056 - .saturating_add(Weight::from_parts(462_536, 0).saturating_mul(x.into())) + // Minimum execution time: 31_306_000 picoseconds. + Weight::from_parts(33_304_799, 11003) + // Standard Error: 892 + .saturating_add(Weight::from_parts(451_655, 0).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -209,10 +204,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `89 + r * (57 ±0)` // Estimated: `2626` - // Minimum execution time: 8_413_000 picoseconds. - Weight::from_parts(8_846_436, 2626) - // Standard Error: 1_470 - .saturating_add(Weight::from_parts(113_780, 0).saturating_mul(r.into())) + // Minimum execution time: 8_215_000 picoseconds. + Weight::from_parts(8_692_102, 2626) + // Standard Error: 1_455 + .saturating_add(Weight::from_parts(110_912, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -223,10 +218,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `89 + r * (57 ±0)` // Estimated: `2626` - // Minimum execution time: 8_753_000 picoseconds. - Weight::from_parts(9_143_938, 2626) - // Standard Error: 1_490 - .saturating_add(Weight::from_parts(113_406, 0).saturating_mul(r.into())) + // Minimum execution time: 8_397_000 picoseconds. + Weight::from_parts(8_787_656, 2626) + // Standard Error: 1_440 + .saturating_add(Weight::from_parts(111_212, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -237,10 +232,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `89 + r * (57 ±0)` // Estimated: `2626` - // Minimum execution time: 8_320_000 picoseconds. - Weight::from_parts(8_800_306, 2626) - // Standard Error: 1_345 - .saturating_add(Weight::from_parts(125_258, 0).saturating_mul(r.into())) + // Minimum execution time: 8_466_000 picoseconds. + Weight::from_parts(8_689_763, 2626) + // Standard Error: 1_536 + .saturating_add(Weight::from_parts(106_371, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -253,13 +248,13 @@ impl WeightInfo for SubstrateWeight { fn provide_judgement(r: u32, x: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `445 + r * (57 ±0) + x * (66 ±0)` - // Estimated: `13629` - // Minimum execution time: 25_313_000 picoseconds. - Weight::from_parts(23_968_548, 13629) - // Standard Error: 4_143 - .saturating_add(Weight::from_parts(164_678, 0).saturating_mul(r.into())) - // Standard Error: 766 - .saturating_add(Weight::from_parts(713_576, 0).saturating_mul(x.into())) + // Estimated: `11003` + // Minimum execution time: 25_132_000 picoseconds. + Weight::from_parts(20_582_313, 11003) + // Standard Error: 10_427 + .saturating_add(Weight::from_parts(277_545, 0).saturating_mul(r.into())) + // Standard Error: 1_929 + .saturating_add(Weight::from_parts(747_966, 0).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -277,15 +272,15 @@ impl WeightInfo for SubstrateWeight { fn kill_identity(r: u32, s: u32, x: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `676 + r * (5 ±0) + s * (32 ±0) + x * (66 ±0)` - // Estimated: `21319` - // Minimum execution time: 64_638_000 picoseconds. - Weight::from_parts(43_317_654, 21319) - // Standard Error: 10_182 - .saturating_add(Weight::from_parts(61_967, 0).saturating_mul(r.into())) - // Standard Error: 1_988 - .saturating_add(Weight::from_parts(1_224_202, 0).saturating_mul(s.into())) - // Standard Error: 1_988 - .saturating_add(Weight::from_parts(233_897, 0).saturating_mul(x.into())) + // Estimated: `11003` + // Minimum execution time: 72_043_000 picoseconds. + Weight::from_parts(50_994_735, 11003) + // Standard Error: 9_304 + .saturating_add(Weight::from_parts(123_052, 0).saturating_mul(r.into())) + // Standard Error: 1_817 + .saturating_add(Weight::from_parts(1_256_713, 0).saturating_mul(s.into())) + // Standard Error: 1_817 + .saturating_add(Weight::from_parts(219_242, 0).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -300,11 +295,11 @@ impl WeightInfo for SubstrateWeight { fn add_sub(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `475 + s * (36 ±0)` - // Estimated: `21305` - // Minimum execution time: 28_661_000 picoseconds. - Weight::from_parts(33_432_641, 21305) - // Standard Error: 1_547 - .saturating_add(Weight::from_parts(71_314, 0).saturating_mul(s.into())) + // Estimated: `11003` + // Minimum execution time: 30_747_000 picoseconds. + Weight::from_parts(35_975_985, 11003) + // Standard Error: 1_625 + .saturating_add(Weight::from_parts(73_263, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -316,11 +311,11 @@ impl WeightInfo for SubstrateWeight { fn rename_sub(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `591 + s * (3 ±0)` - // Estimated: `14582` - // Minimum execution time: 13_885_000 picoseconds. - Weight::from_parts(16_105_165, 14582) - // Standard Error: 562 - .saturating_add(Weight::from_parts(17_087, 0).saturating_mul(s.into())) + // Estimated: `11003` + // Minimum execution time: 13_586_000 picoseconds. + Weight::from_parts(15_909_245, 11003) + // Standard Error: 611 + .saturating_add(Weight::from_parts(16_949, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -334,11 +329,11 @@ impl WeightInfo for SubstrateWeight { fn remove_sub(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `638 + s * (35 ±0)` - // Estimated: `21305` - // Minimum execution time: 32_192_000 picoseconds. - Weight::from_parts(35_393_444, 21305) - // Standard Error: 2_198 - .saturating_add(Weight::from_parts(62_316, 0).saturating_mul(s.into())) + // Estimated: `11003` + // Minimum execution time: 34_286_000 picoseconds. + Weight::from_parts(37_391_401, 11003) + // Standard Error: 1_099 + .saturating_add(Weight::from_parts(61_165, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -350,11 +345,11 @@ impl WeightInfo for SubstrateWeight { fn quit_sub(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `564 + s * (37 ±0)` - // Estimated: `10302` - // Minimum execution time: 20_803_000 picoseconds. - Weight::from_parts(23_462_393, 10302) - // Standard Error: 1_619 - .saturating_add(Weight::from_parts(59_938, 0).saturating_mul(s.into())) + // Estimated: `6723` + // Minimum execution time: 22_197_000 picoseconds. + Weight::from_parts(24_630_311, 6723) + // Standard Error: 1_092 + .saturating_add(Weight::from_parts(63_415, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -369,10 +364,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `32 + r * (57 ±0)` // Estimated: `2626` - // Minimum execution time: 13_092_000 picoseconds. - Weight::from_parts(13_798_719, 2626) - // Standard Error: 1_553 - .saturating_add(Weight::from_parts(109_215, 0).saturating_mul(r.into())) + // Minimum execution time: 12_851_000 picoseconds. + Weight::from_parts(13_448_645, 2626) + // Standard Error: 1_636 + .saturating_add(Weight::from_parts(113_654, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -384,12 +379,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `442 + r * (5 ±0)` // Estimated: `11003` - // Minimum execution time: 30_800_000 picoseconds. - Weight::from_parts(31_140_040, 11003) - // Standard Error: 4_896 - .saturating_add(Weight::from_parts(69_348, 0).saturating_mul(r.into())) - // Standard Error: 955 - .saturating_add(Weight::from_parts(430_082, 0).saturating_mul(x.into())) + // Minimum execution time: 33_342_000 picoseconds. + Weight::from_parts(33_155_116, 11003) + // Standard Error: 2_307 + .saturating_add(Weight::from_parts(56_409, 0).saturating_mul(r.into())) + // Standard Error: 450 + .saturating_add(Weight::from_parts(437_684, 0).saturating_mul(x.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -403,11 +398,11 @@ impl WeightInfo for () { fn set_subs_new(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `101` - // Estimated: `18716 + s * (2589 ±0)` - // Minimum execution time: 10_301_000 picoseconds. - Weight::from_parts(23_255_636, 18716) - // Standard Error: 5_562 - .saturating_add(Weight::from_parts(2_978_765, 0).saturating_mul(s.into())) + // Estimated: `11003 + s * (2589 ±0)` + // Minimum execution time: 10_315_000 picoseconds. + Weight::from_parts(26_535_526, 11003) + // Standard Error: 4_344 + .saturating_add(Weight::from_parts(3_016_873, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(s.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) @@ -424,11 +419,11 @@ impl WeightInfo for () { fn set_subs_old(p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `194 + p * (32 ±0)` - // Estimated: `17726` - // Minimum execution time: 10_095_000 picoseconds. - Weight::from_parts(23_197_533, 17726) - // Standard Error: 3_460 - .saturating_add(Weight::from_parts(1_227_498, 0).saturating_mul(p.into())) + // Estimated: `11003` + // Minimum execution time: 10_220_000 picoseconds. + Weight::from_parts(25_050_056, 11003) + // Standard Error: 3_621 + .saturating_add(Weight::from_parts(1_291_143, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(p.into()))) @@ -445,13 +440,13 @@ impl WeightInfo for () { fn clear_identity(_r: u32, s: u32, x: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `469 + r * (5 ±0) + s * (32 ±0) + x * (66 ±0)` - // Estimated: `17726` - // Minimum execution time: 51_054_000 picoseconds. - Weight::from_parts(30_184_047, 17726) - // Standard Error: 2_441 - .saturating_add(Weight::from_parts(1_221_983, 0).saturating_mul(s.into())) - // Standard Error: 2_441 - .saturating_add(Weight::from_parts(234_084, 0).saturating_mul(x.into())) + // Estimated: `11003` + // Minimum execution time: 56_018_000 picoseconds. + Weight::from_parts(37_757_186, 11003) + // Standard Error: 1_852 + .saturating_add(Weight::from_parts(1_257_980, 0).saturating_mul(s.into())) + // Standard Error: 1_852 + .saturating_add(Weight::from_parts(215_426, 0).saturating_mul(x.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -465,13 +460,13 @@ impl WeightInfo for () { fn request_judgement(r: u32, x: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `367 + r * (57 ±0) + x * (66 ±0)` - // Estimated: `13629` - // Minimum execution time: 32_747_000 picoseconds. - Weight::from_parts(29_557_659, 13629) - // Standard Error: 4_616 - .saturating_add(Weight::from_parts(200_494, 0).saturating_mul(r.into())) - // Standard Error: 900 - .saturating_add(Weight::from_parts(468_381, 0).saturating_mul(x.into())) + // Estimated: `11003` + // Minimum execution time: 34_792_000 picoseconds. + Weight::from_parts(35_368_327, 11003) + // Standard Error: 3_476 + .saturating_add(Weight::from_parts(78_981, 0).saturating_mul(r.into())) + // Standard Error: 678 + .saturating_add(Weight::from_parts(459_077, 0).saturating_mul(x.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -479,16 +474,14 @@ impl WeightInfo for () { /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) /// The range of component `r` is `[1, 20]`. /// The range of component `x` is `[0, 100]`. - fn cancel_request(r: u32, x: u32, ) -> Weight { + fn cancel_request(_r: u32, x: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `398 + x * (66 ±0)` // Estimated: `11003` - // Minimum execution time: 28_853_000 picoseconds. - Weight::from_parts(26_811_119, 11003) - // Standard Error: 15_667 - .saturating_add(Weight::from_parts(240_647, 0).saturating_mul(r.into())) - // Standard Error: 3_056 - .saturating_add(Weight::from_parts(462_536, 0).saturating_mul(x.into())) + // Minimum execution time: 31_306_000 picoseconds. + Weight::from_parts(33_304_799, 11003) + // Standard Error: 892 + .saturating_add(Weight::from_parts(451_655, 0).saturating_mul(x.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -499,10 +492,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `89 + r * (57 ±0)` // Estimated: `2626` - // Minimum execution time: 8_413_000 picoseconds. - Weight::from_parts(8_846_436, 2626) - // Standard Error: 1_470 - .saturating_add(Weight::from_parts(113_780, 0).saturating_mul(r.into())) + // Minimum execution time: 8_215_000 picoseconds. + Weight::from_parts(8_692_102, 2626) + // Standard Error: 1_455 + .saturating_add(Weight::from_parts(110_912, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -513,10 +506,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `89 + r * (57 ±0)` // Estimated: `2626` - // Minimum execution time: 8_753_000 picoseconds. - Weight::from_parts(9_143_938, 2626) - // Standard Error: 1_490 - .saturating_add(Weight::from_parts(113_406, 0).saturating_mul(r.into())) + // Minimum execution time: 8_397_000 picoseconds. + Weight::from_parts(8_787_656, 2626) + // Standard Error: 1_440 + .saturating_add(Weight::from_parts(111_212, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -527,10 +520,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `89 + r * (57 ±0)` // Estimated: `2626` - // Minimum execution time: 8_320_000 picoseconds. - Weight::from_parts(8_800_306, 2626) - // Standard Error: 1_345 - .saturating_add(Weight::from_parts(125_258, 0).saturating_mul(r.into())) + // Minimum execution time: 8_466_000 picoseconds. + Weight::from_parts(8_689_763, 2626) + // Standard Error: 1_536 + .saturating_add(Weight::from_parts(106_371, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -543,13 +536,13 @@ impl WeightInfo for () { fn provide_judgement(r: u32, x: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `445 + r * (57 ±0) + x * (66 ±0)` - // Estimated: `13629` - // Minimum execution time: 25_313_000 picoseconds. - Weight::from_parts(23_968_548, 13629) - // Standard Error: 4_143 - .saturating_add(Weight::from_parts(164_678, 0).saturating_mul(r.into())) - // Standard Error: 766 - .saturating_add(Weight::from_parts(713_576, 0).saturating_mul(x.into())) + // Estimated: `11003` + // Minimum execution time: 25_132_000 picoseconds. + Weight::from_parts(20_582_313, 11003) + // Standard Error: 10_427 + .saturating_add(Weight::from_parts(277_545, 0).saturating_mul(r.into())) + // Standard Error: 1_929 + .saturating_add(Weight::from_parts(747_966, 0).saturating_mul(x.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -567,15 +560,15 @@ impl WeightInfo for () { fn kill_identity(r: u32, s: u32, x: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `676 + r * (5 ±0) + s * (32 ±0) + x * (66 ±0)` - // Estimated: `21319` - // Minimum execution time: 64_638_000 picoseconds. - Weight::from_parts(43_317_654, 21319) - // Standard Error: 10_182 - .saturating_add(Weight::from_parts(61_967, 0).saturating_mul(r.into())) - // Standard Error: 1_988 - .saturating_add(Weight::from_parts(1_224_202, 0).saturating_mul(s.into())) - // Standard Error: 1_988 - .saturating_add(Weight::from_parts(233_897, 0).saturating_mul(x.into())) + // Estimated: `11003` + // Minimum execution time: 72_043_000 picoseconds. + Weight::from_parts(50_994_735, 11003) + // Standard Error: 9_304 + .saturating_add(Weight::from_parts(123_052, 0).saturating_mul(r.into())) + // Standard Error: 1_817 + .saturating_add(Weight::from_parts(1_256_713, 0).saturating_mul(s.into())) + // Standard Error: 1_817 + .saturating_add(Weight::from_parts(219_242, 0).saturating_mul(x.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -590,11 +583,11 @@ impl WeightInfo for () { fn add_sub(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `475 + s * (36 ±0)` - // Estimated: `21305` - // Minimum execution time: 28_661_000 picoseconds. - Weight::from_parts(33_432_641, 21305) - // Standard Error: 1_547 - .saturating_add(Weight::from_parts(71_314, 0).saturating_mul(s.into())) + // Estimated: `11003` + // Minimum execution time: 30_747_000 picoseconds. + Weight::from_parts(35_975_985, 11003) + // Standard Error: 1_625 + .saturating_add(Weight::from_parts(73_263, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -606,11 +599,11 @@ impl WeightInfo for () { fn rename_sub(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `591 + s * (3 ±0)` - // Estimated: `14582` - // Minimum execution time: 13_885_000 picoseconds. - Weight::from_parts(16_105_165, 14582) - // Standard Error: 562 - .saturating_add(Weight::from_parts(17_087, 0).saturating_mul(s.into())) + // Estimated: `11003` + // Minimum execution time: 13_586_000 picoseconds. + Weight::from_parts(15_909_245, 11003) + // Standard Error: 611 + .saturating_add(Weight::from_parts(16_949, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -624,11 +617,11 @@ impl WeightInfo for () { fn remove_sub(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `638 + s * (35 ±0)` - // Estimated: `21305` - // Minimum execution time: 32_192_000 picoseconds. - Weight::from_parts(35_393_444, 21305) - // Standard Error: 2_198 - .saturating_add(Weight::from_parts(62_316, 0).saturating_mul(s.into())) + // Estimated: `11003` + // Minimum execution time: 34_286_000 picoseconds. + Weight::from_parts(37_391_401, 11003) + // Standard Error: 1_099 + .saturating_add(Weight::from_parts(61_165, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -640,11 +633,11 @@ impl WeightInfo for () { fn quit_sub(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `564 + s * (37 ±0)` - // Estimated: `10302` - // Minimum execution time: 20_803_000 picoseconds. - Weight::from_parts(23_462_393, 10302) - // Standard Error: 1_619 - .saturating_add(Weight::from_parts(59_938, 0).saturating_mul(s.into())) + // Estimated: `6723` + // Minimum execution time: 22_197_000 picoseconds. + Weight::from_parts(24_630_311, 6723) + // Standard Error: 1_092 + .saturating_add(Weight::from_parts(63_415, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } diff --git a/frame/im-online/src/weights.rs b/frame/im-online/src/weights.rs index f97df1c367562..64c1eb5f3a9b0 100644 --- a/frame/im-online/src/weights.rs +++ b/frame/im-online/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_im_online //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,9 +31,6 @@ // --steps=50 // --repeat=20 // --pallet=pallet_im_online -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -72,17 +69,17 @@ impl WeightInfo for SubstrateWeight { fn validate_unsigned_and_then_heartbeat(k: u32, e: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `295 + k * (32 ±0)` - // Estimated: `10349544 + e * (35 ±0) + k * (64 ±0)` - // Minimum execution time: 106_224_000 picoseconds. - Weight::from_parts(79_172_319, 10349544) - // Standard Error: 259 - .saturating_add(Weight::from_parts(29_576, 0).saturating_mul(k.into())) - // Standard Error: 2_611 - .saturating_add(Weight::from_parts(422_369, 0).saturating_mul(e.into())) + // Estimated: `10024497 + e * (35 ±0) + k * (32 ±0)` + // Minimum execution time: 95_573_000 picoseconds. + Weight::from_parts(78_856_572, 10024497) + // Standard Error: 315 + .saturating_add(Weight::from_parts(22_926, 0).saturating_mul(k.into())) + // Standard Error: 3_181 + .saturating_add(Weight::from_parts(362_093, 0).saturating_mul(e.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 35).saturating_mul(e.into())) - .saturating_add(Weight::from_parts(0, 64).saturating_mul(k.into())) + .saturating_add(Weight::from_parts(0, 32).saturating_mul(k.into())) } } @@ -103,16 +100,16 @@ impl WeightInfo for () { fn validate_unsigned_and_then_heartbeat(k: u32, e: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `295 + k * (32 ±0)` - // Estimated: `10349544 + e * (35 ±0) + k * (64 ±0)` - // Minimum execution time: 106_224_000 picoseconds. - Weight::from_parts(79_172_319, 10349544) - // Standard Error: 259 - .saturating_add(Weight::from_parts(29_576, 0).saturating_mul(k.into())) - // Standard Error: 2_611 - .saturating_add(Weight::from_parts(422_369, 0).saturating_mul(e.into())) + // Estimated: `10024497 + e * (35 ±0) + k * (32 ±0)` + // Minimum execution time: 95_573_000 picoseconds. + Weight::from_parts(78_856_572, 10024497) + // Standard Error: 315 + .saturating_add(Weight::from_parts(22_926, 0).saturating_mul(k.into())) + // Standard Error: 3_181 + .saturating_add(Weight::from_parts(362_093, 0).saturating_mul(e.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 35).saturating_mul(e.into())) - .saturating_add(Weight::from_parts(0, 64).saturating_mul(k.into())) + .saturating_add(Weight::from_parts(0, 32).saturating_mul(k.into())) } } diff --git a/frame/indices/src/weights.rs b/frame/indices/src/weights.rs index 87160ccfbb208..21d01c14ef9a2 100644 --- a/frame/indices/src/weights.rs +++ b/frame/indices/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_indices //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,9 +31,6 @@ // --steps=50 // --repeat=20 // --pallet=pallet_indices -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -67,8 +64,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `76` // Estimated: `3534` - // Minimum execution time: 22_365_000 picoseconds. - Weight::from_parts(22_713_000, 3534) + // Minimum execution time: 27_250_000 picoseconds. + Weight::from_parts(27_829_000, 3534) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -79,9 +76,9 @@ impl WeightInfo for SubstrateWeight { fn transfer() -> Weight { // Proof Size summary in bytes: // Measured: `275` - // Estimated: `7127` - // Minimum execution time: 28_380_000 picoseconds. - Weight::from_parts(29_251_000, 7127) + // Estimated: `3593` + // Minimum execution time: 37_880_000 picoseconds. + Weight::from_parts(38_329_000, 3593) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -91,8 +88,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `172` // Estimated: `3534` - // Minimum execution time: 22_932_000 picoseconds. - Weight::from_parts(23_442_000, 3534) + // Minimum execution time: 27_455_000 picoseconds. + Weight::from_parts(27_788_000, 3534) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -103,9 +100,9 @@ impl WeightInfo for SubstrateWeight { fn force_transfer() -> Weight { // Proof Size summary in bytes: // Measured: `275` - // Estimated: `7127` - // Minimum execution time: 25_223_000 picoseconds. - Weight::from_parts(25_519_000, 7127) + // Estimated: `3593` + // Minimum execution time: 29_865_000 picoseconds. + Weight::from_parts(30_420_000, 3593) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -115,8 +112,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `172` // Estimated: `3534` - // Minimum execution time: 25_223_000 picoseconds. - Weight::from_parts(26_127_000, 3534) + // Minimum execution time: 29_689_000 picoseconds. + Weight::from_parts(30_443_000, 3534) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -130,8 +127,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `76` // Estimated: `3534` - // Minimum execution time: 22_365_000 picoseconds. - Weight::from_parts(22_713_000, 3534) + // Minimum execution time: 27_250_000 picoseconds. + Weight::from_parts(27_829_000, 3534) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -142,9 +139,9 @@ impl WeightInfo for () { fn transfer() -> Weight { // Proof Size summary in bytes: // Measured: `275` - // Estimated: `7127` - // Minimum execution time: 28_380_000 picoseconds. - Weight::from_parts(29_251_000, 7127) + // Estimated: `3593` + // Minimum execution time: 37_880_000 picoseconds. + Weight::from_parts(38_329_000, 3593) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -154,8 +151,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `172` // Estimated: `3534` - // Minimum execution time: 22_932_000 picoseconds. - Weight::from_parts(23_442_000, 3534) + // Minimum execution time: 27_455_000 picoseconds. + Weight::from_parts(27_788_000, 3534) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -166,9 +163,9 @@ impl WeightInfo for () { fn force_transfer() -> Weight { // Proof Size summary in bytes: // Measured: `275` - // Estimated: `7127` - // Minimum execution time: 25_223_000 picoseconds. - Weight::from_parts(25_519_000, 7127) + // Estimated: `3593` + // Minimum execution time: 29_865_000 picoseconds. + Weight::from_parts(30_420_000, 3593) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -178,8 +175,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `172` // Estimated: `3534` - // Minimum execution time: 25_223_000 picoseconds. - Weight::from_parts(26_127_000, 3534) + // Minimum execution time: 29_689_000 picoseconds. + Weight::from_parts(30_443_000, 3534) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/frame/lottery/src/weights.rs b/frame/lottery/src/weights.rs index c8c373ad6f88d..c21b09e7d5b92 100644 --- a/frame/lottery/src/weights.rs +++ b/frame/lottery/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_lottery //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,9 +31,6 @@ // --steps=50 // --repeat=20 // --pallet=pallet_lottery -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -79,9 +76,9 @@ impl WeightInfo for SubstrateWeight { fn buy_ticket() -> Weight { // Proof Size summary in bytes: // Measured: `452` - // Estimated: `13121` - // Minimum execution time: 43_076_000 picoseconds. - Weight::from_parts(43_902_000, 13121) + // Estimated: `3593` + // Minimum execution time: 61_502_000 picoseconds. + Weight::from_parts(62_578_000, 3593) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -92,10 +89,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_222_000 picoseconds. - Weight::from_parts(9_166_238, 0) - // Standard Error: 3_489 - .saturating_add(Weight::from_parts(328_564, 0).saturating_mul(n.into())) + // Minimum execution time: 8_282_000 picoseconds. + Weight::from_parts(9_271_031, 0) + // Standard Error: 3_756 + .saturating_add(Weight::from_parts(349_990, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Lottery Lottery (r:1 w:1) @@ -107,9 +104,9 @@ impl WeightInfo for SubstrateWeight { fn start_lottery() -> Weight { // Proof Size summary in bytes: // Measured: `161` - // Estimated: `6596` - // Minimum execution time: 36_555_000 picoseconds. - Weight::from_parts(37_008_000, 6596) + // Estimated: `3593` + // Minimum execution time: 38_975_000 picoseconds. + Weight::from_parts(39_552_000, 3593) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -119,8 +116,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `219` // Estimated: `1514` - // Minimum execution time: 8_230_000 picoseconds. - Weight::from_parts(8_355_000, 1514) + // Minimum execution time: 8_243_000 picoseconds. + Weight::from_parts(8_359_000, 1514) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -137,9 +134,9 @@ impl WeightInfo for SubstrateWeight { fn on_initialize_end() -> Weight { // Proof Size summary in bytes: // Measured: `524` - // Estimated: `16787` - // Minimum execution time: 60_097_000 picoseconds. - Weight::from_parts(62_055_000, 16787) + // Estimated: `6196` + // Minimum execution time: 76_062_000 picoseconds. + Weight::from_parts(76_547_000, 6196) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -158,9 +155,9 @@ impl WeightInfo for SubstrateWeight { fn on_initialize_repeat() -> Weight { // Proof Size summary in bytes: // Measured: `524` - // Estimated: `18276` - // Minimum execution time: 61_354_000 picoseconds. - Weight::from_parts(62_429_000, 18276) + // Estimated: `6196` + // Minimum execution time: 78_089_000 picoseconds. + Weight::from_parts(78_632_000, 6196) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -185,9 +182,9 @@ impl WeightInfo for () { fn buy_ticket() -> Weight { // Proof Size summary in bytes: // Measured: `452` - // Estimated: `13121` - // Minimum execution time: 43_076_000 picoseconds. - Weight::from_parts(43_902_000, 13121) + // Estimated: `3593` + // Minimum execution time: 61_502_000 picoseconds. + Weight::from_parts(62_578_000, 3593) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -198,10 +195,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_222_000 picoseconds. - Weight::from_parts(9_166_238, 0) - // Standard Error: 3_489 - .saturating_add(Weight::from_parts(328_564, 0).saturating_mul(n.into())) + // Minimum execution time: 8_282_000 picoseconds. + Weight::from_parts(9_271_031, 0) + // Standard Error: 3_756 + .saturating_add(Weight::from_parts(349_990, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Lottery Lottery (r:1 w:1) @@ -213,9 +210,9 @@ impl WeightInfo for () { fn start_lottery() -> Weight { // Proof Size summary in bytes: // Measured: `161` - // Estimated: `6596` - // Minimum execution time: 36_555_000 picoseconds. - Weight::from_parts(37_008_000, 6596) + // Estimated: `3593` + // Minimum execution time: 38_975_000 picoseconds. + Weight::from_parts(39_552_000, 3593) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -225,8 +222,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `219` // Estimated: `1514` - // Minimum execution time: 8_230_000 picoseconds. - Weight::from_parts(8_355_000, 1514) + // Minimum execution time: 8_243_000 picoseconds. + Weight::from_parts(8_359_000, 1514) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -243,9 +240,9 @@ impl WeightInfo for () { fn on_initialize_end() -> Weight { // Proof Size summary in bytes: // Measured: `524` - // Estimated: `16787` - // Minimum execution time: 60_097_000 picoseconds. - Weight::from_parts(62_055_000, 16787) + // Estimated: `6196` + // Minimum execution time: 76_062_000 picoseconds. + Weight::from_parts(76_547_000, 6196) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -264,9 +261,9 @@ impl WeightInfo for () { fn on_initialize_repeat() -> Weight { // Proof Size summary in bytes: // Measured: `524` - // Estimated: `18276` - // Minimum execution time: 61_354_000 picoseconds. - Weight::from_parts(62_429_000, 18276) + // Estimated: `6196` + // Minimum execution time: 78_089_000 picoseconds. + Weight::from_parts(78_632_000, 6196) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } diff --git a/frame/membership/src/weights.rs b/frame/membership/src/weights.rs index 31c359b4469eb..70c50d8695dfc 100644 --- a/frame/membership/src/weights.rs +++ b/frame/membership/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_membership //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,9 +31,6 @@ // --steps=50 // --repeat=20 // --pallet=pallet_membership -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -75,14 +72,14 @@ impl WeightInfo for SubstrateWeight { fn add_member(m: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `174 + m * (64 ±0)` - // Estimated: `6691 + m * (192 ±0)` - // Minimum execution time: 17_587_000 picoseconds. - Weight::from_parts(18_658_163, 6691) - // Standard Error: 710 - .saturating_add(Weight::from_parts(46_294, 0).saturating_mul(m.into())) + // Estimated: `4687 + m * (64 ±0)` + // Minimum execution time: 18_264_000 picoseconds. + Weight::from_parts(19_343_697, 4687) + // Standard Error: 699 + .saturating_add(Weight::from_parts(44_401, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 192).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) } /// Storage: TechnicalMembership Members (r:1 w:1) /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) @@ -98,14 +95,14 @@ impl WeightInfo for SubstrateWeight { fn remove_member(m: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `278 + m * (64 ±0)` - // Estimated: `8520 + m * (192 ±0)` - // Minimum execution time: 20_402_000 picoseconds. - Weight::from_parts(21_165_819, 8520) - // Standard Error: 643 - .saturating_add(Weight::from_parts(45_481, 0).saturating_mul(m.into())) + // Estimated: `4687 + m * (64 ±0)` + // Minimum execution time: 21_092_000 picoseconds. + Weight::from_parts(22_140_391, 4687) + // Standard Error: 545 + .saturating_add(Weight::from_parts(40_638, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 192).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) } /// Storage: TechnicalMembership Members (r:1 w:1) /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) @@ -121,14 +118,14 @@ impl WeightInfo for SubstrateWeight { fn swap_member(m: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `278 + m * (64 ±0)` - // Estimated: `8520 + m * (192 ±0)` - // Minimum execution time: 20_380_000 picoseconds. - Weight::from_parts(21_633_260, 8520) - // Standard Error: 770 - .saturating_add(Weight::from_parts(55_504, 0).saturating_mul(m.into())) + // Estimated: `4687 + m * (64 ±0)` + // Minimum execution time: 21_002_000 picoseconds. + Weight::from_parts(22_364_944, 4687) + // Standard Error: 752 + .saturating_add(Weight::from_parts(54_363, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 192).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) } /// Storage: TechnicalMembership Members (r:1 w:1) /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) @@ -144,14 +141,14 @@ impl WeightInfo for SubstrateWeight { fn reset_member(m: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `278 + m * (64 ±0)` - // Estimated: `8520 + m * (192 ±0)` - // Minimum execution time: 19_989_000 picoseconds. - Weight::from_parts(22_352_059, 8520) - // Standard Error: 2_878 - .saturating_add(Weight::from_parts(156_367, 0).saturating_mul(m.into())) + // Estimated: `4687 + m * (64 ±0)` + // Minimum execution time: 20_443_000 picoseconds. + Weight::from_parts(22_188_301, 4687) + // Standard Error: 945 + .saturating_add(Weight::from_parts(162_799, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 192).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) } /// Storage: TechnicalMembership Members (r:1 w:1) /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) @@ -167,14 +164,14 @@ impl WeightInfo for SubstrateWeight { fn change_key(m: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `278 + m * (64 ±0)` - // Estimated: `8520 + m * (192 ±0)` - // Minimum execution time: 21_275_000 picoseconds. - Weight::from_parts(23_344_594, 8520) - // Standard Error: 2_750 - .saturating_add(Weight::from_parts(46_736, 0).saturating_mul(m.into())) + // Estimated: `4687 + m * (64 ±0)` + // Minimum execution time: 21_527_000 picoseconds. + Weight::from_parts(23_146_706, 4687) + // Standard Error: 724 + .saturating_add(Weight::from_parts(55_027, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) - .saturating_add(Weight::from_parts(0, 192).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) } /// Storage: TechnicalMembership Members (r:1 w:0) /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) @@ -186,11 +183,11 @@ impl WeightInfo for SubstrateWeight { fn set_prime(m: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `32 + m * (32 ±0)` - // Estimated: `4719 + m * (32 ±0)` - // Minimum execution time: 8_087_000 picoseconds. - Weight::from_parts(8_909_627, 4719) - // Standard Error: 1_572 - .saturating_add(Weight::from_parts(17_186, 0).saturating_mul(m.into())) + // Estimated: `4687 + m * (32 ±0)` + // Minimum execution time: 8_054_000 picoseconds. + Weight::from_parts(8_558_341, 4687) + // Standard Error: 360 + .saturating_add(Weight::from_parts(16_362, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(Weight::from_parts(0, 32).saturating_mul(m.into())) @@ -200,14 +197,12 @@ impl WeightInfo for SubstrateWeight { /// Storage: TechnicalCommittee Prime (r:0 w:1) /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `m` is `[1, 100]`. - fn clear_prime(m: u32, ) -> Weight { + fn clear_prime(_m: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_752_000 picoseconds. - Weight::from_parts(4_081_144, 0) - // Standard Error: 229 - .saturating_add(Weight::from_parts(1_298, 0).saturating_mul(m.into())) + // Minimum execution time: 3_784_000 picoseconds. + Weight::from_parts(4_100_031, 0) .saturating_add(T::DbWeight::get().writes(2_u64)) } } @@ -226,14 +221,14 @@ impl WeightInfo for () { fn add_member(m: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `174 + m * (64 ±0)` - // Estimated: `6691 + m * (192 ±0)` - // Minimum execution time: 17_587_000 picoseconds. - Weight::from_parts(18_658_163, 6691) - // Standard Error: 710 - .saturating_add(Weight::from_parts(46_294, 0).saturating_mul(m.into())) + // Estimated: `4687 + m * (64 ±0)` + // Minimum execution time: 18_264_000 picoseconds. + Weight::from_parts(19_343_697, 4687) + // Standard Error: 699 + .saturating_add(Weight::from_parts(44_401, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 192).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) } /// Storage: TechnicalMembership Members (r:1 w:1) /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) @@ -249,14 +244,14 @@ impl WeightInfo for () { fn remove_member(m: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `278 + m * (64 ±0)` - // Estimated: `8520 + m * (192 ±0)` - // Minimum execution time: 20_402_000 picoseconds. - Weight::from_parts(21_165_819, 8520) - // Standard Error: 643 - .saturating_add(Weight::from_parts(45_481, 0).saturating_mul(m.into())) + // Estimated: `4687 + m * (64 ±0)` + // Minimum execution time: 21_092_000 picoseconds. + Weight::from_parts(22_140_391, 4687) + // Standard Error: 545 + .saturating_add(Weight::from_parts(40_638, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 192).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) } /// Storage: TechnicalMembership Members (r:1 w:1) /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) @@ -272,14 +267,14 @@ impl WeightInfo for () { fn swap_member(m: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `278 + m * (64 ±0)` - // Estimated: `8520 + m * (192 ±0)` - // Minimum execution time: 20_380_000 picoseconds. - Weight::from_parts(21_633_260, 8520) - // Standard Error: 770 - .saturating_add(Weight::from_parts(55_504, 0).saturating_mul(m.into())) + // Estimated: `4687 + m * (64 ±0)` + // Minimum execution time: 21_002_000 picoseconds. + Weight::from_parts(22_364_944, 4687) + // Standard Error: 752 + .saturating_add(Weight::from_parts(54_363, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 192).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) } /// Storage: TechnicalMembership Members (r:1 w:1) /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) @@ -295,14 +290,14 @@ impl WeightInfo for () { fn reset_member(m: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `278 + m * (64 ±0)` - // Estimated: `8520 + m * (192 ±0)` - // Minimum execution time: 19_989_000 picoseconds. - Weight::from_parts(22_352_059, 8520) - // Standard Error: 2_878 - .saturating_add(Weight::from_parts(156_367, 0).saturating_mul(m.into())) + // Estimated: `4687 + m * (64 ±0)` + // Minimum execution time: 20_443_000 picoseconds. + Weight::from_parts(22_188_301, 4687) + // Standard Error: 945 + .saturating_add(Weight::from_parts(162_799, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 192).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) } /// Storage: TechnicalMembership Members (r:1 w:1) /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) @@ -318,14 +313,14 @@ impl WeightInfo for () { fn change_key(m: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `278 + m * (64 ±0)` - // Estimated: `8520 + m * (192 ±0)` - // Minimum execution time: 21_275_000 picoseconds. - Weight::from_parts(23_344_594, 8520) - // Standard Error: 2_750 - .saturating_add(Weight::from_parts(46_736, 0).saturating_mul(m.into())) + // Estimated: `4687 + m * (64 ±0)` + // Minimum execution time: 21_527_000 picoseconds. + Weight::from_parts(23_146_706, 4687) + // Standard Error: 724 + .saturating_add(Weight::from_parts(55_027, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) - .saturating_add(Weight::from_parts(0, 192).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) } /// Storage: TechnicalMembership Members (r:1 w:0) /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) @@ -337,11 +332,11 @@ impl WeightInfo for () { fn set_prime(m: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `32 + m * (32 ±0)` - // Estimated: `4719 + m * (32 ±0)` - // Minimum execution time: 8_087_000 picoseconds. - Weight::from_parts(8_909_627, 4719) - // Standard Error: 1_572 - .saturating_add(Weight::from_parts(17_186, 0).saturating_mul(m.into())) + // Estimated: `4687 + m * (32 ±0)` + // Minimum execution time: 8_054_000 picoseconds. + Weight::from_parts(8_558_341, 4687) + // Standard Error: 360 + .saturating_add(Weight::from_parts(16_362, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(Weight::from_parts(0, 32).saturating_mul(m.into())) @@ -351,14 +346,12 @@ impl WeightInfo for () { /// Storage: TechnicalCommittee Prime (r:0 w:1) /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `m` is `[1, 100]`. - fn clear_prime(m: u32, ) -> Weight { + fn clear_prime(_m: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_752_000 picoseconds. - Weight::from_parts(4_081_144, 0) - // Standard Error: 229 - .saturating_add(Weight::from_parts(1_298, 0).saturating_mul(m.into())) + // Minimum execution time: 3_784_000 picoseconds. + Weight::from_parts(4_100_031, 0) .saturating_add(RocksDbWeight::get().writes(2_u64)) } } diff --git a/frame/message-queue/src/weights.rs b/frame/message-queue/src/weights.rs index fc44456db28bd..9dae12f518e44 100644 --- a/frame/message-queue/src/weights.rs +++ b/frame/message-queue/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_message_queue //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,9 +31,6 @@ // --steps=50 // --repeat=20 // --pallet=pallet_message_queue -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -73,9 +70,9 @@ impl WeightInfo for SubstrateWeight { fn ready_ring_knit() -> Weight { // Proof Size summary in bytes: // Measured: `233` - // Estimated: `7527` - // Minimum execution time: 12_561_000 picoseconds. - Weight::from_parts(12_758_000, 7527) + // Estimated: `6038` + // Minimum execution time: 12_076_000 picoseconds. + Weight::from_parts(12_350_000, 6038) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -86,9 +83,9 @@ impl WeightInfo for SubstrateWeight { fn ready_ring_unknit() -> Weight { // Proof Size summary in bytes: // Measured: `233` - // Estimated: `7527` - // Minimum execution time: 11_854_000 picoseconds. - Weight::from_parts(12_178_000, 7527) + // Estimated: `6038` + // Minimum execution time: 11_586_000 picoseconds. + Weight::from_parts(11_912_000, 6038) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -98,8 +95,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `42` // Estimated: `3514` - // Minimum execution time: 7_900_000 picoseconds. - Weight::from_parts(8_046_000, 3514) + // Minimum execution time: 4_581_000 picoseconds. + Weight::from_parts(4_715_000, 3514) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -109,8 +106,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `113` // Estimated: `69049` - // Minimum execution time: 6_284_000 picoseconds. - Weight::from_parts(6_433_000, 69049) + // Minimum execution time: 5_826_000 picoseconds. + Weight::from_parts(5_932_000, 69049) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -120,8 +117,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `113` // Estimated: `69049` - // Minimum execution time: 6_418_000 picoseconds. - Weight::from_parts(6_633_000, 69049) + // Minimum execution time: 6_235_000 picoseconds. + Weight::from_parts(6_430_000, 69049) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -129,8 +126,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 52_661_000 picoseconds. - Weight::from_parts(52_994_000, 0) + // Minimum execution time: 53_860_000 picoseconds. + Weight::from_parts(53_984_000, 0) } /// Storage: MessageQueue ServiceHead (r:1 w:1) /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -139,9 +136,9 @@ impl WeightInfo for SubstrateWeight { fn bump_service_head() -> Weight { // Proof Size summary in bytes: // Measured: `140` - // Estimated: `5003` - // Minimum execution time: 7_132_000 picoseconds. - Weight::from_parts(7_386_000, 5003) + // Estimated: `3514` + // Minimum execution time: 7_018_000 picoseconds. + Weight::from_parts(7_205_000, 3514) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -152,9 +149,9 @@ impl WeightInfo for SubstrateWeight { fn reap_page() -> Weight { // Proof Size summary in bytes: // Measured: `65710` - // Estimated: `72563` - // Minimum execution time: 54_377_000 picoseconds. - Weight::from_parts(54_804_000, 72563) + // Estimated: `69049` + // Minimum execution time: 53_485_000 picoseconds. + Weight::from_parts(54_154_000, 69049) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -165,9 +162,9 @@ impl WeightInfo for SubstrateWeight { fn execute_overweight_page_removed() -> Weight { // Proof Size summary in bytes: // Measured: `65710` - // Estimated: `72563` - // Minimum execution time: 69_461_000 picoseconds. - Weight::from_parts(70_016_000, 72563) + // Estimated: `69049` + // Minimum execution time: 68_830_000 picoseconds. + Weight::from_parts(69_487_000, 69049) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -178,9 +175,9 @@ impl WeightInfo for SubstrateWeight { fn execute_overweight_page_updated() -> Weight { // Proof Size summary in bytes: // Measured: `65710` - // Estimated: `72563` - // Minimum execution time: 81_787_000 picoseconds. - Weight::from_parts(83_100_000, 72563) + // Estimated: `69049` + // Minimum execution time: 81_643_000 picoseconds. + Weight::from_parts(82_399_000, 69049) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -195,9 +192,9 @@ impl WeightInfo for () { fn ready_ring_knit() -> Weight { // Proof Size summary in bytes: // Measured: `233` - // Estimated: `7527` - // Minimum execution time: 12_561_000 picoseconds. - Weight::from_parts(12_758_000, 7527) + // Estimated: `6038` + // Minimum execution time: 12_076_000 picoseconds. + Weight::from_parts(12_350_000, 6038) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -208,9 +205,9 @@ impl WeightInfo for () { fn ready_ring_unknit() -> Weight { // Proof Size summary in bytes: // Measured: `233` - // Estimated: `7527` - // Minimum execution time: 11_854_000 picoseconds. - Weight::from_parts(12_178_000, 7527) + // Estimated: `6038` + // Minimum execution time: 11_586_000 picoseconds. + Weight::from_parts(11_912_000, 6038) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -220,8 +217,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `42` // Estimated: `3514` - // Minimum execution time: 7_900_000 picoseconds. - Weight::from_parts(8_046_000, 3514) + // Minimum execution time: 4_581_000 picoseconds. + Weight::from_parts(4_715_000, 3514) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -231,8 +228,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `113` // Estimated: `69049` - // Minimum execution time: 6_284_000 picoseconds. - Weight::from_parts(6_433_000, 69049) + // Minimum execution time: 5_826_000 picoseconds. + Weight::from_parts(5_932_000, 69049) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -242,8 +239,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `113` // Estimated: `69049` - // Minimum execution time: 6_418_000 picoseconds. - Weight::from_parts(6_633_000, 69049) + // Minimum execution time: 6_235_000 picoseconds. + Weight::from_parts(6_430_000, 69049) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -251,8 +248,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 52_661_000 picoseconds. - Weight::from_parts(52_994_000, 0) + // Minimum execution time: 53_860_000 picoseconds. + Weight::from_parts(53_984_000, 0) } /// Storage: MessageQueue ServiceHead (r:1 w:1) /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -261,9 +258,9 @@ impl WeightInfo for () { fn bump_service_head() -> Weight { // Proof Size summary in bytes: // Measured: `140` - // Estimated: `5003` - // Minimum execution time: 7_132_000 picoseconds. - Weight::from_parts(7_386_000, 5003) + // Estimated: `3514` + // Minimum execution time: 7_018_000 picoseconds. + Weight::from_parts(7_205_000, 3514) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -274,9 +271,9 @@ impl WeightInfo for () { fn reap_page() -> Weight { // Proof Size summary in bytes: // Measured: `65710` - // Estimated: `72563` - // Minimum execution time: 54_377_000 picoseconds. - Weight::from_parts(54_804_000, 72563) + // Estimated: `69049` + // Minimum execution time: 53_485_000 picoseconds. + Weight::from_parts(54_154_000, 69049) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -287,9 +284,9 @@ impl WeightInfo for () { fn execute_overweight_page_removed() -> Weight { // Proof Size summary in bytes: // Measured: `65710` - // Estimated: `72563` - // Minimum execution time: 69_461_000 picoseconds. - Weight::from_parts(70_016_000, 72563) + // Estimated: `69049` + // Minimum execution time: 68_830_000 picoseconds. + Weight::from_parts(69_487_000, 69049) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -300,9 +297,9 @@ impl WeightInfo for () { fn execute_overweight_page_updated() -> Weight { // Proof Size summary in bytes: // Measured: `65710` - // Estimated: `72563` - // Minimum execution time: 81_787_000 picoseconds. - Weight::from_parts(83_100_000, 72563) + // Estimated: `69049` + // Minimum execution time: 81_643_000 picoseconds. + Weight::from_parts(82_399_000, 69049) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } diff --git a/frame/multisig/src/weights.rs b/frame/multisig/src/weights.rs index 8941ce44f9a2b..7fda4bec8352d 100644 --- a/frame/multisig/src/weights.rs +++ b/frame/multisig/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_multisig //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,9 +31,6 @@ // --steps=50 // --repeat=20 // --pallet=pallet_multisig -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -68,10 +65,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 12_096_000 picoseconds. - Weight::from_parts(12_442_958, 0) - // Standard Error: 1 - .saturating_add(Weight::from_parts(494, 0).saturating_mul(z.into())) + // Minimum execution time: 12_199_000 picoseconds. + Weight::from_parts(12_595_771, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(490, 0).saturating_mul(z.into())) } /// Storage: Multisig Multisigs (r:1 w:1) /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) @@ -81,12 +78,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `301 + s * (2 ±0)` // Estimated: `6811` - // Minimum execution time: 37_609_000 picoseconds. - Weight::from_parts(32_693_100, 6811) - // Standard Error: 449 - .saturating_add(Weight::from_parts(56_623, 0).saturating_mul(s.into())) - // Standard Error: 4 - .saturating_add(Weight::from_parts(1_203, 0).saturating_mul(z.into())) + // Minimum execution time: 42_810_000 picoseconds. + Weight::from_parts(37_500_997, 6811) + // Standard Error: 308 + .saturating_add(Weight::from_parts(59_961, 0).saturating_mul(s.into())) + // Standard Error: 3 + .saturating_add(Weight::from_parts(1_198, 0).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -98,12 +95,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `320` // Estimated: `6811` - // Minimum execution time: 27_434_000 picoseconds. - Weight::from_parts(22_659_090, 6811) - // Standard Error: 328 - .saturating_add(Weight::from_parts(53_508, 0).saturating_mul(s.into())) - // Standard Error: 3 - .saturating_add(Weight::from_parts(1_213, 0).saturating_mul(z.into())) + // Minimum execution time: 27_775_000 picoseconds. + Weight::from_parts(22_868_524, 6811) + // Standard Error: 273 + .saturating_add(Weight::from_parts(55_219, 0).saturating_mul(s.into())) + // Standard Error: 2 + .saturating_add(Weight::from_parts(1_202, 0).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -116,13 +113,13 @@ impl WeightInfo for SubstrateWeight { fn as_multi_complete(s: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `426 + s * (33 ±0)` - // Estimated: `10404` - // Minimum execution time: 43_592_000 picoseconds. - Weight::from_parts(36_465_266, 10404) - // Standard Error: 1_049 - .saturating_add(Weight::from_parts(78_833, 0).saturating_mul(s.into())) - // Standard Error: 10 - .saturating_add(Weight::from_parts(1_238, 0).saturating_mul(z.into())) + // Estimated: `6811` + // Minimum execution time: 48_223_000 picoseconds. + Weight::from_parts(39_193_453, 6811) + // Standard Error: 2_162 + .saturating_add(Weight::from_parts(93_763, 0).saturating_mul(s.into())) + // Standard Error: 21 + .saturating_add(Weight::from_parts(1_372, 0).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -133,10 +130,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `301 + s * (2 ±0)` // Estimated: `6811` - // Minimum execution time: 30_216_000 picoseconds. - Weight::from_parts(31_430_373, 6811) - // Standard Error: 967 - .saturating_add(Weight::from_parts(57_035, 0).saturating_mul(s.into())) + // Minimum execution time: 34_775_000 picoseconds. + Weight::from_parts(35_966_626, 6811) + // Standard Error: 464 + .saturating_add(Weight::from_parts(61_492, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -147,10 +144,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `320` // Estimated: `6811` - // Minimum execution time: 19_960_000 picoseconds. - Weight::from_parts(21_281_659, 6811) - // Standard Error: 435 - .saturating_add(Weight::from_parts(56_445, 0).saturating_mul(s.into())) + // Minimum execution time: 19_947_000 picoseconds. + Weight::from_parts(21_253_025, 6811) + // Standard Error: 402 + .saturating_add(Weight::from_parts(58_491, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -161,10 +158,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `492 + s * (1 ±0)` // Estimated: `6811` - // Minimum execution time: 31_219_000 picoseconds. - Weight::from_parts(32_395_963, 6811) - // Standard Error: 500 - .saturating_add(Weight::from_parts(56_853, 0).saturating_mul(s.into())) + // Minimum execution time: 35_023_000 picoseconds. + Weight::from_parts(36_756_977, 6811) + // Standard Error: 547 + .saturating_add(Weight::from_parts(62_235, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -177,10 +174,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 12_096_000 picoseconds. - Weight::from_parts(12_442_958, 0) - // Standard Error: 1 - .saturating_add(Weight::from_parts(494, 0).saturating_mul(z.into())) + // Minimum execution time: 12_199_000 picoseconds. + Weight::from_parts(12_595_771, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(490, 0).saturating_mul(z.into())) } /// Storage: Multisig Multisigs (r:1 w:1) /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) @@ -190,12 +187,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `301 + s * (2 ±0)` // Estimated: `6811` - // Minimum execution time: 37_609_000 picoseconds. - Weight::from_parts(32_693_100, 6811) - // Standard Error: 449 - .saturating_add(Weight::from_parts(56_623, 0).saturating_mul(s.into())) - // Standard Error: 4 - .saturating_add(Weight::from_parts(1_203, 0).saturating_mul(z.into())) + // Minimum execution time: 42_810_000 picoseconds. + Weight::from_parts(37_500_997, 6811) + // Standard Error: 308 + .saturating_add(Weight::from_parts(59_961, 0).saturating_mul(s.into())) + // Standard Error: 3 + .saturating_add(Weight::from_parts(1_198, 0).saturating_mul(z.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -207,12 +204,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `320` // Estimated: `6811` - // Minimum execution time: 27_434_000 picoseconds. - Weight::from_parts(22_659_090, 6811) - // Standard Error: 328 - .saturating_add(Weight::from_parts(53_508, 0).saturating_mul(s.into())) - // Standard Error: 3 - .saturating_add(Weight::from_parts(1_213, 0).saturating_mul(z.into())) + // Minimum execution time: 27_775_000 picoseconds. + Weight::from_parts(22_868_524, 6811) + // Standard Error: 273 + .saturating_add(Weight::from_parts(55_219, 0).saturating_mul(s.into())) + // Standard Error: 2 + .saturating_add(Weight::from_parts(1_202, 0).saturating_mul(z.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -225,13 +222,13 @@ impl WeightInfo for () { fn as_multi_complete(s: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `426 + s * (33 ±0)` - // Estimated: `10404` - // Minimum execution time: 43_592_000 picoseconds. - Weight::from_parts(36_465_266, 10404) - // Standard Error: 1_049 - .saturating_add(Weight::from_parts(78_833, 0).saturating_mul(s.into())) - // Standard Error: 10 - .saturating_add(Weight::from_parts(1_238, 0).saturating_mul(z.into())) + // Estimated: `6811` + // Minimum execution time: 48_223_000 picoseconds. + Weight::from_parts(39_193_453, 6811) + // Standard Error: 2_162 + .saturating_add(Weight::from_parts(93_763, 0).saturating_mul(s.into())) + // Standard Error: 21 + .saturating_add(Weight::from_parts(1_372, 0).saturating_mul(z.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -242,10 +239,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `301 + s * (2 ±0)` // Estimated: `6811` - // Minimum execution time: 30_216_000 picoseconds. - Weight::from_parts(31_430_373, 6811) - // Standard Error: 967 - .saturating_add(Weight::from_parts(57_035, 0).saturating_mul(s.into())) + // Minimum execution time: 34_775_000 picoseconds. + Weight::from_parts(35_966_626, 6811) + // Standard Error: 464 + .saturating_add(Weight::from_parts(61_492, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -256,10 +253,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `320` // Estimated: `6811` - // Minimum execution time: 19_960_000 picoseconds. - Weight::from_parts(21_281_659, 6811) - // Standard Error: 435 - .saturating_add(Weight::from_parts(56_445, 0).saturating_mul(s.into())) + // Minimum execution time: 19_947_000 picoseconds. + Weight::from_parts(21_253_025, 6811) + // Standard Error: 402 + .saturating_add(Weight::from_parts(58_491, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -270,10 +267,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `492 + s * (1 ±0)` // Estimated: `6811` - // Minimum execution time: 31_219_000 picoseconds. - Weight::from_parts(32_395_963, 6811) - // Standard Error: 500 - .saturating_add(Weight::from_parts(56_853, 0).saturating_mul(s.into())) + // Minimum execution time: 35_023_000 picoseconds. + Weight::from_parts(36_756_977, 6811) + // Standard Error: 547 + .saturating_add(Weight::from_parts(62_235, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/frame/nfts/src/weights.rs b/frame/nfts/src/weights.rs index c5010a73cc7cb..19a61974a61a7 100644 --- a/frame/nfts/src/weights.rs +++ b/frame/nfts/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_nfts //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,9 +31,6 @@ // --steps=50 // --repeat=20 // --pallet=pallet_nfts -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -108,9 +105,9 @@ impl WeightInfo for SubstrateWeight { fn create() -> Weight { // Proof Size summary in bytes: // Measured: `182` - // Estimated: `5038` - // Minimum execution time: 36_780_000 picoseconds. - Weight::from_parts(37_508_000, 5038) + // Estimated: `3549` + // Minimum execution time: 40_664_000 picoseconds. + Weight::from_parts(41_224_000, 3549) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -127,9 +124,9 @@ impl WeightInfo for SubstrateWeight { fn force_create() -> Weight { // Proof Size summary in bytes: // Measured: `42` - // Estimated: `5038` - // Minimum execution time: 25_144_000 picoseconds. - Weight::from_parts(25_800_000, 5038) + // Estimated: `3549` + // Minimum execution time: 24_725_000 picoseconds. + Weight::from_parts(25_147_000, 3549) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -152,16 +149,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `m` is `[0, 1000]`. /// The range of component `c` is `[0, 1000]`. /// The range of component `a` is `[0, 1000]`. - fn destroy(m: u32, _c: u32, a: u32, ) -> Weight { + fn destroy(_m: u32, _c: u32, a: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `32186 + a * (332 ±0)` - // Estimated: `2538589 + a * (2921 ±0)` - // Minimum execution time: 1_122_858_000 picoseconds. - Weight::from_parts(1_094_711_913, 2538589) - // Standard Error: 4_485 - .saturating_add(Weight::from_parts(3_481, 0).saturating_mul(m.into())) - // Standard Error: 4_485 - .saturating_add(Weight::from_parts(5_520_602, 0).saturating_mul(a.into())) + // Estimated: `2523990 + a * (2921 ±0)` + // Minimum execution time: 1_100_509_000 picoseconds. + Weight::from_parts(1_081_634_178, 2523990) + // Standard Error: 3_025 + .saturating_add(Weight::from_parts(5_339_415, 0).saturating_mul(a.into())) .saturating_add(T::DbWeight::get().reads(1004_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(a.into()))) .saturating_add(T::DbWeight::get().writes(1005_u64)) @@ -183,9 +178,9 @@ impl WeightInfo for SubstrateWeight { fn mint() -> Weight { // Proof Size summary in bytes: // Measured: `421` - // Estimated: `18460` - // Minimum execution time: 48_590_000 picoseconds. - Weight::from_parts(49_260_000, 18460) + // Estimated: `4326` + // Minimum execution time: 52_464_000 picoseconds. + Weight::from_parts(52_847_000, 4326) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -204,9 +199,9 @@ impl WeightInfo for SubstrateWeight { fn force_mint() -> Weight { // Proof Size summary in bytes: // Measured: `421` - // Estimated: `18460` - // Minimum execution time: 46_646_000 picoseconds. - Weight::from_parts(47_331_000, 18460) + // Estimated: `4326` + // Minimum execution time: 50_327_000 picoseconds. + Weight::from_parts(51_093_000, 4326) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -229,9 +224,9 @@ impl WeightInfo for SubstrateWeight { fn burn() -> Weight { // Proof Size summary in bytes: // Measured: `530` - // Estimated: `14993` - // Minimum execution time: 46_976_000 picoseconds. - Weight::from_parts(47_606_000, 14993) + // Estimated: `4326` + // Minimum execution time: 51_342_000 picoseconds. + Weight::from_parts(51_846_000, 4326) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } @@ -252,9 +247,9 @@ impl WeightInfo for SubstrateWeight { fn transfer() -> Weight { // Proof Size summary in bytes: // Measured: `559` - // Estimated: `14926` - // Minimum execution time: 38_013_000 picoseconds. - Weight::from_parts(38_420_000, 14926) + // Estimated: `4326` + // Minimum execution time: 38_309_000 picoseconds. + Weight::from_parts(38_672_000, 4326) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -268,11 +263,11 @@ impl WeightInfo for SubstrateWeight { fn redeposit(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `729 + i * (108 ±0)` - // Estimated: `8077 + i * (3336 ±0)` - // Minimum execution time: 17_428_000 picoseconds. - Weight::from_parts(17_664_000, 8077) - // Standard Error: 16_385 - .saturating_add(Weight::from_parts(14_150_405, 0).saturating_mul(i.into())) + // Estimated: `3549 + i * (3336 ±0)` + // Minimum execution time: 17_525_000 picoseconds. + Weight::from_parts(17_657_000, 3549) + // Standard Error: 15_884 + .saturating_add(Weight::from_parts(16_026_633, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(i.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) @@ -285,9 +280,9 @@ impl WeightInfo for SubstrateWeight { fn lock_item_transfer() -> Weight { // Proof Size summary in bytes: // Measured: `401` - // Estimated: `7047` - // Minimum execution time: 21_760_000 picoseconds. - Weight::from_parts(22_063_000, 7047) + // Estimated: `3534` + // Minimum execution time: 21_814_000 picoseconds. + Weight::from_parts(22_171_000, 3534) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -298,9 +293,9 @@ impl WeightInfo for SubstrateWeight { fn unlock_item_transfer() -> Weight { // Proof Size summary in bytes: // Measured: `401` - // Estimated: `7047` - // Minimum execution time: 21_622_000 picoseconds. - Weight::from_parts(22_056_000, 7047) + // Estimated: `3534` + // Minimum execution time: 21_728_000 picoseconds. + Weight::from_parts(21_893_000, 3534) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -311,9 +306,9 @@ impl WeightInfo for SubstrateWeight { fn lock_collection() -> Weight { // Proof Size summary in bytes: // Measured: `306` - // Estimated: `7087` - // Minimum execution time: 18_820_000 picoseconds. - Weight::from_parts(19_212_000, 7087) + // Estimated: `3549` + // Minimum execution time: 18_359_000 picoseconds. + Weight::from_parts(19_101_000, 3549) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -326,9 +321,9 @@ impl WeightInfo for SubstrateWeight { fn transfer_ownership() -> Weight { // Proof Size summary in bytes: // Measured: `354` - // Estimated: `7066` - // Minimum execution time: 25_433_000 picoseconds. - Weight::from_parts(25_793_000, 7066) + // Estimated: `3549` + // Minimum execution time: 24_713_000 picoseconds. + Weight::from_parts(25_032_000, 3549) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -339,9 +334,9 @@ impl WeightInfo for SubstrateWeight { fn set_team() -> Weight { // Proof Size summary in bytes: // Measured: `335` - // Estimated: `9627` - // Minimum execution time: 43_368_000 picoseconds. - Weight::from_parts(43_974_000, 9627) + // Estimated: `6078` + // Minimum execution time: 42_372_000 picoseconds. + Weight::from_parts(42_971_000, 6078) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -353,8 +348,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `277` // Estimated: `3549` - // Minimum execution time: 20_009_000 picoseconds. - Weight::from_parts(20_220_000, 3549) + // Minimum execution time: 19_703_000 picoseconds. + Weight::from_parts(19_993_000, 3549) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -366,8 +361,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `242` // Estimated: `3549` - // Minimum execution time: 16_048_000 picoseconds. - Weight::from_parts(16_353_000, 3549) + // Minimum execution time: 15_500_000 picoseconds. + Weight::from_parts(15_929_000, 3549) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -378,9 +373,9 @@ impl WeightInfo for SubstrateWeight { fn lock_item_properties() -> Weight { // Proof Size summary in bytes: // Measured: `401` - // Estimated: `7047` - // Minimum execution time: 20_890_000 picoseconds. - Weight::from_parts(21_237_000, 7047) + // Estimated: `3534` + // Minimum execution time: 20_778_000 picoseconds. + Weight::from_parts(21_187_000, 3534) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -397,9 +392,9 @@ impl WeightInfo for SubstrateWeight { fn set_attribute() -> Weight { // Proof Size summary in bytes: // Measured: `505` - // Estimated: `18045` - // Minimum execution time: 50_686_000 picoseconds. - Weight::from_parts(50_981_000, 18045) + // Estimated: `3911` + // Minimum execution time: 53_016_000 picoseconds. + Weight::from_parts(53_579_000, 3911) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -410,9 +405,9 @@ impl WeightInfo for SubstrateWeight { fn force_set_attribute() -> Weight { // Proof Size summary in bytes: // Measured: `310` - // Estimated: `7460` - // Minimum execution time: 28_714_000 picoseconds. - Weight::from_parts(29_044_000, 7460) + // Estimated: `3911` + // Minimum execution time: 28_790_000 picoseconds. + Weight::from_parts(29_157_000, 3911) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -427,9 +422,9 @@ impl WeightInfo for SubstrateWeight { fn clear_attribute() -> Weight { // Proof Size summary in bytes: // Measured: `916` - // Estimated: `14507` - // Minimum execution time: 46_232_000 picoseconds. - Weight::from_parts(46_738_000, 14507) + // Estimated: `3911` + // Minimum execution time: 48_584_000 picoseconds. + Weight::from_parts(49_202_000, 3911) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -440,9 +435,9 @@ impl WeightInfo for SubstrateWeight { fn approve_item_attributes() -> Weight { // Proof Size summary in bytes: // Measured: `347` - // Estimated: `8472` - // Minimum execution time: 19_332_000 picoseconds. - Weight::from_parts(19_765_000, 8472) + // Estimated: `4326` + // Minimum execution time: 19_616_000 picoseconds. + Weight::from_parts(19_972_000, 4326) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -458,11 +453,11 @@ impl WeightInfo for SubstrateWeight { fn cancel_item_attributes_approval(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `803 + n * (364 ±0)` - // Estimated: `15976 + n * (2921 ±0)` - // Minimum execution time: 29_227_000 picoseconds. - Weight::from_parts(29_661_000, 15976) - // Standard Error: 3_574 - .saturating_add(Weight::from_parts(5_442_937, 0).saturating_mul(n.into())) + // Estimated: `4326 + n * (2921 ±0)` + // Minimum execution time: 28_897_000 picoseconds. + Weight::from_parts(29_061_000, 4326) + // Standard Error: 3_139 + .saturating_add(Weight::from_parts(5_396_415, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) @@ -482,9 +477,9 @@ impl WeightInfo for SubstrateWeight { fn set_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `505` - // Estimated: `17739` - // Minimum execution time: 41_297_000 picoseconds. - Weight::from_parts(41_902_000, 17739) + // Estimated: `3605` + // Minimum execution time: 43_748_000 picoseconds. + Weight::from_parts(44_178_000, 3605) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -499,9 +494,9 @@ impl WeightInfo for SubstrateWeight { fn clear_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `608` - // Estimated: `14201` - // Minimum execution time: 39_312_000 picoseconds. - Weight::from_parts(40_048_000, 14201) + // Estimated: `3605` + // Minimum execution time: 42_116_000 picoseconds. + Weight::from_parts(42_455_000, 3605) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -516,9 +511,9 @@ impl WeightInfo for SubstrateWeight { fn set_collection_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `364` - // Estimated: `14173` - // Minimum execution time: 36_932_000 picoseconds. - Weight::from_parts(38_207_000, 14173) + // Estimated: `3552` + // Minimum execution time: 40_926_000 picoseconds. + Weight::from_parts(41_512_000, 3552) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -533,9 +528,9 @@ impl WeightInfo for SubstrateWeight { fn clear_collection_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `475` - // Estimated: `14173` - // Minimum execution time: 35_264_000 picoseconds. - Weight::from_parts(35_829_000, 14173) + // Estimated: `3552` + // Minimum execution time: 39_792_000 picoseconds. + Weight::from_parts(40_443_000, 3552) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -546,9 +541,9 @@ impl WeightInfo for SubstrateWeight { fn approve_transfer() -> Weight { // Proof Size summary in bytes: // Measured: `376` - // Estimated: `7864` - // Minimum execution time: 22_819_000 picoseconds. - Weight::from_parts(23_121_000, 7864) + // Estimated: `4326` + // Minimum execution time: 22_648_000 picoseconds. + Weight::from_parts(23_139_000, 4326) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -558,8 +553,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `384` // Estimated: `4326` - // Minimum execution time: 20_377_000 picoseconds. - Weight::from_parts(20_625_000, 4326) + // Minimum execution time: 20_552_000 picoseconds. + Weight::from_parts(20_920_000, 4326) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -569,8 +564,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `384` // Estimated: `4326` - // Minimum execution time: 19_180_000 picoseconds. - Weight::from_parts(19_468_000, 4326) + // Minimum execution time: 19_114_000 picoseconds. + Weight::from_parts(19_876_000, 4326) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -580,8 +575,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `42` // Estimated: `3517` - // Minimum execution time: 17_381_000 picoseconds. - Weight::from_parts(17_718_000, 3517) + // Minimum execution time: 17_089_000 picoseconds. + Weight::from_parts(17_363_000, 3517) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -592,9 +587,9 @@ impl WeightInfo for SubstrateWeight { fn set_collection_max_supply() -> Weight { // Proof Size summary in bytes: // Measured: `306` - // Estimated: `7087` - // Minimum execution time: 20_373_000 picoseconds. - Weight::from_parts(20_662_000, 7087) + // Estimated: `3549` + // Minimum execution time: 20_667_000 picoseconds. + Weight::from_parts(20_898_000, 3549) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -605,9 +600,9 @@ impl WeightInfo for SubstrateWeight { fn update_mint_settings() -> Weight { // Proof Size summary in bytes: // Measured: `289` - // Estimated: `7072` - // Minimum execution time: 20_154_000 picoseconds. - Weight::from_parts(20_592_000, 7072) + // Estimated: `3538` + // Minimum execution time: 19_666_000 picoseconds. + Weight::from_parts(20_136_000, 3538) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -622,9 +617,9 @@ impl WeightInfo for SubstrateWeight { fn set_price() -> Weight { // Proof Size summary in bytes: // Measured: `484` - // Estimated: `11377` - // Minimum execution time: 25_644_000 picoseconds. - Weight::from_parts(25_999_000, 11377) + // Estimated: `4326` + // Minimum execution time: 25_778_000 picoseconds. + Weight::from_parts(26_447_000, 4326) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -645,9 +640,9 @@ impl WeightInfo for SubstrateWeight { fn buy_item() -> Weight { // Proof Size summary in bytes: // Measured: `671` - // Estimated: `18480` - // Minimum execution time: 51_542_000 picoseconds. - Weight::from_parts(52_203_000, 18480) + // Estimated: `4326` + // Minimum execution time: 50_809_000 picoseconds. + Weight::from_parts(51_503_000, 4326) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -656,10 +651,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_796_000 picoseconds. - Weight::from_parts(5_517_617, 0) - // Standard Error: 14_247 - .saturating_add(Weight::from_parts(3_757_796, 0).saturating_mul(n.into())) + // Minimum execution time: 2_789_000 picoseconds. + Weight::from_parts(5_528_034, 0) + // Standard Error: 14_405 + .saturating_add(Weight::from_parts(3_788_038, 0).saturating_mul(n.into())) } /// Storage: Nfts Item (r:2 w:0) /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) @@ -669,8 +664,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `460` // Estimated: `7662` - // Minimum execution time: 23_218_000 picoseconds. - Weight::from_parts(23_590_000, 7662) + // Minimum execution time: 22_884_000 picoseconds. + Weight::from_parts(23_732_000, 7662) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -681,9 +676,9 @@ impl WeightInfo for SubstrateWeight { fn cancel_swap() -> Weight { // Proof Size summary in bytes: // Measured: `479` - // Estimated: `7862` - // Minimum execution time: 22_536_000 picoseconds. - Weight::from_parts(22_874_000, 7862) + // Estimated: `4326` + // Minimum execution time: 22_686_000 picoseconds. + Weight::from_parts(23_088_000, 4326) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -704,9 +699,9 @@ impl WeightInfo for SubstrateWeight { fn claim_swap() -> Weight { // Proof Size summary in bytes: // Measured: `800` - // Estimated: `24321` - // Minimum execution time: 77_372_000 picoseconds. - Weight::from_parts(78_109_000, 24321) + // Estimated: `7662` + // Minimum execution time: 77_494_000 picoseconds. + Weight::from_parts(78_650_000, 7662) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(10_u64)) } @@ -732,11 +727,11 @@ impl WeightInfo for SubstrateWeight { fn mint_pre_signed(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `595` - // Estimated: `29192 + n * (2921 ±0)` - // Minimum execution time: 131_935_000 picoseconds. - Weight::from_parts(137_455_891, 29192) - // Standard Error: 31_617 - .saturating_add(Weight::from_parts(27_550_750, 0).saturating_mul(n.into())) + // Estimated: `6078 + n * (2921 ±0)` + // Minimum execution time: 139_109_000 picoseconds. + Weight::from_parts(144_449_034, 6078) + // Standard Error: 26_869 + .saturating_add(Weight::from_parts(29_961_772, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(6_u64)) @@ -759,11 +754,11 @@ impl WeightInfo for SubstrateWeight { fn set_attributes_pre_signed(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `625` - // Estimated: `20142 + n * (2921 ±0)` - // Minimum execution time: 77_694_000 picoseconds. - Weight::from_parts(90_089_732, 20142) - // Standard Error: 71_327 - .saturating_add(Weight::from_parts(27_832_189, 0).saturating_mul(n.into())) + // Estimated: `4326 + n * (2921 ±0)` + // Minimum execution time: 78_280_000 picoseconds. + Weight::from_parts(92_826_883, 4326) + // Standard Error: 81_125 + .saturating_add(Weight::from_parts(29_898_245, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) @@ -787,9 +782,9 @@ impl WeightInfo for () { fn create() -> Weight { // Proof Size summary in bytes: // Measured: `182` - // Estimated: `5038` - // Minimum execution time: 36_780_000 picoseconds. - Weight::from_parts(37_508_000, 5038) + // Estimated: `3549` + // Minimum execution time: 40_664_000 picoseconds. + Weight::from_parts(41_224_000, 3549) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -806,9 +801,9 @@ impl WeightInfo for () { fn force_create() -> Weight { // Proof Size summary in bytes: // Measured: `42` - // Estimated: `5038` - // Minimum execution time: 25_144_000 picoseconds. - Weight::from_parts(25_800_000, 5038) + // Estimated: `3549` + // Minimum execution time: 24_725_000 picoseconds. + Weight::from_parts(25_147_000, 3549) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -831,16 +826,14 @@ impl WeightInfo for () { /// The range of component `m` is `[0, 1000]`. /// The range of component `c` is `[0, 1000]`. /// The range of component `a` is `[0, 1000]`. - fn destroy(m: u32, _c: u32, a: u32, ) -> Weight { + fn destroy(_m: u32, _c: u32, a: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `32186 + a * (332 ±0)` - // Estimated: `2538589 + a * (2921 ±0)` - // Minimum execution time: 1_122_858_000 picoseconds. - Weight::from_parts(1_094_711_913, 2538589) - // Standard Error: 4_485 - .saturating_add(Weight::from_parts(3_481, 0).saturating_mul(m.into())) - // Standard Error: 4_485 - .saturating_add(Weight::from_parts(5_520_602, 0).saturating_mul(a.into())) + // Estimated: `2523990 + a * (2921 ±0)` + // Minimum execution time: 1_100_509_000 picoseconds. + Weight::from_parts(1_081_634_178, 2523990) + // Standard Error: 3_025 + .saturating_add(Weight::from_parts(5_339_415, 0).saturating_mul(a.into())) .saturating_add(RocksDbWeight::get().reads(1004_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(a.into()))) .saturating_add(RocksDbWeight::get().writes(1005_u64)) @@ -862,9 +855,9 @@ impl WeightInfo for () { fn mint() -> Weight { // Proof Size summary in bytes: // Measured: `421` - // Estimated: `18460` - // Minimum execution time: 48_590_000 picoseconds. - Weight::from_parts(49_260_000, 18460) + // Estimated: `4326` + // Minimum execution time: 52_464_000 picoseconds. + Weight::from_parts(52_847_000, 4326) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -883,9 +876,9 @@ impl WeightInfo for () { fn force_mint() -> Weight { // Proof Size summary in bytes: // Measured: `421` - // Estimated: `18460` - // Minimum execution time: 46_646_000 picoseconds. - Weight::from_parts(47_331_000, 18460) + // Estimated: `4326` + // Minimum execution time: 50_327_000 picoseconds. + Weight::from_parts(51_093_000, 4326) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -908,9 +901,9 @@ impl WeightInfo for () { fn burn() -> Weight { // Proof Size summary in bytes: // Measured: `530` - // Estimated: `14993` - // Minimum execution time: 46_976_000 picoseconds. - Weight::from_parts(47_606_000, 14993) + // Estimated: `4326` + // Minimum execution time: 51_342_000 picoseconds. + Weight::from_parts(51_846_000, 4326) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } @@ -931,9 +924,9 @@ impl WeightInfo for () { fn transfer() -> Weight { // Proof Size summary in bytes: // Measured: `559` - // Estimated: `14926` - // Minimum execution time: 38_013_000 picoseconds. - Weight::from_parts(38_420_000, 14926) + // Estimated: `4326` + // Minimum execution time: 38_309_000 picoseconds. + Weight::from_parts(38_672_000, 4326) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -947,11 +940,11 @@ impl WeightInfo for () { fn redeposit(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `729 + i * (108 ±0)` - // Estimated: `8077 + i * (3336 ±0)` - // Minimum execution time: 17_428_000 picoseconds. - Weight::from_parts(17_664_000, 8077) - // Standard Error: 16_385 - .saturating_add(Weight::from_parts(14_150_405, 0).saturating_mul(i.into())) + // Estimated: `3549 + i * (3336 ±0)` + // Minimum execution time: 17_525_000 picoseconds. + Weight::from_parts(17_657_000, 3549) + // Standard Error: 15_884 + .saturating_add(Weight::from_parts(16_026_633, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(i.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(i.into()))) @@ -964,9 +957,9 @@ impl WeightInfo for () { fn lock_item_transfer() -> Weight { // Proof Size summary in bytes: // Measured: `401` - // Estimated: `7047` - // Minimum execution time: 21_760_000 picoseconds. - Weight::from_parts(22_063_000, 7047) + // Estimated: `3534` + // Minimum execution time: 21_814_000 picoseconds. + Weight::from_parts(22_171_000, 3534) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -977,9 +970,9 @@ impl WeightInfo for () { fn unlock_item_transfer() -> Weight { // Proof Size summary in bytes: // Measured: `401` - // Estimated: `7047` - // Minimum execution time: 21_622_000 picoseconds. - Weight::from_parts(22_056_000, 7047) + // Estimated: `3534` + // Minimum execution time: 21_728_000 picoseconds. + Weight::from_parts(21_893_000, 3534) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -990,9 +983,9 @@ impl WeightInfo for () { fn lock_collection() -> Weight { // Proof Size summary in bytes: // Measured: `306` - // Estimated: `7087` - // Minimum execution time: 18_820_000 picoseconds. - Weight::from_parts(19_212_000, 7087) + // Estimated: `3549` + // Minimum execution time: 18_359_000 picoseconds. + Weight::from_parts(19_101_000, 3549) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1005,9 +998,9 @@ impl WeightInfo for () { fn transfer_ownership() -> Weight { // Proof Size summary in bytes: // Measured: `354` - // Estimated: `7066` - // Minimum execution time: 25_433_000 picoseconds. - Weight::from_parts(25_793_000, 7066) + // Estimated: `3549` + // Minimum execution time: 24_713_000 picoseconds. + Weight::from_parts(25_032_000, 3549) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -1018,9 +1011,9 @@ impl WeightInfo for () { fn set_team() -> Weight { // Proof Size summary in bytes: // Measured: `335` - // Estimated: `9627` - // Minimum execution time: 43_368_000 picoseconds. - Weight::from_parts(43_974_000, 9627) + // Estimated: `6078` + // Minimum execution time: 42_372_000 picoseconds. + Weight::from_parts(42_971_000, 6078) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -1032,8 +1025,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `277` // Estimated: `3549` - // Minimum execution time: 20_009_000 picoseconds. - Weight::from_parts(20_220_000, 3549) + // Minimum execution time: 19_703_000 picoseconds. + Weight::from_parts(19_993_000, 3549) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -1045,8 +1038,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `242` // Estimated: `3549` - // Minimum execution time: 16_048_000 picoseconds. - Weight::from_parts(16_353_000, 3549) + // Minimum execution time: 15_500_000 picoseconds. + Weight::from_parts(15_929_000, 3549) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1057,9 +1050,9 @@ impl WeightInfo for () { fn lock_item_properties() -> Weight { // Proof Size summary in bytes: // Measured: `401` - // Estimated: `7047` - // Minimum execution time: 20_890_000 picoseconds. - Weight::from_parts(21_237_000, 7047) + // Estimated: `3534` + // Minimum execution time: 20_778_000 picoseconds. + Weight::from_parts(21_187_000, 3534) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1076,9 +1069,9 @@ impl WeightInfo for () { fn set_attribute() -> Weight { // Proof Size summary in bytes: // Measured: `505` - // Estimated: `18045` - // Minimum execution time: 50_686_000 picoseconds. - Weight::from_parts(50_981_000, 18045) + // Estimated: `3911` + // Minimum execution time: 53_016_000 picoseconds. + Weight::from_parts(53_579_000, 3911) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1089,9 +1082,9 @@ impl WeightInfo for () { fn force_set_attribute() -> Weight { // Proof Size summary in bytes: // Measured: `310` - // Estimated: `7460` - // Minimum execution time: 28_714_000 picoseconds. - Weight::from_parts(29_044_000, 7460) + // Estimated: `3911` + // Minimum execution time: 28_790_000 picoseconds. + Weight::from_parts(29_157_000, 3911) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1106,9 +1099,9 @@ impl WeightInfo for () { fn clear_attribute() -> Weight { // Proof Size summary in bytes: // Measured: `916` - // Estimated: `14507` - // Minimum execution time: 46_232_000 picoseconds. - Weight::from_parts(46_738_000, 14507) + // Estimated: `3911` + // Minimum execution time: 48_584_000 picoseconds. + Weight::from_parts(49_202_000, 3911) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1119,9 +1112,9 @@ impl WeightInfo for () { fn approve_item_attributes() -> Weight { // Proof Size summary in bytes: // Measured: `347` - // Estimated: `8472` - // Minimum execution time: 19_332_000 picoseconds. - Weight::from_parts(19_765_000, 8472) + // Estimated: `4326` + // Minimum execution time: 19_616_000 picoseconds. + Weight::from_parts(19_972_000, 4326) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1137,11 +1130,11 @@ impl WeightInfo for () { fn cancel_item_attributes_approval(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `803 + n * (364 ±0)` - // Estimated: `15976 + n * (2921 ±0)` - // Minimum execution time: 29_227_000 picoseconds. - Weight::from_parts(29_661_000, 15976) - // Standard Error: 3_574 - .saturating_add(Weight::from_parts(5_442_937, 0).saturating_mul(n.into())) + // Estimated: `4326 + n * (2921 ±0)` + // Minimum execution time: 28_897_000 picoseconds. + Weight::from_parts(29_061_000, 4326) + // Standard Error: 3_139 + .saturating_add(Weight::from_parts(5_396_415, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(2_u64)) @@ -1161,9 +1154,9 @@ impl WeightInfo for () { fn set_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `505` - // Estimated: `17739` - // Minimum execution time: 41_297_000 picoseconds. - Weight::from_parts(41_902_000, 17739) + // Estimated: `3605` + // Minimum execution time: 43_748_000 picoseconds. + Weight::from_parts(44_178_000, 3605) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1178,9 +1171,9 @@ impl WeightInfo for () { fn clear_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `608` - // Estimated: `14201` - // Minimum execution time: 39_312_000 picoseconds. - Weight::from_parts(40_048_000, 14201) + // Estimated: `3605` + // Minimum execution time: 42_116_000 picoseconds. + Weight::from_parts(42_455_000, 3605) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1195,9 +1188,9 @@ impl WeightInfo for () { fn set_collection_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `364` - // Estimated: `14173` - // Minimum execution time: 36_932_000 picoseconds. - Weight::from_parts(38_207_000, 14173) + // Estimated: `3552` + // Minimum execution time: 40_926_000 picoseconds. + Weight::from_parts(41_512_000, 3552) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1212,9 +1205,9 @@ impl WeightInfo for () { fn clear_collection_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `475` - // Estimated: `14173` - // Minimum execution time: 35_264_000 picoseconds. - Weight::from_parts(35_829_000, 14173) + // Estimated: `3552` + // Minimum execution time: 39_792_000 picoseconds. + Weight::from_parts(40_443_000, 3552) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1225,9 +1218,9 @@ impl WeightInfo for () { fn approve_transfer() -> Weight { // Proof Size summary in bytes: // Measured: `376` - // Estimated: `7864` - // Minimum execution time: 22_819_000 picoseconds. - Weight::from_parts(23_121_000, 7864) + // Estimated: `4326` + // Minimum execution time: 22_648_000 picoseconds. + Weight::from_parts(23_139_000, 4326) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1237,8 +1230,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `384` // Estimated: `4326` - // Minimum execution time: 20_377_000 picoseconds. - Weight::from_parts(20_625_000, 4326) + // Minimum execution time: 20_552_000 picoseconds. + Weight::from_parts(20_920_000, 4326) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1248,8 +1241,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `384` // Estimated: `4326` - // Minimum execution time: 19_180_000 picoseconds. - Weight::from_parts(19_468_000, 4326) + // Minimum execution time: 19_114_000 picoseconds. + Weight::from_parts(19_876_000, 4326) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1259,8 +1252,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `42` // Estimated: `3517` - // Minimum execution time: 17_381_000 picoseconds. - Weight::from_parts(17_718_000, 3517) + // Minimum execution time: 17_089_000 picoseconds. + Weight::from_parts(17_363_000, 3517) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1271,9 +1264,9 @@ impl WeightInfo for () { fn set_collection_max_supply() -> Weight { // Proof Size summary in bytes: // Measured: `306` - // Estimated: `7087` - // Minimum execution time: 20_373_000 picoseconds. - Weight::from_parts(20_662_000, 7087) + // Estimated: `3549` + // Minimum execution time: 20_667_000 picoseconds. + Weight::from_parts(20_898_000, 3549) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1284,9 +1277,9 @@ impl WeightInfo for () { fn update_mint_settings() -> Weight { // Proof Size summary in bytes: // Measured: `289` - // Estimated: `7072` - // Minimum execution time: 20_154_000 picoseconds. - Weight::from_parts(20_592_000, 7072) + // Estimated: `3538` + // Minimum execution time: 19_666_000 picoseconds. + Weight::from_parts(20_136_000, 3538) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1301,9 +1294,9 @@ impl WeightInfo for () { fn set_price() -> Weight { // Proof Size summary in bytes: // Measured: `484` - // Estimated: `11377` - // Minimum execution time: 25_644_000 picoseconds. - Weight::from_parts(25_999_000, 11377) + // Estimated: `4326` + // Minimum execution time: 25_778_000 picoseconds. + Weight::from_parts(26_447_000, 4326) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1324,9 +1317,9 @@ impl WeightInfo for () { fn buy_item() -> Weight { // Proof Size summary in bytes: // Measured: `671` - // Estimated: `18480` - // Minimum execution time: 51_542_000 picoseconds. - Weight::from_parts(52_203_000, 18480) + // Estimated: `4326` + // Minimum execution time: 50_809_000 picoseconds. + Weight::from_parts(51_503_000, 4326) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -1335,10 +1328,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_796_000 picoseconds. - Weight::from_parts(5_517_617, 0) - // Standard Error: 14_247 - .saturating_add(Weight::from_parts(3_757_796, 0).saturating_mul(n.into())) + // Minimum execution time: 2_789_000 picoseconds. + Weight::from_parts(5_528_034, 0) + // Standard Error: 14_405 + .saturating_add(Weight::from_parts(3_788_038, 0).saturating_mul(n.into())) } /// Storage: Nfts Item (r:2 w:0) /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) @@ -1348,8 +1341,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `460` // Estimated: `7662` - // Minimum execution time: 23_218_000 picoseconds. - Weight::from_parts(23_590_000, 7662) + // Minimum execution time: 22_884_000 picoseconds. + Weight::from_parts(23_732_000, 7662) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1360,9 +1353,9 @@ impl WeightInfo for () { fn cancel_swap() -> Weight { // Proof Size summary in bytes: // Measured: `479` - // Estimated: `7862` - // Minimum execution time: 22_536_000 picoseconds. - Weight::from_parts(22_874_000, 7862) + // Estimated: `4326` + // Minimum execution time: 22_686_000 picoseconds. + Weight::from_parts(23_088_000, 4326) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1383,9 +1376,9 @@ impl WeightInfo for () { fn claim_swap() -> Weight { // Proof Size summary in bytes: // Measured: `800` - // Estimated: `24321` - // Minimum execution time: 77_372_000 picoseconds. - Weight::from_parts(78_109_000, 24321) + // Estimated: `7662` + // Minimum execution time: 77_494_000 picoseconds. + Weight::from_parts(78_650_000, 7662) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(10_u64)) } @@ -1411,11 +1404,11 @@ impl WeightInfo for () { fn mint_pre_signed(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `595` - // Estimated: `29192 + n * (2921 ±0)` - // Minimum execution time: 131_935_000 picoseconds. - Weight::from_parts(137_455_891, 29192) - // Standard Error: 31_617 - .saturating_add(Weight::from_parts(27_550_750, 0).saturating_mul(n.into())) + // Estimated: `6078 + n * (2921 ±0)` + // Minimum execution time: 139_109_000 picoseconds. + Weight::from_parts(144_449_034, 6078) + // Standard Error: 26_869 + .saturating_add(Weight::from_parts(29_961_772, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(6_u64)) @@ -1438,11 +1431,11 @@ impl WeightInfo for () { fn set_attributes_pre_signed(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `625` - // Estimated: `20142 + n * (2921 ±0)` - // Minimum execution time: 77_694_000 picoseconds. - Weight::from_parts(90_089_732, 20142) - // Standard Error: 71_327 - .saturating_add(Weight::from_parts(27_832_189, 0).saturating_mul(n.into())) + // Estimated: `4326 + n * (2921 ±0)` + // Minimum execution time: 78_280_000 picoseconds. + Weight::from_parts(92_826_883, 4326) + // Standard Error: 81_125 + .saturating_add(Weight::from_parts(29_898_245, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(2_u64)) diff --git a/frame/nis/src/weights.rs b/frame/nis/src/weights.rs index 14b7b4d9c6f9a..4f92da874b5a2 100644 --- a/frame/nis/src/weights.rs +++ b/frame/nis/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_nis //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,9 +31,6 @@ // --steps=50 // --repeat=20 // --pallet=pallet_nis -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -55,10 +52,10 @@ pub trait WeightInfo { fn place_bid_max() -> Weight; fn retract_bid(l: u32, ) -> Weight; fn fund_deficit() -> Weight; + fn communify() -> Weight; + fn privatize() -> Weight; fn thaw_private() -> Weight; fn thaw_communal() -> Weight; - fn privatize() -> Weight; - fn communify() -> Weight; fn process_queues() -> Weight; fn process_queue() -> Weight; fn process_bid() -> Weight; @@ -69,52 +66,52 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { /// Storage: Nis Queues (r:1 w:1) /// Proof: Nis Queues (max_values: None, max_size: Some(48022), added: 50497, mode: MaxEncodedLen) - /// Storage: Balances Reserves (r:1 w:1) - /// Proof: Balances Reserves (max_values: None, max_size: Some(1249), added: 3724, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(66), added: 2541, mode: MaxEncodedLen) /// Storage: Nis QueueTotals (r:1 w:1) /// Proof: Nis QueueTotals (max_values: Some(1), max_size: Some(6002), added: 6497, mode: MaxEncodedLen) /// The range of component `l` is `[0, 999]`. fn place_bid(l: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `6182 + l * (48 ±0)` - // Estimated: `63688` - // Minimum execution time: 31_160_000 picoseconds. - Weight::from_parts(39_023_414, 63688) - // Standard Error: 214 - .saturating_add(Weight::from_parts(46_106, 0).saturating_mul(l.into())) + // Measured: `6175 + l * (48 ±0)` + // Estimated: `51487` + // Minimum execution time: 49_132_000 picoseconds. + Weight::from_parts(55_373_619, 51487) + // Standard Error: 198 + .saturating_add(Weight::from_parts(44_421, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: Nis Queues (r:1 w:1) /// Proof: Nis Queues (max_values: None, max_size: Some(48022), added: 50497, mode: MaxEncodedLen) - /// Storage: Balances Reserves (r:1 w:1) - /// Proof: Balances Reserves (max_values: None, max_size: Some(1249), added: 3724, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(66), added: 2541, mode: MaxEncodedLen) /// Storage: Nis QueueTotals (r:1 w:1) /// Proof: Nis QueueTotals (max_values: Some(1), max_size: Some(6002), added: 6497, mode: MaxEncodedLen) fn place_bid_max() -> Weight { // Proof Size summary in bytes: - // Measured: `54184` - // Estimated: `63688` - // Minimum execution time: 85_703_000 picoseconds. - Weight::from_parts(86_613_000, 63688) + // Measured: `54177` + // Estimated: `51487` + // Minimum execution time: 111_471_000 picoseconds. + Weight::from_parts(112_287_000, 51487) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: Nis Queues (r:1 w:1) /// Proof: Nis Queues (max_values: None, max_size: Some(48022), added: 50497, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(66), added: 2541, mode: MaxEncodedLen) /// Storage: Nis QueueTotals (r:1 w:1) /// Proof: Nis QueueTotals (max_values: Some(1), max_size: Some(6002), added: 6497, mode: MaxEncodedLen) - /// Storage: Balances Reserves (r:1 w:1) - /// Proof: Balances Reserves (max_values: None, max_size: Some(1249), added: 3724, mode: MaxEncodedLen) /// The range of component `l` is `[1, 1000]`. fn retract_bid(l: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `6182 + l * (48 ±0)` - // Estimated: `63688` - // Minimum execution time: 37_637_000 picoseconds. - Weight::from_parts(39_977_788, 63688) - // Standard Error: 152 - .saturating_add(Weight::from_parts(34_595, 0).saturating_mul(l.into())) + // Measured: `6175 + l * (48 ±0)` + // Estimated: `51487` + // Minimum execution time: 51_134_000 picoseconds. + Weight::from_parts(52_353_883, 51487) + // Standard Error: 161 + .saturating_add(Weight::from_parts(62_171, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -125,47 +122,32 @@ impl WeightInfo for SubstrateWeight { fn fund_deficit() -> Weight { // Proof Size summary in bytes: // Measured: `191` - // Estimated: `5118` - // Minimum execution time: 35_807_000 picoseconds. - Weight::from_parts(36_329_000, 5118) + // Estimated: `3593` + // Minimum execution time: 41_421_000 picoseconds. + Weight::from_parts(41_762_000, 3593) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Nis Receipts (r:1 w:1) /// Proof: Nis Receipts (max_values: None, max_size: Some(81), added: 2556, mode: MaxEncodedLen) - /// Storage: Nis Summary (r:1 w:1) - /// Proof: Nis Summary (max_values: Some(1), max_size: Some(40), added: 535, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:0) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(66), added: 2541, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Balances Reserves (r:1 w:1) - /// Proof: Balances Reserves (max_values: None, max_size: Some(1249), added: 3724, mode: MaxEncodedLen) - fn thaw_private() -> Weight { - // Proof Size summary in bytes: - // Measured: `360` - // Estimated: `13378` - // Minimum execution time: 51_342_000 picoseconds. - Weight::from_parts(51_976_000, 13378) - .saturating_add(T::DbWeight::get().reads(4_u64)) - .saturating_add(T::DbWeight::get().writes(3_u64)) - } - /// Storage: Nis Receipts (r:1 w:1) - /// Proof: Nis Receipts (max_values: None, max_size: Some(81), added: 2556, mode: MaxEncodedLen) /// Storage: Nis Summary (r:1 w:1) /// Proof: Nis Summary (max_values: Some(1), max_size: Some(40), added: 535, mode: MaxEncodedLen) /// Storage: Assets Asset (r:1 w:1) /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) /// Storage: Assets Account (r:1 w:1) /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn thaw_communal() -> Weight { + fn communify() -> Weight { // Proof Size summary in bytes: - // Measured: `773` - // Estimated: `15906` - // Minimum execution time: 76_535_000 picoseconds. - Weight::from_parts(78_073_000, 15906) - .saturating_add(T::DbWeight::get().reads(5_u64)) - .saturating_add(T::DbWeight::get().writes(5_u64)) + // Measured: `667` + // Estimated: `3675` + // Minimum execution time: 74_179_000 picoseconds. + Weight::from_parts(74_795_000, 3675) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(6_u64)) } /// Storage: Nis Receipts (r:1 w:1) /// Proof: Nis Receipts (max_values: None, max_size: Some(81), added: 2556, mode: MaxEncodedLen) @@ -177,37 +159,52 @@ impl WeightInfo for SubstrateWeight { /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) /// Storage: Assets Account (r:1 w:1) /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) - /// Storage: Balances Reserves (r:1 w:1) - /// Proof: Balances Reserves (max_values: None, max_size: Some(1249), added: 3724, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(66), added: 2541, mode: MaxEncodedLen) fn privatize() -> Weight { // Proof Size summary in bytes: - // Measured: `835` - // Estimated: `20620` - // Minimum execution time: 84_680_000 picoseconds. - Weight::from_parts(85_661_000, 20620) + // Measured: `828` + // Estimated: `3675` + // Minimum execution time: 85_252_000 picoseconds. + Weight::from_parts(85_949_000, 3675) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } /// Storage: Nis Receipts (r:1 w:1) /// Proof: Nis Receipts (max_values: None, max_size: Some(81), added: 2556, mode: MaxEncodedLen) - /// Storage: Balances Reserves (r:1 w:1) - /// Proof: Balances Reserves (max_values: None, max_size: Some(1249), added: 3724, mode: MaxEncodedLen) + /// Storage: Nis Summary (r:1 w:1) + /// Proof: Nis Summary (max_values: Some(1), max_size: Some(40), added: 535, mode: MaxEncodedLen) /// Storage: System Account (r:1 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(66), added: 2541, mode: MaxEncodedLen) + fn thaw_private() -> Weight { + // Proof Size summary in bytes: + // Measured: `456` + // Estimated: `3593` + // Minimum execution time: 82_100_000 picoseconds. + Weight::from_parts(82_563_000, 3593) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: Nis Receipts (r:1 w:1) + /// Proof: Nis Receipts (max_values: None, max_size: Some(81), added: 2556, mode: MaxEncodedLen) /// Storage: Nis Summary (r:1 w:1) /// Proof: Nis Summary (max_values: Some(1), max_size: Some(40), added: 535, mode: MaxEncodedLen) /// Storage: Assets Asset (r:1 w:1) /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) /// Storage: Assets Account (r:1 w:1) /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) - fn communify() -> Weight { + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + fn thaw_communal() -> Weight { // Proof Size summary in bytes: - // Measured: `674` - // Estimated: `20620` - // Minimum execution time: 72_828_000 picoseconds. - Weight::from_parts(73_553_000, 20620) - .saturating_add(T::DbWeight::get().reads(6_u64)) - .saturating_add(T::DbWeight::get().writes(6_u64)) + // Measured: `773` + // Estimated: `3675` + // Minimum execution time: 86_498_000 picoseconds. + Weight::from_parts(87_175_000, 3675) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) } /// Storage: Nis Summary (r:1 w:1) /// Proof: Nis Summary (max_values: Some(1), max_size: Some(40), added: 535, mode: MaxEncodedLen) @@ -218,9 +215,9 @@ impl WeightInfo for SubstrateWeight { fn process_queues() -> Weight { // Proof Size summary in bytes: // Measured: `6624` - // Estimated: `12605` - // Minimum execution time: 23_311_000 picoseconds. - Weight::from_parts(23_855_000, 12605) + // Estimated: `7487` + // Minimum execution time: 22_507_000 picoseconds. + Weight::from_parts(22_788_000, 7487) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -230,8 +227,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `42` // Estimated: `51487` - // Minimum execution time: 4_485_000 picoseconds. - Weight::from_parts(4_717_000, 51487) + // Minimum execution time: 4_692_000 picoseconds. + Weight::from_parts(4_862_000, 51487) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -241,8 +238,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_837_000 picoseconds. - Weight::from_parts(12_913_000, 0) + // Minimum execution time: 8_031_000 picoseconds. + Weight::from_parts(8_183_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } } @@ -251,52 +248,52 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { /// Storage: Nis Queues (r:1 w:1) /// Proof: Nis Queues (max_values: None, max_size: Some(48022), added: 50497, mode: MaxEncodedLen) - /// Storage: Balances Reserves (r:1 w:1) - /// Proof: Balances Reserves (max_values: None, max_size: Some(1249), added: 3724, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(66), added: 2541, mode: MaxEncodedLen) /// Storage: Nis QueueTotals (r:1 w:1) /// Proof: Nis QueueTotals (max_values: Some(1), max_size: Some(6002), added: 6497, mode: MaxEncodedLen) /// The range of component `l` is `[0, 999]`. fn place_bid(l: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `6182 + l * (48 ±0)` - // Estimated: `63688` - // Minimum execution time: 31_160_000 picoseconds. - Weight::from_parts(39_023_414, 63688) - // Standard Error: 214 - .saturating_add(Weight::from_parts(46_106, 0).saturating_mul(l.into())) + // Measured: `6175 + l * (48 ±0)` + // Estimated: `51487` + // Minimum execution time: 49_132_000 picoseconds. + Weight::from_parts(55_373_619, 51487) + // Standard Error: 198 + .saturating_add(Weight::from_parts(44_421, 0).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: Nis Queues (r:1 w:1) /// Proof: Nis Queues (max_values: None, max_size: Some(48022), added: 50497, mode: MaxEncodedLen) - /// Storage: Balances Reserves (r:1 w:1) - /// Proof: Balances Reserves (max_values: None, max_size: Some(1249), added: 3724, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(66), added: 2541, mode: MaxEncodedLen) /// Storage: Nis QueueTotals (r:1 w:1) /// Proof: Nis QueueTotals (max_values: Some(1), max_size: Some(6002), added: 6497, mode: MaxEncodedLen) fn place_bid_max() -> Weight { // Proof Size summary in bytes: - // Measured: `54184` - // Estimated: `63688` - // Minimum execution time: 85_703_000 picoseconds. - Weight::from_parts(86_613_000, 63688) + // Measured: `54177` + // Estimated: `51487` + // Minimum execution time: 111_471_000 picoseconds. + Weight::from_parts(112_287_000, 51487) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: Nis Queues (r:1 w:1) /// Proof: Nis Queues (max_values: None, max_size: Some(48022), added: 50497, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(66), added: 2541, mode: MaxEncodedLen) /// Storage: Nis QueueTotals (r:1 w:1) /// Proof: Nis QueueTotals (max_values: Some(1), max_size: Some(6002), added: 6497, mode: MaxEncodedLen) - /// Storage: Balances Reserves (r:1 w:1) - /// Proof: Balances Reserves (max_values: None, max_size: Some(1249), added: 3724, mode: MaxEncodedLen) /// The range of component `l` is `[1, 1000]`. fn retract_bid(l: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `6182 + l * (48 ±0)` - // Estimated: `63688` - // Minimum execution time: 37_637_000 picoseconds. - Weight::from_parts(39_977_788, 63688) - // Standard Error: 152 - .saturating_add(Weight::from_parts(34_595, 0).saturating_mul(l.into())) + // Measured: `6175 + l * (48 ±0)` + // Estimated: `51487` + // Minimum execution time: 51_134_000 picoseconds. + Weight::from_parts(52_353_883, 51487) + // Standard Error: 161 + .saturating_add(Weight::from_parts(62_171, 0).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -307,47 +304,32 @@ impl WeightInfo for () { fn fund_deficit() -> Weight { // Proof Size summary in bytes: // Measured: `191` - // Estimated: `5118` - // Minimum execution time: 35_807_000 picoseconds. - Weight::from_parts(36_329_000, 5118) + // Estimated: `3593` + // Minimum execution time: 41_421_000 picoseconds. + Weight::from_parts(41_762_000, 3593) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Nis Receipts (r:1 w:1) /// Proof: Nis Receipts (max_values: None, max_size: Some(81), added: 2556, mode: MaxEncodedLen) - /// Storage: Nis Summary (r:1 w:1) - /// Proof: Nis Summary (max_values: Some(1), max_size: Some(40), added: 535, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:0) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(66), added: 2541, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Balances Reserves (r:1 w:1) - /// Proof: Balances Reserves (max_values: None, max_size: Some(1249), added: 3724, mode: MaxEncodedLen) - fn thaw_private() -> Weight { - // Proof Size summary in bytes: - // Measured: `360` - // Estimated: `13378` - // Minimum execution time: 51_342_000 picoseconds. - Weight::from_parts(51_976_000, 13378) - .saturating_add(RocksDbWeight::get().reads(4_u64)) - .saturating_add(RocksDbWeight::get().writes(3_u64)) - } - /// Storage: Nis Receipts (r:1 w:1) - /// Proof: Nis Receipts (max_values: None, max_size: Some(81), added: 2556, mode: MaxEncodedLen) /// Storage: Nis Summary (r:1 w:1) /// Proof: Nis Summary (max_values: Some(1), max_size: Some(40), added: 535, mode: MaxEncodedLen) /// Storage: Assets Asset (r:1 w:1) /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) /// Storage: Assets Account (r:1 w:1) /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn thaw_communal() -> Weight { + fn communify() -> Weight { // Proof Size summary in bytes: - // Measured: `773` - // Estimated: `15906` - // Minimum execution time: 76_535_000 picoseconds. - Weight::from_parts(78_073_000, 15906) - .saturating_add(RocksDbWeight::get().reads(5_u64)) - .saturating_add(RocksDbWeight::get().writes(5_u64)) + // Measured: `667` + // Estimated: `3675` + // Minimum execution time: 74_179_000 picoseconds. + Weight::from_parts(74_795_000, 3675) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(6_u64)) } /// Storage: Nis Receipts (r:1 w:1) /// Proof: Nis Receipts (max_values: None, max_size: Some(81), added: 2556, mode: MaxEncodedLen) @@ -359,37 +341,52 @@ impl WeightInfo for () { /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) /// Storage: Assets Account (r:1 w:1) /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) - /// Storage: Balances Reserves (r:1 w:1) - /// Proof: Balances Reserves (max_values: None, max_size: Some(1249), added: 3724, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(66), added: 2541, mode: MaxEncodedLen) fn privatize() -> Weight { // Proof Size summary in bytes: - // Measured: `835` - // Estimated: `20620` - // Minimum execution time: 84_680_000 picoseconds. - Weight::from_parts(85_661_000, 20620) + // Measured: `828` + // Estimated: `3675` + // Minimum execution time: 85_252_000 picoseconds. + Weight::from_parts(85_949_000, 3675) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } /// Storage: Nis Receipts (r:1 w:1) /// Proof: Nis Receipts (max_values: None, max_size: Some(81), added: 2556, mode: MaxEncodedLen) - /// Storage: Balances Reserves (r:1 w:1) - /// Proof: Balances Reserves (max_values: None, max_size: Some(1249), added: 3724, mode: MaxEncodedLen) + /// Storage: Nis Summary (r:1 w:1) + /// Proof: Nis Summary (max_values: Some(1), max_size: Some(40), added: 535, mode: MaxEncodedLen) /// Storage: System Account (r:1 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(66), added: 2541, mode: MaxEncodedLen) + fn thaw_private() -> Weight { + // Proof Size summary in bytes: + // Measured: `456` + // Estimated: `3593` + // Minimum execution time: 82_100_000 picoseconds. + Weight::from_parts(82_563_000, 3593) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + } + /// Storage: Nis Receipts (r:1 w:1) + /// Proof: Nis Receipts (max_values: None, max_size: Some(81), added: 2556, mode: MaxEncodedLen) /// Storage: Nis Summary (r:1 w:1) /// Proof: Nis Summary (max_values: Some(1), max_size: Some(40), added: 535, mode: MaxEncodedLen) /// Storage: Assets Asset (r:1 w:1) /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) /// Storage: Assets Account (r:1 w:1) /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) - fn communify() -> Weight { + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + fn thaw_communal() -> Weight { // Proof Size summary in bytes: - // Measured: `674` - // Estimated: `20620` - // Minimum execution time: 72_828_000 picoseconds. - Weight::from_parts(73_553_000, 20620) - .saturating_add(RocksDbWeight::get().reads(6_u64)) - .saturating_add(RocksDbWeight::get().writes(6_u64)) + // Measured: `773` + // Estimated: `3675` + // Minimum execution time: 86_498_000 picoseconds. + Weight::from_parts(87_175_000, 3675) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(5_u64)) } /// Storage: Nis Summary (r:1 w:1) /// Proof: Nis Summary (max_values: Some(1), max_size: Some(40), added: 535, mode: MaxEncodedLen) @@ -400,9 +397,9 @@ impl WeightInfo for () { fn process_queues() -> Weight { // Proof Size summary in bytes: // Measured: `6624` - // Estimated: `12605` - // Minimum execution time: 23_311_000 picoseconds. - Weight::from_parts(23_855_000, 12605) + // Estimated: `7487` + // Minimum execution time: 22_507_000 picoseconds. + Weight::from_parts(22_788_000, 7487) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -412,8 +409,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `42` // Estimated: `51487` - // Minimum execution time: 4_485_000 picoseconds. - Weight::from_parts(4_717_000, 51487) + // Minimum execution time: 4_692_000 picoseconds. + Weight::from_parts(4_862_000, 51487) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -423,8 +420,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_837_000 picoseconds. - Weight::from_parts(12_913_000, 0) + // Minimum execution time: 8_031_000 picoseconds. + Weight::from_parts(8_183_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } } diff --git a/frame/nomination-pools/src/weights.rs b/frame/nomination-pools/src/weights.rs index 003ba93eb8a7e..0ac50d2f745ed 100644 --- a/frame/nomination-pools/src/weights.rs +++ b/frame/nomination-pools/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_nomination_pools //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,9 +31,6 @@ // --steps=50 // --repeat=20 // --pallet=pallet_nomination_pools -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -100,6 +97,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: NominationPools CounterForPoolMembers (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: VoterList ListNodes (r:3 w:3) /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) /// Storage: VoterList ListBags (r:2 w:2) @@ -107,10 +106,10 @@ impl WeightInfo for SubstrateWeight { fn join() -> Weight { // Proof Size summary in bytes: // Measured: `3300` - // Estimated: `52435` - // Minimum execution time: 160_675_000 picoseconds. - Weight::from_parts(162_605_000, 52435) - .saturating_add(T::DbWeight::get().reads(18_u64)) + // Estimated: `8877` + // Minimum execution time: 186_523_000 picoseconds. + Weight::from_parts(187_817_000, 8877) + .saturating_add(T::DbWeight::get().reads(19_u64)) .saturating_add(T::DbWeight::get().writes(12_u64)) } /// Storage: NominationPools PoolMembers (r:1 w:1) @@ -129,6 +128,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: VoterList ListNodes (r:3 w:3) /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) /// Storage: VoterList ListBags (r:2 w:2) @@ -136,10 +137,10 @@ impl WeightInfo for SubstrateWeight { fn bond_extra_transfer() -> Weight { // Proof Size summary in bytes: // Measured: `3310` - // Estimated: `49070` - // Minimum execution time: 156_820_000 picoseconds. - Weight::from_parts(159_798_000, 49070) - .saturating_add(T::DbWeight::get().reads(15_u64)) + // Estimated: `8877` + // Minimum execution time: 183_120_000 picoseconds. + Weight::from_parts(184_749_000, 8877) + .saturating_add(T::DbWeight::get().reads(16_u64)) .saturating_add(T::DbWeight::get().writes(12_u64)) } /// Storage: NominationPools ClaimPermissions (r:1 w:0) @@ -160,6 +161,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: VoterList ListNodes (r:3 w:3) /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) /// Storage: VoterList ListBags (r:2 w:2) @@ -167,10 +170,10 @@ impl WeightInfo for SubstrateWeight { fn bond_extra_other() -> Weight { // Proof Size summary in bytes: // Measured: `3375` - // Estimated: `52576` - // Minimum execution time: 175_820_000 picoseconds. - Weight::from_parts(177_378_000, 52576) - .saturating_add(T::DbWeight::get().reads(16_u64)) + // Estimated: `8877` + // Minimum execution time: 218_799_000 picoseconds. + Weight::from_parts(220_139_000, 8877) + .saturating_add(T::DbWeight::get().reads(17_u64)) .saturating_add(T::DbWeight::get().writes(13_u64)) } /// Storage: NominationPools ClaimPermissions (r:1 w:0) @@ -188,9 +191,9 @@ impl WeightInfo for SubstrateWeight { fn claim_payout() -> Weight { // Proof Size summary in bytes: // Measured: `1171` - // Estimated: `19532` - // Minimum execution time: 62_011_000 picoseconds. - Weight::from_parts(62_680_000, 19532) + // Estimated: `3702` + // Minimum execution time: 79_493_000 picoseconds. + Weight::from_parts(80_266_000, 3702) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -216,6 +219,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: VoterList ListNodes (r:3 w:3) /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) /// Storage: VoterList ListBags (r:2 w:2) @@ -227,10 +232,10 @@ impl WeightInfo for SubstrateWeight { fn unbond() -> Weight { // Proof Size summary in bytes: // Measured: `3586` - // Estimated: `82816` - // Minimum execution time: 163_294_000 picoseconds. - Weight::from_parts(164_375_000, 82816) - .saturating_add(T::DbWeight::get().reads(19_u64)) + // Estimated: `27847` + // Minimum execution time: 168_592_000 picoseconds. + Weight::from_parts(170_130_000, 27847) + .saturating_add(T::DbWeight::get().reads(20_u64)) .saturating_add(T::DbWeight::get().writes(13_u64)) } /// Storage: NominationPools BondedPools (r:1 w:0) @@ -243,16 +248,18 @@ impl WeightInfo for SubstrateWeight { /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// The range of component `s` is `[0, 100]`. fn pool_withdraw_unbonded(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `1687` - // Estimated: `18031` - // Minimum execution time: 54_775_000 picoseconds. - Weight::from_parts(55_724_944, 18031) - // Standard Error: 536 - .saturating_add(Weight::from_parts(10_059, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(5_u64)) + // Estimated: `4764` + // Minimum execution time: 63_254_000 picoseconds. + Weight::from_parts(64_154_755, 4764) + // Standard Error: 344 + .saturating_add(Weight::from_parts(8_798, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: NominationPools PoolMembers (r:1 w:1) @@ -269,6 +276,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: System Account (r:1 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: NominationPools CounterForPoolMembers (r:1 w:1) @@ -279,12 +288,12 @@ impl WeightInfo for SubstrateWeight { fn withdraw_unbonded_update(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `2115` - // Estimated: `54662` - // Minimum execution time: 106_820_000 picoseconds. - Weight::from_parts(109_870_849, 54662) - // Standard Error: 11_111 - .saturating_add(Weight::from_parts(2_006, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(9_u64)) + // Estimated: `27847` + // Minimum execution time: 131_339_000 picoseconds. + Weight::from_parts(133_590_267, 27847) + // Standard Error: 1_058 + .saturating_add(Weight::from_parts(9_932, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(10_u64)) .saturating_add(T::DbWeight::get().writes(8_u64)) } /// Storage: NominationPools PoolMembers (r:1 w:1) @@ -309,6 +318,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: NominationPools CounterForPoolMembers (r:1 w:1) /// Proof: NominationPools CounterForPoolMembers (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: NominationPools ReversePoolIdLookup (r:1 w:1) @@ -330,15 +341,13 @@ impl WeightInfo for SubstrateWeight { /// Storage: NominationPools ClaimPermissions (r:0 w:1) /// Proof: NominationPools ClaimPermissions (max_values: None, max_size: Some(41), added: 2516, mode: MaxEncodedLen) /// The range of component `s` is `[0, 100]`. - fn withdraw_unbonded_kill(s: u32, ) -> Weight { + fn withdraw_unbonded_kill(_s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `2470` - // Estimated: `87490` - // Minimum execution time: 170_908_000 picoseconds. - Weight::from_parts(173_616_555, 87490) - // Standard Error: 2_324 - .saturating_add(Weight::from_parts(4_397, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(20_u64)) + // Estimated: `27847` + // Minimum execution time: 219_026_000 picoseconds. + Weight::from_parts(223_230_356, 27847) + .saturating_add(T::DbWeight::get().reads(21_u64)) .saturating_add(T::DbWeight::get().writes(18_u64)) } /// Storage: NominationPools LastPoolId (r:1 w:1) @@ -371,6 +380,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: NominationPools RewardPools (r:1 w:1) /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) /// Storage: NominationPools CounterForRewardPools (r:1 w:1) @@ -386,10 +397,10 @@ impl WeightInfo for SubstrateWeight { fn create() -> Weight { // Proof Size summary in bytes: // Measured: `1289` - // Estimated: `51410` - // Minimum execution time: 148_934_000 picoseconds. - Weight::from_parts(149_702_000, 51410) - .saturating_add(T::DbWeight::get().reads(21_u64)) + // Estimated: `6196` + // Minimum execution time: 189_710_000 picoseconds. + Weight::from_parts(190_251_000, 6196) + .saturating_add(T::DbWeight::get().reads(22_u64)) .saturating_add(T::DbWeight::get().writes(15_u64)) } /// Storage: NominationPools BondedPools (r:1 w:0) @@ -420,11 +431,11 @@ impl WeightInfo for SubstrateWeight { fn nominate(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `1849` - // Estimated: `33934 + n * (2520 ±0)` - // Minimum execution time: 68_986_000 picoseconds. - Weight::from_parts(69_474_269, 33934) - // Standard Error: 6_602 - .saturating_add(Weight::from_parts(1_416_294, 0).saturating_mul(n.into())) + // Estimated: `4556 + n * (2520 ±0)` + // Minimum execution time: 70_044_000 picoseconds. + Weight::from_parts(69_307_256, 4556) + // Standard Error: 6_066 + .saturating_add(Weight::from_parts(1_517_942, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(5_u64)) @@ -439,9 +450,9 @@ impl WeightInfo for SubstrateWeight { fn set_state() -> Weight { // Proof Size summary in bytes: // Measured: `1438` - // Estimated: `11778` - // Minimum execution time: 36_300_000 picoseconds. - Weight::from_parts(36_713_000, 11778) + // Estimated: `4556` + // Minimum execution time: 36_610_000 picoseconds. + Weight::from_parts(37_212_000, 4556) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -455,11 +466,11 @@ impl WeightInfo for SubstrateWeight { fn set_metadata(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `531` - // Estimated: `8909` - // Minimum execution time: 14_976_000 picoseconds. - Weight::from_parts(15_538_088, 8909) - // Standard Error: 71 - .saturating_add(Weight::from_parts(1_548, 0).saturating_mul(n.into())) + // Estimated: `3735` + // Minimum execution time: 15_334_000 picoseconds. + Weight::from_parts(15_753_107, 3735) + // Standard Error: 62 + .saturating_add(Weight::from_parts(1_365, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -479,8 +490,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_259_000 picoseconds. - Weight::from_parts(7_499_000, 0) + // Minimum execution time: 7_156_000 picoseconds. + Weight::from_parts(7_596_000, 0) .saturating_add(T::DbWeight::get().writes(6_u64)) } /// Storage: NominationPools BondedPools (r:1 w:1) @@ -489,8 +500,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `531` // Estimated: `3685` - // Minimum execution time: 20_454_000 picoseconds. - Weight::from_parts(20_771_000, 3685) + // Minimum execution time: 20_342_000 picoseconds. + Weight::from_parts(20_699_000, 3685) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -515,9 +526,9 @@ impl WeightInfo for SubstrateWeight { fn chill() -> Weight { // Proof Size summary in bytes: // Measured: `2012` - // Estimated: `29455` - // Minimum execution time: 66_404_000 picoseconds. - Weight::from_parts(66_872_000, 29455) + // Estimated: `4556` + // Minimum execution time: 66_608_000 picoseconds. + Weight::from_parts(67_416_000, 4556) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -532,9 +543,9 @@ impl WeightInfo for SubstrateWeight { fn set_commission() -> Weight { // Proof Size summary in bytes: // Measured: `770` - // Estimated: `12324` - // Minimum execution time: 34_240_000 picoseconds. - Weight::from_parts(34_797_000, 12324) + // Estimated: `3685` + // Minimum execution time: 34_619_000 picoseconds. + Weight::from_parts(34_894_000, 3685) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -544,8 +555,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `571` // Estimated: `3685` - // Minimum execution time: 19_469_000 picoseconds. - Weight::from_parts(19_865_000, 3685) + // Minimum execution time: 19_676_000 picoseconds. + Weight::from_parts(19_958_000, 3685) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -555,8 +566,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `531` // Estimated: `3685` - // Minimum execution time: 20_423_000 picoseconds. - Weight::from_parts(20_620_000, 3685) + // Minimum execution time: 20_404_000 picoseconds. + Weight::from_parts(20_859_000, 3685) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -567,9 +578,9 @@ impl WeightInfo for SubstrateWeight { fn set_claim_permission() -> Weight { // Proof Size summary in bytes: // Measured: `542` - // Estimated: `7208` - // Minimum execution time: 15_346_000 picoseconds. - Weight::from_parts(15_613_000, 7208) + // Estimated: `3702` + // Minimum execution time: 15_401_000 picoseconds. + Weight::from_parts(15_706_000, 3702) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -584,9 +595,9 @@ impl WeightInfo for SubstrateWeight { fn claim_commission() -> Weight { // Proof Size summary in bytes: // Measured: `968` - // Estimated: `12324` - // Minimum execution time: 48_749_000 picoseconds. - Weight::from_parts(49_131_000, 12324) + // Estimated: `3685` + // Minimum execution time: 66_775_000 picoseconds. + Weight::from_parts(67_242_000, 3685) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -618,6 +629,8 @@ impl WeightInfo for () { /// Proof: NominationPools CounterForPoolMembers (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: VoterList ListNodes (r:3 w:3) /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) /// Storage: VoterList ListBags (r:2 w:2) @@ -625,10 +638,10 @@ impl WeightInfo for () { fn join() -> Weight { // Proof Size summary in bytes: // Measured: `3300` - // Estimated: `52435` - // Minimum execution time: 160_675_000 picoseconds. - Weight::from_parts(162_605_000, 52435) - .saturating_add(RocksDbWeight::get().reads(18_u64)) + // Estimated: `8877` + // Minimum execution time: 186_523_000 picoseconds. + Weight::from_parts(187_817_000, 8877) + .saturating_add(RocksDbWeight::get().reads(19_u64)) .saturating_add(RocksDbWeight::get().writes(12_u64)) } /// Storage: NominationPools PoolMembers (r:1 w:1) @@ -647,6 +660,8 @@ impl WeightInfo for () { /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: VoterList ListNodes (r:3 w:3) /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) /// Storage: VoterList ListBags (r:2 w:2) @@ -654,10 +669,10 @@ impl WeightInfo for () { fn bond_extra_transfer() -> Weight { // Proof Size summary in bytes: // Measured: `3310` - // Estimated: `49070` - // Minimum execution time: 156_820_000 picoseconds. - Weight::from_parts(159_798_000, 49070) - .saturating_add(RocksDbWeight::get().reads(15_u64)) + // Estimated: `8877` + // Minimum execution time: 183_120_000 picoseconds. + Weight::from_parts(184_749_000, 8877) + .saturating_add(RocksDbWeight::get().reads(16_u64)) .saturating_add(RocksDbWeight::get().writes(12_u64)) } /// Storage: NominationPools ClaimPermissions (r:1 w:0) @@ -678,6 +693,8 @@ impl WeightInfo for () { /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: VoterList ListNodes (r:3 w:3) /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) /// Storage: VoterList ListBags (r:2 w:2) @@ -685,10 +702,10 @@ impl WeightInfo for () { fn bond_extra_other() -> Weight { // Proof Size summary in bytes: // Measured: `3375` - // Estimated: `52576` - // Minimum execution time: 175_820_000 picoseconds. - Weight::from_parts(177_378_000, 52576) - .saturating_add(RocksDbWeight::get().reads(16_u64)) + // Estimated: `8877` + // Minimum execution time: 218_799_000 picoseconds. + Weight::from_parts(220_139_000, 8877) + .saturating_add(RocksDbWeight::get().reads(17_u64)) .saturating_add(RocksDbWeight::get().writes(13_u64)) } /// Storage: NominationPools ClaimPermissions (r:1 w:0) @@ -706,9 +723,9 @@ impl WeightInfo for () { fn claim_payout() -> Weight { // Proof Size summary in bytes: // Measured: `1171` - // Estimated: `19532` - // Minimum execution time: 62_011_000 picoseconds. - Weight::from_parts(62_680_000, 19532) + // Estimated: `3702` + // Minimum execution time: 79_493_000 picoseconds. + Weight::from_parts(80_266_000, 3702) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -734,6 +751,8 @@ impl WeightInfo for () { /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: VoterList ListNodes (r:3 w:3) /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) /// Storage: VoterList ListBags (r:2 w:2) @@ -745,10 +764,10 @@ impl WeightInfo for () { fn unbond() -> Weight { // Proof Size summary in bytes: // Measured: `3586` - // Estimated: `82816` - // Minimum execution time: 163_294_000 picoseconds. - Weight::from_parts(164_375_000, 82816) - .saturating_add(RocksDbWeight::get().reads(19_u64)) + // Estimated: `27847` + // Minimum execution time: 168_592_000 picoseconds. + Weight::from_parts(170_130_000, 27847) + .saturating_add(RocksDbWeight::get().reads(20_u64)) .saturating_add(RocksDbWeight::get().writes(13_u64)) } /// Storage: NominationPools BondedPools (r:1 w:0) @@ -761,16 +780,18 @@ impl WeightInfo for () { /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// The range of component `s` is `[0, 100]`. fn pool_withdraw_unbonded(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `1687` - // Estimated: `18031` - // Minimum execution time: 54_775_000 picoseconds. - Weight::from_parts(55_724_944, 18031) - // Standard Error: 536 - .saturating_add(Weight::from_parts(10_059, 0).saturating_mul(s.into())) - .saturating_add(RocksDbWeight::get().reads(5_u64)) + // Estimated: `4764` + // Minimum execution time: 63_254_000 picoseconds. + Weight::from_parts(64_154_755, 4764) + // Standard Error: 344 + .saturating_add(Weight::from_parts(8_798, 0).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: NominationPools PoolMembers (r:1 w:1) @@ -787,6 +808,8 @@ impl WeightInfo for () { /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: System Account (r:1 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: NominationPools CounterForPoolMembers (r:1 w:1) @@ -797,12 +820,12 @@ impl WeightInfo for () { fn withdraw_unbonded_update(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `2115` - // Estimated: `54662` - // Minimum execution time: 106_820_000 picoseconds. - Weight::from_parts(109_870_849, 54662) - // Standard Error: 11_111 - .saturating_add(Weight::from_parts(2_006, 0).saturating_mul(s.into())) - .saturating_add(RocksDbWeight::get().reads(9_u64)) + // Estimated: `27847` + // Minimum execution time: 131_339_000 picoseconds. + Weight::from_parts(133_590_267, 27847) + // Standard Error: 1_058 + .saturating_add(Weight::from_parts(9_932, 0).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(10_u64)) .saturating_add(RocksDbWeight::get().writes(8_u64)) } /// Storage: NominationPools PoolMembers (r:1 w:1) @@ -827,6 +850,8 @@ impl WeightInfo for () { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: NominationPools CounterForPoolMembers (r:1 w:1) /// Proof: NominationPools CounterForPoolMembers (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: NominationPools ReversePoolIdLookup (r:1 w:1) @@ -848,15 +873,13 @@ impl WeightInfo for () { /// Storage: NominationPools ClaimPermissions (r:0 w:1) /// Proof: NominationPools ClaimPermissions (max_values: None, max_size: Some(41), added: 2516, mode: MaxEncodedLen) /// The range of component `s` is `[0, 100]`. - fn withdraw_unbonded_kill(s: u32, ) -> Weight { + fn withdraw_unbonded_kill(_s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `2470` - // Estimated: `87490` - // Minimum execution time: 170_908_000 picoseconds. - Weight::from_parts(173_616_555, 87490) - // Standard Error: 2_324 - .saturating_add(Weight::from_parts(4_397, 0).saturating_mul(s.into())) - .saturating_add(RocksDbWeight::get().reads(20_u64)) + // Estimated: `27847` + // Minimum execution time: 219_026_000 picoseconds. + Weight::from_parts(223_230_356, 27847) + .saturating_add(RocksDbWeight::get().reads(21_u64)) .saturating_add(RocksDbWeight::get().writes(18_u64)) } /// Storage: NominationPools LastPoolId (r:1 w:1) @@ -889,6 +912,8 @@ impl WeightInfo for () { /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: NominationPools RewardPools (r:1 w:1) /// Proof: NominationPools RewardPools (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) /// Storage: NominationPools CounterForRewardPools (r:1 w:1) @@ -904,10 +929,10 @@ impl WeightInfo for () { fn create() -> Weight { // Proof Size summary in bytes: // Measured: `1289` - // Estimated: `51410` - // Minimum execution time: 148_934_000 picoseconds. - Weight::from_parts(149_702_000, 51410) - .saturating_add(RocksDbWeight::get().reads(21_u64)) + // Estimated: `6196` + // Minimum execution time: 189_710_000 picoseconds. + Weight::from_parts(190_251_000, 6196) + .saturating_add(RocksDbWeight::get().reads(22_u64)) .saturating_add(RocksDbWeight::get().writes(15_u64)) } /// Storage: NominationPools BondedPools (r:1 w:0) @@ -938,11 +963,11 @@ impl WeightInfo for () { fn nominate(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `1849` - // Estimated: `33934 + n * (2520 ±0)` - // Minimum execution time: 68_986_000 picoseconds. - Weight::from_parts(69_474_269, 33934) - // Standard Error: 6_602 - .saturating_add(Weight::from_parts(1_416_294, 0).saturating_mul(n.into())) + // Estimated: `4556 + n * (2520 ±0)` + // Minimum execution time: 70_044_000 picoseconds. + Weight::from_parts(69_307_256, 4556) + // Standard Error: 6_066 + .saturating_add(Weight::from_parts(1_517_942, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(5_u64)) @@ -957,9 +982,9 @@ impl WeightInfo for () { fn set_state() -> Weight { // Proof Size summary in bytes: // Measured: `1438` - // Estimated: `11778` - // Minimum execution time: 36_300_000 picoseconds. - Weight::from_parts(36_713_000, 11778) + // Estimated: `4556` + // Minimum execution time: 36_610_000 picoseconds. + Weight::from_parts(37_212_000, 4556) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -973,11 +998,11 @@ impl WeightInfo for () { fn set_metadata(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `531` - // Estimated: `8909` - // Minimum execution time: 14_976_000 picoseconds. - Weight::from_parts(15_538_088, 8909) - // Standard Error: 71 - .saturating_add(Weight::from_parts(1_548, 0).saturating_mul(n.into())) + // Estimated: `3735` + // Minimum execution time: 15_334_000 picoseconds. + Weight::from_parts(15_753_107, 3735) + // Standard Error: 62 + .saturating_add(Weight::from_parts(1_365, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -997,8 +1022,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_259_000 picoseconds. - Weight::from_parts(7_499_000, 0) + // Minimum execution time: 7_156_000 picoseconds. + Weight::from_parts(7_596_000, 0) .saturating_add(RocksDbWeight::get().writes(6_u64)) } /// Storage: NominationPools BondedPools (r:1 w:1) @@ -1007,8 +1032,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `531` // Estimated: `3685` - // Minimum execution time: 20_454_000 picoseconds. - Weight::from_parts(20_771_000, 3685) + // Minimum execution time: 20_342_000 picoseconds. + Weight::from_parts(20_699_000, 3685) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1033,9 +1058,9 @@ impl WeightInfo for () { fn chill() -> Weight { // Proof Size summary in bytes: // Measured: `2012` - // Estimated: `29455` - // Minimum execution time: 66_404_000 picoseconds. - Weight::from_parts(66_872_000, 29455) + // Estimated: `4556` + // Minimum execution time: 66_608_000 picoseconds. + Weight::from_parts(67_416_000, 4556) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -1050,9 +1075,9 @@ impl WeightInfo for () { fn set_commission() -> Weight { // Proof Size summary in bytes: // Measured: `770` - // Estimated: `12324` - // Minimum execution time: 34_240_000 picoseconds. - Weight::from_parts(34_797_000, 12324) + // Estimated: `3685` + // Minimum execution time: 34_619_000 picoseconds. + Weight::from_parts(34_894_000, 3685) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1062,8 +1087,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `571` // Estimated: `3685` - // Minimum execution time: 19_469_000 picoseconds. - Weight::from_parts(19_865_000, 3685) + // Minimum execution time: 19_676_000 picoseconds. + Weight::from_parts(19_958_000, 3685) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1073,8 +1098,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `531` // Estimated: `3685` - // Minimum execution time: 20_423_000 picoseconds. - Weight::from_parts(20_620_000, 3685) + // Minimum execution time: 20_404_000 picoseconds. + Weight::from_parts(20_859_000, 3685) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1085,9 +1110,9 @@ impl WeightInfo for () { fn set_claim_permission() -> Weight { // Proof Size summary in bytes: // Measured: `542` - // Estimated: `7208` - // Minimum execution time: 15_346_000 picoseconds. - Weight::from_parts(15_613_000, 7208) + // Estimated: `3702` + // Minimum execution time: 15_401_000 picoseconds. + Weight::from_parts(15_706_000, 3702) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1102,9 +1127,9 @@ impl WeightInfo for () { fn claim_commission() -> Weight { // Proof Size summary in bytes: // Measured: `968` - // Estimated: `12324` - // Minimum execution time: 48_749_000 picoseconds. - Weight::from_parts(49_131_000, 12324) + // Estimated: `3685` + // Minimum execution time: 66_775_000 picoseconds. + Weight::from_parts(67_242_000, 3685) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } diff --git a/frame/preimage/src/weights.rs b/frame/preimage/src/weights.rs index 168cb634c2d48..2177309db1612 100644 --- a/frame/preimage/src/weights.rs +++ b/frame/preimage/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_preimage //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,9 +31,6 @@ // --steps=50 // --repeat=20 // --pallet=pallet_preimage -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -77,10 +74,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `143` // Estimated: `3556` - // Minimum execution time: 27_010_000 picoseconds. - Weight::from_parts(27_665_000, 3556) + // Minimum execution time: 31_578_000 picoseconds. + Weight::from_parts(31_955_000, 3556) // Standard Error: 0 - .saturating_add(Weight::from_parts(1_414, 0).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_395, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -93,10 +90,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3556` - // Minimum execution time: 16_984_000 picoseconds. - Weight::from_parts(17_455_000, 3556) + // Minimum execution time: 17_017_000 picoseconds. + Weight::from_parts(17_549_000, 3556) // Standard Error: 0 - .saturating_add(Weight::from_parts(1_414, 0).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_394, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -109,10 +106,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3556` - // Minimum execution time: 16_579_000 picoseconds. - Weight::from_parts(16_849_000, 3556) + // Minimum execution time: 16_507_000 picoseconds. + Weight::from_parts(16_624_000, 3556) // Standard Error: 0 - .saturating_add(Weight::from_parts(1_414, 0).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_395, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -124,8 +121,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `289` // Estimated: `3556` - // Minimum execution time: 33_552_000 picoseconds. - Weight::from_parts(35_134_000, 3556) + // Minimum execution time: 38_016_000 picoseconds. + Weight::from_parts(38_909_000, 3556) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -137,8 +134,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `144` // Estimated: `3556` - // Minimum execution time: 22_102_000 picoseconds. - Weight::from_parts(22_860_000, 3556) + // Minimum execution time: 21_408_000 picoseconds. + Weight::from_parts(22_343_000, 3556) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -148,8 +145,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `188` // Estimated: `3556` - // Minimum execution time: 19_590_000 picoseconds. - Weight::from_parts(20_638_000, 3556) + // Minimum execution time: 20_035_000 picoseconds. + Weight::from_parts(20_639_000, 3556) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -159,8 +156,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `144` // Estimated: `3556` - // Minimum execution time: 11_689_000 picoseconds. - Weight::from_parts(12_577_000, 3556) + // Minimum execution time: 12_028_000 picoseconds. + Weight::from_parts(12_509_000, 3556) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -170,8 +167,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `42` // Estimated: `3556` - // Minimum execution time: 13_673_000 picoseconds. - Weight::from_parts(14_210_000, 3556) + // Minimum execution time: 13_568_000 picoseconds. + Weight::from_parts(14_161_000, 3556) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -181,8 +178,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3556` - // Minimum execution time: 8_810_000 picoseconds. - Weight::from_parts(9_044_000, 3556) + // Minimum execution time: 8_538_000 picoseconds. + Weight::from_parts(8_933_000, 3556) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -194,8 +191,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `144` // Estimated: `3556` - // Minimum execution time: 21_236_000 picoseconds. - Weight::from_parts(21_684_000, 3556) + // Minimum execution time: 20_692_000 picoseconds. + Weight::from_parts(21_770_000, 3556) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -205,8 +202,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3556` - // Minimum execution time: 8_709_000 picoseconds. - Weight::from_parts(8_970_000, 3556) + // Minimum execution time: 8_572_000 picoseconds. + Weight::from_parts(8_795_000, 3556) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -216,8 +213,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3556` - // Minimum execution time: 8_976_000 picoseconds. - Weight::from_parts(9_164_000, 3556) + // Minimum execution time: 8_266_000 picoseconds. + Weight::from_parts(8_721_000, 3556) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -234,10 +231,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `143` // Estimated: `3556` - // Minimum execution time: 27_010_000 picoseconds. - Weight::from_parts(27_665_000, 3556) + // Minimum execution time: 31_578_000 picoseconds. + Weight::from_parts(31_955_000, 3556) // Standard Error: 0 - .saturating_add(Weight::from_parts(1_414, 0).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_395, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -250,10 +247,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3556` - // Minimum execution time: 16_984_000 picoseconds. - Weight::from_parts(17_455_000, 3556) + // Minimum execution time: 17_017_000 picoseconds. + Weight::from_parts(17_549_000, 3556) // Standard Error: 0 - .saturating_add(Weight::from_parts(1_414, 0).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_394, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -266,10 +263,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3556` - // Minimum execution time: 16_579_000 picoseconds. - Weight::from_parts(16_849_000, 3556) + // Minimum execution time: 16_507_000 picoseconds. + Weight::from_parts(16_624_000, 3556) // Standard Error: 0 - .saturating_add(Weight::from_parts(1_414, 0).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_395, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -281,8 +278,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `289` // Estimated: `3556` - // Minimum execution time: 33_552_000 picoseconds. - Weight::from_parts(35_134_000, 3556) + // Minimum execution time: 38_016_000 picoseconds. + Weight::from_parts(38_909_000, 3556) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -294,8 +291,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `144` // Estimated: `3556` - // Minimum execution time: 22_102_000 picoseconds. - Weight::from_parts(22_860_000, 3556) + // Minimum execution time: 21_408_000 picoseconds. + Weight::from_parts(22_343_000, 3556) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -305,8 +302,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `188` // Estimated: `3556` - // Minimum execution time: 19_590_000 picoseconds. - Weight::from_parts(20_638_000, 3556) + // Minimum execution time: 20_035_000 picoseconds. + Weight::from_parts(20_639_000, 3556) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -316,8 +313,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `144` // Estimated: `3556` - // Minimum execution time: 11_689_000 picoseconds. - Weight::from_parts(12_577_000, 3556) + // Minimum execution time: 12_028_000 picoseconds. + Weight::from_parts(12_509_000, 3556) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -327,8 +324,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `42` // Estimated: `3556` - // Minimum execution time: 13_673_000 picoseconds. - Weight::from_parts(14_210_000, 3556) + // Minimum execution time: 13_568_000 picoseconds. + Weight::from_parts(14_161_000, 3556) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -338,8 +335,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3556` - // Minimum execution time: 8_810_000 picoseconds. - Weight::from_parts(9_044_000, 3556) + // Minimum execution time: 8_538_000 picoseconds. + Weight::from_parts(8_933_000, 3556) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -351,8 +348,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `144` // Estimated: `3556` - // Minimum execution time: 21_236_000 picoseconds. - Weight::from_parts(21_684_000, 3556) + // Minimum execution time: 20_692_000 picoseconds. + Weight::from_parts(21_770_000, 3556) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -362,8 +359,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3556` - // Minimum execution time: 8_709_000 picoseconds. - Weight::from_parts(8_970_000, 3556) + // Minimum execution time: 8_572_000 picoseconds. + Weight::from_parts(8_795_000, 3556) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -373,8 +370,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3556` - // Minimum execution time: 8_976_000 picoseconds. - Weight::from_parts(9_164_000, 3556) + // Minimum execution time: 8_266_000 picoseconds. + Weight::from_parts(8_721_000, 3556) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/frame/proxy/src/weights.rs b/frame/proxy/src/weights.rs index 28e24c4682f18..5a6352fc7ed7f 100644 --- a/frame/proxy/src/weights.rs +++ b/frame/proxy/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_proxy //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,9 +31,6 @@ // --steps=50 // --repeat=20 // --pallet=pallet_proxy -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -73,10 +70,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `161 + p * (37 ±0)` // Estimated: `4706` - // Minimum execution time: 16_407_000 picoseconds. - Weight::from_parts(17_044_509, 4706) - // Standard Error: 1_177 - .saturating_add(Weight::from_parts(36_533, 0).saturating_mul(p.into())) + // Minimum execution time: 16_542_000 picoseconds. + Weight::from_parts(17_131_651, 4706) + // Standard Error: 1_279 + .saturating_add(Weight::from_parts(31_622, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: Proxy Proxies (r:1 w:0) @@ -90,13 +87,13 @@ impl WeightInfo for SubstrateWeight { fn proxy_announced(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `488 + a * (68 ±0) + p * (37 ±0)` - // Estimated: `13997` - // Minimum execution time: 38_523_000 picoseconds. - Weight::from_parts(39_227_232, 13997) - // Standard Error: 5_703 - .saturating_add(Weight::from_parts(136_003, 0).saturating_mul(a.into())) - // Standard Error: 5_893 - .saturating_add(Weight::from_parts(42_397, 0).saturating_mul(p.into())) + // Estimated: `5698` + // Minimum execution time: 41_702_000 picoseconds. + Weight::from_parts(41_868_091, 5698) + // Standard Error: 3_771 + .saturating_add(Weight::from_parts(135_604, 0).saturating_mul(a.into())) + // Standard Error: 3_896 + .saturating_add(Weight::from_parts(32_615, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -106,16 +103,14 @@ impl WeightInfo for SubstrateWeight { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `a` is `[0, 31]`. /// The range of component `p` is `[1, 31]`. - fn remove_announcement(a: u32, p: u32, ) -> Weight { + fn remove_announcement(a: u32, _p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `403 + a * (68 ±0)` - // Estimated: `9291` - // Minimum execution time: 22_541_000 picoseconds. - Weight::from_parts(23_402_268, 9291) - // Standard Error: 3_242 - .saturating_add(Weight::from_parts(178_017, 0).saturating_mul(a.into())) - // Standard Error: 3_349 - .saturating_add(Weight::from_parts(6_230, 0).saturating_mul(p.into())) + // Estimated: `5698` + // Minimum execution time: 25_432_000 picoseconds. + Weight::from_parts(26_301_674, 5698) + // Standard Error: 1_413 + .saturating_add(Weight::from_parts(167_176, 0).saturating_mul(a.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -128,13 +123,13 @@ impl WeightInfo for SubstrateWeight { fn reject_announcement(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `403 + a * (68 ±0)` - // Estimated: `9291` - // Minimum execution time: 22_539_000 picoseconds. - Weight::from_parts(23_479_286, 9291) - // Standard Error: 1_329 - .saturating_add(Weight::from_parts(174_021, 0).saturating_mul(a.into())) - // Standard Error: 1_373 - .saturating_add(Weight::from_parts(6_465, 0).saturating_mul(p.into())) + // Estimated: `5698` + // Minimum execution time: 25_280_000 picoseconds. + Weight::from_parts(26_099_549, 5698) + // Standard Error: 1_458 + .saturating_add(Weight::from_parts(168_724, 0).saturating_mul(a.into())) + // Standard Error: 1_507 + .saturating_add(Weight::from_parts(2_212, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -149,13 +144,13 @@ impl WeightInfo for SubstrateWeight { fn announce(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `420 + a * (68 ±0) + p * (37 ±0)` - // Estimated: `13997` - // Minimum execution time: 32_049_000 picoseconds. - Weight::from_parts(35_352_453, 13997) - // Standard Error: 4_389 - .saturating_add(Weight::from_parts(144_573, 0).saturating_mul(a.into())) - // Standard Error: 4_535 - .saturating_add(Weight::from_parts(41_849, 0).saturating_mul(p.into())) + // Estimated: `5698` + // Minimum execution time: 35_889_000 picoseconds. + Weight::from_parts(37_535_424, 5698) + // Standard Error: 3_899 + .saturating_add(Weight::from_parts(138_757, 0).saturating_mul(a.into())) + // Standard Error: 4_028 + .saturating_add(Weight::from_parts(46_196, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -166,10 +161,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `161 + p * (37 ±0)` // Estimated: `4706` - // Minimum execution time: 24_491_000 picoseconds. - Weight::from_parts(25_291_582, 4706) - // Standard Error: 11_080 - .saturating_add(Weight::from_parts(68_024, 0).saturating_mul(p.into())) + // Minimum execution time: 26_876_000 picoseconds. + Weight::from_parts(27_356_694, 4706) + // Standard Error: 1_437 + .saturating_add(Weight::from_parts(68_994, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -180,10 +175,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `161 + p * (37 ±0)` // Estimated: `4706` - // Minimum execution time: 23_849_000 picoseconds. - Weight::from_parts(25_370_806, 4706) - // Standard Error: 8_763 - .saturating_add(Weight::from_parts(63_413, 0).saturating_mul(p.into())) + // Minimum execution time: 26_655_000 picoseconds. + Weight::from_parts(27_726_692, 4706) + // Standard Error: 1_980 + .saturating_add(Weight::from_parts(55_932, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -194,24 +189,22 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `161 + p * (37 ±0)` // Estimated: `4706` - // Minimum execution time: 19_488_000 picoseconds. - Weight::from_parts(20_219_817, 4706) - // Standard Error: 1_385 - .saturating_add(Weight::from_parts(30_354, 0).saturating_mul(p.into())) + // Minimum execution time: 23_716_000 picoseconds. + Weight::from_parts(24_660_737, 4706) + // Standard Error: 1_400 + .saturating_add(Weight::from_parts(31_679, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Proxy Proxies (r:1 w:1) /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) /// The range of component `p` is `[1, 31]`. - fn create_pure(p: u32, ) -> Weight { + fn create_pure(_p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `173` // Estimated: `4706` - // Minimum execution time: 25_864_000 picoseconds. - Weight::from_parts(26_712_232, 4706) - // Standard Error: 1_331 - .saturating_add(Weight::from_parts(4_401, 0).saturating_mul(p.into())) + // Minimum execution time: 28_233_000 picoseconds. + Weight::from_parts(29_602_422, 4706) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -222,10 +215,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `198 + p * (37 ±0)` // Estimated: `4706` - // Minimum execution time: 20_488_000 picoseconds. - Weight::from_parts(21_135_155, 4706) - // Standard Error: 1_255 - .saturating_add(Weight::from_parts(36_312, 0).saturating_mul(p.into())) + // Minimum execution time: 24_759_000 picoseconds. + Weight::from_parts(25_533_053, 4706) + // Standard Error: 1_254 + .saturating_add(Weight::from_parts(36_331, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -240,10 +233,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `161 + p * (37 ±0)` // Estimated: `4706` - // Minimum execution time: 16_407_000 picoseconds. - Weight::from_parts(17_044_509, 4706) - // Standard Error: 1_177 - .saturating_add(Weight::from_parts(36_533, 0).saturating_mul(p.into())) + // Minimum execution time: 16_542_000 picoseconds. + Weight::from_parts(17_131_651, 4706) + // Standard Error: 1_279 + .saturating_add(Weight::from_parts(31_622, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: Proxy Proxies (r:1 w:0) @@ -257,13 +250,13 @@ impl WeightInfo for () { fn proxy_announced(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `488 + a * (68 ±0) + p * (37 ±0)` - // Estimated: `13997` - // Minimum execution time: 38_523_000 picoseconds. - Weight::from_parts(39_227_232, 13997) - // Standard Error: 5_703 - .saturating_add(Weight::from_parts(136_003, 0).saturating_mul(a.into())) - // Standard Error: 5_893 - .saturating_add(Weight::from_parts(42_397, 0).saturating_mul(p.into())) + // Estimated: `5698` + // Minimum execution time: 41_702_000 picoseconds. + Weight::from_parts(41_868_091, 5698) + // Standard Error: 3_771 + .saturating_add(Weight::from_parts(135_604, 0).saturating_mul(a.into())) + // Standard Error: 3_896 + .saturating_add(Weight::from_parts(32_615, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -273,16 +266,14 @@ impl WeightInfo for () { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `a` is `[0, 31]`. /// The range of component `p` is `[1, 31]`. - fn remove_announcement(a: u32, p: u32, ) -> Weight { + fn remove_announcement(a: u32, _p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `403 + a * (68 ±0)` - // Estimated: `9291` - // Minimum execution time: 22_541_000 picoseconds. - Weight::from_parts(23_402_268, 9291) - // Standard Error: 3_242 - .saturating_add(Weight::from_parts(178_017, 0).saturating_mul(a.into())) - // Standard Error: 3_349 - .saturating_add(Weight::from_parts(6_230, 0).saturating_mul(p.into())) + // Estimated: `5698` + // Minimum execution time: 25_432_000 picoseconds. + Weight::from_parts(26_301_674, 5698) + // Standard Error: 1_413 + .saturating_add(Weight::from_parts(167_176, 0).saturating_mul(a.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -295,13 +286,13 @@ impl WeightInfo for () { fn reject_announcement(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `403 + a * (68 ±0)` - // Estimated: `9291` - // Minimum execution time: 22_539_000 picoseconds. - Weight::from_parts(23_479_286, 9291) - // Standard Error: 1_329 - .saturating_add(Weight::from_parts(174_021, 0).saturating_mul(a.into())) - // Standard Error: 1_373 - .saturating_add(Weight::from_parts(6_465, 0).saturating_mul(p.into())) + // Estimated: `5698` + // Minimum execution time: 25_280_000 picoseconds. + Weight::from_parts(26_099_549, 5698) + // Standard Error: 1_458 + .saturating_add(Weight::from_parts(168_724, 0).saturating_mul(a.into())) + // Standard Error: 1_507 + .saturating_add(Weight::from_parts(2_212, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -316,13 +307,13 @@ impl WeightInfo for () { fn announce(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `420 + a * (68 ±0) + p * (37 ±0)` - // Estimated: `13997` - // Minimum execution time: 32_049_000 picoseconds. - Weight::from_parts(35_352_453, 13997) - // Standard Error: 4_389 - .saturating_add(Weight::from_parts(144_573, 0).saturating_mul(a.into())) - // Standard Error: 4_535 - .saturating_add(Weight::from_parts(41_849, 0).saturating_mul(p.into())) + // Estimated: `5698` + // Minimum execution time: 35_889_000 picoseconds. + Weight::from_parts(37_535_424, 5698) + // Standard Error: 3_899 + .saturating_add(Weight::from_parts(138_757, 0).saturating_mul(a.into())) + // Standard Error: 4_028 + .saturating_add(Weight::from_parts(46_196, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -333,10 +324,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `161 + p * (37 ±0)` // Estimated: `4706` - // Minimum execution time: 24_491_000 picoseconds. - Weight::from_parts(25_291_582, 4706) - // Standard Error: 11_080 - .saturating_add(Weight::from_parts(68_024, 0).saturating_mul(p.into())) + // Minimum execution time: 26_876_000 picoseconds. + Weight::from_parts(27_356_694, 4706) + // Standard Error: 1_437 + .saturating_add(Weight::from_parts(68_994, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -347,10 +338,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `161 + p * (37 ±0)` // Estimated: `4706` - // Minimum execution time: 23_849_000 picoseconds. - Weight::from_parts(25_370_806, 4706) - // Standard Error: 8_763 - .saturating_add(Weight::from_parts(63_413, 0).saturating_mul(p.into())) + // Minimum execution time: 26_655_000 picoseconds. + Weight::from_parts(27_726_692, 4706) + // Standard Error: 1_980 + .saturating_add(Weight::from_parts(55_932, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -361,24 +352,22 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `161 + p * (37 ±0)` // Estimated: `4706` - // Minimum execution time: 19_488_000 picoseconds. - Weight::from_parts(20_219_817, 4706) - // Standard Error: 1_385 - .saturating_add(Weight::from_parts(30_354, 0).saturating_mul(p.into())) + // Minimum execution time: 23_716_000 picoseconds. + Weight::from_parts(24_660_737, 4706) + // Standard Error: 1_400 + .saturating_add(Weight::from_parts(31_679, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Proxy Proxies (r:1 w:1) /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) /// The range of component `p` is `[1, 31]`. - fn create_pure(p: u32, ) -> Weight { + fn create_pure(_p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `173` // Estimated: `4706` - // Minimum execution time: 25_864_000 picoseconds. - Weight::from_parts(26_712_232, 4706) - // Standard Error: 1_331 - .saturating_add(Weight::from_parts(4_401, 0).saturating_mul(p.into())) + // Minimum execution time: 28_233_000 picoseconds. + Weight::from_parts(29_602_422, 4706) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -389,10 +378,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `198 + p * (37 ±0)` // Estimated: `4706` - // Minimum execution time: 20_488_000 picoseconds. - Weight::from_parts(21_135_155, 4706) - // Standard Error: 1_255 - .saturating_add(Weight::from_parts(36_312, 0).saturating_mul(p.into())) + // Minimum execution time: 24_759_000 picoseconds. + Weight::from_parts(25_533_053, 4706) + // Standard Error: 1_254 + .saturating_add(Weight::from_parts(36_331, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/frame/ranked-collective/src/weights.rs b/frame/ranked-collective/src/weights.rs index e25737a1df8f0..754fcf70aaafc 100644 --- a/frame/ranked-collective/src/weights.rs +++ b/frame/ranked-collective/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_ranked_collective //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,9 +31,6 @@ // --steps=50 // --repeat=20 // --pallet=pallet_ranked_collective -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -73,9 +70,9 @@ impl WeightInfo for SubstrateWeight { fn add_member() -> Weight { // Proof Size summary in bytes: // Measured: `109` - // Estimated: `6986` - // Minimum execution time: 19_174_000 picoseconds. - Weight::from_parts(19_391_000, 6986) + // Estimated: `3507` + // Minimum execution time: 18_480_000 picoseconds. + Weight::from_parts(18_769_000, 3507) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -91,16 +88,16 @@ impl WeightInfo for SubstrateWeight { fn remove_member(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `583 + r * (281 ±0)` - // Estimated: `14024 + r * (7547 ±0)` - // Minimum execution time: 30_972_000 picoseconds. - Weight::from_parts(35_526_205, 14024) - // Standard Error: 47_832 - .saturating_add(Weight::from_parts(12_838_739, 0).saturating_mul(r.into())) + // Estimated: `3519 + r * (2529 ±0)` + // Minimum execution time: 30_087_000 picoseconds. + Weight::from_parts(33_646_239, 3519) + // Standard Error: 22_498 + .saturating_add(Weight::from_parts(12_524_289, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 7547).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 2529).saturating_mul(r.into())) } /// Storage: RankedCollective Members (r:1 w:1) /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) @@ -114,11 +111,11 @@ impl WeightInfo for SubstrateWeight { fn promote_member(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `281 + r * (17 ±0)` - // Estimated: `6986` - // Minimum execution time: 21_573_000 picoseconds. - Weight::from_parts(22_184_210, 6986) - // Standard Error: 10_584 - .saturating_add(Weight::from_parts(289_535, 0).saturating_mul(r.into())) + // Estimated: `3507` + // Minimum execution time: 20_974_000 picoseconds. + Weight::from_parts(21_582_135, 3507) + // Standard Error: 4_965 + .saturating_add(Weight::from_parts(294_566, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -134,11 +131,11 @@ impl WeightInfo for SubstrateWeight { fn demote_member(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `599 + r * (72 ±0)` - // Estimated: `14024` - // Minimum execution time: 30_249_000 picoseconds. - Weight::from_parts(32_702_502, 14024) - // Standard Error: 26_725 - .saturating_add(Weight::from_parts(651_139, 0).saturating_mul(r.into())) + // Estimated: `3519` + // Minimum execution time: 29_621_000 picoseconds. + Weight::from_parts(32_118_301, 3519) + // Standard Error: 27_596 + .saturating_add(Weight::from_parts(647_979, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -153,9 +150,9 @@ impl WeightInfo for SubstrateWeight { fn vote() -> Weight { // Proof Size summary in bytes: // Measured: `595` - // Estimated: `230816` - // Minimum execution time: 46_972_000 picoseconds. - Weight::from_parts(47_617_000, 230816) + // Estimated: `219984` + // Minimum execution time: 46_360_000 picoseconds. + Weight::from_parts(46_793_000, 219984) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -169,11 +166,11 @@ impl WeightInfo for SubstrateWeight { fn cleanup_poll(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `429 + n * (50 ±0)` - // Estimated: `8364 + n * (2540 ±0)` - // Minimum execution time: 15_301_000 picoseconds. - Weight::from_parts(19_308_613, 8364) - // Standard Error: 1_792 - .saturating_add(Weight::from_parts(1_015_251, 0).saturating_mul(n.into())) + // Estimated: `3795 + n * (2540 ±0)` + // Minimum execution time: 14_869_000 picoseconds. + Weight::from_parts(18_545_013, 3795) + // Standard Error: 1_376 + .saturating_add(Weight::from_parts(1_005_397, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) @@ -194,9 +191,9 @@ impl WeightInfo for () { fn add_member() -> Weight { // Proof Size summary in bytes: // Measured: `109` - // Estimated: `6986` - // Minimum execution time: 19_174_000 picoseconds. - Weight::from_parts(19_391_000, 6986) + // Estimated: `3507` + // Minimum execution time: 18_480_000 picoseconds. + Weight::from_parts(18_769_000, 3507) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -212,16 +209,16 @@ impl WeightInfo for () { fn remove_member(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `583 + r * (281 ±0)` - // Estimated: `14024 + r * (7547 ±0)` - // Minimum execution time: 30_972_000 picoseconds. - Weight::from_parts(35_526_205, 14024) - // Standard Error: 47_832 - .saturating_add(Weight::from_parts(12_838_739, 0).saturating_mul(r.into())) + // Estimated: `3519 + r * (2529 ±0)` + // Minimum execution time: 30_087_000 picoseconds. + Weight::from_parts(33_646_239, 3519) + // Standard Error: 22_498 + .saturating_add(Weight::from_parts(12_524_289, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 7547).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 2529).saturating_mul(r.into())) } /// Storage: RankedCollective Members (r:1 w:1) /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) @@ -235,11 +232,11 @@ impl WeightInfo for () { fn promote_member(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `281 + r * (17 ±0)` - // Estimated: `6986` - // Minimum execution time: 21_573_000 picoseconds. - Weight::from_parts(22_184_210, 6986) - // Standard Error: 10_584 - .saturating_add(Weight::from_parts(289_535, 0).saturating_mul(r.into())) + // Estimated: `3507` + // Minimum execution time: 20_974_000 picoseconds. + Weight::from_parts(21_582_135, 3507) + // Standard Error: 4_965 + .saturating_add(Weight::from_parts(294_566, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -255,11 +252,11 @@ impl WeightInfo for () { fn demote_member(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `599 + r * (72 ±0)` - // Estimated: `14024` - // Minimum execution time: 30_249_000 picoseconds. - Weight::from_parts(32_702_502, 14024) - // Standard Error: 26_725 - .saturating_add(Weight::from_parts(651_139, 0).saturating_mul(r.into())) + // Estimated: `3519` + // Minimum execution time: 29_621_000 picoseconds. + Weight::from_parts(32_118_301, 3519) + // Standard Error: 27_596 + .saturating_add(Weight::from_parts(647_979, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -274,9 +271,9 @@ impl WeightInfo for () { fn vote() -> Weight { // Proof Size summary in bytes: // Measured: `595` - // Estimated: `230816` - // Minimum execution time: 46_972_000 picoseconds. - Weight::from_parts(47_617_000, 230816) + // Estimated: `219984` + // Minimum execution time: 46_360_000 picoseconds. + Weight::from_parts(46_793_000, 219984) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -290,11 +287,11 @@ impl WeightInfo for () { fn cleanup_poll(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `429 + n * (50 ±0)` - // Estimated: `8364 + n * (2540 ±0)` - // Minimum execution time: 15_301_000 picoseconds. - Weight::from_parts(19_308_613, 8364) - // Standard Error: 1_792 - .saturating_add(Weight::from_parts(1_015_251, 0).saturating_mul(n.into())) + // Estimated: `3795 + n * (2540 ±0)` + // Minimum execution time: 14_869_000 picoseconds. + Weight::from_parts(18_545_013, 3795) + // Standard Error: 1_376 + .saturating_add(Weight::from_parts(1_005_397, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) diff --git a/frame/recovery/src/weights.rs b/frame/recovery/src/weights.rs index 8245b9606deee..97d4c8b87aa53 100644 --- a/frame/recovery/src/weights.rs +++ b/frame/recovery/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_recovery //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,9 +31,6 @@ // --steps=50 // --repeat=20 // --pallet=pallet_recovery -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -71,8 +68,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `281` // Estimated: `3545` - // Minimum execution time: 9_937_000 picoseconds. - Weight::from_parts(10_213_000, 3545) + // Minimum execution time: 10_405_000 picoseconds. + Weight::from_parts(10_807_000, 3545) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: Recovery Proxy (r:0 w:1) @@ -81,8 +78,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_704_000 picoseconds. - Weight::from_parts(9_997_000, 0) + // Minimum execution time: 11_198_000 picoseconds. + Weight::from_parts(11_459_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Recovery Recoverable (r:1 w:1) @@ -92,10 +89,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `175` // Estimated: `3816` - // Minimum execution time: 23_260_000 picoseconds. - Weight::from_parts(24_408_081, 3816) - // Standard Error: 3_086 - .saturating_add(Weight::from_parts(41_628, 0).saturating_mul(n.into())) + // Minimum execution time: 28_009_000 picoseconds. + Weight::from_parts(28_755_652, 3816) + // Standard Error: 3_536 + .saturating_add(Weight::from_parts(78_348, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -106,9 +103,9 @@ impl WeightInfo for SubstrateWeight { fn initiate_recovery() -> Weight { // Proof Size summary in bytes: // Measured: `272` - // Estimated: `7670` - // Minimum execution time: 28_148_000 picoseconds. - Weight::from_parts(28_577_000, 7670) + // Estimated: `3854` + // Minimum execution time: 31_233_000 picoseconds. + Weight::from_parts(31_508_000, 3854) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -120,11 +117,11 @@ impl WeightInfo for SubstrateWeight { fn vouch_recovery(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `360 + n * (64 ±0)` - // Estimated: `7670` - // Minimum execution time: 20_395_000 picoseconds. - Weight::from_parts(21_287_972, 7670) - // Standard Error: 4_464 - .saturating_add(Weight::from_parts(170_214, 0).saturating_mul(n.into())) + // Estimated: `3854` + // Minimum execution time: 20_542_000 picoseconds. + Weight::from_parts(21_224_065, 3854) + // Standard Error: 3_018 + .saturating_add(Weight::from_parts(171_994, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -138,11 +135,11 @@ impl WeightInfo for SubstrateWeight { fn claim_recovery(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `392 + n * (64 ±0)` - // Estimated: `11215` - // Minimum execution time: 24_902_000 picoseconds. - Weight::from_parts(25_662_621, 11215) - // Standard Error: 3_101 - .saturating_add(Weight::from_parts(60_748, 0).saturating_mul(n.into())) + // Estimated: `3854` + // Minimum execution time: 25_141_000 picoseconds. + Weight::from_parts(25_880_238, 3854) + // Standard Error: 3_156 + .saturating_add(Weight::from_parts(54_405, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -154,11 +151,11 @@ impl WeightInfo for SubstrateWeight { fn close_recovery(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `513 + n * (32 ±0)` - // Estimated: `7447` - // Minimum execution time: 30_071_000 picoseconds. - Weight::from_parts(30_727_760, 7447) - // Standard Error: 4_442 - .saturating_add(Weight::from_parts(98_153, 0).saturating_mul(n.into())) + // Estimated: `3854` + // Minimum execution time: 35_314_000 picoseconds. + Weight::from_parts(36_380_338, 3854) + // Standard Error: 7_396 + .saturating_add(Weight::from_parts(3_861, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -167,12 +164,14 @@ impl WeightInfo for SubstrateWeight { /// Storage: Recovery Recoverable (r:1 w:1) /// Proof: Recovery Recoverable (max_values: None, max_size: Some(351), added: 2826, mode: MaxEncodedLen) /// The range of component `n` is `[1, 9]`. - fn remove_recovery(_n: u32, ) -> Weight { + fn remove_recovery(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `270 + n * (32 ±0)` - // Estimated: `7670` - // Minimum execution time: 29_088_000 picoseconds. - Weight::from_parts(30_535_744, 7670) + // Estimated: `3854` + // Minimum execution time: 33_453_000 picoseconds. + Weight::from_parts(34_078_626, 3854) + // Standard Error: 2_563 + .saturating_add(Weight::from_parts(78_179, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -182,8 +181,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `281` // Estimated: `3545` - // Minimum execution time: 12_712_000 picoseconds. - Weight::from_parts(12_980_000, 3545) + // Minimum execution time: 12_196_000 picoseconds. + Weight::from_parts(12_580_000, 3545) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -197,8 +196,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `281` // Estimated: `3545` - // Minimum execution time: 9_937_000 picoseconds. - Weight::from_parts(10_213_000, 3545) + // Minimum execution time: 10_405_000 picoseconds. + Weight::from_parts(10_807_000, 3545) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: Recovery Proxy (r:0 w:1) @@ -207,8 +206,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_704_000 picoseconds. - Weight::from_parts(9_997_000, 0) + // Minimum execution time: 11_198_000 picoseconds. + Weight::from_parts(11_459_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Recovery Recoverable (r:1 w:1) @@ -218,10 +217,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `175` // Estimated: `3816` - // Minimum execution time: 23_260_000 picoseconds. - Weight::from_parts(24_408_081, 3816) - // Standard Error: 3_086 - .saturating_add(Weight::from_parts(41_628, 0).saturating_mul(n.into())) + // Minimum execution time: 28_009_000 picoseconds. + Weight::from_parts(28_755_652, 3816) + // Standard Error: 3_536 + .saturating_add(Weight::from_parts(78_348, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -232,9 +231,9 @@ impl WeightInfo for () { fn initiate_recovery() -> Weight { // Proof Size summary in bytes: // Measured: `272` - // Estimated: `7670` - // Minimum execution time: 28_148_000 picoseconds. - Weight::from_parts(28_577_000, 7670) + // Estimated: `3854` + // Minimum execution time: 31_233_000 picoseconds. + Weight::from_parts(31_508_000, 3854) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -246,11 +245,11 @@ impl WeightInfo for () { fn vouch_recovery(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `360 + n * (64 ±0)` - // Estimated: `7670` - // Minimum execution time: 20_395_000 picoseconds. - Weight::from_parts(21_287_972, 7670) - // Standard Error: 4_464 - .saturating_add(Weight::from_parts(170_214, 0).saturating_mul(n.into())) + // Estimated: `3854` + // Minimum execution time: 20_542_000 picoseconds. + Weight::from_parts(21_224_065, 3854) + // Standard Error: 3_018 + .saturating_add(Weight::from_parts(171_994, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -264,11 +263,11 @@ impl WeightInfo for () { fn claim_recovery(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `392 + n * (64 ±0)` - // Estimated: `11215` - // Minimum execution time: 24_902_000 picoseconds. - Weight::from_parts(25_662_621, 11215) - // Standard Error: 3_101 - .saturating_add(Weight::from_parts(60_748, 0).saturating_mul(n.into())) + // Estimated: `3854` + // Minimum execution time: 25_141_000 picoseconds. + Weight::from_parts(25_880_238, 3854) + // Standard Error: 3_156 + .saturating_add(Weight::from_parts(54_405, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -280,11 +279,11 @@ impl WeightInfo for () { fn close_recovery(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `513 + n * (32 ±0)` - // Estimated: `7447` - // Minimum execution time: 30_071_000 picoseconds. - Weight::from_parts(30_727_760, 7447) - // Standard Error: 4_442 - .saturating_add(Weight::from_parts(98_153, 0).saturating_mul(n.into())) + // Estimated: `3854` + // Minimum execution time: 35_314_000 picoseconds. + Weight::from_parts(36_380_338, 3854) + // Standard Error: 7_396 + .saturating_add(Weight::from_parts(3_861, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -293,12 +292,14 @@ impl WeightInfo for () { /// Storage: Recovery Recoverable (r:1 w:1) /// Proof: Recovery Recoverable (max_values: None, max_size: Some(351), added: 2826, mode: MaxEncodedLen) /// The range of component `n` is `[1, 9]`. - fn remove_recovery(_n: u32, ) -> Weight { + fn remove_recovery(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `270 + n * (32 ±0)` - // Estimated: `7670` - // Minimum execution time: 29_088_000 picoseconds. - Weight::from_parts(30_535_744, 7670) + // Estimated: `3854` + // Minimum execution time: 33_453_000 picoseconds. + Weight::from_parts(34_078_626, 3854) + // Standard Error: 2_563 + .saturating_add(Weight::from_parts(78_179, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -308,8 +309,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `281` // Estimated: `3545` - // Minimum execution time: 12_712_000 picoseconds. - Weight::from_parts(12_980_000, 3545) + // Minimum execution time: 12_196_000 picoseconds. + Weight::from_parts(12_580_000, 3545) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/frame/referenda/src/weights.rs b/frame/referenda/src/weights.rs index 3ac0f54ed8307..464e60dc581e6 100644 --- a/frame/referenda/src/weights.rs +++ b/frame/referenda/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_referenda //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,9 +31,6 @@ // --steps=50 // --repeat=20 // --pallet=pallet_referenda -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -95,9 +92,9 @@ impl WeightInfo for SubstrateWeight { fn submit() -> Weight { // Proof Size summary in bytes: // Measured: `220` - // Estimated: `111976` - // Minimum execution time: 36_851_000 picoseconds. - Weight::from_parts(37_183_000, 111976) + // Estimated: `110487` + // Minimum execution time: 42_285_000 picoseconds. + Weight::from_parts(42_646_000, 110487) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -108,9 +105,9 @@ impl WeightInfo for SubstrateWeight { fn place_decision_deposit_preparing() -> Weight { // Proof Size summary in bytes: // Measured: `473` - // Estimated: `223815` - // Minimum execution time: 49_435_000 picoseconds. - Weight::from_parts(50_056_000, 223815) + // Estimated: `219984` + // Minimum execution time: 53_455_000 picoseconds. + Weight::from_parts(54_034_000, 219984) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -123,9 +120,9 @@ impl WeightInfo for SubstrateWeight { fn place_decision_deposit_queued() -> Weight { // Proof Size summary in bytes: // Measured: `3107` - // Estimated: `12787` - // Minimum execution time: 47_061_000 picoseconds. - Weight::from_parts(47_579_000, 12787) + // Estimated: `5477` + // Minimum execution time: 50_138_000 picoseconds. + Weight::from_parts(50_449_000, 5477) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -138,9 +135,9 @@ impl WeightInfo for SubstrateWeight { fn place_decision_deposit_not_queued() -> Weight { // Proof Size summary in bytes: // Measured: `3127` - // Estimated: `12787` - // Minimum execution time: 46_513_000 picoseconds. - Weight::from_parts(47_212_000, 12787) + // Estimated: `5477` + // Minimum execution time: 49_707_000 picoseconds. + Weight::from_parts(50_246_000, 5477) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -153,9 +150,9 @@ impl WeightInfo for SubstrateWeight { fn place_decision_deposit_passing() -> Weight { // Proof Size summary in bytes: // Measured: `473` - // Estimated: `227294` - // Minimum execution time: 59_255_000 picoseconds. - Weight::from_parts(60_114_000, 227294) + // Estimated: `219984` + // Minimum execution time: 62_880_000 picoseconds. + Weight::from_parts(63_579_000, 219984) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -168,9 +165,9 @@ impl WeightInfo for SubstrateWeight { fn place_decision_deposit_failing() -> Weight { // Proof Size summary in bytes: // Measured: `473` - // Estimated: `227294` - // Minimum execution time: 57_927_000 picoseconds. - Weight::from_parts(58_625_000, 227294) + // Estimated: `219984` + // Minimum execution time: 60_827_000 picoseconds. + Weight::from_parts(61_392_000, 219984) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -180,8 +177,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3831` - // Minimum execution time: 27_186_000 picoseconds. - Weight::from_parts(27_551_000, 3831) + // Minimum execution time: 31_991_000 picoseconds. + Weight::from_parts(32_474_000, 3831) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -191,8 +188,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `341` // Estimated: `3831` - // Minimum execution time: 27_339_000 picoseconds. - Weight::from_parts(27_828_000, 3831) + // Minimum execution time: 32_162_000 picoseconds. + Weight::from_parts(32_776_000, 3831) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -203,9 +200,9 @@ impl WeightInfo for SubstrateWeight { fn cancel() -> Weight { // Proof Size summary in bytes: // Measured: `381` - // Estimated: `223815` - // Minimum execution time: 37_081_000 picoseconds. - Weight::from_parts(38_110_000, 223815) + // Estimated: `219984` + // Minimum execution time: 37_493_000 picoseconds. + Weight::from_parts(37_979_000, 219984) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -218,9 +215,9 @@ impl WeightInfo for SubstrateWeight { fn kill() -> Weight { // Proof Size summary in bytes: // Measured: `622` - // Estimated: `227332` - // Minimum execution time: 70_195_000 picoseconds. - Weight::from_parts(71_451_000, 227332) + // Estimated: `219984` + // Minimum execution time: 80_095_000 picoseconds. + Weight::from_parts(80_831_000, 219984) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -231,9 +228,9 @@ impl WeightInfo for SubstrateWeight { fn one_fewer_deciding_queue_empty() -> Weight { // Proof Size summary in bytes: // Measured: `174` - // Estimated: `8956` - // Minimum execution time: 10_748_000 picoseconds. - Weight::from_parts(10_912_000, 8956) + // Estimated: `5477` + // Minimum execution time: 10_906_000 picoseconds. + Weight::from_parts(11_055_000, 5477) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -246,9 +243,9 @@ impl WeightInfo for SubstrateWeight { fn one_fewer_deciding_failing() -> Weight { // Proof Size summary in bytes: // Measured: `4567` - // Estimated: `229292` - // Minimum execution time: 89_144_000 picoseconds. - Weight::from_parts(90_552_000, 229292) + // Estimated: `219984` + // Minimum execution time: 90_747_000 picoseconds. + Weight::from_parts(91_407_000, 219984) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -261,9 +258,9 @@ impl WeightInfo for SubstrateWeight { fn one_fewer_deciding_passing() -> Weight { // Proof Size summary in bytes: // Measured: `4567` - // Estimated: `229292` - // Minimum execution time: 92_164_000 picoseconds. - Weight::from_parts(92_947_000, 229292) + // Estimated: `219984` + // Minimum execution time: 93_615_000 picoseconds. + Weight::from_parts(94_245_000, 219984) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -276,9 +273,9 @@ impl WeightInfo for SubstrateWeight { fn nudge_referendum_requeued_insertion() -> Weight { // Proof Size summary in bytes: // Measured: `4588` - // Estimated: `119795` - // Minimum execution time: 59_212_000 picoseconds. - Weight::from_parts(59_843_000, 119795) + // Estimated: `110487` + // Minimum execution time: 60_945_000 picoseconds. + Weight::from_parts(61_246_000, 110487) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -291,9 +288,9 @@ impl WeightInfo for SubstrateWeight { fn nudge_referendum_requeued_slide() -> Weight { // Proof Size summary in bytes: // Measured: `4574` - // Estimated: `119795` - // Minimum execution time: 59_049_000 picoseconds. - Weight::from_parts(59_760_000, 119795) + // Estimated: `110487` + // Minimum execution time: 60_105_000 picoseconds. + Weight::from_parts(60_544_000, 110487) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -308,9 +305,9 @@ impl WeightInfo for SubstrateWeight { fn nudge_referendum_queued() -> Weight { // Proof Size summary in bytes: // Measured: `4548` - // Estimated: `123274` - // Minimum execution time: 61_774_000 picoseconds. - Weight::from_parts(62_480_000, 123274) + // Estimated: `110487` + // Minimum execution time: 62_251_000 picoseconds. + Weight::from_parts(62_952_000, 110487) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -325,9 +322,9 @@ impl WeightInfo for SubstrateWeight { fn nudge_referendum_not_queued() -> Weight { // Proof Size summary in bytes: // Measured: `4582` - // Estimated: `123274` - // Minimum execution time: 61_605_000 picoseconds. - Weight::from_parts(62_385_000, 123274) + // Estimated: `110487` + // Minimum execution time: 61_527_000 picoseconds. + Weight::from_parts(62_082_000, 110487) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -338,9 +335,9 @@ impl WeightInfo for SubstrateWeight { fn nudge_referendum_no_deposit() -> Weight { // Proof Size summary in bytes: // Measured: `333` - // Estimated: `114318` - // Minimum execution time: 24_423_000 picoseconds. - Weight::from_parts(24_747_000, 114318) + // Estimated: `110487` + // Minimum execution time: 24_897_000 picoseconds. + Weight::from_parts(25_213_000, 110487) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -351,9 +348,9 @@ impl WeightInfo for SubstrateWeight { fn nudge_referendum_preparing() -> Weight { // Proof Size summary in bytes: // Measured: `381` - // Estimated: `114318` - // Minimum execution time: 24_487_000 picoseconds. - Weight::from_parts(24_941_000, 114318) + // Estimated: `110487` + // Minimum execution time: 25_077_000 picoseconds. + Weight::from_parts(25_385_000, 110487) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -363,8 +360,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `278` // Estimated: `3831` - // Minimum execution time: 17_454_000 picoseconds. - Weight::from_parts(17_697_000, 3831) + // Minimum execution time: 17_930_000 picoseconds. + Weight::from_parts(18_112_000, 3831) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -377,9 +374,9 @@ impl WeightInfo for SubstrateWeight { fn nudge_referendum_begin_deciding_failing() -> Weight { // Proof Size summary in bytes: // Measured: `381` - // Estimated: `117797` - // Minimum execution time: 34_721_000 picoseconds. - Weight::from_parts(35_295_000, 117797) + // Estimated: `110487` + // Minimum execution time: 34_405_000 picoseconds. + Weight::from_parts(34_698_000, 110487) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -392,9 +389,9 @@ impl WeightInfo for SubstrateWeight { fn nudge_referendum_begin_deciding_passing() -> Weight { // Proof Size summary in bytes: // Measured: `381` - // Estimated: `117797` - // Minimum execution time: 36_587_000 picoseconds. - Weight::from_parts(37_095_000, 117797) + // Estimated: `110487` + // Minimum execution time: 37_313_000 picoseconds. + Weight::from_parts(37_807_000, 110487) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -405,9 +402,9 @@ impl WeightInfo for SubstrateWeight { fn nudge_referendum_begin_confirming() -> Weight { // Proof Size summary in bytes: // Measured: `434` - // Estimated: `114318` - // Minimum execution time: 30_003_000 picoseconds. - Weight::from_parts(30_541_000, 114318) + // Estimated: `110487` + // Minimum execution time: 30_552_000 picoseconds. + Weight::from_parts(30_817_000, 110487) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -418,9 +415,9 @@ impl WeightInfo for SubstrateWeight { fn nudge_referendum_end_confirming() -> Weight { // Proof Size summary in bytes: // Measured: `417` - // Estimated: `114318` - // Minimum execution time: 30_479_000 picoseconds. - Weight::from_parts(30_900_000, 114318) + // Estimated: `110487` + // Minimum execution time: 31_100_000 picoseconds. + Weight::from_parts(31_696_000, 110487) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -431,9 +428,9 @@ impl WeightInfo for SubstrateWeight { fn nudge_referendum_continue_not_confirming() -> Weight { // Proof Size summary in bytes: // Measured: `434` - // Estimated: `114318` - // Minimum execution time: 27_657_000 picoseconds. - Weight::from_parts(28_054_000, 114318) + // Estimated: `110487` + // Minimum execution time: 28_777_000 picoseconds. + Weight::from_parts(29_188_000, 110487) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -444,9 +441,9 @@ impl WeightInfo for SubstrateWeight { fn nudge_referendum_continue_confirming() -> Weight { // Proof Size summary in bytes: // Measured: `438` - // Estimated: `114318` - // Minimum execution time: 26_713_000 picoseconds. - Weight::from_parts(27_284_000, 114318) + // Estimated: `110487` + // Minimum execution time: 26_986_000 picoseconds. + Weight::from_parts(27_283_000, 110487) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -459,9 +456,9 @@ impl WeightInfo for SubstrateWeight { fn nudge_referendum_approved() -> Weight { // Proof Size summary in bytes: // Measured: `438` - // Estimated: `227328` - // Minimum execution time: 42_374_000 picoseconds. - Weight::from_parts(43_142_000, 227328) + // Estimated: `219984` + // Minimum execution time: 43_538_000 picoseconds. + Weight::from_parts(44_671_000, 219984) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -472,9 +469,9 @@ impl WeightInfo for SubstrateWeight { fn nudge_referendum_rejected() -> Weight { // Proof Size summary in bytes: // Measured: `434` - // Estimated: `114318` - // Minimum execution time: 30_213_000 picoseconds. - Weight::from_parts(30_633_000, 114318) + // Estimated: `110487` + // Minimum execution time: 30_559_000 picoseconds. + Weight::from_parts(31_294_000, 110487) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -487,9 +484,9 @@ impl WeightInfo for SubstrateWeight { fn set_some_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `422` - // Estimated: `7387` - // Minimum execution time: 20_887_000 picoseconds. - Weight::from_parts(21_242_000, 7387) + // Estimated: `3831` + // Minimum execution time: 21_196_000 picoseconds. + Weight::from_parts(21_593_000, 3831) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -500,9 +497,9 @@ impl WeightInfo for SubstrateWeight { fn clear_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `355` - // Estimated: `7348` - // Minimum execution time: 18_702_000 picoseconds. - Weight::from_parts(18_880_000, 7348) + // Estimated: `3831` + // Minimum execution time: 18_827_000 picoseconds. + Weight::from_parts(19_171_000, 3831) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -519,9 +516,9 @@ impl WeightInfo for () { fn submit() -> Weight { // Proof Size summary in bytes: // Measured: `220` - // Estimated: `111976` - // Minimum execution time: 36_851_000 picoseconds. - Weight::from_parts(37_183_000, 111976) + // Estimated: `110487` + // Minimum execution time: 42_285_000 picoseconds. + Weight::from_parts(42_646_000, 110487) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -532,9 +529,9 @@ impl WeightInfo for () { fn place_decision_deposit_preparing() -> Weight { // Proof Size summary in bytes: // Measured: `473` - // Estimated: `223815` - // Minimum execution time: 49_435_000 picoseconds. - Weight::from_parts(50_056_000, 223815) + // Estimated: `219984` + // Minimum execution time: 53_455_000 picoseconds. + Weight::from_parts(54_034_000, 219984) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -547,9 +544,9 @@ impl WeightInfo for () { fn place_decision_deposit_queued() -> Weight { // Proof Size summary in bytes: // Measured: `3107` - // Estimated: `12787` - // Minimum execution time: 47_061_000 picoseconds. - Weight::from_parts(47_579_000, 12787) + // Estimated: `5477` + // Minimum execution time: 50_138_000 picoseconds. + Weight::from_parts(50_449_000, 5477) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -562,9 +559,9 @@ impl WeightInfo for () { fn place_decision_deposit_not_queued() -> Weight { // Proof Size summary in bytes: // Measured: `3127` - // Estimated: `12787` - // Minimum execution time: 46_513_000 picoseconds. - Weight::from_parts(47_212_000, 12787) + // Estimated: `5477` + // Minimum execution time: 49_707_000 picoseconds. + Weight::from_parts(50_246_000, 5477) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -577,9 +574,9 @@ impl WeightInfo for () { fn place_decision_deposit_passing() -> Weight { // Proof Size summary in bytes: // Measured: `473` - // Estimated: `227294` - // Minimum execution time: 59_255_000 picoseconds. - Weight::from_parts(60_114_000, 227294) + // Estimated: `219984` + // Minimum execution time: 62_880_000 picoseconds. + Weight::from_parts(63_579_000, 219984) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -592,9 +589,9 @@ impl WeightInfo for () { fn place_decision_deposit_failing() -> Weight { // Proof Size summary in bytes: // Measured: `473` - // Estimated: `227294` - // Minimum execution time: 57_927_000 picoseconds. - Weight::from_parts(58_625_000, 227294) + // Estimated: `219984` + // Minimum execution time: 60_827_000 picoseconds. + Weight::from_parts(61_392_000, 219984) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -604,8 +601,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3831` - // Minimum execution time: 27_186_000 picoseconds. - Weight::from_parts(27_551_000, 3831) + // Minimum execution time: 31_991_000 picoseconds. + Weight::from_parts(32_474_000, 3831) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -615,8 +612,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `341` // Estimated: `3831` - // Minimum execution time: 27_339_000 picoseconds. - Weight::from_parts(27_828_000, 3831) + // Minimum execution time: 32_162_000 picoseconds. + Weight::from_parts(32_776_000, 3831) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -627,9 +624,9 @@ impl WeightInfo for () { fn cancel() -> Weight { // Proof Size summary in bytes: // Measured: `381` - // Estimated: `223815` - // Minimum execution time: 37_081_000 picoseconds. - Weight::from_parts(38_110_000, 223815) + // Estimated: `219984` + // Minimum execution time: 37_493_000 picoseconds. + Weight::from_parts(37_979_000, 219984) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -642,9 +639,9 @@ impl WeightInfo for () { fn kill() -> Weight { // Proof Size summary in bytes: // Measured: `622` - // Estimated: `227332` - // Minimum execution time: 70_195_000 picoseconds. - Weight::from_parts(71_451_000, 227332) + // Estimated: `219984` + // Minimum execution time: 80_095_000 picoseconds. + Weight::from_parts(80_831_000, 219984) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -655,9 +652,9 @@ impl WeightInfo for () { fn one_fewer_deciding_queue_empty() -> Weight { // Proof Size summary in bytes: // Measured: `174` - // Estimated: `8956` - // Minimum execution time: 10_748_000 picoseconds. - Weight::from_parts(10_912_000, 8956) + // Estimated: `5477` + // Minimum execution time: 10_906_000 picoseconds. + Weight::from_parts(11_055_000, 5477) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -670,9 +667,9 @@ impl WeightInfo for () { fn one_fewer_deciding_failing() -> Weight { // Proof Size summary in bytes: // Measured: `4567` - // Estimated: `229292` - // Minimum execution time: 89_144_000 picoseconds. - Weight::from_parts(90_552_000, 229292) + // Estimated: `219984` + // Minimum execution time: 90_747_000 picoseconds. + Weight::from_parts(91_407_000, 219984) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -685,9 +682,9 @@ impl WeightInfo for () { fn one_fewer_deciding_passing() -> Weight { // Proof Size summary in bytes: // Measured: `4567` - // Estimated: `229292` - // Minimum execution time: 92_164_000 picoseconds. - Weight::from_parts(92_947_000, 229292) + // Estimated: `219984` + // Minimum execution time: 93_615_000 picoseconds. + Weight::from_parts(94_245_000, 219984) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -700,9 +697,9 @@ impl WeightInfo for () { fn nudge_referendum_requeued_insertion() -> Weight { // Proof Size summary in bytes: // Measured: `4588` - // Estimated: `119795` - // Minimum execution time: 59_212_000 picoseconds. - Weight::from_parts(59_843_000, 119795) + // Estimated: `110487` + // Minimum execution time: 60_945_000 picoseconds. + Weight::from_parts(61_246_000, 110487) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -715,9 +712,9 @@ impl WeightInfo for () { fn nudge_referendum_requeued_slide() -> Weight { // Proof Size summary in bytes: // Measured: `4574` - // Estimated: `119795` - // Minimum execution time: 59_049_000 picoseconds. - Weight::from_parts(59_760_000, 119795) + // Estimated: `110487` + // Minimum execution time: 60_105_000 picoseconds. + Weight::from_parts(60_544_000, 110487) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -732,9 +729,9 @@ impl WeightInfo for () { fn nudge_referendum_queued() -> Weight { // Proof Size summary in bytes: // Measured: `4548` - // Estimated: `123274` - // Minimum execution time: 61_774_000 picoseconds. - Weight::from_parts(62_480_000, 123274) + // Estimated: `110487` + // Minimum execution time: 62_251_000 picoseconds. + Weight::from_parts(62_952_000, 110487) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -749,9 +746,9 @@ impl WeightInfo for () { fn nudge_referendum_not_queued() -> Weight { // Proof Size summary in bytes: // Measured: `4582` - // Estimated: `123274` - // Minimum execution time: 61_605_000 picoseconds. - Weight::from_parts(62_385_000, 123274) + // Estimated: `110487` + // Minimum execution time: 61_527_000 picoseconds. + Weight::from_parts(62_082_000, 110487) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -762,9 +759,9 @@ impl WeightInfo for () { fn nudge_referendum_no_deposit() -> Weight { // Proof Size summary in bytes: // Measured: `333` - // Estimated: `114318` - // Minimum execution time: 24_423_000 picoseconds. - Weight::from_parts(24_747_000, 114318) + // Estimated: `110487` + // Minimum execution time: 24_897_000 picoseconds. + Weight::from_parts(25_213_000, 110487) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -775,9 +772,9 @@ impl WeightInfo for () { fn nudge_referendum_preparing() -> Weight { // Proof Size summary in bytes: // Measured: `381` - // Estimated: `114318` - // Minimum execution time: 24_487_000 picoseconds. - Weight::from_parts(24_941_000, 114318) + // Estimated: `110487` + // Minimum execution time: 25_077_000 picoseconds. + Weight::from_parts(25_385_000, 110487) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -787,8 +784,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `278` // Estimated: `3831` - // Minimum execution time: 17_454_000 picoseconds. - Weight::from_parts(17_697_000, 3831) + // Minimum execution time: 17_930_000 picoseconds. + Weight::from_parts(18_112_000, 3831) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -801,9 +798,9 @@ impl WeightInfo for () { fn nudge_referendum_begin_deciding_failing() -> Weight { // Proof Size summary in bytes: // Measured: `381` - // Estimated: `117797` - // Minimum execution time: 34_721_000 picoseconds. - Weight::from_parts(35_295_000, 117797) + // Estimated: `110487` + // Minimum execution time: 34_405_000 picoseconds. + Weight::from_parts(34_698_000, 110487) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -816,9 +813,9 @@ impl WeightInfo for () { fn nudge_referendum_begin_deciding_passing() -> Weight { // Proof Size summary in bytes: // Measured: `381` - // Estimated: `117797` - // Minimum execution time: 36_587_000 picoseconds. - Weight::from_parts(37_095_000, 117797) + // Estimated: `110487` + // Minimum execution time: 37_313_000 picoseconds. + Weight::from_parts(37_807_000, 110487) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -829,9 +826,9 @@ impl WeightInfo for () { fn nudge_referendum_begin_confirming() -> Weight { // Proof Size summary in bytes: // Measured: `434` - // Estimated: `114318` - // Minimum execution time: 30_003_000 picoseconds. - Weight::from_parts(30_541_000, 114318) + // Estimated: `110487` + // Minimum execution time: 30_552_000 picoseconds. + Weight::from_parts(30_817_000, 110487) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -842,9 +839,9 @@ impl WeightInfo for () { fn nudge_referendum_end_confirming() -> Weight { // Proof Size summary in bytes: // Measured: `417` - // Estimated: `114318` - // Minimum execution time: 30_479_000 picoseconds. - Weight::from_parts(30_900_000, 114318) + // Estimated: `110487` + // Minimum execution time: 31_100_000 picoseconds. + Weight::from_parts(31_696_000, 110487) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -855,9 +852,9 @@ impl WeightInfo for () { fn nudge_referendum_continue_not_confirming() -> Weight { // Proof Size summary in bytes: // Measured: `434` - // Estimated: `114318` - // Minimum execution time: 27_657_000 picoseconds. - Weight::from_parts(28_054_000, 114318) + // Estimated: `110487` + // Minimum execution time: 28_777_000 picoseconds. + Weight::from_parts(29_188_000, 110487) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -868,9 +865,9 @@ impl WeightInfo for () { fn nudge_referendum_continue_confirming() -> Weight { // Proof Size summary in bytes: // Measured: `438` - // Estimated: `114318` - // Minimum execution time: 26_713_000 picoseconds. - Weight::from_parts(27_284_000, 114318) + // Estimated: `110487` + // Minimum execution time: 26_986_000 picoseconds. + Weight::from_parts(27_283_000, 110487) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -883,9 +880,9 @@ impl WeightInfo for () { fn nudge_referendum_approved() -> Weight { // Proof Size summary in bytes: // Measured: `438` - // Estimated: `227328` - // Minimum execution time: 42_374_000 picoseconds. - Weight::from_parts(43_142_000, 227328) + // Estimated: `219984` + // Minimum execution time: 43_538_000 picoseconds. + Weight::from_parts(44_671_000, 219984) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -896,9 +893,9 @@ impl WeightInfo for () { fn nudge_referendum_rejected() -> Weight { // Proof Size summary in bytes: // Measured: `434` - // Estimated: `114318` - // Minimum execution time: 30_213_000 picoseconds. - Weight::from_parts(30_633_000, 114318) + // Estimated: `110487` + // Minimum execution time: 30_559_000 picoseconds. + Weight::from_parts(31_294_000, 110487) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -911,9 +908,9 @@ impl WeightInfo for () { fn set_some_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `422` - // Estimated: `7387` - // Minimum execution time: 20_887_000 picoseconds. - Weight::from_parts(21_242_000, 7387) + // Estimated: `3831` + // Minimum execution time: 21_196_000 picoseconds. + Weight::from_parts(21_593_000, 3831) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -924,9 +921,9 @@ impl WeightInfo for () { fn clear_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `355` - // Estimated: `7348` - // Minimum execution time: 18_702_000 picoseconds. - Weight::from_parts(18_880_000, 7348) + // Estimated: `3831` + // Minimum execution time: 18_827_000 picoseconds. + Weight::from_parts(19_171_000, 3831) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/frame/remark/src/weights.rs b/frame/remark/src/weights.rs index bb2e91b5dfbd0..9aa56eb339fcb 100644 --- a/frame/remark/src/weights.rs +++ b/frame/remark/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_remark //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,9 +31,6 @@ // --steps=50 // --repeat=20 // --pallet=pallet_remark -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -62,10 +59,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_284_000 picoseconds. - Weight::from_parts(4_054_843, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(1_094, 0).saturating_mul(l.into())) + // Minimum execution time: 9_301_000 picoseconds. + Weight::from_parts(2_516_065, 0) + // Standard Error: 1 + .saturating_add(Weight::from_parts(1_089, 0).saturating_mul(l.into())) } } @@ -76,9 +73,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_284_000 picoseconds. - Weight::from_parts(4_054_843, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(1_094, 0).saturating_mul(l.into())) + // Minimum execution time: 9_301_000 picoseconds. + Weight::from_parts(2_516_065, 0) + // Standard Error: 1 + .saturating_add(Weight::from_parts(1_089, 0).saturating_mul(l.into())) } } diff --git a/frame/salary/src/weights.rs b/frame/salary/src/weights.rs index 7195a144a65a3..074bff4da170d 100644 --- a/frame/salary/src/weights.rs +++ b/frame/salary/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_salary //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,9 +31,6 @@ // --steps=50 // --repeat=20 // --pallet=pallet_salary -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -69,8 +66,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `4` // Estimated: `1541` - // Minimum execution time: 11_732_000 picoseconds. - Weight::from_parts(12_162_000, 1541) + // Minimum execution time: 11_785_000 picoseconds. + Weight::from_parts(12_086_000, 1541) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -80,8 +77,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `86` // Estimated: `1541` - // Minimum execution time: 12_966_000 picoseconds. - Weight::from_parts(13_443_000, 1541) + // Minimum execution time: 12_721_000 picoseconds. + Weight::from_parts(13_033_000, 1541) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -94,9 +91,9 @@ impl WeightInfo for SubstrateWeight { fn induct() -> Weight { // Proof Size summary in bytes: // Measured: `362` - // Estimated: `8591` - // Minimum execution time: 20_467_000 picoseconds. - Weight::from_parts(20_782_000, 8591) + // Estimated: `3543` + // Minimum execution time: 19_516_000 picoseconds. + Weight::from_parts(19_938_000, 3543) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -109,9 +106,9 @@ impl WeightInfo for SubstrateWeight { fn register() -> Weight { // Proof Size summary in bytes: // Measured: `429` - // Estimated: `8591` - // Minimum execution time: 23_547_000 picoseconds. - Weight::from_parts(23_911_000, 8591) + // Estimated: `3543` + // Minimum execution time: 23_145_000 picoseconds. + Weight::from_parts(23_804_000, 3543) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -124,9 +121,9 @@ impl WeightInfo for SubstrateWeight { fn payout() -> Weight { // Proof Size summary in bytes: // Measured: `429` - // Estimated: `8591` - // Minimum execution time: 47_145_000 picoseconds. - Weight::from_parts(47_778_000, 8591) + // Estimated: `3543` + // Minimum execution time: 62_187_000 picoseconds. + Weight::from_parts(63_016_000, 3543) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -141,9 +138,9 @@ impl WeightInfo for SubstrateWeight { fn payout_other() -> Weight { // Proof Size summary in bytes: // Measured: `429` - // Estimated: `12184` - // Minimum execution time: 48_763_000 picoseconds. - Weight::from_parts(49_853_000, 12184) + // Estimated: `3593` + // Minimum execution time: 63_828_000 picoseconds. + Weight::from_parts(64_791_000, 3593) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -154,9 +151,9 @@ impl WeightInfo for SubstrateWeight { fn check_payment() -> Weight { // Proof Size summary in bytes: // Measured: `170` - // Estimated: `5084` - // Minimum execution time: 12_825_000 picoseconds. - Weight::from_parts(13_143_000, 5084) + // Estimated: `3543` + // Minimum execution time: 12_911_000 picoseconds. + Weight::from_parts(13_079_000, 3543) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -170,8 +167,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `4` // Estimated: `1541` - // Minimum execution time: 11_732_000 picoseconds. - Weight::from_parts(12_162_000, 1541) + // Minimum execution time: 11_785_000 picoseconds. + Weight::from_parts(12_086_000, 1541) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -181,8 +178,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `86` // Estimated: `1541` - // Minimum execution time: 12_966_000 picoseconds. - Weight::from_parts(13_443_000, 1541) + // Minimum execution time: 12_721_000 picoseconds. + Weight::from_parts(13_033_000, 1541) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -195,9 +192,9 @@ impl WeightInfo for () { fn induct() -> Weight { // Proof Size summary in bytes: // Measured: `362` - // Estimated: `8591` - // Minimum execution time: 20_467_000 picoseconds. - Weight::from_parts(20_782_000, 8591) + // Estimated: `3543` + // Minimum execution time: 19_516_000 picoseconds. + Weight::from_parts(19_938_000, 3543) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -210,9 +207,9 @@ impl WeightInfo for () { fn register() -> Weight { // Proof Size summary in bytes: // Measured: `429` - // Estimated: `8591` - // Minimum execution time: 23_547_000 picoseconds. - Weight::from_parts(23_911_000, 8591) + // Estimated: `3543` + // Minimum execution time: 23_145_000 picoseconds. + Weight::from_parts(23_804_000, 3543) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -225,9 +222,9 @@ impl WeightInfo for () { fn payout() -> Weight { // Proof Size summary in bytes: // Measured: `429` - // Estimated: `8591` - // Minimum execution time: 47_145_000 picoseconds. - Weight::from_parts(47_778_000, 8591) + // Estimated: `3543` + // Minimum execution time: 62_187_000 picoseconds. + Weight::from_parts(63_016_000, 3543) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -242,9 +239,9 @@ impl WeightInfo for () { fn payout_other() -> Weight { // Proof Size summary in bytes: // Measured: `429` - // Estimated: `12184` - // Minimum execution time: 48_763_000 picoseconds. - Weight::from_parts(49_853_000, 12184) + // Estimated: `3593` + // Minimum execution time: 63_828_000 picoseconds. + Weight::from_parts(64_791_000, 3593) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -255,9 +252,9 @@ impl WeightInfo for () { fn check_payment() -> Weight { // Proof Size summary in bytes: // Measured: `170` - // Estimated: `5084` - // Minimum execution time: 12_825_000 picoseconds. - Weight::from_parts(13_143_000, 5084) + // Estimated: `3543` + // Minimum execution time: 12_911_000 picoseconds. + Weight::from_parts(13_079_000, 3543) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } diff --git a/frame/scheduler/src/weights.rs b/frame/scheduler/src/weights.rs index bccb502656a72..897363f134e7b 100644 --- a/frame/scheduler/src/weights.rs +++ b/frame/scheduler/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_scheduler //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,9 +31,6 @@ // --steps=50 // --repeat=20 // --pallet=pallet_scheduler -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -74,8 +71,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `31` // Estimated: `1489` - // Minimum execution time: 3_965_000 picoseconds. - Weight::from_parts(4_126_000, 1489) + // Minimum execution time: 3_776_000 picoseconds. + Weight::from_parts(3_992_000, 1489) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -86,10 +83,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `81 + s * (177 ±0)` // Estimated: `110487` - // Minimum execution time: 3_662_000 picoseconds. - Weight::from_parts(8_746_597, 110487) - // Standard Error: 754 - .saturating_add(Weight::from_parts(309_350, 0).saturating_mul(s.into())) + // Minimum execution time: 3_418_000 picoseconds. + Weight::from_parts(8_606_012, 110487) + // Standard Error: 769 + .saturating_add(Weight::from_parts(309_376, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -97,8 +94,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_807_000 picoseconds. - Weight::from_parts(5_963_000, 0) + // Minimum execution time: 5_624_000 picoseconds. + Weight::from_parts(5_758_000, 0) } /// Storage: Preimage PreimageFor (r:1 w:1) /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: Measured) @@ -108,11 +105,11 @@ impl WeightInfo for SubstrateWeight { fn service_task_fetched(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `179 + s * (1 ±0)` - // Estimated: `7200 + s * (1 ±0)` - // Minimum execution time: 20_188_000 picoseconds. - Weight::from_parts(20_422_000, 7200) - // Standard Error: 1 - .saturating_add(Weight::from_parts(1_143, 0).saturating_mul(s.into())) + // Estimated: `3644 + s * (1 ±0)` + // Minimum execution time: 20_150_000 picoseconds. + Weight::from_parts(20_271_000, 3644) + // Standard Error: 0 + .saturating_add(Weight::from_parts(1_132, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(s.into())) @@ -123,30 +120,30 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_787_000 picoseconds. - Weight::from_parts(8_046_000, 0) + // Minimum execution time: 7_451_000 picoseconds. + Weight::from_parts(7_693_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } fn service_task_periodic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_730_000 picoseconds. - Weight::from_parts(5_901_000, 0) + // Minimum execution time: 5_477_000 picoseconds. + Weight::from_parts(5_733_000, 0) } fn execute_dispatch_signed() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_569_000 picoseconds. - Weight::from_parts(2_710_000, 0) + // Minimum execution time: 2_675_000 picoseconds. + Weight::from_parts(2_870_000, 0) } fn execute_dispatch_unsigned() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_611_000 picoseconds. - Weight::from_parts(2_765_000, 0) + // Minimum execution time: 2_697_000 picoseconds. + Weight::from_parts(2_807_000, 0) } /// Storage: Scheduler Agenda (r:1 w:1) /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) @@ -155,10 +152,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `81 + s * (177 ±0)` // Estimated: `110487` - // Minimum execution time: 14_237_000 picoseconds. - Weight::from_parts(18_553_929, 110487) - // Standard Error: 757 - .saturating_add(Weight::from_parts(327_347, 0).saturating_mul(s.into())) + // Minimum execution time: 13_921_000 picoseconds. + Weight::from_parts(18_717_223, 110487) + // Standard Error: 771 + .saturating_add(Weight::from_parts(333_102, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -171,10 +168,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `81 + s * (177 ±0)` // Estimated: `110487` - // Minimum execution time: 18_003_000 picoseconds. - Weight::from_parts(19_521_283, 110487) - // Standard Error: 901 - .saturating_add(Weight::from_parts(496_401, 0).saturating_mul(s.into())) + // Minimum execution time: 17_552_000 picoseconds. + Weight::from_parts(19_006_016, 110487) + // Standard Error: 1_115 + .saturating_add(Weight::from_parts(495_979, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -186,11 +183,11 @@ impl WeightInfo for SubstrateWeight { fn schedule_named(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `596 + s * (178 ±0)` - // Estimated: `114000` - // Minimum execution time: 17_713_000 picoseconds. - Weight::from_parts(24_442_945, 114000) - // Standard Error: 764 - .saturating_add(Weight::from_parts(330_307, 0).saturating_mul(s.into())) + // Estimated: `110487` + // Minimum execution time: 17_240_000 picoseconds. + Weight::from_parts(24_376_370, 110487) + // Standard Error: 928 + .saturating_add(Weight::from_parts(331_209, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -202,11 +199,11 @@ impl WeightInfo for SubstrateWeight { fn cancel_named(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `709 + s * (177 ±0)` - // Estimated: `114000` - // Minimum execution time: 19_808_000 picoseconds. - Weight::from_parts(22_601_896, 114000) - // Standard Error: 991 - .saturating_add(Weight::from_parts(496_702, 0).saturating_mul(s.into())) + // Estimated: `110487` + // Minimum execution time: 19_731_000 picoseconds. + Weight::from_parts(23_787_948, 110487) + // Standard Error: 1_133 + .saturating_add(Weight::from_parts(503_805, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -220,8 +217,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `31` // Estimated: `1489` - // Minimum execution time: 3_965_000 picoseconds. - Weight::from_parts(4_126_000, 1489) + // Minimum execution time: 3_776_000 picoseconds. + Weight::from_parts(3_992_000, 1489) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -232,10 +229,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `81 + s * (177 ±0)` // Estimated: `110487` - // Minimum execution time: 3_662_000 picoseconds. - Weight::from_parts(8_746_597, 110487) - // Standard Error: 754 - .saturating_add(Weight::from_parts(309_350, 0).saturating_mul(s.into())) + // Minimum execution time: 3_418_000 picoseconds. + Weight::from_parts(8_606_012, 110487) + // Standard Error: 769 + .saturating_add(Weight::from_parts(309_376, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -243,8 +240,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_807_000 picoseconds. - Weight::from_parts(5_963_000, 0) + // Minimum execution time: 5_624_000 picoseconds. + Weight::from_parts(5_758_000, 0) } /// Storage: Preimage PreimageFor (r:1 w:1) /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: Measured) @@ -254,11 +251,11 @@ impl WeightInfo for () { fn service_task_fetched(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `179 + s * (1 ±0)` - // Estimated: `7200 + s * (1 ±0)` - // Minimum execution time: 20_188_000 picoseconds. - Weight::from_parts(20_422_000, 7200) - // Standard Error: 1 - .saturating_add(Weight::from_parts(1_143, 0).saturating_mul(s.into())) + // Estimated: `3644 + s * (1 ±0)` + // Minimum execution time: 20_150_000 picoseconds. + Weight::from_parts(20_271_000, 3644) + // Standard Error: 0 + .saturating_add(Weight::from_parts(1_132, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(s.into())) @@ -269,30 +266,30 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_787_000 picoseconds. - Weight::from_parts(8_046_000, 0) + // Minimum execution time: 7_451_000 picoseconds. + Weight::from_parts(7_693_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } fn service_task_periodic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_730_000 picoseconds. - Weight::from_parts(5_901_000, 0) + // Minimum execution time: 5_477_000 picoseconds. + Weight::from_parts(5_733_000, 0) } fn execute_dispatch_signed() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_569_000 picoseconds. - Weight::from_parts(2_710_000, 0) + // Minimum execution time: 2_675_000 picoseconds. + Weight::from_parts(2_870_000, 0) } fn execute_dispatch_unsigned() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_611_000 picoseconds. - Weight::from_parts(2_765_000, 0) + // Minimum execution time: 2_697_000 picoseconds. + Weight::from_parts(2_807_000, 0) } /// Storage: Scheduler Agenda (r:1 w:1) /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) @@ -301,10 +298,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `81 + s * (177 ±0)` // Estimated: `110487` - // Minimum execution time: 14_237_000 picoseconds. - Weight::from_parts(18_553_929, 110487) - // Standard Error: 757 - .saturating_add(Weight::from_parts(327_347, 0).saturating_mul(s.into())) + // Minimum execution time: 13_921_000 picoseconds. + Weight::from_parts(18_717_223, 110487) + // Standard Error: 771 + .saturating_add(Weight::from_parts(333_102, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -317,10 +314,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `81 + s * (177 ±0)` // Estimated: `110487` - // Minimum execution time: 18_003_000 picoseconds. - Weight::from_parts(19_521_283, 110487) - // Standard Error: 901 - .saturating_add(Weight::from_parts(496_401, 0).saturating_mul(s.into())) + // Minimum execution time: 17_552_000 picoseconds. + Weight::from_parts(19_006_016, 110487) + // Standard Error: 1_115 + .saturating_add(Weight::from_parts(495_979, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -332,11 +329,11 @@ impl WeightInfo for () { fn schedule_named(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `596 + s * (178 ±0)` - // Estimated: `114000` - // Minimum execution time: 17_713_000 picoseconds. - Weight::from_parts(24_442_945, 114000) - // Standard Error: 764 - .saturating_add(Weight::from_parts(330_307, 0).saturating_mul(s.into())) + // Estimated: `110487` + // Minimum execution time: 17_240_000 picoseconds. + Weight::from_parts(24_376_370, 110487) + // Standard Error: 928 + .saturating_add(Weight::from_parts(331_209, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -348,11 +345,11 @@ impl WeightInfo for () { fn cancel_named(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `709 + s * (177 ±0)` - // Estimated: `114000` - // Minimum execution time: 19_808_000 picoseconds. - Weight::from_parts(22_601_896, 114000) - // Standard Error: 991 - .saturating_add(Weight::from_parts(496_702, 0).saturating_mul(s.into())) + // Estimated: `110487` + // Minimum execution time: 19_731_000 picoseconds. + Weight::from_parts(23_787_948, 110487) + // Standard Error: 1_133 + .saturating_add(Weight::from_parts(503_805, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } diff --git a/frame/session/src/weights.rs b/frame/session/src/weights.rs index 3515ff4464a3a..add7f333590e1 100644 --- a/frame/session/src/weights.rs +++ b/frame/session/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_session //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,9 +31,6 @@ // --steps=50 // --repeat=20 // --pallet=pallet_session -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -67,9 +64,9 @@ impl WeightInfo for SubstrateWeight { fn set_keys() -> Weight { // Proof Size summary in bytes: // Measured: `1891` - // Estimated: `22693` - // Minimum execution time: 48_165_000 picoseconds. - Weight::from_parts(48_967_000, 22693) + // Estimated: `12781` + // Minimum execution time: 48_507_000 picoseconds. + Weight::from_parts(49_214_000, 12781) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -82,9 +79,9 @@ impl WeightInfo for SubstrateWeight { fn purge_keys() -> Weight { // Proof Size summary in bytes: // Measured: `1758` - // Estimated: `11537` - // Minimum execution time: 35_824_000 picoseconds. - Weight::from_parts(36_267_000, 11537) + // Estimated: `5223` + // Minimum execution time: 35_388_000 picoseconds. + Weight::from_parts(35_763_000, 5223) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -101,9 +98,9 @@ impl WeightInfo for () { fn set_keys() -> Weight { // Proof Size summary in bytes: // Measured: `1891` - // Estimated: `22693` - // Minimum execution time: 48_165_000 picoseconds. - Weight::from_parts(48_967_000, 22693) + // Estimated: `12781` + // Minimum execution time: 48_507_000 picoseconds. + Weight::from_parts(49_214_000, 12781) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -116,9 +113,9 @@ impl WeightInfo for () { fn purge_keys() -> Weight { // Proof Size summary in bytes: // Measured: `1758` - // Estimated: `11537` - // Minimum execution time: 35_824_000 picoseconds. - Weight::from_parts(36_267_000, 11537) + // Estimated: `5223` + // Minimum execution time: 35_388_000 picoseconds. + Weight::from_parts(35_763_000, 5223) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } diff --git a/frame/staking/src/weights.rs b/frame/staking/src/weights.rs index 01d874d55660b..34b01445d965a 100644 --- a/frame/staking/src/weights.rs +++ b/frame/staking/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_staking //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,9 +31,6 @@ // --steps=50 // --repeat=20 // --pallet=pallet_staking -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -94,15 +91,17 @@ impl WeightInfo for SubstrateWeight { /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: Staking Payee (r:0 w:1) /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) fn bond() -> Weight { // Proof Size summary in bytes: // Measured: `1047` - // Estimated: `14346` - // Minimum execution time: 46_401_000 picoseconds. - Weight::from_parts(46_987_000, 14346) - .saturating_add(T::DbWeight::get().reads(4_u64)) + // Estimated: `4764` + // Minimum execution time: 54_907_000 picoseconds. + Weight::from_parts(55_685_000, 4764) + .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } /// Storage: Staking Bonded (r:1 w:0) @@ -111,6 +110,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: VoterList ListNodes (r:3 w:3) /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) /// Storage: VoterList ListBags (r:2 w:2) @@ -118,10 +119,10 @@ impl WeightInfo for SubstrateWeight { fn bond_extra() -> Weight { // Proof Size summary in bytes: // Measured: `2028` - // Estimated: `27838` - // Minimum execution time: 87_755_000 picoseconds. - Weight::from_parts(88_802_000, 27838) - .saturating_add(T::DbWeight::get().reads(8_u64)) + // Estimated: `8877` + // Minimum execution time: 94_779_000 picoseconds. + Weight::from_parts(95_455_000, 8877) + .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } /// Storage: Staking Ledger (r:1 w:1) @@ -134,6 +135,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: System Account (r:1 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: VoterList ListNodes (r:3 w:3) @@ -145,10 +148,10 @@ impl WeightInfo for SubstrateWeight { fn unbond() -> Weight { // Proof Size summary in bytes: // Measured: `2233` - // Estimated: `38444` - // Minimum execution time: 95_698_000 picoseconds. - Weight::from_parts(96_971_000, 38444) - .saturating_add(T::DbWeight::get().reads(12_u64)) + // Estimated: `8877` + // Minimum execution time: 98_004_000 picoseconds. + Weight::from_parts(98_730_000, 8877) + .saturating_add(T::DbWeight::get().reads(13_u64)) .saturating_add(T::DbWeight::get().writes(8_u64)) } /// Storage: Staking Ledger (r:1 w:1) @@ -157,18 +160,20 @@ impl WeightInfo for SubstrateWeight { /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: System Account (r:1 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `1021` - // Estimated: `14402` - // Minimum execution time: 38_239_000 picoseconds. - Weight::from_parts(39_615_452, 14402) - // Standard Error: 447 - .saturating_add(Weight::from_parts(9_199, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(4_u64)) + // Estimated: `4764` + // Minimum execution time: 45_888_000 picoseconds. + Weight::from_parts(47_568_327, 4764) + // Standard Error: 402 + .saturating_add(Weight::from_parts(7_520, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: Staking Ledger (r:1 w:1) @@ -195,6 +200,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: Staking Payee (r:0 w:1) /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) /// Storage: Staking SpanSlash (r:0 w:100) @@ -203,12 +210,12 @@ impl WeightInfo for SubstrateWeight { fn withdraw_unbonded_kill(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `2294 + s * (4 ±0)` - // Estimated: `43999 + s * (4 ±0)` - // Minimum execution time: 84_251_000 picoseconds. - Weight::from_parts(90_113_319, 43999) - // Standard Error: 2_177 - .saturating_add(Weight::from_parts(1_278_840, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(13_u64)) + // Estimated: `6248 + s * (4 ±0)` + // Minimum execution time: 93_288_000 picoseconds. + Weight::from_parts(99_415_523, 6248) + // Standard Error: 3_291 + .saturating_add(Weight::from_parts(1_296_734, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(14_u64)) .saturating_add(T::DbWeight::get().writes(12_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) .saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into())) @@ -238,9 +245,9 @@ impl WeightInfo for SubstrateWeight { fn validate() -> Weight { // Proof Size summary in bytes: // Measured: `1414` - // Estimated: `30249` - // Minimum execution time: 60_509_000 picoseconds. - Weight::from_parts(61_305_000, 30249) + // Estimated: `4556` + // Minimum execution time: 58_755_000 picoseconds. + Weight::from_parts(59_424_000, 4556) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -252,11 +259,11 @@ impl WeightInfo for SubstrateWeight { fn kick(k: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `1260 + k * (569 ±0)` - // Estimated: `5546 + k * (3033 ±0)` - // Minimum execution time: 30_063_000 picoseconds. - Weight::from_parts(31_774_698, 5546) - // Standard Error: 11_088 - .saturating_add(Weight::from_parts(7_869_325, 0).saturating_mul(k.into())) + // Estimated: `4556 + k * (3033 ±0)` + // Minimum execution time: 29_399_000 picoseconds. + Weight::from_parts(30_443_621, 4556) + // Standard Error: 10_402 + .saturating_add(Weight::from_parts(7_890_220, 0).saturating_mul(k.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(k.into()))) @@ -288,11 +295,11 @@ impl WeightInfo for SubstrateWeight { fn nominate(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `1888 + n * (105 ±0)` - // Estimated: `32878 + n * (2520 ±0)` - // Minimum execution time: 70_091_000 picoseconds. - Weight::from_parts(67_744_973, 32878) - // Standard Error: 12_799 - .saturating_add(Weight::from_parts(3_238_224, 0).saturating_mul(n.into())) + // Estimated: `6248 + n * (2520 ±0)` + // Minimum execution time: 68_471_000 picoseconds. + Weight::from_parts(65_972_990, 6248) + // Standard Error: 13_983 + .saturating_add(Weight::from_parts(3_255_731, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(6_u64)) @@ -315,9 +322,9 @@ impl WeightInfo for SubstrateWeight { fn chill() -> Weight { // Proof Size summary in bytes: // Measured: `1748` - // Estimated: `24862` - // Minimum execution time: 60_582_000 picoseconds. - Weight::from_parts(61_208_000, 24862) + // Estimated: `6248` + // Minimum execution time: 59_537_000 picoseconds. + Weight::from_parts(60_446_000, 6248) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -329,8 +336,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `808` // Estimated: `4556` - // Minimum execution time: 15_630_000 picoseconds. - Weight::from_parts(16_018_000, 4556) + // Minimum execution time: 15_403_000 picoseconds. + Weight::from_parts(15_676_000, 4556) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -341,9 +348,9 @@ impl WeightInfo for SubstrateWeight { fn set_controller() -> Weight { // Proof Size summary in bytes: // Measured: `907` - // Estimated: `11659` - // Minimum execution time: 23_895_000 picoseconds. - Weight::from_parts(24_306_000, 11659) + // Estimated: `8122` + // Minimum execution time: 23_316_000 picoseconds. + Weight::from_parts(23_670_000, 8122) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -353,8 +360,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_694_000 picoseconds. - Weight::from_parts(3_820_000, 0) + // Minimum execution time: 3_558_000 picoseconds. + Weight::from_parts(3_759_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Staking ForceEra (r:0 w:1) @@ -363,8 +370,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 10_729_000 picoseconds. - Weight::from_parts(11_086_000, 0) + // Minimum execution time: 12_724_000 picoseconds. + Weight::from_parts(13_047_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Staking ForceEra (r:0 w:1) @@ -373,8 +380,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 10_959_000 picoseconds. - Weight::from_parts(11_371_000, 0) + // Minimum execution time: 12_734_000 picoseconds. + Weight::from_parts(13_218_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Staking ForceEra (r:0 w:1) @@ -383,8 +390,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 11_101_000 picoseconds. - Weight::from_parts(11_506_000, 0) + // Minimum execution time: 12_996_000 picoseconds. + Weight::from_parts(13_375_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Staking Invulnerables (r:0 w:1) @@ -394,10 +401,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_016_000 picoseconds. - Weight::from_parts(4_454_020, 0) - // Standard Error: 82 - .saturating_add(Weight::from_parts(10_703, 0).saturating_mul(v.into())) + // Minimum execution time: 3_920_000 picoseconds. + Weight::from_parts(4_619_469, 0) + // Standard Error: 22 + .saturating_add(Weight::from_parts(10_108, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Staking Bonded (r:1 w:1) @@ -420,6 +427,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: Staking Ledger (r:0 w:1) /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) /// Storage: Staking Payee (r:0 w:1) @@ -430,12 +439,12 @@ impl WeightInfo for SubstrateWeight { fn force_unstake(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `2018 + s * (4 ±0)` - // Estimated: `37678 + s * (4 ±0)` - // Minimum execution time: 76_338_000 picoseconds. - Weight::from_parts(82_426_098, 37678) - // Standard Error: 3_761 - .saturating_add(Weight::from_parts(1_279_343, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(11_u64)) + // Estimated: `6248 + s * (4 ±0)` + // Minimum execution time: 86_516_000 picoseconds. + Weight::from_parts(92_324_464, 6248) + // Standard Error: 2_925 + .saturating_add(Weight::from_parts(1_286_284, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(12_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) .saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into())) @@ -447,10 +456,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `66639` // Estimated: `70104` - // Minimum execution time: 91_160_000 picoseconds. - Weight::from_parts(794_662_495, 70104) - // Standard Error: 51_479 - .saturating_add(Weight::from_parts(4_346_694, 0).saturating_mul(s.into())) + // Minimum execution time: 90_193_000 picoseconds. + Weight::from_parts(821_522_318, 70104) + // Standard Error: 57_922 + .saturating_add(Weight::from_parts(4_554_659, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -476,16 +485,16 @@ impl WeightInfo for SubstrateWeight { fn payout_stakers_dead_controller(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `20217 + n * (143 ±0)` - // Estimated: `63416 + n * (8024 ±1)` - // Minimum execution time: 77_845_000 picoseconds. - Weight::from_parts(86_178_186, 63416) - // Standard Error: 21_971 - .saturating_add(Weight::from_parts(26_966_654, 0).saturating_mul(n.into())) + // Estimated: `19844 + n * (2603 ±1)` + // Minimum execution time: 80_329_000 picoseconds. + Weight::from_parts(97_340_643, 19844) + // Standard Error: 22_713 + .saturating_add(Weight::from_parts(29_087_425, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 8024).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 2603).saturating_mul(n.into())) } /// Storage: Staking CurrentEra (r:1 w:0) /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -507,25 +516,29 @@ impl WeightInfo for SubstrateWeight { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: Balances Locks (r:257 w:257) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:257 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// The range of component `n` is `[0, 256]`. fn payout_stakers_alive_staked(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `34971 + n * (401 ±0)` - // Estimated: `93244 + n * (15898 ±0)` - // Minimum execution time: 98_209_000 picoseconds. - Weight::from_parts(102_121_432, 93244) - // Standard Error: 25_633 - .saturating_add(Weight::from_parts(39_244_200, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(10_u64)) - .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(n.into()))) + // Estimated: `32376 + n * (3774 ±0)` + // Minimum execution time: 105_591_000 picoseconds. + Weight::from_parts(111_587_915, 32376) + // Standard Error: 15_598 + .saturating_add(Weight::from_parts(48_948_195, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(11_u64)) + .saturating_add(T::DbWeight::get().reads((6_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 15898).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 3774).saturating_mul(n.into())) } /// Storage: Staking Ledger (r:1 w:1) /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: System Account (r:1 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: VoterList ListNodes (r:3 w:3) @@ -538,12 +551,12 @@ impl WeightInfo for SubstrateWeight { fn rebond(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `2029 + l * (7 ±0)` - // Estimated: `31431` - // Minimum execution time: 87_067_000 picoseconds. - Weight::from_parts(87_971_483, 31431) - // Standard Error: 1_668 - .saturating_add(Weight::from_parts(56_024, 0).saturating_mul(l.into())) - .saturating_add(T::DbWeight::get().reads(9_u64)) + // Estimated: `8877` + // Minimum execution time: 89_420_000 picoseconds. + Weight::from_parts(90_743_615, 8877) + // Standard Error: 1_260 + .saturating_add(Weight::from_parts(50_832, 0).saturating_mul(l.into())) + .saturating_add(T::DbWeight::get().reads(10_u64)) .saturating_add(T::DbWeight::get().writes(8_u64)) } /// Storage: System Account (r:1 w:1) @@ -568,6 +581,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: Staking Payee (r:0 w:1) /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) /// Storage: Staking SpanSlash (r:0 w:100) @@ -576,12 +591,12 @@ impl WeightInfo for SubstrateWeight { fn reap_stash(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `2294 + s * (4 ±0)` - // Estimated: `42515 + s * (4 ±0)` - // Minimum execution time: 90_421_000 picoseconds. - Weight::from_parts(91_873_866, 42515) - // Standard Error: 1_867 - .saturating_add(Weight::from_parts(1_275_581, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(12_u64)) + // Estimated: `6248 + s * (4 ±0)` + // Minimum execution time: 100_911_000 picoseconds. + Weight::from_parts(102_678_006, 6248) + // Standard Error: 2_349 + .saturating_add(Weight::from_parts(1_262_431, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(13_u64)) .saturating_add(T::DbWeight::get().writes(12_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) .saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into())) @@ -624,21 +639,21 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 100]`. fn new_era(v: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0 + v * (3598 ±0) + n * (720 ±0)` - // Estimated: `537749 + v * (16699 ±39) + n * (12763 ±3)` - // Minimum execution time: 552_452_000 picoseconds. - Weight::from_parts(555_250_000, 537749) - // Standard Error: 1_893_951 - .saturating_add(Weight::from_parts(61_059_451, 0).saturating_mul(v.into())) - // Standard Error: 188_721 - .saturating_add(Weight::from_parts(17_220_679, 0).saturating_mul(n.into())) + // Measured: `0 + n * (720 ±0) + v * (3598 ±0)` + // Estimated: `512390 + n * (3566 ±0) + v * (3566 ±0)` + // Minimum execution time: 554_712_000 picoseconds. + Weight::from_parts(556_603_000, 512390) + // Standard Error: 1_925_251 + .saturating_add(Weight::from_parts(62_627_196, 0).saturating_mul(v.into())) + // Standard Error: 191_840 + .saturating_add(Weight::from_parts(16_681_790, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(206_u64)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(v.into()))) - .saturating_add(Weight::from_parts(0, 16699).saturating_mul(v.into())) - .saturating_add(Weight::from_parts(0, 12763).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 3566).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 3566).saturating_mul(v.into())) } /// Storage: VoterList CounterForListNodes (r:1 w:0) /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -660,20 +675,20 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[500, 1000]`. fn get_npos_voters(v: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `3135 + v * (395 ±0) + n * (911 ±0)` - // Estimated: `518829 + v * (14295 ±0) + n * (11775 ±0)` - // Minimum execution time: 32_870_065_000 picoseconds. - Weight::from_parts(33_295_716_000, 518829) - // Standard Error: 371_824 - .saturating_add(Weight::from_parts(5_148_979, 0).saturating_mul(v.into())) - // Standard Error: 371_824 - .saturating_add(Weight::from_parts(3_376_262, 0).saturating_mul(n.into())) + // Measured: `3135 + n * (911 ±0) + v * (395 ±0)` + // Estimated: `512390 + n * (3566 ±0) + v * (3566 ±0)` + // Minimum execution time: 31_770_670_000 picoseconds. + Weight::from_parts(31_839_042_000, 512390) + // Standard Error: 355_382 + .saturating_add(Weight::from_parts(5_044_540, 0).saturating_mul(v.into())) + // Standard Error: 355_382 + .saturating_add(Weight::from_parts(3_205_722, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(201_u64)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) - .saturating_add(Weight::from_parts(0, 14295).saturating_mul(v.into())) - .saturating_add(Weight::from_parts(0, 11775).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 3566).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 3566).saturating_mul(v.into())) } /// Storage: Staking CounterForValidators (r:1 w:0) /// Proof: Staking CounterForValidators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -683,11 +698,11 @@ impl WeightInfo for SubstrateWeight { fn get_npos_targets(v: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `983 + v * (50 ±0)` - // Estimated: `4999 + v * (2520 ±0)` - // Minimum execution time: 2_321_389_000 picoseconds. - Weight::from_parts(70_122_933, 4999) - // Standard Error: 7_249 - .saturating_add(Weight::from_parts(4_632_666, 0).saturating_mul(v.into())) + // Estimated: `3510 + v * (2520 ±0)` + // Minimum execution time: 2_253_567_000 picoseconds. + Weight::from_parts(61_440_613, 3510) + // Standard Error: 5_276 + .saturating_add(Weight::from_parts(4_414_153, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) .saturating_add(Weight::from_parts(0, 2520).saturating_mul(v.into())) @@ -708,8 +723,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_581_000 picoseconds. - Weight::from_parts(9_802_000, 0) + // Minimum execution time: 9_292_000 picoseconds. + Weight::from_parts(9_587_000, 0) .saturating_add(T::DbWeight::get().writes(6_u64)) } /// Storage: Staking MinCommission (r:0 w:1) @@ -728,8 +743,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_883_000 picoseconds. - Weight::from_parts(9_151_000, 0) + // Minimum execution time: 8_294_000 picoseconds. + Weight::from_parts(8_597_000, 0) .saturating_add(T::DbWeight::get().writes(6_u64)) } /// Storage: Staking Ledger (r:1 w:0) @@ -755,9 +770,9 @@ impl WeightInfo for SubstrateWeight { fn chill_other() -> Weight { // Proof Size summary in bytes: // Measured: `1871` - // Estimated: `29338` - // Minimum execution time: 77_916_000 picoseconds. - Weight::from_parts(78_877_000, 29338) + // Estimated: `6248` + // Minimum execution time: 75_742_000 picoseconds. + Weight::from_parts(76_252_000, 6248) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -768,9 +783,9 @@ impl WeightInfo for SubstrateWeight { fn force_apply_min_commission() -> Weight { // Proof Size summary in bytes: // Measured: `694` - // Estimated: `4999` - // Minimum execution time: 16_658_000 picoseconds. - Weight::from_parts(16_968_000, 4999) + // Estimated: `3510` + // Minimum execution time: 16_407_000 picoseconds. + Weight::from_parts(16_726_000, 3510) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -780,8 +795,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_982_000 picoseconds. - Weight::from_parts(5_232_000, 0) + // Minimum execution time: 4_977_000 picoseconds. + Weight::from_parts(5_224_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } } @@ -796,15 +811,17 @@ impl WeightInfo for () { /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: Staking Payee (r:0 w:1) /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) fn bond() -> Weight { // Proof Size summary in bytes: // Measured: `1047` - // Estimated: `14346` - // Minimum execution time: 46_401_000 picoseconds. - Weight::from_parts(46_987_000, 14346) - .saturating_add(RocksDbWeight::get().reads(4_u64)) + // Estimated: `4764` + // Minimum execution time: 54_907_000 picoseconds. + Weight::from_parts(55_685_000, 4764) + .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } /// Storage: Staking Bonded (r:1 w:0) @@ -813,6 +830,8 @@ impl WeightInfo for () { /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: VoterList ListNodes (r:3 w:3) /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) /// Storage: VoterList ListBags (r:2 w:2) @@ -820,10 +839,10 @@ impl WeightInfo for () { fn bond_extra() -> Weight { // Proof Size summary in bytes: // Measured: `2028` - // Estimated: `27838` - // Minimum execution time: 87_755_000 picoseconds. - Weight::from_parts(88_802_000, 27838) - .saturating_add(RocksDbWeight::get().reads(8_u64)) + // Estimated: `8877` + // Minimum execution time: 94_779_000 picoseconds. + Weight::from_parts(95_455_000, 8877) + .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } /// Storage: Staking Ledger (r:1 w:1) @@ -836,6 +855,8 @@ impl WeightInfo for () { /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: System Account (r:1 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: VoterList ListNodes (r:3 w:3) @@ -847,10 +868,10 @@ impl WeightInfo for () { fn unbond() -> Weight { // Proof Size summary in bytes: // Measured: `2233` - // Estimated: `38444` - // Minimum execution time: 95_698_000 picoseconds. - Weight::from_parts(96_971_000, 38444) - .saturating_add(RocksDbWeight::get().reads(12_u64)) + // Estimated: `8877` + // Minimum execution time: 98_004_000 picoseconds. + Weight::from_parts(98_730_000, 8877) + .saturating_add(RocksDbWeight::get().reads(13_u64)) .saturating_add(RocksDbWeight::get().writes(8_u64)) } /// Storage: Staking Ledger (r:1 w:1) @@ -859,18 +880,20 @@ impl WeightInfo for () { /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: System Account (r:1 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `1021` - // Estimated: `14402` - // Minimum execution time: 38_239_000 picoseconds. - Weight::from_parts(39_615_452, 14402) - // Standard Error: 447 - .saturating_add(Weight::from_parts(9_199, 0).saturating_mul(s.into())) - .saturating_add(RocksDbWeight::get().reads(4_u64)) + // Estimated: `4764` + // Minimum execution time: 45_888_000 picoseconds. + Weight::from_parts(47_568_327, 4764) + // Standard Error: 402 + .saturating_add(Weight::from_parts(7_520, 0).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: Staking Ledger (r:1 w:1) @@ -897,6 +920,8 @@ impl WeightInfo for () { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: Staking Payee (r:0 w:1) /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) /// Storage: Staking SpanSlash (r:0 w:100) @@ -905,12 +930,12 @@ impl WeightInfo for () { fn withdraw_unbonded_kill(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `2294 + s * (4 ±0)` - // Estimated: `43999 + s * (4 ±0)` - // Minimum execution time: 84_251_000 picoseconds. - Weight::from_parts(90_113_319, 43999) - // Standard Error: 2_177 - .saturating_add(Weight::from_parts(1_278_840, 0).saturating_mul(s.into())) - .saturating_add(RocksDbWeight::get().reads(13_u64)) + // Estimated: `6248 + s * (4 ±0)` + // Minimum execution time: 93_288_000 picoseconds. + Weight::from_parts(99_415_523, 6248) + // Standard Error: 3_291 + .saturating_add(Weight::from_parts(1_296_734, 0).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(14_u64)) .saturating_add(RocksDbWeight::get().writes(12_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) .saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into())) @@ -940,9 +965,9 @@ impl WeightInfo for () { fn validate() -> Weight { // Proof Size summary in bytes: // Measured: `1414` - // Estimated: `30249` - // Minimum execution time: 60_509_000 picoseconds. - Weight::from_parts(61_305_000, 30249) + // Estimated: `4556` + // Minimum execution time: 58_755_000 picoseconds. + Weight::from_parts(59_424_000, 4556) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -954,11 +979,11 @@ impl WeightInfo for () { fn kick(k: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `1260 + k * (569 ±0)` - // Estimated: `5546 + k * (3033 ±0)` - // Minimum execution time: 30_063_000 picoseconds. - Weight::from_parts(31_774_698, 5546) - // Standard Error: 11_088 - .saturating_add(Weight::from_parts(7_869_325, 0).saturating_mul(k.into())) + // Estimated: `4556 + k * (3033 ±0)` + // Minimum execution time: 29_399_000 picoseconds. + Weight::from_parts(30_443_621, 4556) + // Standard Error: 10_402 + .saturating_add(Weight::from_parts(7_890_220, 0).saturating_mul(k.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(k.into()))) @@ -990,11 +1015,11 @@ impl WeightInfo for () { fn nominate(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `1888 + n * (105 ±0)` - // Estimated: `32878 + n * (2520 ±0)` - // Minimum execution time: 70_091_000 picoseconds. - Weight::from_parts(67_744_973, 32878) - // Standard Error: 12_799 - .saturating_add(Weight::from_parts(3_238_224, 0).saturating_mul(n.into())) + // Estimated: `6248 + n * (2520 ±0)` + // Minimum execution time: 68_471_000 picoseconds. + Weight::from_parts(65_972_990, 6248) + // Standard Error: 13_983 + .saturating_add(Weight::from_parts(3_255_731, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(6_u64)) @@ -1017,9 +1042,9 @@ impl WeightInfo for () { fn chill() -> Weight { // Proof Size summary in bytes: // Measured: `1748` - // Estimated: `24862` - // Minimum execution time: 60_582_000 picoseconds. - Weight::from_parts(61_208_000, 24862) + // Estimated: `6248` + // Minimum execution time: 59_537_000 picoseconds. + Weight::from_parts(60_446_000, 6248) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -1031,8 +1056,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `808` // Estimated: `4556` - // Minimum execution time: 15_630_000 picoseconds. - Weight::from_parts(16_018_000, 4556) + // Minimum execution time: 15_403_000 picoseconds. + Weight::from_parts(15_676_000, 4556) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1043,9 +1068,9 @@ impl WeightInfo for () { fn set_controller() -> Weight { // Proof Size summary in bytes: // Measured: `907` - // Estimated: `11659` - // Minimum execution time: 23_895_000 picoseconds. - Weight::from_parts(24_306_000, 11659) + // Estimated: `8122` + // Minimum execution time: 23_316_000 picoseconds. + Weight::from_parts(23_670_000, 8122) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -1055,8 +1080,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_694_000 picoseconds. - Weight::from_parts(3_820_000, 0) + // Minimum execution time: 3_558_000 picoseconds. + Weight::from_parts(3_759_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Staking ForceEra (r:0 w:1) @@ -1065,8 +1090,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 10_729_000 picoseconds. - Weight::from_parts(11_086_000, 0) + // Minimum execution time: 12_724_000 picoseconds. + Weight::from_parts(13_047_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Staking ForceEra (r:0 w:1) @@ -1075,8 +1100,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 10_959_000 picoseconds. - Weight::from_parts(11_371_000, 0) + // Minimum execution time: 12_734_000 picoseconds. + Weight::from_parts(13_218_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Staking ForceEra (r:0 w:1) @@ -1085,8 +1110,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 11_101_000 picoseconds. - Weight::from_parts(11_506_000, 0) + // Minimum execution time: 12_996_000 picoseconds. + Weight::from_parts(13_375_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Staking Invulnerables (r:0 w:1) @@ -1096,10 +1121,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_016_000 picoseconds. - Weight::from_parts(4_454_020, 0) - // Standard Error: 82 - .saturating_add(Weight::from_parts(10_703, 0).saturating_mul(v.into())) + // Minimum execution time: 3_920_000 picoseconds. + Weight::from_parts(4_619_469, 0) + // Standard Error: 22 + .saturating_add(Weight::from_parts(10_108, 0).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Staking Bonded (r:1 w:1) @@ -1122,6 +1147,8 @@ impl WeightInfo for () { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: Staking Ledger (r:0 w:1) /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) /// Storage: Staking Payee (r:0 w:1) @@ -1132,12 +1159,12 @@ impl WeightInfo for () { fn force_unstake(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `2018 + s * (4 ±0)` - // Estimated: `37678 + s * (4 ±0)` - // Minimum execution time: 76_338_000 picoseconds. - Weight::from_parts(82_426_098, 37678) - // Standard Error: 3_761 - .saturating_add(Weight::from_parts(1_279_343, 0).saturating_mul(s.into())) - .saturating_add(RocksDbWeight::get().reads(11_u64)) + // Estimated: `6248 + s * (4 ±0)` + // Minimum execution time: 86_516_000 picoseconds. + Weight::from_parts(92_324_464, 6248) + // Standard Error: 2_925 + .saturating_add(Weight::from_parts(1_286_284, 0).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().writes(12_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) .saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into())) @@ -1149,10 +1176,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `66639` // Estimated: `70104` - // Minimum execution time: 91_160_000 picoseconds. - Weight::from_parts(794_662_495, 70104) - // Standard Error: 51_479 - .saturating_add(Weight::from_parts(4_346_694, 0).saturating_mul(s.into())) + // Minimum execution time: 90_193_000 picoseconds. + Weight::from_parts(821_522_318, 70104) + // Standard Error: 57_922 + .saturating_add(Weight::from_parts(4_554_659, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1178,16 +1205,16 @@ impl WeightInfo for () { fn payout_stakers_dead_controller(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `20217 + n * (143 ±0)` - // Estimated: `63416 + n * (8024 ±1)` - // Minimum execution time: 77_845_000 picoseconds. - Weight::from_parts(86_178_186, 63416) - // Standard Error: 21_971 - .saturating_add(Weight::from_parts(26_966_654, 0).saturating_mul(n.into())) + // Estimated: `19844 + n * (2603 ±1)` + // Minimum execution time: 80_329_000 picoseconds. + Weight::from_parts(97_340_643, 19844) + // Standard Error: 22_713 + .saturating_add(Weight::from_parts(29_087_425, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 8024).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 2603).saturating_mul(n.into())) } /// Storage: Staking CurrentEra (r:1 w:0) /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -1209,25 +1236,29 @@ impl WeightInfo for () { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: Balances Locks (r:257 w:257) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:257 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// The range of component `n` is `[0, 256]`. fn payout_stakers_alive_staked(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `34971 + n * (401 ±0)` - // Estimated: `93244 + n * (15898 ±0)` - // Minimum execution time: 98_209_000 picoseconds. - Weight::from_parts(102_121_432, 93244) - // Standard Error: 25_633 - .saturating_add(Weight::from_parts(39_244_200, 0).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(10_u64)) - .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(n.into()))) + // Estimated: `32376 + n * (3774 ±0)` + // Minimum execution time: 105_591_000 picoseconds. + Weight::from_parts(111_587_915, 32376) + // Standard Error: 15_598 + .saturating_add(Weight::from_parts(48_948_195, 0).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(11_u64)) + .saturating_add(RocksDbWeight::get().reads((6_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 15898).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 3774).saturating_mul(n.into())) } /// Storage: Staking Ledger (r:1 w:1) /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: System Account (r:1 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: VoterList ListNodes (r:3 w:3) @@ -1240,12 +1271,12 @@ impl WeightInfo for () { fn rebond(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `2029 + l * (7 ±0)` - // Estimated: `31431` - // Minimum execution time: 87_067_000 picoseconds. - Weight::from_parts(87_971_483, 31431) - // Standard Error: 1_668 - .saturating_add(Weight::from_parts(56_024, 0).saturating_mul(l.into())) - .saturating_add(RocksDbWeight::get().reads(9_u64)) + // Estimated: `8877` + // Minimum execution time: 89_420_000 picoseconds. + Weight::from_parts(90_743_615, 8877) + // Standard Error: 1_260 + .saturating_add(Weight::from_parts(50_832, 0).saturating_mul(l.into())) + .saturating_add(RocksDbWeight::get().reads(10_u64)) .saturating_add(RocksDbWeight::get().writes(8_u64)) } /// Storage: System Account (r:1 w:1) @@ -1270,6 +1301,8 @@ impl WeightInfo for () { /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: Staking Payee (r:0 w:1) /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) /// Storage: Staking SpanSlash (r:0 w:100) @@ -1278,12 +1311,12 @@ impl WeightInfo for () { fn reap_stash(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `2294 + s * (4 ±0)` - // Estimated: `42515 + s * (4 ±0)` - // Minimum execution time: 90_421_000 picoseconds. - Weight::from_parts(91_873_866, 42515) - // Standard Error: 1_867 - .saturating_add(Weight::from_parts(1_275_581, 0).saturating_mul(s.into())) - .saturating_add(RocksDbWeight::get().reads(12_u64)) + // Estimated: `6248 + s * (4 ±0)` + // Minimum execution time: 100_911_000 picoseconds. + Weight::from_parts(102_678_006, 6248) + // Standard Error: 2_349 + .saturating_add(Weight::from_parts(1_262_431, 0).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(13_u64)) .saturating_add(RocksDbWeight::get().writes(12_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) .saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into())) @@ -1326,21 +1359,21 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 100]`. fn new_era(v: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0 + v * (3598 ±0) + n * (720 ±0)` - // Estimated: `537749 + v * (16699 ±39) + n * (12763 ±3)` - // Minimum execution time: 552_452_000 picoseconds. - Weight::from_parts(555_250_000, 537749) - // Standard Error: 1_893_951 - .saturating_add(Weight::from_parts(61_059_451, 0).saturating_mul(v.into())) - // Standard Error: 188_721 - .saturating_add(Weight::from_parts(17_220_679, 0).saturating_mul(n.into())) + // Measured: `0 + n * (720 ±0) + v * (3598 ±0)` + // Estimated: `512390 + n * (3566 ±0) + v * (3566 ±0)` + // Minimum execution time: 554_712_000 picoseconds. + Weight::from_parts(556_603_000, 512390) + // Standard Error: 1_925_251 + .saturating_add(Weight::from_parts(62_627_196, 0).saturating_mul(v.into())) + // Standard Error: 191_840 + .saturating_add(Weight::from_parts(16_681_790, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(206_u64)) .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(v.into()))) - .saturating_add(Weight::from_parts(0, 16699).saturating_mul(v.into())) - .saturating_add(Weight::from_parts(0, 12763).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 3566).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 3566).saturating_mul(v.into())) } /// Storage: VoterList CounterForListNodes (r:1 w:0) /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -1362,20 +1395,20 @@ impl WeightInfo for () { /// The range of component `n` is `[500, 1000]`. fn get_npos_voters(v: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `3135 + v * (395 ±0) + n * (911 ±0)` - // Estimated: `518829 + v * (14295 ±0) + n * (11775 ±0)` - // Minimum execution time: 32_870_065_000 picoseconds. - Weight::from_parts(33_295_716_000, 518829) - // Standard Error: 371_824 - .saturating_add(Weight::from_parts(5_148_979, 0).saturating_mul(v.into())) - // Standard Error: 371_824 - .saturating_add(Weight::from_parts(3_376_262, 0).saturating_mul(n.into())) + // Measured: `3135 + n * (911 ±0) + v * (395 ±0)` + // Estimated: `512390 + n * (3566 ±0) + v * (3566 ±0)` + // Minimum execution time: 31_770_670_000 picoseconds. + Weight::from_parts(31_839_042_000, 512390) + // Standard Error: 355_382 + .saturating_add(Weight::from_parts(5_044_540, 0).saturating_mul(v.into())) + // Standard Error: 355_382 + .saturating_add(Weight::from_parts(3_205_722, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(201_u64)) .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) - .saturating_add(Weight::from_parts(0, 14295).saturating_mul(v.into())) - .saturating_add(Weight::from_parts(0, 11775).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 3566).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 3566).saturating_mul(v.into())) } /// Storage: Staking CounterForValidators (r:1 w:0) /// Proof: Staking CounterForValidators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -1385,11 +1418,11 @@ impl WeightInfo for () { fn get_npos_targets(v: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `983 + v * (50 ±0)` - // Estimated: `4999 + v * (2520 ±0)` - // Minimum execution time: 2_321_389_000 picoseconds. - Weight::from_parts(70_122_933, 4999) - // Standard Error: 7_249 - .saturating_add(Weight::from_parts(4_632_666, 0).saturating_mul(v.into())) + // Estimated: `3510 + v * (2520 ±0)` + // Minimum execution time: 2_253_567_000 picoseconds. + Weight::from_parts(61_440_613, 3510) + // Standard Error: 5_276 + .saturating_add(Weight::from_parts(4_414_153, 0).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(v.into()))) .saturating_add(Weight::from_parts(0, 2520).saturating_mul(v.into())) @@ -1410,8 +1443,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_581_000 picoseconds. - Weight::from_parts(9_802_000, 0) + // Minimum execution time: 9_292_000 picoseconds. + Weight::from_parts(9_587_000, 0) .saturating_add(RocksDbWeight::get().writes(6_u64)) } /// Storage: Staking MinCommission (r:0 w:1) @@ -1430,8 +1463,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_883_000 picoseconds. - Weight::from_parts(9_151_000, 0) + // Minimum execution time: 8_294_000 picoseconds. + Weight::from_parts(8_597_000, 0) .saturating_add(RocksDbWeight::get().writes(6_u64)) } /// Storage: Staking Ledger (r:1 w:0) @@ -1457,9 +1490,9 @@ impl WeightInfo for () { fn chill_other() -> Weight { // Proof Size summary in bytes: // Measured: `1871` - // Estimated: `29338` - // Minimum execution time: 77_916_000 picoseconds. - Weight::from_parts(78_877_000, 29338) + // Estimated: `6248` + // Minimum execution time: 75_742_000 picoseconds. + Weight::from_parts(76_252_000, 6248) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -1470,9 +1503,9 @@ impl WeightInfo for () { fn force_apply_min_commission() -> Weight { // Proof Size summary in bytes: // Measured: `694` - // Estimated: `4999` - // Minimum execution time: 16_658_000 picoseconds. - Weight::from_parts(16_968_000, 4999) + // Estimated: `3510` + // Minimum execution time: 16_407_000 picoseconds. + Weight::from_parts(16_726_000, 3510) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1482,8 +1515,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_982_000 picoseconds. - Weight::from_parts(5_232_000, 0) + // Minimum execution time: 4_977_000 picoseconds. + Weight::from_parts(5_224_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } } diff --git a/frame/state-trie-migration/src/weights.rs b/frame/state-trie-migration/src/weights.rs index 961cec7bcfa51..8565dd73e0c46 100644 --- a/frame/state-trie-migration/src/weights.rs +++ b/frame/state-trie-migration/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_state_trie_migration //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,9 +31,6 @@ // --steps=50 // --repeat=20 // --pallet=pallet_state_trie_migration -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -70,9 +67,9 @@ impl WeightInfo for SubstrateWeight { fn continue_migrate() -> Weight { // Proof Size summary in bytes: // Measured: `108` - // Estimated: `4020` - // Minimum execution time: 15_449_000 picoseconds. - Weight::from_parts(16_040_000, 4020) + // Estimated: `2527` + // Minimum execution time: 17_385_000 picoseconds. + Weight::from_parts(17_766_000, 2527) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -82,16 +79,16 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `76` // Estimated: `1493` - // Minimum execution time: 4_632_000 picoseconds. - Weight::from_parts(4_768_000, 1493) + // Minimum execution time: 4_537_000 picoseconds. + Weight::from_parts(4_734_000, 1493) .saturating_add(T::DbWeight::get().reads(1_u64)) } fn migrate_custom_top_success() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_596_000 picoseconds. - Weight::from_parts(9_866_000, 0) + // Minimum execution time: 10_127_000 picoseconds. + Weight::from_parts(10_384_000, 0) } /// Storage: unknown `0x666f6f` (r:1 w:1) /// Proof Skipped: unknown `0x666f6f` (r:1 w:1) @@ -99,8 +96,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `113` // Estimated: `3578` - // Minimum execution time: 27_352_000 picoseconds. - Weight::from_parts(28_089_000, 3578) + // Minimum execution time: 31_113_000 picoseconds. + Weight::from_parts(31_833_000, 3578) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -108,8 +105,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 10_286_000 picoseconds. - Weight::from_parts(10_761_000, 0) + // Minimum execution time: 10_445_000 picoseconds. + Weight::from_parts(10_726_000, 0) } /// Storage: unknown `0x666f6f` (r:1 w:1) /// Proof Skipped: unknown `0x666f6f` (r:1 w:1) @@ -117,8 +114,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `105` // Estimated: `3570` - // Minimum execution time: 27_355_000 picoseconds. - Weight::from_parts(28_092_000, 3570) + // Minimum execution time: 31_795_000 picoseconds. + Weight::from_parts(32_737_000, 3570) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -129,10 +126,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `197 + v * (1 ±0)` // Estimated: `3662 + v * (1 ±0)` - // Minimum execution time: 6_004_000 picoseconds. - Weight::from_parts(6_188_000, 3662) - // Standard Error: 1 - .saturating_add(Weight::from_parts(1_073, 0).saturating_mul(v.into())) + // Minimum execution time: 5_933_000 picoseconds. + Weight::from_parts(6_040_000, 3662) + // Standard Error: 3 + .saturating_add(Weight::from_parts(1_336, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(v.into())) @@ -148,9 +145,9 @@ impl WeightInfo for () { fn continue_migrate() -> Weight { // Proof Size summary in bytes: // Measured: `108` - // Estimated: `4020` - // Minimum execution time: 15_449_000 picoseconds. - Weight::from_parts(16_040_000, 4020) + // Estimated: `2527` + // Minimum execution time: 17_385_000 picoseconds. + Weight::from_parts(17_766_000, 2527) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -160,16 +157,16 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `76` // Estimated: `1493` - // Minimum execution time: 4_632_000 picoseconds. - Weight::from_parts(4_768_000, 1493) + // Minimum execution time: 4_537_000 picoseconds. + Weight::from_parts(4_734_000, 1493) .saturating_add(RocksDbWeight::get().reads(1_u64)) } fn migrate_custom_top_success() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_596_000 picoseconds. - Weight::from_parts(9_866_000, 0) + // Minimum execution time: 10_127_000 picoseconds. + Weight::from_parts(10_384_000, 0) } /// Storage: unknown `0x666f6f` (r:1 w:1) /// Proof Skipped: unknown `0x666f6f` (r:1 w:1) @@ -177,8 +174,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `113` // Estimated: `3578` - // Minimum execution time: 27_352_000 picoseconds. - Weight::from_parts(28_089_000, 3578) + // Minimum execution time: 31_113_000 picoseconds. + Weight::from_parts(31_833_000, 3578) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -186,8 +183,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 10_286_000 picoseconds. - Weight::from_parts(10_761_000, 0) + // Minimum execution time: 10_445_000 picoseconds. + Weight::from_parts(10_726_000, 0) } /// Storage: unknown `0x666f6f` (r:1 w:1) /// Proof Skipped: unknown `0x666f6f` (r:1 w:1) @@ -195,8 +192,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `105` // Estimated: `3570` - // Minimum execution time: 27_355_000 picoseconds. - Weight::from_parts(28_092_000, 3570) + // Minimum execution time: 31_795_000 picoseconds. + Weight::from_parts(32_737_000, 3570) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -207,10 +204,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `197 + v * (1 ±0)` // Estimated: `3662 + v * (1 ±0)` - // Minimum execution time: 6_004_000 picoseconds. - Weight::from_parts(6_188_000, 3662) - // Standard Error: 1 - .saturating_add(Weight::from_parts(1_073, 0).saturating_mul(v.into())) + // Minimum execution time: 5_933_000 picoseconds. + Weight::from_parts(6_040_000, 3662) + // Standard Error: 3 + .saturating_add(Weight::from_parts(1_336, 0).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(v.into())) diff --git a/frame/support/src/weights/block_weights.rs b/frame/support/src/weights/block_weights.rs index b8ac9a0383dee..b358aa473bfd7 100644 --- a/frame/support/src/weights/block_weights.rs +++ b/frame/support/src/weights/block_weights.rs @@ -16,8 +16,8 @@ // limitations under the License. //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-15 (Y/M/D) -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! DATE: 2023-04-06 (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` @@ -44,17 +44,17 @@ parameter_types! { /// Calculated by multiplying the *Average* with `1.0` and adding `0`. /// /// Stats nanoseconds: - /// Min, Max: 402_748, 458_228 - /// Average: 412_772 - /// Median: 406_151 - /// Std-Dev: 13480.33 + /// Min, Max: 386_820, 419_676 + /// Average: 392_184 + /// Median: 389_668 + /// Std-Dev: 5285.57 /// /// Percentiles nanoseconds: - /// 99th: 450_080 - /// 95th: 445_111 - /// 75th: 414_170 + /// 99th: 406_316 + /// 95th: 399_697 + /// 75th: 396_532 pub const BlockExecutionWeight: Weight = - Weight::from_parts(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(412_772), 0); + Weight::from_parts(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(392_184), 0); } #[cfg(test)] diff --git a/frame/support/src/weights/extrinsic_weights.rs b/frame/support/src/weights/extrinsic_weights.rs index 44b1b94aeb8ba..1a6facc3d42c3 100644 --- a/frame/support/src/weights/extrinsic_weights.rs +++ b/frame/support/src/weights/extrinsic_weights.rs @@ -16,8 +16,8 @@ // limitations under the License. //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-15 (Y/M/D) -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! DATE: 2023-04-06 (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` @@ -44,17 +44,17 @@ parameter_types! { /// Calculated by multiplying the *Average* with `1.0` and adding `0`. /// /// Stats nanoseconds: - /// Min, Max: 109_595, 114_170 - /// Average: 110_536 - /// Median: 110_233 - /// Std-Dev: 933.39 + /// Min, Max: 113_246, 114_346 + /// Average: 113_638 + /// Median: 113_641 + /// Std-Dev: 188.44 /// /// Percentiles nanoseconds: - /// 99th: 114_120 - /// 95th: 112_680 - /// 75th: 110_858 + /// 99th: 114_181 + /// 95th: 113_961 + /// 75th: 113_703 pub const ExtrinsicBaseWeight: Weight = - Weight::from_parts(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(110_536), 0); + Weight::from_parts(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(113_638), 0); } #[cfg(test)] diff --git a/frame/system/src/weights.rs b/frame/system/src/weights.rs index 34c0b62dcdd2f..96fd7a1972eb2 100644 --- a/frame/system/src/weights.rs +++ b/frame/system/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for frame_system //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,9 +31,6 @@ // --steps=50 // --repeat=20 // --pallet=frame_system -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -67,20 +64,20 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_519_000 picoseconds. - Weight::from_parts(2_576_000, 0) + // Minimum execution time: 2_430_000 picoseconds. + Weight::from_parts(2_522_000, 0) // Standard Error: 0 - .saturating_add(Weight::from_parts(365, 0).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(362, 0).saturating_mul(b.into())) } /// The range of component `b` is `[0, 3932160]`. fn remark_with_event(b: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_687_000 picoseconds. - Weight::from_parts(8_875_000, 0) + // Minimum execution time: 8_738_000 picoseconds. + Weight::from_parts(8_963_000, 0) // Standard Error: 0 - .saturating_add(Weight::from_parts(1_121, 0).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(1_113, 0).saturating_mul(b.into())) } /// Storage: System Digest (r:1 w:1) /// Proof Skipped: System Digest (max_values: Some(1), max_size: None, mode: Measured) @@ -90,8 +87,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `1485` - // Minimum execution time: 5_281_000 picoseconds. - Weight::from_parts(5_383_000, 1485) + // Minimum execution time: 5_109_000 picoseconds. + Weight::from_parts(5_336_000, 1485) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -102,10 +99,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_346_000 picoseconds. - Weight::from_parts(2_491_000, 0) - // Standard Error: 815 - .saturating_add(Weight::from_parts(731_217, 0).saturating_mul(i.into())) + // Minimum execution time: 2_531_000 picoseconds. + Weight::from_parts(2_617_000, 0) + // Standard Error: 861 + .saturating_add(Weight::from_parts(761_465, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) } /// Storage: Skipped Metadata (r:0 w:0) @@ -115,10 +112,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_394_000 picoseconds. - Weight::from_parts(2_567_000, 0) - // Standard Error: 935 - .saturating_add(Weight::from_parts(554_023, 0).saturating_mul(i.into())) + // Minimum execution time: 2_631_000 picoseconds. + Weight::from_parts(2_717_000, 0) + // Standard Error: 1_097 + .saturating_add(Weight::from_parts(570_803, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) } /// Storage: Skipped Metadata (r:0 w:0) @@ -128,10 +125,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `116 + p * (69 ±0)` // Estimated: `121 + p * (70 ±0)` - // Minimum execution time: 4_706_000 picoseconds. - Weight::from_parts(4_858_000, 121) - // Standard Error: 1_291 - .saturating_add(Weight::from_parts(1_142_198, 0).saturating_mul(p.into())) + // Minimum execution time: 4_692_000 picoseconds. + Weight::from_parts(4_789_000, 121) + // Standard Error: 1_013 + .saturating_add(Weight::from_parts(1_143_616, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(p.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(p.into()))) .saturating_add(Weight::from_parts(0, 70).saturating_mul(p.into())) @@ -145,20 +142,20 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_519_000 picoseconds. - Weight::from_parts(2_576_000, 0) + // Minimum execution time: 2_430_000 picoseconds. + Weight::from_parts(2_522_000, 0) // Standard Error: 0 - .saturating_add(Weight::from_parts(365, 0).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(362, 0).saturating_mul(b.into())) } /// The range of component `b` is `[0, 3932160]`. fn remark_with_event(b: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_687_000 picoseconds. - Weight::from_parts(8_875_000, 0) + // Minimum execution time: 8_738_000 picoseconds. + Weight::from_parts(8_963_000, 0) // Standard Error: 0 - .saturating_add(Weight::from_parts(1_121, 0).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(1_113, 0).saturating_mul(b.into())) } /// Storage: System Digest (r:1 w:1) /// Proof Skipped: System Digest (max_values: Some(1), max_size: None, mode: Measured) @@ -168,8 +165,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `1485` - // Minimum execution time: 5_281_000 picoseconds. - Weight::from_parts(5_383_000, 1485) + // Minimum execution time: 5_109_000 picoseconds. + Weight::from_parts(5_336_000, 1485) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -180,10 +177,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_346_000 picoseconds. - Weight::from_parts(2_491_000, 0) - // Standard Error: 815 - .saturating_add(Weight::from_parts(731_217, 0).saturating_mul(i.into())) + // Minimum execution time: 2_531_000 picoseconds. + Weight::from_parts(2_617_000, 0) + // Standard Error: 861 + .saturating_add(Weight::from_parts(761_465, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(i.into()))) } /// Storage: Skipped Metadata (r:0 w:0) @@ -193,10 +190,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_394_000 picoseconds. - Weight::from_parts(2_567_000, 0) - // Standard Error: 935 - .saturating_add(Weight::from_parts(554_023, 0).saturating_mul(i.into())) + // Minimum execution time: 2_631_000 picoseconds. + Weight::from_parts(2_717_000, 0) + // Standard Error: 1_097 + .saturating_add(Weight::from_parts(570_803, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(i.into()))) } /// Storage: Skipped Metadata (r:0 w:0) @@ -206,10 +203,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `116 + p * (69 ±0)` // Estimated: `121 + p * (70 ±0)` - // Minimum execution time: 4_706_000 picoseconds. - Weight::from_parts(4_858_000, 121) - // Standard Error: 1_291 - .saturating_add(Weight::from_parts(1_142_198, 0).saturating_mul(p.into())) + // Minimum execution time: 4_692_000 picoseconds. + Weight::from_parts(4_789_000, 121) + // Standard Error: 1_013 + .saturating_add(Weight::from_parts(1_143_616, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(p.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(p.into()))) .saturating_add(Weight::from_parts(0, 70).saturating_mul(p.into())) diff --git a/frame/timestamp/src/weights.rs b/frame/timestamp/src/weights.rs index e1ada6f63c961..1c254bf220076 100644 --- a/frame/timestamp/src/weights.rs +++ b/frame/timestamp/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_timestamp //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,9 +31,6 @@ // --steps=50 // --repeat=20 // --pallet=pallet_timestamp -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -65,9 +62,9 @@ impl WeightInfo for SubstrateWeight { fn set() -> Weight { // Proof Size summary in bytes: // Measured: `312` - // Estimated: `2986` - // Minimum execution time: 10_913_000 picoseconds. - Weight::from_parts(11_453_000, 2986) + // Estimated: `1493` + // Minimum execution time: 10_834_000 picoseconds. + Weight::from_parts(11_099_000, 1493) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -75,8 +72,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `161` // Estimated: `0` - // Minimum execution time: 4_400_000 picoseconds. - Weight::from_parts(4_550_000, 0) + // Minimum execution time: 4_472_000 picoseconds. + Weight::from_parts(4_645_000, 0) } } @@ -89,9 +86,9 @@ impl WeightInfo for () { fn set() -> Weight { // Proof Size summary in bytes: // Measured: `312` - // Estimated: `2986` - // Minimum execution time: 10_913_000 picoseconds. - Weight::from_parts(11_453_000, 2986) + // Estimated: `1493` + // Minimum execution time: 10_834_000 picoseconds. + Weight::from_parts(11_099_000, 1493) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -99,7 +96,7 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `161` // Estimated: `0` - // Minimum execution time: 4_400_000 picoseconds. - Weight::from_parts(4_550_000, 0) + // Minimum execution time: 4_472_000 picoseconds. + Weight::from_parts(4_645_000, 0) } } diff --git a/frame/tips/src/weights.rs b/frame/tips/src/weights.rs index 205413d52d7ff..ec5eef8c8bd81 100644 --- a/frame/tips/src/weights.rs +++ b/frame/tips/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_tips //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,9 +31,6 @@ // --steps=50 // --repeat=20 // --pallet=pallet_tips -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -70,11 +67,11 @@ impl WeightInfo for SubstrateWeight { fn report_awesome(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `4` - // Estimated: `6938` - // Minimum execution time: 26_789_000 picoseconds. - Weight::from_parts(27_619_925, 6938) - // Standard Error: 168 - .saturating_add(Weight::from_parts(1_352, 0).saturating_mul(r.into())) + // Estimated: `3469` + // Minimum execution time: 30_728_000 picoseconds. + Weight::from_parts(31_794_924, 3469) + // Standard Error: 171 + .saturating_add(Weight::from_parts(1_020, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -85,9 +82,9 @@ impl WeightInfo for SubstrateWeight { fn retract_tip() -> Weight { // Proof Size summary in bytes: // Measured: `221` - // Estimated: `3907` - // Minimum execution time: 25_322_000 picoseconds. - Weight::from_parts(26_107_000, 3907) + // Estimated: `3686` + // Minimum execution time: 29_183_000 picoseconds. + Weight::from_parts(30_017_000, 3686) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -99,17 +96,19 @@ impl WeightInfo for SubstrateWeight { /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 300]`. /// The range of component `t` is `[1, 13]`. - fn tip_new(_r: u32, t: u32, ) -> Weight { + fn tip_new(r: u32, t: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `526 + t * (64 ±0)` - // Estimated: `6528 + t * (192 ±0)` - // Minimum execution time: 21_112_000 picoseconds. - Weight::from_parts(21_825_317, 6528) - // Standard Error: 11_230 - .saturating_add(Weight::from_parts(86_081, 0).saturating_mul(t.into())) + // Estimated: `3991 + t * (64 ±0)` + // Minimum execution time: 20_726_000 picoseconds. + Weight::from_parts(20_964_411, 3991) + // Standard Error: 119 + .saturating_add(Weight::from_parts(1_230, 0).saturating_mul(r.into())) + // Standard Error: 2_837 + .saturating_add(Weight::from_parts(81_831, 0).saturating_mul(t.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) - .saturating_add(Weight::from_parts(0, 192).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(0, 64).saturating_mul(t.into())) } /// Storage: Elections Members (r:1 w:0) /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) @@ -119,14 +118,14 @@ impl WeightInfo for SubstrateWeight { fn tip(t: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `747 + t * (112 ±0)` - // Estimated: `6444 + t * (224 ±0)` - // Minimum execution time: 16_703_000 picoseconds. - Weight::from_parts(16_679_429, 6444) - // Standard Error: 18_088 - .saturating_add(Weight::from_parts(281_667, 0).saturating_mul(t.into())) + // Estimated: `4212 + t * (112 ±0)` + // Minimum execution time: 16_048_000 picoseconds. + Weight::from_parts(16_694_981, 4212) + // Standard Error: 4_480 + .saturating_add(Weight::from_parts(179_723, 0).saturating_mul(t.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) - .saturating_add(Weight::from_parts(0, 224).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(0, 112).saturating_mul(t.into())) } /// Storage: Tips Tips (r:1 w:1) /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) @@ -140,26 +139,28 @@ impl WeightInfo for SubstrateWeight { fn close_tip(t: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `786 + t * (112 ±0)` - // Estimated: `10874 + t * (336 ±0)` - // Minimum execution time: 46_106_000 picoseconds. - Weight::from_parts(47_844_269, 10874) - // Standard Error: 9_247 - .saturating_add(Weight::from_parts(87_804, 0).saturating_mul(t.into())) + // Estimated: `4242 + t * (112 ±0)` + // Minimum execution time: 61_319_000 picoseconds. + Weight::from_parts(62_217_195, 4242) + // Standard Error: 6_721 + .saturating_add(Weight::from_parts(186_620, 0).saturating_mul(t.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 336).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(0, 112).saturating_mul(t.into())) } /// Storage: Tips Tips (r:1 w:1) /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) /// Storage: Tips Reasons (r:0 w:1) /// Proof Skipped: Tips Reasons (max_values: None, max_size: None, mode: Measured) /// The range of component `t` is `[1, 13]`. - fn slash_tip(_t: u32, ) -> Weight { + fn slash_tip(t: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `269` - // Estimated: `4003` - // Minimum execution time: 15_508_000 picoseconds. - Weight::from_parts(16_207_284, 4003) + // Estimated: `3734` + // Minimum execution time: 15_397_000 picoseconds. + Weight::from_parts(15_942_494, 3734) + // Standard Error: 1_657 + .saturating_add(Weight::from_parts(4_128, 0).saturating_mul(t.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -175,11 +176,11 @@ impl WeightInfo for () { fn report_awesome(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `4` - // Estimated: `6938` - // Minimum execution time: 26_789_000 picoseconds. - Weight::from_parts(27_619_925, 6938) - // Standard Error: 168 - .saturating_add(Weight::from_parts(1_352, 0).saturating_mul(r.into())) + // Estimated: `3469` + // Minimum execution time: 30_728_000 picoseconds. + Weight::from_parts(31_794_924, 3469) + // Standard Error: 171 + .saturating_add(Weight::from_parts(1_020, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -190,9 +191,9 @@ impl WeightInfo for () { fn retract_tip() -> Weight { // Proof Size summary in bytes: // Measured: `221` - // Estimated: `3907` - // Minimum execution time: 25_322_000 picoseconds. - Weight::from_parts(26_107_000, 3907) + // Estimated: `3686` + // Minimum execution time: 29_183_000 picoseconds. + Weight::from_parts(30_017_000, 3686) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -204,17 +205,19 @@ impl WeightInfo for () { /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 300]`. /// The range of component `t` is `[1, 13]`. - fn tip_new(_r: u32, t: u32, ) -> Weight { + fn tip_new(r: u32, t: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `526 + t * (64 ±0)` - // Estimated: `6528 + t * (192 ±0)` - // Minimum execution time: 21_112_000 picoseconds. - Weight::from_parts(21_825_317, 6528) - // Standard Error: 11_230 - .saturating_add(Weight::from_parts(86_081, 0).saturating_mul(t.into())) + // Estimated: `3991 + t * (64 ±0)` + // Minimum execution time: 20_726_000 picoseconds. + Weight::from_parts(20_964_411, 3991) + // Standard Error: 119 + .saturating_add(Weight::from_parts(1_230, 0).saturating_mul(r.into())) + // Standard Error: 2_837 + .saturating_add(Weight::from_parts(81_831, 0).saturating_mul(t.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) - .saturating_add(Weight::from_parts(0, 192).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(0, 64).saturating_mul(t.into())) } /// Storage: Elections Members (r:1 w:0) /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) @@ -224,14 +227,14 @@ impl WeightInfo for () { fn tip(t: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `747 + t * (112 ±0)` - // Estimated: `6444 + t * (224 ±0)` - // Minimum execution time: 16_703_000 picoseconds. - Weight::from_parts(16_679_429, 6444) - // Standard Error: 18_088 - .saturating_add(Weight::from_parts(281_667, 0).saturating_mul(t.into())) + // Estimated: `4212 + t * (112 ±0)` + // Minimum execution time: 16_048_000 picoseconds. + Weight::from_parts(16_694_981, 4212) + // Standard Error: 4_480 + .saturating_add(Weight::from_parts(179_723, 0).saturating_mul(t.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) - .saturating_add(Weight::from_parts(0, 224).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(0, 112).saturating_mul(t.into())) } /// Storage: Tips Tips (r:1 w:1) /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) @@ -245,26 +248,28 @@ impl WeightInfo for () { fn close_tip(t: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `786 + t * (112 ±0)` - // Estimated: `10874 + t * (336 ±0)` - // Minimum execution time: 46_106_000 picoseconds. - Weight::from_parts(47_844_269, 10874) - // Standard Error: 9_247 - .saturating_add(Weight::from_parts(87_804, 0).saturating_mul(t.into())) + // Estimated: `4242 + t * (112 ±0)` + // Minimum execution time: 61_319_000 picoseconds. + Weight::from_parts(62_217_195, 4242) + // Standard Error: 6_721 + .saturating_add(Weight::from_parts(186_620, 0).saturating_mul(t.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 336).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(0, 112).saturating_mul(t.into())) } /// Storage: Tips Tips (r:1 w:1) /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) /// Storage: Tips Reasons (r:0 w:1) /// Proof Skipped: Tips Reasons (max_values: None, max_size: None, mode: Measured) /// The range of component `t` is `[1, 13]`. - fn slash_tip(_t: u32, ) -> Weight { + fn slash_tip(t: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `269` - // Estimated: `4003` - // Minimum execution time: 15_508_000 picoseconds. - Weight::from_parts(16_207_284, 4003) + // Estimated: `3734` + // Minimum execution time: 15_397_000 picoseconds. + Weight::from_parts(15_942_494, 3734) + // Standard Error: 1_657 + .saturating_add(Weight::from_parts(4_128, 0).saturating_mul(t.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } diff --git a/frame/transaction-storage/src/weights.rs b/frame/transaction-storage/src/weights.rs index 2845136b7d2a9..5103ac375e97a 100644 --- a/frame/transaction-storage/src/weights.rs +++ b/frame/transaction-storage/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_transaction_storage //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,9 +31,6 @@ // --steps=50 // --repeat=20 // --pallet=pallet_transaction_storage -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -69,11 +66,11 @@ impl WeightInfo for SubstrateWeight { fn store(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `176` - // Estimated: `41353` - // Minimum execution time: 33_286_000 picoseconds. - Weight::from_parts(33_596_000, 41353) + // Estimated: `38351` + // Minimum execution time: 36_983_000 picoseconds. + Weight::from_parts(37_296_000, 38351) // Standard Error: 2 - .saturating_add(Weight::from_parts(4_954, 0).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(4_908, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -88,9 +85,9 @@ impl WeightInfo for SubstrateWeight { fn renew() -> Weight { // Proof Size summary in bytes: // Measured: `326` - // Estimated: `81704` - // Minimum execution time: 41_892_000 picoseconds. - Weight::from_parts(42_802_000, 81704) + // Estimated: `40351` + // Minimum execution time: 44_637_000 picoseconds. + Weight::from_parts(45_464_000, 40351) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -107,9 +104,9 @@ impl WeightInfo for SubstrateWeight { fn check_proof_max() -> Weight { // Proof Size summary in bytes: // Measured: `37145` - // Estimated: `48332` - // Minimum execution time: 63_799_000 picoseconds. - Weight::from_parts(66_145_000, 48332) + // Estimated: `40351` + // Minimum execution time: 59_653_000 picoseconds. + Weight::from_parts(61_068_000, 40351) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -127,11 +124,11 @@ impl WeightInfo for () { fn store(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `176` - // Estimated: `41353` - // Minimum execution time: 33_286_000 picoseconds. - Weight::from_parts(33_596_000, 41353) + // Estimated: `38351` + // Minimum execution time: 36_983_000 picoseconds. + Weight::from_parts(37_296_000, 38351) // Standard Error: 2 - .saturating_add(Weight::from_parts(4_954, 0).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(4_908, 0).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -146,9 +143,9 @@ impl WeightInfo for () { fn renew() -> Weight { // Proof Size summary in bytes: // Measured: `326` - // Estimated: `81704` - // Minimum execution time: 41_892_000 picoseconds. - Weight::from_parts(42_802_000, 81704) + // Estimated: `40351` + // Minimum execution time: 44_637_000 picoseconds. + Weight::from_parts(45_464_000, 40351) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -165,9 +162,9 @@ impl WeightInfo for () { fn check_proof_max() -> Weight { // Proof Size summary in bytes: // Measured: `37145` - // Estimated: `48332` - // Minimum execution time: 63_799_000 picoseconds. - Weight::from_parts(66_145_000, 48332) + // Estimated: `40351` + // Minimum execution time: 59_653_000 picoseconds. + Weight::from_parts(61_068_000, 40351) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/frame/treasury/src/weights.rs b/frame/treasury/src/weights.rs index a7c093a8001ec..edf1a674f73ff 100644 --- a/frame/treasury/src/weights.rs +++ b/frame/treasury/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_treasury //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,9 +31,6 @@ // --steps=50 // --repeat=20 // --pallet=pallet_treasury -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -71,9 +68,9 @@ impl WeightInfo for SubstrateWeight { fn spend() -> Weight { // Proof Size summary in bytes: // Measured: `42` - // Estimated: `3376` - // Minimum execution time: 17_010_000 picoseconds. - Weight::from_parts(17_247_000, 3376) + // Estimated: `1887` + // Minimum execution time: 16_592_000 picoseconds. + Weight::from_parts(16_959_000, 1887) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -85,8 +82,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `143` // Estimated: `1489` - // Minimum execution time: 25_780_000 picoseconds. - Weight::from_parts(41_064_000, 1489) + // Minimum execution time: 29_742_000 picoseconds. + Weight::from_parts(30_359_000, 1489) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -97,9 +94,9 @@ impl WeightInfo for SubstrateWeight { fn reject_proposal() -> Weight { // Proof Size summary in bytes: // Measured: `301` - // Estimated: `7166` - // Minimum execution time: 27_805_000 picoseconds. - Weight::from_parts(28_322_000, 7166) + // Estimated: `3593` + // Minimum execution time: 31_248_000 picoseconds. + Weight::from_parts(31_882_000, 3593) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -111,11 +108,11 @@ impl WeightInfo for SubstrateWeight { fn approve_proposal(p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `470 + p * (8 ±0)` - // Estimated: `5460` - // Minimum execution time: 10_939_000 picoseconds. - Weight::from_parts(13_667_341, 5460) - // Standard Error: 907 - .saturating_add(Weight::from_parts(26_648, 0).saturating_mul(p.into())) + // Estimated: `3573` + // Minimum execution time: 10_441_000 picoseconds. + Weight::from_parts(13_061_079, 3573) + // Standard Error: 877 + .saturating_add(Weight::from_parts(26_940, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -125,8 +122,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `127` // Estimated: `1887` - // Minimum execution time: 8_261_000 picoseconds. - Weight::from_parts(8_399_000, 1887) + // Minimum execution time: 7_935_000 picoseconds. + Weight::from_parts(8_153_000, 1887) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -144,16 +141,16 @@ impl WeightInfo for SubstrateWeight { fn on_initialize_proposals(p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `387 + p * (251 ±0)` - // Estimated: `7255 + p * (7789 ±0)` - // Minimum execution time: 43_781_000 picoseconds. - Weight::from_parts(68_521_487, 7255) - // Standard Error: 58_804 - .saturating_add(Weight::from_parts(33_271_211, 0).saturating_mul(p.into())) + // Estimated: `1887 + p * (5206 ±0)` + // Minimum execution time: 45_306_000 picoseconds. + Weight::from_parts(53_639_830, 1887) + // Standard Error: 32_330 + .saturating_add(Weight::from_parts(38_930_307, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(p.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(p.into()))) - .saturating_add(Weight::from_parts(0, 7789).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 5206).saturating_mul(p.into())) } } @@ -168,9 +165,9 @@ impl WeightInfo for () { fn spend() -> Weight { // Proof Size summary in bytes: // Measured: `42` - // Estimated: `3376` - // Minimum execution time: 17_010_000 picoseconds. - Weight::from_parts(17_247_000, 3376) + // Estimated: `1887` + // Minimum execution time: 16_592_000 picoseconds. + Weight::from_parts(16_959_000, 1887) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -182,8 +179,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `143` // Estimated: `1489` - // Minimum execution time: 25_780_000 picoseconds. - Weight::from_parts(41_064_000, 1489) + // Minimum execution time: 29_742_000 picoseconds. + Weight::from_parts(30_359_000, 1489) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -194,9 +191,9 @@ impl WeightInfo for () { fn reject_proposal() -> Weight { // Proof Size summary in bytes: // Measured: `301` - // Estimated: `7166` - // Minimum execution time: 27_805_000 picoseconds. - Weight::from_parts(28_322_000, 7166) + // Estimated: `3593` + // Minimum execution time: 31_248_000 picoseconds. + Weight::from_parts(31_882_000, 3593) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -208,11 +205,11 @@ impl WeightInfo for () { fn approve_proposal(p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `470 + p * (8 ±0)` - // Estimated: `5460` - // Minimum execution time: 10_939_000 picoseconds. - Weight::from_parts(13_667_341, 5460) - // Standard Error: 907 - .saturating_add(Weight::from_parts(26_648, 0).saturating_mul(p.into())) + // Estimated: `3573` + // Minimum execution time: 10_441_000 picoseconds. + Weight::from_parts(13_061_079, 3573) + // Standard Error: 877 + .saturating_add(Weight::from_parts(26_940, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -222,8 +219,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `127` // Estimated: `1887` - // Minimum execution time: 8_261_000 picoseconds. - Weight::from_parts(8_399_000, 1887) + // Minimum execution time: 7_935_000 picoseconds. + Weight::from_parts(8_153_000, 1887) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -241,15 +238,15 @@ impl WeightInfo for () { fn on_initialize_proposals(p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `387 + p * (251 ±0)` - // Estimated: `7255 + p * (7789 ±0)` - // Minimum execution time: 43_781_000 picoseconds. - Weight::from_parts(68_521_487, 7255) - // Standard Error: 58_804 - .saturating_add(Weight::from_parts(33_271_211, 0).saturating_mul(p.into())) + // Estimated: `1887 + p * (5206 ±0)` + // Minimum execution time: 45_306_000 picoseconds. + Weight::from_parts(53_639_830, 1887) + // Standard Error: 32_330 + .saturating_add(Weight::from_parts(38_930_307, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(p.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(p.into()))) - .saturating_add(Weight::from_parts(0, 7789).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 5206).saturating_mul(p.into())) } } diff --git a/frame/uniques/src/weights.rs b/frame/uniques/src/weights.rs index 1f0e3772696f7..14a55d163e0ff 100644 --- a/frame/uniques/src/weights.rs +++ b/frame/uniques/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_uniques //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,9 +31,6 @@ // --steps=50 // --repeat=20 // --pallet=pallet_uniques -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -90,8 +87,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `249` // Estimated: `3643` - // Minimum execution time: 27_805_000 picoseconds. - Weight::from_parts(28_303_000, 3643) + // Minimum execution time: 32_067_000 picoseconds. + Weight::from_parts(32_817_000, 3643) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -103,8 +100,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `109` // Estimated: `3643` - // Minimum execution time: 16_257_000 picoseconds. - Weight::from_parts(16_626_000, 3643) + // Minimum execution time: 16_365_000 picoseconds. + Weight::from_parts(16_707_000, 3643) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -129,16 +126,16 @@ impl WeightInfo for SubstrateWeight { /// The range of component `a` is `[0, 1000]`. fn destroy(n: u32, m: u32, a: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `418 + n * (76 ±0) + m * (56 ±0) + a * (107 ±0)` - // Estimated: `9210 + n * (2597 ±0) + a * (2839 ±0) + m * (2583 ±0)` - // Minimum execution time: 2_510_772_000 picoseconds. - Weight::from_parts(2_522_511_000, 9210) - // Standard Error: 27_455 - .saturating_add(Weight::from_parts(6_708_827, 0).saturating_mul(n.into())) - // Standard Error: 27_455 - .saturating_add(Weight::from_parts(375_591, 0).saturating_mul(m.into())) - // Standard Error: 27_455 - .saturating_add(Weight::from_parts(251_697, 0).saturating_mul(a.into())) + // Measured: `418 + a * (107 ±0) + m * (56 ±0) + n * (76 ±0)` + // Estimated: `3643 + a * (2839 ±0) + m * (2583 ±0) + n * (2597 ±0)` + // Minimum execution time: 2_498_918_000 picoseconds. + Weight::from_parts(2_516_809_000, 3643) + // Standard Error: 26_297 + .saturating_add(Weight::from_parts(6_648_035, 0).saturating_mul(n.into())) + // Standard Error: 26_297 + .saturating_add(Weight::from_parts(354_268, 0).saturating_mul(m.into())) + // Standard Error: 26_297 + .saturating_add(Weight::from_parts(223_770, 0).saturating_mul(a.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(m.into()))) @@ -147,9 +144,9 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(m.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(a.into()))) - .saturating_add(Weight::from_parts(0, 2597).saturating_mul(n.into())) .saturating_add(Weight::from_parts(0, 2839).saturating_mul(a.into())) .saturating_add(Weight::from_parts(0, 2583).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 2597).saturating_mul(n.into())) } /// Storage: Uniques Asset (r:1 w:1) /// Proof: Uniques Asset (max_values: None, max_size: Some(122), added: 2597, mode: MaxEncodedLen) @@ -162,9 +159,9 @@ impl WeightInfo for SubstrateWeight { fn mint() -> Weight { // Proof Size summary in bytes: // Measured: `349` - // Estimated: `10719` - // Minimum execution time: 33_959_000 picoseconds. - Weight::from_parts(34_380_000, 10719) + // Estimated: `3643` + // Minimum execution time: 38_157_000 picoseconds. + Weight::from_parts(38_677_000, 3643) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -179,9 +176,9 @@ impl WeightInfo for SubstrateWeight { fn burn() -> Weight { // Proof Size summary in bytes: // Measured: `495` - // Estimated: `7230` - // Minimum execution time: 34_194_000 picoseconds. - Weight::from_parts(34_808_000, 7230) + // Estimated: `3643` + // Minimum execution time: 39_069_000 picoseconds. + Weight::from_parts(40_442_000, 3643) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -196,9 +193,9 @@ impl WeightInfo for SubstrateWeight { fn transfer() -> Weight { // Proof Size summary in bytes: // Measured: `495` - // Estimated: `7230` - // Minimum execution time: 27_841_000 picoseconds. - Weight::from_parts(28_263_000, 7230) + // Estimated: `3643` + // Minimum execution time: 28_085_000 picoseconds. + Weight::from_parts(28_403_000, 3643) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -210,11 +207,11 @@ impl WeightInfo for SubstrateWeight { fn redeposit(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `805 + i * (76 ±0)` - // Estimated: `4633 + i * (2597 ±0)` - // Minimum execution time: 15_577_000 picoseconds. - Weight::from_parts(15_706_000, 4633) - // Standard Error: 17_679 - .saturating_add(Weight::from_parts(14_173_779, 0).saturating_mul(i.into())) + // Estimated: `3643 + i * (2597 ±0)` + // Minimum execution time: 16_202_000 picoseconds. + Weight::from_parts(16_380_000, 3643) + // Standard Error: 18_639 + .saturating_add(Weight::from_parts(16_047_161, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(i.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) @@ -228,9 +225,9 @@ impl WeightInfo for SubstrateWeight { fn freeze() -> Weight { // Proof Size summary in bytes: // Measured: `495` - // Estimated: `7230` - // Minimum execution time: 19_474_000 picoseconds. - Weight::from_parts(19_807_000, 7230) + // Estimated: `3643` + // Minimum execution time: 20_131_000 picoseconds. + Weight::from_parts(20_535_000, 3643) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -241,9 +238,9 @@ impl WeightInfo for SubstrateWeight { fn thaw() -> Weight { // Proof Size summary in bytes: // Measured: `495` - // Estimated: `7230` - // Minimum execution time: 19_526_000 picoseconds. - Weight::from_parts(19_818_000, 7230) + // Estimated: `3643` + // Minimum execution time: 19_895_000 picoseconds. + Weight::from_parts(20_198_000, 3643) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -253,8 +250,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `349` // Estimated: `3643` - // Minimum execution time: 15_324_000 picoseconds. - Weight::from_parts(15_599_000, 3643) + // Minimum execution time: 15_312_000 picoseconds. + Weight::from_parts(15_555_000, 3643) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -264,8 +261,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `349` // Estimated: `3643` - // Minimum execution time: 15_294_000 picoseconds. - Weight::from_parts(15_504_000, 3643) + // Minimum execution time: 15_145_000 picoseconds. + Weight::from_parts(15_371_000, 3643) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -278,9 +275,9 @@ impl WeightInfo for SubstrateWeight { fn transfer_ownership() -> Weight { // Proof Size summary in bytes: // Measured: `423` - // Estimated: `7160` - // Minimum execution time: 24_007_000 picoseconds. - Weight::from_parts(24_555_000, 7160) + // Estimated: `3643` + // Minimum execution time: 23_800_000 picoseconds. + Weight::from_parts(23_991_000, 3643) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -290,8 +287,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `349` // Estimated: `3643` - // Minimum execution time: 15_616_000 picoseconds. - Weight::from_parts(15_897_000, 3643) + // Minimum execution time: 15_929_000 picoseconds. + Weight::from_parts(16_219_000, 3643) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -303,8 +300,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `349` // Estimated: `3643` - // Minimum execution time: 18_459_000 picoseconds. - Weight::from_parts(18_705_000, 3643) + // Minimum execution time: 18_617_000 picoseconds. + Weight::from_parts(19_016_000, 3643) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -317,9 +314,9 @@ impl WeightInfo for SubstrateWeight { fn set_attribute() -> Weight { // Proof Size summary in bytes: // Measured: `547` - // Estimated: `11045` - // Minimum execution time: 39_056_000 picoseconds. - Weight::from_parts(39_513_000, 11045) + // Estimated: `3829` + // Minimum execution time: 41_982_000 picoseconds. + Weight::from_parts(42_329_000, 3829) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -332,9 +329,9 @@ impl WeightInfo for SubstrateWeight { fn clear_attribute() -> Weight { // Proof Size summary in bytes: // Measured: `936` - // Estimated: `11045` - // Minimum execution time: 37_441_000 picoseconds. - Weight::from_parts(37_859_000, 11045) + // Estimated: `3829` + // Minimum execution time: 39_921_000 picoseconds. + Weight::from_parts(40_499_000, 3829) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -345,9 +342,9 @@ impl WeightInfo for SubstrateWeight { fn set_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `415` - // Estimated: `7216` - // Minimum execution time: 29_456_000 picoseconds. - Weight::from_parts(29_930_000, 7216) + // Estimated: `3643` + // Minimum execution time: 31_774_000 picoseconds. + Weight::from_parts(32_327_000, 3643) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -358,9 +355,9 @@ impl WeightInfo for SubstrateWeight { fn clear_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `547` - // Estimated: `7216` - // Minimum execution time: 29_817_000 picoseconds. - Weight::from_parts(30_364_000, 7216) + // Estimated: `3643` + // Minimum execution time: 32_551_000 picoseconds. + Weight::from_parts(32_891_000, 3643) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -371,9 +368,9 @@ impl WeightInfo for SubstrateWeight { fn set_collection_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `349` - // Estimated: `7196` - // Minimum execution time: 29_392_000 picoseconds. - Weight::from_parts(29_878_000, 7196) + // Estimated: `3643` + // Minimum execution time: 33_490_000 picoseconds. + Weight::from_parts(34_617_000, 3643) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -384,9 +381,9 @@ impl WeightInfo for SubstrateWeight { fn clear_collection_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `461` - // Estimated: `7196` - // Minimum execution time: 27_234_000 picoseconds. - Weight::from_parts(27_664_000, 7196) + // Estimated: `3643` + // Minimum execution time: 31_691_000 picoseconds. + Weight::from_parts(32_042_000, 3643) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -397,9 +394,9 @@ impl WeightInfo for SubstrateWeight { fn approve_transfer() -> Weight { // Proof Size summary in bytes: // Measured: `495` - // Estimated: `7230` - // Minimum execution time: 20_447_000 picoseconds. - Weight::from_parts(20_886_000, 7230) + // Estimated: `3643` + // Minimum execution time: 20_738_000 picoseconds. + Weight::from_parts(21_067_000, 3643) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -410,9 +407,9 @@ impl WeightInfo for SubstrateWeight { fn cancel_approval() -> Weight { // Proof Size summary in bytes: // Measured: `528` - // Estimated: `7230` - // Minimum execution time: 20_934_000 picoseconds. - Weight::from_parts(21_271_000, 7230) + // Estimated: `3643` + // Minimum execution time: 20_404_000 picoseconds. + Weight::from_parts(20_999_000, 3643) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -422,8 +419,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `109` // Estimated: `3517` - // Minimum execution time: 17_004_000 picoseconds. - Weight::from_parts(17_401_000, 3517) + // Minimum execution time: 17_047_000 picoseconds. + Weight::from_parts(17_307_000, 3517) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -434,9 +431,9 @@ impl WeightInfo for SubstrateWeight { fn set_collection_max_supply() -> Weight { // Proof Size summary in bytes: // Measured: `349` - // Estimated: `7132` - // Minimum execution time: 17_371_000 picoseconds. - Weight::from_parts(18_103_000, 7132) + // Estimated: `3643` + // Minimum execution time: 17_829_000 picoseconds. + Weight::from_parts(18_194_000, 3643) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -448,8 +445,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `326` // Estimated: `3587` - // Minimum execution time: 17_624_000 picoseconds. - Weight::from_parts(17_866_000, 3587) + // Minimum execution time: 17_620_000 picoseconds. + Weight::from_parts(17_931_000, 3587) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -464,9 +461,9 @@ impl WeightInfo for SubstrateWeight { fn buy_item() -> Weight { // Proof Size summary in bytes: // Measured: `607` - // Estimated: `10784` - // Minimum execution time: 39_736_000 picoseconds. - Weight::from_parts(40_855_000, 10784) + // Estimated: `3643` + // Minimum execution time: 39_550_000 picoseconds. + Weight::from_parts(40_052_000, 3643) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -482,8 +479,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `249` // Estimated: `3643` - // Minimum execution time: 27_805_000 picoseconds. - Weight::from_parts(28_303_000, 3643) + // Minimum execution time: 32_067_000 picoseconds. + Weight::from_parts(32_817_000, 3643) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -495,8 +492,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `109` // Estimated: `3643` - // Minimum execution time: 16_257_000 picoseconds. - Weight::from_parts(16_626_000, 3643) + // Minimum execution time: 16_365_000 picoseconds. + Weight::from_parts(16_707_000, 3643) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -521,16 +518,16 @@ impl WeightInfo for () { /// The range of component `a` is `[0, 1000]`. fn destroy(n: u32, m: u32, a: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `418 + n * (76 ±0) + m * (56 ±0) + a * (107 ±0)` - // Estimated: `9210 + n * (2597 ±0) + a * (2839 ±0) + m * (2583 ±0)` - // Minimum execution time: 2_510_772_000 picoseconds. - Weight::from_parts(2_522_511_000, 9210) - // Standard Error: 27_455 - .saturating_add(Weight::from_parts(6_708_827, 0).saturating_mul(n.into())) - // Standard Error: 27_455 - .saturating_add(Weight::from_parts(375_591, 0).saturating_mul(m.into())) - // Standard Error: 27_455 - .saturating_add(Weight::from_parts(251_697, 0).saturating_mul(a.into())) + // Measured: `418 + a * (107 ±0) + m * (56 ±0) + n * (76 ±0)` + // Estimated: `3643 + a * (2839 ±0) + m * (2583 ±0) + n * (2597 ±0)` + // Minimum execution time: 2_498_918_000 picoseconds. + Weight::from_parts(2_516_809_000, 3643) + // Standard Error: 26_297 + .saturating_add(Weight::from_parts(6_648_035, 0).saturating_mul(n.into())) + // Standard Error: 26_297 + .saturating_add(Weight::from_parts(354_268, 0).saturating_mul(m.into())) + // Standard Error: 26_297 + .saturating_add(Weight::from_parts(223_770, 0).saturating_mul(a.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(m.into()))) @@ -539,9 +536,9 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().writes((2_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(m.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(a.into()))) - .saturating_add(Weight::from_parts(0, 2597).saturating_mul(n.into())) .saturating_add(Weight::from_parts(0, 2839).saturating_mul(a.into())) .saturating_add(Weight::from_parts(0, 2583).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 2597).saturating_mul(n.into())) } /// Storage: Uniques Asset (r:1 w:1) /// Proof: Uniques Asset (max_values: None, max_size: Some(122), added: 2597, mode: MaxEncodedLen) @@ -554,9 +551,9 @@ impl WeightInfo for () { fn mint() -> Weight { // Proof Size summary in bytes: // Measured: `349` - // Estimated: `10719` - // Minimum execution time: 33_959_000 picoseconds. - Weight::from_parts(34_380_000, 10719) + // Estimated: `3643` + // Minimum execution time: 38_157_000 picoseconds. + Weight::from_parts(38_677_000, 3643) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -571,9 +568,9 @@ impl WeightInfo for () { fn burn() -> Weight { // Proof Size summary in bytes: // Measured: `495` - // Estimated: `7230` - // Minimum execution time: 34_194_000 picoseconds. - Weight::from_parts(34_808_000, 7230) + // Estimated: `3643` + // Minimum execution time: 39_069_000 picoseconds. + Weight::from_parts(40_442_000, 3643) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -588,9 +585,9 @@ impl WeightInfo for () { fn transfer() -> Weight { // Proof Size summary in bytes: // Measured: `495` - // Estimated: `7230` - // Minimum execution time: 27_841_000 picoseconds. - Weight::from_parts(28_263_000, 7230) + // Estimated: `3643` + // Minimum execution time: 28_085_000 picoseconds. + Weight::from_parts(28_403_000, 3643) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -602,11 +599,11 @@ impl WeightInfo for () { fn redeposit(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `805 + i * (76 ±0)` - // Estimated: `4633 + i * (2597 ±0)` - // Minimum execution time: 15_577_000 picoseconds. - Weight::from_parts(15_706_000, 4633) - // Standard Error: 17_679 - .saturating_add(Weight::from_parts(14_173_779, 0).saturating_mul(i.into())) + // Estimated: `3643 + i * (2597 ±0)` + // Minimum execution time: 16_202_000 picoseconds. + Weight::from_parts(16_380_000, 3643) + // Standard Error: 18_639 + .saturating_add(Weight::from_parts(16_047_161, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(i.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) @@ -620,9 +617,9 @@ impl WeightInfo for () { fn freeze() -> Weight { // Proof Size summary in bytes: // Measured: `495` - // Estimated: `7230` - // Minimum execution time: 19_474_000 picoseconds. - Weight::from_parts(19_807_000, 7230) + // Estimated: `3643` + // Minimum execution time: 20_131_000 picoseconds. + Weight::from_parts(20_535_000, 3643) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -633,9 +630,9 @@ impl WeightInfo for () { fn thaw() -> Weight { // Proof Size summary in bytes: // Measured: `495` - // Estimated: `7230` - // Minimum execution time: 19_526_000 picoseconds. - Weight::from_parts(19_818_000, 7230) + // Estimated: `3643` + // Minimum execution time: 19_895_000 picoseconds. + Weight::from_parts(20_198_000, 3643) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -645,8 +642,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `349` // Estimated: `3643` - // Minimum execution time: 15_324_000 picoseconds. - Weight::from_parts(15_599_000, 3643) + // Minimum execution time: 15_312_000 picoseconds. + Weight::from_parts(15_555_000, 3643) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -656,8 +653,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `349` // Estimated: `3643` - // Minimum execution time: 15_294_000 picoseconds. - Weight::from_parts(15_504_000, 3643) + // Minimum execution time: 15_145_000 picoseconds. + Weight::from_parts(15_371_000, 3643) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -670,9 +667,9 @@ impl WeightInfo for () { fn transfer_ownership() -> Weight { // Proof Size summary in bytes: // Measured: `423` - // Estimated: `7160` - // Minimum execution time: 24_007_000 picoseconds. - Weight::from_parts(24_555_000, 7160) + // Estimated: `3643` + // Minimum execution time: 23_800_000 picoseconds. + Weight::from_parts(23_991_000, 3643) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -682,8 +679,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `349` // Estimated: `3643` - // Minimum execution time: 15_616_000 picoseconds. - Weight::from_parts(15_897_000, 3643) + // Minimum execution time: 15_929_000 picoseconds. + Weight::from_parts(16_219_000, 3643) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -695,8 +692,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `349` // Estimated: `3643` - // Minimum execution time: 18_459_000 picoseconds. - Weight::from_parts(18_705_000, 3643) + // Minimum execution time: 18_617_000 picoseconds. + Weight::from_parts(19_016_000, 3643) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -709,9 +706,9 @@ impl WeightInfo for () { fn set_attribute() -> Weight { // Proof Size summary in bytes: // Measured: `547` - // Estimated: `11045` - // Minimum execution time: 39_056_000 picoseconds. - Weight::from_parts(39_513_000, 11045) + // Estimated: `3829` + // Minimum execution time: 41_982_000 picoseconds. + Weight::from_parts(42_329_000, 3829) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -724,9 +721,9 @@ impl WeightInfo for () { fn clear_attribute() -> Weight { // Proof Size summary in bytes: // Measured: `936` - // Estimated: `11045` - // Minimum execution time: 37_441_000 picoseconds. - Weight::from_parts(37_859_000, 11045) + // Estimated: `3829` + // Minimum execution time: 39_921_000 picoseconds. + Weight::from_parts(40_499_000, 3829) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -737,9 +734,9 @@ impl WeightInfo for () { fn set_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `415` - // Estimated: `7216` - // Minimum execution time: 29_456_000 picoseconds. - Weight::from_parts(29_930_000, 7216) + // Estimated: `3643` + // Minimum execution time: 31_774_000 picoseconds. + Weight::from_parts(32_327_000, 3643) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -750,9 +747,9 @@ impl WeightInfo for () { fn clear_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `547` - // Estimated: `7216` - // Minimum execution time: 29_817_000 picoseconds. - Weight::from_parts(30_364_000, 7216) + // Estimated: `3643` + // Minimum execution time: 32_551_000 picoseconds. + Weight::from_parts(32_891_000, 3643) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -763,9 +760,9 @@ impl WeightInfo for () { fn set_collection_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `349` - // Estimated: `7196` - // Minimum execution time: 29_392_000 picoseconds. - Weight::from_parts(29_878_000, 7196) + // Estimated: `3643` + // Minimum execution time: 33_490_000 picoseconds. + Weight::from_parts(34_617_000, 3643) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -776,9 +773,9 @@ impl WeightInfo for () { fn clear_collection_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `461` - // Estimated: `7196` - // Minimum execution time: 27_234_000 picoseconds. - Weight::from_parts(27_664_000, 7196) + // Estimated: `3643` + // Minimum execution time: 31_691_000 picoseconds. + Weight::from_parts(32_042_000, 3643) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -789,9 +786,9 @@ impl WeightInfo for () { fn approve_transfer() -> Weight { // Proof Size summary in bytes: // Measured: `495` - // Estimated: `7230` - // Minimum execution time: 20_447_000 picoseconds. - Weight::from_parts(20_886_000, 7230) + // Estimated: `3643` + // Minimum execution time: 20_738_000 picoseconds. + Weight::from_parts(21_067_000, 3643) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -802,9 +799,9 @@ impl WeightInfo for () { fn cancel_approval() -> Weight { // Proof Size summary in bytes: // Measured: `528` - // Estimated: `7230` - // Minimum execution time: 20_934_000 picoseconds. - Weight::from_parts(21_271_000, 7230) + // Estimated: `3643` + // Minimum execution time: 20_404_000 picoseconds. + Weight::from_parts(20_999_000, 3643) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -814,8 +811,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `109` // Estimated: `3517` - // Minimum execution time: 17_004_000 picoseconds. - Weight::from_parts(17_401_000, 3517) + // Minimum execution time: 17_047_000 picoseconds. + Weight::from_parts(17_307_000, 3517) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -826,9 +823,9 @@ impl WeightInfo for () { fn set_collection_max_supply() -> Weight { // Proof Size summary in bytes: // Measured: `349` - // Estimated: `7132` - // Minimum execution time: 17_371_000 picoseconds. - Weight::from_parts(18_103_000, 7132) + // Estimated: `3643` + // Minimum execution time: 17_829_000 picoseconds. + Weight::from_parts(18_194_000, 3643) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -840,8 +837,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `326` // Estimated: `3587` - // Minimum execution time: 17_624_000 picoseconds. - Weight::from_parts(17_866_000, 3587) + // Minimum execution time: 17_620_000 picoseconds. + Weight::from_parts(17_931_000, 3587) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -856,9 +853,9 @@ impl WeightInfo for () { fn buy_item() -> Weight { // Proof Size summary in bytes: // Measured: `607` - // Estimated: `10784` - // Minimum execution time: 39_736_000 picoseconds. - Weight::from_parts(40_855_000, 10784) + // Estimated: `3643` + // Minimum execution time: 39_550_000 picoseconds. + Weight::from_parts(40_052_000, 3643) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } diff --git a/frame/utility/src/weights.rs b/frame/utility/src/weights.rs index 0c50de4f5df88..0ff261a33f362 100644 --- a/frame/utility/src/weights.rs +++ b/frame/utility/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_utility //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,9 +31,6 @@ // --steps=50 // --repeat=20 // --pallet=pallet_utility -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -66,44 +63,44 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_828_000 picoseconds. - Weight::from_parts(13_806_712, 0) - // Standard Error: 2_750 - .saturating_add(Weight::from_parts(4_169_287, 0).saturating_mul(c.into())) + // Minimum execution time: 7_932_000 picoseconds. + Weight::from_parts(24_064_040, 0) + // Standard Error: 2_486 + .saturating_add(Weight::from_parts(4_238_449, 0).saturating_mul(c.into())) } fn as_derivative() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_835_000 picoseconds. - Weight::from_parts(6_305_000, 0) + // Minimum execution time: 5_536_000 picoseconds. + Weight::from_parts(5_963_000, 0) } /// The range of component `c` is `[0, 1000]`. fn batch_all(c: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_010_000 picoseconds. - Weight::from_parts(10_539_696, 0) - // Standard Error: 2_681 - .saturating_add(Weight::from_parts(4_368_716, 0).saturating_mul(c.into())) + // Minimum execution time: 7_820_000 picoseconds. + Weight::from_parts(18_969_535, 0) + // Standard Error: 2_228 + .saturating_add(Weight::from_parts(4_448_073, 0).saturating_mul(c.into())) } fn dispatch_as() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 10_139_000 picoseconds. - Weight::from_parts(10_679_000, 0) + // Minimum execution time: 9_811_000 picoseconds. + Weight::from_parts(10_162_000, 0) } /// The range of component `c` is `[0, 1000]`. fn force_batch(c: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_960_000 picoseconds. - Weight::from_parts(16_874_350, 0) - // Standard Error: 3_040 - .saturating_add(Weight::from_parts(4_151_507, 0).saturating_mul(c.into())) + // Minimum execution time: 7_829_000 picoseconds. + Weight::from_parts(12_960_288, 0) + // Standard Error: 2_222 + .saturating_add(Weight::from_parts(4_272_019, 0).saturating_mul(c.into())) } } @@ -114,43 +111,43 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_828_000 picoseconds. - Weight::from_parts(13_806_712, 0) - // Standard Error: 2_750 - .saturating_add(Weight::from_parts(4_169_287, 0).saturating_mul(c.into())) + // Minimum execution time: 7_932_000 picoseconds. + Weight::from_parts(24_064_040, 0) + // Standard Error: 2_486 + .saturating_add(Weight::from_parts(4_238_449, 0).saturating_mul(c.into())) } fn as_derivative() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_835_000 picoseconds. - Weight::from_parts(6_305_000, 0) + // Minimum execution time: 5_536_000 picoseconds. + Weight::from_parts(5_963_000, 0) } /// The range of component `c` is `[0, 1000]`. fn batch_all(c: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_010_000 picoseconds. - Weight::from_parts(10_539_696, 0) - // Standard Error: 2_681 - .saturating_add(Weight::from_parts(4_368_716, 0).saturating_mul(c.into())) + // Minimum execution time: 7_820_000 picoseconds. + Weight::from_parts(18_969_535, 0) + // Standard Error: 2_228 + .saturating_add(Weight::from_parts(4_448_073, 0).saturating_mul(c.into())) } fn dispatch_as() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 10_139_000 picoseconds. - Weight::from_parts(10_679_000, 0) + // Minimum execution time: 9_811_000 picoseconds. + Weight::from_parts(10_162_000, 0) } /// The range of component `c` is `[0, 1000]`. fn force_batch(c: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_960_000 picoseconds. - Weight::from_parts(16_874_350, 0) - // Standard Error: 3_040 - .saturating_add(Weight::from_parts(4_151_507, 0).saturating_mul(c.into())) + // Minimum execution time: 7_829_000 picoseconds. + Weight::from_parts(12_960_288, 0) + // Standard Error: 2_222 + .saturating_add(Weight::from_parts(4_272_019, 0).saturating_mul(c.into())) } } diff --git a/frame/vesting/src/weights.rs b/frame/vesting/src/weights.rs index 400984f06823d..4cf3b3dcfbfd0 100644 --- a/frame/vesting/src/weights.rs +++ b/frame/vesting/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_vesting //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,9 +31,6 @@ // --steps=50 // --repeat=20 // --pallet=pallet_vesting -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -68,44 +65,50 @@ impl WeightInfo for SubstrateWeight { /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[1, 28]`. fn vest_locked(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `381 + l * (25 ±0) + s * (36 ±0)` - // Estimated: `9286` - // Minimum execution time: 31_657_000 picoseconds. - Weight::from_parts(30_569_947, 9286) - // Standard Error: 794 - .saturating_add(Weight::from_parts(63_114, 0).saturating_mul(l.into())) - // Standard Error: 1_413 - .saturating_add(Weight::from_parts(58_636, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(2_u64)) + // Estimated: `4764` + // Minimum execution time: 36_182_000 picoseconds. + Weight::from_parts(35_159_830, 4764) + // Standard Error: 952 + .saturating_add(Weight::from_parts(63_309, 0).saturating_mul(l.into())) + // Standard Error: 1_694 + .saturating_add(Weight::from_parts(62_244, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: Vesting Vesting (r:1 w:1) /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[1, 28]`. fn vest_unlocked(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `381 + l * (25 ±0) + s * (36 ±0)` - // Estimated: `9286` - // Minimum execution time: 30_474_000 picoseconds. - Weight::from_parts(30_227_344, 9286) - // Standard Error: 1_005 - .saturating_add(Weight::from_parts(56_742, 0).saturating_mul(l.into())) - // Standard Error: 1_788 - .saturating_add(Weight::from_parts(33_890, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(2_u64)) + // Estimated: `4764` + // Minimum execution time: 39_344_000 picoseconds. + Weight::from_parts(38_921_936, 4764) + // Standard Error: 1_283 + .saturating_add(Weight::from_parts(61_531, 0).saturating_mul(l.into())) + // Standard Error: 2_283 + .saturating_add(Weight::from_parts(36_175, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: Vesting Vesting (r:1 w:1) /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: System Account (r:1 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `l` is `[0, 49]`. @@ -113,20 +116,22 @@ impl WeightInfo for SubstrateWeight { fn vest_other_locked(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `484 + l * (25 ±0) + s * (36 ±0)` - // Estimated: `12879` - // Minimum execution time: 33_681_000 picoseconds. - Weight::from_parts(32_540_534, 12879) - // Standard Error: 2_642 - .saturating_add(Weight::from_parts(62_200, 0).saturating_mul(l.into())) - // Standard Error: 4_701 - .saturating_add(Weight::from_parts(69_703, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(3_u64)) + // Estimated: `4764` + // Minimum execution time: 39_461_000 picoseconds. + Weight::from_parts(38_206_465, 4764) + // Standard Error: 743 + .saturating_add(Weight::from_parts(56_973, 0).saturating_mul(l.into())) + // Standard Error: 1_322 + .saturating_add(Weight::from_parts(65_059, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: Vesting Vesting (r:1 w:1) /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: System Account (r:1 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `l` is `[0, 49]`. @@ -134,14 +139,14 @@ impl WeightInfo for SubstrateWeight { fn vest_other_unlocked(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `484 + l * (25 ±0) + s * (36 ±0)` - // Estimated: `12879` - // Minimum execution time: 32_255_000 picoseconds. - Weight::from_parts(31_637_918, 12879) - // Standard Error: 3_135 - .saturating_add(Weight::from_parts(62_121, 0).saturating_mul(l.into())) - // Standard Error: 5_579 - .saturating_add(Weight::from_parts(61_055, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(3_u64)) + // Estimated: `4764` + // Minimum execution time: 42_029_000 picoseconds. + Weight::from_parts(42_153_438, 4764) + // Standard Error: 1_108 + .saturating_add(Weight::from_parts(50_058, 0).saturating_mul(l.into())) + // Standard Error: 1_971 + .saturating_add(Weight::from_parts(32_391, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: Vesting Vesting (r:1 w:1) @@ -150,19 +155,21 @@ impl WeightInfo for SubstrateWeight { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[0, 27]`. fn vested_transfer(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `555 + l * (25 ±0) + s * (36 ±0)` - // Estimated: `12879` - // Minimum execution time: 51_697_000 picoseconds. - Weight::from_parts(52_048_055, 12879) - // Standard Error: 1_598 - .saturating_add(Weight::from_parts(60_508, 0).saturating_mul(l.into())) - // Standard Error: 2_843 - .saturating_add(Weight::from_parts(37_870, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(3_u64)) + // Estimated: `4764` + // Minimum execution time: 75_223_000 picoseconds. + Weight::from_parts(76_675_778, 4764) + // Standard Error: 2_534 + .saturating_add(Weight::from_parts(70_731, 0).saturating_mul(l.into())) + // Standard Error: 4_509 + .saturating_add(Weight::from_parts(108_866, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: Vesting Vesting (r:1 w:1) @@ -171,25 +178,29 @@ impl WeightInfo for SubstrateWeight { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[0, 27]`. fn force_vested_transfer(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `658 + l * (25 ±0) + s * (36 ±0)` - // Estimated: `15482` - // Minimum execution time: 54_585_000 picoseconds. - Weight::from_parts(54_492_070, 15482) - // Standard Error: 1_694 - .saturating_add(Weight::from_parts(52_633, 0).saturating_mul(l.into())) - // Standard Error: 3_014 - .saturating_add(Weight::from_parts(45_485, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(4_u64)) + // Estimated: `6196` + // Minimum execution time: 76_922_000 picoseconds. + Weight::from_parts(78_634_098, 6196) + // Standard Error: 2_099 + .saturating_add(Weight::from_parts(68_218, 0).saturating_mul(l.into())) + // Standard Error: 3_736 + .saturating_add(Weight::from_parts(95_990, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } /// Storage: Vesting Vesting (r:1 w:1) /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: System Account (r:1 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `l` is `[0, 49]`. @@ -197,20 +208,22 @@ impl WeightInfo for SubstrateWeight { fn not_unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `482 + l * (25 ±0) + s * (36 ±0)` - // Estimated: `12879` - // Minimum execution time: 34_312_000 picoseconds. - Weight::from_parts(33_740_101, 12879) - // Standard Error: 996 - .saturating_add(Weight::from_parts(62_123, 0).saturating_mul(l.into())) - // Standard Error: 1_841 - .saturating_add(Weight::from_parts(56_463, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(3_u64)) + // Estimated: `4764` + // Minimum execution time: 39_476_000 picoseconds. + Weight::from_parts(38_261_747, 4764) + // Standard Error: 1_794 + .saturating_add(Weight::from_parts(69_639, 0).saturating_mul(l.into())) + // Standard Error: 3_313 + .saturating_add(Weight::from_parts(73_202, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: Vesting Vesting (r:1 w:1) /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: System Account (r:1 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `l` is `[0, 49]`. @@ -218,14 +231,14 @@ impl WeightInfo for SubstrateWeight { fn unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `482 + l * (25 ±0) + s * (36 ±0)` - // Estimated: `12879` - // Minimum execution time: 34_965_000 picoseconds. - Weight::from_parts(33_831_484, 12879) - // Standard Error: 1_530 - .saturating_add(Weight::from_parts(59_136, 0).saturating_mul(l.into())) - // Standard Error: 2_827 - .saturating_add(Weight::from_parts(58_493, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(3_u64)) + // Estimated: `4764` + // Minimum execution time: 43_764_000 picoseconds. + Weight::from_parts(42_679_386, 4764) + // Standard Error: 1_224 + .saturating_add(Weight::from_parts(65_857, 0).saturating_mul(l.into())) + // Standard Error: 2_261 + .saturating_add(Weight::from_parts(70_861, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } } @@ -236,44 +249,50 @@ impl WeightInfo for () { /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[1, 28]`. fn vest_locked(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `381 + l * (25 ±0) + s * (36 ±0)` - // Estimated: `9286` - // Minimum execution time: 31_657_000 picoseconds. - Weight::from_parts(30_569_947, 9286) - // Standard Error: 794 - .saturating_add(Weight::from_parts(63_114, 0).saturating_mul(l.into())) - // Standard Error: 1_413 - .saturating_add(Weight::from_parts(58_636, 0).saturating_mul(s.into())) - .saturating_add(RocksDbWeight::get().reads(2_u64)) + // Estimated: `4764` + // Minimum execution time: 36_182_000 picoseconds. + Weight::from_parts(35_159_830, 4764) + // Standard Error: 952 + .saturating_add(Weight::from_parts(63_309, 0).saturating_mul(l.into())) + // Standard Error: 1_694 + .saturating_add(Weight::from_parts(62_244, 0).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: Vesting Vesting (r:1 w:1) /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[1, 28]`. fn vest_unlocked(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `381 + l * (25 ±0) + s * (36 ±0)` - // Estimated: `9286` - // Minimum execution time: 30_474_000 picoseconds. - Weight::from_parts(30_227_344, 9286) - // Standard Error: 1_005 - .saturating_add(Weight::from_parts(56_742, 0).saturating_mul(l.into())) - // Standard Error: 1_788 - .saturating_add(Weight::from_parts(33_890, 0).saturating_mul(s.into())) - .saturating_add(RocksDbWeight::get().reads(2_u64)) + // Estimated: `4764` + // Minimum execution time: 39_344_000 picoseconds. + Weight::from_parts(38_921_936, 4764) + // Standard Error: 1_283 + .saturating_add(Weight::from_parts(61_531, 0).saturating_mul(l.into())) + // Standard Error: 2_283 + .saturating_add(Weight::from_parts(36_175, 0).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: Vesting Vesting (r:1 w:1) /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: System Account (r:1 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `l` is `[0, 49]`. @@ -281,20 +300,22 @@ impl WeightInfo for () { fn vest_other_locked(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `484 + l * (25 ±0) + s * (36 ±0)` - // Estimated: `12879` - // Minimum execution time: 33_681_000 picoseconds. - Weight::from_parts(32_540_534, 12879) - // Standard Error: 2_642 - .saturating_add(Weight::from_parts(62_200, 0).saturating_mul(l.into())) - // Standard Error: 4_701 - .saturating_add(Weight::from_parts(69_703, 0).saturating_mul(s.into())) - .saturating_add(RocksDbWeight::get().reads(3_u64)) + // Estimated: `4764` + // Minimum execution time: 39_461_000 picoseconds. + Weight::from_parts(38_206_465, 4764) + // Standard Error: 743 + .saturating_add(Weight::from_parts(56_973, 0).saturating_mul(l.into())) + // Standard Error: 1_322 + .saturating_add(Weight::from_parts(65_059, 0).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: Vesting Vesting (r:1 w:1) /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: System Account (r:1 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `l` is `[0, 49]`. @@ -302,14 +323,14 @@ impl WeightInfo for () { fn vest_other_unlocked(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `484 + l * (25 ±0) + s * (36 ±0)` - // Estimated: `12879` - // Minimum execution time: 32_255_000 picoseconds. - Weight::from_parts(31_637_918, 12879) - // Standard Error: 3_135 - .saturating_add(Weight::from_parts(62_121, 0).saturating_mul(l.into())) - // Standard Error: 5_579 - .saturating_add(Weight::from_parts(61_055, 0).saturating_mul(s.into())) - .saturating_add(RocksDbWeight::get().reads(3_u64)) + // Estimated: `4764` + // Minimum execution time: 42_029_000 picoseconds. + Weight::from_parts(42_153_438, 4764) + // Standard Error: 1_108 + .saturating_add(Weight::from_parts(50_058, 0).saturating_mul(l.into())) + // Standard Error: 1_971 + .saturating_add(Weight::from_parts(32_391, 0).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: Vesting Vesting (r:1 w:1) @@ -318,19 +339,21 @@ impl WeightInfo for () { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[0, 27]`. fn vested_transfer(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `555 + l * (25 ±0) + s * (36 ±0)` - // Estimated: `12879` - // Minimum execution time: 51_697_000 picoseconds. - Weight::from_parts(52_048_055, 12879) - // Standard Error: 1_598 - .saturating_add(Weight::from_parts(60_508, 0).saturating_mul(l.into())) - // Standard Error: 2_843 - .saturating_add(Weight::from_parts(37_870, 0).saturating_mul(s.into())) - .saturating_add(RocksDbWeight::get().reads(3_u64)) + // Estimated: `4764` + // Minimum execution time: 75_223_000 picoseconds. + Weight::from_parts(76_675_778, 4764) + // Standard Error: 2_534 + .saturating_add(Weight::from_parts(70_731, 0).saturating_mul(l.into())) + // Standard Error: 4_509 + .saturating_add(Weight::from_parts(108_866, 0).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: Vesting Vesting (r:1 w:1) @@ -339,25 +362,29 @@ impl WeightInfo for () { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[0, 27]`. fn force_vested_transfer(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `658 + l * (25 ±0) + s * (36 ±0)` - // Estimated: `15482` - // Minimum execution time: 54_585_000 picoseconds. - Weight::from_parts(54_492_070, 15482) - // Standard Error: 1_694 - .saturating_add(Weight::from_parts(52_633, 0).saturating_mul(l.into())) - // Standard Error: 3_014 - .saturating_add(Weight::from_parts(45_485, 0).saturating_mul(s.into())) - .saturating_add(RocksDbWeight::get().reads(4_u64)) + // Estimated: `6196` + // Minimum execution time: 76_922_000 picoseconds. + Weight::from_parts(78_634_098, 6196) + // Standard Error: 2_099 + .saturating_add(Weight::from_parts(68_218, 0).saturating_mul(l.into())) + // Standard Error: 3_736 + .saturating_add(Weight::from_parts(95_990, 0).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } /// Storage: Vesting Vesting (r:1 w:1) /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: System Account (r:1 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `l` is `[0, 49]`. @@ -365,20 +392,22 @@ impl WeightInfo for () { fn not_unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `482 + l * (25 ±0) + s * (36 ±0)` - // Estimated: `12879` - // Minimum execution time: 34_312_000 picoseconds. - Weight::from_parts(33_740_101, 12879) - // Standard Error: 996 - .saturating_add(Weight::from_parts(62_123, 0).saturating_mul(l.into())) - // Standard Error: 1_841 - .saturating_add(Weight::from_parts(56_463, 0).saturating_mul(s.into())) - .saturating_add(RocksDbWeight::get().reads(3_u64)) + // Estimated: `4764` + // Minimum execution time: 39_476_000 picoseconds. + Weight::from_parts(38_261_747, 4764) + // Standard Error: 1_794 + .saturating_add(Weight::from_parts(69_639, 0).saturating_mul(l.into())) + // Standard Error: 3_313 + .saturating_add(Weight::from_parts(73_202, 0).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: Vesting Vesting (r:1 w:1) /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) /// Storage: Balances Locks (r:1 w:1) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// Storage: System Account (r:1 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `l` is `[0, 49]`. @@ -386,14 +415,14 @@ impl WeightInfo for () { fn unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `482 + l * (25 ±0) + s * (36 ±0)` - // Estimated: `12879` - // Minimum execution time: 34_965_000 picoseconds. - Weight::from_parts(33_831_484, 12879) - // Standard Error: 1_530 - .saturating_add(Weight::from_parts(59_136, 0).saturating_mul(l.into())) - // Standard Error: 2_827 - .saturating_add(Weight::from_parts(58_493, 0).saturating_mul(s.into())) - .saturating_add(RocksDbWeight::get().reads(3_u64)) + // Estimated: `4764` + // Minimum execution time: 43_764_000 picoseconds. + Weight::from_parts(42_679_386, 4764) + // Standard Error: 1_224 + .saturating_add(Weight::from_parts(65_857, 0).saturating_mul(l.into())) + // Standard Error: 2_261 + .saturating_add(Weight::from_parts(70_861, 0).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } } diff --git a/frame/whitelist/src/weights.rs b/frame/whitelist/src/weights.rs index 536cd188761b1..8636ea376e246 100644 --- a/frame/whitelist/src/weights.rs +++ b/frame/whitelist/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_whitelist //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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: @@ -31,9 +31,6 @@ // --steps=50 // --repeat=20 // --pallet=pallet_whitelist -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --execution=wasm // --wasm-execution=compiled @@ -67,9 +64,9 @@ impl WeightInfo for SubstrateWeight { fn whitelist_call() -> Weight { // Proof Size summary in bytes: // Measured: `217` - // Estimated: `7061` - // Minimum execution time: 21_530_000 picoseconds. - Weight::from_parts(21_986_000, 7061) + // Estimated: `3556` + // Minimum execution time: 21_370_000 picoseconds. + Weight::from_parts(21_834_000, 3556) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -80,9 +77,9 @@ impl WeightInfo for SubstrateWeight { fn remove_whitelisted_call() -> Weight { // Proof Size summary in bytes: // Measured: `346` - // Estimated: `7061` - // Minimum execution time: 18_980_000 picoseconds. - Weight::from_parts(19_474_000, 7061) + // Estimated: `3556` + // Minimum execution time: 19_222_000 picoseconds. + Weight::from_parts(19_582_000, 3556) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -96,11 +93,11 @@ impl WeightInfo for SubstrateWeight { fn dispatch_whitelisted_call(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `422 + n * (1 ±0)` - // Estimated: `10947 + n * (1 ±0)` - // Minimum execution time: 32_377_000 picoseconds. - Weight::from_parts(32_643_000, 10947) - // Standard Error: 0 - .saturating_add(Weight::from_parts(1_147, 0).saturating_mul(n.into())) + // Estimated: `3886 + n * (1 ±0)` + // Minimum execution time: 31_417_000 picoseconds. + Weight::from_parts(31_620_000, 3886) + // Standard Error: 1 + .saturating_add(Weight::from_parts(1_145, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -113,11 +110,11 @@ impl WeightInfo for SubstrateWeight { fn dispatch_whitelisted_call_with_preimage(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `346` - // Estimated: `7061` - // Minimum execution time: 23_421_000 picoseconds. - Weight::from_parts(24_488_523, 7061) + // Estimated: `3556` + // Minimum execution time: 23_092_000 picoseconds. + Weight::from_parts(24_043_432, 3556) // Standard Error: 5 - .saturating_add(Weight::from_parts(1_217, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(1_227, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -132,9 +129,9 @@ impl WeightInfo for () { fn whitelist_call() -> Weight { // Proof Size summary in bytes: // Measured: `217` - // Estimated: `7061` - // Minimum execution time: 21_530_000 picoseconds. - Weight::from_parts(21_986_000, 7061) + // Estimated: `3556` + // Minimum execution time: 21_370_000 picoseconds. + Weight::from_parts(21_834_000, 3556) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -145,9 +142,9 @@ impl WeightInfo for () { fn remove_whitelisted_call() -> Weight { // Proof Size summary in bytes: // Measured: `346` - // Estimated: `7061` - // Minimum execution time: 18_980_000 picoseconds. - Weight::from_parts(19_474_000, 7061) + // Estimated: `3556` + // Minimum execution time: 19_222_000 picoseconds. + Weight::from_parts(19_582_000, 3556) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -161,11 +158,11 @@ impl WeightInfo for () { fn dispatch_whitelisted_call(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `422 + n * (1 ±0)` - // Estimated: `10947 + n * (1 ±0)` - // Minimum execution time: 32_377_000 picoseconds. - Weight::from_parts(32_643_000, 10947) - // Standard Error: 0 - .saturating_add(Weight::from_parts(1_147, 0).saturating_mul(n.into())) + // Estimated: `3886 + n * (1 ±0)` + // Minimum execution time: 31_417_000 picoseconds. + Weight::from_parts(31_620_000, 3886) + // Standard Error: 1 + .saturating_add(Weight::from_parts(1_145, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -178,11 +175,11 @@ impl WeightInfo for () { fn dispatch_whitelisted_call_with_preimage(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `346` - // Estimated: `7061` - // Minimum execution time: 23_421_000 picoseconds. - Weight::from_parts(24_488_523, 7061) + // Estimated: `3556` + // Minimum execution time: 23_092_000 picoseconds. + Weight::from_parts(24_043_432, 3556) // Standard Error: 5 - .saturating_add(Weight::from_parts(1_217, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(1_227, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } diff --git a/scripts/run_all_benchmarks.sh b/scripts/run_all_benchmarks.sh index b632cb5c12f04..727b49e26afe5 100755 --- a/scripts/run_all_benchmarks.sh +++ b/scripts/run_all_benchmarks.sh @@ -59,7 +59,7 @@ done if [ "$skip_build" != true ] then echo "[+] Compiling Substrate benchmarks..." - cargo build --profile=production --locked --features=runtime-benchmarks + cargo build --profile=production --locked --features=runtime-benchmarks --bin substrate fi # The executable to use. diff --git a/utils/frame/benchmarking-cli/src/pallet/command.rs b/utils/frame/benchmarking-cli/src/pallet/command.rs index 0c3b6b3e8f45c..08bcf3ee5a6b5 100644 --- a/utils/frame/benchmarking-cli/src/pallet/command.rs +++ b/utils/frame/benchmarking-cli/src/pallet/command.rs @@ -473,7 +473,7 @@ impl PalletCmd { log::info!( target: LOG_TARGET, - "Running Benchmark: {}.{}({} args) {}/{} {}/{}", + "Running benchmark: {}.{}({} args) {}/{} {}/{}", String::from_utf8(pallet.clone()) .expect("Encoded from String; qed"), String::from_utf8(extrinsic.clone()) diff --git a/utils/frame/benchmarking-cli/src/pallet/writer.rs b/utils/frame/benchmarking-cli/src/pallet/writer.rs index a609f9e38c0ce..89cce45627e68 100644 --- a/utils/frame/benchmarking-cli/src/pallet/writer.rs +++ b/utils/frame/benchmarking-cli/src/pallet/writer.rs @@ -278,6 +278,7 @@ fn get_benchmark_data( used_recorded_proof_size.push(ComponentSlope { name: name.clone(), slope, error }); } }); + used_recorded_proof_size.sort_by(|a, b| a.name.cmp(&b.name)); // We add additional comments showing which storage items were touched. // We find the worst case proof size, and use that as the final proof size result. @@ -315,12 +316,12 @@ fn get_benchmark_data( let mut base_calculated_proof_size = 0; // Sum up the proof sizes per component for (_, slope, base) in proof_size_per_components.iter() { - base_calculated_proof_size += base; + base_calculated_proof_size = base_calculated_proof_size.max(*base); for component in slope.iter() { let mut found = false; for used_component in used_calculated_proof_size.iter_mut() { if used_component.name == component.name { - used_component.slope += component.slope; + used_component.slope = used_component.slope.max(component.slope); found = true; break } @@ -337,6 +338,7 @@ fn get_benchmark_data( } } } + used_calculated_proof_size.sort_by(|a, b| a.name.cmp(&b.name)); // This puts a marker on any component which is entirely unused in the weight formula. let components = batch.time_results[0] @@ -626,7 +628,7 @@ pub(crate) fn process_storage_results( }, }; // Add the additional trie layer overhead for every new prefix. - if *reads > 0 { + if *reads > 0 && !is_all_ignored { prefix_result.proof_size += 15 * 33 * additional_trie_layers as u32; } storage_per_prefix.entry(prefix.clone()).or_default().push(prefix_result); From 7f930c23a8458f360625c9e5e0e1446edbcbb957 Mon Sep 17 00:00:00 2001 From: Sasha Gryaznov Date: Thu, 13 Apr 2023 16:57:28 +0300 Subject: [PATCH 647/715] stabilize call_runtime (#13901) --- frame/contracts/src/wasm/runtime.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index 19eb0fb50739b..bfb991ae51dfa 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -2404,8 +2404,6 @@ pub mod env { /// - Provide functionality **exclusively** to contracts. /// - Provide custom weights. /// - Avoid the need to keep the `Call` data structure stable. - #[unstable] - #[prefixed_alias] fn call_runtime( ctx: _, memory: _, From 186db7a7785ab74e15457d57072660344f237c2b Mon Sep 17 00:00:00 2001 From: Mira Ressel Date: Thu, 13 Apr 2023 19:14:44 +0200 Subject: [PATCH 648/715] fix .test-refs-check-benches condition (#13906) This check is meant to catch pipelines triggered by the scripts ci-linux staging tests. The correct CI_PIPELINE_SOURCE for multi-project pipelines such as this is "pipeline"; "parent_pipeline" is only set for child pipelines triggered /within the same repo/. cf https://docs.gitlab.com/ee/ci/jobs/job_control.html#common-if-clauses-for-rules --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 470ce2ce3180e..30a584635f367 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -179,7 +179,7 @@ variables: # 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 == "pipeline" && $CI_IMAGE =~ /staging$/ when: never - if: $CI_PIPELINE_SOURCE == "web" - if: $CI_PIPELINE_SOURCE == "schedule" From b5b57513f64193bbe43b5bee69c950e78af9a5f6 Mon Sep 17 00:00:00 2001 From: Mira Ressel Date: Thu, 13 Apr 2023 19:14:55 +0200 Subject: [PATCH 649/715] Disable timestamping for the crate publishing jobs (#13910) --- .gitlab-ci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 30a584635f367..a8687216feba9 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -259,6 +259,9 @@ variables: - artifacts/ variables: SPUB_TMP: artifacts + # disable timestamping for the crate publishing jobs, they leave stray child processes behind + # which don't interact well with the timestamping script + CI_DISABLE_TIMESTAMP: 1 #### stage: .pre From a49292aa6c1853ea70d22dbfda31e42159d1b43b Mon Sep 17 00:00:00 2001 From: Mira Ressel Date: Thu, 13 Apr 2023 20:17:12 +0200 Subject: [PATCH 650/715] Refactor the automatic-crate-publishing logic, make triggered pipelines uninterruptible as well (#13908) * Use a new approach to make automatic-crate-publishing uninterruptible It's not neccessary to dynamically change the `interruptible` setting for *all* jobs as the old approach does; gitlab already considers a pipeline uninterruptible as soon as a single uninterruptible job has started (cf https://docs.gitlab.com/ee/ci/yaml/#interruptible). IMO this approach is more readable, as it avoids dynamically loading the .defaults section from different files based on import conditions; the logic is now shorter and entirely contained in the main .gitlab-ci.yml. * Make triggered multi-project pipelines uninterruptible --- .gitlab-ci.yml | 42 +++++++++---------- .../ci/gitlab/crate-publishing-pipeline.yml | 1 - scripts/ci/gitlab/default-pipeline.yml | 1 - 3 files changed, 19 insertions(+), 25 deletions(-) delete mode 100644 scripts/ci/gitlab/crate-publishing-pipeline.yml delete mode 100644 scripts/ci/gitlab/default-pipeline.yml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a8687216feba9..e7b0093184cd3 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -58,7 +58,7 @@ variables: NEXTEST_SUCCESS_OUTPUT: final ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.3.43" -.shared-default: &shared-default +default: retry: max: 2 when: @@ -66,21 +66,7 @@ variables: - unknown_failure - api_failure cache: {} - -.default-pipeline-definitions: - default: - <<: *shared-default - interruptible: true - -.crate-publishing-pipeline-definitions: - default: - <<: *shared-default - # The crate-publishing pipeline defaults to `interruptible: false` so that we'll be able to - # reach and run the publishing jobs despite the "Auto-cancel redundant pipelines" CI setting. - # The setting is relevant because the crate-publishing pipeline runs on `master`, thus future - # pipelines on `master` (e.g. created for new commits or other schedules) might unintendedly - # cancel the publishing jobs or its dependencies before we get to actually publish the crates. - interruptible: false + interruptible: true .collect-artifacts: artifacts: @@ -291,6 +277,23 @@ check-crates-publishing-pipeline: https://github.com/paritytech/releng-scripts.git - ONLY_CHECK_PIPELINE=true ./releng-scripts/publish-crates +# By default our pipelines are interruptible, but some special pipelines shouldn't be interrupted: +# * multi-project pipelines such as the ones triggered by the scripts repo +# * the scheduled automatic-crate-publishing pipeline +# +# In those cases, we add an uninterruptible .pre job; once that one has started, +# the entire pipeline becomes uninterruptible +uninterruptible-pipeline: + extends: .kubernetes-env + variables: + CI_IMAGE: "paritytech/tools:latest" + stage: .pre + interruptible: false + rules: + - if: $CI_PIPELINE_SOURCE == "pipeline" + - if: $CI_PIPELINE_SOURCE == "schedule" && $PIPELINE == "automatic-crate-publishing" + script: "true" + include: # check jobs - scripts/ci/gitlab/pipeline/check.yml @@ -311,13 +314,6 @@ include: # pipeline is made uninterruptible to ensure that test jobs also get a chance to run to # completion, because the publishing jobs depends on them AS INTENDED: crates should not be # published before their source code is checked. - - local: scripts/ci/gitlab/crate-publishing-pipeline.yml - rules: - - if: $PIPELINE == "automatic-crate-publishing" - # For normal pipelines: run it with defaults + `interruptible: true` - - local: scripts/ci/gitlab/default-pipeline.yml - rules: - - if: $PIPELINE != "automatic-crate-publishing" - project: parity/infrastructure/ci_cd/shared ref: v0.2 file: /common/timestamp.yml diff --git a/scripts/ci/gitlab/crate-publishing-pipeline.yml b/scripts/ci/gitlab/crate-publishing-pipeline.yml deleted file mode 100644 index 9d5303952e6ef..0000000000000 --- a/scripts/ci/gitlab/crate-publishing-pipeline.yml +++ /dev/null @@ -1 +0,0 @@ -default: !reference [.crate-publishing-pipeline-definitions, default] diff --git a/scripts/ci/gitlab/default-pipeline.yml b/scripts/ci/gitlab/default-pipeline.yml deleted file mode 100644 index 19f6c320c3c24..0000000000000 --- a/scripts/ci/gitlab/default-pipeline.yml +++ /dev/null @@ -1 +0,0 @@ -default: !reference [.default-pipeline-definitions, default] From e155ab8aefbe5831cbd6100767bd111bbad32ee7 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Thu, 13 Apr 2023 22:44:46 +0200 Subject: [PATCH 651/715] Update proc-macro-warning (#13876) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update proc-macro-warning Closes https://github.com/paritytech/substrate/issues/13872 Signed-off-by: Oliver Tale-Yazdi * Update to v0.3.1 (including syn 2.0) Signed-off-by: Oliver Tale-Yazdi * Revert "Update to v0.3.1 (including syn 2.0)" CI is red since it Polkadot uses a different syn version… Going to update it lean. This reverts commit 3240d379b72f6f722eaf502ed49e9a1b0f79db4b. Signed-off-by: Oliver Tale-Yazdi --------- Signed-off-by: Oliver Tale-Yazdi --- Cargo.lock | 4 ++-- frame/support/procedural/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 45542b8c269e5..d5eb703610be5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7552,9 +7552,9 @@ dependencies = [ [[package]] name = "proc-macro-warning" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d4f284d87b9cedc2ff57223cbc4e3937cd6063c01e92c8e2a8c080df0013933" +checksum = "f0e25495609acefcaeb5052edad8ac91017c9bc98fc38ef321ed524e50b68bac" dependencies = [ "proc-macro2", "quote", diff --git a/frame/support/procedural/Cargo.toml b/frame/support/procedural/Cargo.toml index d57b81a3444fe..e508730f43f95 100644 --- a/frame/support/procedural/Cargo.toml +++ b/frame/support/procedural/Cargo.toml @@ -23,7 +23,7 @@ proc-macro2 = "1.0.56" quote = "1.0.26" syn = { version = "2.0.14", features = ["full"] } frame-support-procedural-tools = { version = "4.0.0-dev", path = "./tools" } -proc-macro-warning = { version = "0.2.0", default-features = false } +proc-macro-warning = { version = "0.3.0", default-features = false } [features] default = ["std"] From 4b212829fd62c180c23a90718a73c221f5b4f4ae Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 14 Apr 2023 09:32:24 +0200 Subject: [PATCH 652/715] Bump h2 from 0.3.16 to 0.3.17 (#13915) Bumps [h2](https://github.com/hyperium/h2) from 0.3.16 to 0.3.17. - [Release notes](https://github.com/hyperium/h2/releases) - [Changelog](https://github.com/hyperium/h2/blob/master/CHANGELOG.md) - [Commits](https://github.com/hyperium/h2/compare/v0.3.16...v0.3.17) --- updated-dependencies: - dependency-name: h2 dependency-type: indirect ... 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 d5eb703610be5..94fd66e0faf38 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2941,9 +2941,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be7b54589b581f624f566bf5d8eb2bab1db736c51528720b6bd36b96b55924d" +checksum = "66b91535aa35fea1523ad1b86cb6b53c28e0ae566ba4a460f4457e936cad7c6f" dependencies = [ "bytes", "fnv", From 6a560f85d24bb027a1909109b1f84a35b3348e8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Fri, 14 Apr 2023 10:21:06 +0200 Subject: [PATCH 653/715] Unqueue invalid transactions when skipping (#13918) The check was intially added by: https://github.com/paritytech/substrate/pull/5121 But a later pr fixed it properly: https://github.com/paritytech/substrate/pull/9789 TLDR: We don't need to check for skipped anymore, as we already remove all transactions that are being unlocked by an invalid transactions and thus, we will not tag them as invalid directly because the nonce for example is incorrect. Fixes: https://github.com/paritytech/substrate/issues/13911 --- client/basic-authorship/src/basic_authorship.rs | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/client/basic-authorship/src/basic_authorship.rs b/client/basic-authorship/src/basic_authorship.rs index 376278fa1b6db..795288d0a1da8 100644 --- a/client/basic-authorship/src/basic_authorship.rs +++ b/client/basic-authorship/src/basic_authorship.rs @@ -474,14 +474,6 @@ where break EndProposingReason::HitBlockWeightLimit } }, - Err(e) if skipped > 0 => { - pending_iterator.report_invalid(&pending_tx); - trace!( - "[{:?}] Ignoring invalid transaction when skipping: {}", - pending_tx_hash, - e - ); - }, Err(e) => { pending_iterator.report_invalid(&pending_tx); debug!("[{:?}] Invalid transaction: {}", pending_tx_hash, e); @@ -740,8 +732,11 @@ mod tests { ); } + // This test ensures that if one transaction of a user was rejected, because for example + // the weight limit was hit, we don't mark the other transactions of the user as invalid because + // the nonce is not matching. #[test] - fn should_not_remove_invalid_transactions_when_skipping() { + fn should_not_remove_invalid_transactions_from_the_same_sender_after_one_was_invalid() { // given let mut client = Arc::new(substrate_test_runtime_client::new()); let spawner = sp_core::testing::TaskExecutor::new(); From b23e52d340f1d8c6405c631e5e836f45966df326 Mon Sep 17 00:00:00 2001 From: Mira Ressel Date: Fri, 14 Apr 2023 14:16:17 +0200 Subject: [PATCH 654/715] Fail dependant checks on cargo check warnings (#13922) * Fail dependant checks on cargo check warnings * Adjust feature flags for check-dependent-polkadot --- scripts/ci/gitlab/pipeline/build.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/scripts/ci/gitlab/pipeline/build.yml b/scripts/ci/gitlab/pipeline/build.yml index 806a4ef970960..0c04abfd5aa30 100644 --- a/scripts/ci/gitlab/pipeline/build.yml +++ b/scripts/ci/gitlab/pipeline/build.yml @@ -12,6 +12,8 @@ extends: - .docker-env - .test-refs-no-trigger-prs-only + variables: + RUSTFLAGS: "-D warnings" script: - git clone --depth=1 @@ -35,6 +37,10 @@ check-dependent-polkadot: COMPANION_OVERRIDES: | substrate: polkadot-v* polkadot: release-v* + # enable the same feature flags as polkadot's test-linux-stable + COMPANION_CHECK_COMMAND: > + cargo check --all-targets --workspace + --features=runtime-benchmarks,runtime-metrics,try-runtime rules: - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ #PRs From c2f664e1acff27dbc165d02ab1785829b23ac3f9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 14 Apr 2023 14:52:51 +0200 Subject: [PATCH 655/715] Bump cargo_metadata from 0.15.3 to 0.15.4 (#13899) Bumps [cargo_metadata](https://github.com/oli-obk/cargo_metadata) from 0.15.3 to 0.15.4. - [Release notes](https://github.com/oli-obk/cargo_metadata/releases) - [Changelog](https://github.com/oli-obk/cargo_metadata/blob/main/CHANGELOG.md) - [Commits](https://github.com/oli-obk/cargo_metadata/compare/0.15.3...0.15.4) --- 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 ++-- client/executor/wasmtime/Cargo.toml | 2 +- utils/wasm-builder/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 94fd66e0faf38..bb8081221f0e2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -797,9 +797,9 @@ dependencies = [ [[package]] name = "cargo_metadata" -version = "0.15.3" +version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08a1ec454bc3eead8719cb56e15dbbfecdbc14e4b3a3ae4936cc6e31f5fc0d07" +checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a" dependencies = [ "camino", "cargo-platform", diff --git a/client/executor/wasmtime/Cargo.toml b/client/executor/wasmtime/Cargo.toml index bffccd12badfb..fed284e916fd6 100644 --- a/client/executor/wasmtime/Cargo.toml +++ b/client/executor/wasmtime/Cargo.toml @@ -48,4 +48,4 @@ sp-io = { version = "7.0.0", path = "../../../primitives/io" } tempfile = "3.3.0" paste = "1.0" codec = { package = "parity-scale-codec", version = "3.2.2" } -cargo_metadata = "0.15.2" +cargo_metadata = "0.15.4" diff --git a/utils/wasm-builder/Cargo.toml b/utils/wasm-builder/Cargo.toml index e1444a24042d1..7f356294e6cf9 100644 --- a/utils/wasm-builder/Cargo.toml +++ b/utils/wasm-builder/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] ansi_term = "0.12.1" build-helper = "0.1.1" -cargo_metadata = "0.15.2" +cargo_metadata = "0.15.4" strum = { version = "0.24.1", features = ["derive"] } tempfile = "3.1.0" toml = "0.7.3" From a9f67d0e59fc388c97efe8b1e6b2f928fae85b19 Mon Sep 17 00:00:00 2001 From: NingLin-P Date: Fri, 14 Apr 2023 22:15:31 +0800 Subject: [PATCH 656/715] Drain all the pending messages in the channel when TracingUnboundedReceiver is dropped (#13917) Signed-off-by: linning --- client/utils/src/mpsc.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/client/utils/src/mpsc.rs b/client/utils/src/mpsc.rs index 3f783b10060bd..7e06bd203b010 100644 --- a/client/utils/src/mpsc.rs +++ b/client/utils/src/mpsc.rs @@ -141,6 +141,7 @@ impl TracingUnboundedReceiver { impl Drop for TracingUnboundedReceiver { fn drop(&mut self) { + // Close the channel to prevent any further messages to be sent into the channel self.close(); // the number of messages about to be dropped let count = self.inner.len(); @@ -150,6 +151,10 @@ impl Drop for TracingUnboundedReceiver { .with_label_values(&[self.name, "dropped"]) .inc_by(count.saturated_into()); } + // Drain all the pending messages in the channel since they can never be accessed, + // this can be removed once https://github.com/smol-rs/async-channel/issues/23 is + // resolved + while let Ok(_) = self.inner.try_recv() {} } } @@ -177,3 +182,22 @@ impl FusedStream for TracingUnboundedReceiver { self.inner.is_terminated() } } + +#[cfg(test)] +mod tests { + use super::tracing_unbounded; + use async_channel::{self, RecvError, TryRecvError}; + + #[test] + fn test_tracing_unbounded_receiver_drop() { + let (tracing_unbounded_sender, tracing_unbounded_receiver) = + tracing_unbounded("test-receiver-drop", 10); + let (tx, rx) = async_channel::unbounded::(); + + tracing_unbounded_sender.unbounded_send(tx).unwrap(); + drop(tracing_unbounded_receiver); + + assert_eq!(rx.try_recv(), Err(TryRecvError::Closed)); + assert_eq!(rx.recv_blocking(), Err(RecvError)); + } +} From 3f8dc9ed594fdba455d0bf6780768e7176188514 Mon Sep 17 00:00:00 2001 From: gupnik Date: Fri, 14 Apr 2023 22:54:26 +0530 Subject: [PATCH 657/715] Updates Benchmark macro parsing to use Generic Argument (#13919) * WIP Signed-off-by: Oliver Tale-Yazdi * Removes POC code * Adds assertion and UT * adds runtime error * removes const_assert * ".git/.scripts/commands/fmt/fmt.sh" --------- Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Oliver Tale-Yazdi Co-authored-by: command-bot <> --- frame/support/procedural/src/benchmark.rs | 32 ++++++++----------- .../tests/benchmark_ui/bad_param_range.rs | 16 ---------- .../tests/benchmark_ui/bad_param_range.stderr | 5 --- .../benchmark_ui/pass/valid_const_expr.rs | 28 ++++++++++++++++ 4 files changed, 41 insertions(+), 40 deletions(-) delete mode 100644 frame/support/test/tests/benchmark_ui/bad_param_range.rs delete mode 100644 frame/support/test/tests/benchmark_ui/bad_param_range.stderr create mode 100644 frame/support/test/tests/benchmark_ui/pass/valid_const_expr.rs diff --git a/frame/support/procedural/src/benchmark.rs b/frame/support/procedural/src/benchmark.rs index cf091e7cb0cf7..315a6000bc8bf 100644 --- a/frame/support/procedural/src/benchmark.rs +++ b/frame/support/procedural/src/benchmark.rs @@ -28,9 +28,9 @@ use syn::{ punctuated::Punctuated, spanned::Spanned, token::{Comma, Gt, Lt, PathSep}, - Attribute, Error, Expr, ExprBlock, ExprCall, ExprPath, FnArg, Item, ItemFn, ItemMod, LitInt, - Pat, Path, PathArguments, PathSegment, Result, ReturnType, Signature, Stmt, Token, Type, - TypePath, Visibility, WhereClause, + Attribute, Error, Expr, ExprBlock, ExprCall, ExprPath, FnArg, Item, ItemFn, ItemMod, Pat, Path, + PathArguments, PathSegment, Result, ReturnType, Signature, Stmt, Token, Type, TypePath, + Visibility, WhereClause, }; mod keywords { @@ -54,17 +54,17 @@ mod keywords { struct ParamDef { name: String, typ: Type, - start: u32, - end: u32, + start: syn::GenericArgument, + end: syn::GenericArgument, } /// Allows easy parsing of the `<10, 20>` component of `x: Linear<10, 20>`. #[derive(Parse)] struct RangeArgs { _lt_token: Lt, - start: LitInt, + start: syn::GenericArgument, _comma: Comma, - end: LitInt, + end: syn::GenericArgument, _gt_token: Gt, } @@ -228,17 +228,8 @@ fn parse_params(item_fn: &ItemFn) -> Result> { let Some(segment) = tpath.path.segments.last() else { return invalid_param(typ.span()) }; let args = segment.arguments.to_token_stream().into(); let Ok(args) = syn::parse::(args) else { return invalid_param(typ.span()) }; - let Ok(start) = args.start.base10_parse::() else { return invalid_param(args.start.span()) }; - let Ok(end) = args.end.base10_parse::() else { return invalid_param(args.end.span()) }; - if end < start { - return Err(Error::new( - args.start.span(), - "The start of a `ParamRange` must be less than or equal to the end", - )) - } - - params.push(ParamDef { name, typ: typ.clone(), start, end }); + params.push(ParamDef { name, typ: typ.clone(), start: args.start, end: args.end }); } Ok(params) } @@ -700,8 +691,8 @@ impl UnrolledParams { .iter() .map(|p| { let name = Ident::new(&p.name, Span::call_site()); - let start = p.start; - let end = p.end; + let start = &p.start; + let end = &p.end; quote!(#name, #start, #end) }) .collect(); @@ -987,6 +978,9 @@ fn expand_benchmark( // 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] + if high < low { + return Err("The start of a `ParamRange` must be less than or equal to the end".into()); + } let mut values = #krate::vec![low]; let diff = (high - low).min(num_values - 1); diff --git a/frame/support/test/tests/benchmark_ui/bad_param_range.rs b/frame/support/test/tests/benchmark_ui/bad_param_range.rs deleted file mode 100644 index 993f2a0004103..0000000000000 --- a/frame/support/test/tests/benchmark_ui/bad_param_range.rs +++ /dev/null @@ -1,16 +0,0 @@ -use frame_benchmarking::v2::*; -#[allow(unused_imports)] -use frame_support_test::Config; - -#[benchmarks] -mod benches { - use super::*; - - #[benchmark] - fn bench(x: Linear<3, 1>) { - #[block] - {} - } -} - -fn main() {} diff --git a/frame/support/test/tests/benchmark_ui/bad_param_range.stderr b/frame/support/test/tests/benchmark_ui/bad_param_range.stderr deleted file mode 100644 index 1347af0a07b8e..0000000000000 --- a/frame/support/test/tests/benchmark_ui/bad_param_range.stderr +++ /dev/null @@ -1,5 +0,0 @@ -error: The start of a `ParamRange` must be less than or equal to the end - --> tests/benchmark_ui/bad_param_range.rs:10:21 - | -10 | fn bench(x: Linear<3, 1>) { - | ^ diff --git a/frame/support/test/tests/benchmark_ui/pass/valid_const_expr.rs b/frame/support/test/tests/benchmark_ui/pass/valid_const_expr.rs new file mode 100644 index 0000000000000..bead3bf277be2 --- /dev/null +++ b/frame/support/test/tests/benchmark_ui/pass/valid_const_expr.rs @@ -0,0 +1,28 @@ +use frame_benchmarking::v2::*; +use frame_support_test::Config; +use frame_support::parameter_types; + +#[benchmarks] +mod benches { + use super::*; + + const MY_CONST: u32 = 100; + + const fn my_fn() -> u32 { + 200 + } + + parameter_types! { + const MyConst: u32 = MY_CONST; + } + + #[benchmark(skip_meta, extra)] + fn bench(a: Linear<{MY_CONST * 2}, {my_fn() + MyConst::get()}>) { + let a = 2 + 2; + #[block] + {} + assert_eq!(a, 4); + } +} + +fn main() {} From f1e2fa43ef10f0abc4fc0620ff08979ac6a6e097 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Sat, 15 Apr 2023 23:27:51 +0200 Subject: [PATCH 658/715] sc-allocator: Do not panic on invalid header pointer (#13925) We should not panic on an invalid header pointer and instead return an error. It is possible that the application modifies the header pointer illegally, but then we should return an error instead of panicking. --- client/allocator/src/freeing_bump.rs | 31 +++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/client/allocator/src/freeing_bump.rs b/client/allocator/src/freeing_bump.rs index c3cb827afec08..144c0764540db 100644 --- a/client/allocator/src/freeing_bump.rs +++ b/client/allocator/src/freeing_bump.rs @@ -421,11 +421,11 @@ impl FreeingBumpHeapAllocator { let header_ptr: u32 = match self.free_lists[order] { Link::Ptr(header_ptr) => { - assert!( - u64::from(header_ptr + order.size() + HEADER_SIZE) <= mem.size(), - "Pointer is looked up in list of free entries, into which - only valid values are inserted; qed" - ); + if (u64::from(header_ptr) + u64::from(order.size()) + u64::from(HEADER_SIZE)) > + mem.size() + { + return Err(error("Invalid header pointer detected")) + } // Remove this header from the free list. let next_free = Header::read_from(mem, header_ptr)? @@ -1106,4 +1106,25 @@ mod tests { assert_eq!(3, mem.pages()); } + + #[test] + fn modifying_the_header_leads_to_an_error() { + let mut mem = MemoryInstance::with_pages(1); + let mut heap = FreeingBumpHeapAllocator::new(0); + + let ptr = heap.allocate(&mut mem, 5).unwrap(); + + heap.deallocate(&mut mem, ptr).unwrap(); + + Header::Free(Link::Ptr(u32::MAX - 1)) + .write_into(&mut mem, u32::from(ptr) - HEADER_SIZE) + .unwrap(); + + heap.allocate(&mut mem, 5).unwrap(); + assert!(heap + .allocate(&mut mem, 5) + .unwrap_err() + .to_string() + .contains("Invalid header pointer")); + } } From 35049b176e49ca23240d1ee3ec6c190804e3b4d1 Mon Sep 17 00:00:00 2001 From: Roman Useinov Date: Sun, 16 Apr 2023 00:25:56 +0200 Subject: [PATCH 659/715] [Fix] Remove redundant stash from Stake (#13907) * [Fix] Remove redundant stash from Stake * fix tests --- frame/nomination-pools/src/mock.rs | 6 +++--- frame/staking/src/pallet/impls.rs | 2 +- primitives/staking/src/lib.rs | 2 -- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/frame/nomination-pools/src/mock.rs b/frame/nomination-pools/src/mock.rs index 6d83ef61de793..3565ff14e6c82 100644 --- a/frame/nomination-pools/src/mock.rs +++ b/frame/nomination-pools/src/mock.rs @@ -122,9 +122,9 @@ impl sp_staking::StakingInterface for StakingMock { BondedBalanceMap::get().get(who).copied(), ) { (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 }), + (Some(v), None) => Ok(Stake { total: v, active: 0 }), + (None, Some(v)) => Ok(Stake { total: v, active: v }), + (Some(a), Some(b)) => Ok(Stake { total: a + b, active: b }), } } diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index d5072476fb37e..5143538c2a513 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -1611,7 +1611,7 @@ impl StakingInterface for Pallet { 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 }) + .map(|l| Stake { total: l.total, active: l.active }) .ok_or(Error::::NotStash.into()) } diff --git a/primitives/staking/src/lib.rs b/primitives/staking/src/lib.rs index a8d8e6a602c94..f328696551eed 100644 --- a/primitives/staking/src/lib.rs +++ b/primitives/staking/src/lib.rs @@ -58,8 +58,6 @@ impl OnStakerSlash for () { /// 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`]. From 4e93782c16f741cde18a8b98bd791838e03788fb Mon Sep 17 00:00:00 2001 From: Sergej Sakac <73715684+Szegoo@users.noreply.github.com> Date: Mon, 17 Apr 2023 07:43:13 +0200 Subject: [PATCH 660/715] Try-state for Collective pallet (#13645) * write the try_state_ function * update tests * update check * fix benchmarking * fix nonsense * Update frame/collective/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * Update frame/collective/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * unique proposal index * prime must be a member of the collective * oops * Add new checks * use ensure * fix --------- Co-authored-by: Oliver Tale-Yazdi --- frame/collective/src/benchmarking.rs | 2 +- frame/collective/src/lib.rs | 118 ++++++++++++++++++++++++++- frame/collective/src/tests.rs | 99 ++++++++++++---------- 3 files changed, 175 insertions(+), 44 deletions(-) diff --git a/frame/collective/src/benchmarking.rs b/frame/collective/src/benchmarking.rs index d4b5af1bc1937..bcd203c3894a3 100644 --- a/frame/collective/src/benchmarking.rs +++ b/frame/collective/src/benchmarking.rs @@ -646,5 +646,5 @@ benchmarks_instance_pallet! { assert_last_event::(Event::Disapproved { proposal_hash: last_hash }.into()); } - impl_benchmark_test_suite!(Collective, crate::tests::new_test_ext(), crate::tests::Test); + impl_benchmark_test_suite!(Collective, crate::tests::ExtBuilder::default().build(), crate::tests::Test); } diff --git a/frame/collective/src/lib.rs b/frame/collective/src/lib.rs index bde08f08c13b4..0cbf7e97261df 100644 --- a/frame/collective/src/lib.rs +++ b/frame/collective/src/lib.rs @@ -50,8 +50,8 @@ use sp_std::{marker::PhantomData, prelude::*, result}; use frame_support::{ codec::{Decode, Encode, MaxEncodedLen}, dispatch::{ - DispatchError, DispatchResultWithPostInfo, Dispatchable, GetDispatchInfo, Pays, - PostDispatchInfo, + DispatchError, DispatchResult, DispatchResultWithPostInfo, Dispatchable, GetDispatchInfo, + Pays, PostDispatchInfo, }, ensure, traits::{ @@ -341,6 +341,15 @@ pub mod pallet { WrongProposalLength, } + #[pallet::hooks] + impl, I: 'static> Hooks> for Pallet { + #[cfg(feature = "try-runtime")] + fn try_state(_n: BlockNumberFor) -> Result<(), &'static str> { + Self::do_try_state()?; + Ok(()) + } + } + // Note that councillor operations are assigned to the operational class. #[pallet::call] impl, I: 'static> Pallet { @@ -916,6 +925,111 @@ impl, I: 'static> Pallet { }); num_proposals as u32 } + + /// Ensure the correctness of the state of this pallet. + /// + /// The following expectation must always apply. + /// + /// ## Expectations: + /// + /// Looking at proposals: + /// + /// * Each hash of a proposal that is stored inside `Proposals` must have a + /// call mapped to it inside the `ProposalOf` storage map. + /// * `ProposalCount` must always be more or equal to the number of + /// proposals inside the `Proposals` storage value. The reason why + /// `ProposalCount` can be more is because when a proposal is removed the + /// count is not deducted. + /// * Count of `ProposalOf` should match the count of `Proposals` + /// + /// Looking at votes: + /// * The sum of aye and nay votes for a proposal can never exceed + /// `MaxMembers`. + /// * The proposal index inside the `Voting` storage map must be unique. + /// * All proposal hashes inside `Voting` must exist in `Proposals`. + /// + /// Looking at members: + /// * The members count must never exceed `MaxMembers`. + /// * All the members must be sorted by value. + /// + /// Looking at prime account: + /// * The prime account must be a member of the collective. + #[cfg(any(feature = "try-runtime", test))] + fn do_try_state() -> DispatchResult { + Self::proposals().into_iter().try_for_each(|proposal| -> DispatchResult { + ensure!( + Self::proposal_of(proposal).is_some(), + DispatchError::Other( + "Proposal hash from `Proposals` is not found inside the `ProposalOf` mapping." + ) + ); + Ok(()) + })?; + + ensure!( + Self::proposals().into_iter().count() <= Self::proposal_count() as usize, + DispatchError::Other("The actual number of proposals is greater than `ProposalCount`") + ); + ensure!( + Self::proposals().into_iter().count() == >::iter_keys().count(), + DispatchError::Other("Proposal count inside `Proposals` is not equal to the proposal count in `ProposalOf`") + ); + + Self::proposals().into_iter().try_for_each(|proposal| -> DispatchResult { + if let Some(votes) = Self::voting(proposal) { + let ayes = votes.ayes.len(); + let nays = votes.nays.len(); + + ensure!( + ayes.saturating_add(nays) <= T::MaxMembers::get() as usize, + DispatchError::Other("The sum of ayes and nays is greater than `MaxMembers`") + ); + } + Ok(()) + })?; + + let mut proposal_indices = vec![]; + Self::proposals().into_iter().try_for_each(|proposal| -> DispatchResult { + if let Some(votes) = Self::voting(proposal) { + let proposal_index = votes.index; + ensure!( + !proposal_indices.contains(&proposal_index), + DispatchError::Other("The proposal index is not unique.") + ); + proposal_indices.push(proposal_index); + } + Ok(()) + })?; + + >::iter_keys().try_for_each(|proposal_hash| -> DispatchResult { + ensure!( + Self::proposals().contains(&proposal_hash), + DispatchError::Other( + "`Proposals` doesn't contain the proposal hash from the `Voting` storage map." + ) + ); + Ok(()) + })?; + + ensure!( + Self::members().len() <= T::MaxMembers::get() as usize, + DispatchError::Other("The member count is greater than `MaxMembers`.") + ); + + ensure!( + Self::members().windows(2).all(|members| members[0] <= members[1]), + DispatchError::Other("The members are not sorted by value.") + ); + + if let Some(prime) = Self::prime() { + ensure!( + Self::members().contains(&prime), + DispatchError::Other("Prime account is not a member.") + ); + } + + Ok(()) + } } impl, I: 'static> ChangeMembers for Pallet { diff --git a/frame/collective/src/tests.rs b/frame/collective/src/tests.rs index 2550ab3ed2017..79dc3becfffc6 100644 --- a/frame/collective/src/tests.rs +++ b/frame/collective/src/tests.rs @@ -155,23 +155,40 @@ impl Config for Test { type SetMembersOrigin = EnsureRoot; } -pub fn new_test_ext() -> sp_io::TestExternalities { - let mut ext: sp_io::TestExternalities = GenesisConfig { - collective: pallet_collective::GenesisConfig { - members: vec![1, 2, 3], - phantom: Default::default(), - }, - collective_majority: pallet_collective::GenesisConfig { - members: vec![1, 2, 3, 4, 5], - phantom: Default::default(), - }, - default_collective: Default::default(), +pub struct ExtBuilder {} + +impl Default for ExtBuilder { + fn default() -> Self { + Self {} + } +} + +impl ExtBuilder { + pub fn build(self) -> sp_io::TestExternalities { + let mut ext: sp_io::TestExternalities = GenesisConfig { + collective: pallet_collective::GenesisConfig { + members: vec![1, 2, 3], + phantom: Default::default(), + }, + collective_majority: pallet_collective::GenesisConfig { + members: vec![1, 2, 3, 4, 5], + phantom: Default::default(), + }, + default_collective: Default::default(), + } + .build_storage() + .unwrap() + .into(); + ext.execute_with(|| System::set_block_number(1)); + ext + } + + pub fn build_and_execute(self, test: impl FnOnce() -> ()) { + self.build().execute_with(|| { + test(); + Collective::do_try_state().unwrap(); + }) } - .build_storage() - .unwrap() - .into(); - ext.execute_with(|| System::set_block_number(1)); - ext } fn make_proposal(value: u64) -> RuntimeCall { @@ -186,7 +203,7 @@ fn record(event: RuntimeEvent) -> EventRecord { #[test] fn motions_basic_environment_works() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build_and_execute(|| { assert_eq!(Collective::members(), vec![1, 2, 3]); assert_eq!(*Collective::proposals(), Vec::::new()); }); @@ -194,7 +211,7 @@ fn motions_basic_environment_works() { #[test] fn close_works() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build_and_execute(|| { 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; @@ -262,7 +279,7 @@ fn close_works() { #[test] fn proposal_weight_limit_works_on_approve() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build_and_execute(|| { let proposal = RuntimeCall::Collective(crate::Call::set_members { new_members: vec![1, 2, 3], prime: None, @@ -304,7 +321,7 @@ fn proposal_weight_limit_works_on_approve() { #[test] fn proposal_weight_limit_ignored_on_disapprove() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build_and_execute(|| { let proposal = RuntimeCall::Collective(crate::Call::set_members { new_members: vec![1, 2, 3], prime: None, @@ -334,7 +351,7 @@ fn proposal_weight_limit_ignored_on_disapprove() { #[test] fn close_with_prime_works() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build_and_execute(|| { 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; @@ -402,7 +419,7 @@ fn close_with_prime_works() { #[test] fn close_with_voting_prime_works() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build_and_execute(|| { 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; @@ -472,7 +489,7 @@ fn close_with_voting_prime_works() { #[test] fn close_with_no_prime_but_majority_works() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build_and_execute(|| { 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; @@ -552,7 +569,7 @@ fn close_with_no_prime_but_majority_works() { #[test] fn removal_of_old_voters_votes_works() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build_and_execute(|| { let proposal = make_proposal(42); let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); let hash = BlakeTwo256::hash_of(&proposal); @@ -600,7 +617,7 @@ fn removal_of_old_voters_votes_works() { #[test] fn removal_of_old_voters_votes_works_with_set_members() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build_and_execute(|| { let proposal = make_proposal(42); let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); let hash = BlakeTwo256::hash_of(&proposal); @@ -658,7 +675,7 @@ fn removal_of_old_voters_votes_works_with_set_members() { #[test] fn propose_works() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build_and_execute(|| { let proposal = make_proposal(42); let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); let hash = proposal.blake2_256().into(); @@ -690,7 +707,7 @@ fn propose_works() { #[test] fn limit_active_proposals() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build_and_execute(|| { for i in 0..MaxProposals::get() { let proposal = make_proposal(i as u64); let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); @@ -717,7 +734,7 @@ fn limit_active_proposals() { #[test] fn correct_validate_and_get_proposal() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build_and_execute(|| { let proposal = RuntimeCall::Collective(crate::Call::set_members { new_members: vec![1, 2, 3], prime: None, @@ -763,7 +780,7 @@ fn correct_validate_and_get_proposal() { #[test] fn motions_ignoring_non_collective_proposals_works() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build_and_execute(|| { let proposal = make_proposal(42); let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); assert_noop!( @@ -780,7 +797,7 @@ fn motions_ignoring_non_collective_proposals_works() { #[test] fn motions_ignoring_non_collective_votes_works() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build_and_execute(|| { let proposal = make_proposal(42); let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); let hash: H256 = proposal.blake2_256().into(); @@ -799,7 +816,7 @@ fn motions_ignoring_non_collective_votes_works() { #[test] fn motions_ignoring_bad_index_collective_vote_works() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build_and_execute(|| { System::set_block_number(3); let proposal = make_proposal(42); let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); @@ -819,7 +836,7 @@ fn motions_ignoring_bad_index_collective_vote_works() { #[test] fn motions_vote_after_works() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build_and_execute(|| { let proposal = make_proposal(42); let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); let hash: H256 = proposal.blake2_256().into(); @@ -888,7 +905,7 @@ fn motions_vote_after_works() { #[test] fn motions_all_first_vote_free_works() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build_and_execute(|| { let proposal = make_proposal(42); let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); let hash: H256 = proposal.blake2_256().into(); @@ -946,7 +963,7 @@ fn motions_all_first_vote_free_works() { #[test] fn motions_reproposing_disapproved_works() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build_and_execute(|| { 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; @@ -978,7 +995,7 @@ fn motions_reproposing_disapproved_works() { #[test] fn motions_approval_with_enough_votes_and_lower_voting_threshold_works() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build_and_execute(|| { 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; @@ -1108,7 +1125,7 @@ fn motions_approval_with_enough_votes_and_lower_voting_threshold_works() { #[test] fn motions_disapproval_works() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build_and_execute(|| { 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; @@ -1167,7 +1184,7 @@ fn motions_disapproval_works() { #[test] fn motions_approval_works() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build_and_execute(|| { 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; @@ -1228,7 +1245,7 @@ fn motions_approval_works() { #[test] fn motion_with_no_votes_closes_with_disapproval() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build_and_execute(|| { 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; @@ -1289,7 +1306,7 @@ fn close_disapprove_does_not_care_about_weight_or_len() { // This test confirms that if you close a proposal that would be disapproved, // we do not care about the proposal length or proposal weight since it will // not be read from storage or executed. - new_test_ext().execute_with(|| { + ExtBuilder::default().build_and_execute(|| { let proposal = make_proposal(42); let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); let hash: H256 = proposal.blake2_256().into(); @@ -1321,7 +1338,7 @@ fn close_disapprove_does_not_care_about_weight_or_len() { #[test] fn disapprove_proposal_works() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build_and_execute(|| { let proposal = make_proposal(42); let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); let hash: H256 = proposal.blake2_256().into(); @@ -1380,7 +1397,7 @@ fn genesis_build_panics_with_duplicate_members() { #[test] fn migration_v4() { - new_test_ext().execute_with(|| { + ExtBuilder::default().build_and_execute(|| { use frame_support::traits::PalletInfoAccess; let old_pallet = "OldCollective"; From 15bb9c61aecf73a3a7a1853151a27587edb34b97 Mon Sep 17 00:00:00 2001 From: Mike Ruje Date: Mon, 17 Apr 2023 11:07:14 +0200 Subject: [PATCH 661/715] imp function comparison (#13928) --- bin/node/bench/src/core.rs | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/bin/node/bench/src/core.rs b/bin/node/bench/src/core.rs index 29cda70990aa0..1f22d3db69261 100644 --- a/bin/node/bench/src/core.rs +++ b/bin/node/bench/src/core.rs @@ -72,24 +72,13 @@ pub struct NsFormatter(pub u64); impl fmt::Display for NsFormatter { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let v = self.0; - - if v < 100 { - return write!(f, "{} ns", v) - } - - if self.0 < 100_000 { - return write!(f, "{:.1} µs", v as f64 / 1000.0) - } - - if self.0 < 1_000_000 { - return write!(f, "{:.4} ms", v as f64 / 1_000_000.0) - } - - if self.0 < 100_000_000 { - return write!(f, "{:.1} ms", v as f64 / 1_000_000.0) + match v { + v if v < 100 => write!(f, "{} ns", v), + v if v < 100_000 => write!(f, "{:.1} µs", v as f64 / 1000.0), + v if v < 1_000_000 => write!(f, "{:.4} ms", v as f64 / 1_000_000.0), + v if v < 100_000_000 => write!(f, "{:.1} ms", v as f64 / 1_000_000.0), + _ => write!(f, "{:.4} s", v as f64 / 1_000_000_000.0), } - - write!(f, "{:.4} s", v as f64 / 1_000_000_000.0) } } From 915d22ccaa45b2b93b1eb4194b4349c1db7930d8 Mon Sep 17 00:00:00 2001 From: Przemek Rzad Date: Mon, 17 Apr 2023 12:22:59 +0200 Subject: [PATCH 662/715] Update links in the Referenda Readme (#13929) * Update links in the Referenda Readme * Update frame/referenda/README.md --------- Co-authored-by: Oliver Tale-Yazdi --- frame/referenda/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frame/referenda/README.md b/frame/referenda/README.md index 85031a0113033..b9a8b022cbdb7 100644 --- a/frame/referenda/README.md +++ b/frame/referenda/README.md @@ -1,8 +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) +- [`Config`](https://docs.rs/pallet-referenda/latest/pallet_referenda/pallet/trait.Config.html) +- [`Call`](https://docs.rs/pallet-referenda/latest/pallet_referenda/pallet/enum.Call.html) ## Overview -The Assembly pallet handles the administration of general stakeholder voting. +The Referenda pallet handles the administration of general stakeholder voting. From 785115b3a13901b0c708af8166430bcc9c71f28f Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Mon, 17 Apr 2023 19:13:55 +0100 Subject: [PATCH 663/715] Balances: repatriate_reserved should respect freezes (#13885) * repatriate_reserved should respect freezes * Docs * Fix and clean * Formatting * Update frame/balances/src/types.rs Co-authored-by: Jegor Sidorenko <5252494+jsidorenko@users.noreply.github.com> * Fix * Simplify * Fixes * Fixes --------- Co-authored-by: Jegor Sidorenko <5252494+jsidorenko@users.noreply.github.com> --- frame/balances/src/impl_currency.rs | 9 +++- frame/balances/src/lib.rs | 70 +++++++++++++++-------------- frame/balances/src/types.rs | 6 +-- 3 files changed, 46 insertions(+), 39 deletions(-) diff --git a/frame/balances/src/impl_currency.rs b/frame/balances/src/impl_currency.rs index 790a29f004764..329ea289f966e 100644 --- a/frame/balances/src/impl_currency.rs +++ b/frame/balances/src/impl_currency.rs @@ -22,7 +22,7 @@ use frame_support::{ ensure, pallet_prelude::DispatchResult, traits::{ - tokens::{fungible, BalanceStatus as Status}, + tokens::{fungible, BalanceStatus as Status, Fortitude::Polite, Precision::BestEffort}, Currency, DefensiveSaturating, ExistenceRequirement, ExistenceRequirement::AllowDeath, Get, Imbalance, LockIdentifier, LockableCurrency, NamedReservableCurrency, @@ -590,13 +590,18 @@ where /// Is a no-op if: /// - the value to be moved is zero; or /// - the `slashed` id equal to `beneficiary` and the `status` is `Reserved`. + /// + /// This is `Polite` and thus will not repatriate any funds which would lead the total balance + /// to be less than the frozen amount. Returns `Ok` with the actual amount of funds moved, + /// which may be less than `value` since the operation is done an a `BestEffort` basis. fn repatriate_reserved( slashed: &T::AccountId, beneficiary: &T::AccountId, value: Self::Balance, status: Status, ) -> Result { - let actual = Self::do_transfer_reserved(slashed, beneficiary, value, true, status)?; + let actual = + Self::do_transfer_reserved(slashed, beneficiary, value, BestEffort, Polite, status)?; Ok(value.saturating_sub(actual)) } } diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index 029a170535a10..74aec1f2d259b 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -205,7 +205,10 @@ type AccountIdLookupOf = <::Lookup as StaticLookup #[frame_support::pallet] pub mod pallet { use super::*; - use frame_support::{pallet_prelude::*, traits::fungible::Credit}; + use frame_support::{ + pallet_prelude::*, + traits::{fungible::Credit, tokens::Precision}, + }; use frame_system::pallet_prelude::*; pub type CreditOf = Credit<::AccountId, Pallet>; @@ -1100,59 +1103,58 @@ pub mod pallet { } /// Move the reserved balance of one account into the balance of another, according to - /// `status`. + /// `status`. This will respect freezes/locks only if `fortitude` is `Polite`. /// - /// Is a no-op if: - /// - the value to be moved is zero; or - /// - the `slashed` id equal to `beneficiary` and the `status` is `Reserved`. + /// Is a no-op if the value to be moved is zero. /// /// NOTE: returns actual amount of transferred value in `Ok` case. pub(crate) fn do_transfer_reserved( slashed: &T::AccountId, beneficiary: &T::AccountId, value: T::Balance, - best_effort: bool, + precision: Precision, + fortitude: Fortitude, status: Status, ) -> Result { if value.is_zero() { return Ok(Zero::zero()) } + let max = >::reducible_total_balance_on_hold( + slashed, fortitude, + ); + let actual = match precision { + Precision::BestEffort => value.min(max), + Precision::Exact => value, + }; + ensure!(actual <= max, TokenError::FundsUnavailable); if slashed == beneficiary { return match status { - Status::Free => Ok(value.saturating_sub(Self::unreserve(slashed, value))), - Status::Reserved => Ok(value.saturating_sub(Self::reserved_balance(slashed))), + Status::Free => Ok(actual.saturating_sub(Self::unreserve(slashed, actual))), + Status::Reserved => Ok(actual), } } - let ((actual, maybe_dust_1), maybe_dust_2) = Self::try_mutate_account( + let ((_, maybe_dust_1), maybe_dust_2) = Self::try_mutate_account( beneficiary, - |to_account, is_new| -> Result<(T::Balance, Option), DispatchError> { + |to_account, is_new| -> Result<((), Option), DispatchError> { ensure!(!is_new, Error::::DeadAccount); - Self::try_mutate_account( - slashed, - |from_account, _| -> Result { - let actual = cmp::min(from_account.reserved, value); - ensure!( - best_effort || actual == value, - Error::::InsufficientBalance - ); - match status { - Status::Free => - to_account.free = to_account - .free - .checked_add(&actual) - .ok_or(ArithmeticError::Overflow)?, - Status::Reserved => - to_account.reserved = to_account - .reserved - .checked_add(&actual) - .ok_or(ArithmeticError::Overflow)?, - } - from_account.reserved -= actual; - Ok(actual) - }, - ) + Self::try_mutate_account(slashed, |from_account, _| -> DispatchResult { + match status { + Status::Free => + to_account.free = to_account + .free + .checked_add(&actual) + .ok_or(ArithmeticError::Overflow)?, + Status::Reserved => + to_account.reserved = to_account + .reserved + .checked_add(&actual) + .ok_or(ArithmeticError::Overflow)?, + } + from_account.reserved.saturating_reduce(actual); + Ok(()) + }) }, )?; diff --git a/frame/balances/src/types.rs b/frame/balances/src/types.rs index c96e1e44b4165..389124402a8f1 100644 --- a/frame/balances/src/types.rs +++ b/frame/balances/src/types.rs @@ -102,9 +102,9 @@ pub struct AccountData { /// This is the sum of all individual holds together with any sums still under the (deprecated) /// reserves API. pub reserved: Balance, - /// The amount that `free` may not drop below when reducing the balance, except for actions - /// where the account owner cannot reasonably benefit from thr balance reduction, such as - /// slashing. + /// The amount that `free + reserved` may not drop below when reducing the balance, except for + /// actions where the account owner cannot reasonably benefit from the balance reduction, such + /// as slashing. pub frozen: Balance, /// Extra information about this account. The MSB is a flag indicating whether the new ref- /// counting logic is in place for this account. From af29c6f10ee84c862f6ba7c14fc302b9824f9d4f Mon Sep 17 00:00:00 2001 From: Aaro Altonen <48052676+altonen@users.noreply.github.com> Date: Tue, 18 Apr 2023 10:47:36 +0300 Subject: [PATCH 664/715] Poll the substream validation before polling `Notifications` (#13934) * Poll the substream validation before polling `Notifications` In tests, it can happen that `Notifications` doesn't produce any events which causes `poll()` to return `Poll::Pending` and the substream validation futures won't get polled. Poll the futures before calling `Notifications` so results for substream validations are received even if `Notifications` is not producing any events. * Remove `pending_messages` * Remove unused import --- client/network/src/protocol.rs | 44 +++++++++++++--------------------- 1 file changed, 16 insertions(+), 28 deletions(-) diff --git a/client/network/src/protocol.rs b/client/network/src/protocol.rs index a7e6f36ef6215..0075e856e7574 100644 --- a/client/network/src/protocol.rs +++ b/client/network/src/protocol.rs @@ -40,7 +40,7 @@ use sc_utils::mpsc::TracingUnboundedSender; use sp_runtime::traits::Block as BlockT; use std::{ - collections::{HashMap, HashSet, VecDeque}, + collections::{HashMap, HashSet}, future::Future, iter, pin::Pin, @@ -77,8 +77,6 @@ type PendingSyncSubstreamValidation = // Lock must always be taken in order declared here. pub struct Protocol { - /// Pending list of messages to return from `poll` as a priority. - pending_messages: VecDeque, /// Used to report reputation changes. peerset_handle: sc_peerset::PeersetHandle, /// Handles opening the unique substream and sending and receiving raw messages. @@ -181,7 +179,6 @@ impl Protocol { }; let protocol = Self { - pending_messages: VecDeque::new(), peerset_handle: peerset_handle.clone(), behaviour, notification_protocols: iter::once(block_announces_protocol.notifications_protocol) @@ -409,8 +406,21 @@ impl NetworkBehaviour for Protocol { cx: &mut std::task::Context, params: &mut impl PollParameters, ) -> Poll> { - if let Some(message) = self.pending_messages.pop_front() { - return Poll::Ready(NetworkBehaviourAction::GenerateEvent(message)) + while let Poll::Ready(Some(validation_result)) = + self.sync_substream_validations.poll_next_unpin(cx) + { + match validation_result { + Ok((peer, roles)) => { + self.peers.insert(peer, roles); + }, + Err(peer) => { + log::debug!( + target: "sub-libp2p", + "`SyncingEngine` rejected stream" + ); + self.behaviour.disconnect_peer(&peer, HARDCODED_PEERSETS_SYNC); + }, + } } let event = match self.behaviour.poll(cx, params) { @@ -430,23 +440,6 @@ impl NetworkBehaviour for Protocol { return Poll::Ready(NetworkBehaviourAction::CloseConnection { peer_id, connection }), }; - while let Poll::Ready(Some(validation_result)) = - self.sync_substream_validations.poll_next_unpin(cx) - { - match validation_result { - Ok((peer, roles)) => { - self.peers.insert(peer, roles); - }, - Err(peer) => { - log::debug!( - target: "sub-libp2p", - "`SyncingEngine` rejected stream" - ); - self.behaviour.disconnect_peer(&peer, HARDCODED_PEERSETS_SYNC); - }, - } - } - let outcome = match event { NotificationsOut::CustomProtocolOpen { peer_id, @@ -509,7 +502,6 @@ impl NetworkBehaviour for Protocol { ) { Ok(handshake) => { let roles = handshake.roles; - self.peers.insert(peer_id, roles); let (tx, rx) = oneshot::channel(); let _ = self.tx.unbounded_send( @@ -644,10 +636,6 @@ impl NetworkBehaviour for Protocol { return Poll::Ready(NetworkBehaviourAction::GenerateEvent(outcome)) } - if let Some(message) = self.pending_messages.pop_front() { - return Poll::Ready(NetworkBehaviourAction::GenerateEvent(message)) - } - // This block can only be reached if an event was pulled from the behaviour and that // resulted in `CustomMessageOutcome::None`. Since there might be another pending // message from the behaviour, the task is scheduled again. From cb954820a8d8d765ce75021e244223a3b4d5722d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= <123550+andresilva@users.noreply.github.com> Date: Tue, 18 Apr 2023 10:38:04 +0100 Subject: [PATCH 665/715] babe: replace usage of SharedEpochChanges with internal RPC (#13883) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * babe: replace usage of SharedEpochChanges with internal RPC * babe-rpc: fix tests * babe: use SinkExt::send instead of Sender::try_send SinkExt::send provides backpressure in case the channel is full * Update client/consensus/babe/src/lib.rs Co-authored-by: Bastian Köcher * babe: fix spawn * babe: send handles backpressure * babe: use testing::TaskExecutor * babe-rpc: better error handling --------- Co-authored-by: Bastian Köcher --- Cargo.lock | 1 - bin/node/cli/src/service.rs | 10 +- bin/node/rpc/Cargo.toml | 1 - bin/node/rpc/src/lib.rs | 24 ++--- client/consensus/babe/rpc/src/lib.rs | 135 +++++++++++++------------- client/consensus/babe/src/lib.rs | 140 ++++++++++++++------------- client/sync-state-rpc/src/lib.rs | 35 ++++--- 7 files changed, 171 insertions(+), 175 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bb8081221f0e2..b7d3bd5ee41e6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5142,7 +5142,6 @@ dependencies = [ "sc-client-api", "sc-consensus-babe", "sc-consensus-babe-rpc", - "sc-consensus-epochs", "sc-consensus-grandpa", "sc-consensus-grandpa-rpc", "sc-rpc", diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs index 7b0dfcda6ff0e..de640180574ce 100644 --- a/bin/node/cli/src/service.rs +++ b/bin/node/cli/src/service.rs @@ -203,7 +203,7 @@ pub fn new_partial( )?; let slot_duration = babe_link.config().slot_duration(); - let import_queue = sc_consensus_babe::import_queue( + let (import_queue, babe_worker_handle) = sc_consensus_babe::import_queue( babe_link.clone(), block_import.clone(), Some(Box::new(justification_import)), @@ -228,7 +228,7 @@ pub fn new_partial( let import_setup = (block_import, grandpa_link, babe_link); let (rpc_extensions_builder, rpc_setup) = { - let (_, grandpa_link, babe_link) = &import_setup; + let (_, grandpa_link, _) = &import_setup; let justification_stream = grandpa_link.justification_stream(); let shared_authority_set = grandpa_link.shared_authority_set().clone(); @@ -240,9 +240,6 @@ pub fn new_partial( Some(shared_authority_set.clone()), ); - let babe_config = babe_link.config().clone(); - let shared_epoch_changes = babe_link.epoch_changes().clone(); - let client = client.clone(); let pool = transaction_pool.clone(); let select_chain = select_chain.clone(); @@ -258,9 +255,8 @@ pub fn new_partial( chain_spec: chain_spec.cloned_box(), deny_unsafe, babe: node_rpc::BabeDeps { - babe_config: babe_config.clone(), - shared_epoch_changes: shared_epoch_changes.clone(), keystore: keystore.clone(), + babe_worker_handle: babe_worker_handle.clone(), }, grandpa: node_rpc::GrandpaDeps { shared_voter_state: shared_voter_state.clone(), diff --git a/bin/node/rpc/Cargo.toml b/bin/node/rpc/Cargo.toml index 0ea6f49bd6094..724efbe9a5721 100644 --- a/bin/node/rpc/Cargo.toml +++ b/bin/node/rpc/Cargo.toml @@ -21,7 +21,6 @@ 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-consensus-grandpa = { version = "0.10.0-dev", path = "../../../client/consensus/grandpa" } sc-consensus-grandpa-rpc = { version = "0.10.0-dev", path = "../../../client/consensus/grandpa/rpc" } sc-rpc = { version = "4.0.0-dev", path = "../../../client/rpc" } diff --git a/bin/node/rpc/src/lib.rs b/bin/node/rpc/src/lib.rs index 9dcdf0f218923..5f61fdcd55d97 100644 --- a/bin/node/rpc/src/lib.rs +++ b/bin/node/rpc/src/lib.rs @@ -36,8 +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::{BabeConfiguration, Epoch}; -use sc_consensus_epochs::SharedEpochChanges; +use sc_consensus_babe::BabeWorkerHandle; use sc_consensus_grandpa::{ FinalityProofProvider, GrandpaJustificationStream, SharedAuthoritySet, SharedVoterState, }; @@ -53,10 +52,8 @@ use sp_keystore::KeystorePtr; /// Extra dependencies for BABE. pub struct BabeDeps { - /// BABE protocol config. - pub babe_config: BabeConfiguration, - /// BABE pending epoch changes. - pub shared_epoch_changes: SharedEpochChanges, + /// A handle to the BABE worker for issuing requests. + pub babe_worker_handle: BabeWorkerHandle, /// The keystore that manages the keys of the node. pub keystore: KeystorePtr, } @@ -130,7 +127,7 @@ where 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; + let BabeDeps { keystore, babe_worker_handle } = babe; let GrandpaDeps { shared_voter_state, shared_authority_set, @@ -151,15 +148,8 @@ where io.merge(Mmr::new(client.clone()).into_rpc())?; io.merge(TransactionPayment::new(client.clone()).into_rpc())?; io.merge( - Babe::new( - client.clone(), - shared_epoch_changes.clone(), - keystore, - babe_config, - select_chain, - deny_unsafe, - ) - .into_rpc(), + Babe::new(client.clone(), babe_worker_handle.clone(), keystore, select_chain, deny_unsafe) + .into_rpc(), )?; io.merge( Grandpa::new( @@ -173,7 +163,7 @@ where )?; io.merge( - SyncState::new(chain_spec, client.clone(), shared_authority_set, shared_epoch_changes)? + SyncState::new(chain_spec, client.clone(), shared_authority_set, babe_worker_handle)? .into_rpc(), )?; diff --git a/client/consensus/babe/rpc/src/lib.rs b/client/consensus/babe/rpc/src/lib.rs index cdc8dbfd80a34..1ae15cc5453d7 100644 --- a/client/consensus/babe/rpc/src/lib.rs +++ b/client/consensus/babe/rpc/src/lib.rs @@ -18,28 +18,29 @@ //! RPC api for babe. +use std::{collections::HashMap, sync::Arc}; + use futures::TryFutureExt; use jsonrpsee::{ core::{async_trait, Error as JsonRpseeError, RpcResult}, proc_macros::rpc, types::{error::CallError, ErrorObject}, }; +use serde::{Deserialize, Serialize}; -use sc_consensus_babe::{authorship, Epoch}; -use sc_consensus_epochs::{descendent_query, Epoch as EpochT, SharedEpochChanges}; +use sc_consensus_babe::{authorship, BabeWorkerHandle}; +use sc_consensus_epochs::Epoch as EpochT; use sc_rpc_api::DenyUnsafe; -use serde::{Deserialize, Serialize}; use sp_api::ProvideRuntimeApi; use sp_application_crypto::AppCrypto; 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, BabeConfiguration, -}; +use sp_consensus_babe::{digests::PreDigest, AuthorityId, BabeApi as BabeRuntimeApi}; use sp_core::crypto::ByteArray; use sp_keystore::KeystorePtr; use sp_runtime::traits::{Block as BlockT, Header as _}; -use std::{collections::HashMap, sync::Arc}; + +const BABE_ERROR: i32 = 9000; /// Provides rpc methods for interacting with Babe. #[rpc(client, server)] @@ -54,12 +55,10 @@ pub trait BabeApi { pub struct Babe { /// shared reference to the client. client: Arc, - /// shared reference to EpochChanges - shared_epoch_changes: SharedEpochChanges, + /// A handle to the BABE worker for issuing requests. + babe_worker_handle: BabeWorkerHandle, /// shared reference to the Keystore keystore: KeystorePtr, - /// config (actually holds the slot duration) - babe_config: BabeConfiguration, /// The SelectChain strategy select_chain: SC, /// Whether to deny unsafe calls @@ -70,13 +69,12 @@ impl Babe { /// Creates a new instance of the Babe Rpc handler. pub fn new( client: Arc, - shared_epoch_changes: SharedEpochChanges, + babe_worker_handle: BabeWorkerHandle, keystore: KeystorePtr, - babe_config: BabeConfiguration, select_chain: SC, deny_unsafe: DenyUnsafe, ) -> Self { - Self { client, shared_epoch_changes, keystore, babe_config, select_chain, deny_unsafe } + Self { client, babe_worker_handle, keystore, select_chain, deny_unsafe } } } @@ -93,21 +91,21 @@ where { 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 best_header = self.select_chain.best_chain().map_err(Error::SelectChain).await?; + let epoch_start = self .client .runtime_api() - .current_epoch_start(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?; + .current_epoch_start(best_header.hash()) + .map_err(|_| Error::FetchEpoch)?; + + let epoch = self + .babe_worker_handle + .epoch_data_for_child_of(best_header.hash(), *best_header.number(), epoch_start) + .await + .map_err(|_| Error::FetchEpoch)?; + let (epoch_start, epoch_end) = (epoch.start_slot(), epoch.end_slot()); let mut claims: HashMap = HashMap::new(); @@ -159,59 +157,37 @@ pub struct EpochAuthorship { secondary_vrf: Vec, } -/// Errors encountered by the RPC +/// Top-level error type for the RPC handler. #[derive(Debug, thiserror::Error)] pub enum Error { - /// Consensus error - #[error(transparent)] - Consensus(#[from] ConsensusError), - /// Errors that can be formatted as a String - #[error("{0}")] - StringError(String), + /// Failed to fetch the current best header. + #[error("Failed to fetch the current best header: {0}")] + SelectChain(ConsensusError), + /// Failed to fetch epoch data. + #[error("Failed to fetch epoch data")] + FetchEpoch, } impl From for JsonRpseeError { fn from(error: Error) -> Self { + let error_code = match error { + Error::SelectChain(_) => 1, + Error::FetchEpoch => 2, + }; + JsonRpseeError::Call(CallError::Custom(ErrorObject::owned( - 1234, + BABE_ERROR + error_code, error.to_string(), - None::<()>, + Some(format!("{:?}", error)), ))) } } -/// Fetches the epoch data for a given slot. -async fn epoch_data( - epoch_changes: &SharedEpochChanges, - client: &Arc, - babe_config: &BabeConfiguration, - slot: u64, - select_chain: &SC, -) -> Result -where - B: BlockT, - C: HeaderBackend + HeaderMetadata + 'static, - SC: SelectChain, -{ - let parent = select_chain.best_chain().await?; - epoch_changes - .shared_data() - .epoch_data_for_child_of( - descendent_query(&**client), - &parent.hash(), - *parent.number(), - slot.into(), - |slot| Epoch::genesis(babe_config, slot), - ) - .map_err(|e| Error::Consensus(ConsensusError::ChainLookup(e.to_string())))? - .ok_or(Error::Consensus(ConsensusError::InvalidAuthoritiesSet)) -} - #[cfg(test)] mod tests { use super::*; - use sc_consensus_babe::block_import; - use sp_core::crypto::key_types::BABE; + use sp_consensus_babe::inherents::InherentDataProvider; + use sp_core::{crypto::key_types::BABE, testing::TaskExecutor}; use sp_keyring::Sr25519Keyring; use sp_keystore::{testing::MemoryKeystore, Keystore}; use substrate_test_runtime_client::{ @@ -233,14 +209,35 @@ mod tests { let builder = TestClientBuilder::new(); let (client, longest_chain) = builder.build_with_longest_chain(); let client = Arc::new(client); + let task_executor = TaskExecutor::new(); + let keystore = create_keystore(Sr25519Keyring::Alice); + 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"); + let slot_duration = config.slot_duration(); - let epoch_changes = link.epoch_changes().clone(); - let keystore = create_keystore(Sr25519Keyring::Alice); + let (block_import, link) = + sc_consensus_babe::block_import(config.clone(), client.clone(), client.clone()) + .expect("can initialize block-import"); + + let (_, babe_worker_handle) = sc_consensus_babe::import_queue( + link.clone(), + block_import.clone(), + None, + client.clone(), + longest_chain.clone(), + move |_, _| async move { + Ok((InherentDataProvider::from_timestamp_and_slot_duration( + 0.into(), + slot_duration, + ),)) + }, + &task_executor, + None, + None, + ) + .unwrap(); - Babe::new(client.clone(), epoch_changes, keystore, config, longest_chain, deny_unsafe) + Babe::new(client.clone(), babe_worker_handle, keystore, longest_chain, deny_unsafe) } #[tokio::test] diff --git a/client/consensus/babe/src/lib.rs b/client/consensus/babe/src/lib.rs index e540cae1f7e76..6327c8c657bb6 100644 --- a/client/consensus/babe/src/lib.rs +++ b/client/consensus/babe/src/lib.rs @@ -89,8 +89,8 @@ use prometheus_endpoint::Registry; use schnorrkel::SignatureError; use sc_client_api::{ - backend::AuxStore, AuxDataOperations, Backend as BackendT, BlockchainEvents, - FinalityNotification, PreCommitActions, ProvideUncles, UsageProvider, + backend::AuxStore, AuxDataOperations, Backend as BackendT, FinalityNotification, + PreCommitActions, UsageProvider, }; use sc_consensus::{ block_import::{ @@ -338,6 +338,9 @@ pub enum Error { /// Create inherents error. #[error("Creating inherents failed: {0}")] CreateInherents(sp_inherents::Error), + /// Background worker is not running and therefore requests cannot be answered. + #[error("Background worker is not running")] + BackgroundWorkerTerminated, /// Client error #[error(transparent)] Client(sp_blockchain::Error), @@ -475,9 +478,6 @@ pub fn start_babe( where B: BlockT, C: ProvideRuntimeApi - + ProvideUncles - + BlockchainEvents - + PreCommitActions + HeaderBackend + HeaderMetadata + Send @@ -498,8 +498,6 @@ where BS: BackoffAuthoringBlocksStrategy> + Send + Sync + 'static, Error: std::error::Error + Send + From + From + 'static, { - const HANDLE_BUFFER_SIZE: usize = 1024; - let slot_notification_sinks = Arc::new(Mutex::new(Vec::new())); let worker = BabeSlotWorker { @@ -529,17 +527,7 @@ where create_inherent_data_providers, ); - let (worker_tx, worker_rx) = channel(HANDLE_BUFFER_SIZE); - - let answer_requests = - 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 { - inner: Box::pin(inner.map(|_| ())), - slot_notification_sinks, - handle: BabeWorkerHandle(worker_tx), - }) + Ok(BabeWorker { inner: Box::pin(slot_worker), slot_notification_sinks }) } // Remove obsolete block's weight data by leveraging finality notifications. @@ -593,42 +581,26 @@ async fn answer_requests( client: Arc, epoch_changes: SharedEpochChanges, ) where - C: ProvideRuntimeApi - + ProvideUncles - + BlockchainEvents - + HeaderBackend - + HeaderMetadata - + Send - + Sync - + 'static, + C: HeaderBackend + HeaderMetadata, { while let Some(request) = request_rx.next().await { match request { - BabeRequest::EpochForChild(parent_hash, parent_number, slot_number, response) => { + BabeRequest::EpochData(response) => { + let _ = response.send(epoch_changes.shared_data().clone()); + }, + BabeRequest::EpochDataForChildOf(parent_hash, parent_number, slot, response) => { let lookup = || { let epoch_changes = epoch_changes.shared_data(); - let epoch_descriptor = epoch_changes - .epoch_descriptor_for_child_of( + epoch_changes + .epoch_data_for_child_of( descendent_query(&*client), &parent_hash, parent_number, - slot_number, + slot, + |slot| Epoch::genesis(&config, slot), ) .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(&config, slot)) - .ok_or(Error::::FetchEpoch(parent_hash))?; - - Ok(sp_consensus_babe::Epoch { - epoch_index: viable_epoch.as_ref().epoch_index, - start_slot: viable_epoch.as_ref().start_slot, - duration: viable_epoch.as_ref().duration, - authorities: viable_epoch.as_ref().authorities.clone(), - randomness: viable_epoch.as_ref().randomness, - config: viable_epoch.as_ref().config.clone(), - }) + .ok_or(Error::::FetchEpoch(parent_hash)) }; let _ = response.send(lookup()); @@ -638,17 +610,13 @@ async fn answer_requests( } /// Requests to the BABE service. -#[non_exhaustive] -pub enum BabeRequest { +enum BabeRequest { + /// Request all available epoch data. + EpochData(oneshot::Sender>), /// Request the epoch that a child of the given block, with the given slot number would have. /// /// The parent block is identified by its hash and number. - EpochForChild( - B::Hash, - NumberFor, - Slot, - oneshot::Sender>>, - ), + EpochDataForChildOf(B::Hash, NumberFor, Slot, oneshot::Sender>>), } /// A handle to the BABE worker for issuing requests. @@ -656,11 +624,41 @@ pub enum BabeRequest { pub struct BabeWorkerHandle(Sender>); impl BabeWorkerHandle { - /// Send a request to the BABE service. - pub async fn send(&mut self, request: BabeRequest) { - // Failure to send means that the service is down. - // This will manifest as the receiver of the request being dropped. - let _ = self.0.send(request).await; + async fn send_request(&self, request: BabeRequest) -> Result<(), Error> { + match self.0.clone().send(request).await { + Err(err) if err.is_disconnected() => return Err(Error::BackgroundWorkerTerminated), + Err(err) => warn!( + target: LOG_TARGET, + "Unhandled error when sending request to worker: {:?}", err + ), + _ => {}, + } + + Ok(()) + } + + /// Fetch all available epoch data. + pub async fn epoch_data(&self) -> Result, Error> { + let (tx, rx) = oneshot::channel(); + self.send_request(BabeRequest::EpochData(tx)).await?; + + rx.await.or(Err(Error::BackgroundWorkerTerminated)) + } + + /// Fetch the epoch that a child of the given block, with the given slot number would have. + /// + /// The parent block is identified by its hash and number. + pub async fn epoch_data_for_child_of( + &self, + parent_hash: B::Hash, + parent_number: NumberFor, + slot: Slot, + ) -> Result> { + let (tx, rx) = oneshot::channel(); + self.send_request(BabeRequest::EpochDataForChildOf(parent_hash, parent_number, slot, tx)) + .await?; + + rx.await.or(Err(Error::BackgroundWorkerTerminated))? } } @@ -669,7 +667,6 @@ impl BabeWorkerHandle { pub struct BabeWorker { inner: Pin + Send + 'static>>, slot_notification_sinks: SlotNotificationSinks, - handle: BabeWorkerHandle, } impl BabeWorker { @@ -684,11 +681,6 @@ impl BabeWorker { self.slot_notification_sinks.lock().push(sink); stream } - - /// Get a handle to the worker. - pub fn handle(&self) -> BabeWorkerHandle { - self.handle.clone() - } } impl Future for BabeWorker { @@ -1790,7 +1782,7 @@ pub fn import_queue( spawner: &impl sp_core::traits::SpawnEssentialNamed, registry: Option<&Registry>, telemetry: Option, -) -> ClientResult> +) -> ClientResult<(DefaultImportQueue, BabeWorkerHandle)> where Inner: BlockImport< Block, @@ -1811,16 +1803,28 @@ where CIDP: CreateInherentDataProviders + Send + Sync + 'static, CIDP::InherentDataProviders: InherentDataProviderExt + Send + Sync, { + const HANDLE_BUFFER_SIZE: usize = 1024; + let verifier = BabeVerifier { select_chain, create_inherent_data_providers, - config: babe_link.config, - epoch_changes: babe_link.epoch_changes, + config: babe_link.config.clone(), + epoch_changes: babe_link.epoch_changes.clone(), telemetry, - client, + client: client.clone(), }; - Ok(BasicQueue::new(verifier, Box::new(block_import), justification_import, spawner, registry)) + let (worker_tx, worker_rx) = channel(HANDLE_BUFFER_SIZE); + + let answer_requests = + answer_requests(worker_rx, babe_link.config, client, babe_link.epoch_changes); + + spawner.spawn_essential("babe-worker", Some("babe"), answer_requests.boxed()); + + Ok(( + BasicQueue::new(verifier, Box::new(block_import), justification_import, spawner, registry), + BabeWorkerHandle(worker_tx), + )) } /// Reverts protocol aux data to at most the last finalized block. diff --git a/client/sync-state-rpc/src/lib.rs b/client/sync-state-rpc/src/lib.rs index 78d5cafa31e26..dda8a7edfa9bb 100644 --- a/client/sync-state-rpc/src/lib.rs +++ b/client/sync-state-rpc/src/lib.rs @@ -41,20 +41,21 @@ #![deny(unused_crate_dependencies)] +use std::sync::Arc; + use jsonrpsee::{ - core::{Error as JsonRpseeError, RpcResult}, + core::{async_trait, Error as JsonRpseeError, RpcResult}, proc_macros::rpc, types::{error::CallError, ErrorObject}, }; + use sc_client_api::StorageData; +use sc_consensus_babe::{BabeWorkerHandle, Error as BabeError}; use sp_blockchain::HeaderBackend; use sp_runtime::traits::{Block as BlockT, NumberFor}; -use std::sync::Arc; type SharedAuthoritySet = sc_consensus_grandpa::SharedAuthoritySet<::Hash, NumberFor>; -type SharedEpochChanges = - sc_consensus_epochs::SharedEpochChanges; /// Error type used by this crate. #[derive(Debug, thiserror::Error)] @@ -66,6 +67,9 @@ pub enum Error { #[error("Failed to load the block weight for block {0:?}")] LoadingBlockWeightFailed(Block::Hash), + #[error("Failed to load the BABE epoch data: {0}")] + LoadingEpochDataFailed(BabeError), + #[error("JsonRpc error: {0}")] JsonRpc(String), @@ -125,7 +129,7 @@ pub struct LightSyncState { 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; + async fn system_gen_sync_spec(&self, raw: bool) -> RpcResult; } /// An api for sync state RPC calls. @@ -133,7 +137,7 @@ pub struct SyncState { chain_spec: Box, client: Arc, shared_authority_set: SharedAuthoritySet, - shared_epoch_changes: SharedEpochChanges, + babe_worker_handle: BabeWorkerHandle, } impl SyncState @@ -146,18 +150,24 @@ where chain_spec: Box, client: Arc, shared_authority_set: SharedAuthoritySet, - shared_epoch_changes: SharedEpochChanges, + babe_worker_handle: BabeWorkerHandle, ) -> Result> { if sc_chain_spec::get_extension::(chain_spec.extensions()) .is_some() { - Ok(Self { chain_spec, client, shared_authority_set, shared_epoch_changes }) + Ok(Self { chain_spec, client, shared_authority_set, babe_worker_handle }) } else { Err(Error::::LightSyncStateExtensionNotFound) } } - fn build_sync_state(&self) -> Result, Error> { + async fn build_sync_state(&self) -> Result, Error> { + let epoch_changes = self + .babe_worker_handle + .epoch_data() + .await + .map_err(Error::LoadingEpochDataFailed)?; + let finalized_hash = self.client.info().finalized_hash; let finalized_header = self .client @@ -170,20 +180,21 @@ where Ok(LightSyncState { finalized_block_header: finalized_header, - babe_epoch_changes: self.shared_epoch_changes.shared_data().clone(), + babe_epoch_changes: epoch_changes, babe_finalized_block_weight: finalized_block_weight, grandpa_authority_set: self.shared_authority_set.clone_inner(), }) } } +#[async_trait] impl SyncStateApiServer for SyncState where Block: BlockT, Backend: HeaderBackend + sc_client_api::AuxStore + 'static, { - fn system_gen_sync_spec(&self, raw: bool) -> RpcResult { - let current_sync_state = self.build_sync_state()?; + async fn system_gen_sync_spec(&self, raw: bool) -> RpcResult { + let current_sync_state = self.build_sync_state().await?; let mut chain_spec = self.chain_spec.cloned_box(); let extension = sc_chain_spec::get_extension_mut::( From 88e2c9e3935c3951da3c6e3bdb8fb1ae74dc1258 Mon Sep 17 00:00:00 2001 From: yjh Date: Tue, 18 Apr 2023 23:46:46 +0800 Subject: [PATCH 666/715] chore(docs): improve some comments (#13937) * chore(docs): improve some comments * Update client/network/common/src/sync/message.rs Co-authored-by: Koute * Update client/rpc-api/src/chain/mod.rs Co-authored-by: Koute * Update client/rpc/src/chain/mod.rs Co-authored-by: Koute * Update client/rpc/src/chain/mod.rs Co-authored-by: Koute * Update frame/staking/src/pallet/impls.rs Co-authored-by: Koute --------- Co-authored-by: Koute --- client/network/common/src/sync/message.rs | 2 +- client/network/common/src/sync/warp.rs | 4 ++-- client/rpc-api/src/chain/mod.rs | 2 +- client/rpc/src/chain/mod.rs | 4 ++-- frame/staking/src/pallet/impls.rs | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/client/network/common/src/sync/message.rs b/client/network/common/src/sync/message.rs index c651660c89c8d..7cdb14172885e 100644 --- a/client/network/common/src/sync/message.rs +++ b/client/network/common/src/sync/message.rs @@ -185,7 +185,7 @@ pub mod generic { pub blocks: Vec>, } - /// Announce a new complete relay chain block on the network. + /// Announce a new complete block on the network. #[derive(Debug, PartialEq, Eq, Clone)] pub struct BlockAnnounce { /// New block header. diff --git a/client/network/common/src/sync/warp.rs b/client/network/common/src/sync/warp.rs index 5f2cacd2eeae5..aef257af4d057 100644 --- a/client/network/common/src/sync/warp.rs +++ b/client/network/common/src/sync/warp.rs @@ -32,7 +32,7 @@ pub struct WarpProofRequest { /// The different types of warp syncing. pub enum WarpSyncParams { - /// Standard warp sync for the relay chain + /// Standard warp sync for the chain. WithProvider(Arc>), /// Skip downloading proofs and wait for a header of the state that should be downloaded. /// @@ -48,7 +48,7 @@ pub enum VerificationResult { Complete(SetId, AuthorityList, Block::Header), } -/// Warp sync backend. Handles retrieveing and verifying warp sync proofs. +/// Warp sync backend. Handles retrieving and verifying warp sync proofs. pub trait WarpSyncProvider: Send + Sync { /// Generate proof starting at given block hash. The proof is accumulated until maximum proof /// size is reached. diff --git a/client/rpc-api/src/chain/mod.rs b/client/rpc-api/src/chain/mod.rs index 2ed767c370a65..f215cd978f03a 100644 --- a/client/rpc-api/src/chain/mod.rs +++ b/client/rpc-api/src/chain/mod.rs @@ -29,7 +29,7 @@ pub trait ChainApi { #[method(name = "chain_getHeader", blocking)] fn header(&self, hash: Option) -> RpcResult>; - /// Get header and body of a relay chain block. + /// Get header and body of a block. #[method(name = "chain_getBlock", blocking)] fn block(&self, hash: Option) -> RpcResult>; diff --git a/client/rpc/src/chain/mod.rs b/client/rpc/src/chain/mod.rs index d54811320e749..2b5994f217df3 100644 --- a/client/rpc/src/chain/mod.rs +++ b/client/rpc/src/chain/mod.rs @@ -59,10 +59,10 @@ where } } - /// Get header of a relay chain block. + /// Get header of a block. fn header(&self, hash: Option) -> Result, Error>; - /// Get header and body of a relay chain block. + /// Get header and body of a block. fn block(&self, hash: Option) -> Result>, Error>; /// Get hash of the n-th block in the canon chain. diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 5143538c2a513..3058d3edc6fd6 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -1230,7 +1230,7 @@ impl historical::SessionManager pallet_authorship::EventHandler for Pallet where T: Config + pallet_authorship::Config + pallet_session::Config, From 917f7e38c58cbf98ef2a2ed460bab530b160bc1e Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Wed, 19 Apr 2023 09:49:42 +0200 Subject: [PATCH 667/715] feat: pallet asset-rate (#13608) * poc * fix: remove AssetIdParameter * tests: add * docs: add pallet description * feat: add benches * refactor: UnknownAssetId * fix: normalize mock cfg * fix: benchmarks * chore: add weights * refactor: remove storage getter * chore: apply suggestions from code review * docs: add native balance to calls * chore: apply suggestions from code review * chore: apply ConversionFromAssetBalance * tests: update balance mock * chore: apply suggestions from code review * ci: set publish to false * docs: fix missing rustdoc --------- Co-authored-by: parity-processbot <> --- Cargo.lock | 17 ++ Cargo.toml | 1 + bin/node/runtime/Cargo.toml | 4 + bin/node/runtime/src/lib.rs | 13 ++ frame/asset-rate/Cargo.toml | 52 ++++++ frame/asset-rate/src/benchmarking.rs | 86 ++++++++++ frame/asset-rate/src/lib.rs | 239 +++++++++++++++++++++++++++ frame/asset-rate/src/mock.rs | 100 +++++++++++ frame/asset-rate/src/tests.rs | 121 ++++++++++++++ frame/asset-rate/src/weights.rs | 129 +++++++++++++++ 10 files changed, 762 insertions(+) create mode 100644 frame/asset-rate/Cargo.toml create mode 100644 frame/asset-rate/src/benchmarking.rs create mode 100644 frame/asset-rate/src/lib.rs create mode 100644 frame/asset-rate/src/mock.rs create mode 100644 frame/asset-rate/src/tests.rs create mode 100644 frame/asset-rate/src/weights.rs diff --git a/Cargo.lock b/Cargo.lock index b7d3bd5ee41e6..c0920e4dc6659 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3634,6 +3634,7 @@ dependencies = [ "log", "node-primitives", "pallet-alliance", + "pallet-asset-rate", "pallet-asset-tx-payment", "pallet-assets", "pallet-authority-discovery", @@ -5556,6 +5557,22 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-asset-rate" +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-asset-tx-payment" version = "4.0.0-dev" diff --git a/Cargo.toml b/Cargo.toml index cae8976cca4a9..ae89750dd8f26 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -166,6 +166,7 @@ members = [ "frame/transaction-payment/rpc/runtime-api", "frame/transaction-storage", "frame/treasury", + "frame/asset-rate", "frame/tips", "frame/uniques", "frame/utility", diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index 65a8d208d7f4c..0fa037c657cee 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -53,6 +53,7 @@ frame-election-provider-support = { version = "4.0.0-dev", default-features = fa 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-asset-rate = { version = "4.0.0-dev", default-features = false, path = "../../../frame/asset-rate" } 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" } @@ -201,6 +202,7 @@ std = [ "pallet-transaction-payment/std", "pallet-transaction-storage/std", "pallet-treasury/std", + "pallet-asset-rate/std", "sp-transaction-pool/std", "pallet-utility/std", "sp-version/std", @@ -272,6 +274,7 @@ runtime-benchmarks = [ "pallet-tips/runtime-benchmarks", "pallet-transaction-storage/runtime-benchmarks", "pallet-treasury/runtime-benchmarks", + "pallet-asset-rate/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-uniques/runtime-benchmarks", "pallet-nfts/runtime-benchmarks", @@ -333,6 +336,7 @@ try-runtime = [ "pallet-timestamp/try-runtime", "pallet-tips/try-runtime", "pallet-treasury/try-runtime", + "pallet-asset-rate/try-runtime", "pallet-utility/try-runtime", "pallet-transaction-payment/try-runtime", "pallet-asset-tx-payment/try-runtime", diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 433ca8e8b839e..cdb05d1597629 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1131,6 +1131,17 @@ impl pallet_treasury::Config for Runtime { type SpendOrigin = EnsureWithSuccess, AccountId, MaxBalance>; } +impl pallet_asset_rate::Config for Runtime { + type CreateOrigin = EnsureRoot; + type RemoveOrigin = EnsureRoot; + type UpdateOrigin = EnsureRoot; + type Balance = Balance; + type Currency = Balances; + type AssetId = u32; + type RuntimeEvent = RuntimeEvent; + type WeightInfo = pallet_asset_rate::weights::SubstrateWeight; +} + parameter_types! { pub const BountyCuratorDeposit: Permill = Permill::from_percent(50); pub const BountyValueMinimum: Balance = 5 * DOLLARS; @@ -1765,6 +1776,7 @@ construct_runtime!( TechnicalMembership: pallet_membership::, Grandpa: pallet_grandpa, Treasury: pallet_treasury, + AssetRate: pallet_asset_rate, Contracts: pallet_contracts, Sudo: pallet_sudo, ImOnline: pallet_im_online, @@ -1922,6 +1934,7 @@ mod benches { [pallet_tips, Tips] [pallet_transaction_storage, TransactionStorage] [pallet_treasury, Treasury] + [pallet_asset_rate, AssetRate] [pallet_uniques, Uniques] [pallet_nfts, Nfts] [pallet_utility, Utility] diff --git a/frame/asset-rate/Cargo.toml b/frame/asset-rate/Cargo.toml new file mode 100644 index 0000000000000..36aabb12bcbbd --- /dev/null +++ b/frame/asset-rate/Cargo.toml @@ -0,0 +1,52 @@ +[package] +name = "pallet-asset-rate" +version = "4.0.0-dev" +description = "Whitelist non-native assets for treasury spending and provide conversion to native balance" +authors = ["William Freudenberger "] +homepage = "https://substrate.io" +edition = "2021" +license = "Apache-2.0" +repository = "https://github.com/paritytech/substrate/" +publish = false + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.2.2", 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" } +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] +default = ["std"] +std = [ + "codec/std", + "frame-benchmarking?/std", + "frame-support/std", + "frame-system/std", + "scale-info/std", + "sp-runtime/std", + "sp-std/std", +] +runtime-benchmarks = [ + "frame-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", +] +try-runtime = [ + "frame-support/try-runtime", + "frame-system/try-runtime", + "sp-runtime/try-runtime", +] diff --git a/frame/asset-rate/src/benchmarking.rs b/frame/asset-rate/src/benchmarking.rs new file mode 100644 index 0000000000000..dde0d764affb2 --- /dev/null +++ b/frame/asset-rate/src/benchmarking.rs @@ -0,0 +1,86 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT 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 benchmarks. + +use super::*; +use crate::{pallet as pallet_asset_rate, Pallet as AssetRate}; + +use frame_benchmarking::v2::*; +use frame_support::assert_ok; +use frame_system::RawOrigin; + +const ASSET_ID: u32 = 1; + +fn default_conversion_rate() -> FixedU128 { + FixedU128::from_u32(1u32) +} + +#[benchmarks(where ::AssetId: From)] +mod benchmarks { + use super::*; + + #[benchmark] + fn create() -> Result<(), BenchmarkError> { + let asset_id: T::AssetId = ASSET_ID.into(); + #[extrinsic_call] + _(RawOrigin::Root, asset_id, default_conversion_rate()); + + assert_eq!( + pallet_asset_rate::ConversionRateToNative::::get(asset_id), + Some(default_conversion_rate()) + ); + Ok(()) + } + + #[benchmark] + fn update() -> Result<(), BenchmarkError> { + let asset_id: T::AssetId = ASSET_ID.into(); + assert_ok!(AssetRate::::create( + RawOrigin::Root.into(), + asset_id, + default_conversion_rate() + )); + + #[extrinsic_call] + _(RawOrigin::Root, asset_id, FixedU128::from_u32(2)); + + assert_eq!( + pallet_asset_rate::ConversionRateToNative::::get(asset_id), + Some(FixedU128::from_u32(2)) + ); + Ok(()) + } + + #[benchmark] + fn remove() -> Result<(), BenchmarkError> { + let asset_id: T::AssetId = ASSET_ID.into(); + assert_ok!(AssetRate::::create( + RawOrigin::Root.into(), + ASSET_ID.into(), + default_conversion_rate() + )); + + #[extrinsic_call] + _(RawOrigin::Root, asset_id); + + assert!(pallet_asset_rate::ConversionRateToNative::::get(asset_id).is_none()); + Ok(()) + } + + impl_benchmark_test_suite! { AssetRate, crate::mock::new_test_ext(), crate::mock::Test } +} diff --git a/frame/asset-rate/src/lib.rs b/frame/asset-rate/src/lib.rs new file mode 100644 index 0000000000000..8c6597a389833 --- /dev/null +++ b/frame/asset-rate/src/lib.rs @@ -0,0 +1,239 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! # Asset Rate Pallet +//! +//! - [`Config`] +//! - [`Call`] +//! +//! ## Overview +//! +//! The AssetRate pallet provides means of setting conversion rates for some asset to native +//! balance. +//! +//! The supported dispatchable functions are documented in the [`Call`] enum. +//! +//! ### Terminology +//! +//! * **Asset balance**: The balance type of an arbitrary asset. The network might only know about +//! the identifier of the asset and nothing more. +//! * **Native balance**: The balance type of the network's native currency. +//! +//! ### Goals +//! +//! The asset-rate system in Substrate is designed to make the following possible: +//! +//! * Providing a soft conversion for the balance of supported assets to a default asset class. +//! * Updating existing conversion rates. +//! +//! ## Interface +//! +//! ### Permissioned Functions +//! +//! * `create`: Creates a new asset conversion rate. +//! * `remove`: Removes an existing asset conversion rate. +//! * `update`: Overwrites an existing assert conversion rate. +//! +//! Please refer to the [`Call`] enum and its associated variants for documentation on each +//! function. +//! +//! ### Assumptions +//! +//! * Conversion rates are only used as estimates, and are not designed to be precise or closely +//! tracking real world values. +//! * All conversion rates reflect the ration of some asset to native, e.g. native = asset * rate. + +#![cfg_attr(not(feature = "std"), no_std)] + +use frame_support::traits::{ + fungible::Inspect, + tokens::{Balance, ConversionFromAssetBalance}, +}; +use sp_runtime::{traits::Zero, FixedPointNumber, FixedPointOperand, FixedU128}; + +pub use pallet::*; +pub use weights::WeightInfo; + +#[cfg(feature = "runtime-benchmarks")] +pub mod benchmarking; +#[cfg(test)] +mod mock; +#[cfg(test)] +mod tests; +pub mod weights; + +// Type alias for `frame_system`'s account id. +type AccountIdOf = ::AccountId; +// This pallet's asset id and balance type. +type AssetIdOf = ::AssetId; +// Generic fungible balance type. +type BalanceOf = <::Currency as Inspect>>::Balance; + +#[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 { + /// The Weight information for extrinsics in this pallet. + type WeightInfo: WeightInfo; + + /// The runtime event type. + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + + /// The origin permissioned to create a conversion rate for an asset. + type CreateOrigin: EnsureOrigin; + + /// The origin permissioned to remove an existing conversion rate for an asset. + type RemoveOrigin: EnsureOrigin; + + /// The origin permissioned to update an existiing conversion rate for an asset. + type UpdateOrigin: EnsureOrigin; + + /// The units in which we record balances. + type Balance: Balance + FixedPointOperand; + + /// The currency mechanism for this pallet. + type Currency: Inspect; + + /// The identifier for the class of asset. + type AssetId: frame_support::traits::tokens::AssetId; + } + + /// Maps an asset to its fixed point representation in the native balance. + /// + /// E.g. `native_amount = asset_amount * ConversionRateToNative::::get(asset_id)` + #[pallet::storage] + pub type ConversionRateToNative = + StorageMap<_, Blake2_128Concat, T::AssetId, FixedU128, OptionQuery>; + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + // Some `asset_id` conversion rate was created. + AssetRateCreated { asset_id: T::AssetId, rate: FixedU128 }, + // Some `asset_id` conversion rate was removed. + AssetRateRemoved { asset_id: T::AssetId }, + // Some existing `asset_id` conversion rate was updated from `old` to `new`. + AssetRateUpdated { asset_id: T::AssetId, old: FixedU128, new: FixedU128 }, + } + + #[pallet::error] + pub enum Error { + /// The given asset ID is unknown. + UnknownAssetId, + /// The given asset ID already has an assigned conversion rate and cannot be re-created. + AlreadyExists, + } + + #[pallet::call] + impl Pallet { + /// Initialize a conversion rate to native balance for the given asset. + /// + /// ## Complexity + /// - O(1) + #[pallet::call_index(0)] + #[pallet::weight(T::WeightInfo::create())] + pub fn create( + origin: OriginFor, + asset_id: T::AssetId, + rate: FixedU128, + ) -> DispatchResult { + T::CreateOrigin::ensure_origin(origin)?; + + ensure!( + !ConversionRateToNative::::contains_key(asset_id), + Error::::AlreadyExists + ); + ConversionRateToNative::::set(asset_id, Some(rate)); + + Self::deposit_event(Event::AssetRateCreated { asset_id, rate }); + Ok(()) + } + + /// Update the conversion rate to native balance for the given asset. + /// + /// ## Complexity + /// - O(1) + #[pallet::call_index(1)] + #[pallet::weight(T::WeightInfo::update())] + pub fn update( + origin: OriginFor, + asset_id: T::AssetId, + rate: FixedU128, + ) -> DispatchResult { + T::UpdateOrigin::ensure_origin(origin)?; + + let mut old = FixedU128::zero(); + ConversionRateToNative::::mutate(asset_id, |maybe_rate| { + if let Some(r) = maybe_rate { + old = *r; + *r = rate; + + Ok(()) + } else { + Err(Error::::UnknownAssetId) + } + })?; + + Self::deposit_event(Event::AssetRateUpdated { asset_id, old, new: rate }); + Ok(()) + } + + /// Remove an existing conversion rate to native balance for the given asset. + /// + /// ## Complexity + /// - O(1) + #[pallet::call_index(2)] + #[pallet::weight(T::WeightInfo::remove())] + pub fn remove(origin: OriginFor, asset_id: T::AssetId) -> DispatchResult { + T::RemoveOrigin::ensure_origin(origin)?; + + ensure!( + ConversionRateToNative::::contains_key(asset_id), + Error::::UnknownAssetId + ); + ConversionRateToNative::::remove(asset_id); + + Self::deposit_event(Event::AssetRateRemoved { asset_id }); + Ok(()) + } + } +} + +/// Exposes conversion of an arbitrary balance of an asset to native balance. +impl ConversionFromAssetBalance, AssetIdOf, BalanceOf> for Pallet +where + T: Config, + BalanceOf: FixedPointOperand + Zero, +{ + type Error = pallet::Error; + + fn from_asset_balance( + balance: BalanceOf, + asset_id: AssetIdOf, + ) -> Result, pallet::Error> { + let rate = pallet::ConversionRateToNative::::get(asset_id) + .ok_or(pallet::Error::::UnknownAssetId.into())?; + Ok(rate.saturating_mul_int(balance)) + } +} diff --git a/frame/asset-rate/src/mock.rs b/frame/asset-rate/src/mock.rs new file mode 100644 index 0000000000000..9775b7a747926 --- /dev/null +++ b/frame/asset-rate/src/mock.rs @@ -0,0 +1,100 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! The crate's mock. + +use crate as pallet_asset_rate; +use frame_support::traits::{ConstU16, ConstU64}; +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, + AssetRate: pallet_asset_rate, + Balances: pallet_balances, + } +); + +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 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 = ConstU16<42>; + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; +} + +impl pallet_balances::Config for Test { + type Balance = u64; + type DustRemoval = (); + type RuntimeEvent = RuntimeEvent; + type ExistentialDeposit = ConstU64<1>; + type AccountStore = System; + type WeightInfo = (); + type MaxLocks = (); + type MaxReserves = (); + type ReserveIdentifier = [u8; 8]; + type HoldIdentifier = (); + type FreezeIdentifier = (); + type MaxHolds = (); + type MaxFreezes = (); +} + +impl pallet_asset_rate::Config for Test { + type WeightInfo = (); + type RuntimeEvent = RuntimeEvent; + type CreateOrigin = frame_system::EnsureRoot; + type RemoveOrigin = frame_system::EnsureRoot; + type UpdateOrigin = frame_system::EnsureRoot; + type Balance = u64; + type Currency = Balances; + type AssetId = u32; +} + +// Build genesis storage according to the mock runtime. +pub fn new_test_ext() -> sp_io::TestExternalities { + frame_system::GenesisConfig::default().build_storage::().unwrap().into() +} diff --git a/frame/asset-rate/src/tests.rs b/frame/asset-rate/src/tests.rs new file mode 100644 index 0000000000000..4e5a3167bef21 --- /dev/null +++ b/frame/asset-rate/src/tests.rs @@ -0,0 +1,121 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT 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::pallet as pallet_asset_rate; +use frame_support::{assert_noop, assert_ok}; +use mock::{new_test_ext, AssetRate, RuntimeOrigin, Test}; +use sp_runtime::FixedU128; + +const ASSET_ID: u32 = 42; + +#[test] +fn create_works() { + new_test_ext().execute_with(|| { + assert!(pallet_asset_rate::ConversionRateToNative::::get(ASSET_ID).is_none()); + assert_ok!(AssetRate::create(RuntimeOrigin::root(), ASSET_ID, FixedU128::from_float(0.1))); + + assert_eq!( + pallet_asset_rate::ConversionRateToNative::::get(ASSET_ID), + Some(FixedU128::from_float(0.1)) + ); + }); +} + +#[test] +fn create_existing_throws() { + new_test_ext().execute_with(|| { + assert!(pallet_asset_rate::ConversionRateToNative::::get(ASSET_ID).is_none()); + assert_ok!(AssetRate::create(RuntimeOrigin::root(), ASSET_ID, FixedU128::from_float(0.1))); + + assert_noop!( + AssetRate::create(RuntimeOrigin::root(), ASSET_ID, FixedU128::from_float(0.1)), + Error::::AlreadyExists + ); + }); +} + +#[test] +fn remove_works() { + new_test_ext().execute_with(|| { + assert_ok!(AssetRate::create(RuntimeOrigin::root(), ASSET_ID, FixedU128::from_float(0.1))); + + assert_ok!(AssetRate::remove(RuntimeOrigin::root(), ASSET_ID,)); + assert!(pallet_asset_rate::ConversionRateToNative::::get(ASSET_ID).is_none()); + }); +} + +#[test] +fn remove_unknown_throws() { + new_test_ext().execute_with(|| { + assert_noop!( + AssetRate::remove(RuntimeOrigin::root(), ASSET_ID,), + Error::::UnknownAssetId + ); + }); +} + +#[test] +fn update_works() { + new_test_ext().execute_with(|| { + assert_ok!(AssetRate::create(RuntimeOrigin::root(), ASSET_ID, FixedU128::from_float(0.1))); + assert_ok!(AssetRate::update(RuntimeOrigin::root(), ASSET_ID, FixedU128::from_float(0.5))); + + assert_eq!( + pallet_asset_rate::ConversionRateToNative::::get(ASSET_ID), + Some(FixedU128::from_float(0.5)) + ); + }); +} + +#[test] +fn update_unknown_throws() { + new_test_ext().execute_with(|| { + assert_noop!( + AssetRate::update(RuntimeOrigin::root(), ASSET_ID, FixedU128::from_float(0.5)), + Error::::UnknownAssetId + ); + }); +} + +#[test] +fn convert_works() { + new_test_ext().execute_with(|| { + assert_ok!(AssetRate::create(RuntimeOrigin::root(), ASSET_ID, FixedU128::from_float(2.51))); + + let conversion = , + ::AssetId, + BalanceOf, + >>::from_asset_balance(10, ASSET_ID); + assert_eq!(conversion.expect("Conversion rate exists for asset"), 25); + }); +} + +#[test] +fn convert_unknown_throws() { + new_test_ext().execute_with(|| { + let conversion = , + ::AssetId, + BalanceOf, + >>::from_asset_balance(10, ASSET_ID); + assert!(conversion.is_err()); + }); +} diff --git a/frame/asset-rate/src/weights.rs b/frame/asset-rate/src/weights.rs new file mode 100644 index 0000000000000..4fae62634ef13 --- /dev/null +++ b/frame/asset-rate/src/weights.rs @@ -0,0 +1,129 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for pallet_asset_rate +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `local`, CPU: `` +//! 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_asset_rate +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=./frame/asset-rate/src/weights.rs +// --header=./HEADER-APACHE2 +// --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_asset_rate. +pub trait WeightInfo { + fn create() -> Weight; + fn update() -> Weight; + fn remove() -> Weight; +} + +/// Weights for pallet_asset_rate using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + /// Storage: AssetRate ConversionRateToNative (r:1 w:1) + /// Proof: AssetRate ConversionRateToNative (max_values: None, max_size: Some(36), added: 2511, mode: MaxEncodedLen) + fn create() -> Weight { + // Proof Size summary in bytes: + // Measured: `76` + // Estimated: `3501` + // Minimum execution time: 6_000_000 picoseconds. + Weight::from_parts(7_000_000, 3501) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: AssetRate ConversionRateToNative (r:1 w:1) + /// Proof: AssetRate ConversionRateToNative (max_values: None, max_size: Some(36), added: 2511, mode: MaxEncodedLen) + fn update() -> Weight { + // Proof Size summary in bytes: + // Measured: `137` + // Estimated: `3501` + // Minimum execution time: 7_000_000 picoseconds. + Weight::from_parts(8_000_000, 3501) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: AssetRate ConversionRateToNative (r:1 w:1) + /// Proof: AssetRate ConversionRateToNative (max_values: None, max_size: Some(36), added: 2511, mode: MaxEncodedLen) + fn remove() -> Weight { + // Proof Size summary in bytes: + // Measured: `137` + // Estimated: `3501` + // Minimum execution time: 7_000_000 picoseconds. + Weight::from_parts(8_000_000, 3501) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } +} + +// For backwards compatibility and tests +impl WeightInfo for () { + /// Storage: AssetRate ConversionRateToNative (r:1 w:1) + /// Proof: AssetRate ConversionRateToNative (max_values: None, max_size: Some(36), added: 2511, mode: MaxEncodedLen) + fn create() -> Weight { + // Proof Size summary in bytes: + // Measured: `76` + // Estimated: `3501` + // Minimum execution time: 6_000_000 picoseconds. + Weight::from_parts(7_000_000, 3501) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: AssetRate ConversionRateToNative (r:1 w:1) + /// Proof: AssetRate ConversionRateToNative (max_values: None, max_size: Some(36), added: 2511, mode: MaxEncodedLen) + fn update() -> Weight { + // Proof Size summary in bytes: + // Measured: `137` + // Estimated: `3501` + // Minimum execution time: 7_000_000 picoseconds. + Weight::from_parts(8_000_000, 3501) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: AssetRate ConversionRateToNative (r:1 w:1) + /// Proof: AssetRate ConversionRateToNative (max_values: None, max_size: Some(36), added: 2511, mode: MaxEncodedLen) + fn remove() -> Weight { + // Proof Size summary in bytes: + // Measured: `137` + // Estimated: `3501` + // Minimum execution time: 7_000_000 picoseconds. + Weight::from_parts(8_000_000, 3501) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } +} From 1fbf283120446b229ba2cc0da9e175f184949891 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 19 Apr 2023 10:15:57 +0200 Subject: [PATCH 668/715] call_executor: Remove code deduplication (#13948) --- client/service/src/client/call_executor.rs | 34 +++++++++++++--------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/client/service/src/client/call_executor.rs b/client/service/src/client/call_executor.rs index 7979c139e2a6c..7f83d62874c8e 100644 --- a/client/service/src/client/call_executor.rs +++ b/client/service/src/client/call_executor.rs @@ -81,13 +81,14 @@ where fn check_override<'a>( &'a self, onchain_code: RuntimeCode<'a>, - hash: ::Hash, + state: &B::State, + hash: Block::Hash, ) -> sp_blockchain::Result<(RuntimeCode<'a>, RuntimeVersion)> where Block: BlockT, B: backend::Backend, { - let on_chain_version = self.on_chain_runtime_version(hash)?; + let on_chain_version = self.on_chain_runtime_version(&onchain_code, state)?; let code_and_version = if let Some(d) = self.wasm_override.as_ref().as_ref().and_then(|o| { o.get( &on_chain_version.spec_version, @@ -115,17 +116,18 @@ where } /// Returns the on chain runtime version. - fn on_chain_runtime_version(&self, hash: Block::Hash) -> sp_blockchain::Result { + fn on_chain_runtime_version( + &self, + code: &RuntimeCode, + state: &B::State, + ) -> sp_blockchain::Result { let mut overlay = OverlayedChanges::default(); - let state = self.backend.state_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); - let runtime_code = - state_runtime_code.runtime_code().map_err(sp_blockchain::Error::RuntimeCode)?; + let mut ext = Ext::new(&mut overlay, &mut cache, state, None); + self.executor - .runtime_version(&mut ext, &runtime_code) + .runtime_version(&mut ext, code) .map_err(|e| sp_blockchain::Error::VersionInvalid(e.to_string())) } } @@ -176,7 +178,7 @@ where let runtime_code = state_runtime_code.runtime_code().map_err(sp_blockchain::Error::RuntimeCode)?; - let runtime_code = self.check_override(runtime_code, at_hash)?.0; + let runtime_code = self.check_override(runtime_code, &state, at_hash)?.0; let extensions = self.execution_extensions.extensions( at_hash, @@ -233,7 +235,7 @@ where let runtime_code = state_runtime_code.runtime_code().map_err(sp_blockchain::Error::RuntimeCode)?; - let runtime_code = self.check_override(runtime_code, at_hash)?.0; + let runtime_code = self.check_override(runtime_code, &state, at_hash)?.0; match recorder { Some(recorder) => { @@ -282,7 +284,7 @@ where let runtime_code = state_runtime_code.runtime_code().map_err(sp_blockchain::Error::RuntimeCode)?; - self.check_override(runtime_code, at_hash).map(|(_, v)| v) + self.check_override(runtime_code, &state, at_hash).map(|(_, v)| v) } fn prove_execution( @@ -300,7 +302,7 @@ where let state_runtime_code = sp_state_machine::backend::BackendRuntimeCode::new(trie_backend); let runtime_code = state_runtime_code.runtime_code().map_err(sp_blockchain::Error::RuntimeCode)?; - let runtime_code = self.check_override(runtime_code, at_hash)?.0; + let runtime_code = self.check_override(runtime_code, &state, at_hash)?.0; sp_state_machine::prove_execution_on_trie_backend( trie_backend, @@ -436,7 +438,11 @@ mod tests { }; let check = call_executor - .check_override(onchain_code, backend.blockchain().info().genesis_hash) + .check_override( + onchain_code, + &backend.state_at(backend.blockchain().info().genesis_hash).unwrap(), + backend.blockchain().info().genesis_hash, + ) .expect("RuntimeCode override") .0; From d4802eb1ac31e574a7bcfa5afe63b8ae92e34d81 Mon Sep 17 00:00:00 2001 From: Mike Ruje Date: Wed, 19 Apr 2023 11:03:56 +0200 Subject: [PATCH 669/715] Improve has good jugement (#13952) * improve run_benchmark * Revert "improve run_benchmark" This reverts commit 4d9cf7a63e37fedca376d692f1461486d3dca659. * improve has_good_judgement * Update bin/node/runtime/src/impls.rs * ".git/.scripts/commands/fmt/fmt.sh" --------- Co-authored-by: Oliver Tale-Yazdi Co-authored-by: command-bot <> --- bin/node/runtime/src/impls.rs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/bin/node/runtime/src/impls.rs b/bin/node/runtime/src/impls.rs index 033549549a73f..05531f47c6e05 100644 --- a/bin/node/runtime/src/impls.rs +++ b/bin/node/runtime/src/impls.rs @@ -61,15 +61,13 @@ impl IdentityVerifier for AllianceIdentityVerifier { 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 - } + crate::Identity::identity(who) + .map(|registration| registration.judgements) + .map_or(false, |judgements| { + judgements + .iter() + .any(|(_, j)| matches!(j, Judgement::KnownGood | Judgement::Reasonable)) + }) } fn super_account_id(who: &AccountId) -> Option { From 37f3d588423cbd295f69a24cae31f2a93936cc93 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Wed, 19 Apr 2023 11:11:47 +0200 Subject: [PATCH 670/715] VRF refactory (#13889) * First iteration to encapsulate schnorrkel and merlin usage * Remove schnorkel direct dependency from BABE pallet * Remove schnorrkel direct dependency from BABE client * Trivial renaming for VrfTranscript data and value * Better errors * Expose a function to get a schnorrkel friendly transcript * Keep the vrf signature stuff together (preventing some clones around) * Fix tests * Remove vrf agnostic transcript and define it as an associated type for VrfSigner and VrfVerifier * Fix babe pallet mock * Inner types are required to be public for polkadot * Update client/consensus/babe/src/verification.rs Co-authored-by: Koute * Nit * Remove Deref implementations * make_bytes as a method * Trigger CI --------- Co-authored-by: Koute --- Cargo.lock | 20 -- Cargo.toml | 1 - client/consensus/babe/Cargo.toml | 3 - client/consensus/babe/src/authorship.rs | 65 +++--- client/consensus/babe/src/lib.rs | 21 +- client/consensus/babe/src/migration.rs | 4 +- client/consensus/babe/src/tests.rs | 67 ++---- client/consensus/babe/src/verification.rs | 84 ++++---- client/keystore/src/local.rs | 32 +-- frame/babe/Cargo.toml | 4 +- frame/babe/src/lib.rs | 66 +++--- frame/babe/src/mock.rs | 41 ++-- frame/babe/src/randomness.rs | 8 +- frame/babe/src/tests.rs | 22 +- primitives/consensus/babe/Cargo.toml | 4 - primitives/consensus/babe/src/digests.rs | 28 ++- primitives/consensus/babe/src/lib.rs | 48 ++--- primitives/consensus/vrf/Cargo.toml | 32 --- primitives/consensus/vrf/README.md | 3 - primitives/consensus/vrf/src/lib.rs | 21 -- primitives/consensus/vrf/src/schnorrkel.rs | 188 ----------------- primitives/core/Cargo.toml | 8 +- primitives/core/src/crypto.rs | 26 ++- primitives/core/src/sr25519.rs | 231 ++++++++++++++++++--- primitives/keystore/Cargo.toml | 4 - primitives/keystore/src/lib.rs | 7 +- primitives/keystore/src/testing.rs | 48 +++-- primitives/keystore/src/vrf.rs | 94 --------- 28 files changed, 468 insertions(+), 712 deletions(-) delete mode 100644 primitives/consensus/vrf/Cargo.toml delete mode 100644 primitives/consensus/vrf/README.md delete mode 100644 primitives/consensus/vrf/src/lib.rs delete mode 100644 primitives/consensus/vrf/src/schnorrkel.rs delete mode 100644 primitives/keystore/src/vrf.rs diff --git a/Cargo.lock b/Cargo.lock index c0920e4dc6659..26fb7c4ae1950 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5695,7 +5695,6 @@ dependencies = [ "scale-info", "sp-application-crypto", "sp-consensus-babe", - "sp-consensus-vrf", "sp-core", "sp-io", "sp-runtime", @@ -8594,7 +8593,6 @@ dependencies = [ "fork-tree", "futures", "log", - "merlin", "num-bigint", "num-rational", "num-traits", @@ -8611,7 +8609,6 @@ dependencies = [ "sc-network-test", "sc-telemetry", "scale-info", - "schnorrkel", "sp-api", "sp-application-crypto", "sp-block-builder", @@ -8619,7 +8616,6 @@ dependencies = [ "sp-consensus", "sp-consensus-babe", "sp-consensus-slots", - "sp-consensus-vrf", "sp-core", "sp-inherents", "sp-keyring", @@ -10361,7 +10357,6 @@ name = "sp-consensus-babe" version = "0.10.0-dev" dependencies = [ "async-trait", - "merlin", "parity-scale-codec", "scale-info", "serde", @@ -10369,7 +10364,6 @@ dependencies = [ "sp-application-crypto", "sp-consensus", "sp-consensus-slots", - "sp-consensus-vrf", "sp-core", "sp-inherents", "sp-keystore", @@ -10437,18 +10431,6 @@ dependencies = [ "sp-timestamp", ] -[[package]] -name = "sp-consensus-vrf" -version = "0.10.0-dev" -dependencies = [ - "parity-scale-codec", - "scale-info", - "schnorrkel", - "sp-core", - "sp-runtime", - "sp-std", -] - [[package]] name = "sp-core" version = "7.0.0" @@ -10600,12 +10582,10 @@ name = "sp-keystore" version = "0.13.0" dependencies = [ "futures", - "merlin", "parity-scale-codec", "parking_lot 0.12.1", "rand 0.7.3", "rand_chacha 0.2.2", - "schnorrkel", "serde", "sp-core", "sp-externalities", diff --git a/Cargo.toml b/Cargo.toml index ae89750dd8f26..507d7621000b5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -190,7 +190,6 @@ members = [ "primitives/consensus/grandpa", "primitives/consensus/pow", "primitives/consensus/slots", - "primitives/consensus/vrf", "primitives/core", "primitives/core/hashing", "primitives/core/hashing/proc-macro", diff --git a/client/consensus/babe/Cargo.toml b/client/consensus/babe/Cargo.toml index d10ef21c4dad4..2382d064d0219 100644 --- a/client/consensus/babe/Cargo.toml +++ b/client/consensus/babe/Cargo.toml @@ -19,12 +19,10 @@ scale-info = { version = "2.5.0", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.2.2", features = ["derive"] } futures = "0.3.21" log = "0.4.17" -merlin = "2.0" num-bigint = "0.4.3" num-rational = "0.4.1" num-traits = "0.2.8" parking_lot = "0.12.1" -schnorrkel = { version = "0.9.1", features = ["preaudit_deprecated"] } 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" } @@ -41,7 +39,6 @@ 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 = "7.0.0", path = "../../../primitives/core" } sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } sp-keystore = { version = "0.13.0", path = "../../../primitives/keystore" } diff --git a/client/consensus/babe/src/authorship.rs b/client/consensus/babe/src/authorship.rs index 3ff4c393ffd67..dc7cd10867745 100644 --- a/client/consensus/babe/src/authorship.rs +++ b/client/consensus/babe/src/authorship.rs @@ -18,17 +18,19 @@ //! BABE authority selection and slot claiming. -use super::Epoch; +use super::{Epoch, AUTHORING_SCORE_LENGTH, AUTHORING_SCORE_VRF_CONTEXT}; use codec::Encode; use sc_consensus_epochs::Epoch as EpochT; -use schnorrkel::{keys::PublicKey, vrf::VRFInOut}; use sp_application_crypto::AppCrypto; use sp_consensus_babe::{ digests::{PreDigest, PrimaryPreDigest, SecondaryPlainPreDigest, SecondaryVRFPreDigest}, - make_transcript, make_transcript_data, AuthorityId, BabeAuthorityWeight, Slot, BABE_VRF_PREFIX, + make_transcript, AuthorityId, BabeAuthorityWeight, Randomness, Slot, +}; +use sp_core::{ + blake2_256, + crypto::{ByteArray, Wraps}, + U256, }; -use sp_consensus_vrf::schnorrkel::{VRFOutput, VRFProof}; -use sp_core::{blake2_256, crypto::ByteArray, U256}; use sp_keystore::KeystorePtr; /// Calculates the primary selection threshold for a given authority, taking @@ -95,19 +97,13 @@ pub(super) fn calculate_primary_threshold( ) } -/// Returns true if the given VRF output is lower than the given threshold, -/// false otherwise. -pub(super) fn check_primary_threshold(inout: &VRFInOut, threshold: u128) -> bool { - u128::from_le_bytes(inout.make_bytes::<[u8; 16]>(BABE_VRF_PREFIX)) < threshold -} - /// Get the expected secondary author for the given slot and with given /// authorities. This should always assign the slot to some authority unless the /// authorities list is empty. pub(super) fn secondary_slot_author( slot: Slot, authorities: &[(AuthorityId, BabeAuthorityWeight)], - randomness: [u8; 32], + randomness: Randomness, ) -> Option<&AuthorityId> { if authorities.is_empty() { return None @@ -152,18 +148,14 @@ fn claim_secondary_slot( for (authority_id, authority_index) in keys { if authority_id == expected_author { let pre_digest = if author_secondary_vrf { - let transcript_data = make_transcript_data(randomness, slot, epoch_index); - let result = keystore.sr25519_vrf_sign( - AuthorityId::ID, - authority_id.as_ref(), - transcript_data, - ); - if let Ok(Some(signature)) = result { + let transcript = make_transcript(randomness, slot, epoch_index); + let result = + keystore.sr25519_vrf_sign(AuthorityId::ID, authority_id.as_ref(), &transcript); + if let Ok(Some(vrf_signature)) = result { Some(PreDigest::SecondaryVRF(SecondaryVRFPreDigest { slot, - vrf_output: VRFOutput(signature.output), - vrf_proof: VRFProof(signature.proof), authority_index: *authority_index as u32, + vrf_signature, })) } else { None @@ -247,25 +239,28 @@ fn claim_primary_slot( epoch_index = epoch.clone_for_slot(slot).epoch_index; } - 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); - let result = - keystore.sr25519_vrf_sign(AuthorityId::ID, authority_id.as_ref(), transcript_data); - if let Ok(Some(signature)) = result { - let public = PublicKey::from_bytes(&authority_id.to_raw_vec()).ok()?; - let inout = match signature.output.attach_input_hash(&public, transcript) { - Ok(inout) => inout, - Err(_) => continue, - }; + let transcript = make_transcript(randomness, slot, epoch_index); + for (authority_id, authority_index) in keys { + let result = keystore.sr25519_vrf_sign(AuthorityId::ID, authority_id.as_ref(), &transcript); + if let Ok(Some(vrf_signature)) = result { let threshold = calculate_primary_threshold(c, authorities, *authority_index); - if check_primary_threshold(&inout, threshold) { + + let can_claim = authority_id + .as_inner_ref() + .make_bytes::<[u8; AUTHORING_SCORE_LENGTH]>( + AUTHORING_SCORE_VRF_CONTEXT, + &transcript, + &vrf_signature.output, + ) + .map(|bytes| u128::from_le_bytes(bytes) < threshold) + .unwrap_or_default(); + + if can_claim { let pre_digest = PreDigest::Primary(PrimaryPreDigest { slot, - vrf_output: VRFOutput(signature.output), - vrf_proof: VRFProof(signature.proof), authority_index: *authority_index as u32, + vrf_signature, }); return Some((pre_digest, authority_id.clone())) diff --git a/client/consensus/babe/src/lib.rs b/client/consensus/babe/src/lib.rs index 6327c8c657bb6..219b52294952a 100644 --- a/client/consensus/babe/src/lib.rs +++ b/client/consensus/babe/src/lib.rs @@ -86,7 +86,6 @@ use futures::{ use log::{debug, info, log, trace, warn}; use parking_lot::Mutex; use prometheus_endpoint::Registry; -use schnorrkel::SignatureError; use sc_client_api::{ backend::AuxStore, AuxDataOperations, Backend as BackendT, FinalityNotification, @@ -134,7 +133,7 @@ pub use sp_consensus_babe::{ PrimaryPreDigest, SecondaryPlainPreDigest, }, AuthorityId, AuthorityPair, AuthoritySignature, BabeApi, BabeAuthorityWeight, BabeBlockWeight, - BabeConfiguration, BabeEpochConfiguration, ConsensusLog, BABE_ENGINE_ID, VRF_OUTPUT_LENGTH, + BabeConfiguration, BabeEpochConfiguration, ConsensusLog, Randomness, BABE_ENGINE_ID, }; pub use aux_schema::load_block_weight as block_weight; @@ -149,6 +148,12 @@ mod tests; const LOG_TARGET: &str = "babe"; +/// VRF context used for slots claiming lottery. +const AUTHORING_SCORE_VRF_CONTEXT: &[u8] = b"substrate-babe-vrf"; + +/// VRF output length for slots claiming lottery. +const AUTHORING_SCORE_LENGTH: usize = 16; + /// BABE epoch information #[derive(Decode, Encode, PartialEq, Eq, Clone, Debug, scale_info::TypeInfo)] pub struct Epoch { @@ -161,7 +166,7 @@ pub struct Epoch { /// The authorities and their weights. pub authorities: Vec<(AuthorityId, BabeAuthorityWeight)>, /// Randomness for this epoch. - pub randomness: [u8; VRF_OUTPUT_LENGTH], + pub randomness: Randomness, /// Configuration of the epoch. pub config: BabeEpochConfiguration, } @@ -308,12 +313,12 @@ pub enum Error { /// No secondary author expected. #[error("No secondary author expected.")] NoSecondaryAuthorExpected, - /// VRF verification of block by author failed - #[error("VRF verification of block by author {0:?} failed: threshold {1} exceeded")] - VRFVerificationOfBlockFailed(AuthorityId, u128), /// VRF verification failed - #[error("VRF verification failed: {0:?}")] - VRFVerificationFailed(SignatureError), + #[error("VRF verification failed")] + VrfVerificationFailed, + /// Primary slot threshold too low + #[error("VRF output rejected, threshold {0} exceeded")] + VrfThresholdExceeded(u128), /// Could not fetch parent header #[error("Could not fetch parent header: {0}")] FetchParentHeader(sp_blockchain::Error), diff --git a/client/consensus/babe/src/migration.rs b/client/consensus/babe/src/migration.rs index ec864b8e5510f..2b1396c41c268 100644 --- a/client/consensus/babe/src/migration.rs +++ b/client/consensus/babe/src/migration.rs @@ -18,7 +18,7 @@ use crate::{ AuthorityId, BabeAuthorityWeight, BabeConfiguration, BabeEpochConfiguration, Epoch, - NextEpochDescriptor, VRF_OUTPUT_LENGTH, + NextEpochDescriptor, Randomness, }; use codec::{Decode, Encode}; use sc_consensus_epochs::Epoch as EpochT; @@ -36,7 +36,7 @@ pub struct EpochV0 { /// The authorities and their weights. pub authorities: Vec<(AuthorityId, BabeAuthorityWeight)>, /// Randomness for this epoch. - pub randomness: [u8; VRF_OUTPUT_LENGTH], + pub randomness: Randomness, } impl EpochT for EpochV0 { diff --git a/client/consensus/babe/src/tests.rs b/client/consensus/babe/src/tests.rs index 7f8448d91991c..740ce63676374 100644 --- a/client/consensus/babe/src/tests.rs +++ b/client/consensus/babe/src/tests.rs @@ -20,10 +20,6 @@ use super::*; use authorship::claim_slot; -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}; @@ -33,16 +29,13 @@ use sc_network_test::{Block as TestBlock, *}; use sp_application_crypto::key_types::BABE; use sp_consensus::{DisableProofRecording, NoNetwork as DummyOracle, Proposal}; use sp_consensus_babe::{ - inherents::InherentDataProvider, make_transcript, make_transcript_data, AllowedSlots, - AuthorityId, AuthorityPair, Slot, + inherents::InherentDataProvider, make_transcript, AllowedSlots, AuthorityId, AuthorityPair, + Slot, }; use sp_consensus_slots::SlotDuration; -use sp_consensus_vrf::schnorrkel::VRFOutput; use sp_core::crypto::Pair; use sp_keyring::Sr25519Keyring; -use sp_keystore::{ - testing::MemoryKeystore, vrf::make_transcript as transcript_from_data, Keystore, -}; +use sp_keystore::{testing::MemoryKeystore, Keystore}; use sp_runtime::{ generic::{Digest, DigestItem}, traits::Block as BlockT, @@ -637,24 +630,24 @@ fn claim_vrf_check() { PreDigest::Primary(d) => d, v => panic!("Unexpected pre-digest variant {:?}", v), }; - let transcript = make_transcript_data(&epoch.randomness.clone(), 0.into(), epoch.epoch_index); + let transcript = make_transcript(&epoch.randomness.clone(), 0.into(), epoch.epoch_index); let sign = keystore - .sr25519_vrf_sign(AuthorityId::ID, &public, transcript) + .sr25519_vrf_sign(AuthorityId::ID, &public, &transcript) .unwrap() .unwrap(); - assert_eq!(pre_digest.vrf_output, VRFOutput(sign.output)); + assert_eq!(pre_digest.vrf_signature.output, sign.output); // We expect a SecondaryVRF claim for slot 1 let pre_digest = match claim_slot(1.into(), &epoch, &keystore).unwrap().0 { PreDigest::SecondaryVRF(d) => d, v => panic!("Unexpected pre-digest variant {:?}", v), }; - let transcript = make_transcript_data(&epoch.randomness.clone(), 1.into(), epoch.epoch_index); + let transcript = make_transcript(&epoch.randomness.clone(), 1.into(), epoch.epoch_index); let sign = keystore - .sr25519_vrf_sign(AuthorityId::ID, &public, transcript) + .sr25519_vrf_sign(AuthorityId::ID, &public, &transcript) .unwrap() .unwrap(); - assert_eq!(pre_digest.vrf_output, VRFOutput(sign.output)); + assert_eq!(pre_digest.vrf_signature.output, sign.output); // Check that correct epoch index has been used if epochs are skipped (primary VRF) let slot = Slot::from(103); @@ -663,13 +656,13 @@ fn claim_vrf_check() { v => panic!("Unexpected claim variant {:?}", v), }; let fixed_epoch = epoch.clone_for_slot(slot); - let transcript = make_transcript_data(&epoch.randomness.clone(), slot, fixed_epoch.epoch_index); + let transcript = make_transcript(&epoch.randomness.clone(), slot, fixed_epoch.epoch_index); let sign = keystore - .sr25519_vrf_sign(AuthorityId::ID, &public, transcript) + .sr25519_vrf_sign(AuthorityId::ID, &public, &transcript) .unwrap() .unwrap(); assert_eq!(fixed_epoch.epoch_index, 11); - assert_eq!(claim.vrf_output, VRFOutput(sign.output)); + assert_eq!(claim.vrf_signature.output, sign.output); // Check that correct epoch index has been used if epochs are skipped (secondary VRF) let slot = Slot::from(100); @@ -678,13 +671,13 @@ fn claim_vrf_check() { v => panic!("Unexpected claim variant {:?}", v), }; let fixed_epoch = epoch.clone_for_slot(slot); - let transcript = make_transcript_data(&epoch.randomness.clone(), slot, fixed_epoch.epoch_index); + let transcript = make_transcript(&epoch.randomness.clone(), slot, fixed_epoch.epoch_index); let sign = keystore - .sr25519_vrf_sign(AuthorityId::ID, &public, transcript) + .sr25519_vrf_sign(AuthorityId::ID, &public, &transcript) .unwrap() .unwrap(); assert_eq!(fixed_epoch.epoch_index, 11); - assert_eq!(pre_digest.vrf_output, VRFOutput(sign.output)); + assert_eq!(pre_digest.vrf_signature.output, sign.output); } // Propose and import a new BABE block on top of the given parent. @@ -1084,36 +1077,6 @@ async fn verify_slots_are_strictly_increasing() { propose_and_import_block(&b1, Some(999.into()), &mut proposer_factory, &mut block_import).await; } -#[test] -fn babe_transcript_generation_match() { - sp_tracing::try_init_simple(); - - let authority = Sr25519Keyring::Alice; - let _keystore = create_keystore(authority); - - let epoch = Epoch { - start_slot: 0.into(), - authorities: vec![(authority.public().into(), 1)], - randomness: [0; 32], - epoch_index: 1, - duration: 100, - config: BabeEpochConfiguration { - c: (3, 10), - allowed_slots: AllowedSlots::PrimaryAndSecondaryPlainSlots, - }, - }; - - let orig_transcript = make_transcript(&epoch.randomness.clone(), 1.into(), epoch.epoch_index); - let new_transcript = make_transcript_data(&epoch.randomness, 1.into(), epoch.epoch_index); - - let test = |t: merlin::Transcript| -> [u8; 16] { - let mut b = [0u8; 16]; - t.build_rng().finalize(&mut ChaChaRng::from_seed([0u8; 32])).fill_bytes(&mut b); - b - }; - debug_assert!(test(orig_transcript) == test(transcript_from_data(new_transcript))); -} - #[tokio::test] async fn obsolete_blocks_aux_data_cleanup() { let mut net = BabeTestNet::new(1); diff --git a/client/consensus/babe/src/verification.rs b/client/consensus/babe/src/verification.rs index 96d3961d44571..cadceb6a57510 100644 --- a/client/consensus/babe/src/verification.rs +++ b/client/consensus/babe/src/verification.rs @@ -18,8 +18,9 @@ //! Verification for BABE headers. use crate::{ - authorship::{calculate_primary_threshold, check_primary_threshold, secondary_slot_author}, - babe_err, find_pre_digest, BlockT, Epoch, Error, LOG_TARGET, + authorship::{calculate_primary_threshold, secondary_slot_author}, + babe_err, find_pre_digest, BlockT, Epoch, Error, AUTHORING_SCORE_LENGTH, + AUTHORING_SCORE_VRF_CONTEXT, LOG_TARGET, }; use log::{debug, trace}; use sc_consensus_epochs::Epoch as EpochT; @@ -32,7 +33,10 @@ use sp_consensus_babe::{ make_transcript, AuthorityId, AuthorityPair, AuthoritySignature, }; use sp_consensus_slots::Slot; -use sp_core::{ByteArray, Pair}; +use sp_core::{ + crypto::{VrfVerifier, Wraps}, + Pair, +}; use sp_runtime::{traits::Header, DigestItem}; /// BABE verification parameters @@ -155,7 +159,7 @@ fn check_primary_header( epoch: &Epoch, c: (u64, u64), ) -> Result<(), Error> { - let author = &epoch.authorities[pre_digest.authority_index as usize].0; + let authority_id = &epoch.authorities[pre_digest.authority_index as usize].0; let mut epoch_index = epoch.epoch_index; if epoch.end_slot() <= pre_digest.slot { @@ -163,28 +167,34 @@ fn check_primary_header( epoch_index = epoch.clone_for_slot(pre_digest.slot).epoch_index; } - if AuthorityPair::verify(&signature, pre_hash, author) { - let (inout, _) = { - let transcript = make_transcript(&epoch.randomness, pre_digest.slot, epoch_index); - - schnorrkel::PublicKey::from_bytes(author.as_slice()) - .and_then(|p| { - p.vrf_verify(transcript, &pre_digest.vrf_output, &pre_digest.vrf_proof) - }) - .map_err(|s| babe_err(Error::VRFVerificationFailed(s)))? - }; + if !AuthorityPair::verify(&signature, pre_hash, authority_id) { + return Err(babe_err(Error::BadSignature(pre_hash))) + } - let threshold = - calculate_primary_threshold(c, &epoch.authorities, pre_digest.authority_index as usize); + let transcript = make_transcript(&epoch.randomness, pre_digest.slot, epoch_index); - if !check_primary_threshold(&inout, threshold) { - return Err(babe_err(Error::VRFVerificationOfBlockFailed(author.clone(), threshold))) - } + if !authority_id.as_inner_ref().vrf_verify(&transcript, &pre_digest.vrf_signature) { + return Err(babe_err(Error::VrfVerificationFailed)) + } - Ok(()) - } else { - Err(babe_err(Error::BadSignature(pre_hash))) + let threshold = + calculate_primary_threshold(c, &epoch.authorities, pre_digest.authority_index as usize); + + let score = authority_id + .as_inner_ref() + .make_bytes::<[u8; AUTHORING_SCORE_LENGTH]>( + AUTHORING_SCORE_VRF_CONTEXT, + &transcript, + &pre_digest.vrf_signature.output, + ) + .map(u128::from_le_bytes) + .map_err(|_| babe_err(Error::VrfVerificationFailed))?; + + if score >= threshold { + return Err(babe_err(Error::VrfThresholdExceeded(threshold))) } + + Ok(()) } /// Check a secondary slot proposal header. We validate that the given header is @@ -197,8 +207,7 @@ fn check_secondary_plain_header( signature: AuthoritySignature, epoch: &Epoch, ) -> Result<(), Error> { - // check the signature is valid under the expected authority and - // chain state. + // check the signature is valid under the expected authority and chain state. let expected_author = secondary_slot_author(pre_digest.slot, &epoch.authorities, epoch.randomness) .ok_or(Error::NoSecondaryAuthorExpected)?; @@ -209,11 +218,11 @@ fn check_secondary_plain_header( return Err(Error::InvalidAuthor(expected_author.clone(), author.clone())) } - if AuthorityPair::verify(&signature, pre_hash.as_ref(), author) { - Ok(()) - } else { - Err(Error::BadSignature(pre_hash)) + if !AuthorityPair::verify(&signature, pre_hash.as_ref(), author) { + return Err(Error::BadSignature(pre_hash)) } + + Ok(()) } /// Check a secondary VRF slot proposal header. @@ -223,8 +232,7 @@ fn check_secondary_vrf_header( signature: AuthoritySignature, epoch: &Epoch, ) -> Result<(), Error> { - // check the signature is valid under the expected authority and - // chain state. + // check the signature is valid under the expected authority and chain state. let expected_author = secondary_slot_author(pre_digest.slot, &epoch.authorities, epoch.randomness) .ok_or(Error::NoSecondaryAuthorExpected)?; @@ -241,15 +249,15 @@ fn check_secondary_vrf_header( epoch_index = epoch.clone_for_slot(pre_digest.slot).epoch_index; } - if AuthorityPair::verify(&signature, pre_hash.as_ref(), author) { - let transcript = make_transcript(&epoch.randomness, pre_digest.slot, epoch_index); + if !AuthorityPair::verify(&signature, pre_hash.as_ref(), author) { + return Err(Error::BadSignature(pre_hash)) + } - schnorrkel::PublicKey::from_bytes(author.as_slice()) - .and_then(|p| p.vrf_verify(transcript, &pre_digest.vrf_output, &pre_digest.vrf_proof)) - .map_err(|s| babe_err(Error::VRFVerificationFailed(s)))?; + let transcript = make_transcript(&epoch.randomness, pre_digest.slot, epoch_index); - Ok(()) - } else { - Err(Error::BadSignature(pre_hash)) + if !author.as_inner_ref().vrf_verify(&transcript, &pre_digest.vrf_signature) { + return Err(Error::VrfVerificationFailed) } + + Ok(()) } diff --git a/client/keystore/src/local.rs b/client/keystore/src/local.rs index 2486b2fd045d5..3551623f332a2 100644 --- a/client/keystore/src/local.rs +++ b/client/keystore/src/local.rs @@ -20,13 +20,10 @@ use parking_lot::RwLock; use sp_application_crypto::{AppCrypto, AppPair, IsWrappedBy}; use sp_core::{ - crypto::{ByteArray, ExposeSecret, KeyTypeId, Pair as CorePair, SecretString}, + crypto::{ByteArray, ExposeSecret, KeyTypeId, Pair as CorePair, SecretString, VrfSigner}, ecdsa, ed25519, sr25519, }; -use sp_keystore::{ - vrf::{make_transcript, VRFSignature, VRFTranscriptData}, - Error as TraitError, Keystore, KeystorePtr, -}; +use sp_keystore::{Error as TraitError, Keystore, KeystorePtr}; use std::{ collections::HashMap, fs::{self, File}, @@ -100,6 +97,20 @@ impl LocalKeystore { .map(|pair| pair.sign(msg)); Ok(signature) } + + fn vrf_sign( + &self, + key_type: KeyTypeId, + public: &T::Public, + transcript: &T::VrfInput, + ) -> std::result::Result, TraitError> { + let sig = self + .0 + .read() + .key_pair_by_type::(public, key_type)? + .map(|pair| pair.vrf_sign(transcript)); + Ok(sig) + } } impl Keystore for LocalKeystore { @@ -131,14 +142,9 @@ impl Keystore for LocalKeystore { &self, key_type: KeyTypeId, public: &sr25519::Public, - transcript_data: VRFTranscriptData, - ) -> std::result::Result, TraitError> { - let sig = self.0.read().key_pair_by_type::(public, key_type)?.map(|pair| { - let transcript = make_transcript(transcript_data); - let (inout, proof, _) = pair.as_ref().vrf_sign(transcript); - VRFSignature { output: inout.to_output(), proof } - }); - Ok(sig) + transcript: &sr25519::vrf::VrfTranscript, + ) -> std::result::Result, TraitError> { + self.vrf_sign::(key_type, public, transcript) } fn ed25519_public_keys(&self, key_type: KeyTypeId) -> Vec { diff --git a/frame/babe/Cargo.toml b/frame/babe/Cargo.toml index c4f6592dba9e1..ff9e4b3aeac43 100644 --- a/frame/babe/Cargo.toml +++ b/frame/babe/Cargo.toml @@ -24,7 +24,7 @@ pallet-session = { version = "4.0.0-dev", default-features = false, path = "../s pallet-timestamp = { version = "4.0.0-dev", default-features = false, path = "../timestamp" } 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-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" } @@ -53,7 +53,7 @@ std = [ "scale-info/std", "sp-application-crypto/std", "sp-consensus-babe/std", - "sp-consensus-vrf/std", + "sp-core/std", "sp-io/std", "sp-runtime/std", "sp-session/std", diff --git a/frame/babe/src/lib.rs b/frame/babe/src/lib.rs index 61284267b07e7..e3ead424e7f6b 100644 --- a/frame/babe/src/lib.rs +++ b/frame/babe/src/lib.rs @@ -29,13 +29,13 @@ use frame_support::{ weights::Weight, BoundedVec, WeakBoundedVec, }; -use sp_application_crypto::ByteArray; use sp_consensus_babe::{ digests::{NextConfigDescriptor, NextEpochDescriptor, PreDigest}, AllowedSlots, BabeAuthorityWeight, BabeEpochConfiguration, ConsensusLog, Epoch, - EquivocationProof, Slot, BABE_ENGINE_ID, + EquivocationProof, Randomness as BabeRandomness, Slot, BABE_ENGINE_ID, RANDOMNESS_LENGTH, + RANDOMNESS_VRF_CONTEXT, }; -use sp_consensus_vrf::schnorrkel; +use sp_core::crypto::Wraps; use sp_runtime::{ generic::DigestItem, traits::{IsMember, One, SaturatedConversion, Saturating, Zero}, @@ -45,7 +45,7 @@ use sp_session::{GetSessionNumber, GetValidatorCount}; use sp_staking::{offence::OffenceReportSystem, SessionIndex}; use sp_std::prelude::*; -pub use sp_consensus_babe::{AuthorityId, PUBLIC_KEY_LENGTH, RANDOMNESS_LENGTH, VRF_OUTPUT_LENGTH}; +pub use sp_consensus_babe::AuthorityId; const LOG_TARGET: &str = "runtime::babe"; @@ -218,7 +218,7 @@ pub mod pallet { // variable to its underlying value. #[pallet::storage] #[pallet::getter(fn randomness)] - pub type Randomness = StorageValue<_, schnorrkel::Randomness, ValueQuery>; + pub type Randomness = StorageValue<_, BabeRandomness, ValueQuery>; /// Pending epoch configuration change that will be applied when the next epoch is enacted. #[pallet::storage] @@ -226,7 +226,7 @@ pub mod pallet { /// Next epoch randomness. #[pallet::storage] - pub(super) type NextRandomness = StorageValue<_, schnorrkel::Randomness, ValueQuery>; + pub(super) type NextRandomness = StorageValue<_, BabeRandomness, ValueQuery>; /// Next epoch authorities. #[pallet::storage] @@ -254,7 +254,7 @@ pub mod pallet { _, Twox64Concat, u32, - BoundedVec>, + BoundedVec>, ValueQuery, >; @@ -270,8 +270,7 @@ pub mod pallet { /// 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<_, Option, ValueQuery>; + pub(super) type AuthorVrfRandomness = StorageValue<_, Option, ValueQuery>; /// The block numbers when the last and current epoch have started, respectively `N-1` and /// `N`. @@ -358,31 +357,33 @@ pub mod pallet { ); } - if let Some((vrf_output, vrf_proof)) = pre_digest.vrf() { - let randomness: Option = Authorities::::get() + if let Some(vrf_signature) = pre_digest.vrf_signature() { + 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 public = authority.as_inner_ref(); let transcript = sp_consensus_babe::make_transcript( &Self::randomness(), - current_slot, + CurrentSlot::::get(), 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 + // 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)); + debug_assert!({ + use sp_core::crypto::VrfVerifier; + public.vrf_verify(&transcript, &vrf_signature) + }); + + public + .make_bytes( + RANDOMNESS_VRF_CONTEXT, + &transcript, + &vrf_signature.output, + ) + .ok() + }); if let Some(randomness) = pre_digest.is_primary().then(|| randomness).flatten() { @@ -484,9 +485,6 @@ pub mod pallet { } } -/// A BABE public key -pub type BabeKey = [u8; PUBLIC_KEY_LENGTH]; - impl FindAuthor for Pallet { fn find_author<'a, I>(digests: I) -> Option where @@ -737,7 +735,7 @@ impl Pallet { >::deposit_log(log) } - fn deposit_randomness(randomness: &schnorrkel::Randomness) { + fn deposit_randomness(randomness: &BabeRandomness) { let segment_idx = SegmentIndex::::get(); let mut segment = UnderConstruction::::get(&segment_idx); if segment.try_push(*randomness).is_ok() { @@ -831,7 +829,7 @@ impl Pallet { /// Call this function exactly once when an epoch changes, to update the /// randomness. Returns the new randomness. - fn randomness_change_epoch(next_epoch_index: u64) -> schnorrkel::Randomness { + fn randomness_change_epoch(next_epoch_index: u64) -> BabeRandomness { let this_randomness = NextRandomness::::get(); let segment_idx: u32 = SegmentIndex::::mutate(|s| sp_std::mem::replace(s, 0)); @@ -990,12 +988,12 @@ where // // an optional size hint as to how many VRF outputs there were may be provided. fn compute_randomness( - last_epoch_randomness: schnorrkel::Randomness, + last_epoch_randomness: BabeRandomness, epoch_index: u64, - rho: impl Iterator, + rho: impl Iterator, rho_size_hint: Option, -) -> schnorrkel::Randomness { - let mut s = Vec::with_capacity(40 + rho_size_hint.unwrap_or(0) * VRF_OUTPUT_LENGTH); +) -> BabeRandomness { + let mut s = Vec::with_capacity(40 + rho_size_hint.unwrap_or(0) * RANDOMNESS_LENGTH); s.extend_from_slice(&last_epoch_randomness); s.extend_from_slice(&epoch_index.to_le_bytes()); diff --git a/frame/babe/src/mock.rs b/frame/babe/src/mock.rs index 94e748d0bca52..bccdb42c71ac3 100644 --- a/frame/babe/src/mock.rs +++ b/frame/babe/src/mock.rs @@ -25,10 +25,9 @@ use frame_support::{ traits::{ConstU128, ConstU32, ConstU64, GenesisBuild, KeyOwnerProofSystem, OnInitialize}, }; use pallet_session::historical as pallet_session_historical; -use sp_consensus_babe::{AuthorityId, AuthorityPair, Slot}; -use sp_consensus_vrf::schnorrkel::{VRFOutput, VRFProof}; +use sp_consensus_babe::{AuthorityId, AuthorityPair, Randomness, Slot, VrfSignature}; use sp_core::{ - crypto::{IsWrappedBy, KeyTypeId, Pair}, + crypto::{KeyTypeId, Pair, VrfSigner}, H256, U256, }; use sp_io; @@ -283,16 +282,10 @@ pub fn start_era(era_index: EraIndex) { pub fn make_primary_pre_digest( authority_index: sp_consensus_babe::AuthorityIndex, slot: sp_consensus_babe::Slot, - vrf_output: VRFOutput, - vrf_proof: VRFProof, + vrf_signature: VrfSignature, ) -> Digest { let digest_data = sp_consensus_babe::digests::PreDigest::Primary( - sp_consensus_babe::digests::PrimaryPreDigest { - authority_index, - slot, - vrf_output, - vrf_proof, - }, + sp_consensus_babe::digests::PrimaryPreDigest { authority_index, slot, vrf_signature }, ); let log = DigestItem::PreRuntime(sp_consensus_babe::BABE_ENGINE_ID, digest_data.encode()); Digest { logs: vec![log] } @@ -312,16 +305,10 @@ pub fn make_secondary_plain_pre_digest( pub fn make_secondary_vrf_pre_digest( authority_index: sp_consensus_babe::AuthorityIndex, slot: sp_consensus_babe::Slot, - vrf_output: VRFOutput, - vrf_proof: VRFProof, + vrf_signature: VrfSignature, ) -> Digest { let digest_data = sp_consensus_babe::digests::PreDigest::SecondaryVRF( - sp_consensus_babe::digests::SecondaryVRFPreDigest { - authority_index, - slot, - vrf_output, - vrf_proof, - }, + sp_consensus_babe::digests::SecondaryVRFPreDigest { authority_index, slot, vrf_signature }, ); let log = DigestItem::PreRuntime(sp_consensus_babe::BABE_ENGINE_ID, digest_data.encode()); Digest { logs: vec![log] } @@ -330,16 +317,16 @@ pub fn make_secondary_vrf_pre_digest( pub fn make_vrf_output( slot: Slot, pair: &sp_consensus_babe::AuthorityPair, -) -> (VRFOutput, VRFProof, [u8; 32]) { - let pair = sp_core::sr25519::Pair::from_ref(pair).as_ref(); +) -> (VrfSignature, Randomness) { let transcript = sp_consensus_babe::make_transcript(&Babe::randomness(), slot, 0); - let vrf_inout = pair.vrf_sign(transcript); - let vrf_randomness: sp_consensus_vrf::schnorrkel::Randomness = - vrf_inout.0.make_bytes::<[u8; 32]>(&sp_consensus_babe::BABE_VRF_INOUT_CONTEXT); - let vrf_output = VRFOutput(vrf_inout.0.to_output()); - let vrf_proof = VRFProof(vrf_inout.1); - (vrf_output, vrf_proof, vrf_randomness) + let signature = pair.as_ref().vrf_sign(&transcript); + + let randomness = pair + .as_ref() + .make_bytes::(sp_consensus_babe::RANDOMNESS_VRF_CONTEXT, &transcript); + + (signature, randomness) } pub fn new_test_ext(authorities_len: usize) -> sp_io::TestExternalities { diff --git a/frame/babe/src/randomness.rs b/frame/babe/src/randomness.rs index b223df6804c0b..b9b24786b7a74 100644 --- a/frame/babe/src/randomness.rs +++ b/frame/babe/src/randomness.rs @@ -19,7 +19,7 @@ //! randomness collected from VRF outputs. use super::{ - AuthorVrfRandomness, Config, EpochStart, NextRandomness, Randomness, VRF_OUTPUT_LENGTH, + AuthorVrfRandomness, Config, EpochStart, NextRandomness, Randomness, RANDOMNESS_LENGTH, }; use frame_support::traits::Randomness as RandomnessT; use sp_runtime::traits::{Hash, One, Saturating}; @@ -132,7 +132,7 @@ pub struct CurrentBlockRandomness(sp_std::marker::PhantomData); impl RandomnessT for RandomnessFromTwoEpochsAgo { fn random(subject: &[u8]) -> (T::Hash, T::BlockNumber) { let mut subject = subject.to_vec(); - subject.reserve(VRF_OUTPUT_LENGTH); + subject.reserve(RANDOMNESS_LENGTH); subject.extend_from_slice(&Randomness::::get()[..]); (T::Hashing::hash(&subject[..]), EpochStart::::get().0) @@ -142,7 +142,7 @@ impl RandomnessT for RandomnessFromTwoEpochs impl RandomnessT for RandomnessFromOneEpochAgo { fn random(subject: &[u8]) -> (T::Hash, T::BlockNumber) { let mut subject = subject.to_vec(); - subject.reserve(VRF_OUTPUT_LENGTH); + subject.reserve(RANDOMNESS_LENGTH); subject.extend_from_slice(&NextRandomness::::get()[..]); (T::Hashing::hash(&subject[..]), EpochStart::::get().1) @@ -153,7 +153,7 @@ impl RandomnessT, T::BlockNumber> for ParentBlockRand fn random(subject: &[u8]) -> (Option, T::BlockNumber) { let random = AuthorVrfRandomness::::get().map(|random| { let mut subject = subject.to_vec(); - subject.reserve(VRF_OUTPUT_LENGTH); + subject.reserve(RANDOMNESS_LENGTH); subject.extend_from_slice(&random); T::Hashing::hash(&subject[..]) diff --git a/frame/babe/src/tests.rs b/frame/babe/src/tests.rs index 8b63f41b37b74..8a9aa6fcc03d2 100644 --- a/frame/babe/src/tests.rs +++ b/frame/babe/src/tests.rs @@ -25,11 +25,12 @@ 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_consensus_babe::{ + AllowedSlots, BabeEpochConfiguration, Slot, VrfSignature, RANDOMNESS_LENGTH, +}; use sp_core::crypto::Pair; -const EMPTY_RANDOMNESS: [u8; 32] = [ +const EMPTY_RANDOMNESS: [u8; RANDOMNESS_LENGTH] = [ 74, 25, 49, 128, 53, 97, 244, 49, 222, 202, 176, 2, 231, 66, 95, 10, 133, 49, 213, 228, 86, 161, 164, 127, 217, 153, 138, 37, 48, 192, 248, 0, ]; @@ -62,10 +63,9 @@ fn first_block_epoch_zero_start() { ext.execute_with(|| { let genesis_slot = Slot::from(100); - let (vrf_output, vrf_proof, vrf_randomness) = make_vrf_output(genesis_slot, &pairs[0]); + let (vrf_signature, vrf_randomness) = make_vrf_output(genesis_slot, &pairs[0]); - let first_vrf = vrf_output; - let pre_digest = make_primary_pre_digest(0, genesis_slot, first_vrf.clone(), vrf_proof); + let pre_digest = make_primary_pre_digest(0, genesis_slot, vrf_signature); assert_eq!(Babe::genesis_slot(), Slot::from(0)); System::reset_events(); @@ -111,8 +111,8 @@ fn current_slot_is_processed_on_initialization() { ext.execute_with(|| { let genesis_slot = Slot::from(10); - let (vrf_output, vrf_proof, vrf_randomness) = make_vrf_output(genesis_slot, &pairs[0]); - let pre_digest = make_primary_pre_digest(0, genesis_slot, vrf_output, vrf_proof); + let (vrf_signature, vrf_randomness) = make_vrf_output(genesis_slot, &pairs[0]); + let pre_digest = make_primary_pre_digest(0, genesis_slot, vrf_signature); System::reset_events(); System::initialize(&1, &Default::default(), &pre_digest); @@ -134,14 +134,14 @@ fn current_slot_is_processed_on_initialization() { fn test_author_vrf_output(make_pre_digest: F) where - F: Fn(sp_consensus_babe::AuthorityIndex, Slot, VRFOutput, VRFProof) -> sp_runtime::Digest, + F: Fn(sp_consensus_babe::AuthorityIndex, Slot, VrfSignature) -> 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 pre_digest = make_pre_digest(0, genesis_slot, vrf_output, vrf_proof); + let (vrf_signature, vrf_randomness) = make_vrf_output(genesis_slot, &pairs[0]); + let pre_digest = make_pre_digest(0, genesis_slot, vrf_signature); System::reset_events(); System::initialize(&1, &Default::default(), &pre_digest); diff --git a/primitives/consensus/babe/Cargo.toml b/primitives/consensus/babe/Cargo.toml index d106cd0d0c875..7e171811a7fe2 100644 --- a/primitives/consensus/babe/Cargo.toml +++ b/primitives/consensus/babe/Cargo.toml @@ -15,14 +15,12 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-trait = { version = "0.1.57", optional = true } codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false } -merlin = { version = "2.0", default-features = false } scale-info = { version = "2.5.0", 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 = "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 = "7.0.0", default-features = false, path = "../../core" } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../inherents" } sp-keystore = { version = "0.13.0", default-features = false, optional = true, path = "../../keystore" } @@ -35,14 +33,12 @@ default = ["std"] std = [ "async-trait", "codec/std", - "merlin/std", "scale-info/std", "serde", "sp-api/std", "sp-application-crypto/std", "sp-consensus", "sp-consensus-slots/std", - "sp-consensus-vrf/std", "sp-core/std", "sp-inherents/std", "sp-keystore", diff --git a/primitives/consensus/babe/src/digests.rs b/primitives/consensus/babe/src/digests.rs index 4364057a4b478..afc967e3af391 100644 --- a/primitives/consensus/babe/src/digests.rs +++ b/primitives/consensus/babe/src/digests.rs @@ -19,14 +19,15 @@ use super::{ AllowedSlots, AuthorityId, AuthorityIndex, AuthoritySignature, BabeAuthorityWeight, - BabeEpochConfiguration, Slot, BABE_ENGINE_ID, + BabeEpochConfiguration, Randomness, Slot, BABE_ENGINE_ID, }; -use codec::{Decode, Encode, MaxEncodedLen}; -use scale_info::TypeInfo; + +use sp_core::sr25519::vrf::VrfSignature; use sp_runtime::{DigestItem, RuntimeDebug}; use sp_std::vec::Vec; -use sp_consensus_vrf::schnorrkel::{Randomness, VRFOutput, VRFProof}; +use codec::{Decode, Encode, MaxEncodedLen}; +use scale_info::TypeInfo; /// Raw BABE primary slot assignment pre-digest. #[derive(Clone, RuntimeDebug, Encode, Decode, MaxEncodedLen, TypeInfo)] @@ -35,10 +36,8 @@ pub struct PrimaryPreDigest { pub authority_index: super::AuthorityIndex, /// Slot pub slot: Slot, - /// VRF output - pub vrf_output: VRFOutput, - /// VRF proof - pub vrf_proof: VRFProof, + /// VRF signature + pub vrf_signature: VrfSignature, } /// BABE secondary slot assignment pre-digest. @@ -62,10 +61,8 @@ pub struct SecondaryVRFPreDigest { pub authority_index: super::AuthorityIndex, /// Slot pub slot: Slot, - /// VRF output - pub vrf_output: VRFOutput, - /// VRF proof - pub vrf_proof: VRFProof, + /// VRF signature + pub vrf_signature: VrfSignature, } /// A BABE pre-runtime digest. This contains all data required to validate a @@ -118,11 +115,10 @@ impl PreDigest { } /// Returns the VRF output and proof, if they exist. - pub fn vrf(&self) -> Option<(&VRFOutput, &VRFProof)> { + pub fn vrf_signature(&self) -> Option<&VrfSignature> { match self { - PreDigest::Primary(primary) => Some((&primary.vrf_output, &primary.vrf_proof)), - PreDigest::SecondaryVRF(secondary) => - Some((&secondary.vrf_output, &secondary.vrf_proof)), + PreDigest::Primary(primary) => Some(&primary.vrf_signature), + PreDigest::SecondaryVRF(secondary) => Some(&secondary.vrf_signature), PreDigest::SecondaryPlain(_) => None, } } diff --git a/primitives/consensus/babe/src/lib.rs b/primitives/consensus/babe/src/lib.rs index e7747ac4c204a..37cf0c3f0b677 100644 --- a/primitives/consensus/babe/src/lib.rs +++ b/primitives/consensus/babe/src/lib.rs @@ -23,22 +23,17 @@ pub mod digests; pub mod inherents; -pub use merlin::Transcript; -pub use sp_consensus_vrf::schnorrkel::{ - Randomness, RANDOMNESS_LENGTH, VRF_OUTPUT_LENGTH, VRF_PROOF_LENGTH, -}; - use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; -#[cfg(feature = "std")] -use sp_keystore::vrf::{VRFTranscriptData, VRFTranscriptValue}; use sp_runtime::{traits::Header, ConsensusEngineId, RuntimeDebug}; use sp_std::vec::Vec; use crate::digests::{NextConfigDescriptor, NextEpochDescriptor}; +pub use sp_core::sr25519::vrf::{VrfOutput, VrfProof, VrfSignature, VrfTranscript}; + /// Key type for BABE module. pub const KEY_TYPE: sp_core::crypto::KeyTypeId = sp_application_crypto::key_types::BABE; @@ -47,11 +42,14 @@ mod app { app_crypto!(sr25519, BABE); } -/// The prefix used by BABE for its VRF keys. -pub const BABE_VRF_PREFIX: &[u8] = b"substrate-babe-vrf"; +/// VRF context used for per-slot randomness generation. +pub const RANDOMNESS_VRF_CONTEXT: &[u8] = b"BabeVRFInOutContext"; -/// BABE VRFInOut context. -pub static BABE_VRF_INOUT_CONTEXT: &[u8] = b"BabeVRFInOutContext"; +/// VRF output length for per-slot randomness. +pub const RANDOMNESS_LENGTH: usize = 32; + +/// Randomness type required by BABE operations. +pub type Randomness = [u8; RANDOMNESS_LENGTH]; /// A Babe authority keypair. Necessarily equivalent to the schnorrkel public key used in /// the main Babe module. If that ever changes, then this must, too. @@ -96,26 +94,16 @@ pub type BabeAuthorityWeight = u64; /// of 0 (regardless of whether they are plain or vrf secondary blocks). pub type BabeBlockWeight = u32; -/// Make a VRF transcript from given randomness, slot number and epoch. -pub fn make_transcript(randomness: &Randomness, slot: Slot, epoch: u64) -> Transcript { - let mut transcript = Transcript::new(&BABE_ENGINE_ID); - transcript.append_u64(b"slot number", *slot); - transcript.append_u64(b"current epoch", epoch); - transcript.append_message(b"chain randomness", &randomness[..]); - transcript -} - /// Make a VRF transcript data container -#[cfg(feature = "std")] -pub fn make_transcript_data(randomness: &Randomness, slot: Slot, epoch: u64) -> VRFTranscriptData { - VRFTranscriptData { - label: &BABE_ENGINE_ID, - items: vec![ - ("slot number", VRFTranscriptValue::U64(*slot)), - ("current epoch", VRFTranscriptValue::U64(epoch)), - ("chain randomness", VRFTranscriptValue::Bytes(randomness.to_vec())), +pub fn make_transcript(randomness: &Randomness, slot: Slot, epoch: u64) -> VrfTranscript { + VrfTranscript::new( + &BABE_ENGINE_ID, + &[ + (b"slot number", &slot.to_le_bytes()), + (b"current epoch", &epoch.to_le_bytes()), + (b"chain randomness", randomness), ], - } + ) } /// An consensus log item for BABE. @@ -355,7 +343,7 @@ pub struct Epoch { /// The authorities and their weights. pub authorities: Vec<(AuthorityId, BabeAuthorityWeight)>, /// Randomness for this epoch. - pub randomness: [u8; VRF_OUTPUT_LENGTH], + pub randomness: Randomness, /// Configuration of the epoch. pub config: BabeEpochConfiguration, } diff --git a/primitives/consensus/vrf/Cargo.toml b/primitives/consensus/vrf/Cargo.toml deleted file mode 100644 index e7b4f0f0dec0e..0000000000000 --- a/primitives/consensus/vrf/Cargo.toml +++ /dev/null @@ -1,32 +0,0 @@ -[package] -name = "sp-consensus-vrf" -version = "0.10.0-dev" -authors = ["Parity Technologies "] -description = "Primitives for VRF based consensus" -edition = "2021" -license = "Apache-2.0" -repository = "https://github.com/paritytech/substrate/" -homepage = "https://substrate.io" -readme = "README.md" - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] - -[dependencies] -codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false } -scale-info = { version = "2.5.0", default-features = false } -schnorrkel = { version = "0.9.1", default-features = false, features = ["preaudit_deprecated", "u64_backend"] } -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"] -std = [ - "codec/std", - "scale-info/std", - "schnorrkel/std", - "sp-core/std", - "sp-runtime/std", - "sp-std/std", -] diff --git a/primitives/consensus/vrf/README.md b/primitives/consensus/vrf/README.md deleted file mode 100644 index d66490e023b38..0000000000000 --- a/primitives/consensus/vrf/README.md +++ /dev/null @@ -1,3 +0,0 @@ -Primitives for VRF-based consensus engines. - -License: Apache-2.0 \ No newline at end of file diff --git a/primitives/consensus/vrf/src/lib.rs b/primitives/consensus/vrf/src/lib.rs deleted file mode 100644 index 84040c18590e0..0000000000000 --- a/primitives/consensus/vrf/src/lib.rs +++ /dev/null @@ -1,21 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Primitives for VRF-based consensus engines. -#![cfg_attr(not(feature = "std"), no_std)] - -pub mod schnorrkel; diff --git a/primitives/consensus/vrf/src/schnorrkel.rs b/primitives/consensus/vrf/src/schnorrkel.rs deleted file mode 100644 index be145c5b12096..0000000000000 --- a/primitives/consensus/vrf/src/schnorrkel.rs +++ /dev/null @@ -1,188 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Schnorrkel-based VRF. - -use codec::{Decode, Encode, EncodeLike, MaxEncodedLen}; -use scale_info::TypeInfo; -use schnorrkel::errors::MultiSignatureStage; -use sp_core::U512; -use sp_std::{ - ops::{Deref, DerefMut}, - prelude::*, -}; - -pub use schnorrkel::{ - vrf::{VRF_OUTPUT_LENGTH, VRF_PROOF_LENGTH}, - PublicKey, SignatureError, -}; - -/// The length of the Randomness. -pub const RANDOMNESS_LENGTH: usize = VRF_OUTPUT_LENGTH; - -/// VRF output type available for `std` environment, suitable for schnorrkel operations. -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct VRFOutput(pub schnorrkel::vrf::VRFOutput); - -impl Deref for VRFOutput { - type Target = schnorrkel::vrf::VRFOutput; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl DerefMut for VRFOutput { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} - -impl Encode for VRFOutput { - fn encode(&self) -> Vec { - self.0.as_bytes().encode() - } -} - -impl EncodeLike for VRFOutput {} - -impl Decode for VRFOutput { - fn decode(i: &mut R) -> Result { - let decoded = <[u8; VRF_OUTPUT_LENGTH]>::decode(i)?; - Ok(Self(schnorrkel::vrf::VRFOutput::from_bytes(&decoded).map_err(convert_error)?)) - } -} - -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; - - fn try_from(raw: [u8; VRF_OUTPUT_LENGTH]) -> Result { - schnorrkel::vrf::VRFOutput::from_bytes(&raw).map(VRFOutput) - } -} - -/// VRF proof type available for `std` environment, suitable for schnorrkel operations. -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct VRFProof(pub schnorrkel::vrf::VRFProof); - -impl PartialOrd for VRFProof { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for VRFProof { - fn cmp(&self, other: &Self) -> core::cmp::Ordering { - U512::from(self.0.to_bytes()).cmp(&U512::from(other.0.to_bytes())) - } -} - -impl Deref for VRFProof { - type Target = schnorrkel::vrf::VRFProof; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl DerefMut for VRFProof { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} - -impl Encode for VRFProof { - fn encode(&self) -> Vec { - self.0.to_bytes().encode() - } -} - -impl EncodeLike for VRFProof {} - -impl Decode for VRFProof { - fn decode(i: &mut R) -> Result { - let decoded = <[u8; VRF_PROOF_LENGTH]>::decode(i)?; - Ok(Self(schnorrkel::vrf::VRFProof::from_bytes(&decoded).map_err(convert_error)?)) - } -} - -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; - - fn try_from(raw: [u8; VRF_PROOF_LENGTH]) -> Result { - schnorrkel::vrf::VRFProof::from_bytes(&raw).map(VRFProof) - } -} - -fn convert_error(e: SignatureError) -> codec::Error { - use MultiSignatureStage::*; - use SignatureError::*; - match e { - EquationFalse => "Signature error: `EquationFalse`".into(), - PointDecompressionError => "Signature error: `PointDecompressionError`".into(), - ScalarFormatError => "Signature error: `ScalarFormatError`".into(), - NotMarkedSchnorrkel => "Signature error: `NotMarkedSchnorrkel`".into(), - BytesLengthError { .. } => "Signature error: `BytesLengthError`".into(), - MuSigAbsent { musig_stage: Commitment } => - "Signature error: `MuSigAbsent` at stage `Commitment`".into(), - MuSigAbsent { musig_stage: Reveal } => - "Signature error: `MuSigAbsent` at stage `Reveal`".into(), - MuSigAbsent { musig_stage: Cosignature } => - "Signature error: `MuSigAbsent` at stage `Commitment`".into(), - MuSigInconsistent { musig_stage: Commitment, duplicate: true } => - "Signature error: `MuSigInconsistent` at stage `Commitment` on duplicate".into(), - MuSigInconsistent { musig_stage: Commitment, duplicate: false } => - "Signature error: `MuSigInconsistent` at stage `Commitment` on not duplicate".into(), - MuSigInconsistent { musig_stage: Reveal, duplicate: true } => - "Signature error: `MuSigInconsistent` at stage `Reveal` on duplicate".into(), - MuSigInconsistent { musig_stage: Reveal, duplicate: false } => - "Signature error: `MuSigInconsistent` at stage `Reveal` on not duplicate".into(), - MuSigInconsistent { musig_stage: Cosignature, duplicate: true } => - "Signature error: `MuSigInconsistent` at stage `Cosignature` on duplicate".into(), - MuSigInconsistent { musig_stage: Cosignature, duplicate: false } => - "Signature error: `MuSigInconsistent` at stage `Cosignature` on not duplicate".into(), - } -} - -/// Schnorrkel randomness value. Same size as `VRFOutput`. -pub type Randomness = [u8; RANDOMNESS_LENGTH]; diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index 1edd28b3fca7e..302d52f2f862b 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -44,9 +44,9 @@ bitflags = "1.3" array-bytes = { version = "4.1", 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", "u64_backend"], 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 } +schnorrkel = { version = "0.9.1", features = ["preaudit_deprecated", "u64_backend"], default-features = false } +merlin = { version = "2.0", default-features = false } secp256k1 = { version = "0.24.0", default-features = false, features = ["recovery", "alloc"], optional = true } ss58-registry = { version = "1.34.0", default-features = false } sp-core-hashing = { version = "5.0.0", path = "./hashing", default-features = false, optional = true } @@ -69,7 +69,7 @@ bench = false [features] default = ["std"] std = [ - "merlin?/std", + "merlin/std", "full_crypto", "log/std", "thiserror", @@ -119,10 +119,8 @@ full_crypto = [ "array-bytes", "ed25519-zebra", "blake2", - "schnorrkel", "libsecp256k1", "secp256k1", "sp-core-hashing", "sp-runtime-interface/disable_target_static_assertions", - "merlin", ] diff --git a/primitives/core/src/crypto.rs b/primitives/core/src/crypto.rs index f77e952d84546..4fec79fc6ea18 100644 --- a/primitives/core/src/crypto.rs +++ b/primitives/core/src/crypto.rs @@ -28,11 +28,8 @@ use rand::{rngs::OsRng, RngCore}; #[cfg(feature = "std")] use regex::Regex; use scale_info::TypeInfo; -/// Trait for accessing reference to `SecretString`. -pub use secrecy::ExposeSecret; -/// A store for sensitive data. #[cfg(feature = "std")] -pub use secrecy::SecretString; +pub use secrecy::{ExposeSecret, SecretString}; use sp_runtime_interface::pass_by::PassByInner; #[doc(hidden)] pub use sp_std::ops::Deref; @@ -1102,6 +1099,27 @@ impl<'a> TryFrom<&'a str> for KeyTypeId { } } +/// Trait grouping types shared by a VRF signer and verifiers. +pub trait VrfCrypto { + /// Associated signature type. + type VrfSignature; + + /// Vrf input data. Generally some form of transcript. + type VrfInput; +} + +/// VRF Signer. +pub trait VrfSigner: VrfCrypto { + /// Sign input data. + fn vrf_sign(&self, data: &Self::VrfInput) -> Self::VrfSignature; +} + +/// VRF Verifier. +pub trait VrfVerifier: VrfCrypto { + /// Verify input data signature. + fn vrf_verify(&self, data: &Self::VrfInput, signature: &Self::VrfSignature) -> bool; +} + /// An identifier for a specific cryptographic algorithm used by a key pair #[derive(Debug, Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Encode, Decode)] #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] diff --git a/primitives/core/src/sr25519.rs b/primitives/core/src/sr25519.rs index d7c1c79c3f42b..fcd7f38a74f1f 100644 --- a/primitives/core/src/sr25519.rs +++ b/primitives/core/src/sr25519.rs @@ -15,12 +15,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -// tag::description[] //! Simple sr25519 (Schnorr-Ristretto) API. //! //! Note: `CHAIN_CODE_LENGTH` must be equal to `crate::crypto::JUNCTION_ID_LEN` //! for this to work. -// end::description[] + #[cfg(feature = "std")] use crate::crypto::Ss58Codec; #[cfg(feature = "full_crypto")] @@ -30,7 +29,6 @@ use schnorrkel::{ derive::{ChainCode, Derivation, CHAIN_CODE_LENGTH}, signing_context, ExpansionMode, Keypair, MiniSecretKey, PublicKey, SecretKey, }; -#[cfg(feature = "full_crypto")] use sp_std::vec::Vec; use crate::{ @@ -200,8 +198,6 @@ 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 #[cfg_attr(feature = "full_crypto", derive(Hash))] #[derive(Encode, Decode, MaxEncodedLen, PassByInner, TypeInfo, PartialEq, Eq)] pub struct Signature(pub [u8; 64]); @@ -545,43 +541,194 @@ impl CryptoType for Pair { type Pair = Pair; } -/// Batch verification. -/// -/// `messages`, `signatures` and `pub_keys` should all have equal length. -/// -/// Returns `true` if all signatures are correct, `false` otherwise. -#[cfg(feature = "std")] -pub fn verify_batch( - messages: Vec<&[u8]>, - signatures: Vec<&Signature>, - pub_keys: Vec<&Public>, -) -> bool { - let mut sr_pub_keys = Vec::with_capacity(pub_keys.len()); - for pub_key in pub_keys { - match schnorrkel::PublicKey::from_bytes(pub_key.as_ref()) { - Ok(pk) => sr_pub_keys.push(pk), - Err(_) => return false, - }; +/// Schnorrkel VRF related types and operations. +pub mod vrf { + use super::*; + #[cfg(feature = "full_crypto")] + use crate::crypto::VrfSigner; + use crate::crypto::{VrfCrypto, VrfVerifier}; + use schnorrkel::{ + errors::MultiSignatureStage, + vrf::{VRF_OUTPUT_LENGTH, VRF_PROOF_LENGTH}, + SignatureError, + }; + + /// VRF transcript ready to be used for VRF sign/verify operations. + pub struct VrfTranscript(pub merlin::Transcript); + + impl VrfTranscript { + /// Build a new transcript ready to be used by a VRF signer/verifier. + pub fn new(label: &'static [u8], data: &[(&'static [u8], &[u8])]) -> Self { + let mut transcript = merlin::Transcript::new(label); + data.iter().for_each(|(l, b)| transcript.append_message(l, b)); + VrfTranscript(transcript) + } } - let mut sr_signatures = Vec::with_capacity(signatures.len()); - for signature in signatures { - match schnorrkel::Signature::from_bytes(signature.as_ref()) { - Ok(s) => sr_signatures.push(s), - Err(_) => return false, - }; + /// VRF signature data + #[derive(Clone, Debug, PartialEq, Eq, Encode, Decode, MaxEncodedLen, TypeInfo)] + pub struct VrfSignature { + /// The initial VRF configuration + pub output: VrfOutput, + /// The calculated VRF proof + pub proof: VrfProof, + } + + /// VRF output type suitable for schnorrkel operations. + #[derive(Clone, Debug, PartialEq, Eq)] + pub struct VrfOutput(pub schnorrkel::vrf::VRFOutput); + + impl Encode for VrfOutput { + fn encode(&self) -> Vec { + self.0.as_bytes().encode() + } + } + + impl Decode for VrfOutput { + fn decode(i: &mut R) -> Result { + let decoded = <[u8; VRF_OUTPUT_LENGTH]>::decode(i)?; + Ok(Self(schnorrkel::vrf::VRFOutput::from_bytes(&decoded).map_err(convert_error)?)) + } } - let mut messages: Vec = messages - .into_iter() - .map(|msg| signing_context(SIGNING_CTX).bytes(msg)) - .collect(); + 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() + } + } + + /// VRF proof type suitable for schnorrkel operations. + #[derive(Clone, Debug, PartialEq, Eq)] + pub struct VrfProof(pub schnorrkel::vrf::VRFProof); + + impl Encode for VrfProof { + fn encode(&self) -> Vec { + self.0.to_bytes().encode() + } + } + + impl Decode for VrfProof { + fn decode(i: &mut R) -> Result { + let decoded = <[u8; VRF_PROOF_LENGTH]>::decode(i)?; + Ok(Self(schnorrkel::vrf::VRFProof::from_bytes(&decoded).map_err(convert_error)?)) + } + } + + impl MaxEncodedLen for VrfProof { + fn max_encoded_len() -> usize { + <[u8; VRF_PROOF_LENGTH]>::max_encoded_len() + } + } - schnorrkel::verify_batch(&mut messages, &sr_signatures, &sr_pub_keys, true).is_ok() + impl TypeInfo for VrfProof { + type Identity = [u8; VRF_PROOF_LENGTH]; + + fn type_info() -> scale_info::Type { + Self::Identity::type_info() + } + } + + #[cfg(feature = "full_crypto")] + impl VrfCrypto for Pair { + type VrfSignature = VrfSignature; + type VrfInput = VrfTranscript; + } + + #[cfg(feature = "full_crypto")] + impl VrfSigner for Pair { + fn vrf_sign(&self, transcript: &Self::VrfInput) -> Self::VrfSignature { + let (inout, proof, _) = self.0.vrf_sign(transcript.0.clone()); + VrfSignature { output: VrfOutput(inout.to_output()), proof: VrfProof(proof) } + } + } + + impl VrfCrypto for Public { + type VrfSignature = VrfSignature; + type VrfInput = VrfTranscript; + } + + impl VrfVerifier for Public { + fn vrf_verify(&self, transcript: &Self::VrfInput, signature: &Self::VrfSignature) -> bool { + schnorrkel::PublicKey::from_bytes(self) + .and_then(|public| { + public.vrf_verify(transcript.0.clone(), &signature.output.0, &signature.proof.0) + }) + .is_ok() + } + } + + fn convert_error(e: SignatureError) -> codec::Error { + use MultiSignatureStage::*; + use SignatureError::*; + match e { + EquationFalse => "Signature error: `EquationFalse`".into(), + PointDecompressionError => "Signature error: `PointDecompressionError`".into(), + ScalarFormatError => "Signature error: `ScalarFormatError`".into(), + NotMarkedSchnorrkel => "Signature error: `NotMarkedSchnorrkel`".into(), + BytesLengthError { .. } => "Signature error: `BytesLengthError`".into(), + MuSigAbsent { musig_stage: Commitment } => + "Signature error: `MuSigAbsent` at stage `Commitment`".into(), + MuSigAbsent { musig_stage: Reveal } => + "Signature error: `MuSigAbsent` at stage `Reveal`".into(), + MuSigAbsent { musig_stage: Cosignature } => + "Signature error: `MuSigAbsent` at stage `Commitment`".into(), + MuSigInconsistent { musig_stage: Commitment, duplicate: true } => + "Signature error: `MuSigInconsistent` at stage `Commitment` on duplicate".into(), + MuSigInconsistent { musig_stage: Commitment, duplicate: false } => + "Signature error: `MuSigInconsistent` at stage `Commitment` on not duplicate".into(), + MuSigInconsistent { musig_stage: Reveal, duplicate: true } => + "Signature error: `MuSigInconsistent` at stage `Reveal` on duplicate".into(), + MuSigInconsistent { musig_stage: Reveal, duplicate: false } => + "Signature error: `MuSigInconsistent` at stage `Reveal` on not duplicate".into(), + MuSigInconsistent { musig_stage: Cosignature, duplicate: true } => + "Signature error: `MuSigInconsistent` at stage `Cosignature` on duplicate".into(), + MuSigInconsistent { musig_stage: Cosignature, duplicate: false } => + "Signature error: `MuSigInconsistent` at stage `Cosignature` on not duplicate" + .into(), + } + } + + #[cfg(feature = "full_crypto")] + impl Pair { + /// Generate bytes from the given VRF configuration. + pub fn make_bytes>( + &self, + context: &[u8], + transcript: &VrfTranscript, + ) -> B { + let inout = self.0.vrf_create_hash(transcript.0.clone()); + inout.make_bytes::(context) + } + } + + impl Public { + /// Generate bytes from the given VRF configuration. + pub fn make_bytes>( + &self, + context: &[u8], + transcript: &VrfTranscript, + output: &VrfOutput, + ) -> Result { + let pubkey = schnorrkel::PublicKey::from_bytes(&self.0).map_err(convert_error)?; + let inout = output + .0 + .attach_input_hash(&pubkey, transcript.0.clone()) + .map_err(convert_error)?; + Ok(inout.make_bytes::(context)) + } + } } #[cfg(test)] -mod compatibility_test { +mod tests { use super::*; use crate::crypto::{Ss58Codec, DEV_ADDRESS, DEV_PHRASE}; use serde_json; @@ -811,4 +958,20 @@ mod compatibility_test { // Poorly-sized assert!(deserialize_signature("\"abc123\"").is_err()); } + + #[test] + fn vrf_make_bytes_matches() { + use super::vrf::*; + use crate::crypto::VrfSigner; + let pair = Pair::from_seed(b"12345678901234567890123456789012"); + let public = pair.public(); + let transcript = VrfTranscript::new(b"test", &[(b"foo", b"bar")]); + + let signature = pair.vrf_sign(&transcript); + + let ctx = b"randbytes"; + let b1 = pair.make_bytes::<[u8; 32]>(ctx, &transcript); + let b2 = public.make_bytes::<[u8; 32]>(ctx, &transcript, &signature.output).unwrap(); + assert_eq!(b1, b2); + } } diff --git a/primitives/keystore/Cargo.toml b/primitives/keystore/Cargo.toml index 543f01059412e..6b0194247219a 100644 --- a/primitives/keystore/Cargo.toml +++ b/primitives/keystore/Cargo.toml @@ -15,9 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } futures = "0.3.21" -merlin = { version = "2.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" sp-core = { version = "7.0.0", default-features = false, path = "../core" } @@ -31,8 +29,6 @@ rand_chacha = "0.2.2" default = ["std"] std = [ "codec/std", - "merlin/std", - "schnorrkel/std", "serde", "sp-core/std", "sp-externalities/std", diff --git a/primitives/keystore/src/lib.rs b/primitives/keystore/src/lib.rs index 577969cdfecd8..5b41f3b80043d 100644 --- a/primitives/keystore/src/lib.rs +++ b/primitives/keystore/src/lib.rs @@ -16,10 +16,9 @@ // limitations under the License. //! Keystore traits + pub mod testing; -pub mod vrf; -use crate::vrf::{VRFSignature, VRFTranscriptData}; use sp_core::{ crypto::{ByteArray, CryptoTypeId, KeyTypeId}, ecdsa, ed25519, sr25519, @@ -87,8 +86,8 @@ pub trait Keystore: Send + Sync { &self, key_type: KeyTypeId, public: &sr25519::Public, - transcript_data: VRFTranscriptData, - ) -> Result, Error>; + transcript: &sr25519::vrf::VrfTranscript, + ) -> Result, Error>; /// Returns all ed25519 public keys for the given key type. fn ed25519_public_keys(&self, key_type: KeyTypeId) -> Vec; diff --git a/primitives/keystore/src/testing.rs b/primitives/keystore/src/testing.rs index e5107cba746f2..a6fcd6e26abe3 100644 --- a/primitives/keystore/src/testing.rs +++ b/primitives/keystore/src/testing.rs @@ -17,15 +17,13 @@ //! Types that should only be used for testing! +use crate::{Error, Keystore, KeystorePtr}; + use sp_core::{ - crypto::{ByteArray, KeyTypeId, Pair}, + crypto::{ByteArray, KeyTypeId, Pair, VrfSigner}, ecdsa, ed25519, sr25519, }; -use crate::{ - vrf::{make_transcript, VRFSignature, VRFTranscriptData}, - Error, Keystore, KeystorePtr, -}; use parking_lot::RwLock; use std::{collections::HashMap, sync::Arc}; @@ -100,6 +98,16 @@ impl MemoryKeystore { let sig = self.pair::(key_type, public).map(|pair| pair.sign(msg)); Ok(sig) } + + fn vrf_sign( + &self, + key_type: KeyTypeId, + public: &T::Public, + transcript: &T::VrfInput, + ) -> Result, Error> { + let sig = self.pair::(key_type, public).map(|pair| pair.vrf_sign(transcript)); + Ok(sig) + } } impl Keystore for MemoryKeystore { @@ -128,14 +136,9 @@ impl Keystore for MemoryKeystore { &self, key_type: KeyTypeId, public: &sr25519::Public, - transcript_data: VRFTranscriptData, - ) -> Result, Error> { - let sig = self.pair::(key_type, public).map(|pair| { - let transcript = make_transcript(transcript_data); - let (inout, proof, _) = pair.as_ref().vrf_sign(transcript); - VRFSignature { output: inout.to_output(), proof } - }); - Ok(sig) + transcript: &sr25519::vrf::VrfTranscript, + ) -> Result, Error> { + self.vrf_sign::(key_type, public, transcript) } fn ed25519_public_keys(&self, key_type: KeyTypeId) -> Vec { @@ -225,7 +228,6 @@ impl Into for MemoryKeystore { #[cfg(test)] mod tests { use super::*; - use crate::vrf::VRFTranscriptValue; use sp_core::{ sr25519, testing::{ECDSA, ED25519, SR25519}, @@ -265,23 +267,23 @@ mod tests { let secret_uri = "//Alice"; let key_pair = sr25519::Pair::from_string(secret_uri, None).expect("Generates key pair"); - let transcript_data = VRFTranscriptData { - label: b"Test", - items: vec![ - ("one", VRFTranscriptValue::U64(1)), - ("two", VRFTranscriptValue::U64(2)), - ("three", VRFTranscriptValue::Bytes("test".as_bytes().to_vec())), + let transcript = sr25519::vrf::VrfTranscript::new( + b"Test", + &[ + (b"one", &1_u64.to_le_bytes()), + (b"two", &2_u64.to_le_bytes()), + (b"three", "test".as_bytes()), ], - }; + ); - let result = store.sr25519_vrf_sign(SR25519, &key_pair.public(), transcript_data.clone()); + let result = store.sr25519_vrf_sign(SR25519, &key_pair.public(), &transcript); assert!(result.unwrap().is_none()); store .insert(SR25519, secret_uri, key_pair.public().as_ref()) .expect("Inserts unknown key"); - let result = store.sr25519_vrf_sign(SR25519, &key_pair.public(), transcript_data); + let result = store.sr25519_vrf_sign(SR25519, &key_pair.public(), &transcript); assert!(result.unwrap().is_some()); } diff --git a/primitives/keystore/src/vrf.rs b/primitives/keystore/src/vrf.rs deleted file mode 100644 index e089336c1485b..0000000000000 --- a/primitives/keystore/src/vrf.rs +++ /dev/null @@ -1,94 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! VRF-specifc data types and helpers - -use codec::Encode; -use merlin::Transcript; -use schnorrkel::vrf::{VRFOutput, VRFProof}; - -/// An enum whose variants represent possible -/// accepted values to construct the VRF transcript -#[derive(Clone, Encode)] -#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] -pub enum VRFTranscriptValue { - /// Value is an array of bytes - Bytes(Vec), - /// Value is a u64 integer - U64(u64), -} -/// VRF Transcript data -#[derive(Clone, Encode)] -pub struct VRFTranscriptData { - /// The transcript's label - pub label: &'static [u8], - /// Additional data to be registered into the transcript - pub items: Vec<(&'static str, VRFTranscriptValue)>, -} -/// VRF signature data -pub struct VRFSignature { - /// The VRFOutput serialized - pub output: VRFOutput, - /// The calculated VRFProof - pub proof: VRFProof, -} - -/// Construct a `Transcript` object from data. -/// -/// Returns `merlin::Transcript` -pub fn make_transcript(data: VRFTranscriptData) -> Transcript { - let mut transcript = Transcript::new(data.label); - for (label, value) in data.items.into_iter() { - match value { - VRFTranscriptValue::Bytes(bytes) => { - transcript.append_message(label.as_bytes(), &bytes); - }, - VRFTranscriptValue::U64(val) => { - transcript.append_u64(label.as_bytes(), val); - }, - } - } - transcript -} - -#[cfg(test)] -mod tests { - use super::*; - use rand::RngCore; - use rand_chacha::{rand_core::SeedableRng, ChaChaRng}; - - #[test] - fn transcript_creation_matches() { - let mut orig_transcript = Transcript::new(b"My label"); - orig_transcript.append_u64(b"one", 1); - orig_transcript.append_message(b"two", "test".as_bytes()); - - let new_transcript = make_transcript(VRFTranscriptData { - label: b"My label", - items: vec![ - ("one", VRFTranscriptValue::U64(1)), - ("two", VRFTranscriptValue::Bytes("test".as_bytes().to_vec())), - ], - }); - let test = |t: Transcript| -> [u8; 16] { - let mut b = [0u8; 16]; - t.build_rng().finalize(&mut ChaChaRng::from_seed([0u8; 32])).fill_bytes(&mut b); - b - }; - debug_assert!(test(orig_transcript) == test(new_transcript)); - } -} From 54ce95eb1f11f4d30277f1ec47a4398cdf8896d8 Mon Sep 17 00:00:00 2001 From: gupnik <17176722+gupnik@users.noreply.github.com> Date: Wed, 19 Apr 2023 16:24:19 +0530 Subject: [PATCH 671/715] Adds example for dev_mode and updates doc (#13944) * Adds example for dev_mode and updates doc * Addresses review comments * Update frame/examples/dev-mode/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Addresses review comment --------- Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- Cargo.lock | 16 ++++ Cargo.toml | 1 + frame/examples/dev-mode/Cargo.toml | 42 +++++++++ frame/examples/dev-mode/README.md | 11 +++ frame/examples/dev-mode/src/lib.rs | 118 ++++++++++++++++++++++++ frame/examples/dev-mode/src/tests.rs | 130 +++++++++++++++++++++++++++ frame/support/procedural/src/lib.rs | 2 + 7 files changed, 320 insertions(+) create mode 100644 frame/examples/dev-mode/Cargo.toml create mode 100644 frame/examples/dev-mode/README.md create mode 100644 frame/examples/dev-mode/src/lib.rs create mode 100644 frame/examples/dev-mode/src/tests.rs diff --git a/Cargo.lock b/Cargo.lock index 26fb7c4ae1950..c7f74a495d2fe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5986,6 +5986,22 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-dev-mode" +version = "4.0.0-dev" +dependencies = [ + "frame-support", + "frame-system", + "log", + "pallet-balances", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-election-provider-multi-phase" version = "4.0.0-dev" diff --git a/Cargo.toml b/Cargo.toml index 507d7621000b5..82e2264a3a2c6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -106,6 +106,7 @@ members = [ "frame/election-provider-support/solution-type/fuzzer", "frame/examples/basic", "frame/examples/offchain-worker", + "frame/examples/dev-mode", "frame/executive", "frame/nis", "frame/grandpa", diff --git a/frame/examples/dev-mode/Cargo.toml b/frame/examples/dev-mode/Cargo.toml new file mode 100644 index 0000000000000..a1f8de4b09d74 --- /dev/null +++ b/frame/examples/dev-mode/Cargo.toml @@ -0,0 +1,42 @@ +[package] +name = "pallet-dev-mode" +version = "4.0.0-dev" +authors = ["Parity Technologies "] +edition = "2021" +license = "MIT-0" +homepage = "https://substrate.io" +repository = "https://github.com/paritytech/substrate/" +description = "FRAME example pallet" +readme = "README.md" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false } +log = { version = "0.4.17", default-features = false } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +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 = "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 = "7.0.0", default-features = false, path = "../../../primitives/core" } + +[features] +default = ["std"] +std = [ + "codec/std", + "frame-support/std", + "frame-system/std", + "log/std", + "pallet-balances/std", + "scale-info/std", + "sp-io/std", + "sp-runtime/std", + "sp-std/std", +] +try-runtime = ["frame-support/try-runtime"] diff --git a/frame/examples/dev-mode/README.md b/frame/examples/dev-mode/README.md new file mode 100644 index 0000000000000..4c9ee88629c23 --- /dev/null +++ b/frame/examples/dev-mode/README.md @@ -0,0 +1,11 @@ + +# Dev Mode Example Pallet + +A simple example of a FRAME pallet demonstrating +the ease of requirements for a pallet in dev mode. + +Run `cargo doc --package pallet-dev-mode --open` to view this pallet's documentation. + +**Dev mode is not meant to be used in production.** + +License: MIT-0 diff --git a/frame/examples/dev-mode/src/lib.rs b/frame/examples/dev-mode/src/lib.rs new file mode 100644 index 0000000000000..dbc302f4997d4 --- /dev/null +++ b/frame/examples/dev-mode/src/lib.rs @@ -0,0 +1,118 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! +//! # Dev Mode Example Pallet +//! +//! A simple example of a FRAME pallet demonstrating +//! the ease of requirements for a pallet in dev mode. +//! +//! Run `cargo doc --package pallet-dev-mode --open` to view this pallet's documentation. +//! +//! **Dev mode is not meant to be used in production.** + +// Ensure we're `no_std` when compiling for Wasm. +#![cfg_attr(not(feature = "std"), no_std)] + +use frame_support::dispatch::DispatchResult; +use frame_system::ensure_signed; + +// Re-export pallet items so that they can be accessed from the crate namespace. +pub use pallet::*; + +#[cfg(test)] +mod tests; + +/// A type alias for the balance type from this pallet's point of view. +type BalanceOf = ::Balance; + +/// Enable `dev_mode` for this pallet. +#[frame_support::pallet(dev_mode)] +pub mod pallet { + use super::*; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + #[pallet::config] + pub trait Config: pallet_balances::Config + frame_system::Config { + /// The overarching event type. + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + } + + // Simple declaration of the `Pallet` type. It is placeholder we use to implement traits and + // method. + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::call] + impl Pallet { + #[pallet::call_index(0)] + /// No need to define a `weight` attribute here because of `dev_mode`. + pub fn add_dummy(origin: OriginFor, id: T::AccountId) -> DispatchResult { + ensure_root(origin)?; + + if let Some(mut dummies) = Dummy::::get() { + dummies.push(id.clone()); + Dummy::::set(Some(dummies)); + } else { + Dummy::::set(Some(vec![id.clone()])); + } + + // Let's deposit an event to let the outside world know this happened. + Self::deposit_event(Event::AddDummy { account: id }); + + Ok(()) + } + + #[pallet::call_index(1)] + /// No need to define a `weight` attribute here because of `dev_mode`. + pub fn set_bar( + origin: OriginFor, + #[pallet::compact] new_value: T::Balance, + ) -> DispatchResult { + let sender = ensure_signed(origin)?; + + // Put the new value into storage. + >::insert(&sender, new_value); + + Self::deposit_event(Event::SetBar { account: sender, balance: new_value }); + + Ok(()) + } + } + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + AddDummy { account: T::AccountId }, + SetBar { account: T::AccountId, balance: BalanceOf }, + } + + /// The MEL requirement for bounded pallets is skipped by `dev_mode`. + /// This means that all storages are marked as unbounded. + /// This is equivalent to specifying `#[pallet::unbounded]` on this type definitions. + /// When the dev_mode is removed, we would need to implement implement `MaxEncodedLen`. + #[pallet::storage] + pub type Dummy = StorageValue<_, Vec>; + + /// The Hasher requirement is skipped by `dev_mode`. So, second parameter can be `_` + /// and `Blake2_128Concat` is used as a default. + /// When the dev_mode is removed, we would need to specify the hasher like so: + /// `pub type Bar = StorageMap<_, Blake2_128Concat, T::AccountId, T::Balance>;`. + #[pallet::storage] + pub type Bar = StorageMap<_, _, T::AccountId, T::Balance>; +} diff --git a/frame/examples/dev-mode/src/tests.rs b/frame/examples/dev-mode/src/tests.rs new file mode 100644 index 0000000000000..e2f06ddda6cd7 --- /dev/null +++ b/frame/examples/dev-mode/src/tests.rs @@ -0,0 +1,130 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT 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-dev-mode. + +use crate::*; +use frame_support::{assert_ok, traits::ConstU64}; +use sp_core::H256; +use sp_runtime::{ + testing::Header, + traits::{BlakeTwo256, IdentityLookup}, + BuildStorage, +}; +// Reexport crate as its pallet name for construct_runtime. +use crate as pallet_dev_mode; + +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +type Block = frame_system::mocking::MockBlock; + +// For testing the pallet, we construct a mock runtime. +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}, + Example: pallet_dev_mode::{Pallet, Call, Storage, Event}, + } +); + +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 = frame_support::traits::ConstU32<16>; +} + +impl pallet_balances::Config for Test { + type MaxLocks = (); + type MaxReserves = (); + type ReserveIdentifier = [u8; 8]; + type Balance = u64; + type DustRemoval = (); + type RuntimeEvent = RuntimeEvent; + type ExistentialDeposit = ConstU64<1>; + type AccountStore = System; + type WeightInfo = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type HoldIdentifier = (); + type MaxHolds = (); +} + +impl Config for Test { + type RuntimeEvent = RuntimeEvent; +} + +// 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 t = GenesisConfig { + // We use default for brevity, but you can configure as desired if needed. + system: Default::default(), + balances: Default::default(), + } + .build_storage() + .unwrap(); + t.into() +} + +#[test] +fn it_works_for_optional_value() { + new_test_ext().execute_with(|| { + assert_eq!(Dummy::::get(), None); + + let val1 = 42; + assert_ok!(Example::add_dummy(RuntimeOrigin::root(), val1)); + assert_eq!(Dummy::::get(), Some(vec![val1])); + + // Check that accumulate works when we have Some value in Dummy already. + let val2 = 27; + assert_ok!(Example::add_dummy(RuntimeOrigin::root(), val2)); + assert_eq!(Dummy::::get(), Some(vec![val1, val2])); + }); +} + +#[test] +fn set_dummy_works() { + new_test_ext().execute_with(|| { + let test_val = 133; + assert_ok!(Example::set_bar(RuntimeOrigin::signed(1), test_val.into())); + assert_eq!(Bar::::get(1), Some(test_val)); + }); +} diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index ea997752c3a53..33d9ce9473e59 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -465,6 +465,8 @@ pub fn construct_runtime(input: TokenStream) -> TokenStream { /// * 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. +/// * Storage hashers no longer need to be specified and can be replaced by `_`. In dev mode, these +/// will be replaced by `Blake2_128Concat`. /// /// 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 From 50de15d8740a129db9c18a6698fbd183b00326a2 Mon Sep 17 00:00:00 2001 From: Muharem Ismailov Date: Wed, 19 Apr 2023 13:00:27 +0200 Subject: [PATCH 672/715] Collective pallet: max proposal weight (#13771) * collective: max proposal weight * fix test --------- Co-authored-by: parity-processbot <> --- bin/node/runtime/src/lib.rs | 4 ++++ frame/alliance/src/mock.rs | 6 ++++- frame/collective/src/lib.rs | 14 ++++++++++++ frame/collective/src/tests.rs | 42 ++++++++++++++++++++++++++++++++++- frame/utility/src/tests.rs | 2 ++ 5 files changed, 66 insertions(+), 2 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index cdb05d1597629..5722603fe62a5 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -210,6 +210,7 @@ parameter_types! { }) .avg_block_initialization(AVERAGE_ON_INITIALIZE_RATIO) .build_or_panic(); + pub MaxCollectivesProposalWeight: Weight = Perbill::from_percent(50) * RuntimeBlockWeights::get().max_block; } const_assert!(NORMAL_DISPATCH_RATIO.deconstruct() >= AVERAGE_ON_INITIALIZE_RATIO.deconstruct()); @@ -1012,6 +1013,7 @@ impl pallet_collective::Config for Runtime { type DefaultVote = pallet_collective::PrimeDefaultVote; type WeightInfo = pallet_collective::weights::SubstrateWeight; type SetMembersOrigin = EnsureRoot; + type MaxProposalWeight = MaxCollectivesProposalWeight; } parameter_types! { @@ -1072,6 +1074,7 @@ impl pallet_collective::Config for Runtime { type DefaultVote = pallet_collective::PrimeDefaultVote; type WeightInfo = pallet_collective::weights::SubstrateWeight; type SetMembersOrigin = EnsureRoot; + type MaxProposalWeight = MaxCollectivesProposalWeight; } type EnsureRootOrHalfCouncil = EitherOfDiverse< @@ -1700,6 +1703,7 @@ impl pallet_collective::Config for Runtime { type DefaultVote = pallet_collective::PrimeDefaultVote; type WeightInfo = pallet_collective::weights::SubstrateWeight; type SetMembersOrigin = EnsureRoot; + type MaxProposalWeight = MaxCollectivesProposalWeight; } parameter_types! { diff --git a/frame/alliance/src/mock.rs b/frame/alliance/src/mock.rs index 848f6b2a00557..c334a3943b025 100644 --- a/frame/alliance/src/mock.rs +++ b/frame/alliance/src/mock.rs @@ -43,10 +43,12 @@ type AccountId = u64; parameter_types! { pub const BlockHashCount: BlockNumber = 250; + pub BlockWeights: frame_system::limits::BlockWeights = + frame_system::limits::BlockWeights::simple_max(Weight::MAX); } impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = (); + type BlockWeights = BlockWeights; type BlockLength = (); type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; @@ -97,6 +99,7 @@ parameter_types! { pub const MotionDuration: BlockNumber = MOTION_DURATION_IN_BLOCKS; pub const MaxProposals: u32 = 100; pub const MaxMembers: u32 = 100; + pub MaxProposalWeight: Weight = sp_runtime::Perbill::from_percent(50) * BlockWeights::get().max_block; } type AllianceCollective = pallet_collective::Instance1; impl pallet_collective::Config for Test { @@ -109,6 +112,7 @@ impl pallet_collective::Config for Test { type DefaultVote = pallet_collective::PrimeDefaultVote; type WeightInfo = (); type SetMembersOrigin = EnsureRoot; + type MaxProposalWeight = MaxProposalWeight; } parameter_types! { diff --git a/frame/collective/src/lib.rs b/frame/collective/src/lib.rs index 0cbf7e97261df..0ecf008fee80e 100644 --- a/frame/collective/src/lib.rs +++ b/frame/collective/src/lib.rs @@ -217,6 +217,10 @@ pub mod pallet { /// Origin allowed to set collective members type SetMembersOrigin: EnsureOrigin<::RuntimeOrigin>; + + /// The maximum weight of a dispatch call that can be proposed and executed. + #[pallet::constant] + type MaxProposalWeight: Get; } #[pallet::genesis_config] @@ -667,6 +671,11 @@ impl, I: 'static> Pallet { ) -> Result<(u32, DispatchResultWithPostInfo), DispatchError> { let proposal_len = proposal.encoded_size(); ensure!(proposal_len <= length_bound as usize, Error::::WrongProposalLength); + let proposal_weight = proposal.get_dispatch_info().weight; + ensure!( + proposal_weight.all_lte(T::MaxProposalWeight::get()), + Error::::WrongProposalWeight + ); let proposal_hash = T::Hashing::hash_of(&proposal); ensure!(!>::contains_key(proposal_hash), Error::::DuplicateProposal); @@ -689,6 +698,11 @@ impl, I: 'static> Pallet { ) -> Result<(u32, u32), DispatchError> { let proposal_len = proposal.encoded_size(); ensure!(proposal_len <= length_bound as usize, Error::::WrongProposalLength); + let proposal_weight = proposal.get_dispatch_info().weight; + ensure!( + proposal_weight.all_lte(T::MaxProposalWeight::get()), + Error::::WrongProposalWeight + ); let proposal_hash = T::Hashing::hash_of(&proposal); ensure!(!>::contains_key(proposal_hash), Error::::DuplicateProposal); diff --git a/frame/collective/src/tests.rs b/frame/collective/src/tests.rs index 79dc3becfffc6..4775133ffa2f6 100644 --- a/frame/collective/src/tests.rs +++ b/frame/collective/src/tests.rs @@ -90,10 +90,13 @@ pub type MaxMembers = ConstU32<100>; parameter_types! { pub const MotionDuration: u64 = 3; pub const MaxProposals: u32 = 257; + pub BlockWeights: frame_system::limits::BlockWeights = + frame_system::limits::BlockWeights::simple_max(Weight::MAX); + pub static MaxProposalWeight: Weight = default_max_proposal_weight(); } impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = (); + type BlockWeights = BlockWeights; type BlockLength = (); type DbWeight = (); type RuntimeOrigin = RuntimeOrigin; @@ -127,6 +130,7 @@ impl Config for Test { type DefaultVote = PrimeDefaultVote; type WeightInfo = (); type SetMembersOrigin = EnsureRoot; + type MaxProposalWeight = MaxProposalWeight; } impl Config for Test { type RuntimeOrigin = RuntimeOrigin; @@ -138,6 +142,7 @@ impl Config for Test { type DefaultVote = MoreThanMajorityThenPrimeDefaultVote; type WeightInfo = (); type SetMembersOrigin = EnsureRoot; + type MaxProposalWeight = MaxProposalWeight; } impl mock_democracy::Config for Test { type RuntimeEvent = RuntimeEvent; @@ -153,6 +158,7 @@ impl Config for Test { type DefaultVote = PrimeDefaultVote; type WeightInfo = (); type SetMembersOrigin = EnsureRoot; + type MaxProposalWeight = MaxProposalWeight; } pub struct ExtBuilder {} @@ -201,6 +207,10 @@ fn record(event: RuntimeEvent) -> EventRecord { EventRecord { phase: Phase::Initialization, event, topics: vec![] } } +fn default_max_proposal_weight() -> Weight { + sp_runtime::Perbill::from_percent(80) * BlockWeights::get().max_block +} + #[test] fn motions_basic_environment_works() { ExtBuilder::default().build_and_execute(|| { @@ -209,6 +219,36 @@ fn motions_basic_environment_works() { }); } +#[test] +fn proposal_weight_limit_works() { + ExtBuilder::default().build_and_execute(|| { + let proposal = make_proposal(42); + let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); + + assert_ok!(Collective::propose( + RuntimeOrigin::signed(1), + 2, + Box::new(proposal.clone()), + proposal_len + )); + + // set a small limit for max proposal weight. + MaxProposalWeight::set(Weight::from_parts(1, 1)); + assert_noop!( + Collective::propose( + RuntimeOrigin::signed(1), + 2, + Box::new(proposal.clone()), + proposal_len + ), + Error::::WrongProposalWeight + ); + + // reset the max weight to default. + MaxProposalWeight::set(default_max_proposal_weight()); + }); +} + #[test] fn close_works() { ExtBuilder::default().build_and_execute(|| { diff --git a/frame/utility/src/tests.rs b/frame/utility/src/tests.rs index d23c57e69bec5..6f156e318c8cf 100644 --- a/frame/utility/src/tests.rs +++ b/frame/utility/src/tests.rs @@ -209,6 +209,7 @@ parameter_types! { pub const MotionDuration: BlockNumber = MOTION_DURATION_IN_BLOCKS; pub const MaxProposals: u32 = 100; pub const MaxMembers: u32 = 100; + pub MaxProposalWeight: Weight = sp_runtime::Perbill::from_percent(50) * BlockWeights::get().max_block; } type CouncilCollective = pallet_collective::Instance1; @@ -222,6 +223,7 @@ impl pallet_collective::Config for Test { type DefaultVote = pallet_collective::PrimeDefaultVote; type WeightInfo = (); type SetMembersOrigin = frame_system::EnsureRoot; + type MaxProposalWeight = MaxProposalWeight; } impl example::Config for Test {} From f9d10fabe04d598d68f8b097cc4905adbb1ad630 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Thu, 20 Apr 2023 10:53:06 +0200 Subject: [PATCH 673/715] `build_network` doesn't require the `MaintainedTransactionPool` bound (#13959) --- client/service/src/builder.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index 415fa03a10020..2208c55cf4090 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -60,7 +60,7 @@ use sc_rpc::{ }; use sc_rpc_spec_v2::{chain_head::ChainHeadApiServer, transaction::TransactionApiServer}; use sc_telemetry::{telemetry, ConnectionMessage, Telemetry, TelemetryHandle, SUBSTRATE_INFO}; -use sc_transaction_pool_api::MaintainedTransactionPool; +use sc_transaction_pool_api::{MaintainedTransactionPool, TransactionPool}; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedSender}; use sp_api::{CallApiAt, ProvideRuntimeApi}; use sp_blockchain::{HeaderBackend, HeaderMetadata}; @@ -756,7 +756,7 @@ where + HeaderBackend + BlockchainEvents + 'static, - TExPool: MaintainedTransactionPool::Hash> + 'static, + TExPool: TransactionPool::Hash> + 'static, TImpQu: ImportQueue + 'static, { let BuildNetworkParams { From 87fd264d52ef8f23716e13b9abda34a63877ec63 Mon Sep 17 00:00:00 2001 From: Mira Ressel Date: Thu, 20 Apr 2023 14:02:40 +0200 Subject: [PATCH 674/715] ci: drop skip-if-draft job (#13961) It's been effectively disabled for half a year already, and according to internal discussion we don't want it back. --- .gitlab-ci.yml | 14 -------------- scripts/ci/gitlab/skip_if_draft.sh | 14 -------------- 2 files changed, 28 deletions(-) delete mode 100755 scripts/ci/gitlab/skip_if_draft.sh diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e7b0093184cd3..d585d688aa8b7 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -251,20 +251,6 @@ default: #### stage: .pre -skip-if-draft: - extends: .kubernetes-env - variables: - CI_IMAGE: "paritytech/tools:latest" - stage: .pre - rules: - - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs - script: - - echo "Commit message is ${CI_COMMIT_MESSAGE}" - - echo "Ref is ${CI_COMMIT_REF_NAME}" - - echo "pipeline source is ${CI_PIPELINE_SOURCE}" - - ./scripts/ci/gitlab/skip_if_draft.sh - allow_failure: true - check-crates-publishing-pipeline: stage: .pre extends: diff --git a/scripts/ci/gitlab/skip_if_draft.sh b/scripts/ci/gitlab/skip_if_draft.sh deleted file mode 100755 index cf6ea6a5b3115..0000000000000 --- a/scripts/ci/gitlab/skip_if_draft.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/sh -url="https://api.github.com/repos/paritytech/substrate/pulls/${CI_COMMIT_REF_NAME}" -echo "[+] API URL: $url" - -draft_state=$(curl -H "Authorization: token ${GITHUB_PR_TOKEN}" "$url" | jq -r .draft) -echo "[+] Draft state: $draft_state" - -if [ "$draft_state" = 'true' ]; then - echo "[!] PR is currently a draft, stopping pipeline" - exit 1 -else - echo "[+] PR is not a draft. Proceeding with CI pipeline" - exit 0 -fi From 532edcf9ac691bebd2959ca3fa4cd90d8171ccb3 Mon Sep 17 00:00:00 2001 From: Mira Ressel Date: Thu, 20 Apr 2023 14:03:05 +0200 Subject: [PATCH 675/715] replace unused cargo-deny check with a new cargo-deny-licenses job (#13956) * ci: remove the cargo-deny job It's been broken and disabled for quite a while, and per internal discussion there doesn't seem to be any interest in fixing it and actually using the job output for anything. * ci: add new cargo-deny-licenses job It'll run on all PRs and fail if external dependencies with unsuitable licenses are detected. --- .gitlab-ci.yml | 5 - scripts/ci/deny.toml | 212 +++++++++------------------- scripts/ci/gitlab/pipeline/test.yml | 12 +- 3 files changed, 73 insertions(+), 156 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d585d688aa8b7..c6ce21c7e416f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -215,11 +215,6 @@ default: .zombienet-refs: extends: .build-refs -.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" - .crates-publishing-variables: variables: CRATESIO_CRATES_OWNER: parity-crate-owner diff --git a/scripts/ci/deny.toml b/scripts/ci/deny.toml index bc41f746cbb1e..f932875937606 100644 --- a/scripts/ci/deny.toml +++ b/scripts/ci/deny.toml @@ -1,87 +1,19 @@ -# This template contains all of the possible sections and their default values - -# Note that all fields that take a lint level have these possible values: -# * deny - An error will be produced and the check will fail -# * warn - A warning will be produced, but the check will not fail -# * allow - No warning or error will be produced, though in some cases a note -# will be - -# The values provided in this template are the default values that will be used -# when any section or field is not specified in your own configuration - -# If 1 or more target triples (and optionally, target_features) are specified, -# only the specified targets will be checked when running `cargo deny check`. -# This means, if a particular package is only ever used as a target specific -# dependency, such as, for example, the `nix` crate only being used via the -# `target_family = "unix"` configuration, that only having windows targets in -# this list would mean the nix crate, as well as any of its exclusive -# dependencies not shared by any other crates, would be ignored, as the target -# list here is effectively saying which targets you are building for. -targets = [ - # The triple can be any string, but only the target triples built in to - # rustc (as of 1.40) can be checked against actual config expressions - #{ triple = "x86_64-unknown-linux-musl" }, - # You can also specify which target_features you promise are enabled for a - # particular target. target_features are currently not validated against - # the actual valid features supported by the target architecture. - #{ triple = "wasm32-unknown-unknown", features = ["atomics"] }, -] - -# This section is considered when running `cargo deny check advisories` -# More documentation for the advisories section can be found here: -# https://embarkstudios.github.io/cargo-deny/checks/advisories/cfg.html -[advisories] -# The path where the advisory database is cloned/fetched into -db-path = "~/.cargo/advisory-db" -# The url of the advisory database to use -db-url = "https://github.com/rustsec/advisory-db" -# The lint level for security vulnerabilities -vulnerability = "deny" -# The lint level for unmaintained crates -unmaintained = "warn" -# The lint level for crates that have been yanked from their source registry -yanked = "warn" -# The lint level for crates with security notices. Note that as of -# 2019-12-17 there are no security notice advisories in -# https://github.com/rustsec/advisory-db -notice = "warn" -# A list of advisory IDs to ignore. Note that ignored advisories will still -# output a note when they are encountered. -ignore = [ - #"RUSTSEC-0000-0000", -] -# Threshold for security vulnerabilities, any vulnerability with a CVSS score -# lower than the range specified will be ignored. Note that ignored advisories -# will still output a note when they are encountered. -# * None - CVSS Score 0.0 -# * Low - CVSS Score 0.1 - 3.9 -# * Medium - CVSS Score 4.0 - 6.9 -# * High - CVSS Score 7.0 - 8.9 -# * Critical - CVSS Score 9.0 - 10.0 -#severity-threshold = - -# This section is considered when running `cargo deny check licenses` -# More documentation for the licenses section can be found here: -# https://embarkstudios.github.io/cargo-deny/checks/licenses/cfg.html [licenses] # The lint level for crates which do not have a detectable license unlicensed = "deny" -# List of explictly allowed licenses +# List of explicitly allowed licenses # See https://spdx.org/licenses/ for list of possible licenses -# [possible values: any SPDX 3.7 short identifier (+ optional exception)]. +# [possible values: any SPDX 3.11 short identifier (+ optional exception)]. allow = [ - #"MIT", - #"Apache-2.0", - #"Apache-2.0 WITH LLVM-exception", + "MPL-2.0", ] -# List of explictly disallowed licenses +# List of explicitly disallowed licenses # See https://spdx.org/licenses/ for list of possible licenses -# [possible values: any SPDX 3.7 short identifier (+ optional exception)]. +# [possible values: any SPDX 3.11 short identifier (+ optional exception)]. deny = [ - #"Nokia", ] # Lint level for licenses considered copyleft -copyleft = "allow" +copyleft = "deny" # Blanket approval or denial for OSI-approved or FSF Free/Libre licenses # * both - The license will be approved if it is both OSI-approved *AND* FSF # * either - The license will be approved if it is either OSI-approved *OR* FSF @@ -98,13 +30,69 @@ default = "deny" # The higher the value, the more closely the license text must be to the # canonical license text of a valid SPDX license file. # [possible values: any between 0.0 and 1.0]. -confidence-threshold = 0.9 +confidence-threshold = 0.8 # Allow 1 or more licenses on a per-crate basis, so that particular licenses # aren't accepted for every possible crate as with the normal allow list exceptions = [ - # Each entry is the crate and version constraint, and its specific allow - # list - #{ allow = ["Zlib"], name = "adler32", version = "*" }, + # Each entry is the crate and version constraint, and its specific allow list + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "chain-spec-builder" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "mmr-gadget" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "node-bench" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "node-cli" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "node-inspect" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "node-testing" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-authority-discovery" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-basic-authorship" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-block-builder" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-chain-spec" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-chain-spec-derive" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-cli" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-client-api" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-client-db" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-consensus" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-consensus-aura" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-consensus-babe" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-consensus-babe-rpc" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-consensus-beefy" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-consensus-beefy-rpc" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-consensus-epochs" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-consensus-grandpa" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-consensus-grandpa-rpc" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-consensus-manual-seal" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-consensus-pow" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-consensus-slots" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-executor" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-executor-common" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-executor-wasmi" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-executor-wasmtime" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-informant" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-keystore" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-network" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-network-bitswap" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-network-common" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-network-gossip" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-network-light" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-network-sync" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-network-test" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-network-transactions" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-offchain" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-peerset" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-proposer-metrics" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-rpc" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-rpc-api" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-rpc-server" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-rpc-spec-v2" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-runtime-test" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-service" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-service-test" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-state-db" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-storage-monitor" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-sysinfo" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-telemetry" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-tracing" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-transaction-pool" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "sc-transaction-pool-api" }, + { allow = ["GPL-3.0 WITH Classpath-exception-2.0"], name = "subkey" }, ] # Some crates don't have (easily) machine readable licensing information, @@ -113,10 +101,8 @@ exceptions = [ [[licenses.clarify]] # The name of the crate the clarification applies to name = "ring" -# THe optional version constraint for the crate -#version = "*" # The SPDX expression for the license requirements of the crate -expression = "OpenSSL" +expression = "MIT AND ISC AND OpenSSL" # One or more files in the crate's source used as the "source of truth" for # the license expression. If the contents match, the clarification will be used # when running the license check, otherwise the clarification will be ignored @@ -126,67 +112,3 @@ license-files = [ # Each entry is a crate relative path, and the (opaque) hash of its contents { path = "LICENSE", hash = 0xbd0eed23 } ] -[[licenses.clarify]] -name = "webpki" -expression = "ISC" -license-files = [{ path = "LICENSE", hash = 0x001c7e6c }] - -[licenses.private] -# If true, ignores workspace crates that aren't published, or are only -# published to private registries -ignore = false -# One or more private registries that you might publish crates to, if a crate -# is only published to private registries, and ignore is true, the crate will -# not have its license(s) checked -registries = [ - #"https://sekretz.com/registry -] - -# This section is considered when running `cargo deny check bans`. -# More documentation about the 'bans' section can be found here: -# https://embarkstudios.github.io/cargo-deny/checks/bans/cfg.html -[bans] -# Lint level for when multiple versions of the same crate are detected -multiple-versions = "warn" -# The graph highlighting used when creating dotgraphs for crates -# with multiple versions -# * lowest-version - The path to the lowest versioned duplicate is highlighted -# * simplest-path - The path to the version with the fewest edges is highlighted -# * all - Both lowest-version and simplest-path are used -highlight = "lowest-version" -# List of crates that are allowed. Use with care! -allow = [ - #{ name = "ansi_term", version = "=0.11.0" }, -] -# List of crates to deny -deny = [ - # Each entry the name of a crate and a version range. If version is - # not specified, all versions will be matched. -] -# Certain crates/versions that will be skipped when doing duplicate detection. -skip = [ - #{ name = "ansi_term", version = "=0.11.0" }, -] -# Similarly to `skip` allows you to skip certain crates during duplicate -# detection. Unlike skip, it also includes the entire tree of transitive -# dependencies starting at the specified crate, up to a certain depth, which is -# by default infinite -skip-tree = [ - #{ name = "ansi_term", version = "=0.11.0", depth = 20 }, -] - -# This section is considered when running `cargo deny check sources`. -# More documentation about the 'sources' section can be found here: -# https://embarkstudios.github.io/cargo-deny/checks/sources/cfg.html -[sources] -# Lint level for what to happen when a crate from a crate registry that is not -# in the allow list is encountered -unknown-registry = "deny" -# Lint level for what to happen when a crate from a git repository that is not -# in the allow list is encountered -unknown-git = "warn" -# List of URLs for allowed crate registries. Defaults to the crates.io index -# if not specified. If it is specified but empty, no registries are allowed. -allow-registry = ["https://github.com/rust-lang/crates.io-index"] -# List of URLs for allowed Git repositories -allow-git = [] diff --git a/scripts/ci/gitlab/pipeline/test.yml b/scripts/ci/gitlab/pipeline/test.yml index bf7803d56505c..7e84694c24775 100644 --- a/scripts/ci/gitlab/pipeline/test.yml +++ b/scripts/ci/gitlab/pipeline/test.yml @@ -21,27 +21,27 @@ find-fail-ci-phrase: exit 0; fi -cargo-deny: +cargo-deny-licenses: stage: test extends: - .docker-env - - .nightly-pipeline + - .test-refs + variables: + CARGO_DENY_CMD: "cargo deny --all-features check licenses -c ./scripts/ci/deny.toml" script: - rusty-cachier snapshot create - - cargo deny check --hide-inclusion-graph -c ./scripts/ci/deny.toml + - $CARGO_DENY_CMD --hide-inclusion-graph - rusty-cachier cache upload after_script: - !reference [.rusty-cachier, after_script] - echo "___The complete log is in the artifacts___" - - cargo deny check -c ./scripts/ci/deny.toml 2> deny.log + - $CARGO_DENY_CMD 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 From d8c320941ad83bc8aa9b7136776553cd345e5c17 Mon Sep 17 00:00:00 2001 From: Jegor Sidorenko <5252494+jsidorenko@users.noreply.github.com> Date: Thu, 20 Apr 2023 15:38:45 +0300 Subject: [PATCH 676/715] [NFTs] Improve offchain signature validation (#13960) * Improve signature validation * Rework --- frame/nfts/src/common_functions.rs | 25 +++++++++++++++++++++++++ frame/nfts/src/lib.rs | 9 +++------ frame/nfts/src/tests.rs | 28 ++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 6 deletions(-) diff --git a/frame/nfts/src/common_functions.rs b/frame/nfts/src/common_functions.rs index 1ef6591db02b4..a3486edec23cb 100644 --- a/frame/nfts/src/common_functions.rs +++ b/frame/nfts/src/common_functions.rs @@ -18,6 +18,7 @@ //! Various pieces of common functionality. use crate::*; +use frame_support::pallet_prelude::*; impl, I: 'static> Pallet { /// Get the owner of the item, if the item exists. @@ -30,6 +31,30 @@ impl, I: 'static> Pallet { Collection::::get(collection).map(|i| i.owner) } + /// Validate the `data` was signed by `signer` and the `signature` is correct. + pub fn validate_signature( + data: &Vec, + signature: &T::OffchainSignature, + signer: &T::AccountId, + ) -> DispatchResult { + if signature.verify(&**data, &signer) { + return Ok(()) + } + + // NOTE: for security reasons modern UIs implicitly wrap the data requested to sign into + // , that's why we support both wrapped and raw versions. + let prefix = b""; + let suffix = b""; + let mut wrapped: Vec = Vec::with_capacity(data.len() + prefix.len() + suffix.len()); + wrapped.extend(prefix); + wrapped.extend(data); + wrapped.extend(suffix); + + ensure!(signature.verify(&*wrapped, &signer), Error::::WrongSignature); + + Ok(()) + } + #[cfg(any(test, feature = "runtime-benchmarks"))] pub fn set_next_id(id: T::CollectionId) { NextCollectionId::::set(Some(id)); diff --git a/frame/nfts/src/lib.rs b/frame/nfts/src/lib.rs index f4d0e41593476..4796819df6d2c 100644 --- a/frame/nfts/src/lib.rs +++ b/frame/nfts/src/lib.rs @@ -50,7 +50,7 @@ use frame_support::traits::{ }; use frame_system::Config as SystemConfig; use sp_runtime::{ - traits::{Saturating, StaticLookup, Zero}, + traits::{IdentifyAccount, Saturating, StaticLookup, Verify, Zero}, RuntimeDebug, }; use sp_std::prelude::*; @@ -69,7 +69,6 @@ pub mod pallet { use super::*; use frame_support::{pallet_prelude::*, traits::ExistenceRequirement}; use frame_system::pallet_prelude::*; - use sp_runtime::traits::{IdentifyAccount, Verify}; /// The current storage version. const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); @@ -1841,8 +1840,7 @@ pub mod pallet { signer: T::AccountId, ) -> DispatchResult { let origin = ensure_signed(origin)?; - let msg = Encode::encode(&mint_data); - ensure!(signature.verify(&*msg, &signer), Error::::WrongSignature); + Self::validate_signature(&Encode::encode(&mint_data), &signature, &signer)?; Self::do_mint_pre_signed(origin, mint_data, signer) } @@ -1868,8 +1866,7 @@ pub mod pallet { signer: T::AccountId, ) -> DispatchResult { let origin = ensure_signed(origin)?; - let msg = Encode::encode(&data); - ensure!(signature.verify(&*msg, &signer), Error::::WrongSignature); + Self::validate_signature(&Encode::encode(&data), &signature, &signer)?; Self::do_set_attributes_pre_signed(origin, data, signer) } } diff --git a/frame/nfts/src/tests.rs b/frame/nfts/src/tests.rs index d36f8b54e2b91..4ab12f0506056 100644 --- a/frame/nfts/src/tests.rs +++ b/frame/nfts/src/tests.rs @@ -3140,6 +3140,34 @@ fn add_remove_item_attributes_approval_should_work() { }) } +#[test] +fn validate_signature() { + new_test_ext().execute_with(|| { + let user_1_pair = sp_core::sr25519::Pair::from_string("//Alice", None).unwrap(); + let user_1_signer = MultiSigner::Sr25519(user_1_pair.public()); + let user_1 = user_1_signer.clone().into_account(); + let mint_data: PreSignedMint = PreSignedMint { + collection: 0, + item: 0, + attributes: vec![], + metadata: vec![], + only_account: None, + deadline: 100000, + }; + let encoded_data = Encode::encode(&mint_data); + let signature = MultiSignature::Sr25519(user_1_pair.sign(&encoded_data)); + assert_ok!(Nfts::validate_signature(&encoded_data, &signature, &user_1)); + + let mut wrapped_data: Vec = Vec::new(); + wrapped_data.extend(b""); + wrapped_data.extend(&encoded_data); + wrapped_data.extend(b""); + + let signature = MultiSignature::Sr25519(user_1_pair.sign(&wrapped_data)); + assert_ok!(Nfts::validate_signature(&encoded_data, &signature, &user_1)); + }) +} + #[test] fn pre_signed_mints_should_work() { new_test_ext().execute_with(|| { From 9f0d54a10a055d9809aebc60a0db9890e3530ce0 Mon Sep 17 00:00:00 2001 From: Aaro Altonen <48052676+altonen@users.noreply.github.com> Date: Thu, 20 Apr 2023 16:27:05 +0300 Subject: [PATCH 677/715] Keep track of the pending response for each peer individually (#13941) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Keep track of the pending response for each peer individually When peer disconnects or the syncing is restarted, remove the pending response so syncing won't start sending duplicate requests/receive stale responses from disconnected peers. Before this commit pending responses where stored in `FuturesUnordered` which made it hard to keep track of pending responses for each individual peer. * Update client/network/sync/src/lib.rs Co-authored-by: Bastian Köcher * ".git/.scripts/commands/fmt/fmt.sh" * Apply suggestions from code review Co-authored-by: Dmitry Markin Co-authored-by: Sebastian Kunert * Update client/network/sync/src/lib.rs --------- Co-authored-by: Bastian Köcher Co-authored-by: command-bot <> Co-authored-by: Dmitry Markin Co-authored-by: Sebastian Kunert --- client/network/sync/src/lib.rs | 116 ++++++++++++++++++++++++++++++--- 1 file changed, 108 insertions(+), 8 deletions(-) diff --git a/client/network/sync/src/lib.rs b/client/network/sync/src/lib.rs index e112a1715ced1..29c4bc840b2ae 100644 --- a/client/network/sync/src/lib.rs +++ b/client/network/sync/src/lib.rs @@ -344,7 +344,7 @@ pub struct ChainSync { /// Protocol name used to send out warp sync requests warp_sync_protocol_name: Option, /// Pending responses - pending_responses: FuturesUnordered>, + pending_responses: HashMap>, /// Handle to import queue. import_queue: Box>, /// Metrics. @@ -1238,6 +1238,7 @@ where gap_sync.blocks.clear_peer_download(who) } self.peers.remove(who); + self.pending_responses.remove(who); self.extra_justifications.peer_disconnected(who); self.allowed_requests.set_all(); self.fork_targets.retain(|_, target| { @@ -1360,7 +1361,7 @@ where if self.peers.contains_key(&who) { self.pending_responses - .push(Box::pin(async move { (who, PeerRequest::Block(request), rx.await) })); + .insert(who, Box::pin(async move { (who, PeerRequest::Block(request), rx.await) })); } match self.encode_block_request(&opaque_req) { @@ -1457,7 +1458,7 @@ where .notifications_protocol .clone() .into(), - pending_responses: Default::default(), + pending_responses: HashMap::new(), import_queue, metrics: if let Some(r) = &metrics_registry { match SyncingMetrics::register(r) { @@ -1810,6 +1811,9 @@ where return None } + // since the request is not a justification, remove it from pending responses + self.pending_responses.remove(&id); + // handle peers that were in other states. match self.new_peer(id, p.best_hash, p.best_number) { Ok(None) => None, @@ -2009,7 +2013,7 @@ where if self.peers.contains_key(&who) { self.pending_responses - .push(Box::pin(async move { (who, PeerRequest::State, rx.await) })); + .insert(who, Box::pin(async move { (who, PeerRequest::State, rx.await) })); } match self.encode_state_request(&request) { @@ -2037,7 +2041,7 @@ where if self.peers.contains_key(&who) { self.pending_responses - .push(Box::pin(async move { (who, PeerRequest::WarpProof, rx.await) })); + .insert(who, Box::pin(async move { (who, PeerRequest::WarpProof, rx.await) })); } match &self.warp_sync_protocol_name { @@ -2175,9 +2179,20 @@ where } 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) - { + let ready_responses = self + .pending_responses + .values_mut() + .filter_map(|future| match future.poll_unpin(cx) { + Poll::Pending => None, + Poll::Ready(result) => Some(result), + }) + .collect::>(); + + for (id, request, response) in ready_responses { + self.pending_responses + .remove(&id) + .expect("Logic error: peer id from pending response is missing in the map."); + match response { Ok(Ok(resp)) => match request { PeerRequest::Block(req) => { @@ -4116,4 +4131,89 @@ mod test { let state = AncestorSearchState::::BinarySearch(1, 3); assert!(handle_ancestor_search_state(&state, 2, true).is_none()); } + + #[test] + fn sync_restart_removes_block_but_not_justification_requests() { + let mut client = Arc::new(TestClientBuilder::new().build()); + let block_announce_validator = Box::new(DefaultBlockAnnounceValidator); + let import_queue = Box::new(sc_consensus::import_queue::mock::MockImportQueueHandle::new()); + let (_chain_sync_network_provider, chain_sync_network_handle) = + NetworkServiceProvider::new(); + 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, + 64, + None, + None, + chain_sync_network_handle, + import_queue, + ProtocolName::from("block-request"), + ProtocolName::from("state-request"), + None, + ) + .unwrap(); + + let peers = vec![PeerId::random(), PeerId::random()]; + + let mut new_blocks = |n| { + for _ in 0..n { + let block = client.new_block(Default::default()).unwrap().build().unwrap().block; + block_on(client.import(BlockOrigin::Own, block.clone())).unwrap(); + } + + let info = client.info(); + (info.best_hash, info.best_number) + }; + + let (b1_hash, b1_number) = new_blocks(50); + + // add new peer and request blocks from them + sync.new_peer(peers[0], Hash::random(), 42).unwrap(); + + // we wil send block requests to these peers + // for these blocks we don't know about + for (peer, request) in sync.block_requests() { + sync.send_block_request(peer, request); + } + + // add a new peer at a known block + sync.new_peer(peers[1], b1_hash, b1_number).unwrap(); + + // we request a justification for a block we have locally + sync.request_justification(&b1_hash, b1_number); + + // the justification request should be scheduled to the + // new peer which is at the given block + let mut requests = sync.justification_requests().collect::>(); + assert_eq!(requests.len(), 1); + let (peer, request) = requests.remove(0); + sync.send_block_request(peer, request); + + assert!(!std::matches!( + sync.peers.get(&peers[0]).unwrap().state, + PeerSyncState::DownloadingJustification(_), + )); + assert_eq!( + sync.peers.get(&peers[1]).unwrap().state, + PeerSyncState::DownloadingJustification(b1_hash), + ); + assert_eq!(sync.pending_responses.len(), 2); + + let requests = sync.restart().collect::>(); + assert!(requests.iter().any(|res| res.as_ref().unwrap().0 == peers[0])); + + assert_eq!(sync.pending_responses.len(), 1); + assert!(sync.pending_responses.get(&peers[1]).is_some()); + assert_eq!( + sync.peers.get(&peers[1]).unwrap().state, + PeerSyncState::DownloadingJustification(b1_hash), + ); + sync.peer_disconnected(&peers[1]); + assert_eq!(sync.pending_responses.len(), 0); + } } From e44b43e155b795b69595b32b1cbc6b52e9d4c9ac Mon Sep 17 00:00:00 2001 From: Aaro Altonen <48052676+altonen@users.noreply.github.com> Date: Fri, 21 Apr 2023 11:22:26 +0300 Subject: [PATCH 678/715] Evict inactive peers from `SyncingEngine` (#13829) * Evict inactive peers from `SyncingEngine` If both halves of the block announce notification stream have been inactive for 2 minutes, report the peer and disconnect it, allowing `SyncingEngine` to free up a slot for some other peer that hopefully is more active. This needs to be done because the node may falsely believe it has open connections to peers because the inbound substream can be closed without any notification and closed outbound substream is noticed only when node attempts to write to it which may not happen if the node has nothing to send. * zzz * wip * Evict peers only when timeout expires * Use `debug!()` --------- Co-authored-by: parity-processbot <> --- client/network/sync/src/engine.rs | 50 +++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/client/network/sync/src/engine.rs b/client/network/sync/src/engine.rs index 6fb618a571c25..eca0ebfe41a9f 100644 --- a/client/network/sync/src/engine.rs +++ b/client/network/sync/src/engine.rs @@ -67,6 +67,7 @@ use std::{ Arc, }, task::Poll, + time::{Duration, Instant}, }; /// Interval at which we perform time based maintenance @@ -75,12 +76,19 @@ const TICK_TIMEOUT: std::time::Duration = std::time::Duration::from_millis(1100) /// Maximum number of known block hashes to keep for a peer. const MAX_KNOWN_BLOCKS: usize = 1024; // ~32kb per peer + LruHashSet overhead +/// If the block announces stream to peer has been inactive for two minutes meaning local node +/// has not sent or received block announcements to/from the peer, report the node for inactivity, +/// disconnect it and attempt to establish connection to some other peer. +const INACTIVITY_EVICT_THRESHOLD: Duration = Duration::from_secs(30); + mod rep { use sc_peerset::ReputationChange as Rep; /// Peer has different genesis. pub const GENESIS_MISMATCH: Rep = Rep::new_fatal("Genesis mismatch"); /// Peer send us a block announcement that failed at validation. pub const BAD_BLOCK_ANNOUNCEMENT: Rep = Rep::new(-(1 << 12), "Bad block announcement"); + /// Block announce substream with the peer has been inactive too long + pub const INACTIVE_SUBSTREAM: Rep = Rep::new(-(1 << 10), "Inactive block announce substream"); } struct Metrics { @@ -160,6 +168,10 @@ pub struct Peer { pub known_blocks: LruHashSet, /// Notification sink. sink: NotificationsSink, + /// Instant when the last notification was sent to peer. + last_notification_sent: Instant, + /// Instant when the last notification was received from peer. + last_notification_received: Instant, } pub struct SyncingEngine { @@ -200,6 +212,9 @@ pub struct SyncingEngine { /// All connected peers. Contains both full and light node peers. peers: HashMap>, + /// Evicted peers + evicted: HashSet, + /// List of nodes for which we perform additional logging because they are important for the /// user. important_peers: HashSet, @@ -353,6 +368,7 @@ where chain_sync, network_service, peers: HashMap::new(), + evicted: HashSet::new(), block_announce_data_cache: LruCache::new(cache_capacity), block_announce_protocol_name, num_connected: num_connected.clone(), @@ -516,6 +532,7 @@ where }, }; peer.known_blocks.insert(hash); + peer.last_notification_received = Instant::now(); if peer.info.roles.is_full() { let is_best = match announce.state.unwrap_or(BlockState::Best) { @@ -566,6 +583,7 @@ where data: Some(data.clone()), }; + peer.last_notification_sent = Instant::now(); peer.sink.send_sync_notification(message.encode()); } } @@ -596,6 +614,35 @@ where while let Poll::Ready(()) = self.tick_timeout.poll_unpin(cx) { self.report_metrics(); + + // go over all connected peers and check if any of them have been idle for a while. Idle + // in this case means that we haven't sent or received block announcements to/from this + // peer. If that is the case, because of #5685, it could be that the block announces + // substream is not actually open and and this peer is just wasting a slot and is should + // be replaced with some other node that is willing to send us block announcements. + for (id, peer) in self.peers.iter() { + // because of a delay between disconnecting a peer in `SyncingEngine` and getting + // the response back from `Protocol`, a peer might be reported and disconnect + // multiple times. To prevent this from happening (until the underlying issue is + // fixed), keep track of evicted peers and report and disconnect them only once. + if self.evicted.contains(id) { + continue + } + + let last_received_late = + peer.last_notification_received.elapsed() > INACTIVITY_EVICT_THRESHOLD; + let last_sent_late = + peer.last_notification_sent.elapsed() > INACTIVITY_EVICT_THRESHOLD; + + if last_received_late && last_sent_late { + log::debug!(target: "sync", "evict peer {id} since it has been idling for too long"); + self.network_service.report_peer(*id, rep::INACTIVE_SUBSTREAM); + self.network_service + .disconnect_peer(*id, self.block_announce_protocol_name.clone()); + self.evicted.insert(*id); + } + } + self.tick_timeout.reset(TICK_TIMEOUT); } @@ -692,6 +739,7 @@ where }, }, sc_network::SyncEvent::NotificationStreamClosed { remote } => { + self.evicted.remove(&remote); if self.on_sync_peer_disconnected(remote).is_err() { log::trace!( target: "sync", @@ -844,6 +892,8 @@ where NonZeroUsize::new(MAX_KNOWN_BLOCKS).expect("Constant is nonzero"), ), sink, + last_notification_sent: Instant::now(), + last_notification_received: Instant::now(), }; let req = if peer.info.roles.is_full() { From dad40923604250c47d99f3801a61bde1dc36664e Mon Sep 17 00:00:00 2001 From: Liam Aharon Date: Fri, 21 Apr 2023 18:46:54 +1000 Subject: [PATCH 679/715] `balances` `impl_currency` WithdrawReasons note (#13964) * add withdrawreason note * improve comment * Update frame/balances/src/impl_currency.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * cargo fmt +nightly --------- Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- frame/balances/src/impl_currency.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/frame/balances/src/impl_currency.rs b/frame/balances/src/impl_currency.rs index 329ea289f966e..ff8cc71d6224a 100644 --- a/frame/balances/src/impl_currency.rs +++ b/frame/balances/src/impl_currency.rs @@ -16,6 +16,9 @@ // limitations under the License. //! Implementations for the `Currency` family of traits. +//! +//! Note that `WithdrawReasons` are intentionally not used for anything in this implementation and +//! are expected to be removed in the near future, once migration to `fungible::*` traits is done. use super::*; use frame_support::{ From 2059dca9764f2f28c91011f6db2e74516142cb32 Mon Sep 17 00:00:00 2001 From: Liam Aharon Date: Fri, 21 Apr 2023 19:16:40 +1000 Subject: [PATCH 680/715] try-runtime: dynamic storage query sizes (#13923) * improve batch rpc error message * wip aimd storage data fetch * complete aimd function refactor * make batch_request function async * improve function name * fix load_child_remote issue * slight efficiency improvement * improve logs and variable name * remove redundant comment * improve comment * address pr comments * Update utils/frame/remote-externalities/src/lib.rs Co-authored-by: Niklas Adolfsson * simplify client handling * fix type issue * fix clippy issue * try to trigger ci * try to trigger ci --------- Co-authored-by: Niklas Adolfsson --- Cargo.lock | 34 ++ utils/frame/remote-externalities/Cargo.toml | 2 + utils/frame/remote-externalities/src/lib.rs | 519 +++++++++++--------- utils/frame/try-runtime/cli/src/lib.rs | 12 - 4 files changed, 323 insertions(+), 244 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c7f74a495d2fe..b316993185862 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -395,6 +395,17 @@ dependencies = [ "futures-lite", ] +[[package]] +name = "async-recursion" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e97ce7de6cf12de5d7226c73f5ba9811622f4db3a5b91b55c53e987e5f91cba" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.14", +] + [[package]] name = "async-stream" version = "0.3.4" @@ -2427,8 +2438,10 @@ dependencies = [ name = "frame-remote-externalities" version = "0.10.0-dev" dependencies = [ + "async-recursion", "frame-support", "futures", + "jsonrpsee", "log", "pallet-elections-phragmen", "parity-scale-codec", @@ -3202,6 +3215,7 @@ dependencies = [ "rustls-native-certs", "tokio", "tokio-rustls", + "webpki-roots", ] [[package]] @@ -3468,6 +3482,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d291e3a5818a2384645fd9756362e6d89cf0541b0b916fa7702ea4a9833608e" dependencies = [ "jsonrpsee-core", + "jsonrpsee-http-client", "jsonrpsee-proc-macros", "jsonrpsee-server", "jsonrpsee-types", @@ -3524,6 +3539,25 @@ dependencies = [ "tracing", ] +[[package]] +name = "jsonrpsee-http-client" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc345b0a43c6bc49b947ebeb936e886a419ee3d894421790c969cc56040542ad" +dependencies = [ + "async-trait", + "hyper", + "hyper-rustls", + "jsonrpsee-core", + "jsonrpsee-types", + "rustc-hash", + "serde", + "serde_json", + "thiserror", + "tokio", + "tracing", +] + [[package]] name = "jsonrpsee-proc-macros" version = "0.16.2" diff --git a/utils/frame/remote-externalities/Cargo.toml b/utils/frame/remote-externalities/Cargo.toml index 8611ae4980f12..d3909af34451b 100644 --- a/utils/frame/remote-externalities/Cargo.toml +++ b/utils/frame/remote-externalities/Cargo.toml @@ -12,6 +12,7 @@ description = "An externalities provided environment that can load itself from r targets = ["x86_64-unknown-linux-gnu"] [dependencies] +jsonrpsee = { version = "0.16.2", features = ["http-client"] } codec = { package = "parity-scale-codec", version = "3.2.2" } log = "0.4.17" serde = "1.0.136" @@ -22,6 +23,7 @@ sp-runtime = { version = "7.0.0", path = "../../../primitives/runtime" } tokio = { version = "1.22.0", features = ["macros", "rt-multi-thread"] } substrate-rpc-client = { path = "../rpc/client" } futures = "0.3" +async-recursion = "1.0.4" [dev-dependencies] frame-support = { version = "4.0.0-dev", path = "../../../frame/support" } diff --git a/utils/frame/remote-externalities/src/lib.rs b/utils/frame/remote-externalities/src/lib.rs index ee342408828de..b60e2bc75d0db 100644 --- a/utils/frame/remote-externalities/src/lib.rs +++ b/utils/frame/remote-externalities/src/lib.rs @@ -20,8 +20,13 @@ //! An equivalent of `sp_io::TestExternalities` that can load its state from a remote substrate //! based chain, or a local state snapshot file. +use async_recursion::async_recursion; use codec::{Decode, Encode}; use futures::{channel::mpsc, stream::StreamExt}; +use jsonrpsee::{ + core::params::ArrayParams, + http_client::{HttpClient, HttpClientBuilder}, +}; use log::*; use serde::de::DeserializeOwned; use sp_core::{ @@ -35,6 +40,7 @@ use sp_core::{ pub use sp_io::TestExternalities; use sp_runtime::{traits::Block as BlockT, StateVersion}; use std::{ + cmp::max, fs, num::NonZeroUsize, ops::{Deref, DerefMut}, @@ -42,19 +48,14 @@ use std::{ sync::Arc, thread, }; -use substrate_rpc_client::{ - rpc_params, ws_client, BatchRequestBuilder, ChainApi, ClientT, StateApi, WsClient, -}; +use substrate_rpc_client::{rpc_params, BatchRequestBuilder, ChainApi, ClientT, StateApi}; type KeyValue = (StorageKey, StorageData); type TopKeyValues = Vec; type ChildKeyValues = Vec<(ChildInfo, Vec)>; const LOG_TARGET: &str = "remote-ext"; -const DEFAULT_WS_ENDPOINT: &str = "wss://rpc.polkadot.io:443"; -const DEFAULT_VALUE_DOWNLOAD_BATCH: usize = 4096; -// NOTE: increasing this value does not seem to impact speed all that much. -const DEFAULT_KEY_DOWNLOAD_PAGE: u32 = 1000; +const DEFAULT_HTTP_ENDPOINT: &str = "https://rpc.polkadot.io:443"; /// The snapshot that we store on disk. #[derive(Decode, Encode)] struct Snapshot { @@ -117,36 +118,51 @@ pub struct OfflineConfig { pub enum Transport { /// Use the `URI` to open a new WebSocket connection. Uri(String), - /// Use existing WebSocket connection. - RemoteClient(Arc), + /// Use HTTP connection. + RemoteClient(Arc), } impl Transport { - fn as_client(&self) -> Option<&WsClient> { + fn as_client(&self) -> Option<&HttpClient> { match self { Self::RemoteClient(client) => Some(client), _ => None, } } - fn as_client_cloned(&self) -> Option> { + fn as_client_cloned(&self) -> Option> { match self { Self::RemoteClient(client) => Some(client.clone()), _ => None, } } - // Open a new WebSocket connection if it's not connected. - async fn map_uri(&mut self) -> Result<(), &'static str> { + // Build an HttpClient from a URI. + async fn init(&mut self) -> Result<(), &'static str> { if let Self::Uri(uri) = self { log::debug!(target: LOG_TARGET, "initializing remote client to {:?}", uri); - let ws_client = ws_client(uri).await.map_err(|e| { + // If we have a ws uri, try to convert it to an http uri. + // We use an HTTP client rather than WS because WS starts to choke with "accumulated + // message length exceeds maximum" errors after processing ~10k keys when fetching + // from a node running a default configuration. + let uri = if uri.starts_with("ws://") { + let uri = uri.replace("ws://", "http://"); + log::info!(target: LOG_TARGET, "replacing ws:// in uri with http://: {:?} (ws is currently unstable for fetching remote storage, for more see https://github.com/paritytech/jsonrpsee/issues/1086)", uri); + uri + } else if uri.starts_with("wss://") { + let uri = uri.replace("wss://", "https://"); + log::info!(target: LOG_TARGET, "replacing wss:// in uri with https://: {:?} (ws is currently unstable for fetching remote storage, for more see https://github.com/paritytech/jsonrpsee/issues/1086)", uri); + uri + } else { + uri.clone() + }; + let http_client = HttpClientBuilder::default().build(uri).map_err(|e| { log::error!(target: LOG_TARGET, "error: {:?}", e); - "failed to build ws client" + "failed to build http client" })?; - *self = Self::RemoteClient(Arc::new(ws_client)) + *self = Self::RemoteClient(Arc::new(http_client)) } Ok(()) @@ -159,8 +175,8 @@ impl From for Transport { } } -impl From> for Transport { - fn from(client: Arc) -> Self { +impl From> for Transport { + fn from(client: Arc) -> Self { Transport::RemoteClient(client) } } @@ -189,18 +205,18 @@ pub struct OnlineConfig { } impl OnlineConfig { - /// Return rpc (ws) client reference. - fn rpc_client(&self) -> &WsClient { + /// Return rpc (http) client reference. + fn rpc_client(&self) -> &HttpClient { self.transport .as_client() - .expect("ws client must have been initialized by now; qed.") + .expect("http client must have been initialized by now; qed.") } - /// Return a cloned rpc (ws) client, suitable for being moved to threads. - fn rpc_client_cloned(&self) -> Arc { + /// Return a cloned rpc (http) client, suitable for being moved to threads. + fn rpc_client_cloned(&self) -> Arc { self.transport .as_client_cloned() - .expect("ws client must have been initialized by now; qed.") + .expect("http client must have been initialized by now; qed.") } fn at_expected(&self) -> B::Hash { @@ -211,7 +227,7 @@ impl OnlineConfig { impl Default for OnlineConfig { fn default() -> Self { Self { - transport: Transport::from(DEFAULT_WS_ENDPOINT.to_owned()), + transport: Transport::from(DEFAULT_HTTP_ENDPOINT.to_owned()), child_trie: true, at: None, state_snapshot: None, @@ -307,10 +323,16 @@ where B::Hash: DeserializeOwned, B::Header: DeserializeOwned, { + const BATCH_SIZE_INCREASE_FACTOR: f32 = 1.10; + const BATCH_SIZE_DECREASE_FACTOR: f32 = 0.50; + const INITIAL_BATCH_SIZE: usize = 5000; + // NOTE: increasing this value does not seem to impact speed all that much. + const DEFAULT_KEY_DOWNLOAD_PAGE: u32 = 1000; + /// Get the number of threads to use. fn threads() -> NonZeroUsize { thread::available_parallelism() - .unwrap_or(NonZeroUsize::new(4usize).expect("4 is non-zero; qed")) + .unwrap_or(NonZeroUsize::new(1usize).expect("4 is non-zero; qed")) } async fn rpc_get_storage( @@ -352,7 +374,7 @@ where .rpc_client() .storage_keys_paged( Some(prefix.clone()), - DEFAULT_KEY_DOWNLOAD_PAGE, + Self::DEFAULT_KEY_DOWNLOAD_PAGE, last_key.clone(), Some(at), ) @@ -365,7 +387,7 @@ where all_keys.extend(page); - if page_len < DEFAULT_KEY_DOWNLOAD_PAGE as usize { + if page_len < Self::DEFAULT_KEY_DOWNLOAD_PAGE as usize { log::debug!(target: LOG_TARGET, "last page received: {}", page_len); break all_keys } else { @@ -384,6 +406,123 @@ where Ok(keys) } + /// Fetches storage data from a node using a dynamic batch size. + /// + /// This function adjusts the batch size on the fly to help prevent overwhelming the node with + /// large batch requests, and stay within request size limits enforced by the node. + /// + /// # Arguments + /// + /// * `client` - An `Arc` wrapped `HttpClient` used for making the requests. + /// * `payloads` - A vector of tuples containing a JSONRPC method name and `ArrayParams` + /// * `batch_size` - The initial batch size to use for the request. The batch size will be + /// adjusted dynamically in case of failure. + /// + /// # Returns + /// + /// Returns a `Result` with a vector of `Option`, where each element corresponds to + /// the storage data for the given method and parameters. The result will be an `Err` with a + /// `String` error message if the request fails. + /// + /// # Errors + /// + /// This function will return an error if: + /// * The batch request fails and the batch size is less than 2. + /// * There are invalid batch params. + /// * There is an error in the batch response. + /// + /// # Example + /// + /// ```ignore + /// use your_crate::{get_storage_data_dynamic_batch_size, HttpClient, ArrayParams}; + /// use std::sync::Arc; + /// + /// async fn example() { + /// let client = Arc::new(HttpClient::new()); + /// let payloads = vec![ + /// ("some_method".to_string(), ArrayParams::new(vec![])), + /// ("another_method".to_string(), ArrayParams::new(vec![])), + /// ]; + /// let initial_batch_size = 10; + /// + /// let storage_data = get_storage_data_dynamic_batch_size(client, payloads, batch_size).await; + /// match storage_data { + /// Ok(data) => println!("Storage data: {:?}", data), + /// Err(e) => eprintln!("Error fetching storage data: {}", e), + /// } + /// } + /// ``` + #[async_recursion] + async fn get_storage_data_dynamic_batch_size( + client: &Arc, + payloads: Vec<(String, ArrayParams)>, + batch_size: usize, + ) -> Result>, String> { + // All payloads have been processed + if payloads.is_empty() { + return Ok(vec![]) + }; + + log::debug!( + target: LOG_TARGET, + "Remaining payloads: {} Batch request size: {}", + payloads.len(), + batch_size, + ); + + // Payloads to attempt to process this batch + let page = payloads.iter().take(batch_size).cloned().collect::>(); + + // Build the batch request + let mut batch = BatchRequestBuilder::new(); + for (method, params) in page.iter() { + batch + .insert(method, params.clone()) + .map_err(|_| "Invalid batch method and/or params")? + } + let batch_response = match client.batch_request::>(batch).await { + Ok(batch_response) => batch_response, + Err(e) => { + if batch_size < 2 { + return Err(e.to_string()) + } + + log::debug!( + target: LOG_TARGET, + "Batch request failed, trying again with smaller batch size. {}", + e.to_string() + ); + + return Self::get_storage_data_dynamic_batch_size( + client, + payloads, + max(1, (batch_size as f32 * Self::BATCH_SIZE_DECREASE_FACTOR) as usize), + ) + .await + }, + }; + + // Collect the data from this batch + let mut data: Vec> = vec![]; + for item in batch_response.into_iter() { + match item { + Ok(x) => data.push(x), + Err(e) => return Err(e.message().to_string()), + } + } + + // Return this data joined with the remaining keys + let payloads = payloads.iter().skip(batch_size).cloned().collect::>(); + let mut rest = Self::get_storage_data_dynamic_batch_size( + client, + payloads, + max(batch_size + 1, (batch_size as f32 * Self::BATCH_SIZE_INCREASE_FACTOR) as usize), + ) + .await?; + data.append(&mut rest); + Ok(data) + } + /// Synonym of `getPairs` that uses paged queries to first get the keys, and then /// map them to values one by one. /// @@ -428,81 +567,61 @@ where let (tx, mut rx) = mpsc::unbounded::(); for thread_keys in keys_chunked { - let thread_client = client.clone(); let thread_sender = tx.clone(); + let thread_client = client.clone(); let handle = std::thread::spawn(move || { - let rt = tokio::runtime::Runtime::new().unwrap(); - let mut thread_key_values = Vec::with_capacity(thread_keys.len()); - - for chunk_keys in thread_keys.chunks(DEFAULT_VALUE_DOWNLOAD_BATCH) { - let mut batch = BatchRequestBuilder::new(); - - for key in chunk_keys.iter() { - batch - .insert("state_getStorage", rpc_params![key, at]) - .map_err(|_| "Invalid batch params") - .unwrap(); - } - - let batch_response = rt - .block_on(thread_client.batch_request::>(batch)) - .map_err(|e| { - log::error!( - target: LOG_TARGET, - "failed to execute batch: {:?}. Error: {:?}", - chunk_keys.iter().map(HexDisplay::from).collect::>(), - e - ); - "batch failed." - }) - .unwrap(); + // Process the payloads in chunks so each thread can pass kvs back to the main + // thread to start inserting before all of the data has been queried from the node. + // Inserting data takes a very long time, so the earlier it can start the better. + let mut thread_key_values = vec![]; + let chunk_size = thread_keys.len() / 1; + for thread_keys_chunk in thread_keys.chunks(chunk_size) { + let mut thread_key_chunk_values = Vec::with_capacity(thread_keys_chunk.len()); + + let payloads = thread_keys_chunk + .iter() + .map(|key| ("state_getStorage".to_string(), rpc_params!(key, at))) + .collect::>(); + + let rt = tokio::runtime::Runtime::new().unwrap(); + let storage_data = match rt.block_on(Self::get_storage_data_dynamic_batch_size( + &thread_client, + payloads, + Self::INITIAL_BATCH_SIZE, + )) { + Ok(storage_data) => storage_data, + Err(e) => { + thread_sender.unbounded_send(Message::BatchFailed(e)).unwrap(); + return Default::default() + }, + }; // Check if we got responses for all submitted requests. - assert_eq!(chunk_keys.len(), batch_response.len()); + assert_eq!(thread_keys_chunk.len(), storage_data.len()); - let mut batch_kv = Vec::with_capacity(chunk_keys.len()); - for (key, maybe_value) in chunk_keys.into_iter().zip(batch_response) { + let mut batch_kv = Vec::with_capacity(thread_keys_chunk.len()); + for (key, maybe_value) in thread_keys_chunk.iter().zip(storage_data) { match maybe_value { - Ok(Some(data)) => { - thread_key_values.push((key.clone(), data.clone())); + Some(data) => { + thread_key_chunk_values.push((key.clone(), data.clone())); batch_kv.push((key.clone().0, data.0)); }, - Ok(None) => { + None => { log::warn!( target: LOG_TARGET, "key {:?} had none corresponding value.", &key ); let data = StorageData(vec![]); - thread_key_values.push((key.clone(), data.clone())); + thread_key_chunk_values.push((key.clone(), data.clone())); batch_kv.push((key.clone().0, data.0)); }, - Err(e) => { - let reason = format!("key {:?} failed: {:?}", &key, e); - log::error!(target: LOG_TARGET, "Reason: {}", reason); - // Signal failures to the main thread, stop aggregating (key, value) - // pairs and return immediately an error. - thread_sender.unbounded_send(Message::BatchFailed(reason)).unwrap(); - return Default::default() - }, }; - - if thread_key_values.len() % (thread_keys.len() / 10).max(1) == 0 { - let ratio: f64 = - thread_key_values.len() as f64 / thread_keys.len() as f64; - log::debug!( - target: LOG_TARGET, - "[thread = {:?}] progress = {:.2} [{} / {}]", - std::thread::current().id(), - ratio, - thread_key_values.len(), - thread_keys.len(), - ); - } } - // Send this batch to the main thread to start inserting. + // Send this chunk to the main thread to start inserting. thread_sender.unbounded_send(Message::Batch(batch_kv)).unwrap(); + thread_key_values.extend(thread_key_chunk_values); } thread_sender.unbounded_send(Message::Terminated).unwrap(); @@ -516,10 +635,21 @@ where // `pending_ext`. let mut terminated = 0usize; let mut batch_failed = false; + let mut processed = 0usize; loop { match rx.next().await.unwrap() { Message::Batch(kv) => { for (k, v) in kv { + processed += 1; + if processed % 50_000 == 0 || processed == keys.len() || processed == 1 { + log::info!( + target: LOG_TARGET, + "inserting keys progress = {:.0}% [{} / {}]", + (processed as f32 / keys.len() as f32) * 100f32, + processed, + keys.len(), + ); + } // skip writing the child root data. if is_default_child_storage_key(k.as_ref()) { continue @@ -554,73 +684,58 @@ where /// Get the values corresponding to `child_keys` at the given `prefixed_top_key`. pub(crate) async fn rpc_child_get_storage_paged( - client: &WsClient, + client: &Arc, prefixed_top_key: &StorageKey, child_keys: Vec, 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(DEFAULT_VALUE_DOWNLOAD_BATCH) { - 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()), - key, - at - ], - ) - .map_err(|_| "Invalid batch params")?; - } + let child_keys_len = child_keys.len(); - let batch_response = - 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." - })?; + let payloads = child_keys + .iter() + .map(|key| { + ( + "childstate_getStorage".to_string(), + rpc_params![ + PrefixedStorageKey::new(prefixed_top_key.as_ref().to_vec()), + key, + at + ], + ) + }) + .collect::>(); - assert_eq!(batch_child_key.len(), batch_response.len()); - - 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; - }, - }; - } - } + let storage_data = match Self::get_storage_data_dynamic_batch_size( + client, + payloads, + Self::INITIAL_BATCH_SIZE, + ) + .await + { + Ok(storage_data) => storage_data, + Err(e) => { + log::error!(target: LOG_TARGET, "batch processing failed: {:?}", e); + return Err("batch processing failed") + }, + }; - if batch_success { - Ok(child_kv_inner) - } else { - Err("batch failed.") - } + assert_eq!(child_keys_len, storage_data.len()); + + Ok(child_keys + .iter() + .zip(storage_data) + .map(|(key, maybe_value)| match maybe_value { + Some(v) => (key.clone(), v), + None => { + log::warn!(target: LOG_TARGET, "key {:?} had no corresponding value.", &key); + (key.clone(), StorageData(vec![])) + }, + }) + .collect::>()) } pub(crate) async fn rpc_child_get_keys( - client: &WsClient, + client: &HttpClient, prefixed_top_key: &StorageKey, child_prefix: StorageKey, at: B::Hash, @@ -678,107 +793,47 @@ where return Ok(Default::default()) } - // div-ceil simulation. - let threads = Self::threads().get(); - let child_roots_per_thread = (child_roots.len() + threads - 1) / threads; - info!( target: LOG_TARGET, - "👩‍👦 scraping child-tree data from {} top keys, split among {} threads, {} top keys per thread", + "👩‍👦 scraping child-tree data from {} top keys", child_roots.len(), - threads, - child_roots_per_thread, ); - // NOTE: the threading done here is the simpler, yet slightly un-elegant because we are - // splitting child root among threads, and it is very common for these root to have vastly - // different child tries underneath them, causing some threads to finish way faster than - // others. Certainly still better than single thread though. - let mut handles = vec![]; - let client = self.as_online().rpc_client_cloned(); let at = self.as_online().at_expected(); - enum Message { - Terminated, - Batch((ChildInfo, Vec<(Vec, Vec)>)), - } - let (tx, mut rx) = mpsc::unbounded::(); - - for thread_child_roots in child_roots - .chunks(child_roots_per_thread) - .map(|x| x.into()) - .collect::>>() - { - let thread_client = client.clone(); - let thread_sender = tx.clone(); - let handle = thread::spawn(move || { - let rt = tokio::runtime::Runtime::new().unwrap(); - let mut thread_child_kv = vec![]; - for prefixed_top_key in thread_child_roots { - let child_keys = rt.block_on(Self::rpc_child_get_keys( - &thread_client, - &prefixed_top_key, - StorageKey(vec![]), - at, - ))?; - let child_kv_inner = rt.block_on(Self::rpc_child_get_storage_paged( - &thread_client, - &prefixed_top_key, - child_keys, - at, - ))?; - - 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") - }, - }; - - thread_sender - .unbounded_send(Message::Batch(( - ChildInfo::new_default(un_prefixed), - child_kv_inner - .iter() - .cloned() - .map(|(k, v)| (k.0, v.0)) - .collect::>(), - ))) - .unwrap(); - thread_child_kv.push((ChildInfo::new_default(un_prefixed), child_kv_inner)); - } - - thread_sender.unbounded_send(Message::Terminated).unwrap(); - Ok(thread_child_kv) - }); - handles.push(handle); - } - - // first, wait until all threads send a `Terminated` message, in the meantime populate - // `pending_ext`. - let mut terminated = 0usize; - loop { - match rx.next().await.unwrap() { - Message::Batch((info, kvs)) => - for (k, v) in kvs { - pending_ext.insert_child(info.clone(), k, v); - }, - Message::Terminated => { - terminated += 1; - if terminated == handles.len() { - break - } + let arc_client = self.as_online().rpc_client_cloned(); + let mut child_kv = vec![]; + for prefixed_top_key in child_roots { + let child_keys = Self::rpc_child_get_keys( + arc_client.as_ref(), + &prefixed_top_key, + StorageKey(vec![]), + at, + ) + .await?; + + let child_kv_inner = + Self::rpc_child_get_storage_paged(&arc_client, &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") }, + }; + + let info = ChildInfo::new_default(un_prefixed); + let key_values = + child_kv_inner.iter().cloned().map(|(k, v)| (k.0, v.0)).collect::>(); + child_kv.push((info.clone(), child_kv_inner)); + for (k, v) in key_values { + pending_ext.insert_child(info.clone(), k, v); } } - let child_kv = handles - .into_iter() - .flat_map(|h| h.join().unwrap()) - .flatten() - .collect::>(); Ok(child_kv) } @@ -841,8 +896,8 @@ where /// /// initializes the remote client in `transport`, and sets the `at` field, if not specified. async fn init_remote_client(&mut self) -> Result<(), &'static str> { - // First, initialize the ws client. - self.as_online_mut().transport.map_uri().await?; + // First, initialize the http client. + self.as_online_mut().transport.init().await?; // Then, if `at` is not set, set it. if self.as_online().at.is_none() { diff --git a/utils/frame/try-runtime/cli/src/lib.rs b/utils/frame/try-runtime/cli/src/lib.rs index cd6c48f52f45e..9268ef2edba8b 100644 --- a/utils/frame/try-runtime/cli/src/lib.rs +++ b/utils/frame/try-runtime/cli/src/lib.rs @@ -97,18 +97,6 @@ //! > If anything, in most cases, we expect spec-versions to NOT match, because try-runtime is all //! > about testing unreleased runtimes. //! -//! ## Note on nodes that respond to `try-runtime` requests. -//! -//! 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-response-size 1000` and -//! - `--rpc-max-request-size 1000` to ensure connections are not dropped in case the state is -//! large. -//! - set `--rpc-cors all` to ensure ws connections can come through. -//! -//! Note that *none* of the try-runtime operations need unsafe RPCs. -//! //! ## Note on signature and state-root checks //! //! All of the commands calling into `TryRuntime_execute_block` ([`Command::ExecuteBlock`] and From 471b49b09fd0d2a3057090ab0720f4e39faed5c5 Mon Sep 17 00:00:00 2001 From: Harald Heckmann Date: Fri, 21 Apr 2023 12:06:26 +0200 Subject: [PATCH 681/715] Add Freeze/Thaw events and tests (#13779) * Add Freeze/Thaw events and tests * Remove duplicate docstring * Correct spelling error * Cargo fmt * Use proper punctuation in docstring Co-authored-by: Jegor Sidorenko <5252494+jsidorenko@users.noreply.github.com> --------- Co-authored-by: Jegor Sidorenko <5252494+jsidorenko@users.noreply.github.com> Co-authored-by: parity-processbot <> --- frame/balances/src/lib.rs | 15 +++++++ frame/balances/src/tests/fungible_tests.rs | 46 ++++++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index 74aec1f2d259b..6835d3c8148bb 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -337,6 +337,10 @@ pub mod pallet { Locked { who: T::AccountId, amount: T::Balance }, /// Some balance was unlocked. Unlocked { who: T::AccountId, amount: T::Balance }, + /// Some balance was frozen. + Frozen { who: T::AccountId, amount: T::Balance }, + /// Some balance was thawed. + Thawed { who: T::AccountId, amount: T::Balance }, } #[pallet::error] @@ -1084,7 +1088,10 @@ pub mod pallet { who: &T::AccountId, freezes: BoundedSlice, T::MaxFreezes>, ) -> DispatchResult { + let mut prev_frozen = Zero::zero(); + let mut after_frozen = Zero::zero(); let (_, maybe_dust) = Self::mutate_account(who, |b| { + prev_frozen = b.frozen; b.frozen = Zero::zero(); for l in Locks::::get(who).iter() { b.frozen = b.frozen.max(l.amount); @@ -1092,6 +1099,7 @@ pub mod pallet { for l in freezes.iter() { b.frozen = b.frozen.max(l.amount); } + after_frozen = b.frozen; })?; debug_assert!(maybe_dust.is_none(), "Not altering main balance; qed"); if freezes.is_empty() { @@ -1099,6 +1107,13 @@ pub mod pallet { } else { Freezes::::insert(who, freezes); } + if prev_frozen > after_frozen { + let amount = prev_frozen.saturating_sub(after_frozen); + Self::deposit_event(Event::Thawed { who: who.clone(), amount }); + } else if after_frozen > prev_frozen { + let amount = after_frozen.saturating_sub(prev_frozen); + Self::deposit_event(Event::Frozen { who: who.clone(), amount }); + } Ok(()) } diff --git a/frame/balances/src/tests/fungible_tests.rs b/frame/balances/src/tests/fungible_tests.rs index 128086885391f..185396019b13d 100644 --- a/frame/balances/src/tests/fungible_tests.rs +++ b/frame/balances/src/tests/fungible_tests.rs @@ -397,3 +397,49 @@ fn unholding_frees_hold_slot() { assert_ok!(Balances::hold(&TestId::Baz, &1, 10)); }); } + +#[test] +fn emit_events_with_changing_freezes() { + ExtBuilder::default().build_and_execute_with(|| { + let _ = Balances::set_balance(&1, 100); + System::reset_events(); + + // Freeze = [] --> [10] + assert_ok!(Balances::set_freeze(&TestId::Foo, &1, 10)); + assert_eq!(events(), [RuntimeEvent::Balances(crate::Event::Frozen { who: 1, amount: 10 })]); + + // Freeze = [10] --> [15] + assert_ok!(Balances::set_freeze(&TestId::Foo, &1, 15)); + assert_eq!(events(), [RuntimeEvent::Balances(crate::Event::Frozen { who: 1, amount: 5 })]); + + // Freeze = [15] --> [15, 20] + assert_ok!(Balances::set_freeze(&TestId::Bar, &1, 20)); + assert_eq!(events(), [RuntimeEvent::Balances(crate::Event::Frozen { who: 1, amount: 5 })]); + + // Freeze = [15, 20] --> [17, 20] + assert_ok!(Balances::set_freeze(&TestId::Foo, &1, 17)); + for event in events() { + match event { + RuntimeEvent::Balances(crate::Event::Frozen { .. }) => { + assert!(false, "unexpected freeze event") + }, + RuntimeEvent::Balances(crate::Event::Thawed { .. }) => { + assert!(false, "unexpected thaw event") + }, + _ => continue, + } + } + + // Freeze = [17, 20] --> [17, 15] + assert_ok!(Balances::set_freeze(&TestId::Bar, &1, 15)); + assert_eq!(events(), [RuntimeEvent::Balances(crate::Event::Thawed { who: 1, amount: 3 })]); + + // Freeze = [17, 15] --> [15] + assert_ok!(Balances::thaw(&TestId::Foo, &1)); + assert_eq!(events(), [RuntimeEvent::Balances(crate::Event::Thawed { who: 1, amount: 2 })]); + + // Freeze = [15] --> [] + assert_ok!(Balances::thaw(&TestId::Bar, &1)); + assert_eq!(events(), [RuntimeEvent::Balances(crate::Event::Thawed { who: 1, amount: 15 })]); + }); +} From 35d04fb506b00128739b5bead363f0ca651a4ff3 Mon Sep 17 00:00:00 2001 From: PG Herveou Date: Fri, 21 Apr 2023 17:24:12 +0200 Subject: [PATCH 682/715] Update macro use and optimize storage collection (#13970) --- frame/contracts/src/lib.rs | 3 +-- frame/contracts/src/storage/meter.rs | 2 +- frame/contracts/src/tests.rs | 26 +++++++++++++------------- 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index 26b16b3291a2f..fa230a8cade14 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -83,11 +83,10 @@ #![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(feature = "runtime-benchmarks", recursion_limit = "1024")] -#[macro_use] -mod gas; mod address; mod benchmarking; mod exec; +mod gas; mod migration; mod schedule; mod storage; diff --git a/frame/contracts/src/storage/meter.rs b/frame/contracts/src/storage/meter.rs index ef3e01f6d6c4f..497ee03ac319a 100644 --- a/frame/contracts/src/storage/meter.rs +++ b/frame/contracts/src/storage/meter.rs @@ -293,8 +293,8 @@ where .total_deposit .saturating_add(&absorbed.total_deposit) .saturating_add(&own_deposit); + self.charges.extend_from_slice(&absorbed.charges); if !own_deposit.is_zero() { - self.charges.extend_from_slice(&absorbed.charges); self.charges.push(Charge { deposit_account, amount: own_deposit, diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index ac1fb07bf5ce0..4e6c468f19c81 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -73,7 +73,19 @@ frame_support::construct_runtime!( } ); -#[macro_use] +macro_rules! assert_return_code { + ( $x:expr , $y:expr $(,)? ) => {{ + 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(); + assert_eq!(is, $should); + }}; +} + pub mod test_utils { use super::{Balances, Hash, SysConfig, Test}; use crate::{exec::AccountIdOf, CodeHash, Config, ContractInfo, ContractInfoOf, Nonce}; @@ -105,18 +117,6 @@ pub mod test_utils { 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); - }}; - } - - macro_rules! assert_refcount { - ( $code_hash:expr , $should:expr $(,)? ) => {{ - let is = crate::OwnerInfoOf::::get($code_hash).map(|m| m.refcount()).unwrap(); - assert_eq!(is, $should); - }}; - } } impl Test { From 2fde3802da6256b5846ce33760685ca40008d00d Mon Sep 17 00:00:00 2001 From: ordian Date: Fri, 21 Apr 2023 21:58:05 +0200 Subject: [PATCH 683/715] cargo upgrade --workspace kvdb-rocksdb (#13973) --- Cargo.lock | 12 ++++++------ bin/node/bench/Cargo.toml | 2 +- client/db/Cargo.toml | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b316993185862..aa7d22daccb80 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3776,9 +3776,9 @@ dependencies = [ [[package]] name = "kvdb-rocksdb" -version = "0.17.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2182b8219fee6bd83aacaab7344e840179ae079d5216aa4e249b4d704646a844" +checksum = "fe7a749456510c45f795e8b04a6a3e0976d0139213ecbf465843830ad55e2217" dependencies = [ "kvdb", "num_cpus", @@ -4311,9 +4311,9 @@ dependencies = [ [[package]] name = "librocksdb-sys" -version = "0.8.3+7.4.4" +version = "0.10.0+7.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "557b255ff04123fcc176162f56ed0c9cd42d8f357cf55b3fabeb60f7413741b3" +checksum = "0fe4d5874f5ff2bc616e55e8c6086d478fcda13faf9495768a4aa1c22042d30b" dependencies = [ "bindgen", "bzip2-sys", @@ -8097,9 +8097,9 @@ dependencies = [ [[package]] name = "rocksdb" -version = "0.19.0" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e9562ea1d70c0cc63a34a22d977753b50cca91cc6b6527750463bd5dd8697bc" +checksum = "015439787fce1e75d55f279078d33ff14b4af5d93d995e8838ee4631301c8a99" dependencies = [ "libc", "librocksdb-sys", diff --git a/bin/node/bench/Cargo.toml b/bin/node/bench/Cargo.toml index 153a721da41f8..30266ab0d24e7 100644 --- a/bin/node/bench/Cargo.toml +++ b/bin/node/bench/Cargo.toml @@ -25,7 +25,7 @@ serde = "1.0.136" serde_json = "1.0.85" derive_more = { version = "0.99.17", default-features = false, features = ["display"] } kvdb = "0.13.0" -kvdb-rocksdb = "0.17.0" +kvdb-rocksdb = "0.18.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" } diff --git a/client/db/Cargo.toml b/client/db/Cargo.toml index 8e4bcf18a2d04..cd3a73dd4dab4 100644 --- a/client/db/Cargo.toml +++ b/client/db/Cargo.toml @@ -19,7 +19,7 @@ codec = { package = "parity-scale-codec", version = "3.2.2", features = [ hash-db = "0.16.0" kvdb = "0.13.0" kvdb-memorydb = "0.13.0" -kvdb-rocksdb = { version = "0.17.0", optional = true } +kvdb-rocksdb = { version = "0.18.0", optional = true } linked-hash-map = "0.5.4" log = "0.4.17" parity-db = "0.4.6" @@ -37,7 +37,7 @@ sp-trie = { version = "7.0.0", path = "../../primitives/trie" } [dev-dependencies] criterion = "0.4.0" -kvdb-rocksdb = "0.17.0" +kvdb-rocksdb = "0.18.0" rand = "0.8.5" tempfile = "3.1.0" quickcheck = { version = "1.0.3", default-features = false } From c7d26dcf3d6c19fa7dcbd1f2633e337e5a5cbc40 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Fri, 21 Apr 2023 22:32:32 +0200 Subject: [PATCH 684/715] Remove superflous Pair::verify_weak (#13972) --- primitives/application-crypto/src/lib.rs | 7 ------- primitives/core/src/crypto.rs | 15 -------------- primitives/core/src/ecdsa.rs | 18 ++-------------- primitives/core/src/ed25519.rs | 26 ++++++++---------------- primitives/core/src/sr25519.rs | 18 +++++----------- 5 files changed, 15 insertions(+), 69 deletions(-) diff --git a/primitives/application-crypto/src/lib.rs b/primitives/application-crypto/src/lib.rs index 3f12e06e11ec3..5e77795199dd9 100644 --- a/primitives/application-crypto/src/lib.rs +++ b/primitives/application-crypto/src/lib.rs @@ -154,13 +154,6 @@ macro_rules! app_crypto_pair { ) -> bool { <$pair>::verify(&sig.0, message, pubkey.as_ref()) } - fn verify_weak, M: AsRef<[u8]>>( - sig: &[u8], - message: M, - pubkey: P, - ) -> bool { - <$pair>::verify_weak(sig, message, pubkey) - } fn public(&self) -> Self::Public { Public(self.0.public()) } diff --git a/primitives/core/src/crypto.rs b/primitives/core/src/crypto.rs index 4fec79fc6ea18..dd0d9e60529f2 100644 --- a/primitives/core/src/crypto.rs +++ b/primitives/core/src/crypto.rs @@ -716,10 +716,6 @@ mod dummy { true } - fn verify_weak, M: AsRef<[u8]>>(_: &[u8], _: M, _: P) -> bool { - true - } - fn public(&self) -> Self::Public { Self } @@ -917,9 +913,6 @@ pub trait Pair: CryptoType + Sized + Clone + Send + Sync + 'static { /// Verify a signature on a message. Returns true if the signature is good. fn verify>(sig: &Self::Signature, message: M, pubkey: &Self::Public) -> bool; - /// Verify a signature on a message. Returns true if the signature is good. - fn verify_weak, M: AsRef<[u8]>>(sig: &[u8], message: M, pubkey: P) -> bool; - /// Get the public key. fn public(&self) -> Self::Public; @@ -1272,14 +1265,6 @@ mod tests { true } - fn verify_weak, M: AsRef<[u8]>>( - _sig: &[u8], - _message: M, - _pubkey: P, - ) -> bool { - true - } - fn public(&self) -> Self::Public { TestPublic } diff --git a/primitives/core/src/ecdsa.rs b/primitives/core/src/ecdsa.rs index 8dc4a55130fd6..2474fa7736b78 100644 --- a/primitives/core/src/ecdsa.rs +++ b/primitives/core/src/ecdsa.rs @@ -407,22 +407,8 @@ impl TraitPair for Pair { } /// Verify a signature on a message. Returns true if the signature is good. - fn verify>(sig: &Self::Signature, message: M, pubkey: &Self::Public) -> bool { - match sig.recover(message) { - Some(actual) => actual == *pubkey, - None => false, - } - } - - /// Verify a signature on a message. Returns true if the signature is good. - /// - /// 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 { - match Signature::from_slice(sig).and_then(|sig| sig.recover(message)) { - Some(actual) => actual.as_ref() == pubkey.as_ref(), - None => false, - } + fn verify>(sig: &Self::Signature, message: M, public: &Self::Public) -> bool { + sig.recover(message).map(|actual| actual == *public).unwrap_or_default() } /// Return a vec filled with raw data. diff --git a/primitives/core/src/ed25519.rs b/primitives/core/src/ed25519.rs index 884d29dc122e9..d0e6bef97a7d9 100644 --- a/primitives/core/src/ed25519.rs +++ b/primitives/core/src/ed25519.rs @@ -406,27 +406,17 @@ impl TraitPair for Pair { Signature::from_raw(self.secret.sign(message).into()) } - /// Verify a signature on a message. Returns true if the signature is good. - fn verify>(sig: &Self::Signature, message: M, pubkey: &Self::Public) -> bool { - Self::verify_weak(&sig.0[..], message.as_ref(), pubkey) - } - - /// Verify a signature on a message. Returns true if the signature is good. + /// Verify a signature on a message. /// - /// 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 VerificationKey::try_from(pubkey.as_ref()) { - Ok(pk) => pk, - Err(_) => return false, + /// Returns true if the signature is good. + fn verify>(sig: &Self::Signature, message: M, public: &Self::Public) -> bool { + let Ok(public) = VerificationKey::try_from(public.as_slice()) else { + return false }; - - let sig = match ed25519_zebra::Signature::try_from(sig) { - Ok(s) => s, - Err(_) => return false, + let Ok(signature) = ed25519_zebra::Signature::try_from(sig.as_ref()) else { + return false }; - - public_key.verify(&sig, message.as_ref()).is_ok() + public.verify(&signature, message.as_ref()).is_ok() } /// Return a vec filled with raw data. diff --git a/primitives/core/src/sr25519.rs b/primitives/core/src/sr25519.rs index fcd7f38a74f1f..9b1c82205de10 100644 --- a/primitives/core/src/sr25519.rs +++ b/primitives/core/src/sr25519.rs @@ -487,21 +487,13 @@ impl TraitPair for Pair { } fn verify>(sig: &Self::Signature, message: M, pubkey: &Self::Public) -> bool { - Self::verify_weak(&sig.0[..], message, pubkey) - } - - fn verify_weak, M: AsRef<[u8]>>(sig: &[u8], message: M, pubkey: P) -> bool { - let signature = match schnorrkel::Signature::from_bytes(sig) { - Ok(signature) => signature, - Err(_) => return false, + let Ok(signature) = schnorrkel::Signature::from_bytes(sig.as_ref()) else { + return false }; - - let pub_key = match PublicKey::from_bytes(pubkey.as_ref()) { - Ok(pub_key) => pub_key, - Err(_) => return false, + let Ok(public) = PublicKey::from_bytes(pubkey.as_ref()) else { + return false }; - - pub_key.verify_simple(SIGNING_CTX, message.as_ref(), &signature).is_ok() + public.verify_simple(SIGNING_CTX, message.as_ref(), &signature).is_ok() } fn to_raw_vec(&self) -> Vec { From 9370f42ab35f7013f70b703884c9884888a3b153 Mon Sep 17 00:00:00 2001 From: gupnik <17176722+gupnik@users.noreply.github.com> Date: Mon, 24 Apr 2023 17:34:15 +0530 Subject: [PATCH 685/715] Adds force_origin support (#13845) * Adds force_origin support * Moves a couple of tests to showcase v2 with force_origin * Adds remaining tests * adds documentation * minor * adds test for invalid origin * ".git/.scripts/commands/fmt/fmt.sh" * updates param to use MaxCalls * Fixes compilation error * Updates doc comment * Fixes test outputs * Fixes test output * ".git/.scripts/commands/fmt/fmt.sh" --------- Co-authored-by: command-bot <> --- frame/benchmarking/src/lib.rs | 7 + frame/lottery/src/benchmarking.rs | 127 ++++++++++++------ frame/support/procedural/src/benchmark.rs | 35 +++-- .../test/tests/benchmark_ui/invalid_origin.rs | 17 +++ .../tests/benchmark_ui/invalid_origin.stderr | 16 +++ 5 files changed, 141 insertions(+), 61 deletions(-) create mode 100644 frame/support/test/tests/benchmark_ui/invalid_origin.rs create mode 100644 frame/support/test/tests/benchmark_ui/invalid_origin.stderr diff --git a/frame/benchmarking/src/lib.rs b/frame/benchmarking/src/lib.rs index 7110c378d581e..b11e164fe8e44 100644 --- a/frame/benchmarking/src/lib.rs +++ b/frame/benchmarking/src/lib.rs @@ -160,6 +160,13 @@ pub use v1::*; /// The underscore will be substituted with the name of the benchmark (i.e. the name of the /// function in the benchmark function definition). /// +/// In case of a `force_origin` where you want to elevate the privileges of the provided origin, +/// this is the general syntax: +/// ```ignore +/// #[extrinsic_call] +/// _(force_origin as T::RuntimeOrigin, 0u32.into(), 0); +/// ``` +/// /// Regardless of whether `#[extrinsic_call]` or `#[block]` is used, this attribute also serves /// the purpose of designating the boundary between the setup code portion of the benchmark /// (everything before the `#[extrinsic_call]` or `#[block]` attribute) and the verification diff --git a/frame/lottery/src/benchmarking.rs b/frame/lottery/src/benchmarking.rs index 9216464b07d35..1510d250dbeaf 100644 --- a/frame/lottery/src/benchmarking.rs +++ b/frame/lottery/src/benchmarking.rs @@ -21,7 +21,12 @@ use super::*; -use frame_benchmarking::v1::{account, benchmarks, whitelisted_caller, BenchmarkError}; +use crate::Pallet as Lottery; +use frame_benchmarking::{ + impl_benchmark_test_suite, + v1::{account, whitelisted_caller, BenchmarkError}, + v2::*, +}; use frame_support::{ storage::bounded_vec::BoundedVec, traits::{EnsureOrigin, OnInitialize}, @@ -29,8 +34,6 @@ use frame_support::{ use frame_system::RawOrigin; use sp_runtime::traits::{Bounded, Zero}; -use crate::Pallet as Lottery; - // Set up and start a lottery fn setup_lottery(repeat: bool) -> Result<(), &'static str> { let price = T::Currency::minimum_balance(); @@ -50,72 +53,100 @@ fn setup_lottery(repeat: bool) -> Result<(), &'static str> { Ok(()) } -benchmarks! { - buy_ticket { +#[benchmarks] +mod benchmarks { + use super::*; + + #[benchmark] + fn buy_ticket() -> Result<(), BenchmarkError> { let caller = whitelisted_caller(); T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); setup_lottery::(false)?; // force user to have a long vec of calls participating let set_code_index: CallIndex = Lottery::::call_to_index( - &frame_system::Call::::set_code{ code: vec![] }.into() + &frame_system::Call::::set_code { code: vec![] }.into(), )?; let already_called: (u32, BoundedVec) = ( LotteryIndex::::get(), BoundedVec::::try_from(vec![ set_code_index; - T::MaxCalls::get().saturating_sub(1) as usize - ]).unwrap(), + T::MaxCalls::get().saturating_sub(1) + as usize + ]) + .unwrap(), ); Participants::::insert(&caller, already_called); let call = frame_system::Call::::remark { remark: vec![] }; - }: _(RawOrigin::Signed(caller), Box::new(call.into())) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(caller), Box::new(call.into())); + assert_eq!(TicketsCount::::get(), 1); + + Ok(()) } - set_calls { - let n in 0 .. T::MaxCalls::get() as u32; + #[benchmark] + fn set_calls(n: Linear<0, { T::MaxCalls::get() }>) -> Result<(), BenchmarkError> { let calls = vec![frame_system::Call::::remark { remark: vec![] }.into(); n as usize]; let origin = T::ManagerOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; assert!(CallIndices::::get().is_empty()); - }: _(origin, calls) - verify { + + #[extrinsic_call] + _(origin as T::RuntimeOrigin, calls); + if !n.is_zero() { assert!(!CallIndices::::get().is_empty()); } + + Ok(()) } - start_lottery { + #[benchmark] + fn start_lottery() -> Result<(), BenchmarkError> { let price = BalanceOf::::max_value(); let end = 10u32.into(); let payout = 5u32.into(); let origin = T::ManagerOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; - }: _(origin, price, end, payout, true) - verify { + + #[extrinsic_call] + _(origin as T::RuntimeOrigin, price, end, payout, true); + assert!(crate::Lottery::::get().is_some()); + + Ok(()) } - stop_repeat { + #[benchmark] + fn stop_repeat() -> Result<(), BenchmarkError> { setup_lottery::(true)?; assert_eq!(crate::Lottery::::get().unwrap().repeat, true); let origin = T::ManagerOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; - }: _(origin) - verify { + + #[extrinsic_call] + _(origin as T::RuntimeOrigin); + assert_eq!(crate::Lottery::::get().unwrap().repeat, false); + + Ok(()) } - on_initialize_end { + #[benchmark] + fn on_initialize_end() -> Result<(), BenchmarkError> { setup_lottery::(false)?; let winner = account("winner", 0, 0); // User needs more than min balance to get ticket T::Currency::make_free_balance_be(&winner, T::Currency::minimum_balance() * 10u32.into()); // Make sure lottery account has at least min balance too let lottery_account = Lottery::::account_id(); - T::Currency::make_free_balance_be(&lottery_account, T::Currency::minimum_balance() * 10u32.into()); + T::Currency::make_free_balance_be( + &lottery_account, + T::Currency::minimum_balance() * 10u32.into(), + ); // Buy a ticket let call = frame_system::Call::::remark { remark: vec![] }; Lottery::::buy_ticket(RawOrigin::Signed(winner.clone()).into(), Box::new(call.into()))?; @@ -124,29 +155,37 @@ benchmarks! { // Assert that lotto is set up for winner assert_eq!(TicketsCount::::get(), 1); assert!(!Lottery::::pot().1.is_zero()); - }: { - // Generate `MaxGenerateRandom` numbers for worst case scenario - for i in 0 .. T::MaxGenerateRandom::get() { - Lottery::::generate_random_number(i); + + #[block] + { + // Generate `MaxGenerateRandom` numbers for worst case scenario + for i in 0..T::MaxGenerateRandom::get() { + Lottery::::generate_random_number(i); + } + // Start lottery has block 15 configured for payout + Lottery::::on_initialize(15u32.into()); } - // Start lottery has block 15 configured for payout - Lottery::::on_initialize(15u32.into()); - } - verify { + assert!(crate::Lottery::::get().is_none()); assert_eq!(TicketsCount::::get(), 0); assert_eq!(Lottery::::pot().1, 0u32.into()); - assert!(!T::Currency::free_balance(&winner).is_zero()) + assert!(!T::Currency::free_balance(&winner).is_zero()); + + Ok(()) } - on_initialize_repeat { + #[benchmark] + fn on_initialize_repeat() -> Result<(), BenchmarkError> { setup_lottery::(true)?; let winner = account("winner", 0, 0); // User needs more than min balance to get ticket T::Currency::make_free_balance_be(&winner, T::Currency::minimum_balance() * 10u32.into()); // Make sure lottery account has at least min balance too let lottery_account = Lottery::::account_id(); - T::Currency::make_free_balance_be(&lottery_account, T::Currency::minimum_balance() * 10u32.into()); + T::Currency::make_free_balance_be( + &lottery_account, + T::Currency::minimum_balance() * 10u32.into(), + ); // Buy a ticket let call = frame_system::Call::::remark { remark: vec![] }; Lottery::::buy_ticket(RawOrigin::Signed(winner.clone()).into(), Box::new(call.into()))?; @@ -155,20 +194,24 @@ benchmarks! { // Assert that lotto is set up for winner assert_eq!(TicketsCount::::get(), 1); assert!(!Lottery::::pot().1.is_zero()); - }: { - // Generate `MaxGenerateRandom` numbers for worst case scenario - for i in 0 .. T::MaxGenerateRandom::get() { - Lottery::::generate_random_number(i); + + #[block] + { + // Generate `MaxGenerateRandom` numbers for worst case scenario + for i in 0..T::MaxGenerateRandom::get() { + Lottery::::generate_random_number(i); + } + // Start lottery has block 15 configured for payout + Lottery::::on_initialize(15u32.into()); } - // Start lottery has block 15 configured for payout - Lottery::::on_initialize(15u32.into()); - } - verify { + assert!(crate::Lottery::::get().is_some()); assert_eq!(LotteryIndex::::get(), 2); assert_eq!(TicketsCount::::get(), 0); assert_eq!(Lottery::::pot().1, 0u32.into()); - assert!(!T::Currency::free_balance(&winner).is_zero()) + assert!(!T::Currency::free_balance(&winner).is_zero()); + + Ok(()) } impl_benchmark_test_suite!(Lottery, crate::mock::new_test_ext(), crate::mock::Test); diff --git a/frame/support/procedural/src/benchmark.rs b/frame/support/procedural/src/benchmark.rs index 315a6000bc8bf..28b5aa1b983b7 100644 --- a/frame/support/procedural/src/benchmark.rs +++ b/frame/support/procedural/src/benchmark.rs @@ -53,7 +53,7 @@ mod keywords { #[derive(Clone)] struct ParamDef { name: String, - typ: Type, + _typ: Type, start: syn::GenericArgument, end: syn::GenericArgument, } @@ -229,7 +229,7 @@ fn parse_params(item_fn: &ItemFn) -> Result> { let args = segment.arguments.to_token_stream().into(); let Ok(args) = syn::parse::(args) else { return invalid_param(typ.span()) }; - params.push(ParamDef { name, typ: typ.clone(), start: args.start, end: args.end }); + params.push(ParamDef { name, _typ: typ.clone(), start: args.start, end: args.end }); } Ok(params) } @@ -681,7 +681,6 @@ pub fn benchmarks( struct UnrolledParams { param_ranges: Vec, param_names: Vec, - param_types: Vec, } impl UnrolledParams { @@ -703,14 +702,7 @@ impl UnrolledParams { quote!(#name) }) .collect(); - let param_types: Vec = params - .iter() - .map(|p| { - let typ = &p.typ; - quote!(#typ) - }) - .collect(); - UnrolledParams { param_ranges, param_names, param_types } + UnrolledParams { param_ranges, param_names } } } @@ -726,7 +718,6 @@ fn expand_benchmark( Ok(ident) => ident, Err(err) => return err.to_compile_error().into(), }; - let home = quote!(#krate::v2); let codec = quote!(#krate::frame_support::codec); let traits = quote!(#krate::frame_support::traits); let setup_stmts = benchmark_def.setup_stmts; @@ -738,7 +729,6 @@ fn expand_benchmark( let unrolled = UnrolledParams::from(&benchmark_def.params); let param_names = unrolled.param_names; let param_ranges = unrolled.param_ranges; - let param_types = unrolled.param_types; let type_use_generics = match is_instance { false => quote!(T), @@ -763,6 +753,18 @@ fn expand_benchmark( } expr_call.args = final_args; + let origin = match origin { + Expr::Cast(t) => { + let ty = t.ty.clone(); + quote! { + <::RuntimeOrigin as From<#ty>>::from(#origin); + } + }, + _ => quote! { + #origin.into(); + }, + }; + // determine call name (handles `_` and normal call syntax) let expr_span = expr_call.span(); let call_err = || { @@ -803,7 +805,7 @@ fn expand_benchmark( let __call_decoded = as #codec::Decode> ::decode(&mut &__benchmarked_call_encoded[..]) .expect("call is encoded above, encoding must be correct"); - let __origin = #origin.into(); + let __origin = #origin; as #traits::UnfilteredDispatchable>::dispatch_bypass_filter( __call_decoded, __origin, @@ -877,11 +879,6 @@ fn expand_benchmark( // benchmark function definition #fn_def - // compile-time assertions that each referenced param type implements ParamRange - #( - #home::assert_impl_all!(#param_types: #home::ParamRange); - )* - #[allow(non_camel_case_types)] #( #fn_attrs diff --git a/frame/support/test/tests/benchmark_ui/invalid_origin.rs b/frame/support/test/tests/benchmark_ui/invalid_origin.rs new file mode 100644 index 0000000000000..81cfc39790969 --- /dev/null +++ b/frame/support/test/tests/benchmark_ui/invalid_origin.rs @@ -0,0 +1,17 @@ +use frame_benchmarking::v2::*; +#[allow(unused_imports)] +use frame_support_test::Config; +use frame_support_test::Call; + +#[benchmarks] +mod benches { + use super::*; + + #[benchmark] + fn bench() { + #[extrinsic_call] + thing(1); + } +} + +fn main() {} diff --git a/frame/support/test/tests/benchmark_ui/invalid_origin.stderr b/frame/support/test/tests/benchmark_ui/invalid_origin.stderr new file mode 100644 index 0000000000000..ab8499d995d47 --- /dev/null +++ b/frame/support/test/tests/benchmark_ui/invalid_origin.stderr @@ -0,0 +1,16 @@ +error[E0599]: no variant or associated item named `new_call_variant_thing` found for enum `Call` in the current scope + --> tests/benchmark_ui/invalid_origin.rs:6:1 + | +6 | #[benchmarks] + | ^^^^^^^^^^^^^ variant or associated item not found in `Call` + | + = note: this error originates in the attribute macro `benchmarks` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `::RuntimeOrigin: From<{integer}>` is not satisfied + --> tests/benchmark_ui/invalid_origin.rs:6:1 + | +6 | #[benchmarks] + | ^^^^^^^^^^^^^ the trait `From<{integer}>` is not implemented for `::RuntimeOrigin` + | + = note: required for `{integer}` to implement `Into<::RuntimeOrigin>` + = note: this error originates in the attribute macro `benchmarks` (in Nightly builds, run with -Z macro-backtrace for more info) From 910bafbf6a43f16424188a52337715e881b4414e Mon Sep 17 00:00:00 2001 From: Muharem Ismailov Date: Mon, 24 Apr 2023 16:57:45 +0200 Subject: [PATCH 686/715] Vote locks for all reasons except RESERVE (#13914) * Vote locks tip * except reserve * reason for delegate * fix tests --------- Co-authored-by: parity-processbot <> --- frame/conviction-voting/src/lib.rs | 9 +++++++-- frame/democracy/src/lib.rs | 21 ++++++++++++++++++--- frame/democracy/src/tests/lock_voting.rs | 2 +- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/frame/conviction-voting/src/lib.rs b/frame/conviction-voting/src/lib.rs index 072e57035484d..3ad81486ed26d 100644 --- a/frame/conviction-voting/src/lib.rs +++ b/frame/conviction-voting/src/lib.rs @@ -639,7 +639,12 @@ impl, I: 'static> Pallet { }, } }); - T::Currency::extend_lock(CONVICTION_VOTING_ID, who, amount, WithdrawReasons::TRANSFER); + T::Currency::extend_lock( + CONVICTION_VOTING_ID, + who, + amount, + WithdrawReasons::except(WithdrawReasons::RESERVE), + ); } /// Rejig the lock on an account. It will never get more stringent (since that would indicate @@ -669,7 +674,7 @@ impl, I: 'static> Pallet { CONVICTION_VOTING_ID, who, lock_needed, - WithdrawReasons::TRANSFER, + WithdrawReasons::except(WithdrawReasons::RESERVE), ); } } diff --git a/frame/democracy/src/lib.rs b/frame/democracy/src/lib.rs index a3d7f103a98f3..4cfd4958400c9 100644 --- a/frame/democracy/src/lib.rs +++ b/frame/democracy/src/lib.rs @@ -1308,7 +1308,12 @@ impl Pallet { })?; // Extend the lock to `balance` (rather than setting it) since we don't know what other // votes are in place. - T::Currency::extend_lock(DEMOCRACY_ID, who, vote.balance(), WithdrawReasons::TRANSFER); + T::Currency::extend_lock( + DEMOCRACY_ID, + who, + vote.balance(), + WithdrawReasons::except(WithdrawReasons::RESERVE), + ); ReferendumInfoOf::::insert(ref_index, ReferendumInfo::Ongoing(status)); Ok(()) } @@ -1454,7 +1459,12 @@ impl Pallet { let votes = Self::increase_upstream_delegation(&target, conviction.votes(balance)); // Extend the lock to `balance` (rather than setting it) since we don't know what other // votes are in place. - T::Currency::extend_lock(DEMOCRACY_ID, &who, balance, WithdrawReasons::TRANSFER); + T::Currency::extend_lock( + DEMOCRACY_ID, + &who, + balance, + WithdrawReasons::except(WithdrawReasons::RESERVE), + ); Ok(votes) })?; Self::deposit_event(Event::::Delegated { who, target }); @@ -1499,7 +1509,12 @@ impl Pallet { if lock_needed.is_zero() { T::Currency::remove_lock(DEMOCRACY_ID, who); } else { - T::Currency::set_lock(DEMOCRACY_ID, who, lock_needed, WithdrawReasons::TRANSFER); + T::Currency::set_lock( + DEMOCRACY_ID, + who, + lock_needed, + WithdrawReasons::except(WithdrawReasons::RESERVE), + ); } } diff --git a/frame/democracy/src/tests/lock_voting.rs b/frame/democracy/src/tests/lock_voting.rs index 9b9172ff02b45..31f2e3f3dcc26 100644 --- a/frame/democracy/src/tests/lock_voting.rs +++ b/frame/democracy/src/tests/lock_voting.rs @@ -34,7 +34,7 @@ fn nay(x: u8, balance: u64) -> AccountVote { } fn the_lock(amount: u64) -> BalanceLock { - BalanceLock { id: DEMOCRACY_ID, amount, reasons: pallet_balances::Reasons::Misc } + BalanceLock { id: DEMOCRACY_ID, amount, reasons: pallet_balances::Reasons::All } } #[test] From fff96aca38aa97d0c07a34fe0bba0b3c67513d22 Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Mon, 24 Apr 2023 17:33:21 +0200 Subject: [PATCH 687/715] [ci] Update buildah command and version (#13989) --- .gitlab-ci.yml | 3 ++- scripts/ci/gitlab/pipeline/publish.yml | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index c6ce21c7e416f..59d42936e1769 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -49,7 +49,8 @@ variables: DOCKER_OS: "debian:stretch" ARCH: "x86_64" CI_IMAGE: "paritytech/ci-linux:production" - BUILDAH_IMAGE: "quay.io/buildah/stable:v1.27" + BUILDAH_IMAGE: "quay.io/buildah/stable:v1.29" + BUILDAH_COMMAND: "buildah --storage-driver overlay2" RELENG_SCRIPTS_BRANCH: "master" RUSTY_CACHIER_SINGLE_BRANCH: master RUSTY_CACHIER_DONT_OPERATE_ON_MAIN_BRANCH: "true" diff --git a/scripts/ci/gitlab/pipeline/publish.yml b/scripts/ci/gitlab/pipeline/publish.yml index a772096447663..5a69e876ac9ff 100644 --- a/scripts/ci/gitlab/pipeline/publish.yml +++ b/scripts/ci/gitlab/pipeline/publish.yml @@ -19,7 +19,7 @@ script: - test "$DOCKER_USER" -a "$DOCKER_PASS" || ( echo "no docker credentials provided"; exit 1 ) - - buildah bud + - $BUILDAH_COMMAND build --format=docker --build-arg VCS_REF="${CI_COMMIT_SHA}" --build-arg BUILD_DATE="$(date -u '+%Y-%m-%dT%H:%M:%SZ')" @@ -29,9 +29,9 @@ --file "$DOCKERFILE" . - 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" + - $BUILDAH_COMMAND info + - $BUILDAH_COMMAND push --format=v2s2 "$IMAGE_NAME:$VERSION" + - $BUILDAH_COMMAND push --format=v2s2 "$IMAGE_NAME:latest" after_script: - buildah logout --all - echo "SUBSTRATE_IMAGE_NAME=${IMAGE_NAME}" | tee -a ./artifacts/$PRODUCT/build.env From 42448c2339daf43d88ec37dc7b4383928f66750f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Apr 2023 21:31:13 +0200 Subject: [PATCH 688/715] Bump enumflags2 from 0.7.5 to 0.7.7 (#13995) Bumps [enumflags2](https://github.com/meithecatte/enumflags2) from 0.7.5 to 0.7.7. - [Release notes](https://github.com/meithecatte/enumflags2/releases) - [Commits](https://github.com/meithecatte/enumflags2/compare/v0.7.5...v0.7.7) --- updated-dependencies: - dependency-name: enumflags2 dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 10 +++++----- frame/identity/Cargo.toml | 2 +- frame/nfts/Cargo.toml | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index aa7d22daccb80..79b79e2b2ef45 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1982,22 +1982,22 @@ dependencies = [ [[package]] name = "enumflags2" -version = "0.7.5" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e75d4cd21b95383444831539909fbb14b9dc3fdceb2a6f5d36577329a1f55ccb" +checksum = "c041f5090df68b32bcd905365fd51769c8b9d553fe87fde0b683534f10c01bd2" dependencies = [ "enumflags2_derive", ] [[package]] name = "enumflags2_derive" -version = "0.7.4" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f58dc3c5e468259f19f2d46304a6b28f1c3d034442e14b322d2b850e36f6d5ae" +checksum = "5e9a1f9f7d83e59740248a6e14ecf93929ade55027844dfcea78beafccc15745" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.14", ] [[package]] diff --git a/frame/identity/Cargo.toml b/frame/identity/Cargo.toml index 23c690889e19c..2479b0609a0ab 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.2.2", default-features = false, features = ["derive", "max-encoded-len"] } -enumflags2 = { version = "0.7.4" } +enumflags2 = { version = "0.7.7" } scale-info = { version = "2.5.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" } diff --git a/frame/nfts/Cargo.toml b/frame/nfts/Cargo.toml index 96d46dacbbd0c..73df7518e96c0 100644 --- a/frame/nfts/Cargo.toml +++ b/frame/nfts/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false } -enumflags2 = { version = "0.7.5" } +enumflags2 = { version = "0.7.7" } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } From 2b91202014e718525f90c17eb0545e2f2a3261ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Mon, 24 Apr 2023 22:23:26 +0200 Subject: [PATCH 689/715] frame-support-procedural: Fix detection of the tuples feature (#13996) We didn't had the tuples features declared for the `frame-support-procedural` crate and thus, it could not properly detect that the feature was already enabled. --- frame/support/Cargo.toml | 4 ++-- frame/support/procedural/Cargo.toml | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index f62609585818a..fe068d9360d4e 100644 --- a/frame/support/Cargo.toml +++ b/frame/support/Cargo.toml @@ -80,5 +80,5 @@ no-metadata-docs = ["frame-support-procedural/no-metadata-docs", "sp-api/no-meta 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 = [] +tuples-96 = ["frame-support-procedural/tuples-96"] +tuples-128 = ["frame-support-procedural/tuples-128"] diff --git a/frame/support/procedural/Cargo.toml b/frame/support/procedural/Cargo.toml index e508730f43f95..1a17924b40e2e 100644 --- a/frame/support/procedural/Cargo.toml +++ b/frame/support/procedural/Cargo.toml @@ -29,3 +29,7 @@ proc-macro-warning = { version = "0.3.0", default-features = false } default = ["std"] std = [] no-metadata-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 = [] From 222d1189267db873be9466e5658d7e2b033e44ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 25 Apr 2023 09:21:54 +0200 Subject: [PATCH 690/715] pallet-democracy: Do not request the proposal when scheduling (#13827) The requesting of the proposal is actually done now in `pallet-scheduler`. Fixes: https://github.com/paritytech/substrate/issues/13534 --- frame/democracy/src/lib.rs | 5 ----- frame/democracy/src/tests/metadata.rs | 22 +++++++++++----------- frame/support/src/traits/schedule.rs | 2 ++ 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/frame/democracy/src/lib.rs b/frame/democracy/src/lib.rs index 4cfd4958400c9..69438eba91d8e 100644 --- a/frame/democracy/src/lib.rs +++ b/frame/democracy/src/lib.rs @@ -1606,11 +1606,6 @@ impl Pallet { if approved { Self::deposit_event(Event::::Passed { ref_index: index }); - // 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())); diff --git a/frame/democracy/src/tests/metadata.rs b/frame/democracy/src/tests/metadata.rs index 59229abfe4aab..5a36d80b72637 100644 --- a/frame/democracy/src/tests/metadata.rs +++ b/frame/democracy/src/tests/metadata.rs @@ -33,7 +33,7 @@ fn set_external_metadata_works() { Error::::NoProposal, ); // create an external proposal. - assert_ok!(Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(2),)); + assert_ok!(Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(2))); assert!(>::exists()); // fails to set metadata with non external origin. assert_noop!( @@ -47,7 +47,7 @@ fn set_external_metadata_works() { ); // set metadata successful. let hash = note_preimage(1); - assert_ok!(Democracy::set_metadata(RuntimeOrigin::signed(2), owner.clone(), Some(hash),),); + assert_ok!(Democracy::set_metadata(RuntimeOrigin::signed(2), owner.clone(), Some(hash))); System::assert_last_event(RuntimeEvent::Democracy(crate::Event::MetadataSet { owner, hash, @@ -61,11 +61,11 @@ fn clear_metadata_works() { // metadata owner is an external proposal. let owner = MetadataOwner::External; // create an external proposal. - assert_ok!(Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(2),)); + assert_ok!(Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(2))); assert!(>::exists()); // set metadata. let hash = note_preimage(1); - assert_ok!(Democracy::set_metadata(RuntimeOrigin::signed(2), owner.clone(), Some(hash),)); + assert_ok!(Democracy::set_metadata(RuntimeOrigin::signed(2), owner.clone(), Some(hash))); // fails to clear metadata with a wrong origin. assert_noop!( Democracy::set_metadata(RuntimeOrigin::signed(1), owner.clone(), None), @@ -92,18 +92,18 @@ fn set_proposal_metadata_works() { let owner = MetadataOwner::Proposal(Democracy::public_prop_count() - 1); // fails to set non-existing preimage. assert_noop!( - Democracy::set_metadata(RuntimeOrigin::signed(1), owner.clone(), Some(invalid_hash),), + Democracy::set_metadata(RuntimeOrigin::signed(1), owner.clone(), Some(invalid_hash)), Error::::PreimageNotExist, ); // note preimage. let hash = note_preimage(1); // fails to set a preimage if an origin is not a proposer. assert_noop!( - Democracy::set_metadata(RuntimeOrigin::signed(3), owner.clone(), Some(hash),), + Democracy::set_metadata(RuntimeOrigin::signed(3), owner.clone(), Some(hash)), Error::::NoPermission, ); // set metadata successful. - assert_ok!(Democracy::set_metadata(RuntimeOrigin::signed(1), owner.clone(), Some(hash),),); + assert_ok!(Democracy::set_metadata(RuntimeOrigin::signed(1), owner.clone(), Some(hash))); System::assert_last_event(RuntimeEvent::Democracy(crate::Event::MetadataSet { owner, hash, @@ -120,7 +120,7 @@ fn clear_proposal_metadata_works() { let owner = MetadataOwner::Proposal(Democracy::public_prop_count() - 1); // set metadata. let hash = note_preimage(1); - assert_ok!(Democracy::set_metadata(RuntimeOrigin::signed(1), owner.clone(), Some(hash),)); + assert_ok!(Democracy::set_metadata(RuntimeOrigin::signed(1), owner.clone(), Some(hash))); // fails to clear metadata with a wrong origin. assert_noop!( Democracy::set_metadata(RuntimeOrigin::signed(3), owner.clone(), None), @@ -150,16 +150,16 @@ fn set_referendum_metadata_by_root() { let hash = note_preimage(1); // fails to set if not a root. assert_noop!( - Democracy::set_metadata(RuntimeOrigin::signed(3), owner.clone(), Some(hash),), + Democracy::set_metadata(RuntimeOrigin::signed(3), owner.clone(), Some(hash)), Error::::NoPermission, ); // fails to clear if not a root. assert_noop!( - Democracy::set_metadata(RuntimeOrigin::signed(3), owner.clone(), None,), + Democracy::set_metadata(RuntimeOrigin::signed(3), owner.clone(), None), Error::::NoPermission, ); // succeed to set metadata by a root for an ongoing referendum. - assert_ok!(Democracy::set_metadata(RuntimeOrigin::root(), owner.clone(), Some(hash),)); + assert_ok!(Democracy::set_metadata(RuntimeOrigin::root(), owner.clone(), Some(hash))); System::assert_last_event(RuntimeEvent::Democracy(crate::Event::MetadataSet { owner: owner.clone(), hash, diff --git a/frame/support/src/traits/schedule.rs b/frame/support/src/traits/schedule.rs index 4e17092ae329b..74a5951142d52 100644 --- a/frame/support/src/traits/schedule.rs +++ b/frame/support/src/traits/schedule.rs @@ -438,6 +438,8 @@ pub mod v3 { /// 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. + /// + /// NOTE: This will request `call` to be made available. fn schedule_named( id: TaskName, when: DispatchTime, From c92eb70d160b33861dc754831ca66d9920a58dad Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Tue, 25 Apr 2023 10:15:57 +0200 Subject: [PATCH 691/715] [ci] Add message to cargo-deny (#14001) * [ci] Add message to cargo-deny * fix cargo-deny-licenses --- 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 7e84694c24775..c73268caa79af 100644 --- a/scripts/ci/gitlab/pipeline/test.yml +++ b/scripts/ci/gitlab/pipeline/test.yml @@ -36,6 +36,9 @@ cargo-deny-licenses: - !reference [.rusty-cachier, after_script] - echo "___The complete log is in the artifacts___" - $CARGO_DENY_CMD 2> deny.log + - if [ $CI_JOB_STATUS != 'success' ]; then + echo 'Please check license of your crate or add an exception to scripts/ci/deny.toml'; + fi artifacts: name: $CI_COMMIT_SHORT_SHA expire_in: 3 days From b5846ccc8480806aa6035ae4d2e89d61930f697e Mon Sep 17 00:00:00 2001 From: yjh Date: Tue, 25 Apr 2023 16:18:35 +0800 Subject: [PATCH 692/715] refactor(cli): Make some run params reusable (#13870) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: extract TelemetryParams and PrometheusParams * improve run_cmd docs * extract `RuntimeParams` * use `normalize` * keep params types same style * improve `max_runtime_instances` * fmt * add license and improve code * Update client/cli/src/params/runtime_params.rs Co-authored-by: Bastian Köcher --------- Co-authored-by: Bastian Köcher --- client/cli/src/commands/run_cmd.rs | 121 +++++---------------- client/cli/src/params/keystore_params.rs | 2 +- client/cli/src/params/message_params.rs | 5 +- client/cli/src/params/mod.rs | 7 +- client/cli/src/params/prometheus_params.rs | 63 +++++++++++ client/cli/src/params/pruning_params.rs | 2 +- client/cli/src/params/runtime_params.rs | 43 ++++++++ client/cli/src/params/shared_params.rs | 2 +- client/cli/src/params/telemetry_params.rs | 68 ++++++++++++ 9 files changed, 210 insertions(+), 103 deletions(-) create mode 100644 client/cli/src/params/prometheus_params.rs create mode 100644 client/cli/src/params/runtime_params.rs create mode 100644 client/cli/src/params/telemetry_params.rs diff --git a/client/cli/src/commands/run_cmd.rs b/client/cli/src/commands/run_cmd.rs index 9441acecc4dfc..a38ba6f49e3dd 100644 --- a/client/cli/src/commands/run_cmd.rs +++ b/client/cli/src/commands/run_cmd.rs @@ -23,7 +23,7 @@ use crate::{ ImportParams, KeystoreParams, NetworkParams, OffchainWorkerParams, SharedParams, TransactionPoolParams, }, - CliConfiguration, + CliConfiguration, PrometheusParams, RuntimeParams, TelemetryParams, }; use clap::Parser; use regex::Regex; @@ -116,12 +116,6 @@ pub struct RunCmd { #[arg(long)] pub rpc_max_subscriptions_per_connection: Option, - /// Expose Prometheus exporter on all interfaces. - /// - /// Default is local. - #[arg(long)] - pub prometheus_external: bool, - /// DEPRECATED, IPC support has been removed. #[arg(long, value_name = "PATH")] pub ipc_path: Option, @@ -151,36 +145,23 @@ pub struct RunCmd { #[arg(long, value_name = "ORIGINS", value_parser = parse_cors)] pub rpc_cors: Option, - /// Specify Prometheus exporter TCP Port. - #[arg(long, value_name = "PORT")] - pub prometheus_port: Option, - - /// Do not expose a Prometheus exporter endpoint. - /// - /// Prometheus metric endpoint is enabled by default. - #[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. + /// It's used as network node name. #[arg(long, value_name = "NAME")] pub name: Option, - /// Disable connecting to the Substrate telemetry server. - /// - /// Telemetry is on by default on global chains. - #[arg(long)] - pub no_telemetry: bool, + #[allow(missing_docs)] + #[clap(flatten)] + pub telemetry_params: TelemetryParams, - /// The URL of the telemetry server to connect to. - /// - /// This flag can be passed multiple times as a means to specify multiple - /// telemetry endpoints. Verbosity levels range from 0-9, with 0 denoting - /// the least verbosity. - /// Expected format is 'URL VERBOSITY', e.g. `--telemetry-url 'wss://foo/bar 0'`. - #[arg(long = "telemetry-url", value_name = "URL VERBOSITY", value_parser = parse_telemetry_endpoints)] - pub telemetry_endpoints: Vec<(String, u8)>, + #[allow(missing_docs)] + #[clap(flatten)] + pub prometheus_params: PrometheusParams, + + #[allow(missing_docs)] + #[clap(flatten)] + pub runtime_params: RuntimeParams, #[allow(missing_docs)] #[clap(flatten)] @@ -202,6 +183,10 @@ pub struct RunCmd { #[clap(flatten)] pub pool_config: TransactionPoolParams, + #[allow(missing_docs)] + #[clap(flatten)] + pub keystore_params: KeystoreParams, + /// Shortcut for `--name Alice --validator` with session keys for `Alice` added to keystore. #[arg(long, conflicts_with_all = &["bob", "charlie", "dave", "eve", "ferdie", "one", "two"])] pub alice: bool, @@ -239,20 +224,6 @@ pub struct RunCmd { #[arg(long)] pub force_authoring: bool, - #[allow(missing_docs)] - #[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. - #[arg(long)] - pub max_runtime_instances: Option, - - /// Maximum number of different runtimes that can be cached. - #[arg(long, default_value_t = 2)] - pub runtime_cache_size: u8, - /// Run a temporary node. /// /// A temporary directory will be created to store the configuration and will be deleted @@ -345,11 +316,12 @@ impl CliConfiguration for RunCmd { &self, chain_spec: &Box, ) -> Result> { - Ok(if self.no_telemetry { + let params = &self.telemetry_params; + Ok(if params.no_telemetry { None - } else if !self.telemetry_endpoints.is_empty() { + } else if !params.telemetry_endpoints.is_empty() { Some( - TelemetryEndpoints::new(self.telemetry_endpoints.clone()) + TelemetryEndpoints::new(params.telemetry_endpoints.clone()) .map_err(|e| e.to_string())?, ) } else { @@ -361,7 +333,7 @@ impl CliConfiguration for RunCmd { let keyring = self.get_keyring(); let is_authority = self.validator || is_dev || keyring.is_some(); - Ok(if is_authority { sc_service::Role::Authority } else { sc_service::Role::Full }) + Ok(if is_authority { Role::Authority } else { Role::Full }) } fn force_authoring(&self) -> Result { @@ -374,20 +346,9 @@ impl CliConfiguration for RunCmd { default_listen_port: u16, chain_spec: &Box, ) -> Result> { - Ok(if self.no_prometheus { - None - } else { - 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), - ), - chain_spec.id().into(), - )) - }) + Ok(self + .prometheus_params + .prometheus_config(default_listen_port, chain_spec.id().to_string())) } fn disable_grandpa(&self) -> Result { @@ -474,11 +435,11 @@ impl CliConfiguration for RunCmd { } fn max_runtime_instances(&self) -> Result> { - Ok(self.max_runtime_instances.map(|x| x.min(256))) + Ok(Some(self.runtime_params.max_runtime_instances)) } fn runtime_cache_size(&self) -> Result { - Ok(self.runtime_cache_size) + Ok(self.runtime_params.runtime_cache_size) } fn base_path(&self) -> Result> { @@ -546,36 +507,6 @@ fn rpc_interface( } } -#[derive(Debug)] -enum TelemetryParsingError { - MissingVerbosity, - VerbosityParsingError(std::num::ParseIntError), -} - -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 { - TelemetryParsingError::MissingVerbosity => write!(f, "Verbosity level missing"), - TelemetryParsingError::VerbosityParsingError(e) => write!(f, "{}", e), - } - } -} - -fn parse_telemetry_endpoints(s: &str) -> std::result::Result<(String, u8), TelemetryParsingError> { - let pos = s.find(' '); - match pos { - None => Err(TelemetryParsingError::MissingVerbosity), - Some(pos_) => { - let url = s[..pos_].to_string(); - let verbosity = - s[pos_ + 1..].parse().map_err(TelemetryParsingError::VerbosityParsingError)?; - Ok((url, verbosity)) - }, - } -} - /// CORS setting /// /// The type is introduced to overcome `Option>` handling of `clap`. diff --git a/client/cli/src/params/keystore_params.rs b/client/cli/src/params/keystore_params.rs index 8933110c400b7..a2fdd6b2218c4 100644 --- a/client/cli/src/params/keystore_params.rs +++ b/client/cli/src/params/keystore_params.rs @@ -61,7 +61,7 @@ pub struct KeystoreParams { pub password_filename: Option, } -/// Parse a sercret string, returning a displayable error. +/// Parse a secret string, returning a displayable error. pub fn secret_string_from_str(s: &str) -> std::result::Result { std::str::FromStr::from_str(s).map_err(|_| "Could not get SecretString".to_string()) } diff --git a/client/cli/src/params/message_params.rs b/client/cli/src/params/message_params.rs index a935bbb25bddd..3fcb6f2c6e8cc 100644 --- a/client/cli/src/params/message_params.rs +++ b/client/cli/src/params/message_params.rs @@ -20,14 +20,13 @@ use crate::error::Error; use array_bytes::{hex2bytes, hex_bytes2hex_str}; -use clap::Parser; +use clap::Args; use std::io::BufRead; /// Params to configure how a message should be passed into a command. -#[derive(Parser, Debug, Clone)] +#[derive(Debug, Clone, Args)] pub struct MessageParams { /// Message to process. Will be read from STDIN otherwise. - /// /// The message is assumed to be raw bytes per default. Use `--hex` for hex input. Can /// optionally be prefixed with `0x` in the hex case. #[arg(long)] diff --git a/client/cli/src/params/mod.rs b/client/cli/src/params/mod.rs index f9c840d2d4865..247ffc0e04ba5 100644 --- a/client/cli/src/params/mod.rs +++ b/client/cli/src/params/mod.rs @@ -22,8 +22,11 @@ mod message_params; mod network_params; mod node_key_params; mod offchain_worker_params; +mod prometheus_params; mod pruning_params; +mod runtime_params; mod shared_params; +mod telemetry_params; mod transaction_pool_params; use crate::arg_enums::{CryptoScheme, OutputType}; @@ -37,8 +40,8 @@ use std::{fmt::Debug, str::FromStr}; pub use crate::params::{ database_params::*, import_params::*, keystore_params::*, message_params::*, network_params::*, - node_key_params::*, offchain_worker_params::*, pruning_params::*, shared_params::*, - transaction_pool_params::*, + node_key_params::*, offchain_worker_params::*, prometheus_params::*, pruning_params::*, + runtime_params::*, shared_params::*, telemetry_params::*, transaction_pool_params::*, }; /// Parse Ss58AddressFormat diff --git a/client/cli/src/params/prometheus_params.rs b/client/cli/src/params/prometheus_params.rs new file mode 100644 index 0000000000000..69199ad5b2603 --- /dev/null +++ b/client/cli/src/params/prometheus_params.rs @@ -0,0 +1,63 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use clap::Args; +use sc_service::config::PrometheusConfig; +use std::net::{Ipv4Addr, SocketAddr}; + +/// Parameters used to config prometheus. +#[derive(Debug, Clone, Args)] +pub struct PrometheusParams { + /// Specify Prometheus exporter TCP Port. + #[arg(long, value_name = "PORT")] + pub prometheus_port: Option, + /// Expose Prometheus exporter on all interfaces. + /// + /// Default is local. + #[arg(long)] + pub prometheus_external: bool, + /// Do not expose a Prometheus exporter endpoint. + /// + /// Prometheus metric endpoint is enabled by default. + #[arg(long)] + pub no_prometheus: bool, +} + +impl PrometheusParams { + /// Creates [`PrometheusConfig`]. + pub fn prometheus_config( + &self, + default_listen_port: u16, + chain_id: String, + ) -> Option { + if self.no_prometheus { + None + } else { + 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), + ), + chain_id, + )) + } + } +} diff --git a/client/cli/src/params/pruning_params.rs b/client/cli/src/params/pruning_params.rs index 59eeb13cd0379..757da2dd9cbb5 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::{BlocksPruning, PruningMode}; /// Parameters to define the pruning mode -#[derive(Debug, Clone, PartialEq, Args)] +#[derive(Debug, Clone, Args)] pub struct PruningParams { /// Specify the state pruning mode. /// diff --git a/client/cli/src/params/runtime_params.rs b/client/cli/src/params/runtime_params.rs new file mode 100644 index 0000000000000..79035fc7d4c5d --- /dev/null +++ b/client/cli/src/params/runtime_params.rs @@ -0,0 +1,43 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use clap::Args; +use std::str::FromStr; + +/// Parameters used to config runtime. +#[derive(Debug, Clone, Args)] +pub struct RuntimeParams { + /// The size of the instances cache for each runtime. The values higher than 256 are illegal. + #[arg(long, default_value_t = 8, value_parser = parse_max_runtime_instances)] + pub max_runtime_instances: usize, + + /// Maximum number of different runtimes that can be cached. + #[arg(long, default_value_t = 2)] + pub runtime_cache_size: u8, +} + +fn parse_max_runtime_instances(s: &str) -> Result { + let max_runtime_instances = usize::from_str(s) + .map_err(|_err| format!("Illegal `--max-runtime-instances` value: {s}"))?; + + if max_runtime_instances > 256 { + Err(format!("Illegal `--max-runtime-instances` value: {max_runtime_instances} is more than the allowed maximum of `256` ")) + } else { + Ok(max_runtime_instances) + } +} diff --git a/client/cli/src/params/shared_params.rs b/client/cli/src/params/shared_params.rs index 46f5390039d46..913a6c436185c 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, PartialEq, Args)] +#[derive(Debug, Clone, Args)] pub struct SharedParams { /// Specify the chain specification. /// diff --git a/client/cli/src/params/telemetry_params.rs b/client/cli/src/params/telemetry_params.rs new file mode 100644 index 0000000000000..ca096419869af --- /dev/null +++ b/client/cli/src/params/telemetry_params.rs @@ -0,0 +1,68 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use clap::Args; + +/// Parameters used to config telemetry. +#[derive(Debug, Clone, Args)] +pub struct TelemetryParams { + /// Disable connecting to the Substrate telemetry server. + /// + /// Telemetry is on by default on global chains. + #[arg(long)] + pub no_telemetry: bool, + + /// The URL of the telemetry server to connect to. + /// + /// This flag can be passed multiple times as a means to specify multiple + /// telemetry endpoints. Verbosity levels range from 0-9, with 0 denoting + /// the least verbosity. + /// Expected format is 'URL VERBOSITY', e.g. `--telemetry-url 'wss://foo/bar 0'`. + #[arg(long = "telemetry-url", value_name = "URL VERBOSITY", value_parser = parse_telemetry_endpoints)] + pub telemetry_endpoints: Vec<(String, u8)>, +} + +#[derive(Debug)] +enum TelemetryParsingError { + MissingVerbosity, + VerbosityParsingError(std::num::ParseIntError), +} + +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 { + TelemetryParsingError::MissingVerbosity => write!(f, "Verbosity level missing"), + TelemetryParsingError::VerbosityParsingError(e) => write!(f, "{}", e), + } + } +} + +fn parse_telemetry_endpoints(s: &str) -> Result<(String, u8), TelemetryParsingError> { + let pos = s.find(' '); + match pos { + None => Err(TelemetryParsingError::MissingVerbosity), + Some(pos_) => { + let url = s[..pos_].to_string(); + let verbosity = + s[pos_ + 1..].parse().map_err(TelemetryParsingError::VerbosityParsingError)?; + Ok((url, verbosity)) + }, + } +} From 8cb72571798a0d2d9ad089ba977c310ddb2b5c11 Mon Sep 17 00:00:00 2001 From: PG Herveou Date: Tue, 25 Apr 2023 13:46:20 +0200 Subject: [PATCH 693/715] contracts Add LOG_TARGET constant (#14002) * contracts Add LOG_TARGET constant * Update frame/contracts/src/lib.rs Co-authored-by: Sasha Gryaznov --------- Co-authored-by: Sasha Gryaznov --- frame/contracts/src/exec.rs | 6 +++--- frame/contracts/src/lib.rs | 7 +++++++ frame/contracts/src/storage/meter.rs | 6 +++--- frame/contracts/src/wasm/mod.rs | 6 +++--- frame/contracts/src/wasm/prepare.rs | 10 +++++----- 5 files changed, 21 insertions(+), 14 deletions(-) diff --git a/frame/contracts/src/exec.rs b/frame/contracts/src/exec.rs index 574f4495e479f..46a611dbfd09b 100644 --- a/frame/contracts/src/exec.rs +++ b/frame/contracts/src/exec.rs @@ -19,7 +19,7 @@ use crate::{ gas::GasMeter, storage::{self, DepositAccount, WriteOutcome}, BalanceOf, CodeHash, Config, ContractInfo, ContractInfoOf, DebugBufferVec, Determinism, Error, - Event, Nonce, Pallet as Contracts, Schedule, System, + Event, Nonce, Pallet as Contracts, Schedule, System, LOG_TARGET, }; use frame_support::{ crypto::ecdsa::ECDSAExt, @@ -1002,7 +1002,7 @@ where } else { if let Some((msg, false)) = self.debug_message.as_ref().map(|m| (m, m.is_empty())) { log::debug!( - target: "runtime::contracts", + target: LOG_TARGET, "Execution finished with debug buffer: {}", core::str::from_utf8(msg).unwrap_or(""), ); @@ -1331,7 +1331,7 @@ where .try_extend(&mut msg.bytes()) .map_err(|_| { log::debug!( - target: "runtime::contracts", + target: LOG_TARGET, "Debug buffer (of {} bytes) exhausted!", DebugBufferVec::::bound(), ) diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index fa230a8cade14..118da36ae88a1 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -163,6 +163,13 @@ type OldWeight = u64; /// that this value makes sense for a memory location or length. const SENTINEL: u32 = u32::MAX; +/// The target that is used for the log output emitted by this crate. +/// +/// Hence you can use this target to selectively increase the log level for this crate. +/// +/// Example: `RUST_LOG=runtime::contracts=debug my_code --dev` +const LOG_TARGET: &str = "runtime::contracts"; + #[frame_support::pallet] pub mod pallet { use super::*; diff --git a/frame/contracts/src/storage/meter.rs b/frame/contracts/src/storage/meter.rs index 497ee03ac319a..51a0af574bcd5 100644 --- a/frame/contracts/src/storage/meter.rs +++ b/frame/contracts/src/storage/meter.rs @@ -19,7 +19,7 @@ use crate::{ storage::{ContractInfo, DepositAccount}, - BalanceOf, Config, Error, Inspect, Pallet, System, + BalanceOf, Config, Error, Inspect, Pallet, System, LOG_TARGET, }; use codec::Encode; use frame_support::{ @@ -502,7 +502,7 @@ impl Ext for ReservingExt { ); if let Err(err) = result { log::error!( - target: "runtime::contracts", + target: LOG_TARGET, "Failed to transfer storage deposit {:?} from origin {:?} to deposit account {:?}: {:?}", amount, origin, deposit_account, err, ); @@ -531,7 +531,7 @@ impl Ext for ReservingExt { ); if matches!(result, Err(_)) { log::error!( - target: "runtime::contracts", + target: LOG_TARGET, "Failed to refund storage deposit {:?} from deposit account {:?} to origin {:?}: {:?}", amount, deposit_account, origin, result, ); diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index c8f1be6dd9db1..4723f0c833654 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -43,7 +43,7 @@ use crate::{ exec::{ExecResult, Executable, ExportedFunction, Ext}, gas::GasMeter, AccountIdOf, BalanceOf, CodeHash, CodeVec, Config, Error, OwnerInfoOf, RelaxedCodeVec, - Schedule, + Schedule, LOG_TARGET, }; use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::dispatch::{DispatchError, DispatchResult}; @@ -326,7 +326,7 @@ impl Executable for PrefabWasmModule { }, ) .map_err(|msg| { - log::debug!(target: "runtime::contracts", "failed to instantiate code: {}", msg); + log::debug!(target: LOG_TARGET, "failed to instantiate code: {}", msg); Error::::CodeRejected })?; store.data_mut().set_memory(memory); @@ -335,7 +335,7 @@ impl Executable for PrefabWasmModule { .get_export(&store, function.identifier()) .and_then(|export| export.into_func()) .ok_or_else(|| { - log::error!(target: "runtime::contracts", "failed to find entry point"); + log::error!(target: LOG_TARGET, "failed to find entry point"); Error::::CodeRejected })?; diff --git a/frame/contracts/src/wasm/prepare.rs b/frame/contracts/src/wasm/prepare.rs index f0065d77a1c9a..14fec834733eb 100644 --- a/frame/contracts/src/wasm/prepare.rs +++ b/frame/contracts/src/wasm/prepare.rs @@ -25,7 +25,7 @@ use crate::{ wasm::{ runtime::AllowDeprecatedInterface, Determinism, Environment, OwnerInfo, PrefabWasmModule, }, - AccountIdOf, CodeVec, Config, Error, Schedule, + AccountIdOf, CodeVec, Config, Error, Schedule, LOG_TARGET, }; use codec::{Encode, MaxEncodedLen}; use sp_runtime::{traits::Hash, DispatchError}; @@ -379,7 +379,7 @@ where }) .validate_all(original_code) .map_err(|err| { - log::debug!(target: "runtime::contracts", "{}", err); + log::debug!(target: LOG_TARGET, "{}", err); (Error::::CodeRejected.into(), "validation of new code failed") })?; @@ -403,7 +403,7 @@ where Ok((code, memory_limits)) })() .map_err(|msg: &str| { - log::debug!(target: "runtime::contracts", "new code rejected: {}", msg); + log::debug!(target: LOG_TARGET, "new code rejected: {}", msg); (Error::::CodeRejected.into(), msg) })?; @@ -426,7 +426,7 @@ where }, ) .map_err(|err| { - log::debug!(target: "runtime::contracts", "{}", err); + log::debug!(target: LOG_TARGET, "{}", err); (Error::::CodeRejected.into(), "new code rejected after instrumentation") })?; } @@ -518,7 +518,7 @@ where InstrumentReason::Reinstrument, ) .map_err(|(err, msg)| { - log::error!(target: "runtime::contracts", "CodeRejected during reinstrument: {}", msg); + log::error!(target: LOG_TARGET, "CodeRejected during reinstrument: {}", msg); err }) .map(|(code, _)| code) From 6f0f5a92739b92199b3345fc4a716211c8a8b46f Mon Sep 17 00:00:00 2001 From: Qinxuan Chen Date: Tue, 25 Apr 2023 19:58:21 +0800 Subject: [PATCH 694/715] frame-support: migrate some tests from `decl_*` macros to the new `pallet` macros (#12401) * frame-support: migrate some tests from decl macros to new pallet attribute macros * Remove useless type alias * Remove useless type alias * Work around for rust issue 52234 Signed-off-by: Oliver Tale-Yazdi * Fix tests Signed-off-by: Oliver Tale-Yazdi * Use polkadot-compatible paste version Signed-off-by: Oliver Tale-Yazdi * Fix crate access and add tests Signed-off-by: Oliver Tale-Yazdi * Typo Signed-off-by: Oliver Tale-Yazdi --------- Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Oliver Tale-Yazdi Co-authored-by: parity-processbot <> --- Cargo.lock | 5 +- frame/support/src/dispatch.rs | 183 +++++++++----- frame/support/src/lib.rs | 237 ++++++++++++------ .../src/storage/generator/double_map.rs | 43 +--- frame/support/src/storage/generator/map.rs | 43 +--- frame/support/src/storage/generator/mod.rs | 128 ++++++++-- frame/support/src/storage/generator/nmap.rs | 61 ++--- primitives/core/Cargo.toml | 1 + primitives/core/src/lib.rs | 85 ++++--- primitives/runtime/src/lib.rs | 20 ++ 10 files changed, 490 insertions(+), 316 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 79b79e2b2ef45..8d8d2d59a3c88 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7239,9 +7239,9 @@ dependencies = [ [[package]] name = "paste" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d01a5bd0424d00070b0098dd17ebca6f961a959dead1dbcbbbc1d1cd8d3deeba" +checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" [[package]] name = "pbkdf2" @@ -10503,6 +10503,7 @@ dependencies = [ "merlin", "parity-scale-codec", "parking_lot 0.12.1", + "paste", "primitive-types", "rand 0.8.5", "regex", diff --git a/frame/support/src/dispatch.rs b/frame/support/src/dispatch.rs index 9e949ef6d4a21..c75d75b41a292 100644 --- a/frame/support/src/dispatch.rs +++ b/frame/support/src/dispatch.rs @@ -3532,112 +3532,177 @@ mod tests { #[allow(dead_code)] mod weight_tests { use super::{tests::*, *}; - use sp_core::{parameter_types, Get}; + use sp_core::parameter_types; + use sp_runtime::{generic, traits::BlakeTwo256}; use sp_weights::RuntimeDbWeight; - pub trait Config: 'static { - type RuntimeOrigin; - type Balance; - type BlockNumber; - type DbWeight: Get; - type PalletInfo: crate::traits::PalletInfo; - } + pub use self::frame_system::{Call, Config, Pallet}; - pub struct TraitImpl {} + #[crate::pallet(dev_mode)] + pub mod frame_system { + use super::{frame_system, frame_system::pallet_prelude::*}; + pub use crate::dispatch::RawOrigin; + use crate::pallet_prelude::*; - parameter_types! { - pub const DbWeight: RuntimeDbWeight = RuntimeDbWeight { - read: 100, - write: 1000, - }; - } + #[pallet::pallet] + pub struct Pallet(PhantomData); - impl Config for TraitImpl { - type RuntimeOrigin = u32; - type BlockNumber = u32; - type Balance = u32; - type DbWeight = DbWeight; - type PalletInfo = crate::tests::PanicPalletInfo; - } + #[pallet::config] + #[pallet::disable_frame_system_supertrait_check] + pub trait Config: 'static { + type BlockNumber: Parameter + Default + MaxEncodedLen; + type AccountId; + type Balance; + type BaseCallFilter: crate::traits::Contains; + type RuntimeOrigin; + type RuntimeCall; + type PalletInfo: crate::traits::PalletInfo; + type DbWeight: Get; + } - decl_module! { - pub struct Module for enum Call where origin: T::RuntimeOrigin, system=self { + #[pallet::error] + pub enum Error { + /// Required by construct_runtime + CallFiltered, + } + + #[pallet::origin] + pub type Origin = RawOrigin<::AccountId>; + + #[pallet::call] + impl Pallet { // no arguments, fixed weight - #[weight = 1000] - fn f00(_origin) { unimplemented!(); } + #[pallet::weight(1000)] + pub fn f00(_origin: OriginFor) -> DispatchResult { + unimplemented!(); + } - #[weight = (1000, DispatchClass::Mandatory)] - fn f01(_origin) { unimplemented!(); } + #[pallet::weight((1000, DispatchClass::Mandatory))] + pub fn f01(_origin: OriginFor) -> DispatchResult { + unimplemented!(); + } - #[weight = (1000, Pays::No)] - fn f02(_origin) { unimplemented!(); } + #[pallet::weight((1000, Pays::No))] + pub fn f02(_origin: OriginFor) -> DispatchResult { + unimplemented!(); + } - #[weight = (1000, DispatchClass::Operational, Pays::No)] - fn f03(_origin) { unimplemented!(); } + #[pallet::weight((1000, DispatchClass::Operational, Pays::No))] + pub fn f03(_origin: OriginFor) -> DispatchResult { + 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!(); } + #[pallet::weight(((_a * 10 + _eb * 1) as u64, DispatchClass::Normal, Pays::Yes))] + pub fn f11(_origin: OriginFor, _a: u32, _eb: u32) -> DispatchResult { + unimplemented!(); + } - #[weight = (0, DispatchClass::Operational, Pays::Yes)] - fn f12(_origin, _a: u32, _eb: u32) { unimplemented!(); } + #[pallet::weight((0, DispatchClass::Operational, Pays::Yes))] + pub fn f12(_origin: OriginFor, _a: u32, _eb: u32) -> DispatchResult { + unimplemented!(); + } - #[weight = T::DbWeight::get().reads(3) + T::DbWeight::get().writes(2) + Weight::from_parts(10_000, 0)] - fn f20(_origin) { unimplemented!(); } + #[pallet::weight(T::DbWeight::get().reads(3) + T::DbWeight::get().writes(2) + Weight::from_all(10_000))] + pub fn f20(_origin: OriginFor) -> DispatchResult { + unimplemented!(); + } + + #[pallet::weight(T::DbWeight::get().reads_writes(6, 5) + Weight::from_all(40_000))] + pub fn f21(_origin: OriginFor) -> DispatchResult { + unimplemented!(); + } + } + + pub mod pallet_prelude { + pub type OriginFor = ::RuntimeOrigin; + } + } - #[weight = T::DbWeight::get().reads_writes(6, 5) + Weight::from_parts(40_000, 0)] - fn f21(_origin) { unimplemented!(); } + type BlockNumber = u32; + type AccountId = u32; + type Balance = u32; + type Header = generic::Header; + type UncheckedExtrinsic = generic::UncheckedExtrinsic; + type Block = generic::Block; + crate::construct_runtime!( + pub enum Runtime + where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: self::frame_system, } + ); + + parameter_types! { + pub const DbWeight: RuntimeDbWeight = RuntimeDbWeight { + read: 100, + write: 1000, + }; + } + + impl Config for Runtime { + type BlockNumber = BlockNumber; + type AccountId = AccountId; + type Balance = Balance; + type BaseCallFilter = crate::traits::Everything; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type DbWeight = DbWeight; + type PalletInfo = PalletInfo; } #[test] fn weights_are_correct() { - // #[weight = 1000] - let info = Call::::f00 {}.get_dispatch_info(); + // #[pallet::weight(1000)] + let info = Call::::f00 {}.get_dispatch_info(); assert_eq!(info.weight, Weight::from_parts(1000, 0)); assert_eq!(info.class, DispatchClass::Normal); assert_eq!(info.pays_fee, Pays::Yes); - // #[weight = (1000, DispatchClass::Mandatory)] - let info = Call::::f01 {}.get_dispatch_info(); + // #[pallet::weight((1000, DispatchClass::Mandatory))] + let info = Call::::f01 {}.get_dispatch_info(); assert_eq!(info.weight, Weight::from_parts(1000, 0)); assert_eq!(info.class, DispatchClass::Mandatory); assert_eq!(info.pays_fee, Pays::Yes); - // #[weight = (1000, Pays::No)] - let info = Call::::f02 {}.get_dispatch_info(); + // #[pallet::weight((1000, Pays::No))] + let info = Call::::f02 {}.get_dispatch_info(); assert_eq!(info.weight, Weight::from_parts(1000, 0)); 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(); + // #[pallet::weight((1000, DispatchClass::Operational, Pays::No))] + let info = Call::::f03 {}.get_dispatch_info(); assert_eq!(info.weight, Weight::from_parts(1000, 0)); 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(); + // #[pallet::weight(((_a * 10 + _eb * 1) as u64, DispatchClass::Normal, Pays::Yes))] + let info = Call::::f11 { a: 13, eb: 20 }.get_dispatch_info(); assert_eq!(info.weight, Weight::from_parts(150, 0)); // 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_parts(0, 0)); + // #[pallet::weight((0, DispatchClass::Operational, Pays::Yes))] + let info = Call::::f12 { a: 10, eb: 20 }.get_dispatch_info(); + assert_eq!(info.weight, Weight::zero()); 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_parts(12300, 0)); // 100*3 + 1000*2 + 10_1000 + // #[pallet::weight(T::DbWeight::get().reads(3) + T::DbWeight::get().writes(2) + + // Weight::from_all(10_000))] + let info = Call::::f20 {}.get_dispatch_info(); + assert_eq!(info.weight, Weight::from_parts(12300, 10000)); // 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_parts(45600, 0)); // 100*6 + 1000*5 + 40_1000 + // #[pallet::weight(T::DbWeight::get().reads_writes(6, 5) + Weight::from_all(40_000))] + let info = Call::::f21 {}.get_dispatch_info(); + assert_eq!(info.weight, Weight::from_parts(45600, 40000)); // 100*6 + 1000*5 + 40_1000 assert_eq!(info.class, DispatchClass::Normal); assert_eq!(info.pays_fee, Pays::Yes); } diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 036bd93464b9f..0ee82b9f16a8f 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -829,77 +829,153 @@ pub mod tests { PalletStorageMetadataIR, StorageEntryMetadataIR, StorageEntryModifierIR, StorageEntryTypeIR, StorageHasherIR, }; - use codec::{Codec, EncodeLike}; - use frame_support::traits::CrateVersion; use sp_io::{MultiRemovalResults, TestExternalities}; + use sp_runtime::{generic, traits::BlakeTwo256, BuildStorage}; use sp_std::result; - /// A PalletInfo implementation which just panics. - pub struct PanicPalletInfo; + pub use self::frame_system::{Config, Pallet}; - impl crate::traits::PalletInfo for PanicPalletInfo { - fn index() -> Option { - unimplemented!("PanicPalletInfo mustn't be triggered by 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"); + #[pallet] + pub mod frame_system { + #[allow(unused)] + use super::{frame_system, frame_system::pallet_prelude::*}; + pub use crate::dispatch::RawOrigin; + use crate::pallet_prelude::*; + + #[pallet::pallet] + pub struct Pallet(PhantomData); + + #[pallet::config] + #[pallet::disable_frame_system_supertrait_check] + pub trait Config: 'static { + type BlockNumber: Parameter + Default + MaxEncodedLen; + type AccountId; + type BaseCallFilter: crate::traits::Contains; + type RuntimeOrigin; + type RuntimeCall; + type PalletInfo: crate::traits::PalletInfo; + type DbWeight: Get; } - } - pub trait Config: 'static { - type BlockNumber: Codec + EncodeLike + Default + TypeInfo; - type RuntimeOrigin; - type PalletInfo: crate::traits::PalletInfo; - type DbWeight: crate::traits::Get; - } + #[pallet::error] + pub enum Error { + /// Required by construct_runtime + CallFiltered, + } - mod module { - #![allow(dead_code)] + #[pallet::origin] + pub type Origin = RawOrigin<::AccountId>; + + #[pallet::call] + impl Pallet {} + + #[pallet::storage] + pub type Data = StorageMap<_, Twox64Concat, u32, u64, ValueQuery>; + + #[pallet::storage] + pub type OptionLinkedMap = StorageMap<_, Blake2_128Concat, u32, u32, OptionQuery>; + + #[pallet::storage] + #[pallet::getter(fn generic_data)] + pub type GenericData = + StorageMap<_, Identity, T::BlockNumber, T::BlockNumber, ValueQuery>; + + #[pallet::storage] + #[pallet::getter(fn generic_data2)] + pub type GenericData2 = + StorageMap<_, Blake2_128Concat, T::BlockNumber, T::BlockNumber, OptionQuery>; + + #[pallet::storage] + pub type DataDM = + StorageDoubleMap<_, Twox64Concat, u32, Blake2_128Concat, u32, u64, ValueQuery>; + + #[pallet::storage] + pub type GenericDataDM = StorageDoubleMap< + _, + Blake2_128Concat, + T::BlockNumber, + Identity, + T::BlockNumber, + T::BlockNumber, + ValueQuery, + >; + + #[pallet::storage] + pub type GenericData2DM = StorageDoubleMap< + _, + Blake2_128Concat, + T::BlockNumber, + Twox64Concat, + T::BlockNumber, + T::BlockNumber, + OptionQuery, + >; + + #[pallet::storage] + #[pallet::unbounded] + pub type AppendableDM = StorageDoubleMap< + _, + Blake2_128Concat, + u32, + Blake2_128Concat, + T::BlockNumber, + Vec, + ValueQuery, + >; + + #[pallet::genesis_config] + pub struct GenesisConfig { + pub data: Vec<(u32, u64)>, + pub test_config: Vec<(u32, u32, u64)>, + } - use super::Config; + impl Default for GenesisConfig { + fn default() -> Self { + Self { data: vec![(15u32, 42u64)], test_config: vec![(15u32, 16u32, 42u64)] } + } + } - decl_module! { - pub struct Module for enum Call where origin: T::RuntimeOrigin, system=self {} + #[pallet::genesis_build] + impl GenesisBuild for GenesisConfig { + fn build(&self) { + for (k, v) in &self.data { + >::insert(k, v); + } + for (k1, k2, v) in &self.test_config { + >::insert(k1, k2, v); + } + } } - } - use self::module::Module; - - decl_storage! { - trait Store for Module as Test { - pub Value get(fn value): u64; - pub Data get(fn data) build(|_| vec![(15u32, 42u64)]): - map hasher(twox_64_concat) u32 => u64; - pub OptionLinkedMap: map hasher(blake2_128_concat) u32 => Option; - pub GenericData get(fn generic_data): - map hasher(identity) T::BlockNumber => T::BlockNumber; - pub GenericData2 get(fn generic_data2): - map hasher(blake2_128_concat) T::BlockNumber => Option; - pub DataDM config(test_config) build(|_| vec![(15u32, 16u32, 42u64)]): - double_map hasher(twox_64_concat) u32, hasher(blake2_128_concat) u32 => u64; - pub GenericDataDM: - double_map hasher(blake2_128_concat) T::BlockNumber, hasher(identity) T::BlockNumber - => T::BlockNumber; - pub GenericData2DM: - double_map hasher(blake2_128_concat) T::BlockNumber, hasher(twox_64_concat) T::BlockNumber - => Option; - pub AppendableDM: - double_map hasher(blake2_128_concat) u32, hasher(blake2_128_concat) T::BlockNumber => Vec; + pub mod pallet_prelude { + pub type OriginFor = ::RuntimeOrigin; } } - struct Test; + type BlockNumber = u32; + type AccountId = u32; + type Header = generic::Header; + type UncheckedExtrinsic = generic::UncheckedExtrinsic; + type Block = generic::Block; + + crate::construct_runtime!( + pub enum Runtime + where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: self::frame_system, + } + ); - impl Config for Test { - type BlockNumber = u32; - type RuntimeOrigin = u32; - type PalletInfo = PanicPalletInfo; + impl Config for Runtime { + type BlockNumber = BlockNumber; + type AccountId = AccountId; + type BaseCallFilter = crate::traits::Everything; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type PalletInfo = PalletInfo; type DbWeight = (); } @@ -907,8 +983,6 @@ pub mod tests { GenesisConfig::default().build_storage().unwrap().into() } - type Map = Data; - trait Sorted { fn sorted(self) -> Self; } @@ -925,15 +999,15 @@ pub mod tests { new_test_ext().execute_with(|| { #[crate::storage_alias] type GenericData2 = StorageMap< - Test, + System, Blake2_128Concat, ::BlockNumber, ::BlockNumber, >; - assert_eq!(Module::::generic_data2(5), None); - GenericData2::::insert(5, 5); - assert_eq!(Module::::generic_data2(5), Some(5)); + assert_eq!(Pallet::::generic_data2(5), None); + GenericData2::::insert(5, 5); + assert_eq!(Pallet::::generic_data2(5), Some(5)); /// Some random docs that ensure that docs are accepted #[crate::storage_alias] @@ -1004,6 +1078,8 @@ pub mod tests { #[test] fn map_issue_3318() { new_test_ext().execute_with(|| { + type OptionLinkedMap = self::frame_system::OptionLinkedMap; + OptionLinkedMap::insert(1, 1); assert_eq!(OptionLinkedMap::get(1), Some(1)); OptionLinkedMap::insert(1, 2); @@ -1014,6 +1090,8 @@ pub mod tests { #[test] fn map_swap_works() { new_test_ext().execute_with(|| { + type OptionLinkedMap = self::frame_system::OptionLinkedMap; + OptionLinkedMap::insert(0, 0); OptionLinkedMap::insert(1, 1); OptionLinkedMap::insert(2, 2); @@ -1043,6 +1121,8 @@ pub mod tests { #[test] fn double_map_swap_works() { new_test_ext().execute_with(|| { + type DataDM = self::frame_system::DataDM; + DataDM::insert(0, 1, 1); DataDM::insert(1, 0, 2); DataDM::insert(1, 1, 3); @@ -1075,6 +1155,8 @@ pub mod tests { #[test] fn map_basic_insert_remove_should_work() { new_test_ext().execute_with(|| { + type Map = self::frame_system::Data; + // initialized during genesis assert_eq!(Map::get(&15u32), 42u64); @@ -1101,6 +1183,8 @@ pub mod tests { #[test] fn map_iteration_should_work() { new_test_ext().execute_with(|| { + type Map = self::frame_system::Data; + assert_eq!(Map::iter().collect::>().sorted(), vec![(15, 42)]); // insert / remove let key = 17u32; @@ -1154,7 +1238,7 @@ pub mod tests { fn double_map_basic_insert_remove_remove_prefix_with_commit_should_work() { let key1 = 17u32; let key2 = 18u32; - type DoubleMap = DataDM; + type DoubleMap = self::frame_system::DataDM; let mut e = new_test_ext(); e.execute_with(|| { // initialized during genesis @@ -1199,7 +1283,7 @@ pub mod tests { new_test_ext().execute_with(|| { let key1 = 17u32; let key2 = 18u32; - type DoubleMap = DataDM; + type DoubleMap = self::frame_system::DataDM; // initialized during genesis assert_eq!(DoubleMap::get(&15u32, &16u32), 42u64); @@ -1247,7 +1331,7 @@ pub mod tests { #[test] fn double_map_append_should_work() { new_test_ext().execute_with(|| { - type DoubleMap = AppendableDM; + type DoubleMap = self::frame_system::AppendableDM; let key1 = 17u32; let key2 = 18u32; @@ -1261,7 +1345,7 @@ pub mod tests { #[test] fn double_map_mutate_exists_should_work() { new_test_ext().execute_with(|| { - type DoubleMap = DataDM; + type DoubleMap = self::frame_system::DataDM; let (key1, key2) = (11, 13); @@ -1278,8 +1362,8 @@ pub mod tests { #[test] fn double_map_try_mutate_exists_should_work() { new_test_ext().execute_with(|| { - type DoubleMap = DataDM; - type TestResult = result::Result<(), &'static str>; + type DoubleMap = self::frame_system::DataDM; + type TestResult = Result<(), &'static str>; let (key1, key2) = (11, 13); @@ -1310,15 +1394,8 @@ pub mod tests { fn expected_metadata() -> PalletStorageMetadataIR { PalletStorageMetadataIR { - prefix: "Test", + prefix: "System", entries: vec![ - StorageEntryMetadataIR { - name: "Value", - modifier: StorageEntryModifierIR::Default, - ty: StorageEntryTypeIR::Plain(scale_info::meta_type::()), - default: vec![0, 0, 0, 0, 0, 0, 0, 0], - docs: vec![], - }, StorageEntryMetadataIR { name: "Data", modifier: StorageEntryModifierIR::Default, @@ -1422,7 +1499,7 @@ pub mod tests { #[test] fn store_metadata() { - let metadata = Module::::storage_metadata(); + let metadata = Pallet::::storage_metadata(); pretty_assertions::assert_eq!(expected_metadata(), metadata); } @@ -1441,12 +1518,6 @@ pub mod tests { assert_eq!(300, StorageParameter::get()); }) } - - parameter_types! { - pub const BlockHashCount: u64 = 250; - pub static Members: Vec = vec![]; - pub const Foo: Option = None; - } } /// Prelude to be used alongside pallet macro, for ease of use. diff --git a/frame/support/src/storage/generator/double_map.rs b/frame/support/src/storage/generator/double_map.rs index 5763a472cd570..5da68873b10e6 100644 --- a/frame/support/src/storage/generator/double_map.rs +++ b/frame/support/src/storage/generator/double_map.rs @@ -514,43 +514,12 @@ where mod test_iterators { use crate::{ hash::StorageHasher, - storage::{generator::StorageDoubleMap, unhashed, IterableStorageDoubleMap}, + storage::{ + generator::{tests::*, StorageDoubleMap}, + unhashed, + }, }; - use codec::{Decode, Encode}; - - pub trait Config: 'static { - 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::RuntimeOrigin, system=self {} - } - - #[derive(PartialEq, Eq, Clone, Encode, Decode)] - struct NoDef(u32); - - crate::decl_storage! { - trait Store for Module as Test { - DoubleMap: double_map hasher(blake2_128_concat) u16, hasher(twox_64_concat) u32 => u64; - } - } - - fn key_before_prefix(mut prefix: Vec) -> Vec { - let last = prefix.iter_mut().last().unwrap(); - assert!(*last != 0, "mock function not implemented for this prefix"); - *last -= 1; - prefix - } - - fn key_after_prefix(mut prefix: Vec) -> Vec { - let last = prefix.iter_mut().last().unwrap(); - assert!(*last != 255, "mock function not implemented for this prefix"); - *last += 1; - prefix - } + use codec::Encode; #[test] fn double_map_iter_from() { @@ -589,6 +558,8 @@ mod test_iterators { #[test] fn double_map_reversible_reversible_iteration() { sp_io::TestExternalities::default().execute_with(|| { + type DoubleMap = self::frame_system::DoubleMap; + // All map iterator let prefix = DoubleMap::prefix_hash(); diff --git a/frame/support/src/storage/generator/map.rs b/frame/support/src/storage/generator/map.rs index fb499384f1506..3b36b9bddb704 100644 --- a/frame/support/src/storage/generator/map.rs +++ b/frame/support/src/storage/generator/map.rs @@ -349,43 +349,12 @@ impl> storage::StorageMap mod test_iterators { use crate::{ hash::StorageHasher, - storage::{generator::StorageMap, unhashed, IterableStorageMap}, + storage::{ + generator::{tests::*, StorageMap}, + unhashed, + }, }; - use codec::{Decode, Encode}; - - pub trait Config: 'static { - 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::RuntimeOrigin, system=self {} - } - - #[derive(PartialEq, Eq, Clone, Encode, Decode)] - struct NoDef(u32); - - crate::decl_storage! { - trait Store for Module as Test { - Map: map hasher(blake2_128_concat) u16 => u64; - } - } - - fn key_before_prefix(mut prefix: Vec) -> Vec { - let last = prefix.iter_mut().last().unwrap(); - assert!(*last != 0, "mock function not implemented for this prefix"); - *last -= 1; - prefix - } - - fn key_after_prefix(mut prefix: Vec) -> Vec { - let last = prefix.iter_mut().last().unwrap(); - assert!(*last != 255, "mock function not implemented for this prefix"); - *last += 1; - prefix - } + use codec::Encode; #[test] fn map_iter_from() { @@ -413,6 +382,8 @@ mod test_iterators { #[test] fn map_reversible_reversible_iteration() { sp_io::TestExternalities::default().execute_with(|| { + type Map = self::frame_system::Map; + // All map iterator let prefix = Map::prefix_hash(); diff --git a/frame/support/src/storage/generator/mod.rs b/frame/support/src/storage/generator/mod.rs index 2da612b24de8f..568d400129689 100644 --- a/frame/support/src/storage/generator/mod.rs +++ b/frame/support/src/storage/generator/mod.rs @@ -35,47 +35,123 @@ pub use nmap::StorageNMap; pub use value::StorageValue; #[cfg(test)] -#[allow(dead_code)] mod tests { + use codec::Encode; + use sp_io::TestExternalities; + use sp_runtime::{generic, traits::BlakeTwo256, BuildStorage}; + use crate::{ assert_noop, assert_ok, - storage::{generator::StorageValue, unhashed, IterableStorageMap}, + storage::{generator::StorageValue, unhashed}, }; - use codec::Encode; - use sp_io::TestExternalities; - struct Runtime; + #[crate::pallet] + pub mod frame_system { + #[allow(unused)] + use super::{frame_system, frame_system::pallet_prelude::*}; + pub use crate::dispatch::RawOrigin; + use crate::pallet_prelude::*; + + #[pallet::pallet] + pub struct Pallet(PhantomData); + + #[pallet::config] + #[pallet::disable_frame_system_supertrait_check] + pub trait Config: 'static { + type BlockNumber; + type AccountId; + type BaseCallFilter: crate::traits::Contains; + type RuntimeOrigin; + type RuntimeCall; + type PalletInfo: crate::traits::PalletInfo; + type DbWeight: Get; + } + + #[pallet::origin] + pub type Origin = RawOrigin<::AccountId>; + + #[pallet::error] + pub enum Error { + /// Required by construct_runtime + CallFiltered, + } + + #[pallet::call] + impl Pallet {} + + #[pallet::storage] + pub type Value = StorageValue<_, (u64, u64), ValueQuery>; - pub trait Config: 'static { - type RuntimeOrigin; - type BlockNumber; - type PalletInfo: crate::traits::PalletInfo; - type DbWeight: crate::traits::Get; + #[pallet::storage] + pub type Map = StorageMap<_, Blake2_128Concat, u16, u64, ValueQuery>; + + #[pallet::storage] + pub type NumberMap = StorageMap<_, Identity, u32, u64, ValueQuery>; + + #[pallet::storage] + pub type DoubleMap = + StorageDoubleMap<_, Blake2_128Concat, u16, Twox64Concat, u32, u64, ValueQuery>; + + #[pallet::storage] + pub type NMap = StorageNMap< + _, + (storage::Key, storage::Key), + u64, + ValueQuery, + >; + + pub mod pallet_prelude { + pub type OriginFor = ::RuntimeOrigin; + } } - impl Config for Runtime { - type RuntimeOrigin = u32; - type BlockNumber = u32; - type PalletInfo = crate::tests::PanicPalletInfo; + type BlockNumber = u32; + type AccountId = u32; + type Header = generic::Header; + type UncheckedExtrinsic = generic::UncheckedExtrinsic; + type Block = generic::Block; + + crate::construct_runtime!( + pub enum Runtime + where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: self::frame_system, + } + ); + + impl self::frame_system::Config for Runtime { + type BlockNumber = BlockNumber; + type AccountId = AccountId; + type BaseCallFilter = crate::traits::Everything; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type PalletInfo = PalletInfo; type DbWeight = (); } - decl_module! { - pub struct Module for enum Call where origin: T::RuntimeOrigin, system=self {} + pub fn key_before_prefix(mut prefix: Vec) -> Vec { + let last = prefix.iter_mut().last().unwrap(); + assert_ne!(*last, 0, "mock function not implemented for this prefix"); + *last -= 1; + prefix } - crate::decl_storage! { - trait Store for Module as Runtime { - Value get(fn value) config(): (u64, u64); - NumberMap: map hasher(identity) u32 => u64; - DoubleMap: double_map hasher(identity) u32, hasher(identity) u32 => u64; - } + pub fn key_after_prefix(mut prefix: Vec) -> Vec { + let last = prefix.iter_mut().last().unwrap(); + assert_ne!(*last, 255, "mock function not implemented for this prefix"); + *last += 1; + prefix } #[test] fn value_translate_works() { let t = GenesisConfig::default().build_storage().unwrap(); TestExternalities::new(t).execute_with(|| { + type Value = self::frame_system::Value; + // put the old value `1111u32` in the storage. let key = Value::storage_value_final_key(); unhashed::put_raw(&key, &1111u32.encode()); @@ -96,7 +172,9 @@ mod tests { fn map_translate_works() { let t = GenesisConfig::default().build_storage().unwrap(); TestExternalities::new(t).execute_with(|| { - // start with a map of u32 -> u32. + type NumberMap = self::frame_system::NumberMap; + + // start with a map of u32 -> u64. for i in 0u32..100u32 { unhashed::put(&NumberMap::hashed_key_for(&i), &(i as u64)); } @@ -125,6 +203,10 @@ mod tests { fn try_mutate_works() { let t = GenesisConfig::default().build_storage().unwrap(); TestExternalities::new(t).execute_with(|| { + type Value = self::frame_system::Value; + type NumberMap = self::frame_system::NumberMap; + type DoubleMap = self::frame_system::DoubleMap; + assert_eq!(Value::get(), (0, 0)); assert_eq!(NumberMap::get(0), 0); assert_eq!(DoubleMap::get(0, 0), 0); diff --git a/frame/support/src/storage/generator/nmap.rs b/frame/support/src/storage/generator/nmap.rs index 21fe7b41eda99..5d3d689aa98a6 100755 --- a/frame/support/src/storage/generator/nmap.rs +++ b/frame/support/src/storage/generator/nmap.rs @@ -462,43 +462,12 @@ impl> mod test_iterators { use crate::{ hash::StorageHasher, - storage::{generator::StorageNMap, unhashed, IterableStorageNMap}, + storage::{ + generator::{tests::*, StorageNMap}, + unhashed, + }, }; - use codec::{Decode, Encode}; - - pub trait Config: 'static { - 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::RuntimeOrigin, system=self {} - } - - #[derive(PartialEq, Eq, Clone, Encode, Decode)] - struct NoDef(u32); - - crate::decl_storage! { - trait Store for Module as Test { - NMap: nmap hasher(blake2_128_concat) u16, hasher(twox_64_concat) u32 => u64; - } - } - - fn key_before_prefix(mut prefix: Vec) -> Vec { - let last = prefix.iter_mut().last().unwrap(); - assert!(*last != 0, "mock function not implemented for this prefix"); - *last -= 1; - prefix - } - - fn key_after_prefix(mut prefix: Vec) -> Vec { - let last = prefix.iter_mut().last().unwrap(); - assert!(*last != 255, "mock function not implemented for this prefix"); - *last += 1; - prefix - } + use codec::Encode; #[test] fn n_map_iter_from() { @@ -545,22 +514,18 @@ mod test_iterators { #[test] fn n_map_double_map_identical_key() { sp_io::TestExternalities::default().execute_with(|| { + use crate::hash::{Blake2_128Concat, Twox64Concat}; + + type NMap = self::frame_system::NMap; + NMap::insert((1, 2), 50); let key_hash = NMap::hashed_key_for((1, 2)); { #[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); + type NMap = StorageDoubleMap; + + assert_eq!(NMap::get(1, 2), Some(50)); assert_eq!(NMap::hashed_key_for(1, 2), key_hash); } }); @@ -569,6 +534,8 @@ mod test_iterators { #[test] fn n_map_reversible_reversible_iteration() { sp_io::TestExternalities::default().execute_with(|| { + type NMap = self::frame_system::NMap; + // All map iterator let prefix = NMap::prefix_hash(); diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index 302d52f2f862b..8eac0996760e3 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -39,6 +39,7 @@ 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" +paste = "1.0.7" # full crypto array-bytes = { version = "4.1", optional = true } diff --git a/primitives/core/src/lib.rs b/primitives/core/src/lib.rs index efccd0378e95a..04f44631cb21c 100644 --- a/primitives/core/src/lib.rs +++ b/primitives/core/src/lib.rs @@ -53,6 +53,7 @@ pub mod hashing; pub use hashing::{blake2_128, blake2_256, keccak_256, twox_128, twox_256, twox_64}; pub mod crypto; pub mod hexdisplay; +pub use paste; pub mod defer; pub mod ecdsa; @@ -403,38 +404,62 @@ pub const MAX_POSSIBLE_ALLOCATION: u32 = 33554432; // 2^25 bytes, 32 MiB #[rustfmt::skip] macro_rules! generate_feature_enabled_macro { ( $macro_name:ident, $feature_name:meta, $d:tt ) => { - /// Enable/disable the given code depending on - #[doc = concat!("`", stringify!($feature_name), "`")] - /// being enabled for the crate or not. - /// - /// # Example - /// - /// ```nocompile - /// // Will add the code depending on the feature being enabled or not. - #[doc = concat!(stringify!($macro_name), "!( println!(\"Hello\") )")] - /// ``` - #[cfg($feature_name)] - #[macro_export] - macro_rules! $macro_name { - ( $d ( $d input:tt )* ) => { - $d ( $d input )* + $crate::paste::paste!{ + /// Enable/disable the given code depending on + #[doc = concat!("`", stringify!($feature_name), "`")] + /// being enabled for the crate or not. + /// + /// # Example + /// + /// ```nocompile + /// // Will add the code depending on the feature being enabled or not. + #[doc = concat!(stringify!($macro_name), "!( println!(\"Hello\") )")] + /// ``` + #[cfg($feature_name)] + #[macro_export] + macro_rules! [<_ $macro_name>] { + ( $d ( $d input:tt )* ) => { + $d ( $d input )* + } + } + + /// Enable/disable the given code depending on + #[doc = concat!("`", stringify!($feature_name), "`")] + /// being enabled for the crate or not. + /// + /// # Example + /// + /// ```nocompile + /// // Will add the code depending on the feature being enabled or not. + #[doc = concat!(stringify!($macro_name), "!( println!(\"Hello\") )")] + /// ``` + #[cfg(not($feature_name))] + #[macro_export] + macro_rules! [<_ $macro_name>] { + ( $d ( $d input:tt )* ) => {}; } - } - /// Enable/disable the given code depending on - #[doc = concat!("`", stringify!($feature_name), "`")] - /// being enabled for the crate or not. - /// - /// # Example - /// - /// ```nocompile - /// // Will add the code depending on the feature being enabled or not. - #[doc = concat!(stringify!($macro_name), "!( println!(\"Hello\") )")] - /// ``` - #[cfg(not($feature_name))] - #[macro_export] - macro_rules! $macro_name { - ( $d ( $d input:tt )* ) => {}; + // Work around for: + #[doc(hidden)] + pub use [<_ $macro_name>] as $macro_name; } }; } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[should_panic] + fn generate_feature_enabled_macro_panics() { + generate_feature_enabled_macro!(if_test, test, $); + if_test!(panic!("This should panic")); + } + + #[test] + fn generate_feature_enabled_macro_works() { + generate_feature_enabled_macro!(if_not_test, not(test), $); + if_not_test!(panic!("This should not panic")); + } +} diff --git a/primitives/runtime/src/lib.rs b/primitives/runtime/src/lib.rs index 2d959425e0f8e..0994dc21b31dd 100644 --- a/primitives/runtime/src/lib.rs +++ b/primitives/runtime/src/lib.rs @@ -1054,3 +1054,23 @@ mod tests { }); } } + +// NOTE: we have to test the sp_core stuff also from a different crate to check that the macro +// can access the sp_core crate. +#[cfg(test)] +mod sp_core_tests { + use super::*; + + #[test] + #[should_panic] + fn generate_feature_enabled_macro_panics() { + sp_core::generate_feature_enabled_macro!(if_test, test, $); + if_test!(panic!("This should panic")); + } + + #[test] + fn generate_feature_enabled_macro_works() { + sp_core::generate_feature_enabled_macro!(if_not_test, not(test), $); + if_not_test!(panic!("This should not panic")); + } +} From db6ebf564bcdfdfaf5fd026bb321de6f7d7e6fc0 Mon Sep 17 00:00:00 2001 From: gupnik <17176722+gupnik@users.noreply.github.com> Date: Tue, 25 Apr 2023 20:50:58 +0530 Subject: [PATCH 695/715] Removes ReportsByKindIndex (#13936) * Removes ReportsByKind * Minor build fixes * adds migration * Addresses review comment * Uses clear but weight check fails * Uses unique * Updates test to commit the change before migration * Uses reads_writes * ".git/.scripts/commands/fmt/fmt.sh" * Fixes build * Addresses review comments * ".git/.scripts/commands/fmt/fmt.sh" * fixes typo --------- Co-authored-by: command-bot <> --- frame/offences/src/lib.rs | 43 ++++--------- frame/offences/src/migration.rs | 103 ++++++++++++++++++++++++++++++-- frame/offences/src/mock.rs | 5 -- frame/offences/src/tests.rs | 49 +-------------- 4 files changed, 113 insertions(+), 87 deletions(-) diff --git a/frame/offences/src/lib.rs b/frame/offences/src/lib.rs index 96c7c119c2038..1c7ffeca71983 100644 --- a/frame/offences/src/lib.rs +++ b/frame/offences/src/lib.rs @@ -26,7 +26,9 @@ pub mod migration; mod mock; mod tests; -use codec::{Decode, Encode}; +use core::marker::PhantomData; + +use codec::Encode; use frame_support::weights::Weight; use sp_runtime::{traits::Hash, Perbill}; use sp_staking::{ @@ -43,12 +45,17 @@ type OpaqueTimeSlot = Vec; /// A type alias for a report identifier. type ReportIdOf = ::Hash; +const LOG_TARGET: &str = "runtime::offences"; + #[frame_support::pallet] pub mod pallet { use super::*; use frame_support::pallet_prelude::*; + const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); + #[pallet::pallet] + #[pallet::storage_version(STORAGE_VERSION)] #[pallet::without_storage_info] pub struct Pallet(_); @@ -85,21 +92,6 @@ pub mod pallet { ValueQuery, >; - /// Enumerates all reports of a kind along with the time they happened. - /// - /// All reports are sorted by the time of offence. - /// - /// Note that the actual type of this mapping is `Vec`, this is because values of - /// different types are not supported at the moment so we are doing the manual serialization. - #[pallet::storage] - pub type ReportsByKindIndex = StorageMap< - _, - Twox64Concat, - Kind, - Vec, // (O::TimeSlot, ReportIdOf) - ValueQuery, - >; - /// Events type. #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] @@ -190,7 +182,7 @@ impl Pallet { OffenceDetails { offender, reporters: reporters.clone() }, ); - storage.insert(time_slot, report_id); + storage.insert(report_id); } } @@ -225,7 +217,7 @@ struct TriageOutcome { struct ReportIndexStorage> { opaque_time_slot: OpaqueTimeSlot, concurrent_reports: Vec>, - same_kind_reports: Vec<(O::TimeSlot, ReportIdOf)>, + _phantom: PhantomData, } impl> ReportIndexStorage { @@ -233,30 +225,19 @@ impl> ReportIndexStorage { fn load(time_slot: &O::TimeSlot) -> Self { let opaque_time_slot = time_slot.encode(); - let same_kind_reports = ReportsByKindIndex::::get(&O::ID); - let same_kind_reports = - Vec::<(O::TimeSlot, ReportIdOf)>::decode(&mut &same_kind_reports[..]) - .unwrap_or_default(); - let concurrent_reports = >::get(&O::ID, &opaque_time_slot); - Self { opaque_time_slot, concurrent_reports, same_kind_reports } + Self { opaque_time_slot, concurrent_reports, _phantom: Default::default() } } /// Insert a new report to the index. - fn insert(&mut self, time_slot: &O::TimeSlot, report_id: ReportIdOf) { - // Insert the report id into the list while maintaining the ordering by the time - // slot. - let pos = self.same_kind_reports.partition_point(|(when, _)| when <= time_slot); - self.same_kind_reports.insert(pos, (time_slot.clone(), report_id)); - + fn insert(&mut self, report_id: ReportIdOf) { // Update the list of concurrent reports. self.concurrent_reports.push(report_id); } /// Dump the indexes to the storage. fn save(self) { - ReportsByKindIndex::::insert(&O::ID, self.same_kind_reports.encode()); >::insert( &O::ID, &self.opaque_time_slot, diff --git a/frame/offences/src/migration.rs b/frame/offences/src/migration.rs index 95b94ba87cc9c..07bd68407d378 100644 --- a/frame/offences/src/migration.rs +++ b/frame/offences/src/migration.rs @@ -15,11 +15,84 @@ // See the License for the specific language governing permissions and // limitations under the License. -use super::{Config, OffenceDetails, Perbill, SessionIndex}; -use frame_support::{pallet_prelude::ValueQuery, storage_alias, traits::Get, weights::Weight}; +use super::{Config, Kind, OffenceDetails, Pallet, Perbill, SessionIndex, LOG_TARGET}; +use frame_support::{ + dispatch::GetStorageVersion, + pallet_prelude::ValueQuery, + storage_alias, + traits::{Get, OnRuntimeUpgrade}, + weights::Weight, + Twox64Concat, +}; use sp_staking::offence::{DisableStrategy, OnOffenceHandler}; use sp_std::vec::Vec; +#[cfg(feature = "try-runtime")] +use frame_support::ensure; + +mod v0 { + use super::*; + + #[storage_alias] + pub type ReportsByKindIndex = StorageMap< + Pallet, + Twox64Concat, + Kind, + Vec, // (O::TimeSlot, ReportIdOf) + ValueQuery, + >; +} + +pub mod v1 { + use frame_support::traits::StorageVersion; + + use super::*; + + 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, "pallet_offences::MigrateToV1 migration can be deleted"); + + log::info!( + target: LOG_TARGET, + "Number of reports to refund and delete: {}", + v0::ReportsByKindIndex::::iter_keys().count() + ); + + Ok(Vec::new()) + } + + fn on_runtime_upgrade() -> Weight { + let onchain = Pallet::::on_chain_storage_version(); + + if onchain > 0 { + log::info!(target: LOG_TARGET, "pallet_offences::MigrateToV1 should be removed"); + return T::DbWeight::get().reads(1) + } + + let keys_removed = v0::ReportsByKindIndex::::clear(u32::MAX, None).unique as u64; + let weight = T::DbWeight::get().reads_writes(keys_removed, keys_removed); + + StorageVersion::new(1).put::>(); + + weight + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(_state: Vec) -> Result<(), &'static str> { + let onchain = Pallet::::on_chain_storage_version(); + ensure!(onchain == 1, "pallet_offences::MigrateToV1 needs to be run"); + ensure!( + v0::ReportsByKindIndex::::iter_keys().count() == 0, + "there are some dangling reports that need to be destroyed and refunded" + ); + Ok(()) + } + } +} + /// Type of data stored as a deferred offence type DeferredOffenceOf = ( Vec::AccountId, ::IdentificationTuple>>, @@ -36,7 +109,7 @@ type DeferredOffences = pub fn remove_deferred_storage() -> Weight { let mut weight = T::DbWeight::get().reads_writes(1, 1); let deferred = >::take(); - log::info!(target: "runtime::offences", "have {} deferred offences, applying.", deferred.len()); + log::info!(target: LOG_TARGET, "have {} deferred offences, applying.", deferred.len()); for (offences, perbill, session) in deferred.iter() { let consumed = T::OnOffenceHandler::on_offence( offences, @@ -53,10 +126,32 @@ pub fn remove_deferred_storage() -> Weight { #[cfg(test)] mod test { use super::*; - use crate::mock::{new_test_ext, with_on_offence_fractions, Runtime as T}; + use crate::mock::{new_test_ext, with_on_offence_fractions, Runtime as T, KIND}; + use codec::Encode; use sp_runtime::Perbill; use sp_staking::offence::OffenceDetails; + #[test] + fn migration_to_v1_works() { + let mut ext = new_test_ext(); + + ext.execute_with(|| { + >::insert(KIND, 2u32.encode()); + assert!(>::iter_values().count() > 0); + }); + + ext.commit_all().unwrap(); + + ext.execute_with(|| { + assert_eq!( + v1::MigrateToV1::::on_runtime_upgrade(), + ::DbWeight::get().reads_writes(1, 1), + ); + + assert!(>::iter_values().count() == 0); + }) + } + #[test] fn should_resubmit_deferred_offences() { new_test_ext().execute_with(|| { diff --git a/frame/offences/src/mock.rs b/frame/offences/src/mock.rs index 27e1da8c4e636..17480be76c1d8 100644 --- a/frame/offences/src/mock.rs +++ b/frame/offences/src/mock.rs @@ -164,8 +164,3 @@ impl offence::Offence for Offence { Perbill::from_percent(5 + offenders_count * 100 / self.validator_set_count) } } - -/// Create the report id for the given `offender` and `time_slot` combination. -pub fn report_id(time_slot: u128, offender: u64) -> H256 { - Offences::report_id::(&time_slot, &offender) -} diff --git a/frame/offences/src/tests.rs b/frame/offences/src/tests.rs index 81f0f44f1b939..d525c7c3ab1d9 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, Offence, Offences, - RuntimeEvent, System, KIND, + new_test_ext, offence_reports, with_on_offence_fractions, Offence, Offences, RuntimeEvent, + System, KIND, }; use frame_system::{EventRecord, Phase}; use sp_runtime::Perbill; @@ -245,48 +245,3 @@ fn should_properly_count_offences() { ); }); } - -/// We insert offences in sorted order using the time slot in the `same_kind_reports`. -/// This test ensures that it works as expected. -#[test] -fn should_properly_sort_offences() { - new_test_ext().execute_with(|| { - // given - let time_slot = 42; - assert_eq!(offence_reports(KIND, time_slot), vec![]); - - let offence1 = Offence { validator_set_count: 5, time_slot, offenders: vec![5] }; - let offence2 = Offence { validator_set_count: 5, time_slot, offenders: vec![4] }; - let offence3 = - Offence { validator_set_count: 5, time_slot: time_slot + 1, offenders: vec![6, 7] }; - let offence4 = - Offence { validator_set_count: 5, time_slot: time_slot - 1, offenders: vec![3] }; - Offences::report_offence(vec![], offence1).unwrap(); - with_on_offence_fractions(|f| { - assert_eq!(f.clone(), vec![Perbill::from_percent(25)]); - f.clear(); - }); - - // when - // report for the second time - Offences::report_offence(vec![], offence2).unwrap(); - Offences::report_offence(vec![], offence3).unwrap(); - Offences::report_offence(vec![], offence4).unwrap(); - - // then - let same_kind_reports = Vec::<(u128, sp_core::H256)>::decode( - &mut &crate::ReportsByKindIndex::::get(KIND)[..], - ) - .unwrap(); - assert_eq!( - same_kind_reports, - vec![ - (time_slot - 1, report_id(time_slot - 1, 3)), - (time_slot, report_id(time_slot, 5)), - (time_slot, report_id(time_slot, 4)), - (time_slot + 1, report_id(time_slot + 1, 6)), - (time_slot + 1, report_id(time_slot + 1, 7)), - ] - ); - }); -} From c4f425b062a749010b724a3b74e8d93b6f9b01d8 Mon Sep 17 00:00:00 2001 From: Squirrel Date: Tue, 25 Apr 2023 21:48:37 +0100 Subject: [PATCH 696/715] Allow missing docs for autogen weights. (#14011) --- .maintain/frame-weight-template.hbs | 1 + utils/frame/benchmarking-cli/src/pallet/template.hbs | 1 + 2 files changed, 2 insertions(+) diff --git a/.maintain/frame-weight-template.hbs b/.maintain/frame-weight-template.hbs index 0df6bef5d3bee..38bb4de26362f 100644 --- a/.maintain/frame-weight-template.hbs +++ b/.maintain/frame-weight-template.hbs @@ -15,6 +15,7 @@ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] +#![allow(missing_docs)] use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; diff --git a/utils/frame/benchmarking-cli/src/pallet/template.hbs b/utils/frame/benchmarking-cli/src/pallet/template.hbs index f852e773ce7d7..85b0e86caad96 100644 --- a/utils/frame/benchmarking-cli/src/pallet/template.hbs +++ b/utils/frame/benchmarking-cli/src/pallet/template.hbs @@ -15,6 +15,7 @@ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] +#![allow(missing_docs)] use frame_support::{traits::Get, weights::Weight}; use core::marker::PhantomData; From af504bc374db82e0d764f1393f4faee42929e4ad Mon Sep 17 00:00:00 2001 From: Sasha Gryaznov Date: Wed, 26 Apr 2023 14:27:13 +0300 Subject: [PATCH 697/715] [contracts] Port host functions to Weight V2 and storage deposit limit (#13565) * added [unstable][seal2] call() * updated test to cover new seal_call proof_limit * docs updated * add [seal2][unstable] instantiate() and test * add [seal2][unstable] weight_to_fee() + docs and test * add [seal2][unstable] gas_left() + docs and test * update benchmarks * add DefaultDepositLimit to pallet Config * specify deposit limit for nested call add test for nested call deposit limit save: separate deposit limit for nested calls * specify deposit limit for nested instantiate save: works with test cleaned up debugging outputs * update benchmarks * added missing fixtures * fix benches * pass explicit deposit limit to storage bench * explicit deposit limit for another set_storage bench * add more deposit limit for storage benches * moving to simplified benchmarks * moved to simplified benchmarks * fix seal_weight_to_fee bench * fix seal_instantiate benchmark * doc typo fix * default dl for benchmarking more dl for tests dl for tests to max deposit_limit fix in instantiate bench fix instantiate bench fix instantiate benchmark fix instantiate bench again remove dbg fix seal bench again fixing it still seal_instantiate zero deposit less runs to check if deposit enough try try 2 try 3 try 4 * max_runtime_mem to Schedule limits * add default deposit limit fallback check to test * weight params renaming * fmt * Update frame/contracts/src/benchmarking/mod.rs Co-authored-by: PG Herveou * prettify inputs in tests * typestate param refactored --------- Co-authored-by: PG Herveou --- bin/node/runtime/src/lib.rs | 2 + frame/contracts/README.md | 8 +- frame/contracts/fixtures/call_with_limit.wat | 21 +- frame/contracts/fixtures/caller_contract.wat | 137 +++++--- .../fixtures/create_storage_and_call.wat | 13 +- .../create_storage_and_instantiate.wat | 66 ++++ .../fixtures/{store.wat => store_call.wat} | 0 frame/contracts/fixtures/store_deploy.wat | 45 +++ frame/contracts/src/benchmarking/mod.rs | 79 +++-- frame/contracts/src/exec.rs | 124 +++++-- frame/contracts/src/lib.rs | 18 +- frame/contracts/src/schedule.rs | 5 + frame/contracts/src/storage/meter.rs | 80 +++-- frame/contracts/src/tests.rs | 327 ++++++++++++++---- frame/contracts/src/wasm/mod.rs | 48 +-- frame/contracts/src/wasm/runtime.rs | 249 ++++++++++--- 16 files changed, 948 insertions(+), 274 deletions(-) create mode 100644 frame/contracts/fixtures/create_storage_and_instantiate.wat rename frame/contracts/fixtures/{store.wat => store_call.wat} (100%) create mode 100644 frame/contracts/fixtures/store_deploy.wat diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 5722603fe62a5..766bc9515b8ab 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1215,6 +1215,7 @@ impl pallet_tips::Config for Runtime { parameter_types! { pub const DepositPerItem: Balance = deposit(1, 0); pub const DepositPerByte: Balance = deposit(0, 1); + pub const DefaultDepositLimit: Balance = deposit(1024, 1024 * 1024); pub Schedule: pallet_contracts::Schedule = Default::default(); } @@ -1233,6 +1234,7 @@ impl pallet_contracts::Config for Runtime { type CallFilter = Nothing; type DepositPerItem = DepositPerItem; type DepositPerByte = DepositPerByte; + type DefaultDepositLimit = DefaultDepositLimit; type CallStack = [pallet_contracts::Frame; 5]; type WeightPrice = pallet_transaction_payment::Pallet; type WeightInfo = pallet_contracts::weights::SubstrateWeight; diff --git a/frame/contracts/README.md b/frame/contracts/README.md index cf89c9514142d..13c5e7253c1d8 100644 --- a/frame/contracts/README.md +++ b/frame/contracts/README.md @@ -1,6 +1,6 @@ -# Contract Module +# Contracts Module -The Contract module provides functionality for the runtime to deploy and execute WebAssembly smart-contracts. +The Contracts module provides functionality for the runtime to deploy and execute WebAssembly smart-contracts. - [`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) @@ -63,9 +63,9 @@ directly. This makes sure that by default `pallet-contracts` does not expose any 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` +An indeterministic code can be deployed on-chain by passing `Determinism::Relaxed` to `upload_code`. A deterministic 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 +is ran by using `bare_call` and passing `Determinism::Relaxed` to it. **Never use this argument when the contract is called from an on-chain transaction.** ## Interface diff --git a/frame/contracts/fixtures/call_with_limit.wat b/frame/contracts/fixtures/call_with_limit.wat index abb8708267271..04da59551a8ce 100644 --- a/frame/contracts/fixtures/call_with_limit.wat +++ b/frame/contracts/fixtures/call_with_limit.wat @@ -1,8 +1,8 @@ -;; This expects [account_id, gas_limit] as input and calls the account_id with the supplied gas_limit. +;; This expects [account_id, ref_time, proof_size] as input and calls the account_id with the supplied 2D Weight limit. ;; It returns the result of the call as output data. (module (import "seal0" "seal_input" (func $seal_input (param i32 i32))) - (import "seal0" "seal_call" (func $seal_call (param i32 i32 i64 i32 i32 i32 i32 i32 i32) (result i32))) + (import "seal2" "call" (func $seal_call (param i32 i32 i64 i64 i32 i32 i32 i32 i32 i32) (result i32))) (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32))) (import "env" "memory" (memory 1 1)) @@ -13,24 +13,25 @@ (func (export "deploy")) (func (export "call") - ;; Receive the encoded call + gas_limit + ;; Receive the encoded account_id, ref_time, proof_size (call $seal_input (i32.const 4) ;; Pointer to the input buffer - (i32.const 0) ;; Size of the length buffer + (i32.const 0) ;; Pointer to the length of the input buffer ) (i32.store (i32.const 0) (call $seal_call + (i32.const 0) ;; Set no flag. (i32.const 4) ;; Pointer to "callee" address. - (i32.const 32) ;; Length of "callee" address. - (i64.load (i32.const 36)) ;; How much gas to devote for the execution. + (i64.load (i32.const 36)) ;; How much ref_time to devote for the execution. + (i64.load (i32.const 44)) ;; How much proof_size to devote for the execution. + (i32.const 0xffffffff) ;; u32 max sentinel value: pass no deposit limit. (i32.const 0) ;; Pointer to the buffer with value to transfer - (i32.const 0) ;; Length of the buffer with value to transfer. (i32.const 0) ;; Pointer to input data buffer address - (i32.const 0) ;; Length of input data buffer + (i32.const 0) ;; Length of input data buffer (i32.const 0xffffffff) ;; u32 max sentinel value: do not copy output - (i32.const 0) ;; Ptr to output buffer len - ) + (i32.const 0) ;; Length is ignored in this case + ) ) (call $seal_return (i32.const 0) (i32.const 0) (i32.const 4)) ) diff --git a/frame/contracts/fixtures/caller_contract.wat b/frame/contracts/fixtures/caller_contract.wat index f9caf49f29ca8..929171b9a26f6 100644 --- a/frame/contracts/fixtures/caller_contract.wat +++ b/frame/contracts/fixtures/caller_contract.wat @@ -1,9 +1,9 @@ (module (import "seal0" "seal_input" (func $seal_input (param i32 i32))) (import "seal0" "seal_balance" (func $seal_balance (param i32 i32))) - (import "seal0" "seal_call" (func $seal_call (param i32 i32 i64 i32 i32 i32 i32 i32 i32) (result i32))) - (import "seal0" "seal_instantiate" (func $seal_instantiate - (param i32 i32 i64 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32) (result i32) + (import "seal2" "call" (func $seal_call (param i32 i32 i64 i64 i32 i32 i32 i32 i32 i32) (result i32))) + (import "seal2" "instantiate" (func $seal_instantiate + (param i32 i64 i64 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32) (result i32) )) (import "env" "memory" (memory 1 1)) @@ -43,18 +43,18 @@ (set_local $exit_code (call $seal_instantiate (i32.const 24) ;; Pointer to the code hash. - (i32.const 32) ;; Length of the code hash. - (i64.const 0) ;; How much gas to devote for the execution. 0 = all. + (i64.const 0) ;; How much ref_time weight to devote for the execution. 0 = all. + (i64.const 0) ;; How much proof_size weight to devote for the execution. 0 = all. + (i32.const 0xffffffff) ;; u32 max sentinel value: pass no deposit limit. (i32.const 0) ;; Pointer to the buffer with value to transfer - (i32.const 8) ;; Length of the buffer with value to transfer. (i32.const 9) ;; Pointer to input data buffer address (i32.const 7) ;; Length of input data buffer - (i32.const 4294967295) ;; u32 max sentinel value: do not copy address - (i32.const 0) ;; Length is ignored in this case + (i32.const 4294967295) ;; u32 max sentinel value: do not copy address + (i32.const 0) ;; Length is ignored in this case (i32.const 4294967295) ;; u32 max sentinel value: do not copy output - (i32.const 0) ;; Length is ignored in this case - (i32.const 0) ;; salt_ptr - (i32.const 0) ;; salt_le + (i32.const 0) ;; Length is ignored in this case + (i32.const 0) ;; salt_ptr + (i32.const 0) ;; salt_le ) ) @@ -63,22 +63,47 @@ (i32.eq (get_local $exit_code) (i32.const 2)) ;; ReturnCode::CalleeReverted ) - ;; Fail to deploy the contract due to insufficient gas. + ;; Fail to deploy the contract due to insufficient ref_time weight. (set_local $exit_code (call $seal_instantiate (i32.const 24) ;; Pointer to the code hash. - (i32.const 32) ;; Length of the code hash. - (i64.const 1) ;; Supply too little gas + (i64.const 1) ;; Supply too little ref_time weight + (i64.const 0) ;; How much proof_size weight to devote for the execution. 0 = all. + (i32.const 0xffffffff) ;; u32 max sentinel value: pass no deposit limit. (i32.const 0) ;; Pointer to the buffer with value to transfer - (i32.const 8) ;; Length of the buffer with value to transfer. (i32.const 8) ;; Pointer to input data buffer address (i32.const 8) ;; Length of input data buffer (i32.const 4294967295) ;; u32 max sentinel value: do not copy address - (i32.const 0) ;; Length is ignored in this case + (i32.const 0) ;; Length is ignored in this case (i32.const 4294967295) ;; u32 max sentinel value: do not copy output - (i32.const 0) ;; Length is ignored in this case - (i32.const 0) ;; salt_ptr - (i32.const 0) ;; salt_le + (i32.const 0) ;; Length is ignored in this case + (i32.const 0) ;; salt_ptr + (i32.const 0) ;; salt_le + + ) + ) + + ;; Check for special trap exit status. + (call $assert + (i32.eq (get_local $exit_code) (i32.const 1)) ;; ReturnCode::CalleeTrapped + ) + + ;; Fail to deploy the contract due to insufficient ref_time weight. + (set_local $exit_code + (call $seal_instantiate + (i32.const 24) ;; Pointer to the code hash. + (i64.const 0) ;; How much ref_time weight to devote for the execution. 0 = all. + (i64.const 1) ;; Supply too little proof_size weight + (i32.const 0xffffffff) ;; u32 max sentinel value: pass no deposit limit. + (i32.const 0) ;; Pointer to the buffer with value to transfer + (i32.const 8) ;; Pointer to input data buffer address + (i32.const 8) ;; Length of input data buffer + (i32.const 4294967295) ;; u32 max sentinel value: do not copy address + (i32.const 0) ;; Length is ignored in this case + (i32.const 4294967295) ;; u32 max sentinel value: do not copy output + (i32.const 0) ;; Length is ignored in this case + (i32.const 0) ;; salt_ptr + (i32.const 0) ;; salt_le ) ) @@ -98,18 +123,18 @@ (set_local $exit_code (call $seal_instantiate (i32.const 24) ;; Pointer to the code hash. - (i32.const 32) ;; Length of the code hash. - (i64.const 0) ;; How much gas to devote for the execution. 0 = all. + (i64.const 0) ;; How much ref_time weight to devote for the execution. 0 = all. + (i64.const 0) ;; How much proof_size weight to devote for the execution. 0 = all. + (i32.const 0xffffffff) ;; u32 max sentinel value: pass no deposit limit. (i32.const 0) ;; Pointer to the buffer with value to transfer - (i32.const 8) ;; Length of the buffer with value to transfer. (i32.const 8) ;; Pointer to input data buffer address (i32.const 8) ;; Length of input data buffer - (i32.const 16) ;; Pointer to the address output buffer - (i32.sub (get_local $sp) (i32.const 4)) ;; Pointer to the address buffer length - (i32.const 4294967295) ;; u32 max sentinel value: do not copy output - (i32.const 0) ;; Length is ignored in this case - (i32.const 0) ;; salt_ptr - (i32.const 0) ;; salt_le + (i32.const 16) ;; Pointer to the address output buffer + (i32.sub (get_local $sp) (i32.const 4)) ;; Pointer to the address buffer length + (i32.const 4294967295) ;; u32 max sentinel value: do not copy output + (i32.const 0) ;; Length is ignored in this case + (i32.const 0) ;; salt_ptr + (i32.const 0) ;; salt_le ) ) @@ -139,15 +164,16 @@ ;; Call the new contract and expect it to return failing exit code. (set_local $exit_code (call $seal_call + (i32.const 0) ;; Set no flag (i32.const 16) ;; Pointer to "callee" address. - (i32.const 32) ;; Length of "callee" address. - (i64.const 0) ;; How much gas to devote for the execution. 0 = all. + (i64.const 0) ;; How much ref_time weight to devote for the execution. 0 = all. + (i64.const 0) ;; How much proof_size weight to devote for the execution. 0 = all. + (i32.const 0xffffffff) ;; u32 max sentinel value: pass no deposit limit. (i32.const 0) ;; Pointer to the buffer with value to transfer - (i32.const 8) ;; Length of the buffer with value to transfer. (i32.const 9) ;; Pointer to input data buffer address (i32.const 7) ;; Length of input data buffer - (i32.sub (get_local $sp) (i32.const 4)) ;; Ptr to output buffer - (i32.sub (get_local $sp) (i32.const 8)) ;; Ptr to output buffer len + (i32.sub (get_local $sp) (i32.const 4)) ;; Ptr to output buffer + (i32.sub (get_local $sp) (i32.const 8)) ;; Ptr to output buffer len ) ) @@ -167,18 +193,40 @@ ) ) - ;; Fail to call the contract due to insufficient gas. + ;; Fail to call the contract due to insufficient ref_time weight. (set_local $exit_code (call $seal_call + (i32.const 0) ;; Set no flag (i32.const 16) ;; Pointer to "callee" address. - (i32.const 32) ;; Length of "callee" address. - (i64.const 1) ;; Supply too little gas + (i64.const 1) ;; Supply too little ref_time weight + (i64.const 0) ;; How much proof_size weight to devote for the execution. 0 = all. + (i32.const 0xffffffff) ;; u32 max sentinel value: pass no deposit limit. (i32.const 0) ;; Pointer to the buffer with value to transfer - (i32.const 8) ;; Length of the buffer with value to transfer. (i32.const 8) ;; Pointer to input data buffer address (i32.const 8) ;; Length of input data buffer - (i32.const 4294967295) ;; u32 max sentinel value: do not copy output - (i32.const 0) ;; Length is ignored in this cas + (i32.const 4294967295) ;; u32 max sentinel value: do not copy output + (i32.const 0) ;; Length is ignored in this cas + ) + ) + + ;; Check for special trap exit status. + (call $assert + (i32.eq (get_local $exit_code) (i32.const 1)) ;; ReturnCode::CalleeTrapped + ) + + ;; Fail to call the contract due to insufficient proof_size weight. + (set_local $exit_code + (call $seal_call + (i32.const 0) ;; Set no flag + (i32.const 16) ;; Pointer to "callee" address. + (i64.const 0) ;; How much ref_time weight to devote for the execution. 0 = all. + (i64.const 1) ;; Supply too little proof_size weight + (i32.const 0xffffffff) ;; u32 max sentinel value: pass no deposit limit. + (i32.const 0) ;; Pointer to the buffer with value to transfer + (i32.const 8) ;; Pointer to input data buffer address + (i32.const 8) ;; Length of input data buffer + (i32.const 4294967295) ;; u32 max sentinel value: do not copy output + (i32.const 0) ;; Length is ignored in this cas ) ) @@ -202,15 +250,16 @@ ;; Call the contract successfully. (set_local $exit_code (call $seal_call + (i32.const 0) ;; Set no flag (i32.const 16) ;; Pointer to "callee" address. - (i32.const 32) ;; Length of "callee" address. - (i64.const 0) ;; How much gas to devote for the execution. 0 = all. + (i64.const 0) ;; How much ref_time weight to devote for the execution. 0 = all. + (i64.const 0) ;; How much proof_size weight to devote for the execution. 0 = all. + (i32.const 0xffffffff) ;; u32 max sentinel value: pass no deposit limit. (i32.const 0) ;; Pointer to the buffer with value to transfer - (i32.const 8) ;; Length of the buffer with value to transfer. (i32.const 8) ;; Pointer to input data buffer address (i32.const 8) ;; Length of input data buffer - (i32.sub (get_local $sp) (i32.const 4)) ;; Ptr to output buffer - (i32.sub (get_local $sp) (i32.const 8)) ;; Ptr to output buffer len + (i32.sub (get_local $sp) (i32.const 4)) ;; Ptr to output buffer + (i32.sub (get_local $sp) (i32.const 8)) ;; Ptr to output buffer len ) ) diff --git a/frame/contracts/fixtures/create_storage_and_call.wat b/frame/contracts/fixtures/create_storage_and_call.wat index 2a1e53f7ce08a..5592e7e96a980 100644 --- a/frame/contracts/fixtures/create_storage_and_call.wat +++ b/frame/contracts/fixtures/create_storage_and_call.wat @@ -2,7 +2,7 @@ (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 "seal2" "call" (func $seal_call (param i32 i32 i64 i64 i32 i32 i32 i32 i32 i32) (result i32))) (import "env" "memory" (memory 1 1)) (func $assert (param i32) @@ -20,7 +20,10 @@ ;; store length of input buffer (i32.store (i32.const 0) (i32.const 512)) - ;; copy input at address 4 + ;; copy input at address 4: + ;; first 4 bytes for the size of the storage to be created in callee + ;; next 32 bytes are for the callee address + ;; next bytes for the encoded deposit limit (call $seal_input (i32.const 4) (i32.const 0)) ;; create 4 byte of storage before calling @@ -34,8 +37,10 @@ (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 8) ;; Pointer to "callee" address + (i64.const 0) ;; How much ref_time to devote for the execution. 0 = all + (i64.const 0) ;; How much proof_limit to devote for the execution. 0 = all + (i32.const 40) ;; Pointer to the storage deposit limit (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 diff --git a/frame/contracts/fixtures/create_storage_and_instantiate.wat b/frame/contracts/fixtures/create_storage_and_instantiate.wat new file mode 100644 index 0000000000000..cd7202478437b --- /dev/null +++ b/frame/contracts/fixtures/create_storage_and_instantiate.wat @@ -0,0 +1,66 @@ +;; This instantiates another contract and passes some input to its constructor. +(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 "seal2" "instantiate" (func $seal_instantiate + (param i32 i64 i64 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32) (result i32) + )) + (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32))) + (import "env" "memory" (memory 1 1)) + + ;; [0, 8) send 10_000 balance + (data (i32.const 48) "\10\27\00\00\00\00\00\00") + + (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)) + ;; store length of contract address + (i32.store (i32.const 84) (i32.const 32)) + + ;; copy input at address 4 + (call $seal_input (i32.const 4) (i32.const 0)) + + ;; memory layout is: + ;; [0,4): size of input buffer + ;; [4,8): size of the storage to be created in callee + ;; [8,40): the code hash of the contract to instantiate + ;; [40,48): for the encoded deposit limit + ;; [48,52): value to transfer + ;; [52,84): address of the deployed contract + ;; [84,88): len of the address + + ;; instantiate a contract + (call $assert (i32.eqz +;; (i32.store +;; (i32.const 64) + (call $seal_instantiate + (i32.const 8) ;; Pointer to the code hash. + (i64.const 0) ;; How much ref_time weight to devote for the execution. 0 = all. + (i64.const 0) ;; How much proof_size weight to devote for the execution. 0 = all. + (i32.const 40) ;; Pointer to the storage deposit limit + (i32.const 48) ;; 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 52) ;; Pointer to where to copy address + (i32.const 84) ;; Pointer to address len ptr + (i32.const 0xffffffff) ;; u32 max sentinel value: do not copy output + (i32.const 0) ;; Length is ignored in this case + (i32.const 0) ;; salt_ptr + (i32.const 0) ;; salt_len + ) + )) + ;; return the deployed contract address + (call $seal_return (i32.const 0) (i32.const 52) (i32.const 32)) + ) +) diff --git a/frame/contracts/fixtures/store.wat b/frame/contracts/fixtures/store_call.wat similarity index 100% rename from frame/contracts/fixtures/store.wat rename to frame/contracts/fixtures/store_call.wat diff --git a/frame/contracts/fixtures/store_deploy.wat b/frame/contracts/fixtures/store_deploy.wat new file mode 100644 index 0000000000000..cc428e9623bfb --- /dev/null +++ b/frame/contracts/fixtures/store_deploy.wat @@ -0,0 +1,45 @@ +;; Stores a value of the passed size in constructor. +(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 "deploy") + (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 "call")) +) diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index 98a3dc36b7b68..6ebfb18509b1c 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -547,7 +547,7 @@ benchmarks! { seal_gas_left { let r in 0 .. API_BENCHMARK_RUNS; let instance = Contract::::new(WasmModule::getter( - "seal0", "seal_gas_left", r + "seal1", "gas_left", r ), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) @@ -604,9 +604,9 @@ benchmarks! { let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { - module: "seal0", - name: "seal_weight_to_fee", - params: vec![ValueType::I64, ValueType::I32, ValueType::I32], + module: "seal1", + name: "weight_to_fee", + params: vec![ValueType::I64, ValueType::I64, ValueType::I32, ValueType::I32], return_type: None, }], data_segments: vec![DataSegment { @@ -615,6 +615,7 @@ benchmarks! { }], call_body: Some(body::repeated(r, &[ Instruction::I64Const(500_000), + Instruction::I64Const(300_000), Instruction::I32Const(4), Instruction::I32Const(0), Instruction::Call(0), @@ -1584,16 +1585,26 @@ benchmarks! { let callee_bytes = callees.iter().flat_map(|x| x.account_id.encode()).collect(); let value: BalanceOf = 0u32.into(); let value_bytes = value.encode(); - let value_len = value_bytes.len(); + let value_len = BalanceOf::::max_encoded_len() as u32; + // Set an own limit every 2nd call + let own_limit = (u32::MAX - 100).into(); + let deposits = (0..r) + .map(|i| if i % 2 == 0 { 0u32.into() } else { own_limit } ) + .collect::>>(); + let deposits_bytes: Vec = deposits.iter().flat_map(|i| i.encode()).collect(); + let deposits_len = deposits_bytes.len() as u32; + let deposit_len = value_len.clone(); + let callee_offset = value_len + deposits_len; let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { - module: "seal0", - name: "seal_call", + module: "seal2", + name: "call", params: vec![ ValueType::I32, ValueType::I32, ValueType::I64, + ValueType::I64, ValueType::I32, ValueType::I32, ValueType::I32, @@ -1609,16 +1620,21 @@ benchmarks! { value: value_bytes, }, DataSegment { - offset: value_len as u32, + offset: value_len, + value: deposits_bytes, + }, + DataSegment { + offset: callee_offset, value: callee_bytes, }, ], call_body: Some(body::repeated_dyn(r, vec![ - 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)), // flags + Counter(callee_offset, callee_len as u32), // callee_ptr + Regular(Instruction::I64Const(0)), // ref_time weight + Regular(Instruction::I64Const(0)), // proof_size weight + Counter(value_len, deposit_len as u32), // deposit_limit_ptr 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(0)), // input_data_len Regular(Instruction::I32Const(SENTINEL as i32)), // output_ptr @@ -1630,7 +1646,7 @@ benchmarks! { }); let instance = Contract::::new(code, vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + }: call(origin, instance.addr, 0u32.into(), Weight::MAX, Some(BalanceOf::::from(u32::MAX).into()), vec![]) // This is a slow call: We redeuce the number of runs. #[pov_mode = Measured] @@ -1742,17 +1758,17 @@ benchmarks! { }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, bytes) // We assume that every instantiate sends at least the minimum balance. - // This is a slow call: We redeuce the number of runs. + // This is a slow call: we reduce the number of runs. #[pov_mode = Measured] seal_instantiate { - let r in 0 .. API_BENCHMARK_RUNS / 2; + let r in 1 .. API_BENCHMARK_RUNS / 2; let hashes = (0..r) .map(|i| { let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), call_body: Some(body::plain(vec![ - // we need to add this in order to make contracts unique - // so that they can be deployed from the same sender + // We need to add this in order to make contracts unique, + // so that they can be deployed from the same sender. Instruction::I32Const(i as i32), Instruction::Drop, Instruction::End, @@ -1765,27 +1781,24 @@ benchmarks! { .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_len = &hashes_bytes.len(); let value = Pallet::::min_balance(); assert!(value > 0u32.into()); let value_bytes = value.encode(); - let value_len = value_bytes.len(); + let value_len = BalanceOf::::max_encoded_len(); let addr_len = T::AccountId::max_encoded_len(); - - // offsets where to place static data in contract memory - let value_offset = 0; - let hashes_offset = value_offset + value_len; + // Offsets where to place static data in contract memory. + let hashes_offset = value_len; let addr_len_offset = hashes_offset + hashes_len; let addr_offset = addr_len_offset + addr_len; - let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { - module: "seal0", - name: "seal_instantiate", + module: "seal2", + name: "instantiate", params: vec![ ValueType::I32, - ValueType::I32, + ValueType::I64, ValueType::I64, ValueType::I32, ValueType::I32, @@ -1802,7 +1815,7 @@ benchmarks! { }], data_segments: vec![ DataSegment { - offset: value_offset as u32, + offset: 0, value: value_bytes, }, DataSegment { @@ -1816,10 +1829,10 @@ benchmarks! { ], call_body: Some(body::repeated_dyn(r, vec![ Counter(hashes_offset as u32, hash_len as u32), // code_hash_ptr - Regular(Instruction::I32Const(hash_len as i32)), // code_hash_len - Regular(Instruction::I64Const(0)), // gas - Regular(Instruction::I32Const(value_offset as i32)), // value_ptr - Regular(Instruction::I32Const(value_len as i32)), // value_len + Regular(Instruction::I64Const(0)), // ref_time weight + Regular(Instruction::I64Const(0)), // proof_size weight + Regular(Instruction::I32Const(SENTINEL as i32)), // deposit limit ptr: use parent's limit + Regular(Instruction::I32Const(0)), // value_ptr Regular(Instruction::I32Const(0)), // input_data_ptr Regular(Instruction::I32Const(0)), // input_data_len Regular(Instruction::I32Const(addr_offset as i32)), // address_ptr @@ -1827,7 +1840,7 @@ benchmarks! { 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 + Regular(Instruction::I32Const(0)), // salt_len_ptr Regular(Instruction::Call(0)), Regular(Instruction::Drop), ])), diff --git a/frame/contracts/src/exec.rs b/frame/contracts/src/exec.rs index 46a611dbfd09b..d0a650e0a0ef6 100644 --- a/frame/contracts/src/exec.rs +++ b/frame/contracts/src/exec.rs @@ -23,7 +23,9 @@ use crate::{ }; use frame_support::{ crypto::ecdsa::ECDSAExt, - dispatch::{DispatchError, DispatchResult, DispatchResultWithPostInfo, Dispatchable}, + dispatch::{ + fmt::Debug, DispatchError, DispatchResult, DispatchResultWithPostInfo, Dispatchable, + }, storage::{with_transaction, TransactionOutcome}, traits::{ tokens::{Fortitude::Polite, Preservation::Expendable}, @@ -40,7 +42,7 @@ use sp_core::{ sr25519::{Public as SR25519Public, Signature as SR25519Signature}, }; use sp_io::{crypto::secp256k1_ecdsa_recover_compressed, hashing::blake2_256}; -use sp_runtime::traits::{Convert, Hash}; +use sp_runtime::traits::{Convert, Hash, Zero}; use sp_std::{marker::PhantomData, mem, prelude::*, vec::Vec}; pub type AccountIdOf = ::AccountId; @@ -137,6 +139,7 @@ pub trait Ext: sealing::Sealed { fn call( &mut self, gas_limit: Weight, + deposit_limit: BalanceOf, to: AccountIdOf, value: BalanceOf, input_data: Vec, @@ -160,6 +163,7 @@ pub trait Ext: sealing::Sealed { fn instantiate( &mut self, gas_limit: Weight, + deposit_limit: BalanceOf, code: CodeHash, value: BalanceOf, input_data: Vec, @@ -692,8 +696,9 @@ where args, value, gas_meter, - storage_meter, Weight::zero(), + storage_meter, + BalanceOf::::zero(), schedule, determinism, )?; @@ -719,12 +724,13 @@ 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, + storage_meter: &mut storage::meter::GenericMeter, + deposit_limit: BalanceOf, schedule: &Schedule, determinism: Determinism, ) -> Result<(Frame, E, Option), ExecError> { @@ -781,7 +787,7 @@ where account_id, entry_point, nested_gas: gas_meter.nested(gas_limit)?, - nested_storage: storage_meter.nested(), + nested_storage: storage_meter.nested(deposit_limit), allows_reentry: true, }; @@ -794,6 +800,7 @@ where frame_args: FrameArgs, value_transferred: BalanceOf, gas_limit: Weight, + deposit_limit: BalanceOf, ) -> Result { if self.frames.len() == T::CallStack::size() { return Err(Error::::MaxCallDepthReached.into()) @@ -817,8 +824,9 @@ where frame_args, value_transferred, nested_gas, - nested_storage, gas_limit, + nested_storage, + deposit_limit, self.schedule, self.determinism, )?; @@ -859,8 +867,10 @@ 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. + // Storage limit is normally enforced as late as possible (when the last frame returns) + // so that the ordering of storage accesses does not matter. + // (However, if a special limit was set for a sub-call, it should be enforced right + // after the sub-call returned. See below for this case of enforcement). if self.frames.is_empty() { let frame = &mut self.first_frame; frame.contract_info.load(&frame.account_id); @@ -869,7 +879,7 @@ where } let frame = self.top_frame(); - let account_id = &frame.account_id; + let account_id = &frame.account_id.clone(); match (entry_point, delegated_code_hash) { (ExportedFunction::Constructor, _) => { // It is not allowed to terminate a contract inside its constructor. @@ -877,6 +887,13 @@ where return Err(Error::::TerminatedInConstructor.into()) } + // If a special limit was set for the sub-call, we enforce it here. + // This is needed because contract constructor might write to storage. + // The sub-call will be rolled back in case the limit is exhausted. + let frame = self.top_frame_mut(); + let contract = frame.contract_info.as_contract(); + frame.nested_storage.enforce_subcall_limit(contract)?; + // Deposit an instantiation event. Contracts::::deposit_event( vec![T::Hashing::hash_of(self.caller()), T::Hashing::hash_of(account_id)], @@ -893,9 +910,15 @@ where ); }, (ExportedFunction::Call, None) => { + // If a special limit was set for the sub-call, we enforce it here. + // The sub-call will be rolled back in case the limit is exhausted. + let frame = self.top_frame_mut(); + let contract = frame.contract_info.as_contract(); + frame.nested_storage.enforce_subcall_limit(contract)?; + let caller = self.caller(); Contracts::::deposit_event( - vec![T::Hashing::hash_of(caller), T::Hashing::hash_of(account_id)], + vec![T::Hashing::hash_of(caller), T::Hashing::hash_of(&account_id)], Event::Called { caller: caller.clone(), contract: account_id.clone() }, ); }, @@ -1107,6 +1130,7 @@ where fn call( &mut self, gas_limit: Weight, + deposit_limit: BalanceOf, to: T::AccountId, value: BalanceOf, input_data: Vec, @@ -1135,6 +1159,7 @@ where FrameArgs::Call { dest: to, cached_info, delegated_call: None }, value, gas_limit, + deposit_limit, )?; self.run(executable, input_data) }; @@ -1166,6 +1191,7 @@ where }, value, Weight::zero(), + BalanceOf::::zero(), )?; self.run(executable, input_data) } @@ -1173,6 +1199,7 @@ where fn instantiate( &mut self, gas_limit: Weight, + deposit_limit: BalanceOf, code_hash: CodeHash, value: BalanceOf, input_data: Vec, @@ -1190,6 +1217,7 @@ where }, value, gas_limit, + deposit_limit, )?; let account_id = self.top_frame().account_id.clone(); self.run(executable, input_data).map(|ret| (account_id, ret)) @@ -1917,7 +1945,7 @@ mod tests { 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); + let r = ctx.ext.call(Weight::zero(), BalanceOf::::zero(), BOB, 0, vec![], true); ReachedBottom::mutate(|reached_bottom| { if !*reached_bottom { @@ -1971,7 +1999,11 @@ mod tests { 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(_)); + assert_matches!( + ctx.ext + .call(Weight::zero(), BalanceOf::::zero(), CHARLIE, 0, vec![], true), + Ok(_) + ); exec_success() }); let charlie_ch = MockLoader::insert(Call, |ctx, _| { @@ -2105,7 +2137,8 @@ mod tests { // ALICE is the origin of the call stack assert!(ctx.ext.caller_is_origin()); // BOB calls CHARLIE - ctx.ext.call(Weight::zero(), CHARLIE, 0, vec![], true) + ctx.ext + .call(Weight::zero(), BalanceOf::::zero(), CHARLIE, 0, vec![], true) }); ExtBuilder::default().build().execute_with(|| { @@ -2136,7 +2169,11 @@ mod tests { assert_eq!(*ctx.ext.address(), BOB); // Call into charlie contract. - assert_matches!(ctx.ext.call(Weight::zero(), CHARLIE, 0, vec![], true), Ok(_)); + assert_matches!( + ctx.ext + .call(Weight::zero(), BalanceOf::::zero(), CHARLIE, 0, vec![], true), + Ok(_) + ); exec_success() }); let charlie_ch = MockLoader::insert(Call, |ctx, _| { @@ -2287,6 +2324,7 @@ mod tests { .ext .instantiate( Weight::zero(), + BalanceOf::::zero(), dummy_ch, ::Currency::minimum_balance(), vec![], @@ -2351,6 +2389,7 @@ mod tests { assert_matches!( ctx.ext.instantiate( Weight::zero(), + BalanceOf::::zero(), dummy_ch, ::Currency::minimum_balance(), vec![], @@ -2443,13 +2482,26 @@ mod tests { let info = ctx.ext.contract_info(); 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.call( + Weight::zero(), + BalanceOf::::zero(), + CHARLIE, + 0, + vec![], + true + ), + exec_trapped() + ); assert_eq!(ctx.ext.contract_info().storage_byte_deposit, 42); } exec_success() }); let code_charlie = MockLoader::insert(Call, |ctx, _| { - assert!(ctx.ext.call(Weight::zero(), BOB, 0, vec![99], true).is_ok()); + assert!(ctx + .ext + .call(Weight::zero(), BalanceOf::::zero(), BOB, 0, vec![99], true) + .is_ok()); exec_trapped() }); @@ -2479,7 +2531,7 @@ mod tests { fn recursive_call_during_constructor_fails() { let code = MockLoader::insert(Constructor, |ctx, _| { assert_matches!( - ctx.ext.call(Weight::zero(), ctx.ext.address().clone(), 0, vec![], true), + ctx.ext.call(Weight::zero(), BalanceOf::::zero(), ctx.ext.address().clone(), 0, vec![], true), Err(ExecError{error, ..}) if error == >::ContractNotFound.into() ); exec_success() @@ -2618,7 +2670,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(Weight::zero(), dest, 0, vec![], false) + ctx.ext.call(Weight::zero(), BalanceOf::::zero(), dest, 0, vec![], false) }); let code_charlie = MockLoader::insert(Call, |_, _| exec_success()); @@ -2665,15 +2717,17 @@ mod tests { fn call_deny_reentry() { let code_bob = MockLoader::insert(Call, |ctx, _| { if ctx.input_data[0] == 0 { - ctx.ext.call(Weight::zero(), CHARLIE, 0, vec![], false) + ctx.ext + .call(Weight::zero(), BalanceOf::::zero(), CHARLIE, 0, vec![], false) } else { exec_success() } }); // call BOB with input set to '1' - let code_charlie = - MockLoader::insert(Call, |ctx, _| ctx.ext.call(Weight::zero(), BOB, 0, vec![1], true)); + let code_charlie = MockLoader::insert(Call, |ctx, _| { + ctx.ext.call(Weight::zero(), BalanceOf::::zero(), BOB, 0, vec![1], true) + }); ExtBuilder::default().build().execute_with(|| { let schedule = ::Schedule::get(); @@ -2862,6 +2916,7 @@ mod tests { ctx.ext .instantiate( Weight::zero(), + BalanceOf::::zero(), fail_code, ctx.ext.minimum_balance() * 100, vec![], @@ -2875,6 +2930,7 @@ mod tests { .ext .instantiate( Weight::zero(), + BalanceOf::::zero(), success_code, ctx.ext.minimum_balance() * 100, vec![], @@ -2883,7 +2939,9 @@ mod tests { .unwrap(); // a plain call should not influence the account counter - ctx.ext.call(Weight::zero(), account_id, 0, vec![], false).unwrap(); + ctx.ext + .call(Weight::zero(), BalanceOf::::zero(), account_id, 0, vec![], false) + .unwrap(); exec_success() }); @@ -3387,7 +3445,14 @@ mod tests { assert_eq!(ctx.ext.nonce(), 1); // Should not change with a failed instantiation assert_err!( - ctx.ext.instantiate(Weight::zero(), fail_code, 0, vec![], &[],), + ctx.ext.instantiate( + Weight::zero(), + BalanceOf::::zero(), + fail_code, + 0, + vec![], + &[], + ), ExecError { error: >::ContractTrapped.into(), origin: ErrorOrigin::Callee @@ -3395,7 +3460,16 @@ mod tests { ); assert_eq!(ctx.ext.nonce(), 1); // Successful instantiation increments - ctx.ext.instantiate(Weight::zero(), success_code, 0, vec![], &[]).unwrap(); + ctx.ext + .instantiate( + Weight::zero(), + BalanceOf::::zero(), + success_code, + 0, + vec![], + &[], + ) + .unwrap(); assert_eq!(ctx.ext.nonce(), 2); exec_success() }); diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index 118da36ae88a1..5a82a4a42b4a9 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -15,9 +15,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! # Contract Pallet +//! # Contracts Pallet //! -//! The Contract module provides functionality for the runtime to deploy and execute WebAssembly +//! The Contracts module provides functionality for the runtime to deploy and execute WebAssembly //! smart-contracts. //! //! - [`Config`] @@ -73,7 +73,7 @@ //! //! ## Usage //! -//! The Contract module is a work in progress. The following examples show how this Contract module +//! The Contracts module is a work in progress. The following examples show how this module //! can be used to instantiate and call contracts. //! //! * [`ink!`](https://use.ink) is @@ -265,6 +265,10 @@ pub mod pallet { #[pallet::constant] type DepositPerByte: Get>; + /// Fallback value to limit the storage deposit if it's not being set by the caller. + #[pallet::constant] + type DefaultDepositLimit: Get>; + /// The amount of balance a caller has to pay for each storage item. /// /// # Note @@ -315,8 +319,8 @@ pub mod pallet { } fn integrity_test() { - // Total runtime memory is expected to have 128Mb upper limit - const MAX_RUNTIME_MEM: u32 = 1024 * 1024 * 128; + // Total runtime memory limit + let max_runtime_mem: u32 = T::Schedule::get().limits.runtime_memory; // Memory limits for a single contract: // Value stack size: 1Mb per contract, default defined in wasmi const MAX_STACK_SIZE: u32 = 1024 * 1024; @@ -350,10 +354,10 @@ pub mod pallet { // This gives us the following formula: // // `(MaxCodeLen * 18 * 4 + MAX_STACK_SIZE + max_heap_size) * max_call_depth < - // MAX_RUNTIME_MEM/2` + // max_runtime_mem/2` // // Hence the upper limit for the `MaxCodeLen` can be defined as follows: - let code_len_limit = MAX_RUNTIME_MEM + let code_len_limit = max_runtime_mem .saturating_div(2) .saturating_div(max_call_depth) .saturating_sub(max_heap_size) diff --git a/frame/contracts/src/schedule.rs b/frame/contracts/src/schedule.rs index 747540bce6359..aef2fa1ca7dc1 100644 --- a/frame/contracts/src/schedule.rs +++ b/frame/contracts/src/schedule.rs @@ -127,6 +127,10 @@ pub struct Limits { /// The maximum size of a storage value and event payload in bytes. pub payload_len: u32, + + /// The maximum node runtime memory. This is for integrity checks only and does not affect the + /// real setting. + pub runtime_memory: u32, } impl Limits { @@ -479,6 +483,7 @@ impl Default for Limits { br_table_size: 256, subject_len: 32, payload_len: 16 * 1024, + runtime_memory: 1024 * 1024 * 128, } } } diff --git a/frame/contracts/src/storage/meter.rs b/frame/contracts/src/storage/meter.rs index 51a0af574bcd5..b8bbd6dc4178b 100644 --- a/frame/contracts/src/storage/meter.rs +++ b/frame/contracts/src/storage/meter.rs @@ -23,7 +23,7 @@ use crate::{ }; use codec::Encode; use frame_support::{ - dispatch::DispatchError, + dispatch::{fmt::Debug, DispatchError}, ensure, traits::{ tokens::{Fortitude::Polite, Preservation::Protect, WithdrawConsequence}, @@ -32,7 +32,10 @@ use frame_support::{ DefaultNoBound, RuntimeDebugNoBound, }; use pallet_contracts_primitives::StorageDeposit as Deposit; -use sp_runtime::{traits::Saturating, FixedPointNumber, FixedU128}; +use sp_runtime::{ + traits::{Saturating, Zero}, + FixedPointNumber, FixedU128, +}; use sp_std::{marker::PhantomData, vec::Vec}; /// Deposit that uses the native currency's balance type. @@ -96,17 +99,24 @@ pub enum ReservingExt {} pub trait State: private::Sealed {} /// State parameter that constitutes a meter that is in its root state. -pub enum Root {} +#[derive(Default, Debug)] +pub struct Root; /// State parameter that constitutes a meter that is in its nested state. -pub enum Nested {} +/// Its value indicates whether the nested meter has its own limit. +#[derive(DefaultNoBound, RuntimeDebugNoBound)] +pub enum Nested { + #[default] + DerivedLimit, + OwnLimit, +} 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, RuntimeDebugNoBound)] -pub struct RawMeter { +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. @@ -118,8 +128,10 @@ pub struct RawMeter { /// 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)>, + /// We store the nested state to determine if it has a special limit for sub-call. + nested: S, + /// Type parameter only used in impls. + _phantom: PhantomData, } /// This type is used to describe a storage change when charging from the meter. @@ -214,6 +226,9 @@ impl Diff { /// 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. +/// The only exception is when a special (tougher) deposit limit is specified for a cross-contract +/// call. In that case the limit is enforced once the call is returned, rolling it back if +/// exhausted. #[derive(RuntimeDebugNoBound, Clone)] struct Charge { deposit_account: DepositAccount, @@ -255,16 +270,24 @@ impl RawMeter where T: Config, E: Ext, - S: State, + S: State + Default + Debug, { - /// Create a new child that has its `limit` set to whatever is remaining of it. + /// Create a new child that has its `limit`. + /// Passing `0` as the limit is interpreted as to take whatever is remaining from its parent. /// /// 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 { + pub fn nested(&self, limit: BalanceOf) -> RawMeter { debug_assert!(self.is_alive()); - RawMeter { limit: self.available(), ..Default::default() } + // If a special limit is specified higher than it is available, + // we want to enforce the lesser limit to the nested meter, to fail in the sub-call. + let limit = self.available().min(limit); + if limit.is_zero() { + RawMeter { limit: self.available(), ..Default::default() } + } else { + RawMeter { limit, nested: Nested::OwnLimit, ..Default::default() } + } } /// Absorb a child that was spawned to handle a sub call. @@ -397,7 +420,7 @@ where self.total_deposit = deposit.clone(); info.storage_base_deposit = deposit.charge_or_zero(); - // Usually, deposit charges are deferred to be able to coalesce them with refunds. + // Normally, deposit charges are deferred to be able to coalesce them with refunds. // However, we need to charge immediately so that the account is created before // charges possibly below the ed are collected and fail. E::charge( @@ -429,8 +452,10 @@ where /// /// # 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. + /// We normally need to call this **once** for every call stack and not for every cross contract + /// call. However, if a dedicated limit is specified for a sub-call, this needs to be called + /// once the sub-call has returned. For this, the [`Self::enforce_subcall_limit`] wrapper is + /// used. pub fn enforce_limit( &mut self, info: Option<&mut ContractInfo>, @@ -448,6 +473,18 @@ where } Ok(()) } + + /// This is a wrapper around [`Self::enforce_limit`] to use on the exit from a sub-call to + /// enforce its special limit if needed. + pub fn enforce_subcall_limit( + &mut self, + info: Option<&mut ContractInfo>, + ) -> Result<(), DispatchError> { + match self.nested { + Nested::OwnLimit => self.enforce_limit(info), + Nested::DerivedLimit => Ok(()), + } + } } impl Ext for ReservingExt { @@ -462,7 +499,8 @@ impl Ext for ReservingExt { let max = T::Currency::reducible_balance(origin, Protect, Polite) .saturating_sub(min_leftover) .saturating_sub(Pallet::::min_balance()); - let limit = limit.unwrap_or(max); + let default = max.min(T::DefaultDepositLimit::get()); + let limit = limit.unwrap_or(default); ensure!( limit <= max && matches!(T::Currency::can_withdraw(origin, limit), WithdrawConsequence::Success), @@ -673,7 +711,7 @@ mod tests { assert_eq!(meter.available(), 1_000); // an empty charge does not create a `Charge` entry - let mut nested0 = meter.nested(); + let mut nested0 = meter.nested(BalanceOf::::zero()); nested0.charge(&Default::default()); meter.absorb(nested0, DepositAccount(BOB), None); @@ -695,7 +733,7 @@ mod tests { let mut nested0_info = new_info(StorageInfo { bytes: 100, items: 5, bytes_deposit: 100, items_deposit: 10 }); - let mut nested0 = meter.nested(); + let mut nested0 = meter.nested(BalanceOf::::zero()); nested0.charge(&Diff { bytes_added: 108, bytes_removed: 5, @@ -706,13 +744,13 @@ mod tests { let mut nested1_info = new_info(StorageInfo { bytes: 100, items: 10, bytes_deposit: 100, items_deposit: 20 }); - let mut nested1 = nested0.nested(); + let mut nested1 = nested0.nested(BalanceOf::::zero()); nested1.charge(&Diff { items_removed: 5, ..Default::default() }); nested0.absorb(nested1, DepositAccount(CHARLIE), Some(&mut nested1_info)); let mut nested2_info = new_info(StorageInfo { bytes: 100, items: 7, bytes_deposit: 100, items_deposit: 20 }); - let mut nested2 = nested0.nested(); + let mut nested2 = nested0.nested(BalanceOf::::zero()); nested2.charge(&Diff { items_removed: 7, ..Default::default() }); nested0.absorb(nested2, DepositAccount(CHARLIE), Some(&mut nested2_info)); @@ -760,7 +798,7 @@ mod tests { let mut meter = TestMeter::new(&ALICE, Some(1_000), 0).unwrap(); assert_eq!(meter.available(), 1_000); - let mut nested0 = meter.nested(); + let mut nested0 = meter.nested(BalanceOf::::zero()); nested0.charge(&Diff { bytes_added: 5, bytes_removed: 1, @@ -771,7 +809,7 @@ mod tests { let mut nested1_info = new_info(StorageInfo { bytes: 100, items: 10, bytes_deposit: 100, items_deposit: 20 }); - let mut nested1 = nested0.nested(); + let mut nested1 = nested0.nested(BalanceOf::::zero()); nested1.charge(&Diff { items_removed: 5, ..Default::default() }); nested1.charge(&Diff { bytes_added: 20, ..Default::default() }); nested1.terminate(&nested1_info); diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index 4e6c468f19c81..7b2bb04428a6f 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -16,6 +16,7 @@ // limitations under the License. use self::test_utils::hash; +use crate as pallet_contracts; use crate::{ chain_extension::{ ChainExtension, Environment, Ext, InitState, RegisteredChainExtension, @@ -44,6 +45,7 @@ use frame_support::{ }; use frame_system::{EventRecord, Phase}; use pretty_assertions::{assert_eq, assert_ne}; +use sp_core::ByteArray; use sp_io::hashing::blake2_256; use sp_keystore::{testing::MemoryKeystore, KeystoreExt}; use sp_runtime::{ @@ -53,8 +55,6 @@ use sp_runtime::{ }; use std::ops::Deref; -use crate as pallet_contracts; - type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; type Block = frame_system::mocking::MockBlock; @@ -345,6 +345,8 @@ parameter_types! { }; pub static DepositPerByte: BalanceOf = 1; pub const DepositPerItem: BalanceOf = 2; + // We need this one set high enough for running benchmarks. + pub static DefaultDepositLimit: BalanceOf = 10_000_000; } impl Convert> for Test { @@ -402,6 +404,7 @@ impl Config for Test { type Schedule = MySchedule; type DepositPerByte = DepositPerByte; type DepositPerItem = DepositPerItem; + type DefaultDepositLimit = DefaultDepositLimit; type AddressGenerator = DefaultAddressGenerator; type MaxCodeLen = ConstU32<{ 123 * 1024 }>; type MaxStorageKeyLen = ConstU32<128>; @@ -1110,7 +1113,7 @@ fn cannot_self_destruct_through_draning() { #[test] fn cannot_self_destruct_through_storage_refund_after_price_change() { - let (wasm, _code_hash) = compile_module::("store").unwrap(); + let (wasm, _code_hash) = compile_module::("store_call").unwrap(); ExtBuilder::default().existential_deposit(200).build().execute_with(|| { let _ = Balances::deposit_creating(&ALICE, 1_000_000); let min_balance = ::Currency::minimum_balance(); @@ -2628,7 +2631,6 @@ fn gas_estimation_nested_call_fixed_limit() { ExtBuilder::default().existential_deposit(50).build().execute_with(|| { let min_balance = ::Currency::minimum_balance(); let _ = Balances::deposit_creating(&ALICE, 1000 * min_balance); - let _ = Balances::deposit_creating(&CHARLIE, 1000 * min_balance); let addr_caller = Contracts::bare_instantiate( ALICE, @@ -2662,6 +2664,7 @@ fn gas_estimation_nested_call_fixed_limit() { .iter() .cloned() .chain((GAS_LIMIT / 5).ref_time().to_le_bytes()) + .chain((GAS_LIMIT / 5).proof_size().to_le_bytes()) .collect(); // Call in order to determine the gas that is required for this call @@ -2678,22 +2681,36 @@ 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.ref_time() > result.gas_consumed.ref_time()); + assert!(result.gas_required.all_gt(result.gas_consumed)); // Make the same call using the estimated gas. Should succeed. assert_ok!( Contracts::bare_call( ALICE, - addr_caller, + addr_caller.clone(), 0, result.gas_required, Some(result.storage_deposit.charge_or_zero()), - input, + input.clone(), false, Determinism::Enforced, ) .result ); + + // Make the same call using proof_size a but less than estimated. Should fail with OutOfGas. + let result = Contracts::bare_call( + ALICE, + addr_caller, + 0, + result.gas_required.sub_proof_size(1), + Some(result.storage_deposit.charge_or_zero()), + input, + false, + Determinism::Enforced, + ) + .result; + assert_err!(result, >::OutOfGas); }); } @@ -2774,7 +2791,7 @@ fn gas_estimation_call_runtime() { } #[test] -fn gas_call_runtime_reentrancy_guarded() { +fn call_runtime_reentrancy_guarded() { 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(|| { @@ -3968,7 +3985,7 @@ fn set_code_hash() { #[test] fn storage_deposit_limit_is_enforced() { - let (wasm, _code_hash) = compile_module::("store").unwrap(); + let (wasm, _code_hash) = compile_module::("store_call").unwrap(); ExtBuilder::default().existential_deposit(200).build().execute_with(|| { let _ = Balances::deposit_creating(&ALICE, 1_000_000); let min_balance = ::Currency::minimum_balance(); @@ -3992,15 +4009,47 @@ fn storage_deposit_limit_is_enforced() { 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 + // Create 1 byte of storage with a price of per byte, + // setting insufficient deposit limit, as it requires 3 Balance: + // 2 for the item added + 1 for the new storage item. assert_err_ignore_postinfo!( Contracts::call( RuntimeOrigin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, - Some(codec::Compact(1)), - 100u32.to_le_bytes().to_vec() + Some(codec::Compact(2)), + 1u32.to_le_bytes().to_vec() + ), + >::StorageDepositLimitExhausted, + ); + + // To check that deposit limit fallbacks to DefaultDepositLimit, + // we customize it here. + DEFAULT_DEPOSIT_LIMIT.with(|c| *c.borrow_mut() = 3); + + // Create 1 byte of storage, should cost 3 Balance: + // 2 for the item added + 1 for the new storage item. + // Should pass as it fallbacks to DefaultDepositLimit. + assert_ok!(Contracts::call( + RuntimeOrigin::signed(ALICE), + addr.clone(), + 0, + GAS_LIMIT, + None, + 1u32.to_le_bytes().to_vec() + )); + + // Use 4 more bytes of the storage for the same item, which requires 4 Balance. + // Should fail as DefaultDepositLimit is 3 and hence isn't enough. + assert_err_ignore_postinfo!( + Contracts::call( + RuntimeOrigin::signed(ALICE), + addr.clone(), + 0, + GAS_LIMIT, + None, + 5u32.to_le_bytes().to_vec() ), >::StorageDepositLimitExhausted, ); @@ -4008,10 +4057,10 @@ fn storage_deposit_limit_is_enforced() { } #[test] -fn storage_deposit_limit_is_enforced_late() { +fn deposit_limit_in_nested_calls() { let (wasm_caller, _code_hash_caller) = compile_module::("create_storage_and_call").unwrap(); - let (wasm_callee, _code_hash_callee) = compile_module::("store").unwrap(); + let (wasm_callee, _code_hash_callee) = compile_module::("store_call").unwrap(); ExtBuilder::default().existential_deposit(200).build().execute_with(|| { let _ = Balances::deposit_creating(&ALICE, 1_000_000); @@ -4054,27 +4103,28 @@ fn storage_deposit_limit_is_enforced_late() { 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. + // We do not remove any storage but add a storage item of 12 bytes in the caller + // contract. This would cost 12 + 2 = 14 Balance. + // The nested call doesn't get a special limit, which is set by passing 0 to it. + // This should fail as the specified parent's limit is less than the cost: 13 < + // 14. 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(), + Some(codec::Compact(13)), + (100u32, &addr_callee, 0u64).encode(), ), >::StorageDepositLimitExhausted, ); - - // Allow for the additional 14 bytes but demand an additional byte in the callee contract. + // Now we specify the parent's limit high enough to cover the caller's storage additions. + // However, we use a single byte more in the callee, hence the storage deposit should be 15 + // Balance. + // The nested call doesn't get a special limit, which is set by passing 0 to it. + // This should fail as the specified parent's limit is less than the cost: 14 + // < 15. assert_err_ignore_postinfo!( Contracts::call( RuntimeOrigin::signed(ALICE), @@ -4082,19 +4132,31 @@ fn storage_deposit_limit_is_enforced_late() { 0, GAS_LIMIT, Some(codec::Compact(14)), - 101u32 - .to_le_bytes() - .as_ref() - .iter() - .chain(<_ as AsRef<[u8]>>::as_ref(&addr_callee)) - .cloned() - .collect(), + (101u32, &addr_callee, 0u64).encode(), ), >::StorageDepositLimitExhausted, ); - // Refund in the callee contract but not enough to cover the 14 balance required by the - // caller. + // Now we specify the parent's limit high enough to cover both the caller's and callee's + // storage additions. However, we set a special deposit limit of 1 Balance for the nested + // call. This should fail as callee adds up 2 bytes to the storage, meaning that the nested + // call should have a deposit limit of at least 2 Balance. The sub-call should be rolled + // back, which is covered by the next test case. + assert_err_ignore_postinfo!( + Contracts::call( + RuntimeOrigin::signed(ALICE), + addr_caller.clone(), + 0, + GAS_LIMIT, + Some(codec::Compact(16)), + (102u32, &addr_callee, 1u64).encode(), + ), + >::StorageDepositLimitExhausted, + ); + + // Refund in the callee contract but not enough to cover the 14 Balance required by the + // caller. Note that if previous sub-call wouldn't roll back, this call would pass making + // the test case fail. We don't set a special limit for the nested call here. assert_err_ignore_postinfo!( Contracts::call( RuntimeOrigin::signed(ALICE), @@ -4102,59 +4164,198 @@ fn storage_deposit_limit_is_enforced_late() { 0, GAS_LIMIT, Some(codec::Compact(0)), - 87u32 - .to_le_bytes() - .as_ref() - .iter() - .chain(<_ as AsRef<[u8]>>::as_ref(&addr_callee)) - .cloned() - .collect(), + (87u32, &addr_callee, 0u64).encode(), ), >::StorageDepositLimitExhausted, ); let _ = Balances::make_free_balance_be(&ALICE, 1_000); - // Send more than the sender has balance. + // Require more than the sender's balance. + // We don't set a special limit for the nested call. 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(), + None, + (1200u32, &addr_callee, 1u64).encode(), ), >::StorageDepositLimitExhausted, ); - // Same as above but allow for the additional balance. + // Same as above but allow for the additional deposit of 1 Balance in parent. + // We set the special deposit limit of 1 Balance for the nested call, which isn't + // enforced as callee frees up storage. This should pass. 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(), + (87u32, &addr_callee, 1u64).encode(), )); }); } +#[test] +fn deposit_limit_in_nested_instantiate() { + let (wasm_caller, _code_hash_caller) = + compile_module::("create_storage_and_instantiate").unwrap(); + let (wasm_callee, code_hash_callee) = compile_module::("store_deploy").unwrap(); + const ED: u64 = 5; + ExtBuilder::default().existential_deposit(ED).build().execute_with(|| { + let _ = Balances::deposit_creating(&ALICE, 1_000_000); + let _ = Balances::deposit_creating(&BOB, 1_000_000); + // Create caller contract + let addr_caller = Contracts::bare_instantiate( + ALICE, + 10_000u64, // this balance is later passed to the deployed contract + GAS_LIMIT, + None, + Code::Upload(wasm_caller), + vec![], + vec![], + false, + ) + .result + .unwrap() + .account_id; + // Deploy a contract to get its occupied storage size + let addr = Contracts::bare_instantiate( + ALICE, + 0, + GAS_LIMIT, + None, + Code::Upload(wasm_callee), + vec![0, 0, 0, 0], + vec![], + false, + ) + .result + .unwrap() + .account_id; + + let callee_info_len = ContractInfoOf::::get(&addr).unwrap().encoded_size() as u64; + + // We don't set a special deposit limit for the nested instantiation. + // + // The deposit limit set for the parent is insufficient for the instantiation, which + // requires: + // - callee_info_len + 2 for storing the new contract info, + // - ED for deployed contract account, + // - 2 for the storage item of 0 bytes being created in the callee constructor + // or (callee_info_len + 2 + ED + 2) Balance in total. + // + // Provided the limit is set to be 1 Balance less, + // this call should fail on the return from the caller contract. + assert_err_ignore_postinfo!( + Contracts::call( + RuntimeOrigin::signed(BOB), + addr_caller.clone(), + 0, + GAS_LIMIT, + Some(codec::Compact(callee_info_len + 2 + ED + 1)), + (0u32, &code_hash_callee, 0u64).encode(), + ), + >::StorageDepositLimitExhausted, + ); + // The charges made on instantiation should be rolled back. + assert_eq!(::Currency::free_balance(&BOB), 1_000_000); + + // Now we give enough limit for the instantiation itself, but require for 1 more storage + // byte in the constructor. Hence +1 Balance to the limit is needed. This should fail on the + // return from constructor. + assert_err_ignore_postinfo!( + Contracts::call( + RuntimeOrigin::signed(BOB), + addr_caller.clone(), + 0, + GAS_LIMIT, + Some(codec::Compact(callee_info_len + 2 + ED + 2)), + (1u32, &code_hash_callee, 0u64).encode(), + ), + >::StorageDepositLimitExhausted, + ); + // The charges made on the instantiation should be rolled back. + assert_eq!(::Currency::free_balance(&BOB), 1_000_000); + + // Now we set enough limit in parent call, but an insufficient limit for child instantiate. + // This should fail during the charging for the instantiation in + // `RawMeter::charge_instantiate()` + assert_err_ignore_postinfo!( + Contracts::call( + RuntimeOrigin::signed(BOB), + addr_caller.clone(), + 0, + GAS_LIMIT, + Some(codec::Compact(callee_info_len + 2 + ED + 2)), + (0u32, &code_hash_callee, callee_info_len + 2 + ED + 1).encode(), + ), + >::StorageDepositLimitExhausted, + ); + // The charges made on the instantiation should be rolled back. + assert_eq!(::Currency::free_balance(&BOB), 1_000_000); + + // Same as above but requires for single added storage + // item of 1 byte to be covered by the limit, which implies 3 more Balance. + // Now we set enough limit for the parent call, but insufficient limit for child + // instantiate. This should fail right after the constructor execution. + assert_err_ignore_postinfo!( + Contracts::call( + RuntimeOrigin::signed(BOB), + addr_caller.clone(), + 0, + GAS_LIMIT, + Some(codec::Compact(callee_info_len + 2 + ED + 3)), // enough parent limit + (1u32, &code_hash_callee, callee_info_len + 2 + ED + 2).encode(), + ), + >::StorageDepositLimitExhausted, + ); + // The charges made on the instantiation should be rolled back. + assert_eq!(::Currency::free_balance(&BOB), 1_000_000); + + // Set enough deposit limit for the child instantiate. This should succeed. + let result = Contracts::bare_call( + BOB, + addr_caller.clone(), + 0, + GAS_LIMIT, + Some(codec::Compact(callee_info_len + 2 + ED + 4).into()), + (1u32, &code_hash_callee, callee_info_len + 2 + ED + 3).encode(), + false, + Determinism::Enforced, + ); + + let returned = result.result.unwrap(); + // All balance of the caller except ED has been transferred to the callee. + // No deposit has been taken from it. + assert_eq!(::Currency::free_balance(&addr_caller), ED); + // Get address of the deployed contract. + let addr_callee = AccountId32::from_slice(&returned.data[0..32]).unwrap(); + // 10_000 should be sent to callee from the caller contract, plus ED to be sent from the + // origin. + assert_eq!(::Currency::free_balance(&addr_callee), 10_000 + ED); + // The origin should be charged with: + // - callee instantiation deposit = (callee_info_len + 2) + // - callee account ED + // - for writing an item of 1 byte to storage = 3 Balance + // + // Still, the latter is to be charged at the end of the call stack, hence + // only (callee_info_len + 2 + ED) is charged so far + assert_eq!( + ::Currency::free_balance(&BOB), + 1_000_000 - (callee_info_len + 2 + ED) + ); + // Check that deposit due to be charged still includes these 3 Balance + assert_eq!(result.storage_deposit.charge_or_zero(), (callee_info_len + 2 + ED + 3),) + }); +} + #[test] fn deposit_limit_honors_liquidity_restrictions() { - let (wasm, _code_hash) = compile_module::("store").unwrap(); + let (wasm, _code_hash) = compile_module::("store_call").unwrap(); ExtBuilder::default().existential_deposit(200).build().execute_with(|| { let _ = Balances::deposit_creating(&ALICE, 1_000_000); let _ = Balances::deposit_creating(&BOB, 1_000); @@ -4198,7 +4399,7 @@ fn deposit_limit_honors_liquidity_restrictions() { #[test] fn deposit_limit_honors_existential_deposit() { - let (wasm, _code_hash) = compile_module::("store").unwrap(); + let (wasm, _code_hash) = compile_module::("store_call").unwrap(); ExtBuilder::default().existential_deposit(200).build().execute_with(|| { let _ = Balances::deposit_creating(&ALICE, 1_000_000); let _ = Balances::deposit_creating(&BOB, 1_000); @@ -4241,7 +4442,7 @@ fn deposit_limit_honors_existential_deposit() { #[test] fn deposit_limit_honors_min_leftover() { - let (wasm, _code_hash) = compile_module::("store").unwrap(); + let (wasm, _code_hash) = compile_module::("store_call").unwrap(); ExtBuilder::default().existential_deposit(200).build().execute_with(|| { let _ = Balances::deposit_creating(&ALICE, 1_000_000); let _ = Balances::deposit_creating(&BOB, 1_000); @@ -4266,7 +4467,7 @@ fn deposit_limit_honors_min_leftover() { 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 + // check that the minimum leftover (value send) is considered assert_err_ignore_postinfo!( Contracts::call( RuntimeOrigin::signed(BOB), diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index 4723f0c833654..5be28a301d8f4 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -370,7 +370,7 @@ mod tests { gas::GasMeter, storage::WriteOutcome, tests::{RuntimeCall, Test, ALICE, BOB}, - BalanceOf, CodeHash, Error, OldWeight, Pallet as Contracts, + BalanceOf, CodeHash, Error, Pallet as Contracts, }; use assert_matches::assert_matches; use frame_support::{ @@ -470,6 +470,7 @@ mod tests { fn call( &mut self, _gas_limit: Weight, + _deposit_limit: BalanceOf, to: AccountIdOf, value: u64, data: Vec, @@ -489,6 +490,7 @@ mod tests { fn instantiate( &mut self, gas_limit: Weight, + _deposit_limit: BalanceOf, code_hash: CodeHash, value: u64, data: Vec, @@ -587,7 +589,11 @@ mod tests { 16_384 } fn get_weight_price(&self, weight: Weight) -> BalanceOf { - BalanceOf::::from(1312_u32).saturating_mul(weight.ref_time().into()) + BalanceOf::::from(1312_u32) + .saturating_mul(weight.ref_time().into()) + .saturating_add( + BalanceOf::::from(103_u32).saturating_mul(weight.proof_size()), + ) } fn schedule(&self) -> &Schedule { &self.schedule @@ -1589,7 +1595,7 @@ mod tests { const CODE_GAS_PRICE: &str = r#" (module - (import "seal0" "seal_weight_to_fee" (func $seal_weight_to_fee (param i64 i32 i32))) + (import "seal1" "weight_to_fee" (func $seal_weight_to_fee (param i64 i64 i32 i32))) (import "env" "memory" (memory 1 1)) ;; size of our buffer is 32 bytes @@ -1606,7 +1612,7 @@ mod tests { (func (export "call") ;; This stores the gas price in the buffer - (call $seal_weight_to_fee (i64.const 2) (i32.const 0) (i32.const 32)) + (call $seal_weight_to_fee (i64.const 2) (i64.const 1) (i32.const 0) (i32.const 32)) ;; assert len == 8 (call $assert @@ -1616,11 +1622,11 @@ mod tests { ) ) - ;; assert that contents of the buffer is equal to the i64 value of 2 * 1312. + ;; assert that contents of the buffer is equal to the i64 value of 2 * 1312 + 103 = 2727. (call $assert (i64.eq (i64.load (i32.const 0)) - (i64.const 2624) + (i64.const 2727) ) ) ) @@ -1635,12 +1641,12 @@ mod tests { const CODE_GAS_LEFT: &str = r#" (module - (import "seal0" "seal_gas_left" (func $seal_gas_left (param i32 i32))) + (import "seal1" "gas_left" (func $seal_gas_left (param i32 i32))) (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32))) (import "env" "memory" (memory 1 1)) - ;; size of our buffer is 32 bytes - (data (i32.const 32) "\20") + ;; Make output buffer size 20 bytes + (data (i32.const 20) "\14") (func $assert (param i32) (block $ok @@ -1652,19 +1658,19 @@ mod tests { ) (func (export "call") - ;; This stores the gas left in the buffer - (call $seal_gas_left (i32.const 0) (i32.const 32)) + ;; This stores the weight left to the buffer + (call $seal_gas_left (i32.const 0) (i32.const 20)) - ;; assert len == 8 + ;; Assert len <= 16 (max encoded Weight len) (call $assert - (i32.eq - (i32.load (i32.const 32)) - (i32.const 8) + (i32.le_u + (i32.load (i32.const 20)) + (i32.const 16) ) ) - ;; return gas left - (call $seal_return (i32.const 0) (i32.const 0) (i32.const 8)) + ;; Return weight left and its encoded value len + (call $seal_return (i32.const 0) (i32.const 0) (i32.load (i32.const 20))) (unreachable) ) @@ -1679,11 +1685,11 @@ mod tests { let output = execute(CODE_GAS_LEFT, vec![], &mut ext).unwrap(); - let gas_left = OldWeight::decode(&mut &*output.data).unwrap(); + let weight_left = Weight::decode(&mut &*output.data).unwrap(); let actual_left = ext.gas_meter.gas_left(); - // 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"); + + assert!(weight_left.all_lt(gas_limit), "gas_left must be less than initial"); + assert!(weight_left.all_gt(actual_left), "gas_left must be greater than final"); } /// Test that [`frame_support::weights::OldWeight`] en/decodes the same as our diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index bfb991ae51dfa..92ae2e3e6ea57 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -433,7 +433,7 @@ bitflags! { /// The kind of call that should be performed. enum CallType { /// Execute another instantiated contract - Call { callee_ptr: u32, value_ptr: u32, gas: u64 }, + Call { callee_ptr: u32, value_ptr: u32, deposit_ptr: u32, weight: Weight }, /// Execute deployed code in the context (storage, account ID, value) of the caller contract DelegateCall { code_hash_ptr: u32 }, } @@ -873,16 +873,22 @@ impl<'a, E: Ext + 'a> Runtime<'a, E> { }; let call_outcome = match call_type { - CallType::Call { callee_ptr, value_ptr, gas } => { + CallType::Call { callee_ptr, value_ptr, deposit_ptr, weight } => { let callee: <::T as frame_system::Config>::AccountId = self.read_sandbox_memory_as(memory, callee_ptr)?; + let deposit_limit: BalanceOf<::T> = if deposit_ptr == SENTINEL { + BalanceOf::<::T>::zero() + } else { + self.read_sandbox_memory_as(memory, deposit_ptr)? + }; let value: BalanceOf<::T> = self.read_sandbox_memory_as(memory, value_ptr)?; if value > 0u32.into() { self.charge_gas(RuntimeCosts::CallSurchargeTransfer)?; } self.ext.call( - Weight::from_parts(gas, 0), + weight, + deposit_limit, callee, value, input_data, @@ -926,7 +932,8 @@ impl<'a, E: Ext + 'a> Runtime<'a, E> { &mut self, memory: &mut [u8], code_hash_ptr: u32, - gas: u64, + weight: Weight, + deposit_ptr: u32, value_ptr: u32, input_data_ptr: u32, input_data_len: u32, @@ -937,8 +944,12 @@ impl<'a, E: Ext + 'a> Runtime<'a, E> { salt_ptr: u32, salt_len: u32, ) -> Result { - let gas = Weight::from_parts(gas, 0); self.charge_gas(RuntimeCosts::InstantiateBase { input_data_len, salt_len })?; + let deposit_limit: BalanceOf<::T> = if deposit_ptr == SENTINEL { + BalanceOf::<::T>::zero() + } else { + self.read_sandbox_memory_as(memory, deposit_ptr)? + }; let value: BalanceOf<::T> = self.read_sandbox_memory_as(memory, value_ptr)?; if value > 0u32.into() { self.charge_gas(RuntimeCosts::InstantiateSurchargeTransfer)?; @@ -947,7 +958,8 @@ impl<'a, E: Ext + 'a> Runtime<'a, E> { 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); + let instantiate_outcome = + self.ext.instantiate(weight, deposit_limit, code_hash, value, input_data, &salt); if let Ok((address, output)) = &instantiate_outcome { if !output.flags.contains(ReturnFlags::REVERT) { self.write_sandbox_output( @@ -993,6 +1005,7 @@ pub mod env { /// /// 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. + /// It deals only with the *ref_time* Weight. /// /// - `amount`: How much gas is used. fn gas(ctx: _, _memory: _, amount: u64) -> Result<(), TrapReason> { @@ -1002,8 +1015,9 @@ pub mod env { /// Set the value at the given key in the contract storage. /// - /// Equivalent to the newer version [`super::seal1::Api::set_storage`] with the exception of the - /// return type. Still a valid thing to call when not interested in the return value. + /// Equivalent to the newer [`seal1`][`super::api_doc::Version1::set_storage`] version with the + /// exception of the return type. Still a valid thing to call when not interested in the return + /// value. #[prefixed_alias] fn set_storage( ctx: _, @@ -1076,8 +1090,9 @@ pub mod env { /// Clear the value at the given key in the contract storage. /// - /// Equivalent to the newer version [`super::seal1::Api::clear_storage`] with the exception of - /// the return type. Still a valid thing to call when not interested in the return value. + /// Equivalent to the newer [`seal1`][`super::api_doc::Version1::clear_storage`] version with + /// the exception of the return type. Still a valid thing to call when not interested in the + /// return value. #[prefixed_alias] fn clear_storage(ctx: _, memory: _, key_ptr: u32) -> Result<(), TrapReason> { ctx.clear_storage(memory, KeyType::Fix, key_ptr).map(|_| ()) @@ -1299,7 +1314,47 @@ pub mod env { ctx.call( memory, CallFlags::ALLOW_REENTRY, - CallType::Call { callee_ptr, value_ptr, gas }, + CallType::Call { + callee_ptr, + value_ptr, + deposit_ptr: SENTINEL, + weight: Weight::from_parts(gas, 0), + }, + input_data_ptr, + input_data_len, + output_ptr, + output_len_ptr, + ) + } + + /// Make a call to another contract. + /// + /// Equivalent to the newer [`seal2`][`super::api_doc::Version2::call`] version but works with + /// *ref_time* Weight only. It is recommended to switch to the latest version, once it's + /// stabilized. + #[version(1)] + #[prefixed_alias] + fn call( + ctx: _, + memory: _, + flags: u32, + callee_ptr: u32, + gas: u64, + value_ptr: u32, + input_data_ptr: u32, + input_data_len: u32, + output_ptr: u32, + output_len_ptr: u32, + ) -> Result { + ctx.call( + memory, + CallFlags::from_bits(flags).ok_or(Error::::InvalidCallFlags)?, + CallType::Call { + callee_ptr, + value_ptr, + deposit_ptr: SENTINEL, + weight: Weight::from_parts(gas, 0), + }, input_data_ptr, input_data_len, output_ptr, @@ -1318,7 +1373,12 @@ pub mod env { /// - `flags`: See `crate::wasm::runtime::CallFlags` for a documentation of the supported flags. /// - `callee_ptr`: a pointer to the address of the callee contract. Should be decodable as an /// `T::AccountId`. Traps otherwise. - /// - `gas`: how much gas to devote to the execution. + /// - `ref_time_limit`: how much *ref_time* Weight to devote to the execution. + /// - `proof_size_limit`: how much *proof_size* Weight to devote to the execution. + /// - `deposit_ptr`: a pointer to the buffer with value of the storage deposit limit for the + /// call. Should be decodable as a `T::Balance`. Traps otherwise. Passing `SENTINEL` means + /// setting no specific limit for the call, which implies storage usage up to the limit of the + /// parent call. /// - `value_ptr`: a pointer to the buffer with value, how much value to send. Should be /// decodable as a `T::Balance`. Traps otherwise. /// - `input_data_ptr`: a pointer to a buffer to be used as input data to the callee. @@ -1336,14 +1396,16 @@ pub mod env { /// - `ReturnCode::CalleeTrapped` /// - `ReturnCode::TransferFailed` /// - `ReturnCode::NotCallable` - #[version(1)] - #[prefixed_alias] + #[version(2)] + #[unstable] fn call( ctx: _, memory: _, flags: u32, callee_ptr: u32, - gas: u64, + ref_time_limit: u64, + proof_size_limit: u64, + deposit_ptr: u32, value_ptr: u32, input_data_ptr: u32, input_data_len: u32, @@ -1353,7 +1415,12 @@ pub mod env { ctx.call( memory, CallFlags::from_bits(flags).ok_or(Error::::InvalidCallFlags)?, - CallType::Call { callee_ptr, value_ptr, gas }, + CallType::Call { + callee_ptr, + value_ptr, + deposit_ptr, + weight: Weight::from_parts(ref_time_limit, proof_size_limit), + }, input_data_ptr, input_data_len, output_ptr, @@ -1417,8 +1484,7 @@ pub mod env { /// # Note /// /// The values `_code_hash_len` and `_value_len` are ignored because the encoded sizes - /// of those types are fixed through - /// [`codec::MaxEncodedLen`]. The fields exist + /// of those types are fixed through [`codec::MaxEncodedLen`]. The fields exist /// for backwards compatibility. Consider switching to the newest version of this function. #[prefixed_alias] fn instantiate( @@ -1441,7 +1507,47 @@ pub mod env { ctx.instantiate( memory, code_hash_ptr, - gas, + Weight::from_parts(gas, 0), + SENTINEL, + value_ptr, + input_data_ptr, + input_data_len, + address_ptr, + address_len_ptr, + output_ptr, + output_len_ptr, + salt_ptr, + salt_len, + ) + } + + /// Instantiate a contract with the specified code hash. + /// + /// Equivalent to the newer [`seal2`][`super::api_doc::Version2::instantiate`] version but works + /// with *ref_time* Weight only. It is recommended to switch to the latest version, once it's + /// stabilized. + #[version(1)] + #[prefixed_alias] + fn instantiate( + ctx: _, + memory: _, + code_hash_ptr: u32, + gas: u64, + value_ptr: u32, + input_data_ptr: u32, + input_data_len: u32, + address_ptr: u32, + address_len_ptr: u32, + output_ptr: u32, + output_len_ptr: u32, + salt_ptr: u32, + salt_len: u32, + ) -> Result { + ctx.instantiate( + memory, + code_hash_ptr, + Weight::from_parts(gas, 0), + SENTINEL, value_ptr, input_data_ptr, input_data_len, @@ -1468,15 +1574,21 @@ pub mod env { /// # 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. + /// - `ref_time_limit`: how much *ref_time* Weight to devote to the execution. + /// - `proof_size_limit`: how much *proof_size* Weight to devote to the execution. + /// - `deposit_ptr`: a pointer to the buffer with value of the storage deposit limit for + /// instantiation. Should be decodable as a `T::Balance`. Traps otherwise. Passing `SENTINEL` + /// means setting no specific limit for the call, which implies storage usage up to the limit + /// of the parent call. /// - `value_ptr`: a pointer to the buffer with value, how much value to send. Should be /// decodable as a `T::Balance`. Traps otherwise. /// - `input_data_ptr`: a pointer to a buffer to be used as input data to the initializer code. /// - `input_data_len`: length of the input data buffer. - /// - `address_ptr`: a pointer where the new account's address is copied to. - /// - `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. + /// - `address_ptr`: a pointer where the new account's address is copied to. `SENTINEL` means + /// not to copy. + /// - `address_len_ptr`: pointer to where put the length of the address. + /// - `output_ptr`: a pointer where the output buffer is copied to. `SENTINEL` means not to + /// copy. /// - `output_len_ptr`: in-out pointer to where the length of the buffer is read from and the /// actual length is written to. /// - `salt_ptr`: Pointer to raw bytes used for address derivation. See `fn contract_address`. @@ -1494,13 +1606,15 @@ pub mod env { /// - `ReturnCode::CalleeTrapped` /// - `ReturnCode::TransferFailed` /// - `ReturnCode::CodeNotFound` - #[version(1)] - #[prefixed_alias] + #[version(2)] + #[unstable] fn instantiate( ctx: _, memory: _, code_hash_ptr: u32, - gas: u64, + ref_time_limit: u64, + proof_size_limit: u64, + deposit_ptr: u32, value_ptr: u32, input_data_ptr: u32, input_data_len: u32, @@ -1514,7 +1628,8 @@ pub mod env { ctx.instantiate( memory, code_hash_ptr, - gas, + Weight::from_parts(ref_time_limit, proof_size_limit), + deposit_ptr, value_ptr, input_data_ptr, input_data_len, @@ -1762,49 +1877,99 @@ pub mod env { /// 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. + /// Equivalent to the newer [`seal1`][`super::api_doc::Version2::weight_to_fee`] version but + /// works with *ref_time* Weight only. It is recommended to switch to the latest version, once + /// it's stabilized. + #[prefixed_alias] + fn weight_to_fee( + ctx: _, + memory: _, + gas: u64, + out_ptr: u32, + out_len_ptr: u32, + ) -> Result<(), TrapReason> { + let gas = Weight::from_parts(gas, 0); + ctx.charge_gas(RuntimeCosts::WeightToFee)?; + Ok(ctx.write_sandbox_output( + memory, + out_ptr, + out_len_ptr, + &ctx.ext.get_weight_price(gas).encode(), + false, + already_charged, + )?) + } + + /// Stores the price for the specified amount of weight into the supplied buffer. + /// + /// # Parameters + /// + /// - `out_ptr`: pointer to the linear memory where the returning value is written to. If the + /// available space at `out_ptr` is less than the size of the value a trap is triggered. + /// - `out_len_ptr`: in-out pointer into linear memory where the buffer length is read from and + /// the value length is written to. /// /// The data is encoded as `T::Balance`. /// /// # Note /// - /// It is recommended to avoid specifying very small values for `gas` as the prices for a single - /// gas can be smaller than one. - #[prefixed_alias] + /// It is recommended to avoid specifying very small values for `ref_time_limit` and + /// `proof_size_limit` as the prices for a single gas can be smaller than the basic balance + /// unit. + #[version(1)] + #[unstable] fn weight_to_fee( ctx: _, memory: _, - gas: u64, + ref_time_limit: u64, + proof_size_limit: u64, out_ptr: u32, out_len_ptr: u32, ) -> Result<(), TrapReason> { - let gas = Weight::from_parts(gas, 0); + let weight = Weight::from_parts(ref_time_limit, proof_size_limit); ctx.charge_gas(RuntimeCosts::WeightToFee)?; Ok(ctx.write_sandbox_output( memory, out_ptr, out_len_ptr, - &ctx.ext.get_weight_price(gas).encode(), + &ctx.ext.get_weight_price(weight).encode(), false, already_charged, )?) } - /// Stores the amount of gas left into the supplied buffer. + /// Stores the weight left into the supplied buffer. + /// + /// Equivalent to the newer [`seal1`][`super::api_doc::Version2::gas_left`] version but + /// works with *ref_time* Weight only. It is recommended to switch to the latest version, once + /// it's stabilized. + #[prefixed_alias] + 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( + memory, + out_ptr, + out_len_ptr, + gas_left, + false, + already_charged, + )?) + } + + /// Stores the amount of weight left into the supplied buffer. /// /// The value is stored to linear memory at the address pointed to by `out_ptr`. /// `out_len_ptr` must point to a u32 value that describes the available space at /// `out_ptr`. This call overwrites it with the size of the value. If the available /// space at `out_ptr` is less than the size of the value a trap is triggered. /// - /// The data is encoded as Gas. - #[prefixed_alias] + /// The data is encoded as Weight. + #[version(1)] + #[unstable] 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(); + let gas_left = &ctx.ext.gas_meter().gas_left().encode(); Ok(ctx.write_sandbox_output( memory, out_ptr, From 7ddfdfbdfab482866a9909ad4927dc2c9b77f8e2 Mon Sep 17 00:00:00 2001 From: Qinxuan Chen Date: Wed, 26 Apr 2023 19:37:44 +0800 Subject: [PATCH 698/715] sp-core: remove useless bounded module (#13865) --- primitives/core/src/bounded.rs | 28 ---------------------------- 1 file changed, 28 deletions(-) delete mode 100644 primitives/core/src/bounded.rs diff --git a/primitives/core/src/bounded.rs b/primitives/core/src/bounded.rs deleted file mode 100644 index c78f1f85a4c23..0000000000000 --- a/primitives/core/src/bounded.rs +++ /dev/null @@ -1,28 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! 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; From 154448b77413de5eaed7479f847191df20c46a96 Mon Sep 17 00:00:00 2001 From: Sasha Gryaznov Date: Wed, 26 Apr 2023 16:46:44 +0300 Subject: [PATCH 699/715] fix a test (#14021) --- frame/contracts/src/tests.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index 7b2bb04428a6f..3c1015bc9ec60 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -4341,12 +4341,9 @@ fn deposit_limit_in_nested_instantiate() { // - callee instantiation deposit = (callee_info_len + 2) // - callee account ED // - for writing an item of 1 byte to storage = 3 Balance - // - // Still, the latter is to be charged at the end of the call stack, hence - // only (callee_info_len + 2 + ED) is charged so far assert_eq!( ::Currency::free_balance(&BOB), - 1_000_000 - (callee_info_len + 2 + ED) + 1_000_000 - (callee_info_len + 2 + ED + 3) ); // Check that deposit due to be charged still includes these 3 Balance assert_eq!(result.storage_deposit.charge_or_zero(), (callee_info_len + 2 + ED + 3),) From 943c520aa78fcfaf3509790009ad062e8d4c6990 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Wed, 26 Apr 2023 15:26:07 +0100 Subject: [PATCH 700/715] Various minor fixes (#13945) * Fix: Incorrect implementation of can_reserve check * Fix: Incorrect migration of consumer counting for existing accounts with frozen amounts * Fix: Inconsistent implementation between assets can_deposit and new_account * Fixes * Fixes * Another fix * Update tests.rs * Update fungible_tests.rs * Use `can_accrue_consumers` in the body of `can_inc_consumer` --------- Co-authored-by: Keith Yeung Co-authored-by: Oliver Tale-Yazdi Co-authored-by: parity-processbot <> --- frame/assets/src/functions.rs | 2 +- frame/assets/src/tests.rs | 51 ++++++++++++++++++---- frame/balances/src/impl_currency.rs | 4 +- frame/balances/src/lib.rs | 2 +- frame/balances/src/tests/currency_tests.rs | 10 +++++ frame/balances/src/tests/fungible_tests.rs | 25 +++++++++++ frame/system/src/lib.rs | 20 +++++++-- 7 files changed, 98 insertions(+), 16 deletions(-) diff --git a/frame/assets/src/functions.rs b/frame/assets/src/functions.rs index af9e269acf8bc..1e10e0066e851 100644 --- a/frame/assets/src/functions.rs +++ b/frame/assets/src/functions.rs @@ -138,7 +138,7 @@ impl, I: 'static> Pallet { if amount < details.min_balance { return DepositConsequence::BelowMinimum } - if !details.is_sufficient && !frame_system::Pallet::::can_inc_consumer(who) { + if !details.is_sufficient && !frame_system::Pallet::::can_accrue_consumers(who, 2) { return DepositConsequence::CannotCreate } if details.is_sufficient && details.sufficients.checked_add(1).is_none() { diff --git a/frame/assets/src/tests.rs b/frame/assets/src/tests.rs index afd224ad66642..b47fb6486cb27 100644 --- a/frame/assets/src/tests.rs +++ b/frame/assets/src/tests.rs @@ -21,7 +21,7 @@ use super::*; use crate::{mock::*, Error}; use frame_support::{ assert_noop, assert_ok, - traits::{fungibles::InspectEnumerable, Currency}, + traits::{fungibles::InspectEnumerable, tokens::Preservation::Protect, Currency}, }; use pallet_balances::Error as BalancesError; use sp_io::storage; @@ -33,6 +33,25 @@ fn asset_ids() -> Vec { s } +#[test] +fn transfer_should_never_burn() { + new_test_ext().execute_with(|| { + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, false, 1)); + Balances::make_free_balance_be(&1, 100); + Balances::make_free_balance_be(&2, 100); + + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); + assert_eq!(Assets::balance(0, 1), 100); + + while System::inc_consumers(&2).is_ok() {} + let _ = System::dec_consumers(&2); + // Exactly one consumer ref remaining. + + let _ = >::transfer(0, &1, &2, 50, Protect); + assert_eq!(Assets::balance(0, 1) + Assets::balance(0, 2), 100); + }); +} + #[test] fn basic_minting_should_work() { new_test_ext().execute_with(|| { @@ -57,10 +76,7 @@ fn minting_too_many_insufficient_assets_fails() { Balances::make_free_balance_be(&1, 100); 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), - Error::::UnavailableConsumer - ); + assert_noop!(Assets::mint(RuntimeOrigin::signed(1), 2, 1, 100), TokenError::CannotCreate); Balances::make_free_balance_be(&2, 1); assert_ok!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 100)); @@ -78,10 +94,7 @@ fn minting_insufficient_asset_with_deposit_should_work_when_consumers_exhausted( Balances::make_free_balance_be(&1, 100); 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), - Error::::UnavailableConsumer - ); + assert_noop!(Assets::mint(RuntimeOrigin::signed(1), 2, 1, 100), TokenError::CannotCreate); assert_ok!(Assets::touch(RuntimeOrigin::signed(1), 2)); assert_eq!(Balances::reserved_balance(&1), 10); @@ -1322,3 +1335,23 @@ fn asset_create_and_destroy_is_reverted_if_callback_fails() { ); }); } + +#[test] +fn multiple_transfer_alls_work_ok() { + new_test_ext().execute_with(|| { + // Only run PoC when the system pallet is enabled, since the underlying bug is in the + // system pallet it won't work with BalancesAccountStore + // Start with a balance of 100 + Balances::force_set_balance(RuntimeOrigin::root(), 1, 100).unwrap(); + // Emulate a sufficient, in reality this could be reached by transferring a sufficient + // asset to the account + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); + // Spend the same balance multiple times + assert_ok!(Balances::transfer_all(RuntimeOrigin::signed(1), 1337, false)); + assert_ok!(Balances::transfer_all(RuntimeOrigin::signed(1), 1337, false)); + + assert_eq!(Balances::free_balance(&1), 0); + assert_eq!(Balances::free_balance(&1337), 100); + }); +} diff --git a/frame/balances/src/impl_currency.rs b/frame/balances/src/impl_currency.rs index ff8cc71d6224a..9f764a37b8b89 100644 --- a/frame/balances/src/impl_currency.rs +++ b/frame/balances/src/impl_currency.rs @@ -490,7 +490,9 @@ where return true } Self::account(who).free.checked_sub(&value).map_or(false, |new_balance| { - Self::ensure_can_withdraw(who, value, WithdrawReasons::RESERVE, new_balance).is_ok() + new_balance >= T::ExistentialDeposit::get() && + Self::ensure_can_withdraw(who, value, WithdrawReasons::RESERVE, new_balance) + .is_ok() }) } diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index 6835d3c8148bb..c87b01d77bae5 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -788,7 +788,7 @@ pub mod pallet { return false } a.flags.set_new_logic(); - if !a.reserved.is_zero() || !a.frozen.is_zero() { + if !a.reserved.is_zero() && a.frozen.is_zero() { if system::Pallet::::providers(who) == 0 { // Gah!! We have no provider refs :( // This shouldn't practically happen, but we need a failsafe anyway: let's give diff --git a/frame/balances/src/tests/currency_tests.rs b/frame/balances/src/tests/currency_tests.rs index 034c92f65689b..e25b122c1fcf0 100644 --- a/frame/balances/src/tests/currency_tests.rs +++ b/frame/balances/src/tests/currency_tests.rs @@ -1180,6 +1180,16 @@ fn named_reserve_should_work() { }); } +#[test] +fn reserve_must_succeed_if_can_reserve_does() { + ExtBuilder::default().build_and_execute_with(|| { + let _ = Balances::deposit_creating(&1, 1); + let _ = Balances::deposit_creating(&2, 2); + assert!(Balances::can_reserve(&1, 1) == Balances::reserve(&1, 1).is_ok()); + assert!(Balances::can_reserve(&2, 1) == Balances::reserve(&2, 1).is_ok()); + }); +} + #[test] fn reserved_named_to_yourself_should_work() { ExtBuilder::default().build_and_execute_with(|| { diff --git a/frame/balances/src/tests/fungible_tests.rs b/frame/balances/src/tests/fungible_tests.rs index 185396019b13d..ab2606c53ff71 100644 --- a/frame/balances/src/tests/fungible_tests.rs +++ b/frame/balances/src/tests/fungible_tests.rs @@ -398,6 +398,31 @@ fn unholding_frees_hold_slot() { }); } +#[test] +fn sufficients_work_properly_with_reference_counting() { + ExtBuilder::default() + .existential_deposit(1) + .monied(true) + .build_and_execute_with(|| { + // Only run PoC when the system pallet is enabled, since the underlying bug is in the + // system pallet it won't work with BalancesAccountStore + if UseSystem::get() { + // Start with a balance of 100 + >::set_balance(&1, 100); + // Emulate a sufficient, in reality this could be reached by transferring a + // sufficient asset to the account + System::inc_sufficients(&1); + // Spend the same balance multiple times + assert_ok!(>::transfer(&1, &1337, 100, Expendable)); + assert_eq!(Balances::free_balance(&1), 0); + assert_noop!( + >::transfer(&1, &1337, 100, Expendable), + TokenError::FundsUnavailable + ); + } + }); +} + #[test] fn emit_events_with_changing_freezes() { ExtBuilder::default().build_and_execute_with(|| { diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 88291c326edba..6bbebb870594c 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -1222,10 +1222,20 @@ impl Pallet { a.consumers == 0 || a.providers > 1 } - /// True if the account has at least one provider reference. - pub fn can_inc_consumer(who: &T::AccountId) -> bool { + /// True if the account has at least one provider reference and adding `amount` consumer + /// references would not take it above the the maximum. + pub fn can_accrue_consumers(who: &T::AccountId, amount: u32) -> bool { let a = Account::::get(who); - a.providers > 0 && a.consumers < T::MaxConsumers::max_consumers() + match a.consumers.checked_add(amount) { + Some(c) => a.providers > 0 && c <= T::MaxConsumers::max_consumers(), + None => false, + } + } + + /// True if the account has at least one provider reference and fewer consumer references than + /// the maximum. + pub fn can_inc_consumer(who: &T::AccountId) -> bool { + Self::can_accrue_consumers(who, 1) } /// Deposits an event into this block's event record. @@ -1679,8 +1689,10 @@ impl StoredMap for Pallet { let is_default = account.data == T::AccountData::default(); let mut some_data = if is_default { None } else { Some(account.data) }; let result = f(&mut some_data)?; - if Self::providers(k) > 0 { + if Self::providers(k) > 0 || Self::sufficients(k) > 0 { Account::::mutate(k, |a| a.data = some_data.unwrap_or_default()); + } else { + Account::::remove(k) } Ok(result) } From 2e7e628ecdf96d279c4c3d5d1aea0dd55a02012e Mon Sep 17 00:00:00 2001 From: PG Herveou Date: Thu, 27 Apr 2023 08:23:01 +0200 Subject: [PATCH 701/715] contracts Add storage_deposit test (#14003) * contracts Add storage_deposit test * fix comments * PR comments --- frame/contracts/fixtures/call.wat | 39 +++++++++++++++++++++++ frame/contracts/src/tests.rs | 53 +++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 frame/contracts/fixtures/call.wat diff --git a/frame/contracts/fixtures/call.wat b/frame/contracts/fixtures/call.wat new file mode 100644 index 0000000000000..4558b2c6409b9 --- /dev/null +++ b/frame/contracts/fixtures/call.wat @@ -0,0 +1,39 @@ +;; This calls another contract as passed as its account id. +(module + (import "seal0" "seal_input" (func $seal_input (param i32 i32))) + (import "seal1" "seal_call" (func $seal_call (param i32 i32 i64 i32 i32 i32 i32 i32) (result i32))) + (import "env" "memory" (memory 1 1)) + + (func $assert (param i32) + (block $ok + (br_if $ok + (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)) + + ;; Call passed contract. + (call $assert (i32.eqz + (call $seal_call + (i32.const 0) ;; No flags + (i32.const 8) ;; Pointer to "callee" address. + (i64.const 0) ;; How much gas to devote for the execution. 0 = all. + (i32.const 512) ;; Pointer to the buffer with value to transfer + (i32.const 4) ;; Pointer to input data buffer address + (i32.const 4) ;; Length of input data buffer + (i32.const 4294967295) ;; u32 max value is the sentinel value: do not copy output + (i32.const 0) ;; Length is ignored in this case + ) + )) + ) +) diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index 3c1015bc9ec60..dbe61cf33da56 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -3582,6 +3582,59 @@ fn storage_deposit_works() { }); } +#[test] +fn storage_deposit_callee_works() { + let (wasm_caller, _code_hash_caller) = compile_module::("call").unwrap(); + let (wasm_callee, _code_hash_callee) = compile_module::("store").unwrap(); + const ED: u64 = 200; + ExtBuilder::default().existential_deposit(ED).build().execute_with(|| { + let _ = Balances::deposit_creating(&ALICE, 1_000_000); + + // Create both contracts: Constructors do nothing. + let addr_caller = Contracts::bare_instantiate( + ALICE, + 0, + GAS_LIMIT, + None, + Code::Upload(wasm_caller), + vec![], + vec![], + false, + ) + .result + .unwrap() + .account_id; + let addr_callee = Contracts::bare_instantiate( + ALICE, + 0, + GAS_LIMIT, + None, + Code::Upload(wasm_callee), + vec![], + vec![], + false, + ) + .result + .unwrap() + .account_id; + + assert_ok!(Contracts::call( + RuntimeOrigin::signed(ALICE), + addr_caller, + 0, + GAS_LIMIT, + None, + (100u32, &addr_callee).encode() + )); + + let callee = get_contract(&addr_callee); + let deposit = ED + DepositPerByte::get() * 100 + DepositPerItem::get() * 1; + + assert_eq!(test_utils::get_balance(callee.deposit_account()), deposit); + assert_eq!(callee.total_deposit(), deposit); + }); +} + #[test] fn set_code_extrinsic() { let (wasm, code_hash) = compile_module::("dummy").unwrap(); From dce73feadc8e33983a055e06f56066665c218544 Mon Sep 17 00:00:00 2001 From: Liam Aharon Date: Thu, 27 Apr 2023 18:12:29 +1000 Subject: [PATCH 702/715] remote-externalities: batch insert key/values (#14004) * add batch inserting into remote externalities * use into_iter * remove redundant comment * redundant batch insert * avoid extra vec allocations --- primitives/state-machine/src/testing.rs | 11 +++++ utils/frame/remote-externalities/src/lib.rs | 49 +++++++++------------ 2 files changed, 32 insertions(+), 28 deletions(-) diff --git a/primitives/state-machine/src/testing.rs b/primitives/state-machine/src/testing.rs index 3a0165fe4588d..1921287a64745 100644 --- a/primitives/state-machine/src/testing.rs +++ b/primitives/state-machine/src/testing.rs @@ -132,6 +132,17 @@ where self.offchain_db.clone() } + /// Batch insert key/values into backend + pub fn batch_insert(&mut self, kvs: I) + where + I: IntoIterator, + { + self.backend.insert( + Some((None, kvs.into_iter().map(|(k, v)| (k, Some(v))).collect())), + self.state_version, + ); + } + /// Insert key/value into backend pub fn insert(&mut self, k: StorageKey, v: StorageValue) { self.backend.insert(vec![(None, vec![(k, Some(v))])], self.state_version); diff --git a/utils/frame/remote-externalities/src/lib.rs b/utils/frame/remote-externalities/src/lib.rs index b60e2bc75d0db..ea9b68ce2f6ae 100644 --- a/utils/frame/remote-externalities/src/lib.rs +++ b/utils/frame/remote-externalities/src/lib.rs @@ -638,24 +638,20 @@ where let mut processed = 0usize; loop { match rx.next().await.unwrap() { - Message::Batch(kv) => { - for (k, v) in kv { - processed += 1; - if processed % 50_000 == 0 || processed == keys.len() || processed == 1 { - log::info!( - target: LOG_TARGET, - "inserting keys progress = {:.0}% [{} / {}]", - (processed as f32 / keys.len() as f32) * 100f32, - processed, - keys.len(), - ); - } - // skip writing the child root data. - if is_default_child_storage_key(k.as_ref()) { - continue - } - pending_ext.insert(k, v); - } + Message::Batch(kvs) => { + let kvs = kvs + .into_iter() + .filter(|(k, _)| !is_default_child_storage_key(k)) + .collect::>(); + processed += kvs.len(); + pending_ext.batch_insert(kvs); + log::info!( + target: LOG_TARGET, + "inserting keys progress = {:.0}% [{} / {}]", + (processed as f32 / keys.len() as f32) * 100f32, + processed, + keys.len(), + ); }, Message::BatchFailed(error) => { log::error!(target: LOG_TARGET, "Batch processing failed: {:?}", error); @@ -1010,13 +1006,12 @@ where ); info!(target: LOG_TARGET, "injecting a total of {} top keys", top.len()); - for (k, v) in top { - // skip writing the child root data. - if is_default_child_storage_key(k.as_ref()) { - continue - } - inner_ext.insert(k.0, v.0); - } + let top = top + .into_iter() + .filter(|(k, _)| !is_default_child_storage_key(k.as_ref())) + .map(|(k, v)| (k.0, v.0)) + .collect::>(); + inner_ext.batch_insert(top); info!( target: LOG_TARGET, @@ -1052,9 +1047,7 @@ where "extending externalities with {} manually injected key-values", self.hashed_key_values.len() ); - for (k, v) in self.hashed_key_values { - ext.insert(k.0, v.0); - } + ext.batch_insert(self.hashed_key_values.into_iter().map(|(k, v)| (k.0, v.0))); } // exclude manual key values. From 587959e2287360bfe64b84fd983031d0bed9b892 Mon Sep 17 00:00:00 2001 From: Liam Aharon Date: Thu, 27 Apr 2023 18:55:01 +1000 Subject: [PATCH 703/715] collective pallet: sort genesis members and enforce max len constraint (#13988) * insert members in sorted order * improve variable name * enforce genesis members length constraint --- frame/collective/src/lib.rs | 6 ++++++ frame/collective/src/tests.rs | 40 +++++++++++++++++++++++++++++++---- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/frame/collective/src/lib.rs b/frame/collective/src/lib.rs index 0ecf008fee80e..fd89a998ad97e 100644 --- a/frame/collective/src/lib.rs +++ b/frame/collective/src/lib.rs @@ -246,6 +246,10 @@ pub mod pallet { self.members.len(), "Members cannot contain duplicate accounts." ); + assert!( + self.members.len() <= T::MaxMembers::get() as usize, + "Members length cannot exceed MaxMembers.", + ); Pallet::::initialize_members(&self.members) } @@ -1107,6 +1111,8 @@ impl, I: 'static> InitializeMembers for Pallet fn initialize_members(members: &[T::AccountId]) { if !members.is_empty() { assert!(>::get().is_empty(), "Members are already initialized!"); + let mut members = members.to_vec(); + members.sort(); >::put(members); } } diff --git a/frame/collective/src/tests.rs b/frame/collective/src/tests.rs index 4775133ffa2f6..1165ebcec2287 100644 --- a/frame/collective/src/tests.rs +++ b/frame/collective/src/tests.rs @@ -86,6 +86,7 @@ mod mock_democracy { } pub type MaxMembers = ConstU32<100>; +type AccountId = u64; parameter_types! { pub const MotionDuration: u64 = 3; @@ -105,7 +106,7 @@ impl frame_system::Config for Test { type RuntimeCall = RuntimeCall; type Hash = H256; type Hashing = BlakeTwo256; - type AccountId = u64; + type AccountId = AccountId; type Lookup = IdentityLookup; type Header = Header; type RuntimeEvent = RuntimeEvent; @@ -161,19 +162,26 @@ impl Config for Test { type MaxProposalWeight = MaxProposalWeight; } -pub struct ExtBuilder {} +pub struct ExtBuilder { + collective_members: Vec, +} impl Default for ExtBuilder { fn default() -> Self { - Self {} + Self { collective_members: vec![1, 2, 3] } } } impl ExtBuilder { + fn set_collective_members(mut self, collective_members: Vec) -> Self { + self.collective_members = collective_members; + self + } + pub fn build(self) -> sp_io::TestExternalities { let mut ext: sp_io::TestExternalities = GenesisConfig { collective: pallet_collective::GenesisConfig { - members: vec![1, 2, 3], + members: self.collective_members, phantom: Default::default(), }, collective_majority: pallet_collective::GenesisConfig { @@ -219,6 +227,17 @@ fn motions_basic_environment_works() { }); } +#[test] +fn initialize_members_sorts_members() { + let unsorted_members = vec![3, 2, 4, 1]; + let expected_members = vec![1, 2, 3, 4]; + ExtBuilder::default() + .set_collective_members(unsorted_members) + .build_and_execute(|| { + assert_eq!(Collective::members(), expected_members); + }); +} + #[test] fn proposal_weight_limit_works() { ExtBuilder::default().build_and_execute(|| { @@ -1424,6 +1443,19 @@ fn disapprove_proposal_works() { }) } +#[should_panic(expected = "Members length cannot exceed MaxMembers.")] +#[test] +fn genesis_build_panics_with_too_many_members() { + let max_members: u32 = MaxMembers::get(); + let too_many_members = (1..=max_members as u64 + 1).collect::>(); + pallet_collective::GenesisConfig:: { + members: too_many_members, + phantom: Default::default(), + } + .build_storage() + .unwrap(); +} + #[test] #[should_panic(expected = "Members cannot contain duplicate accounts.")] fn genesis_build_panics_with_duplicate_members() { From 1e4c01125c326e2cef0c3318b70eea5093b744bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Thu, 27 Apr 2023 11:28:03 +0200 Subject: [PATCH 704/715] sc-network-sync: Improve error reporting (#14025) Before this wasn't printing a warning for `VerificationFailed` when there wasn't a peer assigned to the error message. However, if there happens an error on importing the state there wouldn't be any error. This pr improves the situation to also print an error in this case. Besides that there are some other cleanups. --- client/network/sync/src/lib.rs | 43 +++++++++++++++------------------- 1 file changed, 19 insertions(+), 24 deletions(-) diff --git a/client/network/sync/src/lib.rs b/client/network/sync/src/lib.rs index 29c4bc840b2ae..3f1cbebd57255 100644 --- a/client/network/sync/src/lib.rs +++ b/client/network/sync/src/lib.rs @@ -2708,9 +2708,7 @@ where break } - if result.is_err() { - has_error = true; - } + has_error |= result.is_err(); match result { Ok(BlockImportStatus::ImportedKnown(number, who)) => @@ -2721,9 +2719,7 @@ where if aux.clear_justification_requests { trace!( target: "sync", - "Block imported clears all pending justification requests {}: {:?}", - number, - hash, + "Block imported clears all pending justification requests {number}: {hash:?}", ); self.clear_justification_requests(); } @@ -2731,9 +2727,7 @@ where if aux.needs_justification { trace!( target: "sync", - "Block imported but requires justification {}: {:?}", - number, - hash, + "Block imported but requires justification {number}: {hash:?}", ); self.request_justification(&hash, number); } @@ -2793,25 +2787,26 @@ where output.push(Err(BadPeer(peer, rep::INCOMPLETE_HEADER))); output.extend(self.restart()); }, - Err(BlockImportError::VerificationFailed(who, e)) => + Err(BlockImportError::VerificationFailed(who, e)) => { + let extra_message = + who.map_or_else(|| "".into(), |peer| format!(" received from ({peer})")); + + warn!( + target: "sync", + "💔 Verification failed for block {hash:?}{extra_message}: {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()); - }, + } + + 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, + "💔 Block {hash:?} received from peer {peer} has been blacklisted", ); output.push(Err(BadPeer(peer, rep::BAD_BLOCK))); }, @@ -2819,10 +2814,10 @@ where // This may happen if the chain we were requesting upon has been discarded // in the meantime because other chain has been finalized. // Don't mark it as bad as it still may be synced if explicitly requested. - trace!(target: "sync", "Obsolete block {:?}", hash); + trace!(target: "sync", "Obsolete block {hash:?}"); }, e @ Err(BlockImportError::UnknownParent) | e @ Err(BlockImportError::Other(_)) => { - warn!(target: "sync", "💔 Error importing block {:?}: {}", hash, e.unwrap_err()); + warn!(target: "sync", "💔 Error importing block {hash:?}: {}", e.unwrap_err()); self.state_sync = None; self.warp_sync = None; output.extend(self.restart()); From d5d63e9b7f624de321032a033675387a73a66646 Mon Sep 17 00:00:00 2001 From: PG Herveou Date: Thu, 27 Apr 2023 12:01:12 +0200 Subject: [PATCH 705/715] contracts Fix store-call test path (#14028) --- frame/contracts/src/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index dbe61cf33da56..697b58f15c609 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -3585,7 +3585,7 @@ fn storage_deposit_works() { #[test] fn storage_deposit_callee_works() { let (wasm_caller, _code_hash_caller) = compile_module::("call").unwrap(); - let (wasm_callee, _code_hash_callee) = compile_module::("store").unwrap(); + let (wasm_callee, _code_hash_callee) = compile_module::("store_call").unwrap(); const ED: u64 = 200; ExtBuilder::default().existential_deposit(ED).build().execute_with(|| { let _ = Balances::deposit_creating(&ALICE, 1_000_000); From 04248e293e5156a5468ed162a8565f192de325d7 Mon Sep 17 00:00:00 2001 From: yjh Date: Thu, 27 Apr 2023 18:34:15 +0800 Subject: [PATCH 706/715] chore(cli): make cli display docs correctly (#14017) * chore(cli): make cli display docs correctly * ".git/.scripts/commands/fmt/fmt.sh" --------- Co-authored-by: command-bot <> --- client/cli/src/commands/build_spec_cmd.rs | 1 - client/cli/src/commands/check_block_cmd.rs | 3 +- client/cli/src/commands/export_blocks_cmd.rs | 2 -- client/cli/src/commands/generate_node_key.rs | 2 -- client/cli/src/commands/import_blocks_cmd.rs | 1 - client/cli/src/commands/insert_key.rs | 2 +- client/cli/src/commands/inspect_key.rs | 5 --- client/cli/src/commands/inspect_node_key.rs | 2 -- client/cli/src/commands/run_cmd.rs | 11 ------- client/cli/src/params/import_params.rs | 7 ---- client/cli/src/params/network_params.rs | 6 ---- client/cli/src/params/node_key_params.rs | 12 ------- .../cli/src/params/offchain_worker_params.rs | 5 +-- client/cli/src/params/prometheus_params.rs | 2 -- client/cli/src/params/pruning_params.rs | 32 +++---------------- client/cli/src/params/shared_params.rs | 7 ---- client/cli/src/params/telemetry_params.rs | 2 -- 17 files changed, 8 insertions(+), 94 deletions(-) diff --git a/client/cli/src/commands/build_spec_cmd.rs b/client/cli/src/commands/build_spec_cmd.rs index a2cbfedb764fc..aa5314f9cf5a4 100644 --- a/client/cli/src/commands/build_spec_cmd.rs +++ b/client/cli/src/commands/build_spec_cmd.rs @@ -38,7 +38,6 @@ pub struct BuildSpecCmd { 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. #[arg(long)] diff --git a/client/cli/src/commands/check_block_cmd.rs b/client/cli/src/commands/check_block_cmd.rs index 897b61c8e0386..ba20376d998a9 100644 --- a/client/cli/src/commands/check_block_cmd.rs +++ b/client/cli/src/commands/check_block_cmd.rs @@ -29,12 +29,11 @@ use std::{fmt::Debug, str::FromStr, sync::Arc}; /// The `check-block` command used to validate blocks. #[derive(Debug, Clone, Parser)] pub struct CheckBlockCmd { - /// Block hash or number + /// Block 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. #[arg(long, value_name = "COUNT")] pub default_heap_pages: Option, diff --git a/client/cli/src/commands/export_blocks_cmd.rs b/client/cli/src/commands/export_blocks_cmd.rs index 7e8a295f99618..120d7889878e5 100644 --- a/client/cli/src/commands/export_blocks_cmd.rs +++ b/client/cli/src/commands/export_blocks_cmd.rs @@ -36,13 +36,11 @@ pub struct ExportBlocksCmd { pub output: Option, /// Specify starting block number. - /// /// Default is 1. #[arg(long, value_name = "BLOCK")] pub from: Option, /// Specify last block number. - /// /// Default is best block. #[arg(long, value_name = "BLOCK")] pub to: Option, diff --git a/client/cli/src/commands/generate_node_key.rs b/client/cli/src/commands/generate_node_key.rs index 2288cd4037773..a16ba499082c5 100644 --- a/client/cli/src/commands/generate_node_key.rs +++ b/client/cli/src/commands/generate_node_key.rs @@ -35,13 +35,11 @@ use std::{ )] pub struct GenerateNodeKeyCmd { /// Name of file to save secret key to. - /// /// If not given, the secret key is printed to stdout. #[arg(long)] file: Option, /// The output is in raw binary format. - /// /// If not given, the output is written as an hex encoded string. #[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 f76c72924ddb6..815c6ab18aa6c 100644 --- a/client/cli/src/commands/import_blocks_cmd.rs +++ b/client/cli/src/commands/import_blocks_cmd.rs @@ -41,7 +41,6 @@ pub struct ImportBlocksCmd { 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. #[arg(long, value_name = "COUNT")] pub default_heap_pages: Option, diff --git a/client/cli/src/commands/insert_key.rs b/client/cli/src/commands/insert_key.rs index e80058d44a5af..fa9d125d33108 100644 --- a/client/cli/src/commands/insert_key.rs +++ b/client/cli/src/commands/insert_key.rs @@ -36,7 +36,7 @@ pub struct InsertKeyCmd { #[arg(long)] suri: Option, - /// Key type, examples: "gran", or "imon" + /// Key type, examples: "gran", or "imon". #[arg(long)] key_type: String, diff --git a/client/cli/src/commands/inspect_key.rs b/client/cli/src/commands/inspect_key.rs index de82fe71e2445..5aa8b0bdcaa60 100644 --- a/client/cli/src/commands/inspect_key.rs +++ b/client/cli/src/commands/inspect_key.rs @@ -34,12 +34,9 @@ use std::str::FromStr; pub struct InspectKeyCmd { /// A Key URI to be inspected. May be a secret seed, secret URI /// (with derivation paths and password), SS58, public URI or a hex encoded public key. - /// /// If it is a hex encoded public key, `--public` needs to be given as argument. - /// /// If the given value is a file, the file content will be used /// as URI. - /// /// If omitted, you will be prompted for the URI. uri: Option, @@ -64,12 +61,10 @@ pub struct InspectKeyCmd { 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. #[arg(long, conflicts_with = "public")] diff --git a/client/cli/src/commands/inspect_node_key.rs b/client/cli/src/commands/inspect_node_key.rs index 2370f4a0989ba..733a1343a4333 100644 --- a/client/cli/src/commands/inspect_node_key.rs +++ b/client/cli/src/commands/inspect_node_key.rs @@ -34,13 +34,11 @@ use std::{ )] 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). #[arg(long)] file: Option, /// The input is in raw binary format. - /// /// If not given, the input is read as an hex encoded string. #[arg(long)] bin: bool, diff --git a/client/cli/src/commands/run_cmd.rs b/client/cli/src/commands/run_cmd.rs index a38ba6f49e3dd..7cc1e6c730cc9 100644 --- a/client/cli/src/commands/run_cmd.rs +++ b/client/cli/src/commands/run_cmd.rs @@ -38,7 +38,6 @@ use std::net::{IpAddr, Ipv4Addr, SocketAddr}; #[derive(Debug, Clone, Parser)] pub struct RunCmd { /// Enable validator mode. - /// /// The node will be started with the authority role and actively /// participate in any consensus task that it can (e.g. depending on /// availability of local keys). @@ -51,7 +50,6 @@ pub struct RunCmd { pub no_grandpa: bool, /// Listen to all RPC interfaces. - /// /// Default is local. Note: not all RPC methods are safe to be exposed publicly. Use an RPC /// proxy server to filter out dangerous methods. More details: /// . @@ -60,13 +58,11 @@ pub struct RunCmd { pub rpc_external: bool, /// Listen to all RPC interfaces. - /// /// Same as `--rpc-external`. #[arg(long)] pub unsafe_rpc_external: bool, /// RPC methods to expose. - /// /// - `unsafe`: Exposes every RPC method. /// - `safe`: Exposes only a safe subset of RPC methods, denying unsafe RPC methods. /// - `auto`: Acts as `safe` if RPC is served externally, e.g. when `--{rpc,ws}-external` is @@ -82,7 +78,6 @@ pub struct RunCmd { pub rpc_methods: RpcMethods, /// Listen to all Websocket interfaces. - /// /// Default is local. Note: not all RPC methods are safe to be exposed publicly. Use an RPC /// proxy server to filter out dangerous methods. More details: /// . @@ -91,7 +86,6 @@ pub struct RunCmd { pub ws_external: bool, /// Listen to all Websocket interfaces. - /// /// Same as `--ws-external` but doesn't warn you about it. #[arg(long)] pub unsafe_ws_external: bool, @@ -137,7 +131,6 @@ pub struct RunCmd { 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` /// value). Value of `all` will disable origin validation. Default is to /// allow localhost and origins. When running in @@ -146,7 +139,6 @@ pub struct RunCmd { pub rpc_cors: Option, /// The human-readable name for this node. - /// /// It's used as network node name. #[arg(long, value_name = "NAME")] pub name: Option, @@ -225,13 +217,10 @@ pub struct RunCmd { pub force_authoring: bool, /// Run a temporary node. - /// /// A temporary directory will be created to store the configuration and will be deleted /// at the end of the process. - /// /// Note: the directory is random per process execution. This directory is used as base path /// which includes: database, node key and keystore. - /// /// When `--dev` is given and no explicit `--base-path`, this option is implied. #[arg(long, conflicts_with = "base_path")] pub tmp: bool, diff --git a/client/cli/src/params/import_params.rs b/client/cli/src/params/import_params.rs index e36fbb5ffd91c..9e57a017e51ca 100644 --- a/client/cli/src/params/import_params.rs +++ b/client/cli/src/params/import_params.rs @@ -52,15 +52,11 @@ 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. @@ -73,7 +69,6 @@ pub struct ImportParams { pub wasmtime_instantiation_strategy: WasmtimeInstantiationStrategy, /// Specify the path where local WASM runtimes are stored. - /// /// These runtimes will override on-chain runtimes when the version matches. #[arg(long, value_name = "PATH")] pub wasm_runtime_overrides: Option, @@ -83,13 +78,11 @@ pub struct ImportParams { pub execution_strategies: ExecutionStrategiesParams, /// Specify the state cache size. - /// /// Providing `0` will disable the cache. #[arg(long, value_name = "Bytes", default_value_t = 67108864)] pub trie_cache_size: usize, /// DEPRECATED - /// /// Switch to `--trie-cache-size`. #[arg(long)] state_cache_size: Option, diff --git a/client/cli/src/params/network_params.rs b/client/cli/src/params/network_params.rs index 9d61e7204295d..13e4338257691 100644 --- a/client/cli/src/params/network_params.rs +++ b/client/cli/src/params/network_params.rs @@ -42,9 +42,7 @@ pub struct NetworkParams { pub reserved_nodes: Vec, /// Whether to only synchronize the chain with reserved nodes. - /// /// Also disables automatic peer discovery. - /// /// TCP connections might still be established with non-reserved nodes. /// In particular, if you are a validator your node might still connect to other /// validator nodes and collator nodes regardless of whether they are defined as @@ -95,14 +93,12 @@ pub struct NetworkParams { 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. #[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. #[arg(long, value_name = "COUNT", default_value_t = 5)] @@ -113,7 +109,6 @@ pub struct NetworkParams { pub node_key_params: NodeKeyParams, /// Enable peer discovery on local networks. - /// /// By default this option is `true` for `--dev` or when the chain type is /// `Local`/`Development` and false otherwise. #[arg(long)] @@ -121,7 +116,6 @@ pub struct NetworkParams { /// Require iterative Kademlia DHT queries to use disjoint paths for increased resiliency in /// the presence of potentially adversarial nodes. - /// /// See the S/Kademlia paper for more information on the high level design as well as its /// security improvements. #[arg(long)] diff --git a/client/cli/src/params/node_key_params.rs b/client/cli/src/params/node_key_params.rs index 074b95bea0f3a..e31963d2f8b9d 100644 --- a/client/cli/src/params/node_key_params.rs +++ b/client/cli/src/params/node_key_params.rs @@ -33,16 +33,12 @@ const NODE_KEY_ED25519_FILE: &str = "secret_ed25519"; #[derive(Debug, Clone, Args)] pub struct NodeKeyParams { /// The secret key to use for libp2p networking. - /// /// The value is a string that is parsed according to the choice of /// `--node-key-type` as follows: - /// /// `ed25519`: /// The value is parsed as a hex-encoded Ed25519 32 byte secret key, /// i.e. 64 hex characters. - /// /// The value of this option takes precedence over `--node-key-file`. - /// /// WARNING: Secrets provided as command-line arguments are easily exposed. /// Use of this option should be limited to development and testing. To use /// an externally managed secret key, use `--node-key-file` instead. @@ -50,33 +46,25 @@ pub struct NodeKeyParams { pub node_key: Option, /// The type of secret key to use for libp2p networking. - /// /// The secret key of the node is obtained as follows: - /// /// * If the `--node-key` option is given, the value is parsed as a secret key according to /// the type. See the documentation for `--node-key`. - /// /// * If the `--node-key-file` option is given, the secret key is read from the specified /// file. See the documentation for `--node-key-file`. - /// /// * Otherwise, the secret key is read from a file with a predetermined, type-specific name /// from the chain-specific network config directory inside the base directory specified by /// `--base-dir`. If this file does not exist, it is created with a newly generated secret /// key of the chosen type. - /// /// The node's secret key determines the corresponding public key and hence the /// node's peer ID in the context of libp2p. #[arg(long, value_name = "TYPE", value_enum, ignore_case = true, default_value_t = NodeKeyType::Ed25519)] pub node_key_type: NodeKeyType, /// The file from which to read the node's secret key to use for libp2p networking. - /// /// The contents of the file are parsed according to the choice of `--node-key-type` /// as follows: - /// /// `ed25519`: /// The file must contain an unencoded 32 byte or hex encoded Ed25519 secret key. - /// /// If the file does not exist, it is created with a newly generated secret key of /// the chosen type. #[arg(long, value_name = "FILE")] diff --git a/client/cli/src/params/offchain_worker_params.rs b/client/cli/src/params/offchain_worker_params.rs index 33fd8d609b605..d1fedab4cb2eb 100644 --- a/client/cli/src/params/offchain_worker_params.rs +++ b/client/cli/src/params/offchain_worker_params.rs @@ -33,7 +33,6 @@ use crate::{error, OffchainWorkerEnabled}; #[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. #[arg( long = "offchain-worker", @@ -45,9 +44,7 @@ pub struct OffchainWorkerParams { pub enabled: OffchainWorkerEnabled, /// Enable Offchain Indexing API, which allows block import to write to Offchain DB. - /// - /// Enables a runtime to write directly to a offchain workers - /// DB during block import. + /// Enables a runtime to write directly to a offchain workers DB during block import. #[arg(long = "enable-offchain-indexing", value_name = "ENABLE_OFFCHAIN_INDEXING", default_value_t = false, action = ArgAction::Set)] pub indexing_enabled: bool, } diff --git a/client/cli/src/params/prometheus_params.rs b/client/cli/src/params/prometheus_params.rs index 69199ad5b2603..4d234ea33c20d 100644 --- a/client/cli/src/params/prometheus_params.rs +++ b/client/cli/src/params/prometheus_params.rs @@ -27,12 +27,10 @@ pub struct PrometheusParams { #[arg(long, value_name = "PORT")] pub prometheus_port: Option, /// Expose Prometheus exporter on all interfaces. - /// /// Default is local. #[arg(long)] pub prometheus_external: bool, /// Do not expose a Prometheus exporter endpoint. - /// /// Prometheus metric endpoint is enabled by default. #[arg(long)] pub no_prometheus: bool, diff --git a/client/cli/src/params/pruning_params.rs b/client/cli/src/params/pruning_params.rs index 757da2dd9cbb5..1b5bf247d942e 100644 --- a/client/cli/src/params/pruning_params.rs +++ b/client/cli/src/params/pruning_params.rs @@ -24,48 +24,26 @@ use sc_service::{BlocksPruning, PruningMode}; #[derive(Debug, Clone, Args)] pub struct PruningParams { /// Specify the state pruning mode. - /// /// This mode specifies when the block's state (ie, storage) /// should be pruned (ie, removed) from the database. - /// /// This setting can only be set on the first creation of the database. Every subsequent run /// will load the pruning mode from the database and will error if the stored mode doesn't /// match this CLI value. It is fine to drop this CLI flag for subsequent runs. - /// /// 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. - /// + /// - 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. /// [default: 256] #[arg(alias = "pruning", long, value_name = "PRUNING_MODE")] pub state_pruning: Option, /// Specify the blocks pruning mode. - /// /// This mode specifies when the block's body (including justifications) /// should be pruned (ie, removed) from the database. - /// /// Possible values: - /// - 'archive' - /// - /// Keep all blocks. - /// - /// - 'archive-canonical' - /// - /// Keep only finalized blocks. - /// + /// - 'archive' Keep all blocks. + /// - 'archive-canonical' Keep only finalized blocks. /// - number - /// /// Keep the last `number` of finalized blocks. #[arg( alias = "keep-blocks", diff --git a/client/cli/src/params/shared_params.rs b/client/cli/src/params/shared_params.rs index 913a6c436185c..3d20ca504a691 100644 --- a/client/cli/src/params/shared_params.rs +++ b/client/cli/src/params/shared_params.rs @@ -25,14 +25,12 @@ use std::path::PathBuf; #[derive(Debug, Clone, Args)] pub struct SharedParams { /// Specify the chain specification. - /// /// It can be one of the predefined ones (dev, local, or staging) or it can be a path to a file /// with the chainspec (such as one exported by the `build-spec` subcommand). #[arg(long, value_name = "CHAIN_SPEC")] pub chain: Option, /// Specify the development chain. - /// /// This flag sets `--chain=dev`, `--force-authoring`, `--rpc-cors=all`, /// `--alice`, and `--tmp` flags, unless explicitly overridden. #[arg(long, conflicts_with_all = &["chain"])] @@ -43,16 +41,13 @@ pub struct SharedParams { 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`. #[arg(short = 'l', long, value_name = "LOG_PATTERN", num_args = 1..)] pub log: Vec, /// Enable detailed log output. - /// /// This includes displaying the log target, log level and thread name. - /// /// This is automatically enabled when something is logged with any higher level than `info`. #[arg(long)] pub detailed_log_output: bool, @@ -62,10 +57,8 @@ pub struct SharedParams { pub disable_log_color: bool, /// Enable feature to dynamically update and reload the log filter. - /// /// Be aware that enabling this feature can lead to a performance decrease up to factor six or /// more. Depending on the global logging level the performance decrease changes. - /// /// The `system_addLogFilter` and `system_resetLogFilter` RPCs will have no effect with this /// option not being set. #[arg(long)] diff --git a/client/cli/src/params/telemetry_params.rs b/client/cli/src/params/telemetry_params.rs index ca096419869af..67f441071410c 100644 --- a/client/cli/src/params/telemetry_params.rs +++ b/client/cli/src/params/telemetry_params.rs @@ -22,13 +22,11 @@ use clap::Args; #[derive(Debug, Clone, Args)] pub struct TelemetryParams { /// Disable connecting to the Substrate telemetry server. - /// /// Telemetry is on by default on global chains. #[arg(long)] pub no_telemetry: bool, /// The URL of the telemetry server to connect to. - /// /// This flag can be passed multiple times as a means to specify multiple /// telemetry endpoints. Verbosity levels range from 0-9, with 0 denoting /// the least verbosity. From 58be496f61f98b8e04fbf11a46e56bb9c2b3d9c7 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Thu, 27 Apr 2023 13:27:12 +0200 Subject: [PATCH 707/715] improve staking interface methods (#14023) * improve staking interface methods * fix * fix * fix build * restart * fix --------- Co-authored-by: parity-processbot <> --- Cargo.lock | 1 + .../nomination-pools/benchmarking/src/lib.rs | 4 +- frame/nomination-pools/src/mock.rs | 12 +++++- frame/staking/src/lib.rs | 13 +------ frame/staking/src/pallet/impls.rs | 30 ++++++++++++++- frame/staking/src/tests.rs | 23 +++++++++++ primitives/staking/Cargo.toml | 2 + primitives/staking/src/lib.rs | 38 ++++++++++++++++--- 8 files changed, 99 insertions(+), 24 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8d8d2d59a3c88..c06bf41c24b4d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10862,6 +10862,7 @@ version = "4.0.0-dev" dependencies = [ "parity-scale-codec", "scale-info", + "serde", "sp-core", "sp-runtime", "sp-std", diff --git a/frame/nomination-pools/benchmarking/src/lib.rs b/frame/nomination-pools/benchmarking/src/lib.rs index d58bbaf3d117c..137b9e9af63e3 100644 --- a/frame/nomination-pools/benchmarking/src/lib.rs +++ b/frame/nomination-pools/benchmarking/src/lib.rs @@ -684,12 +684,12 @@ frame_benchmarking::benchmarks! { .collect(); assert_ok!(T::Staking::nominate(&pool_account, validators)); - assert!(T::Staking::nominations(Pools::::create_bonded_account(1)).is_some()); + assert!(T::Staking::nominations(&Pools::::create_bonded_account(1)).is_some()); whitelist_account!(depositor); }:_(RuntimeOrigin::Signed(depositor.clone()), 1) verify { - assert!(T::Staking::nominations(Pools::::create_bonded_account(1)).is_none()); + assert!(T::Staking::nominations(&Pools::::create_bonded_account(1)).is_none()); } set_commission { diff --git a/frame/nomination-pools/src/mock.rs b/frame/nomination-pools/src/mock.rs index 3565ff14e6c82..3ab9be516fdb9 100644 --- a/frame/nomination-pools/src/mock.rs +++ b/frame/nomination-pools/src/mock.rs @@ -67,6 +67,14 @@ impl sp_staking::StakingInterface for StakingMock { BondingDuration::get() } + fn status( + _: &Self::AccountId, + ) -> Result, DispatchError> { + Nominations::get() + .map(|noms| sp_staking::StakerStatus::Nominator(noms)) + .ok_or(DispatchError::Other("NotStash")) + } + fn bond_extra(who: &Self::AccountId, extra: Self::Balance) -> DispatchResult { let mut x = BondedBalanceMap::get(); x.get_mut(who).map(|v| *v += extra); @@ -108,7 +116,7 @@ impl sp_staking::StakingInterface for StakingMock { } #[cfg(feature = "runtime-benchmarks")] - fn nominations(_: Self::AccountId) -> Option> { + fn nominations(_: &Self::AccountId) -> Option> { Nominations::get() } @@ -116,7 +124,7 @@ impl sp_staking::StakingInterface for StakingMock { unimplemented!("method currently not used in testing") } - fn stake(who: &Self::AccountId) -> Result, DispatchError> { + fn stake(who: &Self::AccountId) -> Result, DispatchError> { match ( UnbondingBalanceMap::get().get(who).copied(), BondedBalanceMap::get().get(who).copied(), diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index d6345c2161f73..28d970b9121e7 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -311,6 +311,7 @@ use sp_runtime::{ traits::{AtLeast32BitUnsigned, Convert, Saturating, StaticLookup, Zero}, Perbill, Perquintill, Rounding, RuntimeDebug, }; +pub use sp_staking::StakerStatus; use sp_staking::{ offence::{Offence, OffenceError, ReportOffence}, EraIndex, SessionIndex, @@ -381,18 +382,6 @@ impl Default for EraRewardPoints { } } -/// Indicates the initial status of the staker. -#[derive(RuntimeDebug, TypeInfo)] -#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize, Clone))] -pub enum StakerStatus { - /// Chilling. - Idle, - /// Declared desire in validating or already participating in it. - Validator, - /// Nominating for a group of other stakers. - Nominator(Vec), -} - /// A destination account for payment. #[derive(PartialEq, Eq, Copy, Clone, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub enum RewardDestination { diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 3058d3edc6fd6..984871f7f9813 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -22,6 +22,7 @@ use frame_election_provider_support::{ SortedListProvider, VoteWeight, VoterOf, }; use frame_support::{ + defensive, dispatch::WithPostDispatchInfo, pallet_prelude::*, traits::{ @@ -1608,7 +1609,7 @@ impl StakingInterface for Pallet { Self::current_era().unwrap_or(Zero::zero()) } - fn stake(who: &Self::AccountId) -> Result, DispatchError> { + fn stake(who: &Self::AccountId) -> Result>, DispatchError> { Self::bonded(who) .and_then(|c| Self::ledger(c)) .map(|l| Stake { total: l.total, active: l.active }) @@ -1662,8 +1663,33 @@ impl StakingInterface for Pallet { Self::nominate(RawOrigin::Signed(ctrl).into(), targets) } + fn status( + who: &Self::AccountId, + ) -> Result, DispatchError> { + let is_bonded = Self::bonded(who).is_some(); + if !is_bonded { + return Err(Error::::NotStash.into()) + } + + let is_validator = Validators::::contains_key(&who); + let is_nominator = Nominators::::get(&who); + + use sp_staking::StakerStatus; + match (is_validator, is_nominator.is_some()) { + (false, false) => Ok(StakerStatus::Idle), + (true, false) => Ok(StakerStatus::Validator), + (false, true) => Ok(StakerStatus::Nominator( + is_nominator.expect("is checked above; qed").targets.into_inner(), + )), + (true, true) => { + defensive!("cannot be both validators and nominator"); + Err(Error::::BadState.into()) + }, + } + } + sp_staking::runtime_benchmarks_enabled! { - fn nominations(who: Self::AccountId) -> Option> { + 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 d97eb3ef89cab..affee60026500 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -5824,4 +5824,27 @@ mod staking_interface { )); }); } + + #[test] + fn status() { + ExtBuilder::default().build_and_execute(|| { + // stash of a validator is identified as a validator + assert_eq!(Staking::status(&11).unwrap(), StakerStatus::Validator); + // .. but not the controller. + assert!(Staking::status(&10).is_err()); + + // stash of nominator is identified as a nominator + assert_eq!(Staking::status(&101).unwrap(), StakerStatus::Nominator(vec![11, 21])); + // .. but not the controller. + assert!(Staking::status(&100).is_err()); + + // stash of chilled is identified as a chilled + assert_eq!(Staking::status(&41).unwrap(), StakerStatus::Idle); + // .. but not the controller. + assert!(Staking::status(&40).is_err()); + + // random other account. + assert!(Staking::status(&42).is_err()); + }) + } } diff --git a/primitives/staking/Cargo.toml b/primitives/staking/Cargo.toml index f92bca2788c41..f383a5e88759f 100644 --- a/primitives/staking/Cargo.toml +++ b/primitives/staking/Cargo.toml @@ -13,6 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] +serde = { version = "1.0.136", optional = true } codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } sp-core = { version = "7.0.0", default-features = false, path = "../core" } @@ -22,6 +23,7 @@ sp-std = { version = "5.0.0", default-features = false, path = "../std" } [features] default = ["std"] std = [ + "serde", "codec/std", "scale-info/std", "sp-core/std", diff --git a/primitives/staking/src/lib.rs b/primitives/staking/src/lib.rs index f328696551eed..57128bd327d9e 100644 --- a/primitives/staking/src/lib.rs +++ b/primitives/staking/src/lib.rs @@ -20,6 +20,8 @@ //! 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 scale_info::TypeInfo; +use sp_core::RuntimeDebug; use sp_runtime::{DispatchError, DispatchResult}; use sp_std::{collections::btree_map::BTreeMap, vec::Vec}; @@ -31,6 +33,18 @@ pub type SessionIndex = u32; /// Counter for the number of eras that have passed. pub type EraIndex = u32; +/// Representation of the status of a staker. +#[derive(RuntimeDebug, TypeInfo)] +#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize, PartialEq, Eq, Clone))] +pub enum StakerStatus { + /// Chilling. + Idle, + /// Declaring desire in validate, i.e author blocks. + Validator, + /// Declaring desire to nominate, delegate, or generally approve of the given set of others. + Nominator(Vec), +} + /// Trait describing something that implements a hook for any operations to perform when a staker is /// slashed. pub trait OnStakerSlash { @@ -57,7 +71,7 @@ impl OnStakerSlash for () { /// 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 { +pub struct Stake { /// 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`]. @@ -67,10 +81,10 @@ pub struct Stake { /// 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, + pub total: Balance, /// The total amount of the stash's balance that will be at stake in any forthcoming /// rounds. - pub active: T::Balance, + pub active: Balance, } /// A generic representation of a staking implementation. @@ -109,21 +123,25 @@ pub trait StakingInterface { /// This should be the latest planned era that the staking system knows about. fn current_era() -> EraIndex; - /// Returns the stake of `who`. - fn stake(who: &Self::AccountId) -> Result, DispatchError>; + /// Returns the [`Stake`] of `who`. + fn stake(who: &Self::AccountId) -> Result, DispatchError>; + /// Total stake of a staker, `Err` if not a staker. fn total_stake(who: &Self::AccountId) -> Result { Self::stake(who).map(|s| s.total) } + /// Total active portion of a staker's [`Stake`], `Err` if not a staker. fn active_stake(who: &Self::AccountId) -> Result { Self::stake(who).map(|s| s.active) } + /// Returns whether a staker is unbonding, `Err` if not a staker at all. fn is_unbonding(who: &Self::AccountId) -> Result { Self::stake(who).map(|s| s.active != s.total) } + /// Returns whether a staker is FULLY unbonding, `Err` if not a staker at all. fn fully_unbond(who: &Self::AccountId) -> DispatchResult { Self::unbond(who, Self::stake(who)?.active) } @@ -174,9 +192,17 @@ pub trait StakingInterface { /// Checks whether an account `staker` has been exposed in an era. fn is_exposed_in_era(who: &Self::AccountId, era: &EraIndex) -> bool; + /// Return the status of the given staker, `None` if not staked at all. + fn status(who: &Self::AccountId) -> Result, DispatchError>; + /// 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> { + match Self::status(who) { + Ok(StakerStatus::Nominator(t)) => Some(t), + _ => None, + } + } #[cfg(feature = "runtime-benchmarks")] fn add_era_stakers( From 5d1b74c29b51d5e18e525347c3ee57e86a20140a Mon Sep 17 00:00:00 2001 From: Liam Aharon Date: Fri, 28 Apr 2023 00:03:47 +1000 Subject: [PATCH 708/715] try-runtime-cli: improve ci stability (#14030) * hardcode 1 thread * ci stability * fix comment * improve comment * kick ci * kick ci * update expect message * improve comment * kick ci * kick ci * configure threads with env var * fix threads env var * fix threads env var --- utils/frame/remote-externalities/src/lib.rs | 31 ++++++++++++++++----- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/utils/frame/remote-externalities/src/lib.rs b/utils/frame/remote-externalities/src/lib.rs index ea9b68ce2f6ae..283d2c280b15e 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, StateVersion}; use std::{ - cmp::max, + cmp::{max, min}, fs, num::NonZeroUsize, ops::{Deref, DerefMut}, @@ -157,10 +157,14 @@ impl Transport { } else { uri.clone() }; - let http_client = HttpClientBuilder::default().build(uri).map_err(|e| { - log::error!(target: LOG_TARGET, "error: {:?}", e); - "failed to build http client" - })?; + let http_client = HttpClientBuilder::default() + .max_request_body_size(u32::MAX) + .request_timeout(std::time::Duration::from_secs(60 * 5)) + .build(uri) + .map_err(|e| { + log::error!(target: LOG_TARGET, "error: {:?}", e); + "failed to build http client" + })?; *self = Self::RemoteClient(Arc::new(http_client)) } @@ -323,6 +327,7 @@ where B::Hash: DeserializeOwned, B::Header: DeserializeOwned, { + const DEFAULT_PARALLELISM: usize = 4; const BATCH_SIZE_INCREASE_FACTOR: f32 = 1.10; const BATCH_SIZE_DECREASE_FACTOR: f32 = 0.50; const INITIAL_BATCH_SIZE: usize = 5000; @@ -330,9 +335,21 @@ where const DEFAULT_KEY_DOWNLOAD_PAGE: u32 = 1000; /// Get the number of threads to use. + /// Cap the number of threads. Performance improvement beyond a small number of threads is + /// negligible, and too many threads can create issues with the HttpClient. fn threads() -> NonZeroUsize { - thread::available_parallelism() - .unwrap_or(NonZeroUsize::new(1usize).expect("4 is non-zero; qed")) + let avaliable = thread::available_parallelism() + .unwrap_or(NonZeroUsize::new(1usize).expect("1 is non-zero; qed")) + .get(); + assert!(avaliable > 0, "avaliable parallelism must be greater than 0"); + + let requested: usize = match std::env::var("TRY_RUNTIME_MAX_THREADS") { + Ok(n) => n.parse::().expect("TRY_RUNTIME_MAX_THREADS must be a number"), + Err(_) => Self::DEFAULT_PARALLELISM, + }; + assert!(requested > 0, "TRY_RUNTIME_MAX_THREADS must be greater than 0"); + return NonZeroUsize::new(min(requested, avaliable)) + .expect("requested and avaliable are non-zero; qed") } async fn rpc_get_storage( From f2b668074331d975a9ab06540d01713dc7c67086 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Thu, 27 Apr 2023 16:08:08 +0200 Subject: [PATCH 709/715] FRAME: inherited call weight syntax (#13932) * First approach on pallet::call_weight Signed-off-by: Oliver Tale-Yazdi * Use attr on pallet::call instead Signed-off-by: Oliver Tale-Yazdi * Ui tests Signed-off-by: Oliver Tale-Yazdi * Rename to weight(prefix = ...)) Signed-off-by: Oliver Tale-Yazdi * Simplify to #[pallet::call(weight(T))] Signed-off-by: Oliver Tale-Yazdi * Add stray token error Signed-off-by: Oliver Tale-Yazdi * Cleanup Signed-off-by: Oliver Tale-Yazdi * Migrate remaining pallets Using script from https://github.com/ggwpez/substrate-scripts/blob/e1b5ea5b5b4018867f3e869fce6f448b4ba9d71f/frame-code-migration/src/call_weight.rs Signed-off-by: Oliver Tale-Yazdi * Try to add some docs Signed-off-by: Oliver Tale-Yazdi * Revert "Migrate remaining pallets" Lets do this as a follow-up, I dont want to bloat this small MR. This reverts commit 331d4b42d72de1dacaed714d69166fa1bc9c92dd. Signed-off-by: Oliver Tale-Yazdi * Renames Signed-off-by: Oliver Tale-Yazdi * Review fixes Co-authored-by: Sam Johnson Signed-off-by: Oliver Tale-Yazdi * Test weights Signed-off-by: Oliver Tale-Yazdi * Update UI tests Signed-off-by: Oliver Tale-Yazdi * Update frame/support/procedural/src/pallet/parse/mod.rs Co-authored-by: Muharem Ismailov * Remove old code Signed-off-by: Oliver Tale-Yazdi * Update docs Signed-off-by: Oliver Tale-Yazdi --------- Signed-off-by: Oliver Tale-Yazdi Co-authored-by: parity-processbot <> Co-authored-by: Muharem Ismailov --- frame/alliance/src/lib.rs | 12 +-- frame/alliance/src/tests.rs | 9 ++ frame/assets/src/lib.rs | 25 +----- frame/assets/src/tests.rs | 10 +++ frame/balances/src/lib.rs | 7 +- frame/balances/src/tests/mod.rs | 11 ++- frame/examples/basic/src/lib.rs | 5 +- frame/examples/basic/src/tests.rs | 1 + .../procedural/src/pallet/expand/call.rs | 39 ++++++--- .../procedural/src/pallet/parse/call.rs | 53 ++++++++---- .../procedural/src/pallet/parse/mod.rs | 83 +++++++++++++++++-- .../src/pallet/parse/pallet_struct.rs | 4 +- frame/support/src/lib.rs | 2 +- .../pallet_ui/call_missing_weight.stderr | 6 +- .../call_weight_inherited_invalid.rs | 50 +++++++++++ .../call_weight_inherited_invalid.stderr | 11 +++ .../call_weight_inherited_invalid2.rs | 53 ++++++++++++ .../call_weight_inherited_invalid2.stderr | 11 +++ .../call_weight_inherited_invalid3.rs | 53 ++++++++++++ .../call_weight_inherited_invalid3.stderr | 19 +++++ .../call_weight_inherited_invalid4.rs | 52 ++++++++++++ .../call_weight_inherited_invalid4.stderr | 11 +++ .../call_weight_inherited_invalid5.rs | 44 ++++++++++ .../call_weight_inherited_invalid5.stderr | 11 +++ .../tests/pallet_ui/dev_mode_without_arg.rs | 2 - .../pallet_ui/dev_mode_without_arg.stderr | 14 ++-- .../pallet_ui/pass/inherited_call_weight.rs | 51 ++++++++++++ .../pallet_ui/pass/inherited_call_weight2.rs | 57 +++++++++++++ .../pallet_ui/pass/inherited_call_weight3.rs | 54 ++++++++++++ .../pass/inherited_call_weight_dev_mode.rs | 30 +++++++ 30 files changed, 698 insertions(+), 92 deletions(-) create mode 100644 frame/support/test/tests/pallet_ui/call_weight_inherited_invalid.rs create mode 100644 frame/support/test/tests/pallet_ui/call_weight_inherited_invalid.stderr create mode 100644 frame/support/test/tests/pallet_ui/call_weight_inherited_invalid2.rs create mode 100644 frame/support/test/tests/pallet_ui/call_weight_inherited_invalid2.stderr create mode 100644 frame/support/test/tests/pallet_ui/call_weight_inherited_invalid3.rs create mode 100644 frame/support/test/tests/pallet_ui/call_weight_inherited_invalid3.stderr create mode 100644 frame/support/test/tests/pallet_ui/call_weight_inherited_invalid4.rs create mode 100644 frame/support/test/tests/pallet_ui/call_weight_inherited_invalid4.stderr create mode 100644 frame/support/test/tests/pallet_ui/call_weight_inherited_invalid5.rs create mode 100644 frame/support/test/tests/pallet_ui/call_weight_inherited_invalid5.stderr create mode 100644 frame/support/test/tests/pallet_ui/pass/inherited_call_weight.rs create mode 100644 frame/support/test/tests/pallet_ui/pass/inherited_call_weight2.rs create mode 100644 frame/support/test/tests/pallet_ui/pass/inherited_call_weight3.rs create mode 100644 frame/support/test/tests/pallet_ui/pass/inherited_call_weight_dev_mode.rs diff --git a/frame/alliance/src/lib.rs b/frame/alliance/src/lib.rs index d50e20ba00c07..86a64caaf8e75 100644 --- a/frame/alliance/src/lib.rs +++ b/frame/alliance/src/lib.rs @@ -497,7 +497,7 @@ pub mod pallet { pub type UnscrupulousWebsites, I: 'static = ()> = StorageValue<_, BoundedVec, T::MaxUnscrupulousItems>, ValueQuery>; - #[pallet::call] + #[pallet::call(weight(>::WeightInfo))] impl, I: 'static> Pallet { /// Add a new proposal to be voted on. /// @@ -649,7 +649,6 @@ 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)?; @@ -661,7 +660,6 @@ 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)?; @@ -677,7 +675,6 @@ 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)?; @@ -695,7 +692,6 @@ 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)?; @@ -732,7 +728,6 @@ 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)?; ensure!(Self::has_voting_rights(&nominator), Error::::NoVotingRights); @@ -757,7 +752,6 @@ 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)?; let ally = T::Lookup::lookup(ally)?; @@ -774,7 +768,6 @@ 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)?; let role = Self::member_role_of(&who).ok_or(Error::::NotMember)?; @@ -797,7 +790,6 @@ 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)?; let retirement_period_end = RetiringMembers::::get(&who) @@ -820,7 +812,6 @@ 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)?; let member = T::Lookup::lookup(who)?; @@ -922,7 +913,6 @@ pub mod pallet { /// 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)?; let role = Self::member_role_of(&who).ok_or(Error::::NotMember)?; diff --git a/frame/alliance/src/tests.rs b/frame/alliance/src/tests.rs index 5942595469d5f..de7cda4710fc7 100644 --- a/frame/alliance/src/tests.rs +++ b/frame/alliance/src/tests.rs @@ -629,3 +629,12 @@ fn remove_unscrupulous_items_works() { assert_eq!(Alliance::unscrupulous_accounts(), Vec::::new()); }); } + +#[test] +fn weights_sane() { + let info = crate::Call::::join_alliance {}.get_dispatch_info(); + assert_eq!(<() as crate::WeightInfo>::join_alliance(), info.weight); + + let info = crate::Call::::nominate_ally { who: 10 }.get_dispatch_info(); + assert_eq!(<() as crate::WeightInfo>::nominate_ally(), info.weight); +} diff --git a/frame/assets/src/lib.rs b/frame/assets/src/lib.rs index 859a13243d509..d32b407e67f6e 100644 --- a/frame/assets/src/lib.rs +++ b/frame/assets/src/lib.rs @@ -568,7 +568,7 @@ pub mod pallet { CallbackFailed, } - #[pallet::call] + #[pallet::call(weight(>::WeightInfo))] impl, I: 'static> Pallet { /// Issue a new class of fungible assets from a public origin. /// @@ -590,7 +590,6 @@ pub mod pallet { /// /// Weight: `O(1)` #[pallet::call_index(0)] - #[pallet::weight(T::WeightInfo::create())] pub fn create( origin: OriginFor, id: T::AssetIdParameter, @@ -654,7 +653,6 @@ pub mod pallet { /// /// Weight: `O(1)` #[pallet::call_index(1)] - #[pallet::weight(T::WeightInfo::force_create())] pub fn force_create( origin: OriginFor, id: T::AssetIdParameter, @@ -680,7 +678,6 @@ pub mod pallet { /// /// 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) { Ok(_) => None, @@ -749,7 +746,6 @@ pub mod pallet { /// /// 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)?; let id: T::AssetId = id.into(); @@ -769,7 +765,6 @@ 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, id: T::AssetIdParameter, @@ -799,7 +794,6 @@ 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, id: T::AssetIdParameter, @@ -834,7 +828,6 @@ pub mod pallet { /// 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, id: T::AssetIdParameter, @@ -868,7 +861,6 @@ pub mod pallet { /// 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, id: T::AssetIdParameter, @@ -903,7 +895,6 @@ pub mod pallet { /// 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, id: T::AssetIdParameter, @@ -931,7 +922,6 @@ pub mod pallet { /// /// Weight: `O(1)` #[pallet::call_index(11)] - #[pallet::weight(T::WeightInfo::freeze())] pub fn freeze( origin: OriginFor, id: T::AssetIdParameter, @@ -968,7 +958,6 @@ pub mod pallet { /// /// Weight: `O(1)` #[pallet::call_index(12)] - #[pallet::weight(T::WeightInfo::thaw())] pub fn thaw( origin: OriginFor, id: T::AssetIdParameter, @@ -1004,7 +993,6 @@ pub mod pallet { /// /// 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)?; let id: T::AssetId = id.into(); @@ -1031,7 +1019,6 @@ pub mod pallet { /// /// 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)?; let id: T::AssetId = id.into(); @@ -1059,7 +1046,6 @@ pub mod pallet { /// /// Weight: `O(1)` #[pallet::call_index(15)] - #[pallet::weight(T::WeightInfo::transfer_ownership())] pub fn transfer_ownership( origin: OriginFor, id: T::AssetIdParameter, @@ -1103,7 +1089,6 @@ pub mod pallet { /// /// Weight: `O(1)` #[pallet::call_index(16)] - #[pallet::weight(T::WeightInfo::set_team())] pub fn set_team( origin: OriginFor, id: T::AssetIdParameter, @@ -1173,7 +1158,6 @@ pub mod pallet { /// /// 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)?; let id: T::AssetId = id.into(); @@ -1257,7 +1241,6 @@ pub mod pallet { /// /// Weight: `O(1)` #[pallet::call_index(20)] - #[pallet::weight(T::WeightInfo::force_clear_metadata())] pub fn force_clear_metadata( origin: OriginFor, id: T::AssetIdParameter, @@ -1297,7 +1280,6 @@ pub mod pallet { /// /// Weight: `O(1)` #[pallet::call_index(21)] - #[pallet::weight(T::WeightInfo::force_asset_status())] pub fn force_asset_status( origin: OriginFor, id: T::AssetIdParameter, @@ -1354,7 +1336,6 @@ pub mod pallet { /// /// Weight: `O(1)` #[pallet::call_index(22)] - #[pallet::weight(T::WeightInfo::approve_transfer())] pub fn approve_transfer( origin: OriginFor, id: T::AssetIdParameter, @@ -1381,7 +1362,6 @@ pub mod pallet { /// /// Weight: `O(1)` #[pallet::call_index(23)] - #[pallet::weight(T::WeightInfo::cancel_approval())] pub fn cancel_approval( origin: OriginFor, id: T::AssetIdParameter, @@ -1418,7 +1398,6 @@ pub mod pallet { /// /// Weight: `O(1)` #[pallet::call_index(24)] - #[pallet::weight(T::WeightInfo::force_cancel_approval())] pub fn force_cancel_approval( origin: OriginFor, id: T::AssetIdParameter, @@ -1468,7 +1447,6 @@ pub mod pallet { /// /// Weight: `O(1)` #[pallet::call_index(25)] - #[pallet::weight(T::WeightInfo::transfer_approved())] pub fn transfer_approved( origin: OriginFor, id: T::AssetIdParameter, @@ -1531,7 +1509,6 @@ pub mod pallet { /// /// Emits `AssetMinBalanceChanged` event when successful. #[pallet::call_index(28)] - #[pallet::weight(T::WeightInfo::set_min_balance())] pub fn set_min_balance( origin: OriginFor, id: T::AssetIdParameter, diff --git a/frame/assets/src/tests.rs b/frame/assets/src/tests.rs index b47fb6486cb27..88ba92d0685a9 100644 --- a/frame/assets/src/tests.rs +++ b/frame/assets/src/tests.rs @@ -21,6 +21,7 @@ use super::*; use crate::{mock::*, Error}; use frame_support::{ assert_noop, assert_ok, + dispatch::GetDispatchInfo, traits::{fungibles::InspectEnumerable, tokens::Preservation::Protect, Currency}, }; use pallet_balances::Error as BalancesError; @@ -1355,3 +1356,12 @@ fn multiple_transfer_alls_work_ok() { assert_eq!(Balances::free_balance(&1337), 100); }); } + +#[test] +fn weights_sane() { + let info = crate::Call::::create { id: 10, admin: 4, min_balance: 3 }.get_dispatch_info(); + assert_eq!(<() as crate::WeightInfo>::create(), info.weight); + + let info = crate::Call::::finish_destroy { id: 10 }.get_dispatch_info(); + assert_eq!(<() as crate::WeightInfo>::finish_destroy(), info.weight); +} diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index c87b01d77bae5..b3dc77a9b879d 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -526,7 +526,7 @@ pub mod pallet { } } - #[pallet::call] + #[pallet::call(weight(>::WeightInfo))] impl, I: 'static> Pallet { /// Transfer some liquid free balance to another account. /// @@ -536,7 +536,6 @@ pub mod pallet { /// /// The dispatch origin for this call must be `Signed` by the transactor. #[pallet::call_index(0)] - #[pallet::weight(T::WeightInfo::transfer_allow_death())] pub fn transfer_allow_death( origin: OriginFor, dest: AccountIdLookupOf, @@ -598,7 +597,6 @@ pub mod pallet { /// Exactly as `transfer_allow_death`, except the origin must be root and the source account /// may be specified. #[pallet::call_index(2)] - #[pallet::weight(T::WeightInfo::force_transfer())] pub fn force_transfer( origin: OriginFor, source: AccountIdLookupOf, @@ -619,7 +617,6 @@ pub mod pallet { /// /// [`transfer_allow_death`]: struct.Pallet.html#method.transfer #[pallet::call_index(3)] - #[pallet::weight(T::WeightInfo::transfer_keep_alive())] pub fn transfer_keep_alive( origin: OriginFor, dest: AccountIdLookupOf, @@ -647,7 +644,6 @@ pub mod pallet { /// transfer everything except at least the existential deposit, which will guarantee to /// keep the sender account alive (true). #[pallet::call_index(4)] - #[pallet::weight(T::WeightInfo::transfer_all())] pub fn transfer_all( origin: OriginFor, dest: AccountIdLookupOf, @@ -674,7 +670,6 @@ pub mod pallet { /// /// Can only be called by ROOT. #[pallet::call_index(5)] - #[pallet::weight(T::WeightInfo::force_unreserve())] pub fn force_unreserve( origin: OriginFor, who: AccountIdLookupOf, diff --git a/frame/balances/src/tests/mod.rs b/frame/balances/src/tests/mod.rs index 68e7e82035b0e..9b451f36d1d94 100644 --- a/frame/balances/src/tests/mod.rs +++ b/frame/balances/src/tests/mod.rs @@ -23,7 +23,7 @@ use crate::{self as pallet_balances, AccountData, Config, CreditOf, Error, Palle use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ assert_err, assert_noop, assert_ok, assert_storage_noop, - dispatch::DispatchInfo, + dispatch::{DispatchInfo, GetDispatchInfo}, parameter_types, traits::{ tokens::fungible, ConstU32, ConstU64, ConstU8, Imbalance as ImbalanceT, OnUnbalanced, @@ -294,3 +294,12 @@ pub fn events() -> Vec { pub fn info_from_weight(w: Weight) -> DispatchInfo { DispatchInfo { weight: w, ..Default::default() } } + +#[test] +fn weights_sane() { + let info = crate::Call::::transfer_allow_death { dest: 10, value: 4 }.get_dispatch_info(); + assert_eq!(<() as crate::WeightInfo>::transfer_allow_death(), info.weight); + + let info = crate::Call::::force_unreserve { who: 10, amount: 4 }.get_dispatch_info(); + assert_eq!(<() as crate::WeightInfo>::force_unreserve(), info.weight); +} diff --git a/frame/examples/basic/src/lib.rs b/frame/examples/basic/src/lib.rs index 6665c3b78b024..bbeaac19f809c 100644 --- a/frame/examples/basic/src/lib.rs +++ b/frame/examples/basic/src/lib.rs @@ -441,7 +441,7 @@ pub mod pallet { // against them as the first thing you do in your function. There are three convenience calls // in system that do the matching for you and return a convenient result: `ensure_signed`, // `ensure_root` and `ensure_none`. - #[pallet::call] + #[pallet::call(weight(::WeightInfo))] impl Pallet { /// This is your public interface. Be extremely careful. /// This is just a simple example of how to interact with the pallet from the external @@ -497,9 +497,6 @@ 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() - )] 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. let _sender = ensure_signed(origin)?; diff --git a/frame/examples/basic/src/tests.rs b/frame/examples/basic/src/tests.rs index d9a8a4e8e1cdc..1d9cf81a5074c 100644 --- a/frame/examples/basic/src/tests.rs +++ b/frame/examples/basic/src/tests.rs @@ -192,6 +192,7 @@ fn weights_work() { // aka. `let info = as GetDispatchInfo>::get_dispatch_info(&default_call);` // TODO: account for proof size weight assert!(info1.weight.ref_time() > 0); + assert_eq!(info1.weight, ::WeightInfo::accumulate_dummy()); // `set_dummy` is simpler than `accumulate_dummy`, and the weight // should be less. diff --git a/frame/support/procedural/src/pallet/expand/call.rs b/frame/support/procedural/src/pallet/expand/call.rs index aa5af9d54882f..f17fdc81a647c 100644 --- a/frame/support/procedural/src/pallet/expand/call.rs +++ b/frame/support/procedural/src/pallet/expand/call.rs @@ -15,8 +15,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::{pallet::Def, COUNTER}; -use quote::ToTokens; +use crate::{ + pallet::{parse::call::CallWeightDef, Def}, + COUNTER, +}; +use proc_macro2::TokenStream as TokenStream2; +use quote::{quote, ToTokens}; use syn::spanned::Spanned; /// @@ -74,15 +78,12 @@ pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream { call_index_warnings.push(warning); } - let fn_weight = methods.iter().map(|method| &method.weight); + let mut fn_weight = Vec::::new(); let mut weight_warnings = Vec::new(); - for weight in fn_weight.clone() { - if def.dev_mode { - continue - } - - match weight { - syn::Expr::Lit(lit) => { + for method in &methods { + match &method.weight { + CallWeightDef::DevModeDefault => fn_weight.push(syn::parse_quote!(0)), + CallWeightDef::Immediate(e @ syn::Expr::Lit(lit)) if !def.dev_mode => { let warning = proc_macro_warning::Warning::new_deprecated("ConstantWeight") .index(weight_warnings.len()) .old("use hard-coded constant as call weight") @@ -91,10 +92,26 @@ pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream { .span(lit.span()) .build(); weight_warnings.push(warning); + fn_weight.push(e.into_token_stream()); + }, + CallWeightDef::Immediate(e) => fn_weight.push(e.into_token_stream()), + CallWeightDef::Inherited => { + let pallet_weight = def + .call + .as_ref() + .expect("we have methods; we have calls; qed") + .inherited_call_weight + .as_ref() + .expect("the parser prevents this"); + + // Expand `<::WeightInfo>::call_name()`. + let t = &pallet_weight.typename; + let n = &method.name; + fn_weight.push(quote!({ < #t > :: #n () })); }, - _ => {}, } } + debug_assert_eq!(fn_weight.len(), methods.len()); let fn_doc = methods.iter().map(|method| &method.docs).collect::>(); diff --git a/frame/support/procedural/src/pallet/parse/call.rs b/frame/support/procedural/src/pallet/parse/call.rs index ae1c039c9ddde..90631f264b92a 100644 --- a/frame/support/procedural/src/pallet/parse/call.rs +++ b/frame/support/procedural/src/pallet/parse/call.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use super::helper; +use super::{helper, InheritedCallWeightAttr}; use frame_support_procedural_tools::get_doc_literals; use quote::ToTokens; use std::collections::HashMap; @@ -46,6 +46,23 @@ pub struct CallDef { pub attr_span: proc_macro2::Span, /// Docs, specified on the impl Block. pub docs: Vec, + /// The optional `weight` attribute on the `pallet::call`. + pub inherited_call_weight: Option, +} + +/// The weight of a call. +#[derive(Clone)] +pub enum CallWeightDef { + /// Explicitly set on the call itself with `#[pallet::weight(…)]`. This value is used. + Immediate(syn::Expr), + + /// The default value that should be set for dev-mode pallets. Usually zero. + DevModeDefault, + + /// Inherits whatever value is configured on the pallet level. + /// + /// The concrete value is not known at this point. + Inherited, } /// Definition of dispatchable typically: `#[weight...] fn foo(origin .., param1: ...) -> ..` @@ -55,8 +72,8 @@ pub struct CallVariantDef { pub name: syn::Ident, /// Information on args: `(is_compact, name, type)` pub args: Vec<(bool, syn::Ident, Box)>, - /// Weight formula. - pub weight: syn::Expr, + /// Weight for the call. + pub weight: CallWeightDef, /// Call index of the dispatchable. pub call_index: u8, /// Whether an explicit call index was specified. @@ -151,6 +168,7 @@ impl CallDef { index: usize, item: &mut syn::Item, dev_mode: bool, + inherited_call_weight: Option, ) -> syn::Result { let item_impl = if let syn::Item::Impl(item) = item { item @@ -228,17 +246,23 @@ impl CallDef { 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)]`" - } else { - "Invalid pallet::call, too many weight attributes given" - }; - return Err(syn::Error::new(method.sig.span(), msg)) - } - let weight = match weight_attrs.pop().unwrap() { - FunctionAttr::Weight(w) => w, - _ => unreachable!("checked during creation of the let binding"), + let weight = match weight_attrs.len() { + 0 if inherited_call_weight.is_some() => CallWeightDef::Inherited, + 0 if dev_mode => CallWeightDef::DevModeDefault, + 0 => return Err(syn::Error::new( + method.sig.span(), + "A pallet::call requires either a concrete `#[pallet::weight($expr)]` or an + inherited weight from the `#[pallet:call(weight($type))]` attribute, but + none were given.", + )), + 1 => match weight_attrs.pop().unwrap() { + FunctionAttr::Weight(w) => CallWeightDef::Immediate(w), + _ => unreachable!("checked during creation of the let binding"), + }, + _ => { + let msg = "Invalid pallet::call, too many weight attributes given"; + return Err(syn::Error::new(method.sig.span(), msg)) + }, }; if call_idx_attrs.len() > 1 { @@ -321,6 +345,7 @@ impl CallDef { methods, where_clause: item_impl.generics.where_clause.clone(), docs: get_doc_literals(&item_impl.attrs), + inherited_call_weight, }) } } diff --git a/frame/support/procedural/src/pallet/parse/mod.rs b/frame/support/procedural/src/pallet/parse/mod.rs index 06b9899d03b97..770cba68c1aad 100644 --- a/frame/support/procedural/src/pallet/parse/mod.rs +++ b/frame/support/procedural/src/pallet/parse/mod.rs @@ -110,8 +110,8 @@ impl Def { let m = hooks::HooksDef::try_from(span, index, item)?; hooks = Some(m); }, - Some(PalletAttr::RuntimeCall(span)) if call.is_none() => - call = Some(call::CallDef::try_from(span, index, item, dev_mode)?), + Some(PalletAttr::RuntimeCall(cw, span)) if call.is_none() => + call = Some(call::CallDef::try_from(span, index, item, dev_mode, cw)?), 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() => @@ -402,6 +402,7 @@ impl GenericKind { mod keyword { syn::custom_keyword!(origin); syn::custom_keyword!(call); + syn::custom_keyword!(weight); syn::custom_keyword!(event); syn::custom_keyword!(config); syn::custom_keyword!(hooks); @@ -425,7 +426,44 @@ enum PalletAttr { Config(proc_macro2::Span), Pallet(proc_macro2::Span), Hooks(proc_macro2::Span), - RuntimeCall(proc_macro2::Span), + /// A `#[pallet::call]` with optional attributes to specialize the behaviour. + /// + /// # Attributes + /// + /// Each attribute `attr` can take the form of `#[pallet::call(attr = …)]` or + /// `#[pallet::call(attr(…))]`. The possible attributes are: + /// + /// ## `weight` + /// + /// Can be used to reduce the repetitive weight annotation in the trivial case. It accepts one + /// argument that is expected to be an implementation of the `WeightInfo` or something that + /// behaves syntactically equivalent. This allows to annotate a `WeightInfo` for all the calls. + /// Now each call does not need to specify its own `#[pallet::weight]` but can instead use the + /// one from the `#[pallet::call]` definition. So instead of having to write it on each call: + /// + /// ```ignore + /// #[pallet::call] + /// impl Pallet { + /// #[pallet::weight(T::WeightInfo::create())] + /// pub fn create( + /// ``` + /// you can now omit it on the call itself, if the name of the weigh function matches the call: + /// + /// ```ignore + /// #[pallet::call(weight = ::WeightInfo)] + /// impl Pallet { + /// pub fn create( + /// ``` + /// + /// It is possible to use this syntax together with instantiated pallets by using `Config` + /// instead. + /// + /// ### Dev Mode + /// + /// Normally the `dev_mode` sets all weights of calls without a `#[pallet::weight]` annotation + /// to zero. Now when there is a `weight` attribute on the `#[pallet::call]`, then that is used + /// instead of the zero weight. So to say: it works together with `dev_mode`. + RuntimeCall(Option, proc_macro2::Span), Error(proc_macro2::Span), RuntimeEvent(proc_macro2::Span), RuntimeOrigin(proc_macro2::Span), @@ -445,7 +483,7 @@ impl PalletAttr { Self::Config(span) => *span, Self::Pallet(span) => *span, Self::Hooks(span) => *span, - Self::RuntimeCall(span) => *span, + Self::RuntimeCall(_, span) => *span, Self::Error(span) => *span, Self::RuntimeEvent(span) => *span, Self::RuntimeOrigin(span) => *span, @@ -477,7 +515,12 @@ 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::RuntimeCall(content.parse::()?.span())) + let span = content.parse::().expect("peeked").span(); + let attr = match content.is_empty() { + true => None, + false => Some(InheritedCallWeightAttr::parse(&content)?), + }; + Ok(PalletAttr::RuntimeCall(attr, span)) } else if lookahead.peek(keyword::error) { Ok(PalletAttr::Error(content.parse::()?.span())) } else if lookahead.peek(keyword::event) { @@ -505,3 +548,33 @@ impl syn::parse::Parse for PalletAttr { } } } + +/// The optional weight annotation on a `#[pallet::call]` like `#[pallet::call(weight($type))]`. +#[derive(Clone)] +pub struct InheritedCallWeightAttr { + pub typename: syn::Type, + pub span: proc_macro2::Span, +} + +impl syn::parse::Parse for InheritedCallWeightAttr { + // Parses `(weight($type))` or `(weight = $type)`. + fn parse(input: syn::parse::ParseStream) -> syn::Result { + let content; + syn::parenthesized!(content in input); + content.parse::()?; + let lookahead = content.lookahead1(); + + let buffer = if lookahead.peek(syn::token::Paren) { + let inner; + syn::parenthesized!(inner in content); + inner + } else if lookahead.peek(syn::Token![=]) { + content.parse::().expect("peeked"); + content + } else { + return Err(lookahead.error()) + }; + + Ok(Self { typename: buffer.parse()?, span: input.span() }) + } +} diff --git a/frame/support/procedural/src/pallet/parse/pallet_struct.rs b/frame/support/procedural/src/pallet/parse/pallet_struct.rs index 98312d0652d8e..f4af86aa3e993 100644 --- a/frame/support/procedural/src/pallet/parse/pallet_struct.rs +++ b/frame/support/procedural/src/pallet/parse/pallet_struct.rs @@ -61,8 +61,8 @@ pub enum PalletStructAttr { impl PalletStructAttr { fn span(&self) -> proc_macro2::Span { match self { - Self::GenerateStore { span, .. } => *span, - Self::WithoutStorageInfoTrait(span) => *span, + Self::GenerateStore { span, .. } | + Self::WithoutStorageInfoTrait(span) | Self::StorageVersion { span, .. } => *span, } } diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 0ee82b9f16a8f..138b7b55bf0eb 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -2600,7 +2600,7 @@ pub mod pallet_prelude { /// #[pallet::extra_constants] /// impl, I: 'static> Pallet { /// /// Some description -/// fn exra_constant_name() -> u128 { 4u128 } +/// fn extra_constant_name() -> u128 { 4u128 } /// } /// /// #[pallet::pallet] diff --git a/frame/support/test/tests/pallet_ui/call_missing_weight.stderr b/frame/support/test/tests/pallet_ui/call_missing_weight.stderr index ec45d478870c1..0a6cf16571f95 100644 --- a/frame/support/test/tests/pallet_ui/call_missing_weight.stderr +++ b/frame/support/test/tests/pallet_ui/call_missing_weight.stderr @@ -1,5 +1,7 @@ -error: Invalid pallet::call, requires weight attribute i.e. `#[pallet::weight($expr)]` - --> $DIR/call_missing_weight.rs:17:7 +error: A pallet::call requires either a concrete `#[pallet::weight($expr)]` or an + inherited weight from the `#[pallet:call(weight($type))]` attribute, but + none were given. + --> tests/pallet_ui/call_missing_weight.rs:17:7 | 17 | pub fn foo(origin: OriginFor) -> DispatchResultWithPostInfo {} | ^^ diff --git a/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid.rs b/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid.rs new file mode 100644 index 0000000000000..ff235e986099f --- /dev/null +++ b/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid.rs @@ -0,0 +1,50 @@ +use frame_support::pallet_prelude::*; + +pub trait WeightInfo { + fn foo() -> Weight; +} + +#[frame_support::pallet] +mod pallet { + use super::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + type WeightInfo: crate::WeightInfo; + } + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::call(invalid)] + impl Pallet { + #[pallet::call_index(0)] + pub fn foo(_: OriginFor) -> DispatchResult { + Ok(()) + } + } +} + +#[frame_support::pallet] +mod assign { + use super::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + type WeightInfo: crate::WeightInfo; + } + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::call = invalid] + impl Pallet { + #[pallet::call_index(0)] + pub fn foo(_: OriginFor) -> DispatchResult { + Ok(()) + } + } +} + +fn main() { +} diff --git a/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid.stderr b/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid.stderr new file mode 100644 index 0000000000000..7eed646e7b190 --- /dev/null +++ b/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid.stderr @@ -0,0 +1,11 @@ +error: expected `weight` + --> tests/pallet_ui/call_weight_inherited_invalid.rs:19:17 + | +19 | #[pallet::call(invalid)] + | ^^^^^^^ + +error: expected parentheses + --> tests/pallet_ui/call_weight_inherited_invalid.rs:40:17 + | +40 | #[pallet::call = invalid] + | ^ diff --git a/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid2.rs b/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid2.rs new file mode 100644 index 0000000000000..76ccf5db22019 --- /dev/null +++ b/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid2.rs @@ -0,0 +1,53 @@ +// Weight is an ident instead of a type. + +use frame_support::pallet_prelude::*; +use frame_system::pallet_prelude::*; + +pub trait WeightInfo { + fn foo() -> Weight; +} + +#[frame_support::pallet] +mod parentheses { + use super::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + type WeightInfo: crate::WeightInfo; + } + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::call(weight(prefix))] + impl Pallet { + #[pallet::call_index(0)] + pub fn foo(_: OriginFor) -> DispatchResult { + Ok(()) + } + } +} + +#[frame_support::pallet] +mod assign { + use super::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + type WeightInfo: crate::WeightInfo; + } + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::call(weight = prefix)] + impl Pallet { + #[pallet::call_index(0)] + pub fn foo(_: OriginFor) -> DispatchResult { + Ok(()) + } + } +} + +fn main() { +} diff --git a/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid2.stderr b/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid2.stderr new file mode 100644 index 0000000000000..29f3b6bfd2b0d --- /dev/null +++ b/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid2.stderr @@ -0,0 +1,11 @@ +error[E0412]: cannot find type `prefix` in this scope + --> tests/pallet_ui/call_weight_inherited_invalid2.rs:22:24 + | +22 | #[pallet::call(weight(prefix))] + | ^^^^^^ not found in this scope + +error[E0412]: cannot find type `prefix` in this scope + --> tests/pallet_ui/call_weight_inherited_invalid2.rs:43:26 + | +43 | #[pallet::call(weight = prefix)] + | ^^^^^^ not found in this scope diff --git a/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid3.rs b/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid3.rs new file mode 100644 index 0000000000000..b31bc0ae234b2 --- /dev/null +++ b/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid3.rs @@ -0,0 +1,53 @@ +// Call weight is an LitInt instead of a type. + +use frame_support::pallet_prelude::*; +use frame_system::pallet_prelude::*; + +pub trait WeightInfo { + fn foo() -> Weight; +} + +#[frame_support::pallet] +mod parentheses { + use super::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + type WeightInfo: crate::WeightInfo; + } + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::call(weight(123))] + impl Pallet { + #[pallet::call_index(0)] + pub fn foo(_: OriginFor) -> DispatchResult { + Ok(()) + } + } +} + +#[frame_support::pallet] +mod assign { + use super::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + type WeightInfo: crate::WeightInfo; + } + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::call(weight = 123)] + impl Pallet { + #[pallet::call_index(0)] + pub fn foo(_: OriginFor) -> DispatchResult { + Ok(()) + } + } +} + +fn main() { +} diff --git a/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid3.stderr b/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid3.stderr new file mode 100644 index 0000000000000..fab7acb90deaf --- /dev/null +++ b/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid3.stderr @@ -0,0 +1,19 @@ +error: expected one of: `for`, parentheses, `fn`, `unsafe`, `extern`, identifier, `::`, `<`, `dyn`, square brackets, `*`, `&`, `!`, `impl`, `_`, lifetime + --> tests/pallet_ui/call_weight_inherited_invalid3.rs:22:24 + | +22 | #[pallet::call(weight(123))] + | ^^^ + +error: expected one of: `for`, parentheses, `fn`, `unsafe`, `extern`, identifier, `::`, `<`, `dyn`, square brackets, `*`, `&`, `!`, `impl`, `_`, lifetime + --> tests/pallet_ui/call_weight_inherited_invalid3.rs:43:26 + | +43 | #[pallet::call(weight = 123)] + | ^^^ + +error: unused import: `frame_system::pallet_prelude::*` + --> tests/pallet_ui/call_weight_inherited_invalid3.rs:4:5 + | +4 | use frame_system::pallet_prelude::*; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D unused-imports` implied by `-D warnings` diff --git a/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid4.rs b/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid4.rs new file mode 100644 index 0000000000000..39c0929d603ad --- /dev/null +++ b/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid4.rs @@ -0,0 +1,52 @@ +// Function does not exist in the trait. + +use frame_support::pallet_prelude::*; +use frame_system::pallet_prelude::*; + +pub trait WeightInfo { +} + +#[frame_support::pallet] +mod parentheses { + use super::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + type WeightInfo: crate::WeightInfo; + } + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::call(weight(::WeightInfo))] + impl Pallet { + #[pallet::call_index(0)] + pub fn foo(_: OriginFor) -> DispatchResult { + Ok(()) + } + } +} + +#[frame_support::pallet] +mod assign { + use super::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + type WeightInfo: crate::WeightInfo; + } + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::call(weight = ::WeightInfo)] + impl Pallet { + #[pallet::call_index(0)] + pub fn foo(_: OriginFor) -> DispatchResult { + Ok(()) + } + } +} + +fn main() { +} diff --git a/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid4.stderr b/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid4.stderr new file mode 100644 index 0000000000000..46872fc7c3691 --- /dev/null +++ b/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid4.stderr @@ -0,0 +1,11 @@ +error[E0599]: no function or associated item named `foo` found for associated type `::WeightInfo` in the current scope + --> tests/pallet_ui/call_weight_inherited_invalid4.rs:24:10 + | +24 | pub fn foo(_: OriginFor) -> DispatchResult { + | ^^^ function or associated item not found in `::WeightInfo` + +error[E0599]: no function or associated item named `foo` found for associated type `::WeightInfo` in the current scope + --> tests/pallet_ui/call_weight_inherited_invalid4.rs:45:10 + | +45 | pub fn foo(_: OriginFor) -> DispatchResult { + | ^^^ function or associated item not found in `::WeightInfo` diff --git a/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid5.rs b/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid5.rs new file mode 100644 index 0000000000000..a5b2f5c7f6aa6 --- /dev/null +++ b/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid5.rs @@ -0,0 +1,44 @@ +// Stray tokens after good input. + +#[frame_support::pallet] +mod parentheses { + use super::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + } + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::call(weight(::WeightInfo straycat))] + impl Pallet { + #[pallet::call_index(0)] + pub fn foo(_: OriginFor) -> DispatchResult { + Ok(()) + } + } +} + +#[frame_support::pallet] +mod assign { + use super::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + } + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::call(weight = ::WeightInfo straycat)] + impl Pallet { + #[pallet::call_index(0)] + pub fn foo(_: OriginFor) -> DispatchResult { + Ok(()) + } + } +} + +fn main() { +} diff --git a/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid5.stderr b/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid5.stderr new file mode 100644 index 0000000000000..c0e9ef2d9e9d8 --- /dev/null +++ b/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid5.stderr @@ -0,0 +1,11 @@ +error: unexpected token + --> tests/pallet_ui/call_weight_inherited_invalid5.rs:14:50 + | +14 | #[pallet::call(weight(::WeightInfo straycat))] + | ^^^^^^^^ + +error: unexpected token + --> tests/pallet_ui/call_weight_inherited_invalid5.rs:34:52 + | +34 | #[pallet::call(weight = ::WeightInfo straycat)] + | ^^^^^^^^ 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 index f044ae6d7878f..2a413eea9b4aa 100644 --- a/frame/support/test/tests/pallet_ui/dev_mode_without_arg.rs +++ b/frame/support/test/tests/pallet_ui/dev_mode_without_arg.rs @@ -1,7 +1,5 @@ #![cfg_attr(not(feature = "std"), no_std)] -pub use pallet::*; - #[frame_support::pallet] pub mod pallet { use frame_support::pallet_prelude::*; 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 index fac7fd77df9ae..1e2011b2a30cf 100644 --- a/frame/support/test/tests/pallet_ui/dev_mode_without_arg.stderr +++ b/frame/support/test/tests/pallet_ui/dev_mode_without_arg.stderr @@ -1,11 +1,7 @@ -error: Invalid pallet::call, requires weight attribute i.e. `#[pallet::weight($expr)]` - --> tests/pallet_ui/dev_mode_without_arg.rs:24:7 +error: A pallet::call requires either a concrete `#[pallet::weight($expr)]` or an + inherited weight from the `#[pallet:call(weight($type))]` attribute, but + none were given. + --> tests/pallet_ui/dev_mode_without_arg.rs:22:7 | -24 | pub fn my_call(_origin: OriginFor) -> DispatchResult { +22 | 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/pass/inherited_call_weight.rs b/frame/support/test/tests/pallet_ui/pass/inherited_call_weight.rs new file mode 100644 index 0000000000000..355a1c978df06 --- /dev/null +++ b/frame/support/test/tests/pallet_ui/pass/inherited_call_weight.rs @@ -0,0 +1,51 @@ +use frame_support::pallet_prelude::*; +use frame_system::pallet_prelude::*; + +pub trait WeightInfo { + fn foo() -> Weight; +} + +#[frame_support::pallet] +mod parentheses { + use super::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + type WeightInfo: crate::WeightInfo; + } + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::call(weight(::WeightInfo))] + impl Pallet { + #[pallet::call_index(0)] + pub fn foo(_: OriginFor) -> DispatchResult { + Ok(()) + } + } +} + +#[frame_support::pallet] +mod assign { + use super::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + type WeightInfo: crate::WeightInfo; + } + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::call(weight = ::WeightInfo)] + impl Pallet { + #[pallet::call_index(0)] + pub fn foo(_: OriginFor) -> DispatchResult { + Ok(()) + } + } +} + +fn main() { +} diff --git a/frame/support/test/tests/pallet_ui/pass/inherited_call_weight2.rs b/frame/support/test/tests/pallet_ui/pass/inherited_call_weight2.rs new file mode 100644 index 0000000000000..ae70c295d8db2 --- /dev/null +++ b/frame/support/test/tests/pallet_ui/pass/inherited_call_weight2.rs @@ -0,0 +1,57 @@ +use frame_support::pallet_prelude::*; +use frame_system::pallet_prelude::*; + +pub trait WeightInfo { + fn foo() -> Weight; +} + +impl WeightInfo for () { + fn foo() -> Weight { + Weight::zero() + } +} + +#[frame_support::pallet] +mod parentheses { + use super::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + } + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + // Crazy man just uses `()`, but it still works ;) + #[pallet::call(weight(()))] + impl Pallet { + #[pallet::call_index(0)] + pub fn foo(_: OriginFor) -> DispatchResult { + Ok(()) + } + } +} + +#[frame_support::pallet] +mod assign { + use super::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + } + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + // Crazy man just uses `()`, but it still works ;) + #[pallet::call(weight = ())] + impl Pallet { + #[pallet::call_index(0)] + pub fn foo(_: OriginFor) -> DispatchResult { + Ok(()) + } + } +} + +fn main() { +} diff --git a/frame/support/test/tests/pallet_ui/pass/inherited_call_weight3.rs b/frame/support/test/tests/pallet_ui/pass/inherited_call_weight3.rs new file mode 100644 index 0000000000000..567fd2e5fa032 --- /dev/null +++ b/frame/support/test/tests/pallet_ui/pass/inherited_call_weight3.rs @@ -0,0 +1,54 @@ +use frame_support::pallet_prelude::*; +use frame_system::pallet_prelude::*; + +// If, for whatever reason, you dont to not use a `WeightInfo` trait - it will still work. +struct Impl; + +impl Impl { + fn foo() -> Weight { + Weight::zero() + } +} + +#[frame_support::pallet] +mod parentheses { + use super::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + } + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::call(weight(crate::Impl))] + impl Pallet { + #[pallet::call_index(0)] + pub fn foo(_: OriginFor) -> DispatchResult { + Ok(()) + } + } +} + +#[frame_support::pallet] +mod assign { + use super::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + } + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::call(weight = crate::Impl)] + impl Pallet { + #[pallet::call_index(0)] + pub fn foo(_: OriginFor) -> DispatchResult { + Ok(()) + } + } +} + +fn main() { +} diff --git a/frame/support/test/tests/pallet_ui/pass/inherited_call_weight_dev_mode.rs b/frame/support/test/tests/pallet_ui/pass/inherited_call_weight_dev_mode.rs new file mode 100644 index 0000000000000..04ce49ee71e99 --- /dev/null +++ b/frame/support/test/tests/pallet_ui/pass/inherited_call_weight_dev_mode.rs @@ -0,0 +1,30 @@ +use frame_support::pallet_prelude::*; +use frame_system::pallet_prelude::*; + +pub trait WeightInfo { + fn foo() -> Weight; +} + +#[frame_support::pallet(dev_mode)] +mod pallet { + use super::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + type WeightInfo: WeightInfo; + } + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::call(weight(::WeightInfo))] + impl Pallet { + #[pallet::call_index(0)] + pub fn foo(_: OriginFor) -> DispatchResult { + Ok(()) + } + } +} + +fn main() { +} From 6d71741dd2f64cc7c5732a60b26229f8e6fd6587 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 27 Apr 2023 20:08:42 +0000 Subject: [PATCH 710/715] Bump wasmtime from 6.0.1 to 6.0.2 (#14037) Bumps [wasmtime](https://github.com/bytecodealliance/wasmtime) from 6.0.1 to 6.0.2. - [Release notes](https://github.com/bytecodealliance/wasmtime/releases) - [Changelog](https://github.com/bytecodealliance/wasmtime/blob/main/docs/WASI-some-possible-changes.md) - [Commits](https://github.com/bytecodealliance/wasmtime/compare/v6.0.1...v6.0.2) --- updated-dependencies: - dependency-name: wasmtime dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 76 ++++++++++++++-------------- client/executor/wasmtime/Cargo.toml | 2 +- primitives/wasm-interface/Cargo.toml | 2 +- 3 files changed, 40 insertions(+), 40 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c06bf41c24b4d..420c9040897b5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1172,18 +1172,18 @@ dependencies = [ [[package]] name = "cranelift-bforest" -version = "0.93.1" +version = "0.93.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7379abaacee0f14abf3204a7606118f0465785252169d186337bcb75030815a" +checksum = "2bc42ba2e232e5b20ff7dc299a812d53337dadce9a7e39a238e6a5cb82d2e57b" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-codegen" -version = "0.93.1" +version = "0.93.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9489fa336927df749631f1008007ced2871068544f40a202ce6d93fbf2366a7b" +checksum = "253531aca9b6f56103c9420369db3263e784df39aa1c90685a1f69cfbba0623e" dependencies = [ "arrayvec 0.7.2", "bumpalo", @@ -1202,33 +1202,33 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.93.1" +version = "0.93.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05bbb67da91ec721ed57cef2f7c5ef7728e1cd9bde9ffd3ef8601022e73e3239" +checksum = "72f2154365e2bff1b1b8537a7181591fdff50d8e27fa6e40d5c69c3bad0ca7c8" dependencies = [ "cranelift-codegen-shared", ] [[package]] name = "cranelift-codegen-shared" -version = "0.93.1" +version = "0.93.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418ecb2f36032f6665dc1a5e2060a143dbab41d83b784882e97710e890a7a16d" +checksum = "687e14e3f5775248930e0d5a84195abef8b829958e9794bf8d525104993612b4" [[package]] name = "cranelift-entity" -version = "0.93.1" +version = "0.93.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cf583f7b093f291005f9fb1323e2c37f6ee4c7909e39ce016b2e8360d461705" +checksum = "f42ea692c7b450ad18b8c9889661505d51c09ec4380cf1c2d278dbb2da22cae1" dependencies = [ "serde", ] [[package]] name = "cranelift-frontend" -version = "0.93.1" +version = "0.93.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b66bf9e916f57fbbd0f7703ec6286f4624866bf45000111627c70d272c8dda1" +checksum = "8483c2db6f45fe9ace984e5adc5d058102227e4c62e5aa2054e16b0275fd3a6e" dependencies = [ "cranelift-codegen", "log", @@ -1238,15 +1238,15 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.93.1" +version = "0.93.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "649782a39ce99798dd6b4029e2bb318a2fbeaade1b4fa25330763c10c65bc358" +checksum = "e9793158837678902446c411741d87b43f57dadfb944f2440db4287cda8cbd59" [[package]] name = "cranelift-native" -version = "0.93.1" +version = "0.93.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "937e021e089c51f9749d09e7ad1c4f255c2f8686cb8c3df63a34b3ec9921bc41" +checksum = "72668c7755f2b880665cb422c8ad2d56db58a88b9bebfef0b73edc2277c13c49" dependencies = [ "cranelift-codegen", "libc", @@ -1255,9 +1255,9 @@ dependencies = [ [[package]] name = "cranelift-wasm" -version = "0.93.1" +version = "0.93.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d850cf6775477747c9dfda9ae23355dd70512ffebc70cf82b85a5b111ae668b5" +checksum = "3852ce4b088b44ac4e29459573943009a70d1b192c8d77ef949b4e814f656fc1" dependencies = [ "cranelift-codegen", "cranelift-entity", @@ -12635,9 +12635,9 @@ dependencies = [ [[package]] name = "wasmtime" -version = "6.0.1" +version = "6.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6e89f9819523447330ffd70367ef4a18d8c832e24e8150fe054d1d912841632" +checksum = "76a222f5fa1e14b2cefc286f1b68494d7a965f4bf57ec04c59bb62673d639af6" dependencies = [ "anyhow", "bincode", @@ -12663,18 +12663,18 @@ dependencies = [ [[package]] name = "wasmtime-asm-macros" -version = "6.0.1" +version = "6.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bd3a5e46c198032da934469f3a6e48649d1f9142438e4fd4617b68a35644b8a" +checksum = "4407a7246e7d2f3d8fb1cf0c72fda8dbafdb6dd34d555ae8bea0e5ae031089cc" dependencies = [ "cfg-if", ] [[package]] name = "wasmtime-cache" -version = "6.0.1" +version = "6.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b389ae9b678b9c3851091a4804f4182d688d27aff7abc9aa37fa7be37d8ecffa" +checksum = "5ceb3adf61d654be0be67fffdce42447b0880481348785be5fe40b5dd7663a4c" dependencies = [ "anyhow", "base64 0.13.1", @@ -12692,9 +12692,9 @@ dependencies = [ [[package]] name = "wasmtime-cranelift" -version = "6.0.1" +version = "6.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59b2c92a08c0db6efffd88fdc97d7aa9c7c63b03edb0971dbca745469f820e8c" +checksum = "3c366bb8647e01fd08cb5589976284b00abfded5529b33d7e7f3f086c68304a4" dependencies = [ "anyhow", "cranelift-codegen", @@ -12713,9 +12713,9 @@ dependencies = [ [[package]] name = "wasmtime-environ" -version = "6.0.1" +version = "6.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a6db9fc52985ba06ca601f2ff0ff1f526c5d724c7ac267b47326304b0c97883" +checksum = "47b8b50962eae38ee319f7b24900b7cf371f03eebdc17400c1dc8575fc10c9a7" dependencies = [ "anyhow", "cranelift-entity", @@ -12732,9 +12732,9 @@ dependencies = [ [[package]] name = "wasmtime-jit" -version = "6.0.1" +version = "6.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b77e3a52cd84d0f7f18554afa8060cfe564ccac61e3b0802d3fd4084772fa5f6" +checksum = "ffaed4f9a234ba5225d8e64eac7b4a5d13b994aeb37353cde2cbeb3febda9eaa" dependencies = [ "addr2line 0.17.0", "anyhow", @@ -12756,9 +12756,9 @@ dependencies = [ [[package]] name = "wasmtime-jit-debug" -version = "6.0.1" +version = "6.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0245e8a9347017c7185a72e215218a802ff561545c242953c11ba00fccc930f" +checksum = "eed41cbcbf74ce3ff6f1d07d1b707888166dc408d1a880f651268f4f7c9194b2" dependencies = [ "object 0.29.0", "once_cell", @@ -12767,9 +12767,9 @@ dependencies = [ [[package]] name = "wasmtime-jit-icache-coherence" -version = "6.0.1" +version = "6.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67d412e9340ab1c83867051d8d1d7c90aa8c9afc91da086088068e2734e25064" +checksum = "43a28ae1e648461bfdbb79db3efdaee1bca5b940872e4175390f465593a2e54c" dependencies = [ "cfg-if", "libc", @@ -12778,9 +12778,9 @@ dependencies = [ [[package]] name = "wasmtime-runtime" -version = "6.0.1" +version = "6.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d594e791b5fdd4dbaf8cf7ae62f2e4ff85018ce90f483ca6f42947688e48827d" +checksum = "e704b126e4252788ccfc3526d4d4511d4b23c521bf123e447ac726c14545217b" dependencies = [ "anyhow", "cc", @@ -12802,9 +12802,9 @@ dependencies = [ [[package]] name = "wasmtime-types" -version = "6.0.1" +version = "6.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6688d6f96d4dbc1f89fab626c56c1778936d122b5f4ae7a57c2eb42b8d982e2" +checksum = "83e5572c5727c1ee7e8f28717aaa8400e4d22dcbd714ea5457d85b5005206568" dependencies = [ "cranelift-entity", "serde", diff --git a/client/executor/wasmtime/Cargo.toml b/client/executor/wasmtime/Cargo.toml index fed284e916fd6..58a1ffde07898 100644 --- a/client/executor/wasmtime/Cargo.toml +++ b/client/executor/wasmtime/Cargo.toml @@ -19,7 +19,7 @@ libc = "0.2.121" # When bumping wasmtime do not forget to also bump rustix # to exactly the same version as used by wasmtime! -wasmtime = { version = "6.0.1", default-features = false, features = [ +wasmtime = { version = "6.0.2", default-features = false, features = [ "cache", "cranelift", "jitdump", diff --git a/primitives/wasm-interface/Cargo.toml b/primitives/wasm-interface/Cargo.toml index 441d66f0fb064..c45ea75830ef7 100644 --- a/primitives/wasm-interface/Cargo.toml +++ b/primitives/wasm-interface/Cargo.toml @@ -18,7 +18,7 @@ codec = { package = "parity-scale-codec", version = "3.2.2", default-features = impl-trait-for-tuples = "0.2.2" log = { version = "0.4.17", optional = true } wasmi = { version = "0.13.2", optional = true } -wasmtime = { version = "6.0.1", default-features = false, optional = true } +wasmtime = { version = "6.0.2", default-features = false, optional = true } anyhow = { version = "1.0.68", optional = true } sp-std = { version = "5.0.0", default-features = false, path = "../std" } From bca8a29dbde0009e80c4c4737be47abff6b3e2c2 Mon Sep 17 00:00:00 2001 From: Chevdor Date: Wed, 3 May 2023 16:32:44 +0200 Subject: [PATCH 711/715] Only calculate tree route during finalization when there are multiple leaves (#14067) (#14069) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Only calculate tree route when there are multiple leaves * Update client/service/src/client/client.rs --------- Co-authored-by: Sebastian Kunert Co-authored-by: Bastian Köcher --- client/service/src/client/client.rs | 31 +++++++++++++++++------------ 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/client/service/src/client/client.rs b/client/service/src/client/client.rs index eee7e6b82363c..91c59cdbac844 100644 --- a/client/service/src/client/client.rs +++ b/client/service/src/client/client.rs @@ -936,19 +936,24 @@ where return Err(sp_blockchain::Error::NotInFinalizedChain) } - let route_from_best = - sp_blockchain::tree_route(self.backend.blockchain(), best_block, block)?; - - // if the block is not a direct ancestor of the current best chain, - // then some other block is the common ancestor. - if route_from_best.common_block().hash != block { - // NOTE: we're setting the finalized block as best block, this might - // be slightly inaccurate since we might have a "better" block - // further along this chain, but since best chain selection logic is - // 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)?; + // If there is only one leaf, best block is guaranteed to be + // a descendant of the new finalized block. If not, + // we need to check. + if self.backend.blockchain().leaves()?.len() > 1 { + let route_from_best = + sp_blockchain::tree_route(self.backend.blockchain(), best_block, block)?; + + // if the block is not a direct ancestor of the current best chain, + // then some other block is the common ancestor. + if route_from_best.common_block().hash != block { + // NOTE: we're setting the finalized block as best block, this might + // be slightly inaccurate since we might have a "better" block + // further along this chain, but since best chain selection logic is + // 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)?; + } } let enacted = route_from_finalized.enacted(); From 3bb3882ce094ac211dea93fabfdcd4f902f5a7fd Mon Sep 17 00:00:00 2001 From: Chevdor Date: Wed, 10 May 2023 09:23:15 +0200 Subject: [PATCH 712/715] Emit events related to asset mutations (#14099) (#14102) * Emit events related to asset mutations * Fixes * Improve unit tests * cargo fmt Co-authored-by: Keith Yeung --- frame/assets/src/impl_fungibles.rs | 33 +++++++++++++++++++++++++++++- frame/assets/src/tests.rs | 29 ++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/frame/assets/src/impl_fungibles.rs b/frame/assets/src/impl_fungibles.rs index 7bec884f4c56b..893d74b6aa306 100644 --- a/frame/assets/src/impl_fungibles.rs +++ b/frame/assets/src/impl_fungibles.rs @@ -81,7 +81,38 @@ impl, I: 'static> fungibles::Inspect<::AccountId } } -impl, I: 'static> fungibles::Mutate<::AccountId> for Pallet {} +impl, I: 'static> fungibles::Mutate<::AccountId> for Pallet { + fn done_mint_into( + asset_id: Self::AssetId, + beneficiary: &::AccountId, + amount: Self::Balance, + ) { + Self::deposit_event(Event::Issued { asset_id, owner: beneficiary.clone(), amount }) + } + + fn done_burn_from( + asset_id: Self::AssetId, + target: &::AccountId, + balance: Self::Balance, + ) { + Self::deposit_event(Event::Burned { asset_id, owner: target.clone(), balance }); + } + + fn done_transfer( + asset_id: Self::AssetId, + source: &::AccountId, + dest: &::AccountId, + amount: Self::Balance, + ) { + Self::deposit_event(Event::Transferred { + asset_id, + from: source.clone(), + to: dest.clone(), + amount, + }); + } +} + impl, I: 'static> fungibles::Balanced<::AccountId> for Pallet { diff --git a/frame/assets/src/tests.rs b/frame/assets/src/tests.rs index 88ba92d0685a9..4dacfac41cb6b 100644 --- a/frame/assets/src/tests.rs +++ b/frame/assets/src/tests.rs @@ -46,9 +46,18 @@ fn transfer_should_never_burn() { while System::inc_consumers(&2).is_ok() {} let _ = System::dec_consumers(&2); + let _ = System::dec_consumers(&2); // Exactly one consumer ref remaining. + assert_eq!(System::consumers(&2), 1); let _ = >::transfer(0, &1, &2, 50, Protect); + System::assert_has_event(RuntimeEvent::Assets(crate::Event::Transferred { + asset_id: 0, + from: 1, + to: 2, + amount: 50, + })); + assert_eq!(Assets::balance(0, 1), 50); assert_eq!(Assets::balance(0, 1) + Assets::balance(0, 2), 100); }); } @@ -59,11 +68,26 @@ fn basic_minting_should_work() { assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); assert_ok!(Assets::force_create(RuntimeOrigin::root(), 1, 1, true, 1)); assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); + System::assert_last_event(RuntimeEvent::Assets(crate::Event::Issued { + asset_id: 0, + owner: 1, + amount: 100, + })); assert_eq!(Assets::balance(0, 1), 100); assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 2, 100)); + System::assert_last_event(RuntimeEvent::Assets(crate::Event::Issued { + asset_id: 0, + owner: 2, + amount: 100, + })); assert_eq!(Assets::balance(0, 2), 100); assert_eq!(asset_ids(), vec![0, 1, 999]); assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 1, 1, 100)); + System::assert_last_event(RuntimeEvent::Assets(crate::Event::Issued { + asset_id: 1, + owner: 1, + amount: 100, + })); assert_eq!(Assets::account_balances(1), vec![(0, 100), (999, 100), (1, 100)]); }); } @@ -786,6 +810,11 @@ fn burning_asset_balance_with_positive_balance_should_work() { assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); assert_eq!(Assets::balance(0, 1), 100); assert_ok!(Assets::burn(RuntimeOrigin::signed(1), 0, 1, u64::MAX)); + System::assert_last_event(RuntimeEvent::Assets(crate::Event::Burned { + asset_id: 0, + owner: 1, + balance: 100, + })); assert_eq!(Assets::balance(0, 1), 0); }); } From 13c4f34c614ee36e61f51c81b4d5d32bd23f365b Mon Sep 17 00:00:00 2001 From: devdanco Date: Tue, 13 Jun 2023 14:26:22 +0200 Subject: [PATCH 713/715] fix tests --- frame/executive/src/lib.rs | 70 ++++++++------------------------------ 1 file changed, 14 insertions(+), 56 deletions(-) diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index 8799547084972..39f1073e43456 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -131,6 +131,7 @@ use frame_support::{ weights::Weight, }; use schnorrkel::vrf::{VRFOutput, VRFProof}; +use sp_keystore::testing::MemoryKeystore; use sp_runtime::{ generic::Digest, traits::{ @@ -867,10 +868,7 @@ mod tests { use pallet_balances::Call as BalancesCall; use pallet_transaction_payment::CurrencyAdapter; use sp_core::crypto::key_types::AURA; - use sp_keystore::{ - vrf::{VRFTranscriptData, VRFTranscriptValue}, - SyncCryptoStore, - }; + use sp_core::sr25519::vrf::{VrfOutput, VrfProof, VrfSignature, VrfTranscript}; use sp_runtime::{ generic::{DigestItem, Era}, testing::{BlockVer as Block, Digest, HeaderVer as Header}, @@ -1867,7 +1865,7 @@ mod tests { new_test_ext(1).execute_with(|| { let prev_seed = vec![0u8; 32]; let secret_uri = "//Alice"; - let keystore = sp_keystore::testing::KeyStore::new(); + let keystore = MemoryKeystore::new(); let key_pair = sr25519::Pair::from_string(secret_uri, None).expect("Generates key pair"); @@ -1875,10 +1873,7 @@ mod tests { .insert_unknown(AURA, secret_uri, key_pair.public().as_ref()) .expect("Inserts unknown key"); - let transcript = VRFTranscriptData { - label: b"shuffling_seed", - items: vec![("prev_seed", VRFTranscriptValue::Bytes(prev_seed))], - }; + let transcript = VrfTranscript::new(b"shuffling_seed", &[(b"prev_seed",&prev_seed)]); let signature = keystore .sr25519_vrf_sign(AURA, &key_pair.public(), transcript.clone()) @@ -1920,7 +1915,7 @@ mod tests { fn accept_block_that_fetches_txs_from_the_queue() { new_test_ext(1).execute_with(|| { let secret_uri = "//Alice"; - let keystore = sp_keystore::testing::KeyStore::new(); + let keystore = MemoryKeyStore::new(); let key_pair = sr25519::Pair::from_string(secret_uri, None).expect("Generates key pair"); @@ -2008,7 +2003,7 @@ mod tests { fn rejects_block_that_enqueues_too_many_transactions_to_storage_queue() { new_test_ext(1).execute_with(|| { let secret_uri = "//Alice"; - let keystore = sp_keystore::testing::KeyStore::new(); + let keystore = MemoryKeyStore::new(); let key_pair = sr25519::Pair::from_string(secret_uri, None).expect("Generates key pair"); @@ -2070,7 +2065,7 @@ mod tests { fn rejects_block_that_enqueues_new_txs_but_doesnt_execute_any() { new_test_ext(1).execute_with(|| { let secret_uri = "//Alice"; - let keystore = sp_keystore::testing::KeyStore::new(); + let keystore = MemoryKeyStore::new(); let key_pair = sr25519::Pair::from_string(secret_uri, None).expect("Generates key pair"); @@ -2159,7 +2154,7 @@ mod tests { fn do_not_allow_to_accept_binary_blobs_that_does_not_deserialize_into_valid_tx() { new_test_ext(1).execute_with(|| { let secret_uri = "//Alice"; - let keystore = sp_keystore::testing::KeyStore::new(); + let keystore = MemoryKeyStore::new(); let key_pair = sr25519::Pair::from_string(secret_uri, None).expect("Generates key pair"); @@ -2212,7 +2207,7 @@ mod tests { fn do_not_panic_when_tx_poped_from_storage_queue_cannot_be_deserialized() { new_test_ext(1).execute_with(|| { let secret_uri = "//Alice"; - let keystore = sp_keystore::testing::KeyStore::new(); + let keystore = MemoryKeyStore::new(); let key_pair = sr25519::Pair::from_string(secret_uri, None).expect("Generates key pair"); @@ -2304,7 +2299,7 @@ mod tests { // inject txs with wrong nonces new_test_ext(1).execute_with(|| { let secret_uri = "//Alice"; - let keystore = sp_keystore::testing::KeyStore::new(); + let keystore = MemoryKeyStore::new(); let key_pair = sr25519::Pair::from_string(secret_uri, None).expect("Generates key pair"); @@ -2397,7 +2392,7 @@ mod tests { fn reject_block_that_tries_to_enqueue_same_tx_mulitple_times() { new_test_ext(1).execute_with(|| { let secret_uri = "//Alice"; - let keystore = sp_keystore::testing::KeyStore::new(); + let keystore = MemoryKeyStore::new(); let key_pair = sr25519::Pair::from_string(secret_uri, None).expect("Generates key pair"); @@ -2460,7 +2455,7 @@ mod tests { fn reject_block_that_enqueus_same_tx_multiple_times() { new_test_ext(1).execute_with(|| { let secret_uri = "//Alice"; - let keystore = sp_keystore::testing::KeyStore::new(); + let keystore = MemoryKeyStore::new(); let key_pair = sr25519::Pair::from_string(secret_uri, None).expect("Generates key pair"); @@ -2537,7 +2532,7 @@ mod tests { // 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); + let xt1 = TestXt::new(RuntimeCall::Custom(custom::Call::inherent_call {}), sign_extra(1, 0, 0)); new_test_ext(1).execute_with(|| { assert_eq!( @@ -2558,7 +2553,7 @@ mod tests { fn reject_block_that_tries_to_pop_more_txs_than_available() { new_test_ext(1).execute_with(|| { let secret_uri = "//Alice"; - let keystore = sp_keystore::testing::KeyStore::new(); + let keystore = MemoryKeyStore::new(); let key_pair = sr25519::Pair::from_string(secret_uri, None).expect("Generates key pair"); @@ -2631,43 +2626,6 @@ mod tests { }); } - // 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() - ); - }) - } - #[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() { From 49fa79b748df35558022d730cdcf8ad11b0f16f4 Mon Sep 17 00:00:00 2001 From: devdanco Date: Wed, 14 Jun 2023 13:38:30 +0200 Subject: [PATCH 714/715] wip --- frame/executive/src/lib.rs | 79 +++++++++++++++++++------------------- primitives/ver/src/lib.rs | 5 +-- 2 files changed, 41 insertions(+), 43 deletions(-) diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index 39f1073e43456..f9574e6ffa457 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -131,7 +131,6 @@ use frame_support::{ weights::Weight, }; use schnorrkel::vrf::{VRFOutput, VRFProof}; -use sp_keystore::testing::MemoryKeystore; use sp_runtime::{ generic::Digest, traits::{ @@ -855,7 +854,7 @@ where mod tests { use super::*; use hex_literal::hex; - use sp_core::{sr25519, testing::SR25519, Pair, ShufflingSeed, H256}; + use sp_core::{sr25519, testing::SR25519, Pair, ShufflingSeed, H256, H512}; use sp_ver::calculate_next_seed_from_bytes; @@ -869,6 +868,8 @@ mod tests { use pallet_transaction_payment::CurrencyAdapter; use sp_core::crypto::key_types::AURA; use sp_core::sr25519::vrf::{VrfOutput, VrfProof, VrfSignature, VrfTranscript}; + use sp_keystore::testing::MemoryKeystore; + use sp_core::hexdisplay::AsBytesRef; use sp_runtime::{ generic::{DigestItem, Era}, testing::{BlockVer as Block, Digest, HeaderVer as Header}, @@ -1219,13 +1220,13 @@ mod tests { block_import_works_inner( new_test_ext_v0(1), array_bytes::hex_n_into_unchecked( - "65e953676859e7a33245908af7ad3637d6861eb90416d433d485e95e2dd174a1", + "d1d38dfbb0537af5d25007407f38233f372280d9092c702337a333559dc43b92", ), ); block_import_works_inner( new_test_ext(1), array_bytes::hex_n_into_unchecked( - "5a19b3d6fdb7241836349fdcbe2d9df4d4f945b949d979e31ad50bff1cbcd1c2", + "933ded67b9e4e60948c030e9f934f525e9a383b202190bd8377cd61c96f54188", ), ); } @@ -1865,18 +1866,18 @@ mod tests { new_test_ext(1).execute_with(|| { let prev_seed = vec![0u8; 32]; let secret_uri = "//Alice"; - let keystore = MemoryKeystore::new(); + let keystore = Arc::new(MemoryKeystore::new()); let key_pair = sr25519::Pair::from_string(secret_uri, None).expect("Generates key pair"); keystore - .insert_unknown(AURA, secret_uri, key_pair.public().as_ref()) + .insert(AURA, secret_uri, key_pair.public().as_ref()) .expect("Inserts unknown key"); let transcript = VrfTranscript::new(b"shuffling_seed", &[(b"prev_seed",&prev_seed)]); let signature = keystore - .sr25519_vrf_sign(AURA, &key_pair.public(), transcript.clone()) + .sr25519_vrf_sign(AURA, &key_pair.public(), &transcript) .unwrap() .unwrap(); @@ -1890,7 +1891,7 @@ mod tests { parent_hash: [69u8; 32].into(), number: 1, state_root: hex!( - "7c3644ad634bf7d91f11984ebb149e389c92f99fef8ac181f7a9a43ee31d94e3" + "3f6b94972b987d9c76943ad7031349c8e62d5900fd98ba6345da8435dad66d09" ) .into(), extrinsics_root: hex!( @@ -1900,8 +1901,8 @@ mod tests { digest: Digest { logs: vec![] }, count: 0, seed: ShufflingSeed { - seed: signature.output.to_bytes().into(), - proof: signature.proof.to_bytes().into(), + seed: H256::from_slice(signature.output.encode().as_bytes_ref()), + proof: H512::from_slice(signature.proof.encode().as_bytes_ref()), }, }, extrinsics: vec![], @@ -1915,12 +1916,10 @@ mod tests { fn accept_block_that_fetches_txs_from_the_queue() { new_test_ext(1).execute_with(|| { let secret_uri = "//Alice"; - let keystore = MemoryKeyStore::new(); - + let keystore = MemoryKeystore::new(); let key_pair = sr25519::Pair::from_string(secret_uri, None).expect("Generates key pair"); - keystore - .insert_unknown(AURA, secret_uri, key_pair.public().as_ref()) + keystore.insert(AURA, secret_uri, key_pair.public().as_ref()) .expect("Inserts unknown key"); let xt = TestXt::new(call_transfer(2, 69), sign_extra(1, 0, 0)); @@ -1948,7 +1947,7 @@ mod tests { parent_hash: System::parent_hash(), number: 1, state_root: hex!( - "10b8fe2ef82cb245fc71dab724fde5462bacc4f0d2b3b6bf0581aa89d63ef3a1" + "102bbfb2d146b9313489419e816d176b1f7280e8b1000cd27852bed7d495abbd" ) .into(), extrinsics_root: hex!( @@ -1975,7 +1974,7 @@ mod tests { parent_hash: System::parent_hash(), number: 2, state_root: hex!( - "9bd12b1263d49dd1d6cf7fdf0d1c8330db2c927bb2d55e77b725ccdcaaefcba5" + "da228fb69aec5dd5f76ebb155e8faf848c49581528c06f776543c834369032fa" ) .into(), extrinsics_root: hex!( @@ -2003,12 +2002,12 @@ mod tests { fn rejects_block_that_enqueues_too_many_transactions_to_storage_queue() { new_test_ext(1).execute_with(|| { let secret_uri = "//Alice"; - let keystore = MemoryKeyStore::new(); + let keystore = MemoryKeystore::new(); let key_pair = sr25519::Pair::from_string(secret_uri, None).expect("Generates key pair"); keystore - .insert_unknown(AURA, secret_uri, key_pair.public().as_ref()) + .insert(AURA, secret_uri, key_pair.public().as_ref()) .expect("Inserts unknown key"); let txs = (0..100000) @@ -2037,7 +2036,7 @@ mod tests { parent_hash: System::parent_hash(), number: 1, state_root: hex!( - "5bc40cfd524119a0f1ca2fbd9f0357806d0041f56e0de1750b1fe0011915ca4c" + "831e2467d5152af868a45ef85d03eff185fd9c2b29df12b2daec5e0ea069acb4" ) .into(), extrinsics_root: hex!( @@ -2065,12 +2064,12 @@ mod tests { fn rejects_block_that_enqueues_new_txs_but_doesnt_execute_any() { new_test_ext(1).execute_with(|| { let secret_uri = "//Alice"; - let keystore = MemoryKeyStore::new(); + let keystore = MemoryKeystore::new(); let key_pair = sr25519::Pair::from_string(secret_uri, None).expect("Generates key pair"); keystore - .insert_unknown(AURA, secret_uri, key_pair.public().as_ref()) + .insert(AURA, secret_uri, key_pair.public().as_ref()) .expect("Inserts unknown key"); let txs = (0..10) @@ -2099,7 +2098,7 @@ mod tests { parent_hash: System::parent_hash(), number: 1, state_root: hex!( - "5bc40cfd524119a0f1ca2fbd9f0357806d0041f56e0de1750b1fe0011915ca4c" + "831e2467d5152af868a45ef85d03eff185fd9c2b29df12b2daec5e0ea069acb4" ) .into(), extrinsics_root: hex!( @@ -2154,12 +2153,12 @@ mod tests { fn do_not_allow_to_accept_binary_blobs_that_does_not_deserialize_into_valid_tx() { new_test_ext(1).execute_with(|| { let secret_uri = "//Alice"; - let keystore = MemoryKeyStore::new(); + let keystore = MemoryKeystore::new(); let key_pair = sr25519::Pair::from_string(secret_uri, None).expect("Generates key pair"); keystore - .insert_unknown(AURA, secret_uri, key_pair.public().as_ref()) + .insert(AURA, secret_uri, key_pair.public().as_ref()) .expect("Inserts unknown key"); let pub_key_bytes = AsRef::<[u8; 32]>::as_ref(&key_pair.public()) @@ -2207,12 +2206,12 @@ mod tests { fn do_not_panic_when_tx_poped_from_storage_queue_cannot_be_deserialized() { new_test_ext(1).execute_with(|| { let secret_uri = "//Alice"; - let keystore = MemoryKeyStore::new(); + let keystore = MemoryKeystore::new(); let key_pair = sr25519::Pair::from_string(secret_uri, None).expect("Generates key pair"); keystore - .insert_unknown(AURA, secret_uri, key_pair.public().as_ref()) + .insert(AURA, secret_uri, key_pair.public().as_ref()) .expect("Inserts unknown key"); let pub_key_bytes = AsRef::<[u8; 32]>::as_ref(&key_pair.public()) @@ -2238,7 +2237,7 @@ mod tests { parent_hash: System::parent_hash(), number: 1, state_root: hex!( - "10b8fe2ef82cb245fc71dab724fde5462bacc4f0d2b3b6bf0581aa89d63ef3a1" + "102bbfb2d146b9313489419e816d176b1f7280e8b1000cd27852bed7d495abbd" ) .into(), extrinsics_root: hex!( @@ -2271,7 +2270,7 @@ mod tests { parent_hash: System::parent_hash(), number: 2, state_root: hex!( - "9a3734f7495f8d2cdeaf71b8908040428848f8333274f9b871f522aa8838cc2e" + "30bb4cf688e7331e3149053da3e83aa56b4b7e2e289106fd7fd523369fb1cbe5" ) .into(), extrinsics_root: hex!( @@ -2299,12 +2298,12 @@ mod tests { // inject txs with wrong nonces new_test_ext(1).execute_with(|| { let secret_uri = "//Alice"; - let keystore = MemoryKeyStore::new(); + let keystore = MemoryKeystore::new(); let key_pair = sr25519::Pair::from_string(secret_uri, None).expect("Generates key pair"); keystore - .insert_unknown(AURA, secret_uri, key_pair.public().as_ref()) + .insert(AURA, secret_uri, key_pair.public().as_ref()) .expect("Inserts unknown key"); let pub_key_bytes = AsRef::<[u8; 32]>::as_ref(&key_pair.public()) @@ -2336,7 +2335,7 @@ mod tests { parent_hash: System::parent_hash(), number: 1, state_root: hex!( - "19fd2bb5ce39066549e0f84e2fcabb715e3541e3c26ec8047554bbcd9c7885a4" + "9768ee8cbc4d885d73464409ef4adbe4b6997d9accd75eb205eaa09140aace7f" ) .into(), extrinsics_root: hex!( @@ -2364,7 +2363,7 @@ mod tests { parent_hash: System::parent_hash(), number: 2, state_root: hex!( - "15a8610abb49b6649f043cf75c2ff9ed4209fb5b657fd345d0e0fc9b8165ba72" + "f4c46903988d1f2877c965ea22f33853c94ebbd7da3c8597335e46b0392d638b" ) .into(), extrinsics_root: hex!( @@ -2392,12 +2391,12 @@ mod tests { fn reject_block_that_tries_to_enqueue_same_tx_mulitple_times() { new_test_ext(1).execute_with(|| { let secret_uri = "//Alice"; - let keystore = MemoryKeyStore::new(); + let keystore = MemoryKeystore::new(); let key_pair = sr25519::Pair::from_string(secret_uri, None).expect("Generates key pair"); keystore - .insert_unknown(AURA, secret_uri, key_pair.public().as_ref()) + .insert(AURA, secret_uri, key_pair.public().as_ref()) .expect("Inserts unknown key"); let pub_key_bytes = AsRef::<[u8; 32]>::as_ref(&key_pair.public()) @@ -2427,7 +2426,7 @@ mod tests { parent_hash: System::parent_hash(), number: 1, state_root: hex!( - "10b8fe2ef82cb245fc71dab724fde5462bacc4f0d2b3b6bf0581aa89d63ef3a1" + "102bbfb2d146b9313489419e816d176b1f7280e8b1000cd27852bed7d495abbd" ) .into(), extrinsics_root: hex!( @@ -2455,12 +2454,12 @@ mod tests { fn reject_block_that_enqueus_same_tx_multiple_times() { new_test_ext(1).execute_with(|| { let secret_uri = "//Alice"; - let keystore = MemoryKeyStore::new(); + let keystore = MemoryKeystore::new(); let key_pair = sr25519::Pair::from_string(secret_uri, None).expect("Generates key pair"); keystore - .insert_unknown(AURA, secret_uri, key_pair.public().as_ref()) + .insert(AURA, secret_uri, key_pair.public().as_ref()) .expect("Inserts unknown key"); let pub_key_bytes = AsRef::<[u8; 32]>::as_ref(&key_pair.public()) @@ -2486,7 +2485,7 @@ mod tests { parent_hash: System::parent_hash(), number: 1, state_root: hex!( - "10b8fe2ef82cb245fc71dab724fde5462bacc4f0d2b3b6bf0581aa89d63ef3a1" + "102bbfb2d146b9313489419e816d176b1f7280e8b1000cd27852bed7d495abbd" ) .into(), extrinsics_root: hex!( @@ -2553,12 +2552,12 @@ mod tests { fn reject_block_that_tries_to_pop_more_txs_than_available() { new_test_ext(1).execute_with(|| { let secret_uri = "//Alice"; - let keystore = MemoryKeyStore::new(); + let keystore = MemoryKeystore::new(); let key_pair = sr25519::Pair::from_string(secret_uri, None).expect("Generates key pair"); keystore - .insert_unknown(AURA, secret_uri, key_pair.public().as_ref()) + .insert(AURA, secret_uri, key_pair.public().as_ref()) .expect("Inserts unknown key"); let pub_key_bytes = AsRef::<[u8; 32]>::as_ref(&key_pair.public()) diff --git a/primitives/ver/src/lib.rs b/primitives/ver/src/lib.rs index 4f8eb67df8f36..790a573a22238 100644 --- a/primitives/ver/src/lib.rs +++ b/primitives/ver/src/lib.rs @@ -38,7 +38,7 @@ pub fn extract_inherent_data(data: &InherentData) -> Result( +pub fn calculate_next_seed( keystore: &T, public_key: &sr25519::Public, prev_seed: &ShufflingSeed, @@ -47,7 +47,7 @@ pub fn calculate_next_seed( } #[cfg(feature = "helpers")] -pub fn calculate_next_seed_from_bytes( +pub fn calculate_next_seed_from_bytes( keystore: &T, public_key: &sr25519::Public, prev_seed: Vec, @@ -57,7 +57,6 @@ pub fn calculate_next_seed_from_bytes( .ok() .flatten() .map(|sig| { - ShufflingSeed { seed: H256::from_slice(sig.output.encode().as_bytes_ref()), proof: H512::from_slice(sig.proof.encode().as_bytes_ref()), From 45307535efba31f2daa86be4a8e9b25e03cd5db3 Mon Sep 17 00:00:00 2001 From: vanderian Date: Mon, 26 Jun 2023 14:42:57 +0200 Subject: [PATCH 715/715] sp-api: support nested transactions --- Cargo.lock | 1 + .../api/proc-macro/src/impl_runtime_apis.rs | 79 +++++++++---------- primitives/api/test/Cargo.toml | 1 + primitives/api/test/tests/runtime_calls.rs | 54 ++++++++++++- test-utils/runtime/src/lib.rs | 10 +++ 5 files changed, 101 insertions(+), 44 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2b977e28e57d6..cbff1e45657f5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10434,6 +10434,7 @@ dependencies = [ "sp-state-machine", "sp-tracing", "sp-version", + "static_assertions", "substrate-test-runtime-client", "trybuild", ] diff --git a/primitives/api/proc-macro/src/impl_runtime_apis.rs b/primitives/api/proc-macro/src/impl_runtime_apis.rs index b8dcf625df45e..7e46f0a5a65eb 100644 --- a/primitives/api/proc-macro/src/impl_runtime_apis.rs +++ b/primitives/api/proc-macro/src/impl_runtime_apis.rs @@ -227,7 +227,7 @@ fn generate_runtime_api_base_structures() -> Result { #[cfg(any(feature = "std", test))] pub struct RuntimeApiImpl + 'static> { call: &'static C, - commit_on_success: std::cell::RefCell, + in_transaction: std::cell::RefCell, changes: std::cell::RefCell<#crate_::OverlayedChanges>, storage_transaction_cache: std::cell::RefCell< #crate_::StorageTransactionCache @@ -247,9 +247,9 @@ fn generate_runtime_api_base_structures() -> Result { ) -> R where Self: Sized { self.start_transaction(); - *std::cell::RefCell::borrow_mut(&self.commit_on_success) = false; + let old_value = std::cell::RefCell::replace(&self.in_transaction, true); let res = call(self); - *std::cell::RefCell::borrow_mut(&self.commit_on_success) = true; + *std::cell::RefCell::borrow_mut(&self.in_transaction) = old_value; self.commit_or_rollback(std::matches!(res, #crate_::TransactionOutcome::Commit(_))); @@ -332,7 +332,7 @@ fn generate_runtime_api_base_structures() -> Result { ) -> #crate_::ApiRef<'a, Self::RuntimeApi> { RuntimeApiImpl { call: unsafe { std::mem::transmute(call) }, - commit_on_success: true.into(), + in_transaction: false.into(), changes: std::default::Default::default(), recorder: std::default::Default::default(), storage_transaction_cache: std::default::Default::default(), @@ -348,46 +348,35 @@ fn generate_runtime_api_base_structures() -> Result { 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 *std::cell::RefCell::borrow(&self.commit_on_success) { - let res = if commit { - let res = if let Some(recorder) = &self.recorder { - #crate_::ProofRecorder::::commit_transaction(&recorder) - } else { - Ok(()) - }; - - let res2 = #crate_::OverlayedChanges::commit_transaction( - &mut std::cell::RefCell::borrow_mut(&self.changes) - ); - - // Will panic on an `Err` below, however we should call commit - // on the recorder and the changes together. - std::result::Result::and(res, std::result::Result::map_err(res2, drop)) + let res = if commit { + let res = if let Some(recorder) = &self.recorder { + #crate_::ProofRecorder::::commit_transaction(&recorder) } else { - let res = if let Some(recorder) = &self.recorder { - #crate_::ProofRecorder::::rollback_transaction(&recorder) - } else { - Ok(()) - }; - - let res2 = #crate_::OverlayedChanges::rollback_transaction( - &mut std::cell::RefCell::borrow_mut(&self.changes) - ); - - // Will panic on an `Err` below, however we should call commit - // on the recorder and the changes together. - std::result::Result::and(res, std::result::Result::map_err(res2, drop)) + Ok(()) }; - - std::result::Result::expect(res, proof); - } + let res2 = #crate_::OverlayedChanges::commit_transaction( + &mut std::cell::RefCell::borrow_mut(&self.changes) + ); + // Will panic on an `Err` below, however we should call commit + // on the recorder and the changes together. + std::result::Result::and(res, std::result::Result::map_err(res2, drop)) + } else { + let res = if let Some(recorder) = &self.recorder { + #crate_::ProofRecorder::::rollback_transaction(&recorder) + } else { + Ok(()) + }; + let res2 = #crate_::OverlayedChanges::rollback_transaction( + &mut std::cell::RefCell::borrow_mut(&self.changes) + ); + // Will panic on an `Err` below, however we should call commit + // on the recorder and the changes together. + std::result::Result::and(res, std::result::Result::map_err(res2, drop)) + }; + std::result::Result::expect(res, proof); } fn start_transaction(&self) { - if !*std::cell::RefCell::borrow(&self.commit_on_success) { - return - } - #crate_::OverlayedChanges::start_transaction( &mut std::cell::RefCell::borrow_mut(&self.changes) ); @@ -486,7 +475,13 @@ impl<'a> ApiRuntimeImplToApiRuntimeApiImpl<'a> { params: std::vec::Vec, fn_name: &dyn Fn(#crate_::RuntimeVersion) -> &'static str, ) -> std::result::Result, #crate_::ApiError> { - self.start_transaction(); + // If we are not already in a transaction, we should create a new transaction + // and then commit/roll it back at the end! + let in_transaction = *std::cell::RefCell::borrow(&self.in_transaction); + + if !in_transaction { + self.start_transaction(); + } let res = (|| { let version = #crate_::CallApiAt::<__SrApiBlock__>::runtime_version_at( @@ -510,7 +505,9 @@ impl<'a> ApiRuntimeImplToApiRuntimeApiImpl<'a> { ) })(); - self.commit_or_rollback(std::result::Result::is_ok(&res)); + if !in_transaction { + self.commit_or_rollback(std::result::Result::is_ok(&res)); + } res } diff --git a/primitives/api/test/Cargo.toml b/primitives/api/test/Cargo.toml index 5b6c144ef3f6b..338644fc1dc21 100644 --- a/primitives/api/test/Cargo.toml +++ b/primitives/api/test/Cargo.toml @@ -29,6 +29,7 @@ criterion = "0.4.0" futures = "0.3.21" log = "0.4.17" sp-core = { version = "7.0.0", path = "../../core" } +static_assertions = "1.1.0" [[bench]] name = "bench" diff --git a/primitives/api/test/tests/runtime_calls.rs b/primitives/api/test/tests/runtime_calls.rs index 956a6a25f1558..b4d5002d7c194 100644 --- a/primitives/api/test/tests/runtime_calls.rs +++ b/primitives/api/test/tests/runtime_calls.rs @@ -15,15 +15,20 @@ // See the License for the specific language governing permissions and // limitations under the License. -use sp_api::{Core, ProvideRuntimeApi}; -use sp_runtime::traits::{HashFor, Header as HeaderT}; +use std::panic::UnwindSafe; + +use sp_api::{ApiExt, Core, ProvideRuntimeApi}; +use sp_runtime::{ + traits::{HashFor, Header as HeaderT}, + TransactionOutcome, +}; use sp_state_machine::{ create_proof_check_backend, execution_proof_check_on_trie_backend, ExecutionStrategy, }; use substrate_test_runtime_client::{ prelude::*, runtime::{Block, Header, TestAPI, Transfer}, - DefaultTestClientBuilderExt, TestClientBuilder, + DefaultTestClientBuilderExt, TestClient, TestClientBuilder, }; use codec::Encode; @@ -205,6 +210,49 @@ fn call_runtime_api_with_multiple_arguments() { .unwrap(); } +// Certain logic like the transaction handling is not unwind safe. +// +// Ensure that the type is not unwind safe! +static_assertions::assert_not_impl_any!(>::Api: UnwindSafe); + +#[test] +fn ensure_transactional_works() { + const KEY: &[u8] = b"test"; + + let client = TestClientBuilder::new().build(); + let best_hash = client.chain_info().best_hash; + + let runtime_api = client.runtime_api(); + runtime_api.execute_in_transaction(|api| { + api.write_key_value(best_hash, KEY.to_vec(), vec![1, 2, 3], false).unwrap(); + + api.execute_in_transaction(|api| { + api.write_key_value(best_hash, KEY.to_vec(), vec![1, 2, 3, 4], false).unwrap(); + + TransactionOutcome::Commit(()) + }); + + TransactionOutcome::Commit(()) + }); + + let changes = runtime_api + .into_storage_changes(&client.state_at(best_hash).unwrap(), best_hash) + .unwrap(); + assert_eq!(changes.main_storage_changes[0].1, Some(vec![1, 2, 3, 4])); + + let runtime_api = client.runtime_api(); + runtime_api.execute_in_transaction(|api| { + assert!(api.write_key_value(best_hash, KEY.to_vec(), vec![1, 2, 3], true).is_err()); + + TransactionOutcome::Commit(()) + }); + + let changes = runtime_api + .into_storage_changes(&client.state_at(best_hash).unwrap(), best_hash) + .unwrap(); + assert_eq!(changes.main_storage_changes[0].1, Some(vec![1, 2, 3])); +} + #[test] fn disable_logging_works() { if std::env::var("RUN_TEST").is_ok() { diff --git a/test-utils/runtime/src/lib.rs b/test-utils/runtime/src/lib.rs index ca81e3ffb1601..57726316b7272 100644 --- a/test-utils/runtime/src/lib.rs +++ b/test-utils/runtime/src/lib.rs @@ -390,6 +390,8 @@ cfg_if! { fn do_trace_log(); /// Verify the given signature, public & message bundle. fn verify_ed25519(sig: ed25519::Signature, public: ed25519::Public, message: Vec) -> bool; + /// Write the given `value` under the given `key` into the storage and then optional panic. + fn write_key_value(key: Vec, value: Vec, panic: bool); } } } else { @@ -905,6 +907,14 @@ cfg_if! { fn verify_ed25519(sig: ed25519::Signature, public: ed25519::Public, message: Vec) -> bool { sp_io::crypto::ed25519_verify(&sig, &message, &public) } + + fn write_key_value(key: Vec, value: Vec, panic: bool) { + sp_io::storage::set(&key, &value); + + if panic { + panic!("I'm just following my master"); + } + } } impl sp_consensus_aura::AuraApi for Runtime {

(path: P) -> Result -where - P: AsRef, -{ - fs::OpenOptions::new().write(true).create_new(true).open(path) -} - -#[cfg(test)] -mod tests { - use super::*; - use tempfile::TempDir; - - fn tempdir_with_prefix(prefix: &str) -> TempDir { - tempfile::Builder::new().prefix(prefix).tempdir().unwrap() - } - - fn secret_bytes(kp: &Keypair) -> Vec { - let Keypair::Ed25519(p) = kp; - p.secret().as_ref().iter().cloned().collect() - } - - #[test] - fn test_secret_file() { - let tmp = tempdir_with_prefix("x"); - std::fs::remove_dir(tmp.path()).unwrap(); // should be recreated - let file = tmp.path().join("x").to_path_buf(); - let kp1 = NodeKeyConfig::Ed25519(Secret::File(file.clone())).into_keypair().unwrap(); - let kp2 = NodeKeyConfig::Ed25519(Secret::File(file.clone())).into_keypair().unwrap(); - assert!(file.is_file() && secret_bytes(&kp1) == secret_bytes(&kp2)) - } - - #[test] - fn test_secret_input() { - let sk = ed25519::SecretKey::generate(); - let kp1 = NodeKeyConfig::Ed25519(Secret::Input(sk.clone())).into_keypair().unwrap(); - let kp2 = NodeKeyConfig::Ed25519(Secret::Input(sk)).into_keypair().unwrap(); - assert!(secret_bytes(&kp1) == secret_bytes(&kp2)); - } - - #[test] - fn test_secret_new() { - let kp1 = NodeKeyConfig::Ed25519(Secret::New).into_keypair().unwrap(); - let kp2 = NodeKeyConfig::Ed25519(Secret::New).into_keypair().unwrap(); - assert!(secret_bytes(&kp1) != secret_bytes(&kp2)); - } -} diff --git a/client/network/src/lib.rs b/client/network/src/lib.rs index 8714d66f1332d..f94a71681cd3d 100644 --- a/client/network/src/lib.rs +++ b/client/network/src/lib.rs @@ -257,8 +257,6 @@ 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}, @@ -273,14 +271,13 @@ pub use sc_network_common::{ }, sync::{ warp::{WarpSyncPhase, WarpSyncProgress}, - StateDownloadProgress, SyncState, + ExtendedPeerInfo, StateDownloadProgress, SyncEventStream, SyncState, SyncStatusProvider, }, }; pub use service::{ DecodingError, Keypair, NetworkService, NetworkWorker, NotificationSender, NotificationSenderReady, OutboundFailure, PublicKey, }; -use sp_runtime::traits::{Block as BlockT, NumberFor}; pub use sc_peerset::ReputationChange; @@ -295,18 +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; - -/// Abstraction over syncing-related services -pub trait ChainSyncInterface: - NetworkSyncForkRequest> + JustificationSyncLink + Link + Send + Sync -{ -} - -impl ChainSyncInterface for T where - T: NetworkSyncForkRequest> - + JustificationSyncLink - + Link - + Send - + Sync -{ -} diff --git a/client/network/src/protocol.rs b/client/network/src/protocol.rs index 2443fce815676..8d604124233a0 100644 --- a/client/network/src/protocol.rs +++ b/client/network/src/protocol.rs @@ -19,8 +19,7 @@ use crate::config; use bytes::Bytes; -use codec::{Decode, DecodeAll, Encode}; -use futures::prelude::*; +use codec::{DecodeAll, Encode}; use libp2p::{ core::connection::ConnectionId, swarm::{ @@ -29,32 +28,20 @@ use libp2p::{ }, Multiaddr, PeerId, }; -use log::{debug, error, log, trace, warn, Level}; -use lru::LruCache; +use log::{debug, error, warn}; 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_network_common::{ config::NonReservedPeerMode, error, protocol::{role::Roles, ProtocolName}, - sync::{ - message::{BlockAnnounce, BlockAnnouncesHandshake, BlockData, BlockResponse, BlockState}, - BadPeer, ChainSync, PollBlockAnnounceValidation, SyncStatus, - }, - utils::{interval, LruHashSet}, + sync::message::BlockAnnouncesHandshake, }; -use sp_arithmetic::traits::SaturatedConversion; -use sp_runtime::traits::{Block as BlockT, CheckedSub, Header as HeaderT, NumberFor, Zero}; +use sp_runtime::traits::Block as BlockT; use std::{ collections::{HashMap, HashSet, VecDeque}, iter, - num::NonZeroUsize, - pin::Pin, - sync::Arc, task::Poll, - time, }; mod notifications; @@ -63,12 +50,6 @@ pub mod message; pub use notifications::{NotificationsSink, NotifsHandlerError, Ready}; -/// Interval at which we perform time based maintenance -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 size used for notifications in the block announce and transaction protocols. // Must be equal to `max(MAX_BLOCK_ANNOUNCE_SIZE, MAX_TRANSACTIONS_SIZE)`. pub(crate) const BLOCK_ANNOUNCES_TRANSACTIONS_SUBSTREAM_SIZE: u64 = 16 * 1024 * 1024; @@ -79,88 +60,16 @@ const HARDCODED_PEERSETS_SYNC: sc_peerset::SetId = sc_peerset::SetId::from(0); /// superior to this value corresponds to a user-defined protocol. const NUM_HARDCODED_PEERSETS: usize = 1; -/// When light node connects to the full node and the full node is behind light node -/// for at least `LIGHT_MAXIMAL_BLOCKS_DIFFERENCE` blocks, we consider it not useful -/// and disconnect to free connection slot. -const LIGHT_MAXIMAL_BLOCKS_DIFFERENCE: u64 = 8192; - mod rep { use sc_peerset::ReputationChange as Rep; - /// 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 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. - pub const BAD_BLOCK_ANNOUNCEMENT: Rep = Rep::new(-(1 << 12), "Bad block announcement"); -} - -struct Metrics { - peers: Gauge, - queued_blocks: Gauge, - fork_targets: Gauge, - justifications: GaugeVec, -} - -impl Metrics { - fn register(r: &Registry) -> Result { - Ok(Self { - peers: { - let g = Gauge::new("substrate_sync_peers", "Number of peers we sync with")?; - register(g, r)? - }, - queued_blocks: { - let g = - Gauge::new("substrate_sync_queued_blocks", "Number of blocks in import queue")?; - register(g, r)? - }, - fork_targets: { - let g = Gauge::new("substrate_sync_fork_targets", "Number of fork sync targets")?; - register(g, r)? - }, - justifications: { - let g = GaugeVec::new( - Opts::new( - "substrate_sync_extra_justifications", - "Number of extra justifications requests", - ), - &["status"], - )?; - register(g, r)? - }, - }) - } } // Lock must always be taken in order declared here. -pub struct Protocol { - /// Interval at which we call `tick`. - tick_timeout: Pin + Send>>, +pub struct Protocol { /// Pending list of messages to return from `poll` as a priority. - pending_messages: VecDeque>, - /// Assigned roles. - roles: Roles, - genesis_hash: B::Hash, - /// State machine that handles the list of in-progress requests. Only full node peers are - /// registered. - chain_sync: Box>, - // 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, - /// 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. - default_peers_set_num_light: usize, + pending_messages: VecDeque, /// Used to report reputation changes. peerset_handle: sc_peerset::PeersetHandle, /// Handles opening the unique substream and sending and receiving raw messages. @@ -174,85 +83,18 @@ pub struct Protocol { /// solve this, an entry is added to this map whenever an invalid handshake is received. /// Entries are removed when the corresponding "substream closed" is later received. bad_handshake_substreams: HashSet<(PeerId, sc_peerset::SetId)>, - /// Prometheus metrics. - metrics: Option, - /// 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: LruCache>, + /// Connected peers. + peers: HashMap, + _marker: std::marker::PhantomData, } -/// Peer information -#[derive(Debug)] -struct Peer { - info: PeerInfo, - /// Holds a set of blocks known to this peer. - known_blocks: LruHashSet, -} - -/// Info about a peer's known state. -#[derive(Clone, Debug)] -pub struct PeerInfo { - /// Roles - pub roles: Roles, - /// Peer best block hash - pub best_hash: B::Hash, - /// Peer best block number - pub best_number: ::Number, -} - -impl Protocol -where - B: BlockT, - Client: HeaderBackend + 'static, -{ +impl Protocol { /// Create a new instance. pub fn new( roles: Roles, - chain: Arc, network_config: &config::NetworkConfiguration, - 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(); - - let boot_node_ids = { - let mut list = HashSet::new(); - for node in &network_config.boot_nodes { - list.insert(node.peer_id); - } - list.shrink_to_fit(); - list - }; - - let important_peers = { - let mut imp_p = HashSet::new(); - for reserved in &network_config.default_peers_set.reserved_nodes { - imp_p.insert(reserved.peer_id); - } - for reserved in network_config - .extra_sets - .iter() - .flat_map(|s| s.set_config.reserved_nodes.iter()) - { - imp_p.insert(reserved.peer_id); - } - imp_p.shrink_to_fit(); - 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) = { @@ -326,44 +168,17 @@ where ) }; - 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)), pending_messages: VecDeque::new(), - roles, - peers: HashMap::new(), - chain, - 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 + - 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: 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 { - Some(Metrics::register(r)?) - } else { - None - }, - boot_node_ids, - block_announce_data_cache, + peers: HashMap::new(), + // TODO: remove when `BlockAnnouncesHandshake` is moved away from `Protocol` + _marker: Default::default(), }; Ok((protocol, peerset_handle, known_addresses)) @@ -384,6 +199,7 @@ where if let Some(position) = self.notification_protocols.iter().position(|p| *p == protocol_name) { self.behaviour.disconnect_peer(peer_id, sc_peerset::SetId::from(position)); + self.peers.remove(peer_id); } else { warn!(target: "sub-libp2p", "disconnect_peer() with invalid protocol name") } @@ -399,391 +215,23 @@ where self.peers.len() } - /// Returns the number of peers we're connected to and that are being queried. - pub fn num_active_peers(&self) -> usize { - self.chain_sync.num_active_peers() - } - - /// Current global sync state. - pub fn sync_state(&self) -> SyncStatus { - self.chain_sync.status() - } - - /// Target sync block number. - pub fn best_seen_block(&self) -> Option> { - self.chain_sync.status().best_seen_block - } - - /// Number of peers participating in syncing. - pub fn num_sync_peers(&self) -> u32 { - self.chain_sync.status().num_peers - } - - /// Number of blocks in the import queue. - pub fn num_queued_blocks(&self) -> u32 { - self.chain_sync.status().queued_blocks - } - - /// Number of downloaded blocks. - pub fn num_downloaded_blocks(&self) -> usize { - self.chain_sync.num_downloaded_blocks() - } - - /// Number of active sync requests. - pub fn num_sync_requests(&self) -> usize { - 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.chain_sync.update_chain_info(&hash, number); - - self.behaviour.set_notif_protocol_handshake( - HARDCODED_PEERSETS_SYNC, - BlockAnnouncesHandshake::::build(self.roles, number, hash, self.genesis_hash) - .encode(), - ); - } - - fn update_peer_info(&mut self, who: &PeerId) { - if let Some(info) = self.chain_sync.peer_info(who) { - if let Some(ref mut peer) = self.peers.get_mut(who) { - peer.info.best_hash = info.best_hash; - peer.info.best_number = info.best_number; - } - } - } - - /// Returns information about all the peers we are connected to after the handshake message. - pub fn peers_info(&self) -> impl Iterator)> { - self.peers.iter().map(|(id, peer)| (id, &peer.info)) - } - - /// Called by peer when it is disconnecting. - /// - /// Returns a result if the handshake of this peer was indeed accepted. - pub fn on_sync_peer_disconnected(&mut self, peer: PeerId) -> Result<(), ()> { - if self.important_peers.contains(&peer) { - warn!(target: "sync", "Reserved peer {} disconnected", peer); - } else { - debug!(target: "sync", "{} disconnected", peer); - } - - if let Some(_peer_data) = self.peers.remove(&peer) { - self.chain_sync.peer_disconnected(&peer); - self.default_peers_set_no_slot_connected_peers.remove(&peer); - Ok(()) - } else { - Err(()) - } - } - /// Adjusts the reputation of a node. pub fn report_peer(&self, who: PeerId, reputation: sc_peerset::ReputationChange) { self.peerset_handle.report_peer(who, reputation) } - /// Perform time based maintenance. - /// - /// > **Note**: This method normally doesn't have to be called except for testing purposes. - pub fn tick(&mut self) { - self.report_metrics() - } - - /// Called on the first connection between two peers on the default set, after their exchange - /// of handshake. - /// - /// Returns `Ok` if the handshake is accepted and the peer added to the list of peers we sync - /// from. - fn on_sync_peer_connected( - &mut self, - who: PeerId, - status: BlockAnnouncesHandshake, - ) -> Result<(), ()> { - trace!(target: "sync", "New peer {} {:?}", who, status); - - if self.peers.contains_key(&who) { - error!(target: "sync", "Called on_sync_peer_connected with already connected peer {}", who); - debug_assert!(false); - return Err(()) - } - - if status.genesis_hash != self.genesis_hash { - log!( - target: "sync", - if self.important_peers.contains(&who) { Level::Warn } else { Level::Debug }, - "Peer is on different chain (our genesis: {} theirs: {})", - self.genesis_hash, status.genesis_hash - ); - self.peerset_handle.report_peer(who, rep::GENESIS_MISMATCH); - self.behaviour.disconnect_peer(&who, HARDCODED_PEERSETS_SYNC); - - if self.boot_node_ids.contains(&who) { - error!( - target: "sync", - "Bootnode with peer id `{}` is on a different chain (our genesis: {} theirs: {})", - who, - self.genesis_hash, - status.genesis_hash, - ); - } - - return Err(()) - } - - 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); - self.peerset_handle.report_peer(who, rep::BAD_ROLE); - self.behaviour.disconnect_peer(&who, HARDCODED_PEERSETS_SYNC); - return Err(()) - } - - // we don't interested in peers that are far behind us - let self_best_block = self.chain.info().best_number; - let blocks_difference = self_best_block - .checked_sub(&status.best_number) - .unwrap_or_else(Zero::zero) - .saturated_into::(); - if blocks_difference > LIGHT_MAXIMAL_BLOCKS_DIFFERENCE { - debug!(target: "sync", "Peer {} is far behind us and will unable to serve light requests", who); - self.peerset_handle.report_peer(who, rep::PEER_BEHIND_US_LIGHT); - self.behaviour.disconnect_peer(&who, HARDCODED_PEERSETS_SYNC); - return Err(()) - } - } - - 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); - return Err(()) - } - - if status.roles.is_light() && - (self.peers.len() - self.chain_sync.num_peers()) >= self.default_peers_set_num_light - { - // Make sure that not all slots are occupied by light clients. - 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, - best_hash: status.best_hash, - best_number: status.best_number, - }, - known_blocks: LruHashSet::new( - NonZeroUsize::new(MAX_KNOWN_BLOCKS).expect("Constant is nonzero"), - ), - }; - - let req = if peer.info.roles.is_full() { - 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); - self.peerset_handle.report_peer(id, repu); - return Err(()) - }, - } + /// Set handshake for the notification protocol. + pub fn set_notification_handshake(&mut self, protocol: ProtocolName, handshake: Vec) { + if let Some(index) = self.notification_protocols.iter().position(|p| *p == protocol) { + self.behaviour + .set_notif_protocol_handshake(sc_peerset::SetId::from(index), handshake); } else { - None - }; - - 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)); - - if let Some(req) = req { - self.chain_sync.send_block_request(who, req); - } - - Ok(()) - } - - /// 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. - pub fn announce_block(&mut self, hash: B::Hash, data: Option>) { - let header = match self.chain.header(hash) { - Ok(Some(header)) => header, - Ok(None) => { - warn!("Trying to announce unknown block: {}", hash); - return - }, - Err(e) => { - warn!("Error reading block header {}: {}", hash, e); - return - }, - }; - - // don't announce genesis block since it will be ignored - if header.number().is_zero() { - return - } - - let is_best = self.chain.info().best_hash == hash; - debug!(target: "sync", "Reannouncing block {:?} is_best: {}", hash, is_best); - - let data = data - .or_else(|| self.block_announce_data_cache.get(&hash).cloned()) - .unwrap_or_default(); - - for (who, ref mut peer) in self.peers.iter_mut() { - let inserted = peer.known_blocks.insert(hash); - if inserted { - trace!(target: "sync", "Announcing block {:?} to {}", hash, who); - let message = BlockAnnounce { - header: header.clone(), - state: if is_best { Some(BlockState::Best) } else { Some(BlockState::Normal) }, - data: Some(data.clone()), - }; - - self.behaviour - .write_notification(who, HARDCODED_PEERSETS_SYNC, message.encode()); - } - } - } - - /// Push a block announce validation. - /// - /// It is required that [`ChainSync::poll_block_announce_validation`] is - /// called later to check for finished validations. The result of the validation - /// needs to be passed to [`Protocol::process_block_announce_validation_result`] - /// to finish the processing. - /// - /// # Note - /// - /// This will internally create a future, but this future will not be registered - /// in the task before being polled once. So, it is required to call - /// [`ChainSync::poll_block_announce_validation`] to ensure that the future is - /// registered properly and will wake up the task when being ready. - fn push_block_announce_validation(&mut self, who: PeerId, announce: BlockAnnounce) { - let hash = announce.header.hash(); - - let peer = match self.peers.get_mut(&who) { - Some(p) => p, - None => { - log::error!(target: "sync", "Received block announce from disconnected peer {}", who); - debug_assert!(false); - return - }, - }; - - peer.known_blocks.insert(hash); - - let is_best = match announce.state.unwrap_or(BlockState::Best) { - BlockState::Best => true, - BlockState::Normal => false, - }; - - if peer.info.roles.is_full() { - self.chain_sync.push_block_announce_validation(who, hash, announce, is_best); - } - } - - /// Process the result of the block announce validation. - fn process_block_announce_validation_result( - &mut self, - validation_result: PollBlockAnnounceValidation, - ) -> CustomMessageOutcome { - let (header, is_best, who) = match validation_result { - PollBlockAnnounceValidation::Skip => return CustomMessageOutcome::None, - PollBlockAnnounceValidation::Nothing { is_best, who, announce } => { - self.update_peer_info(&who); - - if let Some(data) = announce.data { - if !data.is_empty() { - self.block_announce_data_cache.put(announce.header.hash(), data); - } - } - - // `on_block_announce` returns `OnBlockAnnounce::ImportHeader` - // when we have all data required to import the block - // in the BlockAnnounce message. This is only when: - // 1) we're on light client; - // AND - // 2) parent block is already imported and not pruned. - if is_best { - return CustomMessageOutcome::PeerNewBest(who, *announce.header.number()) - } else { - return CustomMessageOutcome::None - } - }, - PollBlockAnnounceValidation::ImportHeader { announce, is_best, who } => { - self.update_peer_info(&who); - - if let Some(data) = announce.data { - if !data.is_empty() { - self.block_announce_data_cache.put(announce.header.hash(), data); - } - } - - (announce.header, is_best, who) - }, - PollBlockAnnounceValidation::Failure { who, disconnect } => { - if disconnect { - self.behaviour.disconnect_peer(&who, HARDCODED_PEERSETS_SYNC); - } - - self.report_peer(who, rep::BAD_BLOCK_ANNOUNCEMENT); - return CustomMessageOutcome::None - }, - }; - - let number = *header.number(); - - // 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.chain_sync.on_block_data( - &who, - None, - BlockResponse:: { - id: 0, - blocks: vec![BlockData:: { - hash: header.hash(), - header: Some(header), - body: None, - indexed_body: None, - receipt: None, - message_queue: None, - justification: None, - justifications: None, - }], - }, - ); - self.chain_sync.process_block_response_data(blocks_to_import); - - if is_best { - self.pending_messages.push_back(CustomMessageOutcome::PeerNewBest(who, number)); + error!( + target: "sub-libp2p", + "set_notification_handshake with unknown protocol: {}", + protocol + ); } - - CustomMessageOutcome::None - } - - /// 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.chain_sync.on_block_finalized(&hash, *header.number()) } /// Set whether the syncing peers set is in reserved-only mode. @@ -884,41 +332,12 @@ where ); } } - - 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.chain_sync.metrics(); - - metrics.fork_targets.set(m.fork_targets.into()); - metrics.queued_blocks.set(m.queued_blocks.into()); - - metrics - .justifications - .with_label_values(&["pending"]) - .set(m.justifications.pending_requests.into()); - metrics - .justifications - .with_label_values(&["active"]) - .set(m.justifications.active_requests.into()); - metrics - .justifications - .with_label_values(&["failed"]) - .set(m.justifications.failed_requests.into()); - metrics - .justifications - .with_label_values(&["importing"]) - .set(m.justifications.importing_requests.into()); - } - } } /// Outcome of an incoming custom message. #[derive(Debug)] #[must_use] -pub enum CustomMessageOutcome { +pub enum CustomMessageOutcome { /// Notification protocols have been opened with a remote. NotificationStreamOpened { remote: PeerId, @@ -926,6 +345,7 @@ pub enum CustomMessageOutcome { /// See [`crate::Event::NotificationStreamOpened::negotiated_fallback`]. negotiated_fallback: Option, roles: Roles, + received_handshake: Vec, notifications_sink: NotificationsSink, }, /// The [`NotificationsSink`] of some notification protocols need an update. @@ -935,31 +355,16 @@ pub enum CustomMessageOutcome { notifications_sink: NotificationsSink, }, /// Notification protocols have been closed with a remote. - NotificationStreamClosed { - remote: PeerId, - protocol: ProtocolName, - }, + NotificationStreamClosed { remote: PeerId, protocol: ProtocolName }, /// Messages have been received on one or more notifications protocols. - NotificationsReceived { - remote: PeerId, - messages: Vec<(ProtocolName, Bytes)>, - }, - /// Peer has a reported a new head of chain. - PeerNewBest(PeerId, NumberFor), + NotificationsReceived { remote: PeerId, messages: Vec<(ProtocolName, Bytes)> }, /// Now connected to a new peer for syncing purposes. - SyncConnected(PeerId), - /// No longer connected to a peer for syncing purposes. - SyncDisconnected(PeerId), None, } -impl NetworkBehaviour for Protocol -where - B: BlockT, - Client: HeaderBackend + 'static, -{ +impl NetworkBehaviour for Protocol { type ConnectionHandler = ::ConnectionHandler; - type OutEvent = CustomMessageOutcome; + type OutEvent = CustomMessageOutcome; fn new_handler(&mut self) -> Self::ConnectionHandler { self.behaviour.new_handler() @@ -994,25 +399,6 @@ where return Poll::Ready(NetworkBehaviourAction::GenerateEvent(message)) } - // 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), - } - } - - 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)) - } - let event = match self.behaviour.poll(cx, params) { Poll::Pending => return Poll::Pending, Poll::Ready(NetworkBehaviourAction::GenerateEvent(ev)) => ev, @@ -1045,17 +431,22 @@ where // announces substream. match as DecodeAll>::decode_all(&mut &received_handshake[..]) { Ok(GenericMessage::Status(handshake)) => { - let handshake = BlockAnnouncesHandshake { + let roles = handshake.roles; + let handshake = BlockAnnouncesHandshake:: { roles: handshake.roles, best_number: handshake.best_number, best_hash: handshake.best_hash, genesis_hash: handshake.genesis_hash, }; + self.peers.insert(peer_id, roles); - if self.on_sync_peer_connected(peer_id, handshake).is_ok() { - CustomMessageOutcome::SyncConnected(peer_id) - } else { - CustomMessageOutcome::None + CustomMessageOutcome::NotificationStreamOpened { + remote: peer_id, + protocol: self.notification_protocols[usize::from(set_id)].clone(), + negotiated_fallback, + received_handshake: handshake.encode(), + roles, + notifications_sink, } }, Ok(msg) => { @@ -1073,14 +464,21 @@ where &mut &received_handshake[..], ) { Ok(handshake) => { - if self.on_sync_peer_connected(peer_id, handshake).is_ok() { - CustomMessageOutcome::SyncConnected(peer_id) - } else { - CustomMessageOutcome::None + let roles = handshake.roles; + self.peers.insert(peer_id, roles); + + CustomMessageOutcome::NotificationStreamOpened { + remote: peer_id, + protocol: self.notification_protocols[usize::from(set_id)] + .clone(), + negotiated_fallback, + received_handshake, + roles, + notifications_sink, } }, Err(err2) => { - debug!( + log::debug!( target: "sync", "Couldn't decode handshake sent by {}: {:?}: {} & {}", peer_id, @@ -1104,9 +502,10 @@ where protocol: self.notification_protocols[usize::from(set_id)].clone(), negotiated_fallback, roles, + received_handshake, notifications_sink, }, - (Err(_), Some(peer)) if received_handshake.is_empty() => { + (Err(_), Some(roles)) if received_handshake.is_empty() => { // As a convenience, we allow opening substreams for "external" // notification protocols with an empty handshake. This fetches the // roles from the locally-known roles. @@ -1115,7 +514,8 @@ where remote: peer_id, protocol: self.notification_protocols[usize::from(set_id)].clone(), negotiated_fallback, - roles: peer.info.roles, + roles: *roles, + received_handshake, notifications_sink, } }, @@ -1124,15 +524,14 @@ where self.bad_handshake_substreams.insert((peer_id, set_id)); self.behaviour.disconnect_peer(&peer_id, set_id); self.peerset_handle.report_peer(peer_id, rep::BAD_MESSAGE); + self.peers.remove(&peer_id); CustomMessageOutcome::None }, } } }, NotificationsOut::CustomProtocolReplaced { peer_id, notifications_sink, set_id } => - if set_id == HARDCODED_PEERSETS_SYNC || - self.bad_handshake_substreams.contains(&(peer_id, set_id)) - { + if self.bad_handshake_substreams.contains(&(peer_id, set_id)) { CustomMessageOutcome::None } else { CustomMessageOutcome::NotificationStreamReplaced { @@ -1142,19 +541,7 @@ where } }, NotificationsOut::CustomProtocolClosed { peer_id, set_id } => { - // Set number 0 is hardcoded the default set of peers we sync from. - if set_id == HARDCODED_PEERSETS_SYNC { - if self.on_sync_peer_disconnected(peer_id).is_ok() { - CustomMessageOutcome::SyncDisconnected(peer_id) - } else { - log::trace!( - target: "sync", - "Disconnected peer which had earlier been refused by on_sync_peer_connected {}", - peer_id - ); - CustomMessageOutcome::None - } - } else if self.bad_handshake_substreams.remove(&(peer_id, set_id)) { + if self.bad_handshake_substreams.remove(&(peer_id, set_id)) { // The substream that has just been closed had been opened with a bad // handshake. The outer layers have never received an opening event about this // substream, and consequently shouldn't receive a closing event either. @@ -1166,45 +553,20 @@ 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) = 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 - // polled once to be registered in the task. - if let Poll::Ready(res) = self.chain_sync.poll_block_announce_validation(cx) - { - self.process_block_announce_validation_result(res) - } else { - CustomMessageOutcome::None - } - } else { - warn!(target: "sub-libp2p", "Failed to decode block announce"); - CustomMessageOutcome::None - } - }, - HARDCODED_PEERSETS_SYNC => { - trace!( - target: "sync", - "Received sync for peer earlier refused by sync layer: {}", - peer_id - ); + NotificationsOut::Notification { peer_id, set_id, message } => { + if self.bad_handshake_substreams.contains(&(peer_id, set_id)) { CustomMessageOutcome::None - }, - _ if self.bad_handshake_substreams.contains(&(peer_id, set_id)) => - CustomMessageOutcome::None, - _ => { + } else { let protocol_name = self.notification_protocols[usize::from(set_id)].clone(); CustomMessageOutcome::NotificationsReceived { remote: peer_id, messages: vec![(protocol_name, message.freeze())], } - }, + } }, }; - if !matches!(outcome, CustomMessageOutcome::::None) { + if !matches!(outcome, CustomMessageOutcome::None) { return Poll::Ready(NetworkBehaviourAction::GenerateEvent(outcome)) } diff --git a/client/network/src/protocol/notifications/behaviour.rs b/client/network/src/protocol/notifications/behaviour.rs index 027ea0ab53136..093d5846db7de 100644 --- a/client/network/src/protocol/notifications/behaviour.rs +++ b/client/network/src/protocol/notifications/behaviour.rs @@ -538,48 +538,6 @@ impl Notifications { self.peerset.reserved_peers(set_id) } - /// Sends a notification to a peer. - /// - /// Has no effect if the custom protocol is not open with the given peer. - /// - /// Also note that even if we have a valid open substream, it may in fact be already closed - /// without us knowing, in which case the packet will not be received. - /// - /// The `fallback` parameter is used for backwards-compatibility reason if the remote doesn't - /// support our protocol. One needs to pass the equivalent of what would have been passed - /// with `send_packet`. - pub fn write_notification( - &mut self, - target: &PeerId, - set_id: sc_peerset::SetId, - message: impl Into>, - ) { - let notifs_sink = match self.peers.get(&(*target, set_id)).and_then(|p| p.get_open()) { - None => { - trace!( - target: "sub-libp2p", - "Tried to sent notification to {:?} without an open channel.", - target, - ); - return - }, - Some(sink) => sink, - }; - - let message = message.into(); - - trace!( - target: "sub-libp2p", - "External API => Notification({:?}, {:?}, {} bytes)", - target, - set_id, - message.len(), - ); - trace!(target: "sub-libp2p", "Handler({:?}) <= Sync notification", target); - - notifs_sink.send_sync_notification(message); - } - /// Returns the state of the peerset manager, for debugging purposes. pub fn peerset_debug_info(&mut self) -> serde_json::Value { self.peerset.debug_info() @@ -3058,7 +3016,13 @@ mod tests { panic!("invalid state"); } - notif.write_notification(&peer, set_id, vec![1, 3, 3, 7]); + notif + .peers + .get(&(peer, set_id)) + .unwrap() + .get_open() + .unwrap() + .send_sync_notification(vec![1, 3, 3, 7]); assert_eq!(conn_yielder.get_next_event(peer, set_id.into()).await, Some(vec![1, 3, 3, 7])); } diff --git a/client/network/src/service.rs b/client/network/src/service.rs index fd0b965b77372..4a05393618cfb 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -34,8 +34,8 @@ use crate::{ network_state::{ NetworkState, NotConnectedPeer as NetworkStateNotConnectedPeer, Peer as NetworkStatePeer, }, - protocol::{self, NotificationsSink, NotifsHandlerError, PeerInfo, Protocol, Ready}, - transport, ChainSyncInterface, ReputationChange, + protocol::{self, NotificationsSink, NotifsHandlerError, Protocol, Ready}, + transport, ReputationChange, }; use futures::{channel::oneshot, prelude::*}; @@ -65,17 +65,16 @@ use sc_network_common::{ request_responses::{IfDisconnected, RequestFailure}, service::{ NetworkDHTProvider, NetworkEventStream, NetworkNotification, NetworkPeers, NetworkSigner, - NetworkStateInfo, NetworkStatus, NetworkStatusProvider, NetworkSyncForkRequest, + NetworkStateInfo, NetworkStatus, NetworkStatusProvider, NotificationSender as NotificationSenderT, NotificationSenderError, NotificationSenderReady as NotificationSenderReadyT, Signature, SigningError, }, - sync::SyncStatus, ExHashT, }; use sc_peerset::PeersetHandle; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; use sp_blockchain::HeaderBackend; -use sp_runtime::traits::{Block as BlockT, NumberFor, Zero}; +use sp_runtime::traits::{Block as BlockT, Zero}; use std::{ cmp, collections::{HashMap, HashSet}, @@ -85,7 +84,7 @@ use std::{ pin::Pin, str, sync::{ - atomic::{AtomicBool, AtomicUsize, Ordering}, + atomic::{AtomicUsize, Ordering}, Arc, }, }; @@ -98,7 +97,7 @@ mod out_events; mod tests; pub use libp2p::identity::{error::DecodingError, Keypair, PublicKey}; -use sc_network_common::service::{NetworkBlock, NetworkRequest}; +use sc_network_common::service::NetworkRequest; /// Custom error that can be produced by the [`ConnectionHandler`] of the [`NetworkBehaviour`]. /// Used as a template parameter of [`SwarmEvent`] below. @@ -114,8 +113,6 @@ pub struct NetworkService { external_addresses: Arc>>, /// Listen addresses. Do **NOT** include a trailing `/p2p/` with our `PeerId`. listen_addresses: Arc>>, - /// Are we actively catching up with the chain? - 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. @@ -126,9 +123,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>, - /// Interface that can be used to delegate calls to `ChainSync` - chain_sync_service: Box>, + 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>>, @@ -138,20 +133,23 @@ pub struct NetworkService { /// Marker to pin the `H` generic. Serves no purpose except to not break backwards /// compatibility. _marker: PhantomData, + /// Marker for block type + _block: PhantomData, } -impl NetworkWorker +impl NetworkWorker where B: BlockT + 'static, H: ExHashT, - Client: HeaderBackend + '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 + 'static>( + 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(); @@ -230,10 +228,7 @@ where let (protocol, peerset_handle, mut known_addresses) = Protocol::new( From::from(¶ms.role), - params.chain.clone(), ¶ms.network_config, - params.metrics_registry.as_ref(), - params.chain_sync, params.block_announce_config, )?; @@ -268,10 +263,9 @@ where })?; let num_connected = Arc::new(AtomicUsize::new(0)); - let is_major_syncing = Arc::new(AtomicBool::new(false)); // Build the swarm. - let (mut swarm, bandwidth): (Swarm>, _) = { + let (mut swarm, bandwidth): (Swarm>, _) = { let user_agent = format!( "{} ({})", params.network_config.client_version, params.network_config.node_name @@ -418,7 +412,6 @@ where registry, MetricSources { bandwidth: bandwidth.clone(), - major_syncing: is_major_syncing.clone(), connected_peers: num_connected.clone(), }, )?), @@ -427,14 +420,14 @@ where // 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( + Swarm::>::add_external_address( &mut swarm, addr.clone(), AddressScore::Infinite, @@ -450,24 +443,22 @@ where external_addresses: external_addresses.clone(), listen_addresses: listen_addresses.clone(), num_connected: num_connected.clone(), - is_major_syncing: is_major_syncing.clone(), peerset: peerset_handle, 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() .map(|metrics| metrics.notifications_sizes.clone()), _marker: PhantomData, + _block: Default::default(), }); Ok(NetworkWorker { external_addresses, listen_addresses, num_connected, - is_major_syncing, network_service: swarm, service, from_service, @@ -476,22 +467,16 @@ where metrics, boot_node_ids, _marker: Default::default(), + _block: Default::default(), }) } /// High-level network status information. - pub fn status(&self) -> NetworkStatus { - let status = self.sync_state(); + pub fn status(&self) -> NetworkStatus { NetworkStatus { - sync_state: status.state, - best_seen_block: self.best_seen_block(), - num_sync_peers: self.num_sync_peers(), num_connected_peers: self.num_connected_peers(), - num_active_peers: self.num_active_peers(), total_bytes_inbound: self.total_bytes_inbound(), total_bytes_outbound: self.total_bytes_outbound(), - state_sync: status.state_sync, - warp_sync: status.warp_sync, } } @@ -510,42 +495,7 @@ where self.network_service.behaviour().user_protocol().num_connected_peers() } - /// Returns the number of peers we're connected to and that are being queried. - pub fn num_active_peers(&self) -> usize { - self.network_service.behaviour().user_protocol().num_active_peers() - } - - /// Current global sync state. - pub fn sync_state(&self) -> SyncStatus { - self.network_service.behaviour().user_protocol().sync_state() - } - - /// Target sync block number. - pub fn best_seen_block(&self) -> Option> { - self.network_service.behaviour().user_protocol().best_seen_block() - } - - /// Number of peers participating in syncing. - pub fn num_sync_peers(&self) -> u32 { - self.network_service.behaviour().user_protocol().num_sync_peers() - } - - /// Number of blocks in the import queue. - pub fn num_queued_blocks(&self) -> u32 { - self.network_service.behaviour().user_protocol().num_queued_blocks() - } - - /// Returns the number of downloaded blocks. - pub fn num_downloaded_blocks(&self) -> usize { - self.network_service.behaviour().user_protocol().num_downloaded_blocks() - } - - /// Number of active sync requests. - pub fn num_sync_requests(&self) -> usize { - self.network_service.behaviour().user_protocol().num_sync_requests() - } - - /// Adds an address known to a node. + /// Adds an address for a node. pub fn add_known_address(&mut self, peer_id: PeerId, addr: Multiaddr) { self.network_service.behaviour_mut().add_known_address(peer_id, addr); } @@ -556,32 +506,16 @@ where &self.service } - /// You must call this when a new block is finalized by the client. - pub fn on_block_finalized(&mut self, hash: B::Hash, header: B::Header) { - self.network_service - .behaviour_mut() - .user_protocol_mut() - .on_block_finalized(hash, &header); - } - - /// Inform the network service about new best imported block. - pub fn new_best_block_imported(&mut self, hash: B::Hash, number: NumberFor) { - self.network_service - .behaviour_mut() - .user_protocol_mut() - .new_best_block_imported(hash, number); - } - /// 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. @@ -661,7 +595,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(); @@ -675,16 +609,6 @@ where } } - /// Get currently connected peers. - pub fn peers_debug_info(&mut self) -> Vec<(PeerId, PeerInfo)> { - self.network_service - .behaviour_mut() - .user_protocol_mut() - .peers_info() - .map(|(id, info)| (*id, info.clone())) - .collect() - } - /// Removes a `PeerId` from the list of reserved peers. pub fn remove_reserved_peer(&self, peer: PeerId) { self.service.remove_reserved_peer(peer); @@ -722,20 +646,6 @@ impl NetworkService { } } - /// Get connected peers debug information. - /// - /// Returns an error if the `NetworkWorker` is no longer running. - pub async fn peers_debug_info(&self) -> Result)>, ()> { - let (tx, rx) = oneshot::channel(); - - let _ = self - .to_worker - .unbounded_send(ServiceToWorkerMsg::PeersDebugInfo { pending_response: tx }); - - // The channel can only be closed if the network worker no longer exists. - rx.await.map_err(|_| ()) - } - /// Get the list of reserved peers. /// /// Returns an error if the `NetworkWorker` is no longer running. @@ -779,30 +689,6 @@ impl NetworkService { } } -impl sp_consensus::SyncOracle for NetworkService { - fn is_major_syncing(&self) -> bool { - self.is_major_syncing.load(Ordering::Relaxed) - } - - 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. - fn request_justification(&self, hash: &B::Hash, number: NumberFor) { - let _ = self.chain_sync_service.request_justification(hash, number); - } - - fn clear_justification_requests(&self) { - let _ = self.chain_sync_service.clear_justification_requests(); - } -} - impl NetworkStateInfo for NetworkService where B: sp_runtime::traits::Block, @@ -856,29 +742,13 @@ where } } -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) { - self.chain_sync_service.set_sync_fork_request(peers, hash, number); - } -} - #[async_trait::async_trait] -impl NetworkStatusProvider for NetworkService +impl NetworkStatusProvider for NetworkService where B: BlockT + 'static, H: ExHashT, { - async fn status(&self) -> Result, ()> { + async fn status(&self) -> Result { let (tx, rx) = oneshot::channel(); let _ = self @@ -1125,6 +995,12 @@ where Ok(Box::new(NotificationSender { sink, protocol_name: protocol, notification_size_metric })) } + + fn set_notification_handshake(&self, protocol: ProtocolName, handshake: Vec) { + let _ = self + .to_worker + .unbounded_send(ServiceToWorkerMsg::SetNotificationHandshake(protocol, handshake)); + } } #[async_trait::async_trait] @@ -1171,22 +1047,6 @@ where } } -impl NetworkBlock> for NetworkService -where - B: BlockT + 'static, - H: ExHashT, -{ - fn announce_block(&self, hash: B::Hash, data: Option>) { - let _ = self.to_worker.unbounded_send(ServiceToWorkerMsg::AnnounceBlock(hash, data)); - } - - fn new_best_block_imported(&self, hash: B::Hash, number: NumberFor) { - let _ = self - .to_worker - .unbounded_send(ServiceToWorkerMsg::NewBestBlockImported(hash, number)); - } -} - /// A `NotificationSender` allows for sending notifications to a peer with a chosen protocol. #[must_use] pub struct NotificationSender { @@ -1257,8 +1117,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 { - AnnounceBlock(B::Hash, Option>), +enum ServiceToWorkerMsg { GetValue(KademliaKey), PutValue(KademliaKey, Vec), AddKnownAddress(PeerId, Multiaddr), @@ -1280,16 +1139,13 @@ enum ServiceToWorkerMsg { connect: IfDisconnected, }, NetworkStatus { - pending_response: oneshot::Sender, RequestFailure>>, + pending_response: oneshot::Sender>, }, NetworkState { pending_response: oneshot::Sender>, }, DisconnectPeer(PeerId, ProtocolName), - NewBestBlockImported(B::Hash, NumberFor), - PeersDebugInfo { - pending_response: oneshot::Sender)>>, - }, + SetNotificationHandshake(ProtocolName, Vec), ReservedPeers { pending_response: oneshot::Sender>, }, @@ -1299,11 +1155,10 @@ 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 + 'static, { /// Updated by the `NetworkWorker` and loaded by the `NetworkService`. external_addresses: Arc>>, @@ -1311,14 +1166,12 @@ where listen_addresses: Arc>>, /// Updated by the `NetworkWorker` and loaded by the `NetworkService`. num_connected: Arc, - /// Updated by the `NetworkWorker` and loaded by the `NetworkService`. - is_major_syncing: Arc, /// The network service that can be extracted and shared through the codebase. service: Arc>, /// The *actual* network. - network_service: Swarm>, + network_service: Swarm>, /// 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. @@ -1331,13 +1184,14 @@ where /// Marker to pin the `H` generic. Serves no purpose except to not break backwards /// compatibility. _marker: PhantomData, + /// Marker for block type + _block: PhantomData, } -impl NetworkWorker +impl NetworkWorker where B: BlockT + 'static, H: ExHashT, - Client: HeaderBackend + 'static, { /// Run the network. pub async fn run(mut self) { @@ -1364,10 +1218,9 @@ where }, }; + // Update the variables shared with the `NetworkService`. let num_connected_peers = self.network_service.behaviour_mut().user_protocol_mut().num_connected_peers(); - - // Update the variables shared with the `NetworkService`. self.num_connected.store(num_connected_peers, Ordering::Relaxed); { let external_addresses = @@ -1379,16 +1232,6 @@ where *self.listen_addresses.lock() = listen_addresses; } - let is_major_syncing = self - .network_service - .behaviour_mut() - .user_protocol_mut() - .sync_state() - .state - .is_major_syncing(); - - self.is_major_syncing.store(is_major_syncing, Ordering::Relaxed); - if let Some(metrics) = self.metrics.as_ref() { if let Some(buckets) = self.network_service.behaviour_mut().num_entries_per_kbucket() { for (lower_ilog2_bucket_bound, num_entries) in buckets { @@ -1420,13 +1263,8 @@ where } /// Process the next message coming from the `NetworkService`. - fn handle_worker_message(&mut self, msg: ServiceToWorkerMsg) { + fn handle_worker_message(&mut self, msg: ServiceToWorkerMsg) { match msg { - ServiceToWorkerMsg::AnnounceBlock(hash, data) => self - .network_service - .behaviour_mut() - .user_protocol_mut() - .announce_block(hash, data), ServiceToWorkerMsg::GetValue(key) => self.network_service.behaviour_mut().get_value(key), ServiceToWorkerMsg::PutValue(key, value) => @@ -1505,14 +1343,11 @@ where .behaviour_mut() .user_protocol_mut() .disconnect_peer(&who, protocol_name), - ServiceToWorkerMsg::NewBestBlockImported(hash, number) => self + ServiceToWorkerMsg::SetNotificationHandshake(protocol, handshake) => self .network_service .behaviour_mut() .user_protocol_mut() - .new_best_block_imported(hash, number), - ServiceToWorkerMsg::PeersDebugInfo { pending_response } => { - let _ = pending_response.send(self.peers_debug_info()); - }, + .set_notification_handshake(protocol, handshake), ServiceToWorkerMsg::ReservedPeers { pending_response } => { let _ = pending_response.send(self.reserved_peers().map(ToOwned::to_owned).collect()); @@ -1523,7 +1358,7 @@ where /// Process the next event coming from `Swarm`. fn handle_swarm_event( &mut self, - event: SwarmEvent>>, + event: SwarmEvent>>, ) { match event { SwarmEvent::Behaviour(BehaviourOut::InboundRequest { protocol, result, .. }) => { @@ -1642,6 +1477,7 @@ where negotiated_fallback, notifications_sink, role, + received_handshake, }) => { if let Some(metrics) = self.metrics.as_ref() { metrics @@ -1660,6 +1496,7 @@ where protocol, negotiated_fallback, role, + received_handshake, }); }, SwarmEvent::Behaviour(BehaviourOut::NotificationStreamReplaced { @@ -1725,12 +1562,6 @@ where } self.event_streams.send(Event::NotificationsReceived { remote, messages }); }, - SwarmEvent::Behaviour(BehaviourOut::SyncConnected(remote)) => { - self.event_streams.send(Event::SyncConnected { remote }); - }, - SwarmEvent::Behaviour(BehaviourOut::SyncDisconnected(remote)) => { - self.event_streams.send(Event::SyncDisconnected { remote }); - }, SwarmEvent::Behaviour(BehaviourOut::Dht(event, duration)) => { if let Some(metrics) = self.metrics.as_ref() { let query_type = match event { @@ -1925,11 +1756,10 @@ where } } -impl Unpin for NetworkWorker +impl Unpin for NetworkWorker where B: BlockT + 'static, H: ExHashT, - Client: HeaderBackend + 'static, { } diff --git a/client/network/src/service/metrics.rs b/client/network/src/service/metrics.rs index ccb440b2c3e1a..13bc4b4e7aff8 100644 --- a/client/network/src/service/metrics.rs +++ b/client/network/src/service/metrics.rs @@ -24,7 +24,7 @@ use prometheus_endpoint::{ use std::{ str, sync::{ - atomic::{AtomicBool, AtomicUsize, Ordering}, + atomic::{AtomicUsize, Ordering}, Arc, }, }; @@ -34,7 +34,6 @@ pub use prometheus_endpoint::{Histogram, HistogramVec}; /// Registers all networking metrics with the given registry. pub fn register(registry: &Registry, sources: MetricSources) -> Result { BandwidthCounters::register(registry, sources.bandwidth)?; - MajorSyncingGauge::register(registry, sources.major_syncing)?; NumConnectedGauge::register(registry, sources.connected_peers)?; Metrics::register(registry) } @@ -42,7 +41,6 @@ pub fn register(registry: &Registry, sources: MetricSources) -> Result, - pub major_syncing: Arc, pub connected_peers: Arc, } @@ -266,37 +264,6 @@ impl MetricSource for BandwidthCounters { } } -/// The "major syncing" metric. -#[derive(Clone)] -pub struct MajorSyncingGauge(Arc); - -impl MajorSyncingGauge { - /// Registers the `MajorSyncGauge` metric whose value is - /// obtained from the given `AtomicBool`. - fn register(registry: &Registry, value: Arc) -> Result<(), PrometheusError> { - prometheus::register( - SourcedGauge::new( - &Opts::new( - "substrate_sub_libp2p_is_major_syncing", - "Whether the node is performing a major sync or not.", - ), - MajorSyncingGauge(value), - )?, - registry, - )?; - - Ok(()) - } -} - -impl MetricSource for MajorSyncingGauge { - type N = u64; - - fn collect(&self, mut set: impl FnMut(&[&str], Self::N)) { - set(&[], self.0.load(Ordering::Relaxed) as u64); - } -} - /// The connected peers metric. #[derive(Clone)] pub struct NumConnectedGauge(Arc); diff --git a/client/network/src/service/out_events.rs b/client/network/src/service/out_events.rs index 99ac022c2d8b6..3771ea1643aec 100644 --- a/client/network/src/service/out_events.rs +++ b/client/network/src/service/out_events.rs @@ -268,12 +268,6 @@ impl Metrics { Event::Dht(_) => { self.events_total.with_label_values(&["dht", "sent", name]).inc(); }, - Event::SyncConnected { .. } => { - self.events_total.with_label_values(&["sync-connected", "sent", name]).inc(); - }, - Event::SyncDisconnected { .. } => { - self.events_total.with_label_values(&["sync-disconnected", "sent", name]).inc(); - }, Event::NotificationStreamOpened { protocol, .. } => { format_label("notif-open-", protocol, |protocol_label| { self.events_total.with_label_values(&[protocol_label, "sent", name]).inc(); @@ -301,14 +295,6 @@ impl Metrics { Event::Dht(_) => { self.events_total.with_label_values(&["dht", "received", name]).inc(); }, - Event::SyncConnected { .. } => { - self.events_total.with_label_values(&["sync-connected", "received", name]).inc(); - }, - Event::SyncDisconnected { .. } => { - self.events_total - .with_label_values(&["sync-disconnected", "received", name]) - .inc(); - }, Event::NotificationStreamOpened { protocol, .. } => { format_label("notif-open-", protocol, |protocol_label| { self.events_total.with_label_values(&[protocol_label, "received", name]).inc(); diff --git a/client/network/src/service/tests/chain_sync.rs b/client/network/src/service/tests/chain_sync.rs deleted file mode 100644 index a369b71748974..0000000000000 --- a/client/network/src/service/tests/chain_sync.rs +++ /dev/null @@ -1,420 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use crate::{ - config, - service::tests::{TestNetworkBuilder, BLOCK_ANNOUNCE_PROTO_NAME}, -}; - -use futures::prelude::*; -use libp2p::PeerId; -use sc_block_builder::BlockBuilderProvider; -use sc_client_api::HeaderBackend; -use sc_consensus::JustificationSyncLink; -use sc_network_common::{ - config::{MultiaddrWithPeerId, ProtocolId, SetConfig}, - protocol::{event::Event, role::Roles, ProtocolName}, - service::NetworkSyncForkRequest, - sync::{SyncState, SyncStatus}, -}; -use sc_network_sync::{mock::MockChainSync, service::mock::MockChainSyncInterface, ChainSync}; -use sp_core::H256; -use sp_runtime::traits::{Block as BlockT, Header as _}; -use std::{ - sync::{Arc, RwLock}, - task::Poll, - time::Duration, -}; -use substrate_test_runtime_client::{TestClientBuilder, TestClientBuilderExt as _}; - -fn set_default_expecations_no_peers( - chain_sync: &mut MockChainSync, -) { - chain_sync.expect_poll().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, - }); -} - -#[tokio::test] -async fn normal_network_poll_no_peers() { - // 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 set no expecations for it (i.e., it cannot be - // called) - let chain_sync_service = - Box::new(MockChainSyncInterface::::new()); - - let mut network = TestNetworkBuilder::new() - .with_chain_sync((chain_sync, chain_sync_service)) - .build(); - - // perform one action on network - let _ = network.network().next_action().await; -} - -#[tokio::test] -async fn request_justification() { - let hash = H256::random(); - let number = 1337u64; - - // 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() - .with_chain_sync((Box::new(chain_sync), chain_sync_service)) - .build(); - - // send "request justifiction" message and poll the network - network.service().request_justification(&hash, number); - - // perform one action on network - let _ = network.network().next_action().await; -} - -#[tokio::test] -async fn clear_justification_requests() { - // build `ChainSyncInterface` provider and expect - // `JustificationSyncLink::clear_justification_requests()` to be called - let mut chain_sync_service = - Box::new(MockChainSyncInterface::::new()); - - 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()); - - set_default_expecations_no_peers(&mut chain_sync); - 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(); - - // perform one action on network - let _ = network.network().next_action().await; -} - -#[tokio::test] -async fn set_sync_fork_request() { - // 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_service - .expect_set_sync_fork_request() - .withf(move |in_peers, in_hash, in_number| { - &peers == in_peers && &hash == in_hash && &number == in_number - }) - .once() - .returning(|_, _, _| ()); - - 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); - - // perform one action on network - let _ = network.network().next_action().await; -} - -#[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 - // 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()); - - let at = client.header(client.info().best_hash).unwrap().unwrap().hash(); - let block = client - .new_block_at(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 = 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.network().on_block_finalized(hash, header); - - // perform one action on network - let _ = network.network().next_action().await; -} - -// report from mock import queue that importing a justification was not successful -// and verify that connection to the peer is closed -#[tokio::test] -async fn invalid_justification_imported() { - struct DummyImportQueueHandle; - - impl - sc_consensus::import_queue::ImportQueueService< - substrate_test_runtime_client::runtime::Block, - > for DummyImportQueueHandle - { - 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, - ) { - } - } - - 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, - link: &mut dyn sc_consensus::Link, - ) { - if let Some((peer, hash, number)) = *self.0.read().unwrap() { - 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() - .with_import_queue(Box::new(DummyImportQueue( - justification_info.clone(), - DummyImportQueueHandle {}, - ))) - .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 tokio::time::timeout(Duration::from_secs(5), wait_disconnection).await.is_err() { - panic!("did not receive disconnection event in time"); - } -} - -#[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::())]; - - 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(); - - 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, - None, - chain_sync_network_handle.clone(), - import_queue, - ProtocolName::from("block-request"), - ProtocolName::from("state-request"), - None, - ) - .unwrap(); - - let (node1, mut event_stream1) = TestNetworkBuilder::new() - .with_listen_addresses(vec![listen_addr.clone()]) - .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() - .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 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 3233b15840a2a..3ac7829003f45 100644 --- a/client/network/src/service/tests/mod.rs +++ b/client/network/src/service/tests/mod.rs @@ -16,44 +16,36 @@ // 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 crate::{config, NetworkService, NetworkWorker}; use futures::prelude::*; use libp2p::Multiaddr; -use sc_client_api::{BlockBackend, HeaderBackend}; use sc_consensus::{ImportQueue, Link}; use sc_network_common::{ - config::{ - NonDefaultSetConfig, NonReservedPeerMode, NotificationHandshake, ProtocolId, SetConfig, - TransportConfig, - }, + config::{NonDefaultSetConfig, 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, + engine::SyncingEngine, service::network::{NetworkServiceHandle, NetworkServiceProvider}, state_request_handler::StateRequestHandler, - ChainSync, }; -use sp_runtime::traits::{Block as BlockT, Header as _, Zero}; +use sp_runtime::traits::{Block as BlockT, Header as _}; use std::sync::Arc; use substrate_test_runtime_client::{ runtime::{Block as TestBlock, Hash as TestHash}, - TestClient, TestClientBuilder, TestClientBuilderExt as _, + TestClientBuilder, TestClientBuilderExt as _, }; -#[cfg(test)] -mod chain_sync; #[cfg(test)] mod service; -type TestNetworkWorker = NetworkWorker; +type TestNetworkWorker = NetworkWorker; type TestNetworkService = NetworkService; -const BLOCK_ANNOUNCE_PROTO_NAME: &str = "/block-announces"; const PROTOCOL_NAME: &str = "/foo"; struct TestNetwork { @@ -65,14 +57,6 @@ impl TestNetwork { 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)) { @@ -92,7 +76,6 @@ struct TestNetworkBuilder { client: Option>, listen_addresses: Vec, set_config: Option, - chain_sync: Option<(Box>, Box>)>, chain_sync_network: Option<(NetworkServiceProvider, NetworkServiceHandle)>, config: Option, } @@ -105,17 +88,11 @@ impl TestNetworkBuilder { client: None, listen_addresses: Vec::new(), set_config: None, - chain_sync: None, chain_sync_network: 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 @@ -131,27 +108,6 @@ impl TestNetworkBuilder { self } - pub fn with_chain_sync( - mut self, - chain_sync: (Box>, Box>), - ) -> Self { - self.chain_sync = Some(chain_sync); - 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), @@ -240,73 +196,29 @@ impl TestNetworkBuilder { 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 (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, - None, - chain_sync_network_handle, - import_queue.service(), - block_request_protocol_config.name.clone(), - state_request_protocol_config.name.clone(), - None, - ) - .unwrap(); - - 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 (engine, chain_sync_service, block_announce_config) = SyncingEngine::new( + Roles::from(&config::Role::Full), + client.clone(), + None, + &network_config, + protocol_id.clone(), + &None, + Box::new(sp_consensus::block_validation::DefaultBlockAnnounceValidator), + None, + chain_sync_network_handle, + import_queue.service(), + block_request_protocol_config.name.clone(), + state_request_protocol_config.name.clone(), + None, + ) + .unwrap(); + let mut link = self.link.unwrap_or(Box::new(chain_sync_service.clone())); 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, @@ -317,8 +229,6 @@ impl TestNetworkBuilder { chain: client.clone(), protocol_id, fork_id, - chain_sync, - chain_sync_service, metrics_registry: None, request_response_protocol_configs: [ block_request_protocol_config, @@ -343,6 +253,8 @@ impl TestNetworkBuilder { tokio::time::sleep(std::time::Duration::from_millis(250)).await; } }); + let stream = worker.service().event_stream("syncing"); + tokio::spawn(engine.run(stream)); TestNetwork::new(worker) } diff --git a/client/network/src/service/tests/service.rs b/client/network/src/service/tests/service.rs index 1c7b32ff0dd17..9c4c0ad6e0cd9 100644 --- a/client/network/src/service/tests/service.rs +++ b/client/network/src/service/tests/service.rs @@ -32,7 +32,6 @@ type TestNetworkService = NetworkService< substrate_test_runtime_client::runtime::Hash, >; -const BLOCK_ANNOUNCE_PROTO_NAME: &str = "/block-announces"; const PROTOCOL_NAME: &str = "/foo"; /// Builds two nodes and their associated events stream. @@ -196,10 +195,6 @@ async fn notifications_state_consistent() { }, // Add new events here. - future::Either::Left(Event::SyncConnected { .. }) => {}, - future::Either::Right(Event::SyncConnected { .. }) => {}, - future::Either::Left(Event::SyncDisconnected { .. }) => {}, - future::Either::Right(Event::SyncDisconnected { .. }) => {}, future::Either::Left(Event::Dht(_)) => {}, future::Either::Right(Event::Dht(_)) => {}, }; @@ -208,6 +203,7 @@ async fn notifications_state_consistent() { #[tokio::test] async fn lots_of_incoming_peers_works() { + sp_tracing::try_init_simple(); let listen_addr = config::build_multiaddr![Memory(rand::random::())]; let (main_node, _) = TestNetworkBuilder::new() @@ -241,6 +237,7 @@ async fn lots_of_incoming_peers_works() { let mut timer = futures_timer::Delay::new(Duration::from_secs(3600 * 24 * 7)).fuse(); let mut event_stream = event_stream.fuse(); + let mut sync_protocol_name = None; loop { futures::select! { _ = timer => { @@ -249,15 +246,21 @@ async fn lots_of_incoming_peers_works() { } ev = event_stream.next() => { match ev.unwrap() { - Event::NotificationStreamOpened { remote, .. } => { + Event::NotificationStreamOpened { protocol, remote, .. } => { + if let None = sync_protocol_name { + sync_protocol_name = Some(protocol.clone()); + } + assert_eq!(remote, main_node_peer_id); // Test succeeds after 5 seconds. This timer is here in order to // detect a potential problem after opening. timer = futures_timer::Delay::new(Duration::from_secs(5)).fuse(); } - Event::NotificationStreamClosed { .. } => { - // Test failed. - panic!(); + Event::NotificationStreamClosed { protocol, .. } => { + if Some(protocol) != sync_protocol_name { + // Test failed. + panic!(); + } } _ => {} } @@ -282,10 +285,19 @@ async fn notifications_back_pressure() { let receiver = tokio::spawn(async move { let mut received_notifications = 0; + let mut sync_protocol_name = None; while received_notifications < TOTAL_NOTIFS { match events_stream2.next().await.unwrap() { - Event::NotificationStreamClosed { .. } => panic!(), + Event::NotificationStreamOpened { protocol, .. } => + if let None = sync_protocol_name { + sync_protocol_name = Some(protocol); + }, + Event::NotificationStreamClosed { protocol, .. } => { + if Some(&protocol) != sync_protocol_name.as_ref() { + panic!() + } + }, Event::NotificationsReceived { messages, .. } => for message in messages { assert_eq!(message.0, PROTOCOL_NAME.into()); @@ -387,42 +399,6 @@ async fn fallback_name_working() { receiver.await.unwrap(); } -// Disconnect peer by calling `Protocol::disconnect_peer()` with the supplied block announcement -// protocol name and verify that `SyncDisconnected` event is emitted -#[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(); - - 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 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()); - assert!(std::matches!( - events_stream2.next().await, - Some(Event::NotificationStreamClosed { .. }) - )); - let _ = events_stream2.next().await; // ignore the reopen event - - // 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 { .. }))); -} - #[tokio::test] #[should_panic(expected = "don't match the transport")] async fn ensure_listen_addresses_consistent_with_transport_memory() { diff --git a/client/network/sync/Cargo.toml b/client/network/sync/Cargo.toml index bd51776d6f898..52ab0d15e1670 100644 --- a/client/network/sync/Cargo.toml +++ b/client/network/sync/Cargo.toml @@ -20,6 +20,7 @@ array-bytes = "4.1" async-trait = "0.1.58" codec = { package = "parity-scale-codec", version = "3.2.2", features = ["derive"] } futures = "0.3.21" +futures-timer = "3.0.2" libp2p = "0.50.0" log = "0.4.17" lru = "0.8.1" diff --git a/client/network/sync/src/engine.rs b/client/network/sync/src/engine.rs new file mode 100644 index 0000000000000..25cd3968c2924 --- /dev/null +++ b/client/network/sync/src/engine.rs @@ -0,0 +1,924 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2023 Parity Technologies (UK) Ltd. +// SPDX-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 . + +//! `SyncingEngine` is the actor responsible for syncing Substrate chain +//! to tip and keep the blockchain up to date with network updates. + +use crate::{ + service::{self, chain_sync::ToServiceCommand}, + ChainSync, ClientError, SyncingService, +}; + +use futures::{FutureExt, Stream, StreamExt}; +use libp2p::PeerId; +use lru::LruCache; +use prometheus_endpoint::{ + register, Gauge, GaugeVec, MetricSource, Opts, PrometheusError, Registry, SourcedGauge, U64, +}; + +use codec::{Decode, DecodeAll, Encode}; +use futures_timer::Delay; +use sc_client_api::{BlockBackend, HeaderBackend, ProofProvider}; +use sc_consensus::import_queue::ImportQueueService; +use sc_network_common::{ + config::{ + NetworkConfiguration, NonDefaultSetConfig, ProtocolId, SyncMode as SyncOperationMode, + }, + protocol::{event::Event, role::Roles, ProtocolName}, + sync::{ + message::{ + generic::{BlockData, BlockResponse}, + BlockAnnounce, BlockAnnouncesHandshake, BlockState, + }, + warp::WarpSyncParams, + BadPeer, ChainSync as ChainSyncT, ExtendedPeerInfo, PollBlockAnnounceValidation, SyncEvent, + SyncMode, + }, + utils::LruHashSet, +}; +use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; +use sp_blockchain::HeaderMetadata; +use sp_consensus::block_validation::BlockAnnounceValidator; +use sp_runtime::{ + traits::{Block as BlockT, CheckedSub, Header, NumberFor, Zero}, + SaturatedConversion, +}; + +use std::{ + collections::{HashMap, HashSet}, + num::NonZeroUsize, + pin::Pin, + sync::{ + atomic::{AtomicBool, AtomicUsize, Ordering}, + Arc, + }, + task::Poll, +}; + +/// Interval at which we perform time based maintenance +const TICK_TIMEOUT: std::time::Duration = std::time::Duration::from_millis(1100); + +/// When light node connects to the full node and the full node is behind light node +/// for at least `LIGHT_MAXIMAL_BLOCKS_DIFFERENCE` blocks, we consider it not useful +/// and disconnect to free connection slot. +const LIGHT_MAXIMAL_BLOCKS_DIFFERENCE: u64 = 8192; + +/// Maximum number of known block hashes to keep for a peer. +const MAX_KNOWN_BLOCKS: usize = 1024; // ~32kb per peer + LruHashSet overhead + +mod rep { + use sc_peerset::ReputationChange as Rep; + /// 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 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. + pub const BAD_BLOCK_ANNOUNCEMENT: Rep = Rep::new(-(1 << 12), "Bad block announcement"); +} + +struct Metrics { + peers: Gauge, + queued_blocks: Gauge, + fork_targets: Gauge, + justifications: GaugeVec, +} + +impl Metrics { + fn register(r: &Registry, major_syncing: Arc) -> Result { + let _ = MajorSyncingGauge::register(r, major_syncing)?; + Ok(Self { + peers: { + let g = Gauge::new("substrate_sync_peers", "Number of peers we sync with")?; + register(g, r)? + }, + queued_blocks: { + let g = + Gauge::new("substrate_sync_queued_blocks", "Number of blocks in import queue")?; + register(g, r)? + }, + fork_targets: { + let g = Gauge::new("substrate_sync_fork_targets", "Number of fork sync targets")?; + register(g, r)? + }, + justifications: { + let g = GaugeVec::new( + Opts::new( + "substrate_sync_extra_justifications", + "Number of extra justifications requests", + ), + &["status"], + )?; + register(g, r)? + }, + }) + } +} + +/// The "major syncing" metric. +#[derive(Clone)] +pub struct MajorSyncingGauge(Arc); + +impl MajorSyncingGauge { + /// Registers the [`MajorSyncGauge`] metric whose value is + /// obtained from the given `AtomicBool`. + fn register(registry: &Registry, value: Arc) -> Result<(), PrometheusError> { + prometheus_endpoint::register( + SourcedGauge::new( + &Opts::new( + "substrate_sub_libp2p_is_major_syncing", + "Whether the node is performing a major sync or not.", + ), + MajorSyncingGauge(value), + )?, + registry, + )?; + + Ok(()) + } +} + +impl MetricSource for MajorSyncingGauge { + type N = u64; + + fn collect(&self, mut set: impl FnMut(&[&str], Self::N)) { + set(&[], self.0.load(Ordering::Relaxed) as u64); + } +} + +/// Peer information +#[derive(Debug)] +pub struct Peer { + pub info: ExtendedPeerInfo, + /// Holds a set of blocks known to this peer. + pub known_blocks: LruHashSet, +} + +pub struct SyncingEngine { + /// State machine that handles the list of in-progress requests. Only full node peers are + /// registered. + chain_sync: ChainSync, + + /// Blockchain client. + client: Arc, + + /// Number of peers we're connected to. + num_connected: Arc, + + /// Are we actively catching up with the chain? + is_major_syncing: Arc, + + /// Network service. + network_service: service::network::NetworkServiceHandle, + + /// Channel for receiving service commands + service_rx: TracingUnboundedReceiver>, + + /// Assigned roles. + roles: Roles, + + /// Genesis hash. + genesis_hash: B::Hash, + + /// Set of channels for other protocols that have subscribed to syncing events. + event_streams: Vec>, + + /// Interval at which we call `tick`. + tick_timeout: Delay, + + /// All connected peers. Contains both full and light node peers. + peers: HashMap>, + + /// List of nodes for which we perform additional logging because they are important for the + /// user. + important_peers: HashSet, + + /// Actual list of connected no-slot nodes. + default_peers_set_no_slot_connected_peers: HashSet, + + /// List of nodes that should never occupy peer slots. + default_peers_set_no_slot_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, + + /// A cache for the data that was associated to a block announcement. + block_announce_data_cache: LruCache>, + + /// The `PeerId`'s of all boot nodes. + boot_node_ids: HashSet, + + /// Protocol name used for block announcements + block_announce_protocol_name: ProtocolName, + + /// Prometheus metrics. + metrics: Option, +} + +impl SyncingEngine +where + B: BlockT, + Client: HeaderBackend + + BlockBackend + + HeaderMetadata + + ProofProvider + + Send + + Sync + + 'static, +{ + pub fn new( + roles: Roles, + client: Arc, + metrics_registry: Option<&Registry>, + network_config: &NetworkConfiguration, + protocol_id: ProtocolId, + fork_id: &Option, + block_announce_validator: Box + Send>, + warp_sync_params: Option>, + 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, SyncingService, NonDefaultSetConfig), ClientError> { + let mode = match network_config.sync_mode { + SyncOperationMode::Full => SyncMode::Full, + SyncOperationMode::Fast { skip_proofs, storage_chain_mode } => + SyncMode::LightState { skip_proofs, storage_chain_mode }, + SyncOperationMode::Warp => SyncMode::Warp, + }; + let max_parallel_downloads = network_config.max_parallel_downloads; + 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 important_peers = { + let mut imp_p = HashSet::new(); + for reserved in &network_config.default_peers_set.reserved_nodes { + imp_p.insert(reserved.peer_id); + } + for reserved in network_config + .extra_sets + .iter() + .flat_map(|s| s.set_config.reserved_nodes.iter()) + { + imp_p.insert(reserved.peer_id); + } + imp_p.shrink_to_fit(); + imp_p + }; + let boot_node_ids = { + let mut list = HashSet::new(); + for node in &network_config.boot_nodes { + list.insert(node.peer_id); + } + list.shrink_to_fit(); + list + }; + 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 default_peers_set_num_full = network_config.default_peers_set_num_full as usize; + let 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 + }; + + let (chain_sync, block_announce_config) = ChainSync::new( + mode, + client.clone(), + protocol_id, + fork_id, + roles, + block_announce_validator, + max_parallel_downloads, + warp_sync_params, + metrics_registry, + network_service.clone(), + import_queue, + block_request_protocol_name, + state_request_protocol_name, + warp_sync_protocol_name, + )?; + + let block_announce_protocol_name = block_announce_config.notifications_protocol.clone(); + let (tx, service_rx) = tracing_unbounded("mpsc_chain_sync", 100_000); + let num_connected = Arc::new(AtomicUsize::new(0)); + let is_major_syncing = Arc::new(AtomicBool::new(false)); + let genesis_hash = client + .block_hash(0u32.into()) + .ok() + .flatten() + .expect("Genesis block exists; qed"); + + Ok(( + Self { + roles, + client, + chain_sync, + network_service, + peers: HashMap::new(), + block_announce_data_cache: LruCache::new(cache_capacity), + block_announce_protocol_name, + num_connected: num_connected.clone(), + is_major_syncing: is_major_syncing.clone(), + service_rx, + genesis_hash, + important_peers, + default_peers_set_no_slot_connected_peers: HashSet::new(), + boot_node_ids, + default_peers_set_no_slot_peers, + default_peers_set_num_full, + default_peers_set_num_light, + event_streams: Vec::new(), + tick_timeout: Delay::new(TICK_TIMEOUT), + metrics: if let Some(r) = metrics_registry { + match Metrics::register(r, is_major_syncing.clone()) { + Ok(metrics) => Some(metrics), + Err(err) => { + log::error!(target: "sync", "Failed to register metrics {err:?}"); + None + }, + } + } else { + None + }, + }, + SyncingService::new(tx, num_connected, is_major_syncing), + block_announce_config, + )) + } + + /// Report Prometheus metrics. + pub 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.chain_sync.metrics(); + + metrics.fork_targets.set(m.fork_targets.into()); + metrics.queued_blocks.set(m.queued_blocks.into()); + + metrics + .justifications + .with_label_values(&["pending"]) + .set(m.justifications.pending_requests.into()); + metrics + .justifications + .with_label_values(&["active"]) + .set(m.justifications.active_requests.into()); + metrics + .justifications + .with_label_values(&["failed"]) + .set(m.justifications.failed_requests.into()); + metrics + .justifications + .with_label_values(&["importing"]) + .set(m.justifications.importing_requests.into()); + } + } + + fn update_peer_info(&mut self, who: &PeerId) { + if let Some(info) = self.chain_sync.peer_info(who) { + if let Some(ref mut peer) = self.peers.get_mut(who) { + peer.info.best_hash = info.best_hash; + peer.info.best_number = info.best_number; + } + } + } + + /// Process the result of the block announce validation. + pub fn process_block_announce_validation_result( + &mut self, + validation_result: PollBlockAnnounceValidation, + ) { + let (header, _is_best, who) = match validation_result { + PollBlockAnnounceValidation::Skip => return, + PollBlockAnnounceValidation::Nothing { is_best: _, who, announce } => { + self.update_peer_info(&who); + + if let Some(data) = announce.data { + if !data.is_empty() { + self.block_announce_data_cache.put(announce.header.hash(), data); + } + } + + return + }, + PollBlockAnnounceValidation::ImportHeader { announce, is_best, who } => { + self.update_peer_info(&who); + + if let Some(data) = announce.data { + if !data.is_empty() { + self.block_announce_data_cache.put(announce.header.hash(), data); + } + } + + (announce.header, is_best, who) + }, + PollBlockAnnounceValidation::Failure { who, disconnect } => { + if disconnect { + self.network_service + .disconnect_peer(who, self.block_announce_protocol_name.clone()); + } + + self.network_service.report_peer(who, rep::BAD_BLOCK_ANNOUNCEMENT); + return + }, + }; + + // 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.chain_sync.on_block_data( + &who, + None, + BlockResponse { + id: 0, + blocks: vec![BlockData { + hash: header.hash(), + header: Some(header), + body: None, + indexed_body: None, + receipt: None, + message_queue: None, + justification: None, + justifications: None, + }], + }, + ); + + self.chain_sync.process_block_response_data(blocks_to_import); + } + + /// Push a block announce validation. + /// + /// It is required that [`ChainSync::poll_block_announce_validation`] is + /// called later to check for finished validations. The result of the validation + /// needs to be passed to [`SyncingEngine::process_block_announce_validation_result`] + /// to finish the processing. + /// + /// # Note + /// + /// This will internally create a future, but this future will not be registered + /// in the task before being polled once. So, it is required to call + /// [`ChainSync::poll_block_announce_validation`] to ensure that the future is + /// registered properly and will wake up the task when being ready. + pub fn push_block_announce_validation( + &mut self, + who: PeerId, + announce: BlockAnnounce, + ) { + let hash = announce.header.hash(); + + let peer = match self.peers.get_mut(&who) { + Some(p) => p, + None => { + log::error!(target: "sync", "Received block announce from disconnected peer {}", who); + debug_assert!(false); + return + }, + }; + peer.known_blocks.insert(hash); + + if peer.info.roles.is_full() { + let is_best = match announce.state.unwrap_or(BlockState::Best) { + BlockState::Best => true, + BlockState::Normal => false, + }; + + self.chain_sync.push_block_announce_validation(who, hash, announce, is_best); + } + } + + /// 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. + pub fn announce_block(&mut self, hash: B::Hash, data: Option>) { + let header = match self.client.header(hash) { + Ok(Some(header)) => header, + Ok(None) => { + log::warn!(target: "sync", "Trying to announce unknown block: {}", hash); + return + }, + Err(e) => { + log::warn!(target: "sync", "Error reading block header {}: {}", hash, e); + return + }, + }; + + // don't announce genesis block since it will be ignored + if header.number().is_zero() { + return + } + + let is_best = self.client.info().best_hash == hash; + log::debug!(target: "sync", "Reannouncing block {:?} is_best: {}", hash, is_best); + + let data = data + .or_else(|| self.block_announce_data_cache.get(&hash).cloned()) + .unwrap_or_default(); + + for (who, ref mut peer) in self.peers.iter_mut() { + let inserted = peer.known_blocks.insert(hash); + if inserted { + log::trace!(target: "sync", "Announcing block {:?} to {}", hash, who); + let message = BlockAnnounce { + header: header.clone(), + state: if is_best { Some(BlockState::Best) } else { Some(BlockState::Normal) }, + data: Some(data.clone()), + }; + + self.network_service.write_notification( + *who, + self.block_announce_protocol_name.clone(), + message.encode(), + ); + } + } + } + + /// Inform sync about new best imported block. + pub fn new_best_block_imported(&mut self, hash: B::Hash, number: NumberFor) { + log::debug!(target: "sync", "New best block imported {:?}/#{}", hash, number); + + self.chain_sync.update_chain_info(&hash, number); + self.network_service.set_notification_handshake( + self.block_announce_protocol_name.clone(), + BlockAnnouncesHandshake::::build(self.roles, number, hash, self.genesis_hash) + .encode(), + ) + } + + pub async fn run(mut self, mut stream: Pin + Send>>) { + loop { + futures::future::poll_fn(|cx| self.poll(cx, &mut stream)).await; + } + } + + pub fn poll( + &mut self, + cx: &mut std::task::Context, + event_stream: &mut Pin + Send>>, + ) -> Poll<()> { + self.num_connected.store(self.peers.len(), Ordering::Relaxed); + self.is_major_syncing + .store(self.chain_sync.status().state.is_major_syncing(), Ordering::Relaxed); + + while let Poll::Ready(()) = self.tick_timeout.poll_unpin(cx) { + self.report_metrics(); + self.tick_timeout.reset(TICK_TIMEOUT); + } + + while let Poll::Ready(Some(event)) = event_stream.poll_next_unpin(cx) { + match event { + Event::NotificationStreamOpened { + remote, protocol, received_handshake, .. + } => { + if protocol != self.block_announce_protocol_name { + continue + } + + match as DecodeAll>::decode_all( + &mut &received_handshake[..], + ) { + Ok(handshake) => { + if self.on_sync_peer_connected(remote, handshake).is_err() { + log::debug!( + target: "sync", + "Failed to register peer {remote:?}: {received_handshake:?}", + ); + } + }, + Err(err) => { + log::debug!( + target: "sync", + "Couldn't decode handshake sent by {}: {:?}: {}", + remote, + received_handshake, + err, + ); + self.network_service.report_peer(remote, rep::BAD_MESSAGE); + }, + } + }, + Event::NotificationStreamClosed { remote, protocol } => { + if protocol != self.block_announce_protocol_name { + continue + } + + if self.on_sync_peer_disconnected(remote).is_err() { + log::trace!( + target: "sync", + "Disconnected peer which had earlier been refused by on_sync_peer_connected {}", + remote + ); + } + }, + Event::NotificationsReceived { remote, messages } => { + for (protocol, message) in messages { + if protocol != self.block_announce_protocol_name { + continue + } + + if self.peers.contains_key(&remote) { + if let Ok(announce) = BlockAnnounce::decode(&mut message.as_ref()) { + self.push_block_announce_validation(remote, announce); + + // Make sure that the newly added block announce validation future + // was polled once to be registered in the task. + if let Poll::Ready(res) = + self.chain_sync.poll_block_announce_validation(cx) + { + self.process_block_announce_validation_result(res) + } + } else { + log::warn!(target: "sub-libp2p", "Failed to decode block announce"); + } + } else { + log::trace!( + target: "sync", + "Received sync for peer earlier refused by sync layer: {}", + remote + ); + } + } + }, + _ => {}, + } + } + + while let Poll::Ready(Some(event)) = self.service_rx.poll_next_unpin(cx) { + match event { + ToServiceCommand::SetSyncForkRequest(peers, hash, number) => { + self.chain_sync.set_sync_fork_request(peers, &hash, number); + }, + ToServiceCommand::EventStream(tx) => self.event_streams.push(tx), + ToServiceCommand::RequestJustification(hash, number) => + self.chain_sync.request_justification(&hash, number), + ToServiceCommand::ClearJustificationRequests => + self.chain_sync.clear_justification_requests(), + ToServiceCommand::BlocksProcessed(imported, count, results) => { + for result in self.chain_sync.on_blocks_processed(imported, count, results) { + match result { + Ok((id, req)) => self.chain_sync.send_block_request(id, req), + Err(BadPeer(id, repu)) => { + self.network_service + .disconnect_peer(id, self.block_announce_protocol_name.clone()); + self.network_service.report_peer(id, repu) + }, + } + } + }, + ToServiceCommand::JustificationImported(peer, hash, number, success) => { + self.chain_sync.on_justification_import(hash, number, success); + if !success { + log::info!(target: "sync", "💔 Invalid justification provided by {} for #{}", peer, hash); + 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"), + ); + } + }, + ToServiceCommand::AnnounceBlock(hash, data) => self.announce_block(hash, data), + ToServiceCommand::NewBestBlockImported(hash, number) => + self.new_best_block_imported(hash, number), + ToServiceCommand::Status(tx) => { + let _ = tx.send(self.chain_sync.status()); + }, + ToServiceCommand::NumActivePeers(tx) => { + let _ = tx.send(self.chain_sync.num_active_peers()); + }, + ToServiceCommand::SyncState(tx) => { + let _ = tx.send(self.chain_sync.status()); + }, + ToServiceCommand::BestSeenBlock(tx) => { + let _ = tx.send(self.chain_sync.status().best_seen_block); + }, + ToServiceCommand::NumSyncPeers(tx) => { + let _ = tx.send(self.chain_sync.status().num_peers); + }, + ToServiceCommand::NumQueuedBlocks(tx) => { + let _ = tx.send(self.chain_sync.status().queued_blocks); + }, + ToServiceCommand::NumDownloadedBlocks(tx) => { + let _ = tx.send(self.chain_sync.num_downloaded_blocks()); + }, + ToServiceCommand::NumSyncRequests(tx) => { + let _ = tx.send(self.chain_sync.num_sync_requests()); + }, + ToServiceCommand::PeersInfo(tx) => { + let peers_info = + self.peers.iter().map(|(id, peer)| (*id, peer.info.clone())).collect(); + let _ = tx.send(peers_info); + }, + ToServiceCommand::OnBlockFinalized(hash, header) => + self.chain_sync.on_block_finalized(&hash, *header.number()), + } + } + + while let Poll::Ready(result) = self.chain_sync.poll(cx) { + self.process_block_announce_validation_result(result); + } + + Poll::Pending + } + + /// Called by peer when it is disconnecting. + /// + /// Returns a result if the handshake of this peer was indeed accepted. + pub fn on_sync_peer_disconnected(&mut self, peer: PeerId) -> Result<(), ()> { + if self.important_peers.contains(&peer) { + log::warn!(target: "sync", "Reserved peer {} disconnected", peer); + } else { + log::debug!(target: "sync", "{} disconnected", peer); + } + + if self.peers.remove(&peer).is_some() { + self.chain_sync.peer_disconnected(&peer); + self.default_peers_set_no_slot_connected_peers.remove(&peer); + self.event_streams + .retain(|stream| stream.unbounded_send(SyncEvent::PeerDisconnected(peer)).is_ok()); + Ok(()) + } else { + Err(()) + } + } + + /// Called on the first connection between two peers on the default set, after their exchange + /// of handshake. + /// + /// Returns `Ok` if the handshake is accepted and the peer added to the list of peers we sync + /// from. + pub fn on_sync_peer_connected( + &mut self, + who: PeerId, + status: BlockAnnouncesHandshake, + ) -> Result<(), ()> { + log::trace!(target: "sync", "New peer {} {:?}", who, status); + + if self.peers.contains_key(&who) { + log::error!(target: "sync", "Called on_sync_peer_connected with already connected peer {}", who); + debug_assert!(false); + return Err(()) + } + + if status.genesis_hash != self.genesis_hash { + self.network_service.report_peer(who, rep::GENESIS_MISMATCH); + self.network_service + .disconnect_peer(who, self.block_announce_protocol_name.clone()); + + if self.important_peers.contains(&who) { + log::error!( + target: "sync", + "Reserved peer id `{}` is on a different chain (our genesis: {} theirs: {})", + who, + self.genesis_hash, + status.genesis_hash, + ); + } else if self.boot_node_ids.contains(&who) { + log::error!( + target: "sync", + "Bootnode with peer id `{}` is on a different chain (our genesis: {} theirs: {})", + who, + self.genesis_hash, + status.genesis_hash, + ); + } else { + log::debug!( + target: "sync", + "Peer is on different chain (our genesis: {} theirs: {})", + self.genesis_hash, status.genesis_hash + ); + } + + return Err(()) + } + + if self.roles.is_light() { + // we're not interested in light peers + if status.roles.is_light() { + log::debug!(target: "sync", "Peer {} is unable to serve light requests", who); + self.network_service.report_peer(who, rep::BAD_ROLE); + self.network_service + .disconnect_peer(who, self.block_announce_protocol_name.clone()); + return Err(()) + } + + // we don't interested in peers that are far behind us + let self_best_block = self.client.info().best_number; + let blocks_difference = self_best_block + .checked_sub(&status.best_number) + .unwrap_or_else(Zero::zero) + .saturated_into::(); + if blocks_difference > LIGHT_MAXIMAL_BLOCKS_DIFFERENCE { + log::debug!(target: "sync", "Peer {} is far behind us and will unable to serve light requests", who); + self.network_service.report_peer(who, rep::PEER_BEHIND_US_LIGHT); + self.network_service + .disconnect_peer(who, self.block_announce_protocol_name.clone()); + return Err(()) + } + } + + 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 + { + log::debug!(target: "sync", "Too many full nodes, rejecting {}", who); + self.network_service + .disconnect_peer(who, self.block_announce_protocol_name.clone()); + return Err(()) + } + + if status.roles.is_light() && + (self.peers.len() - self.chain_sync.num_peers()) >= self.default_peers_set_num_light + { + // Make sure that not all slots are occupied by light clients. + log::debug!(target: "sync", "Too many light nodes, rejecting {}", who); + self.network_service + .disconnect_peer(who, self.block_announce_protocol_name.clone()); + return Err(()) + } + + let peer = Peer { + info: ExtendedPeerInfo { + roles: status.roles, + best_hash: status.best_hash, + best_number: status.best_number, + }, + known_blocks: LruHashSet::new( + NonZeroUsize::new(MAX_KNOWN_BLOCKS).expect("Constant is nonzero"), + ), + }; + + let req = if peer.info.roles.is_full() { + match self.chain_sync.new_peer(who, peer.info.best_hash, peer.info.best_number) { + Ok(req) => req, + Err(BadPeer(id, repu)) => { + self.network_service + .disconnect_peer(id, self.block_announce_protocol_name.clone()); + self.network_service.report_peer(id, repu); + return Err(()) + }, + } + } else { + None + }; + + log::debug!(target: "sync", "Connected {}", who); + + self.peers.insert(who, peer); + if no_slot_peer { + self.default_peers_set_no_slot_connected_peers.insert(who); + } + + if let Some(req) = req { + self.chain_sync.send_block_request(who, req); + } + + self.event_streams + .retain(|stream| stream.unbounded_send(SyncEvent::PeerConnected(who)).is_ok()); + + Ok(()) + } +} diff --git a/client/network/sync/src/lib.rs b/client/network/sync/src/lib.rs index f710215e74177..23269b02bd128 100644 --- a/client/network/sync/src/lib.rs +++ b/client/network/sync/src/lib.rs @@ -30,20 +30,18 @@ pub mod block_request_handler; pub mod blocks; +pub mod engine; 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}, }; @@ -78,7 +76,7 @@ use sc_network_common::{ SyncState, SyncStatus, }, }; -use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver}; +pub use service::chain_sync::SyncingService; use sp_arithmetic::traits::Saturating; use sp_blockchain::{Error as ClientError, HeaderBackend, HeaderMetadata}; use sp_consensus::{ @@ -327,8 +325,6 @@ pub struct ChainSync { import_existing: bool, /// Gap download process. gap_sync: Option>, - /// Channel for receiving service commands - service_rx: TracingUnboundedReceiver>, /// Handle for communicating with `NetworkService` network_service: service::network::NetworkServiceHandle, /// Protocol name used for block announcements @@ -1326,47 +1322,6 @@ where &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"), - ); - } - }, - ToServiceCommand::BlockFinalized(hash, number) => { - self.on_block_finalized(&hash, number); - }, - ToServiceCommand::Status { pending_response } => { - let _ = pending_response.send(self.status()); - }, - } - } - // Should be called before `process_outbound_requests` to ensure // that a potential target block is directly leading to requests. if let Some(warp_sync) = &mut self.warp_sync { @@ -1448,8 +1403,7 @@ where block_request_protocol_name: ProtocolName, state_request_protocol_name: ProtocolName, warp_sync_protocol_name: Option, - ) -> Result<(Self, ChainSyncInterfaceHandle, NonDefaultSetConfig), ClientError> { - let (tx, service_rx) = tracing_unbounded("mpsc_chain_sync", 100_000); + ) -> Result<(Self, NonDefaultSetConfig), ClientError> { let block_announce_config = Self::get_block_announce_proto_config( protocol_id, fork_id, @@ -1483,7 +1437,6 @@ where warp_sync: None, import_existing: false, gap_sync: None, - service_rx, network_service, block_request_protocol_name, state_request_protocol_name, @@ -1509,7 +1462,7 @@ where }; sync.reset_sync_start_point()?; - Ok((sync, ChainSyncInterfaceHandle::new(tx), block_announce_config)) + Ok((sync, block_announce_config)) } /// Returns the median seen block number. @@ -3231,7 +3184,7 @@ mod test { let import_queue = Box::new(sc_consensus::import_queue::mock::MockImportQueueHandle::new()); let (_chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new(); - let (mut sync, _, _) = ChainSync::new( + let (mut sync, _) = ChainSync::new( SyncMode::Full, client.clone(), ProtocolId::from("test-protocol-name"), @@ -3297,7 +3250,7 @@ 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"), @@ -3478,7 +3431,7 @@ 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"), @@ -3604,7 +3557,7 @@ 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"), @@ -3760,7 +3713,7 @@ 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"), @@ -3901,7 +3854,7 @@ 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"), @@ -4042,7 +3995,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(), ProtocolId::from("test-protocol-name"), @@ -4087,7 +4040,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(), ProtocolId::from("test-protocol-name"), diff --git a/client/network/sync/src/service/chain_sync.rs b/client/network/sync/src/service/chain_sync.rs index 4d47899a31727..99b4197740eda 100644 --- a/client/network/sync/src/service/chain_sync.rs +++ b/client/network/sync/src/service/chain_sync.rs @@ -16,15 +16,26 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use futures::channel::oneshot; +use futures::{channel::oneshot, Stream}; use libp2p::PeerId; + use sc_consensus::{BlockImportError, BlockImportStatus, JustificationSyncLink, Link}; -use sc_network_common::{service::NetworkSyncForkRequest, sync::SyncStatus}; -use sc_utils::mpsc::TracingUnboundedSender; +use sc_network_common::{ + service::{NetworkBlock, NetworkSyncForkRequest}, + sync::{ExtendedPeerInfo, SyncEvent, SyncEventStream, SyncStatus, SyncStatusProvider}, +}; +use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedSender}; use sp_runtime::traits::{Block as BlockT, NumberFor}; +use std::{ + pin::Pin, + sync::{ + atomic::{AtomicBool, AtomicUsize, Ordering}, + Arc, + }, +}; + /// Commands send to `ChainSync` -#[derive(Debug)] pub enum ToServiceCommand { SetSyncForkRequest(Vec, B::Hash, NumberFor), RequestJustification(B::Hash, NumberFor), @@ -35,27 +46,105 @@ pub enum ToServiceCommand { Vec<(Result>, BlockImportError>, B::Hash)>, ), JustificationImported(PeerId, B::Hash, NumberFor, bool), - BlockFinalized(B::Hash, NumberFor), - Status { - pending_response: oneshot::Sender>, - }, + AnnounceBlock(B::Hash, Option>), + NewBestBlockImported(B::Hash, NumberFor), + EventStream(TracingUnboundedSender), + Status(oneshot::Sender>), + NumActivePeers(oneshot::Sender), + SyncState(oneshot::Sender>), + BestSeenBlock(oneshot::Sender>>), + NumSyncPeers(oneshot::Sender), + NumQueuedBlocks(oneshot::Sender), + NumDownloadedBlocks(oneshot::Sender), + NumSyncRequests(oneshot::Sender), + PeersInfo(oneshot::Sender)>>), + OnBlockFinalized(B::Hash, B::Header), + // Status { + // pending_response: oneshot::Sender>, + // }, } /// Handle for communicating with `ChainSync` asynchronously #[derive(Clone)] -pub struct ChainSyncInterfaceHandle { +pub struct SyncingService { tx: TracingUnboundedSender>, + /// Number of peers we're connected to. + num_connected: Arc, + /// Are we actively catching up with the chain? + is_major_syncing: Arc, } -impl ChainSyncInterfaceHandle { +impl SyncingService { /// Create new handle - pub fn new(tx: TracingUnboundedSender>) -> Self { - Self { tx } + pub fn new( + tx: TracingUnboundedSender>, + num_connected: Arc, + is_major_syncing: Arc, + ) -> Self { + Self { tx, num_connected, is_major_syncing } } - /// Notify ChainSync about finalized block - pub fn on_block_finalized(&self, hash: B::Hash, number: NumberFor) { - let _ = self.tx.unbounded_send(ToServiceCommand::BlockFinalized(hash, number)); + /// Get the number of active peers. + pub async fn num_active_peers(&self) -> Result { + let (tx, rx) = oneshot::channel(); + let _ = self.tx.unbounded_send(ToServiceCommand::NumActivePeers(tx)); + + rx.await + } + + /// Get best seen block. + pub async fn best_seen_block(&self) -> Result>, oneshot::Canceled> { + let (tx, rx) = oneshot::channel(); + let _ = self.tx.unbounded_send(ToServiceCommand::BestSeenBlock(tx)); + + rx.await + } + + /// Get the number of sync peers. + pub async fn num_sync_peers(&self) -> Result { + let (tx, rx) = oneshot::channel(); + let _ = self.tx.unbounded_send(ToServiceCommand::NumSyncPeers(tx)); + + rx.await + } + + /// Get the number of queued blocks. + pub async fn num_queued_blocks(&self) -> Result { + let (tx, rx) = oneshot::channel(); + let _ = self.tx.unbounded_send(ToServiceCommand::NumQueuedBlocks(tx)); + + rx.await + } + + /// Get the number of downloaded blocks. + pub async fn num_downloaded_blocks(&self) -> Result { + let (tx, rx) = oneshot::channel(); + let _ = self.tx.unbounded_send(ToServiceCommand::NumDownloadedBlocks(tx)); + + rx.await + } + + /// Get the number of sync requests. + pub async fn num_sync_requests(&self) -> Result { + let (tx, rx) = oneshot::channel(); + let _ = self.tx.unbounded_send(ToServiceCommand::NumSyncRequests(tx)); + + rx.await + } + + /// Get peer information. + pub async fn peers_info( + &self, + ) -> Result)>, oneshot::Canceled> { + let (tx, rx) = oneshot::channel(); + let _ = self.tx.unbounded_send(ToServiceCommand::PeersInfo(tx)); + + rx.await + } + + /// Notify the `SyncingEngine` that a block has been finalized. + pub fn on_block_finalized(&self, hash: B::Hash, header: B::Header) { + let _ = self.tx.unbounded_send(ToServiceCommand::OnBlockFinalized(hash, header)); } /// Get sync status @@ -63,15 +152,13 @@ impl ChainSyncInterfaceHandle { /// Returns an error if `ChainSync` has terminated. pub async fn status(&self) -> Result, ()> { let (tx, rx) = oneshot::channel(); - let _ = self.tx.unbounded_send(ToServiceCommand::Status { pending_response: tx }); + let _ = self.tx.unbounded_send(ToServiceCommand::Status(tx)); rx.await.map_err(|_| ()) } } -impl NetworkSyncForkRequest> - for ChainSyncInterfaceHandle -{ +impl NetworkSyncForkRequest> for SyncingService { /// Configure an explicit fork sync request. /// /// Note that this function should not be used for recent blocks. @@ -87,7 +174,7 @@ impl NetworkSyncForkRequest> } } -impl JustificationSyncLink for ChainSyncInterfaceHandle { +impl JustificationSyncLink for SyncingService { /// 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 @@ -101,7 +188,18 @@ impl JustificationSyncLink for ChainSyncInterfaceHandle { } } -impl Link for ChainSyncInterfaceHandle { +#[async_trait::async_trait] +impl SyncStatusProvider for SyncingService { + /// Get high-level view of the syncing status. + async fn status(&self) -> Result, ()> { + let (rtx, rrx) = oneshot::channel(); + + let _ = self.tx.unbounded_send(ToServiceCommand::Status(rtx)); + rrx.await.map_err(|_| ()) + } +} + +impl Link for SyncingService { fn blocks_processed( &mut self, imported: usize, @@ -129,3 +227,32 @@ impl Link for ChainSyncInterfaceHandle { let _ = self.tx.unbounded_send(ToServiceCommand::RequestJustification(*hash, number)); } } + +impl SyncEventStream for SyncingService { + /// Get syncing event stream. + fn event_stream(&self, name: &'static str) -> Pin + Send>> { + let (tx, rx) = tracing_unbounded(name, 100_000); + let _ = self.tx.unbounded_send(ToServiceCommand::EventStream(tx)); + Box::pin(rx) + } +} + +impl NetworkBlock> for SyncingService { + fn announce_block(&self, hash: B::Hash, data: Option>) { + let _ = self.tx.unbounded_send(ToServiceCommand::AnnounceBlock(hash, data)); + } + + fn new_best_block_imported(&self, hash: B::Hash, number: NumberFor) { + let _ = self.tx.unbounded_send(ToServiceCommand::NewBestBlockImported(hash, number)); + } +} + +impl sp_consensus::SyncOracle for SyncingService { + fn is_major_syncing(&self) -> bool { + self.is_major_syncing.load(Ordering::Relaxed) + } + + fn is_offline(&self) -> bool { + self.num_connected.load(Ordering::Relaxed) == 0 + } +} diff --git a/client/network/sync/src/service/mock.rs b/client/network/sync/src/service/mock.rs index e66a9e5611f09..2853616adfb4d 100644 --- a/client/network/sync/src/service/mock.rs +++ b/client/network/sync/src/service/mock.rs @@ -23,7 +23,10 @@ use sc_network_common::{ config::MultiaddrWithPeerId, protocol::ProtocolName, request_responses::{IfDisconnected, RequestFailure}, - service::{NetworkPeers, NetworkRequest, NetworkSyncForkRequest}, + service::{ + NetworkNotification, NetworkPeers, NetworkRequest, NetworkSyncForkRequest, + NotificationSender, NotificationSenderError, + }, }; use sc_peerset::ReputationChange; use sp_runtime::traits::{Block as BlockT, NumberFor}; @@ -125,4 +128,14 @@ mockall::mock! { connect: IfDisconnected, ); } + + impl NetworkNotification for Network { + fn write_notification(&self, target: PeerId, protocol: ProtocolName, message: Vec); + fn notification_sender( + &self, + target: PeerId, + protocol: ProtocolName, + ) -> Result, NotificationSenderError>; + fn set_notification_handshake(&self, protocol: ProtocolName, handshake: Vec); + } } diff --git a/client/network/sync/src/service/network.rs b/client/network/sync/src/service/network.rs index de7e255f5a895..a1f4f27bbbd99 100644 --- a/client/network/sync/src/service/network.rs +++ b/client/network/sync/src/service/network.rs @@ -21,16 +21,16 @@ use libp2p::PeerId; use sc_network_common::{ protocol::ProtocolName, request_responses::{IfDisconnected, RequestFailure}, - service::{NetworkPeers, NetworkRequest}, + service::{NetworkNotification, 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 + NetworkRequest {} +pub trait Network: NetworkPeers + NetworkRequest + NetworkNotification {} -impl Network for T where T: NetworkPeers + NetworkRequest {} +impl Network for T where T: NetworkPeers + NetworkRequest + NetworkNotification {} /// Network service provider for `ChainSync` /// @@ -56,6 +56,12 @@ pub enum ToServiceCommand { oneshot::Sender, RequestFailure>>, IfDisconnected, ), + + /// Call `NetworkNotification::write_notification()` + WriteNotification(PeerId, ProtocolName, Vec), + + /// Call `NetworkNotification::set_notification_handshake()` + SetNotificationHandshake(ProtocolName, Vec), } /// Handle that is (temporarily) passed to `ChainSync` so it can @@ -94,6 +100,20 @@ impl NetworkServiceHandle { .tx .unbounded_send(ToServiceCommand::StartRequest(who, protocol, request, tx, connect)); } + + /// Send notification to peer + pub fn write_notification(&self, who: PeerId, protocol: ProtocolName, message: Vec) { + let _ = self + .tx + .unbounded_send(ToServiceCommand::WriteNotification(who, protocol, message)); + } + + /// Set handshake for the notification protocol. + pub fn set_notification_handshake(&self, protocol: ProtocolName, handshake: Vec) { + let _ = self + .tx + .unbounded_send(ToServiceCommand::SetNotificationHandshake(protocol, handshake)); + } } impl NetworkServiceProvider { @@ -114,6 +134,10 @@ impl NetworkServiceProvider { service.report_peer(peer, reputation_change), ToServiceCommand::StartRequest(peer, protocol, request, tx, connect) => service.start_request(peer, protocol, request, tx, connect), + ToServiceCommand::WriteNotification(peer, protocol, message) => + service.write_notification(peer, protocol, message), + ToServiceCommand::SetNotificationHandshake(protocol, handshake) => + service.set_notification_handshake(protocol, handshake), } } } diff --git a/client/network/sync/src/tests.rs b/client/network/sync/src/tests.rs deleted file mode 100644 index d56e84093ad71..0000000000000 --- a/client/network/sync/src/tests.rs +++ /dev/null @@ -1,78 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use crate::{service::network::NetworkServiceProvider, ChainSync, ForkTarget}; - -use libp2p::PeerId; -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}; -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 -#[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, - 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, - None, - chain_sync_network_handle, - import_queue, - ProtocolName::from("block-request"), - ProtocolName::from("state-request"), - 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 544f4c5f62d18..95381dd7b4cf1 100644 --- a/client/network/test/src/lib.rs +++ b/client/network/test/src/lib.rs @@ -46,24 +46,24 @@ use sc_consensus::{ ForkChoiceStrategy, ImportQueue, ImportResult, JustificationImport, JustificationSyncLink, LongestChain, Verifier, }; -use sc_network::{ - config::{NetworkConfiguration, RequestResponseConfig, Role, SyncMode}, - Multiaddr, NetworkService, NetworkWorker, -}; +use sc_network::{Multiaddr, NetworkService, NetworkWorker}; use sc_network_common::{ config::{ - MultiaddrWithPeerId, NonDefaultSetConfig, NonReservedPeerMode, ProtocolId, TransportConfig, + MultiaddrWithPeerId, NetworkConfiguration, NonDefaultSetConfig, NonReservedPeerMode, + ProtocolId, RequestResponseConfig, Role, SyncMode, TransportConfig, }, protocol::{role::Roles, ProtocolName}, - service::{NetworkBlock, NetworkStateInfo, NetworkSyncForkRequest}, + service::{NetworkBlock, NetworkEventStream, NetworkStateInfo, NetworkSyncForkRequest}, sync::warp::{ AuthorityList, EncodedProof, SetId, VerificationResult, WarpSyncParams, WarpSyncProvider, }, }; use sc_network_light::light_client_requests::handler::LightClientRequestHandler; use sc_network_sync::{ - block_request_handler::BlockRequestHandler, service::network::NetworkServiceProvider, - state_request_handler::StateRequestHandler, warp_request_handler, ChainSync, + block_request_handler::BlockRequestHandler, + service::{chain_sync::SyncingService, network::NetworkServiceProvider}, + state_request_handler::StateRequestHandler, + warp_request_handler, }; use sc_service::client::Client; use sp_blockchain::{ @@ -241,7 +241,8 @@ pub struct Peer { block_import: BlockImportAdapter, select_chain: Option>, backend: Option>, - network: NetworkWorker::Hash, PeersFullClient>, + network: NetworkWorker::Hash>, + sync_service: Arc>, imported_blocks_stream: Pin> + Send>>, finality_notification_stream: Pin> + Send>>, listen_addr: Multiaddr, @@ -259,7 +260,7 @@ where /// Returns true if we're major syncing. pub fn is_major_syncing(&self) -> bool { - self.network.service().is_major_syncing() + self.sync_service.is_major_syncing() } // Returns a clone of the local SelectChain, only available on full nodes @@ -275,23 +276,23 @@ where } /// Returns the number of downloaded blocks. - pub fn num_downloaded_blocks(&self) -> usize { - self.network.num_downloaded_blocks() + pub async fn num_downloaded_blocks(&self) -> usize { + self.sync_service.num_downloaded_blocks().await.unwrap() } /// Returns true if we have no peer. pub fn is_offline(&self) -> bool { - self.num_peers() == 0 + self.sync_service.is_offline() } /// Request a justification for the given block. pub fn request_justification(&self, hash: &::Hash, number: NumberFor) { - self.network.service().request_justification(hash, number); + self.sync_service.request_justification(hash, number); } /// Announces an important block on the network. pub fn announce_block(&self, hash: ::Hash, data: Option>) { - self.network.service().announce_block(hash, data); + self.sync_service.announce_block(hash, data); } /// Request explicit fork sync. @@ -301,7 +302,7 @@ where hash: ::Hash, number: NumberFor, ) { - self.network.service().set_sync_fork_request(peers, hash, number); + self.sync_service.set_sync_fork_request(peers, hash, number); } /// Add blocks to the peer -- edit the block before adding @@ -402,14 +403,14 @@ where futures::executor::block_on(self.block_import.import_block(import_block, cache)) .expect("block_import failed"); if announce_block { - self.network.service().announce_block(hash, None); + self.sync_service.announce_block(hash, None); } hashes.push(hash); at = hash; } if inform_sync_about_new_best_block { - self.network.new_best_block_imported( + self.sync_service.new_best_block_imported( at, *full_client.header(at).ok().flatten().unwrap().number(), ); @@ -525,8 +526,12 @@ where self.network.service() } + pub fn sync_service(&self) -> &Arc> { + &self.sync_service + } + /// Get a reference to the network worker. - pub fn network(&self) -> &NetworkWorker::Hash, PeersFullClient> { + pub fn network(&self) -> &NetworkWorker::Hash> { &self.network } @@ -728,13 +733,13 @@ pub struct FullPeerConfig { } #[async_trait::async_trait] -pub trait TestNetFactory: Default + Sized +pub trait TestNetFactory: Default + Sized + Send where >::Transaction: Send, { type Verifier: 'static + Verifier; type BlockImport: BlockImport + Clone + Send + Sync + 'static; - type PeerData: Default; + type PeerData: Default + Send; /// This one needs to be implemented! fn make_verifier(&self, client: PeersClient, peer_data: &Self::PeerData) -> Self::Verifier; @@ -742,6 +747,7 @@ where /// Get reference to peer. fn peer(&mut self, i: usize) -> &mut Peer; fn peers(&self) -> &Vec>; + fn peers_mut(&mut self) -> &mut Vec>; fn mut_peers>)>( &mut self, closure: F, @@ -900,31 +906,25 @@ where let (chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::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 } => - sc_network_common::sync::SyncMode::LightState { - skip_proofs, - storage_chain_mode, - }, - 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_params), - 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()), - ) - .unwrap(); + let (engine, sync_service, block_announce_config) = + sc_network_sync::engine::SyncingEngine::new( + Roles::from(if config.is_authority { &Role::Authority } else { &Role::Full }), + client.clone(), + None, + &network_config, + protocol_id.clone(), + &fork_id, + block_announce_validator, + Some(warp_sync_params), + 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()), + ) + .unwrap(); + let sync_service_import_queue = Box::new(sync_service.clone()); + let sync_service = Arc::new(sync_service.clone()); let network = NetworkWorker::new(sc_network::config::Params { role: if config.is_authority { Role::Authority } else { Role::Full }, @@ -935,8 +935,6 @@ where chain: client.clone(), protocol_id, fork_id, - chain_sync: Box::new(chain_sync), - chain_sync_service: Box::new(chain_sync_service.clone()), metrics_registry: None, block_announce_config, request_response_protocol_configs: [ @@ -955,8 +953,14 @@ where tokio::spawn(async move { chain_sync_network_provider.run(service).await; }); + + tokio::spawn(async move { + import_queue.run(sync_service_import_queue).await; + }); + + let service = network.service().clone(); tokio::spawn(async move { - import_queue.run(Box::new(chain_sync_service)).await; + engine.run(service.event_stream("syncing")).await; }); self.mut_peers(move |peers| { @@ -979,6 +983,7 @@ where block_import, verifier, network, + sync_service, listen_addr, }); }); @@ -989,71 +994,75 @@ where tokio::spawn(f); } - /// Polls the testnet until all nodes are in sync. + /// Polls the testnet until all peers are connected to each other. /// /// Must be executed in a task context. - fn poll_until_sync(&mut self, cx: &mut FutureContext) -> Poll<()> { + fn poll_until_connected(&mut self, cx: &mut FutureContext) -> Poll<()> { self.poll(cx); - // Return `NotReady` if there's a mismatch in the highest block number. + let num_peers = self.peers().len(); + if self.peers().iter().all(|p| p.num_peers() == num_peers - 1) { + return Poll::Ready(()) + } + + Poll::Pending + } + + async fn is_in_sync(&mut self) -> bool { let mut highest = None; - for peer in self.peers().iter() { - if peer.is_major_syncing() || peer.network.num_queued_blocks() != 0 { - return Poll::Pending + let peers = self.peers_mut(); + + for peer in peers { + if peer.sync_service.is_major_syncing() || + peer.sync_service.num_queued_blocks().await.unwrap() != 0 + { + return false } - if peer.network.num_sync_requests() != 0 { - return Poll::Pending + if peer.sync_service.num_sync_requests().await.unwrap() != 0 { + return false } match (highest, peer.client.info().best_hash) { (None, b) => highest = Some(b), (Some(ref a), ref b) if a == b => {}, - (Some(_), _) => return Poll::Pending, + (Some(_), _) => return false, } } - Poll::Ready(()) - } - /// Polls the testnet until theres' no activiy of any kind. - /// - /// Must be executed in a task context. - fn poll_until_idle(&mut self, cx: &mut FutureContext) -> Poll<()> { - self.poll(cx); + true + } - for peer in self.peers().iter() { - if peer.is_major_syncing() || peer.network.num_queued_blocks() != 0 { - return Poll::Pending + async fn is_idle(&mut self) -> bool { + let peers = self.peers_mut(); + for peer in peers { + if peer.sync_service.num_queued_blocks().await.unwrap() != 0 { + return false } - if peer.network.num_sync_requests() != 0 { - return Poll::Pending + if peer.sync_service.num_sync_requests().await.unwrap() != 0 { + return false } } - Poll::Ready(()) - } - - /// Polls the testnet until all peers are connected to each other. - /// - /// Must be executed in a task context. - fn poll_until_connected(&mut self, cx: &mut FutureContext) -> Poll<()> { - self.poll(cx); - - let num_peers = self.peers().len(); - if self.peers().iter().all(|p| p.num_peers() == num_peers - 1) { - return Poll::Ready(()) - } - - Poll::Pending + true } - /// Run the network until we are sync'ed. + /// 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.) async fn run_until_sync(&mut self) { - timeout( - Duration::from_secs(10 * 60), - futures::future::poll_fn::<(), _>(|cx| self.poll_until_sync(cx)), - ) + timeout(Duration::from_secs(10 * 60), async { + loop { + futures::future::poll_fn::<(), _>(|cx| { + self.poll(cx); + Poll::Ready(()) + }) + .await; + + if self.is_in_sync().await { + break + } + } + }) .await .expect("sync didn't happen within 10 mins"); } @@ -1062,7 +1071,17 @@ where /// /// Calls `poll_until_idle` repeatedly with the runtime passed as parameter. async fn run_until_idle(&mut self) { - futures::future::poll_fn::<(), _>(|cx| self.poll_until_idle(cx)).await; + loop { + futures::future::poll_fn::<(), _>(|cx| { + self.poll(cx); + Poll::Ready(()) + }) + .await; + + if self.is_idle().await { + break + } + } } /// Run the network until all peers are connected to each other. @@ -1095,14 +1114,14 @@ where while let Poll::Ready(Some(notification)) = peer.imported_blocks_stream.as_mut().poll_next(cx) { - peer.network.service().announce_block(notification.hash, None); + peer.sync_service.announce_block(notification.hash, None); } // We poll `finality_notification_stream`. while let Poll::Ready(Some(notification)) = peer.finality_notification_stream.as_mut().poll_next(cx) { - peer.network.on_block_finalized(notification.hash, notification.header); + peer.sync_service.on_block_finalized(notification.hash, notification.header); } } }); @@ -1142,6 +1161,10 @@ impl TestNetFactory for TestNet { &self.peers } + fn peers_mut(&mut self) -> &mut Vec> { + &mut self.peers + } + fn mut_peers>)>(&mut self, closure: F) { closure(&mut self.peers); } @@ -1189,6 +1212,10 @@ impl TestNetFactory for JustificationTestNet { self.0.peers() } + fn peers_mut(&mut self) -> &mut Vec> { + self.0.peers_mut() + } + fn mut_peers>)>( &mut self, closure: F, diff --git a/client/network/test/src/sync.rs b/client/network/test/src/sync.rs index 490ec134c7ab9..d87b03fb3a78c 100644 --- a/client/network/test/src/sync.rs +++ b/client/network/test/src/sync.rs @@ -652,12 +652,12 @@ async fn imports_stale_once() { // check that NEW block is imported from announce message let new_hash = net.peer(0).push_blocks(1, false).pop().unwrap(); import_with_announce(&mut net, new_hash).await; - assert_eq!(net.peer(1).num_downloaded_blocks(), 1); + assert_eq!(net.peer(1).num_downloaded_blocks().await, 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).pop().unwrap(); import_with_announce(&mut net, known_stale_hash).await; - assert_eq!(net.peer(1).num_downloaded_blocks(), 2); + assert_eq!(net.peer(1).num_downloaded_blocks().await, 2); } #[tokio::test(flavor = "multi_thread", worker_threads = 2)] @@ -820,7 +820,7 @@ async fn sync_to_tip_requires_that_sync_protocol_is_informed_about_best_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.peer(0).sync_service().new_best_block_imported(block_hash, 3); net.run_until_idle().await; // Connect another node that should now sync to the tip @@ -865,8 +865,8 @@ async 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); + net.peer(0).sync_service().new_best_block_imported(block_hash, 10_000); + net.peer(0).sync_service().announce_block(block_hash, None); while !net.peer(2).has_block(block_hash) && !net.peer(1).has_block(block_hash) { net.run_until_idle().await; @@ -1045,14 +1045,17 @@ async fn syncs_all_forks_from_single_peer() { let branch1 = net.peer(0).push_blocks_at(BlockId::Number(10), 2, true).pop().unwrap(); // Wait till peer 1 starts downloading - futures::future::poll_fn::<(), _>(|cx| { - net.poll(cx); - if net.peer(1).network().best_seen_block() != Some(12) { - return Poll::Pending + loop { + futures::future::poll_fn::<(), _>(|cx| { + net.poll(cx); + Poll::Ready(()) + }) + .await; + + if net.peer(1).sync_service().best_seen_block().await.unwrap() == Some(12) { + break } - Poll::Ready(()) - }) - .await; + } // Peer 0 produces and announces another fork let branch2 = net.peer(0).push_blocks_at(BlockId::Number(10), 2, false).pop().unwrap(); diff --git a/client/network/transactions/src/lib.rs b/client/network/transactions/src/lib.rs index d4d08d2ab7545..48bb394946671 100644 --- a/client/network/transactions/src/lib.rs +++ b/client/network/transactions/src/lib.rs @@ -37,6 +37,7 @@ use sc_network_common::{ error, protocol::{event::Event, role::ObservedRole, ProtocolName}, service::{NetworkEventStream, NetworkNotification, NetworkPeers}, + sync::{SyncEvent, SyncEventStream}, utils::{interval, LruHashSet}, ExHashT, }; @@ -161,14 +162,17 @@ impl TransactionsHandlerPrototype { pub fn build< B: BlockT + 'static, H: ExHashT, - S: NetworkPeers + NetworkEventStream + NetworkNotification + sp_consensus::SyncOracle, + N: NetworkPeers + NetworkEventStream + NetworkNotification, + S: SyncEventStream + sp_consensus::SyncOracle, >( self, - service: S, + network: N, + sync: S, transaction_pool: Arc>, metrics_registry: Option<&Registry>, - ) -> error::Result<(TransactionsHandler, TransactionsHandlerController)> { - let event_stream = service.event_stream("transactions-handler"); + ) -> error::Result<(TransactionsHandler, TransactionsHandlerController)> { + let net_event_stream = network.event_stream("transactions-handler-net"); + let sync_event_stream = sync.event_stream("transactions-handler-sync"); let (to_handler, from_controller) = tracing_unbounded("mpsc_transactions_handler", 100_000); let handler = TransactionsHandler { @@ -178,8 +182,10 @@ impl TransactionsHandlerPrototype { .fuse(), pending_transactions: FuturesUnordered::new(), pending_transactions_peers: HashMap::new(), - service, - event_stream: event_stream.fuse(), + network, + sync, + net_event_stream: net_event_stream.fuse(), + sync_event_stream: sync_event_stream.fuse(), peers: HashMap::new(), transaction_pool, from_controller, @@ -228,7 +234,8 @@ enum ToHandler { pub struct TransactionsHandler< B: BlockT + 'static, H: ExHashT, - S: NetworkPeers + NetworkEventStream + NetworkNotification + sp_consensus::SyncOracle, + N: NetworkPeers + NetworkEventStream + NetworkNotification, + S: SyncEventStream + sp_consensus::SyncOracle, > { protocol_name: ProtocolName, /// Interval at which we call `propagate_transactions`. @@ -241,9 +248,13 @@ pub struct TransactionsHandler< /// multiple times concurrently. pending_transactions_peers: HashMap>, /// Network service to use to send messages and manage peers. - service: S, + network: N, + /// Syncing service. + sync: S, /// Stream of networking events. - event_stream: stream::Fuse + Send>>>, + net_event_stream: stream::Fuse + Send>>>, + /// Receiver for syncing-related events. + sync_event_stream: stream::Fuse + Send>>>, // All connected peers peers: HashMap>, transaction_pool: Arc>, @@ -260,11 +271,12 @@ struct Peer { role: ObservedRole, } -impl TransactionsHandler +impl TransactionsHandler where B: BlockT + 'static, H: ExHashT, - S: NetworkPeers + NetworkEventStream + NetworkNotification + sp_consensus::SyncOracle, + N: NetworkPeers + NetworkEventStream + NetworkNotification, + S: SyncEventStream + sp_consensus::SyncOracle, { /// Turns the [`TransactionsHandler`] into a future that should run forever and not be /// interrupted. @@ -281,7 +293,7 @@ where warn!(target: "sub-libp2p", "Inconsistent state, no peers for pending transaction!"); } }, - network_event = self.event_stream.next() => { + network_event = self.net_event_stream.next() => { if let Some(network_event) = network_event { self.handle_network_event(network_event).await; } else { @@ -289,6 +301,14 @@ where return; } }, + sync_event = self.sync_event_stream.next() => { + if let Some(sync_event) = sync_event { + self.handle_sync_event(sync_event); + } else { + // Syncing has seemingly closed. Closing as well. + return; + } + } message = self.from_controller.select_next_some() => { match message { ToHandler::PropagateTransaction(hash) => self.propagate_transaction(&hash), @@ -299,13 +319,12 @@ where } } - async fn handle_network_event(&mut self, event: Event) { + fn handle_sync_event(&mut self, event: SyncEvent) { match event { - Event::Dht(_) => {}, - Event::SyncConnected { remote } => { + SyncEvent::PeerConnected(remote) => { let addr = iter::once(multiaddr::Protocol::P2p(remote.into())) .collect::(); - let result = self.service.add_peers_to_reserved_set( + let result = self.network.add_peers_to_reserved_set( self.protocol_name.clone(), iter::once(addr).collect(), ); @@ -313,13 +332,18 @@ where log::error!(target: "sync", "Add reserved peer failed: {}", err); } }, - Event::SyncDisconnected { remote } => { - self.service.remove_peers_from_reserved_set( + SyncEvent::PeerDisconnected(remote) => { + self.network.remove_peers_from_reserved_set( self.protocol_name.clone(), iter::once(remote).collect(), ); }, + } + } + async fn handle_network_event(&mut self, event: Event) { + match event { + Event::Dht(_) => {}, Event::NotificationStreamOpened { remote, protocol, role, .. } if protocol == self.protocol_name => { @@ -365,7 +389,7 @@ where /// Called when peer sends us new transactions fn on_transactions(&mut self, who: PeerId, transactions: Transactions) { // Accept transactions only when node is not major syncing - if self.service.is_major_syncing() { + if self.sync.is_major_syncing() { trace!(target: "sync", "{} Ignoring transactions while major syncing", who); return } @@ -385,7 +409,7 @@ where let hash = self.transaction_pool.hash_of(&t); peer.known_transactions.insert(hash.clone()); - self.service.report_peer(who, rep::ANY_TRANSACTION); + self.network.report_peer(who, rep::ANY_TRANSACTION); match self.pending_transactions_peers.entry(hash.clone()) { Entry::Vacant(entry) => { @@ -406,9 +430,9 @@ where fn on_handle_transaction_import(&mut self, who: PeerId, import: TransactionImport) { match import { TransactionImport::KnownGood => - self.service.report_peer(who, rep::ANY_TRANSACTION_REFUND), - TransactionImport::NewGood => self.service.report_peer(who, rep::GOOD_TRANSACTION), - TransactionImport::Bad => self.service.report_peer(who, rep::BAD_TRANSACTION), + self.network.report_peer(who, rep::ANY_TRANSACTION_REFUND), + TransactionImport::NewGood => self.network.report_peer(who, rep::GOOD_TRANSACTION), + TransactionImport::Bad => self.network.report_peer(who, rep::BAD_TRANSACTION), TransactionImport::None => {}, } } @@ -416,7 +440,7 @@ where /// Propagate one transaction. pub fn propagate_transaction(&mut self, hash: &H) { // Accept transactions only when node is not major syncing - if self.service.is_major_syncing() { + if self.sync.is_major_syncing() { return } @@ -453,7 +477,7 @@ where propagated_to.entry(hash).or_default().push(who.to_base58()); } trace!(target: "sync", "Sending {} transactions to {}", to_send.len(), who); - self.service + self.network .write_notification(*who, self.protocol_name.clone(), to_send.encode()); } } @@ -468,7 +492,7 @@ where /// Call when we must propagate ready transactions to peers. fn propagate_transactions(&mut self) { // Accept transactions only when node is not major syncing - if self.service.is_major_syncing() { + if self.sync.is_major_syncing() { return } diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index 2c690dcd2f8ac..ea4b630003123 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -38,18 +38,19 @@ 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::NetworkService; use sc_network_bitswap::BitswapRequestHandler; use sc_network_common::{ + config::SyncMode, protocol::role::Roles, - service::{NetworkStateInfo, NetworkStatusProvider}, + service::{NetworkEventStream, NetworkStateInfo, NetworkStatusProvider}, sync::warp::WarpSyncParams, }; use sc_network_light::light_client_requests::handler::LightClientRequestHandler; use sc_network_sync::{ - block_request_handler::BlockRequestHandler, service::network::NetworkServiceProvider, - state_request_handler::StateRequestHandler, - warp_request_handler::RequestHandler as WarpSyncRequestHandler, ChainSync, + block_request_handler::BlockRequestHandler, engine::SyncingEngine, + service::network::NetworkServiceProvider, state_request_handler::StateRequestHandler, + warp_request_handler::RequestHandler as WarpSyncRequestHandler, SyncingService, }; use sc_rpc::{ author::AuthorApiServer, @@ -349,12 +350,7 @@ where /// Shared network instance implementing a set of mandatory traits. pub trait SpawnTaskNetwork: - sc_offchain::NetworkProvider - + NetworkStateInfo - + NetworkStatusProvider - + Send - + Sync - + 'static + sc_offchain::NetworkProvider + NetworkStateInfo + NetworkStatusProvider + Send + Sync + 'static { } @@ -363,7 +359,7 @@ where Block: BlockT, T: sc_offchain::NetworkProvider + NetworkStateInfo - + NetworkStatusProvider + + NetworkStatusProvider + Send + Sync + 'static, @@ -394,6 +390,8 @@ pub struct SpawnTasksParams<'a, TBl: BlockT, TCl, TExPool, TRpc, Backend> { /// Controller for transactions handlers pub tx_handler_controller: sc_network_transactions::TransactionsHandlerController<::Hash>, + /// Syncing service. + pub sync_service: Arc>, /// Telemetry instance for this node. pub telemetry: Option<&'a mut Telemetry>, } @@ -471,6 +469,7 @@ where network, system_rpc_tx, tx_handler_controller, + sync_service, telemetry, } = params; @@ -533,7 +532,12 @@ where spawn_handle.spawn( "telemetry-periodic-send", None, - metrics_service.run(client.clone(), transaction_pool.clone(), network.clone()), + metrics_service.run( + client.clone(), + transaction_pool.clone(), + network.clone(), + sync_service.clone(), + ), ); let rpc_id_provider = config.rpc_id_provider.take(); @@ -560,7 +564,12 @@ where spawn_handle.spawn( "informant", None, - sc_informant::build(client.clone(), network, config.informant_output_format), + sc_informant::build( + client.clone(), + network, + sync_service.clone(), + config.informant_output_format, + ), ); task_manager.keep_alive((config.base_path, rpc)); @@ -771,6 +780,7 @@ pub fn build_network( TracingUnboundedSender>, sc_network_transactions::TransactionsHandlerController<::Hash>, NetworkStarter, + Arc>, ), Error, > @@ -876,27 +886,23 @@ where }; let (chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::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 } => - sc_network_common::sync::SyncMode::LightState { skip_proofs, storage_chain_mode }, - SyncMode::Warp => sc_network_common::sync::SyncMode::Warp, - }, + let (engine, sync_service, block_announce_config) = SyncingEngine::new( + Roles::from(&config.role), client.clone(), + config.prometheus_config.as_ref().map(|config| config.registry.clone()).as_ref(), + &config.network, 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_params, - 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()), )?; + let sync_service_import_queue = sync_service.clone(); + let sync_service = Arc::new(sync_service); request_response_protocol_configs.push(config.network.ipfs_server.then(|| { let (handler, protocol_config) = BitswapRequestHandler::new(client.clone()); @@ -916,8 +922,6 @@ where chain: client.clone(), protocol_id: protocol_id.clone(), fork_id: config.chain_spec.fork_id().map(ToOwned::to_owned), - chain_sync: Box::new(chain_sync), - 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 @@ -953,6 +957,7 @@ where let (tx_handler, tx_handler_controller) = transactions_handler_proto.build( network.clone(), + sync_service.clone(), Arc::new(TransactionPoolAdapter { pool: transaction_pool, client: client.clone() }), config.prometheus_config.as_ref().map(|config| &config.registry), )?; @@ -963,11 +968,10 @@ where Some("networking"), chain_sync_network_provider.run(network.clone()), ); - spawn_handle.spawn( - "import-queue", - None, - import_queue.run(Box::new(chain_sync_service.clone())), - ); + spawn_handle.spawn("import-queue", None, import_queue.run(Box::new(sync_service_import_queue))); + + let event_stream = network.event_stream("syncing"); + spawn_handle.spawn("syncing", None, engine.run(event_stream)); let (system_rpc_tx, system_rpc_rx) = tracing_unbounded("mpsc_system_rpc", 10_000); spawn_handle.spawn( @@ -976,7 +980,7 @@ where build_system_rpc_future( config.role.clone(), network_mut.service().clone(), - chain_sync_service.clone(), + sync_service.clone(), client.clone(), system_rpc_rx, has_bootnodes, @@ -984,7 +988,7 @@ where ); let future = - build_network_future(network_mut, client, chain_sync_service, config.announce_block); + build_network_future(network_mut, client, sync_service.clone(), config.announce_block); // TODO: Normally, one is supposed to pass a list of notifications protocols supported by the // node through the `NetworkConfiguration` struct. But because this function doesn't know in @@ -1022,7 +1026,13 @@ where future.await }); - Ok((network, system_rpc_tx, tx_handler_controller, NetworkStarter(network_start_tx))) + Ok(( + network, + system_rpc_tx, + tx_handler_controller, + NetworkStarter(network_start_tx), + sync_service.clone(), + )) } /// Object used to start the network. diff --git a/client/service/src/config.rs b/client/service/src/config.rs index 7f3a2e3c0bb25..8e843b58f285e 100644 --- a/client/service/src/config.rs +++ b/client/service/src/config.rs @@ -22,11 +22,14 @@ pub use sc_client_api::execution_extensions::{ExecutionStrategies, ExecutionStra pub use sc_client_db::{BlocksPruning, Database, DatabaseSource, PruningMode}; pub use sc_executor::{WasmExecutionMethod, WasmtimeInstantiationStrategy}; pub use sc_network::{ - config::{NetworkConfiguration, NodeKeyConfig, Role}, + config::{NetworkConfiguration, Role}, Multiaddr, }; pub use sc_network_common::{ - config::{MultiaddrWithPeerId, NonDefaultSetConfig, ProtocolId, SetConfig, TransportConfig}, + config::{ + MultiaddrWithPeerId, NodeKeyConfig, NonDefaultSetConfig, ProtocolId, SetConfig, + TransportConfig, + }, request_responses::{ IncomingRequest, OutgoingResponse, ProtocolConfig as RequestResponseConfig, }, @@ -34,7 +37,7 @@ pub use sc_network_common::{ use prometheus_endpoint::Registry; use sc_chain_spec::ChainSpec; -use sc_network::config::SyncMode; +use sc_network_common::config::SyncMode; pub use sc_telemetry::TelemetryEndpoints; pub use sc_transaction_pool::Options as TransactionPoolOptions; use sp_core::crypto::SecretString; diff --git a/client/service/src/lib.rs b/client/service/src/lib.rs index 6bafa9936c0bf..8e674ca44a125 100644 --- a/client/service/src/lib.rs +++ b/client/service/src/lib.rs @@ -46,7 +46,7 @@ use sc_network_common::{ config::MultiaddrWithPeerId, service::{NetworkBlock, NetworkPeers}, }; -use sc_network_sync::service::chain_sync::ChainSyncInterfaceHandle; +use sc_network_sync::SyncingService; use sc_utils::mpsc::TracingUnboundedReceiver; use sp_blockchain::HeaderMetadata; use sp_consensus::SyncOracle; @@ -158,9 +158,9 @@ async fn build_network_future< + 'static, H: sc_network_common::ExHashT, >( - network: sc_network::NetworkWorker, + network: sc_network::NetworkWorker, client: Arc, - chain_sync_service: ChainSyncInterfaceHandle, + sync_service: Arc>, announce_imported_blocks: bool, ) { let mut imported_blocks_stream = client.import_notification_stream().fuse(); @@ -168,8 +168,6 @@ async fn build_network_future< // Stream of finalized blocks reported by the client. let mut finality_notification_stream = client.finality_notification_stream().fuse(); - let network_service = network.service().clone(); - let network_run = network.run().fuse(); pin_mut!(network_run); @@ -188,11 +186,11 @@ async fn build_network_future< }; if announce_imported_blocks { - network_service.announce_block(notification.hash, None); + sync_service.announce_block(notification.hash, None); } if notification.is_new_best { - network_service.new_best_block_imported( + sync_service.new_best_block_imported( notification.hash, *notification.header.number(), ); @@ -201,7 +199,7 @@ async fn build_network_future< // List of blocks that the client has finalized. notification = finality_notification_stream.select_next_some() => { - chain_sync_service.on_block_finalized(notification.hash, *notification.header.number()); + sync_service.on_block_finalized(notification.hash, notification.header); } // Drive the network. Shut down the network future if `NetworkWorker` has terminated. @@ -228,7 +226,7 @@ async fn build_system_rpc_future< >( role: Role, network_service: Arc>, - chain_sync_service: ChainSyncInterfaceHandle, + sync_service: Arc>, client: Arc, mut rpc_rx: TracingUnboundedReceiver>, should_have_peers: bool, @@ -244,23 +242,21 @@ async fn build_system_rpc_future< }; match req { - sc_rpc::system::Request::Health(sender) => { - let peers = network_service.peers_debug_info().await; - if let Ok(peers) = peers { + sc_rpc::system::Request::Health(sender) => match sync_service.peers_info().await { + Ok(info) => { let _ = sender.send(sc_rpc::system::Health { - peers: peers.len(), - is_syncing: network_service.is_major_syncing(), + peers: info.len(), + is_syncing: sync_service.is_major_syncing(), should_have_peers, }); - } else { - break - } + }, + Err(_) => log::error!("`SyncingEngine` shut down"), }, sc_rpc::system::Request::LocalPeerId(sender) => { let _ = sender.send(network_service.local_peer_id().to_base58()); }, sc_rpc::system::Request::LocalListenAddresses(sender) => { - let peer_id = network_service.local_peer_id().into(); + let peer_id = (network_service.local_peer_id()).into(); let p2p_proto_suffix = sc_network::multiaddr::Protocol::P2p(peer_id); let addresses = network_service .listen_addresses() @@ -269,12 +265,10 @@ async fn build_system_rpc_future< .collect(); let _ = sender.send(addresses); }, - sc_rpc::system::Request::Peers(sender) => { - let peers = network_service.peers_debug_info().await; - if let Ok(peers) = peers { + sc_rpc::system::Request::Peers(sender) => match sync_service.peers_info().await { + Ok(info) => { let _ = sender.send( - peers - .into_iter() + info.into_iter() .map(|(peer_id, p)| sc_rpc::system::PeerInfo { peer_id: peer_id.to_base58(), roles: format!("{:?}", p.roles), @@ -283,9 +277,8 @@ async fn build_system_rpc_future< }) .collect(), ); - } else { - break - } + }, + Err(_) => log::error!("`SyncingEngine` shut down"), }, sc_rpc::system::Request::NetworkState(sender) => { let network_state = network_service.network_state().await; @@ -339,21 +332,21 @@ async fn build_system_rpc_future< sc_rpc::system::Request::SyncState(sender) => { use sc_rpc::system::SyncState; - let best_number = client.info().best_number; - - let Ok(status) = chain_sync_service.status().await else { - debug!("`ChainSync` has terminated, shutting down the system RPC future."); - return - }; - - let _ = sender.send(SyncState { - starting_block, - current_block: best_number, - highest_block: status.best_seen_block.unwrap_or(best_number), - }); + match sync_service.best_seen_block().await { + Ok(best_seen_block) => { + let best_number = client.info().best_number; + let _ = sender.send(SyncState { + starting_block, + current_block: best_number, + highest_block: best_seen_block.unwrap_or(best_number), + }); + }, + Err(_) => log::error!("`SyncingEngine` shut down"), + } }, } } + debug!("`NetworkWorker` has terminated, shutting down the system RPC future."); } diff --git a/client/service/src/metrics.rs b/client/service/src/metrics.rs index 19c64e953667d..967e3133dbea9 100644 --- a/client/service/src/metrics.rs +++ b/client/service/src/metrics.rs @@ -23,7 +23,10 @@ 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; -use sc_network_common::service::{NetworkStatus, NetworkStatusProvider}; +use sc_network_common::{ + service::{NetworkStatus, NetworkStatusProvider}, + sync::{SyncStatus, SyncStatusProvider}, +}; use sc_telemetry::{telemetry, TelemetryHandle, SUBSTRATE_INFO}; use sc_transaction_pool_api::{MaintainedTransactionPool, PoolStatus}; use sc_utils::metrics::register_globals; @@ -175,16 +178,18 @@ 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: TNet, + syncing: TSync, ) where TBl: Block, TCl: ProvideRuntimeApi + UsageProvider, TExPool: MaintainedTransactionPool::Hash>, - TNet: NetworkStatusProvider, + TNet: NetworkStatusProvider, + TSync: SyncStatusProvider, { let mut timer = Delay::new(Duration::from_secs(0)); let timer_interval = Duration::from_secs(5); @@ -196,8 +201,11 @@ impl MetricsService { // Try to get the latest network information. let net_status = network.status().await.ok(); + // Try to get the latest syncing information. + let sync_status = syncing.status().await.ok(); + // Update / Send the metrics. - self.update(&client.usage_info(), &transactions.status(), net_status); + self.update(&client.usage_info(), &transactions.status(), net_status, sync_status); // Schedule next tick. timer.reset(timer_interval); @@ -208,7 +216,8 @@ impl MetricsService { &mut self, info: &ClientInfo, txpool_status: &PoolStatus, - net_status: Option>, + net_status: Option, + sync_status: Option>, ) { let now = Instant::now(); let elapsed = (now - self.last_update).as_secs(); @@ -273,10 +282,12 @@ impl MetricsService { "bandwidth_download" => avg_bytes_per_sec_inbound, "bandwidth_upload" => avg_bytes_per_sec_outbound, ); + } + if let Some(sync_status) = sync_status { if let Some(metrics) = self.metrics.as_ref() { let best_seen_block: Option = - net_status.best_seen_block.map(|num: NumberFor| { + sync_status.best_seen_block.map(|num: NumberFor| { UniqueSaturatedInto::::unique_saturated_into(num) }); diff --git a/client/service/test/Cargo.toml b/client/service/test/Cargo.toml index 488fe76c333bc..f58b8c295ed76 100644 --- a/client/service/test/Cargo.toml +++ b/client/service/test/Cargo.toml @@ -27,6 +27,7 @@ sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/commo 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-network-sync = { version = "0.10.0-dev", path = "../../network/sync" } 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 655aff2423094..b1a09a0620fcd 100644 --- a/client/service/test/src/lib.rs +++ b/client/service/test/src/lib.rs @@ -27,6 +27,7 @@ use sc_network_common::{ config::{MultiaddrWithPeerId, TransportConfig}, service::{NetworkBlock, NetworkPeers, NetworkStateInfo}, }; +use sc_network_sync::SyncingService; use sc_service::{ client::Client, config::{BasePath, DatabaseSource, KeystoreConfig}, @@ -79,6 +80,7 @@ pub trait TestNetNode: fn network( &self, ) -> Arc::Hash>>; + fn sync(&self) -> &Arc>; fn spawn_handle(&self) -> SpawnTaskHandle; } @@ -87,6 +89,7 @@ pub struct TestNetComponents { client: Arc>, transaction_pool: Arc, network: Arc::Hash>>, + sync: Arc>, } impl @@ -96,9 +99,16 @@ impl task_manager: TaskManager, client: Arc>, network: Arc::Hash>>, + sync: Arc>, transaction_pool: Arc, ) -> Self { - Self { client, transaction_pool, network, task_manager: Arc::new(Mutex::new(task_manager)) } + Self { + client, + sync, + transaction_pool, + network, + task_manager: Arc::new(Mutex::new(task_manager)), + } } } @@ -111,6 +121,7 @@ impl Clone client: self.client.clone(), transaction_pool: self.transaction_pool.clone(), network: self.network.clone(), + sync: self.sync.clone(), } } } @@ -151,6 +162,9 @@ where ) -> Arc::Hash>> { self.network.clone() } + fn sync(&self) -> &Arc> { + &self.sync + } fn spawn_handle(&self) -> SpawnTaskHandle { self.task_manager.lock().spawn_handle() } @@ -477,7 +491,7 @@ pub fn sync( let info = network.full_nodes[0].1.client().info(); network.full_nodes[0] .1 - .network() + .sync() .new_best_block_imported(info.best_hash, info.best_number); network.full_nodes[0].3.clone() }; From 0f5a22a04d944d6e46877313a929c2cec99d3c88 Mon Sep 17 00:00:00 2001 From: Liu-Cheng Xu Date: Tue, 7 Mar 2023 04:39:32 +0800 Subject: [PATCH 475/715] Expose `new_full_parts_with_genesis_builder` from sc-service (#13539) I forgot this in https://github.com/paritytech/substrate/pull/12291 --- client/service/src/lib.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/client/service/src/lib.rs b/client/service/src/lib.rs index 8e674ca44a125..9dab81a5b4ed9 100644 --- a/client/service/src/lib.rs +++ b/client/service/src/lib.rs @@ -58,8 +58,9 @@ use sp_runtime::{ 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, - SpawnTasksParams, TFullBackend, TFullCallExecutor, TFullClient, + new_full_parts, new_full_parts_with_genesis_builder, spawn_tasks, BuildNetworkParams, + KeystoreContainer, NetworkStarter, SpawnTasksParams, TFullBackend, TFullCallExecutor, + TFullClient, }, client::{ClientConfig, LocalCallExecutor}, error::Error, From 2aa2b4ef88af23e970da55d7b9b420f8f552ba99 Mon Sep 17 00:00:00 2001 From: Dmitry Markin Date: Tue, 7 Mar 2023 10:57:26 +0300 Subject: [PATCH 476/715] Make unbounded channels size warning exact (part 2) (#13504) --- Cargo.lock | 4 +- .../common/src/import_queue/basic_queue.rs | 58 +-- .../common/src/import_queue/buffered_link.rs | 4 +- client/service/src/task_manager/mod.rs | 2 +- client/service/test/Cargo.toml | 1 + client/service/test/src/client/mod.rs | 20 +- client/utils/Cargo.toml | 3 +- client/utils/README.md | 17 +- client/utils/src/lib.rs | 14 +- client/utils/src/metrics.rs | 4 - client/utils/src/mpsc.rs | 389 ++++++------------ client/utils/src/notification.rs | 2 +- client/utils/src/pubsub.rs | 2 +- .../src/pubsub/tests/normal_operation.rs | 3 +- 14 files changed, 196 insertions(+), 327 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 72b5943d48b3f..e0cc2c1074f80 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9231,6 +9231,7 @@ name = "sc-service-test" version = "2.0.0" dependencies = [ "array-bytes", + "async-channel", "fdlimit", "futures", "log", @@ -9435,13 +9436,14 @@ dependencies = [ name = "sc-utils" version = "4.0.0-dev" dependencies = [ - "backtrace", + "async-channel", "futures", "futures-timer", "lazy_static", "log", "parking_lot 0.12.1", "prometheus", + "sp-arithmetic", "tokio-test", ] diff --git a/client/consensus/common/src/import_queue/basic_queue.rs b/client/consensus/common/src/import_queue/basic_queue.rs index 06122491eedce..6404708151f00 100644 --- a/client/consensus/common/src/import_queue/basic_queue.rs +++ b/client/consensus/common/src/import_queue/basic_queue.rs @@ -118,8 +118,8 @@ impl BasicQueueHandle { } pub fn close(&mut self) { - self.justification_sender.close_channel(); - self.block_import_sender.close_channel(); + self.justification_sender.close(); + self.block_import_sender.close(); } } @@ -597,11 +597,11 @@ mod tests { fn prioritizes_finality_work_over_block_import() { let (result_sender, mut result_port) = buffered_link::buffered_link(100_000); - let (worker, mut finality_sender, mut block_import_sender) = + let (worker, finality_sender, block_import_sender) = BlockImportWorker::new(result_sender, (), Box::new(()), Some(Box::new(())), None); futures::pin_mut!(worker); - let mut import_block = |n| { + let import_block = |n| { let header = Header { parent_hash: Hash::random(), number: n, @@ -612,35 +612,37 @@ mod tests { let hash = header.hash(); - block_on(block_import_sender.send(worker_messages::ImportBlocks( - BlockOrigin::Own, - vec![IncomingBlock { - hash, - header: Some(header), - body: None, - indexed_body: None, - justifications: None, - origin: None, - allow_missing_state: false, - import_existing: false, - state: None, - skip_execution: false, - }], - ))) - .unwrap(); + block_import_sender + .unbounded_send(worker_messages::ImportBlocks( + BlockOrigin::Own, + vec![IncomingBlock { + hash, + header: Some(header), + body: None, + indexed_body: None, + justifications: None, + origin: None, + allow_missing_state: false, + import_existing: false, + state: None, + skip_execution: false, + }], + )) + .unwrap(); hash }; - let mut import_justification = || { + let import_justification = || { let hash = Hash::random(); - block_on(finality_sender.send(worker_messages::ImportJustification( - libp2p::PeerId::random(), - hash, - 1, - (*b"TEST", Vec::new()), - ))) - .unwrap(); + finality_sender + .unbounded_send(worker_messages::ImportJustification( + libp2p::PeerId::random(), + hash, + 1, + (*b"TEST", Vec::new()), + )) + .unwrap(); hash }; diff --git a/client/consensus/common/src/import_queue/buffered_link.rs b/client/consensus/common/src/import_queue/buffered_link.rs index 5c95cbc4260e1..c23a4b0d5d0ab 100644 --- a/client/consensus/common/src/import_queue/buffered_link.rs +++ b/client/consensus/common/src/import_queue/buffered_link.rs @@ -53,7 +53,7 @@ use super::BlockImportResult; /// can be used to buffer commands, and the receiver can be used to poll said commands and transfer /// them to another link. `queue_size_warning` sets the warning threshold of the channel queue size. pub fn buffered_link( - queue_size_warning: i64, + queue_size_warning: usize, ) -> (BufferedLinkSender, BufferedLinkReceiver) { let (tx, rx) = tracing_unbounded("mpsc_buffered_link", queue_size_warning); let tx = BufferedLinkSender { tx }; @@ -166,7 +166,7 @@ impl BufferedLinkReceiver { } /// Close the channel. - pub fn close(&mut self) { + pub fn close(&mut self) -> bool { self.rx.get_mut().close() } } diff --git a/client/service/src/task_manager/mod.rs b/client/service/src/task_manager/mod.rs index 8dc4748b089ee..afccee9033e36 100644 --- a/client/service/src/task_manager/mod.rs +++ b/client/service/src/task_manager/mod.rs @@ -281,7 +281,7 @@ impl SpawnEssentialTaskHandle { let essential_failed = self.essential_failed_tx.clone(); let essential_task = std::panic::AssertUnwindSafe(task).catch_unwind().map(move |_| { log::error!("Essential task `{}` failed. Shutting down service.", name); - let _ = essential_failed.close_channel(); + let _ = essential_failed.close(); }); let _ = self.inner.spawn_inner(name, group, essential_task, task_type); diff --git a/client/service/test/Cargo.toml b/client/service/test/Cargo.toml index f58b8c295ed76..94a844aa7dc0d 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] +async-channel = "1.8.0" array-bytes = "4.1" fdlimit = "0.2.1" futures = "0.3.21" diff --git a/client/service/test/src/client/mod.rs b/client/service/test/src/client/mod.rs index f8988c5a454c3..c7b19ca8ba27f 100644 --- a/client/service/test/src/client/mod.rs +++ b/client/service/test/src/client/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 . +use async_channel::TryRecvError; use futures::executor::block_on; use parity_scale_codec::{Decode, Encode, Joiner}; use sc_block_builder::BlockBuilderProvider; @@ -175,16 +176,17 @@ fn finality_notification_check( finalized: &[Hash], stale_heads: &[Hash], ) { - match notifications.try_next() { - Ok(Some(notif)) => { + match notifications.try_recv() { + Ok(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()), + Err(TryRecvError::Closed) => + panic!("unexpected notification result, client send channel was closed"), + Err(TryRecvError::Empty) => assert!(finalized.is_empty()), } } @@ -983,7 +985,7 @@ fn import_with_justification() { 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()); + assert!(matches!(finality_notifications.try_recv().unwrap_err(), TryRecvError::Empty)); } #[test] @@ -1038,7 +1040,7 @@ fn importing_diverged_finalized_block_should_trigger_reorg() { 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()); + assert!(matches!(finality_notifications.try_recv().unwrap_err(), TryRecvError::Empty)); } #[test] @@ -1124,7 +1126,7 @@ fn finalizing_diverged_block_should_trigger_reorg() { 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()); + assert!(matches!(finality_notifications.try_recv().unwrap_err(), TryRecvError::Empty)); } #[test] @@ -1227,7 +1229,7 @@ fn finality_notifications_content() { 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()); + assert!(matches!(finality_notifications.try_recv().unwrap_err(), TryRecvError::Empty)); } #[test] @@ -1437,7 +1439,7 @@ fn doesnt_import_blocks_that_revert_finality() { finality_notification_check(&mut finality_notifications, &[a3.hash()], &[b2.hash()]); - assert!(finality_notifications.try_next().is_err()); + assert!(matches!(finality_notifications.try_recv().unwrap_err(), TryRecvError::Empty)); } #[test] diff --git a/client/utils/Cargo.toml b/client/utils/Cargo.toml index e80588453597e..38484285d3065 100644 --- a/client/utils/Cargo.toml +++ b/client/utils/Cargo.toml @@ -10,13 +10,14 @@ description = "I/O for Substrate runtimes" readme = "README.md" [dependencies] -backtrace = "0.3.67" +async-channel = "1.8.0" futures = "0.3.21" futures-timer = "3.0.2" lazy_static = "1.4.0" log = "0.4" parking_lot = "0.12.1" prometheus = { version = "0.13.0", default-features = false } +sp-arithmetic = { version = "6.0.0", default-features = false, path = "../../primitives/arithmetic" } [features] default = ["metered"] diff --git a/client/utils/README.md b/client/utils/README.md index 2da70f09ccbc5..d20fe69efc5ac 100644 --- a/client/utils/README.md +++ b/client/utils/README.md @@ -1,16 +1,11 @@ -Utilities Primitives for Substrate +# Utilities Primitives for Substrate -## Features +This crate provides `mpsc::tracing_unbounded` function that returns wrapper types to +`async_channel::Sender` and `async_channel::Receiver`, which register every +`send`/`received`/`dropped` action happened on the channel. -### metered - -This feature changes the behaviour of the function `mpsc::tracing_unbounded`. -With the disabled feature this function is an alias to `futures::channel::mpsc::unbounded`. -However, when the feature is enabled it creates wrapper types to `UnboundedSender` -and `UnboundedReceiver` to register every `send`/`received`/`dropped` action happened on -the channel. - -Also this feature creates and registers a prometheus vector with name `unbounded_channel_len` and labels: +Also this wrapper creates and registers a prometheus vector with name `unbounded_channel_len` +and labels: | Label | Description | | ------------ | --------------------------------------------- | diff --git a/client/utils/src/lib.rs b/client/utils/src/lib.rs index f0cc1efe6111c..017fc76207d27 100644 --- a/client/utils/src/lib.rs +++ b/client/utils/src/lib.rs @@ -18,17 +18,11 @@ //! Utilities Primitives for Substrate //! -//! # Features +//! This crate provides `mpsc::tracing_unbounded` function that returns wrapper types to +//! `async_channel::Sender` and `async_channel::Receiver`, which register every +//! `send`/`received`/`dropped` action happened on the channel. //! -//! ## metered -//! -//! This feature changes the behaviour of the function `mpsc::tracing_unbounded`. -//! With the disabled feature this function is an alias to `futures::channel::mpsc::unbounded`. -//! However, when the feature is enabled it creates wrapper types to `UnboundedSender` -//! and `UnboundedReceiver` to register every `send`/`received`/`dropped` action happened on -//! the channel. -//! -//! Also this feature creates and registers a prometheus vector with name `unbounded_channel_len` +//! Also this wrapper creates and registers a prometheus vector with name `unbounded_channel_len` //! and labels: //! //! | Label | Description | diff --git a/client/utils/src/metrics.rs b/client/utils/src/metrics.rs index c2b10100f229f..6bbdbe2e2e599 100644 --- a/client/utils/src/metrics.rs +++ b/client/utils/src/metrics.rs @@ -24,7 +24,6 @@ use prometheus::{ Error as PrometheusError, Registry, }; -#[cfg(feature = "metered")] use prometheus::{core::GenericCounterVec, Opts}; lazy_static! { @@ -36,7 +35,6 @@ lazy_static! { .expect("Creating of statics doesn't fail. qed"); } -#[cfg(feature = "metered")] lazy_static! { pub static ref UNBOUNDED_CHANNELS_COUNTER : GenericCounterVec = GenericCounterVec::new( Opts::new("substrate_unbounded_channel_len", "Items in each mpsc::unbounded instance"), @@ -49,8 +47,6 @@ lazy_static! { pub fn register_globals(registry: &Registry) -> Result<(), PrometheusError> { registry.register(Box::new(TOKIO_THREADS_ALIVE.clone()))?; registry.register(Box::new(TOKIO_THREADS_TOTAL.clone()))?; - - #[cfg(feature = "metered")] registry.register(Box::new(UNBOUNDED_CHANNELS_COUNTER.clone()))?; Ok(()) diff --git a/client/utils/src/mpsc.rs b/client/utils/src/mpsc.rs index df45e33ff8ee5..3f783b10060bd 100644 --- a/client/utils/src/mpsc.rs +++ b/client/utils/src/mpsc.rs @@ -16,287 +16,164 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -//! Features to meter unbounded channels - -#[cfg(not(feature = "metered"))] -mod inner { - // just aliased, non performance implications - use futures::channel::mpsc::{self, UnboundedReceiver, UnboundedSender}; - pub type TracingUnboundedSender = UnboundedSender; - pub type TracingUnboundedReceiver = UnboundedReceiver; - - /// Alias `mpsc::unbounded` - pub fn tracing_unbounded( - _key: &'static str, - ) -> (TracingUnboundedSender, TracingUnboundedReceiver) { - mpsc::unbounded() - } +//! Code to meter unbounded channels. + +use crate::metrics::UNBOUNDED_CHANNELS_COUNTER; +use async_channel::{Receiver, Sender, TryRecvError, TrySendError}; +use futures::{ + stream::{FusedStream, Stream}, + task::{Context, Poll}, +}; +use log::error; +use sp_arithmetic::traits::SaturatedConversion; +use std::{ + backtrace::Backtrace, + pin::Pin, + sync::{ + atomic::{AtomicBool, Ordering}, + Arc, + }, +}; + +/// Wrapper Type around [`async_channel::Sender`] that increases the global +/// measure when a message is added. +#[derive(Debug)] +pub struct TracingUnboundedSender { + inner: Sender, + name: &'static str, + queue_size_warning: usize, + warning_fired: Arc, + creation_backtrace: Arc, } -#[cfg(feature = "metered")] -mod inner { - // tracing implementation - use crate::metrics::UNBOUNDED_CHANNELS_COUNTER; - use backtrace::Backtrace; - use futures::{ - channel::mpsc::{ - self, SendError, TryRecvError, TrySendError, UnboundedReceiver, UnboundedSender, - }, - sink::Sink, - stream::{FusedStream, Stream}, - task::{Context, Poll}, - }; - use log::error; - use std::{ - pin::Pin, - sync::{ - atomic::{AtomicBool, AtomicI64, Ordering}, - Arc, - }, - }; - - /// Wrapper Type around `UnboundedSender` that increases the global - /// measure when a message is added - #[derive(Debug)] - pub struct TracingUnboundedSender { - inner: UnboundedSender, - name: &'static str, - // To not bother with ordering and possible underflow errors of the unsigned counter - // we just use `i64` and `Ordering::Relaxed`, and perceive `queue_size` as approximate. - // It can turn < 0 though. - queue_size: Arc, - queue_size_warning: i64, - warning_fired: Arc, - creation_backtrace: Arc, - } - - // Strangely, deriving `Clone` requires that `T` is also `Clone`. - impl Clone for TracingUnboundedSender { - fn clone(&self) -> Self { - Self { - inner: self.inner.clone(), - name: self.name, - queue_size: self.queue_size.clone(), - queue_size_warning: self.queue_size_warning, - warning_fired: self.warning_fired.clone(), - creation_backtrace: self.creation_backtrace.clone(), - } +// Strangely, deriving `Clone` requires that `T` is also `Clone`. +impl Clone for TracingUnboundedSender { + fn clone(&self) -> Self { + Self { + inner: self.inner.clone(), + name: self.name, + queue_size_warning: self.queue_size_warning, + warning_fired: self.warning_fired.clone(), + creation_backtrace: self.creation_backtrace.clone(), } } +} - /// Wrapper Type around `UnboundedReceiver` that decreases the global - /// measure when a message is polled - #[derive(Debug)] - pub struct TracingUnboundedReceiver { - inner: UnboundedReceiver, - name: &'static str, - queue_size: Arc, - } - - /// Wrapper around `mpsc::unbounded` that tracks the in- and outflow via - /// `UNBOUNDED_CHANNELS_COUNTER` and warns if the message queue grows - /// above the warning threshold. - pub fn tracing_unbounded( - name: &'static str, - queue_size_warning: i64, - ) -> (TracingUnboundedSender, TracingUnboundedReceiver) { - let (s, r) = mpsc::unbounded(); - let queue_size = Arc::new(AtomicI64::new(0)); - let sender = TracingUnboundedSender { - inner: s, - name, - queue_size: queue_size.clone(), - queue_size_warning, - warning_fired: Arc::new(AtomicBool::new(false)), - creation_backtrace: Arc::new(Backtrace::new_unresolved()), - }; - let receiver = TracingUnboundedReceiver { inner: r, name, queue_size }; - (sender, receiver) - } - - impl TracingUnboundedSender { - /// Proxy function to mpsc::UnboundedSender - pub fn poll_ready(&self, ctx: &mut Context) -> Poll> { - self.inner.poll_ready(ctx) - } - - /// Proxy function to mpsc::UnboundedSender - pub fn is_closed(&self) -> bool { - self.inner.is_closed() - } - - /// Proxy function to mpsc::UnboundedSender - pub fn close_channel(&self) { - self.inner.close_channel() - } - - /// Proxy function to mpsc::UnboundedSender - pub fn disconnect(&mut self) { - self.inner.disconnect() - } - - pub fn start_send(&mut self, msg: T) -> Result<(), SendError> { - // The underlying implementation of [`UnboundedSender::start_send`] is the same as - // [`UnboundedSender::unbounded_send`], so we just reuse the message counting and - // error reporting code from `unbounded_send`. - self.unbounded_send(msg).map_err(TrySendError::into_send_error) - } - - /// Proxy function to mpsc::UnboundedSender - pub fn unbounded_send(&self, msg: T) -> Result<(), TrySendError> { - self.inner.unbounded_send(msg).map(|s| { - UNBOUNDED_CHANNELS_COUNTER.with_label_values(&[self.name, "send"]).inc(); - - let queue_size = self.queue_size.fetch_add(1, Ordering::Relaxed); - if queue_size == self.queue_size_warning && - self.warning_fired - .compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed) - .is_ok() - { - // `warning_fired` and `queue_size` are not synchronized, so it's possible - // that the warning is fired few times before the `warning_fired` is seen - // by all threads. This seems better than introducing a mutex guarding them. - let mut backtrace = (*self.creation_backtrace).clone(); - backtrace.resolve(); - error!( - "The number of unprocessed messages in channel `{}` reached {}.\n\ - The channel was created at:\n{:?}", - self.name, self.queue_size_warning, backtrace, - ); - } +/// Wrapper Type around [`async_channel::Receiver`] that decreases the global +/// measure when a message is polled. +#[derive(Debug)] +pub struct TracingUnboundedReceiver { + inner: Receiver, + name: &'static str, +} - s - }) - } +/// Wrapper around [`async_channel::unbounded`] that tracks the in- and outflow via +/// `UNBOUNDED_CHANNELS_COUNTER` and warns if the message queue grows +/// above the warning threshold. +pub fn tracing_unbounded( + name: &'static str, + queue_size_warning: usize, +) -> (TracingUnboundedSender, TracingUnboundedReceiver) { + let (s, r) = async_channel::unbounded(); + let sender = TracingUnboundedSender { + inner: s, + name, + queue_size_warning, + warning_fired: Arc::new(AtomicBool::new(false)), + creation_backtrace: Arc::new(Backtrace::force_capture()), + }; + let receiver = TracingUnboundedReceiver { inner: r, name }; + (sender, receiver) +} - /// Proxy function to mpsc::UnboundedSender - pub fn same_receiver(&self, other: &UnboundedSender) -> bool { - self.inner.same_receiver(other) - } +impl TracingUnboundedSender { + /// Proxy function to [`async_channel::Sender`]. + pub fn is_closed(&self) -> bool { + self.inner.is_closed() } - impl TracingUnboundedReceiver { - fn consume(&mut self) { - // consume all items, make sure to reflect the updated count - let mut count = 0; - loop { - if self.inner.is_terminated() { - break - } + /// Proxy function to [`async_channel::Sender`]. + pub fn close(&self) -> bool { + self.inner.close() + } - match self.try_next() { - Ok(Some(..)) => count += 1, - _ => break, - } + /// Proxy function to `async_channel::Sender::try_send`. + pub fn unbounded_send(&self, msg: T) -> Result<(), TrySendError> { + self.inner.try_send(msg).map(|s| { + UNBOUNDED_CHANNELS_COUNTER.with_label_values(&[self.name, "send"]).inc(); + + if self.inner.len() >= self.queue_size_warning && + self.warning_fired + .compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed) + .is_ok() + { + error!( + "The number of unprocessed messages in channel `{}` exceeded {}.\n\ + The channel was created at:\n{}\n + Last message was sent from:\n{}", + self.name, + self.queue_size_warning, + self.creation_backtrace, + Backtrace::force_capture(), + ); } - // and discount the messages - if count > 0 { - UNBOUNDED_CHANNELS_COUNTER - .with_label_values(&[self.name, "dropped"]) - .inc_by(count); - } - } - /// Proxy function to mpsc::UnboundedReceiver - /// that consumes all messages first and updates the counter - pub fn close(&mut self) { - self.consume(); - self.inner.close() - } - - /// Proxy function to mpsc::UnboundedReceiver - /// that discounts the messages taken out - pub fn try_next(&mut self) -> Result, TryRecvError> { - self.inner.try_next().map(|s| { - if s.is_some() { - let _ = self.queue_size.fetch_sub(1, Ordering::Relaxed); - UNBOUNDED_CHANNELS_COUNTER.with_label_values(&[self.name, "received"]).inc(); - } - s - }) - } + s + }) } +} - impl Drop for TracingUnboundedReceiver { - fn drop(&mut self) { - self.consume(); - } +impl TracingUnboundedReceiver { + /// Proxy function to [`async_channel::Receiver`]. + pub fn close(&mut self) -> bool { + self.inner.close() } - impl Unpin for TracingUnboundedReceiver {} - - impl Stream for TracingUnboundedReceiver { - type Item = T; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let s = self.get_mut(); - match Pin::new(&mut s.inner).poll_next(cx) { - Poll::Ready(msg) => { - if msg.is_some() { - let _ = s.queue_size.fetch_sub(1, Ordering::Relaxed); - UNBOUNDED_CHANNELS_COUNTER.with_label_values(&[s.name, "received"]).inc(); - } - Poll::Ready(msg) - }, - Poll::Pending => Poll::Pending, - } - } + /// Proxy function to [`async_channel::Receiver`] + /// that discounts the messages taken out. + pub fn try_recv(&mut self) -> Result { + self.inner.try_recv().map(|s| { + UNBOUNDED_CHANNELS_COUNTER.with_label_values(&[self.name, "received"]).inc(); + s + }) } +} - impl FusedStream for TracingUnboundedReceiver { - fn is_terminated(&self) -> bool { - self.inner.is_terminated() +impl Drop for TracingUnboundedReceiver { + fn drop(&mut self) { + self.close(); + // the number of messages about to be dropped + let count = self.inner.len(); + // discount the messages + if count > 0 { + UNBOUNDED_CHANNELS_COUNTER + .with_label_values(&[self.name, "dropped"]) + .inc_by(count.saturated_into()); } } +} - impl Sink for TracingUnboundedSender { - type Error = SendError; - - fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - TracingUnboundedSender::poll_ready(&*self, cx) - } - - fn start_send(mut self: Pin<&mut Self>, msg: T) -> Result<(), Self::Error> { - TracingUnboundedSender::start_send(&mut *self, msg) - } +impl Unpin for TracingUnboundedReceiver {} - fn poll_flush(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { - Poll::Ready(Ok(())) - } +impl Stream for TracingUnboundedReceiver { + type Item = T; - fn poll_close( - mut self: Pin<&mut Self>, - _: &mut Context<'_>, - ) -> Poll> { - self.disconnect(); - Poll::Ready(Ok(())) + fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + let s = self.get_mut(); + match Pin::new(&mut s.inner).poll_next(cx) { + Poll::Ready(msg) => { + if msg.is_some() { + UNBOUNDED_CHANNELS_COUNTER.with_label_values(&[s.name, "received"]).inc(); + } + Poll::Ready(msg) + }, + Poll::Pending => Poll::Pending, } } +} - impl Sink for &TracingUnboundedSender { - type Error = SendError; - - fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - TracingUnboundedSender::poll_ready(*self, cx) - } - - fn start_send(self: Pin<&mut Self>, msg: T) -> Result<(), Self::Error> { - self.unbounded_send(msg).map_err(TrySendError::into_send_error) - } - - fn poll_flush(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { - Poll::Ready(Ok(())) - } - - fn poll_close(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { - // The difference with `TracingUnboundedSender` is intentional. The underlying - // implementation differs for `UnboundedSender` and `&UnboundedSender`: - // the latter closes the channel completely with `close_channel()`, while the former - // only closes this specific sender with `disconnect()`. - self.close_channel(); - Poll::Ready(Ok(())) - } +impl FusedStream for TracingUnboundedReceiver { + fn is_terminated(&self) -> bool { + self.inner.is_terminated() } } - -pub use inner::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; diff --git a/client/utils/src/notification.rs b/client/utils/src/notification.rs index 7d866ffc8c019..dabb85d613cc9 100644 --- a/client/utils/src/notification.rs +++ b/client/utils/src/notification.rs @@ -79,7 +79,7 @@ impl NotificationStream { } /// Subscribe to a channel through which the generic payload can be received. - pub fn subscribe(&self, queue_size_warning: i64) -> NotificationReceiver { + pub fn subscribe(&self, queue_size_warning: usize) -> NotificationReceiver { let receiver = self.hub.subscribe((), queue_size_warning); NotificationReceiver { receiver } } diff --git a/client/utils/src/pubsub.rs b/client/utils/src/pubsub.rs index 8136aa0692c26..5293fa42ed94c 100644 --- a/client/utils/src/pubsub.rs +++ b/client/utils/src/pubsub.rs @@ -164,7 +164,7 @@ impl Hub { /// 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, queue_size_warning: i64) -> Receiver + pub fn subscribe(&self, subs_key: K, queue_size_warning: usize) -> Receiver where R: Subscribe + Unsubscribe, { diff --git a/client/utils/src/pubsub/tests/normal_operation.rs b/client/utils/src/pubsub/tests/normal_operation.rs index d4b614d7a8889..a3ea4f7ddee69 100644 --- a/client/utils/src/pubsub/tests/normal_operation.rs +++ b/client/utils/src/pubsub/tests/normal_operation.rs @@ -37,9 +37,8 @@ fn positive_rx_receives_relevant_messages_and_terminates_upon_hub_drop() { // 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()); + assert_eq!(None, rx_01.next().await); }); } From 6a154768e2491b761d96f53d0a2bd66b9a4ae94f Mon Sep 17 00:00:00 2001 From: Koute Date: Tue, 7 Mar 2023 17:57:16 +0900 Subject: [PATCH 477/715] Switch to the `blake2b_simd` crate in `sp-core-hashing` (#13548) * Switch to the `blake2b_simd` crate in `sp-core-hashing` * ".git/.scripts/commands/bench/bench.sh" pallet dev frame_benchmarking --------- Co-authored-by: command-bot <> --- Cargo.lock | 4 +- frame/benchmarking/src/weights.rs | 69 +++++++++++++++--------------- primitives/core/hashing/Cargo.toml | 4 +- primitives/core/hashing/src/lib.rs | 25 +++++++---- 4 files changed, 55 insertions(+), 47 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e0cc2c1074f80..53a8675437ff9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10193,7 +10193,7 @@ dependencies = [ name = "sp-core-hashing" version = "5.0.0" dependencies = [ - "blake2", + "blake2b_simd", "byteorder", "digest 0.10.6", "sha2 0.10.6", @@ -11775,7 +11775,7 @@ checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" dependencies = [ "cfg-if", "digest 0.10.6", - "rand 0.7.3", + "rand 0.8.5", "static_assertions", ] diff --git a/frame/benchmarking/src/weights.rs b/frame/benchmarking/src/weights.rs index fdd4429f2039b..b05feb5900a65 100644 --- a/frame/benchmarking/src/weights.rs +++ b/frame/benchmarking/src/weights.rs @@ -18,25 +18,26 @@ //! Autogenerated weights for frame_benchmarking //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `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 // --steps=50 // --repeat=20 -// --pallet=frame_benchmarking // --extrinsic=* // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/benchmarking/src/weights.rs +// --json-file=/var/lib/gitlab-runner/builds/zyw4fam_/0/parity/mirrors/substrate/.git/.artifacts/bench.json +// --pallet=frame_benchmarking +// --chain=dev // --header=./HEADER-APACHE2 +// --output=./frame/benchmarking/src/weights.rs // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -64,49 +65,49 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 138 nanoseconds. - Weight::from_parts(199_805, 0) + // Minimum execution time: 168_000 picoseconds. + Weight::from_parts(237_577, 0) } /// The range of component `i` is `[0, 1000000]`. fn subtraction(_i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 142 nanoseconds. - Weight::from_parts(201_435, 0) + // Minimum execution time: 169_000 picoseconds. + Weight::from_parts(224_111, 0) } /// The range of component `i` is `[0, 1000000]`. fn multiplication(_i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 138 nanoseconds. - Weight::from_parts(207_037, 0) + // Minimum execution time: 175_000 picoseconds. + Weight::from_parts(229_708, 0) } /// The range of component `i` is `[0, 1000000]`. fn division(_i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 151 nanoseconds. - Weight::from_parts(205_150, 0) + // Minimum execution time: 173_000 picoseconds. + Weight::from_parts(229_855, 0) } fn hashing() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 21_950_884 nanoseconds. - Weight::from_parts(21_994_001_000, 0) + // Minimum execution time: 21_286_627_000 picoseconds. + Weight::from_parts(21_405_011_000, 0) } /// The range of component `i` is `[0, 100]`. fn sr25519_verification(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 168 nanoseconds. - Weight::from_parts(1_680_898, 0) - // Standard Error: 10_291 - .saturating_add(Weight::from_parts(46_867_301, 0).saturating_mul(i.into())) + // Minimum execution time: 239_000 picoseconds. + Weight::from_parts(661_987, 0) + // Standard Error: 24_324 + .saturating_add(Weight::from_parts(47_322_399, 0).saturating_mul(i.into())) } } @@ -117,48 +118,48 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 138 nanoseconds. - Weight::from_parts(199_805, 0) + // Minimum execution time: 168_000 picoseconds. + Weight::from_parts(237_577, 0) } /// The range of component `i` is `[0, 1000000]`. fn subtraction(_i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 142 nanoseconds. - Weight::from_parts(201_435, 0) + // Minimum execution time: 169_000 picoseconds. + Weight::from_parts(224_111, 0) } /// The range of component `i` is `[0, 1000000]`. fn multiplication(_i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 138 nanoseconds. - Weight::from_parts(207_037, 0) + // Minimum execution time: 175_000 picoseconds. + Weight::from_parts(229_708, 0) } /// The range of component `i` is `[0, 1000000]`. fn division(_i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 151 nanoseconds. - Weight::from_parts(205_150, 0) + // Minimum execution time: 173_000 picoseconds. + Weight::from_parts(229_855, 0) } fn hashing() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 21_950_884 nanoseconds. - Weight::from_parts(21_994_001_000, 0) + // Minimum execution time: 21_286_627_000 picoseconds. + Weight::from_parts(21_405_011_000, 0) } /// The range of component `i` is `[0, 100]`. fn sr25519_verification(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 168 nanoseconds. - Weight::from_parts(1_680_898, 0) - // Standard Error: 10_291 - .saturating_add(Weight::from_parts(46_867_301, 0).saturating_mul(i.into())) + // Minimum execution time: 239_000 picoseconds. + Weight::from_parts(661_987, 0) + // Standard Error: 24_324 + .saturating_add(Weight::from_parts(47_322_399, 0).saturating_mul(i.into())) } } diff --git a/primitives/core/hashing/Cargo.toml b/primitives/core/hashing/Cargo.toml index 1bb67ffff5142..a77aaaa7aebc6 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.4", default-features = false } +blake2b_simd = { version = "1.0.1", 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 } @@ -25,7 +25,7 @@ sp-std = { version = "5.0.0", default-features = false, path = "../../std" } default = ["std"] std = [ "digest/std", - "blake2/std", + "blake2b_simd/std", "byteorder/std", "sha2/std", "sha3/std", diff --git a/primitives/core/hashing/src/lib.rs b/primitives/core/hashing/src/lib.rs index 26941bb60fa51..33d777f85b014 100644 --- a/primitives/core/hashing/src/lib.rs +++ b/primitives/core/hashing/src/lib.rs @@ -23,34 +23,41 @@ use core::hash::Hasher; use byteorder::{ByteOrder, LittleEndian}; -use digest::{ - consts::{U16, U32, U8}, - Digest, -}; +use digest::Digest; + +#[inline(always)] +fn blake2(data: &[u8]) -> [u8; N] { + blake2b_simd::Params::new() + .hash_length(N) + .hash(data) + .as_bytes() + .try_into() + .expect("slice is always the necessary length") +} /// 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::Blake2b512::digest(data).as_slice()); + *dest = blake2(data); } /// Do a Blake2 512-bit hash and return result. pub fn blake2_512(data: &[u8]) -> [u8; 64] { - blake2::Blake2b512::digest(data).into() + blake2(data) } /// Do a Blake2 256-bit hash and return result. pub fn blake2_256(data: &[u8]) -> [u8; 32] { - blake2::Blake2b::::digest(data).into() + blake2(data) } /// Do a Blake2 128-bit hash and return result. pub fn blake2_128(data: &[u8]) -> [u8; 16] { - blake2::Blake2b::::digest(data).into() + blake2(data) } /// Do a Blake2 64-bit hash and return result. pub fn blake2_64(data: &[u8]) -> [u8; 8] { - blake2::Blake2b::::digest(data).into() + blake2(data) } /// Do a XX 64-bit hash and place result in `dest`. From c09ce08526542a45ff12c6f87b2518094f69f8e1 Mon Sep 17 00:00:00 2001 From: yjh Date: Tue, 7 Mar 2023 16:59:04 +0800 Subject: [PATCH 478/715] remove serde derive for BlockId (#13457) --- primitives/runtime/src/generic/block.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/primitives/runtime/src/generic/block.rs b/primitives/runtime/src/generic/block.rs index 85d0b7ca1fd2d..1df747a16c839 100644 --- a/primitives/runtime/src/generic/block.rs +++ b/primitives/runtime/src/generic/block.rs @@ -33,9 +33,6 @@ use sp_std::prelude::*; /// Something to identify a block. #[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))] pub enum BlockId { /// Identify by block header hash. Hash(Block::Hash), @@ -45,12 +42,12 @@ pub enum BlockId { impl BlockId { /// Create a block ID from a hash. - pub fn hash(hash: Block::Hash) -> Self { + pub const fn hash(hash: Block::Hash) -> Self { BlockId::Hash(hash) } /// Create a block ID from a number. - pub fn number(number: NumberFor) -> Self { + pub const fn number(number: NumberFor) -> Self { BlockId::Number(number) } From 4d8f3d543b357a6145b7ba1bea9c63ddeaafdc5a Mon Sep 17 00:00:00 2001 From: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Date: Tue, 7 Mar 2023 11:56:14 +0200 Subject: [PATCH 479/715] rpc/chainHead: Fix pruned blocks events from forks (#13379) * rpc/chainhead: Test unpin for noncanonical prunned blocks Signed-off-by: Alexandru Vasile * rpc/tests: Ensure fork is not reported by the Finalized event Signed-off-by: Alexandru Vasile * rpc/chainhead: Detect pruned forks to ignore from events Signed-off-by: Alexandru Vasile * rpc/tests: Check unpin can be called on pruned hashes Signed-off-by: Alexandru Vasile * Fix clippy Signed-off-by: Alexandru Vasile * rpc/chain_head: Handle race with memory blocks and notifications Signed-off-by: Alexandru Vasile * rpc/chain_head: Add data config for the `follow` future Signed-off-by: Alexandru Vasile * rpc/chain_head: Address feedback Signed-off-by: Alexandru Vasile * rpc/chain_head: Move best block cache on the data config Signed-off-by: Alexandru Vasile * rpc/chain_head: Send new events from the finalized stream Signed-off-by: Alexandru Vasile * rpc/chian_head: Report all pruned blocks Signed-off-by: Alexandru Vasile * rpc/chain_head: Move `chainHead_follow` logic on dedicated file Signed-off-by: Alexandru Vasile * rpc/chain_head: Delegate follow logic to `chain_head_follow` Signed-off-by: Alexandru Vasile * rpc/chain_head: Remove subscriptions on drop Signed-off-by: Alexandru Vasile * rpc/tests: Ignore pruned blocks for a longer fork Signed-off-by: Alexandru Vasile * rpc/tests: Check all pruned blocks are reported, not just stale heads Signed-off-by: Alexandru Vasile * rpc/tests: Remove println debug and fix indentation Signed-off-by: Alexandru Vasile * rpc/chain_head: Remove unnecessary trait bounds Signed-off-by: Alexandru Vasile * rpc/chain_head: Add debug log for pruned forks Signed-off-by: Alexandru Vasile * Revert "rpc/chain_head: Add debug log for pruned forks" This reverts commit 425d6e7a8b60421bcece12add1941fe58524cf52. * Adjust blockID for testing Signed-off-by: Alexandru Vasile * Update client/rpc-spec-v2/src/chain_head/chain_head_follow.rs Co-authored-by: Davide Galassi * rpc/chain_head: Rename `ChainHeadFollow` to `ChainHeadFollower` Signed-off-by: Alexandru Vasile * rpc/chain_head: Remove subscriptions manually Signed-off-by: Alexandru Vasile * rpc/chain_head: Improve log messages by adding subID and errors Signed-off-by: Alexandru Vasile * rpc/chain_head: Ensure `follow` stops sending events on first error Signed-off-by: Alexandru Vasile * rpc/chain_head: Use default constructor Signed-off-by: Alexandru Vasile * rpc/chain_head: Add `StartupPoint` structure Signed-off-by: Alexandru Vasile * rpc/chain_head: Rename `in_memory_blocks` Signed-off-by: Alexandru Vasile * rpc/chain_head: Fix comment typo Signed-off-by: Alexandru Vasile * rpc/chain_head: Keep unique blocks and remove itertools Signed-off-by: Alexandru Vasile * rpc/chain_head: Make sure `bestBlocks` events are generated in order Signed-off-by: Alexandru Vasile * rpc/chain_head: Maintain order of reported blocks Signed-off-by: Alexandru Vasile * rpc/chain_head: Parent of finalized block could be unpinned Signed-off-by: Alexandru Vasile * rpc/chain_head: Fix warning Signed-off-by: Alexandru Vasile --------- Signed-off-by: Alexandru Vasile Co-authored-by: Davide Galassi --- .../rpc-spec-v2/src/chain_head/chain_head.rs | 399 +---------- .../src/chain_head/chain_head_follow.rs | 644 ++++++++++++++++++ client/rpc-spec-v2/src/chain_head/mod.rs | 1 + .../src/chain_head/subscription.rs | 25 +- client/rpc-spec-v2/src/chain_head/tests.rs | 301 ++++++++ 5 files changed, 989 insertions(+), 381 deletions(-) create mode 100644 client/rpc-spec-v2/src/chain_head/chain_head_follow.rs diff --git a/client/rpc-spec-v2/src/chain_head/chain_head.rs b/client/rpc-spec-v2/src/chain_head/chain_head.rs index 4fa47dc403cc9..c63e874c1bc15 100644 --- a/client/rpc-spec-v2/src/chain_head/chain_head.rs +++ b/client/rpc-spec-v2/src/chain_head/chain_head.rs @@ -21,41 +21,33 @@ use crate::{ chain_head::{ api::ChainHeadApiServer, + chain_head_follow::ChainHeadFollower, error::Error as ChainHeadRpcError, - event::{ - BestBlockChanged, ChainHeadEvent, ChainHeadResult, ErrorEvent, Finalized, FollowEvent, - Initialized, NetworkConfig, NewBlock, RuntimeEvent, RuntimeVersionEvent, - }, - subscription::{SubscriptionHandle, SubscriptionManagement, SubscriptionManagementError}, + event::{ChainHeadEvent, ChainHeadResult, ErrorEvent, FollowEvent, NetworkConfig}, + subscription::SubscriptionManagement, }, SubscriptionTaskExecutor, }; use codec::Encode; -use futures::{ - channel::oneshot, - future::FutureExt, - stream::{self, Stream, StreamExt}, -}; -use futures_util::future::Either; +use futures::future::FutureExt; use jsonrpsee::{ core::{async_trait, RpcResult}, types::{SubscriptionEmptyError, SubscriptionId, SubscriptionResult}, SubscriptionSink, }; -use log::{debug, error}; +use log::debug; use sc_client_api::{ - Backend, BlockBackend, BlockImportNotification, BlockchainEvents, CallExecutor, ChildInfo, - ExecutorProvider, FinalityNotification, StorageKey, StorageProvider, + Backend, BlockBackend, BlockchainEvents, CallExecutor, ChildInfo, ExecutorProvider, StorageKey, + StorageProvider, }; -use serde::Serialize; use sp_api::CallApiAt; -use sp_blockchain::{ - Backend as BlockChainBackend, Error as BlockChainError, HeaderBackend, HeaderMetadata, -}; +use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata}; use sp_core::{hexdisplay::HexDisplay, storage::well_known_keys, traits::CallContext, Bytes}; -use sp_runtime::traits::{Block as BlockT, Header}; +use sp_runtime::traits::Block as BlockT; use std::{marker::PhantomData, sync::Arc}; +pub(crate) const LOG_TARGET: &str = "rpc-spec-v2"; + /// An API for chain head RPC calls. pub struct ChainHead { /// Substrate client. @@ -119,64 +111,6 @@ impl ChainHead { } } -/// Generate the initial events reported by the RPC `follow` method. -/// -/// This includes the "Initialized" event followed by the in-memory -/// blocks via "NewBlock" and the "BestBlockChanged". -fn generate_initial_events( - client: &Arc, - backend: &Arc, - handle: &SubscriptionHandle, - runtime_updates: bool, -) -> Result>, SubscriptionManagementError> -where - Block: BlockT + 'static, - Block::Header: Unpin, - BE: Backend + 'static, - Client: HeaderBackend + CallApiAt + 'static, -{ - // The initialized event is the first one sent. - let finalized_block_hash = client.info().finalized_hash; - handle.pin_block(finalized_block_hash)?; - - let finalized_block_runtime = - generate_runtime_event(&client, runtime_updates, finalized_block_hash, None); - - let initialized_event = FollowEvent::Initialized(Initialized { - finalized_block_hash, - finalized_block_runtime, - runtime_updates, - }); - - let initial_blocks = get_initial_blocks(&backend, finalized_block_hash); - let mut in_memory_blocks = Vec::with_capacity(initial_blocks.len() + 1); - - in_memory_blocks.push(initialized_event); - for (child, parent) in initial_blocks.into_iter() { - handle.pin_block(child)?; - - let new_runtime = generate_runtime_event(&client, runtime_updates, child, Some(parent)); - - let event = FollowEvent::NewBlock(NewBlock { - block_hash: child, - parent_block_hash: parent, - new_runtime, - runtime_updates, - }); - - in_memory_blocks.push(event); - } - - // Generate a new best block event. - let best_block_hash = client.info().best_hash; - if best_block_hash != finalized_block_hash { - let best_block = FollowEvent::BestBlockChanged(BestBlockChanged { best_block_hash }); - in_memory_blocks.push(best_block); - }; - - Ok(in_memory_blocks) -} - /// Parse hex-encoded string parameter as raw bytes. /// /// If the parsing fails, the subscription is rejected. @@ -198,243 +132,6 @@ fn parse_hex_param( } } -/// Conditionally generate the runtime event of the given block. -fn generate_runtime_event( - client: &Arc, - runtime_updates: bool, - block: Block::Hash, - parent: Option, -) -> Option -where - Block: BlockT + 'static, - Client: CallApiAt + 'static, -{ - // No runtime versions should be reported. - if !runtime_updates { - return None - } - - let block_rt = match client.runtime_version_at(block) { - Ok(rt) => rt, - Err(err) => return Some(err.into()), - }; - - let parent = match parent { - Some(parent) => parent, - // Nothing to compare against, always report. - None => return Some(RuntimeEvent::Valid(RuntimeVersionEvent { spec: block_rt })), - }; - - let parent_rt = match client.runtime_version_at(parent) { - Ok(rt) => rt, - Err(err) => return Some(err.into()), - }; - - // Report the runtime version change. - if block_rt != parent_rt { - Some(RuntimeEvent::Valid(RuntimeVersionEvent { spec: block_rt })) - } else { - None - } -} - -/// Get the in-memory blocks of the client, starting from the provided finalized hash. -/// -/// Returns a tuple of block hash with parent hash. -fn get_initial_blocks( - backend: &Arc, - parent_hash: Block::Hash, -) -> Vec<(Block::Hash, Block::Hash)> -where - Block: BlockT + 'static, - BE: Backend + 'static, -{ - let mut result = Vec::new(); - let mut next_hash = Vec::new(); - next_hash.push(parent_hash); - - while let Some(parent_hash) = next_hash.pop() { - let Ok(blocks) = backend.blockchain().children(parent_hash) else { - continue - }; - - for child_hash in blocks { - result.push((child_hash, parent_hash)); - next_hash.push(child_hash); - } - } - - result -} - -/// Submit the events from the provided stream to the RPC client -/// for as long as the `rx_stop` event was not called. -async fn submit_events( - sink: &mut SubscriptionSink, - mut stream: EventStream, - rx_stop: oneshot::Receiver<()>, -) where - EventStream: Stream + Unpin, - T: Serialize, -{ - let mut stream_item = stream.next(); - let mut stop_event = rx_stop; - - while let Either::Left((Some(event), next_stop_event)) = - futures_util::future::select(stream_item, stop_event).await - { - match sink.send(&event) { - Ok(true) => { - stream_item = stream.next(); - stop_event = next_stop_event; - }, - // Client disconnected. - Ok(false) => return, - Err(_) => { - // Failed to submit event. - break - }, - } - } - - let _ = sink.send(&FollowEvent::::Stop); -} - -/// Generate the "NewBlock" event and potentially the "BestBlockChanged" event for -/// every notification. -fn handle_import_blocks( - client: &Arc, - handle: &SubscriptionHandle, - runtime_updates: bool, - notification: BlockImportNotification, -) -> Result<(FollowEvent, Option>), SubscriptionManagementError> -where - Block: BlockT + 'static, - Client: CallApiAt + 'static, -{ - handle.pin_block(notification.hash)?; - - let new_runtime = generate_runtime_event( - &client, - runtime_updates, - notification.hash, - Some(*notification.header.parent_hash()), - ); - - // Note: `Block::Hash` will serialize to hexadecimal encoded string. - let new_block = FollowEvent::NewBlock(NewBlock { - block_hash: notification.hash, - parent_block_hash: *notification.header.parent_hash(), - new_runtime, - runtime_updates, - }); - - if !notification.is_new_best { - return Ok((new_block, None)) - } - - // If this is the new best block, then we need to generate two events. - let best_block_event = - FollowEvent::BestBlockChanged(BestBlockChanged { best_block_hash: notification.hash }); - - let mut best_block_cache = handle.best_block_write(); - match *best_block_cache { - Some(block_cache) => { - // The RPC layer has not reported this block as best before. - // Note: This handles the race with the finalized branch. - if block_cache != notification.hash { - *best_block_cache = Some(notification.hash); - Ok((new_block, Some(best_block_event))) - } else { - Ok((new_block, None)) - } - }, - None => { - *best_block_cache = Some(notification.hash); - Ok((new_block, Some(best_block_event))) - }, - } -} - -/// Generate the "Finalized" event and potentially the "BestBlockChanged" for -/// every notification. -fn handle_finalized_blocks( - client: &Arc, - handle: &SubscriptionHandle, - notification: FinalityNotification, -) -> Result<(FollowEvent, Option>), SubscriptionManagementError> -where - Block: BlockT + 'static, - Client: HeaderBackend + HeaderMetadata + 'static, -{ - let last_finalized = notification.hash; - // We might not receive all new blocks reports, also pin the block here. - handle.pin_block(last_finalized)?; - - // The tree route contains the exclusive path from the last finalized block - // to the block reported by the notification. Ensure the finalized block is - // properly reported to that path. - let mut finalized_block_hashes = notification.tree_route.iter().cloned().collect::>(); - finalized_block_hashes.push(last_finalized); - - let pruned_block_hashes: Vec<_> = notification.stale_heads.iter().cloned().collect(); - - let finalized_event = FollowEvent::Finalized(Finalized { - finalized_block_hashes, - pruned_block_hashes: pruned_block_hashes.clone(), - }); - - let mut best_block_cache = handle.best_block_write(); - match *best_block_cache { - Some(block_cache) => { - // Check if the current best block is also reported as pruned. - let reported_pruned = pruned_block_hashes.iter().find(|&&hash| hash == block_cache); - if reported_pruned.is_none() { - return Ok((finalized_event, None)) - } - - // The best block is reported as pruned. Therefore, we need to signal a new - // best block event before submitting the finalized event. - let best_block_hash = client.info().best_hash; - if best_block_hash == block_cache { - // The client doest not have any new information about the best block. - // The information from `.info()` is updated from the DB as the last - // step of the finalization and it should be up to date. Also, the - // displaced nodes (list of nodes reported) should be reported with - // an offset of 32 blocks for substrate. - // If the info is outdated, there is nothing the RPC can do for now. - error!(target: "rpc-spec-v2", "Client does not contain different best block"); - Ok((finalized_event, None)) - } else { - let ancestor = sp_blockchain::lowest_common_ancestor( - &**client, - last_finalized, - best_block_hash, - ) - .map_err(|_| { - SubscriptionManagementError::Custom("Could not find common ancestor".into()) - })?; - - // The client's best block must be a descendent of the last finalized block. - // In other words, the lowest common ancestor must be the last finalized block. - if ancestor.hash != last_finalized { - return Err(SubscriptionManagementError::Custom( - "The finalized block is not an ancestor of the best block".into(), - )) - } - - // The RPC needs to also submit a new best block changed before the - // finalized event. - *best_block_cache = Some(best_block_hash); - let best_block_event = - FollowEvent::BestBlockChanged(BestBlockChanged { best_block_hash }); - Ok((finalized_event, Some(best_block_event))) - } - }, - None => Ok((finalized_event, None)), - } -} - #[async_trait] impl ChainHeadApiServer for ChainHead where @@ -467,71 +164,28 @@ where let Some((rx_stop, sub_handle)) = self.subscriptions.insert_subscription(sub_id.clone(), runtime_updates, self.max_pinned_blocks) else { // Inserting the subscription can only fail if the JsonRPSee // generated a duplicate subscription ID. - debug!(target: "rpc-spec-v2", "[follow][id={:?}] Subscription already accepted", sub_id); + debug!(target: LOG_TARGET, "[follow][id={:?}] Subscription already accepted", sub_id); let _ = sink.send(&FollowEvent::::Stop); return Ok(()) }; - debug!(target: "rpc-spec-v2", "[follow][id={:?}] Subscription accepted", sub_id); + debug!(target: LOG_TARGET, "[follow][id={:?}] Subscription accepted", sub_id); - let client = self.client.clone(); - let handle = sub_handle.clone(); - let subscription_id = sub_id.clone(); - - let stream_import = self - .client - .import_notification_stream() - .map(move |notification| { - match handle_import_blocks(&client, &handle, runtime_updates, notification) { - Ok((new_block, None)) => stream::iter(vec![new_block]), - Ok((new_block, Some(best_block))) => stream::iter(vec![new_block, best_block]), - Err(_) => { - debug!(target: "rpc-spec-v2", "[follow][id={:?}] Failed to handle block import notification.", subscription_id); - handle.stop(); - stream::iter(vec![]) - }, - } - }) - .flatten(); - - let client = self.client.clone(); - let handle = sub_handle.clone(); - let subscription_id = sub_id.clone(); - - let stream_finalized = self - .client - .finality_notification_stream() - .map(move |notification| { - match handle_finalized_blocks(&client, &handle, notification) { - Ok((finalized_event, None)) => stream::iter(vec![finalized_event]), - Ok((finalized_event, Some(best_block))) => - stream::iter(vec![best_block, finalized_event]), - Err(_) => { - debug!(target: "rpc-spec-v2", "[follow][id={:?}] Failed to import finalized blocks", subscription_id); - handle.stop(); - stream::iter(vec![]) - }, - } - }) - .flatten(); - - let merged = tokio_stream::StreamExt::merge(stream_import, stream_finalized); let subscriptions = self.subscriptions.clone(); - let client = self.client.clone(); let backend = self.backend.clone(); + let client = self.client.clone(); let fut = async move { - let Ok(initial_events) = generate_initial_events(&client, &backend, &sub_handle, runtime_updates) else { - // Stop the subscription if we exceeded the maximum number of blocks pinned. - debug!(target: "rpc-spec-v2", "[follow][id={:?}] Exceeded max pinned blocks from initial events", sub_id); - let _ = sink.send(&FollowEvent::::Stop); - return - }; + let mut chain_head_follow = ChainHeadFollower::new( + client, + backend, + sub_handle, + runtime_updates, + sub_id.clone(), + ); - let stream = stream::iter(initial_events).chain(merged); + chain_head_follow.generate_events(sink, rx_stop).await; - submit_events(&mut sink, stream.boxed(), rx_stop).await; - // The client disconnected or called the unsubscribe method. subscriptions.remove_subscription(&sub_id); - debug!(target: "rpc-spec-v2", "[follow][id={:?}] Subscription removed", sub_id); + debug!(target: LOG_TARGET, "[follow][id={:?}] Subscription removed", sub_id); }; self.executor.spawn("substrate-rpc-subscription", Some("rpc"), fut.boxed()); @@ -569,7 +223,12 @@ where }, Ok(None) => { // The block's body was pruned. This subscription ID has become invalid. - debug!(target: "rpc-spec-v2", "[body][id={:?}] Stopping subscription because hash={:?} was pruned", follow_subscription, hash); + debug!( + target: LOG_TARGET, + "[body][id={:?}] Stopping subscription because hash={:?} was pruned", + follow_subscription, + hash + ); handle.stop(); ChainHeadEvent::::Disjoint }, diff --git a/client/rpc-spec-v2/src/chain_head/chain_head_follow.rs b/client/rpc-spec-v2/src/chain_head/chain_head_follow.rs new file mode 100644 index 0000000000000..9173b7340b7e5 --- /dev/null +++ b/client/rpc-spec-v2/src/chain_head/chain_head_follow.rs @@ -0,0 +1,644 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Implementation of the `chainHead_follow` method. + +use crate::chain_head::{ + chain_head::LOG_TARGET, + event::{ + BestBlockChanged, Finalized, FollowEvent, Initialized, NewBlock, RuntimeEvent, + RuntimeVersionEvent, + }, + subscription::{SubscriptionHandle, SubscriptionManagementError}, +}; +use futures::{ + channel::oneshot, + stream::{self, Stream, StreamExt}, +}; +use futures_util::future::Either; +use jsonrpsee::SubscriptionSink; +use log::{debug, error}; +use sc_client_api::{ + Backend, BlockBackend, BlockImportNotification, BlockchainEvents, FinalityNotification, +}; +use sp_api::CallApiAt; +use sp_blockchain::{ + Backend as BlockChainBackend, Error as BlockChainError, HeaderBackend, HeaderMetadata, Info, +}; +use sp_runtime::{ + traits::{Block as BlockT, Header as HeaderT, One}, + Saturating, +}; +use std::{collections::HashSet, sync::Arc}; + +/// Generates the events of the `chainHead_follow` method. +pub struct ChainHeadFollower { + /// Substrate client. + client: Arc, + /// Backend of the chain. + backend: Arc, + /// Subscription handle. + sub_handle: SubscriptionHandle, + /// Subscription was started with the runtime updates flag. + runtime_updates: bool, + /// Subscription ID. + sub_id: String, + /// The best reported block by this subscription. + best_block_cache: Option, +} + +impl ChainHeadFollower { + /// Create a new [`ChainHeadFollower`]. + pub fn new( + client: Arc, + backend: Arc, + sub_handle: SubscriptionHandle, + runtime_updates: bool, + sub_id: String, + ) -> Self { + Self { client, backend, sub_handle, runtime_updates, sub_id, best_block_cache: None } + } +} + +/// A block notification. +enum NotificationType { + /// The initial events generated from the node's memory. + InitialEvents(Vec>), + /// The new block notification obtained from `import_notification_stream`. + NewBlock(BlockImportNotification), + /// The finalized block notification obtained from `finality_notification_stream`. + Finalized(FinalityNotification), +} + +/// The initial blocks that should be reported or ignored by the chainHead. +#[derive(Clone, Debug)] +struct InitialBlocks { + /// Children of the latest finalized block, for which the `NewBlock` + /// event must be generated. + /// + /// It is a tuple of (block hash, parent hash). + finalized_block_descendants: Vec<(Block::Hash, Block::Hash)>, + /// Blocks that should not be reported as pruned by the `Finalized` event. + /// + /// Substrate database will perform the pruning of height N at + /// the finalization N + 1. We could have the following block tree + /// when the user subscribes to the `follow` method: + /// [A] - [A1] - [A2] - [A3] + /// ^^ finalized + /// - [A1] - [B1] + /// + /// When the A3 block is finalized, B1 is reported as pruned, however + /// B1 was never reported as `NewBlock` (and as such was never pinned). + /// This is because the `NewBlock` events are generated for children of + /// the finalized hash. + pruned_forks: HashSet, +} + +/// The startup point from which chainHead started to generate events. +struct StartupPoint { + /// Best block hash. + pub best_hash: Block::Hash, + /// The head of the finalized chain. + pub finalized_hash: Block::Hash, + /// Last finalized block number. + pub finalized_number: <::Header as HeaderT>::Number, +} + +impl From> for StartupPoint { + fn from(info: Info) -> Self { + StartupPoint:: { + best_hash: info.best_hash, + finalized_hash: info.finalized_hash, + finalized_number: info.finalized_number, + } + } +} + +impl ChainHeadFollower +where + Block: BlockT + 'static, + BE: Backend + 'static, + Client: BlockBackend + + HeaderBackend + + HeaderMetadata + + BlockchainEvents + + CallApiAt + + 'static, +{ + /// Conditionally generate the runtime event of the given block. + fn generate_runtime_event( + &self, + block: Block::Hash, + parent: Option, + ) -> Option { + // No runtime versions should be reported. + if !self.runtime_updates { + return None + } + + let block_rt = match self.client.runtime_version_at(block) { + Ok(rt) => rt, + Err(err) => return Some(err.into()), + }; + + let parent = match parent { + Some(parent) => parent, + // Nothing to compare against, always report. + None => return Some(RuntimeEvent::Valid(RuntimeVersionEvent { spec: block_rt })), + }; + + let parent_rt = match self.client.runtime_version_at(parent) { + Ok(rt) => rt, + Err(err) => return Some(err.into()), + }; + + // Report the runtime version change. + if block_rt != parent_rt { + Some(RuntimeEvent::Valid(RuntimeVersionEvent { spec: block_rt })) + } else { + None + } + } + + /// Get the in-memory blocks of the client, starting from the provided finalized hash. + fn get_init_blocks_with_forks( + &self, + startup_point: &StartupPoint, + ) -> Result, SubscriptionManagementError> { + let blockchain = self.backend.blockchain(); + let leaves = blockchain.leaves()?; + let finalized = startup_point.finalized_hash; + let mut pruned_forks = HashSet::new(); + let mut finalized_block_descendants = Vec::new(); + let mut unique_descendants = HashSet::new(); + for leaf in leaves { + let tree_route = sp_blockchain::tree_route(blockchain, finalized, leaf)?; + + let blocks = tree_route.enacted().iter().map(|block| block.hash); + if !tree_route.retracted().is_empty() { + pruned_forks.extend(blocks); + } else { + // Ensure a `NewBlock` event is generated for all children of the + // finalized block. Describe the tree route as (child_node, parent_node) + // Note: the order of elements matters here. + let parents = std::iter::once(finalized).chain(blocks.clone()); + + for pair in blocks.zip(parents) { + if unique_descendants.insert(pair) { + finalized_block_descendants.push(pair); + } + } + } + } + + Ok(InitialBlocks { finalized_block_descendants, pruned_forks }) + } + + /// Generate the initial events reported by the RPC `follow` method. + /// + /// Returns the initial events that should be reported directly, together with pruned + /// block hashes that should be ignored by the `Finalized` event. + fn generate_init_events( + &mut self, + startup_point: &StartupPoint, + ) -> Result<(Vec>, HashSet), SubscriptionManagementError> + { + let init = self.get_init_blocks_with_forks(startup_point)?; + + let initial_blocks = init.finalized_block_descendants; + + // The initialized event is the first one sent. + let finalized_block_hash = startup_point.finalized_hash; + self.sub_handle.pin_block(finalized_block_hash)?; + + let finalized_block_runtime = self.generate_runtime_event(finalized_block_hash, None); + + let initialized_event = FollowEvent::Initialized(Initialized { + finalized_block_hash, + finalized_block_runtime, + runtime_updates: self.runtime_updates, + }); + + let mut finalized_block_descendants = Vec::with_capacity(initial_blocks.len() + 1); + + finalized_block_descendants.push(initialized_event); + for (child, parent) in initial_blocks.into_iter() { + self.sub_handle.pin_block(child)?; + + let new_runtime = self.generate_runtime_event(child, Some(parent)); + + let event = FollowEvent::NewBlock(NewBlock { + block_hash: child, + parent_block_hash: parent, + new_runtime, + runtime_updates: self.runtime_updates, + }); + + finalized_block_descendants.push(event); + } + + // Generate a new best block event. + let best_block_hash = startup_point.best_hash; + if best_block_hash != finalized_block_hash { + let best_block = FollowEvent::BestBlockChanged(BestBlockChanged { best_block_hash }); + self.best_block_cache = Some(best_block_hash); + finalized_block_descendants.push(best_block); + }; + + Ok((finalized_block_descendants, init.pruned_forks)) + } + + /// Generate the "NewBlock" event and potentially the "BestBlockChanged" event for the + /// given block hash. + fn generate_import_events( + &mut self, + block_hash: Block::Hash, + parent_block_hash: Block::Hash, + is_best_block: bool, + ) -> Vec> { + let new_runtime = self.generate_runtime_event(block_hash, Some(parent_block_hash)); + + let new_block = FollowEvent::NewBlock(NewBlock { + block_hash, + parent_block_hash, + new_runtime, + runtime_updates: self.runtime_updates, + }); + + if !is_best_block { + return vec![new_block] + } + + // If this is the new best block, then we need to generate two events. + let best_block_event = + FollowEvent::BestBlockChanged(BestBlockChanged { best_block_hash: block_hash }); + + match self.best_block_cache { + Some(block_cache) => { + // The RPC layer has not reported this block as best before. + // Note: This handles the race with the finalized branch. + if block_cache != block_hash { + self.best_block_cache = Some(block_hash); + vec![new_block, best_block_event] + } else { + vec![new_block] + } + }, + None => { + self.best_block_cache = Some(block_hash); + vec![new_block, best_block_event] + }, + } + } + + /// Handle the import of new blocks by generating the appropriate events. + fn handle_import_blocks( + &mut self, + notification: BlockImportNotification, + startup_point: &StartupPoint, + ) -> Result>, SubscriptionManagementError> { + // The block was already pinned by the initial block events or by the finalized event. + if !self.sub_handle.pin_block(notification.hash)? { + return Ok(Default::default()) + } + + // Ensure we are only reporting blocks after the starting point. + let Some(block_number) = self.client.number(notification.hash)? else { + return Err(SubscriptionManagementError::BlockNumberAbsent) + }; + if block_number < startup_point.finalized_number { + return Ok(Default::default()) + } + + Ok(self.generate_import_events( + notification.hash, + *notification.header.parent_hash(), + notification.is_new_best, + )) + } + + /// Generates new block events from the given finalized hashes. + /// + /// It may be possible that the `Finalized` event fired before the `NewBlock` + /// event. In that case, for each finalized hash that was not reported yet + /// generate the `NewBlock` event. For the final finalized hash we must also + /// generate one `BestBlock` event. + fn generate_finalized_events( + &mut self, + finalized_block_hashes: &[Block::Hash], + ) -> Result>, SubscriptionManagementError> { + let mut events = Vec::new(); + + // Nothing to be done if no finalized hashes are provided. + let Some(first_hash) = finalized_block_hashes.get(0) else { + return Ok(Default::default()) + }; + + // Find the parent hash. + let Some(first_number) = self.client.number(*first_hash)? else { + return Err(SubscriptionManagementError::BlockNumberAbsent) + }; + let Some(parent) = self.client.hash(first_number.saturating_sub(One::one()))? else { + return Err(SubscriptionManagementError::BlockHashAbsent) + }; + + let last_finalized = finalized_block_hashes + .last() + .expect("At least one finalized hash inserted; qed"); + let parents = std::iter::once(&parent).chain(finalized_block_hashes.iter()); + for (hash, parent) in finalized_block_hashes.iter().zip(parents) { + // This block is already reported by the import notification. + if !self.sub_handle.pin_block(*hash)? { + continue + } + + // Generate only the `NewBlock` event for this block. + if hash != last_finalized { + events.extend(self.generate_import_events(*hash, *parent, false)); + continue + } + + match self.best_block_cache { + Some(best_block_hash) => { + // If the best reported block is a children of the last finalized, + // then we had a gap in notification. + let ancestor = sp_blockchain::lowest_common_ancestor( + &*self.client, + *last_finalized, + best_block_hash, + )?; + + // A descendent of the finalized block was already reported + // before the `NewBlock` event containing the finalized block + // is reported. + if ancestor.hash == *last_finalized { + return Err(SubscriptionManagementError::Custom( + "A descendent of the finalized block was already reported".into(), + )) + } + self.best_block_cache = Some(*hash); + }, + // This is the first best block event that we generate. + None => { + self.best_block_cache = Some(*hash); + }, + }; + + // This is the first time we see this block. Generate the `NewBlock` event; if this is + // the last block, also generate the `BestBlock` event. + events.extend(self.generate_import_events(*hash, *parent, true)) + } + + Ok(events) + } + + /// Get all pruned block hashes from the provided stale heads. + /// + /// The result does not include hashes from `to_ignore`. + fn get_pruned_hashes( + &self, + stale_heads: &[Block::Hash], + last_finalized: Block::Hash, + to_ignore: &mut HashSet, + ) -> Result, SubscriptionManagementError> { + let blockchain = self.backend.blockchain(); + let mut pruned = Vec::new(); + + for stale_head in stale_heads { + let tree_route = sp_blockchain::tree_route(blockchain, last_finalized, *stale_head)?; + + // Collect only blocks that are not part of the canonical chain. + pruned.extend(tree_route.enacted().iter().filter_map(|block| { + if !to_ignore.remove(&block.hash) { + Some(block.hash) + } else { + None + } + })) + } + + Ok(pruned) + } + + /// Handle the finalization notification by generating the `Finalized` event. + /// + /// If the block of the notification was not reported yet, this method also + /// generates the events similar to `handle_import_blocks`. + fn handle_finalized_blocks( + &mut self, + notification: FinalityNotification, + to_ignore: &mut HashSet, + startup_point: &StartupPoint, + ) -> Result>, SubscriptionManagementError> { + let last_finalized = notification.hash; + + // Ensure we are only reporting blocks after the starting point. + let Some(block_number) = self.client.number(last_finalized)? else { + return Err(SubscriptionManagementError::BlockNumberAbsent) + }; + if block_number < startup_point.finalized_number { + return Ok(Default::default()) + } + + // The tree route contains the exclusive path from the last finalized block to the block + // reported by the notification. Ensure the finalized block is also reported. + let mut finalized_block_hashes = + notification.tree_route.iter().cloned().collect::>(); + finalized_block_hashes.push(last_finalized); + + // If the finalized hashes were not reported yet, generate the `NewBlock` events. + let mut events = self.generate_finalized_events(&finalized_block_hashes)?; + + // Report all pruned blocks from the notification that are not + // part of the fork we need to ignore. + let pruned_block_hashes = + self.get_pruned_hashes(¬ification.stale_heads, last_finalized, to_ignore)?; + + let finalized_event = FollowEvent::Finalized(Finalized { + finalized_block_hashes, + pruned_block_hashes: pruned_block_hashes.clone(), + }); + + match self.best_block_cache { + Some(block_cache) => { + // Check if the current best block is also reported as pruned. + let reported_pruned = pruned_block_hashes.iter().find(|&&hash| hash == block_cache); + if reported_pruned.is_none() { + events.push(finalized_event); + return Ok(events) + } + + // The best block is reported as pruned. Therefore, we need to signal a new + // best block event before submitting the finalized event. + let best_block_hash = self.client.info().best_hash; + if best_block_hash == block_cache { + // The client doest not have any new information about the best block. + // The information from `.info()` is updated from the DB as the last + // step of the finalization and it should be up to date. + // If the info is outdated, there is nothing the RPC can do for now. + error!( + target: LOG_TARGET, + "[follow][id={:?}] Client does not contain different best block", + self.sub_id, + ); + events.push(finalized_event); + Ok(events) + } else { + let ancestor = sp_blockchain::lowest_common_ancestor( + &*self.client, + last_finalized, + best_block_hash, + )?; + + // The client's best block must be a descendent of the last finalized block. + // In other words, the lowest common ancestor must be the last finalized block. + if ancestor.hash != last_finalized { + return Err(SubscriptionManagementError::Custom( + "The finalized block is not an ancestor of the best block".into(), + )) + } + + // The RPC needs to also submit a new best block changed before the + // finalized event. + self.best_block_cache = Some(best_block_hash); + let best_block_event = + FollowEvent::BestBlockChanged(BestBlockChanged { best_block_hash }); + events.extend([best_block_event, finalized_event]); + Ok(events) + } + }, + None => { + events.push(finalized_event); + Ok(events) + }, + } + } + + /// Submit the events from the provided stream to the RPC client + /// for as long as the `rx_stop` event was not called. + async fn submit_events( + &mut self, + startup_point: &StartupPoint, + mut stream: EventStream, + mut to_ignore: HashSet, + mut sink: SubscriptionSink, + rx_stop: oneshot::Receiver<()>, + ) where + EventStream: Stream> + Unpin, + { + let mut stream_item = stream.next(); + let mut stop_event = rx_stop; + + while let Either::Left((Some(event), next_stop_event)) = + futures_util::future::select(stream_item, stop_event).await + { + let events = match event { + NotificationType::InitialEvents(events) => Ok(events), + NotificationType::NewBlock(notification) => + self.handle_import_blocks(notification, &startup_point), + NotificationType::Finalized(notification) => + self.handle_finalized_blocks(notification, &mut to_ignore, &startup_point), + }; + + let events = match events { + Ok(events) => events, + Err(err) => { + debug!( + target: LOG_TARGET, + "[follow][id={:?}] Failed to handle stream notification {:?}", + self.sub_id, + err + ); + let _ = sink.send(&FollowEvent::::Stop); + return + }, + }; + + for event in events { + let result = sink.send(&event); + + // Migration note: the new version of jsonrpsee returns Result<(), DisconnectError> + // The logic from `Err(err)` should be moved when building the new + // `SubscriptionMessage`. + + // For now, jsonrpsee returns: + // Ok(true): message sent + // Ok(false): client disconnected or subscription closed + // Err(err): serder serialization error of the event + if let Err(err) = result { + // Failed to submit event. + debug!( + target: LOG_TARGET, + "[follow][id={:?}] Failed to send event {:?}", self.sub_id, err + ); + + let _ = sink.send(&FollowEvent::::Stop); + return + } + + if let Ok(false) = result { + // Client disconnected or subscription was closed. + return + } + } + + stream_item = stream.next(); + stop_event = next_stop_event; + } + } + + /// Generate the block events for the `chainHead_follow` method. + pub async fn generate_events( + &mut self, + mut sink: SubscriptionSink, + rx_stop: oneshot::Receiver<()>, + ) { + // Register for the new block and finalized notifications. + let stream_import = self + .client + .import_notification_stream() + .map(|notification| NotificationType::NewBlock(notification)); + + let stream_finalized = self + .client + .finality_notification_stream() + .map(|notification| NotificationType::Finalized(notification)); + + let startup_point = StartupPoint::from(self.client.info()); + let (initial_events, pruned_forks) = match self.generate_init_events(&startup_point) { + Ok(blocks) => blocks, + Err(err) => { + debug!( + target: LOG_TARGET, + "[follow][id={:?}] Failed to generate the initial events {:?}", + self.sub_id, + err + ); + let _ = sink.send(&FollowEvent::::Stop); + return + }, + }; + + let initial = NotificationType::InitialEvents(initial_events); + let merged = tokio_stream::StreamExt::merge(stream_import, stream_finalized); + let stream = stream::once(futures::future::ready(initial)).chain(merged); + + self.submit_events(&startup_point, stream.boxed(), pruned_forks, sink, rx_stop) + .await; + } +} diff --git a/client/rpc-spec-v2/src/chain_head/mod.rs b/client/rpc-spec-v2/src/chain_head/mod.rs index 3d6d5a916aa75..afa8d3b2189ae 100644 --- a/client/rpc-spec-v2/src/chain_head/mod.rs +++ b/client/rpc-spec-v2/src/chain_head/mod.rs @@ -30,6 +30,7 @@ pub mod chain_head; pub mod error; pub mod event; +mod chain_head_follow; mod subscription; pub use api::ChainHeadApiServer; diff --git a/client/rpc-spec-v2/src/chain_head/subscription.rs b/client/rpc-spec-v2/src/chain_head/subscription.rs index e52336097086d..77d57e747ebc1 100644 --- a/client/rpc-spec-v2/src/chain_head/subscription.rs +++ b/client/rpc-spec-v2/src/chain_head/subscription.rs @@ -19,7 +19,8 @@ //! Subscription management for tracking subscription IDs to pinned blocks. use futures::channel::oneshot; -use parking_lot::{RwLock, RwLockWriteGuard}; +use parking_lot::RwLock; +use sp_blockchain::Error; use sp_runtime::traits::Block as BlockT; use std::{ collections::{hash_map::Entry, HashMap, HashSet}, @@ -33,10 +34,22 @@ pub enum SubscriptionManagementError { /// the subscription has exceeded the maximum number /// of blocks pinned. ExceededLimits, + /// Error originated from the blockchain (client or backend). + Blockchain(Error), + /// The database does not contain a block number. + BlockNumberAbsent, + /// The database does not contain a block hash. + BlockHashAbsent, /// Custom error. Custom(String), } +impl From for SubscriptionManagementError { + fn from(err: Error) -> Self { + SubscriptionManagementError::Blockchain(err) + } +} + /// Inner subscription data structure. struct SubscriptionInner { /// The `runtime_updates` parameter flag of the subscription. @@ -53,10 +66,6 @@ struct SubscriptionInner { #[derive(Clone)] pub struct SubscriptionHandle { inner: Arc>>, - /// The best reported block by this subscription. - /// Have this as a separate variable to easily share - /// the write guard with the RPC layer. - best_block: Arc>>, } impl SubscriptionHandle { @@ -69,7 +78,6 @@ impl SubscriptionHandle { blocks: HashSet::new(), max_pinned_blocks, })), - best_block: Arc::new(RwLock::new(None)), } } @@ -125,11 +133,6 @@ impl SubscriptionHandle { let inner = self.inner.read(); inner.runtime_updates } - - /// Get the write guard of the best reported block. - pub fn best_block_write(&self) -> RwLockWriteGuard<'_, Option> { - self.best_block.write() - } } /// Manage block pinning / unpinning for subscription IDs. diff --git a/client/rpc-spec-v2/src/chain_head/tests.rs b/client/rpc-spec-v2/src/chain_head/tests.rs index 79be391368f71..0886efa94a756 100644 --- a/client/rpc-spec-v2/src/chain_head/tests.rs +++ b/client/rpc-spec-v2/src/chain_head/tests.rs @@ -1015,4 +1015,305 @@ async fn follow_prune_best_block() { pruned_block_hashes: vec![format!("{:?}", block_2_hash)], }); assert_eq!(event, expected); + + // Pruned hash can be unpinned. + let sub_id = sub.subscription_id(); + let sub_id = serde_json::to_string(&sub_id).unwrap(); + let hash = format!("{:?}", block_2_hash); + let _res: () = api.call("chainHead_unstable_unpin", [&sub_id, &hash]).await.unwrap(); +} + +#[tokio::test] +async fn follow_forks_pruned_block() { + let builder = TestClientBuilder::new(); + let backend = builder.backend(); + let mut client = Arc::new(builder.build()); + + let api = ChainHead::new( + client.clone(), + backend, + Arc::new(TaskExecutor::default()), + CHAIN_GENESIS, + MAX_PINNED_BLOCKS, + ) + .into_rpc(); + + // Block tree before the subscription: + // + // finalized -> block 1 -> block 2 -> block 3 + // ^^^ finalized + // -> block 1 -> block 4 -> block 5 + // + + let block_1 = client.new_block(Default::default()).unwrap().build().unwrap().block; + client.import(BlockOrigin::Own, block_1.clone()).await.unwrap(); + + let block_2 = client.new_block(Default::default()).unwrap().build().unwrap().block; + client.import(BlockOrigin::Own, block_2.clone()).await.unwrap(); + + let block_3 = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block_3_hash = block_3.header.hash(); + client.import(BlockOrigin::Own, block_3.clone()).await.unwrap(); + + // Block 4 with parent Block 1 is not the best imported. + let mut block_builder = + client.new_block_at(block_1.header.hash(), Default::default(), false).unwrap(); + // This push is required as otherwise block 4 has the same hash as block 2 and won't get + // imported + block_builder + .push_transfer(Transfer { + from: AccountKeyring::Alice.into(), + to: AccountKeyring::Ferdie.into(), + amount: 41, + nonce: 0, + }) + .unwrap(); + let block_4 = block_builder.build().unwrap().block; + client.import(BlockOrigin::Own, block_4.clone()).await.unwrap(); + + let mut block_builder = + client.new_block_at(block_4.header.hash(), Default::default(), false).unwrap(); + block_builder + .push_transfer(Transfer { + from: AccountKeyring::Bob.into(), + to: AccountKeyring::Ferdie.into(), + amount: 41, + nonce: 0, + }) + .unwrap(); + let block_5 = block_builder.build().unwrap().block; + client.import(BlockOrigin::Own, block_5.clone()).await.unwrap(); + + // Block 4 and 5 are not pruned, pruning happens at height (N - 1). + client.finalize_block(block_3_hash, None).unwrap(); + + let mut sub = api.subscribe("chainHead_unstable_follow", [false]).await.unwrap(); + + // Initialized must always be reported first. + let event: FollowEvent = get_next_event(&mut sub).await; + let expected = FollowEvent::Initialized(Initialized { + finalized_block_hash: format!("{:?}", block_3_hash), + finalized_block_runtime: None, + runtime_updates: false, + }); + assert_eq!(event, expected); + + // Block tree: + // + // finalized -> block 1 -> block 2 -> block 3 -> block 6 + // ^^^ finalized + // -> block 1 -> block 4 -> block 5 + // + // Mark block 6 as finalized to force block 4 and 5 to get pruned. + + let block_6 = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block_6_hash = block_6.header.hash(); + client.import(BlockOrigin::Own, block_6.clone()).await.unwrap(); + + client.finalize_block(block_6_hash, None).unwrap(); + + // Check block 6. + let event: FollowEvent = get_next_event(&mut sub).await; + let expected = FollowEvent::NewBlock(NewBlock { + block_hash: format!("{:?}", block_6_hash), + parent_block_hash: format!("{:?}", block_3_hash), + new_runtime: None, + runtime_updates: false, + }); + assert_eq!(event, expected); + let event: FollowEvent = get_next_event(&mut sub).await; + let expected = FollowEvent::BestBlockChanged(BestBlockChanged { + best_block_hash: format!("{:?}", block_6_hash), + }); + assert_eq!(event, expected); + + // Block 4 and 5 must not be reported as pruned. + let event: FollowEvent = get_next_event(&mut sub).await; + let expected = FollowEvent::Finalized(Finalized { + finalized_block_hashes: vec![format!("{:?}", block_6_hash)], + pruned_block_hashes: vec![], + }); + assert_eq!(event, expected); +} + +#[tokio::test] +async fn follow_report_multiple_pruned_block() { + let builder = TestClientBuilder::new(); + let backend = builder.backend(); + let mut client = Arc::new(builder.build()); + + let api = ChainHead::new( + client.clone(), + backend, + Arc::new(TaskExecutor::default()), + CHAIN_GENESIS, + MAX_PINNED_BLOCKS, + ) + .into_rpc(); + + // Block tree: + // + // finalized -> block 1 -> block 2 -> block 3 + // ^^^ finalized after subscription + // -> block 1 -> block 4 -> block 5 + + let finalized_hash = client.info().finalized_hash; + + let block_1 = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block_1_hash = block_1.header.hash(); + client.import(BlockOrigin::Own, block_1.clone()).await.unwrap(); + + let block_2 = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block_2_hash = block_2.header.hash(); + client.import(BlockOrigin::Own, block_2.clone()).await.unwrap(); + + let block_3 = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block_3_hash = block_3.header.hash(); + client.import(BlockOrigin::Own, block_3.clone()).await.unwrap(); + + // Block 4 with parent Block 1 is not the best imported. + let mut block_builder = + client.new_block_at(block_1.header.hash(), Default::default(), false).unwrap(); + // This push is required as otherwise block 4 has the same hash as block 2 and won't get + // imported + block_builder + .push_transfer(Transfer { + from: AccountKeyring::Alice.into(), + to: AccountKeyring::Ferdie.into(), + amount: 41, + nonce: 0, + }) + .unwrap(); + let block_4 = block_builder.build().unwrap().block; + let block_4_hash = block_4.header.hash(); + client.import(BlockOrigin::Own, block_4.clone()).await.unwrap(); + + let mut block_builder = + client.new_block_at(block_4.header.hash(), Default::default(), false).unwrap(); + block_builder + .push_transfer(Transfer { + from: AccountKeyring::Bob.into(), + to: AccountKeyring::Ferdie.into(), + amount: 41, + nonce: 0, + }) + .unwrap(); + let block_5 = block_builder.build().unwrap().block; + let block_5_hash = block_5.header.hash(); + client.import(BlockOrigin::Own, block_5.clone()).await.unwrap(); + let mut sub = api.subscribe("chainHead_unstable_follow", [false]).await.unwrap(); + + // Initialized must always be reported first. + let event: FollowEvent = get_next_event(&mut sub).await; + let expected = FollowEvent::Initialized(Initialized { + finalized_block_hash: format!("{:?}", finalized_hash), + finalized_block_runtime: None, + runtime_updates: false, + }); + assert_eq!(event, expected); + + let event: FollowEvent = get_next_event(&mut sub).await; + let expected = FollowEvent::NewBlock(NewBlock { + block_hash: format!("{:?}", block_1_hash), + parent_block_hash: format!("{:?}", finalized_hash), + new_runtime: None, + runtime_updates: false, + }); + assert_eq!(event, expected); + + let event: FollowEvent = get_next_event(&mut sub).await; + let expected = FollowEvent::NewBlock(NewBlock { + block_hash: format!("{:?}", block_2_hash), + parent_block_hash: format!("{:?}", block_1_hash), + new_runtime: None, + runtime_updates: false, + }); + assert_eq!(event, expected); + + let event: FollowEvent = get_next_event(&mut sub).await; + let expected = FollowEvent::NewBlock(NewBlock { + block_hash: format!("{:?}", block_3_hash), + parent_block_hash: format!("{:?}", block_2_hash), + new_runtime: None, + runtime_updates: false, + }); + assert_eq!(event, expected); + + // The fork must also be reported. + let event: FollowEvent = get_next_event(&mut sub).await; + let expected = FollowEvent::NewBlock(NewBlock { + block_hash: format!("{:?}", block_4_hash), + parent_block_hash: format!("{:?}", block_1_hash), + new_runtime: None, + runtime_updates: false, + }); + assert_eq!(event, expected); + + let event: FollowEvent = get_next_event(&mut sub).await; + let expected = FollowEvent::NewBlock(NewBlock { + block_hash: format!("{:?}", block_5_hash), + parent_block_hash: format!("{:?}", block_4_hash), + new_runtime: None, + runtime_updates: false, + }); + assert_eq!(event, expected); + + // The best block of the chain must also be reported. + let event: FollowEvent = get_next_event(&mut sub).await; + let expected = FollowEvent::BestBlockChanged(BestBlockChanged { + best_block_hash: format!("{:?}", block_3_hash), + }); + assert_eq!(event, expected); + + // Block 4 and 5 are not pruned, pruning happens at height (N - 1). + client.finalize_block(block_3_hash, None).unwrap(); + + // Finalizing block 3 directly will also result in block 1 and 2 being finalized. + let event: FollowEvent = get_next_event(&mut sub).await; + let expected = FollowEvent::Finalized(Finalized { + finalized_block_hashes: vec![ + format!("{:?}", block_1_hash), + format!("{:?}", block_2_hash), + format!("{:?}", block_3_hash), + ], + pruned_block_hashes: vec![], + }); + assert_eq!(event, expected); + + // Block tree: + // + // finalized -> block 1 -> block 2 -> block 3 -> block 6 + // ^^^ finalized + // -> block 1 -> block 4 -> block 5 + // + // Mark block 6 as finalized to force block 4 and 5 to get pruned. + + let block_6 = client.new_block(Default::default()).unwrap().build().unwrap().block; + let block_6_hash = block_6.header.hash(); + client.import(BlockOrigin::Own, block_6.clone()).await.unwrap(); + + client.finalize_block(block_6_hash, None).unwrap(); + + // Check block 6. + let event: FollowEvent = get_next_event(&mut sub).await; + let expected = FollowEvent::NewBlock(NewBlock { + block_hash: format!("{:?}", block_6_hash), + parent_block_hash: format!("{:?}", block_3_hash), + new_runtime: None, + runtime_updates: false, + }); + assert_eq!(event, expected); + let event: FollowEvent = get_next_event(&mut sub).await; + let expected = FollowEvent::BestBlockChanged(BestBlockChanged { + best_block_hash: format!("{:?}", block_6_hash), + }); + assert_eq!(event, expected); + + // Block 4 and 5 be reported as pruned, not just the stale head (block 5). + let event: FollowEvent = get_next_event(&mut sub).await; + let expected = FollowEvent::Finalized(Finalized { + finalized_block_hashes: vec![format!("{:?}", block_6_hash)], + pruned_block_hashes: vec![format!("{:?}", block_4_hash), format!("{:?}", block_5_hash)], + }); + assert_eq!(event, expected); } From d90e41ae9bf51319b2579a3c932e7412e4726aa7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= <123550+andresilva@users.noreply.github.com> Date: Tue, 7 Mar 2023 10:47:13 +0000 Subject: [PATCH 480/715] core: remove unused localized signature type (#13552) --- primitives/core/src/ed25519.rs | 10 ---------- primitives/core/src/sr25519.rs | 11 ----------- 2 files changed, 21 deletions(-) diff --git a/primitives/core/src/ed25519.rs b/primitives/core/src/ed25519.rs index 4eb9401a9bde2..76b3064ad5a44 100644 --- a/primitives/core/src/ed25519.rs +++ b/primitives/core/src/ed25519.rs @@ -332,16 +332,6 @@ impl Signature { } } -/// A localized signature also contains sender information. -#[cfg(feature = "std")] -#[derive(PartialEq, Eq, Clone, Debug, Encode, Decode)] -pub struct LocalizedSignature { - /// The signer of the signature. - pub signer: Public, - /// The signature itself. - pub signature: Signature, -} - 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 1206cf5f431fa..809d83aaf08a8 100644 --- a/primitives/core/src/sr25519.rs +++ b/primitives/core/src/sr25519.rs @@ -307,17 +307,6 @@ impl sp_std::fmt::Debug for Signature { } } -/// 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")] -#[derive(PartialEq, Eq, Clone, Debug)] -pub struct LocalizedSignature { - /// The signer of the signature. - pub signer: Public, - /// The signature itself. - pub signature: Signature, -} - impl UncheckedFrom<[u8; 64]> for Signature { fn unchecked_from(data: [u8; 64]) -> Signature { Signature(data) From 8d0b7564d5ba9ee0223a84f72ed15ac64c3be068 Mon Sep 17 00:00:00 2001 From: afm Date: Tue, 7 Mar 2023 08:14:12 -0300 Subject: [PATCH 481/715] Pub enum runtime to pub struct runtime (#13250) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * pub enum Runtime -> pub struct Runtime * changing some more * fmt * updating *.stderr files * re-run trybuild after rust update * keep a test file for `pub enum Runtime` * Delete construct_runtime_2.rs * ".git/.scripts/commands/fmt/fmt.sh" --------- Co-authored-by: Bastian Köcher Co-authored-by: parity-processbot <> --- bin/node/runtime/src/lib.rs | 2 +- frame/bags-list/src/mock.rs | 2 +- frame/election-provider-multi-phase/src/mock.rs | 2 +- frame/election-provider-support/src/onchain.rs | 2 +- frame/executive/src/lib.rs | 2 +- frame/fast-unstake/src/mock.rs | 5 +++-- frame/im-online/src/mock.rs | 2 +- frame/nomination-pools/benchmarking/src/mock.rs | 2 +- frame/nomination-pools/src/mock.rs | 2 +- frame/nomination-pools/test-staking/src/mock.rs | 2 +- frame/offences/src/mock.rs | 2 +- frame/support/test/compile_pass/src/lib.rs | 5 +++-- frame/support/test/tests/construct_runtime.rs | 4 ++-- .../construct_runtime_ui/abundant_where_param.rs | 2 +- .../both_use_and_excluded_parts.rs | 2 +- .../tests/construct_runtime_ui/conflicting_index.rs | 2 +- .../construct_runtime_ui/conflicting_index_2.rs | 2 +- .../construct_runtime_ui/conflicting_module_name.rs | 2 +- .../construct_runtime_ui/double_module_parts.rs | 2 +- .../tests/construct_runtime_ui/duplicate_exclude.rs | 2 +- .../tests/construct_runtime_ui/empty_pallet_path.rs | 2 +- .../tests/construct_runtime_ui/exclude_missspell.rs | 2 +- .../construct_runtime_ui/exclude_undefined_part.rs | 2 +- .../feature_gated_system_pallet.rs | 2 +- .../generics_in_invalid_module.rs | 2 +- .../construct_runtime_ui/invalid_meta_literal.rs | 2 +- .../construct_runtime_ui/invalid_module_details.rs | 2 +- .../invalid_module_details_keyword.rs | 2 +- .../construct_runtime_ui/invalid_module_entry.rs | 2 +- .../invalid_token_after_module.rs | 2 +- .../construct_runtime_ui/invalid_token_after_name.rs | 2 +- .../construct_runtime_ui/invalid_where_param.rs | 2 +- .../missing_event_generic_on_module_with_instance.rs | 2 +- .../construct_runtime_ui/missing_module_instance.rs | 2 +- ...missing_origin_generic_on_module_with_instance.rs | 2 +- .../construct_runtime_ui/missing_system_module.rs | 2 +- .../construct_runtime_ui/missing_where_block.rs | 2 +- .../construct_runtime_ui/missing_where_block.stderr | 6 +++--- .../construct_runtime_ui/missing_where_param.rs | 2 +- .../construct_runtime_ui/more_than_256_modules.rs | 2 +- .../construct_runtime_ui/no_comma_after_where.rs | 2 +- .../construct_runtime_ui/no_std_genesis_config.rs | 2 +- .../no_std_genesis_config.stderr | 6 +++--- .../old_unsupported_pallet_decl.rs | 2 +- .../old_unsupported_pallet_decl.stderr | 8 ++++---- .../construct_runtime_ui/pallet_error_too_large.rs | 2 +- .../pallet_error_too_large.stderr | 2 +- .../construct_runtime_ui/undefined_call_part.rs | 2 +- .../construct_runtime_ui/undefined_call_part.stderr | 2 +- .../construct_runtime_ui/undefined_event_part.rs | 2 +- .../construct_runtime_ui/undefined_event_part.stderr | 4 ++-- .../undefined_genesis_config_part.rs | 2 +- .../undefined_genesis_config_part.stderr | 6 +++--- .../construct_runtime_ui/undefined_inherent_part.rs | 2 +- .../undefined_inherent_part.stderr | 12 ++++++------ .../construct_runtime_ui/undefined_origin_part.rs | 2 +- .../undefined_origin_part.stderr | 6 +++--- .../undefined_validate_unsigned_part.rs | 2 +- .../undefined_validate_unsigned_part.stderr | 8 ++++---- .../unsupported_meta_structure.rs | 2 +- .../construct_runtime_ui/unsupported_pallet_attr.rs | 2 +- .../tests/construct_runtime_ui/use_undefined_part.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 +- .../test/tests/pallet_compatibility_instance.rs | 2 +- frame/support/test/tests/pallet_instance.rs | 2 +- .../test/tests/pallet_with_name_trait_is_valid.rs | 2 +- frame/support/test/tests/storage_layers.rs | 2 +- frame/system/benches/bench.rs | 2 +- .../transaction-payment/asset-tx-payment/src/mock.rs | 3 ++- frame/transaction-payment/src/mock.rs | 2 +- 73 files changed, 99 insertions(+), 96 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 0c21fcc904fa1..3d160108f62bb 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1740,7 +1740,7 @@ impl frame_benchmarking_pallet_pov::Config for Runtime { } construct_runtime!( - pub enum Runtime where + pub struct Runtime where Block = Block, NodeBlock = node_primitives::Block, UncheckedExtrinsic = UncheckedExtrinsic diff --git a/frame/bags-list/src/mock.rs b/frame/bags-list/src/mock.rs index 2ccc3c438af37..a48b66b200e8e 100644 --- a/frame/bags-list/src/mock.rs +++ b/frame/bags-list/src/mock.rs @@ -88,7 +88,7 @@ impl bags_list::Config for Runtime { type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; type Block = frame_system::mocking::MockBlock; frame_support::construct_runtime!( - pub enum Runtime where + pub struct Runtime where Block = Block, NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic, diff --git a/frame/election-provider-multi-phase/src/mock.rs b/frame/election-provider-multi-phase/src/mock.rs index a46aa861ecf86..8dee94bb39716 100644 --- a/frame/election-provider-multi-phase/src/mock.rs +++ b/frame/election-provider-multi-phase/src/mock.rs @@ -54,7 +54,7 @@ pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; frame_support::construct_runtime!( - pub enum Runtime where + pub struct Runtime where Block = Block, NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic diff --git a/frame/election-provider-support/src/onchain.rs b/frame/election-provider-support/src/onchain.rs index 296ac976d59f3..a312562d4944c 100644 --- a/frame/election-provider-support/src/onchain.rs +++ b/frame/election-provider-support/src/onchain.rs @@ -197,7 +197,7 @@ mod tests { pub type Block = sp_runtime::generic::Block; frame_support::construct_runtime!( - pub enum Runtime where + pub struct Runtime where Block = Block, NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index 05f3ee4f53588..b3a04c4fe0596 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -838,7 +838,7 @@ mod tests { } frame_support::construct_runtime!( - pub enum Runtime where + pub struct Runtime where Block = TestBlock, NodeBlock = TestBlock, UncheckedExtrinsic = TestUncheckedExtrinsic diff --git a/frame/fast-unstake/src/mock.rs b/frame/fast-unstake/src/mock.rs index b20ba43ab3758..c9a1d6d517308 100644 --- a/frame/fast-unstake/src/mock.rs +++ b/frame/fast-unstake/src/mock.rs @@ -193,10 +193,11 @@ impl fast_unstake::Config for Runtime { type Block = frame_system::mocking::MockBlock; type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; frame_support::construct_runtime!( - pub enum Runtime where + pub struct Runtime + where Block = Block, NodeBlock = Block, - UncheckedExtrinsic = UncheckedExtrinsic + UncheckedExtrinsic = UncheckedExtrinsic, { System: frame_system, Timestamp: pallet_timestamp, diff --git a/frame/im-online/src/mock.rs b/frame/im-online/src/mock.rs index 97b411e8719de..64e77b24b9b09 100644 --- a/frame/im-online/src/mock.rs +++ b/frame/im-online/src/mock.rs @@ -43,7 +43,7 @@ type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic type Block = frame_system::mocking::MockBlock; frame_support::construct_runtime!( - pub enum Runtime where + pub struct Runtime where Block = Block, NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic, diff --git a/frame/nomination-pools/benchmarking/src/mock.rs b/frame/nomination-pools/benchmarking/src/mock.rs index 4e188ea7ef189..f6b2022bce518 100644 --- a/frame/nomination-pools/benchmarking/src/mock.rs +++ b/frame/nomination-pools/benchmarking/src/mock.rs @@ -173,7 +173,7 @@ impl crate::Config for Runtime {} type Block = frame_system::mocking::MockBlock; type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; frame_support::construct_runtime!( - pub enum Runtime where + pub struct Runtime where Block = Block, NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic diff --git a/frame/nomination-pools/src/mock.rs b/frame/nomination-pools/src/mock.rs index 99d521df3241b..e8924c0b9c0fa 100644 --- a/frame/nomination-pools/src/mock.rs +++ b/frame/nomination-pools/src/mock.rs @@ -236,7 +236,7 @@ impl pools::Config for Runtime { type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; type Block = frame_system::mocking::MockBlock; frame_support::construct_runtime!( - pub enum Runtime where + pub struct Runtime where Block = Block, NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic, diff --git a/frame/nomination-pools/test-staking/src/mock.rs b/frame/nomination-pools/test-staking/src/mock.rs index 3d0ab2c6f35f3..85d0dd6c50677 100644 --- a/frame/nomination-pools/test-staking/src/mock.rs +++ b/frame/nomination-pools/test-staking/src/mock.rs @@ -186,7 +186,7 @@ type Block = frame_system::mocking::MockBlock; type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; frame_support::construct_runtime!( - pub enum Runtime where + pub struct Runtime where Block = Block, NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic diff --git a/frame/offences/src/mock.rs b/frame/offences/src/mock.rs index 5fc987ebdafca..d0fc7377acfd6 100644 --- a/frame/offences/src/mock.rs +++ b/frame/offences/src/mock.rs @@ -70,7 +70,7 @@ type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic type Block = frame_system::mocking::MockBlock; frame_support::construct_runtime!( - pub enum Runtime where + pub struct Runtime where Block = Block, NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic, diff --git a/frame/support/test/compile_pass/src/lib.rs b/frame/support/test/compile_pass/src/lib.rs index 1ff72bea5dd13..7e9fdaff27b03 100644 --- a/frame/support/test/compile_pass/src/lib.rs +++ b/frame/support/test/compile_pass/src/lib.rs @@ -85,10 +85,11 @@ pub type Block = generic::Block; pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; construct_runtime!( - pub enum Runtime where + pub struct Runtime + where Block = Block, NodeBlock = Block, - UncheckedExtrinsic = UncheckedExtrinsic + UncheckedExtrinsic = UncheckedExtrinsic, { System: frame_system, } diff --git a/frame/support/test/tests/construct_runtime.rs b/frame/support/test/tests/construct_runtime.rs index 24f8a278b3539..d0b31d71a6fcb 100644 --- a/frame/support/test/tests/construct_runtime.rs +++ b/frame/support/test/tests/construct_runtime.rs @@ -16,7 +16,7 @@ // limitations under the License. //! General tests for construct_runtime macro, test for: -//! * error declareed with decl_error works +//! * error declared with decl_error works //! * integrity test is generated #![recursion_limit = "128"] @@ -254,7 +254,7 @@ impl system::Config for Runtime { } frame_support::construct_runtime!( - pub enum Runtime where + pub struct Runtime where Block = Block, NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic diff --git a/frame/support/test/tests/construct_runtime_ui/abundant_where_param.rs b/frame/support/test/tests/construct_runtime_ui/abundant_where_param.rs index d5e9f225219de..ab55c22e9fbf1 100644 --- a/frame/support/test/tests/construct_runtime_ui/abundant_where_param.rs +++ b/frame/support/test/tests/construct_runtime_ui/abundant_where_param.rs @@ -1,7 +1,7 @@ use frame_support::construct_runtime; construct_runtime! { - pub enum Runtime where + pub struct Runtime where Block = Block, NodeBlock = Block, Block = Block1, 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 7a074db9986a2..ea468d6de13ee 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 @@ -20,7 +20,7 @@ pub type UncheckedExtrinsic = generic::UncheckedExtrinsic tests/construct_runtime_ui/missing_where_block.rs:4:19 + --> tests/construct_runtime_ui/missing_where_block.rs:4:21 | -4 | pub enum Runtime {} - | ^ +4 | pub struct Runtime {} + | ^ diff --git a/frame/support/test/tests/construct_runtime_ui/missing_where_param.rs b/frame/support/test/tests/construct_runtime_ui/missing_where_param.rs index 2e311c5ea01ae..4d2225a4afbc9 100644 --- a/frame/support/test/tests/construct_runtime_ui/missing_where_param.rs +++ b/frame/support/test/tests/construct_runtime_ui/missing_where_param.rs @@ -1,7 +1,7 @@ use frame_support::construct_runtime; construct_runtime! { - pub enum Runtime where + pub struct Runtime where Block = Block, NodeBlock = Block, {} diff --git a/frame/support/test/tests/construct_runtime_ui/more_than_256_modules.rs b/frame/support/test/tests/construct_runtime_ui/more_than_256_modules.rs index 4c8331ae442c8..7dcbdb9aa4fba 100644 --- a/frame/support/test/tests/construct_runtime_ui/more_than_256_modules.rs +++ b/frame/support/test/tests/construct_runtime_ui/more_than_256_modules.rs @@ -1,7 +1,7 @@ use frame_support::construct_runtime; construct_runtime! { - pub enum Runtime where + pub struct Runtime where UncheckedExtrinsic = UncheckedExtrinsic, Block = Block, NodeBlock = Block, diff --git a/frame/support/test/tests/construct_runtime_ui/no_comma_after_where.rs b/frame/support/test/tests/construct_runtime_ui/no_comma_after_where.rs index 954fadefa1794..499f9a5cdcd54 100644 --- a/frame/support/test/tests/construct_runtime_ui/no_comma_after_where.rs +++ b/frame/support/test/tests/construct_runtime_ui/no_comma_after_where.rs @@ -1,7 +1,7 @@ use frame_support::construct_runtime; construct_runtime! { - pub enum Runtime where + pub struct Runtime where UncheckedExtrinsic = UncheckedExtrinsic Block = Block, NodeBlock = Block, 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 2ca9676406579..9c9c49c4b2740 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 @@ -38,7 +38,7 @@ impl frame_system::Config for Runtime { } construct_runtime! { - pub enum Runtime where + pub struct Runtime where Block = Block, NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic 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 d35565fb933ac..2cf451aa65135 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 @@ -2,7 +2,7 @@ error: `Pallet` does not have the std feature enabled, this will cause the `test --> tests/construct_runtime_ui/no_std_genesis_config.rs:40:1 | 40 | / construct_runtime! { -41 | | pub enum Runtime where +41 | | pub struct Runtime where 42 | | Block = Block, 43 | | NodeBlock = Block, ... | @@ -16,7 +16,7 @@ error[E0412]: cannot find type `GenesisConfig` in crate `test_pallet` --> tests/construct_runtime_ui/no_std_genesis_config.rs:40:1 | 40 | / construct_runtime! { -41 | | pub enum Runtime where +41 | | pub struct Runtime where 42 | | Block = Block, 43 | | NodeBlock = Block, ... | @@ -34,7 +34,7 @@ error[E0283]: type annotations needed --> tests/construct_runtime_ui/no_std_genesis_config.rs:40:1 | 40 | / construct_runtime! { -41 | | pub enum Runtime where +41 | | pub struct Runtime where 42 | | Block = Block, 43 | | NodeBlock = Block, ... | 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 5691549c20f34..477ca3cc088a2 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 @@ -13,7 +13,7 @@ mod pallet_old { } construct_runtime! { - pub enum Runtime where + pub struct Runtime where UncheckedExtrinsic = UncheckedExtrinsic, Block = Block, NodeBlock = Block, 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 index f8ec07e00106f..6029e7e6f48bb 100644 --- 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 @@ -1,8 +1,8 @@ error[E0433]: failed to resolve: could not find `tt_default_parts` in `pallet_old` - --> $DIR/old_unsupported_pallet_decl.rs:15:1 + --> tests/construct_runtime_ui/old_unsupported_pallet_decl.rs:15:1 | 15 | / construct_runtime! { -16 | | pub enum Runtime where +16 | | pub struct Runtime where 17 | | UncheckedExtrinsic = UncheckedExtrinsic, 18 | | Block = Block, ... | @@ -13,7 +13,7 @@ error[E0433]: failed to resolve: could not find `tt_default_parts` in `pallet_ol = 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 + --> tests/construct_runtime_ui/old_unsupported_pallet_decl.rs:6:2 | 6 | decl_storage! { | ^^^^^^^^^^^^ @@ -22,7 +22,7 @@ error: cannot find macro `decl_storage` in this scope frame_support::decl_storage error: cannot find macro `decl_module` in this scope - --> $DIR/old_unsupported_pallet_decl.rs:10:2 + --> tests/construct_runtime_ui/old_unsupported_pallet_decl.rs:10:2 | 10 | decl_module! { | ^^^^^^^^^^^ 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 b7ccadb5e3e58..866c3f0de6c3c 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 @@ -72,7 +72,7 @@ impl frame_system::Config for Runtime { } construct_runtime! { - pub enum Runtime where + pub struct Runtime where Block = Block, NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic 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 99a543eef7a8a..b9cec02a2b092 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 @@ -2,7 +2,7 @@ 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 +75 | | pub struct Runtime where 76 | | Block = Block, 77 | | NodeBlock = Block, ... | 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 abe5c4cfeb343..0010f5277bb40 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 @@ -47,7 +47,7 @@ impl frame_system::Config for Runtime { } construct_runtime! { - pub enum Runtime where + pub struct Runtime where Block = Block, NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic 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 6baf01e866f64..c2092edea05b5 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 @@ -5,7 +5,7 @@ error: `Pallet` does not have #[pallet::call] defined, perhaps you should remove | ^^^^^^^^^^^^^^^^^^^^^^^^ ... 49 | / construct_runtime! { -50 | | pub enum Runtime where +50 | | pub struct Runtime where 51 | | Block = Block, 52 | | NodeBlock = Block, ... | 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 9a6ac5c6251fb..35212df8f457c 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 @@ -47,7 +47,7 @@ impl frame_system::Config for Runtime { } construct_runtime! { - pub enum Runtime where + pub struct Runtime where Block = Block, NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic 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 ff8ecf3041bf6..1ca64f381b005 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 @@ -5,7 +5,7 @@ error: `Pallet` does not have #[pallet::event] defined, perhaps you should remov | ^^^^^^^^^^^^^^^^^^^^^^^^ ... 49 | / construct_runtime! { -50 | | pub enum Runtime where +50 | | pub struct Runtime where 51 | | Block = Block, 52 | | NodeBlock = Block, ... | @@ -19,7 +19,7 @@ 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 +50 | | pub struct Runtime where 51 | | Block = Block, 52 | | NodeBlock = Block, ... | 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 4facf85e280c0..ec753e9a03129 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 @@ -47,7 +47,7 @@ impl frame_system::Config for Runtime { } construct_runtime! { - pub enum Runtime where + pub struct Runtime where Block = Block, NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic 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 046369e1112b0..72099c1b94c0d 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 @@ -5,7 +5,7 @@ error: `Pallet` does not have #[pallet::genesis_config] defined, perhaps you sho | ^^^^^^^^^^^^^^^^^^^^^^^^ ... 49 | / construct_runtime! { -50 | | pub enum Runtime where +50 | | pub struct Runtime where 51 | | Block = Block, 52 | | NodeBlock = Block, ... | @@ -19,7 +19,7 @@ error[E0412]: cannot find type `GenesisConfig` in module `pallet` --> tests/construct_runtime_ui/undefined_genesis_config_part.rs:49:1 | 49 | / construct_runtime! { -50 | | pub enum Runtime where +50 | | pub struct Runtime where 51 | | Block = Block, 52 | | NodeBlock = Block, ... | @@ -37,7 +37,7 @@ error[E0283]: type annotations needed --> tests/construct_runtime_ui/undefined_genesis_config_part.rs:49:1 | 49 | / construct_runtime! { -50 | | pub enum Runtime where +50 | | pub struct Runtime where 51 | | Block = Block, 52 | | NodeBlock = Block, ... | 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 322fa2c297285..22eaccca42d97 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 @@ -47,7 +47,7 @@ impl frame_system::Config for Runtime { } construct_runtime! { - pub enum Runtime where + pub struct Runtime where Block = Block, NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic 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 74af0c264cd5e..dab6514261420 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 @@ -5,7 +5,7 @@ error: `Pallet` does not have #[pallet::inherent] defined, perhaps you should re | ^^^^^^^^^^^^^^^^^^^^^^^^ ... 49 | / construct_runtime! { -50 | | pub enum Runtime where +50 | | pub struct Runtime where 51 | | Block = Block, 52 | | NodeBlock = Block, ... | @@ -22,7 +22,7 @@ error[E0599]: no function or associated item named `create_inherent` found for s | -------------------- function or associated item `create_inherent` not found for this struct ... 49 | / construct_runtime! { -50 | | pub enum Runtime where +50 | | pub struct Runtime where 51 | | Block = Block, 52 | | NodeBlock = Block, ... | @@ -42,7 +42,7 @@ error[E0599]: no function or associated item named `is_inherent` found for struc | -------------------- function or associated item `is_inherent` not found for this struct ... 49 | / construct_runtime! { -50 | | pub enum Runtime where +50 | | pub struct Runtime where 51 | | Block = Block, 52 | | NodeBlock = Block, ... | @@ -62,7 +62,7 @@ error[E0599]: no function or associated item named `check_inherent` found for st | -------------------- function or associated item `check_inherent` not found for this struct ... 49 | / construct_runtime! { -50 | | pub enum Runtime where +50 | | pub struct Runtime where 51 | | Block = Block, 52 | | NodeBlock = Block, ... | @@ -82,7 +82,7 @@ error[E0599]: no associated item named `INHERENT_IDENTIFIER` found for struct `p | -------------------- associated item `INHERENT_IDENTIFIER` not found for this struct ... 49 | / construct_runtime! { -50 | | pub enum Runtime where +50 | | pub struct Runtime where 51 | | Block = Block, 52 | | NodeBlock = Block, ... | @@ -102,7 +102,7 @@ error[E0599]: no function or associated item named `is_inherent_required` found | -------------------- function or associated item `is_inherent_required` not found for this struct ... 49 | / construct_runtime! { -50 | | pub enum Runtime where +50 | | pub struct Runtime where 51 | | Block = Block, 52 | | NodeBlock = Block, ... | 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 55cd5b545d6ba..1705fff49dda8 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 @@ -47,7 +47,7 @@ impl frame_system::Config for Runtime { } construct_runtime! { - pub enum Runtime where + pub struct Runtime where Block = Block, NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic 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 4907053b12877..dd1bdf76106e6 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 @@ -5,7 +5,7 @@ error: `Pallet` does not have #[pallet::origin] defined, perhaps you should remo | ^^^^^^^^^^^^^^^^^^^^^^^^ ... 49 | / construct_runtime! { -50 | | pub enum Runtime where +50 | | pub struct Runtime where 51 | | Block = Block, 52 | | NodeBlock = Block, ... | @@ -19,7 +19,7 @@ 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 +50 | | pub struct Runtime where 51 | | Block = Block, 52 | | NodeBlock = Block, ... | @@ -37,7 +37,7 @@ error[E0282]: type annotations needed --> tests/construct_runtime_ui/undefined_origin_part.rs:49:1 | 49 | / construct_runtime! { -50 | | pub enum Runtime where +50 | | pub struct Runtime where 51 | | Block = Block, 52 | | NodeBlock = Block, ... | 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 0cf305a7dc055..8f64d30940725 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 @@ -47,7 +47,7 @@ impl frame_system::Config for Runtime { } construct_runtime! { - pub enum Runtime where + pub struct Runtime where Block = Block, NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic 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 6f0b13c58933e..14106ddd09c17 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 @@ -5,7 +5,7 @@ error: `Pallet` does not have #[pallet::validate_unsigned] defined, perhaps you | ^^^^^^^^^^^^^^^^^^^^^^^^ ... 49 | / construct_runtime! { -50 | | pub enum Runtime where +50 | | pub struct Runtime where 51 | | Block = Block, 52 | | NodeBlock = Block, ... | @@ -19,7 +19,7 @@ error[E0599]: no variant or associated item named `Pallet` found for enum `Runti --> tests/construct_runtime_ui/undefined_validate_unsigned_part.rs:56:3 | 49 | / construct_runtime! { -50 | | pub enum Runtime where +50 | | pub struct Runtime where 51 | | Block = Block, 52 | | NodeBlock = Block, ... | @@ -36,7 +36,7 @@ error[E0599]: no function or associated item named `pre_dispatch` found for stru | -------------------- function or associated item `pre_dispatch` not found for this struct ... 49 | / construct_runtime! { -50 | | pub enum Runtime where +50 | | pub struct Runtime where 51 | | Block = Block, 52 | | NodeBlock = Block, ... | @@ -57,7 +57,7 @@ error[E0599]: no function or associated item named `validate_unsigned` found for | -------------------- function or associated item `validate_unsigned` not found for this struct ... 49 | / construct_runtime! { -50 | | pub enum Runtime where +50 | | pub struct Runtime where 51 | | Block = Block, 52 | | NodeBlock = Block, ... | 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 index b93adf9a780a7..e5fd284dc8722 100644 --- a/frame/support/test/tests/construct_runtime_ui/unsupported_meta_structure.rs +++ b/frame/support/test/tests/construct_runtime_ui/unsupported_meta_structure.rs @@ -1,7 +1,7 @@ use frame_support::construct_runtime; construct_runtime! { - pub enum Runtime where + pub struct Runtime where Block = Block, NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic 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 index 3ec8b9db1d435..03363d30a6429 100644 --- a/frame/support/test/tests/construct_runtime_ui/unsupported_pallet_attr.rs +++ b/frame/support/test/tests/construct_runtime_ui/unsupported_pallet_attr.rs @@ -1,7 +1,7 @@ use frame_support::construct_runtime; construct_runtime! { - pub enum Runtime where + pub struct Runtime where Block = Block, NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic 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 c74e29bc05469..971e2b831ae08 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 @@ -25,7 +25,7 @@ pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; frame_support::construct_runtime!( - pub enum Runtime where + pub struct Runtime where Block = Block, NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic diff --git a/frame/support/test/tests/pallet_compatibility.rs b/frame/support/test/tests/pallet_compatibility.rs index bd11d0da3ca65..077b3c96e992c 100644 --- a/frame/support/test/tests/pallet_compatibility.rs +++ b/frame/support/test/tests/pallet_compatibility.rs @@ -267,7 +267,7 @@ pub type Block = sp_runtime::generic::Block; pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; frame_support::construct_runtime!( - pub enum Runtime where + pub struct Runtime where Block = Block, NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic diff --git a/frame/support/test/tests/pallet_compatibility_instance.rs b/frame/support/test/tests/pallet_compatibility_instance.rs index 1d2705b12ff31..c641556beda20 100644 --- a/frame/support/test/tests/pallet_compatibility_instance.rs +++ b/frame/support/test/tests/pallet_compatibility_instance.rs @@ -268,7 +268,7 @@ pub type Block = sp_runtime::generic::Block; pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; frame_support::construct_runtime!( - pub enum Runtime where + pub struct Runtime where Block = Block, NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic diff --git a/frame/support/test/tests/pallet_instance.rs b/frame/support/test/tests/pallet_instance.rs index 6dc73a6d4230f..5beb1480a4e82 100644 --- a/frame/support/test/tests/pallet_instance.rs +++ b/frame/support/test/tests/pallet_instance.rs @@ -334,7 +334,7 @@ pub type Block = sp_runtime::generic::Block; pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; frame_support::construct_runtime!( - pub enum Runtime where + pub struct Runtime where Block = Block, NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic 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 43330dbe25b41..8cd3c79cc6c08 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 @@ -114,7 +114,7 @@ mod tests { >; frame_support::construct_runtime!( - pub enum Runtime where + pub struct Runtime where Block = TestBlock, NodeBlock = TestBlock, UncheckedExtrinsic = TestUncheckedExtrinsic diff --git a/frame/support/test/tests/storage_layers.rs b/frame/support/test/tests/storage_layers.rs index c5bbbae02e111..f124aed9aa561 100644 --- a/frame/support/test/tests/storage_layers.rs +++ b/frame/support/test/tests/storage_layers.rs @@ -114,7 +114,7 @@ impl pallet::Config for Runtime {} impl decl_pallet::Config for Runtime {} frame_support::construct_runtime!( - pub enum Runtime where + pub struct Runtime where Block = Block, NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic diff --git a/frame/system/benches/bench.rs b/frame/system/benches/bench.rs index 51652727c4766..d2b579814f8a9 100644 --- a/frame/system/benches/bench.rs +++ b/frame/system/benches/bench.rs @@ -48,7 +48,7 @@ type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic type Block = frame_system::mocking::MockBlock; frame_support::construct_runtime!( - pub enum Runtime where + pub struct Runtime where Block = Block, NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic, diff --git a/frame/transaction-payment/asset-tx-payment/src/mock.rs b/frame/transaction-payment/asset-tx-payment/src/mock.rs index bc994b4dce2cb..cd5147c3acd13 100644 --- a/frame/transaction-payment/asset-tx-payment/src/mock.rs +++ b/frame/transaction-payment/asset-tx-payment/src/mock.rs @@ -40,7 +40,8 @@ type Balance = u64; type AccountId = u64; frame_support::construct_runtime!( - pub enum Runtime where + pub struct Runtime + where Block = Block, NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic, diff --git a/frame/transaction-payment/src/mock.rs b/frame/transaction-payment/src/mock.rs index 92799bf5b0237..bfb9a194f8cb2 100644 --- a/frame/transaction-payment/src/mock.rs +++ b/frame/transaction-payment/src/mock.rs @@ -37,7 +37,7 @@ type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic type Block = frame_system::mocking::MockBlock; frame_support::construct_runtime!( - pub enum Runtime where + pub struct Runtime where Block = Block, NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic, From 8a4746e37c39dfa62552af0a47886dcc4ef1575f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= <123550+andresilva@users.noreply.github.com> Date: Tue, 7 Mar 2023 11:19:19 +0000 Subject: [PATCH 482/715] consensus: remove caching functionality from block import pipeline (#13551) * consensus: remove caching functionality from block import pipeline * client: update docs on Verifier::verify * node: fix block production benchmark --- bin/node/cli/benches/block_production.rs | 2 +- bin/node/cli/src/service.rs | 2 +- bin/node/testing/src/bench.rs | 6 ++-- client/api/src/backend.rs | 14 +++----- client/api/src/in_mem.rs | 4 +-- client/consensus/aura/src/import_queue.rs | 8 ++--- client/consensus/babe/src/lib.rs | 25 ++++++--------- client/consensus/babe/src/tests.rs | 7 ++-- client/consensus/beefy/src/import.rs | 9 +++--- client/consensus/beefy/src/tests.rs | 15 ++++----- client/consensus/common/src/block_import.rs | 13 ++------ client/consensus/common/src/import_queue.rs | 18 +++++------ .../common/src/import_queue/basic_queue.rs | 8 ++--- client/consensus/grandpa/src/import.rs | 14 ++++---- client/consensus/grandpa/src/tests.rs | 21 ++++-------- .../manual-seal/src/consensus/babe.rs | 5 ++- client/consensus/manual-seal/src/lib.rs | 6 ++-- .../consensus/manual-seal/src/seal_block.rs | 4 +-- client/consensus/pow/src/lib.rs | 11 +++---- client/consensus/pow/src/worker.rs | 3 +- client/consensus/slots/src/lib.rs | 2 +- client/db/src/lib.rs | 8 ++--- client/network/src/service/tests/mod.rs | 27 ++-------------- client/network/test/src/lib.rs | 32 +++++-------------- client/service/src/client/client.rs | 14 +++----- client/service/test/src/client/mod.rs | 4 +-- primitives/blockchain/src/backend.rs | 15 --------- primitives/consensus/common/src/lib.rs | 3 -- test-utils/client/src/client_ext.rs | 17 +++++----- 29 files changed, 103 insertions(+), 214 deletions(-) diff --git a/bin/node/cli/benches/block_production.rs b/bin/node/cli/benches/block_production.rs index e4b48497e0f88..501d69fc287b7 100644 --- a/bin/node/cli/benches/block_production.rs +++ b/bin/node/cli/benches/block_production.rs @@ -137,7 +137,7 @@ fn import_block( 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())) + futures::executor::block_on(client.import_block(params)) .expect("importing a block doesn't fail"); } diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs index 6e000a4755ecf..e9a34b2a5c728 100644 --- a/bin/node/cli/src/service.rs +++ b/bin/node/cli/src/service.rs @@ -760,7 +760,7 @@ mod tests { ); params.fork_choice = Some(ForkChoiceStrategy::LongestChain); - futures::executor::block_on(block_import.import_block(params, Default::default())) + futures::executor::block_on(block_import.import_block(params)) .expect("error importing test block"); }, |service, _| { diff --git a/bin/node/testing/src/bench.rs b/bin/node/testing/src/bench.rs index ccce6dc23cfeb..1a9af13028483 100644 --- a/bin/node/testing/src/bench.rs +++ b/bin/node/testing/src/bench.rs @@ -682,10 +682,8 @@ impl BenchContext { assert_eq!(self.client.chain_info().best_number, 0); assert_eq!( - futures::executor::block_on( - self.client.import_block(import_params, Default::default()) - ) - .expect("Failed to import block"), + futures::executor::block_on(self.client.import_block(import_params)) + .expect("Failed to import block"), ImportResult::Imported(ImportedAux { header_only: false, clear_justification_requests: false, diff --git a/client/api/src/backend.rs b/client/api/src/backend.rs index 26a0cf0351998..b88feafb6ca3a 100644 --- a/client/api/src/backend.rs +++ b/client/api/src/backend.rs @@ -18,12 +18,10 @@ //! Substrate Client data backend -use crate::{ - blockchain::{well_known_cache_keys, Backend as BlockchainBackend}, - UsageInfo, -}; +use std::collections::HashSet; + use parking_lot::RwLock; -use sp_blockchain; + use sp_consensus::BlockOrigin; use sp_core::offchain::OffchainStorage; use sp_runtime::{ @@ -35,7 +33,8 @@ use sp_state_machine::{ OffchainChangesCollection, StorageCollection, StorageIterator, }; use sp_storage::{ChildInfo, StorageData, StorageKey}; -use std::collections::{HashMap, HashSet}; + +use crate::{blockchain::Backend as BlockchainBackend, UsageInfo}; pub use sp_state_machine::{Backend as StateBackend, KeyValueStates}; @@ -179,9 +178,6 @@ pub trait BlockImportOperation { state: NewBlockState, ) -> sp_blockchain::Result<()>; - /// Update cached data. - fn update_cache(&mut self, cache: HashMap>); - /// Inject storage data into the database. fn update_db_storage( &mut self, diff --git a/client/api/src/in_mem.rs b/client/api/src/in_mem.rs index 7096910e10b93..27a74ddd79ed6 100644 --- a/client/api/src/in_mem.rs +++ b/client/api/src/in_mem.rs @@ -40,7 +40,7 @@ use std::{ use crate::{ backend::{self, NewBlockState}, - blockchain::{self, well_known_cache_keys::Id as CacheKeyId, BlockStatus, HeaderBackend}, + blockchain::{self, BlockStatus, HeaderBackend}, leaves::LeafSet, UsageInfo, }; @@ -549,8 +549,6 @@ where Ok(()) } - fn update_cache(&mut self, _cache: HashMap>) {} - fn update_db_storage( &mut self, update: > as StateBackend>>::Transaction, diff --git a/client/consensus/aura/src/import_queue.rs b/client/consensus/aura/src/import_queue.rs index 99b5af0818dc9..46e0ccb4e302a 100644 --- a/client/consensus/aura/src/import_queue.rs +++ b/client/consensus/aura/src/import_queue.rs @@ -34,7 +34,7 @@ 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::Id as CacheKeyId, HeaderBackend}; +use sp_blockchain::HeaderBackend; use sp_consensus::Error as ConsensusError; use sp_consensus_aura::{digests::CompatibleDigestItem, inherents::AuraInherentData, AuraApi}; use sp_consensus_slots::Slot; @@ -184,7 +184,7 @@ where async fn verify( &mut self, mut block: BlockImportParams, - ) -> Result<(BlockImportParams, Option)>>), String> { + ) -> Result, String> { // Skip checks that include execution, if being told so or when importing only state. // // This is done for example when gap syncing and it is expected that the block after the gap @@ -194,7 +194,7 @@ where // When we are importing only the state of a block, it will be the best block. block.fork_choice = Some(ForkChoiceStrategy::Custom(block.with_state())); - return Ok((block, Default::default())) + return Ok(block) } let hash = block.header.hash(); @@ -278,7 +278,7 @@ where block.fork_choice = Some(ForkChoiceStrategy::LongestChain); block.post_hash = Some(hash); - Ok((block, None)) + Ok(block) }, CheckedHeader::Deferred(a, b) => { debug!(target: LOG_TARGET, "Checking {:?} failed; {:?}, {:?}.", hash, a, b); diff --git a/client/consensus/babe/src/lib.rs b/client/consensus/babe/src/lib.rs index 271e3f648c261..1d42057a36b23 100644 --- a/client/consensus/babe/src/lib.rs +++ b/client/consensus/babe/src/lib.rs @@ -67,7 +67,7 @@ #![warn(missing_docs)] use std::{ - collections::{HashMap, HashSet}, + collections::HashSet, future::Future, pin::Pin, sync::Arc, @@ -114,9 +114,7 @@ use sp_blockchain::{ Backend as _, BlockStatus, Error as ClientError, ForkBackend, HeaderBackend, HeaderMetadata, Result as ClientResult, }; -use sp_consensus::{ - BlockOrigin, CacheKeyId, Environment, Error as ConsensusError, Proposer, SelectChain, -}; +use sp_consensus::{BlockOrigin, Environment, Error as ConsensusError, Proposer, SelectChain}; use sp_consensus_babe::inherents::BabeInherentData; use sp_consensus_slots::Slot; use sp_core::{crypto::ByteArray, ExecutionContext}; @@ -1131,9 +1129,6 @@ where } } -type BlockVerificationResult = - Result<(BlockImportParams, Option)>>), String>; - #[async_trait::async_trait] impl Verifier for BabeVerifier @@ -1153,7 +1148,7 @@ where async fn verify( &mut self, mut block: BlockImportParams, - ) -> BlockVerificationResult { + ) -> Result, String> { trace!( target: LOG_TARGET, "Verifying origin: {:?} header: {:?} justification(s): {:?} body: {:?}", @@ -1177,7 +1172,7 @@ where // read it from the state after import. We also skip all verifications // because there's no parent state and we trust the sync module to verify // that the state is correct and finalized. - return Ok((block, Default::default())) + return Ok(block) } debug!( @@ -1296,7 +1291,7 @@ where ); block.post_hash = Some(hash); - Ok((block, Default::default())) + Ok(block) }, CheckedHeader::Deferred(a, b) => { debug!(target: LOG_TARGET, "Checking {:?} failed; {:?}, {:?}.", hash, a, b); @@ -1368,7 +1363,6 @@ where async fn import_state( &mut self, mut block: BlockImportParams>, - new_cache: HashMap>, ) -> Result { let hash = block.post_hash(); let parent_hash = *block.header.parent_hash(); @@ -1383,7 +1377,7 @@ where }); // First make the client import the state. - let import_result = self.inner.import_block(block, new_cache).await; + let import_result = self.inner.import_block(block).await; let aux = match import_result { Ok(ImportResult::Imported(aux)) => aux, Ok(r) => @@ -1433,7 +1427,6 @@ where async fn import_block( &mut self, mut block: BlockImportParams, - new_cache: HashMap>, ) -> Result { let hash = block.post_hash(); let number = *block.header.number(); @@ -1454,11 +1447,11 @@ where // In case of initial sync intermediates should not be present... 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) + return self.inner.import_block(block).await.map_err(Into::into) } if block.with_state() { - return self.import_state(block, new_cache).await + return self.import_state(block).await } let pre_digest = find_pre_digest::(&block.header).expect( @@ -1694,7 +1687,7 @@ where epoch_changes.release_mutex() }; - let import_result = self.inner.import_block(block, new_cache).await; + let import_result = self.inner.import_block(block).await; // revert to the original epoch changes in case there's an error // importing the block diff --git a/client/consensus/babe/src/tests.rs b/client/consensus/babe/src/tests.rs index fcdada94c4538..25f1f87235702 100644 --- a/client/consensus/babe/src/tests.rs +++ b/client/consensus/babe/src/tests.rs @@ -209,9 +209,8 @@ where async fn import_block( &mut self, block: BlockImportParams, - new_cache: HashMap>, ) -> Result { - Ok(self.0.import_block(block, new_cache).await.expect("importing block failed")) + Ok(self.0.import_block(block).await.expect("importing block failed")) } async fn check_block( @@ -258,7 +257,7 @@ impl Verifier for TestVerifier { async fn verify( &mut self, mut block: BlockImportParams, - ) -> Result<(BlockImportParams, Option)>>), String> { + ) -> Result, String> { // apply post-sealing mutations (i.e. stripping seal, if desired). (self.mutator)(&mut block.header, Stage::PostSeal); self.inner.verify(block).await @@ -743,7 +742,7 @@ async fn propose_and_import_block( import .insert_intermediate(INTERMEDIATE_KEY, BabeIntermediate:: { epoch_descriptor }); import.fork_choice = Some(ForkChoiceStrategy::LongestChain); - let import_result = block_import.import_block(import, Default::default()).await.unwrap(); + let import_result = block_import.import_block(import).await.unwrap(); match import_result { ImportResult::Imported(_) => {}, diff --git a/client/consensus/beefy/src/import.rs b/client/consensus/beefy/src/import.rs index 177a99b1066b2..dd2ed92ef8353 100644 --- a/client/consensus/beefy/src/import.rs +++ b/client/consensus/beefy/src/import.rs @@ -16,13 +16,13 @@ // 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 sp_consensus_beefy::{BeefyApi, BEEFY_ENGINE_ID}; -use std::{collections::HashMap, sync::Arc}; use sp_api::{ProvideRuntimeApi, TransactionFor}; -use sp_blockchain::well_known_cache_keys; use sp_consensus::Error as ConsensusError; +use sp_consensus_beefy::{BeefyApi, BEEFY_ENGINE_ID}; use sp_runtime::{ traits::{Block as BlockT, Header as HeaderT, NumberFor}, EncodedJustification, @@ -132,7 +132,6 @@ where async fn import_block( &mut self, mut block: BlockImportParams, - new_cache: HashMap>, ) -> Result { let hash = block.post_hash(); let number = *block.header.number(); @@ -146,7 +145,7 @@ where }); // Run inner block import. - let inner_import_result = self.inner.import_block(block, new_cache).await?; + let inner_import_result = self.inner.import_block(block).await?; match (beefy_encoded, &inner_import_result) { (Some(encoded), ImportResult::Imported(_)) => { diff --git a/client/consensus/beefy/src/tests.rs b/client/consensus/beefy/src/tests.rs index fb1c45b90a83a..44920aaa6faa9 100644 --- a/client/consensus/beefy/src/tests.rs +++ b/client/consensus/beefy/src/tests.rs @@ -61,7 +61,7 @@ use sp_runtime::{ traits::{Header as HeaderT, NumberFor}, BuildStorage, DigestItem, EncodedJustification, Justifications, Storage, }; -use std::{collections::HashMap, marker::PhantomData, sync::Arc, task::Poll}; +use std::{marker::PhantomData, sync::Arc, task::Poll}; use substrate_test_runtime_client::{runtime::Header, ClientExt}; use tokio::time::Duration; @@ -766,14 +766,11 @@ async fn beefy_importing_justifications() { // Import block 1 without justifications. assert_eq!( - block_import - .import_block(params(block.clone(), None), HashMap::new()) - .await - .unwrap(), + block_import.import_block(params(block.clone(), None)).await.unwrap(), ImportResult::Imported(ImportedAux { is_new_best: true, ..Default::default() }), ); assert_eq!( - block_import.import_block(params(block, None), HashMap::new()).await.unwrap(), + block_import.import_block(params(block, None)).await.unwrap(), ImportResult::AlreadyInChain, ); @@ -788,7 +785,7 @@ async fn beefy_importing_justifications() { let encoded = versioned_proof.encode(); let justif = Some(Justifications::from((BEEFY_ENGINE_ID, encoded))); assert_eq!( - block_import.import_block(params(block, justif), HashMap::new()).await.unwrap(), + block_import.import_block(params(block, justif)).await.unwrap(), ImportResult::Imported(ImportedAux { bad_justification: false, is_new_best: true, @@ -820,7 +817,7 @@ async fn beefy_importing_justifications() { let justif = Some(Justifications::from((BEEFY_ENGINE_ID, encoded))); let mut justif_recv = justif_stream.subscribe(100_000); assert_eq!( - block_import.import_block(params(block, justif), HashMap::new()).await.unwrap(), + block_import.import_block(params(block, justif)).await.unwrap(), ImportResult::Imported(ImportedAux { bad_justification: false, is_new_best: true, @@ -856,7 +853,7 @@ async fn beefy_importing_justifications() { let justif = Some(Justifications::from((BEEFY_ENGINE_ID, encoded))); let mut justif_recv = justif_stream.subscribe(100_000); assert_eq!( - block_import.import_block(params(block, justif), HashMap::new()).await.unwrap(), + block_import.import_block(params(block, justif)).await.unwrap(), ImportResult::Imported(ImportedAux { // Still `false` because we don't want to fail import on bad BEEFY justifications. bad_justification: false, diff --git a/client/consensus/common/src/block_import.rs b/client/consensus/common/src/block_import.rs index 98accc1d2f8c4..70bf0283af2d9 100644 --- a/client/consensus/common/src/block_import.rs +++ b/client/consensus/common/src/block_import.rs @@ -25,7 +25,7 @@ use sp_runtime::{ }; use std::{any::Any, borrow::Cow, collections::HashMap, sync::Arc}; -use sp_consensus::{BlockOrigin, CacheKeyId, Error}; +use sp_consensus::{BlockOrigin, Error}; /// Block import result. #[derive(Debug, PartialEq, Eq)] @@ -348,12 +348,9 @@ pub trait BlockImport { ) -> Result; /// Import a block. - /// - /// Cached data can be accessed through the blockchain cache. async fn import_block( &mut self, block: BlockImportParams, - cache: HashMap>, ) -> Result; } @@ -374,14 +371,11 @@ where } /// Import a block. - /// - /// Cached data can be accessed through the blockchain cache. async fn import_block( &mut self, block: BlockImportParams, - cache: HashMap>, ) -> Result { - (**self).import_block(block, cache).await + (**self).import_block(block).await } } @@ -405,9 +399,8 @@ where async fn import_block( &mut self, block: BlockImportParams, - cache: HashMap>, ) -> Result { - (&**self).import_block(block, cache).await + (&**self).import_block(block).await } } diff --git a/client/consensus/common/src/import_queue.rs b/client/consensus/common/src/import_queue.rs index 66ff5e6d5e12f..cec9aca47e29f 100644 --- a/client/consensus/common/src/import_queue.rs +++ b/client/consensus/common/src/import_queue.rs @@ -27,9 +27,9 @@ //! instantiated. The `BasicQueue` and `BasicVerifier` traits allow serial //! queues to be instantiated simply. -use std::{collections::HashMap, iter::FromIterator}; - use log::{debug, trace}; + +use sp_consensus::{error::Error as ConsensusError, BlockOrigin}; use sp_runtime::{ traits::{Block as BlockT, Header as _, NumberFor}, Justifications, @@ -42,8 +42,8 @@ use crate::{ }, metrics::Metrics, }; + pub use basic_queue::BasicQueue; -use sp_consensus::{error::Error as ConsensusError, BlockOrigin, CacheKeyId}; const LOG_TARGET: &str = "sync::import-queue"; @@ -96,13 +96,12 @@ pub struct IncomingBlock { /// Verify a justification of a block #[async_trait::async_trait] pub trait Verifier: Send + Sync { - /// Verify the given data and return the BlockImportParams and an optional - /// new set of validators to import. If not, err with an Error-Message - /// presented to the User in the logs. + /// Verify the given block data and return the `BlockImportParams` to + /// continue the block import process. async fn verify( &mut self, block: BlockImportParams, - ) -> Result<(BlockImportParams, Option)>>), String>; + ) -> Result, String>; } /// Blocks import queue API. @@ -328,7 +327,7 @@ pub(crate) async fn import_single_block_metered< import_block.state_action = StateAction::ExecuteIfPossible; } - let (import_block, maybe_keys) = verifier.verify(import_block).await.map_err(|msg| { + let import_block = verifier.verify(import_block).await.map_err(|msg| { if let Some(ref peer) = peer { trace!( target: LOG_TARGET, @@ -351,9 +350,8 @@ pub(crate) async fn import_single_block_metered< metrics.report_verification(true, started.elapsed()); } - let cache = HashMap::from_iter(maybe_keys.unwrap_or_default()); let import_block = import_block.clear_storage_changes_and_mutate(); - let imported = import_handle.import_block(import_block, cache).await; + let imported = import_handle.import_block(import_block).await; if let Some(metrics) = metrics.as_ref() { metrics.report_verification_and_import(started.elapsed()); } diff --git a/client/consensus/common/src/import_queue/basic_queue.rs b/client/consensus/common/src/import_queue/basic_queue.rs index 6404708151f00..653c88321554e 100644 --- a/client/consensus/common/src/import_queue/basic_queue.rs +++ b/client/consensus/common/src/import_queue/basic_queue.rs @@ -504,19 +504,18 @@ mod tests { block_import::{ BlockCheckParams, BlockImport, BlockImportParams, ImportResult, JustificationImport, }, - import_queue::{CacheKeyId, Verifier}, + import_queue::Verifier, }; use futures::{executor::block_on, Future}; use sp_test_primitives::{Block, BlockNumber, Extrinsic, Hash, Header}; - use std::collections::HashMap; #[async_trait::async_trait] impl Verifier for () { async fn verify( &mut self, block: BlockImportParams, - ) -> Result<(BlockImportParams, Option)>>), String> { - Ok((BlockImportParams::new(block.origin, block.header), None)) + ) -> Result, String> { + Ok(BlockImportParams::new(block.origin, block.header)) } } @@ -535,7 +534,6 @@ mod tests { async fn import_block( &mut self, _block: BlockImportParams, - _cache: HashMap>, ) -> Result { Ok(ImportResult::imported(true)) } diff --git a/client/consensus/grandpa/src/import.rs b/client/consensus/grandpa/src/import.rs index c1f6cb566dae9..cd13f832ce6dc 100644 --- a/client/consensus/grandpa/src/import.rs +++ b/client/consensus/grandpa/src/import.rs @@ -29,7 +29,7 @@ use sc_consensus::{ use sc_telemetry::TelemetryHandle; use sc_utils::mpsc::TracingUnboundedSender; use sp_api::{Core, RuntimeApiInfo, TransactionFor}; -use sp_blockchain::{well_known_cache_keys, BlockStatus}; +use sp_blockchain::BlockStatus; use sp_consensus::{BlockOrigin, Error as ConsensusError, SelectChain}; use sp_consensus_grandpa::{ConsensusLog, GrandpaApi, ScheduledChange, SetId, GRANDPA_ENGINE_ID}; use sp_core::hashing::twox_128; @@ -460,13 +460,12 @@ where async fn import_state( &mut self, mut block: BlockImportParams>, - new_cache: HashMap>, ) -> Result { let hash = block.post_hash(); let number = *block.header.number(); // Force imported state finality. block.finalized = true; - let import_result = (&*self.inner).import_block(block, new_cache).await; + let import_result = (&*self.inner).import_block(block).await; match import_result { Ok(ImportResult::Imported(aux)) => { // We've just imported a new state. We trust the sync module has verified @@ -526,7 +525,6 @@ where async fn import_block( &mut self, mut block: BlockImportParams, - new_cache: HashMap>, ) -> Result { let hash = block.post_hash(); let number = *block.header.number(); @@ -537,14 +535,14 @@ where Ok(BlockStatus::InChain) => { // Strip justifications when re-importing an existing block. let _justifications = block.justifications.take(); - return (&*self.inner).import_block(block, new_cache).await + return (&*self.inner).import_block(block).await }, Ok(BlockStatus::Unknown) => {}, Err(e) => return Err(ConsensusError::ClientImport(e.to_string())), } if block.with_state() { - return self.import_state(block, new_cache).await + return self.import_state(block).await } if number <= self.inner.info().finalized_number { @@ -570,7 +568,7 @@ where }, ); } - return (&*self.inner).import_block(block, new_cache).await + return (&*self.inner).import_block(block).await } // on initial sync we will restrict logging under info to avoid spam. @@ -580,7 +578,7 @@ where // we don't want to finalize on `inner.import_block` let mut justifications = block.justifications.take(); - let import_result = (&*self.inner).import_block(block, new_cache).await; + let import_result = (&*self.inner).import_block(block).await; let mut imported_aux = { match import_result { diff --git a/client/consensus/grandpa/src/tests.rs b/client/consensus/grandpa/src/tests.rs index f7747a20301f5..f5e5c45e74207 100644 --- a/client/consensus/grandpa/src/tests.rs +++ b/client/consensus/grandpa/src/tests.rs @@ -47,10 +47,7 @@ use sp_runtime::{ traits::{Block as BlockT, Header as HeaderT}, Justifications, }; -use std::{ - collections::{HashMap, HashSet}, - pin::Pin, -}; +use std::{collections::HashSet, pin::Pin}; use substrate_test_runtime_client::runtime::BlockNumber; use tokio::runtime::Handle; @@ -906,7 +903,7 @@ async fn allows_reimporting_change_blocks() { }; assert_eq!( - block_import.import_block(block(), HashMap::new()).await.unwrap(), + block_import.import_block(block()).await.unwrap(), ImportResult::Imported(ImportedAux { needs_justification: true, clear_justification_requests: false, @@ -916,10 +913,7 @@ async fn allows_reimporting_change_blocks() { }), ); - assert_eq!( - block_import.import_block(block(), HashMap::new()).await.unwrap(), - ImportResult::AlreadyInChain - ); + assert_eq!(block_import.import_block(block()).await.unwrap(), ImportResult::AlreadyInChain); } #[tokio::test] @@ -955,7 +949,7 @@ async fn test_bad_justification() { }; assert_eq!( - block_import.import_block(block(), HashMap::new()).await.unwrap(), + block_import.import_block(block()).await.unwrap(), ImportResult::Imported(ImportedAux { needs_justification: true, clear_justification_requests: false, @@ -965,10 +959,7 @@ async fn test_bad_justification() { }), ); - assert_eq!( - block_import.import_block(block(), HashMap::new()).await.unwrap(), - ImportResult::AlreadyInChain - ); + assert_eq!(block_import.import_block(block()).await.unwrap(), ImportResult::AlreadyInChain); } #[tokio::test] @@ -1938,7 +1929,7 @@ async fn imports_justification_for_regular_blocks_on_import() { import.fork_choice = Some(ForkChoiceStrategy::LongestChain); assert_eq!( - block_import.import_block(import, HashMap::new()).await.unwrap(), + block_import.import_block(import).await.unwrap(), ImportResult::Imported(ImportedAux { needs_justification: false, clear_justification_requests: false, diff --git a/client/consensus/manual-seal/src/consensus/babe.rs b/client/consensus/manual-seal/src/consensus/babe.rs index 476d2f0f4094d..3d21fd73d95ae 100644 --- a/client/consensus/manual-seal/src/consensus/babe.rs +++ b/client/consensus/manual-seal/src/consensus/babe.rs @@ -35,7 +35,6 @@ use std::{marker::PhantomData, sync::Arc}; use sc_consensus::{BlockImportParams, ForkChoiceStrategy, Verifier}; use sp_api::{ProvideRuntimeApi, TransactionFor}; use sp_blockchain::{HeaderBackend, HeaderMetadata}; -use sp_consensus::CacheKeyId; use sp_consensus_babe::{ digests::{NextEpochDescriptor, PreDigest, SecondaryPlainPreDigest}, inherents::BabeInherentData, @@ -99,7 +98,7 @@ where async fn verify( &mut self, mut import_params: BlockImportParams, - ) -> Result<(BlockImportParams, Option)>>), String> { + ) -> Result, String> { import_params.finalized = false; import_params.fork_choice = Some(ForkChoiceStrategy::LongestChain); @@ -128,7 +127,7 @@ where import_params .insert_intermediate(INTERMEDIATE_KEY, BabeIntermediate:: { epoch_descriptor }); - Ok((import_params, None)) + Ok(import_params) } } diff --git a/client/consensus/manual-seal/src/lib.rs b/client/consensus/manual-seal/src/lib.rs index 41f1f44335525..b277b34366577 100644 --- a/client/consensus/manual-seal/src/lib.rs +++ b/client/consensus/manual-seal/src/lib.rs @@ -27,7 +27,7 @@ use sc_consensus::{ import_queue::{BasicQueue, BoxBlockImport, Verifier}, }; use sp_blockchain::HeaderBackend; -use sp_consensus::{CacheKeyId, Environment, Proposer, SelectChain}; +use sp_consensus::{Environment, Proposer, SelectChain}; use sp_inherents::CreateInherentDataProviders; use sp_runtime::{traits::Block as BlockT, ConsensusEngineId}; use std::{marker::PhantomData, sync::Arc}; @@ -62,10 +62,10 @@ impl Verifier for ManualSealVerifier { async fn verify( &mut self, mut block: BlockImportParams, - ) -> Result<(BlockImportParams, Option)>>), String> { + ) -> Result, String> { block.finalized = false; block.fork_choice = Some(ForkChoiceStrategy::LongestChain); - Ok((block, None)) + Ok(block) } } diff --git a/client/consensus/manual-seal/src/seal_block.rs b/client/consensus/manual-seal/src/seal_block.rs index eda3d91c9782b..e6133bccae885 100644 --- a/client/consensus/manual-seal/src/seal_block.rs +++ b/client/consensus/manual-seal/src/seal_block.rs @@ -27,7 +27,7 @@ use sp_blockchain::HeaderBackend; use sp_consensus::{self, BlockOrigin, Environment, Proposer, SelectChain}; use sp_inherents::{CreateInherentDataProviders, InherentDataProvider}; use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; -use std::{collections::HashMap, sync::Arc, time::Duration}; +use std::{sync::Arc, time::Duration}; /// max duration for creating a proposal in secs pub const MAX_PROPOSAL_DURATION: u64 = 10; @@ -153,7 +153,7 @@ pub async fn seal_block( 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? { + match block_import.import_block(params).await? { ImportResult::Imported(aux) => Ok(CreatedBlock { hash: ::Header::hash(&post_header), aux }), other => Err(other.into()), diff --git a/client/consensus/pow/src/lib.rs b/client/consensus/pow/src/lib.rs index 513386fb22ac0..913686b7bf36d 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}; +use sp_blockchain::HeaderBackend; use sp_consensus::{Environment, Error as ConsensusError, Proposer, SelectChain, SyncOracle}; use sp_consensus_pow::{Seal, TotalDifficulty, POW_ENGINE_ID}; use sp_core::ExecutionContext; @@ -65,7 +65,7 @@ use sp_runtime::{ traits::{Block as BlockT, Header as HeaderT}, RuntimeString, }; -use std::{cmp::Ordering, collections::HashMap, marker::PhantomData, sync::Arc, time::Duration}; +use std::{cmp::Ordering, marker::PhantomData, sync::Arc, time::Duration}; const LOG_TARGET: &str = "pow"; @@ -325,7 +325,6 @@ where async fn import_block( &mut self, mut block: BlockImportParams, - new_cache: HashMap>, ) -> Result { let best_header = self .select_chain @@ -399,7 +398,7 @@ where )); } - self.inner.import_block(block, new_cache).await.map_err(Into::into) + self.inner.import_block(block).await.map_err(Into::into) } } @@ -449,7 +448,7 @@ where async fn verify( &mut self, mut block: BlockImportParams, - ) -> Result<(BlockImportParams, Option)>>), String> { + ) -> Result, String> { let hash = block.header.hash(); let (checked_header, seal) = self.check_header(block.header)?; @@ -459,7 +458,7 @@ where block.insert_intermediate(INTERMEDIATE_KEY, intermediate); block.post_hash = Some(hash); - Ok((block, None)) + Ok(block) } } diff --git a/client/consensus/pow/src/worker.rs b/client/consensus/pow/src/worker.rs index 1a423895770fb..3cb5dfcc09260 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::{ - collections::HashMap, pin::Pin, sync::{ atomic::{AtomicUsize, Ordering}, @@ -203,7 +202,7 @@ where let header = import_block.post_header(); let mut block_import = self.block_import.lock(); - match block_import.import_block(import_block, HashMap::default()).await { + match block_import.import_block(import_block).await { Ok(res) => { res.handle_justification( &header.hash(), diff --git a/client/consensus/slots/src/lib.rs b/client/consensus/slots/src/lib.rs index ec6481a87f6d4..c18284de6a088 100644 --- a/client/consensus/slots/src/lib.rs +++ b/client/consensus/slots/src/lib.rs @@ -424,7 +424,7 @@ pub trait SimpleSlotWorker { ); let header = block_import_params.post_header(); - match self.block_import().import_block(block_import_params, Default::default()).await { + match self.block_import().import_block(block_import_params).await { Ok(res) => { res.handle_justification( &header.hash(), diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index b78c66228390d..c62b9ce0e7a61 100644 --- a/client/db/src/lib.rs +++ b/client/db/src/lib.rs @@ -68,8 +68,8 @@ use sc_client_api::{ use sc_state_db::{IsPruned, LastCanonicalized, StateDb}; use sp_arithmetic::traits::Saturating; use sp_blockchain::{ - well_known_cache_keys, Backend as _, CachedHeaderMetadata, Error as ClientError, HeaderBackend, - HeaderMetadata, HeaderMetadataCache, Result as ClientResult, + Backend as _, CachedHeaderMetadata, Error as ClientError, HeaderBackend, HeaderMetadata, + HeaderMetadataCache, Result as ClientResult, }; use sp_core::{ offchain::OffchainOverlayedChange, @@ -913,10 +913,6 @@ impl sc_client_api::backend::BlockImportOperation Ok(()) } - fn update_cache(&mut self, _cache: HashMap>) { - // Currently cache isn't implemented on full nodes. - } - fn update_db_storage(&mut self, update: PrefixedMemoryDB>) -> ClientResult<()> { self.db_updates = update; Ok(()) diff --git a/client/network/src/service/tests/mod.rs b/client/network/src/service/tests/mod.rs index 3ac7829003f45..f29e43e6ce366 100644 --- a/client/network/src/service/tests/mod.rs +++ b/client/network/src/service/tests/mod.rs @@ -33,7 +33,7 @@ use sc_network_sync::{ service::network::{NetworkServiceHandle, NetworkServiceProvider}, state_request_handler::StateRequestHandler, }; -use sp_runtime::traits::{Block as BlockT, Header as _}; +use sp_runtime::traits::Block as BlockT; use std::sync::Arc; use substrate_test_runtime_client::{ runtime::{Block as TestBlock, Hash as TestHash}, @@ -135,31 +135,10 @@ impl TestNetworkBuilder { 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())] - }); - + ) -> Result, String> { block.finalized = self.0; block.fork_choice = Some(sc_consensus::ForkChoiceStrategy::LongestChain); - Ok((block, maybe_keys)) + Ok(block) } } diff --git a/client/network/test/src/lib.rs b/client/network/test/src/lib.rs index 95381dd7b4cf1..a79e17e2fb6d1 100644 --- a/client/network/test/src/lib.rs +++ b/client/network/test/src/lib.rs @@ -67,7 +67,6 @@ use sc_network_sync::{ }; use sc_service::client::Client; use sp_blockchain::{ - well_known_cache_keys::{self, Id as CacheKeyId}, Backend as BlockchainBackend, HeaderBackend, Info as BlockchainInfo, Result as ClientResult, }; use sp_consensus::{ @@ -77,7 +76,7 @@ use sp_consensus::{ use sp_core::H256; use sp_runtime::{ codec::{Decode, Encode}, - generic::{BlockId, OpaqueDigestItemId}, + generic::BlockId, traits::{Block as BlockT, Header as HeaderT, NumberFor}, Justification, Justifications, }; @@ -112,20 +111,12 @@ impl Verifier for PassThroughVerifier { async fn verify( &mut self, mut block: BlockImportParams, - ) -> Result<(BlockImportParams, Option)>>), String> { - let maybe_keys = block - .header - .digest() - .log(|l| { - l.try_as_raw(OpaqueDigestItemId::Consensus(b"aura")) - .or_else(|| l.try_as_raw(OpaqueDigestItemId::Consensus(b"babe"))) - }) - .map(|blob| vec![(well_known_cache_keys::AUTHORITIES, blob.to_vec())]); + ) -> Result, String> { if block.fork_choice.is_none() { block.fork_choice = Some(ForkChoiceStrategy::LongestChain); }; block.finalized = self.finalized; - Ok((block, maybe_keys)) + Ok(block) } } @@ -224,9 +215,8 @@ impl BlockImport for PeersClient { async fn import_block( &mut self, block: BlockImportParams, - cache: HashMap>, ) -> Result { - self.client.import_block(block.clear_storage_changes_and_mutate(), cache).await + self.client.import_block(block.clear_storage_changes_and_mutate()).await } } @@ -392,15 +382,10 @@ where 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) = + let import_block = futures::executor::block_on(self.verifier.verify(import_block)).unwrap(); - let cache = if let Some(cache) = cache { - cache.into_iter().collect() - } else { - Default::default() - }; - futures::executor::block_on(self.block_import.import_block(import_block, cache)) + futures::executor::block_on(self.block_import.import_block(import_block)) .expect("block_import failed"); if announce_block { self.sync_service.announce_block(hash, None); @@ -633,9 +618,8 @@ where async fn import_block( &mut self, block: BlockImportParams, - cache: HashMap>, ) -> Result { - self.inner.import_block(block.clear_storage_changes_and_mutate(), cache).await + self.inner.import_block(block.clear_storage_changes_and_mutate()).await } } @@ -650,7 +634,7 @@ impl Verifier for VerifierAdapter { async fn verify( &mut self, block: BlockImportParams, - ) -> Result<(BlockImportParams, Option)>>), String> { + ) -> Result, String> { let hash = block.header.hash(); self.verifier.lock().await.verify(block).await.map_err(|e| { self.failed_verifications.lock().insert(hash, e.clone()); diff --git a/client/service/src/client/client.rs b/client/service/src/client/client.rs index 9a2a376ebc19f..3613cc760f569 100644 --- a/client/service/src/client/client.rs +++ b/client/service/src/client/client.rs @@ -51,8 +51,8 @@ use sp_api::{ ProvideRuntimeApi, }; use sp_blockchain::{ - self as blockchain, well_known_cache_keys::Id as CacheKeyId, Backend as ChainBackend, - CachedHeaderMetadata, Error, HeaderBackend as ChainHeaderBackend, HeaderMetadata, + self as blockchain, Backend as ChainBackend, CachedHeaderMetadata, Error, + HeaderBackend as ChainHeaderBackend, HeaderMetadata, }; use sp_consensus::{BlockOrigin, BlockStatus, Error as ConsensusError}; @@ -504,7 +504,6 @@ where &self, operation: &mut ClientImportOperation, import_block: BlockImportParams>, - new_cache: HashMap>, storage_changes: Option< sc_consensus::StorageChanges>, >, @@ -559,7 +558,6 @@ where body, indexed_body, storage_changes, - new_cache, finalized, auxiliary, fork_choice, @@ -599,7 +597,6 @@ where storage_changes: Option< sc_consensus::StorageChanges>, >, - new_cache: HashMap>, finalized: bool, aux: Vec<(Vec, Option>)>, fork_choice: ForkChoiceStrategy, @@ -712,7 +709,6 @@ where }, }; - operation.op.update_cache(new_cache); storage_changes }, None => None, @@ -1770,7 +1766,6 @@ where async fn import_block( &mut self, mut import_block: BlockImportParams>, - new_cache: HashMap>, ) -> Result { let span = tracing::span!(tracing::Level::DEBUG, "import_block"); let _enter = span.enter(); @@ -1785,7 +1780,7 @@ where }; self.lock_import_and_run(|operation| { - self.apply_block(operation, import_block, new_cache, storage_changes) + self.apply_block(operation, import_block, storage_changes) }) .map_err(|e| { warn!("Block import error: {}", e); @@ -1875,9 +1870,8 @@ where async fn import_block( &mut self, import_block: BlockImportParams, - new_cache: HashMap>, ) -> Result { - (&*self).import_block(import_block, new_cache).await + (&*self).import_block(import_block).await } async fn check_block( diff --git a/client/service/test/src/client/mod.rs b/client/service/test/src/client/mod.rs index c7b19ca8ba27f..cae69413c7a02 100644 --- a/client/service/test/src/client/mod.rs +++ b/client/service/test/src/client/mod.rs @@ -930,7 +930,7 @@ fn finality_target_with_best_not_on_longest_chain() { let mut import_params = BlockImportParams::new(BlockOrigin::Own, header); import_params.body = Some(extrinsics); import_params.fork_choice = Some(ForkChoiceStrategy::Custom(false)); - block_on(client.import_block(import_params, Default::default())).unwrap(); + block_on(client.import_block(import_params)).unwrap(); // double check that B3 is still the best... assert_eq!(client.info().best_hash, b3.hash()); @@ -1963,7 +1963,7 @@ fn cleans_up_closed_notification_sinks_on_block_import() { let mut import = BlockImportParams::new(origin, header); import.body = Some(extrinsics); import.fork_choice = Some(ForkChoiceStrategy::LongestChain); - block_on(client.import_block(import, Default::default())).unwrap(); + block_on(client.import_block(import)).unwrap(); }; // after importing a block we should still have 4 notification sinks diff --git a/primitives/blockchain/src/backend.rs b/primitives/blockchain/src/backend.rs index 227559239d011..e9278be1d5d3c 100644 --- a/primitives/blockchain/src/backend.rs +++ b/primitives/blockchain/src/backend.rs @@ -288,18 +288,3 @@ pub enum BlockStatus { /// Not in the queue or the blockchain. Unknown, } - -/// A list of all well known keys in the blockchain cache. -pub mod well_known_cache_keys { - /// The type representing cache keys. - pub type Id = sp_consensus::CacheKeyId; - - /// A list of authorities. - pub const AUTHORITIES: Id = *b"auth"; - - /// Current Epoch data. - pub const EPOCH: Id = *b"epch"; - - /// Changes trie configuration. - pub const CHANGES_TRIE_CONFIG: Id = *b"chtr"; -} diff --git a/primitives/consensus/common/src/lib.rs b/primitives/consensus/common/src/lib.rs index e02564654bd52..215b4448b4a8e 100644 --- a/primitives/consensus/common/src/lib.rs +++ b/primitives/consensus/common/src/lib.rs @@ -39,9 +39,6 @@ pub use select_chain::SelectChain; pub use sp_inherents::InherentData; pub use sp_state_machine::Backend as StateBackend; -/// Type of keys in the blockchain cache that consensus module could use for its needs. -pub type CacheKeyId = [u8; 4]; - /// Block status. #[derive(Debug, PartialEq, Eq)] pub enum BlockStatus { diff --git a/test-utils/client/src/client_ext.rs b/test-utils/client/src/client_ext.rs index c73ea76a3a244..a258faa5e03e3 100644 --- a/test-utils/client/src/client_ext.rs +++ b/test-utils/client/src/client_ext.rs @@ -17,7 +17,6 @@ //! Client extension for tests. -use codec::alloc::collections::hash_map::HashMap; use sc_client_api::{backend::Finalizer, client::BlockBackend}; use sc_consensus::{BlockImport, BlockImportParams, ForkChoiceStrategy}; use sc_service::client::Client; @@ -100,7 +99,7 @@ where import.body = Some(extrinsics); import.fork_choice = Some(ForkChoiceStrategy::LongestChain); - BlockImport::import_block(self, import, HashMap::new()).await.map(|_| ()) + BlockImport::import_block(self, import).await.map(|_| ()) } async fn import_as_best( @@ -113,7 +112,7 @@ where import.body = Some(extrinsics); import.fork_choice = Some(ForkChoiceStrategy::Custom(true)); - BlockImport::import_block(self, import, HashMap::new()).await.map(|_| ()) + BlockImport::import_block(self, import).await.map(|_| ()) } async fn import_as_final( @@ -127,7 +126,7 @@ where import.finalized = true; import.fork_choice = Some(ForkChoiceStrategy::Custom(true)); - BlockImport::import_block(self, import, HashMap::new()).await.map(|_| ()) + BlockImport::import_block(self, import).await.map(|_| ()) } async fn import_justified( @@ -143,7 +142,7 @@ where import.finalized = true; import.fork_choice = Some(ForkChoiceStrategy::LongestChain); - BlockImport::import_block(self, import, HashMap::new()).await.map(|_| ()) + BlockImport::import_block(self, import).await.map(|_| ()) } } @@ -162,7 +161,7 @@ where import.body = Some(extrinsics); import.fork_choice = Some(ForkChoiceStrategy::LongestChain); - BlockImport::import_block(self, import, HashMap::new()).await.map(|_| ()) + BlockImport::import_block(self, import).await.map(|_| ()) } async fn import_as_best( @@ -175,7 +174,7 @@ where import.body = Some(extrinsics); import.fork_choice = Some(ForkChoiceStrategy::Custom(true)); - BlockImport::import_block(self, import, HashMap::new()).await.map(|_| ()) + BlockImport::import_block(self, import).await.map(|_| ()) } async fn import_as_final( @@ -189,7 +188,7 @@ where import.finalized = true; import.fork_choice = Some(ForkChoiceStrategy::Custom(true)); - BlockImport::import_block(self, import, HashMap::new()).await.map(|_| ()) + BlockImport::import_block(self, import).await.map(|_| ()) } async fn import_justified( @@ -205,6 +204,6 @@ where import.finalized = true; import.fork_choice = Some(ForkChoiceStrategy::LongestChain); - BlockImport::import_block(self, import, HashMap::new()).await.map(|_| ()) + BlockImport::import_block(self, import).await.map(|_| ()) } } From 306382bce6b21a8ddeaf9a3574557e51cc8a48b6 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Tue, 7 Mar 2023 12:31:57 +0100 Subject: [PATCH 483/715] `MessageQueue`: unknit permanently overweight books (#13528) * Unknit permanently overweight books A book with only permanently overweight messages should be unkit from the ready ring. This does currently not happen since perm. overweight messages are not counted as "processed" and therefore not increase the "total_processed" counter. This is only a problem when the next and only message that is processed is overweight. Eventually this should resolve itself when another non-overweight message is enqueued and processed. But for correctness it should be unknitted. Signed-off-by: Oliver Tale-Yazdi * Add tests Signed-off-by: Oliver Tale-Yazdi * fmt Signed-off-by: Oliver Tale-Yazdi * One more tests Signed-off-by: Oliver Tale-Yazdi * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet-message-queue --------- Signed-off-by: Oliver Tale-Yazdi Co-authored-by: command-bot <> --- frame/message-queue/src/lib.rs | 4 +- frame/message-queue/src/mock.rs | 9 ++ frame/message-queue/src/mock_helpers.rs | 4 +- frame/message-queue/src/tests.rs | 115 ++++++++++++++++++++++++ frame/message-queue/src/weights.rs | 104 +++++++++------------ 5 files changed, 170 insertions(+), 66 deletions(-) diff --git a/frame/message-queue/src/lib.rs b/frame/message-queue/src/lib.rs index 409503d31725a..bed131e5f0669 100644 --- a/frame/message-queue/src/lib.rs +++ b/frame/message-queue/src/lib.rs @@ -961,11 +961,11 @@ impl Pallet { 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 { + if book_state.begin >= book_state.end { // No longer ready - unknit. if let Some(neighbours) = book_state.ready_neighbours.take() { Self::ready_ring_unknit(&origin, neighbours); - } else { + } else if total_processed > 0 { defensive!("Freshly processed queue must have been ready"); } } diff --git a/frame/message-queue/src/mock.rs b/frame/message-queue/src/mock.rs index 28a599bcf83c6..a0fe0105671e0 100644 --- a/frame/message-queue/src/mock.rs +++ b/frame/message-queue/src/mock.rs @@ -320,3 +320,12 @@ pub fn knit(queue: &MessageOrigin) { pub fn unknit(queue: &MessageOrigin) { super::mock_helpers::unknit::(queue); } + +pub fn num_overweight_enqueued_events() -> u32 { + frame_system::Pallet::::events() + .into_iter() + .filter(|e| { + matches!(e.event, RuntimeEvent::MessageQueue(crate::Event::OverweightEnqueued { .. })) + }) + .count() as u32 +} diff --git a/frame/message-queue/src/mock_helpers.rs b/frame/message-queue/src/mock_helpers.rs index 716a60782ec7f..257691cae4171 100644 --- a/frame/message-queue/src/mock_helpers.rs +++ b/frame/message-queue/src/mock_helpers.rs @@ -74,11 +74,11 @@ where } /// Create a message from the given data. -pub fn msg>(x: &'static str) -> BoundedSlice { +pub fn msg>(x: &str) -> BoundedSlice { BoundedSlice::defensive_truncate_from(x.as_bytes()) } -pub fn vmsg(x: &'static str) -> Vec { +pub fn vmsg(x: &str) -> Vec { x.as_bytes().to_vec() } diff --git a/frame/message-queue/src/tests.rs b/frame/message-queue/src/tests.rs index d3b0555f281f7..15bb905738531 100644 --- a/frame/message-queue/src/tests.rs +++ b/frame/message-queue/src/tests.rs @@ -1083,6 +1083,121 @@ fn execute_overweight_works() { assert_eq!(consumed, Err(ExecuteOverweightError::NotFound)); assert!(QueueChanges::take().is_empty()); assert!(!Pages::::contains_key(origin, 0), "Page is gone"); + // The book should have been unknit from the ready ring. + assert!(!ServiceHead::::exists(), "No ready book"); + }); +} + +#[test] +fn permanently_overweight_book_unknits() { + use MessageOrigin::*; + + 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()); + + MessageQueue::enqueue_messages([msg("weight=9")].into_iter(), Here); + + // It is the only ready book. + assert_ring(&[Here]); + // Mark the message as overweight. + assert_eq!(MessageQueue::service_queues(8.into_weight()), 4.into_weight()); + assert_last_event::( + Event::OverweightEnqueued { + hash: ::Hashing::hash(b"weight=9"), + origin: Here, + message_index: 0, + page_index: 0, + } + .into(), + ); + // The book is not ready anymore. + assert_ring(&[]); + assert_eq!(MessagesProcessed::take().len(), 0); + assert_eq!(BookStateFor::::get(Here).message_count, 1); + // Now if we enqueue another message, it will become ready again. + MessageQueue::enqueue_messages([msg("weight=1")].into_iter(), Here); + assert_ring(&[Here]); + assert_eq!(MessageQueue::service_queues(8.into_weight()), 5.into_weight()); + assert_eq!(MessagesProcessed::take().len(), 1); + assert_ring(&[]); + }); +} + +#[test] +fn permanently_overweight_book_unknits_multiple() { + use MessageOrigin::*; + + 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()); + + MessageQueue::enqueue_messages( + [msg("weight=1"), msg("weight=9"), msg("weight=9")].into_iter(), + Here, + ); + + assert_ring(&[Here]); + // Process the first message. + assert_eq!(MessageQueue::service_queues(4.into_weight()), 4.into_weight()); + assert_eq!(num_overweight_enqueued_events(), 0); + assert_eq!(MessagesProcessed::take().len(), 1); + + // Book is still ready since it was not marked as overweight yet. + assert_ring(&[Here]); + assert_eq!(MessageQueue::service_queues(8.into_weight()), 5.into_weight()); + assert_eq!(num_overweight_enqueued_events(), 2); + assert_eq!(MessagesProcessed::take().len(), 0); + // Now it is overweight. + assert_ring(&[]); + // Enqueue another message. + MessageQueue::enqueue_messages([msg("weight=1")].into_iter(), Here); + assert_ring(&[Here]); + assert_eq!(MessageQueue::service_queues(4.into_weight()), 4.into_weight()); + assert_eq!(MessagesProcessed::take().len(), 1); + assert_ring(&[]); + }); +} + +/// We don't want empty books in the ready ring, but if they somehow make their way in there, it +/// should not panic. +#[test] +#[cfg(not(debug_assertions))] // Would trigger a defensive failure otherwise. +fn ready_but_empty_does_not_panic() { + use MessageOrigin::*; + + new_test_ext::().execute_with(|| { + BookStateFor::::insert(Here, empty_book::()); + BookStateFor::::insert(There, empty_book::()); + + knit(&Here); + knit(&There); + assert_ring(&[Here, There]); + + assert_eq!(MessageQueue::service_queues(Weight::MAX), 0.into_weight()); + assert_ring(&[]); + }); +} + +/// We don't want permanently books in the ready ring, but if they somehow make their way in there, +/// it should not panic. +#[test] +#[cfg(not(debug_assertions))] // Would trigger a defensive failure otherwise. +fn ready_but_perm_overweight_does_not_panic() { + use MessageOrigin::*; + + new_test_ext::().execute_with(|| { + MessageQueue::enqueue_message(msg("weight=9"), Here); + assert_eq!(MessageQueue::service_queues(8.into_weight()), 0.into_weight()); + assert_ring(&[]); + // Force it back into the ready ring. + knit(&Here); + assert_ring(&[Here]); + assert_eq!(MessageQueue::service_queues(Weight::MAX), 0.into_weight()); + // Unready again. + assert_ring(&[]); }); } diff --git a/frame/message-queue/src/weights.rs b/frame/message-queue/src/weights.rs index d1ccb338e66c3..fd788f2ba4052 100644 --- a/frame/message-queue/src/weights.rs +++ b/frame/message-queue/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_message_queue //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -34,7 +34,7 @@ // --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 +// --pallet=pallet-message-queue // --chain=dev // --header=./HEADER-APACHE2 // --output=./frame/message-queue/src/weights.rs @@ -72,9 +72,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `295` // Estimated: `7527` - // Minimum execution time: 12_538 nanoseconds. - Weight::from_parts(12_799_000, 0) - .saturating_add(Weight::from_parts(0, 7527)) + // Minimum execution time: 12_283_000 picoseconds. + Weight::from_parts(12_554_000, 7527) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -86,9 +85,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `295` // Estimated: `7527` - // Minimum execution time: 11_727 nanoseconds. - Weight::from_parts(12_177_000, 0) - .saturating_add(Weight::from_parts(0, 7527)) + // Minimum execution time: 11_484_000 picoseconds. + Weight::from_parts(11_900_000, 7527) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -98,9 +96,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `42` // Estimated: `3514` - // Minimum execution time: 4_983 nanoseconds. - Weight::from_parts(5_174_000, 0) - .saturating_add(Weight::from_parts(0, 3514)) + // Minimum execution time: 4_793_000 picoseconds. + Weight::from_parts(4_990_000, 3514) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -110,9 +107,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `113` // Estimated: `69049` - // Minimum execution time: 6_299 nanoseconds. - Weight::from_parts(6_670_000, 0) - .saturating_add(Weight::from_parts(0, 69049)) + // Minimum execution time: 6_231_000 picoseconds. + Weight::from_parts(6_442_000, 69049) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -122,9 +118,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `113` // Estimated: `69049` - // Minimum execution time: 6_762 nanoseconds. - Weight::from_parts(7_059_000, 0) - .saturating_add(Weight::from_parts(0, 69049)) + // Minimum execution time: 6_660_000 picoseconds. + Weight::from_parts(6_825_000, 69049) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -132,9 +127,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 72_681 nanoseconds. - Weight::from_parts(73_147_000, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Minimum execution time: 72_805_000 picoseconds. + Weight::from_parts(74_650_000, 0) } /// Storage: MessageQueue ServiceHead (r:1 w:1) /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -144,9 +138,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `172` // Estimated: `5003` - // Minimum execution time: 7_066 nanoseconds. - Weight::from_parts(7_214_000, 0) - .saturating_add(Weight::from_parts(0, 5003)) + // Minimum execution time: 7_078_000 picoseconds. + Weight::from_parts(7_230_000, 5003) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -158,9 +151,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `65742` // Estimated: `72563` - // Minimum execution time: 57_778 nanoseconds. - Weight::from_parts(58_778_000, 0) - .saturating_add(Weight::from_parts(0, 72563)) + // Minimum execution time: 56_799_000 picoseconds. + Weight::from_parts(57_634_000, 72563) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -172,9 +164,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `65742` // Estimated: `72563` - // Minimum execution time: 72_144 nanoseconds. - Weight::from_parts(72_942_000, 0) - .saturating_add(Weight::from_parts(0, 72563)) + // Minimum execution time: 72_290_000 picoseconds. + Weight::from_parts(72_754_000, 72563) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -186,9 +177,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `65742` // Estimated: `72563` - // Minimum execution time: 84_890 nanoseconds. - Weight::from_parts(86_073_000, 0) - .saturating_add(Weight::from_parts(0, 72563)) + // Minimum execution time: 84_987_000 picoseconds. + Weight::from_parts(85_562_000, 72563) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -204,9 +194,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `295` // Estimated: `7527` - // Minimum execution time: 12_538 nanoseconds. - Weight::from_parts(12_799_000, 0) - .saturating_add(Weight::from_parts(0, 7527)) + // Minimum execution time: 12_283_000 picoseconds. + Weight::from_parts(12_554_000, 7527) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -218,9 +207,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `295` // Estimated: `7527` - // Minimum execution time: 11_727 nanoseconds. - Weight::from_parts(12_177_000, 0) - .saturating_add(Weight::from_parts(0, 7527)) + // Minimum execution time: 11_484_000 picoseconds. + Weight::from_parts(11_900_000, 7527) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -230,9 +218,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `42` // Estimated: `3514` - // Minimum execution time: 4_983 nanoseconds. - Weight::from_parts(5_174_000, 0) - .saturating_add(Weight::from_parts(0, 3514)) + // Minimum execution time: 4_793_000 picoseconds. + Weight::from_parts(4_990_000, 3514) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -242,9 +229,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `113` // Estimated: `69049` - // Minimum execution time: 6_299 nanoseconds. - Weight::from_parts(6_670_000, 0) - .saturating_add(Weight::from_parts(0, 69049)) + // Minimum execution time: 6_231_000 picoseconds. + Weight::from_parts(6_442_000, 69049) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -254,9 +240,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `113` // Estimated: `69049` - // Minimum execution time: 6_762 nanoseconds. - Weight::from_parts(7_059_000, 0) - .saturating_add(Weight::from_parts(0, 69049)) + // Minimum execution time: 6_660_000 picoseconds. + Weight::from_parts(6_825_000, 69049) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -264,9 +249,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 72_681 nanoseconds. - Weight::from_parts(73_147_000, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Minimum execution time: 72_805_000 picoseconds. + Weight::from_parts(74_650_000, 0) } /// Storage: MessageQueue ServiceHead (r:1 w:1) /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -276,9 +260,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `172` // Estimated: `5003` - // Minimum execution time: 7_066 nanoseconds. - Weight::from_parts(7_214_000, 0) - .saturating_add(Weight::from_parts(0, 5003)) + // Minimum execution time: 7_078_000 picoseconds. + Weight::from_parts(7_230_000, 5003) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -290,9 +273,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `65742` // Estimated: `72563` - // Minimum execution time: 57_778 nanoseconds. - Weight::from_parts(58_778_000, 0) - .saturating_add(Weight::from_parts(0, 72563)) + // Minimum execution time: 56_799_000 picoseconds. + Weight::from_parts(57_634_000, 72563) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -304,9 +286,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `65742` // Estimated: `72563` - // Minimum execution time: 72_144 nanoseconds. - Weight::from_parts(72_942_000, 0) - .saturating_add(Weight::from_parts(0, 72563)) + // Minimum execution time: 72_290_000 picoseconds. + Weight::from_parts(72_754_000, 72563) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -318,9 +299,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `65742` // Estimated: `72563` - // Minimum execution time: 84_890 nanoseconds. - Weight::from_parts(86_073_000, 0) - .saturating_add(Weight::from_parts(0, 72563)) + // Minimum execution time: 84_987_000 picoseconds. + Weight::from_parts(85_562_000, 72563) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } From 851e73a6a1ff749cda0f50d5797eb1ae9804294b Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Tue, 7 Mar 2023 21:25:55 +0100 Subject: [PATCH 484/715] Offences report system rework (#13425) * Experiments with common equivocation trait * Improved equivocation trait * Fix grandpa equivocation implementation * Remove some cruft * Remove some more cruft * More generic naming * Simplification of offences manipilation * More refactory * Some prograss with the encapsulation of offence report system * Finally unit type works as a universal null report system * Align substrate node code * Further simplification * Fix test utils * Remove not required associated type * Fix benches * Rollback to prev field name * Box big params * Fix typo * Remove new tag computation * Remove default implementations * Better docs * Return 'Result' instead of bool * Change offence report system return types * Some renaming and documentation * Improve documentation * More abstract offence report system * Rename 'consume_evidence' to 'process_evidence' * Further docs refinements * Doc for dummy offence report * Fix rustdoc * Fix after master merge * Apply code review suggestions * Improve docs --- bin/node-template/runtime/src/lib.rs | 15 +- bin/node/runtime/src/lib.rs | 53 +--- frame/babe/src/equivocation.rs | 281 ++++++++--------- frame/babe/src/lib.rs | 131 +++----- frame/babe/src/mock.rs | 17 +- frame/babe/src/tests.rs | 2 +- frame/grandpa/src/equivocation.rs | 384 ++++++++++-------------- frame/grandpa/src/lib.rs | 159 +++------- frame/grandpa/src/mock.rs | 18 +- frame/grandpa/src/tests.rs | 3 +- frame/offences/benchmarking/src/lib.rs | 4 +- frame/offences/src/lib.rs | 6 +- frame/offences/src/mock.rs | 10 +- frame/offences/src/tests.rs | 12 +- primitives/consensus/grandpa/src/lib.rs | 3 + primitives/consensus/slots/src/lib.rs | 2 +- primitives/staking/src/offence.rs | 71 ++++- test-utils/runtime/src/lib.rs | 19 +- 18 files changed, 474 insertions(+), 716 deletions(-) diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs index 57e4470c762ac..ef90517a2a258 100644 --- a/bin/node-template/runtime/src/lib.rs +++ b/bin/node-template/runtime/src/lib.rs @@ -214,21 +214,12 @@ impl pallet_aura::Config for Runtime { impl pallet_grandpa::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type KeyOwnerProofSystem = (); - - type KeyOwnerProof = - >::Proof; - - type KeyOwnerIdentification = >::IdentificationTuple; - - type HandleEquivocation = (); - type WeightInfo = (); type MaxAuthorities = ConstU32<32>; type MaxSetIdSessionEntries = ConstU64<0>; + + type KeyOwnerProof = sp_core::Void; + type EquivocationReportSystem = (); } impl pallet_timestamp::Config for Runtime { diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 3d160108f62bb..c507c2d8d752f 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -113,6 +113,11 @@ pub mod assets_api; #[cfg(feature = "std")] include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); +/// Max size for serialized extrinsic params for this testing runtime. +/// This is a quite arbitrary but empirically battle tested value. +#[cfg(test)] +pub const CALL_PARAMS_MAX_SIZE: usize = 208; + /// Wasm binary unwrapped. If built with `SKIP_WASM_BUILD`, the function panics. #[cfg(feature = "std")] pub fn wasm_binary_unwrap() -> &'static [u8] { @@ -399,24 +404,12 @@ impl pallet_babe::Config for Runtime { type ExpectedBlockTime = ExpectedBlockTime; type EpochChangeTrigger = pallet_babe::ExternalTrigger; type DisabledValidators = Session; - - type KeyOwnerProofSystem = Historical; - - type KeyOwnerProof = >::Proof; - - type KeyOwnerIdentification = >::IdentificationTuple; - - type HandleEquivocation = - pallet_babe::EquivocationHandler; - type WeightInfo = (); type MaxAuthorities = MaxAuthorities; + type KeyOwnerProof = + >::Proof; + type EquivocationReportSystem = + pallet_babe::EquivocationReportSystem; } parameter_types! { @@ -1328,26 +1321,12 @@ parameter_types! { impl pallet_grandpa::Config for Runtime { type RuntimeEvent = RuntimeEvent; - - type KeyOwnerProofSystem = Historical; - - type KeyOwnerProof = - >::Proof; - - type KeyOwnerIdentification = >::IdentificationTuple; - - type HandleEquivocation = pallet_grandpa::EquivocationHandler< - Self::KeyOwnerIdentification, - Offences, - ReportLongevity, - >; - type WeightInfo = (); type MaxAuthorities = MaxAuthorities; type MaxSetIdSessionEntries = MaxSetIdSessionEntries; + type KeyOwnerProof = >::Proof; + type EquivocationReportSystem = + pallet_grandpa::EquivocationReportSystem; } parameter_types! { @@ -2483,10 +2462,10 @@ mod tests { fn call_size() { let size = core::mem::size_of::(); assert!( - size <= 208, - "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 <= CALL_PARAMS_MAX_SIZE, + "size of RuntimeCall {} is more than {CALL_PARAMS_MAX_SIZE} 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.", size, ); } diff --git a/frame/babe/src/equivocation.rs b/frame/babe/src/equivocation.rs index 2a2e2b47605d1..ed98385a74474 100644 --- a/frame/babe/src/equivocation.rs +++ b/frame/babe/src/equivocation.rs @@ -34,143 +34,163 @@ //! definition. use frame_support::traits::{Get, KeyOwnerProofSystem}; -use sp_consensus_babe::{EquivocationProof, Slot}; +use log::{error, info}; + +use sp_consensus_babe::{AuthorityId, EquivocationProof, Slot, KEY_TYPE}; use sp_runtime::{ transaction_validity::{ InvalidTransaction, TransactionPriority, TransactionSource, TransactionValidity, TransactionValidityError, ValidTransaction, }, - DispatchResult, Perbill, + DispatchError, KeyTypeId, Perbill, }; +use sp_session::{GetSessionNumber, GetValidatorCount}; use sp_staking::{ - offence::{Kind, Offence, OffenceError, ReportOffence}, + offence::{Kind, Offence, OffenceReportSystem, ReportOffence}, SessionIndex, }; use sp_std::prelude::*; -use crate::{Call, Config, Pallet, LOG_TARGET}; - -/// A trait with utility methods for handling equivocation reports in BABE. -/// The trait provides methods for reporting an offence triggered by a valid -/// equivocation report, checking the current block author (to declare as the -/// reporter), and also for creating and submitting equivocation report -/// extrinsics (useful only in offchain context). -pub trait HandleEquivocation { - /// The longevity, in blocks, that the equivocation report is valid for. When using the staking - /// pallet this should be equal to the bonding duration (in blocks, not eras). - type ReportLongevity: Get; - - /// Report an offence proved by the given reporters. - fn report_offence( - reporters: Vec, - offence: BabeEquivocationOffence, - ) -> Result<(), OffenceError>; - - /// Returns true if all of the offenders at the given time slot have already been reported. - fn is_known_offence(offenders: &[T::KeyOwnerIdentification], time_slot: &Slot) -> bool; - - /// Create and dispatch an equivocation report extrinsic. - fn submit_unsigned_equivocation_report( - equivocation_proof: EquivocationProof, - key_owner_proof: T::KeyOwnerProof, - ) -> DispatchResult; - - /// Fetch the current block author id, if defined. - fn block_author() -> Option; +use crate::{Call, Config, Error, Pallet, LOG_TARGET}; + +/// BABE equivocation offence report. +/// +/// When a validator released two or more blocks at the same slot. +pub struct EquivocationOffence { + /// A babe slot in which this incident happened. + pub slot: Slot, + /// The session index in which the incident happened. + pub session_index: SessionIndex, + /// The size of the validator set at the time of the offence. + pub validator_set_count: u32, + /// The authority that produced the equivocation. + pub offender: Offender, } -impl HandleEquivocation for () { - type ReportLongevity = (); +impl Offence for EquivocationOffence { + const ID: Kind = *b"babe:equivocatio"; + type TimeSlot = Slot; - fn report_offence( - _reporters: Vec, - _offence: BabeEquivocationOffence, - ) -> Result<(), OffenceError> { - Ok(()) + fn offenders(&self) -> Vec { + vec![self.offender.clone()] } - fn is_known_offence(_offenders: &[T::KeyOwnerIdentification], _time_slot: &Slot) -> bool { - true + fn session_index(&self) -> SessionIndex { + self.session_index } - fn submit_unsigned_equivocation_report( - _equivocation_proof: EquivocationProof, - _key_owner_proof: T::KeyOwnerProof, - ) -> DispatchResult { - Ok(()) + fn validator_set_count(&self) -> u32 { + self.validator_set_count } - fn block_author() -> Option { - None + fn time_slot(&self) -> Self::TimeSlot { + self.slot } -} - -/// Generic equivocation handler. This type implements `HandleEquivocation` -/// using existing subsystems that are part of frame (type bounds described -/// below) and will dispatch to them directly, it's only purpose is to wire all -/// subsystems together. -pub struct EquivocationHandler { - _phantom: sp_std::marker::PhantomData<(I, R, L)>, -} -impl Default for EquivocationHandler { - fn default() -> Self { - Self { _phantom: Default::default() } + // The formula is min((3k / n)^2, 1) + // where k = offenders_number and n = validators_number + fn slash_fraction(&self, offenders_count: u32) -> Perbill { + // Perbill type domain is [0, 1] by definition + Perbill::from_rational(3 * offenders_count, self.validator_set_count).square() } } -impl HandleEquivocation for EquivocationHandler +/// Babe equivocation offence system. +/// +/// This type implements `OffenceReportSystem` +pub struct EquivocationReportSystem(sp_std::marker::PhantomData<(T, R, P, L)>); + +// We use the authorship pallet to fetch the current block author and use +// `offchain::SendTransactionTypes` for unsigned extrinsic creation and +// submission. +impl + OffenceReportSystem, (EquivocationProof, T::KeyOwnerProof)> + for EquivocationReportSystem where - // We use the authorship pallet to fetch the current block author and use - // `offchain::SendTransactionTypes` for unsigned extrinsic creation and - // submission. T: Config + pallet_authorship::Config + frame_system::offchain::SendTransactionTypes>, - // A system for reporting offences after valid equivocation reports are - // processed. R: ReportOffence< T::AccountId, - T::KeyOwnerIdentification, - BabeEquivocationOffence, + P::IdentificationTuple, + EquivocationOffence, >, - // The longevity (in blocks) that the equivocation report is valid for. When using the staking - // pallet this should be the bonding duration. + P: KeyOwnerProofSystem<(KeyTypeId, AuthorityId), Proof = T::KeyOwnerProof>, + P::IdentificationTuple: Clone, L: Get, { - type ReportLongevity = L; + type Longevity = L; - fn report_offence( - reporters: Vec, - offence: BabeEquivocationOffence, - ) -> Result<(), OffenceError> { - R::report_offence(reporters, offence) - } - - fn is_known_offence(offenders: &[T::KeyOwnerIdentification], time_slot: &Slot) -> bool { - R::is_known_offence(offenders, time_slot) - } - - fn submit_unsigned_equivocation_report( - equivocation_proof: EquivocationProof, - key_owner_proof: T::KeyOwnerProof, - ) -> DispatchResult { + fn publish_evidence( + evidence: (EquivocationProof, T::KeyOwnerProof), + ) -> Result<(), ()> { use frame_system::offchain::SubmitTransaction; + let (equivocation_proof, key_owner_proof) = evidence; let call = Call::report_equivocation_unsigned { equivocation_proof: Box::new(equivocation_proof), key_owner_proof, }; - - match SubmitTransaction::>::submit_unsigned_transaction(call.into()) { - Ok(()) => log::info!(target: LOG_TARGET, "Submitted BABE equivocation report.",), - Err(e) => - log::error!(target: LOG_TARGET, "Error submitting equivocation report: {:?}", e,), + let res = SubmitTransaction::>::submit_unsigned_transaction(call.into()); + match res { + Ok(()) => info!(target: LOG_TARGET, "Submitted equivocation report."), + Err(e) => error!(target: LOG_TARGET, "Error submitting equivocation report: {:?}", e), } + res + } - Ok(()) + fn check_evidence( + evidence: (EquivocationProof, T::KeyOwnerProof), + ) -> Result<(), TransactionValidityError> { + let (equivocation_proof, key_owner_proof) = evidence; + + // Check the membership proof to extract the offender's id + let key = (sp_consensus_babe::KEY_TYPE, equivocation_proof.offender.clone()); + let offender = + P::check_proof(key, key_owner_proof.clone()).ok_or(InvalidTransaction::BadProof)?; + + // Check if the offence has already been reported, and if so then we can discard the report. + if R::is_known_offence(&[offender], &equivocation_proof.slot) { + Err(InvalidTransaction::Stale.into()) + } else { + Ok(()) + } } - fn block_author() -> Option { - >::author() + fn process_evidence( + reporter: Option, + evidence: (EquivocationProof, T::KeyOwnerProof), + ) -> Result<(), DispatchError> { + let (equivocation_proof, key_owner_proof) = evidence; + let reporter = reporter.or_else(|| >::author()); + let offender = equivocation_proof.offender.clone(); + let slot = equivocation_proof.slot; + + // Validate the equivocation proof (check votes are different and signatures are valid) + if !sp_consensus_babe::check_equivocation_proof(equivocation_proof) { + return Err(Error::::InvalidEquivocationProof.into()) + } + + let validator_set_count = key_owner_proof.validator_count(); + let session_index = key_owner_proof.session(); + + let epoch_index = + *slot.saturating_sub(crate::GenesisSlot::::get()) / T::EpochDuration::get(); + + // Check that the slot number is consistent with the session index + // in the key ownership proof (i.e. slot is for that epoch) + if Pallet::::session_index_for_epoch(epoch_index) != session_index { + return Err(Error::::InvalidKeyOwnershipProof.into()) + } + + // Check the membership proof and extract the offender's id + let offender = P::check_proof((KEY_TYPE, offender), key_owner_proof) + .ok_or(Error::::InvalidKeyOwnershipProof)?; + + let offence = EquivocationOffence { slot, validator_set_count, offender, session_index }; + + R::report_offence(reporter.into_iter().collect(), offence) + .map_err(|_| Error::::DuplicateOffenceReport)?; + + Ok(()) } } @@ -194,11 +214,12 @@ impl Pallet { }, } - // check report staleness - is_known_offence::(equivocation_proof, key_owner_proof)?; + // Check report validity + let evidence = (*equivocation_proof.clone(), key_owner_proof.clone()); + T::EquivocationReportSystem::check_evidence(evidence)?; let longevity = - >::ReportLongevity::get(); + >::Longevity::get(); ValidTransaction::with_tag_prefix("BabeEquivocation") // We assign the maximum priority for any equivocation report. @@ -216,72 +237,10 @@ impl Pallet { pub fn pre_dispatch(call: &Call) -> Result<(), TransactionValidityError> { if let Call::report_equivocation_unsigned { equivocation_proof, key_owner_proof } = call { - is_known_offence::(equivocation_proof, key_owner_proof) + let evidence = (*equivocation_proof.clone(), key_owner_proof.clone()); + T::EquivocationReportSystem::check_evidence(evidence) } else { Err(InvalidTransaction::Call.into()) } } } - -fn is_known_offence( - equivocation_proof: &EquivocationProof, - key_owner_proof: &T::KeyOwnerProof, -) -> Result<(), TransactionValidityError> { - // check the membership proof to extract the offender's id - let key = (sp_consensus_babe::KEY_TYPE, equivocation_proof.offender.clone()); - - let offender = T::KeyOwnerProofSystem::check_proof(key, key_owner_proof.clone()) - .ok_or(InvalidTransaction::BadProof)?; - - // check if the offence has already been reported, - // and if so then we can discard the report. - if T::HandleEquivocation::is_known_offence(&[offender], &equivocation_proof.slot) { - Err(InvalidTransaction::Stale.into()) - } else { - Ok(()) - } -} - -/// A BABE equivocation offence report. -/// -/// When a validator released two or more blocks at the same slot. -pub struct BabeEquivocationOffence { - /// A babe slot in which this incident happened. - pub slot: Slot, - /// The session index in which the incident happened. - pub session_index: SessionIndex, - /// The size of the validator set at the time of the offence. - pub validator_set_count: u32, - /// The authority that produced the equivocation. - pub offender: FullIdentification, -} - -impl Offence - for BabeEquivocationOffence -{ - const ID: Kind = *b"babe:equivocatio"; - type TimeSlot = Slot; - - fn offenders(&self) -> Vec { - vec![self.offender.clone()] - } - - fn session_index(&self) -> SessionIndex { - self.session_index - } - - fn validator_set_count(&self) -> u32 { - self.validator_set_count - } - - fn time_slot(&self) -> Self::TimeSlot { - self.slot - } - - fn slash_fraction(&self, offenders_count: u32) -> Perbill { - // the formula is min((3k / n)^2, 1) - let x = Perbill::from_rational(3 * offenders_count, self.validator_set_count); - // _ ^ 2 - x.square() - } -} diff --git a/frame/babe/src/lib.rs b/frame/babe/src/lib.rs index bb07037ee0a12..903f6249e3310 100644 --- a/frame/babe/src/lib.rs +++ b/frame/babe/src/lib.rs @@ -25,29 +25,25 @@ use codec::{Decode, Encode}; use frame_support::{ dispatch::{DispatchResultWithPostInfo, Pays}, ensure, - traits::{ - ConstU32, DisabledValidators, FindAuthor, Get, KeyOwnerProofSystem, OnTimestampSet, - OneSessionHandler, - }, + traits::{ConstU32, DisabledValidators, FindAuthor, Get, OnTimestampSet, OneSessionHandler}, weights::Weight, BoundedVec, WeakBoundedVec, }; use sp_application_crypto::ByteArray; -use sp_runtime::{ - generic::DigestItem, - traits::{IsMember, One, SaturatedConversion, Saturating, Zero}, - ConsensusEngineId, KeyTypeId, Permill, -}; -use sp_session::{GetSessionNumber, GetValidatorCount}; -use sp_staking::SessionIndex; -use sp_std::prelude::*; - use sp_consensus_babe::{ digests::{NextConfigDescriptor, NextEpochDescriptor, PreDigest}, AllowedSlots, BabeAuthorityWeight, BabeEpochConfiguration, ConsensusLog, Epoch, EquivocationProof, Slot, BABE_ENGINE_ID, }; use sp_consensus_vrf::schnorrkel; +use sp_runtime::{ + generic::DigestItem, + traits::{IsMember, One, SaturatedConversion, Saturating, Zero}, + ConsensusEngineId, Permill, +}; +use sp_session::{GetSessionNumber, GetValidatorCount}; +use sp_staking::{offence::OffenceReportSystem, SessionIndex}; +use sp_std::prelude::*; pub use sp_consensus_babe::{AuthorityId, PUBLIC_KEY_LENGTH, RANDOMNESS_LENGTH, VRF_OUTPUT_LENGTH}; @@ -64,7 +60,7 @@ mod mock; #[cfg(all(feature = "std", test))] mod tests; -pub use equivocation::{BabeEquivocationOffence, EquivocationHandler, HandleEquivocation}; +pub use equivocation::{EquivocationOffence, EquivocationReportSystem}; #[allow(deprecated)] pub use randomness::CurrentBlockRandomness; pub use randomness::{ @@ -150,35 +146,25 @@ pub mod pallet { /// initialization. type DisabledValidators: DisabledValidators; + /// Helper for weights computations + type WeightInfo: WeightInfo; + + /// Max number of authorities allowed + #[pallet::constant] + type MaxAuthorities: Get; + /// The proof of key ownership, used for validating equivocation reports. /// The proof must include the session index and validator count of the /// session at which the equivocation occurred. type KeyOwnerProof: Parameter + GetSessionNumber + GetValidatorCount; - /// The identification of a key owner, used when reporting equivocations. - type KeyOwnerIdentification: Parameter; - - /// A system for proving ownership of keys, i.e. that a given key was part - /// of a validator set, needed for validating equivocation reports. - type KeyOwnerProofSystem: KeyOwnerProofSystem< - (KeyTypeId, AuthorityId), - Proof = Self::KeyOwnerProof, - IdentificationTuple = Self::KeyOwnerIdentification, + /// The equivocation handling subsystem, defines methods to check/report an + /// offence and for submitting a transaction to report an equivocation + /// (from an offchain context). + type EquivocationReportSystem: OffenceReportSystem< + Option, + (EquivocationProof, Self::KeyOwnerProof), >; - - /// The equivocation handling subsystem, defines methods to report an - /// offence (after the equivocation has been validated) and for submitting a - /// transaction to report an equivocation (from an offchain context). - /// NOTE: when enabling equivocation handling (i.e. this type isn't set to - /// `()`) you must use this pallet's `ValidateUnsigned` in the runtime - /// definition. - type HandleEquivocation: HandleEquivocation; - - type WeightInfo: WeightInfo; - - /// Max number of authorities allowed - #[pallet::constant] - type MaxAuthorities: Get; } #[pallet::error] @@ -429,8 +415,12 @@ pub mod pallet { key_owner_proof: T::KeyOwnerProof, ) -> DispatchResultWithPostInfo { let reporter = ensure_signed(origin)?; - - Self::do_report_equivocation(Some(reporter), *equivocation_proof, key_owner_proof) + T::EquivocationReportSystem::process_evidence( + Some(reporter), + (*equivocation_proof, key_owner_proof), + )?; + // Waive the fee since the report is valid and beneficial + Ok(Pays::No.into()) } /// Report authority equivocation/misbehavior. This method will verify @@ -451,12 +441,11 @@ pub mod pallet { key_owner_proof: T::KeyOwnerProof, ) -> DispatchResultWithPostInfo { ensure_none(origin)?; - - Self::do_report_equivocation( - T::HandleEquivocation::block_author(), - *equivocation_proof, - key_owner_proof, - ) + T::EquivocationReportSystem::process_evidence( + None, + (*equivocation_proof, key_owner_proof), + )?; + Ok(Pays::No.into()) } /// Plan an epoch config change. The epoch config change is recorded and will be enacted on @@ -866,7 +855,7 @@ impl Pallet { /// This function is only well defined for epochs that actually existed, /// e.g. if we skipped from epoch 10 to 20 then a call for epoch 15 (which /// didn't exist) will return an incorrect session index. - fn session_index_for_epoch(epoch_index: u64) -> SessionIndex { + pub(crate) fn session_index_for_epoch(epoch_index: u64) -> SessionIndex { let skipped_epochs = SkippedEpochs::::get(); match skipped_epochs.binary_search_by_key(&epoch_index, |(epoch_index, _)| *epoch_index) { // we have an exact match so we just return the given session index @@ -890,50 +879,6 @@ impl Pallet { } } - fn do_report_equivocation( - reporter: Option, - equivocation_proof: EquivocationProof, - key_owner_proof: T::KeyOwnerProof, - ) -> DispatchResultWithPostInfo { - let offender = equivocation_proof.offender.clone(); - let slot = equivocation_proof.slot; - - // validate the equivocation proof - if !sp_consensus_babe::check_equivocation_proof(equivocation_proof) { - return Err(Error::::InvalidEquivocationProof.into()) - } - - let validator_set_count = key_owner_proof.validator_count(); - let session_index = key_owner_proof.session(); - - let epoch_index = *slot.saturating_sub(GenesisSlot::::get()) / T::EpochDuration::get(); - - // check that the slot number is consistent with the session index - // in the key ownership proof (i.e. slot is for that epoch) - if Self::session_index_for_epoch(epoch_index) != session_index { - return Err(Error::::InvalidKeyOwnershipProof.into()) - } - - // check the membership proof and extract the offender's id - let key = (sp_consensus_babe::KEY_TYPE, offender); - let offender = T::KeyOwnerProofSystem::check_proof(key, key_owner_proof) - .ok_or(Error::::InvalidKeyOwnershipProof)?; - - let offence = - BabeEquivocationOffence { slot, validator_set_count, offender, session_index }; - - let reporters = match reporter { - Some(id) => vec![id], - None => vec![], - }; - - T::HandleEquivocation::report_offence(reporters, offence) - .map_err(|_| Error::::DuplicateOffenceReport)?; - - // waive the fee since the report is valid and beneficial - Ok(Pays::No.into()) - } - /// Submits an extrinsic to report an equivocation. This method will create /// an unsigned extrinsic with a call to `report_equivocation_unsigned` and /// will push the transaction to the pool. Only useful in an offchain @@ -942,11 +887,7 @@ impl Pallet { equivocation_proof: EquivocationProof, key_owner_proof: T::KeyOwnerProof, ) -> Option<()> { - T::HandleEquivocation::submit_unsigned_equivocation_report( - equivocation_proof, - key_owner_proof, - ) - .ok() + T::EquivocationReportSystem::publish_evidence((equivocation_proof, key_owner_proof)).ok() } } diff --git a/frame/babe/src/mock.rs b/frame/babe/src/mock.rs index b130677897883..9b832bfffdb69 100644 --- a/frame/babe/src/mock.rs +++ b/frame/babe/src/mock.rs @@ -223,22 +223,11 @@ impl Config for Test { type ExpectedBlockTime = ConstU64<1>; type EpochChangeTrigger = crate::ExternalTrigger; type DisabledValidators = Session; - - type KeyOwnerProofSystem = Historical; - - type KeyOwnerProof = - >::Proof; - - type KeyOwnerIdentification = >::IdentificationTuple; - - type HandleEquivocation = - super::EquivocationHandler; - type WeightInfo = (); type MaxAuthorities = ConstU32<10>; + type KeyOwnerProof = >::Proof; + type EquivocationReportSystem = + super::EquivocationReportSystem; } pub fn go_to_block(n: u64, s: u64) { diff --git a/frame/babe/src/tests.rs b/frame/babe/src/tests.rs index 68426d0a8636e..8b63f41b37b74 100644 --- a/frame/babe/src/tests.rs +++ b/frame/babe/src/tests.rs @@ -21,7 +21,7 @@ use super::{Call, *}; use frame_support::{ assert_err, assert_noop, assert_ok, dispatch::{GetDispatchInfo, Pays}, - traits::{Currency, EstimateNextSessionRotation, OnFinalize}, + traits::{Currency, EstimateNextSessionRotation, KeyOwnerProofSystem, OnFinalize}, }; use mock::*; use pallet_session::ShouldEndSession; diff --git a/frame/grandpa/src/equivocation.rs b/frame/grandpa/src/equivocation.rs index 7d8eb6774097c..6fd12bbdfcdb9 100644 --- a/frame/grandpa/src/equivocation.rs +++ b/frame/grandpa/src/equivocation.rs @@ -35,86 +35,73 @@ //! that the `ValidateUnsigned` for the GRANDPA pallet is used in the runtime //! definition. -use sp_std::prelude::*; - use codec::{self as codec, Decode, Encode}; use frame_support::traits::{Get, KeyOwnerProofSystem}; -use sp_consensus_grandpa::{EquivocationProof, RoundNumber, SetId}; +use log::{error, info}; +use sp_consensus_grandpa::{AuthorityId, EquivocationProof, RoundNumber, SetId, KEY_TYPE}; use sp_runtime::{ transaction_validity::{ InvalidTransaction, TransactionPriority, TransactionSource, TransactionValidity, TransactionValidityError, ValidTransaction, }, - DispatchResult, Perbill, + DispatchError, KeyTypeId, Perbill, }; +use sp_session::{GetSessionNumber, GetValidatorCount}; use sp_staking::{ - offence::{Kind, Offence, OffenceError, ReportOffence}, + offence::{Kind, Offence, OffenceReportSystem, ReportOffence}, SessionIndex, }; +use sp_std::prelude::*; -use super::{Call, Config, Pallet, LOG_TARGET}; - -/// A trait with utility methods for handling equivocation reports in GRANDPA. -/// The offence type is generic, and the trait provides , reporting an offence -/// triggered by a valid equivocation report, and also for creating and -/// submitting equivocation report extrinsics (useful only in offchain context). -pub trait HandleEquivocation { - /// The offence type used for reporting offences on valid equivocation reports. - type Offence: GrandpaOffence; - - /// The longevity, in blocks, that the equivocation report is valid for. When using the staking - /// pallet this should be equal to the bonding duration (in blocks, not eras). - type ReportLongevity: Get; - - /// Report an offence proved by the given reporters. - fn report_offence( - reporters: Vec, - offence: Self::Offence, - ) -> Result<(), OffenceError>; - - /// Returns true if all of the offenders at the given time slot have already been reported. - fn is_known_offence( - offenders: &[T::KeyOwnerIdentification], - time_slot: &>::TimeSlot, - ) -> bool; - - /// Create and dispatch an equivocation report extrinsic. - fn submit_unsigned_equivocation_report( - equivocation_proof: EquivocationProof, - key_owner_proof: T::KeyOwnerProof, - ) -> DispatchResult; - - /// Fetch the current block author id, if defined. - fn block_author() -> Option; +use super::{Call, Config, Error, Pallet, LOG_TARGET}; + +/// A round number and set id which point on the time of an offence. +#[derive(Copy, Clone, PartialOrd, Ord, Eq, PartialEq, Encode, Decode)] +pub struct GrandpaTimeSlot { + // The order of these matters for `derive(Ord)`. + /// Grandpa Set ID. + pub set_id: SetId, + /// Round number. + pub round: RoundNumber, } -impl HandleEquivocation for () { - type Offence = GrandpaEquivocationOffence; - type ReportLongevity = (); +/// A GRANDPA equivocation offence report. +pub struct EquivocationOffence { + /// Time slot at which this incident happened. + pub time_slot: GrandpaTimeSlot, + /// The session index in which the incident happened. + pub session_index: SessionIndex, + /// The size of the validator set at the time of the offence. + pub validator_set_count: u32, + /// The authority which produced this equivocation. + pub offender: Offender, +} - fn report_offence( - _reporters: Vec, - _offence: GrandpaEquivocationOffence, - ) -> Result<(), OffenceError> { - Ok(()) +impl Offence for EquivocationOffence { + const ID: Kind = *b"grandpa:equivoca"; + type TimeSlot = GrandpaTimeSlot; + + fn offenders(&self) -> Vec { + vec![self.offender.clone()] } - fn is_known_offence( - _offenders: &[T::KeyOwnerIdentification], - _time_slot: &GrandpaTimeSlot, - ) -> bool { - true + fn session_index(&self) -> SessionIndex { + self.session_index } - fn submit_unsigned_equivocation_report( - _equivocation_proof: EquivocationProof, - _key_owner_proof: T::KeyOwnerProof, - ) -> DispatchResult { - Ok(()) + fn validator_set_count(&self) -> u32 { + self.validator_set_count + } + + fn time_slot(&self) -> Self::TimeSlot { + self.time_slot } - fn block_author() -> Option { - None + // The formula is min((3k / n)^2, 1) + // where k = offenders_number and n = validators_number + fn slash_fraction(&self, offenders_count: u32) -> Perbill { + // Perbill type domain is [0, 1] by definition + Perbill::from_rational(3 * offenders_count, self.validator_set_count).square() } } @@ -122,75 +109,129 @@ impl HandleEquivocation for () { /// using existing subsystems that are part of frame (type bounds described /// below) and will dispatch to them directly, it's only purpose is to wire all /// subsystems together. -pub struct EquivocationHandler> { - _phantom: sp_std::marker::PhantomData<(I, R, L, O)>, -} - -impl Default for EquivocationHandler { - fn default() -> Self { - Self { _phantom: Default::default() } - } -} - -impl HandleEquivocation for EquivocationHandler +pub struct EquivocationReportSystem(sp_std::marker::PhantomData<(T, R, P, L)>); + +// We use the authorship pallet to fetch the current block author and use +// `offchain::SendTransactionTypes` for unsigned extrinsic creation and +// submission. +impl + OffenceReportSystem< + Option, + (EquivocationProof, T::KeyOwnerProof), + > for EquivocationReportSystem where - // We use the authorship pallet to fetch the current block author and use - // `offchain::SendTransactionTypes` for unsigned extrinsic creation and - // submission. T: Config + pallet_authorship::Config + frame_system::offchain::SendTransactionTypes>, - // A system for reporting offences after valid equivocation reports are - // processed. - R: ReportOffence, - // The longevity (in blocks) that the equivocation report is valid for. When using the staking - // pallet this should be the bonding duration. + R: ReportOffence< + T::AccountId, + P::IdentificationTuple, + EquivocationOffence, + >, + P: KeyOwnerProofSystem<(KeyTypeId, AuthorityId), Proof = T::KeyOwnerProof>, + P::IdentificationTuple: Clone, L: Get, - // The offence type that should be used when reporting. - O: GrandpaOffence, { - type Offence = O; - type ReportLongevity = L; - - fn report_offence(reporters: Vec, offence: O) -> Result<(), OffenceError> { - R::report_offence(reporters, offence) - } + type Longevity = L; - fn is_known_offence(offenders: &[T::KeyOwnerIdentification], time_slot: &O::TimeSlot) -> bool { - R::is_known_offence(offenders, time_slot) - } - - fn submit_unsigned_equivocation_report( - equivocation_proof: EquivocationProof, - key_owner_proof: T::KeyOwnerProof, - ) -> DispatchResult { + fn publish_evidence( + evidence: (EquivocationProof, T::KeyOwnerProof), + ) -> Result<(), ()> { use frame_system::offchain::SubmitTransaction; + let (equivocation_proof, key_owner_proof) = evidence; let call = Call::report_equivocation_unsigned { equivocation_proof: Box::new(equivocation_proof), key_owner_proof, }; - - match SubmitTransaction::>::submit_unsigned_transaction(call.into()) { - Ok(()) => log::info!(target: LOG_TARGET, "Submitted GRANDPA equivocation report.",), - Err(e) => - log::error!(target: LOG_TARGET, "Error submitting equivocation report: {:?}", e,), + let res = SubmitTransaction::>::submit_unsigned_transaction(call.into()); + match res { + Ok(()) => info!(target: LOG_TARGET, "Submitted equivocation report."), + Err(e) => error!(target: LOG_TARGET, "Error submitting equivocation report: {:?}", e), } - - Ok(()) + res } - fn block_author() -> Option { - >::author() + fn check_evidence( + evidence: (EquivocationProof, T::KeyOwnerProof), + ) -> Result<(), TransactionValidityError> { + let (equivocation_proof, key_owner_proof) = evidence; + + // Check the membership proof to extract the offender's id + let key = (KEY_TYPE, equivocation_proof.offender().clone()); + let offender = P::check_proof(key, key_owner_proof).ok_or(InvalidTransaction::BadProof)?; + + // Check if the offence has already been reported, and if so then we can discard the report. + let time_slot = GrandpaTimeSlot { + set_id: equivocation_proof.set_id(), + round: equivocation_proof.round(), + }; + if R::is_known_offence(&[offender], &time_slot) { + Err(InvalidTransaction::Stale.into()) + } else { + Ok(()) + } } -} -/// A round number and set id which point on the time of an offence. -#[derive(Copy, Clone, PartialOrd, Ord, Eq, PartialEq, Encode, Decode)] -pub struct GrandpaTimeSlot { - // The order of these matters for `derive(Ord)`. - /// Grandpa Set ID. - pub set_id: SetId, - /// Round number. - pub round: RoundNumber, + fn process_evidence( + reporter: Option, + evidence: (EquivocationProof, T::KeyOwnerProof), + ) -> Result<(), DispatchError> { + let (equivocation_proof, key_owner_proof) = evidence; + let reporter = reporter.or_else(|| >::author()); + let offender = equivocation_proof.offender().clone(); + + // We check the equivocation within the context of its set id (and + // associated session) and round. We also need to know the validator + // set count when the offence since it is required to calculate the + // slash amount. + let set_id = equivocation_proof.set_id(); + let round = equivocation_proof.round(); + let session_index = key_owner_proof.session(); + let validator_set_count = key_owner_proof.validator_count(); + + // Validate equivocation proof (check votes are different and signatures are valid). + if !sp_consensus_grandpa::check_equivocation_proof(equivocation_proof) { + return Err(Error::::InvalidEquivocationProof.into()) + } + + // Validate the key ownership proof extracting the id of the offender. + let offender = P::check_proof((KEY_TYPE, offender), key_owner_proof) + .ok_or(Error::::InvalidKeyOwnershipProof)?; + + // Fetch the current and previous sets last session index. + // For genesis set there's no previous set. + let previous_set_id_session_index = if set_id != 0 { + let idx = crate::SetIdSession::::get(set_id - 1) + .ok_or(Error::::InvalidEquivocationProof)?; + Some(idx) + } else { + None + }; + + let set_id_session_index = + crate::SetIdSession::::get(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. + if session_index > set_id_session_index || + previous_set_id_session_index + .map(|previous_index| session_index <= previous_index) + .unwrap_or(false) + { + return Err(Error::::InvalidEquivocationProof.into()) + } + + let offence = EquivocationOffence { + time_slot: GrandpaTimeSlot { set_id, round }, + session_index, + offender, + validator_set_count, + }; + + R::report_offence(reporter.into_iter().collect(), offence) + .map_err(|_| Error::::DuplicateOffenceReport)?; + + Ok(()) + } } /// Methods for the `ValidateUnsigned` implementation: @@ -213,11 +254,12 @@ impl Pallet { }, } - // check report staleness - is_known_offence::(equivocation_proof, key_owner_proof)?; + // Check report validity + let evidence = (*equivocation_proof.clone(), key_owner_proof.clone()); + T::EquivocationReportSystem::check_evidence(evidence)?; let longevity = - >::ReportLongevity::get(); + >::Longevity::get(); ValidTransaction::with_tag_prefix("GrandpaEquivocation") // We assign the maximum priority for any equivocation report. @@ -239,118 +281,10 @@ impl Pallet { pub fn pre_dispatch(call: &Call) -> Result<(), TransactionValidityError> { if let Call::report_equivocation_unsigned { equivocation_proof, key_owner_proof } = call { - is_known_offence::(equivocation_proof, key_owner_proof) + let evidence = (*equivocation_proof.clone(), key_owner_proof.clone()); + T::EquivocationReportSystem::check_evidence(evidence) } else { Err(InvalidTransaction::Call.into()) } } } - -fn is_known_offence( - equivocation_proof: &EquivocationProof, - key_owner_proof: &T::KeyOwnerProof, -) -> Result<(), TransactionValidityError> { - // check the membership proof to extract the offender's id - let key = (sp_consensus_grandpa::KEY_TYPE, equivocation_proof.offender().clone()); - - let offender = T::KeyOwnerProofSystem::check_proof(key, key_owner_proof.clone()) - .ok_or(InvalidTransaction::BadProof)?; - - // check if the offence has already been reported, - // and if so then we can discard the report. - let time_slot = >::Offence::new_time_slot( - equivocation_proof.set_id(), - equivocation_proof.round(), - ); - - let is_known_offence = T::HandleEquivocation::is_known_offence(&[offender], &time_slot); - - if is_known_offence { - Err(InvalidTransaction::Stale.into()) - } else { - Ok(()) - } -} - -/// A grandpa equivocation offence report. -#[allow(dead_code)] -pub struct GrandpaEquivocationOffence { - /// Time slot at which this incident happened. - pub time_slot: GrandpaTimeSlot, - /// The session index in which the incident happened. - pub session_index: SessionIndex, - /// The size of the validator set at the time of the offence. - pub validator_set_count: u32, - /// The authority which produced this equivocation. - pub offender: FullIdentification, -} - -/// An interface for types that will be used as GRANDPA offences and must also -/// implement the `Offence` trait. This trait provides a constructor that is -/// provided all available data during processing of GRANDPA equivocations. -pub trait GrandpaOffence: Offence { - /// Create a new GRANDPA offence using the given equivocation details. - fn new( - session_index: SessionIndex, - validator_set_count: u32, - offender: FullIdentification, - set_id: SetId, - round: RoundNumber, - ) -> Self; - - /// Create a new GRANDPA offence time slot. - fn new_time_slot(set_id: SetId, round: RoundNumber) -> Self::TimeSlot; -} - -impl GrandpaOffence - for GrandpaEquivocationOffence -{ - fn new( - session_index: SessionIndex, - validator_set_count: u32, - offender: FullIdentification, - set_id: SetId, - round: RoundNumber, - ) -> Self { - GrandpaEquivocationOffence { - session_index, - validator_set_count, - offender, - time_slot: GrandpaTimeSlot { set_id, round }, - } - } - - fn new_time_slot(set_id: SetId, round: RoundNumber) -> Self::TimeSlot { - GrandpaTimeSlot { set_id, round } - } -} - -impl Offence - for GrandpaEquivocationOffence -{ - const ID: Kind = *b"grandpa:equivoca"; - type TimeSlot = GrandpaTimeSlot; - - fn offenders(&self) -> Vec { - vec![self.offender.clone()] - } - - fn session_index(&self) -> SessionIndex { - self.session_index - } - - fn validator_set_count(&self) -> u32 { - self.validator_set_count - } - - fn time_slot(&self) -> Self::TimeSlot { - self.time_slot - } - - fn slash_fraction(&self, offenders_count: u32) -> Perbill { - // the formula is min((3k / n)^2, 1) - let x = Perbill::from_rational(3 * offenders_count, self.validator_set_count); - // _ ^ 2 - x.square() - } -} diff --git a/frame/grandpa/src/lib.rs b/frame/grandpa/src/lib.rs index 85d116ee7d7e7..2106860ea1441 100644 --- a/frame/grandpa/src/lib.rs +++ b/frame/grandpa/src/lib.rs @@ -28,29 +28,29 @@ #![cfg_attr(not(feature = "std"), no_std)] -// re-export since this is necessary for `impl_apis` in runtime. -pub use sp_consensus_grandpa as fg_primitives; - -use sp_std::prelude::*; +// Re-export since this is necessary for `impl_apis` in runtime. +pub use sp_consensus_grandpa::{ + self as fg_primitives, AuthorityId, AuthorityList, AuthorityWeight, VersionedAuthorityList, +}; 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, - GRANDPA_ENGINE_ID, RUNTIME_LOG_TARGET as LOG_TARGET, -}; use frame_support::{ dispatch::{DispatchResultWithPostInfo, Pays}, pallet_prelude::Get, storage, - traits::{KeyOwnerProofSystem, OneSessionHandler}, + traits::OneSessionHandler, weights::Weight, WeakBoundedVec, }; use scale_info::TypeInfo; -use sp_runtime::{generic::DigestItem, traits::Zero, DispatchResult, KeyTypeId}; +use sp_consensus_grandpa::{ + ConsensusLog, EquivocationProof, ScheduledChange, SetId, GRANDPA_AUTHORITIES_KEY, + GRANDPA_ENGINE_ID, RUNTIME_LOG_TARGET as LOG_TARGET, +}; +use sp_runtime::{generic::DigestItem, traits::Zero, DispatchResult}; use sp_session::{GetSessionNumber, GetValidatorCount}; -use sp_staking::SessionIndex; +use sp_staking::{offence::OffenceReportSystem, SessionIndex}; +use sp_std::prelude::*; mod default_weights; mod equivocation; @@ -63,10 +63,7 @@ mod mock; #[cfg(all(feature = "std", test))] mod tests; -pub use equivocation::{ - EquivocationHandler, GrandpaEquivocationOffence, GrandpaOffence, GrandpaTimeSlot, - HandleEquivocation, -}; +pub use equivocation::{EquivocationOffence, EquivocationReportSystem, GrandpaTimeSlot}; pub use pallet::*; @@ -91,30 +88,6 @@ pub mod pallet { + 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 - /// session at which the equivocation occurred. - type KeyOwnerProof: Parameter + GetSessionNumber + GetValidatorCount; - - /// The identification of a key owner, used when reporting equivocations. - type KeyOwnerIdentification: Parameter; - - /// A system for proving ownership of keys, i.e. that a given key was part - /// of a validator set, needed for validating equivocation reports. - type KeyOwnerProofSystem: KeyOwnerProofSystem< - (KeyTypeId, AuthorityId), - Proof = Self::KeyOwnerProof, - IdentificationTuple = Self::KeyOwnerIdentification, - >; - - /// The equivocation handling subsystem, defines methods to report an - /// offence (after the equivocation has been validated) and for submitting a - /// transaction to report an equivocation (from an offchain context). - /// NOTE: when enabling equivocation handling (i.e. this type isn't set to - /// `()`) you must use this pallet's `ValidateUnsigned` in the runtime - /// definition. - type HandleEquivocation: HandleEquivocation; - /// Weights for this pallet. type WeightInfo: WeightInfo; @@ -130,6 +103,19 @@ pub mod pallet { /// can be zero. #[pallet::constant] type MaxSetIdSessionEntries: Get; + + /// The proof of key ownership, used for validating equivocation reports + /// The proof include the session index and validator count of the + /// session at which the equivocation occurred. + type KeyOwnerProof: Parameter + GetSessionNumber + GetValidatorCount; + + /// The equivocation handling subsystem, defines methods to check/report an + /// offence and for submitting a transaction to report an equivocation + /// (from an offchain context). + type EquivocationReportSystem: OffenceReportSystem< + Option, + (EquivocationProof, Self::KeyOwnerProof), + >; } #[pallet::hooks] @@ -211,7 +197,12 @@ pub mod pallet { ) -> DispatchResultWithPostInfo { let reporter = ensure_signed(origin)?; - Self::do_report_equivocation(Some(reporter), *equivocation_proof, key_owner_proof) + T::EquivocationReportSystem::process_evidence( + Some(reporter), + (*equivocation_proof, key_owner_proof), + )?; + // Waive the fee since the report is valid and beneficial + Ok(Pays::No.into()) } /// Report voter equivocation/misbehavior. This method will verify the @@ -232,11 +223,11 @@ pub mod pallet { ) -> DispatchResultWithPostInfo { ensure_none(origin)?; - Self::do_report_equivocation( - T::HandleEquivocation::block_author(), - *equivocation_proof, - key_owner_proof, - ) + T::EquivocationReportSystem::process_evidence( + None, + (*equivocation_proof, key_owner_proof), + )?; + Ok(Pays::No.into()) } /// Note that the current authority set of the GRANDPA finality gadget has stalled. @@ -352,7 +343,7 @@ pub mod pallet { #[pallet::genesis_build] impl GenesisBuild for GenesisConfig { fn build(&self) { - CurrentSetId::::put(fg_primitives::SetId::default()); + CurrentSetId::::put(SetId::default()); Pallet::::initialize(&self.authorities) } } @@ -532,74 +523,6 @@ impl Pallet { SetIdSession::::insert(0, 0); } - fn do_report_equivocation( - reporter: Option, - equivocation_proof: EquivocationProof, - key_owner_proof: T::KeyOwnerProof, - ) -> DispatchResultWithPostInfo { - // we check the equivocation within the context of its set id (and - // associated session) and round. we also need to know the validator - // set count when the offence since it is required to calculate the - // slash amount. - let set_id = equivocation_proof.set_id(); - let round = equivocation_proof.round(); - let session_index = key_owner_proof.session(); - let validator_count = key_owner_proof.validator_count(); - - // validate the key ownership proof extracting the id of the offender. - let offender = T::KeyOwnerProofSystem::check_proof( - (fg_primitives::KEY_TYPE, equivocation_proof.offender().clone()), - key_owner_proof, - ) - .ok_or(Error::::InvalidKeyOwnershipProof)?; - - // validate equivocation proof (check votes are different and - // signatures are valid). - if !sp_consensus_grandpa::check_equivocation_proof(equivocation_proof) { - return Err(Error::::InvalidEquivocationProof.into()) - } - - // fetch the current and previous sets last session index. on the - // genesis set there's no previous set. - let previous_set_id_session_index = if set_id == 0 { - None - } else { - 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(Error::::InvalidEquivocationProof)?; - - // check that the session id for the membership proof is within the - // bounds of the set id reported in the equivocation. - if session_index > set_id_session_index || - previous_set_id_session_index - .map(|previous_index| session_index <= previous_index) - .unwrap_or(false) - { - return Err(Error::::InvalidEquivocationProof.into()) - } - - // report to the offences module rewarding the sender. - T::HandleEquivocation::report_offence( - reporter.into_iter().collect(), - >::Offence::new( - session_index, - validator_count, - offender, - set_id, - round, - ), - ) - .map_err(|_| Error::::DuplicateOffenceReport)?; - - // waive the fee since the report is valid and beneficial - Ok(Pays::No.into()) - } - /// Submits an extrinsic to report an equivocation. This method will create /// an unsigned extrinsic with a call to `report_equivocation_unsigned` and /// will push the transaction to the pool. Only useful in an offchain @@ -608,11 +531,7 @@ impl Pallet { equivocation_proof: EquivocationProof, key_owner_proof: T::KeyOwnerProof, ) -> Option<()> { - T::HandleEquivocation::submit_unsigned_equivocation_report( - equivocation_proof, - key_owner_proof, - ) - .ok() + T::EquivocationReportSystem::publish_evidence((equivocation_proof, key_owner_proof)).ok() } fn on_stalled(further_wait: T::BlockNumber, median: T::BlockNumber) { diff --git a/frame/grandpa/src/mock.rs b/frame/grandpa/src/mock.rs index a33fbb22d6ff8..22ca9c624c626 100644 --- a/frame/grandpa/src/mock.rs +++ b/frame/grandpa/src/mock.rs @@ -225,22 +225,14 @@ parameter_types! { impl Config for Test { type RuntimeEvent = RuntimeEvent; - type KeyOwnerProofSystem = Historical; - - type KeyOwnerProof = - >::Proof; - - type KeyOwnerIdentification = >::IdentificationTuple; - - type HandleEquivocation = - super::EquivocationHandler; - type WeightInfo = (); type MaxAuthorities = ConstU32<100>; type MaxSetIdSessionEntries = MaxSetIdSessionEntries; + + type KeyOwnerProof = >::Proof; + + type EquivocationReportSystem = + super::EquivocationReportSystem; } pub fn grandpa_log(log: ConsensusLog) -> DigestItem { diff --git a/frame/grandpa/src/tests.rs b/frame/grandpa/src/tests.rs index 0bf3c8ddf63dc..a956ca4bca6e9 100644 --- a/frame/grandpa/src/tests.rs +++ b/frame/grandpa/src/tests.rs @@ -21,12 +21,11 @@ use super::{Call, Event, *}; use crate::mock::*; -use codec::Encode; use fg_primitives::ScheduledChange; use frame_support::{ assert_err, assert_noop, assert_ok, dispatch::{GetDispatchInfo, Pays}, - traits::{Currency, OnFinalize, OneSessionHandler}, + traits::{Currency, KeyOwnerProofSystem, OnFinalize, OneSessionHandler}, }; use frame_system::{EventRecord, Phase}; use sp_core::H256; diff --git a/frame/offences/benchmarking/src/lib.rs b/frame/offences/benchmarking/src/lib.rs index 16d77335e1a82..3db937bb378e5 100644 --- a/frame/offences/benchmarking/src/lib.rs +++ b/frame/offences/benchmarking/src/lib.rs @@ -36,9 +36,9 @@ use sp_runtime::{ }; use sp_staking::offence::{Offence, ReportOffence}; -use pallet_babe::BabeEquivocationOffence; +use pallet_babe::EquivocationOffence as BabeEquivocationOffence; use pallet_balances::Config as BalancesConfig; -use pallet_grandpa::{GrandpaEquivocationOffence, GrandpaTimeSlot}; +use pallet_grandpa::{EquivocationOffence as GrandpaEquivocationOffence, GrandpaTimeSlot}; use pallet_im_online::{Config as ImOnlineConfig, Pallet as ImOnline, UnresponsivenessOffence}; use pallet_offences::{Config as OffencesConfig, Pallet as Offences}; use pallet_session::{ diff --git a/frame/offences/src/lib.rs b/frame/offences/src/lib.rs index 6ba16161b320c..8ac1ca0bd734c 100644 --- a/frame/offences/src/lib.rs +++ b/frame/offences/src/lib.rs @@ -112,10 +112,10 @@ pub mod pallet { } } -impl> - ReportOffence for Pallet +impl ReportOffence for Pallet where - T::IdentificationTuple: Clone, + T: Config, + O: Offence, { fn report_offence(reporters: Vec, offence: O) -> Result<(), OffenceError> { let offenders = offence.offenders(); diff --git a/frame/offences/src/mock.rs b/frame/offences/src/mock.rs index d0fc7377acfd6..27e1da8c4e636 100644 --- a/frame/offences/src/mock.rs +++ b/frame/offences/src/mock.rs @@ -134,17 +134,17 @@ pub fn offence_reports(kind: Kind, time_slot: u128) -> Vec { +pub struct Offence { pub validator_set_count: u32, - pub offenders: Vec, + pub offenders: Vec, pub time_slot: u128, } -impl offence::Offence for Offence { +impl offence::Offence for Offence { const ID: offence::Kind = KIND; type TimeSlot = u128; - fn offenders(&self) -> Vec { + fn offenders(&self) -> Vec { self.offenders.clone() } @@ -167,5 +167,5 @@ impl offence::Offence for Offence { /// Create the report id for the given `offender` and `time_slot` combination. pub fn report_id(time_slot: u128, offender: u64) -> H256 { - Offences::report_id::>(&time_slot, &offender) + Offences::report_id::(&time_slot, &offender) } diff --git a/frame/offences/src/tests.rs b/frame/offences/src/tests.rs index a5c18020bcaa3..81f0f44f1b939 100644 --- a/frame/offences/src/tests.rs +++ b/frame/offences/src/tests.rs @@ -160,20 +160,18 @@ fn doesnt_deposit_event_for_dups() { #[test] fn reports_if_an_offence_is_dup() { - type TestOffence = Offence; - new_test_ext().execute_with(|| { let time_slot = 42; assert_eq!(offence_reports(KIND, time_slot), vec![]); let offence = - |time_slot, offenders| TestOffence { validator_set_count: 5, time_slot, offenders }; + |time_slot, offenders| Offence { validator_set_count: 5, time_slot, offenders }; let mut test_offence = offence(time_slot, vec![0]); // the report for authority 0 at time slot 42 should not be a known // offence - assert!(!>::is_known_offence( + assert!(!>::is_known_offence( &test_offence.offenders, &test_offence.time_slot )); @@ -182,7 +180,7 @@ fn reports_if_an_offence_is_dup() { Offences::report_offence(vec![], test_offence.clone()).unwrap(); // the same report should be a known offence now - assert!(>::is_known_offence( + assert!(>::is_known_offence( &test_offence.offenders, &test_offence.time_slot )); @@ -197,7 +195,7 @@ fn reports_if_an_offence_is_dup() { test_offence.offenders.push(1); // it should not be a known offence anymore - assert!(!>::is_known_offence( + assert!(!>::is_known_offence( &test_offence.offenders, &test_offence.time_slot )); @@ -208,7 +206,7 @@ fn reports_if_an_offence_is_dup() { // creating a new offence for the same authorities on the next slot // should be considered a new offence and thefore not known let test_offence_next_slot = offence(time_slot + 1, vec![0, 1]); - assert!(!>::is_known_offence( + assert!(!>::is_known_offence( &test_offence_next_slot.offenders, &test_offence_next_slot.time_slot )); diff --git a/primitives/consensus/grandpa/src/lib.rs b/primitives/consensus/grandpa/src/lib.rs index b466dcf374ccf..26cee07b80be8 100644 --- a/primitives/consensus/grandpa/src/lib.rs +++ b/primitives/consensus/grandpa/src/lib.rs @@ -240,6 +240,9 @@ pub struct EquivocationProof { equivocation: Equivocation, } +// Don't bother the grandpa crate... +impl Eq for EquivocationProof {} + impl EquivocationProof { /// Create a new `EquivocationProof` for the given set id and using the /// given equivocation as proof. diff --git a/primitives/consensus/slots/src/lib.rs b/primitives/consensus/slots/src/lib.rs index d723785278da9..1f2fa585df7f2 100644 --- a/primitives/consensus/slots/src/lib.rs +++ b/primitives/consensus/slots/src/lib.rs @@ -130,7 +130,7 @@ impl SlotDuration { /// 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 /// include the slot number. -#[derive(Clone, Debug, Decode, Encode, PartialEq, TypeInfo)] +#[derive(Clone, Debug, Decode, Encode, PartialEq, TypeInfo, Eq)] pub struct EquivocationProof { /// Returns the authority id of the equivocator. pub offender: Id, diff --git a/primitives/staking/src/offence.rs b/primitives/staking/src/offence.rs index dec9756687979..6694c9055d4ff 100644 --- a/primitives/staking/src/offence.rs +++ b/primitives/staking/src/offence.rs @@ -18,10 +18,10 @@ //! Common traits and types that are useful for describing offences for usage in environments //! that use staking. -use sp_std::vec::Vec; - use codec::{Decode, Encode}; -use sp_runtime::Perbill; +use sp_core::Get; +use sp_runtime::{transaction_validity::TransactionValidityError, DispatchError, Perbill}; +use sp_std::vec::Vec; use crate::SessionIndex; @@ -209,3 +209,68 @@ pub struct OffenceDetails { /// particular reporters. pub reporters: Vec, } + +/// An abstract system to publish, check and process offence evidences. +/// +/// Implementation details are left opaque and we don't assume any specific usage +/// scenario for this trait at this level. The main goal is to group together some +/// common actions required during a typical offence report flow. +/// +/// Even though this trait doesn't assume too much, this is a general guideline +/// for a typical usage scenario: +/// +/// 1. An offence is detected and an evidence is submitted on-chain via the +/// [`OffenceReportSystem::publish_evidence`] method. This will construct +/// and submit an extrinsic transaction containing the offence evidence. +/// +/// 2. If the extrinsic is unsigned then the transaction receiver may want to +/// perform some preliminary checks before further processing. This is a good +/// place to call the [`OffenceReportSystem::check_evidence`] method. +/// +/// 3. Finally the report extrinsic is executed on-chain. This is where the user +/// calls the [`OffenceReportSystem::process_evidence`] to consume the offence +/// report and enact any required action. +pub trait OffenceReportSystem { + /// Longevity, in blocks, for the evidence report validity. + /// + /// For example, when using the staking pallet this should be set equal + /// to the bonding duration in blocks, not eras. + type Longevity: Get; + + /// Publish an offence evidence. + /// + /// Common usage: submit the evidence on-chain via some kind of extrinsic. + fn publish_evidence(evidence: Evidence) -> Result<(), ()>; + + /// Check an offence evidence. + /// + /// Common usage: preliminary validity check before execution + /// (e.g. for unsigned extrinsic quick checks). + fn check_evidence(evidence: Evidence) -> Result<(), TransactionValidityError>; + + /// Process an offence evidence. + /// + /// Common usage: enact some form of slashing directly or by forwarding + /// the evidence to a lower level specialized subsystem (e.g. a handler + /// implementing `ReportOffence` trait). + fn process_evidence(reporter: Reporter, evidence: Evidence) -> Result<(), DispatchError>; +} + +/// Dummy offence report system. +/// +/// Doesn't do anything special and returns `Ok(())` for all the actions. +impl OffenceReportSystem for () { + type Longevity = (); + + fn publish_evidence(_evidence: Evidence) -> Result<(), ()> { + Ok(()) + } + + fn check_evidence(_evidence: Evidence) -> Result<(), TransactionValidityError> { + Ok(()) + } + + fn process_evidence(_reporter: Reporter, _evidence: Evidence) -> Result<(), DispatchError> { + Ok(()) + } +} diff --git a/test-utils/runtime/src/lib.rs b/test-utils/runtime/src/lib.rs index 1ea8b866367dd..83b4e2977b5cd 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, OpaqueMetadata, RuntimeDebug}; +use sp_core::{OpaqueMetadata, RuntimeDebug}; use sp_trie::{ trie_types::{TrieDBBuilder, TrieDBMutBuilderV1}, PrefixedMemoryDB, StorageProof, @@ -39,7 +39,7 @@ use cfg_if::cfg_if; use frame_support::{ dispatch::RawOrigin, parameter_types, - traits::{CallerTrait, ConstU32, ConstU64, CrateVersion, KeyOwnerProofSystem}, + traits::{CallerTrait, ConstU32, ConstU64, CrateVersion}, weights::{RuntimeDbWeight, Weight}, }; use frame_system::limits::{BlockLength, BlockWeights}; @@ -659,21 +659,10 @@ impl pallet_babe::Config for Runtime { // pallet_babe::SameAuthoritiesForever. type EpochChangeTrigger = pallet_babe::ExternalTrigger; type DisabledValidators = (); - - type KeyOwnerProofSystem = (); - - type KeyOwnerProof = - >::Proof; - - type KeyOwnerIdentification = >::IdentificationTuple; - - type HandleEquivocation = (); type WeightInfo = (); - type MaxAuthorities = ConstU32<10>; + type KeyOwnerProof = sp_core::Void; + type EquivocationReportSystem = (); } /// Adds one to the given input and returns the final result. From f59f5019333c44b2513852f7ddf30514430ec78f Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Wed, 8 Mar 2023 07:57:46 +1100 Subject: [PATCH 485/715] fix: Fixes #13071 change order of ldd command and update ./docker/README.md (#13072) * fixes #13071 * remove warning --- docker/README.md | 7 ++++++- docker/substrate_builder.Dockerfile | 4 ++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/docker/README.md b/docker/README.md index ca3c1bde4e321..b3b80678797a4 100644 --- a/docker/README.md +++ b/docker/README.md @@ -1,6 +1,6 @@ # 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. +The Docker image in this folder is a `builder` image. It is self contained and allows users to build the binaries themselves. There is no requirement on having Rust or any other toolchain installed but a working Docker environment. Unlike the `parity/polkadot` image which contains a single binary (`polkadot`!) used by default, the image in this folder builds and contains several binaries and you need to provide the name of the binary to be called. @@ -12,6 +12,11 @@ You should refer to the .Dockerfile for the actual list. At the time of editing, - node-template - chain-spec-builder +To generate the latest parity/substrate image. Please first run: +```sh +./build.sh +``` + 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: diff --git a/docker/substrate_builder.Dockerfile b/docker/substrate_builder.Dockerfile index d0812c1a80c40..03b6b46caf41f 100644 --- a/docker/substrate_builder.Dockerfile +++ b/docker/substrate_builder.Dockerfile @@ -24,10 +24,10 @@ 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 && \ +# unclutter and minimize the attack surface + rm -rf /usr/bin /usr/sbin && \ /usr/local/bin/substrate --version USER substrate From 7c3d27927577b7fa9ea659aed3197d1f67dd663e Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Thu, 9 Mar 2023 00:51:43 +1100 Subject: [PATCH 486/715] [docker] Use `BASH_SOURCE` to find project root, add `.dockerignore` (#13472) --- docker/build.sh | 7 +++---- docker/substrate_builder.Dockerfile.dockerignore | 11 +++++++++++ 2 files changed, 14 insertions(+), 4 deletions(-) create mode 100644 docker/substrate_builder.Dockerfile.dockerignore diff --git a/docker/build.sh b/docker/build.sh index f0a4560ff8fea..d4befd864e4e8 100755 --- a/docker/build.sh +++ b/docker/build.sh @@ -3,9 +3,8 @@ set -e pushd . -# The following line ensure we run from the project root -PROJECT_ROOT=`git rev-parse --show-toplevel` -cd $PROJECT_ROOT +# Change to the project root and supports calls from symlinks +cd $(dirname "$(dirname "$(realpath "${BASH_SOURCE[0]}")")") # Find the current version from Cargo.toml VERSION=`grep "^version" ./bin/node/cli/Cargo.toml | egrep -o "([0-9\.]+)"` @@ -14,7 +13,7 @@ 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 . +time DOCKER_BUILDKIT=1 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 diff --git a/docker/substrate_builder.Dockerfile.dockerignore b/docker/substrate_builder.Dockerfile.dockerignore new file mode 100644 index 0000000000000..dccfeb651ad8d --- /dev/null +++ b/docker/substrate_builder.Dockerfile.dockerignore @@ -0,0 +1,11 @@ +doc +**target* +.idea/ +.git/ +.github/ +Dockerfile +.dockerignore +.local +.env* +HEADER-GPL3 +LICENSE-GPL3 From 77c675b15cd805e5a9d61345763655ad8941591e Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Thu, 9 Mar 2023 00:57:44 +1100 Subject: [PATCH 487/715] Update Docker instructions (#13437) --- .gitignore | 1 + README.md | 1 + bin/node-template/README.md | 29 +++---------------- bin/node-template/docker-compose.yml | 17 ----------- bin/node-template/scripts/docker_run.sh | 10 ------- docker/README.md | 38 +++++++++++++++++++++---- docker/run.sh | 13 +++++++++ 7 files changed, 51 insertions(+), 58 deletions(-) delete mode 100644 bin/node-template/docker-compose.yml delete mode 100755 bin/node-template/scripts/docker_run.sh create mode 100755 docker/run.sh diff --git a/.gitignore b/.gitignore index efb63520e1e1b..f30103c625fe0 100644 --- a/.gitignore +++ b/.gitignore @@ -25,4 +25,5 @@ rls*.log *.bin *.iml scripts/ci/node-template-release/Cargo.lock +bin/node-template/Cargo.lock substrate.code-workspace diff --git a/README.md b/README.md index 7d8c7e575581c..361f410ab2790 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ Substrate is a next-generation framework for blockchain innovation 🚀. Head to [docs.substrate.io](https://docs.substrate.io) and follow the [installation](https://docs.substrate.io/install/) instructions. Then try out one of the [tutorials](https://docs.substrate.io/tutorials/). +Refer to the [Docker instructions](./docker/README.md) to quickly run Substrate, Substrate Node Template, Subkey, or to build a chain spec. ## Community & Support diff --git a/bin/node-template/README.md b/bin/node-template/README.md index c42b58449565d..7562b6247f353 100644 --- a/bin/node-template/README.md +++ b/bin/node-template/README.md @@ -2,10 +2,10 @@ A fresh [Substrate](https://substrate.io/) node, ready for hacking :rocket: -A standalone version of this template is available for each release of Polkadot in the [Substrate Developer Hub Parachain Template](https://github.com/substrate-developer-hub/substrate-parachain-template/) repository. -The parachain template is generated directly at each Polkadot release branch form the [Node Template in Substreate](https://github.com/paritytech/substrate/tree/master/bin/node-template) upstream +A standalone version of this template is available for each release of Polkadot in the [Substrate Developer Hub Parachain Template](https://github.com/substrate-developer-hub/substrate-parachain-template/) repository. +The parachain template is generated directly at each Polkadot release branch from the [Node Template in Substrate](https://github.com/paritytech/substrate/tree/master/bin/node-template) upstream -It is usually best to to use the stand-alone version to start a new project. +It is usually best to use the stand-alone version to start a new project. All bugs, suggestions, and feature requests should be made upstream in the [Substrate](https://github.com/paritytech/substrate/tree/master/bin/node-template) repository. ## Getting Started @@ -158,25 +158,4 @@ To get all the correct dependencies, activate direnv `direnv allow` and lorri `l ### Docker -First, install [Docker](https://docs.docker.com/get-docker/) and [Docker Compose](https://docs.docker.com/compose/install/). - -Then run the following command to start a single node development chain. - -```sh -./scripts/docker_run.sh -``` - -This command compiles the code and starts a local development network. -You can also replace the default command (`cargo build --release && ./target/release/node-template --dev --ws-external`) by appending your own. -For example: - -```sh -# Run Substrate node without re-compiling -./scripts/docker_run.sh ./target/release/node-template --dev --ws-external - -# Purge the local dev chain -./scripts/docker_run.sh ./target/release/node-template purge-chain --dev - -# Check whether the code is compilable -./scripts/docker_run.sh cargo check -``` +Please follow the [Substrate Docker instructions here](https://github.com/paritytech/substrate/blob/master/docker/README.md) to build the Docker container with the Substrate Node Template binary. diff --git a/bin/node-template/docker-compose.yml b/bin/node-template/docker-compose.yml deleted file mode 100644 index bc1922f47d963..0000000000000 --- a/bin/node-template/docker-compose.yml +++ /dev/null @@ -1,17 +0,0 @@ -version: "3.2" - -services: - dev: - container_name: node-template - image: paritytech/ci-linux:production - working_dir: /var/www/node-template - ports: - - "9944:9944" - environment: - - CARGO_HOME=/var/www/node-template/.cargo - volumes: - - .:/var/www/node-template - - type: bind - source: ./.local - target: /root/.local - command: bash -c "cargo build --release && ./target/release/node-template --dev --ws-external" diff --git a/bin/node-template/scripts/docker_run.sh b/bin/node-template/scripts/docker_run.sh deleted file mode 100755 index 0bac44b4cfb3b..0000000000000 --- a/bin/node-template/scripts/docker_run.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash -# This script is meant to be run on Unix/Linux based systems -set -e - -echo "*** Start Substrate node template ***" - -cd $(dirname ${BASH_SOURCE[0]})/.. - -docker-compose down --remove-orphans -docker-compose run --rm --service-ports dev $@ diff --git a/docker/README.md b/docker/README.md index b3b80678797a4..71ddb2dffd1bb 100644 --- a/docker/README.md +++ b/docker/README.md @@ -5,23 +5,49 @@ There is no requirement on having Rust or any other toolchain installed but a wo 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: +You should refer to the [.Dockerfile](./substrate_builder.Dockerfile) for the actual list. At the time of editing, the list of included binaries is: - substrate - subkey - node-template - chain-spec-builder -To generate the latest parity/substrate image. Please first run: +First, install [Docker](https://docs.docker.com/get-docker/). + +Then to generate the latest parity/substrate image. Please run: ```sh ./build.sh ``` +> If you wish to create a debug build rather than a production build, then you may modify the [.Dockerfile](./substrate_builder.Dockerfile) replacing `cargo build --locked --release` with just `cargo build --locked` and replacing `target/release` with `target/debug`. + +> If you get an error that a tcp port address is already in use then find an available port to use for the host port in the [.Dockerfile](./substrate_builder.Dockerfile). + The image can be used by passing the selected binary followed by the appropriate tags for this binary. 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` +- `./run.sh substrate --version` +- `./run.sh subkey --help` +- `./run.sh node-template --version` +- `./run.sh chain-spec-builder --help` + +Then try running the following command to start a single node development chain using the Substrate Node Template binary `node-template`: + +```sh +./run.sh node-template --dev --ws-external +``` + +Note: It is recommended to provide a custom `--base-path` to store the chain database. For example: + +```sh +# Run Substrate Node Template without re-compiling +./run.sh node-template --dev --ws-external --base-path=/data +``` + +> To print logs follow the [Substrate debugging instructions](https://docs.substrate.io/test/debug/). + +```sh +# Purge the local dev chain +./run.sh node-template purge-chain --dev --base-path=/data -y +``` diff --git a/docker/run.sh b/docker/run.sh new file mode 100755 index 0000000000000..43510bee07f58 --- /dev/null +++ b/docker/run.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +args=$@ + +# handle when arguments not provided. run arguments provided to script. +if [ "$args" = "" ] ; then + printf "Note: Please try providing an argument to the script.\n\n" + exit 1 +else + printf "*** Running Substrate Docker container with provided arguments: $args\n\n" + docker run --rm -it parity/substrate $args +fi + From 48e7cb147cb9a27125fd2e82edbcf4d0ed5927c4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 9 Mar 2023 07:08:00 +0000 Subject: [PATCH 488/715] Bump wasmtime from 6.0.0 to 6.0.1 (#13566) Bumps [wasmtime](https://github.com/bytecodealliance/wasmtime) from 6.0.0 to 6.0.1. - [Release notes](https://github.com/bytecodealliance/wasmtime/releases) - [Changelog](https://github.com/bytecodealliance/wasmtime/blob/main/docs/WASI-some-possible-changes.md) - [Commits](https://github.com/bytecodealliance/wasmtime/compare/v6.0.0...v6.0.1) --- updated-dependencies: - dependency-name: wasmtime dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 76 ++++++++++++++-------------- client/executor/wasmtime/Cargo.toml | 2 +- primitives/wasm-interface/Cargo.toml | 2 +- 3 files changed, 40 insertions(+), 40 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 53a8675437ff9..c0dcc47fd4f5d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1154,18 +1154,18 @@ dependencies = [ [[package]] name = "cranelift-bforest" -version = "0.93.0" +version = "0.93.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91b18cf92869a6ae85cde3af4bc4beb6154efa8adef03b18db2ad413d5bce3a2" +checksum = "a7379abaacee0f14abf3204a7606118f0465785252169d186337bcb75030815a" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-codegen" -version = "0.93.0" +version = "0.93.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567d9f6e919bac076f39b902a072686eaf9e6d015baa34d10a61b85105b7af59" +checksum = "9489fa336927df749631f1008007ced2871068544f40a202ce6d93fbf2366a7b" dependencies = [ "arrayvec 0.7.2", "bumpalo", @@ -1184,33 +1184,33 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.93.0" +version = "0.93.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e72b2d5ec8917b2971fe83850187373d0a186db4748a7c23a5f48691b8d92bb" +checksum = "05bbb67da91ec721ed57cef2f7c5ef7728e1cd9bde9ffd3ef8601022e73e3239" dependencies = [ "cranelift-codegen-shared", ] [[package]] name = "cranelift-codegen-shared" -version = "0.93.0" +version = "0.93.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3461c0e0c2ebbeb92533aacb27e219289f60dc84134ef34fbf2d77c9eddf07ef" +checksum = "418ecb2f36032f6665dc1a5e2060a143dbab41d83b784882e97710e890a7a16d" [[package]] name = "cranelift-entity" -version = "0.93.0" +version = "0.93.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af684f7f7b01427b1942c7102673322a51b9d6f261e9663dc5e5595786775531" +checksum = "7cf583f7b093f291005f9fb1323e2c37f6ee4c7909e39ce016b2e8360d461705" dependencies = [ "serde", ] [[package]] name = "cranelift-frontend" -version = "0.93.0" +version = "0.93.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d361ed0373cf5f086b49c499aa72227b646a64f899f32e34312f97c0fadff75" +checksum = "0b66bf9e916f57fbbd0f7703ec6286f4624866bf45000111627c70d272c8dda1" dependencies = [ "cranelift-codegen", "log", @@ -1220,15 +1220,15 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.93.0" +version = "0.93.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cef4f8f3984d772c199a48896d2fb766f96301bf71b371e03a2b99f4f3b7b931" +checksum = "649782a39ce99798dd6b4029e2bb318a2fbeaade1b4fa25330763c10c65bc358" [[package]] name = "cranelift-native" -version = "0.93.0" +version = "0.93.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f98e4e99a353703475d5acb402b9c13482d41d8a4008b352559bd560afb90363" +checksum = "937e021e089c51f9749d09e7ad1c4f255c2f8686cb8c3df63a34b3ec9921bc41" dependencies = [ "cranelift-codegen", "libc", @@ -1237,9 +1237,9 @@ dependencies = [ [[package]] name = "cranelift-wasm" -version = "0.93.0" +version = "0.93.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1e3f4f0779a1b0f286a6ef19835d8665f88326e656a6d7d84fa9a39fa38ca32" +checksum = "d850cf6775477747c9dfda9ae23355dd70512ffebc70cf82b85a5b111ae668b5" dependencies = [ "cranelift-codegen", "cranelift-entity", @@ -12214,9 +12214,9 @@ dependencies = [ [[package]] name = "wasmtime" -version = "6.0.0" +version = "6.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9010891d0b8e367c3be94ca35d7bc25c1de3240463bb1d61bcfc8c2233c4e0d0" +checksum = "f6e89f9819523447330ffd70367ef4a18d8c832e24e8150fe054d1d912841632" dependencies = [ "anyhow", "bincode", @@ -12242,18 +12242,18 @@ dependencies = [ [[package]] name = "wasmtime-asm-macros" -version = "6.0.0" +version = "6.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65805c663eaa8257b910666f6d4b056b5c7329750da754ba5df54f3af7dbf35c" +checksum = "9bd3a5e46c198032da934469f3a6e48649d1f9142438e4fd4617b68a35644b8a" dependencies = [ "cfg-if", ] [[package]] name = "wasmtime-cache" -version = "6.0.0" +version = "6.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2049ddfc1b10efc3c5591d0e84b9570ca50478f8818f3bfabb1a467918f53fb4" +checksum = "b389ae9b678b9c3851091a4804f4182d688d27aff7abc9aa37fa7be37d8ecffa" dependencies = [ "anyhow", "base64 0.13.1", @@ -12271,9 +12271,9 @@ dependencies = [ [[package]] name = "wasmtime-cranelift" -version = "6.0.0" +version = "6.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9065cad6a724fa838ec8497567e0b23acc26417bb2449f8d9d2021925c72f2" +checksum = "59b2c92a08c0db6efffd88fdc97d7aa9c7c63b03edb0971dbca745469f820e8c" dependencies = [ "anyhow", "cranelift-codegen", @@ -12292,9 +12292,9 @@ dependencies = [ [[package]] name = "wasmtime-environ" -version = "6.0.0" +version = "6.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f964bb0b91fa021b8d1b488c62cc77b346c1dae6e3ebd010050b57c1f2ca657" +checksum = "9a6db9fc52985ba06ca601f2ff0ff1f526c5d724c7ac267b47326304b0c97883" dependencies = [ "anyhow", "cranelift-entity", @@ -12311,9 +12311,9 @@ dependencies = [ [[package]] name = "wasmtime-jit" -version = "6.0.0" +version = "6.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7a1d06f5d109539e0168fc74fa65e3948ac8dac3bb8cdbd08b62b36a0ae27b8" +checksum = "b77e3a52cd84d0f7f18554afa8060cfe564ccac61e3b0802d3fd4084772fa5f6" dependencies = [ "addr2line 0.17.0", "anyhow", @@ -12335,9 +12335,9 @@ dependencies = [ [[package]] name = "wasmtime-jit-debug" -version = "6.0.0" +version = "6.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f76ef2e410329aaf8555ac6571d6fe07711be0646dcdf7ff3ab750a42ed2e583" +checksum = "d0245e8a9347017c7185a72e215218a802ff561545c242953c11ba00fccc930f" dependencies = [ "object 0.29.0", "once_cell", @@ -12346,9 +12346,9 @@ dependencies = [ [[package]] name = "wasmtime-jit-icache-coherence" -version = "6.0.0" +version = "6.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec1fd0f0dd79e7cc0f55b102e320d7c77ab76cd272008a8fd98e25b5777e2636" +checksum = "67d412e9340ab1c83867051d8d1d7c90aa8c9afc91da086088068e2734e25064" dependencies = [ "cfg-if", "libc", @@ -12357,9 +12357,9 @@ dependencies = [ [[package]] name = "wasmtime-runtime" -version = "6.0.0" +version = "6.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271aef9b4ca2e953a866293683f2db33cda46f6933c5e431e68d8373723d4ab6" +checksum = "d594e791b5fdd4dbaf8cf7ae62f2e4ff85018ce90f483ca6f42947688e48827d" dependencies = [ "anyhow", "cc", @@ -12381,9 +12381,9 @@ dependencies = [ [[package]] name = "wasmtime-types" -version = "6.0.0" +version = "6.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b18144b0e45479a830ac9fcebfc71a16d90dc72d8ebd5679700eb3bfe974d7df" +checksum = "a6688d6f96d4dbc1f89fab626c56c1778936d122b5f4ae7a57c2eb42b8d982e2" dependencies = [ "cranelift-entity", "serde", diff --git a/client/executor/wasmtime/Cargo.toml b/client/executor/wasmtime/Cargo.toml index 2e892a98a126b..bffccd12badfb 100644 --- a/client/executor/wasmtime/Cargo.toml +++ b/client/executor/wasmtime/Cargo.toml @@ -19,7 +19,7 @@ libc = "0.2.121" # When bumping wasmtime do not forget to also bump rustix # to exactly the same version as used by wasmtime! -wasmtime = { version = "6.0.0", default-features = false, features = [ +wasmtime = { version = "6.0.1", default-features = false, features = [ "cache", "cranelift", "jitdump", diff --git a/primitives/wasm-interface/Cargo.toml b/primitives/wasm-interface/Cargo.toml index 306a47e6dc1b7..441d66f0fb064 100644 --- a/primitives/wasm-interface/Cargo.toml +++ b/primitives/wasm-interface/Cargo.toml @@ -18,7 +18,7 @@ codec = { package = "parity-scale-codec", version = "3.2.2", default-features = impl-trait-for-tuples = "0.2.2" log = { version = "0.4.17", optional = true } wasmi = { version = "0.13.2", optional = true } -wasmtime = { version = "6.0.0", default-features = false, optional = true } +wasmtime = { version = "6.0.1", default-features = false, optional = true } anyhow = { version = "1.0.68", optional = true } sp-std = { version = "5.0.0", default-features = false, path = "../std" } From e46d96cb843b8ae025d2aae8abb46035a6df738c Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Thu, 9 Mar 2023 13:29:03 +0100 Subject: [PATCH 489/715] Undeploy insecure randomness pallet (#13560) * Undeploy insecure randomness pallet from node-template Signed-off-by: Oliver Tale-Yazdi * Update lockfile Signed-off-by: Oliver Tale-Yazdi * Remove from runtime Signed-off-by: Oliver Tale-Yazdi --------- Signed-off-by: Oliver Tale-Yazdi --- Cargo.lock | 1 - bin/node-template/runtime/Cargo.toml | 3 --- bin/node-template/runtime/src/lib.rs | 3 --- 3 files changed, 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c0dcc47fd4f5d..a970be356b2dc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5096,7 +5096,6 @@ dependencies = [ "pallet-aura", "pallet-balances", "pallet-grandpa", - "pallet-insecure-randomness-collective-flip", "pallet-sudo", "pallet-template", "pallet-timestamp", diff --git a/bin/node-template/runtime/Cargo.toml b/bin/node-template/runtime/Cargo.toml index 55fdea7f59031..90fa6269ebe8c 100644 --- a/bin/node-template/runtime/Cargo.toml +++ b/bin/node-template/runtime/Cargo.toml @@ -20,7 +20,6 @@ pallet-aura = { version = "4.0.0-dev", default-features = false, path = "../../. pallet-balances = { version = "4.0.0-dev", default-features = false, path = "../../../frame/balances" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../../frame/support" } pallet-grandpa = { version = "4.0.0-dev", default-features = false, path = "../../../frame/grandpa" } -pallet-insecure-randomness-collective-flip = { version = "4.0.0-dev", default-features = false, path = "../../../frame/insecure-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 } @@ -70,7 +69,6 @@ std = [ "pallet-aura/std", "pallet-balances/std", "pallet-grandpa/std", - "pallet-insecure-randomness-collective-flip/std", "pallet-sudo/std", "pallet-template/std", "pallet-timestamp/std", @@ -109,7 +107,6 @@ try-runtime = [ "pallet-aura/try-runtime", "pallet-balances/try-runtime", "pallet-grandpa/try-runtime", - "pallet-insecure-randomness-collective-flip/try-runtime", "pallet-sudo/try-runtime", "pallet-template/try-runtime", "pallet-timestamp/try-runtime", diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs index ef90517a2a258..ac01aa95f4f12 100644 --- a/bin/node-template/runtime/src/lib.rs +++ b/bin/node-template/runtime/src/lib.rs @@ -203,8 +203,6 @@ impl frame_system::Config for Runtime { type MaxConsumers = frame_support::traits::ConstU32<16>; } -impl pallet_insecure_randomness_collective_flip::Config for Runtime {} - impl pallet_aura::Config for Runtime { type AuthorityId = AuraId; type DisabledValidators = (); @@ -279,7 +277,6 @@ construct_runtime!( UncheckedExtrinsic = UncheckedExtrinsic, { System: frame_system, - RandomnessCollectiveFlip: pallet_insecure_randomness_collective_flip, Timestamp: pallet_timestamp, Aura: pallet_aura, Grandpa: pallet_grandpa, From 11b932677ea71920c76c4a204947db773cf710f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= <123550+andresilva@users.noreply.github.com> Date: Thu, 9 Mar 2023 14:05:04 +0000 Subject: [PATCH 490/715] grandpa: send neighbor packets to light clients on set transition (#13559) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * grandpa: send neighbor packets to light clients on set transition * Apply suggestions from code review Co-authored-by: Bastian Köcher * remove match statement --------- Co-authored-by: Bastian Köcher --- .../grandpa/src/communication/gossip.rs | 175 +++++++++++------- 1 file changed, 109 insertions(+), 66 deletions(-) diff --git a/client/consensus/grandpa/src/communication/gossip.rs b/client/consensus/grandpa/src/communication/gossip.rs index cf476f8e32222..0a3029e25477a 100644 --- a/client/consensus/grandpa/src/communication/gossip.rs +++ b/client/consensus/grandpa/src/communication/gossip.rs @@ -791,68 +791,67 @@ impl Inner { /// 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 - }, - }; + let local_view = self.local_view.as_mut()?; + if local_view.round == round { + // Do not send neighbor packets out if `round` has not changed --- + // such behavior is punishable. + return None + } - let set_id = local_view.set_id; + let set_id = local_view.set_id; - debug!( - target: LOG_TARGET, - "Voter {} noting beginning of round {:?} to network.", - self.config.name(), - (round, set_id) - ); + debug!( + target: LOG_TARGET, + "Voter {} noting beginning of round {:?} to network.", + self.config.name(), + (round, set_id) + ); - local_view.update_round(round); + local_view.update_round(round); - self.live_topics.push(round, set_id); - self.peers.reshuffle(); - } - self.multicast_neighbor_packet() + self.live_topics.push(round, set_id); + self.peers.reshuffle(); + + self.multicast_neighbor_packet(false) } /// Note that a voter set with given ID has started. Does nothing if the last /// call to the function was with the same `set_id`. fn note_set(&mut self, set_id: SetId, authorities: Vec) -> MaybeMessage { - { - let local_view = match self.local_view { - ref mut x @ None => x.get_or_insert(LocalView::new(set_id, Round(1))), - Some(ref mut v) => - if v.set_id == set_id { - let diff_authorities = self.authorities.iter().collect::>() != - authorities.iter().collect::>(); - - if diff_authorities { - debug!(target: LOG_TARGET, - "Gossip validator noted set {:?} twice with different authorities. \ - Was the authority set hard forked?", - set_id, - ); - self.authorities = authorities; - } - // Do not send neighbor packets out if the `set_id` has not changed --- - // such behavior is punishable. - return None - } else { - v - }, - }; + let local_view = match self.local_view { + ref mut x @ None => x.get_or_insert(LocalView::new(set_id, Round(1))), + Some(ref mut v) => + if v.set_id == set_id { + let diff_authorities = self.authorities.iter().collect::>() != + authorities.iter().collect::>(); + + if diff_authorities { + debug!( + target: LOG_TARGET, + "Gossip validator noted set {:?} twice with different authorities. \ + Was the authority set hard forked?", + set_id, + ); + + self.authorities = authorities; + } - local_view.update_set(set_id); - self.live_topics.push(Round(1), set_id); - self.authorities = authorities; - } - self.multicast_neighbor_packet() + // Do not send neighbor packets out if the `set_id` has not changed --- + // such behavior is punishable. + return None + } else { + v + }, + }; + + local_view.update_set(set_id); + self.live_topics.push(Round(1), set_id); + self.authorities = authorities; + + // when transitioning to a new set we also want to send neighbor packets to light clients, + // this is so that they know who to ask justifications from in order to finalize the last + // block in the previous set. + self.multicast_neighbor_packet(true) } /// Note that we've imported a commit finalizing a given block. Does nothing if the last @@ -864,19 +863,14 @@ impl Inner { set_id: SetId, finalized: NumberFor, ) -> MaybeMessage { - { - match self.local_view { - None => return None, - Some(ref mut v) => - if v.last_commit_height() < Some(&finalized) { - v.last_commit = Some((finalized, round, set_id)); - } else { - return None - }, - }; + let local_view = self.local_view.as_mut()?; + if local_view.last_commit_height() < Some(&finalized) { + local_view.last_commit = Some((finalized, round, set_id)); + } else { + return None } - self.multicast_neighbor_packet() + self.multicast_neighbor_packet(false) } fn consider_vote(&self, round: Round, set_id: SetId) -> Consider { @@ -1193,7 +1187,7 @@ impl Inner { (neighbor_topics, action, catch_up, report) } - fn multicast_neighbor_packet(&self) -> MaybeMessage { + fn multicast_neighbor_packet(&self, force_light: bool) -> MaybeMessage { self.local_view.as_ref().map(|local_view| { let packet = NeighborPacket { round: local_view.round, @@ -1207,8 +1201,9 @@ impl Inner { .iter() .filter_map(|(id, info)| { // light clients don't participate in the full GRANDPA voter protocol - // and therefore don't need to be informed about view updates - if info.roles.is_light() { + // and therefore don't need to be informed about all view updates unless + // we explicitly require it (e.g. when transitioning to a new set) + if info.roles.is_light() && !force_light { None } else { Some(id) @@ -2612,4 +2607,52 @@ mod tests { assert_eq!(val.inner().read().authorities, a2); } + + #[test] + fn sends_neighbor_packets_to_non_light_peers_when_starting_a_new_round() { + let (val, _) = GossipValidator::::new(config(), voter_set_state(), None, None); + + // initialize the validator to a stable set id + val.note_set(SetId(1), Vec::new(), |_, _| {}); + + let authority_peer = PeerId::random(); + let full_peer = PeerId::random(); + let light_peer = PeerId::random(); + + val.inner.write().peers.new_peer(authority_peer, ObservedRole::Authority); + val.inner.write().peers.new_peer(full_peer, ObservedRole::Full); + val.inner.write().peers.new_peer(light_peer, ObservedRole::Light); + + val.note_round(Round(2), |peers, message| { + assert_eq!(peers.len(), 2); + assert!(peers.contains(&authority_peer)); + assert!(peers.contains(&full_peer)); + assert!(!peers.contains(&light_peer)); + assert!(matches!(message, NeighborPacket { set_id: SetId(1), round: Round(2), .. })); + }); + } + + #[test] + fn sends_neighbor_packets_to_all_peers_when_starting_a_new_set() { + let (val, _) = GossipValidator::::new(config(), voter_set_state(), None, None); + + // initialize the validator to a stable set id + val.note_set(SetId(1), Vec::new(), |_, _| {}); + + let authority_peer = PeerId::random(); + let full_peer = PeerId::random(); + let light_peer = PeerId::random(); + + val.inner.write().peers.new_peer(authority_peer, ObservedRole::Authority); + val.inner.write().peers.new_peer(full_peer, ObservedRole::Full); + val.inner.write().peers.new_peer(light_peer, ObservedRole::Light); + + val.note_set(SetId(2), Vec::new(), |peers, message| { + assert_eq!(peers.len(), 3); + assert!(peers.contains(&authority_peer)); + assert!(peers.contains(&full_peer)); + assert!(peers.contains(&light_peer)); + assert!(matches!(message, NeighborPacket { set_id: SetId(2), round: Round(1), .. })); + }); + } } From 48c8875c417a4aebf105112b4442e1343228c7ab Mon Sep 17 00:00:00 2001 From: Jun Jiang Date: Thu, 9 Mar 2023 23:57:02 +0800 Subject: [PATCH 491/715] Make pallet_nfts storages public (#13517) --- frame/nfts/src/lib.rs | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/frame/nfts/src/lib.rs b/frame/nfts/src/lib.rs index 681d908423da6..9314098d3b334 100644 --- a/frame/nfts/src/lib.rs +++ b/frame/nfts/src/lib.rs @@ -196,7 +196,7 @@ pub mod pallet { /// Details of a collection. #[pallet::storage] - pub(super) type Collection, I: 'static = ()> = StorageMap< + pub type Collection, I: 'static = ()> = StorageMap< _, Blake2_128Concat, T::CollectionId, @@ -205,13 +205,13 @@ pub mod pallet { /// The collection, if any, of which an account is willing to take ownership. #[pallet::storage] - pub(super) type OwnershipAcceptance, I: 'static = ()> = + pub type OwnershipAcceptance, I: 'static = ()> = StorageMap<_, Blake2_128Concat, T::AccountId, T::CollectionId>; /// The items held by any given account; set out this way so that items owned by a single /// account can be enumerated. #[pallet::storage] - pub(super) type Account, I: 'static = ()> = StorageNMap< + pub type Account, I: 'static = ()> = StorageNMap< _, ( NMapKey, // owner @@ -225,7 +225,7 @@ pub mod pallet { /// The collections owned by any given account; set out this way so that collections owned by /// a single account can be enumerated. #[pallet::storage] - pub(super) type CollectionAccount, I: 'static = ()> = StorageDoubleMap< + pub type CollectionAccount, I: 'static = ()> = StorageDoubleMap< _, Blake2_128Concat, T::AccountId, @@ -238,7 +238,7 @@ pub mod pallet { /// The items in existence and their ownership details. #[pallet::storage] /// Stores collection roles as per account. - pub(super) type CollectionRoleOf, I: 'static = ()> = StorageDoubleMap< + pub type CollectionRoleOf, I: 'static = ()> = StorageDoubleMap< _, Blake2_128Concat, T::CollectionId, @@ -250,7 +250,7 @@ pub mod pallet { /// The items in existence and their ownership details. #[pallet::storage] - pub(super) type Item, I: 'static = ()> = StorageDoubleMap< + pub type Item, I: 'static = ()> = StorageDoubleMap< _, Blake2_128Concat, T::CollectionId, @@ -262,7 +262,7 @@ pub mod pallet { /// Metadata of a collection. #[pallet::storage] - pub(super) type CollectionMetadataOf, I: 'static = ()> = StorageMap< + pub type CollectionMetadataOf, I: 'static = ()> = StorageMap< _, Blake2_128Concat, T::CollectionId, @@ -272,7 +272,7 @@ pub mod pallet { /// Metadata of an item. #[pallet::storage] - pub(super) type ItemMetadataOf, I: 'static = ()> = StorageDoubleMap< + pub type ItemMetadataOf, I: 'static = ()> = StorageDoubleMap< _, Blake2_128Concat, T::CollectionId, @@ -284,7 +284,7 @@ pub mod pallet { /// Attributes of a collection. #[pallet::storage] - pub(super) type Attribute, I: 'static = ()> = StorageNMap< + pub type Attribute, I: 'static = ()> = StorageNMap< _, ( NMapKey, @@ -298,7 +298,7 @@ pub mod pallet { /// A price of an item. #[pallet::storage] - pub(super) type ItemPriceOf, I: 'static = ()> = StorageDoubleMap< + pub type ItemPriceOf, I: 'static = ()> = StorageDoubleMap< _, Blake2_128Concat, T::CollectionId, @@ -310,7 +310,7 @@ pub mod pallet { /// Item attribute approvals. #[pallet::storage] - pub(super) type ItemAttributesApprovalsOf, I: 'static = ()> = StorageDoubleMap< + pub type ItemAttributesApprovalsOf, I: 'static = ()> = StorageDoubleMap< _, Blake2_128Concat, T::CollectionId, @@ -323,12 +323,12 @@ pub mod pallet { /// Stores the `CollectionId` that is going to be used for the next collection. /// This gets incremented whenever a new collection is created. #[pallet::storage] - pub(super) type NextCollectionId, I: 'static = ()> = + pub type NextCollectionId, I: 'static = ()> = StorageValue<_, T::CollectionId, OptionQuery>; /// Handles all the pending swaps. #[pallet::storage] - pub(super) type PendingSwapOf, I: 'static = ()> = StorageDoubleMap< + pub type PendingSwapOf, I: 'static = ()> = StorageDoubleMap< _, Blake2_128Concat, T::CollectionId, @@ -345,12 +345,12 @@ pub mod pallet { /// Config of a collection. #[pallet::storage] - pub(super) type CollectionConfigOf, I: 'static = ()> = + pub type CollectionConfigOf, I: 'static = ()> = StorageMap<_, Blake2_128Concat, T::CollectionId, CollectionConfigFor, OptionQuery>; /// Config of an item. #[pallet::storage] - pub(super) type ItemConfigOf, I: 'static = ()> = StorageDoubleMap< + pub type ItemConfigOf, I: 'static = ()> = StorageDoubleMap< _, Blake2_128Concat, T::CollectionId, From 33eee69bf53d45449c1f6b145afe5da872310b6a Mon Sep 17 00:00:00 2001 From: Jun Jiang Date: Fri, 10 Mar 2023 01:44:26 +0800 Subject: [PATCH 492/715] Add amalgamation traits for NFT CollectionId and ItemId (#13514) * Add amalgamation traits for NFT CollectionId, ItemId, and DestroyWitness * Apply @bkchr suggests * ".git/.scripts/commands/fmt/fmt.sh" --------- Co-authored-by: command-bot <> --- frame/support/src/traits/tokens/nonfungible_v2.rs | 7 +++++-- frame/support/src/traits/tokens/nonfungibles_v2.rs | 8 ++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/frame/support/src/traits/tokens/nonfungible_v2.rs b/frame/support/src/traits/tokens/nonfungible_v2.rs index 175d94324aaa4..c23bf3e4055b1 100644 --- a/frame/support/src/traits/tokens/nonfungible_v2.rs +++ b/frame/support/src/traits/tokens/nonfungible_v2.rs @@ -25,7 +25,10 @@ //! use. use super::nonfungibles_v2 as nonfungibles; -use crate::{dispatch::DispatchResult, traits::Get}; +use crate::{ + dispatch::{DispatchResult, Parameter}, + traits::Get, +}; use codec::{Decode, Encode}; use sp_runtime::TokenError; use sp_std::prelude::*; @@ -33,7 +36,7 @@ use sp_std::prelude::*; /// Trait for providing an interface to a read-only NFT-like item. pub trait Inspect { /// Type for identifying an item. - type ItemId; + type ItemId: Parameter; /// Returns the owner of `item`, or `None` if the item doesn't exist or has no /// owner. diff --git a/frame/support/src/traits/tokens/nonfungibles_v2.rs b/frame/support/src/traits/tokens/nonfungibles_v2.rs index 5deb0c568f431..9d32f29becd4c 100644 --- a/frame/support/src/traits/tokens/nonfungibles_v2.rs +++ b/frame/support/src/traits/tokens/nonfungibles_v2.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::{DispatchError, DispatchResult}; +use crate::dispatch::{DispatchError, DispatchResult, Parameter}; use codec::{Decode, Encode}; use sp_runtime::TokenError; use sp_std::prelude::*; @@ -35,11 +35,11 @@ use sp_std::prelude::*; /// Trait for providing an interface to many read-only NFT-like sets of items. pub trait Inspect { /// Type for identifying an item. - type ItemId; + type ItemId: Parameter; /// Type for identifying a collection (an identifier for an independent collection of /// items). - type CollectionId; + type CollectionId: Parameter; /// Returns the owner of `item` of `collection`, or `None` if the item doesn't exist /// (or somehow has no owner). @@ -193,7 +193,7 @@ pub trait Create: Inspect { /// Trait for providing the ability to destroy collections of nonfungible items. pub trait Destroy: Inspect { /// The witness data needed to destroy an item. - type DestroyWitness; + type DestroyWitness: Parameter; /// Provide the appropriate witness data needed to destroy an item. fn get_destroy_witness(collection: &Self::CollectionId) -> Option; From 0f3b2a2d8d6c7be3d2ff8e846e7556cf65916cdf Mon Sep 17 00:00:00 2001 From: Jun Jiang Date: Fri, 10 Mar 2023 16:44:23 +0800 Subject: [PATCH 493/715] Nfts: Make ItemConfig members pub (#13575) --- frame/nfts/src/types.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/nfts/src/types.rs b/frame/nfts/src/types.rs index 8c43024cdaceb..459aa1cffe0df 100644 --- a/frame/nfts/src/types.rs +++ b/frame/nfts/src/types.rs @@ -399,7 +399,7 @@ impl_codec_bitflags!(ItemSettings, u64, ItemSetting); )] pub struct ItemConfig { /// Item's settings. - pub(super) settings: ItemSettings, + pub settings: ItemSettings, } impl ItemConfig { From 8f9b07445057ab83a057cb61aac56a4a0a671395 Mon Sep 17 00:00:00 2001 From: Jegor Sidorenko <5252494+jsidorenko@users.noreply.github.com> Date: Fri, 10 Mar 2023 11:52:10 +0200 Subject: [PATCH 494/715] Nfts: minor fixes (#13576) * Rename owner_of_item to owned_item * Move AttributeNamespace into the types file --- frame/nfts/src/lib.rs | 10 ++++------ frame/nfts/src/tests.rs | 6 +++--- frame/nfts/src/types.rs | 17 ++++++++++++++++- frame/support/src/traits/tokens.rs | 5 ++--- frame/support/src/traits/tokens/misc.rs | 15 --------------- 5 files changed, 25 insertions(+), 28 deletions(-) diff --git a/frame/nfts/src/lib.rs b/frame/nfts/src/lib.rs index 9314098d3b334..2d19cf0455ad4 100644 --- a/frame/nfts/src/lib.rs +++ b/frame/nfts/src/lib.rs @@ -45,9 +45,7 @@ pub mod weights; use codec::{Decode, Encode}; use frame_support::traits::{ - tokens::{AttributeNamespace, Locker}, - BalanceStatus::Reserved, - Currency, EnsureOriginWithArg, ReservableCurrency, + tokens::Locker, BalanceStatus::Reserved, Currency, EnsureOriginWithArg, ReservableCurrency, }; use frame_system::Config as SystemConfig; use sp_runtime::{ @@ -809,13 +807,13 @@ pub mod pallet { match mint_settings.mint_type { MintType::Issuer => return Err(Error::::NoPermission.into()), MintType::HolderOf(collection_id) => { - let MintWitness { owner_of_item } = + let MintWitness { owned_item } = witness_data.ok_or(Error::::BadWitness)?; let owns_item = Account::::contains_key(( &caller, &collection_id, - &owner_of_item, + &owned_item, )); ensure!(owns_item, Error::::BadWitness); @@ -824,7 +822,7 @@ pub mod pallet { let key = ( &collection_id, - Some(owner_of_item), + Some(owned_item), AttributeNamespace::Pallet, &Self::construct_attribute_key(pallet_attribute.encode())?, ); diff --git a/frame/nfts/src/tests.rs b/frame/nfts/src/tests.rs index 8d937b0f7fe68..e44e4151f84a0 100644 --- a/frame/nfts/src/tests.rs +++ b/frame/nfts/src/tests.rs @@ -335,7 +335,7 @@ fn mint_should_work() { 1, 42, account(2), - Some(MintWitness { owner_of_item: 42 }) + Some(MintWitness { owned_item: 42 }) ), Error::::BadWitness ); @@ -344,7 +344,7 @@ fn mint_should_work() { 1, 42, account(2), - Some(MintWitness { owner_of_item: 43 }) + Some(MintWitness { owned_item: 43 }) )); // can't mint twice @@ -354,7 +354,7 @@ fn mint_should_work() { 1, 46, account(2), - Some(MintWitness { owner_of_item: 43 }) + Some(MintWitness { owned_item: 43 }) ), Error::::AlreadyClaimed ); diff --git a/frame/nfts/src/types.rs b/frame/nfts/src/types.rs index 459aa1cffe0df..f8ab2a355b48b 100644 --- a/frame/nfts/src/types.rs +++ b/frame/nfts/src/types.rs @@ -124,7 +124,7 @@ impl CollectionDetails { #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo)] pub struct MintWitness { /// Provide the id of the item in a required collection. - pub owner_of_item: ItemId, + pub owned_item: ItemId, } /// Information concerning the ownership of a single unique item. @@ -317,6 +317,21 @@ impl Default for MintSettings { + /// An attribute was set by the pallet. + Pallet, + /// An attribute was set by collection's owner. + CollectionOwner, + /// An attribute was set by item's owner. + ItemOwner, + /// An attribute was set by pre-approved account. + Account(AccountId), +} + /// A witness data to cancel attributes approval operation. #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo)] pub struct CancelAttributesApprovalWitness { diff --git a/frame/support/src/traits/tokens.rs b/frame/support/src/traits/tokens.rs index f8dcf68159f1a..e1a96f621bd4f 100644 --- a/frame/support/src/traits/tokens.rs +++ b/frame/support/src/traits/tokens.rs @@ -28,7 +28,6 @@ pub mod nonfungibles; pub mod nonfungibles_v2; pub use imbalance::Imbalance; pub use misc::{ - AssetId, AttributeNamespace, Balance, BalanceConversion, BalanceStatus, ConvertRank, - DepositConsequence, ExistenceRequirement, GetSalary, Locker, WithdrawConsequence, - WithdrawReasons, + AssetId, Balance, BalanceConversion, BalanceStatus, ConvertRank, DepositConsequence, + ExistenceRequirement, GetSalary, Locker, WithdrawConsequence, WithdrawReasons, }; diff --git a/frame/support/src/traits/tokens/misc.rs b/frame/support/src/traits/tokens/misc.rs index eff65f3620a32..6113642c83460 100644 --- a/frame/support/src/traits/tokens/misc.rs +++ b/frame/support/src/traits/tokens/misc.rs @@ -126,21 +126,6 @@ pub enum BalanceStatus { Reserved, } -/// Attribute namespaces for non-fungible tokens. -#[derive( - Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, scale_info::TypeInfo, MaxEncodedLen, -)] -pub enum AttributeNamespace { - /// An attribute was set by the pallet. - Pallet, - /// An attribute was set by collection's owner. - CollectionOwner, - /// An attribute was set by item's owner. - ItemOwner, - /// An attribute was set by pre-approved account. - Account(AccountId), -} - bitflags::bitflags! { /// Reasons for moving funds out of an account. #[derive(Encode, Decode, MaxEncodedLen)] From 9d34fb0cb7985b867116cb946f88d76c4fc481df Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Sat, 11 Mar 2023 13:11:15 +0100 Subject: [PATCH 495/715] Logic for the (Core) Fellowship (#13503) * More drafting * Paymaster pallet * Fix build * More tests * Rename * Rename * Renaming * Revert old changes * Multi-phase payouts to avoid bank-runs * Tests * Tests * Allow payment to be targeted elsewhere * Proper ssync payment failure handling * Test for repayment * Docs * Impl RankedMembers for RankedCollective * Implement Pay for Pot (i.e. basic account). * Benchmarks * Weights * Introduce Salary benchmark into node * Fix warning * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_salary * Update primitives/arithmetic/src/traits.rs Co-authored-by: Jegor Sidorenko <5252494+jsidorenko@users.noreply.github.com> * Update frame/salary/src/lib.rs Co-authored-by: Jegor Sidorenko <5252494+jsidorenko@users.noreply.github.com> * Update lib.rs * Update frame/salary/src/lib.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Docs * Update frame/salary/src/lib.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Update frame/salary/src/lib.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Fix * Fixes * Fixes * Move some salary traits stuff to a shared location * Initial draft * Comment out bits * Fix * First couple of tests * One more test * Update frame/salary/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * Update frame/salary/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * Mul floor * Tests * Mul floor * Fix warnings * Fix test * Tests * Last tests * Docs * Fix warnings * Benchmarks * Weights * Integrate benchmark * Fixes * Fix * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_core_fellowship * Better process flow * Fix benchmarks & tests * Docs * Fixes * Fixes * docs * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_core_fellowship * Docs and allow custom evidence size * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_core_fellowship * Update frame/core-fellowship/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update frame/core-fellowship/src/tests.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update frame/core-fellowship/src/benchmarking.rs * Update frame/core-fellowship/src/benchmarking.rs * Apply suggestions from code review * Rename * Update primitives/arithmetic/src/traits.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Reduce magic numbers * Update frame/core-fellowship/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * Update frame/core-fellowship/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * Benchmark result * Remove dependency * set_params should pay * induct should pay * Remove some other free calls --------- Co-authored-by: command-bot <> Co-authored-by: Jegor Sidorenko <5252494+jsidorenko@users.noreply.github.com> Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> Co-authored-by: Oliver Tale-Yazdi Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- Cargo.lock | 20 + Cargo.toml | 1 + bin/node/runtime/Cargo.toml | 4 + bin/node/runtime/src/lib.rs | 14 + frame/core-fellowship/Cargo.toml | 55 ++ frame/core-fellowship/README.md | 3 + frame/core-fellowship/src/benchmarking.rs | 216 ++++++++ frame/core-fellowship/src/lib.rs | 594 ++++++++++++++++++++++ frame/core-fellowship/src/tests.rs | 362 +++++++++++++ frame/core-fellowship/src/weights.rs | 393 ++++++++++++++ frame/salary/src/lib.rs | 4 +- frame/system/src/lib.rs | 7 +- primitives/arithmetic/src/traits.rs | 32 ++ primitives/runtime/src/traits.rs | 18 + 14 files changed, 1716 insertions(+), 7 deletions(-) create mode 100644 frame/core-fellowship/Cargo.toml create mode 100644 frame/core-fellowship/README.md create mode 100644 frame/core-fellowship/src/benchmarking.rs create mode 100644 frame/core-fellowship/src/lib.rs create mode 100644 frame/core-fellowship/src/tests.rs create mode 100644 frame/core-fellowship/src/weights.rs diff --git a/Cargo.lock b/Cargo.lock index a970be356b2dc..9a63e25b4878c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3522,6 +3522,7 @@ dependencies = [ "pallet-contracts", "pallet-contracts-primitives", "pallet-conviction-voting", + "pallet-core-fellowship", "pallet-democracy", "pallet-election-provider-multi-phase", "pallet-election-provider-support-benchmarking", @@ -5777,6 +5778,25 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-core-fellowship" +version = "4.0.0-dev" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "pallet-ranked-collective", + "pallet-salary", + "parity-scale-codec", + "scale-info", + "sp-arithmetic", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-democracy" version = "4.0.0-dev" diff --git a/Cargo.toml b/Cargo.toml index 0b490bd17c82b..de562ad79e47e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -94,6 +94,7 @@ members = [ "frame/contracts/proc-macro", "frame/contracts/primitives", "frame/conviction-voting", + "frame/core-fellowship", "frame/democracy", "frame/fast-unstake", "frame/try-runtime", diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index a610bbe5d8113..16f1d0a4cb532 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -65,6 +65,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 = "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-core-fellowship = { version = "4.0.0-dev", default-features = false, path = "../../../frame/core-fellowship" } 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 } @@ -148,6 +149,7 @@ std = [ "pallet-contracts/std", "pallet-contracts-primitives/std", "pallet-conviction-voting/std", + "pallet-core-fellowship/std", "pallet-democracy/std", "pallet-elections-phragmen/std", "pallet-fast-unstake/std", @@ -235,6 +237,7 @@ runtime-benchmarks = [ "pallet-collective/runtime-benchmarks", "pallet-contracts/runtime-benchmarks", "pallet-conviction-voting/runtime-benchmarks", + "pallet-core-fellowship/runtime-benchmarks", "pallet-democracy/runtime-benchmarks", "pallet-election-provider-multi-phase/runtime-benchmarks", "pallet-election-provider-support-benchmarking/runtime-benchmarks", @@ -294,6 +297,7 @@ try-runtime = [ "pallet-collective/try-runtime", "pallet-contracts/try-runtime", "pallet-conviction-voting/try-runtime", + "pallet-core-fellowship/try-runtime", "pallet-democracy/try-runtime", "pallet-election-provider-multi-phase/try-runtime", "pallet-elections-phragmen/try-runtime", diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index c507c2d8d752f..614dbc4d958c8 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1574,6 +1574,18 @@ impl pallet_salary::Config for Runtime { type Budget = Budget; } +impl pallet_core_fellowship::Config for Runtime { + type WeightInfo = (); + type RuntimeEvent = RuntimeEvent; + type Members = RankedCollective; + type Balance = Balance; + type ParamsOrigin = frame_system::EnsureRoot; + type InductOrigin = pallet_core_fellowship::EnsureInducted; + type ApproveOrigin = frame_system::EnsureRootWithSuccess>; + type PromoteOrigin = frame_system::EnsureRootWithSuccess>; + type EvidenceSize = ConstU32<16_384>; +} + parameter_types! { pub Features: PalletFeatures = PalletFeatures::all_enabled(); pub const MaxAttributesPerCall: u32 = 10; @@ -1770,6 +1782,7 @@ construct_runtime!( Uniques: pallet_uniques, Nfts: pallet_nfts, Salary: pallet_salary, + CoreFellowship: pallet_core_fellowship, TransactionStorage: pallet_transaction_storage, VoterList: pallet_bags_list::, StateTrieMigration: pallet_state_trie_migration, @@ -1866,6 +1879,7 @@ mod benches { [pallet_collective, Council] [pallet_conviction_voting, ConvictionVoting] [pallet_contracts, Contracts] + [pallet_core_fellowship, CoreFellowship] [pallet_democracy, Democracy] [pallet_election_provider_multi_phase, ElectionProviderMultiPhase] [pallet_election_provider_support_benchmarking, EPSBench::] diff --git a/frame/core-fellowship/Cargo.toml b/frame/core-fellowship/Cargo.toml new file mode 100644 index 0000000000000..2785346c7341f --- /dev/null +++ b/frame/core-fellowship/Cargo.toml @@ -0,0 +1,55 @@ +[package] +name = "pallet-core-fellowship" +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 = "Logic as per the description of The Fellowship for core Polkadot technology" +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 = "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" } + +[dev-dependencies] +pallet-ranked-collective = { version = "4.0.0-dev", default-features = false, path = "../ranked-collective" } +pallet-salary = { version = "4.0.0-dev", default-features = false, path = "../salary" } + +[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", + "pallet-ranked-collective/runtime-benchmarks", + "pallet-salary/runtime-benchmarks", +] +try-runtime = ["frame-support/try-runtime"] diff --git a/frame/core-fellowship/README.md b/frame/core-fellowship/README.md new file mode 100644 index 0000000000000..3c9b1f63e0896 --- /dev/null +++ b/frame/core-fellowship/README.md @@ -0,0 +1,3 @@ +# Core Fellowship + +Logic specific to the core Polkadot Fellowship. \ No newline at end of file diff --git a/frame/core-fellowship/src/benchmarking.rs b/frame/core-fellowship/src/benchmarking.rs new file mode 100644 index 0000000000000..551ec30c19f01 --- /dev/null +++ b/frame/core-fellowship/src/benchmarking.rs @@ -0,0 +1,216 @@ +// 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. + +//! Salary pallet benchmarking. + +#![cfg(feature = "runtime-benchmarks")] + +use super::*; +use crate::Pallet as CoreFellowship; + +use frame_benchmarking::v2::*; +use frame_system::RawOrigin; +use sp_arithmetic::traits::Bounded; + +const SEED: u32 = 0; + +type BenchResult = Result<(), BenchmarkError>; + +#[instance_benchmarks] +mod benchmarks { + use super::*; + + fn ensure_evidence, I: 'static>(who: &T::AccountId) -> BenchResult { + let evidence = BoundedVec::try_from(vec![0; Evidence::::bound()]).unwrap(); + let wish = Wish::Retention; + let origin = RawOrigin::Signed(who.clone()).into(); + CoreFellowship::::submit_evidence(origin, wish, evidence)?; + assert!(MemberEvidence::::contains_key(who)); + Ok(()) + } + + fn make_member, I: 'static>(rank: u16) -> Result { + let member = account("member", 0, SEED); + T::Members::induct(&member)?; + for _ in 0..rank { + T::Members::promote(&member)?; + } + CoreFellowship::::import(RawOrigin::Signed(member.clone()).into())?; + Ok(member) + } + + #[benchmark] + fn set_params() -> Result<(), BenchmarkError> { + let params = ParamsType { + active_salary: [100u32.into(); 9], + passive_salary: [10u32.into(); 9], + demotion_period: [100u32.into(); 9], + min_promotion_period: [100u32.into(); 9], + offboard_timeout: 1u32.into(), + }; + + #[extrinsic_call] + _(RawOrigin::Root, Box::new(params.clone())); + + assert_eq!(Params::::get(), params); + Ok(()) + } + + #[benchmark] + fn bump_offboard() -> Result<(), BenchmarkError> { + let member = make_member::(0)?; + + // Set it to the max value to ensure that any possible auto-demotion period has passed. + frame_system::Pallet::::set_block_number(T::BlockNumber::max_value()); + ensure_evidence::(&member)?; + assert!(Member::::contains_key(&member)); + + #[extrinsic_call] + CoreFellowship::::bump(RawOrigin::Signed(member.clone()), member.clone()); + + assert!(!Member::::contains_key(&member)); + assert!(!MemberEvidence::::contains_key(&member)); + Ok(()) + } + + #[benchmark] + fn bump_demote() -> Result<(), BenchmarkError> { + let member = make_member::(2)?; + + // Set it to the max value to ensure that any possible auto-demotion period has passed. + frame_system::Pallet::::set_block_number(T::BlockNumber::max_value()); + ensure_evidence::(&member)?; + assert!(Member::::contains_key(&member)); + assert_eq!(T::Members::rank_of(&member), Some(2)); + + #[extrinsic_call] + CoreFellowship::::bump(RawOrigin::Signed(member.clone()), member.clone()); + + assert!(Member::::contains_key(&member)); + assert_eq!(T::Members::rank_of(&member), Some(1)); + assert!(!MemberEvidence::::contains_key(&member)); + Ok(()) + } + + #[benchmark] + fn set_active() -> Result<(), BenchmarkError> { + let member = make_member::(1)?; + assert!(Member::::get(&member).unwrap().is_active); + + #[extrinsic_call] + _(RawOrigin::Signed(member.clone()), false); + + assert!(!Member::::get(&member).unwrap().is_active); + Ok(()) + } + + #[benchmark] + fn induct() -> Result<(), BenchmarkError> { + let candidate: T::AccountId = account("candidate", 0, SEED); + + #[extrinsic_call] + _(RawOrigin::Root, candidate.clone()); + + assert_eq!(T::Members::rank_of(&candidate), Some(0)); + assert!(Member::::contains_key(&candidate)); + Ok(()) + } + + #[benchmark] + fn promote() -> Result<(), BenchmarkError> { + let member = make_member::(1)?; + ensure_evidence::(&member)?; + + #[extrinsic_call] + _(RawOrigin::Root, member.clone(), 2u8.into()); + + assert_eq!(T::Members::rank_of(&member), Some(2)); + assert!(!MemberEvidence::::contains_key(&member)); + Ok(()) + } + + #[benchmark] + fn offboard() -> Result<(), BenchmarkError> { + let member = make_member::(0)?; + T::Members::demote(&member)?; + ensure_evidence::(&member)?; + + assert!(T::Members::rank_of(&member).is_none()); + assert!(Member::::contains_key(&member)); + assert!(MemberEvidence::::contains_key(&member)); + + #[extrinsic_call] + _(RawOrigin::Signed(member.clone()), member.clone()); + + assert!(!Member::::contains_key(&member)); + assert!(!MemberEvidence::::contains_key(&member)); + Ok(()) + } + + #[benchmark] + fn import() -> Result<(), BenchmarkError> { + let member = account("member", 0, SEED); + T::Members::induct(&member)?; + T::Members::promote(&member)?; + + assert!(!Member::::contains_key(&member)); + + #[extrinsic_call] + _(RawOrigin::Signed(member.clone())); + + assert!(Member::::contains_key(&member)); + Ok(()) + } + + #[benchmark] + fn approve() -> Result<(), BenchmarkError> { + let member = make_member::(1)?; + let then = frame_system::Pallet::::block_number(); + let now = then.saturating_plus_one(); + frame_system::Pallet::::set_block_number(now); + ensure_evidence::(&member)?; + + assert_eq!(Member::::get(&member).unwrap().last_proof, then); + + #[extrinsic_call] + _(RawOrigin::Root, member.clone(), 1u8.into()); + + assert_eq!(Member::::get(&member).unwrap().last_proof, now); + assert!(!MemberEvidence::::contains_key(&member)); + Ok(()) + } + + #[benchmark] + fn submit_evidence() -> Result<(), BenchmarkError> { + let member = make_member::(1)?; + let evidence = vec![0; Evidence::::bound()].try_into().unwrap(); + + assert!(!MemberEvidence::::contains_key(&member)); + + #[extrinsic_call] + _(RawOrigin::Signed(member.clone()), Wish::Retention, evidence); + + assert!(MemberEvidence::::contains_key(&member)); + Ok(()) + } + + impl_benchmark_test_suite! { + CoreFellowship, + crate::tests::new_test_ext(), + crate::tests::Test, + } +} diff --git a/frame/core-fellowship/src/lib.rs b/frame/core-fellowship/src/lib.rs new file mode 100644 index 0000000000000..6ba60dbaf2559 --- /dev/null +++ b/frame/core-fellowship/src/lib.rs @@ -0,0 +1,594 @@ +// 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. + +//! Additional logic for the Core Fellowship. This determines salary, registers activity/passivity +//! and handles promotion and demotion periods. +//! +//! This only handles members of non-zero rank. +//! +//! # Process Flow +//! - Begin with a call to `induct`, where some privileged origin (perhaps a pre-existing member of +//! `rank > 1`) is able to make a candidate from an account and introduce it to be tracked in this +//! pallet in order to allow evidence to be submitted and promotion voted on. +//! - The candidate then calls `submit_evidence` to apply for their promotion to rank 1. +//! - A `PromoteOrigin` of at least rank 1 calls `promote` on the candidate to elevate it to rank 1. +//! - Some time later but before rank 1's `demotion_period` elapses, candidate calls +//! `submit_evidence` with evidence of their efforts to apply for approval to stay at rank 1. +//! - An `ApproveOrigin` of at least rank 1 calls `approve` on the candidate to avoid imminent +//! demotion and keep it at rank 1. +//! - These last two steps continue until the candidate is ready to apply for a promotion, at which +//! point the previous two steps are repeated with a higher rank. +//! - If the member fails to get an approval within the `demotion_period` then anyone may call +//! `bump` to demote the candidate by one rank. +//! - If a candidate fails to be promoted to a member within the `offboard_timeout` period, then +//! anyone may call `bump` to remove the account's candidacy. +//! - Pre-existing members may call `import` to have their rank recognised and be inducted into this +//! pallet (to gain a salary and allow for eventual promotion). +//! - If, externally to this pallet, a member or candidate has their rank removed completely, then +//! `offboard` may be called to remove them entirely from this pallet. +//! +//! Note there is a difference between having a rank of 0 (whereby the account is a *candidate*) and +//! having no rank at all (whereby we consider it *unranked*). An account can be demoted from rank +//! 0 to become unranked. This process is called being offboarded and there is an extrinsic to do +//! this explicitly when external factors to this pallet have caused the tracked account to become +//! unranked. At rank 0, there is not a "demotion" period after which the account may be bumped to +//! become offboarded but rather an "offboard timeout". +//! +//! Candidates may be introduced (i.e. an account to go from unranked to rank of 0) by an origin +//! of a different privilege to that for promotion. This allows the possibility for even a single +//! existing member to introduce a new candidate without payment. +//! +//! Only tracked/ranked accounts may submit evidence for their proof and promotion. Candidates +//! cannot be approved - they must proceed only to promotion prior to the offboard timeout elapsing. + +#![cfg_attr(not(feature = "std"), no_std)] +#![recursion_limit = "128"] + +use codec::{Decode, Encode, MaxEncodedLen}; +use scale_info::TypeInfo; +use sp_arithmetic::traits::{Saturating, Zero}; +use sp_std::{marker::PhantomData, prelude::*}; + +use frame_support::{ + dispatch::DispatchResultWithPostInfo, + ensure, + traits::{tokens::Balance as BalanceTrait, EnsureOrigin, Get, RankedMembers}, + BoundedVec, RuntimeDebug, +}; + +#[cfg(test)] +mod tests; + +#[cfg(feature = "runtime-benchmarks")] +mod benchmarking; +pub mod weights; + +pub use pallet::*; +pub use weights::WeightInfo; + +/// The desired outcome for which evidence is presented. +#[derive(Encode, Decode, Eq, PartialEq, Copy, Clone, TypeInfo, MaxEncodedLen, RuntimeDebug)] +pub enum Wish { + /// Member wishes only to retain their current rank. + Retention, + /// Member wishes to be promoted. + Promotion, +} + +/// A piece of evidence to underpin a [Wish]. +/// +/// From the pallet's perspective, this is just a blob of data without meaning. The fellows can +/// decide how to concretely utilise it. This could be an IPFS hash, a URL or structured data. +pub type Evidence = BoundedVec>::EvidenceSize>; + +/// The status of the pallet instance. +#[derive(Encode, Decode, Eq, PartialEq, Clone, TypeInfo, MaxEncodedLen, RuntimeDebug)] +pub struct ParamsType { + /// The amounts to be paid when a member of a given rank (-1) is active. + active_salary: [Balance; RANKS], + /// The amounts to be paid when a member of a given rank (-1) is passive. + passive_salary: [Balance; RANKS], + /// The period between which unproven members become demoted. + demotion_period: [BlockNumber; RANKS], + /// The period between which members must wait before they may proceed to this rank. + min_promotion_period: [BlockNumber; RANKS], + /// Amount by which an account can remain at rank 0 (candidate before being offboard entirely). + offboard_timeout: BlockNumber, +} + +impl Default + for ParamsType +{ + fn default() -> Self { + Self { + active_salary: [Balance::default(); RANKS], + passive_salary: [Balance::default(); RANKS], + demotion_period: [BlockNumber::default(); RANKS], + min_promotion_period: [BlockNumber::default(); RANKS], + offboard_timeout: BlockNumber::default(), + } + } +} + +/// The status of a single member. +#[derive(Encode, Decode, Eq, PartialEq, Clone, TypeInfo, MaxEncodedLen, RuntimeDebug)] +pub struct MemberStatus { + /// Are they currently active? + is_active: bool, + /// The block number at which we last promoted them. + last_promotion: BlockNumber, + /// The last time a member was demoted, promoted or proved their rank. + last_proof: BlockNumber, +} + +#[frame_support::pallet] +pub mod pallet { + use super::*; + use frame_support::{ + dispatch::Pays, + pallet_prelude::*, + traits::{tokens::GetSalary, EnsureOrigin}, + }; + use frame_system::{ensure_root, pallet_prelude::*}; + + const RANK_COUNT: usize = 9; + + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + 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 runtime event type. + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; + + /// The current membership of the fellowship. + type Members: RankedMembers< + AccountId = ::AccountId, + Rank = u16, + >; + + /// The type in which salaries/budgets are measured. + type Balance: BalanceTrait; + + /// The origin which has permission update the parameters. + type ParamsOrigin: EnsureOrigin; + + /// The origin which has permission to move a candidate into being tracked in this pallet. + /// Generally a very low-permission, such as a pre-existing member of rank 1 or above. + /// + /// This allows the candidate to deposit evidence for their request to be promoted to a + /// member. + type InductOrigin: EnsureOrigin; + + /// The origin which has permission to issue a proof that a member may retain their rank. + /// The `Success` value is the maximum rank of members it is able to prove. + type ApproveOrigin: EnsureOrigin>; + + /// The origin which has permission to promote a member. The `Success` value is the maximum + /// rank to which it can promote. + type PromoteOrigin: EnsureOrigin>; + + /// The maximum size in bytes submitted evidence is allowed to be. + #[pallet::constant] + type EvidenceSize: Get; + } + + pub type ParamsOf = + ParamsType<>::Balance, ::BlockNumber, RANK_COUNT>; + pub type MemberStatusOf = MemberStatus<::BlockNumber>; + pub type RankOf = <>::Members as RankedMembers>::Rank; + + /// The overall status of the system. + #[pallet::storage] + pub(super) type Params, I: 'static = ()> = + StorageValue<_, ParamsOf, ValueQuery>; + + /// The status of a claimant. + #[pallet::storage] + pub(super) type Member, I: 'static = ()> = + StorageMap<_, Twox64Concat, T::AccountId, MemberStatusOf, OptionQuery>; + + /// Some evidence together with the desired outcome for which it was presented. + #[pallet::storage] + pub(super) type MemberEvidence, I: 'static = ()> = + StorageMap<_, Twox64Concat, T::AccountId, (Wish, Evidence), OptionQuery>; + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event, I: 'static = ()> { + /// Parameters for the pallet have changed. + ParamsChanged { params: ParamsOf }, + /// Member activity flag has been set. + ActiveChanged { who: T::AccountId, is_active: bool }, + /// Member has begun being tracked in this pallet. + Inducted { who: T::AccountId }, + /// Member has been removed from being tracked in this pallet (i.e. because rank is now + /// zero). + Offboarded { who: T::AccountId }, + /// Member has been promoted to the given rank. + Promoted { who: T::AccountId, to_rank: RankOf }, + /// Member has been demoted to the given (non-zero) rank. + Demoted { who: T::AccountId, to_rank: RankOf }, + /// Member has been proven at their current rank, postponing auto-demotion. + Proven { who: T::AccountId, at_rank: RankOf }, + /// Member has stated evidence of their efforts their request for rank. + Requested { who: T::AccountId, wish: Wish }, + /// Some submitted evidence was judged and removed. There may or may not have been a change + /// to the rank, but in any case, `last_proof` is reset. + EvidenceJudged { + /// The member/candidate. + who: T::AccountId, + /// The desired outcome for which the evidence was presented. + wish: Wish, + /// The evidence of efforts. + evidence: Evidence, + /// The old rank, prior to this change. + old_rank: u16, + /// New rank. If `None` then candidate record was removed entirely. + new_rank: Option, + }, + /// Pre-ranked account has been inducted at their current rank. + Imported { who: T::AccountId, rank: RankOf }, + } + + #[pallet::error] + pub enum Error { + /// Member's rank is too low. + Unranked, + /// Member's rank is not zero. + Ranked, + /// Member's rank is not as expected - generally means that the rank provided to the call + /// does not agree with the state of the system. + UnexpectedRank, + /// The given rank is invalid - this generally means it's not between 1 and `RANK_COUNT`. + InvalidRank, + /// The origin does not have enough permission to do this operation. + NoPermission, + /// No work needs to be done at present for this member. + NothingDoing, + /// The candidate has already been inducted. This should never happen since it would + /// require a candidate (rank 0) to already be tracked in the pallet. + AlreadyInducted, + /// The candidate has not been inducted, so cannot be offboarded from this pallet. + NotTracked, + /// Operation cannot be done yet since not enough time has passed. + TooSoon, + } + + #[pallet::call] + impl, I: 'static> Pallet { + /// Bump the state of a member. + /// + /// This will demote a member whose `last_proof` is now beyond their rank's + /// `demotion_period`. + /// + /// - `origin`: A `Signed` origin of an account. + /// - `who`: A member account whose state is to be updated. + #[pallet::weight(T::WeightInfo::bump_offboard().max(T::WeightInfo::bump_demote()))] + #[pallet::call_index(0)] + pub fn bump(origin: OriginFor, who: T::AccountId) -> DispatchResultWithPostInfo { + let _ = ensure_signed(origin)?; + let mut member = Member::::get(&who).ok_or(Error::::NotTracked)?; + let rank = T::Members::rank_of(&who).ok_or(Error::::Unranked)?; + + let params = Params::::get(); + let demotion_period = if rank == 0 { + params.offboard_timeout + } else { + let rank_index = Self::rank_to_index(rank).ok_or(Error::::InvalidRank)?; + params.demotion_period[rank_index] + }; + let demotion_block = member.last_proof.saturating_add(demotion_period); + + // Ensure enough time has passed. + let now = frame_system::Pallet::::block_number(); + if now >= demotion_block { + T::Members::demote(&who)?; + let maybe_to_rank = T::Members::rank_of(&who); + Self::dispose_evidence(who.clone(), rank, maybe_to_rank); + let event = if let Some(to_rank) = maybe_to_rank { + member.last_proof = now; + Member::::insert(&who, &member); + Event::::Demoted { who, to_rank } + } else { + Member::::remove(&who); + Event::::Offboarded { who } + }; + Self::deposit_event(event); + return Ok(Pays::No.into()) + } + + Err(Error::::NothingDoing.into()) + } + + /// Set the parameters. + /// + /// - `origin`: A origin complying with `ParamsOrigin` or root. + /// - `params`: The new parameters for the pallet. + #[pallet::weight(T::WeightInfo::set_params())] + #[pallet::call_index(1)] + pub fn set_params(origin: OriginFor, params: Box>) -> DispatchResult { + T::ParamsOrigin::try_origin(origin).map(|_| ()).or_else(|o| ensure_root(o))?; + Params::::put(params.as_ref()); + Self::deposit_event(Event::::ParamsChanged { params: *params }); + Ok(()) + } + + /// Set whether a member is active or not. + /// + /// - `origin`: A `Signed` origin of a member's account. + /// - `is_active`: `true` iff the member is active. + #[pallet::weight(T::WeightInfo::set_active())] + #[pallet::call_index(2)] + pub fn set_active(origin: OriginFor, is_active: bool) -> DispatchResult { + let who = ensure_signed(origin)?; + ensure!( + T::Members::rank_of(&who).map_or(false, |r| !r.is_zero()), + Error::::Unranked + ); + let mut member = Member::::get(&who).ok_or(Error::::NotTracked)?; + member.is_active = is_active; + Member::::insert(&who, &member); + Self::deposit_event(Event::::ActiveChanged { who, is_active }); + Ok(()) + } + + /// Approve a member to continue at their rank. + /// + /// This resets `last_proof` to the current block, thereby delaying any automatic demotion. + /// + /// If `who` is not already tracked by this pallet, then it will become tracked. + /// `last_promotion` will be set to zero. + /// + /// - `origin`: An origin which satisfies `ApproveOrigin` or root. + /// - `who`: A member (i.e. of non-zero rank). + /// - `at_rank`: The rank of member. + #[pallet::weight(T::WeightInfo::approve())] + #[pallet::call_index(3)] + pub fn approve( + origin: OriginFor, + who: T::AccountId, + at_rank: RankOf, + ) -> DispatchResult { + match T::PromoteOrigin::try_origin(origin) { + Ok(allow_rank) => ensure!(allow_rank >= at_rank, Error::::NoPermission), + Err(origin) => ensure_root(origin)?, + } + ensure!(at_rank > 0, Error::::InvalidRank); + let rank = T::Members::rank_of(&who).ok_or(Error::::Unranked)?; + ensure!(rank == at_rank, Error::::UnexpectedRank); + let mut member = Member::::get(&who).ok_or(Error::::NotTracked)?; + + member.last_proof = frame_system::Pallet::::block_number(); + Member::::insert(&who, &member); + + Self::dispose_evidence(who.clone(), at_rank, Some(at_rank)); + Self::deposit_event(Event::::Proven { who, at_rank }); + + Ok(()) + } + + /// Introduce a new and unranked candidate (rank zero). + /// + /// - `origin`: An origin which satisfies `InductOrigin` or root. + /// - `who`: The account ID of the candidate to be inducted and become a member. + #[pallet::weight(T::WeightInfo::induct())] + #[pallet::call_index(4)] + pub fn induct(origin: OriginFor, who: T::AccountId) -> DispatchResult { + match T::InductOrigin::try_origin(origin) { + Ok(_) => {}, + Err(origin) => ensure_root(origin)?, + } + ensure!(!Member::::contains_key(&who), Error::::AlreadyInducted); + ensure!(T::Members::rank_of(&who).is_none(), Error::::Ranked); + + T::Members::induct(&who)?; + let now = frame_system::Pallet::::block_number(); + Member::::insert( + &who, + MemberStatus { is_active: true, last_promotion: now, last_proof: now }, + ); + Self::deposit_event(Event::::Inducted { who }); + Ok(()) + } + + /// Increment the rank of a ranked and tracked account. + /// + /// - `origin`: An origin which satisfies `PromoteOrigin` with a `Success` result of + /// `to_rank` or more or root. + /// - `who`: The account ID of the member to be promoted to `to_rank`. + /// - `to_rank`: One more than the current rank of `who`. + #[pallet::weight(T::WeightInfo::promote())] + #[pallet::call_index(5)] + pub fn promote( + origin: OriginFor, + who: T::AccountId, + to_rank: RankOf, + ) -> DispatchResult { + match T::PromoteOrigin::try_origin(origin) { + Ok(allow_rank) => ensure!(allow_rank >= to_rank, Error::::NoPermission), + Err(origin) => ensure_root(origin)?, + } + let rank = T::Members::rank_of(&who).ok_or(Error::::Unranked)?; + ensure!( + rank.checked_add(1).map_or(false, |i| i == to_rank), + Error::::UnexpectedRank + ); + + let mut member = Member::::get(&who).ok_or(Error::::NotTracked)?; + let now = frame_system::Pallet::::block_number(); + + let params = Params::::get(); + let rank_index = Self::rank_to_index(to_rank).ok_or(Error::::InvalidRank)?; + let min_period = params.min_promotion_period[rank_index]; + // Ensure enough time has passed. + ensure!( + member.last_promotion.saturating_add(min_period) <= now, + Error::::TooSoon, + ); + + T::Members::promote(&who)?; + member.last_promotion = now; + member.last_proof = now; + Member::::insert(&who, &member); + Self::dispose_evidence(who.clone(), rank, Some(to_rank)); + + Self::deposit_event(Event::::Promoted { who, to_rank }); + + Ok(()) + } + + /// Stop tracking a prior member who is now not a ranked member of the collective. + /// + /// - `origin`: A `Signed` origin of an account. + /// - `who`: The ID of an account which was tracked in this pallet but which is now not a + /// ranked member of the collective. + #[pallet::weight(T::WeightInfo::offboard())] + #[pallet::call_index(6)] + pub fn offboard(origin: OriginFor, who: T::AccountId) -> DispatchResultWithPostInfo { + let _ = ensure_signed(origin)?; + ensure!(T::Members::rank_of(&who).is_none(), Error::::Ranked); + ensure!(Member::::contains_key(&who), Error::::NotTracked); + Member::::remove(&who); + MemberEvidence::::remove(&who); + Self::deposit_event(Event::::Offboarded { who }); + Ok(Pays::No.into()) + } + + /// Provide evidence that a rank is deserved. + /// + /// This is free as long as no evidence for the forthcoming judgement is already submitted. + /// Evidence is cleared after an outcome (either demotion, promotion of approval). + /// + /// - `origin`: A `Signed` origin of an inducted and ranked account. + /// - `wish`: The stated desire of the member. + /// - `evidence`: A dump of evidence to be considered. This should generally be either a + /// Markdown-encoded document or a series of 32-byte hashes which can be found on a + /// decentralised content-based-indexing system such as IPFS. + #[pallet::weight(T::WeightInfo::submit_evidence())] + #[pallet::call_index(7)] + pub fn submit_evidence( + origin: OriginFor, + wish: Wish, + evidence: Evidence, + ) -> DispatchResultWithPostInfo { + let who = ensure_signed(origin)?; + ensure!(Member::::contains_key(&who), Error::::NotTracked); + let replaced = MemberEvidence::::contains_key(&who); + MemberEvidence::::insert(&who, (wish, evidence)); + Self::deposit_event(Event::::Requested { who, wish }); + Ok(if replaced { Pays::Yes } else { Pays::No }.into()) + } + + /// Introduce an already-ranked individual of the collective into this pallet. The rank may + /// still be zero. + /// + /// This resets `last_proof` to the current block and `last_promotion` will be set to zero, + /// thereby delaying any automatic demotion but allowing immediate promotion. + /// + /// - `origin`: A signed origin of a ranked, but not tracked, account. + #[pallet::weight(T::WeightInfo::import())] + #[pallet::call_index(8)] + pub fn import(origin: OriginFor) -> DispatchResultWithPostInfo { + let who = ensure_signed(origin)?; + ensure!(!Member::::contains_key(&who), Error::::AlreadyInducted); + let rank = T::Members::rank_of(&who).ok_or(Error::::Unranked)?; + + let now = frame_system::Pallet::::block_number(); + Member::::insert( + &who, + MemberStatus { is_active: true, last_promotion: 0u32.into(), last_proof: now }, + ); + Self::deposit_event(Event::::Imported { who, rank }); + + Ok(Pays::No.into()) + } + } + + impl, I: 'static> Pallet { + /// Convert a rank into a `0..RANK_COUNT` index suitable for the arrays in Params. + /// + /// Rank 1 becomes index 0, rank `RANK_COUNT` becomes index `RANK_COUNT - 1`. Any rank not + /// in the range `1..=RANK_COUNT` is `None`. + pub(crate) fn rank_to_index(rank: RankOf) -> Option { + match TryInto::::try_into(rank) { + Ok(r) if r <= RANK_COUNT && r > 0 => Some(r - 1), + _ => return None, + } + } + + fn dispose_evidence(who: T::AccountId, old_rank: u16, new_rank: Option) { + if let Some((wish, evidence)) = MemberEvidence::::take(&who) { + let e = Event::::EvidenceJudged { who, wish, evidence, old_rank, new_rank }; + Self::deposit_event(e); + } + } + } + + impl, I: 'static> GetSalary, T::AccountId, T::Balance> for Pallet { + fn get_salary(rank: RankOf, who: &T::AccountId) -> T::Balance { + let index = match Self::rank_to_index(rank) { + Some(i) => i, + None => return Zero::zero(), + }; + let member = match Member::::get(who) { + Some(m) => m, + None => return Zero::zero(), + }; + let params = Params::::get(); + let salary = + if member.is_active { params.active_salary } else { params.passive_salary }; + salary[index] + } + } +} + +/// Guard to ensure that the given origin is inducted into this pallet with a given minimum rank. +/// The account ID of the member is the `Success` value. +pub struct EnsureInducted(PhantomData<(T, I)>); +impl, I: 'static, const MIN_RANK: u16> EnsureOrigin + for EnsureInducted +{ + type Success = T::AccountId; + + fn try_origin(o: T::RuntimeOrigin) -> Result { + let who = frame_system::EnsureSigned::try_origin(o)?; + match T::Members::rank_of(&who) { + Some(rank) if rank >= MIN_RANK && Member::::contains_key(&who) => Ok(who), + _ => Err(frame_system::RawOrigin::Signed(who).into()), + } + } + + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin() -> Result { + let who = frame_benchmarking::account::("successful_origin", 0, 0); + if T::Members::rank_of(&who).is_none() { + T::Members::induct(&who).map_err(|_| ())?; + } + for _ in 0..MIN_RANK { + if T::Members::rank_of(&who).ok_or(())? < MIN_RANK { + T::Members::promote(&who).map_err(|_| ())?; + } + } + Ok(frame_system::RawOrigin::Signed(who).into()) + } +} diff --git a/frame/core-fellowship/src/tests.rs b/frame/core-fellowship/src/tests.rs new file mode 100644 index 0000000000000..87c0de112ac33 --- /dev/null +++ b/frame/core-fellowship/src/tests.rs @@ -0,0 +1,362 @@ +// 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, ord_parameter_types, + pallet_prelude::Weight, + parameter_types, + traits::{tokens::GetSalary, ConstU32, ConstU64, Everything, IsInVec, TryMapSuccess}, +}; +use frame_system::EnsureSignedBy; +use sp_core::H256; +use sp_runtime::{ + testing::Header, + traits::{BlakeTwo256, IdentityLookup, TryMorphInto}, + DispatchError, DispatchResult, +}; +use sp_std::cell::RefCell; + +use super::*; +use crate as pallet_core_fellowship; + +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}, + CoreFellowship: pallet_core_fellowship::{Pallet, Call, Storage, Event}, + } +); + +parameter_types! { + pub BlockWeights: frame_system::limits::BlockWeights = + frame_system::limits::BlockWeights::simple_max(Weight::from_parts(1_000_000, u64::max_value())); +} +impl frame_system::Config for Test { + type BaseCallFilter = Everything; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type RuntimeOrigin = RuntimeOrigin; + type Index = u64; + type BlockNumber = u64; + type RuntimeCall = RuntimeCall; + type Hash = H256; + 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>; +} + +thread_local! { + pub static CLUB: RefCell> = RefCell::new(BTreeMap::new()); +} + +pub struct TestClub; +impl RankedMembers for TestClub { + type AccountId = u64; + type Rank = u16; + fn min_rank() -> Self::Rank { + 0 + } + fn rank_of(who: &Self::AccountId) -> Option { + CLUB.with(|club| club.borrow().get(who).cloned()) + } + fn induct(who: &Self::AccountId) -> DispatchResult { + CLUB.with(|club| club.borrow_mut().insert(*who, 0)); + Ok(()) + } + fn promote(who: &Self::AccountId) -> DispatchResult { + CLUB.with(|club| { + club.borrow_mut().entry(*who).and_modify(|r| *r += 1); + }); + Ok(()) + } + fn demote(who: &Self::AccountId) -> DispatchResult { + CLUB.with(|club| match Self::rank_of(who) { + None => Err(sp_runtime::DispatchError::Unavailable), + Some(0) => { + club.borrow_mut().remove(&who); + Ok(()) + }, + Some(_) => { + club.borrow_mut().entry(*who).and_modify(|x| *x -= 1); + Ok(()) + }, + }) + } +} + +fn set_rank(who: u64, rank: u16) { + CLUB.with(|club| club.borrow_mut().insert(who, rank)); +} + +fn unrank(who: u64) { + CLUB.with(|club| club.borrow_mut().remove(&who)); +} + +parameter_types! { + pub ZeroToNine: Vec = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; +} +ord_parameter_types! { + pub const One: u64 = 1; +} + +impl Config for Test { + type WeightInfo = (); + type RuntimeEvent = RuntimeEvent; + type Members = TestClub; + type Balance = u64; + type ParamsOrigin = EnsureSignedBy; + type InductOrigin = EnsureInducted; + type ApproveOrigin = TryMapSuccess, u64>, TryMorphInto>; + type PromoteOrigin = TryMapSuccess, u64>, TryMorphInto>; + type EvidenceSize = ConstU32<1024>; +} + +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(|| { + let params = ParamsType { + active_salary: [10, 20, 30, 40, 50, 60, 70, 80, 90], + passive_salary: [1, 2, 3, 4, 5, 6, 7, 8, 9], + demotion_period: [2, 4, 6, 8, 10, 12, 14, 16, 18], + min_promotion_period: [3, 6, 9, 12, 15, 18, 21, 24, 27], + offboard_timeout: 1, + }; + assert_ok!(CoreFellowship::set_params(signed(1), Box::new(params))); + System::set_block_number(1); + }); + ext +} + +fn next_block() { + System::set_block_number(System::block_number() + 1); +} + +fn run_to(n: u64) { + while System::block_number() < n { + next_block(); + } +} + +fn signed(who: u64) -> RuntimeOrigin { + RuntimeOrigin::signed(who) +} + +fn next_demotion(who: u64) -> u64 { + let member = Member::::get(who).unwrap(); + let demotion_period = Params::::get().demotion_period; + member.last_proof + demotion_period[TestClub::rank_of(&who).unwrap() as usize - 1] +} + +#[test] +fn basic_stuff() { + new_test_ext().execute_with(|| { + assert_eq!(CoreFellowship::rank_to_index(0), None); + assert_eq!(CoreFellowship::rank_to_index(1), Some(0)); + assert_eq!(CoreFellowship::rank_to_index(9), Some(8)); + assert_eq!(CoreFellowship::rank_to_index(10), None); + assert_eq!(CoreFellowship::get_salary(0, &1), 0); + }); +} + +#[test] +fn set_params_works() { + new_test_ext().execute_with(|| { + let params = ParamsType { + active_salary: [10, 20, 30, 40, 50, 60, 70, 80, 90], + passive_salary: [1, 2, 3, 4, 5, 6, 7, 8, 9], + demotion_period: [1, 2, 3, 4, 5, 6, 7, 8, 9], + min_promotion_period: [1, 2, 3, 4, 5, 10, 15, 20, 30], + offboard_timeout: 1, + }; + assert_noop!( + CoreFellowship::set_params(signed(2), Box::new(params.clone())), + DispatchError::BadOrigin + ); + assert_ok!(CoreFellowship::set_params(signed(1), Box::new(params))); + }); +} + +#[test] +fn induct_works() { + new_test_ext().execute_with(|| { + set_rank(0, 0); + assert_ok!(CoreFellowship::import(signed(0))); + set_rank(1, 1); + assert_ok!(CoreFellowship::import(signed(1))); + + assert_noop!(CoreFellowship::induct(signed(10), 10), DispatchError::BadOrigin); + assert_noop!(CoreFellowship::induct(signed(0), 10), DispatchError::BadOrigin); + assert_ok!(CoreFellowship::induct(signed(1), 10)); + assert_noop!(CoreFellowship::induct(signed(1), 10), Error::::AlreadyInducted); + }); +} + +#[test] +fn promote_works() { + new_test_ext().execute_with(|| { + set_rank(1, 1); + assert_ok!(CoreFellowship::import(signed(1))); + assert_noop!(CoreFellowship::promote(signed(1), 10, 1), Error::::Unranked); + + assert_ok!(CoreFellowship::induct(signed(1), 10)); + assert_noop!(CoreFellowship::promote(signed(10), 10, 1), DispatchError::BadOrigin); + assert_noop!(CoreFellowship::promote(signed(0), 10, 1), Error::::NoPermission); + assert_noop!(CoreFellowship::promote(signed(3), 10, 2), Error::::UnexpectedRank); + run_to(3); + assert_noop!(CoreFellowship::promote(signed(1), 10, 1), Error::::TooSoon); + run_to(4); + assert_ok!(CoreFellowship::promote(signed(1), 10, 1)); + set_rank(11, 0); + assert_noop!(CoreFellowship::promote(signed(1), 11, 1), Error::::NotTracked); + }); +} + +#[test] +fn sync_works() { + new_test_ext().execute_with(|| { + set_rank(10, 5); + assert_noop!(CoreFellowship::approve(signed(4), 10, 5), Error::::NoPermission); + assert_noop!(CoreFellowship::approve(signed(6), 10, 6), Error::::UnexpectedRank); + assert_ok!(CoreFellowship::import(signed(10))); + assert!(Member::::contains_key(10)); + assert_eq!(next_demotion(10), 11); + }); +} + +#[test] +fn auto_demote_works() { + new_test_ext().execute_with(|| { + set_rank(10, 5); + assert_ok!(CoreFellowship::import(signed(10))); + + run_to(10); + assert_noop!(CoreFellowship::bump(signed(0), 10), Error::::NothingDoing); + run_to(11); + assert_ok!(CoreFellowship::bump(signed(0), 10)); + assert_eq!(TestClub::rank_of(&10), Some(4)); + assert_noop!(CoreFellowship::bump(signed(0), 10), Error::::NothingDoing); + assert_eq!(next_demotion(10), 19); + }); +} + +#[test] +fn auto_demote_offboard_works() { + new_test_ext().execute_with(|| { + set_rank(10, 1); + assert_ok!(CoreFellowship::import(signed(10))); + + run_to(3); + assert_ok!(CoreFellowship::bump(signed(0), 10)); + assert_eq!(TestClub::rank_of(&10), Some(0)); + assert_noop!(CoreFellowship::bump(signed(0), 10), Error::::NothingDoing); + run_to(4); + assert_ok!(CoreFellowship::bump(signed(0), 10)); + assert_noop!(CoreFellowship::bump(signed(0), 10), Error::::NotTracked); + }); +} + +#[test] +fn offboard_works() { + new_test_ext().execute_with(|| { + assert_noop!(CoreFellowship::offboard(signed(0), 10), Error::::NotTracked); + set_rank(10, 0); + assert_noop!(CoreFellowship::offboard(signed(0), 10), Error::::Ranked); + + assert_ok!(CoreFellowship::import(signed(10))); + assert_noop!(CoreFellowship::offboard(signed(0), 10), Error::::Ranked); + + unrank(10); + assert_ok!(CoreFellowship::offboard(signed(0), 10)); + assert_noop!(CoreFellowship::offboard(signed(0), 10), Error::::NotTracked); + assert_noop!(CoreFellowship::bump(signed(0), 10), Error::::NotTracked); + }); +} + +#[test] +fn proof_postpones_auto_demote() { + new_test_ext().execute_with(|| { + set_rank(10, 5); + assert_ok!(CoreFellowship::import(signed(10))); + + run_to(11); + assert_ok!(CoreFellowship::approve(signed(5), 10, 5)); + assert_eq!(next_demotion(10), 21); + assert_noop!(CoreFellowship::bump(signed(0), 10), Error::::NothingDoing); + }); +} + +#[test] +fn promote_postpones_auto_demote() { + new_test_ext().execute_with(|| { + set_rank(10, 5); + assert_ok!(CoreFellowship::import(signed(10))); + + run_to(19); + assert_ok!(CoreFellowship::promote(signed(6), 10, 6)); + assert_eq!(next_demotion(10), 31); + assert_noop!(CoreFellowship::bump(signed(0), 10), Error::::NothingDoing); + }); +} + +#[test] +fn get_salary_works() { + new_test_ext().execute_with(|| { + for i in 1..=9u64 { + set_rank(10 + i, i as u16); + assert_ok!(CoreFellowship::import(signed(10 + i))); + assert_eq!(CoreFellowship::get_salary(i as u16, &(10 + i)), i * 10); + } + }); +} + +#[test] +fn active_changing_get_salary_works() { + new_test_ext().execute_with(|| { + for i in 1..=9u64 { + set_rank(10 + i, i as u16); + assert_ok!(CoreFellowship::import(signed(10 + i))); + assert_ok!(CoreFellowship::set_active(signed(10 + i), false)); + assert_eq!(CoreFellowship::get_salary(i as u16, &(10 + i)), i); + assert_ok!(CoreFellowship::set_active(signed(10 + i), true)); + assert_eq!(CoreFellowship::get_salary(i as u16, &(10 + i)), i * 10); + } + }); +} diff --git a/frame/core-fellowship/src/weights.rs b/frame/core-fellowship/src/weights.rs new file mode 100644 index 0000000000000..9f290635ec1cf --- /dev/null +++ b/frame/core-fellowship/src/weights.rs @@ -0,0 +1,393 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for pallet_core_fellowship +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-03-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 + +// Executed Command: +// target/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_core_fellowship +// --chain=dev +// --header=./HEADER-APACHE2 +// --output=./frame/core-fellowship/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_core_fellowship. +pub trait WeightInfo { + fn set_params() -> Weight; + fn bump_offboard() -> Weight; + fn bump_demote() -> Weight; + fn set_active() -> Weight; + fn induct() -> Weight; + fn promote() -> Weight; + fn offboard() -> Weight; + fn import() -> Weight; + fn approve() -> Weight; + fn submit_evidence() -> Weight; +} + +/// Weights for pallet_core_fellowship using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + /// Storage: CoreFellowship Params (r:0 w:1) + /// Proof: CoreFellowship Params (max_values: Some(1), max_size: Some(364), added: 859, mode: MaxEncodedLen) + fn set_params() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 10_489_000 picoseconds. + Weight::from_parts(10_873_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: CoreFellowship Member (r:1 w:1) + /// Proof: CoreFellowship Member (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: RankedCollective Members (r:1 w:1) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: CoreFellowship Params (r:1 w:0) + /// Proof: CoreFellowship Params (max_values: Some(1), max_size: Some(364), added: 859, mode: MaxEncodedLen) + /// Storage: RankedCollective MemberCount (r:1 w:1) + /// Proof: RankedCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: RankedCollective IdToIndex (r:1 w:0) + /// Proof: RankedCollective IdToIndex (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) + /// Storage: CoreFellowship MemberEvidence (r:1 w:1) + /// Proof: CoreFellowship MemberEvidence (max_values: None, max_size: Some(16429), added: 18904, mode: MaxEncodedLen) + fn bump_offboard() -> Weight { + // Proof Size summary in bytes: + // Measured: `16886` + // Estimated: `35762` + // Minimum execution time: 61_794_000 picoseconds. + Weight::from_parts(62_455_000, 35762) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: CoreFellowship Member (r:1 w:1) + /// Proof: CoreFellowship Member (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: RankedCollective Members (r:1 w:1) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: CoreFellowship Params (r:1 w:0) + /// Proof: CoreFellowship Params (max_values: Some(1), max_size: Some(364), added: 859, mode: MaxEncodedLen) + /// Storage: RankedCollective MemberCount (r:1 w:1) + /// Proof: RankedCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: RankedCollective IdToIndex (r:1 w:0) + /// Proof: RankedCollective IdToIndex (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) + /// Storage: CoreFellowship MemberEvidence (r:1 w:1) + /// Proof: CoreFellowship MemberEvidence (max_values: None, max_size: Some(16429), added: 18904, mode: MaxEncodedLen) + fn bump_demote() -> Weight { + // Proof Size summary in bytes: + // Measured: `16996` + // Estimated: `35762` + // Minimum execution time: 63_921_000 picoseconds. + Weight::from_parts(64_871_000, 35762) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: RankedCollective Members (r:1 w:0) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: CoreFellowship Member (r:1 w:1) + /// Proof: CoreFellowship Member (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + fn set_active() -> Weight { + // Proof Size summary in bytes: + // Measured: `355` + // Estimated: `7021` + // Minimum execution time: 19_023_000 picoseconds. + Weight::from_parts(19_270_000, 7021) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: CoreFellowship Member (r:1 w:1) + /// Proof: CoreFellowship Member (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: RankedCollective Members (r:1 w:1) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: RankedCollective MemberCount (r:1 w:1) + /// Proof: RankedCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: RankedCollective IndexToId (r:0 w:1) + /// Proof: RankedCollective IndexToId (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) + /// Storage: RankedCollective IdToIndex (r:0 w:1) + /// Proof: RankedCollective IdToIndex (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) + fn induct() -> Weight { + // Proof Size summary in bytes: + // Measured: `113` + // Estimated: `10500` + // Minimum execution time: 29_089_000 picoseconds. + Weight::from_parts(29_718_000, 10500) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) + } + /// Storage: RankedCollective Members (r:1 w:1) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: CoreFellowship Member (r:1 w:1) + /// Proof: CoreFellowship Member (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: CoreFellowship Params (r:1 w:0) + /// Proof: CoreFellowship Params (max_values: Some(1), max_size: Some(364), added: 859, mode: MaxEncodedLen) + /// Storage: RankedCollective MemberCount (r:1 w:1) + /// Proof: RankedCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: CoreFellowship MemberEvidence (r:1 w:1) + /// Proof: CoreFellowship MemberEvidence (max_values: None, max_size: Some(16429), added: 18904, mode: MaxEncodedLen) + /// Storage: RankedCollective IndexToId (r:0 w:1) + /// Proof: RankedCollective IndexToId (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) + /// Storage: RankedCollective IdToIndex (r:0 w:1) + /// Proof: RankedCollective IdToIndex (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) + fn promote() -> Weight { + // Proof Size summary in bytes: + // Measured: `16864` + // Estimated: `32243` + // Minimum execution time: 59_529_000 picoseconds. + Weight::from_parts(60_057_000, 32243) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(6_u64)) + } + /// Storage: RankedCollective Members (r:1 w:0) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: CoreFellowship Member (r:1 w:1) + /// Proof: CoreFellowship Member (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + fn offboard() -> Weight { + // Proof Size summary in bytes: + // Measured: `292` + // Estimated: `7021` + // Minimum execution time: 17_221_000 picoseconds. + Weight::from_parts(17_585_000, 7021) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: CoreFellowship Member (r:1 w:1) + /// Proof: CoreFellowship Member (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: RankedCollective Members (r:1 w:0) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + fn import() -> Weight { + // Proof Size summary in bytes: + // Measured: `280` + // Estimated: `7021` + // Minimum execution time: 18_602_000 picoseconds. + Weight::from_parts(18_813_000, 7021) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: RankedCollective Members (r:1 w:0) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: CoreFellowship Member (r:1 w:1) + /// Proof: CoreFellowship Member (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: CoreFellowship MemberEvidence (r:1 w:1) + /// Proof: CoreFellowship MemberEvidence (max_values: None, max_size: Some(16429), added: 18904, mode: MaxEncodedLen) + fn approve() -> Weight { + // Proof Size summary in bytes: + // Measured: `16842` + // Estimated: `26915` + // Minimum execution time: 43_525_000 picoseconds. + Weight::from_parts(43_994_000, 26915) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: CoreFellowship Member (r:1 w:0) + /// Proof: CoreFellowship Member (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: CoreFellowship MemberEvidence (r:1 w:1) + /// Proof: CoreFellowship MemberEvidence (max_values: None, max_size: Some(16429), added: 18904, mode: MaxEncodedLen) + fn submit_evidence() -> Weight { + // Proof Size summary in bytes: + // Measured: `79` + // Estimated: `23408` + // Minimum execution time: 27_960_000 picoseconds. + Weight::from_parts(28_331_000, 23408) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } +} + +// For backwards compatibility and tests +impl WeightInfo for () { + /// Storage: CoreFellowship Params (r:0 w:1) + /// Proof: CoreFellowship Params (max_values: Some(1), max_size: Some(364), added: 859, mode: MaxEncodedLen) + fn set_params() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 10_489_000 picoseconds. + Weight::from_parts(10_873_000, 0) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: CoreFellowship Member (r:1 w:1) + /// Proof: CoreFellowship Member (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: RankedCollective Members (r:1 w:1) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: CoreFellowship Params (r:1 w:0) + /// Proof: CoreFellowship Params (max_values: Some(1), max_size: Some(364), added: 859, mode: MaxEncodedLen) + /// Storage: RankedCollective MemberCount (r:1 w:1) + /// Proof: RankedCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: RankedCollective IdToIndex (r:1 w:0) + /// Proof: RankedCollective IdToIndex (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) + /// Storage: CoreFellowship MemberEvidence (r:1 w:1) + /// Proof: CoreFellowship MemberEvidence (max_values: None, max_size: Some(16429), added: 18904, mode: MaxEncodedLen) + fn bump_offboard() -> Weight { + // Proof Size summary in bytes: + // Measured: `16886` + // Estimated: `35762` + // Minimum execution time: 61_794_000 picoseconds. + Weight::from_parts(62_455_000, 35762) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + } + /// Storage: CoreFellowship Member (r:1 w:1) + /// Proof: CoreFellowship Member (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: RankedCollective Members (r:1 w:1) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: CoreFellowship Params (r:1 w:0) + /// Proof: CoreFellowship Params (max_values: Some(1), max_size: Some(364), added: 859, mode: MaxEncodedLen) + /// Storage: RankedCollective MemberCount (r:1 w:1) + /// Proof: RankedCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: RankedCollective IdToIndex (r:1 w:0) + /// Proof: RankedCollective IdToIndex (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) + /// Storage: CoreFellowship MemberEvidence (r:1 w:1) + /// Proof: CoreFellowship MemberEvidence (max_values: None, max_size: Some(16429), added: 18904, mode: MaxEncodedLen) + fn bump_demote() -> Weight { + // Proof Size summary in bytes: + // Measured: `16996` + // Estimated: `35762` + // Minimum execution time: 63_921_000 picoseconds. + Weight::from_parts(64_871_000, 35762) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + } + /// Storage: RankedCollective Members (r:1 w:0) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: CoreFellowship Member (r:1 w:1) + /// Proof: CoreFellowship Member (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + fn set_active() -> Weight { + // Proof Size summary in bytes: + // Measured: `355` + // Estimated: `7021` + // Minimum execution time: 19_023_000 picoseconds. + Weight::from_parts(19_270_000, 7021) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: CoreFellowship Member (r:1 w:1) + /// Proof: CoreFellowship Member (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: RankedCollective Members (r:1 w:1) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: RankedCollective MemberCount (r:1 w:1) + /// Proof: RankedCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: RankedCollective IndexToId (r:0 w:1) + /// Proof: RankedCollective IndexToId (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) + /// Storage: RankedCollective IdToIndex (r:0 w:1) + /// Proof: RankedCollective IdToIndex (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) + fn induct() -> Weight { + // Proof Size summary in bytes: + // Measured: `113` + // Estimated: `10500` + // Minimum execution time: 29_089_000 picoseconds. + Weight::from_parts(29_718_000, 10500) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(5_u64)) + } + /// Storage: RankedCollective Members (r:1 w:1) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: CoreFellowship Member (r:1 w:1) + /// Proof: CoreFellowship Member (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: CoreFellowship Params (r:1 w:0) + /// Proof: CoreFellowship Params (max_values: Some(1), max_size: Some(364), added: 859, mode: MaxEncodedLen) + /// Storage: RankedCollective MemberCount (r:1 w:1) + /// Proof: RankedCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: CoreFellowship MemberEvidence (r:1 w:1) + /// Proof: CoreFellowship MemberEvidence (max_values: None, max_size: Some(16429), added: 18904, mode: MaxEncodedLen) + /// Storage: RankedCollective IndexToId (r:0 w:1) + /// Proof: RankedCollective IndexToId (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) + /// Storage: RankedCollective IdToIndex (r:0 w:1) + /// Proof: RankedCollective IdToIndex (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) + fn promote() -> Weight { + // Proof Size summary in bytes: + // Measured: `16864` + // Estimated: `32243` + // Minimum execution time: 59_529_000 picoseconds. + Weight::from_parts(60_057_000, 32243) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(6_u64)) + } + /// Storage: RankedCollective Members (r:1 w:0) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: CoreFellowship Member (r:1 w:1) + /// Proof: CoreFellowship Member (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + fn offboard() -> Weight { + // Proof Size summary in bytes: + // Measured: `292` + // Estimated: `7021` + // Minimum execution time: 17_221_000 picoseconds. + Weight::from_parts(17_585_000, 7021) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: CoreFellowship Member (r:1 w:1) + /// Proof: CoreFellowship Member (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: RankedCollective Members (r:1 w:0) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + fn import() -> Weight { + // Proof Size summary in bytes: + // Measured: `280` + // Estimated: `7021` + // Minimum execution time: 18_602_000 picoseconds. + Weight::from_parts(18_813_000, 7021) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: RankedCollective Members (r:1 w:0) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: CoreFellowship Member (r:1 w:1) + /// Proof: CoreFellowship Member (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: CoreFellowship MemberEvidence (r:1 w:1) + /// Proof: CoreFellowship MemberEvidence (max_values: None, max_size: Some(16429), added: 18904, mode: MaxEncodedLen) + fn approve() -> Weight { + // Proof Size summary in bytes: + // Measured: `16842` + // Estimated: `26915` + // Minimum execution time: 43_525_000 picoseconds. + Weight::from_parts(43_994_000, 26915) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: CoreFellowship Member (r:1 w:0) + /// Proof: CoreFellowship Member (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: CoreFellowship MemberEvidence (r:1 w:1) + /// Proof: CoreFellowship MemberEvidence (max_values: None, max_size: Some(16429), added: 18904, mode: MaxEncodedLen) + fn submit_evidence() -> Weight { + // Proof Size summary in bytes: + // Measured: `79` + // Estimated: `23408` + // Minimum execution time: 27_960_000 picoseconds. + Weight::from_parts(28_331_000, 23408) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } +} diff --git a/frame/salary/src/lib.rs b/frame/salary/src/lib.rs index 2169952f1a7f3..5a4ff8a66da50 100644 --- a/frame/salary/src/lib.rs +++ b/frame/salary/src/lib.rs @@ -82,8 +82,8 @@ pub trait Pay { /// after this call. Used in benchmarking code. #[cfg(feature = "runtime-benchmarks")] fn ensure_successful(who: &Self::AccountId, amount: Self::Balance); - /// Ensure that a call to check_payment with the given parameters will return either Success - /// or Failure. + /// Ensure that a call to `check_payment` with the given parameters will return either `Success` + /// or `Failure`. #[cfg(feature = "runtime-benchmarks")] fn ensure_concluded(id: Self::Id); } diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 5e921ab854df1..0ec808d4c960f 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -878,12 +878,9 @@ impl< #[cfg(feature = "runtime-benchmarks")] fn try_successful_origin() -> Result { - let zero_account_id = - AccountId::decode(&mut TrailingZeroInput::zeroes()).map_err(|_| ())?; - let members = Who::sorted_members(); - let first_member = match members.get(0) { + let first_member = match Who::sorted_members().first() { Some(account) => account.clone(), - None => zero_account_id, + None => AccountId::decode(&mut TrailingZeroInput::zeroes()).map_err(|_| ())?, }; Ok(O::from(RawOrigin::Signed(first_member))) } diff --git a/primitives/arithmetic/src/traits.rs b/primitives/arithmetic/src/traits.rs index 84e3f60aa6a7d..33b4e376aaf9d 100644 --- a/primitives/arithmetic/src/traits.rs +++ b/primitives/arithmetic/src/traits.rs @@ -148,6 +148,20 @@ impl< { } +/// A meta trait for arithmetic. +/// +/// Arithmetic types do all the usual stuff you'd expect numbers to do. They are guaranteed to +/// be able to represent at least `u8` values without loss, hence the trait implies `From` +/// and smaller integers. All other conversions are fallible. +pub trait AtLeast8Bit: BaseArithmetic + From {} + +impl> AtLeast8Bit for T {} + +/// A meta trait for arithmetic. Same as [`AtLeast8Bit `], but also bounded to be unsigned. +pub trait AtLeast8BitUnsigned: AtLeast8Bit + Unsigned {} + +impl AtLeast8BitUnsigned for T {} + /// A meta trait for arithmetic. /// /// Arithmetic types do all the usual stuff you'd expect numbers to do. They are guaranteed to @@ -220,6 +234,24 @@ pub trait Saturating { /// instead of overflowing. fn saturating_pow(self, exp: usize) -> Self; + /// Decrement self by one, saturating at zero. + fn saturating_less_one(mut self) -> Self + where + Self: One, + { + self.saturating_dec(); + self + } + + /// Increment self by one, saturating at the numeric bounds instead of overflowing. + fn saturating_plus_one(mut self) -> Self + where + Self: One, + { + self.saturating_inc(); + self + } + /// Increment self by one, saturating. fn saturating_inc(&mut self) where diff --git a/primitives/runtime/src/traits.rs b/primitives/runtime/src/traits.rs index e853cad61d81e..4bba6f6bc1283 100644 --- a/primitives/runtime/src/traits.rs +++ b/primitives/runtime/src/traits.rs @@ -319,6 +319,24 @@ impl TryMorph for Identity { } } +/// Implementation of `Morph` which converts between types using `Into`. +pub struct MorphInto(sp_std::marker::PhantomData); +impl> Morph for MorphInto { + type Outcome = T; + fn morph(a: A) -> T { + a.into() + } +} + +/// Implementation of `TryMorph` which attmepts to convert between types using `TryInto`. +pub struct TryMorphInto(sp_std::marker::PhantomData); +impl> TryMorph for TryMorphInto { + type Outcome = T; + fn try_morph(a: A) -> Result { + a.try_into().map_err(|_| ()) + } +} + /// Create a `Morph` and/or `TryMorph` impls with a simple closure-like expression. /// /// # Examples From 3c3b223be82d91be85b3f3cc8305e444b2ca37fa Mon Sep 17 00:00:00 2001 From: Mira Ressel Date: Sat, 11 Mar 2023 17:04:54 +0100 Subject: [PATCH 496/715] Fix dependabot labels (#13578) * dependabot: fix label names * dependabot: apply E2-dependencies label for Cargo.lock changes --- .github/dependabot.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index cca9219e6c5e1..04cf0d1e1a5a4 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -2,11 +2,11 @@ version: 2 updates: - package-ecosystem: "cargo" directory: "/" - labels: ["A2-insubstantial", "B0-silent", "C1-low 📌"] + labels: ["A2-insubstantial", "B0-silent", "C1-low", "E2-dependencies"] schedule: interval: "daily" - package-ecosystem: github-actions directory: '/' - labels: ["A2-insubstantial", "B0-silent", "C1-low 📌", "E3-dependencies"] + labels: ["A2-insubstantial", "B0-silent", "C1-low", "E2-dependencies"] schedule: interval: daily From 310fe4095bff177ddcfa660ac0ab06171a25a9c2 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Sat, 11 Mar 2023 19:05:55 +0100 Subject: [PATCH 497/715] BEEFY: introduce offence report system (#13564) * Trivial adjustments to beefy and grandpa pallets * Introduce offence report system to beefy pallet * Minor adjustments * Fix beefy-mmr mock * Apply suggestions from code review Co-authored-by: Anton --------- Co-authored-by: Anton --- frame/babe/src/equivocation.rs | 14 +- frame/beefy-mmr/src/mock.rs | 14 +- frame/beefy/src/equivocation.rs | 412 ++++++++++--------------- frame/beefy/src/lib.rs | 130 ++------ frame/beefy/src/mock.rs | 12 +- frame/grandpa/src/equivocation.rs | 33 +- frame/grandpa/src/lib.rs | 3 +- frame/grandpa/src/mock.rs | 3 - frame/grandpa/src/tests.rs | 12 +- frame/offences/benchmarking/src/lib.rs | 4 +- 10 files changed, 233 insertions(+), 404 deletions(-) diff --git a/frame/babe/src/equivocation.rs b/frame/babe/src/equivocation.rs index ed98385a74474..3a14cacc905d2 100644 --- a/frame/babe/src/equivocation.rs +++ b/frame/babe/src/equivocation.rs @@ -95,14 +95,16 @@ impl Offence for EquivocationOffence { } } -/// Babe equivocation offence system. +/// BABE equivocation offence report system. /// -/// This type implements `OffenceReportSystem` +/// This type implements `OffenceReportSystem` such that: +/// - Equivocation reports are published on-chain as unsigned extrinsic via +/// `offchain::SendTransactioinsTypes`. +/// - On-chain validity checks and processing are mostly delegated to the user provided generic +/// types implementing `KeyOwnerProofSystem` and `ReportOffence` traits. +/// - Offence reporter for unsigned transactions is fetched via the the authorship pallet. pub struct EquivocationReportSystem(sp_std::marker::PhantomData<(T, R, P, L)>); -// We use the authorship pallet to fetch the current block author and use -// `offchain::SendTransactionTypes` for unsigned extrinsic creation and -// submission. impl OffenceReportSystem, (EquivocationProof, T::KeyOwnerProof)> for EquivocationReportSystem @@ -131,7 +133,7 @@ where }; let res = SubmitTransaction::>::submit_unsigned_transaction(call.into()); match res { - Ok(()) => info!(target: LOG_TARGET, "Submitted equivocation report."), + Ok(_) => info!(target: LOG_TARGET, "Submitted equivocation report"), Err(e) => error!(target: LOG_TARGET, "Error submitting equivocation report: {:?}", e), } res diff --git a/frame/beefy-mmr/src/mock.rs b/frame/beefy-mmr/src/mock.rs index d31effc9ab577..8b3bedcb960b4 100644 --- a/frame/beefy-mmr/src/mock.rs +++ b/frame/beefy-mmr/src/mock.rs @@ -21,11 +21,11 @@ use codec::Encode; use frame_support::{ construct_runtime, parameter_types, sp_io::TestExternalities, - traits::{ConstU16, ConstU32, ConstU64, GenesisBuild, KeyOwnerProofSystem}, + traits::{ConstU16, ConstU32, ConstU64, GenesisBuild}, BasicExternalities, }; use sp_consensus_beefy::mmr::MmrLeafVersion; -use sp_core::{crypto::KeyTypeId, Hasher, H256}; +use sp_core::{Hasher, H256}; use sp_runtime::{ app_crypto::ecdsa::Public, impl_opaque_keys, @@ -124,18 +124,12 @@ impl pallet_mmr::Config for Test { impl pallet_beefy::Config for Test { type BeefyId = BeefyId; - type KeyOwnerProofSystem = (); - type KeyOwnerProof = - >::Proof; - type KeyOwnerIdentification = >::IdentificationTuple; - type HandleEquivocation = (); type MaxAuthorities = ConstU32<100>; type MaxSetIdSessionEntries = ConstU64<100>; type OnNewValidatorSet = BeefyMmr; type WeightInfo = (); + type KeyOwnerProof = sp_core::Void; + type EquivocationReportSystem = (); } parameter_types! { diff --git a/frame/beefy/src/equivocation.rs b/frame/beefy/src/equivocation.rs index cc04f316c3638..f83b037dcd26e 100644 --- a/frame/beefy/src/equivocation.rs +++ b/frame/beefy/src/equivocation.rs @@ -34,179 +34,205 @@ //! that the `ValidateUnsigned` for the BEEFY pallet is used in the runtime //! definition. -use sp_std::prelude::*; - use codec::{self as codec, Decode, Encode}; use frame_support::{ log, traits::{Get, KeyOwnerProofSystem}, }; -use frame_system::pallet_prelude::BlockNumberFor; -use sp_consensus_beefy::{EquivocationProof, ValidatorSetId}; +use log::{error, info}; +use sp_consensus_beefy::{EquivocationProof, ValidatorSetId, KEY_TYPE}; use sp_runtime::{ transaction_validity::{ InvalidTransaction, TransactionPriority, TransactionSource, TransactionValidity, TransactionValidityError, ValidTransaction, }, - DispatchResult, Perbill, RuntimeAppPublic, + DispatchError, KeyTypeId, Perbill, RuntimeAppPublic, }; +use sp_session::{GetSessionNumber, GetValidatorCount}; use sp_staking::{ - offence::{Kind, Offence, OffenceError, ReportOffence}, + offence::{Kind, Offence, OffenceReportSystem, ReportOffence}, SessionIndex, }; +use sp_std::prelude::*; -use super::{Call, Config, Pallet, LOG_TARGET}; - -/// A trait with utility methods for handling equivocation reports in BEEFY. -/// The offence type is generic, and the trait provides, reporting an offence -/// triggered by a valid equivocation report, and also for creating and -/// submitting equivocation report extrinsics (useful only in offchain context). -pub trait HandleEquivocation { - /// The offence type used for reporting offences on valid equivocation reports. - type Offence: BeefyOffence, T::KeyOwnerIdentification>; - - /// The longevity, in blocks, that the equivocation report is valid for. When using the staking - /// pallet this should be equal to the bonding duration (in blocks, not eras). - type ReportLongevity: Get; - - /// Report an offence proved by the given reporters. - fn report_offence( - reporters: Vec, - offence: Self::Offence, - ) -> Result<(), OffenceError>; - - /// Returns true if all of the offenders at the given time slot have already been reported. - fn is_known_offence( - offenders: &[T::KeyOwnerIdentification], - time_slot: &>::TimeSlot, - ) -> bool; - - /// Create and dispatch an equivocation report extrinsic. - fn submit_unsigned_equivocation_report( - equivocation_proof: EquivocationProof< - BlockNumberFor, - T::BeefyId, - ::Signature, - >, - key_owner_proof: T::KeyOwnerProof, - ) -> DispatchResult; - - /// Fetch the current block author id, if defined. - fn block_author() -> Option; +use super::{Call, Config, Error, Pallet, LOG_TARGET}; + +/// A round number and set id which point on the time of an offence. +#[derive(Copy, Clone, PartialOrd, Ord, Eq, PartialEq, Encode, Decode)] +pub struct TimeSlot { + // The order of these matters for `derive(Ord)`. + /// BEEFY Set ID. + pub set_id: ValidatorSetId, + /// Round number. + pub round: N, } -impl HandleEquivocation for () { - type Offence = BeefyEquivocationOffence, T::KeyOwnerIdentification>; - type ReportLongevity = (); +/// BEEFY equivocation offence report. +pub struct EquivocationOffence +where + N: Copy + Clone + PartialOrd + Ord + Eq + PartialEq + Encode + Decode, +{ + /// Time slot at which this incident happened. + pub time_slot: TimeSlot, + /// The session index in which the incident happened. + pub session_index: SessionIndex, + /// The size of the validator set at the time of the offence. + pub validator_set_count: u32, + /// The authority which produced this equivocation. + pub offender: Offender, +} - fn report_offence( - _reporters: Vec, - _offence: BeefyEquivocationOffence, T::KeyOwnerIdentification>, - ) -> Result<(), OffenceError> { - Ok(()) - } +impl Offence for EquivocationOffence +where + N: Copy + Clone + PartialOrd + Ord + Eq + PartialEq + Encode + Decode, +{ + const ID: Kind = *b"beefy:equivocati"; + type TimeSlot = TimeSlot; - fn is_known_offence( - _offenders: &[T::KeyOwnerIdentification], - _time_slot: &BeefyTimeSlot>, - ) -> bool { - true + fn offenders(&self) -> Vec { + vec![self.offender.clone()] } - fn submit_unsigned_equivocation_report( - _equivocation_proof: EquivocationProof< - BlockNumberFor, - T::BeefyId, - ::Signature, - >, - _key_owner_proof: T::KeyOwnerProof, - ) -> DispatchResult { - Ok(()) + fn session_index(&self) -> SessionIndex { + self.session_index } - fn block_author() -> Option { - None + fn validator_set_count(&self) -> u32 { + self.validator_set_count } -} -/// Generic equivocation handler. This type implements `HandleEquivocation` -/// using existing subsystems that are part of frame (type bounds described -/// below) and will dispatch to them directly, it's only purpose is to wire all -/// subsystems together. -pub struct EquivocationHandler> { - _phantom: sp_std::marker::PhantomData<(N, I, R, L, O)>, -} + fn time_slot(&self) -> Self::TimeSlot { + self.time_slot + } -impl Default for EquivocationHandler { - fn default() -> Self { - Self { _phantom: Default::default() } + // The formula is min((3k / n)^2, 1) + // where k = offenders_number and n = validators_number + fn slash_fraction(&self, offenders_count: u32) -> Perbill { + // Perbill type domain is [0, 1] by definition + Perbill::from_rational(3 * offenders_count, self.validator_set_count).square() } } -impl HandleEquivocation - for EquivocationHandler, T::KeyOwnerIdentification, R, L, O> +/// BEEFY equivocation offence report system. +/// +/// This type implements `OffenceReportSystem` such that: +/// - Equivocation reports are published on-chain as unsigned extrinsic via +/// `offchain::SendTransactioinsTypes`. +/// - On-chain validity checks and processing are mostly delegated to the user provided generic +/// types implementing `KeyOwnerProofSystem` and `ReportOffence` traits. +/// - Offence reporter for unsigned transactions is fetched via the the authorship pallet. +pub struct EquivocationReportSystem(sp_std::marker::PhantomData<(T, R, P, L)>); + +/// Equivocation evidence convenience alias. +pub type EquivocationEvidenceFor = ( + EquivocationProof< + ::BlockNumber, + ::BeefyId, + <::BeefyId as RuntimeAppPublic>::Signature, + >, + ::KeyOwnerProof, +); + +impl OffenceReportSystem, EquivocationEvidenceFor> + for EquivocationReportSystem where - // We use the authorship pallet to fetch the current block author and use - // `offchain::SendTransactionTypes` for unsigned extrinsic creation and - // submission. T: Config + pallet_authorship::Config + frame_system::offchain::SendTransactionTypes>, - // A system for reporting offences after valid equivocation reports are - // processed. - R: ReportOffence, - // The longevity (in blocks) that the equivocation report is valid for. When using the staking - // pallet this should be the bonding duration. + R: ReportOffence< + T::AccountId, + P::IdentificationTuple, + EquivocationOffence, + >, + P: KeyOwnerProofSystem<(KeyTypeId, T::BeefyId), Proof = T::KeyOwnerProof>, + P::IdentificationTuple: Clone, L: Get, - // The offence type that should be used when reporting. - O: BeefyOffence, T::KeyOwnerIdentification>, { - type Offence = O; - type ReportLongevity = L; + type Longevity = L; - fn report_offence(reporters: Vec, offence: O) -> Result<(), OffenceError> { - R::report_offence(reporters, offence) - } - - fn is_known_offence(offenders: &[T::KeyOwnerIdentification], time_slot: &O::TimeSlot) -> bool { - R::is_known_offence(offenders, time_slot) - } - - fn submit_unsigned_equivocation_report( - equivocation_proof: EquivocationProof< - BlockNumberFor, - T::BeefyId, - ::Signature, - >, - key_owner_proof: T::KeyOwnerProof, - ) -> DispatchResult { + fn publish_evidence(evidence: EquivocationEvidenceFor) -> Result<(), ()> { use frame_system::offchain::SubmitTransaction; + let (equivocation_proof, key_owner_proof) = evidence; let call = Call::report_equivocation_unsigned { equivocation_proof: Box::new(equivocation_proof), key_owner_proof, }; - match SubmitTransaction::>::submit_unsigned_transaction(call.into()) { - Ok(()) => log::info!(target: LOG_TARGET, "Submitted BEEFY equivocation report.",), - Err(e) => - log::error!(target: LOG_TARGET, "Error submitting equivocation report: {:?}", e,), + let res = SubmitTransaction::>::submit_unsigned_transaction(call.into()); + match res { + Ok(_) => info!(target: LOG_TARGET, "Submitted equivocation report."), + Err(e) => error!(target: LOG_TARGET, "Error submitting equivocation report: {:?}", e), } - - Ok(()) + res } - fn block_author() -> Option { - >::author() + fn check_evidence( + evidence: EquivocationEvidenceFor, + ) -> Result<(), TransactionValidityError> { + let (equivocation_proof, key_owner_proof) = evidence; + + // Check the membership proof to extract the offender's id + let key = (KEY_TYPE, equivocation_proof.offender_id().clone()); + let offender = P::check_proof(key, key_owner_proof).ok_or(InvalidTransaction::BadProof)?; + + // Check if the offence has already been reported, and if so then we can discard the report. + let time_slot = TimeSlot { + set_id: equivocation_proof.set_id(), + round: *equivocation_proof.round_number(), + }; + + if R::is_known_offence(&[offender], &time_slot) { + Err(InvalidTransaction::Stale.into()) + } else { + Ok(()) + } } -} -/// A round number and set id which point on the time of an offence. -#[derive(Copy, Clone, PartialOrd, Ord, Eq, PartialEq, Encode, Decode)] -pub struct BeefyTimeSlot { - // The order of these matters for `derive(Ord)`. - /// BEEFY Set ID. - pub set_id: ValidatorSetId, - /// Round number. - pub round: N, + fn process_evidence( + reporter: Option, + evidence: EquivocationEvidenceFor, + ) -> Result<(), DispatchError> { + let (equivocation_proof, key_owner_proof) = evidence; + let reporter = reporter.or_else(|| >::author()); + let offender = equivocation_proof.offender_id().clone(); + + // We check the equivocation within the context of its set id (and + // associated session) and round. We also need to know the validator + // set count at the time of the offence since it is required to calculate + // the slash amount. + let set_id = equivocation_proof.set_id(); + let round = *equivocation_proof.round_number(); + let session_index = key_owner_proof.session(); + let validator_set_count = key_owner_proof.validator_count(); + + // Validate the key ownership proof extracting the id of the offender. + let offender = P::check_proof((KEY_TYPE, offender), key_owner_proof) + .ok_or(Error::::InvalidKeyOwnershipProof)?; + + // Validate equivocation proof (check votes are different and signatures are valid). + if !sp_consensus_beefy::check_equivocation_proof(&equivocation_proof) { + return Err(Error::::InvalidEquivocationProof.into()) + } + + // Check that the session id for the membership proof is within the + // bounds of the set id reported in the equivocation. + let set_id_session_index = + crate::SetIdSession::::get(set_id).ok_or(Error::::InvalidEquivocationProof)?; + if session_index != set_id_session_index { + return Err(Error::::InvalidEquivocationProof.into()) + } + + let offence = EquivocationOffence { + time_slot: TimeSlot { set_id, round }, + session_index, + validator_set_count, + offender, + }; + + R::report_offence(reporter.into_iter().collect(), offence) + .map_err(|_| Error::::DuplicateOffenceReport)?; + + Ok(()) + } } /// Methods for the `ValidateUnsigned` implementation: @@ -228,11 +254,11 @@ impl Pallet { }, } - // check report staleness - is_known_offence::(equivocation_proof, key_owner_proof)?; + let evidence = (*equivocation_proof.clone(), key_owner_proof.clone()); + T::EquivocationReportSystem::check_evidence(evidence)?; let longevity = - >::ReportLongevity::get(); + >::Longevity::get(); ValidTransaction::with_tag_prefix("BeefyEquivocation") // We assign the maximum priority for any equivocation report. @@ -254,132 +280,10 @@ impl Pallet { pub fn pre_dispatch(call: &Call) -> Result<(), TransactionValidityError> { if let Call::report_equivocation_unsigned { equivocation_proof, key_owner_proof } = call { - is_known_offence::(equivocation_proof, key_owner_proof) + let evidence = (*equivocation_proof.clone(), key_owner_proof.clone()); + T::EquivocationReportSystem::check_evidence(evidence) } else { Err(InvalidTransaction::Call.into()) } } } - -fn is_known_offence( - equivocation_proof: &EquivocationProof< - BlockNumberFor, - T::BeefyId, - ::Signature, - >, - key_owner_proof: &T::KeyOwnerProof, -) -> Result<(), TransactionValidityError> { - // check the membership proof to extract the offender's id, - // equivocation validity will be fully checked during the call. - let key = (sp_consensus_beefy::KEY_TYPE, equivocation_proof.offender_id().clone()); - - let offender = T::KeyOwnerProofSystem::check_proof(key, key_owner_proof.clone()) - .ok_or(InvalidTransaction::BadProof)?; - - // check if the offence has already been reported, - // and if so then we can discard the report. - let time_slot = >::Offence::new_time_slot( - equivocation_proof.set_id(), - *equivocation_proof.round_number(), - ); - - let is_known_offence = T::HandleEquivocation::is_known_offence(&[offender], &time_slot); - - if is_known_offence { - Err(InvalidTransaction::Stale.into()) - } else { - Ok(()) - } -} - -/// A BEEFY equivocation offence report. -pub struct BeefyEquivocationOffence -where - N: Copy + Clone + PartialOrd + Ord + Eq + PartialEq + Encode + Decode, -{ - /// Time slot at which this incident happened. - pub time_slot: BeefyTimeSlot, - /// The session index in which the incident happened. - pub session_index: SessionIndex, - /// The size of the validator set at the time of the offence. - pub validator_set_count: u32, - /// The authority which produced this equivocation. - pub offender: FullIdentification, -} - -/// An interface for types that will be used as BEEFY offences and must also -/// implement the `Offence` trait. This trait provides a constructor that is -/// provided all available data during processing of BEEFY equivocations. -pub trait BeefyOffence: Offence -where - N: Copy + Clone + PartialOrd + Ord + Eq + PartialEq + Encode + Decode, -{ - /// Create a new BEEFY offence using the given equivocation details. - fn new( - session_index: SessionIndex, - validator_set_count: u32, - offender: FullIdentification, - set_id: ValidatorSetId, - round: N, - ) -> Self; - - /// Create a new BEEFY offence time slot. - fn new_time_slot(set_id: ValidatorSetId, round: N) -> Self::TimeSlot; -} - -impl BeefyOffence - for BeefyEquivocationOffence -where - N: Copy + Clone + PartialOrd + Ord + Eq + PartialEq + Encode + Decode, -{ - fn new( - session_index: SessionIndex, - validator_set_count: u32, - offender: FullIdentification, - set_id: ValidatorSetId, - round: N, - ) -> Self { - BeefyEquivocationOffence { - session_index, - validator_set_count, - offender, - time_slot: BeefyTimeSlot { set_id, round }, - } - } - - fn new_time_slot(set_id: ValidatorSetId, round: N) -> Self::TimeSlot { - BeefyTimeSlot { set_id, round } - } -} - -impl Offence - for BeefyEquivocationOffence -where - N: Copy + Clone + PartialOrd + Ord + Eq + PartialEq + Encode + Decode, -{ - const ID: Kind = *b"beefy:equivocati"; - type TimeSlot = BeefyTimeSlot; - - fn offenders(&self) -> Vec { - vec![self.offender.clone()] - } - - fn session_index(&self) -> SessionIndex { - self.session_index - } - - fn validator_set_count(&self) -> u32 { - self.validator_set_count - } - - fn time_slot(&self) -> Self::TimeSlot { - self.time_slot - } - - fn slash_fraction(&self, offenders_count: u32) -> Perbill { - // the formula is min((3k / n)^2, 1) - let x = Perbill::from_rational(3 * offenders_count, self.validator_set_count); - // _ ^ 2 - x.square() - } -} diff --git a/frame/beefy/src/lib.rs b/frame/beefy/src/lib.rs index 698e6e73312f1..945b32c12fe58 100644 --- a/frame/beefy/src/lib.rs +++ b/frame/beefy/src/lib.rs @@ -23,7 +23,7 @@ use frame_support::{ dispatch::{DispatchResultWithPostInfo, Pays}, log, pallet_prelude::*, - traits::{Get, KeyOwnerProofSystem, OneSessionHandler}, + traits::{Get, OneSessionHandler}, weights::Weight, BoundedSlice, BoundedVec, Parameter, }; @@ -34,10 +34,10 @@ use frame_system::{ use sp_runtime::{ generic::DigestItem, traits::{IsMember, Member}, - KeyTypeId, RuntimeAppPublic, + RuntimeAppPublic, }; use sp_session::{GetSessionNumber, GetValidatorCount}; -use sp_staking::SessionIndex; +use sp_staking::{offence::OffenceReportSystem, SessionIndex}; use sp_std::prelude::*; use sp_consensus_beefy::{ @@ -52,11 +52,11 @@ mod mock; #[cfg(test)] mod tests; -pub use crate::equivocation::{ - BeefyEquivocationOffence, BeefyOffence, BeefyTimeSlot, EquivocationHandler, HandleEquivocation, -}; +pub use crate::equivocation::{EquivocationOffence, EquivocationReportSystem, TimeSlot}; pub use pallet::*; +use crate::equivocation::EquivocationEvidenceFor; + const LOG_TARGET: &str = "runtime::beefy"; #[frame_support::pallet] @@ -74,30 +74,6 @@ pub mod pallet { + MaybeSerializeDeserialize + MaxEncodedLen; - /// A system for proving ownership of keys, i.e. that a given key was part - /// of a validator set, needed for validating equivocation reports. - type KeyOwnerProofSystem: KeyOwnerProofSystem< - (KeyTypeId, Self::BeefyId), - Proof = Self::KeyOwnerProof, - IdentificationTuple = Self::KeyOwnerIdentification, - >; - - /// The proof of key ownership, used for validating equivocation reports - /// The proof must include the session index and validator count of the - /// session at which the equivocation occurred. - type KeyOwnerProof: Parameter + GetSessionNumber + GetValidatorCount; - - /// The identification of a key owner, used when reporting equivocations. - type KeyOwnerIdentification: Parameter; - - /// The equivocation handling subsystem, defines methods to report an - /// offence (after the equivocation has been validated) and for submitting a - /// transaction to report an equivocation (from an offchain context). - /// NOTE: when enabling equivocation handling (i.e. this type isn't set to - /// `()`) you must use this pallet's `ValidateUnsigned` in the runtime - /// definition. - type HandleEquivocation: HandleEquivocation; - /// The maximum number of authorities that can be added. #[pallet::constant] type MaxAuthorities: Get; @@ -120,6 +96,19 @@ pub mod pallet { /// Weights for this pallet. type WeightInfo: WeightInfo; + + /// The proof of key ownership, used for validating equivocation reports + /// The proof must include the session index and validator count of the + /// session at which the equivocation occurred. + type KeyOwnerProof: Parameter + GetSessionNumber + GetValidatorCount; + + /// The equivocation handling subsystem. + /// + /// Defines methods to publish, check and process an equivocation offence. + type EquivocationReportSystem: OffenceReportSystem< + Option, + EquivocationEvidenceFor, + >; } #[pallet::pallet] @@ -229,7 +218,12 @@ pub mod pallet { ) -> DispatchResultWithPostInfo { let reporter = ensure_signed(origin)?; - Self::do_report_equivocation(Some(reporter), *equivocation_proof, key_owner_proof) + T::EquivocationReportSystem::process_evidence( + Some(reporter), + (*equivocation_proof, key_owner_proof), + )?; + // Waive the fee since the report is valid and beneficial + Ok(Pays::No.into()) } /// Report voter equivocation/misbehavior. This method will verify the @@ -256,20 +250,22 @@ pub mod pallet { ) -> DispatchResultWithPostInfo { ensure_none(origin)?; - Self::do_report_equivocation( - T::HandleEquivocation::block_author(), - *equivocation_proof, - key_owner_proof, - ) + T::EquivocationReportSystem::process_evidence( + None, + (*equivocation_proof, key_owner_proof), + )?; + Ok(Pays::No.into()) } } #[pallet::validate_unsigned] impl ValidateUnsigned for Pallet { type Call = Call; + fn pre_dispatch(call: &Self::Call) -> Result<(), TransactionValidityError> { Self::pre_dispatch(call) } + fn validate_unsigned(source: TransactionSource, call: &Self::Call) -> TransactionValidity { Self::validate_unsigned(source, call) } @@ -295,11 +291,7 @@ impl Pallet { >, key_owner_proof: T::KeyOwnerProof, ) -> Option<()> { - T::HandleEquivocation::submit_unsigned_equivocation_report( - equivocation_proof, - key_owner_proof, - ) - .ok() + T::EquivocationReportSystem::publish_evidence((equivocation_proof, key_owner_proof)).ok() } fn change_authorities( @@ -368,62 +360,6 @@ impl Pallet { Ok(()) } - - fn do_report_equivocation( - reporter: Option, - equivocation_proof: EquivocationProof< - BlockNumberFor, - T::BeefyId, - ::Signature, - >, - key_owner_proof: T::KeyOwnerProof, - ) -> DispatchResultWithPostInfo { - // We check the equivocation within the context of its set id (and - // associated session) and round. We also need to know the validator - // set count at the time of the offence since it is required to calculate - // the slash amount. - let set_id = equivocation_proof.set_id(); - let round = *equivocation_proof.round_number(); - let offender_id = equivocation_proof.offender_id().clone(); - let session_index = key_owner_proof.session(); - let validator_count = key_owner_proof.validator_count(); - - // validate the key ownership proof extracting the id of the offender. - let offender = T::KeyOwnerProofSystem::check_proof( - (sp_consensus_beefy::KEY_TYPE, offender_id), - key_owner_proof, - ) - .ok_or(Error::::InvalidKeyOwnershipProof)?; - - // validate equivocation proof (check votes are different and signatures are valid). - if !sp_consensus_beefy::check_equivocation_proof(&equivocation_proof) { - return Err(Error::::InvalidEquivocationProof.into()) - } - - // check that the session id for the membership proof is within the - // bounds of the set id reported in the equivocation. - let set_id_session_index = - Self::session_for_set(set_id).ok_or(Error::::InvalidEquivocationProof)?; - if session_index != set_id_session_index { - return Err(Error::::InvalidEquivocationProof.into()) - } - - // report to the offences module rewarding the sender. - T::HandleEquivocation::report_offence( - reporter.into_iter().collect(), - >::Offence::new( - session_index, - validator_count, - offender, - set_id, - round, - ), - ) - .map_err(|_| Error::::DuplicateOffenceReport)?; - - // waive the fee since the report is valid and beneficial - Ok(Pays::No.into()) - } } impl sp_runtime::BoundToRuntimeAppPublic for Pallet { diff --git a/frame/beefy/src/mock.rs b/frame/beefy/src/mock.rs index 72e3f83dff91c..c92966235118e 100644 --- a/frame/beefy/src/mock.rs +++ b/frame/beefy/src/mock.rs @@ -116,19 +116,13 @@ parameter_types! { impl pallet_beefy::Config for Test { type BeefyId = BeefyId; - type KeyOwnerProofSystem = Historical; - type KeyOwnerProof = - >::Proof; - type KeyOwnerIdentification = >::IdentificationTuple; - type HandleEquivocation = - super::EquivocationHandler; type MaxAuthorities = ConstU32<100>; type MaxSetIdSessionEntries = MaxSetIdSessionEntries; type OnNewValidatorSet = (); type WeightInfo = (); + type KeyOwnerProof = >::Proof; + type EquivocationReportSystem = + super::EquivocationReportSystem; } parameter_types! { diff --git a/frame/grandpa/src/equivocation.rs b/frame/grandpa/src/equivocation.rs index 6fd12bbdfcdb9..44d0266375230 100644 --- a/frame/grandpa/src/equivocation.rs +++ b/frame/grandpa/src/equivocation.rs @@ -57,7 +57,7 @@ use super::{Call, Config, Error, Pallet, LOG_TARGET}; /// A round number and set id which point on the time of an offence. #[derive(Copy, Clone, PartialOrd, Ord, Eq, PartialEq, Encode, Decode)] -pub struct GrandpaTimeSlot { +pub struct TimeSlot { // The order of these matters for `derive(Ord)`. /// Grandpa Set ID. pub set_id: SetId, @@ -65,10 +65,10 @@ pub struct GrandpaTimeSlot { pub round: RoundNumber, } -/// A GRANDPA equivocation offence report. +/// GRANDPA equivocation offence report. pub struct EquivocationOffence { /// Time slot at which this incident happened. - pub time_slot: GrandpaTimeSlot, + pub time_slot: TimeSlot, /// The session index in which the incident happened. pub session_index: SessionIndex, /// The size of the validator set at the time of the offence. @@ -79,7 +79,7 @@ pub struct EquivocationOffence { impl Offence for EquivocationOffence { const ID: Kind = *b"grandpa:equivoca"; - type TimeSlot = GrandpaTimeSlot; + type TimeSlot = TimeSlot; fn offenders(&self) -> Vec { vec![self.offender.clone()] @@ -105,15 +105,16 @@ impl Offence for EquivocationOffence { } } -/// Generic equivocation handler. This type implements `HandleEquivocation` -/// using existing subsystems that are part of frame (type bounds described -/// below) and will dispatch to them directly, it's only purpose is to wire all -/// subsystems together. +/// GRANDPA equivocation offence report system. +/// +/// This type implements `OffenceReportSystem` such that: +/// - Equivocation reports are published on-chain as unsigned extrinsic via +/// `offchain::SendTransactioinsTypes`. +/// - On-chain validity checks and processing are mostly delegated to the user provided generic +/// types implementing `KeyOwnerProofSystem` and `ReportOffence` traits. +/// - Offence reporter for unsigned transactions is fetched via the the authorship pallet. pub struct EquivocationReportSystem(sp_std::marker::PhantomData<(T, R, P, L)>); -// We use the authorship pallet to fetch the current block author and use -// `offchain::SendTransactionTypes` for unsigned extrinsic creation and -// submission. impl OffenceReportSystem< Option, @@ -144,7 +145,7 @@ where }; let res = SubmitTransaction::>::submit_unsigned_transaction(call.into()); match res { - Ok(()) => info!(target: LOG_TARGET, "Submitted equivocation report."), + Ok(_) => info!(target: LOG_TARGET, "Submitted equivocation report"), Err(e) => error!(target: LOG_TARGET, "Error submitting equivocation report: {:?}", e), } res @@ -160,10 +161,8 @@ where let offender = P::check_proof(key, key_owner_proof).ok_or(InvalidTransaction::BadProof)?; // Check if the offence has already been reported, and if so then we can discard the report. - let time_slot = GrandpaTimeSlot { - set_id: equivocation_proof.set_id(), - round: equivocation_proof.round(), - }; + let time_slot = + TimeSlot { set_id: equivocation_proof.set_id(), round: equivocation_proof.round() }; if R::is_known_offence(&[offender], &time_slot) { Err(InvalidTransaction::Stale.into()) } else { @@ -221,7 +220,7 @@ where } let offence = EquivocationOffence { - time_slot: GrandpaTimeSlot { set_id, round }, + time_slot: TimeSlot { set_id, round }, session_index, offender, validator_set_count, diff --git a/frame/grandpa/src/lib.rs b/frame/grandpa/src/lib.rs index 2106860ea1441..538cd365b5a1a 100644 --- a/frame/grandpa/src/lib.rs +++ b/frame/grandpa/src/lib.rs @@ -63,7 +63,7 @@ mod mock; #[cfg(all(feature = "std", test))] mod tests; -pub use equivocation::{EquivocationOffence, EquivocationReportSystem, GrandpaTimeSlot}; +pub use equivocation::{EquivocationOffence, EquivocationReportSystem, TimeSlot}; pub use pallet::*; @@ -351,6 +351,7 @@ pub mod pallet { #[pallet::validate_unsigned] impl ValidateUnsigned for Pallet { type Call = Call; + fn validate_unsigned(source: TransactionSource, call: &Self::Call) -> TransactionValidity { Self::validate_unsigned(source, call) } diff --git a/frame/grandpa/src/mock.rs b/frame/grandpa/src/mock.rs index 22ca9c624c626..4e4f2f79d040e 100644 --- a/frame/grandpa/src/mock.rs +++ b/frame/grandpa/src/mock.rs @@ -224,13 +224,10 @@ parameter_types! { impl Config for Test { type RuntimeEvent = RuntimeEvent; - type WeightInfo = (); type MaxAuthorities = ConstU32<100>; type MaxSetIdSessionEntries = MaxSetIdSessionEntries; - type KeyOwnerProof = >::Proof; - type EquivocationReportSystem = super::EquivocationReportSystem; } diff --git a/frame/grandpa/src/tests.rs b/frame/grandpa/src/tests.rs index a956ca4bca6e9..16d89307bb71f 100644 --- a/frame/grandpa/src/tests.rs +++ b/frame/grandpa/src/tests.rs @@ -296,12 +296,12 @@ fn schedule_resume_only_when_paused() { #[test] fn time_slot_have_sane_ord() { // Ensure that `Ord` implementation is sane. - const FIXTURE: &[GrandpaTimeSlot] = &[ - GrandpaTimeSlot { set_id: 0, round: 0 }, - GrandpaTimeSlot { set_id: 0, round: 1 }, - GrandpaTimeSlot { set_id: 1, round: 0 }, - GrandpaTimeSlot { set_id: 1, round: 1 }, - GrandpaTimeSlot { set_id: 1, round: 2 }, + const FIXTURE: &[TimeSlot] = &[ + TimeSlot { set_id: 0, round: 0 }, + TimeSlot { set_id: 0, round: 1 }, + TimeSlot { set_id: 1, round: 0 }, + TimeSlot { set_id: 1, round: 1 }, + TimeSlot { set_id: 1, round: 2 }, ]; assert!(FIXTURE.windows(2).all(|f| f[0] < f[1])); } diff --git a/frame/offences/benchmarking/src/lib.rs b/frame/offences/benchmarking/src/lib.rs index 3db937bb378e5..0efbdcd48ecf3 100644 --- a/frame/offences/benchmarking/src/lib.rs +++ b/frame/offences/benchmarking/src/lib.rs @@ -38,7 +38,9 @@ use sp_staking::offence::{Offence, ReportOffence}; use pallet_babe::EquivocationOffence as BabeEquivocationOffence; use pallet_balances::Config as BalancesConfig; -use pallet_grandpa::{EquivocationOffence as GrandpaEquivocationOffence, GrandpaTimeSlot}; +use pallet_grandpa::{ + EquivocationOffence as GrandpaEquivocationOffence, TimeSlot as GrandpaTimeSlot, +}; use pallet_im_online::{Config as ImOnlineConfig, Pallet as ImOnline, UnresponsivenessOffence}; use pallet_offences::{Config as OffencesConfig, Pallet as Offences}; use pallet_session::{ From f5c2cecd7efe6dcbc828906794f3c4c41f23c791 Mon Sep 17 00:00:00 2001 From: Jegor Sidorenko <5252494+jsidorenko@users.noreply.github.com> Date: Mon, 13 Mar 2023 10:25:46 +0200 Subject: [PATCH 498/715] [NFTs] Rework permissions model (#13482) * Disallow admin to transfer or burn items he doesn't own * lock_collection should be accessible by collection's owner only * Allow admin to access lock_item_properties() * Fix do_lock_item_properties * Move update_mint_settings() to Issuer * Rename check_owner to check_origin * Typo * Make admin to be in charge of managing the metadata * Make admin the main attributes manager * offchain mint should be signed by Issuer * Remove the special case when the Issuer calls the mint() function * Rework burn and destroy methods * Return back item_metadatas * Don't repatriate the deposit on transfer * A bit more tests * One more test * Add migration * Chore * Clippy * Rename to owned_item * Address comments * Replace .filter_map with .find_map * Improve version validation in pre_upgrade() * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_nfts --------- Co-authored-by: parity-processbot <> --- frame/nfts/src/benchmarking.rs | 100 +- frame/nfts/src/features/approvals.rs | 12 +- frame/nfts/src/features/attributes.rs | 57 +- .../src/features/create_delete_collection.rs | 22 +- frame/nfts/src/features/create_delete_item.rs | 24 +- frame/nfts/src/features/lock.rs | 17 +- frame/nfts/src/features/metadata.rs | 66 +- frame/nfts/src/features/roles.rs | 15 + frame/nfts/src/features/settings.rs | 11 +- frame/nfts/src/features/transfer.rs | 10 - frame/nfts/src/lib.rs | 140 ++- frame/nfts/src/migration.rs | 117 ++ frame/nfts/src/tests.rs | 145 ++- frame/nfts/src/types.rs | 10 +- frame/nfts/src/weights.rs | 1028 ++++++++--------- 15 files changed, 970 insertions(+), 804 deletions(-) create mode 100644 frame/nfts/src/migration.rs diff --git a/frame/nfts/src/benchmarking.rs b/frame/nfts/src/benchmarking.rs index ae628fbefcce6..d4bbd809ce8be 100644 --- a/frame/nfts/src/benchmarking.rs +++ b/frame/nfts/src/benchmarking.rs @@ -72,6 +72,40 @@ fn add_collection_metadata, I: 'static>() -> (T::AccountId, Account fn mint_item, I: 'static>( index: u16, +) -> (T::ItemId, T::AccountId, AccountIdLookupOf) { + let item = T::Helper::item(index); + let collection = T::Helper::collection(0); + let caller = Collection::::get(collection).unwrap().owner; + if caller != whitelisted_caller() { + whitelist_account!(caller); + } + let caller_lookup = T::Lookup::unlookup(caller.clone()); + let item_exists = Item::::contains_key(&collection, &item); + let item_config = ItemConfigOf::::get(&collection, &item); + if item_exists { + return (item, caller, caller_lookup) + } else if let Some(item_config) = item_config { + assert_ok!(Nfts::::force_mint( + SystemOrigin::Signed(caller.clone()).into(), + collection, + item, + caller_lookup.clone(), + item_config, + )); + } else { + assert_ok!(Nfts::::mint( + SystemOrigin::Signed(caller.clone()).into(), + collection, + item, + caller_lookup.clone(), + None, + )); + } + (item, caller, caller_lookup) +} + +fn lock_item, I: 'static>( + index: u16, ) -> (T::ItemId, T::AccountId, AccountIdLookupOf) { let caller = Collection::::get(T::Helper::collection(0)).unwrap().owner; if caller != whitelisted_caller() { @@ -79,12 +113,27 @@ fn mint_item, I: 'static>( } let caller_lookup = T::Lookup::unlookup(caller.clone()); let item = T::Helper::item(index); - assert_ok!(Nfts::::mint( + assert_ok!(Nfts::::lock_item_transfer( + SystemOrigin::Signed(caller.clone()).into(), + T::Helper::collection(0), + item, + )); + (item, caller, caller_lookup) +} + +fn burn_item, I: 'static>( + index: u16, +) -> (T::ItemId, T::AccountId, AccountIdLookupOf) { + 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()); + let item = T::Helper::item(index); + assert_ok!(Nfts::::burn( SystemOrigin::Signed(caller.clone()).into(), T::Helper::collection(0), item, - caller_lookup.clone(), - None, )); (item, caller, caller_lookup) } @@ -126,6 +175,26 @@ fn add_item_attribute, I: 'static>( (key, caller, caller_lookup) } +fn add_collection_attribute, I: 'static>( + i: u16, +) -> (BoundedVec, T::AccountId, AccountIdLookupOf) { + 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()); + let key: BoundedVec<_, _> = make_filled_vec(i, T::KeyLimit::get() as usize).try_into().unwrap(); + assert_ok!(Nfts::::set_attribute( + SystemOrigin::Signed(caller.clone()).into(), + T::Helper::collection(0), + None, + AttributeNamespace::CollectionOwner, + key.clone(), + vec![0; T::ValueLimit::get() as usize].try_into().unwrap(), + )); + (key, caller, caller_lookup) +} + fn assert_last_event, I: 'static>(generic_event: >::RuntimeEvent) { let events = frame_system::Pallet::::events(); let system_event: ::RuntimeEvent = generic_event.into(); @@ -190,26 +259,25 @@ benchmarks_instance_pallet! { } destroy { - let n in 0 .. 1_000; let m in 0 .. 1_000; + let c in 0 .. 1_000; let a in 0 .. 1_000; let (collection, caller, _) = create_collection::(); add_collection_metadata::(); - for i in 0..n { - mint_item::(i as u16); - } for i in 0..m { - if !Item::::contains_key(collection, T::Helper::item(i as u16)) { - mint_item::(i as u16); - } + mint_item::(i as u16); add_item_metadata::(T::Helper::item(i as u16)); + lock_item::(i as u16); + burn_item::(i as u16); + } + for i in 0..c { + mint_item::(i as u16); + lock_item::(i as u16); + burn_item::(i as u16); } for i in 0..a { - if !Item::::contains_key(collection, T::Helper::item(i as u16)) { - mint_item::(i as u16); - } - add_item_attribute::(T::Helper::item(i as u16)); + add_collection_attribute::(i as u16); } let witness = Collection::::get(collection).unwrap().destroy_witness(); }: _(SystemOrigin::Signed(caller), collection, witness) @@ -234,9 +302,9 @@ benchmarks_instance_pallet! { } burn { - let (collection, caller, caller_lookup) = create_collection::(); + let (collection, caller, _) = create_collection::(); let (item, ..) = mint_item::(0); - }: _(SystemOrigin::Signed(caller.clone()), collection, item, Some(caller_lookup)) + }: _(SystemOrigin::Signed(caller.clone()), collection, item) verify { assert_last_event::(Event::Burned { collection, item, owner: caller }.into()); } diff --git a/frame/nfts/src/features/approvals.rs b/frame/nfts/src/features/approvals.rs index 408c441290fb4..634436a8562d8 100644 --- a/frame/nfts/src/features/approvals.rs +++ b/frame/nfts/src/features/approvals.rs @@ -40,9 +40,7 @@ impl, I: 'static> Pallet { ); if let Some(check_origin) = maybe_check_origin { - let is_admin = Self::has_role(&collection, &check_origin, CollectionRole::Admin); - let permitted = is_admin || check_origin == details.owner; - ensure!(permitted, Error::::NoPermission); + ensure!(check_origin == details.owner, Error::::NoPermission); } let now = frame_system::Pallet::::block_number(); @@ -85,9 +83,7 @@ impl, I: 'static> Pallet { if !is_past_deadline { if let Some(check_origin) = maybe_check_origin { - let is_admin = Self::has_role(&collection, &check_origin, CollectionRole::Admin); - let permitted = is_admin || check_origin == details.owner; - ensure!(permitted, Error::::NoPermission); + ensure!(check_origin == details.owner, Error::::NoPermission); } } @@ -113,9 +109,7 @@ impl, I: 'static> Pallet { Item::::get(&collection, &item).ok_or(Error::::UnknownCollection)?; if let Some(check_origin) = maybe_check_origin { - let is_admin = Self::has_role(&collection, &check_origin, CollectionRole::Admin); - let permitted = is_admin || check_origin == details.owner; - ensure!(permitted, Error::::NoPermission); + ensure!(check_origin == details.owner, Error::::NoPermission); } details.approvals.clear(); diff --git a/frame/nfts/src/features/attributes.rs b/frame/nfts/src/features/attributes.rs index fbd1c93247a52..9098679fa9145 100644 --- a/frame/nfts/src/features/attributes.rs +++ b/frame/nfts/src/features/attributes.rs @@ -33,17 +33,8 @@ impl, I: 'static> Pallet { Error::::MethodDisabled ); - let mut collection_details = - Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; - ensure!( - Self::is_valid_namespace( - &origin, - &namespace, - &collection, - &collection_details.owner, - &maybe_item, - )?, + Self::is_valid_namespace(&origin, &namespace, &collection, &maybe_item)?, Error::::NoPermission ); @@ -66,6 +57,9 @@ impl, I: 'static> Pallet { _ => (), } + let mut collection_details = + Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; + let attribute = Attribute::::get((collection, maybe_item, &namespace, &key)); let attribute_exists = attribute.is_some(); if !attribute_exists { @@ -219,7 +213,7 @@ impl, I: 'static> Pallet { } pub(crate) fn do_clear_attribute( - maybe_check_owner: Option, + maybe_check_origin: Option, collection: T::CollectionId, maybe_item: Option, namespace: AttributeNamespace, @@ -227,21 +221,13 @@ impl, I: 'static> Pallet { ) -> DispatchResult { let (_, deposit) = Attribute::::take((collection, maybe_item, &namespace, &key)) .ok_or(Error::::AttributeNotFound)?; - let mut collection_details = - Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; - if let Some(check_owner) = &maybe_check_owner { + if let Some(check_origin) = &maybe_check_origin { // validate the provided namespace when it's not a root call and the caller is not // the same as the `deposit.account` (e.g. the deposit was paid by different account) - if deposit.account != maybe_check_owner { + if deposit.account != maybe_check_origin { ensure!( - Self::is_valid_namespace( - &check_owner, - &namespace, - &collection, - &collection_details.owner, - &maybe_item, - )?, + Self::is_valid_namespace(&check_origin, &namespace, &collection, &maybe_item)?, Error::::NoPermission ); } @@ -264,17 +250,15 @@ impl, I: 'static> Pallet { .map_or(None, |c| { Some(c.has_disabled_setting(ItemSetting::UnlockedAttributes)) }); - match maybe_is_locked { - Some(is_locked) => { - // when item exists, then only the collection's owner can clear that - // attribute - ensure!( - check_owner == &collection_details.owner, - Error::::NoPermission - ); - ensure!(!is_locked, Error::::LockedItemAttributes); - }, - None => (), + if let Some(is_locked) = maybe_is_locked { + ensure!(!is_locked, Error::::LockedItemAttributes); + // Only the collection's admin can clear attributes in that namespace. + // e.g. in off-chain mints, the attribute's depositor will be the item's + // owner, that's why we need to do this extra check. + ensure!( + Self::has_role(&collection, &check_origin, CollectionRole::Admin), + Error::::NoPermission + ); } }, }, @@ -282,6 +266,9 @@ impl, I: 'static> Pallet { }; } + let mut collection_details = + Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; + collection_details.attributes.saturating_dec(); match deposit.account { @@ -372,12 +359,12 @@ impl, I: 'static> Pallet { origin: &T::AccountId, namespace: &AttributeNamespace, collection: &T::CollectionId, - collection_owner: &T::AccountId, maybe_item: &Option, ) -> Result { let mut result = false; match namespace { - AttributeNamespace::CollectionOwner => result = origin == collection_owner, + AttributeNamespace::CollectionOwner => + result = Self::has_role(&collection, &origin, CollectionRole::Admin), AttributeNamespace::ItemOwner => if let Some(item) = maybe_item { let item_details = diff --git a/frame/nfts/src/features/create_delete_collection.rs b/frame/nfts/src/features/create_delete_collection.rs index 8187fff7fca77..e9434760628ec 100644 --- a/frame/nfts/src/features/create_delete_collection.rs +++ b/frame/nfts/src/features/create_delete_collection.rs @@ -38,6 +38,7 @@ impl, I: 'static> Pallet { owner_deposit: deposit, items: 0, item_metadatas: 0, + item_configs: 0, attributes: 0, }, ); @@ -71,24 +72,23 @@ impl, I: 'static> Pallet { if let Some(check_owner) = maybe_check_owner { ensure!(collection_details.owner == check_owner, Error::::NoPermission); } - ensure!(collection_details.items == witness.items, Error::::BadWitness); + ensure!(collection_details.items == 0, Error::::CollectionNotEmpty); + ensure!(collection_details.attributes == witness.attributes, Error::::BadWitness); ensure!( collection_details.item_metadatas == witness.item_metadatas, Error::::BadWitness ); - ensure!(collection_details.attributes == witness.attributes, Error::::BadWitness); + ensure!( + collection_details.item_configs == witness.item_configs, + Error::::BadWitness + ); - for (item, details) in Item::::drain_prefix(&collection) { - Account::::remove((&details.owner, &collection, &item)); - T::Currency::unreserve(&details.deposit.account, details.deposit.amount); - } for (_, metadata) in ItemMetadataOf::::drain_prefix(&collection) { if let Some(depositor) = metadata.deposit.account { T::Currency::unreserve(&depositor, metadata.deposit.amount); } } - let _ = ItemPriceOf::::clear_prefix(&collection, witness.items, None); - let _ = PendingSwapOf::::clear_prefix(&collection, witness.items, None); + CollectionMetadataOf::::remove(&collection); Self::clear_roles(&collection)?; @@ -103,15 +103,13 @@ impl, I: 'static> Pallet { CollectionAccount::::remove(&collection_details.owner, &collection); T::Currency::unreserve(&collection_details.owner, collection_details.owner_deposit); CollectionConfigOf::::remove(&collection); - let _ = ItemConfigOf::::clear_prefix(&collection, witness.items, None); - let _ = - ItemAttributesApprovalsOf::::clear_prefix(&collection, witness.items, None); + let _ = ItemConfigOf::::clear_prefix(&collection, witness.item_configs, None); Self::deposit_event(Event::Destroyed { collection }); Ok(DestroyWitness { - items: collection_details.items, item_metadatas: collection_details.item_metadatas, + item_configs: collection_details.item_configs, attributes: collection_details.attributes, }) }) diff --git a/frame/nfts/src/features/create_delete_item.rs b/frame/nfts/src/features/create_delete_item.rs index 0319f2c8a0f18..cd96d28448055 100644 --- a/frame/nfts/src/features/create_delete_item.rs +++ b/frame/nfts/src/features/create_delete_item.rs @@ -66,6 +66,7 @@ impl, I: 'static> Pallet { ensure!(existing_config == item_config, Error::::InconsistentItemConfig); } else { ItemConfigOf::::insert(&collection, &item, item_config); + collection_details.item_configs.saturating_inc(); } T::Currency::reserve(&deposit_account, deposit_amount)?; @@ -107,7 +108,11 @@ impl, I: 'static> Pallet { let collection_details = Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; - ensure!(collection_details.owner == signer, Error::::NoPermission); + + ensure!( + Self::has_role(&collection, &signer, CollectionRole::Issuer), + Error::::NoPermission + ); let item_config = ItemConfig { settings: Self::get_default_item_settings(&collection)? }; Self::do_mint( @@ -118,9 +123,11 @@ impl, I: 'static> Pallet { item_config, |_, _| Ok(()), )?; + let origin = Self::find_account_by_role(&collection, CollectionRole::Admin) + .unwrap_or(collection_details.owner.clone()); for (key, value) in attributes { Self::do_set_attribute( - collection_details.owner.clone(), + origin.clone(), collection, Some(item), AttributeNamespace::CollectionOwner, @@ -131,7 +138,7 @@ impl, I: 'static> Pallet { } if !metadata.len().is_zero() { Self::do_set_item_metadata( - Some(collection_details.owner.clone()), + Some(origin.clone()), collection, item, metadata, @@ -148,6 +155,9 @@ impl, I: 'static> Pallet { ) -> DispatchResult { ensure!(!T::Locker::is_locked(collection, item), Error::::ItemLocked); let item_config = Self::get_item_config(&collection, &item)?; + // NOTE: if item's settings are not empty (e.g. item's metadata is locked) + // then we keep the config record and don't remove it + let remove_config = !item_config.has_disabled_settings(); let owner = Collection::::try_mutate( &collection, |maybe_collection_details| -> Result { @@ -161,6 +171,10 @@ impl, I: 'static> Pallet { T::Currency::unreserve(&details.deposit.account, details.deposit.amount); collection_details.items.saturating_dec(); + if remove_config { + collection_details.item_configs.saturating_dec(); + } + // Clear the metadata if it's not locked. if item_config.is_setting_enabled(ItemSetting::UnlockedMetadata) { if let Some(metadata) = ItemMetadataOf::::take(&collection, &item) { @@ -188,9 +202,7 @@ impl, I: 'static> Pallet { PendingSwapOf::::remove(&collection, &item); ItemAttributesApprovalsOf::::remove(&collection, &item); - // NOTE: if item's settings are not empty (e.g. item's metadata is locked) - // then we keep the record and don't remove it - if !item_config.has_disabled_settings() { + if remove_config { ItemConfigOf::::remove(&collection, &item); } diff --git a/frame/nfts/src/features/lock.rs b/frame/nfts/src/features/lock.rs index c28fdda983774..8b4914baeb450 100644 --- a/frame/nfts/src/features/lock.rs +++ b/frame/nfts/src/features/lock.rs @@ -24,10 +24,7 @@ impl, I: 'static> Pallet { collection: T::CollectionId, lock_settings: CollectionSettings, ) -> DispatchResult { - ensure!( - Self::has_role(&collection, &origin, CollectionRole::Freezer), - Error::::NoPermission - ); + ensure!(Self::collection_owner(collection) == Some(origin), Error::::NoPermission); ensure!( !lock_settings.is_disabled(CollectionSetting::DepositRequired), Error::::WrongSetting @@ -85,17 +82,17 @@ impl, I: 'static> Pallet { } pub(crate) fn do_lock_item_properties( - maybe_check_owner: Option, + maybe_check_origin: Option, collection: T::CollectionId, item: T::ItemId, lock_metadata: bool, lock_attributes: bool, ) -> DispatchResult { - let collection_details = - Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; - - if let Some(check_owner) = &maybe_check_owner { - ensure!(check_owner == &collection_details.owner, Error::::NoPermission); + if let Some(check_origin) = &maybe_check_origin { + ensure!( + Self::has_role(&collection, &check_origin, CollectionRole::Admin), + Error::::NoPermission + ); } ItemConfigOf::::try_mutate(collection, item, |maybe_config| { diff --git a/frame/nfts/src/features/metadata.rs b/frame/nfts/src/features/metadata.rs index 232262bdbb8fc..fde0296784d11 100644 --- a/frame/nfts/src/features/metadata.rs +++ b/frame/nfts/src/features/metadata.rs @@ -21,13 +21,20 @@ use frame_support::pallet_prelude::*; impl, I: 'static> Pallet { /// Note: if `maybe_depositor` is None, that means the depositor will be a collection's owner pub(crate) fn do_set_item_metadata( - maybe_check_owner: Option, + maybe_check_origin: Option, collection: T::CollectionId, item: T::ItemId, data: BoundedVec, maybe_depositor: Option, ) -> DispatchResult { - let is_root = maybe_check_owner.is_none(); + if let Some(check_origin) = &maybe_check_origin { + ensure!( + Self::has_role(&collection, &check_origin, CollectionRole::Admin), + Error::::NoPermission + ); + } + + let is_root = maybe_check_origin.is_none(); let mut collection_details = Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; @@ -37,10 +44,6 @@ impl, I: 'static> Pallet { Error::::LockedItemMetadata ); - if let Some(check_owner) = &maybe_check_owner { - ensure!(check_owner == &collection_details.owner, Error::::NoPermission); - } - let collection_config = Self::get_collection_config(&collection)?; ItemMetadataOf::::try_mutate_exists(collection, item, |metadata| { @@ -89,22 +92,26 @@ impl, I: 'static> Pallet { } pub(crate) fn do_clear_item_metadata( - maybe_check_owner: Option, + maybe_check_origin: Option, collection: T::CollectionId, item: T::ItemId, ) -> DispatchResult { - let is_root = maybe_check_owner.is_none(); + if let Some(check_origin) = &maybe_check_origin { + ensure!( + Self::has_role(&collection, &check_origin, CollectionRole::Admin), + Error::::NoPermission + ); + } + + let is_root = maybe_check_origin.is_none(); let metadata = ItemMetadataOf::::take(collection, item) .ok_or(Error::::MetadataNotFound)?; let mut collection_details = Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; + let depositor_account = metadata.deposit.account.unwrap_or(collection_details.owner.clone()); - if let Some(check_owner) = &maybe_check_owner { - ensure!(check_owner == &collection_details.owner, Error::::NoPermission); - } - // NOTE: if the item was previously burned, the ItemConfigOf record might not exist let is_locked = Self::get_item_config(&collection, &item) .map_or(false, |c| c.has_disabled_setting(ItemSetting::UnlockedMetadata)); @@ -125,29 +132,32 @@ impl, I: 'static> Pallet { } pub(crate) fn do_set_collection_metadata( - maybe_check_owner: Option, + maybe_check_origin: Option, collection: T::CollectionId, data: BoundedVec, ) -> DispatchResult { + if let Some(check_origin) = &maybe_check_origin { + ensure!( + Self::has_role(&collection, &check_origin, CollectionRole::Admin), + Error::::NoPermission + ); + } + + let is_root = maybe_check_origin.is_none(); let collection_config = Self::get_collection_config(&collection)?; ensure!( - maybe_check_owner.is_none() || - collection_config.is_setting_enabled(CollectionSetting::UnlockedMetadata), + is_root || collection_config.is_setting_enabled(CollectionSetting::UnlockedMetadata), Error::::LockedCollectionMetadata ); 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); - } CollectionMetadataOf::::try_mutate_exists(collection, |metadata| { let old_deposit = metadata.take().map_or(Zero::zero(), |m| m.deposit); details.owner_deposit.saturating_reduce(old_deposit); let mut deposit = Zero::zero(); - if maybe_check_owner.is_some() && - collection_config.is_setting_enabled(CollectionSetting::DepositRequired) + if !is_root && collection_config.is_setting_enabled(CollectionSetting::DepositRequired) { deposit = T::DepositPerByte::get() .saturating_mul(((data.len()) as u32).into()) @@ -170,18 +180,22 @@ impl, I: 'static> Pallet { } pub(crate) fn do_clear_collection_metadata( - maybe_check_owner: Option, + maybe_check_origin: Option, collection: T::CollectionId, ) -> DispatchResult { - let details = - Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; - if let Some(check_owner) = &maybe_check_owner { - ensure!(check_owner == &details.owner, Error::::NoPermission); + if let Some(check_origin) = &maybe_check_origin { + ensure!( + Self::has_role(&collection, &check_origin, CollectionRole::Admin), + Error::::NoPermission + ); } + let details = + Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; let collection_config = Self::get_collection_config(&collection)?; + ensure!( - maybe_check_owner.is_none() || + maybe_check_origin.is_none() || collection_config.is_setting_enabled(CollectionSetting::UnlockedMetadata), Error::::LockedCollectionMetadata ); diff --git a/frame/nfts/src/features/roles.rs b/frame/nfts/src/features/roles.rs index f3fa277b15617..f91f3ecb6f348 100644 --- a/frame/nfts/src/features/roles.rs +++ b/frame/nfts/src/features/roles.rs @@ -82,6 +82,21 @@ impl, I: 'static> Pallet { .map_or(false, |roles| roles.has_role(role)) } + /// Finds the account by a provided role within a collection. + /// + /// - `collection_id`: A collection to check the role in. + /// - `role`: A role to find the account for. + /// + /// Returns `Some(T::AccountId)` if the record was found, `None` otherwise. + pub(crate) fn find_account_by_role( + collection_id: &T::CollectionId, + role: CollectionRole, + ) -> Option { + CollectionRoleOf::::iter_prefix(&collection_id).into_iter().find_map( + |(account, roles)| if roles.has_role(role) { Some(account.clone()) } else { None }, + ) + } + /// Groups provided roles by account, given one account could have multiple roles. /// /// - `input`: A vector of (Account, Role) tuples. diff --git a/frame/nfts/src/features/settings.rs b/frame/nfts/src/features/settings.rs index 91bff9dc683f8..080d7b97f13b1 100644 --- a/frame/nfts/src/features/settings.rs +++ b/frame/nfts/src/features/settings.rs @@ -57,7 +57,7 @@ impl, I: 'static> Pallet { } pub(crate) fn do_update_mint_settings( - maybe_check_owner: Option, + maybe_check_origin: Option, collection: T::CollectionId, mint_settings: MintSettings< BalanceOf, @@ -65,10 +65,11 @@ impl, I: 'static> Pallet { T::CollectionId, >, ) -> DispatchResult { - let details = - Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; - if let Some(check_owner) = &maybe_check_owner { - ensure!(check_owner == &details.owner, Error::::NoPermission); + if let Some(check_origin) = &maybe_check_origin { + ensure!( + Self::has_role(&collection, &check_origin, CollectionRole::Issuer), + Error::::NoPermission + ); } CollectionConfigOf::::try_mutate(collection, |maybe_config| { diff --git a/frame/nfts/src/features/transfer.rs b/frame/nfts/src/features/transfer.rs index 998df81cd1fe1..00b5d4e76882a 100644 --- a/frame/nfts/src/features/transfer.rs +++ b/frame/nfts/src/features/transfer.rs @@ -48,16 +48,6 @@ impl, I: 'static> Pallet { Item::::get(&collection, &item).ok_or(Error::::UnknownItem)?; with_details(&collection_details, &mut details)?; - if details.deposit.account == details.owner { - // Move the deposit to the new owner. - T::Currency::repatriate_reserved( - &details.owner, - &dest, - details.deposit.amount, - Reserved, - )?; - } - Account::::remove((&details.owner, &collection, &item)); Account::::insert((&dest, &collection, &item), ()); let origin = details.owner; diff --git a/frame/nfts/src/lib.rs b/frame/nfts/src/lib.rs index 2d19cf0455ad4..4d9547659a2a7 100644 --- a/frame/nfts/src/lib.rs +++ b/frame/nfts/src/lib.rs @@ -30,6 +30,7 @@ #[cfg(feature = "runtime-benchmarks")] mod benchmarking; +pub mod migration; #[cfg(test)] pub mod mock; #[cfg(test)] @@ -58,6 +59,9 @@ pub use pallet::*; pub use types::*; pub use weights::WeightInfo; +/// The log target of this pallet. +pub const LOG_TARGET: &'static str = "runtime::nfts"; + type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; #[frame_support::pallet] @@ -67,9 +71,13 @@ pub mod pallet { use frame_system::pallet_prelude::*; use sp_runtime::traits::{IdentifyAccount, Verify}; + /// The current storage version. + const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); + #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] - pub struct Pallet(_); + #[pallet::storage_version(STORAGE_VERSION)] + pub struct Pallet(PhantomData<(T, I)>); #[cfg(feature = "runtime-benchmarks")] pub trait BenchmarkHelper { @@ -628,6 +636,8 @@ pub mod pallet { MaxAttributesLimitReached, /// The provided namespace isn't supported in this call. WrongNamespace, + /// Can't delete non-empty collections. + CollectionNotEmpty, } #[pallet::call] @@ -719,20 +729,22 @@ pub mod pallet { /// The origin must conform to `ForceOrigin` or must be `Signed` and the sender must be the /// owner of the `collection`. /// + /// NOTE: The collection must have 0 items to be destroyed. + /// /// - `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.items` + /// Weight: `O(m + c + a)` where: /// - `m = witness.item_metadatas` + /// - `c = witness.item_configs` /// - `a = witness.attributes` #[pallet::call_index(2)] #[pallet::weight(T::WeightInfo::destroy( - witness.items, - witness.item_metadatas, + witness.item_metadatas, + witness.item_configs, witness.attributes, ))] pub fn destroy( @@ -746,8 +758,8 @@ pub mod pallet { let details = Self::do_destroy_collection(collection, witness, maybe_check_owner)?; Ok(Some(T::WeightInfo::destroy( - details.items, details.item_metadatas, + details.item_configs, details.attributes, )) .into()) @@ -755,7 +767,7 @@ pub mod pallet { /// Mint an item of a particular collection. /// - /// The origin must be Signed and the sender must be the Issuer of the `collection`. + /// The origin must be Signed and the sender must comply with the `mint_settings` rules. /// /// - `collection`: The collection of the item to be minted. /// - `item`: An identifier of the new item. @@ -789,11 +801,6 @@ pub mod pallet { mint_to.clone(), item_config, |collection_details, collection_config| { - // Issuer can mint regardless of mint settings - if Self::has_role(&collection, &caller, CollectionRole::Issuer) { - return Ok(()) - } - let mint_settings = collection_config.mint_settings; let now = frame_system::Pallet::::block_number(); @@ -805,7 +812,12 @@ pub mod pallet { } match mint_settings.mint_type { - MintType::Issuer => return Err(Error::::NoPermission.into()), + MintType::Issuer => { + ensure!( + Self::has_role(&collection, &caller, CollectionRole::Issuer), + Error::::NoPermission + ); + }, MintType::HolderOf(collection_id) => { let MintWitness { owned_item } = witness_data.ok_or(Error::::BadWitness)?; @@ -899,38 +911,30 @@ pub mod pallet { /// Destroy a single item. /// - /// Origin must be Signed and the signing account must be either: - /// - the Admin of the `collection`; - /// - the Owner of the `item`; + /// The origin must conform to `ForceOrigin` or must be Signed and the signing account must + /// be the owner of the `item`. /// /// - `collection`: The collection of the item to be burned. /// - `item`: The item to be burned. - /// - `check_owner`: If `Some` then the operation will fail with `WrongOwner` unless the - /// item is owned by this value. /// - /// Emits `Burned` with the actual amount burned. + /// Emits `Burned`. /// /// Weight: `O(1)` - /// Modes: `check_owner.is_some()`. #[pallet::call_index(5)] #[pallet::weight(T::WeightInfo::burn())] pub fn burn( origin: OriginFor, collection: T::CollectionId, item: T::ItemId, - check_owner: Option>, ) -> DispatchResult { - let origin = ensure_signed(origin)?; - let check_owner = check_owner.map(T::Lookup::lookup).transpose()?; + let maybe_check_origin = T::ForceOrigin::try_origin(origin) + .map(|_| None) + .or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?; Self::do_burn(collection, item, |details| { - let is_admin = Self::has_role(&collection, &origin, CollectionRole::Admin); - let is_permitted = is_admin || details.owner == origin; - ensure!(is_permitted, Error::::NoPermission); - ensure!( - check_owner.map_or(true, |o| o == details.owner), - Error::::WrongOwner - ); + if let Some(check_origin) = maybe_check_origin { + ensure!(details.owner == check_origin, Error::::NoPermission); + } Ok(()) }) } @@ -938,7 +942,6 @@ pub mod pallet { /// Move an item from the sender account to another. /// /// Origin must be Signed and the signing account must be either: - /// - the Admin of the `collection`; /// - the Owner of the `item`; /// - the approved delegate for the `item` (in this case, the approval is reset). /// @@ -962,8 +965,7 @@ pub mod pallet { let dest = T::Lookup::lookup(dest)?; Self::do_transfer(collection, item, dest, |_, details| { - let is_admin = Self::has_role(&collection, &origin, CollectionRole::Admin); - if details.owner != origin && !is_admin { + if details.owner != origin { let deadline = details.approvals.get(&origin).ok_or(Error::::NoPermission)?; if let Some(d) = deadline { @@ -1086,12 +1088,13 @@ pub mod pallet { /// Disallows specified settings for the whole collection. /// - /// Origin must be Signed and the sender should be the Freezer of the `collection`. + /// Origin must be Signed and the sender should be the Owner of the `collection`. /// /// - `collection`: The collection to be locked. /// - `lock_settings`: The settings to be locked. /// /// Note: it's possible to only lock(set) the setting, but not to unset it. + /// /// Emits `CollectionLocked`. /// /// Weight: `O(1)` @@ -1243,7 +1246,6 @@ pub mod pallet { /// /// Origin must be either: /// - the `Force` origin; - /// - `Signed` with the signer being the Admin of the `collection`; /// - `Signed` with the signer being the Owner of the `item`; /// /// Arguments: @@ -1273,7 +1275,6 @@ pub mod pallet { /// /// Origin must be either: /// - the `Force` origin; - /// - `Signed` with the signer being the Admin of the `collection`; /// - `Signed` with the signer being the Owner of the `item`; /// /// Arguments: @@ -1298,8 +1299,8 @@ pub mod pallet { /// Disallows changing the metadata or attributes of the item. /// - /// Origin must be either `ForceOrigin` or Signed and the sender should be the Owner of the - /// `collection`. + /// Origin must be either `ForceOrigin` or Signed and the sender should be the Admin + /// of the `collection`. /// /// - `collection`: The collection if the `item`. /// - `item`: An item to be locked. @@ -1307,8 +1308,8 @@ pub mod pallet { /// - `lock_attributes`: Specifies whether the attributes in the `CollectionOwner` namespace /// should be locked. /// - /// Note: `lock_attributes` affects the attributes in the `CollectionOwner` namespace - /// only. When the metadata or attributes are locked, it won't be possible the unlock them. + /// Note: `lock_attributes` affects the attributes in the `CollectionOwner` namespace only. + /// When the metadata or attributes are locked, it won't be possible the unlock them. /// /// Emits `ItemPropertiesLocked`. /// @@ -1322,11 +1323,11 @@ pub mod pallet { lock_metadata: bool, lock_attributes: bool, ) -> DispatchResult { - let maybe_check_owner = T::ForceOrigin::try_origin(origin) + let maybe_check_origin = T::ForceOrigin::try_origin(origin) .map(|_| None) .or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?; Self::do_lock_item_properties( - maybe_check_owner, + maybe_check_origin, collection, item, lock_metadata, @@ -1337,7 +1338,7 @@ pub mod pallet { /// Set an attribute for a collection or item. /// /// Origin must be Signed and must conform to the namespace ruleset: - /// - `CollectionOwner` namespace could be modified by the `collection` owner only; + /// - `CollectionOwner` namespace could be modified by the `collection` Admin only; /// - `ItemOwner` namespace could be modified by the `maybe_item` owner only. `maybe_item` /// should be set in that case; /// - `Account(AccountId)` namespace could be modified only when the `origin` was given a @@ -1367,15 +1368,12 @@ pub mod pallet { value: BoundedVec, ) -> DispatchResult { let origin = ensure_signed(origin)?; - Self::do_set_attribute( - origin.clone(), - collection, - maybe_item, - namespace, - key, - value, - origin, - ) + let depositor = match namespace { + AttributeNamespace::CollectionOwner => + Self::collection_owner(collection).ok_or(Error::::UnknownCollection)?, + _ => origin.clone(), + }; + Self::do_set_attribute(origin, collection, maybe_item, namespace, key, value, depositor) } /// Force-set an attribute for a collection or item. @@ -1490,7 +1488,7 @@ pub mod pallet { /// Set the metadata for an item. /// - /// Origin must be either `ForceOrigin` or Signed and the sender should be the Owner of the + /// Origin must be either `ForceOrigin` or Signed and the sender should be the Admin of the /// `collection`. /// /// If the origin is Signed, then funds of signer are reserved according to the formula: @@ -1512,15 +1510,15 @@ pub mod pallet { item: T::ItemId, data: BoundedVec, ) -> DispatchResult { - let maybe_check_owner = T::ForceOrigin::try_origin(origin) + let maybe_check_origin = T::ForceOrigin::try_origin(origin) .map(|_| None) .or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?; - Self::do_set_item_metadata(maybe_check_owner, collection, item, data, None) + Self::do_set_item_metadata(maybe_check_origin, collection, item, data, None) } /// Clear the metadata for an item. /// - /// Origin must be either `ForceOrigin` or Signed and the sender should be the Owner of the + /// Origin must be either `ForceOrigin` or Signed and the sender should be the Admin of the /// `collection`. /// /// Any deposit is freed for the collection's owner. @@ -1538,15 +1536,15 @@ pub mod pallet { collection: T::CollectionId, item: T::ItemId, ) -> DispatchResult { - let maybe_check_owner = T::ForceOrigin::try_origin(origin) + let maybe_check_origin = T::ForceOrigin::try_origin(origin) .map(|_| None) .or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?; - Self::do_clear_item_metadata(maybe_check_owner, collection, item) + Self::do_clear_item_metadata(maybe_check_origin, collection, item) } /// Set the metadata for a collection. /// - /// Origin must be either `ForceOrigin` or `Signed` and the sender should be the Owner of + /// Origin must be either `ForceOrigin` or `Signed` and the sender should be the Admin of /// the `collection`. /// /// If the origin is `Signed`, then funds of signer are reserved according to the formula: @@ -1566,15 +1564,15 @@ pub mod pallet { collection: T::CollectionId, data: BoundedVec, ) -> DispatchResult { - let maybe_check_owner = T::ForceOrigin::try_origin(origin) + let maybe_check_origin = T::ForceOrigin::try_origin(origin) .map(|_| None) .or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?; - Self::do_set_collection_metadata(maybe_check_owner, collection, data) + Self::do_set_collection_metadata(maybe_check_origin, collection, data) } /// Clear the metadata for a collection. /// - /// Origin must be either `ForceOrigin` or `Signed` and the sender should be the Owner of + /// Origin must be either `ForceOrigin` or `Signed` and the sender should be the Admin of /// the `collection`. /// /// Any deposit is freed for the collection's owner. @@ -1590,10 +1588,10 @@ pub mod pallet { origin: OriginFor, collection: T::CollectionId, ) -> DispatchResult { - let maybe_check_owner = T::ForceOrigin::try_origin(origin) + let maybe_check_origin = T::ForceOrigin::try_origin(origin) .map(|_| None) .or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?; - Self::do_clear_collection_metadata(maybe_check_owner, collection) + Self::do_clear_collection_metadata(maybe_check_origin, collection) } /// Set (or reset) the acceptance of ownership for a particular account. @@ -1640,8 +1638,8 @@ pub mod pallet { /// Update mint settings. /// - /// Origin must be either `ForceOrigin` or `Signed` and the sender should be the Owner of - /// the `collection`. + /// Origin must be either `ForceOrigin` or `Signed` and the sender should be the Issuer + /// of the `collection`. /// /// - `collection`: The identifier of the collection to change. /// - `mint_settings`: The new mint settings. @@ -1658,15 +1656,15 @@ pub mod pallet { T::CollectionId, >, ) -> DispatchResult { - let maybe_check_owner = T::ForceOrigin::try_origin(origin) + let maybe_check_origin = T::ForceOrigin::try_origin(origin) .map(|_| None) .or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?; - Self::do_update_mint_settings(maybe_check_owner, collection, mint_settings) + Self::do_update_mint_settings(maybe_check_origin, collection, mint_settings) } /// Set (or reset) the price for an item. /// - /// Origin must be Signed and must be the owner of the asset `item`. + /// Origin must be Signed and must be the owner of the `item`. /// /// - `collection`: The collection of the item. /// - `item`: The item to set the price for. @@ -1827,7 +1825,7 @@ pub mod pallet { /// its metadata, attributes, who can mint it (`None` for anyone) and until what block /// number. /// - `signature`: The signature of the `data` object. - /// - `signer`: The `data` object's signer. Should be an owner of the collection. + /// - `signer`: The `data` object's signer. Should be an Issuer of the collection. /// /// Emits `Issued` on success. /// Emits `AttributeSet` if the attributes were provided. @@ -1853,7 +1851,7 @@ pub mod pallet { /// - `data`: The pre-signed approval that consists of the information about the item, /// attributes to update and until what block number. /// - `signature`: The signature of the `data` object. - /// - `signer`: The `data` object's signer. Should be an owner of the collection for the + /// - `signer`: The `data` object's signer. Should be an Admin of the collection for the /// `CollectionOwner` namespace. /// /// Emits `AttributeSet` for each provided attribute. diff --git a/frame/nfts/src/migration.rs b/frame/nfts/src/migration.rs new file mode 100644 index 0000000000000..33ee87e4b9284 --- /dev/null +++ b/frame/nfts/src/migration.rs @@ -0,0 +1,117 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT 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 OldCollectionDetails { + pub owner: AccountId, + pub owner_deposit: DepositBalance, + pub items: u32, + pub item_metadatas: u32, + pub attributes: u32, + } + + impl OldCollectionDetails { + fn migrate_to_v1(self, item_configs: u32) -> CollectionDetails { + CollectionDetails { + owner: self.owner, + owner_deposit: self.owner_deposit, + items: self.items, + item_metadatas: self.item_metadatas, + item_configs, + attributes: self.attributes, + } + } + } + + 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(); + + log::info!( + target: LOG_TARGET, + "Running migration with current storage version {:?} / onchain {:?}", + current_version, + onchain_version + ); + + if onchain_version == 0 && current_version == 1 { + let mut translated = 0u64; + let mut configs_iterated = 0u64; + Collection::::translate::< + OldCollectionDetails>, + _, + >(|key, old_value| { + let item_configs = ItemConfigOf::::iter_prefix(&key).count() as u32; + configs_iterated += item_configs as u64; + translated.saturating_inc(); + Some(old_value.migrate_to_v1(item_configs)) + }); + + current_version.put::>(); + + log::info!( + target: LOG_TARGET, + "Upgraded {} records, storage to version {:?}", + translated, + current_version + ); + T::DbWeight::get().reads_writes(translated + configs_iterated + 1, translated + 1) + } else { + log::info!( + target: LOG_TARGET, + "Migration did not execute. This probably should be removed" + ); + T::DbWeight::get().reads(1) + } + } + + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, &'static str> { + let current_version = Pallet::::current_storage_version(); + let onchain_version = Pallet::::on_chain_storage_version(); + ensure!(onchain_version == 0 && current_version == 1, "migration from version 0 to 1."); + let prev_count = Collection::::iter().count(); + Ok((prev_count as u32).encode()) + } + + #[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 = Collection::::iter().count() as u32; + assert_eq!( + prev_count, post_count, + "the records count before and after the migration should be the same" + ); + + ensure!(Pallet::::on_chain_storage_version() == 1, "wrong storage version"); + + Ok(()) + } + } +} diff --git a/frame/nfts/src/tests.rs b/frame/nfts/src/tests.rs index e44e4151f84a0..694468aceebe5 100644 --- a/frame/nfts/src/tests.rs +++ b/frame/nfts/src/tests.rs @@ -215,21 +215,44 @@ fn lifecycle_should_work() { assert_eq!(items(), vec![(account(1), 0, 70), (account(10), 0, 42), (account(20), 0, 69)]); assert_eq!(Collection::::get(0).unwrap().items, 3); assert_eq!(Collection::::get(0).unwrap().item_metadatas, 0); + assert_eq!(Collection::::get(0).unwrap().item_configs, 3); - assert_eq!(Balances::reserved_balance(&account(2)), 0); + assert_eq!(Balances::reserved_balance(&account(1)), 8); assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(1)), 0, 70, account(2))); - assert_eq!(Balances::reserved_balance(&account(2)), 1); + assert_eq!(Balances::reserved_balance(&account(1)), 8); + assert_eq!(Balances::reserved_balance(&account(2)), 0); assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(account(1)), 0, 42, bvec![42, 42])); - assert_eq!(Balances::reserved_balance(&account(1)), 10); + assert_eq!(Balances::reserved_balance(&account(1)), 11); assert!(ItemMetadataOf::::contains_key(0, 42)); assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(account(1)), 0, 69, bvec![69, 69])); - assert_eq!(Balances::reserved_balance(&account(1)), 13); + assert_eq!(Balances::reserved_balance(&account(1)), 14); assert!(ItemMetadataOf::::contains_key(0, 69)); - + assert!(ItemConfigOf::::contains_key(0, 69)); let w = Nfts::get_destroy_witness(&0).unwrap(); - assert_eq!(w.items, 3); assert_eq!(w.item_metadatas, 2); + assert_eq!(w.item_configs, 3); + assert_noop!( + Nfts::destroy(RuntimeOrigin::signed(account(1)), 0, w), + Error::::CollectionNotEmpty + ); + + assert_ok!(Nfts::set_attribute( + RuntimeOrigin::signed(account(1)), + 0, + Some(69), + AttributeNamespace::CollectionOwner, + bvec![0], + bvec![0], + )); + assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(10)), 0, 42)); + assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(20)), 0, 69)); + assert_ok!(Nfts::burn(RuntimeOrigin::root(), 0, 70)); + + let w = Nfts::get_destroy_witness(&0).unwrap(); + assert_eq!(w.attributes, 1); + assert_eq!(w.item_metadatas, 0); + assert_eq!(w.item_configs, 0); assert_ok!(Nfts::destroy(RuntimeOrigin::signed(account(1)), 0, w)); assert_eq!(Balances::reserved_balance(&account(1)), 0); @@ -240,6 +263,8 @@ fn lifecycle_should_work() { assert!(!CollectionMetadataOf::::contains_key(0)); assert!(!ItemMetadataOf::::contains_key(0, 42)); assert!(!ItemMetadataOf::::contains_key(0, 69)); + assert!(!ItemConfigOf::::contains_key(0, 69)); + assert_eq!(attributes(0), vec![]); assert_eq!(collections(), vec![]); assert_eq!(items(), vec![]); }); @@ -256,14 +281,51 @@ fn destroy_with_bad_witness_should_not_work() { )); let w = Collection::::get(0).unwrap().destroy_witness(); - assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 42, account(1), None)); assert_noop!( - Nfts::destroy(RuntimeOrigin::signed(account(1)), 0, w), + Nfts::destroy( + RuntimeOrigin::signed(account(1)), + 0, + DestroyWitness { item_configs: 1, ..w } + ), Error::::BadWitness ); }); } +#[test] +fn destroy_should_work() { + new_test_ext().execute_with(|| { + Balances::make_free_balance_be(&account(1), 100); + assert_ok!(Nfts::create( + RuntimeOrigin::signed(account(1)), + account(1), + collection_config_with_all_settings_enabled() + )); + + assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 42, account(2), None)); + assert_noop!( + Nfts::destroy( + RuntimeOrigin::signed(account(1)), + 0, + Nfts::get_destroy_witness(&0).unwrap() + ), + Error::::CollectionNotEmpty + ); + assert_ok!(Nfts::lock_item_transfer(RuntimeOrigin::signed(account(1)), 0, 42)); + assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(2)), 0, 42)); + assert_eq!(Collection::::get(0).unwrap().item_configs, 1); + assert_eq!(ItemConfigOf::::iter_prefix(0).count() as u32, 1); + assert!(ItemConfigOf::::contains_key(0, 42)); + assert_ok!(Nfts::destroy( + RuntimeOrigin::signed(account(1)), + 0, + Nfts::get_destroy_witness(&0).unwrap() + )); + assert!(!ItemConfigOf::::contains_key(0, 42)); + assert_eq!(ItemConfigOf::::iter_prefix(0).count() as u32, 0); + }); +} + #[test] fn mint_should_work() { new_test_ext().execute_with(|| { @@ -491,8 +553,9 @@ fn origin_guards_should_work() { Nfts::mint(RuntimeOrigin::signed(account(2)), 0, 69, account(2), None), Error::::NoPermission ); + assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 43, account(2), None)); assert_noop!( - Nfts::burn(RuntimeOrigin::signed(account(2)), 0, 42, None), + Nfts::burn(RuntimeOrigin::signed(account(1)), 0, 43), Error::::NoPermission ); let w = Nfts::get_destroy_witness(&0).unwrap(); @@ -536,13 +599,13 @@ fn transfer_owner_should_work() { // Mint and set metadata now and make sure that deposit gets transferred back. assert_ok!(Nfts::set_collection_metadata( - RuntimeOrigin::signed(account(2)), + RuntimeOrigin::signed(account(1)), 0, bvec![0u8; 20], )); assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 42, account(1), None)); assert_eq!(Balances::reserved_balance(&account(1)), 1); - assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(account(2)), 0, 42, bvec![0u8; 20])); + assert_ok!(Nfts::set_metadata(RuntimeOrigin::signed(account(1)), 0, 42, bvec![0u8; 20])); assert_ok!(Nfts::set_accept_ownership(RuntimeOrigin::signed(account(3)), Some(0))); assert_ok!(Nfts::transfer_ownership(RuntimeOrigin::signed(account(2)), 0, account(3))); assert_eq!(collections(), vec![(account(3), 0)]); @@ -552,8 +615,9 @@ fn transfer_owner_should_work() { assert_eq!(Balances::reserved_balance(&account(3)), 44); assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(1)), 0, 42, account(2))); - assert_eq!(Balances::reserved_balance(&account(1)), 0); - assert_eq!(Balances::reserved_balance(&account(2)), 1); + // reserved_balance of accounts 1 & 2 should be unchanged: + assert_eq!(Balances::reserved_balance(&account(1)), 1); + assert_eq!(Balances::reserved_balance(&account(2)), 0); // 2's acceptance from before is reset when it became an owner, so it cannot be transferred // without a fresh acceptance. @@ -583,8 +647,14 @@ fn set_team_should_work() { assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(2)), 0, 42, account(2), None)); assert_ok!(Nfts::lock_item_transfer(RuntimeOrigin::signed(account(4)), 0, 42)); assert_ok!(Nfts::unlock_item_transfer(RuntimeOrigin::signed(account(4)), 0, 42)); - assert_ok!(Nfts::transfer(RuntimeOrigin::signed(account(3)), 0, 42, account(3))); - assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(3)), 0, 42, None)); + assert_noop!( + Nfts::transfer(RuntimeOrigin::signed(account(3)), 0, 42, account(3)), + Error::::NoPermission + ); + assert_noop!( + Nfts::burn(RuntimeOrigin::signed(account(3)), 0, 42), + Error::::NoPermission + ); }); } @@ -594,7 +664,7 @@ fn set_collection_metadata_should_work() { // Cannot add metadata to unknown item assert_noop!( Nfts::set_collection_metadata(RuntimeOrigin::signed(account(1)), 0, bvec![0u8; 20]), - Error::::NoConfig, + Error::::NoPermission, ); assert_ok!(Nfts::force_create( RuntimeOrigin::root(), @@ -668,7 +738,7 @@ fn set_collection_metadata_should_work() { ); assert_noop!( Nfts::clear_collection_metadata(RuntimeOrigin::signed(account(1)), 1), - Error::::UnknownCollection + Error::::NoPermission ); assert_noop!( Nfts::clear_collection_metadata(RuntimeOrigin::signed(account(1)), 0), @@ -743,7 +813,7 @@ fn set_item_metadata_should_work() { ); assert_noop!( Nfts::clear_metadata(RuntimeOrigin::signed(account(1)), 1, 42), - Error::::MetadataNotFound, + Error::::NoPermission, ); assert_ok!(Nfts::clear_metadata(RuntimeOrigin::root(), 0, 42)); assert!(!ItemMetadataOf::::contains_key(0, 42)); @@ -832,6 +902,7 @@ fn set_collection_owner_attributes_should_work() { ); assert_eq!(Balances::reserved_balance(account(1)), 16); + assert_ok!(Nfts::burn(RuntimeOrigin::root(), 0, 0)); let w = Nfts::get_destroy_witness(&0).unwrap(); assert_ok!(Nfts::destroy(RuntimeOrigin::signed(account(1)), 0, w)); assert_eq!(attributes(0), vec![]); @@ -997,7 +1068,7 @@ fn set_item_owner_attributes_should_work() { assert_eq!(Balances::reserved_balance(account(3)), 13); // validate attributes on item deletion - assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(3)), 0, 0, None)); + assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(3)), 0, 0)); assert_eq!( attributes(0), vec![ @@ -1317,7 +1388,7 @@ fn preserve_config_for_frozen_items() { assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(1)), 0, 1, account(1), None)); // if the item is not locked/frozen then the config gets deleted on item burn - assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(1)), 0, 1, Some(account(1)))); + assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(1)), 0, 1)); assert!(!ItemConfigOf::::contains_key(0, 1)); // lock the item and ensure the config stays unchanged @@ -1329,7 +1400,7 @@ fn preserve_config_for_frozen_items() { let config = ItemConfigOf::::get(0, 0).unwrap(); assert_eq!(config, expect_config); - assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(1)), 0, 0, Some(account(1)))); + assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(1)), 0, 0)); let config = ItemConfigOf::::get(0, 0).unwrap(); assert_eq!(config, expect_config); @@ -1405,6 +1476,7 @@ fn force_update_collection_should_work() { Balances::make_free_balance_be(&account(5), 100); assert_ok!(Nfts::force_collection_owner(RuntimeOrigin::root(), 0, account(5))); + assert_ok!(Nfts::set_team(RuntimeOrigin::root(), 0, account(2), account(5), account(4))); assert_eq!(collections(), vec![(account(5), 0)]); assert_eq!(Balances::reserved_balance(account(1)), 2); assert_eq!(Balances::reserved_balance(account(5)), 63); @@ -1475,7 +1547,7 @@ fn burn_works() { )); assert_noop!( - Nfts::burn(RuntimeOrigin::signed(account(5)), 0, 42, Some(account(5))), + Nfts::burn(RuntimeOrigin::signed(account(5)), 0, 42), Error::::UnknownItem ); @@ -1496,16 +1568,12 @@ fn burn_works() { assert_eq!(Balances::reserved_balance(account(1)), 2); assert_noop!( - Nfts::burn(RuntimeOrigin::signed(account(0)), 0, 42, None), + Nfts::burn(RuntimeOrigin::signed(account(0)), 0, 42), Error::::NoPermission ); - assert_noop!( - Nfts::burn(RuntimeOrigin::signed(account(5)), 0, 42, Some(account(6))), - Error::::WrongOwner - ); - assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(5)), 0, 42, Some(account(5)))); - assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(3)), 0, 69, Some(account(5)))); + assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(5)), 0, 42)); + assert_ok!(Nfts::burn(RuntimeOrigin::signed(account(5)), 0, 69)); assert_eq!(Balances::reserved_balance(account(1)), 0); }); } @@ -1819,21 +1887,21 @@ fn cancel_approval_works_with_admin() { None )); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(1)), 1, 42, account(1)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 1, 42, account(1)), Error::::UnknownItem ); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(1)), 0, 43, account(1)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 43, account(1)), Error::::UnknownItem ); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(1)), 0, 42, account(4)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(4)), Error::::NotDelegate ); - assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(1)), 0, 42, account(3))); + assert_ok!(Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(3))); assert_noop!( - Nfts::cancel_approval(RuntimeOrigin::signed(account(1)), 0, 42, account(1)), + Nfts::cancel_approval(RuntimeOrigin::signed(account(2)), 0, 42, account(1)), Error::::NotDelegate ); }); @@ -3013,6 +3081,7 @@ fn add_remove_item_attributes_approval_should_work() { #[test] fn pre_signed_mints_should_work() { new_test_ext().execute_with(|| { + let user_0 = account(0); let user_1_pair = sp_core::sr25519::Pair::from_string("//Alice", None).unwrap(); let user_1_signer = MultiSigner::Sr25519(user_1_pair.public()); let user_1 = user_1_signer.clone().into_account(); @@ -3029,10 +3098,10 @@ fn pre_signed_mints_should_work() { let user_2 = account(2); let user_3 = account(3); - Balances::make_free_balance_be(&user_1, 100); + Balances::make_free_balance_be(&user_0, 100); Balances::make_free_balance_be(&user_2, 100); assert_ok!(Nfts::create( - RuntimeOrigin::signed(user_1.clone()), + RuntimeOrigin::signed(user_0.clone()), user_1.clone(), collection_config_with_all_settings_enabled(), )); @@ -3069,7 +3138,7 @@ fn pre_signed_mints_should_work() { assert_eq!(deposit.account, Some(user_2.clone())); assert_eq!(deposit.amount, 3); - assert_eq!(Balances::free_balance(&user_1), 100 - 2); // 2 - collection deposit + assert_eq!(Balances::free_balance(&user_0), 100 - 2); // 2 - collection deposit assert_eq!(Balances::free_balance(&user_2), 100 - 1 - 3 - 6); // 1 - item deposit, 3 - metadata, 6 - attributes assert_noop!( @@ -3082,7 +3151,7 @@ fn pre_signed_mints_should_work() { Error::::AlreadyExists ); - assert_ok!(Nfts::burn(RuntimeOrigin::signed(user_2.clone()), 0, 0, Some(user_2.clone()))); + assert_ok!(Nfts::burn(RuntimeOrigin::signed(user_2.clone()), 0, 0)); assert_eq!(Balances::free_balance(&user_2), 100 - 6); // validate the `only_account` field diff --git a/frame/nfts/src/types.rs b/frame/nfts/src/types.rs index f8ab2a355b48b..fe6d31c12acec 100644 --- a/frame/nfts/src/types.rs +++ b/frame/nfts/src/types.rs @@ -92,6 +92,8 @@ pub struct CollectionDetails { pub(super) items: u32, /// The total number of outstanding item metadata of this collection. pub(super) item_metadatas: u32, + /// The total number of outstanding item configs of this collection. + pub(super) item_configs: u32, /// The total number of attributes for this collection. pub(super) attributes: u32, } @@ -99,12 +101,12 @@ pub struct CollectionDetails { /// Witness data for the destroy transactions. #[derive(Copy, Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct DestroyWitness { - /// The total number of outstanding items of this collection. - #[codec(compact)] - pub items: u32, /// The total number of items in this collection that have outstanding item metadata. #[codec(compact)] pub item_metadatas: u32, + /// The total number of outstanding item configs of this collection. + #[codec(compact)] + pub item_configs: u32, /// The total number of attributes for this collection. #[codec(compact)] pub attributes: u32, @@ -113,8 +115,8 @@ pub struct DestroyWitness { impl CollectionDetails { pub fn destroy_witness(&self) -> DestroyWitness { DestroyWitness { - items: self.items, item_metadatas: self.item_metadatas, + item_configs: self.item_configs, attributes: self.attributes, } } diff --git a/frame/nfts/src/weights.rs b/frame/nfts/src/weights.rs index 858ae2fec9226..3d447c8d264d4 100644 --- a/frame/nfts/src/weights.rs +++ b/frame/nfts/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for pallet_nfts //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-10, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-osnnfcqu-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! 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: @@ -33,7 +33,7 @@ // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --json-file=/builds/parity/mirrors/substrate/.git/.artifacts/bench.json +// --json-file=/var/lib/gitlab-runner/builds/zyw4fam_/0/parity/mirrors/substrate/.git/.artifacts/bench.json // --pallet=pallet_nfts // --chain=dev // --header=./HEADER-APACHE2 @@ -51,7 +51,7 @@ use sp_std::marker::PhantomData; pub trait WeightInfo { fn create() -> Weight; fn force_create() -> Weight; - fn destroy(n: u32, m: u32, a: u32, ) -> Weight; + fn destroy(m: u32, c: u32, a: u32, ) -> Weight; fn mint() -> Weight; fn force_mint() -> Weight; fn burn() -> Weight; @@ -96,7 +96,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: Nfts NextCollectionId (r:1 w:1) /// Proof: Nfts NextCollectionId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) /// Storage: Nfts CollectionRoleOf (r:0 w:1) /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) /// Storage: Nfts CollectionConfigOf (r:0 w:1) @@ -106,17 +106,16 @@ impl WeightInfo for SubstrateWeight { fn create() -> Weight { // Proof Size summary in bytes: // Measured: `214` - // Estimated: `3054` - // Minimum execution time: 33_769 nanoseconds. - Weight::from_parts(36_031_000, 0) - .saturating_add(Weight::from_parts(0, 3054)) + // Estimated: `5038` + // Minimum execution time: 37_598_000 picoseconds. + Weight::from_parts(38_703_000, 5038) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } /// Storage: Nfts NextCollectionId (r:1 w:1) /// Proof: Nfts NextCollectionId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) /// Storage: Nfts CollectionRoleOf (r:0 w:1) /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) /// Storage: Nfts CollectionConfigOf (r:0 w:1) @@ -126,54 +125,45 @@ impl WeightInfo for SubstrateWeight { fn force_create() -> Weight { // Proof Size summary in bytes: // Measured: `42` - // Estimated: `3054` - // Minimum execution time: 21_767 nanoseconds. - Weight::from_parts(22_565_000, 0) - .saturating_add(Weight::from_parts(0, 3054)) + // Estimated: `5038` + // Minimum execution time: 25_899_000 picoseconds. + Weight::from_parts(26_385_000, 5038) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) - /// Storage: Nfts Item (r:1001 w:1000) - /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) - /// Storage: Nfts ItemMetadataOf (r:1001 w:1000) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: Nfts ItemMetadataOf (r:1 w:0) /// Proof: Nfts ItemMetadataOf (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) + /// Storage: Nfts CollectionRoleOf (r:1 w:1) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) /// Storage: Nfts Attribute (r:1001 w:1000) /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) - /// Storage: Nfts CollectionRoleOf (r:0 w:1) - /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:1000 w:1000) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) /// Storage: Nfts CollectionMetadataOf (r:0 w:1) /// Proof: Nfts CollectionMetadataOf (max_values: None, max_size: Some(87), added: 2562, mode: MaxEncodedLen) /// Storage: Nfts CollectionConfigOf (r:0 w:1) /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: Nfts ItemConfigOf (r:0 w:1000) - /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) - /// Storage: Nfts Account (r:0 w:1000) - /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) /// Storage: Nfts CollectionAccount (r:0 w:1) /// Proof: Nfts CollectionAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) - /// The range of component `n` is `[0, 1000]`. /// The range of component `m` is `[0, 1000]`. + /// The range of component `c` is `[0, 1000]`. /// The range of component `a` is `[0, 1000]`. - fn destroy(_n: u32, m: u32, a: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `172781 + m * (127 ±0) + a * (402 ±0)` - // Estimated: `3347427 + m * (2615 ±0) + a * (2921 ±0)` - // Minimum execution time: 26_973_627 nanoseconds. - Weight::from_parts(19_692_361_714, 0) - .saturating_add(Weight::from_parts(0, 3347427)) - // Standard Error: 17_036 - .saturating_add(Weight::from_parts(7_797_219, 0).saturating_mul(m.into())) - // Standard Error: 17_036 - .saturating_add(Weight::from_parts(9_504_128, 0).saturating_mul(a.into())) + fn destroy(m: u32, _c: u32, a: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `32218 + a * (364 ±0)` + // Estimated: `2538589 + a * (2921 ±0)` + // Minimum execution time: 1_129_980_000 picoseconds. + Weight::from_parts(1_096_213_543, 2538589) + // Standard Error: 5_210 + .saturating_add(Weight::from_parts(92, 0).saturating_mul(m.into())) + // Standard Error: 5_210 + .saturating_add(Weight::from_parts(5_480_550, 0).saturating_mul(a.into())) .saturating_add(T::DbWeight::get().reads(1004_u64)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(m.into()))) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(a.into()))) - .saturating_add(T::DbWeight::get().writes(3005_u64)) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(m.into()))) + .saturating_add(T::DbWeight::get().writes(1005_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(a.into()))) - .saturating_add(Weight::from_parts(0, 2615).saturating_mul(m.into())) .saturating_add(Weight::from_parts(0, 2921).saturating_mul(a.into())) } /// Storage: Nfts CollectionConfigOf (r:1 w:0) @@ -181,7 +171,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: Nfts Item (r:1 w:1) /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) /// Storage: Nfts CollectionRoleOf (r:1 w:0) /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) /// Storage: Nfts ItemConfigOf (r:1 w:1) @@ -190,11 +180,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) fn mint() -> Weight { // Proof Size summary in bytes: - // Measured: `448` - // Estimated: `13506` - // Minimum execution time: 44_837 nanoseconds. - Weight::from_parts(46_794_000, 0) - .saturating_add(Weight::from_parts(0, 13506)) + // Measured: `453` + // Estimated: `18460` + // Minimum execution time: 49_434_000 picoseconds. + Weight::from_parts(50_248_000, 18460) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -203,7 +192,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: Nfts Item (r:1 w:1) /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) /// Storage: Nfts CollectionConfigOf (r:1 w:0) /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) /// Storage: Nfts ItemConfigOf (r:1 w:1) @@ -212,22 +201,19 @@ impl WeightInfo for SubstrateWeight { /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) fn force_mint() -> Weight { // Proof Size summary in bytes: - // Measured: `448` - // Estimated: `13506` - // Minimum execution time: 43_976 nanoseconds. - Weight::from_parts(44_831_000, 0) - .saturating_add(Weight::from_parts(0, 13506)) + // Measured: `453` + // Estimated: `18460` + // Minimum execution time: 47_393_000 picoseconds. + Weight::from_parts(47_906_000, 18460) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } /// Storage: Nfts ItemConfigOf (r:1 w:1) /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) /// Storage: Nfts Item (r:1 w:1) /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) - /// Storage: Nfts CollectionRoleOf (r:1 w:0) - /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) /// Storage: Nfts ItemMetadataOf (r:1 w:0) /// Proof: Nfts ItemMetadataOf (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) /// Storage: Nfts Account (r:0 w:1) @@ -240,26 +226,21 @@ impl WeightInfo for SubstrateWeight { /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) fn burn() -> Weight { // Proof Size summary in bytes: - // Measured: `647` - // Estimated: `13573` - // Minimum execution time: 48_233 nanoseconds. - Weight::from_parts(50_113_000, 0) - .saturating_add(Weight::from_parts(0, 13573)) - .saturating_add(T::DbWeight::get().reads(5_u64)) + // Measured: `594` + // Estimated: `14993` + // Minimum execution time: 47_188_000 picoseconds. + Weight::from_parts(47_746_000, 14993) + .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } /// Storage: Nfts Collection (r:1 w:0) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) /// Storage: Nfts CollectionConfigOf (r:1 w:0) /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) /// Storage: Nfts ItemConfigOf (r:1 w:0) /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) /// Storage: Nfts Item (r:1 w:1) /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) - /// Storage: Nfts CollectionRoleOf (r:1 w:0) - /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: Nfts Account (r:0 w:2) /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) /// Storage: Nfts ItemPriceOf (r:0 w:1) @@ -268,16 +249,15 @@ impl WeightInfo for SubstrateWeight { /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) fn transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `882` - // Estimated: `16109` - // Minimum execution time: 55_452 nanoseconds. - Weight::from_parts(57_642_000, 0) - .saturating_add(Weight::from_parts(0, 16109)) - .saturating_add(T::DbWeight::get().reads(6_u64)) - .saturating_add(T::DbWeight::get().writes(6_u64)) + // Measured: `623` + // Estimated: `14926` + // Minimum execution time: 37_984_000 picoseconds. + Weight::from_parts(38_446_000, 14926) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) } /// Storage: Nfts Collection (r:1 w:0) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) /// Storage: Nfts CollectionConfigOf (r:1 w:0) /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) /// Storage: Nfts Item (r:5000 w:5000) @@ -285,13 +265,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `756 + i * (140 ±0)` - // Estimated: `5103 + i * (3336 ±0)` - // Minimum execution time: 15_598 nanoseconds. - Weight::from_parts(15_926_000, 0) - .saturating_add(Weight::from_parts(0, 5103)) - // Standard Error: 13_692 - .saturating_add(Weight::from_parts(14_040_741, 0).saturating_mul(i.into())) + // Measured: `761 + i * (140 ±0)` + // Estimated: `8077 + i * (3336 ±0)` + // Minimum execution time: 17_297_000 picoseconds. + Weight::from_parts(17_634_000, 8077) + // Standard Error: 17_773 + .saturating_add(Weight::from_parts(14_395_819, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(i.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) @@ -304,10 +283,9 @@ impl WeightInfo for SubstrateWeight { fn lock_item_transfer() -> Weight { // Proof Size summary in bytes: // Measured: `401` - // Estimated: `5067` - // Minimum execution time: 19_686 nanoseconds. - Weight::from_parts(20_404_000, 0) - .saturating_add(Weight::from_parts(0, 5067)) + // Estimated: `7047` + // Minimum execution time: 21_827_000 picoseconds. + Weight::from_parts(22_134_000, 7047) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -318,101 +296,96 @@ impl WeightInfo for SubstrateWeight { fn unlock_item_transfer() -> Weight { // Proof Size summary in bytes: // Measured: `401` - // Estimated: `5067` - // Minimum execution time: 19_172 nanoseconds. - Weight::from_parts(20_151_000, 0) - .saturating_add(Weight::from_parts(0, 5067)) + // Estimated: `7047` + // Minimum execution time: 21_549_000 picoseconds. + Weight::from_parts(21_987_000, 7047) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Nfts CollectionRoleOf (r:1 w:0) - /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:0) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) /// Storage: Nfts CollectionConfigOf (r:1 w:1) /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) fn lock_collection() -> Weight { // Proof Size summary in bytes: - // Measured: `289` - // Estimated: `5092` - // Minimum execution time: 17_063 nanoseconds. - Weight::from_parts(17_482_000, 0) - .saturating_add(Weight::from_parts(0, 5092)) + // Measured: `338` + // Estimated: `7087` + // Minimum execution time: 18_930_000 picoseconds. + Weight::from_parts(19_200_000, 7087) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Nfts OwnershipAcceptance (r:1 w:1) /// Proof: Nfts OwnershipAcceptance (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) /// Storage: Nfts CollectionAccount (r:0 w:2) /// Proof: Nfts CollectionAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) fn transfer_ownership() -> Weight { // Proof Size summary in bytes: - // Measured: `381` - // Estimated: `5082` - // Minimum execution time: 21_974 nanoseconds. - Weight::from_parts(22_770_000, 0) - .saturating_add(Weight::from_parts(0, 5082)) + // Measured: `386` + // Estimated: `7066` + // Minimum execution time: 24_929_000 picoseconds. + Weight::from_parts(25_786_000, 7066) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) - /// Storage: Nfts CollectionRoleOf (r:0 w:4) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: Nfts CollectionRoleOf (r:1 w:4) /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) fn set_team() -> Weight { // Proof Size summary in bytes: - // Measured: `362` - // Estimated: `2555` - // Minimum execution time: 24_341 nanoseconds. - Weight::from_parts(25_059_000, 0) - .saturating_add(Weight::from_parts(0, 2555)) - .saturating_add(T::DbWeight::get().reads(1_u64)) + // Measured: `367` + // Estimated: `7083` + // Minimum execution time: 28_245_000 picoseconds. + Weight::from_parts(28_490_000, 7083) + .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) /// Storage: Nfts CollectionAccount (r:0 w:2) /// Proof: Nfts CollectionAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) fn force_collection_owner() -> Weight { // Proof Size summary in bytes: - // Measured: `304` - // Estimated: `2555` - // Minimum execution time: 16_897 nanoseconds. - Weight::from_parts(17_560_000, 0) - .saturating_add(Weight::from_parts(0, 2555)) + // Measured: `309` + // Estimated: `3549` + // Minimum execution time: 19_971_000 picoseconds. + Weight::from_parts(20_276_000, 3549) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: Nfts Collection (r:1 w:0) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) /// Storage: Nfts CollectionConfigOf (r:0 w:1) /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) fn force_collection_config() -> Weight { // Proof Size summary in bytes: // Measured: `242` - // Estimated: `2555` - // Minimum execution time: 13_239 nanoseconds. - Weight::from_parts(13_963_000, 0) - .saturating_add(Weight::from_parts(0, 2555)) + // Estimated: `3549` + // Minimum execution time: 15_924_000 picoseconds. + Weight::from_parts(16_258_000, 3549) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Nfts Collection (r:1 w:0) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) /// Storage: Nfts ItemConfigOf (r:1 w:1) /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) fn lock_item_properties() -> Weight { // Proof Size summary in bytes: - // Measured: `445` - // Estimated: `5078` - // Minimum execution time: 17_187 nanoseconds. - Weight::from_parts(17_942_000, 0) - .saturating_add(Weight::from_parts(0, 5078)) + // Measured: `401` + // Estimated: `7047` + // Minimum execution time: 20_780_000 picoseconds. + Weight::from_parts(21_109_000, 7047) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) /// Storage: Nfts CollectionConfigOf (r:1 w:0) /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) /// Storage: Nfts ItemConfigOf (r:1 w:0) @@ -421,42 +394,41 @@ impl WeightInfo for SubstrateWeight { /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) fn set_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `474` - // Estimated: `10547` - // Minimum execution time: 40_925 nanoseconds. - Weight::from_parts(42_733_000, 0) - .saturating_add(Weight::from_parts(0, 10547)) - .saturating_add(T::DbWeight::get().reads(4_u64)) + // Measured: `537` + // Estimated: `18045` + // Minimum execution time: 50_817_000 picoseconds. + Weight::from_parts(51_585_000, 18045) + .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) /// Storage: Nfts Attribute (r:1 w:1) /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) fn force_set_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `337` - // Estimated: `5476` - // Minimum execution time: 24_486 nanoseconds. - Weight::from_parts(25_409_000, 0) - .saturating_add(Weight::from_parts(0, 5476)) + // Measured: `342` + // Estimated: `7460` + // Minimum execution time: 28_821_000 picoseconds. + Weight::from_parts(29_417_000, 7460) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: Nfts Attribute (r:1 w:1) /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) - /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) /// Storage: Nfts ItemConfigOf (r:1 w:0) /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) fn clear_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `916` - // Estimated: `7999` - // Minimum execution time: 36_643 nanoseconds. - Weight::from_parts(37_805_000, 0) - .saturating_add(Weight::from_parts(0, 7999)) - .saturating_add(T::DbWeight::get().reads(3_u64)) + // Measured: `979` + // Estimated: `14507` + // Minimum execution time: 47_021_000 picoseconds. + Weight::from_parts(47_509_000, 14507) + .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: Nfts Item (r:1 w:0) @@ -466,10 +438,9 @@ impl WeightInfo for SubstrateWeight { fn approve_item_attributes() -> Weight { // Proof Size summary in bytes: // Measured: `379` - // Estimated: `6492` - // Minimum execution time: 16_798 nanoseconds. - Weight::from_parts(17_326_000, 0) - .saturating_add(Weight::from_parts(0, 6492)) + // Estimated: `8472` + // Minimum execution time: 19_457_000 picoseconds. + Weight::from_parts(19_738_000, 8472) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -485,20 +456,21 @@ impl WeightInfo for SubstrateWeight { fn cancel_item_attributes_approval(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `899 + n * (396 ±0)` - // Estimated: `12016 + n * (2921 ±0)` - // Minimum execution time: 25_524 nanoseconds. - Weight::from_parts(26_107_000, 0) - .saturating_add(Weight::from_parts(0, 12016)) - // Standard Error: 5_460 - .saturating_add(Weight::from_parts(9_030_830, 0).saturating_mul(n.into())) + // Estimated: `15976 + n * (2921 ±0)` + // Minimum execution time: 29_027_000 picoseconds. + Weight::from_parts(29_376_000, 15976) + // Standard Error: 3_500 + .saturating_add(Weight::from_parts(5_568_116, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) .saturating_add(Weight::from_parts(0, 2921).saturating_mul(n.into())) } + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) /// Storage: Nfts ItemConfigOf (r:1 w:0) /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) /// Storage: Nfts CollectionConfigOf (r:1 w:0) @@ -507,104 +479,97 @@ impl WeightInfo for SubstrateWeight { /// Proof: Nfts ItemMetadataOf (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) fn set_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `474` - // Estimated: `10241` - // Minimum execution time: 34_400 nanoseconds. - Weight::from_parts(35_469_000, 0) - .saturating_add(Weight::from_parts(0, 10241)) - .saturating_add(T::DbWeight::get().reads(4_u64)) + // Measured: `537` + // Estimated: `17739` + // Minimum execution time: 41_658_000 picoseconds. + Weight::from_parts(42_241_000, 17739) + .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) /// Storage: Nfts ItemMetadataOf (r:1 w:1) /// Proof: Nfts ItemMetadataOf (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) /// Storage: Nfts ItemConfigOf (r:1 w:0) /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) fn clear_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `609` - // Estimated: `7693` - // Minimum execution time: 31_560 nanoseconds. - Weight::from_parts(33_081_000, 0) - .saturating_add(Weight::from_parts(0, 7693)) - .saturating_add(T::DbWeight::get().reads(3_u64)) + // Measured: `672` + // Estimated: `14201` + // Minimum execution time: 39_838_000 picoseconds. + Weight::from_parts(40_757_000, 14201) + .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) /// Storage: Nfts CollectionConfigOf (r:1 w:0) /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) /// Storage: Nfts CollectionMetadataOf (r:1 w:1) /// Proof: Nfts CollectionMetadataOf (max_values: None, max_size: Some(87), added: 2562, mode: MaxEncodedLen) fn set_collection_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `333` - // Estimated: `7665` - // Minimum execution time: 28_821 nanoseconds. - Weight::from_parts(30_010_000, 0) - .saturating_add(Weight::from_parts(0, 7665)) - .saturating_add(T::DbWeight::get().reads(3_u64)) + // Measured: `396` + // Estimated: `14173` + // Minimum execution time: 37_327_000 picoseconds. + Weight::from_parts(37_874_000, 14173) + .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) /// Storage: Nfts Collection (r:1 w:0) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) /// Storage: Nfts CollectionConfigOf (r:1 w:0) /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) /// Storage: Nfts CollectionMetadataOf (r:1 w:1) /// Proof: Nfts CollectionMetadataOf (max_values: None, max_size: Some(87), added: 2562, mode: MaxEncodedLen) fn clear_collection_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `476` - // Estimated: `7665` - // Minimum execution time: 27_608 nanoseconds. - Weight::from_parts(28_766_000, 0) - .saturating_add(Weight::from_parts(0, 7665)) - .saturating_add(T::DbWeight::get().reads(3_u64)) + // Measured: `539` + // Estimated: `14173` + // Minimum execution time: 35_305_000 picoseconds. + Weight::from_parts(36_213_000, 14173) + .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Nfts Item (r:1 w:1) /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) /// Storage: Nfts CollectionConfigOf (r:1 w:0) /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: Nfts CollectionRoleOf (r:1 w:0) - /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) fn approve_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `466` - // Estimated: `8428` - // Minimum execution time: 23_987 nanoseconds. - Weight::from_parts(24_819_000, 0) - .saturating_add(Weight::from_parts(0, 8428)) - .saturating_add(T::DbWeight::get().reads(3_u64)) + // Measured: `408` + // Estimated: `7864` + // Minimum execution time: 22_680_000 picoseconds. + Weight::from_parts(23_126_000, 7864) + .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Nfts Item (r:1 w:1) /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) - /// Storage: Nfts CollectionRoleOf (r:1 w:0) - /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) fn cancel_approval() -> Weight { // Proof Size summary in bytes: - // Measured: `474` - // Estimated: `5880` - // Minimum execution time: 21_254 nanoseconds. - Weight::from_parts(21_826_000, 0) - .saturating_add(Weight::from_parts(0, 5880)) - .saturating_add(T::DbWeight::get().reads(2_u64)) + // Measured: `416` + // Estimated: `4326` + // Minimum execution time: 19_837_000 picoseconds. + Weight::from_parts(20_352_000, 4326) + .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Nfts Item (r:1 w:1) /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) - /// Storage: Nfts CollectionRoleOf (r:1 w:0) - /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) fn clear_all_transfer_approvals() -> Weight { // Proof Size summary in bytes: - // Measured: `474` - // Estimated: `5880` - // Minimum execution time: 20_272 nanoseconds. - Weight::from_parts(20_922_000, 0) - .saturating_add(Weight::from_parts(0, 5880)) - .saturating_add(T::DbWeight::get().reads(2_u64)) + // Measured: `416` + // Estimated: `4326` + // Minimum execution time: 18_911_000 picoseconds. + Weight::from_parts(19_233_000, 4326) + .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Nfts OwnershipAcceptance (r:1 w:1) @@ -612,38 +577,35 @@ impl WeightInfo for SubstrateWeight { fn set_accept_ownership() -> Weight { // Proof Size summary in bytes: // Measured: `42` - // Estimated: `2527` - // Minimum execution time: 14_287 nanoseconds. - Weight::from_parts(14_960_000, 0) - .saturating_add(Weight::from_parts(0, 2527)) + // Estimated: `3517` + // Minimum execution time: 17_292_000 picoseconds. + Weight::from_parts(17_568_000, 3517) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Nfts CollectionConfigOf (r:1 w:1) /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) /// Storage: Nfts Collection (r:1 w:0) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) fn set_collection_max_supply() -> Weight { // Proof Size summary in bytes: - // Measured: `333` - // Estimated: `5103` - // Minimum execution time: 17_948 nanoseconds. - Weight::from_parts(18_780_000, 0) - .saturating_add(Weight::from_parts(0, 5103)) + // Measured: `338` + // Estimated: `7087` + // Minimum execution time: 20_323_000 picoseconds. + Weight::from_parts(20_692_000, 7087) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Nfts Collection (r:1 w:0) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) /// Storage: Nfts CollectionConfigOf (r:1 w:1) /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) fn update_mint_settings() -> Weight { // Proof Size summary in bytes: - // Measured: `333` - // Estimated: `5103` - // Minimum execution time: 16_616 nanoseconds. - Weight::from_parts(17_155_000, 0) - .saturating_add(Weight::from_parts(0, 5103)) + // Measured: `289` + // Estimated: `7072` + // Minimum execution time: 19_971_000 picoseconds. + Weight::from_parts(20_159_000, 7072) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -658,10 +620,9 @@ impl WeightInfo for SubstrateWeight { fn set_price() -> Weight { // Proof Size summary in bytes: // Measured: `516` - // Estimated: `8407` - // Minimum execution time: 22_777 nanoseconds. - Weight::from_parts(23_955_000, 0) - .saturating_add(Weight::from_parts(0, 8407)) + // Estimated: `11377` + // Minimum execution time: 26_202_000 picoseconds. + Weight::from_parts(26_499_000, 11377) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -670,37 +631,33 @@ impl WeightInfo for SubstrateWeight { /// Storage: Nfts ItemPriceOf (r:1 w:1) /// Proof: Nfts ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) /// Storage: Nfts Collection (r:1 w:0) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) /// Storage: Nfts CollectionConfigOf (r:1 w:0) /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) /// Storage: Nfts ItemConfigOf (r:1 w:0) /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: Nfts Account (r:0 w:2) /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) /// Storage: Nfts PendingSwapOf (r:0 w:1) /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) fn buy_item() -> Weight { // Proof Size summary in bytes: - // Measured: `934` - // Estimated: `16129` - // Minimum execution time: 61_131 nanoseconds. - Weight::from_parts(62_791_000, 0) - .saturating_add(Weight::from_parts(0, 16129)) - .saturating_add(T::DbWeight::get().reads(6_u64)) - .saturating_add(T::DbWeight::get().writes(6_u64)) + // Measured: `767` + // Estimated: `18480` + // Minimum execution time: 50_601_000 picoseconds. + Weight::from_parts(51_283_000, 18480) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) } /// The range of component `n` is `[0, 10]`. fn pay_tips(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_952 nanoseconds. - Weight::from_parts(3_975_700, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 11_254 - .saturating_add(Weight::from_parts(3_501_698, 0).saturating_mul(n.into())) + // Minimum execution time: 2_733_000 picoseconds. + Weight::from_parts(5_568_590, 0) + // Standard Error: 14_136 + .saturating_add(Weight::from_parts(3_763_928, 0).saturating_mul(n.into())) } /// Storage: Nfts Item (r:2 w:0) /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) @@ -709,10 +666,9 @@ impl WeightInfo for SubstrateWeight { fn create_swap() -> Weight { // Proof Size summary in bytes: // Measured: `524` - // Estimated: `6672` - // Minimum execution time: 20_327 nanoseconds. - Weight::from_parts(21_714_000, 0) - .saturating_add(Weight::from_parts(0, 6672)) + // Estimated: `7662` + // Minimum execution time: 22_901_000 picoseconds. + Weight::from_parts(23_673_000, 7662) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -723,10 +679,9 @@ impl WeightInfo for SubstrateWeight { fn cancel_swap() -> Weight { // Proof Size summary in bytes: // Measured: `511` - // Estimated: `5882` - // Minimum execution time: 20_668 nanoseconds. - Weight::from_parts(21_416_000, 0) - .saturating_add(Weight::from_parts(0, 5882)) + // Estimated: `7862` + // Minimum execution time: 22_532_000 picoseconds. + Weight::from_parts(22_831_000, 7862) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -735,29 +690,28 @@ impl WeightInfo for SubstrateWeight { /// Storage: Nfts PendingSwapOf (r:1 w:2) /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) /// Storage: Nfts Collection (r:1 w:0) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) /// Storage: Nfts CollectionConfigOf (r:1 w:0) /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) /// Storage: Nfts ItemConfigOf (r:2 w:0) /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: Nfts Account (r:0 w:4) /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) /// Storage: Nfts ItemPriceOf (r:0 w:2) /// Proof: Nfts ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) fn claim_swap() -> Weight { // Proof Size summary in bytes: - // Measured: `1097` - // Estimated: `21970` - // Minimum execution time: 88_006 nanoseconds. - Weight::from_parts(90_390_000, 0) - .saturating_add(Weight::from_parts(0, 21970)) - .saturating_add(T::DbWeight::get().reads(8_u64)) - .saturating_add(T::DbWeight::get().writes(11_u64)) + // Measured: `896` + // Estimated: `24321` + // Minimum execution time: 77_668_000 picoseconds. + Weight::from_parts(78_407_000, 24321) + .saturating_add(T::DbWeight::get().reads(7_u64)) + .saturating_add(T::DbWeight::get().writes(10_u64)) } /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: Nfts CollectionRoleOf (r:2 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) /// Storage: Nfts CollectionConfigOf (r:1 w:0) /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) /// Storage: Nfts Item (r:1 w:1) @@ -775,14 +729,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 10]`. fn mint_pre_signed(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `596` - // Estimated: `16180 + n * (2921 ±0)` - // Minimum execution time: 124_967 nanoseconds. - Weight::from_parts(131_602_642, 0) - .saturating_add(Weight::from_parts(0, 16180)) - // Standard Error: 36_480 - .saturating_add(Weight::from_parts(25_811_394, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(6_u64)) + // Measured: `659` + // Estimated: `29192 + n * (2921 ±0)` + // Minimum execution time: 133_147_000 picoseconds. + Weight::from_parts(138_031_439, 29192) + // Standard Error: 28_665 + .saturating_add(Weight::from_parts(28_206_062, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(6_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) @@ -792,10 +745,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) /// Storage: Nfts ItemAttributesApprovalsOf (r:1 w:1) /// Proof: Nfts ItemAttributesApprovalsOf (max_values: None, max_size: Some(681), added: 3156, mode: MaxEncodedLen) - /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) /// Storage: Nfts CollectionConfigOf (r:1 w:0) /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) /// Storage: Nfts Attribute (r:10 w:10) /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) /// Storage: System Account (r:1 w:1) @@ -803,13 +756,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 10]`. fn set_attributes_pre_signed(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `716` - // Estimated: `14198 + n * (2921 ±0)` - // Minimum execution time: 84_153 nanoseconds. - Weight::from_parts(96_401_623, 0) - .saturating_add(Weight::from_parts(0, 14198)) - // Standard Error: 70_244 - .saturating_add(Weight::from_parts(26_866_222, 0).saturating_mul(n.into())) + // Measured: `721` + // Estimated: `20142 + n * (2921 ±0)` + // Minimum execution time: 78_243_000 picoseconds. + Weight::from_parts(90_947_408, 20142) + // Standard Error: 75_516 + .saturating_add(Weight::from_parts(28_059_623, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) @@ -823,7 +775,7 @@ impl WeightInfo for () { /// Storage: Nfts NextCollectionId (r:1 w:1) /// Proof: Nfts NextCollectionId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) /// Storage: Nfts CollectionRoleOf (r:0 w:1) /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) /// Storage: Nfts CollectionConfigOf (r:0 w:1) @@ -833,17 +785,16 @@ impl WeightInfo for () { fn create() -> Weight { // Proof Size summary in bytes: // Measured: `214` - // Estimated: `3054` - // Minimum execution time: 33_769 nanoseconds. - Weight::from_parts(36_031_000, 0) - .saturating_add(Weight::from_parts(0, 3054)) + // Estimated: `5038` + // Minimum execution time: 37_598_000 picoseconds. + Weight::from_parts(38_703_000, 5038) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } /// Storage: Nfts NextCollectionId (r:1 w:1) /// Proof: Nfts NextCollectionId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) /// Storage: Nfts CollectionRoleOf (r:0 w:1) /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) /// Storage: Nfts CollectionConfigOf (r:0 w:1) @@ -853,54 +804,45 @@ impl WeightInfo for () { fn force_create() -> Weight { // Proof Size summary in bytes: // Measured: `42` - // Estimated: `3054` - // Minimum execution time: 21_767 nanoseconds. - Weight::from_parts(22_565_000, 0) - .saturating_add(Weight::from_parts(0, 3054)) + // Estimated: `5038` + // Minimum execution time: 25_899_000 picoseconds. + Weight::from_parts(26_385_000, 5038) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) - /// Storage: Nfts Item (r:1001 w:1000) - /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) - /// Storage: Nfts ItemMetadataOf (r:1001 w:1000) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: Nfts ItemMetadataOf (r:1 w:0) /// Proof: Nfts ItemMetadataOf (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) + /// Storage: Nfts CollectionRoleOf (r:1 w:1) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) /// Storage: Nfts Attribute (r:1001 w:1000) /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) - /// Storage: Nfts CollectionRoleOf (r:0 w:1) - /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:1000 w:1000) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) /// Storage: Nfts CollectionMetadataOf (r:0 w:1) /// Proof: Nfts CollectionMetadataOf (max_values: None, max_size: Some(87), added: 2562, mode: MaxEncodedLen) /// Storage: Nfts CollectionConfigOf (r:0 w:1) /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: Nfts ItemConfigOf (r:0 w:1000) - /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) - /// Storage: Nfts Account (r:0 w:1000) - /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) /// Storage: Nfts CollectionAccount (r:0 w:1) /// Proof: Nfts CollectionAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) - /// The range of component `n` is `[0, 1000]`. /// The range of component `m` is `[0, 1000]`. + /// The range of component `c` is `[0, 1000]`. /// The range of component `a` is `[0, 1000]`. - fn destroy(_n: u32, m: u32, a: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `172781 + m * (127 ±0) + a * (402 ±0)` - // Estimated: `3347427 + m * (2615 ±0) + a * (2921 ±0)` - // Minimum execution time: 26_973_627 nanoseconds. - Weight::from_parts(19_692_361_714, 0) - .saturating_add(Weight::from_parts(0, 3347427)) - // Standard Error: 17_036 - .saturating_add(Weight::from_parts(7_797_219, 0).saturating_mul(m.into())) - // Standard Error: 17_036 - .saturating_add(Weight::from_parts(9_504_128, 0).saturating_mul(a.into())) + fn destroy(m: u32, _c: u32, a: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `32218 + a * (364 ±0)` + // Estimated: `2538589 + a * (2921 ±0)` + // Minimum execution time: 1_129_980_000 picoseconds. + Weight::from_parts(1_096_213_543, 2538589) + // Standard Error: 5_210 + .saturating_add(Weight::from_parts(92, 0).saturating_mul(m.into())) + // Standard Error: 5_210 + .saturating_add(Weight::from_parts(5_480_550, 0).saturating_mul(a.into())) .saturating_add(RocksDbWeight::get().reads(1004_u64)) - .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(m.into()))) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(a.into()))) - .saturating_add(RocksDbWeight::get().writes(3005_u64)) - .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(m.into()))) + .saturating_add(RocksDbWeight::get().writes(1005_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(a.into()))) - .saturating_add(Weight::from_parts(0, 2615).saturating_mul(m.into())) .saturating_add(Weight::from_parts(0, 2921).saturating_mul(a.into())) } /// Storage: Nfts CollectionConfigOf (r:1 w:0) @@ -908,7 +850,7 @@ impl WeightInfo for () { /// Storage: Nfts Item (r:1 w:1) /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) /// Storage: Nfts CollectionRoleOf (r:1 w:0) /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) /// Storage: Nfts ItemConfigOf (r:1 w:1) @@ -917,11 +859,10 @@ impl WeightInfo for () { /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) fn mint() -> Weight { // Proof Size summary in bytes: - // Measured: `448` - // Estimated: `13506` - // Minimum execution time: 44_837 nanoseconds. - Weight::from_parts(46_794_000, 0) - .saturating_add(Weight::from_parts(0, 13506)) + // Measured: `453` + // Estimated: `18460` + // Minimum execution time: 49_434_000 picoseconds. + Weight::from_parts(50_248_000, 18460) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -930,7 +871,7 @@ impl WeightInfo for () { /// Storage: Nfts Item (r:1 w:1) /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) /// Storage: Nfts CollectionConfigOf (r:1 w:0) /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) /// Storage: Nfts ItemConfigOf (r:1 w:1) @@ -939,22 +880,19 @@ impl WeightInfo for () { /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) fn force_mint() -> Weight { // Proof Size summary in bytes: - // Measured: `448` - // Estimated: `13506` - // Minimum execution time: 43_976 nanoseconds. - Weight::from_parts(44_831_000, 0) - .saturating_add(Weight::from_parts(0, 13506)) + // Measured: `453` + // Estimated: `18460` + // Minimum execution time: 47_393_000 picoseconds. + Weight::from_parts(47_906_000, 18460) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } /// Storage: Nfts ItemConfigOf (r:1 w:1) /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) /// Storage: Nfts Item (r:1 w:1) /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) - /// Storage: Nfts CollectionRoleOf (r:1 w:0) - /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) /// Storage: Nfts ItemMetadataOf (r:1 w:0) /// Proof: Nfts ItemMetadataOf (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) /// Storage: Nfts Account (r:0 w:1) @@ -967,26 +905,21 @@ impl WeightInfo for () { /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) fn burn() -> Weight { // Proof Size summary in bytes: - // Measured: `647` - // Estimated: `13573` - // Minimum execution time: 48_233 nanoseconds. - Weight::from_parts(50_113_000, 0) - .saturating_add(Weight::from_parts(0, 13573)) - .saturating_add(RocksDbWeight::get().reads(5_u64)) + // Measured: `594` + // Estimated: `14993` + // Minimum execution time: 47_188_000 picoseconds. + Weight::from_parts(47_746_000, 14993) + .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } /// Storage: Nfts Collection (r:1 w:0) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) /// Storage: Nfts CollectionConfigOf (r:1 w:0) /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) /// Storage: Nfts ItemConfigOf (r:1 w:0) /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) /// Storage: Nfts Item (r:1 w:1) /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) - /// Storage: Nfts CollectionRoleOf (r:1 w:0) - /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: Nfts Account (r:0 w:2) /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) /// Storage: Nfts ItemPriceOf (r:0 w:1) @@ -995,16 +928,15 @@ impl WeightInfo for () { /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) fn transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `882` - // Estimated: `16109` - // Minimum execution time: 55_452 nanoseconds. - Weight::from_parts(57_642_000, 0) - .saturating_add(Weight::from_parts(0, 16109)) - .saturating_add(RocksDbWeight::get().reads(6_u64)) - .saturating_add(RocksDbWeight::get().writes(6_u64)) + // Measured: `623` + // Estimated: `14926` + // Minimum execution time: 37_984_000 picoseconds. + Weight::from_parts(38_446_000, 14926) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(5_u64)) } /// Storage: Nfts Collection (r:1 w:0) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) /// Storage: Nfts CollectionConfigOf (r:1 w:0) /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) /// Storage: Nfts Item (r:5000 w:5000) @@ -1012,13 +944,12 @@ impl WeightInfo for () { /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `756 + i * (140 ±0)` - // Estimated: `5103 + i * (3336 ±0)` - // Minimum execution time: 15_598 nanoseconds. - Weight::from_parts(15_926_000, 0) - .saturating_add(Weight::from_parts(0, 5103)) - // Standard Error: 13_692 - .saturating_add(Weight::from_parts(14_040_741, 0).saturating_mul(i.into())) + // Measured: `761 + i * (140 ±0)` + // Estimated: `8077 + i * (3336 ±0)` + // Minimum execution time: 17_297_000 picoseconds. + Weight::from_parts(17_634_000, 8077) + // Standard Error: 17_773 + .saturating_add(Weight::from_parts(14_395_819, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(i.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(i.into()))) @@ -1031,10 +962,9 @@ impl WeightInfo for () { fn lock_item_transfer() -> Weight { // Proof Size summary in bytes: // Measured: `401` - // Estimated: `5067` - // Minimum execution time: 19_686 nanoseconds. - Weight::from_parts(20_404_000, 0) - .saturating_add(Weight::from_parts(0, 5067)) + // Estimated: `7047` + // Minimum execution time: 21_827_000 picoseconds. + Weight::from_parts(22_134_000, 7047) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1045,101 +975,96 @@ impl WeightInfo for () { fn unlock_item_transfer() -> Weight { // Proof Size summary in bytes: // Measured: `401` - // Estimated: `5067` - // Minimum execution time: 19_172 nanoseconds. - Weight::from_parts(20_151_000, 0) - .saturating_add(Weight::from_parts(0, 5067)) + // Estimated: `7047` + // Minimum execution time: 21_549_000 picoseconds. + Weight::from_parts(21_987_000, 7047) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Nfts CollectionRoleOf (r:1 w:0) - /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:0) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) /// Storage: Nfts CollectionConfigOf (r:1 w:1) /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) fn lock_collection() -> Weight { // Proof Size summary in bytes: - // Measured: `289` - // Estimated: `5092` - // Minimum execution time: 17_063 nanoseconds. - Weight::from_parts(17_482_000, 0) - .saturating_add(Weight::from_parts(0, 5092)) + // Measured: `338` + // Estimated: `7087` + // Minimum execution time: 18_930_000 picoseconds. + Weight::from_parts(19_200_000, 7087) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Nfts OwnershipAcceptance (r:1 w:1) /// Proof: Nfts OwnershipAcceptance (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) /// Storage: Nfts CollectionAccount (r:0 w:2) /// Proof: Nfts CollectionAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) fn transfer_ownership() -> Weight { // Proof Size summary in bytes: - // Measured: `381` - // Estimated: `5082` - // Minimum execution time: 21_974 nanoseconds. - Weight::from_parts(22_770_000, 0) - .saturating_add(Weight::from_parts(0, 5082)) + // Measured: `386` + // Estimated: `7066` + // Minimum execution time: 24_929_000 picoseconds. + Weight::from_parts(25_786_000, 7066) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) - /// Storage: Nfts CollectionRoleOf (r:0 w:4) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: Nfts CollectionRoleOf (r:1 w:4) /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) fn set_team() -> Weight { // Proof Size summary in bytes: - // Measured: `362` - // Estimated: `2555` - // Minimum execution time: 24_341 nanoseconds. - Weight::from_parts(25_059_000, 0) - .saturating_add(Weight::from_parts(0, 2555)) - .saturating_add(RocksDbWeight::get().reads(1_u64)) + // Measured: `367` + // Estimated: `7083` + // Minimum execution time: 28_245_000 picoseconds. + Weight::from_parts(28_490_000, 7083) + .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) /// Storage: Nfts CollectionAccount (r:0 w:2) /// Proof: Nfts CollectionAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) fn force_collection_owner() -> Weight { // Proof Size summary in bytes: - // Measured: `304` - // Estimated: `2555` - // Minimum execution time: 16_897 nanoseconds. - Weight::from_parts(17_560_000, 0) - .saturating_add(Weight::from_parts(0, 2555)) + // Measured: `309` + // Estimated: `3549` + // Minimum execution time: 19_971_000 picoseconds. + Weight::from_parts(20_276_000, 3549) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: Nfts Collection (r:1 w:0) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) /// Storage: Nfts CollectionConfigOf (r:0 w:1) /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) fn force_collection_config() -> Weight { // Proof Size summary in bytes: // Measured: `242` - // Estimated: `2555` - // Minimum execution time: 13_239 nanoseconds. - Weight::from_parts(13_963_000, 0) - .saturating_add(Weight::from_parts(0, 2555)) + // Estimated: `3549` + // Minimum execution time: 15_924_000 picoseconds. + Weight::from_parts(16_258_000, 3549) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Nfts Collection (r:1 w:0) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) /// Storage: Nfts ItemConfigOf (r:1 w:1) /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) fn lock_item_properties() -> Weight { // Proof Size summary in bytes: - // Measured: `445` - // Estimated: `5078` - // Minimum execution time: 17_187 nanoseconds. - Weight::from_parts(17_942_000, 0) - .saturating_add(Weight::from_parts(0, 5078)) + // Measured: `401` + // Estimated: `7047` + // Minimum execution time: 20_780_000 picoseconds. + Weight::from_parts(21_109_000, 7047) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) /// Storage: Nfts CollectionConfigOf (r:1 w:0) /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) /// Storage: Nfts ItemConfigOf (r:1 w:0) @@ -1148,42 +1073,41 @@ impl WeightInfo for () { /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) fn set_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `474` - // Estimated: `10547` - // Minimum execution time: 40_925 nanoseconds. - Weight::from_parts(42_733_000, 0) - .saturating_add(Weight::from_parts(0, 10547)) - .saturating_add(RocksDbWeight::get().reads(4_u64)) + // Measured: `537` + // Estimated: `18045` + // Minimum execution time: 50_817_000 picoseconds. + Weight::from_parts(51_585_000, 18045) + .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) /// Storage: Nfts Attribute (r:1 w:1) /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) fn force_set_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `337` - // Estimated: `5476` - // Minimum execution time: 24_486 nanoseconds. - Weight::from_parts(25_409_000, 0) - .saturating_add(Weight::from_parts(0, 5476)) + // Measured: `342` + // Estimated: `7460` + // Minimum execution time: 28_821_000 picoseconds. + Weight::from_parts(29_417_000, 7460) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: Nfts Attribute (r:1 w:1) /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) - /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) /// Storage: Nfts ItemConfigOf (r:1 w:0) /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) fn clear_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `916` - // Estimated: `7999` - // Minimum execution time: 36_643 nanoseconds. - Weight::from_parts(37_805_000, 0) - .saturating_add(Weight::from_parts(0, 7999)) - .saturating_add(RocksDbWeight::get().reads(3_u64)) + // Measured: `979` + // Estimated: `14507` + // Minimum execution time: 47_021_000 picoseconds. + Weight::from_parts(47_509_000, 14507) + .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: Nfts Item (r:1 w:0) @@ -1193,10 +1117,9 @@ impl WeightInfo for () { fn approve_item_attributes() -> Weight { // Proof Size summary in bytes: // Measured: `379` - // Estimated: `6492` - // Minimum execution time: 16_798 nanoseconds. - Weight::from_parts(17_326_000, 0) - .saturating_add(Weight::from_parts(0, 6492)) + // Estimated: `8472` + // Minimum execution time: 19_457_000 picoseconds. + Weight::from_parts(19_738_000, 8472) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1212,20 +1135,21 @@ impl WeightInfo for () { fn cancel_item_attributes_approval(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `899 + n * (396 ±0)` - // Estimated: `12016 + n * (2921 ±0)` - // Minimum execution time: 25_524 nanoseconds. - Weight::from_parts(26_107_000, 0) - .saturating_add(Weight::from_parts(0, 12016)) - // Standard Error: 5_460 - .saturating_add(Weight::from_parts(9_030_830, 0).saturating_mul(n.into())) + // Estimated: `15976 + n * (2921 ±0)` + // Minimum execution time: 29_027_000 picoseconds. + Weight::from_parts(29_376_000, 15976) + // Standard Error: 3_500 + .saturating_add(Weight::from_parts(5_568_116, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) .saturating_add(Weight::from_parts(0, 2921).saturating_mul(n.into())) } + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) /// Storage: Nfts ItemConfigOf (r:1 w:0) /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) /// Storage: Nfts CollectionConfigOf (r:1 w:0) @@ -1234,104 +1158,97 @@ impl WeightInfo for () { /// Proof: Nfts ItemMetadataOf (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) fn set_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `474` - // Estimated: `10241` - // Minimum execution time: 34_400 nanoseconds. - Weight::from_parts(35_469_000, 0) - .saturating_add(Weight::from_parts(0, 10241)) - .saturating_add(RocksDbWeight::get().reads(4_u64)) + // Measured: `537` + // Estimated: `17739` + // Minimum execution time: 41_658_000 picoseconds. + Weight::from_parts(42_241_000, 17739) + .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) /// Storage: Nfts ItemMetadataOf (r:1 w:1) /// Proof: Nfts ItemMetadataOf (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) /// Storage: Nfts ItemConfigOf (r:1 w:0) /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) fn clear_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `609` - // Estimated: `7693` - // Minimum execution time: 31_560 nanoseconds. - Weight::from_parts(33_081_000, 0) - .saturating_add(Weight::from_parts(0, 7693)) - .saturating_add(RocksDbWeight::get().reads(3_u64)) + // Measured: `672` + // Estimated: `14201` + // Minimum execution time: 39_838_000 picoseconds. + Weight::from_parts(40_757_000, 14201) + .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) /// Storage: Nfts CollectionConfigOf (r:1 w:0) /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) /// Storage: Nfts CollectionMetadataOf (r:1 w:1) /// Proof: Nfts CollectionMetadataOf (max_values: None, max_size: Some(87), added: 2562, mode: MaxEncodedLen) fn set_collection_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `333` - // Estimated: `7665` - // Minimum execution time: 28_821 nanoseconds. - Weight::from_parts(30_010_000, 0) - .saturating_add(Weight::from_parts(0, 7665)) - .saturating_add(RocksDbWeight::get().reads(3_u64)) + // Measured: `396` + // Estimated: `14173` + // Minimum execution time: 37_327_000 picoseconds. + Weight::from_parts(37_874_000, 14173) + .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) /// Storage: Nfts Collection (r:1 w:0) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) /// Storage: Nfts CollectionConfigOf (r:1 w:0) /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) /// Storage: Nfts CollectionMetadataOf (r:1 w:1) /// Proof: Nfts CollectionMetadataOf (max_values: None, max_size: Some(87), added: 2562, mode: MaxEncodedLen) fn clear_collection_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `476` - // Estimated: `7665` - // Minimum execution time: 27_608 nanoseconds. - Weight::from_parts(28_766_000, 0) - .saturating_add(Weight::from_parts(0, 7665)) - .saturating_add(RocksDbWeight::get().reads(3_u64)) + // Measured: `539` + // Estimated: `14173` + // Minimum execution time: 35_305_000 picoseconds. + Weight::from_parts(36_213_000, 14173) + .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Nfts Item (r:1 w:1) /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) /// Storage: Nfts CollectionConfigOf (r:1 w:0) /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: Nfts CollectionRoleOf (r:1 w:0) - /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) fn approve_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `466` - // Estimated: `8428` - // Minimum execution time: 23_987 nanoseconds. - Weight::from_parts(24_819_000, 0) - .saturating_add(Weight::from_parts(0, 8428)) - .saturating_add(RocksDbWeight::get().reads(3_u64)) + // Measured: `408` + // Estimated: `7864` + // Minimum execution time: 22_680_000 picoseconds. + Weight::from_parts(23_126_000, 7864) + .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Nfts Item (r:1 w:1) /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) - /// Storage: Nfts CollectionRoleOf (r:1 w:0) - /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) fn cancel_approval() -> Weight { // Proof Size summary in bytes: - // Measured: `474` - // Estimated: `5880` - // Minimum execution time: 21_254 nanoseconds. - Weight::from_parts(21_826_000, 0) - .saturating_add(Weight::from_parts(0, 5880)) - .saturating_add(RocksDbWeight::get().reads(2_u64)) + // Measured: `416` + // Estimated: `4326` + // Minimum execution time: 19_837_000 picoseconds. + Weight::from_parts(20_352_000, 4326) + .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Nfts Item (r:1 w:1) /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) - /// Storage: Nfts CollectionRoleOf (r:1 w:0) - /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) fn clear_all_transfer_approvals() -> Weight { // Proof Size summary in bytes: - // Measured: `474` - // Estimated: `5880` - // Minimum execution time: 20_272 nanoseconds. - Weight::from_parts(20_922_000, 0) - .saturating_add(Weight::from_parts(0, 5880)) - .saturating_add(RocksDbWeight::get().reads(2_u64)) + // Measured: `416` + // Estimated: `4326` + // Minimum execution time: 18_911_000 picoseconds. + Weight::from_parts(19_233_000, 4326) + .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Nfts OwnershipAcceptance (r:1 w:1) @@ -1339,38 +1256,35 @@ impl WeightInfo for () { fn set_accept_ownership() -> Weight { // Proof Size summary in bytes: // Measured: `42` - // Estimated: `2527` - // Minimum execution time: 14_287 nanoseconds. - Weight::from_parts(14_960_000, 0) - .saturating_add(Weight::from_parts(0, 2527)) + // Estimated: `3517` + // Minimum execution time: 17_292_000 picoseconds. + Weight::from_parts(17_568_000, 3517) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Nfts CollectionConfigOf (r:1 w:1) /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) /// Storage: Nfts Collection (r:1 w:0) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) fn set_collection_max_supply() -> Weight { // Proof Size summary in bytes: - // Measured: `333` - // Estimated: `5103` - // Minimum execution time: 17_948 nanoseconds. - Weight::from_parts(18_780_000, 0) - .saturating_add(Weight::from_parts(0, 5103)) + // Measured: `338` + // Estimated: `7087` + // Minimum execution time: 20_323_000 picoseconds. + Weight::from_parts(20_692_000, 7087) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Nfts Collection (r:1 w:0) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) /// Storage: Nfts CollectionConfigOf (r:1 w:1) /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) fn update_mint_settings() -> Weight { // Proof Size summary in bytes: - // Measured: `333` - // Estimated: `5103` - // Minimum execution time: 16_616 nanoseconds. - Weight::from_parts(17_155_000, 0) - .saturating_add(Weight::from_parts(0, 5103)) + // Measured: `289` + // Estimated: `7072` + // Minimum execution time: 19_971_000 picoseconds. + Weight::from_parts(20_159_000, 7072) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1385,10 +1299,9 @@ impl WeightInfo for () { fn set_price() -> Weight { // Proof Size summary in bytes: // Measured: `516` - // Estimated: `8407` - // Minimum execution time: 22_777 nanoseconds. - Weight::from_parts(23_955_000, 0) - .saturating_add(Weight::from_parts(0, 8407)) + // Estimated: `11377` + // Minimum execution time: 26_202_000 picoseconds. + Weight::from_parts(26_499_000, 11377) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1397,37 +1310,33 @@ impl WeightInfo for () { /// Storage: Nfts ItemPriceOf (r:1 w:1) /// Proof: Nfts ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) /// Storage: Nfts Collection (r:1 w:0) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) /// Storage: Nfts CollectionConfigOf (r:1 w:0) /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) /// Storage: Nfts ItemConfigOf (r:1 w:0) /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: Nfts Account (r:0 w:2) /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) /// Storage: Nfts PendingSwapOf (r:0 w:1) /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) fn buy_item() -> Weight { // Proof Size summary in bytes: - // Measured: `934` - // Estimated: `16129` - // Minimum execution time: 61_131 nanoseconds. - Weight::from_parts(62_791_000, 0) - .saturating_add(Weight::from_parts(0, 16129)) - .saturating_add(RocksDbWeight::get().reads(6_u64)) - .saturating_add(RocksDbWeight::get().writes(6_u64)) + // Measured: `767` + // Estimated: `18480` + // Minimum execution time: 50_601_000 picoseconds. + Weight::from_parts(51_283_000, 18480) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(5_u64)) } /// The range of component `n` is `[0, 10]`. fn pay_tips(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_952 nanoseconds. - Weight::from_parts(3_975_700, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 11_254 - .saturating_add(Weight::from_parts(3_501_698, 0).saturating_mul(n.into())) + // Minimum execution time: 2_733_000 picoseconds. + Weight::from_parts(5_568_590, 0) + // Standard Error: 14_136 + .saturating_add(Weight::from_parts(3_763_928, 0).saturating_mul(n.into())) } /// Storage: Nfts Item (r:2 w:0) /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) @@ -1436,10 +1345,9 @@ impl WeightInfo for () { fn create_swap() -> Weight { // Proof Size summary in bytes: // Measured: `524` - // Estimated: `6672` - // Minimum execution time: 20_327 nanoseconds. - Weight::from_parts(21_714_000, 0) - .saturating_add(Weight::from_parts(0, 6672)) + // Estimated: `7662` + // Minimum execution time: 22_901_000 picoseconds. + Weight::from_parts(23_673_000, 7662) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1450,10 +1358,9 @@ impl WeightInfo for () { fn cancel_swap() -> Weight { // Proof Size summary in bytes: // Measured: `511` - // Estimated: `5882` - // Minimum execution time: 20_668 nanoseconds. - Weight::from_parts(21_416_000, 0) - .saturating_add(Weight::from_parts(0, 5882)) + // Estimated: `7862` + // Minimum execution time: 22_532_000 picoseconds. + Weight::from_parts(22_831_000, 7862) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1462,29 +1369,28 @@ impl WeightInfo for () { /// Storage: Nfts PendingSwapOf (r:1 w:2) /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) /// Storage: Nfts Collection (r:1 w:0) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) /// Storage: Nfts CollectionConfigOf (r:1 w:0) /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) /// Storage: Nfts ItemConfigOf (r:2 w:0) /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: Nfts Account (r:0 w:4) /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) /// Storage: Nfts ItemPriceOf (r:0 w:2) /// Proof: Nfts ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) fn claim_swap() -> Weight { // Proof Size summary in bytes: - // Measured: `1097` - // Estimated: `21970` - // Minimum execution time: 88_006 nanoseconds. - Weight::from_parts(90_390_000, 0) - .saturating_add(Weight::from_parts(0, 21970)) - .saturating_add(RocksDbWeight::get().reads(8_u64)) - .saturating_add(RocksDbWeight::get().writes(11_u64)) + // Measured: `896` + // Estimated: `24321` + // Minimum execution time: 77_668_000 picoseconds. + Weight::from_parts(78_407_000, 24321) + .saturating_add(RocksDbWeight::get().reads(7_u64)) + .saturating_add(RocksDbWeight::get().writes(10_u64)) } /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: Nfts CollectionRoleOf (r:2 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) /// Storage: Nfts CollectionConfigOf (r:1 w:0) /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) /// Storage: Nfts Item (r:1 w:1) @@ -1502,14 +1408,13 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 10]`. fn mint_pre_signed(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `596` - // Estimated: `16180 + n * (2921 ±0)` - // Minimum execution time: 124_967 nanoseconds. - Weight::from_parts(131_602_642, 0) - .saturating_add(Weight::from_parts(0, 16180)) - // Standard Error: 36_480 - .saturating_add(Weight::from_parts(25_811_394, 0).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(6_u64)) + // Measured: `659` + // Estimated: `29192 + n * (2921 ±0)` + // Minimum execution time: 133_147_000 picoseconds. + Weight::from_parts(138_031_439, 29192) + // Standard Error: 28_665 + .saturating_add(Weight::from_parts(28_206_062, 0).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(6_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) @@ -1519,10 +1424,10 @@ impl WeightInfo for () { /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) /// Storage: Nfts ItemAttributesApprovalsOf (r:1 w:1) /// Proof: Nfts ItemAttributesApprovalsOf (max_values: None, max_size: Some(681), added: 3156, mode: MaxEncodedLen) - /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) /// Storage: Nfts CollectionConfigOf (r:1 w:0) /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) /// Storage: Nfts Attribute (r:10 w:10) /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) /// Storage: System Account (r:1 w:1) @@ -1530,13 +1435,12 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 10]`. fn set_attributes_pre_signed(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `716` - // Estimated: `14198 + n * (2921 ±0)` - // Minimum execution time: 84_153 nanoseconds. - Weight::from_parts(96_401_623, 0) - .saturating_add(Weight::from_parts(0, 14198)) - // Standard Error: 70_244 - .saturating_add(Weight::from_parts(26_866_222, 0).saturating_mul(n.into())) + // Measured: `721` + // Estimated: `20142 + n * (2921 ±0)` + // Minimum execution time: 78_243_000 picoseconds. + Weight::from_parts(90_947_408, 20142) + // Standard Error: 75_516 + .saturating_add(Weight::from_parts(28_059_623, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(2_u64)) From 1bbde5d7c50e55458ff3925ed0ee911d035719d5 Mon Sep 17 00:00:00 2001 From: Vivek Pandya Date: Mon, 13 Mar 2023 21:00:05 +0530 Subject: [PATCH 499/715] Remove use of trait Store from all pallets and deprecate it. (#13535) * Remove use of trait Store from staking pallet * Remove use of trait Store from bounties pallet * Remove use of trait Store from collective pallet * Remove use of trait Store from babe pallet * Remove use of trait Store from assets pallet * Remove use of trait Store from grandpa pallet * Remove use of trait Store from balances pallet * Remove use of trait Store from authorship pallet * Remove use of trait Store from authority-discovery pallet * Remove use of trait Store from atomic-swap pallet * Remove use of trait Store from sudo pallet * Remove use of trait Store from scheduler pallet * Remove use of trait Store from scored-pool pallet * Remove use of trait Store from society pallet * Remove use of trait Store from lottery pallet * Remove use of trait Store from executive pallet * Remove use of trait Store from democracy pallet * Remove use of trait Store from elections-phragmen pallet * Remove use of trait Store from indices pallet * Remove use of trait Store from identity pallet * Remove use of trait Store from multisig pallet * Remove use of trait Store from merkle-mountain-range pallet * Remove use of trait Store from im-online pallet * Remove use of trait Store from membership pallet * Remove use of trait Store from nicks pallet * Remove use of trait Store from session pallet * Remove use of trait Store from transaction-payment pallet * Remove use of trait Store from utility pallet * Remove use of trait Store from child-bounties pallet * Remove use of trait Store from nis pallet * Remove use of trait Store from nfts pallet * Remove use of trait Store from conviction-voting pallet * Remove use of trait Store from treasury pallet * Remove use of trait Store from vesting pallet * Remove use of trait Store from preimage pallet * Remove use of trait Store from uniques pallet * Remove use of trait Store from ranked-collective pallet * Remove use of trait Store from beefy-mmr pallet * Remove use of trait Store from referenda pallet * Remove use of trait Store from whitelist pallet * Remove use of trait Store from alliance pallet * Remove use of trait Store from nomination-pools pallet * Remove use of trait Store from state-trie-migration pallet * Remove use of trait Store from message-queue pallet * Remove use of trait Store from root-offences pallet * Remove use of trait Store from root-testing pallet * Remove use of trait Store from timestamps pallet * Remove use of trait Store from system pallet * Remove use of trait Store from offences pallet * Remove use of trait Store from recovery pallet * Remove use of trait Store from node-authorization pallet * Remove use of trait Store from proxy pallet * Remove use of trait Store from benchmarking pallet * Remove use of trait Store from bags-list pallet * Add deprecated warning in store_trait * Change warning message * Run cargo fmt * Fix warning and update tests * Remove unnecessary allow deprecated * Remove use of trait Store * Fix mismatch in expected output * Minor update to warning message for deprecation of generate_store with Store trait attribute * Fixes as per review comments * Fixes as per review suggestions * Remove use of Store trait from core-fellowship pallet * Fix type in store_trait.rs * Fixes as pre review comment --- bin/node-template/pallets/template/src/lib.rs | 1 - frame/alliance/src/lib.rs | 1 - frame/assets/src/lib.rs | 1 - frame/atomic-swap/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/benchmarking/pov/src/lib.rs | 1 - frame/benchmarking/src/tests.rs | 1 - frame/benchmarking/src/tests_instance.rs | 1 - frame/bounties/src/lib.rs | 1 - frame/child-bounties/src/lib.rs | 1 - frame/collective/src/lib.rs | 1 - frame/collective/src/tests.rs | 1 - frame/conviction-voting/src/lib.rs | 1 - frame/core-fellowship/src/lib.rs | 1 - frame/democracy/src/lib.rs | 1 - frame/elections-phragmen/src/lib.rs | 1 - frame/examples/basic/src/lib.rs | 1 - frame/examples/offchain-worker/src/lib.rs | 1 - frame/executive/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 - .../src/lib.rs | 4 +- frame/lottery/src/lib.rs | 1 - frame/membership/src/lib.rs | 1 - frame/merkle-mountain-range/src/lib.rs | 1 - frame/message-queue/src/lib.rs | 3 +- frame/multisig/src/lib.rs | 1 - frame/nfts/src/lib.rs | 1 - frame/nicks/src/lib.rs | 1 - frame/nis/src/lib.rs | 1 - frame/node-authorization/src/lib.rs | 1 - frame/nomination-pools/src/lib.rs | 1 - frame/offences/src/lib.rs | 1 - frame/preimage/src/lib.rs | 1 - frame/proxy/src/lib.rs | 1 - frame/ranked-collective/src/lib.rs | 1 - frame/recovery/src/lib.rs | 1 - frame/referenda/src/lib.rs | 1 - frame/root-offences/src/lib.rs | 1 - frame/root-testing/src/lib.rs | 1 - frame/salary/src/lib.rs | 1 - frame/scheduler/src/lib.rs | 1 - frame/scheduler/src/mock.rs | 1 - frame/scored-pool/src/lib.rs | 1 - frame/session/src/historical/mod.rs | 5 +-- frame/session/src/lib.rs | 1 - frame/society/src/lib.rs | 1 - frame/staking/src/migrations.rs | 2 +- frame/staking/src/pallet/impls.rs | 4 +- frame/staking/src/pallet/mod.rs | 5 +-- frame/staking/src/slashing.rs | 41 +++++++++-------- frame/staking/src/tests.rs | 44 +++++++++---------- frame/state-trie-migration/src/lib.rs | 1 - frame/sudo/src/lib.rs | 1 - frame/sudo/src/mock.rs | 1 - .../src/pallet/expand/store_trait.rs | 13 +++++- .../src/pallet/parse/pallet_struct.rs | 10 ++--- frame/support/test/tests/pallet.rs | 11 ----- frame/support/test/tests/pallet_instance.rs | 2 - .../tests/pallet_ui/deprecated_store_attr.rs | 11 +++++ .../pallet_ui/deprecated_store_attr.stderr | 9 ++++ .../tests/pallet_ui/duplicate_call_attr.rs | 1 - .../pallet_ui/duplicate_call_attr.stderr | 4 +- .../pallet_ui/duplicate_storage_prefix.rs | 1 - .../pallet_ui/duplicate_storage_prefix.stderr | 32 +++++++------- .../pallet_ui/duplicate_store_attr.stderr | 4 +- .../pallet_ui/store_trait_leak_private.stderr | 12 ++++- frame/system/benches/bench.rs | 1 - frame/system/src/lib.rs | 1 - frame/timestamp/src/lib.rs | 1 - frame/tips/src/lib.rs | 1 - .../asset-tx-payment/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/utility/src/lib.rs | 1 - frame/utility/src/tests.rs | 1 - frame/vesting/src/lib.rs | 1 - frame/whitelist/src/lib.rs | 1 - test-utils/runtime/src/system.rs | 1 - utils/frame/rpc/support/src/lib.rs | 1 - 89 files changed, 119 insertions(+), 168 deletions(-) create mode 100644 frame/support/test/tests/pallet_ui/deprecated_store_attr.rs create mode 100644 frame/support/test/tests/pallet_ui/deprecated_store_attr.stderr diff --git a/bin/node-template/pallets/template/src/lib.rs b/bin/node-template/pallets/template/src/lib.rs index 4630e344add31..9f17623db328f 100644 --- a/bin/node-template/pallets/template/src/lib.rs +++ b/bin/node-template/pallets/template/src/lib.rs @@ -20,7 +20,6 @@ pub mod pallet { 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. diff --git a/frame/alliance/src/lib.rs b/frame/alliance/src/lib.rs index c9232a1f2fb8e..6cc162f7d2f3d 100644 --- a/frame/alliance/src/lib.rs +++ b/frame/alliance/src/lib.rs @@ -222,7 +222,6 @@ pub mod pallet { use super::*; #[pallet::pallet] - #[pallet::generate_store(pub (super) trait Store)] #[pallet::storage_version(migration::STORAGE_VERSION)] pub struct Pallet(PhantomData<(T, I)>); diff --git a/frame/assets/src/lib.rs b/frame/assets/src/lib.rs index 662c20e00fb1a..bb0e8ce8b3704 100644 --- a/frame/assets/src/lib.rs +++ b/frame/assets/src/lib.rs @@ -197,7 +197,6 @@ pub mod pallet { const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] #[pallet::storage_version(STORAGE_VERSION)] pub struct Pallet(_); diff --git a/frame/atomic-swap/src/lib.rs b/frame/atomic-swap/src/lib.rs index 68d2544204b83..ed89a88698a3c 100644 --- a/frame/atomic-swap/src/lib.rs +++ b/frame/atomic-swap/src/lib.rs @@ -184,7 +184,6 @@ pub mod pallet { } #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] pub struct Pallet(PhantomData); #[pallet::storage] diff --git a/frame/authority-discovery/src/lib.rs b/frame/authority-discovery/src/lib.rs index e93deabeb5318..341646b674e48 100644 --- a/frame/authority-discovery/src/lib.rs +++ b/frame/authority-discovery/src/lib.rs @@ -38,7 +38,6 @@ pub mod pallet { use frame_support::pallet_prelude::*; #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] pub struct Pallet(_); #[pallet::config] diff --git a/frame/authorship/src/lib.rs b/frame/authorship/src/lib.rs index cb1d777fa56c3..4bb8ba587ac8b 100644 --- a/frame/authorship/src/lib.rs +++ b/frame/authorship/src/lib.rs @@ -49,7 +49,6 @@ pub mod pallet { } #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] pub struct Pallet(_); #[pallet::hooks] diff --git a/frame/babe/src/lib.rs b/frame/babe/src/lib.rs index 903f6249e3310..61284267b07e7 100644 --- a/frame/babe/src/lib.rs +++ b/frame/babe/src/lib.rs @@ -114,7 +114,6 @@ pub mod pallet { /// The BABE Pallet #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] pub struct Pallet(_); #[pallet::config] diff --git a/frame/bags-list/src/lib.rs b/frame/bags-list/src/lib.rs index b65b65c39223d..87eb2d1b341aa 100644 --- a/frame/bags-list/src/lib.rs +++ b/frame/bags-list/src/lib.rs @@ -99,7 +99,6 @@ pub mod pallet { use frame_system::pallet_prelude::*; #[pallet::pallet] - #[pallet::generate_store(pub(crate) trait Store)] pub struct Pallet(_); #[pallet::config] diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index f02c7f9c0c579..ecd7e171e39ec 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -253,7 +253,6 @@ pub mod pallet { 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)>); diff --git a/frame/beefy-mmr/src/lib.rs b/frame/beefy-mmr/src/lib.rs index ba52be4f883f0..b9d4bdfd8eb59 100644 --- a/frame/beefy-mmr/src/lib.rs +++ b/frame/beefy-mmr/src/lib.rs @@ -95,7 +95,6 @@ pub mod pallet { /// BEEFY-MMR pallet. #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] pub struct Pallet(_); /// The module's configuration trait. diff --git a/frame/benchmarking/pov/src/lib.rs b/frame/benchmarking/pov/src/lib.rs index b66b5e417817a..dccfe72d3f243 100644 --- a/frame/benchmarking/pov/src/lib.rs +++ b/frame/benchmarking/pov/src/lib.rs @@ -32,7 +32,6 @@ pub mod pallet { use sp_std::prelude::*; #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] pub struct Pallet(PhantomData); #[pallet::config] diff --git a/frame/benchmarking/src/tests.rs b/frame/benchmarking/src/tests.rs index a3e19cde3642e..453e8e125cbb3 100644 --- a/frame/benchmarking/src/tests.rs +++ b/frame/benchmarking/src/tests.rs @@ -35,7 +35,6 @@ mod pallet_test { use frame_system::pallet_prelude::*; #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] pub struct Pallet(PhantomData); #[pallet::config] diff --git a/frame/benchmarking/src/tests_instance.rs b/frame/benchmarking/src/tests_instance.rs index 49f9786d77ea1..d49d7cc817c6b 100644 --- a/frame/benchmarking/src/tests_instance.rs +++ b/frame/benchmarking/src/tests_instance.rs @@ -34,7 +34,6 @@ mod pallet_test { use frame_system::pallet_prelude::*; #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] pub struct Pallet(PhantomData<(T, I)>); pub trait OtherConfig { diff --git a/frame/bounties/src/lib.rs b/frame/bounties/src/lib.rs index 325347502a918..e7a3e2053c065 100644 --- a/frame/bounties/src/lib.rs +++ b/frame/bounties/src/lib.rs @@ -188,7 +188,6 @@ pub mod pallet { use super::*; #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] pub struct Pallet(_); #[pallet::config] diff --git a/frame/child-bounties/src/lib.rs b/frame/child-bounties/src/lib.rs index 3046d97007cae..094b41822c433 100644 --- a/frame/child-bounties/src/lib.rs +++ b/frame/child-bounties/src/lib.rs @@ -130,7 +130,6 @@ pub mod pallet { use super::*; #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] pub struct Pallet(_); #[pallet::config] diff --git a/frame/collective/src/lib.rs b/frame/collective/src/lib.rs index ae5b22559d7c8..c58965d2c9199 100644 --- a/frame/collective/src/lib.rs +++ b/frame/collective/src/lib.rs @@ -175,7 +175,6 @@ pub mod pallet { 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<(T, I)>); diff --git a/frame/collective/src/tests.rs b/frame/collective/src/tests.rs index 2d9b31a539d59..79f6cc27fadbd 100644 --- a/frame/collective/src/tests.rs +++ b/frame/collective/src/tests.rs @@ -57,7 +57,6 @@ mod mock_democracy { use frame_system::pallet_prelude::*; #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] pub struct Pallet(_); #[pallet::config] diff --git a/frame/conviction-voting/src/lib.rs b/frame/conviction-voting/src/lib.rs index 6c15c6cf25b13..f28953c4a35b9 100644 --- a/frame/conviction-voting/src/lib.rs +++ b/frame/conviction-voting/src/lib.rs @@ -92,7 +92,6 @@ pub mod pallet { use frame_system::pallet_prelude::*; #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] pub struct Pallet(_); #[pallet::config] diff --git a/frame/core-fellowship/src/lib.rs b/frame/core-fellowship/src/lib.rs index 6ba60dbaf2559..93d2302448989 100644 --- a/frame/core-fellowship/src/lib.rs +++ b/frame/core-fellowship/src/lib.rs @@ -148,7 +148,6 @@ pub mod pallet { const RANK_COUNT: usize = 9; #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] pub struct Pallet(PhantomData<(T, I)>); #[pallet::config] diff --git a/frame/democracy/src/lib.rs b/frame/democracy/src/lib.rs index e1e111e96313f..a3d7f103a98f3 100644 --- a/frame/democracy/src/lib.rs +++ b/frame/democracy/src/lib.rs @@ -217,7 +217,6 @@ pub mod pallet { const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] #[pallet::storage_version(STORAGE_VERSION)] pub struct Pallet(_); diff --git a/frame/elections-phragmen/src/lib.rs b/frame/elections-phragmen/src/lib.rs index fa63762c5e09a..e3eed6ec4bcc4 100644 --- a/frame/elections-phragmen/src/lib.rs +++ b/frame/elections-phragmen/src/lib.rs @@ -187,7 +187,6 @@ pub mod pallet { 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); diff --git a/frame/examples/basic/src/lib.rs b/frame/examples/basic/src/lib.rs index a75a0e17cceba..6665c3b78b024 100644 --- a/frame/examples/basic/src/lib.rs +++ b/frame/examples/basic/src/lib.rs @@ -379,7 +379,6 @@ pub mod pallet { // Simple declaration of the `Pallet` type. It is placeholder we use to implement traits and // method. #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] pub struct Pallet(_); // Pallet implements [`Hooks`] trait to define some logic to execute in some context. diff --git a/frame/examples/offchain-worker/src/lib.rs b/frame/examples/offchain-worker/src/lib.rs index c9c72f8e82514..418ad5d139ef3 100644 --- a/frame/examples/offchain-worker/src/lib.rs +++ b/frame/examples/offchain-worker/src/lib.rs @@ -158,7 +158,6 @@ pub mod pallet { } #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] pub struct Pallet(_); #[pallet::hooks] diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index b3a04c4fe0596..7a8de43140c35 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -706,7 +706,6 @@ mod tests { use frame_system::pallet_prelude::*; #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] pub struct Pallet(_); #[pallet::config] diff --git a/frame/grandpa/src/lib.rs b/frame/grandpa/src/lib.rs index 538cd365b5a1a..f01c25e49edd4 100644 --- a/frame/grandpa/src/lib.rs +++ b/frame/grandpa/src/lib.rs @@ -77,7 +77,6 @@ pub mod pallet { const STORAGE_VERSION: StorageVersion = StorageVersion::new(4); #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] #[pallet::storage_version(STORAGE_VERSION)] pub struct Pallet(_); diff --git a/frame/identity/src/lib.rs b/frame/identity/src/lib.rs index d1b764591dc79..f192ee2b461b3 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)] 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 39762945ca70e..bc1e541cef125 100644 --- a/frame/im-online/src/lib.rs +++ b/frame/im-online/src/lib.rs @@ -313,7 +313,6 @@ pub mod pallet { use frame_system::pallet_prelude::*; #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] pub struct Pallet(_); #[pallet::config] diff --git a/frame/indices/src/lib.rs b/frame/indices/src/lib.rs index 82dc48f7bce5b..74f86abb51914 100644 --- a/frame/indices/src/lib.rs +++ b/frame/indices/src/lib.rs @@ -75,7 +75,6 @@ pub mod pallet { } #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] pub struct Pallet(PhantomData); #[pallet::call] diff --git a/frame/insecure-randomness-collective-flip/src/lib.rs b/frame/insecure-randomness-collective-flip/src/lib.rs index c73419efe87fe..ad39c4c4fd885 100644 --- a/frame/insecure-randomness-collective-flip/src/lib.rs +++ b/frame/insecure-randomness-collective-flip/src/lib.rs @@ -17,7 +17,7 @@ //! # DO NOT USE IN PRODUCTION //! -//! The produced values do not fulfill the cryptographic requirements for random numbers. +//! The produced values do not fulfill the cryptographic requirements for random numbers. //! Should not be used for high-stake production use-cases. //! //! # Randomness Pallet @@ -51,7 +51,6 @@ //! use frame_system::pallet_prelude::*; //! //! #[pallet::pallet] -//! #[pallet::generate_store(pub(super) trait Store)] //! pub struct Pallet(_); //! //! #[pallet::config] @@ -94,7 +93,6 @@ pub mod pallet { use frame_system::pallet_prelude::*; #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] pub struct Pallet(_); #[pallet::config] diff --git a/frame/lottery/src/lib.rs b/frame/lottery/src/lib.rs index bd7ca40fb4556..178f221a8946f 100644 --- a/frame/lottery/src/lib.rs +++ b/frame/lottery/src/lib.rs @@ -123,7 +123,6 @@ pub mod pallet { use frame_system::pallet_prelude::*; #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] pub struct Pallet(_); /// The pallet's config trait. diff --git a/frame/membership/src/lib.rs b/frame/membership/src/lib.rs index 04263b93e1a89..0be33a95613fe 100644 --- a/frame/membership/src/lib.rs +++ b/frame/membership/src/lib.rs @@ -50,7 +50,6 @@ pub mod pallet { const STORAGE_VERSION: StorageVersion = StorageVersion::new(4); #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] #[pallet::storage_version(STORAGE_VERSION)] pub struct Pallet(PhantomData<(T, I)>); diff --git a/frame/merkle-mountain-range/src/lib.rs b/frame/merkle-mountain-range/src/lib.rs index 0b4c2f8d97a8b..4ef833e6c5fca 100644 --- a/frame/merkle-mountain-range/src/lib.rs +++ b/frame/merkle-mountain-range/src/lib.rs @@ -121,7 +121,6 @@ pub mod pallet { use frame_system::pallet_prelude::*; #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] pub struct Pallet(PhantomData<(T, I)>); /// This pallet's configuration trait diff --git a/frame/message-queue/src/lib.rs b/frame/message-queue/src/lib.rs index bed131e5f0669..c8e1976103ebf 100644 --- a/frame/message-queue/src/lib.rs +++ b/frame/message-queue/src/lib.rs @@ -39,7 +39,7 @@ //! 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. +//! `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. @@ -438,7 +438,6 @@ pub mod pallet { use super::*; #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] pub struct Pallet(_); /// The module configuration trait. diff --git a/frame/multisig/src/lib.rs b/frame/multisig/src/lib.rs index fb10838cedc44..64058be9c8fbf 100644 --- a/frame/multisig/src/lib.rs +++ b/frame/multisig/src/lib.rs @@ -172,7 +172,6 @@ pub mod pallet { const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] #[pallet::storage_version(STORAGE_VERSION)] pub struct Pallet(_); diff --git a/frame/nfts/src/lib.rs b/frame/nfts/src/lib.rs index 4d9547659a2a7..254fa75964ab8 100644 --- a/frame/nfts/src/lib.rs +++ b/frame/nfts/src/lib.rs @@ -75,7 +75,6 @@ pub mod pallet { const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] #[pallet::storage_version(STORAGE_VERSION)] pub struct Pallet(PhantomData<(T, I)>); diff --git a/frame/nicks/src/lib.rs b/frame/nicks/src/lib.rs index b457cc2996dbf..b74d2e6ee40b2 100644 --- a/frame/nicks/src/lib.rs +++ b/frame/nicks/src/lib.rs @@ -114,7 +114,6 @@ pub mod pallet { StorageMap<_, Twox64Concat, T::AccountId, (BoundedVec, BalanceOf)>; #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] pub struct Pallet(_); #[pallet::call] diff --git a/frame/nis/src/lib.rs b/frame/nis/src/lib.rs index 9cae5e2aae5c1..6fd9c60a89836 100644 --- a/frame/nis/src/lib.rs +++ b/frame/nis/src/lib.rs @@ -310,7 +310,6 @@ pub mod pallet { } #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] pub struct Pallet(_); /// A single bid, an item of a *queue* in `Queues`. diff --git a/frame/node-authorization/src/lib.rs b/frame/node-authorization/src/lib.rs index d91a769b36ba0..eaeda3cade9e9 100644 --- a/frame/node-authorization/src/lib.rs +++ b/frame/node-authorization/src/lib.rs @@ -59,7 +59,6 @@ pub mod pallet { use frame_system::pallet_prelude::*; #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] #[pallet::without_storage_info] pub struct Pallet(_); diff --git a/frame/nomination-pools/src/lib.rs b/frame/nomination-pools/src/lib.rs index b296eb048562a..c1dda69ab5d67 100644 --- a/frame/nomination-pools/src/lib.rs +++ b/frame/nomination-pools/src/lib.rs @@ -1214,7 +1214,6 @@ pub mod pallet { const STORAGE_VERSION: StorageVersion = StorageVersion::new(3); #[pallet::pallet] - #[pallet::generate_store(pub(crate) trait Store)] #[pallet::storage_version(STORAGE_VERSION)] pub struct Pallet(_); diff --git a/frame/offences/src/lib.rs b/frame/offences/src/lib.rs index 8ac1ca0bd734c..c89d93c12bd95 100644 --- a/frame/offences/src/lib.rs +++ b/frame/offences/src/lib.rs @@ -49,7 +49,6 @@ pub mod pallet { use frame_support::pallet_prelude::*; #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] #[pallet::without_storage_info] pub struct Pallet(_); diff --git a/frame/preimage/src/lib.rs b/frame/preimage/src/lib.rs index 74a3176b1144a..60208424db953 100644 --- a/frame/preimage/src/lib.rs +++ b/frame/preimage/src/lib.rs @@ -107,7 +107,6 @@ pub mod pallet { } #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] #[pallet::storage_version(STORAGE_VERSION)] pub struct Pallet(PhantomData); diff --git a/frame/proxy/src/lib.rs b/frame/proxy/src/lib.rs index c26a53d1a0c40..023d0253519f7 100644 --- a/frame/proxy/src/lib.rs +++ b/frame/proxy/src/lib.rs @@ -102,7 +102,6 @@ pub mod pallet { use frame_system::pallet_prelude::*; #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] pub struct Pallet(_); /// Configuration trait. diff --git a/frame/ranked-collective/src/lib.rs b/frame/ranked-collective/src/lib.rs index 8ed1bbd2e01d6..288fd78d6e718 100644 --- a/frame/ranked-collective/src/lib.rs +++ b/frame/ranked-collective/src/lib.rs @@ -321,7 +321,6 @@ pub mod pallet { use frame_system::pallet_prelude::*; #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] pub struct Pallet(PhantomData<(T, I)>); #[pallet::config] diff --git a/frame/recovery/src/lib.rs b/frame/recovery/src/lib.rs index b32d19d5dda1d..d66b5725fd4f7 100644 --- a/frame/recovery/src/lib.rs +++ b/frame/recovery/src/lib.rs @@ -218,7 +218,6 @@ pub mod pallet { use sp_runtime::ArithmeticError; #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] pub struct Pallet(_); /// Configuration trait. diff --git a/frame/referenda/src/lib.rs b/frame/referenda/src/lib.rs index dccc40112867d..f699850062267 100644 --- a/frame/referenda/src/lib.rs +++ b/frame/referenda/src/lib.rs @@ -145,7 +145,6 @@ pub mod pallet { const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] #[pallet::storage_version(STORAGE_VERSION)] pub struct Pallet(_); diff --git a/frame/root-offences/src/lib.rs b/frame/root-offences/src/lib.rs index 92f3e17b5e17e..a93e7ff848718 100644 --- a/frame/root-offences/src/lib.rs +++ b/frame/root-offences/src/lib.rs @@ -57,7 +57,6 @@ pub mod pallet { } #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] pub struct Pallet(_); #[pallet::event] diff --git a/frame/root-testing/src/lib.rs b/frame/root-testing/src/lib.rs index ad0e4cfea7373..e04c7bfa13d26 100644 --- a/frame/root-testing/src/lib.rs +++ b/frame/root-testing/src/lib.rs @@ -39,7 +39,6 @@ pub mod pallet { pub trait Config: frame_system::Config {} #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] pub struct Pallet(_); #[pallet::call] diff --git a/frame/salary/src/lib.rs b/frame/salary/src/lib.rs index 5a4ff8a66da50..6f9e63271cc2f 100644 --- a/frame/salary/src/lib.rs +++ b/frame/salary/src/lib.rs @@ -155,7 +155,6 @@ pub mod pallet { use frame_system::pallet_prelude::*; #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] pub struct Pallet(PhantomData<(T, I)>); #[pallet::config] diff --git a/frame/scheduler/src/lib.rs b/frame/scheduler/src/lib.rs index 95bfe8411f381..09bb3561188f8 100644 --- a/frame/scheduler/src/lib.rs +++ b/frame/scheduler/src/lib.rs @@ -172,7 +172,6 @@ pub mod pallet { const STORAGE_VERSION: StorageVersion = StorageVersion::new(4); #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] #[pallet::storage_version(STORAGE_VERSION)] pub struct Pallet(_); diff --git a/frame/scheduler/src/mock.rs b/frame/scheduler/src/mock.rs index 914a97ab9d5d7..adb54fd78b181 100644 --- a/frame/scheduler/src/mock.rs +++ b/frame/scheduler/src/mock.rs @@ -50,7 +50,6 @@ pub mod logger { } #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] pub struct Pallet(PhantomData); #[pallet::hooks] diff --git a/frame/scored-pool/src/lib.rs b/frame/scored-pool/src/lib.rs index 16d59b6609000..336a69a798477 100644 --- a/frame/scored-pool/src/lib.rs +++ b/frame/scored-pool/src/lib.rs @@ -135,7 +135,6 @@ pub mod pallet { use frame_system::pallet_prelude::*; #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] pub struct Pallet(_); #[pallet::config] diff --git a/frame/session/src/historical/mod.rs b/frame/session/src/historical/mod.rs index d9827679400b8..f00a1c95e763e 100644 --- a/frame/session/src/historical/mod.rs +++ b/frame/session/src/historical/mod.rs @@ -62,7 +62,6 @@ pub mod pallet { const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] #[pallet::storage_version(STORAGE_VERSION)] pub struct Pallet(_); @@ -97,7 +96,7 @@ impl Pallet { /// Prune historical stored session roots up to (but not including) /// `up_to`. pub fn prune_up_to(up_to: SessionIndex) { - ::StoredRange::mutate(|range| { + StoredRange::::mutate(|range| { let (start, end) = match *range { Some(range) => range, None => return, // nothing to prune. @@ -109,7 +108,7 @@ impl Pallet { return // out of bounds. harmless. } - (start..up_to).for_each(::HistoricalSessions::remove); + (start..up_to).for_each(HistoricalSessions::::remove); let new_start = up_to; *range = if new_start == end { diff --git a/frame/session/src/lib.rs b/frame/session/src/lib.rs index 7d5dd632493f3..ed5f80e6099c1 100644 --- a/frame/session/src/lib.rs +++ b/frame/session/src/lib.rs @@ -371,7 +371,6 @@ pub mod pallet { const STORAGE_VERSION: StorageVersion = StorageVersion::new(0); #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] #[pallet::storage_version(STORAGE_VERSION)] #[pallet::without_storage_info] pub struct Pallet(_); diff --git a/frame/society/src/lib.rs b/frame/society/src/lib.rs index f3207dabdaf8f..899b6005af024 100644 --- a/frame/society/src/lib.rs +++ b/frame/society/src/lib.rs @@ -371,7 +371,6 @@ pub mod pallet { use super::*; #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] #[pallet::without_storage_info] pub struct Pallet(_); diff --git a/frame/staking/src/migrations.rs b/frame/staking/src/migrations.rs index 3c33ae2a35d62..23bcfa4398627 100644 --- a/frame/staking/src/migrations.rs +++ b/frame/staking/src/migrations.rs @@ -265,7 +265,7 @@ pub mod v10 { impl OnRuntimeUpgrade for MigrateToV10 { fn on_runtime_upgrade() -> frame_support::weights::Weight { if StorageVersion::::get() == ObsoleteReleases::V9_0_0 { - let pending_slashes = as Store>::UnappliedSlashes::iter().take(512); + let pending_slashes = 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 diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 78c9a51bc829c..760345e8ddb28 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -682,7 +682,7 @@ impl Pallet { /// Apply previously-unapplied slashes on the beginning of a new era, after a delay. fn apply_unapplied_slashes(active_era: EraIndex) { - let era_slashes = ::UnappliedSlashes::take(&active_era); + let era_slashes = UnappliedSlashes::::take(&active_era); log!( debug, "found {} slashes scheduled to be executed in era {:?}", @@ -1369,7 +1369,7 @@ where active_era, slash_era + slash_defer_duration + 1, ); - ::UnappliedSlashes::mutate( + UnappliedSlashes::::mutate( slash_era.saturating_add(slash_defer_duration).saturating_add(One::one()), move |for_later| for_later.push(unapplied), ); diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index a030538878241..d8f1855da4bc0 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -68,7 +68,6 @@ pub mod pallet { const STORAGE_VERSION: StorageVersion = StorageVersion::new(13); #[pallet::pallet] - #[pallet::generate_store(pub(crate) trait Store)] #[pallet::storage_version(STORAGE_VERSION)] pub struct Pallet(_); @@ -1452,7 +1451,7 @@ pub mod pallet { ensure!(!slash_indices.is_empty(), Error::::EmptyTargets); ensure!(is_sorted_and_unique(&slash_indices), Error::::NotSortedAndUnique); - let mut unapplied = ::UnappliedSlashes::get(&era); + let mut unapplied = UnappliedSlashes::::get(&era); let last_item = slash_indices[slash_indices.len() - 1]; ensure!((last_item as usize) < unapplied.len(), Error::::InvalidSlashIndex); @@ -1461,7 +1460,7 @@ pub mod pallet { unapplied.remove(index); } - ::UnappliedSlashes::insert(&era, &unapplied); + UnappliedSlashes::::insert(&era, &unapplied); Ok(()) } diff --git a/frame/staking/src/slashing.rs b/frame/staking/src/slashing.rs index f73e3a6f818a2..bb02da73f6e5d 100644 --- a/frame/staking/src/slashing.rs +++ b/frame/staking/src/slashing.rs @@ -50,8 +50,9 @@ //! Based on research at use crate::{ - BalanceOf, Config, Error, Exposure, NegativeImbalanceOf, Pallet, Perbill, SessionInterface, - Store, UnappliedSlash, + BalanceOf, Config, Error, Exposure, NegativeImbalanceOf, NominatorSlashInEra, + OffendingValidators, Pallet, Perbill, SessionInterface, SpanSlash, UnappliedSlash, + ValidatorSlashInEra, }; use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ @@ -239,14 +240,13 @@ pub(crate) fn compute_slash( return None } - let prior_slash_p = - as Store>::ValidatorSlashInEra::get(¶ms.slash_era, params.stash) - .map_or(Zero::zero(), |(prior_slash_proportion, _)| prior_slash_proportion); + let prior_slash_p = ValidatorSlashInEra::::get(¶ms.slash_era, params.stash) + .map_or(Zero::zero(), |(prior_slash_proportion, _)| prior_slash_proportion); // compare slash proportions rather than slash values to avoid issues due to rounding // error. if params.slash.deconstruct() > prior_slash_p.deconstruct() { - as Store>::ValidatorSlashInEra::insert( + ValidatorSlashInEra::::insert( ¶ms.slash_era, params.stash, &(params.slash, own_slash), @@ -327,7 +327,7 @@ fn kick_out_if_recent(params: SlashParams) { /// 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| { + OffendingValidators::::mutate(|offending| { let validators = T::SessionInterface::validators(); let validator_index = match validators.iter().position(|i| i == stash) { Some(index) => index, @@ -388,10 +388,9 @@ fn slash_nominators( let own_slash_difference = own_slash_by_validator.saturating_sub(own_slash_prior); let mut era_slash = - as Store>::NominatorSlashInEra::get(¶ms.slash_era, stash) - .unwrap_or_else(Zero::zero); + 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); + NominatorSlashInEra::::insert(¶ms.slash_era, stash, &era_slash); era_slash }; @@ -445,9 +444,9 @@ fn fetch_spans<'a, T: Config + 'a>( slash_of: &'a mut BalanceOf, reward_proportion: Perbill, ) -> InspectingSpans<'a, T> { - let spans = as Store>::SlashingSpans::get(stash).unwrap_or_else(|| { + let spans = crate::SlashingSpans::::get(stash).unwrap_or_else(|| { let spans = SlashingSpans::new(window_start); - as Store>::SlashingSpans::insert(stash, &spans); + crate::SlashingSpans::::insert(stash, &spans); spans }); @@ -496,7 +495,7 @@ impl<'a, T: 'a + Config> InspectingSpans<'a, T> { ) -> Option { let target_span = self.era_span(slash_era)?; let span_slash_key = (self.stash.clone(), target_span.index); - let mut span_record = as Store>::SpanSlash::get(&span_slash_key); + let mut span_record = SpanSlash::::get(&span_slash_key); let mut changed = false; let reward = if span_record.slashed < slash { @@ -527,7 +526,7 @@ impl<'a, T: 'a + Config> InspectingSpans<'a, T> { if changed { self.dirty = true; - as Store>::SpanSlash::insert(&span_slash_key, &span_record); + SpanSlash::::insert(&span_slash_key, &span_record); } Some(target_span.index) @@ -543,20 +542,20 @@ impl<'a, T: 'a + Config> Drop for InspectingSpans<'a, T> { if let Some((start, end)) = self.spans.prune(self.window_start) { for span_index in start..end { - as Store>::SpanSlash::remove(&(self.stash.clone(), span_index)); + SpanSlash::::remove(&(self.stash.clone(), span_index)); } } - as Store>::SlashingSpans::insert(self.stash, &self.spans); + crate::SlashingSpans::::insert(self.stash, &self.spans); } } /// 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); + ValidatorSlashInEra::::remove_prefix(&obsolete_era, None); #[allow(deprecated)] - as Store>::NominatorSlashInEra::remove_prefix(&obsolete_era, None); + NominatorSlashInEra::::remove_prefix(&obsolete_era, None); } /// Clear slashing metadata for a dead account. @@ -564,7 +563,7 @@ pub(crate) fn clear_stash_metadata( stash: &T::AccountId, num_slashing_spans: u32, ) -> DispatchResult { - let spans = match as Store>::SlashingSpans::get(stash) { + let spans = match crate::SlashingSpans::::get(stash) { None => return Ok(()), Some(s) => s, }; @@ -574,7 +573,7 @@ pub(crate) fn clear_stash_metadata( Error::::IncorrectSlashingSpans ); - as Store>::SlashingSpans::remove(stash); + crate::SlashingSpans::::remove(stash); // kill slashing-span metadata for account. // @@ -582,7 +581,7 @@ pub(crate) fn clear_stash_metadata( // in that case, they may re-bond, but it would count again as span 0. Further ancient // slashes would slash into this new bond, since metadata has now been cleared. for span in spans.iter() { - as Store>::SpanSlash::remove(&(stash.clone(), span.index)); + SpanSlash::::remove(&(stash.clone(), span.index)); } Ok(()) diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 16bafae01e3c3..966eae8c1da9a 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -512,10 +512,10 @@ fn no_candidate_emergency_condition() { // initial validators assert_eq_uvec!(validator_controllers(), vec![10, 20, 30, 40]); let prefs = ValidatorPrefs { commission: Perbill::one(), ..Default::default() }; - ::Validators::insert(11, prefs.clone()); + Validators::::insert(11, prefs.clone()); // set the minimum validator count. - ::MinimumValidatorCount::put(10); + MinimumValidatorCount::::put(10); // try to chill let res = Staking::chill(RuntimeOrigin::signed(10)); @@ -536,7 +536,7 @@ fn no_candidate_emergency_condition() { // changed) assert_eq_uvec!(validator_controllers(), vec![10, 20, 30, 40]); // The chill is still pending. - assert!(!::Validators::contains_key(11)); + assert!(!Validators::::contains_key(11)); // No new era is created. assert_eq!(current_era, CurrentEra::::get()); }); @@ -2432,7 +2432,7 @@ fn slash_in_old_span_does_not_deselect() { ); // the validator doesn't get chilled again - assert!(::Validators::iter().any(|(stash, _)| stash == 11)); + assert!(Validators::::iter().any(|(stash, _)| stash == 11)); // but we are still forcing a new era assert_eq!(Staking::force_era(), Forcing::ForceNew); @@ -2449,7 +2449,7 @@ fn slash_in_old_span_does_not_deselect() { ); // the validator doesn't get chilled again - assert!(::Validators::iter().any(|(stash, _)| stash == 11)); + assert!(Validators::::iter().any(|(stash, _)| stash == 11)); // but it's disabled assert!(is_disabled(10)); @@ -2648,8 +2648,8 @@ 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(), &200); + assert!(SlashingSpans::::get(&11).is_some()); + assert_eq!(SpanSlash::::get(&(11, 0)).amount(), &200); on_offence_now( &[OffenceDetails { @@ -2665,7 +2665,7 @@ fn garbage_collection_after_slashing() { assert_eq!(Balances::free_balance(11), 2); assert_eq!(Balances::total_balance(&11), 2); - let slashing_spans = ::SlashingSpans::get(&11).unwrap(); + let slashing_spans = SlashingSpans::::get(&11).unwrap(); assert_eq!(slashing_spans.iter().count(), 2); // reap_stash respects num_slashing_spans so that weight is accurate @@ -2675,8 +2675,8 @@ fn garbage_collection_after_slashing() { ); assert_ok!(Staking::reap_stash(RuntimeOrigin::signed(20), 11, 2)); - assert!(::SlashingSpans::get(&11).is_none()); - assert_eq!(::SpanSlash::get(&(11, 0)).amount(), &0); + assert!(SlashingSpans::::get(&11).is_none()); + assert_eq!(SpanSlash::::get(&(11, 0)).amount(), &0); }) } @@ -2702,19 +2702,19 @@ fn garbage_collection_on_window_pruning() { assert_eq!(Balances::free_balance(11), 900); assert_eq!(Balances::free_balance(101), 2000 - (nominated_value / 10)); - assert!(::ValidatorSlashInEra::get(&now, &11).is_some()); - assert!(::NominatorSlashInEra::get(&now, &101).is_some()); + assert!(ValidatorSlashInEra::::get(&now, &11).is_some()); + assert!(NominatorSlashInEra::::get(&now, &101).is_some()); // + 1 because we have to exit the bonding window. for era in (0..(BondingDuration::get() + 1)).map(|offset| offset + now + 1) { - assert!(::ValidatorSlashInEra::get(&now, &11).is_some()); - assert!(::NominatorSlashInEra::get(&now, &101).is_some()); + assert!(ValidatorSlashInEra::::get(&now, &11).is_some()); + assert!(NominatorSlashInEra::::get(&now, &101).is_some()); mock::start_active_era(era); } - assert!(::ValidatorSlashInEra::get(&now, &11).is_none()); - assert!(::NominatorSlashInEra::get(&now, &101).is_none()); + assert!(ValidatorSlashInEra::::get(&now, &11).is_none()); + assert!(NominatorSlashInEra::::get(&now, &101).is_none()); }) } @@ -2755,7 +2755,7 @@ fn slashing_nominators_by_span_max() { slashing::SlashingSpan { index: 0, start: 0, length: Some(4) }, ]; - let get_span = |account| ::SlashingSpans::get(&account).unwrap(); + let get_span = |account| SlashingSpans::::get(&account).unwrap(); assert_eq!(get_span(11).iter().collect::>(), expected_spans); @@ -2817,7 +2817,7 @@ fn slashes_are_summed_across_spans() { assert_eq!(Balances::free_balance(21), 2000); assert_eq!(Staking::slashable_balance_of(&21), 1000); - let get_span = |account| ::SlashingSpans::get(&account).unwrap(); + let get_span = |account| SlashingSpans::::get(&account).unwrap(); on_offence_now( &[OffenceDetails { @@ -3192,7 +3192,7 @@ fn remove_multi_deferred() { &[Perbill::from_percent(25)], ); - assert_eq!(::UnappliedSlashes::get(&4).len(), 5); + assert_eq!(UnappliedSlashes::::get(&4).len(), 5); // fails if list is not sorted assert_noop!( @@ -3212,7 +3212,7 @@ fn remove_multi_deferred() { assert_ok!(Staking::cancel_deferred_slash(RuntimeOrigin::root(), 4, vec![0, 2, 4])); - let slashes = ::UnappliedSlashes::get(&4); + let slashes = UnappliedSlashes::::get(&4); assert_eq!(slashes.len(), 2); assert_eq!(slashes[0].validator, 21); assert_eq!(slashes[1].validator, 42); @@ -3267,7 +3267,7 @@ fn slash_kicks_validators_not_nominators_and_disables_nominator_for_kicked_valid assert_eq!(Balances::free_balance(101), 2000 - nominator_slash_amount_11); // check that validator was chilled. - assert!(::Validators::iter().all(|(stash, _)| stash != 11)); + assert!(Validators::::iter().all(|(stash, _)| stash != 11)); // actually re-bond the slashed validator assert_ok!(Staking::validate(RuntimeOrigin::signed(10), Default::default())); @@ -3612,7 +3612,7 @@ fn zero_slash_keeps_nominators() { assert_eq!(Balances::free_balance(101), 2000); // 11 is still removed.. - assert!(::Validators::iter().all(|(stash, _)| stash != 11)); + assert!(Validators::::iter().all(|(stash, _)| stash != 11)); // but their nominations are kept. assert_eq!(Staking::nominators(101).unwrap().targets, vec![11, 21]); }); diff --git a/frame/state-trie-migration/src/lib.rs b/frame/state-trie-migration/src/lib.rs index 547dfa5cda9c8..5385c6b5f4f46 100644 --- a/frame/state-trie-migration/src/lib.rs +++ b/frame/state-trie-migration/src/lib.rs @@ -439,7 +439,6 @@ pub mod pallet { /// The outer Pallet struct. #[pallet::pallet] - #[pallet::generate_store(pub(crate) trait Store)] pub struct Pallet(_); /// Configurations of this pallet. diff --git a/frame/sudo/src/lib.rs b/frame/sudo/src/lib.rs index 4d5149926ac29..47309833a0681 100644 --- a/frame/sudo/src/lib.rs +++ b/frame/sudo/src/lib.rs @@ -133,7 +133,6 @@ pub mod pallet { } #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] pub struct Pallet(PhantomData); #[pallet::call] diff --git a/frame/sudo/src/mock.rs b/frame/sudo/src/mock.rs index 59a5cb6cc1a15..6d6043cfd1821 100644 --- a/frame/sudo/src/mock.rs +++ b/frame/sudo/src/mock.rs @@ -39,7 +39,6 @@ pub mod logger { } #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] pub struct Pallet(PhantomData); #[pallet::call] diff --git a/frame/support/procedural/src/pallet/expand/store_trait.rs b/frame/support/procedural/src/pallet/expand/store_trait.rs index 15a6a223e9708..251c88f08e7a0 100644 --- a/frame/support/procedural/src/pallet/expand/store_trait.rs +++ b/frame/support/procedural/src/pallet/expand/store_trait.rs @@ -22,7 +22,7 @@ use syn::spanned::Spanned; /// * generate Store trait with all storages, /// * implement Store trait for Pallet. pub fn expand_store_trait(def: &mut Def) -> proc_macro2::TokenStream { - let (trait_vis, trait_store) = + let (trait_vis, trait_store, attribute_span) = if let Some(store) = &def.pallet_struct.store { store } else { return Default::default() }; let type_impl_gen = &def.type_impl_generics(trait_store.span()); @@ -36,8 +36,19 @@ pub fn expand_store_trait(def: &mut Def) -> proc_macro2::TokenStream { let storage_names = &def.storages.iter().map(|storage| &storage.ident).collect::>(); let storage_cfg_attrs = &def.storages.iter().map(|storage| &storage.cfg_attrs).collect::>(); + let warnig_struct_name = syn::Ident::new("Store", *attribute_span); + let warning: syn::ItemStruct = syn::parse_quote!( + #[deprecated(note = r" + Use of `#[pallet::generate_store(pub(super) trait Store)]` will be removed soon. + Check https://github.com/paritytech/substrate/pull/13535 for more details.")] + struct #warnig_struct_name; + ); quote::quote_spanned!(trait_store.span() => + const _:() = { + #warning + const _: Option<#warnig_struct_name> = None; + }; #trait_vis trait #trait_store { #( #(#storage_cfg_attrs)* diff --git a/frame/support/procedural/src/pallet/parse/pallet_struct.rs b/frame/support/procedural/src/pallet/parse/pallet_struct.rs index 571298d5a12ec..98312d0652d8e 100644 --- a/frame/support/procedural/src/pallet/parse/pallet_struct.rs +++ b/frame/support/procedural/src/pallet/parse/pallet_struct.rs @@ -38,7 +38,7 @@ pub struct PalletStructDef { /// The keyword Pallet used (contains span). pub pallet: keyword::Pallet, /// Whether the trait `Store` must be generated. - pub store: Option<(syn::Visibility, keyword::Store)>, + pub store: Option<(syn::Visibility, keyword::Store, proc_macro2::Span)>, /// The span of the pallet::pallet attribute. pub attr_span: proc_macro2::Span, /// Whether to specify the storages max encoded len when implementing `StorageInfoTrait`. @@ -78,13 +78,13 @@ impl syn::parse::Parse for PalletStructAttr { let lookahead = content.lookahead1(); if lookahead.peek(keyword::generate_store) { - let span = content.parse::()?.span(); - + content.parse::()?; let generate_content; syn::parenthesized!(generate_content in content); let vis = generate_content.parse::()?; generate_content.parse::()?; let keyword = generate_content.parse::()?; + let span = content.span(); Ok(Self::GenerateStore { vis, keyword, span }) } else if lookahead.peek(keyword::without_storage_info) { let span = content.parse::()?.span(); @@ -123,8 +123,8 @@ impl PalletStructDef { let struct_attrs: Vec = helper::take_item_pallet_attrs(&mut item.attrs)?; for attr in struct_attrs { match attr { - PalletStructAttr::GenerateStore { vis, keyword, .. } if store.is_none() => { - store = Some((vis, keyword)); + PalletStructAttr::GenerateStore { vis, keyword, span } if store.is_none() => { + store = Some((vis, keyword, span)); }, PalletStructAttr::WithoutStorageInfoTrait(span) if without_storage_info.is_none() => diff --git a/frame/support/test/tests/pallet.rs b/frame/support/test/tests/pallet.rs index c33d2c8c9cf25..8e77cd0251184 100644 --- a/frame/support/test/tests/pallet.rs +++ b/frame/support/test/tests/pallet.rs @@ -158,7 +158,6 @@ pub mod pallet { } #[pallet::pallet] - #[pallet::generate_store(pub(crate) trait Store)] #[pallet::storage_version(STORAGE_VERSION)] pub struct Pallet(_); @@ -496,7 +495,6 @@ pub mod pallet2 { } #[pallet::pallet] - #[pallet::generate_store(pub(crate) trait Store)] #[pallet::without_storage_info] pub struct Pallet(_); @@ -946,15 +944,6 @@ fn validate_unsigned_expand() { assert_eq!(validity, ValidTransaction::default()); } -#[test] -fn trait_store_expand() { - TestExternalities::default().execute_with(|| { - as pallet::Store>::Value::get(); - as pallet::Store>::Map::get(1); - as pallet::Store>::DoubleMap::get(1, 2); - }) -} - #[test] fn pallet_expand_deposit_event() { TestExternalities::default().execute_with(|| { diff --git a/frame/support/test/tests/pallet_instance.rs b/frame/support/test/tests/pallet_instance.rs index 5beb1480a4e82..517f920c5ce07 100644 --- a/frame/support/test/tests/pallet_instance.rs +++ b/frame/support/test/tests/pallet_instance.rs @@ -46,7 +46,6 @@ pub mod pallet { } #[pallet::pallet] - #[pallet::generate_store(pub(crate) trait Store)] pub struct Pallet(PhantomData<(T, I)>); #[pallet::hooks] @@ -260,7 +259,6 @@ pub mod pallet2 { } #[pallet::pallet] - #[pallet::generate_store(pub(crate) trait Store)] pub struct Pallet(PhantomData<(T, I)>); #[pallet::event] diff --git a/frame/support/test/tests/pallet_ui/deprecated_store_attr.rs b/frame/support/test/tests/pallet_ui/deprecated_store_attr.rs new file mode 100644 index 0000000000000..0799a3fce8d58 --- /dev/null +++ b/frame/support/test/tests/pallet_ui/deprecated_store_attr.rs @@ -0,0 +1,11 @@ +#[frame_support::pallet] +mod pallet { + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + #[pallet::generate_store(trait Store)] + pub struct Pallet(core::marker::PhantomData); +} + +fn main() {} diff --git a/frame/support/test/tests/pallet_ui/deprecated_store_attr.stderr b/frame/support/test/tests/pallet_ui/deprecated_store_attr.stderr new file mode 100644 index 0000000000000..bbc4743fc1003 --- /dev/null +++ b/frame/support/test/tests/pallet_ui/deprecated_store_attr.stderr @@ -0,0 +1,9 @@ +error: use of deprecated struct `pallet::_::Store`: + Use of `#[pallet::generate_store(pub(super) trait Store)]` will be removed soon. + Check https://github.com/paritytech/substrate/pull/13535 for more details. + --> tests/pallet_ui/deprecated_store_attr.rs:7:3 + | +7 | #[pallet::generate_store(trait Store)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D deprecated` implied by `-D warnings` diff --git a/frame/support/test/tests/pallet_ui/duplicate_call_attr.rs b/frame/support/test/tests/pallet_ui/duplicate_call_attr.rs index b8a32a0bd9f69..6d781a19e6742 100644 --- a/frame/support/test/tests/pallet_ui/duplicate_call_attr.rs +++ b/frame/support/test/tests/pallet_ui/duplicate_call_attr.rs @@ -8,7 +8,6 @@ mod pallet { pub trait Config: frame_system::Config {} #[pallet::pallet] - #[pallet::generate_store(trait Store)] pub struct Pallet(core::marker::PhantomData); #[pallet::hooks] diff --git a/frame/support/test/tests/pallet_ui/duplicate_call_attr.stderr b/frame/support/test/tests/pallet_ui/duplicate_call_attr.stderr index c2956717bb2bb..2b03f41024351 100644 --- a/frame/support/test/tests/pallet_ui/duplicate_call_attr.stderr +++ b/frame/support/test/tests/pallet_ui/duplicate_call_attr.stderr @@ -1,5 +1,5 @@ error: Invalid duplicated attribute - --> $DIR/duplicate_call_attr.rs:23:12 + --> $DIR/duplicate_call_attr.rs:22:12 | -23 | #[pallet::call] +22 | #[pallet::call] | ^^^^ diff --git a/frame/support/test/tests/pallet_ui/duplicate_storage_prefix.rs b/frame/support/test/tests/pallet_ui/duplicate_storage_prefix.rs index 5e99c84050c95..543c15bd06905 100644 --- a/frame/support/test/tests/pallet_ui/duplicate_storage_prefix.rs +++ b/frame/support/test/tests/pallet_ui/duplicate_storage_prefix.rs @@ -6,7 +6,6 @@ mod pallet { pub trait Config: frame_system::Config {} #[pallet::pallet] - #[pallet::generate_store(trait Store)] pub struct Pallet(core::marker::PhantomData); #[pallet::storage] diff --git a/frame/support/test/tests/pallet_ui/duplicate_storage_prefix.stderr b/frame/support/test/tests/pallet_ui/duplicate_storage_prefix.stderr index 716888c9d8b65..75297dc5a7f79 100644 --- a/frame/support/test/tests/pallet_ui/duplicate_storage_prefix.stderr +++ b/frame/support/test/tests/pallet_ui/duplicate_storage_prefix.stderr @@ -1,47 +1,47 @@ error: Duplicate storage prefixes found for `Foo` - --> $DIR/duplicate_storage_prefix.rs:16:29 + --> $DIR/duplicate_storage_prefix.rs:15:29 | -16 | #[pallet::storage_prefix = "Foo"] +15 | #[pallet::storage_prefix = "Foo"] | ^^^^^ error: Duplicate storage prefixes found for `Foo` - --> $DIR/duplicate_storage_prefix.rs:13:7 + --> $DIR/duplicate_storage_prefix.rs:12:7 | -13 | type Foo = StorageValue<_, u8>; +12 | type Foo = StorageValue<_, u8>; | ^^^ error: Duplicate storage prefixes found for `CounterForBar`, used for counter associated to counted storage map - --> $DIR/duplicate_storage_prefix.rs:23:7 + --> $DIR/duplicate_storage_prefix.rs:22:7 | -23 | type Bar = CountedStorageMap<_, Twox64Concat, u16, u16>; +22 | type Bar = CountedStorageMap<_, Twox64Concat, u16, u16>; | ^^^ error: Duplicate storage prefixes found for `CounterForBar` - --> $DIR/duplicate_storage_prefix.rs:20:7 + --> $DIR/duplicate_storage_prefix.rs:19:7 | -20 | type CounterForBar = StorageValue<_, u16>; +19 | type CounterForBar = StorageValue<_, u16>; | ^^^^^^^^^^^^^ error[E0412]: cannot find type `_GeneratedPrefixForStorageFoo` in this scope - --> $DIR/duplicate_storage_prefix.rs:13:7 + --> $DIR/duplicate_storage_prefix.rs:12:7 | -13 | type Foo = StorageValue<_, u8>; +12 | type Foo = StorageValue<_, u8>; | ^^^ not found in this scope error[E0412]: cannot find type `_GeneratedPrefixForStorageNotFoo` in this scope - --> $DIR/duplicate_storage_prefix.rs:17:7 + --> $DIR/duplicate_storage_prefix.rs:16:7 | -17 | type NotFoo = StorageValue<_, u16>; +16 | type NotFoo = StorageValue<_, u16>; | ^^^^^^ not found in this scope error[E0412]: cannot find type `_GeneratedPrefixForStorageCounterForBar` in this scope - --> $DIR/duplicate_storage_prefix.rs:20:7 + --> $DIR/duplicate_storage_prefix.rs:19:7 | -20 | type CounterForBar = StorageValue<_, u16>; +19 | type CounterForBar = StorageValue<_, u16>; | ^^^^^^^^^^^^^ not found in this scope error[E0412]: cannot find type `_GeneratedPrefixForStorageBar` in this scope - --> $DIR/duplicate_storage_prefix.rs:23:7 + --> $DIR/duplicate_storage_prefix.rs:22:7 | -23 | type Bar = CountedStorageMap<_, Twox64Concat, u16, u16>; +22 | type Bar = CountedStorageMap<_, Twox64Concat, u16, u16>; | ^^^ not found in this scope diff --git a/frame/support/test/tests/pallet_ui/duplicate_store_attr.stderr b/frame/support/test/tests/pallet_ui/duplicate_store_attr.stderr index 232144b8deaca..1c13ee17eb751 100644 --- a/frame/support/test/tests/pallet_ui/duplicate_store_attr.stderr +++ b/frame/support/test/tests/pallet_ui/duplicate_store_attr.stderr @@ -1,5 +1,5 @@ error: Unexpected duplicated attribute - --> $DIR/duplicate_store_attr.rs:12:12 + --> tests/pallet_ui/duplicate_store_attr.rs:12:3 | 12 | #[pallet::generate_store(trait Store)] - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/frame/support/test/tests/pallet_ui/store_trait_leak_private.stderr b/frame/support/test/tests/pallet_ui/store_trait_leak_private.stderr index d8c62faa303ee..24fda4ff1abbf 100644 --- a/frame/support/test/tests/pallet_ui/store_trait_leak_private.stderr +++ b/frame/support/test/tests/pallet_ui/store_trait_leak_private.stderr @@ -1,5 +1,15 @@ +error: use of deprecated struct `pallet::_::Store`: + Use of `#[pallet::generate_store(pub(super) trait Store)]` will be removed soon. + Check https://github.com/paritytech/substrate/pull/13535 for more details. + --> tests/pallet_ui/store_trait_leak_private.rs:11:3 + | +11 | #[pallet::generate_store(pub trait Store)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D deprecated` implied by `-D warnings` + error[E0446]: private type `_GeneratedPrefixForStorageFoo` in public interface - --> $DIR/store_trait_leak_private.rs:11:37 + --> tests/pallet_ui/store_trait_leak_private.rs:11:37 | 11 | #[pallet::generate_store(pub trait Store)] | ^^^^^ can't leak private type diff --git a/frame/system/benches/bench.rs b/frame/system/benches/bench.rs index d2b579814f8a9..e2fed3e51855d 100644 --- a/frame/system/benches/bench.rs +++ b/frame/system/benches/bench.rs @@ -29,7 +29,6 @@ mod module { use frame_support::pallet_prelude::*; #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] pub struct Pallet(_); #[pallet::config] diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 0ec808d4c960f..faa1ee5d6cf4f 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -357,7 +357,6 @@ pub mod pallet { } #[pallet::pallet] - #[pallet::generate_store(pub (super) trait Store)] pub struct Pallet(_); #[pallet::hooks] diff --git a/frame/timestamp/src/lib.rs b/frame/timestamp/src/lib.rs index 93af4447d9612..192c81502bf6e 100644 --- a/frame/timestamp/src/lib.rs +++ b/frame/timestamp/src/lib.rs @@ -151,7 +151,6 @@ pub mod pallet { } #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] 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 d82906563fb8e..970e2ac152c4b 100644 --- a/frame/tips/src/lib.rs +++ b/frame/tips/src/lib.rs @@ -121,7 +121,6 @@ pub mod pallet { 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(_); diff --git a/frame/transaction-payment/asset-tx-payment/src/lib.rs b/frame/transaction-payment/asset-tx-payment/src/lib.rs index ec0bfcd4f4028..b9cd6ef995578 100644 --- a/frame/transaction-payment/asset-tx-payment/src/lib.rs +++ b/frame/transaction-payment/asset-tx-payment/src/lib.rs @@ -124,7 +124,6 @@ pub mod pallet { } #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] pub struct Pallet(_); #[pallet::event] diff --git a/frame/transaction-payment/src/lib.rs b/frame/transaction-payment/src/lib.rs index 42798c62f4012..83ff69428d144 100644 --- a/frame/transaction-payment/src/lib.rs +++ b/frame/transaction-payment/src/lib.rs @@ -295,7 +295,6 @@ pub mod pallet { use frame_system::pallet_prelude::*; #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] pub struct Pallet(_); #[pallet::config] diff --git a/frame/transaction-storage/src/lib.rs b/frame/transaction-storage/src/lib.rs index c4b1a622fc5f3..59662ee860541 100644 --- a/frame/transaction-storage/src/lib.rs +++ b/frame/transaction-storage/src/lib.rs @@ -141,7 +141,6 @@ pub mod pallet { } #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] pub struct Pallet(_); #[pallet::hooks] diff --git a/frame/treasury/src/lib.rs b/frame/treasury/src/lib.rs index 04e989373c8cd..450aee51f2ce8 100644 --- a/frame/treasury/src/lib.rs +++ b/frame/treasury/src/lib.rs @@ -140,7 +140,6 @@ pub mod pallet { use frame_system::pallet_prelude::*; #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] pub struct Pallet(PhantomData<(T, I)>); #[pallet::config] diff --git a/frame/uniques/src/lib.rs b/frame/uniques/src/lib.rs index 587f1ae4b7d84..fd94bd3a9a7e4 100644 --- a/frame/uniques/src/lib.rs +++ b/frame/uniques/src/lib.rs @@ -71,7 +71,6 @@ pub mod pallet { use frame_system::pallet_prelude::*; #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] pub struct Pallet(_); #[cfg(feature = "runtime-benchmarks")] diff --git a/frame/utility/src/lib.rs b/frame/utility/src/lib.rs index 6cfa8b7e36e9a..af212a31eb971 100644 --- a/frame/utility/src/lib.rs +++ b/frame/utility/src/lib.rs @@ -76,7 +76,6 @@ pub mod pallet { use frame_system::pallet_prelude::*; #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] pub struct Pallet(_); /// Configuration trait. diff --git a/frame/utility/src/tests.rs b/frame/utility/src/tests.rs index 413315a25eb44..d9ac2ebbc15a9 100644 --- a/frame/utility/src/tests.rs +++ b/frame/utility/src/tests.rs @@ -96,7 +96,6 @@ mod mock_democracy { use frame_system::pallet_prelude::*; #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] pub struct Pallet(_); #[pallet::config] diff --git a/frame/vesting/src/lib.rs b/frame/vesting/src/lib.rs index dbc018796a3c6..af3654924914c 100644 --- a/frame/vesting/src/lib.rs +++ b/frame/vesting/src/lib.rs @@ -211,7 +211,6 @@ pub mod pallet { pub(crate) type StorageVersion = StorageValue<_, Releases, ValueQuery>; #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] pub struct Pallet(_); #[pallet::genesis_config] diff --git a/frame/whitelist/src/lib.rs b/frame/whitelist/src/lib.rs index bfbadd073a8f8..decf010b06757 100644 --- a/frame/whitelist/src/lib.rs +++ b/frame/whitelist/src/lib.rs @@ -88,7 +88,6 @@ pub mod pallet { } #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] pub struct Pallet(_); #[pallet::event] diff --git a/test-utils/runtime/src/system.rs b/test-utils/runtime/src/system.rs index 657e3c90fa6d3..12ebf486bb1b9 100644 --- a/test-utils/runtime/src/system.rs +++ b/test-utils/runtime/src/system.rs @@ -47,7 +47,6 @@ mod pallet { use frame_support::pallet_prelude::*; #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] #[pallet::without_storage_info] pub struct Pallet(PhantomData); diff --git a/utils/frame/rpc/support/src/lib.rs b/utils/frame/rpc/support/src/lib.rs index c0ec8befc4bee..eecc80c408efd 100644 --- a/utils/frame/rpc/support/src/lib.rs +++ b/utils/frame/rpc/support/src/lib.rs @@ -94,7 +94,6 @@ use sp_storage::{StorageData, StorageKey}; /// use frame_support::pallet_prelude::*; /// /// #[pallet::pallet] -/// #[pallet::generate_store(pub(super) trait Store)] /// pub struct Pallet(PhantomData); /// /// #[pallet::config] From 30aa444d2e398c5ca798e306c9c9b04c0e1b5ea9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dino=20Pa=C4=8Dandi?= <3002868+Dinonard@users.noreply.github.com> Date: Mon, 13 Mar 2023 16:44:47 +0100 Subject: [PATCH 500/715] Pallet assets improvements (#13543) --- frame/assets/src/functions.rs | 4 +-- frame/assets/src/lib.rs | 13 +++++++--- frame/assets/src/mock.rs | 40 +++++++++++++++++++++++++++--- frame/assets/src/tests.rs | 46 +++++++++++++++++++++++++++++------ 4 files changed, 85 insertions(+), 18 deletions(-) diff --git a/frame/assets/src/functions.rs b/frame/assets/src/functions.rs index f6e027472f159..47657ff267494 100644 --- a/frame/assets/src/functions.rs +++ b/frame/assets/src/functions.rs @@ -661,8 +661,8 @@ impl, I: 'static> Pallet { status: AssetStatus::Live, }, ); + ensure!(T::CallbackHandle::created(&id, &owner).is_ok(), Error::::CallbackFailed); Self::deposit_event(Event::ForceCreated { asset_id: id, owner: owner.clone() }); - T::CallbackHandle::created(&id, &owner); Ok(()) } @@ -752,7 +752,6 @@ impl, I: 'static> Pallet { approvals_destroyed: removed_approvals as u32, approvals_remaining: details.approvals as u32, }); - T::CallbackHandle::destroyed(&id); Ok(()) })?; Ok(removed_approvals) @@ -767,6 +766,7 @@ impl, I: 'static> Pallet { ensure!(details.status == AssetStatus::Destroying, Error::::IncorrectStatus); ensure!(details.accounts == 0, Error::::InUse); ensure!(details.approvals == 0, Error::::InUse); + ensure!(T::CallbackHandle::destroyed(&id).is_ok(), Error::::CallbackFailed); let metadata = Metadata::::take(&id); T::Currency::unreserve( diff --git a/frame/assets/src/lib.rs b/frame/assets/src/lib.rs index bb0e8ce8b3704..b36a5cabd377a 100644 --- a/frame/assets/src/lib.rs +++ b/frame/assets/src/lib.rs @@ -178,10 +178,14 @@ const LOG_TARGET: &str = "runtime::assets"; /// Trait with callbacks that are executed after successfull asset creation or destruction. pub trait AssetsCallback { /// Indicates that asset with `id` was successfully created by the `owner` - fn created(_id: &AssetId, _owner: &AccountId) {} + fn created(_id: &AssetId, _owner: &AccountId) -> Result<(), ()> { + Ok(()) + } /// Indicates that asset with `id` has just been destroyed - fn destroyed(_id: &AssetId) {} + fn destroyed(_id: &AssetId) -> Result<(), ()> { + Ok(()) + } } /// Empty implementation in case no callbacks are required. @@ -560,6 +564,8 @@ pub mod pallet { IncorrectStatus, /// The asset should be frozen before the given operation. NotFrozen, + /// Callback action resulted in error + CallbackFailed, } #[pallet::call] @@ -618,13 +624,12 @@ pub mod pallet { status: AssetStatus::Live, }, ); - + ensure!(T::CallbackHandle::created(&id, &owner).is_ok(), Error::::CallbackFailed); Self::deposit_event(Event::Created { asset_id: id, creator: owner.clone(), owner: admin, }); - T::CallbackHandle::created(&id, &owner); Ok(()) } diff --git a/frame/assets/src/mock.rs b/frame/assets/src/mock.rs index 14795b10a7e15..3f456a7de3eda 100644 --- a/frame/assets/src/mock.rs +++ b/frame/assets/src/mock.rs @@ -91,12 +91,44 @@ impl pallet_balances::Config for Test { pub struct AssetsCallbackHandle; impl AssetsCallback for AssetsCallbackHandle { - fn created(_id: &AssetId, _owner: &AccountId) { - storage::set(b"asset_created", &().encode()); + fn created(_id: &AssetId, _owner: &AccountId) -> Result<(), ()> { + if Self::should_err() { + Err(()) + } else { + storage::set(Self::CREATED.as_bytes(), &().encode()); + Ok(()) + } } - fn destroyed(_id: &AssetId) { - storage::set(b"asset_destroyed", &().encode()); + fn destroyed(_id: &AssetId) -> Result<(), ()> { + if Self::should_err() { + Err(()) + } else { + storage::set(Self::DESTROYED.as_bytes(), &().encode()); + Ok(()) + } + } +} + +impl AssetsCallbackHandle { + pub const CREATED: &'static str = "asset_created"; + pub const DESTROYED: &'static str = "asset_destroyed"; + + const RETURN_ERROR: &'static str = "return_error"; + + // Configures `Self` to return `Ok` when callbacks are invoked + pub fn set_return_ok() { + storage::clear(Self::RETURN_ERROR.as_bytes()); + } + + // Configures `Self` to return `Err` when callbacks are invoked + pub fn set_return_error() { + storage::set(Self::RETURN_ERROR.as_bytes(), &().encode()); + } + + // If `true`, callback should return `Err`, `Ok` otherwise. + fn should_err() -> bool { + storage::exists(Self::RETURN_ERROR.as_bytes()) } } diff --git a/frame/assets/src/tests.rs b/frame/assets/src/tests.rs index a2788f7f4a9aa..bc61810a76ac4 100644 --- a/frame/assets/src/tests.rs +++ b/frame/assets/src/tests.rs @@ -1261,28 +1261,58 @@ fn querying_roles_should_work() { #[test] fn normal_asset_create_and_destroy_callbacks_should_work() { new_test_ext().execute_with(|| { - assert!(storage::get(b"asset_created").is_none()); - assert!(storage::get(b"asset_destroyed").is_none()); + assert!(storage::get(AssetsCallbackHandle::CREATED.as_bytes()).is_none()); + assert!(storage::get(AssetsCallbackHandle::DESTROYED.as_bytes()).is_none()); Balances::make_free_balance_be(&1, 100); assert_ok!(Assets::create(RuntimeOrigin::signed(1), 0, 1, 1)); - assert!(storage::get(b"asset_created").is_some()); - assert!(storage::get(b"asset_destroyed").is_none()); + assert!(storage::get(AssetsCallbackHandle::CREATED.as_bytes()).is_some()); + assert!(storage::get(AssetsCallbackHandle::DESTROYED.as_bytes()).is_none()); 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)); + // Callback still hasn't been invoked + assert!(storage::get(AssetsCallbackHandle::DESTROYED.as_bytes()).is_none()); + assert_ok!(Assets::finish_destroy(RuntimeOrigin::signed(1), 0)); - assert!(storage::get(b"asset_destroyed").is_some()); + assert!(storage::get(AssetsCallbackHandle::DESTROYED.as_bytes()).is_some()); }); } #[test] fn root_asset_create_should_work() { new_test_ext().execute_with(|| { - assert!(storage::get(b"asset_created").is_none()); + assert!(storage::get(AssetsCallbackHandle::CREATED.as_bytes()).is_none()); assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); - assert!(storage::get(b"asset_created").is_some()); - assert!(storage::get(b"asset_destroyed").is_none()); + assert!(storage::get(AssetsCallbackHandle::CREATED.as_bytes()).is_some()); + assert!(storage::get(AssetsCallbackHandle::DESTROYED.as_bytes()).is_none()); + }); +} + +#[test] +fn asset_create_and_destroy_is_reverted_if_callback_fails() { + new_test_ext().execute_with(|| { + // Asset creation fails due to callback failure + AssetsCallbackHandle::set_return_error(); + Balances::make_free_balance_be(&1, 100); + assert_noop!( + Assets::create(RuntimeOrigin::signed(1), 0, 1, 1), + Error::::CallbackFailed + ); + + // Callback succeeds, so asset creation succeeds + AssetsCallbackHandle::set_return_ok(); + assert_ok!(Assets::create(RuntimeOrigin::signed(1), 0, 1, 1)); + + // Asset destroy should fail due to callback failure + AssetsCallbackHandle::set_return_error(); + 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_noop!( + Assets::finish_destroy(RuntimeOrigin::signed(1), 0), + Error::::CallbackFailed + ); }); } From 959c5b636f2536b883f64e13591aa61825a558f5 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Date: Mon, 13 Mar 2023 21:02:53 +0200 Subject: [PATCH 501/715] Metadata V15: Expose pallet documentation (#13452) * frame/proc: Helpers to parse pallet documentation attributes Signed-off-by: Alexandru Vasile * frame/proc: Expand pallet with runtime metadata documentation Signed-off-by: Alexandru Vasile * frame/dispatch: Implement doc function getter for dispatch Signed-off-by: Alexandru Vasile * frame/tests: Check exposed runtime metadata documentation Signed-off-by: Alexandru Vasile * frame/tests: Add UI tests for `pallet_doc` attribute Signed-off-by: Alexandru Vasile * frame/proc: Document pallet_doc attribute Signed-off-by: Alexandru Vasile * frame/support: Use `derive_syn_parse` Signed-off-by: Alexandru Vasile * Update frame/support/procedural/src/lib.rs Co-authored-by: Niklas Adolfsson * frame/support: Improve documentation Signed-off-by: Alexandru Vasile --------- Signed-off-by: Alexandru Vasile Co-authored-by: parity-processbot <> Co-authored-by: Niklas Adolfsson --- frame/support/procedural/src/lib.rs | 51 ++++ .../src/pallet/expand/documentation.rs | 221 ++++++++++++++++++ .../procedural/src/pallet/expand/mod.rs | 4 + frame/support/src/dispatch.rs | 24 ++ frame/support/test/tests/pallet.rs | 12 + .../pallet_ui/pallet_doc_arg_non_path.rs | 16 ++ .../pallet_ui/pallet_doc_arg_non_path.stderr | 5 + .../test/tests/pallet_ui/pallet_doc_empty.rs | 16 ++ .../tests/pallet_ui/pallet_doc_empty.stderr | 5 + .../tests/pallet_ui/pallet_doc_invalid_arg.rs | 16 ++ .../pallet_ui/pallet_doc_invalid_arg.stderr | 5 + .../pallet_ui/pallet_doc_multiple_args.rs | 16 ++ .../pallet_ui/pallet_doc_multiple_args.stderr | 5 + 13 files changed, 396 insertions(+) create mode 100644 frame/support/procedural/src/pallet/expand/documentation.rs create mode 100644 frame/support/test/tests/pallet_ui/pallet_doc_arg_non_path.rs create mode 100644 frame/support/test/tests/pallet_ui/pallet_doc_arg_non_path.stderr create mode 100644 frame/support/test/tests/pallet_ui/pallet_doc_empty.rs create mode 100644 frame/support/test/tests/pallet_ui/pallet_doc_empty.stderr create mode 100644 frame/support/test/tests/pallet_ui/pallet_doc_invalid_arg.rs create mode 100644 frame/support/test/tests/pallet_ui/pallet_doc_invalid_arg.stderr create mode 100644 frame/support/test/tests/pallet_ui/pallet_doc_multiple_args.rs create mode 100644 frame/support/test/tests/pallet_ui/pallet_doc_multiple_args.stderr diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index fec824107f123..1d5dde20e2034 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -481,6 +481,57 @@ pub fn construct_runtime(input: TokenStream) -> TokenStream { /// /// /// See `frame_support::pallet` docs for more info. +/// +/// ## Runtime Metadata Documentation +/// +/// The documentation added to this pallet is included in the runtime metadata. +/// +/// The documentation can be defined in the following ways: +/// +/// ```ignore +/// #[pallet::pallet] +/// /// Documentation for pallet 1 +/// #[doc = "Documentation for pallet 2"] +/// #[doc = include_str!("../README.md")] +/// #[pallet_doc("../doc1.md")] +/// #[pallet_doc("../doc2.md")] +/// pub struct Pallet(_); +/// ``` +/// +/// The runtime metadata for this pallet contains the following +/// - " Documentation for pallet 1" (captured from `///`) +/// - "Documentation for pallet 2" (captured from `#[doc]`) +/// - content of ../README.md (captured from `#[doc]` with `include_str!`) +/// - content of "../doc1.md" (captured from `pallet_doc`) +/// - content of "../doc2.md" (captured from `pallet_doc`) +/// +/// ### `doc` attribute +/// +/// The value of the `doc` attribute is included in the runtime metadata, as well as +/// expanded on the pallet module. The previous example is expanded to: +/// +/// ```ignore +/// /// Documentation for pallet 1 +/// /// Documentation for pallet 2 +/// /// Content of README.md +/// pub struct Pallet(_); +/// ``` +/// +/// If you want to specify the file from which the documentation is loaded, you can use the +/// `include_str` macro. However, if you only want the documentation to be included in the +/// runtime metadata, use the `pallet_doc` attribute. +/// +/// ### `pallet_doc` attribute +/// +/// Unlike the `doc` attribute, the documentation provided to the `pallet_doc` attribute is +/// not inserted on the module. +/// +/// The `pallet_doc` attribute can only be provided with one argument, +/// which is the file path that holds the documentation to be added to the metadata. +/// +/// This approach is beneficial when you use the `include_str` macro at the beginning of the file +/// and want that documentation to extend to the runtime metadata, without reiterating the +/// documentation on the module itself. #[proc_macro_attribute] pub fn pallet(attr: TokenStream, item: TokenStream) -> TokenStream { pallet::pallet(attr, item) diff --git a/frame/support/procedural/src/pallet/expand/documentation.rs b/frame/support/procedural/src/pallet/expand/documentation.rs new file mode 100644 index 0000000000000..e158448a89711 --- /dev/null +++ b/frame/support/procedural/src/pallet/expand/documentation.rs @@ -0,0 +1,221 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT 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; +use derive_syn_parse::Parse; +use proc_macro2::TokenStream; +use quote::ToTokens; +use syn::{ + parse::{self, Parse, ParseStream}, + spanned::Spanned, + Attribute, Lit, +}; + +const DOC: &'static str = "doc"; +const PALLET_DOC: &'static str = "pallet_doc"; + +mod keywords { + syn::custom_keyword!(include_str); +} + +/// Get the documentation file path from the `pallet_doc` attribute. +/// +/// Supported format: +/// `#[pallet_doc(PATH)]`: The path of the file from which the documentation is loaded +fn parse_pallet_doc_value(attr: &Attribute) -> syn::Result { + let span = attr.span(); + + let meta = attr.parse_meta()?; + let syn::Meta::List(metalist) = meta else { + let msg = "The `pallet_doc` attribute must receive arguments as a list. Supported format: `pallet_doc(PATH)`"; + return Err(syn::Error::new(span, msg)) + }; + + let paths: Vec<_> = metalist + .nested + .into_iter() + .map(|nested| { + let syn::NestedMeta::Lit(lit) = nested else { + let msg = "The `pallet_doc` received an unsupported argument. Supported format: `pallet_doc(PATH)`"; + return Err(syn::Error::new(span, msg)) + }; + + Ok(lit) + }) + .collect::>()?; + + if paths.len() != 1 { + let msg = "The `pallet_doc` attribute must receive only one argument. Supported format: `pallet_doc(PATH)`"; + return Err(syn::Error::new(span, msg)) + } + + Ok(DocMetaValue::Path(paths[0].clone())) +} + +/// Get the value from the `doc` comment attribute: +/// +/// Supported formats: +/// - `#[doc = "A doc string"]`: Documentation as a string literal +/// - `#[doc = include_str!(PATH)]`: Documentation obtained from a path +fn parse_doc_value(attr: &Attribute) -> Option { + let Some(ident) = attr.path.get_ident() else { + return None + }; + if ident != DOC { + return None + } + + let parser = |input: ParseStream| DocParser::parse(input); + let result = parse::Parser::parse2(parser, attr.tokens.clone()).ok()?; + + if let Some(lit) = result.lit { + Some(DocMetaValue::Lit(lit)) + } else if let Some(include_doc) = result.include_doc { + Some(DocMetaValue::Path(include_doc.lit)) + } else { + None + } +} + +/// Parse the include_str attribute. +#[derive(Debug, Parse)] +struct IncludeDocParser { + _include_str: keywords::include_str, + _eq_token: syn::token::Bang, + #[paren] + _paren: syn::token::Paren, + #[inside(_paren)] + lit: Lit, +} + +/// Parse the doc literal. +#[derive(Debug, Parse)] +struct DocParser { + _eq_token: syn::token::Eq, + #[peek(Lit)] + lit: Option, + #[parse_if(lit.is_none())] + include_doc: Option, +} + +/// Supported documentation tokens. +#[derive(Debug)] +enum DocMetaValue { + /// Documentation with string literals. + /// + /// `#[doc = "Lit"]` + Lit(Lit), + /// Documentation with `include_str!` macro. + /// + /// The string literal represents the file `PATH`. + /// + /// `#[doc = include_str!(PATH)]` + Path(Lit), +} + +impl ToTokens for DocMetaValue { + fn to_tokens(&self, tokens: &mut TokenStream) { + match self { + DocMetaValue::Lit(lit) => lit.to_tokens(tokens), + DocMetaValue::Path(path_lit) => { + let decl = quote::quote!(include_str!(#path_lit)); + tokens.extend(decl) + }, + } + } +} + +/// Extract the documentation from the given pallet definition +/// to include in the runtime metadata. +/// +/// Implement a `pallet_documentation_metadata` function to fetch the +/// documentation that is included in the metadata. +/// +/// The documentation is placed at the top of the module similar to: +/// +/// ```ignore +/// #[pallet] +/// /// Documentation for pallet +/// #[doc = "Documentation for pallet"] +/// #[doc = include_str!("../README.md")] +/// #[pallet_doc("../documentation1.md")] +/// #[pallet_doc("../documentation2.md")] +/// pub mod pallet {} +/// ``` +/// +/// # pallet_doc +/// +/// The `pallet_doc` attribute can only be provided with one argument, +/// which is the file path that holds the documentation to be added to the metadata. +/// +/// Unlike the `doc` attribute, the documentation provided to the `proc_macro` attribute is +/// not inserted at the beginning of the module. +pub fn expand_documentation(def: &mut Def) -> proc_macro2::TokenStream { + let frame_support = &def.frame_support; + 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 where_clauses = &def.config.where_clause; + + // TODO: Use [drain_filter](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.drain_filter) when it is stable. + + // The `pallet_doc` attributes are excluded from the generation of the pallet, + // but they are included in the runtime metadata. + let mut pallet_docs = Vec::with_capacity(def.item.attrs.len()); + let mut index = 0; + while index < def.item.attrs.len() { + let attr = &def.item.attrs[index]; + if let Some(ident) = attr.path.get_ident() { + if ident == PALLET_DOC { + let elem = def.item.attrs.remove(index); + pallet_docs.push(elem); + // Do not increment the index, we have just removed the + // element from the attributes. + continue + } + } + + index += 1; + } + + // Capture the `#[doc = include_str!("../README.md")]` and `#[doc = "Documentation"]`. + let mut docs: Vec<_> = def.item.attrs.iter().filter_map(parse_doc_value).collect(); + + // Capture the `#[pallet_doc("../README.md")]`. + let pallet_docs: Vec<_> = match pallet_docs + .into_iter() + .map(|attr| parse_pallet_doc_value(&attr)) + .collect::>() + { + Ok(docs) => docs, + Err(err) => return err.into_compile_error(), + }; + + docs.extend(pallet_docs); + + quote::quote!( + impl<#type_impl_gen> #pallet_ident<#type_use_gen> #where_clauses{ + + #[doc(hidden)] + pub fn pallet_documentation_metadata() + -> #frame_support::sp_std::vec::Vec<&'static str> + { + #frame_support::sp_std::vec![ #( #docs ),* ] + } + } + ) +} diff --git a/frame/support/procedural/src/pallet/expand/mod.rs b/frame/support/procedural/src/pallet/expand/mod.rs index 3ccbf91b4f130..09a25a7101ee7 100644 --- a/frame/support/procedural/src/pallet/expand/mod.rs +++ b/frame/support/procedural/src/pallet/expand/mod.rs @@ -18,6 +18,7 @@ mod call; mod config; mod constants; +mod documentation; mod error; mod event; mod genesis_build; @@ -52,6 +53,8 @@ pub fn merge_where_clauses(clauses: &[&Option]) -> Option proc_macro2::TokenStream { + // Remove the `pallet_doc` attribute first. + let metadata_docs = documentation::expand_documentation(&mut def); let constants = constants::expand_constants(&mut def); let pallet_struct = pallet_struct::expand_pallet_struct(&mut def); let config = config::expand_config(&mut def); @@ -82,6 +85,7 @@ pub fn expand(mut def: Def) -> proc_macro2::TokenStream { } let new_items = quote::quote!( + #metadata_docs #constants #pallet_struct #config diff --git a/frame/support/src/dispatch.rs b/frame/support/src/dispatch.rs index e2798763df437..c5f4cc60c1f1b 100644 --- a/frame/support/src/dispatch.rs +++ b/frame/support/src/dispatch.rs @@ -2948,6 +2948,10 @@ macro_rules! decl_module { { $( $other_where_bounds )* } $( $error_type )* } + $crate::__impl_docs_metadata! { + $mod_type<$trait_instance: $trait_name $(, $instance: $instantiable)?> + { $( $other_where_bounds )* } + } $crate::__impl_module_constants_metadata ! { $mod_type<$trait_instance: $trait_name $(, $instance: $instantiable)?> { $( $other_where_bounds )* } @@ -3018,6 +3022,26 @@ macro_rules! __impl_error_metadata { }; } +/// Implement metadata for pallet documentation. +#[macro_export] +#[doc(hidden)] +macro_rules! __impl_docs_metadata { + ( + $mod_type:ident<$trait_instance:ident: $trait_name:ident$(, $instance:ident: $instantiable:path)?> + { $( $other_where_bounds:tt )* } + ) => { + impl<$trait_instance: $trait_name $(, $instance: $instantiable)?> $mod_type<$trait_instance $(, $instance)?> + where $( $other_where_bounds )* + { + #[doc(hidden)] + #[allow(dead_code)] + pub fn pallet_documentation_metadata() -> $crate::sp_std::vec::Vec<&'static str> { + $crate::sp_std::vec![] + } + } + }; +} + /// Implement metadata for module constants. #[macro_export] #[doc(hidden)] diff --git a/frame/support/test/tests/pallet.rs b/frame/support/test/tests/pallet.rs index 8e77cd0251184..fbebbef455f7b 100644 --- a/frame/support/test/tests/pallet.rs +++ b/frame/support/test/tests/pallet.rs @@ -101,6 +101,10 @@ impl SomeAssociation2 for u64 { } #[frame_support::pallet] +/// Pallet documentation +// Comments should not be included in the pallet documentation +#[pallet_doc("../../README.md")] +#[doc = include_str!("../../README.md")] pub mod pallet { use super::*; use frame_support::pallet_prelude::*; @@ -1589,6 +1593,14 @@ fn metadata() { pretty_assertions::assert_eq!(actual_metadata.pallets, expected_metadata.pallets); } +#[test] +fn test_pallet_runtime_docs() { + let docs = crate::pallet::Pallet::::pallet_documentation_metadata(); + let readme = "Support code for the runtime.\n\nLicense: Apache-2.0"; + let expected = vec![" Pallet documentation", readme, readme]; + assert_eq!(docs, expected); +} + #[test] fn test_pallet_info_access() { assert_eq!(::name(), "System"); diff --git a/frame/support/test/tests/pallet_ui/pallet_doc_arg_non_path.rs b/frame/support/test/tests/pallet_ui/pallet_doc_arg_non_path.rs new file mode 100644 index 0000000000000..ef3097d23007d --- /dev/null +++ b/frame/support/test/tests/pallet_ui/pallet_doc_arg_non_path.rs @@ -0,0 +1,16 @@ +#[frame_support::pallet] +// Must receive a string literal pointing to a path +#[pallet_doc(X)] +mod pallet { + #[pallet::config] + pub trait Config: frame_system::Config + where + ::Index: From, + { + } + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); +} + +fn main() {} diff --git a/frame/support/test/tests/pallet_ui/pallet_doc_arg_non_path.stderr b/frame/support/test/tests/pallet_ui/pallet_doc_arg_non_path.stderr new file mode 100644 index 0000000000000..ba60479c07202 --- /dev/null +++ b/frame/support/test/tests/pallet_ui/pallet_doc_arg_non_path.stderr @@ -0,0 +1,5 @@ +error: The `pallet_doc` received an unsupported argument. Supported format: `pallet_doc(PATH)` + --> tests/pallet_ui/pallet_doc_arg_non_path.rs:3:1 + | +3 | #[pallet_doc(X)] + | ^ diff --git a/frame/support/test/tests/pallet_ui/pallet_doc_empty.rs b/frame/support/test/tests/pallet_ui/pallet_doc_empty.rs new file mode 100644 index 0000000000000..fe40806d2fa75 --- /dev/null +++ b/frame/support/test/tests/pallet_ui/pallet_doc_empty.rs @@ -0,0 +1,16 @@ +#[frame_support::pallet] +// Expected one argument for the doc path. +#[pallet_doc] +mod pallet { + #[pallet::config] + pub trait Config: frame_system::Config + where + ::Index: From, + { + } + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); +} + +fn main() {} diff --git a/frame/support/test/tests/pallet_ui/pallet_doc_empty.stderr b/frame/support/test/tests/pallet_ui/pallet_doc_empty.stderr new file mode 100644 index 0000000000000..d6a189d7918f5 --- /dev/null +++ b/frame/support/test/tests/pallet_ui/pallet_doc_empty.stderr @@ -0,0 +1,5 @@ +error: The `pallet_doc` attribute must receive arguments as a list. Supported format: `pallet_doc(PATH)` + --> tests/pallet_ui/pallet_doc_empty.rs:3:1 + | +3 | #[pallet_doc] + | ^ diff --git a/frame/support/test/tests/pallet_ui/pallet_doc_invalid_arg.rs b/frame/support/test/tests/pallet_ui/pallet_doc_invalid_arg.rs new file mode 100644 index 0000000000000..8f0ccb3777a49 --- /dev/null +++ b/frame/support/test/tests/pallet_ui/pallet_doc_invalid_arg.rs @@ -0,0 +1,16 @@ +#[frame_support::pallet] +// Argument expected as list, not named value. +#[pallet_doc = "invalid"] +mod pallet { + #[pallet::config] + pub trait Config: frame_system::Config + where + ::Index: From, + { + } + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); +} + +fn main() {} diff --git a/frame/support/test/tests/pallet_ui/pallet_doc_invalid_arg.stderr b/frame/support/test/tests/pallet_ui/pallet_doc_invalid_arg.stderr new file mode 100644 index 0000000000000..9dd03978934a4 --- /dev/null +++ b/frame/support/test/tests/pallet_ui/pallet_doc_invalid_arg.stderr @@ -0,0 +1,5 @@ +error: The `pallet_doc` attribute must receive arguments as a list. Supported format: `pallet_doc(PATH)` + --> tests/pallet_ui/pallet_doc_invalid_arg.rs:3:1 + | +3 | #[pallet_doc = "invalid"] + | ^ diff --git a/frame/support/test/tests/pallet_ui/pallet_doc_multiple_args.rs b/frame/support/test/tests/pallet_ui/pallet_doc_multiple_args.rs new file mode 100644 index 0000000000000..ffbed9d950799 --- /dev/null +++ b/frame/support/test/tests/pallet_ui/pallet_doc_multiple_args.rs @@ -0,0 +1,16 @@ +#[frame_support::pallet] +// Supports only one argument. +#[pallet_doc("A", "B")] +mod pallet { + #[pallet::config] + pub trait Config: frame_system::Config + where + ::Index: From, + { + } + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); +} + +fn main() {} diff --git a/frame/support/test/tests/pallet_ui/pallet_doc_multiple_args.stderr b/frame/support/test/tests/pallet_ui/pallet_doc_multiple_args.stderr new file mode 100644 index 0000000000000..58ad75a0a2aec --- /dev/null +++ b/frame/support/test/tests/pallet_ui/pallet_doc_multiple_args.stderr @@ -0,0 +1,5 @@ +error: The `pallet_doc` attribute must receive only one argument. Supported format: `pallet_doc(PATH)` + --> tests/pallet_ui/pallet_doc_multiple_args.rs:3:1 + | +3 | #[pallet_doc("A", "B")] + | ^ From 3a94009daac8919db46e3014964fe23866edb996 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Mon, 13 Mar 2023 22:46:53 +0100 Subject: [PATCH 502/715] sc-slots: Cleanup (#13590) Calculate remaining proposal duration once and also use proposal time as timeout for creating the inherent data. --- client/consensus/slots/src/lib.rs | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/client/consensus/slots/src/lib.rs b/client/consensus/slots/src/lib.rs index c18284de6a088..f1d817ab7d8cf 100644 --- a/client/consensus/slots/src/lib.rs +++ b/client/consensus/slots/src/lib.rs @@ -190,7 +190,7 @@ pub trait SimpleSlotWorker { proposer: Self::Proposer, claim: &Self::Claim, slot_info: SlotInfo, - proposing_remaining: Delay, + end_proposing_at: Instant, ) -> Option< Proposal< B, @@ -202,9 +202,11 @@ pub trait SimpleSlotWorker { let telemetry = self.telemetry(); let log_target = self.logging_target(); - let inherent_data = Self::create_inherent_data(&slot_info, &log_target).await?; + let inherent_data = + Self::create_inherent_data(&slot_info, &log_target, end_proposing_at).await?; - let proposing_remaining_duration = self.proposing_remaining_duration(&slot_info); + let proposing_remaining_duration = + end_proposing_at.saturating_duration_since(Instant::now()); let logs = self.pre_digest_data(slot, claim); // deadline our production to 98% of the total time left for proposing. As we deadline @@ -219,7 +221,12 @@ pub trait SimpleSlotWorker { ) .map_err(|e| sp_consensus::Error::ClientImport(e.to_string())); - let proposal = match futures::future::select(proposing, proposing_remaining).await { + let proposal = match futures::future::select( + proposing, + Delay::new(proposing_remaining_duration), + ) + .await + { Either::Left((Ok(p), _)) => p, Either::Left((Err(err), _)) => { warn!(target: log_target, "Proposing failed: {}", err); @@ -255,8 +262,9 @@ pub trait SimpleSlotWorker { async fn create_inherent_data( slot_info: &SlotInfo, logging_target: &str, + end_proposing_at: Instant, ) -> Option { - let remaining_duration = slot_info.ends_at.saturating_duration_since(Instant::now()); + let remaining_duration = end_proposing_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 { @@ -300,7 +308,7 @@ pub trait SimpleSlotWorker { let proposing_remaining_duration = self.proposing_remaining_duration(&slot_info); - let proposing_remaining = if proposing_remaining_duration == Duration::default() { + let end_proposing_at = if proposing_remaining_duration == Duration::default() { debug!( target: logging_target, "Skipping proposal slot {} since there's no time left to propose", slot, @@ -308,7 +316,7 @@ pub trait SimpleSlotWorker { return None } else { - Delay::new(proposing_remaining_duration) + Instant::now() + proposing_remaining_duration }; let aux_data = match self.aux_data(&slot_info.chain_head, slot) { @@ -379,7 +387,7 @@ pub trait SimpleSlotWorker { }, }; - let proposal = self.propose(proposer, &claim, slot_info, proposing_remaining).await?; + let proposal = self.propose(proposer, &claim, slot_info, end_proposing_at).await?; let (block, storage_proof) = (proposal.block, proposal.proof); let (header, body) = block.deconstruct(); From 4f28d2923a825dafc8431825270e78c5ab218ce0 Mon Sep 17 00:00:00 2001 From: Jegor Sidorenko <5252494+jsidorenko@users.noreply.github.com> Date: Tue, 14 Mar 2023 09:55:18 +0200 Subject: [PATCH 503/715] [NFTs] Allow to set the role to None (#13591) * Allow to unset the role * Chore * Array instead of vec --------- Co-authored-by: parity-processbot <> --- frame/nfts/src/benchmarking.rs | 12 +-- frame/nfts/src/features/create_delete_item.rs | 46 +++++----- frame/nfts/src/features/roles.rs | 38 ++++++-- frame/nfts/src/lib.rs | 21 +++-- frame/nfts/src/tests.rs | 88 +++++++++++++++---- 5 files changed, 143 insertions(+), 62 deletions(-) diff --git a/frame/nfts/src/benchmarking.rs b/frame/nfts/src/benchmarking.rs index d4bbd809ce8be..68252ebfc9cac 100644 --- a/frame/nfts/src/benchmarking.rs +++ b/frame/nfts/src/benchmarking.rs @@ -383,16 +383,16 @@ benchmarks_instance_pallet! { set_team { 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)); + let target0 = Some(T::Lookup::unlookup(account("target", 0, SEED))); + let target1 = Some(T::Lookup::unlookup(account("target", 1, SEED))); + let target2 = Some(T::Lookup::unlookup(account("target", 2, SEED))); }: _(SystemOrigin::Signed(caller), collection, target0, target1, target2) verify { assert_last_event::(Event::TeamChanged{ collection, - issuer: account("target", 0, SEED), - admin: account("target", 1, SEED), - freezer: account("target", 2, SEED), + issuer: Some(account("target", 0, SEED)), + admin: Some(account("target", 1, SEED)), + freezer: Some(account("target", 2, SEED)), }.into()); } diff --git a/frame/nfts/src/features/create_delete_item.rs b/frame/nfts/src/features/create_delete_item.rs index cd96d28448055..2aa27dc066619 100644 --- a/frame/nfts/src/features/create_delete_item.rs +++ b/frame/nfts/src/features/create_delete_item.rs @@ -106,9 +106,6 @@ impl, I: 'static> Pallet { let now = frame_system::Pallet::::block_number(); ensure!(deadline >= now, Error::::DeadlineExpired); - let collection_details = - Collection::::get(&collection).ok_or(Error::::UnknownCollection)?; - ensure!( Self::has_role(&collection, &signer, CollectionRole::Issuer), Error::::NoPermission @@ -123,27 +120,28 @@ impl, I: 'static> Pallet { item_config, |_, _| Ok(()), )?; - let origin = Self::find_account_by_role(&collection, CollectionRole::Admin) - .unwrap_or(collection_details.owner.clone()); - for (key, value) in attributes { - Self::do_set_attribute( - origin.clone(), - collection, - Some(item), - AttributeNamespace::CollectionOwner, - Self::construct_attribute_key(key)?, - Self::construct_attribute_value(value)?, - mint_to.clone(), - )?; - } - if !metadata.len().is_zero() { - Self::do_set_item_metadata( - Some(origin.clone()), - collection, - item, - metadata, - Some(mint_to.clone()), - )?; + let admin_account = Self::find_account_by_role(&collection, CollectionRole::Admin); + if let Some(admin_account) = admin_account { + for (key, value) in attributes { + Self::do_set_attribute( + admin_account.clone(), + collection, + Some(item), + AttributeNamespace::CollectionOwner, + Self::construct_attribute_key(key)?, + Self::construct_attribute_value(value)?, + mint_to.clone(), + )?; + } + if !metadata.len().is_zero() { + Self::do_set_item_metadata( + Some(admin_account.clone()), + collection, + item, + metadata, + Some(mint_to.clone()), + )?; + } } Ok(()) } diff --git a/frame/nfts/src/features/roles.rs b/frame/nfts/src/features/roles.rs index f91f3ecb6f348..3bac002069cf3 100644 --- a/frame/nfts/src/features/roles.rs +++ b/frame/nfts/src/features/roles.rs @@ -23,24 +23,46 @@ impl, I: 'static> Pallet { pub(crate) fn do_set_team( maybe_check_owner: Option, collection: T::CollectionId, - issuer: T::AccountId, - admin: T::AccountId, - freezer: T::AccountId, + issuer: Option, + admin: Option, + freezer: Option, ) -> DispatchResult { Collection::::try_mutate(collection, |maybe_details| { let details = maybe_details.as_mut().ok_or(Error::::UnknownCollection)?; + let is_root = maybe_check_owner.is_none(); if let Some(check_origin) = maybe_check_owner { ensure!(check_origin == details.owner, Error::::NoPermission); } - // delete previous values - Self::clear_roles(&collection)?; - - let account_to_role = Self::group_roles_by_account(vec![ + let roles_map = [ (issuer.clone(), CollectionRole::Issuer), (admin.clone(), CollectionRole::Admin), (freezer.clone(), CollectionRole::Freezer), - ]); + ]; + + // only root can change the role from `None` to `Some(account)` + if !is_root { + for (account, role) in roles_map.iter() { + if account.is_some() { + ensure!( + Self::find_account_by_role(&collection, *role).is_some(), + Error::::NoPermission + ); + } + } + } + + let roles = roles_map + .into_iter() + .filter_map(|(account, role)| account.map(|account| (account, role))) + .collect(); + + let account_to_role = Self::group_roles_by_account(roles); + + // delete the previous records + Self::clear_roles(&collection)?; + + // insert new records for (account, roles) in account_to_role { CollectionRoleOf::::insert(&collection, &account, roles); } diff --git a/frame/nfts/src/lib.rs b/frame/nfts/src/lib.rs index 254fa75964ab8..f4d0e41593476 100644 --- a/frame/nfts/src/lib.rs +++ b/frame/nfts/src/lib.rs @@ -403,9 +403,9 @@ pub mod pallet { /// The management team changed. TeamChanged { collection: T::CollectionId, - issuer: T::AccountId, - admin: T::AccountId, - freezer: T::AccountId, + issuer: Option, + admin: Option, + freezer: Option, }, /// An `item` of a `collection` has been approved by the `owner` for transfer by /// a `delegate`. @@ -1136,6 +1136,9 @@ pub mod pallet { /// Origin must be either `ForceOrigin` or Signed and the sender should be the Owner of the /// `collection`. /// + /// Note: by setting the role to `None` only the `ForceOrigin` will be able to change it + /// after to `Some(account)`. + /// /// - `collection`: The collection whose team should be changed. /// - `issuer`: The new Issuer of this collection. /// - `admin`: The new Admin of this collection. @@ -1149,16 +1152,16 @@ pub mod pallet { pub fn set_team( origin: OriginFor, collection: T::CollectionId, - issuer: AccountIdLookupOf, - admin: AccountIdLookupOf, - freezer: AccountIdLookupOf, + issuer: Option>, + admin: Option>, + freezer: Option>, ) -> DispatchResult { let maybe_check_owner = T::ForceOrigin::try_origin(origin) .map(|_| None) .or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?; - let issuer = T::Lookup::lookup(issuer)?; - let admin = T::Lookup::lookup(admin)?; - let freezer = T::Lookup::lookup(freezer)?; + let issuer = issuer.map(T::Lookup::lookup).transpose()?; + let admin = admin.map(T::Lookup::lookup).transpose()?; + let freezer = freezer.map(T::Lookup::lookup).transpose()?; Self::do_set_team(maybe_check_owner, collection, issuer, admin, freezer) } diff --git a/frame/nfts/src/tests.rs b/frame/nfts/src/tests.rs index 694468aceebe5..0fc6fcd15c45f 100644 --- a/frame/nfts/src/tests.rs +++ b/frame/nfts/src/tests.rs @@ -535,9 +535,9 @@ fn origin_guards_should_work() { Nfts::set_team( RuntimeOrigin::signed(account(2)), 0, - account(2), - account(2), - account(2), + Some(account(2)), + Some(account(2)), + Some(account(2)), ), Error::::NoPermission ); @@ -639,14 +639,14 @@ fn set_team_should_work() { assert_ok!(Nfts::set_team( RuntimeOrigin::signed(account(1)), 0, - account(2), - account(3), - account(4), + Some(account(2)), + Some(account(3)), + Some(account(4)), )); assert_ok!(Nfts::mint(RuntimeOrigin::signed(account(2)), 0, 42, account(2), None)); - assert_ok!(Nfts::lock_item_transfer(RuntimeOrigin::signed(account(4)), 0, 42)); - assert_ok!(Nfts::unlock_item_transfer(RuntimeOrigin::signed(account(4)), 0, 42)); + + // admin can't transfer/burn items he doesn't own assert_noop!( Nfts::transfer(RuntimeOrigin::signed(account(3)), 0, 42, account(3)), Error::::NoPermission @@ -655,6 +655,46 @@ fn set_team_should_work() { Nfts::burn(RuntimeOrigin::signed(account(3)), 0, 42), Error::::NoPermission ); + + assert_ok!(Nfts::lock_item_transfer(RuntimeOrigin::signed(account(4)), 0, 42)); + assert_ok!(Nfts::unlock_item_transfer(RuntimeOrigin::signed(account(4)), 0, 42)); + + // validate we can set any role to None + assert_ok!(Nfts::set_team( + RuntimeOrigin::signed(account(1)), + 0, + Some(account(2)), + Some(account(3)), + None, + )); + assert_noop!( + Nfts::lock_item_transfer(RuntimeOrigin::signed(account(4)), 0, 42), + Error::::NoPermission + ); + + // set all the roles to None + assert_ok!(Nfts::set_team(RuntimeOrigin::signed(account(1)), 0, None, None, None,)); + + // validate we can't set the roles back + assert_noop!( + Nfts::set_team( + RuntimeOrigin::signed(account(1)), + 0, + Some(account(2)), + Some(account(3)), + None, + ), + Error::::NoPermission + ); + + // only the root account can change the roles from None to Some() + assert_ok!(Nfts::set_team( + RuntimeOrigin::root(), + 0, + Some(account(2)), + Some(account(3)), + None, + )); }); } @@ -1476,7 +1516,13 @@ fn force_update_collection_should_work() { Balances::make_free_balance_be(&account(5), 100); assert_ok!(Nfts::force_collection_owner(RuntimeOrigin::root(), 0, account(5))); - assert_ok!(Nfts::set_team(RuntimeOrigin::root(), 0, account(2), account(5), account(4))); + assert_ok!(Nfts::set_team( + RuntimeOrigin::root(), + 0, + Some(account(2)), + Some(account(5)), + Some(account(4)), + )); assert_eq!(collections(), vec![(account(5), 0)]); assert_eq!(Balances::reserved_balance(account(1)), 2); assert_eq!(Balances::reserved_balance(account(5)), 63); @@ -1502,7 +1548,13 @@ fn force_update_collection_should_work() { assert_eq!(Balances::reserved_balance(account(5)), 0); // validate new roles - assert_ok!(Nfts::set_team(RuntimeOrigin::root(), 0, account(2), account(3), account(4))); + assert_ok!(Nfts::set_team( + RuntimeOrigin::root(), + 0, + Some(account(2)), + Some(account(3)), + Some(account(4)), + )); assert_eq!( CollectionRoleOf::::get(0, account(2)).unwrap(), CollectionRoles(CollectionRole::Issuer.into()) @@ -1516,7 +1568,13 @@ fn force_update_collection_should_work() { CollectionRoles(CollectionRole::Freezer.into()) ); - assert_ok!(Nfts::set_team(RuntimeOrigin::root(), 0, account(3), account(2), account(3))); + assert_ok!(Nfts::set_team( + RuntimeOrigin::root(), + 0, + Some(account(3)), + Some(account(2)), + Some(account(3)), + )); assert_eq!( CollectionRoleOf::::get(0, account(2)).unwrap(), @@ -1541,9 +1599,9 @@ fn burn_works() { assert_ok!(Nfts::set_team( RuntimeOrigin::signed(account(1)), 0, - account(2), - account(3), - account(4), + Some(account(2)), + Some(account(3)), + Some(account(4)), )); assert_noop!( @@ -3220,7 +3278,7 @@ fn pre_signed_mints_should_work() { signature, user_1.clone(), ), - Error::::UnknownCollection + Error::::NoPermission ); // validate max attributes limit From 897b95d98424a44eb493eb982e5ac88d37f60cb5 Mon Sep 17 00:00:00 2001 From: Aaro Altonen <48052676+altonen@users.noreply.github.com> Date: Tue, 14 Mar 2023 14:06:40 +0200 Subject: [PATCH 504/715] Move code from `sc-network-common` back to `sc-network` (#13592) * Move service tests to `client/network/tests` These tests depend on `sc-network` and `sc-network-sync` so they should live outside the crate. * Move some configs from `sc-network-common` to `sc-network` * Move `NetworkService` traits to `sc-network` * Move request-responses to `sc-network` * Remove more stuff * Remove rest of configs from `sc-network-common` to `sc-network` * Remove more stuff * Fix warnings * Update client/network/src/request_responses.rs Co-authored-by: Dmitry Markin * Fix cargo doc --------- Co-authored-by: Dmitry Markin --- Cargo.lock | 12 +- bin/node/cli/src/service.rs | 6 +- client/authority-discovery/Cargo.toml | 1 + client/authority-discovery/src/lib.rs | 2 +- client/authority-discovery/src/worker.rs | 5 +- .../authority-discovery/src/worker/tests.rs | 9 +- client/chain-spec/Cargo.toml | 2 +- client/chain-spec/src/chain_spec.rs | 2 +- client/chain-spec/src/lib.rs | 2 +- client/cli/src/arg_enums.rs | 20 +- client/cli/src/params/network_params.rs | 8 +- client/cli/src/params/node_key_params.rs | 14 +- .../consensus/beefy/src/communication/mod.rs | 5 +- .../incoming_requests_handler.rs | 6 +- .../outgoing_requests_engine.rs | 5 +- client/consensus/beefy/src/lib.rs | 3 +- .../grandpa/src/communication/gossip.rs | 7 +- .../grandpa/src/communication/mod.rs | 9 +- .../grandpa/src/communication/tests.rs | 16 +- client/consensus/grandpa/src/lib.rs | 10 +- client/informant/Cargo.toml | 1 + client/informant/src/display.rs | 10 +- client/informant/src/lib.rs | 3 +- client/network-gossip/Cargo.toml | 1 + client/network-gossip/src/bridge.rs | 18 +- client/network-gossip/src/lib.rs | 7 +- client/network-gossip/src/state_machine.rs | 14 +- client/network-gossip/src/validator.rs | 2 +- client/network/Cargo.toml | 1 + client/network/bitswap/Cargo.toml | 1 + client/network/bitswap/src/lib.rs | 9 +- client/network/common/Cargo.toml | 1 - client/network/common/src/config.rs | 702 ----------------- client/network/common/src/lib.rs | 7 +- .../network/common/src/request_responses.rs | 155 ---- .../network/common/src/{protocol => }/role.rs | 0 client/network/common/src/sync.rs | 2 +- client/network/common/src/sync/message.rs | 2 +- client/network/light/Cargo.toml | 1 + .../light/src/light_client_requests.rs | 8 +- .../src/light_client_requests/handler.rs | 2 +- client/network/src/behaviour.rs | 13 +- client/network/src/config.rs | 708 +++++++++++++++++- client/network/src/discovery.rs | 5 +- client/network/{common => }/src/error.rs | 3 +- .../{common/src/protocol => src}/event.rs | 6 +- client/network/src/lib.rs | 32 +- client/network/src/peer_info.rs | 4 +- client/network/src/protocol.rs | 26 +- client/network/src/protocol/message.rs | 2 +- .../src/protocol/notifications/behaviour.rs | 8 +- .../src/protocol/notifications/handler.rs | 15 +- .../protocol/notifications/upgrade/collec.rs | 2 +- .../notifications/upgrade/notifications.rs | 8 +- client/network/src/request_responses.rs | 160 +++- client/network/src/service.rs | 54 +- client/network/src/service/out_events.rs | 3 +- .../{common => }/src/service/signature.rs | 4 +- client/network/src/service/tests/mod.rs | 240 ------ .../src/service.rs => src/service/traits.rs} | 11 +- .../{common/src/protocol.rs => src/types.rs} | 9 +- client/network/{common => }/src/utils.rs | 3 + client/network/sync/Cargo.toml | 1 + .../network/sync/src/block_request_handler.rs | 7 +- client/network/sync/src/engine.rs | 14 +- client/network/sync/src/lib.rs | 44 +- client/network/sync/src/service/chain_sync.rs | 6 +- client/network/sync/src/service/mock.rs | 14 +- client/network/sync/src/service/network.rs | 8 +- .../network/sync/src/state_request_handler.rs | 5 +- .../network/sync/src/warp_request_handler.rs | 6 +- client/network/test/src/lib.rs | 16 +- .../service/tests => test/src}/service.rs | 245 +++++- client/network/transactions/Cargo.toml | 1 + client/network/transactions/src/lib.rs | 15 +- client/offchain/Cargo.toml | 1 + client/offchain/src/api.rs | 6 +- client/offchain/src/lib.rs | 4 +- client/rpc/src/system/tests.rs | 2 +- client/service/src/builder.rs | 11 +- client/service/src/config.rs | 10 +- client/service/src/error.rs | 2 +- client/service/src/lib.rs | 6 +- client/service/src/metrics.rs | 7 +- client/service/test/src/lib.rs | 7 +- 85 files changed, 1411 insertions(+), 1434 deletions(-) delete mode 100644 client/network/common/src/config.rs delete mode 100644 client/network/common/src/request_responses.rs rename client/network/common/src/{protocol => }/role.rs (100%) rename client/network/{common => }/src/error.rs (97%) rename client/network/{common/src/protocol => src}/event.rs (97%) rename client/network/{common => }/src/service/signature.rs (96%) delete mode 100644 client/network/src/service/tests/mod.rs rename client/network/{common/src/service.rs => src/service/traits.rs} (99%) rename client/network/{common/src/protocol.rs => src/types.rs} (99%) rename client/network/{common => }/src/utils.rs (98%) rename client/network/{src/service/tests => test/src}/service.rs (72%) diff --git a/Cargo.lock b/Cargo.lock index 9a63e25b4878c..4aac7f3c7ed99 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8101,6 +8101,7 @@ dependencies = [ "quickcheck", "rand 0.8.5", "sc-client-api", + "sc-network", "sc-network-common", "sp-api", "sp-authority-discovery", @@ -8163,7 +8164,7 @@ dependencies = [ "sc-chain-spec-derive", "sc-client-api", "sc-executor", - "sc-network-common", + "sc-network", "sc-telemetry", "serde", "serde_json", @@ -8751,6 +8752,7 @@ dependencies = [ "futures-timer", "log", "sc-client-api", + "sc-network", "sc-network-common", "sp-blockchain", "sp-runtime", @@ -8787,6 +8789,7 @@ dependencies = [ "futures-timer", "ip_network", "libp2p", + "linked_hash_set", "log", "lru", "mockall", @@ -8838,6 +8841,7 @@ dependencies = [ "sc-block-builder", "sc-client-api", "sc-consensus", + "sc-network", "sc-network-common", "sp-blockchain", "sp-consensus", @@ -8861,7 +8865,6 @@ dependencies = [ "futures", "futures-timer", "libp2p", - "linked_hash_set", "parity-scale-codec", "prost-build", "sc-consensus", @@ -8890,6 +8893,7 @@ dependencies = [ "log", "lru", "quickcheck", + "sc-network", "sc-network-common", "sc-peerset", "sp-runtime", @@ -8911,6 +8915,7 @@ dependencies = [ "prost", "prost-build", "sc-client-api", + "sc-network", "sc-network-common", "sc-peerset", "sp-blockchain", @@ -8939,6 +8944,7 @@ dependencies = [ "sc-block-builder", "sc-client-api", "sc-consensus", + "sc-network", "sc-network-common", "sc-peerset", "sc-utils", @@ -8997,6 +9003,7 @@ dependencies = [ "log", "parity-scale-codec", "pin-project", + "sc-network", "sc-network-common", "sc-peerset", "sc-utils", @@ -9026,6 +9033,7 @@ dependencies = [ "sc-block-builder", "sc-client-api", "sc-client-db", + "sc-network", "sc-network-common", "sc-peerset", "sc-transaction-pool", diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs index e9a34b2a5c728..3c9716c08d1c0 100644 --- a/bin/node/cli/src/service.rs +++ b/bin/node/cli/src/service.rs @@ -31,10 +31,8 @@ use node_primitives::Block; use sc_client_api::BlockBackend; use sc_consensus_babe::{self, SlotProportion}; use sc_executor::NativeElseWasmExecutor; -use sc_network::NetworkService; -use sc_network_common::{ - protocol::event::Event, service::NetworkEventStream, sync::warp::WarpSyncParams, -}; +use sc_network::{event::Event, NetworkEventStream, NetworkService}; +use sc_network_common::sync::warp::WarpSyncParams; use sc_network_sync::SyncingService; use sc_service::{config::Configuration, error::Error as ServiceError, RpcHandlers, TaskManager}; use sc_telemetry::{Telemetry, TelemetryWorker}; diff --git a/client/authority-discovery/Cargo.toml b/client/authority-discovery/Cargo.toml index b37507662bfeb..900d9c59dfdae 100644 --- a/client/authority-discovery/Cargo.toml +++ b/client/authority-discovery/Cargo.toml @@ -28,6 +28,7 @@ rand = "0.8.5" 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/" } 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" } diff --git a/client/authority-discovery/src/lib.rs b/client/authority-discovery/src/lib.rs index 579b9d8b15051..a3c6699091297 100644 --- a/client/authority-discovery/src/lib.rs +++ b/client/authority-discovery/src/lib.rs @@ -40,7 +40,7 @@ use futures::{ }; use libp2p::{Multiaddr, PeerId}; -use sc_network_common::protocol::event::DhtEvent; +use sc_network::event::DhtEvent; use sp_authority_discovery::AuthorityId; use sp_blockchain::HeaderBackend; use sp_runtime::traits::Block as BlockT; diff --git a/client/authority-discovery/src/worker.rs b/client/authority-discovery/src/worker.rs index bc5fe2848d5a1..034d72902e65d 100644 --- a/client/authority-discovery/src/worker.rs +++ b/client/authority-discovery/src/worker.rs @@ -43,9 +43,8 @@ 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_network_common::{ - protocol::event::DhtEvent, - service::{KademliaKey, NetworkDHTProvider, NetworkSigner, NetworkStateInfo, Signature}, +use sc_network::{ + event::DhtEvent, KademliaKey, NetworkDHTProvider, NetworkSigner, NetworkStateInfo, Signature, }; use sp_api::{ApiError, ProvideRuntimeApi}; use sp_authority_discovery::{ diff --git a/client/authority-discovery/src/worker/tests.rs b/client/authority-discovery/src/worker/tests.rs index 22f984d9718ee..febe40657e06a 100644 --- a/client/authority-discovery/src/worker/tests.rs +++ b/client/authority-discovery/src/worker/tests.rs @@ -29,11 +29,16 @@ use futures::{ sink::SinkExt, task::LocalSpawn, }; -use libp2p::{core::multiaddr, identity::Keypair, PeerId}; +use libp2p::{ + core::multiaddr, + identity::{error::SigningError, Keypair}, + kad::record::Key as KademliaKey, + PeerId, +}; use prometheus_endpoint::prometheus::default_registry; use sc_client_api::HeaderBackend; -use sc_network_common::service::{KademliaKey, Signature, SigningError}; +use sc_network::Signature; use sp_api::{ApiRef, ProvideRuntimeApi}; use sp_keystore::{testing::KeyStore, CryptoStore}; use sp_runtime::traits::{Block as BlockT, NumberFor, Zero}; diff --git a/client/chain-spec/Cargo.toml b/client/chain-spec/Cargo.toml index 6168a897c962c..b1188b3bd4625 100644 --- a/client/chain-spec/Cargo.toml +++ b/client/chain-spec/Cargo.toml @@ -19,7 +19,7 @@ serde_json = "1.0.85" sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-chain-spec-derive = { version = "4.0.0-dev", path = "./derive" } sc-executor = { version = "0.10.0-dev", path = "../executor" } -sc-network-common = { version = "0.10.0-dev", path = "../network/common" } +sc-network = { version = "0.10.0-dev", path = "../network" } sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" } sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-core = { version = "7.0.0", path = "../../primitives/core" } diff --git a/client/chain-spec/src/chain_spec.rs b/client/chain-spec/src/chain_spec.rs index 9eed5bbbc4e69..96e36d8399ed5 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_common::config::MultiaddrWithPeerId; +use sc_network::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 e43a247961f02..6239eb7326b78 100644 --- a/client/chain-spec/src/lib.rs +++ b/client/chain-spec/src/lib.rs @@ -189,7 +189,7 @@ pub use self::{ }; pub use sc_chain_spec_derive::{ChainSpecExtension, ChainSpecGroup}; -use sc_network_common::config::MultiaddrWithPeerId; +use sc_network::config::MultiaddrWithPeerId; use sc_telemetry::TelemetryEndpoints; use serde::{de::DeserializeOwned, Serialize}; use sp_core::storage::Storage; diff --git a/client/cli/src/arg_enums.rs b/client/cli/src/arg_enums.rs index 472c1722f9ed8..c3399a89680d1 100644 --- a/client/cli/src/arg_enums.rs +++ b/client/cli/src/arg_enums.rs @@ -251,19 +251,15 @@ pub enum SyncMode { Warp, } -impl Into for SyncMode { - fn into(self) -> sc_network_common::config::SyncMode { +impl Into for SyncMode { + fn into(self) -> sc_network::config::SyncMode { match self { - SyncMode::Full => sc_network_common::config::SyncMode::Full, - SyncMode::Fast => sc_network_common::config::SyncMode::Fast { - skip_proofs: false, - storage_chain_mode: false, - }, - SyncMode::FastUnsafe => sc_network_common::config::SyncMode::Fast { - skip_proofs: true, - storage_chain_mode: false, - }, - SyncMode::Warp => sc_network_common::config::SyncMode::Warp, + SyncMode::Full => sc_network::config::SyncMode::Full, + SyncMode::Fast => + sc_network::config::SyncMode::Fast { skip_proofs: false, storage_chain_mode: false }, + SyncMode::FastUnsafe => + sc_network::config::SyncMode::Fast { skip_proofs: true, storage_chain_mode: false }, + SyncMode::Warp => sc_network::config::SyncMode::Warp, } } } diff --git a/client/cli/src/params/network_params.rs b/client/cli/src/params/network_params.rs index 31b761938df84..106fba75aa727 100644 --- a/client/cli/src/params/network_params.rs +++ b/client/cli/src/params/network_params.rs @@ -18,8 +18,12 @@ use crate::{arg_enums::SyncMode, params::node_key_params::NodeKeyParams}; use clap::Args; -use sc_network::{config::NetworkConfiguration, multiaddr::Protocol}; -use sc_network_common::config::{NodeKeyConfig, NonReservedPeerMode, SetConfig, TransportConfig}; +use sc_network::{ + config::{ + NetworkConfiguration, NodeKeyConfig, NonReservedPeerMode, SetConfig, TransportConfig, + }, + multiaddr::Protocol, +}; use sc_service::{ config::{Multiaddr, MultiaddrWithPeerId}, ChainSpec, ChainType, diff --git a/client/cli/src/params/node_key_params.rs b/client/cli/src/params/node_key_params.rs index d470ef1fad12a..074b95bea0f3a 100644 --- a/client/cli/src/params/node_key_params.rs +++ b/client/cli/src/params/node_key_params.rs @@ -17,7 +17,7 @@ // along with this program. If not, see . use clap::Args; -use sc_network_common::config::{identity::ed25519, NodeKeyConfig}; +use sc_network::config::{identity::ed25519, NodeKeyConfig}; use sp_core::H256; use std::{path::PathBuf, str::FromStr}; @@ -92,7 +92,7 @@ impl NodeKeyParams { let secret = if let Some(node_key) = self.node_key.as_ref() { parse_ed25519_secret(node_key)? } else { - sc_network_common::config::Secret::File( + sc_network::config::Secret::File( self.node_key_file .clone() .unwrap_or_else(|| net_config_dir.join(NODE_KEY_ED25519_FILE)), @@ -111,10 +111,10 @@ 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 { +fn parse_ed25519_secret(hex: &str) -> error::Result { H256::from_str(hex).map_err(invalid_node_key).and_then(|bytes| { ed25519::SecretKey::from_bytes(bytes) - .map(sc_network_common::config::Secret::Input) + .map(sc_network::config::Secret::Input) .map_err(invalid_node_key) }) } @@ -123,7 +123,7 @@ fn parse_ed25519_secret(hex: &str) -> error::Result Ok(()), _ => Err(error::Error::Input("Unexpected node key config".into())), @@ -200,7 +200,7 @@ mod tests { let dir = PathBuf::from(net_config_dir.clone()); let typ = params.node_key_type; params.node_key(net_config_dir).and_then(move |c| match c { - NodeKeyConfig::Ed25519(sc_network_common::config::Secret::File(ref f)) + NodeKeyConfig::Ed25519(sc_network::config::Secret::File(ref f)) if typ == NodeKeyType::Ed25519 && f == &dir.join(NODE_KEY_ED25519_FILE) => Ok(()), _ => Err(error::Error::Input("Unexpected node key config".into())), diff --git a/client/consensus/beefy/src/communication/mod.rs b/client/consensus/beefy/src/communication/mod.rs index f91b08bbc97ec..295d549bb1ba8 100644 --- a/client/consensus/beefy/src/communication/mod.rs +++ b/client/consensus/beefy/src/communication/mod.rs @@ -67,9 +67,8 @@ pub(crate) mod beefy_protocol_name { /// For standard protocol name see [`beefy_protocol_name::gossip_protocol_name`]. pub fn beefy_peers_set_config( gossip_protocol_name: sc_network::ProtocolName, -) -> sc_network_common::config::NonDefaultSetConfig { - let mut cfg = - sc_network_common::config::NonDefaultSetConfig::new(gossip_protocol_name, 1024 * 1024); +) -> sc_network::config::NonDefaultSetConfig { + let mut cfg = sc_network::config::NonDefaultSetConfig::new(gossip_protocol_name, 1024 * 1024); cfg.allow_non_reserved(25, 25); cfg } diff --git a/client/consensus/beefy/src/communication/request_response/incoming_requests_handler.rs b/client/consensus/beefy/src/communication/request_response/incoming_requests_handler.rs index ab6c21a187c95..1670e99828831 100644 --- a/client/consensus/beefy/src/communication/request_response/incoming_requests_handler.rs +++ b/client/consensus/beefy/src/communication/request_response/incoming_requests_handler.rs @@ -23,8 +23,10 @@ use futures::{ }; 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 sc_network::{ + config as netconfig, config::RequestResponseConfig, types::ProtocolName, PeerId, + ReputationChange, +}; use sp_consensus_beefy::BEEFY_ENGINE_ID; use sp_runtime::traits::Block; use std::{marker::PhantomData, sync::Arc}; diff --git a/client/consensus/beefy/src/communication/request_response/outgoing_requests_engine.rs b/client/consensus/beefy/src/communication/request_response/outgoing_requests_engine.rs index 7450d4b3239f1..c642e3dfe581c 100644 --- a/client/consensus/beefy/src/communication/request_response/outgoing_requests_engine.rs +++ b/client/consensus/beefy/src/communication/request_response/outgoing_requests_engine.rs @@ -22,10 +22,9 @@ use codec::Encode; use futures::channel::{oneshot, oneshot::Canceled}; use log::{debug, warn}; use parking_lot::Mutex; -use sc_network::{PeerId, ProtocolName}; -use sc_network_common::{ +use sc_network::{ request_responses::{IfDisconnected, RequestFailure}, - service::NetworkRequest, + NetworkRequest, PeerId, ProtocolName, }; use sp_consensus_beefy::{crypto::AuthorityId, ValidatorSet}; use sp_runtime::traits::{Block, NumberFor}; diff --git a/client/consensus/beefy/src/lib.rs b/client/consensus/beefy/src/lib.rs index 67758a4979b19..eb56a97de1dd9 100644 --- a/client/consensus/beefy/src/lib.rs +++ b/client/consensus/beefy/src/lib.rs @@ -38,8 +38,7 @@ use parking_lot::Mutex; use prometheus::Registry; use sc_client_api::{Backend, BlockBackend, BlockchainEvents, FinalityNotifications, Finalizer}; use sc_consensus::BlockImport; -use sc_network::ProtocolName; -use sc_network_common::service::NetworkRequest; +use sc_network::{NetworkRequest, ProtocolName}; use sc_network_gossip::{GossipEngine, Network as GossipNetwork, Syncing as GossipSyncing}; use sp_api::{HeaderT, NumberFor, ProvideRuntimeApi}; use sp_blockchain::{ diff --git a/client/consensus/grandpa/src/communication/gossip.rs b/client/consensus/grandpa/src/communication/gossip.rs index 0a3029e25477a..2c0fe3d8571e5 100644 --- a/client/consensus/grandpa/src/communication/gossip.rs +++ b/client/consensus/grandpa/src/communication/gossip.rs @@ -91,7 +91,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::role::ObservedRole; +use sc_network_common::role::ObservedRole; use sc_network_gossip::{MessageIntent, ValidatorContext}; use sc_telemetry::{telemetry, TelemetryHandle, CONSENSUS_DEBUG}; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; @@ -820,7 +820,7 @@ impl Inner { fn note_set(&mut self, set_id: SetId, authorities: Vec) -> MaybeMessage { let local_view = match self.local_view { ref mut x @ None => x.get_or_insert(LocalView::new(set_id, Round(1))), - Some(ref mut v) => + Some(ref mut v) => { if v.set_id == set_id { let diff_authorities = self.authorities.iter().collect::>() != authorities.iter().collect::>(); @@ -841,7 +841,8 @@ impl Inner { return None } else { v - }, + } + }, }; local_view.update_set(set_id); diff --git a/client/consensus/grandpa/src/communication/mod.rs b/client/consensus/grandpa/src/communication/mod.rs index 6c7e3ea46511e..3896bc36031ba 100644 --- a/client/consensus/grandpa/src/communication/mod.rs +++ b/client/consensus/grandpa/src/communication/mod.rs @@ -46,7 +46,7 @@ use finality_grandpa::{ Message::{Precommit, Prevote, PrimaryPropose}, }; use parity_scale_codec::{Decode, Encode}; -use sc_network::ReputationChange; +use sc_network::{NetworkBlock, NetworkSyncForkRequest, ReputationChange}; use sc_network_gossip::{GossipEngine, Network as GossipNetwork}; use sc_telemetry::{telemetry, TelemetryHandle, CONSENSUS_DEBUG, CONSENSUS_INFO}; use sp_keystore::SyncCryptoStorePtr; @@ -59,10 +59,7 @@ use crate::{ use gossip::{ FullCatchUpMessage, FullCommitMessage, GossipMessage, GossipValidator, PeerReport, VoteMessage, }; -use sc_network_common::{ - service::{NetworkBlock, NetworkSyncForkRequest}, - sync::SyncEventStream, -}; +use sc_network_common::sync::SyncEventStream; use sc_utils::mpsc::TracingUnboundedReceiver; use sp_consensus_grandpa::{AuthorityId, AuthoritySignature, RoundNumber, SetId as SetIdNumber}; @@ -77,7 +74,7 @@ pub(crate) const NEIGHBOR_REBROADCAST_PERIOD: Duration = Duration::from_secs(2 * pub mod grandpa_protocol_name { use sc_chain_spec::ChainSpec; - use sc_network_common::protocol::ProtocolName; + use sc_network::types::ProtocolName; pub(crate) const NAME: &str = "/grandpa/1"; /// Old names for the notifications protocol, used for backward compatibility. diff --git a/client/consensus/grandpa/src/communication/tests.rs b/client/consensus/grandpa/src/communication/tests.rs index 843e5467910e8..f97b1f1e88181 100644 --- a/client/consensus/grandpa/src/communication/tests.rs +++ b/client/consensus/grandpa/src/communication/tests.rs @@ -25,14 +25,16 @@ use super::{ use crate::{communication::grandpa_protocol_name, environment::SharedVoterSetState}; use futures::prelude::*; use parity_scale_codec::Encode; -use sc_network::{config::Role, Multiaddr, PeerId, ReputationChange}; +use sc_network::{ + config::{MultiaddrWithPeerId, Role}, + event::Event as NetworkEvent, + types::ProtocolName, + Multiaddr, NetworkBlock, NetworkEventStream, NetworkNotification, NetworkPeers, + NetworkSyncForkRequest, NotificationSenderError, NotificationSenderT as NotificationSender, + PeerId, ReputationChange, +}; use sc_network_common::{ - config::MultiaddrWithPeerId, - protocol::{event::Event as NetworkEvent, role::ObservedRole, ProtocolName}, - service::{ - NetworkBlock, NetworkEventStream, NetworkNotification, NetworkPeers, - NetworkSyncForkRequest, NotificationSender, NotificationSenderError, - }, + role::ObservedRole, sync::{SyncEvent as SyncStreamEvent, SyncEventStream}, }; use sc_network_gossip::Validator; diff --git a/client/consensus/grandpa/src/lib.rs b/client/consensus/grandpa/src/lib.rs index 7bf48a498fabb..2baa135081c55 100644 --- a/client/consensus/grandpa/src/lib.rs +++ b/client/consensus/grandpa/src/lib.rs @@ -68,7 +68,7 @@ use sc_client_api::{ StorageProvider, TransactionFor, }; use sc_consensus::BlockImport; -use sc_network_common::protocol::ProtocolName; +use sc_network::types::ProtocolName; use sc_telemetry::{telemetry, TelemetryHandle, CONSENSUS_DEBUG, CONSENSUS_INFO}; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver}; use sp_api::ProvideRuntimeApi; @@ -695,19 +695,19 @@ pub struct GrandpaParams { /// For standard protocol name see [`crate::protocol_standard_name`]. pub fn grandpa_peers_set_config( protocol_name: ProtocolName, -) -> sc_network_common::config::NonDefaultSetConfig { +) -> sc_network::config::NonDefaultSetConfig { use communication::grandpa_protocol_name; - sc_network_common::config::NonDefaultSetConfig { + sc_network::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, handshake: None, - set_config: sc_network_common::config::SetConfig { + set_config: sc_network::config::SetConfig { in_peers: 0, out_peers: 0, reserved_nodes: Vec::new(), - non_reserved_mode: sc_network_common::config::NonReservedPeerMode::Deny, + non_reserved_mode: sc_network::config::NonReservedPeerMode::Deny, }, } } diff --git a/client/informant/Cargo.toml b/client/informant/Cargo.toml index ca0ae03af3265..cd84dcb5a0dfe 100644 --- a/client/informant/Cargo.toml +++ b/client/informant/Cargo.toml @@ -19,5 +19,6 @@ futures-timer = "3.0.1" log = "0.4.17" 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-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } sp-runtime = { version = "7.0.0", path = "../../primitives/runtime" } diff --git a/client/informant/src/display.rs b/client/informant/src/display.rs index fc68e5603c134..46e7229273d79 100644 --- a/client/informant/src/display.rs +++ b/client/informant/src/display.rs @@ -20,12 +20,10 @@ use crate::OutputFormat; use ansi_term::Colour; use log::info; use sc_client_api::ClientInfo; -use sc_network_common::{ - service::NetworkStatus, - sync::{ - warp::{WarpSyncPhase, WarpSyncProgress}, - SyncState, SyncStatus, - }, +use sc_network::NetworkStatus; +use sc_network_common::sync::{ + warp::{WarpSyncPhase, WarpSyncProgress}, + SyncState, SyncStatus, }; 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 dc6aebc2ed658..03f9075055e2f 100644 --- a/client/informant/src/lib.rs +++ b/client/informant/src/lib.rs @@ -23,7 +23,8 @@ use futures::prelude::*; use futures_timer::Delay; use log::{debug, info, trace}; use sc_client_api::{BlockchainEvents, UsageProvider}; -use sc_network_common::{service::NetworkStatusProvider, sync::SyncStatusProvider}; +use sc_network::NetworkStatusProvider; +use sc_network_common::sync::SyncStatusProvider; use sp_blockchain::HeaderMetadata; use sp_runtime::traits::{Block as BlockT, Header}; use std::{collections::VecDeque, fmt::Display, sync::Arc, time::Duration}; diff --git a/client/network-gossip/Cargo.toml b/client/network-gossip/Cargo.toml index 7811e86c095ba..5c1bc91f105c8 100644 --- a/client/network-gossip/Cargo.toml +++ b/client/network-gossip/Cargo.toml @@ -22,6 +22,7 @@ log = "0.4.17" lru = "0.8.1" 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 = "7.0.0", path = "../../primitives/runtime" } diff --git a/client/network-gossip/src/bridge.rs b/client/network-gossip/src/bridge.rs index 7368cc770306e..4793d7822ddbe 100644 --- a/client/network-gossip/src/bridge.rs +++ b/client/network-gossip/src/bridge.rs @@ -21,10 +21,8 @@ use crate::{ Network, Syncing, Validator, }; -use sc_network_common::{ - protocol::{event::Event, ProtocolName}, - sync::SyncEvent, -}; +use sc_network::{event::Event, types::ProtocolName}; +use sc_network_common::sync::SyncEvent; use sc_peerset::ReputationChange; use futures::{ @@ -340,15 +338,11 @@ mod tests { future::poll_fn, }; use quickcheck::{Arbitrary, Gen, QuickCheck}; - use sc_network_common::{ - config::MultiaddrWithPeerId, - protocol::role::ObservedRole, - service::{ - NetworkBlock, NetworkEventStream, NetworkNotification, NetworkPeers, - NotificationSender, NotificationSenderError, - }, - sync::SyncEventStream, + use sc_network::{ + config::MultiaddrWithPeerId, NetworkBlock, NetworkEventStream, NetworkNotification, + NetworkPeers, NotificationSenderError, NotificationSenderT as NotificationSender, }; + use sc_network_common::{role::ObservedRole, sync::SyncEventStream}; use sp_runtime::{ testing::H256, traits::{Block as BlockT, NumberFor}, diff --git a/client/network-gossip/src/lib.rs b/client/network-gossip/src/lib.rs index e3448ba01c373..ef87dd599e010 100644 --- a/client/network-gossip/src/lib.rs +++ b/client/network-gossip/src/lib.rs @@ -68,11 +68,10 @@ pub use self::{ }; use libp2p::{multiaddr, PeerId}; -use sc_network_common::{ - protocol::ProtocolName, - service::{NetworkBlock, NetworkEventStream, NetworkNotification, NetworkPeers}, - sync::SyncEventStream, +use sc_network::{ + types::ProtocolName, NetworkBlock, NetworkEventStream, NetworkNotification, NetworkPeers, }; +use sc_network_common::sync::SyncEventStream; use sp_runtime::traits::{Block as BlockT, NumberFor}; use std::iter; diff --git a/client/network-gossip/src/state_machine.rs b/client/network-gossip/src/state_machine.rs index 3a0d5fc0de173..e6d2b0e2ae4c8 100644 --- a/client/network-gossip/src/state_machine.rs +++ b/client/network-gossip/src/state_machine.rs @@ -22,7 +22,8 @@ use ahash::AHashSet; use libp2p::PeerId; use lru::LruCache; use prometheus_endpoint::{register, Counter, PrometheusError, Registry, U64}; -use sc_network_common::protocol::{role::ObservedRole, ProtocolName}; +use sc_network::types::ProtocolName; +use sc_network_common::role::ObservedRole; use sp_runtime::traits::{Block as BlockT, Hash, HashFor}; use std::{collections::HashMap, iter, num::NonZeroUsize, sync::Arc, time, time::Instant}; @@ -525,13 +526,10 @@ mod tests { use super::*; use crate::multiaddr::Multiaddr; use futures::prelude::*; - use sc_network_common::{ - config::MultiaddrWithPeerId, - protocol::event::Event, - service::{ - NetworkBlock, NetworkEventStream, NetworkNotification, NetworkPeers, - NotificationSender, NotificationSenderError, - }, + use sc_network::{ + config::MultiaddrWithPeerId, event::Event, NetworkBlock, NetworkEventStream, + NetworkNotification, NetworkPeers, NotificationSenderError, + NotificationSenderT as NotificationSender, }; use sc_peerset::ReputationChange; use sp_runtime::{ diff --git a/client/network-gossip/src/validator.rs b/client/network-gossip/src/validator.rs index 26835a5ae6687..2272efba50652 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::role::ObservedRole; +use sc_network_common::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 5a918bebd626e..90b5ce871ef1a 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -26,6 +26,7 @@ futures = "0.3.21" futures-timer = "3.0.2" ip_network = "0.4.1" libp2p = { version = "0.50.0", features = ["dns", "identify", "kad", "macros", "mdns", "mplex", "noise", "ping", "tcp", "tokio", "yamux", "websocket"] } +linked_hash_set = "0.1.3" log = "0.4.17" lru = "0.8.1" mockall = "0.11.3" diff --git a/client/network/bitswap/Cargo.toml b/client/network/bitswap/Cargo.toml index 0bbb5ff09e4b9..ee2e0cfc79ff7 100644 --- a/client/network/bitswap/Cargo.toml +++ b/client/network/bitswap/Cargo.toml @@ -24,6 +24,7 @@ prost = "0.11" thiserror = "1.0" unsigned-varint = { version = "0.7.1", features = ["futures", "asynchronous_codec"] } sc-client-api = { version = "4.0.0-dev", path = "../../api" } +sc-network = { version = "0.10.0-dev", path = "../" } sc-network-common = { version = "0.10.0-dev", path = "../common" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sp-runtime = { version = "7.0.0", path = "../../../primitives/runtime" } diff --git a/client/network/bitswap/src/lib.rs b/client/network/bitswap/src/lib.rs index dd5fc46f6ca71..5a7a7b51355c6 100644 --- a/client/network/bitswap/src/lib.rs +++ b/client/network/bitswap/src/lib.rs @@ -26,9 +26,9 @@ use libp2p::core::PeerId; use log::{debug, error, trace}; use prost::Message; use sc_client_api::BlockBackend; -use sc_network_common::{ - protocol::ProtocolName, +use sc_network::{ request_responses::{IncomingRequest, OutgoingResponse, ProtocolConfig}, + types::ProtocolName, }; use schema::bitswap::{ message::{wantlist::WantType, Block as MessageBlock, BlockPresence, BlockPresenceType}, @@ -127,8 +127,9 @@ impl BitswapRequestHandler { }; match pending_response.send(response) { - Ok(()) => - trace!(target: LOG_TARGET, "Handled bitswap request from {peer}.",), + Ok(()) => { + trace!(target: LOG_TARGET, "Handled bitswap request from {peer}.",) + }, Err(_) => debug!( target: LOG_TARGET, "Failed to handle light client request from {peer}: {}", diff --git a/client/network/common/Cargo.toml b/client/network/common/Cargo.toml index c5f9d6d4cb027..983342b014b82 100644 --- a/client/network/common/Cargo.toml +++ b/client/network/common/Cargo.toml @@ -26,7 +26,6 @@ codec = { package = "parity-scale-codec", version = "3.2.2", features = [ futures = "0.3.21" futures-timer = "3.0.2" libp2p = { version = "0.50.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" sc-consensus = { version = "0.10.0-dev", path = "../../consensus/common" } diff --git a/client/network/common/src/config.rs b/client/network/common/src/config.rs deleted file mode 100644 index 6a02129fcfe06..0000000000000 --- a/client/network/common/src/config.rs +++ /dev/null @@ -1,702 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -//! Configuration of the networking layer. - -pub use crate::{ - protocol::{self, role::Role}, - request_responses::{ - IncomingRequest, OutgoingResponse, ProtocolConfig as RequestResponseConfig, - }, - sync::warp::WarpSyncProvider, - ExHashT, -}; -pub use libp2p::{build_multiaddr, core::PublicKey, identity}; - -use codec::Encode; -use libp2p::{ - identity::{ed25519, Keypair}, - multiaddr, Multiaddr, PeerId, -}; -use zeroize::Zeroize; - -use std::{ - error::Error, - fmt, fs, - io::{self, Write}, - iter, - net::Ipv4Addr, - path::{Path, PathBuf}, - str, - str::FromStr, -}; - -/// 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]>); - -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. -/// -/// # 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) - } -} - -/// 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, - } - } -} - -/// 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 -/// > 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, - /// 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, - /// 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(), - handshake: None, - 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/IPv6 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_ip: 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, - } - } -} - -/// Sync operation mode. -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub enum SyncMode { - /// Full block download and verification. - Full, - /// Download blocks and the latest state. - Fast { - /// Skip state proof download and verification. - skip_proofs: bool, - /// Download indexed transactions for recent blocks. - storage_chain_mode: bool, - }, - /// Warp sync - verify authority set transitions and the latest state. - 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 - } -} - -/// Network service configuration. -#[derive(Clone, Debug)] -pub struct NetworkConfiguration { - /// Directory path to store network-specific configuration. None means nothing will be saved. - pub net_config_path: Option, - /// Multiaddresses to listen for incoming connections. - pub listen_addresses: Vec, - /// Multiaddresses to advertise. Detected automatically if empty. - pub public_addresses: Vec, - /// List of initial node addresses - pub boot_nodes: Vec, - /// The node key configuration, which determines the node's network identity keypair. - pub node_key: NodeKeyConfig, - /// List of request-response protocols that the node supports. - 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. - pub client_version: String, - /// Name of the node. Sent over the wire for debugging purposes. - pub node_name: String, - /// Configuration for the transport layer. - pub transport: TransportConfig, - /// Maximum number of peers to ask the same blocks in parallel. - pub max_parallel_downloads: u32, - /// Initial syncing mode. - pub sync_mode: SyncMode, - - /// True if Kademlia random discovery should be enabled. - /// - /// If true, the node will automatically randomly walk the DHT in order to find new peers. - pub enable_dht_random_walk: bool, - - /// Should we insert non-global addresses into the DHT? - pub allow_non_globals_in_dht: bool, - - /// Require iterative Kademlia DHT queries to use disjoint paths for increased resiliency in - /// the presence of potentially adversarial nodes. - pub kademlia_disjoint_query_paths: bool, - /// Enable serving block data over IPFS bitswap. - pub ipfs_server: bool, - - /// Size of Yamux receive window of all substreams. `None` for the default (256kiB). - /// Any value less than 256kiB is invalid. - /// - /// # Context - /// - /// By design, notifications substreams on top of Yamux connections only allow up to `N` bytes - /// to be transferred at a time, where `N` is the Yamux receive window size configurable here. - /// This means, in practice, that every `N` bytes must be acknowledged by the receiver before - /// the sender can send more data. The maximum bandwidth of each notifications substream is - /// therefore `N / round_trip_time`. - /// - /// It is recommended to leave this to `None`, and use a request-response protocol instead if - /// a large amount of data must be transferred. The reason why the value is configurable is - /// that some Substrate users mis-use notification protocols to send large amounts of data. - /// As such, this option isn't designed to stay and will likely get removed in the future. - /// - /// Note that configuring a value here isn't a modification of the Yamux protocol, but rather - /// a modification of the way the implementation works. Different nodes with different - /// configured values remain compatible with each other. - pub yamux_window_size: Option, -} - -impl NetworkConfiguration { - /// Create new default configuration - pub fn new, SV: Into>( - node_name: SN, - client_version: SV, - node_key: NodeKeyConfig, - net_config_path: Option, - ) -> Self { - let default_peers_set = SetConfig::default(); - Self { - net_config_path, - listen_addresses: Vec::new(), - public_addresses: Vec::new(), - boot_nodes: Vec::new(), - node_key, - request_response_protocols: Vec::new(), - 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(), - transport: TransportConfig::Normal { enable_mdns: false, allow_private_ip: true }, - max_parallel_downloads: 5, - sync_mode: SyncMode::Full, - enable_dht_random_walk: true, - allow_non_globals_in_dht: false, - kademlia_disjoint_query_paths: false, - yamux_window_size: None, - ipfs_server: false, - } - } - - /// Create new default configuration for localhost-only connection with random port (useful for - /// testing) - pub fn new_local() -> NetworkConfiguration { - let mut config = - NetworkConfiguration::new("test-node", "test-client", Default::default(), None); - - config.listen_addresses = - vec![iter::once(multiaddr::Protocol::Ip4(Ipv4Addr::new(127, 0, 0, 1))) - .chain(iter::once(multiaddr::Protocol::Tcp(0))) - .collect()]; - - config.allow_non_globals_in_dht = true; - config - } - - /// Create new default configuration for localhost-only connection with random port (useful for - /// testing) - pub fn new_memory() -> NetworkConfiguration { - let mut config = - NetworkConfiguration::new("test-node", "test-client", Default::default(), None); - - config.listen_addresses = - vec![iter::once(multiaddr::Protocol::Ip4(Ipv4Addr::new(127, 0, 0, 1))) - .chain(iter::once(multiaddr::Protocol::Tcp(0))) - .collect()]; - - config.allow_non_globals_in_dht = true; - config - } -} - -/// 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. -#[derive(Clone, Debug)] -pub enum NodeKeyConfig { - /// A Ed25519 secret key configuration. - Ed25519(Secret), -} - -impl Default for NodeKeyConfig { - fn default() -> NodeKeyConfig { - Self::Ed25519(Secret::New) - } -} - -/// The options for obtaining a Ed25519 secret key. -pub type Ed25519Secret = Secret; - -/// The configuration options for obtaining a secret key `K`. -#[derive(Clone)] -pub enum Secret { - /// Use the given secret key `K`. - Input(K), - /// Read the secret key from a file. If the file does not exist, - /// it is created with a newly generated secret key `K`. The format - /// of the file is determined by `K`: - /// - /// * `ed25519::SecretKey`: An unencoded 32 bytes Ed25519 secret key. - File(PathBuf), - /// Always generate a new secret key `K`. - New, -} - -impl fmt::Debug for Secret { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Self::Input(_) => f.debug_tuple("Secret::Input").finish(), - Self::File(path) => f.debug_tuple("Secret::File").field(path).finish(), - Self::New => f.debug_tuple("Secret::New").finish(), - } - } -} - -impl NodeKeyConfig { - /// Evaluate a `NodeKeyConfig` to obtain an identity `Keypair`: - /// - /// * If the secret is configured as input, the corresponding keypair is returned. - /// - /// * If the secret is configured as a file, it is read from that file, if it exists. Otherwise - /// a new secret is generated and stored. In either case, the keypair obtained from the - /// secret is returned. - /// - /// * If the secret is configured to be new, it is generated and the corresponding keypair is - /// returned. - pub fn into_keypair(self) -> io::Result { - use NodeKeyConfig::*; - match self { - Ed25519(Secret::New) => Ok(Keypair::generate_ed25519()), - - Ed25519(Secret::Input(k)) => Ok(Keypair::Ed25519(k.into())), - - Ed25519(Secret::File(f)) => get_secret( - f, - |mut b| match String::from_utf8(b.to_vec()).ok().and_then(|s| { - if s.len() == 64 { - array_bytes::hex2bytes(&s).ok() - } else { - None - } - }) { - Some(s) => ed25519::SecretKey::from_bytes(s), - _ => ed25519::SecretKey::from_bytes(&mut b), - }, - ed25519::SecretKey::generate, - |b| b.as_ref().to_vec(), - ) - .map(ed25519::Keypair::from) - .map(Keypair::Ed25519), - } - } -} - -/// Load a secret key from a file, if it exists, or generate a -/// new secret key and write it to that file. In either case, -/// the secret key is returned. -fn get_secret(file: P, parse: F, generate: G, serialize: W) -> io::Result -where - P: AsRef, - F: for<'r> FnOnce(&'r mut [u8]) -> Result, - G: FnOnce() -> K, - E: Error + Send + Sync + 'static, - W: Fn(&K) -> Vec, -{ - std::fs::read(&file) - .and_then(|mut sk_bytes| { - parse(&mut sk_bytes).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) - }) - .or_else(|e| { - if e.kind() == io::ErrorKind::NotFound { - file.as_ref().parent().map_or(Ok(()), fs::create_dir_all)?; - let sk = generate(); - let mut sk_vec = serialize(&sk); - write_secret_file(file, &sk_vec)?; - sk_vec.zeroize(); - Ok(sk) - } else { - Err(e) - } - }) -} - -/// Write secret bytes to a file. -fn write_secret_file